Daily bump.
[official-gcc.git] / gcc / config / pdp11 / pdp11.c
blob505456550bd72a0e0b718e6e593564f7b64aeaef
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)
11 any later version.
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. */
23 #include "config.h"
24 #include "system.h"
25 #include "rtl.h"
26 #include "regs.h"
27 #include "hard-reg-set.h"
28 #include "real.h"
29 #include "insn-config.h"
30 #include "conditions.h"
31 #include "function.h"
32 #include "output.h"
33 #include "insn-attr.h"
34 #include "flags.h"
35 #include "recog.h"
36 #include "tree.h"
37 #include "expr.h"
38 #include "toplev.h"
39 #include "tm_p.h"
40 #include "target.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
49 defined in tm.h */
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. */
85 int
86 arith_operand (op, mode)
87 rtx op;
88 enum machine_mode mode;
90 return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
93 int
94 const_immediate_operand (op, mode)
95 rtx op;
96 enum machine_mode mode ATTRIBUTE_UNUSED;
98 return (GET_CODE (op) == CONST_INT);
101 int
102 immediate15_operand (op, mode)
103 rtx op;
104 enum machine_mode mode ATTRIBUTE_UNUSED;
106 return (GET_CODE (op) == CONST_INT && ((INTVAL (op) & 0x8000) == 0x0000));
110 expand_shift_operand (op, mode)
111 rtx op;
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.
128 #ifdef TWO_BSD
130 static void
131 pdp11_output_function_prologue (stream, size)
132 FILE *stream;
133 HOST_WIDE_INT size;
135 fprintf (stream, "\tjsr r5, csv\n");
136 if (size)
138 fprintf (stream, "\t/*abuse empty parameter slot for locals!*/\n");
139 if (size > 2)
140 fprintf(stream, "\tsub $%d, sp\n", size - 2);
145 #else /* !TWO_BSD */
147 static void
148 pdp11_output_function_prologue (stream, size)
149 FILE *stream;
150 HOST_WIDE_INT size;
152 HOST_WIDE_INT fsize = ((size) + 1) & ~1;
153 int regno;
154 int via_ac = -1;
156 fprintf (stream,
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)
163 fprintf(stream,
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");
174 else
176 /* DON'T SAVE FP */
179 /* make frame */
180 if (fsize)
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 */
192 via_ac = -1;
194 for (regno = 8; regno < FIRST_PSEUDO_REGISTER ; regno++)
196 /* ac0 - ac3 */
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]);
202 via_ac = regno;
205 /* maybe make ac4, ac5 call used regs?? */
206 /* ac4 - ac5 */
207 if (NO_LOAD_FPU_REG_P(regno)
208 && regs_ever_live[regno]
209 && ! call_used_regs[regno])
211 if (via_ac == -1)
212 abort();
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
228 before returning. */
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? */
243 #ifdef TWO_BSD
245 static void
246 pdp11_output_function_epilogue (stream, size)
247 FILE *stream;
248 HOST_WIDE_INT size ATTRIBUTE_UNUSED;
250 fprintf (stream, "\t/* SP ignored by cret? */\n");
251 fprintf (stream, "\tjmp cret\n");
254 #else /* !TWO_BSD */
256 static void
257 pdp11_output_function_epilogue (stream, size)
258 FILE *stream;
259 HOST_WIDE_INT size;
261 HOST_WIDE_INT fsize = ((size) + 1) & ~1;
262 int i, j, k;
264 int via_ac;
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])
275 j++;
277 /* remember # of pushed bytes for CPU regs */
278 k = 2*j;
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]);
284 /* get ACs */
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])
290 via_ac = i;
291 k += 8;
294 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
296 if (LOAD_FPU_REG_P(i)
297 && regs_ever_live[i]
298 && ! call_used_regs[i])
300 fprintf(stream, "\tfldd %o(fp), %s\n", -fsize-k, reg_names[i]);
301 k -= 8;
304 if (NO_LOAD_FPU_REG_P(i)
305 && regs_ever_live[i]
306 && ! call_used_regs[i])
308 if (! LOAD_FPU_REG_P(via_ac))
309 abort();
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]);
313 k -= 8;
317 fprintf(stream, "\tmov fp, sp\n");
318 fprintf (stream, "\tmov (sp)+, fp\n");
320 else
322 via_ac = FIRST_PSEUDO_REGISTER -1;
324 /* get ACs */
325 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
326 if (regs_ever_live[i] && call_used_regs[i])
327 via_ac = i;
329 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
331 if (LOAD_FPU_REG_P(i)
332 && regs_ever_live[i]
333 && ! call_used_regs[i])
334 fprintf(stream, "\tfldd (sp)+, %s\n", reg_names[i]);
336 if (NO_LOAD_FPU_REG_P(i)
337 && regs_ever_live[i]
338 && ! call_used_regs[i])
340 if (! LOAD_FPU_REG_P(via_ac))
341 abort();
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]);
352 if (fsize)
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. */
364 static const char *
365 singlemove_string (operands)
366 rtx *operands;
368 if (operands[1] != const0_rtx)
369 return "mov %1,%0";
371 return "clr %0";
375 /* Output assembler code to perform a doubleword move insn
376 with operands OPERANDS. */
378 const char *
379 output_move_double (operands)
380 rtx *operands;
382 enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
383 rtx latehalf[2];
384 rtx addreg0 = 0, addreg1 = 0;
386 /* First classify both operands. */
388 if (REG_P (operands[0]))
389 optype0 = REGOP;
390 else if (offsettable_memref_p (operands[0]))
391 optype0 = OFFSOP;
392 else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
393 optype0 = POPOP;
394 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
395 optype0 = PUSHOP;
396 else if (GET_CODE (operands[0]) == MEM)
397 optype0 = MEMOP;
398 else
399 optype0 = RNDOP;
401 if (REG_P (operands[1]))
402 optype1 = REGOP;
403 else if (CONSTANT_P (operands[1]))
404 #if 0
405 || GET_CODE (operands[1]) == CONST_DOUBLE)
406 #endif
407 optype1 = CNSTOP;
408 else if (offsettable_memref_p (operands[1]))
409 optype1 = OFFSOP;
410 else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
411 optype1 = POPOP;
412 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
413 optype1 = PUSHOP;
414 else if (GET_CODE (operands[1]) == MEM)
415 optype1 = MEMOP;
416 else
417 optype1 = RNDOP;
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)
424 abort ();
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]);
435 optype0 = OFFSOP;
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]);
442 optype1 = OFFSOP;
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);
467 else
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 */
487 abort();
490 else
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. */
514 if (addreg0)
515 output_asm_insn ("add $2,%0", &addreg0);
516 if (addreg1)
517 output_asm_insn ("add $2,%0", &addreg1);
519 /* Do that word. */
520 output_asm_insn (singlemove_string (latehalf), latehalf);
522 /* Undo the adds we just did. */
523 if (addreg0)
524 output_asm_insn ("sub $2,%0", &addreg0);
525 if (addreg1)
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. */
537 if (addreg0)
538 output_asm_insn ("add $2,%0", &addreg0);
539 if (addreg1)
540 output_asm_insn ("add $2,%0", &addreg1);
542 /* Do that word. */
543 output_asm_insn (singlemove_string (latehalf), latehalf);
545 /* Undo the adds we just did. */
546 if (addreg0)
547 output_asm_insn ("sub $2,%0", &addreg0);
548 if (addreg1)
549 output_asm_insn ("sub $2,%0", &addreg1);
551 return "";
553 /* Output assembler code to perform a quadword move insn
554 with operands OPERANDS. */
556 const char *
557 output_move_quad (operands)
558 rtx *operands;
560 enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
561 rtx latehalf[2];
562 rtx addreg0 = 0, addreg1 = 0;
564 output_asm_insn(";; movdi/df: %1 -> %0", operands);
566 if (REG_P (operands[0]))
567 optype0 = REGOP;
568 else if (offsettable_memref_p (operands[0]))
569 optype0 = OFFSOP;
570 else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
571 optype0 = POPOP;
572 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
573 optype0 = PUSHOP;
574 else if (GET_CODE (operands[0]) == MEM)
575 optype0 = MEMOP;
576 else
577 optype0 = RNDOP;
579 if (REG_P (operands[1]))
580 optype1 = REGOP;
581 else if (CONSTANT_P (operands[1])
582 || GET_CODE (operands[1]) == CONST_DOUBLE)
583 optype1 = CNSTOP;
584 else if (offsettable_memref_p (operands[1]))
585 optype1 = OFFSOP;
586 else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
587 optype1 = POPOP;
588 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
589 optype1 = PUSHOP;
590 else if (GET_CODE (operands[1]) == MEM)
591 optype1 = MEMOP;
592 else
593 optype1 = RNDOP;
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)
600 abort ();
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])))
607 abort();
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]);
627 if (u.d == 0.0)
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]);
647 optype0 = OFFSOP;
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]);
654 optype1 = OFFSOP;
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);
679 else
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 !!!! */
697 abort();
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);
711 else
712 abort();
714 else
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. */
738 if (addreg0)
739 output_asm_insn ("add $4,%0", &addreg0);
740 if (addreg1)
741 output_asm_insn ("add $4,%0", &addreg1);
743 /* Do that word. */
744 output_asm_insn(output_move_double(latehalf), latehalf);
746 /* Undo the adds we just did. */
747 if (addreg0)
748 output_asm_insn ("sub $4,%0", &addreg0);
749 if (addreg1)
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. */
761 if (addreg0)
762 output_asm_insn ("add $4,%0", &addreg0);
763 if (addreg1)
764 output_asm_insn ("add $4,%0", &addreg1);
766 /* Do that word. */
767 output_asm_insn (output_move_double (latehalf), latehalf);
769 /* Undo the adds we just did. */
770 if (addreg0)
771 output_asm_insn ("sub $4,%0", &addreg0);
772 if (addreg1)
773 output_asm_insn ("sub $4,%0", &addreg1);
775 return "";
779 /* Return a REG that occurs in ADDR with coefficient 1.
780 ADDR can be effectively incremented by incrementing REG. */
782 static rtx
783 find_addr_reg (addr)
784 rtx addr;
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)
798 return addr;
799 return 0;
802 /* Output an ascii string. */
803 void
804 output_ascii (file, p, size)
805 FILE *file;
806 const char *p;
807 int size;
809 int i;
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];
818 if (c < 0)
819 c += 256;
820 fprintf (file, "%o", c);
821 if (i < size - 1)
822 putc (',', file);
824 putc ('\n', file);
828 /* --- stole from out-vax, needs changes */
830 void
831 print_operand_address (file, addr)
832 FILE *file;
833 register rtx addr;
835 register rtx reg1, reg2, breg, ireg;
836 rtx offset;
838 retry:
840 switch (GET_CODE (addr))
842 case MEM:
843 if (TARGET_UNIX_ASM)
844 fprintf (file, "*");
845 else
846 fprintf (file, "@");
847 addr = XEXP (addr, 0);
848 goto retry;
850 case REG:
851 fprintf (file, "(%s)", reg_names[REGNO (addr)]);
852 break;
854 case PRE_DEC:
855 fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]);
856 break;
858 case POST_INC:
859 fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]);
860 break;
862 case PLUS:
863 reg1 = 0; reg2 = 0;
864 ireg = 0; breg = 0;
865 offset = 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)
902 if (reg1 == 0)
903 reg1 = addr;
904 else
905 reg2 = addr;
906 addr = 0;
908 if (offset != 0)
910 if (addr != 0) abort ();
911 addr = offset;
913 if (reg1 != 0 && GET_CODE (reg1) == MULT)
915 breg = reg2;
916 ireg = reg1;
918 else if (reg2 != 0 && GET_CODE (reg2) == MULT)
920 breg = reg1;
921 ireg = reg2;
923 else if (reg2 != 0 || GET_CODE (addr) == MEM)
925 breg = reg2;
926 ireg = reg1;
928 else
930 breg = reg1;
931 ireg = reg2;
933 if (addr != 0)
934 output_address (addr);
935 if (breg != 0)
937 if (GET_CODE (breg) != REG)
938 abort ();
939 fprintf (file, "(%s)", reg_names[REGNO (breg)]);
941 if (ireg != 0)
943 if (GET_CODE (ireg) == MULT)
944 ireg = XEXP (ireg, 0);
945 if (GET_CODE (ireg) != REG)
946 abort ();
947 abort();
948 fprintf (file, "[%s]", reg_names[REGNO (ireg)]);
950 break;
952 default:
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. */
960 static bool
961 pdp11_assemble_integer (x, size, aligned_p)
962 rtx x;
963 unsigned int size;
964 int aligned_p;
966 if (aligned_p)
967 switch (size)
969 case 1:
970 fprintf (asm_out_file, "\t.byte\t");
971 output_addr_const_pdp11 (asm_out_file, x);
972 fprintf (asm_out_file, " /* char */\n");
973 return true;
975 case 2:
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");
979 return true;
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 ? */
1006 int
1007 register_move_cost(c1, c2)
1008 enum reg_class c1, c2;
1010 return move_costs[(int)c1][(int)c2];
1013 const char *
1014 output_jump(pos, neg, length)
1015 const char *pos, *neg;
1016 int length;
1018 static int x = 0;
1020 static char buf[1000];
1022 #if 0
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
1027 FCC! */
1028 if (cc_status.flags & CC_IN_FPU)
1029 output_asm_insn("cfcc", NULL);
1030 #endif
1032 switch (length)
1034 case 1:
1036 strcpy(buf, pos);
1037 strcat(buf, " %l0");
1039 return buf;
1041 case 3:
1043 sprintf(buf, "%s JMP_%d\n\tjmp %%l0\nJMP_%d:", neg, x, x);
1045 x++;
1047 return buf;
1049 default:
1051 abort();
1056 void
1057 notice_update_cc_on_set(exp, insn)
1058 rtx exp;
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
1092 && cc_status.value2
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
1096 && cc_status.value2
1097 && GET_CODE (cc_status.value2) == MEM)
1098 cc_status.value2 = 0;
1100 else if (GET_CODE (SET_SRC (exp)) == CALL)
1102 CC_STATUS_INIT;
1104 else if (GET_CODE (SET_DEST (exp)) == REG)
1105 /* what's this ? */
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)
1116 /* jump */
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)
1130 rtx op;
1131 enum machine_mode mode ATTRIBUTE_UNUSED;
1133 rtx addr;
1135 /* Eliminate non-memory operations */
1136 if (GET_CODE (op) != MEM)
1137 return FALSE;
1139 #if 0
1140 /* dword operations really put out 2 instructions, so eliminate them. */
1141 if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4))
1142 return FALSE;
1143 #endif
1145 /* Decode the address now. */
1147 indirection:
1149 addr = XEXP (op, 0);
1151 switch (GET_CODE (addr))
1153 case REG:
1154 /* (R0) - no extra cost */
1155 return 1;
1157 case PRE_DEC:
1158 case POST_INC:
1159 /* -(R0), (R0)+ - cheap! */
1160 return 0;
1162 case MEM:
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)
1168 return 0;
1170 op=addr;
1171 goto indirection;
1173 case CONST_INT:
1174 case LABEL_REF:
1175 case CONST:
1176 case SYMBOL_REF:
1177 /* @#address - extra cost */
1178 return 0;
1180 case PLUS:
1181 /* X(R0) - extra cost */
1182 return 0;
1184 default:
1185 break;
1188 return FALSE;
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
1203 const char *
1204 output_block_move(operands)
1205 rtx *operands;
1207 static int count = 0;
1208 char buf[200];
1210 if (GET_CODE(operands[2]) == CONST_INT
1211 && ! optimize_size)
1213 if (INTVAL(operands[2]) < 16
1214 && INTVAL(operands[3]) == 1)
1216 register int i;
1218 for (i = 1; i <= INTVAL(operands[2]); i++)
1219 output_asm_insn("movb (%1)+, (%0)+", operands);
1221 return "";
1223 else if (INTVAL(operands[2]) < 32)
1225 register int i;
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 ???
1233 I HOPE SO !
1236 return "";
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);
1248 else
1250 /* just clobber the register */
1251 operands[4] = operands[2];
1255 /* switch over alignment */
1256 switch (INTVAL(operands[3]))
1258 case 1:
1262 movb (%1)+, (%0)+
1264 if (TARGET_45)
1265 sob %4,x
1266 else
1267 dec %4
1268 bgt x
1272 sprintf(buf, "\nmovestrhi%d:", count);
1273 output_asm_insn(buf, NULL);
1275 output_asm_insn("movb (%1)+, (%0)+", operands);
1277 if (TARGET_45)
1279 sprintf(buf, "sob %%4, movestrhi%d", count);
1280 output_asm_insn(buf, operands);
1282 else
1284 output_asm_insn("dec %4", operands);
1286 sprintf(buf, "bgt movestrhi%d", count);
1287 output_asm_insn(buf, NULL);
1290 count ++;
1291 break;
1293 case 2:
1296 asr %4
1300 mov (%1)+, (%0)+
1302 if (TARGET_45)
1303 sob %4, x
1304 else
1305 dec %4
1306 bgt x
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);
1318 if (TARGET_45)
1320 sprintf(buf, "sob %%4, movestrhi%d", count);
1321 output_asm_insn(buf, operands);
1323 else
1325 output_asm_insn("dec %4", operands);
1327 sprintf(buf, "bgt movestrhi%d", count);
1328 output_asm_insn(buf, NULL);
1331 count ++;
1332 break;
1334 case 4:
1338 asr %4
1339 asr %4
1343 mov (%1)+, (%0)+
1344 mov (%1)+, (%0)+
1346 if (TARGET_45)
1347 sob %4, x
1348 else
1349 dec %4
1350 bgt x
1353 if (optimize_size)
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);
1365 if (TARGET_45)
1367 sprintf(buf, "sob %%4, movestrhi%d", count);
1368 output_asm_insn(buf, operands);
1370 else
1372 output_asm_insn("dec %4", operands);
1374 sprintf(buf, "bgt movestrhi%d", count);
1375 output_asm_insn(buf, NULL);
1378 count ++;
1379 break;
1381 default:
1385 asr %4
1386 asr %4
1387 asr %4
1391 mov (%1)+, (%0)+
1392 mov (%1)+, (%0)+
1393 mov (%1)+, (%0)+
1394 mov (%1)+, (%0)+
1396 if (TARGET_45)
1397 sob %4, x
1398 else
1399 dec %4
1400 bgt x
1404 if (optimize_size)
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);
1419 if (TARGET_45)
1421 sprintf(buf, "sob %%4, movestrhi%d", count);
1422 output_asm_insn(buf, operands);
1424 else
1426 output_asm_insn("dec %4", operands);
1428 sprintf(buf, "bgt movestrhi%d", count);
1429 output_asm_insn(buf, NULL);
1432 count ++;
1433 break;
1439 return "";
1442 /* for future use */
1444 comparison_operator_index(op)
1445 rtx op;
1447 switch (GET_CODE(op))
1449 case NE:
1450 return 0;
1452 case EQ:
1453 return 1;
1455 case GE:
1456 return 2;
1458 case GT:
1459 return 3;
1461 case LE:
1462 return 4;
1464 case LT:
1465 return 5;
1467 case GEU:
1468 return 6;
1470 case GTU:
1471 return 7;
1473 case LEU:
1474 return 8;
1476 case LTU:
1477 return 9;
1479 default:
1480 return -1;
1484 /* tests whether the rtx is a comparison operator */
1486 comp_operator (op, mode)
1487 rtx op;
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;
1497 rtx address;
1499 /* #define REG_OK_STRICT */
1500 GO_IF_LEGITIMATE_ADDRESS(mode, address, win);
1502 return 0;
1504 win:
1505 return 1;
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.
1515 void
1516 output_addr_const_pdp11 (file, x)
1517 FILE *file;
1518 rtx x;
1520 char buf[256];
1522 restart:
1523 switch (GET_CODE (x))
1525 case PC:
1526 if (flag_pic)
1527 putc ('.', file);
1528 else
1529 abort ();
1530 break;
1532 case SYMBOL_REF:
1533 assemble_name (file, XSTR (x, 0));
1534 break;
1536 case LABEL_REF:
1537 ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
1538 assemble_name (file, buf);
1539 break;
1541 case CODE_LABEL:
1542 ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
1543 assemble_name (file, buf);
1544 break;
1546 case CONST_INT:
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));
1550 break;
1552 case CONST:
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));
1556 break;
1558 case CONST_DOUBLE:
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? */
1564 else
1565 fprintf (file, "%ho", (unsigned short) CONST_DOUBLE_LOW (x));
1567 else
1568 /* We can't handle floating point constants;
1569 PRINT_OPERAND must handle them. */
1570 output_operand_lossage ("floating constant misused");
1571 break;
1573 case PLUS:
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));
1582 else
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));
1589 break;
1591 case MINUS:
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)
1596 goto restart;
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);
1607 else
1608 output_addr_const_pdp11 (file, XEXP (x, 1));
1609 break;
1611 case ZERO_EXTEND:
1612 case SIGN_EXTEND:
1613 output_addr_const_pdp11 (file, XEXP (x, 0));
1614 break;
1616 default:
1617 output_operand_lossage ("invalid expression as operand");