Commit | Line | Data |
---|---|---|
32a32c6c C |
1 | |
2 | ;;- Machine description for SPARC chip for GNU C compiler | |
3 | ;; Copyright (C) 1988, 1989 Free Software Foundation, Inc. | |
4 | ;; Contributed by Michael Tiemann (tiemann@mcc.com) | |
5 | ||
6 | ;; This file is part of GNU CC. | |
7 | ||
8 | ;; GNU CC is free software; you can redistribute it and/or modify | |
9 | ;; it under the terms of the GNU General Public License as published by | |
10 | ;; the Free Software Foundation; either version 1, or (at your option) | |
11 | ;; any later version. | |
12 | ||
13 | ;; GNU CC is distributed in the hope that it will be useful, | |
14 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | ;; GNU General Public License for more details. | |
17 | ||
18 | ;; You should have received a copy of the GNU General Public License | |
19 | ;; along with GNU CC; see the file COPYING. If not, write to | |
20 | ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
21 | ||
22 | ||
23 | ;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. | |
24 | ||
25 | ;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code | |
26 | ;;- updates for most instructions. | |
27 | ||
28 | ;;- Operand classes for the register allocator: | |
29 | \f | |
30 | ;; Compare instructions. | |
31 | ;; This controls RTL generation and register allocation. | |
32 | ||
33 | ;; Put cmpsi first among compare insns so it matches two CONST_INT operands. | |
34 | ||
35 | (define_insn "cmpsi" | |
36 | [(set (cc0) | |
37 | (compare (match_operand:SI 0 "arith_operand" "r,rI") | |
38 | (match_operand:SI 1 "arith_operand" "I,r")))] | |
39 | "" | |
40 | "* | |
41 | { | |
42 | if (! REG_P (operands[0])) | |
43 | { | |
44 | cc_status.flags |= CC_REVERSED; | |
45 | return \"cmp %1,%0\"; | |
46 | } | |
47 | return \"cmp %0,%1\"; | |
48 | }") | |
49 | ||
50 | (define_expand "cmpdf" | |
51 | [(set (cc0) | |
52 | (compare (match_operand:DF 0 "nonmemory_operand" "f,fG") | |
53 | (match_operand:DF 1 "nonmemory_operand" "G,f")))] | |
54 | "" | |
55 | "emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, DFmode, 32)));") | |
56 | ||
57 | (define_insn "" | |
58 | [(set (cc0) | |
59 | (compare (match_operand:DF 0 "nonmemory_operand" "f,fG") | |
60 | (match_operand:DF 1 "nonmemory_operand" "G,f")))] | |
61 | "GET_CODE (operands[0]) != CONST_INT && GET_CODE (operands[1]) != CONST_INT" | |
62 | "* | |
63 | { | |
64 | if (GET_CODE (operands[0]) == CONST_DOUBLE | |
65 | || GET_CODE (operands[1]) == CONST_DOUBLE) | |
66 | make_f0_contain_0 (2); | |
67 | ||
68 | cc_status.flags |= CC_IN_FCCR; | |
69 | if (GET_CODE (operands[0]) == CONST_DOUBLE) | |
70 | return \"fcmped %%f0,%1\;nop\"; | |
71 | if (GET_CODE (operands[1]) == CONST_DOUBLE) | |
72 | return \"fcmped %0,%%f0\;nop\"; | |
73 | return \"fcmped %0,%1\;nop\"; | |
74 | }") | |
75 | ||
76 | (define_expand "cmpsf" | |
77 | [(set (cc0) | |
78 | (compare (match_operand:SF 0 "nonmemory_operand" "f,fG") | |
79 | (match_operand:SF 1 "nonmemory_operand" "G,f")))] | |
80 | "" | |
81 | "emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, SFmode, 32)));") | |
82 | ||
83 | (define_insn "" | |
84 | [(set (cc0) | |
85 | (compare (match_operand:SF 0 "nonmemory_operand" "f,fG") | |
86 | (match_operand:SF 1 "nonmemory_operand" "G,f")))] | |
87 | "GET_CODE (operands[0]) != CONST_INT && GET_CODE (operands[1]) != CONST_INT" | |
88 | "* | |
89 | { | |
90 | if (GET_CODE (operands[0]) == CONST_DOUBLE | |
91 | || GET_CODE (operands[1]) == CONST_DOUBLE) | |
92 | make_f0_contain_0 (1); | |
93 | ||
94 | cc_status.flags |= CC_IN_FCCR; | |
95 | if (GET_CODE (operands[0]) == CONST_DOUBLE) | |
96 | return \"fcmpes %%f0,%1\;nop\"; | |
97 | if (GET_CODE (operands[1]) == CONST_DOUBLE) | |
98 | return \"fcmpes %0,%%f0\;nop\"; | |
99 | return \"fcmpes %0,%1\;nop\"; | |
100 | }") | |
101 | ||
102 | ;; Put tstsi first among test insns so it matches a CONST_INT operand. | |
103 | ||
104 | (define_insn "tstsi" | |
105 | [(set (cc0) | |
106 | (match_operand:SI 0 "register_operand" "r"))] | |
107 | "" | |
108 | "tst %0") | |
109 | ||
110 | ;; Need this to take a general operand because cse can make | |
111 | ;; a CONST which won't be in a register. | |
112 | (define_insn "" | |
113 | [(set (cc0) | |
114 | (match_operand:SI 0 "immediate_operand" "i"))] | |
115 | "" | |
116 | "set %0,%%g1\;tst %%g1") | |
117 | ||
118 | ;; Optimize the case of following a reg-reg move with a test | |
119 | ;; of reg just moved. | |
120 | ||
121 | (define_peephole | |
122 | [(set (match_operand:SI 0 "register_operand" "=r") | |
123 | (match_operand:SI 1 "register_operand" "r")) | |
124 | (set (cc0) (match_operand:SI 2 "register_operand" "r"))] | |
125 | "operands[2] == operands[0] | |
126 | || operands[2] == operands[1]" | |
127 | "orcc %1,%%g0,%0 ! 2-insn combine") | |
128 | ||
129 | ;; Optimize 5(6) insn sequence to 3(4) insns. | |
130 | ;; These patterns could also optimize more complicated sets | |
131 | ;; before conditional branches. | |
132 | ||
133 | ;; Turned off because (1) this case is rarely encounted | |
134 | ;; (2) to be correct, more conditions must be checked | |
135 | ;; (3) the conditions must be checked with rtx_equal_p, not == | |
136 | ;; (4) when branch scheduling is added to the compiler, | |
137 | ;; this optimization will be performed by the branch scheduler | |
138 | ;; Bottom line: it is not worth the trouble of fixing or | |
139 | ;; maintaining it. | |
140 | ||
141 | ;(define_peephole | |
142 | ; [(set (match_operand:SI 0 "register_operand" "=r") | |
143 | ; (match_operand:SI 1 "general_operand" "g")) | |
144 | ; (set (match_operand:SI 2 "register_operand" "=r") | |
145 | ; (match_operand:SI 3 "reg_or_0_operand" "rJ")) | |
146 | ; (set (cc0) (match_operand:SI 4 "register_operand" "r")) | |
147 | ; (set (pc) (match_operand 5 "" ""))] | |
148 | ; "GET_CODE (operands[5]) == IF_THEN_ELSE | |
149 | ; && operands[0] != operands[3] | |
150 | ; && ! reg_mentioned_p (operands[2], operands[1]) | |
151 | ; && (operands[4] == operands[0] | |
152 | ; || operands[4] == operands[2] | |
153 | ; || operands[4] == operands[3])" | |
154 | ; "* | |
155 | ;{ | |
156 | ; rtx xoperands[2]; | |
157 | ; int parity; | |
158 | ; xoperands[0] = XEXP (operands[5], 0); | |
159 | ; if (GET_CODE (XEXP (operands[5], 1)) == PC) | |
160 | ; { | |
161 | ; parity = 1; | |
162 | ; xoperands[1] = XEXP (XEXP (operands[5], 2), 0); | |
163 | ; } | |
164 | ; else | |
165 | ; { | |
166 | ; parity = 0; | |
167 | ; xoperands[1] = XEXP (XEXP (operands[5], 1), 0); | |
168 | ; } | |
169 | ; | |
170 | ; if (operands[4] == operands[0]) | |
171 | ; { | |
172 | ; /* Although the constraints for operands[1] permit a general | |
173 | ; operand (and hence possibly a const_int), we know that | |
174 | ; in this branch it cannot be a CONST_INT, since that would give | |
175 | ; us a fixed condition, and those should have been optimized away. */ | |
176 | ; if (REG_P (operands[1])) | |
177 | ; output_asm_insn (\"orcc %1,%%g0,%0 ! 3-insn reorder\", operands); | |
178 | ; else if (GET_CODE (operands[1]) != MEM) | |
179 | ; abort (); | |
180 | ; else | |
181 | ; { | |
182 | ; if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
183 | ; output_asm_insn (\"sethi %%hi(%m1),%%g1\;ld [%%g1+%%lo(%m1)],%0\;tst %0 ! 4-insn reorder\", operands); | |
184 | ; else | |
185 | ; output_asm_insn (\"ld %1,%0\;tst %0 ! 3.5-insn reorder\", operands); | |
186 | ; } | |
187 | ; XVECEXP (PATTERN (insn), 0, 0) = XVECEXP (PATTERN (insn), 0, 2); | |
188 | ; XVECEXP (PATTERN (insn), 0, 1) = XVECEXP (PATTERN (insn), 0, 3); | |
189 | ; } | |
190 | ; else | |
191 | ; { | |
192 | ; output_asm_insn (\"orcc %3,%%g0,%2 ! 3-insn reorder\", operands); | |
193 | ; } | |
194 | ; if (parity) | |
195 | ; return output_delayed_branch (\"b%N0 %l1\", xoperands, insn); | |
196 | ; else | |
197 | ; return output_delayed_branch (\"b%C0 %l1\", xoperands, insn); | |
198 | ;}") | |
199 | ||
200 | ;; By default, operations don't set the condition codes. | |
201 | ;; These patterns allow cc's to be set, while doing some work | |
202 | ||
203 | (define_insn "" | |
204 | [(set (cc0) | |
205 | (zero_extend:SI (subreg:QI (match_operand:SI 0 "register_operand" "r") 0)))] | |
206 | "" | |
207 | "andcc %0,0xff,%%g0") | |
208 | ||
209 | (define_insn "" | |
210 | [(set (cc0) | |
211 | (plus:SI (match_operand:SI 0 "register_operand" "r%") | |
212 | (match_operand:SI 1 "arith_operand" "rI")))] | |
213 | "ignore_overflow_conditional_p (NEXT_INSN (insn))" | |
214 | "* | |
215 | { | |
216 | cc_status.flags |= CC_NO_OVERFLOW; | |
217 | return \"addcc %0,%1,%%g0\"; | |
218 | }") | |
219 | ||
220 | (define_insn "" | |
221 | [(set (cc0) | |
222 | (plus:SI (match_operand:SI 0 "register_operand" "r%") | |
223 | (match_operand:SI 1 "arith_operand" "rI"))) | |
224 | (set (match_operand:SI 2 "register_operand" "=r") | |
225 | (plus:SI (match_dup 0) (match_dup 1)))] | |
226 | "ignore_overflow_conditional_p (NEXT_INSN (insn))" | |
227 | "* | |
228 | { | |
229 | cc_status.flags |= CC_NO_OVERFLOW; | |
230 | return \"addcc %0,%1,%2\"; | |
231 | }") | |
232 | ||
233 | (define_insn "" | |
234 | [(set (cc0) | |
235 | (minus:SI (match_operand:SI 0 "register_operand" "r") | |
236 | (match_operand:SI 1 "arith_operand" "rI")))] | |
237 | "ignore_overflow_conditional_p (NEXT_INSN (insn))" | |
238 | "* | |
239 | { | |
240 | cc_status.flags |= CC_NO_OVERFLOW; | |
241 | return \"subcc %0,%1,%%g0\"; | |
242 | }") | |
243 | ||
244 | (define_insn "" | |
245 | [(set (cc0) | |
246 | (minus:SI (match_operand:SI 0 "register_operand" "r") | |
247 | (match_operand:SI 1 "arith_operand" "rI"))) | |
248 | (set (match_operand:SI 2 "register_operand" "=r") | |
249 | (minus:SI (match_dup 0) (match_dup 1)))] | |
250 | "ignore_overflow_conditional_p (NEXT_INSN (insn))" | |
251 | "* | |
252 | { | |
253 | cc_status.flags |= CC_NO_OVERFLOW; | |
254 | return \"subcc %0,%1,%2\"; | |
255 | }") | |
256 | ||
257 | (define_insn "" | |
258 | [(set (cc0) | |
259 | (and:SI (match_operand:SI 0 "register_operand" "r%") | |
260 | (match_operand:SI 1 "arith_operand" "rI")))] | |
261 | "" | |
262 | "andcc %0,%1,%%g0") | |
263 | ||
264 | (define_insn "" | |
265 | [(set (cc0) | |
266 | (and:SI (match_operand:SI 0 "register_operand" "r%") | |
267 | (match_operand:SI 1 "arith_operand" "rI"))) | |
268 | (set (match_operand:SI 2 "register_operand" "=r") | |
269 | (and:SI (match_dup 0) (match_dup 1)))] | |
270 | "" | |
271 | "andcc %0,%1,%2") | |
272 | ||
273 | (define_insn "" | |
274 | [(set (cc0) | |
275 | (and:SI (match_operand:SI 0 "register_operand" "r") | |
276 | (not:SI (match_operand:SI 1 "arith_operand" "rI"))))] | |
277 | "" | |
278 | "andncc %0,%1,%%g0") | |
279 | ||
280 | (define_insn "" | |
281 | [(set (cc0) | |
282 | (and:SI (match_operand:SI 0 "register_operand" "r") | |
283 | (not:SI (match_operand:SI 1 "arith_operand" "rI")))) | |
284 | (set (match_operand:SI 2 "register_operand" "=r") | |
285 | (and:SI (match_dup 0) (not:SI (match_dup 1))))] | |
286 | "" | |
287 | "andncc %0,%1,%2") | |
288 | ||
289 | (define_insn "" | |
290 | [(set (cc0) | |
291 | (ior:SI (match_operand:SI 0 "register_operand" "r%") | |
292 | (match_operand:SI 1 "arith_operand" "rI")))] | |
293 | "" | |
294 | "orcc %0,%1,%%g0") | |
295 | ||
296 | (define_insn "" | |
297 | [(set (cc0) | |
298 | (ior:SI (match_operand:SI 0 "register_operand" "r%") | |
299 | (match_operand:SI 1 "arith_operand" "rI"))) | |
300 | (set (match_operand:SI 2 "register_operand" "=r") | |
301 | (ior:SI (match_dup 0) (match_dup 1)))] | |
302 | "" | |
303 | "orcc %0,%1,%2") | |
304 | ||
305 | (define_insn "" | |
306 | [(set (cc0) | |
307 | (ior:SI (match_operand:SI 0 "register_operand" "r") | |
308 | (not:SI (match_operand:SI 1 "arith_operand" "rI"))))] | |
309 | "" | |
310 | "orncc %0,%1,%%g0") | |
311 | ||
312 | (define_insn "" | |
313 | [(set (cc0) | |
314 | (ior:SI (match_operand:SI 0 "register_operand" "r") | |
315 | (not:SI (match_operand:SI 1 "arith_operand" "rI")))) | |
316 | (set (match_operand:SI 2 "register_operand" "=r") | |
317 | (ior:SI (match_dup 0) (not:SI (match_dup 1))))] | |
318 | "" | |
319 | "orncc %0,%1,%2") | |
320 | ||
321 | (define_insn "" | |
322 | [(set (cc0) | |
323 | (xor:SI (match_operand:SI 0 "register_operand" "r%") | |
324 | (match_operand:SI 1 "arith_operand" "rI")))] | |
325 | "" | |
326 | "xorcc %0,%1,%%g0") | |
327 | ||
328 | (define_insn "" | |
329 | [(set (cc0) | |
330 | (xor:SI (match_operand:SI 0 "register_operand" "r%") | |
331 | (match_operand:SI 1 "arith_operand" "rI"))) | |
332 | (set (match_operand:SI 2 "register_operand" "=r") | |
333 | (xor:SI (match_dup 0) (match_dup 1)))] | |
334 | "" | |
335 | "xorcc %0,%1,%2") | |
336 | ||
337 | (define_insn "" | |
338 | [(set (cc0) | |
339 | (xor:SI (match_operand:SI 0 "register_operand" "r") | |
340 | (not:SI (match_operand:SI 1 "arith_operand" "rI"))))] | |
341 | "" | |
342 | "xnorcc %0,%1,%%g0") | |
343 | ||
344 | (define_insn "" | |
345 | [(set (cc0) | |
346 | (xor:SI (match_operand:SI 0 "register_operand" "r") | |
347 | (not:SI (match_operand:SI 1 "arith_operand" "rI")))) | |
348 | (set (match_operand:SI 2 "register_operand" "=r") | |
349 | (xor:SI (match_dup 0) (not:SI (match_dup 1))))] | |
350 | "" | |
351 | "xnorcc %0,%1,%2") | |
352 | ||
353 | (define_expand "tstdf" | |
354 | [(set (cc0) | |
355 | (match_operand:DF 0 "register_operand" "f"))] | |
356 | "" | |
357 | "emit_insn (gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, DFmode, 32)));") | |
358 | ||
359 | (define_insn "" | |
360 | [(set (cc0) | |
361 | (match_operand:DF 0 "register_operand" "f"))] | |
362 | "" | |
363 | "* | |
364 | { | |
365 | make_f0_contain_0 (2); | |
366 | cc_status.flags |= CC_IN_FCCR; | |
367 | return \"fcmped %0,%%f0\;nop\"; | |
368 | }") | |
369 | ||
370 | (define_expand "tstsf" | |
371 | [(set (cc0) | |
372 | (match_operand:SF 0 "register_operand" "f"))] | |
373 | "" | |
374 | "emit_insn (gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SFmode, 32)));") | |
375 | ||
376 | (define_insn "" | |
377 | [(set (cc0) | |
378 | (match_operand:SF 0 "register_operand" "f"))] | |
379 | "" | |
380 | "* | |
381 | { | |
382 | make_f0_contain_0 (1); | |
383 | cc_status.flags |= CC_IN_FCCR; | |
384 | return \"fcmpes %0,%%f0\;nop\"; | |
385 | }") | |
386 | \f | |
387 | ;; There are no logical links for the condition codes. This | |
388 | ;; would not normally be a problem, but on the SPARC (and possibly | |
389 | ;; other RISC machines), when argument passing, the insn which sets | |
390 | ;; the condition code and the insn which uses the set condition code | |
391 | ;; may not be performed adjacently (due to optimizations performed | |
392 | ;; in combine.c). To make up for this, we emit insn patterns which | |
393 | ;; cannot possibly be rearranged on us. | |
394 | (define_expand "seq" | |
395 | [(set (match_operand:SI 0 "general_operand" "=r") | |
396 | (eq (cc0) (const_int 0)))] | |
397 | "" | |
398 | "gen_scc_insn (EQ, VOIDmode, operands); DONE;") | |
399 | ||
400 | (define_expand "sne" | |
401 | [(set (match_operand:SI 0 "general_operand" "=r") | |
402 | (ne (cc0) (const_int 0)))] | |
403 | "" | |
404 | "gen_scc_insn (NE, VOIDmode, operands); DONE;") | |
405 | ||
406 | (define_insn "" | |
407 | [(set (match_operand:SI 0 "general_operand" "=r,r") | |
408 | (match_operator 1 "eq_or_neq" | |
409 | [(compare (match_operand:SI 2 "general_operand" "r,rI") | |
410 | (match_operand:SI 3 "general_operand" "I,r")) | |
411 | (const_int 0)]))] | |
412 | "" | |
413 | "* | |
414 | { | |
415 | CC_STATUS_INIT; | |
416 | cc_status.value1 = operands[0]; | |
417 | if (! REG_P (operands[2])) | |
418 | { | |
419 | output_asm_insn (\"cmp %3,%2\", operands); | |
420 | cc_status.flags |= CC_REVERSED; | |
421 | } | |
422 | else | |
423 | output_asm_insn (\"cmp %2,%3\", operands); | |
424 | return output_scc_insn (GET_CODE (operands[1]), operands[0]); | |
425 | }") | |
426 | ||
427 | (define_insn "" | |
428 | [(set (match_operand:SI 0 "general_operand" "=r") | |
429 | (match_operator 1 "eq_or_neq" | |
430 | [(match_operand:SI 2 "general_operand" "r") | |
431 | (const_int 0)]))] | |
432 | "" | |
433 | "* | |
434 | { | |
435 | CC_STATUS_INIT; | |
436 | cc_status.value1 = operands[0]; | |
437 | output_asm_insn (\"tst %2\", operands); | |
438 | return output_scc_insn (GET_CODE (operands[1]), operands[0]); | |
439 | }") | |
440 | ||
441 | (define_insn "" | |
442 | [(set (match_operand:SI 0 "general_operand" "=r,r") | |
443 | (match_operator 1 "eq_or_neq" | |
444 | [(compare (match_operand:DF 2 "general_operand" "f,fG") | |
445 | (match_operand:DF 3 "general_operand" "G,f")) | |
446 | (const_int 0)]))] | |
447 | "" | |
448 | "* | |
449 | { | |
450 | CC_STATUS_INIT; | |
451 | cc_status.value1 = operands[0]; | |
452 | cc_status.flags |= CC_IN_FCCR; | |
453 | ||
454 | if (GET_CODE (operands[2]) == CONST_DOUBLE | |
455 | || GET_CODE (operands[3]) == CONST_DOUBLE) | |
456 | make_f0_contain_0 (2); | |
457 | ||
458 | if (GET_CODE (operands[2]) == CONST_DOUBLE) | |
459 | output_asm_insn (\"fcmped %%f0,%3\;nop\", operands); | |
460 | else if (GET_CODE (operands[3]) == CONST_DOUBLE) | |
461 | output_asm_insn (\"fcmped %2,%%f0\;nop\", operands); | |
462 | else output_asm_insn (\"fcmped %2,%3\;nop\", operands); | |
463 | return output_scc_insn (GET_CODE (operands[1]), operands[0]); | |
464 | }") | |
465 | ||
466 | (define_insn "" | |
467 | [(set (match_operand:SI 0 "general_operand" "=r") | |
468 | (match_operator 1 "eq_or_neq" | |
469 | [(match_operand:DF 2 "general_operand" "f") | |
470 | (const_int 0)]))] | |
471 | "" | |
472 | "* | |
473 | { | |
474 | CC_STATUS_INIT; | |
475 | cc_status.value1 = operands[0]; | |
476 | cc_status.flags |= CC_IN_FCCR; | |
477 | ||
478 | make_f0_contain_0 (2); | |
479 | output_asm_insn (\"fcmped %2,%%f0\;nop\", operands); | |
480 | return output_scc_insn (GET_CODE (operands[1]), operands[0]); | |
481 | }") | |
482 | ||
483 | (define_insn "" | |
484 | [(set (match_operand:SI 0 "general_operand" "=r,r") | |
485 | (match_operator 1 "eq_or_neq" | |
486 | [(compare (match_operand:SF 2 "general_operand" "f,fG") | |
487 | (match_operand:SF 3 "general_operand" "G,f")) | |
488 | (const_int 0)]))] | |
489 | "" | |
490 | "* | |
491 | { | |
492 | CC_STATUS_INIT; | |
493 | cc_status.value1 = operands[0]; | |
494 | cc_status.flags |= CC_IN_FCCR; | |
495 | ||
496 | if (GET_CODE (operands[2]) == CONST_DOUBLE | |
497 | || GET_CODE (operands[3]) == CONST_DOUBLE) | |
498 | make_f0_contain_0 (1); | |
499 | ||
500 | if (GET_CODE (operands[2]) == CONST_DOUBLE) | |
501 | output_asm_insn (\"fcmpes %%f0,%3\;nop\", operands); | |
502 | else if (GET_CODE (operands[3]) == CONST_DOUBLE) | |
503 | output_asm_insn (\"fcmpes %2,%%f0\;nop\", operands); | |
504 | else output_asm_insn (\"fcmpes %2,%3\;nop\", operands); | |
505 | return output_scc_insn (GET_CODE (operands[1]), operands[0]); | |
506 | }") | |
507 | ||
508 | (define_insn "" | |
509 | [(set (match_operand:SI 0 "general_operand" "=r") | |
510 | (match_operator 1 "eq_or_neq" | |
511 | [(match_operand:SF 2 "general_operand" "f") | |
512 | (const_int 0)]))] | |
513 | "" | |
514 | "* | |
515 | { | |
516 | CC_STATUS_INIT; | |
517 | cc_status.value1 = operands[0]; | |
518 | cc_status.flags |= CC_IN_FCCR; | |
519 | ||
520 | make_f0_contain_0 (1); | |
521 | output_asm_insn (\"fcmpes %2,%%f0\;nop\", operands); | |
522 | return output_scc_insn (GET_CODE (operands[1]), operands[0]); | |
523 | }") | |
524 | \f | |
525 | ;; These control RTL generation for conditional jump insns | |
526 | ;; and match them for register allocation. | |
527 | ||
528 | (define_insn "beq" | |
529 | [(set (pc) | |
530 | (if_then_else (eq (cc0) | |
531 | (const_int 0)) | |
532 | (label_ref (match_operand 0 "" "")) | |
533 | (pc)))] | |
534 | "" | |
535 | "* | |
536 | { | |
537 | OUTPUT_JUMP (\"be %l0\;nop\", \"be %l0\;nop\", \"fbe %l0\;nop\"); | |
538 | }") | |
539 | ||
540 | (define_insn "bne" | |
541 | [(set (pc) | |
542 | (if_then_else (ne (cc0) | |
543 | (const_int 0)) | |
544 | (label_ref (match_operand 0 "" "")) | |
545 | (pc)))] | |
546 | "" | |
547 | "* | |
548 | { | |
549 | OUTPUT_JUMP (\"bne %l0\;nop\", \"bne %l0\;nop\", \"fbne %l0\;nop\"); | |
550 | }") | |
551 | ||
552 | (define_insn "bgt" | |
553 | [(set (pc) | |
554 | (if_then_else (gt (cc0) | |
555 | (const_int 0)) | |
556 | (label_ref (match_operand 0 "" "")) | |
557 | (pc)))] | |
558 | "" | |
559 | "* | |
560 | { | |
561 | OUTPUT_JUMP (\"bg %l0\;nop\", 0, \"fbg %l0\;nop\"); | |
562 | }") | |
563 | ||
564 | (define_insn "bgtu" | |
565 | [(set (pc) | |
566 | (if_then_else (gtu (cc0) | |
567 | (const_int 0)) | |
568 | (label_ref (match_operand 0 "" "")) | |
569 | (pc)))] | |
570 | "" | |
571 | "* | |
572 | { | |
573 | if (cc_prev_status.flags & CC_IN_FCCR) | |
574 | abort (); | |
575 | return \"bgu %l0\;nop\"; | |
576 | }") | |
577 | ||
578 | (define_insn "blt" | |
579 | [(set (pc) | |
580 | (if_then_else (lt (cc0) | |
581 | (const_int 0)) | |
582 | (label_ref (match_operand 0 "" "")) | |
583 | (pc)))] | |
584 | "" | |
585 | "* | |
586 | { | |
587 | OUTPUT_JUMP (\"bl %l0\;nop\", \"bneg %l0\;nop\", \"fbl %l0\;nop\"); | |
588 | }") | |
589 | ||
590 | (define_insn "bltu" | |
591 | [(set (pc) | |
592 | (if_then_else (ltu (cc0) | |
593 | (const_int 0)) | |
594 | (label_ref (match_operand 0 "" "")) | |
595 | (pc)))] | |
596 | "" | |
597 | "* | |
598 | { | |
599 | if (cc_prev_status.flags & CC_IN_FCCR) | |
600 | abort (); | |
601 | return \"blu %l0\;nop\"; | |
602 | }") | |
603 | ||
604 | (define_insn "bge" | |
605 | [(set (pc) | |
606 | (if_then_else (ge (cc0) | |
607 | (const_int 0)) | |
608 | (label_ref (match_operand 0 "" "")) | |
609 | (pc)))] | |
610 | "" | |
611 | "* | |
612 | { | |
613 | OUTPUT_JUMP (\"bge %l0\;nop\", \"bpos %l0\;nop\", \"fbge %l0\;nop\"); | |
614 | }") | |
615 | ||
616 | (define_insn "bgeu" | |
617 | [(set (pc) | |
618 | (if_then_else (geu (cc0) | |
619 | (const_int 0)) | |
620 | (label_ref (match_operand 0 "" "")) | |
621 | (pc)))] | |
622 | "" | |
623 | "* | |
624 | { | |
625 | if (cc_prev_status.flags & CC_IN_FCCR) | |
626 | abort (); | |
627 | return \"bgeu %l0\;nop\"; | |
628 | }") | |
629 | ||
630 | (define_insn "ble" | |
631 | [(set (pc) | |
632 | (if_then_else (le (cc0) | |
633 | (const_int 0)) | |
634 | (label_ref (match_operand 0 "" "")) | |
635 | (pc)))] | |
636 | "" | |
637 | "* | |
638 | { | |
639 | OUTPUT_JUMP (\"ble %l0\;nop\", 0, \"fble %l0\;nop\"); | |
640 | }") | |
641 | ||
642 | (define_insn "bleu" | |
643 | [(set (pc) | |
644 | (if_then_else (leu (cc0) | |
645 | (const_int 0)) | |
646 | (label_ref (match_operand 0 "" "")) | |
647 | (pc)))] | |
648 | "" | |
649 | "* | |
650 | { | |
651 | if (cc_prev_status.flags & CC_IN_FCCR) | |
652 | abort (); | |
653 | return \"bleu %l0\;nop\"; | |
654 | }") | |
655 | \f | |
656 | ;; This matches inverted jump insns for register allocation. | |
657 | ||
658 | (define_insn "" | |
659 | [(set (pc) | |
660 | (if_then_else (match_operator 0 "relop" [(cc0) (const_int 0)]) | |
661 | (pc) | |
662 | (label_ref (match_operand 1 "" ""))))] | |
663 | "" | |
664 | "* | |
665 | { | |
666 | if (cc_prev_status.flags & CC_NO_OVERFLOW) | |
667 | { | |
668 | if (GET_CODE (operands[0]) == GT || GET_CODE (operands[0]) == LE) | |
669 | /* These two conditions can't ignore overflow, | |
670 | so reinsert the deleted test instruction. */ | |
671 | return 0; | |
672 | return \"b%U0 %l1\;nop\"; | |
673 | } | |
674 | if (cc_prev_status.flags & CC_IN_FCCR) | |
675 | return \"fb%F0 %l1\;nop\"; | |
676 | return \"b%N0 %l1\;nop\"; | |
677 | }") | |
678 | \f | |
679 | ;; Move instructions | |
680 | ||
681 | (define_insn "swapsi" | |
682 | [(set (match_operand:SI 0 "general_operand" "r,rm") | |
683 | (match_operand:SI 1 "general_operand" "m,r")) | |
684 | (set (match_dup 1) (match_dup 0))] | |
685 | "" | |
686 | "* | |
687 | { | |
688 | if (GET_CODE (operands[1]) == MEM) | |
689 | { | |
690 | if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
691 | output_asm_insn (\"set %a1,%%g1\", operands), | |
692 | operands[1] = gen_rtx (MEM, SImode, gen_rtx (REG, SImode, 1)), | |
693 | cc_status.flags &= ~CC_KNOW_HI_G1; | |
694 | output_asm_insn (\"swap %1,%0\", operands); | |
695 | } | |
696 | if (REG_P (operands[0])) | |
697 | { | |
698 | if (REGNO (operands[0]) == REGNO (operands[1])) | |
699 | return \"\"; | |
700 | return \"xor %0,%1,%0\;xor %1,%0,%1\;xor %0,%1,%0\"; | |
701 | } | |
702 | if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) | |
703 | { | |
704 | output_asm_insn (\"set %a0,%%g1\", operands); | |
705 | operands[0] = gen_rtx (MEM, SImode, gen_rtx (REG, SImode, 1)); | |
706 | cc_status.flags &= ~CC_KNOW_HI_G1; | |
707 | } | |
708 | return \"swap %0,%1\"; | |
709 | }") | |
710 | ||
711 | (define_insn "movsi" | |
712 | [(set (match_operand:SI 0 "general_operand" "=r,m") | |
713 | (match_operand:SI 1 "general_operand" "rmif,rJ"))] | |
714 | "" | |
715 | "* | |
716 | { | |
717 | if (GET_CODE (operands[0]) == MEM) | |
718 | { | |
719 | if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) | |
720 | return output_store (operands); | |
721 | return \"st %r1,%0\"; | |
722 | } | |
723 | if (GET_CODE (operands[1]) == MEM) | |
724 | { | |
725 | if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
726 | return output_load_fixed (operands); | |
727 | return \"ld %1,%0\"; | |
728 | } | |
729 | if (FP_REG_P (operands[1])) | |
730 | return \"st %r1,[%%fp-4]\;ld [%%fp-4],%0\"; | |
731 | if (REG_P (operands[1]) | |
732 | || (GET_CODE (operands[1]) == CONST_INT | |
733 | && SMALL_INT (operands[1]))) | |
734 | return \"mov %1,%0\"; | |
735 | if (GET_CODE (operands[1]) == CONST_INT | |
736 | && (INTVAL (operands[1]) & 0x3ff) == 0) | |
737 | return \"sethi %%hi(%1),%0\"; | |
738 | return \"sethi %%hi(%1),%0\;or %%lo(%1),%0,%0\"; | |
739 | }") | |
740 | ||
741 | (define_insn "movhi" | |
742 | [(set (match_operand:HI 0 "general_operand" "=r,m") | |
743 | (match_operand:HI 1 "general_operand" "rmi,rJ"))] | |
744 | "" | |
745 | "* | |
746 | { | |
747 | if (GET_CODE (operands[0]) == MEM) | |
748 | { | |
749 | if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) | |
750 | return output_store (operands); | |
751 | return \"sth %r1,%0\"; | |
752 | } | |
753 | if (GET_CODE (operands[1]) == MEM) | |
754 | { | |
755 | if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
756 | return output_load_fixed (operands); | |
757 | return \"ldsh %1,%0\"; | |
758 | } | |
759 | if (REG_P (operands[1]) | |
760 | || (GET_CODE (operands[1]) == CONST_INT | |
761 | && SMALL_INT (operands[1]))) | |
762 | return \"mov %1,%0\"; | |
763 | return \"sethi %%hi(%1),%0\;or %%lo(%1),%0,%0\"; | |
764 | }") | |
765 | ||
766 | (define_insn "movqi" | |
767 | [(set (match_operand:QI 0 "general_operand" "=r,m") | |
768 | (match_operand:QI 1 "general_operand" "rmi,rJ"))] | |
769 | "" | |
770 | "* | |
771 | { | |
772 | if (GET_CODE (operands[0]) == MEM) | |
773 | { | |
774 | if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) | |
775 | return output_store (operands); | |
776 | return \"stb %r1,%0\"; | |
777 | } | |
778 | if (GET_CODE (operands[1]) == MEM) | |
779 | { | |
780 | if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
781 | return output_load_fixed (operands); | |
782 | return \"ldsb %1,%0\"; | |
783 | } | |
784 | if (REG_P (operands[1]) | |
785 | || (GET_CODE (operands[1]) == CONST_INT | |
786 | && SMALL_INT (operands[1]))) | |
787 | return \"mov %1,%0\"; | |
788 | return \"sethi %%hi(%1),%0\;or %%lo(%1),%0,%0\"; | |
789 | }") | |
790 | ||
791 | ;; The definition of this insn does not really explain what it does, | |
792 | ;; but it should suffice | |
793 | ;; that anything generated as this insn will be recognized as one | |
794 | ;; and that it won't successfully combine with anything. | |
795 | (define_expand "movstrsi" | |
796 | [(parallel [(set (mem:BLK (match_operand:BLK 0 "general_operand" "")) | |
797 | (mem:BLK (match_operand:BLK 1 "general_operand" ""))) | |
798 | (use (match_operand:SI 2 "arith32_operand" "")) | |
799 | (use (match_operand:SI 3 "immediate_operand" "")) | |
800 | (clobber (match_dup 4)) | |
801 | (clobber (match_dup 0)) | |
802 | (clobber (match_dup 1))])] | |
803 | "" | |
804 | " | |
805 | { | |
806 | operands[0] = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); | |
807 | operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); | |
808 | operands[4] = gen_reg_rtx (SImode); | |
809 | }") | |
810 | ||
811 | (define_insn "" | |
812 | [(set (mem:BLK (match_operand:SI 0 "register_operand" "r")) | |
813 | (mem:BLK (match_operand:SI 1 "register_operand" "r"))) | |
814 | (use (match_operand:SI 2 "arith32_operand" "rn")) | |
815 | (use (match_operand:SI 3 "immediate_operand" "i")) | |
816 | (clobber (match_operand:SI 4 "register_operand" "=r")) | |
817 | (clobber (match_operand:SI 5 "register_operand" "=0")) | |
818 | (clobber (match_operand:SI 6 "register_operand" "=1"))] | |
819 | "" | |
820 | "* return output_block_move (operands);") | |
821 | \f | |
822 | ;; Floating point move insns | |
823 | ||
824 | ;; This pattern forces (set (reg:DF ...) (const_double ...)) | |
825 | ;; to be reloaded by putting the constant into memory. | |
826 | ;; It must come before the more general movdf pattern. | |
827 | (define_insn "" | |
828 | [(set (match_operand:DF 0 "general_operand" "=r,f,o") | |
829 | (match_operand:DF 1 "" "mG,m,G"))] | |
830 | "GET_CODE (operands[1]) == CONST_DOUBLE" | |
831 | "* | |
832 | { | |
833 | if (FP_REG_P (operands[0])) | |
834 | return output_fp_move_double (operands); | |
835 | if (operands[1] == dconst0_rtx && GET_CODE (operands[0]) == REG) | |
836 | { | |
837 | operands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); | |
838 | return \"mov %%g0,%0\;mov %%g0,%1\"; | |
839 | } | |
840 | if (operands[1] == dconst0_rtx && GET_CODE (operands[0]) == MEM) | |
841 | { | |
842 | if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) | |
843 | { | |
844 | if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) | |
845 | && XEXP (operands[0], 0) == cc_prev_status.mdep)) | |
846 | { | |
847 | cc_status.flags |= CC_KNOW_HI_G1; | |
848 | cc_status.mdep = XEXP (operands[0], 0); | |
849 | output_asm_insn (\"sethi %%hi(%m0),%%g1\", operands); | |
850 | } | |
851 | return \"st %%g0,[%%g1+%%lo(%%m0)]\;st %%g0,[%%g1+%%lo(%%m0)+4]\"; | |
852 | } | |
853 | operands[1] = adj_offsettable_operand (operands[0], 4); | |
854 | return \"st %%g0,%0\;st %%g0,%1\"; | |
855 | } | |
856 | return output_move_double (operands); | |
857 | }") | |
858 | ||
859 | (define_insn "movdf" | |
860 | [(set (match_operand:DF 0 "general_operand" "=rm,&r,?f,?rm") | |
861 | (match_operand:DF 1 "general_operand" "r,m,rfm,f"))] | |
862 | "" | |
863 | "* | |
864 | { | |
865 | if (GET_CODE (operands[0]) == MEM | |
866 | && CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) | |
867 | return output_store (operands); | |
868 | if (GET_CODE (operands[1]) == MEM | |
869 | && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
870 | return output_load_floating (operands); | |
871 | ||
872 | if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) | |
873 | return output_fp_move_double (operands); | |
874 | return output_move_double (operands); | |
875 | }") | |
876 | ||
877 | (define_insn "movdi" | |
878 | [(set (match_operand:DI 0 "general_operand" "=rm,&r,?f,?rm") | |
879 | (match_operand:DI 1 "general_operand" "r,mi,rfm,f"))] | |
880 | "" | |
881 | "* | |
882 | { | |
883 | if (GET_CODE (operands[0]) == MEM | |
884 | && CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) | |
885 | return output_store (operands); | |
886 | if (GET_CODE (operands[1]) == MEM | |
887 | && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
888 | return output_load_fixed (operands); | |
889 | ||
890 | if (FP_REG_P (operands[0]) || FP_REG_P (operands[1])) | |
891 | return output_fp_move_double (operands); | |
892 | return output_move_double (operands); | |
893 | }") | |
894 | ||
895 | (define_insn "movsf" | |
896 | [(set (match_operand:SF 0 "general_operand" "=rf,m") | |
897 | (match_operand:SF 1 "general_operand" "rfm,rf"))] | |
898 | "" | |
899 | "* | |
900 | { | |
901 | if (GET_CODE (operands[0]) == MEM | |
902 | && CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) | |
903 | return output_store (operands); | |
904 | if (GET_CODE (operands[1]) == MEM | |
905 | && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
906 | return output_load_floating (operands); | |
907 | if (FP_REG_P (operands[0])) | |
908 | { | |
909 | if (FP_REG_P (operands[1])) | |
910 | return \"fmovs %1,%0\"; | |
911 | if (GET_CODE (operands[1]) == REG) | |
912 | return \"st %r1,[%%fp-4]\;ld [%%fp-4],%0\"; | |
913 | if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
914 | { | |
915 | cc_status.flags |= CC_KNOW_HI_G1; | |
916 | cc_status.mdep = XEXP (operands[1], 0); | |
917 | return \"sethi %%hi(%m1),%%g1\;ld [%%g1+%%lo(%m1)],%0\"; | |
918 | } | |
919 | return \"ld %1,%0\"; | |
920 | } | |
921 | if (FP_REG_P (operands[1])) | |
922 | { | |
923 | if (GET_CODE (operands[0]) == REG) | |
924 | return \"st %r1,[%%fp-4]\;ld [%%fp-4],%0\"; | |
925 | if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) | |
926 | { | |
927 | if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) | |
928 | && XEXP (operands[0], 0) == cc_prev_status.mdep)) | |
929 | { | |
930 | cc_status.flags |= CC_KNOW_HI_G1; | |
931 | cc_status.mdep = XEXP (operands[0], 0); | |
932 | output_asm_insn (\"sethi %%hi(%m0),%%g1\", operands); | |
933 | } | |
934 | return \"st %r1,[%%g1+%%lo(%m0)]\"; | |
935 | } | |
936 | return \"st %r1,%0\"; | |
937 | } | |
938 | if (GET_CODE (operands[0]) == MEM) | |
939 | return \"st %r1,%0\"; | |
940 | if (GET_CODE (operands[1]) == MEM) | |
941 | return \"ld %1,%0\"; | |
942 | return \"mov %1,%0\"; | |
943 | }") | |
944 | \f | |
945 | ;;- truncation instructions | |
946 | (define_insn "truncsiqi2" | |
947 | [(set (match_operand:QI 0 "general_operand" "=g") | |
948 | (truncate:QI | |
949 | (match_operand:SI 1 "register_operand" "r")))] | |
950 | "" | |
951 | "* | |
952 | { | |
953 | if (GET_CODE (operands[0]) == MEM) | |
954 | if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) | |
955 | { | |
956 | if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) | |
957 | && XEXP (operands[0], 0) == cc_prev_status.mdep)) | |
958 | { | |
959 | cc_status.flags |= CC_KNOW_HI_G1; | |
960 | cc_status.mdep = XEXP (operands[0], 0); | |
961 | output_asm_insn (\"sethi %%hi(%m0),%%g1\", operands); | |
962 | } | |
963 | return \"stb %1,[%%g1+%%lo(%m0)]\"; | |
964 | } | |
965 | else | |
966 | return \"stb %1,%0\"; | |
967 | return \"mov %1,%0\"; | |
968 | }") | |
969 | ||
970 | (define_insn "trunchiqi2" | |
971 | [(set (match_operand:QI 0 "general_operand" "=g") | |
972 | (truncate:QI | |
973 | (match_operand:HI 1 "register_operand" "r")))] | |
974 | "" | |
975 | "* | |
976 | { | |
977 | if (GET_CODE (operands[0]) == MEM) | |
978 | if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) | |
979 | { | |
980 | if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) | |
981 | && XEXP (operands[0], 0) == cc_prev_status.mdep)) | |
982 | { | |
983 | cc_status.flags |= CC_KNOW_HI_G1; | |
984 | cc_status.mdep = XEXP (operands[0], 0); | |
985 | output_asm_insn (\"sethi %%hi(%m0),%%g1\", operands); | |
986 | } | |
987 | return \"stb %1,[%%g1+%%lo(%m0)]\"; | |
988 | } | |
989 | else | |
990 | return \"stb %1,%0\"; | |
991 | return \"mov %1,%0\"; | |
992 | }") | |
993 | ||
994 | (define_insn "truncsihi2" | |
995 | [(set (match_operand:HI 0 "general_operand" "=g") | |
996 | (truncate:HI | |
997 | (match_operand:SI 1 "register_operand" "r")))] | |
998 | "" | |
999 | "* | |
1000 | { | |
1001 | if (GET_CODE (operands[0]) == MEM) | |
1002 | if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) | |
1003 | { | |
1004 | if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) | |
1005 | && XEXP (operands[0], 0) == cc_prev_status.mdep)) | |
1006 | { | |
1007 | cc_status.flags |= CC_KNOW_HI_G1; | |
1008 | cc_status.mdep = XEXP (operands[0], 0); | |
1009 | output_asm_insn (\"sethi %%hi(%m0),%%g1\", operands); | |
1010 | } | |
1011 | return \"sth %1,[%%g1+%%lo(%m0)]\"; | |
1012 | } | |
1013 | else | |
1014 | return \"sth %1,%0\"; | |
1015 | return \"mov %1,%0\"; | |
1016 | }") | |
1017 | \f | |
1018 | ;;- zero extension instructions | |
1019 | ||
1020 | ;; Note that the one starting from HImode comes before those for QImode | |
1021 | ;; so that a constant operand will match HImode, not QImode. | |
1022 | ||
1023 | (define_insn "zero_extendhisi2" | |
1024 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1025 | (zero_extend:SI | |
1026 | (match_operand:HI 1 "general_operand" "g")))] | |
1027 | "" | |
1028 | "* | |
1029 | { | |
1030 | if (REG_P (operands[1])) | |
1031 | return \"sll %1,0x10,%0\;srl %0,0x10,%0\"; | |
1032 | if (GET_CODE (operands[1]) == CONST_INT) | |
1033 | { | |
1034 | operands[1] = gen_rtx (CONST_INT, VOIDmode, | |
1035 | INTVAL (operands[1]) & 0xffff); | |
1036 | output_asm_insn (\"set %1,%0\", operands); | |
1037 | return \"\"; | |
1038 | } | |
1039 | if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
1040 | { | |
1041 | cc_status.flags |= CC_KNOW_HI_G1; | |
1042 | cc_status.mdep = XEXP (operands[1], 0); | |
1043 | return \"sethi %%hi(%m1),%%g1\;lduh [%%g1+%%lo(%m1)],%0\"; | |
1044 | } | |
1045 | else | |
1046 | return \"lduh %1,%0\"; | |
1047 | }") | |
1048 | ||
1049 | (define_insn "zero_extendqihi2" | |
1050 | [(set (match_operand:HI 0 "register_operand" "=r") | |
1051 | (zero_extend:HI | |
1052 | (match_operand:QI 1 "general_operand" "g")))] | |
1053 | "" | |
1054 | "* | |
1055 | { | |
1056 | if (REG_P (operands[1])) | |
1057 | return \"and %1,0xff,%0\"; | |
1058 | if (GET_CODE (operands[1]) == CONST_INT) | |
1059 | { | |
1060 | operands[1] = gen_rtx (CONST_INT, VOIDmode, | |
1061 | INTVAL (operands[1]) & 0xff); | |
1062 | output_asm_insn (\"set %1,%0\", operands); | |
1063 | return \"\"; | |
1064 | } | |
1065 | if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
1066 | { | |
1067 | cc_status.flags |= CC_KNOW_HI_G1; | |
1068 | cc_status.mdep = XEXP (operands[1], 0); | |
1069 | return \"sethi %%hi(%m1),%%g1\;ldub [%%g1+%%lo(%m1)],%0\"; | |
1070 | } | |
1071 | else | |
1072 | return \"ldub %1,%0\"; | |
1073 | }") | |
1074 | ||
1075 | (define_insn "zero_extendqisi2" | |
1076 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1077 | (zero_extend:SI | |
1078 | (match_operand:QI 1 "general_operand" "g")))] | |
1079 | "" | |
1080 | "* | |
1081 | { | |
1082 | if (REG_P (operands[1])) | |
1083 | return \"and %1,0xff,%0\"; | |
1084 | if (GET_CODE (operands[1]) == CONST_INT) | |
1085 | { | |
1086 | operands[1] = gen_rtx (CONST_INT, VOIDmode, | |
1087 | INTVAL (operands[1]) & 0xff); | |
1088 | output_asm_insn (\"set %1,%0\", operands); | |
1089 | return \"\"; | |
1090 | } | |
1091 | if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
1092 | { | |
1093 | cc_status.flags |= CC_KNOW_HI_G1; | |
1094 | cc_status.mdep = XEXP (operands[1], 0); | |
1095 | return \"sethi %%hi(%m1),%%g1\;ldub [%%g1+%%lo(%m1)],%0\"; | |
1096 | } | |
1097 | else | |
1098 | return \"ldub %1,%0\"; | |
1099 | }") | |
1100 | \f | |
1101 | ;;- sign extension instructions | |
1102 | ;; Note that the one starting from HImode comes before those for QImode | |
1103 | ;; so that a constant operand will match HImode, not QImode. | |
1104 | ||
1105 | (define_insn "extendhisi2" | |
1106 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1107 | (sign_extend:SI | |
1108 | (match_operand:HI 1 "general_operand" "g")))] | |
1109 | "" | |
1110 | "* | |
1111 | { | |
1112 | if (REG_P (operands[1])) | |
1113 | return \"sll %1,0x10,%0\;sra %0,0x10,%0\"; | |
1114 | if (GET_CODE (operands[1]) == CONST_INT) | |
1115 | { | |
1116 | int i = (short)INTVAL (operands[1]); | |
1117 | operands[1] = gen_rtx (CONST_INT, VOIDmode, i); | |
1118 | output_asm_insn (\"set %1,%0\", operands); | |
1119 | return \"\"; | |
1120 | } | |
1121 | if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
1122 | { | |
1123 | cc_status.flags |= CC_KNOW_HI_G1; | |
1124 | cc_status.mdep = XEXP (operands[1], 0); | |
1125 | return \"sethi %%hi(%m1),%%g1\;ldsh [%%g1+%%lo(%m1)],%0\"; | |
1126 | } | |
1127 | else | |
1128 | return \"ldsh %1,%0\"; | |
1129 | }") | |
1130 | ||
1131 | (define_insn "extendqihi2" | |
1132 | [(set (match_operand:HI 0 "register_operand" "=r") | |
1133 | (sign_extend:HI | |
1134 | (match_operand:QI 1 "general_operand" "g")))] | |
1135 | "" | |
1136 | "* | |
1137 | { | |
1138 | if (REG_P (operands[1])) | |
1139 | return \"sll %1,0x18,%0\;sra %0,0x18,%0\"; | |
1140 | if (GET_CODE (operands[1]) == CONST_INT) | |
1141 | { | |
1142 | int i = (char)INTVAL (operands[1]); | |
1143 | operands[1] = gen_rtx (CONST_INT, VOIDmode, i); | |
1144 | output_asm_insn (\"set %1,%0\", operands); | |
1145 | return \"\"; | |
1146 | } | |
1147 | if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
1148 | { | |
1149 | cc_status.flags |= CC_KNOW_HI_G1; | |
1150 | cc_status.mdep = XEXP (operands[1], 0); | |
1151 | return \"sethi %%hi(%m1),%%g1\;ldsb [%%g1+%%lo(%m1)],%0\"; | |
1152 | } | |
1153 | else | |
1154 | return \"ldsb %1,%0\"; | |
1155 | }") | |
1156 | ||
1157 | (define_insn "extendqisi2" | |
1158 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1159 | (sign_extend:SI | |
1160 | (match_operand:QI 1 "general_operand" "g")))] | |
1161 | "" | |
1162 | "* | |
1163 | { | |
1164 | if (REG_P (operands[1])) | |
1165 | return \"sll %1,0x18,%0\;sra %0,0x18,%0\"; | |
1166 | if (GET_CODE (operands[1]) == CONST_INT) | |
1167 | { | |
1168 | int i = (char)INTVAL (operands[1]); | |
1169 | operands[1] = gen_rtx (CONST_INT, VOIDmode, i); | |
1170 | output_asm_insn (\"set %1,%0\", operands); | |
1171 | return \"\"; | |
1172 | } | |
1173 | if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
1174 | { | |
1175 | cc_status.flags |= CC_KNOW_HI_G1; | |
1176 | cc_status.mdep = XEXP (operands[1], 0); | |
1177 | return \"sethi %%hi(%m1),%%g1\;ldsb [%%g1+%%lo(%m1)],%0\"; | |
1178 | } | |
1179 | else | |
1180 | return \"ldsb %1,%0\"; | |
1181 | }") | |
1182 | ||
1183 | ;; Signed bitfield extractions come out looking like | |
1184 | ;; (shiftrt (shift (sign_extend <Y>) <C1>) <C2>) | |
1185 | ;; which we expand poorly as four shift insns. | |
1186 | ;; These patters yeild two shifts: | |
1187 | ;; (shiftrt (shift <Y> <C3>) <C4>) | |
1188 | (define_insn "" | |
1189 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1190 | (ashiftrt:SI | |
1191 | (sign_extend:SI | |
1192 | (match_operand:QI 1 "register_operand" "r")) | |
1193 | (match_operand:SI 2 "small_int" "n")))] | |
1194 | "" | |
1195 | "sll %1,0x18,%0\;sra %0,0x18+%2,%0") | |
1196 | ||
1197 | (define_insn "" | |
1198 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1199 | (ashiftrt:SI | |
1200 | (sign_extend:SI | |
1201 | (subreg:QI (ashift:SI (match_operand:SI 1 "register_operand" "r") | |
1202 | (match_operand:SI 2 "small_int" "n")) 0)) | |
1203 | (match_operand:SI 3 "small_int" "n")))] | |
1204 | "" | |
1205 | "sll %1,0x18+%2,%0\;sra %0,0x18+%3,%0") | |
1206 | \f | |
1207 | ;; Special patterns for optimizing bit-field instructions. | |
1208 | ||
1209 | ;; First two patterns are for bitfields that came from memory | |
1210 | ;; testing only the high bit. They work with old combiner. | |
1211 | ;; @@ Actually, the second pattern does not work if we | |
1212 | ;; @@ need to set the N bit. | |
1213 | (define_insn "" | |
1214 | [(set (cc0) | |
1215 | (zero_extend:SI (subreg:QI (lshiftrt:SI (match_operand:SI 0 "register_operand" "r") | |
1216 | (const_int 7)) 0)))] | |
1217 | "0" | |
1218 | "andcc %0,128,%%g0") | |
1219 | ||
1220 | (define_insn "" | |
1221 | [(set (cc0) | |
1222 | (sign_extend:SI (subreg:QI (ashiftrt:SI (match_operand:SI 0 "register_operand" "r") | |
1223 | (const_int 7)) 0)))] | |
1224 | "0" | |
1225 | "andcc %0,128,%%g0") | |
1226 | ||
1227 | ;; next two patterns are good for bitfields coming from memory | |
1228 | ;; (via pseudo-register) or from a register, though this optimization | |
1229 | ;; is only good for values contained wholly within the bottom 13 bits | |
1230 | (define_insn "" | |
1231 | [(set (cc0) | |
1232 | (and:SI (lshiftrt:SI (match_operand:SI 0 "register_operand" "r") | |
1233 | (match_operand:SI 1 "small_int" "n")) | |
1234 | (match_operand:SI 2 "small_int" "n")))] | |
1235 | "(unsigned)((INTVAL (operands[2]) << INTVAL (operands[1])) + 0x1000) < 0x2000" | |
1236 | "andcc %0,%2<<%1,%%g0") | |
1237 | ||
1238 | (define_insn "" | |
1239 | [(set (cc0) | |
1240 | (and:SI (ashiftrt:SI (match_operand:SI 0 "register_operand" "r") | |
1241 | (match_operand:SI 1 "small_int" "n")) | |
1242 | (match_operand:SI 2 "small_int" "n")))] | |
1243 | "(unsigned)((INTVAL (operands[2]) << INTVAL (operands[1])) + 0x1000) < 0x2000" | |
1244 | "andcc %0,%2<<%1,%%g0") | |
1245 | \f | |
1246 | ;; Conversions between float and double. | |
1247 | ||
1248 | (define_insn "extendsfdf2" | |
1249 | [(set (match_operand:DF 0 "register_operand" "=f") | |
1250 | (float_extend:DF | |
1251 | (match_operand:SF 1 "register_operand" "f")))] | |
1252 | "" | |
1253 | "fstod %1,%0") | |
1254 | ||
1255 | (define_insn "truncdfsf2" | |
1256 | [(set (match_operand:SF 0 "register_operand" "=f") | |
1257 | (float_truncate:SF | |
1258 | (match_operand:DF 1 "register_operand" "f")))] | |
1259 | "" | |
1260 | "fdtos %1,%0") | |
1261 | \f | |
1262 | ;; Conversion between fixed point and floating point. | |
1263 | ;; Note that among the fix-to-float insns | |
1264 | ;; the ones that start with SImode come first. | |
1265 | ;; That is so that an operand that is a CONST_INT | |
1266 | ;; (and therefore lacks a specific machine mode). | |
1267 | ;; will be recognized as SImode (which is always valid) | |
1268 | ;; rather than as QImode or HImode. | |
1269 | ||
1270 | ;; This pattern forces (set (reg:SF ...) (float:SF (const_int ...))) | |
1271 | ;; to be reloaded by putting the constant into memory. | |
1272 | ;; It must come before the more general floatsisf2 pattern. | |
1273 | (define_insn "" | |
1274 | [(set (match_operand:SF 0 "general_operand" "=f") | |
1275 | (float:SF (match_operand 1 "" "m")))] | |
1276 | "GET_CODE (operands[1]) == CONST_INT" | |
1277 | "* | |
1278 | { | |
1279 | if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
1280 | { | |
1281 | cc_status.flags |= CC_KNOW_HI_G1; | |
1282 | cc_status.mdep = XEXP (operands[1], 0); | |
1283 | return \"sethi %%hi(%m1),%%g1\;ld [%%g1+%%lo(%m1)],%0\;fitos %0,%0\"; | |
1284 | } | |
1285 | return \"ld %1,%0\;fitos %0,%0\"; | |
1286 | }") | |
1287 | ||
1288 | (define_insn "floatsisf2" | |
1289 | [(set (match_operand:SF 0 "general_operand" "=f") | |
1290 | (float:SF (match_operand:SI 1 "general_operand" "rfm")))] | |
1291 | "" | |
1292 | "* | |
1293 | { | |
1294 | if (GET_CODE (operands[1]) == MEM) | |
1295 | if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
1296 | { | |
1297 | cc_status.flags |= CC_KNOW_HI_G1; | |
1298 | cc_status.mdep = XEXP (operands[1], 0); | |
1299 | return \"sethi %%hi(%m1),%%g1\;ld [%%g1+%%lo(%m1)],%0\;fitos %0,%0\"; | |
1300 | } | |
1301 | else | |
1302 | return \"ld %1,%0\;fitos %0,%0\"; | |
1303 | else if (FP_REG_P (operands[1])) | |
1304 | return \"fitos %1,%0\"; | |
1305 | return \"st %r1,[%%fp-4]\;ld [%%fp-4],%0\;fitos %0,%0\"; | |
1306 | }") | |
1307 | ||
1308 | ;; This pattern forces (set (reg:DF ...) (float:DF (const_int ...))) | |
1309 | ;; to be reloaded by putting the constant into memory. | |
1310 | ;; It must come before the more general floatsidf2 pattern. | |
1311 | (define_insn "" | |
1312 | [(set (match_operand:DF 0 "general_operand" "=f") | |
1313 | (float:DF (match_operand 1 "" "m")))] | |
1314 | "GET_CODE (operands[1]) == CONST_INT" | |
1315 | "* | |
1316 | { | |
1317 | if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
1318 | { | |
1319 | cc_status.flags |= CC_KNOW_HI_G1; | |
1320 | cc_status.mdep = XEXP (operands[1], 0); | |
1321 | return \"sethi %%hi(%m1),%%g1\;ld [%%g1+%%lo(%m1)],%0\;fitod %0,%0\"; | |
1322 | } | |
1323 | return \"ld %1,%0\;fitod %0,%0\"; | |
1324 | }") | |
1325 | ||
1326 | (define_insn "floatsidf2" | |
1327 | [(set (match_operand:DF 0 "general_operand" "=f") | |
1328 | (float:DF (match_operand:SI 1 "general_operand" "rfm")))] | |
1329 | "" | |
1330 | "* | |
1331 | { | |
1332 | if (GET_CODE (operands[1]) == MEM) | |
1333 | if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
1334 | { | |
1335 | cc_status.flags |= CC_KNOW_HI_G1; | |
1336 | cc_status.mdep = XEXP (operands[1], 0); | |
1337 | return \"sethi %%hi(%m1),%%g1\;ld [%%g1+%%lo(%m1)],%0\;fitod %0,%0\"; | |
1338 | } | |
1339 | else | |
1340 | return \"ld %1,%0\;fitod %0,%0\"; | |
1341 | else if (FP_REG_P (operands[1])) | |
1342 | return \"fitod %1,%0\"; | |
1343 | else | |
1344 | return \"st %r1,[%%fp-4]\;ld [%%fp-4],%0\;fitod %0,%0\"; | |
1345 | }") | |
1346 | ||
1347 | ;; Convert a float to an actual integer. | |
1348 | ;; Truncation is performed as part of the conversion. | |
1349 | (define_insn "fix_truncsfsi2" | |
1350 | [(set (match_operand:SI 0 "general_operand" "=rm") | |
1351 | (fix:SI (fix:SF (match_operand:SF 1 "general_operand" "fm"))))] | |
1352 | "" | |
1353 | "* | |
1354 | { | |
1355 | cc_status.flags &= ~(CC_F1_IS_0); | |
1356 | if (FP_REG_P (operands[1])) | |
1357 | output_asm_insn (\"fstoi %1,%%f1\", operands); | |
1358 | else if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
1359 | { | |
1360 | cc_status.flags |= CC_KNOW_HI_G1; | |
1361 | cc_status.mdep = XEXP (operands[1], 0); | |
1362 | output_asm_insn (\"sethi %%hi(%m1),%%g1\;ld [%%g1+%%lo(%m1)],%%f1\;fstoi %%f1,%%f1\", operands); | |
1363 | } | |
1364 | else | |
1365 | output_asm_insn (\"ld %1,%%f1\;fstoi %%f1,%%f1\", operands); | |
1366 | if (GET_CODE (operands[0]) == MEM) | |
1367 | if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) | |
1368 | { | |
1369 | if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) | |
1370 | && XEXP (operands[0], 0) == cc_prev_status.mdep)) | |
1371 | { | |
1372 | cc_status.flags |= CC_KNOW_HI_G1; | |
1373 | cc_status.mdep = XEXP (operands[0], 0); | |
1374 | output_asm_insn (\"sethi %%hi(%m0),%%g1\", operands); | |
1375 | } | |
1376 | return \"st %%f1,[%%g1+%%lo(%m0)]\"; | |
1377 | } | |
1378 | else | |
1379 | return \"st %%f1,%0\"; | |
1380 | else | |
1381 | return \"st %%f1,[%%fp-4]\;ld [%%fp-4],%0\"; | |
1382 | }") | |
1383 | ||
1384 | (define_insn "fix_truncdfsi2" | |
1385 | [(set (match_operand:SI 0 "general_operand" "=rm") | |
1386 | (fix:SI (fix:DF (match_operand:DF 1 "general_operand" "fm"))))] | |
1387 | "" | |
1388 | "* | |
1389 | { | |
1390 | cc_status.flags &= ~CC_F0_IS_0; | |
1391 | if (FP_REG_P (operands[1])) | |
1392 | output_asm_insn (\"fdtoi %1,%%f0\", operands); | |
1393 | else | |
1394 | { | |
1395 | rtx xoperands[2]; | |
1396 | xoperands[0] = gen_rtx (REG, DFmode, 32); | |
1397 | xoperands[1] = operands[1]; | |
1398 | output_asm_insn (output_fp_move_double (xoperands), xoperands); | |
1399 | output_asm_insn (\"fdtoi %%f0,%%f0\", 0); | |
1400 | } | |
1401 | if (GET_CODE (operands[0]) == MEM) | |
1402 | if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) | |
1403 | { | |
1404 | if (! ((cc_prev_status.flags & CC_KNOW_HI_G1) | |
1405 | && XEXP (operands[0], 0) == cc_prev_status.mdep)) | |
1406 | { | |
1407 | cc_status.flags |= CC_KNOW_HI_G1; | |
1408 | cc_status.mdep = XEXP (operands[0], 0); | |
1409 | output_asm_insn (\"sethi %%hi(%m0),%%g1\", operands); | |
1410 | } | |
1411 | return \"st %%f0,[%%g1+%%lo(%m0)]\"; | |
1412 | } | |
1413 | else | |
1414 | return \"st %%f0,%0\"; | |
1415 | else | |
1416 | return \"st %%f0,[%%fp-4]\;ld [%%fp-4],%0\"; | |
1417 | }") | |
1418 | \f | |
1419 | ;;- arithmetic instructions | |
1420 | ||
1421 | (define_insn "addsi3" | |
1422 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1423 | (plus:SI (match_operand:SI 1 "arith32_operand" "%r") | |
1424 | (match_operand:SI 2 "arith32_operand" "rn")))] | |
1425 | "" | |
1426 | "* | |
1427 | { | |
1428 | if (REG_P (operands[2])) | |
1429 | return \"add %1,%2,%0\"; | |
1430 | if (SMALL_INT (operands[2])) | |
1431 | return \"add %1,%2,%0\"; | |
1432 | cc_status.flags &= ~CC_KNOW_HI_G1; | |
1433 | return \"sethi %%hi(%2),%%g1\;or %%lo(%2),%%g1,%%g1\;add %1,%%g1,%0\"; | |
1434 | }") | |
1435 | ||
1436 | (define_insn "subsi3" | |
1437 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1438 | (minus:SI (match_operand:SI 1 "register_operand" "r") | |
1439 | (match_operand:SI 2 "arith32_operand" "rn")))] | |
1440 | "" | |
1441 | "* | |
1442 | { | |
1443 | if (REG_P (operands[2])) | |
1444 | return \"sub %1,%2,%0\"; | |
1445 | if (SMALL_INT (operands[2])) | |
1446 | return \"sub %1,%2,%0\"; | |
1447 | cc_status.flags &= ~CC_KNOW_HI_G1; | |
1448 | return \"sethi %%hi(%2),%%g1\;or %%lo(%2),%%g1,%%g1\;sub %1,%%g1,%0\"; | |
1449 | }") | |
1450 | ||
1451 | (define_expand "mulsi3" | |
1452 | [(set (match_operand:SI 0 "register_operand" "r") | |
1453 | (mult:SI (match_operand:SI 1 "general_operand" "") | |
1454 | (match_operand:SI 2 "general_operand" "")))] | |
1455 | "" | |
1456 | " | |
1457 | { | |
1458 | rtx src; | |
1459 | ||
1460 | if (GET_CODE (operands[1]) == CONST_INT) | |
1461 | if (GET_CODE (operands[2]) == CONST_INT) | |
1462 | { | |
1463 | emit_move_insn (operands[0], | |
1464 | gen_rtx (CONST_INT, VOIDmode, | |
1465 | INTVAL (operands[1]) * INTVAL (operands[2]))); | |
1466 | DONE; | |
1467 | } | |
1468 | else | |
1469 | src = gen_rtx (MULT, SImode, | |
1470 | copy_to_mode_reg (SImode, operands[2]), | |
1471 | operands[1]); | |
1472 | else if (GET_CODE (operands[2]) == CONST_INT) | |
1473 | src = gen_rtx (MULT, SImode, | |
1474 | copy_to_mode_reg (SImode, operands[1]), | |
1475 | operands[2]); | |
1476 | else src = 0; | |
1477 | ||
1478 | if (src) | |
1479 | emit_insn (gen_rtx (SET, VOIDmode, operands[0], src)); | |
1480 | else | |
1481 | emit_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (5, | |
1482 | gen_rtx (SET, VOIDmode, operands[0], | |
1483 | gen_rtx (MULT, SImode, operands[1], operands[2])), | |
1484 | gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 8)), | |
1485 | gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 9)), | |
1486 | gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 12)), | |
1487 | gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 13))))); | |
1488 | DONE; | |
1489 | }") | |
1490 | ||
1491 | (define_expand "umulsi3" | |
1492 | [(set (match_operand:SI 0 "register_operand" "r") | |
1493 | (umult:SI (match_operand:SI 1 "general_operand" "") | |
1494 | (match_operand:SI 2 "general_operand" "")))] | |
1495 | "" | |
1496 | " | |
1497 | { | |
1498 | rtx src; | |
1499 | ||
1500 | if (GET_CODE (operands[1]) == CONST_INT) | |
1501 | if (GET_CODE (operands[2]) == CONST_INT) | |
1502 | { | |
1503 | emit_move_insn (operands[0], | |
1504 | gen_rtx (CONST_INT, VOIDmode, | |
1505 | (unsigned)INTVAL (operands[1]) * (unsigned)INTVAL (operands[2]))); | |
1506 | DONE; | |
1507 | } | |
1508 | else | |
1509 | src = gen_rtx (UMULT, SImode, | |
1510 | copy_to_mode_reg (SImode, operands[2]), | |
1511 | operands[1]); | |
1512 | else if (GET_CODE (operands[2]) == CONST_INT) | |
1513 | src = gen_rtx (UMULT, SImode, | |
1514 | copy_to_mode_reg (SImode, operands[1]), | |
1515 | operands[2]); | |
1516 | else src = 0; | |
1517 | ||
1518 | if (src) | |
1519 | emit_insn (gen_rtx (SET, VOIDmode, operands[0], src)); | |
1520 | else | |
1521 | emit_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (5, | |
1522 | gen_rtx (SET, VOIDmode, operands[0], | |
1523 | gen_rtx (UMULT, SImode, operands[1], operands[2])), | |
1524 | gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 8)), | |
1525 | gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 9)), | |
1526 | gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 12)), | |
1527 | gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 13))))); | |
1528 | DONE; | |
1529 | }") | |
1530 | ||
1531 | (define_insn "" | |
1532 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1533 | (mult:SI (match_operand:SI 1 "register_operand" "r") | |
1534 | (match_operand:SI 2 "immediate_operand" "n")))] | |
1535 | "" | |
1536 | "* return output_mul_by_constant (insn, operands, 0);") | |
1537 | ||
1538 | (define_insn "" | |
1539 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1540 | (umult:SI (match_operand:SI 1 "register_operand" "r") | |
1541 | (match_operand:SI 2 "immediate_operand" "n")))] | |
1542 | "" | |
1543 | "* return output_mul_by_constant (insn, operands, 1);") | |
1544 | ||
1545 | (define_insn "" | |
1546 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1547 | (mult:SI (match_operand:SI 1 "general_operand" "%r") | |
1548 | (match_operand:SI 2 "general_operand" "r"))) | |
1549 | (clobber (reg:SI 8)) | |
1550 | (clobber (reg:SI 9)) | |
1551 | (clobber (reg:SI 12)) | |
1552 | (clobber (reg:SI 13))] | |
1553 | "" | |
1554 | "* return output_mul_insn (operands, 0);") | |
1555 | ||
1556 | (define_insn "" | |
1557 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1558 | (umult:SI (match_operand:SI 1 "general_operand" "%r") | |
1559 | (match_operand:SI 2 "general_operand" "r"))) | |
1560 | (clobber (reg:SI 8)) | |
1561 | (clobber (reg:SI 9)) | |
1562 | (clobber (reg:SI 12)) | |
1563 | (clobber (reg:SI 13))] | |
1564 | "" | |
1565 | "* return output_mul_insn (operands, 1);") | |
1566 | ||
1567 | ;; this pattern is needed because cse may eliminate the multiplication, | |
1568 | ;; but leave the clobbers behind. | |
1569 | ||
1570 | (define_insn "" | |
1571 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1572 | (match_operand:SI 1 "general_operand" "g")) | |
1573 | (clobber (reg:SI 8)) | |
1574 | (clobber (reg:SI 9)) | |
1575 | (clobber (reg:SI 12)) | |
1576 | (clobber (reg:SI 13))] | |
1577 | "" | |
1578 | "* | |
1579 | { | |
1580 | if (GET_CODE (operands[1]) == CONST_INT) | |
1581 | { | |
1582 | if (SMALL_INT (operands[1])) | |
1583 | return \"mov %1,%0\"; | |
1584 | return \"sethi %%hi(%1),%0\;or %%lo(%1),%0,%0\"; | |
1585 | } | |
1586 | if (GET_CODE (operands[1]) == MEM) | |
1587 | return \"ld %1,%0\"; | |
1588 | return \"mov %1,%0\"; | |
1589 | }") | |
1590 | ||
1591 | ;; In case constant factor turns out to be -1. | |
1592 | (define_insn "" | |
1593 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1594 | (neg:SI (match_operand:SI 1 "general_operand" "rI"))) | |
1595 | (clobber (reg:SI 8)) | |
1596 | (clobber (reg:SI 9)) | |
1597 | (clobber (reg:SI 12)) | |
1598 | (clobber (reg:SI 13))] | |
1599 | "" | |
1600 | "sub %%g0,%1,%0") | |
1601 | ||
1602 | ;;- and instructions (with compliment also) | |
1603 | (define_insn "andsi3" | |
1604 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1605 | (and:SI (match_operand:SI 1 "arith32_operand" "%r") | |
1606 | (match_operand:SI 2 "arith32_operand" "rn")))] | |
1607 | "" | |
1608 | "* | |
1609 | { | |
1610 | if (REG_P (operands[2]) || SMALL_INT (operands[2])) | |
1611 | return \"and %1,%2,%0\"; | |
1612 | cc_status.flags &= ~CC_KNOW_HI_G1; | |
1613 | return \"sethi %%hi(%2),%%g1\;or %%lo(%2),%%g1,%%g1\;and %1,%%g1,%0\"; | |
1614 | }") | |
1615 | ||
1616 | (define_insn "andcbsi3" | |
1617 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1618 | (and:SI (match_operand:SI 1 "register_operand" "r") | |
1619 | (not:SI (match_operand:SI 2 "register_operand" "r"))))] | |
1620 | "" | |
1621 | "andn %1,%2,%0") | |
1622 | ||
1623 | (define_insn "iorsi3" | |
1624 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1625 | (ior:SI (match_operand:SI 1 "arith32_operand" "%r") | |
1626 | (match_operand:SI 2 "arith32_operand" "rn")))] | |
1627 | "" | |
1628 | "* | |
1629 | { | |
1630 | if (REG_P (operands[2]) || SMALL_INT (operands[2])) | |
1631 | return \"or %1,%2,%0\"; | |
1632 | cc_status.flags &= ~CC_KNOW_HI_G1; | |
1633 | return \"sethi %%hi(%2),%%g1\;or %%lo(%2),%%g1,%%g1\;or %1,%%g1,%0\"; | |
1634 | }") | |
1635 | ||
1636 | (define_insn "iorcbsi3" | |
1637 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1638 | (ior:SI (match_operand:SI 1 "register_operand" "r") | |
1639 | (not:SI (match_operand:SI 2 "register_operand" "r"))))] | |
1640 | "" | |
1641 | "orn %1,%2,%0") | |
1642 | ||
1643 | (define_insn "xorsi3" | |
1644 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1645 | (xor:SI (match_operand:SI 1 "arith32_operand" "%r") | |
1646 | (match_operand:SI 2 "arith32_operand" "rn")))] | |
1647 | "" | |
1648 | "* | |
1649 | { | |
1650 | if (REG_P (operands[2]) || SMALL_INT (operands[2])) | |
1651 | return \"xor %1,%2,%0\"; | |
1652 | cc_status.flags &= ~CC_KNOW_HI_G1; | |
1653 | return \"sethi %%hi(%2),%%g1\;or %%lo(%2),%%g1,%%g1\;xor %1,%%g1,%0\"; | |
1654 | }") | |
1655 | ||
1656 | (define_insn "xorcbsi3" | |
1657 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1658 | (xor:SI (match_operand:SI 1 "register_operand" "r") | |
1659 | (not:SI (match_operand:SI 2 "register_operand" "r"))))] | |
1660 | "" | |
1661 | "xnor %1,%2,%0") | |
1662 | ||
1663 | ;; We cannot use the "neg" pseudo insn because the Sun assembler | |
1664 | ;; does not know how to make it work for constants. | |
1665 | (define_insn "negsi2" | |
1666 | [(set (match_operand:SI 0 "general_operand" "=r") | |
1667 | (neg:SI (match_operand:SI 1 "arith_operand" "rI")))] | |
1668 | "" | |
1669 | "sub %%g0,%1,%0") | |
1670 | ||
1671 | ;; We cannot use the "not" pseudo insn because the Sun assembler | |
1672 | ;; does not know how to make it work for constants. | |
1673 | (define_insn "one_cmplsi2" | |
1674 | [(set (match_operand:SI 0 "general_operand" "=r") | |
1675 | (not:SI (match_operand:SI 1 "arith_operand" "rI")))] | |
1676 | "" | |
1677 | "xnor %%g0,%1,%0") | |
1678 | \f | |
1679 | ;; Floating point arithmetic instructions. | |
1680 | ||
1681 | (define_insn "adddf3" | |
1682 | [(set (match_operand:DF 0 "register_operand" "=f") | |
1683 | (plus:DF (match_operand:DF 1 "register_operand" "f") | |
1684 | (match_operand:DF 2 "register_operand" "f")))] | |
1685 | "" | |
1686 | "faddd %1,%2,%0") | |
1687 | ||
1688 | (define_insn "addsf3" | |
1689 | [(set (match_operand:SF 0 "register_operand" "=f") | |
1690 | (plus:SF (match_operand:SF 1 "register_operand" "f") | |
1691 | (match_operand:SF 2 "register_operand" "f")))] | |
1692 | "" | |
1693 | "fadds %1,%2,%0") | |
1694 | ||
1695 | (define_insn "subdf3" | |
1696 | [(set (match_operand:DF 0 "register_operand" "=f") | |
1697 | (minus:DF (match_operand:DF 1 "register_operand" "f") | |
1698 | (match_operand:DF 2 "register_operand" "f")))] | |
1699 | "" | |
1700 | "fsubd %1,%2,%0") | |
1701 | ||
1702 | (define_insn "subsf3" | |
1703 | [(set (match_operand:SF 0 "register_operand" "=f") | |
1704 | (minus:SF (match_operand:SF 1 "register_operand" "f") | |
1705 | (match_operand:SF 2 "register_operand" "f")))] | |
1706 | "" | |
1707 | "fsubs %1,%2,%0") | |
1708 | ||
1709 | (define_insn "muldf3" | |
1710 | [(set (match_operand:DF 0 "register_operand" "=f") | |
1711 | (mult:DF (match_operand:DF 1 "register_operand" "f") | |
1712 | (match_operand:DF 2 "register_operand" "f")))] | |
1713 | "" | |
1714 | "fmuld %1,%2,%0") | |
1715 | ||
1716 | (define_insn "mulsf3" | |
1717 | [(set (match_operand:SF 0 "register_operand" "=f") | |
1718 | (mult:SF (match_operand:SF 1 "register_operand" "f") | |
1719 | (match_operand:SF 2 "register_operand" "f")))] | |
1720 | "" | |
1721 | "fmuls %1,%2,%0") | |
1722 | ||
1723 | (define_insn "divdf3" | |
1724 | [(set (match_operand:DF 0 "register_operand" "=f") | |
1725 | (div:DF (match_operand:DF 1 "register_operand" "f") | |
1726 | (match_operand:DF 2 "register_operand" "f")))] | |
1727 | "" | |
1728 | "fdivd %1,%2,%0") | |
1729 | ||
1730 | (define_insn "divsf3" | |
1731 | [(set (match_operand:SF 0 "register_operand" "=f") | |
1732 | (div:SF (match_operand:SF 1 "register_operand" "f") | |
1733 | (match_operand:SF 2 "register_operand" "f")))] | |
1734 | "" | |
1735 | "fdivs %1,%2,%0") | |
1736 | ||
1737 | (define_insn "negdf2" | |
1738 | [(set (match_operand:DF 0 "register_operand" "=f") | |
1739 | (neg:DF (match_operand:DF 1 "register_operand" "f")))] | |
1740 | "" | |
1741 | "* | |
1742 | { | |
1743 | output_asm_insn (\"fnegs %1,%0\", operands); | |
1744 | if (REGNO (operands[0]) != REGNO (operands[1])) | |
1745 | { | |
1746 | operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1); | |
1747 | operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1); | |
1748 | output_asm_insn (\"fmovs %1,%0\", operands); | |
1749 | } | |
1750 | return \"\"; | |
1751 | }") | |
1752 | ||
1753 | (define_insn "negsf2" | |
1754 | [(set (match_operand:SF 0 "register_operand" "=f") | |
1755 | (neg:SF (match_operand:SF 1 "register_operand" "f")))] | |
1756 | "" | |
1757 | "fnegs %1,%0") | |
1758 | ||
1759 | (define_insn "absdf2" | |
1760 | [(set (match_operand:DF 0 "register_operand" "=f") | |
1761 | (abs:DF (match_operand:DF 1 "register_operand" "f")))] | |
1762 | "" | |
1763 | "* | |
1764 | { | |
1765 | output_asm_insn (\"fabss %1,%0\", operands); | |
1766 | if (REGNO (operands[0]) != REGNO (operands[1])) | |
1767 | { | |
1768 | operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1); | |
1769 | operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1); | |
1770 | output_asm_insn (\"fmovs %1,%0\", operands); | |
1771 | } | |
1772 | return \"\"; | |
1773 | }") | |
1774 | ||
1775 | (define_insn "abssf2" | |
1776 | [(set (match_operand:SF 0 "register_operand" "=f") | |
1777 | (abs:SF (match_operand:SF 1 "register_operand" "f")))] | |
1778 | "" | |
1779 | "fabss %1,%0") | |
1780 | \f | |
1781 | ;; Shift instructions | |
1782 | ||
1783 | ;; Optimized special case of shifting. | |
1784 | ;; Must precede the general case. | |
1785 | ||
1786 | (define_insn "" | |
1787 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1788 | (ashiftrt:SI (match_operand:SI 1 "memory_operand" "m") | |
1789 | (const_int 24)))] | |
1790 | "" | |
1791 | "* | |
1792 | { | |
1793 | if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
1794 | { | |
1795 | cc_status.flags |= CC_KNOW_HI_G1; | |
1796 | cc_status.mdep = XEXP (operands[1], 0); | |
1797 | return \"sethi %%hi(%m1),%%g1\;ldsb [%%g1+%%lo(%m1)],%0\"; | |
1798 | } | |
1799 | return \"ldsb %1,%0\"; | |
1800 | }") | |
1801 | ||
1802 | (define_insn "" | |
1803 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1804 | (lshiftrt:SI (match_operand:SI 1 "memory_operand" "m") | |
1805 | (const_int 24)))] | |
1806 | "" | |
1807 | "* | |
1808 | { | |
1809 | if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
1810 | { | |
1811 | cc_status.flags |= CC_KNOW_HI_G1; | |
1812 | cc_status.mdep = XEXP (operands[1], 0); | |
1813 | return \"sethi %%hi(%m1),%%g1\;ldub [%%g1+%%lo(%m1)],%0\"; | |
1814 | } | |
1815 | return \"ldub %1,%0\"; | |
1816 | }") | |
1817 | \f | |
1818 | ;;- arithmetic shift instructions | |
1819 | (define_insn "ashlsi3" | |
1820 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1821 | (ashift:SI (match_operand:SI 1 "register_operand" "r") | |
1822 | (match_operand:SI 2 "arith32_operand" "rn")))] | |
1823 | "" | |
1824 | "* | |
1825 | { | |
1826 | if (GET_CODE (operands[2]) == CONST_INT | |
1827 | && INTVAL (operands[2]) >= 32) | |
1828 | operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 31); | |
1829 | return \"sll %1,%2,%0\"; | |
1830 | }") | |
1831 | ||
1832 | (define_insn "ashrsi3" | |
1833 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1834 | (ashiftrt:SI (match_operand:SI 1 "register_operand" "r") | |
1835 | (match_operand:SI 2 "arith32_operand" "rn")))] | |
1836 | "" | |
1837 | "* | |
1838 | { | |
1839 | if (GET_CODE (operands[2]) == CONST_INT | |
1840 | && INTVAL (operands[2]) >= 32) | |
1841 | operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 31); | |
1842 | return \"sra %1,%2,%0\"; | |
1843 | }") | |
1844 | ||
1845 | (define_insn "lshrsi3" | |
1846 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1847 | (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") | |
1848 | (match_operand:SI 2 "arith32_operand" "rn")))] | |
1849 | "" | |
1850 | "* | |
1851 | { | |
1852 | if (GET_CODE (operands[2]) == CONST_INT | |
1853 | && INTVAL (operands[2]) >= 32) | |
1854 | operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 31); | |
1855 | return \"srl %1,%2,%0\"; | |
1856 | }") | |
1857 | \f | |
1858 | ;; Unconditional and other jump instructions | |
1859 | ;; Note that for the Sparc, by setting the annul bit on an unconditional | |
1860 | ;; branch, the following insn is never executed. This saves us a nop, | |
1861 | ;; but requires a debugger which can handle annuled branches. | |
1862 | (define_insn "jump" | |
1863 | [(set (pc) (label_ref (match_operand 0 "" "")))] | |
1864 | "" | |
1865 | "* | |
1866 | { | |
1867 | extern int optimize; | |
1868 | extern int flag_no_peephole; | |
1869 | ||
1870 | if (optimize && !flag_no_peephole) | |
1871 | return \"b,a %l0\"; | |
1872 | return \"b %l0\;nop\"; | |
1873 | }") | |
1874 | ||
1875 | ;; Peephole optimizers recognize a few simple cases when delay insns are safe. | |
1876 | ;; Complex ones are up front. Simple ones after. | |
1877 | ||
1878 | ;; This pattern is just like the following one, but matches when there | |
1879 | ;; is a jump insn after the "delay" insn. Without this pattern, we | |
1880 | ;; de-optimize that case. | |
1881 | ||
1882 | (define_peephole | |
1883 | [(set (pc) (match_operand 0 "" "")) | |
1884 | (set (match_operand:SI 1 "" "") | |
1885 | (match_operand:SI 2 "" "")) | |
1886 | (set (pc) (label_ref (match_operand 3 "" "")))] | |
1887 | "TARGET_EAGER && operands_satisfy_eager_branch_peephole (operands, 2)" | |
1888 | "* | |
1889 | { | |
1890 | rtx xoperands[2]; | |
1891 | rtx pat = gen_rtx (SET, VOIDmode, operands[1], operands[2]); | |
1892 | rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0); | |
1893 | rtx label, head; | |
1894 | int parity; | |
1895 | ||
1896 | if (GET_CODE (XEXP (operands[0], 1)) == PC) | |
1897 | { | |
1898 | parity = 1; | |
1899 | label = XEXP (XEXP (operands[0], 2), 0); | |
1900 | } | |
1901 | else | |
1902 | { | |
1903 | parity = 0; | |
1904 | label = XEXP (XEXP (operands[0], 1), 0); | |
1905 | } | |
1906 | xoperands[0] = XEXP (operands[0], 0); | |
1907 | xoperands[1] = label; | |
1908 | ||
1909 | head = next_real_insn_no_labels (label); | |
1910 | ||
1911 | /* If at the target of this label we set the condition codes, | |
1912 | and the condition codes are already set for that value, | |
1913 | advance, if we can, to the following insn. */ | |
1914 | if (GET_CODE (PATTERN (head)) == SET | |
1915 | && GET_CODE (SET_DEST (PATTERN (head))) == CC0 | |
1916 | && cc_status.value2 == SET_SRC (PATTERN (head))) | |
1917 | { | |
1918 | rtx nhead = next_real_insn_no_labels (head); | |
1919 | if (nhead | |
1920 | && GET_CODE (nhead) == INSN | |
1921 | && GET_CODE (PATTERN (nhead)) == SET | |
1922 | && strict_single_insn_op_p (SET_SRC (PATTERN (nhead)), | |
1923 | GET_MODE (SET_DEST (PATTERN (nhead)))) | |
1924 | && strict_single_insn_op_p (SET_DEST (PATTERN (nhead)), VOIDmode) | |
1925 | /* Moves between FP regs and CPU regs are two insns. */ | |
1926 | && !(GET_CODE (SET_SRC (PATTERN (nhead))) == REG | |
1927 | && GET_CODE (SET_DEST (PATTERN (nhead))) == REG | |
1928 | && (FP_REG_P (SET_SRC (PATTERN (nhead))) | |
1929 | != FP_REG_P (SET_DEST (PATTERN (nhead)))))) | |
1930 | { | |
1931 | head = nhead; | |
1932 | } | |
1933 | } | |
1934 | ||
1935 | /* Output the branch instruction first. */ | |
1936 | if (cc_prev_status.flags & CC_IN_FCCR) | |
1937 | { | |
1938 | if (parity) | |
1939 | output_asm_insn (\"fb%F0,a %l1 ! eager\", xoperands); | |
1940 | else | |
1941 | output_asm_insn (\"fb%C0,a %l1 ! eager\", xoperands); | |
1942 | } | |
1943 | else if (cc_prev_status.flags & CC_NO_OVERFLOW) | |
1944 | { | |
1945 | if (parity) | |
1946 | output_asm_insn (\"b%U0,a %l1 ! eager\", xoperands); | |
1947 | else | |
1948 | output_asm_insn (\"b%I0,a %l1 ! eager\", xoperands); | |
1949 | } | |
1950 | else | |
1951 | { | |
1952 | if (parity) | |
1953 | output_asm_insn (\"b%N0,a %l1 ! eager\", xoperands); | |
1954 | else | |
1955 | output_asm_insn (\"b%C0,a %l1 ! eager\", xoperands); | |
1956 | } | |
1957 | ||
1958 | /* Now steal the first insn of the target. */ | |
1959 | output_eager_then_insn (head, operands); | |
1960 | ||
1961 | XVECEXP (PATTERN (insn), 0, 0) = XVECEXP (PATTERN (insn), 0, 1); | |
1962 | XVECEXP (PATTERN (insn), 0, 1) = XVECEXP (PATTERN (insn), 0, 2); | |
1963 | ||
1964 | return output_delayed_branch (\"b %l3 ! eager2\", operands, insn); | |
1965 | }") | |
1966 | ||
1967 | ;; Here is a peephole which recognizes where delay insns can be made safe: | |
1968 | ;; (1) following a conditional branch, if the target of the conditional branch | |
1969 | ;; has only one user (this insn), move the first insn into our delay slot | |
1970 | ;; and emit an annulled branch. | |
1971 | ;; (2) following a conditional branch, if we can execute the fall-through | |
1972 | ;; insn without risking any evil effects, then do that instead of a nop. | |
1973 | ||
1974 | (define_peephole | |
1975 | [(set (pc) (match_operand 0 "" "")) | |
1976 | (set (match_operand:SI 1 "" "") | |
1977 | (match_operand:SI 2 "" ""))] | |
1978 | "TARGET_EAGER && operands_satisfy_eager_branch_peephole (operands, 1)" | |
1979 | "* | |
1980 | { | |
1981 | rtx xoperands[2]; | |
1982 | rtx pat = gen_rtx (SET, VOIDmode, operands[1], operands[2]); | |
1983 | rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0); | |
1984 | rtx label, head, prev = (rtx)1; | |
1985 | int parity; | |
1986 | ||
1987 | if (GET_CODE (XEXP (operands[0], 1)) == PC) | |
1988 | { | |
1989 | parity = 1; | |
1990 | label = XEXP (XEXP (operands[0], 2), 0); | |
1991 | } | |
1992 | else | |
1993 | { | |
1994 | parity = 0; | |
1995 | label = XEXP (XEXP (operands[0], 1), 0); | |
1996 | } | |
1997 | xoperands[0] = XEXP (operands[0], 0); | |
1998 | xoperands[1] = label; | |
1999 | ||
2000 | if (LABEL_NUSES (label) == 1) | |
2001 | { | |
2002 | prev = PREV_INSN (label); | |
2003 | while (prev | |
2004 | && (GET_CODE (prev) == NOTE | |
2005 | || (GET_CODE (prev) == INSN | |
2006 | && (GET_CODE (PATTERN (prev)) == CLOBBER | |
2007 | || GET_CODE (PATTERN (prev)) == USE)))) | |
2008 | prev = PREV_INSN (prev); | |
2009 | if (prev == 0 | |
2010 | || GET_CODE (prev) == BARRIER) | |
2011 | { | |
2012 | prev = 0; | |
2013 | head = next_real_insn_no_labels (label); | |
2014 | } | |
2015 | } | |
2016 | if (prev == 0 | |
2017 | && head != 0 | |
2018 | && ! INSN_DELETED_P (head) | |
2019 | && GET_CODE (head) == INSN | |
2020 | && GET_CODE (PATTERN (head)) == SET | |
2021 | && strict_single_insn_op_p (SET_SRC (PATTERN (head)), | |
2022 | GET_MODE (SET_DEST (PATTERN (head)))) | |
2023 | && strict_single_insn_op_p (SET_DEST (PATTERN (head)), VOIDmode) | |
2024 | /* Moves between FP regs and CPU regs are two insns. */ | |
2025 | && !(GET_CODE (SET_SRC (PATTERN (head))) == REG | |
2026 | && GET_CODE (SET_DEST (PATTERN (head))) == REG | |
2027 | && (FP_REG_P (SET_SRC (PATTERN (head))) | |
2028 | != FP_REG_P (SET_DEST (PATTERN (head)))))) | |
2029 | { | |
2030 | /* If at the target of this label we set the condition codes, | |
2031 | and the condition codes are already set for that value, | |
2032 | advance, if we can, to the following insn. */ | |
2033 | if (GET_CODE (PATTERN (head)) == SET | |
2034 | && GET_CODE (SET_DEST (PATTERN (head))) == CC0 | |
2035 | && cc_status.value2 == SET_SRC (PATTERN (head))) | |
2036 | { | |
2037 | rtx nhead = next_real_insn_no_labels (head); | |
2038 | if (nhead | |
2039 | && GET_CODE (nhead) == INSN | |
2040 | && GET_CODE (PATTERN (nhead)) == SET | |
2041 | && strict_single_insn_op_p (SET_SRC (PATTERN (nhead)), | |
2042 | GET_MODE (SET_DEST (nhead))) | |
2043 | && strict_single_insn_op_p (SET_DEST (PATTERN (nhead)), VOIDmode) | |
2044 | /* Moves between FP regs and CPU regs are two insns. */ | |
2045 | && !(GET_CODE (SET_SRC (PATTERN (nhead))) == REG | |
2046 | && GET_CODE (SET_DEST (PATTERN (nhead))) == REG | |
2047 | && (FP_REG_P (SET_SRC (PATTERN (nhead))) | |
2048 | != FP_REG_P (SET_DEST (PATTERN (nhead)))))) | |
2049 | head = nhead; | |
2050 | } | |
2051 | ||
2052 | /* Output the branch instruction first. */ | |
2053 | if (cc_prev_status.flags & CC_IN_FCCR) | |
2054 | { | |
2055 | if (parity) | |
2056 | output_asm_insn (\"fb%F0,a %l1 ! eager\", xoperands); | |
2057 | else | |
2058 | output_asm_insn (\"fb%C0,a %l1 ! eager\", xoperands); | |
2059 | } | |
2060 | else if (cc_prev_status.flags & CC_NO_OVERFLOW) | |
2061 | { | |
2062 | if (parity) | |
2063 | output_asm_insn (\"b%U0,a %l1 ! eager\", xoperands); | |
2064 | else | |
2065 | output_asm_insn (\"b%I0,a %l1 ! eager\", xoperands); | |
2066 | } | |
2067 | else | |
2068 | { | |
2069 | if (parity) | |
2070 | output_asm_insn (\"b%N0,a %l1 ! eager\", xoperands); | |
2071 | else | |
2072 | output_asm_insn (\"b%C0,a %l1 ! eager\", xoperands); | |
2073 | } | |
2074 | ||
2075 | /* Now steal the first insn of the target. */ | |
2076 | output_eager_then_insn (head, operands); | |
2077 | } | |
2078 | else | |
2079 | { | |
2080 | /* Output the branch instruction first. */ | |
2081 | if (cc_prev_status.flags & CC_IN_FCCR) | |
2082 | { | |
2083 | if (parity) | |
2084 | output_asm_insn (\"fb%F0 %l1 ! eager\", xoperands); | |
2085 | else | |
2086 | output_asm_insn (\"fb%C0 %l1 ! eager\", xoperands); | |
2087 | } | |
2088 | else if (cc_prev_status.flags & CC_NO_OVERFLOW) | |
2089 | { | |
2090 | if (parity) | |
2091 | output_asm_insn (\"b%U0,a %l1 ! eager\", xoperands); | |
2092 | else | |
2093 | output_asm_insn (\"b%I0,a %l1 ! eager\", xoperands); | |
2094 | } | |
2095 | else | |
2096 | { | |
2097 | if (parity) | |
2098 | output_asm_insn (\"b%N0 %l1 ! eager\", xoperands); | |
2099 | else | |
2100 | output_asm_insn (\"b%C0 %l1 ! eager\", xoperands); | |
2101 | } | |
2102 | } | |
2103 | return output_delay_insn (delay_insn); | |
2104 | }") | |
2105 | ||
2106 | ;; Here are two simple peepholes which fill the delay slot of | |
2107 | ;; an unconditional branch. | |
2108 | ||
2109 | (define_peephole | |
2110 | [(set (match_operand:SI 0 "register_operand" "=r") | |
2111 | (match_operand:SI 1 "single_insn_src_p" "p")) | |
2112 | (set (pc) (label_ref (match_operand 2 "" "")))] | |
2113 | "single_insn_extra_test (operands[0], operands[1])" | |
2114 | "* return output_delayed_branch (\"b %l2\", operands, insn);") | |
2115 | ||
2116 | (define_peephole | |
2117 | [(set (match_operand:SI 0 "memory_operand" "=m") | |
2118 | (match_operand:SI 1 "reg_or_0_operand" "rJ")) | |
2119 | (set (pc) (label_ref (match_operand 2 "" "")))] | |
2120 | "" | |
2121 | "* return output_delayed_branch (\"b %l2\", operands, insn);") | |
2122 | ||
2123 | (define_insn "tablejump" | |
2124 | [(set (pc) (match_operand:SI 0 "register_operand" "r")) | |
2125 | (use (label_ref (match_operand 1 "" "")))] | |
2126 | "" | |
2127 | "jmp %0\;nop") | |
2128 | ||
2129 | (define_peephole | |
2130 | [(set (match_operand:SI 0 "register_operand" "=r") | |
2131 | (match_operand:SI 1 "single_insn_src_p" "p")) | |
2132 | (parallel [(set (pc) (match_operand:SI 2 "register_operand" "r")) | |
2133 | (use (label_ref (match_operand 3 "" "")))])] | |
2134 | "REGNO (operands[0]) != REGNO (operands[2]) | |
2135 | && single_insn_extra_test (operands[0], operands[1])" | |
2136 | "* return output_delayed_branch (\"jmp %2\", operands, insn);") | |
2137 | ||
2138 | (define_peephole | |
2139 | [(set (match_operand:SI 0 "memory_operand" "=m") | |
2140 | (match_operand:SI 1 "reg_or_0_operand" "rJ")) | |
2141 | (parallel [(set (pc) (match_operand:SI 2 "register_operand" "r")) | |
2142 | (use (label_ref (match_operand 3 "" "")))])] | |
2143 | "" | |
2144 | "* return output_delayed_branch (\"jmp %2\", operands, insn);") | |
2145 | ||
2146 | ;;- jump to subroutine | |
2147 | (define_expand "call" | |
2148 | [(call (match_operand:SI 0 "memory_operand" "m") | |
2149 | (match_operand 1 "" "i"))] | |
2150 | ;; operand[2] is next_arg_register | |
2151 | "" | |
2152 | " | |
2153 | { | |
2154 | rtx fn_rtx, nregs_rtx; | |
2155 | ||
2156 | if (TARGET_SUN_ASM && GET_CODE (XEXP (operands[0], 0)) == REG) | |
2157 | { | |
2158 | rtx g1_rtx = gen_rtx (REG, SImode, 1); | |
2159 | emit_move_insn (g1_rtx, XEXP (operands[0], 0)); | |
2160 | fn_rtx = gen_rtx (MEM, SImode, g1_rtx); | |
2161 | } | |
2162 | else | |
2163 | fn_rtx = operands[0]; | |
2164 | ||
2165 | /* Count the number of parameter registers being used by this call. | |
2166 | if that argument is NULL, it means we are using them all, which | |
2167 | means 6 on the sparc. */ | |
2168 | #if 0 | |
2169 | if (operands[2]) | |
2170 | nregs_rtx = gen_rtx (CONST_INT, VOIDmode, REGNO (operands[2]) - 8); | |
2171 | else | |
2172 | nregs_rtx = gen_rtx (CONST_INT, VOIDmode, 6); | |
2173 | #else | |
2174 | nregs_rtx = const0_rtx; | |
2175 | #endif | |
2176 | ||
2177 | emit_call_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2, | |
2178 | gen_rtx (CALL, VOIDmode, fn_rtx, nregs_rtx), | |
2179 | gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, 31))))); | |
2180 | DONE; | |
2181 | }") | |
2182 | ||
2183 | (define_insn "" | |
2184 | [(call (match_operand:SI 0 "memory_operand" "m") | |
2185 | (match_operand 1 "" "i")) | |
2186 | (use (reg:SI 31))] | |
2187 | ;;- Don't use operand 1 for most machines. | |
2188 | "CONSTANT_P (XEXP (operands[0], 0)) | |
2189 | || GET_CODE (XEXP (operands[0], 0)) == REG" | |
2190 | "* | |
2191 | { | |
2192 | /* strip the MEM. */ | |
2193 | operands[0] = XEXP (operands[0], 0); | |
2194 | CC_STATUS_INIT; | |
2195 | if (TARGET_SUN_ASM && GET_CODE (operands[0]) == REG) | |
2196 | return \"jmpl %a0,%%o7\;nop\"; | |
2197 | return \"call %a0,%1\;nop\"; | |
2198 | }") | |
2199 | ||
2200 | (define_peephole | |
2201 | [(set (match_operand:SI 0 "register_operand" "=r") | |
2202 | (match_operand:SI 1 "single_insn_src_p" "p")) | |
2203 | (parallel [(call (match_operand:SI 2 "memory_operand" "m") | |
2204 | (match_operand 3 "" "i")) | |
2205 | (use (reg:SI 31))])] | |
2206 | ;;- Don't use operand 1 for most machines. | |
2207 | "! reg_mentioned_p (operands[0], operands[2]) | |
2208 | && single_insn_extra_test (operands[0], operands[1])" | |
2209 | "* | |
2210 | { | |
2211 | /* strip the MEM. */ | |
2212 | operands[2] = XEXP (operands[2], 0); | |
2213 | if (TARGET_SUN_ASM && GET_CODE (operands[2]) == REG) | |
2214 | return output_delayed_branch (\"jmpl %a2,%%o7\", operands, insn); | |
2215 | return output_delayed_branch (\"call %a2,%3\", operands, insn); | |
2216 | }") | |
2217 | ||
2218 | (define_peephole | |
2219 | [(set (match_operand:SI 0 "memory_operand" "=m") | |
2220 | (match_operand:SI 1 "reg_or_0_operand" "rJ")) | |
2221 | (parallel [(call (match_operand:SI 2 "memory_operand" "m") | |
2222 | (match_operand 3 "" "i")) | |
2223 | (use (reg:SI 31))])] | |
2224 | ;;- Don't use operand 1 for most machines. | |
2225 | "" | |
2226 | "* | |
2227 | { | |
2228 | /* strip the MEM. */ | |
2229 | operands[2] = XEXP (operands[2], 0); | |
2230 | if (TARGET_SUN_ASM && GET_CODE (operands[2]) == REG) | |
2231 | return output_delayed_branch (\"jmpl %a2,%%o7\", operands, insn); | |
2232 | return output_delayed_branch (\"call %a2,%3\", operands, insn); | |
2233 | }") | |
2234 | ||
2235 | (define_expand "call_value" | |
2236 | [(set (match_operand 0 "register_operand" "=rf") | |
2237 | (call (match_operand:SI 1 "memory_operand" "m") | |
2238 | (match_operand 2 "" "i")))] | |
2239 | ;; operand 3 is next_arg_register | |
2240 | "" | |
2241 | " | |
2242 | { | |
2243 | rtx fn_rtx, nregs_rtx; | |
2244 | rtvec vec; | |
2245 | ||
2246 | if (TARGET_SUN_ASM && GET_CODE (XEXP (operands[1], 0)) == REG) | |
2247 | { | |
2248 | rtx g1_rtx = gen_rtx (REG, SImode, 1); | |
2249 | emit_move_insn (g1_rtx, XEXP (operands[1], 0)); | |
2250 | fn_rtx = gen_rtx (MEM, SImode, g1_rtx); | |
2251 | } | |
2252 | else | |
2253 | fn_rtx = operands[1]; | |
2254 | ||
2255 | #if 0 | |
2256 | if (operands[3]) | |
2257 | nregs_rtx = gen_rtx (CONST_INT, VOIDmode, REGNO (operands[3]) - 8); | |
2258 | else | |
2259 | nregs_rtx = gen_rtx (CONST_INT, VOIDmode, 6); | |
2260 | #else | |
2261 | nregs_rtx = const0_rtx; | |
2262 | #endif | |
2263 | ||
2264 | vec = gen_rtvec (2, | |
2265 | gen_rtx (SET, VOIDmode, operands[0], | |
2266 | gen_rtx (CALL, VOIDmode, fn_rtx, nregs_rtx)), | |
2267 | gen_rtx (USE, VOIDmode, gen_rtx (REG, SImode, 31))); | |
2268 | ||
2269 | emit_call_insn (gen_rtx (PARALLEL, VOIDmode, vec)); | |
2270 | DONE; | |
2271 | }") | |
2272 | ||
2273 | (define_insn "" | |
2274 | [(set (match_operand 0 "" "=rf") | |
2275 | (call (match_operand:SI 1 "memory_operand" "m") | |
2276 | (match_operand 2 "" "i"))) | |
2277 | (use (reg:SI 31))] | |
2278 | ;;- Don't use operand 2 for most machines. | |
2279 | "CONSTANT_P (XEXP (operands[1], 0)) | |
2280 | || GET_CODE (XEXP (operands[1], 0)) == REG" | |
2281 | "* | |
2282 | { | |
2283 | /* strip the MEM. */ | |
2284 | operands[1] = XEXP (operands[1], 0); | |
2285 | CC_STATUS_INIT; | |
2286 | if (TARGET_SUN_ASM && GET_CODE (operands[1]) == REG) | |
2287 | return \"jmpl %a1,%%o7\;nop\"; | |
2288 | return \"call %a1,%2\;nop\"; | |
2289 | }") | |
2290 | ||
2291 | (define_peephole | |
2292 | [(set (match_operand:SI 0 "register_operand" "=r") | |
2293 | (match_operand:SI 1 "single_insn_src_p" "p")) | |
2294 | (parallel [(set (match_operand 2 "" "=rf") | |
2295 | (call (match_operand:SI 3 "memory_operand" "m") | |
2296 | (match_operand 4 "" "i"))) | |
2297 | (use (reg:SI 31))])] | |
2298 | ;;- Don't use operand 4 for most machines. | |
2299 | "! reg_mentioned_p (operands[0], operands[3]) | |
2300 | && single_insn_extra_test (operands[0], operands[1])" | |
2301 | "* | |
2302 | { | |
2303 | /* strip the MEM. */ | |
2304 | operands[3] = XEXP (operands[3], 0); | |
2305 | if (TARGET_SUN_ASM && GET_CODE (operands[3]) == REG) | |
2306 | return output_delayed_branch (\"jmpl %a3,%%o7\", operands, insn); | |
2307 | return output_delayed_branch (\"call %a3,%4\", operands, insn); | |
2308 | }") | |
2309 | ||
2310 | (define_peephole | |
2311 | [(set (match_operand:SI 0 "memory_operand" "=m") | |
2312 | (match_operand:SI 1 "reg_or_0_operand" "rJ")) | |
2313 | (parallel [(set (match_operand 2 "" "=rf") | |
2314 | (call (match_operand:SI 3 "memory_operand" "m") | |
2315 | (match_operand 4 "" "i"))) | |
2316 | (use (reg:SI 31))])] | |
2317 | ;;- Don't use operand 4 for most machines. | |
2318 | "" | |
2319 | "* | |
2320 | { | |
2321 | /* strip the MEM. */ | |
2322 | operands[3] = XEXP (operands[3], 0); | |
2323 | if (TARGET_SUN_ASM && GET_CODE (operands[3]) == REG) | |
2324 | return output_delayed_branch (\"jmpl %a3,%%o7\", operands, insn); | |
2325 | return output_delayed_branch (\"call %a3,%4\", operands, insn); | |
2326 | }") | |
2327 | \f | |
2328 | (define_insn "return" | |
2329 | [(return)] | |
2330 | "! TARGET_EPILOGUE" | |
2331 | "ret\;restore") | |
2332 | ||
2333 | (define_peephole | |
2334 | [(set (reg:SI 24) | |
2335 | (match_operand:SI 0 "reg_or_0_operand" "rJ")) | |
2336 | (return)] | |
2337 | "! TARGET_EPILOGUE" | |
2338 | "ret\;restore %r0,0x0,%%o0") | |
2339 | ||
2340 | (define_peephole | |
2341 | [(set (reg:SI 24) | |
2342 | (plus:SI (match_operand:SI 0 "register_operand" "r%") | |
2343 | (match_operand:SI 1 "arith_operand" "rI"))) | |
2344 | (return)] | |
2345 | "! TARGET_EPILOGUE" | |
2346 | "ret\;restore %r0,%1,%%o0") | |
2347 | ||
2348 | (define_peephole | |
2349 | [(set (reg:SI 24) | |
2350 | (minus:SI (match_operand:SI 0 "register_operand" "r") | |
2351 | (match_operand:SI 1 "small_int" "I"))) | |
2352 | (return)] | |
2353 | "! TARGET_EPILOGUE" | |
2354 | "ret\;restore %0,-(%1),%%o0") | |
2355 | ||
2356 | (define_insn "nop" | |
2357 | [(const_int 0)] | |
2358 | "" | |
2359 | "nop") | |
2360 | \f | |
2361 | ;;- Local variables: | |
2362 | ;;- mode:emacs-lisp | |
2363 | ;;- comment-start: ";;- " | |
2364 | ;;- eval: (set-syntax-table (copy-sequence (syntax-table))) | |
2365 | ;;- eval: (modify-syntax-entry ?[ "(]") | |
2366 | ;;- eval: (modify-syntax-entry ?] ")[") | |
2367 | ;;- eval: (modify-syntax-entry ?{ "(}") | |
2368 | ;;- eval: (modify-syntax-entry ?} "){") | |
2369 | ;;- End: | |
2370 |