]>
Commit | Line | Data |
---|---|---|
65a324b4 | 1 | ;; Machine Description for Renesas RX processors |
15ba5696 | 2 | ;; Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc. |
65a324b4 NC |
3 | ;; Contributed by Red Hat. |
4 | ||
5 | ;; This file is part of GCC. | |
6 | ||
7 | ;; GCC is free software; you can redistribute it and/or modify | |
8 | ;; it under the terms of the GNU General Public License as published by | |
9 | ;; the Free Software Foundation; either version 3, or (at your option) | |
10 | ;; any later version. | |
11 | ||
12 | ;; GCC is distributed in the hope that it will be useful, | |
13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | ;; GNU General Public License for more details. | |
16 | ||
17 | ;; You should have received a copy of the GNU General Public License | |
18 | ;; along with GCC; see the file COPYING3. If not see | |
19 | ;; <http://www.gnu.org/licenses/>. | |
20 | \f | |
21 | ||
65a324b4 NC |
22 | ;; This code iterator is used for sign- and zero- extensions. |
23 | (define_mode_iterator small_int_modes [(HI "") (QI "")]) | |
24 | ||
9595a419 NC |
25 | ;; We do not handle DFmode here because it is either |
26 | ;; the same as SFmode, or if -m64bit-doubles is active | |
65a324b4 NC |
27 | ;; then all operations on doubles have to be handled by |
28 | ;; library functions. | |
29 | (define_mode_iterator register_modes | |
30 | [(SF "ALLOW_RX_FPU_INSNS") (SI "") (HI "") (QI "")]) | |
31 | ||
65a324b4 NC |
32 | (define_constants |
33 | [ | |
34 | (SP_REG 0) | |
aea8fc97 | 35 | (CC_REG 16) |
65a324b4 NC |
36 | |
37 | (UNSPEC_LOW_REG 0) | |
38 | (UNSPEC_HIGH_REG 1) | |
39 | ||
40 | (UNSPEC_RTE 10) | |
41 | (UNSPEC_RTFI 11) | |
42 | (UNSPEC_NAKED 12) | |
15ba5696 | 43 | (UNSPEC_CONST 13) |
65a324b4 NC |
44 | |
45 | (UNSPEC_MOVSTR 20) | |
46 | (UNSPEC_MOVMEM 21) | |
47 | (UNSPEC_SETMEM 22) | |
48 | (UNSPEC_STRLEN 23) | |
49 | (UNSPEC_CMPSTRN 24) | |
50 | ||
51 | (UNSPEC_BUILTIN_BRK 30) | |
52 | (UNSPEC_BUILTIN_CLRPSW 31) | |
53 | (UNSPEC_BUILTIN_INT 32) | |
54 | (UNSPEC_BUILTIN_MACHI 33) | |
55 | (UNSPEC_BUILTIN_MACLO 34) | |
56 | (UNSPEC_BUILTIN_MULHI 35) | |
57 | (UNSPEC_BUILTIN_MULLO 36) | |
58 | (UNSPEC_BUILTIN_MVFACHI 37) | |
59 | (UNSPEC_BUILTIN_MVFACMI 38) | |
60 | (UNSPEC_BUILTIN_MVFC 39) | |
61 | (UNSPEC_BUILTIN_MVFCP 40) | |
62 | (UNSPEC_BUILTIN_MVTACHI 41) | |
63 | (UNSPEC_BUILTIN_MVTACLO 42) | |
64 | (UNSPEC_BUILTIN_MVTC 43) | |
9595a419 NC |
65 | (UNSPEC_BUILTIN_MVTIPL 44) |
66 | (UNSPEC_BUILTIN_RACW 45) | |
67 | (UNSPEC_BUILTIN_REVW 46) | |
68 | (UNSPEC_BUILTIN_RMPA 47) | |
69 | (UNSPEC_BUILTIN_ROUND 48) | |
70 | (UNSPEC_BUILTIN_SAT 49) | |
71 | (UNSPEC_BUILTIN_SETPSW 50) | |
72 | (UNSPEC_BUILTIN_WAIT 51) | |
65a324b4 NC |
73 | ] |
74 | ) | |
75 | ||
65a324b4 NC |
76 | (define_attr "length" "" (const_int 8)) |
77 | ||
78 | (include "predicates.md") | |
79 | (include "constraints.md") | |
80 | ||
81 | ;; Pipeline description. | |
82 | ||
83 | ;; The RX only has a single pipeline. It has five stages (fetch, | |
84 | ;; decode, execute, memory access, writeback) each of which normally | |
85 | ;; takes a single CPU clock cycle. | |
86 | ||
87 | ;; The timings attribute consists of two numbers, the first is the | |
88 | ;; throughput, which is the number of cycles the instruction takes | |
89 | ;; to execute and generate a result. The second is the latency | |
90 | ;; which is the effective number of cycles the instruction takes to | |
91 | ;; execute if its result is used by the following instruction. The | |
92 | ;; latency is always greater than or equal to the throughput. | |
93 | ;; These values were taken from tables 2.13 and 2.14 in section 2.8 | |
94 | ;; of the RX610 Group Hardware Manual v0.11 | |
95 | ||
96 | ;; Note - it would be nice to use strings rather than integers for | |
97 | ;; the possible values of this attribute, so that we can have the | |
98 | ;; gcc build mechanism check for values that are not supported by | |
99 | ;; the reservations below. But this will not work because the code | |
100 | ;; in rx_adjust_sched_cost() needs integers not strings. | |
101 | ||
102 | (define_attr "timings" "" (const_int 11)) | |
103 | ||
104 | (define_automaton "pipelining") | |
105 | (define_cpu_unit "throughput" "pipelining") | |
106 | ||
107 | (define_insn_reservation "throughput__1_latency__1" 1 | |
108 | (eq_attr "timings" "11") "throughput") | |
109 | (define_insn_reservation "throughput__1_latency__2" 2 | |
110 | (eq_attr "timings" "12") "throughput,nothing") | |
111 | (define_insn_reservation "throughput__2_latency__2" 1 | |
112 | (eq_attr "timings" "22") "throughput*2") | |
113 | (define_insn_reservation "throughput__3_latency__3" 1 | |
114 | (eq_attr "timings" "33") "throughput*3") | |
115 | (define_insn_reservation "throughput__3_latency__4" 2 | |
116 | (eq_attr "timings" "34") "throughput*3,nothing") | |
117 | (define_insn_reservation "throughput__4_latency__4" 1 | |
118 | (eq_attr "timings" "44") "throughput*4") | |
119 | (define_insn_reservation "throughput__4_latency__5" 2 | |
120 | (eq_attr "timings" "45") "throughput*4,nothing") | |
121 | (define_insn_reservation "throughput__5_latency__5" 1 | |
122 | (eq_attr "timings" "55") "throughput*5") | |
123 | (define_insn_reservation "throughput__5_latency__6" 2 | |
124 | (eq_attr "timings" "56") "throughput*5,nothing") | |
125 | (define_insn_reservation "throughput__6_latency__6" 1 | |
126 | (eq_attr "timings" "66") "throughput*6") | |
127 | (define_insn_reservation "throughput_10_latency_10" 1 | |
128 | (eq_attr "timings" "1010") "throughput*10") | |
129 | (define_insn_reservation "throughput_11_latency_11" 1 | |
130 | (eq_attr "timings" "1111") "throughput*11") | |
131 | (define_insn_reservation "throughput_16_latency_16" 1 | |
132 | (eq_attr "timings" "1616") "throughput*16") | |
133 | (define_insn_reservation "throughput_18_latency_18" 1 | |
134 | (eq_attr "timings" "1818") "throughput*18") | |
135 | ||
e963cb1a RH |
136 | ;; ---------------------------------------------------------------------------- |
137 | ||
65a324b4 NC |
138 | ;; Comparisons |
139 | ||
aea8fc97 NC |
140 | ;; Note - we do not specify the two instructions necessary to perform |
141 | ;; a compare-and-branch in the cbranchsi4 pattern because that would | |
142 | ;; allow the comparison to be moved away from the jump before the reload | |
143 | ;; pass has completed. That would be problematical because reload can | |
144 | ;; generate ADDSI3 instructions which would corrupt the PSW flags. | |
145 | ||
65a324b4 | 146 | (define_expand "cbranchsi4" |
aea8fc97 | 147 | [(set (pc) |
e963cb1a RH |
148 | (if_then_else |
149 | (match_operator 0 "comparison_operator" | |
150 | [(match_operand:SI 1 "register_operand") | |
151 | (match_operand:SI 2 "rx_source_operand")]) | |
152 | (label_ref (match_operand 3 "")) | |
153 | (pc)))] | |
65a324b4 NC |
154 | "" |
155 | ) | |
156 | ||
e963cb1a | 157 | (define_insn_and_split "*cbranchsi4" |
aea8fc97 | 158 | [(set (pc) |
e963cb1a RH |
159 | (if_then_else |
160 | (match_operator 3 "comparison_operator" | |
161 | [(match_operand:SI 0 "register_operand" "r") | |
162 | (match_operand:SI 1 "rx_source_operand" "riQ")]) | |
163 | (match_operand 2 "label_ref_operand" "") | |
164 | (pc)))] | |
aea8fc97 NC |
165 | "" |
166 | "#" | |
167 | "reload_completed" | |
168 | [(const_int 0)] | |
e963cb1a RH |
169 | { |
170 | rx_split_cbranch (CCmode, GET_CODE (operands[3]), | |
171 | operands[0], operands[1], operands[2]); | |
172 | DONE; | |
173 | }) | |
aea8fc97 | 174 | |
e963cb1a RH |
175 | (define_insn "*cmpsi" |
176 | [(set (reg:CC CC_REG) | |
177 | (compare:CC (match_operand:SI 0 "register_operand" "r,r,r,r,r,r,r") | |
178 | (match_operand:SI 1 "rx_source_operand" "r,Uint04,Int08,Sint16,Sint24,i,Q")))] | |
cf6521b4 | 179 | "reload_completed" |
e963cb1a RH |
180 | "cmp\t%Q1, %0" |
181 | [(set_attr "timings" "11,11,11,11,11,11,33") | |
182 | (set_attr "length" "2,2,3,4,5,6,5")] | |
cf6521b4 DD |
183 | ) |
184 | ||
e963cb1a RH |
185 | ;; Canonical method for representing TST. |
186 | (define_insn_and_split "*cbranchsi4_tst" | |
cf6521b4 | 187 | [(set (pc) |
e963cb1a RH |
188 | (if_then_else |
189 | (match_operator 3 "rx_zs_comparison_operator" | |
190 | [(and:SI (match_operand:SI 0 "register_operand" "r") | |
191 | (match_operand:SI 1 "rx_source_operand" "riQ")) | |
192 | (const_int 0)]) | |
193 | (match_operand 2 "label_ref_operand" "") | |
194 | (pc)))] | |
cf6521b4 DD |
195 | "" |
196 | "#" | |
197 | "reload_completed" | |
198 | [(const_int 0)] | |
e963cb1a RH |
199 | { |
200 | rx_split_cbranch (CC_ZSmode, GET_CODE (operands[3]), | |
201 | XEXP (operands[3], 0), XEXP (operands[3], 1), | |
202 | operands[2]); | |
203 | DONE; | |
204 | }) | |
cf6521b4 DD |
205 | |
206 | ;; Various other ways that GCC codes "var & const" | |
e963cb1a | 207 | (define_insn_and_split "*cbranchsi4_tst_ext" |
cf6521b4 | 208 | [(set (pc) |
e963cb1a RH |
209 | (if_then_else |
210 | (match_operator 4 "rx_z_comparison_operator" | |
211 | [(zero_extract:SI | |
212 | (match_operand:SI 0 "register_operand" "r") | |
213 | (match_operand:SI 1 "rx_constshift_operand" "") | |
214 | (match_operand:SI 2 "rx_constshift_operand" "")) | |
215 | (const_int 0)]) | |
216 | (match_operand 3 "label_ref_operand" "") | |
217 | (pc)))] | |
cf6521b4 DD |
218 | "" |
219 | "#" | |
e963cb1a RH |
220 | "reload_completed" |
221 | [(const_int 0)] | |
222 | { | |
223 | HOST_WIDE_INT mask; | |
224 | rtx x; | |
225 | ||
226 | mask = 1; | |
227 | mask <<= INTVAL (operands[1]); | |
228 | mask -= 1; | |
229 | mask <<= INTVAL (operands[2]); | |
230 | x = gen_rtx_AND (SImode, operands[0], gen_int_mode (mask, SImode)); | |
231 | ||
232 | rx_split_cbranch (CC_ZSmode, GET_CODE (operands[4]), | |
233 | x, const0_rtx, operands[3]); | |
234 | DONE; | |
235 | }) | |
236 | ||
237 | (define_insn "*tstsi" | |
238 | [(set (reg:CC_ZS CC_REG) | |
239 | (compare:CC_ZS | |
240 | (and:SI (match_operand:SI 0 "register_operand" "r,r,r") | |
241 | (match_operand:SI 1 "rx_source_operand" "r,i,Q")) | |
242 | (const_int 0)))] | |
243 | "reload_completed" | |
244 | "tst\t%Q1, %0" | |
245 | [(set_attr "timings" "11,11,33") | |
246 | (set_attr "length" "3,7,6")] | |
cf6521b4 DD |
247 | ) |
248 | ||
65a324b4 | 249 | (define_expand "cbranchsf4" |
aea8fc97 | 250 | [(set (pc) |
e963cb1a | 251 | (if_then_else |
440eb8de | 252 | (match_operator 0 "rx_fp_comparison_operator" |
e963cb1a | 253 | [(match_operand:SF 1 "register_operand") |
440eb8de RH |
254 | (match_operand:SF 2 "rx_source_operand")]) |
255 | (label_ref (match_operand 3 "")) | |
e963cb1a | 256 | (pc)))] |
aea8fc97 | 257 | "ALLOW_RX_FPU_INSNS" |
440eb8de | 258 | ) |
e963cb1a RH |
259 | |
260 | (define_insn_and_split "*cbranchsf4" | |
aea8fc97 | 261 | [(set (pc) |
e963cb1a RH |
262 | (if_then_else |
263 | (match_operator 3 "rx_fp_comparison_operator" | |
264 | [(match_operand:SF 0 "register_operand" "r") | |
440eb8de | 265 | (match_operand:SF 1 "rx_source_operand" "rFQ")]) |
e963cb1a RH |
266 | (match_operand 2 "label_ref_operand" "") |
267 | (pc)))] | |
aea8fc97 NC |
268 | "ALLOW_RX_FPU_INSNS" |
269 | "#" | |
270 | "&& reload_completed" | |
271 | [(const_int 0)] | |
e963cb1a | 272 | { |
440eb8de RH |
273 | rx_split_cbranch (CC_Fmode, GET_CODE (operands[3]), |
274 | operands[0], operands[1], operands[2]); | |
e963cb1a RH |
275 | DONE; |
276 | }) | |
277 | ||
278 | (define_insn "*cmpsf" | |
279 | [(set (reg:CC_F CC_REG) | |
280 | (compare:CC_F | |
281 | (match_operand:SF 0 "register_operand" "r,r,r") | |
440eb8de | 282 | (match_operand:SF 1 "rx_source_operand" "r,F,Q")))] |
e963cb1a RH |
283 | "ALLOW_RX_FPU_INSNS && reload_completed" |
284 | "fcmp\t%1, %0" | |
aea8fc97 | 285 | [(set_attr "timings" "11,11,33") |
65a324b4 NC |
286 | (set_attr "length" "3,7,5")] |
287 | ) | |
288 | ||
289 | ;; Flow Control Instructions: | |
290 | ||
e963cb1a | 291 | (define_insn "*conditional_branch" |
65a324b4 | 292 | [(set (pc) |
e963cb1a RH |
293 | (if_then_else |
294 | (match_operator 1 "comparison_operator" | |
295 | [(reg CC_REG) (const_int 0)]) | |
296 | (label_ref (match_operand 0 "" "")) | |
297 | (pc)))] | |
440eb8de | 298 | "reload_completed" |
e963cb1a | 299 | "b%B1\t%0" |
65a324b4 NC |
300 | [(set_attr "length" "8") ;; This length is wrong, but it is |
301 | ;; too hard to compute statically. | |
aea8fc97 | 302 | (set_attr "timings" "33")] ;; The timing assumes that the branch is taken. |
65a324b4 NC |
303 | ) |
304 | ||
e963cb1a | 305 | ;; ---------------------------------------------------------------------------- |
65a324b4 NC |
306 | |
307 | (define_insn "jump" | |
aea8fc97 NC |
308 | [(set (pc) |
309 | (label_ref (match_operand 0 "" "")))] | |
65a324b4 NC |
310 | "" |
311 | "bra\t%0" | |
312 | [(set_attr "length" "4") | |
aea8fc97 | 313 | (set_attr "timings" "33")] |
65a324b4 NC |
314 | ) |
315 | ||
316 | (define_insn "indirect_jump" | |
aea8fc97 NC |
317 | [(set (pc) |
318 | (match_operand:SI 0 "register_operand" "r"))] | |
65a324b4 NC |
319 | "" |
320 | "jmp\t%0" | |
321 | [(set_attr "length" "2") | |
aea8fc97 | 322 | (set_attr "timings" "33")] |
65a324b4 NC |
323 | ) |
324 | ||
325 | (define_insn "tablejump" | |
aea8fc97 NC |
326 | [(set (pc) |
327 | (match_operand:SI 0 "register_operand" "r")) | |
65a324b4 NC |
328 | (use (label_ref (match_operand 1 "" "")))] |
329 | "" | |
330 | { return flag_pic ? (TARGET_AS100_SYNTAX ? "\n?:\tbra\t%0" | |
331 | : "\n1:\tbra\t%0") | |
332 | : "jmp\t%0"; | |
333 | } | |
aea8fc97 | 334 | [(set_attr "timings" "33") |
65a324b4 NC |
335 | (set_attr "length" "2")] |
336 | ) | |
337 | ||
338 | (define_insn "simple_return" | |
339 | [(return)] | |
340 | "" | |
341 | "rts" | |
342 | [(set_attr "length" "1") | |
343 | (set_attr "timings" "55")] | |
344 | ) | |
345 | ||
15ba5696 NC |
346 | ;; Unspec used so that the constant will not be invalid |
347 | ;; if -mmax-constant-size has been specified. | |
65a324b4 NC |
348 | (define_insn "deallocate_and_return" |
349 | [(set (reg:SI SP_REG) | |
350 | (plus:SI (reg:SI SP_REG) | |
15ba5696 | 351 | (const:SI (unspec:SI [(match_operand 0 "const_int_operand" "n")] UNSPEC_CONST)))) |
65a324b4 NC |
352 | (return)] |
353 | "" | |
354 | "rtsd\t%0" | |
355 | [(set_attr "length" "2") | |
356 | (set_attr "timings" "55")] | |
357 | ) | |
358 | ||
359 | (define_insn "pop_and_return" | |
aea8fc97 | 360 | [(match_parallel 1 "rx_rtsd_vector" |
265c835f RH |
361 | [(set (reg:SI SP_REG) |
362 | (plus:SI (reg:SI SP_REG) | |
15ba5696 NC |
363 | (match_operand:SI 0 "const_int_operand" "n")))]) |
364 | (return)] | |
65a324b4 NC |
365 | "reload_completed" |
366 | { | |
367 | rx_emit_stack_popm (operands, false); | |
368 | return ""; | |
369 | } | |
370 | [(set_attr "length" "3") | |
371 | (set_attr "timings" "56")] | |
372 | ) | |
373 | ||
374 | (define_insn "fast_interrupt_return" | |
375 | [(unspec_volatile [(return)] UNSPEC_RTFI) ] | |
376 | "" | |
377 | "rtfi" | |
378 | [(set_attr "length" "2") | |
379 | (set_attr "timings" "33")] | |
380 | ) | |
381 | ||
382 | (define_insn "exception_return" | |
383 | [(unspec_volatile [(return)] UNSPEC_RTE) ] | |
384 | "" | |
385 | "rte" | |
386 | [(set_attr "length" "2") | |
387 | (set_attr "timings" "66")] | |
388 | ) | |
389 | ||
390 | (define_insn "naked_return" | |
391 | [(unspec_volatile [(return)] UNSPEC_NAKED) ] | |
392 | "" | |
393 | "; Naked function: epilogue provided by programmer." | |
394 | ) | |
395 | ||
396 | ||
397 | ;; Note - the following set of patterns do not use the "memory_operand" | |
398 | ;; predicate or an "m" constraint because we do not allow symbol_refs | |
399 | ;; or label_refs as legitmate memory addresses. This matches the | |
400 | ;; behaviour of most of the RX instructions. Only the call/branch | |
401 | ;; instructions are allowed to refer to symbols/labels directly. | |
402 | ;; The call operands are in QImode because that is the value of | |
403 | ;; FUNCTION_MODE | |
404 | ||
405 | (define_expand "call" | |
406 | [(call (match_operand:QI 0 "general_operand") | |
407 | (match_operand:SI 1 "general_operand"))] | |
408 | "" | |
409 | { | |
410 | rtx dest = XEXP (operands[0], 0); | |
411 | ||
412 | if (! rx_call_operand (dest, Pmode)) | |
413 | dest = force_reg (Pmode, dest); | |
15ba5696 | 414 | emit_call_insn (gen_call_internal (dest)); |
65a324b4 NC |
415 | DONE; |
416 | } | |
417 | ) | |
418 | ||
419 | (define_insn "call_internal" | |
420 | [(call (mem:QI (match_operand:SI 0 "rx_call_operand" "r,Symbol")) | |
15ba5696 | 421 | (const_int 0)) |
aea8fc97 | 422 | (clobber (reg:CC CC_REG))] |
65a324b4 NC |
423 | "" |
424 | "@ | |
0d8f38d3 | 425 | jsr\t%0 |
65a324b4 NC |
426 | bsr\t%A0" |
427 | [(set_attr "length" "2,4") | |
428 | (set_attr "timings" "33")] | |
429 | ) | |
430 | ||
431 | (define_expand "call_value" | |
432 | [(set (match_operand 0 "register_operand") | |
433 | (call (match_operand:QI 1 "general_operand") | |
434 | (match_operand:SI 2 "general_operand")))] | |
435 | "" | |
436 | { | |
437 | rtx dest = XEXP (operands[1], 0); | |
438 | ||
439 | if (! rx_call_operand (dest, Pmode)) | |
440 | dest = force_reg (Pmode, dest); | |
15ba5696 | 441 | emit_call_insn (gen_call_value_internal (operands[0], dest)); |
65a324b4 NC |
442 | DONE; |
443 | } | |
444 | ) | |
445 | ||
446 | (define_insn "call_value_internal" | |
447 | [(set (match_operand 0 "register_operand" "=r,r") | |
448 | (call (mem:QI (match_operand:SI 1 "rx_call_operand" "r,Symbol")) | |
15ba5696 | 449 | (const_int 0))) |
aea8fc97 | 450 | (clobber (reg:CC CC_REG))] |
65a324b4 NC |
451 | "" |
452 | "@ | |
0d8f38d3 | 453 | jsr\t%1 |
65a324b4 NC |
454 | bsr\t%A1" |
455 | [(set_attr "length" "2,4") | |
456 | (set_attr "timings" "33")] | |
457 | ) | |
458 | ||
0d8f38d3 NC |
459 | ;; Note - we do not allow indirect sibcalls (with the address |
460 | ;; held in a register) because we cannot guarantee that the register | |
461 | ;; chosen will be a call-used one. If it is a call-saved register, | |
462 | ;; then the epilogue code will corrupt it by popping the saved value | |
463 | ;; off of the stack. | |
464 | (define_expand "sibcall" | |
465 | [(parallel | |
466 | [(call (mem:QI (match_operand:SI 0 "rx_symbolic_call_operand")) | |
467 | (match_operand:SI 1 "general_operand")) | |
468 | (return)])] | |
469 | "" | |
470 | { | |
471 | if (MEM_P (operands[0])) | |
472 | operands[0] = XEXP (operands[0], 0); | |
15ba5696 NC |
473 | emit_call_insn (gen_sibcall_internal (operands[0])); |
474 | DONE; | |
0d8f38d3 NC |
475 | } |
476 | ) | |
477 | ||
478 | (define_insn "sibcall_internal" | |
479 | [(call (mem:QI (match_operand:SI 0 "rx_symbolic_call_operand" "Symbol")) | |
15ba5696 | 480 | (const_int 0)) |
0d8f38d3 | 481 | (return)] |
65a324b4 NC |
482 | "" |
483 | "bra\t%A0" | |
0d8f38d3 | 484 | [(set_attr "length" "4") |
65a324b4 NC |
485 | (set_attr "timings" "33")] |
486 | ) | |
487 | ||
0d8f38d3 NC |
488 | (define_expand "sibcall_value" |
489 | [(parallel | |
490 | [(set (match_operand 0 "register_operand") | |
491 | (call (mem:QI (match_operand:SI 1 "rx_symbolic_call_operand")) | |
492 | (match_operand:SI 2 "general_operand"))) | |
493 | (return)])] | |
494 | "" | |
495 | { | |
496 | if (MEM_P (operands[1])) | |
497 | operands[1] = XEXP (operands[1], 0); | |
15ba5696 NC |
498 | emit_call_insn (gen_sibcall_value_internal (operands[0], operands[1])); |
499 | DONE; | |
0d8f38d3 NC |
500 | } |
501 | ) | |
502 | ||
503 | (define_insn "sibcall_value_internal" | |
65a324b4 NC |
504 | [(set (match_operand 0 "register_operand" "=r") |
505 | (call (mem:QI (match_operand:SI 1 "rx_symbolic_call_operand" "Symbol")) | |
15ba5696 | 506 | (const_int 0))) |
0d8f38d3 | 507 | (return)] |
65a324b4 NC |
508 | "" |
509 | "bra\t%A1" | |
0d8f38d3 | 510 | [(set_attr "length" "4") |
65a324b4 NC |
511 | (set_attr "timings" "33")] |
512 | ) | |
513 | ||
514 | ;; Function Prologue/Epilogue Instructions | |
515 | ||
516 | (define_expand "prologue" | |
517 | [(const_int 0)] | |
518 | "" | |
519 | "rx_expand_prologue (); DONE;" | |
520 | ) | |
521 | ||
522 | (define_expand "epilogue" | |
523 | [(return)] | |
524 | "" | |
525 | "rx_expand_epilogue (false); DONE;" | |
526 | ) | |
527 | ||
528 | (define_expand "sibcall_epilogue" | |
529 | [(return)] | |
530 | "" | |
531 | "rx_expand_epilogue (true); DONE;" | |
532 | ) | |
533 | ||
534 | ;; Move Instructions | |
535 | ||
536 | ;; Note - we do not allow memory to memory moves, even though the ISA | |
537 | ;; supports them. The reason is that the conditions on such moves are | |
538 | ;; too restrictive, specifically the source addressing mode is limited | |
539 | ;; by the destination addressing mode and vice versa. (For example it | |
540 | ;; is not possible to use indexed register indirect addressing for one | |
541 | ;; of the operands if the other operand is anything other than a register, | |
542 | ;; but it is possible to use register relative addressing when the other | |
543 | ;; operand also uses register relative or register indirect addressing). | |
544 | ;; | |
545 | ;; GCC does not support computing legitimate addresses based on the | |
546 | ;; nature of other operands involved in the instruction, and reload is | |
547 | ;; not smart enough to cope with a whole variety of different memory | |
548 | ;; addressing constraints, so it is simpler and safer to just refuse | |
549 | ;; to support memory to memory moves. | |
550 | ||
551 | (define_expand "mov<register_modes:mode>" | |
552 | [(set (match_operand:register_modes 0 "general_operand") | |
553 | (match_operand:register_modes 1 "general_operand"))] | |
554 | "" | |
555 | { | |
556 | if (MEM_P (operand0) && MEM_P (operand1)) | |
557 | operands[1] = copy_to_mode_reg (<register_modes:MODE>mode, operand1); | |
15ba5696 | 558 | if (CONST_INT_P (operand1) |
1a627b35 | 559 | && ! rx_legitimate_constant_p (<register_modes:MODE>mode, operand1)) |
15ba5696 | 560 | FAIL; |
65a324b4 NC |
561 | } |
562 | ) | |
563 | ||
564 | (define_insn "*mov<register_modes:mode>_internal" | |
565 | [(set (match_operand:register_modes | |
566 | 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,Q,Q,Q,Q") | |
567 | (match_operand:register_modes | |
568 | 1 "general_operand" "Int08,Sint16,Sint24,i,r,m,r,Int08,Sint16,Sint24,i"))] | |
569 | "" | |
570 | { return rx_gen_move_template (operands, false); } | |
571 | [(set_attr "length" "3,4,5,6,2,4,6,5,6,7,8") | |
572 | (set_attr "timings" "11,11,11,11,11,12,11,11,11,11,11")] | |
573 | ) | |
574 | ||
575 | (define_insn "extend<small_int_modes:mode>si2" | |
576 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
577 | (sign_extend:SI (match_operand:small_int_modes | |
578 | 1 "nonimmediate_operand" "r,m")))] | |
579 | "" | |
580 | { return rx_gen_move_template (operands, false); } | |
581 | [(set_attr "length" "2,6") | |
582 | (set_attr "timings" "11,12")] | |
583 | ) | |
584 | ||
585 | (define_insn "zero_extend<small_int_modes:mode>si2" | |
586 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
587 | (zero_extend:SI (match_operand:small_int_modes | |
588 | 1 "nonimmediate_operand" "r,m")))] | |
589 | "" | |
590 | { return rx_gen_move_template (operands, true); } | |
591 | [(set_attr "length" "2,4") | |
592 | (set_attr "timings" "11,12")] | |
593 | ) | |
594 | ||
595 | (define_insn "stack_push" | |
265c835f RH |
596 | [(set (reg:SI SP_REG) |
597 | (minus:SI (reg:SI SP_REG) | |
598 | (const_int 4))) | |
599 | (set (mem:SI (reg:SI SP_REG)) | |
600 | (match_operand:SI 0 "register_operand" "r"))] | |
65a324b4 NC |
601 | "" |
602 | "push.l\t%0" | |
603 | [(set_attr "length" "2")] | |
604 | ) | |
605 | ||
606 | (define_insn "stack_pushm" | |
aea8fc97 | 607 | [(match_parallel 1 "rx_store_multiple_vector" |
265c835f RH |
608 | [(set (reg:SI SP_REG) |
609 | (minus:SI (reg:SI SP_REG) | |
610 | (match_operand:SI 0 "const_int_operand" "n")))])] | |
65a324b4 NC |
611 | "reload_completed" |
612 | { | |
613 | rx_emit_stack_pushm (operands); | |
614 | return ""; | |
615 | } | |
616 | [(set_attr "length" "2") | |
617 | (set_attr "timings" "44")] ;; The timing is a guesstimate average timing. | |
618 | ) | |
619 | ||
620 | (define_insn "stack_pop" | |
265c835f RH |
621 | [(set (match_operand:SI 0 "register_operand" "=r") |
622 | (mem:SI (reg:SI SP_REG))) | |
623 | (set (reg:SI SP_REG) | |
624 | (plus:SI (reg:SI SP_REG) | |
625 | (const_int 4)))] | |
65a324b4 NC |
626 | "" |
627 | "pop\t%0" | |
628 | [(set_attr "length" "2") | |
629 | (set_attr "timings" "12")] | |
630 | ) | |
631 | ||
632 | (define_insn "stack_popm" | |
aea8fc97 | 633 | [(match_parallel 1 "rx_load_multiple_vector" |
265c835f RH |
634 | [(set (reg:SI SP_REG) |
635 | (plus:SI (reg:SI SP_REG) | |
636 | (match_operand:SI 0 "const_int_operand" "n")))])] | |
65a324b4 NC |
637 | "reload_completed" |
638 | { | |
639 | rx_emit_stack_popm (operands, true); | |
640 | return ""; | |
641 | } | |
642 | [(set_attr "length" "2") | |
643 | (set_attr "timings" "45")] ;; The timing is a guesstimate average timing. | |
644 | ) | |
645 | ||
6f7310f2 RH |
646 | (define_insn_and_split "cstoresi4" |
647 | [(set (match_operand:SI 0 "register_operand" "=r") | |
aea8fc97 | 648 | (match_operator:SI 1 "comparison_operator" |
6f7310f2 RH |
649 | [(match_operand:SI 2 "register_operand" "r") |
650 | (match_operand:SI 3 "rx_source_operand" "riQ")])) | |
651 | (clobber (reg:CC CC_REG))] | |
65a324b4 | 652 | "" |
6f7310f2 RH |
653 | "#" |
654 | "reload_completed" | |
655 | [(const_int 0)] | |
656 | { | |
657 | rtx flags, x; | |
658 | ||
659 | flags = gen_rtx_REG (CCmode, CC_REG); | |
660 | x = gen_rtx_COMPARE (CCmode, operands[2], operands[3]); | |
661 | x = gen_rtx_SET (VOIDmode, flags, x); | |
662 | emit_insn (x); | |
663 | ||
664 | x = gen_rtx_fmt_ee (GET_CODE (operands[1]), SImode, flags, const0_rtx); | |
665 | x = gen_rtx_SET (VOIDmode, operands[0], x); | |
666 | emit_insn (x); | |
667 | DONE; | |
668 | }) | |
669 | ||
670 | (define_insn "*sccc" | |
671 | [(set (match_operand:SI 0 "register_operand" "=r") | |
672 | (match_operator:SI 1 "comparison_operator" | |
673 | [(reg CC_REG) (const_int 0)]))] | |
674 | "reload_completed" | |
675 | "sc%B1.L\t%0" | |
676 | [(set_attr "length" "3")] | |
65a324b4 NC |
677 | ) |
678 | ||
440eb8de | 679 | (define_insn_and_split "cstoresf4" |
d0acb939 | 680 | [(set (match_operand:SI 0 "register_operand" "=r") |
440eb8de | 681 | (match_operator:SI 1 "rx_fp_comparison_operator" |
d0acb939 | 682 | [(match_operand:SF 2 "register_operand" "r") |
440eb8de | 683 | (match_operand:SF 3 "rx_source_operand" "rFQ")]))] |
d0acb939 RH |
684 | "ALLOW_RX_FPU_INSNS" |
685 | "#" | |
686 | "reload_completed" | |
687 | [(const_int 0)] | |
688 | { | |
d0acb939 | 689 | rtx flags, x; |
d0acb939 RH |
690 | |
691 | flags = gen_rtx_REG (CC_Fmode, CC_REG); | |
692 | x = gen_rtx_COMPARE (CC_Fmode, operands[2], operands[3]); | |
693 | x = gen_rtx_SET (VOIDmode, flags, x); | |
694 | emit_insn (x); | |
695 | ||
440eb8de | 696 | x = gen_rtx_fmt_ee (GET_CODE (operands[1]), SImode, flags, const0_rtx); |
d0acb939 RH |
697 | x = gen_rtx_SET (VOIDmode, operands[0], x); |
698 | emit_insn (x); | |
d0acb939 RH |
699 | DONE; |
700 | }) | |
701 | ||
65a324b4 | 702 | (define_expand "movsicc" |
aea8fc97 NC |
703 | [(parallel |
704 | [(set (match_operand:SI 0 "register_operand") | |
705 | (if_then_else:SI (match_operand:SI 1 "comparison_operator") | |
706 | (match_operand:SI 2 "nonmemory_operand") | |
2882702b RH |
707 | (match_operand:SI 3 "nonmemory_operand"))) |
708 | (clobber (reg:CC CC_REG))])] | |
65a324b4 | 709 | "" |
2882702b RH |
710 | { |
711 | /* ??? Support other conditions via cstore into a temporary? */ | |
712 | if (GET_CODE (operands[1]) != EQ && GET_CODE (operands[1]) != NE) | |
713 | FAIL; | |
714 | /* One operand must be a constant. */ | |
715 | if (!CONSTANT_P (operands[2]) && !CONSTANT_P (operands[3])) | |
716 | FAIL; | |
717 | }) | |
65a324b4 | 718 | |
2882702b RH |
719 | (define_insn_and_split "*movsicc" |
720 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
721 | (if_then_else:SI | |
722 | (match_operator 5 "rx_z_comparison_operator" | |
723 | [(match_operand:SI 3 "register_operand" "r,r") | |
724 | (match_operand:SI 4 "rx_source_operand" "riQ,riQ")]) | |
725 | (match_operand:SI 1 "nonmemory_operand" "i,ri") | |
726 | (match_operand:SI 2 "nonmemory_operand" "ri,i"))) | |
727 | (clobber (reg:CC CC_REG))] | |
728 | "CONSTANT_P (operands[1]) || CONSTANT_P (operands[2])" | |
729 | "#" | |
730 | "&& reload_completed" | |
731 | [(const_int 0)] | |
732 | { | |
733 | rtx x, flags, op0, op1, op2; | |
734 | enum rtx_code cmp_code; | |
65a324b4 | 735 | |
2882702b RH |
736 | flags = gen_rtx_REG (CCmode, CC_REG); |
737 | x = gen_rtx_COMPARE (CCmode, operands[3], operands[4]); | |
738 | emit_insn (gen_rtx_SET (VOIDmode, flags, x)); | |
739 | ||
740 | cmp_code = GET_CODE (operands[5]); | |
741 | op0 = operands[0]; | |
742 | op1 = operands[1]; | |
743 | op2 = operands[2]; | |
744 | ||
745 | /* If OP2 is the constant, reverse the sense of the move. */ | |
746 | if (!CONSTANT_P (operands[1])) | |
747 | { | |
748 | x = op1, op1 = op2, op2 = x; | |
749 | cmp_code = reverse_condition (cmp_code); | |
750 | } | |
751 | ||
752 | /* If OP2 does not match the output, copy it into place. We have allowed | |
753 | these alternatives so that the destination can legitimately be one of | |
754 | the comparison operands without increasing register pressure. */ | |
755 | if (!rtx_equal_p (op0, op2)) | |
756 | emit_move_insn (op0, op2); | |
757 | ||
758 | x = gen_rtx_fmt_ee (cmp_code, VOIDmode, flags, const0_rtx); | |
759 | x = gen_rtx_IF_THEN_ELSE (SImode, x, op1, op0); | |
760 | emit_insn (gen_rtx_SET (VOIDmode, op0, x)); | |
761 | DONE; | |
762 | }) | |
763 | ||
764 | (define_insn "*stcc" | |
765 | [(set (match_operand:SI 0 "register_operand" "+r,r,r,r") | |
766 | (if_then_else:SI | |
767 | (match_operator 2 "rx_z_comparison_operator" | |
768 | [(reg CC_REG) (const_int 0)]) | |
769 | (match_operand:SI 1 "immediate_operand" "Sint08,Sint16,Sint24,i") | |
770 | (match_dup 0)))] | |
771 | "reload_completed" | |
772 | { | |
773 | if (GET_CODE (operands[2]) == EQ) | |
774 | return "stz\t%1, %0"; | |
775 | else | |
776 | return "stnz\t%1, %0"; | |
777 | } | |
778 | [(set_attr "length" "4,5,6,7")] | |
65a324b4 NC |
779 | ) |
780 | ||
781 | ;; Arithmetic Instructions | |
782 | ||
783 | (define_insn "abssi2" | |
784 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
aea8fc97 | 785 | (abs:SI (match_operand:SI 1 "register_operand" "0,r"))) |
b4d83be3 | 786 | (clobber (reg:CC CC_REG))] |
65a324b4 NC |
787 | "" |
788 | "@ | |
789 | abs\t%0 | |
790 | abs\t%1, %0" | |
aea8fc97 | 791 | [(set_attr "length" "2,3")] |
65a324b4 NC |
792 | ) |
793 | ||
b4d83be3 RH |
794 | (define_insn "*abssi2_flags" |
795 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
796 | (abs:SI (match_operand:SI 1 "register_operand" "0,r"))) | |
797 | (set (reg CC_REG) | |
798 | (compare (abs:SI (match_dup 1)) | |
799 | (const_int 0)))] | |
6479ed4b NC |
800 | ;; Note - although the ABS instruction does set the O bit in the processor |
801 | ;; status word, it does not do so in a way that is comparable with the CMP | |
802 | ;; instruction. Hence we use CC_ZSmode rather than CC_ZSOmode. | |
803 | "reload_completed && rx_match_ccmode (insn, CC_ZSmode)" | |
b4d83be3 RH |
804 | "@ |
805 | abs\t%0 | |
806 | abs\t%1, %0" | |
807 | [(set_attr "length" "2,3")] | |
808 | ) | |
809 | ||
65a324b4 | 810 | (define_insn "addsi3" |
aea8fc97 NC |
811 | [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r,r,r,r,r,r") |
812 | (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,0,r,r,r,r,r,r,0") | |
813 | (match_operand:SI 2 "rx_source_operand" "r,Uint04,NEGint4,Sint08,Sint16,Sint24,i,0,r,Sint08,Sint16,Sint24,i,Q"))) | |
b4d83be3 | 814 | (clobber (reg:CC CC_REG))] |
65a324b4 NC |
815 | "" |
816 | "@ | |
817 | add\t%2, %0 | |
818 | add\t%2, %0 | |
c249a7bc | 819 | sub\t%N2, %0 |
65a324b4 NC |
820 | add\t%2, %0 |
821 | add\t%2, %0 | |
822 | add\t%2, %0 | |
823 | add\t%2, %0 | |
aea8fc97 | 824 | add\t%1, %0 |
65a324b4 NC |
825 | add\t%2, %1, %0 |
826 | add\t%2, %1, %0 | |
827 | add\t%2, %1, %0 | |
828 | add\t%2, %1, %0 | |
829 | add\t%2, %1, %0 | |
830 | add\t%Q2, %0" | |
aea8fc97 NC |
831 | [(set_attr "timings" "11,11,11,11,11,11,11,11,11,11,11,11,11,33") |
832 | (set_attr "length" "2,2,2,3,4,5,6,2,3,3,4,5,6,5")] | |
65a324b4 NC |
833 | ) |
834 | ||
b4d83be3 RH |
835 | (define_insn "*addsi3_flags" |
836 | [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r,r,r,r,r,r") | |
837 | (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,0,r,r,r,r,r,r,0") | |
838 | (match_operand:SI 2 "rx_source_operand" "r,Uint04,NEGint4,Sint08,Sint16,Sint24,i,0,r,Sint08,Sint16,Sint24,i,Q"))) | |
839 | (set (reg CC_REG) | |
840 | (compare (plus:SI (match_dup 1) (match_dup 2)) | |
841 | (const_int 0)))] | |
842 | "reload_completed && rx_match_ccmode (insn, CC_ZSCmode)" | |
843 | "@ | |
844 | add\t%2, %0 | |
845 | add\t%2, %0 | |
846 | sub\t%N2, %0 | |
847 | add\t%2, %0 | |
848 | add\t%2, %0 | |
849 | add\t%2, %0 | |
850 | add\t%2, %0 | |
851 | add\t%1, %0 | |
852 | add\t%2, %1, %0 | |
853 | add\t%2, %1, %0 | |
854 | add\t%2, %1, %0 | |
855 | add\t%2, %1, %0 | |
856 | add\t%2, %1, %0 | |
857 | add\t%Q2, %0" | |
858 | [(set_attr "timings" "11,11,11,11,11,11,11,11,11,11,11,11,11,33") | |
859 | (set_attr "length" "2,2,2,3,4,5,6,2,3,3,4,5,6,5")] | |
860 | ) | |
861 | ||
8a5b5449 RH |
862 | ;; A helper to expand the above with the CC_MODE filled in. |
863 | (define_expand "addsi3_flags" | |
864 | [(parallel [(set (match_operand:SI 0 "register_operand") | |
865 | (plus:SI (match_operand:SI 1 "register_operand") | |
866 | (match_operand:SI 2 "rx_source_operand"))) | |
867 | (set (reg:CC_ZSC CC_REG) | |
868 | (compare:CC_ZSC (plus:SI (match_dup 1) (match_dup 2)) | |
869 | (const_int 0)))])] | |
870 | ) | |
871 | ||
872 | (define_insn "adc_internal" | |
873 | [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") | |
874 | (plus:SI | |
875 | (plus:SI | |
876 | (ltu:SI (reg:CC CC_REG) (const_int 0)) | |
877 | (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0")) | |
878 | (match_operand:SI 2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q"))) | |
879 | (clobber (reg:CC CC_REG))] | |
880 | "reload_completed" | |
881 | "adc %2,%0" | |
882 | [(set_attr "timings" "11,11,11,11,11,33") | |
883 | (set_attr "length" "3,4,5,6,7,6")] | |
884 | ) | |
885 | ||
886 | (define_insn "*adc_flags" | |
887 | [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") | |
888 | (plus:SI | |
889 | (plus:SI | |
890 | (ltu:SI (reg:CC CC_REG) (const_int 0)) | |
891 | (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0")) | |
892 | (match_operand:SI 2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q"))) | |
893 | (set (reg CC_REG) | |
894 | (compare | |
895 | (plus:SI | |
896 | (plus:SI | |
897 | (ltu:SI (reg:CC CC_REG) (const_int 0)) | |
898 | (match_dup 1)) | |
899 | (match_dup 2)) | |
900 | (const_int 0)))] | |
901 | "reload_completed && rx_match_ccmode (insn, CC_ZSCmode)" | |
902 | "adc %2,%0" | |
903 | [(set_attr "timings" "11,11,11,11,11,33") | |
904 | (set_attr "length" "3,4,5,6,7,6")] | |
905 | ) | |
906 | ||
907 | (define_expand "adddi3" | |
bcddd3b9 NC |
908 | [(set (match_operand:DI 0 "register_operand") |
909 | (plus:DI (match_operand:DI 1 "register_operand") | |
910 | (match_operand:DI 2 "rx_source_operand")))] | |
8a5b5449 RH |
911 | "" |
912 | { | |
913 | rtx op0l, op0h, op1l, op1h, op2l, op2h; | |
914 | ||
915 | op0l = gen_lowpart (SImode, operands[0]); | |
916 | op1l = gen_lowpart (SImode, operands[1]); | |
917 | op2l = gen_lowpart (SImode, operands[2]); | |
918 | op0h = gen_highpart (SImode, operands[0]); | |
919 | op1h = gen_highpart (SImode, operands[1]); | |
920 | op2h = gen_highpart_mode (SImode, DImode, operands[2]); | |
921 | ||
922 | emit_insn (gen_adddi3_internal (op0l, op0h, op1l, op2l, op1h, op2h)); | |
923 | DONE; | |
924 | }) | |
925 | ||
926 | (define_insn_and_split "adddi3_internal" | |
927 | [(set (match_operand:SI 0 "register_operand" "=r") | |
928 | (plus:SI (match_operand:SI 2 "register_operand" "r") | |
929 | (match_operand:SI 3 "rx_source_operand" "riQ"))) | |
930 | (set (match_operand:SI 1 "register_operand" "=r") | |
931 | (plus:SI | |
932 | (plus:SI | |
933 | (ltu:SI (plus:SI (match_dup 2) (match_dup 3)) (match_dup 2)) | |
934 | (match_operand:SI 4 "register_operand" "%1")) | |
935 | (match_operand:SI 5 "rx_source_operand" "riQ"))) | |
936 | (clobber (match_scratch:SI 6 "=&r")) | |
b4d83be3 | 937 | (clobber (reg:CC CC_REG))] |
65a324b4 | 938 | "" |
8a5b5449 RH |
939 | "#" |
940 | "reload_completed" | |
941 | [(const_int 0)] | |
942 | { | |
943 | rtx op0l = operands[0]; | |
944 | rtx op0h = operands[1]; | |
945 | rtx op1l = operands[2]; | |
946 | rtx op2l = operands[3]; | |
947 | rtx op1h = operands[4]; | |
948 | rtx op2h = operands[5]; | |
949 | rtx scratch = operands[6]; | |
950 | rtx x; | |
951 | ||
952 | if (reg_overlap_mentioned_p (op0l, op1h)) | |
953 | { | |
954 | emit_move_insn (scratch, op0l); | |
955 | op1h = scratch; | |
956 | if (reg_overlap_mentioned_p (op0l, op2h)) | |
957 | op2h = scratch; | |
958 | } | |
959 | else if (reg_overlap_mentioned_p (op0l, op2h)) | |
960 | { | |
961 | emit_move_insn (scratch, op0l); | |
962 | op2h = scratch; | |
963 | } | |
964 | ||
965 | if (rtx_equal_p (op0l, op1l)) | |
966 | ; | |
bcddd3b9 | 967 | /* It is preferable that op0l == op1l... */ |
8a5b5449 RH |
968 | else if (rtx_equal_p (op0l, op2l)) |
969 | x = op1l, op1l = op2l, op2l = x; | |
bcddd3b9 NC |
970 | /* ... but it is only a requirement if op2l == MEM. */ |
971 | else if (MEM_P (op2l)) | |
972 | { | |
973 | /* Let's hope that we still have a scratch register free. */ | |
974 | gcc_assert (op1h != scratch); | |
975 | emit_move_insn (scratch, op2l); | |
976 | op2l = scratch; | |
977 | } | |
978 | ||
8a5b5449 RH |
979 | emit_insn (gen_addsi3_flags (op0l, op1l, op2l)); |
980 | ||
981 | if (rtx_equal_p (op0h, op1h)) | |
982 | ; | |
983 | else if (rtx_equal_p (op0h, op2h)) | |
984 | x = op1h, op1h = op2h, op2h = x; | |
985 | else | |
986 | { | |
987 | emit_move_insn (op0h, op1h); | |
988 | op1h = op0h; | |
989 | } | |
990 | emit_insn (gen_adc_internal (op0h, op1h, op2h)); | |
991 | DONE; | |
992 | }) | |
65a324b4 NC |
993 | |
994 | (define_insn "andsi3" | |
995 | [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r") | |
c249a7bc | 996 | (and:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,r,0") |
aea8fc97 | 997 | (match_operand:SI 2 "rx_source_operand" "r,Uint04,Sint08,Sint16,Sint24,i,0,r,Q"))) |
b4d83be3 | 998 | (clobber (reg:CC CC_REG))] |
65a324b4 NC |
999 | "" |
1000 | "@ | |
1001 | and\t%2, %0 | |
1002 | and\t%2, %0 | |
1003 | and\t%2, %0 | |
1004 | and\t%2, %0 | |
1005 | and\t%2, %0 | |
1006 | and\t%2, %0 | |
c249a7bc | 1007 | and\t%1, %0 |
65a324b4 | 1008 | and\t%2, %1, %0 |
c249a7bc | 1009 | and\t%Q2, %0" |
39242686 | 1010 | [(set_attr "timings" "11,11,11,11,11,11,11,11,33") |
c249a7bc | 1011 | (set_attr "length" "2,2,3,4,5,6,2,5,5")] |
65a324b4 NC |
1012 | ) |
1013 | ||
b4d83be3 RH |
1014 | (define_insn "*andsi3_flags" |
1015 | [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r") | |
1016 | (and:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,r,0") | |
1017 | (match_operand:SI 2 "rx_source_operand" "r,Uint04,Sint08,Sint16,Sint24,i,0,r,Q"))) | |
1018 | (set (reg CC_REG) | |
1019 | (compare (and:SI (match_dup 1) (match_dup 2)) | |
1020 | (const_int 0)))] | |
1021 | "reload_completed && rx_match_ccmode (insn, CC_ZSmode)" | |
1022 | "@ | |
1023 | and\t%2, %0 | |
1024 | and\t%2, %0 | |
1025 | and\t%2, %0 | |
1026 | and\t%2, %0 | |
1027 | and\t%2, %0 | |
1028 | and\t%2, %0 | |
1029 | and\t%1, %0 | |
1030 | and\t%2, %1, %0 | |
1031 | and\t%Q2, %0" | |
39242686 | 1032 | [(set_attr "timings" "11,11,11,11,11,11,11,11,33") |
b4d83be3 RH |
1033 | (set_attr "length" "2,2,3,4,5,6,2,5,5")] |
1034 | ) | |
1035 | ||
65a324b4 NC |
1036 | ;; Byte swap (single 32-bit value). |
1037 | (define_insn "bswapsi2" | |
34fee389 | 1038 | [(set (match_operand:SI 0 "register_operand" "=r") |
65a324b4 NC |
1039 | (bswap:SI (match_operand:SI 1 "register_operand" "r")))] |
1040 | "" | |
1041 | "revl\t%1, %0" | |
1042 | [(set_attr "length" "3")] | |
1043 | ) | |
1044 | ||
1045 | ;; Byte swap (single 16-bit value). Note - we ignore the swapping of the high 16-bits. | |
1046 | (define_insn "bswaphi2" | |
34fee389 | 1047 | [(set (match_operand:HI 0 "register_operand" "=r") |
65a324b4 NC |
1048 | (bswap:HI (match_operand:HI 1 "register_operand" "r")))] |
1049 | "" | |
1050 | "revw\t%1, %0" | |
1051 | [(set_attr "length" "3")] | |
1052 | ) | |
1053 | ||
1054 | (define_insn "divsi3" | |
1055 | [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") | |
1056 | (div:SI (match_operand:SI 1 "register_operand" "0,0,0,0,0,0") | |
aea8fc97 NC |
1057 | (match_operand:SI 2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q"))) |
1058 | (clobber (reg:CC CC_REG))] | |
65a324b4 NC |
1059 | "" |
1060 | "div\t%Q2, %0" | |
aea8fc97 | 1061 | [(set_attr "timings" "1111") ;; Strictly speaking the timing should be |
65a324b4 NC |
1062 | ;; 2222, but that is a worst case sceanario. |
1063 | (set_attr "length" "3,4,5,6,7,6")] | |
1064 | ) | |
1065 | ||
1066 | (define_insn "udivsi3" | |
1067 | [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") | |
1068 | (udiv:SI (match_operand:SI 1 "register_operand" "0,0,0,0,0,0") | |
aea8fc97 NC |
1069 | (match_operand:SI 2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q"))) |
1070 | (clobber (reg:CC CC_REG))] | |
65a324b4 NC |
1071 | "" |
1072 | "divu\t%Q2, %0" | |
aea8fc97 | 1073 | [(set_attr "timings" "1010") ;; Strictly speaking the timing should be |
65a324b4 NC |
1074 | ;; 2020, but that is a worst case sceanario. |
1075 | (set_attr "length" "3,4,5,6,7,6")] | |
1076 | ) | |
1077 | ||
1078 | ;; Note - these patterns are suppressed in big-endian mode because they | |
1079 | ;; generate a little endian result. ie the most significant word of the | |
1080 | ;; result is placed in the higher numbered register of the destination | |
1081 | ;; register pair. | |
1082 | ||
1083 | (define_insn "mulsidi3" | |
1084 | [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r,r") | |
1085 | (mult:DI (sign_extend:DI (match_operand:SI | |
1086 | 1 "register_operand" "%0,0,0,0,0,0")) | |
1087 | (sign_extend:DI (match_operand:SI | |
1088 | 2 "rx_source_operand" | |
1089 | "r,Sint08,Sint16,Sint24,i,Q"))))] | |
1090 | "! TARGET_BIG_ENDIAN_DATA" | |
c249a7bc | 1091 | "emul\t%Q2, %0" |
65a324b4 NC |
1092 | [(set_attr "length" "3,4,5,6,7,6") |
1093 | (set_attr "timings" "22,22,22,22,22,44")] | |
1094 | ) | |
1095 | ||
1096 | ;; See comment for mulsidi3. | |
1097 | ;; Note - the zero_extends are to distinguish this pattern from the | |
1098 | ;; mulsidi3 pattern. Immediate mode addressing is not supported | |
1099 | ;; because gcc cannot handle the expression: (zero_extend (const_int)). | |
1100 | (define_insn "umulsidi3" | |
aea8fc97 NC |
1101 | [(set (match_operand:DI 0 "register_operand" "=r,r") |
1102 | (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0,0")) | |
1103 | (zero_extend:DI (match_operand:SI 2 "rx_compare_operand" "r,Q"))))] | |
65a324b4 | 1104 | "! TARGET_BIG_ENDIAN_DATA" |
c249a7bc | 1105 | "emulu\t%Q2, %0" |
65a324b4 NC |
1106 | [(set_attr "length" "3,6") |
1107 | (set_attr "timings" "22,44")] | |
1108 | ) | |
1109 | ||
1110 | (define_insn "smaxsi3" | |
1111 | [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") | |
1112 | (smax:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0") | |
1113 | (match_operand:SI 2 "rx_source_operand" | |
1114 | "r,Sint08,Sint16,Sint24,i,Q")))] | |
1115 | "" | |
1116 | "max\t%Q2, %0" | |
1117 | [(set_attr "length" "3,4,5,6,7,6") | |
1118 | (set_attr "timings" "11,11,11,11,11,33")] | |
1119 | ) | |
1120 | ||
1121 | (define_insn "sminsi3" | |
a1e205cf NC |
1122 | [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") |
1123 | (smin:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0") | |
65a324b4 | 1124 | (match_operand:SI 2 "rx_source_operand" |
a1e205cf | 1125 | "r,Sint08,Sint16,Sint24,i,Q")))] |
65a324b4 | 1126 | "" |
c249a7bc | 1127 | "min\t%Q2, %0" |
a1e205cf NC |
1128 | [(set_attr "length" "3,4,5,6,7,6") |
1129 | (set_attr "timings" "11,11,11,11,11,33")] | |
65a324b4 NC |
1130 | ) |
1131 | ||
1132 | (define_insn "mulsi3" | |
1133 | [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r") | |
c249a7bc | 1134 | (mult:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,0,r,r") |
65a324b4 NC |
1135 | (match_operand:SI 2 "rx_source_operand" |
1136 | "r,Uint04,Sint08,Sint16,Sint24,i,Q,0,r")))] | |
1137 | "" | |
1138 | "@ | |
c249a7bc NC |
1139 | mul\t%2, %0 |
1140 | mul\t%2, %0 | |
1141 | mul\t%2, %0 | |
1142 | mul\t%2, %0 | |
1143 | mul\t%2, %0 | |
65a324b4 NC |
1144 | mul\t%Q2, %0 |
1145 | mul\t%Q2, %0 | |
c249a7bc NC |
1146 | mul\t%1, %0 |
1147 | mul\t%2, %1, %0" | |
1148 | [(set_attr "length" "2,2,3,4,5,6,5,2,3") | |
1149 | (set_attr "timings" "11,11,11,11,11,11,33,11,11")] | |
65a324b4 NC |
1150 | ) |
1151 | ||
1152 | (define_insn "negsi2" | |
1153 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
aea8fc97 | 1154 | (neg:SI (match_operand:SI 1 "register_operand" "0,r"))) |
b4d83be3 RH |
1155 | (clobber (reg:CC CC_REG))] |
1156 | "" | |
1157 | "@ | |
1158 | neg\t%0 | |
1159 | neg\t%1, %0" | |
1160 | [(set_attr "length" "2,3")] | |
1161 | ) | |
1162 | ||
1163 | ;; Note that the O and C flags are not set as per a normal compare, | |
1164 | ;; and thus are unusable in that context. | |
1165 | (define_insn "*negsi2_flags" | |
1166 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
1167 | (neg:SI (match_operand:SI 1 "register_operand" "0,r"))) | |
1168 | (set (reg CC_REG) | |
1169 | (compare (neg:SI (match_dup 1)) | |
1170 | (const_int 0)))] | |
1171 | "reload_completed && rx_match_ccmode (insn, CC_ZSmode)" | |
65a324b4 NC |
1172 | "@ |
1173 | neg\t%0 | |
1174 | neg\t%1, %0" | |
aea8fc97 | 1175 | [(set_attr "length" "2,3")] |
65a324b4 NC |
1176 | ) |
1177 | ||
1178 | (define_insn "one_cmplsi2" | |
1179 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
aea8fc97 | 1180 | (not:SI (match_operand:SI 1 "register_operand" "0,r"))) |
b4d83be3 | 1181 | (clobber (reg:CC CC_REG))] |
65a324b4 NC |
1182 | "" |
1183 | "@ | |
1184 | not\t%0 | |
1185 | not\t%1, %0" | |
aea8fc97 | 1186 | [(set_attr "length" "2,3")] |
65a324b4 NC |
1187 | ) |
1188 | ||
b4d83be3 RH |
1189 | (define_insn "*one_cmplsi2_flags" |
1190 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
1191 | (not:SI (match_operand:SI 1 "register_operand" "0,r"))) | |
1192 | (set (reg CC_REG) | |
1193 | (compare (not:SI (match_dup 1)) | |
1194 | (const_int 0)))] | |
1195 | "reload_completed && rx_match_ccmode (insn, CC_ZSmode)" | |
1196 | "@ | |
1197 | not\t%0 | |
1198 | not\t%1, %0" | |
1199 | [(set_attr "length" "2,3")] | |
1200 | ) | |
1201 | ||
65a324b4 NC |
1202 | (define_insn "iorsi3" |
1203 | [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r") | |
c249a7bc | 1204 | (ior:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,r,0") |
aea8fc97 | 1205 | (match_operand:SI 2 "rx_source_operand" "r,Uint04,Sint08,Sint16,Sint24,i,0,r,Q"))) |
b4d83be3 | 1206 | (clobber (reg:CC CC_REG))] |
65a324b4 NC |
1207 | "" |
1208 | "@ | |
1209 | or\t%2, %0 | |
1210 | or\t%2, %0 | |
1211 | or\t%2, %0 | |
1212 | or\t%2, %0 | |
1213 | or\t%2, %0 | |
65a324b4 | 1214 | or\t%Q2, %0 |
c249a7bc NC |
1215 | or\t%1, %0 |
1216 | or\t%2, %1, %0 | |
1217 | or\t%Q2, %0" | |
aea8fc97 | 1218 | [(set_attr "timings" "11,11,11,11,11,11,11,11,33") |
c249a7bc | 1219 | (set_attr "length" "2,2,3,4,5,6,2,3,5")] |
65a324b4 NC |
1220 | ) |
1221 | ||
b4d83be3 RH |
1222 | (define_insn "*iorsi3_flags" |
1223 | [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r") | |
1224 | (ior:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,r,0") | |
1225 | (match_operand:SI 2 "rx_source_operand" "r,Uint04,Sint08,Sint16,Sint24,i,0,r,Q"))) | |
1226 | (set (reg CC_REG) | |
1227 | (compare (ior:SI (match_dup 1) (match_dup 2)) | |
1228 | (const_int 0)))] | |
1229 | "reload_completed && rx_match_ccmode (insn, CC_ZSmode)" | |
1230 | "@ | |
1231 | or\t%2, %0 | |
1232 | or\t%2, %0 | |
1233 | or\t%2, %0 | |
1234 | or\t%2, %0 | |
1235 | or\t%2, %0 | |
1236 | or\t%Q2, %0 | |
1237 | or\t%1, %0 | |
1238 | or\t%2, %1, %0 | |
1239 | or\t%Q2, %0" | |
1240 | [(set_attr "timings" "11,11,11,11,11,11,11,11,33") | |
1241 | (set_attr "length" "2,2,3,4,5,6,2,3,5")] | |
1242 | ) | |
1243 | ||
65a324b4 NC |
1244 | (define_insn "rotlsi3" |
1245 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1246 | (rotate:SI (match_operand:SI 1 "register_operand" "0") | |
aea8fc97 | 1247 | (match_operand:SI 2 "rx_shift_operand" "rn"))) |
b4d83be3 | 1248 | (clobber (reg:CC CC_REG))] |
65a324b4 NC |
1249 | "" |
1250 | "rotl\t%2, %0" | |
aea8fc97 | 1251 | [(set_attr "length" "3")] |
65a324b4 NC |
1252 | ) |
1253 | ||
b4d83be3 RH |
1254 | (define_insn "*rotlsi3_flags" |
1255 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1256 | (rotate:SI (match_operand:SI 1 "register_operand" "0") | |
1257 | (match_operand:SI 2 "rx_shift_operand" "rn"))) | |
1258 | (set (reg CC_REG) | |
1259 | (compare (rotate:SI (match_dup 1) (match_dup 2)) | |
1260 | (const_int 0)))] | |
1261 | "reload_completed && rx_match_ccmode (insn, CC_ZSmode)" | |
1262 | "rotl\t%2, %0" | |
1263 | [(set_attr "length" "3")] | |
1264 | ) | |
1265 | ||
65a324b4 NC |
1266 | (define_insn "rotrsi3" |
1267 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1268 | (rotatert:SI (match_operand:SI 1 "register_operand" "0") | |
aea8fc97 | 1269 | (match_operand:SI 2 "rx_shift_operand" "rn"))) |
b4d83be3 | 1270 | (clobber (reg:CC CC_REG))] |
65a324b4 NC |
1271 | "" |
1272 | "rotr\t%2, %0" | |
aea8fc97 | 1273 | [(set_attr "length" "3")] |
65a324b4 NC |
1274 | ) |
1275 | ||
b4d83be3 RH |
1276 | (define_insn "*rotrsi3_flags" |
1277 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1278 | (rotatert:SI (match_operand:SI 1 "register_operand" "0") | |
1279 | (match_operand:SI 2 "rx_shift_operand" "rn"))) | |
1280 | (set (reg CC_REG) | |
1281 | (compare (rotatert:SI (match_dup 1) (match_dup 2)) | |
1282 | (const_int 0)))] | |
1283 | "reload_completed && rx_match_ccmode (insn, CC_ZSmode)" | |
1284 | "rotr\t%2, %0" | |
1285 | [(set_attr "length" "3")] | |
1286 | ) | |
1287 | ||
65a324b4 NC |
1288 | (define_insn "ashrsi3" |
1289 | [(set (match_operand:SI 0 "register_operand" "=r,r,r") | |
1290 | (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r") | |
aea8fc97 | 1291 | (match_operand:SI 2 "rx_shift_operand" "r,n,n"))) |
b4d83be3 | 1292 | (clobber (reg:CC CC_REG))] |
65a324b4 NC |
1293 | "" |
1294 | "@ | |
1295 | shar\t%2, %0 | |
1296 | shar\t%2, %0 | |
1297 | shar\t%2, %1, %0" | |
aea8fc97 | 1298 | [(set_attr "length" "3,2,3")] |
65a324b4 NC |
1299 | ) |
1300 | ||
b4d83be3 RH |
1301 | (define_insn "*ashrsi3_flags" |
1302 | [(set (match_operand:SI 0 "register_operand" "=r,r,r") | |
1303 | (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r") | |
1304 | (match_operand:SI 2 "rx_shift_operand" "r,n,n"))) | |
1305 | (set (reg CC_REG) | |
1306 | (compare (ashiftrt:SI (match_dup 1) (match_dup 2)) | |
1307 | (const_int 0)))] | |
1308 | "reload_completed && rx_match_ccmode (insn, CC_ZSmode)" | |
1309 | "@ | |
1310 | shar\t%2, %0 | |
1311 | shar\t%2, %0 | |
1312 | shar\t%2, %1, %0" | |
1313 | [(set_attr "length" "3,2,3")] | |
1314 | ) | |
1315 | ||
65a324b4 NC |
1316 | (define_insn "lshrsi3" |
1317 | [(set (match_operand:SI 0 "register_operand" "=r,r,r") | |
1318 | (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r") | |
aea8fc97 | 1319 | (match_operand:SI 2 "rx_shift_operand" "r,n,n"))) |
b4d83be3 | 1320 | (clobber (reg:CC CC_REG))] |
65a324b4 NC |
1321 | "" |
1322 | "@ | |
1323 | shlr\t%2, %0 | |
1324 | shlr\t%2, %0 | |
1325 | shlr\t%2, %1, %0" | |
aea8fc97 | 1326 | [(set_attr "length" "3,2,3")] |
65a324b4 NC |
1327 | ) |
1328 | ||
b4d83be3 RH |
1329 | (define_insn "*lshrsi3_flags" |
1330 | [(set (match_operand:SI 0 "register_operand" "=r,r,r") | |
1331 | (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r") | |
1332 | (match_operand:SI 2 "rx_shift_operand" "r,n,n"))) | |
1333 | (set (reg CC_REG) | |
1334 | (compare (lshiftrt:SI (match_dup 1) (match_dup 2)) | |
1335 | (const_int 0)))] | |
1336 | "reload_completed && rx_match_ccmode (insn, CC_ZSmode)" | |
1337 | "@ | |
1338 | shlr\t%2, %0 | |
1339 | shlr\t%2, %0 | |
1340 | shlr\t%2, %1, %0" | |
1341 | [(set_attr "length" "3,2,3")] | |
1342 | ) | |
1343 | ||
65a324b4 NC |
1344 | (define_insn "ashlsi3" |
1345 | [(set (match_operand:SI 0 "register_operand" "=r,r,r") | |
1346 | (ashift:SI (match_operand:SI 1 "register_operand" "0,0,r") | |
aea8fc97 | 1347 | (match_operand:SI 2 "rx_shift_operand" "r,n,n"))) |
b4d83be3 | 1348 | (clobber (reg:CC CC_REG))] |
65a324b4 NC |
1349 | "" |
1350 | "@ | |
1351 | shll\t%2, %0 | |
1352 | shll\t%2, %0 | |
1353 | shll\t%2, %1, %0" | |
aea8fc97 | 1354 | [(set_attr "length" "3,2,3")] |
65a324b4 NC |
1355 | ) |
1356 | ||
b4d83be3 RH |
1357 | (define_insn "*ashlsi3_flags" |
1358 | [(set (match_operand:SI 0 "register_operand" "=r,r,r") | |
1359 | (ashift:SI (match_operand:SI 1 "register_operand" "0,0,r") | |
1360 | (match_operand:SI 2 "rx_shift_operand" "r,n,n"))) | |
1361 | (set (reg CC_REG) | |
1362 | (compare (ashift:SI (match_dup 1) (match_dup 2)) | |
1363 | (const_int 0)))] | |
1364 | "reload_completed && rx_match_ccmode (insn, CC_ZSmode)" | |
1365 | "@ | |
1366 | shll\t%2, %0 | |
1367 | shll\t%2, %0 | |
1368 | shll\t%2, %1, %0" | |
1369 | [(set_attr "length" "3,2,3")] | |
1370 | ) | |
1371 | ||
784f69be RH |
1372 | ;; Saturate to 32-bits |
1373 | (define_insn_and_split "ssaddsi3" | |
1374 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1375 | (ss_plus:SI (match_operand:SI 1 "register_operand" "r") | |
1376 | (match_operand:SI 2 "rx_source_operand" "riQ"))) | |
1377 | (clobber (reg:CC CC_REG))] | |
1378 | "" | |
1379 | "#" | |
1380 | "reload_completed" | |
1381 | [(parallel [(set (match_dup 0) | |
1382 | (plus:SI (match_dup 1) (match_dup 2))) | |
1383 | (set (reg:CC_ZSC CC_REG) | |
1384 | (compare:CC_ZSC | |
1385 | (plus:SI (match_dup 1) (match_dup 2)) | |
1386 | (const_int 0)))]) | |
1387 | (set (match_dup 0) | |
1388 | (unspec:SI [(match_dup 0) (reg:CC CC_REG)] | |
1389 | UNSPEC_BUILTIN_SAT))] | |
1390 | "" | |
1391 | ) | |
1392 | ||
1393 | (define_insn "*sat" | |
1394 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1395 | (unspec:SI [(match_operand:SI 1 "register_operand" "0") | |
1396 | (reg:CC CC_REG)] | |
1397 | UNSPEC_BUILTIN_SAT))] | |
1398 | "reload_completed" | |
1399 | "sat\t%0" | |
1400 | [(set_attr "length" "2")] | |
1401 | ) | |
1402 | ||
65a324b4 NC |
1403 | (define_insn "subsi3" |
1404 | [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r") | |
1405 | (minus:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0") | |
aea8fc97 | 1406 | (match_operand:SI 2 "rx_source_operand" "r,Uint04,n,r,Q"))) |
b4d83be3 | 1407 | (clobber (reg:CC CC_REG))] |
65a324b4 NC |
1408 | "" |
1409 | "@ | |
1410 | sub\t%2, %0 | |
1411 | sub\t%2, %0 | |
1412 | add\t%N2, %0 | |
1413 | sub\t%2, %1, %0 | |
1414 | sub\t%Q2, %0" | |
aea8fc97 | 1415 | [(set_attr "timings" "11,11,11,11,33") |
65a324b4 NC |
1416 | (set_attr "length" "2,2,6,3,5")] |
1417 | ) | |
1418 | ||
b4d83be3 RH |
1419 | ;; Note that the O flag is set as if (compare op1 op2) not for |
1420 | ;; what is described here, (compare op0 0). | |
1421 | (define_insn "*subsi3_flags" | |
1422 | [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r") | |
1423 | (minus:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0") | |
1424 | (match_operand:SI 2 "rx_source_operand" "r,Uint04,n,r,Q"))) | |
1425 | (set (reg CC_REG) | |
1426 | (compare (minus:SI (match_dup 1) (match_dup 2)) | |
1427 | (const_int 0)))] | |
1428 | "reload_completed && rx_match_ccmode (insn, CC_ZSCmode)" | |
1429 | "@ | |
1430 | sub\t%2, %0 | |
1431 | sub\t%2, %0 | |
1432 | add\t%N2, %0 | |
1433 | sub\t%2, %1, %0 | |
1434 | sub\t%Q2, %0" | |
1435 | [(set_attr "timings" "11,11,11,11,33") | |
1436 | (set_attr "length" "2,2,6,3,5")] | |
1437 | ) | |
1438 | ||
8a5b5449 RH |
1439 | ;; A helper to expand the above with the CC_MODE filled in. |
1440 | (define_expand "subsi3_flags" | |
1441 | [(parallel [(set (match_operand:SI 0 "register_operand") | |
1442 | (minus:SI (match_operand:SI 1 "register_operand") | |
1443 | (match_operand:SI 2 "rx_source_operand"))) | |
1444 | (set (reg:CC_ZSC CC_REG) | |
1445 | (compare:CC_ZSC (minus:SI (match_dup 1) (match_dup 2)) | |
1446 | (const_int 0)))])] | |
1447 | ) | |
1448 | ||
1449 | (define_insn "sbb_internal" | |
1450 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
1451 | (minus:SI | |
1452 | (minus:SI | |
1453 | (match_operand:SI 1 "register_operand" " 0,0") | |
1454 | (match_operand:SI 2 "rx_compare_operand" " r,Q")) | |
1455 | (geu:SI (reg:CC CC_REG) (const_int 0)))) | |
1456 | (clobber (reg:CC CC_REG))] | |
1457 | "reload_completed" | |
1458 | "sbb\t%2, %0" | |
1459 | [(set_attr "timings" "11,33") | |
1460 | (set_attr "length" "3,6")] | |
1461 | ) | |
1462 | ||
1463 | (define_insn "*sbb_flags" | |
1464 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
1465 | (minus:SI | |
1466 | (minus:SI | |
1467 | (match_operand:SI 1 "register_operand" " 0,0") | |
1468 | (match_operand:SI 2 "rx_compare_operand" " r,Q")) | |
1469 | (geu:SI (reg:CC CC_REG) (const_int 0)))) | |
1470 | (set (reg CC_REG) | |
1471 | (compare | |
1472 | (minus:SI | |
1473 | (minus:SI (match_dup 1) (match_dup 2)) | |
1474 | (geu:SI (reg:CC CC_REG) (const_int 0))) | |
1475 | (const_int 0)))] | |
1476 | "reload_completed" | |
1477 | "sbb\t%2, %0" | |
1478 | [(set_attr "timings" "11,33") | |
1479 | (set_attr "length" "3,6")] | |
1480 | ) | |
1481 | ||
1482 | (define_expand "subdi3" | |
bcddd3b9 NC |
1483 | [(set (match_operand:DI 0 "register_operand") |
1484 | (minus:DI (match_operand:DI 1 "register_operand") | |
1485 | (match_operand:DI 2 "rx_compare_operand")))] | |
8a5b5449 RH |
1486 | "" |
1487 | { | |
1488 | rtx op0l, op0h, op1l, op1h, op2l, op2h; | |
1489 | ||
1490 | op0l = gen_lowpart (SImode, operands[0]); | |
1491 | op1l = gen_lowpart (SImode, operands[1]); | |
1492 | op2l = gen_lowpart (SImode, operands[2]); | |
1493 | op0h = gen_highpart (SImode, operands[0]); | |
1494 | op1h = gen_highpart (SImode, operands[1]); | |
1495 | op2h = gen_highpart_mode (SImode, DImode, operands[2]); | |
1496 | ||
1497 | emit_insn (gen_subdi3_internal (op0l, op0h, op1l, op2l, op1h, op2h)); | |
1498 | DONE; | |
1499 | }) | |
1500 | ||
1501 | (define_insn_and_split "subdi3_internal" | |
1502 | [(set (match_operand:SI 0 "register_operand" "=&r,&r") | |
1503 | (minus:SI (match_operand:SI 2 "register_operand" " 0, r") | |
bcddd3b9 | 1504 | (match_operand:SI 3 "rx_compare_operand" "rQ, r"))) |
8a5b5449 RH |
1505 | (set (match_operand:SI 1 "register_operand" "= r, r") |
1506 | (minus:SI | |
1507 | (minus:SI | |
1508 | (match_operand:SI 4 "register_operand" " 1, 1") | |
1509 | (match_operand:SI 5 "rx_compare_operand" " rQ,rQ")) | |
1510 | (geu:SI (match_dup 2) (match_dup 3)))) | |
b4d83be3 | 1511 | (clobber (reg:CC CC_REG))] |
65a324b4 | 1512 | "" |
8a5b5449 RH |
1513 | "#" |
1514 | "reload_completed" | |
1515 | [(const_int 0)] | |
1516 | { | |
1517 | emit_insn (gen_subsi3_flags (operands[0], operands[2], operands[3])); | |
1518 | emit_insn (gen_sbb_internal (operands[1], operands[4], operands[5])); | |
1519 | DONE; | |
1520 | }) | |
65a324b4 NC |
1521 | |
1522 | (define_insn "xorsi3" | |
1523 | [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") | |
1524 | (xor:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0") | |
1525 | (match_operand:SI 2 "rx_source_operand" | |
aea8fc97 | 1526 | "r,Sint08,Sint16,Sint24,i,Q"))) |
b4d83be3 | 1527 | (clobber (reg:CC CC_REG))] |
65a324b4 | 1528 | "" |
c249a7bc | 1529 | "xor\t%Q2, %0" |
aea8fc97 | 1530 | [(set_attr "timings" "11,11,11,11,11,33") |
65a324b4 NC |
1531 | (set_attr "length" "3,4,5,6,7,6")] |
1532 | ) | |
b4d83be3 RH |
1533 | |
1534 | (define_insn "*xorsi3_flags" | |
1535 | [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") | |
1536 | (xor:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0") | |
1537 | (match_operand:SI 2 "rx_source_operand" | |
1538 | "r,Sint08,Sint16,Sint24,i,Q"))) | |
1539 | (set (reg CC_REG) | |
1540 | (compare (xor:SI (match_dup 1) (match_dup 2)) | |
1541 | (const_int 0)))] | |
1542 | "reload_completed && rx_match_ccmode (insn, CC_ZSmode)" | |
1543 | "xor\t%Q2, %0" | |
1544 | [(set_attr "timings" "11,11,11,11,11,33") | |
1545 | (set_attr "length" "3,4,5,6,7,6")] | |
1546 | ) | |
9595a419 | 1547 | \f |
e9c0470a NC |
1548 | ;; A set of peepholes to catch extending loads followed by arithmetic operations. |
1549 | ;; We use iterators where possible to reduce the amount of typing and hence the | |
1550 | ;; possibilities for typos. | |
1551 | ||
1552 | (define_code_iterator extend_types [(zero_extend "") (sign_extend "")]) | |
1553 | (define_code_attr letter [(zero_extend "R") (sign_extend "Q")]) | |
1554 | ||
1555 | (define_code_iterator memex_commutative [(plus "") (and "") (ior "") (xor "")]) | |
1556 | (define_code_iterator memex_noncomm [(div "") (udiv "") (minus "")]) | |
1557 | (define_code_iterator memex_nocc [(smax "") (smin "") (mult "")]) | |
1558 | ||
1559 | (define_code_attr op [(plus "add") (and "and") (div "div") (udiv "divu") (smax "max") (smin "min") (mult "mul") (ior "or") (minus "sub") (xor "xor")]) | |
1560 | ||
1561 | (define_peephole2 | |
1562 | [(set (match_operand:SI 0 "register_operand") | |
1563 | (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand"))) | |
1564 | (parallel [(set (match_operand:SI 2 "register_operand") | |
1565 | (memex_commutative:SI (match_dup 0) | |
1566 | (match_dup 2))) | |
1567 | (clobber (reg:CC CC_REG))])] | |
1568 | "peep2_regno_dead_p (2, REGNO (operands[0]))" | |
1569 | [(parallel [(set:SI (match_dup 2) | |
1570 | (memex_commutative:SI (match_dup 2) | |
1571 | (extend_types:SI (match_dup 1)))) | |
1572 | (clobber (reg:CC CC_REG))])] | |
1573 | ) | |
1574 | ||
1575 | (define_peephole2 | |
1576 | [(set (match_operand:SI 0 "register_operand") | |
1577 | (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand"))) | |
1578 | (parallel [(set (match_operand:SI 2 "register_operand") | |
1579 | (memex_commutative:SI (match_dup 2) | |
1580 | (match_dup 0))) | |
1581 | (clobber (reg:CC CC_REG))])] | |
1582 | "peep2_regno_dead_p (2, REGNO (operands[0]))" | |
1583 | [(parallel [(set:SI (match_dup 2) | |
1584 | (memex_commutative:SI (match_dup 2) | |
1585 | (extend_types:SI (match_dup 1)))) | |
1586 | (clobber (reg:CC CC_REG))])] | |
1587 | ) | |
1588 | ||
1589 | (define_peephole2 | |
1590 | [(set (match_operand:SI 0 "register_operand") | |
1591 | (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand"))) | |
1592 | (parallel [(set (match_operand:SI 2 "register_operand") | |
1593 | (memex_noncomm:SI (match_dup 2) | |
1594 | (match_dup 0))) | |
1595 | (clobber (reg:CC CC_REG))])] | |
1596 | "peep2_regno_dead_p (2, REGNO (operands[0]))" | |
1597 | [(parallel [(set:SI (match_dup 2) | |
1598 | (memex_noncomm:SI (match_dup 2) | |
1599 | (extend_types:SI (match_dup 1)))) | |
1600 | (clobber (reg:CC CC_REG))])] | |
1601 | ) | |
1602 | ||
1603 | (define_peephole2 | |
1604 | [(set (match_operand:SI 0 "register_operand") | |
1605 | (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand"))) | |
1606 | (set (match_operand:SI 2 "register_operand") | |
1607 | (memex_nocc:SI (match_dup 0) | |
1608 | (match_dup 2)))] | |
1609 | "peep2_regno_dead_p (2, REGNO (operands[0]))" | |
1610 | [(set:SI (match_dup 2) | |
1611 | (memex_nocc:SI (match_dup 2) | |
1612 | (extend_types:SI (match_dup 1))))] | |
1613 | ) | |
1614 | ||
1615 | (define_peephole2 | |
1616 | [(set (match_operand:SI 0 "register_operand") | |
1617 | (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand"))) | |
1618 | (set (match_operand:SI 2 "register_operand") | |
1619 | (memex_nocc:SI (match_dup 2) | |
1620 | (match_dup 0)))] | |
1621 | "peep2_regno_dead_p (2, REGNO (operands[0]))" | |
1622 | [(set:SI (match_dup 2) | |
1623 | (memex_nocc:SI (match_dup 2) | |
1624 | (extend_types:SI (match_dup 1))))] | |
1625 | ) | |
1626 | ||
1627 | (define_insn "<memex_commutative:code>si3_<extend_types:code><small_int_modes:mode>" | |
1628 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1629 | (memex_commutative:SI (match_operand:SI 1 "register_operand" "%0") | |
1630 | (extend_types:SI (match_operand:small_int_modes 2 "rx_restricted_mem_operand" "Q")))) | |
1631 | (clobber (reg:CC CC_REG))] | |
1632 | "" | |
1633 | "<memex_commutative:op>\t%<extend_types:letter>2, %0" | |
1634 | [(set_attr "timings" "33") | |
1635 | (set_attr "length" "5")] ;; This length is corrected in rx_adjust_insn_length | |
1636 | ) | |
1637 | ||
1638 | (define_insn "<memex_noncomm:code>si3_<extend_types:code><small_int_modes:mode>" | |
1639 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1640 | (memex_noncomm:SI (match_operand:SI 1 "register_operand" "0") | |
1641 | (extend_types:SI (match_operand:small_int_modes 2 "rx_restricted_mem_operand" "Q")))) | |
1642 | (clobber (reg:CC CC_REG))] | |
1643 | "" | |
1644 | "<memex_noncomm:op>\t%<extend_types:letter>2, %0" | |
1645 | [(set_attr "timings" "33") | |
1646 | (set_attr "length" "5")] ;; This length is corrected in rx_adjust_insn_length | |
1647 | ) | |
1648 | ||
1649 | (define_insn "<memex_nocc:code>si3_<extend_types:code><small_int_modes:mode>" | |
1650 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1651 | (memex_nocc:SI (match_operand:SI 1 "register_operand" "%0") | |
1652 | (extend_types:SI (match_operand:small_int_modes 2 "rx_restricted_mem_operand" "Q"))))] | |
1653 | "" | |
1654 | "<memex_nocc:op>\t%<extend_types:letter>2, %0" | |
1655 | [(set_attr "timings" "33") | |
1656 | (set_attr "length" "5")] ;; This length is corrected in rx_adjust_insn_length | |
1657 | ) | |
1658 | ||
1659 | (define_peephole2 | |
1660 | [(set (match_operand:SI 0 "register_operand") | |
1661 | (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand"))) | |
1662 | (set (reg:CC CC_REG) | |
1663 | (compare:CC (match_operand:SI 2 "register_operand") | |
1664 | (match_dup 0)))] | |
1665 | "peep2_regno_dead_p (2, REGNO (operands[0]))" | |
1666 | [(set (reg:CC CC_REG) | |
1667 | (compare:CC (match_dup 2) | |
1668 | (extend_types:SI (match_dup 1))))] | |
1669 | ) | |
1670 | ||
1671 | (define_insn "comparesi3_<extend_types:code><small_int_modes:mode>" | |
1672 | [(set (reg:CC CC_REG) | |
1673 | (compare:CC (match_operand:SI 0 "register_operand" "=r") | |
1674 | (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand" "Q"))))] | |
1675 | "" | |
1676 | "cmp\t%<extend_types:letter>1, %0" | |
1677 | [(set_attr "timings" "33") | |
1678 | (set_attr "length" "5")] ;; This length is corrected in rx_adjust_insn_length | |
1679 | ) | |
1680 | \f | |
65a324b4 | 1681 | ;; Floating Point Instructions |
65a324b4 NC |
1682 | |
1683 | (define_insn "addsf3" | |
1684 | [(set (match_operand:SF 0 "register_operand" "=r,r,r") | |
1685 | (plus:SF (match_operand:SF 1 "register_operand" "%0,0,0") | |
aea8fc97 | 1686 | (match_operand:SF 2 "rx_source_operand" "r,F,Q"))) |
b4d83be3 | 1687 | (clobber (reg:CC CC_REG))] |
65a324b4 | 1688 | "ALLOW_RX_FPU_INSNS" |
c249a7bc | 1689 | "fadd\t%2, %0" |
aea8fc97 | 1690 | [(set_attr "timings" "44,44,66") |
65a324b4 NC |
1691 | (set_attr "length" "3,7,5")] |
1692 | ) | |
1693 | ||
1694 | (define_insn "divsf3" | |
1695 | [(set (match_operand:SF 0 "register_operand" "=r,r,r") | |
1696 | (div:SF (match_operand:SF 1 "register_operand" "0,0,0") | |
aea8fc97 | 1697 | (match_operand:SF 2 "rx_source_operand" "r,F,Q"))) |
b4d83be3 | 1698 | (clobber (reg:CC CC_REG))] |
65a324b4 NC |
1699 | "ALLOW_RX_FPU_INSNS" |
1700 | "fdiv\t%2, %0" | |
aea8fc97 | 1701 | [(set_attr "timings" "1616,1616,1818") |
65a324b4 NC |
1702 | (set_attr "length" "3,7,5")] |
1703 | ) | |
1704 | ||
1705 | (define_insn "mulsf3" | |
1706 | [(set (match_operand:SF 0 "register_operand" "=r,r,r") | |
1707 | (mult:SF (match_operand:SF 1 "register_operand" "%0,0,0") | |
aea8fc97 | 1708 | (match_operand:SF 2 "rx_source_operand" "r,F,Q"))) |
b4d83be3 | 1709 | (clobber (reg:CC CC_REG))] |
65a324b4 | 1710 | "ALLOW_RX_FPU_INSNS" |
c249a7bc | 1711 | "fmul\t%2, %0" |
aea8fc97 | 1712 | [(set_attr "timings" "33,33,55") |
65a324b4 NC |
1713 | (set_attr "length" "3,7,5")] |
1714 | ) | |
1715 | ||
1716 | (define_insn "subsf3" | |
1717 | [(set (match_operand:SF 0 "register_operand" "=r,r,r") | |
1718 | (minus:SF (match_operand:SF 1 "register_operand" "0,0,0") | |
aea8fc97 | 1719 | (match_operand:SF 2 "rx_source_operand" "r,F,Q"))) |
b4d83be3 | 1720 | (clobber (reg:CC CC_REG))] |
65a324b4 | 1721 | "ALLOW_RX_FPU_INSNS" |
c249a7bc | 1722 | "fsub\t%Q2, %0" |
aea8fc97 | 1723 | [(set_attr "timings" "44,44,66") |
65a324b4 NC |
1724 | (set_attr "length" "3,7,5")] |
1725 | ) | |
1726 | ||
1727 | (define_insn "fix_truncsfsi2" | |
1728 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
aea8fc97 | 1729 | (fix:SI (match_operand:SF 1 "rx_compare_operand" "r,Q"))) |
b4d83be3 | 1730 | (clobber (reg:CC CC_REG))] |
65a324b4 | 1731 | "ALLOW_RX_FPU_INSNS" |
c249a7bc | 1732 | "ftoi\t%Q1, %0" |
aea8fc97 | 1733 | [(set_attr "timings" "22,44") |
65a324b4 NC |
1734 | (set_attr "length" "3,5")] |
1735 | ) | |
1736 | ||
1737 | (define_insn "floatsisf2" | |
1738 | [(set (match_operand:SF 0 "register_operand" "=r,r") | |
aea8fc97 | 1739 | (float:SF (match_operand:SI 1 "rx_compare_operand" "r,Q"))) |
b4d83be3 | 1740 | (clobber (reg:CC CC_REG))] |
65a324b4 | 1741 | "ALLOW_RX_FPU_INSNS" |
c249a7bc | 1742 | "itof\t%Q1, %0" |
aea8fc97 | 1743 | [(set_attr "timings" "22,44") |
65a324b4 NC |
1744 | (set_attr "length" "3,6")] |
1745 | ) | |
1746 | \f | |
1747 | ;; Bit manipulation instructions. | |
65a324b4 | 1748 | |
f033541c RH |
1749 | ;; ??? The *_in_memory patterns will not be matched without further help. |
1750 | ;; At one time we had the insv expander generate them, but I suspect that | |
1751 | ;; in general we get better performance by exposing the register load to | |
1752 | ;; the optimizers. | |
1753 | ;; | |
1754 | ;; An alternate solution would be to re-organize these patterns such | |
1755 | ;; that allow both register and memory operands. This would allow the | |
1756 | ;; register allocator to spill and not load the register operand. This | |
1757 | ;; would be possible only for operations for which we have a constant | |
1758 | ;; bit offset, so that we can adjust the address by ofs/8 and replace | |
1759 | ;; the offset in the insn by ofs%8. | |
1760 | ||
1761 | (define_insn "*bitset" | |
265c835f | 1762 | [(set (match_operand:SI 0 "register_operand" "=r") |
f033541c RH |
1763 | (ior:SI (ashift:SI (const_int 1) |
1764 | (match_operand:SI 1 "rx_shift_operand" "ri")) | |
1765 | (match_operand:SI 2 "register_operand" "0")))] | |
65a324b4 | 1766 | "" |
f033541c | 1767 | "bset\t%1, %0" |
65a324b4 NC |
1768 | [(set_attr "length" "3")] |
1769 | ) | |
1770 | ||
f033541c RH |
1771 | (define_insn "*bitset_in_memory" |
1772 | [(set (match_operand:QI 0 "memory_operand" "+Q") | |
1773 | (ior:QI (ashift:QI (const_int 1) | |
1774 | (match_operand:QI 1 "nonmemory_operand" "ri")) | |
1775 | (match_dup 0)))] | |
65a324b4 | 1776 | "" |
f033541c | 1777 | "bset\t%1, %0.B" |
65a324b4 | 1778 | [(set_attr "length" "3") |
d845b2f9 | 1779 | (set_attr "timings" "33")] |
65a324b4 NC |
1780 | ) |
1781 | ||
34fee389 RH |
1782 | (define_insn "*bitinvert" |
1783 | [(set (match_operand:SI 0 "register_operand" "=r") | |
f033541c RH |
1784 | (xor:SI (ashift:SI (const_int 1) |
1785 | (match_operand:SI 1 "rx_shift_operand" "ri")) | |
1786 | (match_operand:SI 2 "register_operand" "0")))] | |
65a324b4 | 1787 | "" |
f033541c | 1788 | "bnot\t%1, %0" |
65a324b4 NC |
1789 | [(set_attr "length" "3")] |
1790 | ) | |
1791 | ||
f033541c RH |
1792 | (define_insn "*bitinvert_in_memory" |
1793 | [(set (match_operand:QI 0 "memory_operand" "+Q") | |
1794 | (xor:QI (ashift:QI (const_int 1) | |
1795 | (match_operand:QI 1 "nonmemory_operand" "ri")) | |
1796 | (match_dup 0)))] | |
65a324b4 | 1797 | "" |
f033541c | 1798 | "bnot\t%1, %0.B" |
65a324b4 NC |
1799 | [(set_attr "length" "5") |
1800 | (set_attr "timings" "33")] | |
1801 | ) | |
1802 | ||
f033541c | 1803 | (define_insn "*bitclr" |
265c835f | 1804 | [(set (match_operand:SI 0 "register_operand" "=r") |
f033541c | 1805 | (and:SI (not:SI |
265c835f RH |
1806 | (ashift:SI |
1807 | (const_int 1) | |
f033541c RH |
1808 | (match_operand:SI 1 "rx_shift_operand" "ri"))) |
1809 | (match_operand:SI 2 "register_operand" "0")))] | |
65a324b4 | 1810 | "" |
f033541c | 1811 | "bclr\t%1, %0" |
65a324b4 NC |
1812 | [(set_attr "length" "3")] |
1813 | ) | |
1814 | ||
f033541c RH |
1815 | (define_insn "*bitclr_in_memory" |
1816 | [(set (match_operand:QI 0 "memory_operand" "+Q") | |
1817 | (and:QI (not:QI | |
265c835f RH |
1818 | (ashift:QI |
1819 | (const_int 1) | |
f033541c RH |
1820 | (match_operand:QI 1 "nonmemory_operand" "ri"))) |
1821 | (match_dup 0)))] | |
65a324b4 | 1822 | "" |
f033541c | 1823 | "bclr\t%1, %0.B" |
65a324b4 | 1824 | [(set_attr "length" "3") |
d845b2f9 | 1825 | (set_attr "timings" "33")] |
65a324b4 NC |
1826 | ) |
1827 | ||
f033541c RH |
1828 | (define_insn "*insv_imm" |
1829 | [(set (zero_extract:SI | |
1830 | (match_operand:SI 0 "register_operand" "+r") | |
1831 | (const_int 1) | |
1832 | (match_operand:SI 1 "rx_shift_operand" "ri")) | |
1833 | (match_operand:SI 2 "const_int_operand" ""))] | |
1834 | "" | |
1835 | { | |
1836 | if (INTVAL (operands[2]) & 1) | |
1837 | return "bset\t%1, %0"; | |
1838 | else | |
1839 | return "bclr\t%1, %0"; | |
1840 | } | |
1841 | [(set_attr "length" "3")] | |
1842 | ) | |
1843 | ||
1844 | (define_insn_and_split "rx_insv_reg" | |
1845 | [(set (zero_extract:SI | |
1846 | (match_operand:SI 0 "register_operand" "+r") | |
1847 | (const_int 1) | |
1848 | (match_operand:SI 1 "const_int_operand" "")) | |
1849 | (match_operand:SI 2 "register_operand" "r")) | |
1850 | (clobber (reg:CC CC_REG))] | |
1851 | "" | |
1852 | "#" | |
1853 | "reload_completed" | |
1854 | [(set (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1)) | |
1855 | (match_dup 3))] | |
1856 | { | |
1857 | rtx flags, x; | |
1858 | ||
1859 | /* Emit tst #1, op2. */ | |
1860 | flags = gen_rtx_REG (CC_ZSmode, CC_REG); | |
1861 | x = gen_rtx_AND (SImode, operands[2], const1_rtx); | |
1862 | x = gen_rtx_COMPARE (CC_ZSmode, x, const0_rtx); | |
1863 | x = gen_rtx_SET (VOIDmode, flags, x); | |
1864 | emit_insn (x); | |
1865 | ||
1866 | /* Emit bmne. */ | |
1867 | operands[3] = gen_rtx_NE (SImode, flags, const0_rtx); | |
1868 | }) | |
1869 | ||
1870 | (define_insn_and_split "*insv_cond" | |
1871 | [(set (zero_extract:SI | |
1872 | (match_operand:SI 0 "register_operand" "+r") | |
1873 | (const_int 1) | |
1874 | (match_operand:SI 1 "const_int_operand" "")) | |
1875 | (match_operator:SI 4 "comparison_operator" | |
1876 | [(match_operand:SI 2 "register_operand" "r") | |
1877 | (match_operand:SI 3 "rx_source_operand" "riQ")])) | |
1878 | (clobber (reg:CC CC_REG))] | |
1879 | "" | |
1880 | "#" | |
1881 | "reload_completed" | |
1882 | [(set (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1)) | |
1883 | (match_dup 4))] | |
1884 | { | |
1885 | rtx flags, x; | |
1886 | ||
1887 | flags = gen_rtx_REG (CCmode, CC_REG); | |
1888 | x = gen_rtx_COMPARE (CCmode, operands[2], operands[3]); | |
1889 | x = gen_rtx_SET (VOIDmode, flags, x); | |
1890 | emit_insn (x); | |
1891 | ||
1892 | operands[4] = gen_rtx_fmt_ee (GET_CODE (operands[4]), SImode, | |
1893 | flags, const0_rtx); | |
1894 | }) | |
1895 | ||
1896 | (define_insn "*bmcc" | |
1897 | [(set (zero_extract:SI | |
1898 | (match_operand:SI 0 "register_operand" "+r") | |
1899 | (const_int 1) | |
1900 | (match_operand:SI 1 "const_int_operand" "")) | |
1901 | (match_operator:SI 2 "comparison_operator" | |
1902 | [(reg CC_REG) (const_int 0)]))] | |
1903 | "reload_completed" | |
1904 | "bm%B2\t%1, %0" | |
1905 | [(set_attr "length" "3")] | |
1906 | ) | |
1907 | ||
1908 | ;; Work around the fact that X=Y<0 is preferentially expanded as a shift. | |
1909 | (define_insn_and_split "*insv_cond_lt" | |
1910 | [(set (zero_extract:SI | |
1911 | (match_operand:SI 0 "register_operand" "+r") | |
1912 | (const_int 1) | |
1913 | (match_operand:SI 1 "const_int_operand" "")) | |
1914 | (match_operator:SI 3 "rshift_operator" | |
1915 | [(match_operand:SI 2 "register_operand" "r") | |
1916 | (const_int 31)])) | |
1917 | (clobber (reg:CC CC_REG))] | |
1918 | "" | |
1919 | "#" | |
1920 | "" | |
1921 | [(parallel [(set (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1)) | |
1922 | (lt:SI (match_dup 2) (const_int 0))) | |
1923 | (clobber (reg:CC CC_REG))])] | |
1924 | "" | |
1925 | ) | |
1926 | ||
65a324b4 | 1927 | (define_expand "insv" |
f033541c RH |
1928 | [(set (zero_extract:SI |
1929 | (match_operand:SI 0 "register_operand") ;; Destination | |
1930 | (match_operand:SI 1 "const_int_operand") ;; # of bits to set | |
1931 | (match_operand:SI 2 "nonmemory_operand")) ;; Starting bit | |
1932 | (match_operand:SI 3 "nonmemory_operand"))] ;; Bits to insert | |
65a324b4 | 1933 | "" |
f033541c RH |
1934 | { |
1935 | /* We only handle single-bit inserts. */ | |
1936 | if (!CONST_INT_P (operands[1]) || INTVAL (operands[1]) != 1) | |
1937 | FAIL; | |
1938 | ||
1939 | /* Either the bit to insert or the position must be constant. */ | |
1940 | if (CONST_INT_P (operands[3])) | |
1941 | operands[3] = GEN_INT (INTVAL (operands[3]) & 1); | |
1942 | else if (CONST_INT_P (operands[2])) | |
1943 | { | |
1944 | emit_insn (gen_rx_insv_reg (operands[0], operands[2], operands[3])); | |
65a324b4 | 1945 | DONE; |
f033541c RH |
1946 | } |
1947 | else | |
65a324b4 | 1948 | FAIL; |
f033541c | 1949 | }) |
65a324b4 NC |
1950 | \f |
1951 | ;; Atomic exchange operation. | |
1952 | ||
1953 | (define_insn "sync_lock_test_and_setsi" | |
265c835f RH |
1954 | [(set (match_operand:SI 0 "register_operand" "=r,r") |
1955 | (match_operand:SI 1 "rx_compare_operand" "=r,Q")) | |
1956 | (set (match_dup 1) | |
1957 | (match_operand:SI 2 "register_operand" "0,0"))] | |
65a324b4 NC |
1958 | "" |
1959 | "xchg\t%1, %0" | |
1960 | [(set_attr "length" "3,6") | |
1961 | (set_attr "timings" "22")] | |
1962 | ) | |
65a324b4 NC |
1963 | \f |
1964 | ;; Block move functions. | |
1965 | ||
1966 | (define_expand "movstr" | |
265c835f RH |
1967 | [(set (match_operand:BLK 1 "memory_operand") ;; Dest |
1968 | (match_operand:BLK 2 "memory_operand")) ;; Source | |
1969 | (use (match_operand:SI 0 "register_operand")) ;; Updated Dest | |
65a324b4 NC |
1970 | ] |
1971 | "" | |
1972 | { | |
1973 | rtx addr1 = gen_rtx_REG (SImode, 1); | |
1974 | rtx addr2 = gen_rtx_REG (SImode, 2); | |
1975 | rtx len = gen_rtx_REG (SImode, 3); | |
1976 | rtx dest_copy = gen_reg_rtx (SImode); | |
1977 | ||
1978 | emit_move_insn (len, GEN_INT (-1)); | |
1979 | emit_move_insn (addr1, force_operand (XEXP (operands[1], 0), NULL_RTX)); | |
1980 | emit_move_insn (addr2, force_operand (XEXP (operands[2], 0), NULL_RTX)); | |
1981 | operands[1] = replace_equiv_address_nv (operands[1], addr1); | |
1982 | operands[2] = replace_equiv_address_nv (operands[2], addr2); | |
1983 | emit_move_insn (dest_copy, addr1); | |
1984 | emit_insn (gen_rx_movstr ()); | |
1985 | emit_move_insn (len, GEN_INT (-1)); | |
1986 | emit_insn (gen_rx_strend (operands[0], dest_copy)); | |
1987 | DONE; | |
1988 | } | |
1989 | ) | |
1990 | ||
1991 | (define_insn "rx_movstr" | |
265c835f RH |
1992 | [(set (mem:BLK (reg:SI 1)) |
1993 | (mem:BLK (reg:SI 2))) | |
65a324b4 NC |
1994 | (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_MOVSTR) |
1995 | (clobber (reg:SI 1)) | |
1996 | (clobber (reg:SI 2)) | |
aea8fc97 | 1997 | (clobber (reg:SI 3))] |
65a324b4 NC |
1998 | "" |
1999 | "smovu" | |
2000 | [(set_attr "length" "2") | |
2001 | (set_attr "timings" "1111")] ;; The timing is a guesstimate. | |
2002 | ) | |
2003 | ||
2004 | (define_insn "rx_strend" | |
265c835f RH |
2005 | [(set (match_operand:SI 0 "register_operand" "=r") |
2006 | (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "r") | |
65a324b4 NC |
2007 | (reg:SI 3)] UNSPEC_STRLEN)) |
2008 | (clobber (reg:SI 1)) | |
2009 | (clobber (reg:SI 2)) | |
2010 | (clobber (reg:SI 3)) | |
aea8fc97 NC |
2011 | (clobber (reg:CC CC_REG)) |
2012 | ] | |
65a324b4 NC |
2013 | "" |
2014 | "mov\t%1, r1\n\tmov\t#0, r2\n\tsuntil.b\n\tmov\tr1, %0\n\tsub\t#1, %0" | |
2015 | [(set_attr "length" "10") | |
65a324b4 NC |
2016 | (set_attr "timings" "1111")] ;; The timing is a guesstimate. |
2017 | ) | |
2018 | ||
2019 | (define_expand "movmemsi" | |
2020 | [(parallel | |
2021 | [(set (match_operand:BLK 0 "memory_operand") ;; Dest | |
2022 | (match_operand:BLK 1 "memory_operand")) ;; Source | |
2023 | (use (match_operand:SI 2 "register_operand")) ;; Length in bytes | |
2024 | (match_operand 3 "immediate_operand") ;; Align | |
2025 | (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_MOVMEM)] | |
2026 | )] | |
2027 | "" | |
2028 | { | |
2029 | rtx addr1 = gen_rtx_REG (SImode, 1); | |
2030 | rtx addr2 = gen_rtx_REG (SImode, 2); | |
2031 | rtx len = gen_rtx_REG (SImode, 3); | |
2032 | ||
673a5740 NC |
2033 | /* Do not use when the source or destination are volatile - the SMOVF |
2034 | instruction will read and write in word sized blocks, which may be | |
2035 | outside of the valid address range. */ | |
2036 | if (MEM_P (operands[0]) && MEM_VOLATILE_P (operands[0])) | |
2037 | FAIL; | |
2038 | if (MEM_P (operands[1]) && MEM_VOLATILE_P (operands[1])) | |
2039 | FAIL; | |
2040 | ||
65a324b4 NC |
2041 | if (REG_P (operands[0]) && (REGNO (operands[0]) == 2 |
2042 | || REGNO (operands[0]) == 3)) | |
2043 | FAIL; | |
2044 | if (REG_P (operands[1]) && (REGNO (operands[1]) == 1 | |
2045 | || REGNO (operands[1]) == 3)) | |
2046 | FAIL; | |
2047 | if (REG_P (operands[2]) && (REGNO (operands[2]) == 1 | |
2048 | || REGNO (operands[2]) == 2)) | |
2049 | FAIL; | |
d845b2f9 | 2050 | |
65a324b4 NC |
2051 | emit_move_insn (addr1, force_operand (XEXP (operands[0], 0), NULL_RTX)); |
2052 | emit_move_insn (addr2, force_operand (XEXP (operands[1], 0), NULL_RTX)); | |
2053 | emit_move_insn (len, force_operand (operands[2], NULL_RTX)); | |
2054 | operands[0] = replace_equiv_address_nv (operands[0], addr1); | |
2055 | operands[1] = replace_equiv_address_nv (operands[1], addr2); | |
2056 | emit_insn (gen_rx_movmem ()); | |
2057 | DONE; | |
2058 | } | |
2059 | ) | |
2060 | ||
2061 | (define_insn "rx_movmem" | |
2062 | [(set (mem:BLK (reg:SI 1)) | |
2063 | (mem:BLK (reg:SI 2))) | |
2064 | (use (reg:SI 3)) | |
2065 | (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_MOVMEM) | |
2066 | (clobber (reg:SI 1)) | |
2067 | (clobber (reg:SI 2)) | |
2068 | (clobber (reg:SI 3))] | |
2069 | "" | |
2070 | "smovf" | |
2071 | [(set_attr "length" "2") | |
2072 | (set_attr "timings" "1111")] ;; The timing is a guesstimate. | |
2073 | ) | |
2074 | ||
2075 | (define_expand "setmemsi" | |
2076 | [(set (match_operand:BLK 0 "memory_operand") ;; Dest | |
2077 | (match_operand:QI 2 "nonmemory_operand")) ;; Value | |
2078 | (use (match_operand:SI 1 "nonmemory_operand")) ;; Length | |
2079 | (match_operand 3 "immediate_operand") ;; Align | |
2080 | (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_SETMEM)] | |
2081 | "" | |
2082 | { | |
2083 | rtx addr = gen_rtx_REG (SImode, 1); | |
2084 | rtx val = gen_rtx_REG (QImode, 2); | |
2085 | rtx len = gen_rtx_REG (SImode, 3); | |
2086 | ||
2087 | emit_move_insn (addr, force_operand (XEXP (operands[0], 0), NULL_RTX)); | |
2088 | emit_move_insn (len, force_operand (operands[1], NULL_RTX)); | |
2089 | emit_move_insn (val, operands[2]); | |
2090 | emit_insn (gen_rx_setmem ()); | |
2091 | DONE; | |
2092 | } | |
2093 | ) | |
2094 | ||
2095 | (define_insn "rx_setmem" | |
265c835f RH |
2096 | [(set (mem:BLK (reg:SI 1)) |
2097 | (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_SETMEM)) | |
65a324b4 NC |
2098 | (clobber (reg:SI 1)) |
2099 | (clobber (reg:SI 3))] | |
2100 | "" | |
2101 | "sstr.b" | |
2102 | [(set_attr "length" "2") | |
2103 | (set_attr "timings" "1111")] ;; The timing is a guesstimate. | |
2104 | ) | |
2105 | ||
2106 | (define_expand "cmpstrnsi" | |
aea8fc97 NC |
2107 | [(set (match_operand:SI 0 "register_operand") ;; Result |
2108 | (unspec_volatile:SI [(match_operand:BLK 1 "memory_operand") ;; String1 | |
2109 | (match_operand:BLK 2 "memory_operand")] ;; String2 | |
65a324b4 | 2110 | UNSPEC_CMPSTRN)) |
aea8fc97 NC |
2111 | (use (match_operand:SI 3 "register_operand")) ;; Max Length |
2112 | (match_operand:SI 4 "immediate_operand")] ;; Known Align | |
65a324b4 NC |
2113 | "" |
2114 | { | |
2115 | rtx str1 = gen_rtx_REG (SImode, 1); | |
2116 | rtx str2 = gen_rtx_REG (SImode, 2); | |
2117 | rtx len = gen_rtx_REG (SImode, 3); | |
2118 | ||
2119 | emit_move_insn (str1, force_operand (XEXP (operands[1], 0), NULL_RTX)); | |
2120 | emit_move_insn (str2, force_operand (XEXP (operands[2], 0), NULL_RTX)); | |
2121 | emit_move_insn (len, force_operand (operands[3], NULL_RTX)); | |
2122 | ||
2123 | emit_insn (gen_rx_cmpstrn (operands[0], operands[1], operands[2])); | |
2124 | DONE; | |
2125 | } | |
2126 | ) | |
2127 | ||
2128 | (define_expand "cmpstrsi" | |
aea8fc97 NC |
2129 | [(set (match_operand:SI 0 "register_operand") ;; Result |
2130 | (unspec_volatile:SI [(match_operand:BLK 1 "memory_operand") ;; String1 | |
2131 | (match_operand:BLK 2 "memory_operand")] ;; String2 | |
65a324b4 | 2132 | UNSPEC_CMPSTRN)) |
aea8fc97 | 2133 | (match_operand:SI 3 "immediate_operand")] ;; Known Align |
65a324b4 NC |
2134 | "" |
2135 | { | |
2136 | rtx str1 = gen_rtx_REG (SImode, 1); | |
2137 | rtx str2 = gen_rtx_REG (SImode, 2); | |
2138 | rtx len = gen_rtx_REG (SImode, 3); | |
2139 | ||
2140 | emit_move_insn (str1, force_reg (SImode, XEXP (operands[1], 0))); | |
2141 | emit_move_insn (str2, force_reg (SImode, XEXP (operands[2], 0))); | |
2142 | emit_move_insn (len, GEN_INT (-1)); | |
2143 | ||
2144 | emit_insn (gen_rx_cmpstrn (operands[0], operands[1], operands[2])); | |
2145 | DONE; | |
2146 | } | |
2147 | ) | |
2148 | ||
2149 | (define_insn "rx_cmpstrn" | |
265c835f RH |
2150 | [(set (match_operand:SI 0 "register_operand" "=r") |
2151 | (unspec_volatile:SI [(reg:SI 1) (reg:SI 2) (reg:SI 3)] | |
2152 | UNSPEC_CMPSTRN)) | |
2153 | (use (match_operand:BLK 1 "memory_operand" "m")) | |
2154 | (use (match_operand:BLK 2 "memory_operand" "m")) | |
65a324b4 NC |
2155 | (clobber (reg:SI 1)) |
2156 | (clobber (reg:SI 2)) | |
aea8fc97 NC |
2157 | (clobber (reg:SI 3)) |
2158 | (clobber (reg:CC CC_REG))] | |
65a324b4 NC |
2159 | "" |
2160 | "scmpu ; Perform the string comparison | |
2161 | mov #-1, %0 ; Set up -1 result (which cannot be created | |
2162 | ; by the SC insn) | |
2163 | bnc ?+ ; If Carry is not set skip over | |
2164 | scne.L %0 ; Set result based on Z flag | |
2165 | ?: | |
2166 | " | |
2167 | [(set_attr "length" "9") | |
2168 | (set_attr "timings" "1111")] ;; The timing is a guesstimate. | |
2169 | ) | |
2170 | \f | |
2171 | ;; Builtin Functions | |
2172 | ;; | |
2173 | ;; GCC does not have the ability to generate the following instructions | |
2174 | ;; on its own so they are provided as builtins instead. To use them from | |
2175 | ;; a program for example invoke them as __builtin_rx_<insn_name>. For | |
2176 | ;; example: | |
2177 | ;; | |
2178 | ;; int short_byte_swap (int arg) { return __builtin_rx_revw (arg); } | |
2179 | ||
2180 | ;;---------- Accumulator Support ------------------------ | |
2181 | ||
2182 | ;; Multiply & Accumulate (high) | |
2183 | (define_insn "machi" | |
2184 | [(unspec:SI [(match_operand:SI 0 "register_operand" "r") | |
2185 | (match_operand:SI 1 "register_operand" "r")] | |
2186 | UNSPEC_BUILTIN_MACHI)] | |
2187 | "" | |
2188 | "machi\t%0, %1" | |
2189 | [(set_attr "length" "3")] | |
2190 | ) | |
2191 | ||
2192 | ;; Multiply & Accumulate (low) | |
2193 | (define_insn "maclo" | |
2194 | [(unspec:SI [(match_operand:SI 0 "register_operand" "r") | |
2195 | (match_operand:SI 1 "register_operand" "r")] | |
2196 | UNSPEC_BUILTIN_MACLO)] | |
2197 | "" | |
2198 | "maclo\t%0, %1" | |
2199 | [(set_attr "length" "3")] | |
2200 | ) | |
2201 | ||
2202 | ;; Multiply (high) | |
2203 | (define_insn "mulhi" | |
2204 | [(unspec:SI [(match_operand:SI 0 "register_operand" "r") | |
2205 | (match_operand:SI 1 "register_operand" "r")] | |
2206 | UNSPEC_BUILTIN_MULHI)] | |
2207 | "" | |
2208 | "mulhi\t%0, %1" | |
2209 | [(set_attr "length" "3")] | |
2210 | ) | |
2211 | ||
2212 | ;; Multiply (low) | |
2213 | (define_insn "mullo" | |
2214 | [(unspec:SI [(match_operand:SI 0 "register_operand" "r") | |
2215 | (match_operand:SI 1 "register_operand" "r")] | |
2216 | UNSPEC_BUILTIN_MULLO)] | |
2217 | "" | |
2218 | "mullo\t%0, %1" | |
2219 | [(set_attr "length" "3")] | |
2220 | ) | |
2221 | ||
2222 | ;; Move from Accumulator (high) | |
2223 | (define_insn "mvfachi" | |
2224 | [(set (match_operand:SI 0 "register_operand" "=r") | |
2225 | (unspec:SI [(const_int 0)] | |
2226 | UNSPEC_BUILTIN_MVFACHI))] | |
2227 | "" | |
2228 | "mvfachi\t%0" | |
2229 | [(set_attr "length" "3")] | |
2230 | ) | |
2231 | ||
2232 | ;; Move from Accumulator (middle) | |
2233 | (define_insn "mvfacmi" | |
2234 | [(set (match_operand:SI 0 "register_operand" "=r") | |
2235 | (unspec:SI [(const_int 0)] | |
2236 | UNSPEC_BUILTIN_MVFACMI))] | |
2237 | "" | |
2238 | "mvfacmi\t%0" | |
2239 | [(set_attr "length" "3")] | |
2240 | ) | |
2241 | ||
2242 | ;; Move to Accumulator (high) | |
2243 | (define_insn "mvtachi" | |
9595a419 NC |
2244 | [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] |
2245 | UNSPEC_BUILTIN_MVTACHI)] | |
65a324b4 NC |
2246 | "" |
2247 | "mvtachi\t%0" | |
2248 | [(set_attr "length" "3")] | |
2249 | ) | |
2250 | ||
2251 | ;; Move to Accumulator (low) | |
2252 | (define_insn "mvtaclo" | |
9595a419 NC |
2253 | [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] |
2254 | UNSPEC_BUILTIN_MVTACLO)] | |
65a324b4 NC |
2255 | "" |
2256 | "mvtaclo\t%0" | |
2257 | [(set_attr "length" "3")] | |
2258 | ) | |
2259 | ||
2260 | ;; Round Accumulator | |
2261 | (define_insn "racw" | |
9595a419 NC |
2262 | [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")] |
2263 | UNSPEC_BUILTIN_RACW)] | |
65a324b4 NC |
2264 | "" |
2265 | "racw\t%0" | |
2266 | [(set_attr "length" "3")] | |
2267 | ) | |
2268 | ||
2269 | ;; Repeat multiply and accumulate | |
2270 | (define_insn "rmpa" | |
2271 | [(unspec:SI [(const_int 0) (reg:SI 1) (reg:SI 2) (reg:SI 3) | |
2272 | (reg:SI 4) (reg:SI 5) (reg:SI 6)] | |
2273 | UNSPEC_BUILTIN_RMPA) | |
2274 | (clobber (reg:SI 1)) | |
2275 | (clobber (reg:SI 2)) | |
2276 | (clobber (reg:SI 3))] | |
2277 | "" | |
2278 | "rmpa" | |
2279 | [(set_attr "length" "2") | |
2280 | (set_attr "timings" "1010")] | |
2281 | ) | |
2282 | ||
2283 | ;;---------- Arithmetic ------------------------ | |
2284 | ||
2285 | ;; Byte swap (two 16-bit values). | |
2286 | (define_insn "revw" | |
34fee389 | 2287 | [(set (match_operand:SI 0 "register_operand" "=r") |
65a324b4 NC |
2288 | (unspec:SI [(match_operand:SI 1 "register_operand" "r")] |
2289 | UNSPEC_BUILTIN_REVW))] | |
2290 | "" | |
2291 | "revw\t%1, %0" | |
2292 | [(set_attr "length" "3")] | |
2293 | ) | |
2294 | ||
2295 | ;; Round to integer. | |
2296 | (define_insn "lrintsf2" | |
2297 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
2298 | (unspec:SI [(match_operand:SF 1 "rx_compare_operand" "r,Q")] | |
aea8fc97 NC |
2299 | UNSPEC_BUILTIN_ROUND)) |
2300 | (clobber (reg:CC CC_REG))] | |
65a324b4 NC |
2301 | "" |
2302 | "round\t%1, %0" | |
aea8fc97 | 2303 | [(set_attr "timings" "22,44") |
65a324b4 NC |
2304 | (set_attr "length" "3,5")] |
2305 | ) | |
2306 | ||
65a324b4 NC |
2307 | ;;---------- Control Registers ------------------------ |
2308 | ||
2309 | ;; Clear Processor Status Word | |
2310 | (define_insn "clrpsw" | |
bf9afb7d | 2311 | [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")] |
65a324b4 | 2312 | UNSPEC_BUILTIN_CLRPSW) |
aea8fc97 | 2313 | (clobber (reg:CC CC_REG))] |
65a324b4 NC |
2314 | "" |
2315 | "clrpsw\t%F0" | |
aea8fc97 | 2316 | [(set_attr "length" "2")] |
65a324b4 NC |
2317 | ) |
2318 | ||
2319 | ;; Set Processor Status Word | |
2320 | (define_insn "setpsw" | |
bf9afb7d | 2321 | [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")] |
65a324b4 | 2322 | UNSPEC_BUILTIN_SETPSW) |
aea8fc97 | 2323 | (clobber (reg:CC CC_REG))] |
65a324b4 NC |
2324 | "" |
2325 | "setpsw\t%F0" | |
aea8fc97 | 2326 | [(set_attr "length" "2")] |
65a324b4 NC |
2327 | ) |
2328 | ||
2329 | ;; Move from control register | |
2330 | (define_insn "mvfc" | |
9595a419 | 2331 | [(set (match_operand:SI 0 "register_operand" "=r") |
bf9afb7d | 2332 | (unspec_volatile:SI [(match_operand:SI 1 "immediate_operand" "i")] |
65a324b4 NC |
2333 | UNSPEC_BUILTIN_MVFC))] |
2334 | "" | |
2335 | "mvfc\t%C1, %0" | |
2336 | [(set_attr "length" "3")] | |
2337 | ) | |
2338 | ||
2339 | ;; Move to control register | |
2340 | (define_insn "mvtc" | |
bf9afb7d | 2341 | [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i,i") |
65a324b4 | 2342 | (match_operand:SI 1 "nonmemory_operand" "r,i")] |
9595a419 | 2343 | UNSPEC_BUILTIN_MVTC)] |
65a324b4 NC |
2344 | "" |
2345 | "mvtc\t%1, %C0" | |
9595a419 NC |
2346 | [(set_attr "length" "3,7")] |
2347 | ;; Ignore possible clobbering of the comparison flags in the | |
2348 | ;; PSW register. This is a cc0 target so any cc0 setting | |
2349 | ;; instruction will always be paired with a cc0 user, without | |
2350 | ;; the possibility of this instruction being placed in between | |
2351 | ;; them. | |
2352 | ) | |
2353 | ||
2354 | ;; Move to interrupt priority level | |
2355 | (define_insn "mvtipl" | |
bf9afb7d | 2356 | [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "Uint04")] |
9595a419 NC |
2357 | UNSPEC_BUILTIN_MVTIPL)] |
2358 | "" | |
2359 | "mvtipl\t%0" | |
2360 | [(set_attr "length" "3")] | |
65a324b4 NC |
2361 | ) |
2362 | ||
2363 | ;;---------- Interrupts ------------------------ | |
2364 | ||
2365 | ;; Break | |
2366 | (define_insn "brk" | |
2367 | [(unspec_volatile [(const_int 0)] | |
2368 | UNSPEC_BUILTIN_BRK)] | |
2369 | "" | |
2370 | "brk" | |
2371 | [(set_attr "length" "1") | |
2372 | (set_attr "timings" "66")] | |
2373 | ) | |
2374 | ||
2375 | ;; Interrupt | |
2376 | (define_insn "int" | |
2377 | [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")] | |
2378 | UNSPEC_BUILTIN_INT)] | |
2379 | "" | |
2380 | "int\t%0" | |
2381 | [(set_attr "length" "3")] | |
2382 | ) | |
2383 | ||
2384 | ;; Wait | |
2385 | (define_insn "wait" | |
2386 | [(unspec_volatile [(const_int 0)] | |
2387 | UNSPEC_BUILTIN_WAIT)] | |
2388 | "" | |
2389 | "wait" | |
2390 | [(set_attr "length" "2")] | |
2391 | ) | |
2392 | ||
2393 | ;;---------- CoProcessor Support ------------------------ | |
2394 | ||
2395 | ;; FIXME: The instructions are currently commented out because | |
2396 | ;; the bit patterns have not been finalized, so the assembler | |
2397 | ;; does not support them. Once they are decided and the assembler | |
2398 | ;; supports them, enable the instructions here. | |
2399 | ||
2400 | ;; Move from co-processor register | |
2401 | (define_insn "mvfcp" | |
2402 | [(set (match_operand:SI 0 "register_operand" "=r") | |
2403 | (unspec:SI [(match_operand:SI 1 "immediate_operand" "i") | |
2404 | (match_operand:SI 2 "immediate_operand" "i")] | |
2405 | UNSPEC_BUILTIN_MVFCP))] | |
2406 | "" | |
2407 | "; mvfcp\t%1, %0, %2" | |
2408 | [(set_attr "length" "5")] | |
2409 | ) | |
2410 | ||
65a324b4 NC |
2411 | ;;---------- Misc ------------------------ |
2412 | ||
2413 | ;; Required by cfglayout.c... | |
2414 | (define_insn "nop" | |
2415 | [(const_int 0)] | |
2416 | "" | |
2417 | "nop" | |
2418 | [(set_attr "length" "1")] | |
2419 | ) |