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