|
|
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:
1.1.1.2 ! root 148: /* Whether to suppress issuing .loc's because the user attempted
1.1 root 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:
523: /* Eliminate non-memory operations */
524: if (GET_CODE (op) != MEM)
525: return FALSE;
526:
527: /* dword operations really put out 2 instructions, so eliminate them. */
528: if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4))
529: return FALSE;
530:
531: /* Decode the address now. */
532: addr = XEXP (op, 0);
533: switch (GET_CODE (addr))
534: {
535: case REG:
536: return TRUE;
537:
538: case CONST_INT:
539: return SMALL_INT (op);
540:
541: case PLUS:
542: plus0 = XEXP (addr, 0);
543: plus1 = XEXP (addr, 1);
544: if (GET_CODE (plus0) == REG
545: && GET_CODE (plus1) == CONST_INT
546: && SMALL_INT (plus1))
547: return TRUE;
548:
549: else if (GET_CODE (plus1) == REG
550: && GET_CODE (plus0) == CONST_INT
551: && SMALL_INT (plus0))
552: return TRUE;
553:
554: else
555: return FALSE;
556:
557: #if 0
558: /* We used to allow small symbol refs here (ie, stuff in .sdata
559: or .sbss), but this causes some bugs in G++. Also, it won't
560: interfere if the MIPS linker rewrites the store instruction
561: because the function is PIC. */
562:
563: case LABEL_REF: /* never gp relative */
564: break;
565:
566: case CONST:
567: /* If -G 0, we can never have a GP relative memory operation.
568: Also, save some time if not optimizing. */
569: if (mips_section_threshold == 0 || !optimize || !TARGET_GP_OPT)
570: return FALSE;
571:
1.1.1.2 ! root 572: {
! 573: rtx offset = const0_rtx;
! 574: addr = eliminate_constant_term (addr, &offset);
! 575: if (GET_CODE (op) != SYMBOL_REF)
! 576: return FALSE;
! 577:
! 578: /* let's be paranoid.... */
! 579: if (INTVAL (offset) < 0 || INTVAL (offset) > 0xffff)
! 580: return FALSE;
! 581: }
1.1 root 582: /* fall through */
583:
584: case SYMBOL_REF:
585: return SYMBOL_REF_FLAG (addr);
586: #endif
587: }
588:
589: return FALSE;
590: }
591:
592: /* Return true if the address is suitable for function call. */
593:
594: int
595: call_memory_operand (op, mode)
596: rtx op;
597: enum machine_mode mode;
598: {
599: rtx addr;
600: enum rtx_code code;
601:
602: if (GET_CODE (op) != MEM)
603: return FALSE;
604:
605: addr = XEXP (op, 0);
606: code = GET_CODE (addr);
607:
608: if (GET_MODE (addr) != FUNCTION_MODE)
609: return FALSE;
610:
611: if (code == REG || code == SUBREG)
612: return TRUE;
613:
614: if (CONSTANT_ADDRESS_P (addr))
615: return TRUE;
616:
617: return FALSE;
618: }
619:
620: /* Return true if the code of this rtx pattern is EQ or NE. */
621:
622: int
623: equality_op (op, mode)
624: rtx op;
625: enum machine_mode mode;
626: {
627: if (mode != GET_MODE (op))
628: return FALSE;
629:
630: return (classify_op (op, mode) & CLASS_EQUALITY_OP) != 0;
631: }
632:
633: /* Return true if the code is a relational operations (EQ, LE, etc.) */
634:
635: int
636: cmp_op (op, mode)
637: rtx op;
638: enum machine_mode mode;
639: {
640: if (mode != GET_MODE (op))
641: return FALSE;
642:
643: return (classify_op (op, mode) & CLASS_CMP_OP) != 0;
644: }
645:
646:
647: /* Genrecog does not take the type of match_operator into consideration,
648: and would complain about two patterns being the same if the same
649: function is used, so make it believe they are different. */
650:
651: int
652: cmp2_op (op, mode)
653: rtx op;
654: enum machine_mode mode;
655: {
656: if (mode != GET_MODE (op))
657: return FALSE;
658:
659: return (classify_op (op, mode) & CLASS_CMP_OP) != 0;
660: }
661:
662: /* Return true if the code is an unsigned relational operations (LEU, etc.) */
663:
664: int
665: uns_cmp_op (op,mode)
666: rtx op;
667: enum machine_mode mode;
668: {
669: if (mode != GET_MODE (op))
670: return FALSE;
671:
672: return (classify_op (op, mode) & CLASS_UNS_CMP_OP) == CLASS_UNS_CMP_OP;
673: }
674:
675: /* Return true if the code is a relational operation FP can use. */
676:
677: int
678: fcmp_op (op, mode)
679: rtx op;
680: enum machine_mode mode;
681: {
682: if (mode != GET_MODE (op))
683: return FALSE;
684:
685: return (classify_op (op, mode) & CLASS_FCMP_OP) != 0;
686: }
687:
688:
689: /* Return an operand string if the given instruction's delay slot or
690: wrap it in a .set noreorder section. This is for filling delay
691: slots on load type instructions under GAS, which does no reordering
692: on its own. For the MIPS assembler, all we do is update the filled
693: delay slot statistics.
694:
695: We assume that operands[0] is the target register that is set.
696:
697: In order to check the next insn, most of this functionality is moved
698: to FINAL_PRESCAN_INSN, and we just set the global variables that
699: it needs. */
700:
701: char *
702: mips_fill_delay_slot (ret, type, operands, cur_insn)
703: char *ret; /* normal string to return */
704: enum delay_type type; /* type of delay */
705: rtx operands[]; /* operands to use */
706: rtx cur_insn; /* current insn */
707: {
708: register rtx set_reg;
709: register enum machine_mode mode;
710: register rtx next_insn = (cur_insn) ? NEXT_INSN (cur_insn) : (rtx)0;
711: register int num_nops;
712:
713: if (type == DELAY_LOAD)
714: num_nops = 1;
715:
716: else if (type == DELAY_HILO)
717: num_nops = 2;
718:
719: else
720: num_nops = 0;
721:
722: /* Make sure that we don't put nop's after labels. */
723: next_insn = NEXT_INSN (cur_insn);
724: while (next_insn != (rtx)0 && GET_CODE (next_insn) == NOTE)
725: next_insn = NEXT_INSN (next_insn);
726:
727: dslots_load_total += num_nops;
728: if (TARGET_DEBUG_F_MODE
729: || !optimize
730: || type == DELAY_NONE
731: || operands == (rtx *)0
732: || cur_insn == (rtx)0
733: || next_insn == (rtx)0
734: || GET_CODE (next_insn) == CODE_LABEL
735: || (set_reg = operands[0]) == (rtx)0)
736: {
737: dslots_number_nops = 0;
738: mips_load_reg = (rtx)0;
739: mips_load_reg2 = (rtx)0;
740: mips_load_reg3 = (rtx)0;
741: mips_load_reg4 = (rtx)0;
742: return ret;
743: }
744:
745: set_reg = operands[0];
746: if (set_reg == (rtx)0)
747: return ret;
748:
749: while (GET_CODE (set_reg) == SUBREG)
750: set_reg = SUBREG_REG (set_reg);
751:
752: mode = GET_MODE (set_reg);
753: dslots_number_nops = num_nops;
754: mips_load_reg = set_reg;
755: mips_load_reg2 = (mode == DImode || mode == DFmode)
756: ? gen_rtx (REG, SImode, REGNO (set_reg) + 1)
757: : (rtx)0;
758:
759: if (type == DELAY_HILO)
760: {
761: mips_load_reg3 = gen_rtx (REG, SImode, MD_REG_FIRST);
762: mips_load_reg4 = gen_rtx (REG, SImode, MD_REG_FIRST+1);
763: }
764: else
765: {
766: mips_load_reg3 = 0;
767: mips_load_reg4 = 0;
768: }
769:
770: if (TARGET_GAS && set_noreorder++ == 0)
771: fputs ("\t.set\tnoreorder\n", asm_out_file);
772:
773: return ret;
774: }
775:
776:
777: /* Determine whether a memory reference takes one (based off of the GP pointer),
1.1.1.2 ! root 778: two (normal), or three (label + reg) instructions, and bump the appropriate
1.1 root 779: counter for -mstats. */
780:
781: void
782: mips_count_memory_refs (op, num)
783: rtx op;
784: int num;
785: {
786: int additional = 0;
787: int n_words = 0;
788: rtx addr, plus0, plus1;
789: enum rtx_code code0, code1;
790: int looping;
791:
792: if (TARGET_DEBUG_B_MODE)
793: {
794: fprintf (stderr, "\n========== mips_count_memory_refs:\n");
795: debug_rtx (op);
796: }
797:
798: /* Skip MEM if passed, otherwise handle movsi of address. */
799: addr = (GET_CODE (op) != MEM) ? op : XEXP (op, 0);
800:
801: /* Loop, going through the address RTL */
802: do
803: {
804: looping = FALSE;
805: switch (GET_CODE (addr))
806: {
807: case REG:
808: case CONST_INT:
809: break;
810:
811: case PLUS:
812: plus0 = XEXP (addr, 0);
813: plus1 = XEXP (addr, 1);
814: code0 = GET_CODE (plus0);
815: code1 = GET_CODE (plus1);
816:
817: if (code0 == REG)
818: {
819: additional++;
820: addr = plus1;
821: looping = TRUE;
822: continue;
823: }
824:
825: if (code0 == CONST_INT)
826: {
827: addr = plus1;
828: looping = TRUE;
829: continue;
830: }
831:
832: if (code1 == REG)
833: {
834: additional++;
835: addr = plus0;
836: looping = TRUE;
837: continue;
838: }
839:
840: if (code1 == CONST_INT)
841: {
842: addr = plus0;
843: looping = TRUE;
844: continue;
845: }
846:
847: if (code0 == SYMBOL_REF || code0 == LABEL_REF || code0 == CONST)
848: {
849: addr = plus0;
850: looping = TRUE;
851: continue;
852: }
853:
854: if (code1 == SYMBOL_REF || code1 == LABEL_REF || code1 == CONST)
855: {
856: addr = plus1;
857: looping = TRUE;
858: continue;
859: }
860:
861: break;
862:
863: case LABEL_REF:
864: n_words = 2; /* always 2 words */
865: break;
866:
867: case CONST:
868: addr = XEXP (addr, 0);
869: looping = TRUE;
870: continue;
871:
872: case SYMBOL_REF:
873: n_words = SYMBOL_REF_FLAG (addr) ? 1 : 2;
874: break;
875: }
876: }
877: while (looping);
878:
879: if (n_words == 0)
880: return;
881:
882: n_words += additional;
883: if (n_words > 3)
884: n_words = 3;
885:
886: num_refs[n_words-1] += num;
887: }
888:
889:
890: /* Return the appropriate instructions to move one operand to another. */
891:
892: char *
893: mips_move_1word (operands, insn, unsignedp)
894: rtx operands[];
895: rtx insn;
896: int unsignedp;
897: {
898: char *ret = 0;
899: rtx op0 = operands[0];
900: rtx op1 = operands[1];
901: enum rtx_code code0 = GET_CODE (op0);
902: enum rtx_code code1 = GET_CODE (op1);
903: enum machine_mode mode = GET_MODE (op0);
904: int subreg_word0 = 0;
905: int subreg_word1 = 0;
906: enum delay_type delay = DELAY_NONE;
907:
908: while (code0 == SUBREG)
909: {
910: subreg_word0 += SUBREG_WORD (op0);
911: op0 = SUBREG_REG (op0);
912: code0 = GET_CODE (op0);
913: }
914:
915: while (code1 == SUBREG)
916: {
917: subreg_word1 += SUBREG_WORD (op1);
918: op1 = SUBREG_REG (op1);
919: code1 = GET_CODE (op1);
920: }
921:
922: if (code0 == REG)
923: {
924: int regno0 = REGNO (op0) + subreg_word0;
925:
926: if (code1 == REG)
927: {
928: int regno1 = REGNO (op1) + subreg_word1;
929:
930: /* Just in case, don't do anything for assigning a register
931: to itself, unless we are filling a delay slot. */
932: if (regno0 == regno1 && set_nomacro == 0)
933: ret = "";
934:
935: else if (GP_REG_P (regno0))
936: {
937: if (GP_REG_P (regno1))
938: ret = "move\t%0,%1";
939:
940: else if (MD_REG_P (regno1))
941: {
942: delay = DELAY_HILO;
943: ret = "mf%1\t%0";
944: }
945:
946: else
947: {
948: delay = DELAY_LOAD;
949: if (FP_REG_P (regno1))
950: ret = "mfc1\t%0,%1";
951:
952: else if (regno1 == FPSW_REGNUM)
953: ret = "cfc1\t%0,$31";
954: }
955: }
956:
957: else if (FP_REG_P (regno0))
958: {
959: if (GP_REG_P (regno1))
960: {
961: delay = DELAY_LOAD;
962: ret = "mtc1\t%1,%0";
963: }
964:
965: if (FP_REG_P (regno1))
966: ret = "mov.s\t%0,%1";
967: }
968:
969: else if (MD_REG_P (regno0))
970: {
971: if (GP_REG_P (regno1))
972: {
973: delay = DELAY_HILO;
974: ret = "mt%0\t%1";
975: }
976: }
977:
978: else if (regno0 == FPSW_REGNUM)
979: {
980: if (GP_REG_P (regno1))
981: {
982: delay = DELAY_LOAD;
983: ret = "ctc1\t%0,$31";
984: }
985: }
986: }
987:
988: else if (code1 == MEM)
989: {
990: delay = DELAY_LOAD;
991:
992: if (TARGET_STATS)
993: mips_count_memory_refs (op1, 1);
994:
995: if (GP_REG_P (regno0))
996: {
997: /* For loads, use the mode of the memory item, instead of the
998: target, so zero/sign extend can use this code as well. */
999: switch (GET_MODE (op1))
1000: {
1001: case SFmode: ret = "lw\t%0,%1"; break;
1002: case SImode: ret = "lw\t%0,%1"; break;
1003: case HImode: ret = (unsignedp) ? "lhu\t%0,%1" : "lh\t%0,%1"; break;
1004: case QImode: ret = (unsignedp) ? "lbu\t%0,%1" : "lb\t%0,%1"; break;
1005: }
1006: }
1007:
1008: else if (FP_REG_P (regno0) && (mode == SImode || mode == SFmode))
1009: ret = "l.s\t%0,%1";
1010:
1011: if (ret != (char *)0 && MEM_VOLATILE_P (op1))
1012: {
1013: int i = strlen (ret);
1014: if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
1015: abort ();
1016:
1017: sprintf (volatile_buffer, "%%{%s%%}", ret);
1018: ret = volatile_buffer;
1019: }
1020: }
1021:
1022: else if (code1 == CONST_INT)
1023: {
1024: if (INTVAL (op1) == 0)
1025: {
1026: if (GP_REG_P (regno0))
1027: ret = "move\t%0,%z1";
1028:
1029: else if (FP_REG_P (regno0))
1030: {
1031: delay = DELAY_LOAD;
1032: return "mtc1\t%z1,%0";
1033: }
1034: }
1035:
1036: else if (GP_REG_P (regno0))
1037: {
1038: if ((INTVAL (operands[1]) & 0x0000ffff) == 0)
1039: ret = "lui\t%0,(%X1)>>16";
1040: else
1041: ret = "li\t%0,%1";
1042: }
1043: }
1044:
1045: else if (code1 == CONST_DOUBLE && mode == SFmode)
1046: {
1047: if (CONST_DOUBLE_HIGH (op1) == 0 && CONST_DOUBLE_LOW (op1) == 0)
1048: {
1049: if (GP_REG_P (regno0))
1050: ret = "move\t%0,%.";
1051:
1052: else if (FP_REG_P (regno0))
1053: {
1054: delay = DELAY_LOAD;
1055: ret = "mtc1\t%.,%0";
1056: }
1057: }
1058:
1059: else
1060: {
1061: delay = DELAY_LOAD;
1062: ret = "li.s\t%0,%1";
1063: }
1064: }
1065:
1066: else if (code1 == LABEL_REF)
1067: ret = "la\t%0,%a1";
1068:
1069: else if (code1 == SYMBOL_REF || code1 == CONST)
1070: {
1071: if (TARGET_STATS)
1072: mips_count_memory_refs (op1, 1);
1073:
1074: if (HALF_PIC_P () && CONSTANT_P (op1) && HALF_PIC_ADDRESS_P (op1))
1075: {
1076: delay = DELAY_LOAD;
1077: ret = "la\t%0,%a1\t\t# pic reference";
1078: }
1079: else
1080: ret = "la\t%0,%a1";
1081: }
1082:
1083: else if (code1 == PLUS)
1084: {
1085: rtx add_op0 = XEXP (op1, 0);
1086: rtx add_op1 = XEXP (op1, 1);
1087:
1088: if (GET_CODE (XEXP (op1, 1)) == REG && GET_CODE (XEXP (op1, 0)) == CONST_INT)
1089: {
1090: add_op0 = XEXP (op1, 1); /* reverse operands */
1091: add_op1 = XEXP (op1, 0);
1092: }
1093:
1094: operands[2] = add_op0;
1095: operands[3] = add_op1;
1096: ret = "add%:\t%0,%2,%3";
1097: }
1098: }
1099:
1100: else if (code0 == MEM)
1101: {
1102: if (TARGET_STATS)
1103: mips_count_memory_refs (op0, 1);
1104:
1105: if (code1 == REG)
1106: {
1107: int regno1 = REGNO (op1) + subreg_word1;
1108:
1109: if (GP_REG_P (regno1))
1110: {
1111: switch (mode)
1112: {
1113: case SFmode: ret = "sw\t%1,%0"; break;
1114: case SImode: ret = "sw\t%1,%0"; break;
1115: case HImode: ret = "sh\t%1,%0"; break;
1116: case QImode: ret = "sb\t%1,%0"; break;
1117: }
1118: }
1119:
1120: else if (FP_REG_P (regno1) && (mode == SImode || mode == SFmode))
1121: ret = "s.s\t%1,%0";
1122: }
1123:
1124: else if (code1 == CONST_INT && INTVAL (op1) == 0)
1125: {
1126: switch (mode)
1127: {
1128: case SFmode: ret = "sw\t%z1,%0"; break;
1129: case SImode: ret = "sw\t%z1,%0"; break;
1130: case HImode: ret = "sh\t%z1,%0"; break;
1131: case QImode: ret = "sb\t%z1,%0"; break;
1132: }
1133: }
1134:
1135: else if (code1 == CONST_DOUBLE && CONST_DOUBLE_HIGH (op1) == 0 && CONST_DOUBLE_LOW (op1) == 0)
1136: {
1137: switch (mode)
1138: {
1139: case SFmode: ret = "sw\t%.,%0"; break;
1140: case SImode: ret = "sw\t%.,%0"; break;
1141: case HImode: ret = "sh\t%.,%0"; break;
1142: case QImode: ret = "sb\t%.,%0"; break;
1143: }
1144: }
1145:
1146: if (ret != (char *)0 && MEM_VOLATILE_P (op0))
1147: {
1148: int i = strlen (ret);
1149: if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
1150: abort ();
1151:
1152: sprintf (volatile_buffer, "%%{%s%%}", ret);
1153: ret = volatile_buffer;
1154: }
1155: }
1156:
1157: if (ret == (char *)0)
1158: {
1159: abort_with_insn (insn, "Bad move");
1160: return 0;
1161: }
1162:
1163: if (delay != DELAY_NONE)
1164: return mips_fill_delay_slot (ret, delay, operands, insn);
1165:
1166: return ret;
1167: }
1168:
1169:
1170: /* Return the appropriate instructions to move 2 words */
1171:
1172: char *
1173: mips_move_2words (operands, insn)
1174: rtx operands[];
1175: rtx insn;
1176: {
1177: char *ret = 0;
1178: rtx op0 = operands[0];
1179: rtx op1 = operands[1];
1180: enum rtx_code code0 = GET_CODE (operands[0]);
1181: enum rtx_code code1 = GET_CODE (operands[1]);
1182: int subreg_word0 = 0;
1183: int subreg_word1 = 0;
1184: enum delay_type delay = DELAY_NONE;
1185:
1186: while (code0 == SUBREG)
1187: {
1188: subreg_word0 += SUBREG_WORD (op0);
1189: op0 = SUBREG_REG (op0);
1190: code0 = GET_CODE (op0);
1191: }
1192:
1193: while (code1 == SUBREG)
1194: {
1195: subreg_word1 += SUBREG_WORD (op1);
1196: op1 = SUBREG_REG (op1);
1197: code1 = GET_CODE (op1);
1198: }
1199:
1200: if (code0 == REG)
1201: {
1202: int regno0 = REGNO (op0) + subreg_word0;
1203:
1204: if (code1 == REG)
1205: {
1206: int regno1 = REGNO (op1) + subreg_word1;
1207:
1208: /* Just in case, don't do anything for assigning a register
1209: to itself, unless we are filling a delay slot. */
1210: if (regno0 == regno1 && set_nomacro == 0)
1211: ret = "";
1212:
1213: else if (FP_REG_P (regno0))
1214: {
1215: if (FP_REG_P (regno1))
1216: ret = "mov.d\t%0,%1";
1217:
1218: else
1219: {
1220: delay = DELAY_LOAD;
1221: ret = (TARGET_FLOAT64)
1222: ? "dmtc1\t%1,%0"
1223: : "mtc1\t%L1,%0\n\tmtc1\t%M1,%D0";
1224: }
1225: }
1226:
1227: else if (FP_REG_P (regno1))
1228: {
1229: delay = DELAY_LOAD;
1230: ret = (TARGET_FLOAT64)
1231: ? "dmfc1\t%0,%1"
1232: : "mfc1\t%L0,%1\n\tmfc1\t%M0,%D1";
1233: }
1234:
1235: else if (MD_REG_P (regno0) && GP_REG_P (regno1))
1236: {
1237: delay = DELAY_HILO;
1238: ret = "mthi\t%M1\n\tmtlo\t%L1";
1239: }
1240:
1241: else if (GP_REG_P (regno0) && MD_REG_P (regno1))
1242: {
1243: delay = DELAY_HILO;
1244: ret = "mfhi\t%M0\n\tmflo\t%L0";
1245: }
1246:
1247: else if (regno0 != (regno1+1))
1248: ret = "move\t%0,%1\n\tmove\t%D0,%D1";
1249:
1250: else
1251: ret = "move\t%D0,%D1\n\tmove\t%0,%1";
1252: }
1253:
1254: else if (code1 == CONST_DOUBLE)
1255: {
1256: if (CONST_DOUBLE_HIGH (op1) != 0 || CONST_DOUBLE_LOW (op1) != 0)
1257: {
1258: if (GET_MODE (op1) == DFmode)
1259: {
1260: delay = DELAY_LOAD;
1261: ret = "li.d\t%0,%1";
1262: }
1263:
1264: else
1265: {
1266: operands[2] = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_LOW (op1));
1267: operands[3] = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_HIGH (op1));
1268: ret = "li\t%M0,%3\n\tli\t%L0,%2";
1269: }
1270: }
1271:
1272: else
1273: {
1274: if (GP_REG_P (regno0))
1275: ret = "move\t%0,%.\n\tmove\t%D0,%.";
1276:
1277: else if (FP_REG_P (regno0))
1278: {
1279: delay = DELAY_LOAD;
1280: ret = (TARGET_FLOAT64)
1281: ? "dmtc1\t%.,%0"
1282: : "mtc1\t%.,%0\n\tmtc1\t%.,%D0";
1283: }
1284: }
1285: }
1286:
1287: else if (code1 == CONST_INT && INTVAL (op1) == 0)
1288: {
1289: if (GP_REG_P (regno0))
1290: ret = "move\t%0,%.\n\tmove\t%D0,%.";
1291:
1292: else if (FP_REG_P (regno0))
1293: {
1294: delay = DELAY_LOAD;
1295: ret = (TARGET_FLOAT64)
1296: ? "dmtc1\t%.,%0"
1297: : "mtc1\t%.,%0\n\tmtc1\t%.,%D0";
1298: }
1299: }
1300:
1301: else if (code1 == CONST_INT && GET_MODE (op0) == DImode && GP_REG_P (regno0))
1302: {
1303: operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[1]) >= 0 ? 0 : -1);
1304: ret = "li\t%M0,%2\n\tli\t%L0,%1";
1305: }
1306:
1307: else if (code1 == MEM)
1308: {
1309: delay = DELAY_LOAD;
1310:
1311: if (TARGET_STATS)
1312: mips_count_memory_refs (op1, 2);
1313:
1314: if (FP_REG_P (regno0))
1315: ret = "l.d\t%0,%1";
1316:
1317: else if (offsettable_address_p (1, DFmode, XEXP (op1, 0)))
1318: {
1319: operands[2] = adj_offsettable_operand (op1, 4);
1320: if (reg_mentioned_p (op0, op1))
1321: ret = "lw\t%D0,%2\n\tlw\t%0,%1";
1322: else
1323: ret = "lw\t%0,%1\n\tlw\t%D0,%2";
1324: }
1325:
1326: if (ret != (char *)0 && MEM_VOLATILE_P (op1))
1327: {
1328: int i = strlen (ret);
1329: if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
1330: abort ();
1331:
1332: sprintf (volatile_buffer, "%%{%s%%}", ret);
1333: ret = volatile_buffer;
1334: }
1335: }
1336: }
1337:
1338: else if (code0 == MEM)
1339: {
1340: if (code1 == REG)
1341: {
1342: int regno1 = REGNO (op1) + subreg_word1;
1343:
1344: if (FP_REG_P (regno1))
1345: ret = "s.d\t%1,%0";
1346:
1347: else if (offsettable_address_p (1, DFmode, XEXP (op0, 0)))
1348: {
1349: operands[2] = adj_offsettable_operand (op0, 4);
1350: ret = "sw\t%1,%0\n\tsw\t%D1,%2";
1351: }
1352: }
1353:
1354: else if (code1 == CONST_DOUBLE
1355: && CONST_DOUBLE_HIGH (op1) == 0
1356: && CONST_DOUBLE_LOW (op1) == 0
1357: && offsettable_address_p (1, DFmode, XEXP (op0, 0)))
1358: {
1359: if (TARGET_FLOAT64)
1360: ret = "sd\t%.,%0";
1361: else
1362: {
1363: operands[2] = adj_offsettable_operand (op0, 4);
1364: ret = "sw\t%.,%0\n\tsw\t%.,%2";
1365: }
1366: }
1367:
1368: if (TARGET_STATS)
1369: mips_count_memory_refs (op0, 2);
1370:
1371: if (ret != (char *)0 && MEM_VOLATILE_P (op0))
1372: {
1373: int i = strlen (ret);
1374: if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))
1375: abort ();
1376:
1377: sprintf (volatile_buffer, "%%{%s%%}", ret);
1378: ret = volatile_buffer;
1379: }
1380: }
1381:
1382: if (ret == (char *)0)
1383: {
1384: abort_with_insn (insn, "Bad move");
1385: return 0;
1386: }
1387:
1388: if (delay != DELAY_NONE)
1389: return mips_fill_delay_slot (ret, delay, operands, insn);
1390:
1391: return ret;
1392: }
1393:
1394:
1395: /* Provide the costs of an addressing mode that contains ADDR.
1.1.1.2 ! root 1396: If ADDR is not a valid address, its cost is irrelevant. */
1.1 root 1397:
1398: int
1399: mips_address_cost (addr)
1400: rtx addr;
1401: {
1402: switch (GET_CODE (addr))
1403: {
1404: case LO_SUM:
1405: case HIGH:
1406: return 1;
1407:
1408: case LABEL_REF:
1409: return 2;
1410:
1411: case CONST:
1.1.1.2 ! root 1412: {
! 1413: rtx offset = const0_rtx;
! 1414: addr = eliminate_constant_term (addr, &offset);
! 1415: if (GET_CODE (addr) == LABEL_REF)
! 1416: return 2;
1.1 root 1417:
1.1.1.2 ! root 1418: if (GET_CODE (addr) != SYMBOL_REF)
! 1419: return 4;
1.1 root 1420:
1.1.1.2 ! root 1421: if (INTVAL (offset) < -32768 || INTVAL (offset) > 32767)
! 1422: return 2;
! 1423: }
1.1 root 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 */
1.1.1.2 ! root 1635: rtx dest_addr; /* destination address */
1.1 root 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:
1.1.1.2 ! root 2420: /* Set up the classification arrays now. */
1.1 root 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
1.1.1.2 ! root 2480: mandatory delay, it is as fast to load from cached memory as to move
1.1 root 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: {
1.1.1.2 ! root 2528: rtx offset2 = const0_rtx;
1.1 root 2529: rtx reg = eliminate_constant_term (addr, &offset2);
2530:
2531: if (!offset)
1.1.1.2 ! root 2532: offset = INTVAL (offset2);
1.1 root 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);
1.1.1.2 ! root 2985: if (!TARGET_GAS && write_symbols == DBX_DEBUG)
! 2986: fprintf (stream, "\t#@stabs\n");
1.1 root 2987: }
2988:
2989: else if (!TARGET_GAS && write_symbols == DBX_DEBUG)
2990: {
2991: ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", 0);
2992: fprintf (stream, "%s \"%s\",%d,0,0,%s\n", ASM_STABS_OP,
2993: name, N_SOL, <ext_label_name[1]);
2994: }
2995:
2996: else if (name != current_function_file
2997: && strcmp (name, current_function_file) != 0)
2998: {
2999: if (inside_function && !TARGET_GAS)
3000: {
3001: if (!file_in_function_warning)
3002: {
3003: file_in_function_warning = TRUE;
3004: ignore_line_number = TRUE;
3005: warning ("MIPS ECOFF format does not allow changing filenames within functions with #line");
3006: }
3007:
3008: fprintf (stream, "\t#.file\t%d \"%s\"\n", num_source_filenames, name);
3009: }
3010:
3011: else
3012: {
3013: SET_FILE_NUMBER ();
3014: current_function_file = name;
3015: fprintf (stream, "\t.file\t%d \"%s\"\n", num_source_filenames, name);
3016: }
3017: }
3018: }
3019:
3020:
3021: /* Emit a linenumber. For encapsulated stabs, we need to put out a stab
3022: as well as a .loc, since it is possible that MIPS ECOFF might not be
3023: able to represent the location for inlines that come from a different
3024: file. */
3025:
3026: void
3027: mips_output_lineno (stream, line)
3028: FILE *stream;
3029: int line;
3030: {
3031: if (!TARGET_GAS && write_symbols == DBX_DEBUG)
3032: {
3033: ++sym_lineno;
3034: fprintf (stream, "$LM%d:\n\t%s %d,0,%d,$LM%d\n",
3035: sym_lineno, ASM_STABN_OP, N_SLINE, line, sym_lineno);
3036: }
3037:
3038: else
3039: {
3040: fprintf (stream, "\n\t%s.loc\t%d %d\n",
3041: (ignore_line_number) ? "#" : "",
3042: num_source_filenames, line);
3043:
3044: LABEL_AFTER_LOC (stream);
3045: }
3046: }
3047:
3048:
3049: /* Output at beginning of assembler file.
3050: If we are optimizing to use the global pointer, create a temporary
3051: file to hold all of the text stuff, and write it out to the end.
3052: This is needed because the MIPS assembler is evidently one pass,
3053: and if it hasn't seen the relevant .comm/.lcomm/.extern/.sdata
3054: declaration when the code is processed, it generates a two
3055: instruction sequence. */
3056:
3057: void
3058: mips_asm_file_start (stream)
3059: FILE *stream;
3060: {
3061: ASM_OUTPUT_SOURCE_FILENAME (stream, main_input_filename);
3062:
3063: /* Versions of the MIPS assembler before 2.20 generate errors
3064: if a branch inside of a .set noreorder section jumps to a
3065: label outside of the .set noreorder section. Revision 2.20
3066: just set nobopt silently rather than fixing the bug. */
3067:
3068: if (TARGET_MIPS_AS && optimize && flag_delayed_branch)
3069: fprintf (stream, "\t.set\tnobopt\n");
3070:
3071: /* Generate the pseudo ops that the Pyramid based System V.4 wants. */
3072: if (TARGET_ABICALLS)
3073: fprintf (stream, "\t.abicalls\n");
3074:
3075: /* put gcc_compiled. in data, not text */
3076: data_section ();
3077:
3078: if (TARGET_GP_OPT)
3079: {
3080: asm_out_data_file = stream;
3081: asm_out_text_file = make_temp_file ();
3082: }
3083: else
3084: asm_out_data_file = asm_out_text_file = stream;
3085:
3086: if (TARGET_NAME_REGS)
3087: fprintf (asm_out_file, "#include <regdef.h>\n");
3088:
3089: print_options (stream);
3090: }
3091:
3092:
3093: /* If we are optimizing the global pointer, emit the text section now
3094: and any small externs which did not have .comm, etc that are
3095: needed. Also, give a warning if the data area is more than 32K and
3096: -pic because 3 instructions are needed to reference the data
3097: pointers. */
3098:
3099: void
3100: mips_asm_file_end (file)
3101: FILE *file;
3102: {
3103: char buffer[8192];
3104: tree name_tree;
3105: struct extern_list *p;
3106: int len;
3107:
3108: if (TARGET_GP_OPT)
3109: {
3110: if (extern_head)
3111: fputs ("\n", file);
3112:
3113: for (p = extern_head; p != 0; p = p->next)
3114: {
3115: name_tree = get_identifier (p->name);
1.1.1.2 ! root 3116:
! 3117: /* Positively ensure only one .extern for any given symbol. */
! 3118: if (! TREE_ASM_WRITTEN (name_tree))
1.1 root 3119: {
1.1.1.2 ! root 3120: TREE_ASM_WRITTEN (name_tree) = 1;
1.1 root 3121: fputs ("\t.extern\t", file);
3122: assemble_name (file, p->name);
3123: fprintf (file, ", %d\n", p->size);
3124: }
3125: }
3126:
3127: fprintf (file, "\n\t.text\n");
3128: rewind (asm_out_text_file);
3129: if (ferror (asm_out_text_file))
3130: fatal_io_error (temp_filename);
3131:
3132: while ((len = fread (buffer, 1, sizeof (buffer), asm_out_text_file)) > 0)
3133: if (fwrite (buffer, 1, len, file) != len)
3134: pfatal_with_name (asm_file_name);
3135:
3136: if (len < 0)
3137: pfatal_with_name (temp_filename);
3138:
3139: if (fclose (asm_out_text_file) != 0)
3140: pfatal_with_name (temp_filename);
3141: }
3142: }
3143:
3144:
1.1.1.2 ! root 3145: /* Emit either a label, .comm, or .lcomm directive, and mark
! 3146: that the symbol is used, so that we don't emit an .extern
! 3147: for it in mips_asm_file_end. */
! 3148:
! 3149: void
! 3150: mips_declare_object (stream, name, init_string, final_string, size)
! 3151: FILE *stream;
! 3152: char *name;
! 3153: char *init_string;
! 3154: char *final_string;
! 3155: int size;
! 3156: {
! 3157: fputs (init_string, stream); /* "", "\t.comm\t", or "\t.lcomm\t" */
! 3158: assemble_name (stream, name);
! 3159: fprintf (stream, final_string, size); /* ":\n", ",%u\n", ",%u\n" */
! 3160:
! 3161: if (TARGET_GP_OPT && mips_section_threshold != 0)
! 3162: {
! 3163: tree name_tree = get_identifier (name);
! 3164: TREE_ASM_WRITTEN (name_tree) = 1;
! 3165: }
! 3166: }
! 3167:
! 3168:
1.1 root 3169: /* Return the bytes needed to compute the frame pointer from the current
3170: stack pointer.
3171:
3172: Mips stack frames look like:
3173:
3174: Before call After call
3175: +-----------------------+ +-----------------------+
3176: high | | | |
3177: mem. | | | |
3178: | caller's temps. | | caller's temps. |
3179: | | | |
3180: +-----------------------+ +-----------------------+
3181: | | | |
3182: | arguments on stack. | | arguments on stack. |
3183: | | | |
3184: +-----------------------+ +-----------------------+
3185: | 4 words to save | | 4 words to save |
3186: | arguments passed | | arguments passed |
3187: | in registers, even | | in registers, even |
3188: SP->| if not passed. | FP->| if not passed. |
3189: +-----------------------+ +-----------------------+
3190: | |
3191: | GP save for V.4 abi |
3192: | |
3193: +-----------------------+
3194: | |
3195: | local variables |
3196: | |
3197: +-----------------------+
3198: | |
3199: | fp register save |
3200: | |
3201: +-----------------------+
3202: | |
3203: | gp register save |
3204: | |
3205: +-----------------------+
3206: | |
3207: | alloca allocations |
3208: | |
3209: +-----------------------+
3210: | |
3211: | arguments on stack |
3212: | |
3213: +-----------------------+
3214: | 4 words to save |
3215: | arguments passed |
3216: | in registers, even |
3217: low SP->| if not passed. |
3218: memory +-----------------------+
3219:
3220: */
3221:
3222: unsigned long
3223: compute_frame_size (size)
3224: int size; /* # of var. bytes allocated */
3225: {
3226: int regno;
3227: unsigned long total_size; /* # bytes that the entire frame takes up */
3228: unsigned long var_size; /* # bytes that variables take up */
3229: unsigned long args_size; /* # bytes that outgoing arguments take up */
3230: unsigned long extra_size; /* # extra bytes */
3231: unsigned int gp_reg_rounded; /* # bytes needed to store gp after rounding */
3232: unsigned int gp_reg_size; /* # bytes needed to store gp regs */
3233: unsigned int fp_reg_size; /* # bytes needed to store fp regs */
3234: unsigned long mask; /* mask of saved gp registers */
3235: unsigned long fmask; /* mask of saved fp registers */
3236: int fp_inc; /* 1 or 2 depending on the size of fp regs */
3237: int fp_bits; /* bitmask to use for each fp register */
3238:
3239: extra_size = MIPS_STACK_ALIGN (((TARGET_ABICALLS) ? UNITS_PER_WORD : 0)
3240: -STARTING_FRAME_OFFSET);
3241:
3242: var_size = MIPS_STACK_ALIGN (size);
3243: args_size = MIPS_STACK_ALIGN (current_function_outgoing_args_size);
3244: total_size = var_size + args_size + extra_size;
3245: gp_reg_size = 0;
3246: fp_reg_size = 0;
3247: mask = 0;
3248: fmask = 0;
3249:
3250: /* Calculate space needed for gp registers. */
3251: for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
3252: {
3253: if (MUST_SAVE_REGISTER (regno))
3254: {
3255: gp_reg_size += UNITS_PER_WORD;
3256: mask |= 1 << (regno - GP_REG_FIRST);
3257: }
3258: }
3259:
3260: /* Calculate space needed for fp registers. */
3261: if (TARGET_FLOAT64)
3262: {
3263: fp_inc = 1;
3264: fp_bits = 1;
3265: }
3266: else
3267: {
3268: fp_inc = 2;
3269: fp_bits = 3;
3270: }
3271:
3272: for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno += fp_inc)
3273: {
3274: if (regs_ever_live[regno] && !call_used_regs[regno])
3275: {
3276: fp_reg_size += 2*UNITS_PER_WORD;
3277: fmask |= fp_bits << (regno - FP_REG_FIRST);
3278: }
3279: }
3280:
3281: gp_reg_rounded = MIPS_STACK_ALIGN (gp_reg_size);
3282: total_size += gp_reg_rounded + fp_reg_size;
3283:
3284: if (total_size == extra_size)
3285: total_size = extra_size = 0;
3286:
3287: /* Save other computed information. */
3288: current_frame_info.total_size = total_size;
3289: current_frame_info.var_size = var_size;
3290: current_frame_info.args_size = args_size;
3291: current_frame_info.extra_size = extra_size;
3292: current_frame_info.gp_reg_size = gp_reg_size;
3293: current_frame_info.fp_reg_size = fp_reg_size;
3294: current_frame_info.mask = mask;
3295: current_frame_info.fmask = fmask;
3296: current_frame_info.initialized = reload_completed;
3297:
3298: if (mask)
3299: {
3300: unsigned long offset = args_size + gp_reg_size - UNITS_PER_WORD;
3301: current_frame_info.gp_sp_offset = offset;
3302: current_frame_info.gp_save_offset = offset - total_size;
3303: }
3304:
3305: if (fmask)
3306: {
3307: unsigned long offset = args_size + gp_reg_rounded + fp_reg_size - 2*UNITS_PER_WORD;
3308: current_frame_info.fp_sp_offset = offset;
3309: current_frame_info.fp_save_offset = offset - total_size + UNITS_PER_WORD;
3310: }
3311:
3312: /* Ok, we're done. */
3313: return total_size;
3314: }
3315:
3316:
3317: /* Common code to save/restore registers. */
3318:
3319: void
3320: save_restore (file, gp_op, gp_2word_op, fp_op)
3321: FILE *file; /* stream to write to */
3322: char *gp_op; /* operation to do on gp registers */
3323: char *gp_2word_op; /* 2 word op to do on gp registers */
3324: char *fp_op; /* operation to do on fp registers */
3325: {
3326: int regno;
3327: unsigned long mask = current_frame_info.mask;
3328: unsigned long fmask = current_frame_info.fmask;
3329: unsigned long gp_offset;
3330: unsigned long fp_offset;
3331: unsigned long max_offset;
3332: char *base_reg;
3333:
3334: if (mask == 0 && fmask == 0)
3335: return;
3336:
3337: base_reg = reg_names[STACK_POINTER_REGNUM];
3338: gp_offset = current_frame_info.gp_sp_offset;
3339: fp_offset = current_frame_info.fp_sp_offset;
3340: max_offset = (gp_offset > fp_offset) ? gp_offset : fp_offset;
3341:
3342: /* Deal with calling functions with a large structure. */
3343: if (max_offset >= 32768)
3344: {
3345: char *temp = reg_names[MIPS_TEMP2_REGNUM];
3346: fprintf (file, "\tli\t%s,%ld\n", temp, max_offset);
3347: fprintf (file, "\taddu\t%s,%s,%s\n", temp, temp, base_reg);
3348: base_reg = temp;
3349: gp_offset = max_offset - gp_offset;
3350: fp_offset = max_offset - fp_offset;
3351: }
3352:
3353: /* Save registers starting from high to low. The debuggers prefer
3354: at least the return register be stored at func+4, and also it
3355: allows us not to need a nop in the epilog if at least one
3356: register is reloaded in addition to return address. */
3357:
3358: if (mask || frame_pointer_needed)
3359: {
3360: for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
3361: {
3362: if ((mask & (1L << (regno - GP_REG_FIRST))) != 0
3363: || (regno == FRAME_POINTER_REGNUM && frame_pointer_needed))
3364: {
3365: fprintf (file, "\t%s\t%s,%d(%s)\n",
3366: gp_op, reg_names[regno],
3367: gp_offset, base_reg);
3368:
3369: gp_offset -= UNITS_PER_WORD;
3370: }
3371: }
3372: }
3373:
3374: if (fmask)
3375: {
3376: int fp_inc = (TARGET_FLOAT64) ? 1 : 2;
3377:
3378: for (regno = FP_REG_LAST-1; regno >= FP_REG_FIRST; regno -= fp_inc)
3379: {
3380: if ((fmask & (1L << (regno - FP_REG_FIRST))) != 0)
3381: {
3382: fprintf (file, "\t%s\t%s,%d(%s)\n",
3383: fp_op, reg_names[regno], fp_offset, base_reg);
3384:
3385: fp_offset -= 2*UNITS_PER_WORD;
3386: }
3387: }
3388: }
3389: }
3390:
3391:
3392: /* Set up the stack and frame (if desired) for the function. */
3393:
3394: void
3395: function_prologue (file, size)
3396: FILE *file;
3397: int size;
3398: {
3399: int regno;
3400: int tsize;
3401: char *sp_str = reg_names[STACK_POINTER_REGNUM];
3402: char *fp_str = (!frame_pointer_needed)
3403: ? sp_str
3404: : reg_names[FRAME_POINTER_REGNUM];
3405: tree fndecl = current_function_decl; /* current... is tooo long */
3406: tree fntype = TREE_TYPE (fndecl);
3407: tree fnargs = (TREE_CODE (fntype) != METHOD_TYPE)
3408: ? DECL_ARGUMENTS (fndecl)
3409: : 0;
3410: tree next_arg;
3411: tree cur_arg;
3412: char *arg_name = (char *)0;
3413: CUMULATIVE_ARGS args_so_far;
3414:
3415: ASM_OUTPUT_SOURCE_FILENAME (file, DECL_SOURCE_FILE (current_function_decl));
3416: ASM_OUTPUT_SOURCE_LINE (file, DECL_SOURCE_LINE (current_function_decl));
3417:
3418: inside_function = 1;
3419: fputs ("\t.ent\t", file);
3420: assemble_name (file, current_function_name);
3421: fputs ("\n", file);
3422: assemble_name (file, current_function_name);
3423: fputs (":\n", file);
3424:
3425: if (TARGET_ABICALLS)
3426: fprintf (file,
3427: "\t.set\tnoreorder\n\t.cpload\t%s\n\t.set\treorder\n",
3428: reg_names[ GP_REG_FIRST + 25 ]);
3429:
3430: /* Determine the last argument, and get its name. */
3431: for (cur_arg = fnargs; cur_arg != (tree)0; cur_arg = next_arg)
3432: {
3433: next_arg = TREE_CHAIN (cur_arg);
3434: if (next_arg == (tree)0)
3435: {
3436: if (DECL_NAME (cur_arg))
3437: arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg));
3438:
3439: break;
3440: }
3441: }
3442:
3443: /* If this function is a varargs function, store any registers that
3444: would normally hold arguments ($4 - $7) on the stack. */
3445: if ((TYPE_ARG_TYPES (fntype) != 0
3446: && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node))
3447: || (arg_name
3448: && (strcmp (arg_name, "__builtin_va_alist") == 0
3449: || strcmp (arg_name, "va_alist") == 0)))
3450: {
3451: tree parm;
3452:
3453: regno = GP_ARG_FIRST;
3454: INIT_CUMULATIVE_ARGS (args_so_far, fntype, (rtx)0);
3455:
3456: for (parm = fnargs; (parm && (regno <= GP_ARG_LAST)); parm = TREE_CHAIN (parm))
3457: {
3458: rtx entry_parm;
3459: enum machine_mode passed_mode;
3460: tree type;
3461:
3462: type = DECL_ARG_TYPE (parm);
3463: passed_mode = TYPE_MODE (type);
3464: entry_parm = FUNCTION_ARG (args_so_far, passed_mode,
3465: DECL_ARG_TYPE (parm), 1);
3466:
3467: if (entry_parm)
3468: {
3469: int words;
3470:
3471: /* passed in a register, so will get homed automatically */
3472: if (GET_MODE (entry_parm) == BLKmode)
3473: words = (int_size_in_bytes (type) + 3) / 4;
3474: else
3475: words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;
3476:
3477: regno = REGNO (entry_parm) + words - 1;
3478: }
3479: else
3480: {
3481: regno = GP_ARG_LAST+1;
3482: break;
3483: }
3484:
3485: FUNCTION_ARG_ADVANCE (args_so_far, passed_mode,
3486: DECL_ARG_TYPE (parm), 1);
3487: }
3488:
3489: if (regno <= GP_ARG_LAST && (regno & 1) != 0)
3490: {
3491: fprintf (file, "\tsw\t%s,%d(%s)\t\t# varargs home register\n",
3492: reg_names[regno], (regno - 4) * 4, sp_str);
3493: regno++;
3494: }
3495:
3496: for (; regno <= GP_ARG_LAST; regno += 2)
3497: {
3498: fprintf (file, "\tsd\t%s,%d(%s)\t\t# varargs home register\n",
3499: reg_names[regno], (regno - 4) * 4, sp_str);
3500: }
3501: }
3502:
3503: size = MIPS_STACK_ALIGN (size);
3504: tsize = (!current_frame_info.initialized)
3505: ? compute_frame_size (size)
3506: : current_frame_info.total_size;
3507:
3508: if (tsize > 0)
3509: {
3510: if (tsize <= 32767)
3511: fprintf (file,
3512: "\tsubu\t%s,%s,%d\t\t# vars= %d, regs= %d/%d, args = %d, extra= %d\n",
3513: sp_str, sp_str, tsize, current_frame_info.var_size,
3514: current_frame_info.gp_reg_size / 4,
3515: current_frame_info.fp_reg_size / 8,
3516: current_function_outgoing_args_size,
3517: current_frame_info.extra_size);
3518: else
3519: fprintf (file,
3520: "\tli\t%s,%d\n\tsubu\t%s,%s,%s\t\t# vars= %d, regs= %d/%d, args = %d, sfo= %d\n",
3521: reg_names[MIPS_TEMP1_REGNUM], tsize, sp_str, sp_str,
3522: reg_names[MIPS_TEMP1_REGNUM], current_frame_info.var_size,
3523: current_frame_info.gp_reg_size / 4,
3524: current_frame_info.fp_reg_size / 8,
3525: current_function_outgoing_args_size,
3526: current_frame_info.extra_size);
3527: }
3528:
3529: if (TARGET_ABICALLS)
3530: fprintf (file, "\t.cprestore %d\n", tsize + STARTING_FRAME_OFFSET);
3531:
3532: fprintf (file, "\t.frame\t%s,%d,%s\n\t.mask\t0x%08lx,%d\n\t.fmask\t0x%08lx,%d\n",
3533: fp_str,
3534: (frame_pointer_needed) ? 0 : tsize,
3535: reg_names[31 + GP_REG_FIRST],
3536: current_frame_info.mask,
3537: current_frame_info.gp_save_offset,
3538: current_frame_info.fmask,
3539: current_frame_info.fp_save_offset);
3540:
3541: save_restore (file, "sw", "sd", "s.d");
3542:
3543: if (frame_pointer_needed)
3544: {
3545: if (tsize <= 32767)
3546: fprintf (file, "\taddu\t%s,%s,%d\t# set up frame pointer\n", fp_str, sp_str, tsize);
3547:
3548: else
3549: fprintf (file, "\taddu\t%s,%s,%s\t# set up frame pointer\n", fp_str, sp_str,
3550: reg_names[MIPS_TEMP1_REGNUM]);
3551: }
3552: }
3553:
3554:
3555: /* Do any necessary cleanup after a function to restore stack, frame, and regs. */
3556:
3557: void
3558: function_epilogue (file, size)
3559: FILE *file;
3560: int size;
3561: {
3562: int tsize;
3563: char *sp_str = reg_names[STACK_POINTER_REGNUM];
3564: char *t1_str = reg_names[MIPS_TEMP1_REGNUM];
3565: rtx epilogue_delay = current_function_epilogue_delay_list;
3566: int noreorder = !TARGET_MIPS_AS || (epilogue_delay != 0);
3567: int noepilogue = FALSE;
3568: int load_nop = FALSE;
3569: int load_only_r31;
3570:
3571: /* The epilogue does not depend on any registers, but the stack
3572: registers, so we assume that if we have 1 pending nop, it can be
3573: ignored, and 2 it must be filled (2 nops occur for integer
3574: multiply and divide). */
3575:
3576: if (dslots_number_nops > 0)
3577: {
3578: if (dslots_number_nops == 1)
3579: {
3580: dslots_number_nops = 0;
3581: dslots_load_filled++;
3582: }
3583: else
3584: {
3585: while (--dslots_number_nops > 0)
3586: fputs ((set_noreorder) ? "\tnop\n" : "\t#nop\n", asm_out_file);
3587: }
3588:
3589: if (set_noreorder > 0 && --set_noreorder == 0)
3590: fputs ("\t.set\treorder\n", file);
3591: }
3592:
3593: if (set_noat != 0)
3594: {
3595: set_noat = 0;
3596: fputs ("\t.set\tat\n", file);
3597: error ("internal gcc error: .set noat left on in epilogue");
3598: }
3599:
3600: if (set_nomacro != 0)
3601: {
3602: set_nomacro = 0;
3603: fputs ("\t.set\tmacro\n", file);
3604: error ("internal gcc error: .set nomacro left on in epilogue");
3605: }
3606:
3607: if (set_noreorder != 0)
3608: {
3609: set_noreorder = 0;
3610: fputs ("\t.set\treorder\n", file);
3611: error ("internal gcc error: .set noreorder left on in epilogue");
3612: }
3613:
3614: if (set_volatile != 0)
3615: {
3616: set_volatile = 0;
3617: fprintf (file, "\t#.set\tnovolatile\n", (TARGET_MIPS_AS) ? "" : "#");
3618: error ("internal gcc error: .set volatile left on in epilogue");
3619: }
3620:
3621: size = MIPS_STACK_ALIGN (size);
3622: tsize = (!current_frame_info.initialized)
3623: ? compute_frame_size (size)
3624: : current_frame_info.total_size;
3625:
3626: if (tsize == 0 && epilogue_delay == 0)
3627: {
3628: rtx insn = get_last_insn ();
3629:
3630: /* If the last insn was a BARRIER, we don't have to write any code
3631: because a jump (aka return) was put there. */
3632: if (GET_CODE (insn) == NOTE)
3633: insn = prev_nonnote_insn (insn);
3634: if (insn && GET_CODE (insn) == BARRIER)
3635: noepilogue = TRUE;
3636:
3637: noreorder = FALSE;
3638: }
3639:
3640: if (!noepilogue)
3641: {
3642: /* In the reload sequence, we don't need to fill the load delay
3643: slots for most of the loads, also see if we can fill the final
3644: delay slot if not otherwise filled by the reload sequence. */
3645:
3646: if (noreorder)
3647: fprintf (file, "\t.set\tnoreorder\n");
3648:
3649: if (tsize > 32767)
3650: fprintf (file, "\tli\t%s,%d\n", t1_str, tsize);
3651:
3652: if (frame_pointer_needed)
3653: {
3654: char *fp_str = reg_names[FRAME_POINTER_REGNUM];
3655: if (tsize > 32767)
3656: fprintf (file,"\tsubu\t%s,%s,%s\t\t# sp not trusted here\n",
3657: sp_str, fp_str, t1_str);
3658: else
3659: fprintf (file,"\tsubu\t%s,%s,%d\t\t# sp not trusted here\n",
3660: sp_str, fp_str, tsize);
3661: }
3662:
3663: save_restore (file, "lw", "ld", "l.d");
3664:
3665: load_only_r31 = (current_frame_info.mask == (1 << 31)
3666: && current_frame_info.fmask == 0);
3667:
3668: if (noreorder)
3669: {
3670: /* If the only register saved is the return address, we need a
3671: nop, unless we have an instruction to put into it. Otherwise
3672: we don't since reloading multiple registers doesn't reference
3673: the register being loaded. */
3674:
3675: if (load_only_r31)
3676: {
3677: if (epilogue_delay)
3678: final_scan_insn (XEXP (epilogue_delay, 0),
3679: file,
3680: 1, /* optimize */
3681: -2, /* prescan */
3682: 1); /* nopeepholes */
3683: else
3684: {
3685: fprintf (file, "\tnop\n");
3686: load_nop = TRUE;
3687: }
3688: }
3689:
3690: fprintf (file, "\tj\t%s\n", reg_names[GP_REG_FIRST + 31]);
3691:
3692: if (tsize > 32767)
3693: fprintf (file, "\taddu\t%s,%s,%s\n", sp_str, sp_str, t1_str);
3694:
3695: else if (tsize > 0)
3696: fprintf (file, "\taddu\t%s,%s,%d\n", sp_str, sp_str, tsize);
3697:
3698: else if (!load_only_r31 && epilogue_delay != 0)
3699: final_scan_insn (XEXP (epilogue_delay, 0),
3700: file,
3701: 1, /* optimize */
3702: -2, /* prescan */
3703: 1); /* nopeepholes */
3704:
3705: fprintf (file, "\t.set\treorder\n");
3706: }
3707:
3708: else
3709: {
3710: if (tsize > 32767)
3711: fprintf (file, "\taddu\t%s,%s,%s\n", sp_str, sp_str, t1_str);
3712:
3713: else if (tsize > 0)
3714: fprintf (file, "\taddu\t%s,%s,%d\n", sp_str, sp_str, tsize);
3715:
3716: fprintf (file, "\tj\t%s\n", reg_names[GP_REG_FIRST + 31]);
3717: }
3718: }
3719:
3720: fputs ("\t.end\t", file);
3721: assemble_name (file, current_function_name);
3722: fputs ("\n", file);
3723:
3724: if (TARGET_STATS)
3725: {
3726: int num_gp_regs = current_frame_info.gp_reg_size / 4;
3727: int num_fp_regs = current_frame_info.fp_reg_size / 8;
3728: int num_regs = num_gp_regs + num_fp_regs;
3729:
3730: dslots_load_total += num_regs;
3731:
3732: if (!noepilogue)
3733: dslots_jump_total++;
3734:
3735: if (noreorder)
3736: {
3737: dslots_load_filled += num_regs;
3738:
3739: /* If the only register saved is the return register, we
3740: can't fill this register's delay slot. */
3741:
3742: if (load_only_r31 && epilogue_delay == 0)
3743: dslots_load_filled--;
3744:
3745: if (tsize > 0 || (!load_only_r31 && epilogue_delay != 0))
3746: dslots_jump_filled++;
3747: }
3748:
3749: fprintf (stderr,
3750: "%-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",
3751: current_function_name,
3752: (frame_pointer_needed) ? 'y' : 'n',
3753: ((current_frame_info.mask & (1 << 31)) != 0) ? 'n' : 'y',
3754: (current_function_calls_alloca) ? 'y' : 'n',
3755: (current_function_calls_setjmp) ? 'y' : 'n',
3756: (long)current_frame_info.total_size,
3757: (long)current_function_outgoing_args_size,
3758: num_gp_regs, num_fp_regs,
3759: dslots_load_total, dslots_load_filled,
3760: dslots_jump_total, dslots_jump_filled,
3761: num_refs[0], num_refs[1], num_refs[2]);
3762: }
3763:
3764: /* Reset state info for each function. */
3765: inside_function = FALSE;
3766: ignore_line_number = FALSE;
3767: dslots_load_total = 0;
3768: dslots_jump_total = 0;
3769: dslots_load_filled = 0;
3770: dslots_jump_filled = 0;
3771: num_refs[0] = 0;
3772: num_refs[1] = 0;
3773: num_refs[2] = 0;
3774: mips_load_reg = (rtx)0;
3775: mips_load_reg2 = (rtx)0;
3776: number_functions_processed++;
3777: current_frame_info = zero_frame_info;
3778:
3779: /* Restore the output file if optimizing the GP (optimizing the GP causes
3780: the text to be diverted to a tempfile, so that data decls come before
3781: references to the data). */
3782:
3783: if (TARGET_GP_OPT)
3784: asm_out_file = asm_out_data_file;
3785: }
3786:
3787:
3788: /* Define the number of delay slots needed for the function epilogue.
3789:
3790: On the mips, we need a slot if either no stack has been allocated,
3791: or the only register saved is the return register. */
3792:
3793: int
3794: mips_epilogue_delay_slots ()
3795: {
3796: if (!current_frame_info.initialized)
3797: (void) compute_frame_size (get_frame_size ());
3798:
3799: if (current_frame_info.total_size == 0)
3800: return 1;
3801:
3802: if (current_frame_info.mask == (1 << 31) && current_frame_info.fmask == 0)
3803: return 1;
3804:
3805: return 0;
3806: }
3807:
3808:
3809: /* Return true if this function is known to have a null epilogue.
3810: This allows the optimizer to omit jumps to jumps if no stack
3811: was created. */
3812:
3813: int
3814: null_epilogue ()
3815: {
3816: if (!reload_completed)
3817: return 0;
3818:
3819: if (current_frame_info.initialized)
3820: return current_frame_info.total_size == 0;
3821:
3822: return (compute_frame_size (get_frame_size ())) == 0;
3823: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.