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