]>
Commit | Line | Data |
---|---|---|
11bb1f11 | 1 | /* Subroutines for insn-output.c for Matsushita MN10300 series |
74452ac3 | 2 | Copyright (C) 1996, 1997 Free Software Foundation, Inc. |
11bb1f11 JL |
3 | Contributed by Jeff Law (law@cygnus.com). |
4 | ||
5 | This file is part of GNU CC. | |
6 | ||
7 | GNU CC is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2, or (at your option) | |
10 | any later version. | |
11 | ||
12 | GNU CC is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with GNU CC; see the file COPYING. If not, write to | |
19 | the Free Software Foundation, 59 Temple Place - Suite 330, | |
20 | Boston, MA 02111-1307, USA. */ | |
21 | ||
22 | #include <stdio.h> | |
23 | #include "config.h" | |
24 | #include "rtl.h" | |
25 | #include "regs.h" | |
26 | #include "hard-reg-set.h" | |
27 | #include "real.h" | |
28 | #include "insn-config.h" | |
29 | #include "conditions.h" | |
30 | #include "insn-flags.h" | |
31 | #include "output.h" | |
32 | #include "insn-attr.h" | |
33 | #include "flags.h" | |
34 | #include "recog.h" | |
35 | #include "expr.h" | |
36 | #include "tree.h" | |
37 | #include "obstack.h" | |
38 | ||
74452ac3 JL |
39 | /* Global registers known to hold the value zero. |
40 | ||
41 | Normally we'd depend on CSE and combine to put zero into a | |
42 | register and re-use it. | |
43 | ||
44 | However, on the mn10x00 processors we implicitly use the constant | |
45 | zero in tst instructions, so we might be able to do better by | |
46 | loading the value into a register in the prologue, then re-useing | |
47 | that register throughout the function. | |
48 | ||
49 | We could perform similar optimizations for other constants, but with | |
50 | gcse due soon, it doesn't seem worth the effort. | |
51 | ||
52 | These variables hold a rtx for a register known to hold the value | |
53 | zero throughout the entire function, or NULL if no register of | |
54 | the appropriate class has such a value throughout the life of the | |
55 | function. */ | |
56 | rtx zero_dreg; | |
57 | rtx zero_areg; | |
58 | ||
11bb1f11 JL |
59 | void |
60 | asm_file_start (file) | |
61 | FILE *file; | |
62 | { | |
63 | fprintf (file, "#\tGCC For the Matsushita MN10300\n"); | |
64 | if (optimize) | |
65 | fprintf (file, "# -O%d\n", optimize); | |
66 | else | |
67 | fprintf (file, "\n\n"); | |
68 | output_file_directive (file, main_input_filename); | |
69 | } | |
70 | \f | |
71 | ||
11bb1f11 JL |
72 | /* Print operand X using operand code CODE to assembly language output file |
73 | FILE. */ | |
74 | ||
75 | void | |
76 | print_operand (file, x, code) | |
77 | FILE *file; | |
78 | rtx x; | |
79 | int code; | |
80 | { | |
81 | switch (code) | |
82 | { | |
83 | case 'b': | |
84 | case 'B': | |
85 | /* These are normal and reversed branches. */ | |
86 | switch (code == 'b' ? GET_CODE (x) : reverse_condition (GET_CODE (x))) | |
87 | { | |
88 | case NE: | |
89 | fprintf (file, "ne"); | |
90 | break; | |
91 | case EQ: | |
92 | fprintf (file, "eq"); | |
93 | break; | |
94 | case GE: | |
95 | fprintf (file, "ge"); | |
96 | break; | |
97 | case GT: | |
98 | fprintf (file, "gt"); | |
99 | break; | |
100 | case LE: | |
101 | fprintf (file, "le"); | |
102 | break; | |
103 | case LT: | |
104 | fprintf (file, "lt"); | |
105 | break; | |
106 | case GEU: | |
107 | fprintf (file, "cc"); | |
108 | break; | |
109 | case GTU: | |
110 | fprintf (file, "hi"); | |
111 | break; | |
112 | case LEU: | |
113 | fprintf (file, "ls"); | |
114 | break; | |
115 | case LTU: | |
116 | fprintf (file, "cs"); | |
117 | break; | |
118 | default: | |
119 | abort (); | |
120 | } | |
121 | break; | |
122 | case 'C': | |
123 | /* This is used for the operand to a call instruction; | |
124 | if it's a REG, enclose it in parens, else output | |
125 | the operand normally. */ | |
126 | if (GET_CODE (x) == REG) | |
127 | { | |
128 | fputc ('(', file); | |
129 | print_operand (file, x, 0); | |
130 | fputc (')', file); | |
131 | } | |
132 | else | |
133 | print_operand (file, x, 0); | |
134 | break; | |
135 | ||
38c37a0e JL |
136 | /* These are the least significant word in a 64bit value. */ |
137 | case 'L': | |
138 | switch (GET_CODE (x)) | |
139 | { | |
140 | case MEM: | |
141 | fputc ('(', file); | |
142 | output_address (XEXP (x, 0)); | |
143 | fputc (')', file); | |
144 | break; | |
145 | ||
146 | case REG: | |
147 | fprintf (file, "%s", reg_names[REGNO (x)]); | |
148 | break; | |
149 | ||
150 | case SUBREG: | |
151 | fprintf (file, "%s", | |
152 | reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)]); | |
153 | break; | |
154 | ||
155 | case CONST_DOUBLE: | |
156 | { | |
157 | long val[2]; | |
158 | REAL_VALUE_TYPE rv; | |
159 | ||
160 | switch (GET_MODE (x)) | |
161 | { | |
162 | case DFmode: | |
163 | REAL_VALUE_FROM_CONST_DOUBLE (rv, x); | |
164 | REAL_VALUE_TO_TARGET_DOUBLE (rv, val); | |
165 | print_operand_address (file, GEN_INT (val[0])); | |
166 | break;; | |
167 | case SFmode: | |
168 | REAL_VALUE_FROM_CONST_DOUBLE (rv, x); | |
169 | REAL_VALUE_TO_TARGET_SINGLE (rv, val[0]); | |
170 | print_operand_address (file, GEN_INT (val[0])); | |
171 | break;; | |
172 | case VOIDmode: | |
173 | case DImode: | |
174 | print_operand_address (file, | |
175 | GEN_INT (CONST_DOUBLE_LOW (x))); | |
176 | break; | |
177 | } | |
178 | break; | |
179 | } | |
180 | ||
181 | case CONST_INT: | |
182 | print_operand_address (file, x); | |
183 | break; | |
184 | ||
185 | default: | |
186 | abort (); | |
187 | } | |
188 | break; | |
189 | ||
190 | /* Similarly, but for the most significant word. */ | |
191 | case 'H': | |
192 | switch (GET_CODE (x)) | |
193 | { | |
194 | case MEM: | |
195 | fputc ('(', file); | |
196 | x = adj_offsettable_operand (x, 4); | |
197 | output_address (XEXP (x, 0)); | |
198 | fputc (')', file); | |
199 | break; | |
200 | ||
201 | case REG: | |
202 | fprintf (file, "%s", reg_names[REGNO (x) + 1]); | |
203 | break; | |
204 | ||
205 | case SUBREG: | |
206 | fprintf (file, "%s", | |
207 | reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)] + 1); | |
208 | break; | |
209 | ||
210 | case CONST_DOUBLE: | |
211 | { | |
212 | long val[2]; | |
213 | REAL_VALUE_TYPE rv; | |
214 | ||
215 | switch (GET_MODE (x)) | |
216 | { | |
217 | case DFmode: | |
218 | REAL_VALUE_FROM_CONST_DOUBLE (rv, x); | |
219 | REAL_VALUE_TO_TARGET_DOUBLE (rv, val); | |
220 | print_operand_address (file, GEN_INT (val[1])); | |
221 | break;; | |
222 | case SFmode: | |
223 | abort (); | |
224 | case VOIDmode: | |
225 | case DImode: | |
226 | print_operand_address (file, | |
227 | GEN_INT (CONST_DOUBLE_HIGH (x))); | |
228 | break; | |
229 | } | |
230 | break; | |
231 | } | |
232 | ||
233 | case CONST_INT: | |
234 | if (INTVAL (x) < 0) | |
235 | print_operand_address (file, GEN_INT (-1)); | |
236 | else | |
237 | print_operand_address (file, GEN_INT (0)); | |
238 | break; | |
239 | default: | |
240 | abort (); | |
241 | } | |
242 | break; | |
243 | ||
244 | case 'A': | |
245 | fputc ('(', file); | |
246 | if (GET_CODE (XEXP (x, 0)) == REG) | |
247 | output_address (gen_rtx (PLUS, SImode, XEXP (x, 0), GEN_INT (0))); | |
248 | else | |
249 | output_address (XEXP (x, 0)); | |
250 | fputc (')', file); | |
251 | break; | |
252 | ||
6fafc523 JL |
253 | case 'N': |
254 | output_address (GEN_INT ((~INTVAL (x)) & 0xff)); | |
255 | break; | |
256 | ||
11bb1f11 JL |
257 | default: |
258 | switch (GET_CODE (x)) | |
259 | { | |
260 | case MEM: | |
261 | fputc ('(', file); | |
262 | output_address (XEXP (x, 0)); | |
263 | fputc (')', file); | |
264 | break; | |
265 | ||
38c37a0e JL |
266 | case PLUS: |
267 | output_address (x); | |
268 | break; | |
269 | ||
11bb1f11 JL |
270 | case REG: |
271 | fprintf (file, "%s", reg_names[REGNO (x)]); | |
272 | break; | |
273 | ||
274 | case SUBREG: | |
275 | fprintf (file, "%s", | |
276 | reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)]); | |
277 | break; | |
278 | ||
38c37a0e JL |
279 | /* This will only be single precision.... */ |
280 | case CONST_DOUBLE: | |
281 | { | |
282 | unsigned long val; | |
283 | REAL_VALUE_TYPE rv; | |
284 | ||
285 | REAL_VALUE_FROM_CONST_DOUBLE (rv, x); | |
286 | REAL_VALUE_TO_TARGET_SINGLE (rv, val); | |
287 | print_operand_address (file, GEN_INT (val)); | |
288 | break; | |
289 | } | |
290 | ||
11bb1f11 JL |
291 | case CONST_INT: |
292 | case SYMBOL_REF: | |
293 | case CONST: | |
294 | case LABEL_REF: | |
295 | case CODE_LABEL: | |
296 | print_operand_address (file, x); | |
297 | break; | |
298 | default: | |
299 | abort (); | |
300 | } | |
301 | break; | |
302 | } | |
303 | } | |
304 | ||
305 | /* Output assembly language output for the address ADDR to FILE. */ | |
306 | ||
307 | void | |
308 | print_operand_address (file, addr) | |
309 | FILE *file; | |
310 | rtx addr; | |
311 | { | |
312 | switch (GET_CODE (addr)) | |
313 | { | |
314 | case REG: | |
315 | if (addr == stack_pointer_rtx) | |
316 | print_operand_address (file, gen_rtx (PLUS, SImode, | |
317 | stack_pointer_rtx, | |
318 | GEN_INT (0))); | |
319 | else | |
320 | print_operand (file, addr, 0); | |
321 | break; | |
322 | case PLUS: | |
323 | { | |
324 | rtx base, index; | |
325 | if (REG_P (XEXP (addr, 0)) | |
326 | && REG_OK_FOR_BASE_P (XEXP (addr, 0))) | |
327 | base = XEXP (addr, 0), index = XEXP (addr, 1); | |
328 | else if (REG_P (XEXP (addr, 1)) | |
329 | && REG_OK_FOR_BASE_P (XEXP (addr, 1))) | |
330 | base = XEXP (addr, 1), index = XEXP (addr, 0); | |
331 | else | |
332 | abort (); | |
333 | print_operand (file, index, 0); | |
334 | fputc (',', file); | |
335 | print_operand (file, base, 0);; | |
336 | break; | |
337 | } | |
338 | case SYMBOL_REF: | |
339 | output_addr_const (file, addr); | |
340 | break; | |
341 | default: | |
342 | output_addr_const (file, addr); | |
343 | break; | |
344 | } | |
345 | } | |
346 | ||
38c37a0e JL |
347 | int |
348 | can_use_return_insn () | |
349 | { | |
460f4b9d JL |
350 | /* size includes the fixed stack space needed for function calls. */ |
351 | int size = get_frame_size () + current_function_outgoing_args_size; | |
352 | ||
353 | /* And space for the return pointer. */ | |
354 | size += current_function_outgoing_args_size ? 4 : 0; | |
38c37a0e JL |
355 | |
356 | return (reload_completed | |
357 | && size == 0 | |
358 | && !regs_ever_live[2] | |
359 | && !regs_ever_live[3] | |
360 | && !regs_ever_live[6] | |
361 | && !regs_ever_live[7] | |
362 | && !frame_pointer_needed); | |
363 | } | |
364 | ||
74452ac3 JL |
365 | /* Count the number of tst insns which compare a data or address |
366 | register with zero. */ | |
367 | static void | |
368 | count_tst_insns (dreg_countp, areg_countp) | |
369 | int *dreg_countp; | |
370 | int *areg_countp; | |
371 | { | |
372 | rtx insn; | |
373 | ||
374 | /* Assume no tst insns exist. */ | |
375 | *dreg_countp = 0; | |
376 | *areg_countp = 0; | |
377 | ||
378 | /* If not optimizing, then quit now. */ | |
379 | if (!optimize) | |
380 | return; | |
381 | ||
382 | /* Walk through all the insns. */ | |
383 | for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) | |
384 | { | |
385 | rtx pat; | |
386 | ||
387 | /* Ignore anything that is not a normal INSN. */ | |
388 | if (GET_CODE (insn) != INSN) | |
389 | continue; | |
390 | ||
391 | /* Ignore anything that isn't a SET. */ | |
392 | pat = PATTERN (insn); | |
393 | if (GET_CODE (pat) != SET) | |
394 | continue; | |
395 | ||
396 | /* Check for a tst insn. */ | |
397 | if (SET_DEST (pat) == cc0_rtx | |
398 | && GET_CODE (SET_SRC (pat)) == REG) | |
399 | { | |
400 | if (REGNO_REG_CLASS (REGNO (SET_SRC (pat))) == DATA_REGS) | |
401 | (*dreg_countp)++; | |
402 | ||
403 | if (REGNO_REG_CLASS (REGNO (SET_SRC (pat))) == ADDRESS_REGS) | |
404 | (*areg_countp)++; | |
405 | } | |
406 | ||
407 | /* Setting an address register to zero can also be optimized, | |
408 | so count it just like a tst insn. */ | |
409 | if (GET_CODE (SET_DEST (pat)) == REG | |
410 | && GET_CODE (SET_SRC (pat)) == CONST_INT | |
411 | && INTVAL (SET_SRC (pat)) == 0 | |
412 | && REGNO_REG_CLASS (REGNO (SET_DEST (pat))) == ADDRESS_REGS) | |
413 | (*areg_countp)++; | |
414 | } | |
415 | } | |
416 | ||
11bb1f11 JL |
417 | void |
418 | expand_prologue () | |
419 | { | |
3dbc43d1 JL |
420 | unsigned int size; |
421 | ||
6c0870b8 JL |
422 | /* We need to end the current sequence so that count_tst_insns can |
423 | look at all the insns in this function. Normally this would be | |
424 | unsafe, but it's OK in the prologue/epilogue expanders. */ | |
425 | end_sequence (); | |
426 | ||
74452ac3 JL |
427 | /* Determine if it is profitable to put the value zero into a register |
428 | for the entire function. If so, set ZERO_DREG and ZERO_AREG. */ | |
429 | if (regs_ever_live[2] || regs_ever_live[3] | |
430 | || regs_ever_live[6] || regs_ever_live[7] | |
431 | || frame_pointer_needed) | |
432 | { | |
433 | int dreg_count, areg_count; | |
434 | ||
435 | /* Get a count of the number of tst insns which use address and | |
436 | data registers. */ | |
437 | count_tst_insns (&dreg_count, &areg_count); | |
438 | ||
439 | /* If there's more than one tst insn using a data register, then | |
440 | this optimization is a win. */ | |
441 | if (dreg_count > 1 | |
442 | && (!regs_ever_live[2] || !regs_ever_live[3])) | |
443 | { | |
444 | if (!regs_ever_live[2]) | |
445 | { | |
446 | regs_ever_live[2] = 1; | |
447 | zero_dreg = gen_rtx (REG, SImode, 2); | |
448 | } | |
449 | else | |
450 | { | |
451 | regs_ever_live[3] = 1; | |
452 | zero_dreg = gen_rtx (REG, SImode, 3); | |
453 | } | |
454 | } | |
455 | else | |
456 | zero_dreg = NULL_RTX; | |
457 | ||
458 | /* If there's more than two tst insns using an address register, | |
459 | then this optimization is a win. */ | |
460 | if (areg_count > 2 | |
461 | && (!regs_ever_live[6] || !regs_ever_live[7])) | |
462 | { | |
463 | if (!regs_ever_live[6]) | |
464 | { | |
465 | regs_ever_live[6] = 1; | |
466 | zero_areg = gen_rtx (REG, SImode, 6); | |
467 | } | |
468 | else | |
469 | { | |
470 | regs_ever_live[7] = 1; | |
471 | zero_areg = gen_rtx (REG, SImode, 7); | |
472 | } | |
473 | } | |
474 | else | |
475 | zero_areg = NULL_RTX; | |
476 | } | |
477 | else | |
478 | { | |
479 | zero_dreg = NULL_RTX; | |
480 | zero_areg = NULL_RTX; | |
481 | } | |
482 | ||
6c0870b8 JL |
483 | /* Start a new sequence. */ |
484 | start_sequence (); | |
485 | ||
3dbc43d1 | 486 | /* SIZE includes the fixed stack space needed for function calls. */ |
460f4b9d JL |
487 | size = get_frame_size () + current_function_outgoing_args_size; |
488 | size += (current_function_outgoing_args_size ? 4 : 0); | |
11bb1f11 | 489 | |
22ef4e9b JL |
490 | /* If this is an old-style varargs function, then its arguments |
491 | need to be flushed back to the stack. */ | |
492 | if (current_function_varargs) | |
493 | { | |
494 | emit_move_insn (gen_rtx (MEM, SImode, | |
495 | gen_rtx (PLUS, Pmode, stack_pointer_rtx, | |
496 | GEN_INT (4))), | |
497 | gen_rtx (REG, SImode, 0)); | |
498 | emit_move_insn (gen_rtx (MEM, SImode, | |
499 | gen_rtx (PLUS, Pmode, stack_pointer_rtx, | |
500 | GEN_INT (8))), | |
501 | gen_rtx (REG, SImode, 1)); | |
502 | } | |
503 | ||
777fbf09 JL |
504 | /* And now store all the registers onto the stack with a |
505 | single two byte instruction. */ | |
506 | if (regs_ever_live[2] || regs_ever_live[3] | |
507 | || regs_ever_live[6] || regs_ever_live[7] | |
508 | || frame_pointer_needed) | |
509 | emit_insn (gen_store_movm ()); | |
510 | ||
511 | /* Now put the frame pointer into the frame pointer register. */ | |
11bb1f11 | 512 | if (frame_pointer_needed) |
6e86170d | 513 | emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); |
11bb1f11 | 514 | |
777fbf09 | 515 | /* Allocate stack for this frame. */ |
11bb1f11 JL |
516 | if (size) |
517 | emit_insn (gen_addsi3 (stack_pointer_rtx, | |
518 | stack_pointer_rtx, | |
519 | GEN_INT (-size))); | |
74452ac3 JL |
520 | |
521 | /* Load zeros into registers as needed. */ | |
522 | if (zero_dreg) | |
523 | emit_move_insn (zero_dreg, const0_rtx); | |
524 | ||
525 | if (zero_areg) | |
526 | emit_move_insn (zero_areg, const0_rtx); | |
11bb1f11 JL |
527 | } |
528 | ||
529 | void | |
530 | expand_epilogue () | |
531 | { | |
3dbc43d1 JL |
532 | unsigned int size; |
533 | ||
3dbc43d1 | 534 | /* SIZE includes the fixed stack space needed for function calls. */ |
460f4b9d JL |
535 | size = get_frame_size () + current_function_outgoing_args_size; |
536 | size += (current_function_outgoing_args_size ? 4 : 0); | |
11bb1f11 JL |
537 | |
538 | /* Cut back the stack. */ | |
539 | if (frame_pointer_needed) | |
540 | { | |
11bb1f11 | 541 | emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); |
4246e0c5 JL |
542 | size = 0; |
543 | } | |
6fafc523 JL |
544 | else if ((regs_ever_live[2] || regs_ever_live[3] |
545 | || regs_ever_live[6] || regs_ever_live[7]) | |
546 | && size > 255) | |
4246e0c5 JL |
547 | { |
548 | emit_insn (gen_addsi3 (stack_pointer_rtx, | |
549 | stack_pointer_rtx, | |
550 | GEN_INT (size))); | |
551 | size = 0; | |
11bb1f11 | 552 | } |
11bb1f11 | 553 | |
777fbf09 JL |
554 | /* For simplicity, we just movm all the callee saved registers to |
555 | the stack with one instruction. | |
556 | ||
557 | ?!? Only save registers which are actually used. Reduces | |
558 | stack requireents and is faster. */ | |
559 | if (regs_ever_live[2] || regs_ever_live[3] | |
560 | || regs_ever_live[6] || regs_ever_live[7] | |
561 | || frame_pointer_needed) | |
562 | emit_jump_insn (gen_return_internal_regs (GEN_INT (size))); | |
563 | else | |
564 | { | |
565 | if (size) | |
38c37a0e JL |
566 | { |
567 | emit_insn (gen_addsi3 (stack_pointer_rtx, | |
568 | stack_pointer_rtx, | |
569 | GEN_INT (size))); | |
570 | emit_jump_insn (gen_return_internal ()); | |
571 | } | |
572 | else | |
573 | { | |
574 | emit_jump_insn (gen_return ()); | |
575 | } | |
777fbf09 | 576 | } |
11bb1f11 JL |
577 | } |
578 | ||
579 | /* Update the condition code from the insn. */ | |
580 | ||
581 | void | |
582 | notice_update_cc (body, insn) | |
583 | rtx body; | |
584 | rtx insn; | |
585 | { | |
11bb1f11 JL |
586 | switch (get_attr_cc (insn)) |
587 | { | |
588 | case CC_NONE: | |
589 | /* Insn does not affect CC at all. */ | |
590 | break; | |
591 | ||
592 | case CC_NONE_0HIT: | |
593 | /* Insn does not change CC, but the 0'th operand has been changed. */ | |
594 | if (cc_status.value1 != 0 | |
595 | && reg_overlap_mentioned_p (recog_operand[0], cc_status.value1)) | |
596 | cc_status.value1 = 0; | |
597 | break; | |
598 | ||
d116300b | 599 | case CC_SET_ZN: |
11bb1f11 | 600 | /* Insn sets the Z,N flags of CC to recog_operand[0]. |
d116300b | 601 | V,C are unusable. */ |
11bb1f11 | 602 | CC_STATUS_INIT; |
d116300b | 603 | cc_status.flags |= CC_NO_CARRY | CC_OVERFLOW_UNUSABLE; |
11bb1f11 JL |
604 | cc_status.value1 = recog_operand[0]; |
605 | break; | |
606 | ||
d116300b JL |
607 | case CC_SET_ZNV: |
608 | /* Insn sets the Z,N,V flags of CC to recog_operand[0]. | |
609 | C is unusable. */ | |
82c6faa8 | 610 | CC_STATUS_INIT; |
d116300b | 611 | cc_status.flags |= CC_NO_CARRY; |
82c6faa8 JL |
612 | cc_status.value1 = recog_operand[0]; |
613 | break; | |
614 | ||
11bb1f11 JL |
615 | case CC_COMPARE: |
616 | /* The insn is a compare instruction. */ | |
617 | CC_STATUS_INIT; | |
618 | cc_status.value1 = SET_SRC (body); | |
619 | break; | |
620 | ||
3b800f71 JL |
621 | case CC_INVERT: |
622 | /* The insn is a compare instruction. */ | |
623 | CC_STATUS_INIT; | |
624 | cc_status.value1 = SET_SRC (body); | |
625 | cc_status.flags |= CC_INVERTED; | |
626 | break; | |
627 | ||
11bb1f11 JL |
628 | case CC_CLOBBER: |
629 | /* Insn doesn't leave CC in a usable state. */ | |
630 | CC_STATUS_INIT; | |
631 | break; | |
82c6faa8 JL |
632 | |
633 | default: | |
634 | abort (); | |
11bb1f11 | 635 | } |
11bb1f11 JL |
636 | } |
637 | ||
638 | /* Return true if OP is a valid call operand. */ | |
639 | ||
640 | int | |
641 | call_address_operand (op, mode) | |
642 | rtx op; | |
643 | enum machine_mode mode; | |
644 | { | |
645 | return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == REG); | |
646 | } | |
647 | ||
648 | /* What (if any) secondary registers are needed to move IN with mode | |
649 | MODE into a register from in register class CLASS. | |
650 | ||
651 | We might be able to simplify this. */ | |
652 | enum reg_class | |
653 | secondary_reload_class (class, mode, in) | |
654 | enum reg_class class; | |
655 | enum machine_mode mode; | |
656 | rtx in; | |
657 | { | |
658 | int regno; | |
659 | ||
660 | /* Memory loads less than a full word wide can't have an | |
661 | address or stack pointer destination. They must use | |
662 | a data register as an intermediate register. */ | |
663 | if (GET_CODE (in) == MEM | |
664 | && (mode == QImode || mode == HImode) | |
665 | && (class == ADDRESS_REGS || class == SP_REGS)) | |
666 | return DATA_REGS; | |
667 | ||
668 | /* We can't directly load sp + const_int into a data register; | |
669 | we must use an address register as an intermediate. */ | |
777fbf09 JL |
670 | if (class != SP_REGS |
671 | && class != ADDRESS_REGS | |
672 | && class != SP_OR_ADDRESS_REGS | |
11bb1f11 JL |
673 | && (in == stack_pointer_rtx |
674 | || (GET_CODE (in) == PLUS | |
777fbf09 JL |
675 | && (XEXP (in, 0) == stack_pointer_rtx |
676 | || XEXP (in, 1) == stack_pointer_rtx)))) | |
11bb1f11 JL |
677 | return ADDRESS_REGS; |
678 | ||
4c742813 JL |
679 | if (GET_CODE (in) == PLUS |
680 | && (XEXP (in, 0) == stack_pointer_rtx | |
681 | || XEXP (in, 1) == stack_pointer_rtx)) | |
682 | return DATA_REGS; | |
683 | ||
684 | ||
777fbf09 JL |
685 | /* Otherwise assume no secondary reloads are needed. */ |
686 | return NO_REGS; | |
687 | } | |
688 | ||
689 | int | |
690 | initial_offset (from, to) | |
691 | int from, to; | |
692 | { | |
3dbc43d1 JL |
693 | /* The difference between the argument pointer and the frame pointer |
694 | is the size of the callee register save area. */ | |
777fbf09 | 695 | if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM) |
11bb1f11 | 696 | { |
777fbf09 JL |
697 | if (regs_ever_live[2] || regs_ever_live[3] |
698 | || regs_ever_live[6] || regs_ever_live[7] | |
699 | || frame_pointer_needed) | |
22ef4e9b | 700 | return 16; |
777fbf09 | 701 | else |
22ef4e9b | 702 | return 0; |
11bb1f11 JL |
703 | } |
704 | ||
3dbc43d1 JL |
705 | /* The difference between the argument pointer and the stack pointer is |
706 | the sum of the size of this function's frame, the callee register save | |
707 | area, and the fixed stack space needed for function calls (if any). */ | |
777fbf09 JL |
708 | if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM) |
709 | { | |
710 | if (regs_ever_live[2] || regs_ever_live[3] | |
711 | || regs_ever_live[6] || regs_ever_live[7] | |
712 | || frame_pointer_needed) | |
460f4b9d JL |
713 | return (get_frame_size () + 16 |
714 | + (current_function_outgoing_args_size | |
715 | ? current_function_outgoing_args_size + 4 : 0)); | |
777fbf09 | 716 | else |
460f4b9d JL |
717 | return (get_frame_size () |
718 | + (current_function_outgoing_args_size | |
719 | ? current_function_outgoing_args_size + 4 : 0)); | |
777fbf09 | 720 | } |
11bb1f11 | 721 | |
3dbc43d1 JL |
722 | /* The difference between the frame pointer and stack pointer is the sum |
723 | of the size of this function's frame and the fixed stack space needed | |
724 | for function calls (if any). */ | |
777fbf09 | 725 | if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) |
460f4b9d JL |
726 | return (get_frame_size () |
727 | + (current_function_outgoing_args_size | |
728 | ? current_function_outgoing_args_size + 4 : 0)); | |
777fbf09 JL |
729 | |
730 | abort (); | |
11bb1f11 | 731 | } |
22ef4e9b JL |
732 | |
733 | /* Flush the argument registers to the stack for a stdarg function; | |
734 | return the new argument pointer. */ | |
735 | rtx | |
736 | mn10300_builtin_saveregs (arglist) | |
737 | tree arglist; | |
738 | { | |
739 | rtx offset; | |
740 | tree fntype = TREE_TYPE (current_function_decl); | |
741 | int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0 | |
742 | && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) | |
743 | != void_type_node))) | |
744 | ? UNITS_PER_WORD : 0); | |
745 | ||
746 | if (argadj) | |
747 | offset = plus_constant (current_function_arg_offset_rtx, argadj); | |
748 | else | |
749 | offset = current_function_arg_offset_rtx; | |
750 | ||
751 | emit_move_insn (gen_rtx (MEM, SImode, current_function_internal_arg_pointer), | |
752 | gen_rtx (REG, SImode, 0)); | |
753 | emit_move_insn (gen_rtx (MEM, SImode, | |
754 | plus_constant | |
755 | (current_function_internal_arg_pointer, 4)), | |
756 | gen_rtx (REG, SImode, 1)); | |
757 | return copy_to_reg (expand_binop (Pmode, add_optab, | |
758 | current_function_internal_arg_pointer, | |
759 | offset, 0, 0, OPTAB_LIB_WIDEN)); | |
760 | } | |
761 | ||
762 | /* Return an RTX to represent where a value with mode MODE will be returned | |
763 | from a function. If the result is 0, the argument is pushed. */ | |
764 | ||
765 | rtx | |
766 | function_arg (cum, mode, type, named) | |
767 | CUMULATIVE_ARGS *cum; | |
768 | enum machine_mode mode; | |
769 | tree type; | |
770 | int named; | |
771 | { | |
772 | rtx result = 0; | |
773 | int size, align; | |
774 | ||
775 | /* We only support using 2 data registers as argument registers. */ | |
776 | int nregs = 2; | |
777 | ||
778 | /* Figure out the size of the object to be passed. */ | |
779 | if (mode == BLKmode) | |
780 | size = int_size_in_bytes (type); | |
781 | else | |
782 | size = GET_MODE_SIZE (mode); | |
783 | ||
784 | /* Figure out the alignment of the object to be passed. */ | |
785 | align = size; | |
786 | ||
787 | cum->nbytes = (cum->nbytes + 3) & ~3; | |
788 | ||
789 | /* Don't pass this arg via a register if all the argument registers | |
790 | are used up. */ | |
791 | if (cum->nbytes > nregs * UNITS_PER_WORD) | |
792 | return 0; | |
793 | ||
794 | /* Don't pass this arg via a register if it would be split between | |
795 | registers and memory. */ | |
796 | if (type == NULL_TREE | |
797 | && cum->nbytes + size > nregs * UNITS_PER_WORD) | |
798 | return 0; | |
799 | ||
800 | switch (cum->nbytes / UNITS_PER_WORD) | |
801 | { | |
802 | case 0: | |
803 | result = gen_rtx (REG, mode, 0); | |
804 | break; | |
805 | case 1: | |
806 | result = gen_rtx (REG, mode, 1); | |
807 | break; | |
808 | default: | |
809 | result = 0; | |
810 | } | |
811 | ||
812 | return result; | |
813 | } | |
814 | ||
815 | /* Return the number of registers to use for an argument passed partially | |
816 | in registers and partially in memory. */ | |
817 | ||
818 | int | |
819 | function_arg_partial_nregs (cum, mode, type, named) | |
820 | CUMULATIVE_ARGS *cum; | |
821 | enum machine_mode mode; | |
822 | tree type; | |
823 | int named; | |
824 | { | |
825 | int size, align; | |
826 | ||
827 | /* We only support using 2 data registers as argument registers. */ | |
828 | int nregs = 2; | |
829 | ||
830 | /* Figure out the size of the object to be passed. */ | |
831 | if (mode == BLKmode) | |
832 | size = int_size_in_bytes (type); | |
833 | else | |
834 | size = GET_MODE_SIZE (mode); | |
835 | ||
836 | /* Figure out the alignment of the object to be passed. */ | |
837 | align = size; | |
838 | ||
839 | cum->nbytes = (cum->nbytes + 3) & ~3; | |
840 | ||
841 | /* Don't pass this arg via a register if all the argument registers | |
842 | are used up. */ | |
843 | if (cum->nbytes > nregs * UNITS_PER_WORD) | |
844 | return 0; | |
845 | ||
846 | if (cum->nbytes + size <= nregs * UNITS_PER_WORD) | |
847 | return 0; | |
848 | ||
849 | /* Don't pass this arg via a register if it would be split between | |
850 | registers and memory. */ | |
851 | if (type == NULL_TREE | |
852 | && cum->nbytes + size > nregs * UNITS_PER_WORD) | |
853 | return 0; | |
854 | ||
855 | return (nregs * UNITS_PER_WORD - cum->nbytes) / UNITS_PER_WORD; | |
856 | } | |
857 | ||
858 | /* Output a tst insn. */ | |
859 | char * | |
860 | output_tst (operand, insn) | |
861 | rtx operand, insn; | |
862 | { | |
22ef4e9b JL |
863 | rtx temp; |
864 | int past_call = 0; | |
865 | ||
74452ac3 JL |
866 | /* If we have a data register which is known to be zero throughout |
867 | the function, then use it instead of doing a search. */ | |
868 | if (zero_dreg && REGNO_REG_CLASS (REGNO (operand)) == DATA_REGS) | |
869 | { | |
870 | rtx xoperands[2]; | |
871 | xoperands[0] = operand; | |
872 | xoperands[1] = zero_dreg; | |
873 | ||
874 | output_asm_insn ("cmp %1,%0", xoperands); | |
875 | return ""; | |
876 | } | |
877 | ||
878 | /* Similarly for address registers. */ | |
879 | if (zero_areg && REGNO_REG_CLASS (REGNO (operand)) == ADDRESS_REGS) | |
880 | { | |
881 | rtx xoperands[2]; | |
882 | xoperands[0] = operand; | |
883 | xoperands[1] = zero_areg; | |
884 | ||
885 | output_asm_insn ("cmp %1,%0", xoperands); | |
886 | return ""; | |
887 | } | |
888 | ||
22ef4e9b JL |
889 | /* We can save a byte if we can find a register which has the value |
890 | zero in it. */ | |
891 | temp = PREV_INSN (insn); | |
74452ac3 | 892 | while (optimize && temp) |
22ef4e9b JL |
893 | { |
894 | rtx set; | |
895 | ||
896 | /* We allow the search to go through call insns. We record | |
897 | the fact that we've past a CALL_INSN and reject matches which | |
898 | use call clobbered registers. */ | |
899 | if (GET_CODE (temp) == CODE_LABEL | |
900 | || GET_CODE (temp) == JUMP_INSN | |
901 | || GET_CODE (temp) == BARRIER) | |
902 | break; | |
903 | ||
904 | if (GET_CODE (temp) == CALL_INSN) | |
905 | past_call = 1; | |
906 | ||
907 | if (GET_CODE (temp) == NOTE) | |
908 | { | |
909 | temp = PREV_INSN (temp); | |
910 | continue; | |
911 | } | |
912 | ||
913 | /* It must be an insn, see if it is a simple set. */ | |
914 | set = single_set (temp); | |
915 | if (!set) | |
916 | { | |
917 | temp = PREV_INSN (temp); | |
918 | continue; | |
919 | } | |
920 | ||
921 | /* Are we setting a data register to zero (this does not win for | |
922 | address registers)? | |
923 | ||
924 | If it's a call clobbered register, have we past a call? | |
925 | ||
926 | Make sure the register we find isn't the same as ourself; | |
927 | the mn10300 can't encode that. */ | |
928 | if (REG_P (SET_DEST (set)) | |
929 | && SET_SRC (set) == CONST0_RTX (GET_MODE (SET_DEST (set))) | |
930 | && !reg_set_between_p (SET_DEST (set), temp, insn) | |
74452ac3 JL |
931 | && (REGNO_REG_CLASS (REGNO (SET_DEST (set))) |
932 | == REGNO_REG_CLASS (REGNO (operand))) | |
22ef4e9b JL |
933 | && REGNO (SET_DEST (set)) != REGNO (operand) |
934 | && (!past_call | |
935 | || !call_used_regs[REGNO (SET_DEST (set))])) | |
936 | { | |
937 | rtx xoperands[2]; | |
938 | xoperands[0] = operand; | |
939 | xoperands[1] = SET_DEST (set); | |
940 | ||
941 | output_asm_insn ("cmp %1,%0", xoperands); | |
942 | return ""; | |
943 | } | |
944 | temp = PREV_INSN (temp); | |
945 | } | |
946 | return "cmp 0,%0"; | |
947 | } | |
460f4b9d JL |
948 | |
949 | int | |
950 | impossible_plus_operand (op, mode) | |
951 | rtx op; | |
952 | enum machine_mode mode; | |
953 | { | |
954 | extern rtx *reg_equiv_mem; | |
955 | rtx reg1, reg2; | |
956 | ||
957 | if (GET_CODE (op) != PLUS) | |
958 | return 0; | |
959 | ||
4c742813 JL |
960 | if (XEXP (op, 0) == stack_pointer_rtx |
961 | || XEXP (op, 1) == stack_pointer_rtx) | |
460f4b9d JL |
962 | return 1; |
963 | ||
460f4b9d JL |
964 | return 0; |
965 | } |