1;; Predicate definitions for S/390 and zSeries.
2;; Copyright (C) 2005 Free Software Foundation, Inc.
3;; Contributed by Hartmut Penner (hpenner@de.ibm.com) and
4;;                Ulrich Weigand (uweigand@de.ibm.com).
5;;
6;; This file is part of GCC.
7;;
8;; GCC is free software; you can redistribute it and/or modify
9;; it under the terms of the GNU General Public License as published by
10;; the Free Software Foundation; either version 2, or (at your option)
11;; any later version.
12;;
13;; GCC is distributed in the hope that it will be useful,
14;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16;; GNU General Public License for more details.
17;;
18;; You should have received a copy of the GNU General Public License
19;; along with GCC; see the file COPYING.  If not, write to
20;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
21;; Boston, MA 02110-1301, USA.
22
23;; OP is the current operation.
24;; MODE is the current operation mode.
25
26;; operands --------------------------------------------------------------
27
28;; Return true if OP a (const_int 0) operand.
29
30(define_predicate "const0_operand"
31  (and (match_code "const_int, const_double")
32       (match_test "op == CONST0_RTX (mode)")))
33
34;; Return true if OP is constant.
35
36(define_special_predicate "consttable_operand"
37  (and (match_code "symbol_ref, label_ref, const, const_int, const_double")
38       (match_test "CONSTANT_P (op)")))
39
40;; Return true if OP is a valid S-type operand.
41
42(define_predicate "s_operand"
43  (and (match_code "subreg, mem")
44       (match_operand 0 "general_operand"))
45{
46  /* Just like memory_operand, allow (subreg (mem ...))
47     after reload.  */
48  if (reload_completed
49      && GET_CODE (op) == SUBREG
50      && GET_CODE (SUBREG_REG (op)) == MEM)
51    op = SUBREG_REG (op);
52
53  if (GET_CODE (op) != MEM)
54    return false;
55  if (!s390_legitimate_address_without_index_p (op))
56    return false;
57
58  return true;
59})
60
61;; Return true if OP is a valid operand for the BRAS instruction.
62;; Allow SYMBOL_REFs and @PLT stubs.
63
64(define_special_predicate "bras_sym_operand"
65  (ior (and (match_code "symbol_ref")
66	    (match_test "!flag_pic || SYMBOL_REF_LOCAL_P (op)"))
67       (and (match_code "const")
68	    (and (match_test "GET_CODE (XEXP (op, 0)) == UNSPEC")
69		 (match_test "XINT (XEXP (op, 0), 1) == UNSPEC_PLT")))))
70
71;; Return true if OP is a PLUS that is not a legitimate
72;; operand for the LA instruction.
73
74(define_predicate "s390_plus_operand"
75  (and (match_code "plus")
76       (and (match_test "mode == Pmode")
77	    (match_test "!legitimate_la_operand_p (op)"))))
78
79;; Return true if OP is a valid operand as shift count or setmem.
80
81(define_predicate "shift_count_or_setmem_operand"
82  (match_code "reg, subreg, plus, const_int")
83{
84  HOST_WIDE_INT offset;
85  rtx base;
86
87  /* Extract base register and offset.  */
88  if (!s390_decompose_shift_count (op, &base, &offset))
89    return false;
90
91  /* Don't allow any non-base hard registers.  Doing so without
92     confusing reload and/or regrename would be tricky, and doesn't
93     buy us much anyway.  */
94  if (base && REGNO (base) < FIRST_PSEUDO_REGISTER && !ADDR_REG_P (base))
95    return false;
96
97  /* Unfortunately we have to reject constants that are invalid
98     for an address, or else reload will get confused.  */
99  if (!DISP_IN_RANGE (offset))
100    return false;
101
102  return true;
103})
104
105;;  Return true if OP a valid operand for the LARL instruction.
106
107(define_predicate "larl_operand"
108  (match_code "label_ref, symbol_ref, const, const_int, const_double")
109{
110  /* Allow labels and local symbols.  */
111  if (GET_CODE (op) == LABEL_REF)
112    return true;
113  if (GET_CODE (op) == SYMBOL_REF)
114    return ((SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_ALIGN1) == 0
115	    && SYMBOL_REF_TLS_MODEL (op) == 0
116	    && (!flag_pic || SYMBOL_REF_LOCAL_P (op)));
117
118  /* Everything else must have a CONST, so strip it.  */
119  if (GET_CODE (op) != CONST)
120    return false;
121  op = XEXP (op, 0);
122
123  /* Allow adding *even* in-range constants.  */
124  if (GET_CODE (op) == PLUS)
125    {
126      if (GET_CODE (XEXP (op, 1)) != CONST_INT
127          || (INTVAL (XEXP (op, 1)) & 1) != 0)
128        return false;
129      if (INTVAL (XEXP (op, 1)) >= (HOST_WIDE_INT)1 << 31
130	  || INTVAL (XEXP (op, 1)) < -((HOST_WIDE_INT)1 << 31))
131        return false;
132      op = XEXP (op, 0);
133    }
134
135  /* Labels and local symbols allowed here as well.  */
136  if (GET_CODE (op) == LABEL_REF)
137    return true;
138  if (GET_CODE (op) == SYMBOL_REF)
139    return ((SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_ALIGN1) == 0
140	    && SYMBOL_REF_TLS_MODEL (op) == 0
141	    && (!flag_pic || SYMBOL_REF_LOCAL_P (op)));
142
143  /* Now we must have a @GOTENT offset or @PLT stub
144     or an @INDNTPOFF TLS offset.  */
145  if (GET_CODE (op) == UNSPEC
146      && XINT (op, 1) == UNSPEC_GOTENT)
147    return true;
148  if (GET_CODE (op) == UNSPEC
149      && XINT (op, 1) == UNSPEC_PLT)
150    return true;
151  if (GET_CODE (op) == UNSPEC
152      && XINT (op, 1) == UNSPEC_INDNTPOFF)
153    return true;
154
155  return false;
156})
157
158;; operators --------------------------------------------------------------
159
160;; Return nonzero if OP is a valid comparison operator
161;; for a branch condition.
162
163(define_predicate "s390_comparison"
164  (match_code "eq, ne, lt, gt, le, ge, ltu, gtu, leu, geu,
165	       uneq, unlt, ungt, unle, unge, ltgt,
166	       unordered, ordered")
167{
168  if (GET_CODE (XEXP (op, 0)) != REG
169      || REGNO (XEXP (op, 0)) != CC_REGNUM
170      || XEXP (op, 1) != const0_rtx)
171    return false;
172
173  return (s390_branch_condition_mask (op) >= 0);
174})
175
176;; Return nonzero if OP is a valid comparison operator
177;; for an ALC condition.
178
179(define_predicate "s390_alc_comparison"
180  (match_code "zero_extend, sign_extend, ltu, gtu, leu, geu")
181{
182  while (GET_CODE (op) == ZERO_EXTEND || GET_CODE (op) == SIGN_EXTEND)
183    op = XEXP (op, 0);
184
185  if (!COMPARISON_P (op))
186    return false;
187
188  if (GET_CODE (XEXP (op, 0)) != REG
189      || REGNO (XEXP (op, 0)) != CC_REGNUM
190      || XEXP (op, 1) != const0_rtx)
191    return false;
192
193  switch (GET_MODE (XEXP (op, 0)))
194    {
195    case CCL1mode:
196      return GET_CODE (op) == LTU;
197
198    case CCL2mode:
199      return GET_CODE (op) == LEU;
200
201    case CCL3mode:
202      return GET_CODE (op) == GEU;
203
204    case CCUmode:
205      return GET_CODE (op) == GTU;
206
207    case CCURmode:
208      return GET_CODE (op) == LTU;
209
210    case CCSmode:
211      return GET_CODE (op) == UNGT;
212
213    case CCSRmode:
214      return GET_CODE (op) == UNLT;
215
216    default:
217      return false;
218    }
219})
220
221;; Return nonzero if OP is a valid comparison operator
222;; for an SLB condition.
223
224(define_predicate "s390_slb_comparison"
225  (match_code "zero_extend, sign_extend, ltu, gtu, leu, geu")
226{
227  while (GET_CODE (op) == ZERO_EXTEND || GET_CODE (op) == SIGN_EXTEND)
228    op = XEXP (op, 0);
229
230  if (!COMPARISON_P (op))
231    return false;
232
233  if (GET_CODE (XEXP (op, 0)) != REG
234      || REGNO (XEXP (op, 0)) != CC_REGNUM
235      || XEXP (op, 1) != const0_rtx)
236    return false;
237
238  switch (GET_MODE (XEXP (op, 0)))
239    {
240    case CCL1mode:
241      return GET_CODE (op) == GEU;
242
243    case CCL2mode:
244      return GET_CODE (op) == GTU;
245
246    case CCL3mode:
247      return GET_CODE (op) == LTU;
248
249    case CCUmode:
250      return GET_CODE (op) == LEU;
251
252    case CCURmode:
253      return GET_CODE (op) == GEU;
254
255    case CCSmode:
256      return GET_CODE (op) == LE;
257
258    case CCSRmode:
259      return GET_CODE (op) == GE;
260
261    default:
262      return false;
263    }
264})
265
266;; Return true if OP is a load multiple operation.  It is known to be a
267;; PARALLEL and the first section will be tested.
268
269(define_special_predicate "load_multiple_operation"
270  (match_code "parallel")
271{
272  enum machine_mode elt_mode;
273  int count = XVECLEN (op, 0);
274  unsigned int dest_regno;
275  rtx src_addr;
276  int i, off;
277
278  /* Perform a quick check so we don't blow up below.  */
279  if (count <= 1
280      || GET_CODE (XVECEXP (op, 0, 0)) != SET
281      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
282      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
283    return false;
284
285  dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
286  src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
287  elt_mode = GET_MODE (SET_DEST (XVECEXP (op, 0, 0)));
288
289  /* Check, is base, or base + displacement.  */
290
291  if (GET_CODE (src_addr) == REG)
292    off = 0;
293  else if (GET_CODE (src_addr) == PLUS
294	   && GET_CODE (XEXP (src_addr, 0)) == REG
295	   && GET_CODE (XEXP (src_addr, 1)) == CONST_INT)
296    {
297      off = INTVAL (XEXP (src_addr, 1));
298      src_addr = XEXP (src_addr, 0);
299    }
300  else
301    return false;
302
303  for (i = 1; i < count; i++)
304    {
305      rtx elt = XVECEXP (op, 0, i);
306
307      if (GET_CODE (elt) != SET
308	  || GET_CODE (SET_DEST (elt)) != REG
309	  || GET_MODE (SET_DEST (elt)) != elt_mode
310	  || REGNO (SET_DEST (elt)) != dest_regno + i
311	  || GET_CODE (SET_SRC (elt)) != MEM
312	  || GET_MODE (SET_SRC (elt)) != elt_mode
313	  || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
314	  || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
315	  || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
316	  || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1))
317	     != off + i * GET_MODE_SIZE (elt_mode))
318	return false;
319    }
320
321  return true;
322})
323
324;; Return true if OP is a store multiple operation.  It is known to be a
325;; PARALLEL and the first section will be tested.
326
327(define_special_predicate "store_multiple_operation"
328  (match_code "parallel")
329{
330  enum machine_mode elt_mode;
331  int count = XVECLEN (op, 0);
332  unsigned int src_regno;
333  rtx dest_addr;
334  int i, off;
335
336  /* Perform a quick check so we don't blow up below.  */
337  if (count <= 1
338      || GET_CODE (XVECEXP (op, 0, 0)) != SET
339      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
340      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
341    return false;
342
343  src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
344  dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
345  elt_mode = GET_MODE (SET_SRC (XVECEXP (op, 0, 0)));
346
347  /* Check, is base, or base + displacement.  */
348
349  if (GET_CODE (dest_addr) == REG)
350    off = 0;
351  else if (GET_CODE (dest_addr) == PLUS
352	   && GET_CODE (XEXP (dest_addr, 0)) == REG
353	   && GET_CODE (XEXP (dest_addr, 1)) == CONST_INT)
354    {
355      off = INTVAL (XEXP (dest_addr, 1));
356      dest_addr = XEXP (dest_addr, 0);
357    }
358  else
359    return false;
360
361  for (i = 1; i < count; i++)
362    {
363      rtx elt = XVECEXP (op, 0, i);
364
365      if (GET_CODE (elt) != SET
366	  || GET_CODE (SET_SRC (elt)) != REG
367	  || GET_MODE (SET_SRC (elt)) != elt_mode
368	  || REGNO (SET_SRC (elt)) != src_regno + i
369	  || GET_CODE (SET_DEST (elt)) != MEM
370	  || GET_MODE (SET_DEST (elt)) != elt_mode
371	  || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
372	  || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
373	  || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
374	  || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1))
375	     != off + i * GET_MODE_SIZE (elt_mode))
376	return false;
377    }
378  return true;
379})
380