|
|
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: #ifdef USG
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 char *getenv ();
66:
67: extern char *permalloc ();
68: extern void debug_rtx ();
69: extern void abort_with_insn ();
70: extern rtx copy_to_reg ();
71: extern rtx adj_offsettable_operand ();
72: extern int offsettable_address_p ();
73: extern tree lookup_name ();
74:
75: extern rtx gen_movqi ();
76: extern rtx gen_movhi ();
77: extern rtx gen_movsi ();
78: extern rtx gen_movsi_ulw ();
79: extern rtx gen_movsi_usw ();
80: extern rtx gen_addsi3 ();
81: extern rtx gen_iorsi3 ();
82: extern rtx gen_andsi3 ();
83: extern rtx gen_bne ();
84: extern rtx gen_beq ();
85: extern rtx gen_cmpsi ();
86: extern rtx gen_jump ();
87:
88: extern char call_used_regs[];
89: extern char *asm_file_name;
90: extern FILE *asm_out_file;
91: extern tree current_function_decl;
92: extern char **save_argv;
93: extern char *version_string;
94: extern char *language_string;
95:
96: /* Global variables for machine-dependent things. */
97:
98: /* Threshold for data being put into the small data/bss area, instead
99: of the normal data area (references to the small data/bss area take
100: 1 instruction, and use the global pointer, references to the normal
101: data area takes 2 instructions). */
102: int mips_section_threshold = -1;
103:
104: /* Count the number of .file directives, so that .loc is up to date. */
105: int num_source_filenames = 0;
106:
107: /* Count of the number of functions created so far, in order to make
108: unique labels for omitting the frame pointer. */
109: int number_functions_processed = 0;
110:
111: /* Count the number of sdb related labels are generated (to find block
112: start and end boundaries). */
113: int sdb_label_count = 0;
114:
115: /* Next label # for each statment for Silicon Graphics IRIS systems. */
116: int sym_lineno = 0;
117:
118: /* Non-zero if inside of a function, because the stupid MIPS asm can't
119: handle .files inside of functions. */
120: int inside_function = 0;
121:
122: /* Files to separate the text and the data output, so that all of the data
123: can be emitted before the text, which will mean that the assembler will
124: generate smaller code, based on the global pointer. */
125: FILE *asm_out_data_file;
126: FILE *asm_out_text_file;
127:
128: /* Linked list of all externals that are to be emitted when optimizing
129: for the global pointer if they haven't been declared by the end of
130: the program with an appropriate .comm or initialization. */
131:
132: struct extern_list {
133: struct extern_list *next; /* next external */
134: char *name; /* name of the external */
135: int size; /* size in bytes */
136: } *extern_head = 0;
137:
138: /* Name of the current function. */
139: char *current_function_name;
140:
141: /* Name of the file containing the current function. */
142: char *current_function_file = "";
143:
144: /* Warning given that Mips ECOFF can't support changing files
145: within a function. */
146: int file_in_function_warning = FALSE;
147:
148: /* Whether to supress issuing .loc's because the user attempted
149: to change the filename within a function. */
150: int ignore_line_number = FALSE;
151:
152: /* Number of nested .set noreorder, noat, nomacro, and volatile requests. */
153: int set_noreorder;
154: int set_noat;
155: int set_nomacro;
156: int set_volatile;
157:
158: /* The next branch instruction is a branch likely, not branch normal. */
159: int mips_branch_likely;
160:
161: /* Count of delay slots and how many are filled. */
162: int dslots_load_total;
163: int dslots_load_filled;
164: int dslots_jump_total;
165: int dslots_jump_filled;
166:
167: /* # of nops needed by previous insn */
168: int dslots_number_nops;
169:
170: /* Number of 1/2/3 word references to data items (ie, not jal's). */
171: int num_refs[3];
172:
173: /* registers to check for load delay */
174: rtx mips_load_reg, mips_load_reg2, mips_load_reg3, mips_load_reg4;
175:
176: /* Cached operands, and operator to compare for use in set/branch on
177: condition codes. */
178: rtx branch_cmp[2];
179:
180: /* what type of branch to use */
181: enum cmp_type branch_type;
182:
183: /* which cpu are we scheduling for */
184: enum processor_type mips_cpu;
185:
186: /* which instruction set architecture to use. */
187: int mips_isa;
188:
189: /* Strings to hold which cpu and instruction set architecture to use. */
190: char *mips_cpu_string; /* for -mcpu=<xxx> */
191: char *mips_isa_string; /* for -mips{1,2,3} */
192:
193: /* Array to RTX class classification. At present, we care about
194: whether the operator is an add-type operator, or a divide/modulus,
195: and if divide/modulus, whether it is unsigned. This is for the
196: peephole code. */
197: char mips_rtx_classify[NUM_RTX_CODE];
198:
199: /* Array giving truth value on whether or not a given hard register
200: can support a given mode. */
201: char mips_hard_regno_mode_ok[(int)MAX_MACHINE_MODE][FIRST_PSEUDO_REGISTER];
202:
203: /* Current frame information calculated by compute_frame_size. */
204: struct mips_frame_info current_frame_info;
205:
206: /* Zero structure to initialize current_frame_info. */
207: struct mips_frame_info zero_frame_info;
208:
209: /* Temporary filename used to buffer .text until end of program
210: for -mgpopt. */
211: static char *temp_filename;
212:
213: /* List of all MIPS punctuation characters used by print_operand. */
214: char mips_print_operand_punct[256];
215:
216: /* Map GCC register number to debugger register number. */
217: int mips_dbx_regno[FIRST_PSEUDO_REGISTER];
218:
219: /* Buffer to use to enclose a load/store operation with %{ %} to
220: turn on .set volatile. */
221: static char volatile_buffer[60];
222:
223: /* Hardware names for the registers. If -mrnames is used, this
224: will be overwritten with mips_sw_reg_names. */
225:
226: char mips_reg_names[][8] =
227: {
228: "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
229: "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
230: "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
231: "$24", "$25", "$26", "$27", "$28", "$sp", "$fp", "$31",
232: "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
233: "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
234: "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
235: "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31",
236: "hi", "lo", "$fcr31"
237: };
238:
239: /* Mips software names for the registers, used to overwrite the
240: mips_reg_names array. */
241:
242: char mips_sw_reg_names[][8] =
243: {
244: "$0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
245: "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
246: "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
247: "t8", "t9", "k0", "k1", "gp", "sp", "$fp", "ra",
248: "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
249: "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
250: "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
251: "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31",
252: "hi", "lo", "$fcr31"
253: };
254:
255: /* Map hard register number to register class */
256: enum reg_class mips_regno_to_class[] =
257: {
258: GR_REGS, GR_REGS, GR_REGS, GR_REGS,
259: GR_REGS, GR_REGS, GR_REGS, GR_REGS,
260: GR_REGS, GR_REGS, GR_REGS, GR_REGS,
261: GR_REGS, GR_REGS, GR_REGS, GR_REGS,
262: GR_REGS, GR_REGS, GR_REGS, GR_REGS,
263: GR_REGS, GR_REGS, GR_REGS, GR_REGS,
264: GR_REGS, GR_REGS, GR_REGS, GR_REGS,
265: GR_REGS, GR_REGS, GR_REGS, GR_REGS,
266: FP_REGS, FP_REGS, FP_REGS, FP_REGS,
267: FP_REGS, FP_REGS, FP_REGS, FP_REGS,
268: FP_REGS, FP_REGS, FP_REGS, FP_REGS,
269: FP_REGS, FP_REGS, FP_REGS, FP_REGS,
270: FP_REGS, FP_REGS, FP_REGS, FP_REGS,
271: FP_REGS, FP_REGS, FP_REGS, FP_REGS,
272: FP_REGS, FP_REGS, FP_REGS, FP_REGS,
273: FP_REGS, FP_REGS, FP_REGS, FP_REGS,
274: HI_REG, LO_REG, ST_REGS
275: };
276:
277: /* Map register constraint character to register class. */
278: enum reg_class mips_char_to_class[256] =
279: {
280: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
281: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
282: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
283: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
284: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
285: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
286: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
287: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
288: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
289: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
290: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
291: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
292: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
293: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
294: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
295: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
296: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
297: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
298: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
299: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
300: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
301: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
302: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
303: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
304: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
305: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
306: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
307: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
308: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
309: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
310: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
311: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
312: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
313: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
314: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
315: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
316: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
317: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
318: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
319: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
320: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
321: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
322: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
323: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
324: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
325: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
326: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
327: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
328: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
329: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
330: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
331: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
332: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
333: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
334: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
335: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
336: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
337: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
338: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
339: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
340: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
341: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
342: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
343: NO_REGS, NO_REGS, NO_REGS, NO_REGS,
344: };
345:
346:
347: /* Return truth value of whether OP can be used as an operands
348: where a register or 16 bit unsigned integer is needed. */
349:
350: int
351: uns_arith_operand (op, mode)
352: rtx op;
353: enum machine_mode mode;
354: {
355: if (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (op))
356: return TRUE;
357:
358: return register_operand (op, mode);
359: }
360:
361: /* Return truth value of whether OP can be used as an operands
362: where a 16 bit integer is needed */
363:
364: int
365: arith_operand (op, mode)
366: rtx op;
367: enum machine_mode mode;
368: {
369: if (GET_CODE (op) == CONST_INT && SMALL_INT (op))
370: return TRUE;
371:
372: return register_operand (op, mode);
373: }
374:
375: /* Return truth value of whether OP can be used as an operand in a two
376: address arithmetic insn (such as set 123456,%o4) of mode MODE. */
377:
378: int
379: arith32_operand (op, mode)
380: rtx op;
381: enum machine_mode mode;
382: {
383: if (GET_CODE (op) == CONST_INT)
384: return TRUE;
385:
386: return register_operand (op, mode);
387: }
388:
389: /* Return truth value of whether OP is a integer which fits in 16 bits */
390:
391: int
392: small_int (op, mode)
393: rtx op;
394: enum machine_mode mode;
395: {
396: return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
397: }
398:
399: /* Return truth value of whether OP is an integer which is too big to
400: be loaded with one instruction. */
401:
402: int
403: large_int (op, mode)
404: rtx op;
405: enum machine_mode mode;
406: {
407: long value;
408:
409: if (GET_CODE (op) != CONST_INT)
410: return FALSE;
411:
412: value = INTVAL (op);
413: if ((value & 0xffff0000) == 0) /* ior reg,$r0,value */
414: return FALSE;
415:
416: if ((value & 0xffff0000) == 0xffff0000) /* subu reg,$r0,value */
417: return FALSE;
418:
419: if ((value & 0x0000ffff) == 0) /* lui reg,value>>16 */
420: return FALSE;
421:
422: return TRUE;
423: }
424:
425: /* Return truth value of whether OP is a register or the constant 0. */
426:
427: int
428: reg_or_0_operand (op, mode)
429: rtx op;
430: enum machine_mode mode;
431: {
432: switch (GET_CODE (op))
433: {
434: case CONST_INT:
435: return (INTVAL (op) == 0);
436:
437: case CONST_DOUBLE:
438: if (CONST_DOUBLE_HIGH (op) != 0 || CONST_DOUBLE_LOW (op) != 0)
439: return FALSE;
440:
441: return TRUE;
442:
443: case REG:
444: case SUBREG:
445: return register_operand (op, mode);
446: }
447:
448: return FALSE;
449: }
450:
451: /* Return truth value of whether OP is one of the special multiply/divide
452: registers (hi, lo). */
453:
454: int
455: md_register_operand (op, mode)
456: rtx op;
457: enum machine_mode mode;
458: {
459: return (GET_MODE_CLASS (mode) == MODE_INT
460: && GET_CODE (op) == REG
461: && MD_REG_P (REGNO (op)));
462: }
463:
464: /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
465:
466: int
467: mips_const_double_ok (op, mode)
468: rtx op;
469: enum machine_mode mode;
470: {
471: if (GET_CODE (op) != CONST_DOUBLE)
472: return FALSE;
473:
474: if (mode == DImode)
475: return TRUE;
476:
477: if (mode != SFmode && mode != DFmode)
478: return FALSE;
479:
480: if (CONST_DOUBLE_HIGH (op) == 0 && CONST_DOUBLE_LOW (op) == 0)
481: return TRUE;
482:
483: #if HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
484: if (TARGET_MIPS_AS) /* gas doesn't like li.d/li.s yet */
485: {
486: union { double d; int i[2]; } u;
487: double d;
488:
489: u.i[0] = CONST_DOUBLE_LOW (op);
490: u.i[1] = CONST_DOUBLE_HIGH (op);
491: d = u.d;
492:
493: if (d != d)
494: return FALSE; /* NAN */
495:
496: if (d < 0.0)
497: d = - d;
498:
499: /* Rather than trying to get the accuracy down to the last bit,
500: just use approximate ranges. */
501:
502: if (mode == DFmode && d > 1.0e-300 && d < 1.0e300)
503: return TRUE;
504:
505: if (mode == SFmode && d > 1.0e-38 && d < 1.0e+38)
506: return TRUE;
507: }
508: #endif
509:
510: return FALSE;
511: }
512:
513: /* Return truth value if a memory operand fits in a single instruction
514: (ie, register + small offset). */
515:
516: int
517: simple_memory_operand (op, mode)
518: rtx op;
519: enum machine_mode mode;
520: {
521: rtx addr, plus0, plus1;
522: int offset = 0;
523:
524: /* Eliminate non-memory operations */
525: if (GET_CODE (op) != MEM)
526: return FALSE;
527:
528: /* dword operations really put out 2 instructions, so eliminate them. */
529: if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4))
530: return FALSE;
531:
532: /* Decode the address now. */
533: addr = XEXP (op, 0);
534: switch (GET_CODE (addr))
535: {
536: case REG:
537: return TRUE;
538:
539: case CONST_INT:
540: return SMALL_INT (op);
541:
542: case PLUS:
543: plus0 = XEXP (addr, 0);
544: plus1 = XEXP (addr, 1);
545: if (GET_CODE (plus0) == REG
546: && GET_CODE (plus1) == CONST_INT
547: && SMALL_INT (plus1))
548: return TRUE;
549:
550: else if (GET_CODE (plus1) == REG
551: && GET_CODE (plus0) == CONST_INT
552: && SMALL_INT (plus0))
553: return TRUE;
554:
555: else
556: return FALSE;
557:
558: #if 0
559: /* We used to allow small symbol refs here (ie, stuff in .sdata
560: or .sbss), but this causes some bugs in G++. Also, it won't
561: interfere if the MIPS linker rewrites the store instruction
562: because the function is PIC. */
563:
564: case LABEL_REF: /* never gp relative */
565: break;
566:
567: case CONST:
568: /* If -G 0, we can never have a GP relative memory operation.
569: Also, save some time if not optimizing. */
570: if (mips_section_threshold == 0 || !optimize || !TARGET_GP_OPT)
571: return FALSE;
572:
573: addr = eliminate_constant_term (addr, &offset);
574: if (GET_CODE (op) != SYMBOL_REF)
575: return FALSE;
576:
577: /* fall through */
578:
579: case SYMBOL_REF:
580: /* let's be paranoid.... */
581: if (offset < 0 || offset > 0xffff)
582: return FALSE;
583:
584: return SYMBOL_REF_FLAG (addr);
585: #endif
586: }
587:
588: return FALSE;
589: }
590:
591: /* Return true if the address is suitable for function call. */
592:
593: int
594: call_memory_operand (op, mode)
595: rtx op;
596: enum machine_mode mode;
597: {
598: rtx addr;
599: enum rtx_code code;
600:
601: if (GET_CODE (op) != MEM)
602: return FALSE;
603:
604: addr = XEXP (op, 0);
605: code = GET_CODE (addr);
606:
607: if (GET_MODE (addr) != FUNCTION_MODE)
608: return FALSE;
609:
610: if (code == REG || code == SUBREG)
611: return TRUE;
612:
613: if (CONSTANT_ADDRESS_P (addr))
614: return TRUE;
615:
616: return FALSE;
617: }
618:
619: /* Return true if the code of this rtx pattern is EQ or NE. */
620:
621: int
622: equality_op (op, mode)
623: rtx op;
624: enum machine_mode mode;
625: {
626: if (mode != GET_MODE (op))
627: return FALSE;
628:
629: return (classify_op (op, mode) & CLASS_EQUALITY_OP) != 0;
630: }
631:
632: /* Return true if the code is a relational operations (EQ, LE, etc.) */
633:
634: int
635: cmp_op (op, mode)
636: rtx op;
637: enum machine_mode mode;
638: {
639: if (mode != GET_MODE (op))
640: return FALSE;
641:
642: return (classify_op (op, mode) & CLASS_CMP_OP) != 0;
643: }
644:
645:
646: /* Genrecog does not take the type of match_operator into consideration,
647: and would complain about two patterns being the same if the same
648: function is used, so make it believe they are different. */
649:
650: int
651: cmp2_op (op, mode)
652: rtx op;
653: enum machine_mode mode;
654: {
655: if (mode != GET_MODE (op))
656: return FALSE;
657:
658: return (classify_op (op, mode) & CLASS_CMP_OP) != 0;
659: }
660:
661: /* Return true if the code is an unsigned relational operations (LEU, etc.) */
662:
663: int
664: uns_cmp_op (op,mode)
665: rtx op;
666: enum machine_mode mode;
667: {
668: if (mode != GET_MODE (op))
669: return FALSE;
670:
671: return (classify_op (op, mode) & CLASS_UNS_CMP_OP) == CLASS_UNS_CMP_OP;
672: }
673:
674: /* Return true if the code is a relational operation FP can use. */
675:
676: int
677: fcmp_op (op, mode)
678: rtx op;
679: enum machine_mode mode;
680: {
681: if (mode != GET_MODE (op))
682: return FALSE;
683:
684: return (classify_op (op, mode) & CLASS_FCMP_OP) != 0;
685: }
686:
687:
688: /* Return an operand string if the given instruction's delay slot or
689: wrap it in a .set noreorder section. This is for filling delay
690: slots on load type instructions under GAS, which does no reordering
691: on its own. For the MIPS assembler, all we do is update the filled
692: delay slot statistics.
693:
694: We assume that operands[0] is the target register that is set.
695:
696: In order to check the next insn, most of this functionality is moved
697: to FINAL_PRESCAN_INSN, and we just set the global variables that
698: it needs. */
699:
700: char *
701: mips_fill_delay_slot (ret, type, operands, cur_insn)
702: char *ret; /* normal string to return */
703: enum delay_type type; /* type of delay */
704: rtx operands[]; /* operands to use */
705: rtx cur_insn; /* current insn */
706: {
707: register rtx set_reg;
708: register enum machine_mode mode;
709: register rtx next_insn = (cur_insn) ? NEXT_INSN (cur_insn) : (rtx)0;
710: register int num_nops;
711:
712: if (type == DELAY_LOAD)
713: num_nops = 1;
714:
715: else if (type == DELAY_HILO)
716: num_nops = 2;
717:
718: else
719: num_nops = 0;
720:
721: /* Make sure that we don't put nop's after labels. */
722: next_insn = NEXT_INSN (cur_insn);
723: while (next_insn != (rtx)0 && GET_CODE (next_insn) == NOTE)
724: next_insn = NEXT_INSN (next_insn);
725:
726: dslots_load_total += num_nops;
727: if (TARGET_DEBUG_F_MODE
728: || !optimize
729: || type == DELAY_NONE
730: || operands == (rtx *)0
731: || cur_insn == (rtx)0
732: || next_insn == (rtx)0
733: || GET_CODE (next_insn) == CODE_LABEL
734: || (set_reg = operands[0]) == (rtx)0)
735: {
736: dslots_number_nops = 0;
737: mips_load_reg = (rtx)0;
738: mips_load_reg2 = (rtx)0;
739: mips_load_reg3 = (rtx)0;
740: mips_load_reg4 = (rtx)0;
741: return ret;
742: }
743:
744: set_reg = operands[0];
745: if (set_reg == (rtx)0)
746: return ret;
747:
748: while (GET_CODE (set_reg) == SUBREG)
749: set_reg = SUBREG_REG (set_reg);
750:
751: mode = GET_MODE (set_reg);
752: dslots_number_nops = num_nops;
753: mips_load_reg = set_reg;
754: mips_load_reg2 = (mode == DImode || mode == DFmode)
755: ? gen_rtx (REG, SImode, REGNO (set_reg) + 1)
756: : (rtx)0;
757:
758: if (type == DELAY_HILO)
759: {
760: mips_load_reg3 = gen_rtx (REG, SImode, MD_REG_FIRST);
761: mips_load_reg4 = gen_rtx (REG, SImode, MD_REG_FIRST+1);
762: }
763: else
764: {
765: mips_load_reg3 = 0;
766: mips_load_reg4 = 0;
767: }
768:
769: if (TARGET_GAS && set_noreorder++ == 0)
770: fputs ("\t.set\tnoreorder\n", asm_out_file);
771:
772: return ret;
773: }
774:
775:
776: /* Determine whether a memory reference takes one (based off of the GP pointer),
777: two (normal), or three (label + reg) instructins, and bump the appropriate
778: counter for -mstats. */
779:
780: void
781: mips_count_memory_refs (op, num)
782: rtx op;
783: int num;
784: {
785: int additional = 0;
786: int n_words = 0;
787: rtx addr, plus0, plus1;
788: enum rtx_code code0, code1;
789: int looping;
790:
791: if (TARGET_DEBUG_B_MODE)
792: {
793: fprintf (stderr, "\n========== mips_count_memory_refs:\n");
794: debug_rtx (op);
795: }
796:
797: /* Skip MEM if passed, otherwise handle movsi of address. */
798: addr = (GET_CODE (op) != MEM) ? op : XEXP (op, 0);
799:
800: /* Loop, going through the address RTL */
801: do
802: {
803: looping = FALSE;
804: switch (GET_CODE (addr))
805: {
806: case REG:
807: case CONST_INT:
808: break;
809:
810: case PLUS:
811: plus0 = XEXP (addr, 0);
812: plus1 = XEXP (addr, 1);
813: code0 = GET_CODE (plus0);
814: code1 = GET_CODE (plus1);
815:
816: if (code0 == REG)
817: {
818: additional++;
819: addr = plus1;
820: looping = TRUE;
821: continue;
822: }
823:
824: if (code0 == CONST_INT)
825: {
826: addr = plus1;
827: looping = TRUE;
828: continue;
829: }
830:
831: if (code1 == REG)
832: {
833: additional++;
834: addr = plus0;
835: looping = TRUE;
836: continue;
837: }
838:
839: if (code1 == CONST_INT)
840: {
841: addr = plus0;
842: looping = TRUE;
843: continue;
844: }
845:
846: if (code0 == SYMBOL_REF || code0 == LABEL_REF || code0 == CONST)
847: {
848: addr = plus0;
849: looping = TRUE;
850: continue;
851: }
852:
853: if (code1 == SYMBOL_REF || code1 == LABEL_REF || code1 == CONST)
854: {
855: addr = plus1;
856: looping = TRUE;
857: continue;
858: }
859:
860: break;
861:
862: case LABEL_REF:
863: n_words = 2; /* always 2 words */
864: break;
865:
866: case CONST:
867: addr = XEXP (addr, 0);
868: looping = TRUE;
869: continue;
870:
871: case SYMBOL_REF:
872: n_words = SYMBOL_REF_FLAG (addr) ? 1 : 2;
873: break;
874: }
875: }
876: while (looping);
877:
878: if (n_words == 0)
879: return;
880:
881: n_words += additional;
882: if (n_words > 3)
883: n_words = 3;
884:
885: num_refs[n_words-1] += num;
886: }
887:
888:
889: /* Return the appropriate instructions to move one operand to another. */
890:
891: char *
892: mips_move_1word (operands, insn, unsignedp)
893: rtx operands[];
894: rtx insn;
895: int unsignedp;
896: {
897: char *ret = 0;
898: rtx op0 = operands[0];
899: rtx op1 = operands[1];
900: enum rtx_code code0 = GET_CODE (op0);
901: enum rtx_code code1 = GET_CODE (op1);
902: enum machine_mode mode = GET_MODE (op0);
903: int subreg_word0 = 0;
904: int subreg_word1 = 0;
905: enum delay_type delay = DELAY_NONE;
906:
907: while (code0 == SUBREG)
908: {
909: subreg_word0 += SUBREG_WORD (op0);
910: op0 = SUBREG_REG (op0);
911: code0 = GET_CODE (op0);
912: }
913:
914: while (code1 == SUBREG)
915: {
916: subreg_word1 += SUBREG_WORD (op1);
917: op1 = SUBREG_REG (op1);
918: code1 = GET_CODE (op1);
919: }
920:
921: if (code0 == REG)
922: {
923: int regno0 = REGNO (op0) + subreg_word0;
924:
925: if (code1 == REG)
926: {
927: int regno1 = REGNO (op1) + subreg_word1;
928:
929: /* Just in case, don't do anything for assigning a register
930: to itself, unless we are filling a delay slot. */
931: if (regno0 == regno1 && set_nomacro == 0)
932: ret = "";
933:
934: else if (GP_REG_P (regno0))
935: {
936: if (GP_REG_P (regno1))
937: ret = "move\t%0,%1";
938:
939: else if (MD_REG_P (regno1))
940: {
941: delay = DELAY_HILO;
942: ret = "mf%1\t%0";
943: }
944:
945: else
946: {
947: delay = DELAY_LOAD;
948: if (FP_REG_P (regno1))
949: ret = "mfc1\t%0,%1";
950:
951: else if (regno1 == FPSW_REGNUM)
952: ret = "cfc1\t%0,$31";
953: }
954: }
955:
956: else if (FP_REG_P (regno0))
957: {
958: if (GP_REG_P (regno1))
959: {
960: delay = DELAY_LOAD;
961: ret = "mtc1\t%1,%0";
962: }
963:
964: if (FP_REG_P (regno1))
965: ret = "mov.s\t%0,%1";
966: }
967:
968: else if (MD_REG_P (regno0))
969: {
970: if (GP_REG_P (regno1))
971: {
972: delay = DELAY_HILO;
973: ret = "mt%0\t%1";
974: }
975: }
976:
977: else if (regno0 == FPSW_REGNUM)
978: {
979: if (GP_REG_P (regno1))
980: {
981: delay = DELAY_LOAD;
982: ret = "ctc1\t%0,$31";
983: }
984: }
985: }
986:
987: else if (code1 == MEM)
988: {
989: delay = DELAY_LOAD;
990:
991: if (TARGET_STATS)
992: mips_count_memory_refs (op1, 1);
993:
994: if (GP_REG_P (regno0))
995: {
996: /* For loads, use the mode of the memory item, instead of the
997: target, so zero/sign extend can use this code as well. */
998: switch (GET_MODE (op1))
999: {
1000: case SFmode: ret = "lw\t%0,%1"; break;
1001: case SImode: ret = "lw\t%0,%1"; break;
1002: case HImode: ret = (unsignedp) ? "lhu\t%0,%1" : "lh\t%0,%1"; break;
1003: case QImode: ret = (unsignedp) ? "lbu\t%0,%1" : "lb\t%0,%1"; break;
1004: }
1005: }
1006:
1007: else if (FP_REG_P (regno0) && (mode == SImode || mode == SFmode))
1008: ret = "l.s\t%0,%1";
1009:
1010: if (ret != (char *)0 && MEM_VOLATILE_P (op1))
1011: {
1012: int i = strlen (ret);
1013: if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
1014: abort ();
1015:
1016: sprintf (volatile_buffer, "%%{%s%%}", ret);
1017: ret = volatile_buffer;
1018: }
1019: }
1020:
1021: else if (code1 == CONST_INT)
1022: {
1023: if (INTVAL (op1) == 0)
1024: {
1025: if (GP_REG_P (regno0))
1026: ret = "move\t%0,%z1";
1027:
1028: else if (FP_REG_P (regno0))
1029: {
1030: delay = DELAY_LOAD;
1031: return "mtc1\t%z1,%0";
1032: }
1033: }
1034:
1035: else if (GP_REG_P (regno0))
1036: {
1037: if ((INTVAL (operands[1]) & 0x0000ffff) == 0)
1038: ret = "lui\t%0,(%X1)>>16";
1039: else
1040: ret = "li\t%0,%1";
1041: }
1042: }
1043:
1044: else if (code1 == CONST_DOUBLE && mode == SFmode)
1045: {
1046: if (CONST_DOUBLE_HIGH (op1) == 0 && CONST_DOUBLE_LOW (op1) == 0)
1047: {
1048: if (GP_REG_P (regno0))
1049: ret = "move\t%0,%.";
1050:
1051: else if (FP_REG_P (regno0))
1052: {
1053: delay = DELAY_LOAD;
1054: ret = "mtc1\t%.,%0";
1055: }
1056: }
1057:
1058: else
1059: {
1060: delay = DELAY_LOAD;
1061: ret = "li.s\t%0,%1";
1062: }
1063: }
1064:
1065: else if (code1 == LABEL_REF)
1066: ret = "la\t%0,%a1";
1067:
1068: else if (code1 == SYMBOL_REF || code1 == CONST)
1069: {
1070: if (TARGET_STATS)
1071: mips_count_memory_refs (op1, 1);
1072:
1073: if (HALF_PIC_P () && CONSTANT_P (op1) && HALF_PIC_ADDRESS_P (op1))
1074: {
1075: delay = DELAY_LOAD;
1076: ret = "la\t%0,%a1\t\t# pic reference";
1077: }
1078: else
1079: ret = "la\t%0,%a1";
1080: }
1081:
1082: else if (code1 == PLUS)
1083: {
1084: rtx add_op0 = XEXP (op1, 0);
1085: rtx add_op1 = XEXP (op1, 1);
1086:
1087: if (GET_CODE (XEXP (op1, 1)) == REG && GET_CODE (XEXP (op1, 0)) == CONST_INT)
1088: {
1089: add_op0 = XEXP (op1, 1); /* reverse operands */
1090: add_op1 = XEXP (op1, 0);
1091: }
1092:
1093: operands[2] = add_op0;
1094: operands[3] = add_op1;
1095: ret = "add%:\t%0,%2,%3";
1096: }
1097: }
1098:
1099: else if (code0 == MEM)
1100: {
1101: if (TARGET_STATS)
1102: mips_count_memory_refs (op0, 1);
1103:
1104: if (code1 == REG)
1105: {
1106: int regno1 = REGNO (op1) + subreg_word1;
1107:
1108: if (GP_REG_P (regno1))
1109: {
1110: switch (mode)
1111: {
1112: case SFmode: ret = "sw\t%1,%0"; break;
1113: case SImode: ret = "sw\t%1,%0"; break;
1114: case HImode: ret = "sh\t%1,%0"; break;
1115: case QImode: ret = "sb\t%1,%0"; break;
1116: }
1117: }
1118:
1119: else if (FP_REG_P (regno1) && (mode == SImode || mode == SFmode))
1120: ret = "s.s\t%1,%0";
1121: }
1122:
1123: else if (code1 == CONST_INT && INTVAL (op1) == 0)
1124: {
1125: switch (mode)
1126: {
1127: case SFmode: ret = "sw\t%z1,%0"; break;
1128: case SImode: ret = "sw\t%z1,%0"; break;
1129: case HImode: ret = "sh\t%z1,%0"; break;
1130: case QImode: ret = "sb\t%z1,%0"; break;
1131: }
1132: }
1133:
1134: else if (code1 == CONST_DOUBLE && CONST_DOUBLE_HIGH (op1) == 0 && CONST_DOUBLE_LOW (op1) == 0)
1135: {
1136: switch (mode)
1137: {
1138: case SFmode: ret = "sw\t%.,%0"; break;
1139: case SImode: ret = "sw\t%.,%0"; break;
1140: case HImode: ret = "sh\t%.,%0"; break;
1141: case QImode: ret = "sb\t%.,%0"; break;
1142: }
1143: }
1144:
1145: if (ret != (char *)0 && MEM_VOLATILE_P (op0))
1146: {
1147: int i = strlen (ret);
1148: if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
1149: abort ();
1150:
1151: sprintf (volatile_buffer, "%%{%s%%}", ret);
1152: ret = volatile_buffer;
1153: }
1154: }
1155:
1156: if (ret == (char *)0)
1157: {
1158: abort_with_insn (insn, "Bad move");
1159: return 0;
1160: }
1161:
1162: if (delay != DELAY_NONE)
1163: return mips_fill_delay_slot (ret, delay, operands, insn);
1164:
1165: return ret;
1166: }
1167:
1168:
1169: /* Return the appropriate instructions to move 2 words */
1170:
1171: char *
1172: mips_move_2words (operands, insn)
1173: rtx operands[];
1174: rtx insn;
1175: {
1176: char *ret = 0;
1177: rtx op0 = operands[0];
1178: rtx op1 = operands[1];
1179: enum rtx_code code0 = GET_CODE (operands[0]);
1180: enum rtx_code code1 = GET_CODE (operands[1]);
1181: int subreg_word0 = 0;
1182: int subreg_word1 = 0;
1183: enum delay_type delay = DELAY_NONE;
1184:
1185: while (code0 == SUBREG)
1186: {
1187: subreg_word0 += SUBREG_WORD (op0);
1188: op0 = SUBREG_REG (op0);
1189: code0 = GET_CODE (op0);
1190: }
1191:
1192: while (code1 == SUBREG)
1193: {
1194: subreg_word1 += SUBREG_WORD (op1);
1195: op1 = SUBREG_REG (op1);
1196: code1 = GET_CODE (op1);
1197: }
1198:
1199: if (code0 == REG)
1200: {
1201: int regno0 = REGNO (op0) + subreg_word0;
1202:
1203: if (code1 == REG)
1204: {
1205: int regno1 = REGNO (op1) + subreg_word1;
1206:
1207: /* Just in case, don't do anything for assigning a register
1208: to itself, unless we are filling a delay slot. */
1209: if (regno0 == regno1 && set_nomacro == 0)
1210: ret = "";
1211:
1212: else if (FP_REG_P (regno0))
1213: {
1214: if (FP_REG_P (regno1))
1215: ret = "mov.d\t%0,%1";
1216:
1217: else
1218: {
1219: delay = DELAY_LOAD;
1220: ret = (TARGET_FLOAT64)
1221: ? "dmtc1\t%1,%0"
1222: : "mtc1\t%L1,%0\n\tmtc1\t%M1,%D0";
1223: }
1224: }
1225:
1226: else if (FP_REG_P (regno1))
1227: {
1228: delay = DELAY_LOAD;
1229: ret = (TARGET_FLOAT64)
1230: ? "dmfc1\t%0,%1"
1231: : "mfc1\t%L0,%1\n\tmfc1\t%M0,%D1";
1232: }
1233:
1234: else if (MD_REG_P (regno0) && GP_REG_P (regno1))
1235: {
1236: delay = DELAY_HILO;
1237: ret = "mthi\t%M1\n\tmtlo\t%L1";
1238: }
1239:
1240: else if (GP_REG_P (regno0) && MD_REG_P (regno1))
1241: {
1242: delay = DELAY_HILO;
1243: ret = "mfhi\t%M0\n\tmflo\t%L0";
1244: }
1245:
1246: else if (regno0 != (regno1+1))
1247: ret = "move\t%0,%1\n\tmove\t%D0,%D1";
1248:
1249: else
1250: ret = "move\t%D0,%D1\n\tmove\t%0,%1";
1251: }
1252:
1253: else if (code1 == CONST_DOUBLE)
1254: {
1255: if (CONST_DOUBLE_HIGH (op1) != 0 || CONST_DOUBLE_LOW (op1) != 0)
1256: {
1257: if (GET_MODE (op1) == DFmode)
1258: {
1259: delay = DELAY_LOAD;
1260: ret = "li.d\t%0,%1";
1261: }
1262:
1263: else
1264: {
1265: operands[2] = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_LOW (op1));
1266: operands[3] = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_HIGH (op1));
1267: ret = "li\t%M0,%3\n\tli\t%L0,%2";
1268: }
1269: }
1270:
1271: else
1272: {
1273: if (GP_REG_P (regno0))
1274: ret = "move\t%0,%.\n\tmove\t%D0,%.";
1275:
1276: else if (FP_REG_P (regno0))
1277: {
1278: delay = DELAY_LOAD;
1279: ret = (TARGET_FLOAT64)
1280: ? "dmtc1\t%.,%0"
1281: : "mtc1\t%.,%0\n\tmtc1\t%.,%D0";
1282: }
1283: }
1284: }
1285:
1286: else if (code1 == CONST_INT && INTVAL (op1) == 0)
1287: {
1288: if (GP_REG_P (regno0))
1289: ret = "move\t%0,%.\n\tmove\t%D0,%.";
1290:
1291: else if (FP_REG_P (regno0))
1292: {
1293: delay = DELAY_LOAD;
1294: ret = (TARGET_FLOAT64)
1295: ? "dmtc1\t%.,%0"
1296: : "mtc1\t%.,%0\n\tmtc1\t%.,%D0";
1297: }
1298: }
1299:
1300: else if (code1 == CONST_INT && GET_MODE (op0) == DImode && GP_REG_P (regno0))
1301: {
1302: operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[1]) >= 0 ? 0 : -1);
1303: ret = "li\t%M0,%2\n\tli\t%L0,%1";
1304: }
1305:
1306: else if (code1 == MEM)
1307: {
1308: delay = DELAY_LOAD;
1309:
1310: if (TARGET_STATS)
1311: mips_count_memory_refs (op1, 2);
1312:
1313: if (FP_REG_P (regno0))
1314: ret = "l.d\t%0,%1";
1315:
1316: else if (offsettable_address_p (1, DFmode, XEXP (op1, 0)))
1317: {
1318: operands[2] = adj_offsettable_operand (op1, 4);
1319: if (reg_mentioned_p (op0, op1))
1320: ret = "lw\t%D0,%2\n\tlw\t%0,%1";
1321: else
1322: ret = "lw\t%0,%1\n\tlw\t%D0,%2";
1323: }
1324:
1325: if (ret != (char *)0 && MEM_VOLATILE_P (op1))
1326: {
1327: int i = strlen (ret);
1328: if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
1329: abort ();
1330:
1331: sprintf (volatile_buffer, "%%{%s%%}", ret);
1332: ret = volatile_buffer;
1333: }
1334: }
1335: }
1336:
1337: else if (code0 == MEM)
1338: {
1339: if (code1 == REG)
1340: {
1341: int regno1 = REGNO (op1) + subreg_word1;
1342:
1343: if (FP_REG_P (regno1))
1344: ret = "s.d\t%1,%0";
1345:
1346: else if (offsettable_address_p (1, DFmode, XEXP (op0, 0)))
1347: {
1348: operands[2] = adj_offsettable_operand (op0, 4);
1349: ret = "sw\t%1,%0\n\tsw\t%D1,%2";
1350: }
1351: }
1352:
1353: else if (code1 == CONST_DOUBLE
1354: && CONST_DOUBLE_HIGH (op1) == 0
1355: && CONST_DOUBLE_LOW (op1) == 0
1356: && offsettable_address_p (1, DFmode, XEXP (op0, 0)))
1357: {
1358: if (TARGET_FLOAT64)
1359: ret = "sd\t%.,%0";
1360: else
1361: {
1362: operands[2] = adj_offsettable_operand (op0, 4);
1363: ret = "sw\t%.,%0\n\tsw\t%.,%2";
1364: }
1365: }
1366:
1367: if (TARGET_STATS)
1368: mips_count_memory_refs (op0, 2);
1369:
1370: if (ret != (char *)0 && MEM_VOLATILE_P (op0))
1371: {
1372: int i = strlen (ret);
1373: if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
1374: abort ();
1375:
1376: sprintf (volatile_buffer, "%%{%s%%}", ret);
1377: ret = volatile_buffer;
1378: }
1379: }
1380:
1381: if (ret == (char *)0)
1382: {
1383: abort_with_insn (insn, "Bad move");
1384: return 0;
1385: }
1386:
1387: if (delay != DELAY_NONE)
1388: return mips_fill_delay_slot (ret, delay, operands, insn);
1389:
1390: return ret;
1391: }
1392:
1393:
1394: /* Provide the costs of an addressing mode that contains ADDR.
1395: If ADDR is not a valid address, its cost is irrelavent. */
1396:
1397: int
1398: mips_address_cost (addr)
1399: rtx addr;
1400: {
1401: int offset;
1402:
1403: switch (GET_CODE (addr))
1404: {
1405: case LO_SUM:
1406: case HIGH:
1407: return 1;
1408:
1409: case LABEL_REF:
1410: return 2;
1411:
1412: case CONST:
1413: offset = 0;
1414: addr = eliminate_constant_term (addr, &offset);
1415: if (GET_CODE (addr) == LABEL_REF)
1416: return 2;
1417:
1418: if (GET_CODE (addr) != SYMBOL_REF)
1419: return 4;
1420:
1421: if (offset < -32768 || offset > 32767)
1422: return 2;
1423:
1424: /* fall through */
1425:
1426: case SYMBOL_REF:
1427: return SYMBOL_REF_FLAG (addr) ? 1 : 2;
1428:
1429: case PLUS:
1430: {
1431: register rtx plus0 = XEXP (addr, 0);
1432: register rtx plus1 = XEXP (addr, 1);
1433:
1434: if (GET_CODE (plus0) != REG && GET_CODE (plus1) == REG)
1435: {
1436: plus0 = XEXP (addr, 1);
1437: plus1 = XEXP (addr, 0);
1438: }
1439:
1440: if (GET_CODE (plus0) != REG)
1441: break;
1442:
1443: switch (GET_CODE (plus1))
1444: {
1445: case CONST_INT:
1446: {
1447: int value = INTVAL (plus1);
1448: return (value < -32768 || value > 32767) ? 2 : 1;
1449: }
1450:
1451: case CONST:
1452: case SYMBOL_REF:
1453: case LABEL_REF:
1454: case HIGH:
1455: case LO_SUM:
1456: return mips_address_cost (plus1) + 1;
1457: }
1458: }
1459: }
1460:
1461: return 4;
1462: }
1463:
1464:
1465: /* Emit the common code for doing conditional branches.
1466: operand[0] is the label to jump to.
1467: The comparison operands are saved away by cmp{si,sf,df}. */
1468:
1469: void
1470: gen_conditional_branch (operands, test_code)
1471: rtx operands[];
1472: enum rtx_code test_code;
1473: {
1474: enum {
1475: I_EQ,
1476: I_NE,
1477: I_GT,
1478: I_GE,
1479: I_LT,
1480: I_LE,
1481: I_GTU,
1482: I_GEU,
1483: I_LTU,
1484: I_LEU,
1485: I_MAX
1486: } test = I_MAX;
1487:
1488: static enum machine_mode mode_map[(int)CMP_MAX][(int)I_MAX] = {
1489: { /* CMP_SI */
1490: CC_EQmode, /* eq */
1491: CC_EQmode, /* ne */
1492: CCmode, /* gt */
1493: CCmode, /* ge */
1494: CCmode, /* lt */
1495: CCmode, /* le */
1496: CCmode, /* gtu */
1497: CCmode, /* geu */
1498: CCmode, /* ltu */
1499: CCmode, /* leu */
1500: },
1501: { /* CMP_SF */
1502: CC_FPmode, /* eq */
1503: CC_FPmode, /* ne */
1504: CC_FPmode, /* gt */
1505: CC_FPmode, /* ge */
1506: CC_FPmode, /* lt */
1507: CC_FPmode, /* le */
1508: VOIDmode, /* gtu */
1509: VOIDmode, /* geu */
1510: VOIDmode, /* ltu */
1511: VOIDmode, /* leu */
1512: },
1513: { /* CMP_DF */
1514: CC_FPmode, /* eq */
1515: CC_FPmode, /* ne */
1516: CC_FPmode, /* gt */
1517: CC_FPmode, /* ge */
1518: CC_FPmode, /* lt */
1519: CC_FPmode, /* le */
1520: VOIDmode, /* gtu */
1521: VOIDmode, /* geu */
1522: VOIDmode, /* ltu */
1523: VOIDmode, /* leu */
1524: },
1525: };
1526:
1527: enum machine_mode mode;
1528: enum cmp_type type = branch_type;
1529: rtx cmp0 = branch_cmp[0];
1530: rtx cmp1 = branch_cmp[1];
1531: rtx label = gen_rtx (LABEL_REF, VOIDmode, operands[0]);
1532:
1533: /* Make normal rtx_code into something we can index from an array */
1534: switch (test_code)
1535: {
1536: case EQ: test = I_EQ; break;
1537: case NE: test = I_NE; break;
1538: case GT: test = I_GT; break;
1539: case GE: test = I_GE; break;
1540: case LT: test = I_LT; break;
1541: case LE: test = I_LE; break;
1542: case GTU: test = I_GTU; break;
1543: case GEU: test = I_GEU; break;
1544: case LTU: test = I_LTU; break;
1545: case LEU: test = I_LEU; break;
1546: }
1547:
1548: if (test == I_MAX)
1549: {
1550: mode = CCmode;
1551: goto fail;
1552: }
1553:
1554: /* Get the machine mode to use (CCmode, CC_EQmode, or CC_FPmode). */
1555: mode = mode_map[(int)type][(int)test];
1556: if (mode == VOIDmode)
1557: goto fail;
1558:
1559: switch (branch_type)
1560: {
1561: default:
1562: goto fail;
1563:
1564: case CMP_SI:
1565: /* Change >, >=, <, <= tests against 0 to use CC_0mode, since we have
1566: special instructions to do these tests directly. */
1567:
1568: if (mode == CCmode && GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) == 0)
1569: {
1570: emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, cmp0));
1571: mode = CC_0mode;
1572: }
1573:
1574: else if (mode == CCmode && GET_CODE (cmp0) == CONST_INT && INTVAL (cmp0) == 0)
1575: {
1576: emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, cmp1));
1577: test_code = reverse_condition (test_code);
1578: mode = CC_0mode;
1579: }
1580:
1581: else
1582: {
1583: /* force args to register for equality comparisons. */
1584: if (mode == CC_EQmode && GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) != 0)
1585: cmp1 = force_reg (SImode, cmp1);
1586:
1587: emit_insn (gen_rtx (SET, VOIDmode,
1588: cc0_rtx,
1589: gen_rtx (COMPARE, mode, cmp0, cmp1)));
1590: }
1591: break;
1592:
1593: case CMP_DF:
1594: emit_insn (gen_cmpdf_internal (cmp0, cmp1));
1595: break;
1596:
1597: case CMP_SF:
1598: emit_insn (gen_cmpsf_internal (cmp0, cmp1));
1599: break;
1600: }
1601:
1602: /* Generate the jump */
1603: emit_jump_insn (gen_rtx (SET, VOIDmode,
1604: pc_rtx,
1605: gen_rtx (IF_THEN_ELSE, VOIDmode,
1606: gen_rtx (test_code, mode, cc0_rtx, const0_rtx),
1607: label,
1608: pc_rtx)));
1609: return;
1610:
1611: fail:
1612: abort_with_insn (gen_rtx (test_code, mode, cmp0, cmp1), "bad test");
1613: }
1614:
1615:
1616: #define UNITS_PER_SHORT (SHORT_TYPE_SIZE / BITS_PER_UNIT)
1617:
1618: /* Internal code to generate the load and store of one word/short/byte.
1619: The load is emitted directly, and the store insn is returned. */
1620:
1621: static rtx
1622: block_move_load_store (dest_reg, src_reg, p_bytes, p_offset, align)
1623: rtx src_reg; /* register holding source memory addresss */
1624: rtx dest_reg; /* register holding dest. memory addresss */
1625: int *p_bytes; /* pointer to # bytes remaining */
1626: int *p_offset; /* pointer to current offset */
1627: int align; /* alignment */
1628: {
1629: int bytes; /* # bytes remaining */
1630: int offset; /* offset to use */
1631: int size; /* size in bytes of load/store */
1632: enum machine_mode mode; /* mode to use for load/store */
1633: rtx reg; /* temporary register */
1634: rtx src_addr; /* source address */
1635: rtx dest_addr; /* destintation address */
1636: rtx (*load_func)(); /* function to generate load insn */
1637: rtx (*store_func)(); /* function to generate destination insn */
1638:
1639: bytes = *p_bytes;
1640: if (bytes <= 0 || align <= 0)
1641: abort ();
1642:
1643: if (bytes >= UNITS_PER_WORD && align >= UNITS_PER_WORD)
1644: {
1645: mode = SImode;
1646: size = UNITS_PER_WORD;
1647: load_func = gen_movsi;
1648: store_func = gen_movsi;
1649: }
1650:
1651: else if (bytes >= UNITS_PER_WORD)
1652: {
1653: mode = SImode;
1654: size = UNITS_PER_WORD;
1655: load_func = gen_movsi_ulw;
1656: store_func = gen_movsi_usw;
1657: }
1658:
1659: else if (bytes >= UNITS_PER_SHORT && align >= UNITS_PER_SHORT)
1660: {
1661: mode = HImode;
1662: size = UNITS_PER_SHORT;
1663: load_func = gen_movhi;
1664: store_func = gen_movhi;
1665: }
1666:
1667: else
1668: {
1669: mode = QImode;
1670: size = 1;
1671: load_func = gen_movqi;
1672: store_func = gen_movqi;
1673: }
1674:
1675: offset = *p_offset;
1676: *p_offset = offset + size;
1677: *p_bytes = bytes - size;
1678:
1679: if (offset == 0)
1680: {
1681: src_addr = src_reg;
1682: dest_addr = dest_reg;
1683: }
1684: else
1685: {
1686: src_addr = gen_rtx (PLUS, Pmode, src_reg, gen_rtx (CONST_INT, VOIDmode, offset));
1687: dest_addr = gen_rtx (PLUS, Pmode, dest_reg, gen_rtx (CONST_INT, VOIDmode, offset));
1688: }
1689:
1690: reg = gen_reg_rtx (mode);
1691: emit_insn ((*load_func) (reg, gen_rtx (MEM, mode, src_addr)));
1692: return (*store_func) (gen_rtx (MEM, mode, dest_addr), reg);
1693: }
1694:
1695:
1696: /* Write a series of loads/stores to move some bytes. Generate load/stores as follows:
1697:
1698: load 1
1699: load 2
1700: load 3
1701: store 1
1702: load 4
1703: store 2
1704: load 5
1705: store 3
1706: ...
1707:
1708: This way, no NOP's are needed, except at the end, and only
1709: two temp registers are needed. Two delay slots are used
1710: in deference to the R4000. */
1711:
1712: static void
1713: block_move_sequence (dest_reg, src_reg, bytes, align)
1714: rtx dest_reg; /* register holding destination address */
1715: rtx src_reg; /* register holding source address */
1716: int bytes; /* # bytes to move */
1717: int align; /* max alignment to assume */
1718: {
1719: int offset = 0;
1720: rtx prev2_store = (rtx)0;
1721: rtx prev_store = (rtx)0;
1722: rtx cur_store = (rtx)0;
1723:
1724: while (bytes > 0)
1725: {
1726: /* Is there a store to do? */
1727: if (prev2_store)
1728: emit_insn (prev2_store);
1729:
1730: prev2_store = prev_store;
1731: prev_store = cur_store;
1732: cur_store = block_move_load_store (dest_reg, src_reg, &bytes, &offset, align);
1733: }
1734:
1735: /* Finish up last three stores. */
1736: if (prev2_store)
1737: emit_insn (prev2_store);
1738:
1739: if (prev_store)
1740: emit_insn (prev_store);
1741:
1742: if (cur_store)
1743: emit_insn (cur_store);
1744: }
1745:
1746:
1747: /* Write a loop to move a constant number of bytes. Generate load/stores as follows:
1748:
1749: do {
1750: temp1 = src[0];
1751: temp2 = src[1];
1752: ...
1753: temp<last> = src[MAX_MOVE_REGS-1];
1754: src += MAX_MOVE_REGS;
1755: dest[0] = temp1;
1756: dest[1] = temp2;
1757: ...
1758: dest[MAX_MOVE_REGS-1] = temp<last>;
1759: dest += MAX_MOVE_REGS;
1760: } while (src != final);
1761:
1762: This way, no NOP's are needed, and only MAX_MOVE_REGS+3 temp
1763: registers are needed.
1764:
1765: Aligned moves move MAX_MOVE_REGS*4 bytes every (2*MAX_MOVE_REGS)+3
1766: cycles, unaligned moves move MAX_MOVE_REGS*4 bytes every
1767: (4*MAX_MOVE_REGS)+3 cycles, assuming no cache misses. */
1768:
1769: #define MAX_MOVE_REGS 4
1770: #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
1771:
1772: static void
1773: block_move_loop (dest_reg, src_reg, bytes, align)
1774: rtx dest_reg; /* register holding destination address */
1775: rtx src_reg; /* register holding source address */
1776: int bytes; /* # bytes to move */
1777: int align; /* alignment */
1778: {
1779: rtx stores[MAX_MOVE_REGS];
1780: rtx label;
1781: rtx final_src;
1782: rtx bytes_rtx;
1783: int i;
1784: int leftover;
1785: int offset;
1786:
1787: if (bytes < 2*MAX_MOVE_BYTES)
1788: abort ();
1789:
1790: leftover = bytes % MAX_MOVE_BYTES;
1791: bytes -= leftover;
1792:
1793: label = gen_label_rtx ();
1794: final_src = gen_reg_rtx (Pmode);
1795: bytes_rtx = gen_rtx (CONST_INT, VOIDmode, bytes);
1796:
1797: if (bytes > 0x7fff)
1798: {
1799: emit_insn (gen_movsi (final_src, bytes_rtx));
1800: emit_insn (gen_addsi3 (final_src, final_src, src_reg));
1801: }
1802: else
1803: emit_insn (gen_addsi3 (final_src, src_reg, bytes_rtx));
1804:
1805: emit_label (label);
1806:
1807: offset = 0;
1808: for (i = 0; i < MAX_MOVE_REGS; i++)
1809: stores[i] = block_move_load_store (dest_reg, src_reg, &bytes, &offset, align);
1810:
1811: emit_insn (gen_addsi3 (src_reg, src_reg, gen_rtx (CONST_INT, VOIDmode, MAX_MOVE_BYTES)));
1812: for (i = 0; i < MAX_MOVE_REGS; i++)
1813: emit_insn (stores[i]);
1814:
1815: emit_insn (gen_addsi3 (dest_reg, dest_reg, gen_rtx (CONST_INT, VOIDmode, MAX_MOVE_BYTES)));
1816: emit_insn (gen_cmpsi (src_reg, final_src));
1817: emit_jump_insn (gen_bne (label));
1818:
1819: if (leftover)
1820: block_move_sequence (dest_reg, src_reg, leftover, align);
1821: }
1822:
1823:
1824: /* Use a library function to move some bytes. */
1825:
1826: static void
1827: block_move_call (dest_reg, src_reg, bytes_rtx)
1828: rtx dest_reg;
1829: rtx src_reg;
1830: rtx bytes_rtx;
1831: {
1832: #ifdef TARGET_MEM_FUNCTIONS
1833: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0,
1834: VOIDmode, 3,
1835: dest_reg, Pmode,
1836: src_reg, Pmode,
1837: bytes_rtx, SImode);
1838: #else
1839: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), 0,
1840: VOIDmode, 3,
1841: src_reg, Pmode,
1842: dest_reg, Pmode,
1843: bytes_rtx, SImode);
1844: #endif
1845: }
1846:
1847:
1848: /* Expand string/block move operations.
1849:
1850: operands[0] is the pointer to the destination.
1851: operands[1] is the pointer to the source.
1852: operands[2] is the number of bytes to move.
1853: operands[3] is the alignment. */
1854:
1855: void
1856: expand_block_move (operands)
1857: rtx operands[];
1858: {
1859: rtx bytes_rtx = operands[2];
1860: int constp = (GET_CODE (bytes_rtx) == CONST_INT);
1861: int bytes = (constp ? INTVAL (bytes_rtx) : 0);
1862: int align = INTVAL (operands[3]);
1863: rtx src_reg;
1864: rtx dest_reg;
1865:
1866: if (constp && bytes <= 0)
1867: return;
1868:
1869: /* Move the address into scratch registers. */
1870: dest_reg = copy_addr_to_reg (XEXP (operands[0], 0));
1871: src_reg = copy_addr_to_reg (XEXP (operands[1], 0));
1872:
1873: if (TARGET_MEMCPY)
1874: block_move_call (dest_reg, src_reg, bytes_rtx);
1875:
1876: else if (constp && bytes <= 2*MAX_MOVE_BYTES)
1877: block_move_sequence (dest_reg, src_reg, bytes, align);
1878:
1879: else if (constp && align >= UNITS_PER_WORD && optimize)
1880: block_move_loop (dest_reg, src_reg, bytes, align);
1881:
1882: else if (constp && optimize)
1883: {
1884: /* If the alignment is not word aligned, generate a test at
1885: runtime, to see whether things wound up aligned, and we
1886: can use the faster lw/sw instead ulw/usw. */
1887:
1888: rtx temp = gen_reg_rtx (Pmode);
1889: rtx aligned_label = gen_label_rtx ();
1890: rtx join_label = gen_label_rtx ();
1891: int leftover = bytes % MAX_MOVE_BYTES;
1892:
1893: bytes -= leftover;
1894:
1895: emit_insn (gen_iorsi3 (temp, src_reg, dest_reg));
1896: emit_insn (gen_andsi3 (temp, temp, gen_rtx (CONST_INT, VOIDmode, UNITS_PER_WORD-1)));
1897: emit_insn (gen_cmpsi (temp, const0_rtx));
1898: emit_jump_insn (gen_beq (aligned_label));
1899:
1900: /* Unaligned loop. */
1901: block_move_loop (dest_reg, src_reg, bytes, 1);
1902: emit_jump_insn (gen_jump (join_label));
1903: emit_barrier ();
1904:
1905: /* Aligned loop. */
1906: emit_label (aligned_label);
1907: block_move_loop (dest_reg, src_reg, bytes, UNITS_PER_WORD);
1908: emit_label (join_label);
1909:
1910: /* Bytes at the end of the loop. */
1911: if (leftover)
1912: block_move_sequence (dest_reg, src_reg, leftover, align);
1913: }
1914:
1915: else
1916: block_move_call (dest_reg, src_reg, bytes_rtx);
1917: }
1918:
1919:
1920: /* Argument support functions. */
1921:
1922: /* Initialize CUMULATIVE_ARGS for a function. */
1923:
1924: void
1925: init_cumulative_args (cum, fntype, libname)
1926: CUMULATIVE_ARGS *cum; /* argument info to initialize */
1927: tree fntype; /* tree ptr for function decl */
1928: rtx libname; /* SYMBOL_REF of library name or 0 */
1929: {
1930: tree param, next_param;
1931:
1932: if (TARGET_DEBUG_E_MODE)
1933: fprintf (stderr, "\ninit_cumulative_args\n");
1934:
1935: cum->gp_reg_found = 0;
1936: cum->arg_number = 0;
1937: cum->arg_words = 0;
1938:
1939: /* Determine if this function has variable arguments. This is
1940: indicated by the last argument being 'void_type_mode' if there
1941: are no variable arguments. The standard MIPS calling sequence
1942: passes all arguments in the general purpose registers in this
1943: case. */
1944:
1945: for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0;
1946: param != (tree)0;
1947: param = next_param)
1948: {
1949: next_param = TREE_CHAIN (param);
1950: if (next_param == (tree)0 && TREE_VALUE (param) != void_type_node)
1951: cum->gp_reg_found = 1;
1952: }
1953:
1954: /* Determine if the function is returning a structure, if so,
1955: advance by one argument. */
1956:
1957: if (fntype
1958: && (TREE_CODE (fntype) == FUNCTION_TYPE || TREE_CODE (fntype) == METHOD_TYPE)
1959: && TREE_TYPE (fntype) != 0)
1960: {
1961: tree ret_type = TREE_TYPE (fntype);
1962: enum tree_code ret_code = TREE_CODE (ret_type);
1963:
1964: if (ret_code == RECORD_TYPE || ret_code == UNION_TYPE)
1965: {
1966: cum->gp_reg_found = 1;
1967: cum->arg_number = 1;
1968: cum->arg_words = 1;
1969: }
1970: }
1971: }
1972:
1973: /* Advance the argument to the next argument position. */
1974:
1975: void
1976: function_arg_advance (cum, mode, type, named)
1977: CUMULATIVE_ARGS *cum; /* current arg information */
1978: enum machine_mode mode; /* current arg mode */
1979: tree type; /* type of the argument or 0 if lib support */
1980: {
1981: if (TARGET_DEBUG_E_MODE)
1982: fprintf (stderr,
1983: "function_adv( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d )\n",
1984: cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode),
1985: type, named);
1986:
1987: cum->arg_number++;
1988: switch (mode)
1989: {
1990: default:
1991: error ("Illegal mode given to function_arg_advance");
1992: break;
1993:
1994: case VOIDmode:
1995: break;
1996:
1997: case BLKmode:
1998: cum->gp_reg_found = 1;
1999: cum->arg_words += (int_size_in_bytes (type) + 3) / 4;
2000: break;
2001:
2002: case SFmode:
2003: cum->arg_words++;
2004: break;
2005:
2006: case DFmode:
2007: cum->arg_words += 2;
2008: break;
2009:
2010: case DImode:
2011: cum->gp_reg_found = 1;
2012: cum->arg_words += 2;
2013: break;
2014:
2015: case QImode:
2016: case HImode:
2017: case SImode:
2018: cum->gp_reg_found = 1;
2019: cum->arg_words++;
2020: break;
2021: }
2022: }
2023:
2024: /* Return a RTL expression containing the register for the given mode,
2025: or 0 if the argument is too be passed on the stack. */
2026:
2027: struct rtx_def *
2028: function_arg (cum, mode, type, named)
2029: CUMULATIVE_ARGS *cum; /* current arg information */
2030: enum machine_mode mode; /* current arg mode */
2031: tree type; /* type of the argument or 0 if lib support */
2032: int named; /* != 0 for normal args, == 0 for ... args */
2033: {
2034: int regbase = -1;
2035: int bias = 0;
2036:
2037: if (TARGET_DEBUG_E_MODE)
2038: fprintf (stderr,
2039: "function_arg( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, 0x%.8x, %d ) = ",
2040: cum->gp_reg_found, cum->arg_number, cum->arg_words, GET_MODE_NAME (mode),
2041: type, named);
2042:
2043: switch (mode)
2044: {
2045: default:
2046: error ("Illegal mode given to function_arg");
2047: break;
2048:
2049: case SFmode:
2050: if (cum->gp_reg_found || cum->arg_number >= 2)
2051: regbase = GP_ARG_FIRST;
2052: else {
2053: regbase = (TARGET_SOFT_FLOAT) ? GP_ARG_FIRST : FP_ARG_FIRST;
2054: if (cum->arg_words == 1) /* first arg was float */
2055: bias = 1; /* use correct reg */
2056: }
2057:
2058: break;
2059:
2060: case DFmode:
2061: cum->arg_words += (cum->arg_words & 1);
2062: regbase = (cum->gp_reg_found || TARGET_SOFT_FLOAT)
2063: ? GP_ARG_FIRST
2064: : FP_ARG_FIRST;
2065: break;
2066:
2067: case VOIDmode:
2068: case BLKmode:
2069: case QImode:
2070: case HImode:
2071: case SImode:
2072: regbase = GP_ARG_FIRST;
2073: break;
2074:
2075: case DImode:
2076: cum->arg_words += (cum->arg_words & 1);
2077: regbase = GP_ARG_FIRST;
2078: }
2079:
2080: if (cum->arg_words >= MAX_ARGS_IN_REGISTERS)
2081: {
2082: if (TARGET_DEBUG_E_MODE)
2083: fprintf (stderr, "<stack>\n");
2084:
2085: return 0;
2086: }
2087:
2088: if (regbase == -1)
2089: abort ();
2090:
2091: if (TARGET_DEBUG_E_MODE)
2092: fprintf (stderr, "%s\n", reg_names[regbase + cum->arg_words + bias]);
2093:
2094: return gen_rtx (REG, mode, regbase + cum->arg_words + bias);
2095: }
2096:
2097:
2098: int
2099: function_arg_partial_nregs (cum, mode, type, named)
2100: CUMULATIVE_ARGS *cum; /* current arg information */
2101: enum machine_mode mode; /* current arg mode */
2102: tree type; /* type of the argument or 0 if lib support */
2103: int named; /* != 0 for normal args, == 0 for ... args */
2104: {
2105: if (mode == BLKmode && cum->arg_words < MAX_ARGS_IN_REGISTERS)
2106: {
2107: int words = (int_size_in_bytes (type) + 3) / 4;
2108:
2109: if (words + cum->arg_words < MAX_ARGS_IN_REGISTERS)
2110: return 0; /* structure fits in registers */
2111:
2112: if (TARGET_DEBUG_E_MODE)
2113: fprintf (stderr, "function_arg_partial_nregs = %d\n",
2114: MAX_ARGS_IN_REGISTERS - cum->arg_words);
2115:
2116: return MAX_ARGS_IN_REGISTERS - cum->arg_words;
2117: }
2118:
2119: else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS-1)
2120: {
2121: if (TARGET_DEBUG_E_MODE)
2122: fprintf (stderr, "function_arg_partial_nregs = 1\n");
2123:
2124: return 1;
2125: }
2126:
2127: return 0;
2128: }
2129:
2130:
2131: /* Print the options used in the assembly file. */
2132:
2133: static struct {char *name; int value;} target_switches []
2134: = TARGET_SWITCHES;
2135:
2136: void
2137: print_options (out)
2138: FILE *out;
2139: {
2140: int line_len;
2141: int len;
2142: int j;
2143: char **p;
2144: int mask = TARGET_DEFAULT;
2145:
2146: /* Allow assembly language comparisons with -mdebug eliminating the
2147: compiler version number and switch lists. */
2148:
2149: if (TARGET_DEBUG_MODE)
2150: return;
2151:
2152: fprintf (out, "\n # %s %s", language_string, version_string);
2153: #ifdef TARGET_VERSION_INTERNAL
2154: TARGET_VERSION_INTERNAL (out);
2155: #endif
2156: #ifdef __GNUC__
2157: fprintf (out, " compiled by GNU C\n\n");
2158: #else
2159: fprintf (out, " compiled by CC\n\n");
2160: #endif
2161:
2162: fprintf (out, " # Cc1 defaults:");
2163: line_len = 32767;
2164: for (j = 0; j < sizeof target_switches / sizeof target_switches[0]; j++)
2165: {
2166: if (target_switches[j].name[0] != '\0'
2167: && target_switches[j].value > 0
2168: && (target_switches[j].value & mask) == target_switches[j].value)
2169: {
2170: mask &= ~ target_switches[j].value;
2171: len = strlen (target_switches[j].name) + 1;
2172: if (len + line_len > 79)
2173: {
2174: line_len = 2;
2175: fputs ("\n #", out);
2176: }
2177: fprintf (out, " -m%s", target_switches[j].name);
2178: line_len += len;
2179: }
2180: }
2181:
2182: fprintf (out, "\n\n # Cc1 arguments (-G value = %d, Cpu = %s, ISA = %d):",
2183: mips_section_threshold, mips_cpu_string, mips_isa);
2184:
2185: line_len = 32767;
2186: for (p = &save_argv[1]; *p != (char *)0; p++)
2187: {
2188: char *arg = *p;
2189: if (*arg == '-')
2190: {
2191: len = strlen (arg) + 1;
2192: if (len + line_len > 79)
2193: {
2194: line_len = 2;
2195: fputs ("\n #", out);
2196: }
2197: fprintf (out, " %s", *p);
2198: line_len += len;
2199: }
2200: }
2201:
2202: fputs ("\n\n", out);
2203: }
2204:
2205:
2206: /* Abort after printing out a specific insn. */
2207:
2208: void
2209: abort_with_insn (insn, reason)
2210: rtx insn;
2211: char *reason;
2212: {
2213: error (reason);
2214: debug_rtx (insn);
2215: abort ();
2216: }
2217:
2218: /* Write a message to stderr (for use in macros expanded in files that do not
2219: include stdio.h). */
2220:
2221: void
2222: trace (s, s1, s2)
2223: char *s, *s1, *s2;
2224: {
2225: fprintf (stderr, s, s1, s2);
2226: }
2227:
2228:
2229: #ifdef SIGINFO
2230:
2231: #include <sys/wait.h>
2232:
2233: static void
2234: siginfo (signo)
2235: int signo;
2236: {
2237: char print_pid[50];
2238: char *argv[4];
2239: pid_t pid;
2240: int status;
2241:
2242: fprintf (stderr, "compiling '%s' in '%s'\n",
2243: (current_function_name != (char *)0) ? current_function_name : "<toplevel>",
2244: (current_function_file != (char *)0) ? current_function_file : "<no file>");
2245:
2246: /* Spawn a ps to tell about current memory usage, etc. */
2247: sprintf (print_pid, "-p%d,%d", getpid (), getppid ());
2248: argv[0] = "ps";
2249: argv[1] = print_pid;
2250: argv[2] = "-ouser,state,pid,pri,nice,wchan,tt,start,usertime,systime,pcpu,cp,inblock,oublock,vsize,rss,pmem,ucomm";
2251: argv[3] = (char *)0;
2252:
2253: pid = vfork ();
2254: if (pid == 0) /* child context */
2255: {
2256: execv ("/usr/bin/ps", argv);
2257: execv ("/usr/sbin/ps", argv);
2258: execvp ("ps", argv);
2259: perror ("ps");
2260: _exit (1);
2261: }
2262:
2263: else if (pid > 0) /* parent context */
2264: {
2265: void (*sigint)(int) = signal (SIGINT, SIG_IGN);
2266: void (*sigquit)(int) = signal (SIGQUIT, SIG_IGN);
2267:
2268: (void) waitpid (pid, &status, 0);
2269:
2270: (void) signal (SIGINT, sigint);
2271: (void) signal (SIGQUIT, sigquit);
2272: }
2273:
2274: signal (SIGINFO, siginfo);
2275: }
2276:
2277: #endif /* SIGINFO */
2278:
2279:
2280: /* Set up the threshold for data to go into the small data area, instead
2281: of the normal data area, and detect any conflicts in the switches. */
2282:
2283: void
2284: override_options ()
2285: {
2286: register int i, start;
2287: register int regno;
2288: register enum machine_mode mode;
2289:
2290: if (g_switch_set)
2291: mips_section_threshold = g_switch_value;
2292:
2293: else
2294: mips_section_threshold = (TARGET_MIPS_AS) ? 8 : 0;
2295:
2296: /* Identify the processor type */
2297: if (mips_cpu_string == (char *)0
2298: || !strcmp (mips_cpu_string, "default")
2299: || !strcmp (mips_cpu_string, "DEFAULT"))
2300: {
2301: mips_cpu_string = "default";
2302: mips_cpu = PROCESSOR_DEFAULT;
2303: }
2304:
2305: else
2306: {
2307: char *p = mips_cpu_string;
2308:
2309: if (*p == 'r' || *p == 'R')
2310: p++;
2311:
2312: /* Since there is no difference between a R2000 and R3000 in
2313: terms of the scheduler, we collapse them into just an R3000. */
2314:
2315: mips_cpu = PROCESSOR_DEFAULT;
2316: switch (*p)
2317: {
2318: case '2':
2319: if (!strcmp (p, "2000") || !strcmp (p, "2k") || !strcmp (p, "2K"))
2320: mips_cpu = PROCESSOR_R3000;
2321: break;
2322:
2323: case '3':
2324: if (!strcmp (p, "3000") || !strcmp (p, "3k") || !strcmp (p, "3K"))
2325: mips_cpu = PROCESSOR_R3000;
2326: break;
2327:
2328: case '4':
2329: if (!strcmp (p, "4000") || !strcmp (p, "4k") || !strcmp (p, "4K"))
2330: mips_cpu = PROCESSOR_R4000;
2331: break;
2332:
2333: case '6':
2334: if (!strcmp (p, "6000") || !strcmp (p, "6k") || !strcmp (p, "6K"))
2335: mips_cpu = PROCESSOR_R6000;
2336: break;
2337: }
2338:
2339: if (mips_cpu == PROCESSOR_DEFAULT)
2340: {
2341: error ("bad value (%s) for -mcpu= switch", mips_cpu_string);
2342: mips_cpu_string = "default";
2343: }
2344: }
2345:
2346: /* Now get the architectural level. */
2347: if (mips_isa_string == (char *)0)
2348: mips_isa = 1;
2349:
2350: else if (isdigit (*mips_isa_string))
2351: mips_isa = atoi (mips_isa_string);
2352:
2353: else
2354: {
2355: error ("bad value (%s) for -mips switch", mips_isa_string);
2356: mips_isa = 1;
2357: }
2358:
2359: if (mips_isa < 0 || mips_isa > 3)
2360: error ("-mips%d not supported", mips_isa);
2361:
2362: else if (mips_isa > 1
2363: && (mips_cpu == PROCESSOR_DEFAULT || mips_cpu == PROCESSOR_R3000))
2364: error ("-mcpu=%s does not support -mips%d", mips_cpu_string, mips_isa);
2365:
2366: else if (mips_cpu == PROCESSOR_R6000 && mips_isa > 2)
2367: error ("-mcpu=%s does not support -mips%d", mips_cpu_string, mips_isa);
2368:
2369: /* make sure sizes of ints/longs/etc. are ok */
2370: if (mips_isa < 3)
2371: {
2372: if (TARGET_INT64)
2373: fatal ("Only the r4000 can support 64 bit ints");
2374:
2375: else if (TARGET_LONG64)
2376: fatal ("Only the r4000 can support 64 bit longs");
2377:
2378: else if (TARGET_LLONG128)
2379: fatal ("Only the r4000 can support 128 bit long longs");
2380:
2381: else if (TARGET_FLOAT64)
2382: fatal ("Only the r4000 can support 64 bit fp registers");
2383: }
2384: else if (TARGET_INT64 || TARGET_LONG64 || TARGET_LLONG128 || TARGET_FLOAT64)
2385: warning ("r4000 64/128 bit types not yet supported");
2386:
2387: /* Tell halfpic.c that we have half-pic code if we do. */
2388: if (TARGET_HALF_PIC)
2389: HALF_PIC_INIT ();
2390:
2391: /* -mrnames says to use the MIPS software convention for register
2392: names instead of the hardware names (ie, a0 instead of $4).
2393: We do this by switching the names in mips_reg_names, which the
2394: reg_names points into via the REGISTER_NAMES macro. */
2395:
2396: if (TARGET_NAME_REGS)
2397: {
2398: if (TARGET_GAS)
2399: {
2400: target_flags &= ~ MASK_NAME_REGS;
2401: error ("Gas does not support the MIPS software register name convention.");
2402: }
2403: else
2404: bcopy ((char *) mips_sw_reg_names, (char *) mips_reg_names, sizeof (mips_reg_names));
2405: }
2406:
2407: /* If this is OSF/1, set up a SIGINFO handler so we can see what function
2408: is currently being compiled. */
2409: #ifdef SIGINFO
2410: if (getenv ("GCC_SIGINFO") != (char *)0)
2411: {
2412: struct sigaction action;
2413: action.sa_handler = siginfo;
2414: action.sa_mask = 0;
2415: action.sa_flags = SA_RESTART;
2416: sigaction (SIGINFO, &action, (struct sigaction *)0);
2417: }
2418: #endif
2419:
2420: /* Set up the classificaiton arrays now. */
2421: mips_rtx_classify[(int)PLUS] = CLASS_ADD_OP;
2422: mips_rtx_classify[(int)MINUS] = CLASS_ADD_OP;
2423: mips_rtx_classify[(int)DIV] = CLASS_DIVMOD_OP;
2424: mips_rtx_classify[(int)MOD] = CLASS_DIVMOD_OP;
2425: mips_rtx_classify[(int)UDIV] = CLASS_DIVMOD_OP | CLASS_UNSIGNED_OP;
2426: mips_rtx_classify[(int)UMOD] = CLASS_DIVMOD_OP | CLASS_UNSIGNED_OP;
2427: mips_rtx_classify[(int)EQ] = CLASS_CMP_OP | CLASS_EQUALITY_OP | CLASS_FCMP_OP;
2428: mips_rtx_classify[(int)NE] = CLASS_CMP_OP | CLASS_EQUALITY_OP | CLASS_FCMP_OP;
2429: mips_rtx_classify[(int)GT] = CLASS_CMP_OP | CLASS_FCMP_OP;
2430: mips_rtx_classify[(int)GE] = CLASS_CMP_OP | CLASS_FCMP_OP;
2431: mips_rtx_classify[(int)LT] = CLASS_CMP_OP | CLASS_FCMP_OP;
2432: mips_rtx_classify[(int)LE] = CLASS_CMP_OP | CLASS_FCMP_OP;
2433: mips_rtx_classify[(int)GTU] = CLASS_CMP_OP | CLASS_UNSIGNED_OP;
2434: mips_rtx_classify[(int)GEU] = CLASS_CMP_OP | CLASS_UNSIGNED_OP;
2435: mips_rtx_classify[(int)LTU] = CLASS_CMP_OP | CLASS_UNSIGNED_OP;
2436: mips_rtx_classify[(int)LEU] = CLASS_CMP_OP | CLASS_UNSIGNED_OP;
2437:
2438: mips_print_operand_punct['?'] = TRUE;
2439: mips_print_operand_punct['#'] = TRUE;
2440: mips_print_operand_punct['&'] = TRUE;
2441: mips_print_operand_punct['!'] = TRUE;
2442: mips_print_operand_punct['*'] = TRUE;
2443: mips_print_operand_punct['@'] = TRUE;
2444: mips_print_operand_punct['.'] = TRUE;
2445: mips_print_operand_punct['('] = TRUE;
2446: mips_print_operand_punct[')'] = TRUE;
2447: mips_print_operand_punct['['] = TRUE;
2448: mips_print_operand_punct[']'] = TRUE;
2449: mips_print_operand_punct['<'] = TRUE;
2450: mips_print_operand_punct['>'] = TRUE;
2451: mips_print_operand_punct['{'] = TRUE;
2452: mips_print_operand_punct['}'] = TRUE;
2453:
2454: mips_char_to_class['d'] = GR_REGS;
2455: mips_char_to_class['f'] = ((TARGET_HARD_FLOAT) ? FP_REGS : NO_REGS);
2456: mips_char_to_class['h'] = HI_REG;
2457: mips_char_to_class['l'] = LO_REG;
2458: mips_char_to_class['s'] = ST_REGS;
2459: mips_char_to_class['x'] = MD_REGS;
2460: mips_char_to_class['y'] = GR_REGS;
2461:
2462: /* Set up array to map GCC register number to debug register number.
2463: Ignore the special purpose register numbers. */
2464:
2465: for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
2466: mips_dbx_regno[i] = -1;
2467:
2468: start = GP_DBX_FIRST - GP_REG_FIRST;
2469: for (i = GP_REG_FIRST; i <= GP_REG_LAST; i++)
2470: mips_dbx_regno[i] = i + start;
2471:
2472: start = FP_DBX_FIRST - FP_REG_FIRST;
2473: for (i = FP_REG_FIRST; i <= FP_REG_LAST; i++)
2474: mips_dbx_regno[i] = i + start;
2475:
2476: /* Set up array giving whether a given register can hold a given mode.
2477: At present, restrict ints from being in FP registers, because reload
2478: is a little enthusiastic about storing extra values in FP registers,
2479: and this is not good for things like OS kernels. Also, due to the
2480: manditory delay, it is as fast to load from cached memory as to move
2481: from the FP register. */
2482:
2483: for (mode = VOIDmode;
2484: mode != MAX_MACHINE_MODE;
2485: mode = (enum machine_mode)((int)mode + 1))
2486: {
2487: register int size = GET_MODE_SIZE (mode);
2488: register enum mode_class class = GET_MODE_CLASS (mode);
2489:
2490: for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
2491: {
2492: register int temp = FALSE;
2493:
2494: if (GP_REG_P (regno))
2495: temp = ((regno & 1) == 0 || (size <= UNITS_PER_WORD));
2496:
2497: else if (FP_REG_P (regno))
2498: temp = ((TARGET_FLOAT64 || ((regno & 1) == 0))
2499: && (TARGET_DEBUG_H_MODE
2500: || class == MODE_FLOAT
2501: || class == MODE_COMPLEX_FLOAT));
2502:
2503: else if (MD_REG_P (regno))
2504: temp = (mode == SImode || (regno == MD_REG_FIRST && mode == DImode));
2505:
2506: else if (ST_REG_P (regno))
2507: temp = ((mode == SImode) || (class == MODE_CC));
2508:
2509: mips_hard_regno_mode_ok[(int)mode][regno] = temp;
2510: }
2511: }
2512: }
2513:
2514:
2515: /*
2516: * If the frame pointer has been eliminated, the offset for an auto
2517: * or argument will be based on the stack pointer. But this is not
2518: * what the debugger expects--it needs to find an offset off of the
2519: * frame pointer (whether it exists or not). So here we turn all
2520: * offsets into those based on the (possibly virtual) frame pointer.
2521: */
2522:
2523: int
2524: mips_debugger_offset (addr, offset)
2525: rtx addr;
2526: int offset;
2527: {
2528: int offset2 = 0;
2529: rtx reg = eliminate_constant_term (addr, &offset2);
2530:
2531: if (!offset)
2532: offset = offset2;
2533:
2534: if (reg == stack_pointer_rtx)
2535: {
2536: int frame_size = (!current_frame_info.initialized)
2537: ? compute_frame_size (get_frame_size ())
2538: : current_frame_info.total_size;
2539:
2540: offset = offset - frame_size;
2541: }
2542:
2543: /* Any other register is, we hope, either the frame pointer,
2544: or a pseudo equivalent to the frame pointer. (Assign_parms
2545: copies the arg pointer to a pseudo if ARG_POINTER_REGNUM is
2546: equal to FRAME_POINTER_REGNUM, so references off of the
2547: arg pointer are all off a pseudo.) Seems like all we can
2548: do is to just return OFFSET and hope for the best. */
2549:
2550: return offset;
2551: }
2552:
2553: /* A C compound statement to output to stdio stream STREAM the
2554: assembler syntax for an instruction operand X. X is an RTL
2555: expression.
2556:
2557: CODE is a value that can be used to specify one of several ways
2558: of printing the operand. It is used when identical operands
2559: must be printed differently depending on the context. CODE
2560: comes from the `%' specification that was used to request
2561: printing of the operand. If the specification was just `%DIGIT'
2562: then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2563: is the ASCII code for LTR.
2564:
2565: If X is a register, this macro should print the register's name.
2566: The names can be found in an array `reg_names' whose type is
2567: `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2568:
2569: When the machine description has a specification `%PUNCT' (a `%'
2570: followed by a punctuation character), this macro is called with
2571: a null pointer for X and the punctuation character for CODE.
2572:
2573: The MIPS specific codes are:
2574:
2575: 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
2576: 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
2577: 'd' output integer constant in decimal,
2578: 'z' if the operand is 0, use $0 instead of normal operand.
2579: 'D' print second register of double-word register operand.
2580: 'L' print low-order register of double-word register operand.
2581: 'M' print high-order register of double-word register operand.
2582: 'C' print part of opcode for a branch condition.
2583: 'N' print part of opcode for a branch condition, inverted.
2584: '(' Turn on .set noreorder
2585: ')' Turn on .set reorder
2586: '[' Turn on .set noat
2587: ']' Turn on .set at
2588: '<' Turn on .set nomacro
2589: '>' Turn on .set macro
2590: '{' Turn on .set volatile (not GAS)
2591: '}' Turn on .set novolatile (not GAS)
2592: '&' Turn on .set noreorder if filling delay slots
2593: '*' Turn on both .set noreorder and .set nomacro if filling delay slots
2594: '!' Turn on .set nomacro if filling delay slots
2595: '#' Print nop if in a .set noreorder section.
2596: '?' Print 'l' if we are to use a branch likely instead of normal branch.
2597: '@' Print the name of the assembler temporary register (at or $1).
2598: '.' Print the name of the register with a hard-wired zero (zero or $0). */
2599:
2600: void
2601: print_operand (file, op, letter)
2602: FILE *file; /* file to write to */
2603: rtx op; /* operand to print */
2604: int letter; /* %<letter> or 0 */
2605: {
2606: register enum rtx_code code;
2607:
2608: if (PRINT_OPERAND_PUNCT_VALID_P (letter))
2609: {
2610: switch (letter)
2611: {
2612: default:
2613: error ("PRINT_OPERAND: Unknown punctuation '%c'", letter);
2614: break;
2615:
2616: case '?':
2617: if (mips_branch_likely)
2618: putc ('l', file);
2619: break;
2620:
2621: case '@':
2622: fputs (reg_names [GP_REG_FIRST + 1], file);
2623: break;
2624:
2625: case '.':
2626: fputs (reg_names [GP_REG_FIRST + 0], file);
2627: break;
2628:
2629: case '&':
2630: if (final_sequence != 0 && set_noreorder++ == 0)
2631: fputs (".set\tnoreorder\n\t", file);
2632: break;
2633:
2634: case '*':
2635: if (final_sequence != 0)
2636: {
2637: if (set_noreorder++ == 0)
2638: fputs (".set\tnoreorder\n\t", file);
2639:
2640: if (set_nomacro++ == 0)
2641: fputs (".set\tnomacro\n\t", file);
2642: }
2643: break;
2644:
2645: case '!':
2646: if (final_sequence != 0 && set_nomacro++ == 0)
2647: fputs ("\n\t.set\tnomacro", file);
2648: break;
2649:
2650: case '#':
2651: if (set_noreorder != 0)
2652: fputs ("\n\tnop", file);
2653:
2654: else if (TARGET_GAS || TARGET_STATS)
2655: fputs ("\n\t#nop", file);
2656:
2657: break;
2658:
2659: case '(':
2660: if (set_noreorder++ == 0)
2661: fputs (".set\tnoreorder\n\t", file);
2662: break;
2663:
2664: case ')':
2665: if (set_noreorder == 0)
2666: error ("internal error: %%) found without a %%( in assembler pattern");
2667:
2668: else if (--set_noreorder == 0)
2669: fputs ("\n\t.set\treorder", file);
2670:
2671: break;
2672:
2673: case '[':
2674: if (set_noat++ == 0)
2675: fputs (".set\tnoat\n\t", file);
2676: break;
2677:
2678: case ']':
2679: if (set_noat == 0)
2680: error ("internal error: %%] found without a %%[ in assembler pattern");
2681:
2682: else if (--set_noat == 0)
2683: fputs ("\n\t.set\tat", file);
2684:
2685: break;
2686:
2687: case '<':
2688: if (set_nomacro++ == 0)
2689: fputs (".set\tnomacro\n\t", file);
2690: break;
2691:
2692: case '>':
2693: if (set_nomacro == 0)
2694: error ("internal error: %%> found without a %%< in assembler pattern");
2695:
2696: else if (--set_nomacro == 0)
2697: fputs ("\n\t.set\tmacro", file);
2698:
2699: break;
2700:
2701: case '{':
2702: if (set_volatile++ == 0)
2703: fprintf (file, "%s.set\tvolatile\n\t", (TARGET_MIPS_AS) ? "" : "#");
2704: break;
2705:
2706: case '}':
2707: if (set_volatile == 0)
2708: error ("internal error: %%} found without a %%{ in assembler pattern");
2709:
2710: else if (--set_volatile == 0)
2711: fprintf (file, "\n\t%s.set\tnovolatile", (TARGET_MIPS_AS) ? "" : "#");
2712:
2713: break;
2714: }
2715: return;
2716: }
2717:
2718: if (! op)
2719: {
2720: error ("PRINT_OPERAND null pointer");
2721: return;
2722: }
2723:
2724: code = GET_CODE (op);
2725: if (letter == 'C')
2726: switch (code)
2727: {
2728: case EQ: fputs ("eq", file); break;
2729: case NE: fputs ("ne", file); break;
2730: case GT: fputs ("gt", file); break;
2731: case GE: fputs ("ge", file); break;
2732: case LT: fputs ("lt", file); break;
2733: case LE: fputs ("le", file); break;
2734: case GTU: fputs ("gtu", file); break;
2735: case GEU: fputs ("geu", file); break;
2736: case LTU: fputs ("ltu", file); break;
2737: case LEU: fputs ("leu", file); break;
2738:
2739: default:
2740: abort_with_insn (op, "PRINT_OPERAND, illegal insn for %%C");
2741: }
2742:
2743: else if (letter == 'N')
2744: switch (code)
2745: {
2746: case EQ: fputs ("ne", file); break;
2747: case NE: fputs ("eq", file); break;
2748: case GT: fputs ("le", file); break;
2749: case GE: fputs ("lt", file); break;
2750: case LT: fputs ("ge", file); break;
2751: case LE: fputs ("gt", file); break;
2752: case GTU: fputs ("leu", file); break;
2753: case GEU: fputs ("ltu", file); break;
2754: case LTU: fputs ("geu", file); break;
2755: case LEU: fputs ("gtu", file); break;
2756:
2757: default:
2758: abort_with_insn (op, "PRINT_OPERAND, illegal insn for %%N");
2759: }
2760:
2761: else if (code == REG)
2762: {
2763: register int regnum = REGNO (op);
2764:
2765: if (letter == 'M')
2766: regnum += MOST_SIGNIFICANT_WORD;
2767:
2768: else if (letter == 'L')
2769: regnum += LEAST_SIGNIFICANT_WORD;
2770:
2771: else if (letter == 'D')
2772: regnum++;
2773:
2774: fprintf (file, "%s", reg_names[regnum]);
2775: }
2776:
2777: else if (code == MEM)
2778: output_address (XEXP (op, 0));
2779:
2780: else if (code == CONST_DOUBLE)
2781: {
2782: #if HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
2783: union { double d; int i[2]; } u;
2784: u.i[0] = CONST_DOUBLE_LOW (op);
2785: u.i[1] = CONST_DOUBLE_HIGH (op);
2786: if (GET_MODE (op) == SFmode)
2787: {
2788: float f;
2789: f = u.d;
2790: u.d = f;
2791: }
2792: fprintf (file, "%.20e", u.d);
2793: #else
2794: fatal ("CONST_DOUBLE found in cross compilation");
2795: #endif
2796: }
2797:
2798: else if ((letter == 'x') && (GET_CODE(op) == CONST_INT))
2799: fprintf (file, "0x%04x", 0xffff & (INTVAL(op)));
2800:
2801: else if ((letter == 'X') && (GET_CODE(op) == CONST_INT))
2802: fprintf (file, "0x%08x", INTVAL(op));
2803:
2804: else if ((letter == 'd') && (GET_CODE(op) == CONST_INT))
2805: fprintf (file, "%d", (INTVAL(op)));
2806:
2807: else if (letter == 'z'
2808: && (GET_CODE (op) == CONST_INT)
2809: && INTVAL (op) == 0)
2810: fputs (reg_names[GP_REG_FIRST], file);
2811:
2812: else if (letter == 'd' || letter == 'x' || letter == 'X')
2813: fatal ("PRINT_OPERAND: letter %c was found & insn was not CONST_INT", letter);
2814:
2815: else
2816: output_addr_const (file, op);
2817: }
2818:
2819:
2820: /* A C compound statement to output to stdio stream STREAM the
2821: assembler syntax for an instruction operand that is a memory
2822: reference whose address is ADDR. ADDR is an RTL expression.
2823:
2824: On some machines, the syntax for a symbolic address depends on
2825: the section that the address refers to. On these machines,
2826: define the macro `ENCODE_SECTION_INFO' to store the information
2827: into the `symbol_ref', and then check for it here. */
2828:
2829: void
2830: print_operand_address (file, addr)
2831: FILE *file;
2832: rtx addr;
2833: {
2834: if (!addr)
2835: error ("PRINT_OPERAND_ADDRESS, null pointer");
2836:
2837: else
2838: switch (GET_CODE (addr))
2839: {
2840: default:
2841: abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, illegal insn #1");
2842: break;
2843:
2844: case REG:
2845: fprintf (file, "0(%s)", reg_names [REGNO (addr)]);
2846: break;
2847:
2848: case PLUS:
2849: {
2850: register rtx reg = (rtx)0;
2851: register rtx offset = (rtx)0;
2852: register rtx arg0 = XEXP (addr, 0);
2853: register rtx arg1 = XEXP (addr, 1);
2854:
2855: if (GET_CODE (arg0) == REG)
2856: {
2857: reg = arg0;
2858: offset = arg1;
2859: if (GET_CODE (offset) == REG)
2860: abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, 2 regs");
2861: }
2862: else if (GET_CODE (arg1) == REG)
2863: {
2864: reg = arg1;
2865: offset = arg0;
2866: }
2867: else if (CONSTANT_P (arg0) && CONSTANT_P (arg1))
2868: {
2869: output_addr_const (file, addr);
2870: break;
2871: }
2872: else
2873: abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, no regs");
2874:
2875: if (!CONSTANT_P (offset))
2876: abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, illegal insn #2");
2877:
2878: output_addr_const (file, offset);
2879: fprintf (file, "(%s)", reg_names [REGNO (reg)]);
2880: }
2881: break;
2882:
2883: case LABEL_REF:
2884: case SYMBOL_REF:
2885: case CONST_INT:
2886: case CONST:
2887: output_addr_const (file, addr);
2888: break;
2889: }
2890: }
2891:
2892:
2893: /* If optimizing for the global pointer, keep track of all of
2894: the externs, so that at the end of the file, we can emit
2895: the appropriate .extern declaration for them, before writing
2896: out the text section. We assume that all names passed to
2897: us are in the permanent obstack, so that they will be valid
2898: at the end of the compilation.
2899:
2900: If we have -G 0, or the extern size is unknown, don't bother
2901: emitting the .externs. */
2902:
2903: int
2904: mips_output_external (file, decl, name)
2905: FILE *file;
2906: tree decl;
2907: char *name;
2908: {
2909: register struct extern_list *p;
2910: int len;
2911:
2912: if (TARGET_GP_OPT
2913: && mips_section_threshold != 0
2914: && ((TREE_CODE (decl)) != FUNCTION_DECL)
2915: && ((len = int_size_in_bytes (TREE_TYPE (decl))) > 0))
2916: {
2917: p = (struct extern_list *)permalloc ((long) sizeof (struct extern_list));
2918: p->next = extern_head;
2919: p->name = name;
2920: p->size = len;
2921: extern_head = p;
2922: }
2923: return 0;
2924: }
2925:
2926:
2927: /* Compute a string to use as a temporary file name. */
2928:
2929: static FILE *
2930: make_temp_file ()
2931: {
2932: FILE *stream;
2933: char *base = getenv ("TMPDIR");
2934: int len;
2935:
2936: if (base == (char *)0)
2937: {
2938: #ifdef P_tmpdir
2939: if (access (P_tmpdir, R_OK | W_OK) == 0)
2940: base = P_tmpdir;
2941: else
2942: #endif
2943: if (access ("/usr/tmp", R_OK | W_OK) == 0)
2944: base = "/usr/tmp/";
2945: else
2946: base = "/tmp/";
2947: }
2948:
2949: len = strlen (base);
2950: temp_filename = (char *) alloca (len + sizeof("/ccXXXXXX"));
2951: strcpy (temp_filename, base);
2952: if (len > 0 && temp_filename[len-1] != '/')
2953: temp_filename[len++] = '/';
2954:
2955: strcpy (temp_filename + len, "ccXXXXXX");
2956: mktemp (temp_filename);
2957:
2958: stream = fopen (temp_filename, "w+");
2959: if (!stream)
2960: pfatal_with_name (temp_filename);
2961:
2962: unlink (temp_filename);
2963: return stream;
2964: }
2965:
2966:
2967: /* Emit a new filename to a stream. If this is MIPS ECOFF, watch out
2968: for .file's that start within a function. If we are smuggling stabs, try to
2969: put out a MIPS ECOFF file and a stab. */
2970:
2971: void
2972: mips_output_filename (stream, name)
2973: FILE *stream;
2974: char *name;
2975: {
2976: static int first_time = TRUE;
2977: char ltext_label_name[100];
2978:
2979: if (first_time)
2980: {
2981: first_time = FALSE;
2982: SET_FILE_NUMBER ();
2983: current_function_file = name;
2984: fprintf (stream, "\t.file\t%d \"%s\"\n", num_source_filenames, name);
2985: }
2986:
2987: else if (!TARGET_GAS && write_symbols == DBX_DEBUG)
2988: {
2989: ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", 0);
2990: fprintf (stream, "%s \"%s\",%d,0,0,%s\n", ASM_STABS_OP,
2991: name, N_SOL, <ext_label_name[1]);
2992: }
2993:
2994: else if (name != current_function_file
2995: && strcmp (name, current_function_file) != 0)
2996: {
2997: if (inside_function && !TARGET_GAS)
2998: {
2999: if (!file_in_function_warning)
3000: {
3001: file_in_function_warning = TRUE;
3002: ignore_line_number = TRUE;
3003: warning ("MIPS ECOFF format does not allow changing filenames within functions with #line");
3004: }
3005:
3006: fprintf (stream, "\t#.file\t%d \"%s\"\n", num_source_filenames, name);
3007: }
3008:
3009: else
3010: {
3011: SET_FILE_NUMBER ();
3012: current_function_file = name;
3013: fprintf (stream, "\t.file\t%d \"%s\"\n", num_source_filenames, name);
3014: }
3015: }
3016: }
3017:
3018:
3019: /* Emit a linenumber. For encapsulated stabs, we need to put out a stab
3020: as well as a .loc, since it is possible that MIPS ECOFF might not be
3021: able to represent the location for inlines that come from a different
3022: file. */
3023:
3024: void
3025: mips_output_lineno (stream, line)
3026: FILE *stream;
3027: int line;
3028: {
3029: if (!TARGET_GAS && write_symbols == DBX_DEBUG)
3030: {
3031: ++sym_lineno;
3032: fprintf (stream, "$LM%d:\n\t%s %d,0,%d,$LM%d\n",
3033: sym_lineno, ASM_STABN_OP, N_SLINE, line, sym_lineno);
3034: }
3035:
3036: else
3037: {
3038: fprintf (stream, "\n\t%s.loc\t%d %d\n",
3039: (ignore_line_number) ? "#" : "",
3040: num_source_filenames, line);
3041:
3042: LABEL_AFTER_LOC (stream);
3043: }
3044: }
3045:
3046:
3047: /* Output at beginning of assembler file.
3048: If we are optimizing to use the global pointer, create a temporary
3049: file to hold all of the text stuff, and write it out to the end.
3050: This is needed because the MIPS assembler is evidently one pass,
3051: and if it hasn't seen the relevant .comm/.lcomm/.extern/.sdata
3052: declaration when the code is processed, it generates a two
3053: instruction sequence. */
3054:
3055: void
3056: mips_asm_file_start (stream)
3057: FILE *stream;
3058: {
3059: ASM_OUTPUT_SOURCE_FILENAME (stream, main_input_filename);
3060:
3061: /* Versions of the MIPS assembler before 2.20 generate errors
3062: if a branch inside of a .set noreorder section jumps to a
3063: label outside of the .set noreorder section. Revision 2.20
3064: just set nobopt silently rather than fixing the bug. */
3065:
3066: if (TARGET_MIPS_AS && optimize && flag_delayed_branch)
3067: fprintf (stream, "\t.set\tnobopt\n");
3068:
3069: /* Generate the pseudo ops that the Pyramid based System V.4 wants. */
3070: if (TARGET_ABICALLS)
3071: fprintf (stream, "\t.abicalls\n");
3072:
3073: /* put gcc_compiled. in data, not text */
3074: data_section ();
3075:
3076: if (TARGET_GP_OPT)
3077: {
3078: asm_out_data_file = stream;
3079: asm_out_text_file = make_temp_file ();
3080: }
3081: else
3082: asm_out_data_file = asm_out_text_file = stream;
3083:
3084: if (TARGET_NAME_REGS)
3085: fprintf (asm_out_file, "#include <regdef.h>\n");
3086:
3087: print_options (stream);
3088: }
3089:
3090:
3091: /* If we are optimizing the global pointer, emit the text section now
3092: and any small externs which did not have .comm, etc that are
3093: needed. Also, give a warning if the data area is more than 32K and
3094: -pic because 3 instructions are needed to reference the data
3095: pointers. */
3096:
3097: void
3098: mips_asm_file_end (file)
3099: FILE *file;
3100: {
3101: char buffer[8192];
3102: tree name_tree;
3103: struct extern_list *p;
3104: int len;
3105:
3106: if (TARGET_GP_OPT)
3107: {
3108: if (extern_head)
3109: fputs ("\n", file);
3110:
3111: for (p = extern_head; p != 0; p = p->next)
3112: {
3113: name_tree = get_identifier (p->name);
3114: if (!TREE_ADDRESSABLE (name_tree))
3115: {
3116: TREE_ADDRESSABLE (name_tree) = 1;
3117: fputs ("\t.extern\t", file);
3118: assemble_name (file, p->name);
3119: fprintf (file, ", %d\n", p->size);
3120: }
3121: }
3122:
3123: fprintf (file, "\n\t.text\n");
3124: rewind (asm_out_text_file);
3125: if (ferror (asm_out_text_file))
3126: fatal_io_error (temp_filename);
3127:
3128: while ((len = fread (buffer, 1, sizeof (buffer), asm_out_text_file)) > 0)
3129: if (fwrite (buffer, 1, len, file) != len)
3130: pfatal_with_name (asm_file_name);
3131:
3132: if (len < 0)
3133: pfatal_with_name (temp_filename);
3134:
3135: if (fclose (asm_out_text_file) != 0)
3136: pfatal_with_name (temp_filename);
3137: }
3138: }
3139:
3140:
3141: /* Return the bytes needed to compute the frame pointer from the current
3142: stack pointer.
3143:
3144: Mips stack frames look like:
3145:
3146: Before call After call
3147: +-----------------------+ +-----------------------+
3148: high | | | |
3149: mem. | | | |
3150: | caller's temps. | | caller's temps. |
3151: | | | |
3152: +-----------------------+ +-----------------------+
3153: | | | |
3154: | arguments on stack. | | arguments on stack. |
3155: | | | |
3156: +-----------------------+ +-----------------------+
3157: | 4 words to save | | 4 words to save |
3158: | arguments passed | | arguments passed |
3159: | in registers, even | | in registers, even |
3160: SP->| if not passed. | FP->| if not passed. |
3161: +-----------------------+ +-----------------------+
3162: | |
3163: | GP save for V.4 abi |
3164: | |
3165: +-----------------------+
3166: | |
3167: | local variables |
3168: | |
3169: +-----------------------+
3170: | |
3171: | fp register save |
3172: | |
3173: +-----------------------+
3174: | |
3175: | gp register save |
3176: | |
3177: +-----------------------+
3178: | |
3179: | alloca allocations |
3180: | |
3181: +-----------------------+
3182: | |
3183: | arguments on stack |
3184: | |
3185: +-----------------------+
3186: | 4 words to save |
3187: | arguments passed |
3188: | in registers, even |
3189: low SP->| if not passed. |
3190: memory +-----------------------+
3191:
3192: */
3193:
3194: unsigned long
3195: compute_frame_size (size)
3196: int size; /* # of var. bytes allocated */
3197: {
3198: int regno;
3199: unsigned long total_size; /* # bytes that the entire frame takes up */
3200: unsigned long var_size; /* # bytes that variables take up */
3201: unsigned long args_size; /* # bytes that outgoing arguments take up */
3202: unsigned long extra_size; /* # extra bytes */
3203: unsigned int gp_reg_rounded; /* # bytes needed to store gp after rounding */
3204: unsigned int gp_reg_size; /* # bytes needed to store gp regs */
3205: unsigned int fp_reg_size; /* # bytes needed to store fp regs */
3206: unsigned long mask; /* mask of saved gp registers */
3207: unsigned long fmask; /* mask of saved fp registers */
3208: int fp_inc; /* 1 or 2 depending on the size of fp regs */
3209: int fp_bits; /* bitmask to use for each fp register */
3210:
3211: extra_size = MIPS_STACK_ALIGN (((TARGET_ABICALLS) ? UNITS_PER_WORD : 0)
3212: -STARTING_FRAME_OFFSET);
3213:
3214: var_size = MIPS_STACK_ALIGN (size);
3215: args_size = MIPS_STACK_ALIGN (current_function_outgoing_args_size);
3216: total_size = var_size + args_size + extra_size;
3217: gp_reg_size = 0;
3218: fp_reg_size = 0;
3219: mask = 0;
3220: fmask = 0;
3221:
3222: /* Calculate space needed for gp registers. */
3223: for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
3224: {
3225: if (MUST_SAVE_REGISTER (regno))
3226: {
3227: gp_reg_size += UNITS_PER_WORD;
3228: mask |= 1 << (regno - GP_REG_FIRST);
3229: }
3230: }
3231:
3232: /* Calculate space needed for fp registers. */
3233: if (TARGET_FLOAT64)
3234: {
3235: fp_inc = 1;
3236: fp_bits = 1;
3237: }
3238: else
3239: {
3240: fp_inc = 2;
3241: fp_bits = 3;
3242: }
3243:
3244: for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno += fp_inc)
3245: {
3246: if (regs_ever_live[regno] && !call_used_regs[regno])
3247: {
3248: fp_reg_size += 2*UNITS_PER_WORD;
3249: fmask |= fp_bits << (regno - FP_REG_FIRST);
3250: }
3251: }
3252:
3253: gp_reg_rounded = MIPS_STACK_ALIGN (gp_reg_size);
3254: total_size += gp_reg_rounded + fp_reg_size;
3255:
3256: if (total_size == extra_size)
3257: total_size = extra_size = 0;
3258:
3259: /* Save other computed information. */
3260: current_frame_info.total_size = total_size;
3261: current_frame_info.var_size = var_size;
3262: current_frame_info.args_size = args_size;
3263: current_frame_info.extra_size = extra_size;
3264: current_frame_info.gp_reg_size = gp_reg_size;
3265: current_frame_info.fp_reg_size = fp_reg_size;
3266: current_frame_info.mask = mask;
3267: current_frame_info.fmask = fmask;
3268: current_frame_info.initialized = reload_completed;
3269:
3270: if (mask)
3271: {
3272: unsigned long offset = args_size + gp_reg_size - UNITS_PER_WORD;
3273: current_frame_info.gp_sp_offset = offset;
3274: current_frame_info.gp_save_offset = offset - total_size;
3275: }
3276:
3277: if (fmask)
3278: {
3279: unsigned long offset = args_size + gp_reg_rounded + fp_reg_size - 2*UNITS_PER_WORD;
3280: current_frame_info.fp_sp_offset = offset;
3281: current_frame_info.fp_save_offset = offset - total_size + UNITS_PER_WORD;
3282: }
3283:
3284: /* Ok, we're done. */
3285: return total_size;
3286: }
3287:
3288:
3289: /* Common code to save/restore registers. */
3290:
3291: void
3292: save_restore (file, gp_op, gp_2word_op, fp_op)
3293: FILE *file; /* stream to write to */
3294: char *gp_op; /* operation to do on gp registers */
3295: char *gp_2word_op; /* 2 word op to do on gp registers */
3296: char *fp_op; /* operation to do on fp registers */
3297: {
3298: int regno;
3299: unsigned long mask = current_frame_info.mask;
3300: unsigned long fmask = current_frame_info.fmask;
3301: unsigned long gp_offset;
3302: unsigned long fp_offset;
3303: unsigned long max_offset;
3304: char *base_reg;
3305:
3306: if (mask == 0 && fmask == 0)
3307: return;
3308:
3309: base_reg = reg_names[STACK_POINTER_REGNUM];
3310: gp_offset = current_frame_info.gp_sp_offset;
3311: fp_offset = current_frame_info.fp_sp_offset;
3312: max_offset = (gp_offset > fp_offset) ? gp_offset : fp_offset;
3313:
3314: /* Deal with calling functions with a large structure. */
3315: if (max_offset >= 32768)
3316: {
3317: char *temp = reg_names[MIPS_TEMP2_REGNUM];
3318: fprintf (file, "\tli\t%s,%ld\n", temp, max_offset);
3319: fprintf (file, "\taddu\t%s,%s,%s\n", temp, temp, base_reg);
3320: base_reg = temp;
3321: gp_offset = max_offset - gp_offset;
3322: fp_offset = max_offset - fp_offset;
3323: }
3324:
3325: /* Save registers starting from high to low. The debuggers prefer
3326: at least the return register be stored at func+4, and also it
3327: allows us not to need a nop in the epilog if at least one
3328: register is reloaded in addition to return address. */
3329:
3330: if (mask || frame_pointer_needed)
3331: {
3332: for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
3333: {
3334: if ((mask & (1L << (regno - GP_REG_FIRST))) != 0
3335: || (regno == FRAME_POINTER_REGNUM && frame_pointer_needed))
3336: {
3337: fprintf (file, "\t%s\t%s,%d(%s)\n",
3338: gp_op, reg_names[regno],
3339: gp_offset, base_reg);
3340:
3341: gp_offset -= UNITS_PER_WORD;
3342: }
3343: }
3344: }
3345:
3346: if (fmask)
3347: {
3348: int fp_inc = (TARGET_FLOAT64) ? 1 : 2;
3349:
3350: for (regno = FP_REG_LAST-1; regno >= FP_REG_FIRST; regno -= fp_inc)
3351: {
3352: if ((fmask & (1L << (regno - FP_REG_FIRST))) != 0)
3353: {
3354: fprintf (file, "\t%s\t%s,%d(%s)\n",
3355: fp_op, reg_names[regno], fp_offset, base_reg);
3356:
3357: fp_offset -= 2*UNITS_PER_WORD;
3358: }
3359: }
3360: }
3361: }
3362:
3363:
3364: /* Set up the stack and frame (if desired) for the function. */
3365:
3366: void
3367: function_prologue (file, size)
3368: FILE *file;
3369: int size;
3370: {
3371: int regno;
3372: int tsize;
3373: char *sp_str = reg_names[STACK_POINTER_REGNUM];
3374: char *fp_str = (!frame_pointer_needed)
3375: ? sp_str
3376: : reg_names[FRAME_POINTER_REGNUM];
3377: tree fndecl = current_function_decl; /* current... is tooo long */
3378: tree fntype = TREE_TYPE (fndecl);
3379: tree fnargs = (TREE_CODE (fntype) != METHOD_TYPE)
3380: ? DECL_ARGUMENTS (fndecl)
3381: : 0;
3382: tree next_arg;
3383: tree cur_arg;
3384: char *arg_name = (char *)0;
3385: CUMULATIVE_ARGS args_so_far;
3386:
3387: ASM_OUTPUT_SOURCE_FILENAME (file, DECL_SOURCE_FILE (current_function_decl));
3388: ASM_OUTPUT_SOURCE_LINE (file, DECL_SOURCE_LINE (current_function_decl));
3389:
3390: inside_function = 1;
3391: fputs ("\t.ent\t", file);
3392: assemble_name (file, current_function_name);
3393: fputs ("\n", file);
3394: assemble_name (file, current_function_name);
3395: fputs (":\n", file);
3396:
3397: if (TARGET_ABICALLS)
3398: fprintf (file,
3399: "\t.set\tnoreorder\n\t.cpload\t%s\n\t.set\treorder\n",
3400: reg_names[ GP_REG_FIRST + 25 ]);
3401:
3402: /* Determine the last argument, and get its name. */
3403: for (cur_arg = fnargs; cur_arg != (tree)0; cur_arg = next_arg)
3404: {
3405: next_arg = TREE_CHAIN (cur_arg);
3406: if (next_arg == (tree)0)
3407: {
3408: if (DECL_NAME (cur_arg))
3409: arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg));
3410:
3411: break;
3412: }
3413: }
3414:
3415: /* If this function is a varargs function, store any registers that
3416: would normally hold arguments ($4 - $7) on the stack. */
3417: if ((TYPE_ARG_TYPES (fntype) != 0
3418: && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node))
3419: || (arg_name
3420: && (strcmp (arg_name, "__builtin_va_alist") == 0
3421: || strcmp (arg_name, "va_alist") == 0)))
3422: {
3423: tree parm;
3424:
3425: regno = GP_ARG_FIRST;
3426: INIT_CUMULATIVE_ARGS (args_so_far, fntype, (rtx)0);
3427:
3428: for (parm = fnargs; (parm && (regno <= GP_ARG_LAST)); parm = TREE_CHAIN (parm))
3429: {
3430: rtx entry_parm;
3431: enum machine_mode passed_mode;
3432: tree type;
3433:
3434: type = DECL_ARG_TYPE (parm);
3435: passed_mode = TYPE_MODE (type);
3436: entry_parm = FUNCTION_ARG (args_so_far, passed_mode,
3437: DECL_ARG_TYPE (parm), 1);
3438:
3439: if (entry_parm)
3440: {
3441: int words;
3442:
3443: /* passed in a register, so will get homed automatically */
3444: if (GET_MODE (entry_parm) == BLKmode)
3445: words = (int_size_in_bytes (type) + 3) / 4;
3446: else
3447: words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;
3448:
3449: regno = REGNO (entry_parm) + words - 1;
3450: }
3451: else
3452: {
3453: regno = GP_ARG_LAST+1;
3454: break;
3455: }
3456:
3457: FUNCTION_ARG_ADVANCE (args_so_far, passed_mode,
3458: DECL_ARG_TYPE (parm), 1);
3459: }
3460:
3461: if (regno <= GP_ARG_LAST && (regno & 1) != 0)
3462: {
3463: fprintf (file, "\tsw\t%s,%d(%s)\t\t# varargs home register\n",
3464: reg_names[regno], (regno - 4) * 4, sp_str);
3465: regno++;
3466: }
3467:
3468: for (; regno <= GP_ARG_LAST; regno += 2)
3469: {
3470: fprintf (file, "\tsd\t%s,%d(%s)\t\t# varargs home register\n",
3471: reg_names[regno], (regno - 4) * 4, sp_str);
3472: }
3473: }
3474:
3475: size = MIPS_STACK_ALIGN (size);
3476: tsize = (!current_frame_info.initialized)
3477: ? compute_frame_size (size)
3478: : current_frame_info.total_size;
3479:
3480: if (tsize > 0)
3481: {
3482: if (tsize <= 32767)
3483: fprintf (file,
3484: "\tsubu\t%s,%s,%d\t\t# vars= %d, regs= %d/%d, args = %d, extra= %d\n",
3485: sp_str, sp_str, tsize, current_frame_info.var_size,
3486: current_frame_info.gp_reg_size / 4,
3487: current_frame_info.fp_reg_size / 8,
3488: current_function_outgoing_args_size,
3489: current_frame_info.extra_size);
3490: else
3491: fprintf (file,
3492: "\tli\t%s,%d\n\tsubu\t%s,%s,%s\t\t# vars= %d, regs= %d/%d, args = %d, sfo= %d\n",
3493: reg_names[MIPS_TEMP1_REGNUM], tsize, sp_str, sp_str,
3494: reg_names[MIPS_TEMP1_REGNUM], current_frame_info.var_size,
3495: current_frame_info.gp_reg_size / 4,
3496: current_frame_info.fp_reg_size / 8,
3497: current_function_outgoing_args_size,
3498: current_frame_info.extra_size);
3499: }
3500:
3501: if (TARGET_ABICALLS)
3502: fprintf (file, "\t.cprestore %d\n", tsize + STARTING_FRAME_OFFSET);
3503:
3504: fprintf (file, "\t.frame\t%s,%d,%s\n\t.mask\t0x%08lx,%d\n\t.fmask\t0x%08lx,%d\n",
3505: fp_str,
3506: (frame_pointer_needed) ? 0 : tsize,
3507: reg_names[31 + GP_REG_FIRST],
3508: current_frame_info.mask,
3509: current_frame_info.gp_save_offset,
3510: current_frame_info.fmask,
3511: current_frame_info.fp_save_offset);
3512:
3513: save_restore (file, "sw", "sd", "s.d");
3514:
3515: if (frame_pointer_needed)
3516: {
3517: if (tsize <= 32767)
3518: fprintf (file, "\taddu\t%s,%s,%d\t# set up frame pointer\n", fp_str, sp_str, tsize);
3519:
3520: else
3521: fprintf (file, "\taddu\t%s,%s,%s\t# set up frame pointer\n", fp_str, sp_str,
3522: reg_names[MIPS_TEMP1_REGNUM]);
3523: }
3524: }
3525:
3526:
3527: /* Do any necessary cleanup after a function to restore stack, frame, and regs. */
3528:
3529: void
3530: function_epilogue (file, size)
3531: FILE *file;
3532: int size;
3533: {
3534: int tsize;
3535: char *sp_str = reg_names[STACK_POINTER_REGNUM];
3536: char *t1_str = reg_names[MIPS_TEMP1_REGNUM];
3537: rtx epilogue_delay = current_function_epilogue_delay_list;
3538: int noreorder = !TARGET_MIPS_AS || (epilogue_delay != 0);
3539: int noepilogue = FALSE;
3540: int load_nop = FALSE;
3541: int load_only_r31;
3542:
3543: /* The epilogue does not depend on any registers, but the stack
3544: registers, so we assume that if we have 1 pending nop, it can be
3545: ignored, and 2 it must be filled (2 nops occur for integer
3546: multiply and divide). */
3547:
3548: if (dslots_number_nops > 0)
3549: {
3550: if (dslots_number_nops == 1)
3551: {
3552: dslots_number_nops = 0;
3553: dslots_load_filled++;
3554: }
3555: else
3556: {
3557: while (--dslots_number_nops > 0)
3558: fputs ((set_noreorder) ? "\tnop\n" : "\t#nop\n", asm_out_file);
3559: }
3560:
3561: if (set_noreorder > 0 && --set_noreorder == 0)
3562: fputs ("\t.set\treorder\n", file);
3563: }
3564:
3565: if (set_noat != 0)
3566: {
3567: set_noat = 0;
3568: fputs ("\t.set\tat\n", file);
3569: error ("internal gcc error: .set noat left on in epilogue");
3570: }
3571:
3572: if (set_nomacro != 0)
3573: {
3574: set_nomacro = 0;
3575: fputs ("\t.set\tmacro\n", file);
3576: error ("internal gcc error: .set nomacro left on in epilogue");
3577: }
3578:
3579: if (set_noreorder != 0)
3580: {
3581: set_noreorder = 0;
3582: fputs ("\t.set\treorder\n", file);
3583: error ("internal gcc error: .set noreorder left on in epilogue");
3584: }
3585:
3586: if (set_volatile != 0)
3587: {
3588: set_volatile = 0;
3589: fprintf (file, "\t#.set\tnovolatile\n", (TARGET_MIPS_AS) ? "" : "#");
3590: error ("internal gcc error: .set volatile left on in epilogue");
3591: }
3592:
3593: size = MIPS_STACK_ALIGN (size);
3594: tsize = (!current_frame_info.initialized)
3595: ? compute_frame_size (size)
3596: : current_frame_info.total_size;
3597:
3598: if (tsize == 0 && epilogue_delay == 0)
3599: {
3600: rtx insn = get_last_insn ();
3601:
3602: /* If the last insn was a BARRIER, we don't have to write any code
3603: because a jump (aka return) was put there. */
3604: if (GET_CODE (insn) == NOTE)
3605: insn = prev_nonnote_insn (insn);
3606: if (insn && GET_CODE (insn) == BARRIER)
3607: noepilogue = TRUE;
3608:
3609: noreorder = FALSE;
3610: }
3611:
3612: if (!noepilogue)
3613: {
3614: /* In the reload sequence, we don't need to fill the load delay
3615: slots for most of the loads, also see if we can fill the final
3616: delay slot if not otherwise filled by the reload sequence. */
3617:
3618: if (noreorder)
3619: fprintf (file, "\t.set\tnoreorder\n");
3620:
3621: if (tsize > 32767)
3622: fprintf (file, "\tli\t%s,%d\n", t1_str, tsize);
3623:
3624: if (frame_pointer_needed)
3625: {
3626: char *fp_str = reg_names[FRAME_POINTER_REGNUM];
3627: if (tsize > 32767)
3628: fprintf (file,"\tsubu\t%s,%s,%s\t\t# sp not trusted here\n",
3629: sp_str, fp_str, t1_str);
3630: else
3631: fprintf (file,"\tsubu\t%s,%s,%d\t\t# sp not trusted here\n",
3632: sp_str, fp_str, tsize);
3633: }
3634:
3635: save_restore (file, "lw", "ld", "l.d");
3636:
3637: load_only_r31 = (current_frame_info.mask == (1 << 31)
3638: && current_frame_info.fmask == 0);
3639:
3640: if (noreorder)
3641: {
3642: /* If the only register saved is the return address, we need a
3643: nop, unless we have an instruction to put into it. Otherwise
3644: we don't since reloading multiple registers doesn't reference
3645: the register being loaded. */
3646:
3647: if (load_only_r31)
3648: {
3649: if (epilogue_delay)
3650: final_scan_insn (XEXP (epilogue_delay, 0),
3651: file,
3652: 1, /* optimize */
3653: -2, /* prescan */
3654: 1); /* nopeepholes */
3655: else
3656: {
3657: fprintf (file, "\tnop\n");
3658: load_nop = TRUE;
3659: }
3660: }
3661:
3662: fprintf (file, "\tj\t%s\n", reg_names[GP_REG_FIRST + 31]);
3663:
3664: if (tsize > 32767)
3665: fprintf (file, "\taddu\t%s,%s,%s\n", sp_str, sp_str, t1_str);
3666:
3667: else if (tsize > 0)
3668: fprintf (file, "\taddu\t%s,%s,%d\n", sp_str, sp_str, tsize);
3669:
3670: else if (!load_only_r31 && epilogue_delay != 0)
3671: final_scan_insn (XEXP (epilogue_delay, 0),
3672: file,
3673: 1, /* optimize */
3674: -2, /* prescan */
3675: 1); /* nopeepholes */
3676:
3677: fprintf (file, "\t.set\treorder\n");
3678: }
3679:
3680: else
3681: {
3682: if (tsize > 32767)
3683: fprintf (file, "\taddu\t%s,%s,%s\n", sp_str, sp_str, t1_str);
3684:
3685: else if (tsize > 0)
3686: fprintf (file, "\taddu\t%s,%s,%d\n", sp_str, sp_str, tsize);
3687:
3688: fprintf (file, "\tj\t%s\n", reg_names[GP_REG_FIRST + 31]);
3689: }
3690: }
3691:
3692: fputs ("\t.end\t", file);
3693: assemble_name (file, current_function_name);
3694: fputs ("\n", file);
3695:
3696: if (TARGET_STATS)
3697: {
3698: int num_gp_regs = current_frame_info.gp_reg_size / 4;
3699: int num_fp_regs = current_frame_info.fp_reg_size / 8;
3700: int num_regs = num_gp_regs + num_fp_regs;
3701:
3702: dslots_load_total += num_regs;
3703:
3704: if (!noepilogue)
3705: dslots_jump_total++;
3706:
3707: if (noreorder)
3708: {
3709: dslots_load_filled += num_regs;
3710:
3711: /* If the only register saved is the return register, we
3712: can't fill this register's delay slot. */
3713:
3714: if (load_only_r31 && epilogue_delay == 0)
3715: dslots_load_filled--;
3716:
3717: if (tsize > 0 || (!load_only_r31 && epilogue_delay != 0))
3718: dslots_jump_filled++;
3719: }
3720:
3721: fprintf (stderr,
3722: "%-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\n",
3723: current_function_name,
3724: (frame_pointer_needed) ? 'y' : 'n',
3725: ((current_frame_info.mask & (1 << 31)) != 0) ? 'n' : 'y',
3726: (current_function_calls_alloca) ? 'y' : 'n',
3727: (current_function_calls_setjmp) ? 'y' : 'n',
3728: (long)current_frame_info.total_size,
3729: (long)current_function_outgoing_args_size,
3730: num_gp_regs, num_fp_regs,
3731: dslots_load_total, dslots_load_filled,
3732: dslots_jump_total, dslots_jump_filled,
3733: num_refs[0], num_refs[1], num_refs[2]);
3734: }
3735:
3736: /* Reset state info for each function. */
3737: inside_function = FALSE;
3738: ignore_line_number = FALSE;
3739: dslots_load_total = 0;
3740: dslots_jump_total = 0;
3741: dslots_load_filled = 0;
3742: dslots_jump_filled = 0;
3743: num_refs[0] = 0;
3744: num_refs[1] = 0;
3745: num_refs[2] = 0;
3746: mips_load_reg = (rtx)0;
3747: mips_load_reg2 = (rtx)0;
3748: number_functions_processed++;
3749: current_frame_info = zero_frame_info;
3750:
3751: /* Restore the output file if optimizing the GP (optimizing the GP causes
3752: the text to be diverted to a tempfile, so that data decls come before
3753: references to the data). */
3754:
3755: if (TARGET_GP_OPT)
3756: asm_out_file = asm_out_data_file;
3757: }
3758:
3759:
3760: /* Define the number of delay slots needed for the function epilogue.
3761:
3762: On the mips, we need a slot if either no stack has been allocated,
3763: or the only register saved is the return register. */
3764:
3765: int
3766: mips_epilogue_delay_slots ()
3767: {
3768: if (!current_frame_info.initialized)
3769: (void) compute_frame_size (get_frame_size ());
3770:
3771: if (current_frame_info.total_size == 0)
3772: return 1;
3773:
3774: if (current_frame_info.mask == (1 << 31) && current_frame_info.fmask == 0)
3775: return 1;
3776:
3777: return 0;
3778: }
3779:
3780:
3781: /* Return true if this function is known to have a null epilogue.
3782: This allows the optimizer to omit jumps to jumps if no stack
3783: was created. */
3784:
3785: int
3786: null_epilogue ()
3787: {
3788: if (!reload_completed)
3789: return 0;
3790:
3791: if (current_frame_info.initialized)
3792: return current_frame_info.total_size == 0;
3793:
3794: return (compute_frame_size (get_frame_size ())) == 0;
3795: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.