1 /* Subroutines for gcc2 for pdp11.
2 Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2001
3 Free Software Foundation, Inc.
4 Contributed by Michael K. Gschwind (mike@vlsivie.tuwien.ac.at).
6 This file is part of GNU CC.
8 GNU CC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
13 GNU CC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU CC; see the file COPYING. If not, write to
20 the Free Software Foundation, 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA. */
27 #include "hard-reg-set.h"
29 #include "insn-config.h"
30 #include "conditions.h"
33 #include "insn-attr.h"
41 #include "target-def.h"
44 #define FPU_REG_P(X) ((X)>=8 && (X)<14)
45 #define CPU_REG_P(X) ((X)>=0 && (X)<8)
48 /* this is the current value returned by the macro FIRST_PARM_OFFSET
50 int current_first_parm_offset;
52 /* This is where the condition code register lives. */
53 /* rtx cc0_reg_rtx; - no longer needed? */
55 static rtx find_addr_reg PARAMS ((rtx));
56 static const char *singlemove_string PARAMS ((rtx *));
57 static void pdp11_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
58 static void pdp11_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
60 /* Initialize the GCC target structure. */
61 #undef TARGET_ASM_FUNCTION_PROLOGUE
62 #define TARGET_ASM_FUNCTION_PROLOGUE pdp11_output_function_prologue
63 #undef TARGET_ASM_FUNCTION_EPILOGUE
64 #define TARGET_ASM_FUNCTION_EPILOGUE pdp11_output_function_epilogue
66 #undef TARGET_ASM_OPEN_PAREN
67 #define TARGET_ASM_OPEN_PAREN "["
68 #undef TARGET_ASM_CLOSE_PAREN
69 #define TARGET_ASM_CLOSE_PAREN "]"
71 struct gcc_target targetm = TARGET_INITIALIZER;
73 /* Nonzero if OP is a valid second operand for an arithmetic insn. */
76 arith_operand (op, mode)
78 enum machine_mode mode;
80 return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
84 const_immediate_operand (op, mode)
86 enum machine_mode mode ATTRIBUTE_UNUSED;
88 return (GET_CODE (op) == CONST_INT);
92 immediate15_operand (op, mode)
94 enum machine_mode mode ATTRIBUTE_UNUSED;
96 return (GET_CODE (op) == CONST_INT && ((INTVAL (op) & 0x8000) == 0x0000));
100 expand_shift_operand (op, mode)
102 enum machine_mode mode ATTRIBUTE_UNUSED;
104 return (GET_CODE (op) == CONST_INT
105 && abs (INTVAL(op)) > 1
106 && abs (INTVAL(op)) <= 4);
110 stream is a stdio stream to output the code to.
111 size is an int: how many units of temporary storage to allocate.
112 Refer to the array `regs_ever_live' to determine which registers
113 to save; `regs_ever_live[I]' is nonzero if register number I
114 is ever used in the function. This macro is responsible for
115 knowing which registers should not be saved even if used.
121 pdp11_output_function_prologue (stream, size)
125 fprintf (stream, "\tjsr r5, csv\n");
128 fprintf (stream, "\t/*abuse empty parameter slot for locals!*/\n");
130 fprintf(stream, "\tsub $%d, sp\n", size - 2);
138 pdp11_output_function_prologue (stream, size)
142 HOST_WIDE_INT fsize = ((size) + 1) & ~1;
147 "\n\t; /* function prologue %s*/\n", current_function_name);
149 /* if we are outputting code for main,
150 the switch FPU to right mode if TARGET_FPU */
151 if (MAIN_NAME_P (DECL_NAME (current_function_decl)) && TARGET_FPU)
154 "\t;/* switch cpu to double float, single integer */\n");
155 fprintf(stream, "\tsetd\n");
156 fprintf(stream, "\tseti\n\n");
159 if (frame_pointer_needed)
161 fprintf(stream, "\tmov fp, -(sp)\n");
162 fprintf(stream, "\tmov sp, fp\n");
171 fprintf (stream, "\tsub $%o, sp\n", fsize);
173 /* save CPU registers */
174 for (regno = 0; regno < 8; regno++)
175 if (regs_ever_live[regno] && ! call_used_regs[regno])
176 if (! ((regno == FRAME_POINTER_REGNUM)
177 && frame_pointer_needed))
178 fprintf (stream, "\tmov %s, -(sp)\n", reg_names[regno]);
179 /* fpu regs saving */
181 /* via_ac specifies the ac to use for saving ac4, ac5 */
184 for (regno = 8; regno < FIRST_PSEUDO_REGISTER ; regno++)
187 if (LOAD_FPU_REG_P(regno)
188 && regs_ever_live[regno]
189 && ! call_used_regs[regno])
191 fprintf (stream, "\tfstd %s, -(sp)\n", reg_names[regno]);
195 /* maybe make ac4, ac5 call used regs?? */
197 if (NO_LOAD_FPU_REG_P(regno)
198 && regs_ever_live[regno]
199 && ! call_used_regs[regno])
204 fprintf (stream, "\tfldd %s, %s\n", reg_names[regno], reg_names[via_ac]);
205 fprintf (stream, "\tfstd %s, -(sp)\n", reg_names[via_ac]);
209 fprintf (stream, "\t;/* end of prologue */\n\n");
212 #endif /* !TWO_BSD */
215 The function epilogue should not depend on the current stack pointer!
216 It should use the frame pointer only. This is mandatory because
217 of alloca; we also take advantage of it to omit stack adjustments
220 /* maybe we can make leaf functions faster by switching to the
221 second register file - this way we don't have to save regs!
222 leaf functions are ~ 50% of all functions (dynamically!)
224 set/clear bit 11 (dec. 2048) of status word for switching register files -
225 but how can we do this? the pdp11/45 manual says bit may only
226 be set (p.24), but not cleared!
228 switching to kernel is probably more expensive, so we'll leave it
229 like this and not use the second set of registers...
231 maybe as option if you want to generate code for kernel mode? */
236 pdp11_output_function_epilogue (stream, size)
238 HOST_WIDE_INT size ATTRIBUTE_UNUSED;
240 fprintf (stream, "\t/* SP ignored by cret? */\n");
241 fprintf (stream, "\tjmp cret\n");
247 pdp11_output_function_epilogue (stream, size)
251 HOST_WIDE_INT fsize = ((size) + 1) & ~1;
256 fprintf (stream, "\n\t; /*function epilogue */\n");
258 if (frame_pointer_needed)
260 /* hope this is safe - m68k does it also .... */
261 regs_ever_live[FRAME_POINTER_REGNUM] = 0;
263 for (i =7, j = 0 ; i >= 0 ; i--)
264 if (regs_ever_live[i] && ! call_used_regs[i])
267 /* remember # of pushed bytes for CPU regs */
270 for (i =7 ; i >= 0 ; i--)
271 if (regs_ever_live[i] && ! call_used_regs[i])
272 fprintf(stream, "\tmov %o(fp), %s\n",-fsize-2*j--, reg_names[i]);
275 via_ac = FIRST_PSEUDO_REGISTER -1;
277 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
278 if (regs_ever_live[i] && ! call_used_regs[i])
284 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
286 if (LOAD_FPU_REG_P(i)
288 && ! call_used_regs[i])
290 fprintf(stream, "\tfldd %o(fp), %s\n", -fsize-k, reg_names[i]);
294 if (NO_LOAD_FPU_REG_P(i)
296 && ! call_used_regs[i])
298 if (! LOAD_FPU_REG_P(via_ac))
301 fprintf(stream, "\tfldd %o(fp), %s\n", -fsize-k, reg_names[via_ac]);
302 fprintf(stream, "\tfstd %s, %s\n", reg_names[via_ac], reg_names[i]);
307 fprintf(stream, "\tmov fp, sp\n");
308 fprintf (stream, "\tmov (sp)+, fp\n");
312 via_ac = FIRST_PSEUDO_REGISTER -1;
315 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
316 if (regs_ever_live[i] && call_used_regs[i])
319 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
321 if (LOAD_FPU_REG_P(i)
323 && ! call_used_regs[i])
324 fprintf(stream, "\tfldd (sp)+, %s\n", reg_names[i]);
326 if (NO_LOAD_FPU_REG_P(i)
328 && ! call_used_regs[i])
330 if (! LOAD_FPU_REG_P(via_ac))
333 fprintf(stream, "\tfldd (sp)+, %s\n", reg_names[via_ac]);
334 fprintf(stream, "\tfstd %s, %s\n", reg_names[via_ac], reg_names[i]);
338 for (i=7; i >= 0; i--)
339 if (regs_ever_live[i] && !call_used_regs[i])
340 fprintf(stream, "\tmov (sp)+, %s\n", reg_names[i]);
343 fprintf((stream), "\tadd $%o, sp\n", fsize);
346 fprintf (stream, "\trts pc\n");
347 fprintf (stream, "\t;/* end of epilogue*/\n\n\n");
350 #endif /* !TWO_BSD */
352 /* Return the best assembler insn template
353 for moving operands[1] into operands[0] as a fullword. */
355 singlemove_string (operands)
358 if (operands[1] != const0_rtx)
365 /* Output assembler code to perform a doubleword move insn
366 with operands OPERANDS. */
369 output_move_double (operands)
372 enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
374 rtx addreg0 = 0, addreg1 = 0;
376 /* First classify both operands. */
378 if (REG_P (operands[0]))
380 else if (offsettable_memref_p (operands[0]))
382 else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
384 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
386 else if (GET_CODE (operands[0]) == MEM)
391 if (REG_P (operands[1]))
393 else if (CONSTANT_P (operands[1]))
395 || GET_CODE (operands[1]) == CONST_DOUBLE)
398 else if (offsettable_memref_p (operands[1]))
400 else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
402 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
404 else if (GET_CODE (operands[1]) == MEM)
409 /* Check for the cases that the operand constraints are not
410 supposed to allow to happen. Abort if we get one,
411 because generating code for these cases is painful. */
413 if (optype0 == RNDOP || optype1 == RNDOP)
416 /* If one operand is decrementing and one is incrementing
417 decrement the former register explicitly
418 and change that operand into ordinary indexing. */
420 if (optype0 == PUSHOP && optype1 == POPOP)
422 operands[0] = XEXP (XEXP (operands[0], 0), 0);
423 output_asm_insn ("sub $4,%0", operands);
424 operands[0] = gen_rtx_MEM (SImode, operands[0]);
427 if (optype0 == POPOP && optype1 == PUSHOP)
429 operands[1] = XEXP (XEXP (operands[1], 0), 0);
430 output_asm_insn ("sub $4,%1", operands);
431 operands[1] = gen_rtx_MEM (SImode, operands[1]);
435 /* If an operand is an unoffsettable memory ref, find a register
436 we can increment temporarily to make it refer to the second word. */
438 if (optype0 == MEMOP)
439 addreg0 = find_addr_reg (XEXP (operands[0], 0));
441 if (optype1 == MEMOP)
442 addreg1 = find_addr_reg (XEXP (operands[1], 0));
444 /* Ok, we can do one word at a time.
445 Normally we do the low-numbered word first,
446 but if either operand is autodecrementing then we
447 do the high-numbered word first.
449 In either case, set up in LATEHALF the operands to use
450 for the high-numbered word and in some cases alter the
451 operands in OPERANDS to be suitable for the low-numbered word. */
453 if (optype0 == REGOP)
454 latehalf[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1);
455 else if (optype0 == OFFSOP)
456 latehalf[0] = adjust_address (operands[0], HImode, 2);
458 latehalf[0] = operands[0];
460 if (optype1 == REGOP)
461 latehalf[1] = gen_rtx_REG (HImode, REGNO (operands[1]) + 1);
462 else if (optype1 == OFFSOP)
463 latehalf[1] = adjust_address (operands[1], HImode, 2);
464 else if (optype1 == CNSTOP)
466 if (CONSTANT_P (operands[1]))
468 /* now the mess begins, high word is in lower word???
470 that's what ashc makes me think, but I don't remember :-( */
471 latehalf[1] = GEN_INT (INTVAL(operands[1]) >> 16);
472 operands[1] = GEN_INT (INTVAL(operands[1]) & 0xff);
474 else if (GET_CODE (operands[1]) == CONST_DOUBLE)
476 /* immediate 32 bit values not allowed */
481 latehalf[1] = operands[1];
483 /* If insn is effectively movd N(sp),-(sp) then we will do the
484 high word first. We should use the adjusted operand 1 (which is N+4(sp))
485 for the low word as well, to compensate for the first decrement of sp. */
486 if (optype0 == PUSHOP
487 && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
488 && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
489 operands[1] = latehalf[1];
491 /* If one or both operands autodecrementing,
492 do the two words, high-numbered first. */
494 /* Likewise, the first move would clobber the source of the second one,
495 do them in the other order. This happens only for registers;
496 such overlap can't happen in memory unless the user explicitly
497 sets it up, and that is an undefined circumstance. */
499 if (optype0 == PUSHOP || optype1 == PUSHOP
500 || (optype0 == REGOP && optype1 == REGOP
501 && REGNO (operands[0]) == REGNO (latehalf[1])))
503 /* Make any unoffsettable addresses point at high-numbered word. */
505 output_asm_insn ("add $2,%0", &addreg0);
507 output_asm_insn ("add $2,%0", &addreg1);
510 output_asm_insn (singlemove_string (latehalf), latehalf);
512 /* Undo the adds we just did. */
514 output_asm_insn ("sub $2,%0", &addreg0);
516 output_asm_insn ("sub $2,%0", &addreg1);
518 /* Do low-numbered word. */
519 return singlemove_string (operands);
522 /* Normal case: do the two words, low-numbered first. */
524 output_asm_insn (singlemove_string (operands), operands);
526 /* Make any unoffsettable addresses point at high-numbered word. */
528 output_asm_insn ("add $2,%0", &addreg0);
530 output_asm_insn ("add $2,%0", &addreg1);
533 output_asm_insn (singlemove_string (latehalf), latehalf);
535 /* Undo the adds we just did. */
537 output_asm_insn ("sub $2,%0", &addreg0);
539 output_asm_insn ("sub $2,%0", &addreg1);
543 /* Output assembler code to perform a quadword move insn
544 with operands OPERANDS. */
547 output_move_quad (operands)
550 enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
552 rtx addreg0 = 0, addreg1 = 0;
554 output_asm_insn(";; movdi/df: %1 -> %0", operands);
556 if (REG_P (operands[0]))
558 else if (offsettable_memref_p (operands[0]))
560 else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
562 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
564 else if (GET_CODE (operands[0]) == MEM)
569 if (REG_P (operands[1]))
571 else if (CONSTANT_P (operands[1])
572 || GET_CODE (operands[1]) == CONST_DOUBLE)
574 else if (offsettable_memref_p (operands[1]))
576 else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
578 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
580 else if (GET_CODE (operands[1]) == MEM)
585 /* Check for the cases that the operand constraints are not
586 supposed to allow to happen. Abort if we get one,
587 because generating code for these cases is painful. */
589 if (optype0 == RNDOP || optype1 == RNDOP)
592 /* check if we move a CPU reg to an FPU reg, or vice versa! */
593 if (optype0 == REGOP && optype1 == REGOP)
594 /* bogus - 64 bit cannot reside in CPU! */
595 if (CPU_REG_P(REGNO(operands[0]))
596 || CPU_REG_P (REGNO(operands[1])))
599 if (optype0 == REGOP || optype1 == REGOP)
601 /* check for use of clrd????
602 if you ever allow ac4 and ac5 (now we require secondary load)
603 you must check whether
604 you want to load into them or store from them -
605 then dump ac0 into $help$ movce ac4/5 to ac0, do the
606 store from ac0, and restore ac0 - if you can find
607 an unused ac[0-3], use that and you save a store and a load!*/
609 if (FPU_REG_P(REGNO(operands[0])))
611 if (GET_CODE(operands[1]) == CONST_DOUBLE)
613 union { double d; int i[2]; } u;
614 u.i[0] = CONST_DOUBLE_LOW (operands[1]);
615 u.i[1] = CONST_DOUBLE_HIGH (operands[1]);
618 return "{clrd|clrf} %0";
621 return "{ldd|movf} %1, %0";
624 if (FPU_REG_P(REGNO(operands[1])))
625 return "{std|movf} %1, %0";
628 /* If one operand is decrementing and one is incrementing
629 decrement the former register explicitly
630 and change that operand into ordinary indexing. */
632 if (optype0 == PUSHOP && optype1 == POPOP)
634 operands[0] = XEXP (XEXP (operands[0], 0), 0);
635 output_asm_insn ("sub $8,%0", operands);
636 operands[0] = gen_rtx_MEM (DImode, operands[0]);
639 if (optype0 == POPOP && optype1 == PUSHOP)
641 operands[1] = XEXP (XEXP (operands[1], 0), 0);
642 output_asm_insn ("sub $8,%1", operands);
643 operands[1] = gen_rtx_MEM (SImode, operands[1]);
647 /* If an operand is an unoffsettable memory ref, find a register
648 we can increment temporarily to make it refer to the second word. */
650 if (optype0 == MEMOP)
651 addreg0 = find_addr_reg (XEXP (operands[0], 0));
653 if (optype1 == MEMOP)
654 addreg1 = find_addr_reg (XEXP (operands[1], 0));
656 /* Ok, we can do one word at a time.
657 Normally we do the low-numbered word first,
658 but if either operand is autodecrementing then we
659 do the high-numbered word first.
661 In either case, set up in LATEHALF the operands to use
662 for the high-numbered word and in some cases alter the
663 operands in OPERANDS to be suitable for the low-numbered word. */
665 if (optype0 == REGOP)
666 latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2);
667 else if (optype0 == OFFSOP)
668 latehalf[0] = adjust_address (operands[0], SImode, 4);
670 latehalf[0] = operands[0];
672 if (optype1 == REGOP)
673 latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2);
674 else if (optype1 == OFFSOP)
675 latehalf[1] = adjust_address (operands[1], SImode, 4);
676 else if (optype1 == CNSTOP)
678 if (GET_CODE (operands[1]) == CONST_DOUBLE)
680 /* floats only. not yet supported!
682 -- compute it into PDP float format, - internally,
683 just use IEEE and ignore possible problems ;-)
685 we might get away with it !!!! */
689 #ifndef HOST_WORDS_BIG_ENDIAN
690 latehalf[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
691 operands[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
692 #else /* HOST_WORDS_BIG_ENDIAN */
693 latehalf[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
694 operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
695 #endif /* HOST_WORDS_BIG_ENDIAN */
697 else if (GET_CODE(operands[1]) == CONST_INT)
699 latehalf[1] = GEN_INT (0);
705 latehalf[1] = operands[1];
707 /* If insn is effectively movd N(sp),-(sp) then we will do the
708 high word first. We should use the adjusted operand 1 (which is N+4(sp))
709 for the low word as well, to compensate for the first decrement of sp. */
710 if (optype0 == PUSHOP
711 && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
712 && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
713 operands[1] = latehalf[1];
715 /* If one or both operands autodecrementing,
716 do the two words, high-numbered first. */
718 /* Likewise, the first move would clobber the source of the second one,
719 do them in the other order. This happens only for registers;
720 such overlap can't happen in memory unless the user explicitly
721 sets it up, and that is an undefined circumstance. */
723 if (optype0 == PUSHOP || optype1 == PUSHOP
724 || (optype0 == REGOP && optype1 == REGOP
725 && REGNO (operands[0]) == REGNO (latehalf[1])))
727 /* Make any unoffsettable addresses point at high-numbered word. */
729 output_asm_insn ("add $4,%0", &addreg0);
731 output_asm_insn ("add $4,%0", &addreg1);
734 output_asm_insn(output_move_double(latehalf), latehalf);
736 /* Undo the adds we just did. */
738 output_asm_insn ("sub $4,%0", &addreg0);
740 output_asm_insn ("sub $4,%0", &addreg1);
742 /* Do low-numbered word. */
743 return output_move_double (operands);
746 /* Normal case: do the two words, low-numbered first. */
748 output_asm_insn (output_move_double (operands), operands);
750 /* Make any unoffsettable addresses point at high-numbered word. */
752 output_asm_insn ("add $4,%0", &addreg0);
754 output_asm_insn ("add $4,%0", &addreg1);
757 output_asm_insn (output_move_double (latehalf), latehalf);
759 /* Undo the adds we just did. */
761 output_asm_insn ("sub $4,%0", &addreg0);
763 output_asm_insn ("sub $4,%0", &addreg1);
769 /* Return a REG that occurs in ADDR with coefficient 1.
770 ADDR can be effectively incremented by incrementing REG. */
776 while (GET_CODE (addr) == PLUS)
778 if (GET_CODE (XEXP (addr, 0)) == REG)
779 addr = XEXP (addr, 0);
780 if (GET_CODE (XEXP (addr, 1)) == REG)
781 addr = XEXP (addr, 1);
782 if (CONSTANT_P (XEXP (addr, 0)))
783 addr = XEXP (addr, 1);
784 if (CONSTANT_P (XEXP (addr, 1)))
785 addr = XEXP (addr, 0);
787 if (GET_CODE (addr) == REG)
792 /* Output an ascii string. */
794 output_ascii (file, p, size)
801 /* This used to output .byte "string", which doesn't work with the UNIX
802 assembler and I think not with DEC ones either. */
803 fprintf (file, "\t.byte ");
805 for (i = 0; i < size; i++)
807 register int c = p[i];
810 fprintf (file, "%o", c);
818 /* --- stole from out-vax, needs changes */
821 print_operand_address (file, addr)
825 register rtx reg1, reg2, breg, ireg;
830 switch (GET_CODE (addr))
837 addr = XEXP (addr, 0);
841 fprintf (file, "(%s)", reg_names[REGNO (addr)]);
845 fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]);
849 fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]);
856 if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
857 || GET_CODE (XEXP (addr, 0)) == MEM)
859 offset = XEXP (addr, 0);
860 addr = XEXP (addr, 1);
862 else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
863 || GET_CODE (XEXP (addr, 1)) == MEM)
865 offset = XEXP (addr, 1);
866 addr = XEXP (addr, 0);
868 if (GET_CODE (addr) != PLUS)
870 else if (GET_CODE (XEXP (addr, 0)) == MULT)
872 reg1 = XEXP (addr, 0);
873 addr = XEXP (addr, 1);
875 else if (GET_CODE (XEXP (addr, 1)) == MULT)
877 reg1 = XEXP (addr, 1);
878 addr = XEXP (addr, 0);
880 else if (GET_CODE (XEXP (addr, 0)) == REG)
882 reg1 = XEXP (addr, 0);
883 addr = XEXP (addr, 1);
885 else if (GET_CODE (XEXP (addr, 1)) == REG)
887 reg1 = XEXP (addr, 1);
888 addr = XEXP (addr, 0);
890 if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
900 if (addr != 0) abort ();
903 if (reg1 != 0 && GET_CODE (reg1) == MULT)
908 else if (reg2 != 0 && GET_CODE (reg2) == MULT)
913 else if (reg2 != 0 || GET_CODE (addr) == MEM)
924 output_address (addr);
927 if (GET_CODE (breg) != REG)
929 fprintf (file, "(%s)", reg_names[REGNO (breg)]);
933 if (GET_CODE (ireg) == MULT)
934 ireg = XEXP (ireg, 0);
935 if (GET_CODE (ireg) != REG)
938 fprintf (file, "[%s]", reg_names[REGNO (ireg)]);
943 output_addr_const_pdp11 (file, addr);
947 /* register move costs, indexed by regs */
949 static int move_costs[N_REG_CLASSES][N_REG_CLASSES] =
951 /* NO MUL GEN LFPU NLFPU FPU ALL */
953 /* NO */ { 0, 0, 0, 0, 0, 0, 0},
954 /* MUL */ { 0, 2, 2, 10, 22, 22, 22},
955 /* GEN */ { 0, 2, 2, 10, 22, 22, 22},
956 /* LFPU */ { 0, 10, 10, 2, 2, 2, 10},
957 /* NLFPU */ { 0, 22, 22, 2, 2, 2, 22},
958 /* FPU */ { 0, 22, 22, 2, 2, 2, 22},
959 /* ALL */ { 0, 22, 22, 10, 22, 22, 22}
963 /* -- note that some moves are tremendously expensive,
964 because they require lots of tricks! do we have to
965 charge the costs incurred by secondary reload class
966 -- as we do here with 22 -- or not ? */
969 register_move_cost(c1, c2)
970 enum reg_class c1, c2;
972 return move_costs[(int)c1][(int)c2];
976 output_jump(pos, neg, length)
977 const char *pos, *neg;
982 static char buf[1000];
985 /* currently we don't need this, because the tstdf and cmpdf
986 copy the condition code immediately, and other float operations are not
987 yet recognized as changing the FCC - if so, then the length-cost of all
988 jump insns increases by one, because we have to potentially copy the
990 if (cc_status.flags & CC_IN_FPU)
991 output_asm_insn("cfcc", NULL);
1005 sprintf(buf, "%s JMP_%d\n\tjmp %%l0\nJMP_%d:", neg, x, x);
1019 notice_update_cc_on_set(exp, insn)
1021 rtx insn ATTRIBUTE_UNUSED;
1023 if (GET_CODE (SET_DEST (exp)) == CC0)
1025 cc_status.flags = 0;
1026 cc_status.value1 = SET_DEST (exp);
1027 cc_status.value2 = SET_SRC (exp);
1030 if (GET_MODE(SET_SRC(exp)) == DFmode)
1031 cc_status.flags |= CC_IN_FPU;
1034 else if ((GET_CODE (SET_DEST (exp)) == REG
1035 || GET_CODE (SET_DEST (exp)) == MEM)
1036 && GET_CODE (SET_SRC (exp)) != PC
1037 && (GET_MODE (SET_DEST(exp)) == HImode
1038 || GET_MODE (SET_DEST(exp)) == QImode)
1039 && (GET_CODE (SET_SRC(exp)) == PLUS
1040 || GET_CODE (SET_SRC(exp)) == MINUS
1041 || GET_CODE (SET_SRC(exp)) == AND
1042 || GET_CODE (SET_SRC(exp)) == IOR
1043 || GET_CODE (SET_SRC(exp)) == XOR
1044 || GET_CODE (SET_SRC(exp)) == NOT
1045 || GET_CODE (SET_SRC(exp)) == NEG
1046 || GET_CODE (SET_SRC(exp)) == REG
1047 || GET_CODE (SET_SRC(exp)) == MEM))
1049 cc_status.flags = 0;
1050 cc_status.value1 = SET_SRC (exp);
1051 cc_status.value2 = SET_DEST (exp);
1053 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
1055 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
1056 cc_status.value2 = 0;
1057 if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM
1059 && GET_CODE (cc_status.value2) == MEM)
1060 cc_status.value2 = 0;
1062 else if (GET_CODE (SET_SRC (exp)) == CALL)
1066 else if (GET_CODE (SET_DEST (exp)) == REG)
1069 if ((cc_status.value1
1070 && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1)))
1071 cc_status.value1 = 0;
1072 if ((cc_status.value2
1073 && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2)))
1074 cc_status.value2 = 0;
1076 else if (SET_DEST(exp) == pc_rtx)
1080 else /* if (GET_CODE (SET_DEST (exp)) == MEM) */
1082 /* the last else is a bit paranoiac, but since nearly all instructions
1083 play with condition codes, it's reasonable! */
1085 CC_STATUS_INIT; /* paranoia*/
1091 simple_memory_operand(op, mode)
1093 enum machine_mode mode ATTRIBUTE_UNUSED;
1097 /* Eliminate non-memory operations */
1098 if (GET_CODE (op) != MEM)
1102 /* dword operations really put out 2 instructions, so eliminate them. */
1103 if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4))
1107 /* Decode the address now. */
1111 addr = XEXP (op, 0);
1113 switch (GET_CODE (addr))
1116 /* (R0) - no extra cost */
1121 /* -(R0), (R0)+ - cheap! */
1125 /* cheap - is encoded in addressing mode info!
1127 -- except for @(R0), which has to be @0(R0) !!! */
1129 if (GET_CODE (XEXP (addr, 0)) == REG)
1139 /* @#address - extra cost */
1143 /* X(R0) - extra cost */
1155 * output a block move:
1157 * operands[0] ... to
1158 * operands[1] ... from
1159 * operands[2] ... length
1160 * operands[3] ... alignment
1161 * operands[4] ... scratch register
1166 output_block_move(operands)
1169 static int count = 0;
1172 if (GET_CODE(operands[2]) == CONST_INT
1175 if (INTVAL(operands[2]) < 16
1176 && INTVAL(operands[3]) == 1)
1180 for (i = 1; i <= INTVAL(operands[2]); i++)
1181 output_asm_insn("movb (%1)+, (%0)+", operands);
1185 else if (INTVAL(operands[2]) < 32)
1189 for (i = 1; i <= INTVAL(operands[2])/2; i++)
1190 output_asm_insn("mov (%1)+, (%0)+", operands);
1192 /* may I assume that moved quantity is
1193 multiple of alignment ???
1202 /* can do other clever things, maybe... */
1205 if (CONSTANT_P(operands[2]) )
1207 /* just move count to scratch */
1208 output_asm_insn("mov %2, %4", operands);
1212 /* just clobber the register */
1213 operands[4] = operands[2];
1217 /* switch over alignment */
1218 switch (INTVAL(operands[3]))
1234 sprintf(buf, "\nmovestrhi%d:", count);
1235 output_asm_insn(buf, NULL);
1237 output_asm_insn("movb (%1)+, (%0)+", operands);
1241 sprintf(buf, "sob %%4, movestrhi%d", count);
1242 output_asm_insn(buf, operands);
1246 output_asm_insn("dec %4", operands);
1248 sprintf(buf, "bgt movestrhi%d", count);
1249 output_asm_insn(buf, NULL);
1271 generate_compact_code:
1273 output_asm_insn("asr %4", operands);
1275 sprintf(buf, "\nmovestrhi%d:", count);
1276 output_asm_insn(buf, NULL);
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);
1316 goto generate_compact_code;
1318 output_asm_insn("asr %4", operands);
1319 output_asm_insn("asr %4", operands);
1321 sprintf(buf, "\nmovestrhi%d:", count);
1322 output_asm_insn(buf, NULL);
1324 output_asm_insn("mov (%1)+, (%0)+", operands);
1325 output_asm_insn("mov (%1)+, (%0)+", operands);
1329 sprintf(buf, "sob %%4, movestrhi%d", count);
1330 output_asm_insn(buf, operands);
1334 output_asm_insn("dec %4", operands);
1336 sprintf(buf, "bgt movestrhi%d", count);
1337 output_asm_insn(buf, NULL);
1367 goto generate_compact_code;
1369 output_asm_insn("asr %4", operands);
1370 output_asm_insn("asr %4", operands);
1371 output_asm_insn("asr %4", operands);
1373 sprintf(buf, "\nmovestrhi%d:", count);
1374 output_asm_insn(buf, NULL);
1376 output_asm_insn("mov (%1)+, (%0)+", operands);
1377 output_asm_insn("mov (%1)+, (%0)+", operands);
1378 output_asm_insn("mov (%1)+, (%0)+", operands);
1379 output_asm_insn("mov (%1)+, (%0)+", operands);
1383 sprintf(buf, "sob %%4, movestrhi%d", count);
1384 output_asm_insn(buf, operands);
1388 output_asm_insn("dec %4", operands);
1390 sprintf(buf, "bgt movestrhi%d", count);
1391 output_asm_insn(buf, NULL);
1404 /* for future use */
1406 comparison_operator_index(op)
1409 switch (GET_CODE(op))
1446 /* tests whether the rtx is a comparison operator */
1448 comp_operator (op, mode)
1450 enum machine_mode mode ATTRIBUTE_UNUSED;
1452 return comparison_operator_index(op) >= 0;
1457 legitimate_address_p (mode, address)
1458 enum machine_mode mode;
1461 /* #define REG_OK_STRICT */
1462 GO_IF_LEGITIMATE_ADDRESS(mode, address, win);
1469 /* #undef REG_OK_STRICT */
1472 /* A copy of output_addr_const modified for pdp11 expression syntax.
1473 output_addr_const also gets called for %cDIGIT and %nDIGIT, which we don't
1474 use, and for debugging output, which we don't support with this port either.
1475 So this copy should get called whenever needed.
1478 output_addr_const_pdp11 (file, x)
1485 switch (GET_CODE (x))
1495 assemble_name (file, XSTR (x, 0));
1499 ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
1500 assemble_name (file, buf);
1504 ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
1505 assemble_name (file, buf);
1509 /* Should we check for constants which are too big? Maybe cutting
1510 them off to 16 bits is OK? */
1511 fprintf (file, "%ho", (unsigned short) INTVAL (x));
1515 /* This used to output parentheses around the expression,
1516 but that does not work on the 386 (either ATT or BSD assembler). */
1517 output_addr_const_pdp11 (file, XEXP (x, 0));
1521 if (GET_MODE (x) == VOIDmode)
1523 /* We can use %o if the number is one word and positive. */
1524 if (CONST_DOUBLE_HIGH (x))
1525 abort (); /* Should we just silently drop the high part? */
1527 fprintf (file, "%ho", (unsigned short) CONST_DOUBLE_LOW (x));
1530 /* We can't handle floating point constants;
1531 PRINT_OPERAND must handle them. */
1532 output_operand_lossage ("floating constant misused");
1536 /* Some assemblers need integer constants to appear last (eg masm). */
1537 if (GET_CODE (XEXP (x, 0)) == CONST_INT)
1539 output_addr_const_pdp11 (file, XEXP (x, 1));
1540 if (INTVAL (XEXP (x, 0)) >= 0)
1541 fprintf (file, "+");
1542 output_addr_const_pdp11 (file, XEXP (x, 0));
1546 output_addr_const_pdp11 (file, XEXP (x, 0));
1547 if (INTVAL (XEXP (x, 1)) >= 0)
1548 fprintf (file, "+");
1549 output_addr_const_pdp11 (file, XEXP (x, 1));
1554 /* Avoid outputting things like x-x or x+5-x,
1555 since some assemblers can't handle that. */
1556 x = simplify_subtraction (x);
1557 if (GET_CODE (x) != MINUS)
1560 output_addr_const_pdp11 (file, XEXP (x, 0));
1561 fprintf (file, "-");
1562 if (GET_CODE (XEXP (x, 1)) == CONST_INT
1563 && INTVAL (XEXP (x, 1)) < 0)
1565 fprintf (file, targetm.asm_out.open_paren);
1566 output_addr_const_pdp11 (file, XEXP (x, 1));
1567 fprintf (file, targetm.asm_out.close_paren);
1570 output_addr_const_pdp11 (file, XEXP (x, 1));
1575 output_addr_const_pdp11 (file, XEXP (x, 0));
1579 output_operand_lossage ("invalid expression as operand");