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