]>
Commit | Line | Data |
---|---|---|
4b6bb562 | 1 | ;; Machine description of the Mitsubishi M32R cpu for GNU C compiler |
16f104b3 | 2 | ;; Copyright (C) 1996, 1997, 1998, 1999, 2001 Free Software Foundation, Inc. |
8c5ca3b9 DE |
3 | |
4 | ;; This file is part of GNU CC. | |
5 | ||
6 | ;; GNU CC is free software; you can redistribute it and/or modify | |
7 | ;; it under the terms of the GNU General Public License as published by | |
8 | ;; the Free Software Foundation; either version 2, or (at your option) | |
9 | ;; any later version. | |
10 | ||
11 | ;; GNU CC is distributed in the hope that it will be useful, | |
12 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | ;; GNU General Public License for more details. | |
15 | ||
16 | ;; You should have received a copy of the GNU General Public License | |
17 | ;; along with GNU CC; see the file COPYING. If not, write to | |
18 | ;; the Free Software Foundation, 59 Temple Place - Suite 330, | |
19 | ;; Boston, MA 02111-1307, USA. | |
20 | ||
21 | ;; See file "rtl.def" for documentation on define_insn, match_*, et. al. | |
22 | ||
23 | ;; unspec usage | |
24 | ;; 0 - blockage | |
25 | ;; 1 - flush_icache | |
26 | ;; 2 - load_sda_base | |
5b8ae21f | 27 | ;; 3 - setting carry in addx/subx instructions. |
8c5ca3b9 DE |
28 | \f |
29 | ;; Insn type. Used to default other attribute values. | |
8c5ca3b9 | 30 | (define_attr "type" |
5b8ae21f | 31 | "int2,int4,load2,load4,load8,store2,store4,store8,shift2,shift4,mul2,div4,uncond_branch,branch,call,multi,misc" |
8c5ca3b9 DE |
32 | (const_string "misc")) |
33 | ||
34 | ;; Length in bytes. | |
35 | (define_attr "length" "" | |
5b8ae21f | 36 | (cond [(eq_attr "type" "int2,load2,store2,shift2,mul2") |
8c5ca3b9 DE |
37 | (const_int 2) |
38 | ||
5b8ae21f MM |
39 | (eq_attr "type" "int4,load4,store4,shift4,div4") |
40 | (const_int 4) | |
8c5ca3b9 DE |
41 | |
42 | (eq_attr "type" "multi") | |
43 | (const_int 8) | |
44 | ||
45 | (eq_attr "type" "uncond_branch,branch,call") | |
46 | (const_int 4)] | |
47 | ||
48 | (const_int 4))) | |
49 | ||
50 | ;; The length here is the length of a single asm. Unfortunately it might be | |
51 | ;; 2 or 4 so we must allow for 4. That's ok though. | |
52 | (define_asm_attributes | |
53 | [(set_attr "length" "4") | |
54 | (set_attr "type" "multi")]) | |
2b7972b0 MM |
55 | |
56 | ||
57 | ;; Whether an instruction is 16-bit or 32-bit | |
58 | (define_attr "insn_size" "short,long" | |
5b8ae21f | 59 | (if_then_else (eq_attr "type" "int2,load2,store2,shift2,mul2") |
2b7972b0 MM |
60 | (const_string "short") |
61 | (const_string "long"))) | |
62 | ||
5b8ae21f MM |
63 | (define_attr "debug" "no,yes" |
64 | (const (symbol_ref "(TARGET_DEBUG != 0)"))) | |
65 | ||
66 | (define_attr "opt_size" "no,yes" | |
67 | (const (symbol_ref "(optimize_size != 0)"))) | |
68 | ||
2b7972b0 MM |
69 | (define_attr "m32r" "no,yes" |
70 | (const (symbol_ref "(TARGET_M32R != 0)"))) | |
71 | ||
de41e41c BE |
72 | (define_attr "m32rx" "no,yes" |
73 | (const (symbol_ref "(TARGET_M32RX != 0)"))) | |
74 | ||
75 | (define_attr "m32rx_pipeline" "either,s,o,long,m32r" | |
76 | (cond [(eq_attr "m32rx" "no") | |
77 | (const_string "m32r") | |
78 | ||
79 | (eq_attr "insn_size" "!short") | |
80 | (const_string "long")] | |
81 | ||
82 | (cond [(eq_attr "type" "int2") | |
83 | (const_string "either") | |
84 | ||
85 | (eq_attr "type" "load2,store2,shift2,uncond_branch,branch,call") | |
86 | (const_string "o") | |
87 | ||
88 | (eq_attr "type" "mul2") | |
89 | (const_string "s")] | |
90 | ||
91 | (const_string "long")))) | |
8c5ca3b9 | 92 | \f |
2b7972b0 MM |
93 | ;; :::::::::::::::::::: |
94 | ;; :: | |
95 | ;; :: Function Units | |
96 | ;; :: | |
97 | ;; :::::::::::::::::::: | |
98 | ||
99 | ;; On most RISC machines, there are instructions whose results are not | |
100 | ;; available for a specific number of cycles. Common cases are instructions | |
101 | ;; that load data from memory. On many machines, a pipeline stall will result | |
102 | ;; if the data is referenced too soon after the load instruction. | |
103 | ||
104 | ;; In addition, many newer microprocessors have multiple function units, | |
105 | ;; usually one for integer and one for floating point, and often will incur | |
106 | ;; pipeline stalls when a result that is needed is not yet ready. | |
107 | ||
108 | ;; The descriptions in this section allow the specification of how much time | |
109 | ;; must elapse between the execution of an instruction and the time when its | |
110 | ;; result is used. It also allows specification of when the execution of an | |
111 | ;; instruction will delay execution of similar instructions due to function | |
112 | ;; unit conflicts. | |
113 | ||
114 | ;; For the purposes of the specifications in this section, a machine is divided | |
115 | ;; into "function units", each of which execute a specific class of | |
116 | ;; instructions in first-in-first-out order. Function units that accept one | |
117 | ;; instruction each cycle and allow a result to be used in the succeeding | |
118 | ;; instruction (usually via forwarding) need not be specified. Classic RISC | |
119 | ;; microprocessors will normally have a single function unit, which we can call | |
120 | ;; `memory'. The newer "superscalar" processors will often have function units | |
121 | ;; for floating point operations, usually at least a floating point adder and | |
122 | ;; multiplier. | |
123 | ||
124 | ;; Each usage of a function units by a class of insns is specified with a | |
125 | ;; `define_function_unit' expression, which looks like this: | |
126 | ||
127 | ;; (define_function_unit NAME MULTIPLICITY SIMULTANEITY TEST READY-DELAY | |
128 | ;; ISSUE-DELAY [CONFLICT-LIST]) | |
129 | ||
130 | ;; NAME is a string giving the name of the function unit. | |
131 | ||
132 | ;; MULTIPLICITY is an integer specifying the number of identical units in the | |
133 | ;; processor. If more than one unit is specified, they will be scheduled | |
134 | ;; independently. Only truly independent units should be counted; a pipelined | |
135 | ;; unit should be specified as a single unit. (The only common example of a | |
136 | ;; machine that has multiple function units for a single instruction class that | |
137 | ;; are truly independent and not pipelined are the two multiply and two | |
138 | ;; increment units of the CDC 6600.) | |
139 | ||
140 | ;; SIMULTANEITY specifies the maximum number of insns that can be executing in | |
141 | ;; each instance of the function unit simultaneously or zero if the unit is | |
142 | ;; pipelined and has no limit. | |
143 | ||
144 | ;; All `define_function_unit' definitions referring to function unit NAME must | |
145 | ;; have the same name and values for MULTIPLICITY and SIMULTANEITY. | |
146 | ||
147 | ;; TEST is an attribute test that selects the insns we are describing in this | |
148 | ;; definition. Note that an insn may use more than one function unit and a | |
149 | ;; function unit may be specified in more than one `define_function_unit'. | |
150 | ||
151 | ;; READY-DELAY is an integer that specifies the number of cycles after which | |
152 | ;; the result of the instruction can be used without introducing any stalls. | |
153 | ||
154 | ;; ISSUE-DELAY is an integer that specifies the number of cycles after the | |
155 | ;; instruction matching the TEST expression begins using this unit until a | |
156 | ;; subsequent instruction can begin. A cost of N indicates an N-1 cycle delay. | |
157 | ;; A subsequent instruction may also be delayed if an earlier instruction has a | |
158 | ;; longer READY-DELAY value. This blocking effect is computed using the | |
159 | ;; SIMULTANEITY, READY-DELAY, ISSUE-DELAY, and CONFLICT-LIST terms. For a | |
160 | ;; normal non-pipelined function unit, SIMULTANEITY is one, the unit is taken | |
161 | ;; to block for the READY-DELAY cycles of the executing insn, and smaller | |
162 | ;; values of ISSUE-DELAY are ignored. | |
163 | ||
164 | ;; CONFLICT-LIST is an optional list giving detailed conflict costs for this | |
165 | ;; unit. If specified, it is a list of condition test expressions to be | |
166 | ;; applied to insns chosen to execute in NAME following the particular insn | |
167 | ;; matching TEST that is already executing in NAME. For each insn in the list, | |
168 | ;; ISSUE-DELAY specifies the conflict cost; for insns not in the list, the cost | |
169 | ;; is zero. If not specified, CONFLICT-LIST defaults to all instructions that | |
170 | ;; use the function unit. | |
171 | ||
172 | ;; Typical uses of this vector are where a floating point function unit can | |
173 | ;; pipeline either single- or double-precision operations, but not both, or | |
174 | ;; where a memory unit can pipeline loads, but not stores, etc. | |
175 | ||
176 | ;; As an example, consider a classic RISC machine where the result of a load | |
177 | ;; instruction is not available for two cycles (a single "delay" instruction is | |
178 | ;; required) and where only one load instruction can be executed | |
179 | ;; simultaneously. This would be specified as: | |
180 | ||
181 | ;; (define_function_unit "memory" 1 1 (eq_attr "type" "load") 2 0) | |
182 | ||
183 | ;; For the case of a floating point function unit that can pipeline | |
184 | ;; either single or double precision, but not both, the following could be | |
185 | ;; specified: | |
186 | ;; | |
187 | ;; (define_function_unit "fp" 1 0 | |
188 | ;; (eq_attr "type" "sp_fp") 4 4 | |
189 | ;; [(eq_attr "type" "dp_fp")]) | |
190 | ;; | |
191 | ;; (define_function_unit "fp" 1 0 | |
192 | ;; (eq_attr "type" "dp_fp") 4 4 | |
193 | ;; [(eq_attr "type" "sp_fp")]) | |
194 | ||
195 | ;; Note: The scheduler attempts to avoid function unit conflicts and uses all | |
196 | ;; the specifications in the `define_function_unit' expression. It has | |
197 | ;; recently come to our attention that these specifications may not allow | |
198 | ;; modeling of some of the newer "superscalar" processors that have insns using | |
199 | ;; multiple pipelined units. These insns will cause a potential conflict for | |
200 | ;; the second unit used during their execution and there is no way of | |
201 | ;; representing that conflict. We welcome any examples of how function unit | |
202 | ;; conflicts work in such processors and suggestions for their representation. | |
203 | ||
8c5ca3b9 DE |
204 | ;; Function units of the M32R |
205 | ;; Units that take one cycle do not need to be specified. | |
206 | ||
2b7972b0 | 207 | ;; (define_function_unit {name} {multiplicity} {simulataneity} {test} |
8c5ca3b9 DE |
208 | ;; {ready-delay} {issue-delay} [{conflict-list}]) |
209 | ||
8c5ca3b9 DE |
210 | ;; Hack to get GCC to better pack the instructions. |
211 | ;; We pretend there is a separate long function unit that conflicts with | |
212 | ;; both the left and right 16 bit insn slots. | |
213 | ||
5b8ae21f MM |
214 | (define_function_unit "short" 2 2 |
215 | (and (eq_attr "m32r" "yes") | |
216 | (and (eq_attr "insn_size" "short") | |
217 | (eq_attr "type" "!load2"))) | |
8c5ca3b9 | 218 | 1 0 |
5b8ae21f | 219 | [(eq_attr "insn_size" "long")]) |
8c5ca3b9 | 220 | |
5b8ae21f MM |
221 | (define_function_unit "short" 2 2 ;; load delay of 1 clock for mem execution + 1 clock for WB |
222 | (and (eq_attr "m32r" "yes") | |
223 | (eq_attr "type" "load2")) | |
224 | 3 0 | |
225 | [(eq_attr "insn_size" "long")]) | |
8c5ca3b9 DE |
226 | |
227 | (define_function_unit "long" 1 1 | |
5b8ae21f MM |
228 | (and (eq_attr "m32r" "yes") |
229 | (and (eq_attr "insn_size" "long") | |
230 | (eq_attr "type" "!load4,load8"))) | |
8c5ca3b9 | 231 | 1 0 |
5b8ae21f MM |
232 | [(eq_attr "insn_size" "short")]) |
233 | ||
234 | (define_function_unit "long" 1 1 ;; load delay of 1 clock for mem execution + 1 clock for WB | |
235 | (and (eq_attr "m32r" "yes") | |
236 | (and (eq_attr "insn_size" "long") | |
237 | (eq_attr "type" "load4,load8"))) | |
238 | 3 0 | |
239 | [(eq_attr "insn_size" "short")]) | |
240 | ||
de41e41c BE |
241 | (define_function_unit "left" 1 1 |
242 | (and (eq_attr "m32rx_pipeline" "o,either") | |
243 | (eq_attr "type" "!load2")) | |
244 | 1 0 | |
245 | [(eq_attr "insn_size" "long")]) | |
246 | ||
247 | (define_function_unit "left" 1 1 ;; load delay of 1 clock for mem execution + 1 clock for WB | |
248 | (and (eq_attr "m32rx_pipeline" "o,either") | |
249 | (eq_attr "type" "load2")) | |
250 | 3 0 | |
251 | [(eq_attr "insn_size" "long")]) | |
252 | ||
253 | (define_function_unit "right" 1 1 | |
254 | (eq_attr "m32rx_pipeline" "s,either") | |
255 | 1 0 | |
256 | [(eq_attr "insn_size" "long")]) | |
257 | ||
258 | (define_function_unit "long" 1 1 | |
259 | (and (eq_attr "m32rx" "yes") | |
260 | (and (eq_attr "insn_size" "long") | |
261 | (eq_attr "type" "!load4,load8"))) | |
262 | 2 0 | |
263 | [(eq_attr "insn_size" "short")]) | |
264 | ||
265 | (define_function_unit "long" 1 1 ;; load delay of 1 clock for mem execution + 1 clock for WB | |
266 | (and (eq_attr "m32rx" "yes") | |
267 | (and (eq_attr "insn_size" "long") | |
268 | (eq_attr "type" "load4,load8"))) | |
269 | 3 0 | |
270 | [(eq_attr "insn_size" "short")]) | |
8c5ca3b9 DE |
271 | \f |
272 | ;; Expand prologue as RTL | |
5b8ae21f MM |
273 | (define_expand "prologue" |
274 | [(const_int 1)] | |
275 | "" | |
276 | " | |
277 | { | |
278 | m32r_expand_prologue (); | |
279 | DONE; | |
280 | }") | |
281 | ||
8c5ca3b9 DE |
282 | \f |
283 | ;; Move instructions. | |
284 | ;; | |
285 | ;; For QI and HI moves, the register must contain the full properly | |
286 | ;; sign-extended value. nonzero_bits assumes this [otherwise | |
287 | ;; SHORT_IMMEDIATES_SIGN_EXTEND must be used, but the comment for it | |
288 | ;; says it's a kludge and the .md files should be fixed instead]. | |
289 | ||
290 | (define_expand "movqi" | |
291 | [(set (match_operand:QI 0 "general_operand" "") | |
292 | (match_operand:QI 1 "general_operand" ""))] | |
293 | "" | |
294 | " | |
295 | { | |
296 | /* Everything except mem = const or mem = mem can be done easily. | |
297 | Objects in the small data area are handled too. */ | |
298 | ||
299 | if (GET_CODE (operands[0]) == MEM) | |
300 | operands[1] = force_reg (QImode, operands[1]); | |
301 | }") | |
302 | ||
303 | (define_insn "*movqi_insn" | |
5b8ae21f MM |
304 | [(set (match_operand:QI 0 "move_dest_operand" "=r,r,r,r,r,T,m") |
305 | (match_operand:QI 1 "move_src_operand" "r,I,JQR,T,m,r,r"))] | |
8c5ca3b9 DE |
306 | "register_operand (operands[0], QImode) || register_operand (operands[1], QImode)" |
307 | "@ | |
308 | mv %0,%1 | |
309 | ldi %0,%#%1 | |
310 | ldi %0,%#%1 | |
311 | ldub %0,%1 | |
5b8ae21f MM |
312 | ldub %0,%1 |
313 | stb %1,%0 | |
8c5ca3b9 | 314 | stb %1,%0" |
5b8ae21f MM |
315 | [(set_attr "type" "int2,int2,int4,load2,load4,store2,store4") |
316 | (set_attr "length" "2,2,4,2,4,2,4")]) | |
8c5ca3b9 DE |
317 | |
318 | (define_expand "movhi" | |
319 | [(set (match_operand:HI 0 "general_operand" "") | |
320 | (match_operand:HI 1 "general_operand" ""))] | |
321 | "" | |
322 | " | |
323 | { | |
324 | /* Everything except mem = const or mem = mem can be done easily. */ | |
325 | ||
326 | if (GET_CODE (operands[0]) == MEM) | |
327 | operands[1] = force_reg (HImode, operands[1]); | |
328 | }") | |
329 | ||
330 | (define_insn "*movhi_insn" | |
5b8ae21f MM |
331 | [(set (match_operand:HI 0 "move_dest_operand" "=r,r,r,r,r,r,T,m") |
332 | (match_operand:HI 1 "move_src_operand" "r,I,JQR,K,T,m,r,r"))] | |
8c5ca3b9 DE |
333 | "register_operand (operands[0], HImode) || register_operand (operands[1], HImode)" |
334 | "@ | |
335 | mv %0,%1 | |
336 | ldi %0,%#%1 | |
337 | ldi %0,%#%1 | |
338 | ld24 %0,%#%1 | |
339 | lduh %0,%1 | |
5b8ae21f MM |
340 | lduh %0,%1 |
341 | sth %1,%0 | |
8c5ca3b9 | 342 | sth %1,%0" |
5b8ae21f MM |
343 | [(set_attr "type" "int2,int2,int4,int4,load2,load4,store2,store4") |
344 | (set_attr "length" "2,2,4,4,2,4,2,4")]) | |
345 | ||
346 | (define_expand "movsi_push" | |
347 | [(set (mem:SI (pre_dec:SI (match_operand:SI 0 "register_operand" ""))) | |
348 | (match_operand:SI 1 "register_operand" ""))] | |
349 | "" | |
350 | "") | |
351 | ||
352 | (define_expand "movsi_pop" | |
353 | [(set (match_operand:SI 0 "register_operand" "") | |
354 | (mem:SI (post_inc:SI (match_operand:SI 1 "register_operand" ""))))] | |
355 | "" | |
356 | "") | |
8c5ca3b9 DE |
357 | |
358 | (define_expand "movsi" | |
359 | [(set (match_operand:SI 0 "general_operand" "") | |
360 | (match_operand:SI 1 "general_operand" ""))] | |
361 | "" | |
362 | " | |
363 | { | |
4d6c607f | 364 | /* Everything except mem = const or mem = mem can be done easily. */ |
8c5ca3b9 DE |
365 | |
366 | if (GET_CODE (operands[0]) == MEM) | |
367 | operands[1] = force_reg (SImode, operands[1]); | |
368 | ||
4d6c607f | 369 | /* Small Data Area reference? */ |
8c5ca3b9 DE |
370 | if (small_data_operand (operands[1], SImode)) |
371 | { | |
372 | emit_insn (gen_movsi_sda (operands[0], operands[1])); | |
373 | DONE; | |
374 | } | |
4d6c607f DE |
375 | |
376 | /* If medium or large code model, symbols have to be loaded with | |
377 | seth/add3. */ | |
378 | if (addr32_operand (operands[1], SImode)) | |
8c5ca3b9 DE |
379 | { |
380 | emit_insn (gen_movsi_addr32 (operands[0], operands[1])); | |
381 | DONE; | |
382 | } | |
383 | }") | |
384 | ||
4b6bb562 | 385 | ;; ??? Do we need a const_double constraint here for large unsigned values? |
5b8ae21f | 386 | (define_insn "*movsi_insn" |
56e2e762 | 387 | [(set (match_operand:SI 0 "move_dest_operand" "=r,r,r,r,r,r,r,r,r,T,S,m") |
5b8ae21f | 388 | (match_operand:SI 1 "move_src_operand" "r,I,J,MQ,L,n,T,U,m,r,r,r"))] |
8c5ca3b9 | 389 | "register_operand (operands[0], SImode) || register_operand (operands[1], SImode)" |
5b8ae21f MM |
390 | "* |
391 | { | |
392 | if (GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == SUBREG) | |
393 | { | |
394 | switch (GET_CODE (operands[1])) | |
395 | { | |
396 | HOST_WIDE_INT value; | |
397 | ||
398 | default: | |
399 | break; | |
400 | ||
401 | case REG: | |
402 | case SUBREG: | |
403 | return \"mv %0,%1\"; | |
404 | ||
405 | case MEM: | |
56e2e762 NC |
406 | if (GET_CODE (XEXP (operands[1], 0)) == POST_INC |
407 | && XEXP (XEXP (operands[1], 0), 0) == stack_pointer_rtx) | |
408 | return \"pop %0\"; | |
409 | ||
5b8ae21f MM |
410 | return \"ld %0,%1\"; |
411 | ||
412 | case CONST_INT: | |
413 | value = INTVAL (operands[1]); | |
414 | if (INT16_P (value)) | |
415 | return \"ldi %0,%#%1\\t; %X1\"; | |
416 | ||
417 | if (UINT24_P (value)) | |
418 | return \"ld24 %0,%#%1\\t; %X1\"; | |
419 | ||
420 | if (UPPER16_P (value)) | |
421 | return \"seth %0,%#%T1\\t; %X1\"; | |
422 | ||
423 | return \"#\"; | |
424 | ||
425 | case CONST: | |
426 | case SYMBOL_REF: | |
427 | case LABEL_REF: | |
428 | if (TARGET_ADDR24) | |
429 | return \"ld24 %0,%#%1\"; | |
430 | ||
431 | return \"#\"; | |
432 | } | |
433 | } | |
434 | ||
435 | else if (GET_CODE (operands[0]) == MEM | |
436 | && (GET_CODE (operands[1]) == REG || GET_CODE (operands[1]) == SUBREG)) | |
56e2e762 NC |
437 | { |
438 | if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC | |
439 | && XEXP (XEXP (operands[0], 0), 0) == stack_pointer_rtx) | |
440 | return \"push %1\"; | |
441 | ||
442 | return \"st %1,%0\"; | |
443 | } | |
5b8ae21f | 444 | |
61f3b78f | 445 | abort (); |
5b8ae21f MM |
446 | }" |
447 | [(set_attr "type" "int2,int2,int4,int4,int4,multi,load2,load2,load4,store2,store2,store4") | |
448 | (set_attr "length" "2,2,4,4,4,8,2,2,4,2,2,4")]) | |
8c5ca3b9 | 449 | |
4d6c607f DE |
450 | ; Try to use a four byte / two byte pair for constants not loadable with |
451 | ; ldi, ld24, seth. | |
452 | ||
453 | (define_split | |
454 | [(set (match_operand:SI 0 "register_operand" "") | |
455 | (match_operand:SI 1 "two_insn_const_operand" ""))] | |
456 | "" | |
457 | [(set (match_dup 0) (match_dup 2)) | |
458 | (set (match_dup 0) (ior:SI (match_dup 0) (match_dup 3)))] | |
459 | " | |
460 | { | |
461 | unsigned HOST_WIDE_INT val = INTVAL (operands[1]); | |
462 | unsigned HOST_WIDE_INT tmp; | |
463 | int shift; | |
464 | ||
465 | /* In all cases we will emit two instructions. However we try to | |
4b6bb562 | 466 | use 2 byte instructions wherever possible. We can assume the |
4d6c607f DE |
467 | constant isn't loadable with any of ldi, ld24, or seth. */ |
468 | ||
469 | /* See if we can load a 24 bit unsigned value and invert it. */ | |
470 | if (UINT24_P (~ val)) | |
471 | { | |
472 | emit_insn (gen_movsi (operands[0], GEN_INT (~ val))); | |
473 | emit_insn (gen_one_cmplsi2 (operands[0], operands[0])); | |
474 | DONE; | |
475 | } | |
476 | ||
477 | /* See if we can load a 24 bit unsigned value and shift it into place. | |
478 | 0x01fffffe is just beyond ld24's range. */ | |
479 | for (shift = 1, tmp = 0x01fffffe; | |
480 | shift < 8; | |
481 | ++shift, tmp <<= 1) | |
482 | { | |
483 | if ((val & ~tmp) == 0) | |
484 | { | |
485 | emit_insn (gen_movsi (operands[0], GEN_INT (val >> shift))); | |
486 | emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (shift))); | |
487 | DONE; | |
488 | } | |
489 | } | |
490 | ||
737e7965 JW |
491 | /* Can't use any two byte insn, fall back to seth/or3. Use ~0xffff instead |
492 | of 0xffff0000, since the later fails on a 64-bit host. */ | |
493 | operands[2] = GEN_INT ((val) & ~0xffff); | |
4d6c607f DE |
494 | operands[3] = GEN_INT ((val) & 0xffff); |
495 | }") | |
496 | ||
5b8ae21f MM |
497 | (define_split |
498 | [(set (match_operand:SI 0 "register_operand" "") | |
499 | (match_operand:SI 1 "seth_add3_operand" "i"))] | |
500 | "TARGET_ADDR32" | |
501 | [(set (match_dup 0) | |
502 | (high:SI (match_dup 1))) | |
503 | (set (match_dup 0) | |
504 | (lo_sum:SI (match_dup 0) | |
505 | (match_dup 1)))] | |
506 | "") | |
507 | ||
8c5ca3b9 DE |
508 | ;; Small data area support. |
509 | ;; The address of _SDA_BASE_ is loaded into a register and all objects in | |
510 | ;; the small data area are indexed off that. This is done for each reference | |
511 | ;; but cse will clean things up for us. We let the compiler choose the | |
512 | ;; register to use so we needn't allocate (and maybe even fix) a special | |
513 | ;; register to use. Since the load and store insns have a 16 bit offset the | |
514 | ;; total size of the data area can be 64K. However, if the data area lives | |
515 | ;; above 16M (24 bits), _SDA_BASE_ will have to be loaded with seth/add3 which | |
516 | ;; would then yield 3 instructions to reference an object [though there would | |
517 | ;; be no net loss if two or more objects were referenced]. The 3 insns can be | |
518 | ;; reduced back to 2 if the size of the small data area were reduced to 32K | |
519 | ;; [then seth + ld/st would work for any object in the area]. Doing this | |
520 | ;; would require special handling of _SDA_BASE_ (its value would be | |
521 | ;; (.sdata + 32K) & 0xffff0000) and reloc computations would be different | |
4b6bb562 | 522 | ;; [I think]. What to do about this is deferred until later and for now we |
8c5ca3b9 DE |
523 | ;; require .sdata to be in the first 16M. |
524 | ||
525 | (define_expand "movsi_sda" | |
526 | [(set (match_dup 2) | |
527 | (unspec [(const_int 0)] 2)) | |
528 | (set (match_operand:SI 0 "register_operand" "") | |
529 | (lo_sum:SI (match_dup 2) | |
530 | (match_operand:SI 1 "small_data_operand" "")))] | |
531 | "" | |
532 | " | |
533 | { | |
534 | if (reload_in_progress || reload_completed) | |
535 | operands[2] = operands[0]; | |
536 | else | |
537 | operands[2] = gen_reg_rtx (SImode); | |
538 | }") | |
539 | ||
540 | (define_insn "*load_sda_base" | |
541 | [(set (match_operand:SI 0 "register_operand" "=r") | |
542 | (unspec [(const_int 0)] 2))] | |
543 | "" | |
544 | "ld24 %0,#_SDA_BASE_" | |
5b8ae21f MM |
545 | [(set_attr "type" "int4") |
546 | (set_attr "length" "4")]) | |
8c5ca3b9 DE |
547 | |
548 | ;; 32 bit address support. | |
549 | ||
550 | (define_expand "movsi_addr32" | |
551 | [(set (match_dup 2) | |
552 | ; addr32_operand isn't used because it's too restrictive, | |
553 | ; seth_add3_operand is more general and thus safer. | |
554 | (high:SI (match_operand:SI 1 "seth_add3_operand" ""))) | |
555 | (set (match_operand:SI 0 "register_operand" "") | |
556 | (lo_sum:SI (match_dup 2) (match_dup 1)))] | |
557 | "" | |
558 | " | |
559 | { | |
560 | if (reload_in_progress || reload_completed) | |
561 | operands[2] = operands[0]; | |
562 | else | |
563 | operands[2] = gen_reg_rtx (SImode); | |
564 | }") | |
565 | ||
566 | (define_insn "set_hi_si" | |
567 | [(set (match_operand:SI 0 "register_operand" "=r") | |
568 | (high:SI (match_operand 1 "symbolic_operand" "")))] | |
569 | "" | |
570 | "seth %0,%#shigh(%1)" | |
5b8ae21f MM |
571 | [(set_attr "type" "int4") |
572 | (set_attr "length" "4")]) | |
8c5ca3b9 DE |
573 | |
574 | (define_insn "lo_sum_si" | |
575 | [(set (match_operand:SI 0 "register_operand" "=r") | |
576 | (lo_sum:SI (match_operand:SI 1 "register_operand" "r") | |
577 | (match_operand:SI 2 "immediate_operand" "in")))] | |
578 | "" | |
579 | "add3 %0,%1,%#%B2" | |
5b8ae21f MM |
580 | [(set_attr "type" "int4") |
581 | (set_attr "length" "4")]) | |
8c5ca3b9 DE |
582 | |
583 | (define_expand "movdi" | |
584 | [(set (match_operand:DI 0 "general_operand" "") | |
585 | (match_operand:DI 1 "general_operand" ""))] | |
586 | "" | |
587 | " | |
588 | { | |
589 | /* Everything except mem = const or mem = mem can be done easily. */ | |
590 | ||
591 | if (GET_CODE (operands[0]) == MEM) | |
592 | operands[1] = force_reg (DImode, operands[1]); | |
8c5ca3b9 DE |
593 | }") |
594 | ||
595 | (define_insn "*movdi_insn" | |
5b8ae21f MM |
596 | [(set (match_operand:DI 0 "move_dest_operand" "=r,r,r,r,m") |
597 | (match_operand:DI 1 "move_double_src_operand" "r,nG,F,m,r"))] | |
8c5ca3b9 | 598 | "register_operand (operands[0], DImode) || register_operand (operands[1], DImode)" |
5b8ae21f MM |
599 | "#" |
600 | [(set_attr "type" "multi,multi,multi,load8,store8") | |
601 | (set_attr "length" "4,4,16,6,6")]) | |
8c5ca3b9 DE |
602 | |
603 | (define_split | |
5b8ae21f MM |
604 | [(set (match_operand:DI 0 "move_dest_operand" "") |
605 | (match_operand:DI 1 "move_double_src_operand" ""))] | |
8c5ca3b9 | 606 | "reload_completed" |
5b8ae21f MM |
607 | [(match_dup 2)] |
608 | "operands[2] = gen_split_move_double (operands);") | |
8c5ca3b9 DE |
609 | \f |
610 | ;; Floating point move insns. | |
611 | ||
612 | (define_expand "movsf" | |
613 | [(set (match_operand:SF 0 "general_operand" "") | |
614 | (match_operand:SF 1 "general_operand" ""))] | |
615 | "" | |
616 | " | |
617 | { | |
618 | /* Everything except mem = const or mem = mem can be done easily. */ | |
619 | ||
620 | if (GET_CODE (operands[0]) == MEM) | |
621 | operands[1] = force_reg (SFmode, operands[1]); | |
622 | }") | |
623 | ||
624 | (define_insn "*movsf_insn" | |
56e2e762 NC |
625 | [(set (match_operand:SF 0 "move_dest_operand" "=r,r,r,r,r,T,S,m") |
626 | (match_operand:SF 1 "move_src_operand" "r,F,U,S,m,r,r,r"))] | |
8c5ca3b9 | 627 | "register_operand (operands[0], SFmode) || register_operand (operands[1], SFmode)" |
5b8ae21f MM |
628 | "@ |
629 | mv %0,%1 | |
630 | # | |
631 | ld %0,%1 | |
632 | ld %0,%1 | |
56e2e762 NC |
633 | ld %0,%1 |
634 | st %1,%0 | |
5b8ae21f MM |
635 | st %1,%0 |
636 | st %1,%0" | |
8c5ca3b9 | 637 | ;; ??? Length of alternative 1 is either 2, 4 or 8. |
56e2e762 NC |
638 | [(set_attr "type" "int2,multi,load2,load2,load4,store2,store2,store4") |
639 | (set_attr "length" "2,8,2,2,4,2,2,4")]) | |
5b8ae21f MM |
640 | |
641 | (define_split | |
642 | [(set (match_operand:SF 0 "register_operand" "") | |
643 | (match_operand:SF 1 "const_double_operand" ""))] | |
644 | "reload_completed" | |
645 | [(set (match_dup 2) (match_dup 3))] | |
646 | " | |
647 | { | |
5b8ae21f | 648 | operands[2] = operand_subword (operands[0], 0, 0, SFmode); |
b5a3eb84 | 649 | operands[3] = operand_subword (operands[1], 0, 0, SFmode); |
5b8ae21f | 650 | }") |
8c5ca3b9 DE |
651 | |
652 | (define_expand "movdf" | |
653 | [(set (match_operand:DF 0 "general_operand" "") | |
654 | (match_operand:DF 1 "general_operand" ""))] | |
655 | "" | |
656 | " | |
657 | { | |
658 | /* Everything except mem = const or mem = mem can be done easily. */ | |
659 | ||
660 | if (GET_CODE (operands[0]) == MEM) | |
661 | operands[1] = force_reg (DFmode, operands[1]); | |
8c5ca3b9 DE |
662 | }") |
663 | ||
664 | (define_insn "*movdf_insn" | |
665 | [(set (match_operand:DF 0 "move_dest_operand" "=r,r,r,m") | |
5b8ae21f | 666 | (match_operand:DF 1 "move_double_src_operand" "r,F,m,r"))] |
8c5ca3b9 | 667 | "register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode)" |
5b8ae21f MM |
668 | "#" |
669 | [(set_attr "type" "multi,multi,load8,store8") | |
670 | (set_attr "length" "4,16,6,6")]) | |
671 | ||
672 | (define_split | |
673 | [(set (match_operand:DF 0 "move_dest_operand" "") | |
674 | (match_operand:DF 1 "move_double_src_operand" ""))] | |
675 | "reload_completed" | |
676 | [(match_dup 2)] | |
677 | "operands[2] = gen_split_move_double (operands);") | |
8c5ca3b9 DE |
678 | \f |
679 | ;; Zero extension instructions. | |
680 | ||
681 | (define_insn "zero_extendqihi2" | |
5b8ae21f | 682 | [(set (match_operand:HI 0 "register_operand" "=r,r,r") |
56e2e762 | 683 | (zero_extend:HI (match_operand:QI 1 "extend_operand" "r,T,m")))] |
8c5ca3b9 DE |
684 | "" |
685 | "@ | |
686 | and3 %0,%1,%#255 | |
5b8ae21f | 687 | ldub %0,%1 |
8c5ca3b9 | 688 | ldub %0,%1" |
5b8ae21f MM |
689 | [(set_attr "type" "int4,load2,load4") |
690 | (set_attr "length" "4,2,4")]) | |
8c5ca3b9 DE |
691 | |
692 | (define_insn "zero_extendqisi2" | |
5b8ae21f | 693 | [(set (match_operand:SI 0 "register_operand" "=r,r,r") |
56e2e762 | 694 | (zero_extend:SI (match_operand:QI 1 "extend_operand" "r,T,m")))] |
8c5ca3b9 DE |
695 | "" |
696 | "@ | |
697 | and3 %0,%1,%#255 | |
5b8ae21f | 698 | ldub %0,%1 |
8c5ca3b9 | 699 | ldub %0,%1" |
5b8ae21f MM |
700 | [(set_attr "type" "int4,load2,load4") |
701 | (set_attr "length" "4,2,4")]) | |
8c5ca3b9 DE |
702 | |
703 | (define_insn "zero_extendhisi2" | |
5b8ae21f | 704 | [(set (match_operand:SI 0 "register_operand" "=r,r,r") |
56e2e762 | 705 | (zero_extend:SI (match_operand:HI 1 "extend_operand" "r,T,m")))] |
8c5ca3b9 DE |
706 | "" |
707 | "@ | |
708 | and3 %0,%1,%#65535 | |
5b8ae21f | 709 | lduh %0,%1 |
8c5ca3b9 | 710 | lduh %0,%1" |
5b8ae21f MM |
711 | [(set_attr "type" "int4,load2,load4") |
712 | (set_attr "length" "4,2,4")]) | |
8c5ca3b9 | 713 | \f |
56e2e762 NC |
714 | ;; Signed conversions from a smaller integer to a larger integer |
715 | (define_insn "extendqihi2" | |
716 | [(set (match_operand:HI 0 "register_operand" "=r,r,r") | |
717 | (sign_extend:HI (match_operand:QI 1 "extend_operand" "0,T,m")))] | |
718 | "" | |
719 | "@ | |
720 | # | |
721 | ldb %0,%1 | |
722 | ldb %0,%1" | |
723 | [(set_attr "type" "multi,load2,load4") | |
724 | (set_attr "length" "2,2,4")]) | |
8c5ca3b9 | 725 | |
56e2e762 | 726 | (define_split |
8c5ca3b9 DE |
727 | [(set (match_operand:HI 0 "register_operand" "") |
728 | (sign_extend:HI (match_operand:QI 1 "register_operand" "")))] | |
56e2e762 NC |
729 | "reload_completed" |
730 | [(match_dup 2) | |
731 | (match_dup 3)] | |
8c5ca3b9 DE |
732 | " |
733 | { | |
56e2e762 NC |
734 | rtx op0 = gen_lowpart (SImode, operands[0]); |
735 | rtx shift = gen_rtx (CONST_INT, VOIDmode, 24); | |
8c5ca3b9 | 736 | |
56e2e762 NC |
737 | operands[2] = gen_ashlsi3 (op0, op0, shift); |
738 | operands[3] = gen_ashrsi3 (op0, op0, shift); | |
8c5ca3b9 DE |
739 | }") |
740 | ||
56e2e762 NC |
741 | (define_insn "extendqisi2" |
742 | [(set (match_operand:SI 0 "register_operand" "=r,r,r") | |
743 | (sign_extend:SI (match_operand:QI 1 "extend_operand" "0,T,m")))] | |
8c5ca3b9 | 744 | "" |
56e2e762 NC |
745 | "@ |
746 | # | |
747 | ldb %0,%1 | |
748 | ldb %0,%1" | |
749 | [(set_attr "type" "multi,load2,load4") | |
750 | (set_attr "length" "4,2,4")]) | |
8c5ca3b9 | 751 | |
56e2e762 | 752 | (define_split |
8c5ca3b9 DE |
753 | [(set (match_operand:SI 0 "register_operand" "") |
754 | (sign_extend:SI (match_operand:QI 1 "register_operand" "")))] | |
56e2e762 NC |
755 | "reload_completed" |
756 | [(match_dup 2) | |
757 | (match_dup 3)] | |
8c5ca3b9 DE |
758 | " |
759 | { | |
56e2e762 NC |
760 | rtx op0 = gen_lowpart (SImode, operands[0]); |
761 | rtx shift = gen_rtx (CONST_INT, VOIDmode, 24); | |
8c5ca3b9 | 762 | |
56e2e762 NC |
763 | operands[2] = gen_ashlsi3 (op0, op0, shift); |
764 | operands[3] = gen_ashrsi3 (op0, op0, shift); | |
8c5ca3b9 DE |
765 | }") |
766 | ||
56e2e762 NC |
767 | (define_insn "extendhisi2" |
768 | [(set (match_operand:SI 0 "register_operand" "=r,r,r") | |
769 | (sign_extend:SI (match_operand:HI 1 "extend_operand" "0,T,m")))] | |
8c5ca3b9 | 770 | "" |
56e2e762 NC |
771 | "@ |
772 | # | |
773 | ldh %0,%1 | |
774 | ldh %0,%1" | |
775 | [(set_attr "type" "multi,load2,load4") | |
776 | (set_attr "length" "4,2,4")]) | |
8c5ca3b9 | 777 | |
56e2e762 | 778 | (define_split |
8c5ca3b9 DE |
779 | [(set (match_operand:SI 0 "register_operand" "") |
780 | (sign_extend:SI (match_operand:HI 1 "register_operand" "")))] | |
56e2e762 NC |
781 | "reload_completed" |
782 | [(match_dup 2) | |
783 | (match_dup 3)] | |
8c5ca3b9 DE |
784 | " |
785 | { | |
56e2e762 NC |
786 | rtx op0 = gen_lowpart (SImode, operands[0]); |
787 | rtx shift = gen_rtx (CONST_INT, VOIDmode, 16); | |
8c5ca3b9 | 788 | |
56e2e762 NC |
789 | operands[2] = gen_ashlsi3 (op0, op0, shift); |
790 | operands[3] = gen_ashrsi3 (op0, op0, shift); | |
8c5ca3b9 | 791 | }") |
8c5ca3b9 DE |
792 | \f |
793 | ;; Arithmetic instructions. | |
794 | ||
795 | ; ??? Adding an alternative to split add3 of small constants into two | |
796 | ; insns yields better instruction packing but slower code. Adds of small | |
797 | ; values is done a lot. | |
798 | ||
799 | (define_insn "addsi3" | |
800 | [(set (match_operand:SI 0 "register_operand" "=r,r,r") | |
801 | (plus:SI (match_operand:SI 1 "register_operand" "%0,0,r") | |
802 | (match_operand:SI 2 "nonmemory_operand" "r,I,J")))] | |
803 | "" | |
804 | "@ | |
805 | add %0,%2 | |
806 | addi %0,%#%2 | |
807 | add3 %0,%1,%#%2" | |
5b8ae21f | 808 | [(set_attr "type" "int2,int2,int4") |
8c5ca3b9 DE |
809 | (set_attr "length" "2,2,4")]) |
810 | ||
811 | ;(define_split | |
812 | ; [(set (match_operand:SI 0 "register_operand" "") | |
813 | ; (plus:SI (match_operand:SI 1 "register_operand" "") | |
814 | ; (match_operand:SI 2 "int8_operand" "")))] | |
815 | ; "reload_completed | |
816 | ; && REGNO (operands[0]) != REGNO (operands[1]) | |
817 | ; && INT8_P (INTVAL (operands[2])) | |
818 | ; && INTVAL (operands[2]) != 0" | |
819 | ; [(set (match_dup 0) (match_dup 1)) | |
820 | ; (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 2)))] | |
821 | ; "") | |
822 | ||
823 | (define_insn "adddi3" | |
824 | [(set (match_operand:DI 0 "register_operand" "=r") | |
825 | (plus:DI (match_operand:DI 1 "register_operand" "%0") | |
826 | (match_operand:DI 2 "register_operand" "r"))) | |
51c10c4e | 827 | (clobber (reg:SI 17))] |
8c5ca3b9 | 828 | "" |
5b8ae21f MM |
829 | "#" |
830 | [(set_attr "type" "multi") | |
8c5ca3b9 DE |
831 | (set_attr "length" "6")]) |
832 | ||
5b8ae21f MM |
833 | ;; ??? The cmp clears the condition bit. Can we speed up somehow? |
834 | (define_split | |
835 | [(set (match_operand:DI 0 "register_operand" "") | |
836 | (plus:DI (match_operand:DI 1 "register_operand" "") | |
837 | (match_operand:DI 2 "register_operand" ""))) | |
838 | (clobber (match_operand 3 "" ""))] | |
839 | "reload_completed" | |
840 | [(parallel [(set (match_dup 3) | |
841 | (const_int 0)) | |
842 | (use (match_dup 4))]) | |
843 | (parallel [(set (match_dup 4) | |
844 | (plus:SI (match_dup 4) | |
845 | (plus:SI (match_dup 5) | |
846 | (match_dup 3)))) | |
847 | (set (match_dup 3) | |
848 | (unspec [(const_int 0)] 3))]) | |
849 | (parallel [(set (match_dup 6) | |
850 | (plus:SI (match_dup 6) | |
851 | (plus:SI (match_dup 7) | |
852 | (match_dup 3)))) | |
853 | (set (match_dup 3) | |
854 | (unspec [(const_int 0)] 3))])] | |
855 | " | |
856 | { | |
857 | operands[4] = operand_subword (operands[0], (WORDS_BIG_ENDIAN != 0), 0, DImode); | |
858 | operands[5] = operand_subword (operands[2], (WORDS_BIG_ENDIAN != 0), 0, DImode); | |
859 | operands[6] = operand_subword (operands[0], (WORDS_BIG_ENDIAN == 0), 0, DImode); | |
860 | operands[7] = operand_subword (operands[2], (WORDS_BIG_ENDIAN == 0), 0, DImode); | |
861 | }") | |
862 | ||
863 | (define_insn "*clear_c" | |
51c10c4e | 864 | [(set (reg:SI 17) |
5b8ae21f MM |
865 | (const_int 0)) |
866 | (use (match_operand:SI 0 "register_operand" "r"))] | |
867 | "" | |
868 | "cmp %0,%0" | |
869 | [(set_attr "type" "int2") | |
870 | (set_attr "length" "2")]) | |
871 | ||
872 | (define_insn "*add_carry" | |
873 | [(set (match_operand:SI 0 "register_operand" "=r") | |
874 | (plus:SI (match_operand:SI 1 "register_operand" "%0") | |
875 | (plus:SI (match_operand:SI 2 "register_operand" "r") | |
51c10c4e NC |
876 | (reg:SI 17)))) |
877 | (set (reg:SI 17) | |
5b8ae21f MM |
878 | (unspec [(const_int 0)] 3))] |
879 | "" | |
880 | "addx %0,%2" | |
881 | [(set_attr "type" "int2") | |
882 | (set_attr "length" "2")]) | |
883 | ||
8c5ca3b9 DE |
884 | (define_insn "subsi3" |
885 | [(set (match_operand:SI 0 "register_operand" "=r") | |
886 | (minus:SI (match_operand:SI 1 "register_operand" "0") | |
887 | (match_operand:SI 2 "register_operand" "r")))] | |
888 | "" | |
889 | "sub %0,%2" | |
5b8ae21f MM |
890 | [(set_attr "type" "int2") |
891 | (set_attr "length" "2")]) | |
8c5ca3b9 DE |
892 | |
893 | (define_insn "subdi3" | |
894 | [(set (match_operand:DI 0 "register_operand" "=r") | |
895 | (minus:DI (match_operand:DI 1 "register_operand" "0") | |
896 | (match_operand:DI 2 "register_operand" "r"))) | |
51c10c4e | 897 | (clobber (reg:SI 17))] |
8c5ca3b9 | 898 | "" |
5b8ae21f MM |
899 | "#" |
900 | [(set_attr "type" "multi") | |
8c5ca3b9 | 901 | (set_attr "length" "6")]) |
5b8ae21f MM |
902 | |
903 | ;; ??? The cmp clears the condition bit. Can we speed up somehow? | |
904 | (define_split | |
905 | [(set (match_operand:DI 0 "register_operand" "") | |
906 | (minus:DI (match_operand:DI 1 "register_operand" "") | |
907 | (match_operand:DI 2 "register_operand" ""))) | |
908 | (clobber (match_operand 3 "" ""))] | |
909 | "reload_completed" | |
910 | [(parallel [(set (match_dup 3) | |
911 | (const_int 0)) | |
912 | (use (match_dup 4))]) | |
913 | (parallel [(set (match_dup 4) | |
914 | (minus:SI (match_dup 4) | |
915 | (minus:SI (match_dup 5) | |
916 | (match_dup 3)))) | |
917 | (set (match_dup 3) | |
918 | (unspec [(const_int 0)] 3))]) | |
919 | (parallel [(set (match_dup 6) | |
920 | (minus:SI (match_dup 6) | |
921 | (minus:SI (match_dup 7) | |
922 | (match_dup 3)))) | |
923 | (set (match_dup 3) | |
924 | (unspec [(const_int 0)] 3))])] | |
925 | " | |
926 | { | |
927 | operands[4] = operand_subword (operands[0], (WORDS_BIG_ENDIAN != 0), 0, DImode); | |
928 | operands[5] = operand_subword (operands[2], (WORDS_BIG_ENDIAN != 0), 0, DImode); | |
929 | operands[6] = operand_subword (operands[0], (WORDS_BIG_ENDIAN == 0), 0, DImode); | |
930 | operands[7] = operand_subword (operands[2], (WORDS_BIG_ENDIAN == 0), 0, DImode); | |
931 | }") | |
932 | ||
933 | (define_insn "*sub_carry" | |
934 | [(set (match_operand:SI 0 "register_operand" "=r") | |
935 | (minus:SI (match_operand:SI 1 "register_operand" "%0") | |
936 | (minus:SI (match_operand:SI 2 "register_operand" "r") | |
51c10c4e NC |
937 | (reg:SI 17)))) |
938 | (set (reg:SI 17) | |
5b8ae21f MM |
939 | (unspec [(const_int 0)] 3))] |
940 | "" | |
941 | "subx %0,%2" | |
942 | [(set_attr "type" "int2") | |
943 | (set_attr "length" "2")]) | |
8c5ca3b9 DE |
944 | \f |
945 | ; Multiply/Divide instructions. | |
946 | ||
947 | (define_insn "mulhisi3" | |
948 | [(set (match_operand:SI 0 "register_operand" "=r") | |
949 | (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "r")) | |
950 | (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))] | |
951 | "" | |
952 | "mullo %1,%2\;mvfacmi %0" | |
5b8ae21f | 953 | [(set_attr "type" "multi") |
8c5ca3b9 DE |
954 | (set_attr "length" "4")]) |
955 | ||
956 | (define_insn "mulsi3" | |
957 | [(set (match_operand:SI 0 "register_operand" "=r") | |
958 | (mult:SI (match_operand:SI 1 "register_operand" "%0") | |
959 | (match_operand:SI 2 "register_operand" "r")))] | |
960 | "" | |
961 | "mul %0,%2" | |
5b8ae21f MM |
962 | [(set_attr "type" "mul2") |
963 | (set_attr "length" "2")]) | |
8c5ca3b9 DE |
964 | |
965 | (define_insn "divsi3" | |
966 | [(set (match_operand:SI 0 "register_operand" "=r") | |
967 | (div:SI (match_operand:SI 1 "register_operand" "0") | |
968 | (match_operand:SI 2 "register_operand" "r")))] | |
969 | "" | |
970 | "div %0,%2" | |
5b8ae21f MM |
971 | [(set_attr "type" "div4") |
972 | (set_attr "length" "4")]) | |
8c5ca3b9 DE |
973 | |
974 | (define_insn "udivsi3" | |
975 | [(set (match_operand:SI 0 "register_operand" "=r") | |
976 | (udiv:SI (match_operand:SI 1 "register_operand" "0") | |
977 | (match_operand:SI 2 "register_operand" "r")))] | |
978 | "" | |
979 | "divu %0,%2" | |
5b8ae21f MM |
980 | [(set_attr "type" "div4") |
981 | (set_attr "length" "4")]) | |
8c5ca3b9 DE |
982 | |
983 | (define_insn "modsi3" | |
984 | [(set (match_operand:SI 0 "register_operand" "=r") | |
985 | (mod:SI (match_operand:SI 1 "register_operand" "0") | |
986 | (match_operand:SI 2 "register_operand" "r")))] | |
987 | "" | |
988 | "rem %0,%2" | |
5b8ae21f MM |
989 | [(set_attr "type" "div4") |
990 | (set_attr "length" "4")]) | |
8c5ca3b9 DE |
991 | |
992 | (define_insn "umodsi3" | |
993 | [(set (match_operand:SI 0 "register_operand" "=r") | |
994 | (umod:SI (match_operand:SI 1 "register_operand" "0") | |
995 | (match_operand:SI 2 "register_operand" "r")))] | |
996 | "" | |
997 | "remu %0,%2" | |
5b8ae21f MM |
998 | [(set_attr "type" "div4") |
999 | (set_attr "length" "4")]) | |
8c5ca3b9 DE |
1000 | \f |
1001 | ;; Boolean instructions. | |
1002 | ;; | |
1003 | ;; We don't define the DImode versions as expand_binop does a good enough job. | |
1004 | ;; And if it doesn't it should be fixed. | |
1005 | ||
1006 | (define_insn "andsi3" | |
1007 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
1008 | (and:SI (match_operand:SI 1 "register_operand" "%0,r") | |
56e2e762 | 1009 | (match_operand:SI 2 "reg_or_uint16_operand" "r,K")))] |
8c5ca3b9 | 1010 | "" |
56e2e762 NC |
1011 | "* |
1012 | { | |
1013 | /* If we are worried about space, see if we can break this up into two | |
1014 | short instructions, which might eliminate a NOP being inserted. */ | |
1015 | if (optimize_size | |
1016 | && m32r_not_same_reg (operands[0], operands[1]) | |
1017 | && GET_CODE (operands[2]) == CONST_INT | |
1018 | && INT8_P (INTVAL (operands[2]))) | |
1019 | return \"#\"; | |
1020 | ||
1021 | else if (GET_CODE (operands[2]) == CONST_INT) | |
1022 | return \"and3 %0,%1,%#%X2\"; | |
1023 | ||
1024 | return \"and %0,%2\"; | |
1025 | }" | |
5b8ae21f MM |
1026 | [(set_attr "type" "int2,int4") |
1027 | (set_attr "length" "2,4")]) | |
8c5ca3b9 | 1028 | |
56e2e762 NC |
1029 | (define_split |
1030 | [(set (match_operand:SI 0 "register_operand" "") | |
1031 | (and:SI (match_operand:SI 1 "register_operand" "") | |
1032 | (match_operand:SI 2 "int8_operand" "")))] | |
1033 | "optimize_size && m32r_not_same_reg (operands[0], operands[1])" | |
1034 | [(set (match_dup 0) (match_dup 2)) | |
1035 | (set (match_dup 0) (and:SI (match_dup 1) (match_dup 0)))] | |
1036 | "") | |
1037 | ||
8c5ca3b9 DE |
1038 | (define_insn "iorsi3" |
1039 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
1040 | (ior:SI (match_operand:SI 1 "register_operand" "%0,r") | |
56e2e762 | 1041 | (match_operand:SI 2 "reg_or_uint16_operand" "r,K")))] |
8c5ca3b9 | 1042 | "" |
56e2e762 NC |
1043 | "* |
1044 | { | |
1045 | /* If we are worried about space, see if we can break this up into two | |
1046 | short instructions, which might eliminate a NOP being inserted. */ | |
1047 | if (optimize_size | |
1048 | && m32r_not_same_reg (operands[0], operands[1]) | |
1049 | && GET_CODE (operands[2]) == CONST_INT | |
1050 | && INT8_P (INTVAL (operands[2]))) | |
1051 | return \"#\"; | |
1052 | ||
1053 | else if (GET_CODE (operands[2]) == CONST_INT) | |
1054 | return \"or3 %0,%1,%#%X2\"; | |
1055 | ||
1056 | return \"or %0,%2\"; | |
1057 | }" | |
5b8ae21f MM |
1058 | [(set_attr "type" "int2,int4") |
1059 | (set_attr "length" "2,4")]) | |
8c5ca3b9 | 1060 | |
56e2e762 NC |
1061 | (define_split |
1062 | [(set (match_operand:SI 0 "register_operand" "") | |
1063 | (ior:SI (match_operand:SI 1 "register_operand" "") | |
1064 | (match_operand:SI 2 "int8_operand" "")))] | |
1065 | "optimize_size && m32r_not_same_reg (operands[0], operands[1])" | |
1066 | [(set (match_dup 0) (match_dup 2)) | |
1067 | (set (match_dup 0) (ior:SI (match_dup 1) (match_dup 0)))] | |
1068 | "") | |
1069 | ||
8c5ca3b9 DE |
1070 | (define_insn "xorsi3" |
1071 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
1072 | (xor:SI (match_operand:SI 1 "register_operand" "%0,r") | |
56e2e762 | 1073 | (match_operand:SI 2 "reg_or_uint16_operand" "r,K")))] |
8c5ca3b9 | 1074 | "" |
56e2e762 NC |
1075 | "* |
1076 | { | |
1077 | /* If we are worried about space, see if we can break this up into two | |
1078 | short instructions, which might eliminate a NOP being inserted. */ | |
1079 | if (optimize_size | |
1080 | && m32r_not_same_reg (operands[0], operands[1]) | |
1081 | && GET_CODE (operands[2]) == CONST_INT | |
1082 | && INT8_P (INTVAL (operands[2]))) | |
1083 | return \"#\"; | |
1084 | ||
1085 | else if (GET_CODE (operands[2]) == CONST_INT) | |
1086 | return \"xor3 %0,%1,%#%X2\"; | |
1087 | ||
1088 | return \"xor %0,%2\"; | |
1089 | }" | |
5b8ae21f MM |
1090 | [(set_attr "type" "int2,int4") |
1091 | (set_attr "length" "2,4")]) | |
8c5ca3b9 | 1092 | |
56e2e762 NC |
1093 | (define_split |
1094 | [(set (match_operand:SI 0 "register_operand" "") | |
1095 | (xor:SI (match_operand:SI 1 "register_operand" "") | |
1096 | (match_operand:SI 2 "int8_operand" "")))] | |
1097 | "optimize_size && m32r_not_same_reg (operands[0], operands[1])" | |
1098 | [(set (match_dup 0) (match_dup 2)) | |
1099 | (set (match_dup 0) (xor:SI (match_dup 1) (match_dup 0)))] | |
1100 | "") | |
1101 | ||
8c5ca3b9 DE |
1102 | (define_insn "negsi2" |
1103 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1104 | (neg:SI (match_operand:SI 1 "register_operand" "r")))] | |
1105 | "" | |
1106 | "neg %0,%1" | |
5b8ae21f MM |
1107 | [(set_attr "type" "int2") |
1108 | (set_attr "length" "2")]) | |
8c5ca3b9 DE |
1109 | |
1110 | (define_insn "one_cmplsi2" | |
1111 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1112 | (not:SI (match_operand:SI 1 "register_operand" "r")))] | |
1113 | "" | |
1114 | "not %0,%1" | |
5b8ae21f MM |
1115 | [(set_attr "type" "int2") |
1116 | (set_attr "length" "2")]) | |
8c5ca3b9 DE |
1117 | \f |
1118 | ;; Shift instructions. | |
1119 | ||
1120 | (define_insn "ashlsi3" | |
1121 | [(set (match_operand:SI 0 "register_operand" "=r,r,r") | |
1122 | (ashift:SI (match_operand:SI 1 "register_operand" "0,0,r") | |
1123 | (match_operand:SI 2 "reg_or_uint16_operand" "r,O,K")))] | |
1124 | "" | |
1125 | "@ | |
1126 | sll %0,%2 | |
1127 | slli %0,%#%2 | |
1128 | sll3 %0,%1,%#%2" | |
5b8ae21f | 1129 | [(set_attr "type" "shift2,shift2,shift4") |
8c5ca3b9 DE |
1130 | (set_attr "length" "2,2,4")]) |
1131 | ||
1132 | (define_insn "ashrsi3" | |
1133 | [(set (match_operand:SI 0 "register_operand" "=r,r,r") | |
1134 | (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r") | |
1135 | (match_operand:SI 2 "reg_or_uint16_operand" "r,O,K")))] | |
1136 | "" | |
1137 | "@ | |
1138 | sra %0,%2 | |
1139 | srai %0,%#%2 | |
1140 | sra3 %0,%1,%#%2" | |
5b8ae21f | 1141 | [(set_attr "type" "shift2,shift2,shift4") |
8c5ca3b9 DE |
1142 | (set_attr "length" "2,2,4")]) |
1143 | ||
1144 | (define_insn "lshrsi3" | |
1145 | [(set (match_operand:SI 0 "register_operand" "=r,r,r") | |
1146 | (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r") | |
1147 | (match_operand:SI 2 "reg_or_uint16_operand" "r,O,K")))] | |
1148 | "" | |
1149 | "@ | |
1150 | srl %0,%2 | |
1151 | srli %0,%#%2 | |
1152 | srl3 %0,%1,%#%2" | |
5b8ae21f | 1153 | [(set_attr "type" "shift2,shift2,shift4") |
8c5ca3b9 DE |
1154 | (set_attr "length" "2,2,4")]) |
1155 | \f | |
1156 | ;; Compare instructions. | |
1157 | ;; This controls RTL generation and register allocation. | |
1158 | ||
1159 | ;; We generate RTL for comparisons and branches by having the cmpxx | |
1160 | ;; patterns store away the operands. Then the bcc patterns | |
1161 | ;; emit RTL for both the compare and the branch. | |
1162 | ;; | |
1163 | ;; On the m32r it is more efficient to use the bxxz instructions and | |
1164 | ;; thus merge the compare and branch into one instruction, so they are | |
4b6bb562 | 1165 | ;; preferred. |
8c5ca3b9 DE |
1166 | |
1167 | (define_expand "cmpsi" | |
51c10c4e | 1168 | [(set (reg:SI 17) |
56e2e762 NC |
1169 | (compare:CC (match_operand:SI 0 "register_operand" "") |
1170 | (match_operand:SI 1 "reg_or_cmp_int16_operand" "")))] | |
8c5ca3b9 DE |
1171 | "" |
1172 | " | |
1173 | { | |
1174 | m32r_compare_op0 = operands[0]; | |
1175 | m32r_compare_op1 = operands[1]; | |
1176 | DONE; | |
1177 | }") | |
1178 | ||
de41e41c BE |
1179 | (define_insn "cmp_eqsi_zero_insn" |
1180 | [(set (reg:SI 17) | |
1181 | (eq:SI (match_operand:SI 0 "register_operand" "r,r") | |
1182 | (match_operand:SI 1 "reg_or_zero_operand" "r,P")))] | |
1183 | "TARGET_M32RX" | |
1184 | "@ | |
1185 | cmpeq %0, %1 | |
1186 | cmpz %0" | |
1187 | [(set_attr "type" "int4") | |
1188 | (set_attr "length" "4")]) | |
1189 | ||
8c5ca3b9 DE |
1190 | ;; The cmp_xxx_insn patterns set the condition bit to the result of the |
1191 | ;; comparison. There isn't a "compare equal" instruction so cmp_eqsi_insn | |
1192 | ;; is quite inefficient. However, it is rarely used. | |
1193 | ||
1194 | (define_insn "cmp_eqsi_insn" | |
51c10c4e | 1195 | [(set (reg:SI 17) |
de41e41c BE |
1196 | (eq:SI (match_operand:SI 0 "register_operand" "r,r") |
1197 | (match_operand:SI 1 "reg_or_cmp_int16_operand" "r,P"))) | |
8c5ca3b9 | 1198 | (clobber (match_scratch:SI 2 "=&r,&r"))] |
2b7972b0 MM |
1199 | "" |
1200 | "* | |
1201 | { | |
1202 | if (which_alternative == 0) | |
1203 | { | |
1204 | return \"mv %2,%0\;sub %2,%1\;cmpui %2,#1\"; | |
1205 | } | |
1206 | else | |
1207 | { | |
1208 | if (INTVAL (operands [1]) == 0) | |
1209 | return \"cmpui %0, #1\"; | |
1210 | else if (REGNO (operands [2]) == REGNO (operands [0])) | |
1211 | return \"addi %0,%#%N1\;cmpui %2,#1\"; | |
1212 | else | |
1213 | return \"add3 %2,%0,%#%N1\;cmpui %2,#1\"; | |
1214 | } | |
1215 | }" | |
5b8ae21f | 1216 | [(set_attr "type" "multi,multi") |
8c5ca3b9 DE |
1217 | (set_attr "length" "8,8")]) |
1218 | ||
1219 | (define_insn "cmp_ltsi_insn" | |
51c10c4e | 1220 | [(set (reg:SI 17) |
de41e41c BE |
1221 | (lt:SI (match_operand:SI 0 "register_operand" "r,r") |
1222 | (match_operand:SI 1 "reg_or_int16_operand" "r,J")))] | |
8c5ca3b9 DE |
1223 | "" |
1224 | "@ | |
1225 | cmp %0,%1 | |
1226 | cmpi %0,%#%1" | |
5b8ae21f MM |
1227 | [(set_attr "type" "int2,int4") |
1228 | (set_attr "length" "2,4")]) | |
8c5ca3b9 DE |
1229 | |
1230 | (define_insn "cmp_ltusi_insn" | |
51c10c4e | 1231 | [(set (reg:SI 17) |
de41e41c BE |
1232 | (ltu:SI (match_operand:SI 0 "register_operand" "r,r") |
1233 | (match_operand:SI 1 "reg_or_int16_operand" "r,J")))] | |
8c5ca3b9 | 1234 | "" |
5b8ae21f MM |
1235 | "@ |
1236 | cmpu %0,%1 | |
1237 | cmpui %0,%#%1" | |
1238 | [(set_attr "type" "int2,int4") | |
1239 | (set_attr "length" "2,4")]) | |
8c5ca3b9 | 1240 | |
de41e41c | 1241 | |
8c5ca3b9 DE |
1242 | ;; reg == small constant comparisons are best handled by putting the result |
1243 | ;; of the comparison in a tmp reg and then using beqz/bnez. | |
1244 | ;; ??? The result register doesn't contain 0/STORE_FLAG_VALUE, | |
1245 | ;; it contains 0/non-zero. | |
1246 | ||
1247 | (define_insn "cmp_ne_small_const_insn" | |
2b7972b0 MM |
1248 | [(set (match_operand:SI 0 "register_operand" "=r,r") |
1249 | (ne:SI (match_operand:SI 1 "register_operand" "0,r") | |
5b8ae21f | 1250 | (match_operand:SI 2 "cmp_int16_operand" "N,P")))] |
8c5ca3b9 | 1251 | "" |
2b7972b0 MM |
1252 | "@ |
1253 | addi %0,%#%N2 | |
1254 | add3 %0,%1,%#%N2" | |
5b8ae21f | 1255 | [(set_attr "type" "int2,int4") |
2b7972b0 | 1256 | (set_attr "length" "2,4")]) |
8c5ca3b9 DE |
1257 | \f |
1258 | ;; These control RTL generation for conditional jump insns. | |
1259 | ||
1260 | (define_expand "beq" | |
1261 | [(set (pc) | |
1262 | (if_then_else (match_dup 1) | |
1263 | (label_ref (match_operand 0 "" "")) | |
1264 | (pc)))] | |
1265 | "" | |
1266 | " | |
1267 | { | |
56e2e762 | 1268 | operands[1] = gen_compare (EQ, m32r_compare_op0, m32r_compare_op1, FALSE); |
8c5ca3b9 DE |
1269 | }") |
1270 | ||
1271 | (define_expand "bne" | |
1272 | [(set (pc) | |
1273 | (if_then_else (match_dup 1) | |
1274 | (label_ref (match_operand 0 "" "")) | |
1275 | (pc)))] | |
1276 | "" | |
1277 | " | |
1278 | { | |
56e2e762 | 1279 | operands[1] = gen_compare (NE, m32r_compare_op0, m32r_compare_op1, FALSE); |
8c5ca3b9 DE |
1280 | }") |
1281 | ||
1282 | (define_expand "bgt" | |
1283 | [(set (pc) | |
1284 | (if_then_else (match_dup 1) | |
1285 | (label_ref (match_operand 0 "" "")) | |
1286 | (pc)))] | |
1287 | "" | |
1288 | " | |
1289 | { | |
56e2e762 | 1290 | operands[1] = gen_compare (GT, m32r_compare_op0, m32r_compare_op1, FALSE); |
8c5ca3b9 DE |
1291 | }") |
1292 | ||
1293 | (define_expand "ble" | |
1294 | [(set (pc) | |
1295 | (if_then_else (match_dup 1) | |
1296 | (label_ref (match_operand 0 "" "")) | |
1297 | (pc)))] | |
1298 | "" | |
1299 | " | |
1300 | { | |
56e2e762 | 1301 | operands[1] = gen_compare (LE, m32r_compare_op0, m32r_compare_op1, FALSE); |
8c5ca3b9 DE |
1302 | }") |
1303 | ||
1304 | (define_expand "bge" | |
1305 | [(set (pc) | |
1306 | (if_then_else (match_dup 1) | |
1307 | (label_ref (match_operand 0 "" "")) | |
1308 | (pc)))] | |
1309 | "" | |
1310 | " | |
1311 | { | |
56e2e762 | 1312 | operands[1] = gen_compare (GE, m32r_compare_op0, m32r_compare_op1, FALSE); |
8c5ca3b9 DE |
1313 | }") |
1314 | ||
1315 | (define_expand "blt" | |
1316 | [(set (pc) | |
1317 | (if_then_else (match_dup 1) | |
1318 | (label_ref (match_operand 0 "" "")) | |
1319 | (pc)))] | |
1320 | "" | |
1321 | " | |
1322 | { | |
56e2e762 | 1323 | operands[1] = gen_compare (LT, m32r_compare_op0, m32r_compare_op1, FALSE); |
8c5ca3b9 DE |
1324 | }") |
1325 | ||
1326 | (define_expand "bgtu" | |
1327 | [(set (pc) | |
1328 | (if_then_else (match_dup 1) | |
1329 | (label_ref (match_operand 0 "" "")) | |
1330 | (pc)))] | |
1331 | "" | |
1332 | " | |
1333 | { | |
56e2e762 | 1334 | operands[1] = gen_compare (GTU, m32r_compare_op0, m32r_compare_op1, FALSE); |
8c5ca3b9 DE |
1335 | }") |
1336 | ||
1337 | (define_expand "bleu" | |
1338 | [(set (pc) | |
1339 | (if_then_else (match_dup 1) | |
1340 | (label_ref (match_operand 0 "" "")) | |
1341 | (pc)))] | |
1342 | "" | |
1343 | " | |
1344 | { | |
56e2e762 | 1345 | operands[1] = gen_compare (LEU, m32r_compare_op0, m32r_compare_op1, FALSE); |
8c5ca3b9 DE |
1346 | }") |
1347 | ||
1348 | (define_expand "bgeu" | |
1349 | [(set (pc) | |
1350 | (if_then_else (match_dup 1) | |
1351 | (label_ref (match_operand 0 "" "")) | |
1352 | (pc)))] | |
1353 | "" | |
1354 | " | |
1355 | { | |
56e2e762 | 1356 | operands[1] = gen_compare (GEU, m32r_compare_op0, m32r_compare_op1, FALSE); |
8c5ca3b9 DE |
1357 | }") |
1358 | ||
1359 | (define_expand "bltu" | |
1360 | [(set (pc) | |
1361 | (if_then_else (match_dup 1) | |
1362 | (label_ref (match_operand 0 "" "")) | |
1363 | (pc)))] | |
1364 | "" | |
1365 | " | |
1366 | { | |
56e2e762 | 1367 | operands[1] = gen_compare (LTU, m32r_compare_op0, m32r_compare_op1, FALSE); |
8c5ca3b9 DE |
1368 | }") |
1369 | ||
1370 | ;; Now match both normal and inverted jump. | |
1371 | ||
1372 | (define_insn "*branch_insn" | |
1373 | [(set (pc) | |
1374 | (if_then_else (match_operator 1 "eqne_comparison_operator" | |
1375 | [(reg 17) (const_int 0)]) | |
1376 | (label_ref (match_operand 0 "" "")) | |
1377 | (pc)))] | |
1378 | "" | |
1379 | "* | |
1380 | { | |
2b7972b0 MM |
1381 | static char instruction[40]; |
1382 | sprintf (instruction, \"%s%s %%l0\", | |
1383 | (GET_CODE (operands[1]) == NE) ? \"bc\" : \"bnc\", | |
1384 | (get_attr_length (insn) == 2) ? \".s\" : \"\"); | |
1385 | return instruction; | |
8c5ca3b9 DE |
1386 | }" |
1387 | [(set_attr "type" "branch") | |
1388 | ; We use 400/800 instead of 512,1024 to account for inaccurate insn | |
1389 | ; lengths and insn alignments that are complex to track. | |
1390 | ; It's not important that we be hyper-precise here. It may be more | |
1391 | ; important blah blah blah when the chip supports parallel execution | |
1392 | ; blah blah blah but until then blah blah blah this is simple and | |
1393 | ; suffices. | |
1394 | (set (attr "length") (if_then_else (ltu (plus (minus (match_dup 0) (pc)) | |
1395 | (const_int 400)) | |
1396 | (const_int 800)) | |
1397 | (const_int 2) | |
1398 | (const_int 4)))]) | |
1399 | ||
1400 | (define_insn "*rev_branch_insn" | |
1401 | [(set (pc) | |
1402 | (if_then_else (match_operator 1 "eqne_comparison_operator" | |
1403 | [(reg 17) (const_int 0)]) | |
1404 | (pc) | |
1405 | (label_ref (match_operand 0 "" ""))))] | |
1406 | ;"REVERSIBLE_CC_MODE (GET_MODE (XEXP (operands[1], 0)))" | |
1407 | "" | |
1408 | "* | |
1409 | { | |
2b7972b0 MM |
1410 | static char instruction[40]; |
1411 | sprintf (instruction, \"%s%s %%l0\", | |
1412 | (GET_CODE (operands[1]) == EQ) ? \"bc\" : \"bnc\", | |
1413 | (get_attr_length (insn) == 2) ? \".s\" : \"\"); | |
1414 | return instruction; | |
8c5ca3b9 DE |
1415 | }" |
1416 | [(set_attr "type" "branch") | |
1417 | ; We use 400/800 instead of 512,1024 to account for inaccurate insn | |
1418 | ; lengths and insn alignments that are complex to track. | |
1419 | ; It's not important that we be hyper-precise here. It may be more | |
1420 | ; important blah blah blah when the chip supports parallel execution | |
1421 | ; blah blah blah but until then blah blah blah this is simple and | |
1422 | ; suffices. | |
1423 | (set (attr "length") (if_then_else (ltu (plus (minus (match_dup 0) (pc)) | |
1424 | (const_int 400)) | |
1425 | (const_int 800)) | |
1426 | (const_int 2) | |
1427 | (const_int 4)))]) | |
1428 | ||
1429 | ; reg/reg compare and branch insns | |
1430 | ||
1431 | (define_insn "*reg_branch_insn" | |
1432 | [(set (pc) | |
1433 | (if_then_else (match_operator 1 "eqne_comparison_operator" | |
1434 | [(match_operand:SI 2 "register_operand" "r") | |
1435 | (match_operand:SI 3 "register_operand" "r")]) | |
1436 | (label_ref (match_operand 0 "" "")) | |
1437 | (pc)))] | |
1438 | "" | |
1439 | "* | |
1440 | { | |
1441 | /* Is branch target reachable with beq/bne? */ | |
1442 | if (get_attr_length (insn) == 4) | |
1443 | { | |
1444 | if (GET_CODE (operands[1]) == EQ) | |
1445 | return \"beq %2,%3,%l0\"; | |
1446 | else | |
1447 | return \"bne %2,%3,%l0\"; | |
1448 | } | |
1449 | else | |
1450 | { | |
1451 | if (GET_CODE (operands[1]) == EQ) | |
1452 | return \"bne %2,%3,1f\;bra %l0\;1:\"; | |
1453 | else | |
1454 | return \"beq %2,%3,1f\;bra %l0\;1:\"; | |
1455 | } | |
1456 | }" | |
1457 | [(set_attr "type" "branch") | |
1458 | ; We use 25000/50000 instead of 32768/65536 to account for slot filling | |
1459 | ; which is complex to track and inaccurate length specs. | |
1460 | (set (attr "length") (if_then_else (ltu (plus (minus (match_dup 0) (pc)) | |
1461 | (const_int 25000)) | |
1462 | (const_int 50000)) | |
1463 | (const_int 4) | |
1464 | (const_int 8)))]) | |
1465 | ||
1466 | (define_insn "*rev_reg_branch_insn" | |
1467 | [(set (pc) | |
1468 | (if_then_else (match_operator 1 "eqne_comparison_operator" | |
1469 | [(match_operand:SI 2 "register_operand" "r") | |
1470 | (match_operand:SI 3 "register_operand" "r")]) | |
1471 | (pc) | |
1472 | (label_ref (match_operand 0 "" ""))))] | |
1473 | "" | |
1474 | "* | |
1475 | { | |
1476 | /* Is branch target reachable with beq/bne? */ | |
1477 | if (get_attr_length (insn) == 4) | |
1478 | { | |
1479 | if (GET_CODE (operands[1]) == NE) | |
1480 | return \"beq %2,%3,%l0\"; | |
1481 | else | |
1482 | return \"bne %2,%3,%l0\"; | |
1483 | } | |
1484 | else | |
1485 | { | |
1486 | if (GET_CODE (operands[1]) == NE) | |
1487 | return \"bne %2,%3,1f\;bra %l0\;1:\"; | |
1488 | else | |
1489 | return \"beq %2,%3,1f\;bra %l0\;1:\"; | |
1490 | } | |
1491 | }" | |
1492 | [(set_attr "type" "branch") | |
1493 | ; We use 25000/50000 instead of 32768/65536 to account for slot filling | |
1494 | ; which is complex to track and inaccurate length specs. | |
1495 | (set (attr "length") (if_then_else (ltu (plus (minus (match_dup 0) (pc)) | |
1496 | (const_int 25000)) | |
1497 | (const_int 50000)) | |
1498 | (const_int 4) | |
1499 | (const_int 8)))]) | |
1500 | ||
1501 | ; reg/zero compare and branch insns | |
1502 | ||
1503 | (define_insn "*zero_branch_insn" | |
1504 | [(set (pc) | |
1505 | (if_then_else (match_operator 1 "signed_comparison_operator" | |
1506 | [(match_operand:SI 2 "register_operand" "r") | |
1507 | (const_int 0)]) | |
1508 | (label_ref (match_operand 0 "" "")) | |
1509 | (pc)))] | |
1510 | "" | |
1511 | "* | |
1512 | { | |
de41e41c | 1513 | char *br,*invbr; |
8c5ca3b9 DE |
1514 | char asmtext[40]; |
1515 | ||
1516 | switch (GET_CODE (operands[1])) | |
1517 | { | |
1518 | case EQ : br = \"eq\"; invbr = \"ne\"; break; | |
1519 | case NE : br = \"ne\"; invbr = \"eq\"; break; | |
1520 | case LE : br = \"le\"; invbr = \"gt\"; break; | |
1521 | case GT : br = \"gt\"; invbr = \"le\"; break; | |
1522 | case LT : br = \"lt\"; invbr = \"ge\"; break; | |
1523 | case GE : br = \"ge\"; invbr = \"lt\"; break; | |
61f3b78f RH |
1524 | |
1525 | default: abort(); | |
8c5ca3b9 DE |
1526 | } |
1527 | ||
1528 | /* Is branch target reachable with bxxz? */ | |
1529 | if (get_attr_length (insn) == 4) | |
1530 | { | |
1531 | sprintf (asmtext, \"b%sz %%2,%%l0\", br); | |
1532 | output_asm_insn (asmtext, operands); | |
1533 | } | |
1534 | else | |
1535 | { | |
1536 | sprintf (asmtext, \"b%sz %%2,1f\;bra %%l0\;1:\", invbr); | |
1537 | output_asm_insn (asmtext, operands); | |
1538 | } | |
1539 | return \"\"; | |
1540 | }" | |
1541 | [(set_attr "type" "branch") | |
1542 | ; We use 25000/50000 instead of 32768/65536 to account for slot filling | |
1543 | ; which is complex to track and inaccurate length specs. | |
1544 | (set (attr "length") (if_then_else (ltu (plus (minus (match_dup 0) (pc)) | |
1545 | (const_int 25000)) | |
1546 | (const_int 50000)) | |
1547 | (const_int 4) | |
1548 | (const_int 8)))]) | |
1549 | ||
1550 | (define_insn "*rev_zero_branch_insn" | |
1551 | [(set (pc) | |
1552 | (if_then_else (match_operator 1 "eqne_comparison_operator" | |
1553 | [(match_operand:SI 2 "register_operand" "r") | |
1554 | (const_int 0)]) | |
1555 | (pc) | |
1556 | (label_ref (match_operand 0 "" ""))))] | |
1557 | "" | |
1558 | "* | |
1559 | { | |
de41e41c | 1560 | char *br,*invbr; |
8c5ca3b9 DE |
1561 | char asmtext[40]; |
1562 | ||
1563 | switch (GET_CODE (operands[1])) | |
1564 | { | |
1565 | case EQ : br = \"eq\"; invbr = \"ne\"; break; | |
1566 | case NE : br = \"ne\"; invbr = \"eq\"; break; | |
1567 | case LE : br = \"le\"; invbr = \"gt\"; break; | |
1568 | case GT : br = \"gt\"; invbr = \"le\"; break; | |
1569 | case LT : br = \"lt\"; invbr = \"ge\"; break; | |
1570 | case GE : br = \"ge\"; invbr = \"lt\"; break; | |
61f3b78f RH |
1571 | |
1572 | default: abort(); | |
8c5ca3b9 DE |
1573 | } |
1574 | ||
1575 | /* Is branch target reachable with bxxz? */ | |
1576 | if (get_attr_length (insn) == 4) | |
1577 | { | |
1578 | sprintf (asmtext, \"b%sz %%2,%%l0\", invbr); | |
1579 | output_asm_insn (asmtext, operands); | |
1580 | } | |
1581 | else | |
1582 | { | |
1583 | sprintf (asmtext, \"b%sz %%2,1f\;bra %%l0\;1:\", br); | |
1584 | output_asm_insn (asmtext, operands); | |
1585 | } | |
1586 | return \"\"; | |
1587 | }" | |
1588 | [(set_attr "type" "branch") | |
1589 | ; We use 25000/50000 instead of 32768/65536 to account for slot filling | |
1590 | ; which is complex to track and inaccurate length specs. | |
1591 | (set (attr "length") (if_then_else (ltu (plus (minus (match_dup 0) (pc)) | |
1592 | (const_int 25000)) | |
1593 | (const_int 50000)) | |
1594 | (const_int 4) | |
1595 | (const_int 8)))]) | |
1596 | \f | |
56e2e762 NC |
1597 | ;; S<cc> operations to set a register to 1/0 based on a comparison |
1598 | ||
1599 | (define_expand "seq" | |
1600 | [(match_operand:SI 0 "register_operand" "")] | |
1601 | "" | |
1602 | " | |
1603 | { | |
1604 | rtx op0 = operands[0]; | |
1605 | rtx op1 = m32r_compare_op0; | |
1606 | rtx op2 = m32r_compare_op1; | |
1607 | enum machine_mode mode = GET_MODE (op0); | |
1608 | ||
1609 | if (mode != SImode) | |
1610 | FAIL; | |
1611 | ||
1612 | if (! register_operand (op1, mode)) | |
1613 | op1 = force_reg (mode, op1); | |
1614 | ||
de41e41c BE |
1615 | if (TARGET_M32RX) |
1616 | { | |
1617 | if (! reg_or_zero_operand (op2, mode)) | |
1618 | op2 = force_reg (mode, op2); | |
1619 | ||
1620 | emit_insn (gen_seq_insn_m32rx (op0, op1, op2)); | |
1621 | DONE; | |
1622 | } | |
56e2e762 NC |
1623 | if (GET_CODE (op2) == CONST_INT && INTVAL (op2) == 0) |
1624 | { | |
1625 | emit_insn (gen_seq_zero_insn (op0, op1)); | |
1626 | DONE; | |
1627 | } | |
1628 | ||
1629 | if (! reg_or_eq_int16_operand (op2, mode)) | |
1630 | op2 = force_reg (mode, op2); | |
1631 | ||
1632 | emit_insn (gen_seq_insn (op0, op1, op2)); | |
1633 | DONE; | |
1634 | }") | |
1635 | ||
de41e41c BE |
1636 | (define_insn "seq_insn_m32rx" |
1637 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1638 | (eq:SI (match_operand:SI 1 "register_operand" "%r") | |
1639 | (match_operand:SI 2 "reg_or_zero_operand" "rP"))) | |
1640 | (clobber (reg:SI 17))] | |
1641 | "TARGET_M32RX" | |
1642 | "#" | |
1643 | [(set_attr "type" "multi") | |
1644 | (set_attr "length" "6")]) | |
1645 | ||
1646 | (define_split | |
1647 | [(set (match_operand:SI 0 "register_operand" "") | |
1648 | (eq:SI (match_operand:SI 1 "register_operand" "") | |
1649 | (match_operand:SI 2 "reg_or_zero_operand" ""))) | |
1650 | (clobber (reg:SI 17))] | |
1651 | "TARGET_M32RX" | |
1652 | [(set (reg:SI 17) | |
1653 | (eq:SI (match_dup 1) | |
1654 | (match_dup 2))) | |
1655 | (set (match_dup 0) | |
1656 | (reg:SI 17))] | |
1657 | "") | |
1658 | ||
56e2e762 NC |
1659 | (define_insn "seq_zero_insn" |
1660 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1661 | (eq:SI (match_operand:SI 1 "register_operand" "r") | |
1662 | (const_int 0))) | |
1663 | (clobber (reg:SI 17))] | |
1664 | "TARGET_M32R" | |
1665 | "#" | |
1666 | [(set_attr "type" "multi") | |
1667 | (set_attr "length" "6")]) | |
1668 | ||
1669 | (define_split | |
1670 | [(set (match_operand:SI 0 "register_operand" "") | |
1671 | (eq:SI (match_operand:SI 1 "register_operand" "") | |
1672 | (const_int 0))) | |
1673 | (clobber (reg:SI 17))] | |
1674 | "TARGET_M32R" | |
1675 | [(match_dup 3)] | |
1676 | " | |
1677 | { | |
1678 | rtx op0 = operands[0]; | |
1679 | rtx op1 = operands[1]; | |
1680 | ||
1681 | start_sequence (); | |
1682 | emit_insn (gen_cmp_ltusi_insn (op1, GEN_INT (1))); | |
1683 | emit_insn (gen_movcc_insn (op0)); | |
1684 | operands[3] = gen_sequence (); | |
1685 | end_sequence (); | |
1686 | }") | |
1687 | ||
1688 | (define_insn "seq_insn" | |
1689 | [(set (match_operand:SI 0 "register_operand" "=r,r,??r,r") | |
1690 | (eq:SI (match_operand:SI 1 "register_operand" "r,r,r,r") | |
1691 | (match_operand:SI 2 "reg_or_eq_int16_operand" "r,r,r,PK"))) | |
1692 | (clobber (reg:SI 17)) | |
1693 | (clobber (match_scratch:SI 3 "=1,2,&r,r"))] | |
1694 | "TARGET_M32R" | |
1695 | "#" | |
1696 | [(set_attr "type" "multi") | |
1697 | (set_attr "length" "8,8,10,10")]) | |
1698 | ||
1699 | (define_split | |
1700 | [(set (match_operand:SI 0 "register_operand" "") | |
1701 | (eq:SI (match_operand:SI 1 "register_operand" "") | |
1702 | (match_operand:SI 2 "reg_or_eq_int16_operand" ""))) | |
1703 | (clobber (reg:SI 17)) | |
1704 | (clobber (match_scratch:SI 3 ""))] | |
1705 | "TARGET_M32R && reload_completed" | |
1706 | [(match_dup 4)] | |
1707 | " | |
1708 | { | |
1709 | rtx op0 = operands[0]; | |
1710 | rtx op1 = operands[1]; | |
1711 | rtx op2 = operands[2]; | |
1712 | rtx op3 = operands[3]; | |
1713 | HOST_WIDE_INT value; | |
1714 | ||
1715 | if (GET_CODE (op2) == REG && GET_CODE (op3) == REG | |
1716 | && REGNO (op2) == REGNO (op3)) | |
1717 | { | |
1718 | op1 = operands[2]; | |
1719 | op2 = operands[1]; | |
1720 | } | |
1721 | ||
1722 | start_sequence (); | |
1723 | if (GET_CODE (op1) == REG && GET_CODE (op3) == REG | |
1724 | && REGNO (op1) != REGNO (op3)) | |
1725 | { | |
1726 | emit_move_insn (op3, op1); | |
1727 | op1 = op3; | |
1728 | } | |
1729 | ||
1730 | if (GET_CODE (op2) == CONST_INT && (value = INTVAL (op2)) != 0 | |
1731 | && CMP_INT16_P (value)) | |
1732 | emit_insn (gen_addsi3 (op3, op1, GEN_INT (-value))); | |
1733 | else | |
1734 | emit_insn (gen_xorsi3 (op3, op1, op2)); | |
1735 | ||
1736 | emit_insn (gen_cmp_ltusi_insn (op3, GEN_INT (1))); | |
1737 | emit_insn (gen_movcc_insn (op0)); | |
1738 | operands[4] = gen_sequence (); | |
1739 | end_sequence (); | |
1740 | }") | |
1741 | ||
1742 | (define_expand "sne" | |
1743 | [(match_operand:SI 0 "register_operand" "")] | |
1744 | "" | |
1745 | " | |
1746 | { | |
1747 | rtx op0 = operands[0]; | |
1748 | rtx op1 = m32r_compare_op0; | |
1749 | rtx op2 = m32r_compare_op1; | |
1750 | enum machine_mode mode = GET_MODE (op0); | |
1751 | ||
1752 | if (mode != SImode) | |
1753 | FAIL; | |
1754 | ||
1755 | if (GET_CODE (op2) != CONST_INT | |
1756 | || (INTVAL (op2) != 0 && UINT16_P (INTVAL (op2)))) | |
1757 | { | |
1758 | rtx reg; | |
1759 | ||
1760 | if (reload_completed || reload_in_progress) | |
1761 | FAIL; | |
1762 | ||
1763 | reg = gen_reg_rtx (SImode); | |
1764 | emit_insn (gen_xorsi3 (reg, op1, op2)); | |
1765 | op1 = reg; | |
1766 | ||
1767 | if (! register_operand (op1, mode)) | |
1768 | op1 = force_reg (mode, op1); | |
1769 | ||
1770 | emit_insn (gen_sne_zero_insn (op0, op1)); | |
1771 | DONE; | |
1772 | } | |
1773 | else | |
1774 | FAIL; | |
1775 | }") | |
1776 | ||
1777 | (define_insn "sne_zero_insn" | |
1778 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1779 | (ne:SI (match_operand:SI 1 "register_operand" "r") | |
1780 | (const_int 0))) | |
1781 | (clobber (reg:SI 17)) | |
1782 | (clobber (match_scratch:SI 2 "=&r"))] | |
1783 | "" | |
1784 | "#" | |
1785 | [(set_attr "type" "multi") | |
1786 | (set_attr "length" "6")]) | |
1787 | ||
1788 | (define_split | |
1789 | [(set (match_operand:SI 0 "register_operand" "") | |
1790 | (ne:SI (match_operand:SI 1 "register_operand" "") | |
1791 | (const_int 0))) | |
1792 | (clobber (reg:SI 17)) | |
1793 | (clobber (match_scratch:SI 2 ""))] | |
1794 | "reload_completed" | |
1795 | [(set (match_dup 2) | |
1796 | (const_int 0)) | |
1797 | (set (reg:SI 17) | |
1798 | (ltu:SI (match_dup 2) | |
1799 | (match_dup 1))) | |
1800 | (set (match_dup 0) | |
1801 | (reg:SI 17))] | |
1802 | "") | |
1803 | ||
1804 | (define_expand "slt" | |
1805 | [(match_operand:SI 0 "register_operand" "")] | |
1806 | "" | |
1807 | " | |
1808 | { | |
1809 | rtx op0 = operands[0]; | |
1810 | rtx op1 = m32r_compare_op0; | |
1811 | rtx op2 = m32r_compare_op1; | |
1812 | enum machine_mode mode = GET_MODE (op0); | |
1813 | ||
1814 | if (mode != SImode) | |
1815 | FAIL; | |
1816 | ||
1817 | if (! register_operand (op1, mode)) | |
1818 | op1 = force_reg (mode, op1); | |
1819 | ||
1820 | if (! reg_or_int16_operand (op2, mode)) | |
1821 | op2 = force_reg (mode, op2); | |
1822 | ||
1823 | emit_insn (gen_slt_insn (op0, op1, op2)); | |
1824 | DONE; | |
1825 | }") | |
1826 | ||
1827 | (define_insn "slt_insn" | |
1828 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
1829 | (lt:SI (match_operand:SI 1 "register_operand" "r,r") | |
1830 | (match_operand:SI 2 "reg_or_int16_operand" "r,J"))) | |
1831 | (clobber (reg:SI 17))] | |
1832 | "" | |
1833 | "#" | |
1834 | [(set_attr "type" "multi") | |
1835 | (set_attr "length" "4,6")]) | |
1836 | ||
1837 | (define_split | |
1838 | [(set (match_operand:SI 0 "register_operand" "") | |
1839 | (lt:SI (match_operand:SI 1 "register_operand" "") | |
1840 | (match_operand:SI 2 "reg_or_int16_operand" ""))) | |
1841 | (clobber (reg:SI 17))] | |
1842 | "" | |
1843 | [(set (reg:SI 17) | |
1844 | (lt:SI (match_dup 1) | |
1845 | (match_dup 2))) | |
1846 | (set (match_dup 0) | |
1847 | (reg:SI 17))] | |
1848 | "") | |
1849 | ||
1850 | (define_expand "sle" | |
1851 | [(match_operand:SI 0 "register_operand" "")] | |
1852 | "" | |
1853 | " | |
1854 | { | |
1855 | rtx op0 = operands[0]; | |
1856 | rtx op1 = m32r_compare_op0; | |
1857 | rtx op2 = m32r_compare_op1; | |
1858 | enum machine_mode mode = GET_MODE (op0); | |
1859 | ||
1860 | if (mode != SImode) | |
1861 | FAIL; | |
1862 | ||
1863 | if (! register_operand (op1, mode)) | |
1864 | op1 = force_reg (mode, op1); | |
1865 | ||
1866 | if (GET_CODE (op2) == CONST_INT) | |
1867 | { | |
1868 | HOST_WIDE_INT value = INTVAL (op2); | |
1869 | if (value >= 2147483647) | |
1870 | { | |
1871 | emit_move_insn (op0, GEN_INT (1)); | |
1872 | DONE; | |
1873 | } | |
1874 | ||
1875 | op2 = GEN_INT (value+1); | |
1876 | if (value < -32768 || value >= 32767) | |
1877 | op2 = force_reg (mode, op2); | |
1878 | ||
1879 | emit_insn (gen_slt_insn (op0, op1, op2)); | |
1880 | DONE; | |
1881 | } | |
1882 | ||
1883 | if (! register_operand (op2, mode)) | |
1884 | op2 = force_reg (mode, op2); | |
1885 | ||
1886 | emit_insn (gen_sle_insn (op0, op1, op2)); | |
1887 | DONE; | |
1888 | }") | |
1889 | ||
1890 | (define_insn "sle_insn" | |
1891 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1892 | (le:SI (match_operand:SI 1 "register_operand" "r") | |
1893 | (match_operand:SI 2 "register_operand" "r"))) | |
1894 | (clobber (reg:SI 17))] | |
1895 | "" | |
1896 | "#" | |
1897 | [(set_attr "type" "multi") | |
1898 | (set_attr "length" "8")]) | |
1899 | ||
1900 | (define_split | |
1901 | [(set (match_operand:SI 0 "register_operand" "") | |
1902 | (le:SI (match_operand:SI 1 "register_operand" "") | |
1903 | (match_operand:SI 2 "register_operand" ""))) | |
1904 | (clobber (reg:SI 17))] | |
1905 | "!optimize_size" | |
1906 | [(set (reg:SI 17) | |
1907 | (lt:SI (match_dup 2) | |
1908 | (match_dup 1))) | |
1909 | (set (match_dup 0) | |
1910 | (reg:SI 17)) | |
1911 | (set (match_dup 0) | |
1912 | (xor:SI (match_dup 0) | |
1913 | (const_int 1)))] | |
1914 | "") | |
1915 | ||
1916 | ;; If optimizing for space, use -(reg - 1) to invert the comparison rather than | |
1917 | ;; xor reg,reg,1 which might eliminate a NOP being inserted. | |
1918 | (define_split | |
1919 | [(set (match_operand:SI 0 "register_operand" "") | |
1920 | (le:SI (match_operand:SI 1 "register_operand" "") | |
1921 | (match_operand:SI 2 "register_operand" ""))) | |
1922 | (clobber (reg:SI 17))] | |
1923 | "optimize_size" | |
1924 | [(set (reg:SI 17) | |
1925 | (lt:SI (match_dup 2) | |
1926 | (match_dup 1))) | |
1927 | (set (match_dup 0) | |
1928 | (reg:SI 17)) | |
1929 | (set (match_dup 0) | |
1930 | (plus:SI (match_dup 0) | |
1931 | (const_int -1))) | |
1932 | (set (match_dup 0) | |
1933 | (neg:SI (match_dup 0)))] | |
1934 | "") | |
1935 | ||
1936 | (define_expand "sgt" | |
1937 | [(match_operand:SI 0 "register_operand" "")] | |
1938 | "" | |
1939 | " | |
1940 | { | |
1941 | rtx op0 = operands[0]; | |
1942 | rtx op1 = m32r_compare_op0; | |
1943 | rtx op2 = m32r_compare_op1; | |
1944 | enum machine_mode mode = GET_MODE (op0); | |
1945 | ||
1946 | if (mode != SImode) | |
1947 | FAIL; | |
1948 | ||
1949 | if (! register_operand (op1, mode)) | |
1950 | op1 = force_reg (mode, op1); | |
1951 | ||
1952 | if (! register_operand (op2, mode)) | |
1953 | op2 = force_reg (mode, op2); | |
1954 | ||
1955 | emit_insn (gen_slt_insn (op0, op2, op1)); | |
1956 | DONE; | |
1957 | }") | |
1958 | ||
1959 | (define_expand "sge" | |
1960 | [(match_operand:SI 0 "register_operand" "")] | |
1961 | "" | |
1962 | " | |
1963 | { | |
1964 | rtx op0 = operands[0]; | |
1965 | rtx op1 = m32r_compare_op0; | |
1966 | rtx op2 = m32r_compare_op1; | |
1967 | enum machine_mode mode = GET_MODE (op0); | |
1968 | ||
1969 | if (mode != SImode) | |
1970 | FAIL; | |
1971 | ||
1972 | if (! register_operand (op1, mode)) | |
1973 | op1 = force_reg (mode, op1); | |
1974 | ||
1975 | if (! reg_or_int16_operand (op2, mode)) | |
1976 | op2 = force_reg (mode, op2); | |
1977 | ||
1978 | emit_insn (gen_sge_insn (op0, op1, op2)); | |
1979 | DONE; | |
1980 | }") | |
1981 | ||
1982 | (define_insn "sge_insn" | |
1983 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
1984 | (ge:SI (match_operand:SI 1 "register_operand" "r,r") | |
1985 | (match_operand:SI 2 "reg_or_int16_operand" "r,J"))) | |
1986 | (clobber (reg:SI 17))] | |
1987 | "" | |
1988 | "#" | |
1989 | [(set_attr "type" "multi") | |
1990 | (set_attr "length" "8,10")]) | |
1991 | ||
1992 | (define_split | |
1993 | [(set (match_operand:SI 0 "register_operand" "") | |
1994 | (ge:SI (match_operand:SI 1 "register_operand" "") | |
1995 | (match_operand:SI 2 "reg_or_int16_operand" ""))) | |
1996 | (clobber (reg:SI 17))] | |
1997 | "!optimize_size" | |
1998 | [(set (reg:SI 17) | |
1999 | (lt:SI (match_dup 1) | |
2000 | (match_dup 2))) | |
2001 | (set (match_dup 0) | |
2002 | (reg:SI 17)) | |
2003 | (set (match_dup 0) | |
2004 | (xor:SI (match_dup 0) | |
2005 | (const_int 1)))] | |
2006 | "") | |
2007 | ||
2008 | ;; If optimizing for space, use -(reg - 1) to invert the comparison rather than | |
2009 | ;; xor reg,reg,1 which might eliminate a NOP being inserted. | |
2010 | (define_split | |
2011 | [(set (match_operand:SI 0 "register_operand" "") | |
2012 | (ge:SI (match_operand:SI 1 "register_operand" "") | |
2013 | (match_operand:SI 2 "reg_or_int16_operand" ""))) | |
2014 | (clobber (reg:SI 17))] | |
2015 | "optimize_size" | |
2016 | [(set (reg:SI 17) | |
2017 | (lt:SI (match_dup 1) | |
2018 | (match_dup 2))) | |
2019 | (set (match_dup 0) | |
2020 | (reg:SI 17)) | |
2021 | (set (match_dup 0) | |
2022 | (plus:SI (match_dup 0) | |
2023 | (const_int -1))) | |
2024 | (set (match_dup 0) | |
2025 | (neg:SI (match_dup 0)))] | |
2026 | "") | |
2027 | ||
2028 | (define_expand "sltu" | |
2029 | [(match_operand:SI 0 "register_operand" "")] | |
2030 | "" | |
2031 | " | |
2032 | { | |
2033 | rtx op0 = operands[0]; | |
2034 | rtx op1 = m32r_compare_op0; | |
2035 | rtx op2 = m32r_compare_op1; | |
2036 | enum machine_mode mode = GET_MODE (op0); | |
2037 | ||
2038 | if (mode != SImode) | |
2039 | FAIL; | |
2040 | ||
2041 | if (! register_operand (op1, mode)) | |
2042 | op1 = force_reg (mode, op1); | |
2043 | ||
2044 | if (! reg_or_int16_operand (op2, mode)) | |
2045 | op2 = force_reg (mode, op2); | |
2046 | ||
2047 | emit_insn (gen_sltu_insn (op0, op1, op2)); | |
2048 | DONE; | |
2049 | }") | |
2050 | ||
2051 | (define_insn "sltu_insn" | |
2052 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
2053 | (ltu:SI (match_operand:SI 1 "register_operand" "r,r") | |
2054 | (match_operand:SI 2 "reg_or_int16_operand" "r,J"))) | |
2055 | (clobber (reg:SI 17))] | |
2056 | "" | |
2057 | "#" | |
2058 | [(set_attr "type" "multi") | |
2059 | (set_attr "length" "6,8")]) | |
2060 | ||
2061 | (define_split | |
2062 | [(set (match_operand:SI 0 "register_operand" "") | |
2063 | (ltu:SI (match_operand:SI 1 "register_operand" "") | |
2064 | (match_operand:SI 2 "reg_or_int16_operand" ""))) | |
2065 | (clobber (reg:SI 17))] | |
2066 | "" | |
2067 | [(set (reg:SI 17) | |
2068 | (ltu:SI (match_dup 1) | |
2069 | (match_dup 2))) | |
2070 | (set (match_dup 0) | |
2071 | (reg:SI 17))] | |
2072 | "") | |
2073 | ||
2074 | (define_expand "sleu" | |
2075 | [(match_operand:SI 0 "register_operand" "")] | |
2076 | "" | |
2077 | " | |
2078 | { | |
2079 | rtx op0 = operands[0]; | |
2080 | rtx op1 = m32r_compare_op0; | |
2081 | rtx op2 = m32r_compare_op1; | |
2082 | enum machine_mode mode = GET_MODE (op0); | |
2083 | ||
2084 | if (mode != SImode) | |
2085 | FAIL; | |
2086 | ||
2087 | if (GET_CODE (op2) == CONST_INT) | |
2088 | { | |
2089 | HOST_WIDE_INT value = INTVAL (op2); | |
2090 | if (value >= 2147483647) | |
2091 | { | |
2092 | emit_move_insn (op0, GEN_INT (1)); | |
2093 | DONE; | |
2094 | } | |
2095 | ||
2096 | op2 = GEN_INT (value+1); | |
2097 | if (value < 0 || value >= 32767) | |
2098 | op2 = force_reg (mode, op2); | |
2099 | ||
2100 | emit_insn (gen_sltu_insn (op0, op1, op2)); | |
2101 | DONE; | |
2102 | } | |
2103 | ||
2104 | if (! register_operand (op2, mode)) | |
2105 | op2 = force_reg (mode, op2); | |
2106 | ||
2107 | emit_insn (gen_sleu_insn (op0, op1, op2)); | |
2108 | DONE; | |
2109 | }") | |
2110 | ||
2111 | (define_insn "sleu_insn" | |
2112 | [(set (match_operand:SI 0 "register_operand" "=r") | |
2113 | (leu:SI (match_operand:SI 1 "register_operand" "r") | |
2114 | (match_operand:SI 2 "register_operand" "r"))) | |
2115 | (clobber (reg:SI 17))] | |
2116 | "" | |
2117 | "#" | |
2118 | [(set_attr "type" "multi") | |
2119 | (set_attr "length" "8")]) | |
2120 | ||
2121 | (define_split | |
2122 | [(set (match_operand:SI 0 "register_operand" "") | |
2123 | (leu:SI (match_operand:SI 1 "register_operand" "") | |
2124 | (match_operand:SI 2 "register_operand" ""))) | |
2125 | (clobber (reg:SI 17))] | |
2126 | "!optimize_size" | |
2127 | [(set (reg:SI 17) | |
2128 | (ltu:SI (match_dup 2) | |
2129 | (match_dup 1))) | |
2130 | (set (match_dup 0) | |
2131 | (reg:SI 17)) | |
2132 | (set (match_dup 0) | |
2133 | (xor:SI (match_dup 0) | |
2134 | (const_int 1)))] | |
2135 | "") | |
2136 | ||
2137 | ;; If optimizing for space, use -(reg - 1) to invert the comparison rather than | |
2138 | ;; xor reg,reg,1 which might eliminate a NOP being inserted. | |
2139 | (define_split | |
2140 | [(set (match_operand:SI 0 "register_operand" "") | |
2141 | (leu:SI (match_operand:SI 1 "register_operand" "") | |
2142 | (match_operand:SI 2 "register_operand" ""))) | |
2143 | (clobber (reg:SI 17))] | |
2144 | "optimize_size" | |
2145 | [(set (reg:SI 17) | |
2146 | (ltu:SI (match_dup 2) | |
2147 | (match_dup 1))) | |
2148 | (set (match_dup 0) | |
2149 | (reg:SI 17)) | |
2150 | (set (match_dup 0) | |
2151 | (plus:SI (match_dup 0) | |
2152 | (const_int -1))) | |
2153 | (set (match_dup 0) | |
2154 | (neg:SI (match_dup 0)))] | |
2155 | "") | |
2156 | ||
2157 | (define_expand "sgtu" | |
2158 | [(match_operand:SI 0 "register_operand" "")] | |
2159 | "" | |
2160 | " | |
2161 | { | |
2162 | rtx op0 = operands[0]; | |
2163 | rtx op1 = m32r_compare_op0; | |
2164 | rtx op2 = m32r_compare_op1; | |
2165 | enum machine_mode mode = GET_MODE (op0); | |
2166 | ||
2167 | if (mode != SImode) | |
2168 | FAIL; | |
2169 | ||
2170 | if (! register_operand (op1, mode)) | |
2171 | op1 = force_reg (mode, op1); | |
2172 | ||
2173 | if (! register_operand (op2, mode)) | |
2174 | op2 = force_reg (mode, op2); | |
2175 | ||
2176 | emit_insn (gen_sltu_insn (op0, op2, op1)); | |
2177 | DONE; | |
2178 | }") | |
2179 | ||
2180 | (define_expand "sgeu" | |
2181 | [(match_operand:SI 0 "register_operand" "")] | |
2182 | "" | |
2183 | " | |
2184 | { | |
2185 | rtx op0 = operands[0]; | |
2186 | rtx op1 = m32r_compare_op0; | |
2187 | rtx op2 = m32r_compare_op1; | |
2188 | enum machine_mode mode = GET_MODE (op0); | |
2189 | ||
2190 | if (mode != SImode) | |
2191 | FAIL; | |
2192 | ||
2193 | if (! register_operand (op1, mode)) | |
2194 | op1 = force_reg (mode, op1); | |
2195 | ||
2196 | if (! reg_or_int16_operand (op2, mode)) | |
2197 | op2 = force_reg (mode, op2); | |
2198 | ||
2199 | emit_insn (gen_sgeu_insn (op0, op1, op2)); | |
2200 | DONE; | |
2201 | }") | |
2202 | ||
2203 | (define_insn "sgeu_insn" | |
2204 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
2205 | (geu:SI (match_operand:SI 1 "register_operand" "r,r") | |
2206 | (match_operand:SI 2 "reg_or_int16_operand" "r,J"))) | |
2207 | (clobber (reg:SI 17))] | |
2208 | "" | |
2209 | "#" | |
2210 | [(set_attr "type" "multi") | |
2211 | (set_attr "length" "8,10")]) | |
2212 | ||
2213 | (define_split | |
2214 | [(set (match_operand:SI 0 "register_operand" "") | |
2215 | (geu:SI (match_operand:SI 1 "register_operand" "") | |
2216 | (match_operand:SI 2 "reg_or_int16_operand" ""))) | |
2217 | (clobber (reg:SI 17))] | |
2218 | "!optimize_size" | |
2219 | [(set (reg:SI 17) | |
2220 | (ltu:SI (match_dup 1) | |
2221 | (match_dup 2))) | |
2222 | (set (match_dup 0) | |
2223 | (reg:SI 17)) | |
2224 | (set (match_dup 0) | |
2225 | (xor:SI (match_dup 0) | |
2226 | (const_int 1)))] | |
2227 | "") | |
2228 | ||
2229 | ;; If optimizing for space, use -(reg - 1) to invert the comparison rather than | |
2230 | ;; xor reg,reg,1 which might eliminate a NOP being inserted. | |
2231 | (define_split | |
2232 | [(set (match_operand:SI 0 "register_operand" "") | |
2233 | (geu:SI (match_operand:SI 1 "register_operand" "") | |
2234 | (match_operand:SI 2 "reg_or_int16_operand" ""))) | |
2235 | (clobber (reg:SI 17))] | |
2236 | "optimize_size" | |
2237 | [(set (reg:SI 17) | |
2238 | (ltu:SI (match_dup 1) | |
2239 | (match_dup 2))) | |
2240 | (set (match_dup 0) | |
2241 | (reg:SI 17)) | |
2242 | (set (match_dup 0) | |
2243 | (plus:SI (match_dup 0) | |
2244 | (const_int -1))) | |
2245 | (set (match_dup 0) | |
2246 | (neg:SI (match_dup 0)))] | |
2247 | "") | |
2248 | ||
2249 | (define_insn "movcc_insn" | |
2250 | [(set (match_operand:SI 0 "register_operand" "=r") | |
2251 | (reg:SI 17))] | |
2252 | "" | |
2253 | "mvfc %0, cbr" | |
2254 | [(set_attr "type" "misc") | |
2255 | (set_attr "length" "2")]) | |
2256 | ||
2257 | \f | |
8c5ca3b9 DE |
2258 | ;; Unconditional and other jump instructions. |
2259 | ||
2260 | (define_insn "jump" | |
2261 | [(set (pc) (label_ref (match_operand 0 "" "")))] | |
2262 | "" | |
2263 | "bra %l0" | |
2264 | [(set_attr "type" "uncond_branch") | |
2265 | (set (attr "length") (if_then_else (ltu (plus (minus (match_dup 0) (pc)) | |
2266 | (const_int 400)) | |
2267 | (const_int 800)) | |
2268 | (const_int 2) | |
2269 | (const_int 4)))]) | |
2270 | ||
2271 | (define_insn "indirect_jump" | |
2272 | [(set (pc) (match_operand:SI 0 "address_operand" "p"))] | |
2273 | "" | |
2274 | "jmp %a0" | |
2275 | [(set_attr "type" "uncond_branch") | |
2276 | (set_attr "length" "2")]) | |
56e2e762 NC |
2277 | |
2278 | (define_insn "return" | |
2279 | [(return)] | |
2280 | "direct_return ()" | |
2281 | "jmp lr" | |
2282 | [(set_attr "type" "uncond_branch") | |
2283 | (set_attr "length" "2")]) | |
8c5ca3b9 DE |
2284 | |
2285 | (define_insn "tablejump" | |
2286 | [(set (pc) (match_operand:SI 0 "address_operand" "p")) | |
2287 | (use (label_ref (match_operand 1 "" "")))] | |
2288 | "" | |
2289 | "jmp %a0" | |
2290 | [(set_attr "type" "uncond_branch") | |
2291 | (set_attr "length" "2")]) | |
2292 | ||
2293 | (define_expand "call" | |
2294 | ;; operands[1] is stack_size_rtx | |
2295 | ;; operands[2] is next_arg_register | |
2296 | [(parallel [(call (match_operand:SI 0 "call_operand" "") | |
2297 | (match_operand 1 "" "")) | |
2298 | (clobber (reg:SI 14))])] | |
2299 | "" | |
2300 | "") | |
2301 | ||
2302 | (define_insn "*call_via_reg" | |
2303 | [(call (mem:SI (match_operand:SI 0 "register_operand" "r")) | |
2304 | (match_operand 1 "" "")) | |
2305 | (clobber (reg:SI 14))] | |
2306 | "" | |
2307 | "jl %0" | |
2308 | [(set_attr "type" "call") | |
2309 | (set_attr "length" "2")]) | |
2310 | ||
2311 | (define_insn "*call_via_label" | |
2312 | [(call (mem:SI (match_operand:SI 0 "call_address_operand" "")) | |
2313 | (match_operand 1 "" "")) | |
2314 | (clobber (reg:SI 14))] | |
2315 | "" | |
2316 | "* | |
2317 | { | |
2318 | int call26_p = call26_operand (operands[0], FUNCTION_MODE); | |
2319 | ||
2320 | if (! call26_p) | |
2321 | { | |
2322 | /* We may not be able to reach with a `bl' insn so punt and leave it to | |
2323 | the linker. | |
2324 | We do this here, rather than doing a force_reg in the define_expand | |
2325 | so these insns won't be separated, say by scheduling, thus simplifying | |
2326 | the linker. */ | |
2327 | return \"seth r14,%T0\;add3 r14,r14,%B0\;jl r14\"; | |
2328 | } | |
2329 | else | |
2330 | return \"bl %0\"; | |
2331 | }" | |
2332 | [(set_attr "type" "call") | |
2333 | (set (attr "length") | |
2334 | (if_then_else (eq (symbol_ref "call26_operand (operands[0], FUNCTION_MODE)") | |
2335 | (const_int 0)) | |
2336 | (const_int 12) ; 10 + 2 for nop filler | |
2337 | ; The return address must be on a 4 byte boundary so | |
2338 | ; there's no point in using a value of 2 here. A 2 byte | |
2339 | ; insn may go in the left slot but we currently can't | |
2340 | ; use such knowledge. | |
2341 | (const_int 4)))]) | |
2342 | ||
2343 | (define_expand "call_value" | |
2344 | ;; operand 2 is stack_size_rtx | |
2345 | ;; operand 3 is next_arg_register | |
2346 | [(parallel [(set (match_operand 0 "register_operand" "=r") | |
2347 | (call (match_operand:SI 1 "call_operand" "") | |
2348 | (match_operand 2 "" ""))) | |
2349 | (clobber (reg:SI 14))])] | |
2350 | "" | |
2351 | "") | |
2352 | ||
2353 | (define_insn "*call_value_via_reg" | |
2354 | [(set (match_operand 0 "register_operand" "=r") | |
2355 | (call (mem:SI (match_operand:SI 1 "register_operand" "r")) | |
2356 | (match_operand 2 "" ""))) | |
2357 | (clobber (reg:SI 14))] | |
2358 | "" | |
2359 | "jl %1" | |
2360 | [(set_attr "type" "call") | |
2361 | (set_attr "length" "2")]) | |
2362 | ||
2363 | (define_insn "*call_value_via_label" | |
2364 | [(set (match_operand 0 "register_operand" "=r") | |
2365 | (call (mem:SI (match_operand:SI 1 "call_address_operand" "")) | |
2366 | (match_operand 2 "" ""))) | |
2367 | (clobber (reg:SI 14))] | |
2368 | "" | |
2369 | "* | |
2370 | { | |
2371 | int call26_p = call26_operand (operands[1], FUNCTION_MODE); | |
2372 | ||
2373 | if (! call26_p) | |
2374 | { | |
2375 | /* We may not be able to reach with a `bl' insn so punt and leave it to | |
2376 | the linker. | |
2377 | We do this here, rather than doing a force_reg in the define_expand | |
2378 | so these insns won't be separated, say by scheduling, thus simplifying | |
2379 | the linker. */ | |
2380 | return \"seth r14,%T1\;add3 r14,r14,%B1\;jl r14\"; | |
2381 | } | |
2382 | else | |
2383 | return \"bl %1\"; | |
2384 | }" | |
2385 | [(set_attr "type" "call") | |
2386 | (set (attr "length") | |
2387 | (if_then_else (eq (symbol_ref "call26_operand (operands[1], FUNCTION_MODE)") | |
2388 | (const_int 0)) | |
2389 | (const_int 12) ; 10 + 2 for nop filler | |
2390 | ; The return address must be on a 4 byte boundary so | |
2391 | ; there's no point in using a value of 2 here. A 2 byte | |
2392 | ; insn may go in the left slot but we currently can't | |
2393 | ; use such knowledge. | |
2394 | (const_int 4)))]) | |
2395 | \f | |
2396 | (define_insn "nop" | |
2397 | [(const_int 0)] | |
2398 | "" | |
2399 | "nop" | |
5b8ae21f | 2400 | [(set_attr "type" "int2") |
8c5ca3b9 DE |
2401 | (set_attr "length" "2")]) |
2402 | ||
2403 | ;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and | |
2404 | ;; all of memory. This blocks insns from being moved across this point. | |
2405 | ||
2406 | (define_insn "blockage" | |
2407 | [(unspec_volatile [(const_int 0)] 0)] | |
2408 | "" | |
2409 | "") | |
2410 | ||
2411 | ;; Special pattern to flush the icache. | |
2412 | ||
2413 | (define_insn "flush_icache" | |
2414 | [(unspec_volatile [(match_operand 0 "memory_operand" "m")] 0)] | |
2415 | "" | |
2416 | "* return \"nop ; flush-icache\";" | |
5b8ae21f MM |
2417 | [(set_attr "type" "int2") |
2418 | (set_attr "length" "2")]) | |
2b7972b0 | 2419 | \f |
56e2e762 NC |
2420 | ;; Speed up fabs and provide correct sign handling for -0 |
2421 | ||
2422 | (define_insn "absdf2" | |
2423 | [(set (match_operand:DF 0 "register_operand" "=r") | |
2424 | (abs:DF (match_operand:DF 1 "register_operand" "0")))] | |
2425 | "" | |
2426 | "#" | |
2427 | [(set_attr "type" "multi") | |
2428 | (set_attr "length" "4")]) | |
2429 | ||
2430 | (define_split | |
2431 | [(set (match_operand:DF 0 "register_operand" "") | |
2432 | (abs:DF (match_operand:DF 1 "register_operand" "")))] | |
2433 | "reload_completed" | |
2434 | [(set (match_dup 2) | |
2435 | (ashift:SI (match_dup 2) | |
2436 | (const_int 1))) | |
2437 | (set (match_dup 2) | |
2438 | (lshiftrt:SI (match_dup 2) | |
2439 | (const_int 1)))] | |
2440 | "operands[2] = gen_highpart (SImode, operands[0]);") | |
2441 | ||
2442 | (define_insn "abssf2" | |
2443 | [(set (match_operand:SF 0 "register_operand" "=r") | |
2444 | (abs:SF (match_operand:SF 1 "register_operand" "0")))] | |
2445 | "" | |
2446 | "#" | |
2447 | [(set_attr "type" "multi") | |
2448 | (set_attr "length" "4")]) | |
2449 | ||
2450 | (define_split | |
2451 | [(set (match_operand:SF 0 "register_operand" "") | |
2452 | (abs:SF (match_operand:SF 1 "register_operand" "")))] | |
2453 | "reload_completed" | |
2454 | [(set (match_dup 2) | |
2455 | (ashift:SI (match_dup 2) | |
2456 | (const_int 1))) | |
2457 | (set (match_dup 2) | |
2458 | (lshiftrt:SI (match_dup 2) | |
2459 | (const_int 1)))] | |
2460 | "operands[2] = gen_highpart (SImode, operands[0]);") | |
2461 | \f | |
2b7972b0 MM |
2462 | ;; Conditional move instructions |
2463 | ;; Based on those done for the d10v | |
2464 | ||
2b7972b0 MM |
2465 | (define_expand "movsicc" |
2466 | [ | |
2467 | (set (match_operand:SI 0 "register_operand" "r") | |
2468 | (if_then_else:SI (match_operand 1 "" "") | |
2469 | (match_operand:SI 2 "conditional_move_operand" "O") | |
2470 | (match_operand:SI 3 "conditional_move_operand" "O") | |
2471 | ) | |
2472 | ) | |
2473 | ] | |
2474 | "" | |
2475 | " | |
2476 | { | |
2477 | if (! zero_and_one (operands [2], operands [3])) | |
2478 | FAIL; | |
2479 | ||
2480 | /* Generate the comparision that will set the carry flag. */ | |
56e2e762 | 2481 | operands[1] = gen_compare (GET_CODE (operands[1]), m32r_compare_op0, |
2b7972b0 MM |
2482 | m32r_compare_op1, TRUE); |
2483 | ||
2484 | /* See other movsicc pattern below for reason why. */ | |
56e2e762 | 2485 | emit_insn (gen_blockage ()); |
2b7972b0 MM |
2486 | }") |
2487 | ||
2488 | ;; Generate the conditional instructions based on how the carry flag is examined. | |
2489 | (define_insn "*movsicc_internal" | |
997718c7 | 2490 | [(set (match_operand:SI 0 "register_operand" "=r") |
2b7972b0 MM |
2491 | (if_then_else:SI (match_operand 1 "carry_compare_operand" "") |
2492 | (match_operand:SI 2 "conditional_move_operand" "O") | |
2493 | (match_operand:SI 3 "conditional_move_operand" "O") | |
2494 | ) | |
2495 | )] | |
2496 | "zero_and_one (operands [2], operands[3])" | |
2497 | "* return emit_cond_move (operands, insn);" | |
5b8ae21f | 2498 | [(set_attr "type" "multi") |
2b7972b0 MM |
2499 | (set_attr "length" "8") |
2500 | ] | |
2501 | ) | |
2502 | ||
8c5ca3b9 DE |
2503 | \f |
2504 | ;; Split up troublesome insns for better scheduling. | |
56e2e762 | 2505 | ;; FIXME: Peepholes go at the end. |
8c5ca3b9 DE |
2506 | |
2507 | ;; ??? Setting the type attribute may not be useful, but for completeness | |
2508 | ;; we do it. | |
2509 | ||
2510 | (define_peephole | |
2511 | [(set (mem:SI (plus:SI (match_operand:SI 0 "register_operand" "r") | |
2512 | (const_int 4))) | |
2513 | (match_operand:SI 1 "register_operand" "r"))] | |
5b8ae21f | 2514 | "0 && dead_or_set_p (insn, operands[0])" |
8c5ca3b9 | 2515 | "st %1,@+%0" |
5b8ae21f | 2516 | [(set_attr "type" "store2") |
8c5ca3b9 | 2517 | (set_attr "length" "2")]) |
2b7972b0 MM |
2518 | |
2519 | ;; This case is triggered by compiling this code: | |
2520 | ;; | |
2521 | ;; extern void sub(int *); | |
2522 | ;; void main (void) | |
2523 | ;; { | |
2524 | ;; int i=2,j=3,k; | |
2525 | ;; while (i < j) sub(&k); | |
2526 | ;; i = j / k; | |
2527 | ;; sub(&i); | |
2528 | ;; i = j - k; | |
2529 | ;; sub(&i); | |
2530 | ;; } | |
2531 | ;; | |
2532 | ;; Without the peephole the following assembler is generated for the | |
2533 | ;; divide and subtract expressions: | |
2534 | ;; | |
2535 | ;; div r5,r4 | |
2536 | ;; mv r4,r5 | |
2537 | ;; st r4,@(4,sp) | |
2538 | ;; bl sub | |
2539 | ;; | |
2540 | ;; Simialr code is produced for the subtract expression. With this | |
2541 | ;; peephole the redundant move is eliminated. | |
2542 | ;; | |
2543 | ;; This optimisation onbly works if PRESERVE_DEATH_INFO_REGNO_P is | |
2544 | ;; defined in m32r.h | |
2545 | ||
2546 | (define_peephole | |
2547 | [(set (match_operand:SI 0 "register_operand" "r") | |
2548 | (match_operand:SI 1 "register_operand" "r") | |
2549 | ) | |
2550 | (set (mem:SI (plus: SI (match_operand:SI 2 "register_operand" "r") | |
2551 | (match_operand:SI 3 "immediate_operand" "J"))) | |
2552 | (match_dup 0) | |
2553 | ) | |
2554 | ] | |
5b8ae21f | 2555 | "0 && dead_or_set_p (insn, operands [0])" |
2b7972b0 | 2556 | "st %1,@(%3,%2)" |
5b8ae21f | 2557 | [(set_attr "type" "store4") |
2b7972b0 MM |
2558 | (set_attr "length" "4") |
2559 | ] | |
2560 | ) | |
d2a73f8e NC |
2561 | |
2562 | ;; Block moves, see m32r.c for more details. | |
2563 | ;; Argument 0 is the destination | |
2564 | ;; Argument 1 is the source | |
2565 | ;; Argument 2 is the length | |
2566 | ;; Argument 3 is the alignment | |
2567 | ||
2568 | (define_expand "movstrsi" | |
2569 | [(parallel [(set (match_operand:BLK 0 "general_operand" "") | |
2570 | (match_operand:BLK 1 "general_operand" "")) | |
2571 | (use (match_operand:SI 2 "immediate_operand" "")) | |
2572 | (use (match_operand:SI 3 "immediate_operand" ""))])] | |
2573 | "" | |
2574 | " | |
2575 | { | |
2576 | if (operands[0]) /* avoid unused code messages */ | |
2577 | { | |
2578 | m32r_expand_block_move (operands); | |
2579 | DONE; | |
2580 | } | |
2581 | }") | |
2582 | ||
2583 | ;; Insn generated by block moves | |
2584 | ||
2585 | (define_insn "movstrsi_internal" | |
997718c7 RH |
2586 | [(set (mem:BLK (match_operand:SI 0 "register_operand" "+r")) ;; destination |
2587 | (mem:BLK (match_operand:SI 1 "register_operand" "+r"))) ;; source | |
d2a73f8e | 2588 | (use (match_operand:SI 2 "m32r_block_immediate_operand" "J"));; # bytes to move |
6970d948 NC |
2589 | (set (match_dup 0) (plus:SI (match_dup 0) (minus:SI (match_dup 2) (const_int 4)))) |
2590 | (set (match_dup 1) (plus:SI (match_dup 1) (match_dup 2))) | |
d2a73f8e | 2591 | (clobber (match_scratch:SI 3 "=&r")) ;; temp 1 |
6970d948 | 2592 | (clobber (match_scratch:SI 4 "=&r"))] ;; temp 2 |
d2a73f8e | 2593 | "" |
16f104b3 | 2594 | "* m32r_output_block_move (insn, operands); return \"\"; " |
d2a73f8e NC |
2595 | [(set_attr "type" "store8") |
2596 | (set_attr "length" "72")]) ;; Maximum |