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