]> gcc.gnu.org Git - gcc.git/blob - gcc/config/mips/mips.c
* config/mips/mips.c (mips_asm_file_start): Handle ABICALLS_ASM_OP.
[gcc.git] / gcc / config / mips / mips.c
1 /* Subroutines for insn-output.c for MIPS
2 Contributed by A. Lichnewsky, lich@inria.inria.fr.
3 Changes by Michael Meissner, meissner@osf.org.
4 Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
5
6 This file is part of GNU CC.
7
8 GNU CC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 GNU CC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GNU CC; see the file COPYING. If not, write to
20 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21
22 #include "config.h"
23 #include "rtl.h"
24 #include "regs.h"
25 #include "hard-reg-set.h"
26 #include "real.h"
27 #include "insn-config.h"
28 #include "conditions.h"
29 #include "insn-flags.h"
30 #include "insn-attr.h"
31 #include "insn-codes.h"
32 #include "recog.h"
33 #include "output.h"
34
35 #undef MAX /* sys/param.h may also define these */
36 #undef MIN
37
38 #include <stdio.h>
39 #include <signal.h>
40 #include <sys/types.h>
41 #include <sys/file.h>
42 #include <ctype.h>
43 #include "tree.h"
44 #include "expr.h"
45 #include "flags.h"
46
47 #ifndef R_OK
48 #define R_OK 4
49 #define W_OK 2
50 #define X_OK 1
51 #endif
52
53 #if defined(USG) || defined(NO_STAB_H)
54 #include "gstab.h" /* If doing DBX on sysV, use our own stab.h. */
55 #else
56 #include <stab.h> /* On BSD, use the system's stab.h. */
57 #endif /* not USG */
58
59 #ifdef __GNU_STAB__
60 #define STAB_CODE_TYPE enum __stab_debug_code
61 #else
62 #define STAB_CODE_TYPE int
63 #endif
64
65 extern void abort ();
66 extern int atoi ();
67 extern char *getenv ();
68 extern char *mktemp ();
69
70 extern rtx adj_offsettable_operand ();
71 extern rtx copy_to_reg ();
72 extern void error ();
73 extern void fatal ();
74 extern tree lookup_name ();
75 extern void pfatal_with_name ();
76 extern void warning ();
77
78 extern tree current_function_decl;
79 extern FILE *asm_out_file;
80
81 /* Enumeration for all of the relational tests, so that we can build
82 arrays indexed by the test type, and not worry about the order
83 of EQ, NE, etc. */
84
85 enum internal_test {
86 ITEST_EQ,
87 ITEST_NE,
88 ITEST_GT,
89 ITEST_GE,
90 ITEST_LT,
91 ITEST_LE,
92 ITEST_GTU,
93 ITEST_GEU,
94 ITEST_LTU,
95 ITEST_LEU,
96 ITEST_MAX
97 };
98
99 /* Global variables for machine-dependent things. */
100
101 /* Threshold for data being put into the small data/bss area, instead
102 of the normal data area (references to the small data/bss area take
103 1 instruction, and use the global pointer, references to the normal
104 data area takes 2 instructions). */
105 int mips_section_threshold = -1;
106
107 /* Count the number of .file directives, so that .loc is up to date. */
108 int num_source_filenames = 0;
109
110 /* Count the number of sdb related labels are generated (to find block
111 start and end boundaries). */
112 int sdb_label_count = 0;
113
114 /* Next label # for each statment for Silicon Graphics IRIS systems. */
115 int sym_lineno = 0;
116
117 /* Non-zero if inside of a function, because the stupid MIPS asm can't
118 handle .files inside of functions. */
119 int inside_function = 0;
120
121 /* Files to separate the text and the data output, so that all of the data
122 can be emitted before the text, which will mean that the assembler will
123 generate smaller code, based on the global pointer. */
124 FILE *asm_out_data_file;
125 FILE *asm_out_text_file;
126
127 /* Linked list of all externals that are to be emitted when optimizing
128 for the global pointer if they haven't been declared by the end of
129 the program with an appropriate .comm or initialization. */
130
131 struct extern_list {
132 struct extern_list *next; /* next external */
133 char *name; /* name of the external */
134 int size; /* size in bytes */
135 } *extern_head = 0;
136
137 /* Name of the file containing the current function. */
138 char *current_function_file = "";
139
140 /* Warning given that Mips ECOFF can't support changing files
141 within a function. */
142 int file_in_function_warning = FALSE;
143
144 /* Whether to suppress issuing .loc's because the user attempted
145 to change the filename within a function. */
146 int ignore_line_number = FALSE;
147
148 /* Number of nested .set noreorder, noat, nomacro, and volatile requests. */
149 int set_noreorder;
150 int set_noat;
151 int set_nomacro;
152 int set_volatile;
153
154 /* The next branch instruction is a branch likely, not branch normal. */
155 int mips_branch_likely;
156
157 /* Count of delay slots and how many are filled. */
158 int dslots_load_total;
159 int dslots_load_filled;
160 int dslots_jump_total;
161 int dslots_jump_filled;
162
163 /* # of nops needed by previous insn */
164 int dslots_number_nops;
165
166 /* Number of 1/2/3 word references to data items (ie, not jal's). */
167 int num_refs[3];
168
169 /* registers to check for load delay */
170 rtx mips_load_reg, mips_load_reg2, mips_load_reg3, mips_load_reg4;
171
172 /* Cached operands, and operator to compare for use in set/branch on
173 condition codes. */
174 rtx branch_cmp[2];
175
176 /* what type of branch to use */
177 enum cmp_type branch_type;
178
179 /* Number of previously seen half-pic pointers and references. */
180 static int prev_half_pic_ptrs = 0;
181 static int prev_half_pic_refs = 0;
182
183 /* which cpu are we scheduling for */
184 enum processor_type mips_cpu;
185
186 /* which instruction set architecture to use. */
187 int mips_isa;
188
189 /* Strings to hold which cpu and instruction set architecture to use. */
190 char *mips_cpu_string; /* for -mcpu=<xxx> */
191 char *mips_isa_string; /* for -mips{1,2,3} */
192
193 /* Array to RTX class classification. At present, we care about
194 whether the operator is an add-type operator, or a divide/modulus,
195 and if divide/modulus, whether it is unsigned. This is for the
196 peephole code. */
197 char mips_rtx_classify[NUM_RTX_CODE];
198
199 /* Array giving truth value on whether or not a given hard register
200 can support a given mode. */
201 char mips_hard_regno_mode_ok[(int)MAX_MACHINE_MODE][FIRST_PSEUDO_REGISTER];
202
203 /* Current frame information calculated by compute_frame_size. */
204 struct mips_frame_info current_frame_info;
205
206 /* Zero structure to initialize current_frame_info. */
207 struct mips_frame_info zero_frame_info;
208
209 /* Temporary filename used to buffer .text until end of program
210 for -mgpopt. */
211 static char *temp_filename;
212
213 /* List of all MIPS punctuation characters used by print_operand. */
214 char mips_print_operand_punct[256];
215
216 /* Map GCC register number to debugger register number. */
217 int mips_dbx_regno[FIRST_PSEUDO_REGISTER];
218
219 /* Buffer to use to enclose a load/store operation with %{ %} to
220 turn on .set volatile. */
221 static char volatile_buffer[60];
222
223 /* Hardware names for the registers. If -mrnames is used, this
224 will be overwritten with mips_sw_reg_names. */
225
226 char mips_reg_names[][8] =
227 {
228 "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
229 "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
230 "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
231 "$24", "$25", "$26", "$27", "$28", "$sp", "$fp", "$31",
232 "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
233 "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
234 "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
235 "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31",
236 "hi", "lo", "$fcr31"
237 };
238
239 /* Mips software names for the registers, used to overwrite the
240 mips_reg_names array. */
241
242 char mips_sw_reg_names[][8] =
243 {
244 "$0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
245 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
246 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
247 "t8", "t9", "k0", "k1", "gp", "sp", "$fp", "ra",
248 "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
249 "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
250 "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
251 "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31",
252 "hi", "lo", "$fcr31"
253 };
254
255 /* Map hard register number to register class */
256 enum reg_class mips_regno_to_class[] =
257 {
258 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
259 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
260 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
261 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
262 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
263 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
264 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
265 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
266 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
267 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
268 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
269 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
270 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
271 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
272 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
273 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
274 HI_REG, LO_REG, ST_REGS
275 };
276
277 /* Map register constraint character to register class. */
278 enum reg_class mips_char_to_class[256] =
279 {
280 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
281 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
282 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
283 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
284 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
285 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
286 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
287 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
288 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
289 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
290 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
291 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
292 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
293 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
294 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
295 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
296 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
297 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
298 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
299 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
300 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
301 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
302 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
303 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
304 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
305 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
306 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
307 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
308 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
309 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
310 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
311 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
312 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
313 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
314 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
315 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
316 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
317 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
318 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
319 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
320 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
321 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
322 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
323 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
324 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
325 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
326 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
327 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
328 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
329 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
330 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
331 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
332 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
333 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
334 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
335 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
336 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
337 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
338 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
339 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
340 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
341 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
342 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
343 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
344 };
345
346 \f
347 /* Return truth value of whether OP can be used as an operands
348 where a register or 16 bit unsigned integer is needed. */
349
350 int
351 uns_arith_operand (op, mode)
352 rtx op;
353 enum machine_mode mode;
354 {
355 if (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (op))
356 return TRUE;
357
358 return register_operand (op, mode);
359 }
360
361 /* Return truth value of whether OP can be used as an operands
362 where a 16 bit integer is needed */
363
364 int
365 arith_operand (op, mode)
366 rtx op;
367 enum machine_mode mode;
368 {
369 if (GET_CODE (op) == CONST_INT && SMALL_INT (op))
370 return TRUE;
371
372 return register_operand (op, mode);
373 }
374
375 /* Return truth value of whether OP can be used as an operand in a two
376 address arithmetic insn (such as set 123456,%o4) of mode MODE. */
377
378 int
379 arith32_operand (op, mode)
380 rtx op;
381 enum machine_mode mode;
382 {
383 if (GET_CODE (op) == CONST_INT)
384 return TRUE;
385
386 return register_operand (op, mode);
387 }
388
389 /* Return truth value of whether OP is a integer which fits in 16 bits */
390
391 int
392 small_int (op, mode)
393 rtx op;
394 enum machine_mode mode;
395 {
396 return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
397 }
398
399 /* Return truth value of whether OP is an integer which is too big to
400 be loaded with one instruction. */
401
402 int
403 large_int (op, mode)
404 rtx op;
405 enum machine_mode mode;
406 {
407 HOST_WIDE_INT value;
408
409 if (GET_CODE (op) != CONST_INT)
410 return FALSE;
411
412 value = INTVAL (op);
413 if ((value & ~0x0000ffff) == 0) /* ior reg,$r0,value */
414 return FALSE;
415
416 if (((unsigned long)(value + 32768)) <= 32767) /* subu reg,$r0,value */
417 return FALSE;
418
419 if ((value & 0xffff0000) == value) /* lui reg,value>>16 */
420 return FALSE;
421
422 return TRUE;
423 }
424
425 /* Return truth value of whether OP is a register or the constant 0. */
426
427 int
428 reg_or_0_operand (op, mode)
429 rtx op;
430 enum machine_mode mode;
431 {
432 switch (GET_CODE (op))
433 {
434 default:
435 break;
436
437 case CONST_INT:
438 return (INTVAL (op) == 0);
439
440 case CONST_DOUBLE:
441 if (CONST_DOUBLE_HIGH (op) != 0 || CONST_DOUBLE_LOW (op) != 0)
442 return FALSE;
443
444 return TRUE;
445
446 case REG:
447 case SUBREG:
448 return register_operand (op, mode);
449 }
450
451 return FALSE;
452 }
453
454 /* Return truth value of whether OP is one of the special multiply/divide
455 registers (hi, lo). */
456
457 int
458 md_register_operand (op, mode)
459 rtx op;
460 enum machine_mode mode;
461 {
462 return (GET_MODE_CLASS (mode) == MODE_INT
463 && GET_CODE (op) == REG
464 && MD_REG_P (REGNO (op)));
465 }
466
467 /* Return truth value of whether OP is the FP status register. */
468
469 int
470 fpsw_register_operand (op, mode)
471 rtx op;
472 enum machine_mode mode;
473 {
474 return (GET_CODE (op) == REG && ST_REG_P (REGNO (op)));
475 }
476
477 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
478
479 int
480 mips_const_double_ok (op, mode)
481 rtx op;
482 enum machine_mode mode;
483 {
484 if (GET_CODE (op) != CONST_DOUBLE)
485 return FALSE;
486
487 if (mode == DImode)
488 return TRUE;
489
490 if (mode != SFmode && mode != DFmode)
491 return FALSE;
492
493 if (CONST_DOUBLE_HIGH (op) == 0 && CONST_DOUBLE_LOW (op) == 0)
494 return TRUE;
495
496 #if HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
497 if (TARGET_MIPS_AS) /* gas doesn't like li.d/li.s yet */
498 {
499 union { double d; int i[2]; } u;
500 double d;
501
502 u.i[0] = CONST_DOUBLE_LOW (op);
503 u.i[1] = CONST_DOUBLE_HIGH (op);
504 d = u.d;
505
506 if (d != d)
507 return FALSE; /* NAN */
508
509 if (d < 0.0)
510 d = - d;
511
512 /* Rather than trying to get the accuracy down to the last bit,
513 just use approximate ranges. */
514
515 if (mode == DFmode && d > 1.0e-300 && d < 1.0e300)
516 return TRUE;
517
518 if (mode == SFmode && d > 1.0e-38 && d < 1.0e+38)
519 return TRUE;
520 }
521 #endif
522
523 return FALSE;
524 }
525
526 /* Return truth value if a memory operand fits in a single instruction
527 (ie, register + small offset). */
528
529 int
530 simple_memory_operand (op, mode)
531 rtx op;
532 enum machine_mode mode;
533 {
534 rtx addr, plus0, plus1;
535
536 /* Eliminate non-memory operations */
537 if (GET_CODE (op) != MEM)
538 return FALSE;
539
540 /* dword operations really put out 2 instructions, so eliminate them. */
541 if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4))
542 return FALSE;
543
544 /* Decode the address now. */
545 addr = XEXP (op, 0);
546 switch (GET_CODE (addr))
547 {
548 default:
549 break;
550
551 case REG:
552 return TRUE;
553
554 case CONST_INT:
555 return SMALL_INT (op);
556
557 case PLUS:
558 plus0 = XEXP (addr, 0);
559 plus1 = XEXP (addr, 1);
560 if (GET_CODE (plus0) == REG
561 && GET_CODE (plus1) == CONST_INT
562 && SMALL_INT (plus1))
563 return TRUE;
564
565 else if (GET_CODE (plus1) == REG
566 && GET_CODE (plus0) == CONST_INT
567 && SMALL_INT (plus0))
568 return TRUE;
569
570 else
571 return FALSE;
572
573 #if 0
574 /* We used to allow small symbol refs here (ie, stuff in .sdata
575 or .sbss), but this causes some bugs in G++. Also, it won't
576 interfere if the MIPS linker rewrites the store instruction
577 because the function is PIC. */
578
579 case LABEL_REF: /* never gp relative */
580 break;
581
582 case CONST:
583 /* If -G 0, we can never have a GP relative memory operation.
584 Also, save some time if not optimizing. */
585 if (mips_section_threshold == 0 || !optimize || !TARGET_GP_OPT)
586 return FALSE;
587
588 {
589 rtx offset = const0_rtx;
590 addr = eliminate_constant_term (addr, &offset);
591 if (GET_CODE (op) != SYMBOL_REF)
592 return FALSE;
593
594 /* let's be paranoid.... */
595 if (INTVAL (offset) < 0 || INTVAL (offset) > 0xffff)
596 return FALSE;
597 }
598 /* fall through */
599
600 case SYMBOL_REF:
601 return SYMBOL_REF_FLAG (addr);
602 #endif
603 }
604
605 return FALSE;
606 }
607
608 /* Return true if the code of this rtx pattern is EQ or NE. */
609
610 int
611 equality_op (op, mode)
612 rtx op;
613 enum machine_mode mode;
614 {
615 if (mode != GET_MODE (op))
616 return FALSE;
617
618 return (classify_op (op, mode) & CLASS_EQUALITY_OP) != 0;
619 }
620
621 /* Return true if the code is a relational operations (EQ, LE, etc.) */
622
623 int
624 cmp_op (op, mode)
625 rtx op;
626 enum machine_mode mode;
627 {
628 if (mode != GET_MODE (op))
629 return FALSE;
630
631 return (classify_op (op, mode) & CLASS_CMP_OP) != 0;
632 }
633
634
635 /* Genrecog does not take the type of match_operator into consideration,
636 and would complain about two patterns being the same if the same
637 function is used, so make it believe they are different. */
638
639 int
640 cmp2_op (op, mode)
641 rtx op;
642 enum machine_mode mode;
643 {
644 if (mode != GET_MODE (op))
645 return FALSE;
646
647 return (classify_op (op, mode) & CLASS_CMP_OP) != 0;
648 }
649
650 /* Return true if the code is an unsigned relational operations (LEU, etc.) */
651
652 int
653 uns_cmp_op (op,mode)
654 rtx op;
655 enum machine_mode mode;
656 {
657 if (mode != GET_MODE (op))
658 return FALSE;
659
660 return (classify_op (op, mode) & CLASS_UNS_CMP_OP) == CLASS_UNS_CMP_OP;
661 }
662
663 /* Return true if the code is a relational operation FP can use. */
664
665 int
666 fcmp_op (op, mode)
667 rtx op;
668 enum machine_mode mode;
669 {
670 if (mode != GET_MODE (op))
671 return FALSE;
672
673 return (classify_op (op, mode) & CLASS_FCMP_OP) != 0;
674 }
675
676
677 /* Return true if the operand is either the PC or a label_ref. */
678
679 int
680 pc_or_label_operand (op, mode)
681 rtx op;
682 enum machine_mode mode;
683 {
684 if (op == pc_rtx)
685 return TRUE;
686
687 if (GET_CODE (op) == LABEL_REF)
688 return TRUE;
689
690 return FALSE;
691 }
692
693 /* Test for a valid operand for a call instruction.
694 Don't allow the arg pointer register or virtual regs
695 since they may change into reg + const, which the patterns
696 can't handle yet. */
697
698 int
699 call_insn_operand (op, mode)
700 rtx op;
701 enum machine_mode mode;
702 {
703 if (GET_CODE (op) == MEM
704 && (CONSTANT_ADDRESS_P (XEXP (op, 0))
705 || (GET_CODE (XEXP (op, 0)) == REG
706 && XEXP (op, 0) != arg_pointer_rtx
707 && !(REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER
708 && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))
709 return 1;
710 return 0;
711 }
712 \f
713 /* Return an operand string if the given instruction's delay slot or
714 wrap it in a .set noreorder section. This is for filling delay
715 slots on load type instructions under GAS, which does no reordering
716 on its own. For the MIPS assembler, all we do is update the filled
717 delay slot statistics.
718
719 We assume that operands[0] is the target register that is set.
720
721 In order to check the next insn, most of this functionality is moved
722 to FINAL_PRESCAN_INSN, and we just set the global variables that
723 it needs. */
724
725 char *
726 mips_fill_delay_slot (ret, type, operands, cur_insn)
727 char *ret; /* normal string to return */
728 enum delay_type type; /* type of delay */
729 rtx operands[]; /* operands to use */
730 rtx cur_insn; /* current insn */
731 {
732 register rtx set_reg;
733 register enum machine_mode mode;
734 register rtx next_insn = (cur_insn) ? NEXT_INSN (cur_insn) : (rtx)0;
735 register int num_nops;
736
737 if (type == DELAY_LOAD || type == DELAY_FCMP)
738 num_nops = 1;
739
740 else if (type == DELAY_HILO)
741 num_nops = 2;
742
743 else
744 num_nops = 0;
745
746 /* Make sure that we don't put nop's after labels. */
747 next_insn = NEXT_INSN (cur_insn);
748 while (next_insn != (rtx)0 && GET_CODE (next_insn) == NOTE)
749 next_insn = NEXT_INSN (next_insn);
750
751 dslots_load_total += num_nops;
752 if (TARGET_DEBUG_F_MODE
753 || !optimize
754 || type == DELAY_NONE
755 || operands == (rtx *)0
756 || cur_insn == (rtx)0
757 || next_insn == (rtx)0
758 || GET_CODE (next_insn) == CODE_LABEL
759 || (set_reg = operands[0]) == (rtx)0)
760 {
761 dslots_number_nops = 0;
762 mips_load_reg = (rtx)0;
763 mips_load_reg2 = (rtx)0;
764 mips_load_reg3 = (rtx)0;
765 mips_load_reg4 = (rtx)0;
766 return ret;
767 }
768
769 set_reg = operands[0];
770 if (set_reg == (rtx)0)
771 return ret;
772
773 while (GET_CODE (set_reg) == SUBREG)
774 set_reg = SUBREG_REG (set_reg);
775
776 mode = GET_MODE (set_reg);
777 dslots_number_nops = num_nops;
778 mips_load_reg = set_reg;
779 mips_load_reg2 = (mode == DImode || mode == DFmode)
780 ? gen_rtx (REG, SImode, REGNO (set_reg) + 1)
781 : (rtx)0;
782
783 if (type == DELAY_HILO)
784 {
785 mips_load_reg3 = gen_rtx (REG, SImode, MD_REG_FIRST);
786 mips_load_reg4 = gen_rtx (REG, SImode, MD_REG_FIRST+1);
787 }
788 else
789 {
790 mips_load_reg3 = 0;
791 mips_load_reg4 = 0;
792 }
793
794 if (TARGET_GAS && set_noreorder++ == 0)
795 fputs ("\t.set\tnoreorder\n", asm_out_file);
796
797 return ret;
798 }
799
800 \f
801 /* Determine whether a memory reference takes one (based off of the GP pointer),
802 two (normal), or three (label + reg) instructions, and bump the appropriate
803 counter for -mstats. */
804
805 void
806 mips_count_memory_refs (op, num)
807 rtx op;
808 int num;
809 {
810 int additional = 0;
811 int n_words = 0;
812 rtx addr, plus0, plus1;
813 enum rtx_code code0, code1;
814 int looping;
815
816 if (TARGET_DEBUG_B_MODE)
817 {
818 fprintf (stderr, "\n========== mips_count_memory_refs:\n");
819 debug_rtx (op);
820 }
821
822 /* Skip MEM if passed, otherwise handle movsi of address. */
823 addr = (GET_CODE (op) != MEM) ? op : XEXP (op, 0);
824
825 /* Loop, going through the address RTL */
826 do
827 {
828 looping = FALSE;
829 switch (GET_CODE (addr))
830 {
831 default:
832 break;
833
834 case REG:
835 case CONST_INT:
836 break;
837
838 case PLUS:
839 plus0 = XEXP (addr, 0);
840 plus1 = XEXP (addr, 1);
841 code0 = GET_CODE (plus0);
842 code1 = GET_CODE (plus1);
843
844 if (code0 == REG)
845 {
846 additional++;
847 addr = plus1;
848 looping = TRUE;
849 continue;
850 }
851
852 if (code0 == CONST_INT)
853 {
854 addr = plus1;
855 looping = TRUE;
856 continue;
857 }
858
859 if (code1 == REG)
860 {
861 additional++;
862 addr = plus0;
863 looping = TRUE;
864 continue;
865 }
866
867 if (code1 == CONST_INT)
868 {
869 addr = plus0;
870 looping = TRUE;
871 continue;
872 }
873
874 if (code0 == SYMBOL_REF || code0 == LABEL_REF || code0 == CONST)
875 {
876 addr = plus0;
877 looping = TRUE;
878 continue;
879 }
880
881 if (code1 == SYMBOL_REF || code1 == LABEL_REF || code1 == CONST)
882 {
883 addr = plus1;
884 looping = TRUE;
885 continue;
886 }
887
888 break;
889
890 case LABEL_REF:
891 n_words = 2; /* always 2 words */
892 break;
893
894 case CONST:
895 addr = XEXP (addr, 0);
896 looping = TRUE;
897 continue;
898
899 case SYMBOL_REF:
900 n_words = SYMBOL_REF_FLAG (addr) ? 1 : 2;
901 break;
902 }
903 }
904 while (looping);
905
906 if (n_words == 0)
907 return;
908
909 n_words += additional;
910 if (n_words > 3)
911 n_words = 3;
912
913 num_refs[n_words-1] += num;
914 }
915
916 \f
917 /* Return the appropriate instructions to move one operand to another. */
918
919 char *
920 mips_move_1word (operands, insn, unsignedp)
921 rtx operands[];
922 rtx insn;
923 int unsignedp;
924 {
925 char *ret = 0;
926 rtx op0 = operands[0];
927 rtx op1 = operands[1];
928 enum rtx_code code0 = GET_CODE (op0);
929 enum rtx_code code1 = GET_CODE (op1);
930 enum machine_mode mode = GET_MODE (op0);
931 int subreg_word0 = 0;
932 int subreg_word1 = 0;
933 enum delay_type delay = DELAY_NONE;
934
935 while (code0 == SUBREG)
936 {
937 subreg_word0 += SUBREG_WORD (op0);
938 op0 = SUBREG_REG (op0);
939 code0 = GET_CODE (op0);
940 }
941
942 while (code1 == SUBREG)
943 {
944 subreg_word1 += SUBREG_WORD (op1);
945 op1 = SUBREG_REG (op1);
946 code1 = GET_CODE (op1);
947 }
948
949 if (code0 == REG)
950 {
951 int regno0 = REGNO (op0) + subreg_word0;
952
953 if (code1 == REG)
954 {
955 int regno1 = REGNO (op1) + subreg_word1;
956
957 /* Just in case, don't do anything for assigning a register
958 to itself, unless we are filling a delay slot. */
959 if (regno0 == regno1 && set_nomacro == 0)
960 ret = "";
961
962 else if (GP_REG_P (regno0))
963 {
964 if (GP_REG_P (regno1))
965 ret = "move\t%0,%1";
966
967 else if (MD_REG_P (regno1))
968 {
969 delay = DELAY_HILO;
970 ret = "mf%1\t%0";
971 }
972
973 else
974 {
975 delay = DELAY_LOAD;
976 if (FP_REG_P (regno1))
977 ret = "mfc1\t%0,%1";
978
979 else if (regno1 == FPSW_REGNUM)
980 ret = "cfc1\t%0,$31";
981 }
982 }
983
984 else if (FP_REG_P (regno0))
985 {
986 if (GP_REG_P (regno1))
987 {
988 delay = DELAY_LOAD;
989 ret = "mtc1\t%1,%0";
990 }
991
992 if (FP_REG_P (regno1))
993 ret = "mov.s\t%0,%1";
994 }
995
996 else if (MD_REG_P (regno0))
997 {
998 if (GP_REG_P (regno1))
999 {
1000 delay = DELAY_HILO;
1001 ret = "mt%0\t%1";
1002 }
1003 }
1004
1005 else if (regno0 == FPSW_REGNUM)
1006 {
1007 if (GP_REG_P (regno1))
1008 {
1009 delay = DELAY_LOAD;
1010 ret = "ctc1\t%0,$31";
1011 }
1012 }
1013 }
1014
1015 else if (code1 == MEM)
1016 {
1017 delay = DELAY_LOAD;
1018
1019 if (TARGET_STATS)
1020 mips_count_memory_refs (op1, 1);
1021
1022 if (GP_REG_P (regno0))
1023 {
1024 /* For loads, use the mode of the memory item, instead of the
1025 target, so zero/sign extend can use this code as well. */
1026 switch (GET_MODE (op1))
1027 {
1028 default: break;
1029 case SFmode: ret = "lw\t%0,%1"; break;
1030 case SImode: ret = "lw\t%0,%1"; break;
1031 case HImode: ret = (unsignedp) ? "lhu\t%0,%1" : "lh\t%0,%1"; break;
1032 case QImode: ret = (unsignedp) ? "lbu\t%0,%1" : "lb\t%0,%1"; break;
1033 }
1034 }
1035
1036 else if (FP_REG_P (regno0) && (mode == SImode || mode == SFmode))
1037 ret = "l.s\t%0,%1";
1038
1039 if (ret != (char *)0 && MEM_VOLATILE_P (op1))
1040 {
1041 int i = strlen (ret);
1042 if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
1043 abort ();
1044
1045 sprintf (volatile_buffer, "%%{%s%%}", ret);
1046 ret = volatile_buffer;
1047 }
1048 }
1049
1050 else if (code1 == CONST_INT)
1051 {
1052 if (INTVAL (op1) == 0)
1053 {
1054 if (GP_REG_P (regno0))
1055 ret = "move\t%0,%z1";
1056
1057 else if (FP_REG_P (regno0))
1058 {
1059 delay = DELAY_LOAD;
1060 ret = "mtc1\t%z1,%0";
1061 }
1062 }
1063
1064 else if (GP_REG_P (regno0))
1065 ret = (INTVAL (op1) < 0) ? "li\t%0,%1\t\t\t# %X1" : "li\t%0,%X1\t\t# %1";
1066 }
1067
1068 else if (code1 == CONST_DOUBLE && mode == SFmode)
1069 {
1070 if (CONST_DOUBLE_HIGH (op1) == 0 && CONST_DOUBLE_LOW (op1) == 0)
1071 {
1072 if (GP_REG_P (regno0))
1073 ret = "move\t%0,%.";
1074
1075 else if (FP_REG_P (regno0))
1076 {
1077 delay = DELAY_LOAD;
1078 ret = "mtc1\t%.,%0";
1079 }
1080 }
1081
1082 else
1083 {
1084 delay = DELAY_LOAD;
1085 ret = "li.s\t%0,%1";
1086 }
1087 }
1088
1089 else if (code1 == LABEL_REF)
1090 {
1091 if (TARGET_STATS)
1092 mips_count_memory_refs (op1, 1);
1093
1094 ret = "la\t%0,%a1";
1095 }
1096
1097 else if (code1 == SYMBOL_REF || code1 == CONST)
1098 {
1099 if (HALF_PIC_P () && CONSTANT_P (op1) && HALF_PIC_ADDRESS_P (op1))
1100 {
1101 rtx offset = const0_rtx;
1102
1103 if (GET_CODE (op1) == CONST)
1104 op1 = eliminate_constant_term (XEXP (op1, 0), &offset);
1105
1106 if (GET_CODE (op1) == SYMBOL_REF)
1107 {
1108 operands[2] = HALF_PIC_PTR (op1);
1109
1110 if (TARGET_STATS)
1111 mips_count_memory_refs (operands[2], 1);
1112
1113 if (INTVAL (offset) == 0)
1114 {
1115 delay = DELAY_LOAD;
1116 ret = "lw\t%0,%2";
1117 }
1118 else
1119 {
1120 dslots_load_total++;
1121 operands[3] = offset;
1122 ret = (SMALL_INT (offset))
1123 ? "lw\t%0,%2%#\n\tadd\t%0,%0,%3"
1124 : "lw\t%0,%2%#\n\t%[li\t%@,%3\n\tadd\t%0,%0,%@%]";
1125 }
1126 }
1127 }
1128 else
1129 {
1130 if (TARGET_STATS)
1131 mips_count_memory_refs (op1, 1);
1132
1133 ret = "la\t%0,%a1";
1134 }
1135 }
1136
1137 else if (code1 == PLUS)
1138 {
1139 rtx add_op0 = XEXP (op1, 0);
1140 rtx add_op1 = XEXP (op1, 1);
1141
1142 if (GET_CODE (XEXP (op1, 1)) == REG && GET_CODE (XEXP (op1, 0)) == CONST_INT)
1143 {
1144 add_op0 = XEXP (op1, 1); /* reverse operands */
1145 add_op1 = XEXP (op1, 0);
1146 }
1147
1148 operands[2] = add_op0;
1149 operands[3] = add_op1;
1150 ret = "add%:\t%0,%2,%3";
1151 }
1152 }
1153
1154 else if (code0 == MEM)
1155 {
1156 if (TARGET_STATS)
1157 mips_count_memory_refs (op0, 1);
1158
1159 if (code1 == REG)
1160 {
1161 int regno1 = REGNO (op1) + subreg_word1;
1162
1163 if (GP_REG_P (regno1))
1164 {
1165 switch (mode)
1166 {
1167 default: break;
1168 case SFmode: ret = "sw\t%1,%0"; break;
1169 case SImode: ret = "sw\t%1,%0"; break;
1170 case HImode: ret = "sh\t%1,%0"; break;
1171 case QImode: ret = "sb\t%1,%0"; break;
1172 }
1173 }
1174
1175 else if (FP_REG_P (regno1) && (mode == SImode || mode == SFmode))
1176 ret = "s.s\t%1,%0";
1177 }
1178
1179 else if (code1 == CONST_INT && INTVAL (op1) == 0)
1180 {
1181 switch (mode)
1182 {
1183 default: break;
1184 case SFmode: ret = "sw\t%z1,%0"; break;
1185 case SImode: ret = "sw\t%z1,%0"; break;
1186 case HImode: ret = "sh\t%z1,%0"; break;
1187 case QImode: ret = "sb\t%z1,%0"; break;
1188 }
1189 }
1190
1191 else if (code1 == CONST_DOUBLE && CONST_DOUBLE_HIGH (op1) == 0 && CONST_DOUBLE_LOW (op1) == 0)
1192 {
1193 switch (mode)
1194 {
1195 default: break;
1196 case SFmode: ret = "sw\t%.,%0"; break;
1197 case SImode: ret = "sw\t%.,%0"; break;
1198 case HImode: ret = "sh\t%.,%0"; break;
1199 case QImode: ret = "sb\t%.,%0"; break;
1200 }
1201 }
1202
1203 if (ret != (char *)0 && MEM_VOLATILE_P (op0))
1204 {
1205 int i = strlen (ret);
1206 if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
1207 abort ();
1208
1209 sprintf (volatile_buffer, "%%{%s%%}", ret);
1210 ret = volatile_buffer;
1211 }
1212 }
1213
1214 if (ret == (char *)0)
1215 {
1216 abort_with_insn (insn, "Bad move");
1217 return 0;
1218 }
1219
1220 if (delay != DELAY_NONE)
1221 return mips_fill_delay_slot (ret, delay, operands, insn);
1222
1223 return ret;
1224 }
1225
1226 \f
1227 /* Return the appropriate instructions to move 2 words */
1228
1229 char *
1230 mips_move_2words (operands, insn)
1231 rtx operands[];
1232 rtx insn;
1233 {
1234 char *ret = 0;
1235 rtx op0 = operands[0];
1236 rtx op1 = operands[1];
1237 enum rtx_code code0 = GET_CODE (operands[0]);
1238 enum rtx_code code1 = GET_CODE (operands[1]);
1239 int subreg_word0 = 0;
1240 int subreg_word1 = 0;
1241 enum delay_type delay = DELAY_NONE;
1242
1243 while (code0 == SUBREG)
1244 {
1245 subreg_word0 += SUBREG_WORD (op0);
1246 op0 = SUBREG_REG (op0);
1247 code0 = GET_CODE (op0);
1248 }
1249
1250 while (code1 == SUBREG)
1251 {
1252 subreg_word1 += SUBREG_WORD (op1);
1253 op1 = SUBREG_REG (op1);
1254 code1 = GET_CODE (op1);
1255 }
1256
1257 if (code0 == REG)
1258 {
1259 int regno0 = REGNO (op0) + subreg_word0;
1260
1261 if (code1 == REG)
1262 {
1263 int regno1 = REGNO (op1) + subreg_word1;
1264
1265 /* Just in case, don't do anything for assigning a register
1266 to itself, unless we are filling a delay slot. */
1267 if (regno0 == regno1 && set_nomacro == 0)
1268 ret = "";
1269
1270 else if (FP_REG_P (regno0))
1271 {
1272 if (FP_REG_P (regno1))
1273 ret = "mov.d\t%0,%1";
1274
1275 else
1276 {
1277 delay = DELAY_LOAD;
1278 ret = (TARGET_FLOAT64)
1279 ? "dmtc1\t%1,%0"
1280 : "mtc1\t%L1,%0\n\tmtc1\t%M1,%D0";
1281 }
1282 }
1283
1284 else if (FP_REG_P (regno1))
1285 {
1286 delay = DELAY_LOAD;
1287 ret = (TARGET_FLOAT64)
1288 ? "dmfc1\t%0,%1"
1289 : "mfc1\t%L0,%1\n\tmfc1\t%M0,%D1";
1290 }
1291
1292 else if (MD_REG_P (regno0) && GP_REG_P (regno1))
1293 {
1294 delay = DELAY_HILO;
1295 ret = "mthi\t%M1\n\tmtlo\t%L1";
1296 }
1297
1298 else if (GP_REG_P (regno0) && MD_REG_P (regno1))
1299 {
1300 delay = DELAY_HILO;
1301 ret = "mfhi\t%M0\n\tmflo\t%L0";
1302 }
1303
1304 else if (regno0 != (regno1+1))
1305 ret = "move\t%0,%1\n\tmove\t%D0,%D1";
1306
1307 else
1308 ret = "move\t%D0,%D1\n\tmove\t%0,%1";
1309 }
1310
1311 else if (code1 == CONST_DOUBLE)
1312 {
1313 if (CONST_DOUBLE_HIGH (op1) != 0 || CONST_DOUBLE_LOW (op1) != 0)
1314 {
1315 if (GET_MODE (op1) == DFmode)
1316 {
1317 delay = DELAY_LOAD;
1318 ret = "li.d\t%0,%1";
1319 }
1320
1321 else
1322 {
1323 operands[2] = GEN_INT (CONST_DOUBLE_LOW (op1));
1324 operands[3] = GEN_INT (CONST_DOUBLE_HIGH (op1));
1325 ret = "li\t%M0,%3\n\tli\t%L0,%2";
1326 }
1327 }
1328
1329 else
1330 {
1331 if (GP_REG_P (regno0))
1332 ret = "move\t%0,%.\n\tmove\t%D0,%.";
1333
1334 else if (FP_REG_P (regno0))
1335 {
1336 delay = DELAY_LOAD;
1337 ret = (TARGET_FLOAT64)
1338 ? "dmtc1\t%.,%0"
1339 : "mtc1\t%.,%0\n\tmtc1\t%.,%D0";
1340 }
1341 }
1342 }
1343
1344 else if (code1 == CONST_INT && INTVAL (op1) == 0)
1345 {
1346 if (GP_REG_P (regno0))
1347 ret = "move\t%0,%.\n\tmove\t%D0,%.";
1348
1349 else if (FP_REG_P (regno0))
1350 {
1351 delay = DELAY_LOAD;
1352 ret = (TARGET_FLOAT64)
1353 ? "dmtc1\t%.,%0"
1354 : "mtc1\t%.,%0\n\tmtc1\t%.,%D0";
1355 }
1356 }
1357
1358 else if (code1 == CONST_INT && GET_MODE (op0) == DImode && GP_REG_P (regno0))
1359 {
1360 operands[2] = GEN_INT (INTVAL (operands[1]) >= 0 ? 0 : -1);
1361 ret = "li\t%M0,%2\n\tli\t%L0,%1";
1362 }
1363
1364 else if (code1 == MEM)
1365 {
1366 delay = DELAY_LOAD;
1367
1368 if (TARGET_STATS)
1369 mips_count_memory_refs (op1, 2);
1370
1371 if (FP_REG_P (regno0))
1372 ret = "l.d\t%0,%1";
1373
1374 else if (offsettable_address_p (1, DFmode, XEXP (op1, 0)))
1375 {
1376 operands[2] = adj_offsettable_operand (op1, 4);
1377 if (reg_mentioned_p (op0, op1))
1378 ret = "lw\t%D0,%2\n\tlw\t%0,%1";
1379 else
1380 ret = "lw\t%0,%1\n\tlw\t%D0,%2";
1381 }
1382
1383 if (ret != (char *)0 && MEM_VOLATILE_P (op1))
1384 {
1385 int i = strlen (ret);
1386 if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
1387 abort ();
1388
1389 sprintf (volatile_buffer, "%%{%s%%}", ret);
1390 ret = volatile_buffer;
1391 }
1392 }
1393 }
1394
1395 else if (code0 == MEM)
1396 {
1397 if (code1 == REG)
1398 {
1399 int regno1 = REGNO (op1) + subreg_word1;
1400
1401 if (FP_REG_P (regno1))
1402 ret = "s.d\t%1,%0";
1403
1404 else if (offsettable_address_p (1, DFmode, XEXP (op0, 0)))
1405 {
1406 operands[2] = adj_offsettable_operand (op0, 4);
1407 ret = "sw\t%1,%0\n\tsw\t%D1,%2";
1408 }
1409 }
1410
1411 else if (code1 == CONST_DOUBLE
1412 && CONST_DOUBLE_HIGH (op1) == 0
1413 && CONST_DOUBLE_LOW (op1) == 0
1414 && offsettable_address_p (1, DFmode, XEXP (op0, 0)))
1415 {
1416 if (TARGET_FLOAT64)
1417 ret = "sd\t%.,%0";
1418 else
1419 {
1420 operands[2] = adj_offsettable_operand (op0, 4);
1421 ret = "sw\t%.,%0\n\tsw\t%.,%2";
1422 }
1423 }
1424
1425 if (TARGET_STATS)
1426 mips_count_memory_refs (op0, 2);
1427
1428 if (ret != (char *)0 && MEM_VOLATILE_P (op0))
1429 {
1430 int i = strlen (ret);
1431 if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
1432 abort ();
1433
1434 sprintf (volatile_buffer, "%%{%s%%}", ret);
1435 ret = volatile_buffer;
1436 }
1437 }
1438
1439 if (ret == (char *)0)
1440 {
1441 abort_with_insn (insn, "Bad move");
1442 return 0;
1443 }
1444
1445 if (delay != DELAY_NONE)
1446 return mips_fill_delay_slot (ret, delay, operands, insn);
1447
1448 return ret;
1449 }
1450
1451 \f
1452 /* Provide the costs of an addressing mode that contains ADDR.
1453 If ADDR is not a valid address, its cost is irrelevant. */
1454
1455 int
1456 mips_address_cost (addr)
1457 rtx addr;
1458 {
1459 switch (GET_CODE (addr))
1460 {
1461 default:
1462 break;
1463
1464 case LO_SUM:
1465 case HIGH:
1466 return 1;
1467
1468 case LABEL_REF:
1469 return 2;
1470
1471 case CONST:
1472 {
1473 rtx offset = const0_rtx;
1474 addr = eliminate_constant_term (addr, &offset);
1475 if (GET_CODE (addr) == LABEL_REF)
1476 return 2;
1477
1478 if (GET_CODE (addr) != SYMBOL_REF)
1479 return 4;
1480
1481 if (INTVAL (offset) < -32768 || INTVAL (offset) > 32767)
1482 return 2;
1483 }
1484 /* fall through */
1485
1486 case SYMBOL_REF:
1487 return SYMBOL_REF_FLAG (addr) ? 1 : 2;
1488
1489 case PLUS:
1490 {
1491 register rtx plus0 = XEXP (addr, 0);
1492 register rtx plus1 = XEXP (addr, 1);
1493
1494 if (GET_CODE (plus0) != REG && GET_CODE (plus1) == REG)
1495 {
1496 plus0 = XEXP (addr, 1);
1497 plus1 = XEXP (addr, 0);
1498 }
1499
1500 if (GET_CODE (plus0) != REG)
1501 break;
1502
1503 switch (GET_CODE (plus1))
1504 {
1505 default:
1506 break;
1507
1508 case CONST_INT:
1509 {
1510 int value = INTVAL (plus1);
1511 return (value < -32768 || value > 32767) ? 2 : 1;
1512 }
1513
1514 case CONST:
1515 case SYMBOL_REF:
1516 case LABEL_REF:
1517 case HIGH:
1518 case LO_SUM:
1519 return mips_address_cost (plus1) + 1;
1520 }
1521 }
1522 }
1523
1524 return 4;
1525 }
1526
1527 \f
1528 /* Make normal rtx_code into something we can index from an array */
1529
1530 static enum internal_test
1531 map_test_to_internal_test (test_code)
1532 enum rtx_code test_code;
1533 {
1534 enum internal_test test = ITEST_MAX;
1535
1536 switch (test_code)
1537 {
1538 default: break;
1539 case EQ: test = ITEST_EQ; break;
1540 case NE: test = ITEST_NE; break;
1541 case GT: test = ITEST_GT; break;
1542 case GE: test = ITEST_GE; break;
1543 case LT: test = ITEST_LT; break;
1544 case LE: test = ITEST_LE; break;
1545 case GTU: test = ITEST_GTU; break;
1546 case GEU: test = ITEST_GEU; break;
1547 case LTU: test = ITEST_LTU; break;
1548 case LEU: test = ITEST_LEU; break;
1549 }
1550
1551 return test;
1552 }
1553
1554 \f
1555 /* Generate the code to compare two integer values. The return value is:
1556 (reg:SI xx) The pseudo register the comparison is in
1557 (rtx)0 No register, generate a simple branch. */
1558
1559 rtx
1560 gen_int_relational (test_code, result, cmp0, cmp1, p_invert)
1561 enum rtx_code test_code; /* relational test (EQ, etc) */
1562 rtx result; /* result to store comp. or 0 if branch */
1563 rtx cmp0; /* first operand to compare */
1564 rtx cmp1; /* second operand to compare */
1565 int *p_invert; /* NULL or ptr to hold whether branch needs */
1566 /* to reverse its test */
1567 {
1568 struct cmp_info {
1569 enum rtx_code test_code; /* code to use in instruction (LT vs. LTU) */
1570 int const_low; /* low bound of constant we can accept */
1571 int const_high; /* high bound of constant we can accept */
1572 int const_add; /* constant to add (convert LE -> LT) */
1573 int reverse_regs; /* reverse registers in test */
1574 int invert_const; /* != 0 if invert value if cmp1 is constant */
1575 int invert_reg; /* != 0 if invert value if cmp1 is register */
1576 int unsignedp; /* != 0 for unsigned comparisons. */
1577 };
1578
1579 static struct cmp_info info[ (int)ITEST_MAX ] = {
1580
1581 { XOR, 0, 65535, 0, 0, 0, 0, 0 }, /* EQ */
1582 { XOR, 0, 65535, 0, 0, 1, 1, 0 }, /* NE */
1583 { LT, -32769, 32766, 1, 1, 1, 0, 0 }, /* GT */
1584 { LT, -32768, 32767, 0, 0, 1, 1, 0 }, /* GE */
1585 { LT, -32768, 32767, 0, 0, 0, 0, 0 }, /* LT */
1586 { LT, -32769, 32766, 1, 1, 0, 1, 0 }, /* LE */
1587 { LTU, -32769, 32766, 1, 1, 1, 0, 1 }, /* GTU */
1588 { LTU, -32768, 32767, 0, 0, 1, 1, 1 }, /* GEU */
1589 { LTU, -32768, 32767, 0, 0, 0, 0, 1 }, /* LTU */
1590 { LTU, -32769, 32766, 1, 1, 0, 1, 1 }, /* LEU */
1591 };
1592
1593 enum internal_test test;
1594 struct cmp_info *p_info;
1595 int branch_p;
1596 int eqne_p;
1597 int invert;
1598 rtx reg;
1599 rtx reg2;
1600
1601 test = map_test_to_internal_test (test_code);
1602 if (test == ITEST_MAX)
1603 abort ();
1604
1605 p_info = &info[ (int)test ];
1606 eqne_p = (p_info->test_code == XOR);
1607
1608 /* Eliminate simple branches */
1609 branch_p = (result == (rtx)0);
1610 if (branch_p)
1611 {
1612 if (GET_CODE (cmp0) == REG || GET_CODE (cmp0) == SUBREG)
1613 {
1614 /* Comparisons against zero are simple branches */
1615 if (GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) == 0)
1616 return (rtx)0;
1617
1618 /* Test for beq/bne. */
1619 if (eqne_p)
1620 return (rtx)0;
1621 }
1622
1623 /* allocate a pseudo to calculate the value in. */
1624 result = gen_reg_rtx (SImode);
1625 }
1626
1627 /* Make sure we can handle any constants given to us. */
1628 if (GET_CODE (cmp0) == CONST_INT)
1629 cmp0 = force_reg (SImode, cmp0);
1630
1631 if (GET_CODE (cmp1) == CONST_INT)
1632 {
1633 HOST_WIDE_INT value = INTVAL (cmp1);
1634 if (value < p_info->const_low || value > p_info->const_high)
1635 cmp1 = force_reg (SImode, cmp1);
1636 }
1637
1638 /* See if we need to invert the result. */
1639 invert = (GET_CODE (cmp1) == CONST_INT)
1640 ? p_info->invert_const
1641 : p_info->invert_reg;
1642
1643 if (p_invert != (int *)0)
1644 {
1645 *p_invert = invert;
1646 invert = FALSE;
1647 }
1648
1649 /* Comparison to constants, may involve adding 1 to change a LT into LE.
1650 Comparison between two registers, may involve switching operands. */
1651 if (GET_CODE (cmp1) == CONST_INT)
1652 {
1653 if (p_info->const_add != 0)
1654 {
1655 HOST_WIDE_INT new = INTVAL (cmp1) + p_info->const_add;
1656 /* If modification of cmp1 caused overflow,
1657 we would get the wrong answer if we follow the usual path;
1658 thus, x > 0xffffffffu would turn into x > 0u. */
1659 if ((p_info->unsignedp
1660 ? (unsigned HOST_WIDE_INT) new > INTVAL (cmp1)
1661 : new > INTVAL (cmp1))
1662 != (p_info->const_add > 0))
1663 {
1664 /* This test is always true, but if INVERT is true then
1665 the result of the test needs to be inverted so 0 should
1666 be returned instead. */
1667 emit_move_insn (result, invert ? const0_rtx : const_true_rtx);
1668 return result;
1669 }
1670 else
1671 cmp1 = GEN_INT (new);
1672 }
1673 }
1674 else if (p_info->reverse_regs)
1675 {
1676 rtx temp = cmp0;
1677 cmp0 = cmp1;
1678 cmp1 = temp;
1679 }
1680
1681 if (test == ITEST_NE && GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) == 0)
1682 reg = cmp0;
1683 else
1684 {
1685 reg = (invert || eqne_p) ? gen_reg_rtx (SImode) : result;
1686 emit_move_insn (reg, gen_rtx (p_info->test_code, SImode, cmp0, cmp1));
1687 }
1688
1689 if (test == ITEST_NE)
1690 {
1691 emit_move_insn (result, gen_rtx (GTU, SImode, reg, const0_rtx));
1692 invert = FALSE;
1693 }
1694
1695 else if (test == ITEST_EQ)
1696 {
1697 reg2 = (invert) ? gen_reg_rtx (SImode) : result;
1698 emit_move_insn (reg2, gen_rtx (LTU, SImode, reg, const1_rtx));
1699 reg = reg2;
1700 }
1701
1702 if (invert)
1703 emit_move_insn (result, gen_rtx (XOR, SImode, reg, const1_rtx));
1704
1705 return result;
1706 }
1707
1708 \f
1709 /* Emit the common code for doing conditional branches.
1710 operand[0] is the label to jump to.
1711 The comparison operands are saved away by cmp{si,sf,df}. */
1712
1713 void
1714 gen_conditional_branch (operands, test_code)
1715 rtx operands[];
1716 enum rtx_code test_code;
1717 {
1718 static enum machine_mode mode_map[(int)CMP_MAX][(int)ITEST_MAX] = {
1719 { /* CMP_SI */
1720 SImode, /* eq */
1721 SImode, /* ne */
1722 SImode, /* gt */
1723 SImode, /* ge */
1724 SImode, /* lt */
1725 SImode, /* le */
1726 SImode, /* gtu */
1727 SImode, /* geu */
1728 SImode, /* ltu */
1729 SImode, /* leu */
1730 },
1731 { /* CMP_SF */
1732 CC_FPmode, /* eq */
1733 CC_REV_FPmode, /* ne */
1734 CC_FPmode, /* gt */
1735 CC_FPmode, /* ge */
1736 CC_FPmode, /* lt */
1737 CC_FPmode, /* le */
1738 VOIDmode, /* gtu */
1739 VOIDmode, /* geu */
1740 VOIDmode, /* ltu */
1741 VOIDmode, /* leu */
1742 },
1743 { /* CMP_DF */
1744 CC_FPmode, /* eq */
1745 CC_REV_FPmode, /* ne */
1746 CC_FPmode, /* gt */
1747 CC_FPmode, /* ge */
1748 CC_FPmode, /* lt */
1749 CC_FPmode, /* le */
1750 VOIDmode, /* gtu */
1751 VOIDmode, /* geu */
1752 VOIDmode, /* ltu */
1753 VOIDmode, /* leu */
1754 },
1755 };
1756
1757 enum machine_mode mode;
1758 enum cmp_type type = branch_type;
1759 rtx cmp0 = branch_cmp[0];
1760 rtx cmp1 = branch_cmp[1];
1761 rtx label1 = gen_rtx (LABEL_REF, VOIDmode, operands[0]);
1762 rtx label2 = pc_rtx;
1763 rtx reg = (rtx)0;
1764 int invert = 0;
1765 enum internal_test test = map_test_to_internal_test (test_code);
1766
1767 if (test == ITEST_MAX)
1768 {
1769 mode = SImode;
1770 goto fail;
1771 }
1772
1773 /* Get the machine mode to use (CCmode, CC_EQmode, CC_FPmode, or CC_REV_FPmode). */
1774 mode = mode_map[(int)type][(int)test];
1775 if (mode == VOIDmode)
1776 goto fail;
1777
1778 switch (branch_type)
1779 {
1780 default:
1781 goto fail;
1782
1783 case CMP_SI:
1784 reg = gen_int_relational (test_code, (rtx)0, cmp0, cmp1, &invert);
1785 if (reg != (rtx)0)
1786 {
1787 cmp0 = reg;
1788 cmp1 = const0_rtx;
1789 test_code = NE;
1790 }
1791
1792 /* Make sure not non-zero constant if ==/!= */
1793 else if (GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) != 0)
1794 cmp1 = force_reg (SImode, cmp1);
1795
1796 break;
1797
1798 case CMP_DF:
1799 case CMP_SF:
1800 {
1801 rtx reg = gen_rtx (REG, mode, FPSW_REGNUM);
1802 emit_insn (gen_rtx (SET, VOIDmode, reg, gen_rtx (test_code, mode, cmp0, cmp1)));
1803 cmp0 = reg;
1804 cmp1 = const0_rtx;
1805 test_code = NE;
1806 }
1807 break;
1808 }
1809
1810 /* Generate the jump */
1811 if (invert)
1812 {
1813 label2 = label1;
1814 label1 = pc_rtx;
1815 }
1816
1817 emit_jump_insn (gen_rtx (SET, VOIDmode,
1818 pc_rtx,
1819 gen_rtx (IF_THEN_ELSE, VOIDmode,
1820 gen_rtx (test_code, mode, cmp0, cmp1),
1821 label1,
1822 label2)));
1823
1824 return;
1825
1826 fail:
1827 abort_with_insn (gen_rtx (test_code, mode, cmp0, cmp1), "bad test");
1828 }
1829
1830 \f
1831 #define UNITS_PER_SHORT (SHORT_TYPE_SIZE / BITS_PER_UNIT)
1832
1833 /* Internal code to generate the load and store of one word/short/byte.
1834 The load is emitted directly, and the store insn is returned. */
1835
1836 #if 0
1837 static rtx
1838 block_move_load_store (dest_reg, src_reg, p_bytes, p_offset, align, orig_src)
1839 rtx src_reg; /* register holding source memory address */
1840 rtx dest_reg; /* register holding dest. memory address */
1841 int *p_bytes; /* pointer to # bytes remaining */
1842 int *p_offset; /* pointer to current offset */
1843 int align; /* alignment */
1844 rtx orig_src; /* original source for making a reg note */
1845 {
1846 int bytes; /* # bytes remaining */
1847 int offset; /* offset to use */
1848 int size; /* size in bytes of load/store */
1849 enum machine_mode mode; /* mode to use for load/store */
1850 rtx reg; /* temporary register */
1851 rtx src_addr; /* source address */
1852 rtx dest_addr; /* destination address */
1853 rtx insn; /* insn of the load */
1854 rtx orig_src_addr; /* original source address */
1855 rtx (*load_func)(); /* function to generate load insn */
1856 rtx (*store_func)(); /* function to generate destination insn */
1857
1858 bytes = *p_bytes;
1859 if (bytes <= 0 || align <= 0)
1860 abort ();
1861
1862 if (bytes >= UNITS_PER_WORD && align >= UNITS_PER_WORD)
1863 {
1864 mode = SImode;
1865 size = UNITS_PER_WORD;
1866 load_func = gen_movsi;
1867 store_func = gen_movsi;
1868 }
1869
1870 #if 0
1871 /* Don't generate unaligned moves here, rather defer those to the
1872 general movestrsi_internal pattern. */
1873 else if (bytes >= UNITS_PER_WORD)
1874 {
1875 mode = SImode;
1876 size = UNITS_PER_WORD;
1877 load_func = gen_movsi_ulw;
1878 store_func = gen_movsi_usw;
1879 }
1880 #endif
1881
1882 else if (bytes >= UNITS_PER_SHORT && align >= UNITS_PER_SHORT)
1883 {
1884 mode = HImode;
1885 size = UNITS_PER_SHORT;
1886 load_func = gen_movhi;
1887 store_func = gen_movhi;
1888 }
1889
1890 else
1891 {
1892 mode = QImode;
1893 size = 1;
1894 load_func = gen_movqi;
1895 store_func = gen_movqi;
1896 }
1897
1898 offset = *p_offset;
1899 *p_offset = offset + size;
1900 *p_bytes = bytes - size;
1901
1902 if (offset == 0)
1903 {
1904 src_addr = src_reg;
1905 dest_addr = dest_reg;
1906 }
1907 else
1908 {
1909 src_addr = gen_rtx (PLUS, Pmode, src_reg, GEN_INT (offset));
1910 dest_addr = gen_rtx (PLUS, Pmode, dest_reg, GEN_INT (offset));
1911 }
1912
1913 reg = gen_reg_rtx (mode);
1914 insn = emit_insn ((*load_func) (reg, gen_rtx (MEM, mode, src_addr)));
1915 orig_src_addr = XEXP (orig_src, 0);
1916 if (CONSTANT_P (orig_src_addr))
1917 REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUIV,
1918 plus_constant (orig_src_addr, offset),
1919 REG_NOTES (insn));
1920
1921 return (*store_func) (gen_rtx (MEM, mode, dest_addr), reg);
1922 }
1923 #endif
1924
1925 \f
1926 /* Write a series of loads/stores to move some bytes. Generate load/stores as follows:
1927
1928 load 1
1929 load 2
1930 load 3
1931 store 1
1932 load 4
1933 store 2
1934 load 5
1935 store 3
1936 ...
1937
1938 This way, no NOP's are needed, except at the end, and only
1939 two temp registers are needed. Two delay slots are used
1940 in deference to the R4000. */
1941
1942 #if 0
1943 static void
1944 block_move_sequence (dest_reg, src_reg, bytes, align, orig_src)
1945 rtx dest_reg; /* register holding destination address */
1946 rtx src_reg; /* register holding source address */
1947 int bytes; /* # bytes to move */
1948 int align; /* max alignment to assume */
1949 rtx orig_src; /* original source for making a reg note */
1950 {
1951 int offset = 0;
1952 rtx prev2_store = (rtx)0;
1953 rtx prev_store = (rtx)0;
1954 rtx cur_store = (rtx)0;
1955
1956 while (bytes > 0)
1957 {
1958 /* Is there a store to do? */
1959 if (prev2_store)
1960 emit_insn (prev2_store);
1961
1962 prev2_store = prev_store;
1963 prev_store = cur_store;
1964 cur_store = block_move_load_store (dest_reg, src_reg,
1965 &bytes, &offset,
1966 align, orig_src);
1967 }
1968
1969 /* Finish up last three stores. */
1970 if (prev2_store)
1971 emit_insn (prev2_store);
1972
1973 if (prev_store)
1974 emit_insn (prev_store);
1975
1976 if (cur_store)
1977 emit_insn (cur_store);
1978 }
1979 #endif
1980
1981 \f
1982 /* Write a loop to move a constant number of bytes. Generate load/stores as follows:
1983
1984 do {
1985 temp1 = src[0];
1986 temp2 = src[1];
1987 ...
1988 temp<last> = src[MAX_MOVE_REGS-1];
1989 dest[0] = temp1;
1990 dest[1] = temp2;
1991 ...
1992 dest[MAX_MOVE_REGS-1] = temp<last>;
1993 src += MAX_MOVE_REGS;
1994 dest += MAX_MOVE_REGS;
1995 } while (src != final);
1996
1997 This way, no NOP's are needed, and only MAX_MOVE_REGS+3 temp
1998 registers are needed.
1999
2000 Aligned moves move MAX_MOVE_REGS*4 bytes every (2*MAX_MOVE_REGS)+3
2001 cycles, unaligned moves move MAX_MOVE_REGS*4 bytes every
2002 (4*MAX_MOVE_REGS)+3 cycles, assuming no cache misses. */
2003
2004 #define MAX_MOVE_REGS 4
2005 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
2006
2007 static void
2008 block_move_loop (dest_reg, src_reg, bytes, align, orig_src)
2009 rtx dest_reg; /* register holding destination address */
2010 rtx src_reg; /* register holding source address */
2011 int bytes; /* # bytes to move */
2012 int align; /* alignment */
2013 rtx orig_src; /* original source for making a reg note */
2014 {
2015 rtx dest_mem = gen_rtx (MEM, BLKmode, dest_reg);
2016 rtx src_mem = gen_rtx (MEM, BLKmode, src_reg);
2017 rtx align_rtx = GEN_INT (align);
2018 rtx label;
2019 rtx final_src;
2020 rtx bytes_rtx;
2021 int leftover;
2022
2023 if (bytes < 2*MAX_MOVE_BYTES)
2024 abort ();
2025
2026 leftover = bytes % MAX_MOVE_BYTES;
2027 bytes -= leftover;
2028
2029 label = gen_label_rtx ();
2030 final_src = gen_reg_rtx (Pmode);
2031 bytes_rtx = GEN_INT (bytes);
2032
2033 if (bytes > 0x7fff)
2034 {
2035 emit_insn (gen_movsi (final_src, bytes_rtx));
2036 emit_insn (gen_addsi3 (final_src, final_src, src_reg));
2037 }
2038 else
2039 emit_insn (gen_addsi3 (final_src, src_reg, bytes_rtx));
2040
2041 emit_label (label);
2042
2043 bytes_rtx = GEN_INT (MAX_MOVE_BYTES);
2044 emit_insn (gen_movstrsi_internal (dest_mem, src_mem, bytes_rtx, align_rtx));
2045 emit_insn (gen_addsi3 (src_reg, src_reg, bytes_rtx));
2046 emit_insn (gen_addsi3 (dest_reg, dest_reg, bytes_rtx));
2047 emit_insn (gen_cmpsi (src_reg, final_src));
2048 emit_jump_insn (gen_bne (label));
2049
2050 if (leftover)
2051 emit_insn (gen_movstrsi_internal (dest_mem, src_mem,
2052 GEN_INT (leftover),
2053 align_rtx));
2054 }
2055
2056 \f
2057 /* Use a library function to move some bytes. */
2058
2059 static void
2060 block_move_call (dest_reg, src_reg, bytes_rtx)
2061 rtx dest_reg;
2062 rtx src_reg;
2063 rtx bytes_rtx;
2064 {
2065 #ifdef TARGET_MEM_FUNCTIONS
2066 emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0,
2067 VOIDmode, 3,
2068 dest_reg, Pmode,
2069 src_reg, Pmode,
2070 bytes_rtx, SImode);
2071 #else
2072 emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), 0,
2073 VOIDmode, 3,
2074 src_reg, Pmode,
2075 dest_reg, Pmode,
2076 bytes_rtx, SImode);
2077 #endif
2078 }
2079
2080 \f
2081 /* Expand string/block move operations.
2082
2083 operands[0] is the pointer to the destination.
2084 operands[1] is the pointer to the source.
2085 operands[2] is the number of bytes to move.
2086 operands[3] is the alignment. */
2087
2088 void
2089 expand_block_move (operands)
2090 rtx operands[];
2091 {
2092 rtx bytes_rtx = operands[2];
2093 rtx align_rtx = operands[3];
2094 int constp = (GET_CODE (bytes_rtx) == CONST_INT);
2095 int bytes = (constp ? INTVAL (bytes_rtx) : 0);
2096 int align = INTVAL (align_rtx);
2097 rtx orig_src = operands[1];
2098 rtx src_reg;
2099 rtx dest_reg;
2100
2101 if (constp && bytes <= 0)
2102 return;
2103
2104 if (align > UNITS_PER_WORD)
2105 align = UNITS_PER_WORD;
2106
2107 /* Move the address into scratch registers. */
2108 dest_reg = copy_addr_to_reg (XEXP (operands[0], 0));
2109 src_reg = copy_addr_to_reg (XEXP (orig_src, 0));
2110
2111 if (TARGET_MEMCPY)
2112 block_move_call (dest_reg, src_reg, bytes_rtx);
2113
2114 #if 0
2115 else if (constp && bytes <= 3*align)
2116 block_move_sequence (dest_reg, src_reg, bytes, align, orig_src);
2117 #endif
2118
2119 else if (constp && bytes <= 2*MAX_MOVE_BYTES)
2120 emit_insn (gen_movstrsi_internal (gen_rtx (MEM, BLKmode, dest_reg),
2121 gen_rtx (MEM, BLKmode, src_reg),
2122 bytes_rtx, align_rtx));
2123
2124 else if (constp && align >= UNITS_PER_WORD && optimize)
2125 block_move_loop (dest_reg, src_reg, bytes, align, orig_src);
2126
2127 else if (constp && optimize)
2128 {
2129 /* If the alignment is not word aligned, generate a test at
2130 runtime, to see whether things wound up aligned, and we
2131 can use the faster lw/sw instead ulw/usw. */
2132
2133 rtx temp = gen_reg_rtx (Pmode);
2134 rtx aligned_label = gen_label_rtx ();
2135 rtx join_label = gen_label_rtx ();
2136 int leftover = bytes % MAX_MOVE_BYTES;
2137
2138 bytes -= leftover;
2139
2140 emit_insn (gen_iorsi3 (temp, src_reg, dest_reg));
2141 emit_insn (gen_andsi3 (temp, temp, GEN_INT (UNITS_PER_WORD-1)));
2142 emit_insn (gen_cmpsi (temp, const0_rtx));
2143 emit_jump_insn (gen_beq (aligned_label));
2144
2145 /* Unaligned loop. */
2146 block_move_loop (dest_reg, src_reg, bytes, 1, orig_src);
2147 emit_jump_insn (gen_jump (join_label));
2148 emit_barrier ();
2149
2150 /* Aligned loop. */
2151 emit_label (aligned_label);
2152 block_move_loop (dest_reg, src_reg, bytes, UNITS_PER_WORD, orig_src);
2153 emit_label (join_label);
2154
2155 /* Bytes at the end of the loop. */
2156 if (leftover)
2157 {
2158 #if 0
2159 if (leftover <= 3*align)
2160 block_move_sequence (dest_reg, src_reg, leftover, align, orig_src);
2161
2162 else
2163 #endif
2164 emit_insn (gen_movstrsi_internal (gen_rtx (MEM, BLKmode, dest_reg),
2165 gen_rtx (MEM, BLKmode, src_reg),
2166 GEN_INT (leftover),
2167 GEN_INT (align)));
2168 }
2169 }
2170
2171 else
2172 block_move_call (dest_reg, src_reg, bytes_rtx);
2173 }
2174
2175 \f
2176 /* Emit load/stores for a small constant block_move.
2177
2178 operands[0] is the memory address of the destination.
2179 operands[1] is the memory address of the source.
2180 operands[2] is the number of bytes to move.
2181 operands[3] is the alignment.
2182 operands[4] is a temp register.
2183 operands[5] is a temp register.
2184 ...
2185 operands[3+num_regs] is the last temp register.
2186
2187 The block move type can be one of the following:
2188 BLOCK_MOVE_NORMAL Do all of the block move.
2189 BLOCK_MOVE_NOT_LAST Do all but the last store.
2190 BLOCK_MOVE_LAST Do just the last store. */
2191
2192 char *
2193 output_block_move (insn, operands, num_regs, move_type)
2194 rtx insn;
2195 rtx operands[];
2196 int num_regs;
2197 enum block_move_type move_type;
2198 {
2199 rtx dest_reg = XEXP (operands[0], 0);
2200 rtx src_reg = XEXP (operands[1], 0);
2201 int bytes = INTVAL (operands[2]);
2202 int align = INTVAL (operands[3]);
2203 int num = 0;
2204 int offset = 0;
2205 int use_lwl_lwr = FALSE;
2206 int last_operand = num_regs+4;
2207 int safe_regs = 4;
2208 int i;
2209 rtx xoperands[10];
2210
2211 struct {
2212 char *load; /* load insn without nop */
2213 char *load_nop; /* load insn with trailing nop */
2214 char *store; /* store insn */
2215 char *final; /* if last_store used: NULL or swr */
2216 char *last_store; /* last store instruction */
2217 int offset; /* current offset */
2218 enum machine_mode mode; /* mode to use on (MEM) */
2219 } load_store[4];
2220
2221 /* Detect a bug in GCC, where it can give us a register
2222 the same as one of the addressing registers and reduce
2223 the number of registers available. */
2224 for (i = 4;
2225 i < last_operand && safe_regs < (sizeof(xoperands) / sizeof(xoperands[0]));
2226 i++)
2227 {
2228 if (!reg_mentioned_p (operands[i], operands[0])
2229 && !reg_mentioned_p (operands[i], operands[1]))
2230
2231 xoperands[safe_regs++] = operands[i];
2232 }
2233
2234 if (safe_regs < last_operand)
2235 {
2236 xoperands[0] = operands[0];
2237 xoperands[1] = operands[1];
2238 xoperands[2] = operands[2];
2239 xoperands[3] = operands[3];
2240 return output_block_move (insn, xoperands, safe_regs-4, move_type);
2241 }
2242
2243 /* If we are given global or static addresses, and we would be
2244 emitting a few instructions, try to save time by using a
2245 temporary register for the pointer. */
2246 if (num_regs > 2 && (bytes > 2*align || move_type != BLOCK_MOVE_NORMAL))
2247 {
2248 if (CONSTANT_P (src_reg))
2249 {
2250 if (TARGET_STATS)
2251 mips_count_memory_refs (operands[1], 1);
2252
2253 src_reg = operands[ 3 + num_regs-- ];
2254 if (move_type != BLOCK_MOVE_LAST)
2255 {
2256 xoperands[1] = operands[1];
2257 xoperands[0] = src_reg;
2258 output_asm_insn ("la\t%0,%1", xoperands);
2259 }
2260 }
2261
2262 if (CONSTANT_P (dest_reg))
2263 {
2264 if (TARGET_STATS)
2265 mips_count_memory_refs (operands[0], 1);
2266
2267 dest_reg = operands[ 3 + num_regs-- ];
2268 if (move_type != BLOCK_MOVE_LAST)
2269 {
2270 xoperands[1] = operands[0];
2271 xoperands[0] = dest_reg;
2272 output_asm_insn ("la\t%0,%1", xoperands);
2273 }
2274 }
2275 }
2276
2277 if (num_regs > (sizeof (load_store) / sizeof (load_store[0])))
2278 num_regs = (sizeof (load_store) / sizeof (load_store[0]));
2279
2280 else if (num_regs < 1)
2281 abort_with_insn (insn, "Cannot do block move, not enough scratch registers");
2282
2283 if (TARGET_GAS && move_type != BLOCK_MOVE_LAST && set_noreorder++ == 0)
2284 output_asm_insn (".set\tnoreorder", operands);
2285
2286 while (bytes > 0)
2287 {
2288 load_store[num].offset = offset;
2289
2290 if (bytes >= UNITS_PER_WORD && align >= UNITS_PER_WORD)
2291 {
2292 load_store[num].load = "lw\t%0,%1";
2293 load_store[num].load_nop = "lw\t%0,%1%#";
2294 load_store[num].store = "sw\t%0,%1";
2295 load_store[num].last_store = "sw\t%0,%1";
2296 load_store[num].final = (char *)0;
2297 load_store[num].mode = SImode;
2298 offset += UNITS_PER_WORD;
2299 bytes -= UNITS_PER_WORD;
2300 }
2301
2302 else if (bytes >= UNITS_PER_WORD)
2303 {
2304 #if BYTES_BIG_ENDIAN
2305 load_store[num].load = "lwl\t%0,%1\n\tlwr\t%0,%2";
2306 load_store[num].load_nop = "lwl\t%0,%1\n\tlwr\t%0,%2%#";
2307 load_store[num].store = "swl\t%0,%1\n\tswr\t%0,%2";
2308 load_store[num].last_store = "swr\t%0,%2";
2309 load_store[num].final = "swl\t%0,%1";
2310 #else
2311 load_store[num].load = "lwl\t%0,%2\n\tlwr\t%0,%1";
2312 load_store[num].load_nop = "lwl\t%0,%2\n\tlwr\t%0,%1%#";
2313 load_store[num].store = "swl\t%0,%2\n\tswr\t%0,%1";
2314 load_store[num].last_store = "swr\t%0,%1";
2315 load_store[num].final = "swl\t%0,%2";
2316 #endif
2317 load_store[num].mode = SImode;
2318 offset += UNITS_PER_WORD;
2319 bytes -= UNITS_PER_WORD;
2320 use_lwl_lwr = TRUE;
2321 }
2322
2323 else if (bytes >= UNITS_PER_SHORT && align >= UNITS_PER_SHORT)
2324 {
2325 load_store[num].load = "lh\t%0,%1";
2326 load_store[num].load_nop = "lh\t%0,%1%#";
2327 load_store[num].store = "sh\t%0,%1";
2328 load_store[num].last_store = "sh\t%0,%1";
2329 load_store[num].final = (char *)0;
2330 load_store[num].offset = offset;
2331 load_store[num].mode = HImode;
2332 offset += UNITS_PER_SHORT;
2333 bytes -= UNITS_PER_SHORT;
2334 }
2335
2336 else
2337 {
2338 load_store[num].load = "lb\t%0,%1";
2339 load_store[num].load_nop = "lb\t%0,%1%#";
2340 load_store[num].store = "sb\t%0,%1";
2341 load_store[num].last_store = "sb\t%0,%1";
2342 load_store[num].final = (char *)0;
2343 load_store[num].mode = QImode;
2344 offset++;
2345 bytes--;
2346 }
2347
2348 if (TARGET_STATS && move_type != BLOCK_MOVE_LAST)
2349 {
2350 dslots_load_total++;
2351 dslots_load_filled++;
2352
2353 if (CONSTANT_P (src_reg))
2354 mips_count_memory_refs (src_reg, 1);
2355
2356 if (CONSTANT_P (dest_reg))
2357 mips_count_memory_refs (dest_reg, 1);
2358 }
2359
2360 /* Emit load/stores now if we have run out of registers or are
2361 at the end of the move. */
2362
2363 if (++num == num_regs || bytes == 0)
2364 {
2365 /* If only load/store, we need a NOP after the load. */
2366 if (num == 1)
2367 {
2368 load_store[0].load = load_store[0].load_nop;
2369 if (TARGET_STATS && move_type != BLOCK_MOVE_LAST)
2370 dslots_load_filled--;
2371 }
2372
2373 if (move_type != BLOCK_MOVE_LAST)
2374 {
2375 for (i = 0; i < num; i++)
2376 {
2377 int offset;
2378
2379 if (!operands[i+4])
2380 abort ();
2381
2382 if (GET_MODE (operands[i+4]) != load_store[i].mode)
2383 operands[i+4] = gen_rtx (REG, load_store[i].mode, REGNO (operands[i+4]));
2384
2385 offset = load_store[i].offset;
2386 xoperands[0] = operands[i+4];
2387 xoperands[1] = gen_rtx (MEM, load_store[i].mode,
2388 plus_constant (src_reg, offset));
2389
2390 if (use_lwl_lwr)
2391 xoperands[2] = gen_rtx (MEM, load_store[i].mode,
2392 plus_constant (src_reg, UNITS_PER_WORD-1+offset));
2393
2394 output_asm_insn (load_store[i].load, xoperands);
2395 }
2396 }
2397
2398 for (i = 0; i < num; i++)
2399 {
2400 int last_p = (i == num-1 && bytes == 0);
2401 int offset = load_store[i].offset;
2402
2403 xoperands[0] = operands[i+4];
2404 xoperands[1] = gen_rtx (MEM, load_store[i].mode,
2405 plus_constant (dest_reg, offset));
2406
2407
2408 if (use_lwl_lwr)
2409 xoperands[2] = gen_rtx (MEM, load_store[i].mode,
2410 plus_constant (dest_reg, UNITS_PER_WORD-1+offset));
2411
2412 if (move_type == BLOCK_MOVE_NORMAL)
2413 output_asm_insn (load_store[i].store, xoperands);
2414
2415 else if (move_type == BLOCK_MOVE_NOT_LAST)
2416 {
2417 if (!last_p)
2418 output_asm_insn (load_store[i].store, xoperands);
2419
2420 else if (load_store[i].final != (char *)0)
2421 output_asm_insn (load_store[i].final, xoperands);
2422 }
2423
2424 else if (last_p)
2425 output_asm_insn (load_store[i].last_store, xoperands);
2426 }
2427
2428 num = 0; /* reset load_store */
2429 use_lwl_lwr = FALSE; /* reset whether or not we used lwl/lwr */
2430 }
2431 }
2432
2433 if (TARGET_GAS && move_type != BLOCK_MOVE_LAST && --set_noreorder == 0)
2434 output_asm_insn (".set\treorder", operands);
2435
2436 return "";
2437 }
2438
2439 \f
2440 /* Argument support functions. */
2441
2442 /* Initialize CUMULATIVE_ARGS for a function. */
2443
2444 void
2445 init_cumulative_args (cum, fntype, libname)
2446 CUMULATIVE_ARGS *cum; /* argument info to initialize */
2447 tree fntype; /* tree ptr for function decl */
2448 rtx libname; /* SYMBOL_REF of library name or 0 */
2449 {
2450 static CUMULATIVE_ARGS zero_cum;
2451 tree param, next_param;
2452
2453 if (TARGET_DEBUG_E_MODE)
2454 {
2455 fprintf (stderr, "\ninit_cumulative_args, fntype = 0x%.8lx", (long)fntype);
2456 if (!fntype)
2457 fputc ('\n', stderr);
2458
2459 else
2460 {
2461 tree ret_type = TREE_TYPE (fntype);
2462 fprintf (stderr, ", fntype code = %s, ret code = %s\n",
2463 tree_code_name[ (int)TREE_CODE (fntype) ],
2464 tree_code_name[ (int)TREE_CODE (ret_type) ]);
2465 }
2466 }
2467
2468 *cum = zero_cum;
2469
2470 /* Determine if this function has variable arguments. This is
2471 indicated by the last argument being 'void_type_mode' if there
2472 are no variable arguments. The standard MIPS calling sequence
2473 passes all arguments in the general purpose registers in this
2474 case. */
2475
2476 for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0;
2477 param != (tree)0;
2478 param = next_param)
2479 {
2480 next_param = TREE_CHAIN (param);
2481 if (next_param == (tree)0 && TREE_VALUE (param) != void_type_node)
2482 cum->gp_reg_found = 1;
2483 }
2484 }
2485
2486 /* Advance the argument to the next argument position. */
2487
2488 void
2489 function_arg_advance (cum, mode, type, named)
2490 CUMULATIVE_ARGS *cum; /* current arg information */
2491 enum machine_mode mode; /* current arg mode */
2492 tree type; /* type of the argument or 0 if lib support */
2493 int named; /* whether or not the argument was named */
2494 {
2495 if (TARGET_DEBUG_E_MODE)
2496 fprintf (stderr,
2497 "function_adv( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d )\n\n",
2498 cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode),
2499 type, named);
2500
2501 cum->arg_number++;
2502 switch (mode)
2503 {
2504 default:
2505 error ("Illegal mode given to function_arg_advance");
2506 break;
2507
2508 case VOIDmode:
2509 break;
2510
2511 case BLKmode:
2512 cum->gp_reg_found = 1;
2513 cum->arg_words += (int_size_in_bytes (type) + 3) / 4;
2514 break;
2515
2516 case SFmode:
2517 cum->arg_words++;
2518 break;
2519
2520 case DFmode:
2521 cum->arg_words += 2;
2522 break;
2523
2524 case DImode:
2525 cum->gp_reg_found = 1;
2526 cum->arg_words += 2;
2527 break;
2528
2529 case QImode:
2530 case HImode:
2531 case SImode:
2532 cum->gp_reg_found = 1;
2533 cum->arg_words++;
2534 break;
2535 }
2536 }
2537
2538 /* Return a RTL expression containing the register for the given mode,
2539 or 0 if the argument is too be passed on the stack. */
2540
2541 struct rtx_def *
2542 function_arg (cum, mode, type, named)
2543 CUMULATIVE_ARGS *cum; /* current arg information */
2544 enum machine_mode mode; /* current arg mode */
2545 tree type; /* type of the argument or 0 if lib support */
2546 int named; /* != 0 for normal args, == 0 for ... args */
2547 {
2548 rtx ret;
2549 int regbase = -1;
2550 int bias = 0;
2551 int struct_p = ((type != (tree)0)
2552 && (TREE_CODE (type) == RECORD_TYPE
2553 || TREE_CODE (type) == UNION_TYPE));
2554
2555 if (TARGET_DEBUG_E_MODE)
2556 fprintf (stderr,
2557 "function_arg( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d ) = ",
2558 cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode),
2559 type, named);
2560
2561 switch (mode)
2562 {
2563 default:
2564 error ("Illegal mode given to function_arg");
2565 break;
2566
2567 case SFmode:
2568 if (cum->gp_reg_found || cum->arg_number >= 2)
2569 regbase = GP_ARG_FIRST;
2570 else {
2571 regbase = (TARGET_SOFT_FLOAT) ? GP_ARG_FIRST : FP_ARG_FIRST;
2572 if (cum->arg_words == 1) /* first arg was float */
2573 bias = 1; /* use correct reg */
2574 }
2575
2576 break;
2577
2578 case DFmode:
2579 cum->arg_words += (cum->arg_words & 1);
2580 regbase = (cum->gp_reg_found || TARGET_SOFT_FLOAT || cum->arg_number >= 2
2581 ? GP_ARG_FIRST
2582 : FP_ARG_FIRST);
2583 break;
2584
2585 case BLKmode:
2586 if (type != (tree)0 && TYPE_ALIGN (type) > BITS_PER_WORD)
2587 cum->arg_words += (cum->arg_words & 1);
2588
2589 regbase = GP_ARG_FIRST;
2590 break;
2591
2592 case VOIDmode:
2593 case QImode:
2594 case HImode:
2595 case SImode:
2596 regbase = GP_ARG_FIRST;
2597 break;
2598
2599 case DImode:
2600 cum->arg_words += (cum->arg_words & 1);
2601 regbase = GP_ARG_FIRST;
2602 }
2603
2604 if (cum->arg_words >= MAX_ARGS_IN_REGISTERS)
2605 {
2606 if (TARGET_DEBUG_E_MODE)
2607 fprintf (stderr, "<stack>%s\n", struct_p ? ", [struct]" : "");
2608
2609 ret = (rtx)0;
2610 }
2611 else
2612 {
2613 if (regbase == -1)
2614 abort ();
2615
2616 ret = gen_rtx (REG, mode, regbase + cum->arg_words + bias);
2617
2618 if (TARGET_DEBUG_E_MODE)
2619 fprintf (stderr, "%s%s\n", reg_names[regbase + cum->arg_words + bias],
2620 struct_p ? ", [struct]" : "");
2621
2622 /* The following is a hack in order to pass 1 byte structures
2623 the same way that the MIPS compiler does (namely by passing
2624 the structure in the high byte or half word of the register).
2625 This also makes varargs work. If we have such a structure,
2626 we save the adjustment RTL, and the call define expands will
2627 emit them. For the VOIDmode argument (argument after the
2628 last real argument, pass back a parallel vector holding each
2629 of the adjustments. */
2630
2631 if (struct_p && int_size_in_bytes (type) < 4)
2632 {
2633 rtx amount = GEN_INT (BITS_PER_WORD
2634 - int_size_in_bytes (type) * BITS_PER_UNIT);
2635 rtx reg = gen_rtx (REG, SImode, regbase + cum->arg_words + bias);
2636 cum->adjust[ cum->num_adjusts++ ] = gen_ashlsi3 (reg, reg, amount);
2637 }
2638 }
2639
2640 if (mode == VOIDmode && cum->num_adjusts > 0)
2641 ret = gen_rtx (PARALLEL, VOIDmode, gen_rtvec_v (cum->num_adjusts, cum->adjust));
2642
2643 return ret;
2644 }
2645
2646
2647 int
2648 function_arg_partial_nregs (cum, mode, type, named)
2649 CUMULATIVE_ARGS *cum; /* current arg information */
2650 enum machine_mode mode; /* current arg mode */
2651 tree type; /* type of the argument or 0 if lib support */
2652 int named; /* != 0 for normal args, == 0 for ... args */
2653 {
2654 if (mode == BLKmode && cum->arg_words < MAX_ARGS_IN_REGISTERS)
2655 {
2656 int words = (int_size_in_bytes (type) + 3) / 4;
2657
2658 if (words + cum->arg_words <= MAX_ARGS_IN_REGISTERS)
2659 return 0; /* structure fits in registers */
2660
2661 if (TARGET_DEBUG_E_MODE)
2662 fprintf (stderr, "function_arg_partial_nregs = %d\n",
2663 MAX_ARGS_IN_REGISTERS - cum->arg_words);
2664
2665 return MAX_ARGS_IN_REGISTERS - cum->arg_words;
2666 }
2667
2668 else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS-1)
2669 {
2670 if (TARGET_DEBUG_E_MODE)
2671 fprintf (stderr, "function_arg_partial_nregs = 1\n");
2672
2673 return 1;
2674 }
2675
2676 return 0;
2677 }
2678
2679 \f
2680 /* Print the options used in the assembly file. */
2681
2682 static struct {char *name; int value;} target_switches []
2683 = TARGET_SWITCHES;
2684
2685 void
2686 print_options (out)
2687 FILE *out;
2688 {
2689 int line_len;
2690 int len;
2691 int j;
2692 char **p;
2693 int mask = TARGET_DEFAULT;
2694
2695 /* Allow assembly language comparisons with -mdebug eliminating the
2696 compiler version number and switch lists. */
2697
2698 if (TARGET_DEBUG_MODE)
2699 return;
2700
2701 fprintf (out, "\n # %s %s", language_string, version_string);
2702 #ifdef TARGET_VERSION_INTERNAL
2703 TARGET_VERSION_INTERNAL (out);
2704 #endif
2705 #ifdef __GNUC__
2706 fprintf (out, " compiled by GNU C\n\n");
2707 #else
2708 fprintf (out, " compiled by CC\n\n");
2709 #endif
2710
2711 fprintf (out, " # Cc1 defaults:");
2712 line_len = 32767;
2713 for (j = 0; j < sizeof target_switches / sizeof target_switches[0]; j++)
2714 {
2715 if (target_switches[j].name[0] != '\0'
2716 && target_switches[j].value > 0
2717 && (target_switches[j].value & mask) == target_switches[j].value)
2718 {
2719 mask &= ~ target_switches[j].value;
2720 len = strlen (target_switches[j].name) + 1;
2721 if (len + line_len > 79)
2722 {
2723 line_len = 2;
2724 fputs ("\n #", out);
2725 }
2726 fprintf (out, " -m%s", target_switches[j].name);
2727 line_len += len;
2728 }
2729 }
2730
2731 fprintf (out, "\n\n # Cc1 arguments (-G value = %d, Cpu = %s, ISA = %d):",
2732 mips_section_threshold, mips_cpu_string, mips_isa);
2733
2734 line_len = 32767;
2735 for (p = &save_argv[1]; *p != (char *)0; p++)
2736 {
2737 char *arg = *p;
2738 if (*arg == '-')
2739 {
2740 len = strlen (arg) + 1;
2741 if (len + line_len > 79)
2742 {
2743 line_len = 2;
2744 fputs ("\n #", out);
2745 }
2746 fprintf (out, " %s", *p);
2747 line_len += len;
2748 }
2749 }
2750
2751 fputs ("\n\n", out);
2752 }
2753
2754 \f
2755 /* Abort after printing out a specific insn. */
2756
2757 void
2758 abort_with_insn (insn, reason)
2759 rtx insn;
2760 char *reason;
2761 {
2762 error (reason);
2763 debug_rtx (insn);
2764 abort ();
2765 }
2766
2767 /* Write a message to stderr (for use in macros expanded in files that do not
2768 include stdio.h). */
2769
2770 void
2771 trace (s, s1, s2)
2772 char *s, *s1, *s2;
2773 {
2774 fprintf (stderr, s, s1, s2);
2775 }
2776
2777 \f
2778 #ifdef SIGINFO
2779
2780 static void
2781 siginfo (signo)
2782 int signo;
2783 {
2784 fprintf (stderr, "compiling '%s' in '%s'\n",
2785 (current_function_name != (char *)0) ? current_function_name : "<toplevel>",
2786 (current_function_file != (char *)0) ? current_function_file : "<no file>");
2787 fflush (stderr);
2788 }
2789 #endif /* SIGINFO */
2790
2791 \f
2792 /* Set up the threshold for data to go into the small data area, instead
2793 of the normal data area, and detect any conflicts in the switches. */
2794
2795 void
2796 override_options ()
2797 {
2798 register int i, start;
2799 register int regno;
2800 register enum machine_mode mode;
2801
2802 mips_section_threshold = (g_switch_set) ? g_switch_value : MIPS_DEFAULT_GVALUE;
2803
2804 /* Identify the processor type */
2805 if (mips_cpu_string == (char *)0
2806 || !strcmp (mips_cpu_string, "default")
2807 || !strcmp (mips_cpu_string, "DEFAULT"))
2808 {
2809 mips_cpu_string = "default";
2810 mips_cpu = PROCESSOR_DEFAULT;
2811 }
2812
2813 else
2814 {
2815 char *p = mips_cpu_string;
2816
2817 if (*p == 'r' || *p == 'R')
2818 p++;
2819
2820 /* Since there is no difference between a R2000 and R3000 in
2821 terms of the scheduler, we collapse them into just an R3000. */
2822
2823 mips_cpu = PROCESSOR_DEFAULT;
2824 switch (*p)
2825 {
2826 case '2':
2827 if (!strcmp (p, "2000") || !strcmp (p, "2k") || !strcmp (p, "2K"))
2828 mips_cpu = PROCESSOR_R3000;
2829 break;
2830
2831 case '3':
2832 if (!strcmp (p, "3000") || !strcmp (p, "3k") || !strcmp (p, "3K"))
2833 mips_cpu = PROCESSOR_R3000;
2834 break;
2835
2836 case '4':
2837 if (!strcmp (p, "4000") || !strcmp (p, "4k") || !strcmp (p, "4K"))
2838 mips_cpu = PROCESSOR_R4000;
2839 break;
2840
2841 case '6':
2842 if (!strcmp (p, "6000") || !strcmp (p, "6k") || !strcmp (p, "6K"))
2843 mips_cpu = PROCESSOR_R6000;
2844 break;
2845 }
2846
2847 if (mips_cpu == PROCESSOR_DEFAULT)
2848 {
2849 error ("bad value (%s) for -mcpu= switch", mips_cpu_string);
2850 mips_cpu_string = "default";
2851 }
2852 }
2853
2854 /* Now get the architectural level. */
2855 if (mips_isa_string == (char *)0)
2856 mips_isa = 1;
2857
2858 else if (isdigit (*mips_isa_string))
2859 mips_isa = atoi (mips_isa_string);
2860
2861 else
2862 {
2863 error ("bad value (%s) for -mips switch", mips_isa_string);
2864 mips_isa = 1;
2865 }
2866
2867 if (mips_isa < 0 || mips_isa > 3)
2868 error ("-mips%d not supported", mips_isa);
2869
2870 else if (mips_isa > 1
2871 && (mips_cpu == PROCESSOR_DEFAULT || mips_cpu == PROCESSOR_R3000))
2872 error ("-mcpu=%s does not support -mips%d", mips_cpu_string, mips_isa);
2873
2874 else if (mips_cpu == PROCESSOR_R6000 && mips_isa > 2)
2875 error ("-mcpu=%s does not support -mips%d", mips_cpu_string, mips_isa);
2876
2877 /* make sure sizes of ints/longs/etc. are ok */
2878 if (mips_isa < 3)
2879 {
2880 if (TARGET_INT64)
2881 fatal ("Only the r4000 can support 64 bit ints");
2882
2883 else if (TARGET_LONG64)
2884 fatal ("Only the r4000 can support 64 bit longs");
2885
2886 else if (TARGET_LLONG128)
2887 fatal ("Only the r4000 can support 128 bit long longs");
2888
2889 else if (TARGET_FLOAT64)
2890 fatal ("Only the r4000 can support 64 bit fp registers");
2891 }
2892 else if (TARGET_INT64 || TARGET_LONG64 || TARGET_LLONG128 || TARGET_FLOAT64)
2893 warning ("r4000 64/128 bit types not yet supported");
2894
2895 /* Tell halfpic.c that we have half-pic code if we do. */
2896 if (TARGET_HALF_PIC)
2897 HALF_PIC_INIT ();
2898
2899 /* -mrnames says to use the MIPS software convention for register
2900 names instead of the hardware names (ie, a0 instead of $4).
2901 We do this by switching the names in mips_reg_names, which the
2902 reg_names points into via the REGISTER_NAMES macro. */
2903
2904 if (TARGET_NAME_REGS)
2905 {
2906 if (TARGET_GAS)
2907 {
2908 target_flags &= ~ MASK_NAME_REGS;
2909 error ("Gas does not support the MIPS software register name convention.");
2910 }
2911 else
2912 bcopy ((char *) mips_sw_reg_names, (char *) mips_reg_names, sizeof (mips_reg_names));
2913 }
2914
2915 /* If this is OSF/1, set up a SIGINFO handler so we can see what function
2916 is currently being compiled. */
2917 #ifdef SIGINFO
2918 if (getenv ("GCC_SIGINFO") != (char *)0)
2919 {
2920 struct sigaction action;
2921 action.sa_handler = siginfo;
2922 action.sa_mask = 0;
2923 action.sa_flags = SA_RESTART;
2924 sigaction (SIGINFO, &action, (struct sigaction *)0);
2925 }
2926 #endif
2927
2928 #if defined(_IOLBF)
2929 #if defined(ultrix) || defined(__ultrix) || defined(__OSF1__) || defined(__osf__) || defined(osf)
2930 /* If -mstats and -quiet, make stderr line buffered. */
2931 if (quiet_flag && TARGET_STATS)
2932 setvbuf (stderr, (char *)0, _IOLBF, BUFSIZ);
2933 #endif
2934 #endif
2935
2936 /* Set up the classification arrays now. */
2937 mips_rtx_classify[(int)PLUS] = CLASS_ADD_OP;
2938 mips_rtx_classify[(int)MINUS] = CLASS_ADD_OP;
2939 mips_rtx_classify[(int)DIV] = CLASS_DIVMOD_OP;
2940 mips_rtx_classify[(int)MOD] = CLASS_DIVMOD_OP;
2941 mips_rtx_classify[(int)UDIV] = CLASS_DIVMOD_OP | CLASS_UNSIGNED_OP;
2942 mips_rtx_classify[(int)UMOD] = CLASS_DIVMOD_OP | CLASS_UNSIGNED_OP;
2943 mips_rtx_classify[(int)EQ] = CLASS_CMP_OP | CLASS_EQUALITY_OP | CLASS_FCMP_OP;
2944 mips_rtx_classify[(int)NE] = CLASS_CMP_OP | CLASS_EQUALITY_OP | CLASS_FCMP_OP;
2945 mips_rtx_classify[(int)GT] = CLASS_CMP_OP | CLASS_FCMP_OP;
2946 mips_rtx_classify[(int)GE] = CLASS_CMP_OP | CLASS_FCMP_OP;
2947 mips_rtx_classify[(int)LT] = CLASS_CMP_OP | CLASS_FCMP_OP;
2948 mips_rtx_classify[(int)LE] = CLASS_CMP_OP | CLASS_FCMP_OP;
2949 mips_rtx_classify[(int)GTU] = CLASS_CMP_OP | CLASS_UNSIGNED_OP;
2950 mips_rtx_classify[(int)GEU] = CLASS_CMP_OP | CLASS_UNSIGNED_OP;
2951 mips_rtx_classify[(int)LTU] = CLASS_CMP_OP | CLASS_UNSIGNED_OP;
2952 mips_rtx_classify[(int)LEU] = CLASS_CMP_OP | CLASS_UNSIGNED_OP;
2953
2954 mips_print_operand_punct['?'] = TRUE;
2955 mips_print_operand_punct['#'] = TRUE;
2956 mips_print_operand_punct['&'] = TRUE;
2957 mips_print_operand_punct['!'] = TRUE;
2958 mips_print_operand_punct['*'] = TRUE;
2959 mips_print_operand_punct['@'] = TRUE;
2960 mips_print_operand_punct['.'] = TRUE;
2961 mips_print_operand_punct['('] = TRUE;
2962 mips_print_operand_punct[')'] = TRUE;
2963 mips_print_operand_punct['['] = TRUE;
2964 mips_print_operand_punct[']'] = TRUE;
2965 mips_print_operand_punct['<'] = TRUE;
2966 mips_print_operand_punct['>'] = TRUE;
2967 mips_print_operand_punct['{'] = TRUE;
2968 mips_print_operand_punct['}'] = TRUE;
2969
2970 mips_char_to_class['d'] = GR_REGS;
2971 mips_char_to_class['f'] = ((TARGET_HARD_FLOAT) ? FP_REGS : NO_REGS);
2972 mips_char_to_class['h'] = HI_REG;
2973 mips_char_to_class['l'] = LO_REG;
2974 mips_char_to_class['x'] = MD_REGS;
2975 mips_char_to_class['y'] = GR_REGS;
2976 mips_char_to_class['z'] = ST_REGS;
2977
2978 /* Set up array to map GCC register number to debug register number.
2979 Ignore the special purpose register numbers. */
2980
2981 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
2982 mips_dbx_regno[i] = -1;
2983
2984 start = GP_DBX_FIRST - GP_REG_FIRST;
2985 for (i = GP_REG_FIRST; i <= GP_REG_LAST; i++)
2986 mips_dbx_regno[i] = i + start;
2987
2988 start = FP_DBX_FIRST - FP_REG_FIRST;
2989 for (i = FP_REG_FIRST; i <= FP_REG_LAST; i++)
2990 mips_dbx_regno[i] = i + start;
2991
2992 /* Set up array giving whether a given register can hold a given mode.
2993 At present, restrict ints from being in FP registers, because reload
2994 is a little enthusiastic about storing extra values in FP registers,
2995 and this is not good for things like OS kernels. Also, due to the
2996 mandatory delay, it is as fast to load from cached memory as to move
2997 from the FP register. */
2998
2999 for (mode = VOIDmode;
3000 mode != MAX_MACHINE_MODE;
3001 mode = (enum machine_mode)((int)mode + 1))
3002 {
3003 register int size = GET_MODE_SIZE (mode);
3004 register enum mode_class class = GET_MODE_CLASS (mode);
3005
3006 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
3007 {
3008 register int temp;
3009
3010 if (mode == CC_FPmode || mode == CC_REV_FPmode)
3011 temp = (regno == FPSW_REGNUM);
3012
3013 else if (GP_REG_P (regno))
3014 temp = ((regno & 1) == 0 || (size <= UNITS_PER_WORD));
3015
3016 else if (FP_REG_P (regno))
3017 temp = ((TARGET_FLOAT64 || ((regno & 1) == 0))
3018 && (class == MODE_FLOAT
3019 || class == MODE_COMPLEX_FLOAT
3020 || (TARGET_DEBUG_H_MODE && class == MODE_INT)));
3021
3022 else if (MD_REG_P (regno))
3023 temp = (mode == SImode || (regno == MD_REG_FIRST && mode == DImode));
3024
3025 else
3026 temp = FALSE;
3027
3028 mips_hard_regno_mode_ok[(int)mode][regno] = temp;
3029 }
3030 }
3031 }
3032
3033 \f
3034 /*
3035 * The MIPS debug format wants all automatic variables and arguments
3036 * to be in terms of the virtual frame pointer (stack pointer before
3037 * any adjustment in the function), while the MIPS 3.0 linker wants
3038 * the frame pointer to be the stack pointer after the initial
3039 * adjustment. So, we do the adjustment here. The arg pointer (which
3040 * is eliminated) points to the virtual frame pointer, while the frame
3041 * pointer (which may be eliminated) points to the stack pointer after
3042 * the initial adjustments.
3043 */
3044
3045 int
3046 mips_debugger_offset (addr, offset)
3047 rtx addr;
3048 int offset;
3049 {
3050 rtx offset2 = const0_rtx;
3051 rtx reg = eliminate_constant_term (addr, &offset2);
3052
3053 if (!offset)
3054 offset = INTVAL (offset2);
3055
3056 if (reg == stack_pointer_rtx || reg == frame_pointer_rtx)
3057 {
3058 int frame_size = (!current_frame_info.initialized)
3059 ? compute_frame_size (get_frame_size ())
3060 : current_frame_info.total_size;
3061
3062 offset = offset - frame_size;
3063 }
3064 /* sdbout_parms does not want this to crash for unrecognized cases. */
3065 #if 0
3066 else if (reg != arg_pointer_rtx)
3067 abort_with_insn (addr, "mips_debugger_offset called with non stack/frame/arg pointer.");
3068 #endif
3069
3070 return offset;
3071 }
3072
3073 \f
3074 /* A C compound statement to output to stdio stream STREAM the
3075 assembler syntax for an instruction operand X. X is an RTL
3076 expression.
3077
3078 CODE is a value that can be used to specify one of several ways
3079 of printing the operand. It is used when identical operands
3080 must be printed differently depending on the context. CODE
3081 comes from the `%' specification that was used to request
3082 printing of the operand. If the specification was just `%DIGIT'
3083 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
3084 is the ASCII code for LTR.
3085
3086 If X is a register, this macro should print the register's name.
3087 The names can be found in an array `reg_names' whose type is
3088 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
3089
3090 When the machine description has a specification `%PUNCT' (a `%'
3091 followed by a punctuation character), this macro is called with
3092 a null pointer for X and the punctuation character for CODE.
3093
3094 The MIPS specific codes are:
3095
3096 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
3097 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
3098 'd' output integer constant in decimal,
3099 'z' if the operand is 0, use $0 instead of normal operand.
3100 'D' print second register of double-word register operand.
3101 'L' print low-order register of double-word register operand.
3102 'M' print high-order register of double-word register operand.
3103 'C' print part of opcode for a branch condition.
3104 'N' print part of opcode for a branch condition, inverted.
3105 '(' Turn on .set noreorder
3106 ')' Turn on .set reorder
3107 '[' Turn on .set noat
3108 ']' Turn on .set at
3109 '<' Turn on .set nomacro
3110 '>' Turn on .set macro
3111 '{' Turn on .set volatile (not GAS)
3112 '}' Turn on .set novolatile (not GAS)
3113 '&' Turn on .set noreorder if filling delay slots
3114 '*' Turn on both .set noreorder and .set nomacro if filling delay slots
3115 '!' Turn on .set nomacro if filling delay slots
3116 '#' Print nop if in a .set noreorder section.
3117 '?' Print 'l' if we are to use a branch likely instead of normal branch.
3118 '@' Print the name of the assembler temporary register (at or $1).
3119 '.' Print the name of the register with a hard-wired zero (zero or $0). */
3120
3121 void
3122 print_operand (file, op, letter)
3123 FILE *file; /* file to write to */
3124 rtx op; /* operand to print */
3125 int letter; /* %<letter> or 0 */
3126 {
3127 register enum rtx_code code;
3128
3129 if (PRINT_OPERAND_PUNCT_VALID_P (letter))
3130 {
3131 switch (letter)
3132 {
3133 default:
3134 error ("PRINT_OPERAND: Unknown punctuation '%c'", letter);
3135 break;
3136
3137 case '?':
3138 if (mips_branch_likely)
3139 putc ('l', file);
3140 break;
3141
3142 case '@':
3143 fputs (reg_names [GP_REG_FIRST + 1], file);
3144 break;
3145
3146 case '.':
3147 fputs (reg_names [GP_REG_FIRST + 0], file);
3148 break;
3149
3150 case '&':
3151 if (final_sequence != 0 && set_noreorder++ == 0)
3152 fputs (".set\tnoreorder\n\t", file);
3153 break;
3154
3155 case '*':
3156 if (final_sequence != 0)
3157 {
3158 if (set_noreorder++ == 0)
3159 fputs (".set\tnoreorder\n\t", file);
3160
3161 if (set_nomacro++ == 0)
3162 fputs (".set\tnomacro\n\t", file);
3163 }
3164 break;
3165
3166 case '!':
3167 if (final_sequence != 0 && set_nomacro++ == 0)
3168 fputs ("\n\t.set\tnomacro", file);
3169 break;
3170
3171 case '#':
3172 if (set_noreorder != 0)
3173 fputs ("\n\tnop", file);
3174
3175 else if (TARGET_GAS || TARGET_STATS)
3176 fputs ("\n\t#nop", file);
3177
3178 break;
3179
3180 case '(':
3181 if (set_noreorder++ == 0)
3182 fputs (".set\tnoreorder\n\t", file);
3183 break;
3184
3185 case ')':
3186 if (set_noreorder == 0)
3187 error ("internal error: %%) found without a %%( in assembler pattern");
3188
3189 else if (--set_noreorder == 0)
3190 fputs ("\n\t.set\treorder", file);
3191
3192 break;
3193
3194 case '[':
3195 if (set_noat++ == 0)
3196 fputs (".set\tnoat\n\t", file);
3197 break;
3198
3199 case ']':
3200 if (set_noat == 0)
3201 error ("internal error: %%] found without a %%[ in assembler pattern");
3202
3203 else if (--set_noat == 0)
3204 fputs ("\n\t.set\tat", file);
3205
3206 break;
3207
3208 case '<':
3209 if (set_nomacro++ == 0)
3210 fputs (".set\tnomacro\n\t", file);
3211 break;
3212
3213 case '>':
3214 if (set_nomacro == 0)
3215 error ("internal error: %%> found without a %%< in assembler pattern");
3216
3217 else if (--set_nomacro == 0)
3218 fputs ("\n\t.set\tmacro", file);
3219
3220 break;
3221
3222 case '{':
3223 if (set_volatile++ == 0)
3224 fprintf (file, "%s.set\tvolatile\n\t", (TARGET_MIPS_AS) ? "" : "#");
3225 break;
3226
3227 case '}':
3228 if (set_volatile == 0)
3229 error ("internal error: %%} found without a %%{ in assembler pattern");
3230
3231 else if (--set_volatile == 0)
3232 fprintf (file, "\n\t%s.set\tnovolatile", (TARGET_MIPS_AS) ? "" : "#");
3233
3234 break;
3235 }
3236 return;
3237 }
3238
3239 if (! op)
3240 {
3241 error ("PRINT_OPERAND null pointer");
3242 return;
3243 }
3244
3245 code = GET_CODE (op);
3246 if (letter == 'C')
3247 switch (code)
3248 {
3249 case EQ: fputs ("eq", file); break;
3250 case NE: fputs ("ne", file); break;
3251 case GT: fputs ("gt", file); break;
3252 case GE: fputs ("ge", file); break;
3253 case LT: fputs ("lt", file); break;
3254 case LE: fputs ("le", file); break;
3255 case GTU: fputs ("gtu", file); break;
3256 case GEU: fputs ("geu", file); break;
3257 case LTU: fputs ("ltu", file); break;
3258 case LEU: fputs ("leu", file); break;
3259
3260 default:
3261 abort_with_insn (op, "PRINT_OPERAND, illegal insn for %%C");
3262 }
3263
3264 else if (letter == 'N')
3265 switch (code)
3266 {
3267 case EQ: fputs ("ne", file); break;
3268 case NE: fputs ("eq", file); break;
3269 case GT: fputs ("le", file); break;
3270 case GE: fputs ("lt", file); break;
3271 case LT: fputs ("ge", file); break;
3272 case LE: fputs ("gt", file); break;
3273 case GTU: fputs ("leu", file); break;
3274 case GEU: fputs ("ltu", file); break;
3275 case LTU: fputs ("geu", file); break;
3276 case LEU: fputs ("gtu", file); break;
3277
3278 default:
3279 abort_with_insn (op, "PRINT_OPERAND, illegal insn for %%N");
3280 }
3281
3282 else if (code == REG)
3283 {
3284 register int regnum = REGNO (op);
3285
3286 if (letter == 'M')
3287 regnum += MOST_SIGNIFICANT_WORD;
3288
3289 else if (letter == 'L')
3290 regnum += LEAST_SIGNIFICANT_WORD;
3291
3292 else if (letter == 'D')
3293 regnum++;
3294
3295 fprintf (file, "%s", reg_names[regnum]);
3296 }
3297
3298 else if (code == MEM)
3299 output_address (XEXP (op, 0));
3300
3301 else if (code == CONST_DOUBLE)
3302 {
3303 #if HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
3304 union { double d; int i[2]; } u;
3305 u.i[0] = CONST_DOUBLE_LOW (op);
3306 u.i[1] = CONST_DOUBLE_HIGH (op);
3307 if (GET_MODE (op) == SFmode)
3308 {
3309 float f;
3310 f = u.d;
3311 u.d = f;
3312 }
3313 fprintf (file, "%.20e", u.d);
3314 #else
3315 fatal ("CONST_DOUBLE found in cross compilation");
3316 #endif
3317 }
3318
3319 else if ((letter == 'x') && (GET_CODE(op) == CONST_INT))
3320 fprintf (file, "0x%04x", 0xffff & (INTVAL(op)));
3321
3322 else if ((letter == 'X') && (GET_CODE(op) == CONST_INT))
3323 fprintf (file, "0x%08x", INTVAL(op));
3324
3325 else if ((letter == 'd') && (GET_CODE(op) == CONST_INT))
3326 fprintf (file, "%d", (INTVAL(op)));
3327
3328 else if (letter == 'z'
3329 && (GET_CODE (op) == CONST_INT)
3330 && INTVAL (op) == 0)
3331 fputs (reg_names[GP_REG_FIRST], file);
3332
3333 else if (letter == 'd' || letter == 'x' || letter == 'X')
3334 fatal ("PRINT_OPERAND: letter %c was found & insn was not CONST_INT", letter);
3335
3336 else
3337 output_addr_const (file, op);
3338 }
3339
3340 \f
3341 /* A C compound statement to output to stdio stream STREAM the
3342 assembler syntax for an instruction operand that is a memory
3343 reference whose address is ADDR. ADDR is an RTL expression.
3344
3345 On some machines, the syntax for a symbolic address depends on
3346 the section that the address refers to. On these machines,
3347 define the macro `ENCODE_SECTION_INFO' to store the information
3348 into the `symbol_ref', and then check for it here. */
3349
3350 void
3351 print_operand_address (file, addr)
3352 FILE *file;
3353 rtx addr;
3354 {
3355 if (!addr)
3356 error ("PRINT_OPERAND_ADDRESS, null pointer");
3357
3358 else
3359 switch (GET_CODE (addr))
3360 {
3361 default:
3362 abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, illegal insn #1");
3363 break;
3364
3365 case REG:
3366 if (REGNO (addr) == ARG_POINTER_REGNUM)
3367 abort_with_insn (addr, "Arg pointer not eliminated.");
3368
3369 fprintf (file, "0(%s)", reg_names [REGNO (addr)]);
3370 break;
3371
3372 case PLUS:
3373 {
3374 register rtx reg = (rtx)0;
3375 register rtx offset = (rtx)0;
3376 register rtx arg0 = XEXP (addr, 0);
3377 register rtx arg1 = XEXP (addr, 1);
3378
3379 if (GET_CODE (arg0) == REG)
3380 {
3381 reg = arg0;
3382 offset = arg1;
3383 if (GET_CODE (offset) == REG)
3384 abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, 2 regs");
3385 }
3386 else if (GET_CODE (arg1) == REG)
3387 {
3388 reg = arg1;
3389 offset = arg0;
3390 }
3391 else if (CONSTANT_P (arg0) && CONSTANT_P (arg1))
3392 {
3393 output_addr_const (file, addr);
3394 break;
3395 }
3396 else
3397 abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, no regs");
3398
3399 if (!CONSTANT_P (offset))
3400 abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, illegal insn #2");
3401
3402 if (REGNO (reg) == ARG_POINTER_REGNUM)
3403 abort_with_insn (addr, "Arg pointer not eliminated.");
3404
3405 output_addr_const (file, offset);
3406 fprintf (file, "(%s)", reg_names [REGNO (reg)]);
3407 }
3408 break;
3409
3410 case LABEL_REF:
3411 case SYMBOL_REF:
3412 case CONST_INT:
3413 case CONST:
3414 output_addr_const (file, addr);
3415 break;
3416 }
3417 }
3418
3419 \f
3420 /* If optimizing for the global pointer, keep track of all of
3421 the externs, so that at the end of the file, we can emit
3422 the appropriate .extern declaration for them, before writing
3423 out the text section. We assume that all names passed to
3424 us are in the permanent obstack, so that they will be valid
3425 at the end of the compilation.
3426
3427 If we have -G 0, or the extern size is unknown, don't bother
3428 emitting the .externs. */
3429
3430 int
3431 mips_output_external (file, decl, name)
3432 FILE *file;
3433 tree decl;
3434 char *name;
3435 {
3436 register struct extern_list *p;
3437 int len;
3438
3439 if (TARGET_GP_OPT
3440 && mips_section_threshold != 0
3441 && ((TREE_CODE (decl)) != FUNCTION_DECL)
3442 && ((len = int_size_in_bytes (TREE_TYPE (decl))) > 0))
3443 {
3444 p = (struct extern_list *)permalloc ((long) sizeof (struct extern_list));
3445 p->next = extern_head;
3446 p->name = name;
3447 p->size = len;
3448 extern_head = p;
3449 }
3450 return 0;
3451 }
3452
3453 \f
3454 /* Compute a string to use as a temporary file name. */
3455
3456 static FILE *
3457 make_temp_file ()
3458 {
3459 FILE *stream;
3460 char *base = getenv ("TMPDIR");
3461 int len;
3462
3463 if (base == (char *)0)
3464 {
3465 #ifdef P_tmpdir
3466 if (access (P_tmpdir, R_OK | W_OK) == 0)
3467 base = P_tmpdir;
3468 else
3469 #endif
3470 if (access ("/usr/tmp", R_OK | W_OK) == 0)
3471 base = "/usr/tmp/";
3472 else
3473 base = "/tmp/";
3474 }
3475
3476 len = strlen (base);
3477 temp_filename = (char *) alloca (len + sizeof("/ccXXXXXX"));
3478 strcpy (temp_filename, base);
3479 if (len > 0 && temp_filename[len-1] != '/')
3480 temp_filename[len++] = '/';
3481
3482 strcpy (temp_filename + len, "ccXXXXXX");
3483 mktemp (temp_filename);
3484
3485 stream = fopen (temp_filename, "w+");
3486 if (!stream)
3487 pfatal_with_name (temp_filename);
3488
3489 unlink (temp_filename);
3490 return stream;
3491 }
3492
3493 \f
3494 /* Emit a new filename to a stream. If this is MIPS ECOFF, watch out
3495 for .file's that start within a function. If we are smuggling stabs, try to
3496 put out a MIPS ECOFF file and a stab. */
3497
3498 void
3499 mips_output_filename (stream, name)
3500 FILE *stream;
3501 char *name;
3502 {
3503 static int first_time = TRUE;
3504 char ltext_label_name[100];
3505
3506 if (first_time)
3507 {
3508 first_time = FALSE;
3509 SET_FILE_NUMBER ();
3510 current_function_file = name;
3511 fprintf (stream, "\t.file\t%d ", num_source_filenames);
3512 output_quoted_string (stream, name);
3513 fprintf (stream, "\n");
3514 if (!TARGET_GAS && write_symbols == DBX_DEBUG)
3515 fprintf (stream, "\t#@stabs\n");
3516 }
3517
3518 else if (!TARGET_GAS && write_symbols == DBX_DEBUG)
3519 {
3520 ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", 0);
3521 fprintf (stream, "%s ", ASM_STABS_OP);
3522 output_quoted_string (stream, name);
3523 fprintf (stream, ",%d,0,0,%s\n", N_SOL, &ltext_label_name[1]);
3524 }
3525
3526 else if (name != current_function_file
3527 && strcmp (name, current_function_file) != 0)
3528 {
3529 if (inside_function && !TARGET_GAS)
3530 {
3531 if (!file_in_function_warning)
3532 {
3533 file_in_function_warning = TRUE;
3534 ignore_line_number = TRUE;
3535 warning ("MIPS ECOFF format does not allow changing filenames within functions with #line");
3536 }
3537
3538 fprintf (stream, "\t#.file\t%d ", num_source_filenames);
3539 }
3540
3541 else
3542 {
3543 SET_FILE_NUMBER ();
3544 current_function_file = name;
3545 fprintf (stream, "\t.file\t%d ", num_source_filenames);
3546 }
3547 output_quoted_string (stream, name);
3548 fprintf (stream, "\n");
3549 }
3550 }
3551
3552 \f
3553 /* Emit a linenumber. For encapsulated stabs, we need to put out a stab
3554 as well as a .loc, since it is possible that MIPS ECOFF might not be
3555 able to represent the location for inlines that come from a different
3556 file. */
3557
3558 void
3559 mips_output_lineno (stream, line)
3560 FILE *stream;
3561 int line;
3562 {
3563 if (!TARGET_GAS && write_symbols == DBX_DEBUG)
3564 {
3565 ++sym_lineno;
3566 fprintf (stream, "$LM%d:\n\t%s %d,0,%d,$LM%d\n",
3567 sym_lineno, ASM_STABN_OP, N_SLINE, line, sym_lineno);
3568 }
3569
3570 else
3571 {
3572 fprintf (stream, "\n\t%s.loc\t%d %d\n",
3573 (ignore_line_number) ? "#" : "",
3574 num_source_filenames, line);
3575
3576 LABEL_AFTER_LOC (stream);
3577 }
3578 }
3579
3580 \f
3581 /* If defined, a C statement to be executed just prior to the
3582 output of assembler code for INSN, to modify the extracted
3583 operands so they will be output differently.
3584
3585 Here the argument OPVEC is the vector containing the operands
3586 extracted from INSN, and NOPERANDS is the number of elements of
3587 the vector which contain meaningful data for this insn. The
3588 contents of this vector are what will be used to convert the
3589 insn template into assembler code, so you can change the
3590 assembler output by changing the contents of the vector.
3591
3592 We use it to check if the current insn needs a nop in front of it
3593 because of load delays, and also to update the delay slot
3594 statistics. */
3595
3596 void
3597 final_prescan_insn (insn, opvec, noperands)
3598 rtx insn;
3599 rtx opvec[];
3600 int noperands;
3601 {
3602 if (dslots_number_nops > 0)
3603 {
3604 rtx pattern = PATTERN (insn);
3605 int length = get_attr_length (insn);
3606
3607 /* Do we need to emit a NOP? */
3608 if (length == 0
3609 || (mips_load_reg != (rtx)0 && reg_mentioned_p (mips_load_reg, pattern))
3610 || (mips_load_reg2 != (rtx)0 && reg_mentioned_p (mips_load_reg2, pattern))
3611 || (mips_load_reg3 != (rtx)0 && reg_mentioned_p (mips_load_reg3, pattern))
3612 || (mips_load_reg4 != (rtx)0 && reg_mentioned_p (mips_load_reg4, pattern)))
3613 fputs ((set_noreorder) ? "\tnop\n" : "\t#nop\n", asm_out_file);
3614
3615 else
3616 dslots_load_filled++;
3617
3618 while (--dslots_number_nops > 0)
3619 fputs ((set_noreorder) ? "\tnop\n" : "\t#nop\n", asm_out_file);
3620
3621 mips_load_reg = (rtx)0;
3622 mips_load_reg2 = (rtx)0;
3623 mips_load_reg3 = (rtx)0;
3624 mips_load_reg4 = (rtx)0;
3625
3626 if (set_noreorder && --set_noreorder == 0)
3627 fputs ("\t.set\treorder\n", asm_out_file);
3628 }
3629
3630 if (TARGET_STATS)
3631 {
3632 enum rtx_code code = GET_CODE (insn);
3633 if (code == JUMP_INSN || code == CALL_INSN)
3634 dslots_jump_total++;
3635 }
3636 }
3637
3638 \f
3639 /* Output at beginning of assembler file.
3640 If we are optimizing to use the global pointer, create a temporary
3641 file to hold all of the text stuff, and write it out to the end.
3642 This is needed because the MIPS assembler is evidently one pass,
3643 and if it hasn't seen the relevant .comm/.lcomm/.extern/.sdata
3644 declaration when the code is processed, it generates a two
3645 instruction sequence. */
3646
3647 void
3648 mips_asm_file_start (stream)
3649 FILE *stream;
3650 {
3651 ASM_OUTPUT_SOURCE_FILENAME (stream, main_input_filename);
3652
3653 /* Versions of the MIPS assembler before 2.20 generate errors
3654 if a branch inside of a .set noreorder section jumps to a
3655 label outside of the .set noreorder section. Revision 2.20
3656 just set nobopt silently rather than fixing the bug. */
3657
3658 if (TARGET_MIPS_AS && optimize && flag_delayed_branch)
3659 fprintf (stream, "\t.set\tnobopt\n");
3660
3661 /* Generate the pseudo ops that the Pyramid based System V.4 wants. */
3662 #ifndef ABICALLS_ASM_OP
3663 #define ABICALLS_ASM_OP ".abicalls"
3664 #endif
3665 if (TARGET_ABICALLS)
3666 fprintf (stream, "\t%s\n", ABICALLS_ASM_OP);
3667
3668 if (TARGET_GP_OPT)
3669 {
3670 asm_out_data_file = stream;
3671 asm_out_text_file = make_temp_file ();
3672 }
3673 else
3674 asm_out_data_file = asm_out_text_file = stream;
3675
3676 if (TARGET_NAME_REGS)
3677 fprintf (asm_out_file, "#include <regdef.h>\n");
3678
3679 print_options (stream);
3680 }
3681
3682 \f
3683 /* If we are optimizing the global pointer, emit the text section now
3684 and any small externs which did not have .comm, etc that are
3685 needed. Also, give a warning if the data area is more than 32K and
3686 -pic because 3 instructions are needed to reference the data
3687 pointers. */
3688
3689 void
3690 mips_asm_file_end (file)
3691 FILE *file;
3692 {
3693 char buffer[8192];
3694 tree name_tree;
3695 struct extern_list *p;
3696 int len;
3697
3698 if (HALF_PIC_P ())
3699 HALF_PIC_FINISH (file);
3700
3701 if (TARGET_GP_OPT)
3702 {
3703 if (extern_head)
3704 fputs ("\n", file);
3705
3706 for (p = extern_head; p != 0; p = p->next)
3707 {
3708 name_tree = get_identifier (p->name);
3709
3710 /* Positively ensure only one .extern for any given symbol. */
3711 if (! TREE_ASM_WRITTEN (name_tree))
3712 {
3713 TREE_ASM_WRITTEN (name_tree) = 1;
3714 fputs ("\t.extern\t", file);
3715 assemble_name (file, p->name);
3716 fprintf (file, ", %d\n", p->size);
3717 }
3718 }
3719
3720 fprintf (file, "\n\t.text\n");
3721 rewind (asm_out_text_file);
3722 if (ferror (asm_out_text_file))
3723 fatal_io_error (temp_filename);
3724
3725 while ((len = fread (buffer, 1, sizeof (buffer), asm_out_text_file)) > 0)
3726 if (fwrite (buffer, 1, len, file) != len)
3727 pfatal_with_name (asm_file_name);
3728
3729 if (len < 0)
3730 pfatal_with_name (temp_filename);
3731
3732 if (fclose (asm_out_text_file) != 0)
3733 pfatal_with_name (temp_filename);
3734 }
3735 }
3736
3737 \f
3738 /* Emit either a label, .comm, or .lcomm directive, and mark
3739 that the symbol is used, so that we don't emit an .extern
3740 for it in mips_asm_file_end. */
3741
3742 void
3743 mips_declare_object (stream, name, init_string, final_string, size)
3744 FILE *stream;
3745 char *name;
3746 char *init_string;
3747 char *final_string;
3748 int size;
3749 {
3750 fputs (init_string, stream); /* "", "\t.comm\t", or "\t.lcomm\t" */
3751 assemble_name (stream, name);
3752 fprintf (stream, final_string, size); /* ":\n", ",%u\n", ",%u\n" */
3753
3754 if (TARGET_GP_OPT && mips_section_threshold != 0)
3755 {
3756 tree name_tree = get_identifier (name);
3757 TREE_ASM_WRITTEN (name_tree) = 1;
3758 }
3759 }
3760
3761 \f
3762 /* Output a double precision value to the assembler. If both the
3763 host and target are IEEE, emit the values in hex. */
3764
3765 void
3766 mips_output_double (stream, value)
3767 FILE *stream;
3768 REAL_VALUE_TYPE value;
3769 {
3770 #ifdef REAL_VALUE_TO_TARGET_DOUBLE
3771 long value_long[2];
3772 REAL_VALUE_TO_TARGET_DOUBLE (value, value_long);
3773
3774 fprintf (stream, "\t.word\t0x%08lx\t\t# %.20g\n\t.word\t0x%08lx\n",
3775 value_long[0], value, value_long[1]);
3776 #else
3777 fprintf (stream, "\t.double\t%.20g\n", value);
3778 #endif
3779 }
3780
3781
3782 /* Output a single precision value to the assembler. If both the
3783 host and target are IEEE, emit the values in hex. */
3784
3785 void
3786 mips_output_float (stream, value)
3787 FILE *stream;
3788 REAL_VALUE_TYPE value;
3789 {
3790 #ifdef REAL_VALUE_TO_TARGET_SINGLE
3791 long value_long;
3792 REAL_VALUE_TO_TARGET_SINGLE (value, value_long);
3793
3794 fprintf (stream, "\t.word\t0x%08lx\t\t# %.12g (float)\n", value_long, value);
3795 #else
3796 fprintf (stream, "\t.float\t%.12g\n", value);
3797 #endif
3798 }
3799
3800 \f
3801 /* Return TRUE if any register used in the epilogue is used. This to insure
3802 any insn put into the epilogue delay slots is safe. */
3803
3804 int
3805 epilogue_reg_mentioned_p (insn)
3806 rtx insn;
3807 {
3808 register char *fmt;
3809 register int i;
3810 register enum rtx_code code;
3811 register int regno;
3812
3813 if (insn == (rtx)0)
3814 return 0;
3815
3816 if (GET_CODE (insn) == LABEL_REF)
3817 return 0;
3818
3819 code = GET_CODE (insn);
3820 switch (code)
3821 {
3822 case REG:
3823 regno = REGNO (insn);
3824 if (regno == STACK_POINTER_REGNUM)
3825 return 1;
3826
3827 if (regno == FRAME_POINTER_REGNUM && frame_pointer_needed)
3828 return 1;
3829
3830 if (!call_used_regs[regno])
3831 return 1;
3832
3833 if (regno != MIPS_TEMP1_REGNUM && regno != MIPS_TEMP2_REGNUM)
3834 return 0;
3835
3836 if (!current_frame_info.initialized)
3837 compute_frame_size (get_frame_size ());
3838
3839 return (current_frame_info.total_size >= 32768);
3840
3841 case SCRATCH:
3842 case CC0:
3843 case PC:
3844 case CONST_INT:
3845 case CONST_DOUBLE:
3846 return 0;
3847 }
3848
3849 fmt = GET_RTX_FORMAT (code);
3850 for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
3851 {
3852 if (fmt[i] == 'E')
3853 {
3854 register int j;
3855 for (j = XVECLEN (insn, i) - 1; j >= 0; j--)
3856 if (epilogue_reg_mentioned_p (XVECEXP (insn, i, j)))
3857 return 1;
3858 }
3859 else if (fmt[i] == 'e' && epilogue_reg_mentioned_p (XEXP (insn, i)))
3860 return 1;
3861 }
3862
3863 return 0;
3864 }
3865
3866 \f
3867 /* Return the bytes needed to compute the frame pointer from the current
3868 stack pointer.
3869
3870 Mips stack frames look like:
3871
3872 Before call After call
3873 +-----------------------+ +-----------------------+
3874 high | | | |
3875 mem. | | | |
3876 | caller's temps. | | caller's temps. |
3877 | | | |
3878 +-----------------------+ +-----------------------+
3879 | | | |
3880 | arguments on stack. | | arguments on stack. |
3881 | | | |
3882 +-----------------------+ +-----------------------+
3883 | 4 words to save | | 4 words to save |
3884 | arguments passed | | arguments passed |
3885 | in registers, even | | in registers, even |
3886 SP->| if not passed. | FP->| if not passed. |
3887 +-----------------------+ +-----------------------+
3888 | |
3889 | GP save for V.4 abi |
3890 | |
3891 +-----------------------+
3892 | |
3893 | fp register save |
3894 | |
3895 +-----------------------+
3896 | |
3897 | gp register save |
3898 | |
3899 +-----------------------+
3900 | |
3901 | local variables |
3902 | |
3903 +-----------------------+
3904 | |
3905 | alloca allocations |
3906 | |
3907 +-----------------------+
3908 | |
3909 | arguments on stack |
3910 | |
3911 +-----------------------+
3912 | 4 words to save |
3913 | arguments passed |
3914 | in registers, even |
3915 low SP->| if not passed. |
3916 memory +-----------------------+
3917
3918 */
3919
3920 long
3921 compute_frame_size (size)
3922 int size; /* # of var. bytes allocated */
3923 {
3924 int regno;
3925 long total_size; /* # bytes that the entire frame takes up */
3926 long var_size; /* # bytes that variables take up */
3927 long args_size; /* # bytes that outgoing arguments take up */
3928 long extra_size; /* # extra bytes */
3929 long gp_reg_rounded; /* # bytes needed to store gp after rounding */
3930 long gp_reg_size; /* # bytes needed to store gp regs */
3931 long fp_reg_size; /* # bytes needed to store fp regs */
3932 long mask; /* mask of saved gp registers */
3933 long fmask; /* mask of saved fp registers */
3934 int fp_inc; /* 1 or 2 depending on the size of fp regs */
3935 long fp_bits; /* bitmask to use for each fp register */
3936
3937 gp_reg_size = 0;
3938 fp_reg_size = 0;
3939 mask = 0;
3940 fmask = 0;
3941 extra_size = MIPS_STACK_ALIGN (((TARGET_ABICALLS) ? UNITS_PER_WORD : 0));
3942 var_size = MIPS_STACK_ALIGN (size);
3943 args_size = MIPS_STACK_ALIGN (current_function_outgoing_args_size);
3944
3945 /* The MIPS 3.0 linker does not like functions that dynamically
3946 allocate the stack and have 0 for STACK_DYNAMIC_OFFSET, since it
3947 looks like we are trying to create a second frame pointer to the
3948 function, so allocate some stack space to make it happy. */
3949
3950 if (args_size == 0 && current_function_calls_alloca)
3951 args_size = 4*UNITS_PER_WORD;
3952
3953 total_size = var_size + args_size + extra_size;
3954
3955 /* Calculate space needed for gp registers. */
3956 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
3957 {
3958 if (MUST_SAVE_REGISTER (regno))
3959 {
3960 gp_reg_size += UNITS_PER_WORD;
3961 mask |= 1L << (regno - GP_REG_FIRST);
3962 }
3963 }
3964
3965 /* Calculate space needed for fp registers. */
3966 if (TARGET_FLOAT64)
3967 {
3968 fp_inc = 1;
3969 fp_bits = 1;
3970 }
3971 else
3972 {
3973 fp_inc = 2;
3974 fp_bits = 3;
3975 }
3976
3977 for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno += fp_inc)
3978 {
3979 if (regs_ever_live[regno] && !call_used_regs[regno])
3980 {
3981 fp_reg_size += 2*UNITS_PER_WORD;
3982 fmask |= fp_bits << (regno - FP_REG_FIRST);
3983 }
3984 }
3985
3986 gp_reg_rounded = MIPS_STACK_ALIGN (gp_reg_size);
3987 total_size += gp_reg_rounded + fp_reg_size;
3988
3989 if (total_size == extra_size)
3990 total_size = extra_size = 0;
3991
3992 /* Save other computed information. */
3993 current_frame_info.total_size = total_size;
3994 current_frame_info.var_size = var_size;
3995 current_frame_info.args_size = args_size;
3996 current_frame_info.extra_size = extra_size;
3997 current_frame_info.gp_reg_size = gp_reg_size;
3998 current_frame_info.fp_reg_size = fp_reg_size;
3999 current_frame_info.mask = mask;
4000 current_frame_info.fmask = fmask;
4001 current_frame_info.initialized = reload_completed;
4002 current_frame_info.num_gp = gp_reg_size / UNITS_PER_WORD;
4003 current_frame_info.num_fp = fp_reg_size / (2*UNITS_PER_WORD);
4004
4005 if (mask)
4006 {
4007 unsigned long offset = args_size + var_size + gp_reg_size - UNITS_PER_WORD;
4008 current_frame_info.gp_sp_offset = offset;
4009 current_frame_info.gp_save_offset = offset - total_size;
4010 }
4011 else
4012 {
4013 current_frame_info.gp_sp_offset = 0;
4014 current_frame_info.gp_save_offset = 0;
4015 }
4016
4017
4018 if (fmask)
4019 {
4020 unsigned long offset = args_size + var_size + gp_reg_rounded + fp_reg_size - 2*UNITS_PER_WORD;
4021 current_frame_info.fp_sp_offset = offset;
4022 current_frame_info.fp_save_offset = offset - total_size + UNITS_PER_WORD;
4023 }
4024 else
4025 {
4026 current_frame_info.fp_sp_offset = 0;
4027 current_frame_info.fp_save_offset = 0;
4028 }
4029
4030 /* Ok, we're done. */
4031 return total_size;
4032 }
4033
4034 \f
4035 /* Common code to emit the insns (or to write the instructions to a file)
4036 to save/restore registers.
4037
4038 Other parts of the code assume that MIPS_TEMP1_REGNUM (aka large_reg)
4039 is not modified within save_restore_insns. */
4040
4041 #define BITSET_P(value,bit) (((value) & (1L << (bit))) != 0)
4042
4043 static void
4044 save_restore_insns (store_p, large_reg, large_offset, file)
4045 int store_p; /* true if this is prologue */
4046 rtx large_reg; /* register holding large offset constant or NULL */
4047 long large_offset; /* large constant offset value */
4048 FILE *file; /* file to write instructions to instead of making RTL */
4049 {
4050 long mask = current_frame_info.mask;
4051 long fmask = current_frame_info.fmask;
4052 int regno;
4053 rtx base_reg_rtx;
4054 long base_offset;
4055 long gp_offset;
4056 long fp_offset;
4057 long end_offset;
4058
4059 if (frame_pointer_needed && !BITSET_P (mask, FRAME_POINTER_REGNUM - GP_REG_FIRST))
4060 abort ();
4061
4062 if (mask == 0 && fmask == 0)
4063 return;
4064
4065 /* Save registers starting from high to low. The debuggers prefer
4066 at least the return register be stored at func+4, and also it
4067 allows us not to need a nop in the epilog if at least one
4068 register is reloaded in addition to return address. */
4069
4070 /* Save GP registers if needed. */
4071 if (mask)
4072 {
4073 /* Pick which pointer to use as a base register. For small
4074 frames, just use the stack pointer. Otherwise, use a
4075 temporary register. Save 2 cycles if the save area is near
4076 the end of a large frame, by reusing the constant created in
4077 the prologue/epilogue to adjust the stack frame. */
4078
4079 gp_offset = current_frame_info.gp_sp_offset;
4080 end_offset = gp_offset - (current_frame_info.gp_reg_size - UNITS_PER_WORD);
4081
4082 if (gp_offset < 0 || end_offset < 0)
4083 fatal ("gp_offset (%ld) or end_offset (%ld) is less than zero.",
4084 gp_offset, end_offset);
4085
4086 else if (gp_offset < 32768)
4087 {
4088 base_reg_rtx = stack_pointer_rtx;
4089 base_offset = 0;
4090 }
4091
4092 else if (large_reg != (rtx)0
4093 && (((unsigned long)(large_offset - gp_offset)) < 32768)
4094 && (((unsigned long)(large_offset - end_offset)) < 32768))
4095 {
4096 base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM);
4097 base_offset = large_offset;
4098 if (file == (FILE *)0)
4099 emit_insn (gen_addsi3 (base_reg_rtx, large_reg, stack_pointer_rtx));
4100 else
4101 fprintf (file, "\taddu\t%s,%s,%s\n",
4102 reg_names[MIPS_TEMP2_REGNUM],
4103 reg_names[REGNO (large_reg)],
4104 reg_names[STACK_POINTER_REGNUM]);
4105 }
4106
4107 else
4108 {
4109 base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM);
4110 base_offset = gp_offset;
4111 if (file == (FILE *)0)
4112 {
4113 emit_move_insn (base_reg_rtx, GEN_INT (gp_offset));
4114 emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx, stack_pointer_rtx));
4115 }
4116 else
4117 fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n\taddu\t%s,%s,%s\n",
4118 reg_names[MIPS_TEMP2_REGNUM],
4119 (long)base_offset,
4120 (long)base_offset,
4121 reg_names[MIPS_TEMP2_REGNUM],
4122 reg_names[MIPS_TEMP2_REGNUM],
4123 reg_names[STACK_POINTER_REGNUM]);
4124 }
4125
4126 for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
4127 {
4128 if (BITSET_P (mask, regno - GP_REG_FIRST))
4129 {
4130 if (file == (FILE *)0)
4131 {
4132 rtx reg_rtx = gen_rtx (REG, Pmode, regno);
4133 rtx mem_rtx = gen_rtx (MEM, Pmode,
4134 gen_rtx (PLUS, Pmode, base_reg_rtx,
4135 GEN_INT (gp_offset - base_offset)));
4136
4137 if (store_p)
4138 emit_move_insn (mem_rtx, reg_rtx);
4139 else
4140 emit_move_insn (reg_rtx, mem_rtx);
4141 }
4142 else
4143 fprintf (file, "\t%s\t%s,%ld(%s)\n",
4144 (store_p) ? "sw" : "lw",
4145 reg_names[regno],
4146 gp_offset - base_offset,
4147 reg_names[REGNO(base_reg_rtx)]);
4148
4149 gp_offset -= UNITS_PER_WORD;
4150 }
4151 }
4152 }
4153 else
4154 {
4155 base_reg_rtx = (rtx)0; /* Make sure these are initialzed */
4156 base_offset = 0;
4157 }
4158
4159 /* Save floating point registers if needed. */
4160 if (fmask)
4161 {
4162 int fp_inc = (TARGET_FLOAT64) ? 1 : 2;
4163
4164 /* Pick which pointer to use as a base register. */
4165 fp_offset = current_frame_info.fp_sp_offset;
4166 end_offset = fp_offset - (current_frame_info.fp_reg_size - 2*UNITS_PER_WORD);
4167
4168 if (fp_offset < 0 || end_offset < 0)
4169 fatal ("fp_offset (%ld) or end_offset (%ld) is less than zero.",
4170 fp_offset, end_offset);
4171
4172 else if (fp_offset < 32768)
4173 {
4174 base_reg_rtx = stack_pointer_rtx;
4175 base_offset = 0;
4176 }
4177
4178 else if (base_reg_rtx != (rtx)0
4179 && (((unsigned long)(base_offset - fp_offset)) < 32768)
4180 && (((unsigned long)(base_offset - end_offset)) < 32768))
4181 {
4182 ; /* already set up for gp registers above */
4183 }
4184
4185 else if (large_reg != (rtx)0
4186 && (((unsigned long)(large_offset - fp_offset)) < 32768)
4187 && (((unsigned long)(large_offset - end_offset)) < 32768))
4188 {
4189 base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM);
4190 base_offset = large_offset;
4191 if (file == (FILE *)0)
4192 emit_insn (gen_addsi3 (base_reg_rtx, large_reg, stack_pointer_rtx));
4193 else
4194 fprintf (file, "\taddu\t%s,%s,%s\n",
4195 reg_names[MIPS_TEMP2_REGNUM],
4196 reg_names[REGNO (large_reg)],
4197 reg_names[STACK_POINTER_REGNUM]);
4198 }
4199
4200 else
4201 {
4202 base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM);
4203 base_offset = fp_offset;
4204 if (file == (FILE *)0)
4205 {
4206 emit_move_insn (base_reg_rtx, GEN_INT (fp_offset));
4207 emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx, stack_pointer_rtx));
4208 }
4209 else
4210 fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n\taddu\t%s,%s,%s\n",
4211 reg_names[MIPS_TEMP2_REGNUM],
4212 (long)base_offset,
4213 (long)base_offset,
4214 reg_names[MIPS_TEMP2_REGNUM],
4215 reg_names[MIPS_TEMP2_REGNUM],
4216 reg_names[STACK_POINTER_REGNUM]);
4217 }
4218
4219 for (regno = FP_REG_LAST-1; regno >= FP_REG_FIRST; regno -= fp_inc)
4220 {
4221 if (BITSET_P (fmask, regno - FP_REG_FIRST))
4222 {
4223 if (file == (FILE *)0)
4224 {
4225 rtx reg_rtx = gen_rtx (REG, DFmode, regno);
4226 rtx mem_rtx = gen_rtx (MEM, DFmode,
4227 gen_rtx (PLUS, Pmode, base_reg_rtx,
4228 GEN_INT (fp_offset - base_offset)));
4229
4230 if (store_p)
4231 emit_move_insn (mem_rtx, reg_rtx);
4232 else
4233 emit_move_insn (reg_rtx, mem_rtx);
4234 }
4235 else
4236 fprintf (file, "\t%s\t%s,%ld(%s)\n",
4237 (store_p) ? "s.d" : "l.d",
4238 reg_names[regno],
4239 fp_offset - base_offset,
4240 reg_names[REGNO(base_reg_rtx)]);
4241
4242
4243 fp_offset -= 2*UNITS_PER_WORD;
4244 }
4245 }
4246 }
4247 }
4248
4249 \f
4250 /* Set up the stack and frame (if desired) for the function. */
4251
4252 void
4253 function_prologue (file, size)
4254 FILE *file;
4255 int size;
4256 {
4257 long tsize = current_frame_info.total_size;
4258
4259 ASM_OUTPUT_SOURCE_FILENAME (file, DECL_SOURCE_FILE (current_function_decl));
4260
4261 if (debug_info_level != DINFO_LEVEL_TERSE)
4262 ASM_OUTPUT_SOURCE_LINE (file, DECL_SOURCE_LINE (current_function_decl));
4263
4264 inside_function = 1;
4265 fputs ("\t.ent\t", file);
4266 assemble_name (file, current_function_name);
4267 fputs ("\n", file);
4268
4269 assemble_name (file, current_function_name);
4270 fputs (":\n", file);
4271
4272 if (TARGET_ABICALLS)
4273 fprintf (file,
4274 "\t.set\tnoreorder\n\t.cpload\t%s\n\t.set\treorder\n",
4275 reg_names[ GP_REG_FIRST + 25 ]);
4276
4277 tsize = current_frame_info.total_size;
4278 if (tsize > 0 && TARGET_ABICALLS)
4279 fprintf (file, "\t.cprestore %d\n", tsize + STARTING_FRAME_OFFSET);
4280
4281 fprintf (file, "\t.frame\t%s,%d,%s\t\t# vars= %d, regs= %d/%d, args = %d, extra= %d\n",
4282 reg_names[ (frame_pointer_needed) ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM ],
4283 tsize,
4284 reg_names[31 + GP_REG_FIRST],
4285 current_frame_info.var_size,
4286 current_frame_info.num_gp,
4287 current_frame_info.num_fp,
4288 current_function_outgoing_args_size,
4289 current_frame_info.extra_size);
4290
4291 fprintf (file, "\t.mask\t0x%08lx,%d\n\t.fmask\t0x%08lx,%d\n",
4292 current_frame_info.mask,
4293 current_frame_info.gp_save_offset,
4294 current_frame_info.fmask,
4295 current_frame_info.fp_save_offset);
4296 }
4297
4298 \f
4299 /* Expand the prologue into a bunch of separate insns. */
4300
4301 void
4302 mips_expand_prologue ()
4303 {
4304 int regno;
4305 long tsize;
4306 rtx tmp_rtx = (rtx)0;
4307 char *arg_name = (char *)0;
4308 tree fndecl = current_function_decl;
4309 tree fntype = TREE_TYPE (fndecl);
4310 tree fnargs = (TREE_CODE (fntype) != METHOD_TYPE)
4311 ? DECL_ARGUMENTS (fndecl)
4312 : 0;
4313 rtx next_arg_reg;
4314 int i;
4315 tree next_arg;
4316 tree cur_arg;
4317 CUMULATIVE_ARGS args_so_far;
4318
4319 /* If struct value address is treated as the first argument, make it so. */
4320 if (aggregate_value_p (DECL_RESULT (fndecl))
4321 && ! current_function_returns_pcc_struct
4322 && struct_value_incoming_rtx == 0)
4323 {
4324 tree type = build_pointer_type (fntype);
4325 tree function_result_decl = build_decl (PARM_DECL, NULL_TREE, type);
4326 DECL_ARG_TYPE (function_result_decl) = type;
4327 TREE_CHAIN (function_result_decl) = fnargs;
4328 fnargs = function_result_decl;
4329 }
4330
4331 /* Determine the last argument, and get its name. */
4332
4333 INIT_CUMULATIVE_ARGS (args_so_far, fntype, (rtx)0);
4334 regno = GP_ARG_FIRST;
4335
4336 for (cur_arg = fnargs; cur_arg != (tree)0; cur_arg = next_arg)
4337 {
4338 tree type = DECL_ARG_TYPE (cur_arg);
4339 enum machine_mode passed_mode = TYPE_MODE (type);
4340 rtx entry_parm = FUNCTION_ARG (args_so_far,
4341 passed_mode,
4342 DECL_ARG_TYPE (cur_arg),
4343 1);
4344
4345 if (entry_parm)
4346 {
4347 int words;
4348
4349 /* passed in a register, so will get homed automatically */
4350 if (GET_MODE (entry_parm) == BLKmode)
4351 words = (int_size_in_bytes (type) + 3) / 4;
4352 else
4353 words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;
4354
4355 regno = REGNO (entry_parm) + words - 1;
4356 }
4357 else
4358 {
4359 regno = GP_ARG_LAST+1;
4360 break;
4361 }
4362
4363 FUNCTION_ARG_ADVANCE (args_so_far,
4364 passed_mode,
4365 DECL_ARG_TYPE (cur_arg),
4366 1);
4367
4368 next_arg = TREE_CHAIN (cur_arg);
4369 if (next_arg == (tree)0)
4370 {
4371 if (DECL_NAME (cur_arg))
4372 arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg));
4373
4374 break;
4375 }
4376 }
4377
4378 /* In order to pass small structures by value in registers
4379 compatibly with the MIPS compiler, we need to shift the value
4380 into the high part of the register. Function_arg has encoded a
4381 PARALLEL rtx, holding a vector of adjustments to be made as the
4382 next_arg_reg variable, so we split up the insns, and emit them
4383 separately. */
4384
4385 next_arg_reg = FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1);
4386 if (next_arg_reg != (rtx)0 && GET_CODE (next_arg_reg) == PARALLEL)
4387 {
4388 rtvec adjust = XVEC (next_arg_reg, 0);
4389 int num = GET_NUM_ELEM (adjust);
4390
4391 for (i = 0; i < num; i++)
4392 {
4393 rtx pattern = RTVEC_ELT (adjust, i);
4394 if (GET_CODE (pattern) != SET
4395 || GET_CODE (SET_SRC (pattern)) != ASHIFT)
4396 abort_with_insn (pattern, "Insn is not a shift");
4397
4398 PUT_CODE (SET_SRC (pattern), ASHIFTRT);
4399 emit_insn (pattern);
4400 }
4401 }
4402
4403 /* If this function is a varargs function, store any registers that
4404 would normally hold arguments ($4 - $7) on the stack. */
4405 if ((TYPE_ARG_TYPES (fntype) != 0
4406 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node))
4407 || (arg_name != (char *)0
4408 && ((arg_name[0] == '_' && strcmp (arg_name, "__builtin_va_alist") == 0)
4409 || (arg_name[0] == 'v' && strcmp (arg_name, "va_alist") == 0))))
4410 {
4411 for (; regno <= GP_ARG_LAST; regno++)
4412 {
4413 rtx ptr = stack_pointer_rtx;
4414 if (regno != GP_ARG_FIRST)
4415 ptr = gen_rtx (PLUS, Pmode, ptr,
4416 GEN_INT ((regno - GP_ARG_FIRST) * UNITS_PER_WORD));
4417
4418 emit_move_insn (gen_rtx (MEM, Pmode, ptr), gen_rtx (REG, Pmode, regno));
4419 }
4420 }
4421
4422 tsize = compute_frame_size (get_frame_size ());
4423 if (tsize > 0)
4424 {
4425 rtx tsize_rtx = GEN_INT (tsize);
4426
4427 if (tsize > 32767)
4428 {
4429 tmp_rtx = gen_rtx (REG, SImode, MIPS_TEMP1_REGNUM);
4430 emit_move_insn (tmp_rtx, tsize_rtx);
4431 tsize_rtx = tmp_rtx;
4432 }
4433
4434 emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, tsize_rtx));
4435
4436 save_restore_insns (TRUE, tmp_rtx, tsize, (FILE *)0);
4437
4438 if (frame_pointer_needed)
4439 emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx));
4440 }
4441
4442 /* If we are profiling, make sure no instructions are scheduled before
4443 the call to mcount. */
4444
4445 if (profile_flag || profile_block_flag)
4446 emit_insn (gen_blockage ());
4447 }
4448
4449 \f
4450 /* Do any necessary cleanup after a function to restore stack, frame, and regs. */
4451
4452 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */
4453
4454 void
4455 function_epilogue (file, size)
4456 FILE *file;
4457 int size;
4458 {
4459 long tsize;
4460 char *sp_str = reg_names[STACK_POINTER_REGNUM];
4461 char *t1_str = reg_names[MIPS_TEMP1_REGNUM];
4462 rtx epilogue_delay = current_function_epilogue_delay_list;
4463 int noreorder = !TARGET_MIPS_AS || (epilogue_delay != 0);
4464 int noepilogue = FALSE;
4465 int load_nop = FALSE;
4466 int load_only_r31;
4467 rtx tmp_rtx = (rtx)0;
4468 rtx restore_rtx;
4469 int i;
4470
4471 /* The epilogue does not depend on any registers, but the stack
4472 registers, so we assume that if we have 1 pending nop, it can be
4473 ignored, and 2 it must be filled (2 nops occur for integer
4474 multiply and divide). */
4475
4476 if (dslots_number_nops > 0)
4477 {
4478 if (dslots_number_nops == 1)
4479 {
4480 dslots_number_nops = 0;
4481 dslots_load_filled++;
4482 }
4483 else
4484 {
4485 while (--dslots_number_nops > 0)
4486 fputs ((set_noreorder) ? "\tnop\n" : "\t#nop\n", asm_out_file);
4487 }
4488
4489 if (set_noreorder > 0 && --set_noreorder == 0)
4490 fputs ("\t.set\treorder\n", file);
4491 }
4492
4493 if (set_noat != 0)
4494 {
4495 set_noat = 0;
4496 fputs ("\t.set\tat\n", file);
4497 error ("internal gcc error: .set noat left on in epilogue");
4498 }
4499
4500 if (set_nomacro != 0)
4501 {
4502 set_nomacro = 0;
4503 fputs ("\t.set\tmacro\n", file);
4504 error ("internal gcc error: .set nomacro left on in epilogue");
4505 }
4506
4507 if (set_noreorder != 0)
4508 {
4509 set_noreorder = 0;
4510 fputs ("\t.set\treorder\n", file);
4511 error ("internal gcc error: .set noreorder left on in epilogue");
4512 }
4513
4514 if (set_volatile != 0)
4515 {
4516 set_volatile = 0;
4517 fprintf (file, "\t#.set\tnovolatile\n", (TARGET_MIPS_AS) ? "" : "#");
4518 error ("internal gcc error: .set volatile left on in epilogue");
4519 }
4520
4521 size = MIPS_STACK_ALIGN (size);
4522 tsize = (!current_frame_info.initialized)
4523 ? compute_frame_size (size)
4524 : current_frame_info.total_size;
4525
4526 if (tsize == 0 && epilogue_delay == 0)
4527 {
4528 rtx insn = get_last_insn ();
4529
4530 /* If the last insn was a BARRIER, we don't have to write any code
4531 because a jump (aka return) was put there. */
4532 if (GET_CODE (insn) == NOTE)
4533 insn = prev_nonnote_insn (insn);
4534 if (insn && GET_CODE (insn) == BARRIER)
4535 noepilogue = TRUE;
4536
4537 noreorder = FALSE;
4538 }
4539
4540 if (!noepilogue)
4541 {
4542 /* In the reload sequence, we don't need to fill the load delay
4543 slots for most of the loads, also see if we can fill the final
4544 delay slot if not otherwise filled by the reload sequence. */
4545
4546 if (noreorder)
4547 fprintf (file, "\t.set\tnoreorder\n");
4548
4549 if (tsize > 32767)
4550 {
4551 fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n", t1_str, (long)tsize, (long)tsize);
4552 tmp_rtx = gen_rtx (REG, Pmode, MIPS_TEMP1_REGNUM);
4553 }
4554
4555 if (frame_pointer_needed)
4556 fprintf (file, "\tmove\t%s,%s\t\t\t# sp not trusted here\n",
4557 sp_str, reg_names[FRAME_POINTER_REGNUM]);
4558
4559 save_restore_insns (FALSE, tmp_rtx, tsize, file);
4560
4561 load_only_r31 = (current_frame_info.mask == RA_MASK
4562 && current_frame_info.fmask == 0);
4563
4564 if (noreorder)
4565 {
4566 /* If the only register saved is the return address, we need a
4567 nop, unless we have an instruction to put into it. Otherwise
4568 we don't since reloading multiple registers doesn't reference
4569 the register being loaded. */
4570
4571 if (load_only_r31)
4572 {
4573 if (epilogue_delay)
4574 final_scan_insn (XEXP (epilogue_delay, 0),
4575 file,
4576 1, /* optimize */
4577 -2, /* prescan */
4578 1); /* nopeepholes */
4579 else
4580 {
4581 fprintf (file, "\tnop\n");
4582 load_nop = TRUE;
4583 }
4584 }
4585
4586 fprintf (file, "\tj\t%s\n", reg_names[GP_REG_FIRST + 31]);
4587
4588 if (tsize > 32767)
4589 fprintf (file, "\taddu\t%s,%s,%s\n", sp_str, sp_str, t1_str);
4590
4591 else if (tsize > 0)
4592 fprintf (file, "\taddu\t%s,%s,%d\n", sp_str, sp_str, tsize);
4593
4594 else if (!load_only_r31 && epilogue_delay != 0)
4595 final_scan_insn (XEXP (epilogue_delay, 0),
4596 file,
4597 1, /* optimize */
4598 -2, /* prescan */
4599 1); /* nopeepholes */
4600
4601 fprintf (file, "\t.set\treorder\n");
4602 }
4603
4604 else
4605 {
4606 if (tsize > 32767)
4607 fprintf (file, "\taddu\t%s,%s,%s\n", sp_str, sp_str, t1_str);
4608
4609 else if (tsize > 0)
4610 fprintf (file, "\taddu\t%s,%s,%d\n", sp_str, sp_str, tsize);
4611
4612 fprintf (file, "\tj\t%s\n", reg_names[GP_REG_FIRST + 31]);
4613 }
4614 }
4615
4616 fputs ("\t.end\t", file);
4617 assemble_name (file, current_function_name);
4618 fputs ("\n", file);
4619
4620 if (TARGET_STATS)
4621 {
4622 int num_gp_regs = current_frame_info.gp_reg_size / 4;
4623 int num_fp_regs = current_frame_info.fp_reg_size / 8;
4624 int num_regs = num_gp_regs + num_fp_regs;
4625 char *name = current_function_name;
4626
4627 if (name[0] == '*')
4628 name++;
4629
4630 dslots_load_total += num_regs;
4631
4632 if (!noepilogue)
4633 dslots_jump_total++;
4634
4635 if (noreorder)
4636 {
4637 dslots_load_filled += num_regs;
4638
4639 /* If the only register saved is the return register, we
4640 can't fill this register's delay slot. */
4641
4642 if (load_only_r31 && epilogue_delay == 0)
4643 dslots_load_filled--;
4644
4645 if (tsize > 0 || (!load_only_r31 && epilogue_delay != 0))
4646 dslots_jump_filled++;
4647 }
4648
4649 fprintf (stderr,
4650 "%-20s fp=%c leaf=%c alloca=%c setjmp=%c stack=%4ld arg=%3ld reg=%2d/%d delay=%3d/%3dL %3d/%3dJ refs=%3d/%3d/%3d",
4651 name,
4652 (frame_pointer_needed) ? 'y' : 'n',
4653 ((current_frame_info.mask & RA_MASK) != 0) ? 'n' : 'y',
4654 (current_function_calls_alloca) ? 'y' : 'n',
4655 (current_function_calls_setjmp) ? 'y' : 'n',
4656 (long)current_frame_info.total_size,
4657 (long)current_function_outgoing_args_size,
4658 num_gp_regs, num_fp_regs,
4659 dslots_load_total, dslots_load_filled,
4660 dslots_jump_total, dslots_jump_filled,
4661 num_refs[0], num_refs[1], num_refs[2]);
4662
4663 if (HALF_PIC_NUMBER_PTRS > prev_half_pic_ptrs)
4664 {
4665 fprintf (stderr, " half-pic=%3d", HALF_PIC_NUMBER_PTRS - prev_half_pic_ptrs);
4666 prev_half_pic_ptrs = HALF_PIC_NUMBER_PTRS;
4667 }
4668
4669 if (HALF_PIC_NUMBER_REFS > prev_half_pic_refs)
4670 {
4671 fprintf (stderr, " pic-ref=%3d", HALF_PIC_NUMBER_REFS - prev_half_pic_refs);
4672 prev_half_pic_refs = HALF_PIC_NUMBER_REFS;
4673 }
4674
4675 fputc ('\n', stderr);
4676 }
4677
4678 /* Reset state info for each function. */
4679 inside_function = FALSE;
4680 ignore_line_number = FALSE;
4681 dslots_load_total = 0;
4682 dslots_jump_total = 0;
4683 dslots_load_filled = 0;
4684 dslots_jump_filled = 0;
4685 num_refs[0] = 0;
4686 num_refs[1] = 0;
4687 num_refs[2] = 0;
4688 mips_load_reg = (rtx)0;
4689 mips_load_reg2 = (rtx)0;
4690 current_frame_info = zero_frame_info;
4691
4692 /* Restore the output file if optimizing the GP (optimizing the GP causes
4693 the text to be diverted to a tempfile, so that data decls come before
4694 references to the data). */
4695
4696 if (TARGET_GP_OPT)
4697 asm_out_file = asm_out_data_file;
4698 }
4699
4700 \f
4701 /* Expand the epilogue into a bunch of separate insns. */
4702
4703 void
4704 mips_expand_epilogue ()
4705 {
4706 long tsize = current_frame_info.total_size;
4707 rtx tsize_rtx = GEN_INT (tsize);
4708 rtx tmp_rtx = (rtx)0;
4709
4710 if (tsize > 32767)
4711 {
4712 tmp_rtx = gen_rtx (REG, SImode, MIPS_TEMP1_REGNUM);
4713 emit_move_insn (tmp_rtx, tsize_rtx);
4714 tsize_rtx = tmp_rtx;
4715 }
4716
4717 if (tsize > 0)
4718 {
4719 if (frame_pointer_needed)
4720 emit_insn (gen_movsi (stack_pointer_rtx, frame_pointer_rtx));
4721
4722 save_restore_insns (FALSE, tmp_rtx, tsize, (FILE *)0);
4723
4724 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, tsize_rtx));
4725 }
4726
4727 emit_jump_insn (gen_return_internal (gen_rtx (REG, Pmode, GP_REG_FIRST+31)));
4728 }
4729
4730 \f
4731 /* Define the number of delay slots needed for the function epilogue.
4732
4733 On the mips, we need a slot if either no stack has been allocated,
4734 or the only register saved is the return register. */
4735
4736 int
4737 mips_epilogue_delay_slots ()
4738 {
4739 if (!current_frame_info.initialized)
4740 (void) compute_frame_size (get_frame_size ());
4741
4742 if (current_frame_info.total_size == 0)
4743 return 1;
4744
4745 if (current_frame_info.mask == RA_MASK && current_frame_info.fmask == 0)
4746 return 1;
4747
4748 return 0;
4749 }
4750
4751 \f
4752 /* Return true if this function is known to have a null epilogue.
4753 This allows the optimizer to omit jumps to jumps if no stack
4754 was created. */
4755
4756 int
4757 simple_epilogue_p ()
4758 {
4759 if (!reload_completed)
4760 return 0;
4761
4762 if (current_frame_info.initialized)
4763 return current_frame_info.total_size == 0;
4764
4765 return (compute_frame_size (get_frame_size ())) == 0;
4766 }
This page took 0.251568 seconds and 5 git commands to generate.