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