]>
Commit | Line | Data |
---|---|---|
11bb1f11 JL |
1 | /* Subroutines for insn-output.c for Matsushita MN10300 series |
2 | Copyright (C) 1996 Free Software Foundation, Inc. | |
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 | ||
39 | void | |
40 | asm_file_start (file) | |
41 | FILE *file; | |
42 | { | |
43 | fprintf (file, "#\tGCC For the Matsushita MN10300\n"); | |
44 | if (optimize) | |
45 | fprintf (file, "# -O%d\n", optimize); | |
46 | else | |
47 | fprintf (file, "\n\n"); | |
48 | output_file_directive (file, main_input_filename); | |
49 | } | |
50 | \f | |
51 | ||
11bb1f11 JL |
52 | /* Print operand X using operand code CODE to assembly language output file |
53 | FILE. */ | |
54 | ||
55 | void | |
56 | print_operand (file, x, code) | |
57 | FILE *file; | |
58 | rtx x; | |
59 | int code; | |
60 | { | |
61 | switch (code) | |
62 | { | |
63 | case 'b': | |
64 | case 'B': | |
65 | /* These are normal and reversed branches. */ | |
66 | switch (code == 'b' ? GET_CODE (x) : reverse_condition (GET_CODE (x))) | |
67 | { | |
68 | case NE: | |
69 | fprintf (file, "ne"); | |
70 | break; | |
71 | case EQ: | |
72 | fprintf (file, "eq"); | |
73 | break; | |
74 | case GE: | |
75 | fprintf (file, "ge"); | |
76 | break; | |
77 | case GT: | |
78 | fprintf (file, "gt"); | |
79 | break; | |
80 | case LE: | |
81 | fprintf (file, "le"); | |
82 | break; | |
83 | case LT: | |
84 | fprintf (file, "lt"); | |
85 | break; | |
86 | case GEU: | |
87 | fprintf (file, "cc"); | |
88 | break; | |
89 | case GTU: | |
90 | fprintf (file, "hi"); | |
91 | break; | |
92 | case LEU: | |
93 | fprintf (file, "ls"); | |
94 | break; | |
95 | case LTU: | |
96 | fprintf (file, "cs"); | |
97 | break; | |
98 | default: | |
99 | abort (); | |
100 | } | |
101 | break; | |
102 | case 'C': | |
103 | /* This is used for the operand to a call instruction; | |
104 | if it's a REG, enclose it in parens, else output | |
105 | the operand normally. */ | |
106 | if (GET_CODE (x) == REG) | |
107 | { | |
108 | fputc ('(', file); | |
109 | print_operand (file, x, 0); | |
110 | fputc (')', file); | |
111 | } | |
112 | else | |
113 | print_operand (file, x, 0); | |
114 | break; | |
115 | ||
38c37a0e JL |
116 | /* These are the least significant word in a 64bit value. */ |
117 | case 'L': | |
118 | switch (GET_CODE (x)) | |
119 | { | |
120 | case MEM: | |
121 | fputc ('(', file); | |
122 | output_address (XEXP (x, 0)); | |
123 | fputc (')', file); | |
124 | break; | |
125 | ||
126 | case REG: | |
127 | fprintf (file, "%s", reg_names[REGNO (x)]); | |
128 | break; | |
129 | ||
130 | case SUBREG: | |
131 | fprintf (file, "%s", | |
132 | reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)]); | |
133 | break; | |
134 | ||
135 | case CONST_DOUBLE: | |
136 | { | |
137 | long val[2]; | |
138 | REAL_VALUE_TYPE rv; | |
139 | ||
140 | switch (GET_MODE (x)) | |
141 | { | |
142 | case DFmode: | |
143 | REAL_VALUE_FROM_CONST_DOUBLE (rv, x); | |
144 | REAL_VALUE_TO_TARGET_DOUBLE (rv, val); | |
145 | print_operand_address (file, GEN_INT (val[0])); | |
146 | break;; | |
147 | case SFmode: | |
148 | REAL_VALUE_FROM_CONST_DOUBLE (rv, x); | |
149 | REAL_VALUE_TO_TARGET_SINGLE (rv, val[0]); | |
150 | print_operand_address (file, GEN_INT (val[0])); | |
151 | break;; | |
152 | case VOIDmode: | |
153 | case DImode: | |
154 | print_operand_address (file, | |
155 | GEN_INT (CONST_DOUBLE_LOW (x))); | |
156 | break; | |
157 | } | |
158 | break; | |
159 | } | |
160 | ||
161 | case CONST_INT: | |
162 | print_operand_address (file, x); | |
163 | break; | |
164 | ||
165 | default: | |
166 | abort (); | |
167 | } | |
168 | break; | |
169 | ||
170 | /* Similarly, but for the most significant word. */ | |
171 | case 'H': | |
172 | switch (GET_CODE (x)) | |
173 | { | |
174 | case MEM: | |
175 | fputc ('(', file); | |
176 | x = adj_offsettable_operand (x, 4); | |
177 | output_address (XEXP (x, 0)); | |
178 | fputc (')', file); | |
179 | break; | |
180 | ||
181 | case REG: | |
182 | fprintf (file, "%s", reg_names[REGNO (x) + 1]); | |
183 | break; | |
184 | ||
185 | case SUBREG: | |
186 | fprintf (file, "%s", | |
187 | reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)] + 1); | |
188 | break; | |
189 | ||
190 | case CONST_DOUBLE: | |
191 | { | |
192 | long val[2]; | |
193 | REAL_VALUE_TYPE rv; | |
194 | ||
195 | switch (GET_MODE (x)) | |
196 | { | |
197 | case DFmode: | |
198 | REAL_VALUE_FROM_CONST_DOUBLE (rv, x); | |
199 | REAL_VALUE_TO_TARGET_DOUBLE (rv, val); | |
200 | print_operand_address (file, GEN_INT (val[1])); | |
201 | break;; | |
202 | case SFmode: | |
203 | abort (); | |
204 | case VOIDmode: | |
205 | case DImode: | |
206 | print_operand_address (file, | |
207 | GEN_INT (CONST_DOUBLE_HIGH (x))); | |
208 | break; | |
209 | } | |
210 | break; | |
211 | } | |
212 | ||
213 | case CONST_INT: | |
214 | if (INTVAL (x) < 0) | |
215 | print_operand_address (file, GEN_INT (-1)); | |
216 | else | |
217 | print_operand_address (file, GEN_INT (0)); | |
218 | break; | |
219 | default: | |
220 | abort (); | |
221 | } | |
222 | break; | |
223 | ||
224 | case 'A': | |
225 | fputc ('(', file); | |
226 | if (GET_CODE (XEXP (x, 0)) == REG) | |
227 | output_address (gen_rtx (PLUS, SImode, XEXP (x, 0), GEN_INT (0))); | |
228 | else | |
229 | output_address (XEXP (x, 0)); | |
230 | fputc (')', file); | |
231 | break; | |
232 | ||
6fafc523 JL |
233 | case 'N': |
234 | output_address (GEN_INT ((~INTVAL (x)) & 0xff)); | |
235 | break; | |
236 | ||
11bb1f11 JL |
237 | default: |
238 | switch (GET_CODE (x)) | |
239 | { | |
240 | case MEM: | |
241 | fputc ('(', file); | |
242 | output_address (XEXP (x, 0)); | |
243 | fputc (')', file); | |
244 | break; | |
245 | ||
38c37a0e JL |
246 | case PLUS: |
247 | output_address (x); | |
248 | break; | |
249 | ||
11bb1f11 JL |
250 | case REG: |
251 | fprintf (file, "%s", reg_names[REGNO (x)]); | |
252 | break; | |
253 | ||
254 | case SUBREG: | |
255 | fprintf (file, "%s", | |
256 | reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)]); | |
257 | break; | |
258 | ||
38c37a0e JL |
259 | /* This will only be single precision.... */ |
260 | case CONST_DOUBLE: | |
261 | { | |
262 | unsigned long val; | |
263 | REAL_VALUE_TYPE rv; | |
264 | ||
265 | REAL_VALUE_FROM_CONST_DOUBLE (rv, x); | |
266 | REAL_VALUE_TO_TARGET_SINGLE (rv, val); | |
267 | print_operand_address (file, GEN_INT (val)); | |
268 | break; | |
269 | } | |
270 | ||
11bb1f11 JL |
271 | case CONST_INT: |
272 | case SYMBOL_REF: | |
273 | case CONST: | |
274 | case LABEL_REF: | |
275 | case CODE_LABEL: | |
276 | print_operand_address (file, x); | |
277 | break; | |
278 | default: | |
279 | abort (); | |
280 | } | |
281 | break; | |
282 | } | |
283 | } | |
284 | ||
285 | /* Output assembly language output for the address ADDR to FILE. */ | |
286 | ||
287 | void | |
288 | print_operand_address (file, addr) | |
289 | FILE *file; | |
290 | rtx addr; | |
291 | { | |
292 | switch (GET_CODE (addr)) | |
293 | { | |
294 | case REG: | |
295 | if (addr == stack_pointer_rtx) | |
296 | print_operand_address (file, gen_rtx (PLUS, SImode, | |
297 | stack_pointer_rtx, | |
298 | GEN_INT (0))); | |
299 | else | |
300 | print_operand (file, addr, 0); | |
301 | break; | |
302 | case PLUS: | |
303 | { | |
304 | rtx base, index; | |
305 | if (REG_P (XEXP (addr, 0)) | |
306 | && REG_OK_FOR_BASE_P (XEXP (addr, 0))) | |
307 | base = XEXP (addr, 0), index = XEXP (addr, 1); | |
308 | else if (REG_P (XEXP (addr, 1)) | |
309 | && REG_OK_FOR_BASE_P (XEXP (addr, 1))) | |
310 | base = XEXP (addr, 1), index = XEXP (addr, 0); | |
311 | else | |
312 | abort (); | |
313 | print_operand (file, index, 0); | |
314 | fputc (',', file); | |
315 | print_operand (file, base, 0);; | |
316 | break; | |
317 | } | |
318 | case SYMBOL_REF: | |
319 | output_addr_const (file, addr); | |
320 | break; | |
321 | default: | |
322 | output_addr_const (file, addr); | |
323 | break; | |
324 | } | |
325 | } | |
326 | ||
38c37a0e JL |
327 | int |
328 | can_use_return_insn () | |
329 | { | |
330 | int size = get_frame_size (); | |
331 | ||
332 | return (reload_completed | |
333 | && size == 0 | |
334 | && !regs_ever_live[2] | |
335 | && !regs_ever_live[3] | |
336 | && !regs_ever_live[6] | |
337 | && !regs_ever_live[7] | |
338 | && !frame_pointer_needed); | |
339 | } | |
340 | ||
11bb1f11 JL |
341 | void |
342 | expand_prologue () | |
343 | { | |
344 | unsigned int size = get_frame_size (); | |
345 | ||
22ef4e9b JL |
346 | /* If this is an old-style varargs function, then its arguments |
347 | need to be flushed back to the stack. */ | |
348 | if (current_function_varargs) | |
349 | { | |
350 | emit_move_insn (gen_rtx (MEM, SImode, | |
351 | gen_rtx (PLUS, Pmode, stack_pointer_rtx, | |
352 | GEN_INT (4))), | |
353 | gen_rtx (REG, SImode, 0)); | |
354 | emit_move_insn (gen_rtx (MEM, SImode, | |
355 | gen_rtx (PLUS, Pmode, stack_pointer_rtx, | |
356 | GEN_INT (8))), | |
357 | gen_rtx (REG, SImode, 1)); | |
358 | } | |
359 | ||
777fbf09 JL |
360 | /* And now store all the registers onto the stack with a |
361 | single two byte instruction. */ | |
362 | if (regs_ever_live[2] || regs_ever_live[3] | |
363 | || regs_ever_live[6] || regs_ever_live[7] | |
364 | || frame_pointer_needed) | |
365 | emit_insn (gen_store_movm ()); | |
366 | ||
367 | /* Now put the frame pointer into the frame pointer register. */ | |
11bb1f11 | 368 | if (frame_pointer_needed) |
6e86170d | 369 | emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); |
11bb1f11 | 370 | |
777fbf09 | 371 | /* Allocate stack for this frame. */ |
11bb1f11 JL |
372 | if (size) |
373 | emit_insn (gen_addsi3 (stack_pointer_rtx, | |
374 | stack_pointer_rtx, | |
375 | GEN_INT (-size))); | |
376 | } | |
377 | ||
378 | void | |
379 | expand_epilogue () | |
380 | { | |
381 | unsigned int size = get_frame_size (); | |
382 | ||
383 | /* Cut back the stack. */ | |
384 | if (frame_pointer_needed) | |
385 | { | |
11bb1f11 | 386 | emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); |
4246e0c5 JL |
387 | size = 0; |
388 | } | |
6fafc523 JL |
389 | else if ((regs_ever_live[2] || regs_ever_live[3] |
390 | || regs_ever_live[6] || regs_ever_live[7]) | |
391 | && size > 255) | |
4246e0c5 JL |
392 | { |
393 | emit_insn (gen_addsi3 (stack_pointer_rtx, | |
394 | stack_pointer_rtx, | |
395 | GEN_INT (size))); | |
396 | size = 0; | |
11bb1f11 | 397 | } |
11bb1f11 | 398 | |
777fbf09 JL |
399 | /* For simplicity, we just movm all the callee saved registers to |
400 | the stack with one instruction. | |
401 | ||
402 | ?!? Only save registers which are actually used. Reduces | |
403 | stack requireents and is faster. */ | |
404 | if (regs_ever_live[2] || regs_ever_live[3] | |
405 | || regs_ever_live[6] || regs_ever_live[7] | |
406 | || frame_pointer_needed) | |
407 | emit_jump_insn (gen_return_internal_regs (GEN_INT (size))); | |
408 | else | |
409 | { | |
410 | if (size) | |
38c37a0e JL |
411 | { |
412 | emit_insn (gen_addsi3 (stack_pointer_rtx, | |
413 | stack_pointer_rtx, | |
414 | GEN_INT (size))); | |
415 | emit_jump_insn (gen_return_internal ()); | |
416 | } | |
417 | else | |
418 | { | |
419 | emit_jump_insn (gen_return ()); | |
420 | } | |
777fbf09 | 421 | } |
11bb1f11 JL |
422 | } |
423 | ||
424 | /* Update the condition code from the insn. */ | |
425 | ||
426 | void | |
427 | notice_update_cc (body, insn) | |
428 | rtx body; | |
429 | rtx insn; | |
430 | { | |
11bb1f11 JL |
431 | switch (get_attr_cc (insn)) |
432 | { | |
433 | case CC_NONE: | |
434 | /* Insn does not affect CC at all. */ | |
435 | break; | |
436 | ||
437 | case CC_NONE_0HIT: | |
438 | /* Insn does not change CC, but the 0'th operand has been changed. */ | |
439 | if (cc_status.value1 != 0 | |
440 | && reg_overlap_mentioned_p (recog_operand[0], cc_status.value1)) | |
441 | cc_status.value1 = 0; | |
442 | break; | |
443 | ||
444 | case CC_SET_ZN_C0: | |
445 | /* Insn sets the Z,N flags of CC to recog_operand[0]. | |
446 | V is always set to 0. C may or may not be set to 0 but that's ok | |
447 | because alter_cond will change tests to use EQ/NE. */ | |
448 | CC_STATUS_INIT; | |
777fbf09 | 449 | cc_status.flags |= CC_NO_OVERFLOW | CC_OVERFLOW_UNUSABLE; |
11bb1f11 JL |
450 | cc_status.value1 = recog_operand[0]; |
451 | break; | |
452 | ||
777fbf09 | 453 | case CC_TST: |
82c6faa8 JL |
454 | /* The insn sets all the condition codes, except v is bogus. */ |
455 | CC_STATUS_INIT; | |
82c6faa8 JL |
456 | cc_status.value1 = recog_operand[0]; |
457 | break; | |
458 | ||
11bb1f11 JL |
459 | case CC_COMPARE: |
460 | /* The insn is a compare instruction. */ | |
461 | CC_STATUS_INIT; | |
462 | cc_status.value1 = SET_SRC (body); | |
463 | break; | |
464 | ||
3b800f71 JL |
465 | case CC_INVERT: |
466 | /* The insn is a compare instruction. */ | |
467 | CC_STATUS_INIT; | |
468 | cc_status.value1 = SET_SRC (body); | |
469 | cc_status.flags |= CC_INVERTED; | |
470 | break; | |
471 | ||
11bb1f11 JL |
472 | case CC_CLOBBER: |
473 | /* Insn doesn't leave CC in a usable state. */ | |
474 | CC_STATUS_INIT; | |
475 | break; | |
82c6faa8 JL |
476 | |
477 | default: | |
478 | abort (); | |
11bb1f11 | 479 | } |
11bb1f11 JL |
480 | } |
481 | ||
482 | /* Return true if OP is a valid call operand. */ | |
483 | ||
484 | int | |
485 | call_address_operand (op, mode) | |
486 | rtx op; | |
487 | enum machine_mode mode; | |
488 | { | |
489 | return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == REG); | |
490 | } | |
491 | ||
492 | /* What (if any) secondary registers are needed to move IN with mode | |
493 | MODE into a register from in register class CLASS. | |
494 | ||
495 | We might be able to simplify this. */ | |
496 | enum reg_class | |
497 | secondary_reload_class (class, mode, in) | |
498 | enum reg_class class; | |
499 | enum machine_mode mode; | |
500 | rtx in; | |
501 | { | |
502 | int regno; | |
503 | ||
504 | /* Memory loads less than a full word wide can't have an | |
505 | address or stack pointer destination. They must use | |
506 | a data register as an intermediate register. */ | |
507 | if (GET_CODE (in) == MEM | |
508 | && (mode == QImode || mode == HImode) | |
509 | && (class == ADDRESS_REGS || class == SP_REGS)) | |
510 | return DATA_REGS; | |
511 | ||
512 | /* We can't directly load sp + const_int into a data register; | |
513 | we must use an address register as an intermediate. */ | |
777fbf09 JL |
514 | if (class != SP_REGS |
515 | && class != ADDRESS_REGS | |
516 | && class != SP_OR_ADDRESS_REGS | |
11bb1f11 JL |
517 | && (in == stack_pointer_rtx |
518 | || (GET_CODE (in) == PLUS | |
777fbf09 JL |
519 | && (XEXP (in, 0) == stack_pointer_rtx |
520 | || XEXP (in, 1) == stack_pointer_rtx)))) | |
11bb1f11 JL |
521 | return ADDRESS_REGS; |
522 | ||
777fbf09 JL |
523 | /* Otherwise assume no secondary reloads are needed. */ |
524 | return NO_REGS; | |
525 | } | |
526 | ||
527 | int | |
528 | initial_offset (from, to) | |
529 | int from, to; | |
530 | { | |
531 | if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM) | |
11bb1f11 | 532 | { |
777fbf09 JL |
533 | if (regs_ever_live[2] || regs_ever_live[3] |
534 | || regs_ever_live[6] || regs_ever_live[7] | |
535 | || frame_pointer_needed) | |
22ef4e9b | 536 | return 16; |
777fbf09 | 537 | else |
22ef4e9b | 538 | return 0; |
11bb1f11 JL |
539 | } |
540 | ||
777fbf09 JL |
541 | if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM) |
542 | { | |
543 | if (regs_ever_live[2] || regs_ever_live[3] | |
544 | || regs_ever_live[6] || regs_ever_live[7] | |
545 | || frame_pointer_needed) | |
22ef4e9b | 546 | return get_frame_size () + 16; |
777fbf09 | 547 | else |
22ef4e9b | 548 | return get_frame_size (); |
777fbf09 | 549 | } |
11bb1f11 | 550 | |
777fbf09 JL |
551 | if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) |
552 | return get_frame_size (); | |
553 | ||
554 | abort (); | |
11bb1f11 | 555 | } |
22ef4e9b JL |
556 | |
557 | /* Flush the argument registers to the stack for a stdarg function; | |
558 | return the new argument pointer. */ | |
559 | rtx | |
560 | mn10300_builtin_saveregs (arglist) | |
561 | tree arglist; | |
562 | { | |
563 | rtx offset; | |
564 | tree fntype = TREE_TYPE (current_function_decl); | |
565 | int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0 | |
566 | && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) | |
567 | != void_type_node))) | |
568 | ? UNITS_PER_WORD : 0); | |
569 | ||
570 | if (argadj) | |
571 | offset = plus_constant (current_function_arg_offset_rtx, argadj); | |
572 | else | |
573 | offset = current_function_arg_offset_rtx; | |
574 | ||
575 | emit_move_insn (gen_rtx (MEM, SImode, current_function_internal_arg_pointer), | |
576 | gen_rtx (REG, SImode, 0)); | |
577 | emit_move_insn (gen_rtx (MEM, SImode, | |
578 | plus_constant | |
579 | (current_function_internal_arg_pointer, 4)), | |
580 | gen_rtx (REG, SImode, 1)); | |
581 | return copy_to_reg (expand_binop (Pmode, add_optab, | |
582 | current_function_internal_arg_pointer, | |
583 | offset, 0, 0, OPTAB_LIB_WIDEN)); | |
584 | } | |
585 | ||
586 | /* Return an RTX to represent where a value with mode MODE will be returned | |
587 | from a function. If the result is 0, the argument is pushed. */ | |
588 | ||
589 | rtx | |
590 | function_arg (cum, mode, type, named) | |
591 | CUMULATIVE_ARGS *cum; | |
592 | enum machine_mode mode; | |
593 | tree type; | |
594 | int named; | |
595 | { | |
596 | rtx result = 0; | |
597 | int size, align; | |
598 | ||
599 | /* We only support using 2 data registers as argument registers. */ | |
600 | int nregs = 2; | |
601 | ||
602 | /* Figure out the size of the object to be passed. */ | |
603 | if (mode == BLKmode) | |
604 | size = int_size_in_bytes (type); | |
605 | else | |
606 | size = GET_MODE_SIZE (mode); | |
607 | ||
608 | /* Figure out the alignment of the object to be passed. */ | |
609 | align = size; | |
610 | ||
611 | cum->nbytes = (cum->nbytes + 3) & ~3; | |
612 | ||
613 | /* Don't pass this arg via a register if all the argument registers | |
614 | are used up. */ | |
615 | if (cum->nbytes > nregs * UNITS_PER_WORD) | |
616 | return 0; | |
617 | ||
618 | /* Don't pass this arg via a register if it would be split between | |
619 | registers and memory. */ | |
620 | if (type == NULL_TREE | |
621 | && cum->nbytes + size > nregs * UNITS_PER_WORD) | |
622 | return 0; | |
623 | ||
624 | switch (cum->nbytes / UNITS_PER_WORD) | |
625 | { | |
626 | case 0: | |
627 | result = gen_rtx (REG, mode, 0); | |
628 | break; | |
629 | case 1: | |
630 | result = gen_rtx (REG, mode, 1); | |
631 | break; | |
632 | default: | |
633 | result = 0; | |
634 | } | |
635 | ||
636 | return result; | |
637 | } | |
638 | ||
639 | /* Return the number of registers to use for an argument passed partially | |
640 | in registers and partially in memory. */ | |
641 | ||
642 | int | |
643 | function_arg_partial_nregs (cum, mode, type, named) | |
644 | CUMULATIVE_ARGS *cum; | |
645 | enum machine_mode mode; | |
646 | tree type; | |
647 | int named; | |
648 | { | |
649 | int size, align; | |
650 | ||
651 | /* We only support using 2 data registers as argument registers. */ | |
652 | int nregs = 2; | |
653 | ||
654 | /* Figure out the size of the object to be passed. */ | |
655 | if (mode == BLKmode) | |
656 | size = int_size_in_bytes (type); | |
657 | else | |
658 | size = GET_MODE_SIZE (mode); | |
659 | ||
660 | /* Figure out the alignment of the object to be passed. */ | |
661 | align = size; | |
662 | ||
663 | cum->nbytes = (cum->nbytes + 3) & ~3; | |
664 | ||
665 | /* Don't pass this arg via a register if all the argument registers | |
666 | are used up. */ | |
667 | if (cum->nbytes > nregs * UNITS_PER_WORD) | |
668 | return 0; | |
669 | ||
670 | if (cum->nbytes + size <= nregs * UNITS_PER_WORD) | |
671 | return 0; | |
672 | ||
673 | /* Don't pass this arg via a register if it would be split between | |
674 | registers and memory. */ | |
675 | if (type == NULL_TREE | |
676 | && cum->nbytes + size > nregs * UNITS_PER_WORD) | |
677 | return 0; | |
678 | ||
679 | return (nregs * UNITS_PER_WORD - cum->nbytes) / UNITS_PER_WORD; | |
680 | } | |
681 | ||
682 | /* Output a tst insn. */ | |
683 | char * | |
684 | output_tst (operand, insn) | |
685 | rtx operand, insn; | |
686 | { | |
687 | ||
688 | rtx temp; | |
689 | int past_call = 0; | |
690 | ||
691 | /* We can save a byte if we can find a register which has the value | |
692 | zero in it. */ | |
693 | temp = PREV_INSN (insn); | |
694 | while (temp) | |
695 | { | |
696 | rtx set; | |
697 | ||
698 | /* We allow the search to go through call insns. We record | |
699 | the fact that we've past a CALL_INSN and reject matches which | |
700 | use call clobbered registers. */ | |
701 | if (GET_CODE (temp) == CODE_LABEL | |
702 | || GET_CODE (temp) == JUMP_INSN | |
703 | || GET_CODE (temp) == BARRIER) | |
704 | break; | |
705 | ||
706 | if (GET_CODE (temp) == CALL_INSN) | |
707 | past_call = 1; | |
708 | ||
709 | if (GET_CODE (temp) == NOTE) | |
710 | { | |
711 | temp = PREV_INSN (temp); | |
712 | continue; | |
713 | } | |
714 | ||
715 | /* It must be an insn, see if it is a simple set. */ | |
716 | set = single_set (temp); | |
717 | if (!set) | |
718 | { | |
719 | temp = PREV_INSN (temp); | |
720 | continue; | |
721 | } | |
722 | ||
723 | /* Are we setting a data register to zero (this does not win for | |
724 | address registers)? | |
725 | ||
726 | If it's a call clobbered register, have we past a call? | |
727 | ||
728 | Make sure the register we find isn't the same as ourself; | |
729 | the mn10300 can't encode that. */ | |
730 | if (REG_P (SET_DEST (set)) | |
731 | && SET_SRC (set) == CONST0_RTX (GET_MODE (SET_DEST (set))) | |
732 | && !reg_set_between_p (SET_DEST (set), temp, insn) | |
733 | && REGNO_REG_CLASS (REGNO (SET_DEST (set))) == DATA_REGS | |
734 | && REGNO (SET_DEST (set)) != REGNO (operand) | |
735 | && (!past_call | |
736 | || !call_used_regs[REGNO (SET_DEST (set))])) | |
737 | { | |
738 | rtx xoperands[2]; | |
739 | xoperands[0] = operand; | |
740 | xoperands[1] = SET_DEST (set); | |
741 | ||
742 | output_asm_insn ("cmp %1,%0", xoperands); | |
743 | return ""; | |
744 | } | |
745 | temp = PREV_INSN (temp); | |
746 | } | |
747 | return "cmp 0,%0"; | |
748 | } |