xref: /openbsd/gnu/gcc/gcc/config/pdp11/pdp11.c (revision 404b540a)
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