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