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)
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. */
28 #include "hard-reg-set.h"
30 #include "insn-config.h"
31 #include "conditions.h"
32 #include "insn-flags.h"
34 #include "insn-attr.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
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. */
54 arith_operand (op
, mode
)
56 enum machine_mode mode
;
58 return (register_operand (op
, mode
) || GET_CODE (op
) == CONST_INT
);
62 const_immediate_operand (op
, mode
)
64 enum machine_mode mode
;
66 return (GET_CODE (op
) == CONST_INT
);
70 immediate15_operand (op
, mode
)
72 enum machine_mode mode
;
74 return (GET_CODE (op
) == CONST_INT
&& ((INTVAL (op
) & 0x8000) == 0x0000));
78 expand_shift_operand (op
, mode
)
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.
97 output_function_prologue(stream
, size
)
101 int fsize
= ((size
) + 1) & ~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)
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");
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 */
144 for (regno
= 8; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
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
]);
155 /* maybe make ac4, ac5 call used regs?? */
157 if (NO_LOAD_FPU_REG_P(regno
)
158 && regs_ever_live
[regno
]
159 && ! call_used_regs
[regno
])
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
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? */
193 output_function_epilogue(stream
, size
)
197 extern int may_call_alloca
;
199 int fsize
= ((size
) + 1) & ~1;
200 int nregs
, regno
, i
, j
, k
, adjust_fp
;
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
])
215 /* remember # of pushed bytes for CPU regs */
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
]);
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
])
232 for (i
= FIRST_PSEUDO_REGISTER
; i
> 7; i
--)
234 if (LOAD_FPU_REG_P(i
)
236 && ! call_used_regs
[i
])
238 fprintf(stream
, "\tfldd %d(fp), %s\n", -fsize
-k
, reg_names
[i
]);
242 if (NO_LOAD_FPU_REG_P(i
)
244 && ! call_used_regs
[i
])
246 if (! LOAD_FPU_REG_P(via_ac
))
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
]);
255 fprintf(stream
, "\tmov fp, sp\n");
256 fprintf (stream
, "\tmov (sp)+, fp\n");
260 via_ac
= FIRST_PSEUDO_REGISTER
-1;
263 for (i
= FIRST_PSEUDO_REGISTER
; i
> 7; i
--)
264 if (regs_ever_live
[i
] && call_used_regs
[i
])
267 for (i
= FIRST_PSEUDO_REGISTER
; i
> 7; i
--)
269 if (LOAD_FPU_REG_P(i
)
271 && ! call_used_regs
[i
])
272 fprintf(stream
, "\tfldd (sp)+, %s\n", reg_names
[i
]);
274 if (NO_LOAD_FPU_REG_P(i
)
276 && ! call_used_regs
[i
])
278 if (! LOAD_FPU_REG_P(via_ac
))
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
]);
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. */
301 singlemove_string (operands
)
304 if (operands
[1] != const0_rtx
)
311 /* Output assembler code to perform a doubleword move insn
312 with operands OPERANDS. */
315 output_move_double (operands
)
318 enum { REGOP
, OFFSOP
, MEMOP
, PUSHOP
, POPOP
, CNSTOP
, RNDOP
} optype0
, optype1
;
320 rtx addreg0
= 0, addreg1
= 0;
322 /* First classify both operands. */
324 if (REG_P (operands
[0]))
326 else if (offsettable_memref_p (operands
[0]))
328 else if (GET_CODE (XEXP (operands
[0], 0)) == POST_INC
)
330 else if (GET_CODE (XEXP (operands
[0], 0)) == PRE_DEC
)
332 else if (GET_CODE (operands
[0]) == MEM
)
337 if (REG_P (operands
[1]))
339 else if (CONSTANT_P (operands
[1]))
341 || GET_CODE (operands
[1]) == CONST_DOUBLE
)
344 else if (offsettable_memref_p (operands
[1]))
346 else if (GET_CODE (XEXP (operands
[1], 0)) == POST_INC
)
348 else if (GET_CODE (XEXP (operands
[1], 0)) == PRE_DEC
)
350 else if (GET_CODE (operands
[1]) == MEM
)
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
)
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]);
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]);
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);
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 */
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. */
453 output_asm_insn ("add $2,%0", &addreg0
);
455 output_asm_insn ("add $2,%0", &addreg1
);
458 output_asm_insn (singlemove_string (latehalf
), latehalf
);
460 /* Undo the adds we just did. */
462 output_asm_insn ("sub $2,%0", &addreg0
);
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. */
476 output_asm_insn ("add $2,%0", &addreg0
);
478 output_asm_insn ("add $2,%0", &addreg1
);
481 output_asm_insn (singlemove_string (latehalf
), latehalf
);
483 /* Undo the adds we just did. */
485 output_asm_insn ("sub $2,%0", &addreg0
);
487 output_asm_insn ("sub $2,%0", &addreg1
);
491 /* Output assembler code to perform a quadword move insn
492 with operands OPERANDS. */
495 output_move_quad (operands
)
498 enum { REGOP
, OFFSOP
, MEMOP
, PUSHOP
, POPOP
, CNSTOP
, RNDOP
} optype0
, optype1
;
500 rtx addreg0
= 0, addreg1
= 0;
502 output_asm_insn(";; movdi/df: %1 -> %0", operands
);
504 if (REG_P (operands
[0]))
506 else if (offsettable_memref_p (operands
[0]))
508 else if (GET_CODE (XEXP (operands
[0], 0)) == POST_INC
)
510 else if (GET_CODE (XEXP (operands
[0], 0)) == PRE_DEC
)
512 else if (GET_CODE (operands
[0]) == MEM
)
517 if (REG_P (operands
[1]))
519 else if (CONSTANT_P (operands
[1])
520 || GET_CODE (operands
[1]) == CONST_DOUBLE
)
522 else if (offsettable_memref_p (operands
[1]))
524 else if (GET_CODE (XEXP (operands
[1], 0)) == POST_INC
)
526 else if (GET_CODE (XEXP (operands
[1], 0)) == PRE_DEC
)
528 else if (GET_CODE (operands
[1]) == MEM
)
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
)
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])))
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]);
572 if (FPU_REG_P(REGNO(operands
[1])))
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]);
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]);
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);
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 !!!! */
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);
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. */
682 output_asm_insn ("add $4,%0", &addreg0
);
684 output_asm_insn ("add $4,%0", &addreg1
);
687 output_asm_insn(output_move_double(latehalf
), latehalf
);
689 /* Undo the adds we just did. */
691 output_asm_insn ("sub $4,%0", &addreg0
);
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. */
705 output_asm_insn ("add $4,%0", &addreg0
);
707 output_asm_insn ("add $4,%0", &addreg1
);
710 output_asm_insn (output_move_double (latehalf
), latehalf
);
712 /* Undo the adds we just did. */
714 output_asm_insn ("sub $4,%0", &addreg0
);
716 output_asm_insn ("sub $4,%0", &addreg1
);
722 /* Return a REG that occurs in ADDR with coefficient 1.
723 ADDR can be effectively incremented by incrementing REG. */
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
)
745 /* Output an ascii string. */
746 output_ascii (file
, p
, size
)
753 fprintf (file
, "\t.byte \"");
755 for (i
= 0; i
< size
; i
++)
757 register int c
= p
[i
];
758 if (c
== '\"' || c
== '\\')
760 if (c
>= ' ' && c
< 0177)
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
)
784 register rtx reg1
, reg2
, breg
, ireg
;
789 switch (GET_CODE (addr
))
793 addr
= XEXP (addr
, 0);
797 fprintf (file
, "(%s)", reg_names
[REGNO (addr
)]);
801 fprintf (file
, "-(%s)", reg_names
[REGNO (XEXP (addr
, 0))]);
805 fprintf (file
, "(%s)+", reg_names
[REGNO (XEXP (addr
, 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
)
856 if (addr
!= 0) abort ();
859 if (reg1
!= 0 && GET_CODE (reg1
) == MULT
)
864 else if (reg2
!= 0 && GET_CODE (reg2
) == MULT
)
869 else if (reg2
!= 0 || GET_CODE (addr
) == MEM
)
880 output_address (addr
);
883 if (GET_CODE (breg
) != REG
)
885 fprintf (file
, "(%s)", reg_names
[REGNO (breg
)]);
889 if (GET_CODE (ireg
) == MULT
)
890 ireg
= XEXP (ireg
, 0);
891 if (GET_CODE (ireg
) != REG
)
894 fprintf (file
, "[%s]", reg_names
[REGNO (ireg
)]);
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 ? */
925 register_move_cost(c1
, c2
)
926 enum reg_class c1
, c2
;
928 return move_costs
[(int)c1
][(int)c2
];
932 output_jump(pos
, neg
, length
)
938 static char buf
[1000];
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
946 if (cc_status
.flags
& CC_IN_FPU
)
947 output_asm_insn("cfcc", NULL
);
961 sprintf(buf
, "%s JMP_%d\n\tjmp %%l0\nJMP_%d:", neg
, x
, x
);
975 notice_update_cc_on_set(exp
, insn
)
979 if (GET_CODE (SET_DEST (exp
)) == CC0
)
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
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
1015 && GET_CODE (cc_status
.value2
) == MEM
)
1016 cc_status
.value2
= 0;
1018 else if (GET_CODE (SET_SRC (exp
)) == CALL
)
1022 else if (GET_CODE (SET_DEST (exp
)) == REG
)
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
)
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
)
1048 enum machine_mode mode
;
1050 rtx addr
, plus0
, plus1
;
1053 /* Eliminate non-memory operations */
1054 if (GET_CODE (op
) != MEM
)
1058 /* dword operations really put out 2 instructions, so eliminate them. */
1059 if (GET_MODE_SIZE (GET_MODE (op
)) > (HAVE_64BIT_P () ? 8 : 4))
1063 /* Decode the address now. */
1067 addr
= XEXP (op
, 0);
1069 switch (GET_CODE (addr
))
1072 /* (R0) - no extra cost */
1077 /* -(R0), (R0)+ - cheap! */
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
)
1095 /* @#address - extra cost */
1099 /* X(R0) - extra cost */
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
1119 output_block_move(operands
)
1122 static int count
= 0;
1125 if (GET_CODE(operands
[2]) == CONST_INT
1128 if (INTVAL(operands
[2]) < 16
1129 && INTVAL(operands
[3]) == 1)
1133 for (i
= 1; i
<= INTVAL(operands
[2]); i
++)
1134 output_asm_insn("movb (%1)+, (%0)+", operands
);
1138 else if (INTVAL(operands
[2]) < 32)
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 ???
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
);
1165 /* just clobber the register */
1166 operands
[4] = operands
[2];
1170 /* switch over alignment */
1171 switch (INTVAL(operands
[3]))
1187 sprintf(buf
, "\nmovestrhi%d:", count
);
1188 output_asm_insn(buf
, NULL
);
1190 output_asm_insn("movb (%1)+, (%0)+", operands
);
1194 sprintf(buf
, "sob %%4, movestrhi%d", count
);
1195 output_asm_insn(buf
, operands
);
1199 output_asm_insn("dec %4", operands
);
1201 sprintf(buf
, "bgt movestrhi%d", count
);
1202 output_asm_insn(buf
, NULL
);
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
);
1235 sprintf(buf
, "sob %%4, movestrhi%d", count
);
1236 output_asm_insn(buf
, operands
);
1240 output_asm_insn("dec %4", operands
);
1242 sprintf(buf
, "bgt movestrhi%d", count
);
1243 output_asm_insn(buf
, NULL
);
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
);
1282 sprintf(buf
, "sob %%4, movestrhi%d", count
);
1283 output_asm_insn(buf
, operands
);
1287 output_asm_insn("dec %4", operands
);
1289 sprintf(buf
, "bgt movestrhi%d", count
);
1290 output_asm_insn(buf
, NULL
);
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
);
1336 sprintf(buf
, "sob %%4, movestrhi%d", count
);
1337 output_asm_insn(buf
, operands
);
1341 output_asm_insn("dec %4", operands
);
1343 sprintf(buf
, "bgt movestrhi%d", count
);
1344 output_asm_insn(buf
, NULL
);
1357 /* for future use */
1359 comparison_operator_index(op
)
1362 switch (GET_CODE(op
))
1399 /* tests whether the rtx is a comparison operator */
1401 comp_operator (op
, mode
)
1403 enum machine_mode mode
;
1405 return comparison_operator_index(op
) >= 0;
1410 legitimate_address_p (mode
, address
)
1411 enum machine_mode mode
;
1414 /* #define REG_OK_STRICT */
1415 GO_IF_LEGITIMATE_ADDRESS(mode
, address
, win
);
1422 /* #undef REG_OK_STRICT */