Update Copyright years for files modified in 2010.
[official-gcc.git] / gcc / config / rx / predicates.md
blobe1b3f0c9f913ac0f82f4d8d36c5739cd766582e5
1 ;; Predicate definitions for Renesas RX.
2 ;; Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
3 ;; Contributed by Red Hat.
4 ;;
5 ;; This file is part of GCC.
6 ;;
7 ;; GCC is free software; you can redistribute it and/or modify
8 ;; it under the terms of the GNU General Public License as published by
9 ;; the Free Software Foundation; either version 3, or (at your option)
10 ;; any later version.
12 ;; GCC is distributed in the hope that it will be useful,
13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ;; GNU General Public License for more details.
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with GCC; see the file COPYING3.  If not see
19 ;; <http://www.gnu.org/licenses/>.
23 ;; Check that the operand is suitable for a call insn.
24 ;; Only registers and symbol refs are allowed.
26 (define_predicate "rx_call_operand"
27   (match_code "symbol_ref,reg")
30 ;; For sibcall operations we can only use a symbolic address.
32 (define_predicate "rx_symbolic_call_operand"
33   (match_code "symbol_ref")
36 ;; Check that the operand is suitable for a shift insn
37 ;; Only small integers or a value in a register are permitted.
39 (define_predicate "rx_shift_operand"
40   (match_code "const_int,reg")
41   {
42     if (CONST_INT_P (op))
43       return IN_RANGE (INTVAL (op), 0, 31);
44     return true;
45   }
48 (define_predicate "rx_constshift_operand"
49   (match_code "const_int")
50   {
51     return IN_RANGE (INTVAL (op), 0, 31);
52   }
55 ;; Check that the operand is suitable as the source operand
56 ;; for a logic or arithmeitc instruction.  Registers, integers
57 ;; and a restricted subset of memory addresses are allowed.
59 (define_predicate "rx_source_operand"
60   (match_code "const_int,const_double,const,symbol_ref,label_ref,reg,mem")
61   {
62     if (CONSTANT_P (op))
63       return rx_is_legitimate_constant (op);
65     if (! MEM_P (op))
66       return true;
67       
68     /* Do not allow size conversions whilst accessing memory.  */
69     if (GET_MODE (op) != mode)
70       return false;
72     return rx_is_restricted_memory_address (XEXP (op, 0), mode);
73   }
76 ;; Check that the operand is suitable as the source operand
77 ;; for a comparison instruction.  This is the same as
78 ;; rx_source_operand except that SUBREGs are allowed but
79 ;; CONST_INTs are not.
81 (define_predicate "rx_compare_operand"
82   (match_code "subreg,reg,mem")
83   {
84     if (GET_CODE (op) == SUBREG)
85       return REG_P (XEXP (op, 0));
86     
87     if (! MEM_P (op))
88       return true;
90     return rx_is_restricted_memory_address (XEXP (op, 0), mode);
91   }
94 ;; Return true if OP is a store multiple operation.  This looks like:
96 ;;   [(set (SP) (MINUS (SP) (INT)))
97 ;;    (set (MEM (SP)) (REG))
98 ;;    (set (MEM (MINUS (SP) (INT))) (REG)) {optionally repeated}
99 ;;   ]
101 (define_special_predicate "rx_store_multiple_vector"
102   (match_code "parallel")
104   int count = XVECLEN (op, 0);
105   unsigned int src_regno;
106   rtx element;
107   int i;
109   /* Perform a quick check so we don't blow up below.  */
110   if (count <= 2)
111     return false;
113   /* Check that the first element of the vector is the stack adjust.  */
114   element = XVECEXP (op, 0, 0);
115   if (   ! SET_P (element)
116       || ! REG_P (SET_DEST (element))
117       ||   REGNO (SET_DEST (element)) != SP_REG
118       ||   GET_CODE (SET_SRC (element)) != MINUS
119       || ! REG_P (XEXP (SET_SRC (element), 0))
120       ||   REGNO (XEXP (SET_SRC (element), 0)) != SP_REG
121       || ! CONST_INT_P (XEXP (SET_SRC (element), 1)))
122     return false;
123          
124   /* Check that the next element is the first push.  */
125   element = XVECEXP (op, 0, 1);
126   if (   ! SET_P (element)
127       || ! REG_P (SET_SRC (element))
128       || GET_MODE (SET_SRC (element)) != SImode
129       || ! MEM_P (SET_DEST (element))
130       || GET_MODE (SET_DEST (element)) != SImode
131       || GET_CODE (XEXP (SET_DEST (element), 0)) != MINUS
132       || ! REG_P (XEXP (XEXP (SET_DEST (element), 0), 0))
133       ||   REGNO (XEXP (XEXP (SET_DEST (element), 0), 0)) != SP_REG
134       || ! CONST_INT_P (XEXP (XEXP (SET_DEST (element), 0), 1))
135       || INTVAL (XEXP (XEXP (SET_DEST (element), 0), 1))
136         != GET_MODE_SIZE (SImode))
137     return false;
139   src_regno = REGNO (SET_SRC (element));
141   /* Check that the remaining elements use SP-<disp>
142      addressing and decreasing register numbers.  */
143   for (i = 2; i < count; i++)
144     {
145       element = XVECEXP (op, 0, i);
147       if (   ! SET_P (element)
148           || ! REG_P (SET_SRC (element))
149           || GET_MODE (SET_SRC (element)) != SImode
150           || REGNO (SET_SRC (element)) != src_regno - (i - 1)
151           || ! MEM_P (SET_DEST (element))
152           || GET_MODE (SET_DEST (element)) != SImode
153           || GET_CODE (XEXP (SET_DEST (element), 0)) != MINUS
154           || ! REG_P (XEXP (XEXP (SET_DEST (element), 0), 0))
155           ||   REGNO (XEXP (XEXP (SET_DEST (element), 0), 0)) != SP_REG
156           || ! CONST_INT_P (XEXP (XEXP (SET_DEST (element), 0), 1))
157           || INTVAL (XEXP (XEXP (SET_DEST (element), 0), 1))
158              != i * GET_MODE_SIZE (SImode))
159         return false;
160     }
161   return true;
164 ;; Return true if OP is a load multiple operation.
165 ;; This looks like:
166 ;;  [(set (SP) (PLUS (SP) (INT)))
167 ;;   (set (REG) (MEM (SP)))
168 ;;   (set (REG) (MEM (PLUS (SP) (INT)))) {optionally repeated}
169 ;;  ]
171 (define_special_predicate "rx_load_multiple_vector"
172   (match_code "parallel")
174   int count = XVECLEN (op, 0);
175   unsigned int dest_regno;
176   rtx element;
177   int i;
179   /* Perform a quick check so we don't blow up below.  */
180   if (count <= 2)
181     return false;
183   /* Check that the first element of the vector is the stack adjust.  */
184   element = XVECEXP (op, 0, 0);
185   if (   ! SET_P (element)
186       || ! REG_P (SET_DEST (element))
187       ||   REGNO (SET_DEST (element)) != SP_REG
188       ||   GET_CODE (SET_SRC (element)) != PLUS
189       || ! REG_P (XEXP (SET_SRC (element), 0))
190       ||   REGNO (XEXP (SET_SRC (element), 0)) != SP_REG
191       || ! CONST_INT_P (XEXP (SET_SRC (element), 1)))
192     return false;
193          
194   /* Check that the next element is the first push.  */
195   element = XVECEXP (op, 0, 1);
196   if (   ! SET_P (element)
197       || ! REG_P (SET_DEST (element))
198       || ! MEM_P (SET_SRC (element))
199       || ! REG_P (XEXP (SET_SRC (element), 0))
200       ||   REGNO (XEXP (SET_SRC (element), 0)) != SP_REG)
201     return false;
203   dest_regno = REGNO (SET_DEST (element));
205   /* Check that the remaining elements use SP+<disp>
206      addressing and incremental register numbers.  */
207   for (i = 2; i < count; i++)
208     {
209       element = XVECEXP (op, 0, i);
211       if (   ! SET_P (element)
212           || ! REG_P (SET_DEST (element))
213           || GET_MODE (SET_DEST (element)) != SImode
214           || REGNO (SET_DEST (element)) != dest_regno + (i - 1)
215           || ! MEM_P (SET_SRC (element))
216           || GET_MODE (SET_SRC (element)) != SImode
217           || GET_CODE (XEXP (SET_SRC (element), 0)) != PLUS
218           || ! REG_P (XEXP (XEXP (SET_SRC (element), 0), 0))
219           ||   REGNO (XEXP (XEXP (SET_SRC (element), 0), 0)) != SP_REG
220           || ! CONST_INT_P (XEXP (XEXP (SET_SRC (element), 0), 1))
221           || INTVAL (XEXP (XEXP (SET_SRC (element), 0), 1))
222              != (i - 1) * GET_MODE_SIZE (SImode))
223         return false;
224     }
225   return true;
228 ;; Return true if OP is a pop-and-return load multiple operation.
229 ;; This looks like:
230 ;;  [(set (SP) (PLUS (SP) (INT)))
231 ;;   (set (REG) (MEM (SP)))
232 ;;   (set (REG) (MEM (PLUS (SP) (INT)))) {optional and possibly repeated}
233 ;;   (return)
234 ;;  ]
236 (define_special_predicate "rx_rtsd_vector"
237   (match_code "parallel")
239   int count = XVECLEN (op, 0);
240   unsigned int dest_regno;
241   rtx element;
242   int i;
244   /* Perform a quick check so we don't blow up below.  */
245   if (count <= 2)
246     return false;
248   /* Check that the first element of the vector is the stack adjust.  */
249   element = XVECEXP (op, 0, 0);
250   if (   ! SET_P (element)
251       || ! REG_P (SET_DEST (element))
252       ||   REGNO (SET_DEST (element)) != SP_REG
253       ||   GET_CODE (SET_SRC (element)) != PLUS
254       || ! REG_P (XEXP (SET_SRC (element), 0))
255       ||   REGNO (XEXP (SET_SRC (element), 0)) != SP_REG
256       || ! CONST_INT_P (XEXP (SET_SRC (element), 1)))
257     return false;
258          
259   /* Check that the next element is the first push.  */
260   element = XVECEXP (op, 0, 1);
261   if (   ! SET_P (element)
262       || ! REG_P (SET_DEST (element))
263       || ! MEM_P (SET_SRC (element))
264       || ! REG_P (XEXP (SET_SRC (element), 0))
265       ||   REGNO (XEXP (SET_SRC (element), 0)) != SP_REG)
266     return false;
268   dest_regno = REGNO (SET_DEST (element));
270   /* Check that the remaining elements, if any, and except
271      for the last one, use SP+<disp> addressing and incremental
272      register numbers.  */
273   for (i = 2; i < count - 1; i++)
274     {
275       element = XVECEXP (op, 0, i);
277       if (   ! SET_P (element)
278           || ! REG_P (SET_DEST (element))
279           || GET_MODE (SET_DEST (element)) != SImode
280           || REGNO (SET_DEST (element)) != dest_regno + (i - 1)
281           || ! MEM_P (SET_SRC (element))
282           || GET_MODE (SET_SRC (element)) != SImode
283           || GET_CODE (XEXP (SET_SRC (element), 0)) != PLUS
284           || ! REG_P (XEXP (XEXP (SET_SRC (element), 0), 0))
285           ||   REGNO (XEXP (XEXP (SET_SRC (element), 0), 0)) != SP_REG
286           || ! CONST_INT_P (XEXP (XEXP (SET_SRC (element), 0), 1))
287           || INTVAL (XEXP (XEXP (SET_SRC (element), 0), 1))
288              != (i - 1) * GET_MODE_SIZE (SImode))
289         return false;
290     }
292   /* The last element must be a RETURN.  */    
293   element = XVECEXP (op, 0, count - 1);
294   return GET_CODE (element) == RETURN;