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 bool pdp11_assemble_integer
PARAMS ((rtx
, unsigned int, int));
58 static void pdp11_output_function_prologue
PARAMS ((FILE *, HOST_WIDE_INT
));
59 static void pdp11_output_function_epilogue
PARAMS ((FILE *, HOST_WIDE_INT
));
61 /* Initialize the GCC target structure. */
62 #undef TARGET_ASM_BYTE_OP
63 #define TARGET_ASM_BYTE_OP NULL
64 #undef TARGET_ASM_ALIGNED_HI_OP
65 #define TARGET_ASM_ALIGNED_HI_OP NULL
66 #undef TARGET_ASM_ALIGNED_SI_OP
67 #define TARGET_ASM_ALIGNED_SI_OP NULL
68 #undef TARGET_ASM_INTEGER
69 #define TARGET_ASM_INTEGER pdp11_assemble_integer
71 #undef TARGET_ASM_FUNCTION_PROLOGUE
72 #define TARGET_ASM_FUNCTION_PROLOGUE pdp11_output_function_prologue
73 #undef TARGET_ASM_FUNCTION_EPILOGUE
74 #define TARGET_ASM_FUNCTION_EPILOGUE pdp11_output_function_epilogue
76 #undef TARGET_ASM_OPEN_PAREN
77 #define TARGET_ASM_OPEN_PAREN "["
78 #undef TARGET_ASM_CLOSE_PAREN
79 #define TARGET_ASM_CLOSE_PAREN "]"
81 struct gcc_target targetm
= TARGET_INITIALIZER
;
83 /* Nonzero if OP is a valid second operand for an arithmetic insn. */
86 arith_operand (op
, mode
)
88 enum machine_mode mode
;
90 return (register_operand (op
, mode
) || GET_CODE (op
) == CONST_INT
);
94 const_immediate_operand (op
, mode
)
96 enum machine_mode mode ATTRIBUTE_UNUSED
;
98 return (GET_CODE (op
) == CONST_INT
);
102 immediate15_operand (op
, mode
)
104 enum machine_mode mode ATTRIBUTE_UNUSED
;
106 return (GET_CODE (op
) == CONST_INT
&& ((INTVAL (op
) & 0x8000) == 0x0000));
110 expand_shift_operand (op
, mode
)
112 enum machine_mode mode ATTRIBUTE_UNUSED
;
114 return (GET_CODE (op
) == CONST_INT
115 && abs (INTVAL(op
)) > 1
116 && abs (INTVAL(op
)) <= 4);
120 stream is a stdio stream to output the code to.
121 size is an int: how many units of temporary storage to allocate.
122 Refer to the array `regs_ever_live' to determine which registers
123 to save; `regs_ever_live[I]' is nonzero if register number I
124 is ever used in the function. This macro is responsible for
125 knowing which registers should not be saved even if used.
131 pdp11_output_function_prologue (stream
, size
)
135 fprintf (stream
, "\tjsr r5, csv\n");
138 fprintf (stream
, "\t/*abuse empty parameter slot for locals!*/\n");
140 fprintf(stream
, "\tsub $%d, sp\n", size
- 2);
148 pdp11_output_function_prologue (stream
, size
)
152 HOST_WIDE_INT fsize
= ((size
) + 1) & ~1;
157 "\n\t; /* function prologue %s*/\n", current_function_name
);
159 /* if we are outputting code for main,
160 the switch FPU to right mode if TARGET_FPU */
161 if (MAIN_NAME_P (DECL_NAME (current_function_decl
)) && TARGET_FPU
)
164 "\t;/* switch cpu to double float, single integer */\n");
165 fprintf(stream
, "\tsetd\n");
166 fprintf(stream
, "\tseti\n\n");
169 if (frame_pointer_needed
)
171 fprintf(stream
, "\tmov fp, -(sp)\n");
172 fprintf(stream
, "\tmov sp, fp\n");
181 fprintf (stream
, "\tsub $%o, sp\n", fsize
);
183 /* save CPU registers */
184 for (regno
= 0; regno
< 8; regno
++)
185 if (regs_ever_live
[regno
] && ! call_used_regs
[regno
])
186 if (! ((regno
== FRAME_POINTER_REGNUM
)
187 && frame_pointer_needed
))
188 fprintf (stream
, "\tmov %s, -(sp)\n", reg_names
[regno
]);
189 /* fpu regs saving */
191 /* via_ac specifies the ac to use for saving ac4, ac5 */
194 for (regno
= 8; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
197 if (LOAD_FPU_REG_P(regno
)
198 && regs_ever_live
[regno
]
199 && ! call_used_regs
[regno
])
201 fprintf (stream
, "\tfstd %s, -(sp)\n", reg_names
[regno
]);
205 /* maybe make ac4, ac5 call used regs?? */
207 if (NO_LOAD_FPU_REG_P(regno
)
208 && regs_ever_live
[regno
]
209 && ! call_used_regs
[regno
])
214 fprintf (stream
, "\tfldd %s, %s\n", reg_names
[regno
], reg_names
[via_ac
]);
215 fprintf (stream
, "\tfstd %s, -(sp)\n", reg_names
[via_ac
]);
219 fprintf (stream
, "\t;/* end of prologue */\n\n");
222 #endif /* !TWO_BSD */
225 The function epilogue should not depend on the current stack pointer!
226 It should use the frame pointer only. This is mandatory because
227 of alloca; we also take advantage of it to omit stack adjustments
230 /* maybe we can make leaf functions faster by switching to the
231 second register file - this way we don't have to save regs!
232 leaf functions are ~ 50% of all functions (dynamically!)
234 set/clear bit 11 (dec. 2048) of status word for switching register files -
235 but how can we do this? the pdp11/45 manual says bit may only
236 be set (p.24), but not cleared!
238 switching to kernel is probably more expensive, so we'll leave it
239 like this and not use the second set of registers...
241 maybe as option if you want to generate code for kernel mode? */
246 pdp11_output_function_epilogue (stream
, size
)
248 HOST_WIDE_INT size ATTRIBUTE_UNUSED
;
250 fprintf (stream
, "\t/* SP ignored by cret? */\n");
251 fprintf (stream
, "\tjmp cret\n");
257 pdp11_output_function_epilogue (stream
, size
)
261 HOST_WIDE_INT fsize
= ((size
) + 1) & ~1;
266 fprintf (stream
, "\n\t; /*function epilogue */\n");
268 if (frame_pointer_needed
)
270 /* hope this is safe - m68k does it also .... */
271 regs_ever_live
[FRAME_POINTER_REGNUM
] = 0;
273 for (i
=7, j
= 0 ; i
>= 0 ; i
--)
274 if (regs_ever_live
[i
] && ! call_used_regs
[i
])
277 /* remember # of pushed bytes for CPU regs */
280 for (i
=7 ; i
>= 0 ; i
--)
281 if (regs_ever_live
[i
] && ! call_used_regs
[i
])
282 fprintf(stream
, "\tmov %o(fp), %s\n",-fsize
-2*j
--, reg_names
[i
]);
285 via_ac
= FIRST_PSEUDO_REGISTER
-1;
287 for (i
= FIRST_PSEUDO_REGISTER
; i
> 7; i
--)
288 if (regs_ever_live
[i
] && ! call_used_regs
[i
])
294 for (i
= FIRST_PSEUDO_REGISTER
; i
> 7; i
--)
296 if (LOAD_FPU_REG_P(i
)
298 && ! call_used_regs
[i
])
300 fprintf(stream
, "\tfldd %o(fp), %s\n", -fsize
-k
, reg_names
[i
]);
304 if (NO_LOAD_FPU_REG_P(i
)
306 && ! call_used_regs
[i
])
308 if (! LOAD_FPU_REG_P(via_ac
))
311 fprintf(stream
, "\tfldd %o(fp), %s\n", -fsize
-k
, reg_names
[via_ac
]);
312 fprintf(stream
, "\tfstd %s, %s\n", reg_names
[via_ac
], reg_names
[i
]);
317 fprintf(stream
, "\tmov fp, sp\n");
318 fprintf (stream
, "\tmov (sp)+, fp\n");
322 via_ac
= FIRST_PSEUDO_REGISTER
-1;
325 for (i
= FIRST_PSEUDO_REGISTER
; i
> 7; i
--)
326 if (regs_ever_live
[i
] && call_used_regs
[i
])
329 for (i
= FIRST_PSEUDO_REGISTER
; i
> 7; i
--)
331 if (LOAD_FPU_REG_P(i
)
333 && ! call_used_regs
[i
])
334 fprintf(stream
, "\tfldd (sp)+, %s\n", reg_names
[i
]);
336 if (NO_LOAD_FPU_REG_P(i
)
338 && ! call_used_regs
[i
])
340 if (! LOAD_FPU_REG_P(via_ac
))
343 fprintf(stream
, "\tfldd (sp)+, %s\n", reg_names
[via_ac
]);
344 fprintf(stream
, "\tfstd %s, %s\n", reg_names
[via_ac
], reg_names
[i
]);
348 for (i
=7; i
>= 0; i
--)
349 if (regs_ever_live
[i
] && !call_used_regs
[i
])
350 fprintf(stream
, "\tmov (sp)+, %s\n", reg_names
[i
]);
353 fprintf((stream
), "\tadd $%o, sp\n", fsize
);
356 fprintf (stream
, "\trts pc\n");
357 fprintf (stream
, "\t;/* end of epilogue*/\n\n\n");
360 #endif /* !TWO_BSD */
362 /* Return the best assembler insn template
363 for moving operands[1] into operands[0] as a fullword. */
365 singlemove_string (operands
)
368 if (operands
[1] != const0_rtx
)
375 /* Output assembler code to perform a doubleword move insn
376 with operands OPERANDS. */
379 output_move_double (operands
)
382 enum { REGOP
, OFFSOP
, MEMOP
, PUSHOP
, POPOP
, CNSTOP
, RNDOP
} optype0
, optype1
;
384 rtx addreg0
= 0, addreg1
= 0;
386 /* First classify both operands. */
388 if (REG_P (operands
[0]))
390 else if (offsettable_memref_p (operands
[0]))
392 else if (GET_CODE (XEXP (operands
[0], 0)) == POST_INC
)
394 else if (GET_CODE (XEXP (operands
[0], 0)) == PRE_DEC
)
396 else if (GET_CODE (operands
[0]) == MEM
)
401 if (REG_P (operands
[1]))
403 else if (CONSTANT_P (operands
[1]))
405 || GET_CODE (operands
[1]) == CONST_DOUBLE
)
408 else if (offsettable_memref_p (operands
[1]))
410 else if (GET_CODE (XEXP (operands
[1], 0)) == POST_INC
)
412 else if (GET_CODE (XEXP (operands
[1], 0)) == PRE_DEC
)
414 else if (GET_CODE (operands
[1]) == MEM
)
419 /* Check for the cases that the operand constraints are not
420 supposed to allow to happen. Abort if we get one,
421 because generating code for these cases is painful. */
423 if (optype0
== RNDOP
|| optype1
== RNDOP
)
426 /* If one operand is decrementing and one is incrementing
427 decrement the former register explicitly
428 and change that operand into ordinary indexing. */
430 if (optype0
== PUSHOP
&& optype1
== POPOP
)
432 operands
[0] = XEXP (XEXP (operands
[0], 0), 0);
433 output_asm_insn ("sub $4,%0", operands
);
434 operands
[0] = gen_rtx_MEM (SImode
, operands
[0]);
437 if (optype0
== POPOP
&& optype1
== PUSHOP
)
439 operands
[1] = XEXP (XEXP (operands
[1], 0), 0);
440 output_asm_insn ("sub $4,%1", operands
);
441 operands
[1] = gen_rtx_MEM (SImode
, operands
[1]);
445 /* If an operand is an unoffsettable memory ref, find a register
446 we can increment temporarily to make it refer to the second word. */
448 if (optype0
== MEMOP
)
449 addreg0
= find_addr_reg (XEXP (operands
[0], 0));
451 if (optype1
== MEMOP
)
452 addreg1
= find_addr_reg (XEXP (operands
[1], 0));
454 /* Ok, we can do one word at a time.
455 Normally we do the low-numbered word first,
456 but if either operand is autodecrementing then we
457 do the high-numbered word first.
459 In either case, set up in LATEHALF the operands to use
460 for the high-numbered word and in some cases alter the
461 operands in OPERANDS to be suitable for the low-numbered word. */
463 if (optype0
== REGOP
)
464 latehalf
[0] = gen_rtx_REG (HImode
, REGNO (operands
[0]) + 1);
465 else if (optype0
== OFFSOP
)
466 latehalf
[0] = adjust_address (operands
[0], HImode
, 2);
468 latehalf
[0] = operands
[0];
470 if (optype1
== REGOP
)
471 latehalf
[1] = gen_rtx_REG (HImode
, REGNO (operands
[1]) + 1);
472 else if (optype1
== OFFSOP
)
473 latehalf
[1] = adjust_address (operands
[1], HImode
, 2);
474 else if (optype1
== CNSTOP
)
476 if (CONSTANT_P (operands
[1]))
478 /* now the mess begins, high word is in lower word???
480 that's what ashc makes me think, but I don't remember :-( */
481 latehalf
[1] = GEN_INT (INTVAL(operands
[1]) >> 16);
482 operands
[1] = GEN_INT (INTVAL(operands
[1]) & 0xff);
484 else if (GET_CODE (operands
[1]) == CONST_DOUBLE
)
486 /* immediate 32 bit values not allowed */
491 latehalf
[1] = operands
[1];
493 /* If insn is effectively movd N(sp),-(sp) then we will do the
494 high word first. We should use the adjusted operand 1 (which is N+4(sp))
495 for the low word as well, to compensate for the first decrement of sp. */
496 if (optype0
== PUSHOP
497 && REGNO (XEXP (XEXP (operands
[0], 0), 0)) == STACK_POINTER_REGNUM
498 && reg_overlap_mentioned_p (stack_pointer_rtx
, operands
[1]))
499 operands
[1] = latehalf
[1];
501 /* If one or both operands autodecrementing,
502 do the two words, high-numbered first. */
504 /* Likewise, the first move would clobber the source of the second one,
505 do them in the other order. This happens only for registers;
506 such overlap can't happen in memory unless the user explicitly
507 sets it up, and that is an undefined circumstance. */
509 if (optype0
== PUSHOP
|| optype1
== PUSHOP
510 || (optype0
== REGOP
&& optype1
== REGOP
511 && REGNO (operands
[0]) == REGNO (latehalf
[1])))
513 /* Make any unoffsettable addresses point at high-numbered word. */
515 output_asm_insn ("add $2,%0", &addreg0
);
517 output_asm_insn ("add $2,%0", &addreg1
);
520 output_asm_insn (singlemove_string (latehalf
), latehalf
);
522 /* Undo the adds we just did. */
524 output_asm_insn ("sub $2,%0", &addreg0
);
526 output_asm_insn ("sub $2,%0", &addreg1
);
528 /* Do low-numbered word. */
529 return singlemove_string (operands
);
532 /* Normal case: do the two words, low-numbered first. */
534 output_asm_insn (singlemove_string (operands
), operands
);
536 /* Make any unoffsettable addresses point at high-numbered word. */
538 output_asm_insn ("add $2,%0", &addreg0
);
540 output_asm_insn ("add $2,%0", &addreg1
);
543 output_asm_insn (singlemove_string (latehalf
), latehalf
);
545 /* Undo the adds we just did. */
547 output_asm_insn ("sub $2,%0", &addreg0
);
549 output_asm_insn ("sub $2,%0", &addreg1
);
553 /* Output assembler code to perform a quadword move insn
554 with operands OPERANDS. */
557 output_move_quad (operands
)
560 enum { REGOP
, OFFSOP
, MEMOP
, PUSHOP
, POPOP
, CNSTOP
, RNDOP
} optype0
, optype1
;
562 rtx addreg0
= 0, addreg1
= 0;
564 output_asm_insn(";; movdi/df: %1 -> %0", operands
);
566 if (REG_P (operands
[0]))
568 else if (offsettable_memref_p (operands
[0]))
570 else if (GET_CODE (XEXP (operands
[0], 0)) == POST_INC
)
572 else if (GET_CODE (XEXP (operands
[0], 0)) == PRE_DEC
)
574 else if (GET_CODE (operands
[0]) == MEM
)
579 if (REG_P (operands
[1]))
581 else if (CONSTANT_P (operands
[1])
582 || GET_CODE (operands
[1]) == CONST_DOUBLE
)
584 else if (offsettable_memref_p (operands
[1]))
586 else if (GET_CODE (XEXP (operands
[1], 0)) == POST_INC
)
588 else if (GET_CODE (XEXP (operands
[1], 0)) == PRE_DEC
)
590 else if (GET_CODE (operands
[1]) == MEM
)
595 /* Check for the cases that the operand constraints are not
596 supposed to allow to happen. Abort if we get one,
597 because generating code for these cases is painful. */
599 if (optype0
== RNDOP
|| optype1
== RNDOP
)
602 /* check if we move a CPU reg to an FPU reg, or vice versa! */
603 if (optype0
== REGOP
&& optype1
== REGOP
)
604 /* bogus - 64 bit cannot reside in CPU! */
605 if (CPU_REG_P(REGNO(operands
[0]))
606 || CPU_REG_P (REGNO(operands
[1])))
609 if (optype0
== REGOP
|| optype1
== REGOP
)
611 /* check for use of clrd????
612 if you ever allow ac4 and ac5 (now we require secondary load)
613 you must check whether
614 you want to load into them or store from them -
615 then dump ac0 into $help$ movce ac4/5 to ac0, do the
616 store from ac0, and restore ac0 - if you can find
617 an unused ac[0-3], use that and you save a store and a load!*/
619 if (FPU_REG_P(REGNO(operands
[0])))
621 if (GET_CODE(operands
[1]) == CONST_DOUBLE
)
623 union { double d
; int i
[2]; } u
;
624 u
.i
[0] = CONST_DOUBLE_LOW (operands
[1]);
625 u
.i
[1] = CONST_DOUBLE_HIGH (operands
[1]);
628 return "{clrd|clrf} %0";
631 return "{ldd|movf} %1, %0";
634 if (FPU_REG_P(REGNO(operands
[1])))
635 return "{std|movf} %1, %0";
638 /* If one operand is decrementing and one is incrementing
639 decrement the former register explicitly
640 and change that operand into ordinary indexing. */
642 if (optype0
== PUSHOP
&& optype1
== POPOP
)
644 operands
[0] = XEXP (XEXP (operands
[0], 0), 0);
645 output_asm_insn ("sub $8,%0", operands
);
646 operands
[0] = gen_rtx_MEM (DImode
, operands
[0]);
649 if (optype0
== POPOP
&& optype1
== PUSHOP
)
651 operands
[1] = XEXP (XEXP (operands
[1], 0), 0);
652 output_asm_insn ("sub $8,%1", operands
);
653 operands
[1] = gen_rtx_MEM (SImode
, operands
[1]);
657 /* If an operand is an unoffsettable memory ref, find a register
658 we can increment temporarily to make it refer to the second word. */
660 if (optype0
== MEMOP
)
661 addreg0
= find_addr_reg (XEXP (operands
[0], 0));
663 if (optype1
== MEMOP
)
664 addreg1
= find_addr_reg (XEXP (operands
[1], 0));
666 /* Ok, we can do one word at a time.
667 Normally we do the low-numbered word first,
668 but if either operand is autodecrementing then we
669 do the high-numbered word first.
671 In either case, set up in LATEHALF the operands to use
672 for the high-numbered word and in some cases alter the
673 operands in OPERANDS to be suitable for the low-numbered word. */
675 if (optype0
== REGOP
)
676 latehalf
[0] = gen_rtx_REG (SImode
, REGNO (operands
[0]) + 2);
677 else if (optype0
== OFFSOP
)
678 latehalf
[0] = adjust_address (operands
[0], SImode
, 4);
680 latehalf
[0] = operands
[0];
682 if (optype1
== REGOP
)
683 latehalf
[1] = gen_rtx_REG (SImode
, REGNO (operands
[1]) + 2);
684 else if (optype1
== OFFSOP
)
685 latehalf
[1] = adjust_address (operands
[1], SImode
, 4);
686 else if (optype1
== CNSTOP
)
688 if (GET_CODE (operands
[1]) == CONST_DOUBLE
)
690 /* floats only. not yet supported!
692 -- compute it into PDP float format, - internally,
693 just use IEEE and ignore possible problems ;-)
695 we might get away with it !!!! */
699 #ifndef HOST_WORDS_BIG_ENDIAN
700 latehalf
[1] = GEN_INT (CONST_DOUBLE_LOW (operands
[1]));
701 operands
[1] = GEN_INT (CONST_DOUBLE_HIGH (operands
[1]));
702 #else /* HOST_WORDS_BIG_ENDIAN */
703 latehalf
[1] = GEN_INT (CONST_DOUBLE_HIGH (operands
[1]));
704 operands
[1] = GEN_INT (CONST_DOUBLE_LOW (operands
[1]));
705 #endif /* HOST_WORDS_BIG_ENDIAN */
707 else if (GET_CODE(operands
[1]) == CONST_INT
)
709 latehalf
[1] = GEN_INT (0);
715 latehalf
[1] = operands
[1];
717 /* If insn is effectively movd N(sp),-(sp) then we will do the
718 high word first. We should use the adjusted operand 1 (which is N+4(sp))
719 for the low word as well, to compensate for the first decrement of sp. */
720 if (optype0
== PUSHOP
721 && REGNO (XEXP (XEXP (operands
[0], 0), 0)) == STACK_POINTER_REGNUM
722 && reg_overlap_mentioned_p (stack_pointer_rtx
, operands
[1]))
723 operands
[1] = latehalf
[1];
725 /* If one or both operands autodecrementing,
726 do the two words, high-numbered first. */
728 /* Likewise, the first move would clobber the source of the second one,
729 do them in the other order. This happens only for registers;
730 such overlap can't happen in memory unless the user explicitly
731 sets it up, and that is an undefined circumstance. */
733 if (optype0
== PUSHOP
|| optype1
== PUSHOP
734 || (optype0
== REGOP
&& optype1
== REGOP
735 && REGNO (operands
[0]) == REGNO (latehalf
[1])))
737 /* Make any unoffsettable addresses point at high-numbered word. */
739 output_asm_insn ("add $4,%0", &addreg0
);
741 output_asm_insn ("add $4,%0", &addreg1
);
744 output_asm_insn(output_move_double(latehalf
), latehalf
);
746 /* Undo the adds we just did. */
748 output_asm_insn ("sub $4,%0", &addreg0
);
750 output_asm_insn ("sub $4,%0", &addreg1
);
752 /* Do low-numbered word. */
753 return output_move_double (operands
);
756 /* Normal case: do the two words, low-numbered first. */
758 output_asm_insn (output_move_double (operands
), operands
);
760 /* Make any unoffsettable addresses point at high-numbered word. */
762 output_asm_insn ("add $4,%0", &addreg0
);
764 output_asm_insn ("add $4,%0", &addreg1
);
767 output_asm_insn (output_move_double (latehalf
), latehalf
);
769 /* Undo the adds we just did. */
771 output_asm_insn ("sub $4,%0", &addreg0
);
773 output_asm_insn ("sub $4,%0", &addreg1
);
779 /* Return a REG that occurs in ADDR with coefficient 1.
780 ADDR can be effectively incremented by incrementing REG. */
786 while (GET_CODE (addr
) == PLUS
)
788 if (GET_CODE (XEXP (addr
, 0)) == REG
)
789 addr
= XEXP (addr
, 0);
790 if (GET_CODE (XEXP (addr
, 1)) == REG
)
791 addr
= XEXP (addr
, 1);
792 if (CONSTANT_P (XEXP (addr
, 0)))
793 addr
= XEXP (addr
, 1);
794 if (CONSTANT_P (XEXP (addr
, 1)))
795 addr
= XEXP (addr
, 0);
797 if (GET_CODE (addr
) == REG
)
802 /* Output an ascii string. */
804 output_ascii (file
, p
, size
)
811 /* This used to output .byte "string", which doesn't work with the UNIX
812 assembler and I think not with DEC ones either. */
813 fprintf (file
, "\t.byte ");
815 for (i
= 0; i
< size
; i
++)
817 register int c
= p
[i
];
820 fprintf (file
, "%o", c
);
828 /* --- stole from out-vax, needs changes */
831 print_operand_address (file
, addr
)
835 register rtx reg1
, reg2
, breg
, ireg
;
840 switch (GET_CODE (addr
))
847 addr
= XEXP (addr
, 0);
851 fprintf (file
, "(%s)", reg_names
[REGNO (addr
)]);
855 fprintf (file
, "-(%s)", reg_names
[REGNO (XEXP (addr
, 0))]);
859 fprintf (file
, "(%s)+", reg_names
[REGNO (XEXP (addr
, 0))]);
866 if (CONSTANT_ADDRESS_P (XEXP (addr
, 0))
867 || GET_CODE (XEXP (addr
, 0)) == MEM
)
869 offset
= XEXP (addr
, 0);
870 addr
= XEXP (addr
, 1);
872 else if (CONSTANT_ADDRESS_P (XEXP (addr
, 1))
873 || GET_CODE (XEXP (addr
, 1)) == MEM
)
875 offset
= XEXP (addr
, 1);
876 addr
= XEXP (addr
, 0);
878 if (GET_CODE (addr
) != PLUS
)
880 else if (GET_CODE (XEXP (addr
, 0)) == MULT
)
882 reg1
= XEXP (addr
, 0);
883 addr
= XEXP (addr
, 1);
885 else if (GET_CODE (XEXP (addr
, 1)) == MULT
)
887 reg1
= XEXP (addr
, 1);
888 addr
= XEXP (addr
, 0);
890 else if (GET_CODE (XEXP (addr
, 0)) == REG
)
892 reg1
= XEXP (addr
, 0);
893 addr
= XEXP (addr
, 1);
895 else if (GET_CODE (XEXP (addr
, 1)) == REG
)
897 reg1
= XEXP (addr
, 1);
898 addr
= XEXP (addr
, 0);
900 if (GET_CODE (addr
) == REG
|| GET_CODE (addr
) == MULT
)
910 if (addr
!= 0) abort ();
913 if (reg1
!= 0 && GET_CODE (reg1
) == MULT
)
918 else if (reg2
!= 0 && GET_CODE (reg2
) == MULT
)
923 else if (reg2
!= 0 || GET_CODE (addr
) == MEM
)
934 output_address (addr
);
937 if (GET_CODE (breg
) != REG
)
939 fprintf (file
, "(%s)", reg_names
[REGNO (breg
)]);
943 if (GET_CODE (ireg
) == MULT
)
944 ireg
= XEXP (ireg
, 0);
945 if (GET_CODE (ireg
) != REG
)
948 fprintf (file
, "[%s]", reg_names
[REGNO (ireg
)]);
953 output_addr_const_pdp11 (file
, addr
);
957 /* Target hook to assemble integer objects. We need to use the
958 pdp-specific version of output_addr_const. */
961 pdp11_assemble_integer (x
, size
, aligned_p
)
970 fprintf (asm_out_file
, "\t.byte\t");
971 output_addr_const_pdp11 (asm_out_file
, x
);
972 fprintf (asm_out_file
, " /* char */\n");
976 fprintf (asm_out_file
, TARGET_UNIX_ASM
? "\t" : "\t.word\t");
977 output_addr_const_pdp11 (asm_out_file
, x
);
978 fprintf (asm_out_file
, " /* short */\n");
981 return default_assemble_integer (x
, size
, aligned_p
);
985 /* register move costs, indexed by regs */
987 static int move_costs
[N_REG_CLASSES
][N_REG_CLASSES
] =
989 /* NO MUL GEN LFPU NLFPU FPU ALL */
991 /* NO */ { 0, 0, 0, 0, 0, 0, 0},
992 /* MUL */ { 0, 2, 2, 10, 22, 22, 22},
993 /* GEN */ { 0, 2, 2, 10, 22, 22, 22},
994 /* LFPU */ { 0, 10, 10, 2, 2, 2, 10},
995 /* NLFPU */ { 0, 22, 22, 2, 2, 2, 22},
996 /* FPU */ { 0, 22, 22, 2, 2, 2, 22},
997 /* ALL */ { 0, 22, 22, 10, 22, 22, 22}
1001 /* -- note that some moves are tremendously expensive,
1002 because they require lots of tricks! do we have to
1003 charge the costs incurred by secondary reload class
1004 -- as we do here with 22 -- or not ? */
1007 register_move_cost(c1
, c2
)
1008 enum reg_class c1
, c2
;
1010 return move_costs
[(int)c1
][(int)c2
];
1014 output_jump(pos
, neg
, length
)
1015 const char *pos
, *neg
;
1020 static char buf
[1000];
1023 /* currently we don't need this, because the tstdf and cmpdf
1024 copy the condition code immediately, and other float operations are not
1025 yet recognized as changing the FCC - if so, then the length-cost of all
1026 jump insns increases by one, because we have to potentially copy the
1028 if (cc_status
.flags
& CC_IN_FPU
)
1029 output_asm_insn("cfcc", NULL
);
1037 strcat(buf
, " %l0");
1043 sprintf(buf
, "%s JMP_%d\n\tjmp %%l0\nJMP_%d:", neg
, x
, x
);
1057 notice_update_cc_on_set(exp
, insn
)
1059 rtx insn ATTRIBUTE_UNUSED
;
1061 if (GET_CODE (SET_DEST (exp
)) == CC0
)
1063 cc_status
.flags
= 0;
1064 cc_status
.value1
= SET_DEST (exp
);
1065 cc_status
.value2
= SET_SRC (exp
);
1068 if (GET_MODE(SET_SRC(exp)) == DFmode)
1069 cc_status.flags |= CC_IN_FPU;
1072 else if ((GET_CODE (SET_DEST (exp
)) == REG
1073 || GET_CODE (SET_DEST (exp
)) == MEM
)
1074 && GET_CODE (SET_SRC (exp
)) != PC
1075 && (GET_MODE (SET_DEST(exp
)) == HImode
1076 || GET_MODE (SET_DEST(exp
)) == QImode
)
1077 && (GET_CODE (SET_SRC(exp
)) == PLUS
1078 || GET_CODE (SET_SRC(exp
)) == MINUS
1079 || GET_CODE (SET_SRC(exp
)) == AND
1080 || GET_CODE (SET_SRC(exp
)) == IOR
1081 || GET_CODE (SET_SRC(exp
)) == XOR
1082 || GET_CODE (SET_SRC(exp
)) == NOT
1083 || GET_CODE (SET_SRC(exp
)) == NEG
1084 || GET_CODE (SET_SRC(exp
)) == REG
1085 || GET_CODE (SET_SRC(exp
)) == MEM
))
1087 cc_status
.flags
= 0;
1088 cc_status
.value1
= SET_SRC (exp
);
1089 cc_status
.value2
= SET_DEST (exp
);
1091 if (cc_status
.value1
&& GET_CODE (cc_status
.value1
) == REG
1093 && reg_overlap_mentioned_p (cc_status
.value1
, cc_status
.value2
))
1094 cc_status
.value2
= 0;
1095 if (cc_status
.value1
&& GET_CODE (cc_status
.value1
) == MEM
1097 && GET_CODE (cc_status
.value2
) == MEM
)
1098 cc_status
.value2
= 0;
1100 else if (GET_CODE (SET_SRC (exp
)) == CALL
)
1104 else if (GET_CODE (SET_DEST (exp
)) == REG
)
1107 if ((cc_status
.value1
1108 && reg_overlap_mentioned_p (SET_DEST (exp
), cc_status
.value1
)))
1109 cc_status
.value1
= 0;
1110 if ((cc_status
.value2
1111 && reg_overlap_mentioned_p (SET_DEST (exp
), cc_status
.value2
)))
1112 cc_status
.value2
= 0;
1114 else if (SET_DEST(exp
) == pc_rtx
)
1118 else /* if (GET_CODE (SET_DEST (exp)) == MEM) */
1120 /* the last else is a bit paranoiac, but since nearly all instructions
1121 play with condition codes, it's reasonable! */
1123 CC_STATUS_INIT
; /* paranoia*/
1129 simple_memory_operand(op
, mode
)
1131 enum machine_mode mode ATTRIBUTE_UNUSED
;
1135 /* Eliminate non-memory operations */
1136 if (GET_CODE (op
) != MEM
)
1140 /* dword operations really put out 2 instructions, so eliminate them. */
1141 if (GET_MODE_SIZE (GET_MODE (op
)) > (HAVE_64BIT_P () ? 8 : 4))
1145 /* Decode the address now. */
1149 addr
= XEXP (op
, 0);
1151 switch (GET_CODE (addr
))
1154 /* (R0) - no extra cost */
1159 /* -(R0), (R0)+ - cheap! */
1163 /* cheap - is encoded in addressing mode info!
1165 -- except for @(R0), which has to be @0(R0) !!! */
1167 if (GET_CODE (XEXP (addr
, 0)) == REG
)
1177 /* @#address - extra cost */
1181 /* X(R0) - extra cost */
1193 * output a block move:
1195 * operands[0] ... to
1196 * operands[1] ... from
1197 * operands[2] ... length
1198 * operands[3] ... alignment
1199 * operands[4] ... scratch register
1204 output_block_move(operands
)
1207 static int count
= 0;
1210 if (GET_CODE(operands
[2]) == CONST_INT
1213 if (INTVAL(operands
[2]) < 16
1214 && INTVAL(operands
[3]) == 1)
1218 for (i
= 1; i
<= INTVAL(operands
[2]); i
++)
1219 output_asm_insn("movb (%1)+, (%0)+", operands
);
1223 else if (INTVAL(operands
[2]) < 32)
1227 for (i
= 1; i
<= INTVAL(operands
[2])/2; i
++)
1228 output_asm_insn("mov (%1)+, (%0)+", operands
);
1230 /* may I assume that moved quantity is
1231 multiple of alignment ???
1240 /* can do other clever things, maybe... */
1243 if (CONSTANT_P(operands
[2]) )
1245 /* just move count to scratch */
1246 output_asm_insn("mov %2, %4", operands
);
1250 /* just clobber the register */
1251 operands
[4] = operands
[2];
1255 /* switch over alignment */
1256 switch (INTVAL(operands
[3]))
1272 sprintf(buf
, "\nmovestrhi%d:", count
);
1273 output_asm_insn(buf
, NULL
);
1275 output_asm_insn("movb (%1)+, (%0)+", operands
);
1279 sprintf(buf
, "sob %%4, movestrhi%d", count
);
1280 output_asm_insn(buf
, operands
);
1284 output_asm_insn("dec %4", operands
);
1286 sprintf(buf
, "bgt movestrhi%d", count
);
1287 output_asm_insn(buf
, NULL
);
1309 generate_compact_code
:
1311 output_asm_insn("asr %4", operands
);
1313 sprintf(buf
, "\nmovestrhi%d:", count
);
1314 output_asm_insn(buf
, NULL
);
1316 output_asm_insn("mov (%1)+, (%0)+", operands
);
1320 sprintf(buf
, "sob %%4, movestrhi%d", count
);
1321 output_asm_insn(buf
, operands
);
1325 output_asm_insn("dec %4", operands
);
1327 sprintf(buf
, "bgt movestrhi%d", count
);
1328 output_asm_insn(buf
, NULL
);
1354 goto generate_compact_code
;
1356 output_asm_insn("asr %4", operands
);
1357 output_asm_insn("asr %4", operands
);
1359 sprintf(buf
, "\nmovestrhi%d:", count
);
1360 output_asm_insn(buf
, NULL
);
1362 output_asm_insn("mov (%1)+, (%0)+", operands
);
1363 output_asm_insn("mov (%1)+, (%0)+", operands
);
1367 sprintf(buf
, "sob %%4, movestrhi%d", count
);
1368 output_asm_insn(buf
, operands
);
1372 output_asm_insn("dec %4", operands
);
1374 sprintf(buf
, "bgt movestrhi%d", count
);
1375 output_asm_insn(buf
, NULL
);
1405 goto generate_compact_code
;
1407 output_asm_insn("asr %4", operands
);
1408 output_asm_insn("asr %4", operands
);
1409 output_asm_insn("asr %4", operands
);
1411 sprintf(buf
, "\nmovestrhi%d:", count
);
1412 output_asm_insn(buf
, NULL
);
1414 output_asm_insn("mov (%1)+, (%0)+", operands
);
1415 output_asm_insn("mov (%1)+, (%0)+", operands
);
1416 output_asm_insn("mov (%1)+, (%0)+", operands
);
1417 output_asm_insn("mov (%1)+, (%0)+", operands
);
1421 sprintf(buf
, "sob %%4, movestrhi%d", count
);
1422 output_asm_insn(buf
, operands
);
1426 output_asm_insn("dec %4", operands
);
1428 sprintf(buf
, "bgt movestrhi%d", count
);
1429 output_asm_insn(buf
, NULL
);
1442 /* for future use */
1444 comparison_operator_index(op
)
1447 switch (GET_CODE(op
))
1484 /* tests whether the rtx is a comparison operator */
1486 comp_operator (op
, mode
)
1488 enum machine_mode mode ATTRIBUTE_UNUSED
;
1490 return comparison_operator_index(op
) >= 0;
1495 legitimate_address_p (mode
, address
)
1496 enum machine_mode mode
;
1499 /* #define REG_OK_STRICT */
1500 GO_IF_LEGITIMATE_ADDRESS(mode
, address
, win
);
1507 /* #undef REG_OK_STRICT */
1510 /* A copy of output_addr_const modified for pdp11 expression syntax.
1511 output_addr_const also gets called for %cDIGIT and %nDIGIT, which we don't
1512 use, and for debugging output, which we don't support with this port either.
1513 So this copy should get called whenever needed.
1516 output_addr_const_pdp11 (file
, x
)
1523 switch (GET_CODE (x
))
1533 assemble_name (file
, XSTR (x
, 0));
1537 ASM_GENERATE_INTERNAL_LABEL (buf
, "L", CODE_LABEL_NUMBER (XEXP (x
, 0)));
1538 assemble_name (file
, buf
);
1542 ASM_GENERATE_INTERNAL_LABEL (buf
, "L", CODE_LABEL_NUMBER (x
));
1543 assemble_name (file
, buf
);
1547 /* Should we check for constants which are too big? Maybe cutting
1548 them off to 16 bits is OK? */
1549 fprintf (file
, "%ho", (unsigned short) INTVAL (x
));
1553 /* This used to output parentheses around the expression,
1554 but that does not work on the 386 (either ATT or BSD assembler). */
1555 output_addr_const_pdp11 (file
, XEXP (x
, 0));
1559 if (GET_MODE (x
) == VOIDmode
)
1561 /* We can use %o if the number is one word and positive. */
1562 if (CONST_DOUBLE_HIGH (x
))
1563 abort (); /* Should we just silently drop the high part? */
1565 fprintf (file
, "%ho", (unsigned short) CONST_DOUBLE_LOW (x
));
1568 /* We can't handle floating point constants;
1569 PRINT_OPERAND must handle them. */
1570 output_operand_lossage ("floating constant misused");
1574 /* Some assemblers need integer constants to appear last (eg masm). */
1575 if (GET_CODE (XEXP (x
, 0)) == CONST_INT
)
1577 output_addr_const_pdp11 (file
, XEXP (x
, 1));
1578 if (INTVAL (XEXP (x
, 0)) >= 0)
1579 fprintf (file
, "+");
1580 output_addr_const_pdp11 (file
, XEXP (x
, 0));
1584 output_addr_const_pdp11 (file
, XEXP (x
, 0));
1585 if (INTVAL (XEXP (x
, 1)) >= 0)
1586 fprintf (file
, "+");
1587 output_addr_const_pdp11 (file
, XEXP (x
, 1));
1592 /* Avoid outputting things like x-x or x+5-x,
1593 since some assemblers can't handle that. */
1594 x
= simplify_subtraction (x
);
1595 if (GET_CODE (x
) != MINUS
)
1598 output_addr_const_pdp11 (file
, XEXP (x
, 0));
1599 fprintf (file
, "-");
1600 if (GET_CODE (XEXP (x
, 1)) == CONST_INT
1601 && INTVAL (XEXP (x
, 1)) < 0)
1603 fprintf (file
, targetm
.asm_out
.open_paren
);
1604 output_addr_const_pdp11 (file
, XEXP (x
, 1));
1605 fprintf (file
, targetm
.asm_out
.close_paren
);
1608 output_addr_const_pdp11 (file
, XEXP (x
, 1));
1613 output_addr_const_pdp11 (file
, XEXP (x
, 0));
1617 output_operand_lossage ("invalid expression as operand");