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