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