]>
Commit | Line | Data |
---|---|---|
309dd885 | 1 | ;; FR30 machine description. |
f17178cf KH |
2 | ;; Copyright (C) 1998, 1999, 2000, 2002, 2004, 2005 |
3 | ;; Free Software Foundation, Inc. | |
309dd885 NC |
4 | ;; Contributed by Cygnus Solutions. |
5 | ||
7ec022b2 | 6 | ;; This file is part of GCC. |
309dd885 | 7 | |
7ec022b2 | 8 | ;; GCC is free software; you can redistribute it and/or modify |
309dd885 NC |
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 | ||
7ec022b2 | 13 | ;; GCC is distributed in the hope that it will be useful, |
309dd885 NC |
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 | |
7ec022b2 | 19 | ;; along with GCC; see the file COPYING. If not, write to |
39d14dda KC |
20 | ;; the Free Software Foundation, 51 Franklin Street, Fifth Floor, |
21 | ;; Boston, MA 02110-1301, USA. | |
309dd885 NC |
22 | |
23 | ;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. | |
24 | ||
309dd885 NC |
25 | ;;{{{ Attributes |
26 | ||
27 | (define_attr "length" "" (const_int 2)) | |
28 | ||
29 | ;; Used to distinguish between small memory model targets and big mode targets. | |
30 | ||
31 | (define_attr "size" "small,big" | |
32 | (const (if_then_else (symbol_ref "TARGET_SMALL_MODEL") | |
33 | (const_string "small") | |
34 | (const_string "big")))) | |
35 | ||
36 | ||
37 | ;; Define an attribute to be used by the delay slot code. | |
6fc0bb99 | 38 | ;; An instruction by default is considered to be 'delayable' |
309dd885 | 39 | ;; that is, it can be placed into a delay slot, but it is not |
40b982a9 | 40 | ;; itself a delayed branch type instruction. An instruction |
696e78bf KH |
41 | ;; whose type is 'delayed' is one which has a delay slot, and |
42 | ;; an instruction whose delay_type is 'other' is one which does | |
309dd885 NC |
43 | ;; not have a delay slot, nor can it be placed into a delay slot. |
44 | ||
45 | (define_attr "delay_type" "delayable,delayed,other" (const_string "delayable")) | |
46 | ||
47 | ;;}}} \f | |
48 | ;;{{{ Delay Slot Specifications | |
49 | ||
50 | (define_delay (eq_attr "delay_type" "delayed") | |
51 | [(and (eq_attr "delay_type" "delayable") | |
52 | (eq_attr "length" "2")) | |
53 | (nil) | |
54 | (nil)] | |
55 | ) | |
56 | ||
f17178cf KH |
57 | (include "predicates.md") |
58 | ||
309dd885 NC |
59 | ;;}}} |
60 | ;;{{{ Moves | |
61 | ||
62 | ;;{{{ Comment | |
63 | ||
64 | ;; Wrap moves in define_expand to prevent memory->memory moves from being | |
65 | ;; generated at the RTL level, which generates better code for most machines | |
66 | ;; which can't do mem->mem moves. | |
67 | ||
68 | ;; If operand 0 is a `subreg' with mode M of a register whose own mode is wider | |
69 | ;; than M, the effect of this instruction is to store the specified value in | |
70 | ;; the part of the register that corresponds to mode M. The effect on the rest | |
71 | ;; of the register is undefined. | |
72 | ||
73 | ;; This class of patterns is special in several ways. First of all, each of | |
74 | ;; these names *must* be defined, because there is no other way to copy a datum | |
75 | ;; from one place to another. | |
76 | ||
77 | ;; Second, these patterns are not used solely in the RTL generation pass. Even | |
78 | ;; the reload pass can generate move insns to copy values from stack slots into | |
79 | ;; temporary registers. When it does so, one of the operands is a hard | |
80 | ;; register and the other is an operand that can need to be reloaded into a | |
81 | ;; register. | |
82 | ||
83 | ;; Therefore, when given such a pair of operands, the pattern must | |
84 | ;; generate RTL which needs no reloading and needs no temporary | |
85 | ;; registers--no registers other than the operands. For example, if | |
86 | ;; you support the pattern with a `define_expand', then in such a | |
87 | ;; case the `define_expand' mustn't call `force_reg' or any other such | |
88 | ;; function which might generate new pseudo registers. | |
89 | ||
90 | ;; This requirement exists even for subword modes on a RISC machine | |
91 | ;; where fetching those modes from memory normally requires several | |
92 | ;; insns and some temporary registers. Look in `spur.md' to see how | |
93 | ;; the requirement can be satisfied. | |
94 | ||
95 | ;; During reload a memory reference with an invalid address may be passed as an | |
96 | ;; operand. Such an address will be replaced with a valid address later in the | |
97 | ;; reload pass. In this case, nothing may be done with the address except to | |
98 | ;; use it as it stands. If it is copied, it will not be replaced with a valid | |
99 | ;; address. No attempt should be made to make such an address into a valid | |
100 | ;; address and no routine (such as `change_address') that will do so may be | |
101 | ;; called. Note that `general_operand' will fail when applied to such an | |
102 | ;; address. | |
103 | ;; | |
104 | ;; The global variable `reload_in_progress' (which must be explicitly declared | |
105 | ;; if required) can be used to determine whether such special handling is | |
106 | ;; required. | |
107 | ;; | |
108 | ;; The variety of operands that have reloads depends on the rest of | |
109 | ;; the machine description, but typically on a RISC machine these can | |
110 | ;; only be pseudo registers that did not get hard registers, while on | |
111 | ;; other machines explicit memory references will get optional | |
112 | ;; reloads. | |
113 | ;; | |
114 | ;; If a scratch register is required to move an object to or from memory, it | |
115 | ;; can be allocated using `gen_reg_rtx' prior to reload. But this is | |
116 | ;; impossible during and after reload. If there are cases needing scratch | |
117 | ;; registers after reload, you must define `SECONDARY_INPUT_RELOAD_CLASS' and | |
118 | ;; perhaps also `SECONDARY_OUTPUT_RELOAD_CLASS' to detect them, and provide | |
119 | ;; patterns `reload_inM' or `reload_outM' to handle them. | |
120 | ||
121 | ;; The constraints on a `moveM' must permit moving any hard register to any | |
122 | ;; other hard register provided that `HARD_REGNO_MODE_OK' permits mode M in | |
123 | ;; both registers and `REGISTER_MOVE_COST' applied to their classes returns a | |
124 | ;; value of 2. | |
125 | ||
126 | ;; It is obligatory to support floating point `moveM' instructions | |
127 | ;; into and out of any registers that can hold fixed point values, | |
128 | ;; because unions and structures (which have modes `SImode' or | |
129 | ;; `DImode') can be in those registers and they may have floating | |
130 | ;; point members. | |
131 | ||
132 | ;; There may also be a need to support fixed point `moveM' instructions in and | |
133 | ;; out of floating point registers. Unfortunately, I have forgotten why this | |
134 | ;; was so, and I don't know whether it is still true. If `HARD_REGNO_MODE_OK' | |
135 | ;; rejects fixed point values in floating point registers, then the constraints | |
136 | ;; of the fixed point `moveM' instructions must be designed to avoid ever | |
137 | ;; trying to reload into a floating point register. | |
138 | ||
139 | ;;}}} | |
140 | ;;{{{ Push and Pop | |
141 | ||
142 | ;; Push a register onto the stack | |
143 | (define_insn "movsi_push" | |
144 | [(set:SI (mem:SI (pre_dec:SI (reg:SI 15))) | |
145 | (match_operand:SI 0 "register_operand" "a"))] | |
146 | "" | |
147 | "st %0, @-r15" | |
148 | ) | |
149 | ||
150 | ;; Pop a register off the stack | |
151 | (define_insn "movsi_pop" | |
997718c7 | 152 | [(set:SI (match_operand:SI 0 "register_operand" "=a") |
309dd885 NC |
153 | (mem:SI (post_inc:SI (reg:SI 15))))] |
154 | "" | |
155 | "ld @r15+, %0" | |
156 | ) | |
157 | ||
158 | ;;}}} | |
159 | ;;{{{ 1 Byte Moves | |
160 | ||
161 | (define_expand "movqi" | |
162 | [(set (match_operand:QI 0 "general_operand" "") | |
163 | (match_operand:QI 1 "general_operand" ""))] | |
164 | "" | |
165 | " | |
166 | { | |
167 | if (!reload_in_progress | |
168 | && !reload_completed | |
169 | && GET_CODE (operands[0]) == MEM | |
170 | && (GET_CODE (operands[1]) == MEM | |
171 | || immediate_operand (operands[1], QImode))) | |
172 | operands[1] = copy_to_mode_reg (QImode, operands[1]); | |
173 | }") | |
174 | ||
175 | (define_insn "movqi_unsigned_register_load" | |
176 | [(set (match_operand:SI 0 "register_operand" "=r") | |
177 | (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] | |
178 | "" | |
179 | "ldub %1, %0" | |
180 | ) | |
181 | ||
182 | (define_expand "movqi_signed_register_load" | |
183 | [(set (match_operand:SI 0 "register_operand" "") | |
184 | (sign_extend:SI (match_operand:QI 1 "memory_operand" "")))] | |
185 | "" | |
186 | " | |
187 | emit_insn (gen_movqi_unsigned_register_load (operands[0], operands[1])); | |
188 | emit_insn (gen_extendqisi2 (operands[0], operands[0])); | |
189 | DONE; | |
190 | " | |
191 | ) | |
192 | ||
193 | (define_insn "*movqi_internal" | |
194 | [(set (match_operand:QI 0 "nonimmediate_operand" "=r,red,m,r") | |
195 | (match_operand:QI 1 "general_operand" "i,red,r,rm"))] | |
196 | "" | |
197 | "@ | |
198 | ldi:8\\t#%A1, %0 | |
199 | mov \\t%1, %0 | |
200 | stb \\t%1, %0 | |
201 | ldub \\t%1, %0" | |
202 | ) | |
203 | ||
204 | ;;}}} | |
205 | ;;{{{ 2 Byte Moves | |
206 | ||
207 | (define_expand "movhi" | |
208 | [(set (match_operand:HI 0 "general_operand" "") | |
209 | (match_operand:HI 1 "general_operand" ""))] | |
210 | "" | |
211 | " | |
212 | { | |
213 | if (!reload_in_progress | |
214 | && !reload_completed | |
215 | && GET_CODE (operands[0]) == MEM | |
216 | && (GET_CODE (operands[1]) == MEM | |
217 | || immediate_operand (operands[1], HImode))) | |
218 | operands[1] = copy_to_mode_reg (HImode, operands[1]); | |
219 | }") | |
220 | ||
221 | (define_insn "movhi_unsigned_register_load" | |
222 | [(set (match_operand:SI 0 "register_operand" "=r") | |
223 | (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] | |
224 | "" | |
225 | "lduh %1, %0" | |
226 | ) | |
227 | ||
228 | (define_expand "movhi_signed_register_load" | |
229 | [(set (match_operand:SI 0 "register_operand" "") | |
230 | (sign_extend:SI (match_operand:HI 1 "memory_operand" "")))] | |
231 | "" | |
232 | " | |
233 | emit_insn (gen_movhi_unsigned_register_load (operands[0], operands[1])); | |
234 | emit_insn (gen_extendhisi2 (operands[0], operands[0])); | |
235 | DONE; | |
236 | " | |
237 | ) | |
238 | ||
239 | (define_insn "*movhi_internal" | |
240 | [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,red,m,r") | |
241 | (match_operand:HI 1 "general_operand" "L,M,n,red,r,rm"))] | |
242 | "" | |
243 | "@ | |
244 | ldi:8 \\t#%1, %0 | |
245 | ldi:20\\t#%1, %0 | |
246 | ldi:32\\t#%1, %0 | |
247 | mov \\t%1, %0 | |
248 | sth \\t%1, %0 | |
249 | lduh \\t%1, %0" | |
250 | [(set_attr "length" "*,4,6,*,*,*")] | |
251 | ) | |
252 | ||
253 | ;;}}} | |
254 | ;;{{{ 4 Byte Moves | |
255 | ||
256 | ;; If the destination is a MEM and the source is a | |
257 | ;; MEM or an CONST_INT move the source into a register. | |
258 | (define_expand "movsi" | |
259 | [(set (match_operand:SI 0 "nonimmediate_operand" "") | |
260 | (match_operand:SI 1 "general_operand" ""))] | |
261 | "" | |
262 | "{ | |
263 | if (!reload_in_progress | |
264 | && !reload_completed | |
265 | && GET_CODE(operands[0]) == MEM | |
266 | && (GET_CODE (operands[1]) == MEM | |
267 | || immediate_operand (operands[1], SImode))) | |
268 | operands[1] = copy_to_mode_reg (SImode, operands[1]); | |
269 | }" | |
270 | ) | |
271 | ||
272 | ;; We can do some clever tricks when loading certain immediate | |
273 | ;; values. We implement these tricks as define_splits, rather | |
274 | ;; than putting the code into the define_expand "movsi" above, | |
275 | ;; because if we put them there, they will be evaluated at RTL | |
276 | ;; generation time and then the combiner pass will come along | |
277 | ;; and replace the multiple insns that have been generated with | |
278 | ;; the original, slower, load insns. (The combiner pass only | |
279 | ;; cares about reducing the number of instructions, it does not | |
280 | ;; care about instruction lengths or speeds). Splits are | |
281 | ;; evaluated after the combine pass and before the scheduling | |
282 | ;; passes, so that they are the perfect place to put this | |
283 | ;; intelligence. | |
284 | ;; | |
285 | ;; XXX we probably ought to implement these for QI and HI mode | |
286 | ;; loads as well. | |
287 | ||
288 | ;; If we are loading a small negative constant we can save space | |
289 | ;; and time by loading the positive value and then sign extending it. | |
290 | (define_split | |
997718c7 | 291 | [(set (match_operand:SI 0 "register_operand" "") |
5c7666c1 | 292 | (match_operand:SI 1 "const_int_operand" ""))] |
acb188c1 RS |
293 | "INTVAL (operands[1]) <= -1 && INTVAL (operands[1]) >= -128 |
294 | && (GET_CODE (operands[0]) != SUBREG | |
295 | || SCALAR_INT_MODE_P (GET_MODE (XEXP (operands[0], 0))))" | |
5c7666c1 NC |
296 | [(set:SI (match_dup 0) (match_dup 1)) |
297 | (set:SI (match_dup 0) (sign_extend:SI (match_dup 2)))] | |
309dd885 | 298 | "{ |
5c7666c1 NC |
299 | operands[1] = GEN_INT (INTVAL (operands[1]) & 0xff); |
300 | operands[2] = gen_lowpart (QImode, operands[0]); | |
309dd885 NC |
301 | }" |
302 | ) | |
303 | ||
304 | ;; If we are loading a large negative constant, one which does | |
305 | ;; not have any of its bottom 24 bit set, then we can save time | |
306 | ;; and space by loading the byte value and shifting it into place. | |
307 | (define_split | |
997718c7 | 308 | [(set (match_operand:SI 0 "register_operand" "") |
5c7666c1 NC |
309 | (match_operand:SI 1 "const_int_operand" ""))] |
310 | "(INTVAL (operands[1]) < 0) && ((INTVAL (operands[1]) & 0x00ffffff) == 0)" | |
309dd885 NC |
311 | [(set:SI (match_dup 0) (match_dup 2)) |
312 | (parallel [(set:SI (match_dup 0) (ashift:SI (match_dup 0) (const_int 24))) | |
313 | (clobber (reg:CC 16))])] | |
314 | "{ | |
315 | HOST_WIDE_INT val = INTVAL (operands[1]); | |
316 | operands[2] = GEN_INT (val >> 24); | |
317 | }" | |
318 | ) | |
319 | ||
320 | ;; If we are loading a large positive constant, one which has bits | |
696e78bf | 321 | ;; in the top byte set, but whose set bits all lie within an 8 bit |
309dd885 NC |
322 | ;; range, then we can save time and space by loading the byte value |
323 | ;; and shifting it into place. | |
324 | (define_split | |
997718c7 | 325 | [(set (match_operand:SI 0 "register_operand" "") |
5c7666c1 | 326 | (match_operand:SI 1 "const_int_operand" ""))] |
309dd885 | 327 | "(INTVAL (operands[1]) > 0x00ffffff) |
5c7666c1 | 328 | && ((INTVAL (operands[1]) >> exact_log2 (INTVAL (operands[1]) & (- INTVAL (operands[1])))) < 0x100)" |
309dd885 NC |
329 | [(set:SI (match_dup 0) (match_dup 2)) |
330 | (parallel [(set:SI (match_dup 0) (ashift:SI (match_dup 0) (match_dup 3))) | |
331 | (clobber (reg:CC 16))])] | |
332 | "{ | |
333 | HOST_WIDE_INT val = INTVAL (operands[1]); | |
334 | int shift = exact_log2 (val & ( - val)); | |
335 | operands[2] = GEN_INT (val >> shift); | |
336 | operands[3] = GEN_INT (shift); | |
337 | }" | |
338 | ) | |
339 | ||
340 | ;; When TARGET_SMALL_MODEL is defined we assume that all symbolic | |
341 | ;; values are addresses which will fit in 20 bits. | |
342 | ||
343 | (define_insn "movsi_internal" | |
344 | [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,red,m,r") | |
345 | (match_operand:SI 1 "general_operand" "L,M,n,i,rde,r,rm"))] | |
346 | "" | |
347 | "* | |
348 | { | |
349 | switch (which_alternative) | |
350 | { | |
351 | case 0: return \"ldi:8 \\t#%1, %0\"; | |
352 | case 1: return \"ldi:20\\t#%1, %0\"; | |
353 | case 2: return \"ldi:32\\t#%1, %0\"; | |
354 | case 3: if (TARGET_SMALL_MODEL) | |
355 | return \"ldi:20\\t%1, %0\"; | |
356 | else | |
357 | return \"ldi:32\\t%1, %0\"; | |
358 | case 4: return \"mov \\t%1, %0\"; | |
359 | case 5: return \"st \\t%1, %0\"; | |
360 | case 6: return \"ld \\t%1, %0\"; | |
4e81e7c2 | 361 | default: gcc_unreachable (); |
309dd885 NC |
362 | } |
363 | }" | |
364 | [(set (attr "length") (cond [(eq_attr "alternative" "1") (const_int 4) | |
365 | (eq_attr "alternative" "2") (const_int 6) | |
366 | (eq_attr "alternative" "3") | |
367 | (if_then_else (eq_attr "size" "small") | |
368 | (const_int 4) | |
369 | (const_int 6))] | |
370 | (const_int 2)))] | |
371 | ) | |
372 | ||
aeb4f5ef NC |
373 | ;;}}} |
374 | ;;{{{ 8 Byte Moves | |
375 | ||
376 | ;; Note - the FR30 does not have an 8 byte load/store instruction | |
377 | ;; but we have to support this pattern because some other patterns | |
112cdef5 | 378 | ;; (e.g. muldisi2) can produce a DImode result. |
aeb4f5ef NC |
379 | ;; (This code is stolen from the M32R port.) |
380 | ||
381 | (define_expand "movdi" | |
382 | [(set (match_operand:DI 0 "general_operand" "") | |
383 | (match_operand:DI 1 "general_operand" ""))] | |
384 | "" | |
385 | " | |
386 | /* Everything except mem = const or mem = mem can be done easily. */ | |
387 | ||
388 | if (GET_CODE (operands[0]) == MEM) | |
389 | operands[1] = force_reg (DImode, operands[1]); | |
390 | ") | |
391 | ||
392 | ;; We use an insn and a split so that we can generate | |
393 | ;; RTL rather than text from fr30_move_double(). | |
394 | ||
395 | (define_insn "*movdi_insn" | |
396 | [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r,r,m,r") | |
397 | (match_operand:DI 1 "di_operand" "r,m,r,nF"))] | |
398 | "register_operand (operands[0], DImode) || register_operand (operands[1], DImode)" | |
399 | "#" | |
400 | [(set_attr "length" "4,8,12,12")] | |
401 | ) | |
402 | ||
403 | (define_split | |
404 | [(set (match_operand:DI 0 "nonimmediate_di_operand" "") | |
405 | (match_operand:DI 1 "di_operand" ""))] | |
406 | "reload_completed" | |
407 | [(match_dup 2)] | |
408 | "operands[2] = fr30_move_double (operands);") | |
409 | ||
309dd885 NC |
410 | ;;}}} |
411 | ;;{{{ Load & Store Multiple Registers | |
412 | ||
413 | ;; The load multiple and store multiple patterns are implemented | |
414 | ;; as peepholes because the only time they are expected to occur | |
415 | ;; is during function prologues and epilogues. | |
416 | ||
417 | (define_peephole | |
418 | [(set:SI (mem:SI (pre_dec:SI (reg:SI 15))) | |
419 | (match_operand:SI 0 "high_register_operand" "h")) | |
420 | (set:SI (mem:SI (pre_dec:SI (reg:SI 15))) | |
421 | (match_operand:SI 1 "high_register_operand" "h")) | |
422 | (set:SI (mem:SI (pre_dec:SI (reg:SI 15))) | |
423 | (match_operand:SI 2 "high_register_operand" "h")) | |
424 | (set:SI (mem:SI (pre_dec:SI (reg:SI 15))) | |
425 | (match_operand:SI 3 "high_register_operand" "h"))] | |
426 | "fr30_check_multiple_regs (operands, 4, 1)" | |
427 | "stm1 (%0, %1, %2, %3)" | |
428 | [(set_attr "delay_type" "other")] | |
429 | ) | |
430 | ||
431 | (define_peephole | |
432 | [(set:SI (mem:SI (pre_dec:SI (reg:SI 15))) | |
433 | (match_operand:SI 0 "high_register_operand" "h")) | |
434 | (set:SI (mem:SI (pre_dec:SI (reg:SI 15))) | |
435 | (match_operand:SI 1 "high_register_operand" "h")) | |
436 | (set:SI (mem:SI (pre_dec:SI (reg:SI 15))) | |
437 | (match_operand:SI 2 "high_register_operand" "h"))] | |
438 | "fr30_check_multiple_regs (operands, 3, 1)" | |
439 | "stm1 (%0, %1, %2)" | |
440 | [(set_attr "delay_type" "other")] | |
441 | ) | |
442 | ||
443 | (define_peephole | |
444 | [(set:SI (mem:SI (pre_dec:SI (reg:SI 15))) | |
445 | (match_operand:SI 0 "high_register_operand" "h")) | |
446 | (set:SI (mem:SI (pre_dec:SI (reg:SI 15))) | |
447 | (match_operand:SI 1 "high_register_operand" "h"))] | |
448 | "fr30_check_multiple_regs (operands, 2, 1)" | |
449 | "stm1 (%0, %1)" | |
450 | [(set_attr "delay_type" "other")] | |
451 | ) | |
452 | ||
453 | (define_peephole | |
454 | [(set:SI (match_operand:SI 0 "high_register_operand" "h") | |
455 | (mem:SI (post_inc:SI (reg:SI 15)))) | |
456 | (set:SI (match_operand:SI 1 "high_register_operand" "h") | |
457 | (mem:SI (post_inc:SI (reg:SI 15)))) | |
458 | (set:SI (match_operand:SI 2 "high_register_operand" "h") | |
459 | (mem:SI (post_inc:SI (reg:SI 15)))) | |
460 | (set:SI (match_operand:SI 3 "high_register_operand" "h") | |
461 | (mem:SI (post_inc:SI (reg:SI 15))))] | |
462 | "fr30_check_multiple_regs (operands, 4, 0)" | |
463 | "ldm1 (%0, %1, %2, %3)" | |
464 | [(set_attr "delay_type" "other")] | |
465 | ) | |
466 | ||
467 | (define_peephole | |
468 | [(set:SI (match_operand:SI 0 "high_register_operand" "h") | |
469 | (mem:SI (post_inc:SI (reg:SI 15)))) | |
470 | (set:SI (match_operand:SI 1 "high_register_operand" "h") | |
471 | (mem:SI (post_inc:SI (reg:SI 15)))) | |
472 | (set:SI (match_operand:SI 2 "high_register_operand" "h") | |
473 | (mem:SI (post_inc:SI (reg:SI 15))))] | |
474 | "fr30_check_multiple_regs (operands, 3, 0)" | |
475 | "ldm1 (%0, %1, %2)" | |
476 | [(set_attr "delay_type" "other")] | |
477 | ) | |
478 | ||
479 | (define_peephole | |
480 | [(set:SI (match_operand:SI 0 "high_register_operand" "h") | |
481 | (mem:SI (post_inc:SI (reg:SI 15)))) | |
482 | (set:SI (match_operand:SI 1 "high_register_operand" "h") | |
483 | (mem:SI (post_inc:SI (reg:SI 15))))] | |
484 | "fr30_check_multiple_regs (operands, 2, 0)" | |
485 | "ldm1 (%0, %1)" | |
486 | [(set_attr "delay_type" "other")] | |
487 | ) | |
488 | ||
489 | (define_peephole | |
490 | [(set:SI (mem:SI (pre_dec:SI (reg:SI 15))) | |
491 | (match_operand:SI 0 "low_register_operand" "l")) | |
492 | (set:SI (mem:SI (pre_dec:SI (reg:SI 15))) | |
493 | (match_operand:SI 1 "low_register_operand" "l")) | |
494 | (set:SI (mem:SI (pre_dec:SI (reg:SI 15))) | |
495 | (match_operand:SI 2 "low_register_operand" "l")) | |
496 | (set:SI (mem:SI (pre_dec:SI (reg:SI 15))) | |
497 | (match_operand:SI 3 "low_register_operand" "l"))] | |
498 | "fr30_check_multiple_regs (operands, 4, 1)" | |
499 | "stm0 (%0, %1, %2, %3)" | |
500 | [(set_attr "delay_type" "other")] | |
501 | ) | |
502 | ||
503 | (define_peephole | |
504 | [(set:SI (mem:SI (pre_dec:SI (reg:SI 15))) | |
505 | (match_operand:SI 0 "low_register_operand" "l")) | |
506 | (set:SI (mem:SI (pre_dec:SI (reg:SI 15))) | |
507 | (match_operand:SI 1 "low_register_operand" "l")) | |
508 | (set:SI (mem:SI (pre_dec:SI (reg:SI 15))) | |
509 | (match_operand:SI 2 "low_register_operand" "l"))] | |
510 | "fr30_check_multiple_regs (operands, 3, 1)" | |
511 | "stm0 (%0, %1, %2)" | |
512 | [(set_attr "delay_type" "other")] | |
513 | ) | |
514 | ||
515 | (define_peephole | |
516 | [(set:SI (mem:SI (pre_dec:SI (reg:SI 15))) | |
517 | (match_operand:SI 0 "low_register_operand" "l")) | |
518 | (set:SI (mem:SI (pre_dec:SI (reg:SI 15))) | |
519 | (match_operand:SI 1 "low_register_operand" "l"))] | |
520 | "fr30_check_multiple_regs (operands, 2, 1)" | |
521 | "stm0 (%0, %1)" | |
522 | [(set_attr "delay_type" "other")] | |
523 | ) | |
524 | ||
525 | ;;}}} | |
526 | ;;{{{ Floating Point Moves | |
527 | ||
528 | ;; Note - Patterns for SF mode moves are compulsory, but | |
05713b80 | 529 | ;; patterns for DF are optional, as GCC can synthesize them. |
309dd885 NC |
530 | |
531 | (define_expand "movsf" | |
532 | [(set (match_operand:SF 0 "general_operand" "") | |
533 | (match_operand:SF 1 "general_operand" ""))] | |
534 | "" | |
535 | "{ | |
536 | if (!reload_in_progress && !reload_completed | |
537 | && memory_operand (operands[0], SFmode) | |
538 | && memory_operand (operands[1], SFmode)) | |
539 | operands[1] = copy_to_mode_reg (SFmode, operands[1]); | |
540 | }" | |
541 | ) | |
542 | ||
543 | (define_insn "*movsf_internal" | |
544 | [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,red,m,r") | |
545 | (match_operand:SF 1 "general_operand" "Fn,i,rde,r,rm"))] | |
546 | "" | |
547 | "* | |
548 | { | |
549 | switch (which_alternative) | |
550 | { | |
551 | case 0: return \"ldi:32\\t%1, %0\"; | |
552 | case 1: if (TARGET_SMALL_MODEL) | |
553 | return \"ldi:20\\t%1, %0\"; | |
554 | else | |
555 | return \"ldi:32\\t%1, %0\"; | |
556 | case 2: return \"mov \\t%1, %0\"; | |
557 | case 3: return \"st \\t%1, %0\"; | |
558 | case 4: return \"ld \\t%1, %0\"; | |
4e81e7c2 | 559 | default: gcc_unreachable (); |
309dd885 NC |
560 | } |
561 | }" | |
562 | [(set (attr "length") (cond [(eq_attr "alternative" "0") (const_int 6) | |
563 | (eq_attr "alternative" "1") | |
564 | (if_then_else (eq_attr "size" "small") | |
565 | (const_int 4) | |
566 | (const_int 6))] | |
567 | (const_int 2)))] | |
568 | ) | |
569 | ||
570 | (define_insn "*movsf_constant_store" | |
997718c7 | 571 | [(set (match_operand:SF 0 "memory_operand" "=m") |
309dd885 NC |
572 | (match_operand:SF 1 "immediate_operand" "F"))] |
573 | "" | |
574 | "* | |
575 | { | |
1943c2c1 | 576 | const char * ldi_instr; |
82a9bba5 | 577 | const char * tmp_reg; |
309dd885 | 578 | static char buffer[100]; |
309dd885 | 579 | |
3d5ee65b NC |
580 | ldi_instr = fr30_const_double_is_zero (operands[1]) |
581 | ? ldi_instr = \"ldi:8\" : \"ldi:32\"; | |
309dd885 NC |
582 | |
583 | tmp_reg = reg_names [COMPILER_SCRATCH_REGISTER]; | |
584 | ||
585 | sprintf (buffer, \"%s\\t#%%1, %s\\t;\\n\\tst\\t%s, %%0\\t; Created by movsf_constant_store\", | |
586 | ldi_instr, tmp_reg, tmp_reg); | |
587 | ||
588 | return buffer; | |
589 | }" | |
590 | [(set_attr "length" "8")] | |
591 | ) | |
592 | ||
593 | ;;}}} | |
594 | ||
595 | ;;}}} \f | |
596 | ;;{{{ Conversions | |
597 | ||
598 | ;; Signed conversions from a smaller integer to a larger integer | |
599 | ||
600 | (define_insn "extendqisi2" | |
601 | [(set (match_operand:SI 0 "register_operand" "=r") | |
602 | (sign_extend:SI (match_operand:QI 1 "register_operand" "0")))] | |
603 | "" | |
604 | "extsb %0" | |
605 | ) | |
606 | ||
607 | (define_insn "extendhisi2" | |
608 | [(set (match_operand:SI 0 "register_operand" "=r") | |
609 | (sign_extend:SI (match_operand:HI 1 "register_operand" "0")))] | |
610 | "" | |
611 | "extsh %0" | |
612 | ) | |
613 | ||
614 | ;; Unsigned conversions from a smaller integer to a larger integer | |
615 | ||
616 | (define_insn "zero_extendqisi2" | |
617 | [(set (match_operand:SI 0 "register_operand" "=r") | |
618 | (zero_extend:SI (match_operand:QI 1 "register_operand" "0")))] | |
619 | "" | |
620 | "extub %0" | |
621 | ) | |
622 | ||
623 | (define_insn "zero_extendhisi2" | |
624 | [(set (match_operand:SI 0 "register_operand" "=r") | |
625 | (zero_extend:SI (match_operand:HI 1 "register_operand" "0")))] | |
626 | "" | |
627 | "extuh %0" | |
628 | ) | |
629 | ||
630 | ;;}}} \f | |
631 | ;;{{{ Arithmetic | |
632 | ||
633 | ;;{{{ Addition | |
634 | ||
635 | ;; This is a special pattern just for adjusting the stack size. | |
636 | (define_insn "add_to_stack" | |
637 | [(set (reg:SI 15) | |
638 | (plus:SI (reg:SI 15) | |
639 | (match_operand:SI 0 "stack_add_operand" "i")))] | |
640 | "" | |
641 | "addsp %0" | |
642 | ) | |
643 | ||
644 | ;; We need some trickery to be able to handle the addition of | |
112cdef5 | 645 | ;; large (i.e. outside +/- 16) constants. We need to be able to |
309dd885 | 646 | ;; handle this because reload assumes that it can generate add |
839a4992 | 647 | ;; instructions with arbitrary sized constants. |
309dd885 NC |
648 | (define_expand "addsi3" |
649 | [(set (match_operand:SI 0 "register_operand" "") | |
650 | (plus:SI (match_operand:SI 1 "register_operand" "") | |
651 | (match_operand:SI 2 "nonmemory_operand" "")))] | |
652 | "" | |
653 | "{ | |
654 | if ( GET_CODE (operands[2]) == REG | |
655 | || GET_CODE (operands[2]) == SUBREG) | |
656 | emit_insn (gen_addsi_regs (operands[0], operands[1], operands[2])); | |
657 | else if (GET_CODE (operands[2]) != CONST_INT) | |
658 | emit_insn (gen_addsi_big_int (operands[0], operands[1], operands[2])); | |
a02ee5b2 RS |
659 | else if (INTVAL (operands[2]) >= -16 |
660 | && INTVAL (operands[2]) <= 15 | |
661 | && (!REGNO_PTR_FRAME_P (REGNO (operands[1])) | |
662 | || REGNO (operands[1]) == STACK_POINTER_REGNUM)) | |
309dd885 NC |
663 | emit_insn (gen_addsi_small_int (operands[0], operands[1], operands[2])); |
664 | else | |
665 | emit_insn (gen_addsi_big_int (operands[0], operands[1], operands[2])); | |
666 | DONE; | |
667 | }" | |
668 | ) | |
669 | ||
670 | (define_insn "addsi_regs" | |
671 | [(set (match_operand:SI 0 "register_operand" "=r") | |
672 | (plus:SI (match_operand:SI 1 "register_operand" "%0") | |
673 | (match_operand:SI 2 "register_operand" "r")))] | |
674 | "" | |
675 | "addn %2, %0" | |
676 | ) | |
677 | ||
aaceac0b | 678 | ;; Do not allow an eliminable register in the source register. It |
9cd10576 | 679 | ;; might be eliminated in favor of the stack pointer, probably |
aaceac0b | 680 | ;; increasing the offset, and so rendering the instruction illegal. |
309dd885 NC |
681 | (define_insn "addsi_small_int" |
682 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
683 | (plus:SI (match_operand:SI 1 "register_operand" "0,0") | |
684 | (match_operand:SI 2 "add_immediate_operand" "I,J")))] | |
a02ee5b2 RS |
685 | "! REGNO_PTR_FRAME_P (REGNO (operands[1])) |
686 | || REGNO (operands[1]) == STACK_POINTER_REGNUM" | |
309dd885 NC |
687 | "@ |
688 | addn %2, %0 | |
689 | addn2 %2, %0" | |
690 | ) | |
691 | ||
692 | (define_expand "addsi_big_int" | |
693 | [(set (match_operand:SI 0 "register_operand" "") | |
694 | (plus:SI (match_operand:SI 1 "register_operand" "") | |
695 | (match_operand:SI 2 "immediate_operand" "")))] | |
696 | "" | |
697 | "{ | |
698 | /* Cope with the possibility that ops 0 and 1 are the same register. */ | |
699 | if (REGNO (operands[0]) == REGNO (operands[1])) | |
700 | { | |
701 | if (reload_in_progress || reload_completed) | |
702 | { | |
703 | rtx reg = gen_rtx_REG (SImode, 0/*COMPILER_SCRATCH_REGISTER*/); | |
704 | ||
705 | emit_insn (gen_movsi (reg, operands[2])); | |
706 | emit_insn (gen_addsi_regs (operands[0], operands[0], reg)); | |
707 | } | |
708 | else | |
709 | { | |
710 | operands[2] = force_reg (SImode, operands[2]); | |
711 | emit_insn (gen_addsi_regs (operands[0], operands[0], operands[2])); | |
712 | } | |
713 | } | |
714 | else | |
715 | { | |
716 | emit_insn (gen_movsi (operands[0], operands[2])); | |
717 | emit_insn (gen_addsi_regs (operands[0], operands[0], operands[1])); | |
718 | } | |
719 | DONE; | |
720 | }" | |
721 | ) | |
722 | ||
723 | (define_insn "*addsi_for_reload" | |
724 | [(set (match_operand:SI 0 "register_operand" "=&r,r,r") | |
725 | (plus:SI (match_operand:SI 1 "register_operand" "r,r,r") | |
726 | (match_operand:SI 2 "immediate_operand" "L,M,n")))] | |
727 | "reload_in_progress || reload_completed" | |
728 | "@ | |
729 | ldi:8\\t#%2, %0 \\n\\taddn\\t%1, %0 | |
730 | ldi:20\\t#%2, %0 \\n\\taddn\\t%1, %0 | |
731 | ldi:32\\t#%2, %0 \\n\\taddn\\t%1, %0" | |
732 | [(set_attr "length" "4,6,8")] | |
733 | ) | |
734 | ||
735 | ;;}}} | |
736 | ;;{{{ Subtraction | |
737 | ||
738 | (define_insn "subsi3" | |
739 | [(set (match_operand:SI 0 "register_operand" "=r") | |
997718c7 RH |
740 | (minus:SI (match_operand:SI 1 "register_operand" "0") |
741 | (match_operand:SI 2 "register_operand" "r")))] | |
309dd885 NC |
742 | "" |
743 | "subn %2, %0" | |
744 | ) | |
745 | ||
746 | ;;}}} | |
747 | ;;{{{ Multiplication | |
748 | ||
a7b376ee | 749 | ;; Signed multiplication producing 64-bit results from 32-bit inputs |
309dd885 NC |
750 | (define_insn "mulsidi3" |
751 | [(set (match_operand:DI 0 "register_operand" "=r") | |
752 | (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%r")) | |
753 | (sign_extend:DI (match_operand:SI 2 "register_operand" "r")))) | |
754 | (clobber (reg:CC 16))] | |
755 | "" | |
756 | "mul %2, %1\\n\\tmov\\tmdh, %0\\n\\tmov\\tmdl, %p0" | |
757 | [(set_attr "length" "6")] | |
758 | ) | |
759 | ||
a7b376ee | 760 | ;; Unsigned multiplication producing 64-bit results from 32-bit inputs |
309dd885 NC |
761 | (define_insn "umulsidi3" |
762 | [(set (match_operand:DI 0 "register_operand" "=r") | |
763 | (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%r")) | |
764 | (zero_extend:DI (match_operand:SI 2 "register_operand" "r")))) | |
765 | (clobber (reg:CC 16))] | |
766 | "" | |
767 | "mulu %2, %1\\n\\tmov\\tmdh, %0\\n\\tmov\\tmdl, %p0" | |
768 | [(set_attr "length" "6")] | |
769 | ) | |
770 | ||
a7b376ee | 771 | ;; Signed multiplication producing 32-bit result from 16-bit inputs |
309dd885 NC |
772 | (define_insn "mulhisi3" |
773 | [(set (match_operand:SI 0 "register_operand" "=r") | |
774 | (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%r")) | |
775 | (sign_extend:SI (match_operand:HI 2 "register_operand" "r")))) | |
776 | (clobber (reg:CC 16))] | |
777 | "" | |
778 | "mulh %2, %1\\n\\tmov\\tmdl, %0" | |
779 | [(set_attr "length" "4")] | |
780 | ) | |
781 | ||
a7b376ee | 782 | ;; Unsigned multiplication producing 32-bit result from 16-bit inputs |
309dd885 NC |
783 | (define_insn "umulhisi3" |
784 | [(set (match_operand:SI 0 "register_operand" "=r") | |
785 | (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%r")) | |
786 | (zero_extend:SI (match_operand:HI 2 "register_operand" "r")))) | |
787 | (clobber (reg:CC 16))] | |
788 | "" | |
789 | "muluh %2, %1\\n\\tmov\\tmdl, %0" | |
790 | [(set_attr "length" "4")] | |
791 | ) | |
792 | ||
a7b376ee | 793 | ;; Signed multiplication producing 32-bit result from 32-bit inputs |
309dd885 NC |
794 | (define_insn "mulsi3" |
795 | [(set (match_operand:SI 0 "register_operand" "=r") | |
796 | (mult:SI (match_operand:SI 1 "register_operand" "%r") | |
797 | (match_operand:SI 2 "register_operand" "r"))) | |
798 | (clobber (reg:CC 16))] | |
799 | "" | |
800 | "mul %2, %1\\n\\tmov\\tmdl, %0" | |
801 | [(set_attr "length" "4")] | |
802 | ) | |
803 | ||
804 | ;;}}} | |
805 | ;;{{{ Negation | |
806 | ||
807 | (define_expand "negsi2" | |
808 | [(set (match_operand:SI 0 "register_operand" "") | |
809 | (neg:SI (match_operand:SI 1 "register_operand" "")))] | |
810 | "" | |
811 | "{ | |
812 | if (REGNO (operands[0]) == REGNO (operands[1])) | |
813 | { | |
814 | if (reload_in_progress || reload_completed) | |
815 | { | |
816 | rtx reg = gen_rtx_REG (SImode, 0/*COMPILER_SCRATCH_REGISTER*/); | |
817 | ||
a556fd39 | 818 | emit_insn (gen_movsi (reg, const0_rtx)); |
309dd885 NC |
819 | emit_insn (gen_subsi3 (reg, reg, operands[0])); |
820 | emit_insn (gen_movsi (operands[0], reg)); | |
821 | } | |
822 | else | |
823 | { | |
824 | rtx reg = gen_reg_rtx (SImode); | |
825 | ||
a556fd39 | 826 | emit_insn (gen_movsi (reg, const0_rtx)); |
309dd885 NC |
827 | emit_insn (gen_subsi3 (reg, reg, operands[0])); |
828 | emit_insn (gen_movsi (operands[0], reg)); | |
829 | } | |
830 | } | |
831 | else | |
832 | { | |
a556fd39 | 833 | emit_insn (gen_movsi_internal (operands[0], const0_rtx)); |
309dd885 NC |
834 | emit_insn (gen_subsi3 (operands[0], operands[0], operands[1])); |
835 | } | |
836 | DONE; | |
837 | }" | |
838 | ) | |
839 | ||
840 | ;;}}} | |
841 | ||
842 | ;;}}} \f | |
843 | ;;{{{ Shifts | |
844 | ||
845 | ;; Arithmetic Shift Left | |
846 | (define_insn "ashlsi3" | |
847 | [(set (match_operand:SI 0 "register_operand" "=r,r,r") | |
848 | (ashift:SI (match_operand:SI 1 "register_operand" "0,0,0") | |
849 | (match_operand:SI 2 "nonmemory_operand" "r,I,K"))) | |
850 | (clobber (reg:CC 16))] | |
851 | "" | |
852 | "@ | |
853 | lsl %2, %0 | |
854 | lsl %2, %0 | |
855 | lsl2 %x2, %0" | |
856 | ) | |
857 | ||
858 | ;; Arithmetic Shift Right | |
859 | (define_insn "ashrsi3" | |
860 | [(set (match_operand:SI 0 "register_operand" "=r,r,r") | |
861 | (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0,0") | |
862 | (match_operand:SI 2 "nonmemory_operand" "r,I,K"))) | |
863 | (clobber (reg:CC 16))] | |
864 | "" | |
865 | "@ | |
866 | asr %2, %0 | |
867 | asr %2, %0 | |
868 | asr2 %x2, %0" | |
869 | ) | |
870 | ||
871 | ;; Logical Shift Right | |
872 | (define_insn "lshrsi3" | |
873 | [(set (match_operand:SI 0 "register_operand" "=r,r,r") | |
874 | (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0,0") | |
875 | (match_operand:SI 2 "nonmemory_operand" "r,I,K"))) | |
876 | (clobber (reg:CC 16))] | |
877 | "" | |
878 | "@ | |
879 | lsr %2, %0 | |
880 | lsr %2, %0 | |
881 | lsr2 %x2, %0" | |
882 | ) | |
883 | ||
884 | ;;}}} \f | |
885 | ;;{{{ Logical Operations | |
886 | ||
a7b376ee | 887 | ;; Logical AND, 32-bit integers |
309dd885 NC |
888 | (define_insn "andsi3" |
889 | [(set (match_operand:SI 0 "register_operand" "=r") | |
890 | (and:SI (match_operand:SI 1 "register_operand" "%r") | |
891 | (match_operand:SI 2 "register_operand" "0"))) | |
892 | (clobber (reg:CC 16))] | |
893 | "" | |
894 | "and %1, %0" | |
895 | ) | |
896 | ||
a7b376ee | 897 | ;; Inclusive OR, 32-bit integers |
309dd885 NC |
898 | (define_insn "iorsi3" |
899 | [(set (match_operand:SI 0 "register_operand" "=r") | |
900 | (ior:SI (match_operand:SI 1 "register_operand" "%r") | |
901 | (match_operand:SI 2 "register_operand" "0"))) | |
902 | (clobber (reg:CC 16))] | |
903 | "" | |
904 | "or %1, %0" | |
905 | ) | |
906 | ||
a7b376ee | 907 | ;; Exclusive OR, 32-bit integers |
309dd885 NC |
908 | (define_insn "xorsi3" |
909 | [(set (match_operand:SI 0 "register_operand" "=r") | |
910 | (xor:SI (match_operand:SI 1 "register_operand" "%r") | |
911 | (match_operand:SI 2 "register_operand" "0"))) | |
912 | (clobber (reg:CC 16))] | |
913 | "" | |
914 | "eor %1, %0" | |
915 | ) | |
916 | ||
a7b376ee | 917 | ;; One's complement, 32-bit integers |
309dd885 NC |
918 | (define_expand "one_cmplsi2" |
919 | [(set (match_operand:SI 0 "register_operand" "") | |
920 | (not:SI (match_operand:SI 1 "register_operand" "")))] | |
921 | "" | |
922 | "{ | |
923 | if (REGNO (operands[0]) == REGNO (operands[1])) | |
924 | { | |
925 | if (reload_in_progress || reload_completed) | |
926 | { | |
927 | rtx reg = gen_rtx_REG (SImode, 0/*COMPILER_SCRATCH_REGISTER*/); | |
928 | ||
a556fd39 | 929 | emit_insn (gen_movsi (reg, constm1_rtx)); |
309dd885 NC |
930 | emit_insn (gen_xorsi3 (operands[0], operands[0], reg)); |
931 | } | |
932 | else | |
933 | { | |
934 | rtx reg = gen_reg_rtx (SImode); | |
935 | ||
a556fd39 | 936 | emit_insn (gen_movsi (reg, constm1_rtx)); |
309dd885 NC |
937 | emit_insn (gen_xorsi3 (operands[0], operands[0], reg)); |
938 | } | |
939 | } | |
940 | else | |
941 | { | |
a556fd39 | 942 | emit_insn (gen_movsi_internal (operands[0], constm1_rtx)); |
309dd885 NC |
943 | emit_insn (gen_xorsi3 (operands[0], operands[1], operands[0])); |
944 | } | |
945 | DONE; | |
946 | }" | |
947 | ) | |
948 | ||
949 | ;;}}} \f | |
950 | ;;{{{ Comparisons | |
951 | ||
952 | ;; Note, we store the operands in the comparison insns, and use them later | |
953 | ;; when generating the branch or scc operation. | |
954 | ||
955 | ;; First the routines called by the machine independent part of the compiler | |
956 | (define_expand "cmpsi" | |
957 | [(set (reg:CC 16) | |
958 | (compare:CC (match_operand:SI 0 "register_operand" "") | |
959 | (match_operand:SI 1 "nonmemory_operand" "")))] | |
960 | "" | |
961 | "{ | |
962 | fr30_compare_op0 = operands[0]; | |
963 | fr30_compare_op1 = operands[1]; | |
964 | DONE; | |
965 | }" | |
966 | ) | |
967 | ||
968 | ;; Now, the actual comparisons, generated by the branch and/or scc operations | |
969 | ||
970 | (define_insn "*cmpsi_internal" | |
971 | [(set (reg:CC 16) | |
972 | (compare:CC (match_operand:SI 0 "register_operand" "r,r,r") | |
973 | (match_operand:SI 1 "nonmemory_operand" "r,I,J")))] | |
974 | "" | |
975 | "@ | |
976 | cmp %1, %0 | |
977 | cmp %1, %0 | |
978 | cmp2 %1, %0" | |
979 | ) | |
980 | ||
981 | ;;}}} \f | |
982 | ;;{{{ Branches | |
983 | ||
984 | ;; Define_expands called by the machine independent part of the compiler | |
985 | ;; to allocate a new comparison register | |
986 | ||
987 | (define_expand "beq" | |
988 | [(set (reg:CC 16) | |
989 | (compare:CC (match_dup 1) | |
990 | (match_dup 2))) | |
991 | (set (pc) | |
992 | (if_then_else (eq:CC (reg:CC 16) | |
993 | (const_int 0)) | |
994 | (label_ref (match_operand 0 "" "")) | |
995 | (pc)))] | |
996 | "" | |
997 | "{ | |
998 | operands[1] = fr30_compare_op0; | |
999 | operands[2] = fr30_compare_op1; | |
1000 | }" | |
1001 | ) | |
1002 | ||
1003 | (define_expand "bne" | |
1004 | [(set (reg:CC 16) | |
1005 | (compare:CC (match_dup 1) | |
1006 | (match_dup 2))) | |
1007 | (set (pc) | |
1008 | (if_then_else (ne:CC (reg:CC 16) | |
1009 | (const_int 0)) | |
1010 | (label_ref (match_operand 0 "" "")) | |
1011 | (pc)))] | |
1012 | "" | |
1013 | "{ | |
1014 | operands[1] = fr30_compare_op0; | |
1015 | operands[2] = fr30_compare_op1; | |
1016 | }" | |
1017 | ) | |
1018 | ||
1019 | (define_expand "blt" | |
1020 | [(set (reg:CC 16) | |
1021 | (compare:CC (match_dup 1) | |
1022 | (match_dup 2))) | |
1023 | (set (pc) | |
1024 | (if_then_else (lt:CC (reg:CC 16) | |
1025 | (const_int 0)) | |
1026 | (label_ref (match_operand 0 "" "")) | |
1027 | (pc)))] | |
1028 | "" | |
1029 | "{ | |
1030 | operands[1] = fr30_compare_op0; | |
1031 | operands[2] = fr30_compare_op1; | |
1032 | }" | |
1033 | ) | |
1034 | ||
1035 | (define_expand "ble" | |
1036 | [(set (reg:CC 16) | |
1037 | (compare:CC (match_dup 1) | |
1038 | (match_dup 2))) | |
1039 | (set (pc) | |
1040 | (if_then_else (le:CC (reg:CC 16) | |
1041 | (const_int 0)) | |
1042 | (label_ref (match_operand 0 "" "")) | |
1043 | (pc)))] | |
1044 | "" | |
1045 | "{ | |
1046 | operands[1] = fr30_compare_op0; | |
1047 | operands[2] = fr30_compare_op1; | |
1048 | }" | |
1049 | ) | |
1050 | ||
1051 | (define_expand "bgt" | |
1052 | [(set (reg:CC 16) | |
1053 | (compare:CC (match_dup 1) | |
1054 | (match_dup 2))) | |
1055 | (set (pc) | |
1056 | (if_then_else (gt:CC (reg:CC 16) | |
1057 | (const_int 0)) | |
1058 | (label_ref (match_operand 0 "" "")) | |
1059 | (pc)))] | |
1060 | "" | |
1061 | "{ | |
1062 | operands[1] = fr30_compare_op0; | |
1063 | operands[2] = fr30_compare_op1; | |
1064 | }" | |
1065 | ) | |
1066 | ||
1067 | (define_expand "bge" | |
1068 | [(set (reg:CC 16) | |
1069 | (compare:CC (match_dup 1) | |
1070 | (match_dup 2))) | |
1071 | (set (pc) | |
1072 | (if_then_else (ge:CC (reg:CC 16) | |
1073 | (const_int 0)) | |
1074 | (label_ref (match_operand 0 "" "")) | |
1075 | (pc)))] | |
1076 | "" | |
1077 | "{ | |
1078 | operands[1] = fr30_compare_op0; | |
1079 | operands[2] = fr30_compare_op1; | |
1080 | }" | |
1081 | ) | |
1082 | ||
1083 | (define_expand "bltu" | |
1084 | [(set (reg:CC 16) | |
1085 | (compare:CC (match_dup 1) | |
1086 | (match_dup 2))) | |
1087 | (set (pc) | |
1088 | (if_then_else (ltu:CC (reg:CC 16) | |
1089 | (const_int 0)) | |
1090 | (label_ref (match_operand 0 "" "")) | |
1091 | (pc)))] | |
1092 | "" | |
1093 | "{ | |
1094 | operands[1] = fr30_compare_op0; | |
1095 | operands[2] = fr30_compare_op1; | |
1096 | }" | |
1097 | ) | |
1098 | ||
1099 | (define_expand "bleu" | |
1100 | [(set (reg:CC 16) | |
1101 | (compare:CC (match_dup 1) | |
1102 | (match_dup 2))) | |
1103 | (set (pc) | |
1104 | (if_then_else (leu:CC (reg:CC 16) | |
1105 | (const_int 0)) | |
1106 | (label_ref (match_operand 0 "" "")) | |
1107 | (pc)))] | |
1108 | "" | |
1109 | "{ | |
1110 | operands[1] = fr30_compare_op0; | |
1111 | operands[2] = fr30_compare_op1; | |
1112 | }" | |
1113 | ) | |
1114 | ||
1115 | (define_expand "bgtu" | |
1116 | [(set (reg:CC 16) | |
1117 | (compare:CC (match_dup 1) | |
1118 | (match_dup 2))) | |
1119 | (set (pc) | |
1120 | (if_then_else (gtu:CC (reg:CC 16) | |
1121 | (const_int 0)) | |
1122 | (label_ref (match_operand 0 "" "")) | |
1123 | (pc)))] | |
1124 | "" | |
1125 | "{ | |
1126 | operands[1] = fr30_compare_op0; | |
1127 | operands[2] = fr30_compare_op1; | |
1128 | }" | |
1129 | ) | |
1130 | ||
1131 | (define_expand "bgeu" | |
1132 | [(set (reg:CC 16) | |
1133 | (compare:CC (match_dup 1) | |
1134 | (match_dup 2))) | |
1135 | (set (pc) | |
1136 | (if_then_else (geu:CC (reg:CC 16) | |
1137 | (const_int 0)) | |
1138 | (label_ref (match_operand 0 "" "")) | |
1139 | (pc)))] | |
1140 | "" | |
1141 | "{ | |
1142 | operands[1] = fr30_compare_op0; | |
1143 | operands[2] = fr30_compare_op1; | |
1144 | }" | |
1145 | ) | |
1146 | ||
1147 | ;; Actual branches. We must allow for the (label_ref) and the (pc) to be | |
1148 | ;; swapped. If they are swapped, it reverses the sense of the branch. | |
1149 | ||
1150 | ;; This pattern matches the (branch-if-true) branches generated above. | |
1151 | ;; It generates two different instruction sequences depending upon how | |
1152 | ;; far away the destination is. | |
1153 | ||
1154 | ;; The calculation for the instruction length is derived as follows: | |
a7b376ee | 1155 | ;; The branch instruction has a 9-bit signed displacement so we have |
309dd885 NC |
1156 | ;; this inequality for the displacement: |
1157 | ;; | |
1158 | ;; -256 <= pc < 256 | |
1159 | ;; or | |
1160 | ;; -256 + 256 <= pc + 256 < 256 + 256 | |
112cdef5 | 1161 | ;; i.e. |
309dd885 NC |
1162 | ;; 0 <= pc + 256 < 512 |
1163 | ;; | |
1164 | ;; if we consider the displacement as an unsigned value, then negative | |
1165 | ;; displacements become very large positive displacements, and the | |
1166 | ;; inequality becomes: | |
1167 | ;; | |
1168 | ;; pc + 256 < 512 | |
1169 | ;; | |
1170 | ;; In order to allow for the fact that the real branch instruction works | |
1171 | ;; from pc + 2, we increase the offset to 258. | |
1172 | ;; | |
1173 | ;; Note - we do not have to worry about whether the branch is delayed or | |
272d0bee | 1174 | ;; not, as branch shortening happens after delay slot reorganization. |
309dd885 NC |
1175 | |
1176 | (define_insn "*branch_true" | |
1177 | [(set (pc) | |
1178 | (if_then_else (match_operator:CC 0 "comparison_operator" | |
1179 | [(reg:CC 16) | |
1180 | (const_int 0)]) | |
1181 | (label_ref (match_operand 1 "" "")) | |
1182 | (pc)))] | |
1183 | "" | |
1184 | "* | |
1185 | { | |
1186 | if (get_attr_length (insn) == 2) | |
1187 | return \"b%b0%#\\t%l1\"; | |
1188 | else | |
1189 | { | |
82a9bba5 NC |
1190 | static char buffer [100]; |
1191 | const char * tmp_reg; | |
1943c2c1 | 1192 | const char * ldi_insn; |
309dd885 NC |
1193 | |
1194 | tmp_reg = reg_names [COMPILER_SCRATCH_REGISTER]; | |
1195 | ||
1196 | ldi_insn = TARGET_SMALL_MODEL ? \"ldi:20\" : \"ldi:32\"; | |
1197 | ||
1198 | /* The code produced here is, for say the EQ case: | |
1199 | ||
1200 | Bne 1f | |
1201 | LDI <label>, r0 | |
1202 | JMP r0 | |
1203 | 1: */ | |
1204 | ||
1205 | sprintf (buffer, | |
1206 | \"b%%B0\\t1f\\t;\\n\\t%s\\t%%l1, %s\\t;\\n\\tjmp%%#\\t@%s\\t;\\n1:\", | |
1207 | ldi_insn, tmp_reg, tmp_reg); | |
1208 | ||
1209 | return buffer; | |
1210 | } | |
1211 | }" | |
1212 | [(set (attr "length") (if_then_else | |
1213 | (ltu | |
1214 | (plus | |
1215 | (minus | |
1216 | (match_dup 1) | |
1217 | (pc)) | |
1218 | (const_int 254)) | |
1219 | (const_int 506)) | |
1220 | (const_int 2) | |
1221 | (if_then_else (eq_attr "size" "small") | |
1222 | (const_int 8) | |
1223 | (const_int 10)))) | |
1224 | (set_attr "delay_type" "delayed")] | |
1225 | ) | |
1226 | ||
1227 | ||
1228 | ;; This pattern is a duplicate of the previous one, except that the | |
1229 | ;; branch occurs if the test is false, so the %B operator is used. | |
1230 | (define_insn "*branch_false" | |
1231 | [(set (pc) | |
1232 | (if_then_else (match_operator:CC 0 "comparison_operator" | |
1233 | [(reg:CC 16) | |
1234 | (const_int 0)]) | |
1235 | (pc) | |
1236 | (label_ref (match_operand 1 "" ""))))] | |
1237 | "" | |
1238 | "* | |
1239 | { | |
1240 | if (get_attr_length (insn) == 2) | |
1241 | return \"b%B0%#\\t%l1 \"; | |
1242 | else | |
1243 | { | |
82a9bba5 NC |
1244 | static char buffer [100]; |
1245 | const char * tmp_reg; | |
1943c2c1 | 1246 | const char * ldi_insn; |
309dd885 NC |
1247 | |
1248 | tmp_reg = reg_names [COMPILER_SCRATCH_REGISTER]; | |
1249 | ||
1250 | ldi_insn = TARGET_SMALL_MODEL ? \"ldi:20\" : \"ldi:32\"; | |
1251 | ||
1252 | sprintf (buffer, | |
1253 | \"b%%b0\\t1f\\t;\\n\\t%s\\t%%l1, %s\\t;\\n\\tjmp%%#\\t@%s\\t;\\n1:\", | |
1254 | ldi_insn, tmp_reg, tmp_reg); | |
1255 | ||
1256 | return buffer; | |
1257 | } | |
1258 | }" | |
1259 | [(set (attr "length") (if_then_else (ltu (plus (minus (match_dup 1) (pc)) | |
1260 | (const_int 254)) | |
1261 | (const_int 506)) | |
1262 | (const_int 2) | |
1263 | (if_then_else (eq_attr "size" "small") | |
1264 | (const_int 8) | |
1265 | (const_int 10)))) | |
1266 | (set_attr "delay_type" "delayed")] | |
1267 | ) | |
1268 | ||
1269 | ;;}}} \f | |
1270 | ;;{{{ Calls & Jumps | |
1271 | ||
1272 | ;; Subroutine call instruction returning no value. Operand 0 is the function | |
1273 | ;; to call; operand 1 is the number of bytes of arguments pushed (in mode | |
1274 | ;; `SImode', except it is normally a `const_int'); operand 2 is the number of | |
1275 | ;; registers used as operands. | |
1276 | ||
1277 | (define_insn "call" | |
6e11d5e9 | 1278 | [(call (match_operand 0 "call_operand" "Qm") |
309dd885 NC |
1279 | (match_operand 1 "" "g")) |
1280 | (clobber (reg:SI 17))] | |
1281 | "" | |
1282 | "call%#\\t%0" | |
1283 | [(set_attr "delay_type" "delayed")] | |
1284 | ) | |
1285 | ||
1286 | ;; Subroutine call instruction returning a value. Operand 0 is the hard | |
1287 | ;; register in which the value is returned. There are three more operands, the | |
1288 | ;; same as the three operands of the `call' instruction (but with numbers | |
1289 | ;; increased by one). | |
1290 | ||
1291 | ;; Subroutines that return `BLKmode' objects use the `call' insn. | |
1292 | ||
1293 | (define_insn "call_value" | |
1294 | [(set (match_operand 0 "register_operand" "=r") | |
6e11d5e9 | 1295 | (call (match_operand 1 "call_operand" "Qm") |
309dd885 NC |
1296 | (match_operand 2 "" "g"))) |
1297 | (clobber (reg:SI 17))] | |
1298 | "" | |
1299 | "call%#\\t%1" | |
1300 | [(set_attr "delay_type" "delayed")] | |
1301 | ) | |
1302 | ||
1303 | ;; Normal unconditional jump. | |
1304 | ;; For a description of the computation of the length | |
1305 | ;; attribute see the branch patterns above. | |
a29b099d JJ |
1306 | ;; |
1307 | ;; Although this instruction really clobbers r0, flow | |
1308 | ;; relies on jump being simplejump_p in several places | |
1309 | ;; and as r0 is fixed, this doesn't change anything | |
309dd885 | 1310 | (define_insn "jump" |
a29b099d | 1311 | [(set (pc) (label_ref (match_operand 0 "" "")))] |
309dd885 NC |
1312 | "" |
1313 | "* | |
1314 | { | |
1315 | if (get_attr_length (insn) == 2) | |
1316 | return \"bra%#\\t%0\"; | |
1317 | else | |
1318 | { | |
82a9bba5 NC |
1319 | static char buffer [100]; |
1320 | const char * tmp_reg; | |
1943c2c1 | 1321 | const char * ldi_insn; |
309dd885 NC |
1322 | |
1323 | tmp_reg = reg_names [COMPILER_SCRATCH_REGISTER]; | |
1324 | ||
1325 | ldi_insn = TARGET_SMALL_MODEL ? \"ldi:20\" : \"ldi:32\"; | |
1326 | ||
1327 | sprintf (buffer, \"%s\\t%%0, %s\\t;\\n\\tjmp%%#\\t@%s\\t;\", | |
1328 | ldi_insn, tmp_reg, tmp_reg); | |
1329 | ||
1330 | return buffer; | |
1331 | } | |
1332 | }" | |
1333 | [(set (attr "length") (if_then_else (ltu (plus (minus (match_dup 0) (pc)) | |
1334 | (const_int 254)) | |
1335 | (const_int 506)) | |
1336 | (const_int 2) | |
1337 | (if_then_else (eq_attr "size" "small") | |
1338 | (const_int 6) | |
1339 | (const_int 8)))) | |
1340 | (set_attr "delay_type" "delayed")] | |
1341 | ) | |
1342 | ||
1343 | ;; Indirect jump through a register | |
1344 | (define_insn "indirect_jump" | |
1345 | [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "r"))] | |
1346 | "GET_CODE (operands[0]) != MEM || GET_CODE (XEXP (operands[0], 0)) != PLUS" | |
1347 | "jmp%#\\t@%0" | |
1348 | [(set_attr "delay_type" "delayed")] | |
1349 | ) | |
1350 | ||
1351 | (define_insn "tablejump" | |
1352 | [(set (pc) (match_operand:SI 0 "register_operand" "r")) | |
1353 | (use (label_ref (match_operand 1 "" "")))] | |
1354 | "" | |
1355 | "jmp%#\\t@%0" | |
1356 | [(set_attr "delay_type" "delayed")] | |
1357 | ) | |
1358 | ||
1359 | ;;}}} \f | |
1360 | ;;{{{ Function Prologues and Epilogues | |
1361 | ||
1362 | ;; Called after register allocation to add any instructions needed for the | |
1363 | ;; prologue. Using a prologue insn is favored compared to putting all of the | |
08c148a8 | 1364 | ;; instructions in output_function_prologue(), since it allows the scheduler |
309dd885 NC |
1365 | ;; to intermix instructions with the saves of the caller saved registers. In |
1366 | ;; some cases, it might be necessary to emit a barrier instruction as the last | |
1367 | ;; insn to prevent such scheduling. | |
1368 | (define_expand "prologue" | |
82a9bba5 | 1369 | [(clobber (const_int 0))] |
309dd885 NC |
1370 | "" |
1371 | "{ | |
1372 | fr30_expand_prologue (); | |
1373 | DONE; | |
1374 | }" | |
1375 | ) | |
1376 | ||
1377 | ;; Called after register allocation to add any instructions needed for the | |
5519a4f9 | 1378 | ;; epilogue. Using an epilogue insn is favored compared to putting all of the |
08c148a8 | 1379 | ;; instructions in output_function_epilogue(), since it allows the scheduler |
309dd885 NC |
1380 | ;; to intermix instructions with the restores of the caller saved registers. |
1381 | ;; In some cases, it might be necessary to emit a barrier instruction as the | |
1382 | ;; first insn to prevent such scheduling. | |
1383 | (define_expand "epilogue" | |
1384 | [(return)] | |
1385 | "" | |
1386 | "{ | |
1387 | fr30_expand_epilogue (); | |
1388 | DONE; | |
1389 | }" | |
1390 | ) | |
1391 | ||
1392 | (define_insn "return_from_func" | |
1393 | [(return) | |
1394 | (use (reg:SI 17))] | |
1395 | "reload_completed" | |
1396 | "ret%#" | |
1397 | [(set_attr "delay_type" "delayed")] | |
1398 | ) | |
1399 | ||
1400 | (define_insn "leave_func" | |
1401 | [(set (reg:SI 15) (reg:SI 14)) | |
1402 | (set (reg:SI 14) (mem:SI (post_inc:SI (reg:SI 15))))] | |
1403 | "reload_completed" | |
1404 | "leave" | |
1405 | ) | |
1406 | ||
1407 | (define_insn "enter_func" | |
1408 | [(set:SI (mem:SI (minus:SI (reg:SI 15) | |
1409 | (const_int 4))) | |
1410 | (reg:SI 14)) | |
1411 | (set:SI (reg:SI 14) | |
1412 | (minus:SI (reg:SI 15) | |
1413 | (const_int 4))) | |
1414 | (set:SI (reg:SI 15) | |
1415 | (minus:SI (reg:SI 15) | |
1416 | (match_operand 0 "immediate_operand" "i")))] | |
1417 | "reload_completed" | |
1418 | "enter #%0" | |
1419 | [(set_attr "delay_type" "other")] | |
1420 | ) | |
1421 | ||
1422 | ;;}}} \f | |
1423 | ;;{{{ Miscellaneous | |
1424 | ||
1425 | ;; No operation, needed in case the user uses -g but not -O. | |
1426 | (define_insn "nop" | |
1427 | [(const_int 0)] | |
1428 | "" | |
1429 | "nop" | |
1430 | ) | |
1431 | ||
1432 | ;; Pseudo instruction that prevents the scheduler from moving code above this | |
1433 | ;; point. | |
1434 | (define_insn "blockage" | |
1435 | [(unspec_volatile [(const_int 0)] 0)] | |
1436 | "" | |
1437 | "" | |
1438 | [(set_attr "length" "0")] | |
1439 | ) | |
5c7666c1 | 1440 | ;;}}} \f |
309dd885 NC |
1441 | |
1442 | ;; Local Variables: | |
1443 | ;; mode: md | |
1444 | ;; folded-file: t | |
1445 | ;; End: |