]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/pdp11/pdp11.c
GNU CC -> GCC
[thirdparty/gcc.git] / gcc / config / pdp11 / pdp11.c
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).
5
6 This file is part of GCC.
7
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.
12
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.
17
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. */
22
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"
44
45 /*
46 #define FPU_REG_P(X) ((X)>=8 && (X)<14)
47 #define CPU_REG_P(X) ((X)>=0 && (X)<8)
48 */
49
50 /* this is the current value returned by the macro FIRST_PARM_OFFSET
51 defined in tm.h */
52 int current_first_parm_offset;
53
54 /* This is where the condition code register lives. */
55 /* rtx cc0_reg_rtx; - no longer needed? */
56
57 static rtx find_addr_reg PARAMS ((rtx));
58 static const char *singlemove_string PARAMS ((rtx *));
59 static bool pdp11_assemble_integer PARAMS ((rtx, unsigned int, int));
60 static void pdp11_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
61 static void pdp11_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
62 static bool pdp11_rtx_costs PARAMS ((rtx, int, int, int *));
63 \f
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
73
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
78
79 #undef TARGET_ASM_OPEN_PAREN
80 #define TARGET_ASM_OPEN_PAREN "["
81 #undef TARGET_ASM_CLOSE_PAREN
82 #define TARGET_ASM_CLOSE_PAREN "]"
83
84 #undef TARGET_RTX_COSTS
85 #define TARGET_RTX_COSTS pdp11_rtx_costs
86
87 struct gcc_target targetm = TARGET_INITIALIZER;
88 \f
89 /* Nonzero if OP is a valid second operand for an arithmetic insn. */
90
91 int
92 arith_operand (op, mode)
93 rtx op;
94 enum machine_mode mode;
95 {
96 return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
97 }
98
99 int
100 const_immediate_operand (op, mode)
101 rtx op;
102 enum machine_mode mode ATTRIBUTE_UNUSED;
103 {
104 return (GET_CODE (op) == CONST_INT);
105 }
106
107 int
108 immediate15_operand (op, mode)
109 rtx op;
110 enum machine_mode mode ATTRIBUTE_UNUSED;
111 {
112 return (GET_CODE (op) == CONST_INT && ((INTVAL (op) & 0x8000) == 0x0000));
113 }
114
115 int
116 expand_shift_operand (op, mode)
117 rtx op;
118 enum machine_mode mode ATTRIBUTE_UNUSED;
119 {
120 return (GET_CODE (op) == CONST_INT
121 && abs (INTVAL(op)) > 1
122 && abs (INTVAL(op)) <= 4);
123 }
124
125 /*
126 stream is a stdio stream to output the code to.
127 size is an int: how many units of temporary storage to allocate.
128 Refer to the array `regs_ever_live' to determine which registers
129 to save; `regs_ever_live[I]' is nonzero if register number I
130 is ever used in the function. This macro is responsible for
131 knowing which registers should not be saved even if used.
132 */
133
134 #ifdef TWO_BSD
135
136 static void
137 pdp11_output_function_prologue (stream, size)
138 FILE *stream;
139 HOST_WIDE_INT size;
140 {
141 fprintf (stream, "\tjsr r5, csv\n");
142 if (size)
143 {
144 fprintf (stream, "\t/*abuse empty parameter slot for locals!*/\n");
145 if (size > 2)
146 fprintf(stream, "\tsub $%#o, sp\n", size - 2);
147
148 }
149 }
150
151 #else /* !TWO_BSD */
152
153 static void
154 pdp11_output_function_prologue (stream, size)
155 FILE *stream;
156 HOST_WIDE_INT size;
157 {
158 HOST_WIDE_INT fsize = ((size) + 1) & ~1;
159 int regno;
160 int via_ac = -1;
161
162 fprintf (stream,
163 "\n\t; /* function prologue %s*/\n", current_function_name);
164
165 /* if we are outputting code for main,
166 the switch FPU to right mode if TARGET_FPU */
167 if (MAIN_NAME_P (DECL_NAME (current_function_decl)) && TARGET_FPU)
168 {
169 fprintf(stream,
170 "\t;/* switch cpu to double float, single integer */\n");
171 fprintf(stream, "\tsetd\n");
172 fprintf(stream, "\tseti\n\n");
173 }
174
175 if (frame_pointer_needed)
176 {
177 fprintf(stream, "\tmov r5, -(sp)\n");
178 fprintf(stream, "\tmov sp, r5\n");
179 }
180 else
181 {
182 /* DON'T SAVE FP */
183 }
184
185 /* make frame */
186 if (fsize)
187 fprintf (stream, "\tsub $%#o, sp\n", fsize);
188
189 /* save CPU registers */
190 for (regno = 0; regno < 8; regno++)
191 if (regs_ever_live[regno] && ! call_used_regs[regno])
192 if (! ((regno == FRAME_POINTER_REGNUM)
193 && frame_pointer_needed))
194 fprintf (stream, "\tmov %s, -(sp)\n", reg_names[regno]);
195 /* fpu regs saving */
196
197 /* via_ac specifies the ac to use for saving ac4, ac5 */
198 via_ac = -1;
199
200 for (regno = 8; regno < FIRST_PSEUDO_REGISTER ; regno++)
201 {
202 /* ac0 - ac3 */
203 if (LOAD_FPU_REG_P(regno)
204 && regs_ever_live[regno]
205 && ! call_used_regs[regno])
206 {
207 fprintf (stream, "\tstd %s, -(sp)\n", reg_names[regno]);
208 via_ac = regno;
209 }
210
211 /* maybe make ac4, ac5 call used regs?? */
212 /* ac4 - ac5 */
213 if (NO_LOAD_FPU_REG_P(regno)
214 && regs_ever_live[regno]
215 && ! call_used_regs[regno])
216 {
217 if (via_ac == -1)
218 abort();
219
220 fprintf (stream, "\tldd %s, %s\n", reg_names[regno], reg_names[via_ac]);
221 fprintf (stream, "\tstd %s, -(sp)\n", reg_names[via_ac]);
222 }
223 }
224
225 fprintf (stream, "\t;/* end of prologue */\n\n");
226 }
227
228 #endif /* !TWO_BSD */
229
230 /*
231 The function epilogue should not depend on the current stack pointer!
232 It should use the frame pointer only. This is mandatory because
233 of alloca; we also take advantage of it to omit stack adjustments
234 before returning. */
235
236 /* maybe we can make leaf functions faster by switching to the
237 second register file - this way we don't have to save regs!
238 leaf functions are ~ 50% of all functions (dynamically!)
239
240 set/clear bit 11 (dec. 2048) of status word for switching register files -
241 but how can we do this? the pdp11/45 manual says bit may only
242 be set (p.24), but not cleared!
243
244 switching to kernel is probably more expensive, so we'll leave it
245 like this and not use the second set of registers...
246
247 maybe as option if you want to generate code for kernel mode? */
248
249 #ifdef TWO_BSD
250
251 static void
252 pdp11_output_function_epilogue (stream, size)
253 FILE *stream;
254 HOST_WIDE_INT size ATTRIBUTE_UNUSED;
255 {
256 fprintf (stream, "\t/* SP ignored by cret? */\n");
257 fprintf (stream, "\tjmp cret\n");
258 }
259
260 #else /* !TWO_BSD */
261
262 static void
263 pdp11_output_function_epilogue (stream, size)
264 FILE *stream;
265 HOST_WIDE_INT size;
266 {
267 HOST_WIDE_INT fsize = ((size) + 1) & ~1;
268 int i, j, k;
269
270 int via_ac;
271
272 fprintf (stream, "\n\t; /*function epilogue */\n");
273
274 if (frame_pointer_needed)
275 {
276 /* hope this is safe - m68k does it also .... */
277 regs_ever_live[FRAME_POINTER_REGNUM] = 0;
278
279 for (i =7, j = 0 ; i >= 0 ; i--)
280 if (regs_ever_live[i] && ! call_used_regs[i])
281 j++;
282
283 /* remember # of pushed bytes for CPU regs */
284 k = 2*j;
285
286 /* change fp -> r5 due to the compile error on libgcc2.c */
287 for (i =7 ; i >= 0 ; i--)
288 if (regs_ever_live[i] && ! call_used_regs[i])
289 fprintf(stream, "\tmov %#o(r5), %s\n",(-fsize-2*j--)&0xffff, reg_names[i]);
290
291 /* get ACs */
292 via_ac = FIRST_PSEUDO_REGISTER -1;
293
294 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
295 if (regs_ever_live[i] && ! call_used_regs[i])
296 {
297 via_ac = i;
298 k += 8;
299 }
300
301 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
302 {
303 if (LOAD_FPU_REG_P(i)
304 && regs_ever_live[i]
305 && ! call_used_regs[i])
306 {
307 fprintf(stream, "\tldd %#o(r5), %s\n", (-fsize-k)&0xffff, reg_names[i]);
308 k -= 8;
309 }
310
311 if (NO_LOAD_FPU_REG_P(i)
312 && regs_ever_live[i]
313 && ! call_used_regs[i])
314 {
315 if (! LOAD_FPU_REG_P(via_ac))
316 abort();
317
318 fprintf(stream, "\tldd %#o(r5), %s\n", (-fsize-k)&0xffff, reg_names[via_ac]);
319 fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]);
320 k -= 8;
321 }
322 }
323
324 fprintf(stream, "\tmov r5, sp\n");
325 fprintf (stream, "\tmov (sp)+, r5\n");
326 }
327 else
328 {
329 via_ac = FIRST_PSEUDO_REGISTER -1;
330
331 /* get ACs */
332 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
333 if (regs_ever_live[i] && call_used_regs[i])
334 via_ac = i;
335
336 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
337 {
338 if (LOAD_FPU_REG_P(i)
339 && regs_ever_live[i]
340 && ! call_used_regs[i])
341 fprintf(stream, "\tldd (sp)+, %s\n", reg_names[i]);
342
343 if (NO_LOAD_FPU_REG_P(i)
344 && regs_ever_live[i]
345 && ! call_used_regs[i])
346 {
347 if (! LOAD_FPU_REG_P(via_ac))
348 abort();
349
350 fprintf(stream, "\tldd (sp)+, %s\n", reg_names[via_ac]);
351 fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]);
352 }
353 }
354
355 for (i=7; i >= 0; i--)
356 if (regs_ever_live[i] && !call_used_regs[i])
357 fprintf(stream, "\tmov (sp)+, %s\n", reg_names[i]);
358
359 if (fsize)
360 fprintf((stream), "\tadd $%#o, sp\n", (fsize)&0xffff);
361 }
362
363 fprintf (stream, "\trts pc\n");
364 fprintf (stream, "\t;/* end of epilogue*/\n\n\n");
365 }
366
367 #endif /* !TWO_BSD */
368
369 /* Return the best assembler insn template
370 for moving operands[1] into operands[0] as a fullword. */
371 static const char *
372 singlemove_string (operands)
373 rtx *operands;
374 {
375 if (operands[1] != const0_rtx)
376 return "mov %1,%0";
377
378 return "clr %0";
379 }
380
381 \f
382 /* Output assembler code to perform a doubleword move insn
383 with operands OPERANDS. */
384
385 const char *
386 output_move_double (operands)
387 rtx *operands;
388 {
389 enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
390 rtx latehalf[2];
391 rtx addreg0 = 0, addreg1 = 0;
392
393 /* First classify both operands. */
394
395 if (REG_P (operands[0]))
396 optype0 = REGOP;
397 else if (offsettable_memref_p (operands[0]))
398 optype0 = OFFSOP;
399 else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
400 optype0 = POPOP;
401 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
402 optype0 = PUSHOP;
403 else if (GET_CODE (operands[0]) == MEM)
404 optype0 = MEMOP;
405 else
406 optype0 = RNDOP;
407
408 if (REG_P (operands[1]))
409 optype1 = REGOP;
410 else if (CONSTANT_P (operands[1])
411 #if 0
412 || GET_CODE (operands[1]) == CONST_DOUBLE
413 #endif
414 )
415 optype1 = CNSTOP;
416 else if (offsettable_memref_p (operands[1]))
417 optype1 = OFFSOP;
418 else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
419 optype1 = POPOP;
420 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
421 optype1 = PUSHOP;
422 else if (GET_CODE (operands[1]) == MEM)
423 optype1 = MEMOP;
424 else
425 optype1 = RNDOP;
426
427 /* Check for the cases that the operand constraints are not
428 supposed to allow to happen. Abort if we get one,
429 because generating code for these cases is painful. */
430
431 if (optype0 == RNDOP || optype1 == RNDOP)
432 abort ();
433
434 /* If one operand is decrementing and one is incrementing
435 decrement the former register explicitly
436 and change that operand into ordinary indexing. */
437
438 if (optype0 == PUSHOP && optype1 == POPOP)
439 {
440 operands[0] = XEXP (XEXP (operands[0], 0), 0);
441 output_asm_insn ("sub $4,%0", operands);
442 operands[0] = gen_rtx_MEM (SImode, operands[0]);
443 optype0 = OFFSOP;
444 }
445 if (optype0 == POPOP && optype1 == PUSHOP)
446 {
447 operands[1] = XEXP (XEXP (operands[1], 0), 0);
448 output_asm_insn ("sub $4,%1", operands);
449 operands[1] = gen_rtx_MEM (SImode, operands[1]);
450 optype1 = OFFSOP;
451 }
452
453 /* If an operand is an unoffsettable memory ref, find a register
454 we can increment temporarily to make it refer to the second word. */
455
456 if (optype0 == MEMOP)
457 addreg0 = find_addr_reg (XEXP (operands[0], 0));
458
459 if (optype1 == MEMOP)
460 addreg1 = find_addr_reg (XEXP (operands[1], 0));
461
462 /* Ok, we can do one word at a time.
463 Normally we do the low-numbered word first,
464 but if either operand is autodecrementing then we
465 do the high-numbered word first.
466
467 In either case, set up in LATEHALF the operands to use
468 for the high-numbered word and in some cases alter the
469 operands in OPERANDS to be suitable for the low-numbered word. */
470
471 if (optype0 == REGOP)
472 latehalf[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1);
473 else if (optype0 == OFFSOP)
474 latehalf[0] = adjust_address (operands[0], HImode, 2);
475 else
476 latehalf[0] = operands[0];
477
478 if (optype1 == REGOP)
479 latehalf[1] = gen_rtx_REG (HImode, REGNO (operands[1]) + 1);
480 else if (optype1 == OFFSOP)
481 latehalf[1] = adjust_address (operands[1], HImode, 2);
482 else if (optype1 == CNSTOP)
483 {
484 if (CONSTANT_P (operands[1]))
485 {
486 /* now the mess begins, high word is in lower word???
487
488 that's what ashc makes me think, but I don't remember :-( */
489 latehalf[1] = GEN_INT (INTVAL(operands[1]) >> 16);
490 operands[1] = GEN_INT (INTVAL(operands[1]) & 0xff);
491 }
492 else if (GET_CODE (operands[1]) == CONST_DOUBLE)
493 {
494 /* immediate 32 bit values not allowed */
495 abort();
496 }
497 }
498 else
499 latehalf[1] = operands[1];
500
501 /* If insn is effectively movd N(sp),-(sp) then we will do the
502 high word first. We should use the adjusted operand 1 (which is N+4(sp))
503 for the low word as well, to compensate for the first decrement of sp. */
504 if (optype0 == PUSHOP
505 && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
506 && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
507 operands[1] = latehalf[1];
508
509 /* If one or both operands autodecrementing,
510 do the two words, high-numbered first. */
511
512 /* Likewise, the first move would clobber the source of the second one,
513 do them in the other order. This happens only for registers;
514 such overlap can't happen in memory unless the user explicitly
515 sets it up, and that is an undefined circumstance. */
516
517 if (optype0 == PUSHOP || optype1 == PUSHOP
518 || (optype0 == REGOP && optype1 == REGOP
519 && REGNO (operands[0]) == REGNO (latehalf[1])))
520 {
521 /* Make any unoffsettable addresses point at high-numbered word. */
522 if (addreg0)
523 output_asm_insn ("add $2,%0", &addreg0);
524 if (addreg1)
525 output_asm_insn ("add $2,%0", &addreg1);
526
527 /* Do that word. */
528 output_asm_insn (singlemove_string (latehalf), latehalf);
529
530 /* Undo the adds we just did. */
531 if (addreg0)
532 output_asm_insn ("sub $2,%0", &addreg0);
533 if (addreg1)
534 output_asm_insn ("sub $2,%0", &addreg1);
535
536 /* Do low-numbered word. */
537 return singlemove_string (operands);
538 }
539
540 /* Normal case: do the two words, low-numbered first. */
541
542 output_asm_insn (singlemove_string (operands), operands);
543
544 /* Make any unoffsettable addresses point at high-numbered word. */
545 if (addreg0)
546 output_asm_insn ("add $2,%0", &addreg0);
547 if (addreg1)
548 output_asm_insn ("add $2,%0", &addreg1);
549
550 /* Do that word. */
551 output_asm_insn (singlemove_string (latehalf), latehalf);
552
553 /* Undo the adds we just did. */
554 if (addreg0)
555 output_asm_insn ("sub $2,%0", &addreg0);
556 if (addreg1)
557 output_asm_insn ("sub $2,%0", &addreg1);
558
559 return "";
560 }
561 /* Output assembler code to perform a quadword move insn
562 with operands OPERANDS. */
563
564 const char *
565 output_move_quad (operands)
566 rtx *operands;
567 {
568 enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
569 rtx latehalf[2];
570 rtx addreg0 = 0, addreg1 = 0;
571
572 output_asm_insn(";/* movdi/df: %1 -> %0 */", operands);
573
574 if (REG_P (operands[0]))
575 optype0 = REGOP;
576 else if (offsettable_memref_p (operands[0]))
577 optype0 = OFFSOP;
578 else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
579 optype0 = POPOP;
580 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
581 optype0 = PUSHOP;
582 else if (GET_CODE (operands[0]) == MEM)
583 optype0 = MEMOP;
584 else
585 optype0 = RNDOP;
586
587 if (REG_P (operands[1]))
588 optype1 = REGOP;
589 else if (CONSTANT_P (operands[1])
590 || GET_CODE (operands[1]) == CONST_DOUBLE)
591 optype1 = CNSTOP;
592 else if (offsettable_memref_p (operands[1]))
593 optype1 = OFFSOP;
594 else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
595 optype1 = POPOP;
596 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
597 optype1 = PUSHOP;
598 else if (GET_CODE (operands[1]) == MEM)
599 optype1 = MEMOP;
600 else
601 optype1 = RNDOP;
602
603 /* Check for the cases that the operand constraints are not
604 supposed to allow to happen. Abort if we get one,
605 because generating code for these cases is painful. */
606
607 if (optype0 == RNDOP || optype1 == RNDOP)
608 abort ();
609
610 /* check if we move a CPU reg to an FPU reg, or vice versa! */
611 if (optype0 == REGOP && optype1 == REGOP)
612 /* bogus - 64 bit cannot reside in CPU! */
613 if (CPU_REG_P(REGNO(operands[0]))
614 || CPU_REG_P (REGNO(operands[1])))
615 abort();
616
617 if (optype0 == REGOP || optype1 == REGOP)
618 {
619 /* check for use of clrd????
620 if you ever allow ac4 and ac5 (now we require secondary load)
621 you must check whether
622 you want to load into them or store from them -
623 then dump ac0 into $help$ movce ac4/5 to ac0, do the
624 store from ac0, and restore ac0 - if you can find
625 an unused ac[0-3], use that and you save a store and a load!*/
626
627 if (FPU_REG_P(REGNO(operands[0])))
628 {
629 if (GET_CODE(operands[1]) == CONST_DOUBLE)
630 {
631 REAL_VALUE_TYPE r;
632 REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
633
634 if (REAL_VALUES_EQUAL (r, dconst0))
635 return "{clrd|clrf} %0";
636 }
637
638 return "{ldd|movf} %1, %0";
639 }
640
641 if (FPU_REG_P(REGNO(operands[1])))
642 return "{std|movf} %1, %0";
643 }
644
645 /* If one operand is decrementing and one is incrementing
646 decrement the former register explicitly
647 and change that operand into ordinary indexing. */
648
649 if (optype0 == PUSHOP && optype1 == POPOP)
650 {
651 operands[0] = XEXP (XEXP (operands[0], 0), 0);
652 output_asm_insn ("sub $8,%0", operands);
653 operands[0] = gen_rtx_MEM (DImode, operands[0]);
654 optype0 = OFFSOP;
655 }
656 if (optype0 == POPOP && optype1 == PUSHOP)
657 {
658 operands[1] = XEXP (XEXP (operands[1], 0), 0);
659 output_asm_insn ("sub $8,%1", operands);
660 operands[1] = gen_rtx_MEM (SImode, operands[1]);
661 optype1 = OFFSOP;
662 }
663
664 /* If an operand is an unoffsettable memory ref, find a register
665 we can increment temporarily to make it refer to the second word. */
666
667 if (optype0 == MEMOP)
668 addreg0 = find_addr_reg (XEXP (operands[0], 0));
669
670 if (optype1 == MEMOP)
671 addreg1 = find_addr_reg (XEXP (operands[1], 0));
672
673 /* Ok, we can do one word at a time.
674 Normally we do the low-numbered word first,
675 but if either operand is autodecrementing then we
676 do the high-numbered word first.
677
678 In either case, set up in LATEHALF the operands to use
679 for the high-numbered word and in some cases alter the
680 operands in OPERANDS to be suitable for the low-numbered word. */
681
682 if (optype0 == REGOP)
683 latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2);
684 else if (optype0 == OFFSOP)
685 latehalf[0] = adjust_address (operands[0], SImode, 4);
686 else
687 latehalf[0] = operands[0];
688
689 if (optype1 == REGOP)
690 latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2);
691 else if (optype1 == OFFSOP)
692 latehalf[1] = adjust_address (operands[1], SImode, 4);
693 else if (optype1 == CNSTOP)
694 {
695 if (GET_CODE (operands[1]) == CONST_DOUBLE)
696 {
697 /* floats only. not yet supported!
698
699 -- compute it into PDP float format, - internally,
700 just use IEEE and ignore possible problems ;-)
701
702 we might get away with it !!!! */
703
704 abort();
705
706 #ifndef HOST_WORDS_BIG_ENDIAN
707 latehalf[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
708 operands[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
709 #else /* HOST_WORDS_BIG_ENDIAN */
710 latehalf[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
711 operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
712 #endif /* HOST_WORDS_BIG_ENDIAN */
713 }
714 else if (GET_CODE(operands[1]) == CONST_INT)
715 {
716 latehalf[1] = GEN_INT (0);
717 }
718 else
719 abort();
720 }
721 else
722 latehalf[1] = operands[1];
723
724 /* If insn is effectively movd N(sp),-(sp) then we will do the
725 high word first. We should use the adjusted operand 1 (which is N+4(sp))
726 for the low word as well, to compensate for the first decrement of sp. */
727 if (optype0 == PUSHOP
728 && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
729 && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
730 operands[1] = latehalf[1];
731
732 /* If one or both operands autodecrementing,
733 do the two words, high-numbered first. */
734
735 /* Likewise, the first move would clobber the source of the second one,
736 do them in the other order. This happens only for registers;
737 such overlap can't happen in memory unless the user explicitly
738 sets it up, and that is an undefined circumstance. */
739
740 if (optype0 == PUSHOP || optype1 == PUSHOP
741 || (optype0 == REGOP && optype1 == REGOP
742 && REGNO (operands[0]) == REGNO (latehalf[1])))
743 {
744 /* Make any unoffsettable addresses point at high-numbered word. */
745 if (addreg0)
746 output_asm_insn ("add $4,%0", &addreg0);
747 if (addreg1)
748 output_asm_insn ("add $4,%0", &addreg1);
749
750 /* Do that word. */
751 output_asm_insn(output_move_double(latehalf), latehalf);
752
753 /* Undo the adds we just did. */
754 if (addreg0)
755 output_asm_insn ("sub $4,%0", &addreg0);
756 if (addreg1)
757 output_asm_insn ("sub $4,%0", &addreg1);
758
759 /* Do low-numbered word. */
760 return output_move_double (operands);
761 }
762
763 /* Normal case: do the two words, low-numbered first. */
764
765 output_asm_insn (output_move_double (operands), operands);
766
767 /* Make any unoffsettable addresses point at high-numbered word. */
768 if (addreg0)
769 output_asm_insn ("add $4,%0", &addreg0);
770 if (addreg1)
771 output_asm_insn ("add $4,%0", &addreg1);
772
773 /* Do that word. */
774 output_asm_insn (output_move_double (latehalf), latehalf);
775
776 /* Undo the adds we just did. */
777 if (addreg0)
778 output_asm_insn ("sub $4,%0", &addreg0);
779 if (addreg1)
780 output_asm_insn ("sub $4,%0", &addreg1);
781
782 return "";
783 }
784
785 \f
786 /* Return a REG that occurs in ADDR with coefficient 1.
787 ADDR can be effectively incremented by incrementing REG. */
788
789 static rtx
790 find_addr_reg (addr)
791 rtx addr;
792 {
793 while (GET_CODE (addr) == PLUS)
794 {
795 if (GET_CODE (XEXP (addr, 0)) == REG)
796 addr = XEXP (addr, 0);
797 if (GET_CODE (XEXP (addr, 1)) == REG)
798 addr = XEXP (addr, 1);
799 if (CONSTANT_P (XEXP (addr, 0)))
800 addr = XEXP (addr, 1);
801 if (CONSTANT_P (XEXP (addr, 1)))
802 addr = XEXP (addr, 0);
803 }
804 if (GET_CODE (addr) == REG)
805 return addr;
806 return 0;
807 }
808 \f
809 /* Output an ascii string. */
810 void
811 output_ascii (file, p, size)
812 FILE *file;
813 const char *p;
814 int size;
815 {
816 int i;
817
818 /* This used to output .byte "string", which doesn't work with the UNIX
819 assembler and I think not with DEC ones either. */
820 fprintf (file, "\t.byte ");
821
822 for (i = 0; i < size; i++)
823 {
824 register int c = p[i];
825 if (c < 0)
826 c += 256;
827 fprintf (file, "%#o", c);
828 if (i < size - 1)
829 putc (',', file);
830 }
831 putc ('\n', file);
832 }
833
834
835 /* --- stole from out-vax, needs changes */
836
837 void
838 print_operand_address (file, addr)
839 FILE *file;
840 register rtx addr;
841 {
842 register rtx reg1, reg2, breg, ireg;
843 rtx offset;
844
845 retry:
846
847 switch (GET_CODE (addr))
848 {
849 case MEM:
850 if (TARGET_UNIX_ASM)
851 fprintf (file, "*");
852 else
853 fprintf (file, "@");
854 addr = XEXP (addr, 0);
855 goto retry;
856
857 case REG:
858 fprintf (file, "(%s)", reg_names[REGNO (addr)]);
859 break;
860
861 case PRE_MODIFY:
862 case PRE_DEC:
863 fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]);
864 break;
865
866 case POST_MODIFY:
867 case POST_INC:
868 fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]);
869 break;
870
871 case PLUS:
872 reg1 = 0; reg2 = 0;
873 ireg = 0; breg = 0;
874 offset = 0;
875 if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
876 || GET_CODE (XEXP (addr, 0)) == MEM)
877 {
878 offset = XEXP (addr, 0);
879 addr = XEXP (addr, 1);
880 }
881 else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
882 || GET_CODE (XEXP (addr, 1)) == MEM)
883 {
884 offset = XEXP (addr, 1);
885 addr = XEXP (addr, 0);
886 }
887 if (GET_CODE (addr) != PLUS)
888 ;
889 else if (GET_CODE (XEXP (addr, 0)) == MULT)
890 {
891 reg1 = XEXP (addr, 0);
892 addr = XEXP (addr, 1);
893 }
894 else if (GET_CODE (XEXP (addr, 1)) == MULT)
895 {
896 reg1 = XEXP (addr, 1);
897 addr = XEXP (addr, 0);
898 }
899 else if (GET_CODE (XEXP (addr, 0)) == REG)
900 {
901 reg1 = XEXP (addr, 0);
902 addr = XEXP (addr, 1);
903 }
904 else if (GET_CODE (XEXP (addr, 1)) == REG)
905 {
906 reg1 = XEXP (addr, 1);
907 addr = XEXP (addr, 0);
908 }
909 if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
910 {
911 if (reg1 == 0)
912 reg1 = addr;
913 else
914 reg2 = addr;
915 addr = 0;
916 }
917 if (offset != 0)
918 {
919 if (addr != 0) abort ();
920 addr = offset;
921 }
922 if (reg1 != 0 && GET_CODE (reg1) == MULT)
923 {
924 breg = reg2;
925 ireg = reg1;
926 }
927 else if (reg2 != 0 && GET_CODE (reg2) == MULT)
928 {
929 breg = reg1;
930 ireg = reg2;
931 }
932 else if (reg2 != 0 || GET_CODE (addr) == MEM)
933 {
934 breg = reg2;
935 ireg = reg1;
936 }
937 else
938 {
939 breg = reg1;
940 ireg = reg2;
941 }
942 if (addr != 0)
943 output_address (addr);
944 if (breg != 0)
945 {
946 if (GET_CODE (breg) != REG)
947 abort ();
948 fprintf (file, "(%s)", reg_names[REGNO (breg)]);
949 }
950 if (ireg != 0)
951 {
952 if (GET_CODE (ireg) == MULT)
953 ireg = XEXP (ireg, 0);
954 if (GET_CODE (ireg) != REG)
955 abort ();
956 abort();
957 fprintf (file, "[%s]", reg_names[REGNO (ireg)]);
958 }
959 break;
960
961 default:
962 output_addr_const_pdp11 (file, addr);
963 }
964 }
965
966 /* Target hook to assemble integer objects. We need to use the
967 pdp-specific version of output_addr_const. */
968
969 static bool
970 pdp11_assemble_integer (x, size, aligned_p)
971 rtx x;
972 unsigned int size;
973 int aligned_p;
974 {
975 if (aligned_p)
976 switch (size)
977 {
978 case 1:
979 fprintf (asm_out_file, "\t.byte\t");
980 output_addr_const_pdp11 (asm_out_file, x);
981 fprintf (asm_out_file, " /* char */\n");
982 return true;
983
984 case 2:
985 fprintf (asm_out_file, TARGET_UNIX_ASM ? "\t" : "\t.word\t");
986 output_addr_const_pdp11 (asm_out_file, x);
987 fprintf (asm_out_file, " /* short */\n");
988 return true;
989 }
990 return default_assemble_integer (x, size, aligned_p);
991 }
992
993
994 /* register move costs, indexed by regs */
995
996 static const int move_costs[N_REG_CLASSES][N_REG_CLASSES] =
997 {
998 /* NO MUL GEN LFPU NLFPU FPU ALL */
999
1000 /* NO */ { 0, 0, 0, 0, 0, 0, 0},
1001 /* MUL */ { 0, 2, 2, 10, 22, 22, 22},
1002 /* GEN */ { 0, 2, 2, 10, 22, 22, 22},
1003 /* LFPU */ { 0, 10, 10, 2, 2, 2, 10},
1004 /* NLFPU */ { 0, 22, 22, 2, 2, 2, 22},
1005 /* FPU */ { 0, 22, 22, 2, 2, 2, 22},
1006 /* ALL */ { 0, 22, 22, 10, 22, 22, 22}
1007 } ;
1008
1009
1010 /* -- note that some moves are tremendously expensive,
1011 because they require lots of tricks! do we have to
1012 charge the costs incurred by secondary reload class
1013 -- as we do here with 22 -- or not ? */
1014
1015 int
1016 register_move_cost(c1, c2)
1017 enum reg_class c1, c2;
1018 {
1019 return move_costs[(int)c1][(int)c2];
1020 }
1021
1022 static bool
1023 pdp11_rtx_costs (x, code, outer_code, total)
1024 rtx x;
1025 int code, outer_code ATTRIBUTE_UNUSED;
1026 int *total;
1027 {
1028 switch (code)
1029 {
1030 case CONST_INT:
1031 if (INTVAL (x) == 0 || INTVAL (x) == -1 || INTVAL (x) == 1)
1032 {
1033 *total = 0;
1034 return true;
1035 }
1036 /* FALLTHRU */
1037
1038 case CONST:
1039 case LABEL_REF:
1040 case SYMBOL_REF:
1041 /* Twice as expensive as REG. */
1042 *total = 2;
1043 return true;
1044
1045 case CONST_DOUBLE:
1046 /* Twice (or 4 times) as expensive as 16 bit. */
1047 *total = 4;
1048 return true;
1049
1050 case MULT:
1051 /* ??? There is something wrong in MULT because MULT is not
1052 as cheap as total = 2 even if we can shift! */
1053 /* If optimizing for size make mult etc cheap, but not 1, so when
1054 in doubt the faster insn is chosen. */
1055 if (optimize_size)
1056 *total = COSTS_N_INSNS (2);
1057 else
1058 *total = COSTS_N_INSNS (11);
1059 return false;
1060
1061 case DIV:
1062 if (optimize_size)
1063 *total = COSTS_N_INSNS (2);
1064 else
1065 *total = COSTS_N_INSNS (25);
1066 return false;
1067
1068 case MOD:
1069 if (optimize_size)
1070 *total = COSTS_N_INSNS (2);
1071 else
1072 *total = COSTS_N_INSNS (26);
1073 return false;
1074
1075 case ABS:
1076 /* Equivalent to length, so same for optimize_size. */
1077 *total = COSTS_N_INSNS (3);
1078 return false;
1079
1080 case ZERO_EXTEND:
1081 /* Only used for qi->hi. */
1082 *total = COSTS_N_INSNS (1);
1083 return false;
1084
1085 case SIGN_EXTEND:
1086 if (GET_MODE (x) == HImode)
1087 *total = COSTS_N_INSNS (1);
1088 else if (GET_MODE (x) == SImode)
1089 *total = COSTS_N_INSNS (6);
1090 else
1091 *total = COSTS_N_INSNS (2);
1092 return false;
1093
1094 case ASHIFT:
1095 case LSHIFTRT:
1096 case ASHIFTRT:
1097 if (optimize_size)
1098 *total = COSTS_N_INSNS (1);
1099 else if (GET_MODE (x) == QImode)
1100 {
1101 if (GET_CODE (XEXP (x, 1)) != CONST_INT)
1102 *total = COSTS_N_INSNS (8); /* worst case */
1103 else
1104 *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1)));
1105 }
1106 else if (GET_MODE (x) == HImode)
1107 {
1108 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
1109 {
1110 if (abs (INTVAL (XEXP (x, 1))) == 1)
1111 *total = COSTS_N_INSNS (1);
1112 else
1113 *total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1)));
1114 }
1115 else
1116 *total = COSTS_N_INSNS (10); /* worst case */
1117 }
1118 else if (GET_MODE (x) == SImode)
1119 {
1120 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
1121 *total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1)));
1122 else /* worst case */
1123 *total = COSTS_N_INSNS (18);
1124 }
1125 return false;
1126
1127 default:
1128 return false;
1129 }
1130 }
1131
1132 const char *
1133 output_jump(pos, neg, length)
1134 const char *pos, *neg;
1135 int length;
1136 {
1137 static int x = 0;
1138
1139 static char buf[1000];
1140
1141 #if 0
1142 /* currently we don't need this, because the tstdf and cmpdf
1143 copy the condition code immediately, and other float operations are not
1144 yet recognized as changing the FCC - if so, then the length-cost of all
1145 jump insns increases by one, because we have to potentially copy the
1146 FCC! */
1147 if (cc_status.flags & CC_IN_FPU)
1148 output_asm_insn("cfcc", NULL);
1149 #endif
1150
1151 switch (length)
1152 {
1153 case 1:
1154
1155 strcpy(buf, pos);
1156 strcat(buf, " %l0");
1157
1158 return buf;
1159
1160 case 3:
1161
1162 sprintf(buf, "%s JMP_%d\n\tjmp %%l0\nJMP_%d:", neg, x, x);
1163
1164 x++;
1165
1166 return buf;
1167
1168 default:
1169
1170 abort();
1171 }
1172
1173 }
1174
1175 void
1176 notice_update_cc_on_set(exp, insn)
1177 rtx exp;
1178 rtx insn ATTRIBUTE_UNUSED;
1179 {
1180 if (GET_CODE (SET_DEST (exp)) == CC0)
1181 {
1182 cc_status.flags = 0;
1183 cc_status.value1 = SET_DEST (exp);
1184 cc_status.value2 = SET_SRC (exp);
1185
1186 /*
1187 if (GET_MODE(SET_SRC(exp)) == DFmode)
1188 cc_status.flags |= CC_IN_FPU;
1189 */
1190 }
1191 else if ((GET_CODE (SET_DEST (exp)) == REG
1192 || GET_CODE (SET_DEST (exp)) == MEM)
1193 && GET_CODE (SET_SRC (exp)) != PC
1194 && (GET_MODE (SET_DEST(exp)) == HImode
1195 || GET_MODE (SET_DEST(exp)) == QImode)
1196 && (GET_CODE (SET_SRC(exp)) == PLUS
1197 || GET_CODE (SET_SRC(exp)) == MINUS
1198 || GET_CODE (SET_SRC(exp)) == AND
1199 || GET_CODE (SET_SRC(exp)) == IOR
1200 || GET_CODE (SET_SRC(exp)) == XOR
1201 || GET_CODE (SET_SRC(exp)) == NOT
1202 || GET_CODE (SET_SRC(exp)) == NEG
1203 || GET_CODE (SET_SRC(exp)) == REG
1204 || GET_CODE (SET_SRC(exp)) == MEM))
1205 {
1206 cc_status.flags = 0;
1207 cc_status.value1 = SET_SRC (exp);
1208 cc_status.value2 = SET_DEST (exp);
1209
1210 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
1211 && cc_status.value2
1212 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
1213 cc_status.value2 = 0;
1214 if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM
1215 && cc_status.value2
1216 && GET_CODE (cc_status.value2) == MEM)
1217 cc_status.value2 = 0;
1218 }
1219 else if (GET_CODE (SET_SRC (exp)) == CALL)
1220 {
1221 CC_STATUS_INIT;
1222 }
1223 else if (GET_CODE (SET_DEST (exp)) == REG)
1224 /* what's this ? */
1225 {
1226 if ((cc_status.value1
1227 && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1)))
1228 cc_status.value1 = 0;
1229 if ((cc_status.value2
1230 && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2)))
1231 cc_status.value2 = 0;
1232 }
1233 else if (SET_DEST(exp) == pc_rtx)
1234 {
1235 /* jump */
1236 }
1237 else /* if (GET_CODE (SET_DEST (exp)) == MEM) */
1238 {
1239 /* the last else is a bit paranoiac, but since nearly all instructions
1240 play with condition codes, it's reasonable! */
1241
1242 CC_STATUS_INIT; /* paranoia*/
1243 }
1244 }
1245
1246
1247 int
1248 simple_memory_operand(op, mode)
1249 rtx op;
1250 enum machine_mode mode ATTRIBUTE_UNUSED;
1251 {
1252 rtx addr;
1253
1254 /* Eliminate non-memory operations */
1255 if (GET_CODE (op) != MEM)
1256 return FALSE;
1257
1258 #if 0
1259 /* dword operations really put out 2 instructions, so eliminate them. */
1260 if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4))
1261 return FALSE;
1262 #endif
1263
1264 /* Decode the address now. */
1265
1266 indirection:
1267
1268 addr = XEXP (op, 0);
1269
1270 switch (GET_CODE (addr))
1271 {
1272 case REG:
1273 /* (R0) - no extra cost */
1274 return 1;
1275
1276 case PRE_DEC:
1277 case POST_INC:
1278 /* -(R0), (R0)+ - cheap! */
1279 return 0;
1280
1281 case MEM:
1282 /* cheap - is encoded in addressing mode info!
1283
1284 -- except for @(R0), which has to be @0(R0) !!! */
1285
1286 if (GET_CODE (XEXP (addr, 0)) == REG)
1287 return 0;
1288
1289 op=addr;
1290 goto indirection;
1291
1292 case CONST_INT:
1293 case LABEL_REF:
1294 case CONST:
1295 case SYMBOL_REF:
1296 /* @#address - extra cost */
1297 return 0;
1298
1299 case PLUS:
1300 /* X(R0) - extra cost */
1301 return 0;
1302
1303 default:
1304 break;
1305 }
1306
1307 return FALSE;
1308 }
1309
1310
1311 /*
1312 * output a block move:
1313 *
1314 * operands[0] ... to
1315 * operands[1] ... from
1316 * operands[2] ... length
1317 * operands[3] ... alignment
1318 * operands[4] ... scratch register
1319 */
1320
1321
1322 const char *
1323 output_block_move(operands)
1324 rtx *operands;
1325 {
1326 static int count = 0;
1327 char buf[200];
1328
1329 if (GET_CODE(operands[2]) == CONST_INT
1330 && ! optimize_size)
1331 {
1332 if (INTVAL(operands[2]) < 16
1333 && INTVAL(operands[3]) == 1)
1334 {
1335 register int i;
1336
1337 for (i = 1; i <= INTVAL(operands[2]); i++)
1338 output_asm_insn("movb (%1)+, (%0)+", operands);
1339
1340 return "";
1341 }
1342 else if (INTVAL(operands[2]) < 32)
1343 {
1344 register int i;
1345
1346 for (i = 1; i <= INTVAL(operands[2])/2; i++)
1347 output_asm_insn("mov (%1)+, (%0)+", operands);
1348
1349 /* may I assume that moved quantity is
1350 multiple of alignment ???
1351
1352 I HOPE SO !
1353 */
1354
1355 return "";
1356 }
1357
1358
1359 /* can do other clever things, maybe... */
1360 }
1361
1362 if (CONSTANT_P(operands[2]) )
1363 {
1364 /* just move count to scratch */
1365 output_asm_insn("mov %2, %4", operands);
1366 }
1367 else
1368 {
1369 /* just clobber the register */
1370 operands[4] = operands[2];
1371 }
1372
1373
1374 /* switch over alignment */
1375 switch (INTVAL(operands[3]))
1376 {
1377 case 1:
1378
1379 /*
1380 x:
1381 movb (%1)+, (%0)+
1382
1383 if (TARGET_45)
1384 sob %4,x
1385 else
1386 dec %4
1387 bgt x
1388
1389 */
1390
1391 sprintf(buf, "\nmovestrhi%d:", count);
1392 output_asm_insn(buf, NULL);
1393
1394 output_asm_insn("movb (%1)+, (%0)+", operands);
1395
1396 if (TARGET_45)
1397 {
1398 sprintf(buf, "sob %%4, movestrhi%d", count);
1399 output_asm_insn(buf, operands);
1400 }
1401 else
1402 {
1403 output_asm_insn("dec %4", operands);
1404
1405 sprintf(buf, "bgt movestrhi%d", count);
1406 output_asm_insn(buf, NULL);
1407 }
1408
1409 count ++;
1410 break;
1411
1412 case 2:
1413
1414 /*
1415 asr %4
1416
1417 x:
1418
1419 mov (%1)+, (%0)+
1420
1421 if (TARGET_45)
1422 sob %4, x
1423 else
1424 dec %4
1425 bgt x
1426 */
1427
1428 generate_compact_code:
1429
1430 output_asm_insn("asr %4", operands);
1431
1432 sprintf(buf, "\nmovestrhi%d:", count);
1433 output_asm_insn(buf, NULL);
1434
1435 output_asm_insn("mov (%1)+, (%0)+", operands);
1436
1437 if (TARGET_45)
1438 {
1439 sprintf(buf, "sob %%4, movestrhi%d", count);
1440 output_asm_insn(buf, operands);
1441 }
1442 else
1443 {
1444 output_asm_insn("dec %4", operands);
1445
1446 sprintf(buf, "bgt movestrhi%d", count);
1447 output_asm_insn(buf, NULL);
1448 }
1449
1450 count ++;
1451 break;
1452
1453 case 4:
1454
1455 /*
1456
1457 asr %4
1458 asr %4
1459
1460 x:
1461
1462 mov (%1)+, (%0)+
1463 mov (%1)+, (%0)+
1464
1465 if (TARGET_45)
1466 sob %4, x
1467 else
1468 dec %4
1469 bgt x
1470 */
1471
1472 if (optimize_size)
1473 goto generate_compact_code;
1474
1475 output_asm_insn("asr %4", operands);
1476 output_asm_insn("asr %4", operands);
1477
1478 sprintf(buf, "\nmovestrhi%d:", count);
1479 output_asm_insn(buf, NULL);
1480
1481 output_asm_insn("mov (%1)+, (%0)+", operands);
1482 output_asm_insn("mov (%1)+, (%0)+", operands);
1483
1484 if (TARGET_45)
1485 {
1486 sprintf(buf, "sob %%4, movestrhi%d", count);
1487 output_asm_insn(buf, operands);
1488 }
1489 else
1490 {
1491 output_asm_insn("dec %4", operands);
1492
1493 sprintf(buf, "bgt movestrhi%d", count);
1494 output_asm_insn(buf, NULL);
1495 }
1496
1497 count ++;
1498 break;
1499
1500 default:
1501
1502 /*
1503
1504 asr %4
1505 asr %4
1506 asr %4
1507
1508 x:
1509
1510 mov (%1)+, (%0)+
1511 mov (%1)+, (%0)+
1512 mov (%1)+, (%0)+
1513 mov (%1)+, (%0)+
1514
1515 if (TARGET_45)
1516 sob %4, x
1517 else
1518 dec %4
1519 bgt x
1520 */
1521
1522
1523 if (optimize_size)
1524 goto generate_compact_code;
1525
1526 output_asm_insn("asr %4", operands);
1527 output_asm_insn("asr %4", operands);
1528 output_asm_insn("asr %4", operands);
1529
1530 sprintf(buf, "\nmovestrhi%d:", count);
1531 output_asm_insn(buf, NULL);
1532
1533 output_asm_insn("mov (%1)+, (%0)+", operands);
1534 output_asm_insn("mov (%1)+, (%0)+", operands);
1535 output_asm_insn("mov (%1)+, (%0)+", operands);
1536 output_asm_insn("mov (%1)+, (%0)+", operands);
1537
1538 if (TARGET_45)
1539 {
1540 sprintf(buf, "sob %%4, movestrhi%d", count);
1541 output_asm_insn(buf, operands);
1542 }
1543 else
1544 {
1545 output_asm_insn("dec %4", operands);
1546
1547 sprintf(buf, "bgt movestrhi%d", count);
1548 output_asm_insn(buf, NULL);
1549 }
1550
1551 count ++;
1552 break;
1553
1554 ;
1555
1556 }
1557
1558 return "";
1559 }
1560
1561 /* for future use */
1562 int
1563 comparison_operator_index(op)
1564 rtx op;
1565 {
1566 switch (GET_CODE(op))
1567 {
1568 case NE:
1569 return 0;
1570
1571 case EQ:
1572 return 1;
1573
1574 case GE:
1575 return 2;
1576
1577 case GT:
1578 return 3;
1579
1580 case LE:
1581 return 4;
1582
1583 case LT:
1584 return 5;
1585
1586 case GEU:
1587 return 6;
1588
1589 case GTU:
1590 return 7;
1591
1592 case LEU:
1593 return 8;
1594
1595 case LTU:
1596 return 9;
1597
1598 default:
1599 return -1;
1600 }
1601 }
1602
1603 /* tests whether the rtx is a comparison operator */
1604 int
1605 comp_operator (op, mode)
1606 rtx op;
1607 enum machine_mode mode ATTRIBUTE_UNUSED;
1608 {
1609 return comparison_operator_index(op) >= 0;
1610 }
1611
1612
1613 int
1614 legitimate_address_p (mode, address)
1615 enum machine_mode mode;
1616 rtx address;
1617 {
1618 /* #define REG_OK_STRICT */
1619 GO_IF_LEGITIMATE_ADDRESS(mode, address, win);
1620
1621 return 0;
1622
1623 win:
1624 return 1;
1625
1626 /* #undef REG_OK_STRICT */
1627 }
1628
1629 /* A copy of output_addr_const modified for pdp11 expression syntax.
1630 output_addr_const also gets called for %cDIGIT and %nDIGIT, which we don't
1631 use, and for debugging output, which we don't support with this port either.
1632 So this copy should get called whenever needed.
1633 */
1634 void
1635 output_addr_const_pdp11 (file, x)
1636 FILE *file;
1637 rtx x;
1638 {
1639 char buf[256];
1640
1641 restart:
1642 switch (GET_CODE (x))
1643 {
1644 case PC:
1645 if (flag_pic)
1646 putc ('.', file);
1647 else
1648 abort ();
1649 break;
1650
1651 case SYMBOL_REF:
1652 assemble_name (file, XSTR (x, 0));
1653 break;
1654
1655 case LABEL_REF:
1656 ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
1657 assemble_name (file, buf);
1658 break;
1659
1660 case CODE_LABEL:
1661 ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
1662 assemble_name (file, buf);
1663 break;
1664
1665 case CONST_INT:
1666 /* Should we check for constants which are too big? Maybe cutting
1667 them off to 16 bits is OK? */
1668 fprintf (file, "%#ho", (unsigned short) INTVAL (x));
1669 break;
1670
1671 case CONST:
1672 /* This used to output parentheses around the expression,
1673 but that does not work on the 386 (either ATT or BSD assembler). */
1674 output_addr_const_pdp11 (file, XEXP (x, 0));
1675 break;
1676
1677 case CONST_DOUBLE:
1678 if (GET_MODE (x) == VOIDmode)
1679 {
1680 /* We can use %o if the number is one word and positive. */
1681 if (CONST_DOUBLE_HIGH (x))
1682 abort (); /* Should we just silently drop the high part? */
1683 else
1684 fprintf (file, "%#ho", (unsigned short) CONST_DOUBLE_LOW (x));
1685 }
1686 else
1687 /* We can't handle floating point constants;
1688 PRINT_OPERAND must handle them. */
1689 output_operand_lossage ("floating constant misused");
1690 break;
1691
1692 case PLUS:
1693 /* Some assemblers need integer constants to appear last (eg masm). */
1694 if (GET_CODE (XEXP (x, 0)) == CONST_INT)
1695 {
1696 output_addr_const_pdp11 (file, XEXP (x, 1));
1697 if (INTVAL (XEXP (x, 0)) >= 0)
1698 fprintf (file, "+");
1699 output_addr_const_pdp11 (file, XEXP (x, 0));
1700 }
1701 else
1702 {
1703 output_addr_const_pdp11 (file, XEXP (x, 0));
1704 if (INTVAL (XEXP (x, 1)) >= 0)
1705 fprintf (file, "+");
1706 output_addr_const_pdp11 (file, XEXP (x, 1));
1707 }
1708 break;
1709
1710 case MINUS:
1711 /* Avoid outputting things like x-x or x+5-x,
1712 since some assemblers can't handle that. */
1713 x = simplify_subtraction (x);
1714 if (GET_CODE (x) != MINUS)
1715 goto restart;
1716
1717 output_addr_const_pdp11 (file, XEXP (x, 0));
1718 fprintf (file, "-");
1719 if (GET_CODE (XEXP (x, 1)) == CONST_INT
1720 && INTVAL (XEXP (x, 1)) < 0)
1721 {
1722 fprintf (file, targetm.asm_out.open_paren);
1723 output_addr_const_pdp11 (file, XEXP (x, 1));
1724 fprintf (file, targetm.asm_out.close_paren);
1725 }
1726 else
1727 output_addr_const_pdp11 (file, XEXP (x, 1));
1728 break;
1729
1730 case ZERO_EXTEND:
1731 case SIGN_EXTEND:
1732 output_addr_const_pdp11 (file, XEXP (x, 0));
1733 break;
1734
1735 default:
1736 output_operand_lossage ("invalid expression as operand");
1737 }
1738 }