Initial revision
[official-gcc.git] / gcc / config / pdp11 / pdp11.c
blob19b41485e7d9ce8c6120f285edf491738df9e6fe
1 /* Subroutines for gcc2 for pdp11.
2 Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
3 Contributed by Michael K. Gschwind (mike@vlsivie.tuwien.ac.at).
5 This file is part of GNU CC.
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 1, or (at your option)
10 any later version.
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.
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. */
22 #ifndef FILE
23 #include <stdio.h>
24 #endif
25 #include "config.h"
26 #include "rtl.h"
27 #include "regs.h"
28 #include "hard-reg-set.h"
29 #include "real.h"
30 #include "insn-config.h"
31 #include "conditions.h"
32 #include "insn-flags.h"
33 #include "output.h"
34 #include "insn-attr.h"
35 #include "flags.h"
38 #define FPU_REG_P(X) ((X)>=8 && (X)<14)
39 #define CPU_REG_P(X) ((X)>=0 && (X)<8)
42 /* this is the current value returned by the macro FIRST_PARM_OFFSET
43 defined in tm.h */
44 int current_first_parm_offset;
46 /* This is where the condition code register lives. */
47 /* rtx cc0_reg_rtx; - no longer needed? */
49 static rtx find_addr_reg ();
51 /* Nonzero if OP is a valid second operand for an arithmetic insn. */
53 int
54 arith_operand (op, mode)
55 rtx op;
56 enum machine_mode mode;
58 return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
61 int
62 const_immediate_operand (op, mode)
63 rtx op;
64 enum machine_mode mode;
66 return (GET_CODE (op) == CONST_INT);
69 int
70 immediate15_operand (op, mode)
71 rtx op;
72 enum machine_mode mode;
74 return (GET_CODE (op) == CONST_INT && ((INTVAL (op) & 0x8000) == 0x0000));
77 int
78 expand_shift_operand (op, mode)
79 rtx op;
80 enum machine_mode mode;
82 return (GET_CODE (op) == CONST_INT
83 && abs (INTVAL(op)) > 1
84 && abs (INTVAL(op)) <= 4);
88 stream is a stdio stream to output the code to.
89 size is an int: how many units of temporary storage to allocate.
90 Refer to the array `regs_ever_live' to determine which registers
91 to save; `regs_ever_live[I]' is nonzero if register number I
92 is ever used in the function. This macro is responsible for
93 knowing which registers should not be saved even if used.
96 void
97 output_function_prologue(stream, size)
98 FILE *stream;
99 int size;
101 int fsize = ((size) + 1) & ~1;
102 int regno, nregs, i;
103 int offset = 0;
105 int via_ac = -1;
107 fprintf (stream, "\n\t; /* function prologue %s*/\n", current_function_name);
109 /* if we are outputting code for main,
110 the switch FPU to right mode if TARGET_FPU */
111 if ( (strcmp ("main", current_function_name) == 0)
112 && TARGET_FPU)
114 fprintf(stream, "\t;/* switch cpu to double float, single integer */\n");
115 fprintf(stream, "\tsetd\n");
116 fprintf(stream, "\tseti\n\n");
119 if (frame_pointer_needed)
121 fprintf(stream, "\tmov fp, -(sp)\n");
122 fprintf(stream, "\tmov sp, fp\n");
124 else
126 /* DON'T SAVE FP */
129 /* make frame */
130 if (fsize)
131 fprintf (stream, "\tsub $%d, sp\n", fsize);
133 /* save CPU registers */
134 for (regno = 0; regno < 8; regno++)
135 if (regs_ever_live[regno] && ! call_used_regs[regno])
136 if (! ((regno == FRAME_POINTER_REGNUM)
137 && frame_pointer_needed))
138 fprintf (stream, "\tmov %s, -(sp)\n", reg_names[regno]);
139 /* fpu regs saving */
141 /* via_ac specifies the ac to use for saving ac4, ac5 */
142 via_ac = -1;
144 for (regno = 8; regno < FIRST_PSEUDO_REGISTER ; regno++)
146 /* ac0 - ac3 */
147 if (LOAD_FPU_REG_P(regno)
148 && regs_ever_live[regno]
149 && ! call_used_regs[regno])
151 fprintf (stream, "\tfstd %s, -(sp)\n", reg_names[regno]);
152 via_ac = regno;
155 /* maybe make ac4, ac5 call used regs?? */
156 /* ac4 - ac5 */
157 if (NO_LOAD_FPU_REG_P(regno)
158 && regs_ever_live[regno]
159 && ! call_used_regs[regno])
161 if (via_ac == -1)
162 abort();
164 fprintf (stream, "\tfldd %s, %s\n", reg_names[regno], reg_names[via_ac]);
165 fprintf (stream, "\tfstd %s, -(sp)\n", reg_names[via_ac]);
169 fprintf (stream, "\t;/* end of prologue */\n\n");
173 The function epilogue should not depend on the current stack pointer!
174 It should use the frame pointer only. This is mandatory because
175 of alloca; we also take advantage of it to omit stack adjustments
176 before returning. */
178 /* maybe we can make leaf functions faster by switching to the
179 second register file - this way we don't have to save regs!
180 leaf functions are ~ 50% of all functions (dynamically!)
182 set/clear bit 11 (dec. 2048) of status word for switching register files -
183 but how can we do this? the pdp11/45 manual says bit may only
184 be set (p.24), but not cleared!
186 switching to kernel is probably more expensive, so we'll leave it
187 like this and not use the second set of registers...
189 maybe as option if you want to generate code for kernel mode? */
192 void
193 output_function_epilogue(stream, size)
194 FILE *stream;
195 int size;
197 extern int may_call_alloca;
199 int fsize = ((size) + 1) & ~1;
200 int nregs, regno, i, j, k, adjust_fp;
202 int via_ac;
204 fprintf (stream, "\n\t; /*function epilogue */\n");
206 if (frame_pointer_needed)
208 /* hope this is safe - m68k does it also .... */
209 regs_ever_live[FRAME_POINTER_REGNUM] = 0;
211 for (i =7, j = 0 ; i >= 0 ; i--)
212 if (regs_ever_live[i] && ! call_used_regs[i])
213 j++;
215 /* remember # of pushed bytes for CPU regs */
216 k = 2*j;
218 for (i =7 ; i >= 0 ; i--)
219 if (regs_ever_live[i] && ! call_used_regs[i])
220 fprintf(stream, "\tmov %d(fp), %s\n",-fsize-2*j--, reg_names[i]);
222 /* get ACs */
223 via_ac = FIRST_PSEUDO_REGISTER -1;
225 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
226 if (regs_ever_live[i] && ! call_used_regs[i])
228 via_ac = i;
229 k += 8;
232 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
234 if (LOAD_FPU_REG_P(i)
235 && regs_ever_live[i]
236 && ! call_used_regs[i])
238 fprintf(stream, "\tfldd %d(fp), %s\n", -fsize-k, reg_names[i]);
239 k -= 8;
242 if (NO_LOAD_FPU_REG_P(i)
243 && regs_ever_live[i]
244 && ! call_used_regs[i])
246 if (! LOAD_FPU_REG_P(via_ac))
247 abort();
249 fprintf(stream, "\tfldd %d(fp), %s\n", -fsize-k, reg_names[via_ac]);
250 fprintf(stream, "\tfstd %s, %s\n", reg_names[via_ac], reg_names[i]);
251 k -= 8;
255 fprintf(stream, "\tmov fp, sp\n");
256 fprintf (stream, "\tmov (sp)+, fp\n");
258 else
260 via_ac = FIRST_PSEUDO_REGISTER -1;
262 /* get ACs */
263 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
264 if (regs_ever_live[i] && call_used_regs[i])
265 via_ac = i;
267 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
269 if (LOAD_FPU_REG_P(i)
270 && regs_ever_live[i]
271 && ! call_used_regs[i])
272 fprintf(stream, "\tfldd (sp)+, %s\n", reg_names[i]);
274 if (NO_LOAD_FPU_REG_P(i)
275 && regs_ever_live[i]
276 && ! call_used_regs[i])
278 if (! LOAD_FPU_REG_P(via_ac))
279 abort();
281 fprintf(stream, "\tfldd (sp)+, %s\n", reg_names[via_ac]);
282 fprintf(stream, "\tfstd %s, %s\n", reg_names[via_ac], reg_names[i]);
286 for (i=7; i >= 0; i--)
287 if (regs_ever_live[i] && !call_used_regs[i])
288 fprintf(stream, "\tmov (sp)+, %s\n", reg_names[i]);
290 if (fsize)
291 fprintf((stream), "\tadd $%d, sp\n", fsize);
294 fprintf (stream, "\trts pc\n");
295 fprintf (stream, "\t;/* end of epilogue*/\n\n\n");
298 /* Return the best assembler insn template
299 for moving operands[1] into operands[0] as a fullword. */
300 static char *
301 singlemove_string (operands)
302 rtx *operands;
304 if (operands[1] != const0_rtx)
305 return "mov %1,%0";
307 return "clr %0";
311 /* Output assembler code to perform a doubleword move insn
312 with operands OPERANDS. */
314 char *
315 output_move_double (operands)
316 rtx *operands;
318 enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
319 rtx latehalf[2];
320 rtx addreg0 = 0, addreg1 = 0;
322 /* First classify both operands. */
324 if (REG_P (operands[0]))
325 optype0 = REGOP;
326 else if (offsettable_memref_p (operands[0]))
327 optype0 = OFFSOP;
328 else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
329 optype0 = POPOP;
330 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
331 optype0 = PUSHOP;
332 else if (GET_CODE (operands[0]) == MEM)
333 optype0 = MEMOP;
334 else
335 optype0 = RNDOP;
337 if (REG_P (operands[1]))
338 optype1 = REGOP;
339 else if (CONSTANT_P (operands[1]))
340 #if 0
341 || GET_CODE (operands[1]) == CONST_DOUBLE)
342 #endif
343 optype1 = CNSTOP;
344 else if (offsettable_memref_p (operands[1]))
345 optype1 = OFFSOP;
346 else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
347 optype1 = POPOP;
348 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
349 optype1 = PUSHOP;
350 else if (GET_CODE (operands[1]) == MEM)
351 optype1 = MEMOP;
352 else
353 optype1 = RNDOP;
355 /* Check for the cases that the operand constraints are not
356 supposed to allow to happen. Abort if we get one,
357 because generating code for these cases is painful. */
359 if (optype0 == RNDOP || optype1 == RNDOP)
360 abort ();
362 /* If one operand is decrementing and one is incrementing
363 decrement the former register explicitly
364 and change that operand into ordinary indexing. */
366 if (optype0 == PUSHOP && optype1 == POPOP)
368 operands[0] = XEXP (XEXP (operands[0], 0), 0);
369 output_asm_insn ("sub $4,%0", operands);
370 operands[0] = gen_rtx (MEM, SImode, operands[0]);
371 optype0 = OFFSOP;
373 if (optype0 == POPOP && optype1 == PUSHOP)
375 operands[1] = XEXP (XEXP (operands[1], 0), 0);
376 output_asm_insn ("sub $4,%1", operands);
377 operands[1] = gen_rtx (MEM, SImode, operands[1]);
378 optype1 = OFFSOP;
381 /* If an operand is an unoffsettable memory ref, find a register
382 we can increment temporarily to make it refer to the second word. */
384 if (optype0 == MEMOP)
385 addreg0 = find_addr_reg (XEXP (operands[0], 0));
387 if (optype1 == MEMOP)
388 addreg1 = find_addr_reg (XEXP (operands[1], 0));
390 /* Ok, we can do one word at a time.
391 Normally we do the low-numbered word first,
392 but if either operand is autodecrementing then we
393 do the high-numbered word first.
395 In either case, set up in LATEHALF the operands to use
396 for the high-numbered word and in some cases alter the
397 operands in OPERANDS to be suitable for the low-numbered word. */
399 if (optype0 == REGOP)
400 latehalf[0] = gen_rtx (REG, HImode, REGNO (operands[0]) + 1);
401 else if (optype0 == OFFSOP)
402 latehalf[0] = adj_offsettable_operand (operands[0], 2);
403 else
404 latehalf[0] = operands[0];
406 if (optype1 == REGOP)
407 latehalf[1] = gen_rtx (REG, HImode, REGNO (operands[1]) + 1);
408 else if (optype1 == OFFSOP)
409 latehalf[1] = adj_offsettable_operand (operands[1], 2);
410 else if (optype1 == CNSTOP)
412 if (CONSTANT_P (operands[1]))
414 /* now the mess begins, high word is in lower word???
416 that's what ashc makes me think, but I don't remember :-( */
417 latehalf[1] = gen_rtx(CONST_INT, VOIDmode,
418 INTVAL(operands[1])>>16);
419 operands[1] = gen_rtx(CONST_INT, VOIDmode,
420 INTVAL(operands[1])&0xff);
422 else if (GET_CODE (operands[1]) == CONST_DOUBLE)
424 /* immediate 32 bit values not allowed */
425 abort();
428 else
429 latehalf[1] = operands[1];
431 /* If insn is effectively movd N(sp),-(sp) then we will do the
432 high word first. We should use the adjusted operand 1 (which is N+4(sp))
433 for the low word as well, to compensate for the first decrement of sp. */
434 if (optype0 == PUSHOP
435 && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
436 && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
437 operands[1] = latehalf[1];
439 /* If one or both operands autodecrementing,
440 do the two words, high-numbered first. */
442 /* Likewise, the first move would clobber the source of the second one,
443 do them in the other order. This happens only for registers;
444 such overlap can't happen in memory unless the user explicitly
445 sets it up, and that is an undefined circumstance. */
447 if (optype0 == PUSHOP || optype1 == PUSHOP
448 || (optype0 == REGOP && optype1 == REGOP
449 && REGNO (operands[0]) == REGNO (latehalf[1])))
451 /* Make any unoffsettable addresses point at high-numbered word. */
452 if (addreg0)
453 output_asm_insn ("add $2,%0", &addreg0);
454 if (addreg1)
455 output_asm_insn ("add $2,%0", &addreg1);
457 /* Do that word. */
458 output_asm_insn (singlemove_string (latehalf), latehalf);
460 /* Undo the adds we just did. */
461 if (addreg0)
462 output_asm_insn ("sub $2,%0", &addreg0);
463 if (addreg1)
464 output_asm_insn ("sub $2,%0", &addreg1);
466 /* Do low-numbered word. */
467 return singlemove_string (operands);
470 /* Normal case: do the two words, low-numbered first. */
472 output_asm_insn (singlemove_string (operands), operands);
474 /* Make any unoffsettable addresses point at high-numbered word. */
475 if (addreg0)
476 output_asm_insn ("add $2,%0", &addreg0);
477 if (addreg1)
478 output_asm_insn ("add $2,%0", &addreg1);
480 /* Do that word. */
481 output_asm_insn (singlemove_string (latehalf), latehalf);
483 /* Undo the adds we just did. */
484 if (addreg0)
485 output_asm_insn ("sub $2,%0", &addreg0);
486 if (addreg1)
487 output_asm_insn ("sub $2,%0", &addreg1);
489 return "";
491 /* Output assembler code to perform a quadword move insn
492 with operands OPERANDS. */
494 char *
495 output_move_quad (operands)
496 rtx *operands;
498 enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
499 rtx latehalf[2];
500 rtx addreg0 = 0, addreg1 = 0;
502 output_asm_insn(";; movdi/df: %1 -> %0", operands);
504 if (REG_P (operands[0]))
505 optype0 = REGOP;
506 else if (offsettable_memref_p (operands[0]))
507 optype0 = OFFSOP;
508 else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
509 optype0 = POPOP;
510 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
511 optype0 = PUSHOP;
512 else if (GET_CODE (operands[0]) == MEM)
513 optype0 = MEMOP;
514 else
515 optype0 = RNDOP;
517 if (REG_P (operands[1]))
518 optype1 = REGOP;
519 else if (CONSTANT_P (operands[1])
520 || GET_CODE (operands[1]) == CONST_DOUBLE)
521 optype1 = CNSTOP;
522 else if (offsettable_memref_p (operands[1]))
523 optype1 = OFFSOP;
524 else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
525 optype1 = POPOP;
526 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
527 optype1 = PUSHOP;
528 else if (GET_CODE (operands[1]) == MEM)
529 optype1 = MEMOP;
530 else
531 optype1 = RNDOP;
533 /* Check for the cases that the operand constraints are not
534 supposed to allow to happen. Abort if we get one,
535 because generating code for these cases is painful. */
537 if (optype0 == RNDOP || optype1 == RNDOP)
538 abort ();
540 /* check if we move a CPU reg to an FPU reg, or vice versa! */
541 if (optype0 == REGOP && optype1 == REGOP)
542 /* bogus - 64 bit cannot reside in CPU! */
543 if (CPU_REG_P(REGNO(operands[0]))
544 || CPU_REG_P (REGNO(operands[1])))
545 abort();
547 if (optype0 == REGOP || optype1 == REGOP)
549 /* check for use of clrd????
550 if you ever allow ac4 and ac5 (now we require secondary load)
551 you must check whether
552 you want to load into them or store from them -
553 then dump ac0 into $help$ movce ac4/5 to ac0, do the
554 store from ac0, and restore ac0 - if you can find
555 an unused ac[0-3], use that and you save a store and a load!*/
557 if (FPU_REG_P(REGNO(operands[0])))
559 if (GET_CODE(operands[1]) == CONST_DOUBLE)
561 union { double d; int i[2]; } u;
562 u.i[0] = CONST_DOUBLE_LOW (operands[1]);
563 u.i[1] = CONST_DOUBLE_HIGH (operands[1]);
565 if (u.d == 0.0)
566 return "clrd %0";
569 return "ldd %1, %0";
572 if (FPU_REG_P(REGNO(operands[1])))
573 return "std %1, %0";
576 /* If one operand is decrementing and one is incrementing
577 decrement the former register explicitly
578 and change that operand into ordinary indexing. */
580 if (optype0 == PUSHOP && optype1 == POPOP)
582 operands[0] = XEXP (XEXP (operands[0], 0), 0);
583 output_asm_insn ("sub $8,%0", operands);
584 operands[0] = gen_rtx (MEM, DImode, operands[0]);
585 optype0 = OFFSOP;
587 if (optype0 == POPOP && optype1 == PUSHOP)
589 operands[1] = XEXP (XEXP (operands[1], 0), 0);
590 output_asm_insn ("sub $8,%1", operands);
591 operands[1] = gen_rtx (MEM, SImode, operands[1]);
592 optype1 = OFFSOP;
595 /* If an operand is an unoffsettable memory ref, find a register
596 we can increment temporarily to make it refer to the second word. */
598 if (optype0 == MEMOP)
599 addreg0 = find_addr_reg (XEXP (operands[0], 0));
601 if (optype1 == MEMOP)
602 addreg1 = find_addr_reg (XEXP (operands[1], 0));
604 /* Ok, we can do one word at a time.
605 Normally we do the low-numbered word first,
606 but if either operand is autodecrementing then we
607 do the high-numbered word first.
609 In either case, set up in LATEHALF the operands to use
610 for the high-numbered word and in some cases alter the
611 operands in OPERANDS to be suitable for the low-numbered word. */
613 if (optype0 == REGOP)
614 latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 2);
615 else if (optype0 == OFFSOP)
616 latehalf[0] = adj_offsettable_operand (operands[0], 4);
617 else
618 latehalf[0] = operands[0];
620 if (optype1 == REGOP)
621 latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 2);
622 else if (optype1 == OFFSOP)
623 latehalf[1] = adj_offsettable_operand (operands[1], 4);
624 else if (optype1 == CNSTOP)
626 if (GET_CODE (operands[1]) == CONST_DOUBLE)
628 /* floats only. not yet supported!
630 -- compute it into PDP float format, - internally,
631 just use IEEE and ignore possible problems ;-)
633 we might get away with it !!!! */
635 abort();
637 #ifndef HOST_WORDS_BIG_ENDIAN
638 latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
639 CONST_DOUBLE_LOW (operands[1]));
640 operands[1] = gen_rtx (CONST_INT, VOIDmode,
641 CONST_DOUBLE_HIGH (operands[1]));
642 #else /* HOST_WORDS_BIG_ENDIAN */
643 latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
644 CONST_DOUBLE_HIGH (operands[1]));
645 operands[1] = gen_rtx (CONST_INT, VOIDmode,
646 CONST_DOUBLE_LOW (operands[1]));
647 #endif /* HOST_WORDS_BIG_ENDIAN */
649 else if (GET_CODE(operands[1]) == CONST_INT)
651 latehalf[1] = gen_rtx (CONST_INT, VOIDmode, 0);
653 else
654 abort();
657 else
658 latehalf[1] = operands[1];
660 /* If insn is effectively movd N(sp),-(sp) then we will do the
661 high word first. We should use the adjusted operand 1 (which is N+4(sp))
662 for the low word as well, to compensate for the first decrement of sp. */
663 if (optype0 == PUSHOP
664 && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
665 && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
666 operands[1] = latehalf[1];
668 /* If one or both operands autodecrementing,
669 do the two words, high-numbered first. */
671 /* Likewise, the first move would clobber the source of the second one,
672 do them in the other order. This happens only for registers;
673 such overlap can't happen in memory unless the user explicitly
674 sets it up, and that is an undefined circumstance. */
676 if (optype0 == PUSHOP || optype1 == PUSHOP
677 || (optype0 == REGOP && optype1 == REGOP
678 && REGNO (operands[0]) == REGNO (latehalf[1])))
680 /* Make any unoffsettable addresses point at high-numbered word. */
681 if (addreg0)
682 output_asm_insn ("add $4,%0", &addreg0);
683 if (addreg1)
684 output_asm_insn ("add $4,%0", &addreg1);
686 /* Do that word. */
687 output_asm_insn(output_move_double(latehalf), latehalf);
689 /* Undo the adds we just did. */
690 if (addreg0)
691 output_asm_insn ("sub $4,%0", &addreg0);
692 if (addreg1)
693 output_asm_insn ("sub $4,%0", &addreg1);
695 /* Do low-numbered word. */
696 return output_move_double (operands);
699 /* Normal case: do the two words, low-numbered first. */
701 output_asm_insn (output_move_double (operands), operands);
703 /* Make any unoffsettable addresses point at high-numbered word. */
704 if (addreg0)
705 output_asm_insn ("add $4,%0", &addreg0);
706 if (addreg1)
707 output_asm_insn ("add $4,%0", &addreg1);
709 /* Do that word. */
710 output_asm_insn (output_move_double (latehalf), latehalf);
712 /* Undo the adds we just did. */
713 if (addreg0)
714 output_asm_insn ("sub $4,%0", &addreg0);
715 if (addreg1)
716 output_asm_insn ("sub $4,%0", &addreg1);
718 return "";
722 /* Return a REG that occurs in ADDR with coefficient 1.
723 ADDR can be effectively incremented by incrementing REG. */
725 static rtx
726 find_addr_reg (addr)
727 rtx addr;
729 while (GET_CODE (addr) == PLUS)
731 if (GET_CODE (XEXP (addr, 0)) == REG)
732 addr = XEXP (addr, 0);
733 if (GET_CODE (XEXP (addr, 1)) == REG)
734 addr = XEXP (addr, 1);
735 if (CONSTANT_P (XEXP (addr, 0)))
736 addr = XEXP (addr, 1);
737 if (CONSTANT_P (XEXP (addr, 1)))
738 addr = XEXP (addr, 0);
740 if (GET_CODE (addr) == REG)
741 return addr;
742 return 0;
745 /* Output an ascii string. */
746 output_ascii (file, p, size)
747 FILE *file;
748 char *p;
749 int size;
751 int i;
753 fprintf (file, "\t.byte \"");
755 for (i = 0; i < size; i++)
757 register int c = p[i];
758 if (c == '\"' || c == '\\')
759 putc ('\\', file);
760 if (c >= ' ' && c < 0177)
761 putc (c, file);
762 else
764 fprintf (file, "\\%03o", c);
765 /* After an octal-escape, if a digit follows,
766 terminate one string constant and start another.
767 The Vax assembler fails to stop reading the escape
768 after three digits, so this is the only way we
769 can get it to parse the data properly. */
770 if (i < size - 1 && p[i + 1] >= '0' && p[i + 1] <= '9')
771 fprintf (file, "\"\n\tstring \"");
774 fprintf (file, "\"\n");
778 /* --- stole from out-vax, needs changes */
780 print_operand_address (file, addr)
781 FILE *file;
782 register rtx addr;
784 register rtx reg1, reg2, breg, ireg;
785 rtx offset;
787 retry:
789 switch (GET_CODE (addr))
791 case MEM:
792 fprintf (file, "@");
793 addr = XEXP (addr, 0);
794 goto retry;
796 case REG:
797 fprintf (file, "(%s)", reg_names[REGNO (addr)]);
798 break;
800 case PRE_DEC:
801 fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]);
802 break;
804 case POST_INC:
805 fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]);
806 break;
808 case PLUS:
809 reg1 = 0; reg2 = 0;
810 ireg = 0; breg = 0;
811 offset = 0;
812 if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
813 || GET_CODE (XEXP (addr, 0)) == MEM)
815 offset = XEXP (addr, 0);
816 addr = XEXP (addr, 1);
818 else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
819 || GET_CODE (XEXP (addr, 1)) == MEM)
821 offset = XEXP (addr, 1);
822 addr = XEXP (addr, 0);
824 if (GET_CODE (addr) != PLUS)
826 else if (GET_CODE (XEXP (addr, 0)) == MULT)
828 reg1 = XEXP (addr, 0);
829 addr = XEXP (addr, 1);
831 else if (GET_CODE (XEXP (addr, 1)) == MULT)
833 reg1 = XEXP (addr, 1);
834 addr = XEXP (addr, 0);
836 else if (GET_CODE (XEXP (addr, 0)) == REG)
838 reg1 = XEXP (addr, 0);
839 addr = XEXP (addr, 1);
841 else if (GET_CODE (XEXP (addr, 1)) == REG)
843 reg1 = XEXP (addr, 1);
844 addr = XEXP (addr, 0);
846 if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
848 if (reg1 == 0)
849 reg1 = addr;
850 else
851 reg2 = addr;
852 addr = 0;
854 if (offset != 0)
856 if (addr != 0) abort ();
857 addr = offset;
859 if (reg1 != 0 && GET_CODE (reg1) == MULT)
861 breg = reg2;
862 ireg = reg1;
864 else if (reg2 != 0 && GET_CODE (reg2) == MULT)
866 breg = reg1;
867 ireg = reg2;
869 else if (reg2 != 0 || GET_CODE (addr) == MEM)
871 breg = reg2;
872 ireg = reg1;
874 else
876 breg = reg1;
877 ireg = reg2;
879 if (addr != 0)
880 output_address (addr);
881 if (breg != 0)
883 if (GET_CODE (breg) != REG)
884 abort ();
885 fprintf (file, "(%s)", reg_names[REGNO (breg)]);
887 if (ireg != 0)
889 if (GET_CODE (ireg) == MULT)
890 ireg = XEXP (ireg, 0);
891 if (GET_CODE (ireg) != REG)
892 abort ();
893 abort();
894 fprintf (file, "[%s]", reg_names[REGNO (ireg)]);
896 break;
898 default:
899 output_addr_const (file, addr);
903 /* register move costs, indexed by regs */
905 static int move_costs[N_REG_CLASSES][N_REG_CLASSES] =
907 /* NO MUL GEN LFPU NLFPU FPU ALL */
909 /* NO */ { 0, 0, 0, 0, 0, 0, 0},
910 /* MUL */ { 0, 2, 2, 10, 22, 22, 22},
911 /* GEN */ { 0, 2, 2, 10, 22, 22, 22},
912 /* LFPU */ { 0, 10, 10, 2, 2, 2, 10},
913 /* NLFPU */ { 0, 22, 22, 2, 2, 2, 22},
914 /* FPU */ { 0, 22, 22, 2, 2, 2, 22},
915 /* ALL */ { 0, 22, 22, 10, 22, 22, 22}
919 /* -- note that some moves are tremendously expensive,
920 because they require lots of tricks! do we have to
921 charge the costs incurred by secondary reload class
922 -- as we do here with 22 -- or not ? */
924 int
925 register_move_cost(c1, c2)
926 enum reg_class c1, c2;
928 return move_costs[(int)c1][(int)c2];
931 char *
932 output_jump(pos, neg, length)
933 int length;
934 char *pos, *neg;
936 static int x = 0;
938 static char buf[1000];
940 #if 0
941 /* currently we don't need this, because the tstdf and cmpdf
942 copy the condition code immediately, and other float operations are not
943 yet recognized as changing the FCC - if so, then the length-cost of all
944 jump insns increases by one, because we have to potentially copy the
945 FCC! */
946 if (cc_status.flags & CC_IN_FPU)
947 output_asm_insn("cfcc", NULL);
948 #endif
950 switch (length)
952 case 1:
954 strcpy(buf, pos);
955 strcat(buf, " %l0");
957 return buf;
959 case 3:
961 sprintf(buf, "%s JMP_%d\n\tjmp %%l0\nJMP_%d:", neg, x, x);
963 x++;
965 return buf;
967 default:
969 abort();
974 void
975 notice_update_cc_on_set(exp, insn)
976 rtx exp;
977 rtx insn;
979 if (GET_CODE (SET_DEST (exp)) == CC0)
981 cc_status.flags = 0;
982 cc_status.value1 = SET_DEST (exp);
983 cc_status.value2 = SET_SRC (exp);
986 if (GET_MODE(SET_SRC(exp)) == DFmode)
987 cc_status.flags |= CC_IN_FPU;
990 else if ((GET_CODE (SET_DEST (exp)) == REG
991 || GET_CODE (SET_DEST (exp)) == MEM)
992 && GET_CODE (SET_SRC (exp)) != PC
993 && (GET_MODE (SET_DEST(exp)) == HImode
994 || GET_MODE (SET_DEST(exp)) == QImode)
995 && (GET_CODE (SET_SRC(exp)) == PLUS
996 || GET_CODE (SET_SRC(exp)) == MINUS
997 || GET_CODE (SET_SRC(exp)) == AND
998 || GET_CODE (SET_SRC(exp)) == IOR
999 || GET_CODE (SET_SRC(exp)) == XOR
1000 || GET_CODE (SET_SRC(exp)) == NOT
1001 || GET_CODE (SET_SRC(exp)) == NEG
1002 || GET_CODE (SET_SRC(exp)) == REG
1003 || GET_CODE (SET_SRC(exp)) == MEM))
1005 cc_status.flags = 0;
1006 cc_status.value1 = SET_SRC (exp);
1007 cc_status.value2 = SET_DEST (exp);
1009 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
1010 && cc_status.value2
1011 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
1012 cc_status.value2 = 0;
1013 if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM
1014 && cc_status.value2
1015 && GET_CODE (cc_status.value2) == MEM)
1016 cc_status.value2 = 0;
1018 else if (GET_CODE (SET_SRC (exp)) == CALL)
1020 CC_STATUS_INIT;
1022 else if (GET_CODE (SET_DEST (exp)) == REG)
1023 /* what's this ? */
1025 if ((cc_status.value1
1026 && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1)))
1027 cc_status.value1 = 0;
1028 if ((cc_status.value2
1029 && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2)))
1030 cc_status.value2 = 0;
1032 else if (SET_DEST(exp) == pc_rtx)
1034 /* jump */
1036 else /* if (GET_CODE (SET_DEST (exp)) == MEM) */
1038 /* the last else is a bit paranoiac, but since nearly all instructions
1039 play with condition codes, it's reasonable! */
1041 CC_STATUS_INIT; /* paranoia*/
1046 int simple_memory_operand(op, mode)
1047 rtx op;
1048 enum machine_mode mode;
1050 rtx addr, plus0, plus1;
1051 int offset = 0;
1053 /* Eliminate non-memory operations */
1054 if (GET_CODE (op) != MEM)
1055 return FALSE;
1057 #if 0
1058 /* dword operations really put out 2 instructions, so eliminate them. */
1059 if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4))
1060 return FALSE;
1061 #endif
1063 /* Decode the address now. */
1065 indirection:
1067 addr = XEXP (op, 0);
1069 switch (GET_CODE (addr))
1071 case REG:
1072 /* (R0) - no extra cost */
1073 return 1;
1075 case PRE_DEC:
1076 case POST_INC:
1077 /* -(R0), (R0)+ - cheap! */
1078 return 0;
1080 case MEM:
1081 /* cheap - is encoded in addressing mode info!
1083 -- except for @(R0), which has to be @0(R0) !!! */
1085 if (GET_CODE (XEXP (addr, 0)) == REG)
1086 return 0;
1088 op=addr;
1089 goto indirection;
1091 case CONST_INT:
1092 case LABEL_REF:
1093 case CONST:
1094 case SYMBOL_REF:
1095 /* @#address - extra cost */
1096 return 0;
1098 case PLUS:
1099 /* X(R0) - extra cost */
1100 return 0;
1103 return FALSE;
1108 * output a block move:
1110 * operands[0] ... to
1111 * operands[1] ... from
1112 * operands[2] ... length
1113 * operands[3] ... alignment
1114 * operands[4] ... scratch register
1118 char *
1119 output_block_move(operands)
1120 rtx *operands;
1122 static int count = 0;
1123 char buf[200];
1125 if (GET_CODE(operands[2]) == CONST_INT
1126 && TARGET_TIME)
1128 if (INTVAL(operands[2]) < 16
1129 && INTVAL(operands[3]) == 1)
1131 register int i;
1133 for (i = 1; i <= INTVAL(operands[2]); i++)
1134 output_asm_insn("movb (%1)+, (%0)+", operands);
1136 return "";
1138 else if (INTVAL(operands[2]) < 32)
1140 register int i;
1142 for (i = 1; i <= INTVAL(operands[2])/2; i++)
1143 output_asm_insn("mov (%1)+, (%0)+", operands);
1145 /* may I assume that moved quantity is
1146 multiple of alignment ???
1148 I HOPE SO !
1151 return "";
1155 /* can do other clever things, maybe... */
1158 if (CONSTANT_P(operands[2]) )
1160 /* just move count to scratch */
1161 output_asm_insn("mov %2, %4", operands);
1163 else
1165 /* just clobber the register */
1166 operands[4] = operands[2];
1170 /* switch over alignment */
1171 switch (INTVAL(operands[3]))
1173 case 1:
1177 movb (%1)+, (%0)+
1179 if (TARGET_45)
1180 sob %4,x
1181 else
1182 dec %4
1183 bgt x
1187 sprintf(buf, "\nmovestrhi%d:", count);
1188 output_asm_insn(buf, NULL);
1190 output_asm_insn("movb (%1)+, (%0)+", operands);
1192 if (TARGET_45)
1194 sprintf(buf, "sob %%4, movestrhi%d", count);
1195 output_asm_insn(buf, operands);
1197 else
1199 output_asm_insn("dec %4", operands);
1201 sprintf(buf, "bgt movestrhi%d", count);
1202 output_asm_insn(buf, NULL);
1205 count ++;
1206 break;
1208 case 2:
1211 asr %4
1215 mov (%1)+, (%0)+
1217 if (TARGET_45)
1218 sob %4, x
1219 else
1220 dec %4
1221 bgt x
1224 generate_compact_code:
1226 output_asm_insn("asr %4", operands);
1228 sprintf(buf, "\nmovestrhi%d:", count);
1229 output_asm_insn(buf, NULL);
1231 output_asm_insn("mov (%1)+, (%0)+", operands);
1233 if (TARGET_45)
1235 sprintf(buf, "sob %%4, movestrhi%d", count);
1236 output_asm_insn(buf, operands);
1238 else
1240 output_asm_insn("dec %4", operands);
1242 sprintf(buf, "bgt movestrhi%d", count);
1243 output_asm_insn(buf, NULL);
1246 count ++;
1247 break;
1249 case 4:
1253 asr %4
1254 asr %4
1258 mov (%1)+, (%0)+
1259 mov (%1)+, (%0)+
1261 if (TARGET_45)
1262 sob %4, x
1263 else
1264 dec %4
1265 bgt x
1268 if (TARGET_SPACE)
1269 goto generate_compact_code;
1271 output_asm_insn("asr %4", operands);
1272 output_asm_insn("asr %4", operands);
1274 sprintf(buf, "\nmovestrhi%d:", count);
1275 output_asm_insn(buf, NULL);
1277 output_asm_insn("mov (%1)+, (%0)+", operands);
1278 output_asm_insn("mov (%1)+, (%0)+", operands);
1280 if (TARGET_45)
1282 sprintf(buf, "sob %%4, movestrhi%d", count);
1283 output_asm_insn(buf, operands);
1285 else
1287 output_asm_insn("dec %4", operands);
1289 sprintf(buf, "bgt movestrhi%d", count);
1290 output_asm_insn(buf, NULL);
1293 count ++;
1294 break;
1296 default:
1300 asr %4
1301 asr %4
1302 asr %4
1306 mov (%1)+, (%0)+
1307 mov (%1)+, (%0)+
1308 mov (%1)+, (%0)+
1309 mov (%1)+, (%0)+
1311 if (TARGET_45)
1312 sob %4, x
1313 else
1314 dec %4
1315 bgt x
1319 if (TARGET_SPACE)
1320 goto generate_compact_code;
1322 output_asm_insn("asr %4", operands);
1323 output_asm_insn("asr %4", operands);
1324 output_asm_insn("asr %4", operands);
1326 sprintf(buf, "\nmovestrhi%d:", count);
1327 output_asm_insn(buf, NULL);
1329 output_asm_insn("mov (%1)+, (%0)+", operands);
1330 output_asm_insn("mov (%1)+, (%0)+", operands);
1331 output_asm_insn("mov (%1)+, (%0)+", operands);
1332 output_asm_insn("mov (%1)+, (%0)+", operands);
1334 if (TARGET_45)
1336 sprintf(buf, "sob %%4, movestrhi%d", count);
1337 output_asm_insn(buf, operands);
1339 else
1341 output_asm_insn("dec %4", operands);
1343 sprintf(buf, "bgt movestrhi%d", count);
1344 output_asm_insn(buf, NULL);
1347 count ++;
1348 break;
1354 return "";
1357 /* for future use */
1359 comparison_operator_index(op)
1360 rtx op;
1362 switch (GET_CODE(op))
1364 case NE:
1365 return 0;
1367 case EQ:
1368 return 1;
1370 case GE:
1371 return 2;
1373 case GT:
1374 return 3;
1376 case LE:
1377 return 4;
1379 case LT:
1380 return 5;
1382 case GEU:
1383 return 6;
1385 case GTU:
1386 return 7;
1388 case LEU:
1389 return 8;
1391 case LTU:
1392 return 9;
1394 default:
1395 return -1;
1399 /* tests whether the rtx is a comparison operator */
1401 comp_operator (op, mode)
1402 rtx op;
1403 enum machine_mode mode;
1405 return comparison_operator_index(op) >= 0;
1410 legitimate_address_p (mode, address)
1411 enum machine_mode mode;
1412 rtx address;
1414 /* #define REG_OK_STRICT */
1415 GO_IF_LEGITIMATE_ADDRESS(mode, address, win);
1417 return 0;
1419 win:
1420 return 1;
1422 /* #undef REG_OK_STRICT */