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