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