OSDN Git Service

* MAINTAINERS: Add myself as a maintainer for the RX port.
[pf3gnuchains/gcc-fork.git] / gcc / config / rx / predicates.md
1 ;; Predicate definitions for Renesas RX.
2 ;; Copyright (C) 2008, 2009 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.
11 ;;
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.
16 ;;
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/>.
20
21
22
23 ;; Check that the operand is suitable for a call insn.
24 ;; Only registers and symbol refs are allowed.
25
26 (define_predicate "rx_call_operand"
27   (match_code "symbol_ref,reg")
28 )
29
30 ;; For sibcall operations we can only use a symbolic address.
31
32 (define_predicate "rx_symbolic_call_operand"
33   (match_code "symbol_ref")
34 )
35
36 ;; Check that the operand is suitable for a shift insn
37 ;; Only small integers or a value in a register are permitted.
38
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   }
46 )
47
48 ;; Check that the operand is suitable as the source operand
49 ;; for a logic or arithmeitc instruction.  Registers, integers
50 ;; and a restricted subset of memory addresses are allowed.
51
52 (define_predicate "rx_source_operand"
53   (match_code "const_int,reg,mem")
54   {
55     if (CONST_INT_P (op))
56       return rx_is_legitimate_constant (op);
57
58     if (! MEM_P (op))
59       return true;
60       
61     /* Do not allow size conversions whilst accessing memory.  */
62     if (GET_MODE (op) != mode)
63       return false;
64
65     return rx_is_restricted_memory_address (XEXP (op, 0), mode);
66   }
67 )
68
69 ;; Check that the operand is suitable as the source operand
70 ;; for a comparison instruction.  This is the same as
71 ;; rx_source_operand except that SUBREGs are allowed but
72 ;; CONST_INTs are not.
73
74 (define_predicate "rx_compare_operand"
75   (match_code "subreg,reg,mem")
76   {
77     if (GET_CODE (op) == SUBREG)
78       return REG_P (XEXP (op, 0));
79     
80     if (! MEM_P (op))
81       return true;
82
83     return rx_is_restricted_memory_address (XEXP (op, 0), mode);
84   }
85 )
86
87 ;; Return true if OP is a store multiple operation.  This looks like:
88 ;;
89 ;;   [(set (SP) (MINUS (SP) (INT)))
90 ;;    (set (MEM (SP)) (REG))
91 ;;    (set (MEM (MINUS (SP) (INT))) (REG)) {optionally repeated}
92 ;;   ]
93
94 (define_special_predicate "rx_store_multiple_vector"
95   (match_code "parallel")
96 {
97   int count = XVECLEN (op, 0);
98   unsigned int src_regno;
99   rtx element;
100   int i;
101
102   /* Perform a quick check so we don't blow up below.  */
103   if (count <= 2)
104     return false;
105
106   /* Check that the first element of the vector is the stack adjust.  */
107   element = XVECEXP (op, 0, 0);
108   if (   ! SET_P (element)
109       || ! REG_P (SET_DEST (element))
110       ||   REGNO (SET_DEST (element)) != SP_REG
111       ||   GET_CODE (SET_SRC (element)) != MINUS
112       || ! REG_P (XEXP (SET_SRC (element), 0))
113       ||   REGNO (XEXP (SET_SRC (element), 0)) != SP_REG
114       || ! CONST_INT_P (XEXP (SET_SRC (element), 1)))
115     return false;
116          
117   /* Check that the next element is the first push.  */
118   element = XVECEXP (op, 0, 1);
119   if (   ! SET_P (element)
120       || ! MEM_P (SET_DEST (element))
121       || ! REG_P (XEXP (SET_DEST (element), 0))
122       ||   REGNO (XEXP (SET_DEST (element), 0)) != SP_REG
123       || ! REG_P (SET_SRC (element)))
124     return false;
125
126   src_regno = REGNO (SET_SRC (element));
127
128   /* Check that the remaining elements use SP-<disp>
129      addressing and incremental register numbers.  */
130   for (i = 2; i < count; i++)
131     {
132       element = XVECEXP (op, 0, i);
133
134       if (   ! SET_P (element)
135           || ! REG_P (SET_SRC (element))
136           || GET_MODE (SET_SRC (element)) != SImode
137           || REGNO (SET_SRC (element)) != src_regno + (i - 1)
138           || ! MEM_P (SET_DEST (element))
139           || GET_MODE (SET_DEST (element)) != SImode
140           || GET_CODE (XEXP (SET_DEST (element), 0)) != MINUS
141           || ! REG_P (XEXP (XEXP (SET_DEST (element), 0), 0))
142           ||   REGNO (XEXP (XEXP (SET_DEST (element), 0), 0)) != SP_REG
143           || ! CONST_INT_P (XEXP (XEXP (SET_DEST (element), 0), 1))
144           || INTVAL (XEXP (XEXP (SET_DEST (element), 0), 1))
145              != (i - 1) * GET_MODE_SIZE (SImode))
146         return false;
147     }
148   return true;
149 })
150
151 ;; Return true if OP is a load multiple operation.
152 ;; This looks like:
153 ;;  [(set (SP) (PLUS (SP) (INT)))
154 ;;   (set (REG) (MEM (SP)))
155 ;;   (set (REG) (MEM (PLUS (SP) (INT)))) {optionally repeated}
156 ;;  ]
157
158 (define_special_predicate "rx_load_multiple_vector"
159   (match_code "parallel")
160 {
161   int count = XVECLEN (op, 0);
162   unsigned int dest_regno;
163   rtx element;
164   int i;
165
166   /* Perform a quick check so we don't blow up below.  */
167   if (count <= 2)
168     return false;
169
170   /* Check that the first element of the vector is the stack adjust.  */
171   element = XVECEXP (op, 0, 0);
172   if (   ! SET_P (element)
173       || ! REG_P (SET_DEST (element))
174       ||   REGNO (SET_DEST (element)) != SP_REG
175       ||   GET_CODE (SET_SRC (element)) != PLUS
176       || ! REG_P (XEXP (SET_SRC (element), 0))
177       ||   REGNO (XEXP (SET_SRC (element), 0)) != SP_REG
178       || ! CONST_INT_P (XEXP (SET_SRC (element), 1)))
179     return false;
180          
181   /* Check that the next element is the first push.  */
182   element = XVECEXP (op, 0, 1);
183   if (   ! SET_P (element)
184       || ! REG_P (SET_DEST (element))
185       || ! MEM_P (SET_SRC (element))
186       || ! REG_P (XEXP (SET_SRC (element), 0))
187       ||   REGNO (XEXP (SET_SRC (element), 0)) != SP_REG)
188     return false;
189
190   dest_regno = REGNO (SET_DEST (element));
191
192   /* Check that the remaining elements use SP+<disp>
193      addressing and incremental register numbers.  */
194   for (i = 2; i < count; i++)
195     {
196       element = XVECEXP (op, 0, i);
197
198       if (   ! SET_P (element)
199           || ! REG_P (SET_DEST (element))
200           || GET_MODE (SET_DEST (element)) != SImode
201           || REGNO (SET_DEST (element)) != dest_regno + (i - 1)
202           || ! MEM_P (SET_SRC (element))
203           || GET_MODE (SET_SRC (element)) != SImode
204           || GET_CODE (XEXP (SET_SRC (element), 0)) != PLUS
205           || ! REG_P (XEXP (XEXP (SET_SRC (element), 0), 0))
206           ||   REGNO (XEXP (XEXP (SET_SRC (element), 0), 0)) != SP_REG
207           || ! CONST_INT_P (XEXP (XEXP (SET_SRC (element), 0), 1))
208           || INTVAL (XEXP (XEXP (SET_SRC (element), 0), 1))
209              != (i - 1) * GET_MODE_SIZE (SImode))
210         return false;
211     }
212   return true;
213 })
214
215 ;; Return true if OP is a pop-and-return load multiple operation.
216 ;; This looks like:
217 ;;  [(set (SP) (PLUS (SP) (INT)))
218 ;;   (set (REG) (MEM (SP)))
219 ;;   (set (REG) (MEM (PLUS (SP) (INT)))) {optional and possibly repeated}
220 ;;   (return)
221 ;;  ]
222
223 (define_special_predicate "rx_rtsd_vector"
224   (match_code "parallel")
225 {
226   int count = XVECLEN (op, 0);
227   unsigned int dest_regno;
228   rtx element;
229   int i;
230
231   /* Perform a quick check so we don't blow up below.  */
232   if (count <= 2)
233     return false;
234
235   /* Check that the first element of the vector is the stack adjust.  */
236   element = XVECEXP (op, 0, 0);
237   if (   ! SET_P (element)
238       || ! REG_P (SET_DEST (element))
239       ||   REGNO (SET_DEST (element)) != SP_REG
240       ||   GET_CODE (SET_SRC (element)) != PLUS
241       || ! REG_P (XEXP (SET_SRC (element), 0))
242       ||   REGNO (XEXP (SET_SRC (element), 0)) != SP_REG
243       || ! CONST_INT_P (XEXP (SET_SRC (element), 1)))
244     return false;
245          
246   /* Check that the next element is the first push.  */
247   element = XVECEXP (op, 0, 1);
248   if (   ! SET_P (element)
249       || ! REG_P (SET_DEST (element))
250       || ! MEM_P (SET_SRC (element))
251       || ! REG_P (XEXP (SET_SRC (element), 0))
252       ||   REGNO (XEXP (SET_SRC (element), 0)) != SP_REG)
253     return false;
254
255   dest_regno = REGNO (SET_DEST (element));
256
257   /* Check that the remaining elements, if any, and except
258      for the last one, use SP+<disp> addressing and incremental
259      register numbers.  */
260   for (i = 2; i < count - 1; i++)
261     {
262       element = XVECEXP (op, 0, i);
263
264       if (   ! SET_P (element)
265           || ! REG_P (SET_DEST (element))
266           || GET_MODE (SET_DEST (element)) != SImode
267           || REGNO (SET_DEST (element)) != dest_regno + (i - 1)
268           || ! MEM_P (SET_SRC (element))
269           || GET_MODE (SET_SRC (element)) != SImode
270           || GET_CODE (XEXP (SET_SRC (element), 0)) != PLUS
271           || ! REG_P (XEXP (XEXP (SET_SRC (element), 0), 0))
272           ||   REGNO (XEXP (XEXP (SET_SRC (element), 0), 0)) != SP_REG
273           || ! CONST_INT_P (XEXP (XEXP (SET_SRC (element), 0), 1))
274           || INTVAL (XEXP (XEXP (SET_SRC (element), 0), 1))
275              != (i - 1) * GET_MODE_SIZE (SImode))
276         return false;
277     }
278
279   /* The last element must be a RETURN.  */    
280   element = XVECEXP (op, 0, count - 1);
281   return GET_CODE (element) == RETURN;
282 })