summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/config/s390
diff options
context:
space:
mode:
authorkan <kan@FreeBSD.org>2007-05-19 01:19:51 +0000
committerkan <kan@FreeBSD.org>2007-05-19 01:19:51 +0000
commit1f9ea4d0a40cca64d60cf4dab152349da7b9dddf (patch)
tree0cb530c9c38af219e6dda2994c078b6b2b9ad853 /contrib/gcc/config/s390
parent4895159b2b4f648051c1f139faa7b6dc50c2bfcb (diff)
downloadFreeBSD-src-1f9ea4d0a40cca64d60cf4dab152349da7b9dddf.zip
FreeBSD-src-1f9ea4d0a40cca64d60cf4dab152349da7b9dddf.tar.gz
GCC 4.2.0 release.
Diffstat (limited to 'contrib/gcc/config/s390')
-rw-r--r--contrib/gcc/config/s390/2064.md55
-rw-r--r--contrib/gcc/config/s390/2084.md214
-rw-r--r--contrib/gcc/config/s390/constraints.md438
-rw-r--r--contrib/gcc/config/s390/fixdfdi.h159
-rw-r--r--contrib/gcc/config/s390/libgcc-glibc.ver33
-rw-r--r--contrib/gcc/config/s390/linux-unwind.h134
-rw-r--r--contrib/gcc/config/s390/linux.h107
-rw-r--r--contrib/gcc/config/s390/predicates.md379
-rw-r--r--contrib/gcc/config/s390/s390-modes.def139
-rw-r--r--contrib/gcc/config/s390/s390-protos.h96
-rw-r--r--contrib/gcc/config/s390/s390.c6915
-rw-r--r--contrib/gcc/config/s390/s390.h469
-rw-r--r--contrib/gcc/config/s390/s390.md8094
-rw-r--r--contrib/gcc/config/s390/s390.opt100
-rw-r--r--contrib/gcc/config/s390/s390x.h4
-rw-r--r--contrib/gcc/config/s390/t-crtstuff1
-rw-r--r--contrib/gcc/config/s390/t-linux3
-rw-r--r--contrib/gcc/config/s390/t-linux644
-rw-r--r--contrib/gcc/config/s390/t-tpf8
-rw-r--r--contrib/gcc/config/s390/tpf-unwind.h257
-rw-r--r--contrib/gcc/config/s390/tpf.h85
-rw-r--r--contrib/gcc/config/s390/tpf.md34
-rw-r--r--contrib/gcc/config/s390/tpf.opt28
23 files changed, 10967 insertions, 6789 deletions
diff --git a/contrib/gcc/config/s390/2064.md b/contrib/gcc/config/s390/2064.md
index 143cd1b..2f958a5 100644
--- a/contrib/gcc/config/s390/2064.md
+++ b/contrib/gcc/config/s390/2064.md
@@ -1,5 +1,5 @@
;; Scheduling description for z900 (cpu 2064).
-;; Copyright (C) 2003 Free Software Foundation, Inc.
+;; Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
;; Contributed by Hartmut Penner (hpenner@de.ibm.com) and
;; Ulrich Weigand (uweigand@de.ibm.com).
@@ -17,8 +17,8 @@
;; You should have received a copy of the GNU General Public License
;; along with GCC; see the file COPYING. If not, write to the Free
-;; Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-;; 02111-1307, USA.
+;; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+;; 02110-1301, USA.
;;
;; References:
@@ -40,62 +40,67 @@
;; |
;; 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")
+ (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")
+ (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")
+ (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")
+ (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")
+ (and (eq_attr "cpu" "z900,g5,g6")
(eq_attr "type" "jsr"))
"z_e1*5,z_wr")
-(define_insn_reservation "z_o2" 2
- (and (eq_attr "cpu" "z900")
- (eq_attr "type" "o2"))
- "z_e1*2,z_wr")
+(define_insn_reservation "z_mul" 5
+ (and (eq_attr "cpu" "g5,g6,z900")
+ (eq_attr "type" "imulsi,imulhi"))
+ "z_e1*5,z_wr")
-(define_insn_reservation "z_o3" 3
- (and (eq_attr "cpu" "z900")
- (eq_attr "type" "o3"))
- "z_e1*3,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")
-;
-; Insn still not mentioned are check for
-; the usage of the agen unit
-;
+;; For everything else we check the atype flag.
(define_insn_reservation "z_int" 1
- (and (eq_attr "cpu" "z900")
- (eq_attr "atype" "reg"))
+ (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")
- (eq_attr "atype" "agen"))
+ (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.
diff --git a/contrib/gcc/config/s390/2084.md b/contrib/gcc/config/s390/2084.md
index a74ffbf..3a4479a 100644
--- a/contrib/gcc/config/s390/2084.md
+++ b/contrib/gcc/config/s390/2084.md
@@ -1,5 +1,5 @@
;; Scheduling description for z990 (cpu 2084).
-;; Copyright (C) 2003 Free Software Foundation, Inc.
+;; Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
;; Contributed by Hartmut Penner (hpenner@de.ibm.com) and
;; Ulrich Weigand (uweigand@de.ibm.com).
@@ -17,8 +17,8 @@
;; You should have received a copy of the GNU General Public License
;; along with GCC; see the file COPYING. If not, write to the Free
-;; Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-;; 02111-1307, USA.
+;; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+;; 02110-1301, USA.
(define_automaton "x_ipu")
@@ -61,151 +61,199 @@
;; Simple insns
;;
+(define_insn_reservation "x_int" 1
+ (and (eq_attr "cpu" "z990,z9_109")
+ (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")
+ (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")
+ (and (eq_attr "cpu" "z990,z9_109")
(eq_attr "type" "lr"))
"x-e1-st,x-wr-st")
(define_insn_reservation "x_la" 1
- (and (eq_attr "cpu" "z990")
+ (and (eq_attr "cpu" "z990,z9_109")
(eq_attr "type" "la"))
"x-e1-st,x-wr-st")
(define_insn_reservation "x_larl" 1
- (and (eq_attr "cpu" "z990")
+ (and (eq_attr "cpu" "z990,z9_109")
(eq_attr "type" "larl"))
"x-e1-st,x-wr-st")
(define_insn_reservation "x_load" 1
- (and (eq_attr "cpu" "z990")
+ (and (eq_attr "cpu" "z990,z9_109")
(eq_attr "type" "load"))
"x-e1-st+x-mem,x-wr-st")
(define_insn_reservation "x_store" 1
- (and (eq_attr "cpu" "z990")
+ (and (eq_attr "cpu" "z990,z9_109")
(eq_attr "type" "store"))
"x-e1-st+x_store_tok,x-wr-st")
(define_insn_reservation "x_branch" 1
- (and (eq_attr "cpu" "z990")
+ (and (eq_attr "cpu" "z990,z9_109")
(eq_attr "type" "branch"))
"x_e1_r,x_wr_r")
(define_insn_reservation "x_call" 5
- (and (eq_attr "cpu" "z990")
+ (and (eq_attr "cpu" "z990,z9_109")
(eq_attr "type" "jsr"))
- "x-e1-np*5,x-wr-np")
+ "x-e1-np*5,x-wr-np")
+
+(define_insn_reservation "x_mul_hi" 2
+ (and (eq_attr "cpu" "z990,z9_109")
+ (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")
+ (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")
+ (eq_attr "type" "idiv"))
+ "x-e1-np*10,x-wr-np")
+
+(define_insn_reservation "x_sem" 17
+ (and (eq_attr "cpu" "z990,z9_109")
+ (eq_attr "type" "sem"))
+ "x-e1-np+x-mem,x-e1-np*16,x-wr-st")
;;
;; Multicycle insns
;;
-(define_insn_reservation "x_ss" 1
- (and (eq_attr "cpu" "z990")
- (eq_attr "op_type" "SS"))
+(define_insn_reservation "x_cs" 1
+ (and (eq_attr "cpu" "z990,z9_109")
+ (eq_attr "type" "cs"))
"x-e1-np,x-wr-np")
+(define_insn_reservation "x_vs" 1
+ (and (eq_attr "cpu" "z990,z9_109")
+ (eq_attr "type" "vs"))
+ "x-e1-np*10,x-wr-np")
+
(define_insn_reservation "x_stm" 1
- (and (eq_attr "cpu" "z990")
+ (and (eq_attr "cpu" "z990,z9_109")
(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")
+ (and (eq_attr "cpu" "z990,z9_109")
(eq_attr "type" "lm"))
"x-e1-np*10,x-wr-np")
-(define_insn_reservation "x_nn" 1
- (and (eq_attr "cpu" "z990")
- (eq_attr "op_type" "NN"))
+(define_insn_reservation "x_other" 1
+ (and (eq_attr "cpu" "z990,z9_109")
+ (eq_attr "type" "other"))
"x-e1-np,x-wr-np")
-(define_insn_reservation "x_o2" 2
- (and (eq_attr "cpu" "z990")
- (eq_attr "type" "o2"))
- "x-e1-np*2,x-wr-np")
-
-(define_insn_reservation "x_o3" 3
- (and (eq_attr "cpu" "z990")
- (eq_attr "type" "o3"))
- "x-e1-np*3,x-wr-np")
-
;;
;; Floating point insns
;;
-(define_insn_reservation "x_fsimpd" 6
- (and (eq_attr "cpu" "z990")
- (eq_attr "type" "fsimpd,fmuld"))
+(define_insn_reservation "x_fsimptf" 7
+ (and (eq_attr "cpu" "z990,z9_109")
+ (eq_attr "type" "fsimptf"))
+ "x_e1_t*2,x-wr-fp")
+
+(define_insn_reservation "x_fsimpdf" 6
+ (and (eq_attr "cpu" "z990,z9_109")
+ (eq_attr "type" "fsimpdf,fmuldf"))
"x_e1_t,x-wr-fp")
-(define_insn_reservation "x_fsimps" 6
- (and (eq_attr "cpu" "z990")
- (eq_attr "type" "fsimps,fmuls"))
+(define_insn_reservation "x_fsimpsf" 6
+ (and (eq_attr "cpu" "z990,z9_109")
+ (eq_attr "type" "fsimpsf,fmulsf"))
"x_e1_t,x-wr-fp")
-(define_insn_reservation "x_fdivd" 36
- (and (eq_attr "cpu" "z990")
- (eq_attr "type" "fdivd"))
+
+(define_insn_reservation "x_fmultf" 33
+ (and (eq_attr "cpu" "z990,z9_109")
+ (eq_attr "type" "fmultf"))
+ "x_e1_t*27,x-wr-fp")
+
+
+(define_insn_reservation "x_fdivtf" 82
+ (and (eq_attr "cpu" "z990,z9_109")
+ (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")
+ (eq_attr "type" "fdivdf,fsqrtdf"))
"x_e1_t*30,x-wr-fp")
-(define_insn_reservation "x_fdivs" 36
- (and (eq_attr "cpu" "z990")
- (eq_attr "type" "fdivs"))
+(define_insn_reservation "x_fdivsf" 36
+ (and (eq_attr "cpu" "z990,z9_109")
+ (eq_attr "type" "fdivsf,fsqrtsf"))
"x_e1_t*30,x-wr-fp")
-(define_insn_reservation "x_floadd" 6
- (and (eq_attr "cpu" "z990")
- (eq_attr "type" "floadd"))
+
+(define_insn_reservation "x_floadtf" 6
+ (and (eq_attr "cpu" "z990,z9_109")
+ (eq_attr "type" "floadtf"))
+ "x_e1_t,x-wr-fp")
+
+(define_insn_reservation "x_floaddf" 6
+ (and (eq_attr "cpu" "z990,z9_109")
+ (eq_attr "type" "floaddf"))
"x_e1_t,x-wr-fp")
-(define_insn_reservation "x_floads" 6
- (and (eq_attr "cpu" "z990")
- (eq_attr "type" "floads"))
+(define_insn_reservation "x_floadsf" 6
+ (and (eq_attr "cpu" "z990,z9_109")
+ (eq_attr "type" "floadsf"))
"x_e1_t,x-wr-fp")
-(define_insn_reservation "x_fstored" 1
- (and (eq_attr "cpu" "z990")
- (eq_attr "type" "fstored"))
+
+(define_insn_reservation "x_fstoredf" 1
+ (and (eq_attr "cpu" "z990,z9_109")
+ (eq_attr "type" "fstoredf"))
"x_e1_t,x-wr-fp")
-(define_insn_reservation "x_fstores" 1
- (and (eq_attr "cpu" "z990")
- (eq_attr "type" "fstores"))
+(define_insn_reservation "x_fstoresf" 1
+ (and (eq_attr "cpu" "z990,z9_109")
+ (eq_attr "type" "fstoresf"))
"x_e1_t,x-wr-fp")
+
+(define_insn_reservation "x_ftrunctf" 16
+ (and (eq_attr "cpu" "z990,z9_109")
+ (eq_attr "type" "ftrunctf"))
+ "x_e1_t*10,x-wr-fp")
+
+(define_insn_reservation "x_ftruncdf" 11
+ (and (eq_attr "cpu" "z990,z9_109")
+ (eq_attr "type" "ftruncdf"))
+ "x_e1_t*5,x-wr-fp")
+
+
(define_insn_reservation "x_ftoi" 1
- (and (eq_attr "cpu" "z990")
+ (and (eq_attr "cpu" "z990,z9_109")
(eq_attr "type" "ftoi"))
"x_e1_t*3,x-wr-fp")
(define_insn_reservation "x_itof" 7
- (and (eq_attr "cpu" "z990")
+ (and (eq_attr "cpu" "z990,z9_109")
(eq_attr "type" "itof"))
"x_e1_t*3,x-wr-fp")
-(define_bypass 1 "x_fsimpd" "x_fstored")
+(define_bypass 1 "x_fsimpdf" "x_fstoredf")
-(define_bypass 1 "x_fsimps" "x_fstores")
+(define_bypass 1 "x_fsimpsf" "x_fstoresf")
-(define_bypass 1 "x_floadd" "x_fsimpd,x_fstored,x_floadd")
+(define_bypass 1 "x_floaddf" "x_fsimpdf,x_fstoredf,x_floaddf")
-(define_bypass 1 "x_floads" "x_fsimps,x_fstores,x_floads")
-
-;;
-;; Insns still not mentioned are checked for
-;; the usage of the agen unit
-;;
-
-(define_insn_reservation "x_int" 1
- (and (eq_attr "cpu" "z990")
- (eq_attr "atype" "reg"))
- "x-e1-st,x-wr-st")
-
-(define_insn_reservation "x_agen" 1
- (and (eq_attr "cpu" "z990")
- (eq_attr "atype" "agen"))
- "x-e1-st+x-mem,x-wr-st")
+(define_bypass 1 "x_floadsf" "x_fsimpsf,x_fstoresf,x_floadsf")
;;
;; s390_agen_dep_p returns 1, if a register is set in the
@@ -218,12 +266,12 @@
;;
(define_bypass 5 "x_int,x_agen,x_lr"
- "x_agen,x_la,x_call,x_load,x_store,x_ss,x_stm,x_lm"
+ "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_floadd, x_floads, x_fstored, x_fstores,\
- x_fsimpd, x_fsimps, x_fdivd, x_fdivs"
+ "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
@@ -231,12 +279,12 @@
;;
(define_bypass 4 "x_load"
- "x_agen,x_la,x_call,x_load,x_store,x_ss,x_stm,x_lm"
+ "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_floadd, x_floads, x_fstored, x_fstores,\
- x_fsimpd, x_fsimps, x_fdivd, x_fdivs"
+ "x_floadtf, x_floaddf, x_floadsf, x_fstoredf, x_fstoresf,\
+ x_fsimpdf, x_fsimpsf, x_fdivdf, x_fdivsf"
"s390_agen_dep_p")
;;
@@ -245,12 +293,12 @@
;;
(define_bypass 3 "x_larl,x_la"
- "x_agen,x_la,x_call,x_load,x_store,x_ss,x_stm,x_lm"
+ "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_floadd, x_floads, x_fstored, x_fstores,\
- x_fsimpd, x_fsimps, x_fdivd, x_fdivs"
+ "x_floadtf, x_floaddf, x_floadsf, x_fstoredf, x_fstoresf,\
+ x_fsimpdf, x_fsimpsf, x_fdivdf, x_fdivsf"
"s390_agen_dep_p")
;;
diff --git a/contrib/gcc/config/s390/constraints.md b/contrib/gcc/config/s390/constraints.md
new file mode 100644
index 0000000..cfc8aa5
--- /dev/null
+++ b/contrib/gcc/config/s390/constraints.md
@@ -0,0 +1,438 @@
+;; Constraints definitions belonging to the gcc backend for IBM S/390.
+;; Copyright (C) 2006 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 2, or (at your option) any later
+;; version.
+;;
+;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+;; WARRANTY; without even the implied warranty of MERCHANTABILITY or
+;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+;; for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING. If not, write to the Free
+;; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+;; 02110-1301, USA.
+
+
+;;
+;; Special constraints for s/390 machine description:
+;;
+;; a -- Any address register from 1 to 15.
+;; c -- Condition code register 33.
+;; d -- Any register from 0 to 15.
+;; f -- Floating point registers.
+;; t -- Access registers 36 and 37.
+;; 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).
+;; 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.
+;; W -- Pointer with long displacement.
+;; Y -- Shift count operand.
+;;
+
+
+;;
+;; 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 "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 int) ival <= 255")))
+
+
+(define_constraint "J"
+ "A 12-bit constant (0..4095)"
+ (and (match_code "const_int")
+ (match_test "(unsigned 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).
+ 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 "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"
+ (match_test "s390_mem_constraint (\"U\", op)"))
+
+
+
+(define_address_constraint "W"
+ "Pointer with long displacement"
+ (match_test "s390_mem_constraint (\"W\", op)"))
diff --git a/contrib/gcc/config/s390/fixdfdi.h b/contrib/gcc/config/s390/fixdfdi.h
index a5b9212..88c2197 100644
--- a/contrib/gcc/config/s390/fixdfdi.h
+++ b/contrib/gcc/config/s390/fixdfdi.h
@@ -17,8 +17,158 @@ for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
+
+#ifdef L_fixunstfdi
+
+#define EXPD(fp) (((fp.l.i[0]) >> 16) & 0x7FFF)
+#define EXPONENT_BIAS 16383
+#define MANTISSA_BITS 112
+#define PRECISION (MANTISSA_BITS + 1)
+#define SIGNBIT 0x80000000
+#define SIGND(fp) ((fp.l.i[0]) & SIGNBIT)
+#define MANTD_HIGH_LL(fp) ((fp.ll[0] & HIGH_LL_FRAC_MASK) | HIGH_LL_UNIT_BIT)
+#define MANTD_LOW_LL(fp) (fp.ll[1])
+#define FRACD_ZERO_P(fp) (!fp.ll[1] && !(fp.ll[0] & HIGH_LL_FRAC_MASK))
+#define HIGH_LL_FRAC_BITS 48
+#define HIGH_LL_UNIT_BIT ((UDItype_x)1 << HIGH_LL_FRAC_BITS)
+#define HIGH_LL_FRAC_MASK (HIGH_LL_UNIT_BIT - 1)
+
+typedef int DItype_x __attribute__ ((mode (DI)));
+typedef unsigned int UDItype_x __attribute__ ((mode (DI)));
+typedef int SItype_x __attribute__ ((mode (SI)));
+typedef unsigned int USItype_x __attribute__ ((mode (SI)));
+
+union double_long {
+ long double d;
+ struct {
+ SItype_x i[4]; /* 32 bit parts: 0 upper ... 3 lowest */
+ } l;
+ UDItype_x ll[2]; /* 64 bit parts: 0 upper, 1 lower */
+};
+
+UDItype_x __fixunstfdi (long double a1);
+
+/* convert double to unsigned int */
+UDItype_x
+__fixunstfdi (long double a1)
+{
+ register union double_long dl1;
+ register int exp;
+ register UDItype_x l;
+
+ dl1.d = a1;
+
+ /* +/- 0, denormalized, negative */
+ if (!EXPD (dl1) || SIGND(dl1))
+ return 0;
+
+ /* The exponent - considered the binary point at the right end of
+ the mantissa. */
+ exp = EXPD (dl1) - EXPONENT_BIAS - MANTISSA_BITS;
+
+ /* number < 1: If the mantissa would need to be right-shifted more bits than
+ its size (plus the implied one bit on the left) the result would be
+ zero. */
+ if (exp <= -PRECISION)
+ return 0;
+
+ /* NaN: All exponent bits set and a nonzero fraction. */
+ if ((EXPD(dl1) == 0x7fff) && !FRACD_ZERO_P (dl1))
+ return 0x0ULL;
+
+ /* If the upper ll part of the mantissa isn't
+ zeroed out after shifting the number would be to large. */
+ if (exp >= -HIGH_LL_FRAC_BITS)
+ return 0xFFFFFFFFFFFFFFFFULL;
+
+ exp += HIGH_LL_FRAC_BITS + 1;
+
+ l = MANTD_LOW_LL (dl1) >> (HIGH_LL_FRAC_BITS + 1)
+ | MANTD_HIGH_LL (dl1) << (64 - (HIGH_LL_FRAC_BITS + 1));
+
+ return l >> -exp;
+}
+#define __fixunstfdi ___fixunstfdi
+#endif
+#undef L_fixunstfdi
+
+#ifdef L_fixtfdi
+#define EXPD(fp) (((fp.l.i[0]) >> 16) & 0x7FFF)
+#define EXPONENT_BIAS 16383
+#define MANTISSA_BITS 112
+#define PRECISION (MANTISSA_BITS + 1)
+#define SIGNBIT 0x80000000
+#define SIGND(fp) ((fp.l.i[0]) & SIGNBIT)
+#define MANTD_HIGH_LL(fp) ((fp.ll[0] & HIGH_LL_FRAC_MASK) | HIGH_LL_UNIT_BIT)
+#define MANTD_LOW_LL(fp) (fp.ll[1])
+#define FRACD_ZERO_P(fp) (!fp.ll[1] && !(fp.ll[0] & HIGH_LL_FRAC_MASK))
+#define HIGH_LL_FRAC_BITS 48
+#define HIGH_LL_UNIT_BIT ((UDItype_x)1 << HIGH_LL_FRAC_BITS)
+#define HIGH_LL_FRAC_MASK (HIGH_LL_UNIT_BIT - 1)
+
+typedef int DItype_x __attribute__ ((mode (DI)));
+typedef unsigned int UDItype_x __attribute__ ((mode (DI)));
+typedef int SItype_x __attribute__ ((mode (SI)));
+typedef unsigned int USItype_x __attribute__ ((mode (SI)));
+
+union double_long {
+ long double d;
+ struct {
+ SItype_x i[4]; /* 32 bit parts: 0 upper ... 3 lowest */
+ } l;
+ DItype_x ll[2]; /* 64 bit parts: 0 upper, 1 lower */
+};
+
+DItype_x __fixtfdi (long double a1);
+
+/* convert double to unsigned int */
+DItype_x
+__fixtfdi (long double a1)
+{
+ register union double_long dl1;
+ register int exp;
+ register UDItype_x l;
+
+ dl1.d = a1;
+
+ /* +/- 0, denormalized */
+ if (!EXPD (dl1))
+ return 0;
+
+ /* The exponent - considered the binary point at the right end of
+ the mantissa. */
+ exp = EXPD (dl1) - EXPONENT_BIAS - MANTISSA_BITS;
+
+ /* number < 1: If the mantissa would need to be right-shifted more bits than
+ its size the result would be zero. */
+ if (exp <= -PRECISION)
+ return 0;
+
+ /* NaN: All exponent bits set and a nonzero fraction. */
+ if ((EXPD(dl1) == 0x7fff) && !FRACD_ZERO_P (dl1))
+ return 0x8000000000000000ULL;
+
+ /* If the upper ll part of the mantissa isn't
+ zeroed out after shifting the number would be to large. */
+ if (exp >= -HIGH_LL_FRAC_BITS)
+ {
+ l = (long long)1 << 63; /* long int min */
+ return SIGND (dl1) ? l : l - 1;
+ }
+
+ /* The extra bit is needed for the sign bit. */
+ exp += HIGH_LL_FRAC_BITS + 1;
+
+ l = MANTD_LOW_LL (dl1) >> (HIGH_LL_FRAC_BITS + 1)
+ | MANTD_HIGH_LL (dl1) << (64 - (HIGH_LL_FRAC_BITS + 1));
+
+ return SIGND (dl1) ? -(l >> -exp) : l >> -exp;
+}
+#define __fixtfdi ___fixtfdi
+#endif
+#undef L_fixtfdi
#ifdef L_fixunsdfdi
#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF)
@@ -55,7 +205,7 @@ __fixunsdfdi (double a1)
dl1.d = a1;
- /* +/- 0, denormalized, negativ */
+ /* +/- 0, denormalized, negative */
if (!EXPD (dl1) || SIGND(dl1))
return 0;
@@ -199,7 +349,7 @@ __fixunssfdi (float a1)
fl1.f = a1;
- /* +/- 0, denormalized, negativ */
+ /* +/- 0, denormalized, negative */
if (!EXP (fl1) || SIGN(fl1))
return 0;
@@ -305,4 +455,3 @@ __fixsfdi (float a1)
#define __fixsfdi ___fixsfdi
#endif
#undef L_fixsfdi
-
diff --git a/contrib/gcc/config/s390/libgcc-glibc.ver b/contrib/gcc/config/s390/libgcc-glibc.ver
index 1d9e229..e9413d0 100644
--- a/contrib/gcc/config/s390/libgcc-glibc.ver
+++ b/contrib/gcc/config/s390/libgcc-glibc.ver
@@ -39,3 +39,36 @@ GLIBC_2.2 {
}
%endif
+# With GCC 4.1.0 long double 128 bit support was introduced. The
+# following symbols coming from libgcc are enabled when -mlong-double-128
+# is specified. These lines make the symbols to get a @@GCC_4.1.0 attached.
+
+%exclude {
+ __divtc3
+ __multc3
+ __powitf2
+ __fixtfti
+ __fixunstfti
+ __floattitf
+
+ __fixtfdi
+ __fixunstfdi
+ __floatditf
+}
+
+GCC_4.1.0 {
+ __divtc3
+ __multc3
+ __powitf2
+
+%ifdef __s390x__
+ __fixtfti
+ __fixunstfti
+ __floattitf
+
+%else
+ __fixtfdi
+ __fixunstfdi
+ __floatditf
+%endif
+}
diff --git a/contrib/gcc/config/s390/linux-unwind.h b/contrib/gcc/config/s390/linux-unwind.h
new file mode 100644
index 0000000..221a5d4
--- /dev/null
+++ b/contrib/gcc/config/s390/linux-unwind.h
@@ -0,0 +1,134 @@
+/* DWARF2 EH unwinding support for S/390 Linux.
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file with other programs, and to distribute
+those programs without any restriction coming from the use of this
+file. (The General Public License restrictions do apply in other
+respects; for example, they cover modification of the file, and
+distribution when not linked into another program.)
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
+
+/* Do code reading to identify a signal frame, and set the frame
+ state data appropriately. See unwind-dw2.c for the structs. */
+
+#define MD_FALLBACK_FRAME_STATE_FOR s390_fallback_frame_state
+
+static _Unwind_Reason_Code
+s390_fallback_frame_state (struct _Unwind_Context *context,
+ _Unwind_FrameState *fs)
+{
+ unsigned char *pc = context->ra;
+ long new_cfa;
+ int i;
+
+ typedef struct
+ {
+ unsigned long psw_mask;
+ unsigned long psw_addr;
+ unsigned long gprs[16];
+ unsigned int acrs[16];
+ unsigned int fpc;
+ unsigned int __pad;
+ double fprs[16];
+ } __attribute__ ((__aligned__ (8))) sigregs_;
+
+ sigregs_ *regs;
+ int *signo;
+
+ /* svc $__NR_sigreturn or svc $__NR_rt_sigreturn */
+ if (pc[0] != 0x0a || (pc[1] != 119 && pc[1] != 173))
+ return _URC_END_OF_STACK;
+
+ /* Legacy frames:
+ old signal mask (8 bytes)
+ pointer to sigregs (8 bytes) - points always to next location
+ sigregs
+ retcode
+ This frame layout was used on kernels < 2.6.9 for non-RT frames,
+ and on kernels < 2.4.13 for RT frames as well. Note that we need
+ to look at RA to detect this layout -- this means that if you use
+ sa_restorer to install a different signal restorer on a legacy
+ kernel, unwinding from signal frames will not work. */
+ if (context->ra == context->cfa + 16 + sizeof (sigregs_))
+ {
+ regs = (sigregs_ *)(context->cfa + 16);
+ signo = NULL;
+ }
+
+ /* New-style RT frame:
+ retcode + alignment (8 bytes)
+ siginfo (128 bytes)
+ ucontext (contains sigregs) */
+ else if (pc[1] == 173 /* __NR_rt_sigreturn */)
+ {
+ struct ucontext_
+ {
+ unsigned long uc_flags;
+ struct ucontext_ *uc_link;
+ unsigned long uc_stack[3];
+ sigregs_ uc_mcontext;
+ } *uc = context->cfa + 8 + 128;
+
+ regs = &uc->uc_mcontext;
+ signo = context->cfa + sizeof(long);
+ }
+
+ /* New-style non-RT frame:
+ old signal mask (8 bytes)
+ pointer to sigregs (followed by signal number) */
+ else
+ {
+ regs = *(sigregs_ **)(context->cfa + 8);
+ signo = (int *)(regs + 1);
+ }
+
+ new_cfa = regs->gprs[15] + 16*sizeof(long) + 32;
+ fs->cfa_how = CFA_REG_OFFSET;
+ fs->cfa_reg = 15;
+ fs->cfa_offset =
+ new_cfa - (long) context->cfa + 16*sizeof(long) + 32;
+
+ for (i = 0; i < 16; i++)
+ {
+ fs->regs.reg[i].how = REG_SAVED_OFFSET;
+ fs->regs.reg[i].loc.offset =
+ (long)&regs->gprs[i] - new_cfa;
+ }
+ for (i = 0; i < 16; i++)
+ {
+ fs->regs.reg[16+i].how = REG_SAVED_OFFSET;
+ fs->regs.reg[16+i].loc.offset =
+ (long)&regs->fprs[i] - new_cfa;
+ }
+
+ /* Load return addr from PSW into dummy register 32. */
+
+ fs->regs.reg[32].how = REG_SAVED_OFFSET;
+ fs->regs.reg[32].loc.offset = (long)&regs->psw_addr - new_cfa;
+ fs->retaddr_column = 32;
+ /* SIGILL, SIGFPE and SIGTRAP are delivered with psw_addr
+ after the faulting instruction rather than before it.
+ Don't set FS->signal_frame in that case. */
+ if (!signo || (*signo != 4 && *signo != 5 && *signo != 8))
+ fs->signal_frame = 1;
+
+ return _URC_NO_REASON;
+}
diff --git a/contrib/gcc/config/s390/linux.h b/contrib/gcc/config/s390/linux.h
index 9a6db9d..fd8ef0b 100644
--- a/contrib/gcc/config/s390/linux.h
+++ b/contrib/gcc/config/s390/linux.h
@@ -1,5 +1,6 @@
/* Definitions for Linux for S/390.
- Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006
+ Free Software Foundation, Inc.
Contributed by Hartmut Penner (hpenner@de.ibm.com) and
Ulrich Weigand (uweigand@de.ibm.com).
@@ -17,8 +18,8 @@ for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
#ifndef _LINUX_H
#define _LINUX_H
@@ -54,11 +55,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
do \
{ \
LINUX_TARGET_OS_CPP_BUILTINS(); \
- if (flag_pic) \
- { \
- builtin_define ("__PIC__"); \
- builtin_define ("__pic__"); \
- } \
} \
while (0)
@@ -77,6 +73,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#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} \
@@ -86,88 +85,22 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
%{!static: \
%{rdynamic:-export-dynamic} \
%{!dynamic-linker: \
- %{m31:-dynamic-linker /lib/ld.so.1} \
- %{m64:-dynamic-linker /lib/ld64.so.1}}}}"
+ %{m31:-dynamic-linker " LINUX_DYNAMIC_LINKER32 "} \
+ %{m64:-dynamic-linker " LINUX_DYNAMIC_LINKER64 "}}}}"
+#define CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}"
#define TARGET_ASM_FILE_END file_end_indicate_exec_stack
-/* Do code reading to identify a signal frame, and set the frame
- state data appropriately. See unwind-dw2.c for the structs. */
-
-#define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS) \
- do { \
- unsigned char *pc_ = (CONTEXT)->ra; \
- long new_cfa_; \
- int i_; \
- \
- typedef struct \
- { \
- unsigned long psw_mask; \
- unsigned long psw_addr; \
- unsigned long gprs[16]; \
- unsigned int acrs[16]; \
- unsigned int fpc; \
- unsigned int __pad; \
- double fprs[16]; \
- } __attribute__ ((__aligned__ (8))) sigregs_; \
- \
- sigregs_ *regs_; \
- \
- /* svc $__NR_sigreturn or svc $__NR_rt_sigreturn */ \
- if (pc_[0] != 0x0a || (pc_[1] != 119 && pc_[1] != 173)) \
- break; \
- \
- /* New-style RT frame: \
- retcode + alignment (8 bytes) \
- siginfo (128 bytes) \
- ucontext (contains sigregs) */ \
- if ((CONTEXT)->ra == (CONTEXT)->cfa) \
- { \
- struct ucontext_ \
- { \
- unsigned long uc_flags; \
- struct ucontext_ *uc_link; \
- unsigned long uc_stack[3]; \
- sigregs_ uc_mcontext; \
- } *uc_ = (CONTEXT)->cfa + 8 + 128; \
- \
- regs_ = &uc_->uc_mcontext; \
- } \
- \
- /* Old-style RT frame and all non-RT frames: \
- old signal mask (8 bytes) \
- pointer to sigregs */ \
- else \
- { \
- regs_ = *(sigregs_ **)((CONTEXT)->cfa + 8); \
- } \
- \
- new_cfa_ = regs_->gprs[15] + 16*sizeof(long) + 32; \
- (FS)->cfa_how = CFA_REG_OFFSET; \
- (FS)->cfa_reg = 15; \
- (FS)->cfa_offset = \
- new_cfa_ - (long) (CONTEXT)->cfa + 16*sizeof(long) + 32; \
- \
- for (i_ = 0; i_ < 16; i_++) \
- { \
- (FS)->regs.reg[i_].how = REG_SAVED_OFFSET; \
- (FS)->regs.reg[i_].loc.offset = \
- (long)&regs_->gprs[i_] - new_cfa_; \
- } \
- for (i_ = 0; i_ < 16; i_++) \
- { \
- (FS)->regs.reg[16+i_].how = REG_SAVED_OFFSET; \
- (FS)->regs.reg[16+i_].loc.offset = \
- (long)&regs_->fprs[i_] - new_cfa_; \
- } \
- \
- /* Load return addr from PSW into dummy register 32. */ \
- (FS)->regs.reg[32].how = REG_SAVED_OFFSET; \
- (FS)->regs.reg[32].loc.offset = (long)&regs_->psw_addr - new_cfa_; \
- (FS)->retaddr_column = 32; \
- \
- goto SUCCESS; \
- } while (0)
+#define MD_UNWIND_SUPPORT "config/s390/linux-unwind.h"
+
+#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/contrib/gcc/config/s390/predicates.md b/contrib/gcc/config/s390/predicates.md
new file mode 100644
index 0000000..9f7ea36
--- /dev/null
+++ b/contrib/gcc/config/s390/predicates.md
@@ -0,0 +1,379 @@
+;; Predicate definitions for S/390 and zSeries.
+;; Copyright (C) 2005 Free Software Foundation, Inc.
+;; Contributed by Hartmut Penner (hpenner@de.ibm.com) and
+;; Ulrich Weigand (uweigand@de.ibm.com).
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING. If not, write to
+;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+;; 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_FLAGS (op) & SYMBOL_FLAG_ALIGN1) == 0
+ && SYMBOL_REF_TLS_MODEL (op) == 0
+ && (!flag_pic || SYMBOL_REF_LOCAL_P (op)));
+
+ /* Everything else must have a CONST, so strip it. */
+ if (GET_CODE (op) != CONST)
+ return 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 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/contrib/gcc/config/s390/s390-modes.def b/contrib/gcc/config/s390/s390-modes.def
index 0875955..afcfb1b 100644
--- a/contrib/gcc/config/s390/s390-modes.def
+++ b/contrib/gcc/config/s390/s390-modes.def
@@ -1,5 +1,5 @@
/* Definitions of target machine for GNU compiler, for IBM S/390
- Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
Contributed by Hartmut Penner (hpenner@de.ibm.com) and
Ulrich Weigand (uweigand@de.ibm.com).
@@ -17,21 +17,154 @@ for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
/* 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);
diff --git a/contrib/gcc/config/s390/s390-protos.h b/contrib/gcc/config/s390/s390-protos.h
index 90815a8..8b2db85 100644
--- a/contrib/gcc/config/s390/s390-protos.h
+++ b/contrib/gcc/config/s390/s390-protos.h
@@ -1,5 +1,5 @@
/* Definitions of target machine for GNU compiler, for IBM S/390.
- Copyright (C) 2000, 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
Contributed by Hartmut Penner (hpenner@de.ibm.com)
This file is part of GCC.
@@ -16,52 +16,64 @@ for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
+
+
+
+/* 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);
+
+
/* Declare functions in s390.c. */
extern void optimization_options (int, int);
extern void override_options (void);
-extern HOST_WIDE_INT s390_arg_frame_offset (void);
-extern void s390_load_got (int);
+extern bool s390_can_eliminate (int, int);
+extern HOST_WIDE_INT s390_initial_elimination_offset (int, int);
extern void s390_emit_prologue (void);
-extern void s390_emit_epilogue (void);
+extern void s390_emit_epilogue (bool);
extern void s390_function_profiler (FILE *, int);
+extern void s390_conditional_register_usage (void);
+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 bool 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 const0_operand (rtx, enum machine_mode);
-extern int consttable_operand (rtx, enum machine_mode);
-extern int larl_operand (rtx, enum machine_mode);
-extern int s_operand (rtx, enum machine_mode);
-extern int s_imm_operand (rtx, enum machine_mode);
-extern int shift_count_operand (rtx, enum machine_mode);
-extern int bras_sym_operand (rtx, enum machine_mode);
-extern int load_multiple_operation (rtx, enum machine_mode);
-extern int store_multiple_operation (rtx, enum machine_mode);
+extern int s390_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_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 int s390_match_ccmode (rtx, enum machine_mode);
-extern enum machine_mode s390_tm_ccmode (rtx, rtx, int);
+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 int s390_alc_comparison (rtx op, enum machine_mode mode);
-extern int s390_slb_comparison (rtx op, enum machine_mode mode);
-extern int symbolic_reference_mentioned_p (rtx);
-extern int tls_symbolic_reference_mentioned_p (rtx);
-extern rtx s390_tls_get_offset (void);
-extern int legitimate_la_operand_p (rtx);
-extern int preferred_la_operand_p (rtx);
+extern 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 int legitimate_constant_p (rtx);
-extern int legitimate_reload_constant_p (rtx);
-extern int legitimate_address_p (enum machine_mode, rtx, int);
+extern bool legitimate_reload_constant_p (rtx);
+extern bool legitimate_address_p (enum machine_mode, rtx, int);
extern rtx legitimize_pic_address (rtx, rtx);
extern rtx legitimize_address (rtx, rtx, enum machine_mode);
+extern rtx legitimize_reload_address (rtx, enum machine_mode, int, int);
extern enum reg_class s390_preferred_reload_class (rtx, enum reg_class);
extern enum reg_class s390_secondary_input_reload_class (enum reg_class,
enum machine_mode,
@@ -69,37 +81,49 @@ extern enum reg_class s390_secondary_input_reload_class (enum reg_class,
extern enum reg_class s390_secondary_output_reload_class (enum reg_class,
enum machine_mode,
rtx);
-extern int s390_plus_operand (rtx, enum machine_mode);
extern void s390_expand_plus_operand (rtx, rtx, rtx);
extern void emit_symbolic_move (rtx *);
extern void s390_load_address (rtx, rtx);
-extern void s390_expand_movstr (rtx, rtx, rtx);
-extern void s390_expand_clrstr (rtx, rtx);
+extern void s390_expand_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 s390_output_symbolic_const (FILE *, rtx);
+extern bool s390_output_addr_const_extra (FILE*, rtx);
extern void print_operand_address (FILE *, rtx);
extern void print_operand (FILE *, rtx, int);
-extern void s390_output_constant_pool (rtx, rtx);
-extern void s390_output_pool_entry (FILE *, rtx, enum machine_mode,
- unsigned int);
+extern void s390_output_pool_entry (rtx, enum machine_mode, unsigned int);
extern void s390_trampoline_template (FILE *);
extern void s390_initialize_trampoline (rtx, rtx, rtx);
extern rtx s390_gen_rtx_const_DI (int, int);
-extern void s390_output_dwarf_dtprel (FILE*, int, rtx);
extern int s390_agen_dep_p (rtx, rtx);
+extern 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);
#endif /* RTX_CODE */
#ifdef TREE_CODE
-extern int s390_function_arg_pass_by_reference (enum machine_mode, tree);
extern void s390_function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode,
tree, int);
#ifdef RTX_CODE
extern rtx s390_function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, int);
extern rtx s390_function_value (tree, enum machine_mode);
extern void s390_va_start (tree, rtx);
-extern rtx s390_va_arg (tree, tree);
#endif /* RTX_CODE */
#endif /* TREE_CODE */
diff --git a/contrib/gcc/config/s390/s390.c b/contrib/gcc/config/s390/s390.c
index ced0bf9..86b4b7e 100644
--- a/contrib/gcc/config/s390/s390.c
+++ b/contrib/gcc/config/s390/s390.c
@@ -1,5 +1,5 @@
/* Subroutines used for code generation on IBM S/390 and zSeries
- Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
+ Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
Contributed by Hartmut Penner (hpenner@de.ibm.com) and
Ulrich Weigand (uweigand@de.ibm.com).
@@ -18,8 +18,8 @@ for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
#include "config.h"
#include "system.h"
@@ -50,116 +50,166 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "debug.h"
#include "langhooks.h"
#include "optabs.h"
+#include "tree-gimple.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 dxr;
+ const int ddbr;
+ const int ddr;
+ const int debr;
+ const int der;
+ const int dlgr;
+ const int dlr;
+ const int dr;
+ const int dsgfr;
+ const int dsgr;
+};
-/* Machine-specific symbol_ref flags. */
-#define SYMBOL_FLAG_ALIGN1 (SYMBOL_FLAG_MACH_DEP << 0)
-
-
-static bool s390_assemble_integer (rtx, unsigned int, int);
-static void s390_select_rtx_section (enum machine_mode, rtx,
- unsigned HOST_WIDE_INT);
-static void s390_encode_section_info (tree, rtx, int);
-static bool s390_cannot_force_const_mem (rtx);
-static rtx s390_delegitimize_address (rtx);
-static bool s390_return_in_memory (tree, tree);
-static void s390_init_builtins (void);
-static rtx s390_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
-static void s390_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
- HOST_WIDE_INT, tree);
-static enum attr_type s390_safe_attr_type (rtx);
-
-static int s390_adjust_cost (rtx, rtx, rtx, int);
-static int s390_adjust_priority (rtx, int);
-static int s390_issue_rate (void);
-static int s390_use_dfa_pipeline_interface (void);
-static int s390_first_cycle_multipass_dfa_lookahead (void);
-static int s390_sched_reorder2 (FILE *, int, rtx *, int *, int);
-static bool s390_rtx_costs (rtx, int, int, int *);
-static int s390_address_cost (rtx);
-static void s390_reorg (void);
-static bool s390_valid_pointer_mode (enum machine_mode);
-static tree s390_build_builtin_va_list (void);
-
-#undef TARGET_ASM_ALIGNED_HI_OP
-#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
-#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_ASM_SELECT_RTX_SECTION
-#define TARGET_ASM_SELECT_RTX_SECTION s390_select_rtx_section
-
-#undef TARGET_ENCODE_SECTION_INFO
-#define TARGET_ENCODE_SECTION_INFO s390_encode_section_info
-
-#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_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_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_tree_hwi_hwi_tree_true
-
-#undef TARGET_SCHED_ADJUST_COST
-#define TARGET_SCHED_ADJUST_COST s390_adjust_cost
-#undef TARGET_SCHED_ADJUST_PRIORITY
-#define TARGET_SCHED_ADJUST_PRIORITY s390_adjust_priority
-#undef TARGET_SCHED_ISSUE_RATE
-#define TARGET_SCHED_ISSUE_RATE s390_issue_rate
-#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
-#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE s390_use_dfa_pipeline_interface
-#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
-#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD s390_first_cycle_multipass_dfa_lookahead
-#undef TARGET_SCHED_REORDER2
-#define TARGET_SCHED_REORDER2 s390_sched_reorder2
-
-#undef TARGET_RTX_COSTS
-#define TARGET_RTX_COSTS s390_rtx_costs
-#undef TARGET_ADDRESS_COST
-#define TARGET_ADDRESS_COST s390_address_cost
-
-#undef TARGET_MACHINE_DEPENDENT_REORG
-#define TARGET_MACHINE_DEPENDENT_REORG s390_reorg
-
-#undef TARGET_VALID_POINTER_MODE
-#define TARGET_VALID_POINTER_MODE s390_valid_pointer_mode
+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 (135), /* DXR */
+ COSTS_N_INSNS (30), /* DDBR */
+ COSTS_N_INSNS (30), /* DDR */
+ COSTS_N_INSNS (27), /* DEBR */
+ COSTS_N_INSNS (26), /* DER */
+ 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 */
+};
-#undef TARGET_BUILD_BUILTIN_VA_LIST
-#define TARGET_BUILD_BUILTIN_VA_LIST s390_build_builtin_va_list
+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 (72), /* DXR */
+ COSTS_N_INSNS (40), /* DDBR */
+ COSTS_N_INSNS (44), /* DDR */
+ COSTS_N_INSNS (26), /* DDBR */
+ COSTS_N_INSNS (28), /* DER */
+ 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 */
+};
-struct gcc_target targetm = TARGET_INITIALIZER;
+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 (72), /* DXR */
+ COSTS_N_INSNS (40), /* DDBR */
+ COSTS_N_INSNS (37), /* DDR */
+ COSTS_N_INSNS (26), /* DDBR */
+ COSTS_N_INSNS (28), /* DER */
+ 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 */
+};
extern int reload_completed;
-/* The alias set for prologue/epilogue register save/restore. */
-static int s390_sr_alias_set = 0;
-
/* Save information from a "cmpxx" operation until the branch or scc is
emitted. */
rtx s390_compare_op0, s390_compare_op1;
+/* Save the result of a compare_and_swap until the branch or scc is
+ emitted. */
+rtx s390_compare_emitted = NULL_RTX;
+
/* Structure used to hold the components of a S/390 memory
address. A legitimate address on S/390 is of the general
form
@@ -174,88 +224,179 @@ struct s390_address
rtx base;
rtx indx;
rtx disp;
- int pointer;
+ bool pointer;
+ bool literal_pool;
};
/* Which cpu are we tuning for. */
-enum processor_type s390_tune;
+enum processor_type s390_tune = PROCESSOR_max;
enum processor_flags s390_tune_flags;
/* Which instruction set architecture to use. */
enum processor_type s390_arch;
enum processor_flags s390_arch_flags;
-/* Strings to hold which cpu and instruction set architecture to use. */
-const char *s390_tune_string; /* for -mtune=<xxx> */
-const char *s390_arch_string; /* for -march=<xxx> */
+HOST_WIDE_INT s390_warn_framesize = 0;
+HOST_WIDE_INT s390_stack_size = 0;
+HOST_WIDE_INT s390_stack_guard = 0;
-/* Define the structure for the machine field in struct function. */
+/* The following structure is embedded in the machine
+ specific part of struct function. */
-struct machine_function GTY(())
+struct s390_frame_layout GTY (())
{
- /* Set, if some of the fprs 8-15 need to be saved (64 bit abi). */
- int save_fprs_p;
+ /* 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;
- /* Set if return address needs to be saved. */
- bool save_return_addr_p;
+ /* 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 machine_function GTY(())
+{
+ 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;
+
+ /* True during final stage of literal pool processing. */
+ bool decomposed_literal_pool_addresses_ok_p;
/* Some local-dynamic TLS symbol name. */
const char *some_ld_name;
+
+ bool has_landing_pad_p;
};
-static int s390_match_ccmode_set (rtx, enum machine_mode);
-static int s390_branch_condition_mask (rtx);
-static const char *s390_branch_condition_mnemonic (rtx, int);
-static int check_mode (rtx, enum machine_mode *);
-static int general_s_operand (rtx, enum machine_mode, int);
-static int s390_short_displacement (rtx);
-static int s390_decompose_address (rtx, struct s390_address *);
-static rtx get_thread_pointer (void);
-static rtx legitimize_tls_address (rtx, rtx);
-static void print_shift_count_operand (FILE *, rtx);
-static const char *get_some_local_dynamic_name (void);
-static int get_some_local_dynamic_name_1 (rtx *, void *);
-static int reg_used_in_mem_p (int, rtx);
-static int addr_generation_dependency_p (rtx, rtx);
-static int s390_split_branches (void);
-static void find_constant_pool_ref (rtx, rtx *);
-static void replace_constant_pool_ref (rtx *, rtx, rtx);
-static rtx find_ltrel_base (rtx);
-static void replace_ltrel_base (rtx *, rtx);
-static void s390_optimize_prolog (bool);
-static int find_unused_clobbered_reg (void);
-static void s390_frame_info (void);
-static rtx save_fpr (rtx, int, int);
-static rtx restore_fpr (rtx, int, int);
-static rtx save_gprs (rtx, int, int, int);
-static rtx restore_gprs (rtx, int, int, int);
-static int s390_function_arg_size (enum machine_mode, tree);
-static bool s390_function_arg_float (enum machine_mode, tree);
-static struct machine_function * s390_init_machine_status (void);
-
-/* Check whether integer displacement is in range. */
-#define DISP_IN_RANGE(d) \
- (TARGET_LONG_DISPLACEMENT? ((d) >= -524288 && (d) <= 524287) \
- : ((d) >= 0 && (d) <= 4095))
+/* 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_WORD)
+#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))
+
+/* Return true if the back end supports mode MODE. */
+static bool
+s390_scalar_mode_supported_p (enum machine_mode mode)
+{
+ if (DECIMAL_FLOAT_MODE_P (mode))
+ return true;
+ else
+ 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 int
+static bool
s390_match_ccmode_set (rtx set, enum machine_mode req_mode)
{
enum machine_mode set_mode;
- if (GET_CODE (set) != SET)
- abort ();
+ gcc_assert (GET_CODE (set) == SET);
if (GET_CODE (SET_DEST (set)) != REG || !CC_REGNO_P (REGNO (SET_DEST (set))))
return 1;
@@ -270,6 +411,7 @@ s390_match_ccmode_set (rtx set, enum machine_mode req_mode)
case CCLmode:
case CCL1mode:
case CCL2mode:
+ case CCL3mode:
case CCT1mode:
case CCT2mode:
case CCT3mode:
@@ -290,7 +432,7 @@ s390_match_ccmode_set (rtx set, enum machine_mode req_mode)
break;
default:
- abort ();
+ gcc_unreachable ();
}
return (GET_MODE (SET_SRC (set)) == set_mode);
@@ -301,14 +443,14 @@ s390_match_ccmode_set (rtx set, enum machine_mode req_mode)
CC mode is at least as constrained as REQ_MODE.
If REQ_MODE is VOIDmode, always return false. */
-int
+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 0;
+ return false;
if (GET_CODE (PATTERN (insn)) == SET)
return s390_match_ccmode_set (PATTERN (insn), req_mode);
@@ -319,10 +461,10 @@ s390_match_ccmode (rtx insn, enum machine_mode req_mode)
rtx set = XVECEXP (PATTERN (insn), 0, i);
if (GET_CODE (set) == SET)
if (!s390_match_ccmode_set (set, req_mode))
- return 0;
+ return false;
}
- return 1;
+ return true;
}
/* If a test-under-mask instruction can be used to implement
@@ -333,7 +475,7 @@ s390_match_ccmode (rtx insn, enum machine_mode req_mode)
if the instruction cannot (TM). */
enum machine_mode
-s390_tm_ccmode (rtx op1, rtx op2, int mixed)
+s390_tm_ccmode (rtx op1, rtx op2, bool mixed)
{
int bit0, bit1;
@@ -341,15 +483,20 @@ s390_tm_ccmode (rtx op1, rtx op2, int mixed)
if (GET_CODE (op1) != CONST_INT || GET_CODE (op2) != CONST_INT)
return VOIDmode;
- /* Selected bits all zero: CC0. */
+ /* 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. */
+ /* 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. */
+ /* 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));
@@ -372,8 +519,11 @@ s390_select_ccmode (enum rtx_code code, rtx op0, rtx op1)
{
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_CONSTRAINT_P (INTVAL (XEXP (op0, 1)), 'K', "K"))
+ && CONST_OK_FOR_K (INTVAL (XEXP (op0, 1))))
return CCAPmode;
if ((GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS
|| GET_CODE (op1) == NEG)
@@ -408,14 +558,28 @@ s390_select_ccmode (enum rtx_code code, rtx op0, rtx op1)
case LT:
case GE:
case GT:
- if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 1)) == CONST_INT
- && CONST_OK_FOR_CONSTRAINT_P (INTVAL (XEXP (op0, 1)), 'K', "K"))
- {
- if (INTVAL (XEXP((op0), 1)) < 0)
- return CCANmode;
- else
- return CCAPmode;
- }
+ /* 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:
@@ -452,98 +616,208 @@ s390_select_ccmode (enum rtx_code code, rtx op0, rtx op1)
return CCUmode;
default:
- abort ();
+ gcc_unreachable ();
}
}
-/* Return nonzero if OP is a valid comparison operator
- for an ALC condition in mode MODE. */
+/* Replace the comparison OP0 CODE OP1 by a semantically equivalent one
+ that we can implement more efficiently. */
-int
-s390_alc_comparison (rtx op, enum machine_mode mode)
-{
- if (mode != VOIDmode && mode != GET_MODE (op))
- return 0;
+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;
- if (GET_RTX_CLASS (GET_CODE (op)) != '<')
- return 0;
+ *op0 = gen_rtx_AND (GET_MODE (inner), inner,
+ gen_int_mode (block, GET_MODE (inner)));
+ }
+ }
- if (GET_CODE (XEXP (op, 0)) != REG
- || REGNO (XEXP (op, 0)) != CC_REGNUM
- || XEXP (op, 1) != const0_rtx)
- return 0;
+ /* 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);
+ }
+ }
+ }
- switch (GET_MODE (XEXP (op, 0)))
+ /* 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)
{
- case CCL1mode:
- return GET_CODE (op) == LTU;
-
- case CCL2mode:
- return GET_CODE (op) == LEU;
+ *op0 = gen_lowpart (HImode, *op0);
+ *op1 = constm1_rtx;
+ }
- case CCUmode:
- return GET_CODE (op) == GTU;
- case CCURmode:
- return GET_CODE (op) == LTU;
+ /* Remove redundant UNSPEC_CMPINT conversions if possible. */
+ if (GET_CODE (*op0) == UNSPEC
+ && XINT (*op0, 1) == UNSPEC_CMPINT
+ && 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;
+ }
- case CCSmode:
- return GET_CODE (op) == UNGT;
+ if (new_code != UNKNOWN)
+ {
+ *op0 = XVECEXP (*op0, 0, 0);
+ *code = new_code;
+ }
+ }
- case CCSRmode:
- return GET_CODE (op) == UNLT;
+ /* 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);
+ }
- default:
- return 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);
}
}
-/* Return nonzero if OP is a valid comparison operator
- for an SLB condition in mode MODE. */
+/* 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. */
-int
-s390_slb_comparison (rtx op, enum machine_mode mode)
+rtx
+s390_emit_compare (enum rtx_code code, rtx op0, rtx op1)
{
- if (mode != VOIDmode && mode != GET_MODE (op))
- return 0;
+ enum machine_mode mode = s390_select_ccmode (code, op0, op1);
+ rtx ret = NULL_RTX;
- if (GET_RTX_CLASS (GET_CODE (op)) != '<')
- return 0;
+ /* Do not output a redundant compare instruction if a compare_and_swap
+ pattern already computed the result and the machine modes are compatible. */
+ if (s390_compare_emitted
+ && (s390_cc_modes_compatible (GET_MODE (s390_compare_emitted), mode)
+ == GET_MODE (s390_compare_emitted)))
+ ret = gen_rtx_fmt_ee (code, VOIDmode, s390_compare_emitted, const0_rtx);
+ else
+ {
+ rtx cc = gen_rtx_REG (mode, CC_REGNUM);
+
+ emit_insn (gen_rtx_SET (VOIDmode, cc, gen_rtx_COMPARE (mode, op0, op1)));
+ ret = gen_rtx_fmt_ee (code, VOIDmode, cc, const0_rtx);
+ }
+ s390_compare_emitted = NULL_RTX;
+ return ret;
+}
- if (GET_CODE (XEXP (op, 0)) != REG
- || REGNO (XEXP (op, 0)) != CC_REGNUM
- || XEXP (op, 1) != const0_rtx)
- return 0;
+/* Emit a SImode compare and swap instruction setting MEM to NEW if OLD
+ matches CMP.
+ Return the correct condition RTL to be placed in the IF_THEN_ELSE of the
+ conditional branch testing the result. */
- switch (GET_MODE (XEXP (op, 0)))
- {
- case CCL1mode:
- return GET_CODE (op) == GEU;
+static rtx
+s390_emit_compare_and_swap (enum rtx_code code, rtx old, rtx mem, rtx cmp, rtx new)
+{
+ rtx ret;
- case CCL2mode:
- return GET_CODE (op) == GTU;
+ emit_insn (gen_sync_compare_and_swap_ccsi (old, mem, cmp, new));
+ ret = gen_rtx_fmt_ee (code, VOIDmode, s390_compare_emitted, const0_rtx);
- case CCUmode:
- return GET_CODE (op) == LEU;
+ s390_compare_emitted = NULL_RTX;
- case CCURmode:
- return GET_CODE (op) == GEU;
+ return ret;
+}
- case CCSmode:
- return GET_CODE (op) == LE;
+/* Emit a jump instruction to TARGET. If COND is NULL_RTX, emit an
+ unconditional jump, else a conditional jump under condition COND. */
- case CCSRmode:
- return GET_CODE (op) == GE;
+void
+s390_emit_jump (rtx target, rtx cond)
+{
+ rtx insn;
- default:
- return 0;
- }
+ 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. */
+ specified by CODE. Return -1 for invalid comparisons. */
-static int
+int
s390_branch_condition_mask (rtx code)
{
const int CC0 = 1 << 3;
@@ -551,20 +825,19 @@ s390_branch_condition_mask (rtx code)
const int CC2 = 1 << 1;
const int CC3 = 1 << 0;
- if (GET_CODE (XEXP (code, 0)) != REG
- || REGNO (XEXP (code, 0)) != CC_REGNUM
- || XEXP (code, 1) != const0_rtx)
- abort ();
+ 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:
- abort ();
+ default: return -1;
}
break;
@@ -573,8 +846,7 @@ s390_branch_condition_mask (rtx code)
{
case EQ: return CC1;
case NE: return CC0 | CC2 | CC3;
- default:
- abort ();
+ default: return -1;
}
break;
@@ -583,8 +855,7 @@ s390_branch_condition_mask (rtx code)
{
case EQ: return CC2;
case NE: return CC0 | CC1 | CC3;
- default:
- abort ();
+ default: return -1;
}
break;
@@ -593,8 +864,7 @@ s390_branch_condition_mask (rtx code)
{
case EQ: return CC3;
case NE: return CC0 | CC1 | CC2;
- default:
- abort ();
+ default: return -1;
}
break;
@@ -603,8 +873,7 @@ s390_branch_condition_mask (rtx code)
{
case EQ: return CC0 | CC2;
case NE: return CC1 | CC3;
- default:
- abort ();
+ default: return -1;
}
break;
@@ -613,8 +882,7 @@ s390_branch_condition_mask (rtx code)
{
case LTU: return CC2 | CC3; /* carry */
case GEU: return CC0 | CC1; /* no carry */
- default:
- abort ();
+ default: return -1;
}
break;
@@ -623,11 +891,22 @@ s390_branch_condition_mask (rtx code)
{
case GTU: return CC0 | CC1; /* borrow */
case LEU: return CC2 | CC3; /* no borrow */
- default:
- abort ();
+ 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))
{
@@ -637,8 +916,7 @@ s390_branch_condition_mask (rtx code)
case GTU: return CC2;
case LEU: return CC0 | CC1;
case GEU: return CC0 | CC2;
- default:
- abort ();
+ default: return -1;
}
break;
@@ -651,8 +929,7 @@ s390_branch_condition_mask (rtx code)
case GTU: return CC1;
case LEU: return CC0 | CC2;
case GEU: return CC0 | CC1;
- default:
- abort ();
+ default: return -1;
}
break;
@@ -665,8 +942,7 @@ s390_branch_condition_mask (rtx code)
case GT: return CC2;
case LE: return CC0 | CC1 | CC3;
case GE: return CC0 | CC2;
- default:
- abort ();
+ default: return -1;
}
break;
@@ -679,8 +955,7 @@ s390_branch_condition_mask (rtx code)
case GT: return CC2 | CC3;
case LE: return CC0 | CC1;
case GE: return CC0 | CC2 | CC3;
- default:
- abort ();
+ default: return -1;
}
break;
@@ -701,8 +976,7 @@ s390_branch_condition_mask (rtx code)
case UNLE: return CC0 | CC1 | CC3;
case UNGE: return CC0 | CC2 | CC3;
case LTGT: return CC1 | CC2;
- default:
- abort ();
+ default: return -1;
}
break;
@@ -723,13 +997,12 @@ s390_branch_condition_mask (rtx code)
case UNLE: return CC0 | CC2 | CC3;
case UNGE: return CC0 | CC1 | CC3;
case LTGT: return CC2 | CC1;
- default:
- abort ();
+ default: return -1;
}
break;
default:
- abort ();
+ return -1;
}
}
@@ -749,19 +1022,19 @@ s390_branch_condition_mnemonic (rtx code, int inv)
};
int mask = s390_branch_condition_mask (code);
+ gcc_assert (mask >= 0);
if (inv)
mask ^= 15;
- if (mask < 1 || mask > 14)
- abort ();
+ 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
+ Use this function only if you already know that op really
contains such a part. */
unsigned HOST_WIDE_INT
@@ -770,21 +1043,22 @@ 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 = (1 << part_bits) - 1;
+ 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;
}
-
- abort ();
+
+ gcc_unreachable ();
}
/* If OP is an integer constant of mode MODE with exactly one
@@ -792,26 +1066,27 @@ s390_extract_part (rtx op, enum machine_mode mode, int def)
part. Otherwise, return -1. */
int
-s390_single_part (rtx op,
- enum machine_mode mode,
+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 = (1 << GET_MODE_BITSIZE (part_mode)) - 1;
+ 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)
@@ -855,6 +1130,169 @@ s390_split_ok_p (rtx dst, rtx src, enum machine_mode mode, int first_subword)
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 (sizeof (struct machine_function));
+}
/* Change optimizations to be performed, depending on the
optimization level.
@@ -873,12 +1311,20 @@ optimization_options (int level ATTRIBUTE_UNUSED, int size ATTRIBUTE_UNUSED)
/* By default, always emit DWARF-2 unwind info. This allows debugging
without maintaining a stack frame back-chain. */
flag_asynchronous_unwind_tables = 1;
+
+ /* Use MVCLE instructions to decrease code size if requested. */
+ if (size != 0)
+ target_flags |= MASK_MVCLE;
}
-void
-override_options (void)
+/* Return true if ARG is the name of a processor. Set *TYPE and *FLAGS
+ to the associated processor_type and processor_flags if so. */
+
+static bool
+s390_handle_arch_option (const char *arg,
+ enum processor_type *type,
+ enum processor_flags *flags)
{
- int i;
static struct pta
{
const char *const name; /* processor name or nickname. */
@@ -892,13 +1338,59 @@ override_options (void)
{"z900", PROCESSOR_2064_Z900, PF_IEEE_FLOAT | PF_ZARCH},
{"z990", PROCESSOR_2084_Z990, PF_IEEE_FLOAT | PF_ZARCH
| PF_LONG_DISPLACEMENT},
+ {"z9-109", PROCESSOR_2094_Z9_109, PF_IEEE_FLOAT | PF_ZARCH
+ | PF_LONG_DISPLACEMENT | PF_EXTIMM},
};
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE (processor_alias_table); i++)
+ if (strcmp (arg, processor_alias_table[i].name) == 0)
+ {
+ *type = processor_alias_table[i].processor;
+ *flags = processor_alias_table[i].flags;
+ return true;
+ }
+ return false;
+}
+
+/* Implement TARGET_HANDLE_OPTION. */
+
+static bool
+s390_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
+{
+ switch (code)
+ {
+ case OPT_march_:
+ return s390_handle_arch_option (arg, &s390_arch, &s390_arch_flags);
+
+ case OPT_mstack_guard_:
+ if (sscanf (arg, HOST_WIDE_INT_PRINT_DEC, &s390_stack_guard) != 1)
+ return false;
+ if (exact_log2 (s390_stack_guard) == -1)
+ error ("stack guard value must be an exact power of 2");
+ return true;
- int const pta_size = ARRAY_SIZE (processor_alias_table);
+ case OPT_mstack_size_:
+ if (sscanf (arg, HOST_WIDE_INT_PRINT_DEC, &s390_stack_size) != 1)
+ return false;
+ if (exact_log2 (s390_stack_size) == -1)
+ error ("stack size must be an exact power of 2");
+ return true;
+
+ case OPT_mtune_:
+ return s390_handle_arch_option (arg, &s390_tune, &s390_tune_flags);
- /* Acquire a unique set number for our register saves and restores. */
- s390_sr_alias_set = new_alias_set ();
+ case OPT_mwarn_framesize_:
+ return sscanf (arg, HOST_WIDE_INT_PRINT_DEC, &s390_warn_framesize) == 1;
+
+ default:
+ return true;
+ }
+}
+void
+override_options (void)
+{
/* Set up function hooks. */
init_machine_status = s390_init_machine_status;
@@ -913,43 +1405,52 @@ override_options (void)
/* Determine processor architectural level. */
if (!s390_arch_string)
- s390_arch_string = TARGET_ZARCH? "z900" : "g5";
-
- for (i = 0; i < pta_size; i++)
- if (! strcmp (s390_arch_string, processor_alias_table[i].name))
- {
- s390_arch = processor_alias_table[i].processor;
- s390_arch_flags = processor_alias_table[i].flags;
- break;
- }
- if (i == pta_size)
- error ("Unknown cpu used in -march=%s.", s390_arch_string);
+ {
+ s390_arch_string = TARGET_ZARCH? "z900" : "g5";
+ s390_handle_arch_option (s390_arch_string, &s390_arch, &s390_arch_flags);
+ }
/* Determine processor to tune for. */
- if (!s390_tune_string)
+ if (s390_tune == PROCESSOR_max)
{
s390_tune = s390_arch;
s390_tune_flags = s390_arch_flags;
- s390_tune_string = s390_arch_string;
- }
- else
- {
- for (i = 0; i < pta_size; i++)
- if (! strcmp (s390_tune_string, processor_alias_table[i].name))
- {
- s390_tune = processor_alias_table[i].processor;
- s390_tune_flags = processor_alias_table[i].flags;
- break;
- }
- if (i == pta_size)
- error ("Unknown cpu used in -mtune=%s.", s390_tune_string);
}
/* Sanity checks. */
if (TARGET_ZARCH && !(s390_arch_flags & PF_ZARCH))
- error ("z/Architecture mode not supported on %s.", s390_arch_string);
+ 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.");
+ error ("64-bit ABI not supported in ESA/390 mode");
+
+ /* Set processor cost function. */
+ if (s390_tune == PROCESSOR_2094_Z9_109)
+ s390_cost = &z9_109_cost;
+ else if (s390_tune == PROCESSOR_2084_Z990)
+ s390_cost = &z990_cost;
+ else
+ 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)
+ error ("-mstack-size implies use of -mstack-guard");
+ else 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
}
/* Map for smallest class containing reg regno. */
@@ -963,7 +1464,8 @@ const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
- ADDR_REGS, NO_REGS, ADDR_REGS
+ ADDR_REGS, CC_REGS, ADDR_REGS, ADDR_REGS,
+ ACCESS_REGS, ACCESS_REGS
};
/* Return attribute type of insn. */
@@ -977,257 +1479,424 @@ s390_safe_attr_type (rtx insn)
return TYPE_NONE;
}
-/* Return true if OP a (const_int 0) operand.
- OP is the current operation.
- MODE is the current operation mode. */
+/* Return true if DISP is a valid short displacement. */
-int
-const0_operand (register rtx op, enum machine_mode mode)
+static bool
+s390_short_displacement (rtx disp)
{
- return op == CONST0_RTX (mode);
-}
+ /* No displacement is OK. */
+ if (!disp)
+ return true;
-/* Return true if OP is constant.
- OP is the current operation.
- MODE is the current operation mode. */
+ /* Integer displacement in range. */
+ if (GET_CODE (disp) == CONST_INT)
+ return INTVAL (disp) >= 0 && INTVAL (disp) < 4096;
-int
-consttable_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return CONSTANT_P (op);
+ /* 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;
}
-/* Return true if the mode of operand OP matches MODE.
- If MODE is set to VOIDmode, set it to the mode of OP. */
+/* 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
-check_mode (register rtx op, enum machine_mode *mode)
+s390_decompose_address (rtx addr, struct s390_address *out)
{
- if (*mode == VOIDmode)
- *mode = GET_MODE (op);
- else
- {
- if (GET_MODE (op) != VOIDmode && GET_MODE (op) != *mode)
- return 0;
- }
- return 1;
-}
+ 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);
-/* Return true if OP a valid operand for the LARL instruction.
- OP is the current operation.
- MODE is the current operation mode. */
+ /* Decompose address into base + index + displacement. */
-int
-larl_operand (register rtx op, enum machine_mode mode)
-{
- if (! check_mode (op, &mode))
- return 0;
+ if (GET_CODE (addr) == REG || GET_CODE (addr) == UNSPEC)
+ base = addr;
- /* Allow labels and local symbols. */
- if (GET_CODE (op) == LABEL_REF)
- return 1;
- if (GET_CODE (op) == SYMBOL_REF)
- return ((SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_ALIGN1) == 0
- && SYMBOL_REF_TLS_MODEL (op) == 0
- && (!flag_pic || SYMBOL_REF_LOCAL_P (op)));
+ 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);
- /* Everything else must have a CONST, so strip it. */
- if (GET_CODE (op) != CONST)
- return 0;
- op = XEXP (op, 0);
+ 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;
+ }
- /* Allow adding *even* in-range constants. */
- if (GET_CODE (op) == PLUS)
+ else
+ {
+ return false;
+ }
+ }
+
+ else
+ disp = addr; /* displacement */
+
+ /* Extract integer part of displacement. */
+ orig_disp = disp;
+ if (disp)
{
- if (GET_CODE (XEXP (op, 1)) != CONST_INT
- || (INTVAL (XEXP (op, 1)) & 1) != 0)
- return 0;
-#if HOST_BITS_PER_WIDE_INT > 32
- if (INTVAL (XEXP (op, 1)) >= (HOST_WIDE_INT)1 << 32
- || INTVAL (XEXP (op, 1)) < -((HOST_WIDE_INT)1 << 32))
- return 0;
-#endif
- op = XEXP (op, 0);
+ 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);
+ }
}
- /* Labels and local symbols allowed here as well. */
- if (GET_CODE (op) == LABEL_REF)
- return 1;
- if (GET_CODE (op) == SYMBOL_REF)
- return ((SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_ALIGN1) == 0
- && SYMBOL_REF_TLS_MODEL (op) == 0
- && (!flag_pic || SYMBOL_REF_LOCAL_P (op)));
-
- /* Now we must have a @GOTENT offset or @PLT stub
- or an @INDNTPOFF TLS offset. */
- if (GET_CODE (op) == UNSPEC
- && XINT (op, 1) == UNSPEC_GOTENT)
- return 1;
- if (GET_CODE (op) == UNSPEC
- && XINT (op, 1) == UNSPEC_PLT)
- return 1;
- if (GET_CODE (op) == UNSPEC
- && XINT (op, 1) == UNSPEC_INDNTPOFF)
- return 1;
+ /* Strip off CONST here to avoid special case tests later. */
+ if (disp && GET_CODE (disp) == CONST)
+ disp = XEXP (disp, 0);
- return 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;
-/* Helper routine to implement s_operand and s_imm_operand.
- OP is the current operation.
- MODE is the current operation mode.
- ALLOW_IMMEDIATE specifies whether immediate operands should
- be accepted or not. */
+ /* Mark up the displacement. */
+ disp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, disp),
+ UNSPEC_LTREL_OFFSET);
+ }
-static int
-general_s_operand (register rtx op, enum machine_mode mode,
- int allow_immediate)
-{
- struct s390_address addr;
+ /* 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;
- /* Call general_operand first, so that we don't have to
- check for many special cases. */
- if (!general_operand (op, mode))
- return 0;
+ case UNSPEC_LTREL_BASE:
+ if (XVECLEN (base, 0) == 1)
+ base = fake_pool_base, literal_pool = true;
+ else
+ base = XVECEXP (base, 0, 1);
+ break;
- /* 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);
+ default:
+ return false;
+ }
- switch (GET_CODE (op))
+ 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)
{
- /* Constants are OK as s-operand if ALLOW_IMMEDIATE
- is true and we are still before reload. */
- case CONST_INT:
- case CONST_DOUBLE:
- if (!allow_immediate || reload_completed)
- return 0;
- return 1;
+ 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;
- /* Memory operands are OK unless they already use an
- index register. */
- case MEM:
- if (GET_CODE (XEXP (op, 0)) == ADDRESSOF)
- return 1;
- if (!s390_decompose_address (XEXP (op, 0), &addr))
- return 0;
- if (addr.indx)
- return 0;
- /* Do not allow literal pool references unless ALLOW_IMMEDIATE
- is true. This prevents compares between two literal pool
- entries from being accepted. */
- if (!allow_immediate
- && addr.base && REGNO (addr.base) == BASE_REGISTER)
- return 0;
- return 1;
+ case UNSPEC_LTREL_BASE:
+ if (XVECLEN (indx, 0) == 1)
+ indx = fake_pool_base, literal_pool = true;
+ else
+ indx = XVECEXP (indx, 0, 1);
+ break;
- default:
- 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;
}
- return 0;
-}
+ /* 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;
+ }
-/* Return true if OP is a valid S-type operand.
- OP is the current operation.
- MODE is the current operation mode. */
+ /* 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;
-int
-s_operand (register rtx op, enum machine_mode mode)
-{
- return general_s_operand (op, mode, 0);
-}
+ /* 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)
+ {
+ ;
+ }
-/* Return true if OP is a valid S-type operand or an immediate
- operand that can be addressed as S-type operand by forcing
- it into the literal pool.
- OP is the current operation.
- MODE is the current operation mode. */
+ /* Accept chunkified literal pool symbol references. */
+ else if (cfun && cfun->machine
+ && cfun->machine->decomposed_literal_pool_addresses_ok_p
+ && GET_CODE (disp) == MINUS
+ && GET_CODE (XEXP (disp, 0)) == LABEL_REF
+ && GET_CODE (XEXP (disp, 1)) == LABEL_REF)
+ {
+ ;
+ }
-int
-s_imm_operand (register rtx op, enum machine_mode mode)
-{
- return general_s_operand (op, mode, 1);
+ /* Accept literal pool references. */
+ else if (GET_CODE (disp) == UNSPEC
+ && XINT (disp, 1) == UNSPEC_LTREL_OFFSET)
+ {
+ 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;
}
-/* Return true if OP a valid shift count operand.
- OP is the current operation.
- MODE is the current operation mode. */
+/* Decompose a RTL expression OP for a shift count into its components,
+ and return the base register in BASE and the offset in OFFSET.
-int
-shift_count_operand (rtx op, enum machine_mode mode)
-{
- HOST_WIDE_INT offset = 0;
+ Return true if OP is a valid shift count, false if not. */
- if (! check_mode (op, &mode))
- return 0;
+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. Note that reload already checks
- that any register present is an address register, so
- we just check for any register here. */
+ or a sum of the two. */
if (GET_CODE (op) == CONST_INT)
{
- offset = INTVAL (op);
+ off = INTVAL (op);
op = NULL_RTX;
}
if (op && GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT)
{
- offset = INTVAL (XEXP (op, 1));
+ 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 0;
+ 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 0;
+ if (offset)
+ *offset = off;
+ if (base)
+ *base = op;
- return 1;
+ return true;
}
-/* Return true if DISP is a valid short displacement. */
-
-static int
-s390_short_displacement (rtx disp)
-{
- /* No displacement is OK. */
- if (!disp)
- return 1;
- /* Integer displacement in range. */
- if (GET_CODE (disp) == CONST_INT)
- return INTVAL (disp) >= 0 && INTVAL (disp) < 4096;
+/* Return true if CODE is a valid address without index. */
- /* GOT offset is not OK, the GOT can be large. */
- if (GET_CODE (disp) == CONST
- && GET_CODE (XEXP (disp, 0)) == UNSPEC
- && XINT (XEXP (disp, 0), 1) == UNSPEC_GOT)
- return 0;
+bool
+s390_legitimate_address_without_index_p (rtx op)
+{
+ struct s390_address addr;
- /* All other symbolic constants are literal pool references,
- which are OK as the literal pool must be small. */
- if (GET_CODE (disp) == CONST)
- return 1;
+ if (!s390_decompose_address (XEXP (op, 0), &addr))
+ return false;
+ if (addr.indx)
+ return false;
- return 0;
+ return true;
}
-/* Return true if OP is a valid operand for a C constraint. */
+
+/* Evaluates constraint strings described by the regular expression
+ ([A|B](Q|R|S|T))|U|W and returns 1 if OP is a valid operand for the
+ constraint given in STR, or 0 else. */
int
-s390_extra_constraint_str (rtx op, int c, const char * str)
+s390_mem_constraint (const char *str, rtx op)
{
struct s390_address addr;
+ char c = str[0];
+
+ /* Check for offsettable variants of memory constraints. */
+ if (c == 'A')
+ {
+ /* Only accept non-volatile MEMs. */
+ 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;
- if (c != str[0])
- abort ();
+ c = str[1];
+ }
+
+ /* Check for non-literal-pool variants of memory constraints. */
+ else if (c == 'B')
+ {
+ if (GET_CODE (op) != MEM)
+ return 0;
+ if (!s390_decompose_address (XEXP (op, 0), &addr))
+ return 0;
+ if (addr.literal_pool)
+ return 0;
+
+ c = str[1];
+ }
switch (c)
{
@@ -1305,7 +1974,11 @@ s390_extra_constraint_str (rtx op, int c, const char * str)
break;
case 'Y':
- return shift_count_operand (op, VOIDmode);
+ /* 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;
default:
return 0;
@@ -1314,81 +1987,125 @@ s390_extra_constraint_str (rtx op, int c, const char * str)
return 1;
}
-/* Return true if VALUE matches the constraint STR. */
+
+
+/* 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_const_ok_for_constraint_p (HOST_WIDE_INT value,
- int c,
- const char * str)
+s390_O_constraint_str (const char c, HOST_WIDE_INT value)
{
- enum machine_mode mode, part_mode;
- int def;
- unsigned char part;
-
- if (c != str[0])
- abort ();
+ if (!TARGET_EXTIMM)
+ return 0;
- switch (str[0])
+ switch (c)
{
- case 'I':
- return (unsigned int)value < 256;
+ case 's':
+ return trunc_int_for_mode (value, SImode) == value;
- case 'J':
- return (unsigned int)value < 4096;
+ case 'p':
+ return value == 0
+ || s390_single_part (GEN_INT (value), DImode, SImode, 0) == 1;
- case 'K':
- return value >= -32768 && value < 32768;
+ case 'n':
+ return value == -1
+ || s390_single_part (GEN_INT (value), DImode, SImode, -1) == 1;
- case 'L':
- return (TARGET_LONG_DISPLACEMENT ?
- (value >= -524288 && value <= 524287)
- : (value >= 0 && value <= 4095));
- case 'M':
- return value == 2147483647;
+ default:
+ gcc_unreachable ();
+ }
+}
- case 'N':
- part = str[1] - '0';
- switch (str[2])
- {
- case 'H': part_mode = HImode; break;
- case 'Q': part_mode = QImode; break;
- default: return 0;
- }
-
- switch (str[3])
- {
- case 'H': mode = HImode; break;
- case 'S': mode = SImode; break;
- case 'D': mode = DImode; break;
- default: return 0;
- }
+/* 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. */
- switch (str[4])
- {
- case '0': def = 0; break;
- case 'F': def = -1; break;
- default: return 0;
- }
+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 (GET_MODE_SIZE (mode) <= GET_MODE_SIZE (part_mode))
- return 0;
- if (s390_single_part (GEN_INT (value), mode, part_mode, def) != part)
- return 0;
+ 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)));
+}
+
+
/* 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. */
+ 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 *total)
@@ -1396,60 +2113,195 @@ s390_rtx_costs (rtx x, int code, int outer_code, int *total)
switch (code)
{
case CONST:
- if (GET_CODE (XEXP (x, 0)) == MINUS
- && GET_CODE (XEXP (XEXP (x, 0), 1)) != CONST_INT)
- *total = 1000;
- else
- *total = 0;
- return true;
-
case CONST_INT:
- /* Force_const_mem does not work out of reload, because the
- saveable_obstack is set to reload_obstack, which does not
- live long enough. Because of this we cannot use force_const_mem
- in addsi3. This leads to problems with gen_add2_insn with a
- constant greater than a short. Because of that we give an
- addition of greater constants a cost of 3 (reload1.c 10096). */
- /* ??? saveable_obstack no longer exists. */
- if (outer_code == PLUS
- && (INTVAL (x) > 32767 || INTVAL (x) < -32768))
- *total = COSTS_N_INSNS (3);
- else
- *total = 0;
- return true;
-
case LABEL_REF:
case SYMBOL_REF:
case CONST_DOUBLE:
+ case MEM:
*total = 0;
return true;
case ASHIFT:
case ASHIFTRT:
case LSHIFTRT:
- case PLUS:
+ case ROTATE:
+ case ROTATERT:
case AND:
case IOR:
case XOR:
- case MINUS:
case NEG:
case NOT:
*total = COSTS_N_INSNS (1);
- return true;
+ return false;
- case MULT:
- if (GET_MODE (XEXP (x, 0)) == DImode)
- *total = COSTS_N_INSNS (40);
- else
- *total = COSTS_N_INSNS (7);
- return true;
+ case PLUS:
+ case MINUS:
+ /* Check for multiply and add. */
+ if ((GET_MODE (x) == DFmode || GET_MODE (x) == SFmode)
+ && GET_CODE (XEXP (x, 0)) == MULT
+ && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT && TARGET_FUSED_MADD)
+ {
+ /* This is the multiply and add case. */
+ if (GET_MODE (x) == DFmode)
+ *total = s390_cost->madbr;
+ else
+ *total = s390_cost->maebr;
+ *total += rtx_cost (XEXP (XEXP (x, 0), 0), MULT)
+ + rtx_cost (XEXP (XEXP (x, 0), 1), MULT)
+ + rtx_cost (XEXP (x, 1), code);
+ return true; /* Do not do an additional recursive descent. */
+ }
+ *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_64BIT)
+ {
+ 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 DIV:
case UDIV:
- case MOD:
case UMOD:
- *total = COSTS_N_INSNS (33);
- return true;
+ 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_64BIT)
+ *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)
+ {
+ if (TARGET_IEEE_FLOAT)
+ *total = s390_cost->debr;
+ else /* TARGET_IBM_FLOAT */
+ *total = s390_cost->der;
+ }
+ else if (GET_MODE (x) == DFmode)
+ {
+ if (TARGET_IEEE_FLOAT)
+ *total = s390_cost->ddbr;
+ else /* TARGET_IBM_FLOAT */
+ *total = s390_cost->ddr;
+ }
+ else if (GET_MODE (x) == TFmode)
+ {
+ if (TARGET_IEEE_FLOAT)
+ *total = s390_cost->dxbr;
+ else /* TARGET_IBM_FLOAT */
+ *total = s390_cost->dxr;
+ }
+ 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;
@@ -1468,172 +2320,41 @@ s390_address_cost (rtx addr)
return ad.indx? COSTS_N_INSNS (1) + 1 : COSTS_N_INSNS (1);
}
-/* Return true if OP is a valid operand for the BRAS instruction.
- OP is the current operation.
- MODE is the current operation mode. */
-
-int
-bras_sym_operand (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- register enum rtx_code code = GET_CODE (op);
-
- /* Allow SYMBOL_REFs. */
- if (code == SYMBOL_REF)
- return 1;
-
- /* Allow @PLT stubs. */
- if (code == CONST
- && GET_CODE (XEXP (op, 0)) == UNSPEC
- && XINT (XEXP (op, 0), 1) == UNSPEC_PLT)
- return 1;
- return 0;
-}
-
/* If OP is a SYMBOL_REF of a thread-local symbol, return its TLS mode,
otherwise return 0. */
int
-tls_symbolic_operand (register rtx op)
+tls_symbolic_operand (rtx op)
{
if (GET_CODE (op) != SYMBOL_REF)
return 0;
return SYMBOL_REF_TLS_MODEL (op);
}
-/* Return true if OP is a load multiple operation. It is known to be a
- PARALLEL and the first section will be tested.
- OP is the current operation.
- MODE is the current operation mode. */
+/* 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. */
-int
-load_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+void
+s390_split_access_reg (rtx reg, rtx *lo, rtx *hi)
{
- 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 0;
+ gcc_assert (TARGET_64BIT);
+ gcc_assert (ACCESS_REG_P (reg));
+ gcc_assert (GET_MODE (reg) == DImode);
+ gcc_assert (!(REGNO (reg) & 1));
- 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 0;
-
- if (src_addr == frame_pointer_rtx || src_addr == arg_pointer_rtx)
- return 0;
-
- 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 0;
- }
-
- return 1;
+ *lo = gen_rtx_REG (SImode, REGNO (reg) + 1);
+ *hi = gen_rtx_REG (SImode, REGNO (reg));
}
-/* Return true if OP is a store multiple operation. It is known to be a
- PARALLEL and the first section will be tested.
- OP is the current operation.
- MODE is the current operation mode. */
-
-int
-store_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- enum machine_mode elt_mode;
- int count = XVECLEN (op, 0);
- unsigned int src_regno;
- rtx dest_addr;
- 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 0;
-
- 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 0;
-
- if (dest_addr == frame_pointer_rtx || dest_addr == arg_pointer_rtx)
- return 0;
-
- 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 0;
- }
- return 1;
-}
-
-
/* Return true if OP contains a symbol reference */
-int
+bool
symbolic_reference_mentioned_p (rtx op)
{
- register const char *fmt;
- register int i;
+ const char *fmt;
+ int i;
if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
return 1;
@@ -1643,7 +2364,7 @@ symbolic_reference_mentioned_p (rtx op)
{
if (fmt[i] == 'E')
{
- register int j;
+ int j;
for (j = XVECLEN (op, i) - 1; j >= 0; j--)
if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
@@ -1659,11 +2380,11 @@ symbolic_reference_mentioned_p (rtx op)
/* Return true if OP contains a reference to a thread-local symbol. */
-int
+bool
tls_symbolic_reference_mentioned_p (rtx op)
{
- register const char *fmt;
- register int i;
+ const char *fmt;
+ int i;
if (GET_CODE (op) == SYMBOL_REF)
return tls_symbolic_operand (op);
@@ -1673,18 +2394,18 @@ tls_symbolic_reference_mentioned_p (rtx op)
{
if (fmt[i] == 'E')
{
- register int j;
+ int j;
for (j = XVECLEN (op, i) - 1; j >= 0; j--)
if (tls_symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
- return 1;
+ return true;
}
else if (fmt[i] == 'e' && tls_symbolic_reference_mentioned_p (XEXP (op, i)))
- return 1;
+ return true;
}
- return 0;
+ return false;
}
@@ -1693,7 +2414,7 @@ tls_symbolic_reference_mentioned_p (rtx op)
and that OP satisfies CONSTANT_P or is a CONST_DOUBLE. */
int
-legitimate_pic_operand_p (register rtx op)
+legitimate_pic_operand_p (rtx op)
{
/* Accept all non-symbolic constants. */
if (!SYMBOLIC_CONST (op))
@@ -1708,7 +2429,7 @@ legitimate_pic_operand_p (register rtx op)
It is given that OP satisfies CONSTANT_P or is a CONST_DOUBLE. */
int
-legitimate_constant_p (register rtx op)
+legitimate_constant_p (rtx op)
{
/* Accept all non-symbolic constants. */
if (!SYMBOLIC_CONST (op))
@@ -1784,13 +2505,18 @@ s390_cannot_force_const_mem (rtx x)
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:
- abort ();
+ gcc_unreachable ();
}
}
@@ -1800,31 +2526,55 @@ s390_cannot_force_const_mem (rtx x)
a constant that would need to be forced to the literal pool
before it can be used as operand. */
-int
-legitimate_reload_constant_p (register rtx op)
+bool
+legitimate_reload_constant_p (rtx op)
{
/* Accept la(y) operands. */
if (GET_CODE (op) == CONST_INT
&& DISP_IN_RANGE (INTVAL (op)))
- return 1;
+ return true;
- /* Accept l(g)hi operands. */
+ /* Accept l(g)hi/l(g)fi operands. */
if (GET_CODE (op) == CONST_INT
- && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'K', "K"))
- return 1;
+ && (CONST_OK_FOR_K (INTVAL (op)) || CONST_OK_FOR_Os (INTVAL (op))))
+ return true;
/* Accept lliXX operands. */
if (TARGET_ZARCH
- && s390_single_part (op, DImode, HImode, 0) >= 0)
- return 1;
+ && 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 1;
+ return true;
+
+ /* Accept lzXX operands. */
+ if (GET_CODE (op) == CONST_DOUBLE
+ && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, 'G', "G"))
+ 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 0;
+ return false;
}
/* Given an rtx OP being reloaded into a reg required to be in class CLASS,
@@ -1833,12 +2583,6 @@ legitimate_reload_constant_p (register rtx op)
enum reg_class
s390_preferred_reload_class (rtx op, enum reg_class class)
{
- /* This can happen if a floating point constant is being
- reloaded into an integer register. Leave well alone. */
- if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
- && class != FP_REGS)
- return class;
-
switch (GET_CODE (op))
{
/* Constants we cannot reload must be forced into the
@@ -1878,12 +2622,24 @@ s390_preferred_reload_class (rtx op, enum reg_class class)
is not a legitimate operand of the LOAD ADDRESS instruction. */
enum reg_class
-s390_secondary_input_reload_class (enum reg_class class ATTRIBUTE_UNUSED,
+s390_secondary_input_reload_class (enum reg_class class,
enum machine_mode mode, rtx in)
{
if (s390_plus_operand (in, mode))
return ADDR_REGS;
+ if (reg_classes_intersect_p (FP_REGS, class)
+ && mode == TFmode
+ && GET_CODE (in) == MEM
+ && GET_CODE (XEXP (in, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (in, 0), 1)) == CONST_INT
+ && !DISP_IN_RANGE (INTVAL (XEXP (XEXP (in, 0), 1))
+ + GET_MODE_SIZE (mode) - 1))
+ return ADDR_REGS;
+
+ if (reg_classes_intersect_p (CC_REGS, class))
+ return GENERAL_REGS;
+
return NO_REGS;
}
@@ -1897,35 +2653,30 @@ enum reg_class
s390_secondary_output_reload_class (enum reg_class class,
enum machine_mode mode, rtx out)
{
- if ((TARGET_64BIT ? mode == TImode
+ if ((TARGET_64BIT ? (mode == TImode || mode == TFmode)
: (mode == DImode || mode == DFmode))
&& reg_classes_intersect_p (GENERAL_REGS, class)
&& GET_CODE (out) == MEM
- && !offsettable_memref_p (out)
- && !s_operand (out, VOIDmode))
+ && GET_CODE (XEXP (out, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (out, 0), 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (out, 0), 1)) == CONST_INT
+ && !DISP_IN_RANGE (INTVAL (XEXP (XEXP (out, 0), 1))
+ + GET_MODE_SIZE (mode) - 1))
return ADDR_REGS;
- return NO_REGS;
-}
-
-/* Return true if OP is a PLUS that is not a legitimate
- operand for the LA instruction.
- OP is the current operation.
- MODE is the current operation mode. */
-
-int
-s390_plus_operand (register rtx op, enum machine_mode mode)
-{
- if (!check_mode (op, &mode) || mode != Pmode)
- return FALSE;
-
- if (GET_CODE (op) != PLUS)
- return FALSE;
+ if (reg_classes_intersect_p (FP_REGS, class)
+ && mode == TFmode
+ && GET_CODE (out) == MEM
+ && GET_CODE (XEXP (out, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (out, 0), 1)) == CONST_INT
+ && !DISP_IN_RANGE (INTVAL (XEXP (XEXP (out, 0), 1))
+ + GET_MODE_SIZE (mode) - 1))
+ return ADDR_REGS;
- if (legitimate_la_operand_p (op))
- return FALSE;
+ if (reg_classes_intersect_p (CC_REGS, class))
+ return GENERAL_REGS;
- return TRUE;
+ return NO_REGS;
}
/* Generate code to load SRC, which is PLUS that is not a
@@ -1933,15 +2684,15 @@ s390_plus_operand (register rtx op, enum machine_mode mode)
SCRATCH may be used as scratch register. */
void
-s390_expand_plus_operand (register rtx target, register rtx src,
- register rtx scratch)
+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. */
- if (GET_CODE (src) != PLUS || GET_MODE (src) != Pmode)
- abort ();
+ 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
@@ -1952,8 +2703,8 @@ s390_expand_plus_operand (register rtx target, register rtx src,
/* If the address is already strictly valid, there's nothing to do. */
if (!s390_decompose_address (src, &ad)
- || (ad.base && !REG_OK_FOR_BASE_STRICT_P (ad.base))
- || (ad.indx && !REG_OK_FOR_INDEX_STRICT_P (ad.indx)))
+ || (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. */
@@ -1975,7 +2726,7 @@ s390_expand_plus_operand (register rtx target, register rtx src,
if (sum1 == scratch && sum2 == scratch)
{
debug_rtx (src);
- abort ();
+ gcc_unreachable ();
}
src = gen_rtx_PLUS (Pmode, sum1, sum2);
@@ -1988,314 +2739,83 @@ s390_expand_plus_operand (register rtx target, register rtx src,
}
-/* Decompose a RTL expression ADDR for a memory address into
- its components, returned in OUT.
-
- Returns 0 if ADDR is not a valid memory address, nonzero
- 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 (register rtx addr, struct s390_address *out)
-{
- rtx base = NULL_RTX;
- rtx indx = NULL_RTX;
- rtx disp = NULL_RTX;
- int pointer = FALSE;
- int base_ptr = FALSE;
- int indx_ptr = FALSE;
-
- /* Decompose address into base + index + displacement. */
-
- 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 */
-
-
- /* Validate base register. */
- if (base)
- {
- if (GET_CODE (base) == UNSPEC)
- {
- if (XVECLEN (base, 0) != 1 || XINT (base, 1) != UNSPEC_LTREL_BASE)
- return FALSE;
- base = gen_rtx_REG (Pmode, BASE_REGISTER);
- }
-
- if (GET_CODE (base) != REG || GET_MODE (base) != Pmode)
- return FALSE;
-
- if (REGNO (base) == BASE_REGISTER
- || 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;
- }
-
- /* Validate index register. */
- if (indx)
- {
- if (GET_CODE (indx) == UNSPEC)
- {
- if (XVECLEN (indx, 0) != 1 || XINT (indx, 1) != UNSPEC_LTREL_BASE)
- return FALSE;
- indx = gen_rtx_REG (Pmode, BASE_REGISTER);
- }
-
- if (GET_CODE (indx) != REG || GET_MODE (indx) != Pmode)
- return FALSE;
-
- if (REGNO (indx) == BASE_REGISTER
- || 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;
- }
-
- /* 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)
- {
- /* Allow integer constant in range. */
- if (GET_CODE (disp) == CONST_INT)
- {
- /* If the argument pointer is involved, the displacement will change
- later anyway as the argument pointer gets 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 the arg pointer.
- 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)
- {
- if (!DISP_IN_RANGE (INTVAL (disp)))
- return FALSE;
- }
- }
-
- /* In the small-PIC case, the linker converts @GOT
- and @GOTNTPOFF offsets to possible displacements. */
- else if (GET_CODE (disp) == CONST
- && GET_CODE (XEXP (disp, 0)) == UNSPEC
- && (XINT (XEXP (disp, 0), 1) == UNSPEC_GOT
- || XINT (XEXP (disp, 0), 1) == UNSPEC_GOTNTPOFF))
- {
- if (flag_pic != 1)
- return FALSE;
-
- pointer = TRUE;
- }
-
- /* Accept chunkfied literal pool symbol references. */
- else if (GET_CODE (disp) == CONST
- && GET_CODE (XEXP (disp, 0)) == MINUS
- && GET_CODE (XEXP (XEXP (disp, 0), 0)) == LABEL_REF
- && GET_CODE (XEXP (XEXP (disp, 0), 1)) == LABEL_REF)
- {
- pointer = TRUE;
- }
-
- /* Likewise if a constant offset is present. */
- else if (GET_CODE (disp) == CONST
- && GET_CODE (XEXP (disp, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT
- && GET_CODE (XEXP (XEXP (disp, 0), 0)) == MINUS
- && GET_CODE (XEXP (XEXP (XEXP (disp, 0), 0), 0)) == LABEL_REF
- && GET_CODE (XEXP (XEXP (XEXP (disp, 0), 0), 1)) == LABEL_REF)
- {
- pointer = TRUE;
- }
-
- /* We can convert literal pool addresses to
- displacements by basing them off the base register. */
- else
- {
- /* In some cases, we can accept an additional
- small constant offset. Split these off here. */
-
- unsigned int offset = 0;
-
- 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);
- }
-
- /* Now we must have a literal pool address. */
- if (GET_CODE (disp) != SYMBOL_REF
- || !CONSTANT_POOL_ADDRESS_P (disp))
- return FALSE;
-
- /* If we have an offset, make sure it does not
- exceed the size of the constant pool entry. */
- if (offset && offset >= GET_MODE_SIZE (get_pool_mode (disp)))
- return FALSE;
-
- /* Either base or index must be free to
- hold the base register. */
- if (base && indx)
- return FALSE;
-
- /* Convert the address. */
- if (base)
- indx = gen_rtx_REG (Pmode, BASE_REGISTER);
- else
- base = gen_rtx_REG (Pmode, BASE_REGISTER);
-
- disp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, disp),
- UNSPEC_LTREL_OFFSET);
- disp = gen_rtx_CONST (Pmode, disp);
-
- if (offset)
- disp = plus_constant (disp, offset);
-
- pointer = TRUE;
- }
- }
-
- if (!base && !indx)
- pointer = TRUE;
-
- if (out)
- {
- out->base = base;
- out->indx = indx;
- out->disp = disp;
- out->pointer = pointer;
- }
-
- return TRUE;
-}
-
-/* Return nonzero if ADDR is a valid memory address.
+/* Return true if ADDR is a valid memory address.
STRICT specifies whether strict register checking applies. */
-int
+bool
legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
- register rtx addr, int strict)
+ rtx addr, int strict)
{
struct s390_address ad;
if (!s390_decompose_address (addr, &ad))
- return FALSE;
+ return false;
if (strict)
{
- if (ad.base && !REG_OK_FOR_BASE_STRICT_P (ad.base))
- return FALSE;
- if (ad.indx && !REG_OK_FOR_INDEX_STRICT_P (ad.indx))
- return FALSE;
+ 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 && !REG_OK_FOR_BASE_NONSTRICT_P (ad.base))
- return FALSE;
- if (ad.indx && !REG_OK_FOR_INDEX_NONSTRICT_P (ad.indx))
- return FALSE;
+ 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;
}
-/* Return 1 if OP is a valid operand for the LA instruction.
+/* 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. */
-int
-legitimate_la_operand_p (register rtx op)
+bool
+legitimate_la_operand_p (rtx op)
{
struct s390_address addr;
if (!s390_decompose_address (op, &addr))
- return FALSE;
-
- if (TARGET_64BIT || addr.pointer)
- return TRUE;
+ return false;
- return FALSE;
+ return (TARGET_64BIT || addr.pointer);
}
-/* Return 1 if OP is a valid operand for the LA instruction,
- and we prefer to use LA over addition to compute it. */
+/* Return true if it is valid *and* preferable to use LA to
+ compute the sum of OP1 and OP2. */
-int
-preferred_la_operand_p (register rtx op)
+bool
+preferred_la_operand_p (rtx op1, rtx op2)
{
struct s390_address addr;
- if (!s390_decompose_address (op, &addr))
- return FALSE;
+
+ 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;
if (!TARGET_64BIT && !addr.pointer)
- return FALSE;
+ return false;
if (addr.pointer)
- return TRUE;
+ 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 true;
- return FALSE;
+ return false;
}
/* Emit a forced load-address operation to load SRC into DST.
@@ -2336,6 +2856,8 @@ legitimize_pic_address (rtx orig, rtx reg)
rtx new = 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)))
{
@@ -2363,7 +2885,7 @@ legitimize_pic_address (rtx orig, rtx reg)
new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
if (reg != 0)
{
- emit_move_insn (reg, new);
+ s390_load_address (reg, new);
new = reg;
}
}
@@ -2384,8 +2906,7 @@ legitimize_pic_address (rtx orig, rtx reg)
new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOT);
new = gen_rtx_CONST (Pmode, new);
new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
- new = gen_rtx_MEM (Pmode, new);
- RTX_UNCHANGING_P (new) = 1;
+ new = gen_const_mem (Pmode, new);
emit_move_insn (reg, new);
new = reg;
}
@@ -2400,8 +2921,7 @@ legitimize_pic_address (rtx orig, rtx reg)
new = gen_rtx_CONST (Pmode, new);
emit_move_insn (temp, new);
- new = gen_rtx_MEM (Pmode, temp);
- RTX_UNCHANGING_P (new) = 1;
+ new = gen_const_mem (Pmode, temp);
emit_move_insn (reg, new);
new = reg;
}
@@ -2421,8 +2941,7 @@ legitimize_pic_address (rtx orig, rtx reg)
emit_move_insn (temp, addr);
new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
- new = gen_rtx_MEM (Pmode, new);
- RTX_UNCHANGING_P (new) = 1;
+ new = gen_const_mem (Pmode, new);
emit_move_insn (reg, new);
new = reg;
}
@@ -2434,8 +2953,7 @@ legitimize_pic_address (rtx orig, rtx reg)
addr = XEXP (addr, 0);
if (GET_CODE (addr) == UNSPEC)
{
- if (XVECLEN (addr, 0) != 1)
- abort ();
+ gcc_assert (XVECLEN (addr, 0) == 1);
switch (XINT (addr, 1))
{
/* If someone moved a GOT-relative UNSPEC
@@ -2475,7 +2993,7 @@ legitimize_pic_address (rtx orig, rtx reg)
new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
if (reg != 0)
{
- emit_move_insn (reg, new);
+ s390_load_address (reg, new);
new = reg;
}
}
@@ -2483,22 +3001,29 @@ legitimize_pic_address (rtx orig, rtx reg)
/* Everything else cannot happen. */
default:
- abort ();
+ gcc_unreachable ();
}
}
- else if (GET_CODE (addr) != PLUS)
- abort ();
+ 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))
+ 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)
{
@@ -2508,10 +3033,10 @@ legitimize_pic_address (rtx orig, rtx reg)
if (!DISP_IN_RANGE (INTVAL (op1)))
{
- int even = INTVAL (op1) - 1;
+ HOST_WIDE_INT even = INTVAL (op1) - 1;
op0 = gen_rtx_PLUS (Pmode, op0, GEN_INT (even));
op0 = gen_rtx_CONST (Pmode, op0);
- op1 = GEN_INT (1);
+ op1 = const1_rtx;
}
emit_move_insn (temp, op0);
@@ -2519,7 +3044,7 @@ legitimize_pic_address (rtx orig, rtx reg)
if (reg != 0)
{
- emit_move_insn (reg, new);
+ s390_load_address (reg, new);
new = reg;
}
}
@@ -2548,7 +3073,7 @@ legitimize_pic_address (rtx orig, rtx reg)
new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
if (reg != 0)
{
- emit_move_insn (reg, new);
+ s390_load_address (reg, new);
new = reg;
}
}
@@ -2561,8 +3086,7 @@ legitimize_pic_address (rtx orig, rtx reg)
&& GET_CODE (op1) == CONST_INT
&& XINT (op0, 1) == UNSPEC_GOTOFF)
{
- if (XVECLEN (op0, 0) != 1)
- abort ();
+ gcc_assert (XVECLEN (op0, 0) == 1);
new = force_const_mem (Pmode, orig);
}
@@ -2596,28 +3120,39 @@ legitimize_pic_address (rtx orig, rtx reg)
/* Load the thread pointer into a register. */
-static rtx
-get_thread_pointer (void)
+rtx
+s390_get_thread_pointer (void)
{
- rtx tp;
+ rtx tp = gen_reg_rtx (Pmode);
- tp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TP);
- tp = force_reg (Pmode, tp);
+ emit_move_insn (tp, gen_rtx_REG (Pmode, TP_REGNUM));
mark_reg_pointer (tp, BITS_PER_WORD);
return tp;
}
-/* Construct the SYMBOL_REF for the tls_get_offset function. */
+/* 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;
-rtx
-s390_tls_get_offset (void)
+
+static void
+s390_emit_tls_call_insn (rtx result_reg, rtx tls_call)
{
+ rtx insn;
+
+ gcc_assert (flag_pic);
+
if (!s390_tls_symbol)
s390_tls_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tls_get_offset");
- return s390_tls_symbol;
+ 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);
+ CONST_OR_PURE_CALL_P (insn) = 1;
}
/* ADDR contains a thread-local SYMBOL_REF. Generate code to compute
@@ -2638,7 +3173,7 @@ legitimize_tls_address (rtx addr, rtx reg)
new = gen_rtx_CONST (Pmode, tls_call);
new = force_const_mem (Pmode, new);
emit_move_insn (r2, new);
- emit_call_insn (gen_call_value_tls (r2, tls_call));
+ s390_emit_tls_call_insn (r2, tls_call);
insn = get_insns ();
end_sequence ();
@@ -2646,7 +3181,7 @@ legitimize_tls_address (rtx addr, rtx reg)
temp = gen_reg_rtx (Pmode);
emit_libcall_block (insn, temp, r2, new);
- new = gen_rtx_PLUS (Pmode, get_thread_pointer (), temp);
+ new = gen_rtx_PLUS (Pmode, s390_get_thread_pointer (), temp);
if (reg != 0)
{
s390_load_address (reg, new);
@@ -2661,7 +3196,7 @@ legitimize_tls_address (rtx addr, rtx reg)
new = gen_rtx_CONST (Pmode, tls_call);
new = force_const_mem (Pmode, new);
emit_move_insn (r2, new);
- emit_call_insn (gen_call_value_tls (r2, tls_call));
+ s390_emit_tls_call_insn (r2, tls_call);
insn = get_insns ();
end_sequence ();
@@ -2669,7 +3204,7 @@ legitimize_tls_address (rtx addr, rtx reg)
temp = gen_reg_rtx (Pmode);
emit_libcall_block (insn, temp, r2, new);
- new = gen_rtx_PLUS (Pmode, get_thread_pointer (), temp);
+ new = gen_rtx_PLUS (Pmode, s390_get_thread_pointer (), temp);
base = gen_reg_rtx (Pmode);
s390_load_address (base, new);
@@ -2699,8 +3234,7 @@ legitimize_tls_address (rtx addr, rtx reg)
new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTNTPOFF);
new = gen_rtx_CONST (Pmode, new);
new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
- new = gen_rtx_MEM (Pmode, new);
- RTX_UNCHANGING_P (new) = 1;
+ new = gen_const_mem (Pmode, new);
temp = gen_reg_rtx (Pmode);
emit_move_insn (temp, new);
}
@@ -2714,8 +3248,7 @@ legitimize_tls_address (rtx addr, rtx reg)
temp = gen_reg_rtx (Pmode);
emit_move_insn (temp, new);
- new = gen_rtx_MEM (Pmode, temp);
- RTX_UNCHANGING_P (new) = 1;
+ new = gen_const_mem (Pmode, temp);
temp = gen_reg_rtx (Pmode);
emit_move_insn (temp, new);
}
@@ -2734,8 +3267,7 @@ legitimize_tls_address (rtx addr, rtx reg)
emit_move_insn (temp, new);
new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, temp);
- new = gen_rtx_MEM (Pmode, new);
- RTX_UNCHANGING_P (new) = 1;
+ new = gen_const_mem (Pmode, new);
new = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, new, addr), UNSPEC_TLS_LOAD);
temp = gen_reg_rtx (Pmode);
@@ -2753,15 +3285,13 @@ legitimize_tls_address (rtx addr, rtx reg)
emit_move_insn (temp, new);
new = temp;
- new = gen_rtx_MEM (Pmode, new);
- RTX_UNCHANGING_P (new) = 1;
-
+ new = gen_const_mem (Pmode, new);
new = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, new, addr), UNSPEC_TLS_LOAD);
temp = gen_reg_rtx (Pmode);
emit_insn (gen_rtx_SET (Pmode, temp, new));
}
- new = gen_rtx_PLUS (Pmode, get_thread_pointer (), temp);
+ new = gen_rtx_PLUS (Pmode, s390_get_thread_pointer (), temp);
if (reg != 0)
{
s390_load_address (reg, new);
@@ -2776,7 +3306,7 @@ legitimize_tls_address (rtx addr, rtx reg)
temp = gen_reg_rtx (Pmode);
emit_move_insn (temp, new);
- new = gen_rtx_PLUS (Pmode, get_thread_pointer (), temp);
+ new = gen_rtx_PLUS (Pmode, s390_get_thread_pointer (), temp);
if (reg != 0)
{
s390_load_address (reg, new);
@@ -2785,7 +3315,7 @@ legitimize_tls_address (rtx addr, rtx reg)
break;
default:
- abort ();
+ gcc_unreachable ();
}
else if (GET_CODE (addr) == CONST && GET_CODE (XEXP (addr, 0)) == UNSPEC)
@@ -2793,19 +3323,29 @@ legitimize_tls_address (rtx addr, rtx reg)
switch (XINT (XEXP (addr, 0), 1))
{
case UNSPEC_INDNTPOFF:
- if (TARGET_CPU_ZARCH)
- new = addr;
- else
- abort ();
+ gcc_assert (TARGET_CPU_ZARCH);
+ new = addr;
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
+ else if (GET_CODE (addr) == CONST && GET_CODE (XEXP (addr, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST_INT)
+ {
+ new = XEXP (XEXP (addr, 0), 0);
+ if (GET_CODE (new) != SYMBOL_REF)
+ new = gen_rtx_CONST (Pmode, new);
+
+ new = legitimize_tls_address (new, reg);
+ new = plus_constant (new, INTVAL (XEXP (XEXP (addr, 0), 1)));
+ new = force_operand (new, 0);
+ }
+
else
- abort (); /* for now ... */
+ gcc_unreachable (); /* for now ... */
return new;
}
@@ -2837,7 +3377,7 @@ emit_symbolic_move (rtx *operands)
See comments by legitimize_pic_address for details. */
rtx
-legitimize_address (register rtx x, register rtx oldx ATTRIBUTE_UNUSED,
+legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
enum machine_mode mode ATTRIBUTE_UNUSED)
{
rtx constant_term = const0_rtx;
@@ -2849,6 +3389,12 @@ legitimize_address (register rtx x, register rtx oldx ATTRIBUTE_UNUSED,
if (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)
@@ -2892,8 +3438,8 @@ legitimize_address (register rtx x, register rtx oldx ATTRIBUTE_UNUSED,
{
if (GET_CODE (XEXP (x, 0)) == REG)
{
- register rtx temp = gen_reg_rtx (Pmode);
- register rtx val = force_operand (XEXP (x, 1), temp);
+ rtx temp = gen_reg_rtx (Pmode);
+ rtx val = force_operand (XEXP (x, 1), temp);
if (val != temp)
emit_move_insn (temp, val);
@@ -2902,8 +3448,8 @@ legitimize_address (register rtx x, register rtx oldx ATTRIBUTE_UNUSED,
else if (GET_CODE (XEXP (x, 1)) == REG)
{
- register rtx temp = gen_reg_rtx (Pmode);
- register rtx val = force_operand (XEXP (x, 0), temp);
+ rtx temp = gen_reg_rtx (Pmode);
+ rtx val = force_operand (XEXP (x, 0), temp);
if (val != temp)
emit_move_insn (temp, val);
@@ -2917,37 +3463,80 @@ legitimize_address (register rtx x, register rtx oldx ATTRIBUTE_UNUSED,
return x;
}
+/* Try a machine-dependent way of reloading an illegitimate address AD
+ operand. If we find one, push the reload and and return the new address.
+
+ MODE is the mode of the enclosing MEM. OPNUM is the operand number
+ and TYPE is the reload type of the current reload. */
+
+rtx
+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;
+
+ 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 = 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;
+ }
+
+ return NULL_RTX;
+}
+
/* Emit code to move LEN bytes from DST to SRC. */
void
-s390_expand_movstr (rtx dst, rtx src, rtx len)
+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_movstr_short (dst, src, GEN_INT (INTVAL (len) - 1)));
+ emit_insn (gen_movmem_short (dst, src, GEN_INT (INTVAL (len) - 1)));
}
else if (TARGET_MVCLE)
{
- emit_insn (gen_movstr_long (dst, src, convert_to_mode (Pmode, len, 1)));
+ 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;
- tree type;
mode = GET_MODE (len);
if (mode == VOIDmode)
mode = Pmode;
- type = lang_hooks.types.type_for_mode (mode, 1);
- if (!type)
- abort ();
-
dst_addr = gen_reg_rtx (Pmode);
src_addr = gen_reg_rtx (Pmode);
count = gen_reg_rtx (mode);
@@ -2966,16 +3555,16 @@ s390_expand_movstr (rtx dst, rtx src, rtx len)
if (temp != count)
emit_move_insn (count, temp);
- temp = expand_binop (mode, ashr_optab, count, GEN_INT (8), blocks, 1, 0);
+ temp = expand_binop (mode, lshr_optab, count, GEN_INT (8), blocks, 1, 0);
if (temp != blocks)
emit_move_insn (blocks, temp);
- expand_start_loop (1);
- expand_exit_loop_top_cond (0, build (NE_EXPR, type,
- make_tree (type, blocks),
- make_tree (type, const0_rtx)));
+ emit_cmp_and_jump_insns (blocks, const0_rtx,
+ EQ, NULL_RTX, mode, 1, loop_end_label);
+
+ emit_label (loop_start_label);
- emit_insn (gen_movstr_short (dst, src, GEN_INT (255)));
+ 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,
@@ -2985,45 +3574,72 @@ s390_expand_movstr (rtx dst, rtx src, rtx len)
if (temp != blocks)
emit_move_insn (blocks, temp);
- expand_end_loop ();
+ emit_cmp_and_jump_insns (blocks, const0_rtx,
+ EQ, NULL_RTX, mode, 1, loop_end_label);
- emit_insn (gen_movstr_short (dst, src,
+ 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 clear LEN bytes at DST. */
+/* Emit code to set LEN bytes at DST to VAL.
+ Make use of clrmem if VAL is zero. */
void
-s390_expand_clrstr (rtx dst, rtx len)
+s390_expand_setmem (rtx dst, rtx len, rtx val)
{
- if (GET_CODE (len) == CONST_INT && INTVAL (len) >= 0 && INTVAL (len) <= 256)
+ 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 (INTVAL (len) > 0)
- emit_insn (gen_clrstr_short (dst, GEN_INT (INTVAL (len) - 1)));
+ 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, const1_rtx);
+
+ emit_insn (gen_movmem_short (dstp1, dst,
+ GEN_INT (INTVAL (len) - 2)));
+ }
+ }
}
else if (TARGET_MVCLE)
{
- emit_insn (gen_clrstr_long (dst, convert_to_mode (Pmode, len, 1)));
+ 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, src_addr, count, blocks, temp;
+ rtx dst_addr, src_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;
- tree type;
mode = GET_MODE (len);
if (mode == VOIDmode)
mode = Pmode;
- type = lang_hooks.types.type_for_mode (mode, 1);
- if (!type)
- abort ();
-
dst_addr = gen_reg_rtx (Pmode);
src_addr = gen_reg_rtx (Pmode);
count = gen_reg_rtx (mode);
@@ -3036,20 +3652,38 @@ s390_expand_clrstr (rtx dst, rtx len)
emit_move_insn (dst_addr, force_operand (XEXP (dst, 0), NULL_RTX));
dst = change_address (dst, VOIDmode, dst_addr);
- temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1, 0);
+ if (val == const0_rtx)
+ temp = expand_binop (mode, add_optab, count, constm1_rtx, count, 1, 0);
+ else
+ {
+ dstp1 = adjust_address (dst, VOIDmode, 1);
+ set_mem_size (dst, const1_rtx);
+
+ /* 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, 0);
+ }
if (temp != count)
emit_move_insn (count, temp);
- temp = expand_binop (mode, ashr_optab, count, GEN_INT (8), blocks, 1, 0);
+ temp = expand_binop (mode, lshr_optab, count, GEN_INT (8), blocks, 1, 0);
if (temp != blocks)
emit_move_insn (blocks, temp);
- expand_start_loop (1);
- expand_exit_loop_top_cond (0, build (NE_EXPR, type,
- make_tree (type, blocks),
- make_tree (type, const0_rtx)));
+ emit_cmp_and_jump_insns (blocks, const0_rtx,
+ EQ, NULL_RTX, mode, 1, loop_end_label);
+
+ emit_label (loop_start_label);
- emit_insn (gen_clrstr_short (dst, GEN_INT (255)));
+ 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)));
@@ -3057,9 +3691,16 @@ s390_expand_clrstr (rtx dst, rtx len)
if (temp != blocks)
emit_move_insn (blocks, temp);
- expand_end_loop ();
+ emit_cmp_and_jump_insns (blocks, const0_rtx,
+ EQ, NULL_RTX, mode, 1, loop_end_label);
- emit_insn (gen_clrstr_short (dst, convert_to_mode (Pmode, count, 1)));
+ 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);
}
}
@@ -3070,48 +3711,40 @@ s390_expand_clrstr (rtx dst, rtx len)
void
s390_expand_cmpmem (rtx target, rtx op0, rtx op1, rtx len)
{
- rtx (*gen_result) (rtx) =
- GET_MODE (target) == DImode ? gen_cmpint_di : gen_cmpint_si;
+ rtx ccreg = gen_rtx_REG (CCUmode, CC_REGNUM);
+ rtx tmp;
- op0 = protect_from_queue (op0, 0);
- op1 = protect_from_queue (op1, 0);
- len = protect_from_queue (len, 0);
+ /* 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_result (target));
+ emit_insn (gen_cmpint (target, ccreg));
}
else
emit_move_insn (target, const0_rtx);
}
-
- else /* if (TARGET_MVCLE) */
+ else if (TARGET_MVCLE)
{
emit_insn (gen_cmpmem_long (op0, op1, convert_to_mode (Pmode, len, 1)));
- emit_insn (gen_result (target));
+ emit_insn (gen_cmpint (target, ccreg));
}
-
-#if 0
- /* Deactivate for now as profile code cannot cope with
- CC being live across basic block boundaries. */
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;
- tree type;
mode = GET_MODE (len);
if (mode == VOIDmode)
mode = Pmode;
- type = lang_hooks.types.type_for_mode (mode, 1);
- if (!type)
- abort ();
-
addr0 = gen_reg_rtx (Pmode);
addr1 = gen_reg_rtx (Pmode);
count = gen_reg_rtx (mode);
@@ -3130,17 +3763,17 @@ s390_expand_cmpmem (rtx target, rtx op0, rtx op1, rtx len)
if (temp != count)
emit_move_insn (count, temp);
- temp = expand_binop (mode, ashr_optab, count, GEN_INT (8), blocks, 1, 0);
+ temp = expand_binop (mode, lshr_optab, count, GEN_INT (8), blocks, 1, 0);
if (temp != blocks)
emit_move_insn (blocks, temp);
- expand_start_loop (1);
- expand_exit_loop_top_cond (0, build (NE_EXPR, type,
- make_tree (type, blocks),
- make_tree (type, const0_rtx)));
+ emit_cmp_and_jump_insns (blocks, const0_rtx,
+ EQ, NULL_RTX, mode, 1, loop_end_label);
+
+ emit_label (loop_start_label);
emit_insn (gen_cmpmem_short (op0, op1, GEN_INT (255)));
- temp = gen_rtx_NE (VOIDmode, gen_rtx_REG (CCSmode, 33), const0_rtx);
+ temp = gen_rtx_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);
@@ -3155,21 +3788,540 @@ s390_expand_cmpmem (rtx target, rtx op0, rtx op1, rtx len)
if (temp != blocks)
emit_move_insn (blocks, temp);
- expand_end_loop ();
+ emit_cmp_and_jump_insns (blocks, const0_rtx,
+ EQ, NULL_RTX, mode, 1, loop_end_label);
- emit_insn (gen_cmpmem_short (op0, op1,
+ 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_result (target));
+ emit_insn (gen_cmpint (target, ccreg));
}
-#endif
}
-/* This is called from dwarf2out.c via ASM_OUTPUT_DWARF_DTPREL.
- We need to emit DTP-relative relocations. */
+
+/* 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);
+
+ src = gen_rtx_PLUS (GET_MODE (dst), src, const0_rtx);
+ op_res = gen_rtx_PLUS (GET_MODE (dst), src, op_res);
+ }
+
+ 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, false else. */
+
+bool
+s390_expand_insv (rtx dest, rtx op1, rtx op2, rtx src)
+{
+ int bitsize = INTVAL (op1);
+ int bitpos = INTVAL (op2);
+
+ /* 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, GEN_INT (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, GEN_INT (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 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)
+{
+ 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)))
+ new = s390_expand_mask_and_shift (new, 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, 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))
+ {
+ newv = force_reg (SImode, val);
+ store_bit_field (newv, GET_MODE_BITSIZE (mode), 0, SImode, new);
+ }
+ else
+ newv = force_reg (SImode, expand_simple_binop (SImode, IOR, new, 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 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 = 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, cmp);
+
+ /* Patch new with val at correct position. */
+ switch (code)
+ {
+ case PLUS:
+ case MINUS:
+ val = expand_simple_binop (SImode, code, new, 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, GET_MODE_BITSIZE (mode), 0, SImode, val);
+ else
+ {
+ new = expand_simple_binop (SImode, AND, new, ac.modemaski,
+ NULL_RTX, 1, OPTAB_DIRECT);
+ new = expand_simple_binop (SImode, IOR, new, val,
+ NULL_RTX, 1, OPTAB_DIRECT);
+ }
+ break;
+ case AND:
+ case IOR:
+ case XOR:
+ new = expand_simple_binop (SImode, code, new, val,
+ NULL_RTX, 1, OPTAB_DIRECT);
+ break;
+ case MULT: /* NAND */
+ new = expand_simple_binop (SImode, XOR, new, ac.modemask,
+ NULL_RTX, 1, OPTAB_DIRECT);
+ new = expand_simple_binop (SImode, AND, new, val,
+ NULL_RTX, 1, OPTAB_DIRECT);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ s390_emit_jump (csloop, s390_emit_compare_and_swap (NE, cmp,
+ ac.memsi, cmp, new));
+
+ /* Return the correct part of the bitfield. */
+ if (target)
+ convert_move (target, expand_simple_binop (SImode, LSHIFTRT,
+ after ? new : 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)
@@ -3181,14 +4333,29 @@ s390_output_dwarf_dtprel (FILE *file, int size, rtx x)
fputs ("\t.quad\t", file);
break;
default:
- abort ();
+ gcc_unreachable ();
}
output_addr_const (file, x);
fputs ("@DTPOFF", file);
}
+#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
+/* Implement TARGET_MANGLE_FUNDAMENTAL_TYPE. */
+
+static const char *
+s390_mangle_fundamental_type (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 losage, recognize various UNSPEC sequences
+ general assembler lossage, recognize various UNSPEC sequences
and turn them back into a direct symbol reference. */
static rtx
@@ -3224,58 +4391,35 @@ s390_delegitimize_address (rtx orig_x)
return orig_x;
}
-/* Output shift count operand OP to stdio stream FILE. */
+/* 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 = 0;
+ HOST_WIDE_INT offset;
+ rtx base;
- /* We can have an integer constant, an address register,
- or a sum of the two. */
- if (GET_CODE (op) == CONST_INT)
- {
- offset = INTVAL (op);
- op = NULL_RTX;
- }
- if (op && GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT)
- {
- offset = INTVAL (XEXP (op, 1));
- op = XEXP (op, 0);
- }
- while (op && GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
+ /* Extract base register and offset. */
+ if (!s390_decompose_shift_count (op, &base, &offset))
+ gcc_unreachable ();
/* Sanity check. */
- if (op && (GET_CODE (op) != REG
- || REGNO (op) >= FIRST_PSEUDO_REGISTER
- || REGNO_REG_CLASS (REGNO (op)) != ADDR_REGS))
- abort ();
+ if (base)
+ {
+ gcc_assert (GET_CODE (base) == REG);
+ gcc_assert (REGNO (base) < FIRST_PSEUDO_REGISTER);
+ gcc_assert (REGNO_REG_CLASS (REGNO (base)) == ADDR_REGS);
+ }
- /* Shift counts are truncated to the low six bits anyway. */
- fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset & 63);
- if (op)
- fprintf (file, "(%s)", reg_names[REGNO (op)]);
+ /* 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)]);
}
-/* 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;
-
- abort ();
-}
+/* See 'get_some_local_dynamic_name'. */
static int
get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
@@ -3298,98 +4442,82 @@ get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
return 0;
}
-/* Output symbolic constant X in assembler syntax to
- stdio stream FILE. */
+/* Locate some local-dynamic symbol still in use by this function
+ so that we can print its name in local-dynamic base patterns. */
-void
-s390_output_symbolic_const (FILE *file, rtx x)
+static const char *
+get_some_local_dynamic_name (void)
{
- switch (GET_CODE (x))
- {
- case CONST:
- case ZERO_EXTEND:
- case SIGN_EXTEND:
- s390_output_symbolic_const (file, XEXP (x, 0));
- break;
+ rtx insn;
- case PLUS:
- s390_output_symbolic_const (file, XEXP (x, 0));
- fprintf (file, "+");
- s390_output_symbolic_const (file, XEXP (x, 1));
- break;
+ if (cfun->machine->some_ld_name)
+ return cfun->machine->some_ld_name;
- case MINUS:
- s390_output_symbolic_const (file, XEXP (x, 0));
- fprintf (file, "-");
- s390_output_symbolic_const (file, XEXP (x, 1));
- break;
+ 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;
- case CONST_INT:
- case LABEL_REF:
- case CODE_LABEL:
- case SYMBOL_REF:
- output_addr_const (file, x);
- break;
+ gcc_unreachable ();
+}
- case UNSPEC:
- if (XVECLEN (x, 0) != 1)
- output_operand_lossage ("invalid UNSPEC as operand (1)");
- switch (XINT (x, 1))
- {
- case UNSPEC_GOTENT:
- s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
- fprintf (file, "@GOTENT");
- break;
- case UNSPEC_GOT:
- s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
- fprintf (file, "@GOT");
- break;
- case UNSPEC_GOTOFF:
- s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
- fprintf (file, "@GOTOFF");
- break;
- case UNSPEC_PLT:
- s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
- fprintf (file, "@PLT");
- break;
- case UNSPEC_PLTOFF:
- s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
- fprintf (file, "@PLTOFF");
- break;
- case UNSPEC_TLSGD:
- s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
- fprintf (file, "@TLSGD");
- break;
- case UNSPEC_TLSLDM:
- assemble_name (file, get_some_local_dynamic_name ());
- fprintf (file, "@TLSLDM");
- break;
- case UNSPEC_DTPOFF:
- s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
- fprintf (file, "@DTPOFF");
- break;
- case UNSPEC_NTPOFF:
- s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
- fprintf (file, "@NTPOFF");
- break;
- case UNSPEC_GOTNTPOFF:
- s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
- fprintf (file, "@GOTNTPOFF");
- break;
- case UNSPEC_INDNTPOFF:
- s390_output_symbolic_const (file, XVECEXP (x, 0, 0));
- fprintf (file, "@INDNTPOFF");
- break;
- default:
- output_operand_lossage ("invalid UNSPEC as operand (2)");
- break;
- }
- break;
+/* 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. */
- default:
- fatal_insn ("UNKNOWN in s390_output_symbolic_const !?", x);
- break;
- }
+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;
+ }
+
+ return false;
}
/* Output address operand ADDR in assembler syntax to
@@ -3401,12 +4529,12 @@ print_operand_address (FILE *file, rtx addr)
struct s390_address ad;
if (!s390_decompose_address (addr, &ad)
- || (ad.base && !REG_OK_FOR_BASE_STRICT_P (ad.base))
- || (ad.indx && !REG_OK_FOR_INDEX_STRICT_P (ad.indx)))
- output_operand_lossage ("Cannot decompose address.");
+ || (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)
- s390_output_symbolic_const (file, ad.disp);
+ output_addr_const (file, ad.disp);
else
fprintf (file, "0");
@@ -3424,17 +4552,22 @@ print_operand_address (FILE *file, rtx addr)
'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.
- 'x': print integer X as if it's an unsigned word.
- 'h': print integer X as if it's a signed word.
+ '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 0xffff 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)
@@ -3466,21 +4599,26 @@ print_operand (FILE *file, rtx x, int code)
assemble_name (file, get_some_local_dynamic_name ());
}
else
- abort ();
+ gcc_unreachable ();
+ return;
+
+ case 'G':
+ fprintf (file, "%u", GET_MODE_SIZE (GET_MODE (x)));
return;
case 'O':
{
struct s390_address ad;
+ int ret;
- if (GET_CODE (x) != MEM
- || !s390_decompose_address (XEXP (x, 0), &ad)
- || (ad.base && !REG_OK_FOR_BASE_STRICT_P (ad.base))
- || ad.indx)
- abort ();
+ gcc_assert (GET_CODE (x) == MEM);
+ ret = s390_decompose_address (XEXP (x, 0), &ad);
+ gcc_assert (ret);
+ gcc_assert (!ad.base || REGNO_OK_FOR_BASE_P (REGNO (ad.base)));
+ gcc_assert (!ad.indx);
if (ad.disp)
- s390_output_symbolic_const (file, ad.disp);
+ output_addr_const (file, ad.disp);
else
fprintf (file, "0");
}
@@ -3489,12 +4627,13 @@ print_operand (FILE *file, rtx x, int code)
case 'R':
{
struct s390_address ad;
+ int ret;
- if (GET_CODE (x) != MEM
- || !s390_decompose_address (XEXP (x, 0), &ad)
- || (ad.base && !REG_OK_FOR_BASE_STRICT_P (ad.base))
- || ad.indx)
- abort ();
+ gcc_assert (GET_CODE (x) == MEM);
+ ret = s390_decompose_address (XEXP (x, 0), &ad);
+ gcc_assert (ret);
+ gcc_assert (!ad.base || REGNO_OK_FOR_BASE_P (REGNO (ad.base)));
+ gcc_assert (!ad.indx);
if (ad.base)
fprintf (file, "%s", reg_names[REGNO (ad.base)]);
@@ -3503,13 +4642,34 @@ print_operand (FILE *file, rtx x, int code)
}
return;
+ case 'S':
+ {
+ struct s390_address ad;
+ int ret;
+
+ gcc_assert (GET_CODE (x) == MEM);
+ ret = s390_decompose_address (XEXP (x, 0), &ad);
+ gcc_assert (ret);
+ gcc_assert (!ad.base || REGNO_OK_FOR_BASE_P (REGNO (ad.base)));
+ gcc_assert (!ad.indx);
+
+ 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
- abort ();
+ gcc_unreachable ();
break;
case 'M':
@@ -3518,7 +4678,7 @@ print_operand (FILE *file, rtx x, int code)
else if (GET_CODE (x) == MEM)
x = change_address (x, VOIDmode, plus_constant (XEXP (x, 0), 8));
else
- abort ();
+ gcc_unreachable ();
break;
case 'Y':
@@ -3540,7 +4700,7 @@ print_operand (FILE *file, rtx x, int code)
case CODE_LABEL:
case LABEL_REF:
case SYMBOL_REF:
- s390_output_symbolic_const (file, x);
+ output_addr_const (file, x);
break;
case CONST_INT:
@@ -3551,18 +4711,25 @@ print_operand (FILE *file, rtx x, int code)
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,
+ 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));
+ 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:
- if (GET_MODE (x) != VOIDmode)
- abort ();
+ 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')
@@ -3570,7 +4737,7 @@ print_operand (FILE *file, rtx x, int code)
else if (code == 'h')
fprintf (file, HOST_WIDE_INT_PRINT_DEC, ((CONST_DOUBLE_LOW (x) & 0xffff) ^ 0x8000) - 0x8000);
else
- abort ();
+ gcc_unreachable ();
break;
default:
@@ -3599,7 +4766,7 @@ s390_assemble_integer (rtx x, unsigned int size, int aligned_p)
/* Returns true if register REGNO is used for forming
a memory address in expression X. */
-static int
+static bool
reg_used_in_mem_p (int regno, rtx x)
{
enum rtx_code code = GET_CODE (x);
@@ -3610,14 +4777,14 @@ reg_used_in_mem_p (int regno, rtx x)
{
if (refers_to_regno_p (regno, regno+1,
XEXP (x, 0), 0))
- return 1;
+ 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 1;
+ return true;
}
fmt = GET_RTX_FORMAT (code);
@@ -3625,20 +4792,20 @@ reg_used_in_mem_p (int regno, rtx x)
{
if (fmt[i] == 'e'
&& reg_used_in_mem_p (regno, XEXP (x, i)))
- return 1;
+ 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 1;
+ return true;
}
- return 0;
+ return false;
}
/* Returns true if expression DEP_RTX sets an address register
used by instruction INSN to address memory. */
-static int
+static bool
addr_generation_dependency_p (rtx dep_rtx, rtx insn)
{
rtx target, pat;
@@ -3663,20 +4830,17 @@ addr_generation_dependency_p (rtx dep_rtx, rtx insn)
pat = PATTERN (insn);
if (GET_CODE (pat) == PARALLEL)
{
- if (XVECLEN (pat, 0) != 2)
- abort();
+ gcc_assert (XVECLEN (pat, 0) == 2);
pat = XVECEXP (pat, 0, 0);
}
- if (GET_CODE (pat) == SET)
- return refers_to_regno_p (regno, regno+1, SET_SRC (pat), 0);
- else
- abort();
+ 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 0;
+ return false;
}
/* Return 1, if dep_insn sets register used in insn in the agen unit. */
@@ -3701,63 +4865,6 @@ s390_agen_dep_p (rtx dep_insn, rtx insn)
return 0;
}
-/* Return the modified cost of the dependency of instruction INSN
- on instruction DEP_INSN through the link LINK. COST is the
- default cost of that dependency.
-
- Data dependencies are all handled without delay. However, if a
- register is modified and subsequently used as base or index
- register of a memory reference, at least 4 cycles need to pass
- between setting and using the register to avoid pipeline stalls.
- An exception is the LA instruction. An address generated by LA can
- be used by introducing only a one cycle stall on the pipeline. */
-
-static int
-s390_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
-{
- rtx dep_rtx;
- int i;
-
- /* If the dependence is an anti-dependence, there is no cost. For an
- output dependence, there is sometimes a cost, but it doesn't seem
- worth handling those few cases. */
-
- if (REG_NOTE_KIND (link) != 0)
- return 0;
-
- /* If we can't recognize the insns, we can't really do anything. */
- if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0)
- return cost;
-
- /* DFA based scheduling checks address dependency in md file. */
- if (s390_use_dfa_pipeline_interface ())
- {
- /* Operand forward in case of lr, load and la. */
- if (s390_tune == PROCESSOR_2084_Z990
- && cost == 1
- && (s390_safe_attr_type (dep_insn) == TYPE_LA
- || s390_safe_attr_type (dep_insn) == TYPE_LR
- || s390_safe_attr_type (dep_insn) == TYPE_LOAD))
- return 0;
- return cost;
- }
-
- dep_rtx = PATTERN (dep_insn);
-
- if (GET_CODE (dep_rtx) == SET
- && addr_generation_dependency_p (dep_rtx, insn))
- cost += (s390_safe_attr_type (dep_insn) == TYPE_LA) ? 1 : 4;
- else if (GET_CODE (dep_rtx) == PARALLEL)
- {
- for (i = 0; i < XVECLEN (dep_rtx, 0); i++)
- {
- if (addr_generation_dependency_p (XVECEXP (dep_rtx, 0, i), insn))
- cost += (s390_safe_attr_type (dep_insn) == TYPE_LA) ? 1 : 4;
- }
- }
-
- return cost;
-}
/* A C statement (sans semicolon) to update the integer scheduling priority
INSN_PRIORITY (INSN). Increase the priority to execute the INSN earlier,
reduce the priority to execute INSN later. Do not define this macro if
@@ -3772,16 +4879,18 @@ s390_adjust_priority (rtx insn ATTRIBUTE_UNUSED, int priority)
if (! INSN_P (insn))
return priority;
- if (s390_tune != PROCESSOR_2084_Z990)
+ if (s390_tune != PROCESSOR_2084_Z990
+ && s390_tune != PROCESSOR_2094_Z9_109)
return priority;
switch (s390_safe_attr_type (insn))
{
- case TYPE_FSTORED:
- case TYPE_FSTORES:
+ case TYPE_FSTOREDF:
+ case TYPE_FSTORESF:
priority = priority << 3;
break;
case TYPE_STORE:
+ case TYPE_STM:
priority = priority << 1;
break;
default:
@@ -3795,43 +4904,121 @@ s390_adjust_priority (rtx insn ATTRIBUTE_UNUSED, int priority)
static int
s390_issue_rate (void)
{
- if (s390_tune == PROCESSOR_2084_Z990)
+ if (s390_tune == PROCESSOR_2084_Z990
+ || s390_tune == PROCESSOR_2094_Z9_109)
return 3;
return 1;
}
-/* If the following function returns TRUE, we will use the the DFA
- insn scheduler. */
-
-static int
-s390_use_dfa_pipeline_interface (void)
-{
- if (s390_tune == PROCESSOR_2064_Z900
- || s390_tune == PROCESSOR_2084_Z990)
- return 1;
-
- return 0;
-}
-
static int
s390_first_cycle_multipass_dfa_lookahead (void)
{
- return s390_use_dfa_pipeline_interface () ? 4 : 0;
+ return 4;
}
-/* Called after issuing each insn.
- Triggers default sort algorithm to better slot instructions. */
-static int
-s390_sched_reorder2 (FILE *dump ATTRIBUTE_UNUSED,
- int sched_verbose ATTRIBUTE_UNUSED,
- rtx *ready ATTRIBUTE_UNUSED,
- int *pn_ready ATTRIBUTE_UNUSED,
- int clock_var ATTRIBUTE_UNUSED)
+/* 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)
{
- return s390_issue_rate();
-}
+ 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. */
@@ -3840,7 +5027,7 @@ static int
s390_split_branches (void)
{
rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
- int new_literal = 0;
+ int new_literal = 0, ret;
rtx insn, pat, tmp, target;
rtx *label;
@@ -3882,7 +5069,7 @@ s390_split_branches (void)
/* We are going to use the return register as scratch register,
make sure it will be saved/restored by the prologue/epilogue. */
- cfun->machine->save_return_addr_p = 1;
+ cfun_frame_layout.save_return_addr_p = 1;
if (!flag_pic)
{
@@ -3890,6 +5077,7 @@ s390_split_branches (void)
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;
}
@@ -3902,24 +5090,26 @@ s390_split_branches (void)
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 (1, XEXP (target, 0)),
+ 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);
}
- if (!validate_change (insn, label, target, 0))
- abort ();
+ ret = validate_change (insn, label, target, 0);
+ gcc_assert (ret);
}
return new_literal;
}
-/* Find a literal pool symbol referenced in RTX X, and store
- it at REF. Will abort if X contains references to more than
- one such pool symbol; multiple references to the same symbol
- are allowed, however.
+/* 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. */
@@ -3939,13 +5129,21 @@ find_constant_pool_ref (rtx x, rtx *ref)
&& XINT (x, 1) == UNSPECV_POOL_ENTRY)
return;
- if (GET_CODE (x) == SYMBOL_REF
- && CONSTANT_POOL_ADDRESS_P (x))
+ 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 = x;
- else if (*ref != x)
- abort();
+ *ref = sym;
+ else
+ gcc_assert (*ref == sym);
+
+ return;
}
fmt = GET_RTX_FORMAT (GET_CODE (x));
@@ -3963,60 +5161,34 @@ find_constant_pool_ref (rtx x, rtx *ref)
}
}
-/* Replace every reference to the literal pool symbol REF
- in X by the address ADDR. Fix up MEMs as required. */
+/* 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 addr)
+replace_constant_pool_ref (rtx *x, rtx ref, rtx offset)
{
int i, j;
const char *fmt;
- if (*x == ref)
- abort ();
+ gcc_assert (*x != ref);
- /* Literal pool references can only occur inside a MEM ... */
- if (GET_CODE (*x) == MEM)
+ if (GET_CODE (*x) == UNSPEC
+ && XINT (*x, 1) == UNSPEC_LTREF
+ && XVECEXP (*x, 0, 0) == ref)
{
- rtx memref = XEXP (*x, 0);
-
- if (memref == ref)
- {
- *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
- && XEXP (XEXP (memref, 0), 0) == ref)
- {
- HOST_WIDE_INT off = INTVAL (XEXP (XEXP (memref, 0), 1));
- *x = replace_equiv_address (*x, plus_constant (addr, off));
- return;
- }
+ *x = gen_rtx_PLUS (Pmode, XVECEXP (*x, 0, 1), offset);
+ return;
}
- /* ... or a load-address type pattern. */
- if (GET_CODE (*x) == SET)
+ 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 addrref = SET_SRC (*x);
-
- if (addrref == ref)
- {
- 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
- && XEXP (XEXP (addrref, 0), 0) == ref)
- {
- HOST_WIDE_INT off = INTVAL (XEXP (XEXP (addrref, 0), 1));
- SET_SRC (*x) = plus_constant (addr, off);
- return;
- }
+ 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));
@@ -4024,12 +5196,12 @@ replace_constant_pool_ref (rtx *x, rtx ref, rtx addr)
{
if (fmt[i] == 'e')
{
- replace_constant_pool_ref (&XEXP (*x, i), ref, addr);
+ 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, addr);
+ replace_constant_pool_ref (&XVECEXP (*x, i, j), ref, offset);
}
}
}
@@ -4070,10 +5242,10 @@ find_ltrel_base (rtx x)
return NULL_RTX;
}
-/* Replace any occurrence of UNSPEC_LTREL_BASE in X with BASE. */
+/* Replace any occurrence of UNSPEC_LTREL_BASE in X with its base. */
static void
-replace_ltrel_base (rtx *x, rtx base)
+replace_ltrel_base (rtx *x)
{
int i, j;
const char *fmt;
@@ -4081,7 +5253,7 @@ replace_ltrel_base (rtx *x, rtx base)
if (GET_CODE (*x) == UNSPEC
&& XINT (*x, 1) == UNSPEC_LTREL_BASE)
{
- *x = base;
+ *x = XVECEXP (*x, 0, 1);
return;
}
@@ -4090,12 +5262,12 @@ replace_ltrel_base (rtx *x, rtx base)
{
if (fmt[i] == 'e')
{
- replace_ltrel_base (&XEXP (*x, i), base);
+ 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), base);
+ replace_ltrel_base (&XVECEXP (*x, i, j));
}
}
}
@@ -4104,12 +5276,12 @@ replace_ltrel_base (rtx *x, rtx base)
/* 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 7
+#define NR_C_MODES 11
enum machine_mode constant_modes[NR_C_MODES] =
{
- TImode,
- DFmode, DImode,
- SFmode, SImode,
+ TFmode, TImode, TDmode,
+ DFmode, DImode, DDmode,
+ SFmode, SImode, SDmode,
HImode,
QImode
};
@@ -4129,27 +5301,33 @@ struct constant_pool
bitmap insns;
struct constant *constants[NR_C_MODES];
+ struct constant *execute;
rtx label;
int size;
};
-static struct constant_pool * s390_mainpool_start (void);
-static void s390_mainpool_finish (struct constant_pool *, rtx base_reg);
-static void s390_mainpool_cancel (struct constant_pool *);
+/* Allocate new constant_pool structure. */
-static struct constant_pool * s390_chunkify_start (rtx base_reg);
-static void s390_chunkify_finish (struct constant_pool *, rtx base_reg);
-static void s390_chunkify_cancel (struct constant_pool *);
+static struct constant_pool *
+s390_alloc_pool (void)
+{
+ struct constant_pool *pool;
+ int i;
-static struct constant_pool *s390_start_pool (struct constant_pool **, rtx);
-static void s390_end_pool (struct constant_pool *, rtx);
-static void s390_add_pool_insn (struct constant_pool *, rtx);
-static struct constant_pool *s390_find_pool (struct constant_pool *, rtx);
-static void s390_add_constant (struct constant_pool *, rtx, enum machine_mode);
-static rtx s390_find_constant (struct constant_pool *, rtx, enum machine_mode);
-static rtx s390_dump_pool (struct constant_pool *, bool);
-static struct constant_pool *s390_alloc_pool (void);
-static void s390_free_pool (struct constant_pool *);
+ 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;
+
+ return pool;
+}
/* Create new constant pool covering instructions starting at INSN
and chain it to the end of POOL_LIST. */
@@ -4217,8 +5395,7 @@ s390_add_constant (struct constant_pool *pool, rtx val, enum machine_mode mode)
for (i = 0; i < NR_C_MODES; i++)
if (constant_modes[i] == mode)
break;
- if (i == NR_C_MODES)
- abort ();
+ gcc_assert (i != NR_C_MODES);
for (c = pool->constants[i]; c != NULL; c = c->next)
if (rtx_equal_p (val, c->value))
@@ -4250,15 +5427,13 @@ s390_find_constant (struct constant_pool *pool, rtx val,
for (i = 0; i < NR_C_MODES; i++)
if (constant_modes[i] == mode)
break;
- if (i == NR_C_MODES)
- abort ();
+ 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)
- abort ();
+ gcc_assert (c);
offset = gen_rtx_MINUS (Pmode, gen_rtx_LABEL_REF (Pmode, c->label),
gen_rtx_LABEL_REF (Pmode, pool->label));
@@ -4266,24 +5441,126 @@ s390_find_constant (struct constant_pool *pool, rtx val,
return offset;
}
+/* 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;
+ rtx offset;
+
+ for (c = pool->execute; c != NULL; c = c->next)
+ if (INSN_UID (insn) == INSN_UID (c->value))
+ break;
+
+ gcc_assert (c);
+
+ offset = gen_rtx_MINUS (Pmode, gen_rtx_LABEL_REF (Pmode, c->label),
+ gen_rtx_LABEL_REF (Pmode, pool->label));
+ offset = gen_rtx_CONST (Pmode, offset);
+ return offset;
+}
+
+/* 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 rtx
+static void
s390_dump_pool (struct constant_pool *pool, bool remote_label)
{
struct constant *c;
- rtx insn;
+ rtx insn = pool->pool_insn;
int i;
- /* Pool start insn switches to proper section
- and guarantees necessary alignment. */
+ /* 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_start_64 (), pool->pool_insn);
+ insn = emit_insn_after (gen_pool_align (GEN_INT (8)), insn);
else
- insn = emit_insn_after (gen_pool_start_31 (), pool->pool_insn);
+ 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);
@@ -4310,50 +5587,39 @@ s390_dump_pool (struct constant_pool *pool, bool remote_label)
insn = emit_label_after (c->label, insn);
INSN_ADDRESSES_NEW (insn, -1);
- value = gen_rtx_UNSPEC_VOLATILE (constant_modes[i],
+ value = gen_rtx_UNSPEC_VOLATILE (constant_modes[i],
gen_rtvec (1, value),
UNSPECV_POOL_ENTRY);
insn = emit_insn_after (value, insn);
INSN_ADDRESSES_NEW (insn, -1);
}
- /* Pool end insn switches back to previous section
- and guarantees necessary alignment. */
- if (TARGET_CPU_ZARCH)
- insn = emit_insn_after (gen_pool_end_64 (), insn);
- else
- insn = emit_insn_after (gen_pool_end_31 (), insn);
+ /* 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);
-
- return insn;
-}
-
-/* Allocate new constant_pool structure. */
-
-static struct constant_pool *
-s390_alloc_pool (void)
-{
- struct constant_pool *pool;
- int i;
-
- pool = (struct constant_pool *) xmalloc (sizeof *pool);
- pool->next = NULL;
- for (i = 0; i < NR_C_MODES; i++)
- pool->constants[i] = NULL;
-
- pool->label = gen_label_rtx ();
- pool->first_insn = NULL_RTX;
- pool->pool_insn = NULL_RTX;
- pool->insns = BITMAP_XMALLOC ();
- pool->size = 0;
-
- return pool;
}
/* Free all memory used by POOL. */
@@ -4361,20 +5627,23 @@ s390_alloc_pool (void)
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)
{
- struct constant *c = pool->constants[i];
- while (c != NULL)
- {
- struct constant *next = c->next;
- free (c);
- c = next;
- }
+ next = c->next;
+ free (c);
}
- BITMAP_XFREE (pool->insns);
+ BITMAP_FREE (pool->insns);
free (pool);
}
@@ -4392,15 +5661,19 @@ s390_mainpool_start (void)
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
if (GET_CODE (insn) == INSN
- && GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE
- && XINT (PATTERN (insn), 1) == UNSPECV_MAIN_POOL)
+ && GET_CODE (PATTERN (insn)) == SET
+ && GET_CODE (SET_SRC (PATTERN (insn))) == UNSPEC_VOLATILE
+ && XINT (SET_SRC (PATTERN (insn)), 1) == UNSPECV_MAIN_POOL)
{
- if (pool->pool_insn)
- abort ();
+ gcc_assert (!pool->pool_insn);
pool->pool_insn = insn;
}
- if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_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);
@@ -4413,8 +5686,7 @@ s390_mainpool_start (void)
}
}
- if (!pool->pool_insn)
- abort ();
+ gcc_assert (pool->pool_insn || pool->size == 0);
if (pool->size >= 4096)
{
@@ -4431,18 +5703,22 @@ s390_mainpool_start (void)
/* POOL holds the main literal pool as collected by s390_mainpool_start.
Modify the current function to output the pool constants as well as
- the pool register setup instruction. BASE_REG is the register to
- be used as pool base register. */
+ the pool register setup instruction. */
static void
-s390_mainpool_finish (struct constant_pool *pool, rtx base_reg)
+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)
{
- remove_insn (pool->pool_insn);
+ /* 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;
}
@@ -4458,8 +5734,8 @@ s390_mainpool_finish (struct constant_pool *pool, rtx base_reg)
insn = emit_insn_after (insn, pool->pool_insn);
INSN_ADDRESSES_NEW (insn, -1);
remove_insn (pool->pool_insn);
-
- insn = get_last_insn ();
+
+ insn = get_last_insn ();
pool->pool_insn = emit_insn_after (gen_pool (const0_rtx), insn);
INSN_ADDRESSES_NEW (pool->pool_insn, -1);
@@ -4516,7 +5792,7 @@ s390_mainpool_finish (struct constant_pool *pool, rtx base_reg)
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
if (INSN_P (insn))
- replace_ltrel_base (&PATTERN (insn), base_reg);
+ replace_ltrel_base (&PATTERN (insn));
if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
{
@@ -4524,9 +5800,12 @@ s390_mainpool_finish (struct constant_pool *pool, rtx base_reg)
find_constant_pool_ref (PATTERN (insn), &pool_ref);
if (pool_ref)
{
- addr = s390_find_constant (pool, get_pool_constant (pool_ref),
- get_pool_mode (pool_ref));
- addr = gen_rtx_PLUS (Pmode, base_reg, addr);
+ 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;
}
@@ -4550,14 +5829,13 @@ s390_mainpool_cancel (struct constant_pool *pool)
}
-/* Chunkify the literal pool. BASE_REG is to be used as pool
- register. */
+/* Chunkify the literal pool. */
#define S390_POOL_CHUNK_MIN 0xc00
#define S390_POOL_CHUNK_MAX 0xe00
static struct constant_pool *
-s390_chunkify_start (rtx base_reg)
+s390_chunkify_start (void)
{
struct constant_pool *curr_pool = NULL, *pool_list = NULL;
int extra_size = 0;
@@ -4583,14 +5861,20 @@ s390_chunkify_start (rtx base_reg)
rtx ltrel_base = find_ltrel_base (PATTERN (insn));
if (ltrel_base)
{
- if (ltrel_base == pending_ltrel)
- pending_ltrel = NULL_RTX;
- else
- abort ();
+ gcc_assert (ltrel_base == pending_ltrel);
+ pending_ltrel = NULL_RTX;
}
}
- if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
+ 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 || GET_CODE (insn) == CALL_INSN)
{
rtx pool_ref = NULL_RTX;
find_constant_pool_ref (PATTERN (insn), &pool_ref);
@@ -4611,8 +5895,7 @@ s390_chunkify_start (rtx base_reg)
&& GET_CODE (XEXP (constant, 0)) == UNSPEC
&& XINT (XEXP (constant, 0), 1) == UNSPEC_LTREL_OFFSET)
{
- if (pending_ltrel)
- abort ();
+ gcc_assert (!pending_ltrel);
pending_ltrel = pool_ref;
}
}
@@ -4623,8 +5906,7 @@ s390_chunkify_start (rtx base_reg)
if (curr_pool)
s390_add_pool_insn (curr_pool, insn);
/* An LTREL_BASE must follow within the same basic block. */
- if (pending_ltrel)
- abort ();
+ gcc_assert (!pending_ltrel);
}
if (!curr_pool
@@ -4702,14 +5984,12 @@ s390_chunkify_start (rtx base_reg)
if (curr_pool)
s390_end_pool (curr_pool, NULL_RTX);
- if (pending_ltrel)
- abort ();
-
+ gcc_assert (!pending_ltrel);
/* Find all labels that are branched into
from an insn belonging to a different chunk. */
- far_labels = BITMAP_XMALLOC ();
+ far_labels = BITMAP_ALLOC (NULL);
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
@@ -4784,7 +6064,8 @@ s390_chunkify_start (rtx base_reg)
for (curr_pool = pool_list; curr_pool; curr_pool = curr_pool->next)
{
- rtx new_insn = gen_reload_base (base_reg, curr_pool->label);
+ 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);
}
@@ -4798,13 +6079,14 @@ s390_chunkify_start (rtx base_reg)
struct constant_pool *pool = s390_find_pool (pool_list, insn);
if (pool)
{
- rtx new_insn = gen_reload_base (base_reg, pool->label);
+ rtx new_insn = gen_reload_base (cfun->machine->base_reg,
+ pool->label);
INSN_ADDRESSES_NEW (emit_insn_after (new_insn, insn), -1);
}
}
- BITMAP_XFREE (far_labels);
+ BITMAP_FREE (far_labels);
/* Recompute insn addresses. */
@@ -4817,11 +6099,10 @@ s390_chunkify_start (rtx base_reg)
/* 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. BASE_REG is
- to be used as pool base register. */
+ all changes to the current function as required. */
static void
-s390_chunkify_finish (struct constant_pool *pool_list, rtx base_reg)
+s390_chunkify_finish (struct constant_pool *pool_list)
{
struct constant_pool *curr_pool = NULL;
rtx insn;
@@ -4832,7 +6113,7 @@ s390_chunkify_finish (struct constant_pool *pool_list, rtx base_reg)
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
if (INSN_P (insn))
- replace_ltrel_base (&PATTERN (insn), base_reg);
+ replace_ltrel_base (&PATTERN (insn));
curr_pool = s390_find_pool (pool_list, insn);
if (!curr_pool)
@@ -4844,9 +6125,13 @@ s390_chunkify_finish (struct constant_pool *pool_list, rtx base_reg)
find_constant_pool_ref (PATTERN (insn), &pool_ref);
if (pool_ref)
{
- addr = s390_find_constant (curr_pool, get_pool_constant (pool_ref),
- get_pool_mode (pool_ref));
- addr = gen_rtx_PLUS (Pmode, base_reg, addr);
+ 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;
}
@@ -4929,476 +6214,734 @@ s390_chunkify_cancel (struct constant_pool *pool_list)
}
-/* Output to FILE the constant pool entry EXP in mode MODE
- with alignment ALIGN. */
+/* Output the constant pool entry EXP in mode MODE with alignment ALIGN. */
void
-s390_output_pool_entry (FILE *file, rtx exp, enum machine_mode mode,
- unsigned int align)
+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:
- if (GET_CODE (exp) != CONST_DOUBLE)
- abort ();
+ 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:
- if (GET_CODE (exp) == CONST
- || GET_CODE (exp) == SYMBOL_REF
- || GET_CODE (exp) == LABEL_REF)
- {
- fputs (integer_asm_op (GET_MODE_SIZE (mode), TRUE), file);
- s390_output_symbolic_const (file, exp);
- fputc ('\n', file);
- }
- else
- {
- assemble_integer (exp, GET_MODE_SIZE (mode), align, 1);
- }
+ assemble_integer (exp, GET_MODE_SIZE (mode), align, 1);
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
-/* Rework the prolog/epilog to avoid saving/restoring
- registers unnecessarily. BASE_USED specifies whether
- the literal pool base register needs to be saved. */
+/* 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. */
-static void
-s390_optimize_prolog (bool base_used)
+rtx
+s390_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED)
{
- int save_first, save_last, restore_first, restore_last;
- int i, j;
- rtx insn, new_insn, next_insn;
-
- /* Recompute regs_ever_live data for special registers. */
- regs_ever_live[BASE_REGISTER] = base_used;
- regs_ever_live[RETURN_REGNUM] = cfun->machine->save_return_addr_p;
- regs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0;
-
-
- /* Find first and last gpr to be saved. */
+ int offset;
+ rtx addr;
- for (i = 6; i < 16; i++)
- if (regs_ever_live[i])
- if (!global_regs[i]
- || i == STACK_POINTER_REGNUM
- || i == RETURN_REGNUM
- || i == BASE_REGISTER
- || (flag_pic && i == (int)PIC_OFFSET_TABLE_REGNUM))
- break;
+ /* Without backchain, we fail for all but the current frame. */
- for (j = 15; j > i; j--)
- if (regs_ever_live[j])
- if (!global_regs[j]
- || j == STACK_POINTER_REGNUM
- || j == RETURN_REGNUM
- || j == BASE_REGISTER
- || (flag_pic && j == (int)PIC_OFFSET_TABLE_REGNUM))
- break;
+ if (!TARGET_BACKCHAIN && count > 0)
+ return NULL_RTX;
- if (i == 16)
- {
- /* Nothing to save/restore. */
- save_first = restore_first = -1;
- save_last = restore_last = -1;
- }
- else
- {
- /* Save/restore from i to j. */
- save_first = restore_first = i;
- save_last = restore_last = j;
- }
+ /* For the current frame, we need to make sure the initial
+ value of RETURN_REGNUM is actually saved. */
- /* Varargs functions need to save gprs 2 to 6. */
- if (current_function_stdarg)
+ if (count == 0)
{
- save_first = 2;
- if (save_last < 6)
- save_last = 6;
+ /* 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_WORD;
+ else
+ offset = RETURN_REGNUM * UNITS_PER_WORD;
- /* If all special registers are in fact used, there's nothing we
- can do, so no point in walking the insn list. */
- if (i <= BASE_REGISTER && j >= BASE_REGISTER
- && (TARGET_CPU_ZARCH || (i <= RETURN_REGNUM && j >= RETURN_REGNUM)))
- return;
+ 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. */
- /* Search for prolog/epilog insns and replace them. */
+rtx
+s390_back_chain_rtx (void)
+{
+ rtx chain;
- for (insn = get_insns (); insn; insn = next_insn)
- {
- int first, last, off;
- rtx set, base, offset;
+ gcc_assert (TARGET_BACKCHAIN);
- next_insn = NEXT_INSN (insn);
+ if (TARGET_PACKED_STACK)
+ chain = plus_constant (stack_pointer_rtx,
+ STACK_POINTER_OFFSET - UNITS_PER_WORD);
+ else
+ chain = stack_pointer_rtx;
- if (GET_CODE (insn) != INSN)
- continue;
+ chain = gen_rtx_MEM (Pmode, chain);
+ return chain;
+}
- 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) - first * UNITS_PER_WORD;
+/* 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. */
- if (GET_CODE (base) != REG || off < 0)
- continue;
- if (first > BASE_REGISTER || last < BASE_REGISTER)
- continue;
+static int
+find_unused_clobbered_reg (void)
+{
+ int i;
+ for (i = 0; i < 6; i++)
+ if (!regs_ever_live[i])
+ return i;
+ return 0;
+}
- if (save_first != -1)
- {
- new_insn = save_gprs (base, off, save_first, save_last);
- new_insn = emit_insn_before (new_insn, insn);
- INSN_ADDRESSES_NEW (new_insn, -1);
- }
- remove_insn (insn);
- continue;
- }
+/* Helper function for s390_regs_ever_clobbered. Sets the fields in DATA for all
+ clobbered hard regs in SETREG. */
- if (GET_CODE (PATTERN (insn)) == SET
- && GET_CODE (SET_SRC (PATTERN (insn))) == REG
- && REGNO (SET_SRC (PATTERN (insn))) == BASE_REGISTER
- && GET_CODE (SET_DEST (PATTERN (insn))) == MEM)
- {
- set = PATTERN (insn);
- offset = const0_rtx;
- base = eliminate_constant_term (XEXP (SET_DEST (set), 0), &offset);
- off = INTVAL (offset) - BASE_REGISTER * UNITS_PER_WORD;
+static void
+s390_reg_clobbered_rtx (rtx setreg, 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 (base) != REG || off < 0)
- continue;
+ 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;
- if (save_first != -1)
- {
- new_insn = save_gprs (base, off, save_first, save_last);
- new_insn = emit_insn_before (new_insn, insn);
- INSN_ADDRESSES_NEW (new_insn, -1);
- }
+ for (i = regno;
+ i < regno + HARD_REGNO_NREGS (regno, mode);
+ i++)
+ regs_ever_clobbered[i] = 1;
+}
- remove_insn (insn);
- continue;
- }
+/* 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. */
- if (GET_CODE (PATTERN (insn)) == PARALLEL
- && load_multiple_operation (PATTERN (insn), VOIDmode))
+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 (current_function_calls_eh_return || cfun->machine->has_landing_pad_p)
+ for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM ; i++)
+ if (current_function_calls_eh_return
+ || (cfun->machine->has_landing_pad_p
+ && regs_ever_live [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 (current_function_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)
{
- 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) - first * UNITS_PER_WORD;
-
- if (GET_CODE (base) != REG || off < 0)
- continue;
- if (first > BASE_REGISTER || last < BASE_REGISTER)
- continue;
+ if (INSN_P (cur_insn))
+ note_stores (PATTERN (cur_insn),
+ s390_reg_clobbered_rtx,
+ regs_ever_clobbered);
+ }
+ }
+}
- if (restore_first != -1)
- {
- new_insn = restore_gprs (base, off, restore_first, restore_last);
- new_insn = emit_insn_before (new_insn, insn);
- INSN_ADDRESSES_NEW (new_insn, -1);
- }
+/* 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). */
- remove_insn (insn);
- continue;
- }
+static void
+s390_frame_area (int *area_bottom, int *area_top)
+{
+ int b, t;
+ int i;
- if (GET_CODE (PATTERN (insn)) == SET
- && GET_CODE (SET_DEST (PATTERN (insn))) == REG
- && REGNO (SET_DEST (PATTERN (insn))) == BASE_REGISTER
- && GET_CODE (SET_SRC (PATTERN (insn))) == MEM)
- {
- set = PATTERN (insn);
- offset = const0_rtx;
- base = eliminate_constant_term (XEXP (SET_SRC (set), 0), &offset);
- off = INTVAL (offset) - BASE_REGISTER * UNITS_PER_WORD;
+ b = INT_MAX;
+ t = INT_MIN;
- if (GET_CODE (base) != REG || off < 0)
- continue;
+ if (cfun_frame_layout.first_restore_gpr != -1)
+ {
+ b = (cfun_frame_layout.gprs_offset
+ + cfun_frame_layout.first_restore_gpr * UNITS_PER_WORD);
+ t = b + (cfun_frame_layout.last_restore_gpr
+ - cfun_frame_layout.first_restore_gpr + 1) * UNITS_PER_WORD;
+ }
- if (restore_first != -1)
- {
- new_insn = restore_gprs (base, off, restore_first, restore_last);
- new_insn = emit_insn_before (new_insn, insn);
- INSN_ADDRESSES_NEW (new_insn, -1);
- }
+ 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));
+ }
- remove_insn (insn);
- continue;
+ 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;
}
-/* Perform machine-dependent processing. */
+/* Fill cfun->machine with info about register usage of current function.
+ Return in CLOBBERED_REGS which GPRs are currently considered set. */
static void
-s390_reorg (void)
+s390_register_info (int clobbered_regs[])
{
- rtx base_reg = gen_rtx_REG (Pmode, BASE_REGISTER);
- bool base_used = false;
- bool pool_overflow = false;
+ int i, j;
- /* Make sure all splits have been performed; splits after
- machine_dependent_reorg might confuse insn length counts. */
- split_all_insns_noflow ();
+ /* 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 (regs_ever_live[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.
- /* In small leaf functions, try to use an unused call-clobbered
- register as base register to avoid save/restore overhead. */
- if (current_function_is_leaf && !regs_ever_live[5])
- base_reg = gen_rtx_REG (Pmode, 5);
+ Also, all registers with special meaning to the compiler need
+ to be handled extra. */
+ s390_regs_ever_clobbered (clobbered_regs);
- /* Install the main literal pool and the associated base
- register load insns.
+ for (i = 0; i < 16; i++)
+ clobbered_regs[i] = clobbered_regs[i] && !global_regs[i] && !fixed_regs[i];
- In addition, there are two problematic situations we need
- to correct:
+ if (frame_pointer_needed)
+ clobbered_regs[HARD_FRAME_POINTER_REGNUM] = 1;
- - the literal pool might be > 4096 bytes in size, so that
- some of its elements cannot be directly accessed
+ if (flag_pic)
+ clobbered_regs[PIC_OFFSET_TABLE_REGNUM]
+ |= regs_ever_live[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
+ || current_function_calls_eh_return
+ || current_function_stdarg);
+
+ clobbered_regs[STACK_POINTER_REGNUM]
+ |= (!current_function_is_leaf
+ || TARGET_TPF_PROFILING
+ || cfun_save_high_fprs_p
+ || get_frame_size () > 0
+ || current_function_calls_alloca
+ || current_function_stdarg);
- - a branch target might be > 64K away from the branch, so that
- it is not possible to use a PC-relative instruction.
+ for (i = 6; i < 16; i++)
+ if (regs_ever_live[i] || clobbered_regs[i])
+ break;
+ for (j = 15; j > i; j--)
+ if (regs_ever_live[j] || clobbered_regs[j])
+ break;
- 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.
+ 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;
- 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.
+ for (i = cfun_frame_layout.first_save_gpr_slot;
+ i < cfun_frame_layout.last_save_gpr_slot + 1;
+ i++)
+ if (clobbered_regs[i])
+ break;
- 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 (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;
+ }
+ }
- for (;;)
+ if (current_function_stdarg)
{
- struct constant_pool *pool = NULL;
-
- /* Collect the literal pool. */
- if (!pool_overflow)
+ /* Varargs functions need to save gprs 2 to 6. */
+ if (cfun->va_list_gpr_size
+ && current_function_args_info.gprs < GP_ARG_NUM_REG)
{
- pool = s390_mainpool_start ();
- if (!pool)
- pool_overflow = true;
+ int min_gpr = current_function_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;
+ }
}
- /* If literal pool overflowed, start to chunkify it. */
- if (pool_overflow)
- pool = s390_chunkify_start (base_reg);
+ /* Mark f0, f2 for 31 bit and f0-f4 for 64 bit to be saved. */
+ if (TARGET_HARD_FLOAT && cfun->va_list_fpr_size
+ && current_function_args_info.fprs < FP_ARG_NUM_REG)
+ {
+ int min_fpr = current_function_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);
+ }
+ }
- /* 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);
+ if (!TARGET_64BIT)
+ for (i = 2; i < 4; i++)
+ if (regs_ever_live[i + 16] && !global_regs[i + 16])
+ cfun_set_fpr_bit (i);
+}
- continue;
- }
+/* Fill cfun->machine with info about frame of current function. */
- /* If we made it up to here, both conditions are satisfied.
- Finish up literal pool related changes. */
- if ((pool_overflow || pool->size > 0)
- && REGNO (base_reg) == BASE_REGISTER)
- base_used = true;
+static void
+s390_frame_info (void)
+{
+ int i;
- if (pool_overflow)
- s390_chunkify_finish (pool, base_reg);
+ 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_WORD;
+ 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_WORD);
+ }
+ else if (TARGET_BACKCHAIN) /* kernel stack layout */
+ {
+ cfun_frame_layout.backchain_offset = (STACK_POINTER_OFFSET
+ - UNITS_PER_WORD);
+ cfun_frame_layout.gprs_offset
+ = (cfun_frame_layout.backchain_offset
+ - (STACK_POINTER_REGNUM - cfun_frame_layout.first_save_gpr_slot + 1)
+ * UNITS_PER_WORD);
+
+ 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
- s390_mainpool_finish (pool, base_reg);
-
- break;
+ {
+ /* 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;
}
- s390_optimize_prolog (base_used);
-}
-
+ if (current_function_is_leaf
+ && !TARGET_TPF_PROFILING
+ && cfun_frame_layout.frame_size == 0
+ && !cfun_save_high_fprs_p
+ && !current_function_calls_alloca
+ && !current_function_stdarg)
+ return;
-/* 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. */
+ if (!TARGET_PACKED_STACK)
+ cfun_frame_layout.frame_size += (STACK_POINTER_OFFSET
+ + current_function_outgoing_args_size
+ + cfun_frame_layout.high_fprs * 8);
+ else
+ {
+ if (TARGET_BACKCHAIN)
+ cfun_frame_layout.frame_size += UNITS_PER_WORD;
-rtx
-s390_return_addr_rtx (int count, rtx frame)
-{
- rtx addr;
+ /* 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);
- /* Without backchain, we fail for all but the current frame. */
+ cfun_frame_layout.frame_size += cfun_frame_layout.high_fprs * 8;
- if (!TARGET_BACKCHAIN && count > 0)
- return NULL_RTX;
+ 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));
- /* For the current frame, we need to make sure the initial
- value of RETURN_REGNUM is actually saved. */
+ cfun_frame_layout.frame_size += current_function_outgoing_args_size;
+ }
+}
- if (count == 0)
- cfun->machine->save_return_addr_p = true;
+/* 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. */
- /* To retrieve the return address we read the stack slot where the
- corresponding RETURN_REGNUM value was saved. */
+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
+ || current_function_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 && !regs_ever_live[5])
+ cfun->machine->base_reg = gen_rtx_REG (Pmode, 5);
+ else
+ cfun->machine->base_reg = gen_rtx_REG (Pmode, BASE_REGNUM);
- addr = plus_constant (frame, RETURN_REGNUM * UNITS_PER_WORD);
- addr = memory_address (Pmode, addr);
- return gen_rtx_MEM (Pmode, addr);
+ s390_register_info (clobbered_regs);
+ s390_frame_info ();
+ }
+ while (frame_size != cfun_frame_layout.frame_size);
}
-/* Find first call clobbered register unsused in a function.
- This could be used as base register in a leaf function
- or for holding the return address before epilogue. */
+/* 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 int
-find_unused_clobbered_reg (void)
+static void
+s390_update_frame_layout (void)
{
- int i;
- for (i = 0; i < 6; i++)
- if (!regs_ever_live[i])
- return i;
- return 0;
+ int clobbered_regs[16];
+
+ s390_register_info (clobbered_regs);
+
+ regs_ever_live[BASE_REGNUM] = clobbered_regs[BASE_REGNUM];
+ regs_ever_live[RETURN_REGNUM] = clobbered_regs[RETURN_REGNUM];
+ regs_ever_live[STACK_POINTER_REGNUM] = clobbered_regs[STACK_POINTER_REGNUM];
+
+ if (cfun->machine->base_reg)
+ regs_ever_live[REGNO (cfun->machine->base_reg)] = 1;
}
-/* Fill FRAME with info about frame of current function. */
+/* Return true if it is legal to put a value with MODE into REGNO. */
-static void
-s390_frame_info (void)
+bool
+s390_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
{
- int i, j;
- HOST_WIDE_INT fsize = get_frame_size ();
+ switch (REGNO_REG_CLASS (regno))
+ {
+ case FP_REGS:
+ if (REGNO_PAIR_OK (regno, mode))
+ {
+ if (mode == SImode || mode == DImode)
+ return true;
- if (!TARGET_64BIT && fsize > 0x7fff0000)
- fatal_error ("Total size of local variables exceeds architecture limit.");
+ 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;
- /* fprs 8 - 15 are caller saved for 64 Bit ABI. */
- cfun->machine->save_fprs_p = 0;
- if (TARGET_64BIT)
- for (i = 24; i < 32; i++)
- if (regs_ever_live[i] && !global_regs[i])
+ /* fallthrough */
+ case GENERAL_REGS:
+ if (REGNO_PAIR_OK (regno, mode))
{
- cfun->machine->save_fprs_p = 1;
- break;
+ if (TARGET_64BIT
+ || (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;
+}
- cfun->machine->frame_size = fsize + cfun->machine->save_fprs_p * 64;
+/* Return nonzero if register OLD_REG can be renamed to register NEW_REG. */
- /* Does function need to setup frame and save area. */
+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;
- if (! current_function_is_leaf
- || cfun->machine->frame_size > 0
- || current_function_calls_alloca
- || current_function_stdarg)
- cfun->machine->frame_size += STARTING_FRAME_OFFSET;
+ return true;
+}
- /* If we use the return register, we'll need to make sure
- it is going to be saved/restored. */
+/* Maximum number of registers to represent a value of mode MODE
+ in a register of class CLASS. */
- if (!current_function_is_leaf
- || regs_ever_live[RETURN_REGNUM])
- cfun->machine->save_return_addr_p = 1;
+bool
+s390_class_max_nregs (enum reg_class class, enum machine_mode mode)
+{
+ switch (class)
+ {
+ 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;
+}
- /* Find first and last gpr to be saved. Note that at this point,
- we assume the base register and -on S/390- the return register
- always need to be saved. This is done because the usage of these
- register might change even after the prolog was emitted.
- If it turns out later that we really don't need them, the
- prolog/epilog code is modified again. */
+/* Return true if register FROM can be eliminated via register TO. */
- regs_ever_live[BASE_REGISTER] = 1;
- if (!TARGET_CPU_ZARCH || cfun->machine->save_return_addr_p)
- regs_ever_live[RETURN_REGNUM] = 1;
- regs_ever_live[STACK_POINTER_REGNUM] = cfun->machine->frame_size > 0;
+bool
+s390_can_eliminate (int from, 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;
+ }
- for (i = 6; i < 16; i++)
- if (regs_ever_live[i])
- if (!global_regs[i]
- || i == STACK_POINTER_REGNUM
- || i == RETURN_REGNUM
- || i == BASE_REGISTER
- || (flag_pic && i == (int)PIC_OFFSET_TABLE_REGNUM))
- break;
+ return false;
+ }
- for (j = 15; j > i; j--)
- if (regs_ever_live[j])
- if (!global_regs[j]
- || j == STACK_POINTER_REGNUM
- || j == RETURN_REGNUM
- || j == BASE_REGISTER
- || (flag_pic && j == (int)PIC_OFFSET_TABLE_REGNUM))
- break;
+ /* Everything else must point into the stack frame. */
+ gcc_assert (to == STACK_POINTER_REGNUM
+ || to == HARD_FRAME_POINTER_REGNUM);
- /* Save / Restore from gpr i to j. */
- cfun->machine->first_save_gpr = i;
- cfun->machine->first_restore_gpr = i;
- cfun->machine->last_save_gpr = j;
+ gcc_assert (from == FRAME_POINTER_REGNUM
+ || from == ARG_POINTER_REGNUM
+ || from == RETURN_ADDRESS_POINTER_REGNUM);
- /* Varargs functions need to save gprs 2 to 6. */
- if (current_function_stdarg)
- cfun->machine->first_save_gpr = 2;
+ /* Make sure we actually saved the return address. */
+ if (from == RETURN_ADDRESS_POINTER_REGNUM)
+ if (!current_function_calls_eh_return
+ && !current_function_stdarg
+ && !cfun_frame_layout.save_return_addr_p)
+ return false;
+
+ return true;
}
-/* Return offset between argument pointer and frame pointer
- initially after prologue. */
+/* Return offset between register FROM and TO initially after prolog. */
HOST_WIDE_INT
-s390_arg_frame_offset (void)
+s390_initial_elimination_offset (int from, int to)
{
- HOST_WIDE_INT fsize = get_frame_size ();
- int save_fprs_p, i;
+ HOST_WIDE_INT offset;
+ int index;
- /* fprs 8 - 15 are caller saved for 64 Bit ABI. */
- save_fprs_p = 0;
- if (TARGET_64BIT)
- for (i = 24; i < 32; i++)
- if (regs_ever_live[i] && !global_regs[i])
- {
- save_fprs_p = 1;
- break;
- }
+ /* ??? Why are we called for non-eliminable pairs? */
+ if (!s390_can_eliminate (from, to))
+ return 0;
- fsize = fsize + save_fprs_p * 64;
+ switch (from)
+ {
+ case FRAME_POINTER_REGNUM:
+ offset = (get_frame_size()
+ + STACK_POINTER_OFFSET
+ + current_function_outgoing_args_size);
+ break;
- /* Does function need to setup frame and save area. */
+ 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_WORD;
+ break;
- if (! current_function_is_leaf
- || fsize > 0
- || current_function_calls_alloca
- || current_function_stdarg)
- fsize += STARTING_FRAME_OFFSET;
- return fsize + STACK_POINTER_OFFSET;
+ case BASE_REGNUM:
+ offset = 0;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return offset;
}
/* Emit insn to save fpr REGNUM at offset OFFSET relative
@@ -5409,7 +6952,11 @@ save_fpr (rtx base, int offset, int regnum)
{
rtx addr;
addr = gen_rtx_MEM (DFmode, plus_constant (base, offset));
- set_mem_alias_set (addr, s390_sr_alias_set);
+
+ 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));
}
@@ -5422,7 +6969,7 @@ restore_fpr (rtx base, int offset, int regnum)
{
rtx addr;
addr = gen_rtx_MEM (DFmode, plus_constant (base, offset));
- set_mem_alias_set (addr, s390_sr_alias_set);
+ set_mem_alias_set (addr, get_frame_alias_set ());
return emit_move_insn (gen_rtx_REG (DFmode, regnum), addr);
}
@@ -5437,9 +6984,10 @@ save_gprs (rtx base, int offset, int first, int last)
rtx addr, insn, note;
int i;
- addr = plus_constant (base, offset + first * UNITS_PER_WORD);
+ addr = plus_constant (base, offset);
addr = gen_rtx_MEM (Pmode, addr);
- set_mem_alias_set (addr, s390_sr_alias_set);
+
+ set_mem_alias_set (addr, get_frame_alias_set ());
/* Special-case single register. */
if (first == last)
@@ -5458,6 +7006,14 @@ save_gprs (rtx base, int offset, int first, int last)
gen_rtx_REG (Pmode, first),
GEN_INT (last - first + 1));
+ if (first <= 6 && current_function_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.
@@ -5465,7 +7021,7 @@ save_gprs (rtx base, int offset, int first, int last)
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 the
+ ??? 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
@@ -5483,7 +7039,7 @@ save_gprs (rtx base, int offset, int first, int last)
}
else if (last >= 6)
{
- addr = plus_constant (base, offset + 6 * UNITS_PER_WORD);
+ addr = plus_constant (base, offset + (6 - first) * UNITS_PER_WORD);
note = gen_store_multiple (gen_rtx_MEM (Pmode, addr),
gen_rtx_REG (Pmode, 6),
GEN_INT (last - 6 + 1));
@@ -5512,9 +7068,9 @@ restore_gprs (rtx base, int offset, int first, int last)
{
rtx addr, insn;
- addr = plus_constant (base, offset + first * UNITS_PER_WORD);
+ addr = plus_constant (base, offset);
addr = gen_rtx_MEM (Pmode, addr);
- set_mem_alias_set (addr, s390_sr_alias_set);
+ set_mem_alias_set (addr, get_frame_alias_set ());
/* Special-case single register. */
if (first == last)
@@ -5533,49 +7089,47 @@ restore_gprs (rtx base, int offset, int first, int last)
return insn;
}
-/* Emit code to load the GOT register. If MAYBE_DEAD is true,
- annotate generated insns with REG_MAYBE_DEAD notes. */
+/* Return insn sequence to load the GOT register. */
static GTY(()) rtx got_symbol;
-void
-s390_load_got (int maybe_dead)
+rtx
+s390_load_got (void)
{
+ rtx insns;
+
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)
{
- rtx insn = emit_move_insn (pic_offset_table_rtx, got_symbol);
- if (maybe_dead)
- REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
- REG_NOTES (insn));
+ emit_move_insn (pic_offset_table_rtx, got_symbol);
}
else
{
- rtx offset, insn;
+ 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);
- insn = emit_move_insn (pic_offset_table_rtx, offset);
- if (maybe_dead)
- REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
- REG_NOTES (insn));
+ emit_move_insn (pic_offset_table_rtx, offset);
offset = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, XEXP (offset, 0)),
UNSPEC_LTREL_BASE);
offset = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, offset);
- insn = emit_move_insn (pic_offset_table_rtx, offset);
- if (maybe_dead)
- REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
- REG_NOTES (insn));
+ emit_move_insn (pic_offset_table_rtx, offset);
}
+
+ insns = get_insns ();
+ end_sequence ();
+ return insns;
}
/* Expand the prologue into a bunch of separate insns. */
@@ -5586,90 +7140,179 @@ 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 ();
- /* Compute frame_info. */
+ /* Annotate all constant pool references to let the scheduler know
+ they implicitly use the base register. */
- s390_frame_info ();
+ push_topmost_sequence ();
+
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (INSN_P (insn))
+ annotate_constant_pool_refs (&PATTERN (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 (!current_function_is_leaf
- && !TARGET_TPF)
+ 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. */
-
- insn = save_gprs (stack_pointer_rtx, 0,
- cfun->machine->first_save_gpr, cfun->machine->last_save_gpr);
- emit_insn (insn);
+ if (cfun_frame_layout.first_save_gpr != -1)
+ {
+ insn = save_gprs (stack_pointer_rtx,
+ cfun_frame_layout.gprs_offset +
+ UNITS_PER_WORD * (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. */
- emit_insn (gen_main_pool ());
-
- /* Save fprs for variable args. */
+ if (cfun->machine->base_reg)
+ emit_insn (gen_main_pool (cfun->machine->base_reg));
- if (current_function_stdarg)
- for (i = 16; i < (TARGET_64BIT ? 20 : 18); i++)
- save_fpr (stack_pointer_rtx, 16*UNITS_PER_WORD + 8*(i-16), i);
+ offset = cfun_frame_layout.f0_offset;
- /* Save fprs 4 and 6 if used (31 bit ABI). */
+ /* 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;
+ }
- if (!TARGET_64BIT)
- for (i = 18; i < 20; i++)
- if (regs_ever_live[i] && !global_regs[i])
+ /* 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, 16*UNITS_PER_WORD + 8*(i-16), i);
- RTX_FRAME_RELATED_P (insn) = 1;
+ 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;
/* Decrement stack pointer. */
- if (cfun->machine->frame_size > 0)
+ if (cfun_frame_layout.frame_size > 0)
{
- rtx frame_off = GEN_INT (-cfun->machine->frame_size);
+ rtx frame_off = GEN_INT (-cfun_frame_layout.frame_size);
- /* Save incoming stack pointer into temp reg. */
+ if (s390_stack_size)
+ {
+ HOST_WIDE_INT stack_check_mask = ((s390_stack_size - 1)
+ & ~(s390_stack_guard - 1));
+ rtx t = gen_rtx_AND (Pmode, stack_pointer_rtx,
+ GEN_INT (stack_check_mask));
- if (TARGET_BACKCHAIN || cfun->machine->save_fprs_p)
- {
- insn = emit_insn (gen_move_insn (temp_reg, stack_pointer_rtx));
- }
+ if (TARGET_64BIT)
+ gen_cmpdi (t, const0_rtx);
+ else
+ gen_cmpsi (t, const0_rtx);
+
+ emit_insn (gen_conditional_trap (gen_rtx_EQ (CCmode,
+ gen_rtx_REG (CCmode,
+ CC_REGNUM),
+ const0_rtx),
+ const0_rtx));
+ }
+
+ if (s390_warn_framesize > 0
+ && cfun_frame_layout.frame_size >= s390_warn_framesize)
+ warning (0, "frame size of %qs is " HOST_WIDE_INT_PRINT_DEC " 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,
+ gen_rtx_PLUS (Pmode, stack_pointer_rtx,
frame_off));
insn = emit_insn (insn);
}
else
{
- if (!CONST_OK_FOR_CONSTRAINT_P (INTVAL (frame_off), 'K', "K"))
+ 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;
REG_NOTES (insn) =
gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
gen_rtx_SET (VOIDmode, stack_pointer_rtx,
- gen_rtx_PLUS (Pmode, stack_pointer_rtx,
- GEN_INT (-cfun->machine->frame_size))),
+ gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+ GEN_INT (-cfun_frame_layout.frame_size))),
REG_NOTES (insn));
/* Set backchain. */
if (TARGET_BACKCHAIN)
{
- addr = gen_rtx_MEM (Pmode, stack_pointer_rtx);
- set_mem_alias_set (addr, s390_sr_alias_set);
+ 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));
}
@@ -5686,24 +7329,30 @@ s390_emit_prologue (void)
/* Save fprs 8 - 15 (64 bit ABI). */
- if (cfun->machine->save_fprs_p)
+ if (cfun_save_high_fprs_p && next_fpr)
{
- insn = emit_insn (gen_add2_insn (temp_reg, GEN_INT(-64)));
+ insn = emit_insn (gen_add2_insn (temp_reg,
+ GEN_INT (cfun_frame_layout.f8_offset)));
- for (i = 24; i < 32; i++)
- if (regs_ever_live[i] && !global_regs[i])
+ offset = 0;
+
+ for (i = 24; i <= next_fpr; i++)
+ if (cfun_fpr_bit_p (i - 16))
{
rtx addr = plus_constant (stack_pointer_rtx,
- cfun->machine->frame_size - 64 + (i-24)*8);
-
- insn = save_fpr (temp_reg, (i-24)*8, i);
+ 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;
REG_NOTES (insn) =
gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
- gen_rtx_SET (VOIDmode,
- gen_rtx_MEM (DFmode, addr),
- gen_rtx_REG (DFmode, i)),
- REG_NOTES (insn));
+ gen_rtx_SET (VOIDmode,
+ gen_rtx_MEM (DFmode, addr),
+ gen_rtx_REG (DFmode, i)),
+ REG_NOTES (insn));
}
}
@@ -5718,24 +7367,26 @@ s390_emit_prologue (void)
/* Set up got pointer, if needed. */
if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
- s390_load_got(true);
-
- if (TARGET_TPF)
{
- /* Generate a BAS instruction to serve as a function
- entry intercept to facilitate the use of tracing
- algorithms located at the branch target.
+ rtx insns = s390_load_got ();
- This must use register 1. */
- rtx addr;
- rtx unkn;
- rtx link;
+ for (insn = insns; insn; insn = NEXT_INSN (insn))
+ {
+ annotate_constant_pool_refs (&PATTERN (insn));
- addr = GEN_INT (0xfe0);
- unkn = CONST0_RTX (SImode);
- link = gen_rtx_REG (Pmode, 1);
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, NULL_RTX,
+ REG_NOTES (insn));
+ }
- emit_call_insn (gen_call_exp (gen_rtx_MEM (QImode, addr), unkn, link));
+ 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. */
@@ -5746,76 +7397,34 @@ s390_emit_prologue (void)
/* Expand the epilogue into a bunch of separate insns. */
void
-s390_emit_epilogue (void)
+s390_emit_epilogue (bool sibcall)
{
rtx frame_pointer, return_reg;
int area_bottom, area_top, offset = 0;
+ int next_offset;
rtvec p;
int i;
- if (TARGET_TPF)
+ 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.
-
- This must use register 1. */
-
- rtx addr;
- rtx unkn;
- rtx link;
-
- addr = GEN_INT (0xfe6);
- unkn = CONST0_RTX (SImode);
- link = gen_rtx_REG (Pmode, 1);
+ algorithms located at the branch target. */
/* Emit a blockage here so that all code
lies between the profiling mechanisms. */
emit_insn (gen_blockage ());
- emit_call_insn (gen_call_exp (gen_rtx_MEM (QImode, addr), unkn, link));
+ 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;
+ frame_pointer = (frame_pointer_needed
+ ? hard_frame_pointer_rtx : stack_pointer_rtx);
- /* Compute which parts of the save area we need to access. */
-
- if (cfun->machine->first_restore_gpr != -1)
- {
- area_bottom = cfun->machine->first_restore_gpr * UNITS_PER_WORD;
- area_top = (cfun->machine->last_save_gpr + 1) * UNITS_PER_WORD;
- }
- else
- {
- area_bottom = INT_MAX;
- area_top = INT_MIN;
- }
-
- if (TARGET_64BIT)
- {
- if (cfun->machine->save_fprs_p)
- {
- if (area_bottom > -64)
- area_bottom = -64;
- if (area_top < 0)
- area_top = 0;
- }
- }
- else
- {
- for (i = 18; i < 20; i++)
- if (regs_ever_live[i] && !global_regs[i])
- {
- if (area_bottom > 16*UNITS_PER_WORD + 8*(i-16))
- area_bottom = 16*UNITS_PER_WORD + 8*(i-16);
- if (area_top < 16*UNITS_PER_WORD + 8*(i-16) + 8)
- area_top = 16*UNITS_PER_WORD + 8*(i-16) + 8;
- }
- }
+ s390_frame_area (&area_bottom, &area_top);
/* Check whether we can access the register save area.
If not, increment the frame pointer as required. */
@@ -5824,18 +7433,18 @@ s390_emit_epilogue (void)
{
/* Nothing to restore. */
}
- else if (DISP_IN_RANGE (cfun->machine->frame_size + area_bottom)
- && DISP_IN_RANGE (cfun->machine->frame_size + area_top-1))
+ 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->machine->frame_size;
+ offset = cfun_frame_layout.frame_size;
}
else
{
rtx insn, frame_off;
offset = area_bottom < 0 ? -area_bottom : 0;
- frame_off = GEN_INT (cfun->machine->frame_size - offset);
+ frame_off = GEN_INT (cfun_frame_layout.frame_size - offset);
if (DISP_IN_RANGE (INTVAL (frame_off)))
{
@@ -5845,10 +7454,11 @@ s390_emit_epilogue (void)
}
else
{
- if (!CONST_OK_FOR_CONSTRAINT_P (INTVAL (frame_off), 'K', "K"))
+ 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));
}
}
@@ -5856,18 +7466,36 @@ s390_emit_epilogue (void)
if (TARGET_64BIT)
{
- if (cfun->machine->save_fprs_p)
- for (i = 24; i < 32; i++)
- if (regs_ever_live[i] && !global_regs[i])
- restore_fpr (frame_pointer,
- offset - 64 + (i-24) * 8, i);
+ 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);
+ next_offset += 8;
+ }
+ }
+ }
+
}
else
{
+ next_offset = cfun_frame_layout.f4_offset;
for (i = 18; i < 20; i++)
- if (regs_ever_live[i] && !global_regs[i])
- restore_fpr (frame_pointer,
- offset + 16*UNITS_PER_WORD + 8*(i-16), i);
+ {
+ if (cfun_fpr_bit_p (i - 16))
+ {
+ restore_fpr (frame_pointer,
+ offset + next_offset, i);
+ next_offset += 8;
+ }
+ else if (!TARGET_PACKED_STACK)
+ next_offset += 8;
+ }
+
}
/* Return register. */
@@ -5876,7 +7504,7 @@ s390_emit_epilogue (void)
/* Restore call saved gprs. */
- if (cfun->machine->first_restore_gpr != -1)
+ if (cfun_frame_layout.first_restore_gpr != -1)
{
rtx insn, addr;
int i;
@@ -5884,66 +7512,76 @@ s390_emit_epilogue (void)
/* Check for global register and save them
to stack location from where they get restored. */
- for (i = cfun->machine->first_restore_gpr;
- i <= cfun->machine->last_save_gpr;
+ for (i = cfun_frame_layout.first_restore_gpr;
+ i <= cfun_frame_layout.last_restore_gpr;
i++)
{
/* These registers are special and need to be
restored in any case. */
if (i == STACK_POINTER_REGNUM
|| i == RETURN_REGNUM
- || i == BASE_REGISTER
+ || i == BASE_REGNUM
|| (flag_pic && i == (int)PIC_OFFSET_TABLE_REGNUM))
continue;
if (global_regs[i])
{
addr = plus_constant (frame_pointer,
- offset + i * UNITS_PER_WORD);
+ offset + cfun_frame_layout.gprs_offset
+ + (i - cfun_frame_layout.first_save_gpr_slot)
+ * UNITS_PER_WORD);
addr = gen_rtx_MEM (Pmode, addr);
- set_mem_alias_set (addr, s390_sr_alias_set);
+ set_mem_alias_set (addr, get_frame_alias_set ());
emit_move_insn (addr, gen_rtx_REG (Pmode, i));
}
}
- /* Fetch return address from stack before load multiple,
- this will do good for scheduling. */
-
- if (cfun->machine->save_return_addr_p
- || (cfun->machine->first_restore_gpr < BASE_REGISTER
- && cfun->machine->last_save_gpr > RETURN_REGNUM))
+ if (! sibcall)
{
- int return_regnum = find_unused_clobbered_reg();
- if (!return_regnum)
- return_regnum = 4;
- return_reg = gen_rtx_REG (Pmode, return_regnum);
-
- addr = plus_constant (frame_pointer,
- offset + RETURN_REGNUM * UNITS_PER_WORD);
- addr = gen_rtx_MEM (Pmode, addr);
- set_mem_alias_set (addr, s390_sr_alias_set);
- emit_move_insn (return_reg, addr);
- }
+ /* Fetch return address from stack before load multiple,
+ this will do good for scheduling. */
- /* ??? As references to the base register are not made
- explicit in insn RTX code, we have to add a barrier here
- to prevent incorrect 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);
- emit_insn (gen_blockage());
+ addr = plus_constant (frame_pointer,
+ offset + cfun_frame_layout.gprs_offset
+ + (RETURN_REGNUM
+ - cfun_frame_layout.first_save_gpr_slot)
+ * UNITS_PER_WORD);
+ 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->machine->first_restore_gpr,
- cfun->machine->last_save_gpr);
+ 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_WORD,
+ cfun_frame_layout.first_restore_gpr,
+ cfun_frame_layout.last_restore_gpr);
emit_insn (insn);
}
- /* Return to caller. */
+ if (! sibcall)
+ {
+
+ /* Return to caller. */
- p = rtvec_alloc (2);
+ p = rtvec_alloc (2);
- RTVEC_ELT (p, 0) = gen_rtx_RETURN (VOIDmode);
- RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode, return_reg);
- emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
+ RTVEC_ELT (p, 0) = gen_rtx_RETURN (VOIDmode);
+ RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode, return_reg);
+ emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
+ }
}
@@ -5962,7 +7600,7 @@ s390_function_arg_size (enum machine_mode mode, tree type)
return GET_MODE_SIZE (mode);
/* If we have neither type nor mode, abort */
- abort ();
+ gcc_unreachable ();
}
/* Return true if a function argument of type TYPE and mode MODE
@@ -5981,7 +7619,7 @@ s390_function_arg_float (enum machine_mode mode, tree type)
/* No type info available for some library calls ... */
if (!type)
- return mode == SFmode || mode == DFmode;
+ 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. */
@@ -6023,17 +7661,17 @@ s390_function_arg_integer (enum machine_mode mode, tree type)
/* No type info available for some library calls ... */
if (!type)
return GET_MODE_CLASS (mode) == MODE_INT
- || (TARGET_SOFT_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT);
+ || (TARGET_SOFT_FLOAT && SCALAR_FLOAT_MODE_P (mode));
/* We accept small integral (and similar) types. */
if (INTEGRAL_TYPE_P (type)
- || POINTER_TYPE_P (type)
+ || POINTER_TYPE_P (type)
|| TREE_CODE (type) == OFFSET_TYPE
|| (TARGET_SOFT_FLOAT && TREE_CODE (type) == REAL_TYPE))
return true;
/* We also accept structs of size 1, 2, 4, 8 that are not
- passed in floating-point registers. */
+ passed in floating-point registers. */
if (AGGREGATE_TYPE_P (type)
&& exact_log2 (size) >= 0
&& !s390_function_arg_float (mode, type))
@@ -6048,8 +7686,10 @@ s390_function_arg_integer (enum machine_mode mode, tree type)
all other structures (and complex numbers) are passed by
reference. */
-int
-s390_function_arg_pass_by_reference (enum machine_mode mode, tree type)
+static bool
+s390_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
+ enum machine_mode mode, tree type,
+ bool named ATTRIBUTE_UNUSED)
{
int size = s390_function_arg_size (mode, type);
if (size > 8)
@@ -6078,11 +7718,7 @@ void
s390_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
tree type, int named ATTRIBUTE_UNUSED)
{
- if (s390_function_arg_pass_by_reference (mode, type))
- {
- cum->gprs += 1;
- }
- else if (s390_function_arg_float (mode, type))
+ if (s390_function_arg_float (mode, type))
{
cum->fprs += 1;
}
@@ -6092,7 +7728,7 @@ s390_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
cum->gprs += ((size + UNITS_PER_WORD-1) / UNITS_PER_WORD);
}
else
- abort ();
+ gcc_unreachable ();
}
/* Define where to put the arguments to a function.
@@ -6118,25 +7754,22 @@ rtx
s390_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
int named ATTRIBUTE_UNUSED)
{
- if (s390_function_arg_pass_by_reference (mode, type))
- return 0;
-
if (s390_function_arg_float (mode, type))
{
- if (cum->fprs + 1 > (TARGET_64BIT? 4 : 2))
+ if (cum->fprs + 1 > FP_ARG_NUM_REG)
return 0;
else
- return gen_rtx (REG, mode, cum->fprs + 16);
+ 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_WORD-1) / UNITS_PER_WORD;
- if (cum->gprs + n_gprs > 5)
+ if (cum->gprs + n_gprs > GP_ARG_NUM_REG)
return 0;
else
- return gen_rtx (REG, mode, cum->gprs + 2);
+ return gen_rtx_REG (mode, cum->gprs + 2);
}
/* After the real arguments, expand_call calls us once again
@@ -6147,7 +7780,7 @@ s390_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
else if (type == void_type_node)
return const0_rtx;
- abort ();
+ gcc_unreachable ();
}
/* Return true if return values of type TYPE should be returned
@@ -6159,7 +7792,7 @@ s390_return_in_memory (tree type, tree fundecl ATTRIBUTE_UNUSED)
{
/* We accept small integral (and similar) types. */
if (INTEGRAL_TYPE_P (type)
- || POINTER_TYPE_P (type)
+ || POINTER_TYPE_P (type)
|| TREE_CODE (type) == OFFSET_TYPE
|| TREE_CODE (type) == REAL_TYPE)
return int_size_in_bytes (type) > 8;
@@ -6186,17 +7819,14 @@ s390_function_value (tree type, enum machine_mode mode)
{
if (type)
{
- int unsignedp = TREE_UNSIGNED (type);
+ int unsignedp = TYPE_UNSIGNED (type);
mode = promote_mode (type, TYPE_MODE (type), &unsignedp, 1);
}
- if (GET_MODE_CLASS (mode) != MODE_INT
- && GET_MODE_CLASS (mode) != MODE_FLOAT)
- abort ();
- if (GET_MODE_SIZE (mode) > 8)
- abort ();
+ gcc_assert (GET_MODE_CLASS (mode) == MODE_INT || SCALAR_FLOAT_MODE_P (mode));
+ gcc_assert (GET_MODE_SIZE (mode) <= 8);
- if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
+ if (TARGET_HARD_FLOAT && SCALAR_FLOAT_MODE_P (mode))
return gen_rtx_REG (mode, 16);
else
return gen_rtx_REG (mode, 2);
@@ -6243,6 +7873,9 @@ s390_build_builtin_va_list (void)
f_sav = build_decl (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;
@@ -6287,47 +7920,64 @@ s390_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
f_ovf = TREE_CHAIN (f_fpr);
f_sav = TREE_CHAIN (f_ovf);
- valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
- gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
- fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
- ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
- sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+ 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);
+ 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 = current_function_args_info.gprs;
n_fpr = current_function_args_info.fprs;
- t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, build_int_2 (n_gpr, 0));
- TREE_SIDE_EFFECTS (t) = 1;
- expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ 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);
+ }
- t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, build_int_2 (n_fpr, 0));
- 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. */
- t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
+ 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 (current_function_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);
+ off = INTVAL (current_function_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 = build (PLUS_EXPR, TREE_TYPE (ovf), t, build_int_2 (off, 0));
+ t = build2 (PLUS_EXPR, TREE_TYPE (ovf), t, build_int_cst (NULL_TREE, off));
- t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
- TREE_SIDE_EFFECTS (t) = 1;
- expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ 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. */
- t = make_tree (TREE_TYPE (sav), virtual_incoming_args_rtx);
- t = build (PLUS_EXPR, TREE_TYPE (sav), t,
- build_int_2 (-STACK_POINTER_OFFSET, -1));
- t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, t);
- TREE_SIDE_EFFECTS (t) = 1;
- expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ 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 = build2 (PLUS_EXPR, TREE_TYPE (sav), t,
+ build_int_cst (NULL_TREE, -RETURN_REGNUM * UNITS_PER_WORD));
+
+ 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
@@ -6354,28 +8004,29 @@ s390_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
ret = **args.overflow_arg_area++;
} */
-rtx
-s390_va_arg (tree valist, tree type)
+static tree
+s390_gimplify_va_arg (tree valist, tree type, tree *pre_p,
+ tree *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;
- rtx lab_false, lab_over, addr_rtx, r;
+ tree lab_false, lab_over, addr;
f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
f_fpr = TREE_CHAIN (f_gpr);
f_ovf = TREE_CHAIN (f_fpr);
f_sav = TREE_CHAIN (f_ovf);
- valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
- gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
- fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
- ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
- sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+ 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);
+ 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);
size = int_size_in_bytes (type);
- if (s390_function_arg_pass_by_reference (TYPE_MODE (type), type))
+ if (pass_by_reference (NULL, TYPE_MODE (type), type, false))
{
if (TARGET_DEBUG_ARG)
{
@@ -6387,10 +8038,14 @@ s390_va_arg (tree valist, tree type)
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_WORD;
sav_scale = UNITS_PER_WORD;
size = UNITS_PER_WORD;
- max_reg = 4;
+ max_reg = GP_ARG_NUM_REG - n_reg;
}
else if (s390_function_arg_float (TYPE_MODE (type), type))
{
@@ -6406,8 +8061,7 @@ s390_va_arg (tree valist, tree type)
n_reg = 1;
sav_ofs = 16 * UNITS_PER_WORD;
sav_scale = 8;
- /* TARGET_64BIT has up to 4 parameter in fprs */
- max_reg = TARGET_64BIT ? 3 : 1;
+ max_reg = FP_ARG_NUM_REG - n_reg;
}
else
{
@@ -6421,93 +8075,88 @@ s390_va_arg (tree valist, tree type)
indirect_p = 0;
reg = gpr;
n_reg = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+
+ /* 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_WORD;
if (size < UNITS_PER_WORD)
sav_ofs += UNITS_PER_WORD - size;
sav_scale = UNITS_PER_WORD;
- if (n_reg > 1)
- max_reg = 3;
- else
- max_reg = 4;
+ max_reg = GP_ARG_NUM_REG - n_reg;
}
/* Pull the value out of the saved registers ... */
- lab_false = gen_label_rtx ();
- lab_over = gen_label_rtx ();
- addr_rtx = gen_reg_rtx (Pmode);
+ lab_false = create_artificial_label ();
+ lab_over = create_artificial_label ();
+ addr = create_tmp_var (ptr_type_node, "addr");
+ DECL_POINTER_ALIAS_SET (addr) = get_varargs_alias_set ();
- emit_cmp_and_jump_insns (expand_expr (reg, NULL_RTX, Pmode, EXPAND_NORMAL),
- GEN_INT (max_reg),
- GT, const1_rtx, Pmode, 0, lab_false);
-
- if (sav_ofs)
- t = build (PLUS_EXPR, ptr_type_node, sav, build_int_2 (sav_ofs, 0));
- else
- t = sav;
+ 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);
- u = build (MULT_EXPR, long_integer_type_node,
- reg, build_int_2 (sav_scale, 0));
- TREE_SIDE_EFFECTS (u) = 1;
+ t = build2 (PLUS_EXPR, ptr_type_node, sav,
+ fold_convert (ptr_type_node, size_int (sav_ofs)));
+ u = build2 (MULT_EXPR, TREE_TYPE (reg), reg,
+ fold_convert (TREE_TYPE (reg), size_int (sav_scale)));
+ t = build2 (PLUS_EXPR, ptr_type_node, t, fold_convert (ptr_type_node, u));
- t = build (PLUS_EXPR, ptr_type_node, t, u);
- TREE_SIDE_EFFECTS (t) = 1;
+ t = build2 (MODIFY_EXPR, void_type_node, addr, t);
+ gimplify_and_add (t, pre_p);
- r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
- if (r != addr_rtx)
- emit_move_insn (addr_rtx, r);
+ t = build1 (GOTO_EXPR, void_type_node, lab_over);
+ gimplify_and_add (t, pre_p);
+ t = build1 (LABEL_EXPR, void_type_node, lab_false);
+ append_to_statement_list (t, pre_p);
- emit_jump_insn (gen_jump (lab_over));
- emit_barrier ();
- emit_label (lab_false);
/* ... Otherwise out of the overflow area. */
- t = save_expr (ovf);
-
-
- /* In 64 BIT for each argument on stack, a full 64 bit slot is allocated. */
+ t = ovf;
if (size < UNITS_PER_WORD)
- {
- t = build (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (UNITS_PER_WORD-size, 0));
- t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
- TREE_SIDE_EFFECTS (t) = 1;
- expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ t = build2 (PLUS_EXPR, ptr_type_node, t,
+ fold_convert (ptr_type_node, size_int (UNITS_PER_WORD - size)));
- t = save_expr (ovf);
- }
+ gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue);
+
+ u = build2 (MODIFY_EXPR, void_type_node, addr, t);
+ gimplify_and_add (u, pre_p);
- r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
- if (r != addr_rtx)
- emit_move_insn (addr_rtx, r);
+ t = build2 (PLUS_EXPR, ptr_type_node, t,
+ fold_convert (ptr_type_node, size_int (size)));
+ t = build2 (MODIFY_EXPR, ptr_type_node, ovf, t);
+ gimplify_and_add (t, pre_p);
- t = build (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (size, 0));
- t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
- TREE_SIDE_EFFECTS (t) = 1;
- expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ t = build1 (LABEL_EXPR, void_type_node, lab_over);
+ append_to_statement_list (t, pre_p);
- emit_label (lab_over);
- /* If less than max_regs a registers are retrieved out
- of register save area, increment. */
+ /* Increment register save count. */
- u = build (PREINCREMENT_EXPR, TREE_TYPE (reg), reg,
- build_int_2 (n_reg, 0));
- TREE_SIDE_EFFECTS (u) = 1;
- expand_expr (u, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ 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)
{
- r = gen_rtx_MEM (Pmode, addr_rtx);
- set_mem_alias_set (r, get_varargs_alias_set ());
- emit_move_insn (addr_rtx, r);
+ t = build_pointer_type (build_pointer_type (type));
+ addr = fold_convert (t, addr);
+ addr = build_va_arg_indirect_ref (addr);
+ }
+ else
+ {
+ t = build_pointer_type (type);
+ addr = fold_convert (t, addr);
}
-
- return addr_rtx;
+ return build_va_arg_indirect_ref (addr);
}
@@ -6537,14 +8186,14 @@ s390_init_builtins (void)
tree ftype;
ftype = build_function_type (ptr_type_node, void_list_node);
- builtin_function ("__builtin_thread_pointer", ftype,
- S390_BUILTIN_THREAD_POINTER, BUILT_IN_MD,
- NULL, NULL_TREE);
+ lang_hooks.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);
- builtin_function ("__builtin_set_thread_pointer", ftype,
- S390_BUILTIN_SET_THREAD_POINTER, BUILT_IN_MD,
- NULL, NULL_TREE);
+ lang_hooks.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,
@@ -6623,7 +8272,7 @@ s390_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
pat = GEN_FCN (icode) (target, op[0], op[1]);
break;
default:
- abort ();
+ gcc_unreachable ();
}
if (!pat)
return NULL_RTX;
@@ -6645,23 +8294,23 @@ s390_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
void
s390_trampoline_template (FILE *file)
{
+ rtx op[2];
+ op[0] = gen_rtx_REG (Pmode, 0);
+ op[1] = gen_rtx_REG (Pmode, 1);
+
if (TARGET_64BIT)
{
- fprintf (file, "larl\t%s,0f\n", reg_names[1]);
- fprintf (file, "lg\t%s,0(%s)\n", reg_names[0], reg_names[1]);
- fprintf (file, "lg\t%s,8(%s)\n", reg_names[1], reg_names[1]);
- fprintf (file, "br\t%s\n", reg_names[1]);
- fprintf (file, "0:\t.quad\t0\n");
- fprintf (file, ".quad\t0\n");
+ output_asm_insn ("basr\t%1,0", op);
+ output_asm_insn ("lmg\t%0,%1,14(%1)", op);
+ output_asm_insn ("br\t%1", op);
+ ASM_OUTPUT_SKIP (file, (HOST_WIDE_INT)(TRAMPOLINE_SIZE - 10));
}
else
{
- fprintf (file, "basr\t%s,0\n", reg_names[1]);
- fprintf (file, "l\t%s,10(%s)\n", reg_names[0], reg_names[1]);
- fprintf (file, "l\t%s,14(%s)\n", reg_names[1], reg_names[1]);
- fprintf (file, "br\t%s\n", reg_names[1]);
- fprintf (file, ".long\t0\n");
- fprintf (file, ".long\t0\n");
+ output_asm_insn ("basr\t%1,0", op);
+ output_asm_insn ("lm\t%0,%1,6(%1)", op);
+ output_asm_insn ("br\t%1", op);
+ ASM_OUTPUT_SKIP (file, (HOST_WIDE_INT)(TRAMPOLINE_SIZE - 8));
}
}
@@ -6672,14 +8321,12 @@ s390_trampoline_template (FILE *file)
void
s390_initialize_trampoline (rtx addr, rtx fnaddr, rtx cxt)
{
- emit_move_insn (gen_rtx
- (MEM, Pmode,
+ emit_move_insn (gen_rtx_MEM (Pmode,
memory_address (Pmode,
- plus_constant (addr, (TARGET_64BIT ? 20 : 12) ))), cxt);
- emit_move_insn (gen_rtx
- (MEM, Pmode,
+ plus_constant (addr, (TARGET_64BIT ? 16 : 8)))), cxt);
+ emit_move_insn (gen_rtx_MEM (Pmode,
memory_address (Pmode,
- plus_constant (addr, (TARGET_64BIT ? 28 : 16) ))), fnaddr);
+ plus_constant (addr, (TARGET_64BIT ? 24 : 12)))), fnaddr);
}
/* Return rtx for 64-bit constant formed from the 32-bit subwords
@@ -6699,7 +8346,7 @@ s390_gen_rtx_const_DI (int high, int low)
#if HOST_BITS_PER_WIDE_INT >= 32
return immed_double_const ((HOST_WIDE_INT)low, (HOST_WIDE_INT)high, DImode);
#else
- abort ();
+ gcc_unreachable ();
#endif
#endif
}
@@ -6772,20 +8419,6 @@ s390_function_profiler (FILE *file, int labelno)
}
}
-/* Select section for constant in constant pool. In 32-bit mode,
- constants go in the function section; in 64-bit mode in .rodata. */
-
-static void
-s390_select_rtx_section (enum machine_mode mode ATTRIBUTE_UNUSED,
- rtx x ATTRIBUTE_UNUSED,
- unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
-{
- if (TARGET_CPU_ZARCH)
- readonly_data_section ();
- else
- function_section (current_function_decl);
-}
-
/* Encode symbol attributes (local vs. global, tls model) of a SYMBOL_REF
into its SYMBOL_REF_FLAGS. */
@@ -6854,9 +8487,11 @@ s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
{
/* Setup literal pool pointer if required. */
if ((!DISP_IN_RANGE (delta)
- && !CONST_OK_FOR_CONSTRAINT_P (delta, 'K', "K"))
+ && !CONST_OK_FOR_K (delta)
+ && !CONST_OK_FOR_Os (delta))
|| (!DISP_IN_RANGE (vcall_offset)
- && !CONST_OK_FOR_CONSTRAINT_P (vcall_offset, 'K', "K")))
+ && !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);
@@ -6865,12 +8500,14 @@ s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
/* Add DELTA to this pointer. */
if (delta)
{
- if (CONST_OK_FOR_CONSTRAINT_P (delta, 'J', "J"))
+ 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_CONSTRAINT_P (delta, 'K', "K"))
+ 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 ();
@@ -6886,12 +8523,18 @@ s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
output_asm_insn ("lg\t%4,0(%1)", op);
output_asm_insn ("ag\t%1,%3(%4)", op);
}
- else if (CONST_OK_FOR_CONSTRAINT_P (vcall_offset, 'K', "K"))
+ 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 ();
@@ -6929,9 +8572,11 @@ s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
/* Setup base pointer if required. */
if (!vcall_offset
|| (!DISP_IN_RANGE (delta)
- && !CONST_OK_FOR_CONSTRAINT_P (delta, 'K', "K"))
+ && !CONST_OK_FOR_K (delta)
+ && !CONST_OK_FOR_Os (delta))
|| (!DISP_IN_RANGE (delta)
- && !CONST_OK_FOR_CONSTRAINT_P (vcall_offset, 'K', "K")))
+ && !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);
@@ -6942,12 +8587,14 @@ s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
/* Add DELTA to this pointer. */
if (delta)
{
- if (CONST_OK_FOR_CONSTRAINT_P (delta, 'J', "J"))
+ 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_CONSTRAINT_P (delta, 'K', "K"))
+ 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 ();
@@ -6958,22 +8605,28 @@ s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
/* Perform vcall adjustment. */
if (vcall_offset)
{
- if (CONST_OK_FOR_CONSTRAINT_P (vcall_offset, 'J', "J"))
+ if (CONST_OK_FOR_J (vcall_offset))
{
- output_asm_insn ("lg\t%4,0(%1)", op);
+ 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 ("lg\t%4,0(%1)", op);
+ output_asm_insn ("l\t%4,0(%1)", op);
output_asm_insn ("ay\t%1,%3(%4)", op);
}
- else if (CONST_OK_FOR_CONSTRAINT_P (vcall_offset, 'K', "K"))
+ 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 ();
@@ -7046,18 +8699,630 @@ s390_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
}
}
-bool
+static bool
s390_valid_pointer_mode (enum machine_mode mode)
{
return (mode == SImode || (TARGET_64BIT && mode == DImode));
}
-/* How to allocate a 'struct machine_function'. */
+/* Checks whether the given ARGUMENT_LIST would use a caller
+ saved register. This is used to decide whether sibling call
+ optimization could be performed on the respective function
+ call. */
-static struct machine_function *
-s390_init_machine_status (void)
+static bool
+s390_call_saved_register_used (tree argument_list)
{
- return ggc_alloc_cleared (sizeof (struct machine_function));
+ CUMULATIVE_ARGS cum;
+ tree parameter;
+ enum machine_mode mode;
+ tree type;
+ rtx parm_rtx;
+ int reg;
+
+ INIT_CUMULATIVE_ARGS (cum, NULL, NULL, 0, 0);
+
+ while (argument_list)
+ {
+ parameter = TREE_VALUE (argument_list);
+ argument_list = TREE_CHAIN (argument_list);
+
+ 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, 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 && 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;
+ }
+ }
+ 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. */
+ if (TREE_OPERAND (exp, 1)
+ && s390_call_saved_register_used (TREE_OPERAND (exp, 1)))
+ return false;
+
+ return true;
+}
+
+/* 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))
+ {
+ addr_location = gen_rtx_UNSPEC (Pmode,
+ gen_rtvec (1, addr_location),
+ UNSPEC_PLT);
+ addr_location = gen_rtx_CONST (Pmode, addr_location);
+ plt_call = true;
+ }
+
+ /* 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), pic_offset_table_rtx);
+ }
+ return insn;
+}
+
+/* Implement CONDITIONAL_REGISTER_USAGE. */
+
+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_WORD,
+ 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_WORD,
+ 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;
+ }
+ }
}
+/* 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 ();
+
+ /* From here on decomposed literal pool addresses must be accepted. */
+ cfun->machine->decomposed_literal_pool_addresses_ok_p = true;
+
+ /* 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 ();
+}
+
+
+/* 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_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS (TARGET_DEFAULT | MASK_FUSED_MADD)
+#undef TARGET_HANDLE_OPTION
+#define TARGET_HANDLE_OPTION s390_handle_option
+
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO s390_encode_section_info
+
+#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_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_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_tree_hwi_hwi_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_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_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_GIMPLIFY_VA_ARG_EXPR
+#define TARGET_GIMPLIFY_VA_ARG_EXPR s390_gimplify_va_arg
+
+#undef TARGET_PROMOTE_FUNCTION_ARGS
+#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
+#undef TARGET_PROMOTE_FUNCTION_RETURN
+#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
+#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_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_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_FUNDAMENTAL_TYPE
+#define TARGET_MANGLE_FUNDAMENTAL_TYPE s390_mangle_fundamental_type
+#endif
+
+#undef TARGET_SCALAR_MODE_SUPPORTED_P
+#define TARGET_SCALAR_MODE_SUPPORTED_P s390_scalar_mode_supported_p
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+
#include "gt-s390.h"
diff --git a/contrib/gcc/config/s390/s390.h b/contrib/gcc/config/s390/s390.h
index d2416c8..ba7a036 100644
--- a/contrib/gcc/config/s390/s390.h
+++ b/contrib/gcc/config/s390/s390.h
@@ -1,5 +1,5 @@
/* Definitions of target machine for GNU compiler, for IBM S/390
- Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
+ Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
Contributed by Hartmut Penner (hpenner@de.ibm.com) and
Ulrich Weigand (uweigand@de.ibm.com).
@@ -18,8 +18,8 @@ for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
#ifndef _S390_H
#define _S390_H
@@ -40,6 +40,7 @@ enum processor_type
PROCESSOR_9672_G6,
PROCESSOR_2064_Z900,
PROCESSOR_2084_Z990,
+ PROCESSOR_2094_Z9_109,
PROCESSOR_max
};
@@ -49,16 +50,15 @@ enum processor_flags
{
PF_IEEE_FLOAT = 1,
PF_ZARCH = 2,
- PF_LONG_DISPLACEMENT = 4
+ PF_LONG_DISPLACEMENT = 4,
+ PF_EXTIMM = 8
};
extern enum processor_type s390_tune;
extern enum processor_flags s390_tune_flags;
-extern const char *s390_tune_string;
extern enum processor_type s390_arch;
extern enum processor_flags s390_arch_flags;
-extern const char *s390_arch_string;
#define TARGET_CPU_IEEE_FLOAT \
(s390_arch_flags & PF_IEEE_FLOAT)
@@ -66,13 +66,24 @@ extern const char *s390_arch_string;
(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_LONG_DISPLACEMENT \
(TARGET_ZARCH && TARGET_CPU_LONG_DISPLACEMENT)
-
+#define TARGET_EXTIMM \
+ (TARGET_ZARCH && TARGET_CPU_EXTIMM)
/* 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 \
@@ -82,72 +93,21 @@ extern const char *s390_arch_string;
builtin_define ("__s390__"); \
if (TARGET_64BIT) \
builtin_define ("__s390x__"); \
+ if (TARGET_LONG_DOUBLE_128) \
+ builtin_define ("__LONG_DOUBLE_128__"); \
} \
while (0)
-/* Optional target features. */
-extern int target_flags;
-
-#define MASK_HARD_FLOAT 0x01
-#define MASK_BACKCHAIN 0x02
-#define MASK_SMALL_EXEC 0x04
-#define MASK_DEBUG_ARG 0x08
-#define MASK_64BIT 0x10
-#define MASK_ZARCH 0x20
-#define MASK_MVCLE 0x40
-#define MASK_TPF 0x80
-#define MASK_NO_FUSED_MADD 0x100
-
-#define TARGET_HARD_FLOAT (target_flags & MASK_HARD_FLOAT)
-#define TARGET_SOFT_FLOAT (!(target_flags & MASK_HARD_FLOAT))
-#define TARGET_BACKCHAIN (target_flags & MASK_BACKCHAIN)
-#define TARGET_SMALL_EXEC (target_flags & MASK_SMALL_EXEC)
-#define TARGET_DEBUG_ARG (target_flags & MASK_DEBUG_ARG)
-#define TARGET_64BIT (target_flags & MASK_64BIT)
-#define TARGET_ZARCH (target_flags & MASK_ZARCH)
-#define TARGET_MVCLE (target_flags & MASK_MVCLE)
-#define TARGET_TPF (target_flags & MASK_TPF)
-#define TARGET_NO_FUSED_MADD (target_flags & MASK_NO_FUSED_MADD)
-#define TARGET_FUSED_MADD (! TARGET_NO_FUSED_MADD)
-
/* ??? Once this actually works, it could be made a runtime option. */
#define TARGET_IBM_FLOAT 0
#define TARGET_IEEE_FLOAT 1
#ifdef DEFAULT_TARGET_64BIT
-#define TARGET_DEFAULT 0x31
+#define TARGET_DEFAULT (MASK_64BIT | MASK_ZARCH | MASK_HARD_FLOAT)
#else
-#define TARGET_DEFAULT 0x1
+#define TARGET_DEFAULT MASK_HARD_FLOAT
#endif
-#define TARGET_SWITCHES \
-{ { "hard-float", 1, N_("Use hardware fp")}, \
- { "soft-float", -1, N_("Don't use hardware fp")}, \
- { "backchain", 2, N_("Set backchain")}, \
- { "no-backchain", -2, N_("Don't set backchain (faster, but debug harder")},\
- { "small-exec", 4, N_("Use bras for executable < 64k")}, \
- { "no-small-exec", -4, N_("Don't use bras")}, \
- { "debug", 8, N_("Additional debug prints")}, \
- { "no-debug", -8, N_("Don't print additional debug prints")}, \
- { "64", 16, N_("64 bit ABI")}, \
- { "31", -16, N_("31 bit ABI")}, \
- { "zarch", 32, N_("z/Architecture")}, \
- { "esa", -32, N_("ESA/390 architecture")}, \
- { "mvcle", 64, N_("mvcle use")}, \
- { "no-mvcle", -64, N_("mvc&ex")}, \
- { "tpf", 128, N_("enable tpf OS code")}, \
- { "no-tpf", -128, N_("disable tpf OS code")}, \
- { "no-fused-madd", 256, N_("disable fused multiply/add instructions")},\
- { "fused-madd", -256, N_("enable fused multiply/add instructions")}, \
- { "", TARGET_DEFAULT, 0 } }
-
-#define TARGET_OPTIONS \
-{ { "tune=", &s390_tune_string, \
- N_("Schedule code for given CPU"), 0}, \
- { "arch=", &s390_arch_string, \
- N_("Generate code for given CPU"), 0}, \
-}
-
/* Support for configure-time defaults. */
#define OPTION_DEFAULT_SPECS \
{ "mode", "%{!mesa:%{!mzarch:-m%(VALUE)}}" }, \
@@ -208,11 +168,7 @@ extern int target_flags;
#define MAX_BITS_PER_WORD 64
/* Function arguments and return values are promoted to word size. */
-#define PROMOTE_FUNCTION_ARGS
-#define PROMOTE_FUNCTION_RETURN
-#define PROMOTE_FOR_CALL_ONLY
-
-#define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE) \
+#define PROMOTE_FUNCTION_MODE(MODE, UNSIGNEDP, TYPE) \
if (INTEGRAL_MODE_P (MODE) && \
GET_MODE_SIZE (MODE) < UNITS_PER_WORD) { \
(MODE) = Pmode; \
@@ -259,11 +215,21 @@ if (INTEGRAL_MODE_P (MODE) && \
#define SHORT_TYPE_SIZE 16
#define INT_TYPE_SIZE 32
#define LONG_TYPE_SIZE (TARGET_64BIT ? 64 : 32)
-#define MAX_LONG_TYPE_SIZE 64
#define LONG_LONG_TYPE_SIZE 64
#define FLOAT_TYPE_SIZE 32
#define DOUBLE_TYPE_SIZE 64
-#define LONG_DOUBLE_TYPE_SIZE 64 /* ??? Should support extended format. */
+#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
@@ -283,30 +249,32 @@ if (INTEGRAL_MODE_P (MODE) && \
GPR 14: Return address register
GPR 15: Stack pointer
- Registers 32-34 are 'fake' hard registers that do not
+ 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 34: Frame pointer
+ Reg 35: Return address pointer
-#define FIRST_PSEUDO_REGISTER 35
+ 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) < (TARGET_IEEE_FLOAT? 32 : 20))
#define CC_REGNO_P(N) ((N) == 33)
-#define FRAME_REGNO_P(N) ((N) == 32 || (N) == 34)
+#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 BASE_REGISTER 13
-#define RETURN_REGNUM 14
-#define CC_REGNUM 33
+#define ACCESS_REG_P(X) (REG_P (X) && ACCESS_REGNO_P (REGNO (X)))
/* Set up fixed registers and calling convention:
@@ -317,6 +285,7 @@ if (INTEGRAL_MODE_P (MODE) && \
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.
@@ -331,7 +300,8 @@ if (INTEGRAL_MODE_P (MODE) && \
0, 0, 0, 0, \
0, 0, 0, 0, \
0, 0, 0, 0, \
- 1, 1, 1 }
+ 1, 1, 1, 1, \
+ 1, 1 }
#define CALL_USED_REGISTERS \
{ 1, 1, 1, 1, \
@@ -342,7 +312,8 @@ if (INTEGRAL_MODE_P (MODE) && \
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, \
@@ -353,41 +324,17 @@ if (INTEGRAL_MODE_P (MODE) && \
1, 1, 1, 1, \
1, 1, 1, 1, \
1, 1, 1, 1, \
- 1, 1, 1 }
-
-#define CONDITIONAL_REGISTER_USAGE \
-do \
- { \
- 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[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; \
- } \
- } while (0)
+ 1, 1, 1, 1, \
+ 0, 0 }
+
+#define CONDITIONAL_REGISTER_USAGE s390_conditional_register_usage ()
/* Preferred register allocation order. */
#define REG_ALLOC_ORDER \
-{ 1, 2, 3, 4, 5, 0, 13, 12, 11, 10, 9, 8, 7, 6, 14, \
+{ 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 }
+ 15, 32, 33, 34, 35, 36, 37 }
/* Fitting values into registers. */
@@ -400,31 +347,24 @@ do \
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) \
- (FP_REGNO_P(REGNO)? \
- (GET_MODE_CLASS(MODE) == MODE_COMPLEX_FLOAT ? 2 : 1) : \
- GENERAL_REGNO_P(REGNO)? \
- ((GET_MODE_SIZE(MODE)+UNITS_PER_WORD-1) / UNITS_PER_WORD) : \
- 1)
-
-#define HARD_REGNO_MODE_OK(REGNO, MODE) \
- (FP_REGNO_P(REGNO)? \
- ((MODE) == SImode || (MODE) == DImode || \
- GET_MODE_CLASS(MODE) == MODE_FLOAT || \
- GET_MODE_CLASS(MODE) == MODE_COMPLEX_FLOAT) : \
- GENERAL_REGNO_P(REGNO)? \
- (HARD_REGNO_NREGS(REGNO, MODE) == 1 || !((REGNO) & 1)) : \
- CC_REGNO_P(REGNO)? \
- GET_MODE_CLASS (MODE) == MODE_CC : \
- FRAME_REGNO_P(REGNO)? \
- (enum machine_mode) (MODE) == Pmode : \
- 0)
+ 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) \
@@ -433,16 +373,18 @@ do \
/* Maximum number of registers to represent a value of mode MODE
in a register of class CLASS. */
#define CLASS_MAX_NREGS(CLASS, MODE) \
- ((CLASS) == FP_REGS ? \
- (GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT ? 2 : 1) : \
- (GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+ 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. */
-#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
- (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \
- ? reg_classes_intersect_p (FP_REGS, CLASS) : 0)
+ 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. */
@@ -451,39 +393,48 @@ do \
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. The condition
- code register is only included in ALL_REGS. */
+ are included amongst the address registers here. */
enum reg_class
{
- NO_REGS, ADDR_REGS, GENERAL_REGS,
+ 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", "ADDR_REGS", "GENERAL_REGS", \
+#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 */ \
- { 0x0000fffe, 0x00000005 }, /* ADDR_REGS */ \
- { 0x0000ffff, 0x00000005 }, /* GENERAL_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, 0x00000005 }, /* ADDR_FP_REGS */ \
- { 0xffffffff, 0x00000005 }, /* GENERAL_FP_REGS */ \
- { 0xffffffff, 0x00000007 }, /* ALL_REGS */ \
+ { 0xfffffffe, 0x0000000d }, /* ADDR_FP_REGS */ \
+ { 0xffffffff, 0x0000000d }, /* GENERAL_FP_REGS */ \
+ { 0xffffffff, 0x0000003f }, /* ALL_REGS */ \
}
/* Register -> class mapping. */
@@ -498,8 +449,8 @@ extern const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER];
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) \
- || (reg_renumber[REGNO] > 0 && reg_renumber[REGNO] < 16))
+ && 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)
@@ -530,35 +481,13 @@ extern const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER];
: MODE)
-/* Define various machine-dependent constraint letters. */
-
-#define REG_CLASS_FROM_LETTER(C) \
- ((C) == 'a' ? ADDR_REGS : \
- (C) == 'd' ? GENERAL_REGS : \
- (C) == 'f' ? FP_REGS : NO_REGS)
-
-#define CONST_OK_FOR_CONSTRAINT_P(VALUE, C, STR) \
- s390_const_ok_for_constraint_p ((VALUE), (C), (STR))
-
-#define CONST_DOUBLE_OK_FOR_CONSTRAINT_P(VALUE, C, STR) 1
-
-#define EXTRA_CONSTRAINT_STR(OP, C, STR) \
- s390_extra_constraint_str ((OP), (C), (STR))
-#define EXTRA_MEMORY_CONSTRAINT(C, STR) \
- ((C) == 'Q' || (C) == 'R' || (C) == 'S' || (C) == 'T')
-#define EXTRA_ADDRESS_CONSTRAINT(C, STR) \
- ((C) == 'U' || (C) == 'W' || (C) == 'Y')
-
-#define CONSTRAINT_LEN(C, STR) \
- ((C) == 'N' ? 5 : DEFAULT_CONSTRAINT_LEN ((C), (STR)))
-
/* Stack layout and calling conventions. */
/* Our stack grows from higher to lower addresses. However, local variables
are accessed by positive offsets, and function arguments are stored at
increasing addresses. */
#define STACK_GROWS_DOWNWARD
-/* #undef FRAME_GROWS_DOWNWARD */
+#define FRAME_GROWS_DOWNWARD 1
/* #undef ARGS_GROW_DOWNWARD */
/* The basic stack layout looks like this: the stack pointer points
@@ -570,33 +499,39 @@ extern const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER];
#define STACK_POINTER_OFFSET (TARGET_64BIT ? 160 : 96)
/* Offset within stack frame to start allocating local variables at. */
-extern int current_function_outgoing_args_size;
-#define STARTING_FRAME_OFFSET \
- (STACK_POINTER_OFFSET + current_function_outgoing_args_size)
+#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) (STARTING_FRAME_OFFSET)
+extern int current_function_outgoing_args_size;
+#define STACK_DYNAMIC_OFFSET(FUNDECL) \
+ (STACK_POINTER_OFFSET + current_function_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 \
+ (TARGET_PACKED_STACK ? \
+ plus_constant (arg_pointer_rtx, -UNITS_PER_WORD) : \
+ 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_WORD) : (FRAME))
-#define DYNAMIC_CHAIN_ADDRESS(FRAME) \
- ((FRAME) != hard_frame_pointer_rtx ? (FRAME) : \
- plus_constant (arg_pointer_rtx, -STACK_POINTER_OFFSET))
-
-#define RETURN_ADDR_RTX(COUNT, FRAME) \
+#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 ? GEN_INT (-1) : GEN_INT (0x7fffffff))
+#define MASK_RETURN_ADDR (TARGET_64BIT ? constm1_rtx : GEN_INT (0x7fffffff))
/* Exception handling. */
@@ -608,10 +543,8 @@ extern int current_function_outgoing_args_size;
/* 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, plus_constant (arg_pointer_rtx, \
- -STACK_POINTER_OFFSET + UNITS_PER_WORD*RETURN_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 \
@@ -625,6 +558,7 @@ extern int current_function_outgoing_args_size;
#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
@@ -641,30 +575,20 @@ extern int current_function_outgoing_args_size;
#define FRAME_POINTER_REQUIRED 0
-#define INITIAL_FRAME_POINTER_OFFSET(DEPTH) (DEPTH) = 0
-
-#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}}
-
-#define CAN_ELIMINATE(FROM, TO) (1)
-
-#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
-{ if ((FROM) == FRAME_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \
- { (OFFSET) = 0; } \
- else if ((FROM) == FRAME_POINTER_REGNUM \
- && (TO) == HARD_FRAME_POINTER_REGNUM) \
- { (OFFSET) = 0; } \
- else if ((FROM) == ARG_POINTER_REGNUM \
- && (TO) == HARD_FRAME_POINTER_REGNUM) \
- { (OFFSET) = s390_arg_frame_offset (); } \
- else if ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \
- { (OFFSET) = s390_arg_frame_offset (); } \
- else \
- abort(); \
-}
+#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 CAN_ELIMINATE(FROM, TO) \
+ s390_can_eliminate ((FROM), (TO))
+
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+ (OFFSET) = s390_initial_elimination_offset ((FROM), (TO))
/* Stack arguments. */
@@ -694,11 +618,6 @@ CUMULATIVE_ARGS;
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
s390_function_arg (&CUM, MODE, TYPE, NAMED)
-#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \
- s390_function_arg_pass_by_reference (MODE, TYPE)
-
-#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 0
-
/* Arguments can be placed in general registers 2 to 6,
or in floating point registers 0 and 2. */
#define FUNCTION_ARG_REGNO_P(N) (((N) >=2 && (N) <7) || \
@@ -716,9 +635,6 @@ CUMULATIVE_ARGS;
/* Only gpr 2 and fpr 0 are ever used as return registers. */
#define FUNCTION_VALUE_REGNO_P(N) ((N) == 2 || (N) == 16)
-/* Structure value address is passed as invisible first argument (gpr 2). */
-#define STRUCT_VALUE 0
-
/* Function entry and exit. */
@@ -739,13 +655,9 @@ CUMULATIVE_ARGS;
#define EXPAND_BUILTIN_VA_START(valist, nextarg) \
s390_va_start (valist, nextarg)
-#define EXPAND_BUILTIN_VA_ARG(valist, type) \
- s390_va_arg (valist, type)
-
-
/* Trampolines for nested functions. */
-#define TRAMPOLINE_SIZE (TARGET_64BIT ? 36 : 20)
+#define TRAMPOLINE_SIZE (TARGET_64BIT ? 32 : 16)
#define INITIALIZE_TRAMPOLINE(ADDR, FNADDR, CXT) \
s390_initialize_trampoline ((ADDR), (FNADDR), (CXT))
@@ -754,12 +666,6 @@ CUMULATIVE_ARGS;
s390_trampoline_template (FILE)
-/* Library calls. */
-
-/* We should use memcpy, not bcopy. */
-#define TARGET_MEM_FUNCTIONS
-
-
/* Addressing modes, and classification of registers for them. */
/* Recognize any constant value that is a valid address. */
@@ -768,38 +674,6 @@ CUMULATIVE_ARGS;
/* Maximum number of registers that can appear in a valid memory address. */
#define MAX_REGS_PER_ADDRESS 2
-/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx and check
- its validity for a certain class. We have two alternate definitions
- for each of them. The usual definition accepts all pseudo regs; the
- other rejects them all. The symbol REG_OK_STRICT causes the latter
- definition to be used.
-
- Most source files want to accept pseudo regs in the hope that they will
- get allocated to the class that the insn wants them to be in.
- Some source files that are used after register allocation
- need to be strict. */
-
-#define REG_OK_FOR_INDEX_NONSTRICT_P(X) \
-((GET_MODE (X) == Pmode) && \
- ((REGNO (X) >= FIRST_PSEUDO_REGISTER) \
- || REGNO_REG_CLASS (REGNO (X)) == ADDR_REGS))
-
-#define REG_OK_FOR_BASE_NONSTRICT_P(X) REG_OK_FOR_INDEX_NONSTRICT_P (X)
-
-#define REG_OK_FOR_INDEX_STRICT_P(X) \
-((GET_MODE (X) == Pmode) && (REGNO_OK_FOR_INDEX_P (REGNO (X))))
-
-#define REG_OK_FOR_BASE_STRICT_P(X) \
-((GET_MODE (X) == Pmode) && (REGNO_OK_FOR_BASE_P (REGNO (X))))
-
-#ifndef REG_OK_STRICT
-#define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_INDEX_NONSTRICT_P(X)
-#define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_NONSTRICT_P(X)
-#else
-#define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_INDEX_STRICT_P(X)
-#define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_STRICT_P(X)
-#endif
-
/* S/390 has no mode dependent addresses. */
#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL)
@@ -831,6 +705,19 @@ CUMULATIVE_ARGS;
goto WIN; \
}
+/* Try a machine-dependent way of reloading an illegitimate address
+ operand. If we find one, push the reload and jump to WIN. This
+ macro is used in only one place: `find_reloads_address' in reload.c. */
+#define LEGITIMIZE_RELOAD_ADDRESS(AD, MODE, OPNUM, TYPE, IND, WIN) \
+do { \
+ rtx new = legitimize_reload_address (AD, MODE, OPNUM, (int)(TYPE)); \
+ if (new) \
+ { \
+ (AD) = new; \
+ goto WIN; \
+ } \
+} while (0)
+
/* Nonzero if the constant value X is a legitimate general operand.
It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
#define LEGITIMATE_CONSTANT_P(X) \
@@ -853,10 +740,14 @@ CUMULATIVE_ARGS;
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))
+
/* Define the information needed to generate branch and scc insns. This is
stored from the compare operation. Note that we can't use "rtx" here
since it hasn't been defined! */
-extern struct rtx_def *s390_compare_op0, *s390_compare_op1;
+extern struct rtx_def *s390_compare_op0, *s390_compare_op1, *s390_compare_emitted;
/* Relative costs of operations. */
@@ -880,9 +771,14 @@ extern struct rtx_def *s390_compare_op0, *s390_compare_op1;
/* 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. */
+ between memory and registers or between two memory locations. */
#define MOVE_MAX (TARGET_64BIT ? 16 : 8)
+#define MOVE_MAX_PIECES (TARGET_64BIT ? 8 : 4)
#define MAX_MOVE_MAX 16
/* Determine whether to use move_by_pieces or block move insn. */
@@ -895,6 +791,11 @@ extern struct rtx_def *s390_compare_op0, *s390_compare_op1;
( (SIZE) == 1 || (SIZE) == 2 || (SIZE) == 4 \
|| (TARGET_64BIT && (SIZE) == 8) )
+/* This macro is used to determine whether store_by_pieces should be
+ called to "memset" storage with byte values other than zero, or
+ to "memcpy" storage when the source is a constant string. */
+#define STORE_BY_PIECES_P(SIZE, ALIGN) MOVE_BY_PIECES_P (SIZE, ALIGN)
+
/* Don't perform CSE on function addresses. */
#define NO_FUNCTION_CSE
@@ -959,23 +860,23 @@ extern int flag_pic;
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", \
+ "%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" \
+ "%f8", "%f10", "%f12", "%f14", "%f9", "%f11", "%f13", "%f15", \
+ "%ap", "%cc", "%fp", "%rp", "%a0", "%a1" \
}
-/* Emit a dtp-relative reference to a TLS variable. */
-
-#ifdef HAVE_AS_TLS
-#define ASM_OUTPUT_DWARF_DTPREL(FILE, SIZE, X) \
- s390_output_dwarf_dtprel (FILE, SIZE, X)
-#endif
-
/* Print operand X (an rtx) in assembler syntax to file FILE. */
#define PRINT_OPERAND(FILE, X, CODE) print_operand (FILE, X, CODE)
#define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address (FILE, ADDR)
+/* Output machine-dependent UNSPECs in address constants. */
+#define OUTPUT_ADDR_CONST_EXTRA(FILE, X, FAIL) \
+do { \
+ if (!s390_output_addr_const_extra (FILE, (X))) \
+ goto FAIL; \
+} while (0);
+
/* Output an element of a case-vector that is absolute. */
#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
do { \
@@ -1002,22 +903,6 @@ do { \
/* Miscellaneous parameters. */
-/* Define the codes that are matched by predicates in aux-output.c. */
-#define PREDICATE_CODES \
- {"s_operand", { SUBREG, MEM }}, \
- {"s_imm_operand", { CONST_INT, CONST_DOUBLE, SUBREG, MEM }}, \
- {"shift_count_operand", { REG, SUBREG, PLUS, CONST_INT }}, \
- {"bras_sym_operand",{ SYMBOL_REF, CONST }}, \
- {"larl_operand", { SYMBOL_REF, CONST, CONST_INT, CONST_DOUBLE }}, \
- {"load_multiple_operation", {PARALLEL}}, \
- {"store_multiple_operation", {PARALLEL}}, \
- {"const0_operand", { CONST_INT, CONST_DOUBLE }}, \
- {"consttable_operand", { SYMBOL_REF, LABEL_REF, CONST, \
- CONST_INT, CONST_DOUBLE }}, \
- {"s390_plus_operand", { PLUS }}, \
- {"s390_alc_comparison", { LTU, GTU, LEU, GEU }}, \
- {"s390_slb_comparison", { LTU, GTU, LEU, GEU }},
-
/* Specify the machine mode that this machine uses for the index in the
tablejump instruction. */
#define CASE_VECTOR_MODE (TARGET_64BIT ? DImode : SImode)
@@ -1038,7 +923,15 @@ do { \
indexing purposes) so give the MEM rtx a byte's mode. */
#define FUNCTION_MODE QImode
-/* This macro definition sets up a default value for `main' to return. */
-#define DEFAULT_MAIN_RETURN c_expand_return (integer_zero_node)
+/* 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)
+
+/* Check whether integer displacement is in range. */
+#define DISP_IN_RANGE(d) \
+ (TARGET_LONG_DISPLACEMENT? ((d) >= -524288 && (d) <= 524287) \
+ : ((d) >= 0 && (d) <= 4095))
#endif
diff --git a/contrib/gcc/config/s390/s390.md b/contrib/gcc/config/s390/s390.md
index 345a36a..2348409 100644
--- a/contrib/gcc/config/s390/s390.md
+++ b/contrib/gcc/config/s390/s390.md
@@ -1,5 +1,5 @@
;;- Machine description for GNU compiler -- S/390 / zSeries version.
-;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
+;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
;; Free Software Foundation, Inc.
;; Contributed by Hartmut Penner (hpenner@de.ibm.com) and
;; Ulrich Weigand (uweigand@de.ibm.com).
@@ -18,53 +18,34 @@
;; You should have received a copy of the GNU General Public License
;; along with GCC; see the file COPYING. If not, write to the Free
-;; Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-;; 02111-1307, USA.
+;; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+;; 02110-1301, USA.
;;
-;; Special constraints for s/390 machine description:
-;;
-;; a -- Any address register from 1 to 15.
-;; d -- Any register from 0 to 15.
-;; 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: number of the part counting from most to least significant
-;; H,Q: mode of the part
-;; D,S,H: mode of the containing operand
-;; 0,F: value of the other parts (F - all bits set)
-;;
-;; The constraint matches if the specified part of a constant
-;; has a value different from its other parts.
-;; Q -- Memory reference without index register and with short displacement.
-;; R -- Memory reference with index register and short displacement.
-;; S -- Memory reference without index register but with long displacement.
-;; T -- Memory reference with index register and long displacement.
-;; U -- Pointer with short displacement.
-;; W -- Pointer with long displacement.
-;; Y -- Shift count operand.
+;; 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.
-;; %x: print integer X as if it's an unsigned word.
-;; %h: print integer X as if it's a signed word.
-;; %i: print the first nonzero HImode part of X
-;; %j: print the first HImode part unequal to 0xffff of X
-
+;; %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.
;;
@@ -78,7 +59,8 @@
(define_constants
[; Miscellaneous
(UNSPEC_ROUND 1)
- (UNSPEC_SETHIGH 10)
+ (UNSPEC_CMPINT 2)
+ (UNSPEC_ICM 10)
; GOT/PLT and lt-relative accesses
(UNSPEC_LTREL_OFFSET 100)
@@ -92,6 +74,9 @@
; Literal pool
(UNSPEC_RELOAD_BASE 210)
(UNSPEC_MAIN_BASE 211)
+ (UNSPEC_LTREF 212)
+ (UNSPEC_INSN 213)
+ (UNSPEC_EXECUTE 214)
; TLS relocation specifiers
(UNSPEC_TLSGD 500)
@@ -102,12 +87,16 @@
(UNSPEC_INDNTPOFF 505)
; TLS support
- (UNSPEC_TP 510)
(UNSPEC_TLSLDM_NTPOFF 511)
(UNSPEC_TLS_LOAD 512)
; String Functions
- (UNSPEC_SRST 600)
+ (UNSPEC_SRST 600)
+ (UNSPEC_MVST 601)
+
+ ; Stack Smashing Protector
+ (UNSPEC_SP_SET 700)
+ (UNSPEC_SP_TEST 701)
])
;;
@@ -118,233 +107,241 @@
[; Blockage
(UNSPECV_BLOCKAGE 0)
+ ; TPF Support
+ (UNSPECV_TPF_PROLOGUE 20)
+ (UNSPECV_TPF_EPILOGUE 21)
+
; Literal pool
(UNSPECV_POOL 200)
- (UNSPECV_POOL_START 201)
- (UNSPECV_POOL_END 202)
+ (UNSPECV_POOL_SECTION 201)
+ (UNSPECV_POOL_ALIGN 202)
(UNSPECV_POOL_ENTRY 203)
(UNSPECV_MAIN_POOL 300)
; TLS support
(UNSPECV_SET_TP 500)
- ])
-
-;; Processor type. This attribute must exactly match the processor_type
-;; enumeration in s390.h.
+ ; Atomic Support
+ (UNSPECV_MB 700)
+ (UNSPECV_CAS 701)
+ ])
-(define_attr "cpu" "g5,g6,z900,z990"
- (const (symbol_ref "s390_tune")))
+;;
+;; Registers
+;;
-;; Define an insn type attribute. This is used in function unit delay
-;; computations.
+(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)
+ ])
-(define_attr "type" "none,integer,load,lr,la,larl,lm,stm,
- cs,vs,store,imul,idiv,
- branch,jsr,fsimpd,fsimps,
- floadd,floads,fstored, fstores,
- fmuld,fmuls,fdivd,fdivs,
- ftoi,itof,fsqrtd,fsqrts,
- other,o2,o3"
- (const_string "integer"))
-;; Operand type. Used to default length attribute values
+;; 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"
- (const_string "RX"))
+ (const_string "NN"))
-;; Insn are devide in two classes:
-;; agen: Insn using agen
-;; reg: Insn not using agen
+;; 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,
+ floadtf,floaddf,floadsf,fstoredf,fstoresf,
+ fmultf,fmuldf,fmulsf,fdivtf,fdivdf,fdivsf,
+ ftoi,itof,fsqrttf,fsqrtdf,fsqrtsf,
+ ftrunctf,ftruncdf,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"
-(cond [ (eq_attr "op_type" "E") (const_string "reg")
- (eq_attr "op_type" "RR") (const_string "reg")
- (eq_attr "op_type" "RX") (const_string "agen")
- (eq_attr "op_type" "RI") (const_string "reg")
- (eq_attr "op_type" "RRE") (const_string "reg")
- (eq_attr "op_type" "RS") (const_string "agen")
- (eq_attr "op_type" "RSI") (const_string "agen")
- (eq_attr "op_type" "S") (const_string "agen")
- (eq_attr "op_type" "SI") (const_string "agen")
- (eq_attr "op_type" "SS") (const_string "agen")
- (eq_attr "op_type" "SSE") (const_string "agen")
- (eq_attr "op_type" "RXE") (const_string "agen")
- (eq_attr "op_type" "RSE") (const_string "agen")
- (eq_attr "op_type" "RIL") (const_string "agen")
- (eq_attr "op_type" "RXY") (const_string "agen")
- (eq_attr "op_type" "RSY") (const_string "agen")
- (eq_attr "op_type" "SIY") (const_string "agen")]
- (const_string "reg")))
+ (if_then_else (eq_attr "op_type" "E,RR,RI,RRE")
+ (const_string "reg")
+ (const_string "agen")))
-;; Generic pipeline function unit.
+;; Length in bytes.
-(define_function_unit "integer" 1 0
- (eq_attr "type" "none") 0 0)
+(define_attr "length" ""
+ (cond [(eq_attr "op_type" "E,RR") (const_int 2)
+ (eq_attr "op_type" "RX,RI,RRE,RS,RSI,S,SI") (const_int 4)]
+ (const_int 6)))
-(define_function_unit "integer" 1 0
- (eq_attr "type" "integer") 1 1)
-(define_function_unit "integer" 1 0
- (eq_attr "type" "fsimpd") 1 1)
+;; 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_function_unit "integer" 1 0
- (eq_attr "type" "fsimps") 1 1)
+(define_attr "cpu" "g5,g6,z900,z990,z9_109"
+ (const (symbol_ref "s390_tune")))
-(define_function_unit "integer" 1 0
- (eq_attr "type" "load") 1 1)
+;; Pipeline description for z900. For lack of anything better,
+;; this description is also used for the g5 and g6.
+(include "2064.md")
-(define_function_unit "integer" 1 0
- (eq_attr "type" "floadd") 1 1)
+;; Pipeline description for z990.
+(include "2084.md")
-(define_function_unit "integer" 1 0
- (eq_attr "type" "floads") 1 1)
+;; Predicates
+(include "predicates.md")
-(define_function_unit "integer" 1 0
- (eq_attr "type" "la") 1 1)
+;; Constraint definitions
+(include "constraints.md")
-(define_function_unit "integer" 1 0
- (eq_attr "type" "larl") 1 1)
+;; Other includes
+(include "tpf.md")
-(define_function_unit "integer" 1 0
- (eq_attr "type" "lr") 1 1)
+;; Macros
-(define_function_unit "integer" 1 0
- (eq_attr "type" "branch") 1 1)
+;; This mode macro allows floating point patterns to be generated from the
+;; same template.
+(define_mode_macro FPR [TF DF SF])
+(define_mode_macro DSF [DF SF])
-(define_function_unit "integer" 1 0
- (eq_attr "type" "store") 1 1)
+;; These mode macros allow 31-bit and 64-bit TDSI patterns to be generated
+;; from the same template.
+(define_mode_macro TDSI [(TI "TARGET_64BIT") DI SI])
-(define_function_unit "integer" 1 0
- (eq_attr "type" "fstored") 1 1)
+;; These mode macros allow 31-bit and 64-bit GPR patterns to be generated
+;; from the same template.
+(define_mode_macro GPR [(DI "TARGET_64BIT") SI])
+(define_mode_macro DSI [DI SI])
-(define_function_unit "integer" 1 0
- (eq_attr "type" "fstores") 1 1)
+;; This mode macro allows :P to be used for patterns that operate on
+;; pointer-sized quantities. Exactly one of the two alternatives will match.
+(define_mode_macro DP [(TI "TARGET_64BIT") (DI "!TARGET_64BIT")])
+(define_mode_macro P [(DI "TARGET_64BIT") (SI "!TARGET_64BIT")])
-(define_function_unit "integer" 1 0
- (eq_attr "type" "lm") 2 2)
+;; This mode macro allows the QI and HI patterns to be defined from
+;; the same template.
+(define_mode_macro HQI [HI QI])
-(define_function_unit "integer" 1 0
- (eq_attr "type" "stm") 2 2)
+;; This mode macro allows the integer patterns to be defined from the
+;; same template.
+(define_mode_macro INT [(DI "TARGET_64BIT") SI HI QI])
-(define_function_unit "integer" 1 0
- (eq_attr "type" "cs") 5 5)
+;; This macro allows to unify all 'bCOND' expander patterns.
+(define_code_macro COMPARE [eq ne gt gtu lt ltu ge geu le leu unordered
+ ordered uneq unlt ungt unle unge ltgt])
-(define_function_unit "integer" 1 0
- (eq_attr "type" "vs") 30 30)
+;; This macro allows to unify all 'sCOND' patterns.
+(define_code_macro SCOND [ltu gtu leu geu])
-(define_function_unit "integer" 1 0
- (eq_attr "type" "jsr") 5 5)
+;; This macro allows some 'ashift' and 'lshiftrt' pattern to be defined from
+;; the same template.
+(define_code_macro SHIFT [ashift lshiftrt])
-(define_function_unit "integer" 1 0
- (eq_attr "type" "imul") 7 7)
+;; These macros allow to combine most atomic operations.
+(define_code_macro ATOMIC [and ior xor plus minus mult])
+(define_code_attr atomic [(and "and") (ior "ior") (xor "xor")
+ (plus "add") (minus "sub") (mult "nand")])
-(define_function_unit "integer" 1 0
- (eq_attr "type" "fmuld") 6 6)
-(define_function_unit "integer" 1 0
- (eq_attr "type" "fmuls") 6 6)
+;; In FPR templates, a string like "lt<de>br" will expand to "ltxbr" in TFmode,
+;; "ltdbr" in DFmode, and "ltebr" in SFmode.
+(define_mode_attr xde [(TF "x") (DF "d") (SF "e")])
-(define_function_unit "integer" 1 0
- (eq_attr "type" "idiv") 33 33)
+;; In FPR templates, a string like "m<dee>br" will expand to "mxbr" in TFmode,
+;; "mdbr" in DFmode, and "meebr" in SFmode.
+(define_mode_attr xdee [(TF "x") (DF "d") (SF "ee")])
-(define_function_unit "integer" 1 0
- (eq_attr "type" "fdivd") 33 33)
+;; In FPR 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")])
-(define_function_unit "integer" 1 0
- (eq_attr "type" "fdivs") 33 33)
+;; In FPR 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")])
-(define_function_unit "integer" 1 0
- (eq_attr "type" "fsqrtd") 30 30)
+;; 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")])
-(define_function_unit "integer" 1 0
- (eq_attr "type" "fsqrts") 30 30)
+;; 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")])
-(define_function_unit "integer" 1 0
- (eq_attr "type" "ftoi") 2 2)
+;; 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")])
-(define_function_unit "integer" 1 0
- (eq_attr "type" "itof") 2 2)
+;; 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 "")])
-(define_function_unit "integer" 1 0
- (eq_attr "type" "o2") 2 2)
+;; 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 "")])
-(define_function_unit "integer" 1 0
- (eq_attr "type" "o3") 3 3)
+;; 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 "")])
-(define_function_unit "integer" 1 0
- (eq_attr "type" "other") 5 5)
+;; 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 "")])
-;; Pipeline description for z900
+;; 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")])
-(include "2064.md")
-(include "2084.md")
+;; In DP templates, a string like "cds<g>" will expand to "cdsg" in TImode
+;; and "cds" in DImode.
+(define_mode_attr tg [(TI "g") (DI "")])
-;; Length in bytes.
+;; 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")])
-(define_attr "length" ""
-(cond [ (eq_attr "op_type" "E") (const_int 2)
- (eq_attr "op_type" "RR") (const_int 2)
- (eq_attr "op_type" "RX") (const_int 4)
- (eq_attr "op_type" "RI") (const_int 4)
- (eq_attr "op_type" "RRE") (const_int 4)
- (eq_attr "op_type" "RS") (const_int 4)
- (eq_attr "op_type" "RSI") (const_int 4)
- (eq_attr "op_type" "S") (const_int 4)
- (eq_attr "op_type" "SI") (const_int 4)
- (eq_attr "op_type" "SS") (const_int 6)
- (eq_attr "op_type" "SSE") (const_int 6)
- (eq_attr "op_type" "RXE") (const_int 6)
- (eq_attr "op_type" "RSE") (const_int 6)
- (eq_attr "op_type" "RIL") (const_int 6)
- (eq_attr "op_type" "RXY") (const_int 6)
- (eq_attr "op_type" "RSY") (const_int 6)
- (eq_attr "op_type" "SIY") (const_int 6)]
- (const_int 4)))
-
-;; Define attributes for `asm' insns.
-
-(define_asm_attributes [(set_attr "type" "other")
- (set_attr "op_type" "NN")])
+;; ICM mask required to load MODE value into the lowest subreg
+;; of a SImode register.
+(define_mode_attr icm_lo [(HI "3") (QI "1")])
-;;
-;; Condition Codes
-;;
-;
-; CCL: Zero Nonzero Zero Nonzero (AL, ALR, SL, SLR, N, NC, NI, NR, O, OC, OI, OR, X, XC, XI, XR)
-; CCA: Zero <Zero >Zero Overflow (A, AR, AH, AHI, S, SR, SH, SHI, LTR, LCR, LNR, LPR, SLA, SLDA, SLA, SRDA)
-; CCU: Equal ULess UGreater -- (CL, CLR, CLI, CLM)
-; CCS: Equal SLess SGreater -- (C, CR, CH, CHI, ICM)
-; CCT: Zero Mixed Mixed Ones (TM, TMH, TML)
+;; 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")])
-; CCZ -> CCL / CCZ1
-; CCZ1 -> CCA/CCU/CCS/CCT
-; CCS -> CCA
+;; In P templates, the mode <DBL> will expand to "TI" in DImode and "DI"
+;; in SImode.
+(define_mode_attr DBL [(DI "TI") (SI "DI")])
-; String: CLC, CLCL, CLCLE, CLST, CUSE, MVCL, MVCLE, MVPG, MVST, SRST
-; Clobber: CKSM, CFC, CS, CDS, CUUTF, CUTFU, PLO, SPM, STCK, STCKE, TS, TRT, TRE, UPT
+;; Maximum unsigned integer that fits in MODE.
+(define_mode_attr max_uint [(HI "65535") (QI "255")])
;;
;;- Compare instructions.
;;
-(define_expand "cmpdi"
- [(set (reg:CC 33)
- (compare:CC (match_operand:DI 0 "register_operand" "")
- (match_operand:DI 1 "general_operand" "")))]
- "TARGET_64BIT"
-{
- s390_compare_op0 = operands[0];
- s390_compare_op1 = operands[1];
- DONE;
-})
-
-(define_expand "cmpsi"
- [(set (reg:CC 33)
- (compare:CC (match_operand:SI 0 "register_operand" "")
- (match_operand:SI 1 "general_operand" "")))]
+(define_expand "cmp<mode>"
+ [(set (reg:CC CC_REGNUM)
+ (compare:CC (match_operand:GPR 0 "register_operand" "")
+ (match_operand:GPR 1 "general_operand" "")))]
""
{
s390_compare_op0 = operands[0];
@@ -352,10 +349,10 @@
DONE;
})
-(define_expand "cmpdf"
- [(set (reg:CC 33)
- (compare:CC (match_operand:DF 0 "register_operand" "")
- (match_operand:DF 1 "general_operand" "")))]
+(define_expand "cmp<mode>"
+ [(set (reg:CC CC_REGNUM)
+ (compare:CC (match_operand:FPR 0 "register_operand" "")
+ (match_operand:FPR 1 "general_operand" "")))]
"TARGET_HARD_FLOAT"
{
s390_compare_op0 = operands[0];
@@ -363,185 +360,28 @@
DONE;
})
-(define_expand "cmpsf"
- [(set (reg:CC 33)
- (compare:CC (match_operand:SF 0 "register_operand" "")
- (match_operand:SF 1 "general_operand" "")))]
- "TARGET_HARD_FLOAT"
-{
- s390_compare_op0 = operands[0];
- s390_compare_op1 = operands[1];
- DONE;
-})
-
-
-; Test-under-Mask (zero_extract) instructions
-
-(define_insn "*tmdi_ext"
- [(set (reg 33)
- (compare (zero_extract:DI (match_operand:DI 0 "register_operand" "d")
- (match_operand:DI 1 "const_int_operand" "n")
- (match_operand:DI 2 "const_int_operand" "n"))
- (const_int 0)))]
- "s390_match_ccmode(insn, CCTmode) && TARGET_64BIT
- && INTVAL (operands[1]) >= 1 && INTVAL (operands[2]) >= 0
- && INTVAL (operands[1]) + INTVAL (operands[2]) <= 64
- && (INTVAL (operands[1]) + INTVAL (operands[2]) - 1) >> 4
- == INTVAL (operands[2]) >> 4"
-{
- int part = INTVAL (operands[2]) >> 4;
- int block = (1 << INTVAL (operands[1])) - 1;
- int shift = 16 - INTVAL (operands[1]) - (INTVAL (operands[2]) & 15);
-
- operands[2] = GEN_INT (block << shift);
-
- switch (part)
- {
- case 0: return "tmhh\t%0,%x2";
- case 1: return "tmhl\t%0,%x2";
- case 2: return "tmlh\t%0,%x2";
- case 3: return "tmll\t%0,%x2";
- default: abort ();
- }
-}
- [(set_attr "op_type" "RI")])
-
-(define_insn "*tmsi_ext"
- [(set (reg 33)
- (compare (zero_extract:SI (match_operand:SI 0 "register_operand" "d")
- (match_operand:SI 1 "const_int_operand" "n")
- (match_operand:SI 2 "const_int_operand" "n"))
- (const_int 0)))]
- "s390_match_ccmode(insn, CCTmode)
- && INTVAL (operands[1]) >= 1 && INTVAL (operands[2]) >= 0
- && INTVAL (operands[1]) + INTVAL (operands[2]) <= 32
- && (INTVAL (operands[1]) + INTVAL (operands[2]) - 1) >> 4
- == INTVAL (operands[2]) >> 4"
-{
- int part = INTVAL (operands[2]) >> 4;
- int block = (1 << INTVAL (operands[1])) - 1;
- int shift = 16 - INTVAL (operands[1]) - (INTVAL (operands[2]) & 15);
-
- operands[2] = GEN_INT (block << shift);
-
- switch (part)
- {
- case 0: return "tmh\t%0,%x2";
- case 1: return "tml\t%0,%x2";
- default: abort ();
- }
-}
- [(set_attr "op_type" "RI")])
-
-(define_insn "*tmqisi_ext"
- [(set (reg 33)
- (compare (zero_extract:SI (match_operand:QI 0 "memory_operand" "Q,S")
- (match_operand:SI 1 "const_int_operand" "n,n")
- (match_operand:SI 2 "const_int_operand" "n,n"))
- (const_int 0)))]
- "!TARGET_64BIT && s390_match_ccmode(insn, CCTmode)
- && INTVAL (operands[1]) >= 1 && INTVAL (operands[2]) >= 0
- && INTVAL (operands[1]) + INTVAL (operands[2]) <= 8"
-{
- int block = (1 << INTVAL (operands[1])) - 1;
- int shift = 8 - INTVAL (operands[1]) - INTVAL (operands[2]);
-
- operands[2] = GEN_INT (block << shift);
- return which_alternative == 0 ? "tm\t%0,%b2" : "tmy\t%0,%b2";
-}
- [(set_attr "op_type" "SI,SIY")])
-
-(define_insn "*tmqidi_ext"
- [(set (reg 33)
- (compare (zero_extract:DI (match_operand:QI 0 "memory_operand" "Q,S")
- (match_operand:SI 1 "const_int_operand" "n,n")
- (match_operand:SI 2 "const_int_operand" "n,n"))
- (const_int 0)))]
- "TARGET_64BIT && s390_match_ccmode(insn, CCTmode)
- && INTVAL (operands[1]) >= 1 && INTVAL (operands[2]) >= 0
- && INTVAL (operands[1]) + INTVAL (operands[2]) <= 8"
-{
- int block = (1 << INTVAL (operands[1])) - 1;
- int shift = 8 - INTVAL (operands[1]) - INTVAL (operands[2]);
-
- operands[2] = GEN_INT (block << shift);
- return which_alternative == 0 ? "tm\t%0,%b2" : "tmy\t%0,%b2";
-}
- [(set_attr "op_type" "SI,SIY")])
-
; Test-under-Mask instructions
-(define_insn "*tmdi_mem"
- [(set (reg 33)
- (compare (and:DI (match_operand:DI 0 "memory_operand" "Q,S")
- (match_operand:DI 1 "immediate_operand" "n,n"))
- (match_operand:DI 2 "immediate_operand" "n,n")))]
- "s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 0))
- && s390_single_part (operands[1], DImode, QImode, 0) >= 0"
-{
- int part = s390_single_part (operands[1], DImode, QImode, 0);
- operands[1] = GEN_INT (s390_extract_part (operands[1], QImode, 0));
-
- operands[0] = gen_rtx_MEM (QImode,
- plus_constant (XEXP (operands[0], 0), part));
- return which_alternative == 0 ? "tm\t%0,%b1" : "tmy\t%0,%b1";
-}
- [(set_attr "op_type" "SI,SIY")])
-
-(define_insn "*tmsi_mem"
- [(set (reg 33)
- (compare (and:SI (match_operand:SI 0 "memory_operand" "Q,S")
- (match_operand:SI 1 "immediate_operand" "n,n"))
- (match_operand:SI 2 "immediate_operand" "n,n")))]
- "s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 0))
- && s390_single_part (operands[1], SImode, QImode, 0) >= 0"
-{
- int part = s390_single_part (operands[1], SImode, QImode, 0);
- operands[1] = GEN_INT (s390_extract_part (operands[1], QImode, 0));
-
- operands[0] = gen_rtx_MEM (QImode,
- plus_constant (XEXP (operands[0], 0), part));
- return which_alternative == 0 ? "tm\t%0,%b1" : "tmy\t%0,%b1";
-}
- [(set_attr "op_type" "SI")])
-
-(define_insn "*tmhi_mem"
- [(set (reg 33)
- (compare (and:SI (subreg:SI (match_operand:HI 0 "memory_operand" "Q,S") 0)
- (match_operand:SI 1 "immediate_operand" "n,n"))
- (match_operand:SI 2 "immediate_operand" "n,n")))]
- "s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 0))
- && s390_single_part (operands[1], HImode, QImode, 0) >= 0"
-{
- int part = s390_single_part (operands[1], HImode, QImode, 0);
- operands[1] = GEN_INT (s390_extract_part (operands[1], QImode, 0));
-
- operands[0] = gen_rtx_MEM (QImode,
- plus_constant (XEXP (operands[0], 0), part));
- return which_alternative == 0 ? "tm\t%0,%b1" : "tmy\t%0,%b1";
-}
- [(set_attr "op_type" "SI")])
-
(define_insn "*tmqi_mem"
- [(set (reg 33)
- (compare (and:SI (subreg:SI (match_operand:QI 0 "memory_operand" "Q,S") 0)
- (match_operand:SI 1 "immediate_operand" "n,n"))
- (match_operand:SI 2 "immediate_operand" "n,n")))]
- "s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 0))"
- "@
- tm\t%0,%b1
- tmy\t%0,%b1"
+ [(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")])
(define_insn "*tmdi_reg"
- [(set (reg 33)
+ [(set (reg CC_REGNUM)
(compare (and:DI (match_operand:DI 0 "nonimmediate_operand" "d,d,d,d")
- (match_operand:DI 1 "immediate_operand"
+ (match_operand:DI 1 "immediate_operand"
"N0HD0,N1HD0,N2HD0,N3HD0"))
(match_operand:DI 2 "immediate_operand" "n,n,n,n")))]
"TARGET_64BIT
- && s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 1))
+ && s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], true))
&& s390_single_part (operands[1], DImode, HImode, 0) >= 0"
"@
tmhh\t%0,%i1
@@ -551,38 +391,34 @@
[(set_attr "op_type" "RI")])
(define_insn "*tmsi_reg"
- [(set (reg 33)
+ [(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], 1))
+ "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")])
-(define_insn "*tmhi_full"
- [(set (reg 33)
- (compare (match_operand:HI 0 "register_operand" "d")
- (match_operand:HI 1 "immediate_operand" "n")))]
- "s390_match_ccmode (insn, s390_tm_ccmode (GEN_INT (-1), operands[1], 1))"
- "tml\t%0,65535"
- [(set_attr "op_type" "RX")])
-
-(define_insn "*tmqi_full"
- [(set (reg 33)
- (compare (match_operand:QI 0 "register_operand" "d")
- (match_operand:QI 1 "immediate_operand" "n")))]
- "s390_match_ccmode (insn, s390_tm_ccmode (GEN_INT (-1), operands[1], 1))"
- "tml\t%0,255"
+(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")])
+;
; Load-and-Test instructions
+;
+
+; tst(di|si) instruction pattern(s).
(define_insn "*tstdi_sign"
- [(set (reg 33)
+ [(set (reg CC_REGNUM)
(compare (ashiftrt:DI (ashift:DI (subreg:DI (match_operand:SI 0 "register_operand" "d") 0)
(const_int 32)) (const_int 32))
(match_operand:DI 1 "const0_operand" "")))
@@ -592,167 +428,180 @@
"ltgfr\t%2,%0"
[(set_attr "op_type" "RRE")])
+; ltr, lt, ltgr, ltg
+(define_insn "*tst<mode>_extimm"
+ [(set (reg CC_REGNUM)
+ (compare (match_operand:GPR 0 "nonimmediate_operand" "d,m")
+ (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")])
+
+; ltr, lt, ltgr, ltg
+(define_insn "*tst<mode>_cconly_extimm"
+ [(set (reg CC_REGNUM)
+ (compare (match_operand:GPR 0 "nonimmediate_operand" "d,m")
+ (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")])
+
(define_insn "*tstdi"
- [(set (reg 33)
+ [(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_64BIT"
+ "s390_match_ccmode(insn, CCSmode) && TARGET_64BIT && !TARGET_EXTIMM"
"ltgr\t%2,%0"
[(set_attr "op_type" "RRE")])
-(define_insn "*tstdi_cconly"
- [(set (reg 33)
- (compare (match_operand:DI 0 "register_operand" "d")
- (match_operand:DI 1 "const0_operand" "")))]
- "s390_match_ccmode(insn, CCSmode) && TARGET_64BIT"
- "ltgr\t%0,%0"
- [(set_attr "op_type" "RRE")])
-
-(define_insn "*tstdi_cconly_31"
- [(set (reg 33)
- (compare (match_operand:DI 0 "register_operand" "d")
- (match_operand:DI 1 "const0_operand" "")))]
- "s390_match_ccmode(insn, CCSmode) && !TARGET_64BIT"
- "srda\t%0,0"
- [(set_attr "op_type" "RS")
- (set_attr "atype" "reg")])
-
-
(define_insn "*tstsi"
- [(set (reg 33)
+ [(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)"
+ "s390_match_ccmode(insn, CCSmode) && !TARGET_EXTIMM"
"@
ltr\t%2,%0
- icm\t%2,15,%0
- icmy\t%2,15,%0"
+ icm\t%2,15,%S0
+ icmy\t%2,15,%S0"
[(set_attr "op_type" "RR,RS,RSY")])
(define_insn "*tstsi_cconly"
- [(set (reg 33)
+ [(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,%0
- icmy\t%2,15,%0"
+ icm\t%2,15,%S0
+ icmy\t%2,15,%S0"
[(set_attr "op_type" "RR,RS,RSY")])
-(define_insn "*tstsi_cconly2"
- [(set (reg 33)
- (compare (match_operand:SI 0 "register_operand" "d")
- (match_operand:SI 1 "const0_operand" "")))]
+(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_64BIT"
+ "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)"
- "ltr\t%0,%0"
- [(set_attr "op_type" "RR")])
+ "lt<g>r\t%0,%0"
+ [(set_attr "op_type" "RR<E>")])
-(define_insn "*tsthiCCT"
- [(set (reg 33)
- (compare (match_operand:HI 0 "nonimmediate_operand" "?Q,?S,d")
- (match_operand:HI 1 "const0_operand" "")))
- (set (match_operand:HI 2 "register_operand" "=d,d,0")
+; 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,3,%0
- icmy\t%2,3,%0
- tml\t%0,65535"
+ icm\t%2,<icm_lo>,%S0
+ icmy\t%2,<icm_lo>,%S0
+ tml\t%0,<max_uint>"
[(set_attr "op_type" "RS,RSY,RI")])
(define_insn "*tsthiCCT_cconly"
- [(set (reg 33)
+ [(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,%0
- icmy\t%2,3,%0
+ icm\t%2,3,%S0
+ icmy\t%2,3,%S0
tml\t%0,65535"
[(set_attr "op_type" "RS,RSY,RI")])
-(define_insn "*tsthi"
- [(set (reg 33)
- (compare (match_operand:HI 0 "s_operand" "Q,S")
- (match_operand:HI 1 "const0_operand" "")))
- (set (match_operand:HI 2 "register_operand" "=d,d")
- (match_dup 0))]
- "s390_match_ccmode(insn, CCSmode)"
- "@
- icm\t%2,3,%0
- icmy\t%2,3,%0"
- [(set_attr "op_type" "RS,RSY")])
-
-(define_insn "*tsthi_cconly"
- [(set (reg 33)
- (compare (match_operand:HI 0 "s_operand" "Q,S")
- (match_operand:HI 1 "const0_operand" "")))
- (clobber (match_scratch:HI 2 "=d,d"))]
- "s390_match_ccmode(insn, CCSmode)"
- "@
- icm\t%2,3,%0
- icmy\t%2,3,%0"
- [(set_attr "op_type" "RS,RSY")])
-
-(define_insn "*tstqiCCT"
- [(set (reg 33)
- (compare (match_operand:QI 0 "nonimmediate_operand" "?Q,?S,d")
- (match_operand:QI 1 "const0_operand" "")))
- (set (match_operand:QI 2 "register_operand" "=d,d,0")
- (match_dup 0))]
- "s390_match_ccmode(insn, CCTmode)"
- "@
- icm\t%2,1,%0
- icmy\t%2,1,%0
- tml\t%0,255"
- [(set_attr "op_type" "RS,RSY,RI")])
-
(define_insn "*tstqiCCT_cconly"
- [(set (reg 33)
+ [(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%0,0
- cliy\t%0,0
+ cli\t%S0,0
+ cliy\t%S0,0
tml\t%0,255"
[(set_attr "op_type" "SI,SIY,RI")])
-(define_insn "*tstqi"
- [(set (reg 33)
- (compare (match_operand:QI 0 "s_operand" "Q,S")
- (match_operand:QI 1 "const0_operand" "")))
- (set (match_operand:QI 2 "register_operand" "=d,d")
+(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,1,%0
- icmy\t%2,1,%0"
+ icm\t%2,<icm_lo>,%S0
+ icmy\t%2,<icm_lo>,%S0"
[(set_attr "op_type" "RS,RSY")])
-(define_insn "*tstqi_cconly"
- [(set (reg 33)
- (compare (match_operand:QI 0 "s_operand" "Q,S")
- (match_operand:QI 1 "const0_operand" "")))
- (clobber (match_scratch:QI 2 "=d,d"))]
+(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,1,%0
- icmy\t%2,1,%0"
+ icm\t%2,<icm_lo>,%S0
+ icmy\t%2,<icm_lo>,%S0"
[(set_attr "op_type" "RS,RSY")])
+; 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,m,BQ")))]
+ "s390_match_ccmode (insn, CCTmode) && TARGET_64BIT"
+ "@
+ 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")])
+
+(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")])
+
+
; Compare (signed) instructions
(define_insn "*cmpdi_ccs_sign"
- [(set (reg 33)
+ [(set (reg CC_REGNUM)
(compare (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,m"))
(match_operand:DI 0 "register_operand" "d,d")))]
"s390_match_ccmode(insn, CCSRmode) && TARGET_64BIT"
@@ -761,19 +610,8 @@
cgf\t%0,%1"
[(set_attr "op_type" "RRE,RXY")])
-(define_insn "*cmpdi_ccs"
- [(set (reg 33)
- (compare (match_operand:DI 0 "register_operand" "d,d,d")
- (match_operand:DI 1 "general_operand" "d,K,m")))]
- "s390_match_ccmode(insn, CCSmode) && TARGET_64BIT"
- "@
- cgr\t%0,%1
- cghi\t%0,%c1
- cg\t%0,%1"
- [(set_attr "op_type" "RRE,RI,RXY")])
-
(define_insn "*cmpsi_ccs_sign"
- [(set (reg 33)
+ [(set (reg CC_REGNUM)
(compare (sign_extend:SI (match_operand:HI 1 "memory_operand" "R,T"))
(match_operand:SI 0 "register_operand" "d,d")))]
"s390_match_ccmode(insn, CCSRmode)"
@@ -782,199 +620,168 @@
chy\t%0,%1"
[(set_attr "op_type" "RX,RXY")])
-(define_insn "*cmpsi_ccs"
- [(set (reg 33)
- (compare (match_operand:SI 0 "register_operand" "d,d,d,d")
- (match_operand:SI 1 "general_operand" "d,K,R,T")))]
+; cr, chi, cfi, c, cy, cgr, cghi, cgfi, cg
+(define_insn "*cmp<mode>_ccs"
+ [(set (reg CC_REGNUM)
+ (compare (match_operand:GPR 0 "register_operand" "d,d,d,d,d")
+ (match_operand:GPR 1 "general_operand" "d,K,Os,R,T")))]
"s390_match_ccmode(insn, CCSmode)"
"@
- cr\t%0,%1
- chi\t%0,%c1
- c\t%0,%1
- cy\t%0,%1"
- [(set_attr "op_type" "RR,RI,RX,RXY")])
+ c<g>r\t%0,%1
+ c<g>hi\t%0,%h1
+ c<g>fi\t%0,%1
+ c<g>\t%0,%1
+ c<y>\t%0,%1"
+ [(set_attr "op_type" "RR<E>,RI,RIL,RX<Y>,RXY")])
; Compare (unsigned) instructions
(define_insn "*cmpdi_ccu_zero"
- [(set (reg 33)
+ [(set (reg CC_REGNUM)
(compare (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,m"))
(match_operand:DI 0 "register_operand" "d,d")))]
- "s390_match_ccmode(insn, CCURmode) && TARGET_64BIT"
+ "s390_match_ccmode (insn, CCURmode) && TARGET_64BIT"
"@
clgfr\t%0,%1
clgf\t%0,%1"
[(set_attr "op_type" "RRE,RXY")])
(define_insn "*cmpdi_ccu"
- [(set (reg 33)
- (compare (match_operand:DI 0 "register_operand" "d,d")
- (match_operand:DI 1 "general_operand" "d,m")))]
- "s390_match_ccmode(insn, CCUmode) && TARGET_64BIT"
+ [(set (reg CC_REGNUM)
+ (compare (match_operand:DI 0 "nonimmediate_operand" "d,d,d,Q,BQ")
+ (match_operand:DI 1 "general_operand" "d,Op,m,BQ,Q")))]
+ "s390_match_ccmode (insn, CCUmode) && TARGET_64BIT"
"@
clgr\t%0,%1
- clg\t%0,%1"
- [(set_attr "op_type" "RRE,RXY")])
+ clgfi\t%0,%1
+ clg\t%0,%1
+ #
+ #"
+ [(set_attr "op_type" "RRE,RIL,RXY,SS,SS")])
(define_insn "*cmpsi_ccu"
- [(set (reg 33)
- (compare (match_operand:SI 0 "register_operand" "d,d,d")
- (match_operand:SI 1 "general_operand" "d,R,T")))]
- "s390_match_ccmode(insn, CCUmode)"
+ [(set (reg CC_REGNUM)
+ (compare (match_operand:SI 0 "nonimmediate_operand" "d,d,d,d,Q,BQ")
+ (match_operand:SI 1 "general_operand" "d,Os,R,T,BQ,Q")))]
+ "s390_match_ccmode (insn, CCUmode)"
"@
clr\t%0,%1
+ clfi\t%0,%o1
cl\t%0,%1
- cly\t%0,%1"
- [(set_attr "op_type" "RR,RX,RXY")])
+ cly\t%0,%1
+ #
+ #"
+ [(set_attr "op_type" "RR,RIL,RX,RXY,SS,SS")])
(define_insn "*cmphi_ccu"
- [(set (reg 33)
- (compare (match_operand:HI 0 "register_operand" "d,d")
- (match_operand:HI 1 "s_imm_operand" "Q,S")))]
- "s390_match_ccmode(insn, CCUmode)"
- "@
- clm\t%0,3,%1
- clmy\t%0,3,%1"
- [(set_attr "op_type" "RS,RSY")])
+ [(set (reg CC_REGNUM)
+ (compare (match_operand:HI 0 "nonimmediate_operand" "d,d,Q,BQ")
+ (match_operand:HI 1 "general_operand" "Q,S,BQ,Q")))]
+ "s390_match_ccmode (insn, CCUmode)
+ && !register_operand (operands[1], HImode)"
+ "@
+ clm\t%0,3,%S1
+ clmy\t%0,3,%S1
+ #
+ #"
+ [(set_attr "op_type" "RS,RSY,SS,SS")])
(define_insn "*cmpqi_ccu"
- [(set (reg 33)
- (compare (match_operand:QI 0 "register_operand" "d,d")
- (match_operand:QI 1 "s_imm_operand" "Q,S")))]
- "s390_match_ccmode(insn, CCUmode)"
- "@
- clm\t%0,1,%1
- clmy\t%0,1,%1"
- [(set_attr "op_type" "RS,RSY")])
+ [(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")])
-(define_insn "*cli"
- [(set (reg 33)
- (compare (match_operand:QI 0 "memory_operand" "Q,S")
- (match_operand:QI 1 "immediate_operand" "n,n")))]
- "s390_match_ccmode (insn, CCUmode)"
- "@
- cli\t%0,%b1
- cliy\t%0,%b1"
- [(set_attr "op_type" "SI,SIY")])
-(define_insn "*cmpdi_ccu_mem"
- [(set (reg 33)
- (compare (match_operand:DI 0 "s_operand" "Q")
- (match_operand:DI 1 "s_imm_operand" "Q")))]
- "s390_match_ccmode(insn, CCUmode)"
- "clc\t%O0(8,%R0),%1"
- [(set_attr "op_type" "SS")])
+; Block compare (CLC) instruction patterns.
-(define_insn "*cmpsi_ccu_mem"
- [(set (reg 33)
- (compare (match_operand:SI 0 "s_operand" "Q")
- (match_operand:SI 1 "s_imm_operand" "Q")))]
- "s390_match_ccmode(insn, CCUmode)"
- "clc\t%O0(4,%R0),%1"
- [(set_attr "op_type" "SS")])
-
-(define_insn "*cmphi_ccu_mem"
- [(set (reg 33)
- (compare (match_operand:HI 0 "s_operand" "Q")
- (match_operand:HI 1 "s_imm_operand" "Q")))]
- "s390_match_ccmode(insn, CCUmode)"
- "clc\t%O0(2,%R0),%1"
+(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_insn "*cmpqi_ccu_mem"
- [(set (reg 33)
- (compare (match_operand:QI 0 "s_operand" "Q")
- (match_operand:QI 1 "s_imm_operand" "Q")))]
- "s390_match_ccmode(insn, CCUmode)"
- "clc\t%O0(1,%R0),%1"
- [(set_attr "op_type" "SS")])
-
-
-; DF instructions
-
-(define_insn "*cmpdf_ccs_0"
- [(set (reg 33)
- (compare (match_operand:DF 0 "register_operand" "f")
- (match_operand:DF 1 "const0_operand" "")))]
- "s390_match_ccmode(insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "ltdbr\t%0,%0"
- [(set_attr "op_type" "RRE")
- (set_attr "type" "fsimpd")])
-
-(define_insn "*cmpdf_ccs_0_ibm"
- [(set (reg 33)
- (compare (match_operand:DF 0 "register_operand" "f")
- (match_operand:DF 1 "const0_operand" "")))]
- "s390_match_ccmode(insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
- "ltdr\t%0,%0"
- [(set_attr "op_type" "RR")
- (set_attr "type" "fsimpd")])
-
-(define_insn "*cmpdf_ccs"
- [(set (reg 33)
- (compare (match_operand:DF 0 "register_operand" "f,f")
- (match_operand:DF 1 "general_operand" "f,R")))]
- "s390_match_ccmode(insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "@
- cdbr\t%0,%1
- cdb\t%0,%1"
- [(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fsimpd")])
+(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);
-(define_insn "*cmpdf_ccs_ibm"
- [(set (reg 33)
- (compare (match_operand:DF 0 "register_operand" "f,f")
- (match_operand:DF 1 "general_operand" "f,R")))]
- "s390_match_ccmode(insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
- "@
- cdr\t%0,%1
- cd\t%0,%1"
- [(set_attr "op_type" "RR,RX")
- (set_attr "type" "fsimpd")])
+ operands[1] = gen_rtx_COMPARE (GET_MODE (SET_DEST (PATTERN (curr_insn))),
+ operands[0], operands[1]);
+ operands[0] = SET_DEST (PATTERN (curr_insn));
+})
-; SF instructions
+; (DF|SF) instructions
-(define_insn "*cmpsf_ccs_0"
- [(set (reg 33)
- (compare (match_operand:SF 0 "register_operand" "f")
- (match_operand:SF 1 "const0_operand" "")))]
+; ltxbr, ltdbr, ltebr
+(define_insn "*cmp<mode>_ccs_0"
+ [(set (reg CC_REGNUM)
+ (compare (match_operand:FPR 0 "register_operand" "f")
+ (match_operand:FPR 1 "const0_operand" "")))]
"s390_match_ccmode(insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "ltebr\t%0,%0"
+ "lt<xde>br\t%0,%0"
[(set_attr "op_type" "RRE")
- (set_attr "type" "fsimps")])
+ (set_attr "type" "fsimp<mode>")])
-(define_insn "*cmpsf_ccs_0_ibm"
- [(set (reg 33)
- (compare (match_operand:SF 0 "register_operand" "f")
- (match_operand:SF 1 "const0_operand" "")))]
+; ltxr, ltdr, lter
+(define_insn "*cmp<mode>_ccs_0_ibm"
+ [(set (reg CC_REGNUM)
+ (compare (match_operand:FPR 0 "register_operand" "f")
+ (match_operand:FPR 1 "const0_operand" "")))]
"s390_match_ccmode(insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
- "lter\t%0,%0"
- [(set_attr "op_type" "RR")
- (set_attr "type" "fsimps")])
-
-(define_insn "*cmpsf_ccs"
- [(set (reg 33)
- (compare (match_operand:SF 0 "register_operand" "f,f")
- (match_operand:SF 1 "general_operand" "f,R")))]
+ "lt<xde>r\t%0,%0"
+ [(set_attr "op_type" "<RRe>")
+ (set_attr "type" "fsimp<mode>")])
+
+; cxbr, cdbr, cebr, cxb, cdb, ceb
+(define_insn "*cmp<mode>_ccs"
+ [(set (reg CC_REGNUM)
+ (compare (match_operand:FPR 0 "register_operand" "f,f")
+ (match_operand:FPR 1 "general_operand" "f,<Rf>")))]
"s390_match_ccmode(insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
"@
- cebr\t%0,%1
- ceb\t%0,%1"
+ c<xde>br\t%0,%1
+ c<xde>b\t%0,%1"
[(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fsimps")])
+ (set_attr "type" "fsimp<mode>")])
-(define_insn "*cmpsf_ccs"
- [(set (reg 33)
- (compare (match_operand:SF 0 "register_operand" "f,f")
- (match_operand:SF 1 "general_operand" "f,R")))]
+; cxr, cdr, cer, cx, cd, ce
+(define_insn "*cmp<mode>_ccs_ibm"
+ [(set (reg CC_REGNUM)
+ (compare (match_operand:FPR 0 "register_operand" "f,f")
+ (match_operand:FPR 1 "general_operand" "f,<Rf>")))]
"s390_match_ccmode(insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
"@
- cer\t%0,%1
- ce\t%0,%1"
- [(set_attr "op_type" "RR,RX")
- (set_attr "type" "fsimps")])
+ c<xde>r\t%0,%1
+ c<xde>\t%0,%1"
+ [(set_attr "op_type" "<RRe>,<RXe>")
+ (set_attr "type" "fsimp<mode>")])
;;
@@ -987,16 +794,16 @@
(define_insn "movti"
[(set (match_operand:TI 0 "nonimmediate_operand" "=d,QS,d,o,Q")
- (match_operand:TI 1 "general_operand" "QS,d,dKm,d,Q"))]
+ (match_operand:TI 1 "general_operand" "QS,d,dPm,d,Q"))]
"TARGET_64BIT"
"@
- lmg\t%0,%N0,%1
- stmg\t%1,%N1,%0
+ lmg\t%0,%N0,%S1
+ stmg\t%1,%N1,%S0
#
#
- mvc\t%O0(16,%R0),%1"
- [(set_attr "op_type" "RSY,RSY,NN,NN,SS")
- (set_attr "type" "lm,stm,*,*,cs")])
+ #"
+ [(set_attr "op_type" "RSY,RSY,*,*,SS")
+ (set_attr "type" "lm,stm,*,*,*")])
(define_split
[(set (match_operand:TI 0 "nonimmediate_operand" "")
@@ -1044,9 +851,8 @@
(match_operand:DI 2 "register_operand" "=&a")])]
"TARGET_64BIT"
{
- if (GET_CODE (operands[0]) != MEM)
- abort ();
- s390_load_address (operands[2], XEXP (operands[0], 0));
+ 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;
@@ -1062,16 +868,12 @@
""
{
/* Handle symbolic constants. */
- if (TARGET_64BIT && SYMBOLIC_CONST (operands[1]))
+ 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);
-
- /* During and after reload, we need to force constants
- to the literal pool ourselves, if necessary. */
- if ((reload_in_progress || reload_completed)
- && CONSTANT_P (operands[1])
- && (!legitimate_reload_constant_p (operands[1])
- || FP_REG_P (operands[0])))
- operands[1] = force_const_mem (DImode, operands[1]);
})
(define_insn "*movdi_larl"
@@ -1083,12 +885,46 @@
[(set_attr "op_type" "RIL")
(set_attr "type" "larl")])
+(define_insn "*movdi_64extimm"
+ [(set (match_operand:DI 0 "nonimmediate_operand"
+ "=d,d,d,d,d,d,d,d,d,d,d,m,!*f,!*f,!*f,!R,!T,d,t,Q,t,?Q")
+ (match_operand:DI 1 "general_operand"
+ "K,N0HD0,N1HD0,N2HD0,N3HD0,Os,N0SD0,N1SD0,L,d,m,d,*f,R,T,*f,*f,t,d,t,Q,?Q"))]
+ "TARGET_64BIT && TARGET_EXTIMM"
+ "@
+ 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
+ lay\t%0,%a1
+ lgr\t%0,%1
+ lg\t%0,%1
+ stg\t%1,%0
+ ldr\t%0,%1
+ ld\t%0,%1
+ ldy\t%0,%1
+ std\t%1,%0
+ stdy\t%1,%0
+ #
+ #
+ stam\t%1,%N1,%S0
+ lam\t%0,%N0,%S1
+ #"
+ [(set_attr "op_type" "RI,RI,RI,RI,RI,RIL,RIL,RIL,RXY,RRE,RXY,RXY,
+ RR,RX,RXY,RX,RXY,*,*,RS,RS,SS")
+ (set_attr "type" "*,*,*,*,*,*,*,*,la,lr,load,store,
+ floaddf,floaddf,floaddf,fstoredf,fstoredf,*,*,*,*,*")])
+
(define_insn "*movdi_64"
- [(set (match_operand:DI 0 "nonimmediate_operand"
- "=d,d,d,d,d,d,d,d,m,!*f,!*f,!*f,!R,!T,?Q")
- (match_operand:DI 1 "general_operand"
- "K,N0HD0,N1HD0,N2HD0,N3HD0,L,d,m,d,*f,R,T,*f,*f,?Q"))]
- "TARGET_64BIT"
+ [(set (match_operand:DI 0 "nonimmediate_operand"
+ "=d,d,d,d,d,d,d,d,m,!*f,!*f,!*f,!R,!T,d,t,Q,t,?Q")
+ (match_operand:DI 1 "general_operand"
+ "K,N0HD0,N1HD0,N2HD0,N3HD0,L,d,m,d,*f,R,T,*f,*f,t,d,t,Q,?Q"))]
+ "TARGET_64BIT && !TARGET_EXTIMM"
"@
lghi\t%0,%h1
llihh\t%0,%i1
@@ -1104,18 +940,58 @@
ldy\t%0,%1
std\t%1,%0
stdy\t%1,%0
- mvc\t%O0(8,%R0),%1"
- [(set_attr "op_type" "RI,RI,RI,RI,RI,RXY,RRE,RXY,RXY,RR,RX,RXY,RX,RXY,SS")
- (set_attr "type" "*,*,*,*,*,la,lr,load,store,floadd,floadd,floadd,
- fstored,fstored,cs")])
+ #
+ #
+ stam\t%1,%N1,%S0
+ lam\t%0,%N0,%S1
+ #"
+ [(set_attr "op_type" "RI,RI,RI,RI,RI,RXY,RRE,RXY,RXY,
+ RR,RX,RXY,RX,RXY,*,*,RS,RS,SS")
+ (set_attr "type" "*,*,*,*,*,la,lr,load,store,
+ floaddf,floaddf,floaddf,fstoredf,fstoredf,*,*,*,*,*")])
+
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "")
+ (match_operand:DI 1 "register_operand" ""))]
+ "TARGET_64BIT && 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_64BIT && 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_64BIT && 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,Q,d,o,!*f,!*f,!*f,!R,!T,Q")
- (match_operand:DI 1 "general_operand" "Q,d,dKm,d,*f,R,T,*f,*f,Q"))]
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,Q,S,d,o,!*f,!*f,!*f,!R,!T,Q")
+ (match_operand:DI 1 "general_operand" "Q,S,d,d,dPm,d,*f,R,T,*f,*f,Q"))]
"!TARGET_64BIT"
"@
- lm\t%0,%N0,%1
- stm\t%1,%N1,%0
+ lm\t%0,%N0,%S1
+ lmy\t%0,%N0,%S1
+ stm\t%1,%N1,%S0
+ stmy\t%1,%N1,%S0
#
#
ldr\t%0,%1
@@ -1123,9 +999,9 @@
ldy\t%0,%1
std\t%1,%0
stdy\t%1,%0
- mvc\t%O0(8,%R0),%1"
- [(set_attr "op_type" "RS,RS,NN,NN,RR,RX,RXY,RX,RXY,SS")
- (set_attr "type" "lm,stm,*,*,floadd,floadd,floadd,fstored,fstored,cs")])
+ #"
+ [(set_attr "op_type" "RS,RSY,RS,RSY,*,*,RR,RX,RXY,RX,RXY,SS")
+ (set_attr "type" "lm,lm,stm,stm,*,*,floaddf,floaddf,floaddf,fstoredf,fstoredf,*")])
(define_split
[(set (match_operand:DI 0 "nonimmediate_operand" "")
@@ -1174,9 +1050,8 @@
(match_operand:SI 2 "register_operand" "=&a")])]
"!TARGET_64BIT"
{
- if (GET_CODE (operands[0]) != MEM)
- abort ();
- s390_load_address (operands[2], XEXP (operands[0], 0));
+ 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;
@@ -1208,10 +1083,9 @@
[(parallel
[(set (match_operand:DI 0 "register_operand" "")
(match_operand:QI 1 "address_operand" ""))
- (clobber (reg:CC 33))])]
+ (clobber (reg:CC CC_REGNUM))])]
"TARGET_64BIT
- && strict_memory_address_p (VOIDmode, operands[1])
- && preferred_la_operand_p (operands[1])"
+ && preferred_la_operand_p (operands[1], const0_rtx)"
[(set (match_dup 0) (match_dup 1))]
"")
@@ -1222,11 +1096,10 @@
[(set (match_dup 0)
(plus:DI (match_dup 0)
(match_operand:DI 2 "nonmemory_operand" "")))
- (clobber (reg:CC 33))])]
+ (clobber (reg:CC CC_REGNUM))])]
"TARGET_64BIT
&& !reg_overlap_mentioned_p (operands[0], operands[2])
- && strict_memory_address_p (VOIDmode, gen_rtx_PLUS (DImode, operands[1], operands[2]))
- && preferred_la_operand_p (gen_rtx_PLUS (DImode, operands[1], operands[2]))"
+ && preferred_la_operand_p (operands[1], operands[2])"
[(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2)))]
"")
@@ -1250,29 +1123,12 @@
""
{
/* Handle symbolic constants. */
- if (!TARGET_64BIT && SYMBOLIC_CONST (operands[1]))
+ 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);
-
- /* expr.c tries to load an effective address using
- force_reg. This fails because we don't have a
- generic load_address pattern. Convert the move
- to a proper arithmetic operation instead, unless
- it is guaranteed to be OK. */
- if (GET_CODE (operands[1]) == PLUS
- && !legitimate_la_operand_p (operands[1]))
- {
- operands[1] = force_operand (operands[1], operands[0]);
- if (operands[1] == operands[0])
- DONE;
- }
-
- /* During and after reload, we need to force constants
- to the literal pool ourselves, if necessary. */
- if ((reload_in_progress || reload_completed)
- && CONSTANT_P (operands[1])
- && (!legitimate_reload_constant_p (operands[1])
- || FP_REG_P (operands[0])))
- operands[1] = force_const_mem (SImode, operands[1]);
})
(define_insn "*movsi_larl"
@@ -1285,15 +1141,16 @@
(set_attr "type" "larl")])
(define_insn "*movsi_zarch"
- [(set (match_operand:SI 0 "nonimmediate_operand"
- "=d,d,d,d,d,d,d,R,T,!*f,!*f,!*f,!R,!T,?Q")
- (match_operand:SI 1 "general_operand"
- "K,N0HS0,N1HS0,L,d,R,T,d,d,*f,R,T,*f,*f,?Q"))]
+ [(set (match_operand:SI 0 "nonimmediate_operand"
+ "=d,d,d,d,d,d,d,d,R,T,!*f,!*f,!*f,!R,!T,d,t,Q,t,?Q")
+ (match_operand:SI 1 "general_operand"
+ "K,N0HS0,N1HS0,Os,L,d,R,T,d,d,*f,R,T,*f,*f,t,d,t,Q,?Q"))]
"TARGET_ZARCH"
"@
lhi\t%0,%h1
llilh\t%0,%i1
llill\t%0,%i1
+ iilf\t%0,%o1
lay\t%0,%a1
lr\t%0,%1
l\t%0,%1
@@ -1305,13 +1162,19 @@
ley\t%0,%1
ste\t%1,%0
stey\t%1,%0
- mvc\t%O0(4,%R0),%1"
- [(set_attr "op_type" "RI,RI,RI,RXY,RR,RX,RXY,RX,RXY,RR,RX,RXY,RX,RXY,SS")
- (set_attr "type" "*,*,*,la,lr,load,load,store,store,floads,floads,floads,fstores,fstores,cs")])
+ ear\t%0,%1
+ sar\t%0,%1
+ stam\t%1,%1,%S0
+ lam\t%0,%0,%S1
+ #"
+ [(set_attr "op_type" "RI,RI,RI,RIL,RXY,RR,RX,RXY,RX,RXY,
+ RR,RX,RXY,RX,RXY,RRE,RRE,RS,RS,SS")
+ (set_attr "type" "*,*,*,*,la,lr,load,load,store,store,
+ floadsf,floadsf,floadsf,fstoresf,fstoresf,*,*,*,*,*")])
(define_insn "*movsi_esa"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,R,!*f,!*f,!R,?Q")
- (match_operand:SI 1 "general_operand" "K,d,R,d,*f,R,*f,?Q"))]
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,R,!*f,!*f,!R,d,t,Q,t,?Q")
+ (match_operand:SI 1 "general_operand" "K,d,R,d,*f,R,*f,t,d,t,Q,?Q"))]
"!TARGET_ZARCH"
"@
lhi\t%0,%h1
@@ -1321,9 +1184,13 @@
ler\t%0,%1
le\t%0,%1
ste\t%1,%0
- mvc\t%O0(4,%R0),%1"
- [(set_attr "op_type" "RI,RR,RX,RX,RR,RX,RX,SS")
- (set_attr "type" "*,lr,load,store,floads,floads,fstores,cs")])
+ 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,SS")
+ (set_attr "type" "*,lr,load,store,floadsf,floadsf,fstoresf,*,*,*,*,*")])
(define_peephole2
[(set (match_operand:SI 0 "register_operand" "")
@@ -1350,10 +1217,9 @@
[(parallel
[(set (match_operand:SI 0 "register_operand" "")
(match_operand:QI 1 "address_operand" ""))
- (clobber (reg:CC 33))])]
+ (clobber (reg:CC CC_REGNUM))])]
"!TARGET_64BIT
- && strict_memory_address_p (VOIDmode, operands[1])
- && preferred_la_operand_p (operands[1])"
+ && preferred_la_operand_p (operands[1], const0_rtx)"
[(set (match_dup 0) (match_dup 1))]
"")
@@ -1364,11 +1230,10 @@
[(set (match_dup 0)
(plus:SI (match_dup 0)
(match_operand:SI 2 "nonmemory_operand" "")))
- (clobber (reg:CC 33))])]
+ (clobber (reg:CC CC_REGNUM))])]
"!TARGET_64BIT
&& !reg_overlap_mentioned_p (operands[0], operands[2])
- && strict_memory_address_p (VOIDmode, gen_rtx_PLUS (SImode, operands[1], operands[2]))
- && preferred_la_operand_p (gen_rtx_PLUS (SImode, operands[1], operands[2]))"
+ && preferred_la_operand_p (operands[1], operands[2])"
[(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))]
"")
@@ -1387,7 +1252,7 @@
[(set (match_operand:SI 0 "register_operand" "=d")
(and:SI (match_operand:QI 1 "address_operand" "p")
(const_int 2147483647)))
- (clobber (reg:CC 33))]
+ (clobber (reg:CC CC_REGNUM))]
"!TARGET_64BIT"
"#"
"&& reload_completed"
@@ -1427,12 +1292,11 @@
(match_operand:HI 1 "general_operand" ""))]
""
{
- /* Make it explicit that loading a register from memory
+ /* Make it explicit that loading a register from memory
always sign-extends (at least) to SImode. */
if (optimize && !no_new_pseudos
&& register_operand (operands[0], VOIDmode)
- && GET_CODE (operands[1]) == MEM
- && GET_CODE (XEXP (operands[1], 0)) != ADDRESSOF)
+ && GET_CODE (operands[1]) == MEM)
{
rtx tmp = gen_reg_rtx (SImode);
rtx ext = gen_rtx_SIGN_EXTEND (SImode, operands[1]);
@@ -1452,9 +1316,9 @@
lhy\t%0,%1
sth\t%1,%0
sthy\t%1,%0
- mvc\t%O0(2,%R0),%1"
+ #"
[(set_attr "op_type" "RR,RI,RX,RXY,RX,RXY,SS")
- (set_attr "type" "lr,*,*,*,store,store,cs")])
+ (set_attr "type" "lr,*,*,*,store,store,*")])
(define_peephole2
[(set (match_operand:HI 0 "register_operand" "")
@@ -1479,8 +1343,7 @@
is just as fast as a QImode load. */
if (TARGET_ZARCH && optimize && !no_new_pseudos
&& register_operand (operands[0], VOIDmode)
- && GET_CODE (operands[1]) == MEM
- && GET_CODE (XEXP (operands[1], 0)) != ADDRESSOF)
+ && GET_CODE (operands[1]) == MEM)
{
rtx tmp = gen_reg_rtx (word_mode);
rtx ext = gen_rtx_ZERO_EXTEND (word_mode, operands[1]);
@@ -1500,11 +1363,11 @@
icy\t%0,%1
stc\t%1,%0
stcy\t%1,%0
- mvi\t%0,%b1
- mviy\t%0,%b1
- mvc\t%O0(1,%R0),%1"
+ 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,cs")])
+ (set_attr "type" "lr,*,*,*,store,store,store,store,*")])
(define_peephole2
[(set (match_operand:QI 0 "nonimmediate_operand" "")
@@ -1535,12 +1398,12 @@
(define_insn "*movstricthi"
[(set (strict_low_part (match_operand:HI 0 "register_operand" "+d,d"))
- (match_operand:HI 1 "s_imm_operand" "Q,S"))
- (clobber (reg:CC 33))]
+ (match_operand:HI 1 "memory_operand" "Q,S"))
+ (clobber (reg:CC CC_REGNUM))]
""
"@
- icm\t%0,3,%1
- icmy\t%0,3,%1"
+ icm\t%0,3,%S1
+ icmy\t%0,3,%S1"
[(set_attr "op_type" "RS,RSY")])
;
@@ -1548,15 +1411,159 @@
;
(define_insn "movstrictsi"
- [(set (strict_low_part (match_operand:SI 0 "register_operand" "+d,d,d"))
- (match_operand:SI 1 "general_operand" "d,R,T"))]
+ [(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_64BIT"
"@
lr\t%0,%1
l\t%0,%1
- ly\t%0,%1"
- [(set_attr "op_type" "RR,RX,RXY")
- (set_attr "type" "lr,load,load")])
+ ly\t%0,%1
+ ear\t%0,%1"
+ [(set_attr "op_type" "RR,RX,RXY,RRE")
+ (set_attr "type" "lr,load,load,*")])
+
+;
+; movtf instruction pattern(s).
+;
+
+(define_expand "movtf"
+ [(set (match_operand:TF 0 "nonimmediate_operand" "")
+ (match_operand:TF 1 "general_operand" ""))]
+ ""
+ "")
+
+(define_insn "*movtf_64"
+ [(set (match_operand:TF 0 "nonimmediate_operand" "=f,f,f,o,d,QS,d,o,Q")
+ (match_operand:TF 1 "general_operand" "G,f,o,f,QS,d,dm,d,Q"))]
+ "TARGET_64BIT"
+ "@
+ 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,*,*,*")])
+
+(define_insn "*movtf_31"
+ [(set (match_operand:TF 0 "nonimmediate_operand" "=f,f,f,o,Q")
+ (match_operand:TF 1 "general_operand" "G,f,o,f,Q"))]
+ "!TARGET_64BIT"
+ "@
+ lzxr\t%0
+ lxr\t%0,%1
+ #
+ #
+ #"
+ [(set_attr "op_type" "RRE,RRE,*,*,*")
+ (set_attr "type" "fsimptf,fsimptf,*,*,*")])
+
+; TFmode in GPRs splitters
+
+(define_split
+ [(set (match_operand:TF 0 "nonimmediate_operand" "")
+ (match_operand:TF 1 "general_operand" ""))]
+ "TARGET_64BIT && reload_completed
+ && s390_split_ok_p (operands[0], operands[1], TFmode, 0)"
+ [(set (match_dup 2) (match_dup 4))
+ (set (match_dup 3) (match_dup 5))]
+{
+ operands[2] = operand_subword (operands[0], 0, 0, TFmode);
+ operands[3] = operand_subword (operands[0], 1, 0, TFmode);
+ operands[4] = operand_subword (operands[1], 0, 0, TFmode);
+ operands[5] = operand_subword (operands[1], 1, 0, TFmode);
+})
+
+(define_split
+ [(set (match_operand:TF 0 "nonimmediate_operand" "")
+ (match_operand:TF 1 "general_operand" ""))]
+ "TARGET_64BIT && reload_completed
+ && s390_split_ok_p (operands[0], operands[1], TFmode, 1)"
+ [(set (match_dup 2) (match_dup 4))
+ (set (match_dup 3) (match_dup 5))]
+{
+ operands[2] = operand_subword (operands[0], 1, 0, TFmode);
+ operands[3] = operand_subword (operands[0], 0, 0, TFmode);
+ operands[4] = operand_subword (operands[1], 1, 0, TFmode);
+ operands[5] = operand_subword (operands[1], 0, 0, TFmode);
+})
+
+(define_split
+ [(set (match_operand:TF 0 "register_operand" "")
+ (match_operand:TF 1 "memory_operand" ""))]
+ "TARGET_64BIT && 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, DFmode);
+ s390_load_address (addr, XEXP (operands[1], 0));
+ operands[1] = replace_equiv_address (operands[1], addr);
+})
+
+; TFmode in FPRs splitters
+
+(define_split
+ [(set (match_operand:TF 0 "register_operand" "")
+ (match_operand: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 (DFmode, operands[0], TFmode, 0);
+ operands[3] = simplify_gen_subreg (DFmode, operands[0], TFmode, 8);
+ operands[4] = adjust_address_nv (operands[1], DFmode, 0);
+ operands[5] = adjust_address_nv (operands[1], DFmode, 8);
+})
+
+(define_split
+ [(set (match_operand:TF 0 "memory_operand" "")
+ (match_operand: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], DFmode, 0);
+ operands[3] = adjust_address_nv (operands[0], DFmode, 8);
+ operands[4] = simplify_gen_subreg (DFmode, operands[1], TFmode, 0);
+ operands[5] = simplify_gen_subreg (DFmode, operands[1], TFmode, 8);
+})
+
+(define_expand "reload_outtf"
+ [(parallel [(match_operand:TF 0 "" "")
+ (match_operand:TF 1 "register_operand" "f")
+ (match_operand:SI 2 "register_operand" "=&a")])]
+ ""
+{
+ rtx addr = gen_lowpart (Pmode, operands[2]);
+
+ gcc_assert (MEM_P (operands[0]));
+ s390_load_address (addr, find_replacement (&XEXP (operands[0], 0)));
+ operands[0] = replace_equiv_address (operands[0], addr);
+ emit_move_insn (operands[0], operands[1]);
+ DONE;
+})
+
+(define_expand "reload_intf"
+ [(parallel [(match_operand:TF 0 "register_operand" "=f")
+ (match_operand:TF 1 "" "")
+ (match_operand:SI 2 "register_operand" "=&a")])]
+ ""
+{
+ rtx addr = gen_lowpart (Pmode, operands[2]);
+
+ gcc_assert (MEM_P (operands[1]));
+ s390_load_address (addr, find_replacement (&XEXP (operands[1], 0)));
+ operands[1] = replace_equiv_address (operands[1], addr);
+ emit_move_insn (operands[0], operands[1]);
+ DONE;
+})
;
; movdf instruction pattern(s).
@@ -1566,19 +1573,14 @@
[(set (match_operand:DF 0 "nonimmediate_operand" "")
(match_operand:DF 1 "general_operand" ""))]
""
-{
- /* During and after reload, we need to force constants
- to the literal pool ourselves, if necessary. */
- if ((reload_in_progress || reload_completed)
- && CONSTANT_P (operands[1]))
- operands[1] = force_const_mem (DFmode, operands[1]);
-})
+ "")
(define_insn "*movdf_64"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,R,T,d,d,m,?Q")
- (match_operand:DF 1 "general_operand" "f,R,T,f,f,d,m,d,?Q"))]
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,f,R,T,d,d,m,?Q")
+ (match_operand:DF 1 "general_operand" "G,f,R,T,f,f,d,m,d,?Q"))]
"TARGET_64BIT"
"@
+ lzdr\t%0
ldr\t%0,%1
ld\t%0,%1
ldy\t%0,%1
@@ -1587,27 +1589,31 @@
lgr\t%0,%1
lg\t%0,%1
stg\t%1,%0
- mvc\t%O0(8,%R0),%1"
- [(set_attr "op_type" "RR,RX,RXY,RX,RXY,RRE,RXY,RXY,SS")
- (set_attr "type" "floadd,floadd,floadd,fstored,fstored,lr,load,store,cs")])
+ #"
+ [(set_attr "op_type" "RRE,RR,RX,RXY,RX,RXY,RRE,RXY,RXY,SS")
+ (set_attr "type" "fsimpdf,floaddf,floaddf,floaddf,fstoredf,fstoredf,lr,load,store,*")])
(define_insn "*movdf_31"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,R,T,d,Q,d,o,Q")
- (match_operand:DF 1 "general_operand" "f,R,T,f,f,Q,d,dKm,d,Q"))]
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,f,R,T,d,d,Q,S,d,o,Q")
+ (match_operand:DF 1 "general_operand" "G,f,R,T,f,f,Q,S,d,d,dPm,d,Q"))]
"!TARGET_64BIT"
"@
+ 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,%1
- stm\t%1,%N1,%0
+ lm\t%0,%N0,%S1
+ lmy\t%0,%N0,%S1
+ stm\t%1,%N1,%S0
+ stmy\t%1,%N1,%S0
#
#
- mvc\t%O0(8,%R0),%1"
- [(set_attr "op_type" "RR,RX,RXY,RX,RXY,RS,RS,NN,NN,SS")
- (set_attr "type" "floadd,floadd,floadd,fstored,fstored,lm,stm,*,*,cs")])
+ #"
+ [(set_attr "op_type" "RRE,RR,RX,RXY,RX,RXY,RS,RSY,RS,RSY,*,*,SS")
+ (set_attr "type" "fsimpdf,floaddf,floaddf,floaddf,fstoredf,fstoredf,\
+ lm,lm,stm,stm,*,*,*")])
(define_split
[(set (match_operand:DF 0 "nonimmediate_operand" "")
@@ -1656,9 +1662,8 @@
(match_operand:SI 2 "register_operand" "=&a")])]
"!TARGET_64BIT"
{
- if (GET_CODE (operands[0]) != MEM)
- abort ();
- s390_load_address (operands[2], XEXP (operands[0], 0));
+ 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;
@@ -1668,23 +1673,12 @@
; movsf instruction pattern(s).
;
-(define_expand "movsf"
- [(set (match_operand:SF 0 "nonimmediate_operand" "")
- (match_operand:SF 1 "general_operand" ""))]
- ""
-{
- /* During and after reload, we need to force constants
- to the literal pool ourselves, if necessary. */
- if ((reload_in_progress || reload_completed)
- && CONSTANT_P (operands[1]))
- operands[1] = force_const_mem (SFmode, operands[1]);
-})
-
-(define_insn "*movsf"
- [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,R,T,d,d,d,R,T,?Q")
- (match_operand:SF 1 "general_operand" "f,R,T,f,f,d,R,T,d,d,?Q"))]
+(define_insn "movsf"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,f,R,T,d,d,d,R,T,?Q")
+ (match_operand:SF 1 "general_operand" "G,f,R,T,f,f,d,R,T,d,d,?Q"))]
""
"@
+ lzer\t%0
ler\t%0,%1
le\t%0,%1
ley\t%0,%1
@@ -1695,9 +1689,78 @@
ly\t%0,%1
st\t%1,%0
sty\t%1,%0
- mvc\t%O0(4,%R0),%1"
- [(set_attr "op_type" "RR,RX,RXY,RX,RXY,RR,RX,RXY,RX,RXY,SS")
- (set_attr "type" "floads,floads,floads,fstores,fstores,lr,load,load,store,store,cs")])
+ #"
+ [(set_attr "op_type" "RRE,RR,RX,RXY,RX,RXY,RR,RX,RXY,RX,RXY,SS")
+ (set_attr "type" "fsimpsf,floadsf,floadsf,floadsf,fstoresf,fstoresf,
+ lr,load,load,store,store,*")])
+
+;
+; 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")])
+
+;
+; 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")])
+
+(define_split
+ [(set (match_operand 0 "memory_operand" "")
+ (match_operand 1 "memory_operand" ""))]
+ "reload_completed
+ && 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);
+})
+
+(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).
@@ -1751,9 +1814,6 @@
}
else
FAIL;
-
- if (from == frame_pointer_rtx || from == arg_pointer_rtx)
- FAIL;
}
else
{
@@ -1776,7 +1836,7 @@
{
int words = XVECLEN (operands[0], 0);
operands[0] = gen_rtx_REG (DImode, REGNO (operands[1]) + words - 1);
- return "lmg\t%1,%0,%2";
+ return "lmg\t%1,%0,%S2";
}
[(set_attr "op_type" "RSY")
(set_attr "type" "lm")])
@@ -1789,7 +1849,7 @@
{
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,%2" : "lmy\t%1,%0,%2";
+ return which_alternative == 0 ? "lm\t%1,%0,%S2" : "lmy\t%1,%0,%S2";
}
[(set_attr "op_type" "RS,RSY")
(set_attr "type" "lm")])
@@ -1844,9 +1904,6 @@
}
else
FAIL;
-
- if (to == frame_pointer_rtx || to == arg_pointer_rtx)
- FAIL;
}
else
{
@@ -1870,7 +1927,7 @@
{
int words = XVECLEN (operands[0], 0);
operands[0] = gen_rtx_REG (DImode, REGNO (operands[2]) + words - 1);
- return "stmg\t%2,%0,%1";
+ return "stmg\t%2,%0,%S1";
}
[(set_attr "op_type" "RSY")
(set_attr "type" "stm")])
@@ -1884,7 +1941,7 @@
{
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,%1" : "stmy\t%2,%0,%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")])
@@ -1893,144 +1950,225 @@
;; String instructions.
;;
+(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 "strlendi"
- [(set (reg:QI 0) (match_operand:QI 2 "immediate_operand" ""))
- (parallel
+(define_expand "strlen<mode>"
+ [(set (reg:SI 0) (match_operand:SI 2 "immediate_operand" ""))
+ (parallel
[(set (match_dup 4)
- (unspec:DI [(const_int 0)
+ (unspec:P [(const_int 0)
(match_operand:BLK 1 "memory_operand" "")
- (reg:QI 0)
+ (reg:SI 0)
(match_operand 3 "immediate_operand" "")] UNSPEC_SRST))
- (clobber (scratch:DI))
- (clobber (reg:CC 33))])
+ (clobber (scratch:P))
+ (clobber (reg:CC CC_REGNUM))])
(parallel
- [(set (match_operand:DI 0 "register_operand" "")
- (minus:DI (match_dup 4) (match_dup 5)))
- (clobber (reg:CC 33))])]
- "TARGET_64BIT"
+ [(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 (DImode);
- operands[5] = gen_reg_rtx (DImode);
+ 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 "*strlendi"
- [(set (match_operand:DI 0 "register_operand" "=a")
- (unspec:DI [(match_operand:DI 2 "general_operand" "0")
- (mem:BLK (match_operand:DI 3 "register_operand" "1"))
- (reg:QI 0)
+(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:DI 1 "=a"))
- (clobber (reg:CC 33))]
- "TARGET_64BIT"
+ (clobber (match_scratch:P 1 "=a"))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
"srst\t%0,%1\;jo\t.-4"
- [(set_attr "op_type" "NN")
- (set_attr "type" "vs")
- (set_attr "length" "8")])
+ [(set_attr "length" "8")
+ (set_attr "type" "vs")])
-(define_expand "strlensi"
- [(set (reg:QI 0) (match_operand:QI 2 "immediate_operand" ""))
- (parallel
- [(set (match_dup 4)
- (unspec:SI [(const_int 0)
- (match_operand:BLK 1 "memory_operand" "")
- (reg:QI 0)
- (match_operand 3 "immediate_operand" "")] UNSPEC_SRST))
- (clobber (scratch:SI))
- (clobber (reg:CC 33))])
+;
+; cmpstrM instruction pattern(s).
+;
+
+(define_expand "cmpstrsi"
+ [(set (reg:SI 0) (const_int 0))
(parallel
- [(set (match_operand:SI 0 "register_operand" "")
- (minus:SI (match_dup 4) (match_dup 5)))
- (clobber (reg:CC 33))])]
- "!TARGET_64BIT"
+ [(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_CMPINT))
+ (clobber (reg:CC CC_REGNUM))])]
+ ""
{
- operands[4] = gen_reg_rtx (SImode);
- operands[5] = gen_reg_rtx (SImode);
- emit_move_insn (operands[5], force_operand (XEXP (operands[1], 0), NULL_RTX));
- operands[1] = replace_equiv_address (operands[1], operands[5]);
+ /* 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 "*strlensi"
- [(set (match_operand:SI 0 "register_operand" "=a")
- (unspec:SI [(match_operand:SI 2 "general_operand" "0")
- (mem:BLK (match_operand:SI 3 "register_operand" "1"))
- (reg:QI 0)
- (match_operand 4 "immediate_operand" "")] UNSPEC_SRST))
- (clobber (match_scratch:SI 1 "=a"))
- (clobber (reg:CC 33))]
- "!TARGET_64BIT"
- "srst\t%0,%1\;jo\t.-4"
- [(set_attr "op_type" "NN")
- (set_attr "type" "vs")
- (set_attr "length" "8")])
-
+(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")])
+
;
-; movstrM instruction pattern(s).
+; movstr instruction pattern.
;
-(define_expand "movstrdi"
- [(set (match_operand:BLK 0 "memory_operand" "")
- (match_operand:BLK 1 "memory_operand" ""))
- (use (match_operand:DI 2 "general_operand" ""))
- (match_operand 3 "" "")]
- "TARGET_64BIT"
- "s390_expand_movstr (operands[0], operands[1], operands[2]); DONE;")
+(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_expand "movstrsi"
+(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" "")
(match_operand:BLK 1 "memory_operand" ""))
- (use (match_operand:SI 2 "general_operand" ""))
+ (use (match_operand:GPR 2 "general_operand" ""))
(match_operand 3 "" "")]
""
- "s390_expand_movstr (operands[0], operands[1], operands[2]); DONE;")
+ "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 "movstr_short"
+(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 "*movstr_short"
- [(set (match_operand:BLK 0 "memory_operand" "=Q,Q")
- (match_operand:BLK 1 "memory_operand" "Q,Q"))
- (use (match_operand 2 "nonmemory_operand" "n,a"))
- (clobber (match_scratch 3 "=X,&a"))]
+(define_insn "*movmem_short"
+ [(set (match_operand:BLK 0 "memory_operand" "=Q,Q,Q")
+ (match_operand:BLK 1 "memory_operand" "Q,Q,Q"))
+ (use (match_operand 2 "nonmemory_operand" "n,a,a"))
+ (use (match_operand 3 "immediate_operand" "X,R,X"))
+ (clobber (match_scratch 4 "=X,X,&a"))]
"(GET_MODE (operands[2]) == Pmode || GET_MODE (operands[2]) == VOIDmode)
- && GET_MODE (operands[3]) == Pmode"
-{
- switch (which_alternative)
- {
- case 0:
- return "mvc\t%O0(%b2+1,%R0),%1";
+ && GET_MODE (operands[4]) == Pmode"
+ "#"
+ [(set_attr "type" "cs")])
- case 1:
- output_asm_insn ("bras\t%3,.+10", operands);
- output_asm_insn ("mvc\t%O0(1,%R0),%1", operands);
- return "ex\t%2,0(%3)";
+(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);")
- default:
- abort ();
- }
-}
- [(set_attr "op_type" "SS,NN")
- (set_attr "type" "cs,cs")
- (set_attr "atype" "*,agen")
- (set_attr "length" "*,14")])
+(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 (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 "movstr_long"
+(define_expand "movmem_long"
[(parallel
[(clobber (match_dup 2))
(clobber (match_dup 3))
@@ -2038,7 +2176,7 @@
(match_operand:BLK 1 "memory_operand" ""))
(use (match_operand 2 "general_operand" ""))
(use (match_dup 3))
- (clobber (reg:CC 33))])]
+ (clobber (reg:CC CC_REGNUM))])]
""
{
enum machine_mode dword_mode = word_mode == DImode ? TImode : DImode;
@@ -2063,105 +2201,114 @@
operands[3] = reg1;
})
-(define_insn "*movstr_long_64"
- [(clobber (match_operand:TI 0 "register_operand" "=d"))
- (clobber (match_operand:TI 1 "register_operand" "=d"))
- (set (mem:BLK (subreg:DI (match_operand:TI 2 "register_operand" "0") 0))
- (mem:BLK (subreg:DI (match_operand:TI 3 "register_operand" "1") 0)))
- (use (match_dup 2))
- (use (match_dup 3))
- (clobber (reg:CC 33))]
- "TARGET_64BIT"
- "mvcle\t%0,%1,0\;jo\t.-4"
- [(set_attr "op_type" "NN")
- (set_attr "type" "vs")
- (set_attr "length" "8")])
-
-(define_insn "*movstr_long_31"
- [(clobber (match_operand:DI 0 "register_operand" "=d"))
- (clobber (match_operand:DI 1 "register_operand" "=d"))
- (set (mem:BLK (subreg:SI (match_operand:DI 2 "register_operand" "0") 0))
- (mem:BLK (subreg:SI (match_operand:DI 3 "register_operand" "1") 0)))
+(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 33))]
- "!TARGET_64BIT"
+ (clobber (reg:CC CC_REGNUM))]
+ ""
"mvcle\t%0,%1,0\;jo\t.-4"
- [(set_attr "op_type" "NN")
- (set_attr "type" "vs")
- (set_attr "length" "8")])
+ [(set_attr "length" "8")
+ (set_attr "type" "vs")])
;
-; clrstrM instruction pattern(s).
+; setmemM instruction pattern(s).
;
-(define_expand "clrstrdi"
+(define_expand "setmem<mode>"
[(set (match_operand:BLK 0 "memory_operand" "")
- (const_int 0))
- (use (match_operand:DI 1 "general_operand" ""))
- (match_operand 2 "" "")]
- "TARGET_64BIT"
- "s390_expand_clrstr (operands[0], operands[1]); DONE;")
-
-(define_expand "clrstrsi"
- [(set (match_operand:BLK 0 "memory_operand" "")
- (const_int 0))
- (use (match_operand:SI 1 "general_operand" ""))
- (match_operand 2 "" "")]
+ (match_operand:QI 2 "general_operand" ""))
+ (use (match_operand:GPR 1 "general_operand" ""))
+ (match_operand 3 "" "")]
""
- "s390_expand_clrstr (operands[0], operands[1]); DONE;")
+ "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 "clrstr_short"
+(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 33))])]
+ (clobber (reg:CC CC_REGNUM))])]
""
"operands[2] = gen_rtx_SCRATCH (Pmode);")
-(define_insn "*clrstr_short"
- [(set (match_operand:BLK 0 "memory_operand" "=Q,Q")
+(define_insn "*clrmem_short"
+ [(set (match_operand:BLK 0 "memory_operand" "=Q,Q,Q")
(const_int 0))
- (use (match_operand 1 "nonmemory_operand" "n,a"))
- (clobber (match_scratch 2 "=X,&a"))
- (clobber (reg:CC 33))]
+ (use (match_operand 1 "nonmemory_operand" "n,a,a"))
+ (use (match_operand 2 "immediate_operand" "X,R,X"))
+ (clobber (match_scratch 3 "=X,X,&a"))
+ (clobber (reg:CC CC_REGNUM))]
"(GET_MODE (operands[1]) == Pmode || GET_MODE (operands[1]) == VOIDmode)
- && GET_MODE (operands[2]) == Pmode"
-{
- switch (which_alternative)
- {
- case 0:
- return "xc\t%O0(%b1+1,%R0),%0";
+ && GET_MODE (operands[3]) == Pmode"
+ "#"
+ [(set_attr "type" "cs")])
+
+(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);")
- case 1:
- output_asm_insn ("bras\t%2,.+10", operands);
- output_asm_insn ("xc\t%O0(1,%R0),%0", operands);
- return "ex\t%1,0(%2)";
+(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))])]
+ "")
- default:
- abort ();
- }
-}
- [(set_attr "op_type" "SS,NN")
- (set_attr "type" "cs,cs")
- (set_attr "atype" "*,agen")
- (set_attr "length" "*,14")])
+(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 ();")
-; Clear a block of arbitrary length.
+; Initialize a block of arbitrary length with (operands[2] % 256).
-(define_expand "clrstr_long"
+(define_expand "setmem_long"
[(parallel
[(clobber (match_dup 1))
(set (match_operand:BLK 0 "memory_operand" "")
- (const_int 0))
+ (match_operand 2 "shift_count_or_setmem_operand" ""))
(use (match_operand 1 "general_operand" ""))
- (use (match_dup 2))
- (clobber (reg:CC 33))])]
+ (use (match_dup 3))
+ (clobber (reg:CC CC_REGNUM))])]
""
{
enum machine_mode dword_mode = word_mode == DImode ? TImode : DImode;
@@ -2178,49 +2325,37 @@
operands[0] = replace_equiv_address_nv (operands[0], addr0);
operands[1] = reg0;
- operands[2] = reg1;
+ operands[3] = reg1;
})
-(define_insn "*clrstr_long_64"
- [(clobber (match_operand:TI 0 "register_operand" "=d"))
- (set (mem:BLK (subreg:DI (match_operand:TI 2 "register_operand" "0") 0))
- (const_int 0))
- (use (match_dup 2))
- (use (match_operand:TI 1 "register_operand" "d"))
- (clobber (reg:CC 33))]
- "TARGET_64BIT"
- "mvcle\t%0,%1,0\;jo\t.-4"
- [(set_attr "op_type" "NN")
- (set_attr "type" "vs")
- (set_attr "length" "8")])
-
-(define_insn "*clrstr_long_31"
- [(clobber (match_operand:DI 0 "register_operand" "=d"))
- (set (mem:BLK (subreg:SI (match_operand:DI 2 "register_operand" "0") 0))
- (const_int 0))
- (use (match_dup 2))
- (use (match_operand:DI 1 "register_operand" "d"))
- (clobber (reg:CC 33))]
- "!TARGET_64BIT"
- "mvcle\t%0,%1,0\;jo\t.-4"
- [(set_attr "op_type" "NN")
- (set_attr "type" "vs")
- (set_attr "length" "8")])
-
+(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))]
+ ""
+ "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))]
+ "(INTVAL (operands[4]) & 255) == 255"
+ "mvcle\t%0,%1,%Y2\;jo\t.-4"
+ [(set_attr "length" "8")
+ (set_attr "type" "vs")])
;
; cmpmemM instruction pattern(s).
;
-(define_expand "cmpmemdi"
- [(set (match_operand:DI 0 "register_operand" "")
- (compare:DI (match_operand:BLK 1 "memory_operand" "")
- (match_operand:BLK 2 "memory_operand" "") ) )
- (use (match_operand:DI 3 "general_operand" ""))
- (use (match_operand:DI 4 "" ""))]
- "TARGET_64BIT"
- "s390_expand_cmpmem (operands[0], operands[1],
- operands[2], operands[3]); DONE;")
-
(define_expand "cmpmemsi"
[(set (match_operand:SI 0 "register_operand" "")
(compare:SI (match_operand:BLK 1 "memory_operand" "")
@@ -2236,41 +2371,70 @@
(define_expand "cmpmem_short"
[(parallel
- [(set (reg:CCS 33)
- (compare:CCS (match_operand:BLK 0 "memory_operand" "")
+ [(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:CCS 33)
- (compare:CCS (match_operand:BLK 0 "memory_operand" "=Q,Q")
- (match_operand:BLK 1 "memory_operand" "Q,Q")))
- (use (match_operand 2 "nonmemory_operand" "n,a"))
- (clobber (match_scratch 3 "=X,&a"))]
+ [(set (reg:CCU CC_REGNUM)
+ (compare:CCU (match_operand:BLK 0 "memory_operand" "Q,Q,Q")
+ (match_operand:BLK 1 "memory_operand" "Q,Q,Q")))
+ (use (match_operand 2 "nonmemory_operand" "n,a,a"))
+ (use (match_operand 3 "immediate_operand" "X,R,X"))
+ (clobber (match_scratch 4 "=X,X,&a"))]
"(GET_MODE (operands[2]) == Pmode || GET_MODE (operands[2]) == VOIDmode)
- && GET_MODE (operands[3]) == Pmode"
-{
- switch (which_alternative)
- {
- case 0:
- return "clc\t%O0(%b2+1,%R0),%1";
+ && GET_MODE (operands[4]) == Pmode"
+ "#"
+ [(set_attr "type" "cs")])
- case 1:
- output_asm_insn ("bras\t%3,.+10", operands);
- output_asm_insn ("clc\t%O0(1,%R0),%1", operands);
- return "ex\t%2,0(%3)";
+(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);")
- default:
- abort ();
- }
-}
- [(set_attr "op_type" "SS,NN")
- (set_attr "type" "cs,cs")
- (set_attr "atype" "*,agen")
- (set_attr "length" "*,14")])
+(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 (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.
@@ -2278,8 +2442,8 @@
[(parallel
[(clobber (match_dup 2))
(clobber (match_dup 3))
- (set (reg:CCS 33)
- (compare:CCS (match_operand:BLK 0 "memory_operand" "")
+ (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))])]
@@ -2307,148 +2471,268 @@
operands[3] = reg1;
})
-(define_insn "*cmpmem_long_64"
- [(clobber (match_operand:TI 0 "register_operand" "=d"))
- (clobber (match_operand:TI 1 "register_operand" "=d"))
- (set (reg:CCS 33)
- (compare:CCS (mem:BLK (subreg:DI (match_operand:TI 2 "register_operand" "0") 0))
- (mem:BLK (subreg:DI (match_operand:TI 3 "register_operand" "1") 0))))
- (use (match_dup 2))
- (use (match_dup 3))]
- "TARGET_64BIT"
- "clcle\t%0,%1,0\;jo\t.-4"
- [(set_attr "op_type" "NN")
- (set_attr "type" "vs")
- (set_attr "length" "8")])
-
-(define_insn "*cmpmem_long_31"
- [(clobber (match_operand:DI 0 "register_operand" "=d"))
- (clobber (match_operand:DI 1 "register_operand" "=d"))
- (set (reg:CCS 33)
- (compare:CCS (mem:BLK (subreg:SI (match_operand:DI 2 "register_operand" "0") 0))
- (mem:BLK (subreg:SI (match_operand:DI 3 "register_operand" "1") 0))))
+(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"
+ ""
"clcle\t%0,%1,0\;jo\t.-4"
- [(set_attr "op_type" "NN")
- (set_attr "type" "vs")
- (set_attr "length" "8")])
+ [(set_attr "length" "8")
+ (set_attr "type" "vs")])
-; Convert condition code to integer in range (-1, 0, 1)
+; Convert CCUmode condition code to integer.
+; Result is zero if EQ, positive if LTU, negative if GTU.
-(define_insn "cmpint_si"
+(define_insn_and_split "cmpint"
[(set (match_operand:SI 0 "register_operand" "=d")
- (compare:SI (reg:CCS 33) (const_int 0)))]
+ (unspec:SI [(match_operand:CCU 1 "register_operand" "0")]
+ UNSPEC_CMPINT))
+ (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_CMPINT)
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=d")
+ (unspec:SI [(match_dup 1)] UNSPEC_CMPINT))]
+ "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)))])]
{
- output_asm_insn ("lhi\t%0,1", operands);
- output_asm_insn ("jh\t.+12", operands);
- output_asm_insn ("jl\t.+6", operands);
- output_asm_insn ("sr\t%0,%0", operands);
- return "lcr\t%0,%0";
-}
- [(set_attr "op_type" "NN")
- (set_attr "length" "16")
- (set_attr "type" "other")])
+ 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 "cmpint_di"
+(define_insn_and_split "*cmpint_sign"
[(set (match_operand:DI 0 "register_operand" "=d")
- (compare:DI (reg:CCS 33) (const_int 0)))]
+ (sign_extend:DI (unspec:SI [(match_operand:CCU 1 "register_operand" "0")]
+ UNSPEC_CMPINT)))
+ (clobber (reg:CC CC_REGNUM))]
"TARGET_64BIT"
+ "#"
+ "&& 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_CMPINT) 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_CMPINT)))]
+ "s390_match_ccmode (insn, CCSmode) && TARGET_64BIT"
+ "#"
+ "&& 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)))])]
{
- output_asm_insn ("lghi\t%0,1", operands);
- output_asm_insn ("jh\t.+16", operands);
- output_asm_insn ("jl\t.+8", operands);
- output_asm_insn ("sgr\t%0,%0", operands);
- return "lcgr\t%0,%0";
-}
- [(set_attr "op_type" "NN")
- (set_attr "length" "20")
- (set_attr "type" "other")])
+ 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 "*sethighqisi"
- [(set (match_operand:SI 0 "register_operand" "=d,d")
- (unspec:SI [(match_operand:QI 1 "s_operand" "Q,S")] UNSPEC_SETHIGH))
- (clobber (reg:CC 33))]
- ""
- "@
- icm\t%0,8,%1
- icmy\t%0,8,%1"
- [(set_attr "op_type" "RS,RSY")])
-
-(define_insn "*sethighhisi"
+(define_insn "*sethighpartsi"
[(set (match_operand:SI 0 "register_operand" "=d,d")
- (unspec:SI [(match_operand:HI 1 "s_operand" "Q,S")] UNSPEC_SETHIGH))
- (clobber (reg:CC 33))]
+ (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,12,%1
- icmy\t%0,12,%1"
+ icm\t%0,%2,%S1
+ icmy\t%0,%2,%S1"
[(set_attr "op_type" "RS,RSY")])
-(define_insn "*sethighqidi_64"
+(define_insn "*sethighpartdi_64"
[(set (match_operand:DI 0 "register_operand" "=d")
- (unspec:DI [(match_operand:QI 1 "s_operand" "QS")] UNSPEC_SETHIGH))
- (clobber (reg:CC 33))]
+ (unspec:DI [(match_operand:BLK 1 "s_operand" "QS")
+ (match_operand 2 "const_int_operand" "n")] UNSPEC_ICM))
+ (clobber (reg:CC CC_REGNUM))]
"TARGET_64BIT"
- "icmh\t%0,8,%1"
+ "icmh\t%0,%2,%S1"
[(set_attr "op_type" "RSY")])
-(define_insn "*sethighqidi_31"
+(define_insn "*sethighpartdi_31"
[(set (match_operand:DI 0 "register_operand" "=d,d")
- (unspec:DI [(match_operand:QI 1 "s_operand" "Q,S")] UNSPEC_SETHIGH))
- (clobber (reg:CC 33))]
+ (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_64BIT"
"@
- icm\t%0,8,%1
- icmy\t%0,8,%1"
+ icm\t%0,%2,%S1
+ icmy\t%0,%2,%S1"
[(set_attr "op_type" "RS,RSY")])
-(define_insn_and_split "*extractqi"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (zero_extract:SI (match_operand:QI 1 "s_operand" "Q")
- (match_operand 2 "const_int_operand" "n")
- (const_int 0)))
- (clobber (reg:CC 33))]
- "!TARGET_64BIT
- && INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 8"
+(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:SI [(match_dup 1)] UNSPEC_SETHIGH))
- (clobber (reg:CC 33))])
- (set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 2)))]
+ [(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)))]
{
- operands[2] = GEN_INT (32 - INTVAL (operands[2]));
- operands[1] = change_address (operands[1], QImode, 0);
-}
- [(set_attr "atype" "agen")])
+ 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], GEN_INT (size));
+ operands[2] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode) - bitsize);
+ operands[3] = GEN_INT (mask);
+})
-(define_insn_and_split "*extracthi"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (zero_extract:SI (match_operand:QI 1 "s_operand" "Q")
- (match_operand 2 "const_int_operand" "n")
- (const_int 0)))
- (clobber (reg:CC 33))]
- "!TARGET_64BIT
- && INTVAL (operands[2]) >= 8 && INTVAL (operands[2]) < 16"
+(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:SI [(match_dup 1)] UNSPEC_SETHIGH))
- (clobber (reg:CC 33))])
- (set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 2)))]
+ [(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))])]
{
- operands[2] = GEN_INT (32 - INTVAL (operands[2]));
- operands[1] = change_address (operands[1], HImode, 0);
+ 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], GEN_INT (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>_mem_reg"
+ [(set (zero_extract:P (match_operand:QI 0 "memory_operand" "+Q,S")
+ (match_operand 1 "const_int_operand" "n,n")
+ (const_int 0))
+ (match_operand:P 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 "atype" "agen")])
+ [(set_attr "op_type" "RS,RSY")])
+
+(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_64BIT
+ && 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")])
+
+(define_insn "*insv<mode>_reg_imm"
+ [(set (zero_extract:P (match_operand:P 0 "register_operand" "+d")
+ (const_int 16)
+ (match_operand 1 "const_int_operand" "n"))
+ (match_operand:P 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")])
+
+(define_insn "*insv<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
+ && INTVAL (operands[1]) >= 0
+ && INTVAL (operands[1]) < BITS_PER_WORD
+ && INTVAL (operands[1]) % 32 == 0"
+{
+ switch (BITS_PER_WORD - INTVAL (operands[1]))
+ {
+ case 64: return "iihf\t%0,%o2"; break;
+ case 32: return "iilf\t%0,%o2"; break;
+ default: gcc_unreachable();
+ }
+}
+ [(set_attr "op_type" "RIL")])
;
; extendsidi2 instruction pattern(s).
@@ -2458,7 +2742,6 @@
[(set (match_operand:DI 0 "register_operand" "")
(sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))]
""
- "
{
if (!TARGET_64BIT)
{
@@ -2468,8 +2751,7 @@
emit_insn (gen_ashrdi3 (operands[0], operands[0], GEN_INT (32)));
DONE;
}
-}
-")
+})
(define_insn "*extendsidi2"
[(set (match_operand:DI 0 "register_operand" "=d,d")
@@ -2481,31 +2763,45 @@
[(set_attr "op_type" "RRE,RXY")])
;
-; extendhidi2 instruction pattern(s).
+; extend(hi|qi)(si|di)2 instruction pattern(s).
;
-(define_expand "extendhidi2"
- [(set (match_operand:DI 0 "register_operand" "")
- (sign_extend:DI (match_operand:HI 1 "register_operand" "")))]
+(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 (!TARGET_64BIT)
+ if (<DSI:MODE>mode == DImode && !TARGET_64BIT)
{
rtx tmp = gen_reg_rtx (SImode);
- emit_insn (gen_extendhisi2 (tmp, operands[1]));
+ emit_insn (gen_extend<HQI:mode>si2 (tmp, operands[1]));
emit_insn (gen_extendsidi2 (operands[0], tmp));
DONE;
}
- else
+ else if (!TARGET_EXTIMM)
{
- operands[1] = gen_lowpart (DImode, operands[1]);
- emit_insn (gen_ashldi3 (operands[0], operands[1], GEN_INT (48)));
- emit_insn (gen_ashrdi3 (operands[0], operands[0], GEN_INT (48)));
+ 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")
+ (sign_extend:DI (match_operand:HI 1 "nonimmediate_operand" "d,m")))]
+ "TARGET_64BIT && TARGET_EXTIMM"
+ "@
+ lghr\t%0,%1
+ lgh\t%0,%1"
+ [(set_attr "op_type" "RRE,RXY")])
(define_insn "*extendhidi2"
[(set (match_operand:DI 0 "register_operand" "=d")
@@ -2515,123 +2811,69 @@
[(set_attr "op_type" "RXY")])
;
-; extendqidi2 instruction pattern(s).
-;
-
-(define_expand "extendqidi2"
- [(set (match_operand:DI 0 "register_operand" "")
- (sign_extend:DI (match_operand:QI 1 "register_operand" "")))]
- ""
- "
-{
- if (!TARGET_64BIT)
- {
- rtx tmp = gen_reg_rtx (SImode);
- emit_insn (gen_extendqisi2 (tmp, operands[1]));
- emit_insn (gen_extendsidi2 (operands[0], tmp));
- DONE;
- }
- else
- {
- operands[1] = gen_lowpart (DImode, operands[1]);
- emit_insn (gen_ashldi3 (operands[0], operands[1], GEN_INT (56)));
- emit_insn (gen_ashrdi3 (operands[0], operands[0], GEN_INT (56)));
- DONE;
- }
-}
-")
-
-(define_insn "*extendqidi2"
- [(set (match_operand:DI 0 "register_operand" "=d")
- (sign_extend:DI (match_operand:QI 1 "memory_operand" "m")))]
- "TARGET_64BIT && TARGET_LONG_DISPLACEMENT"
- "lgb\t%0,%1"
- [(set_attr "op_type" "RXY")])
-
-(define_insn_and_split "*extendqidi2_short_displ"
- [(set (match_operand:DI 0 "register_operand" "=d")
- (sign_extend:DI (match_operand:QI 1 "s_operand" "Q")))
- (clobber (reg:CC 33))]
- "TARGET_64BIT && !TARGET_LONG_DISPLACEMENT"
- "#"
- "&& reload_completed"
- [(parallel
- [(set (match_dup 0) (unspec:DI [(match_dup 1)] UNSPEC_SETHIGH))
- (clobber (reg:CC 33))])
- (parallel
- [(set (match_dup 0) (ashiftrt:DI (match_dup 0) (const_int 56)))
- (clobber (reg:CC 33))])]
- "")
-
-;
; extendhisi2 instruction pattern(s).
;
-(define_expand "extendhisi2"
- [(set (match_operand:SI 0 "register_operand" "")
- (sign_extend:SI (match_operand:HI 1 "register_operand" "")))]
- ""
- "
-{
- operands[1] = gen_lowpart (SImode, operands[1]);
- emit_insn (gen_ashlsi3 (operands[0], operands[1], GEN_INT (16)));
- emit_insn (gen_ashrsi3 (operands[0], operands[0], GEN_INT (16)));
- DONE;
-}
-")
+(define_insn "*extendhisi2_extimm"
+ [(set (match_operand:SI 0 "register_operand" "=d,d,d")
+ (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "d,R,T")))]
+ "TARGET_EXTIMM"
+ "@
+ lhr\t%0,%1
+ lh\t%0,%1
+ lhy\t%0,%1"
+ [(set_attr "op_type" "RRE,RX,RXY")])
(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")])
;
-; extendqisi2 instruction pattern(s).
+; extendqi(si|di)2 instruction pattern(s).
;
-(define_expand "extendqisi2"
- [(set (match_operand:SI 0 "register_operand" "")
- (sign_extend:SI (match_operand:QI 1 "register_operand" "")))]
- ""
- "
-{
- operands[1] = gen_lowpart (SImode, operands[1]);
- emit_insn (gen_ashlsi3 (operands[0], operands[1], GEN_INT (24)));
- emit_insn (gen_ashrsi3 (operands[0], operands[0], GEN_INT (24)));
- DONE;
-}
-")
+; 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,m")))]
+ "TARGET_EXTIMM"
+ "@
+ l<g>br\t%0,%1
+ l<g>b\t%0,%1"
+ [(set_attr "op_type" "RRE,RXY")])
-(define_insn "*extendqisi2"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
- "TARGET_LONG_DISPLACEMENT"
- "lb\t%0,%1"
+; lb, lgb
+(define_insn "*extendqi<mode>2"
+ [(set (match_operand:GPR 0 "register_operand" "=d")
+ (sign_extend:GPR (match_operand:QI 1 "memory_operand" "m")))]
+ "!TARGET_EXTIMM && TARGET_LONG_DISPLACEMENT"
+ "l<g>b\t%0,%1"
[(set_attr "op_type" "RXY")])
-(define_insn_and_split "*extendsiqi2_short_displ"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (sign_extend:SI (match_operand:QI 1 "s_operand" "Q")))
- (clobber (reg:CC 33))]
- "!TARGET_LONG_DISPLACEMENT"
+(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:SI [(match_dup 1)] UNSPEC_SETHIGH))
- (clobber (reg:CC 33))])
+ [(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:SI (match_dup 0) (const_int 24)))
- (clobber (reg:CC 33))])]
- "")
-
-;
-; extendqihi2 instruction pattern(s).
-;
-
+ [(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], GEN_INT (GET_MODE_SIZE (QImode)));
+ operands[2] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode)
+ - GET_MODE_BITSIZE (QImode));
+})
;
; zero_extendsidi2 instruction pattern(s).
@@ -2641,7 +2883,6 @@
[(set (match_operand:DI 0 "register_operand" "")
(zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))]
""
- "
{
if (!TARGET_64BIT)
{
@@ -2650,8 +2891,7 @@
emit_move_insn (gen_highpart (SImode, operands[0]), const0_rtx);
DONE;
}
-}
-")
+})
(define_insn "*zero_extendsidi2"
[(set (match_operand:DI 0 "register_operand" "=d,d")
@@ -2663,64 +2903,40 @@
[(set_attr "op_type" "RRE,RXY")])
;
-; zero_extendhidi2 instruction pattern(s).
+; LLGT-type instructions (zero-extend from 31 bit to 64 bit).
;
-(define_expand "zero_extendhidi2"
- [(set (match_operand:DI 0 "register_operand" "")
- (zero_extend:DI (match_operand:HI 1 "register_operand" "")))]
- ""
- "
-{
- if (!TARGET_64BIT)
- {
- rtx tmp = gen_reg_rtx (SImode);
- emit_insn (gen_zero_extendhisi2 (tmp, operands[1]));
- emit_insn (gen_zero_extendsidi2 (operands[0], tmp));
- DONE;
- }
- else
- {
- operands[1] = gen_lowpart (DImode, operands[1]);
- emit_insn (gen_ashldi3 (operands[0], operands[1], GEN_INT (48)));
- emit_insn (gen_lshrdi3 (operands[0], operands[0], GEN_INT (48)));
- DONE;
- }
-}
-")
-
-(define_insn "*zero_extendhidi2"
+(define_insn "*llgt_sidi"
[(set (match_operand:DI 0 "register_operand" "=d")
- (zero_extend:DI (match_operand:HI 1 "memory_operand" "m")))]
+ (and:DI (subreg:DI (match_operand:SI 1 "memory_operand" "m") 0)
+ (const_int 2147483647)))]
"TARGET_64BIT"
- "llgh\t%0,%1"
- [(set_attr "op_type" "RXY")])
+ "llgt\t%0,%1"
+ [(set_attr "op_type" "RXE")])
-;
-; LLGT-type instructions (zero-extend from 31 bit to 64 bit).
-;
+(define_insn_and_split "*llgt_sidi_split"
+ [(set (match_operand:DI 0 "register_operand" "=d")
+ (and:DI (subreg:DI (match_operand:SI 1 "memory_operand" "m") 0)
+ (const_int 2147483647)))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_64BIT"
+ "#"
+ "&& 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,m")
(const_int 2147483647)))]
- "TARGET_64BIT"
+ "TARGET_ZARCH"
"@
llgtr\t%0,%1
llgt\t%0,%1"
[(set_attr "op_type" "RRE,RXE")])
-(define_split
- [(set (match_operand:SI 0 "register_operand" "")
- (and:SI (match_operand:SI 1 "nonimmediate_operand" "")
- (const_int 2147483647)))
- (clobber (reg:CC 33))]
- "TARGET_64BIT && reload_completed"
- [(set (match_dup 0)
- (and:SI (match_dup 1)
- (const_int 2147483647)))]
- "")
-
(define_insn "*llgt_didi"
[(set (match_operand:DI 0 "register_operand" "=d,d")
(and:DI (match_operand:DI 1 "nonimmediate_operand" "d,o")
@@ -2732,130 +2948,87 @@
[(set_attr "op_type" "RRE,RXE")])
(define_split
- [(set (match_operand:DI 0 "register_operand" "")
- (and:DI (match_operand:DI 1 "nonimmediate_operand" "")
- (const_int 2147483647)))
- (clobber (reg:CC 33))]
- "TARGET_64BIT && reload_completed"
+ [(set (match_operand:GPR 0 "register_operand" "")
+ (and:GPR (match_operand:GPR 1 "nonimmediate_operand" "")
+ (const_int 2147483647)))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_ZARCH && reload_completed"
[(set (match_dup 0)
- (and:DI (match_dup 1)
- (const_int 2147483647)))]
- "")
-
-(define_insn "*llgt_sidi"
- [(set (match_operand:DI 0 "register_operand" "=d")
- (and:DI (subreg:DI (match_operand:SI 1 "memory_operand" "m") 0)
- (const_int 2147483647)))]
- "TARGET_64BIT"
- "llgt\t%0,%1"
- [(set_attr "op_type" "RXE")])
-
-(define_insn_and_split "*llgt_sidi_split"
- [(set (match_operand:DI 0 "register_operand" "=d")
- (and:DI (subreg:DI (match_operand:SI 1 "memory_operand" "m") 0)
- (const_int 2147483647)))
- (clobber (reg:CC 33))]
- "TARGET_64BIT"
- "#"
- "&& reload_completed"
- [(set (match_dup 0)
- (and:DI (subreg:DI (match_dup 1) 0)
- (const_int 2147483647)))]
+ (and:GPR (match_dup 1)
+ (const_int 2147483647)))]
"")
;
-; zero_extendqidi2 instruction pattern(s)
+; zero_extend(hi|qi)(si|di)2 instruction pattern(s).
;
-(define_expand "zero_extendqidi2"
+(define_expand "zero_extend<mode>di2"
[(set (match_operand:DI 0 "register_operand" "")
- (zero_extend:DI (match_operand:QI 1 "register_operand" "")))]
+ (zero_extend:DI (match_operand:HQI 1 "nonimmediate_operand" "")))]
""
- "
{
if (!TARGET_64BIT)
{
rtx tmp = gen_reg_rtx (SImode);
- emit_insn (gen_zero_extendqisi2 (tmp, operands[1]));
+ emit_insn (gen_zero_extend<mode>si2 (tmp, operands[1]));
emit_insn (gen_zero_extendsidi2 (operands[0], tmp));
DONE;
}
- else
+ 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], GEN_INT (56)));
- emit_insn (gen_lshrdi3 (operands[0], operands[0], GEN_INT (56)));
+ emit_insn (gen_ashldi3 (operands[0], operands[1], bitcount));
+ emit_insn (gen_lshrdi3 (operands[0], operands[0], bitcount));
DONE;
}
-}
-")
-
-(define_insn "*zero_extendqidi2"
- [(set (match_operand:DI 0 "register_operand" "=d")
- (zero_extend:DI (match_operand:QI 1 "memory_operand" "m")))]
- "TARGET_64BIT"
- "llgc\t%0,%1"
- [(set_attr "op_type" "RXY")])
-
-;
-; zero_extendhisi2 instruction pattern(s).
-;
+})
-(define_expand "zero_extendhisi2"
+(define_expand "zero_extend<mode>si2"
[(set (match_operand:SI 0 "register_operand" "")
- (zero_extend:SI (match_operand:HI 1 "register_operand" "")))]
+ (zero_extend:SI (match_operand:HQI 1 "nonimmediate_operand" "")))]
""
- "
{
- operands[1] = gen_lowpart (SImode, operands[1]);
- emit_insn (gen_andsi3 (operands[0], operands[1], GEN_INT (0xffff)));
- DONE;
-}
-")
+ 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;
+ }
+})
-(define_insn "*zero_extendhisi2_64"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
- "TARGET_64BIT"
- "llgh\t%0,%1"
+; 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,m")))]
+ "TARGET_EXTIMM"
+ "@
+ ll<g><hc>r\t%0,%1
+ ll<g><hc>\t%0,%1"
+ [(set_attr "op_type" "RRE,RXY")])
+
+; 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" "m")))]
+ "TARGET_ZARCH && !TARGET_EXTIMM"
+ "llg<hc>\t%0,%1"
[(set_attr "op_type" "RXY")])
(define_insn_and_split "*zero_extendhisi2_31"
[(set (match_operand:SI 0 "register_operand" "=&d")
(zero_extend:SI (match_operand:HI 1 "s_operand" "QS")))
- (clobber (reg:CC 33))]
- "!TARGET_64BIT"
+ (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 33))])]
- "operands[2] = gen_lowpart (HImode, operands[0]);"
- [(set_attr "atype" "agen")])
-
-;
-; zero_extendqisi2 instruction pattern(s).
-;
-
-(define_expand "zero_extendqisi2"
- [(set (match_operand:SI 0 "register_operand" "")
- (zero_extend:SI (match_operand:QI 1 "register_operand" "")))]
- ""
- "
-{
- operands[1] = gen_lowpart (SImode, operands[1]);
- emit_insn (gen_andsi3 (operands[0], operands[1], GEN_INT (0xff)));
- DONE;
-}
-")
-
-(define_insn "*zero_extendqisi2_64"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
- "TARGET_ZARCH"
- "llgc\t%0,%1"
- [(set_attr "op_type" "RXY")])
+ (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")
@@ -2865,8 +3038,7 @@
"&& reload_completed"
[(set (match_dup 0) (const_int 0))
(set (strict_low_part (match_dup 2)) (match_dup 1))]
- "operands[2] = gen_lowpart (QImode, operands[0]);"
- [(set_attr "atype" "agen")])
+ "operands[2] = gen_lowpart (QImode, operands[0]);")
;
; zero_extendqihi2 instruction pattern(s).
@@ -2875,19 +3047,17 @@
(define_expand "zero_extendqihi2"
[(set (match_operand:HI 0 "register_operand" "")
(zero_extend:HI (match_operand:QI 1 "register_operand" "")))]
- "TARGET_ZARCH"
- "
+ "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" "m")))]
- "TARGET_ZARCH"
+ "TARGET_ZARCH && !TARGET_EXTIMM"
"llgc\t%0,%1"
[(set_attr "op_type" "RXY")])
@@ -2899,89 +3069,80 @@
"&& reload_completed"
[(set (match_dup 0) (const_int 0))
(set (strict_low_part (match_dup 2)) (match_dup 1))]
- "operands[2] = gen_lowpart (QImode, operands[0]);"
- [(set_attr "atype" "agen")])
+ "operands[2] = gen_lowpart (QImode, operands[0]);")
;
-; fixuns_truncdfdi2 and fix_truncdfsi2 instruction pattern(s).
+; fixuns_trunc(sf|df)(si|di)2 and fix_trunc(sf|df)(si|di)2 instruction pattern(s).
;
-(define_expand "fixuns_truncdfdi2"
- [(set (match_operand:DI 0 "register_operand" "")
- (unsigned_fix:DI (match_operand:DF 1 "register_operand" "")))]
- "TARGET_64BIT && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
+(define_expand "fixuns_trunc<FPR:mode><GPR:mode>2"
+ [(set (match_operand:GPR 0 "register_operand" "")
+ (unsigned_fix:GPR (match_operand:FPR 1 "register_operand" "")))]
+ "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
{
rtx label1 = gen_label_rtx ();
rtx label2 = gen_label_rtx ();
- rtx temp = gen_reg_rtx (DFmode);
- operands[1] = force_reg (DFmode, operands[1]);
-
- emit_insn (gen_cmpdf (operands[1],
- CONST_DOUBLE_FROM_REAL_VALUE (
- REAL_VALUE_ATOF ("9223372036854775808.0", DFmode), DFmode)));
+ rtx temp = gen_reg_rtx (<FPR:MODE>mode);
+ REAL_VALUE_TYPE cmp, sub;
+
+ operands[1] = force_reg (<FPR:MODE>mode, operands[1]);
+ real_2expN (&cmp, GET_MODE_BITSIZE(<GPR:MODE>mode) - 1);
+ real_2expN (&sub, GET_MODE_BITSIZE(<GPR:MODE>mode));
+
+ emit_insn (gen_cmp<FPR:mode> (operands[1],
+ CONST_DOUBLE_FROM_REAL_VALUE (cmp, <FPR:MODE>mode)));
emit_jump_insn (gen_blt (label1));
- emit_insn (gen_subdf3 (temp, operands[1],
- CONST_DOUBLE_FROM_REAL_VALUE (
- REAL_VALUE_ATOF ("18446744073709551616.0", DFmode), DFmode)));
- emit_insn (gen_fix_truncdfdi2_ieee (operands[0], temp, GEN_INT(7)));
+ emit_insn (gen_sub<FPR:mode>3 (temp, operands[1],
+ CONST_DOUBLE_FROM_REAL_VALUE (sub, <FPR:MODE>mode)));
+ emit_insn (gen_fix_trunc<FPR:mode><GPR:mode>2_ieee (operands[0], temp,
+ GEN_INT(7)));
emit_jump (label2);
emit_label (label1);
- emit_insn (gen_fix_truncdfdi2_ieee (operands[0], operands[1], GEN_INT(5)));
+ emit_insn (gen_fix_trunc<FPR:mode><GPR:mode>2_ieee (operands[0],
+ operands[1], GEN_INT(5)));
emit_label (label2);
DONE;
})
-(define_expand "fix_truncdfdi2"
+(define_expand "fix_trunc<mode>di2"
[(set (match_operand:DI 0 "register_operand" "")
- (fix:DI (match_operand:DF 1 "nonimmediate_operand" "")))]
+ (fix:DI (match_operand:DSF 1 "nonimmediate_operand" "")))]
"TARGET_64BIT && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
{
- operands[1] = force_reg (DFmode, operands[1]);
- emit_insn (gen_fix_truncdfdi2_ieee (operands[0], operands[1], GEN_INT(5)));
+ operands[1] = force_reg (<MODE>mode, operands[1]);
+ emit_insn (gen_fix_trunc<mode>di2_ieee (operands[0], operands[1],
+ GEN_INT(5)));
DONE;
})
-(define_insn "fix_truncdfdi2_ieee"
- [(set (match_operand:DI 0 "register_operand" "=d")
- (fix:DI (match_operand:DF 1 "register_operand" "f")))
- (unspec:DI [(match_operand:DI 2 "immediate_operand" "K")] UNSPEC_ROUND)
- (clobber (reg:CC 33))]
- "TARGET_64BIT && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "cgdbr\t%0,%h2,%1"
+; cgxbr, cgdbr, cgebr, cfxbr, cfdbr, cfebr
+(define_insn "fix_trunc<FPR:mode><GPR:mode>2_ieee"
+ [(set (match_operand:GPR 0 "register_operand" "=d")
+ (fix:GPR (match_operand:FPR 1 "register_operand" "f")))
+ (unspec:GPR [(match_operand:GPR 2 "immediate_operand" "K")] UNSPEC_ROUND)
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
+ "c<GPR:gf><FPR:xde>br\t%0,%h2,%1"
[(set_attr "op_type" "RRE")
(set_attr "type" "ftoi")])
;
-; fixuns_truncdfsi2 and fix_truncdfsi2 instruction pattern(s).
+; fix_trunctf(si|di)2 instruction pattern(s).
;
-(define_expand "fixuns_truncdfsi2"
- [(set (match_operand:SI 0 "register_operand" "")
- (unsigned_fix:SI (match_operand:DF 1 "register_operand" "")))]
+(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 && TARGET_IEEE_FLOAT"
-{
- rtx label1 = gen_label_rtx ();
- rtx label2 = gen_label_rtx ();
- rtx temp = gen_reg_rtx (DFmode);
-
- operands[1] = force_reg (DFmode,operands[1]);
- emit_insn (gen_cmpdf (operands[1],
- CONST_DOUBLE_FROM_REAL_VALUE (
- REAL_VALUE_ATOF ("2147483648.0", DFmode), DFmode)));
- emit_jump_insn (gen_blt (label1));
- emit_insn (gen_subdf3 (temp, operands[1],
- CONST_DOUBLE_FROM_REAL_VALUE (
- REAL_VALUE_ATOF ("4294967296.0", DFmode), DFmode)));
- emit_insn (gen_fix_truncdfsi2_ieee (operands[0], temp, GEN_INT (7)));
- emit_jump (label2);
+ "")
- emit_label (label1);
- emit_insn (gen_fix_truncdfsi2_ieee (operands[0], operands[1], GEN_INT (5)));
- emit_label (label2);
- DONE;
-})
+;
+; fix_truncdfsi2 instruction pattern(s).
+;
(define_expand "fix_truncdfsi2"
[(set (match_operand:SI 0 "register_operand" "")
@@ -3009,23 +3170,13 @@
DONE;
})
-(define_insn "fix_truncdfsi2_ieee"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (fix:SI (match_operand:DF 1 "register_operand" "f")))
- (unspec:SI [(match_operand:SI 2 "immediate_operand" "K")] UNSPEC_ROUND)
- (clobber (reg:CC 33))]
- "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "cfdbr\t%0,%h2,%1"
- [(set_attr "op_type" "RRE")
- (set_attr "type" "other" )])
-
(define_insn "fix_truncdfsi2_ibm"
[(set (match_operand:SI 0 "register_operand" "=d")
(fix:SI (match_operand:DF 1 "nonimmediate_operand" "+f")))
(use (match_operand:DI 2 "immediate_operand" "m"))
(use (match_operand:DI 3 "immediate_operand" "m"))
(use (match_operand:BLK 4 "memory_operand" "m"))
- (clobber (reg:CC 33))]
+ (clobber (reg:CC CC_REGNUM))]
"TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
{
output_asm_insn ("sd\t%1,%2", operands);
@@ -3034,92 +3185,12 @@
output_asm_insn ("xi\t%N4,128", operands);
return "l\t%0,%N4";
}
- [(set_attr "op_type" "NN")
- (set_attr "type" "ftoi")
- (set_attr "atype" "agen")
- (set_attr "length" "20")])
-
-;
-; fixuns_truncsfdi2 and fix_truncsfdi2 instruction pattern(s).
-;
-
-(define_expand "fixuns_truncsfdi2"
- [(set (match_operand:DI 0 "register_operand" "")
- (unsigned_fix:DI (match_operand:SF 1 "register_operand" "")))]
- "TARGET_64BIT && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
-{
- rtx label1 = gen_label_rtx ();
- rtx label2 = gen_label_rtx ();
- rtx temp = gen_reg_rtx (SFmode);
-
- operands[1] = force_reg (SFmode, operands[1]);
- emit_insn (gen_cmpsf (operands[1],
- CONST_DOUBLE_FROM_REAL_VALUE (
- REAL_VALUE_ATOF ("9223372036854775808.0", SFmode), SFmode)));
- emit_jump_insn (gen_blt (label1));
-
- emit_insn (gen_subsf3 (temp, operands[1],
- CONST_DOUBLE_FROM_REAL_VALUE (
- REAL_VALUE_ATOF ("18446744073709551616.0", SFmode), SFmode)));
- emit_insn (gen_fix_truncsfdi2_ieee (operands[0], temp, GEN_INT(7)));
- emit_jump (label2);
-
- emit_label (label1);
- emit_insn (gen_fix_truncsfdi2_ieee (operands[0], operands[1], GEN_INT(5)));
- emit_label (label2);
- DONE;
-})
-
-(define_expand "fix_truncsfdi2"
- [(set (match_operand:DI 0 "register_operand" "")
- (fix:DI (match_operand:SF 1 "nonimmediate_operand" "")))]
- "TARGET_64BIT && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
-{
- operands[1] = force_reg (SFmode, operands[1]);
- emit_insn (gen_fix_truncsfdi2_ieee (operands[0], operands[1], GEN_INT(5)));
- DONE;
-})
-
-(define_insn "fix_truncsfdi2_ieee"
- [(set (match_operand:DI 0 "register_operand" "=d")
- (fix:DI (match_operand:SF 1 "register_operand" "f")))
- (unspec:DI [(match_operand:DI 2 "immediate_operand" "K")] UNSPEC_ROUND)
- (clobber (reg:CC 33))]
- "TARGET_64BIT && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "cgebr\t%0,%h2,%1"
- [(set_attr "op_type" "RRE")
- (set_attr "type" "ftoi")])
+ [(set_attr "length" "20")])
;
-; fixuns_truncsfsi2 and fix_truncsfsi2 instruction pattern(s).
+; fix_truncsfsi2 instruction pattern(s).
;
-(define_expand "fixuns_truncsfsi2"
- [(set (match_operand:SI 0 "register_operand" "")
- (unsigned_fix:SI (match_operand:SF 1 "register_operand" "")))]
- "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
-{
- rtx label1 = gen_label_rtx ();
- rtx label2 = gen_label_rtx ();
- rtx temp = gen_reg_rtx (SFmode);
-
- operands[1] = force_reg (SFmode, operands[1]);
- emit_insn (gen_cmpsf (operands[1],
- CONST_DOUBLE_FROM_REAL_VALUE (
- REAL_VALUE_ATOF ("2147483648.0", SFmode), SFmode)));
- emit_jump_insn (gen_blt (label1));
- emit_insn (gen_subsf3 (temp, operands[1],
- CONST_DOUBLE_FROM_REAL_VALUE (
- REAL_VALUE_ATOF ("4294967296.0", SFmode), SFmode)));
- emit_insn (gen_fix_truncsfsi2_ieee (operands[0], temp, GEN_INT (7)));
- emit_jump (label2);
-
- emit_label (label1);
- emit_insn (gen_fix_truncsfsi2_ieee (operands[0], operands[1], GEN_INT (5)));
- emit_label (label2);
- DONE;
-})
-
(define_expand "fix_truncsfsi2"
[(set (match_operand:SI 0 "register_operand" "")
(fix:SI (match_operand:SF 1 "nonimmediate_operand" "")))]
@@ -3141,51 +3212,42 @@
DONE;
})
-(define_insn "fix_truncsfsi2_ieee"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (fix:SI (match_operand:SF 1 "register_operand" "f")))
- (unspec:SI [(match_operand:SI 2 "immediate_operand" "K")] UNSPEC_ROUND)
- (clobber (reg:CC 33))]
- "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "cfebr\t%0,%h2,%1"
- [(set_attr "op_type" "RRE")
- (set_attr "type" "ftoi")])
-
;
-; floatdidf2 instruction pattern(s).
+; float(si|di)(tf|df|sf)2 instruction pattern(s).
;
-(define_insn "floatdidf2"
- [(set (match_operand:DF 0 "register_operand" "=f")
- (float:DF (match_operand:DI 1 "register_operand" "d")))
- (clobber (reg:CC 33))]
+; cxgbr, cdgbr, cegbr
+(define_insn "floatdi<mode>2"
+ [(set (match_operand:FPR 0 "register_operand" "=f")
+ (float:FPR (match_operand:DI 1 "register_operand" "d")))]
"TARGET_64BIT && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "cdgbr\t%0,%1"
+ "c<xde>gbr\t%0,%1"
[(set_attr "op_type" "RRE")
(set_attr "type" "itof" )])
-;
-; floatdisf2 instruction pattern(s).
-;
-
-(define_insn "floatdisf2"
- [(set (match_operand:SF 0 "register_operand" "=f")
- (float:SF (match_operand:DI 1 "register_operand" "d")))
- (clobber (reg:CC 33))]
- "TARGET_64BIT && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "cegbr\t%0,%1"
+; cxfbr, cdfbr, cefbr
+(define_insn "floatsi<mode>2_ieee"
+ [(set (match_operand:FPR 0 "register_operand" "=f")
+ (float:FPR (match_operand:SI 1 "register_operand" "d")))]
+ "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
+ "c<xde>fbr\t%0,%1"
[(set_attr "op_type" "RRE")
- (set_attr "type" "itof" )])
+ (set_attr "type" "itof" )])
+
;
-; floatsidf2 instruction pattern(s).
+; floatsi(tf|df)2 instruction pattern(s).
;
+(define_expand "floatsitf2"
+ [(set (match_operand:TF 0 "register_operand" "")
+ (float:TF (match_operand:SI 1 "register_operand" "")))]
+ "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
+ "")
+
(define_expand "floatsidf2"
- [(parallel
- [(set (match_operand:DF 0 "register_operand" "")
- (float:DF (match_operand:SI 1 "register_operand" "")))
- (clobber (reg:CC 33))])]
+ [(set (match_operand:DF 0 "register_operand" "")
+ (float:DF (match_operand:SI 1 "register_operand" "")))]
"TARGET_HARD_FLOAT"
{
if (TARGET_IBM_FLOAT)
@@ -3200,21 +3262,12 @@
}
})
-(define_insn "floatsidf2_ieee"
- [(set (match_operand:DF 0 "register_operand" "=f")
- (float:DF (match_operand:SI 1 "register_operand" "d")))
- (clobber (reg:CC 33))]
- "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "cdfbr\t%0,%1"
- [(set_attr "op_type" "RRE")
- (set_attr "type" "itof" )])
-
(define_insn "floatsidf2_ibm"
[(set (match_operand:DF 0 "register_operand" "=f")
(float:DF (match_operand:SI 1 "register_operand" "d")))
(use (match_operand:DI 2 "immediate_operand" "m"))
(use (match_operand:BLK 3 "memory_operand" "m"))
- (clobber (reg:CC 33))]
+ (clobber (reg:CC CC_REGNUM))]
"TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
{
output_asm_insn ("st\t%1,%N3", operands);
@@ -3223,20 +3276,15 @@
output_asm_insn ("ld\t%0,%3", operands);
return "sd\t%0,%2";
}
- [(set_attr "op_type" "NN")
- (set_attr "type" "other" )
- (set_attr "atype" "agen")
- (set_attr "length" "20")])
+ [(set_attr "length" "20")])
;
; floatsisf2 instruction pattern(s).
;
(define_expand "floatsisf2"
- [(parallel
- [(set (match_operand:SF 0 "register_operand" "")
- (float:SF (match_operand:SI 1 "register_operand" "")))
- (clobber (reg:CC 33))])]
+ [(set (match_operand:SF 0 "register_operand" "")
+ (float:SF (match_operand:SI 1 "register_operand" "")))]
"TARGET_HARD_FLOAT"
{
if (TARGET_IBM_FLOAT)
@@ -3249,41 +3297,93 @@
}
})
-(define_insn "floatsisf2_ieee"
- [(set (match_operand:SF 0 "register_operand" "=f")
- (float:SF (match_operand:SI 1 "register_operand" "d")))
- (clobber (reg:CC 33))]
- "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "cefbr\t%0,%1"
- [(set_attr "op_type" "RRE")
- (set_attr "type" "itof" )])
-
;
; truncdfsf2 instruction pattern(s).
;
(define_expand "truncdfsf2"
[(set (match_operand:SF 0 "register_operand" "")
- (float_truncate:SF (match_operand:DF 1 "general_operand" "")))]
+ (float_truncate:SF (match_operand:DF 1 "register_operand" "")))]
"TARGET_HARD_FLOAT"
"")
(define_insn "truncdfsf2_ieee"
[(set (match_operand:SF 0 "register_operand" "=f")
- (float_truncate:SF (match_operand:DF 1 "general_operand" "f")))]
+ (float_truncate:SF (match_operand:DF 1 "register_operand" "f")))]
"TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
"ledbr\t%0,%1"
- [(set_attr "op_type" "RRE")])
+ [(set_attr "op_type" "RRE")
+ (set_attr "type" "ftruncdf")])
(define_insn "truncdfsf2_ibm"
[(set (match_operand:SF 0 "register_operand" "=f,f")
- (float_truncate:SF (match_operand:DF 1 "general_operand" "f,R")))]
+ (float_truncate:SF (match_operand:DF 1 "nonimmediate_operand" "f,R")))]
"TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
"@
- lrer\t%0,%1
+ ler\t%0,%1
le\t%0,%1"
[(set_attr "op_type" "RR,RX")
- (set_attr "type" "floads,floads")])
+ (set_attr "type" "floadsf")])
+
+;
+; trunctfdf2 instruction pattern(s).
+;
+
+(define_expand "trunctfdf2"
+ [(parallel
+ [(set (match_operand:DF 0 "register_operand" "")
+ (float_truncate:DF (match_operand:TF 1 "register_operand" "")))
+ (clobber (match_scratch:TF 2 "=f"))])]
+ "TARGET_HARD_FLOAT"
+ "")
+
+(define_insn "*trunctfdf2_ieee"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (float_truncate:DF (match_operand:TF 1 "register_operand" "f")))
+ (clobber (match_scratch:TF 2 "=f"))]
+ "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
+ "ldxbr\t%2,%1\;ldr\t%0,%2"
+ [(set_attr "length" "6")
+ (set_attr "type" "ftrunctf")])
+
+(define_insn "*trunctfdf2_ibm"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (float_truncate:DF (match_operand:TF 1 "register_operand" "f")))
+ (clobber (match_scratch:TF 2 "=f"))]
+ "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
+ "ldxr\t%2,%1\;ldr\t%0,%2"
+ [(set_attr "length" "4")
+ (set_attr "type" "ftrunctf")])
+
+;
+; trunctfsf2 instruction pattern(s).
+;
+
+(define_expand "trunctfsf2"
+ [(parallel
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (float_truncate:SF (match_operand:TF 1 "register_operand" "f")))
+ (clobber (match_scratch:TF 2 "=f"))])]
+ "TARGET_HARD_FLOAT"
+ "")
+
+(define_insn "*trunctfsf2_ieee"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (float_truncate:SF (match_operand:TF 1 "register_operand" "f")))
+ (clobber (match_scratch:TF 2 "=f"))]
+ "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
+ "lexbr\t%2,%1\;ler\t%0,%2"
+ [(set_attr "length" "6")
+ (set_attr "type" "ftrunctf")])
+
+(define_insn "*trunctfsf2_ibm"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (float_truncate:SF (match_operand:TF 1 "register_operand" "f")))
+ (clobber (match_scratch:TF 2 "=f"))]
+ "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
+ "lexr\t%2,%1\;ler\t%0,%2"
+ [(set_attr "length" "6")
+ (set_attr "type" "ftrunctf")])
;
; extendsfdf2 instruction pattern(s).
@@ -3309,20 +3409,78 @@
ldebr\t%0,%1
ldeb\t%0,%1"
[(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "floads,floads")])
+ (set_attr "type" "fsimpsf, floadsf")])
(define_insn "extendsfdf2_ibm"
[(set (match_operand:DF 0 "register_operand" "=f,f")
(float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "f,R")))
- (clobber (reg:CC 33))]
+ (clobber (reg:CC CC_REGNUM))]
"TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
"@
sdr\t%0,%0\;ler\t%0,%1
sdr\t%0,%0\;le\t%0,%1"
- [(set_attr "op_type" "NN,NN")
- (set_attr "atype" "reg,agen")
- (set_attr "length" "4,6")
- (set_attr "type" "o2,o2")])
+ [(set_attr "length" "4,6")
+ (set_attr "type" "floadsf")])
+
+;
+; extenddftf2 instruction pattern(s).
+;
+
+(define_expand "extenddftf2"
+ [(set (match_operand:TF 0 "register_operand" "")
+ (float_extend:TF (match_operand:DF 1 "nonimmediate_operand" "")))]
+ "TARGET_HARD_FLOAT"
+ "")
+
+(define_insn "*extenddftf2_ieee"
+ [(set (match_operand:TF 0 "register_operand" "=f,f")
+ (float_extend:TF (match_operand:DF 1 "nonimmediate_operand" "f,R")))]
+ "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
+ "@
+ lxdbr\t%0,%1
+ lxdb\t%0,%1"
+ [(set_attr "op_type" "RRE,RXE")
+ (set_attr "type" "fsimptf, floadtf")])
+
+(define_insn "*extenddftf2_ibm"
+ [(set (match_operand:TF 0 "register_operand" "=f,f")
+ (float_extend:TF (match_operand:DF 1 "nonimmediate_operand" "f,R")))]
+ "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
+ "@
+ lxdr\t%0,%1
+ lxd\t%0,%1"
+ [(set_attr "op_type" "RRE,RXE")
+ (set_attr "type" "fsimptf, floadtf")])
+
+;
+; extendsftf2 instruction pattern(s).
+;
+
+(define_expand "extendsftf2"
+ [(set (match_operand:TF 0 "register_operand" "")
+ (float_extend:TF (match_operand:SF 1 "nonimmediate_operand" "")))]
+ "TARGET_HARD_FLOAT"
+ "")
+
+(define_insn "*extendsftf2_ieee"
+ [(set (match_operand:TF 0 "register_operand" "=f,f")
+ (float_extend:TF (match_operand:SF 1 "nonimmediate_operand" "f,R")))]
+ "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
+ "@
+ lxebr\t%0,%1
+ lxeb\t%0,%1"
+ [(set_attr "op_type" "RRE,RXE")
+ (set_attr "type" "fsimptf, floadtf")])
+
+(define_insn "*extendsftf2_ibm"
+ [(set (match_operand:TF 0 "register_operand" "=f,f")
+ (float_extend:TF (match_operand:SF 1 "nonimmediate_operand" "f,R")))]
+ "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
+ "@
+ lxer\t%0,%1
+ lxe\t%0,%1"
+ [(set_attr "op_type" "RRE,RXE")
+ (set_attr "type" "fsimptf, floadtf")])
;;
@@ -3337,14 +3495,51 @@
;;
;
+; 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_64BIT"
+ "#"
+ "&& 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 (match_dup 4) (match_dup 5))
+ (ltu:DI (reg:CCL1 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);")
+
+;
; adddi3 instruction pattern(s).
;
+(define_expand "adddi3"
+ [(parallel
+ [(set (match_operand:DI 0 "register_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,m"))
(match_operand:DI 1 "register_operand" "0,0")))
- (clobber (reg:CC 33))]
+ (clobber (reg:CC CC_REGNUM))]
"TARGET_64BIT"
"@
agfr\t%0,%2
@@ -3352,7 +3547,7 @@
[(set_attr "op_type" "RRE,RXY")])
(define_insn "*adddi3_zero_cc"
- [(set (reg 33)
+ [(set (reg CC_REGNUM)
(compare (plus:DI (zero_extend:DI (match_operand:SI 2 "general_operand" "d,m"))
(match_operand:DI 1 "register_operand" "0,0"))
(const_int 0)))
@@ -3365,7 +3560,7 @@
[(set_attr "op_type" "RRE,RXY")])
(define_insn "*adddi3_zero_cconly"
- [(set (reg 33)
+ [(set (reg CC_REGNUM)
(compare (plus:DI (zero_extend:DI (match_operand:SI 2 "general_operand" "d,m"))
(match_operand:DI 1 "register_operand" "0,0"))
(const_int 0)))
@@ -3380,172 +3575,60 @@
[(set (match_operand:DI 0 "register_operand" "=d,d")
(plus:DI (zero_extend:DI (match_operand:SI 2 "general_operand" "d,m"))
(match_operand:DI 1 "register_operand" "0,0")))
- (clobber (reg:CC 33))]
+ (clobber (reg:CC CC_REGNUM))]
"TARGET_64BIT"
"@
algfr\t%0,%2
algf\t%0,%2"
[(set_attr "op_type" "RRE,RXY")])
-(define_insn "*adddi3_imm_cc"
- [(set (reg 33)
- (compare (plus:DI (match_operand:DI 1 "nonimmediate_operand" "0")
- (match_operand:DI 2 "const_int_operand" "K"))
- (const_int 0)))
- (set (match_operand:DI 0 "register_operand" "=d")
- (plus:DI (match_dup 1) (match_dup 2)))]
- "TARGET_64BIT
- && s390_match_ccmode (insn, CCAmode)
- && CONST_OK_FOR_CONSTRAINT_P (INTVAL (operands[2]), 'K', \"K\")"
- "aghi\t%0,%h2"
- [(set_attr "op_type" "RI")])
-
-(define_insn "*adddi3_carry1_cc"
- [(set (reg 33)
- (compare (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
- (match_operand:DI 2 "general_operand" "d,m"))
- (match_dup 1)))
- (set (match_operand:DI 0 "register_operand" "=d,d")
- (plus:DI (match_dup 1) (match_dup 2)))]
- "s390_match_ccmode (insn, CCL1mode) && TARGET_64BIT"
- "@
- algr\t%0,%2
- alg\t%0,%2"
- [(set_attr "op_type" "RRE,RXY")])
-
-(define_insn "*adddi3_carry1_cconly"
- [(set (reg 33)
- (compare (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
- (match_operand:DI 2 "general_operand" "d,m"))
- (match_dup 1)))
- (clobber (match_scratch:DI 0 "=d,d"))]
- "s390_match_ccmode (insn, CCL1mode) && TARGET_64BIT"
- "@
- algr\t%0,%2
- alg\t%0,%2"
- [(set_attr "op_type" "RRE,RXY")])
-
-(define_insn "*adddi3_carry2_cc"
- [(set (reg 33)
- (compare (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
- (match_operand:DI 2 "general_operand" "d,m"))
- (match_dup 2)))
- (set (match_operand:DI 0 "register_operand" "=d,d")
- (plus:DI (match_dup 1) (match_dup 2)))]
- "s390_match_ccmode (insn, CCL1mode) && TARGET_64BIT"
- "@
- algr\t%0,%2
- alg\t%0,%2"
- [(set_attr "op_type" "RRE,RXY")])
-
-(define_insn "*adddi3_carry2_cconly"
- [(set (reg 33)
- (compare (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
- (match_operand:DI 2 "general_operand" "d,m"))
- (match_dup 2)))
- (clobber (match_scratch:DI 0 "=d,d"))]
- "s390_match_ccmode (insn, CCL1mode) && TARGET_64BIT"
- "@
- algr\t%0,%2
- alg\t%0,%2"
- [(set_attr "op_type" "RRE,RXY")])
-
-(define_insn "*adddi3_cc"
- [(set (reg 33)
- (compare (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
- (match_operand:DI 2 "general_operand" "d,m"))
- (const_int 0)))
- (set (match_operand:DI 0 "register_operand" "=d,d")
- (plus:DI (match_dup 1) (match_dup 2)))]
- "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT"
- "@
- algr\t%0,%2
- alg\t%0,%2"
- [(set_attr "op_type" "RRE,RXY")])
-
-(define_insn "*adddi3_cconly"
- [(set (reg 33)
- (compare (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
- (match_operand:DI 2 "general_operand" "d,m"))
- (const_int 0)))
- (clobber (match_scratch:DI 0 "=d,d"))]
- "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT"
- "@
- algr\t%0,%2
- alg\t%0,%2"
- [(set_attr "op_type" "RRE,RXY")])
-
-(define_insn "*adddi3_cconly2"
- [(set (reg 33)
- (compare (match_operand:DI 1 "nonimmediate_operand" "%0,0")
- (neg:SI (match_operand:DI 2 "general_operand" "d,m"))))
- (clobber (match_scratch:DI 0 "=d,d"))]
- "s390_match_ccmode(insn, CCLmode) && TARGET_64BIT"
- "@
- algr\t%0,%2
- alg\t%0,%2"
- [(set_attr "op_type" "RRE,RXY")])
-
-(define_insn "*adddi3_64"
- [(set (match_operand:DI 0 "register_operand" "=d,d,d")
- (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0,0")
- (match_operand:DI 2 "general_operand" "d,K,m") ) )
- (clobber (reg:CC 33))]
- "TARGET_64BIT"
- "@
- agr\t%0,%2
- aghi\t%0,%h2
- ag\t%0,%2"
- [(set_attr "op_type" "RRE,RI,RXY")])
-
(define_insn_and_split "*adddi3_31z"
[(set (match_operand:DI 0 "register_operand" "=&d")
(plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0")
(match_operand:DI 2 "general_operand" "do") ) )
- (clobber (reg:CC 33))]
+ (clobber (reg:CC CC_REGNUM))]
"!TARGET_64BIT && TARGET_CPU_ZARCH"
"#"
"&& reload_completed"
[(parallel
- [(set (reg:CCL1 33)
+ [(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 (match_dup 4) (match_dup 5))
- (ltu:SI (reg:CCL1 33) (const_int 0))))
- (clobber (reg:CC 33))])]
+ (ltu:SI (reg:CCL1 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);"
- [(set_attr "op_type" "NN")])
+ operands[8] = operand_subword (operands[2], 1, 0, DImode);")
(define_insn_and_split "*adddi3_31"
[(set (match_operand:DI 0 "register_operand" "=&d")
(plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0")
(match_operand:DI 2 "general_operand" "do") ) )
- (clobber (reg:CC 33))]
+ (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 33))])
+ (clobber (reg:CC CC_REGNUM))])
(parallel
- [(set (reg:CCL1 33)
+ [(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 33) (const_int 0))
+ (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 33))])
+ (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);
@@ -3553,278 +3636,242 @@
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 ();"
- [(set_attr "op_type" "NN")])
+ operands[9] = gen_label_rtx ();")
-(define_expand "adddi3"
+;
+; addsi3 instruction pattern(s).
+;
+
+(define_expand "addsi3"
[(parallel
- [(set (match_operand:DI 0 "register_operand" "")
- (plus:DI (match_operand:DI 1 "nonimmediate_operand" "")
- (match_operand:DI 2 "general_operand" "")))
- (clobber (reg:CC 33))])]
+ [(set (match_operand:SI 0 "register_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")])
+
;
-; addsi3 instruction pattern(s).
+; add(di|si)3 instruction pattern(s).
;
-(define_insn "*addsi3_imm_cc"
- [(set (reg 33)
- (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "0")
- (match_operand:SI 2 "const_int_operand" "K"))
- (const_int 0)))
- (set (match_operand:SI 0 "register_operand" "=d")
- (plus:SI (match_dup 1) (match_dup 2)))]
- "s390_match_ccmode (insn, CCAmode)
- && CONST_OK_FOR_CONSTRAINT_P (INTVAL (operands[2]), 'K', \"K\")"
- "ahi\t%0,%h2"
- [(set_attr "op_type" "RI")])
-
-(define_insn "*addsi3_carry1_cc"
- [(set (reg 33)
- (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0")
- (match_operand:SI 2 "general_operand" "d,R,T"))
+; ar, ahi, alfi, slfi, a, ay, agr, aghi, algfi, slgfi, ag
+(define_insn "*add<mode>3"
+ [(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d,d")
+ (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,0,0,0,0,0")
+ (match_operand:GPR 2 "general_operand" "d,K,Op,On,R,T") ) )
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "@
+ a<g>r\t%0,%2
+ a<g>hi\t%0,%h2
+ al<g>fi\t%0,%2
+ sl<g>fi\t%0,%n2
+ a<g>\t%0,%2
+ a<y>\t%0,%2"
+ [(set_attr "op_type" "RR<E>,RI,RIL,RIL,RX<Y>,RXY")])
+
+; alr, alfi, slfi, al, aly, algr, algfi, slgfi, alg
+(define_insn "*add<mode>3_carry1_cc"
+ [(set (reg CC_REGNUM)
+ (compare (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,0,0,0,0")
+ (match_operand:GPR 2 "general_operand" "d,Op,On,R,T"))
(match_dup 1)))
- (set (match_operand:SI 0 "register_operand" "=d,d,d")
- (plus:SI (match_dup 1) (match_dup 2)))]
+ (set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d")
+ (plus:GPR (match_dup 1) (match_dup 2)))]
"s390_match_ccmode (insn, CCL1mode)"
"@
- alr\t%0,%2
- al\t%0,%2
- aly\t%0,%2"
- [(set_attr "op_type" "RR,RX,RXY")])
-
-(define_insn "*addsi3_carry1_cconly"
- [(set (reg 33)
- (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0")
- (match_operand:SI 2 "general_operand" "d,R,T"))
+ al<g>r\t%0,%2
+ al<g>fi\t%0,%2
+ sl<g>fi\t%0,%n2
+ al<g>\t%0,%2
+ al<y>\t%0,%2"
+ [(set_attr "op_type" "RR<E>,RIL,RIL,RX<Y>,RXY")])
+
+; alr, al, aly, algr, alg
+(define_insn "*add<mode>3_carry1_cconly"
+ [(set (reg CC_REGNUM)
+ (compare (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,0,0")
+ (match_operand:GPR 2 "general_operand" "d,R,T"))
(match_dup 1)))
- (clobber (match_scratch:SI 0 "=d,d,d"))]
+ (clobber (match_scratch:GPR 0 "=d,d,d"))]
"s390_match_ccmode (insn, CCL1mode)"
"@
- alr\t%0,%2
- al\t%0,%2
- aly\t%0,%2"
- [(set_attr "op_type" "RR,RX,RXY")])
+ al<g>r\t%0,%2
+ al<g>\t%0,%2
+ al<y>\t%0,%2"
+ [(set_attr "op_type" "RR<E>,RX<Y>,RXY")])
-(define_insn "*addsi3_carry2_cc"
- [(set (reg 33)
- (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0")
- (match_operand:SI 2 "general_operand" "d,R,T"))
+; alr, alfi, slfi, al, aly, algr, algfi, slgfi, alg
+(define_insn "*add<mode>3_carry2_cc"
+ [(set (reg CC_REGNUM)
+ (compare (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,0,0,0,0")
+ (match_operand:GPR 2 "general_operand" "d,Op,On,R,T"))
(match_dup 2)))
- (set (match_operand:SI 0 "register_operand" "=d,d,d")
- (plus:SI (match_dup 1) (match_dup 2)))]
+ (set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d")
+ (plus:GPR (match_dup 1) (match_dup 2)))]
"s390_match_ccmode (insn, CCL1mode)"
"@
- alr\t%0,%2
- al\t%0,%2
- aly\t%0,%2"
- [(set_attr "op_type" "RR,RX,RXY")])
-
-(define_insn "*addsi3_carry2_cconly"
- [(set (reg 33)
- (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0")
- (match_operand:SI 2 "general_operand" "d,R,T"))
+ al<g>r\t%0,%2
+ al<g>fi\t%0,%2
+ sl<g>fi\t%0,%n2
+ al<g>\t%0,%2
+ al<y>\t%0,%2"
+ [(set_attr "op_type" "RR<E>,RIL,RIL,RX<Y>,RXY")])
+
+; alr, al, aly, algr, alg
+(define_insn "*add<mode>3_carry2_cconly"
+ [(set (reg CC_REGNUM)
+ (compare (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,0,0")
+ (match_operand:GPR 2 "general_operand" "d,R,T"))
(match_dup 2)))
- (clobber (match_scratch:SI 0 "=d,d,d"))]
+ (clobber (match_scratch:GPR 0 "=d,d,d"))]
"s390_match_ccmode (insn, CCL1mode)"
"@
- alr\t%0,%2
- al\t%0,%2
- aly\t%0,%2"
- [(set_attr "op_type" "RR,RX,RXY")])
+ al<g>r\t%0,%2
+ al<g>\t%0,%2
+ al<y>\t%0,%2"
+ [(set_attr "op_type" "RR<E>,RX<Y>,RXY")])
-(define_insn "*addsi3_cc"
- [(set (reg 33)
- (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0")
- (match_operand:SI 2 "general_operand" "d,R,T"))
+; alr, alfi, slfi, al, aly, algr, algfi, slgfi, alg
+(define_insn "*add<mode>3_cc"
+ [(set (reg CC_REGNUM)
+ (compare (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,0,0,0,0")
+ (match_operand:GPR 2 "general_operand" "d,Op,On,R,T"))
(const_int 0)))
- (set (match_operand:SI 0 "register_operand" "=d,d,d")
- (plus:SI (match_dup 1) (match_dup 2)))]
+ (set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d")
+ (plus:GPR (match_dup 1) (match_dup 2)))]
"s390_match_ccmode (insn, CCLmode)"
"@
- alr\t%0,%2
- al\t%0,%2
- aly\t%0,%2"
- [(set_attr "op_type" "RR,RX,RXY")])
-
-(define_insn "*addsi3_cconly"
- [(set (reg 33)
- (compare (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0")
- (match_operand:SI 2 "general_operand" "d,R,T"))
+ al<g>r\t%0,%2
+ al<g>fi\t%0,%2
+ sl<g>fi\t%0,%n2
+ al<g>\t%0,%2
+ al<y>\t%0,%2"
+ [(set_attr "op_type" "RR<E>,RIL,RIL,RX<Y>,RXY")])
+
+; alr, al, aly, algr, alg
+(define_insn "*add<mode>3_cconly"
+ [(set (reg CC_REGNUM)
+ (compare (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,0,0")
+ (match_operand:GPR 2 "general_operand" "d,R,T"))
(const_int 0)))
- (clobber (match_scratch:SI 0 "=d,d,d"))]
- "s390_match_ccmode (insn, CCLmode)"
- "@
- alr\t%0,%2
- al\t%0,%2
- aly\t%0,%2"
- [(set_attr "op_type" "RR,RX,RXY")])
-
-(define_insn "*addsi3_cconly2"
- [(set (reg 33)
- (compare (match_operand:SI 1 "nonimmediate_operand" "%0,0,0")
- (neg:SI (match_operand:SI 2 "general_operand" "d,R,T"))))
- (clobber (match_scratch:SI 0 "=d,d,d"))]
+ (clobber (match_scratch:GPR 0 "=d,d,d"))]
"s390_match_ccmode (insn, CCLmode)"
"@
- alr\t%0,%2
- al\t%0,%2
- aly\t%0,%2"
- [(set_attr "op_type" "RR,RX,RXY")])
-
-(define_insn "*addsi3_sign"
- [(set (match_operand:SI 0 "register_operand" "=d,d")
- (plus:SI (match_operand:SI 1 "register_operand" "0,0")
- (sign_extend:SI (match_operand:HI 2 "memory_operand" "R,T"))))
- (clobber (reg:CC 33))]
- ""
- "@
- ah\t%0,%2
- ahy\t%0,%2"
- [(set_attr "op_type" "RX,RXY")])
-
-(define_insn "addsi3"
- [(set (match_operand:SI 0 "register_operand" "=d,d,d,d")
- (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0,0")
- (match_operand:SI 2 "general_operand" "d,K,R,T")))
- (clobber (reg:CC 33))]
- ""
- "@
- ar\t%0,%2
- ahi\t%0,%h2
- a\t%0,%2
- ay\t%0,%2"
- [(set_attr "op_type" "RR,RI,RX,RXY")])
-
-;
-; adddf3 instruction pattern(s).
-;
-
-(define_expand "adddf3"
- [(parallel
- [(set (match_operand:DF 0 "register_operand" "=f,f")
- (plus:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0")
- (match_operand:DF 2 "general_operand" "f,R")))
- (clobber (reg:CC 33))])]
- "TARGET_HARD_FLOAT"
- "")
-
-(define_insn "*adddf3"
- [(set (match_operand:DF 0 "register_operand" "=f,f")
- (plus:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0")
- (match_operand:DF 2 "general_operand" "f,R")))
- (clobber (reg:CC 33))]
- "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "@
- adbr\t%0,%2
- adb\t%0,%2"
- [(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fsimpd,fsimpd")])
-
-(define_insn "*adddf3_cc"
- [(set (reg 33)
- (compare (plus:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0")
- (match_operand:DF 2 "general_operand" "f,R"))
- (match_operand:DF 3 "const0_operand" "")))
- (set (match_operand:DF 0 "register_operand" "=f,f")
- (plus:DF (match_dup 1) (match_dup 2)))]
- "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "@
- adbr\t%0,%2
- adb\t%0,%2"
- [(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fsimpd,fsimpd")])
-
-(define_insn "*adddf3_cconly"
- [(set (reg 33)
- (compare (plus:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0")
- (match_operand:DF 2 "general_operand" "f,R"))
- (match_operand:DF 3 "const0_operand" "")))
- (clobber (match_scratch:DF 0 "=f,f"))]
- "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "@
- adbr\t%0,%2
- adb\t%0,%2"
- [(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fsimpd,fsimpd")])
-
-(define_insn "*adddf3_ibm"
- [(set (match_operand:DF 0 "register_operand" "=f,f")
- (plus:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0")
- (match_operand:DF 2 "general_operand" "f,R")))
- (clobber (reg:CC 33))]
- "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
+ al<g>r\t%0,%2
+ al<g>\t%0,%2
+ al<y>\t%0,%2"
+ [(set_attr "op_type" "RR<E>,RX<Y>,RXY")])
+
+; alr, al, aly, algr, alg
+(define_insn "*add<mode>3_cconly2"
+ [(set (reg CC_REGNUM)
+ (compare (match_operand:GPR 1 "nonimmediate_operand" "%0,0,0")
+ (neg:GPR (match_operand:GPR 2 "general_operand" "d,R,T"))))
+ (clobber (match_scratch:GPR 0 "=d,d,d"))]
+ "s390_match_ccmode(insn, CCLmode)"
+ "@
+ al<g>r\t%0,%2
+ al<g>\t%0,%2
+ al<y>\t%0,%2"
+ [(set_attr "op_type" "RR<E>,RX<Y>,RXY")])
+
+; ahi, afi, aghi, agfi
+(define_insn "*add<mode>3_imm_cc"
+ [(set (reg CC_REGNUM)
+ (compare (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "0,0")
+ (match_operand:GPR 2 "const_int_operand" "K,Os"))
+ (const_int 0)))
+ (set (match_operand:GPR 0 "register_operand" "=d,d")
+ (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\"))
+ && INTVAL (operands[2]) != -((HOST_WIDE_INT)1 << (GET_MODE_BITSIZE(<MODE>mode) - 1))"
"@
- adr\t%0,%2
- ad\t%0,%2"
- [(set_attr "op_type" "RR,RX")
- (set_attr "type" "fsimpd,fsimpd")])
+ a<g>hi\t%0,%h2
+ a<g>fi\t%0,%2"
+ [(set_attr "op_type" "RI,RIL")])
;
-; addsf3 instruction pattern(s).
+; add(df|sf)3 instruction pattern(s).
;
-(define_expand "addsf3"
+(define_expand "add<mode>3"
[(parallel
- [(set (match_operand:SF 0 "register_operand" "=f,f")
- (plus:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0")
- (match_operand:SF 2 "general_operand" "f,R")))
- (clobber (reg:CC 33))])]
+ [(set (match_operand:FPR 0 "register_operand" "=f,f")
+ (plus:FPR (match_operand:FPR 1 "nonimmediate_operand" "%0,0")
+ (match_operand:FPR 2 "general_operand" "f,<Rf>")))
+ (clobber (reg:CC CC_REGNUM))])]
"TARGET_HARD_FLOAT"
"")
-(define_insn "*addsf3"
- [(set (match_operand:SF 0 "register_operand" "=f,f")
- (plus:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0")
- (match_operand:SF 2 "general_operand" "f,R")))
- (clobber (reg:CC 33))]
+; axbr, adbr, aebr, axb, adb, aeb
+(define_insn "*add<mode>3"
+ [(set (match_operand:FPR 0 "register_operand" "=f,f")
+ (plus:FPR (match_operand:FPR 1 "nonimmediate_operand" "%0,0")
+ (match_operand:FPR 2 "general_operand" "f,<Rf>")))
+ (clobber (reg:CC CC_REGNUM))]
"TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
"@
- aebr\t%0,%2
- aeb\t%0,%2"
+ a<xde>br\t%0,%2
+ a<xde>b\t%0,%2"
[(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fsimps,fsimps")])
-
-(define_insn "*addsf3_cc"
- [(set (reg 33)
- (compare (plus:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0")
- (match_operand:SF 2 "general_operand" "f,R"))
- (match_operand:SF 3 "const0_operand" "")))
- (set (match_operand:SF 0 "register_operand" "=f,f")
- (plus:SF (match_dup 1) (match_dup 2)))]
+ (set_attr "type" "fsimp<mode>")])
+
+; axbr, adbr, aebr, axb, adb, aeb
+(define_insn "*add<mode>3_cc"
+ [(set (reg CC_REGNUM)
+ (compare (plus:FPR (match_operand:FPR 1 "nonimmediate_operand" "%0,0")
+ (match_operand:FPR 2 "general_operand" "f,<Rf>"))
+ (match_operand:FPR 3 "const0_operand" "")))
+ (set (match_operand:FPR 0 "register_operand" "=f,f")
+ (plus:FPR (match_dup 1) (match_dup 2)))]
"s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
"@
- aebr\t%0,%2
- aeb\t%0,%2"
+ a<xde>br\t%0,%2
+ a<xde>b\t%0,%2"
[(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fsimps,fsimps")])
-
-(define_insn "*addsf3_cconly"
- [(set (reg 33)
- (compare (plus:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0")
- (match_operand:SF 2 "general_operand" "f,R"))
- (match_operand:SF 3 "const0_operand" "")))
- (clobber (match_scratch:SF 0 "=f,f"))]
+ (set_attr "type" "fsimp<mode>")])
+
+; axbr, adbr, aebr, axb, adb, aeb
+(define_insn "*add<mode>3_cconly"
+ [(set (reg CC_REGNUM)
+ (compare (plus:FPR (match_operand:FPR 1 "nonimmediate_operand" "%0,0")
+ (match_operand:FPR 2 "general_operand" "f,<Rf>"))
+ (match_operand:FPR 3 "const0_operand" "")))
+ (clobber (match_scratch:FPR 0 "=f,f"))]
"s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
"@
- aebr\t%0,%2
- aeb\t%0,%2"
+ a<xde>br\t%0,%2
+ a<xde>b\t%0,%2"
[(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fsimps,fsimps")])
-
-(define_insn "*addsf3"
- [(set (match_operand:SF 0 "register_operand" "=f,f")
- (plus:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0")
- (match_operand:SF 2 "general_operand" "f,R")))
- (clobber (reg:CC 33))]
+ (set_attr "type" "fsimp<mode>")])
+
+; axr, adr, aer, ax, ad, ae
+(define_insn "*add<mode>3_ibm"
+ [(set (match_operand:FPR 0 "register_operand" "=f,f")
+ (plus:FPR (match_operand:FPR 1 "nonimmediate_operand" "%0,0")
+ (match_operand:FPR 2 "general_operand" "f,<Rf>")))
+ (clobber (reg:CC CC_REGNUM))]
"TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
"@
- aer\t%0,%2
- ae\t%0,%2"
- [(set_attr "op_type" "RR,RX")
- (set_attr "type" "fsimps,fsimps")])
+ a<xde>r\t%0,%2
+ a<xde>\t%0,%2"
+ [(set_attr "op_type" "<RRe>,<RXe>")
+ (set_attr "type" "fsimp<mode>")])
;;
@@ -3832,14 +3879,51 @@
;;
;
+; 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_64BIT"
+ "#"
+ "&& 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,m"))))
- (clobber (reg:CC 33))]
+ (clobber (reg:CC CC_REGNUM))]
"TARGET_64BIT"
"@
sgfr\t%0,%2
@@ -3847,7 +3931,7 @@
[(set_attr "op_type" "RRE,RXY")])
(define_insn "*subdi3_zero_cc"
- [(set (reg 33)
+ [(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,m")))
(const_int 0)))
@@ -3860,7 +3944,7 @@
[(set_attr "op_type" "RRE,RXY")])
(define_insn "*subdi3_zero_cconly"
- [(set (reg 33)
+ [(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,m")))
(const_int 0)))
@@ -3875,122 +3959,60 @@
[(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,m"))))
- (clobber (reg:CC 33))]
+ (clobber (reg:CC CC_REGNUM))]
"TARGET_64BIT"
"@
slgfr\t%0,%2
slgf\t%0,%2"
[(set_attr "op_type" "RRE,RXY")])
-(define_insn "*subdi3_borrow_cc"
- [(set (reg 33)
- (compare (minus:DI (match_operand:DI 1 "register_operand" "0,0")
- (match_operand:DI 2 "general_operand" "d,m"))
- (match_dup 1)))
- (set (match_operand:DI 0 "register_operand" "=d,d")
- (minus:DI (match_dup 1) (match_dup 2)))]
- "s390_match_ccmode (insn, CCL2mode) && TARGET_64BIT"
- "@
- slgr\t%0,%2
- slg\t%0,%2"
- [(set_attr "op_type" "RRE,RXY")])
-
-(define_insn "*subdi3_borrow_cconly"
- [(set (reg 33)
- (compare (minus:DI (match_operand:DI 1 "register_operand" "0,0")
- (match_operand:DI 2 "general_operand" "d,m"))
- (match_dup 1)))
- (clobber (match_scratch:DI 0 "=d,d"))]
- "s390_match_ccmode (insn, CCL2mode) && TARGET_64BIT"
- "@
- slgr\t%0,%2
- slg\t%0,%2"
- [(set_attr "op_type" "RRE,RXY")])
-
-(define_insn "*subdi3_cc"
- [(set (reg 33)
- (compare (minus:DI (match_operand:DI 1 "register_operand" "0,0")
- (match_operand:DI 2 "general_operand" "d,m"))
- (const_int 0)))
- (set (match_operand:DI 0 "register_operand" "=d,d")
- (minus:DI (match_dup 1) (match_dup 2)))]
- "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT"
- "@
- slgr\t%0,%2
- slg\t%0,%2"
- [(set_attr "op_type" "RRE,RXY")])
-
-(define_insn "*subdi3_cconly"
- [(set (reg 33)
- (compare (minus:DI (match_operand:DI 1 "register_operand" "0,0")
- (match_operand:DI 2 "general_operand" "d,m"))
- (const_int 0)))
- (clobber (match_scratch:DI 0 "=d,d"))]
- "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT"
- "@
- slgr\t%0,%2
- slg\t%0,%2"
- [(set_attr "op_type" "RRE,RXY")])
-
-(define_insn "*subdi3_64"
- [(set (match_operand:DI 0 "register_operand" "=d,d")
- (minus:DI (match_operand:DI 1 "register_operand" "0,0")
- (match_operand:DI 2 "general_operand" "d,m") ) )
- (clobber (reg:CC 33))]
- "TARGET_64BIT"
- "@
- sgr\t%0,%2
- sg\t%0,%2"
- [(set_attr "op_type" "RRE,RRE")])
-
(define_insn_and_split "*subdi3_31z"
[(set (match_operand:DI 0 "register_operand" "=&d")
(minus:DI (match_operand:DI 1 "register_operand" "0")
(match_operand:DI 2 "general_operand" "do") ) )
- (clobber (reg:CC 33))]
+ (clobber (reg:CC CC_REGNUM))]
"!TARGET_64BIT && TARGET_CPU_ZARCH"
"#"
"&& reload_completed"
[(parallel
- [(set (reg:CCL2 33)
+ [(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 33) (const_int 0))))
- (clobber (reg:CC 33))])]
+ (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);"
- [(set_attr "op_type" "NN")])
+ 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 33))]
+ (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 33))])
+ (clobber (reg:CC CC_REGNUM))])
(parallel
- [(set (reg:CCL2 33)
+ [(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 33) (const_int 0))
+ (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 33))])
+ (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);
@@ -3998,227 +4020,201 @@
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 ();"
- [(set_attr "op_type" "NN")])
-
-(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 33))])]
- ""
- "")
+ operands[9] = gen_label_rtx ();")
;
; subsi3 instruction pattern(s).
;
-(define_insn "*subsi3_borrow_cc"
- [(set (reg 33)
- (compare (minus:SI (match_operand:SI 1 "register_operand" "0,0,0")
- (match_operand:SI 2 "general_operand" "d,R,T"))
- (match_dup 1)))
- (set (match_operand:SI 0 "register_operand" "=d,d,d")
- (minus:SI (match_dup 1) (match_dup 2)))]
- "s390_match_ccmode (insn, CCL2mode)"
- "@
- slr\t%0,%2
- sl\t%0,%2
- sly\t%0,%2"
- [(set_attr "op_type" "RR,RX,RXY")])
-
-(define_insn "*subsi3_borrow_cconly"
- [(set (reg 33)
- (compare (minus:SI (match_operand:SI 1 "register_operand" "0,0,0")
- (match_operand:SI 2 "general_operand" "d,R,T"))
- (match_dup 1)))
- (clobber (match_scratch:SI 0 "=d,d,d"))]
- "s390_match_ccmode (insn, CCL2mode)"
- "@
- slr\t%0,%2
- sl\t%0,%2
- sly\t%0,%2"
- [(set_attr "op_type" "RR,RX,RXY")])
-
-(define_insn "*subsi3_cc"
- [(set (reg 33)
- (compare (minus:SI (match_operand:SI 1 "register_operand" "0,0,0")
- (match_operand:SI 2 "general_operand" "d,R,T"))
- (const_int 0)))
- (set (match_operand:SI 0 "register_operand" "=d,d,d")
- (minus:SI (match_dup 1) (match_dup 2)))]
- "s390_match_ccmode (insn, CCLmode)"
- "@
- slr\t%0,%2
- sl\t%0,%2
- sly\t%0,%2"
- [(set_attr "op_type" "RR,RX,RXY")])
-
-(define_insn "*subsi3_cconly"
- [(set (reg 33)
- (compare (minus:SI (match_operand:SI 1 "register_operand" "0,0,0")
- (match_operand:SI 2 "general_operand" "d,R,T"))
- (const_int 0)))
- (clobber (match_scratch:SI 0 "=d,d,d"))]
- "s390_match_ccmode (insn, CCLmode)"
- "@
- slr\t%0,%2
- sl\t%0,%2
- sly\t%0,%2"
- [(set_attr "op_type" "RR,RX,RXY")])
+(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 33))]
+ (clobber (reg:CC CC_REGNUM))]
""
"@
sh\t%0,%2
shy\t%0,%2"
[(set_attr "op_type" "RX,RXY")])
-(define_insn "subsi3"
- [(set (match_operand:SI 0 "register_operand" "=d,d,d")
- (minus:SI (match_operand:SI 1 "register_operand" "0,0,0")
- (match_operand:SI 2 "general_operand" "d,R,T")))
- (clobber (reg:CC 33))]
- ""
- "@
- sr\t%0,%2
- s\t%0,%2
- sy\t%0,%2"
- [(set_attr "op_type" "RR,RX,RXY")])
-
-
;
-; subdf3 instruction pattern(s).
+; sub(di|si)3 instruction pattern(s).
;
-(define_expand "subdf3"
- [(parallel
- [(set (match_operand:DF 0 "register_operand" "=f,f")
- (minus:DF (match_operand:DF 1 "register_operand" "0,0")
- (match_operand:DF 2 "general_operand" "f,R")))
- (clobber (reg:CC 33))])]
- "TARGET_HARD_FLOAT"
- "")
+; sr, s, sy, sgr, sg
+(define_insn "*sub<mode>3"
+ [(set (match_operand:GPR 0 "register_operand" "=d,d,d")
+ (minus:GPR (match_operand:GPR 1 "register_operand" "0,0,0")
+ (match_operand:GPR 2 "general_operand" "d,R,T") ) )
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "@
+ s<g>r\t%0,%2
+ s<g>\t%0,%2
+ s<y>\t%0,%2"
+ [(set_attr "op_type" "RR<E>,RX<Y>,RXY")])
-(define_insn "*subdf3"
- [(set (match_operand:DF 0 "register_operand" "=f,f")
- (minus:DF (match_operand:DF 1 "register_operand" "0,0")
- (match_operand:DF 2 "general_operand" "f,R")))
- (clobber (reg:CC 33))]
- "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
+; slr, sl, sly, slgr, slg
+(define_insn "*sub<mode>3_borrow_cc"
+ [(set (reg CC_REGNUM)
+ (compare (minus:GPR (match_operand:GPR 1 "register_operand" "0,0,0")
+ (match_operand:GPR 2 "general_operand" "d,R,T"))
+ (match_dup 1)))
+ (set (match_operand:GPR 0 "register_operand" "=d,d,d")
+ (minus:GPR (match_dup 1) (match_dup 2)))]
+ "s390_match_ccmode (insn, CCL2mode)"
"@
- sdbr\t%0,%2
- sdb\t%0,%2"
- [(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fsimpd,fsimpd")])
-
-(define_insn "*subdf3_cc"
- [(set (reg 33)
- (compare (minus:DF (match_operand:DF 1 "nonimmediate_operand" "0,0")
- (match_operand:DF 2 "general_operand" "f,R"))
- (match_operand:DF 3 "const0_operand" "")))
- (set (match_operand:DF 0 "register_operand" "=f,f")
- (minus:DF (match_dup 1) (match_dup 2)))]
- "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
+ sl<g>r\t%0,%2
+ sl<g>\t%0,%2
+ sl<y>\t%0,%2"
+ [(set_attr "op_type" "RR<E>,RX<Y>,RXY")])
+
+; slr, sl, sly, slgr, slg
+(define_insn "*sub<mode>3_borrow_cconly"
+ [(set (reg CC_REGNUM)
+ (compare (minus:GPR (match_operand:GPR 1 "register_operand" "0,0,0")
+ (match_operand:GPR 2 "general_operand" "d,R,T"))
+ (match_dup 1)))
+ (clobber (match_scratch:GPR 0 "=d,d,d"))]
+ "s390_match_ccmode (insn, CCL2mode)"
"@
- sdbr\t%0,%2
- sdb\t%0,%2"
- [(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fsimpd,fsimpd")])
-
-(define_insn "*subdf3_cconly"
- [(set (reg 33)
- (compare (minus:DF (match_operand:DF 1 "nonimmediate_operand" "0,0")
- (match_operand:DF 2 "general_operand" "f,R"))
- (match_operand:DF 3 "const0_operand" "")))
- (clobber (match_scratch:DF 0 "=f,f"))]
- "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
+ sl<g>r\t%0,%2
+ sl<g>\t%0,%2
+ sl<y>\t%0,%2"
+ [(set_attr "op_type" "RR<E>,RX<Y>,RXY")])
+
+; slr, sl, sly, slgr, slg
+(define_insn "*sub<mode>3_cc"
+ [(set (reg CC_REGNUM)
+ (compare (minus:GPR (match_operand:GPR 1 "register_operand" "0,0,0")
+ (match_operand:GPR 2 "general_operand" "d,R,T"))
+ (const_int 0)))
+ (set (match_operand:GPR 0 "register_operand" "=d,d,d")
+ (minus:GPR (match_dup 1) (match_dup 2)))]
+ "s390_match_ccmode (insn, CCLmode)"
"@
- sdbr\t%0,%2
- sdb\t%0,%2"
- [(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fsimpd,fsimpd")])
+ sl<g>r\t%0,%2
+ sl<g>\t%0,%2
+ sl<y>\t%0,%2"
+ [(set_attr "op_type" "RR<E>,RX<Y>,RXY")])
+
+; slr, sl, sly, slgr, slg
+(define_insn "*sub<mode>3_cc2"
+ [(set (reg CC_REGNUM)
+ (compare (match_operand:GPR 1 "register_operand" "0,0,0")
+ (match_operand:GPR 2 "general_operand" "d,R,T")))
+ (set (match_operand:GPR 0 "register_operand" "=d,d,d")
+ (minus:GPR (match_dup 1) (match_dup 2)))]
+ "s390_match_ccmode (insn, CCL3mode)"
+ "@
+ sl<g>r\t%0,%2
+ sl<g>\t%0,%2
+ sl<y>\t%0,%2"
+ [(set_attr "op_type" "RR<E>,RX<Y>,RXY")])
+
+; slr, sl, sly, slgr, slg
+(define_insn "*sub<mode>3_cconly"
+ [(set (reg CC_REGNUM)
+ (compare (minus:GPR (match_operand:GPR 1 "register_operand" "0,0,0")
+ (match_operand:GPR 2 "general_operand" "d,R,T"))
+ (const_int 0)))
+ (clobber (match_scratch:GPR 0 "=d,d,d"))]
+ "s390_match_ccmode (insn, CCLmode)"
+ "@
+ sl<g>r\t%0,%2
+ sl<g>\t%0,%2
+ sl<y>\t%0,%2"
+ [(set_attr "op_type" "RR<E>,RX<Y>,RXY")])
-(define_insn "*subdf3_ibm"
- [(set (match_operand:DF 0 "register_operand" "=f,f")
- (minus:DF (match_operand:DF 1 "register_operand" "0,0")
- (match_operand:DF 2 "general_operand" "f,R")))
- (clobber (reg:CC 33))]
- "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
+; slr, sl, sly, slgr, slg
+(define_insn "*sub<mode>3_cconly2"
+ [(set (reg CC_REGNUM)
+ (compare (match_operand:GPR 1 "register_operand" "0,0,0")
+ (match_operand:GPR 2 "general_operand" "d,R,T")))
+ (clobber (match_scratch:GPR 0 "=d,d,d"))]
+ "s390_match_ccmode (insn, CCL3mode)"
"@
- sdr\t%0,%2
- sd\t%0,%2"
- [(set_attr "op_type" "RR,RX")
- (set_attr "type" "fsimpd,fsimpd")])
+ sl<g>r\t%0,%2
+ sl<g>\t%0,%2
+ sl<y>\t%0,%2"
+ [(set_attr "op_type" "RR<E>,RX<Y>,RXY")])
;
-; subsf3 instruction pattern(s).
+; sub(df|sf)3 instruction pattern(s).
;
-(define_expand "subsf3"
+(define_expand "sub<mode>3"
[(parallel
- [(set (match_operand:SF 0 "register_operand" "=f,f")
- (minus:SF (match_operand:SF 1 "register_operand" "0,0")
- (match_operand:SF 2 "general_operand" "f,R")))
- (clobber (reg:CC 33))])]
+ [(set (match_operand:FPR 0 "register_operand" "=f,f")
+ (minus:FPR (match_operand:FPR 1 "register_operand" "0,0")
+ (match_operand:FPR 2 "general_operand" "f,R")))
+ (clobber (reg:CC CC_REGNUM))])]
"TARGET_HARD_FLOAT"
"")
-(define_insn "*subsf3"
- [(set (match_operand:SF 0 "register_operand" "=f,f")
- (minus:SF (match_operand:SF 1 "register_operand" "0,0")
- (match_operand:SF 2 "general_operand" "f,R")))
- (clobber (reg:CC 33))]
+; sxbr, sdbr, sebr, sxb, sdb, seb
+(define_insn "*sub<mode>3"
+ [(set (match_operand:FPR 0 "register_operand" "=f,f")
+ (minus:FPR (match_operand:FPR 1 "register_operand" "0,0")
+ (match_operand:FPR 2 "general_operand" "f,<Rf>")))
+ (clobber (reg:CC CC_REGNUM))]
"TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
"@
- sebr\t%0,%2
- seb\t%0,%2"
+ s<xde>br\t%0,%2
+ s<xde>b\t%0,%2"
[(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fsimps,fsimps")])
-
-(define_insn "*subsf3_cc"
- [(set (reg 33)
- (compare (minus:SF (match_operand:SF 1 "nonimmediate_operand" "0,0")
- (match_operand:SF 2 "general_operand" "f,R"))
- (match_operand:SF 3 "const0_operand" "")))
- (set (match_operand:SF 0 "register_operand" "=f,f")
- (minus:SF (match_dup 1) (match_dup 2)))]
+ (set_attr "type" "fsimp<mode>")])
+
+; sxbr, sdbr, sebr, sxb, sdb, seb
+(define_insn "*sub<mode>3_cc"
+ [(set (reg CC_REGNUM)
+ (compare (minus:FPR (match_operand:FPR 1 "nonimmediate_operand" "0,0")
+ (match_operand:FPR 2 "general_operand" "f,<Rf>"))
+ (match_operand:FPR 3 "const0_operand" "")))
+ (set (match_operand:FPR 0 "register_operand" "=f,f")
+ (minus:FPR (match_dup 1) (match_dup 2)))]
"s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
"@
- sebr\t%0,%2
- seb\t%0,%2"
+ s<xde>br\t%0,%2
+ s<xde>b\t%0,%2"
[(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fsimps,fsimps")])
-
-(define_insn "*subsf3_cconly"
- [(set (reg 33)
- (compare (minus:SF (match_operand:SF 1 "nonimmediate_operand" "0,0")
- (match_operand:SF 2 "general_operand" "f,R"))
- (match_operand:SF 3 "const0_operand" "")))
- (clobber (match_scratch:SF 0 "=f,f"))]
+ (set_attr "type" "fsimp<mode>")])
+
+; sxbr, sdbr, sebr, sxb, sdb, seb
+(define_insn "*sub<mode>3_cconly"
+ [(set (reg CC_REGNUM)
+ (compare (minus:FPR (match_operand:FPR 1 "nonimmediate_operand" "0,0")
+ (match_operand:FPR 2 "general_operand" "f,<Rf>"))
+ (match_operand:FPR 3 "const0_operand" "")))
+ (clobber (match_scratch:FPR 0 "=f,f"))]
"s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
"@
- sebr\t%0,%2
- seb\t%0,%2"
+ s<xde>br\t%0,%2
+ s<xde>b\t%0,%2"
[(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fsimps,fsimps")])
-
-(define_insn "*subsf3_ibm"
- [(set (match_operand:SF 0 "register_operand" "=f,f")
- (minus:SF (match_operand:SF 1 "register_operand" "0,0")
- (match_operand:SF 2 "general_operand" "f,R")))
- (clobber (reg:CC 33))]
+ (set_attr "type" "fsimp<mode>")])
+
+; sxr, sdr, ser, sx, sd, se
+(define_insn "*sub<mode>3_ibm"
+ [(set (match_operand:FPR 0 "register_operand" "=f,f")
+ (minus:FPR (match_operand:FPR 1 "register_operand" "0,0")
+ (match_operand:FPR 2 "general_operand" "f,<Rf>")))
+ (clobber (reg:CC CC_REGNUM))]
"TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
"@
- ser\t%0,%2
- se\t%0,%2"
- [(set_attr "op_type" "RR,RX")
- (set_attr "type" "fsimps,fsimps")])
+ s<xde>r\t%0,%2
+ s<xde>\t%0,%2"
+ [(set_attr "op_type" "<RRe>,<RXe>")
+ (set_attr "type" "fsimp<mode>")])
;;
@@ -4226,120 +4222,149 @@
;;
;
-; adddicc instruction pattern(s).
+; add(di|si)cc instruction pattern(s).
;
-(define_insn "*adddi3_alc_cc"
- [(set (reg 33)
+; alcr, alc, alcgr, alcg
+(define_insn "*add<mode>3_alc_cc"
+ [(set (reg CC_REGNUM)
(compare
- (plus:DI (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
- (match_operand:DI 2 "general_operand" "d,m"))
- (match_operand:DI 3 "s390_alc_comparison" ""))
+ (plus:GPR (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,0")
+ (match_operand:GPR 2 "general_operand" "d,m"))
+ (match_operand:GPR 3 "s390_alc_comparison" ""))
(const_int 0)))
- (set (match_operand:DI 0 "register_operand" "=d,d")
- (plus:DI (plus:DI (match_dup 1) (match_dup 2)) (match_dup 3)))]
- "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT"
+ (set (match_operand:GPR 0 "register_operand" "=d,d")
+ (plus:GPR (plus:GPR (match_dup 1) (match_dup 2)) (match_dup 3)))]
+ "s390_match_ccmode (insn, CCLmode) && TARGET_CPU_ZARCH"
"@
- alcgr\\t%0,%2
- alcg\\t%0,%2"
+ alc<g>r\t%0,%2
+ alc<g>\t%0,%2"
[(set_attr "op_type" "RRE,RXY")])
-(define_insn "*adddi3_alc"
- [(set (match_operand:DI 0 "register_operand" "=d,d")
- (plus:DI (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
- (match_operand:DI 2 "general_operand" "d,m"))
- (match_operand:DI 3 "s390_alc_comparison" "")))
- (clobber (reg:CC 33))]
- "TARGET_64BIT"
- "@
- alcgr\\t%0,%2
- alcg\\t%0,%2"
+; 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 1 "nonimmediate_operand" "%0,0")
+ (match_operand:GPR 2 "general_operand" "d,m"))
+ (match_operand:GPR 3 "s390_alc_comparison" "")))
+ (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")])
-(define_insn "*subdi3_slb_cc"
- [(set (reg 33)
+; slbr, slb, slbgr, slbg
+(define_insn "*sub<mode>3_slb_cc"
+ [(set (reg CC_REGNUM)
(compare
- (minus:DI (minus:DI (match_operand:DI 1 "nonimmediate_operand" "0,0")
- (match_operand:DI 2 "general_operand" "d,m"))
- (match_operand:DI 3 "s390_slb_comparison" ""))
+ (minus:GPR (minus:GPR (match_operand:GPR 1 "nonimmediate_operand" "0,0")
+ (match_operand:GPR 2 "general_operand" "d,m"))
+ (match_operand:GPR 3 "s390_slb_comparison" ""))
(const_int 0)))
- (set (match_operand:DI 0 "register_operand" "=d,d")
- (minus:DI (minus:DI (match_dup 1) (match_dup 2)) (match_dup 3)))]
- "s390_match_ccmode (insn, CCLmode) && TARGET_64BIT"
+ (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"
"@
- slbgr\\t%0,%2
- slbg\\t%0,%2"
+ slb<g>r\t%0,%2
+ slb<g>\t%0,%2"
[(set_attr "op_type" "RRE,RXY")])
-(define_insn "*subdi3_slb"
- [(set (match_operand:DI 0 "register_operand" "=d,d")
- (minus:DI (minus:DI (match_operand:DI 1 "nonimmediate_operand" "0,0")
- (match_operand:DI 2 "general_operand" "d,m"))
- (match_operand:DI 3 "s390_slb_comparison" "")))
- (clobber (reg:CC 33))]
- "TARGET_64BIT"
- "@
- slbgr\\t%0,%2
- slbg\\t%0,%2"
+; 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,m"))
+ (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")])
+(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]),
+ s390_compare_op0, s390_compare_op1,
+ operands[0], operands[2],
+ operands[3])) FAIL; DONE;")
+
;
-; addsicc instruction pattern(s).
+; scond instruction pattern(s).
;
-(define_insn "*addsi3_alc_cc"
- [(set (reg 33)
- (compare
- (plus:SI (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
- (match_operand:SI 2 "general_operand" "d,m"))
- (match_operand:SI 3 "s390_alc_comparison" ""))
- (const_int 0)))
- (set (match_operand:SI 0 "register_operand" "=d,d")
- (plus:SI (plus:SI (match_dup 1) (match_dup 2)) (match_dup 3)))]
- "s390_match_ccmode (insn, CCLmode) && TARGET_CPU_ZARCH"
- "@
- alcr\\t%0,%2
- alc\\t%0,%2"
- [(set_attr "op_type" "RRE,RXY")])
+(define_insn_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 0) (match_dup 0))
+ (match_dup 1)))
+ (clobber (reg:CC CC_REGNUM))])]
+ "")
-(define_insn "*addsi3_alc"
- [(set (match_operand:SI 0 "register_operand" "=d,d")
- (plus:SI (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
- (match_operand:SI 2 "general_operand" "d,m"))
- (match_operand:SI 3 "s390_alc_comparison" "")))
- (clobber (reg:CC 33))]
- "TARGET_CPU_ZARCH"
- "@
- alcr\\t%0,%2
- alc\\t%0,%2"
- [(set_attr "op_type" "RRE,RXY")])
+(define_insn_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_insn "*subsi3_slb_cc"
- [(set (reg 33)
- (compare
- (minus:SI (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
- (match_operand:SI 2 "general_operand" "d,m"))
- (match_operand:SI 3 "s390_slb_comparison" ""))
- (const_int 0)))
- (set (match_operand:SI 0 "register_operand" "=d,d")
- (minus:SI (minus:SI (match_dup 1) (match_dup 2)) (match_dup 3)))]
- "s390_match_ccmode (insn, CCLmode) && TARGET_CPU_ZARCH"
- "@
- slbr\\t%0,%2
- slb\\t%0,%2"
- [(set_attr "op_type" "RRE,RXY")])
-(define_insn "*subsi3_slb"
- [(set (match_operand:SI 0 "register_operand" "=d,d")
- (minus:SI (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
- (match_operand:SI 2 "general_operand" "d,m"))
- (match_operand:SI 3 "s390_slb_comparison" "")))
- (clobber (reg:CC 33))]
- "TARGET_CPU_ZARCH"
- "@
- slbr\\t%0,%2
- slb\\t%0,%2"
- [(set_attr "op_type" "RRE,RXY")])
+(define_expand "s<code>"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (SCOND (match_dup 0)
+ (match_dup 0)))]
+ "TARGET_CPU_ZARCH"
+ "if (!s390_expand_addcc (<CODE>, s390_compare_op0, s390_compare_op1,
+ operands[0], const0_rtx, const1_rtx)) FAIL; DONE;")
+
+(define_expand "seq"
+ [(parallel
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (match_dup 1))
+ (clobber (reg:CC CC_REGNUM))])
+ (parallel
+ [(set (match_dup 0) (xor:SI (match_dup 0) (const_int 1)))
+ (clobber (reg:CC CC_REGNUM))])]
+ ""
+{
+ if (!s390_compare_emitted || GET_MODE (s390_compare_emitted) != CCZ1mode)
+ FAIL;
+ operands[1] = s390_emit_compare (NE, s390_compare_op0, s390_compare_op1);
+ PUT_MODE (operands[1], SImode);
+})
+
+(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))])])
;;
@@ -4359,7 +4384,7 @@
msgfr\t%0,%2
msgf\t%0,%2"
[(set_attr "op_type" "RRE,RXY")
- (set_attr "type" "imul")])
+ (set_attr "type" "imuldi")])
(define_insn "muldi3"
[(set (match_operand:DI 0 "register_operand" "=d,d,d")
@@ -4371,7 +4396,7 @@
mghi\t%0,%h2
msg\t%0,%2"
[(set_attr "op_type" "RRE,RI,RXY")
- (set_attr "type" "imul")])
+ (set_attr "type" "imuldi")])
;
; mulsi3 instruction pattern(s).
@@ -4384,7 +4409,7 @@
""
"mh\t%0,%2"
[(set_attr "op_type" "RX")
- (set_attr "type" "imul")])
+ (set_attr "type" "imulhi")])
(define_insn "mulsi3"
[(set (match_operand:SI 0 "register_operand" "=d,d,d,d")
@@ -4397,7 +4422,7 @@
ms\t%0,%2
msy\t%0,%2"
[(set_attr "op_type" "RRE,RI,RX,RXY")
- (set_attr "type" "imul")])
+ (set_attr "type" "imulsi,imulhi,imulsi,imulsi")])
;
; mulsidi3 instruction pattern(s).
@@ -4414,7 +4439,7 @@
mr\t%0,%2
m\t%0,%2"
[(set_attr "op_type" "RR,RX")
- (set_attr "type" "imul")])
+ (set_attr "type" "imulsi")])
;
; umulsidi3 instruction pattern(s).
@@ -4431,121 +4456,68 @@
mlr\t%0,%2
ml\t%0,%2"
[(set_attr "op_type" "RRE,RXY")
- (set_attr "type" "imul")])
+ (set_attr "type" "imulsi")])
;
-; muldf3 instruction pattern(s).
+; mul(df|sf)3 instruction pattern(s).
;
-(define_expand "muldf3"
- [(set (match_operand:DF 0 "register_operand" "=f,f")
- (mult:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0")
- (match_operand:DF 2 "general_operand" "f,R")))]
+(define_expand "mul<mode>3"
+ [(set (match_operand:FPR 0 "register_operand" "=f,f")
+ (mult:FPR (match_operand:FPR 1 "nonimmediate_operand" "%0,0")
+ (match_operand:FPR 2 "general_operand" "f,<Rf>")))]
"TARGET_HARD_FLOAT"
"")
-(define_insn "*muldf3"
- [(set (match_operand:DF 0 "register_operand" "=f,f")
- (mult:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0")
- (match_operand:DF 2 "general_operand" "f,R")))]
- "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "@
- mdbr\t%0,%2
- mdb\t%0,%2"
- [(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fmuld")])
-
-(define_insn "*muldf3_ibm"
- [(set (match_operand:DF 0 "register_operand" "=f,f")
- (mult:DF (match_operand:DF 1 "nonimmediate_operand" "%0,0")
- (match_operand:DF 2 "general_operand" "f,R")))]
- "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
- "@
- mdr\t%0,%2
- md\t%0,%2"
- [(set_attr "op_type" "RR,RX")
- (set_attr "type" "fmuld")])
-
-(define_insn "*fmadddf"
- [(set (match_operand:DF 0 "register_operand" "=f,f")
- (plus:DF (mult:DF (match_operand:DF 1 "register_operand" "%f,f")
- (match_operand:DF 2 "nonimmediate_operand" "f,R"))
- (match_operand:DF 3 "register_operand" "0,0")))]
- "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT && TARGET_FUSED_MADD"
- "@
- madbr\t%0,%1,%2
- madb\t%0,%1,%2"
- [(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fmuld")])
-
-(define_insn "*fmsubdf"
- [(set (match_operand:DF 0 "register_operand" "=f,f")
- (minus:DF (mult:DF (match_operand:DF 1 "register_operand" "f,f")
- (match_operand:DF 2 "nonimmediate_operand" "f,R"))
- (match_operand:DF 3 "register_operand" "0,0")))]
- "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT && TARGET_FUSED_MADD"
- "@
- msdbr\t%0,%1,%2
- msdb\t%0,%1,%2"
- [(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fmuld")])
-
-;
-; mulsf3 instruction pattern(s).
-;
-
-(define_expand "mulsf3"
- [(set (match_operand:SF 0 "register_operand" "=f,f")
- (mult:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0")
- (match_operand:SF 2 "general_operand" "f,R")))]
- "TARGET_HARD_FLOAT"
- "")
-
-(define_insn "*mulsf3"
- [(set (match_operand:SF 0 "register_operand" "=f,f")
- (mult:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0")
- (match_operand:SF 2 "general_operand" "f,R")))]
+; mxbr mdbr, meebr, mxb, mxb, meeb
+(define_insn "*mul<mode>3"
+ [(set (match_operand:FPR 0 "register_operand" "=f,f")
+ (mult:FPR (match_operand:FPR 1 "nonimmediate_operand" "%0,0")
+ (match_operand:FPR 2 "general_operand" "f,<Rf>")))]
"TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
"@
- meebr\t%0,%2
- meeb\t%0,%2"
+ m<xdee>br\t%0,%2
+ m<xdee>b\t%0,%2"
[(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fmuls")])
+ (set_attr "type" "fmul<mode>")])
-(define_insn "*mulsf3_ibm"
- [(set (match_operand:SF 0 "register_operand" "=f,f")
- (mult:SF (match_operand:SF 1 "nonimmediate_operand" "%0,0")
- (match_operand:SF 2 "general_operand" "f,R")))]
+; mxr, mdr, mer, mx, md, me
+(define_insn "*mul<mode>3_ibm"
+ [(set (match_operand:FPR 0 "register_operand" "=f,f")
+ (mult:FPR (match_operand:FPR 1 "nonimmediate_operand" "%0,0")
+ (match_operand:FPR 2 "general_operand" "f,<Rf>")))]
"TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
"@
- mer\t%0,%2
- me\t%0,%2"
- [(set_attr "op_type" "RR,RX")
- (set_attr "type" "fmuls")])
-
-(define_insn "*fmaddsf"
- [(set (match_operand:SF 0 "register_operand" "=f,f")
- (plus:SF (mult:SF (match_operand:SF 1 "register_operand" "%f,f")
- (match_operand:SF 2 "nonimmediate_operand" "f,R"))
- (match_operand:SF 3 "register_operand" "0,0")))]
+ m<xde>r\t%0,%2
+ m<xde>\t%0,%2"
+ [(set_attr "op_type" "<RRe>,<RXe>")
+ (set_attr "type" "fmul<mode>")])
+
+; maxbr, madbr, maebr, maxb, madb, maeb
+(define_insn "*fmadd<mode>"
+ [(set (match_operand:DSF 0 "register_operand" "=f,f")
+ (plus:DSF (mult:DSF (match_operand:DSF 1 "register_operand" "%f,f")
+ (match_operand:DSF 2 "nonimmediate_operand" "f,R"))
+ (match_operand:DSF 3 "register_operand" "0,0")))]
"TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT && TARGET_FUSED_MADD"
"@
- maebr\t%0,%1,%2
- maeb\t%0,%1,%2"
+ ma<xde>br\t%0,%1,%2
+ ma<xde>b\t%0,%1,%2"
[(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fmuls")])
-
-(define_insn "*fmsubsf"
- [(set (match_operand:SF 0 "register_operand" "=f,f")
- (minus:SF (mult:SF (match_operand:SF 1 "register_operand" "f,f")
- (match_operand:SF 2 "nonimmediate_operand" "f,R"))
- (match_operand:SF 3 "register_operand" "0,0")))]
+ (set_attr "type" "fmul<mode>")])
+
+; msxbr, msdbr, msebr, msxb, msdb, mseb
+(define_insn "*fmsub<mode>"
+ [(set (match_operand:DSF 0 "register_operand" "=f,f")
+ (minus:DSF (mult:DSF (match_operand:DSF 1 "register_operand" "f,f")
+ (match_operand:DSF 2 "nonimmediate_operand" "f,R"))
+ (match_operand:DSF 3 "register_operand" "0,0")))]
"TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT && TARGET_FUSED_MADD"
"@
- msebr\t%0,%1,%2
- mseb\t%0,%1,%2"
+ ms<xde>br\t%0,%1,%2
+ ms<xde>b\t%0,%1,%2"
[(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fmuls")])
+ (set_attr "type" "fmul<mode>")])
;;
;;- Divide and modulo instructions.
@@ -4586,14 +4558,12 @@
(define_insn "divmodtidi3"
[(set (match_operand:TI 0 "register_operand" "=d,d")
(ior:TI
- (zero_extend:TI
- (div:DI (match_operand:DI 1 "register_operand" "0,0")
- (match_operand:DI 2 "general_operand" "d,m")))
(ashift:TI
(zero_extend:TI
- (mod:DI (match_dup 1)
- (match_dup 2)))
- (const_int 64))))]
+ (mod:DI (match_operand:DI 1 "register_operand" "0,0")
+ (match_operand:DI 2 "general_operand" "d,m")))
+ (const_int 64))
+ (zero_extend:TI (div:DI (match_dup 1) (match_dup 2)))))]
"TARGET_64BIT"
"@
dsgr\t%0,%2
@@ -4604,14 +4574,14 @@
(define_insn "divmodtisi3"
[(set (match_operand:TI 0 "register_operand" "=d,d")
(ior:TI
- (zero_extend:TI
- (div:DI (match_operand:DI 1 "register_operand" "0,0")
- (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "d,m"))))
(ashift:TI
(zero_extend:TI
- (mod:DI (match_dup 1)
- (sign_extend:DI (match_dup 2))))
- (const_int 64))))]
+ (mod:DI (match_operand:DI 1 "register_operand" "0,0")
+ (sign_extend:DI
+ (match_operand:SI 2 "nonimmediate_operand" "d,m"))))
+ (const_int 64))
+ (zero_extend:TI
+ (div:DI (match_dup 1) (sign_extend:DI (match_dup 2))))))]
"TARGET_64BIT"
"@
dsgfr\t%0,%2
@@ -4637,10 +4607,10 @@
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_ZERO_EXTEND (TImode, div_equal),
gen_rtx_ASHIFT (TImode,
gen_rtx_ZERO_EXTEND (TImode, mod_equal),
- GEN_INT (64)));
+ GEN_INT (64)),
+ gen_rtx_ZERO_EXTEND (TImode, div_equal));
operands[4] = gen_reg_rtx(TImode);
emit_insn (gen_rtx_CLOBBER (VOIDmode, operands[4]));
@@ -4663,16 +4633,17 @@
(define_insn "udivmodtidi3"
[(set (match_operand:TI 0 "register_operand" "=d,d")
- (ior:TI (zero_extend:TI
- (truncate:DI
- (udiv:TI (match_operand:TI 1 "register_operand" "0,0")
- (zero_extend:TI
- (match_operand:DI 2 "nonimmediate_operand" "d,m")))))
- (ashift:TI
- (zero_extend:TI
- (truncate:DI
- (umod:TI (match_dup 1) (zero_extend:TI (match_dup 2)))))
- (const_int 64))))]
+ (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,m")))))
+ (const_int 64))
+ (zero_extend:TI
+ (truncate:DI
+ (udiv:TI (match_dup 1) (zero_extend:TI (match_dup 2)))))))]
"TARGET_64BIT"
"@
dlgr\t%0,%2
@@ -4698,10 +4669,10 @@
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_ZERO_EXTEND (DImode, div_equal),
gen_rtx_ASHIFT (DImode,
gen_rtx_ZERO_EXTEND (DImode, mod_equal),
- GEN_INT (32)));
+ GEN_INT (32)),
+ gen_rtx_ZERO_EXTEND (DImode, div_equal));
operands[4] = gen_reg_rtx(DImode);
emit_insn (gen_extendsidi2 (operands[4], operands[1]));
@@ -4722,16 +4693,17 @@
(define_insn "divmoddisi3"
[(set (match_operand:DI 0 "register_operand" "=d,d")
- (ior:DI (zero_extend:DI
- (truncate:SI
- (div:DI (match_operand:DI 1 "register_operand" "0,0")
- (sign_extend:DI
- (match_operand:SI 2 "nonimmediate_operand" "d,R")))))
- (ashift:DI
- (zero_extend:DI
- (truncate:SI
- (mod:DI (match_dup 1) (sign_extend:DI (match_dup 2)))))
- (const_int 32))))]
+ (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_64BIT"
"@
dr\t%0,%2
@@ -4757,10 +4729,10 @@
div_equal = gen_rtx_UDIV (SImode, operands[1], operands[2]);
mod_equal = gen_rtx_UMOD (SImode, operands[1], operands[2]);
equal = gen_rtx_IOR (DImode,
- gen_rtx_ZERO_EXTEND (DImode, div_equal),
gen_rtx_ASHIFT (DImode,
gen_rtx_ZERO_EXTEND (DImode, mod_equal),
- GEN_INT (32)));
+ GEN_INT (32)),
+ gen_rtx_ZERO_EXTEND (DImode, div_equal));
operands[4] = gen_reg_rtx(DImode);
emit_insn (gen_rtx_CLOBBER (VOIDmode, operands[4]));
@@ -4783,16 +4755,17 @@
(define_insn "udivmoddisi3"
[(set (match_operand:DI 0 "register_operand" "=d,d")
- (ior:DI (zero_extend:DI
- (truncate:SI
- (udiv:DI (match_operand:DI 1 "register_operand" "0,0")
- (zero_extend:DI
- (match_operand:SI 2 "nonimmediate_operand" "d,m")))))
- (ashift:DI
- (zero_extend:DI
- (truncate:SI
- (umod:DI (match_dup 1) (zero_extend:DI (match_dup 2)))))
- (const_int 32))))]
+ (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,m")))))
+ (const_int 32))
+ (zero_extend:DI
+ (truncate:SI
+ (udiv:DI (match_dup 1) (zero_extend:DI (match_dup 2)))))))]
"!TARGET_64BIT && TARGET_CPU_ZARCH"
"@
dlr\t%0,%2
@@ -4812,10 +4785,10 @@
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_ZERO_EXTEND (DImode, udiv_equal),
gen_rtx_ASHIFT (DImode,
gen_rtx_ZERO_EXTEND (DImode, umod_equal),
- GEN_INT (32)));
+ GEN_INT (32)),
+ gen_rtx_ZERO_EXTEND (DImode, udiv_equal));
operands[3] = gen_reg_rtx (DImode);
@@ -4864,7 +4837,7 @@
emit_move_insn (operands[0], const0_rtx);
emit_insn (gen_cmpsi (operands[2], operands[1]));
emit_jump_insn (gen_bgtu (label3));
- emit_insn (gen_cmpsi (operands[2], const1_rtx));
+ emit_insn (gen_cmpsi (operands[2], const0_rtx));
emit_jump_insn (gen_blt (label2));
emit_insn (gen_cmpsi (operands[2], const1_rtx));
emit_jump_insn (gen_beq (label1));
@@ -4903,10 +4876,10 @@
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_ZERO_EXTEND (DImode, udiv_equal),
gen_rtx_ASHIFT (DImode,
gen_rtx_ZERO_EXTEND (DImode, umod_equal),
- GEN_INT (32)));
+ GEN_INT (32)),
+ gen_rtx_ZERO_EXTEND (DImode, udiv_equal));
operands[3] = gen_reg_rtx (DImode);
@@ -4956,7 +4929,7 @@
emit_move_insn(operands[0], operands[1]);
emit_insn (gen_cmpsi (operands[2], operands[1]));
emit_jump_insn (gen_bgtu (label3));
- emit_insn (gen_cmpsi (operands[2], const1_rtx));
+ emit_insn (gen_cmpsi (operands[2], const0_rtx));
emit_jump_insn (gen_blt (label2));
emit_insn (gen_cmpsi (operands[2], const1_rtx));
emit_jump_insn (gen_beq (label1));
@@ -4983,82 +4956,59 @@
})
;
-; divdf3 instruction pattern(s).
+; div(df|sf)3 instruction pattern(s).
;
-(define_expand "divdf3"
- [(set (match_operand:DF 0 "register_operand" "=f,f")
- (div:DF (match_operand:DF 1 "register_operand" "0,0")
- (match_operand:DF 2 "general_operand" "f,R")))]
+(define_expand "div<mode>3"
+ [(set (match_operand:FPR 0 "register_operand" "=f,f")
+ (div:FPR (match_operand:FPR 1 "register_operand" "0,0")
+ (match_operand:FPR 2 "general_operand" "f,<Rf>")))]
"TARGET_HARD_FLOAT"
"")
-(define_insn "*divdf3"
- [(set (match_operand:DF 0 "register_operand" "=f,f")
- (div:DF (match_operand:DF 1 "register_operand" "0,0")
- (match_operand:DF 2 "general_operand" "f,R")))]
+; dxbr, ddbr, debr, dxb, ddb, deb
+(define_insn "*div<mode>3"
+ [(set (match_operand:FPR 0 "register_operand" "=f,f")
+ (div:FPR (match_operand:FPR 1 "register_operand" "0,0")
+ (match_operand:FPR 2 "general_operand" "f,<Rf>")))]
"TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
"@
- ddbr\t%0,%2
- ddb\t%0,%2"
+ d<xde>br\t%0,%2
+ d<xde>b\t%0,%2"
[(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fdivd")])
+ (set_attr "type" "fdiv<mode>")])
-(define_insn "*divdf3_ibm"
- [(set (match_operand:DF 0 "register_operand" "=f,f")
- (div:DF (match_operand:DF 1 "register_operand" "0,0")
- (match_operand:DF 2 "general_operand" "f,R")))]
+; dxr, ddr, der, dx, dd, de
+(define_insn "*div<mode>3_ibm"
+ [(set (match_operand:FPR 0 "register_operand" "=f,f")
+ (div:FPR (match_operand:FPR 1 "register_operand" "0,0")
+ (match_operand:FPR 2 "general_operand" "f,<Rf>")))]
"TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
"@
- ddr\t%0,%2
- dd\t%0,%2"
- [(set_attr "op_type" "RR,RX")
- (set_attr "type" "fdivd")])
-
-;
-; divsf3 instruction pattern(s).
-;
-
-(define_expand "divsf3"
- [(set (match_operand:SF 0 "register_operand" "=f,f")
- (div:SF (match_operand:SF 1 "register_operand" "0,0")
- (match_operand:SF 2 "general_operand" "f,R")))]
- "TARGET_HARD_FLOAT"
- "")
-
-(define_insn "*divsf3"
- [(set (match_operand:SF 0 "register_operand" "=f,f")
- (div:SF (match_operand:SF 1 "register_operand" "0,0")
- (match_operand:SF 2 "general_operand" "f,R")))]
- "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "@
- debr\t%0,%2
- deb\t%0,%2"
- [(set_attr "op_type" "RRE,RXE")
- (set_attr "type" "fdivs")])
-
-(define_insn "*divsf3"
- [(set (match_operand:SF 0 "register_operand" "=f,f")
- (div:SF (match_operand:SF 1 "register_operand" "0,0")
- (match_operand:SF 2 "general_operand" "f,R")))]
- "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
- "@
- der\t%0,%2
- de\t%0,%2"
- [(set_attr "op_type" "RR,RX")
- (set_attr "type" "fdivs")])
+ d<xde>r\t%0,%2
+ d<xde>\t%0,%2"
+ [(set_attr "op_type" "<RRe>,<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 33)
+ [(set (reg CC_REGNUM)
(compare (and:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
(match_operand:DI 2 "general_operand" "d,m"))
(const_int 0)))
@@ -5071,239 +5021,299 @@
[(set_attr "op_type" "RRE,RXY")])
(define_insn "*anddi3_cconly"
- [(set (reg 33)
+ [(set (reg CC_REGNUM)
(compare (and:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
(match_operand:DI 2 "general_operand" "d,m"))
(const_int 0)))
(clobber (match_scratch:DI 0 "=d,d"))]
- "s390_match_ccmode(insn, CCTmode) && TARGET_64BIT"
+ "s390_match_ccmode(insn, CCTmode) && TARGET_64BIT
+ /* Do not steal TM patterns. */
+ && s390_single_part (operands[2], DImode, HImode, 0) < 0"
"@
ngr\t%0,%2
ng\t%0,%2"
[(set_attr "op_type" "RRE,RXY")])
-(define_insn "anddi3"
- [(set (match_operand:DI 0 "register_operand" "=d,d,d,d,d,d,d,d")
- (and:DI (match_operand:DI 1 "nonimmediate_operand" "d,o,0,0,0,0,0,0")
- (match_operand:DI 2 "general_operand"
- "M,M,N0HDF,N1HDF,N2HDF,N3HDF,d,m")))
- (clobber (reg:CC 33))]
- "TARGET_64BIT"
- "@
- #
- #
- nihh\t%0,%j2
- nihl\t%0,%j2
- nilh\t%0,%j2
- nill\t%0,%j2
- ngr\t%0,%2
- ng\t%0,%2"
- [(set_attr "op_type" "RRE,RXE,RI,RI,RI,RI,RRE,RXY")])
-
-(define_insn "*anddi3_ss"
- [(set (match_operand:DI 0 "s_operand" "=Q")
- (and:DI (match_dup 0)
- (match_operand:DI 1 "s_imm_operand" "Q")))
- (clobber (reg:CC 33))]
- ""
- "nc\t%O0(8,%R0),%1"
- [(set_attr "op_type" "SS")])
-
-(define_insn "*anddi3_ss_inv"
- [(set (match_operand:DI 0 "s_operand" "=Q")
- (and:DI (match_operand:DI 1 "s_imm_operand" "Q")
- (match_dup 0)))
- (clobber (reg:CC 33))]
- ""
- "nc\t%O0(8,%R0),%1"
- [(set_attr "op_type" "SS")])
+(define_insn "*anddi3_extimm"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=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,0,0,0")
+ (match_operand:DI 2 "general_operand"
+ "M,M,N0HDF,N1HDF,N2HDF,N3HDF,N0SDF,N1SDF,d,m,NxQDF,Q")))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_64BIT && TARGET_EXTIMM && 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
+ ng\t%0,%2
+ #
+ #"
+ [(set_attr "op_type" "RRE,RXE,RI,RI,RI,RI,RIL,RIL,RRE,RXY,SI,SS")])
+
+(define_insn "*anddi3"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=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,0")
+ (match_operand:DI 2 "general_operand"
+ "M,M,N0HDF,N1HDF,N2HDF,N3HDF,d,m,NxQDF,Q")))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_64BIT && !TARGET_EXTIMM && s390_logical_operator_ok_p (operands)"
+ "@
+ #
+ #
+ nihh\t%0,%j2
+ nihl\t%0,%j2
+ nilh\t%0,%j2
+ nill\t%0,%j2
+ ngr\t%0,%2
+ ng\t%0,%2
+ #
+ #"
+ [(set_attr "op_type" "RRE,RXE,RI,RI,RI,RI,RRE,RXY,SI,SS")])
+
+(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 33)
- (compare (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0")
- (match_operand:SI 2 "general_operand" "d,R,T"))
+ [(set (reg CC_REGNUM)
+ (compare (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0,0")
+ (match_operand:SI 2 "general_operand" "Os,d,R,T"))
(const_int 0)))
- (set (match_operand:SI 0 "register_operand" "=d,d,d")
+ (set (match_operand:SI 0 "register_operand" "=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
n\t%0,%2
ny\t%0,%2"
- [(set_attr "op_type" "RR,RX,RXY")])
+ [(set_attr "op_type" "RIL,RR,RX,RXY")])
(define_insn "*andsi3_cconly"
- [(set (reg 33)
- (compare (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0")
- (match_operand:SI 2 "general_operand" "d,R,T"))
+ [(set (reg CC_REGNUM)
+ (compare (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0,0")
+ (match_operand:SI 2 "general_operand" "Os,d,R,T"))
(const_int 0)))
- (clobber (match_scratch:SI 0 "=d,d,d"))]
- "s390_match_ccmode(insn, CCTmode)"
+ (clobber (match_scratch:SI 0 "=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
n\t%0,%2
ny\t%0,%2"
- [(set_attr "op_type" "RR,RX,RXY")])
-
-(define_expand "andsi3"
- [(parallel
- [(set (match_operand:SI 0 "register_operand" "")
- (and:SI (match_operand:SI 1 "nonimmediate_operand" "")
- (match_operand:SI 2 "general_operand" "")))
- (clobber (reg:CC 33))])]
- ""
- "")
+ [(set_attr "op_type" "RIL,RR,RX,RXY")])
(define_insn "*andsi3_zarch"
- [(set (match_operand:SI 0 "register_operand" "=d,d,d,d,d,d,d")
- (and:SI (match_operand:SI 1 "nonimmediate_operand" "d,o,0,0,0,0,0")
- (match_operand:SI 2 "general_operand" "M,M,N0HSF,N1HSF,d,R,T")))
- (clobber (reg:CC 33))]
- "TARGET_ZARCH"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,d,d,AQ,Q")
+ (and:SI (match_operand:SI 1 "nonimmediate_operand"
+ "%d,o,0,0,0,0,0,0,0,0")
+ (match_operand:SI 2 "general_operand"
+ "M,M,N0HSF,N1HSF,Os,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
+ nill\t%0,%j2
+ nilf\t%0,%o2
nr\t%0,%2
n\t%0,%2
- ny\t%0,%2"
- [(set_attr "op_type" "RRE,RXE,RI,RI,RR,RX,RXY")])
+ ny\t%0,%2
+ #
+ #"
+ [(set_attr "op_type" "RRE,RXE,RI,RI,RIL,RR,RX,RXY,SI,SS")])
(define_insn "*andsi3_esa"
- [(set (match_operand:SI 0 "register_operand" "=d,d")
- (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
- (match_operand:SI 2 "general_operand" "d,R")))
- (clobber (reg:CC 33))]
- "!TARGET_ZARCH"
+ [(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")])
-
-(define_insn "*andsi3_ss"
- [(set (match_operand:SI 0 "s_operand" "=Q")
- (and:SI (match_dup 0)
- (match_operand:SI 1 "s_imm_operand" "Q")))
- (clobber (reg:CC 33))]
- ""
- "nc\t%O0(4,%R0),%1"
- [(set_attr "op_type" "SS")])
-
-(define_insn "*andsi3_ss_inv"
- [(set (match_operand:SI 0 "s_operand" "=Q")
- (and:SI (match_operand:SI 1 "s_imm_operand" "Q")
- (match_dup 0)))
- (clobber (reg:CC 33))]
- ""
- "nc\t%O0(4,%R0),%1"
- [(set_attr "op_type" "SS")])
+ n\t%0,%2
+ #
+ #"
+ [(set_attr "op_type" "RR,RX,SI,SS")])
+
+(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_ni"
- [(set (match_operand:HI 0 "register_operand" "=d,d")
- (and:HI (match_operand:HI 1 "register_operand" "%0,0")
- (match_operand:HI 2 "nonmemory_operand" "d,n")))
- (clobber (reg:CC 33))]
- "TARGET_ZARCH"
+(define_insn "*andhi3_zarch"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,AQ,Q")
+ (and:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,0,0")
+ (match_operand:HI 2 "general_operand" "d,n,NxQHF,Q")))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_ZARCH && s390_logical_operator_ok_p (operands)"
"@
nr\t%0,%2
- nill\t%0,%x2"
- [(set_attr "op_type" "RR,RI")])
+ nill\t%0,%x2
+ #
+ #"
+ [(set_attr "op_type" "RR,RI,SI,SS")])
-(define_insn "andhi3"
- [(set (match_operand:HI 0 "register_operand" "=d")
- (and:HI (match_operand:HI 1 "register_operand" "%0")
- (match_operand:HI 2 "nonmemory_operand" "d")))
- (clobber (reg:CC 33))]
- ""
- "nr\t%0,%2"
- [(set_attr "op_type" "RR")])
-
-(define_insn "*andhi3_ss"
- [(set (match_operand:HI 0 "s_operand" "=Q")
- (and:HI (match_dup 0)
- (match_operand:HI 1 "s_imm_operand" "Q")))
- (clobber (reg:CC 33))]
- ""
- "nc\t%O0(2,%R0),%1"
- [(set_attr "op_type" "SS")])
-
-(define_insn "*andhi3_ss_inv"
- [(set (match_operand:HI 0 "s_operand" "=Q")
- (and:HI (match_operand:HI 1 "s_imm_operand" "Q")
- (match_dup 0)))
- (clobber (reg:CC 33))]
- ""
- "nc\t%O0(2,%R0),%1"
- [(set_attr "op_type" "SS")])
+(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")])
+
+(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_ni"
- [(set (match_operand:QI 0 "register_operand" "=d,d")
- (and:QI (match_operand:QI 1 "register_operand" "%0,0")
- (match_operand:QI 2 "nonmemory_operand" "d,n")))
- (clobber (reg:CC 33))]
- "TARGET_ZARCH"
+(define_insn "*andqi3_zarch"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,Q,S,Q")
+ (and:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0,0,0")
+ (match_operand:QI 2 "general_operand" "d,n,n,n,Q")))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_ZARCH && s390_logical_operator_ok_p (operands)"
"@
nr\t%0,%2
- nill\t%0,%b2"
- [(set_attr "op_type" "RR,RI")])
-
-(define_insn "andqi3"
- [(set (match_operand:QI 0 "register_operand" "=d")
- (and:QI (match_operand:QI 1 "register_operand" "%0")
- (match_operand:QI 2 "nonmemory_operand" "d")))
- (clobber (reg:CC 33))]
- ""
- "nr\t%0,%2"
- [(set_attr "op_type" "RR")])
-
-(define_insn "*andqi3_ss"
- [(set (match_operand:QI 0 "s_operand" "=Q,S,Q")
- (and:QI (match_dup 0)
- (match_operand:QI 1 "s_imm_operand" "n,n,Q")))
- (clobber (reg:CC 33))]
- ""
+ nill\t%0,%b2
+ ni\t%S0,%b2
+ niy\t%S0,%b2
+ #"
+ [(set_attr "op_type" "RR,RI,SI,SIY,SS")])
+
+(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)"
"@
- ni\t%0,%b1
- niy\t%0,%b1
- nc\t%O0(1,%R0),%1"
- [(set_attr "op_type" "SI,SIY,SS")])
+ nr\t%0,%2
+ ni\t%S0,%b2
+ #"
+ [(set_attr "op_type" "RR,SI,SS")])
-(define_insn "*andqi3_ss_inv"
- [(set (match_operand:QI 0 "s_operand" "=Q,S,Q")
- (and:QI (match_operand:QI 1 "s_imm_operand" "n,n,Q")
- (match_dup 0)))
- (clobber (reg:CC 33))]
- ""
- "@
- ni\t%0,%b1
- niy\t%0,%b1
- nc\t%O0(1,%R0),%1"
- [(set_attr "op_type" "SI,SIY,SS")])
+;
+; 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")])
+
+(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 33)
+ [(set (reg CC_REGNUM)
(compare (ior:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
(match_operand:DI 2 "general_operand" "d,m"))
(const_int 0)))
@@ -5316,7 +5326,7 @@
[(set_attr "op_type" "RRE,RXY")])
(define_insn "*iordi3_cconly"
- [(set (reg 33)
+ [(set (reg CC_REGNUM)
(compare (ior:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
(match_operand:DI 2 "general_operand" "d,m"))
(const_int 0)))
@@ -5327,223 +5337,273 @@
og\t%0,%2"
[(set_attr "op_type" "RRE,RXY")])
-(define_insn "iordi3"
- [(set (match_operand:DI 0 "register_operand" "=d,d,d,d,d,d")
- (ior:DI (match_operand:DI 1 "nonimmediate_operand" "0,0,0,0,0,0")
- (match_operand:DI 2 "general_operand" "N0HD0,N1HD0,N2HD0,N3HD0,d,m")))
- (clobber (reg:CC 33))]
- "TARGET_64BIT"
+(define_insn "*iordi3_extimm"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=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,0,0,0")
+ (match_operand:DI 2 "general_operand"
+ "N0HD0,N1HD0,N2HD0,N3HD0,N0SD0,N1SD0,d,m,NxQD0,Q")))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_64BIT && TARGET_EXTIMM && 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
- og\t%0,%2"
- [(set_attr "op_type" "RI,RI,RI,RI,RRE,RXY")])
+ og\t%0,%2
+ #
+ #"
+ [(set_attr "op_type" "RI,RI,RI,RI,RIL,RIL,RRE,RXY,SI,SS")])
-(define_insn "*iordi3_ss"
- [(set (match_operand:DI 0 "s_operand" "=Q")
- (ior:DI (match_dup 0)
- (match_operand:DI 1 "s_imm_operand" "Q")))
- (clobber (reg:CC 33))]
- ""
- "oc\t%O0(8,%R0),%1"
- [(set_attr "op_type" "SS")])
-
-(define_insn "*iordi3_ss_inv"
- [(set (match_operand:DI 0 "s_operand" "=Q")
- (ior:DI (match_operand:DI 1 "s_imm_operand" "Q")
- (match_dup 0)))
- (clobber (reg:CC 33))]
- ""
- "oc\t%O0(8,%R0),%1"
- [(set_attr "op_type" "SS")])
+(define_insn "*iordi3"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,d,AQ,Q")
+ (ior:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0,0,0,0,0,0,0")
+ (match_operand:DI 2 "general_operand"
+ "N0HD0,N1HD0,N2HD0,N3HD0,d,m,NxQD0,Q")))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_64BIT && !TARGET_EXTIMM && s390_logical_operator_ok_p (operands)"
+ "@
+ oihh\t%0,%i2
+ oihl\t%0,%i2
+ oilh\t%0,%i2
+ oill\t%0,%i2
+ ogr\t%0,%2
+ og\t%0,%2
+ #
+ #"
+ [(set_attr "op_type" "RI,RI,RI,RI,RRE,RXY,SI,SS")])
+
+(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 33)
- (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0")
- (match_operand:SI 2 "general_operand" "d,R,T"))
+ [(set (reg CC_REGNUM)
+ (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0,0")
+ (match_operand:SI 2 "general_operand" "Os,d,R,T"))
(const_int 0)))
- (set (match_operand:SI 0 "register_operand" "=d,d,d")
+ (set (match_operand:SI 0 "register_operand" "=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
o\t%0,%2
oy\t%0,%2"
- [(set_attr "op_type" "RR,RX,RXY")])
+ [(set_attr "op_type" "RIL,RR,RX,RXY")])
(define_insn "*iorsi3_cconly"
- [(set (reg 33)
- (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0")
- (match_operand:SI 2 "general_operand" "d,R,T"))
+ [(set (reg CC_REGNUM)
+ (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0,0")
+ (match_operand:SI 2 "general_operand" "Os,d,R,T"))
(const_int 0)))
- (clobber (match_scratch:SI 0 "=d,d,d"))]
+ (clobber (match_scratch:SI 0 "=d,d,d,d"))]
"s390_match_ccmode(insn, CCTmode)"
"@
+ oilf\t%0,%o2
or\t%0,%2
o\t%0,%2
oy\t%0,%2"
- [(set_attr "op_type" "RR,RX,RXY")])
+ [(set_attr "op_type" "RIL,RR,RX,RXY")])
-(define_expand "iorsi3"
- [(parallel
- [(set (match_operand:SI 0 "register_operand" "")
- (ior:SI (match_operand:SI 1 "nonimmediate_operand" "")
- (match_operand:SI 2 "general_operand" "")))
- (clobber (reg:CC 33))])]
- ""
- "")
-
-(define_insn "iorsi3_zarch"
- [(set (match_operand:SI 0 "register_operand" "=d,d,d,d,d")
- (ior:SI (match_operand:SI 1 "nonimmediate_operand" "0,0,0,0,0")
- (match_operand:SI 2 "general_operand" "N0HS0,N1HS0,d,R,T")))
- (clobber (reg:CC 33))]
- "TARGET_ZARCH"
+(define_insn "*iorsi3_zarch"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,AQ,Q")
+ (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0,0,0,0,0,0")
+ (match_operand:SI 2 "general_operand" "N0HS0,N1HS0,Os,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
o\t%0,%2
- oy\t%0,%2"
- [(set_attr "op_type" "RI,RI,RR,RX,RXY")])
+ oy\t%0,%2
+ #
+ #"
+ [(set_attr "op_type" "RI,RI,RIL,RR,RX,RXY,SI,SS")])
-(define_insn "iorsi3_esa"
- [(set (match_operand:SI 0 "register_operand" "=d,d")
- (ior:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
- (match_operand:SI 2 "general_operand" "d,R")))
- (clobber (reg:CC 33))]
- "!TARGET_ZARCH"
+(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")])
-
-(define_insn "*iorsi3_ss"
- [(set (match_operand:SI 0 "s_operand" "=Q")
- (ior:SI (match_dup 0)
- (match_operand:SI 1 "s_imm_operand" "Q")))
- (clobber (reg:CC 33))]
- ""
- "oc\t%O0(4,%R0),%1"
- [(set_attr "op_type" "SS")])
-
-(define_insn "*iorsi3_ss_inv"
- [(set (match_operand:SI 0 "s_operand" "=Q")
- (ior:SI (match_operand:SI 1 "s_imm_operand" "Q")
- (match_dup 0)))
- (clobber (reg:CC 33))]
- ""
- "oc\t%O0(4,%R0),%1"
- [(set_attr "op_type" "SS")])
+ o\t%0,%2
+ #
+ #"
+ [(set_attr "op_type" "RR,RX,SI,SS")])
+
+(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_oi"
- [(set (match_operand:HI 0 "register_operand" "=d,d")
- (ior:HI (match_operand:HI 1 "register_operand" "%0,0")
- (match_operand:HI 2 "nonmemory_operand" "d,n")))
- (clobber (reg:CC 33))]
- "TARGET_ZARCH"
+(define_insn "*iorhi3_zarch"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,AQ,Q")
+ (ior:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,0,0")
+ (match_operand:HI 2 "general_operand" "d,n,NxQH0,Q")))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_ZARCH && s390_logical_operator_ok_p (operands)"
"@
or\t%0,%2
- oill\t%0,%x2"
- [(set_attr "op_type" "RR,RI")])
+ oill\t%0,%x2
+ #
+ #"
+ [(set_attr "op_type" "RR,RI,SI,SS")])
-(define_insn "iorhi3"
- [(set (match_operand:HI 0 "register_operand" "=d")
- (ior:HI (match_operand:HI 1 "register_operand" "%0")
- (match_operand:HI 2 "nonmemory_operand" "d")))
- (clobber (reg:CC 33))]
- ""
- "or\t%0,%2"
- [(set_attr "op_type" "RR")])
-
-(define_insn "*iorhi3_ss"
- [(set (match_operand:HI 0 "s_operand" "=Q")
- (ior:HI (match_dup 0)
- (match_operand:HI 1 "s_imm_operand" "Q")))
- (clobber (reg:CC 33))]
- ""
- "oc\t%O0(2,%R0),%1"
- [(set_attr "op_type" "SS")])
-
-(define_insn "*iorhi3_ss_inv"
- [(set (match_operand:HI 0 "s_operand" "=Q")
- (ior:HI (match_operand:HI 1 "s_imm_operand" "Q")
- (match_dup 0)))
- (clobber (reg:CC 33))]
- ""
- "oc\t%O0(2,%R0),%1"
- [(set_attr "op_type" "SS")])
+(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")])
+
+(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_oi"
- [(set (match_operand:QI 0 "register_operand" "=d,d")
- (ior:QI (match_operand:QI 1 "register_operand" "%0,0")
- (match_operand:QI 2 "nonmemory_operand" "d,n")))
- (clobber (reg:CC 33))]
- "TARGET_ZARCH"
+(define_insn "*iorqi3_zarch"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,Q,S,Q")
+ (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0,0,0")
+ (match_operand:QI 2 "general_operand" "d,n,n,n,Q")))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_ZARCH && s390_logical_operator_ok_p (operands)"
"@
or\t%0,%2
- oill\t%0,%b2"
- [(set_attr "op_type" "RR,RI")])
-
-(define_insn "iorqi3"
- [(set (match_operand:QI 0 "register_operand" "=d")
- (ior:QI (match_operand:QI 1 "register_operand" "%0")
- (match_operand:QI 2 "nonmemory_operand" "d")))
- (clobber (reg:CC 33))]
- ""
- "or\t%0,%2"
- [(set_attr "op_type" "RR")])
-
-(define_insn "*iorqi3_ss"
- [(set (match_operand:QI 0 "s_operand" "=Q,S,Q")
- (ior:QI (match_dup 0)
- (match_operand:QI 1 "s_imm_operand" "n,n,Q")))
- (clobber (reg:CC 33))]
- ""
+ oill\t%0,%b2
+ oi\t%S0,%b2
+ oiy\t%S0,%b2
+ #"
+ [(set_attr "op_type" "RR,RI,SI,SIY,SS")])
+
+(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)"
"@
- oi\t%0,%b1
- oiy\t%0,%b1
- oc\t%O0(1,%R0),%1"
- [(set_attr "op_type" "SI,SIY,SS")])
+ or\t%0,%2
+ oi\t%S0,%b2
+ #"
+ [(set_attr "op_type" "RR,SI,SS")])
-(define_insn "*iorqi3_ss_inv"
- [(set (match_operand:QI 0 "s_operand" "=Q,S,Q")
- (ior:QI (match_operand:QI 1 "s_imm_operand" "n,n,Q")
- (match_dup 0)))
- (clobber (reg:CC 33))]
- ""
- "@
- oi\t%0,%b1
- oiy\t%0,%b1
- oc\t%O0(1,%R0),%1"
- [(set_attr "op_type" "SI,SIY,SS")])
+;
+; 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")])
+
+(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 33)
+ [(set (reg CC_REGNUM)
(compare (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
(match_operand:DI 2 "general_operand" "d,m"))
(const_int 0)))
@@ -5556,7 +5616,7 @@
[(set_attr "op_type" "RRE,RXY")])
(define_insn "*xordi3_cconly"
- [(set (reg 33)
+ [(set (reg CC_REGNUM)
(compare (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
(match_operand:DI 2 "general_operand" "d,m"))
(const_int 0)))
@@ -5567,163 +5627,237 @@
xr\t%0,%2"
[(set_attr "op_type" "RRE,RXY")])
-(define_insn "xordi3"
- [(set (match_operand:DI 0 "register_operand" "=d,d")
- (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
- (match_operand:DI 2 "general_operand" "d,m")))
- (clobber (reg:CC 33))]
- "TARGET_64BIT"
+(define_insn "*xordi3_extimm"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,AQ,Q")
+ (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0,0,0,0,0")
+ (match_operand:DI 2 "general_operand" "N0SD0,N1SD0,d,m,NxQD0,Q")))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_64BIT && TARGET_EXTIMM && s390_logical_operator_ok_p (operands)"
"@
+ xihf\t%0,%k2
+ xilf\t%0,%k2
xgr\t%0,%2
- xg\t%0,%2"
- [(set_attr "op_type" "RRE,RXY")])
+ xg\t%0,%2
+ #
+ #"
+ [(set_attr "op_type" "RIL,RIL,RRE,RXY,SI,SS")])
-(define_insn "*xordi3_ss"
- [(set (match_operand:DI 0 "s_operand" "=Q")
- (xor:DI (match_dup 0)
- (match_operand:DI 1 "s_imm_operand" "Q")))
- (clobber (reg:CC 33))]
- ""
- "xc\t%O0(8,%R0),%1"
- [(set_attr "op_type" "SS")])
-
-(define_insn "*xordi3_ss_inv"
- [(set (match_operand:DI 0 "s_operand" "=Q")
- (xor:DI (match_operand:DI 1 "s_imm_operand" "Q")
- (match_dup 0)))
- (clobber (reg:CC 33))]
- ""
- "xc\t%O0(8,%R0),%1"
- [(set_attr "op_type" "SS")])
+(define_insn "*xordi3"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,AQ,Q")
+ (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0,0,0")
+ (match_operand:DI 2 "general_operand" "d,m,NxQD0,Q")))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_64BIT && !TARGET_EXTIMM && s390_logical_operator_ok_p (operands)"
+ "@
+ xgr\t%0,%2
+ xg\t%0,%2
+ #
+ #"
+ [(set_attr "op_type" "RRE,RXY,SI,SS")])
+
+(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 33)
- (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0")
- (match_operand:SI 2 "general_operand" "d,R,T"))
+ [(set (reg CC_REGNUM)
+ (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0,0")
+ (match_operand:SI 2 "general_operand" "Os,d,R,T"))
(const_int 0)))
- (set (match_operand:SI 0 "register_operand" "=d,d,d")
+ (set (match_operand:SI 0 "register_operand" "=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
x\t%0,%2
xy\t%0,%2"
- [(set_attr "op_type" "RR,RX,RXY")])
+ [(set_attr "op_type" "RIL,RR,RX,RXY")])
(define_insn "*xorsi3_cconly"
- [(set (reg 33)
- (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0")
- (match_operand:SI 2 "general_operand" "d,R,T"))
+ [(set (reg CC_REGNUM)
+ (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0,0")
+ (match_operand:SI 2 "general_operand" "Os,d,R,T"))
(const_int 0)))
- (clobber (match_scratch:SI 0 "=d,d,d"))]
+ (clobber (match_scratch:SI 0 "=d,d,d,d"))]
"s390_match_ccmode(insn, CCTmode)"
"@
+ xilf\t%0,%o2
xr\t%0,%2
x\t%0,%2
xy\t%0,%2"
- [(set_attr "op_type" "RR,RX,RXY")])
+ [(set_attr "op_type" "RIL,RR,RX,RXY")])
-(define_insn "xorsi3"
- [(set (match_operand:SI 0 "register_operand" "=d,d,d")
- (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0")
- (match_operand:SI 2 "general_operand" "d,R,T")))
- (clobber (reg:CC 33))]
- ""
+(define_insn "*xorsi3"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,AQ,Q")
+ (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0,0,0,0")
+ (match_operand:SI 2 "general_operand" "Os,d,R,T,NxQS0,Q")))
+ (clobber (reg:CC CC_REGNUM))]
+ "s390_logical_operator_ok_p (operands)"
"@
+ xilf\t%0,%o2
xr\t%0,%2
x\t%0,%2
- xy\t%0,%2"
- [(set_attr "op_type" "RR,RX,RXY")])
+ xy\t%0,%2
+ #
+ #"
+ [(set_attr "op_type" "RIL,RR,RX,RXY,SI,SS")])
-(define_insn "*xorsi3_ss"
- [(set (match_operand:SI 0 "s_operand" "=Q")
- (xor:SI (match_dup 0)
- (match_operand:SI 1 "s_imm_operand" "Q")))
- (clobber (reg:CC 33))]
- ""
- "xc\t%O0(4,%R0),%1"
- [(set_attr "op_type" "SS")])
-
-(define_insn "*xorsi3_ss_inv"
- [(set (match_operand:SI 0 "s_operand" "=Q")
- (xor:SI (match_operand:SI 1 "s_imm_operand" "Q")
- (match_dup 0)))
- (clobber (reg:CC 33))]
- ""
- "xc\t%O0(4,%R0),%1"
- [(set_attr "op_type" "SS")])
+(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 "register_operand" "=d")
- (xor:HI (match_operand:HI 1 "register_operand" "%0")
- (match_operand:HI 2 "nonmemory_operand" "d")))
- (clobber (reg:CC 33))]
- ""
- "xr\t%0,%2"
- [(set_attr "op_type" "RR")])
-
-(define_insn "*xorhi3_ss"
- [(set (match_operand:HI 0 "s_operand" "=Q")
- (xor:HI (match_dup 0)
- (match_operand:HI 1 "s_imm_operand" "Q")))
- (clobber (reg:CC 33))]
- ""
- "xc\t%O0(2,%R0),%1"
- [(set_attr "op_type" "SS")])
-
-(define_insn "*xorhi3_ss_inv"
- [(set (match_operand:HI 0 "s_operand" "=Q")
- (xor:HI (match_operand:HI 1 "s_imm_operand" "Q")
- (match_dup 0)))
- (clobber (reg:CC 33))]
- ""
- "xc\t%O0(2,%R0),%1"
- [(set_attr "op_type" "SS")])
+(define_insn "*xorhi3"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,AQ,Q")
+ (xor:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,0,0")
+ (match_operand:HI 2 "general_operand" "Os,d,NxQH0,Q")))
+ (clobber (reg:CC CC_REGNUM))]
+ "s390_logical_operator_ok_p (operands)"
+ "@
+ xilf\t%0,%x2
+ xr\t%0,%2
+ #
+ #"
+ [(set_attr "op_type" "RIL,RR,SI,SS")])
+
+(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 "register_operand" "=d")
- (xor:QI (match_operand:QI 1 "register_operand" "%0")
- (match_operand:QI 2 "nonmemory_operand" "d")))
- (clobber (reg:CC 33))]
- ""
- "xr\t%0,%2"
- [(set_attr "op_type" "RR")])
-
-(define_insn "*xorqi3_ss"
- [(set (match_operand:QI 0 "s_operand" "=Q,S,Q")
- (xor:QI (match_dup 0)
- (match_operand:QI 1 "s_imm_operand" "n,n,Q")))
- (clobber (reg:CC 33))]
- ""
+(define_insn "*xorqi3"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,Q,S,Q")
+ (xor:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0,0,0")
+ (match_operand:QI 2 "general_operand" "Os,d,n,n,Q")))
+ (clobber (reg:CC CC_REGNUM))]
+ "s390_logical_operator_ok_p (operands)"
"@
- xi\t%0,%b1
- xiy\t%0,%b1
- xc\t%O0(1,%R0),%1"
- [(set_attr "op_type" "SI,SIY,SS")])
+ xilf\t%0,%b2
+ xr\t%0,%2
+ xi\t%S0,%b2
+ xiy\t%S0,%b2
+ #"
+ [(set_attr "op_type" "RIL,RR,SI,SIY,SS")])
-(define_insn "*xorqi3_ss_inv"
- [(set (match_operand:QI 0 "s_operand" "=Q,S,Q")
- (xor:QI (match_operand:QI 1 "s_imm_operand" "n,n,Q")
- (match_dup 0)))
- (clobber (reg:CC 33))]
- ""
- "@
- xi\t%0,%b1
- xiy\t%0,%b1
- xc\t%O0(1,%R0),%1"
- [(set_attr "op_type" "SI,SIY,SS")])
+;
+; 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")])
+
+(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]));")
;;
@@ -5731,116 +5865,149 @@
;;
;
-; negdi2 instruction pattern(s).
+; neg(di|si)2 instruction pattern(s).
;
-(define_expand "negdi2"
+(define_expand "neg<mode>2"
[(parallel
- [(set (match_operand:DI 0 "register_operand" "=d")
- (neg:DI (match_operand:DI 1 "register_operand" "d")))
- (clobber (reg:CC 33))])]
+ [(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_64"
+(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_64BIT && s390_match_ccmode (insn, CCAmode)"
+ "lcgfr\t%0,%1"
+ [(set_attr "op_type" "RRE")])
+
+(define_insn "*negdi2_sign"
[(set (match_operand:DI 0 "register_operand" "=d")
- (neg:DI (match_operand:DI 1 "register_operand" "d")))
- (clobber (reg:CC 33))]
+ (neg:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d"))))
+ (clobber (reg:CC CC_REGNUM))]
"TARGET_64BIT"
- "lcgr\t%0,%1"
- [(set_attr "op_type" "RR")])
+ "lcgfr\t%0,%1"
+ [(set_attr "op_type" "RRE")])
-(define_insn "*negdi2_31"
+; 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>")])
+
+; 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>")])
+
+; 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>")])
+
+(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 33))]
+ (clobber (reg:CC CC_REGNUM))]
"!TARGET_64BIT"
-{
- rtx xop[1];
- xop[0] = gen_label_rtx ();
- output_asm_insn ("lcr\t%0,%1", operands);
- output_asm_insn ("lcr\t%N0,%N1", operands);
- output_asm_insn ("je\t%l0", xop);
- output_asm_insn ("bctr\t%0,0", operands);
- targetm.asm_out.internal_label (asm_out_file, "L",
- CODE_LABEL_NUMBER (xop[0]));
- return "";
-}
- [(set_attr "op_type" "NN")
- (set_attr "type" "other")
- (set_attr "length" "10")])
-
-;
-; negsi2 instruction pattern(s).
-;
-
-(define_insn "negsi2"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (neg:SI (match_operand:SI 1 "register_operand" "d")))
- (clobber (reg:CC 33))]
- ""
- "lcr\t%0,%1"
- [(set_attr "op_type" "RR")])
+ "#"
+ "&& 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 ();")
;
-; negdf2 instruction pattern(s).
+; neg(df|sf)2 instruction pattern(s).
;
-(define_expand "negdf2"
+(define_expand "neg<mode>2"
[(parallel
- [(set (match_operand:DF 0 "register_operand" "=f")
- (neg:DF (match_operand:DF 1 "register_operand" "f")))
- (clobber (reg:CC 33))])]
+ [(set (match_operand:FPR 0 "register_operand" "=f")
+ (neg:FPR (match_operand:FPR 1 "register_operand" "f")))
+ (clobber (reg:CC CC_REGNUM))])]
"TARGET_HARD_FLOAT"
"")
-(define_insn "*negdf2"
- [(set (match_operand:DF 0 "register_operand" "=f")
- (neg:DF (match_operand:DF 1 "register_operand" "f")))
- (clobber (reg:CC 33))]
- "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "lcdbr\t%0,%1"
+; lcxbr, lcdbr, lcebr
+(define_insn "*neg<mode>2_cc"
+ [(set (reg CC_REGNUM)
+ (compare (neg:FPR (match_operand:FPR 1 "register_operand" "f"))
+ (match_operand:FPR 2 "const0_operand" "")))
+ (set (match_operand:FPR 0 "register_operand" "=f")
+ (neg:FPR (match_dup 1)))]
+ "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
+ "lc<xde>br\t%0,%1"
[(set_attr "op_type" "RRE")
- (set_attr "type" "fsimpd")])
-
-(define_insn "*negdf2_ibm"
- [(set (match_operand:DF 0 "register_operand" "=f")
- (neg:DF (match_operand:DF 1 "register_operand" "f")))
- (clobber (reg:CC 33))]
- "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
- "lcdr\t%0,%1"
- [(set_attr "op_type" "RR")
- (set_attr "type" "fsimpd")])
-
-;
-; negsf2 instruction pattern(s).
-;
-
-(define_expand "negsf2"
- [(parallel
- [(set (match_operand:SF 0 "register_operand" "=f")
- (neg:SF (match_operand:SF 1 "register_operand" "f")))
- (clobber (reg:CC 33))])]
- "TARGET_HARD_FLOAT"
- "")
+ (set_attr "type" "fsimp<mode>")])
+
+; lcxbr, lcdbr, lcebr
+(define_insn "*neg<mode>2_cconly"
+ [(set (reg CC_REGNUM)
+ (compare (neg:FPR (match_operand:FPR 1 "register_operand" "f"))
+ (match_operand:FPR 2 "const0_operand" "")))
+ (clobber (match_scratch:FPR 0 "=f"))]
+ "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
+ "lc<xde>br\t%0,%1"
+ [(set_attr "op_type" "RRE")
+ (set_attr "type" "fsimp<mode>")])
-(define_insn "*negsf2"
- [(set (match_operand:SF 0 "register_operand" "=f")
- (neg:SF (match_operand:SF 1 "register_operand" "f")))
- (clobber (reg:CC 33))]
+; lcxbr, lcdbr, lcebr
+(define_insn "*neg<mode>2"
+ [(set (match_operand:FPR 0 "register_operand" "=f")
+ (neg:FPR (match_operand:FPR 1 "register_operand" "f")))
+ (clobber (reg:CC CC_REGNUM))]
"TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "lcebr\t%0,%1"
+ "lc<xde>br\t%0,%1"
[(set_attr "op_type" "RRE")
- (set_attr "type" "fsimps")])
+ (set_attr "type" "fsimp<mode>")])
-(define_insn "*negsf2"
- [(set (match_operand:SF 0 "register_operand" "=f")
- (neg:SF (match_operand:SF 1 "register_operand" "f")))
- (clobber (reg:CC 33))]
+; lcxr, lcdr, lcer
+(define_insn "*neg<mode>2_ibm"
+ [(set (match_operand:FPR 0 "register_operand" "=f")
+ (neg:FPR (match_operand:FPR 1 "register_operand" "f")))
+ (clobber (reg:CC CC_REGNUM))]
"TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
- "lcer\t%0,%1"
- [(set_attr "op_type" "RR")
- (set_attr "type" "fsimps")])
+ "lc<xde>r\t%0,%1"
+ [(set_attr "op_type" "<RRe>")
+ (set_attr "type" "fsimp<mode>")])
;;
@@ -5848,88 +6015,113 @@
;;
;
-; absdi2 instruction pattern(s).
+; abs(di|si)2 instruction pattern(s).
;
-(define_insn "absdi2"
+(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_64BIT && s390_match_ccmode (insn, CCAmode)"
+ "lpgfr\t%0,%1"
+ [(set_attr "op_type" "RRE")])
+
+(define_insn "*absdi2_sign"
[(set (match_operand:DI 0 "register_operand" "=d")
- (abs:DI (match_operand:DI 1 "register_operand" "d")))
- (clobber (reg:CC 33))]
+ (abs:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d"))))
+ (clobber (reg:CC CC_REGNUM))]
"TARGET_64BIT"
- "lpgr\t%0,%1"
+ "lpgfr\t%0,%1"
[(set_attr "op_type" "RRE")])
-;
-; abssi2 instruction pattern(s).
-;
+; 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>")])
+
+; 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>")])
-(define_insn "abssi2"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (abs:SI (match_operand:SI 1 "register_operand" "d")))
- (clobber (reg:CC 33))]
+; 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))]
""
- "lpr\t%0,%1"
- [(set_attr "op_type" "RR")])
+ "lp<g>r\t%0,%1"
+ [(set_attr "op_type" "RR<E>")])
;
-; absdf2 instruction pattern(s).
+; abs(df|sf)2 instruction pattern(s).
;
-(define_expand "absdf2"
+(define_expand "abs<mode>2"
[(parallel
- [(set (match_operand:DF 0 "register_operand" "=f")
- (abs:DF (match_operand:DF 1 "register_operand" "f")))
- (clobber (reg:CC 33))])]
+ [(set (match_operand:FPR 0 "register_operand" "=f")
+ (abs:FPR (match_operand:FPR 1 "register_operand" "f")))
+ (clobber (reg:CC CC_REGNUM))])]
"TARGET_HARD_FLOAT"
"")
-(define_insn "*absdf2"
- [(set (match_operand:DF 0 "register_operand" "=f")
- (abs:DF (match_operand:DF 1 "register_operand" "f")))
- (clobber (reg:CC 33))]
- "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "lpdbr\t%0,%1"
+; lpxbr, lpdbr, lpebr
+(define_insn "*abs<mode>2_cc"
+ [(set (reg CC_REGNUM)
+ (compare (abs:FPR (match_operand:FPR 1 "register_operand" "f"))
+ (match_operand:FPR 2 "const0_operand" "")))
+ (set (match_operand:FPR 0 "register_operand" "=f")
+ (abs:FPR (match_dup 1)))]
+ "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
+ "lp<xde>br\t%0,%1"
[(set_attr "op_type" "RRE")
- (set_attr "type" "fsimpd")])
-
-(define_insn "*absdf2_ibm"
- [(set (match_operand:DF 0 "register_operand" "=f")
- (abs:DF (match_operand:DF 1 "register_operand" "f")))
- (clobber (reg:CC 33))]
- "TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
- "lpdr\t%0,%1"
- [(set_attr "op_type" "RR")
- (set_attr "type" "fsimpd")])
-
-;
-; abssf2 instruction pattern(s).
-;
-
-(define_expand "abssf2"
- [(parallel
- [(set (match_operand:SF 0 "register_operand" "=f")
- (abs:SF (match_operand:SF 1 "register_operand" "f")))
- (clobber (reg:CC 33))])]
- "TARGET_HARD_FLOAT"
- "")
+ (set_attr "type" "fsimp<mode>")])
+
+; lpxbr, lpdbr, lpebr
+(define_insn "*abs<mode>2_cconly"
+ [(set (reg CC_REGNUM)
+ (compare (abs:FPR (match_operand:FPR 1 "register_operand" "f"))
+ (match_operand:FPR 2 "const0_operand" "")))
+ (clobber (match_scratch:FPR 0 "=f"))]
+ "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
+ "lp<xde>br\t%0,%1"
+ [(set_attr "op_type" "RRE")
+ (set_attr "type" "fsimp<mode>")])
-(define_insn "*abssf2"
- [(set (match_operand:SF 0 "register_operand" "=f")
- (abs:SF (match_operand:SF 1 "register_operand" "f")))
- (clobber (reg:CC 33))]
+; lpxbr, lpdbr, lpebr
+(define_insn "*abs<mode>2"
+ [(set (match_operand:FPR 0 "register_operand" "=f")
+ (abs:FPR (match_operand:FPR 1 "register_operand" "f")))
+ (clobber (reg:CC CC_REGNUM))]
"TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "lpebr\t%0,%1"
+ "lp<xde>br\t%0,%1"
[(set_attr "op_type" "RRE")
- (set_attr "type" "fsimps")])
+ (set_attr "type" "fsimp<mode>")])
-(define_insn "*abssf2_ibm"
- [(set (match_operand:SF 0 "register_operand" "=f")
- (abs:SF (match_operand:SF 1 "register_operand" "f")))
- (clobber (reg:CC 33))]
+; lpxr, lpdr, lper
+(define_insn "*abs<mode>2_ibm"
+ [(set (match_operand:FPR 0 "register_operand" "=f")
+ (abs:FPR (match_operand:FPR 1 "register_operand" "f")))
+ (clobber (reg:CC CC_REGNUM))]
"TARGET_HARD_FLOAT && TARGET_IBM_FLOAT"
- "lper\t%0,%1"
- [(set_attr "op_type" "RR")
- (set_attr "type" "fsimps")])
+ "lp<xde>r\t%0,%1"
+ [(set_attr "op_type" "<RRe>")
+ (set_attr "type" "fsimp<mode>")])
;;
;;- Negated absolute value instructions
@@ -5939,129 +6131,173 @@
; Integer
;
-(define_insn "*negabssi2"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (neg:SI (abs:SI (match_operand:SI 1 "register_operand" "d"))))
- (clobber (reg:CC 33))]
- ""
- "lnr\t%0,%1"
- [(set_attr "op_type" "RR")])
-
-(define_insn "*negabsdi2"
+(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_64BIT && s390_match_ccmode (insn, CCAmode)"
+ "lngfr\t%0,%1"
+ [(set_attr "op_type" "RRE")])
+
+(define_insn "*negabsdi2_sign"
[(set (match_operand:DI 0 "register_operand" "=d")
- (neg:DI (abs:DI (match_operand:DI 1 "register_operand" "d"))))
- (clobber (reg:CC 33))]
+ (neg:DI (abs:DI (sign_extend:DI
+ (match_operand:SI 1 "register_operand" "d")))))
+ (clobber (reg:CC CC_REGNUM))]
"TARGET_64BIT"
- "lngr\t%0,%1"
+ "lngfr\t%0,%1"
[(set_attr "op_type" "RRE")])
+; 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>")])
+
+; 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>")])
+
+; 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>")])
+
;
; Floating point
;
-(define_insn "*negabssf2"
- [(set (match_operand:SF 0 "register_operand" "=f")
- (neg:SF (abs:SF (match_operand:SF 1 "register_operand" "f"))))
- (clobber (reg:CC 33))]
- "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "lnebr\t%0,%1"
+; lnxbr, lndbr, lnebr
+(define_insn "*negabs<mode>2_cc"
+ [(set (reg CC_REGNUM)
+ (compare (neg:FPR (abs:FPR (match_operand:FPR 1 "register_operand" "f")))
+ (match_operand:FPR 2 "const0_operand" "")))
+ (set (match_operand:FPR 0 "register_operand" "=f")
+ (neg:FPR (abs:FPR (match_dup 1))))]
+ "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_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:FPR (abs:FPR (match_operand:FPR 1 "register_operand" "f")))
+ (match_operand:FPR 2 "const0_operand" "")))
+ (clobber (match_scratch:FPR 0 "=f"))]
+ "s390_match_ccmode (insn, CCSmode) && TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
+ "ln<xde>br\t%0,%1"
[(set_attr "op_type" "RRE")
- (set_attr "type" "fsimps")])
+ (set_attr "type" "fsimp<mode>")])
-(define_insn "*negabsdf2"
- [(set (match_operand:DF 0 "register_operand" "=f")
- (neg:DF (abs:DF (match_operand:DF 1 "register_operand" "f"))))
- (clobber (reg:CC 33))]
+; lnxbr, lndbr, lnebr
+(define_insn "*negabs<mode>2"
+ [(set (match_operand:FPR 0 "register_operand" "=f")
+ (neg:FPR (abs:FPR (match_operand:FPR 1 "register_operand" "f"))))
+ (clobber (reg:CC CC_REGNUM))]
"TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "lndbr\t%0,%1"
+ "ln<xde>br\t%0,%1"
[(set_attr "op_type" "RRE")
- (set_attr "type" "fsimpd")])
+ (set_attr "type" "fsimp<mode>")])
;;
;;- Square root instructions.
;;
;
-; sqrtdf2 instruction pattern(s).
+; sqrt(df|sf)2 instruction pattern(s).
;
-(define_insn "sqrtdf2"
- [(set (match_operand:DF 0 "register_operand" "=f,f")
- (sqrt:DF (match_operand:DF 1 "general_operand" "f,R")))]
+; sqxbr, sqdbr, sqebr, sqxb, sqdb, sqeb
+(define_insn "sqrt<mode>2"
+ [(set (match_operand:FPR 0 "register_operand" "=f,f")
+ (sqrt:FPR (match_operand:FPR 1 "general_operand" "f,<Rf>")))]
"TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
"@
- sqdbr\t%0,%1
- sqdb\t%0,%1"
- [(set_attr "op_type" "RRE,RXE")])
-
-;
-; sqrtsf2 instruction pattern(s).
-;
+ sq<xde>br\t%0,%1
+ sq<xde>b\t%0,%1"
+ [(set_attr "op_type" "RRE,RXE")
+ (set_attr "type" "fsqrt<mode>")])
-(define_insn "sqrtsf2"
- [(set (match_operand:SF 0 "register_operand" "=f,f")
- (sqrt:SF (match_operand:SF 1 "general_operand" "f,R")))]
- "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
- "@
- sqebr\t%0,%1
- sqeb\t%0,%1"
- [(set_attr "op_type" "RRE,RXE")])
;;
;;- One complement instructions.
;;
;
-; one_cmpldi2 instruction pattern(s).
+; one_cmpl(di|si|hi|qi)2 instruction pattern(s).
;
-(define_expand "one_cmpldi2"
+(define_expand "one_cmpl<mode>2"
[(parallel
- [(set (match_operand:DI 0 "register_operand" "")
- (xor:DI (match_operand:DI 1 "register_operand" "")
- (const_int -1)))
- (clobber (reg:CC 33))])]
- "TARGET_64BIT"
+ [(set (match_operand:INT 0 "register_operand" "")
+ (xor:INT (match_operand:INT 1 "register_operand" "")
+ (const_int -1)))
+ (clobber (reg:CC CC_REGNUM))])]
+ ""
"")
-;
-; one_cmplsi2 instruction pattern(s).
-;
-(define_expand "one_cmplsi2"
- [(parallel
- [(set (match_operand:SI 0 "register_operand" "")
- (xor:SI (match_operand:SI 1 "register_operand" "")
- (const_int -1)))
- (clobber (reg:CC 33))])]
- ""
- "")
+;;
+;; Find leftmost bit instructions.
+;;
-;
-; one_cmplhi2 instruction pattern(s).
-;
+(define_expand "clzdi2"
+ [(set (match_operand:DI 0 "register_operand" "=d")
+ (clz:DI (match_operand:DI 1 "register_operand" "d")))]
+ "TARGET_EXTIMM && TARGET_64BIT"
+{
+ rtx insn, clz_equal;
+ rtx wide_reg = gen_reg_rtx (TImode);
+ rtx msb = gen_rtx_CONST_INT (DImode, (unsigned HOST_WIDE_INT) 1 << 63);
-(define_expand "one_cmplhi2"
- [(parallel
- [(set (match_operand:HI 0 "register_operand" "")
- (xor:HI (match_operand:HI 1 "register_operand" "")
- (const_int -1)))
- (clobber (reg:CC 33))])]
- ""
- "")
+ clz_equal = gen_rtx_CLZ (DImode, operands[1]);
-;
-; one_cmplqi2 instruction pattern(s).
-;
+ emit_insn (gen_clztidi2 (wide_reg, operands[1], msb));
-(define_expand "one_cmplqi2"
- [(parallel
- [(set (match_operand:QI 0 "register_operand" "")
- (xor:QI (match_operand:QI 1 "register_operand" "")
- (const_int -1)))
- (clobber (reg:CC 33))])]
- ""
- "")
+ insn = emit_move_insn (operands[0], gen_highpart (DImode, wide_reg));
+ REG_NOTES (insn) =
+ gen_rtx_EXPR_LIST (REG_EQUAL, clz_equal, REG_NOTES (insn));
+
+ 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_64BIT"
+ "flogr\t%0,%1"
+ [(set_attr "op_type" "RRE")])
;;
@@ -6069,82 +6305,105 @@
;;
;
-; rotldi3 instruction pattern(s).
+; rotl(di|si)3 instruction pattern(s).
;
-(define_insn "rotldi3"
- [(set (match_operand:DI 0 "register_operand" "=d")
- (rotate:DI (match_operand:DI 1 "register_operand" "d")
- (match_operand:SI 2 "shift_count_operand" "Y")))]
- "TARGET_64BIT"
- "rllg\t%0,%1,%Y2"
+; 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")])
-;
-; rotlsi3 instruction pattern(s).
-;
-
-(define_insn "rotlsi3"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (rotate:SI (match_operand:SI 1 "register_operand" "d")
- (match_operand:SI 2 "shift_count_operand" "Y")))]
- "TARGET_CPU_ZARCH"
- "rll\t%0,%1,%Y2"
+; 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")])
;;
-;;- Arithmetic shift instructions.
+;;- Shift instructions.
;;
;
-; ashldi3 instruction pattern(s).
+; (ashl|lshr)(di|si)3 instruction pattern(s).
;
-(define_expand "ashldi3"
- [(set (match_operand:DI 0 "register_operand" "")
- (ashift:DI (match_operand:DI 1 "register_operand" "")
- (match_operand:SI 2 "shift_count_operand" "")))]
+(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" "")))]
""
"")
-(define_insn "*ashldi3_31"
+; sldl, srdl
+(define_insn "*<shift>di3_31"
[(set (match_operand:DI 0 "register_operand" "=d")
- (ashift:DI (match_operand:DI 1 "register_operand" "0")
- (match_operand:SI 2 "shift_count_operand" "Y")))]
+ (SHIFT:DI (match_operand:DI 1 "register_operand" "0")
+ (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")))]
"!TARGET_64BIT"
- "sldl\t%0,%Y2"
+ "s<lr>dl\t%0,%Y2"
[(set_attr "op_type" "RS")
(set_attr "atype" "reg")])
-(define_insn "*ashldi3_64"
+; sll, srl, sllg, srlg
+(define_insn "*<shift><mode>3"
+ [(set (match_operand:GPR 0 "register_operand" "=d")
+ (SHIFT:GPR (match_operand:GPR 1 "register_operand" "<d0>")
+ (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")))]
+ ""
+ "s<lr>l<g>\t%0,<1>%Y2"
+ [(set_attr "op_type" "RS<E>")
+ (set_attr "atype" "reg")])
+
+; sldl, srdl
+(define_insn "*<shift>di3_31_and"
[(set (match_operand:DI 0 "register_operand" "=d")
- (ashift:DI (match_operand:DI 1 "register_operand" "d")
- (match_operand:SI 2 "shift_count_operand" "Y")))]
- "TARGET_64BIT"
- "sllg\t%0,%1,%Y2"
- [(set_attr "op_type" "RSE")
+ (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_64BIT && (INTVAL (operands[3]) & 63) == 63"
+ "s<lr>dl\t%0,%Y2"
+ [(set_attr "op_type" "RS")
+ (set_attr "atype" "reg")])
+
+; sll, srl, sllg, srlg
+(define_insn "*<shift><mode>3_and"
+ [(set (match_operand:GPR 0 "register_operand" "=d")
+ (SHIFT:GPR (match_operand:GPR 1 "register_operand" "<d0>")
+ (and:SI (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")
+ (match_operand:SI 3 "const_int_operand" "n"))))]
+ "(INTVAL (operands[3]) & 63) == 63"
+ "s<lr>l<g>\t%0,<1>%Y2"
+ [(set_attr "op_type" "RS<E>")
(set_attr "atype" "reg")])
;
-; ashrdi3 instruction pattern(s).
+; ashr(di|si)3 instruction pattern(s).
;
-(define_expand "ashrdi3"
+(define_expand "ashr<mode>3"
[(parallel
- [(set (match_operand:DI 0 "register_operand" "")
- (ashiftrt:DI (match_operand:DI 1 "register_operand" "")
- (match_operand:SI 2 "shift_count_operand" "")))
- (clobber (reg:CC 33))])]
+ [(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 33)
+ [(set (reg CC_REGNUM)
(compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
- (match_operand:SI 2 "shift_count_operand" "Y"))
+ (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)))]
@@ -6154,9 +6413,9 @@
(set_attr "atype" "reg")])
(define_insn "*ashrdi3_cconly_31"
- [(set (reg 33)
+ [(set (reg CC_REGNUM)
(compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
- (match_operand:SI 2 "shift_count_operand" "Y"))
+ (match_operand:SI 2 "shift_count_or_setmem_operand" "Y"))
(const_int 0)))
(clobber (match_scratch:DI 0 "=d"))]
"!TARGET_64BIT && s390_match_ccmode(insn, CCSmode)"
@@ -6167,143 +6426,127 @@
(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_operand" "Y")))
- (clobber (reg:CC 33))]
+ (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")))
+ (clobber (reg:CC CC_REGNUM))]
"!TARGET_64BIT"
"srda\t%0,%Y2"
[(set_attr "op_type" "RS")
(set_attr "atype" "reg")])
-(define_insn "*ashrdi3_cc_64"
- [(set (reg 33)
- (compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "d")
- (match_operand:SI 2 "shift_count_operand" "Y"))
+; sra, srag
+(define_insn "*ashr<mode>3_cc"
+ [(set (reg CC_REGNUM)
+ (compare (ashiftrt:GPR (match_operand:GPR 1 "register_operand" "<d0>")
+ (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)))]
- "s390_match_ccmode(insn, CCSmode) && TARGET_64BIT"
- "srag\t%0,%1,%Y2"
- [(set_attr "op_type" "RSE")
+ (set (match_operand:GPR 0 "register_operand" "=d")
+ (ashiftrt:GPR (match_dup 1) (match_dup 2)))]
+ "s390_match_ccmode(insn, CCSmode)"
+ "sra<g>\t%0,<1>%Y2"
+ [(set_attr "op_type" "RS<E>")
(set_attr "atype" "reg")])
-(define_insn "*ashrdi3_cconly_64"
- [(set (reg 33)
- (compare (ashiftrt:DI (match_operand:DI 1 "register_operand" "d")
- (match_operand:SI 2 "shift_count_operand" "Y"))
+; sra, srag
+(define_insn "*ashr<mode>3_cconly"
+ [(set (reg CC_REGNUM)
+ (compare (ashiftrt:GPR (match_operand:GPR 1 "register_operand" "<d0>")
+ (match_operand:SI 2 "shift_count_or_setmem_operand" "Y"))
(const_int 0)))
- (clobber (match_scratch:DI 0 "=d"))]
- "s390_match_ccmode(insn, CCSmode) && TARGET_64BIT"
- "srag\t%0,%1,%Y2"
- [(set_attr "op_type" "RSE")
+ (clobber (match_scratch:GPR 0 "=d"))]
+ "s390_match_ccmode(insn, CCSmode)"
+ "sra<g>\t%0,<1>%Y2"
+ [(set_attr "op_type" "RS<E>")
(set_attr "atype" "reg")])
-(define_insn "*ashrdi3_64"
- [(set (match_operand:DI 0 "register_operand" "=d")
- (ashiftrt:DI (match_operand:DI 1 "register_operand" "d")
- (match_operand:SI 2 "shift_count_operand" "Y")))
- (clobber (reg:CC 33))]
- "TARGET_64BIT"
- "srag\t%0,%1,%Y2"
- [(set_attr "op_type" "RSE")
+; sra, srag
+(define_insn "*ashr<mode>3"
+ [(set (match_operand:GPR 0 "register_operand" "=d")
+ (ashiftrt:GPR (match_operand:GPR 1 "register_operand" "<d0>")
+ (match_operand:SI 2 "shift_count_or_setmem_operand" "Y")))
+ (clobber (reg:CC CC_REGNUM))]
+ ""
+ "sra<g>\t%0,<1>%Y2"
+ [(set_attr "op_type" "RS<E>")
(set_attr "atype" "reg")])
-;
-; ashlsi3 instruction pattern(s).
-;
+; shift pattern with implicit ANDs
-(define_insn "ashlsi3"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (ashift:SI (match_operand:SI 1 "register_operand" "0")
- (match_operand:SI 2 "shift_count_operand" "Y")))]
- ""
- "sll\t%0,%Y2"
+(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_64BIT && s390_match_ccmode(insn, CCSmode)
+ && (INTVAL (operands[3]) & 63) == 63"
+ "srda\t%0,%Y2"
[(set_attr "op_type" "RS")
(set_attr "atype" "reg")])
-;
-; ashrsi3 instruction pattern(s).
-;
-
-(define_insn "*ashrsi3_cc"
- [(set (reg 33)
- (compare (ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
- (match_operand:SI 2 "shift_count_operand" "Y"))
+(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)))
- (set (match_operand:SI 0 "register_operand" "=d")
- (ashiftrt:SI (match_dup 1) (match_dup 2)))]
- "s390_match_ccmode(insn, CCSmode)"
- "sra\t%0,%Y2"
+ (clobber (match_scratch:DI 0 "=d"))]
+ "!TARGET_64BIT && 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 "*ashrsi3_cconly"
- [(set (reg 33)
- (compare (ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
- (match_operand:SI 2 "shift_count_operand" "Y"))
- (const_int 0)))
- (clobber (match_scratch:SI 0 "=d"))]
- "s390_match_ccmode(insn, CCSmode)"
- "sra\t%0,%Y2"
+(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_64BIT && (INTVAL (operands[3]) & 63) == 63"
+ "srda\t%0,%Y2"
[(set_attr "op_type" "RS")
(set_attr "atype" "reg")])
-(define_insn "ashrsi3"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
- (match_operand:SI 2 "shift_count_operand" "Y")))
- (clobber (reg:CC 33))]
- ""
- "sra\t%0,%Y2"
- [(set_attr "op_type" "RS")
+; sra, srag
+(define_insn "*ashr<mode>3_cc_and"
+ [(set (reg CC_REGNUM)
+ (compare (ashiftrt:GPR (match_operand:GPR 1 "register_operand" "<d0>")
+ (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:GPR 0 "register_operand" "=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"
+ [(set_attr "op_type" "RS<E>")
(set_attr "atype" "reg")])
-
-;;
-;;- logical shift instructions.
-;;
-
-;
-; lshrdi3 instruction pattern(s).
-;
-
-(define_expand "lshrdi3"
- [(set (match_operand:DI 0 "register_operand" "")
- (lshiftrt:DI (match_operand:DI 1 "register_operand" "")
- (match_operand:SI 2 "shift_count_operand" "")))]
- ""
- "")
-
-(define_insn "*lshrdi3_31"
- [(set (match_operand:DI 0 "register_operand" "=d")
- (lshiftrt:DI (match_operand:DI 1 "register_operand" "0")
- (match_operand:SI 2 "shift_count_operand" "Y")))]
- "!TARGET_64BIT"
- "srdl\t%0,%Y2"
- [(set_attr "op_type" "RS")
- (set_attr "atype" "reg")])
-
-(define_insn "*lshrdi3_64"
- [(set (match_operand:DI 0 "register_operand" "=d")
- (lshiftrt:DI (match_operand:DI 1 "register_operand" "d")
- (match_operand:SI 2 "shift_count_operand" "Y")))]
- "TARGET_64BIT"
- "srlg\t%0,%1,%Y2"
- [(set_attr "op_type" "RSE")
+; sra, srag
+(define_insn "*ashr<mode>3_cconly_and"
+ [(set (reg CC_REGNUM)
+ (compare (ashiftrt:GPR (match_operand:GPR 1 "register_operand" "<d0>")
+ (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:GPR 0 "=d"))]
+ "s390_match_ccmode(insn, CCSmode) && (INTVAL (operands[3]) & 63) == 63"
+ "sra<g>\t%0,<1>%Y2"
+ [(set_attr "op_type" "RS<E>")
(set_attr "atype" "reg")])
-;
-; lshrsi3 instruction pattern(s).
-;
-
-(define_insn "lshrsi3"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (lshiftrt:SI (match_operand:SI 1 "register_operand" "0")
- (match_operand:SI 2 "shift_count_operand" "Y")))]
- ""
- "srl\t%0,%Y2"
- [(set_attr "op_type" "RS")
+; sra, srag
+(define_insn "*ashr<mode>3_and"
+ [(set (match_operand:GPR 0 "register_operand" "=d")
+ (ashiftrt:GPR (match_operand:GPR 1 "register_operand" "<d0>")
+ (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))]
+ "(INTVAL (operands[3]) & 63) == 63"
+ "sra<g>\t%0,<1>%Y2"
+ [(set_attr "op_type" "RS<E>")
(set_attr "atype" "reg")])
@@ -6311,204 +6554,66 @@
;; Branch instruction patterns.
;;
-(define_expand "beq"
- [(set (reg:CCZ 33) (compare:CCZ (match_dup 1) (match_dup 2)))
- (set (pc)
- (if_then_else (eq (reg:CCZ 33) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;")
-
-(define_expand "bne"
- [(set (reg:CCZ 33) (compare:CCZ (match_dup 1) (match_dup 2)))
- (set (pc)
- (if_then_else (ne (reg:CCZ 33) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;")
-
-(define_expand "bgt"
- [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
- (set (pc)
- (if_then_else (gt (reg:CCS 33) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;")
-
-(define_expand "bgtu"
- [(set (reg:CCU 33) (compare:CCU (match_dup 1) (match_dup 2)))
- (set (pc)
- (if_then_else (gtu (reg:CCU 33) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;")
-
-(define_expand "blt"
- [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
- (set (pc)
- (if_then_else (lt (reg:CCS 33) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;")
-
-(define_expand "bltu"
- [(set (reg:CCU 33) (compare:CCU (match_dup 1) (match_dup 2)))
- (set (pc)
- (if_then_else (ltu (reg:CCU 33) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;")
-
-(define_expand "bge"
- [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
- (set (pc)
- (if_then_else (ge (reg:CCS 33) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;")
-
-(define_expand "bgeu"
- [(set (reg:CCU 33) (compare:CCU (match_dup 1) (match_dup 2)))
- (set (pc)
- (if_then_else (geu (reg:CCU 33) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;")
-
-(define_expand "ble"
- [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
- (set (pc)
- (if_then_else (le (reg:CCS 33) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;")
-
-(define_expand "bleu"
- [(set (reg:CCU 33) (compare:CCU (match_dup 1) (match_dup 2)))
- (set (pc)
- (if_then_else (leu (reg:CCU 33) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;")
-
-(define_expand "bunordered"
- [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
- (set (pc)
- (if_then_else (unordered (reg:CCS 33) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;")
-
-(define_expand "bordered"
- [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
- (set (pc)
- (if_then_else (ordered (reg:CCS 33) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;")
-
-(define_expand "buneq"
- [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
- (set (pc)
- (if_then_else (uneq (reg:CCS 33) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;")
-
-(define_expand "bungt"
- [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
- (set (pc)
- (if_then_else (ungt (reg:CCS 33) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;")
-
-(define_expand "bunlt"
- [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
- (set (pc)
- (if_then_else (unlt (reg:CCS 33) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;")
-
-(define_expand "bunge"
- [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
- (set (pc)
- (if_then_else (unge (reg:CCS 33) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;")
-
-(define_expand "bunle"
- [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
- (set (pc)
- (if_then_else (unle (reg:CCS 33) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;")
-
-(define_expand "bltgt"
- [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
- (set (pc)
- (if_then_else (ltgt (reg:CCS 33) (const_int 0))
- (label_ref (match_operand 0 "" ""))
+(define_expand "b<code>"
+ [(set (pc)
+ (if_then_else (COMPARE (match_operand 0 "" "")
+ (const_int 0))
+ (match_dup 0)
(pc)))]
""
- "operands[1] = s390_compare_op0; operands[2] = s390_compare_op1;")
+ "s390_emit_jump (operands[0],
+ s390_emit_compare (<CODE>, s390_compare_op0, s390_compare_op1)); DONE;")
;;
;;- Conditional jump instructions.
;;
-(define_insn "cjump"
- [(set (pc)
- (if_then_else
- (match_operator 1 "comparison_operator" [(reg 33) (const_int 0)])
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
+(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 if (TARGET_CPU_ZARCH)
- return "jg%C1\t%l0";
else
- abort ();
+ 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")
- (cond [(lt (abs (minus (pc) (match_dup 0))) (const_int 60000))
- (const_int 4)
- (ne (symbol_ref "TARGET_CPU_ZARCH") (const_int 0))
- (const_int 6)
- (eq (symbol_ref "flag_pic") (const_int 0))
- (const_int 6)] (const_int 8)))])
+ (if_then_else (eq (symbol_ref "flag_pic") (const_int 0))
+ (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 "comparison_operator" [(reg 33) (const_int 0)])
- (match_operand 0 "address_operand" "U")
- (pc)))]
+ [(set (pc)
+ (if_then_else
+ (match_operator 1 "s390_comparison" [(reg CC_REGNUM) (const_int 0)])
+ (match_operand 0 "address_operand" "U")
+ (pc)))]
""
{
if (get_attr_op_type (insn) == OP_TYPE_RR)
@@ -6519,7 +6624,7 @@
[(set (attr "op_type")
(if_then_else (match_operand 0 "register_operand" "")
(const_string "RR") (const_string "RX")))
- (set_attr "type" "branch")
+ (set_attr "type" "branch")
(set_attr "atype" "agen")])
@@ -6527,37 +6632,51 @@
;;- Negated conditional jump instructions.
;;
-(define_insn "icjump"
- [(set (pc)
- (if_then_else
- (match_operator 1 "comparison_operator" [(reg 33) (const_int 0)])
- (pc)
- (label_ref (match_operand 0 "" ""))))]
- ""
+(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 if (TARGET_CPU_ZARCH)
- return "jg%D1\t%l0";
else
- abort ();
+ 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")
- (cond [(lt (abs (minus (pc) (match_dup 0))) (const_int 60000))
- (const_int 4)
- (ne (symbol_ref "TARGET_CPU_ZARCH") (const_int 0))
- (const_int 6)
- (eq (symbol_ref "flag_pic") (const_int 0))
- (const_int 6)] (const_int 8)))])
+ (if_then_else (eq (symbol_ref "flag_pic") (const_int 0))
+ (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 "comparison_operator" [(reg 33) (const_int 0)])
- (pc)
- (match_operand 0 "address_operand" "U")))]
+ [(set (pc)
+ (if_then_else
+ (match_operator 1 "s390_comparison" [(reg CC_REGNUM) (const_int 0)])
+ (pc)
+ (match_operand 0 "address_operand" "U")))]
""
{
if (get_attr_op_type (insn) == OP_TYPE_RR)
@@ -6579,28 +6698,21 @@
[(trap_if (const_int 1) (const_int 0))]
""
"j\t.+2"
- [(set_attr "op_type" "RX")
+ [(set_attr "op_type" "RI")
(set_attr "type" "branch")])
(define_expand "conditional_trap"
- [(set (match_dup 2) (match_dup 3))
- (trap_if (match_operator 0 "comparison_operator"
- [(match_dup 2) (const_int 0)])
- (match_operand:SI 1 "general_operand" ""))]
+ [(trap_if (match_operand 0 "comparison_operator" "")
+ (match_operand 1 "general_operand" ""))]
""
{
- enum machine_mode ccmode;
-
- if (operands[1] != const0_rtx) FAIL;
-
- ccmode = s390_select_ccmode (GET_CODE (operands[0]),
- s390_compare_op0, s390_compare_op1);
- operands[2] = gen_rtx_REG (ccmode, 33);
- operands[3] = gen_rtx_COMPARE (ccmode, s390_compare_op0, s390_compare_op1);
+ if (operands[1] != const0_rtx) FAIL;
+ operands[0] = s390_emit_compare (GET_CODE (operands[0]),
+ s390_compare_op0, s390_compare_op1);
})
(define_insn "*trap"
- [(trap_if (match_operator 0 "comparison_operator" [(reg 33) (const_int 0)])
+ [(trap_if (match_operator 0 "s390_comparison" [(reg CC_REGNUM) (const_int 0)])
(const_int 0))]
""
"j%C0\t.+2";
@@ -6621,8 +6733,10 @@
(use (match_operand 4 "" ""))] ; label
""
{
- if (GET_MODE (operands[0]) == SImode)
- emit_jump_insn (gen_doloop_si (operands[4], operands[0], operands[0]));
+ 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_64BIT)
emit_jump_insn (gen_doloop_di (operands[4], operands[0], operands[0]));
else
@@ -6631,50 +6745,99 @@
DONE;
})
-(define_insn "doloop_si"
+(define_insn_and_split "doloop_si64"
[(set (pc)
(if_then_else
- (ne (match_operand:SI 1 "register_operand" "d,d")
+ (ne (match_operand:SI 1 "register_operand" "d,d,d")
(const_int 1))
(label_ref (match_operand 0 "" ""))
(pc)))
- (set (match_operand:SI 2 "register_operand" "=1,?*m*d")
+ (set (match_operand:SI 2 "nonimmediate_operand" "=1,?X,?X")
(plus:SI (match_dup 1) (const_int -1)))
- (clobber (match_scratch:SI 3 "=X,&d"))
- (clobber (reg:CC 33))]
- ""
+ (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 if (TARGET_CPU_ZARCH)
+ 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")
+ (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
- abort ();
+ 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")
(set_attr "type" "branch")
(set (attr "length")
- (cond [(lt (abs (minus (pc) (match_dup 0))) (const_int 60000))
- (const_int 4)
- (ne (symbol_ref "TARGET_CPU_ZARCH") (const_int 0))
- (const_int 10)
- (eq (symbol_ref "flag_pic") (const_int 0))
- (const_int 6)] (const_int 8)))])
+ (if_then_else (eq (symbol_ref "flag_pic") (const_int 0))
+ (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,d")
+ (ne (match_operand:SI 1 "register_operand" "d")
(const_int 1))
- (match_operand 0 "address_operand" "U,U")
+ (match_operand 0 "address_operand" "U")
(pc)))
- (set (match_operand:SI 2 "register_operand" "=1,?*m*d")
+ (set (match_operand:SI 2 "register_operand" "=1")
(plus:SI (match_dup 1) (const_int -1)))
- (clobber (match_scratch:SI 3 "=X,&d"))
- (clobber (reg:CC 33))]
- ""
+ (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";
@@ -6687,41 +6850,17 @@
(set_attr "type" "branch")
(set_attr "atype" "agen")])
-(define_split
- [(set (pc)
- (if_then_else (ne (match_operand:SI 1 "register_operand" "")
- (const_int 1))
- (match_operand 0 "" "")
- (pc)))
- (set (match_operand:SI 2 "nonimmediate_operand" "")
- (plus:SI (match_dup 1) (const_int -1)))
- (clobber (match_scratch:SI 3 ""))
- (clobber (reg:CC 33))]
- "reload_completed
- && (! REG_P (operands[2])
- || ! rtx_equal_p (operands[1], operands[2]))"
- [(set (match_dup 3) (match_dup 1))
- (parallel [(set (reg:CCAN 33)
- (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 33) (const_int 0))
- (match_dup 0)
- (pc)))]
- "")
-
-(define_insn "doloop_di"
+(define_insn_and_split "doloop_di"
[(set (pc)
(if_then_else
- (ne (match_operand:DI 1 "register_operand" "d,d")
+ (ne (match_operand:DI 1 "register_operand" "d,d,d")
(const_int 1))
(label_ref (match_operand 0 "" ""))
(pc)))
- (set (match_operand:DI 2 "register_operand" "=1,?*m*r")
+ (set (match_operand:DI 2 "nonimmediate_operand" "=1,?X,?X")
(plus:DI (match_dup 1) (const_int -1)))
- (clobber (match_scratch:DI 3 "=X,&d"))
- (clobber (reg:CC 33))]
+ (clobber (match_scratch:DI 3 "=X,&1,&?d"))
+ (clobber (reg:CC CC_REGNUM))]
"TARGET_64BIT"
{
if (which_alternative != 0)
@@ -6731,35 +6870,24 @@
else
return "aghi\t%1,-1\;jgne\t%l0";
}
- [(set_attr "op_type" "RI")
- (set_attr "type" "branch")
- (set (attr "length")
- (if_then_else (lt (abs (minus (pc) (match_dup 0))) (const_int 60000))
- (const_int 4) (const_int 10)))])
-
-(define_split
- [(set (pc)
- (if_then_else (ne (match_operand:DI 1 "register_operand" "")
- (const_int 1))
- (match_operand 0 "" "")
- (pc)))
- (set (match_operand:DI 2 "nonimmediate_operand" "")
- (plus:DI (match_dup 1) (const_int -1)))
- (clobber (match_scratch:DI 3 ""))
- (clobber (reg:CC 33))]
- "reload_completed
+ "&& reload_completed
&& (! REG_P (operands[2])
|| ! rtx_equal_p (operands[1], operands[2]))"
[(set (match_dup 3) (match_dup 1))
- (parallel [(set (reg:CCAN 33)
+ (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 33) (const_int 0))
- (match_dup 0)
+ (set (pc) (if_then_else (ne (reg:CCAN CC_REGNUM) (const_int 0))
+ (label_ref (match_dup 0))
(pc)))]
- "")
+ ""
+ [(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 10)))])
;;
;;- Unconditional jump instructions.
@@ -6769,26 +6897,41 @@
; jump instruction pattern(s).
;
-(define_insn "jump"
- [(set (pc) (label_ref (match_operand 0 "" "")))]
+(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 if (TARGET_CPU_ZARCH)
- return "jg\t%l0";
else
- abort ();
+ return "jg\t%l0";
}
[(set_attr "op_type" "RI")
(set_attr "type" "branch")
(set (attr "length")
- (cond [(lt (abs (minus (pc) (match_dup 0))) (const_int 60000))
- (const_int 4)
- (ne (symbol_ref "TARGET_CPU_ZARCH") (const_int 0))
- (const_int 6)
- (eq (symbol_ref "flag_pic") (const_int 0))
- (const_int 6)] (const_int 8)))])
+ (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 (eq (symbol_ref "flag_pic") (const_int 0))
+ (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).
@@ -6854,11 +6997,11 @@
if (TARGET_64BIT)
emit_insn (gen_ashldi3 (index, index, GEN_INT (3)));
else
- emit_insn (gen_ashlsi3 (index, index, GEN_INT (2)));
+ emit_insn (gen_ashlsi3 (index, index, const2_rtx));
emit_move_insn (base, gen_rtx_LABEL_REF (Pmode, operands[3]));
- index = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, base, index));
+ index = gen_const_mem (Pmode, gen_rtx_PLUS (Pmode, base, index));
emit_move_insn (target, index);
if (flag_pic)
@@ -6915,71 +7058,111 @@
[(set_attr "type" "none")
(set_attr "length" "0")])
-
-
;
-; call instruction pattern(s).
+; sibcall patterns
;
-(define_expand "call"
+(define_expand "sibcall"
[(call (match_operand 0 "" "")
- (match_operand 1 "" ""))
- (use (match_operand 2 "" ""))]
+ (match_operand 1 "" ""))]
""
{
- bool plt_call = false;
- rtx insn;
-
- /* Direct function calls need special treatment. */
- if (GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF)
- {
- rtx sym = XEXP (operands[0], 0);
+ s390_emit_call (XEXP (operands[0], 0), NULL_RTX, NULL_RTX, NULL_RTX);
+ DONE;
+})
- /* 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 (sym))
- {
- sym = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), UNSPEC_PLT);
- sym = gen_rtx_CONST (Pmode, sym);
- plt_call = true;
- }
+(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")])
- /* 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)
- sym = legitimize_pic_address (sym, 0);
- else
- sym = force_reg (Pmode, sym);
- }
+(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")])
- operands[0] = gen_rtx_MEM (QImode, sym);
- }
+(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")])
- /* Emit insn. */
- insn = emit_call_insn (gen_call_exp (operands[0], operands[1],
- gen_rtx_REG (Pmode, RETURN_REGNUM)));
+;
+; sibcall_value patterns
+;
- /* 31-bit PLT stubs use the GOT register implicitly. */
- if (!TARGET_64BIT && plt_call)
- use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
-
+(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_expand "call_exp"
- [(parallel [(call (match_operand 0 "" "")
- (match_operand 1 "" ""))
- (clobber (match_operand 2 "" ""))])]
+(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"))]
- "TARGET_SMALL_EXEC && GET_MODE (operands[2]) == Pmode"
+ "!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")])
@@ -6988,7 +7171,9 @@
[(call (mem:QI (match_operand 0 "bras_sym_operand" "X"))
(match_operand 1 "const_int_operand" "n"))
(clobber (match_operand 2 "register_operand" "=r"))]
- "TARGET_CPU_ZARCH && GET_MODE (operands[2]) == Pmode"
+ "!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")])
@@ -6997,7 +7182,7 @@
[(call (mem:QI (match_operand 0 "address_operand" "U"))
(match_operand 1 "const_int_operand" "n"))
(clobber (match_operand 2 "register_operand" "=r"))]
- "GET_MODE (operands[2]) == Pmode"
+ "!SIBLING_CALL_P (insn) && GET_MODE (operands[2]) == Pmode"
{
if (get_attr_op_type (insn) == OP_TYPE_RR)
return "basr\t%2,%0";
@@ -7021,62 +7206,19 @@
(use (match_operand 3 "" ""))]
""
{
- bool plt_call = false;
- rtx insn;
-
- /* Direct function calls need special treatment. */
- if (GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF)
- {
- rtx sym = XEXP (operands[1], 0);
-
- /* 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 (sym))
- {
- sym = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), UNSPEC_PLT);
- sym = gen_rtx_CONST (Pmode, sym);
- plt_call = true;
- }
-
- /* 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)
- sym = legitimize_pic_address (sym, 0);
- else
- sym = force_reg (Pmode, sym);
- }
-
- operands[1] = gen_rtx_MEM (QImode, sym);
- }
-
- /* Emit insn. */
- insn = emit_call_insn (
- gen_call_value_exp (operands[0], operands[1], operands[2],
- gen_rtx_REG (Pmode, RETURN_REGNUM)));
-
- /* 31-bit PLT stubs use the GOT register implicitly. */
- if (!TARGET_64BIT && plt_call)
- use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
-
+ s390_emit_call (XEXP (operands[1], 0), NULL_RTX, operands[0],
+ gen_rtx_REG (Pmode, RETURN_REGNUM));
DONE;
})
-(define_expand "call_value_exp"
- [(parallel [(set (match_operand 0 "" "")
- (call (match_operand 1 "" "")
- (match_operand 2 "" "")))
- (clobber (match_operand 3 "" ""))])]
- ""
- "")
-
(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"))]
- "TARGET_SMALL_EXEC && GET_MODE (operands[3]) == Pmode"
+ "!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")])
@@ -7086,7 +7228,9 @@
(call (mem:QI (match_operand 1 "bras_sym_operand" "X"))
(match_operand 2 "const_int_operand" "n")))
(clobber (match_operand 3 "register_operand" "=r"))]
- "TARGET_CPU_ZARCH && GET_MODE (operands[3]) == Pmode"
+ "!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")])
@@ -7096,7 +7240,7 @@
(call (mem:QI (match_operand 1 "address_operand" "U"))
(match_operand 2 "const_int_operand" "n")))
(clobber (match_operand 3 "register_operand" "=r"))]
- "GET_MODE (operands[3]) == Pmode"
+ "!SIBLING_CALL_P (insn) && GET_MODE (operands[3]) == Pmode"
{
if (get_attr_op_type (insn) == OP_TYPE_RR)
return "basr\t%3,%1";
@@ -7113,46 +7257,34 @@
;;- Thread-local storage support.
;;
-(define_insn "get_tp_64"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=??d,Q")
- (unspec:DI [(const_int 0)] UNSPEC_TP))]
+(define_expand "get_tp_64"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "") (reg:DI TP_REGNUM))]
"TARGET_64BIT"
- "@
- ear\t%0,%%a0\;sllg\t%0,%0,32\;ear\t%0,%%a1
- stam\t%%a0,%%a1,%0"
- [(set_attr "op_type" "NN,RS")
- (set_attr "atype" "reg,*")
- (set_attr "type" "o3,*")
- (set_attr "length" "14,*")])
+ "")
-(define_insn "get_tp_31"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=d,Q")
- (unspec:SI [(const_int 0)] UNSPEC_TP))]
+(define_expand "get_tp_31"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "") (reg:SI TP_REGNUM))]
"!TARGET_64BIT"
- "@
- ear\t%0,%%a0
- stam\t%%a0,%%a0,%0"
- [(set_attr "op_type" "RRE,RS")])
+ "")
-(define_insn "set_tp_64"
- [(unspec_volatile [(match_operand:DI 0 "general_operand" "??d,Q")] UNSPECV_SET_TP)
- (clobber (match_scratch:SI 1 "=d,X"))]
+(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"
- "@
- sar\t%%a1,%0\;srlg\t%1,%0,32\;sar\t%%a0,%1
- lam\t%%a0,%%a1,%0"
- [(set_attr "op_type" "NN,RS")
- (set_attr "atype" "reg,*")
- (set_attr "type" "o3,*")
- (set_attr "length" "14,*")])
+ "")
-(define_insn "set_tp_31"
- [(unspec_volatile [(match_operand:SI 0 "general_operand" "d,Q")] UNSPECV_SET_TP)]
+(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"
- "@
- sar\t%%a0,%0
- lam\t%%a0,%%a0,%0"
- [(set_attr "op_type" "RRE,RS")])
+ "")
+
+(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")
@@ -7174,64 +7306,15 @@
ly\t%0,%1%J2"
[(set_attr "op_type" "RX,RXY")])
-(define_expand "call_value_tls"
- [(set (match_operand 0 "" "")
- (call (const_int 0) (const_int 0)))
- (use (match_operand 1 "" ""))]
- ""
-{
- rtx insn, sym;
-
- if (!flag_pic)
- abort ();
-
- sym = s390_tls_get_offset ();
- sym = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), UNSPEC_PLT);
- sym = gen_rtx_CONST (Pmode, sym);
-
- /* Unless we can use the bras(l) insn, force the
- routine address into a register. */
- if (!TARGET_SMALL_EXEC && !TARGET_CPU_ZARCH)
- {
- if (flag_pic)
- sym = legitimize_pic_address (sym, 0);
- else
- sym = force_reg (Pmode, sym);
- }
-
- sym = gen_rtx_MEM (QImode, sym);
-
- /* Emit insn. */
- insn = emit_call_insn (
- gen_call_value_tls_exp (operands[0], sym, const0_rtx,
- gen_rtx_REG (Pmode, RETURN_REGNUM),
- operands[1]));
-
- /* The calling convention of __tls_get_offset uses the
- GOT register implicitly. */
- use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
- use_reg (&CALL_INSN_FUNCTION_USAGE (insn), operands[0]);
- CONST_OR_PURE_CALL_P (insn) = 1;
-
- DONE;
-})
-
-(define_expand "call_value_tls_exp"
- [(parallel [(set (match_operand 0 "" "")
- (call (match_operand 1 "" "")
- (match_operand 2 "" "")))
- (clobber (match_operand 3 "" ""))
- (use (match_operand 4 "" ""))])]
- ""
- "")
-
(define_insn "*bras_tls"
[(set (match_operand 0 "" "")
(call (mem:QI (match_operand 1 "bras_sym_operand" "X"))
(match_operand 2 "const_int_operand" "n")))
(clobber (match_operand 3 "register_operand" "=r"))
(use (match_operand 4 "" ""))]
- "TARGET_SMALL_EXEC && GET_MODE (operands[3]) == Pmode"
+ "!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")])
@@ -7242,7 +7325,9 @@
(match_operand 2 "const_int_operand" "n")))
(clobber (match_operand 3 "register_operand" "=r"))
(use (match_operand 4 "" ""))]
- "TARGET_CPU_ZARCH && GET_MODE (operands[3]) == Pmode"
+ "!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")])
@@ -7253,7 +7338,7 @@
(match_operand 2 "const_int_operand" "n")))
(clobber (match_operand 3 "register_operand" "=r"))
(use (match_operand 4 "" ""))]
- "GET_MODE (operands[3]) == Pmode"
+ "!SIBLING_CALL_P (insn) && GET_MODE (operands[3]) == Pmode"
{
if (get_attr_op_type (insn) == OP_TYPE_RR)
return "basr\t%3,%1%J4";
@@ -7267,6 +7352,159 @@
(set_attr "atype" "agen")])
;;
+;;- Atomic operations
+;;
+
+;
+; memory barrier pattern.
+;
+
+(define_expand "memory_barrier"
+ [(set (mem:BLK (match_dup 0))
+ (unspec_volatile:BLK [(mem:BLK (match_dup 0))] UNSPECV_MB))]
+ ""
+{
+ operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (DImode));
+ MEM_VOLATILE_P (operands[0]) = 1;
+})
+
+(define_insn "*memory_barrier"
+ [(set (match_operand:BLK 0 "" "")
+ (unspec_volatile:BLK [(match_operand:BLK 1 "" "")] UNSPECV_MB))]
+ ""
+ "bcr\t15,0"
+ [(set_attr "op_type" "RR")])
+
+;
+; 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))
+ (set (reg:CCZ1 CC_REGNUM)
+ (compare:CCZ1 (match_dup 1) (match_dup 2)))])]
+ ""
+ "s390_expand_cs_hqi (<MODE>mode, operands[0], operands[1],
+ operands[2], operands[3]); DONE;")
+
+(define_expand "sync_compare_and_swap_cc<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 (match_dup 4)
+ (compare:CCZ1 (match_dup 1) (match_dup 2)))])]
+ ""
+{
+ /* Emulate compare. */
+ operands[4] = gen_rtx_REG (CCZ1mode, CC_REGNUM);
+ s390_compare_op0 = operands[1];
+ s390_compare_op1 = operands[2];
+ s390_compare_emitted = operands[4];
+})
+
+; cds, cdsg
+(define_insn "*sync_compare_and_swap<mode>"
+ [(set (match_operand:DP 0 "register_operand" "=r")
+ (match_operand:DP 1 "memory_operand" "+Q"))
+ (set (match_dup 1)
+ (unspec_volatile:DP
+ [(match_dup 1)
+ (match_operand:DP 2 "register_operand" "0")
+ (match_operand:DP 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;")
+
+(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.
;;
@@ -7275,27 +7513,18 @@
;
(define_expand "allocate_stack"
- [(set (reg 15)
- (plus (reg 15) (match_operand 1 "general_operand" "")))
- (set (match_operand 0 "general_operand" "")
- (reg 15))]
+ [(match_operand 0 "general_operand" "")
+ (match_operand 1 "general_operand" "")]
"TARGET_BACKCHAIN"
{
- rtx stack = gen_rtx (REG, Pmode, STACK_POINTER_REGNUM);
- rtx chain = gen_rtx (MEM, Pmode, stack);
- rtx temp = gen_reg_rtx (Pmode);
-
- emit_move_insn (temp, chain);
-
- if (TARGET_64BIT)
- emit_insn (gen_adddi3 (stack, stack, negate_rtx (Pmode, operands[1])));
- else
- emit_insn (gen_addsi3 (stack, stack, negate_rtx (Pmode, operands[1])));
+ rtx temp = gen_reg_rtx (Pmode);
- emit_move_insn (chain, temp);
+ 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;
+ emit_move_insn (operands[0], virtual_stack_dynamic_rtx);
+ DONE;
})
@@ -7307,7 +7536,7 @@
[(match_operand 0 "" "")]
"flag_pic"
{
- s390_load_got (false);
+ emit_insn (s390_load_got ());
emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
DONE;
})
@@ -7334,14 +7563,17 @@
"DONE;")
(define_expand "restore_stack_block"
- [(use (match_operand 0 "register_operand" ""))
- (set (match_dup 2) (match_dup 3))
- (set (match_dup 0) (match_operand 1 "register_operand" ""))
- (set (match_dup 3) (match_dup 2))]
- ""
+ [(match_operand 0 "register_operand" "")
+ (match_operand 1 "register_operand" "")]
+ "TARGET_BACKCHAIN"
{
- operands[2] = gen_reg_rtx (Pmode);
- operands[3] = gen_rtx_MEM (Pmode, operands[0]);
+ 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"
@@ -7349,20 +7581,21 @@
(match_operand 1 "register_operand" "")]
""
{
- rtx temp = gen_reg_rtx (Pmode);
+ enum machine_mode mode = TARGET_64BIT ? OImode : TImode;
+ 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. */
+
+ if (TARGET_BACKCHAIN)
+ {
+ rtx temp = force_reg (Pmode, s390_back_chain_rtx ());
+ emit_move_insn (operand_subword (operands[0], 0, 0, mode), temp);
+ }
+
+ emit_move_insn (operand_subword (operands[0], 1, 0, mode), operands[1]);
+ emit_move_insn (operand_subword (operands[0], 2, 0, mode), base);
- /* Copy the backchain to the first word, sp to the second and the literal pool
- base to the third. */
- emit_move_insn (operand_subword (operands[0], 2, 0,
- TARGET_64BIT ? OImode : TImode),
- gen_rtx_REG (Pmode, BASE_REGISTER));
- emit_move_insn (temp, gen_rtx_MEM (Pmode, operands[1]));
- emit_move_insn (operand_subword (operands[0], 0, 0,
- TARGET_64BIT ? OImode : TImode),
- temp);
- emit_move_insn (operand_subword (operands[0], 1, 0,
- TARGET_64BIT ? OImode : TImode),
- operands[1]);
DONE;
})
@@ -7371,26 +7604,33 @@
(match_operand 1 "memory_operand" "")]
""
{
- rtx temp = gen_reg_rtx (Pmode);
- rtx base = gen_rtx_REG (Pmode, BASE_REGISTER);
+ enum machine_mode mode = TARGET_64BIT ? OImode : TImode;
+ 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. */
- emit_move_insn (temp,
- operand_subword (operands[1], 0, 0,
- TARGET_64BIT ? OImode : TImode));
- emit_move_insn (operands[0],
- operand_subword (operands[1], 1, 0,
- TARGET_64BIT ? OImode : TImode));
- emit_move_insn (gen_rtx_MEM (Pmode, operands[0]), temp);
- emit_move_insn (base,
- operand_subword (operands[1], 2, 0,
- TARGET_64BIT ? OImode : TImode));
- emit_insn (gen_rtx_USE (VOIDmode, base));
+ literal pool base from the third. */
+
+ if (TARGET_BACKCHAIN)
+ temp = force_reg (Pmode, operand_subword (operands[1], 0, 0, mode));
+
+ emit_move_insn (base, operand_subword (operands[1], 2, 0, mode));
+ emit_move_insn (operands[0], operand_subword (operands[1], 1, 0, mode));
+ if (temp)
+ emit_move_insn (s390_back_chain_rtx (), temp);
+
+ emit_insn (gen_rtx_USE (VOIDmode, base));
DONE;
})
+(define_expand "exception_receiver"
+ [(const_int 0)]
+ ""
+{
+ s390_set_has_landing_pad_p (true);
+ DONE;
+})
;
; nop instruction pattern(s).
@@ -7414,40 +7654,30 @@
{
enum machine_mode mode = GET_MODE (PATTERN (insn));
unsigned int align = GET_MODE_BITSIZE (mode);
- s390_output_pool_entry (asm_out_file, operands[0], mode, align);
+ s390_output_pool_entry (operands[0], mode, align);
return "";
}
- [(set_attr "op_type" "NN")
- (set (attr "length")
+ [(set (attr "length")
(symbol_ref "GET_MODE_SIZE (GET_MODE (PATTERN (insn)))"))])
-(define_insn "pool_start_31"
- [(unspec_volatile [(const_int 0)] UNSPECV_POOL_START)]
- "!TARGET_CPU_ZARCH"
- ".align\t4"
- [(set_attr "op_type" "NN")
- (set_attr "length" "2")])
-
-(define_insn "pool_end_31"
- [(unspec_volatile [(const_int 0)] UNSPECV_POOL_END)]
- "!TARGET_CPU_ZARCH"
- ".align\t2"
- [(set_attr "op_type" "NN")
- (set_attr "length" "2")])
+(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_start_64"
- [(unspec_volatile [(const_int 0)] UNSPECV_POOL_START)]
- "TARGET_CPU_ZARCH"
- ".section\t.rodata\;.align\t8"
- [(set_attr "op_type" "NN")
- (set_attr "length" "0")])
+(define_insn "pool_section_start"
+ [(unspec_volatile [(const_int 1)] UNSPECV_POOL_SECTION)]
+ ""
+ ".section\t.rodata"
+ [(set_attr "length" "0")])
-(define_insn "pool_end_64"
- [(unspec_volatile [(const_int 0)] UNSPECV_POOL_END)]
- "TARGET_CPU_ZARCH"
+(define_insn "pool_section_end"
+ [(unspec_volatile [(const_int 0)] UNSPECV_POOL_SECTION)]
+ ""
".previous"
- [(set_attr "op_type" "NN")
- (set_attr "length" "0")])
+ [(set_attr "length" "0")])
(define_insn "main_base_31_small"
[(set (match_operand 0 "register_operand" "=a")
@@ -7474,19 +7704,23 @@
(set_attr "type" "larl")])
(define_insn "main_pool"
- [(unspec_volatile [(const_int 0)] UNSPECV_MAIN_POOL)]
- ""
- "* abort ();"
- [(set_attr "op_type" "NN")])
+ [(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 (ne (symbol_ref "TARGET_CPU_ZARCH") (const_int 0))
+ (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 "op_type" "NN")
- (set_attr "type" "la")
- (set_attr "length" "6")])
+ [(set_attr "length" "6")
+ (set_attr "type" "la")])
(define_insn "reload_base_64"
[(set (match_operand 0 "register_operand" "=a")
@@ -7499,9 +7733,10 @@
(define_insn "pool"
[(unspec_volatile [(match_operand 0 "const_int_operand" "n")] UNSPECV_POOL)]
""
- "* abort ();"
- [(set_attr "op_type" "NN")
- (set (attr "length") (symbol_ref "INTVAL (operands[0])"))])
+{
+ gcc_unreachable ();
+}
+ [(set (attr "length") (symbol_ref "INTVAL (operands[0])"))])
;;
;; Insns related to generating the function prologue and epilogue.
@@ -7516,7 +7751,12 @@
(define_expand "epilogue"
[(use (const_int 1))]
""
- "s390_emit_epilogue (); DONE;")
+ "s390_emit_epilogue (false); DONE;")
+
+(define_expand "sibcall_epilogue"
+ [(use (const_int 0))]
+ ""
+ "s390_emit_epilogue (true); DONE;")
(define_insn "*return"
[(return)
@@ -7541,3 +7781,77 @@
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 "" "")]
+ ""
+{
+#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
+ s390_compare_op0 = operands[0];
+ s390_compare_op1 = operands[1];
+ s390_compare_emitted = gen_rtx_REG (CCZmode, CC_REGNUM);
+
+ if (TARGET_64BIT)
+ emit_insn (gen_stack_protect_testdi (operands[0], operands[1]));
+ else
+ emit_insn (gen_stack_protect_testsi (operands[0], operands[1]));
+
+ emit_jump_insn (gen_beq (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")])
diff --git a/contrib/gcc/config/s390/s390.opt b/contrib/gcc/config/s390/s390.opt
new file mode 100644
index 0000000..21ef4f3
--- /dev/null
+++ b/contrib/gcc/config/s390/s390.opt
@@ -0,0 +1,100 @@
+; Options for the S/390 / zSeries port of the compiler.
+
+; Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+;
+; This file is part of GCC.
+;
+; GCC is free software; you can redistribute it and/or modify it under
+; the terms of the GNU General Public License as published by the Free
+; Software Foundation; either version 2, or (at your option) any later
+; version.
+;
+; GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+; WARRANTY; without even the implied warranty of MERCHANTABILITY or
+; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+; for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with GCC; see the file COPYING. If not, write to the Free
+; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+; 02110-1301, USA.
+
+m31
+Target Report RejectNegative InverseMask(64BIT)
+31 bit ABI
+
+m64
+Target Report RejectNegative Mask(64BIT)
+64 bit ABI
+
+march=
+Target RejectNegative Joined Var(s390_arch_string)
+Generate code for given CPU
+
+mbackchain
+Target Report Mask(BACKCHAIN)
+Maintain backchain pointer
+
+mdebug
+Target Report Mask(DEBUG_ARG)
+Additional debug prints
+
+mesa
+Target Report RejectNegative InverseMask(ZARCH)
+ESA/390 architecture
+
+mfused-madd
+Target Report Mask(FUSED_MADD)
+Enable fused multiply/add instructions
+
+mhard-float
+Target Report RejectNegative Mask(HARD_FLOAT)
+Use hardware fp
+
+mlong-double-128
+Target Report RejectNegative Mask(LONG_DOUBLE_128)
+Use 128-bit long double
+
+mlong-double-64
+Target Report RejectNegative 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 InverseMask(HARD_FLOAT, SOFT_FLOAT)
+Don't use hardware fp
+
+mstack-guard=
+Target RejectNegative Joined
+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
+Emit extra code in the function prologue in order to trap if the stack size exceeds the given limit
+
+mtune=
+Target RejectNegative Joined
+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 Mask(ZARCH)
+z/Architecture
diff --git a/contrib/gcc/config/s390/s390x.h b/contrib/gcc/config/s390/s390x.h
index f9177c1..cbfb45c 100644
--- a/contrib/gcc/config/s390/s390x.h
+++ b/contrib/gcc/config/s390/s390x.h
@@ -17,8 +17,8 @@ for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
#ifndef _S390X_H
#define _S390X_H
diff --git a/contrib/gcc/config/s390/t-crtstuff b/contrib/gcc/config/s390/t-crtstuff
index 5572e6b..39b0eba 100644
--- a/contrib/gcc/config/s390/t-crtstuff
+++ b/contrib/gcc/config/s390/t-crtstuff
@@ -2,3 +2,4 @@
# because then __FRAME_END__ might not be the last thing in .eh_frame
# section.
CRTSTUFF_T_CFLAGS = -fno-asynchronous-unwind-tables
+TARGET_LIBGCC2_CFLAGS += -mlong-double-128
diff --git a/contrib/gcc/config/s390/t-linux b/contrib/gcc/config/s390/t-linux
new file mode 100644
index 0000000..d5a9278
--- /dev/null
+++ b/contrib/gcc/config/s390/t-linux
@@ -0,0 +1,3 @@
+# Override t-slibgcc-elf-ver to export some libgcc symbols with
+# the symbol versions that glibc used.
+SHLIB_MAPFILES = $(srcdir)/libgcc-std.ver $(srcdir)/config/s390/libgcc-glibc.ver
diff --git a/contrib/gcc/config/s390/t-linux64 b/contrib/gcc/config/s390/t-linux64
index db839c6..0ffb690 100644
--- a/contrib/gcc/config/s390/t-linux64
+++ b/contrib/gcc/config/s390/t-linux64
@@ -6,7 +6,3 @@ LIBGCC = stmp-multilib
INSTALL_LIBGCC = install-multilib
EXTRA_MULTILIB_PARTS=crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o
-
-# Override t-slibgcc-elf-ver to export some libgcc symbols with
-# the symbol versions that glibc used.
-SHLIB_MAPFILES = $(srcdir)/libgcc-std.ver $(srcdir)/config/s390/libgcc-glibc.ver
diff --git a/contrib/gcc/config/s390/t-tpf b/contrib/gcc/config/s390/t-tpf
index c04d562..6e4c377 100644
--- a/contrib/gcc/config/s390/t-tpf
+++ b/contrib/gcc/config/s390/t-tpf
@@ -3,11 +3,7 @@ CRTSTUFF_T_CFLAGS_S = $(CRTSTUFF_T_CFLAGS) -fPIC
# Compile libgcc2.a with pic.
TARGET_LIBGCC2_CFLAGS = -fPIC
-# Override t-slibgcc-elf-ver to export some libgcc symbols with
-# the symbol versions that glibc used.
-SHLIB_MAPFILES += $(srcdir)/config/s390/libgcc-glibc.ver
-
-# Use unwind-dw2-fde-glibc
+# Use unwind-dw2-fde-glibc.
LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde-glibc.c \
$(srcdir)/unwind-sjlj.c $(srcdir)/gthr-gnat.c $(srcdir)/unwind-c.c
-LIB2ADDEHDEP = unwind.inc unwind-dw2-fde.h unwind-dw2-fde.c gthr-gnat.c
+LIB2ADDEHDEP = unwind.inc unwind-dw2-fde.h
diff --git a/contrib/gcc/config/s390/tpf-unwind.h b/contrib/gcc/config/s390/tpf-unwind.h
new file mode 100644
index 0000000..87b6892
--- /dev/null
+++ b/contrib/gcc/config/s390/tpf-unwind.h
@@ -0,0 +1,257 @@
+/* DWARF2 EH unwinding support for TPF OS.
+ Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Contributed by P.J. Darcy (darcypj@us.ibm.com).
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file. (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combined
+executable.)
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
+
+#include <dlfcn.h>
+
+/* Function Name: __isPATrange
+ Parameters passed into it: address to check
+ Return Value: A 1 if address is in pat code "range", 0 if not
+ Description: This function simply checks to see if the address
+ passed to it is in the CP pat code range. */
+
+#define MIN_PATRANGE 0x10000
+#define MAX_PATRANGE 0x800000
+
+static inline unsigned int
+__isPATrange (void *addr)
+{
+ if (addr > (void *)MIN_PATRANGE && addr < (void *)MAX_PATRANGE)
+ return 1;
+ else
+ return 0;
+}
+
+/* TPF return address offset from start of stack frame. */
+#define TPFRA_OFFSET 168
+
+/* Exceptions macro defined for TPF so that functions without
+ dwarf frame information can be used with exceptions. */
+#define MD_FALLBACK_FRAME_STATE_FOR s390_fallback_frame_state
+
+static _Unwind_Reason_Code
+s390_fallback_frame_state (struct _Unwind_Context *context,
+ _Unwind_FrameState *fs)
+{
+ unsigned long int regs;
+ unsigned long int new_cfa;
+ int i;
+
+ regs = *((unsigned long int *)
+ (((unsigned long int) context->cfa) - STACK_POINTER_OFFSET));
+
+ /* Are we going through special linkage code? */
+ if (__isPATrange (context->ra))
+ {
+
+ /* Our return register isn't zero for end of stack, so
+ check backward stackpointer to see if it is zero. */
+ if (regs == NULL)
+ return _URC_END_OF_STACK;
+
+ /* No stack frame. */
+ fs->cfa_how = CFA_REG_OFFSET;
+ fs->cfa_reg = 15;
+ fs->cfa_offset = STACK_POINTER_OFFSET;
+
+ /* All registers remain unchanged ... */
+ for (i = 0; i < 32; i++)
+ {
+ fs->regs.reg[i].how = REG_SAVED_REG;
+ fs->regs.reg[i].loc.reg = i;
+ }
+
+ /* ... except for %r14, which is stored at CFA-112
+ and used as return address. */
+ fs->regs.reg[14].how = REG_SAVED_OFFSET;
+ fs->regs.reg[14].loc.offset = TPFRA_OFFSET - STACK_POINTER_OFFSET;
+ fs->retaddr_column = 14;
+
+ return _URC_NO_REASON;
+ }
+
+ regs = *((unsigned long int *)
+ (((unsigned long int) context->cfa) - STACK_POINTER_OFFSET));
+ new_cfa = regs + STACK_POINTER_OFFSET;
+
+ fs->cfa_how = CFA_REG_OFFSET;
+ fs->cfa_reg = 15;
+ fs->cfa_offset = new_cfa -
+ (unsigned long int) context->cfa + STACK_POINTER_OFFSET;
+
+ for (i = 0; i < 16; i++)
+ {
+ fs->regs.reg[i].how = REG_SAVED_OFFSET;
+ fs->regs.reg[i].loc.offset = regs + i*8 - new_cfa;
+ }
+
+ for (i = 0; i < 4; i++)
+ {
+ fs->regs.reg[16 + i].how = REG_SAVED_OFFSET;
+ fs->regs.reg[16 + i].loc.offset = regs + 16*8 + i*8 - new_cfa;
+ }
+
+ fs->retaddr_column = 14;
+
+ return _URC_NO_REASON;
+}
+
+/* Function Name: __tpf_eh_return
+ Parameters passed into it: Destination address to jump to.
+ Return Value: Converted Destination address if a Pat Stub exists.
+ Description: This function swaps the unwinding return address
+ with the cp stub code. The original target return address is
+ then stored into the tpf return address field. The cp stub
+ code is searched for by climbing back up the stack and
+ comparing the tpf stored return address object address to
+ that of the targets object address. */
+
+#define CURRENT_STACK_PTR() \
+ ({ register unsigned long int *stack_ptr asm ("%r15"); stack_ptr; })
+
+#define PREVIOUS_STACK_PTR() \
+ ((unsigned long int *)(*(CURRENT_STACK_PTR())))
+
+#define RA_OFFSET 112
+#define R15_OFFSET 120
+#define TPFAREA_OFFSET 160
+#define TPFAREA_SIZE STACK_POINTER_OFFSET-TPFAREA_OFFSET
+#define INVALID_RETURN 0
+
+void * __tpf_eh_return (void *target);
+
+void *
+__tpf_eh_return (void *target)
+{
+ Dl_info targetcodeInfo, currentcodeInfo;
+ int retval;
+ void *current, *stackptr, *destination_frame;
+ unsigned long int shifter, is_a_stub;
+
+ is_a_stub = 0;
+
+ /* Get code info for target return's address. */
+ retval = dladdr (target, &targetcodeInfo);
+
+ /* Ensure the code info is valid (for target). */
+ if (retval != INVALID_RETURN)
+ {
+
+ /* Get the stack pointer of the stack frame to be modified by
+ the exception unwinder. So that we can begin our climb
+ there. */
+ stackptr = (void *) *((unsigned long int *) (*(PREVIOUS_STACK_PTR())));
+
+ /* Begin looping through stack frames. Stop if invalid
+ code information is retrieved or if a match between the
+ current stack frame iteration shared object's address
+ matches that of the target, calculated above. */
+ do
+ {
+ /* Get return address based on our stackptr iterator. */
+ current = (void *) *((unsigned long int *)
+ (stackptr+RA_OFFSET));
+
+ /* Is it a Pat Stub? */
+ if (__isPATrange (current))
+ {
+ /* Yes it was, get real return address
+ in TPF stack area. */
+ current = (void *) *((unsigned long int *)
+ (stackptr+TPFRA_OFFSET));
+ is_a_stub = 1;
+ }
+
+ /* Get codeinfo on RA so that we can figure out
+ the module address. */
+ retval = dladdr (current, &currentcodeInfo);
+
+ /* Check that codeinfo for current stack frame is valid.
+ Then compare the module address of current stack frame
+ to target stack frame to determine if we have the pat
+ stub address we want. Also ensure we are dealing
+ with a module crossing, stub return address. */
+ if (is_a_stub && retval != INVALID_RETURN
+ && targetcodeInfo.dli_fbase == currentcodeInfo.dli_fbase)
+ {
+ /* Yes! They are in the same module.
+ Force copy of TPF private stack area to
+ destination stack frame TPF private area. */
+ destination_frame = (void *) *((unsigned long int *)
+ (*PREVIOUS_STACK_PTR() + R15_OFFSET));
+
+ /* Copy TPF linkage area from current frame to
+ destination frame. */
+ memcpy((void *) (destination_frame + TPFAREA_OFFSET),
+ (void *) (stackptr + TPFAREA_OFFSET), TPFAREA_SIZE);
+
+ /* Now overlay the
+ real target address into the TPF stack area of
+ the target frame we are jumping to. */
+ *((unsigned long int *) (destination_frame +
+ TPFRA_OFFSET)) = (unsigned long int) target;
+
+ /* Before returning the desired pat stub address to
+ the exception handling unwinder so that it can
+ actually do the "leap" shift out the low order
+ bit designated to determine if we are in 64BIT mode.
+ This is necessary for CTOA stubs.
+ Otherwise we leap one byte past where we want to
+ go to in the TPF pat stub linkage code. */
+ shifter = *((unsigned long int *)
+ (stackptr + RA_OFFSET));
+
+ shifter &= ~1ul;
+
+ /* Store Pat Stub Address in destination Stack Frame. */
+ *((unsigned long int *) (destination_frame +
+ RA_OFFSET)) = shifter;
+
+ /* Re-adjust pat stub address to go to correct place
+ in linkage. */
+ shifter = shifter - 4;
+
+ return (void *) shifter;
+ }
+
+ /* Desired module pat stub not found ...
+ Bump stack frame iterator. */
+ stackptr = (void *) *(unsigned long int *) stackptr;
+
+ is_a_stub = 0;
+
+ } while (stackptr && retval != INVALID_RETURN
+ && targetcodeInfo.dli_fbase != currentcodeInfo.dli_fbase);
+ }
+
+ /* No pat stub found, could be a problem? Simply return unmodified
+ target address. */
+ return target;
+}
+
diff --git a/contrib/gcc/config/s390/tpf.h b/contrib/gcc/config/s390/tpf.h
index 3015827..f0a63f7 100644
--- a/contrib/gcc/config/s390/tpf.h
+++ b/contrib/gcc/config/s390/tpf.h
@@ -1,5 +1,5 @@
/* Definitions for target OS TPF for GNU compiler, for IBM S/390 hardware
- Copyright (C) 2003 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005 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).
@@ -18,21 +18,21 @@ for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
#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_HAS_F_SETLKW
-#undef MD_EXEC_PREFIX
-#undef MD_STARTFILE_PREFIX
+#define TARGET_POSIX_IO
#undef SIZE_TYPE
#define SIZE_TYPE ("long unsigned int")
@@ -50,11 +50,19 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
/* TPF OS specific stack-pointer offset. */
#undef STACK_POINTER_OFFSET
-#define STACK_POINTER_OFFSET 280
+#define STACK_POINTER_OFFSET 448
-/* When building for TPF, set a generic default target that is 64 bits. */
+/* 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 0x33
+#define TARGET_DEFAULT (MASK_TPF_PROFILING | MASK_64BIT | MASK_ZARCH \
+ | MASK_HARD_FLOAT | 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
@@ -64,52 +72,59 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
builtin_define_std ("tpf"); \
builtin_assert ("system=tpf"); \
builtin_define ("__ELF__"); \
- if (flag_pic) \
- { \
- builtin_define ("__PIC__"); \
- builtin_define ("__pic__"); \
- } \
} \
while (0)
+#define EXTRA_SPECS \
+ { "entry_spec", ENTRY_SPEC }
+
/* Make TPF specific spec file settings here. */
-#undef STARTFILE_SPEC
+#undef STARTFILE_SPEC
#define STARTFILE_SPEC \
- "%{!shared: \
- %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} \
- %{!p:%{profile:gcrt1.o%s} \
- %{!profile:crt1.o%s}}}} \
- crti.o%s %{static:crtbeginT.o%s} \
- %{!static:%{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}}"
+ "%{mmain:crt0%O%s} crtbeginS%O%s crt3%O%s"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC "crtendS%O%s"
-#undef ENDFILE_SPEC
-#define ENDFILE_SPEC \
- "%{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.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=*}"
+#undef ASM_SPEC
+#define ASM_SPEC "%{m31&m64}%{mesa&mzarch}%{march=*} \
+ -alshd=%b.lst"
-#undef LIB_SPEC
-#define LIB_SPEC "%{pthread:-lpthread} -lc"
+/* 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 \
- %{shared:-shared} \
- %{!shared: \
- %{static:-static} \
- %{!static: \
- %{rdynamic:-export-dynamic} \
- %{!dynamic-linker:-dynamic-linker /lib/ld64.so}}}"
+ %{static:%estatic is not supported on TPF-OS} \
+ %{shared: -shared} \
+ %{!shared:-shared} \
+ %(entry_spec)"
-#endif /* ! _TPF_H */
+#define MD_UNWIND_SUPPORT "config/s390/tpf-unwind.h"
+/* IBM copies these libraries over with these names. */
+#define MATH_LIBRARY "-lCLBM"
+#define LIBSTDCXX "-lCPP1"
+#endif /* ! _TPF_H */
diff --git a/contrib/gcc/config/s390/tpf.md b/contrib/gcc/config/s390/tpf.md
new file mode 100644
index 0000000..87a2616
--- /dev/null
+++ b/contrib/gcc/config/s390/tpf.md
@@ -0,0 +1,34 @@
+;; S390 TPF-OS specific machine patterns
+;; Copyright (C) 2005 Free Software Foundation, Inc.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING. If not, write to
+;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+(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/contrib/gcc/config/s390/tpf.opt b/contrib/gcc/config/s390/tpf.opt
new file mode 100644
index 0000000..7f12402
--- /dev/null
+++ b/contrib/gcc/config/s390/tpf.opt
@@ -0,0 +1,28 @@
+; Options for the TPF-OS port of the compiler.
+
+; Copyright (C) 2005 Free Software Foundation, Inc.
+;
+; This file is part of GCC.
+;
+; GCC is free software; you can redistribute it and/or modify it under
+; the terms of the GNU General Public License as published by the Free
+; Software Foundation; either version 2, or (at your option) any later
+; version.
+;
+; GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+; WARRANTY; without even the implied warranty of MERCHANTABILITY or
+; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+; for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with GCC; see the file COPYING. If not, write to the Free
+; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+; 02110-1301, USA.
+
+mtpf-trace
+Target Report Mask(TPF_PROFILING)
+Enable TPF-OS tracing code
+
+mmain
+Target Report
+Specify main object for TPF-OS
OpenPOWER on IntegriCloud