]> gcc.gnu.org Git - gcc.git/blob - gcc/config/m88k/m88k.c
* m88k.c (m88k_begin_prologue): Remove superfluous backslash.
[gcc.git] / gcc / config / m88k / m88k.c
1 /* Subroutines for insn-output.c for Motorola 88000.
2 Copyright (C) 1988, 92, 93, 94, 95, 16, 1997 Free Software Foundation, Inc.
3 Contributed by Michael Tiemann (tiemann@mcc.com)
4 Currently maintained by (gcc@dg-rtp.dg.com)
5
6 This file is part of GNU CC.
7
8 GNU CC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 GNU CC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GNU CC; see the file COPYING. If not, write to
20 the Free Software Foundation, 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA. */
22
23 #include <stdio.h>
24 #include <sys/types.h>
25 #include <time.h>
26 #include <ctype.h>
27
28 #include "assert.h"
29 #include "config.h"
30 #include "rtl.h"
31 #include "regs.h"
32 #include "hard-reg-set.h"
33 #include "real.h"
34 #include "insn-config.h"
35 #include "conditions.h"
36 #include "insn-flags.h"
37 #include "output.h"
38 #include "insn-attr.h"
39 #include "tree.h"
40 #include "c-tree.h"
41 #include "expr.h"
42 #include "flags.h"
43
44 extern char *version_string;
45 extern time_t time ();
46 extern char *ctime ();
47 extern int flag_traditional;
48 extern FILE *asm_out_file;
49
50 static char out_rcs_id[] = "$What: <@(#) m88k.c,v 1.8> $";
51 static char tm_rcs_id [] = TM_RCS_ID;
52
53 char *m88k_pound_sign = ""; /* Either # for SVR4 or empty for SVR3 */
54 char *m88k_short_data;
55 char *m88k_version;
56 char m88k_volatile_code;
57
58 unsigned m88k_gp_threshold = 0;
59 int m88k_prologue_done = 0; /* Ln directives can now be emitted */
60 int m88k_function_number = 0; /* Counter unique to each function */
61 int m88k_fp_offset = 0; /* offset of frame pointer if used */
62 int m88k_stack_size = 0; /* size of allocated stack (including frame) */
63 int m88k_case_index;
64
65 rtx m88k_compare_reg; /* cmp output pseudo register */
66 rtx m88k_compare_op0; /* cmpsi operand 0 */
67 rtx m88k_compare_op1; /* cmpsi operand 1 */
68
69 enum processor_type m88k_cpu; /* target cpu */
70 \f
71 /* Determine what instructions are needed to manufacture the integer VALUE
72 in the given MODE. */
73
74 enum m88k_instruction
75 classify_integer (mode, value)
76 enum machine_mode mode;
77 register int value;
78 {
79 register int mask;
80
81 if (value == 0)
82 return m88k_zero;
83 else if (SMALL_INTVAL (value))
84 return m88k_or;
85 else if (SMALL_INTVAL (-value))
86 return m88k_subu;
87 else if (mode == HImode)
88 return m88k_or_lo16;
89 else if (mode == QImode)
90 return m88k_or_lo8;
91 else if ((value & 0xffff) == 0)
92 return m88k_oru_hi16;
93 else if (integer_ok_for_set (value))
94 return m88k_set;
95 else
96 return m88k_oru_or;
97 }
98
99 /* Return the bit number in a compare word corresponding to CONDITION. */
100
101 int
102 condition_value (condition)
103 rtx condition;
104 {
105 switch (GET_CODE (condition))
106 {
107 case EQ: return 2;
108 case NE: return 3;
109 case GT: return 4;
110 case LE: return 5;
111 case LT: return 6;
112 case GE: return 7;
113 case GTU: return 8;
114 case LEU: return 9;
115 case LTU: return 10;
116 case GEU: return 11;
117 default: abort ();
118 }
119 }
120
121 int
122 integer_ok_for_set (value)
123 register unsigned value;
124 {
125 /* All the "one" bits must be contiguous. If so, MASK + 1 will be
126 a power of two or zero. */
127 register unsigned mask = (value | (value - 1));
128 return (value && POWER_OF_2_or_0 (mask + 1));
129 }
130
131 char *
132 output_load_const_int (mode, operands)
133 enum machine_mode mode;
134 rtx *operands;
135 {
136 static char *patterns[] =
137 { "or %0,%#r0,0",
138 "or %0,%#r0,%1",
139 "subu %0,%#r0,%n1",
140 "or %0,%#r0,%h1",
141 "or %0,%#r0,%q1",
142 "set %0,%#r0,%s1",
143 "or.u %0,%#r0,%X1",
144 "or.u %0,%#r0,%X1\n\tor %0,%0,%x1",
145 };
146
147 if (! REG_P (operands[0])
148 || GET_CODE (operands[1]) != CONST_INT)
149 abort ();
150 return patterns[classify_integer (mode, INTVAL (operands[1]))];
151 }
152
153 /* These next two routines assume that floating point numbers are represented
154 in a manner which is consistent between host and target machines. */
155
156 char *
157 output_load_const_float (operands)
158 rtx *operands;
159 {
160 /* These can return 0 under some circumstances when cross-compiling. */
161 operands[0] = operand_subword (operands[0], 0, 0, SFmode);
162 operands[1] = operand_subword (operands[1], 0, 0, SFmode);
163
164 return output_load_const_int (SImode, operands);
165 }
166
167 char *
168 output_load_const_double (operands)
169 rtx *operands;
170 {
171 rtx latehalf[2];
172
173 /* These can return zero on some cross-compilers, but there's nothing
174 we can do about it. */
175 latehalf[0] = operand_subword (operands[0], 1, 0, DFmode);
176 latehalf[1] = operand_subword (operands[1], 1, 0, DFmode);
177
178 operands[0] = operand_subword (operands[0], 0, 0, DFmode);
179 operands[1] = operand_subword (operands[1], 0, 0, DFmode);
180
181 output_asm_insn (output_load_const_int (SImode, operands), operands);
182
183 operands[0] = latehalf[0];
184 operands[1] = latehalf[1];
185
186 return output_load_const_int (SImode, operands);
187 }
188
189 char *
190 output_load_const_dimode (operands)
191 rtx *operands;
192 {
193 rtx latehalf[2];
194
195 latehalf[0] = operand_subword (operands[0], 1, 0, DImode);
196 latehalf[1] = operand_subword (operands[1], 1, 0, DImode);
197
198 operands[0] = operand_subword (operands[0], 0, 0, DImode);
199 operands[1] = operand_subword (operands[1], 0, 0, DImode);
200
201 output_asm_insn (output_load_const_int (SImode, operands), operands);
202
203 operands[0] = latehalf[0];
204 operands[1] = latehalf[1];
205
206 return output_load_const_int (SImode, operands);
207 }
208 \f
209 /* Emit insns to move operands[1] into operands[0].
210
211 Return 1 if we have written out everything that needs to be done to
212 do the move. Otherwise, return 0 and the caller will emit the move
213 normally.
214
215 SCRATCH if non zero can be used as a scratch register for the move
216 operation. It is provided by a SECONDARY_RELOAD_* macro if needed. */
217
218 int
219 emit_move_sequence (operands, mode, scratch)
220 rtx *operands;
221 enum machine_mode mode;
222 rtx scratch;
223 {
224 register rtx operand0 = operands[0];
225 register rtx operand1 = operands[1];
226
227 if (CONSTANT_P (operand1) && flag_pic
228 && pic_address_needs_scratch (operand1))
229 operands[1] = operand1 = legitimize_address (1, operand1, 0, 0);
230
231 /* Handle most common case first: storing into a register. */
232 if (register_operand (operand0, mode))
233 {
234 if (register_operand (operand1, mode)
235 || (GET_CODE (operand1) == CONST_INT && SMALL_INT (operand1))
236 || GET_CODE (operand1) == HIGH
237 /* Only `general_operands' can come here, so MEM is ok. */
238 || GET_CODE (operand1) == MEM)
239 {
240 /* Run this case quickly. */
241 emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1));
242 return 1;
243 }
244 }
245 else if (GET_CODE (operand0) == MEM)
246 {
247 if (register_operand (operand1, mode)
248 || (operand1 == const0_rtx && GET_MODE_SIZE (mode) <= UNITS_PER_WORD))
249 {
250 /* Run this case quickly. */
251 emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1));
252 return 1;
253 }
254 if (! reload_in_progress && ! reload_completed)
255 {
256 operands[0] = validize_mem (operand0);
257 operands[1] = operand1 = force_reg (mode, operand1);
258 }
259 }
260
261 /* Simplify the source if we need to. */
262 if (GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode))
263 {
264 if (GET_CODE (operand1) != CONST_INT
265 && GET_CODE (operand1) != CONST_DOUBLE)
266 {
267 rtx temp = ((reload_in_progress || reload_completed)
268 ? operand0 : 0);
269 operands[1] = legitimize_address (flag_pic
270 && symbolic_address_p (operand1),
271 operand1, temp, scratch);
272 if (mode != SImode)
273 operands[1] = gen_rtx (SUBREG, mode, operands[1], 0);
274 }
275 }
276
277 /* Now have insn-emit do whatever it normally does. */
278 return 0;
279 }
280
281 /* Return a legitimate reference for ORIG (either an address or a MEM)
282 using the register REG. If PIC and the address is already
283 position-independent, use ORIG. Newly generated position-independent
284 addresses go into a reg. This is REG if non zero, otherwise we
285 allocate register(s) as necessary. If this is called during reload,
286 and we need a second temp register, then we use SCRATCH, which is
287 provided via the SECONDARY_INPUT_RELOAD_CLASS mechanism. */
288
289 struct rtx_def *
290 legitimize_address (pic, orig, reg, scratch)
291 int pic;
292 rtx orig;
293 rtx reg;
294 rtx scratch;
295 {
296 rtx addr = (GET_CODE (orig) == MEM ? XEXP (orig, 0) : orig);
297 rtx new = orig;
298 rtx temp, insn;
299
300 if (pic)
301 {
302 if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
303 {
304 if (reg == 0)
305 {
306 if (reload_in_progress || reload_completed)
307 abort ();
308 else
309 reg = gen_reg_rtx (Pmode);
310 }
311
312 if (flag_pic == 2)
313 {
314 /* If not during reload, allocate another temp reg here for
315 loading in the address, so that these instructions can be
316 optimized properly. */
317 temp = ((reload_in_progress || reload_completed)
318 ? reg : gen_reg_rtx (Pmode));
319
320 emit_insn (gen_rtx (SET, VOIDmode, temp,
321 gen_rtx (HIGH, SImode,
322 gen_rtx (UNSPEC, SImode,
323 gen_rtvec (1, addr),
324 0))));
325 emit_insn (gen_rtx (SET, VOIDmode, temp,
326 gen_rtx (LO_SUM, SImode, temp,
327 gen_rtx (UNSPEC, SImode,
328 gen_rtvec (1, addr),
329 0))));
330 addr = temp;
331 }
332 new = gen_rtx (MEM, Pmode,
333 gen_rtx (PLUS, SImode,
334 pic_offset_table_rtx, addr));
335 current_function_uses_pic_offset_table = 1;
336 RTX_UNCHANGING_P (new) = 1;
337 insn = emit_move_insn (reg, new);
338 /* Put a REG_EQUAL note on this insn, so that it can be optimized
339 by loop. */
340 REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL, orig,
341 REG_NOTES (insn));
342 new = reg;
343 }
344 else if (GET_CODE (addr) == CONST)
345 {
346 rtx base, offset;
347
348 if (GET_CODE (XEXP (addr, 0)) == PLUS
349 && XEXP (XEXP (addr, 0), 0) == pic_offset_table_rtx)
350 return orig;
351
352 if (reg == 0)
353 {
354 if (reload_in_progress || reload_completed)
355 abort ();
356 else
357 reg = gen_reg_rtx (Pmode);
358 }
359
360 if (GET_CODE (XEXP (addr, 0)) != PLUS) abort ();
361
362 base = legitimize_address (1, XEXP (XEXP (addr, 0), 0), reg, 0);
363 addr = legitimize_address (1, XEXP (XEXP (addr, 0), 1),
364 base == reg ? 0 : reg, 0);
365
366 if (GET_CODE (addr) == CONST_INT)
367 {
368 if (ADD_INT (addr))
369 return plus_constant_for_output (base, INTVAL (addr));
370 else if (! reload_in_progress && ! reload_completed)
371 addr = force_reg (Pmode, addr);
372 /* We can't create any new registers during reload, so use the
373 SCRATCH reg provided by the reload_insi pattern. */
374 else if (scratch)
375 {
376 emit_move_insn (scratch, addr);
377 addr = scratch;
378 }
379 else
380 /* If we reach here, then the SECONDARY_INPUT_RELOAD_CLASS
381 macro needs to be adjusted so that a scratch reg is provided
382 for this address. */
383 abort ();
384 }
385 new = gen_rtx (PLUS, SImode, base, addr);
386 /* Should we set special REG_NOTEs here? */
387 }
388 }
389 else if (! SHORT_ADDRESS_P (addr, temp))
390 {
391 if (reg == 0)
392 {
393 if (reload_in_progress || reload_completed)
394 abort ();
395 else
396 reg = gen_reg_rtx (Pmode);
397 }
398
399 emit_insn (gen_rtx (SET, VOIDmode,
400 reg, gen_rtx (HIGH, SImode, addr)));
401 new = gen_rtx (LO_SUM, SImode, reg, addr);
402 }
403
404 if (new != orig
405 && GET_CODE (orig) == MEM)
406 {
407 new = gen_rtx (MEM, GET_MODE (orig), new);
408 RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (orig);
409 MEM_VOLATILE_P (new) = MEM_VOLATILE_P (orig);
410 MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (orig);
411 }
412 return new;
413 }
414 \f
415 /* Support functions for code to emit a block move. There are four methods
416 used to perform the block move:
417 + call memcpy
418 + call the looping library function, e.g. __movstrSI64n8
419 + call a non-looping library function, e.g. __movstrHI15x11
420 + produce an inline sequence of ld/st instructions
421
422 The parameters below describe the library functions produced by
423 movstr-m88k.sh. */
424
425 #define MOVSTR_LOOP 64 /* __movstrSI64n68 .. __movstrSI64n8 */
426 #define MOVSTR_QI 16 /* __movstrQI16x16 .. __movstrQI16x2 */
427 #define MOVSTR_HI 48 /* __movstrHI48x48 .. __movstrHI48x4 */
428 #define MOVSTR_SI 96 /* __movstrSI96x96 .. __movstrSI96x8 */
429 #define MOVSTR_DI 96 /* __movstrDI96x96 .. __movstrDI96x16 */
430 #define MOVSTR_ODD_HI 16 /* __movstrHI15x15 .. __movstrHI15x5 */
431 #define MOVSTR_ODD_SI 48 /* __movstrSI47x47 .. __movstrSI47x11,
432 __movstrSI46x46 .. __movstrSI46x10,
433 __movstrSI45x45 .. __movstrSI45x9 */
434 #define MOVSTR_ODD_DI 48 /* __movstrDI47x47 .. __movstrDI47x23,
435 __movstrDI46x46 .. __movstrDI46x22,
436 __movstrDI45x45 .. __movstrDI45x21,
437 __movstrDI44x44 .. __movstrDI44x20,
438 __movstrDI43x43 .. __movstrDI43x19,
439 __movstrDI42x42 .. __movstrDI42x18,
440 __movstrDI41x41 .. __movstrDI41x17 */
441
442 /* Limits for using the non-looping movstr functions. For the m88100
443 processor, we assume the source and destination are word aligned.
444 The QImode and HImode limits are the break even points where memcpy
445 does just as well and beyond which memcpy does better. For the
446 m88110, we tend to assume double word alignment, but also analyze
447 the word aligned cases. The analysis is complicated because memcpy
448 may use the cache control instructions for better performance. */
449
450 #define MOVSTR_QI_LIMIT_88100 13
451 #define MOVSTR_HI_LIMIT_88100 38
452 #define MOVSTR_SI_LIMIT_88100 MOVSTR_SI
453 #define MOVSTR_DI_LIMIT_88100 MOVSTR_SI
454
455 #define MOVSTR_QI_LIMIT_88000 16
456 #define MOVSTR_HI_LIMIT_88000 38
457 #define MOVSTR_SI_LIMIT_88000 72
458 #define MOVSTR_DI_LIMIT_88000 72
459
460 #define MOVSTR_QI_LIMIT_88110 16
461 #define MOVSTR_HI_LIMIT_88110 38
462 #define MOVSTR_SI_LIMIT_88110 72
463 #define MOVSTR_DI_LIMIT_88110 72
464
465 static enum machine_mode mode_from_align[] =
466 {VOIDmode, QImode, HImode, VOIDmode, SImode,
467 VOIDmode, VOIDmode, VOIDmode, DImode};
468 static int max_from_align[] = {0, MOVSTR_QI, MOVSTR_HI, 0, MOVSTR_SI,
469 0, 0, 0, MOVSTR_DI};
470 static int all_from_align[] = {0, MOVSTR_QI, MOVSTR_ODD_HI, 0, MOVSTR_ODD_SI,
471 0, 0, 0, MOVSTR_ODD_DI};
472
473 static int best_from_align[3][9] =
474 {0, MOVSTR_QI_LIMIT_88100, MOVSTR_HI_LIMIT_88100, 0, MOVSTR_SI_LIMIT_88100,
475 0, 0, 0, MOVSTR_DI_LIMIT_88100,
476 0, MOVSTR_QI_LIMIT_88110, MOVSTR_HI_LIMIT_88110, 0, MOVSTR_SI_LIMIT_88110,
477 0, 0, 0, MOVSTR_DI_LIMIT_88110,
478 0, MOVSTR_QI_LIMIT_88000, MOVSTR_HI_LIMIT_88000, 0, MOVSTR_SI_LIMIT_88000,
479 0, 0, 0, MOVSTR_DI_LIMIT_88000};
480
481 static void block_move_loop ();
482 static void block_move_no_loop ();
483 static void block_move_sequence ();
484
485 /* Emit code to perform a block move. Choose the best method.
486
487 OPERANDS[0] is the destination.
488 OPERANDS[1] is the source.
489 OPERANDS[2] is the size.
490 OPERANDS[3] is the alignment safe to use. */
491
492 void
493 expand_block_move (dest_mem, src_mem, operands)
494 rtx dest_mem;
495 rtx src_mem;
496 rtx *operands;
497 {
498 int align = INTVAL (operands[3]);
499 int constp = (GET_CODE (operands[2]) == CONST_INT);
500 int bytes = (constp ? INTVAL (operands[2]) : 0);
501 int target = (int) m88k_cpu;
502
503 assert (PROCESSOR_M88100 == 0);
504 assert (PROCESSOR_M88110 == 1);
505 assert (PROCESSOR_M88000 == 2);
506
507 if (constp && bytes <= 0)
508 return;
509
510 /* Determine machine mode to do move with. */
511 if (align > 4 && !TARGET_88110)
512 align = 4;
513 else if (align <= 0 || align == 3)
514 abort (); /* block move invalid alignment. */
515
516 if (constp && bytes <= 3 * align)
517 block_move_sequence (operands[0], dest_mem, operands[1], src_mem,
518 bytes, align, 0);
519
520 else if (constp && bytes <= best_from_align[target][align])
521 block_move_no_loop (operands[0], dest_mem, operands[1], src_mem,
522 bytes, align);
523
524 else if (constp && align == 4 && TARGET_88100)
525 block_move_loop (operands[0], dest_mem, operands[1], src_mem,
526 bytes, align);
527
528 else
529 {
530 #ifdef TARGET_MEM_FUNCTIONS
531 emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0,
532 VOIDmode, 3,
533 operands[0], Pmode,
534 operands[1], Pmode,
535 convert_to_mode (TYPE_MODE (sizetype), operands[2],
536 TREE_UNSIGNED (sizetype)),
537 TYPE_MODE (sizetype));
538 #else
539 emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), 0,
540 VOIDmode, 3,
541 operands[1], Pmode,
542 operands[0], Pmode,
543 convert_to_mode (TYPE_MODE (integer_type_node),
544 operands[2],
545 TREE_UNSIGNED (integer_type_node)),
546 TYPE_MODE (integer_type_node));
547 #endif
548 }
549 }
550
551 /* Emit code to perform a block move by calling a looping movstr library
552 function. SIZE and ALIGN are known constants. DEST and SRC are
553 registers. */
554
555 static void
556 block_move_loop (dest, dest_mem, src, src_mem, size, align)
557 rtx dest, dest_mem;
558 rtx src, src_mem;
559 int size;
560 int align;
561 {
562 enum machine_mode mode;
563 int count;
564 int units;
565 int remainder;
566 rtx offset_rtx;
567 rtx value_rtx;
568 char entry[30];
569 tree entry_name;
570
571 /* Determine machine mode to do move with. */
572 if (align != 4)
573 abort ();
574
575 /* Determine the structure of the loop. */
576 count = size / MOVSTR_LOOP;
577 units = (size - count * MOVSTR_LOOP) / align;
578
579 if (units < 2)
580 {
581 count--;
582 units += MOVSTR_LOOP / align;
583 }
584
585 if (count <= 0)
586 {
587 block_move_no_loop (dest, dest_mem, src, src_mem, size, align);
588 return;
589 }
590
591 remainder = size - count * MOVSTR_LOOP - units * align;
592
593 mode = mode_from_align[align];
594 sprintf (entry, "__movstr%s%dn%d",
595 GET_MODE_NAME (mode), MOVSTR_LOOP, units * align);
596 entry_name = get_identifier (entry);
597
598 offset_rtx = gen_rtx (CONST_INT, VOIDmode,
599 MOVSTR_LOOP + (1 - units) * align);
600
601 value_rtx = gen_rtx (MEM, MEM_IN_STRUCT_P (src_mem) ? mode : BLKmode,
602 gen_rtx (PLUS, Pmode,
603 gen_rtx (REG, Pmode, 3),
604 offset_rtx));
605 RTX_UNCHANGING_P (value_rtx) = RTX_UNCHANGING_P (src_mem);
606 MEM_VOLATILE_P (value_rtx) = MEM_VOLATILE_P (src_mem);
607 MEM_IN_STRUCT_P (value_rtx) = MEM_IN_STRUCT_P (src_mem);
608
609 emit_insn (gen_call_movstrsi_loop
610 (gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (entry_name)),
611 dest, src, offset_rtx, value_rtx,
612 gen_rtx (REG, mode, ((units & 1) ? 4 : 5)),
613 gen_rtx (CONST_INT, VOIDmode, count)));
614
615 if (remainder)
616 block_move_sequence (gen_rtx (REG, Pmode, 2), dest_mem,
617 gen_rtx (REG, Pmode, 3), src_mem,
618 remainder, align, MOVSTR_LOOP + align);
619 }
620
621 /* Emit code to perform a block move by calling a non-looping library
622 function. SIZE and ALIGN are known constants. DEST and SRC are
623 registers. OFFSET is the known starting point for the output pattern. */
624
625 static void
626 block_move_no_loop (dest, dest_mem, src, src_mem, size, align)
627 rtx dest, dest_mem;
628 rtx src, src_mem;
629 int size;
630 int align;
631 {
632 enum machine_mode mode = mode_from_align[align];
633 int units = size / align;
634 int remainder = size - units * align;
635 int most;
636 int value_reg;
637 rtx offset_rtx;
638 rtx value_rtx;
639 char entry[30];
640 tree entry_name;
641
642 if (remainder && size <= all_from_align[align])
643 {
644 most = all_from_align[align] - (align - remainder);
645 remainder = 0;
646 }
647 else
648 {
649 most = max_from_align[align];
650 }
651
652 sprintf (entry, "__movstr%s%dx%d",
653 GET_MODE_NAME (mode), most, size - remainder);
654 entry_name = get_identifier (entry);
655
656 offset_rtx = gen_rtx (CONST_INT, VOIDmode, most - (size - remainder));
657
658 value_rtx = gen_rtx (MEM, MEM_IN_STRUCT_P (src_mem) ? mode : BLKmode,
659 gen_rtx (PLUS, Pmode,
660 gen_rtx (REG, Pmode, 3),
661 offset_rtx));
662 RTX_UNCHANGING_P (value_rtx) = RTX_UNCHANGING_P (src_mem);
663 MEM_VOLATILE_P (value_rtx) = MEM_VOLATILE_P (src_mem);
664 MEM_IN_STRUCT_P (value_rtx) = MEM_IN_STRUCT_P (src_mem);
665
666 value_reg = ((((most - (size - remainder)) / align) & 1) == 0
667 ? (align == 8 ? 6 : 5) : 4);
668
669 emit_insn (gen_call_block_move
670 (gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (entry_name)),
671 dest, src, offset_rtx, value_rtx,
672 gen_rtx (REG, mode, value_reg)));
673
674 if (remainder)
675 block_move_sequence (gen_rtx (REG, Pmode, 2), dest_mem,
676 gen_rtx (REG, Pmode, 3), src_mem,
677 remainder, align, most);
678 }
679
680 /* Emit code to perform a block move with an offset sequence of ld/st
681 instructions (..., ld 0, st 1, ld 1, st 0, ...). SIZE and ALIGN are
682 known constants. DEST and SRC are registers. OFFSET is the known
683 starting point for the output pattern. */
684
685 static void
686 block_move_sequence (dest, dest_mem, src, src_mem, size, align, offset)
687 rtx dest, dest_mem;
688 rtx src, src_mem;
689 int size;
690 int align;
691 int offset;
692 {
693 rtx temp[2];
694 enum machine_mode mode[2];
695 int amount[2];
696 int active[2];
697 int phase = 0;
698 int next;
699 int offset_ld = offset;
700 int offset_st = offset;
701
702 active[0] = active[1] = FALSE;
703
704 /* Establish parameters for the first load and for the second load if
705 it is known to be the same mode as the first. */
706 amount[0] = amount[1] = align;
707 mode[0] = mode_from_align[align];
708 temp[0] = gen_reg_rtx (mode[0]);
709 if (size >= 2 * align)
710 {
711 mode[1] = mode[0];
712 temp[1] = gen_reg_rtx (mode[1]);
713 }
714
715 do
716 {
717 rtx srcp, dstp;
718 next = phase;
719 phase = !phase;
720
721 if (size > 0)
722 {
723 /* Change modes as the sequence tails off. */
724 if (size < amount[next])
725 {
726 amount[next] = (size >= 4 ? 4 : (size >= 2 ? 2 : 1));
727 mode[next] = mode_from_align[amount[next]];
728 temp[next] = gen_reg_rtx (mode[next]);
729 }
730 size -= amount[next];
731 srcp = gen_rtx (MEM,
732 MEM_IN_STRUCT_P (src_mem) ? mode[next] : BLKmode,
733 gen_rtx (PLUS, Pmode, src,
734 gen_rtx (CONST_INT, SImode, offset_ld)));
735 RTX_UNCHANGING_P (srcp) = RTX_UNCHANGING_P (src_mem);
736 MEM_VOLATILE_P (srcp) = MEM_VOLATILE_P (src_mem);
737 MEM_IN_STRUCT_P (srcp) = MEM_IN_STRUCT_P (src_mem);
738 emit_insn (gen_rtx (SET, VOIDmode, temp[next], srcp));
739 offset_ld += amount[next];
740 active[next] = TRUE;
741 }
742
743 if (active[phase])
744 {
745 active[phase] = FALSE;
746 dstp = gen_rtx (MEM,
747 MEM_IN_STRUCT_P (dest_mem) ? mode[phase] : BLKmode,
748 gen_rtx (PLUS, Pmode, dest,
749 gen_rtx (CONST_INT, SImode, offset_st)));
750 RTX_UNCHANGING_P (dstp) = RTX_UNCHANGING_P (dest_mem);
751 MEM_VOLATILE_P (dstp) = MEM_VOLATILE_P (dest_mem);
752 MEM_IN_STRUCT_P (dstp) = MEM_IN_STRUCT_P (dest_mem);
753 emit_insn (gen_rtx (SET, VOIDmode, dstp, temp[phase]));
754 offset_st += amount[phase];
755 }
756 }
757 while (active[next]);
758 }
759 \f
760 /* Emit the code to do an AND operation. */
761
762 char *
763 output_and (operands)
764 rtx operands[];
765 {
766 unsigned int value;
767
768 if (REG_P (operands[2]))
769 return "and %0,%1,%2";
770
771 value = INTVAL (operands[2]);
772 if (SMALL_INTVAL (value))
773 return "mask %0,%1,%2";
774 else if ((value & 0xffff0000) == 0xffff0000)
775 return "and %0,%1,%x2";
776 else if ((value & 0xffff) == 0xffff)
777 return "and.u %0,%1,%X2";
778 else if ((value & 0xffff) == 0)
779 return "mask.u %0,%1,%X2";
780 else if (integer_ok_for_set (~value))
781 return "clr %0,%1,%S2";
782 else
783 return "and.u %0,%1,%X2\n\tand %0,%0,%x2";
784 }
785
786 /* Emit the code to do an inclusive OR operation. */
787
788 char *
789 output_ior (operands)
790 rtx operands[];
791 {
792 unsigned int value;
793
794 if (REG_P (operands[2]))
795 return "or %0,%1,%2";
796
797 value = INTVAL (operands[2]);
798 if (SMALL_INTVAL (value))
799 return "or %0,%1,%2";
800 else if ((value & 0xffff) == 0)
801 return "or.u %0,%1,%X2";
802 else if (integer_ok_for_set (value))
803 return "set %0,%1,%s2";
804 else
805 return "or.u %0,%1,%X2\n\tor %0,%0,%x2";
806 }
807
808 /* Emit the instructions for doing an XOR. */
809
810 char *
811 output_xor (operands)
812 rtx operands[];
813 {
814 unsigned int value;
815
816 if (REG_P (operands[2]))
817 return "xor %0,%1,%2";
818
819 value = INTVAL (operands[2]);
820 if (SMALL_INTVAL (value))
821 return "xor %0,%1,%2";
822 else if ((value & 0xffff) == 0)
823 return "xor.u %0,%1,%X2";
824 else
825 return "xor.u %0,%1,%X2\n\txor %0,%0,%x2";
826 }
827 \f
828 /* Output a call. Normally this is just bsr or jsr, but this also deals with
829 accomplishing a branch after the call by incrementing r1. This requires
830 that various assembler bugs be accommodated. The 4.30 DG/UX assembler
831 requires that forward references not occur when computing the difference of
832 two labels. The [version?] Motorola assembler computes a word difference.
833 No doubt there's more to come!
834
835 It would seem the same idea could be used to tail call, but in this case,
836 the epilogue will be non-null. */
837
838 static rtx sb_name = 0;
839 static rtx sb_high = 0;
840 static rtx sb_low = 0;
841
842 char *
843 output_call (operands, addr)
844 rtx operands[];
845 rtx addr;
846 {
847 operands[0] = addr;
848 if (final_sequence)
849 {
850 rtx jump;
851 rtx seq_insn;
852
853 /* This can be generalized, but there is currently no need. */
854 if (XVECLEN (final_sequence, 0) != 2)
855 abort ();
856
857 /* The address of interior insns is not computed, so use the sequence. */
858 seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0)));
859 jump = XVECEXP (final_sequence, 0, 1);
860 if (GET_CODE (jump) == JUMP_INSN)
861 {
862 rtx low, high;
863 char *last;
864 rtx dest = XEXP (SET_SRC (PATTERN (jump)), 0);
865 int delta = 4 * (insn_addresses[INSN_UID (dest)]
866 - insn_addresses[INSN_UID (seq_insn)]
867 - 2);
868 #if (MONITOR_GCC & 0x2) /* How often do long branches happen? */
869 if ((unsigned) (delta + 0x8000) >= 0x10000)
870 warning ("Internal gcc monitor: short-branch(%x)", delta);
871 #endif
872
873 /* Delete the jump. */
874 PUT_CODE (jump, NOTE);
875 NOTE_LINE_NUMBER (jump) = NOTE_INSN_DELETED;
876 NOTE_SOURCE_FILE (jump) = 0;
877
878 /* We only do this optimization if -O2, modifying the value of
879 r1 in the delay slot confuses debuggers and profilers on some
880 systems.
881
882 If we loose, we must use the non-delay form. This is unlikely
883 to ever happen. If it becomes a problem, claim that a call
884 has two delay slots and only the second can be filled with
885 a jump.
886
887 The 88110 can lose when a jsr.n r1 is issued and a page fault
888 occurs accessing the delay slot. So don't use jsr.n form when
889 jumping thru r1.
890 */
891 #ifdef AS_BUG_IMMEDIATE_LABEL /* The assembler restricts immediate values. */
892 if (optimize < 2
893 || ! ADD_INTVAL (delta * 2)
894 #else
895 if (optimize < 2
896 || ! ADD_INTVAL (delta)
897 #endif
898 || (REG_P (addr) && REGNO (addr) == 1))
899 {
900 operands[1] = dest;
901 return (REG_P (addr)
902 ? "jsr %0\n\tbr %l1"
903 : (flag_pic
904 ? "bsr %0#plt\n\tbr %l1"
905 : "bsr %0\n\tbr %l1"));
906 }
907
908 /* Output the short branch form. */
909 output_asm_insn ((REG_P (addr)
910 ? "jsr.n %0"
911 : (flag_pic ? "bsr.n %0#plt" : "bsr.n %0")),
912 operands);
913
914 #ifdef USE_GAS
915 last = (delta < 0
916 ? "subu %#r1,%#r1,.-%l0+4"
917 : "addu %#r1,%#r1,%l0-.-4");
918 operands[0] = dest;
919 #else
920 operands[0] = gen_label_rtx ();
921 operands[1] = gen_label_rtx ();
922 if (delta < 0)
923 {
924 low = dest;
925 high = operands[1];
926 last = "subu %#r1,%#r1,%l0\n%l1:";
927 }
928 else
929 {
930 low = operands[1];
931 high = dest;
932 last = "addu %#r1,%#r1,%l0\n%l1:";
933 }
934
935 /* Record the values to be computed later as "def name,high-low". */
936 sb_name = gen_rtx (EXPR_LIST, VOIDmode, operands[0], sb_name);
937 sb_high = gen_rtx (EXPR_LIST, VOIDmode, high, sb_high);
938 sb_low = gen_rtx (EXPR_LIST, VOIDmode, low, sb_low);
939 #endif /* Don't USE_GAS */
940
941 return last;
942 }
943 }
944 return (REG_P (addr)
945 ? "jsr%. %0"
946 : (flag_pic ? "bsr%. %0#plt" : "bsr%. %0"));
947 }
948
949 static void
950 output_short_branch_defs (stream)
951 FILE *stream;
952 {
953 char name[256], high[256], low[256];
954
955 for (; sb_name && sb_high && sb_low;
956 sb_name = XEXP (sb_name, 1),
957 sb_high = XEXP (sb_high, 1),
958 sb_low = XEXP (sb_low, 1))
959 {
960 ASM_GENERATE_INTERNAL_LABEL
961 (name, "L", CODE_LABEL_NUMBER (XEXP (sb_name, 0)));
962 ASM_GENERATE_INTERNAL_LABEL
963 (high, "L", CODE_LABEL_NUMBER (XEXP (sb_high, 0)));
964 ASM_GENERATE_INTERNAL_LABEL
965 (low, "L", CODE_LABEL_NUMBER (XEXP (sb_low, 0)));
966 /* This will change as the assembler requirements become known. */
967 fprintf (stream, "\t%s\t %s,%s-%s\n",
968 SET_ASM_OP, &name[1], &high[1], &low[1]);
969 }
970 if (sb_name || sb_high || sb_low)
971 abort ();
972 }
973 \f
974 /* Return truth value of the statement that this conditional branch is likely
975 to fall through. CONDITION, is the condition that JUMP_INSN is testing. */
976
977 int
978 mostly_false_jump (jump_insn, condition)
979 rtx jump_insn, condition;
980 {
981 rtx target_label = JUMP_LABEL (jump_insn);
982 rtx insnt, insnj;
983
984 /* Much of this isn't computed unless we're optimizing. */
985 if (optimize == 0)
986 return 0;
987
988 /* Determine if one path or the other leads to a return. */
989 for (insnt = NEXT_INSN (target_label);
990 insnt;
991 insnt = NEXT_INSN (insnt))
992 {
993 if (GET_CODE (insnt) == JUMP_INSN)
994 break;
995 else if (GET_CODE (insnt) == INSN
996 && GET_CODE (PATTERN (insnt)) == SEQUENCE
997 && GET_CODE (XVECEXP (PATTERN (insnt), 0, 0)) == JUMP_INSN)
998 {
999 insnt = XVECEXP (PATTERN (insnt), 0, 0);
1000 break;
1001 }
1002 }
1003 if (insnt
1004 && (GET_CODE (PATTERN (insnt)) == RETURN
1005 || (GET_CODE (PATTERN (insnt)) == SET
1006 && GET_CODE (SET_SRC (PATTERN (insnt))) == REG
1007 && REGNO (SET_SRC (PATTERN (insnt))) == 1)))
1008 insnt = 0;
1009
1010 for (insnj = NEXT_INSN (jump_insn);
1011 insnj;
1012 insnj = NEXT_INSN (insnj))
1013 {
1014 if (GET_CODE (insnj) == JUMP_INSN)
1015 break;
1016 else if (GET_CODE (insnj) == INSN
1017 && GET_CODE (PATTERN (insnj)) == SEQUENCE
1018 && GET_CODE (XVECEXP (PATTERN (insnj), 0, 0)) == JUMP_INSN)
1019 {
1020 insnj = XVECEXP (PATTERN (insnj), 0, 0);
1021 break;
1022 }
1023 }
1024 if (insnj
1025 && (GET_CODE (PATTERN (insnj)) == RETURN
1026 || (GET_CODE (PATTERN (insnj)) == SET
1027 && GET_CODE (SET_SRC (PATTERN (insnj))) == REG
1028 && REGNO (SET_SRC (PATTERN (insnj))) == 1)))
1029 insnj = 0;
1030
1031 /* Predict to not return. */
1032 if ((insnt == 0) != (insnj == 0))
1033 return (insnt == 0);
1034
1035 /* Predict loops to loop. */
1036 for (insnt = PREV_INSN (target_label);
1037 insnt && GET_CODE (insnt) == NOTE;
1038 insnt = PREV_INSN (insnt))
1039 if (NOTE_LINE_NUMBER (insnt) == NOTE_INSN_LOOP_END)
1040 return 1;
1041 else if (NOTE_LINE_NUMBER (insnt) == NOTE_INSN_LOOP_BEG)
1042 return 0;
1043 else if (NOTE_LINE_NUMBER (insnt) == NOTE_INSN_LOOP_CONT)
1044 return 0;
1045
1046 /* Predict backward branches usually take. */
1047 if (final_sequence)
1048 insnj = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0)));
1049 else
1050 insnj = jump_insn;
1051 if (insn_addresses[INSN_UID (insnj)]
1052 > insn_addresses[INSN_UID (target_label)])
1053 return 0;
1054
1055 /* EQ tests are usually false and NE tests are usually true. Also,
1056 most quantities are positive, so we can make the appropriate guesses
1057 about signed comparisons against zero. Consider unsigned comparisons
1058 to be a range check and assume quantities to be in range. */
1059 switch (GET_CODE (condition))
1060 {
1061 case CONST_INT:
1062 /* Unconditional branch. */
1063 return 0;
1064 case EQ:
1065 return 1;
1066 case NE:
1067 return 0;
1068 case LE:
1069 case LT:
1070 case GEU:
1071 case GTU: /* Must get casesi right at least. */
1072 if (XEXP (condition, 1) == const0_rtx)
1073 return 1;
1074 break;
1075 case GE:
1076 case GT:
1077 case LEU:
1078 case LTU:
1079 if (XEXP (condition, 1) == const0_rtx)
1080 return 0;
1081 break;
1082 }
1083
1084 return 0;
1085 }
1086 \f
1087 /* Return true if the operand is a power of two and is a floating
1088 point type (to optimize division by power of two into multiplication). */
1089
1090 int
1091 real_power_of_2_operand (op, mode)
1092 rtx op;
1093 enum machine_mode mode;
1094 {
1095 union {
1096 REAL_VALUE_TYPE d;
1097 int i[sizeof (REAL_VALUE_TYPE) / sizeof (int)];
1098 struct { /* IEEE double precision format */
1099 unsigned sign : 1;
1100 unsigned exponent : 11;
1101 unsigned mantissa1 : 20;
1102 unsigned mantissa2;
1103 } s;
1104 struct { /* IEEE double format to quick check */
1105 unsigned sign : 1; /* if it fits in a float */
1106 unsigned exponent1 : 4;
1107 unsigned exponent2 : 7;
1108 unsigned mantissa1 : 20;
1109 unsigned mantissa2;
1110 } s2;
1111 } u;
1112
1113 if (GET_MODE (op) != DFmode && GET_MODE (op) != SFmode)
1114 return 0;
1115
1116 if (GET_CODE (op) != CONST_DOUBLE)
1117 return 0;
1118
1119 u.i[0] = CONST_DOUBLE_LOW (op);
1120 u.i[1] = CONST_DOUBLE_HIGH (op);
1121
1122 if (u.s.mantissa1 != 0 || u.s.mantissa2 != 0 /* not a power of two */
1123 || u.s.exponent == 0 /* constant 0.0 */
1124 || u.s.exponent == 0x7ff /* NAN */
1125 || (u.s2.exponent1 != 0x8 && u.s2.exponent1 != 0x7))
1126 return 0; /* const won't fit in float */
1127
1128 return 1;
1129 }
1130 \f
1131 /* Make OP legitimate for mode MODE. Currently this only deals with DFmode
1132 operands, putting them in registers and making CONST_DOUBLE values
1133 SFmode where possible. */
1134
1135 struct rtx_def *
1136 legitimize_operand (op, mode)
1137 rtx op;
1138 enum machine_mode mode;
1139 {
1140 rtx temp;
1141 union {
1142 union real_extract r;
1143 struct { /* IEEE double precision format */
1144 unsigned sign : 1;
1145 unsigned exponent : 11;
1146 unsigned mantissa1 : 20;
1147 unsigned mantissa2;
1148 } d;
1149 struct { /* IEEE double format to quick check */
1150 unsigned sign : 1; /* if it fits in a float */
1151 unsigned exponent1 : 4;
1152 unsigned exponent2 : 7;
1153 unsigned mantissa1 : 20;
1154 unsigned mantissa2;
1155 } s;
1156 } u;
1157
1158 if (GET_CODE (op) == REG || mode != DFmode)
1159 return op;
1160
1161 if (GET_CODE (op) == CONST_DOUBLE)
1162 {
1163 bcopy (&CONST_DOUBLE_LOW (op), &u.r, sizeof u);
1164 if (u.d.exponent != 0x7ff /* NaN */
1165 && u.d.mantissa2 == 0 /* Mantissa fits */
1166 && (u.s.exponent1 == 0x8 || u.s.exponent1 == 0x7) /* Exponent fits */
1167 && (temp = simplify_unary_operation (FLOAT_TRUNCATE, SFmode,
1168 op, mode)) != 0)
1169 return gen_rtx (FLOAT_EXTEND, mode, force_reg (SFmode, temp));
1170 }
1171 else if (register_operand (op, mode))
1172 return op;
1173
1174 return force_reg (mode, op);
1175 }
1176 \f
1177 /* Return true if OP is a suitable input for a move insn. */
1178
1179 int
1180 move_operand (op, mode)
1181 rtx op;
1182 enum machine_mode mode;
1183 {
1184 if (register_operand (op, mode))
1185 return 1;
1186 if (GET_CODE (op) == CONST_INT)
1187 return (classify_integer (mode, INTVAL (op)) < m88k_oru_hi16);
1188 if (GET_MODE (op) != mode)
1189 return 0;
1190 if (GET_CODE (op) == SUBREG)
1191 op = SUBREG_REG (op);
1192 if (GET_CODE (op) != MEM)
1193 return 0;
1194
1195 op = XEXP (op, 0);
1196 if (GET_CODE (op) == LO_SUM)
1197 return (REG_P (XEXP (op, 0))
1198 && symbolic_address_p (XEXP (op, 1)));
1199 return memory_address_p (mode, op);
1200 }
1201
1202 /* Return true if OP is suitable for a call insn. */
1203
1204 int
1205 call_address_operand (op, mode)
1206 rtx op;
1207 enum machine_mode mode;
1208 {
1209 return (REG_P (op) || symbolic_address_p (op));
1210 }
1211
1212 /* Returns true if OP is either a symbol reference or a sum of a symbol
1213 reference and a constant. */
1214
1215 int
1216 symbolic_address_p (op)
1217 register rtx op;
1218 {
1219 switch (GET_CODE (op))
1220 {
1221 case SYMBOL_REF:
1222 case LABEL_REF:
1223 return 1;
1224
1225 case CONST:
1226 op = XEXP (op, 0);
1227 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1228 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1229 && GET_CODE (XEXP (op, 1)) == CONST_INT);
1230
1231 default:
1232 return 0;
1233 }
1234 }
1235
1236 /* Return true if OP is a register or const0_rtx. */
1237
1238 int
1239 reg_or_0_operand (op, mode)
1240 rtx op;
1241 enum machine_mode mode;
1242 {
1243 return (op == const0_rtx || register_operand (op, mode));
1244 }
1245
1246 /* Nonzero if OP is a valid second operand for an arithmetic insn. */
1247
1248 int
1249 arith_operand (op, mode)
1250 rtx op;
1251 enum machine_mode mode;
1252 {
1253 return (register_operand (op, mode)
1254 || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
1255 }
1256
1257 /* Return true if OP is a register or 5 bit integer. */
1258
1259 int
1260 arith5_operand (op, mode)
1261 rtx op;
1262 enum machine_mode mode;
1263 {
1264 return (register_operand (op, mode)
1265 || (GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 32));
1266 }
1267
1268 int
1269 arith32_operand (op, mode)
1270 rtx op;
1271 enum machine_mode mode;
1272 {
1273 return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
1274 }
1275
1276 int
1277 arith64_operand (op, mode)
1278 rtx op;
1279 enum machine_mode mode;
1280 {
1281 return (register_operand (op, mode)
1282 || GET_CODE (op) == CONST_INT
1283 || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode));
1284 }
1285
1286 int
1287 int5_operand (op, mode)
1288 rtx op;
1289 enum machine_mode mode;
1290 {
1291 return (GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 32);
1292 }
1293
1294 int
1295 int32_operand (op, mode)
1296 rtx op;
1297 enum machine_mode mode;
1298 {
1299 return (GET_CODE (op) == CONST_INT);
1300 }
1301
1302 /* Return true if OP is a register or a valid immediate operand for
1303 addu or subu. */
1304
1305 int
1306 add_operand (op, mode)
1307 rtx op;
1308 enum machine_mode mode;
1309 {
1310 return (register_operand (op, mode)
1311 || (GET_CODE (op) == CONST_INT && ADD_INT (op)));
1312 }
1313
1314 /* Nonzero if this is a bitmask filling the bottom bits, for optimizing and +
1315 shift left combinations into a single mak instruction. */
1316
1317 int
1318 mak_mask_p (value)
1319 int value;
1320 {
1321 return (value && POWER_OF_2_or_0 (value + 1));
1322 }
1323
1324 int
1325 reg_or_bbx_mask_operand (op, mode)
1326 rtx op;
1327 enum machine_mode mode;
1328 {
1329 int value;
1330 if (register_operand (op, mode))
1331 return 1;
1332 if (GET_CODE (op) != CONST_INT)
1333 return 0;
1334
1335 value = INTVAL (op);
1336 if (POWER_OF_2 (value))
1337 return 1;
1338
1339 return 0;
1340 }
1341
1342 /* Return true if OP is valid to use in the context of a floating
1343 point operation. Special case 0.0, since we can use r0. */
1344
1345 int
1346 real_or_0_operand (op, mode)
1347 rtx op;
1348 enum machine_mode mode;
1349 {
1350 if (mode != SFmode && mode != DFmode)
1351 return 0;
1352
1353 return (register_operand (op, mode)
1354 || (GET_CODE (op) == CONST_DOUBLE
1355 && op == CONST0_RTX (mode)));
1356 }
1357
1358 /* Return true if OP is valid to use in the context of logic arithmetic
1359 on condition codes. */
1360
1361 int
1362 partial_ccmode_register_operand (op, mode)
1363 rtx op;
1364 enum machine_mode mode;
1365 {
1366 return register_operand (op, CCmode) || register_operand (op, CCEVENmode);
1367 }
1368
1369 /* Return true if OP is a relational operator. */
1370
1371 int
1372 relop (op, mode)
1373 rtx op;
1374 enum machine_mode mode;
1375 {
1376 switch (GET_CODE (op))
1377 {
1378 case EQ:
1379 case NE:
1380 case LT:
1381 case LE:
1382 case GE:
1383 case GT:
1384 case LTU:
1385 case LEU:
1386 case GEU:
1387 case GTU:
1388 return 1;
1389 default:
1390 return 0;
1391 }
1392 }
1393
1394 int
1395 even_relop (op, mode)
1396 rtx op;
1397 enum machine_mode mode;
1398 {
1399 switch (GET_CODE (op))
1400 {
1401 case EQ:
1402 case LT:
1403 case GT:
1404 case LTU:
1405 case GTU:
1406 return 1;
1407 default:
1408 return 0;
1409 }
1410 }
1411
1412 int
1413 odd_relop (op, mode)
1414 rtx op;
1415 enum machine_mode mode;
1416 {
1417 switch (GET_CODE (op))
1418 {
1419 case NE:
1420 case LE:
1421 case GE:
1422 case LEU:
1423 case GEU:
1424 return 1;
1425 default:
1426 return 0;
1427 }
1428 }
1429
1430 /* Return true if OP is a relational operator, and is not an unsigned
1431 relational operator. */
1432
1433 int
1434 relop_no_unsigned (op, mode)
1435 rtx op;
1436 enum machine_mode mode;
1437 {
1438 switch (GET_CODE (op))
1439 {
1440 case EQ:
1441 case NE:
1442 case LT:
1443 case LE:
1444 case GE:
1445 case GT:
1446 /* @@ What is this test doing? Why not use `mode'? */
1447 if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
1448 || GET_MODE (op) == DImode
1449 || GET_MODE_CLASS (GET_MODE (XEXP (op, 0))) == MODE_FLOAT
1450 || GET_MODE (XEXP (op, 0)) == DImode
1451 || GET_MODE_CLASS (GET_MODE (XEXP (op, 1))) == MODE_FLOAT
1452 || GET_MODE (XEXP (op, 1)) == DImode)
1453 return 0;
1454 return 1;
1455 default:
1456 return 0;
1457 }
1458 }
1459
1460 /* Return true if the code of this rtx pattern is EQ or NE. */
1461
1462 int
1463 equality_op (op, mode)
1464 rtx op;
1465 enum machine_mode mode;
1466 {
1467 return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
1468 }
1469
1470 /* Return true if the code of this rtx pattern is pc or label_ref. */
1471
1472 int
1473 pc_or_label_ref (op, mode)
1474 rtx op;
1475 enum machine_mode mode;
1476 {
1477 return (GET_CODE (op) == PC || GET_CODE (op) == LABEL_REF);
1478 }
1479 \f
1480 /* Output to FILE the start of the assembler file. */
1481
1482 struct options
1483 {
1484 char *string;
1485 int *variable;
1486 int on_value;
1487 };
1488
1489 static int
1490 output_option (file, sep, type, name, indent, pos, max)
1491 FILE *file;
1492 char *sep;
1493 char *type;
1494 char *name;
1495 char *indent;
1496 int pos;
1497 int max;
1498 {
1499 if (strlen (sep) + strlen (type) + strlen (name) + pos > max)
1500 {
1501 fprintf (file, indent);
1502 return fprintf (file, "%s%s", type, name);
1503 }
1504 return pos + fprintf (file, "%s%s%s", sep, type, name);
1505 }
1506
1507 static struct { char *name; int value; } m_options[] = TARGET_SWITCHES;
1508
1509 static void
1510 output_options (file, f_options, f_len, W_options, W_len,
1511 pos, max, sep, indent, term)
1512 FILE *file;
1513 struct options *f_options;
1514 struct options *W_options;
1515 int f_len, W_len;
1516 int pos;
1517 int max;
1518 char *indent;
1519 char *term;
1520 {
1521 register int j;
1522
1523 if (optimize)
1524 pos = output_option (file, sep, "-O", "", indent, pos, max);
1525 if (write_symbols != NO_DEBUG)
1526 pos = output_option (file, sep, "-g", "", indent, pos, max);
1527 if (flag_traditional)
1528 pos = output_option (file, sep, "-traditional", "", indent, pos, max);
1529 if (profile_flag)
1530 pos = output_option (file, sep, "-p", "", indent, pos, max);
1531 if (profile_block_flag)
1532 pos = output_option (file, sep, "-a", "", indent, pos, max);
1533
1534 for (j = 0; j < f_len; j++)
1535 if (*f_options[j].variable == f_options[j].on_value)
1536 pos = output_option (file, sep, "-f", f_options[j].string,
1537 indent, pos, max);
1538
1539 for (j = 0; j < W_len; j++)
1540 if (*W_options[j].variable == W_options[j].on_value)
1541 pos = output_option (file, sep, "-W", W_options[j].string,
1542 indent, pos, max);
1543
1544 for (j = 0; j < sizeof m_options / sizeof m_options[0]; j++)
1545 if (m_options[j].name[0] != '\0'
1546 && m_options[j].value > 0
1547 && ((m_options[j].value & target_flags)
1548 == m_options[j].value))
1549 pos = output_option (file, sep, "-m", m_options[j].name,
1550 indent, pos, max);
1551
1552 if (m88k_short_data)
1553 pos = output_option (file, sep, "-mshort-data-", m88k_short_data,
1554 indent, pos, max);
1555
1556 fprintf (file, term);
1557 }
1558
1559 void
1560 output_file_start (file, f_options, f_len, W_options, W_len)
1561 FILE *file;
1562 struct options *f_options;
1563 struct options *W_options;
1564 int f_len, W_len;
1565 {
1566 register int pos;
1567
1568 ASM_FIRST_LINE (file);
1569 if (TARGET_88110
1570 && TARGET_SVR4)
1571 fprintf (file, "\t%s\n", REQUIRES_88110_ASM_OP);
1572 output_file_directive (file, main_input_filename);
1573 /* Switch to the data section so that the coffsem symbol and the
1574 gcc2_compiled. symbol aren't in the text section. */
1575 data_section ();
1576 ASM_COFFSEM (file);
1577
1578 if (TARGET_IDENTIFY_REVISION)
1579 {
1580 char indent[256];
1581
1582 time_t now = time ((time_t *)0);
1583 sprintf (indent, "]\"\n\t%s\t \"@(#)%s [", IDENT_ASM_OP, main_input_filename);
1584 fprintf (file, indent+3);
1585 pos = fprintf (file, "gcc %s, %.24s,", VERSION_STRING, ctime (&now));
1586 #if 1
1587 /* ??? It would be nice to call print_switch_values here (and thereby
1588 let us delete output_options) but this is kept in until it is known
1589 whether the change in content format matters. */
1590 output_options (file, f_options, f_len, W_options, W_len,
1591 pos, 150 - strlen (indent), " ", indent, "]\"\n\n");
1592 #else
1593 fprintf (file, "]\"\n");
1594 print_switch_values (file, 0, 150 - strlen (indent),
1595 indent + 3, " ", "]\"\n");
1596 #endif
1597 }
1598 }
1599 \f
1600 /* Output an ascii string. */
1601
1602 void
1603 output_ascii (file, opcode, max, p, size)
1604 FILE *file;
1605 char *opcode;
1606 int max;
1607 unsigned char *p;
1608 int size;
1609 {
1610 int i;
1611 int in_escape = 0;
1612
1613 register int num = 0;
1614
1615 fprintf (file, "\t%s\t \"", opcode);
1616 for (i = 0; i < size; i++)
1617 {
1618 register int c = p[i];
1619
1620 if (num > max)
1621 {
1622 fprintf (file, "\"\n\t%s\t \"", opcode);
1623 num = 0;
1624 }
1625
1626 if (c == '\"' || c == '\\')
1627 {
1628 escape:
1629 putc ('\\', file);
1630 putc (c, file);
1631 num += 2;
1632 in_escape = 0;
1633 }
1634 else if (in_escape && c >= '0' && c <= '9')
1635 {
1636 /* If a digit follows an octal-escape, the Vax assembler fails
1637 to stop reading the escape after three digits. Continue to
1638 output the values as an octal-escape until a non-digit is
1639 found. */
1640 fprintf (file, "\\%03o", c);
1641 num += 4;
1642 }
1643 else if ((c >= ' ' && c < 0177) || (c == '\t'))
1644 {
1645 putc (c, file);
1646 num++;
1647 in_escape = 0;
1648 }
1649 else
1650 {
1651 switch (c)
1652 {
1653 /* Some assemblers can't handle \a, \v, or \?. */
1654 case '\f': c = 'f'; goto escape;
1655 case '\b': c = 'b'; goto escape;
1656 case '\r': c = 'r'; goto escape;
1657 case '\n': c = 'n'; goto escape;
1658 }
1659
1660 fprintf (file, "\\%03o", c);
1661 num += 4;
1662 in_escape = 1;
1663 }
1664 }
1665 fprintf (file, "\"\n");
1666 }
1667 \f
1668 /* Output a label (allows insn-output.c to be compiled without including
1669 m88k.c or needing to include stdio.h). */
1670
1671 void
1672 output_label (label_number)
1673 int label_number;
1674 {
1675 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", label_number);
1676 }
1677 \f
1678 /* Generate the assembly code for function entry.
1679
1680 The prologue is responsible for setting up the stack frame,
1681 initializing the frame pointer register, saving registers that must be
1682 saved, and allocating SIZE additional bytes of storage for the
1683 local variables. SIZE is an integer. FILE is a stdio
1684 stream to which the assembler code should be output.
1685
1686 The label for the beginning of the function need not be output by this
1687 macro. That has already been done when the macro is run.
1688
1689 To determine which registers to save, the macro can refer to the array
1690 `regs_ever_live': element R is nonzero if hard register
1691 R is used anywhere within the function. This implies the
1692 function prologue should save register R, but not if it is one
1693 of the call-used registers.
1694
1695 On machines where functions may or may not have frame-pointers, the
1696 function entry code must vary accordingly; it must set up the frame
1697 pointer if one is wanted, and not otherwise. To determine whether a
1698 frame pointer is in wanted, the macro can refer to the variable
1699 `frame_pointer_needed'. The variable's value will be 1 at run
1700 time in a function that needs a frame pointer.
1701
1702 On machines where an argument may be passed partly in registers and
1703 partly in memory, this macro must examine the variable
1704 `current_function_pretend_args_size', and allocate that many bytes
1705 of uninitialized space on the stack just underneath the first argument
1706 arriving on the stack. (This may not be at the very end of the stack,
1707 if the calling sequence has pushed anything else since pushing the stack
1708 arguments. But usually, on such machines, nothing else has been pushed
1709 yet, because the function prologue itself does all the pushing.)
1710
1711 If `ACCUMULATE_OUTGOING_ARGS' is defined, the variable
1712 `current_function_outgoing_args_size' contains the size in bytes
1713 required for the outgoing arguments. This macro must add that
1714 amount of uninitialized space to very bottom of the stack.
1715
1716 The stack frame we use looks like this:
1717
1718 caller callee
1719 |==============================================|
1720 | caller's frame |
1721 |==============================================|
1722 | [caller's outgoing memory arguments] |
1723 |==============================================|
1724 | caller's outgoing argument area (32 bytes) |
1725 sp -> |==============================================| <- ap
1726 | [local variable space] |
1727 |----------------------------------------------|
1728 | [return address (r1)] |
1729 |----------------------------------------------|
1730 | [previous frame pointer (r30)] |
1731 |==============================================| <- fp
1732 | [preserved registers (r25..r14)] |
1733 |----------------------------------------------|
1734 | [preserved registers (x29..x22)] |
1735 |==============================================|
1736 | [dynamically allocated space (alloca)] |
1737 |==============================================|
1738 | [callee's outgoing memory arguments] |
1739 |==============================================|
1740 | [callee's outgoing argument area (32 bytes)] |
1741 |==============================================| <- sp
1742
1743 Notes:
1744
1745 r1 and r30 must be saved if debugging.
1746
1747 fp (if present) is located two words down from the local
1748 variable space.
1749 */
1750
1751 static void emit_add ();
1752 static void preserve_registers ();
1753 static void emit_ldst ();
1754 static void output_tdesc ();
1755
1756 static int nregs;
1757 static int nxregs;
1758 static char save_regs[FIRST_PSEUDO_REGISTER];
1759 static int frame_laid_out;
1760 static int frame_size;
1761 static int variable_args_p;
1762 static int epilogue_marked;
1763 static int prologue_marked;
1764
1765 extern char call_used_regs[];
1766 extern int current_function_pretend_args_size;
1767 extern int current_function_outgoing_args_size;
1768 extern int frame_pointer_needed;
1769
1770 #define FIRST_OCS_PRESERVE_REGISTER 14
1771 #define LAST_OCS_PRESERVE_REGISTER 30
1772
1773 #define FIRST_OCS_EXTENDED_PRESERVE_REGISTER (32 + 22)
1774 #define LAST_OCS_EXTENDED_PRESERVE_REGISTER (32 + 31)
1775
1776 #define STACK_UNIT_BOUNDARY (STACK_BOUNDARY / BITS_PER_UNIT)
1777 #define ROUND_CALL_BLOCK_SIZE(BYTES) \
1778 (((BYTES) + (STACK_UNIT_BOUNDARY - 1)) & ~(STACK_UNIT_BOUNDARY - 1))
1779 \f
1780 /* Establish the position of the FP relative to the SP. This is done
1781 either during FUNCTION_PROLOGUE or by INITIAL_ELIMINATION_OFFSET. */
1782
1783 void
1784 m88k_layout_frame ()
1785 {
1786 int regno, sp_size;
1787
1788 frame_laid_out++;
1789
1790 bzero ((char *) &save_regs[0], sizeof (save_regs));
1791 sp_size = nregs = nxregs = 0;
1792 frame_size = get_frame_size ();
1793
1794 /* Since profiling requires a call, make sure r1 is saved. */
1795 if (profile_flag || profile_block_flag)
1796 save_regs[1] = 1;
1797
1798 /* If we are producing debug information, store r1 and r30 where the
1799 debugger wants to find them (r30 at r30+0, r1 at r30+4). Space has
1800 already been reserved for r1/r30 in STARTING_FRAME_OFFSET. */
1801 if (write_symbols != NO_DEBUG && !TARGET_OCS_FRAME_POSITION)
1802 save_regs[1] = 1;
1803
1804 /* If there is a call, alloca is used, __builtin_alloca is used, or
1805 a dynamic-sized object is defined, add the 8 additional words
1806 for the callee's argument area. The common denominator is that the
1807 FP is required. may_call_alloca only gets calls to alloca;
1808 current_function_calls_alloca gets alloca and __builtin_alloca. */
1809 if (regs_ever_live[1] || frame_pointer_needed)
1810 {
1811 save_regs[1] = 1;
1812 sp_size += REG_PARM_STACK_SPACE (0);
1813 }
1814
1815 /* If we are producing PIC, save the addressing base register and r1. */
1816 if (flag_pic && current_function_uses_pic_offset_table)
1817 {
1818 save_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
1819 nregs++;
1820 }
1821
1822 /* If a frame is requested, save the previous FP, and the return
1823 address (r1), so that a traceback can be done without using tdesc
1824 information. Otherwise, simply save the FP if it is used as
1825 a preserve register. */
1826 if (frame_pointer_needed)
1827 save_regs[FRAME_POINTER_REGNUM] = save_regs[1] = 1;
1828 else if (regs_ever_live[FRAME_POINTER_REGNUM])
1829 save_regs[FRAME_POINTER_REGNUM] = 1;
1830
1831 /* Figure out which extended register(s) needs to be saved. */
1832 for (regno = FIRST_EXTENDED_REGISTER + 1; regno < FIRST_PSEUDO_REGISTER;
1833 regno++)
1834 if (regs_ever_live[regno] && ! call_used_regs[regno])
1835 {
1836 save_regs[regno] = 1;
1837 nxregs++;
1838 }
1839
1840 /* Figure out which normal register(s) needs to be saved. */
1841 for (regno = 2; regno < FRAME_POINTER_REGNUM; regno++)
1842 if (regs_ever_live[regno] && ! call_used_regs[regno])
1843 {
1844 save_regs[regno] = 1;
1845 nregs++;
1846 }
1847
1848 /* Achieve greatest use of double memory ops. Either we end up saving
1849 r30 or we use that slot to align the registers we do save. */
1850 if (nregs >= 2 && save_regs[1] && !save_regs[FRAME_POINTER_REGNUM])
1851 sp_size += 4;
1852
1853 nregs += save_regs[1] + save_regs[FRAME_POINTER_REGNUM];
1854 /* if we need to align extended registers, add a word */
1855 if (nxregs > 0 && (nregs & 1) != 0)
1856 sp_size +=4;
1857 sp_size += 4 * nregs;
1858 sp_size += 8 * nxregs;
1859 sp_size += current_function_outgoing_args_size;
1860
1861 /* The first two saved registers are placed above the new frame pointer
1862 if any. In the only case this matters, they are r1 and r30. */
1863 if (frame_pointer_needed || sp_size)
1864 m88k_fp_offset = ROUND_CALL_BLOCK_SIZE (sp_size - STARTING_FRAME_OFFSET);
1865 else
1866 m88k_fp_offset = -STARTING_FRAME_OFFSET;
1867 m88k_stack_size = m88k_fp_offset + STARTING_FRAME_OFFSET;
1868
1869 /* First, combine m88k_stack_size and size. If m88k_stack_size is
1870 non-zero, align the frame size to 8 mod 16; otherwise align the
1871 frame size to 0 mod 16. (If stacks are 8 byte aligned, this ends
1872 up as a NOP. */
1873 {
1874 int need
1875 = ((m88k_stack_size ? STACK_UNIT_BOUNDARY - STARTING_FRAME_OFFSET : 0)
1876 - (frame_size % STACK_UNIT_BOUNDARY));
1877 if (need)
1878 {
1879 if (need < 0)
1880 need += STACK_UNIT_BOUNDARY;
1881 (void) assign_stack_local (BLKmode, need, BITS_PER_UNIT);
1882 frame_size = get_frame_size ();
1883 }
1884 m88k_stack_size
1885 = ROUND_CALL_BLOCK_SIZE (m88k_stack_size + frame_size
1886 + current_function_pretend_args_size);
1887 }
1888 }
1889
1890 /* Return true if this function is known to have a null prologue. */
1891
1892 int
1893 null_prologue ()
1894 {
1895 if (! reload_completed)
1896 return 0;
1897 if (! frame_laid_out)
1898 m88k_layout_frame ();
1899 return (! frame_pointer_needed
1900 && nregs == 0
1901 && nxregs == 0
1902 && m88k_stack_size == 0);
1903 }
1904
1905 /* Determine if the current function has any references to the arg pointer.
1906 This is done indirectly by examining the DECL_ARGUMENTS' DECL_RTL.
1907 It is OK to return TRUE if there are no references, but FALSE must be
1908 correct. */
1909
1910 static int
1911 uses_arg_area_p ()
1912 {
1913 register tree parm;
1914
1915 if (current_function_decl == 0
1916 || current_function_varargs
1917 || variable_args_p)
1918 return 1;
1919
1920 for (parm = DECL_ARGUMENTS (current_function_decl);
1921 parm;
1922 parm = TREE_CHAIN (parm))
1923 {
1924 if (DECL_RTL (parm) == 0
1925 || GET_CODE (DECL_RTL (parm)) == MEM)
1926 return 1;
1927
1928 if (DECL_INCOMING_RTL (parm) == 0
1929 || GET_CODE (DECL_INCOMING_RTL (parm)) == MEM)
1930 return 1;
1931 }
1932 return 0;
1933 }
1934 \f
1935 void
1936 m88k_begin_prologue (stream, size)
1937 FILE *stream;
1938 int size;
1939 {
1940 if (TARGET_OMIT_LEAF_FRAME_POINTER && ! quiet_flag && leaf_function_p ())
1941 fprintf (stderr, "$");
1942
1943 m88k_prologue_done = 1; /* it's ok now to put out ln directives */
1944 }
1945
1946 void
1947 m88k_end_prologue (stream)
1948 FILE *stream;
1949 {
1950 if (TARGET_OCS_DEBUG_INFO && !prologue_marked)
1951 {
1952 PUT_OCS_FUNCTION_START (stream);
1953 prologue_marked = 1;
1954
1955 /* If we've already passed the start of the epilogue, say that
1956 it starts here. This marks the function as having a null body,
1957 but at a point where the return address is in a known location.
1958
1959 Originally, I thought this couldn't happen, but the pic prologue
1960 for leaf functions ends with the instruction that restores the
1961 return address from the temporary register. If the temporary
1962 register is never used, that instruction can float all the way
1963 to the end of the function. */
1964 if (epilogue_marked)
1965 PUT_OCS_FUNCTION_END (stream);
1966 }
1967 }
1968
1969 void
1970 m88k_expand_prologue ()
1971 {
1972 m88k_layout_frame ();
1973
1974 if (TARGET_OPTIMIZE_ARG_AREA
1975 && m88k_stack_size
1976 && ! uses_arg_area_p ())
1977 {
1978 /* The incoming argument area is used for stack space if it is not
1979 used (or if -mno-optimize-arg-area is given). */
1980 if ((m88k_stack_size -= REG_PARM_STACK_SPACE (0)) < 0)
1981 m88k_stack_size = 0;
1982 }
1983
1984 if (m88k_stack_size)
1985 emit_add (stack_pointer_rtx, stack_pointer_rtx, -m88k_stack_size);
1986
1987 if (nregs || nxregs)
1988 preserve_registers (m88k_fp_offset + 4, 1);
1989
1990 if (frame_pointer_needed)
1991 emit_add (frame_pointer_rtx, stack_pointer_rtx, m88k_fp_offset);
1992
1993 if (flag_pic && save_regs[PIC_OFFSET_TABLE_REGNUM])
1994 {
1995 rtx return_reg = gen_rtx (REG, SImode, 1);
1996 rtx label = gen_label_rtx ();
1997 rtx temp_reg;
1998
1999 if (! save_regs[1])
2000 {
2001 temp_reg = gen_rtx (REG, SImode, TEMP_REGNUM);
2002 emit_move_insn (temp_reg, return_reg);
2003 }
2004 emit_insn (gen_locate1 (pic_offset_table_rtx, label));
2005 emit_insn (gen_locate2 (pic_offset_table_rtx, label));
2006 emit_insn (gen_addsi3 (pic_offset_table_rtx,
2007 pic_offset_table_rtx, return_reg));
2008 if (! save_regs[1])
2009 emit_move_insn (return_reg, temp_reg);
2010 }
2011 if (profile_flag || profile_block_flag)
2012 emit_insn (gen_blockage ());
2013 }
2014 \f
2015 /* This function generates the assembly code for function exit,
2016 on machines that need it. Args are same as for FUNCTION_PROLOGUE.
2017
2018 The function epilogue should not depend on the current stack pointer!
2019 It should use the frame pointer only, if there is a frame pointer.
2020 This is mandatory because of alloca; we also take advantage of it to
2021 omit stack adjustments before returning. */
2022
2023 void
2024 m88k_begin_epilogue (stream)
2025 FILE *stream;
2026 {
2027 if (TARGET_OCS_DEBUG_INFO && !epilogue_marked && prologue_marked)
2028 {
2029 PUT_OCS_FUNCTION_END (stream);
2030 }
2031 epilogue_marked = 1;
2032 }
2033
2034 void
2035 m88k_end_epilogue (stream, size)
2036 FILE *stream;
2037 int size;
2038 {
2039 rtx insn = get_last_insn ();
2040
2041 if (TARGET_OCS_DEBUG_INFO && !epilogue_marked)
2042 PUT_OCS_FUNCTION_END (stream);
2043
2044 /* If the last insn isn't a BARRIER, we must write a return insn. This
2045 should only happen if the function has no prologue and no body. */
2046 if (GET_CODE (insn) == NOTE)
2047 insn = prev_nonnote_insn (insn);
2048 if (insn == 0 || GET_CODE (insn) != BARRIER)
2049 fprintf (stream, "\tjmp\t %s\n", reg_names[1]);
2050
2051 /* If the last insn is a barrier, and the insn before that is a call,
2052 then add a nop instruction so that tdesc can walk the stack correctly
2053 even though there is no epilogue. (Otherwise, the label for the
2054 end of the tdesc region ends up at the start of the next function. */
2055 if (insn && GET_CODE (insn) == BARRIER)
2056 {
2057 insn = prev_nonnote_insn (insn);
2058 if (insn && GET_CODE (insn) == CALL_INSN)
2059 fprintf (stream, "\tor\t %s,%s,%s\n",reg_names[0],reg_names[0],reg_names[0]);
2060 }
2061
2062 output_short_branch_defs (stream);
2063
2064 fprintf (stream, "\n");
2065
2066 if (TARGET_OCS_DEBUG_INFO)
2067 output_tdesc (stream, m88k_fp_offset + 4);
2068
2069 m88k_function_number++;
2070 m88k_prologue_done = 0; /* don't put out ln directives */
2071 variable_args_p = 0; /* has variable args */
2072 frame_laid_out = 0;
2073 epilogue_marked = 0;
2074 prologue_marked = 0;
2075 }
2076
2077 void
2078 m88k_expand_epilogue ()
2079 {
2080 #if (MONITOR_GCC & 0x4) /* What are interesting prologue/epilogue values? */
2081 fprintf (stream, "; size = %d, m88k_fp_offset = %d, m88k_stack_size = %d\n",
2082 size, m88k_fp_offset, m88k_stack_size);
2083 #endif
2084
2085 if (frame_pointer_needed)
2086 emit_add (stack_pointer_rtx, frame_pointer_rtx, -m88k_fp_offset);
2087
2088 if (nregs || nxregs)
2089 preserve_registers (m88k_fp_offset + 4, 0);
2090
2091 if (m88k_stack_size)
2092 emit_add (stack_pointer_rtx, stack_pointer_rtx, m88k_stack_size);
2093 }
2094 \f
2095 /* Emit insns to set DSTREG to SRCREG + AMOUNT during the prologue or
2096 epilogue. */
2097
2098 static void
2099 emit_add (dstreg, srcreg, amount)
2100 rtx dstreg;
2101 rtx srcreg;
2102 int amount;
2103 {
2104 rtx incr = gen_rtx (CONST_INT, VOIDmode, abs (amount));
2105 if (! ADD_INTVAL (amount))
2106 {
2107 rtx temp = gen_rtx (REG, SImode, TEMP_REGNUM);
2108 emit_move_insn (temp, incr);
2109 incr = temp;
2110 }
2111 emit_insn ((amount < 0 ? gen_subsi3 : gen_addsi3) (dstreg, srcreg, incr));
2112 }
2113
2114 /* Save/restore the preserve registers. base is the highest offset from
2115 r31 at which a register is stored. store_p is true if stores are to
2116 be done; otherwise loads. */
2117
2118 static void
2119 preserve_registers (base, store_p)
2120 int base;
2121 int store_p;
2122 {
2123 int regno, offset;
2124 struct mem_op {
2125 int regno;
2126 int nregs;
2127 int offset;
2128 } mem_op[FIRST_PSEUDO_REGISTER];
2129 struct mem_op *mo_ptr = mem_op;
2130
2131 /* The 88open OCS mandates that preserved registers be stored in
2132 increasing order. For compatibility with current practice,
2133 the order is r1, r30, then the preserve registers. */
2134
2135 offset = base;
2136 if (save_regs[1])
2137 {
2138 /* An extra word is given in this case to make best use of double
2139 memory ops. */
2140 if (nregs > 2 && !save_regs[FRAME_POINTER_REGNUM])
2141 offset -= 4;
2142 emit_ldst (store_p, 1, SImode, offset);
2143 offset -= 4;
2144 base = offset;
2145 }
2146
2147 /* Walk the registers to save recording all single memory operations. */
2148 for (regno = FRAME_POINTER_REGNUM; regno > 1; regno--)
2149 if (save_regs[regno])
2150 {
2151 if ((offset & 7) != 4 || (regno & 1) != 1 || !save_regs[regno-1])
2152 {
2153 mo_ptr->nregs = 1;
2154 mo_ptr->regno = regno;
2155 mo_ptr->offset = offset;
2156 mo_ptr++;
2157 offset -= 4;
2158 }
2159 else
2160 {
2161 regno--;
2162 offset -= 2*4;
2163 }
2164 }
2165
2166 /* Walk the registers to save recording all double memory operations.
2167 This avoids a delay in the epilogue (ld.d/ld). */
2168 offset = base;
2169 for (regno = FRAME_POINTER_REGNUM; regno > 1; regno--)
2170 if (save_regs[regno])
2171 {
2172 if ((offset & 7) != 4 || (regno & 1) != 1 || !save_regs[regno-1])
2173 {
2174 offset -= 4;
2175 }
2176 else
2177 {
2178 mo_ptr->nregs = 2;
2179 mo_ptr->regno = regno-1;
2180 mo_ptr->offset = offset-4;
2181 mo_ptr++;
2182 regno--;
2183 offset -= 2*4;
2184 }
2185 }
2186
2187 /* Walk the extended registers to record all memory operations. */
2188 /* Be sure the offset is double word aligned. */
2189 offset = (offset - 1) & ~7;
2190 for (regno = FIRST_PSEUDO_REGISTER - 1; regno > FIRST_EXTENDED_REGISTER;
2191 regno--)
2192 if (save_regs[regno])
2193 {
2194 mo_ptr->nregs = 2;
2195 mo_ptr->regno = regno;
2196 mo_ptr->offset = offset;
2197 mo_ptr++;
2198 offset -= 2*4;
2199 }
2200
2201 mo_ptr->regno = 0;
2202
2203 /* Output the memory operations. */
2204 for (mo_ptr = mem_op; mo_ptr->regno; mo_ptr++)
2205 {
2206 if (mo_ptr->nregs)
2207 emit_ldst (store_p, mo_ptr->regno,
2208 (mo_ptr->nregs > 1 ? DImode : SImode),
2209 mo_ptr->offset);
2210 }
2211 }
2212
2213 static void
2214 emit_ldst (store_p, regno, mode, offset)
2215 int store_p;
2216 int regno;
2217 enum machine_mode mode;
2218 int offset;
2219 {
2220 rtx reg = gen_rtx (REG, mode, regno);
2221 rtx mem;
2222
2223 if (SMALL_INTVAL (offset))
2224 {
2225 mem = gen_rtx (MEM, mode, plus_constant (stack_pointer_rtx, offset));
2226 }
2227 else
2228 {
2229 /* offset is too large for immediate index must use register */
2230
2231 rtx disp = gen_rtx (CONST_INT, VOIDmode, offset);
2232 rtx temp = gen_rtx (REG, SImode, TEMP_REGNUM);
2233 rtx regi = gen_rtx (PLUS, SImode, stack_pointer_rtx, temp);
2234 emit_move_insn (temp, disp);
2235 mem = gen_rtx (MEM, mode, regi);
2236 }
2237
2238 if (store_p)
2239 emit_move_insn (mem, reg);
2240 else
2241 emit_move_insn (reg, mem);
2242 }
2243
2244 /* Convert the address expression REG to a CFA offset. */
2245
2246 int
2247 m88k_debugger_offset (reg, offset)
2248 register rtx reg;
2249 register int offset;
2250 {
2251 if (GET_CODE (reg) == PLUS)
2252 {
2253 offset = INTVAL (XEXP (reg, 1));
2254 reg = XEXP (reg, 0);
2255 }
2256
2257 /* Put the offset in terms of the CFA (arg pointer). */
2258 if (reg == frame_pointer_rtx)
2259 offset += m88k_fp_offset - m88k_stack_size;
2260 else if (reg == stack_pointer_rtx)
2261 offset -= m88k_stack_size;
2262 else if (reg != arg_pointer_rtx)
2263 {
2264 #if (MONITOR_GCC & 0x10) /* Watch for suspicious symbolic locations. */
2265 if (! (GET_CODE (reg) == REG
2266 && REGNO (reg) >= FIRST_PSEUDO_REGISTER))
2267 warning ("Internal gcc error: Can't express symbolic location");
2268 #endif
2269 return 0;
2270 }
2271
2272 return offset;
2273 }
2274
2275 /* Output the 88open OCS proscribed text description information.
2276 The information is:
2277 0 8: zero
2278 0 22: info-byte-length (16 or 20 bytes)
2279 0 2: info-alignment (word 2)
2280 1 32: info-protocol (version 1 or 2(pic))
2281 2 32: starting-address (inclusive, not counting prologue)
2282 3 32: ending-address (exclusive, not counting epilog)
2283 4 8: info-variant (version 1 or 3(extended registers))
2284 4 17: register-save-mask (from register 14 to 30)
2285 4 1: zero
2286 4 1: return-address-info-discriminant
2287 4 5: frame-address-register
2288 5 32: frame-address-offset
2289 6 32: return-address-info
2290 7 32: register-save-offset
2291 8 16: extended-register-save-mask (x16 - x31)
2292 8 16: extended-register-save-offset (WORDS from register-save-offset) */
2293
2294 static void
2295 output_tdesc (file, offset)
2296 FILE *file;
2297 int offset;
2298 {
2299 int regno, i, j;
2300 long mask, return_address_info, register_save_offset;
2301 long xmask, xregister_save_offset;
2302 char buf[256];
2303
2304 for (mask = 0, i = 0, regno = FIRST_OCS_PRESERVE_REGISTER;
2305 regno <= LAST_OCS_PRESERVE_REGISTER;
2306 regno++)
2307 {
2308 mask <<= 1;
2309 if (save_regs[regno])
2310 {
2311 mask |= 1;
2312 i++;
2313 }
2314 }
2315
2316 for (xmask = 0, j = 0, regno = FIRST_OCS_EXTENDED_PRESERVE_REGISTER;
2317 regno <= LAST_OCS_EXTENDED_PRESERVE_REGISTER;
2318 regno++)
2319 {
2320 xmask <<= 1;
2321 if (save_regs[regno])
2322 {
2323 xmask |= 1;
2324 j++;
2325 }
2326 }
2327
2328 if (save_regs[1])
2329 {
2330 if ((nxregs > 0 || nregs > 2) && !save_regs[FRAME_POINTER_REGNUM])
2331 offset -= 4;
2332 return_address_info = - m88k_stack_size + offset;
2333 register_save_offset = return_address_info - i*4;
2334 }
2335 else
2336 {
2337 return_address_info = 1;
2338 register_save_offset = - m88k_stack_size + offset + 4 - i*4;
2339 }
2340
2341 xregister_save_offset = - (j * 2 + ((register_save_offset >> 2) & 1));
2342
2343 tdesc_section ();
2344
2345 fprintf (file, "\t%s\t %d,%d", INT_ASM_OP, /* 8:0,22:(20 or 16),2:2 */
2346 (((xmask != 0) ? 20 : 16) << 2) | 2,
2347 flag_pic ? 2 : 1);
2348
2349 ASM_GENERATE_INTERNAL_LABEL (buf, OCS_START_PREFIX, m88k_function_number);
2350 fprintf (file, ",%s%s", buf+1, flag_pic ? "#rel" : "");
2351 ASM_GENERATE_INTERNAL_LABEL (buf, OCS_END_PREFIX, m88k_function_number);
2352 fprintf (file, ",%s%s", buf+1, flag_pic ? "#rel" : "");
2353
2354 fprintf (file, ",0x%x,0x%x,0x%x,0x%x",
2355 /* 8:1,17:0x%.3x,1:0,1:%d,5:%d */
2356 (((xmask ? 3 : 1) << (17+1+1+5))
2357 | (mask << (1+1+5))
2358 | ((!!save_regs[1]) << 5)
2359 | (frame_pointer_needed
2360 ? FRAME_POINTER_REGNUM
2361 : STACK_POINTER_REGNUM)),
2362 (m88k_stack_size - (frame_pointer_needed ? m88k_fp_offset : 0)),
2363 return_address_info,
2364 register_save_offset);
2365 if (xmask)
2366 fprintf (file, ",0x%x%04x", xmask, (0xffff & xregister_save_offset));
2367 fputc ('\n', file);
2368
2369 text_section ();
2370 }
2371 \f
2372 /* Output assembler code to FILE to increment profiler label # LABELNO
2373 for profiling a function entry. NAME is the mcount function name
2374 (varies), SAVEP indicates whether the parameter registers need to
2375 be saved and restored. */
2376
2377 void
2378 output_function_profiler (file, labelno, name, savep)
2379 FILE *file;
2380 int labelno;
2381 char *name;
2382 int savep;
2383 {
2384 char label[256];
2385 char dbi[256];
2386 char *temp = (savep ? reg_names[2] : reg_names[10]);
2387
2388 /* Remember to update FUNCTION_PROFILER_LENGTH. */
2389
2390 if (savep)
2391 {
2392 fprintf (file, "\tsubu\t %s,%s,64\n", reg_names[31], reg_names[31]);
2393 fprintf (file, "\tst.d\t %s,%s,32\n", reg_names[2], reg_names[31]);
2394 fprintf (file, "\tst.d\t %s,%s,40\n", reg_names[4], reg_names[31]);
2395 fprintf (file, "\tst.d\t %s,%s,48\n", reg_names[6], reg_names[31]);
2396 fprintf (file, "\tst.d\t %s,%s,56\n", reg_names[8], reg_names[31]);
2397 }
2398
2399 ASM_GENERATE_INTERNAL_LABEL (label, "LP", labelno);
2400 if (flag_pic == 2)
2401 {
2402 fprintf (file, "\tor.u\t %s,%s,%shi16(%s#got_rel)\n",
2403 temp, reg_names[0], m88k_pound_sign, &label[1]);
2404 fprintf (file, "\tor\t %s,%s,%slo16(%s#got_rel)\n",
2405 temp, temp, m88k_pound_sign, &label[1]);
2406 sprintf (dbi, "\tld\t %s,%s,%s\n", temp,
2407 reg_names[PIC_OFFSET_TABLE_REGNUM], temp);
2408 }
2409 else if (flag_pic)
2410 {
2411 sprintf (dbi, "\tld\t %s,%s,%s#got_rel\n", temp,
2412 reg_names[PIC_OFFSET_TABLE_REGNUM], &label[1]);
2413 }
2414 else
2415 {
2416 fprintf (file, "\tor.u\t %s,%s,%shi16(%s)\n",
2417 temp, reg_names[0], m88k_pound_sign, &label[1]);
2418 sprintf (dbi, "\tor\t %s,%s,%slo16(%s)\n",
2419 temp, temp, m88k_pound_sign, &label[1]);
2420 }
2421
2422 if (flag_pic)
2423 fprintf (file, "\tbsr.n\t %s#plt\n", name);
2424 else
2425 fprintf (file, "\tbsr.n\t %s\n", name);
2426 fputs (dbi, file);
2427
2428 if (savep)
2429 {
2430 fprintf (file, "\tld.d\t %s,%s,32\n", reg_names[2], reg_names[31]);
2431 fprintf (file, "\tld.d\t %s,%s,40\n", reg_names[4], reg_names[31]);
2432 fprintf (file, "\tld.d\t %s,%s,48\n", reg_names[6], reg_names[31]);
2433 fprintf (file, "\tld.d\t %s,%s,56\n", reg_names[8], reg_names[31]);
2434 fprintf (file, "\taddu\t %s,%s,64\n", reg_names[31], reg_names[31]);
2435 }
2436 }
2437
2438 /* Output assembler code to FILE to initialize basic-block profiling for
2439 the current module. LABELNO is unique to each instance. */
2440
2441 void
2442 output_function_block_profiler (file, labelno)
2443 FILE *file;
2444 int labelno;
2445 {
2446 char block[256];
2447 char label[256];
2448
2449 /* Remember to update FUNCTION_BLOCK_PROFILER_LENGTH. */
2450
2451 ASM_GENERATE_INTERNAL_LABEL (block, "LPBX", 0);
2452 ASM_GENERATE_INTERNAL_LABEL (label, "LPY", labelno);
2453
2454 /* @@ Need to deal with PIC. I'm not sure what the requirements are on
2455 register usage, so I used r26/r27 to be safe. */
2456 fprintf (file, "\tor.u\t %s,%s,%shi16(%s)\n", reg_names[27], reg_names[0],
2457 m88k_pound_sign, &block[1]);
2458 fprintf (file, "\tld\t %s,%s,%slo16(%s)\n", reg_names[26], reg_names[27],
2459 m88k_pound_sign, &block[1]);
2460 fprintf (file, "\tbcnd\t %sne0,%s,%s\n",
2461 m88k_pound_sign, reg_names[26], &label[1]);
2462 fprintf (file, "\tsubu\t %s,%s,64\n", reg_names[31], reg_names[31]);
2463 fprintf (file, "\tst.d\t %s,%s,32\n", reg_names[2], reg_names[31]);
2464 fprintf (file, "\tst.d\t %s,%s,40\n", reg_names[4], reg_names[31]);
2465 fprintf (file, "\tst.d\t %s,%s,48\n", reg_names[6], reg_names[31]);
2466 fprintf (file, "\tst.d\t %s,%s,56\n", reg_names[8], reg_names[31]);
2467 fputs ("\tbsr.n\t ", file);
2468 ASM_OUTPUT_LABELREF (file, "__bb_init_func");
2469 putc ('\n', file);
2470 fprintf (file, "\tor\t %s,%s,%slo16(%s)\n", reg_names[2], reg_names[27],
2471 m88k_pound_sign, &block[1]);
2472 fprintf (file, "\tld.d\t %s,%s,32\n", reg_names[2], reg_names[31]);
2473 fprintf (file, "\tld.d\t %s,%s,40\n", reg_names[4], reg_names[31]);
2474 fprintf (file, "\tld.d\t %s,%s,48\n", reg_names[6], reg_names[31]);
2475 fprintf (file, "\tld.d\t %s,%s,56\n", reg_names[8], reg_names[31]);
2476 fprintf (file, "\taddu\t %s,%s,64\n", reg_names[31], reg_names[31]);
2477 ASM_OUTPUT_INTERNAL_LABEL (file, "LPY", labelno);
2478 }
2479
2480 /* Output assembler code to FILE to increment the count associated with
2481 the basic block number BLOCKNO. */
2482
2483 void
2484 output_block_profiler (file, blockno)
2485 FILE *file;
2486 int blockno;
2487 {
2488 char block[256];
2489
2490 /* Remember to update BLOCK_PROFILER_LENGTH. */
2491
2492 ASM_GENERATE_INTERNAL_LABEL (block, "LPBX", 2);
2493
2494 /* @@ Need to deal with PIC. I'm not sure what the requirements are on
2495 register usage, so I used r26/r27 to be safe. */
2496 fprintf (file, "\tor.u\t %s,%s,%shi16(%s+%d)\n", reg_names[27], reg_names[0],
2497 m88k_pound_sign, &block[1], 4 * blockno);
2498 fprintf (file, "\tld\t %s,%s,%slo16(%s+%d)\n", reg_names[26], reg_names[27],
2499 m88k_pound_sign, &block[1], 4 * blockno);
2500 fprintf (file, "\taddu\t %s,%s,1\n", reg_names[26], reg_names[26]);
2501 fprintf (file, "\tst\t %s,%s,%slo16(%s+%d)\n", reg_names[26], reg_names[27],
2502 m88k_pound_sign, &block[1], 4 * blockno);
2503 }
2504 \f
2505 /* Determine whether a function argument is passed in a register, and
2506 which register.
2507
2508 The arguments are CUM, which summarizes all the previous
2509 arguments; MODE, the machine mode of the argument; TYPE,
2510 the data type of the argument as a tree node or 0 if that is not known
2511 (which happens for C support library functions); and NAMED,
2512 which is 1 for an ordinary argument and 0 for nameless arguments that
2513 correspond to `...' in the called function's prototype.
2514
2515 The value of the expression should either be a `reg' RTX for the
2516 hard register in which to pass the argument, or zero to pass the
2517 argument on the stack.
2518
2519 On the m88000 the first eight words of args are normally in registers
2520 and the rest are pushed. Double precision floating point must be
2521 double word aligned (and if in a register, starting on an even
2522 register). Structures and unions which are not 4 byte, and word
2523 aligned are passed in memory rather than registers, even if they
2524 would fit completely in the registers under OCS rules.
2525
2526 Note that FUNCTION_ARG and FUNCTION_INCOMING_ARG were different.
2527 For structures that are passed in memory, but could have been
2528 passed in registers, we first load the structure into the
2529 register, and then when the last argument is passed, we store
2530 the registers into the stack locations. This fixes some bugs
2531 where GCC did not expect to have register arguments, followed
2532 by stack arguments, followed by register arguments. */
2533
2534 struct rtx_def *
2535 m88k_function_arg (args_so_far, mode, type, named)
2536 CUMULATIVE_ARGS args_so_far;
2537 enum machine_mode mode;
2538 tree type;
2539 int named;
2540 {
2541 int bytes, words;
2542
2543 if (type != 0 /* undo putting struct in register */
2544 && (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE))
2545 mode = BLKmode;
2546
2547 if (mode == BLKmode && TARGET_WARN_PASS_STRUCT)
2548 warning ("argument #%d is a structure", args_so_far + 1);
2549
2550 if ((args_so_far & 1) != 0
2551 && (mode == DImode || mode == DFmode
2552 || (type != 0 && TYPE_ALIGN (type) > 32)))
2553 args_so_far++;
2554
2555 #ifdef ESKIT
2556 if (no_reg_params)
2557 return (rtx) 0; /* don't put args in registers */
2558 #endif
2559
2560 if (type == 0 && mode == BLKmode)
2561 abort (); /* m88k_function_arg argument `type' is NULL for BLKmode. */
2562
2563 bytes = (mode != BLKmode) ? GET_MODE_SIZE (mode) : int_size_in_bytes (type);
2564 words = (bytes + 3) / 4;
2565
2566 if (args_so_far + words > 8)
2567 return (rtx) 0; /* args have exhausted registers */
2568
2569 else if (mode == BLKmode
2570 && (TYPE_ALIGN (type) != BITS_PER_WORD
2571 || bytes != UNITS_PER_WORD))
2572 return (rtx) 0;
2573
2574 return gen_rtx (REG,
2575 ((mode == BLKmode) ? TYPE_MODE (type) : mode),
2576 2 + args_so_far);
2577 }
2578 \f
2579 /* Do what is necessary for `va_start'. The argument is ignored;
2580 We look at the current function to determine if stdargs or varargs
2581 is used and fill in an initial va_list. A pointer to this constructor
2582 is returned. */
2583
2584 struct rtx_def *
2585 m88k_builtin_saveregs (arglist)
2586 tree arglist;
2587 {
2588 rtx block, addr, argsize, dest;
2589 tree fntype = TREE_TYPE (current_function_decl);
2590 int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0
2591 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2592 != void_type_node)))
2593 ? -UNITS_PER_WORD : 0) + UNITS_PER_WORD - 1;
2594 int fixed;
2595 variable_args_p = 1;
2596
2597 if (CONSTANT_P (current_function_arg_offset_rtx))
2598 {
2599 fixed = (XINT (current_function_arg_offset_rtx, 0)
2600 + argadj) / UNITS_PER_WORD;
2601 argsize = gen_rtx (CONST_INT, VOIDmode, fixed);
2602 }
2603 else
2604 {
2605 fixed = 0;
2606 argsize = plus_constant (current_function_arg_offset_rtx, argadj);
2607 argsize = expand_shift (RSHIFT_EXPR, Pmode, argsize,
2608 build_int_2 (2, 0), argsize, 0);
2609 }
2610
2611 /* Allocate the va_list constructor */
2612 block = assign_stack_local (BLKmode, 3 * UNITS_PER_WORD, BITS_PER_WORD);
2613 MEM_IN_STRUCT_P (block) = 1;
2614 RTX_UNCHANGING_P (block) = 1;
2615 RTX_UNCHANGING_P (XEXP (block, 0)) = 1;
2616
2617 /* Store the argsize as the __va_arg member. */
2618 emit_move_insn (change_address (block, SImode, XEXP (block, 0)),
2619 argsize);
2620
2621 /* Store the arg pointer in the __va_stk member. */
2622 emit_move_insn (change_address (block, Pmode,
2623 plus_constant (XEXP (block, 0),
2624 UNITS_PER_WORD)),
2625 copy_to_reg (virtual_incoming_args_rtx));
2626
2627 /* Allocate the register space, and store it as the __va_reg member. */
2628 addr = assign_stack_local (BLKmode, 8 * UNITS_PER_WORD, -1);
2629 MEM_IN_STRUCT_P (addr) = 1;
2630 RTX_UNCHANGING_P (addr) = 1;
2631 RTX_UNCHANGING_P (XEXP (addr, 0)) = 1;
2632 emit_move_insn (change_address (block, Pmode,
2633 plus_constant (XEXP (block, 0),
2634 2 * UNITS_PER_WORD)),
2635 copy_to_reg (XEXP (addr, 0)));
2636
2637 /* Now store the incoming registers. */
2638 if (fixed < 8)
2639 {
2640 dest = change_address (addr, Pmode,
2641 plus_constant (XEXP (addr, 0),
2642 fixed * UNITS_PER_WORD));
2643 move_block_from_reg (2 + fixed, dest, 8 - fixed,
2644 UNITS_PER_WORD * (8 - fixed));
2645 }
2646
2647 if (flag_check_memory_usage)
2648 {
2649 emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
2650 block, ptr_mode,
2651 GEN_INT (3 * UNITS_PER_WORD), TYPE_MODE (sizetype),
2652 GEN_INT (MEMORY_USE_RW), QImode);
2653 if (fixed < 8)
2654 emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
2655 dest, ptr_mode,
2656 GEN_INT (UNITS_PER_WORD * (8 - fixed)),
2657 TYPE_MODE (sizetype),
2658 GEN_INT (MEMORY_USE_RW), QImode);
2659 }
2660
2661 /* Return the address of the va_list constructor, but don't put it in a
2662 register. This fails when not optimizing and produces worse code when
2663 optimizing. */
2664 return XEXP (block, 0);
2665 }
2666 \f
2667 /* If cmpsi has not been generated, emit code to do the test. Return the
2668 expression describing the test of operator OP. */
2669
2670 rtx
2671 emit_test (op, mode)
2672 enum rtx_code op;
2673 enum machine_mode mode;
2674 {
2675 if (m88k_compare_reg == 0)
2676 emit_insn (gen_test (m88k_compare_op0, m88k_compare_op1));
2677 return (gen_rtx (op, mode, m88k_compare_reg, const0_rtx));
2678 }
2679
2680 /* Determine how to best perform cmpsi/bxx, where cmpsi has a constant
2681 operand. All tests with zero (albeit swapped) and all equality tests
2682 with a constant are done with bcnd. The remaining cases are swapped
2683 as needed. */
2684
2685 void
2686 emit_bcnd (op, label)
2687 enum rtx_code op;
2688 rtx label;
2689 {
2690 if (m88k_compare_op1 == const0_rtx)
2691 emit_jump_insn( gen_bcnd (
2692 gen_rtx (op, VOIDmode,m88k_compare_op0, const0_rtx),
2693 label));
2694 else if (m88k_compare_op0 == const0_rtx)
2695 emit_jump_insn( gen_bcnd(
2696 gen_rtx(
2697 swap_condition (op),
2698 VOIDmode, m88k_compare_op1, const0_rtx),
2699 label));
2700 else if (op != EQ && op != NE)
2701 emit_jump_insn (gen_bxx (emit_test (op, VOIDmode), label));
2702 else
2703 {
2704 rtx zero = gen_reg_rtx (SImode);
2705 rtx reg, constant;
2706 int value;
2707
2708 if (GET_CODE (m88k_compare_op1) == CONST_INT)
2709 {
2710 reg = force_reg (SImode, m88k_compare_op0);
2711 constant = m88k_compare_op1;
2712 }
2713 else
2714 {
2715 reg = force_reg (SImode, m88k_compare_op1);
2716 constant = m88k_compare_op0;
2717 }
2718 value = INTVAL (constant);
2719
2720 /* Perform an arithmetic computation to make the compared-to value
2721 zero, but avoid loosing if the bcnd is later changed into sxx. */
2722 if (SMALL_INTVAL (value))
2723 emit_jump_insn (gen_bxx (emit_test (op, VOIDmode), label));
2724 else
2725 {
2726 if (SMALL_INTVAL (-value))
2727 emit_insn (gen_addsi3 (zero, reg,
2728 gen_rtx (CONST_INT, VOIDmode, -value)));
2729 else
2730 emit_insn (gen_xorsi3 (zero, reg, constant));
2731
2732 emit_jump_insn (gen_bcnd (gen_rtx (op, VOIDmode,
2733 zero, const0_rtx),
2734 label));
2735 }
2736 }
2737 }
2738 \f
2739 /* Print an operand. Recognize special options, documented below. */
2740
2741 void
2742 print_operand (file, x, code)
2743 FILE *file;
2744 rtx x;
2745 char code;
2746 {
2747 enum rtx_code xc = (x ? GET_CODE (x) : UNKNOWN);
2748 register int value = (xc == CONST_INT ? INTVAL (x) : 0);
2749 static int sequencep;
2750 static int reversep;
2751
2752 if (sequencep)
2753 {
2754 if (code < 'B' || code > 'E')
2755 output_operand_lossage ("%R not followed by %B/C/D/E");
2756 if (reversep)
2757 xc = reverse_condition (xc);
2758 sequencep = 0;
2759 }
2760
2761 switch (code)
2762 {
2763 case '*': /* addressing base register for PIC */
2764 fputs (reg_names[PIC_OFFSET_TABLE_REGNUM], file); return;
2765
2766 case '#': /* SVR4 pound-sign syntax character (empty if SVR3) */
2767 fputs (m88k_pound_sign, file); return;
2768
2769 case 'V': /* Output a serializing instruction as needed if the operand
2770 (assumed to be a MEM) is a volatile load. */
2771 case 'v': /* ditto for a volatile store. */
2772 if (MEM_VOLATILE_P (x) && TARGET_SERIALIZE_VOLATILE)
2773 {
2774 /* The m88110 implements two FIFO queues, one for loads and
2775 one for stores. These queues mean that loads complete in
2776 their issue order as do stores. An interaction between the
2777 history buffer and the store reservation station ensures
2778 that a store will not bypass load. Finally, a load will not
2779 bypass store, but only when they reference the same address.
2780
2781 To avoid this reordering (a load bypassing a store) for
2782 volatile references, a serializing instruction is output.
2783 We choose the fldcr instruction as it does not serialize on
2784 the m88100 so that -m88000 code will not be degraded.
2785
2786 The mechanism below is completed by having CC_STATUS_INIT set
2787 the code to the unknown value. */
2788
2789 /*
2790 hassey 6/30/93
2791 A problem with 88110 4.1 & 4.2 makes the use of fldcr for
2792 this purpose undesirable. Instead we will use tb1, this will
2793 cause serialization on the 88100 but such is life.
2794 */
2795
2796 static rtx last_addr = 0;
2797 if (code == 'V' /* Only need to serialize before a load. */
2798 && m88k_volatile_code != 'V' /* Loads complete in FIFO order. */
2799 && !(m88k_volatile_code == 'v'
2800 && GET_CODE (XEXP (x, 0)) == LO_SUM
2801 && rtx_equal_p (XEXP (XEXP (x, 0), 1), last_addr)))
2802 fprintf (file,
2803 #if 0
2804 #ifdef AS_BUG_FLDCR
2805 "fldcr\t %s,%scr63\n\t",
2806 #else
2807 "fldcr\t %s,%sfcr63\n\t",
2808 #endif
2809 reg_names[0], m88k_pound_sign);
2810 #else /* 0 */
2811 "tb1\t 1,%s,0xff\n\t", reg_names[0]);
2812 #endif /* 0 */
2813 m88k_volatile_code = code;
2814 last_addr = (GET_CODE (XEXP (x, 0)) == LO_SUM
2815 ? XEXP (XEXP (x, 0), 1) : 0);
2816 }
2817 return;
2818
2819 case 'X': /* print the upper 16 bits... */
2820 value >>= 16;
2821 case 'x': /* print the lower 16 bits of the integer constant in hex */
2822 if (xc != CONST_INT)
2823 output_operand_lossage ("invalid %x/X value");
2824 fprintf (file, "0x%x", value & 0xffff); return;
2825
2826 case 'H': /* print the low 16 bits of the negated integer constant */
2827 if (xc != CONST_INT)
2828 output_operand_lossage ("invalid %H value");
2829 value = -value;
2830 case 'h': /* print the register or low 16 bits of the integer constant */
2831 if (xc == REG)
2832 goto reg;
2833 if (xc != CONST_INT)
2834 output_operand_lossage ("invalid %h value");
2835 fprintf (file, "%d", value & 0xffff);
2836 return;
2837
2838 case 'Q': /* print the low 8 bits of the negated integer constant */
2839 if (xc != CONST_INT)
2840 output_operand_lossage ("invalid %Q value");
2841 value = -value;
2842 case 'q': /* print the register or low 8 bits of the integer constant */
2843 if (xc == REG)
2844 goto reg;
2845 if (xc != CONST_INT)
2846 output_operand_lossage ("invalid %q value");
2847 fprintf (file, "%d", value & 0xff);
2848 return;
2849
2850 case 'w': /* print the integer constant (X == 32 ? 0 : 32 - X) */
2851 if (xc != CONST_INT)
2852 output_operand_lossage ("invalid %o value");
2853 fprintf (file, "%d", value == 32 ? 0 : 32 - value);
2854 return;
2855
2856 case 'p': /* print the logarithm of the integer constant */
2857 if (xc != CONST_INT
2858 || (value = exact_log2 (value)) < 0)
2859 output_operand_lossage ("invalid %p value");
2860 fprintf (file, "%d", value);
2861 return;
2862
2863 case 'S': /* compliment the value and then... */
2864 value = ~value;
2865 case 's': /* print the width and offset values forming the integer
2866 constant with a SET instruction. See integer_ok_for_set. */
2867 {
2868 register unsigned mask, uval = value;
2869 register int top, bottom;
2870
2871 if (xc != CONST_INT)
2872 output_operand_lossage ("invalid %s/S value");
2873 /* All the "one" bits must be contiguous. If so, MASK will be
2874 a power of two or zero. */
2875 mask = (uval | (uval - 1)) + 1;
2876 if (!(uval && POWER_OF_2_or_0 (mask)))
2877 output_operand_lossage ("invalid %s/S value");
2878 top = mask ? exact_log2 (mask) : 32;
2879 bottom = exact_log2 (uval & ~(uval - 1));
2880 fprintf (file,"%d<%d>", top - bottom, bottom);
2881 return;
2882 }
2883
2884 case 'P': /* print nothing if pc_rtx; output label_ref */
2885 if (xc == LABEL_REF)
2886 output_addr_const (file, x);
2887 else if (xc != PC)
2888 output_operand_lossage ("invalid %P operand");
2889 return;
2890
2891 case 'L': /* print 0 or 1 if operand is label_ref and then... */
2892 fputc (xc == LABEL_REF ? '1' : '0', file);
2893 case '.': /* print .n if delay slot is used */
2894 fputs ((final_sequence
2895 && ! INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0)))
2896 ? ".n\t" : "\t", file);
2897 return;
2898
2899 case '!': /* Reverse the following condition. */
2900 sequencep++;
2901 reversep = 1;
2902 return;
2903 case 'R': /* reverse the condition of the next print_operand
2904 if operand is a label_ref. */
2905 sequencep++;
2906 reversep = (xc == LABEL_REF);
2907 return;
2908
2909 case 'B': /* bcnd branch values */
2910 fputs (m88k_pound_sign, file);
2911 switch (xc)
2912 {
2913 case EQ: fputs ("eq0", file); return;
2914 case NE: fputs ("ne0", file); return;
2915 case GT: fputs ("gt0", file); return;
2916 case LE: fputs ("le0", file); return;
2917 case LT: fputs ("lt0", file); return;
2918 case GE: fputs ("ge0", file); return;
2919 default: output_operand_lossage ("invalid %B value");
2920 }
2921
2922 case 'C': /* bb0/bb1 branch values for comparisons */
2923 fputs (m88k_pound_sign, file);
2924 switch (xc)
2925 {
2926 case EQ: fputs ("eq", file); return;
2927 case NE: fputs ("ne", file); return;
2928 case GT: fputs ("gt", file); return;
2929 case LE: fputs ("le", file); return;
2930 case LT: fputs ("lt", file); return;
2931 case GE: fputs ("ge", file); return;
2932 case GTU: fputs ("hi", file); return;
2933 case LEU: fputs ("ls", file); return;
2934 case LTU: fputs ("lo", file); return;
2935 case GEU: fputs ("hs", file); return;
2936 default: output_operand_lossage ("invalid %C value");
2937 }
2938
2939 case 'D': /* bcnd branch values for float comparisons */
2940 switch (xc)
2941 {
2942 case EQ: fputs ("0xa", file); return;
2943 case NE: fputs ("0x5", file); return;
2944 case GT: fputs (m88k_pound_sign, file);
2945 fputs ("gt0", file); return;
2946 case LE: fputs ("0xe", file); return;
2947 case LT: fputs ("0x4", file); return;
2948 case GE: fputs ("0xb", file); return;
2949 default: output_operand_lossage ("invalid %D value");
2950 }
2951
2952 case 'E': /* bcnd branch values for special integers */
2953 switch (xc)
2954 {
2955 case EQ: fputs ("0x8", file); return;
2956 case NE: fputs ("0x7", file); return;
2957 default: output_operand_lossage ("invalid %E value");
2958 }
2959
2960 case 'd': /* second register of a two register pair */
2961 if (xc != REG)
2962 output_operand_lossage ("`%d' operand isn't a register");
2963 fputs (reg_names[REGNO (x) + 1], file);
2964 return;
2965
2966 case 'r': /* an immediate 0 should be represented as `r0' */
2967 if (x == const0_rtx)
2968 {
2969 fputs (reg_names[0], file);
2970 return;
2971 }
2972 else if (xc != REG)
2973 output_operand_lossage ("invalid %r value");
2974 case 0:
2975 name:
2976 if (xc == REG)
2977 {
2978 reg:
2979 if (REGNO (x) == ARG_POINTER_REGNUM)
2980 output_operand_lossage ("operand is r0");
2981 else
2982 fputs (reg_names[REGNO (x)], file);
2983 }
2984 else if (xc == PLUS)
2985 output_address (x);
2986 else if (xc == MEM)
2987 output_address (XEXP (x, 0));
2988 else if (flag_pic && xc == UNSPEC)
2989 {
2990 output_addr_const (file, XVECEXP (x, 0, 0));
2991 fputs ("#got_rel", file);
2992 }
2993 else if (xc == CONST_DOUBLE)
2994 output_operand_lossage ("operand is const_double");
2995 else
2996 output_addr_const (file, x);
2997 return;
2998
2999 case 'g': /* append #got_rel as needed */
3000 if (flag_pic && (xc == SYMBOL_REF || xc == LABEL_REF))
3001 {
3002 output_addr_const (file, x);
3003 fputs ("#got_rel", file);
3004 return;
3005 }
3006 goto name;
3007
3008 case 'a': /* (standard), assume operand is an address */
3009 case 'c': /* (standard), assume operand is an immediate value */
3010 case 'l': /* (standard), assume operand is a label_ref */
3011 case 'n': /* (standard), like %c, except negate first */
3012 default:
3013 output_operand_lossage ("invalid code");
3014 }
3015 }
3016
3017 void
3018 print_operand_address (file, addr)
3019 FILE *file;
3020 rtx addr;
3021 {
3022 register rtx reg0, reg1, temp;
3023
3024 switch (GET_CODE (addr))
3025 {
3026 case REG:
3027 if (REGNO (addr) == ARG_POINTER_REGNUM)
3028 abort ();
3029 else
3030 fprintf (file, "%s,%s", reg_names[0], reg_names [REGNO (addr)]);
3031 break;
3032
3033 case LO_SUM:
3034 fprintf (file, "%s,%slo16(",
3035 reg_names[REGNO (XEXP (addr, 0))], m88k_pound_sign);
3036 output_addr_const (file, XEXP (addr, 1));
3037 fputc (')', file);
3038 break;
3039
3040 case PLUS:
3041 reg0 = XEXP (addr, 0);
3042 reg1 = XEXP (addr, 1);
3043 if (GET_CODE (reg0) == MULT || GET_CODE (reg0) == CONST_INT)
3044 {
3045 rtx tmp = reg0;
3046 reg0 = reg1;
3047 reg1 = tmp;
3048 }
3049
3050 if ((REG_P (reg0) && REGNO (reg0) == ARG_POINTER_REGNUM)
3051 || (REG_P (reg1) && REGNO (reg1) == ARG_POINTER_REGNUM))
3052 abort ();
3053
3054 else if (REG_P (reg0))
3055 {
3056 if (REG_P (reg1))
3057 fprintf (file, "%s,%s",
3058 reg_names [REGNO (reg0)], reg_names [REGNO (reg1)]);
3059
3060 else if (GET_CODE (reg1) == CONST_INT)
3061 fprintf (file, "%s,%d",
3062 reg_names [REGNO (reg0)], INTVAL (reg1));
3063
3064 else if (GET_CODE (reg1) == MULT)
3065 {
3066 rtx mreg = XEXP (reg1, 0);
3067 if (REGNO (mreg) == ARG_POINTER_REGNUM)
3068 abort ();
3069
3070 fprintf (file, "%s[%s]", reg_names[REGNO (reg0)],
3071 reg_names[REGNO (mreg)]);
3072 }
3073
3074 else if (GET_CODE (reg1) == ZERO_EXTRACT)
3075 {
3076 fprintf (file, "%s,%slo16(",
3077 reg_names[REGNO (reg0)], m88k_pound_sign);
3078 output_addr_const (file, XEXP (reg1, 0));
3079 fputc (')', file);
3080 }
3081
3082 else if (flag_pic)
3083 {
3084 fprintf (file, "%s,", reg_names[REGNO (reg0)]);
3085 output_addr_const (file, reg1);
3086 fputs ("#got_rel", file);
3087 }
3088 else abort ();
3089 }
3090
3091 else
3092 abort ();
3093 break;
3094
3095 case MULT:
3096 if (REGNO (XEXP (addr, 0)) == ARG_POINTER_REGNUM)
3097 abort ();
3098
3099 fprintf (file, "%s[%s]",
3100 reg_names[0], reg_names[REGNO (XEXP (addr, 0))]);
3101 break;
3102
3103 case CONST_INT:
3104 fprintf (file, "%s,%d", reg_names[0], INTVAL (addr));
3105 break;
3106
3107 default:
3108 fprintf (file, "%s,", reg_names[0]);
3109 if (SHORT_ADDRESS_P (addr, temp))
3110 {
3111 fprintf (file, "%siw16(", m88k_pound_sign);
3112 output_addr_const (file, addr);
3113 fputc (')', file);
3114 }
3115 else
3116 output_addr_const (file, addr);
3117 }
3118 }
3119
3120 /* Return true if X is an address which needs a temporary register when
3121 reloaded while generating PIC code. */
3122
3123 int
3124 pic_address_needs_scratch (x)
3125 rtx x;
3126 {
3127 /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */
3128 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
3129 && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
3130 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
3131 && ! ADD_INT (XEXP (XEXP (x, 0), 1)))
3132 return 1;
3133
3134 return 0;
3135 }
3136
3137 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
3138 reference and a constant. */
3139
3140 int
3141 symbolic_operand (op, mode)
3142 register rtx op;
3143 enum machine_mode mode;
3144 {
3145 switch (GET_CODE (op))
3146 {
3147 case SYMBOL_REF:
3148 case LABEL_REF:
3149 return 1;
3150
3151 case CONST:
3152 op = XEXP (op, 0);
3153 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
3154 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
3155 && GET_CODE (XEXP (op, 1)) == CONST_INT);
3156
3157 /* ??? This clause seems to be irrelevant. */
3158 case CONST_DOUBLE:
3159 return GET_MODE (op) == mode;
3160
3161 default:
3162 return 0;
3163 }
3164 }
This page took 0.171456 seconds and 5 git commands to generate.