2003-12-26 Guilhem Lavaux <guilhem@kaffe.org>
[official-gcc.git] / gcc / config / pdp11 / pdp11.c
blob02565432cda80035cf96850fbeeba1076d4e30fc
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 GCC.
8 GCC 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 GCC 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 GCC; 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 "coretypes.h"
26 #include "tm.h"
27 #include "rtl.h"
28 #include "regs.h"
29 #include "hard-reg-set.h"
30 #include "real.h"
31 #include "insn-config.h"
32 #include "conditions.h"
33 #include "function.h"
34 #include "output.h"
35 #include "insn-attr.h"
36 #include "flags.h"
37 #include "recog.h"
38 #include "tree.h"
39 #include "expr.h"
40 #include "toplev.h"
41 #include "tm_p.h"
42 #include "target.h"
43 #include "target-def.h"
46 #define FPU_REG_P(X) ((X)>=8 && (X)<14)
47 #define CPU_REG_P(X) ((X)>=0 && (X)<8)
50 /* this is the current value returned by the macro FIRST_PARM_OFFSET
51 defined in tm.h */
52 int current_first_parm_offset;
54 /* This is where the condition code register lives. */
55 /* rtx cc0_reg_rtx; - no longer needed? */
57 static rtx find_addr_reg (rtx);
58 static const char *singlemove_string (rtx *);
59 static bool pdp11_assemble_integer (rtx, unsigned int, int);
60 static void pdp11_output_function_prologue (FILE *, HOST_WIDE_INT);
61 static void pdp11_output_function_epilogue (FILE *, HOST_WIDE_INT);
62 static bool pdp11_rtx_costs (rtx, int, int, int *);
64 /* Initialize the GCC target structure. */
65 #undef TARGET_ASM_BYTE_OP
66 #define TARGET_ASM_BYTE_OP NULL
67 #undef TARGET_ASM_ALIGNED_HI_OP
68 #define TARGET_ASM_ALIGNED_HI_OP NULL
69 #undef TARGET_ASM_ALIGNED_SI_OP
70 #define TARGET_ASM_ALIGNED_SI_OP NULL
71 #undef TARGET_ASM_INTEGER
72 #define TARGET_ASM_INTEGER pdp11_assemble_integer
74 #undef TARGET_ASM_FUNCTION_PROLOGUE
75 #define TARGET_ASM_FUNCTION_PROLOGUE pdp11_output_function_prologue
76 #undef TARGET_ASM_FUNCTION_EPILOGUE
77 #define TARGET_ASM_FUNCTION_EPILOGUE pdp11_output_function_epilogue
79 #undef TARGET_ASM_OPEN_PAREN
80 #define TARGET_ASM_OPEN_PAREN "["
81 #undef TARGET_ASM_CLOSE_PAREN
82 #define TARGET_ASM_CLOSE_PAREN "]"
84 #undef TARGET_RTX_COSTS
85 #define TARGET_RTX_COSTS pdp11_rtx_costs
87 struct gcc_target targetm = TARGET_INITIALIZER;
89 /* Nonzero if OP is a valid second operand for an arithmetic insn. */
91 int
92 arith_operand (rtx op, enum machine_mode mode)
94 return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
97 int
98 const_immediate_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
100 return (GET_CODE (op) == CONST_INT);
103 int
104 immediate15_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
106 return (GET_CODE (op) == CONST_INT && ((INTVAL (op) & 0x8000) == 0x0000));
110 expand_shift_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
112 return (GET_CODE (op) == CONST_INT
113 && abs (INTVAL(op)) > 1
114 && abs (INTVAL(op)) <= 4);
118 stream is a stdio stream to output the code to.
119 size is an int: how many units of temporary storage to allocate.
120 Refer to the array `regs_ever_live' to determine which registers
121 to save; `regs_ever_live[I]' is nonzero if register number I
122 is ever used in the function. This macro is responsible for
123 knowing which registers should not be saved even if used.
126 #ifdef TWO_BSD
128 static void
129 pdp11_output_function_prologue (FILE *stream, HOST_WIDE_INT size)
131 fprintf (stream, "\tjsr r5, csv\n");
132 if (size)
134 fprintf (stream, "\t/*abuse empty parameter slot for locals!*/\n");
135 if (size > 2)
136 fprintf(stream, "\tsub $%#o, sp\n", size - 2);
141 #else /* !TWO_BSD */
143 static void
144 pdp11_output_function_prologue (FILE *stream, HOST_WIDE_INT size)
146 HOST_WIDE_INT fsize = ((size) + 1) & ~1;
147 int regno;
148 int via_ac = -1;
150 fprintf (stream,
151 "\n\t; /* function prologue %s*/\n", current_function_name);
153 /* if we are outputting code for main,
154 the switch FPU to right mode if TARGET_FPU */
155 if (MAIN_NAME_P (DECL_NAME (current_function_decl)) && TARGET_FPU)
157 fprintf(stream,
158 "\t;/* switch cpu to double float, single integer */\n");
159 fprintf(stream, "\tsetd\n");
160 fprintf(stream, "\tseti\n\n");
163 if (frame_pointer_needed)
165 fprintf(stream, "\tmov r5, -(sp)\n");
166 fprintf(stream, "\tmov sp, r5\n");
168 else
170 /* DON'T SAVE FP */
173 /* make frame */
174 if (fsize)
175 fprintf (stream, "\tsub $%#o, sp\n", fsize);
177 /* save CPU registers */
178 for (regno = 0; regno < 8; regno++)
179 if (regs_ever_live[regno] && ! call_used_regs[regno])
180 if (! ((regno == FRAME_POINTER_REGNUM)
181 && frame_pointer_needed))
182 fprintf (stream, "\tmov %s, -(sp)\n", reg_names[regno]);
183 /* fpu regs saving */
185 /* via_ac specifies the ac to use for saving ac4, ac5 */
186 via_ac = -1;
188 for (regno = 8; regno < FIRST_PSEUDO_REGISTER ; regno++)
190 /* ac0 - ac3 */
191 if (LOAD_FPU_REG_P(regno)
192 && regs_ever_live[regno]
193 && ! call_used_regs[regno])
195 fprintf (stream, "\tstd %s, -(sp)\n", reg_names[regno]);
196 via_ac = regno;
199 /* maybe make ac4, ac5 call used regs?? */
200 /* ac4 - ac5 */
201 if (NO_LOAD_FPU_REG_P(regno)
202 && regs_ever_live[regno]
203 && ! call_used_regs[regno])
205 if (via_ac == -1)
206 abort();
208 fprintf (stream, "\tldd %s, %s\n", reg_names[regno], reg_names[via_ac]);
209 fprintf (stream, "\tstd %s, -(sp)\n", reg_names[via_ac]);
213 fprintf (stream, "\t;/* end of prologue */\n\n");
216 #endif /* !TWO_BSD */
219 The function epilogue should not depend on the current stack pointer!
220 It should use the frame pointer only. This is mandatory because
221 of alloca; we also take advantage of it to omit stack adjustments
222 before returning. */
224 /* maybe we can make leaf functions faster by switching to the
225 second register file - this way we don't have to save regs!
226 leaf functions are ~ 50% of all functions (dynamically!)
228 set/clear bit 11 (dec. 2048) of status word for switching register files -
229 but how can we do this? the pdp11/45 manual says bit may only
230 be set (p.24), but not cleared!
232 switching to kernel is probably more expensive, so we'll leave it
233 like this and not use the second set of registers...
235 maybe as option if you want to generate code for kernel mode? */
237 #ifdef TWO_BSD
239 static void
240 pdp11_output_function_epilogue (FILE *stream,
241 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
243 fprintf (stream, "\t/* SP ignored by cret? */\n");
244 fprintf (stream, "\tjmp cret\n");
247 #else /* !TWO_BSD */
249 static void
250 pdp11_output_function_epilogue (FILE *stream, HOST_WIDE_INT size)
252 HOST_WIDE_INT fsize = ((size) + 1) & ~1;
253 int i, j, k;
255 int via_ac;
257 fprintf (stream, "\n\t; /*function epilogue */\n");
259 if (frame_pointer_needed)
261 /* hope this is safe - m68k does it also .... */
262 regs_ever_live[FRAME_POINTER_REGNUM] = 0;
264 for (i =7, j = 0 ; i >= 0 ; i--)
265 if (regs_ever_live[i] && ! call_used_regs[i])
266 j++;
268 /* remember # of pushed bytes for CPU regs */
269 k = 2*j;
271 /* change fp -> r5 due to the compile error on libgcc2.c */
272 for (i =7 ; i >= 0 ; i--)
273 if (regs_ever_live[i] && ! call_used_regs[i])
274 fprintf(stream, "\tmov %#o(r5), %s\n",(-fsize-2*j--)&0xffff, reg_names[i]);
276 /* get ACs */
277 via_ac = FIRST_PSEUDO_REGISTER -1;
279 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
280 if (regs_ever_live[i] && ! call_used_regs[i])
282 via_ac = i;
283 k += 8;
286 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
288 if (LOAD_FPU_REG_P(i)
289 && regs_ever_live[i]
290 && ! call_used_regs[i])
292 fprintf(stream, "\tldd %#o(r5), %s\n", (-fsize-k)&0xffff, reg_names[i]);
293 k -= 8;
296 if (NO_LOAD_FPU_REG_P(i)
297 && regs_ever_live[i]
298 && ! call_used_regs[i])
300 if (! LOAD_FPU_REG_P(via_ac))
301 abort();
303 fprintf(stream, "\tldd %#o(r5), %s\n", (-fsize-k)&0xffff, reg_names[via_ac]);
304 fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]);
305 k -= 8;
309 fprintf(stream, "\tmov r5, sp\n");
310 fprintf (stream, "\tmov (sp)+, r5\n");
312 else
314 via_ac = FIRST_PSEUDO_REGISTER -1;
316 /* get ACs */
317 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
318 if (regs_ever_live[i] && call_used_regs[i])
319 via_ac = i;
321 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
323 if (LOAD_FPU_REG_P(i)
324 && regs_ever_live[i]
325 && ! call_used_regs[i])
326 fprintf(stream, "\tldd (sp)+, %s\n", reg_names[i]);
328 if (NO_LOAD_FPU_REG_P(i)
329 && regs_ever_live[i]
330 && ! call_used_regs[i])
332 if (! LOAD_FPU_REG_P(via_ac))
333 abort();
335 fprintf(stream, "\tldd (sp)+, %s\n", reg_names[via_ac]);
336 fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]);
340 for (i=7; i >= 0; i--)
341 if (regs_ever_live[i] && !call_used_regs[i])
342 fprintf(stream, "\tmov (sp)+, %s\n", reg_names[i]);
344 if (fsize)
345 fprintf((stream), "\tadd $%#o, sp\n", (fsize)&0xffff);
348 fprintf (stream, "\trts pc\n");
349 fprintf (stream, "\t;/* end of epilogue*/\n\n\n");
352 #endif /* !TWO_BSD */
354 /* Return the best assembler insn template
355 for moving operands[1] into operands[0] as a fullword. */
356 static const char *
357 singlemove_string (rtx *operands)
359 if (operands[1] != const0_rtx)
360 return "mov %1,%0";
362 return "clr %0";
366 /* Output assembler code to perform a doubleword move insn
367 with operands OPERANDS. */
369 const char *
370 output_move_double (rtx *operands)
372 enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
373 rtx latehalf[2];
374 rtx addreg0 = 0, addreg1 = 0;
376 /* First classify both operands. */
378 if (REG_P (operands[0]))
379 optype0 = REGOP;
380 else if (offsettable_memref_p (operands[0]))
381 optype0 = OFFSOP;
382 else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
383 optype0 = POPOP;
384 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
385 optype0 = PUSHOP;
386 else if (GET_CODE (operands[0]) == MEM)
387 optype0 = MEMOP;
388 else
389 optype0 = RNDOP;
391 if (REG_P (operands[1]))
392 optype1 = REGOP;
393 else if (CONSTANT_P (operands[1])
394 #if 0
395 || GET_CODE (operands[1]) == CONST_DOUBLE
396 #endif
398 optype1 = CNSTOP;
399 else if (offsettable_memref_p (operands[1]))
400 optype1 = OFFSOP;
401 else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
402 optype1 = POPOP;
403 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
404 optype1 = PUSHOP;
405 else if (GET_CODE (operands[1]) == MEM)
406 optype1 = MEMOP;
407 else
408 optype1 = RNDOP;
410 /* Check for the cases that the operand constraints are not
411 supposed to allow to happen. Abort if we get one,
412 because generating code for these cases is painful. */
414 if (optype0 == RNDOP || optype1 == RNDOP)
415 abort ();
417 /* If one operand is decrementing and one is incrementing
418 decrement the former register explicitly
419 and change that operand into ordinary indexing. */
421 if (optype0 == PUSHOP && optype1 == POPOP)
423 operands[0] = XEXP (XEXP (operands[0], 0), 0);
424 output_asm_insn ("sub $4,%0", operands);
425 operands[0] = gen_rtx_MEM (SImode, operands[0]);
426 optype0 = OFFSOP;
428 if (optype0 == POPOP && optype1 == PUSHOP)
430 operands[1] = XEXP (XEXP (operands[1], 0), 0);
431 output_asm_insn ("sub $4,%1", operands);
432 operands[1] = gen_rtx_MEM (SImode, operands[1]);
433 optype1 = OFFSOP;
436 /* If an operand is an unoffsettable memory ref, find a register
437 we can increment temporarily to make it refer to the second word. */
439 if (optype0 == MEMOP)
440 addreg0 = find_addr_reg (XEXP (operands[0], 0));
442 if (optype1 == MEMOP)
443 addreg1 = find_addr_reg (XEXP (operands[1], 0));
445 /* Ok, we can do one word at a time.
446 Normally we do the low-numbered word first,
447 but if either operand is autodecrementing then we
448 do the high-numbered word first.
450 In either case, set up in LATEHALF the operands to use
451 for the high-numbered word and in some cases alter the
452 operands in OPERANDS to be suitable for the low-numbered word. */
454 if (optype0 == REGOP)
455 latehalf[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1);
456 else if (optype0 == OFFSOP)
457 latehalf[0] = adjust_address (operands[0], HImode, 2);
458 else
459 latehalf[0] = operands[0];
461 if (optype1 == REGOP)
462 latehalf[1] = gen_rtx_REG (HImode, REGNO (operands[1]) + 1);
463 else if (optype1 == OFFSOP)
464 latehalf[1] = adjust_address (operands[1], HImode, 2);
465 else if (optype1 == CNSTOP)
467 if (CONSTANT_P (operands[1]))
469 /* now the mess begins, high word is in lower word???
471 that's what ashc makes me think, but I don't remember :-( */
472 latehalf[1] = GEN_INT (INTVAL(operands[1]) >> 16);
473 operands[1] = GEN_INT (INTVAL(operands[1]) & 0xff);
475 else if (GET_CODE (operands[1]) == CONST_DOUBLE)
477 /* immediate 32 bit values not allowed */
478 abort();
481 else
482 latehalf[1] = operands[1];
484 /* If insn is effectively movd N(sp),-(sp) then we will do the
485 high word first. We should use the adjusted operand 1 (which is N+4(sp))
486 for the low word as well, to compensate for the first decrement of sp. */
487 if (optype0 == PUSHOP
488 && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
489 && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
490 operands[1] = latehalf[1];
492 /* If one or both operands autodecrementing,
493 do the two words, high-numbered first. */
495 /* Likewise, the first move would clobber the source of the second one,
496 do them in the other order. This happens only for registers;
497 such overlap can't happen in memory unless the user explicitly
498 sets it up, and that is an undefined circumstance. */
500 if (optype0 == PUSHOP || optype1 == PUSHOP
501 || (optype0 == REGOP && optype1 == REGOP
502 && REGNO (operands[0]) == REGNO (latehalf[1])))
504 /* Make any unoffsettable addresses point at high-numbered word. */
505 if (addreg0)
506 output_asm_insn ("add $2,%0", &addreg0);
507 if (addreg1)
508 output_asm_insn ("add $2,%0", &addreg1);
510 /* Do that word. */
511 output_asm_insn (singlemove_string (latehalf), latehalf);
513 /* Undo the adds we just did. */
514 if (addreg0)
515 output_asm_insn ("sub $2,%0", &addreg0);
516 if (addreg1)
517 output_asm_insn ("sub $2,%0", &addreg1);
519 /* Do low-numbered word. */
520 return singlemove_string (operands);
523 /* Normal case: do the two words, low-numbered first. */
525 output_asm_insn (singlemove_string (operands), operands);
527 /* Make any unoffsettable addresses point at high-numbered word. */
528 if (addreg0)
529 output_asm_insn ("add $2,%0", &addreg0);
530 if (addreg1)
531 output_asm_insn ("add $2,%0", &addreg1);
533 /* Do that word. */
534 output_asm_insn (singlemove_string (latehalf), latehalf);
536 /* Undo the adds we just did. */
537 if (addreg0)
538 output_asm_insn ("sub $2,%0", &addreg0);
539 if (addreg1)
540 output_asm_insn ("sub $2,%0", &addreg1);
542 return "";
544 /* Output assembler code to perform a quadword move insn
545 with operands OPERANDS. */
547 const char *
548 output_move_quad (rtx *operands)
550 enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
551 rtx latehalf[2];
552 rtx addreg0 = 0, addreg1 = 0;
554 output_asm_insn(";/* movdi/df: %1 -> %0 */", operands);
556 if (REG_P (operands[0]))
557 optype0 = REGOP;
558 else if (offsettable_memref_p (operands[0]))
559 optype0 = OFFSOP;
560 else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
561 optype0 = POPOP;
562 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
563 optype0 = PUSHOP;
564 else if (GET_CODE (operands[0]) == MEM)
565 optype0 = MEMOP;
566 else
567 optype0 = RNDOP;
569 if (REG_P (operands[1]))
570 optype1 = REGOP;
571 else if (CONSTANT_P (operands[1])
572 || GET_CODE (operands[1]) == CONST_DOUBLE)
573 optype1 = CNSTOP;
574 else if (offsettable_memref_p (operands[1]))
575 optype1 = OFFSOP;
576 else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
577 optype1 = POPOP;
578 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
579 optype1 = PUSHOP;
580 else if (GET_CODE (operands[1]) == MEM)
581 optype1 = MEMOP;
582 else
583 optype1 = RNDOP;
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)
590 abort ();
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])))
597 abort();
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 REAL_VALUE_TYPE r;
614 REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
616 if (REAL_VALUES_EQUAL (r, dconst0))
617 return "{clrd|clrf} %0";
620 return "{ldd|movf} %1, %0";
623 if (FPU_REG_P(REGNO(operands[1])))
624 return "{std|movf} %1, %0";
627 /* If one operand is decrementing and one is incrementing
628 decrement the former register explicitly
629 and change that operand into ordinary indexing. */
631 if (optype0 == PUSHOP && optype1 == POPOP)
633 operands[0] = XEXP (XEXP (operands[0], 0), 0);
634 output_asm_insn ("sub $8,%0", operands);
635 operands[0] = gen_rtx_MEM (DImode, operands[0]);
636 optype0 = OFFSOP;
638 if (optype0 == POPOP && optype1 == PUSHOP)
640 operands[1] = XEXP (XEXP (operands[1], 0), 0);
641 output_asm_insn ("sub $8,%1", operands);
642 operands[1] = gen_rtx_MEM (SImode, operands[1]);
643 optype1 = OFFSOP;
646 /* If an operand is an unoffsettable memory ref, find a register
647 we can increment temporarily to make it refer to the second word. */
649 if (optype0 == MEMOP)
650 addreg0 = find_addr_reg (XEXP (operands[0], 0));
652 if (optype1 == MEMOP)
653 addreg1 = find_addr_reg (XEXP (operands[1], 0));
655 /* Ok, we can do one word at a time.
656 Normally we do the low-numbered word first,
657 but if either operand is autodecrementing then we
658 do the high-numbered word first.
660 In either case, set up in LATEHALF the operands to use
661 for the high-numbered word and in some cases alter the
662 operands in OPERANDS to be suitable for the low-numbered word. */
664 if (optype0 == REGOP)
665 latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2);
666 else if (optype0 == OFFSOP)
667 latehalf[0] = adjust_address (operands[0], SImode, 4);
668 else
669 latehalf[0] = operands[0];
671 if (optype1 == REGOP)
672 latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2);
673 else if (optype1 == OFFSOP)
674 latehalf[1] = adjust_address (operands[1], SImode, 4);
675 else if (optype1 == CNSTOP)
677 if (GET_CODE (operands[1]) == CONST_DOUBLE)
679 /* floats only. not yet supported!
681 -- compute it into PDP float format, - internally,
682 just use IEEE and ignore possible problems ;-)
684 we might get away with it !!!! */
686 abort();
688 #ifndef HOST_WORDS_BIG_ENDIAN
689 latehalf[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
690 operands[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
691 #else /* HOST_WORDS_BIG_ENDIAN */
692 latehalf[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
693 operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
694 #endif /* HOST_WORDS_BIG_ENDIAN */
696 else if (GET_CODE(operands[1]) == CONST_INT)
698 latehalf[1] = GEN_INT (0);
700 else
701 abort();
703 else
704 latehalf[1] = operands[1];
706 /* If insn is effectively movd N(sp),-(sp) then we will do the
707 high word first. We should use the adjusted operand 1 (which is N+4(sp))
708 for the low word as well, to compensate for the first decrement of sp. */
709 if (optype0 == PUSHOP
710 && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
711 && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
712 operands[1] = latehalf[1];
714 /* If one or both operands autodecrementing,
715 do the two words, high-numbered first. */
717 /* Likewise, the first move would clobber the source of the second one,
718 do them in the other order. This happens only for registers;
719 such overlap can't happen in memory unless the user explicitly
720 sets it up, and that is an undefined circumstance. */
722 if (optype0 == PUSHOP || optype1 == PUSHOP
723 || (optype0 == REGOP && optype1 == REGOP
724 && REGNO (operands[0]) == REGNO (latehalf[1])))
726 /* Make any unoffsettable addresses point at high-numbered word. */
727 if (addreg0)
728 output_asm_insn ("add $4,%0", &addreg0);
729 if (addreg1)
730 output_asm_insn ("add $4,%0", &addreg1);
732 /* Do that word. */
733 output_asm_insn(output_move_double(latehalf), latehalf);
735 /* Undo the adds we just did. */
736 if (addreg0)
737 output_asm_insn ("sub $4,%0", &addreg0);
738 if (addreg1)
739 output_asm_insn ("sub $4,%0", &addreg1);
741 /* Do low-numbered word. */
742 return output_move_double (operands);
745 /* Normal case: do the two words, low-numbered first. */
747 output_asm_insn (output_move_double (operands), operands);
749 /* Make any unoffsettable addresses point at high-numbered word. */
750 if (addreg0)
751 output_asm_insn ("add $4,%0", &addreg0);
752 if (addreg1)
753 output_asm_insn ("add $4,%0", &addreg1);
755 /* Do that word. */
756 output_asm_insn (output_move_double (latehalf), latehalf);
758 /* Undo the adds we just did. */
759 if (addreg0)
760 output_asm_insn ("sub $4,%0", &addreg0);
761 if (addreg1)
762 output_asm_insn ("sub $4,%0", &addreg1);
764 return "";
768 /* Return a REG that occurs in ADDR with coefficient 1.
769 ADDR can be effectively incremented by incrementing REG. */
771 static rtx
772 find_addr_reg (rtx addr)
774 while (GET_CODE (addr) == PLUS)
776 if (GET_CODE (XEXP (addr, 0)) == REG)
777 addr = XEXP (addr, 0);
778 if (GET_CODE (XEXP (addr, 1)) == REG)
779 addr = XEXP (addr, 1);
780 if (CONSTANT_P (XEXP (addr, 0)))
781 addr = XEXP (addr, 1);
782 if (CONSTANT_P (XEXP (addr, 1)))
783 addr = XEXP (addr, 0);
785 if (GET_CODE (addr) == REG)
786 return addr;
787 return 0;
790 /* Output an ascii string. */
791 void
792 output_ascii (FILE *file, const char *p, int size)
794 int i;
796 /* This used to output .byte "string", which doesn't work with the UNIX
797 assembler and I think not with DEC ones either. */
798 fprintf (file, "\t.byte ");
800 for (i = 0; i < size; i++)
802 register int c = p[i];
803 if (c < 0)
804 c += 256;
805 fprintf (file, "%#o", c);
806 if (i < size - 1)
807 putc (',', file);
809 putc ('\n', file);
813 /* --- stole from out-vax, needs changes */
815 void
816 print_operand_address (FILE *file, register rtx addr)
818 register rtx reg1, reg2, breg, ireg;
819 rtx offset;
821 retry:
823 switch (GET_CODE (addr))
825 case MEM:
826 if (TARGET_UNIX_ASM)
827 fprintf (file, "*");
828 else
829 fprintf (file, "@");
830 addr = XEXP (addr, 0);
831 goto retry;
833 case REG:
834 fprintf (file, "(%s)", reg_names[REGNO (addr)]);
835 break;
837 case PRE_MODIFY:
838 case PRE_DEC:
839 fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]);
840 break;
842 case POST_MODIFY:
843 case POST_INC:
844 fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]);
845 break;
847 case PLUS:
848 reg1 = 0; reg2 = 0;
849 ireg = 0; breg = 0;
850 offset = 0;
851 if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
852 || GET_CODE (XEXP (addr, 0)) == MEM)
854 offset = XEXP (addr, 0);
855 addr = XEXP (addr, 1);
857 else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
858 || GET_CODE (XEXP (addr, 1)) == MEM)
860 offset = XEXP (addr, 1);
861 addr = XEXP (addr, 0);
863 if (GET_CODE (addr) != PLUS)
865 else if (GET_CODE (XEXP (addr, 0)) == MULT)
867 reg1 = XEXP (addr, 0);
868 addr = XEXP (addr, 1);
870 else if (GET_CODE (XEXP (addr, 1)) == MULT)
872 reg1 = XEXP (addr, 1);
873 addr = XEXP (addr, 0);
875 else if (GET_CODE (XEXP (addr, 0)) == REG)
877 reg1 = XEXP (addr, 0);
878 addr = XEXP (addr, 1);
880 else if (GET_CODE (XEXP (addr, 1)) == REG)
882 reg1 = XEXP (addr, 1);
883 addr = XEXP (addr, 0);
885 if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
887 if (reg1 == 0)
888 reg1 = addr;
889 else
890 reg2 = addr;
891 addr = 0;
893 if (offset != 0)
895 if (addr != 0) abort ();
896 addr = offset;
898 if (reg1 != 0 && GET_CODE (reg1) == MULT)
900 breg = reg2;
901 ireg = reg1;
903 else if (reg2 != 0 && GET_CODE (reg2) == MULT)
905 breg = reg1;
906 ireg = reg2;
908 else if (reg2 != 0 || GET_CODE (addr) == MEM)
910 breg = reg2;
911 ireg = reg1;
913 else
915 breg = reg1;
916 ireg = reg2;
918 if (addr != 0)
919 output_address (addr);
920 if (breg != 0)
922 if (GET_CODE (breg) != REG)
923 abort ();
924 fprintf (file, "(%s)", reg_names[REGNO (breg)]);
926 if (ireg != 0)
928 if (GET_CODE (ireg) == MULT)
929 ireg = XEXP (ireg, 0);
930 if (GET_CODE (ireg) != REG)
931 abort ();
932 abort();
933 fprintf (file, "[%s]", reg_names[REGNO (ireg)]);
935 break;
937 default:
938 output_addr_const_pdp11 (file, addr);
942 /* Target hook to assemble integer objects. We need to use the
943 pdp-specific version of output_addr_const. */
945 static bool
946 pdp11_assemble_integer (rtx x, unsigned int size, int aligned_p)
948 if (aligned_p)
949 switch (size)
951 case 1:
952 fprintf (asm_out_file, "\t.byte\t");
953 output_addr_const_pdp11 (asm_out_file, x);
954 fprintf (asm_out_file, " /* char */\n");
955 return true;
957 case 2:
958 fprintf (asm_out_file, TARGET_UNIX_ASM ? "\t" : "\t.word\t");
959 output_addr_const_pdp11 (asm_out_file, x);
960 fprintf (asm_out_file, " /* short */\n");
961 return true;
963 return default_assemble_integer (x, size, aligned_p);
967 /* register move costs, indexed by regs */
969 static const int move_costs[N_REG_CLASSES][N_REG_CLASSES] =
971 /* NO MUL GEN LFPU NLFPU FPU ALL */
973 /* NO */ { 0, 0, 0, 0, 0, 0, 0},
974 /* MUL */ { 0, 2, 2, 10, 22, 22, 22},
975 /* GEN */ { 0, 2, 2, 10, 22, 22, 22},
976 /* LFPU */ { 0, 10, 10, 2, 2, 2, 10},
977 /* NLFPU */ { 0, 22, 22, 2, 2, 2, 22},
978 /* FPU */ { 0, 22, 22, 2, 2, 2, 22},
979 /* ALL */ { 0, 22, 22, 10, 22, 22, 22}
983 /* -- note that some moves are tremendously expensive,
984 because they require lots of tricks! do we have to
985 charge the costs incurred by secondary reload class
986 -- as we do here with 22 -- or not ? */
988 int
989 register_move_cost(c1, c2)
990 enum reg_class c1, c2;
992 return move_costs[(int)c1][(int)c2];
995 static bool
996 pdp11_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
998 switch (code)
1000 case CONST_INT:
1001 if (INTVAL (x) == 0 || INTVAL (x) == -1 || INTVAL (x) == 1)
1003 *total = 0;
1004 return true;
1006 /* FALLTHRU */
1008 case CONST:
1009 case LABEL_REF:
1010 case SYMBOL_REF:
1011 /* Twice as expensive as REG. */
1012 *total = 2;
1013 return true;
1015 case CONST_DOUBLE:
1016 /* Twice (or 4 times) as expensive as 16 bit. */
1017 *total = 4;
1018 return true;
1020 case MULT:
1021 /* ??? There is something wrong in MULT because MULT is not
1022 as cheap as total = 2 even if we can shift! */
1023 /* If optimizing for size make mult etc cheap, but not 1, so when
1024 in doubt the faster insn is chosen. */
1025 if (optimize_size)
1026 *total = COSTS_N_INSNS (2);
1027 else
1028 *total = COSTS_N_INSNS (11);
1029 return false;
1031 case DIV:
1032 if (optimize_size)
1033 *total = COSTS_N_INSNS (2);
1034 else
1035 *total = COSTS_N_INSNS (25);
1036 return false;
1038 case MOD:
1039 if (optimize_size)
1040 *total = COSTS_N_INSNS (2);
1041 else
1042 *total = COSTS_N_INSNS (26);
1043 return false;
1045 case ABS:
1046 /* Equivalent to length, so same for optimize_size. */
1047 *total = COSTS_N_INSNS (3);
1048 return false;
1050 case ZERO_EXTEND:
1051 /* Only used for qi->hi. */
1052 *total = COSTS_N_INSNS (1);
1053 return false;
1055 case SIGN_EXTEND:
1056 if (GET_MODE (x) == HImode)
1057 *total = COSTS_N_INSNS (1);
1058 else if (GET_MODE (x) == SImode)
1059 *total = COSTS_N_INSNS (6);
1060 else
1061 *total = COSTS_N_INSNS (2);
1062 return false;
1064 case ASHIFT:
1065 case LSHIFTRT:
1066 case ASHIFTRT:
1067 if (optimize_size)
1068 *total = COSTS_N_INSNS (1);
1069 else if (GET_MODE (x) == QImode)
1071 if (GET_CODE (XEXP (x, 1)) != CONST_INT)
1072 *total = COSTS_N_INSNS (8); /* worst case */
1073 else
1074 *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1)));
1076 else if (GET_MODE (x) == HImode)
1078 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
1080 if (abs (INTVAL (XEXP (x, 1))) == 1)
1081 *total = COSTS_N_INSNS (1);
1082 else
1083 *total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1)));
1085 else
1086 *total = COSTS_N_INSNS (10); /* worst case */
1088 else if (GET_MODE (x) == SImode)
1090 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
1091 *total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1)));
1092 else /* worst case */
1093 *total = COSTS_N_INSNS (18);
1095 return false;
1097 default:
1098 return false;
1102 const char *
1103 output_jump(const char *pos, const char *neg, int length)
1105 static int x = 0;
1107 static char buf[1000];
1109 #if 0
1110 /* currently we don't need this, because the tstdf and cmpdf
1111 copy the condition code immediately, and other float operations are not
1112 yet recognized as changing the FCC - if so, then the length-cost of all
1113 jump insns increases by one, because we have to potentially copy the
1114 FCC! */
1115 if (cc_status.flags & CC_IN_FPU)
1116 output_asm_insn("cfcc", NULL);
1117 #endif
1119 switch (length)
1121 case 1:
1123 strcpy(buf, pos);
1124 strcat(buf, " %l0");
1126 return buf;
1128 case 3:
1130 sprintf(buf, "%s JMP_%d\n\tjmp %%l0\nJMP_%d:", neg, x, x);
1132 x++;
1134 return buf;
1136 default:
1138 abort();
1143 void
1144 notice_update_cc_on_set(rtx exp, rtx insn ATTRIBUTE_UNUSED)
1146 if (GET_CODE (SET_DEST (exp)) == CC0)
1148 cc_status.flags = 0;
1149 cc_status.value1 = SET_DEST (exp);
1150 cc_status.value2 = SET_SRC (exp);
1153 if (GET_MODE(SET_SRC(exp)) == DFmode)
1154 cc_status.flags |= CC_IN_FPU;
1157 else if ((GET_CODE (SET_DEST (exp)) == REG
1158 || GET_CODE (SET_DEST (exp)) == MEM)
1159 && GET_CODE (SET_SRC (exp)) != PC
1160 && (GET_MODE (SET_DEST(exp)) == HImode
1161 || GET_MODE (SET_DEST(exp)) == QImode)
1162 && (GET_CODE (SET_SRC(exp)) == PLUS
1163 || GET_CODE (SET_SRC(exp)) == MINUS
1164 || GET_CODE (SET_SRC(exp)) == AND
1165 || GET_CODE (SET_SRC(exp)) == IOR
1166 || GET_CODE (SET_SRC(exp)) == XOR
1167 || GET_CODE (SET_SRC(exp)) == NOT
1168 || GET_CODE (SET_SRC(exp)) == NEG
1169 || GET_CODE (SET_SRC(exp)) == REG
1170 || GET_CODE (SET_SRC(exp)) == MEM))
1172 cc_status.flags = 0;
1173 cc_status.value1 = SET_SRC (exp);
1174 cc_status.value2 = SET_DEST (exp);
1176 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
1177 && cc_status.value2
1178 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
1179 cc_status.value2 = 0;
1180 if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM
1181 && cc_status.value2
1182 && GET_CODE (cc_status.value2) == MEM)
1183 cc_status.value2 = 0;
1185 else if (GET_CODE (SET_SRC (exp)) == CALL)
1187 CC_STATUS_INIT;
1189 else if (GET_CODE (SET_DEST (exp)) == REG)
1190 /* what's this ? */
1192 if ((cc_status.value1
1193 && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1)))
1194 cc_status.value1 = 0;
1195 if ((cc_status.value2
1196 && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2)))
1197 cc_status.value2 = 0;
1199 else if (SET_DEST(exp) == pc_rtx)
1201 /* jump */
1203 else /* if (GET_CODE (SET_DEST (exp)) == MEM) */
1205 /* the last else is a bit paranoiac, but since nearly all instructions
1206 play with condition codes, it's reasonable! */
1208 CC_STATUS_INIT; /* paranoia*/
1214 simple_memory_operand(rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1216 rtx addr;
1218 /* Eliminate non-memory operations */
1219 if (GET_CODE (op) != MEM)
1220 return FALSE;
1222 #if 0
1223 /* dword operations really put out 2 instructions, so eliminate them. */
1224 if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4))
1225 return FALSE;
1226 #endif
1228 /* Decode the address now. */
1230 indirection:
1232 addr = XEXP (op, 0);
1234 switch (GET_CODE (addr))
1236 case REG:
1237 /* (R0) - no extra cost */
1238 return 1;
1240 case PRE_DEC:
1241 case POST_INC:
1242 /* -(R0), (R0)+ - cheap! */
1243 return 0;
1245 case MEM:
1246 /* cheap - is encoded in addressing mode info!
1248 -- except for @(R0), which has to be @0(R0) !!! */
1250 if (GET_CODE (XEXP (addr, 0)) == REG)
1251 return 0;
1253 op=addr;
1254 goto indirection;
1256 case CONST_INT:
1257 case LABEL_REF:
1258 case CONST:
1259 case SYMBOL_REF:
1260 /* @#address - extra cost */
1261 return 0;
1263 case PLUS:
1264 /* X(R0) - extra cost */
1265 return 0;
1267 default:
1268 break;
1271 return FALSE;
1276 * output a block move:
1278 * operands[0] ... to
1279 * operands[1] ... from
1280 * operands[2] ... length
1281 * operands[3] ... alignment
1282 * operands[4] ... scratch register
1286 const char *
1287 output_block_move(rtx *operands)
1289 static int count = 0;
1290 char buf[200];
1292 if (GET_CODE(operands[2]) == CONST_INT
1293 && ! optimize_size)
1295 if (INTVAL(operands[2]) < 16
1296 && INTVAL(operands[3]) == 1)
1298 register int i;
1300 for (i = 1; i <= INTVAL(operands[2]); i++)
1301 output_asm_insn("movb (%1)+, (%0)+", operands);
1303 return "";
1305 else if (INTVAL(operands[2]) < 32)
1307 register int i;
1309 for (i = 1; i <= INTVAL(operands[2])/2; i++)
1310 output_asm_insn("mov (%1)+, (%0)+", operands);
1312 /* may I assume that moved quantity is
1313 multiple of alignment ???
1315 I HOPE SO !
1318 return "";
1322 /* can do other clever things, maybe... */
1325 if (CONSTANT_P(operands[2]) )
1327 /* just move count to scratch */
1328 output_asm_insn("mov %2, %4", operands);
1330 else
1332 /* just clobber the register */
1333 operands[4] = operands[2];
1337 /* switch over alignment */
1338 switch (INTVAL(operands[3]))
1340 case 1:
1344 movb (%1)+, (%0)+
1346 if (TARGET_45)
1347 sob %4,x
1348 else
1349 dec %4
1350 bgt x
1354 sprintf(buf, "\nmovestrhi%d:", count);
1355 output_asm_insn(buf, NULL);
1357 output_asm_insn("movb (%1)+, (%0)+", operands);
1359 if (TARGET_45)
1361 sprintf(buf, "sob %%4, movestrhi%d", count);
1362 output_asm_insn(buf, operands);
1364 else
1366 output_asm_insn("dec %4", operands);
1368 sprintf(buf, "bgt movestrhi%d", count);
1369 output_asm_insn(buf, NULL);
1372 count ++;
1373 break;
1375 case 2:
1378 asr %4
1382 mov (%1)+, (%0)+
1384 if (TARGET_45)
1385 sob %4, x
1386 else
1387 dec %4
1388 bgt x
1391 generate_compact_code:
1393 output_asm_insn("asr %4", operands);
1395 sprintf(buf, "\nmovestrhi%d:", count);
1396 output_asm_insn(buf, NULL);
1398 output_asm_insn("mov (%1)+, (%0)+", operands);
1400 if (TARGET_45)
1402 sprintf(buf, "sob %%4, movestrhi%d", count);
1403 output_asm_insn(buf, operands);
1405 else
1407 output_asm_insn("dec %4", operands);
1409 sprintf(buf, "bgt movestrhi%d", count);
1410 output_asm_insn(buf, NULL);
1413 count ++;
1414 break;
1416 case 4:
1420 asr %4
1421 asr %4
1425 mov (%1)+, (%0)+
1426 mov (%1)+, (%0)+
1428 if (TARGET_45)
1429 sob %4, x
1430 else
1431 dec %4
1432 bgt x
1435 if (optimize_size)
1436 goto generate_compact_code;
1438 output_asm_insn("asr %4", operands);
1439 output_asm_insn("asr %4", operands);
1441 sprintf(buf, "\nmovestrhi%d:", count);
1442 output_asm_insn(buf, NULL);
1444 output_asm_insn("mov (%1)+, (%0)+", operands);
1445 output_asm_insn("mov (%1)+, (%0)+", operands);
1447 if (TARGET_45)
1449 sprintf(buf, "sob %%4, movestrhi%d", count);
1450 output_asm_insn(buf, operands);
1452 else
1454 output_asm_insn("dec %4", operands);
1456 sprintf(buf, "bgt movestrhi%d", count);
1457 output_asm_insn(buf, NULL);
1460 count ++;
1461 break;
1463 default:
1467 asr %4
1468 asr %4
1469 asr %4
1473 mov (%1)+, (%0)+
1474 mov (%1)+, (%0)+
1475 mov (%1)+, (%0)+
1476 mov (%1)+, (%0)+
1478 if (TARGET_45)
1479 sob %4, x
1480 else
1481 dec %4
1482 bgt x
1486 if (optimize_size)
1487 goto generate_compact_code;
1489 output_asm_insn("asr %4", operands);
1490 output_asm_insn("asr %4", operands);
1491 output_asm_insn("asr %4", operands);
1493 sprintf(buf, "\nmovestrhi%d:", count);
1494 output_asm_insn(buf, NULL);
1496 output_asm_insn("mov (%1)+, (%0)+", operands);
1497 output_asm_insn("mov (%1)+, (%0)+", operands);
1498 output_asm_insn("mov (%1)+, (%0)+", operands);
1499 output_asm_insn("mov (%1)+, (%0)+", operands);
1501 if (TARGET_45)
1503 sprintf(buf, "sob %%4, movestrhi%d", count);
1504 output_asm_insn(buf, operands);
1506 else
1508 output_asm_insn("dec %4", operands);
1510 sprintf(buf, "bgt movestrhi%d", count);
1511 output_asm_insn(buf, NULL);
1514 count ++;
1515 break;
1521 return "";
1524 /* for future use */
1526 comparison_operator_index(rtx op)
1528 switch (GET_CODE(op))
1530 case NE:
1531 return 0;
1533 case EQ:
1534 return 1;
1536 case GE:
1537 return 2;
1539 case GT:
1540 return 3;
1542 case LE:
1543 return 4;
1545 case LT:
1546 return 5;
1548 case GEU:
1549 return 6;
1551 case GTU:
1552 return 7;
1554 case LEU:
1555 return 8;
1557 case LTU:
1558 return 9;
1560 default:
1561 return -1;
1565 /* tests whether the rtx is a comparison operator */
1567 comp_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1569 return comparison_operator_index(op) >= 0;
1574 legitimate_address_p (enum machine_mode mode, rtx address)
1576 /* #define REG_OK_STRICT */
1577 GO_IF_LEGITIMATE_ADDRESS(mode, address, win);
1579 return 0;
1581 win:
1582 return 1;
1584 /* #undef REG_OK_STRICT */
1587 /* A copy of output_addr_const modified for pdp11 expression syntax.
1588 output_addr_const also gets called for %cDIGIT and %nDIGIT, which we don't
1589 use, and for debugging output, which we don't support with this port either.
1590 So this copy should get called whenever needed.
1592 void
1593 output_addr_const_pdp11 (FILE *file, rtx x)
1595 char buf[256];
1597 restart:
1598 switch (GET_CODE (x))
1600 case PC:
1601 if (flag_pic)
1602 putc ('.', file);
1603 else
1604 abort ();
1605 break;
1607 case SYMBOL_REF:
1608 assemble_name (file, XSTR (x, 0));
1609 break;
1611 case LABEL_REF:
1612 ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
1613 assemble_name (file, buf);
1614 break;
1616 case CODE_LABEL:
1617 ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
1618 assemble_name (file, buf);
1619 break;
1621 case CONST_INT:
1622 /* Should we check for constants which are too big? Maybe cutting
1623 them off to 16 bits is OK? */
1624 fprintf (file, "%#ho", (unsigned short) INTVAL (x));
1625 break;
1627 case CONST:
1628 /* This used to output parentheses around the expression,
1629 but that does not work on the 386 (either ATT or BSD assembler). */
1630 output_addr_const_pdp11 (file, XEXP (x, 0));
1631 break;
1633 case CONST_DOUBLE:
1634 if (GET_MODE (x) == VOIDmode)
1636 /* We can use %o if the number is one word and positive. */
1637 if (CONST_DOUBLE_HIGH (x))
1638 abort (); /* Should we just silently drop the high part? */
1639 else
1640 fprintf (file, "%#ho", (unsigned short) CONST_DOUBLE_LOW (x));
1642 else
1643 /* We can't handle floating point constants;
1644 PRINT_OPERAND must handle them. */
1645 output_operand_lossage ("floating constant misused");
1646 break;
1648 case PLUS:
1649 /* Some assemblers need integer constants to appear last (eg masm). */
1650 if (GET_CODE (XEXP (x, 0)) == CONST_INT)
1652 output_addr_const_pdp11 (file, XEXP (x, 1));
1653 if (INTVAL (XEXP (x, 0)) >= 0)
1654 fprintf (file, "+");
1655 output_addr_const_pdp11 (file, XEXP (x, 0));
1657 else
1659 output_addr_const_pdp11 (file, XEXP (x, 0));
1660 if (INTVAL (XEXP (x, 1)) >= 0)
1661 fprintf (file, "+");
1662 output_addr_const_pdp11 (file, XEXP (x, 1));
1664 break;
1666 case MINUS:
1667 /* Avoid outputting things like x-x or x+5-x,
1668 since some assemblers can't handle that. */
1669 x = simplify_subtraction (x);
1670 if (GET_CODE (x) != MINUS)
1671 goto restart;
1673 output_addr_const_pdp11 (file, XEXP (x, 0));
1674 fprintf (file, "-");
1675 if (GET_CODE (XEXP (x, 1)) == CONST_INT
1676 && INTVAL (XEXP (x, 1)) < 0)
1678 fprintf (file, targetm.asm_out.open_paren);
1679 output_addr_const_pdp11 (file, XEXP (x, 1));
1680 fprintf (file, targetm.asm_out.close_paren);
1682 else
1683 output_addr_const_pdp11 (file, XEXP (x, 1));
1684 break;
1686 case ZERO_EXTEND:
1687 case SIGN_EXTEND:
1688 output_addr_const_pdp11 (file, XEXP (x, 0));
1689 break;
1691 default:
1692 output_operand_lossage ("invalid expression as operand");