1179404Sobrien/* tc-mips.c -- assemble code for a MIPS chip.
2179404Sobrien   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
3218822Sdim   2003, 2004, 2005, 2006 Free Software Foundation, Inc.
4179404Sobrien   Contributed by the OSF and Ralph Campbell.
5179404Sobrien   Written by Keith Knowles and Ralph Campbell, working independently.
6179404Sobrien   Modified for ECOFF and R4000 support by Ian Lance Taylor of Cygnus
7179404Sobrien   Support.
8179404Sobrien
9179404Sobrien   This file is part of GAS.
10179404Sobrien
11179404Sobrien   GAS is free software; you can redistribute it and/or modify
12179404Sobrien   it under the terms of the GNU General Public License as published by
13179404Sobrien   the Free Software Foundation; either version 2, or (at your option)
14179404Sobrien   any later version.
15179404Sobrien
16179404Sobrien   GAS is distributed in the hope that it will be useful,
17179404Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
18179404Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19179404Sobrien   GNU General Public License for more details.
20179404Sobrien
21179404Sobrien   You should have received a copy of the GNU General Public License
22179404Sobrien   along with GAS; see the file COPYING.  If not, write to the Free
23208737Sjmallett   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
24208737Sjmallett   02110-1301, USA.  */
25179404Sobrien
26179404Sobrien#include "as.h"
27179404Sobrien#include "config.h"
28179404Sobrien#include "subsegs.h"
29179404Sobrien#include "safe-ctype.h"
30179404Sobrien
31179404Sobrien#include "opcode/mips.h"
32179404Sobrien#include "itbl-ops.h"
33179404Sobrien#include "dwarf2dbg.h"
34208737Sjmallett#include "dw2gencfi.h"
35179404Sobrien
36179404Sobrien#ifdef DEBUG
37179404Sobrien#define DBG(x) printf x
38179404Sobrien#else
39179404Sobrien#define DBG(x)
40179404Sobrien#endif
41179404Sobrien
42179404Sobrien#ifdef OBJ_MAYBE_ELF
43179404Sobrien/* Clean up namespace so we can include obj-elf.h too.  */
44179404Sobrienstatic int mips_output_flavor (void);
45179404Sobrienstatic int mips_output_flavor (void) { return OUTPUT_FLAVOR; }
46179404Sobrien#undef OBJ_PROCESS_STAB
47179404Sobrien#undef OUTPUT_FLAVOR
48179404Sobrien#undef S_GET_ALIGN
49179404Sobrien#undef S_GET_SIZE
50179404Sobrien#undef S_SET_ALIGN
51179404Sobrien#undef S_SET_SIZE
52179404Sobrien#undef obj_frob_file
53179404Sobrien#undef obj_frob_file_after_relocs
54179404Sobrien#undef obj_frob_symbol
55179404Sobrien#undef obj_pop_insert
56179404Sobrien#undef obj_sec_sym_ok_for_reloc
57179404Sobrien#undef OBJ_COPY_SYMBOL_ATTRIBUTES
58179404Sobrien
59179404Sobrien#include "obj-elf.h"
60179404Sobrien/* Fix any of them that we actually care about.  */
61179404Sobrien#undef OUTPUT_FLAVOR
62179404Sobrien#define OUTPUT_FLAVOR mips_output_flavor()
63179404Sobrien#endif
64179404Sobrien
65179404Sobrien#if defined (OBJ_ELF)
66179404Sobrien#include "elf/mips.h"
67179404Sobrien#endif
68179404Sobrien
69179404Sobrien#ifndef ECOFF_DEBUGGING
70179404Sobrien#define NO_ECOFF_DEBUGGING
71179404Sobrien#define ECOFF_DEBUGGING 0
72179404Sobrien#endif
73179404Sobrien
74179404Sobrienint mips_flag_mdebug = -1;
75179404Sobrien
76179404Sobrien/* Control generation of .pdr sections.  Off by default on IRIX: the native
77179404Sobrien   linker doesn't know about and discards them, but relocations against them
78179404Sobrien   remain, leading to rld crashes.  */
79179404Sobrien#ifdef TE_IRIX
80179404Sobrienint mips_flag_pdr = FALSE;
81179404Sobrien#else
82179404Sobrienint mips_flag_pdr = TRUE;
83179404Sobrien#endif
84179404Sobrien
85208737Sjmallett/* Control generation of error message for unsupported instructions in
86208737Sjmallett   Octeon. Octeon does not have floating point, and all the instructions
87208737Sjmallett   that use floating point registers are not allowed in Elf targets but
88208737Sjmallett   are allowed in Linux targets by default.  */
89208737Sjmallett#ifdef OCTEON_ERROR_ON_UNSUPPORTED
90208737Sjmallettstatic int octeon_error_on_unsupported = 1;
91208737Sjmallett#else
92208737Sjmallettstatic int octeon_error_on_unsupported = 0;
93208737Sjmallett#endif
94208737Sjmallett
95208737Sjmallett/* Control generation of Octeon/MIPS unaligned load/store instructions.
96208737Sjmallett   For ELF target, default to Octeon load/store instructions.
97208737Sjmallett   For Linux target, default to MIPS load/store instructions.  */
98208737Sjmallett#ifdef OCTEON_USE_UNALIGN
99208737Sjmallettstatic int octeon_use_unalign = 1;
100208737Sjmallett#else
101208737Sjmallettstatic int octeon_use_unalign = 0;
102208737Sjmallett#endif
103208737Sjmallett
104179404Sobrien#include "ecoff.h"
105179404Sobrien
106179404Sobrien#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
107179404Sobrienstatic char *mips_regmask_frag;
108179404Sobrien#endif
109179404Sobrien
110179404Sobrien#define ZERO 0
111179404Sobrien#define AT  1
112179404Sobrien#define TREG 24
113179404Sobrien#define PIC_CALL_REG 25
114179404Sobrien#define KT0 26
115179404Sobrien#define KT1 27
116179404Sobrien#define GP  28
117179404Sobrien#define SP  29
118179404Sobrien#define FP  30
119179404Sobrien#define RA  31
120179404Sobrien
121179404Sobrien#define ILLEGAL_REG (32)
122179404Sobrien
123179404Sobrien/* Allow override of standard little-endian ECOFF format.  */
124179404Sobrien
125179404Sobrien#ifndef ECOFF_LITTLE_FORMAT
126179404Sobrien#define ECOFF_LITTLE_FORMAT "ecoff-littlemips"
127179404Sobrien#endif
128179404Sobrien
129179404Sobrienextern int target_big_endian;
130179404Sobrien
131179404Sobrien/* The name of the readonly data section.  */
132208737Sjmallett#define RDATA_SECTION_NAME (OUTPUT_FLAVOR == bfd_target_ecoff_flavour \
133179404Sobrien			    ? ".rdata" \
134179404Sobrien			    : OUTPUT_FLAVOR == bfd_target_coff_flavour \
135179404Sobrien			    ? ".rdata" \
136179404Sobrien			    : OUTPUT_FLAVOR == bfd_target_elf_flavour \
137179404Sobrien			    ? ".rodata" \
138179404Sobrien			    : (abort (), ""))
139179404Sobrien
140208737Sjmallett/* Information about an instruction, including its format, operands
141208737Sjmallett   and fixups.  */
142208737Sjmallettstruct mips_cl_insn
143208737Sjmallett{
144208737Sjmallett  /* The opcode's entry in mips_opcodes or mips16_opcodes.  */
145208737Sjmallett  const struct mips_opcode *insn_mo;
146208737Sjmallett
147208737Sjmallett  /* True if this is a mips16 instruction and if we want the extended
148208737Sjmallett     form of INSN_MO.  */
149208737Sjmallett  bfd_boolean use_extend;
150208737Sjmallett
151208737Sjmallett  /* The 16-bit extension instruction to use when USE_EXTEND is true.  */
152208737Sjmallett  unsigned short extend;
153208737Sjmallett
154208737Sjmallett  /* The 16-bit or 32-bit bitstring of the instruction itself.  This is
155208737Sjmallett     a copy of INSN_MO->match with the operands filled in.  */
156208737Sjmallett  unsigned long insn_opcode;
157208737Sjmallett
158208737Sjmallett  /* The frag that contains the instruction.  */
159208737Sjmallett  struct frag *frag;
160208737Sjmallett
161208737Sjmallett  /* The offset into FRAG of the first instruction byte.  */
162208737Sjmallett  long where;
163208737Sjmallett
164208737Sjmallett  /* The relocs associated with the instruction, if any.  */
165208737Sjmallett  fixS *fixp[3];
166208737Sjmallett
167208737Sjmallett  /* True if this entry cannot be moved from its current position.  */
168208737Sjmallett  unsigned int fixed_p : 1;
169208737Sjmallett
170218822Sdim  /* True if this instruction occurred in a .set noreorder block.  */
171208737Sjmallett  unsigned int noreorder_p : 1;
172208737Sjmallett
173208737Sjmallett  /* True for mips16 instructions that jump to an absolute address.  */
174208737Sjmallett  unsigned int mips16_absolute_jump_p : 1;
175208737Sjmallett};
176208737Sjmallett
177179404Sobrien/* The ABI to use.  */
178179404Sobrienenum mips_abi_level
179179404Sobrien{
180179404Sobrien  NO_ABI = 0,
181179404Sobrien  O32_ABI,
182179404Sobrien  O64_ABI,
183179404Sobrien  N32_ABI,
184179404Sobrien  N64_ABI,
185179404Sobrien  EABI_ABI
186179404Sobrien};
187179404Sobrien
188179404Sobrien/* MIPS ABI we are using for this output file.  */
189179404Sobrienstatic enum mips_abi_level mips_abi = NO_ABI;
190179404Sobrien
191179404Sobrien/* Whether or not we have code that can call pic code.  */
192179404Sobrienint mips_abicalls = FALSE;
193179404Sobrien
194208737Sjmallett/* Whether or not we have code which can be put into a shared
195208737Sjmallett   library.  */
196208737Sjmallettstatic bfd_boolean mips_in_shared = TRUE;
197208737Sjmallett
198179404Sobrien/* This is the set of options which may be modified by the .set
199179404Sobrien   pseudo-op.  We use a struct so that .set push and .set pop are more
200179404Sobrien   reliable.  */
201179404Sobrien
202179404Sobrienstruct mips_set_options
203179404Sobrien{
204179404Sobrien  /* MIPS ISA (Instruction Set Architecture) level.  This is set to -1
205179404Sobrien     if it has not been initialized.  Changed by `.set mipsN', and the
206179404Sobrien     -mipsN command line option, and the default CPU.  */
207179404Sobrien  int isa;
208179404Sobrien  /* Enabled Application Specific Extensions (ASEs).  These are set to -1
209179404Sobrien     if they have not been initialized.  Changed by `.set <asename>', by
210179404Sobrien     command line options, and based on the default architecture.  */
211179404Sobrien  int ase_mips3d;
212179404Sobrien  int ase_mdmx;
213218822Sdim  int ase_smartmips;
214208737Sjmallett  int ase_dsp;
215218822Sdim  int ase_dspr2;
216208737Sjmallett  int ase_mt;
217179404Sobrien  /* Whether we are assembling for the mips16 processor.  0 if we are
218179404Sobrien     not, 1 if we are, and -1 if the value has not been initialized.
219179404Sobrien     Changed by `.set mips16' and `.set nomips16', and the -mips16 and
220179404Sobrien     -nomips16 command line options, and the default CPU.  */
221179404Sobrien  int mips16;
222179404Sobrien  /* Non-zero if we should not reorder instructions.  Changed by `.set
223179404Sobrien     reorder' and `.set noreorder'.  */
224179404Sobrien  int noreorder;
225179404Sobrien  /* Non-zero if we should not permit the $at ($1) register to be used
226179404Sobrien     in instructions.  Changed by `.set at' and `.set noat'.  */
227179404Sobrien  int noat;
228179404Sobrien  /* Non-zero if we should warn when a macro instruction expands into
229179404Sobrien     more than one machine instruction.  Changed by `.set nomacro' and
230179404Sobrien     `.set macro'.  */
231179404Sobrien  int warn_about_macros;
232179404Sobrien  /* Non-zero if we should not move instructions.  Changed by `.set
233179404Sobrien     move', `.set volatile', `.set nomove', and `.set novolatile'.  */
234179404Sobrien  int nomove;
235179404Sobrien  /* Non-zero if we should not optimize branches by moving the target
236179404Sobrien     of the branch into the delay slot.  Actually, we don't perform
237179404Sobrien     this optimization anyhow.  Changed by `.set bopt' and `.set
238179404Sobrien     nobopt'.  */
239179404Sobrien  int nobopt;
240179404Sobrien  /* Non-zero if we should not autoextend mips16 instructions.
241179404Sobrien     Changed by `.set autoextend' and `.set noautoextend'.  */
242179404Sobrien  int noautoextend;
243179404Sobrien  /* Restrict general purpose registers and floating point registers
244179404Sobrien     to 32 bit.  This is initially determined when -mgp32 or -mfp32
245179404Sobrien     is passed but can changed if the assembler code uses .set mipsN.  */
246179404Sobrien  int gp32;
247179404Sobrien  int fp32;
248179404Sobrien  /* MIPS architecture (CPU) type.  Changed by .set arch=FOO, the -march
249179404Sobrien     command line option, and the default CPU.  */
250179404Sobrien  int arch;
251208737Sjmallett  /* True if ".set sym32" is in effect.  */
252208737Sjmallett  bfd_boolean sym32;
253179404Sobrien};
254179404Sobrien
255179404Sobrien/* True if -mgp32 was passed.  */
256179404Sobrienstatic int file_mips_gp32 = -1;
257179404Sobrien
258179404Sobrien/* True if -mfp32 was passed.  */
259179404Sobrienstatic int file_mips_fp32 = -1;
260179404Sobrien
261179404Sobrien/* This is the struct we use to hold the current set of options.  Note
262179404Sobrien   that we must set the isa field to ISA_UNKNOWN and the ASE fields to
263179404Sobrien   -1 to indicate that they have not been initialized.  */
264179404Sobrien
265179404Sobrienstatic struct mips_set_options mips_opts =
266179404Sobrien{
267218822Sdim  ISA_UNKNOWN, -1, -1, 0, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, CPU_UNKNOWN, FALSE
268179404Sobrien};
269179404Sobrien
270179404Sobrien/* These variables are filled in with the masks of registers used.
271179404Sobrien   The object format code reads them and puts them in the appropriate
272179404Sobrien   place.  */
273179404Sobrienunsigned long mips_gprmask;
274179404Sobrienunsigned long mips_cprmask[4];
275179404Sobrien
276179404Sobrien/* MIPS ISA we are using for this output file.  */
277179404Sobrienstatic int file_mips_isa = ISA_UNKNOWN;
278179404Sobrien
279179404Sobrien/* True if -mips16 was passed or implied by arguments passed on the
280179404Sobrien   command line (e.g., by -march).  */
281179404Sobrienstatic int file_ase_mips16;
282179404Sobrien
283218822Sdim#define ISA_SUPPORTS_MIPS16E (mips_opts.isa == ISA_MIPS32		\
284218822Sdim			      || mips_opts.isa == ISA_MIPS32R2		\
285218822Sdim			      || mips_opts.isa == ISA_MIPS64		\
286218822Sdim			      || mips_opts.isa == ISA_MIPS64R2)
287218822Sdim
288179404Sobrien/* True if -mips3d was passed or implied by arguments passed on the
289179404Sobrien   command line (e.g., by -march).  */
290179404Sobrienstatic int file_ase_mips3d;
291179404Sobrien
292179404Sobrien/* True if -mdmx was passed or implied by arguments passed on the
293179404Sobrien   command line (e.g., by -march).  */
294179404Sobrienstatic int file_ase_mdmx;
295179404Sobrien
296218822Sdim/* True if -msmartmips was passed or implied by arguments passed on the
297218822Sdim   command line (e.g., by -march).  */
298218822Sdimstatic int file_ase_smartmips;
299218822Sdim
300218822Sdim#define ISA_SUPPORTS_SMARTMIPS (mips_opts.isa == ISA_MIPS32		\
301218822Sdim				|| mips_opts.isa == ISA_MIPS32R2)
302218822Sdim
303208737Sjmallett/* True if -mdsp was passed or implied by arguments passed on the
304208737Sjmallett   command line (e.g., by -march).  */
305208737Sjmallettstatic int file_ase_dsp;
306208737Sjmallett
307218822Sdim#define ISA_SUPPORTS_DSP_ASE (mips_opts.isa == ISA_MIPS32R2		\
308218822Sdim			      || mips_opts.isa == ISA_MIPS64R2)
309218822Sdim
310218822Sdim#define ISA_SUPPORTS_DSP64_ASE (mips_opts.isa == ISA_MIPS64R2)
311218822Sdim
312218822Sdim/* True if -mdspr2 was passed or implied by arguments passed on the
313218822Sdim   command line (e.g., by -march).  */
314218822Sdimstatic int file_ase_dspr2;
315218822Sdim
316218822Sdim#define ISA_SUPPORTS_DSPR2_ASE (mips_opts.isa == ISA_MIPS32R2		\
317218822Sdim			        || mips_opts.isa == ISA_MIPS64R2)
318218822Sdim
319208737Sjmallett/* True if -mmt was passed or implied by arguments passed on the
320208737Sjmallett   command line (e.g., by -march).  */
321208737Sjmallettstatic int file_ase_mt;
322208737Sjmallett
323218822Sdim#define ISA_SUPPORTS_MT_ASE (mips_opts.isa == ISA_MIPS32R2		\
324218822Sdim			     || mips_opts.isa == ISA_MIPS64R2)
325218822Sdim
326179404Sobrien/* The argument of the -march= flag.  The architecture we are assembling.  */
327179404Sobrienstatic int file_mips_arch = CPU_UNKNOWN;
328179404Sobrienstatic const char *mips_arch_string;
329179404Sobrien
330179404Sobrien/* The argument of the -mtune= flag.  The architecture for which we
331179404Sobrien   are optimizing.  */
332179404Sobrienstatic int mips_tune = CPU_UNKNOWN;
333179404Sobrienstatic const char *mips_tune_string;
334179404Sobrien
335179404Sobrien/* True when generating 32-bit code for a 64-bit processor.  */
336179404Sobrienstatic int mips_32bitmode = 0;
337179404Sobrien
338179404Sobrien/* True if the given ABI requires 32-bit registers.  */
339179404Sobrien#define ABI_NEEDS_32BIT_REGS(ABI) ((ABI) == O32_ABI)
340179404Sobrien
341179404Sobrien/* Likewise 64-bit registers.  */
342218822Sdim#define ABI_NEEDS_64BIT_REGS(ABI)	\
343218822Sdim  ((ABI) == N32_ABI 			\
344218822Sdim   || (ABI) == N64_ABI			\
345179404Sobrien   || (ABI) == O64_ABI)
346179404Sobrien
347218822Sdim/*  Return true if ISA supports 64 bit wide gp registers.  */
348218822Sdim#define ISA_HAS_64BIT_REGS(ISA)		\
349218822Sdim  ((ISA) == ISA_MIPS3			\
350218822Sdim   || (ISA) == ISA_MIPS4		\
351218822Sdim   || (ISA) == ISA_MIPS5		\
352218822Sdim   || (ISA) == ISA_MIPS64		\
353218822Sdim   || (ISA) == ISA_MIPS64R2)
354179404Sobrien
355218822Sdim/*  Return true if ISA supports 64 bit wide float registers.  */
356218822Sdim#define ISA_HAS_64BIT_FPRS(ISA)		\
357218822Sdim  ((ISA) == ISA_MIPS3			\
358218822Sdim   || (ISA) == ISA_MIPS4		\
359218822Sdim   || (ISA) == ISA_MIPS5		\
360218822Sdim   || (ISA) == ISA_MIPS32R2		\
361218822Sdim   || (ISA) == ISA_MIPS64		\
362218822Sdim   || (ISA) == ISA_MIPS64R2)
363218822Sdim
364179404Sobrien/* Return true if ISA supports 64-bit right rotate (dror et al.)
365179404Sobrien   instructions.  */
366218822Sdim#define ISA_HAS_DROR(ISA)		\
367218822Sdim  ((ISA) == ISA_MIPS64R2)
368179404Sobrien
369179404Sobrien/* Return true if ISA supports 32-bit right rotate (ror et al.)
370179404Sobrien   instructions.  */
371218822Sdim#define ISA_HAS_ROR(ISA)		\
372218822Sdim  ((ISA) == ISA_MIPS32R2		\
373218822Sdim   || (ISA) == ISA_MIPS64R2		\
374218822Sdim   || mips_opts.ase_smartmips)
375179404Sobrien
376208737Sjmallett/* Return true if ISA supports ins instructions. */
377218822Sdim#define ISA_HAS_INS(ISA)		\
378218822Sdim  ((ISA) == ISA_MIPS32R2		\
379218822Sdim  || (ISA) == ISA_MIPS64R2)
380208737Sjmallett
381218822Sdim/* Return true if ISA supports single-precision floats in odd registers.  */
382218822Sdim#define ISA_HAS_ODD_SINGLE_FPR(ISA)	\
383218822Sdim  ((ISA) == ISA_MIPS32			\
384218822Sdim   || (ISA) == ISA_MIPS32R2		\
385218822Sdim   || (ISA) == ISA_MIPS64		\
386218822Sdim   || (ISA) == ISA_MIPS64R2)
387218822Sdim
388218822Sdim/* Return true if ISA supports move to/from high part of a 64-bit
389218822Sdim   floating-point register. */
390218822Sdim#define ISA_HAS_MXHC1(ISA)		\
391218822Sdim  ((ISA) == ISA_MIPS32R2		\
392218822Sdim   || (ISA) == ISA_MIPS64R2)
393218822Sdim
394179404Sobrien#define HAVE_32BIT_GPRS		                   \
395218822Sdim    (mips_opts.gp32 || !ISA_HAS_64BIT_REGS (mips_opts.isa))
396179404Sobrien
397179404Sobrien#define HAVE_32BIT_FPRS                            \
398218822Sdim    (mips_opts.fp32 || !ISA_HAS_64BIT_FPRS (mips_opts.isa))
399179404Sobrien
400218822Sdim#define HAVE_64BIT_GPRS (!HAVE_32BIT_GPRS)
401218822Sdim#define HAVE_64BIT_FPRS (!HAVE_32BIT_FPRS)
402179404Sobrien
403179404Sobrien#define HAVE_NEWABI (mips_abi == N32_ABI || mips_abi == N64_ABI)
404179404Sobrien
405179404Sobrien#define HAVE_64BIT_OBJECTS (mips_abi == N64_ABI)
406179404Sobrien
407185925Simp/* True if relocations are stored in-place.  */
408185925Simp#define HAVE_IN_PLACE_ADDENDS (!HAVE_NEWABI)
409185925Simp
410208737Sjmallett/* The ABI-derived address size.  */
411208737Sjmallett#define HAVE_64BIT_ADDRESSES \
412208737Sjmallett  (HAVE_64BIT_GPRS && (mips_abi == EABI_ABI || mips_abi == N64_ABI))
413208737Sjmallett#define HAVE_32BIT_ADDRESSES (!HAVE_64BIT_ADDRESSES)
414179404Sobrien
415208737Sjmallett/* The size of symbolic constants (i.e., expressions of the form
416208737Sjmallett   "SYMBOL" or "SYMBOL + OFFSET").  */
417208737Sjmallett#define HAVE_32BIT_SYMBOLS \
418208737Sjmallett  (HAVE_32BIT_ADDRESSES || !HAVE_64BIT_OBJECTS || mips_opts.sym32)
419208737Sjmallett#define HAVE_64BIT_SYMBOLS (!HAVE_32BIT_SYMBOLS)
420179404Sobrien
421179404Sobrien/* Addresses are loaded in different ways, depending on the address size
422179404Sobrien   in use.  The n32 ABI Documentation also mandates the use of additions
423179404Sobrien   with overflow checking, but existing implementations don't follow it.  */
424179404Sobrien#define ADDRESS_ADD_INSN						\
425179404Sobrien   (HAVE_32BIT_ADDRESSES ? "addu" : "daddu")
426179404Sobrien
427179404Sobrien#define ADDRESS_ADDI_INSN						\
428179404Sobrien   (HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu")
429179404Sobrien
430179404Sobrien#define ADDRESS_LOAD_INSN						\
431179404Sobrien   (HAVE_32BIT_ADDRESSES ? "lw" : "ld")
432179404Sobrien
433179404Sobrien#define ADDRESS_STORE_INSN						\
434179404Sobrien   (HAVE_32BIT_ADDRESSES ? "sw" : "sd")
435179404Sobrien
436179404Sobrien/* Return true if the given CPU supports the MIPS16 ASE.  */
437179404Sobrien#define CPU_HAS_MIPS16(cpu)						\
438179404Sobrien   (strncmp (TARGET_CPU, "mips16", sizeof ("mips16") - 1) == 0		\
439179404Sobrien    || strncmp (TARGET_CANONICAL, "mips-lsi-elf", sizeof ("mips-lsi-elf") - 1) == 0)
440179404Sobrien
441179404Sobrien/* True if CPU has a dror instruction.  */
442179404Sobrien#define CPU_HAS_DROR(CPU)	((CPU) == CPU_VR5400 || (CPU) == CPU_VR5500)
443179404Sobrien
444179404Sobrien/* True if CPU has a ror instruction.  */
445179404Sobrien#define CPU_HAS_ROR(CPU)	CPU_HAS_DROR (CPU)
446179404Sobrien
447179404Sobrien/* True if mflo and mfhi can be immediately followed by instructions
448179404Sobrien   which write to the HI and LO registers.
449179404Sobrien
450179404Sobrien   According to MIPS specifications, MIPS ISAs I, II, and III need
451179404Sobrien   (at least) two instructions between the reads of HI/LO and
452179404Sobrien   instructions which write them, and later ISAs do not.  Contradicting
453179404Sobrien   the MIPS specifications, some MIPS IV processor user manuals (e.g.
454179404Sobrien   the UM for the NEC Vr5000) document needing the instructions between
455179404Sobrien   HI/LO reads and writes, as well.  Therefore, we declare only MIPS32,
456179404Sobrien   MIPS64 and later ISAs to have the interlocks, plus any specific
457179404Sobrien   earlier-ISA CPUs for which CPU documentation declares that the
458179404Sobrien   instructions are really interlocked.  */
459179404Sobrien#define hilo_interlocks \
460179404Sobrien  (mips_opts.isa == ISA_MIPS32                        \
461179404Sobrien   || mips_opts.isa == ISA_MIPS32R2                   \
462179404Sobrien   || mips_opts.isa == ISA_MIPS64                     \
463179404Sobrien   || mips_opts.isa == ISA_MIPS64R2                   \
464179404Sobrien   || mips_opts.arch == CPU_R4010                     \
465179404Sobrien   || mips_opts.arch == CPU_R10000                    \
466179404Sobrien   || mips_opts.arch == CPU_R12000                    \
467179404Sobrien   || mips_opts.arch == CPU_RM7000                    \
468179404Sobrien   || mips_opts.arch == CPU_VR5500                    \
469179404Sobrien   )
470179404Sobrien
471179404Sobrien/* Whether the processor uses hardware interlocks to protect reads
472179404Sobrien   from the GPRs after they are loaded from memory, and thus does not
473179404Sobrien   require nops to be inserted.  This applies to instructions marked
474179404Sobrien   INSN_LOAD_MEMORY_DELAY.  These nops are only required at MIPS ISA
475179404Sobrien   level I.  */
476179404Sobrien#define gpr_interlocks \
477179404Sobrien  (mips_opts.isa != ISA_MIPS1  \
478179404Sobrien   || mips_opts.arch == CPU_R3900)
479179404Sobrien
480179404Sobrien/* Whether the processor uses hardware interlocks to avoid delays
481179404Sobrien   required by coprocessor instructions, and thus does not require
482179404Sobrien   nops to be inserted.  This applies to instructions marked
483179404Sobrien   INSN_LOAD_COPROC_DELAY, INSN_COPROC_MOVE_DELAY, and to delays
484179404Sobrien   between instructions marked INSN_WRITE_COND_CODE and ones marked
485179404Sobrien   INSN_READ_COND_CODE.  These nops are only required at MIPS ISA
486179404Sobrien   levels I, II, and III.  */
487179404Sobrien/* Itbl support may require additional care here.  */
488179404Sobrien#define cop_interlocks                                \
489179404Sobrien  ((mips_opts.isa != ISA_MIPS1                        \
490179404Sobrien    && mips_opts.isa != ISA_MIPS2                     \
491179404Sobrien    && mips_opts.isa != ISA_MIPS3)                    \
492179404Sobrien   || mips_opts.arch == CPU_R4300                     \
493179404Sobrien   )
494179404Sobrien
495179404Sobrien/* Whether the processor uses hardware interlocks to protect reads
496179404Sobrien   from coprocessor registers after they are loaded from memory, and
497179404Sobrien   thus does not require nops to be inserted.  This applies to
498179404Sobrien   instructions marked INSN_COPROC_MEMORY_DELAY.  These nops are only
499179404Sobrien   requires at MIPS ISA level I.  */
500179404Sobrien#define cop_mem_interlocks (mips_opts.isa != ISA_MIPS1)
501179404Sobrien
502179404Sobrien/* Is this a mfhi or mflo instruction?  */
503179404Sobrien#define MF_HILO_INSN(PINFO) \
504179404Sobrien          ((PINFO & INSN_READ_HI) || (PINFO & INSN_READ_LO))
505179404Sobrien
506179404Sobrien/* MIPS PIC level.  */
507179404Sobrien
508179404Sobrienenum mips_pic_level mips_pic;
509179404Sobrien
510179404Sobrien/* 1 if we should generate 32 bit offsets from the $gp register in
511179404Sobrien   SVR4_PIC mode.  Currently has no meaning in other modes.  */
512179404Sobrienstatic int mips_big_got = 0;
513179404Sobrien
514179404Sobrien/* 1 if trap instructions should used for overflow rather than break
515179404Sobrien   instructions.  */
516179404Sobrienstatic int mips_trap = 0;
517179404Sobrien
518179404Sobrien/* 1 if double width floating point constants should not be constructed
519179404Sobrien   by assembling two single width halves into two single width floating
520179404Sobrien   point registers which just happen to alias the double width destination
521179404Sobrien   register.  On some architectures this aliasing can be disabled by a bit
522179404Sobrien   in the status register, and the setting of this bit cannot be determined
523179404Sobrien   automatically at assemble time.  */
524179404Sobrienstatic int mips_disable_float_construction;
525179404Sobrien
526179404Sobrien/* Non-zero if any .set noreorder directives were used.  */
527179404Sobrien
528179404Sobrienstatic int mips_any_noreorder;
529179404Sobrien
530179404Sobrien/* Non-zero if nops should be inserted when the register referenced in
531179404Sobrien   an mfhi/mflo instruction is read in the next two instructions.  */
532179404Sobrienstatic int mips_7000_hilo_fix;
533179404Sobrien
534218822Sdim/* The size of objects in the small data section.  */
535179404Sobrienstatic unsigned int g_switch_value = 8;
536179404Sobrien/* Whether the -G option was used.  */
537179404Sobrienstatic int g_switch_seen = 0;
538179404Sobrien
539179404Sobrien#define N_RMASK 0xc4
540179404Sobrien#define N_VFP   0xd4
541179404Sobrien
542179404Sobrien/* If we can determine in advance that GP optimization won't be
543179404Sobrien   possible, we can skip the relaxation stuff that tries to produce
544179404Sobrien   GP-relative references.  This makes delay slot optimization work
545179404Sobrien   better.
546179404Sobrien
547179404Sobrien   This function can only provide a guess, but it seems to work for
548179404Sobrien   gcc output.  It needs to guess right for gcc, otherwise gcc
549179404Sobrien   will put what it thinks is a GP-relative instruction in a branch
550179404Sobrien   delay slot.
551179404Sobrien
552179404Sobrien   I don't know if a fix is needed for the SVR4_PIC mode.  I've only
553179404Sobrien   fixed it for the non-PIC mode.  KR 95/04/07  */
554179404Sobrienstatic int nopic_need_relax (symbolS *, int);
555179404Sobrien
556179404Sobrien/* handle of the OPCODE hash table */
557179404Sobrienstatic struct hash_control *op_hash = NULL;
558179404Sobrien
559179404Sobrien/* The opcode hash table we use for the mips16.  */
560179404Sobrienstatic struct hash_control *mips16_op_hash = NULL;
561179404Sobrien
562179404Sobrien/* This array holds the chars that always start a comment.  If the
563179404Sobrien    pre-processor is disabled, these aren't very useful */
564179404Sobrienconst char comment_chars[] = "#";
565179404Sobrien
566179404Sobrien/* This array holds the chars that only start a comment at the beginning of
567179404Sobrien   a line.  If the line seems to have the form '# 123 filename'
568179404Sobrien   .line and .file directives will appear in the pre-processed output */
569179404Sobrien/* Note that input_file.c hand checks for '#' at the beginning of the
570179404Sobrien   first line of the input file.  This is because the compiler outputs
571179404Sobrien   #NO_APP at the beginning of its output.  */
572179404Sobrien/* Also note that C style comments are always supported.  */
573179404Sobrienconst char line_comment_chars[] = "#";
574179404Sobrien
575179404Sobrien/* This array holds machine specific line separator characters.  */
576179404Sobrienconst char line_separator_chars[] = ";";
577179404Sobrien
578179404Sobrien/* Chars that can be used to separate mant from exp in floating point nums */
579179404Sobrienconst char EXP_CHARS[] = "eE";
580179404Sobrien
581179404Sobrien/* Chars that mean this number is a floating point constant */
582179404Sobrien/* As in 0f12.456 */
583179404Sobrien/* or    0d1.2345e12 */
584179404Sobrienconst char FLT_CHARS[] = "rRsSfFdDxXpP";
585179404Sobrien
586179404Sobrien/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
587179404Sobrien   changed in read.c .  Ideally it shouldn't have to know about it at all,
588179404Sobrien   but nothing is ideal around here.
589179404Sobrien */
590179404Sobrien
591179404Sobrienstatic char *insn_error;
592179404Sobrien
593179404Sobrienstatic int auto_align = 1;
594179404Sobrien
595179404Sobrien/* When outputting SVR4 PIC code, the assembler needs to know the
596179404Sobrien   offset in the stack frame from which to restore the $gp register.
597179404Sobrien   This is set by the .cprestore pseudo-op, and saved in this
598179404Sobrien   variable.  */
599179404Sobrienstatic offsetT mips_cprestore_offset = -1;
600179404Sobrien
601179404Sobrien/* Similar for NewABI PIC code, where $gp is callee-saved.  NewABI has some
602179404Sobrien   more optimizations, it can use a register value instead of a memory-saved
603179404Sobrien   offset and even an other register than $gp as global pointer.  */
604179404Sobrienstatic offsetT mips_cpreturn_offset = -1;
605179404Sobrienstatic int mips_cpreturn_register = -1;
606179404Sobrienstatic int mips_gp_register = GP;
607179404Sobrienstatic int mips_gprel_offset = 0;
608179404Sobrien
609179404Sobrien/* Whether mips_cprestore_offset has been set in the current function
610179404Sobrien   (or whether it has already been warned about, if not).  */
611179404Sobrienstatic int mips_cprestore_valid = 0;
612179404Sobrien
613179404Sobrien/* This is the register which holds the stack frame, as set by the
614179404Sobrien   .frame pseudo-op.  This is needed to implement .cprestore.  */
615179404Sobrienstatic int mips_frame_reg = SP;
616179404Sobrien
617179404Sobrien/* Whether mips_frame_reg has been set in the current function
618179404Sobrien   (or whether it has already been warned about, if not).  */
619179404Sobrienstatic int mips_frame_reg_valid = 0;
620179404Sobrien
621179404Sobrien/* To output NOP instructions correctly, we need to keep information
622179404Sobrien   about the previous two instructions.  */
623179404Sobrien
624179404Sobrien/* Whether we are optimizing.  The default value of 2 means to remove
625179404Sobrien   unneeded NOPs and swap branch instructions when possible.  A value
626179404Sobrien   of 1 means to not swap branches.  A value of 0 means to always
627179404Sobrien   insert NOPs.  */
628179404Sobrienstatic int mips_optimize = 2;
629179404Sobrien
630179404Sobrien/* Debugging level.  -g sets this to 2.  -gN sets this to N.  -g0 is
631179404Sobrien   equivalent to seeing no -g option at all.  */
632179404Sobrienstatic int mips_debug = 0;
633179404Sobrien
634208737Sjmallett/* The maximum number of NOPs needed to avoid the VR4130 mflo/mfhi errata.  */
635208737Sjmallett#define MAX_VR4130_NOPS 4
636179404Sobrien
637208737Sjmallett/* The maximum number of NOPs needed to fill delay slots.  */
638208737Sjmallett#define MAX_DELAY_NOPS 2
639179404Sobrien
640208737Sjmallett/* The maximum number of NOPs needed for any purpose.  */
641208737Sjmallett#define MAX_NOPS 4
642179404Sobrien
643208737Sjmallett/* A list of previous instructions, with index 0 being the most recent.
644208737Sjmallett   We need to look back MAX_NOPS instructions when filling delay slots
645208737Sjmallett   or working around processor errata.  We need to look back one
646208737Sjmallett   instruction further if we're thinking about using history[0] to
647208737Sjmallett   fill a branch delay slot.  */
648208737Sjmallettstatic struct mips_cl_insn history[1 + MAX_NOPS];
649179404Sobrien
650208737Sjmallett/* Nop instructions used by emit_nop.  */
651208737Sjmallettstatic struct mips_cl_insn nop_insn, mips16_nop_insn;
652179404Sobrien
653208737Sjmallett/* The appropriate nop for the current mode.  */
654208737Sjmallett#define NOP_INSN (mips_opts.mips16 ? &mips16_nop_insn : &nop_insn)
655179404Sobrien
656179404Sobrien/* If this is set, it points to a frag holding nop instructions which
657179404Sobrien   were inserted before the start of a noreorder section.  If those
658179404Sobrien   nops turn out to be unnecessary, the size of the frag can be
659179404Sobrien   decreased.  */
660179404Sobrienstatic fragS *prev_nop_frag;
661179404Sobrien
662179404Sobrien/* The number of nop instructions we created in prev_nop_frag.  */
663179404Sobrienstatic int prev_nop_frag_holds;
664179404Sobrien
665179404Sobrien/* The number of nop instructions that we know we need in
666179404Sobrien   prev_nop_frag.  */
667179404Sobrienstatic int prev_nop_frag_required;
668179404Sobrien
669179404Sobrien/* The number of instructions we've seen since prev_nop_frag.  */
670179404Sobrienstatic int prev_nop_frag_since;
671179404Sobrien
672179404Sobrien/* For ECOFF and ELF, relocations against symbols are done in two
673179404Sobrien   parts, with a HI relocation and a LO relocation.  Each relocation
674179404Sobrien   has only 16 bits of space to store an addend.  This means that in
675179404Sobrien   order for the linker to handle carries correctly, it must be able
676179404Sobrien   to locate both the HI and the LO relocation.  This means that the
677179404Sobrien   relocations must appear in order in the relocation table.
678179404Sobrien
679179404Sobrien   In order to implement this, we keep track of each unmatched HI
680179404Sobrien   relocation.  We then sort them so that they immediately precede the
681179404Sobrien   corresponding LO relocation.  */
682179404Sobrien
683179404Sobrienstruct mips_hi_fixup
684179404Sobrien{
685179404Sobrien  /* Next HI fixup.  */
686179404Sobrien  struct mips_hi_fixup *next;
687179404Sobrien  /* This fixup.  */
688179404Sobrien  fixS *fixp;
689179404Sobrien  /* The section this fixup is in.  */
690179404Sobrien  segT seg;
691179404Sobrien};
692179404Sobrien
693179404Sobrien/* The list of unmatched HI relocs.  */
694179404Sobrien
695179404Sobrienstatic struct mips_hi_fixup *mips_hi_fixup_list;
696179404Sobrien
697179404Sobrien/* The frag containing the last explicit relocation operator.
698179404Sobrien   Null if explicit relocations have not been used.  */
699179404Sobrien
700179404Sobrienstatic fragS *prev_reloc_op_frag;
701179404Sobrien
702179404Sobrien/* Map normal MIPS register numbers to mips16 register numbers.  */
703179404Sobrien
704179404Sobrien#define X ILLEGAL_REG
705179404Sobrienstatic const int mips32_to_16_reg_map[] =
706179404Sobrien{
707179404Sobrien  X, X, 2, 3, 4, 5, 6, 7,
708179404Sobrien  X, X, X, X, X, X, X, X,
709179404Sobrien  0, 1, X, X, X, X, X, X,
710179404Sobrien  X, X, X, X, X, X, X, X
711179404Sobrien};
712179404Sobrien#undef X
713179404Sobrien
714179404Sobrien/* Map mips16 register numbers to normal MIPS register numbers.  */
715179404Sobrien
716179404Sobrienstatic const unsigned int mips16_to_32_reg_map[] =
717179404Sobrien{
718179404Sobrien  16, 17, 2, 3, 4, 5, 6, 7
719179404Sobrien};
720179404Sobrien
721208737Sjmallett/* Classifies the kind of instructions we're interested in when
722208737Sjmallett   implementing -mfix-vr4120.  */
723208737Sjmallettenum fix_vr4120_class {
724208737Sjmallett  FIX_VR4120_MACC,
725208737Sjmallett  FIX_VR4120_DMACC,
726208737Sjmallett  FIX_VR4120_MULT,
727208737Sjmallett  FIX_VR4120_DMULT,
728208737Sjmallett  FIX_VR4120_DIV,
729208737Sjmallett  FIX_VR4120_MTHILO,
730208737Sjmallett  NUM_FIX_VR4120_CLASSES
731208737Sjmallett};
732208737Sjmallett
733208737Sjmallett/* Given two FIX_VR4120_* values X and Y, bit Y of element X is set if
734208737Sjmallett   there must be at least one other instruction between an instruction
735208737Sjmallett   of type X and an instruction of type Y.  */
736208737Sjmallettstatic unsigned int vr4120_conflicts[NUM_FIX_VR4120_CLASSES];
737208737Sjmallett
738208737Sjmallett/* True if -mfix-vr4120 is in force.  */
739179404Sobrienstatic int mips_fix_vr4120;
740179404Sobrien
741208737Sjmallett/* ...likewise -mfix-vr4130.  */
742208737Sjmallettstatic int mips_fix_vr4130;
743208737Sjmallett
744179404Sobrien/* We don't relax branches by default, since this causes us to expand
745179404Sobrien   `la .l2 - .l1' if there's a branch between .l1 and .l2, because we
746179404Sobrien   fail to compute the offset before expanding the macro to the most
747179404Sobrien   efficient expansion.  */
748179404Sobrien
749179404Sobrienstatic int mips_relax_branch;
750179404Sobrien
751179404Sobrien/* The expansion of many macros depends on the type of symbol that
752179404Sobrien   they refer to.  For example, when generating position-dependent code,
753179404Sobrien   a macro that refers to a symbol may have two different expansions,
754179404Sobrien   one which uses GP-relative addresses and one which uses absolute
755179404Sobrien   addresses.  When generating SVR4-style PIC, a macro may have
756179404Sobrien   different expansions for local and global symbols.
757179404Sobrien
758179404Sobrien   We handle these situations by generating both sequences and putting
759179404Sobrien   them in variant frags.  In position-dependent code, the first sequence
760179404Sobrien   will be the GP-relative one and the second sequence will be the
761179404Sobrien   absolute one.  In SVR4 PIC, the first sequence will be for global
762179404Sobrien   symbols and the second will be for local symbols.
763179404Sobrien
764179404Sobrien   The frag's "subtype" is RELAX_ENCODE (FIRST, SECOND), where FIRST and
765179404Sobrien   SECOND are the lengths of the two sequences in bytes.  These fields
766179404Sobrien   can be extracted using RELAX_FIRST() and RELAX_SECOND().  In addition,
767179404Sobrien   the subtype has the following flags:
768179404Sobrien
769179404Sobrien   RELAX_USE_SECOND
770179404Sobrien	Set if it has been decided that we should use the second
771179404Sobrien	sequence instead of the first.
772179404Sobrien
773179404Sobrien   RELAX_SECOND_LONGER
774179404Sobrien	Set in the first variant frag if the macro's second implementation
775179404Sobrien	is longer than its first.  This refers to the macro as a whole,
776179404Sobrien	not an individual relaxation.
777179404Sobrien
778179404Sobrien   RELAX_NOMACRO
779179404Sobrien	Set in the first variant frag if the macro appeared in a .set nomacro
780179404Sobrien	block and if one alternative requires a warning but the other does not.
781179404Sobrien
782179404Sobrien   RELAX_DELAY_SLOT
783179404Sobrien	Like RELAX_NOMACRO, but indicates that the macro appears in a branch
784179404Sobrien	delay slot.
785179404Sobrien
786179404Sobrien   The frag's "opcode" points to the first fixup for relaxable code.
787179404Sobrien
788179404Sobrien   Relaxable macros are generated using a sequence such as:
789179404Sobrien
790179404Sobrien      relax_start (SYMBOL);
791179404Sobrien      ... generate first expansion ...
792179404Sobrien      relax_switch ();
793179404Sobrien      ... generate second expansion ...
794179404Sobrien      relax_end ();
795179404Sobrien
796179404Sobrien   The code and fixups for the unwanted alternative are discarded
797179404Sobrien   by md_convert_frag.  */
798179404Sobrien#define RELAX_ENCODE(FIRST, SECOND) (((FIRST) << 8) | (SECOND))
799179404Sobrien
800179404Sobrien#define RELAX_FIRST(X) (((X) >> 8) & 0xff)
801179404Sobrien#define RELAX_SECOND(X) ((X) & 0xff)
802179404Sobrien#define RELAX_USE_SECOND 0x10000
803179404Sobrien#define RELAX_SECOND_LONGER 0x20000
804179404Sobrien#define RELAX_NOMACRO 0x40000
805179404Sobrien#define RELAX_DELAY_SLOT 0x80000
806179404Sobrien
807179404Sobrien/* Branch without likely bit.  If label is out of range, we turn:
808179404Sobrien
809179404Sobrien 	beq reg1, reg2, label
810179404Sobrien	delay slot
811179404Sobrien
812179404Sobrien   into
813179404Sobrien
814179404Sobrien        bne reg1, reg2, 0f
815179404Sobrien        nop
816179404Sobrien        j label
817179404Sobrien     0: delay slot
818179404Sobrien
819179404Sobrien   with the following opcode replacements:
820179404Sobrien
821179404Sobrien	beq <-> bne
822179404Sobrien	blez <-> bgtz
823179404Sobrien	bltz <-> bgez
824179404Sobrien	bc1f <-> bc1t
825179404Sobrien
826179404Sobrien	bltzal <-> bgezal  (with jal label instead of j label)
827179404Sobrien
828179404Sobrien   Even though keeping the delay slot instruction in the delay slot of
829179404Sobrien   the branch would be more efficient, it would be very tricky to do
830179404Sobrien   correctly, because we'd have to introduce a variable frag *after*
831179404Sobrien   the delay slot instruction, and expand that instead.  Let's do it
832179404Sobrien   the easy way for now, even if the branch-not-taken case now costs
833179404Sobrien   one additional instruction.  Out-of-range branches are not supposed
834179404Sobrien   to be common, anyway.
835179404Sobrien
836179404Sobrien   Branch likely.  If label is out of range, we turn:
837179404Sobrien
838179404Sobrien	beql reg1, reg2, label
839179404Sobrien	delay slot (annulled if branch not taken)
840179404Sobrien
841179404Sobrien   into
842179404Sobrien
843179404Sobrien        beql reg1, reg2, 1f
844179404Sobrien        nop
845179404Sobrien        beql $0, $0, 2f
846179404Sobrien        nop
847179404Sobrien     1: j[al] label
848179404Sobrien        delay slot (executed only if branch taken)
849179404Sobrien     2:
850179404Sobrien
851179404Sobrien   It would be possible to generate a shorter sequence by losing the
852179404Sobrien   likely bit, generating something like:
853179404Sobrien
854179404Sobrien	bne reg1, reg2, 0f
855179404Sobrien	nop
856179404Sobrien	j[al] label
857179404Sobrien	delay slot (executed only if branch taken)
858179404Sobrien     0:
859179404Sobrien
860179404Sobrien	beql -> bne
861179404Sobrien	bnel -> beq
862179404Sobrien	blezl -> bgtz
863179404Sobrien	bgtzl -> blez
864179404Sobrien	bltzl -> bgez
865179404Sobrien	bgezl -> bltz
866179404Sobrien	bc1fl -> bc1t
867179404Sobrien	bc1tl -> bc1f
868179404Sobrien
869179404Sobrien	bltzall -> bgezal  (with jal label instead of j label)
870179404Sobrien	bgezall -> bltzal  (ditto)
871179404Sobrien
872179404Sobrien
873179404Sobrien   but it's not clear that it would actually improve performance.  */
874179404Sobrien#define RELAX_BRANCH_ENCODE(uncond, likely, link, toofar) \
875179404Sobrien  ((relax_substateT) \
876179404Sobrien   (0xc0000000 \
877179404Sobrien    | ((toofar) ? 1 : 0) \
878179404Sobrien    | ((link) ? 2 : 0) \
879179404Sobrien    | ((likely) ? 4 : 0) \
880179404Sobrien    | ((uncond) ? 8 : 0)))
881179404Sobrien#define RELAX_BRANCH_P(i) (((i) & 0xf0000000) == 0xc0000000)
882179404Sobrien#define RELAX_BRANCH_UNCOND(i) (((i) & 8) != 0)
883179404Sobrien#define RELAX_BRANCH_LIKELY(i) (((i) & 4) != 0)
884179404Sobrien#define RELAX_BRANCH_LINK(i) (((i) & 2) != 0)
885179404Sobrien#define RELAX_BRANCH_TOOFAR(i) (((i) & 1) != 0)
886179404Sobrien
887179404Sobrien/* For mips16 code, we use an entirely different form of relaxation.
888179404Sobrien   mips16 supports two versions of most instructions which take
889179404Sobrien   immediate values: a small one which takes some small value, and a
890179404Sobrien   larger one which takes a 16 bit value.  Since branches also follow
891179404Sobrien   this pattern, relaxing these values is required.
892179404Sobrien
893179404Sobrien   We can assemble both mips16 and normal MIPS code in a single
894179404Sobrien   object.  Therefore, we need to support this type of relaxation at
895179404Sobrien   the same time that we support the relaxation described above.  We
896179404Sobrien   use the high bit of the subtype field to distinguish these cases.
897179404Sobrien
898179404Sobrien   The information we store for this type of relaxation is the
899179404Sobrien   argument code found in the opcode file for this relocation, whether
900179404Sobrien   the user explicitly requested a small or extended form, and whether
901179404Sobrien   the relocation is in a jump or jal delay slot.  That tells us the
902179404Sobrien   size of the value, and how it should be stored.  We also store
903179404Sobrien   whether the fragment is considered to be extended or not.  We also
904179404Sobrien   store whether this is known to be a branch to a different section,
905179404Sobrien   whether we have tried to relax this frag yet, and whether we have
906179404Sobrien   ever extended a PC relative fragment because of a shift count.  */
907179404Sobrien#define RELAX_MIPS16_ENCODE(type, small, ext, dslot, jal_dslot)	\
908179404Sobrien  (0x80000000							\
909179404Sobrien   | ((type) & 0xff)						\
910179404Sobrien   | ((small) ? 0x100 : 0)					\
911179404Sobrien   | ((ext) ? 0x200 : 0)					\
912179404Sobrien   | ((dslot) ? 0x400 : 0)					\
913179404Sobrien   | ((jal_dslot) ? 0x800 : 0))
914179404Sobrien#define RELAX_MIPS16_P(i) (((i) & 0xc0000000) == 0x80000000)
915179404Sobrien#define RELAX_MIPS16_TYPE(i) ((i) & 0xff)
916179404Sobrien#define RELAX_MIPS16_USER_SMALL(i) (((i) & 0x100) != 0)
917179404Sobrien#define RELAX_MIPS16_USER_EXT(i) (((i) & 0x200) != 0)
918179404Sobrien#define RELAX_MIPS16_DSLOT(i) (((i) & 0x400) != 0)
919179404Sobrien#define RELAX_MIPS16_JAL_DSLOT(i) (((i) & 0x800) != 0)
920179404Sobrien#define RELAX_MIPS16_EXTENDED(i) (((i) & 0x1000) != 0)
921179404Sobrien#define RELAX_MIPS16_MARK_EXTENDED(i) ((i) | 0x1000)
922179404Sobrien#define RELAX_MIPS16_CLEAR_EXTENDED(i) ((i) &~ 0x1000)
923179404Sobrien#define RELAX_MIPS16_LONG_BRANCH(i) (((i) & 0x2000) != 0)
924179404Sobrien#define RELAX_MIPS16_MARK_LONG_BRANCH(i) ((i) | 0x2000)
925179404Sobrien#define RELAX_MIPS16_CLEAR_LONG_BRANCH(i) ((i) &~ 0x2000)
926179404Sobrien
927179404Sobrien/* Is the given value a sign-extended 32-bit value?  */
928179404Sobrien#define IS_SEXT_32BIT_NUM(x)						\
929179404Sobrien  (((x) &~ (offsetT) 0x7fffffff) == 0					\
930179404Sobrien   || (((x) &~ (offsetT) 0x7fffffff) == ~ (offsetT) 0x7fffffff))
931179404Sobrien
932179404Sobrien/* Is the given value a sign-extended 16-bit value?  */
933179404Sobrien#define IS_SEXT_16BIT_NUM(x)						\
934179404Sobrien  (((x) &~ (offsetT) 0x7fff) == 0					\
935179404Sobrien   || (((x) &~ (offsetT) 0x7fff) == ~ (offsetT) 0x7fff))
936179404Sobrien
937208737Sjmallett/* Is the given value a zero-extended 32-bit value?  Or a negated one?  */
938208737Sjmallett#define IS_ZEXT_32BIT_NUM(x)						\
939208737Sjmallett  (((x) &~ (offsetT) 0xffffffff) == 0					\
940208737Sjmallett   || (((x) &~ (offsetT) 0xffffffff) == ~ (offsetT) 0xffffffff))
941208737Sjmallett
942208737Sjmallett/* Replace bits MASK << SHIFT of STRUCT with the equivalent bits in
943208737Sjmallett   VALUE << SHIFT.  VALUE is evaluated exactly once.  */
944208737Sjmallett#define INSERT_BITS(STRUCT, VALUE, MASK, SHIFT) \
945208737Sjmallett  (STRUCT) = (((STRUCT) & ~((MASK) << (SHIFT))) \
946208737Sjmallett	      | (((VALUE) & (MASK)) << (SHIFT)))
947208737Sjmallett
948208737Sjmallett/* Extract bits MASK << SHIFT from STRUCT and shift them right
949208737Sjmallett   SHIFT places.  */
950208737Sjmallett#define EXTRACT_BITS(STRUCT, MASK, SHIFT) \
951208737Sjmallett  (((STRUCT) >> (SHIFT)) & (MASK))
952208737Sjmallett
953208737Sjmallett/* Change INSN's opcode so that the operand given by FIELD has value VALUE.
954208737Sjmallett   INSN is a mips_cl_insn structure and VALUE is evaluated exactly once.
955208737Sjmallett
956208737Sjmallett   include/opcode/mips.h specifies operand fields using the macros
957208737Sjmallett   OP_MASK_<FIELD> and OP_SH_<FIELD>.  The MIPS16 equivalents start
958208737Sjmallett   with "MIPS16OP" instead of "OP".  */
959208737Sjmallett#define INSERT_OPERAND(FIELD, INSN, VALUE) \
960208737Sjmallett  INSERT_BITS ((INSN).insn_opcode, VALUE, OP_MASK_##FIELD, OP_SH_##FIELD)
961208737Sjmallett#define MIPS16_INSERT_OPERAND(FIELD, INSN, VALUE) \
962208737Sjmallett  INSERT_BITS ((INSN).insn_opcode, VALUE, \
963208737Sjmallett		MIPS16OP_MASK_##FIELD, MIPS16OP_SH_##FIELD)
964208737Sjmallett
965208737Sjmallett/* Extract the operand given by FIELD from mips_cl_insn INSN.  */
966208737Sjmallett#define EXTRACT_OPERAND(FIELD, INSN) \
967208737Sjmallett  EXTRACT_BITS ((INSN).insn_opcode, OP_MASK_##FIELD, OP_SH_##FIELD)
968208737Sjmallett#define MIPS16_EXTRACT_OPERAND(FIELD, INSN) \
969208737Sjmallett  EXTRACT_BITS ((INSN).insn_opcode, \
970208737Sjmallett		MIPS16OP_MASK_##FIELD, \
971208737Sjmallett		MIPS16OP_SH_##FIELD)
972179404Sobrien
973179404Sobrien/* Global variables used when generating relaxable macros.  See the
974179404Sobrien   comment above RELAX_ENCODE for more details about how relaxation
975179404Sobrien   is used.  */
976179404Sobrienstatic struct {
977179404Sobrien  /* 0 if we're not emitting a relaxable macro.
978179404Sobrien     1 if we're emitting the first of the two relaxation alternatives.
979179404Sobrien     2 if we're emitting the second alternative.  */
980179404Sobrien  int sequence;
981179404Sobrien
982179404Sobrien  /* The first relaxable fixup in the current frag.  (In other words,
983179404Sobrien     the first fixup that refers to relaxable code.)  */
984179404Sobrien  fixS *first_fixup;
985179404Sobrien
986179404Sobrien  /* sizes[0] says how many bytes of the first alternative are stored in
987179404Sobrien     the current frag.  Likewise sizes[1] for the second alternative.  */
988179404Sobrien  unsigned int sizes[2];
989179404Sobrien
990179404Sobrien  /* The symbol on which the choice of sequence depends.  */
991179404Sobrien  symbolS *symbol;
992179404Sobrien} mips_relax;
993179404Sobrien
994179404Sobrien/* Global variables used to decide whether a macro needs a warning.  */
995179404Sobrienstatic struct {
996179404Sobrien  /* True if the macro is in a branch delay slot.  */
997179404Sobrien  bfd_boolean delay_slot_p;
998179404Sobrien
999179404Sobrien  /* For relaxable macros, sizes[0] is the length of the first alternative
1000179404Sobrien     in bytes and sizes[1] is the length of the second alternative.
1001179404Sobrien     For non-relaxable macros, both elements give the length of the
1002179404Sobrien     macro in bytes.  */
1003179404Sobrien  unsigned int sizes[2];
1004179404Sobrien
1005179404Sobrien  /* The first variant frag for this macro.  */
1006179404Sobrien  fragS *first_frag;
1007179404Sobrien} mips_macro_warning;
1008179404Sobrien
1009179404Sobrien/* Prototypes for static functions.  */
1010179404Sobrien
1011179404Sobrien#define internalError()							\
1012179404Sobrien    as_fatal (_("internal Error, line %d, %s"), __LINE__, __FILE__)
1013179404Sobrien
1014179404Sobrienenum mips_regclass { MIPS_GR_REG, MIPS_FP_REG, MIPS16_REG };
1015179404Sobrien
1016179404Sobrienstatic void append_insn
1017179404Sobrien  (struct mips_cl_insn *ip, expressionS *p, bfd_reloc_code_real_type *r);
1018208737Sjmallettstatic void mips_no_prev_insn (void);
1019179404Sobrienstatic void mips16_macro_build
1020179404Sobrien  (expressionS *, const char *, const char *, va_list);
1021179404Sobrienstatic void load_register (int, expressionS *, int);
1022179404Sobrienstatic void macro_start (void);
1023179404Sobrienstatic void macro_end (void);
1024179404Sobrienstatic void macro (struct mips_cl_insn * ip);
1025179404Sobrienstatic void mips16_macro (struct mips_cl_insn * ip);
1026179404Sobrien#ifdef LOSING_COMPILER
1027179404Sobrienstatic void macro2 (struct mips_cl_insn * ip);
1028179404Sobrien#endif
1029179404Sobrienstatic void mips_ip (char *str, struct mips_cl_insn * ip);
1030179404Sobrienstatic void mips16_ip (char *str, struct mips_cl_insn * ip);
1031179404Sobrienstatic void mips16_immed
1032179404Sobrien  (char *, unsigned int, int, offsetT, bfd_boolean, bfd_boolean, bfd_boolean,
1033179404Sobrien   unsigned long *, bfd_boolean *, unsigned short *);
1034179404Sobrienstatic size_t my_getSmallExpression
1035179404Sobrien  (expressionS *, bfd_reloc_code_real_type *, char *);
1036179404Sobrienstatic void my_getExpression (expressionS *, char *);
1037179404Sobrienstatic void s_align (int);
1038179404Sobrienstatic void s_change_sec (int);
1039179404Sobrienstatic void s_change_section (int);
1040179404Sobrienstatic void s_cons (int);
1041179404Sobrienstatic void s_float_cons (int);
1042179404Sobrienstatic void s_mips_globl (int);
1043179404Sobrienstatic void s_option (int);
1044179404Sobrienstatic void s_mipsset (int);
1045179404Sobrienstatic void s_abicalls (int);
1046179404Sobrienstatic void s_cpload (int);
1047179404Sobrienstatic void s_cpsetup (int);
1048179404Sobrienstatic void s_cplocal (int);
1049179404Sobrienstatic void s_cprestore (int);
1050179404Sobrienstatic void s_cpreturn (int);
1051218822Sdimstatic void s_dtprelword (int);
1052218822Sdimstatic void s_dtpreldword (int);
1053179404Sobrienstatic void s_gpvalue (int);
1054179404Sobrienstatic void s_gpword (int);
1055179404Sobrienstatic void s_gpdword (int);
1056179404Sobrienstatic void s_cpadd (int);
1057179404Sobrienstatic void s_insn (int);
1058179404Sobrienstatic void md_obj_begin (void);
1059179404Sobrienstatic void md_obj_end (void);
1060179404Sobrienstatic void s_mips_ent (int);
1061179404Sobrienstatic void s_mips_end (int);
1062179404Sobrienstatic void s_mips_frame (int);
1063179404Sobrienstatic void s_mips_mask (int reg_type);
1064179404Sobrienstatic void s_mips_stab (int);
1065179404Sobrienstatic void s_mips_weakext (int);
1066179404Sobrienstatic void s_mips_file (int);
1067179404Sobrienstatic void s_mips_loc (int);
1068179404Sobrienstatic bfd_boolean pic_need_relax (symbolS *, asection *);
1069179404Sobrienstatic int relaxed_branch_length (fragS *, asection *, int);
1070179404Sobrienstatic int validate_mips_insn (const struct mips_opcode *);
1071179404Sobrien
1072179404Sobrien/* Table and functions used to map between CPU/ISA names, and
1073179404Sobrien   ISA levels, and CPU numbers.  */
1074179404Sobrien
1075179404Sobrienstruct mips_cpu_info
1076179404Sobrien{
1077179404Sobrien  const char *name;           /* CPU or ISA name.  */
1078218822Sdim  int flags;                  /* ASEs available, or ISA flag.  */
1079179404Sobrien  int isa;                    /* ISA level.  */
1080179404Sobrien  int cpu;                    /* CPU number (default CPU if ISA).  */
1081179404Sobrien};
1082179404Sobrien
1083218822Sdim#define MIPS_CPU_IS_ISA		0x0001	/* Is this an ISA?  (If 0, a CPU.) */
1084218822Sdim#define MIPS_CPU_ASE_SMARTMIPS	0x0002	/* CPU implements SmartMIPS ASE */
1085218822Sdim#define MIPS_CPU_ASE_DSP	0x0004	/* CPU implements DSP ASE */
1086218822Sdim#define MIPS_CPU_ASE_MT		0x0008	/* CPU implements MT ASE */
1087218822Sdim#define MIPS_CPU_ASE_MIPS3D	0x0010	/* CPU implements MIPS-3D ASE */
1088218822Sdim#define MIPS_CPU_ASE_MDMX	0x0020	/* CPU implements MDMX ASE */
1089218822Sdim#define MIPS_CPU_ASE_DSPR2	0x0040	/* CPU implements DSP R2 ASE */
1090218822Sdim
1091179404Sobrienstatic const struct mips_cpu_info *mips_parse_cpu (const char *, const char *);
1092179404Sobrienstatic const struct mips_cpu_info *mips_cpu_info_from_isa (int);
1093179404Sobrienstatic const struct mips_cpu_info *mips_cpu_info_from_arch (int);
1094179404Sobrien
1095179404Sobrien/* Pseudo-op table.
1096179404Sobrien
1097179404Sobrien   The following pseudo-ops from the Kane and Heinrich MIPS book
1098179404Sobrien   should be defined here, but are currently unsupported: .alias,
1099179404Sobrien   .galive, .gjaldef, .gjrlive, .livereg, .noalias.
1100179404Sobrien
1101179404Sobrien   The following pseudo-ops from the Kane and Heinrich MIPS book are
1102179404Sobrien   specific to the type of debugging information being generated, and
1103179404Sobrien   should be defined by the object format: .aent, .begin, .bend,
1104179404Sobrien   .bgnb, .end, .endb, .ent, .fmask, .frame, .loc, .mask, .verstamp,
1105179404Sobrien   .vreg.
1106179404Sobrien
1107179404Sobrien   The following pseudo-ops from the Kane and Heinrich MIPS book are
1108179404Sobrien   not MIPS CPU specific, but are also not specific to the object file
1109179404Sobrien   format.  This file is probably the best place to define them, but
1110218822Sdim   they are not currently supported: .asm0, .endr, .lab, .struct.  */
1111179404Sobrien
1112179404Sobrienstatic const pseudo_typeS mips_pseudo_table[] =
1113179404Sobrien{
1114179404Sobrien  /* MIPS specific pseudo-ops.  */
1115179404Sobrien  {"option", s_option, 0},
1116179404Sobrien  {"set", s_mipsset, 0},
1117179404Sobrien  {"rdata", s_change_sec, 'r'},
1118179404Sobrien  {"sdata", s_change_sec, 's'},
1119179404Sobrien  {"livereg", s_ignore, 0},
1120179404Sobrien  {"abicalls", s_abicalls, 0},
1121179404Sobrien  {"cpload", s_cpload, 0},
1122179404Sobrien  {"cpsetup", s_cpsetup, 0},
1123179404Sobrien  {"cplocal", s_cplocal, 0},
1124179404Sobrien  {"cprestore", s_cprestore, 0},
1125179404Sobrien  {"cpreturn", s_cpreturn, 0},
1126218822Sdim  {"dtprelword", s_dtprelword, 0},
1127218822Sdim  {"dtpreldword", s_dtpreldword, 0},
1128179404Sobrien  {"gpvalue", s_gpvalue, 0},
1129179404Sobrien  {"gpword", s_gpword, 0},
1130179404Sobrien  {"gpdword", s_gpdword, 0},
1131179404Sobrien  {"cpadd", s_cpadd, 0},
1132179404Sobrien  {"insn", s_insn, 0},
1133179404Sobrien
1134179404Sobrien  /* Relatively generic pseudo-ops that happen to be used on MIPS
1135179404Sobrien     chips.  */
1136179404Sobrien  {"asciiz", stringer, 1},
1137179404Sobrien  {"bss", s_change_sec, 'b'},
1138179404Sobrien  {"err", s_err, 0},
1139179404Sobrien  {"half", s_cons, 1},
1140179404Sobrien  {"dword", s_cons, 3},
1141179404Sobrien  {"weakext", s_mips_weakext, 0},
1142218822Sdim  {"origin", s_org, 0},
1143218822Sdim  {"repeat", s_rept, 0},
1144179404Sobrien
1145179404Sobrien  /* These pseudo-ops are defined in read.c, but must be overridden
1146179404Sobrien     here for one reason or another.  */
1147179404Sobrien  {"align", s_align, 0},
1148179404Sobrien  {"byte", s_cons, 0},
1149179404Sobrien  {"data", s_change_sec, 'd'},
1150179404Sobrien  {"double", s_float_cons, 'd'},
1151179404Sobrien  {"float", s_float_cons, 'f'},
1152179404Sobrien  {"globl", s_mips_globl, 0},
1153179404Sobrien  {"global", s_mips_globl, 0},
1154179404Sobrien  {"hword", s_cons, 1},
1155179404Sobrien  {"int", s_cons, 2},
1156179404Sobrien  {"long", s_cons, 2},
1157179404Sobrien  {"octa", s_cons, 4},
1158179404Sobrien  {"quad", s_cons, 3},
1159179404Sobrien  {"section", s_change_section, 0},
1160179404Sobrien  {"short", s_cons, 1},
1161179404Sobrien  {"single", s_float_cons, 'f'},
1162179404Sobrien  {"stabn", s_mips_stab, 'n'},
1163179404Sobrien  {"text", s_change_sec, 't'},
1164179404Sobrien  {"word", s_cons, 2},
1165179404Sobrien
1166179404Sobrien  { "extern", ecoff_directive_extern, 0},
1167179404Sobrien
1168179404Sobrien  { NULL, NULL, 0 },
1169179404Sobrien};
1170179404Sobrien
1171179404Sobrienstatic const pseudo_typeS mips_nonecoff_pseudo_table[] =
1172179404Sobrien{
1173179404Sobrien  /* These pseudo-ops should be defined by the object file format.
1174179404Sobrien     However, a.out doesn't support them, so we have versions here.  */
1175179404Sobrien  {"aent", s_mips_ent, 1},
1176179404Sobrien  {"bgnb", s_ignore, 0},
1177179404Sobrien  {"end", s_mips_end, 0},
1178179404Sobrien  {"endb", s_ignore, 0},
1179179404Sobrien  {"ent", s_mips_ent, 0},
1180179404Sobrien  {"file", s_mips_file, 0},
1181179404Sobrien  {"fmask", s_mips_mask, 'F'},
1182179404Sobrien  {"frame", s_mips_frame, 0},
1183179404Sobrien  {"loc", s_mips_loc, 0},
1184179404Sobrien  {"mask", s_mips_mask, 'R'},
1185179404Sobrien  {"verstamp", s_ignore, 0},
1186179404Sobrien  { NULL, NULL, 0 },
1187179404Sobrien};
1188179404Sobrien
1189179404Sobrienextern void pop_insert (const pseudo_typeS *);
1190179404Sobrien
1191179404Sobrienvoid
1192179404Sobrienmips_pop_insert (void)
1193179404Sobrien{
1194179404Sobrien  pop_insert (mips_pseudo_table);
1195179404Sobrien  if (! ECOFF_DEBUGGING)
1196179404Sobrien    pop_insert (mips_nonecoff_pseudo_table);
1197179404Sobrien}
1198179404Sobrien
1199179404Sobrien/* Symbols labelling the current insn.  */
1200179404Sobrien
1201179404Sobrienstruct insn_label_list
1202179404Sobrien{
1203179404Sobrien  struct insn_label_list *next;
1204179404Sobrien  symbolS *label;
1205179404Sobrien};
1206179404Sobrien
1207179404Sobrienstatic struct insn_label_list *free_insn_labels;
1208218822Sdim#define label_list tc_segment_info_data
1209179404Sobrien
1210179404Sobrienstatic void mips_clear_insn_labels (void);
1211179404Sobrien
1212179404Sobrienstatic inline void
1213179404Sobrienmips_clear_insn_labels (void)
1214179404Sobrien{
1215179404Sobrien  register struct insn_label_list **pl;
1216218822Sdim  segment_info_type *si;
1217179404Sobrien
1218218822Sdim  if (now_seg)
1219218822Sdim    {
1220218822Sdim      for (pl = &free_insn_labels; *pl != NULL; pl = &(*pl)->next)
1221218822Sdim	;
1222218822Sdim
1223218822Sdim      si = seg_info (now_seg);
1224218822Sdim      *pl = si->label_list;
1225218822Sdim      si->label_list = NULL;
1226218822Sdim    }
1227179404Sobrien}
1228218822Sdim
1229179404Sobrien
1230179404Sobrienstatic char *expr_end;
1231179404Sobrien
1232179404Sobrien/* Expressions which appear in instructions.  These are set by
1233179404Sobrien   mips_ip.  */
1234179404Sobrien
1235179404Sobrienstatic expressionS imm_expr;
1236179404Sobrienstatic expressionS imm2_expr;
1237179404Sobrienstatic expressionS offset_expr;
1238179404Sobrien
1239179404Sobrien/* Relocs associated with imm_expr and offset_expr.  */
1240179404Sobrien
1241179404Sobrienstatic bfd_reloc_code_real_type imm_reloc[3]
1242179404Sobrien  = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
1243179404Sobrienstatic bfd_reloc_code_real_type offset_reloc[3]
1244179404Sobrien  = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
1245179404Sobrien
1246179404Sobrien/* These are set by mips16_ip if an explicit extension is used.  */
1247179404Sobrien
1248179404Sobrienstatic bfd_boolean mips16_small, mips16_ext;
1249179404Sobrien
1250179404Sobrien#ifdef OBJ_ELF
1251179404Sobrien/* The pdr segment for per procedure frame/regmask info.  Not used for
1252179404Sobrien   ECOFF debugging.  */
1253179404Sobrien
1254179404Sobrienstatic segT pdr_seg;
1255179404Sobrien#endif
1256179404Sobrien
1257179404Sobrien/* The default target format to use.  */
1258179404Sobrien
1259179404Sobrienconst char *
1260179404Sobrienmips_target_format (void)
1261179404Sobrien{
1262179404Sobrien  switch (OUTPUT_FLAVOR)
1263179404Sobrien    {
1264179404Sobrien    case bfd_target_ecoff_flavour:
1265179404Sobrien      return target_big_endian ? "ecoff-bigmips" : ECOFF_LITTLE_FORMAT;
1266179404Sobrien    case bfd_target_coff_flavour:
1267179404Sobrien      return "pe-mips";
1268179404Sobrien    case bfd_target_elf_flavour:
1269218822Sdim#ifdef TE_VXWORKS
1270218822Sdim      if (!HAVE_64BIT_OBJECTS && !HAVE_NEWABI)
1271218822Sdim	return (target_big_endian
1272218822Sdim		? "elf32-bigmips-vxworks"
1273218822Sdim		: "elf32-littlemips-vxworks");
1274218822Sdim#endif
1275179404Sobrien#ifdef TE_TMIPS
1276179404Sobrien      /* This is traditional mips.  */
1277179404Sobrien      return (target_big_endian
1278179404Sobrien	      ? (HAVE_64BIT_OBJECTS
1279179404Sobrien		 ? "elf64-tradbigmips"
1280179404Sobrien		 : (HAVE_NEWABI
1281179404Sobrien		    ? "elf32-ntradbigmips" : "elf32-tradbigmips"))
1282179404Sobrien	      : (HAVE_64BIT_OBJECTS
1283179404Sobrien		 ? "elf64-tradlittlemips"
1284179404Sobrien		 : (HAVE_NEWABI
1285179404Sobrien		    ? "elf32-ntradlittlemips" : "elf32-tradlittlemips")));
1286179404Sobrien#else
1287179404Sobrien      return (target_big_endian
1288179404Sobrien	      ? (HAVE_64BIT_OBJECTS
1289179404Sobrien		 ? "elf64-bigmips"
1290179404Sobrien		 : (HAVE_NEWABI
1291179404Sobrien		    ? "elf32-nbigmips" : "elf32-bigmips"))
1292179404Sobrien	      : (HAVE_64BIT_OBJECTS
1293179404Sobrien		 ? "elf64-littlemips"
1294179404Sobrien		 : (HAVE_NEWABI
1295179404Sobrien		    ? "elf32-nlittlemips" : "elf32-littlemips")));
1296179404Sobrien#endif
1297179404Sobrien    default:
1298179404Sobrien      abort ();
1299179404Sobrien      return NULL;
1300179404Sobrien    }
1301179404Sobrien}
1302179404Sobrien
1303208737Sjmallett/* Return the length of instruction INSN.  */
1304208737Sjmallett
1305208737Sjmallettstatic inline unsigned int
1306208737Sjmallettinsn_length (const struct mips_cl_insn *insn)
1307208737Sjmallett{
1308208737Sjmallett  if (!mips_opts.mips16)
1309208737Sjmallett    return 4;
1310208737Sjmallett  return insn->mips16_absolute_jump_p || insn->use_extend ? 4 : 2;
1311208737Sjmallett}
1312208737Sjmallett
1313208737Sjmallett/* Initialise INSN from opcode entry MO.  Leave its position unspecified.  */
1314208737Sjmallett
1315208737Sjmallettstatic void
1316208737Sjmallettcreate_insn (struct mips_cl_insn *insn, const struct mips_opcode *mo)
1317208737Sjmallett{
1318208737Sjmallett  size_t i;
1319208737Sjmallett
1320208737Sjmallett  insn->insn_mo = mo;
1321208737Sjmallett  insn->use_extend = FALSE;
1322208737Sjmallett  insn->extend = 0;
1323208737Sjmallett  insn->insn_opcode = mo->match;
1324208737Sjmallett  insn->frag = NULL;
1325208737Sjmallett  insn->where = 0;
1326208737Sjmallett  for (i = 0; i < ARRAY_SIZE (insn->fixp); i++)
1327208737Sjmallett    insn->fixp[i] = NULL;
1328208737Sjmallett  insn->fixed_p = (mips_opts.noreorder > 0);
1329208737Sjmallett  insn->noreorder_p = (mips_opts.noreorder > 0);
1330208737Sjmallett  insn->mips16_absolute_jump_p = 0;
1331208737Sjmallett}
1332208737Sjmallett
1333208737Sjmallett/* Install INSN at the location specified by its "frag" and "where" fields.  */
1334208737Sjmallett
1335208737Sjmallettstatic void
1336208737Sjmallettinstall_insn (const struct mips_cl_insn *insn)
1337208737Sjmallett{
1338208737Sjmallett  char *f = insn->frag->fr_literal + insn->where;
1339208737Sjmallett  if (!mips_opts.mips16)
1340208737Sjmallett    md_number_to_chars (f, insn->insn_opcode, 4);
1341208737Sjmallett  else if (insn->mips16_absolute_jump_p)
1342208737Sjmallett    {
1343208737Sjmallett      md_number_to_chars (f, insn->insn_opcode >> 16, 2);
1344208737Sjmallett      md_number_to_chars (f + 2, insn->insn_opcode & 0xffff, 2);
1345208737Sjmallett    }
1346208737Sjmallett  else
1347208737Sjmallett    {
1348208737Sjmallett      if (insn->use_extend)
1349208737Sjmallett	{
1350208737Sjmallett	  md_number_to_chars (f, 0xf000 | insn->extend, 2);
1351208737Sjmallett	  f += 2;
1352208737Sjmallett	}
1353208737Sjmallett      md_number_to_chars (f, insn->insn_opcode, 2);
1354208737Sjmallett    }
1355208737Sjmallett}
1356208737Sjmallett
1357208737Sjmallett/* Move INSN to offset WHERE in FRAG.  Adjust the fixups accordingly
1358208737Sjmallett   and install the opcode in the new location.  */
1359208737Sjmallett
1360208737Sjmallettstatic void
1361208737Sjmallettmove_insn (struct mips_cl_insn *insn, fragS *frag, long where)
1362208737Sjmallett{
1363208737Sjmallett  size_t i;
1364208737Sjmallett
1365208737Sjmallett  insn->frag = frag;
1366208737Sjmallett  insn->where = where;
1367208737Sjmallett  for (i = 0; i < ARRAY_SIZE (insn->fixp); i++)
1368208737Sjmallett    if (insn->fixp[i] != NULL)
1369208737Sjmallett      {
1370208737Sjmallett	insn->fixp[i]->fx_frag = frag;
1371208737Sjmallett	insn->fixp[i]->fx_where = where;
1372208737Sjmallett      }
1373208737Sjmallett  install_insn (insn);
1374208737Sjmallett}
1375208737Sjmallett
1376208737Sjmallett/* Add INSN to the end of the output.  */
1377208737Sjmallett
1378208737Sjmallettstatic void
1379208737Sjmallettadd_fixed_insn (struct mips_cl_insn *insn)
1380208737Sjmallett{
1381208737Sjmallett  char *f = frag_more (insn_length (insn));
1382208737Sjmallett  move_insn (insn, frag_now, f - frag_now->fr_literal);
1383208737Sjmallett}
1384208737Sjmallett
1385208737Sjmallett/* Start a variant frag and move INSN to the start of the variant part,
1386208737Sjmallett   marking it as fixed.  The other arguments are as for frag_var.  */
1387208737Sjmallett
1388208737Sjmallettstatic void
1389208737Sjmallettadd_relaxed_insn (struct mips_cl_insn *insn, int max_chars, int var,
1390208737Sjmallett		  relax_substateT subtype, symbolS *symbol, offsetT offset)
1391208737Sjmallett{
1392208737Sjmallett  frag_grow (max_chars);
1393208737Sjmallett  move_insn (insn, frag_now, frag_more (0) - frag_now->fr_literal);
1394208737Sjmallett  insn->fixed_p = 1;
1395208737Sjmallett  frag_var (rs_machine_dependent, max_chars, var,
1396208737Sjmallett	    subtype, symbol, offset, NULL);
1397208737Sjmallett}
1398208737Sjmallett
1399208737Sjmallett/* Insert N copies of INSN into the history buffer, starting at
1400208737Sjmallett   position FIRST.  Neither FIRST nor N need to be clipped.  */
1401208737Sjmallett
1402208737Sjmallettstatic void
1403208737Sjmallettinsert_into_history (unsigned int first, unsigned int n,
1404208737Sjmallett		     const struct mips_cl_insn *insn)
1405208737Sjmallett{
1406208737Sjmallett  if (mips_relax.sequence != 2)
1407208737Sjmallett    {
1408208737Sjmallett      unsigned int i;
1409208737Sjmallett
1410208737Sjmallett      for (i = ARRAY_SIZE (history); i-- > first;)
1411208737Sjmallett	if (i >= first + n)
1412208737Sjmallett	  history[i] = history[i - n];
1413208737Sjmallett	else
1414208737Sjmallett	  history[i] = *insn;
1415208737Sjmallett    }
1416208737Sjmallett}
1417208737Sjmallett
1418208737Sjmallett/* Emit a nop instruction, recording it in the history buffer.  */
1419208737Sjmallett
1420208737Sjmallettstatic void
1421208737Sjmallettemit_nop (void)
1422208737Sjmallett{
1423208737Sjmallett  add_fixed_insn (NOP_INSN);
1424208737Sjmallett  insert_into_history (0, 1, NOP_INSN);
1425208737Sjmallett}
1426208737Sjmallett
1427208737Sjmallett/* Initialize vr4120_conflicts.  There is a bit of duplication here:
1428208737Sjmallett   the idea is to make it obvious at a glance that each errata is
1429208737Sjmallett   included.  */
1430208737Sjmallett
1431208737Sjmallettstatic void
1432208737Sjmallettinit_vr4120_conflicts (void)
1433208737Sjmallett{
1434208737Sjmallett#define CONFLICT(FIRST, SECOND) \
1435208737Sjmallett    vr4120_conflicts[FIX_VR4120_##FIRST] |= 1 << FIX_VR4120_##SECOND
1436208737Sjmallett
1437208737Sjmallett  /* Errata 21 - [D]DIV[U] after [D]MACC */
1438208737Sjmallett  CONFLICT (MACC, DIV);
1439208737Sjmallett  CONFLICT (DMACC, DIV);
1440208737Sjmallett
1441208737Sjmallett  /* Errata 23 - Continuous DMULT[U]/DMACC instructions.  */
1442208737Sjmallett  CONFLICT (DMULT, DMULT);
1443208737Sjmallett  CONFLICT (DMULT, DMACC);
1444208737Sjmallett  CONFLICT (DMACC, DMULT);
1445208737Sjmallett  CONFLICT (DMACC, DMACC);
1446208737Sjmallett
1447208737Sjmallett  /* Errata 24 - MT{LO,HI} after [D]MACC */
1448208737Sjmallett  CONFLICT (MACC, MTHILO);
1449208737Sjmallett  CONFLICT (DMACC, MTHILO);
1450208737Sjmallett
1451208737Sjmallett  /* VR4181A errata MD(1): "If a MULT, MULTU, DMULT or DMULTU
1452208737Sjmallett     instruction is executed immediately after a MACC or DMACC
1453208737Sjmallett     instruction, the result of [either instruction] is incorrect."  */
1454208737Sjmallett  CONFLICT (MACC, MULT);
1455208737Sjmallett  CONFLICT (MACC, DMULT);
1456208737Sjmallett  CONFLICT (DMACC, MULT);
1457208737Sjmallett  CONFLICT (DMACC, DMULT);
1458208737Sjmallett
1459208737Sjmallett  /* VR4181A errata MD(4): "If a MACC or DMACC instruction is
1460208737Sjmallett     executed immediately after a DMULT, DMULTU, DIV, DIVU,
1461208737Sjmallett     DDIV or DDIVU instruction, the result of the MACC or
1462208737Sjmallett     DMACC instruction is incorrect.".  */
1463208737Sjmallett  CONFLICT (DMULT, MACC);
1464208737Sjmallett  CONFLICT (DMULT, DMACC);
1465208737Sjmallett  CONFLICT (DIV, MACC);
1466208737Sjmallett  CONFLICT (DIV, DMACC);
1467208737Sjmallett
1468208737Sjmallett#undef CONFLICT
1469208737Sjmallett}
1470208737Sjmallett
1471218822Sdimstruct regname {
1472218822Sdim  const char *name;
1473218822Sdim  unsigned int num;
1474218822Sdim};
1475179404Sobrien
1476218822Sdim#define RTYPE_MASK	0x1ff00
1477218822Sdim#define RTYPE_NUM	0x00100
1478218822Sdim#define RTYPE_FPU	0x00200
1479218822Sdim#define RTYPE_FCC	0x00400
1480218822Sdim#define RTYPE_VEC	0x00800
1481218822Sdim#define RTYPE_GP	0x01000
1482218822Sdim#define RTYPE_CP0	0x02000
1483218822Sdim#define RTYPE_PC	0x04000
1484218822Sdim#define RTYPE_ACC	0x08000
1485218822Sdim#define RTYPE_CCC	0x10000
1486218822Sdim#define RNUM_MASK	0x000ff
1487218822Sdim#define RWARN		0x80000
1488218822Sdim
1489218822Sdim#define GENERIC_REGISTER_NUMBERS \
1490218822Sdim    {"$0",	RTYPE_NUM | 0},  \
1491218822Sdim    {"$1",	RTYPE_NUM | 1},  \
1492218822Sdim    {"$2",	RTYPE_NUM | 2},  \
1493218822Sdim    {"$3",	RTYPE_NUM | 3},  \
1494218822Sdim    {"$4",	RTYPE_NUM | 4},  \
1495218822Sdim    {"$5",	RTYPE_NUM | 5},  \
1496218822Sdim    {"$6",	RTYPE_NUM | 6},  \
1497218822Sdim    {"$7",	RTYPE_NUM | 7},  \
1498218822Sdim    {"$8",	RTYPE_NUM | 8},  \
1499218822Sdim    {"$9",	RTYPE_NUM | 9},  \
1500218822Sdim    {"$10",	RTYPE_NUM | 10}, \
1501218822Sdim    {"$11",	RTYPE_NUM | 11}, \
1502218822Sdim    {"$12",	RTYPE_NUM | 12}, \
1503218822Sdim    {"$13",	RTYPE_NUM | 13}, \
1504218822Sdim    {"$14",	RTYPE_NUM | 14}, \
1505218822Sdim    {"$15",	RTYPE_NUM | 15}, \
1506218822Sdim    {"$16",	RTYPE_NUM | 16}, \
1507218822Sdim    {"$17",	RTYPE_NUM | 17}, \
1508218822Sdim    {"$18",	RTYPE_NUM | 18}, \
1509218822Sdim    {"$19",	RTYPE_NUM | 19}, \
1510218822Sdim    {"$20",	RTYPE_NUM | 20}, \
1511218822Sdim    {"$21",	RTYPE_NUM | 21}, \
1512218822Sdim    {"$22",	RTYPE_NUM | 22}, \
1513218822Sdim    {"$23",	RTYPE_NUM | 23}, \
1514218822Sdim    {"$24",	RTYPE_NUM | 24}, \
1515218822Sdim    {"$25",	RTYPE_NUM | 25}, \
1516218822Sdim    {"$26",	RTYPE_NUM | 26}, \
1517218822Sdim    {"$27",	RTYPE_NUM | 27}, \
1518218822Sdim    {"$28",	RTYPE_NUM | 28}, \
1519218822Sdim    {"$29",	RTYPE_NUM | 29}, \
1520218822Sdim    {"$30",	RTYPE_NUM | 30}, \
1521218822Sdim    {"$31",	RTYPE_NUM | 31}
1522218822Sdim
1523218822Sdim#define FPU_REGISTER_NAMES       \
1524218822Sdim    {"$f0",	RTYPE_FPU | 0},  \
1525218822Sdim    {"$f1",	RTYPE_FPU | 1},  \
1526218822Sdim    {"$f2",	RTYPE_FPU | 2},  \
1527218822Sdim    {"$f3",	RTYPE_FPU | 3},  \
1528218822Sdim    {"$f4",	RTYPE_FPU | 4},  \
1529218822Sdim    {"$f5",	RTYPE_FPU | 5},  \
1530218822Sdim    {"$f6",	RTYPE_FPU | 6},  \
1531218822Sdim    {"$f7",	RTYPE_FPU | 7},  \
1532218822Sdim    {"$f8",	RTYPE_FPU | 8},  \
1533218822Sdim    {"$f9",	RTYPE_FPU | 9},  \
1534218822Sdim    {"$f10",	RTYPE_FPU | 10}, \
1535218822Sdim    {"$f11",	RTYPE_FPU | 11}, \
1536218822Sdim    {"$f12",	RTYPE_FPU | 12}, \
1537218822Sdim    {"$f13",	RTYPE_FPU | 13}, \
1538218822Sdim    {"$f14",	RTYPE_FPU | 14}, \
1539218822Sdim    {"$f15",	RTYPE_FPU | 15}, \
1540218822Sdim    {"$f16",	RTYPE_FPU | 16}, \
1541218822Sdim    {"$f17",	RTYPE_FPU | 17}, \
1542218822Sdim    {"$f18",	RTYPE_FPU | 18}, \
1543218822Sdim    {"$f19",	RTYPE_FPU | 19}, \
1544218822Sdim    {"$f20",	RTYPE_FPU | 20}, \
1545218822Sdim    {"$f21",	RTYPE_FPU | 21}, \
1546218822Sdim    {"$f22",	RTYPE_FPU | 22}, \
1547218822Sdim    {"$f23",	RTYPE_FPU | 23}, \
1548218822Sdim    {"$f24",	RTYPE_FPU | 24}, \
1549218822Sdim    {"$f25",	RTYPE_FPU | 25}, \
1550218822Sdim    {"$f26",	RTYPE_FPU | 26}, \
1551218822Sdim    {"$f27",	RTYPE_FPU | 27}, \
1552218822Sdim    {"$f28",	RTYPE_FPU | 28}, \
1553218822Sdim    {"$f29",	RTYPE_FPU | 29}, \
1554218822Sdim    {"$f30",	RTYPE_FPU | 30}, \
1555218822Sdim    {"$f31",	RTYPE_FPU | 31}
1556218822Sdim
1557218822Sdim#define FPU_CONDITION_CODE_NAMES \
1558218822Sdim    {"$fcc0",	RTYPE_FCC | 0},  \
1559218822Sdim    {"$fcc1",	RTYPE_FCC | 1},  \
1560218822Sdim    {"$fcc2",	RTYPE_FCC | 2},  \
1561218822Sdim    {"$fcc3",	RTYPE_FCC | 3},  \
1562218822Sdim    {"$fcc4",	RTYPE_FCC | 4},  \
1563218822Sdim    {"$fcc5",	RTYPE_FCC | 5},  \
1564218822Sdim    {"$fcc6",	RTYPE_FCC | 6},  \
1565218822Sdim    {"$fcc7",	RTYPE_FCC | 7}
1566218822Sdim
1567218822Sdim#define COPROC_CONDITION_CODE_NAMES         \
1568218822Sdim    {"$cc0",	RTYPE_FCC | RTYPE_CCC | 0}, \
1569218822Sdim    {"$cc1",	RTYPE_FCC | RTYPE_CCC | 1}, \
1570218822Sdim    {"$cc2",	RTYPE_FCC | RTYPE_CCC | 2}, \
1571218822Sdim    {"$cc3",	RTYPE_FCC | RTYPE_CCC | 3}, \
1572218822Sdim    {"$cc4",	RTYPE_FCC | RTYPE_CCC | 4}, \
1573218822Sdim    {"$cc5",	RTYPE_FCC | RTYPE_CCC | 5}, \
1574218822Sdim    {"$cc6",	RTYPE_FCC | RTYPE_CCC | 6}, \
1575218822Sdim    {"$cc7",	RTYPE_FCC | RTYPE_CCC | 7}
1576218822Sdim
1577218822Sdim#define N32N64_SYMBOLIC_REGISTER_NAMES \
1578218822Sdim    {"$a4",	RTYPE_GP | 8},  \
1579218822Sdim    {"$a5",	RTYPE_GP | 9},  \
1580218822Sdim    {"$a6",	RTYPE_GP | 10}, \
1581218822Sdim    {"$a7",	RTYPE_GP | 11}, \
1582218822Sdim    {"$ta0",	RTYPE_GP | 8},  /* alias for $a4 */ \
1583218822Sdim    {"$ta1",	RTYPE_GP | 9},  /* alias for $a5 */ \
1584218822Sdim    {"$ta2",	RTYPE_GP | 10}, /* alias for $a6 */ \
1585218822Sdim    {"$ta3",	RTYPE_GP | 11}, /* alias for $a7 */ \
1586218822Sdim    {"$t0",	RTYPE_GP | 12}, \
1587218822Sdim    {"$t1",	RTYPE_GP | 13}, \
1588218822Sdim    {"$t2",	RTYPE_GP | 14}, \
1589218822Sdim    {"$t3",	RTYPE_GP | 15}
1590218822Sdim
1591218822Sdim#define O32_SYMBOLIC_REGISTER_NAMES \
1592218822Sdim    {"$t0",	RTYPE_GP | 8},  \
1593218822Sdim    {"$t1",	RTYPE_GP | 9},  \
1594218822Sdim    {"$t2",	RTYPE_GP | 10}, \
1595218822Sdim    {"$t3",	RTYPE_GP | 11}, \
1596218822Sdim    {"$t4",	RTYPE_GP | 12}, \
1597218822Sdim    {"$t5",	RTYPE_GP | 13}, \
1598218822Sdim    {"$t6",	RTYPE_GP | 14}, \
1599218822Sdim    {"$t7",	RTYPE_GP | 15}, \
1600218822Sdim    {"$ta0",	RTYPE_GP | 12}, /* alias for $t4 */ \
1601218822Sdim    {"$ta1",	RTYPE_GP | 13}, /* alias for $t5 */ \
1602218822Sdim    {"$ta2",	RTYPE_GP | 14}, /* alias for $t6 */ \
1603218822Sdim    {"$ta3",	RTYPE_GP | 15}  /* alias for $t7 */
1604218822Sdim
1605218822Sdim/* Remaining symbolic register names */
1606218822Sdim#define SYMBOLIC_REGISTER_NAMES \
1607218822Sdim    {"$zero",	RTYPE_GP | 0},  \
1608218822Sdim    {"$at",	RTYPE_GP | 1},  \
1609218822Sdim    {"$AT",	RTYPE_GP | 1},  \
1610218822Sdim    {"$v0",	RTYPE_GP | 2},  \
1611218822Sdim    {"$v1",	RTYPE_GP | 3},  \
1612218822Sdim    {"$a0",	RTYPE_GP | 4},  \
1613218822Sdim    {"$a1",	RTYPE_GP | 5},  \
1614218822Sdim    {"$a2",	RTYPE_GP | 6},  \
1615218822Sdim    {"$a3",	RTYPE_GP | 7},  \
1616218822Sdim    {"$s0",	RTYPE_GP | 16}, \
1617218822Sdim    {"$s1",	RTYPE_GP | 17}, \
1618218822Sdim    {"$s2",	RTYPE_GP | 18}, \
1619218822Sdim    {"$s3",	RTYPE_GP | 19}, \
1620218822Sdim    {"$s4",	RTYPE_GP | 20}, \
1621218822Sdim    {"$s5",	RTYPE_GP | 21}, \
1622218822Sdim    {"$s6",	RTYPE_GP | 22}, \
1623218822Sdim    {"$s7",	RTYPE_GP | 23}, \
1624218822Sdim    {"$t8",	RTYPE_GP | 24}, \
1625218822Sdim    {"$t9",	RTYPE_GP | 25}, \
1626218822Sdim    {"$k0",	RTYPE_GP | 26}, \
1627218822Sdim    {"$kt0",	RTYPE_GP | 26}, \
1628218822Sdim    {"$k1",	RTYPE_GP | 27}, \
1629218822Sdim    {"$kt1",	RTYPE_GP | 27}, \
1630218822Sdim    {"$gp",	RTYPE_GP | 28}, \
1631218822Sdim    {"$sp",	RTYPE_GP | 29}, \
1632218822Sdim    {"$s8",	RTYPE_GP | 30}, \
1633218822Sdim    {"$fp",	RTYPE_GP | 30}, \
1634218822Sdim    {"$ra",	RTYPE_GP | 31}
1635218822Sdim
1636218822Sdim#define MIPS16_SPECIAL_REGISTER_NAMES \
1637218822Sdim    {"$pc",	RTYPE_PC | 0}
1638218822Sdim
1639218822Sdim#define MDMX_VECTOR_REGISTER_NAMES \
1640218822Sdim    /* {"$v0",	RTYPE_VEC | 0},  clash with REG 2 above */ \
1641218822Sdim    /* {"$v1",	RTYPE_VEC | 1},  clash with REG 3 above */ \
1642218822Sdim    {"$v2",	RTYPE_VEC | 2},  \
1643218822Sdim    {"$v3",	RTYPE_VEC | 3},  \
1644218822Sdim    {"$v4",	RTYPE_VEC | 4},  \
1645218822Sdim    {"$v5",	RTYPE_VEC | 5},  \
1646218822Sdim    {"$v6",	RTYPE_VEC | 6},  \
1647218822Sdim    {"$v7",	RTYPE_VEC | 7},  \
1648218822Sdim    {"$v8",	RTYPE_VEC | 8},  \
1649218822Sdim    {"$v9",	RTYPE_VEC | 9},  \
1650218822Sdim    {"$v10",	RTYPE_VEC | 10}, \
1651218822Sdim    {"$v11",	RTYPE_VEC | 11}, \
1652218822Sdim    {"$v12",	RTYPE_VEC | 12}, \
1653218822Sdim    {"$v13",	RTYPE_VEC | 13}, \
1654218822Sdim    {"$v14",	RTYPE_VEC | 14}, \
1655218822Sdim    {"$v15",	RTYPE_VEC | 15}, \
1656218822Sdim    {"$v16",	RTYPE_VEC | 16}, \
1657218822Sdim    {"$v17",	RTYPE_VEC | 17}, \
1658218822Sdim    {"$v18",	RTYPE_VEC | 18}, \
1659218822Sdim    {"$v19",	RTYPE_VEC | 19}, \
1660218822Sdim    {"$v20",	RTYPE_VEC | 20}, \
1661218822Sdim    {"$v21",	RTYPE_VEC | 21}, \
1662218822Sdim    {"$v22",	RTYPE_VEC | 22}, \
1663218822Sdim    {"$v23",	RTYPE_VEC | 23}, \
1664218822Sdim    {"$v24",	RTYPE_VEC | 24}, \
1665218822Sdim    {"$v25",	RTYPE_VEC | 25}, \
1666218822Sdim    {"$v26",	RTYPE_VEC | 26}, \
1667218822Sdim    {"$v27",	RTYPE_VEC | 27}, \
1668218822Sdim    {"$v28",	RTYPE_VEC | 28}, \
1669218822Sdim    {"$v29",	RTYPE_VEC | 29}, \
1670218822Sdim    {"$v30",	RTYPE_VEC | 30}, \
1671218822Sdim    {"$v31",	RTYPE_VEC | 31}
1672218822Sdim
1673218822Sdim#define MIPS_DSP_ACCUMULATOR_NAMES \
1674218822Sdim    {"$ac0",	RTYPE_ACC | 0}, \
1675218822Sdim    {"$ac1",	RTYPE_ACC | 1}, \
1676218822Sdim    {"$ac2",	RTYPE_ACC | 2}, \
1677218822Sdim    {"$ac3",	RTYPE_ACC | 3}
1678218822Sdim
1679218822Sdimstatic const struct regname reg_names[] = {
1680218822Sdim  GENERIC_REGISTER_NUMBERS,
1681218822Sdim  FPU_REGISTER_NAMES,
1682218822Sdim  FPU_CONDITION_CODE_NAMES,
1683218822Sdim  COPROC_CONDITION_CODE_NAMES,
1684218822Sdim
1685218822Sdim  /* The $txx registers depends on the abi,
1686218822Sdim     these will be added later into the symbol table from
1687218822Sdim     one of the tables below once mips_abi is set after
1688218822Sdim     parsing of arguments from the command line. */
1689218822Sdim  SYMBOLIC_REGISTER_NAMES,
1690218822Sdim
1691218822Sdim  MIPS16_SPECIAL_REGISTER_NAMES,
1692218822Sdim  MDMX_VECTOR_REGISTER_NAMES,
1693218822Sdim  MIPS_DSP_ACCUMULATOR_NAMES,
1694218822Sdim  {0, 0}
1695218822Sdim};
1696218822Sdim
1697218822Sdimstatic const struct regname reg_names_o32[] = {
1698218822Sdim  O32_SYMBOLIC_REGISTER_NAMES,
1699218822Sdim  {0, 0}
1700218822Sdim};
1701218822Sdim
1702218822Sdimstatic const struct regname reg_names_n32n64[] = {
1703218822Sdim  N32N64_SYMBOLIC_REGISTER_NAMES,
1704218822Sdim  {0, 0}
1705218822Sdim};
1706218822Sdim
1707218822Sdimstatic int
1708218822Sdimreg_lookup (char **s, unsigned int types, unsigned int *regnop)
1709218822Sdim{
1710218822Sdim  symbolS *symbolP;
1711218822Sdim  char *e;
1712218822Sdim  char save_c;
1713218822Sdim  int reg = -1;
1714218822Sdim
1715218822Sdim  /* Find end of name.  */
1716218822Sdim  e = *s;
1717218822Sdim  if (is_name_beginner (*e))
1718218822Sdim    ++e;
1719218822Sdim  while (is_part_of_name (*e))
1720218822Sdim    ++e;
1721218822Sdim
1722218822Sdim  /* Terminate name.  */
1723218822Sdim  save_c = *e;
1724218822Sdim  *e = '\0';
1725218822Sdim
1726218822Sdim  /* Look for a register symbol.  */
1727218822Sdim  if ((symbolP = symbol_find (*s)) && S_GET_SEGMENT (symbolP) == reg_section)
1728218822Sdim    {
1729218822Sdim      int r = S_GET_VALUE (symbolP);
1730218822Sdim      if (r & types)
1731218822Sdim	reg = r & RNUM_MASK;
1732218822Sdim      else if ((types & RTYPE_VEC) && (r & ~1) == (RTYPE_GP | 2))
1733218822Sdim	/* Convert GP reg $v0/1 to MDMX reg $v0/1!  */
1734218822Sdim	reg = (r & RNUM_MASK) - 2;
1735218822Sdim    }
1736218822Sdim  /* Else see if this is a register defined in an itbl entry.  */
1737218822Sdim  else if ((types & RTYPE_GP) && itbl_have_entries)
1738218822Sdim    {
1739218822Sdim      char *n = *s;
1740218822Sdim      unsigned long r;
1741218822Sdim
1742218822Sdim      if (*n == '$')
1743218822Sdim	++n;
1744218822Sdim      if (itbl_get_reg_val (n, &r))
1745218822Sdim	reg = r & RNUM_MASK;
1746218822Sdim    }
1747218822Sdim
1748218822Sdim  /* Advance to next token if a register was recognised.  */
1749218822Sdim  if (reg >= 0)
1750218822Sdim    *s = e;
1751218822Sdim  else if (types & RWARN)
1752218822Sdim    as_warn ("Unrecognized register name `%s'", *s);
1753218822Sdim
1754218822Sdim  *e = save_c;
1755218822Sdim  if (regnop)
1756218822Sdim    *regnop = reg;
1757218822Sdim  return reg >= 0;
1758218822Sdim}
1759218822Sdim
1760218822Sdim/* This function is called once, at assembler startup time.  It should set up
1761218822Sdim   all the tables, etc. that the MD part of the assembler will need.  */
1762218822Sdim
1763179404Sobrienvoid
1764179404Sobrienmd_begin (void)
1765179404Sobrien{
1766218822Sdim  const char *retval = NULL;
1767179404Sobrien  int i = 0;
1768179404Sobrien  int broken = 0;
1769179404Sobrien
1770208737Sjmallett  if (mips_pic != NO_PIC)
1771208737Sjmallett    {
1772208737Sjmallett      if (g_switch_seen && g_switch_value != 0)
1773208737Sjmallett	as_bad (_("-G may not be used in position-independent code"));
1774208737Sjmallett      g_switch_value = 0;
1775208737Sjmallett    }
1776208737Sjmallett
1777179404Sobrien  if (! bfd_set_arch_mach (stdoutput, bfd_arch_mips, file_mips_arch))
1778179404Sobrien    as_warn (_("Could not set architecture and machine"));
1779179404Sobrien
1780179404Sobrien  op_hash = hash_new ();
1781179404Sobrien
1782179404Sobrien  for (i = 0; i < NUMOPCODES;)
1783179404Sobrien    {
1784179404Sobrien      const char *name = mips_opcodes[i].name;
1785179404Sobrien
1786179404Sobrien      retval = hash_insert (op_hash, name, (void *) &mips_opcodes[i]);
1787179404Sobrien      if (retval != NULL)
1788179404Sobrien	{
1789179404Sobrien	  fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
1790179404Sobrien		   mips_opcodes[i].name, retval);
1791179404Sobrien	  /* Probably a memory allocation problem?  Give up now.  */
1792179404Sobrien	  as_fatal (_("Broken assembler.  No assembly attempted."));
1793179404Sobrien	}
1794179404Sobrien      do
1795179404Sobrien	{
1796179404Sobrien	  if (mips_opcodes[i].pinfo != INSN_MACRO)
1797179404Sobrien	    {
1798179404Sobrien	      if (!validate_mips_insn (&mips_opcodes[i]))
1799179404Sobrien		broken = 1;
1800208737Sjmallett	      if (nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
1801208737Sjmallett		{
1802208737Sjmallett		  create_insn (&nop_insn, mips_opcodes + i);
1803208737Sjmallett		  nop_insn.fixed_p = 1;
1804208737Sjmallett		}
1805179404Sobrien	    }
1806179404Sobrien	  ++i;
1807179404Sobrien	}
1808179404Sobrien      while ((i < NUMOPCODES) && !strcmp (mips_opcodes[i].name, name));
1809179404Sobrien    }
1810179404Sobrien
1811179404Sobrien  mips16_op_hash = hash_new ();
1812179404Sobrien
1813179404Sobrien  i = 0;
1814179404Sobrien  while (i < bfd_mips16_num_opcodes)
1815179404Sobrien    {
1816179404Sobrien      const char *name = mips16_opcodes[i].name;
1817179404Sobrien
1818179404Sobrien      retval = hash_insert (mips16_op_hash, name, (void *) &mips16_opcodes[i]);
1819179404Sobrien      if (retval != NULL)
1820179404Sobrien	as_fatal (_("internal: can't hash `%s': %s"),
1821179404Sobrien		  mips16_opcodes[i].name, retval);
1822179404Sobrien      do
1823179404Sobrien	{
1824179404Sobrien	  if (mips16_opcodes[i].pinfo != INSN_MACRO
1825179404Sobrien	      && ((mips16_opcodes[i].match & mips16_opcodes[i].mask)
1826179404Sobrien		  != mips16_opcodes[i].match))
1827179404Sobrien	    {
1828179404Sobrien	      fprintf (stderr, _("internal error: bad mips16 opcode: %s %s\n"),
1829179404Sobrien		       mips16_opcodes[i].name, mips16_opcodes[i].args);
1830179404Sobrien	      broken = 1;
1831179404Sobrien	    }
1832208737Sjmallett	  if (mips16_nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
1833208737Sjmallett	    {
1834208737Sjmallett	      create_insn (&mips16_nop_insn, mips16_opcodes + i);
1835208737Sjmallett	      mips16_nop_insn.fixed_p = 1;
1836208737Sjmallett	    }
1837179404Sobrien	  ++i;
1838179404Sobrien	}
1839179404Sobrien      while (i < bfd_mips16_num_opcodes
1840179404Sobrien	     && strcmp (mips16_opcodes[i].name, name) == 0);
1841179404Sobrien    }
1842179404Sobrien
1843179404Sobrien  if (broken)
1844179404Sobrien    as_fatal (_("Broken assembler.  No assembly attempted."));
1845179404Sobrien
1846179404Sobrien  /* We add all the general register names to the symbol table.  This
1847179404Sobrien     helps us detect invalid uses of them.  */
1848218822Sdim  for (i = 0; reg_names[i].name; i++)
1849218822Sdim    symbol_table_insert (symbol_new (reg_names[i].name, reg_section,
1850218822Sdim				     reg_names[i].num, // & RNUM_MASK,
1851218822Sdim				     &zero_address_frag));
1852218822Sdim  if (HAVE_NEWABI)
1853218822Sdim    for (i = 0; reg_names_n32n64[i].name; i++)
1854218822Sdim      symbol_table_insert (symbol_new (reg_names_n32n64[i].name, reg_section,
1855218822Sdim				       reg_names_n32n64[i].num, // & RNUM_MASK,
1856179404Sobrien				       &zero_address_frag));
1857218822Sdim  else
1858218822Sdim    for (i = 0; reg_names_o32[i].name; i++)
1859218822Sdim      symbol_table_insert (symbol_new (reg_names_o32[i].name, reg_section,
1860218822Sdim				       reg_names_o32[i].num, // & RNUM_MASK,
1861179404Sobrien				       &zero_address_frag));
1862179404Sobrien
1863208737Sjmallett  mips_no_prev_insn ();
1864179404Sobrien
1865179404Sobrien  mips_gprmask = 0;
1866179404Sobrien  mips_cprmask[0] = 0;
1867179404Sobrien  mips_cprmask[1] = 0;
1868179404Sobrien  mips_cprmask[2] = 0;
1869179404Sobrien  mips_cprmask[3] = 0;
1870179404Sobrien
1871179404Sobrien  /* set the default alignment for the text section (2**2) */
1872179404Sobrien  record_alignment (text_section, 2);
1873179404Sobrien
1874208737Sjmallett  bfd_set_gp_size (stdoutput, g_switch_value);
1875179404Sobrien
1876218822Sdim#ifdef OBJ_ELF
1877218822Sdim  if (IS_ELF)
1878179404Sobrien    {
1879218822Sdim      /* On a native system other than VxWorks, sections must be aligned
1880218822Sdim	 to 16 byte boundaries.  When configured for an embedded ELF
1881218822Sdim	 target, we don't bother.  */
1882208737Sjmallett      if (strcmp (TARGET_OS, "elf") != 0
1883208737Sjmallett	  && strcmp (TARGET_OS, "vxworks") != 0)
1884179404Sobrien	{
1885179404Sobrien	  (void) bfd_set_section_alignment (stdoutput, text_section, 4);
1886179404Sobrien	  (void) bfd_set_section_alignment (stdoutput, data_section, 4);
1887179404Sobrien	  (void) bfd_set_section_alignment (stdoutput, bss_section, 4);
1888179404Sobrien	}
1889179404Sobrien
1890179404Sobrien      /* Create a .reginfo section for register masks and a .mdebug
1891179404Sobrien	 section for debugging information.  */
1892179404Sobrien      {
1893179404Sobrien	segT seg;
1894179404Sobrien	subsegT subseg;
1895179404Sobrien	flagword flags;
1896179404Sobrien	segT sec;
1897179404Sobrien
1898179404Sobrien	seg = now_seg;
1899179404Sobrien	subseg = now_subseg;
1900179404Sobrien
1901179404Sobrien	/* The ABI says this section should be loaded so that the
1902179404Sobrien	   running program can access it.  However, we don't load it
1903179404Sobrien	   if we are configured for an embedded target */
1904179404Sobrien	flags = SEC_READONLY | SEC_DATA;
1905179404Sobrien	if (strcmp (TARGET_OS, "elf") != 0)
1906179404Sobrien	  flags |= SEC_ALLOC | SEC_LOAD;
1907179404Sobrien
1908179404Sobrien	if (mips_abi != N64_ABI)
1909179404Sobrien	  {
1910179404Sobrien	    sec = subseg_new (".reginfo", (subsegT) 0);
1911179404Sobrien
1912179404Sobrien	    bfd_set_section_flags (stdoutput, sec, flags);
1913179404Sobrien	    bfd_set_section_alignment (stdoutput, sec, HAVE_NEWABI ? 3 : 2);
1914179404Sobrien
1915179404Sobrien	    mips_regmask_frag = frag_more (sizeof (Elf32_External_RegInfo));
1916179404Sobrien	  }
1917179404Sobrien	else
1918179404Sobrien	  {
1919179404Sobrien	    /* The 64-bit ABI uses a .MIPS.options section rather than
1920179404Sobrien               .reginfo section.  */
1921179404Sobrien	    sec = subseg_new (".MIPS.options", (subsegT) 0);
1922179404Sobrien	    bfd_set_section_flags (stdoutput, sec, flags);
1923179404Sobrien	    bfd_set_section_alignment (stdoutput, sec, 3);
1924179404Sobrien
1925179404Sobrien	    /* Set up the option header.  */
1926179404Sobrien	    {
1927179404Sobrien	      Elf_Internal_Options opthdr;
1928179404Sobrien	      char *f;
1929179404Sobrien
1930179404Sobrien	      opthdr.kind = ODK_REGINFO;
1931179404Sobrien	      opthdr.size = (sizeof (Elf_External_Options)
1932179404Sobrien			     + sizeof (Elf64_External_RegInfo));
1933179404Sobrien	      opthdr.section = 0;
1934179404Sobrien	      opthdr.info = 0;
1935179404Sobrien	      f = frag_more (sizeof (Elf_External_Options));
1936179404Sobrien	      bfd_mips_elf_swap_options_out (stdoutput, &opthdr,
1937179404Sobrien					     (Elf_External_Options *) f);
1938179404Sobrien
1939179404Sobrien	      mips_regmask_frag = frag_more (sizeof (Elf64_External_RegInfo));
1940179404Sobrien	    }
1941179404Sobrien	  }
1942179404Sobrien
1943179404Sobrien	if (ECOFF_DEBUGGING)
1944179404Sobrien	  {
1945179404Sobrien	    sec = subseg_new (".mdebug", (subsegT) 0);
1946179404Sobrien	    (void) bfd_set_section_flags (stdoutput, sec,
1947179404Sobrien					  SEC_HAS_CONTENTS | SEC_READONLY);
1948179404Sobrien	    (void) bfd_set_section_alignment (stdoutput, sec, 2);
1949179404Sobrien	  }
1950218822Sdim	else if (mips_flag_pdr)
1951179404Sobrien	  {
1952179404Sobrien	    pdr_seg = subseg_new (".pdr", (subsegT) 0);
1953179404Sobrien	    (void) bfd_set_section_flags (stdoutput, pdr_seg,
1954179404Sobrien					  SEC_READONLY | SEC_RELOC
1955179404Sobrien					  | SEC_DEBUGGING);
1956179404Sobrien	    (void) bfd_set_section_alignment (stdoutput, pdr_seg, 2);
1957179404Sobrien	  }
1958179404Sobrien
1959179404Sobrien	subseg_set (seg, subseg);
1960179404Sobrien      }
1961179404Sobrien    }
1962218822Sdim#endif /* OBJ_ELF */
1963179404Sobrien
1964179404Sobrien  if (! ECOFF_DEBUGGING)
1965179404Sobrien    md_obj_begin ();
1966208737Sjmallett
1967208737Sjmallett  if (mips_fix_vr4120)
1968208737Sjmallett    init_vr4120_conflicts ();
1969179404Sobrien}
1970179404Sobrien
1971179404Sobrienvoid
1972179404Sobrienmd_mips_end (void)
1973179404Sobrien{
1974179404Sobrien  if (! ECOFF_DEBUGGING)
1975179404Sobrien    md_obj_end ();
1976179404Sobrien}
1977179404Sobrien
1978179404Sobrienvoid
1979179404Sobrienmd_assemble (char *str)
1980179404Sobrien{
1981179404Sobrien  struct mips_cl_insn insn;
1982179404Sobrien  bfd_reloc_code_real_type unused_reloc[3]
1983179404Sobrien    = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
1984179404Sobrien
1985179404Sobrien  imm_expr.X_op = O_absent;
1986179404Sobrien  imm2_expr.X_op = O_absent;
1987179404Sobrien  offset_expr.X_op = O_absent;
1988179404Sobrien  imm_reloc[0] = BFD_RELOC_UNUSED;
1989179404Sobrien  imm_reloc[1] = BFD_RELOC_UNUSED;
1990179404Sobrien  imm_reloc[2] = BFD_RELOC_UNUSED;
1991179404Sobrien  offset_reloc[0] = BFD_RELOC_UNUSED;
1992179404Sobrien  offset_reloc[1] = BFD_RELOC_UNUSED;
1993179404Sobrien  offset_reloc[2] = BFD_RELOC_UNUSED;
1994179404Sobrien
1995179404Sobrien  if (mips_opts.mips16)
1996179404Sobrien    mips16_ip (str, &insn);
1997179404Sobrien  else
1998179404Sobrien    {
1999179404Sobrien      mips_ip (str, &insn);
2000179404Sobrien      DBG ((_("returned from mips_ip(%s) insn_opcode = 0x%x\n"),
2001179404Sobrien	    str, insn.insn_opcode));
2002179404Sobrien    }
2003179404Sobrien
2004179404Sobrien  if (insn_error)
2005179404Sobrien    {
2006179404Sobrien      as_bad ("%s `%s'", insn_error, str);
2007179404Sobrien      return;
2008179404Sobrien    }
2009179404Sobrien
2010179404Sobrien  if (insn.insn_mo->pinfo == INSN_MACRO)
2011179404Sobrien    {
2012179404Sobrien      macro_start ();
2013179404Sobrien      if (mips_opts.mips16)
2014179404Sobrien	mips16_macro (&insn);
2015179404Sobrien      else
2016179404Sobrien	macro (&insn);
2017179404Sobrien      macro_end ();
2018179404Sobrien    }
2019179404Sobrien  else
2020179404Sobrien    {
2021179404Sobrien      if (imm_expr.X_op != O_absent)
2022179404Sobrien	append_insn (&insn, &imm_expr, imm_reloc);
2023179404Sobrien      else if (offset_expr.X_op != O_absent)
2024179404Sobrien	append_insn (&insn, &offset_expr, offset_reloc);
2025179404Sobrien      else
2026179404Sobrien	append_insn (&insn, NULL, unused_reloc);
2027179404Sobrien    }
2028179404Sobrien}
2029179404Sobrien
2030179404Sobrien/* Return true if the given relocation might need a matching %lo().
2031208737Sjmallett   This is only "might" because SVR4 R_MIPS_GOT16 relocations only
2032208737Sjmallett   need a matching %lo() when applied to local symbols.  */
2033179404Sobrien
2034179404Sobrienstatic inline bfd_boolean
2035179404Sobrienreloc_needs_lo_p (bfd_reloc_code_real_type reloc)
2036179404Sobrien{
2037218822Sdim  return (HAVE_IN_PLACE_ADDENDS
2038218822Sdim	  && (reloc == BFD_RELOC_HI16_S
2039218822Sdim	      || reloc == BFD_RELOC_MIPS16_HI16_S
2040218822Sdim	      /* VxWorks R_MIPS_GOT16 relocs never need a matching %lo();
2041218822Sdim		 all GOT16 relocations evaluate to "G".  */
2042218822Sdim	      || (reloc == BFD_RELOC_MIPS_GOT16 && mips_pic != VXWORKS_PIC)));
2043179404Sobrien}
2044179404Sobrien
2045179404Sobrien/* Return true if the given fixup is followed by a matching R_MIPS_LO16
2046179404Sobrien   relocation.  */
2047179404Sobrien
2048179404Sobrienstatic inline bfd_boolean
2049179404Sobrienfixup_has_matching_lo_p (fixS *fixp)
2050179404Sobrien{
2051179404Sobrien  return (fixp->fx_next != NULL
2052218822Sdim	  && (fixp->fx_next->fx_r_type == BFD_RELOC_LO16
2053218822Sdim	     || fixp->fx_next->fx_r_type == BFD_RELOC_MIPS16_LO16)
2054179404Sobrien	  && fixp->fx_addsy == fixp->fx_next->fx_addsy
2055179404Sobrien	  && fixp->fx_offset == fixp->fx_next->fx_offset);
2056179404Sobrien}
2057179404Sobrien
2058179404Sobrien/* See whether instruction IP reads register REG.  CLASS is the type
2059179404Sobrien   of register.  */
2060179404Sobrien
2061179404Sobrienstatic int
2062208737Sjmallettinsn_uses_reg (const struct mips_cl_insn *ip, unsigned int reg,
2063179404Sobrien	       enum mips_regclass class)
2064179404Sobrien{
2065179404Sobrien  if (class == MIPS16_REG)
2066179404Sobrien    {
2067179404Sobrien      assert (mips_opts.mips16);
2068179404Sobrien      reg = mips16_to_32_reg_map[reg];
2069179404Sobrien      class = MIPS_GR_REG;
2070179404Sobrien    }
2071179404Sobrien
2072179404Sobrien  /* Don't report on general register ZERO, since it never changes.  */
2073179404Sobrien  if (class == MIPS_GR_REG && reg == ZERO)
2074179404Sobrien    return 0;
2075179404Sobrien
2076179404Sobrien  if (class == MIPS_FP_REG)
2077179404Sobrien    {
2078179404Sobrien      assert (! mips_opts.mips16);
2079179404Sobrien      /* If we are called with either $f0 or $f1, we must check $f0.
2080179404Sobrien	 This is not optimal, because it will introduce an unnecessary
2081179404Sobrien	 NOP between "lwc1 $f0" and "swc1 $f1".  To fix this we would
2082179404Sobrien	 need to distinguish reading both $f0 and $f1 or just one of
2083179404Sobrien	 them.  Note that we don't have to check the other way,
2084179404Sobrien	 because there is no instruction that sets both $f0 and $f1
2085179404Sobrien	 and requires a delay.  */
2086179404Sobrien      if ((ip->insn_mo->pinfo & INSN_READ_FPR_S)
2087208737Sjmallett	  && ((EXTRACT_OPERAND (FS, *ip) & ~(unsigned) 1)
2088179404Sobrien	      == (reg &~ (unsigned) 1)))
2089179404Sobrien	return 1;
2090179404Sobrien      if ((ip->insn_mo->pinfo & INSN_READ_FPR_T)
2091208737Sjmallett	  && ((EXTRACT_OPERAND (FT, *ip) & ~(unsigned) 1)
2092179404Sobrien	      == (reg &~ (unsigned) 1)))
2093179404Sobrien	return 1;
2094179404Sobrien    }
2095179404Sobrien  else if (! mips_opts.mips16)
2096179404Sobrien    {
2097179404Sobrien      if ((ip->insn_mo->pinfo & INSN_READ_GPR_S)
2098208737Sjmallett	  && EXTRACT_OPERAND (RS, *ip) == reg)
2099179404Sobrien	return 1;
2100179404Sobrien      if ((ip->insn_mo->pinfo & INSN_READ_GPR_T)
2101208737Sjmallett	  && EXTRACT_OPERAND (RT, *ip) == reg)
2102179404Sobrien	return 1;
2103179404Sobrien    }
2104179404Sobrien  else
2105179404Sobrien    {
2106179404Sobrien      if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_X)
2107208737Sjmallett	  && mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, *ip)] == reg)
2108179404Sobrien	return 1;
2109179404Sobrien      if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_Y)
2110208737Sjmallett	  && mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RY, *ip)] == reg)
2111179404Sobrien	return 1;
2112179404Sobrien      if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_Z)
2113208737Sjmallett	  && (mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (MOVE32Z, *ip)]
2114179404Sobrien	      == reg))
2115179404Sobrien	return 1;
2116179404Sobrien      if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_T) && reg == TREG)
2117179404Sobrien	return 1;
2118179404Sobrien      if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_SP) && reg == SP)
2119179404Sobrien	return 1;
2120179404Sobrien      if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_31) && reg == RA)
2121179404Sobrien	return 1;
2122179404Sobrien      if ((ip->insn_mo->pinfo & MIPS16_INSN_READ_GPR_X)
2123208737Sjmallett	  && MIPS16_EXTRACT_OPERAND (REGR32, *ip) == reg)
2124179404Sobrien	return 1;
2125179404Sobrien    }
2126179404Sobrien
2127179404Sobrien  return 0;
2128179404Sobrien}
2129179404Sobrien
2130179404Sobrien/* This function returns true if modifying a register requires a
2131179404Sobrien   delay.  */
2132179404Sobrien
2133179404Sobrienstatic int
2134179404Sobrienreg_needs_delay (unsigned int reg)
2135179404Sobrien{
2136179404Sobrien  unsigned long prev_pinfo;
2137179404Sobrien
2138208737Sjmallett  prev_pinfo = history[0].insn_mo->pinfo;
2139179404Sobrien  if (! mips_opts.noreorder
2140179404Sobrien      && (((prev_pinfo & INSN_LOAD_MEMORY_DELAY)
2141179404Sobrien	   && ! gpr_interlocks)
2142179404Sobrien	  || ((prev_pinfo & INSN_LOAD_COPROC_DELAY)
2143179404Sobrien	      && ! cop_interlocks)))
2144179404Sobrien    {
2145179404Sobrien      /* A load from a coprocessor or from memory.  All load delays
2146179404Sobrien	 delay the use of general register rt for one instruction.  */
2147179404Sobrien      /* Itbl support may require additional care here.  */
2148179404Sobrien      know (prev_pinfo & INSN_WRITE_GPR_T);
2149208737Sjmallett      if (reg == EXTRACT_OPERAND (RT, history[0]))
2150179404Sobrien	return 1;
2151179404Sobrien    }
2152179404Sobrien
2153179404Sobrien  return 0;
2154179404Sobrien}
2155179404Sobrien
2156208737Sjmallett/* Move all labels in insn_labels to the current insertion point.  */
2157208737Sjmallett
2158208737Sjmallettstatic void
2159208737Sjmallettmips_move_labels (void)
2160208737Sjmallett{
2161218822Sdim  segment_info_type *si = seg_info (now_seg);
2162208737Sjmallett  struct insn_label_list *l;
2163208737Sjmallett  valueT val;
2164208737Sjmallett
2165218822Sdim  for (l = si->label_list; l != NULL; l = l->next)
2166208737Sjmallett    {
2167208737Sjmallett      assert (S_GET_SEGMENT (l->label) == now_seg);
2168208737Sjmallett      symbol_set_frag (l->label, frag_now);
2169208737Sjmallett      val = (valueT) frag_now_fix ();
2170208737Sjmallett      /* mips16 text labels are stored as odd.  */
2171208737Sjmallett      if (mips_opts.mips16)
2172208737Sjmallett	++val;
2173208737Sjmallett      S_SET_VALUE (l->label, val);
2174208737Sjmallett    }
2175208737Sjmallett}
2176208737Sjmallett
2177218822Sdimstatic bfd_boolean
2178218822Sdims_is_linkonce (symbolS *sym, segT from_seg)
2179218822Sdim{
2180218822Sdim  bfd_boolean linkonce = FALSE;
2181218822Sdim  segT symseg = S_GET_SEGMENT (sym);
2182218822Sdim
2183218822Sdim  if (symseg != from_seg && !S_IS_LOCAL (sym))
2184218822Sdim    {
2185218822Sdim      if ((bfd_get_section_flags (stdoutput, symseg) & SEC_LINK_ONCE))
2186218822Sdim	linkonce = TRUE;
2187218822Sdim#ifdef OBJ_ELF
2188218822Sdim      /* The GNU toolchain uses an extension for ELF: a section
2189218822Sdim	 beginning with the magic string .gnu.linkonce is a
2190218822Sdim	 linkonce section.  */
2191218822Sdim      if (strncmp (segment_name (symseg), ".gnu.linkonce",
2192218822Sdim		   sizeof ".gnu.linkonce" - 1) == 0)
2193218822Sdim	linkonce = TRUE;
2194218822Sdim#endif
2195218822Sdim    }
2196218822Sdim  return linkonce;
2197218822Sdim}
2198218822Sdim
2199179404Sobrien/* Mark instruction labels in mips16 mode.  This permits the linker to
2200179404Sobrien   handle them specially, such as generating jalx instructions when
2201179404Sobrien   needed.  We also make them odd for the duration of the assembly, in
2202179404Sobrien   order to generate the right sort of code.  We will make them even
2203179404Sobrien   in the adjust_symtab routine, while leaving them marked.  This is
2204179404Sobrien   convenient for the debugger and the disassembler.  The linker knows
2205179404Sobrien   to make them odd again.  */
2206179404Sobrien
2207179404Sobrienstatic void
2208179404Sobrienmips16_mark_labels (void)
2209179404Sobrien{
2210218822Sdim  segment_info_type *si = seg_info (now_seg);
2211218822Sdim  struct insn_label_list *l;
2212179404Sobrien
2213218822Sdim  if (!mips_opts.mips16)
2214218822Sdim    return;
2215218822Sdim
2216218822Sdim  for (l = si->label_list; l != NULL; l = l->next)
2217218822Sdim   {
2218218822Sdim      symbolS *label = l->label;
2219218822Sdim
2220218822Sdim#if defined(OBJ_ELF) || defined(OBJ_MAYBE_ELF)
2221218822Sdim      if (IS_ELF)
2222218822Sdim	S_SET_OTHER (label, STO_MIPS16);
2223179404Sobrien#endif
2224218822Sdim      if ((S_GET_VALUE (label) & 1) == 0
2225218822Sdim	/* Don't adjust the address if the label is global or weak, or
2226218822Sdim	   in a link-once section, since we'll be emitting symbol reloc
2227218822Sdim	   references to it which will be patched up by the linker, and
2228218822Sdim	   the final value of the symbol may or may not be MIPS16.  */
2229218822Sdim	  && ! S_IS_WEAK (label)
2230218822Sdim	  && ! S_IS_EXTERNAL (label)
2231218822Sdim	  && ! s_is_linkonce (label, now_seg))
2232218822Sdim	S_SET_VALUE (label, S_GET_VALUE (label) | 1);
2233179404Sobrien    }
2234179404Sobrien}
2235179404Sobrien
2236179404Sobrien/* End the current frag.  Make it a variant frag and record the
2237179404Sobrien   relaxation info.  */
2238179404Sobrien
2239179404Sobrienstatic void
2240179404Sobrienrelax_close_frag (void)
2241179404Sobrien{
2242179404Sobrien  mips_macro_warning.first_frag = frag_now;
2243179404Sobrien  frag_var (rs_machine_dependent, 0, 0,
2244179404Sobrien	    RELAX_ENCODE (mips_relax.sizes[0], mips_relax.sizes[1]),
2245179404Sobrien	    mips_relax.symbol, 0, (char *) mips_relax.first_fixup);
2246179404Sobrien
2247179404Sobrien  memset (&mips_relax.sizes, 0, sizeof (mips_relax.sizes));
2248179404Sobrien  mips_relax.first_fixup = 0;
2249179404Sobrien}
2250179404Sobrien
2251179404Sobrien/* Start a new relaxation sequence whose expansion depends on SYMBOL.
2252179404Sobrien   See the comment above RELAX_ENCODE for more details.  */
2253179404Sobrien
2254179404Sobrienstatic void
2255179404Sobrienrelax_start (symbolS *symbol)
2256179404Sobrien{
2257179404Sobrien  assert (mips_relax.sequence == 0);
2258179404Sobrien  mips_relax.sequence = 1;
2259179404Sobrien  mips_relax.symbol = symbol;
2260179404Sobrien}
2261179404Sobrien
2262179404Sobrien/* Start generating the second version of a relaxable sequence.
2263179404Sobrien   See the comment above RELAX_ENCODE for more details.  */
2264179404Sobrien
2265179404Sobrienstatic void
2266179404Sobrienrelax_switch (void)
2267179404Sobrien{
2268179404Sobrien  assert (mips_relax.sequence == 1);
2269179404Sobrien  mips_relax.sequence = 2;
2270179404Sobrien}
2271179404Sobrien
2272179404Sobrien/* End the current relaxable sequence.  */
2273179404Sobrien
2274179404Sobrienstatic void
2275179404Sobrienrelax_end (void)
2276179404Sobrien{
2277179404Sobrien  assert (mips_relax.sequence == 2);
2278179404Sobrien  relax_close_frag ();
2279179404Sobrien  mips_relax.sequence = 0;
2280179404Sobrien}
2281179404Sobrien
2282208737Sjmallett/* Classify an instruction according to the FIX_VR4120_* enumeration.
2283208737Sjmallett   Return NUM_FIX_VR4120_CLASSES if the instruction isn't affected
2284208737Sjmallett   by VR4120 errata.  */
2285179404Sobrien
2286208737Sjmallettstatic unsigned int
2287208737Sjmallettclassify_vr4120_insn (const char *name)
2288179404Sobrien{
2289208737Sjmallett  if (strncmp (name, "macc", 4) == 0)
2290208737Sjmallett    return FIX_VR4120_MACC;
2291208737Sjmallett  if (strncmp (name, "dmacc", 5) == 0)
2292208737Sjmallett    return FIX_VR4120_DMACC;
2293208737Sjmallett  if (strncmp (name, "mult", 4) == 0)
2294208737Sjmallett    return FIX_VR4120_MULT;
2295208737Sjmallett  if (strncmp (name, "dmult", 5) == 0)
2296208737Sjmallett    return FIX_VR4120_DMULT;
2297208737Sjmallett  if (strstr (name, "div"))
2298208737Sjmallett    return FIX_VR4120_DIV;
2299208737Sjmallett  if (strcmp (name, "mtlo") == 0 || strcmp (name, "mthi") == 0)
2300208737Sjmallett    return FIX_VR4120_MTHILO;
2301208737Sjmallett  return NUM_FIX_VR4120_CLASSES;
2302208737Sjmallett}
2303179404Sobrien
2304208737Sjmallett/* Return the number of instructions that must separate INSN1 and INSN2,
2305208737Sjmallett   where INSN1 is the earlier instruction.  Return the worst-case value
2306208737Sjmallett   for any INSN2 if INSN2 is null.  */
2307179404Sobrien
2308208737Sjmallettstatic unsigned int
2309208737Sjmallettinsns_between (const struct mips_cl_insn *insn1,
2310208737Sjmallett	       const struct mips_cl_insn *insn2)
2311208737Sjmallett{
2312208737Sjmallett  unsigned long pinfo1, pinfo2;
2313179404Sobrien
2314208737Sjmallett  /* This function needs to know which pinfo flags are set for INSN2
2315208737Sjmallett     and which registers INSN2 uses.  The former is stored in PINFO2 and
2316208737Sjmallett     the latter is tested via INSN2_USES_REG.  If INSN2 is null, PINFO2
2317208737Sjmallett     will have every flag set and INSN2_USES_REG will always return true.  */
2318208737Sjmallett  pinfo1 = insn1->insn_mo->pinfo;
2319208737Sjmallett  pinfo2 = insn2 ? insn2->insn_mo->pinfo : ~0U;
2320208737Sjmallett
2321208737Sjmallett#define INSN2_USES_REG(REG, CLASS) \
2322208737Sjmallett   (insn2 == NULL || insn_uses_reg (insn2, REG, CLASS))
2323208737Sjmallett
2324208737Sjmallett  /* For most targets, write-after-read dependencies on the HI and LO
2325208737Sjmallett     registers must be separated by at least two instructions.  */
2326208737Sjmallett  if (!hilo_interlocks)
2327179404Sobrien    {
2328208737Sjmallett      if ((pinfo1 & INSN_READ_LO) && (pinfo2 & INSN_WRITE_LO))
2329208737Sjmallett	return 2;
2330208737Sjmallett      if ((pinfo1 & INSN_READ_HI) && (pinfo2 & INSN_WRITE_HI))
2331208737Sjmallett	return 2;
2332208737Sjmallett    }
2333179404Sobrien
2334208737Sjmallett  /* If we're working around r7000 errata, there must be two instructions
2335208737Sjmallett     between an mfhi or mflo and any instruction that uses the result.  */
2336208737Sjmallett  if (mips_7000_hilo_fix
2337208737Sjmallett      && MF_HILO_INSN (pinfo1)
2338208737Sjmallett      && INSN2_USES_REG (EXTRACT_OPERAND (RD, *insn1), MIPS_GR_REG))
2339208737Sjmallett    return 2;
2340179404Sobrien
2341208737Sjmallett  /* If working around VR4120 errata, check for combinations that need
2342208737Sjmallett     a single intervening instruction.  */
2343208737Sjmallett  if (mips_fix_vr4120)
2344208737Sjmallett    {
2345208737Sjmallett      unsigned int class1, class2;
2346179404Sobrien
2347208737Sjmallett      class1 = classify_vr4120_insn (insn1->insn_mo->name);
2348208737Sjmallett      if (class1 != NUM_FIX_VR4120_CLASSES && vr4120_conflicts[class1] != 0)
2349208737Sjmallett	{
2350208737Sjmallett	  if (insn2 == NULL)
2351208737Sjmallett	    return 1;
2352208737Sjmallett	  class2 = classify_vr4120_insn (insn2->insn_mo->name);
2353208737Sjmallett	  if (vr4120_conflicts[class1] & (1 << class2))
2354208737Sjmallett	    return 1;
2355208737Sjmallett	}
2356208737Sjmallett    }
2357179404Sobrien
2358208737Sjmallett  if (!mips_opts.mips16)
2359208737Sjmallett    {
2360208737Sjmallett      /* Check for GPR or coprocessor load delays.  All such delays
2361208737Sjmallett	 are on the RT register.  */
2362208737Sjmallett      /* Itbl support may require additional care here.  */
2363208737Sjmallett      if ((!gpr_interlocks && (pinfo1 & INSN_LOAD_MEMORY_DELAY))
2364208737Sjmallett	  || (!cop_interlocks && (pinfo1 & INSN_LOAD_COPROC_DELAY)))
2365179404Sobrien	{
2366208737Sjmallett	  know (pinfo1 & INSN_WRITE_GPR_T);
2367208737Sjmallett	  if (INSN2_USES_REG (EXTRACT_OPERAND (RT, *insn1), MIPS_GR_REG))
2368208737Sjmallett	    return 1;
2369179404Sobrien	}
2370208737Sjmallett
2371208737Sjmallett      /* Check for generic coprocessor hazards.
2372208737Sjmallett
2373208737Sjmallett	 This case is not handled very well.  There is no special
2374208737Sjmallett	 knowledge of CP0 handling, and the coprocessors other than
2375208737Sjmallett	 the floating point unit are not distinguished at all.  */
2376208737Sjmallett      /* Itbl support may require additional care here. FIXME!
2377208737Sjmallett	 Need to modify this to include knowledge about
2378208737Sjmallett	 user specified delays!  */
2379208737Sjmallett      else if ((!cop_interlocks && (pinfo1 & INSN_COPROC_MOVE_DELAY))
2380208737Sjmallett	       || (!cop_mem_interlocks && (pinfo1 & INSN_COPROC_MEMORY_DELAY)))
2381179404Sobrien	{
2382208737Sjmallett	  /* Handle cases where INSN1 writes to a known general coprocessor
2383208737Sjmallett	     register.  There must be a one instruction delay before INSN2
2384208737Sjmallett	     if INSN2 reads that register, otherwise no delay is needed.  */
2385208737Sjmallett	  if (pinfo1 & INSN_WRITE_FPR_T)
2386179404Sobrien	    {
2387208737Sjmallett	      if (INSN2_USES_REG (EXTRACT_OPERAND (FT, *insn1), MIPS_FP_REG))
2388208737Sjmallett		return 1;
2389179404Sobrien	    }
2390208737Sjmallett	  else if (pinfo1 & INSN_WRITE_FPR_S)
2391179404Sobrien	    {
2392208737Sjmallett	      if (INSN2_USES_REG (EXTRACT_OPERAND (FS, *insn1), MIPS_FP_REG))
2393208737Sjmallett		return 1;
2394179404Sobrien	    }
2395179404Sobrien	  else
2396179404Sobrien	    {
2397208737Sjmallett	      /* Read-after-write dependencies on the control registers
2398208737Sjmallett		 require a two-instruction gap.  */
2399208737Sjmallett	      if ((pinfo1 & INSN_WRITE_COND_CODE)
2400208737Sjmallett		  && (pinfo2 & INSN_READ_COND_CODE))
2401208737Sjmallett		return 2;
2402208737Sjmallett
2403208737Sjmallett	      /* We don't know exactly what INSN1 does.  If INSN2 is
2404208737Sjmallett		 also a coprocessor instruction, assume there must be
2405208737Sjmallett		 a one instruction gap.  */
2406208737Sjmallett	      if (pinfo2 & INSN_COP)
2407208737Sjmallett		return 1;
2408179404Sobrien	    }
2409179404Sobrien	}
2410179404Sobrien
2411208737Sjmallett      /* Check for read-after-write dependencies on the coprocessor
2412208737Sjmallett	 control registers in cases where INSN1 does not need a general
2413208737Sjmallett	 coprocessor delay.  This means that INSN1 is a floating point
2414208737Sjmallett	 comparison instruction.  */
2415208737Sjmallett      /* Itbl support may require additional care here.  */
2416208737Sjmallett      else if (!cop_interlocks
2417208737Sjmallett	       && (pinfo1 & INSN_WRITE_COND_CODE)
2418208737Sjmallett	       && (pinfo2 & INSN_READ_COND_CODE))
2419208737Sjmallett	return 1;
2420208737Sjmallett    }
2421179404Sobrien
2422208737Sjmallett#undef INSN2_USES_REG
2423179404Sobrien
2424208737Sjmallett  return 0;
2425208737Sjmallett}
2426179404Sobrien
2427208737Sjmallett/* Return the number of nops that would be needed to work around the
2428208737Sjmallett   VR4130 mflo/mfhi errata if instruction INSN immediately followed
2429208737Sjmallett   the MAX_VR4130_NOPS instructions described by HISTORY.  */
2430179404Sobrien
2431208737Sjmallettstatic int
2432208737Sjmallettnops_for_vr4130 (const struct mips_cl_insn *history,
2433208737Sjmallett		 const struct mips_cl_insn *insn)
2434208737Sjmallett{
2435208737Sjmallett  int i, j, reg;
2436179404Sobrien
2437208737Sjmallett  /* Check if the instruction writes to HI or LO.  MTHI and MTLO
2438208737Sjmallett     are not affected by the errata.  */
2439208737Sjmallett  if (insn != 0
2440208737Sjmallett      && ((insn->insn_mo->pinfo & (INSN_WRITE_HI | INSN_WRITE_LO)) == 0
2441208737Sjmallett	  || strcmp (insn->insn_mo->name, "mtlo") == 0
2442208737Sjmallett	  || strcmp (insn->insn_mo->name, "mthi") == 0))
2443208737Sjmallett    return 0;
2444179404Sobrien
2445208737Sjmallett  /* Search for the first MFLO or MFHI.  */
2446208737Sjmallett  for (i = 0; i < MAX_VR4130_NOPS; i++)
2447208737Sjmallett    if (!history[i].noreorder_p && MF_HILO_INSN (history[i].insn_mo->pinfo))
2448208737Sjmallett      {
2449208737Sjmallett	/* Extract the destination register.  */
2450208737Sjmallett	if (mips_opts.mips16)
2451208737Sjmallett	  reg = mips16_to_32_reg_map[MIPS16_EXTRACT_OPERAND (RX, history[i])];
2452208737Sjmallett	else
2453208737Sjmallett	  reg = EXTRACT_OPERAND (RD, history[i]);
2454179404Sobrien
2455208737Sjmallett	/* No nops are needed if INSN reads that register.  */
2456208737Sjmallett	if (insn != NULL && insn_uses_reg (insn, reg, MIPS_GR_REG))
2457208737Sjmallett	  return 0;
2458179404Sobrien
2459208737Sjmallett	/* ...or if any of the intervening instructions do.  */
2460208737Sjmallett	for (j = 0; j < i; j++)
2461208737Sjmallett	  if (insn_uses_reg (&history[j], reg, MIPS_GR_REG))
2462208737Sjmallett	    return 0;
2463179404Sobrien
2464208737Sjmallett	return MAX_VR4130_NOPS - i;
2465208737Sjmallett      }
2466208737Sjmallett  return 0;
2467208737Sjmallett}
2468179404Sobrien
2469208737Sjmallett/* Return the number of nops that would be needed if instruction INSN
2470208737Sjmallett   immediately followed the MAX_NOPS instructions given by HISTORY,
2471208737Sjmallett   where HISTORY[0] is the most recent instruction.  If INSN is null,
2472208737Sjmallett   return the worse-case number of nops for any instruction.  */
2473179404Sobrien
2474208737Sjmallettstatic int
2475208737Sjmallettnops_for_insn (const struct mips_cl_insn *history,
2476208737Sjmallett	       const struct mips_cl_insn *insn)
2477208737Sjmallett{
2478208737Sjmallett  int i, nops, tmp_nops;
2479179404Sobrien
2480208737Sjmallett  nops = 0;
2481208737Sjmallett  for (i = 0; i < MAX_DELAY_NOPS; i++)
2482208737Sjmallett    if (!history[i].noreorder_p)
2483208737Sjmallett      {
2484208737Sjmallett	tmp_nops = insns_between (history + i, insn) - i;
2485208737Sjmallett	if (tmp_nops > nops)
2486208737Sjmallett	  nops = tmp_nops;
2487208737Sjmallett      }
2488179404Sobrien
2489208737Sjmallett  if (mips_fix_vr4130)
2490208737Sjmallett    {
2491208737Sjmallett      tmp_nops = nops_for_vr4130 (history, insn);
2492208737Sjmallett      if (tmp_nops > nops)
2493208737Sjmallett	nops = tmp_nops;
2494208737Sjmallett    }
2495179404Sobrien
2496208737Sjmallett  return nops;
2497208737Sjmallett}
2498179404Sobrien
2499208737Sjmallett/* The variable arguments provide NUM_INSNS extra instructions that
2500208737Sjmallett   might be added to HISTORY.  Return the largest number of nops that
2501208737Sjmallett   would be needed after the extended sequence.  */
2502208737Sjmallett
2503208737Sjmallettstatic int
2504208737Sjmallettnops_for_sequence (int num_insns, const struct mips_cl_insn *history, ...)
2505208737Sjmallett{
2506208737Sjmallett  va_list args;
2507208737Sjmallett  struct mips_cl_insn buffer[MAX_NOPS];
2508208737Sjmallett  struct mips_cl_insn *cursor;
2509208737Sjmallett  int nops;
2510208737Sjmallett
2511208737Sjmallett  va_start (args, history);
2512208737Sjmallett  cursor = buffer + num_insns;
2513208737Sjmallett  memcpy (cursor, history, (MAX_NOPS - num_insns) * sizeof (*cursor));
2514208737Sjmallett  while (cursor > buffer)
2515208737Sjmallett    *--cursor = *va_arg (args, const struct mips_cl_insn *);
2516208737Sjmallett
2517208737Sjmallett  nops = nops_for_insn (buffer, NULL);
2518208737Sjmallett  va_end (args);
2519208737Sjmallett  return nops;
2520208737Sjmallett}
2521208737Sjmallett
2522208737Sjmallett/* Like nops_for_insn, but if INSN is a branch, take into account the
2523208737Sjmallett   worst-case delay for the branch target.  */
2524208737Sjmallett
2525208737Sjmallettstatic int
2526208737Sjmallettnops_for_insn_or_target (const struct mips_cl_insn *history,
2527208737Sjmallett			 const struct mips_cl_insn *insn)
2528208737Sjmallett{
2529208737Sjmallett  int nops, tmp_nops;
2530208737Sjmallett
2531208737Sjmallett  nops = nops_for_insn (history, insn);
2532208737Sjmallett  if (insn->insn_mo->pinfo & (INSN_UNCOND_BRANCH_DELAY
2533208737Sjmallett			      | INSN_COND_BRANCH_DELAY
2534208737Sjmallett			      | INSN_COND_BRANCH_LIKELY))
2535208737Sjmallett    {
2536208737Sjmallett      tmp_nops = nops_for_sequence (2, history, insn, NOP_INSN);
2537208737Sjmallett      if (tmp_nops > nops)
2538208737Sjmallett	nops = tmp_nops;
2539208737Sjmallett    }
2540208737Sjmallett  else if (mips_opts.mips16 && (insn->insn_mo->pinfo & MIPS16_INSN_BRANCH))
2541208737Sjmallett    {
2542208737Sjmallett      tmp_nops = nops_for_sequence (1, history, insn);
2543208737Sjmallett      if (tmp_nops > nops)
2544208737Sjmallett	nops = tmp_nops;
2545208737Sjmallett    }
2546208737Sjmallett  return nops;
2547208737Sjmallett}
2548208737Sjmallett
2549208737Sjmallett/* Output an instruction.  IP is the instruction information.
2550208737Sjmallett   ADDRESS_EXPR is an operand of the instruction to be used with
2551208737Sjmallett   RELOC_TYPE.  */
2552208737Sjmallett
2553208737Sjmallettstatic void
2554208737Sjmallettappend_insn (struct mips_cl_insn *ip, expressionS *address_expr,
2555208737Sjmallett	     bfd_reloc_code_real_type *reloc_type)
2556208737Sjmallett{
2557218822Sdim  unsigned long prev_pinfo, pinfo;
2558208737Sjmallett  relax_stateT prev_insn_frag_type = 0;
2559208737Sjmallett  bfd_boolean relaxed_branch = FALSE;
2560218822Sdim  segment_info_type *si = seg_info (now_seg);
2561208737Sjmallett
2562208737Sjmallett  /* Mark instruction labels in mips16 mode.  */
2563208737Sjmallett  mips16_mark_labels ();
2564208737Sjmallett
2565208737Sjmallett  prev_pinfo = history[0].insn_mo->pinfo;
2566208737Sjmallett  pinfo = ip->insn_mo->pinfo;
2567208737Sjmallett
2568208737Sjmallett  if (mips_relax.sequence != 2 && !mips_opts.noreorder)
2569208737Sjmallett    {
2570208737Sjmallett      /* There are a lot of optimizations we could do that we don't.
2571208737Sjmallett	 In particular, we do not, in general, reorder instructions.
2572208737Sjmallett	 If you use gcc with optimization, it will reorder
2573208737Sjmallett	 instructions and generally do much more optimization then we
2574208737Sjmallett	 do here; repeating all that work in the assembler would only
2575208737Sjmallett	 benefit hand written assembly code, and does not seem worth
2576208737Sjmallett	 it.  */
2577208737Sjmallett      int nops = (mips_optimize == 0
2578208737Sjmallett		  ? nops_for_insn (history, NULL)
2579208737Sjmallett		  : nops_for_insn_or_target (history, ip));
2580208737Sjmallett      if (nops > 0)
2581179404Sobrien	{
2582179404Sobrien	  fragS *old_frag;
2583179404Sobrien	  unsigned long old_frag_offset;
2584179404Sobrien	  int i;
2585179404Sobrien
2586179404Sobrien	  old_frag = frag_now;
2587179404Sobrien	  old_frag_offset = frag_now_fix ();
2588179404Sobrien
2589179404Sobrien	  for (i = 0; i < nops; i++)
2590179404Sobrien	    emit_nop ();
2591179404Sobrien
2592179404Sobrien	  if (listing)
2593179404Sobrien	    {
2594179404Sobrien	      listing_prev_line ();
2595179404Sobrien	      /* We may be at the start of a variant frag.  In case we
2596179404Sobrien                 are, make sure there is enough space for the frag
2597179404Sobrien                 after the frags created by listing_prev_line.  The
2598179404Sobrien                 argument to frag_grow here must be at least as large
2599179404Sobrien                 as the argument to all other calls to frag_grow in
2600179404Sobrien                 this file.  We don't have to worry about being in the
2601179404Sobrien                 middle of a variant frag, because the variants insert
2602179404Sobrien                 all needed nop instructions themselves.  */
2603179404Sobrien	      frag_grow (40);
2604179404Sobrien	    }
2605179404Sobrien
2606208737Sjmallett	  mips_move_labels ();
2607179404Sobrien
2608179404Sobrien#ifndef NO_ECOFF_DEBUGGING
2609179404Sobrien	  if (ECOFF_DEBUGGING)
2610179404Sobrien	    ecoff_fix_loc (old_frag, old_frag_offset);
2611179404Sobrien#endif
2612179404Sobrien	}
2613208737Sjmallett    }
2614208737Sjmallett  else if (mips_relax.sequence != 2 && prev_nop_frag != NULL)
2615208737Sjmallett    {
2616208737Sjmallett      /* Work out how many nops in prev_nop_frag are needed by IP.  */
2617208737Sjmallett      int nops = nops_for_insn_or_target (history, ip);
2618208737Sjmallett      assert (nops <= prev_nop_frag_holds);
2619179404Sobrien
2620208737Sjmallett      /* Enforce NOPS as a minimum.  */
2621208737Sjmallett      if (nops > prev_nop_frag_required)
2622208737Sjmallett	prev_nop_frag_required = nops;
2623179404Sobrien
2624208737Sjmallett      if (prev_nop_frag_holds == prev_nop_frag_required)
2625208737Sjmallett	{
2626208737Sjmallett	  /* Settle for the current number of nops.  Update the history
2627208737Sjmallett	     accordingly (for the benefit of any future .set reorder code).  */
2628208737Sjmallett	  prev_nop_frag = NULL;
2629208737Sjmallett	  insert_into_history (prev_nop_frag_since,
2630208737Sjmallett			       prev_nop_frag_holds, NOP_INSN);
2631179404Sobrien	}
2632208737Sjmallett      else
2633208737Sjmallett	{
2634208737Sjmallett	  /* Allow this instruction to replace one of the nops that was
2635208737Sjmallett	     tentatively added to prev_nop_frag.  */
2636208737Sjmallett	  prev_nop_frag->fr_fix -= mips_opts.mips16 ? 2 : 4;
2637208737Sjmallett	  prev_nop_frag_holds--;
2638208737Sjmallett	  prev_nop_frag_since++;
2639208737Sjmallett	}
2640179404Sobrien    }
2641179404Sobrien
2642208737Sjmallett#ifdef OBJ_ELF
2643208737Sjmallett  /* The value passed to dwarf2_emit_insn is the distance between
2644208737Sjmallett     the beginning of the current instruction and the address that
2645208737Sjmallett     should be recorded in the debug tables.  For MIPS16 debug info
2646208737Sjmallett     we want to use ISA-encoded addresses, so we pass -1 for an
2647208737Sjmallett     address higher by one than the current.  */
2648208737Sjmallett  dwarf2_emit_insn (mips_opts.mips16 ? -1 : 0);
2649208737Sjmallett#endif
2650208737Sjmallett
2651179404Sobrien  /* Record the frag type before frag_var.  */
2652208737Sjmallett  if (history[0].frag)
2653208737Sjmallett    prev_insn_frag_type = history[0].frag->fr_type;
2654179404Sobrien
2655179404Sobrien  if (address_expr
2656179404Sobrien      && *reloc_type == BFD_RELOC_16_PCREL_S2
2657179404Sobrien      && (pinfo & INSN_UNCOND_BRANCH_DELAY || pinfo & INSN_COND_BRANCH_DELAY
2658179404Sobrien	  || pinfo & INSN_COND_BRANCH_LIKELY)
2659179404Sobrien      && mips_relax_branch
2660179404Sobrien      /* Don't try branch relaxation within .set nomacro, or within
2661179404Sobrien	 .set noat if we use $at for PIC computations.  If it turns
2662179404Sobrien	 out that the branch was out-of-range, we'll get an error.  */
2663179404Sobrien      && !mips_opts.warn_about_macros
2664179404Sobrien      && !(mips_opts.noat && mips_pic != NO_PIC)
2665179404Sobrien      && !mips_opts.mips16)
2666179404Sobrien    {
2667179404Sobrien      relaxed_branch = TRUE;
2668208737Sjmallett      add_relaxed_insn (ip, (relaxed_branch_length
2669208737Sjmallett			     (NULL, NULL,
2670208737Sjmallett			      (pinfo & INSN_UNCOND_BRANCH_DELAY) ? -1
2671208737Sjmallett			      : (pinfo & INSN_COND_BRANCH_LIKELY) ? 1
2672208737Sjmallett			      : 0)), 4,
2673208737Sjmallett			RELAX_BRANCH_ENCODE
2674208737Sjmallett			(pinfo & INSN_UNCOND_BRANCH_DELAY,
2675208737Sjmallett			 pinfo & INSN_COND_BRANCH_LIKELY,
2676208737Sjmallett			 pinfo & INSN_WRITE_GPR_31,
2677208737Sjmallett			 0),
2678208737Sjmallett			address_expr->X_add_symbol,
2679208737Sjmallett			address_expr->X_add_number);
2680179404Sobrien      *reloc_type = BFD_RELOC_UNUSED;
2681179404Sobrien    }
2682179404Sobrien  else if (*reloc_type > BFD_RELOC_UNUSED)
2683179404Sobrien    {
2684179404Sobrien      /* We need to set up a variant frag.  */
2685179404Sobrien      assert (mips_opts.mips16 && address_expr != NULL);
2686208737Sjmallett      add_relaxed_insn (ip, 4, 0,
2687208737Sjmallett			RELAX_MIPS16_ENCODE
2688208737Sjmallett			(*reloc_type - BFD_RELOC_UNUSED,
2689208737Sjmallett			 mips16_small, mips16_ext,
2690208737Sjmallett			 prev_pinfo & INSN_UNCOND_BRANCH_DELAY,
2691208737Sjmallett			 history[0].mips16_absolute_jump_p),
2692208737Sjmallett			make_expr_symbol (address_expr), 0);
2693179404Sobrien    }
2694179404Sobrien  else if (mips_opts.mips16
2695179404Sobrien	   && ! ip->use_extend
2696179404Sobrien	   && *reloc_type != BFD_RELOC_MIPS16_JMP)
2697179404Sobrien    {
2698208737Sjmallett      if ((pinfo & INSN_UNCOND_BRANCH_DELAY) == 0)
2699208737Sjmallett	/* Make sure there is enough room to swap this instruction with
2700208737Sjmallett	   a following jump instruction.  */
2701208737Sjmallett	frag_grow (6);
2702208737Sjmallett      add_fixed_insn (ip);
2703179404Sobrien    }
2704179404Sobrien  else
2705179404Sobrien    {
2706179404Sobrien      if (mips_opts.mips16
2707179404Sobrien	  && mips_opts.noreorder
2708179404Sobrien	  && (prev_pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
2709179404Sobrien	as_warn (_("extended instruction in delay slot"));
2710179404Sobrien
2711179404Sobrien      if (mips_relax.sequence)
2712179404Sobrien	{
2713179404Sobrien	  /* If we've reached the end of this frag, turn it into a variant
2714179404Sobrien	     frag and record the information for the instructions we've
2715179404Sobrien	     written so far.  */
2716179404Sobrien	  if (frag_room () < 4)
2717179404Sobrien	    relax_close_frag ();
2718179404Sobrien	  mips_relax.sizes[mips_relax.sequence - 1] += 4;
2719179404Sobrien	}
2720179404Sobrien
2721179404Sobrien      if (mips_relax.sequence != 2)
2722179404Sobrien	mips_macro_warning.sizes[0] += 4;
2723179404Sobrien      if (mips_relax.sequence != 1)
2724179404Sobrien	mips_macro_warning.sizes[1] += 4;
2725179404Sobrien
2726208737Sjmallett      if (mips_opts.mips16)
2727208737Sjmallett	{
2728208737Sjmallett	  ip->fixed_p = 1;
2729208737Sjmallett	  ip->mips16_absolute_jump_p = (*reloc_type == BFD_RELOC_MIPS16_JMP);
2730208737Sjmallett	}
2731208737Sjmallett      add_fixed_insn (ip);
2732179404Sobrien    }
2733179404Sobrien
2734208737Sjmallett  if (address_expr != NULL && *reloc_type <= BFD_RELOC_UNUSED)
2735179404Sobrien    {
2736179404Sobrien      if (address_expr->X_op == O_constant)
2737179404Sobrien	{
2738208737Sjmallett	  unsigned int tmp;
2739179404Sobrien
2740179404Sobrien	  switch (*reloc_type)
2741179404Sobrien	    {
2742179404Sobrien	    case BFD_RELOC_32:
2743179404Sobrien	      ip->insn_opcode |= address_expr->X_add_number;
2744179404Sobrien	      break;
2745179404Sobrien
2746179404Sobrien	    case BFD_RELOC_MIPS_HIGHEST:
2747208737Sjmallett	      tmp = (address_expr->X_add_number + 0x800080008000ull) >> 48;
2748208737Sjmallett	      ip->insn_opcode |= tmp & 0xffff;
2749179404Sobrien	      break;
2750179404Sobrien
2751179404Sobrien	    case BFD_RELOC_MIPS_HIGHER:
2752208737Sjmallett	      tmp = (address_expr->X_add_number + 0x80008000ull) >> 32;
2753208737Sjmallett	      ip->insn_opcode |= tmp & 0xffff;
2754179404Sobrien	      break;
2755179404Sobrien
2756179404Sobrien	    case BFD_RELOC_HI16_S:
2757208737Sjmallett	      tmp = (address_expr->X_add_number + 0x8000) >> 16;
2758208737Sjmallett	      ip->insn_opcode |= tmp & 0xffff;
2759179404Sobrien	      break;
2760179404Sobrien
2761179404Sobrien	    case BFD_RELOC_HI16:
2762179404Sobrien	      ip->insn_opcode |= (address_expr->X_add_number >> 16) & 0xffff;
2763179404Sobrien	      break;
2764179404Sobrien
2765208737Sjmallett	    case BFD_RELOC_UNUSED:
2766179404Sobrien	    case BFD_RELOC_LO16:
2767179404Sobrien	    case BFD_RELOC_MIPS_GOT_DISP:
2768179404Sobrien	      ip->insn_opcode |= address_expr->X_add_number & 0xffff;
2769179404Sobrien	      break;
2770179404Sobrien
2771179404Sobrien	    case BFD_RELOC_MIPS_JMP:
2772179404Sobrien	      if ((address_expr->X_add_number & 3) != 0)
2773179404Sobrien		as_bad (_("jump to misaligned address (0x%lx)"),
2774179404Sobrien			(unsigned long) address_expr->X_add_number);
2775179404Sobrien	      ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0x3ffffff;
2776179404Sobrien	      break;
2777179404Sobrien
2778179404Sobrien	    case BFD_RELOC_MIPS16_JMP:
2779179404Sobrien	      if ((address_expr->X_add_number & 3) != 0)
2780179404Sobrien		as_bad (_("jump to misaligned address (0x%lx)"),
2781179404Sobrien			(unsigned long) address_expr->X_add_number);
2782179404Sobrien	      ip->insn_opcode |=
2783179404Sobrien		(((address_expr->X_add_number & 0x7c0000) << 3)
2784179404Sobrien		 | ((address_expr->X_add_number & 0xf800000) >> 7)
2785179404Sobrien		 | ((address_expr->X_add_number & 0x3fffc) >> 2));
2786179404Sobrien	      break;
2787179404Sobrien
2788179404Sobrien	    case BFD_RELOC_16_PCREL_S2:
2789208737Sjmallett	      if ((address_expr->X_add_number & 3) != 0)
2790208737Sjmallett		as_bad (_("branch to misaligned address (0x%lx)"),
2791208737Sjmallett			(unsigned long) address_expr->X_add_number);
2792208737Sjmallett	      if (mips_relax_branch)
2793208737Sjmallett		goto need_reloc;
2794208737Sjmallett	      if ((address_expr->X_add_number + 0x20000) & ~0x3ffff)
2795208737Sjmallett		as_bad (_("branch address range overflow (0x%lx)"),
2796208737Sjmallett			(unsigned long) address_expr->X_add_number);
2797208737Sjmallett	      ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0xffff;
2798208737Sjmallett	      break;
2799179404Sobrien
2800179404Sobrien	    default:
2801179404Sobrien	      internalError ();
2802179404Sobrien	    }
2803179404Sobrien	}
2804208737Sjmallett      else if (*reloc_type < BFD_RELOC_UNUSED)
2805179404Sobrien	need_reloc:
2806179404Sobrien	{
2807179404Sobrien	  reloc_howto_type *howto;
2808179404Sobrien	  int i;
2809179404Sobrien
2810179404Sobrien	  /* In a compound relocation, it is the final (outermost)
2811179404Sobrien	     operator that determines the relocated field.  */
2812179404Sobrien	  for (i = 1; i < 3; i++)
2813179404Sobrien	    if (reloc_type[i] == BFD_RELOC_UNUSED)
2814179404Sobrien	      break;
2815179404Sobrien
2816179404Sobrien	  howto = bfd_reloc_type_lookup (stdoutput, reloc_type[i - 1]);
2817208737Sjmallett	  ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
2818208737Sjmallett				     bfd_get_reloc_size (howto),
2819208737Sjmallett				     address_expr,
2820208737Sjmallett				     reloc_type[0] == BFD_RELOC_16_PCREL_S2,
2821208737Sjmallett				     reloc_type[0]);
2822179404Sobrien
2823218822Sdim	  /* Tag symbols that have a R_MIPS16_26 relocation against them.  */
2824218822Sdim	  if (reloc_type[0] == BFD_RELOC_MIPS16_JMP
2825218822Sdim	      && ip->fixp[0]->fx_addsy)
2826218822Sdim	    *symbol_get_tc (ip->fixp[0]->fx_addsy) = 1;
2827218822Sdim
2828179404Sobrien	  /* These relocations can have an addend that won't fit in
2829179404Sobrien	     4 octets for 64bit assembly.  */
2830179404Sobrien	  if (HAVE_64BIT_GPRS
2831179404Sobrien	      && ! howto->partial_inplace
2832179404Sobrien	      && (reloc_type[0] == BFD_RELOC_16
2833179404Sobrien		  || reloc_type[0] == BFD_RELOC_32
2834179404Sobrien		  || reloc_type[0] == BFD_RELOC_MIPS_JMP
2835179404Sobrien		  || reloc_type[0] == BFD_RELOC_HI16_S
2836179404Sobrien		  || reloc_type[0] == BFD_RELOC_LO16
2837179404Sobrien		  || reloc_type[0] == BFD_RELOC_GPREL16
2838179404Sobrien		  || reloc_type[0] == BFD_RELOC_MIPS_LITERAL
2839179404Sobrien		  || reloc_type[0] == BFD_RELOC_GPREL32
2840179404Sobrien		  || reloc_type[0] == BFD_RELOC_64
2841179404Sobrien		  || reloc_type[0] == BFD_RELOC_CTOR
2842179404Sobrien		  || reloc_type[0] == BFD_RELOC_MIPS_SUB
2843179404Sobrien		  || reloc_type[0] == BFD_RELOC_MIPS_HIGHEST
2844179404Sobrien		  || reloc_type[0] == BFD_RELOC_MIPS_HIGHER
2845179404Sobrien		  || reloc_type[0] == BFD_RELOC_MIPS_SCN_DISP
2846179404Sobrien		  || reloc_type[0] == BFD_RELOC_MIPS_REL16
2847218822Sdim		  || reloc_type[0] == BFD_RELOC_MIPS_RELGOT
2848218822Sdim		  || reloc_type[0] == BFD_RELOC_MIPS16_GPREL
2849218822Sdim		  || reloc_type[0] == BFD_RELOC_MIPS16_HI16_S
2850218822Sdim		  || reloc_type[0] == BFD_RELOC_MIPS16_LO16))
2851208737Sjmallett	    ip->fixp[0]->fx_no_overflow = 1;
2852179404Sobrien
2853179404Sobrien	  if (mips_relax.sequence)
2854179404Sobrien	    {
2855179404Sobrien	      if (mips_relax.first_fixup == 0)
2856208737Sjmallett		mips_relax.first_fixup = ip->fixp[0];
2857179404Sobrien	    }
2858179404Sobrien	  else if (reloc_needs_lo_p (*reloc_type))
2859179404Sobrien	    {
2860179404Sobrien	      struct mips_hi_fixup *hi_fixup;
2861179404Sobrien
2862179404Sobrien	      /* Reuse the last entry if it already has a matching %lo.  */
2863179404Sobrien	      hi_fixup = mips_hi_fixup_list;
2864179404Sobrien	      if (hi_fixup == 0
2865179404Sobrien		  || !fixup_has_matching_lo_p (hi_fixup->fixp))
2866179404Sobrien		{
2867179404Sobrien		  hi_fixup = ((struct mips_hi_fixup *)
2868179404Sobrien			      xmalloc (sizeof (struct mips_hi_fixup)));
2869179404Sobrien		  hi_fixup->next = mips_hi_fixup_list;
2870179404Sobrien		  mips_hi_fixup_list = hi_fixup;
2871179404Sobrien		}
2872208737Sjmallett	      hi_fixup->fixp = ip->fixp[0];
2873179404Sobrien	      hi_fixup->seg = now_seg;
2874179404Sobrien	    }
2875179404Sobrien
2876179404Sobrien	  /* Add fixups for the second and third relocations, if given.
2877179404Sobrien	     Note that the ABI allows the second relocation to be
2878179404Sobrien	     against RSS_UNDEF, RSS_GP, RSS_GP0 or RSS_LOC.  At the
2879179404Sobrien	     moment we only use RSS_UNDEF, but we could add support
2880179404Sobrien	     for the others if it ever becomes necessary.  */
2881179404Sobrien	  for (i = 1; i < 3; i++)
2882179404Sobrien	    if (reloc_type[i] != BFD_RELOC_UNUSED)
2883179404Sobrien	      {
2884208737Sjmallett		ip->fixp[i] = fix_new (ip->frag, ip->where,
2885208737Sjmallett				       ip->fixp[0]->fx_size, NULL, 0,
2886208737Sjmallett				       FALSE, reloc_type[i]);
2887179404Sobrien
2888208737Sjmallett		/* Use fx_tcbit to mark compound relocs.  */
2889208737Sjmallett		ip->fixp[0]->fx_tcbit = 1;
2890208737Sjmallett		ip->fixp[i]->fx_tcbit = 1;
2891179404Sobrien	      }
2892179404Sobrien	}
2893179404Sobrien    }
2894208737Sjmallett  install_insn (ip);
2895179404Sobrien
2896179404Sobrien  /* Update the register mask information.  */
2897179404Sobrien  if (! mips_opts.mips16)
2898179404Sobrien    {
2899179404Sobrien      if (pinfo & INSN_WRITE_GPR_D)
2900208737Sjmallett	mips_gprmask |= 1 << EXTRACT_OPERAND (RD, *ip);
2901179404Sobrien      if ((pinfo & (INSN_WRITE_GPR_T | INSN_READ_GPR_T)) != 0)
2902208737Sjmallett	mips_gprmask |= 1 << EXTRACT_OPERAND (RT, *ip);
2903179404Sobrien      if (pinfo & INSN_READ_GPR_S)
2904208737Sjmallett	mips_gprmask |= 1 << EXTRACT_OPERAND (RS, *ip);
2905179404Sobrien      if (pinfo & INSN_WRITE_GPR_31)
2906179404Sobrien	mips_gprmask |= 1 << RA;
2907179404Sobrien      if (pinfo & INSN_WRITE_FPR_D)
2908208737Sjmallett	mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FD, *ip);
2909179404Sobrien      if ((pinfo & (INSN_WRITE_FPR_S | INSN_READ_FPR_S)) != 0)
2910208737Sjmallett	mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FS, *ip);
2911179404Sobrien      if ((pinfo & (INSN_WRITE_FPR_T | INSN_READ_FPR_T)) != 0)
2912208737Sjmallett	mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FT, *ip);
2913179404Sobrien      if ((pinfo & INSN_READ_FPR_R) != 0)
2914208737Sjmallett	mips_cprmask[1] |= 1 << EXTRACT_OPERAND (FR, *ip);
2915179404Sobrien      if (pinfo & INSN_COP)
2916179404Sobrien	{
2917179404Sobrien	  /* We don't keep enough information to sort these cases out.
2918179404Sobrien	     The itbl support does keep this information however, although
2919179404Sobrien	     we currently don't support itbl fprmats as part of the cop
2920179404Sobrien	     instruction.  May want to add this support in the future.  */
2921179404Sobrien	}
2922179404Sobrien      /* Never set the bit for $0, which is always zero.  */
2923179404Sobrien      mips_gprmask &= ~1 << 0;
2924179404Sobrien    }
2925179404Sobrien  else
2926179404Sobrien    {
2927179404Sobrien      if (pinfo & (MIPS16_INSN_WRITE_X | MIPS16_INSN_READ_X))
2928208737Sjmallett	mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (RX, *ip);
2929179404Sobrien      if (pinfo & (MIPS16_INSN_WRITE_Y | MIPS16_INSN_READ_Y))
2930208737Sjmallett	mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (RY, *ip);
2931179404Sobrien      if (pinfo & MIPS16_INSN_WRITE_Z)
2932208737Sjmallett	mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (RZ, *ip);
2933179404Sobrien      if (pinfo & (MIPS16_INSN_WRITE_T | MIPS16_INSN_READ_T))
2934179404Sobrien	mips_gprmask |= 1 << TREG;
2935179404Sobrien      if (pinfo & (MIPS16_INSN_WRITE_SP | MIPS16_INSN_READ_SP))
2936179404Sobrien	mips_gprmask |= 1 << SP;
2937179404Sobrien      if (pinfo & (MIPS16_INSN_WRITE_31 | MIPS16_INSN_READ_31))
2938179404Sobrien	mips_gprmask |= 1 << RA;
2939179404Sobrien      if (pinfo & MIPS16_INSN_WRITE_GPR_Y)
2940179404Sobrien	mips_gprmask |= 1 << MIPS16OP_EXTRACT_REG32R (ip->insn_opcode);
2941179404Sobrien      if (pinfo & MIPS16_INSN_READ_Z)
2942208737Sjmallett	mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (MOVE32Z, *ip);
2943179404Sobrien      if (pinfo & MIPS16_INSN_READ_GPR_X)
2944208737Sjmallett	mips_gprmask |= 1 << MIPS16_EXTRACT_OPERAND (REGR32, *ip);
2945179404Sobrien    }
2946179404Sobrien
2947179404Sobrien  if (mips_relax.sequence != 2 && !mips_opts.noreorder)
2948179404Sobrien    {
2949179404Sobrien      /* Filling the branch delay slot is more complex.  We try to
2950179404Sobrien	 switch the branch with the previous instruction, which we can
2951179404Sobrien	 do if the previous instruction does not set up a condition
2952179404Sobrien	 that the branch tests and if the branch is not itself the
2953179404Sobrien	 target of any branch.  */
2954179404Sobrien      if ((pinfo & INSN_UNCOND_BRANCH_DELAY)
2955179404Sobrien	  || (pinfo & INSN_COND_BRANCH_DELAY))
2956179404Sobrien	{
2957179404Sobrien	  if (mips_optimize < 2
2958179404Sobrien	      /* If we have seen .set volatile or .set nomove, don't
2959179404Sobrien		 optimize.  */
2960179404Sobrien	      || mips_opts.nomove != 0
2961208737Sjmallett	      /* We can't swap if the previous instruction's position
2962208737Sjmallett		 is fixed.  */
2963208737Sjmallett	      || history[0].fixed_p
2964179404Sobrien	      /* If the previous previous insn was in a .set
2965179404Sobrien		 noreorder, we can't swap.  Actually, the MIPS
2966179404Sobrien		 assembler will swap in this situation.  However, gcc
2967179404Sobrien		 configured -with-gnu-as will generate code like
2968179404Sobrien		   .set noreorder
2969179404Sobrien		   lw	$4,XXX
2970179404Sobrien		   .set	reorder
2971179404Sobrien		   INSN
2972179404Sobrien		   bne	$4,$0,foo
2973179404Sobrien		 in which we can not swap the bne and INSN.  If gcc is
2974179404Sobrien		 not configured -with-gnu-as, it does not output the
2975208737Sjmallett		 .set pseudo-ops.  */
2976208737Sjmallett	      || history[1].noreorder_p
2977179404Sobrien	      /* If the branch is itself the target of a branch, we
2978179404Sobrien		 can not swap.  We cheat on this; all we check for is
2979179404Sobrien		 whether there is a label on this instruction.  If
2980179404Sobrien		 there are any branches to anything other than a
2981179404Sobrien		 label, users must use .set noreorder.  */
2982218822Sdim	      || si->label_list != NULL
2983179404Sobrien	      /* If the previous instruction is in a variant frag
2984179404Sobrien		 other than this branch's one, we cannot do the swap.
2985179404Sobrien		 This does not apply to the mips16, which uses variant
2986179404Sobrien		 frags for different purposes.  */
2987179404Sobrien	      || (! mips_opts.mips16
2988179404Sobrien		  && prev_insn_frag_type == rs_machine_dependent)
2989208737Sjmallett	      /* Check for conflicts between the branch and the instructions
2990208737Sjmallett		 before the candidate delay slot.  */
2991208737Sjmallett	      || nops_for_insn (history + 1, ip) > 0
2992208737Sjmallett	      /* Check for conflicts between the swapped sequence and the
2993208737Sjmallett		 target of the branch.  */
2994208737Sjmallett	      || nops_for_sequence (2, history + 1, ip, history) > 0
2995179404Sobrien	      /* We do not swap with a trap instruction, since it
2996179404Sobrien		 complicates trap handlers to have the trap
2997179404Sobrien		 instruction be in a delay slot.  */
2998179404Sobrien	      || (prev_pinfo & INSN_TRAP)
2999179404Sobrien	      /* If the branch reads a register that the previous
3000179404Sobrien		 instruction sets, we can not swap.  */
3001179404Sobrien	      || (! mips_opts.mips16
3002179404Sobrien		  && (prev_pinfo & INSN_WRITE_GPR_T)
3003208737Sjmallett		  && insn_uses_reg (ip, EXTRACT_OPERAND (RT, history[0]),
3004179404Sobrien				    MIPS_GR_REG))
3005179404Sobrien	      || (! mips_opts.mips16
3006179404Sobrien		  && (prev_pinfo & INSN_WRITE_GPR_D)
3007208737Sjmallett		  && insn_uses_reg (ip, EXTRACT_OPERAND (RD, history[0]),
3008179404Sobrien				    MIPS_GR_REG))
3009179404Sobrien	      || (mips_opts.mips16
3010179404Sobrien		  && (((prev_pinfo & MIPS16_INSN_WRITE_X)
3011208737Sjmallett		       && (insn_uses_reg
3012208737Sjmallett			   (ip, MIPS16_EXTRACT_OPERAND (RX, history[0]),
3013208737Sjmallett			    MIPS16_REG)))
3014179404Sobrien		      || ((prev_pinfo & MIPS16_INSN_WRITE_Y)
3015208737Sjmallett			  && (insn_uses_reg
3016208737Sjmallett			      (ip, MIPS16_EXTRACT_OPERAND (RY, history[0]),
3017208737Sjmallett			       MIPS16_REG)))
3018179404Sobrien		      || ((prev_pinfo & MIPS16_INSN_WRITE_Z)
3019208737Sjmallett			  && (insn_uses_reg
3020208737Sjmallett			      (ip, MIPS16_EXTRACT_OPERAND (RZ, history[0]),
3021208737Sjmallett			       MIPS16_REG)))
3022179404Sobrien		      || ((prev_pinfo & MIPS16_INSN_WRITE_T)
3023179404Sobrien			  && insn_uses_reg (ip, TREG, MIPS_GR_REG))
3024179404Sobrien		      || ((prev_pinfo & MIPS16_INSN_WRITE_31)
3025179404Sobrien			  && insn_uses_reg (ip, RA, MIPS_GR_REG))
3026179404Sobrien		      || ((prev_pinfo & MIPS16_INSN_WRITE_GPR_Y)
3027179404Sobrien			  && insn_uses_reg (ip,
3028208737Sjmallett					    MIPS16OP_EXTRACT_REG32R
3029208737Sjmallett					      (history[0].insn_opcode),
3030179404Sobrien					    MIPS_GR_REG))))
3031179404Sobrien	      /* If the branch writes a register that the previous
3032179404Sobrien		 instruction sets, we can not swap (we know that
3033179404Sobrien		 branches write only to RD or to $31).  */
3034179404Sobrien	      || (! mips_opts.mips16
3035179404Sobrien		  && (prev_pinfo & INSN_WRITE_GPR_T)
3036179404Sobrien		  && (((pinfo & INSN_WRITE_GPR_D)
3037208737Sjmallett		       && (EXTRACT_OPERAND (RT, history[0])
3038208737Sjmallett			   == EXTRACT_OPERAND (RD, *ip)))
3039179404Sobrien		      || ((pinfo & INSN_WRITE_GPR_31)
3040208737Sjmallett			  && EXTRACT_OPERAND (RT, history[0]) == RA)))
3041179404Sobrien	      || (! mips_opts.mips16
3042179404Sobrien		  && (prev_pinfo & INSN_WRITE_GPR_D)
3043179404Sobrien		  && (((pinfo & INSN_WRITE_GPR_D)
3044208737Sjmallett		       && (EXTRACT_OPERAND (RD, history[0])
3045208737Sjmallett			   == EXTRACT_OPERAND (RD, *ip)))
3046179404Sobrien		      || ((pinfo & INSN_WRITE_GPR_31)
3047208737Sjmallett			  && EXTRACT_OPERAND (RD, history[0]) == RA)))
3048179404Sobrien	      || (mips_opts.mips16
3049179404Sobrien		  && (pinfo & MIPS16_INSN_WRITE_31)
3050179404Sobrien		  && ((prev_pinfo & MIPS16_INSN_WRITE_31)
3051179404Sobrien		      || ((prev_pinfo & MIPS16_INSN_WRITE_GPR_Y)
3052208737Sjmallett			  && (MIPS16OP_EXTRACT_REG32R (history[0].insn_opcode)
3053179404Sobrien			      == RA))))
3054179404Sobrien	      /* If the branch writes a register that the previous
3055179404Sobrien		 instruction reads, we can not swap (we know that
3056179404Sobrien		 branches only write to RD or to $31).  */
3057179404Sobrien	      || (! mips_opts.mips16
3058179404Sobrien		  && (pinfo & INSN_WRITE_GPR_D)
3059208737Sjmallett		  && insn_uses_reg (&history[0],
3060208737Sjmallett				    EXTRACT_OPERAND (RD, *ip),
3061179404Sobrien				    MIPS_GR_REG))
3062179404Sobrien	      || (! mips_opts.mips16
3063179404Sobrien		  && (pinfo & INSN_WRITE_GPR_31)
3064208737Sjmallett		  && insn_uses_reg (&history[0], RA, MIPS_GR_REG))
3065179404Sobrien	      || (mips_opts.mips16
3066179404Sobrien		  && (pinfo & MIPS16_INSN_WRITE_31)
3067208737Sjmallett		  && insn_uses_reg (&history[0], RA, MIPS_GR_REG))
3068179404Sobrien	      /* If one instruction sets a condition code and the
3069179404Sobrien                 other one uses a condition code, we can not swap.  */
3070179404Sobrien	      || ((pinfo & INSN_READ_COND_CODE)
3071179404Sobrien		  && (prev_pinfo & INSN_WRITE_COND_CODE))
3072179404Sobrien	      || ((pinfo & INSN_WRITE_COND_CODE)
3073179404Sobrien		  && (prev_pinfo & INSN_READ_COND_CODE))
3074179404Sobrien	      /* If the previous instruction uses the PC, we can not
3075179404Sobrien                 swap.  */
3076179404Sobrien	      || (mips_opts.mips16
3077179404Sobrien		  && (prev_pinfo & MIPS16_INSN_READ_PC))
3078179404Sobrien	      /* If the previous instruction had a fixup in mips16
3079179404Sobrien                 mode, we can not swap.  This normally means that the
3080179404Sobrien                 previous instruction was a 4 byte branch anyhow.  */
3081208737Sjmallett	      || (mips_opts.mips16 && history[0].fixp[0])
3082179404Sobrien	      /* If the previous instruction is a sync, sync.l, or
3083179404Sobrien		 sync.p, we can not swap.  */
3084179404Sobrien	      || (prev_pinfo & INSN_SYNC))
3085179404Sobrien	    {
3086208737Sjmallett	      if (mips_opts.mips16
3087208737Sjmallett		  && (pinfo & INSN_UNCOND_BRANCH_DELAY)
3088208737Sjmallett		  && (pinfo & (MIPS16_INSN_READ_X | MIPS16_INSN_READ_31))
3089218822Sdim		  && ISA_SUPPORTS_MIPS16E)
3090208737Sjmallett		{
3091208737Sjmallett		  /* Convert MIPS16 jr/jalr into a "compact" jump.  */
3092208737Sjmallett		  ip->insn_opcode |= 0x0080;
3093208737Sjmallett		  install_insn (ip);
3094208737Sjmallett		  insert_into_history (0, 1, ip);
3095208737Sjmallett		}
3096208737Sjmallett	      else
3097208737Sjmallett		{
3098208737Sjmallett		  /* We could do even better for unconditional branches to
3099208737Sjmallett		     portions of this object file; we could pick up the
3100208737Sjmallett		     instruction at the destination, put it in the delay
3101208737Sjmallett		     slot, and bump the destination address.  */
3102208737Sjmallett		  insert_into_history (0, 1, ip);
3103208737Sjmallett		  emit_nop ();
3104208737Sjmallett		}
3105208737Sjmallett
3106208737Sjmallett	      if (mips_relax.sequence)
3107208737Sjmallett		mips_relax.sizes[mips_relax.sequence - 1] += 4;
3108179404Sobrien	    }
3109179404Sobrien	  else
3110179404Sobrien	    {
3111179404Sobrien	      /* It looks like we can actually do the swap.  */
3112208737Sjmallett	      struct mips_cl_insn delay = history[0];
3113208737Sjmallett	      if (mips_opts.mips16)
3114179404Sobrien		{
3115208737Sjmallett		  know (delay.frag == ip->frag);
3116208737Sjmallett                  move_insn (ip, delay.frag, delay.where);
3117208737Sjmallett		  move_insn (&delay, ip->frag, ip->where + insn_length (ip));
3118179404Sobrien		}
3119208737Sjmallett	      else if (relaxed_branch)
3120208737Sjmallett		{
3121208737Sjmallett		  /* Add the delay slot instruction to the end of the
3122208737Sjmallett		     current frag and shrink the fixed part of the
3123208737Sjmallett		     original frag.  If the branch occupies the tail of
3124208737Sjmallett		     the latter, move it backwards to cover the gap.  */
3125208737Sjmallett		  delay.frag->fr_fix -= 4;
3126208737Sjmallett		  if (delay.frag == ip->frag)
3127208737Sjmallett		    move_insn (ip, ip->frag, ip->where - 4);
3128208737Sjmallett		  add_fixed_insn (&delay);
3129208737Sjmallett		}
3130179404Sobrien	      else
3131179404Sobrien		{
3132208737Sjmallett		  move_insn (&delay, ip->frag, ip->where);
3133208737Sjmallett		  move_insn (ip, history[0].frag, history[0].where);
3134179404Sobrien		}
3135208737Sjmallett	      history[0] = *ip;
3136208737Sjmallett	      delay.fixed_p = 1;
3137208737Sjmallett	      insert_into_history (0, 1, &delay);
3138179404Sobrien	    }
3139179404Sobrien
3140179404Sobrien	  /* If that was an unconditional branch, forget the previous
3141179404Sobrien	     insn information.  */
3142179404Sobrien	  if (pinfo & INSN_UNCOND_BRANCH_DELAY)
3143208737Sjmallett	    mips_no_prev_insn ();
3144179404Sobrien	}
3145179404Sobrien      else if (pinfo & INSN_COND_BRANCH_LIKELY)
3146179404Sobrien	{
3147179404Sobrien	  /* We don't yet optimize a branch likely.  What we should do
3148179404Sobrien	     is look at the target, copy the instruction found there
3149179404Sobrien	     into the delay slot, and increment the branch to jump to
3150179404Sobrien	     the next instruction.  */
3151208737Sjmallett	  insert_into_history (0, 1, ip);
3152179404Sobrien	  emit_nop ();
3153179404Sobrien	}
3154179404Sobrien      else
3155208737Sjmallett	insert_into_history (0, 1, ip);
3156179404Sobrien    }
3157208737Sjmallett  else
3158208737Sjmallett    insert_into_history (0, 1, ip);
3159179404Sobrien
3160179404Sobrien  /* We just output an insn, so the next one doesn't have a label.  */
3161179404Sobrien  mips_clear_insn_labels ();
3162179404Sobrien}
3163179404Sobrien
3164208737Sjmallett/* Forget that there was any previous instruction or label.  */
3165179404Sobrien
3166179404Sobrienstatic void
3167208737Sjmallettmips_no_prev_insn (void)
3168179404Sobrien{
3169208737Sjmallett  prev_nop_frag = NULL;
3170208737Sjmallett  insert_into_history (0, ARRAY_SIZE (history), NOP_INSN);
3171208737Sjmallett  mips_clear_insn_labels ();
3172208737Sjmallett}
3173208737Sjmallett
3174208737Sjmallett/* This function must be called before we emit something other than
3175208737Sjmallett   instructions.  It is like mips_no_prev_insn except that it inserts
3176208737Sjmallett   any NOPS that might be needed by previous instructions.  */
3177208737Sjmallett
3178208737Sjmallettvoid
3179208737Sjmallettmips_emit_delays (void)
3180208737Sjmallett{
3181208737Sjmallett  if (! mips_opts.noreorder)
3182179404Sobrien    {
3183208737Sjmallett      int nops = nops_for_insn (history, NULL);
3184208737Sjmallett      if (nops > 0)
3185208737Sjmallett	{
3186208737Sjmallett	  while (nops-- > 0)
3187208737Sjmallett	    add_fixed_insn (NOP_INSN);
3188208737Sjmallett	  mips_move_labels ();
3189208737Sjmallett	}
3190179404Sobrien    }
3191208737Sjmallett  mips_no_prev_insn ();
3192179404Sobrien}
3193179404Sobrien
3194208737Sjmallett/* Start a (possibly nested) noreorder block.  */
3195179404Sobrien
3196179404Sobrienstatic void
3197208737Sjmallettstart_noreorder (void)
3198179404Sobrien{
3199208737Sjmallett  if (mips_opts.noreorder == 0)
3200179404Sobrien    {
3201208737Sjmallett      unsigned int i;
3202179404Sobrien      int nops;
3203179404Sobrien
3204208737Sjmallett      /* None of the instructions before the .set noreorder can be moved.  */
3205208737Sjmallett      for (i = 0; i < ARRAY_SIZE (history); i++)
3206208737Sjmallett	history[i].fixed_p = 1;
3207179404Sobrien
3208208737Sjmallett      /* Insert any nops that might be needed between the .set noreorder
3209208737Sjmallett	 block and the previous instructions.  We will later remove any
3210208737Sjmallett	 nops that turn out not to be needed.  */
3211208737Sjmallett      nops = nops_for_insn (history, NULL);
3212179404Sobrien      if (nops > 0)
3213179404Sobrien	{
3214208737Sjmallett	  if (mips_optimize != 0)
3215179404Sobrien	    {
3216179404Sobrien	      /* Record the frag which holds the nop instructions, so
3217179404Sobrien                 that we can remove them if we don't need them.  */
3218179404Sobrien	      frag_grow (mips_opts.mips16 ? nops * 2 : nops * 4);
3219179404Sobrien	      prev_nop_frag = frag_now;
3220179404Sobrien	      prev_nop_frag_holds = nops;
3221179404Sobrien	      prev_nop_frag_required = 0;
3222179404Sobrien	      prev_nop_frag_since = 0;
3223179404Sobrien	    }
3224179404Sobrien
3225179404Sobrien	  for (; nops > 0; --nops)
3226208737Sjmallett	    add_fixed_insn (NOP_INSN);
3227179404Sobrien
3228208737Sjmallett	  /* Move on to a new frag, so that it is safe to simply
3229208737Sjmallett	     decrease the size of prev_nop_frag.  */
3230208737Sjmallett	  frag_wane (frag_now);
3231208737Sjmallett	  frag_new (0);
3232208737Sjmallett	  mips_move_labels ();
3233179404Sobrien	}
3234208737Sjmallett      mips16_mark_labels ();
3235208737Sjmallett      mips_clear_insn_labels ();
3236179404Sobrien    }
3237208737Sjmallett  mips_opts.noreorder++;
3238208737Sjmallett  mips_any_noreorder = 1;
3239208737Sjmallett}
3240179404Sobrien
3241208737Sjmallett/* End a nested noreorder block.  */
3242179404Sobrien
3243208737Sjmallettstatic void
3244208737Sjmallettend_noreorder (void)
3245208737Sjmallett{
3246208737Sjmallett  mips_opts.noreorder--;
3247208737Sjmallett  if (mips_opts.noreorder == 0 && prev_nop_frag != NULL)
3248208737Sjmallett    {
3249208737Sjmallett      /* Commit to inserting prev_nop_frag_required nops and go back to
3250208737Sjmallett	 handling nop insertion the .set reorder way.  */
3251208737Sjmallett      prev_nop_frag->fr_fix -= ((prev_nop_frag_holds - prev_nop_frag_required)
3252208737Sjmallett				* (mips_opts.mips16 ? 2 : 4));
3253208737Sjmallett      insert_into_history (prev_nop_frag_since,
3254208737Sjmallett			   prev_nop_frag_required, NOP_INSN);
3255208737Sjmallett      prev_nop_frag = NULL;
3256208737Sjmallett    }
3257179404Sobrien}
3258179404Sobrien
3259179404Sobrien/* Set up global variables for the start of a new macro.  */
3260179404Sobrien
3261179404Sobrienstatic void
3262179404Sobrienmacro_start (void)
3263179404Sobrien{
3264179404Sobrien  memset (&mips_macro_warning.sizes, 0, sizeof (mips_macro_warning.sizes));
3265179404Sobrien  mips_macro_warning.delay_slot_p = (mips_opts.noreorder
3266208737Sjmallett				     && (history[0].insn_mo->pinfo
3267179404Sobrien					 & (INSN_UNCOND_BRANCH_DELAY
3268179404Sobrien					    | INSN_COND_BRANCH_DELAY
3269179404Sobrien					    | INSN_COND_BRANCH_LIKELY)) != 0);
3270179404Sobrien}
3271179404Sobrien
3272179404Sobrien/* Given that a macro is longer than 4 bytes, return the appropriate warning
3273179404Sobrien   for it.  Return null if no warning is needed.  SUBTYPE is a bitmask of
3274179404Sobrien   RELAX_DELAY_SLOT and RELAX_NOMACRO.  */
3275179404Sobrien
3276179404Sobrienstatic const char *
3277179404Sobrienmacro_warning (relax_substateT subtype)
3278179404Sobrien{
3279179404Sobrien  if (subtype & RELAX_DELAY_SLOT)
3280179404Sobrien    return _("Macro instruction expanded into multiple instructions"
3281179404Sobrien	     " in a branch delay slot");
3282179404Sobrien  else if (subtype & RELAX_NOMACRO)
3283179404Sobrien    return _("Macro instruction expanded into multiple instructions");
3284179404Sobrien  else
3285179404Sobrien    return 0;
3286179404Sobrien}
3287179404Sobrien
3288179404Sobrien/* Finish up a macro.  Emit warnings as appropriate.  */
3289179404Sobrien
3290179404Sobrienstatic void
3291179404Sobrienmacro_end (void)
3292179404Sobrien{
3293179404Sobrien  if (mips_macro_warning.sizes[0] > 4 || mips_macro_warning.sizes[1] > 4)
3294179404Sobrien    {
3295179404Sobrien      relax_substateT subtype;
3296179404Sobrien
3297179404Sobrien      /* Set up the relaxation warning flags.  */
3298179404Sobrien      subtype = 0;
3299179404Sobrien      if (mips_macro_warning.sizes[1] > mips_macro_warning.sizes[0])
3300179404Sobrien	subtype |= RELAX_SECOND_LONGER;
3301179404Sobrien      if (mips_opts.warn_about_macros)
3302179404Sobrien	subtype |= RELAX_NOMACRO;
3303179404Sobrien      if (mips_macro_warning.delay_slot_p)
3304179404Sobrien	subtype |= RELAX_DELAY_SLOT;
3305179404Sobrien
3306179404Sobrien      if (mips_macro_warning.sizes[0] > 4 && mips_macro_warning.sizes[1] > 4)
3307179404Sobrien	{
3308179404Sobrien	  /* Either the macro has a single implementation or both
3309179404Sobrien	     implementations are longer than 4 bytes.  Emit the
3310179404Sobrien	     warning now.  */
3311179404Sobrien	  const char *msg = macro_warning (subtype);
3312179404Sobrien	  if (msg != 0)
3313179404Sobrien	    as_warn (msg);
3314179404Sobrien	}
3315179404Sobrien      else
3316179404Sobrien	{
3317179404Sobrien	  /* One implementation might need a warning but the other
3318179404Sobrien	     definitely doesn't.  */
3319179404Sobrien	  mips_macro_warning.first_frag->fr_subtype |= subtype;
3320179404Sobrien	}
3321179404Sobrien    }
3322179404Sobrien}
3323179404Sobrien
3324208737Sjmallett/* Read a macro's relocation codes from *ARGS and store them in *R.
3325208737Sjmallett   The first argument in *ARGS will be either the code for a single
3326208737Sjmallett   relocation or -1 followed by the three codes that make up a
3327208737Sjmallett   composite relocation.  */
3328208737Sjmallett
3329208737Sjmallettstatic void
3330208737Sjmallettmacro_read_relocs (va_list *args, bfd_reloc_code_real_type *r)
3331208737Sjmallett{
3332208737Sjmallett  int i, next;
3333208737Sjmallett
3334208737Sjmallett  next = va_arg (*args, int);
3335208737Sjmallett  if (next >= 0)
3336208737Sjmallett    r[0] = (bfd_reloc_code_real_type) next;
3337208737Sjmallett  else
3338208737Sjmallett    for (i = 0; i < 3; i++)
3339208737Sjmallett      r[i] = (bfd_reloc_code_real_type) va_arg (*args, int);
3340208737Sjmallett}
3341208737Sjmallett
3342179404Sobrien/* Build an instruction created by a macro expansion.  This is passed
3343179404Sobrien   a pointer to the count of instructions created so far, an
3344179404Sobrien   expression, the name of the instruction to build, an operand format
3345179404Sobrien   string, and corresponding arguments.  */
3346179404Sobrien
3347179404Sobrienstatic void
3348179404Sobrienmacro_build (expressionS *ep, const char *name, const char *fmt, ...)
3349179404Sobrien{
3350208737Sjmallett  const struct mips_opcode *mo;
3351179404Sobrien  struct mips_cl_insn insn;
3352179404Sobrien  bfd_reloc_code_real_type r[3];
3353179404Sobrien  va_list args;
3354179404Sobrien
3355179404Sobrien  va_start (args, fmt);
3356179404Sobrien
3357179404Sobrien  if (mips_opts.mips16)
3358179404Sobrien    {
3359179404Sobrien      mips16_macro_build (ep, name, fmt, args);
3360179404Sobrien      va_end (args);
3361179404Sobrien      return;
3362179404Sobrien    }
3363179404Sobrien
3364179404Sobrien  r[0] = BFD_RELOC_UNUSED;
3365179404Sobrien  r[1] = BFD_RELOC_UNUSED;
3366179404Sobrien  r[2] = BFD_RELOC_UNUSED;
3367208737Sjmallett  mo = (struct mips_opcode *) hash_find (op_hash, name);
3368208737Sjmallett  assert (mo);
3369208737Sjmallett  assert (strcmp (name, mo->name) == 0);
3370179404Sobrien
3371218822Sdim  while (1)
3372218822Sdim    {
3373218822Sdim      /* Search until we get a match for NAME.  It is assumed here that
3374218822Sdim	 macros will never generate MDMX, MIPS-3D, or MT instructions.  */
3375218822Sdim      if (strcmp (fmt, mo->args) == 0
3376218822Sdim	  && mo->pinfo != INSN_MACRO
3377218822Sdim	  && OPCODE_IS_MEMBER (mo,
3378208737Sjmallett			       (mips_opts.isa
3379218822Sdim				| (mips_opts.mips16 ? INSN_MIPS16 : 0)
3380218822Sdim				| (mips_opts.ase_dsp ? INSN_DSP : 0)
3381218822Sdim				| ((mips_opts.ase_dsp && ISA_SUPPORTS_DSP64_ASE)
3382218822Sdim				   ? INSN_DSP64 : 0)
3383218822Sdim				| (mips_opts.ase_dspr2 ? INSN_DSPR2 : 0)
3384218822Sdim				| (mips_opts.ase_smartmips ? INSN_SMARTMIPS : 0)),
3385208737Sjmallett			       mips_opts.arch)
3386218822Sdim	  && (mips_opts.arch != CPU_R4650 || (mo->pinfo & FP_D) == 0))
3387218822Sdim	break;
3388218822Sdim
3389208737Sjmallett      ++mo;
3390208737Sjmallett      assert (mo->name);
3391208737Sjmallett      assert (strcmp (name, mo->name) == 0);
3392179404Sobrien    }
3393179404Sobrien
3394208737Sjmallett  create_insn (&insn, mo);
3395179404Sobrien  for (;;)
3396179404Sobrien    {
3397179404Sobrien      switch (*fmt++)
3398179404Sobrien	{
3399179404Sobrien	case '\0':
3400179404Sobrien	  break;
3401179404Sobrien
3402179404Sobrien	case ',':
3403179404Sobrien	case '(':
3404179404Sobrien	case ')':
3405179404Sobrien	  continue;
3406179404Sobrien
3407179404Sobrien	case '+':
3408179404Sobrien	  switch (*fmt++)
3409179404Sobrien	    {
3410179404Sobrien	    case 'A':
3411179404Sobrien	    case 'E':
3412208737Sjmallett	      INSERT_OPERAND (SHAMT, insn, va_arg (args, int));
3413179404Sobrien	      continue;
3414179404Sobrien
3415179404Sobrien	    case 'B':
3416179404Sobrien	    case 'F':
3417179404Sobrien	      /* Note that in the macro case, these arguments are already
3418179404Sobrien		 in MSB form.  (When handling the instruction in the
3419179404Sobrien		 non-macro case, these arguments are sizes from which
3420179404Sobrien		 MSB values must be calculated.)  */
3421208737Sjmallett	      INSERT_OPERAND (INSMSB, insn, va_arg (args, int));
3422179404Sobrien	      continue;
3423179404Sobrien
3424179404Sobrien	    case 'C':
3425179404Sobrien	    case 'G':
3426179404Sobrien	    case 'H':
3427179404Sobrien	      /* Note that in the macro case, these arguments are already
3428179404Sobrien		 in MSBD form.  (When handling the instruction in the
3429179404Sobrien		 non-macro case, these arguments are sizes from which
3430179404Sobrien		 MSBD values must be calculated.)  */
3431208737Sjmallett	      INSERT_OPERAND (EXTMSBD, insn, va_arg (args, int));
3432179404Sobrien	      continue;
3433179404Sobrien
3434179404Sobrien	    default:
3435179404Sobrien	      internalError ();
3436179404Sobrien	    }
3437179404Sobrien	  continue;
3438179404Sobrien
3439218822Sdim	case '2':
3440218822Sdim	  INSERT_OPERAND (BP, insn, va_arg (args, int));
3441218822Sdim	  continue;
3442218822Sdim
3443179404Sobrien	case 't':
3444179404Sobrien	case 'w':
3445179404Sobrien	case 'E':
3446208737Sjmallett	  INSERT_OPERAND (RT, insn, va_arg (args, int));
3447179404Sobrien	  continue;
3448179404Sobrien
3449179404Sobrien	case 'c':
3450208737Sjmallett	  INSERT_OPERAND (CODE, insn, va_arg (args, int));
3451179404Sobrien	  continue;
3452179404Sobrien
3453179404Sobrien	case 'T':
3454179404Sobrien	case 'W':
3455208737Sjmallett	  INSERT_OPERAND (FT, insn, va_arg (args, int));
3456179404Sobrien	  continue;
3457179404Sobrien
3458179404Sobrien	case 'd':
3459179404Sobrien	case 'G':
3460179404Sobrien	case 'K':
3461208737Sjmallett	  INSERT_OPERAND (RD, insn, va_arg (args, int));
3462179404Sobrien	  continue;
3463179404Sobrien
3464179404Sobrien	case 'U':
3465179404Sobrien	  {
3466179404Sobrien	    int tmp = va_arg (args, int);
3467179404Sobrien
3468208737Sjmallett	    INSERT_OPERAND (RT, insn, tmp);
3469208737Sjmallett	    INSERT_OPERAND (RD, insn, tmp);
3470179404Sobrien	    continue;
3471179404Sobrien	  }
3472179404Sobrien
3473179404Sobrien	case 'V':
3474179404Sobrien	case 'S':
3475208737Sjmallett	  INSERT_OPERAND (FS, insn, va_arg (args, int));
3476179404Sobrien	  continue;
3477179404Sobrien
3478179404Sobrien	case 'z':
3479179404Sobrien	  continue;
3480179404Sobrien
3481179404Sobrien	case '<':
3482208737Sjmallett	  INSERT_OPERAND (SHAMT, insn, va_arg (args, int));
3483179404Sobrien	  continue;
3484179404Sobrien
3485179404Sobrien	case 'D':
3486208737Sjmallett	  INSERT_OPERAND (FD, insn, va_arg (args, int));
3487179404Sobrien	  continue;
3488179404Sobrien
3489179404Sobrien	case 'B':
3490208737Sjmallett	  INSERT_OPERAND (CODE20, insn, va_arg (args, int));
3491179404Sobrien	  continue;
3492179404Sobrien
3493179404Sobrien	case 'J':
3494208737Sjmallett	  INSERT_OPERAND (CODE19, insn, va_arg (args, int));
3495179404Sobrien	  continue;
3496179404Sobrien
3497179404Sobrien	case 'q':
3498208737Sjmallett	  INSERT_OPERAND (CODE2, insn, va_arg (args, int));
3499179404Sobrien	  continue;
3500179404Sobrien
3501179404Sobrien	case 'b':
3502179404Sobrien	case 's':
3503179404Sobrien	case 'r':
3504179404Sobrien	case 'v':
3505208737Sjmallett	  INSERT_OPERAND (RS, insn, va_arg (args, int));
3506179404Sobrien	  continue;
3507179404Sobrien
3508179404Sobrien	case 'i':
3509179404Sobrien	case 'j':
3510179404Sobrien	case 'o':
3511208737Sjmallett	  macro_read_relocs (&args, r);
3512179404Sobrien	  assert (*r == BFD_RELOC_GPREL16
3513179404Sobrien		  || *r == BFD_RELOC_MIPS_LITERAL
3514179404Sobrien		  || *r == BFD_RELOC_MIPS_HIGHER
3515179404Sobrien		  || *r == BFD_RELOC_HI16_S
3516179404Sobrien		  || *r == BFD_RELOC_LO16
3517179404Sobrien		  || *r == BFD_RELOC_MIPS_GOT16
3518179404Sobrien		  || *r == BFD_RELOC_MIPS_CALL16
3519179404Sobrien		  || *r == BFD_RELOC_MIPS_GOT_DISP
3520179404Sobrien		  || *r == BFD_RELOC_MIPS_GOT_PAGE
3521179404Sobrien		  || *r == BFD_RELOC_MIPS_GOT_OFST
3522179404Sobrien		  || *r == BFD_RELOC_MIPS_GOT_LO16
3523208737Sjmallett		  || *r == BFD_RELOC_MIPS_CALL_LO16);
3524179404Sobrien	  continue;
3525179404Sobrien
3526179404Sobrien	case 'u':
3527208737Sjmallett	  macro_read_relocs (&args, r);
3528179404Sobrien	  assert (ep != NULL
3529179404Sobrien		  && (ep->X_op == O_constant
3530179404Sobrien		      || (ep->X_op == O_symbol
3531179404Sobrien			  && (*r == BFD_RELOC_MIPS_HIGHEST
3532179404Sobrien			      || *r == BFD_RELOC_HI16_S
3533179404Sobrien			      || *r == BFD_RELOC_HI16
3534179404Sobrien			      || *r == BFD_RELOC_GPREL16
3535179404Sobrien			      || *r == BFD_RELOC_MIPS_GOT_HI16
3536208737Sjmallett			      || *r == BFD_RELOC_MIPS_CALL_HI16))));
3537179404Sobrien	  continue;
3538179404Sobrien
3539179404Sobrien	case 'p':
3540179404Sobrien	  assert (ep != NULL);
3541208737Sjmallett
3542179404Sobrien	  /*
3543179404Sobrien	   * This allows macro() to pass an immediate expression for
3544179404Sobrien	   * creating short branches without creating a symbol.
3545208737Sjmallett	   *
3546208737Sjmallett	   * We don't allow branch relaxation for these branches, as
3547208737Sjmallett	   * they should only appear in ".set nomacro" anyway.
3548179404Sobrien	   */
3549179404Sobrien	  if (ep->X_op == O_constant)
3550179404Sobrien	    {
3551208737Sjmallett	      if ((ep->X_add_number & 3) != 0)
3552208737Sjmallett		as_bad (_("branch to misaligned address (0x%lx)"),
3553208737Sjmallett			(unsigned long) ep->X_add_number);
3554208737Sjmallett	      if ((ep->X_add_number + 0x20000) & ~0x3ffff)
3555208737Sjmallett		as_bad (_("branch address range overflow (0x%lx)"),
3556208737Sjmallett			(unsigned long) ep->X_add_number);
3557179404Sobrien	      insn.insn_opcode |= (ep->X_add_number >> 2) & 0xffff;
3558179404Sobrien	      ep = NULL;
3559179404Sobrien	    }
3560179404Sobrien	  else
3561179404Sobrien	    *r = BFD_RELOC_16_PCREL_S2;
3562179404Sobrien	  continue;
3563179404Sobrien
3564179404Sobrien	case 'a':
3565179404Sobrien	  assert (ep != NULL);
3566179404Sobrien	  *r = BFD_RELOC_MIPS_JMP;
3567179404Sobrien	  continue;
3568179404Sobrien
3569179404Sobrien	case 'C':
3570218822Sdim	  INSERT_OPERAND (COPZ, insn, va_arg (args, unsigned long));
3571179404Sobrien	  continue;
3572179404Sobrien
3573218822Sdim	case 'k':
3574218822Sdim	  INSERT_OPERAND (CACHE, insn, va_arg (args, unsigned long));
3575218822Sdim	  continue;
3576218822Sdim
3577179404Sobrien	default:
3578179404Sobrien	  internalError ();
3579179404Sobrien	}
3580179404Sobrien      break;
3581179404Sobrien    }
3582179404Sobrien  va_end (args);
3583179404Sobrien  assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
3584179404Sobrien
3585179404Sobrien  append_insn (&insn, ep, r);
3586179404Sobrien}
3587179404Sobrien
3588179404Sobrienstatic void
3589179404Sobrienmips16_macro_build (expressionS *ep, const char *name, const char *fmt,
3590179404Sobrien		    va_list args)
3591179404Sobrien{
3592208737Sjmallett  struct mips_opcode *mo;
3593179404Sobrien  struct mips_cl_insn insn;
3594179404Sobrien  bfd_reloc_code_real_type r[3]
3595179404Sobrien    = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
3596179404Sobrien
3597208737Sjmallett  mo = (struct mips_opcode *) hash_find (mips16_op_hash, name);
3598208737Sjmallett  assert (mo);
3599208737Sjmallett  assert (strcmp (name, mo->name) == 0);
3600179404Sobrien
3601208737Sjmallett  while (strcmp (fmt, mo->args) != 0 || mo->pinfo == INSN_MACRO)
3602179404Sobrien    {
3603208737Sjmallett      ++mo;
3604208737Sjmallett      assert (mo->name);
3605208737Sjmallett      assert (strcmp (name, mo->name) == 0);
3606179404Sobrien    }
3607179404Sobrien
3608208737Sjmallett  create_insn (&insn, mo);
3609179404Sobrien  for (;;)
3610179404Sobrien    {
3611179404Sobrien      int c;
3612179404Sobrien
3613179404Sobrien      c = *fmt++;
3614179404Sobrien      switch (c)
3615179404Sobrien	{
3616179404Sobrien	case '\0':
3617179404Sobrien	  break;
3618179404Sobrien
3619179404Sobrien	case ',':
3620179404Sobrien	case '(':
3621179404Sobrien	case ')':
3622179404Sobrien	  continue;
3623179404Sobrien
3624179404Sobrien	case 'y':
3625179404Sobrien	case 'w':
3626208737Sjmallett	  MIPS16_INSERT_OPERAND (RY, insn, va_arg (args, int));
3627179404Sobrien	  continue;
3628179404Sobrien
3629179404Sobrien	case 'x':
3630179404Sobrien	case 'v':
3631208737Sjmallett	  MIPS16_INSERT_OPERAND (RX, insn, va_arg (args, int));
3632179404Sobrien	  continue;
3633179404Sobrien
3634179404Sobrien	case 'z':
3635208737Sjmallett	  MIPS16_INSERT_OPERAND (RZ, insn, va_arg (args, int));
3636179404Sobrien	  continue;
3637179404Sobrien
3638179404Sobrien	case 'Z':
3639208737Sjmallett	  MIPS16_INSERT_OPERAND (MOVE32Z, insn, va_arg (args, int));
3640179404Sobrien	  continue;
3641179404Sobrien
3642179404Sobrien	case '0':
3643179404Sobrien	case 'S':
3644179404Sobrien	case 'P':
3645179404Sobrien	case 'R':
3646179404Sobrien	  continue;
3647179404Sobrien
3648179404Sobrien	case 'X':
3649208737Sjmallett	  MIPS16_INSERT_OPERAND (REGR32, insn, va_arg (args, int));
3650179404Sobrien	  continue;
3651179404Sobrien
3652179404Sobrien	case 'Y':
3653179404Sobrien	  {
3654179404Sobrien	    int regno;
3655179404Sobrien
3656179404Sobrien	    regno = va_arg (args, int);
3657179404Sobrien	    regno = ((regno & 7) << 2) | ((regno & 0x18) >> 3);
3658218822Sdim	    MIPS16_INSERT_OPERAND (REG32R, insn, regno);
3659179404Sobrien	  }
3660179404Sobrien	  continue;
3661179404Sobrien
3662179404Sobrien	case '<':
3663179404Sobrien	case '>':
3664179404Sobrien	case '4':
3665179404Sobrien	case '5':
3666179404Sobrien	case 'H':
3667179404Sobrien	case 'W':
3668179404Sobrien	case 'D':
3669179404Sobrien	case 'j':
3670179404Sobrien	case '8':
3671179404Sobrien	case 'V':
3672179404Sobrien	case 'C':
3673179404Sobrien	case 'U':
3674179404Sobrien	case 'k':
3675179404Sobrien	case 'K':
3676179404Sobrien	case 'p':
3677179404Sobrien	case 'q':
3678179404Sobrien	  {
3679179404Sobrien	    assert (ep != NULL);
3680179404Sobrien
3681179404Sobrien	    if (ep->X_op != O_constant)
3682179404Sobrien	      *r = (int) BFD_RELOC_UNUSED + c;
3683179404Sobrien	    else
3684179404Sobrien	      {
3685179404Sobrien		mips16_immed (NULL, 0, c, ep->X_add_number, FALSE, FALSE,
3686179404Sobrien			      FALSE, &insn.insn_opcode, &insn.use_extend,
3687179404Sobrien			      &insn.extend);
3688179404Sobrien		ep = NULL;
3689179404Sobrien		*r = BFD_RELOC_UNUSED;
3690179404Sobrien	      }
3691179404Sobrien	  }
3692179404Sobrien	  continue;
3693179404Sobrien
3694179404Sobrien	case '6':
3695208737Sjmallett	  MIPS16_INSERT_OPERAND (IMM6, insn, va_arg (args, int));
3696179404Sobrien	  continue;
3697179404Sobrien	}
3698179404Sobrien
3699179404Sobrien      break;
3700179404Sobrien    }
3701179404Sobrien
3702179404Sobrien  assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
3703179404Sobrien
3704179404Sobrien  append_insn (&insn, ep, r);
3705179404Sobrien}
3706179404Sobrien
3707179404Sobrien/*
3708208737Sjmallett * Sign-extend 32-bit mode constants that have bit 31 set and all
3709208737Sjmallett * higher bits unset.
3710208737Sjmallett */
3711208737Sjmallettstatic void
3712208737Sjmallettnormalize_constant_expr (expressionS *ex)
3713208737Sjmallett{
3714208737Sjmallett  if (ex->X_op == O_constant
3715208737Sjmallett      && IS_ZEXT_32BIT_NUM (ex->X_add_number))
3716208737Sjmallett    ex->X_add_number = (((ex->X_add_number & 0xffffffff) ^ 0x80000000)
3717208737Sjmallett			- 0x80000000);
3718208737Sjmallett}
3719208737Sjmallett
3720208737Sjmallett/*
3721208737Sjmallett * Sign-extend 32-bit mode address offsets that have bit 31 set and
3722208737Sjmallett * all higher bits unset.
3723208737Sjmallett */
3724208737Sjmallettstatic void
3725208737Sjmallettnormalize_address_expr (expressionS *ex)
3726208737Sjmallett{
3727208737Sjmallett  if (((ex->X_op == O_constant && HAVE_32BIT_ADDRESSES)
3728208737Sjmallett	|| (ex->X_op == O_symbol && HAVE_32BIT_SYMBOLS))
3729208737Sjmallett      && IS_ZEXT_32BIT_NUM (ex->X_add_number))
3730208737Sjmallett    ex->X_add_number = (((ex->X_add_number & 0xffffffff) ^ 0x80000000)
3731208737Sjmallett			- 0x80000000);
3732208737Sjmallett}
3733208737Sjmallett
3734208737Sjmallett/*
3735179404Sobrien * Generate a "jalr" instruction with a relocation hint to the called
3736179404Sobrien * function.  This occurs in NewABI PIC code.
3737179404Sobrien */
3738179404Sobrienstatic void
3739179404Sobrienmacro_build_jalr (expressionS *ep)
3740179404Sobrien{
3741179404Sobrien  char *f = NULL;
3742179404Sobrien
3743179404Sobrien  if (HAVE_NEWABI)
3744179404Sobrien    {
3745179404Sobrien      frag_grow (8);
3746179404Sobrien      f = frag_more (0);
3747179404Sobrien    }
3748179404Sobrien  macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
3749179404Sobrien  if (HAVE_NEWABI)
3750179404Sobrien    fix_new_exp (frag_now, f - frag_now->fr_literal,
3751179404Sobrien		 4, ep, FALSE, BFD_RELOC_MIPS_JALR);
3752179404Sobrien}
3753179404Sobrien
3754179404Sobrien/*
3755179404Sobrien * Generate a "lui" instruction.
3756179404Sobrien */
3757179404Sobrienstatic void
3758179404Sobrienmacro_build_lui (expressionS *ep, int regnum)
3759179404Sobrien{
3760179404Sobrien  expressionS high_expr;
3761208737Sjmallett  const struct mips_opcode *mo;
3762179404Sobrien  struct mips_cl_insn insn;
3763179404Sobrien  bfd_reloc_code_real_type r[3]
3764179404Sobrien    = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
3765179404Sobrien  const char *name = "lui";
3766179404Sobrien  const char *fmt = "t,u";
3767179404Sobrien
3768179404Sobrien  assert (! mips_opts.mips16);
3769179404Sobrien
3770179404Sobrien  high_expr = *ep;
3771179404Sobrien
3772179404Sobrien  if (high_expr.X_op == O_constant)
3773179404Sobrien    {
3774218822Sdim      /* We can compute the instruction now without a relocation entry.  */
3775179404Sobrien      high_expr.X_add_number = ((high_expr.X_add_number + 0x8000)
3776179404Sobrien				>> 16) & 0xffff;
3777179404Sobrien      *r = BFD_RELOC_UNUSED;
3778179404Sobrien    }
3779179404Sobrien  else
3780179404Sobrien    {
3781179404Sobrien      assert (ep->X_op == O_symbol);
3782208737Sjmallett      /* _gp_disp is a special case, used from s_cpload.
3783208737Sjmallett	 __gnu_local_gp is used if mips_no_shared.  */
3784179404Sobrien      assert (mips_pic == NO_PIC
3785179404Sobrien	      || (! HAVE_NEWABI
3786208737Sjmallett		  && strcmp (S_GET_NAME (ep->X_add_symbol), "_gp_disp") == 0)
3787208737Sjmallett	      || (! mips_in_shared
3788208737Sjmallett		  && strcmp (S_GET_NAME (ep->X_add_symbol),
3789208737Sjmallett                             "__gnu_local_gp") == 0));
3790179404Sobrien      *r = BFD_RELOC_HI16_S;
3791179404Sobrien    }
3792179404Sobrien
3793208737Sjmallett  mo = hash_find (op_hash, name);
3794208737Sjmallett  assert (strcmp (name, mo->name) == 0);
3795208737Sjmallett  assert (strcmp (fmt, mo->args) == 0);
3796208737Sjmallett  create_insn (&insn, mo);
3797179404Sobrien
3798208737Sjmallett  insn.insn_opcode = insn.insn_mo->match;
3799208737Sjmallett  INSERT_OPERAND (RT, insn, regnum);
3800179404Sobrien  if (*r == BFD_RELOC_UNUSED)
3801179404Sobrien    {
3802179404Sobrien      insn.insn_opcode |= high_expr.X_add_number;
3803179404Sobrien      append_insn (&insn, NULL, r);
3804179404Sobrien    }
3805179404Sobrien  else
3806179404Sobrien    append_insn (&insn, &high_expr, r);
3807179404Sobrien}
3808179404Sobrien
3809179404Sobrien/* Generate a sequence of instructions to do a load or store from a constant
3810179404Sobrien   offset off of a base register (breg) into/from a target register (treg),
3811179404Sobrien   using AT if necessary.  */
3812179404Sobrienstatic void
3813179404Sobrienmacro_build_ldst_constoffset (expressionS *ep, const char *op,
3814179404Sobrien			      int treg, int breg, int dbl)
3815179404Sobrien{
3816179404Sobrien  assert (ep->X_op == O_constant);
3817179404Sobrien
3818179404Sobrien  /* Sign-extending 32-bit constants makes their handling easier.  */
3819208737Sjmallett  if (!dbl)
3820208737Sjmallett    normalize_constant_expr (ep);
3821179404Sobrien
3822179404Sobrien  /* Right now, this routine can only handle signed 32-bit constants.  */
3823179404Sobrien  if (! IS_SEXT_32BIT_NUM(ep->X_add_number + 0x8000))
3824179404Sobrien    as_warn (_("operand overflow"));
3825179404Sobrien
3826179404Sobrien  if (IS_SEXT_16BIT_NUM(ep->X_add_number))
3827179404Sobrien    {
3828179404Sobrien      /* Signed 16-bit offset will fit in the op.  Easy!  */
3829179404Sobrien      macro_build (ep, op, "t,o(b)", treg, BFD_RELOC_LO16, breg);
3830179404Sobrien    }
3831179404Sobrien  else
3832179404Sobrien    {
3833179404Sobrien      /* 32-bit offset, need multiple instructions and AT, like:
3834179404Sobrien	   lui      $tempreg,const_hi       (BFD_RELOC_HI16_S)
3835179404Sobrien	   addu     $tempreg,$tempreg,$breg
3836179404Sobrien           <op>     $treg,const_lo($tempreg)   (BFD_RELOC_LO16)
3837179404Sobrien         to handle the complete offset.  */
3838179404Sobrien      macro_build_lui (ep, AT);
3839179404Sobrien      macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
3840179404Sobrien      macro_build (ep, op, "t,o(b)", treg, BFD_RELOC_LO16, AT);
3841179404Sobrien
3842179404Sobrien      if (mips_opts.noat)
3843208737Sjmallett	as_bad (_("Macro used $at after \".set noat\""));
3844179404Sobrien    }
3845179404Sobrien}
3846179404Sobrien
3847179404Sobrien/*			set_at()
3848179404Sobrien * Generates code to set the $at register to true (one)
3849179404Sobrien * if reg is less than the immediate expression.
3850179404Sobrien */
3851179404Sobrienstatic void
3852179404Sobrienset_at (int reg, int unsignedp)
3853179404Sobrien{
3854179404Sobrien  if (imm_expr.X_op == O_constant
3855179404Sobrien      && imm_expr.X_add_number >= -0x8000
3856179404Sobrien      && imm_expr.X_add_number < 0x8000)
3857179404Sobrien    macro_build (&imm_expr, unsignedp ? "sltiu" : "slti", "t,r,j",
3858179404Sobrien		 AT, reg, BFD_RELOC_LO16);
3859179404Sobrien  else
3860179404Sobrien    {
3861179404Sobrien      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
3862179404Sobrien      macro_build (NULL, unsignedp ? "sltu" : "slt", "d,v,t", AT, reg, AT);
3863179404Sobrien    }
3864179404Sobrien}
3865179404Sobrien
3866179404Sobrien/* Warn if an expression is not a constant.  */
3867179404Sobrien
3868179404Sobrienstatic void
3869179404Sobriencheck_absolute_expr (struct mips_cl_insn *ip, expressionS *ex)
3870179404Sobrien{
3871179404Sobrien  if (ex->X_op == O_big)
3872179404Sobrien    as_bad (_("unsupported large constant"));
3873179404Sobrien  else if (ex->X_op != O_constant)
3874208737Sjmallett    as_bad (_("Instruction %s requires absolute expression"),
3875208737Sjmallett	    ip->insn_mo->name);
3876179404Sobrien
3877208737Sjmallett  if (HAVE_32BIT_GPRS)
3878208737Sjmallett    normalize_constant_expr (ex);
3879179404Sobrien}
3880179404Sobrien
3881179404Sobrien/* Count the leading zeroes by performing a binary chop. This is a
3882179404Sobrien   bulky bit of source, but performance is a LOT better for the
3883179404Sobrien   majority of values than a simple loop to count the bits:
3884179404Sobrien       for (lcnt = 0; (lcnt < 32); lcnt++)
3885179404Sobrien         if ((v) & (1 << (31 - lcnt)))
3886179404Sobrien           break;
3887179404Sobrien  However it is not code size friendly, and the gain will drop a bit
3888179404Sobrien  on certain cached systems.
3889179404Sobrien*/
3890179404Sobrien#define COUNT_TOP_ZEROES(v)             \
3891179404Sobrien  (((v) & ~0xffff) == 0                 \
3892179404Sobrien   ? ((v) & ~0xff) == 0                 \
3893179404Sobrien     ? ((v) & ~0xf) == 0                \
3894179404Sobrien       ? ((v) & ~0x3) == 0              \
3895179404Sobrien         ? ((v) & ~0x1) == 0            \
3896179404Sobrien           ? !(v)                       \
3897179404Sobrien             ? 32                       \
3898179404Sobrien             : 31                       \
3899179404Sobrien           : 30                         \
3900179404Sobrien         : ((v) & ~0x7) == 0            \
3901179404Sobrien           ? 29                         \
3902179404Sobrien           : 28                         \
3903179404Sobrien       : ((v) & ~0x3f) == 0             \
3904179404Sobrien         ? ((v) & ~0x1f) == 0           \
3905179404Sobrien           ? 27                         \
3906179404Sobrien           : 26                         \
3907179404Sobrien         : ((v) & ~0x7f) == 0           \
3908179404Sobrien           ? 25                         \
3909179404Sobrien           : 24                         \
3910179404Sobrien     : ((v) & ~0xfff) == 0              \
3911179404Sobrien       ? ((v) & ~0x3ff) == 0            \
3912179404Sobrien         ? ((v) & ~0x1ff) == 0          \
3913179404Sobrien           ? 23                         \
3914179404Sobrien           : 22                         \
3915179404Sobrien         : ((v) & ~0x7ff) == 0          \
3916179404Sobrien           ? 21                         \
3917179404Sobrien           : 20                         \
3918179404Sobrien       : ((v) & ~0x3fff) == 0           \
3919179404Sobrien         ? ((v) & ~0x1fff) == 0         \
3920179404Sobrien           ? 19                         \
3921179404Sobrien           : 18                         \
3922179404Sobrien         : ((v) & ~0x7fff) == 0         \
3923179404Sobrien           ? 17                         \
3924179404Sobrien           : 16                         \
3925179404Sobrien   : ((v) & ~0xffffff) == 0             \
3926179404Sobrien     ? ((v) & ~0xfffff) == 0            \
3927179404Sobrien       ? ((v) & ~0x3ffff) == 0          \
3928179404Sobrien         ? ((v) & ~0x1ffff) == 0        \
3929179404Sobrien           ? 15                         \
3930179404Sobrien           : 14                         \
3931179404Sobrien         : ((v) & ~0x7ffff) == 0        \
3932179404Sobrien           ? 13                         \
3933179404Sobrien           : 12                         \
3934179404Sobrien       : ((v) & ~0x3fffff) == 0         \
3935179404Sobrien         ? ((v) & ~0x1fffff) == 0       \
3936179404Sobrien           ? 11                         \
3937179404Sobrien           : 10                         \
3938179404Sobrien         : ((v) & ~0x7fffff) == 0       \
3939179404Sobrien           ? 9                          \
3940179404Sobrien           : 8                          \
3941179404Sobrien     : ((v) & ~0xfffffff) == 0          \
3942179404Sobrien       ? ((v) & ~0x3ffffff) == 0        \
3943179404Sobrien         ? ((v) & ~0x1ffffff) == 0      \
3944179404Sobrien           ? 7                          \
3945179404Sobrien           : 6                          \
3946179404Sobrien         : ((v) & ~0x7ffffff) == 0      \
3947179404Sobrien           ? 5                          \
3948179404Sobrien           : 4                          \
3949179404Sobrien       : ((v) & ~0x3fffffff) == 0       \
3950179404Sobrien         ? ((v) & ~0x1fffffff) == 0     \
3951179404Sobrien           ? 3                          \
3952179404Sobrien           : 2                          \
3953179404Sobrien         : ((v) & ~0x7fffffff) == 0     \
3954179404Sobrien           ? 1                          \
3955179404Sobrien           : 0)
3956179404Sobrien
3957179404Sobrien/*			load_register()
3958179404Sobrien *  This routine generates the least number of instructions necessary to load
3959179404Sobrien *  an absolute expression value into a register.
3960179404Sobrien */
3961179404Sobrienstatic void
3962179404Sobrienload_register (int reg, expressionS *ep, int dbl)
3963179404Sobrien{
3964179404Sobrien  int freg;
3965179404Sobrien  expressionS hi32, lo32;
3966179404Sobrien
3967179404Sobrien  if (ep->X_op != O_big)
3968179404Sobrien    {
3969179404Sobrien      assert (ep->X_op == O_constant);
3970179404Sobrien
3971179404Sobrien      /* Sign-extending 32-bit constants makes their handling easier.  */
3972208737Sjmallett      if (!dbl)
3973208737Sjmallett	normalize_constant_expr (ep);
3974179404Sobrien
3975179404Sobrien      if (IS_SEXT_16BIT_NUM (ep->X_add_number))
3976179404Sobrien	{
3977179404Sobrien	  /* We can handle 16 bit signed values with an addiu to
3978179404Sobrien	     $zero.  No need to ever use daddiu here, since $zero and
3979179404Sobrien	     the result are always correct in 32 bit mode.  */
3980179404Sobrien	  macro_build (ep, "addiu", "t,r,j", reg, 0, BFD_RELOC_LO16);
3981179404Sobrien	  return;
3982179404Sobrien	}
3983179404Sobrien      else if (ep->X_add_number >= 0 && ep->X_add_number < 0x10000)
3984179404Sobrien	{
3985179404Sobrien	  /* We can handle 16 bit unsigned values with an ori to
3986179404Sobrien             $zero.  */
3987179404Sobrien	  macro_build (ep, "ori", "t,r,i", reg, 0, BFD_RELOC_LO16);
3988179404Sobrien	  return;
3989179404Sobrien	}
3990179404Sobrien      else if ((IS_SEXT_32BIT_NUM (ep->X_add_number)))
3991179404Sobrien	{
3992179404Sobrien	  /* 32 bit values require an lui.  */
3993179404Sobrien	  macro_build (ep, "lui", "t,u", reg, BFD_RELOC_HI16);
3994179404Sobrien	  if ((ep->X_add_number & 0xffff) != 0)
3995179404Sobrien	    macro_build (ep, "ori", "t,r,i", reg, reg, BFD_RELOC_LO16);
3996179404Sobrien	  return;
3997179404Sobrien	}
3998179404Sobrien    }
3999179404Sobrien
4000179404Sobrien  /* The value is larger than 32 bits.  */
4001179404Sobrien
4002208737Sjmallett  if (!dbl || HAVE_32BIT_GPRS)
4003179404Sobrien    {
4004208737Sjmallett      char value[32];
4005208737Sjmallett
4006208737Sjmallett      sprintf_vma (value, ep->X_add_number);
4007208737Sjmallett      as_bad (_("Number (0x%s) larger than 32 bits"), value);
4008179404Sobrien      macro_build (ep, "addiu", "t,r,j", reg, 0, BFD_RELOC_LO16);
4009179404Sobrien      return;
4010179404Sobrien    }
4011179404Sobrien
4012179404Sobrien  if (ep->X_op != O_big)
4013179404Sobrien    {
4014179404Sobrien      hi32 = *ep;
4015179404Sobrien      hi32.X_add_number = (valueT) hi32.X_add_number >> 16;
4016179404Sobrien      hi32.X_add_number = (valueT) hi32.X_add_number >> 16;
4017179404Sobrien      hi32.X_add_number &= 0xffffffff;
4018179404Sobrien      lo32 = *ep;
4019179404Sobrien      lo32.X_add_number &= 0xffffffff;
4020179404Sobrien    }
4021179404Sobrien  else
4022179404Sobrien    {
4023179404Sobrien      assert (ep->X_add_number > 2);
4024179404Sobrien      if (ep->X_add_number == 3)
4025179404Sobrien	generic_bignum[3] = 0;
4026179404Sobrien      else if (ep->X_add_number > 4)
4027179404Sobrien	as_bad (_("Number larger than 64 bits"));
4028179404Sobrien      lo32.X_op = O_constant;
4029179404Sobrien      lo32.X_add_number = generic_bignum[0] + (generic_bignum[1] << 16);
4030179404Sobrien      hi32.X_op = O_constant;
4031179404Sobrien      hi32.X_add_number = generic_bignum[2] + (generic_bignum[3] << 16);
4032179404Sobrien    }
4033179404Sobrien
4034179404Sobrien  if (hi32.X_add_number == 0)
4035179404Sobrien    freg = 0;
4036179404Sobrien  else
4037179404Sobrien    {
4038179404Sobrien      int shift, bit;
4039179404Sobrien      unsigned long hi, lo;
4040179404Sobrien
4041179404Sobrien      if (hi32.X_add_number == (offsetT) 0xffffffff)
4042179404Sobrien	{
4043179404Sobrien	  if ((lo32.X_add_number & 0xffff8000) == 0xffff8000)
4044179404Sobrien	    {
4045179404Sobrien	      macro_build (&lo32, "addiu", "t,r,j", reg, 0, BFD_RELOC_LO16);
4046179404Sobrien	      return;
4047179404Sobrien	    }
4048179404Sobrien	  if (lo32.X_add_number & 0x80000000)
4049179404Sobrien	    {
4050179404Sobrien	      macro_build (&lo32, "lui", "t,u", reg, BFD_RELOC_HI16);
4051179404Sobrien	      if (lo32.X_add_number & 0xffff)
4052179404Sobrien		macro_build (&lo32, "ori", "t,r,i", reg, reg, BFD_RELOC_LO16);
4053179404Sobrien	      return;
4054179404Sobrien	    }
4055179404Sobrien	}
4056179404Sobrien
4057179404Sobrien      /* Check for 16bit shifted constant.  We know that hi32 is
4058179404Sobrien         non-zero, so start the mask on the first bit of the hi32
4059179404Sobrien         value.  */
4060179404Sobrien      shift = 17;
4061179404Sobrien      do
4062179404Sobrien	{
4063179404Sobrien	  unsigned long himask, lomask;
4064179404Sobrien
4065179404Sobrien	  if (shift < 32)
4066179404Sobrien	    {
4067179404Sobrien	      himask = 0xffff >> (32 - shift);
4068179404Sobrien	      lomask = (0xffff << shift) & 0xffffffff;
4069179404Sobrien	    }
4070179404Sobrien	  else
4071179404Sobrien	    {
4072179404Sobrien	      himask = 0xffff << (shift - 32);
4073179404Sobrien	      lomask = 0;
4074179404Sobrien	    }
4075179404Sobrien	  if ((hi32.X_add_number & ~(offsetT) himask) == 0
4076179404Sobrien	      && (lo32.X_add_number & ~(offsetT) lomask) == 0)
4077179404Sobrien	    {
4078179404Sobrien	      expressionS tmp;
4079179404Sobrien
4080179404Sobrien	      tmp.X_op = O_constant;
4081179404Sobrien	      if (shift < 32)
4082179404Sobrien		tmp.X_add_number = ((hi32.X_add_number << (32 - shift))
4083179404Sobrien				    | (lo32.X_add_number >> shift));
4084179404Sobrien	      else
4085179404Sobrien		tmp.X_add_number = hi32.X_add_number >> (shift - 32);
4086179404Sobrien	      macro_build (&tmp, "ori", "t,r,i", reg, 0, BFD_RELOC_LO16);
4087179404Sobrien	      macro_build (NULL, (shift >= 32) ? "dsll32" : "dsll", "d,w,<",
4088179404Sobrien			   reg, reg, (shift >= 32) ? shift - 32 : shift);
4089179404Sobrien	      return;
4090179404Sobrien	    }
4091179404Sobrien	  ++shift;
4092179404Sobrien	}
4093179404Sobrien      while (shift <= (64 - 16));
4094179404Sobrien
4095179404Sobrien      /* Find the bit number of the lowest one bit, and store the
4096179404Sobrien         shifted value in hi/lo.  */
4097179404Sobrien      hi = (unsigned long) (hi32.X_add_number & 0xffffffff);
4098179404Sobrien      lo = (unsigned long) (lo32.X_add_number & 0xffffffff);
4099179404Sobrien      if (lo != 0)
4100179404Sobrien	{
4101179404Sobrien	  bit = 0;
4102179404Sobrien	  while ((lo & 1) == 0)
4103179404Sobrien	    {
4104179404Sobrien	      lo >>= 1;
4105179404Sobrien	      ++bit;
4106179404Sobrien	    }
4107179404Sobrien	  lo |= (hi & (((unsigned long) 1 << bit) - 1)) << (32 - bit);
4108179404Sobrien	  hi >>= bit;
4109179404Sobrien	}
4110179404Sobrien      else
4111179404Sobrien	{
4112179404Sobrien	  bit = 32;
4113179404Sobrien	  while ((hi & 1) == 0)
4114179404Sobrien	    {
4115179404Sobrien	      hi >>= 1;
4116179404Sobrien	      ++bit;
4117179404Sobrien	    }
4118179404Sobrien	  lo = hi;
4119179404Sobrien	  hi = 0;
4120179404Sobrien	}
4121179404Sobrien
4122179404Sobrien      /* Optimize if the shifted value is a (power of 2) - 1.  */
4123179404Sobrien      if ((hi == 0 && ((lo + 1) & lo) == 0)
4124179404Sobrien	  || (lo == 0xffffffff && ((hi + 1) & hi) == 0))
4125179404Sobrien	{
4126179404Sobrien	  shift = COUNT_TOP_ZEROES ((unsigned int) hi32.X_add_number);
4127179404Sobrien	  if (shift != 0)
4128179404Sobrien	    {
4129179404Sobrien	      expressionS tmp;
4130179404Sobrien
4131179404Sobrien	      /* This instruction will set the register to be all
4132179404Sobrien                 ones.  */
4133179404Sobrien	      tmp.X_op = O_constant;
4134179404Sobrien	      tmp.X_add_number = (offsetT) -1;
4135179404Sobrien	      macro_build (&tmp, "addiu", "t,r,j", reg, 0, BFD_RELOC_LO16);
4136179404Sobrien	      if (bit != 0)
4137179404Sobrien		{
4138179404Sobrien		  bit += shift;
4139179404Sobrien		  macro_build (NULL, (bit >= 32) ? "dsll32" : "dsll", "d,w,<",
4140179404Sobrien			       reg, reg, (bit >= 32) ? bit - 32 : bit);
4141179404Sobrien		}
4142179404Sobrien	      macro_build (NULL, (shift >= 32) ? "dsrl32" : "dsrl", "d,w,<",
4143179404Sobrien			   reg, reg, (shift >= 32) ? shift - 32 : shift);
4144179404Sobrien	      return;
4145179404Sobrien	    }
4146179404Sobrien	}
4147179404Sobrien
4148179404Sobrien      /* Sign extend hi32 before calling load_register, because we can
4149179404Sobrien         generally get better code when we load a sign extended value.  */
4150179404Sobrien      if ((hi32.X_add_number & 0x80000000) != 0)
4151179404Sobrien	hi32.X_add_number |= ~(offsetT) 0xffffffff;
4152179404Sobrien      load_register (reg, &hi32, 0);
4153179404Sobrien      freg = reg;
4154179404Sobrien    }
4155179404Sobrien  if ((lo32.X_add_number & 0xffff0000) == 0)
4156179404Sobrien    {
4157179404Sobrien      if (freg != 0)
4158179404Sobrien	{
4159179404Sobrien	  macro_build (NULL, "dsll32", "d,w,<", reg, freg, 0);
4160179404Sobrien	  freg = reg;
4161179404Sobrien	}
4162179404Sobrien    }
4163179404Sobrien  else
4164179404Sobrien    {
4165179404Sobrien      expressionS mid16;
4166179404Sobrien
4167179404Sobrien      if ((freg == 0) && (lo32.X_add_number == (offsetT) 0xffffffff))
4168179404Sobrien	{
4169179404Sobrien	  macro_build (&lo32, "lui", "t,u", reg, BFD_RELOC_HI16);
4170179404Sobrien	  macro_build (NULL, "dsrl32", "d,w,<", reg, reg, 0);
4171179404Sobrien	  return;
4172179404Sobrien	}
4173179404Sobrien
4174179404Sobrien      if (freg != 0)
4175179404Sobrien	{
4176179404Sobrien	  macro_build (NULL, "dsll", "d,w,<", reg, freg, 16);
4177179404Sobrien	  freg = reg;
4178179404Sobrien	}
4179179404Sobrien      mid16 = lo32;
4180179404Sobrien      mid16.X_add_number >>= 16;
4181179404Sobrien      macro_build (&mid16, "ori", "t,r,i", reg, freg, BFD_RELOC_LO16);
4182179404Sobrien      macro_build (NULL, "dsll", "d,w,<", reg, reg, 16);
4183179404Sobrien      freg = reg;
4184179404Sobrien    }
4185179404Sobrien  if ((lo32.X_add_number & 0xffff) != 0)
4186179404Sobrien    macro_build (&lo32, "ori", "t,r,i", reg, freg, BFD_RELOC_LO16);
4187179404Sobrien}
4188179404Sobrien
4189208737Sjmallettstatic inline void
4190208737Sjmallettload_delay_nop (void)
4191208737Sjmallett{
4192208737Sjmallett  if (!gpr_interlocks)
4193208737Sjmallett    macro_build (NULL, "nop", "");
4194208737Sjmallett}
4195208737Sjmallett
4196179404Sobrien/* Load an address into a register.  */
4197179404Sobrien
4198179404Sobrienstatic void
4199179404Sobrienload_address (int reg, expressionS *ep, int *used_at)
4200179404Sobrien{
4201179404Sobrien  if (ep->X_op != O_constant
4202179404Sobrien      && ep->X_op != O_symbol)
4203179404Sobrien    {
4204179404Sobrien      as_bad (_("expression too complex"));
4205179404Sobrien      ep->X_op = O_constant;
4206179404Sobrien    }
4207179404Sobrien
4208179404Sobrien  if (ep->X_op == O_constant)
4209179404Sobrien    {
4210179404Sobrien      load_register (reg, ep, HAVE_64BIT_ADDRESSES);
4211179404Sobrien      return;
4212179404Sobrien    }
4213179404Sobrien
4214179404Sobrien  if (mips_pic == NO_PIC)
4215179404Sobrien    {
4216179404Sobrien      /* If this is a reference to a GP relative symbol, we want
4217179404Sobrien	   addiu	$reg,$gp,<sym>		(BFD_RELOC_GPREL16)
4218179404Sobrien	 Otherwise we want
4219179404Sobrien	   lui		$reg,<sym>		(BFD_RELOC_HI16_S)
4220179404Sobrien	   addiu	$reg,$reg,<sym>		(BFD_RELOC_LO16)
4221179404Sobrien	 If we have an addend, we always use the latter form.
4222179404Sobrien
4223179404Sobrien	 With 64bit address space and a usable $at we want
4224179404Sobrien	   lui		$reg,<sym>		(BFD_RELOC_MIPS_HIGHEST)
4225179404Sobrien	   lui		$at,<sym>		(BFD_RELOC_HI16_S)
4226179404Sobrien	   daddiu	$reg,<sym>		(BFD_RELOC_MIPS_HIGHER)
4227179404Sobrien	   daddiu	$at,<sym>		(BFD_RELOC_LO16)
4228179404Sobrien	   dsll32	$reg,0
4229179404Sobrien	   daddu	$reg,$reg,$at
4230179404Sobrien
4231179404Sobrien	 If $at is already in use, we use a path which is suboptimal
4232179404Sobrien	 on superscalar processors.
4233179404Sobrien	   lui		$reg,<sym>		(BFD_RELOC_MIPS_HIGHEST)
4234179404Sobrien	   daddiu	$reg,<sym>		(BFD_RELOC_MIPS_HIGHER)
4235179404Sobrien	   dsll		$reg,16
4236179404Sobrien	   daddiu	$reg,<sym>		(BFD_RELOC_HI16_S)
4237179404Sobrien	   dsll		$reg,16
4238179404Sobrien	   daddiu	$reg,<sym>		(BFD_RELOC_LO16)
4239208737Sjmallett
4240208737Sjmallett	 For GP relative symbols in 64bit address space we can use
4241208737Sjmallett	 the same sequence as in 32bit address space.  */
4242208737Sjmallett      if (HAVE_64BIT_SYMBOLS)
4243179404Sobrien	{
4244208737Sjmallett	  if ((valueT) ep->X_add_number <= MAX_GPREL_OFFSET
4245208737Sjmallett	      && !nopic_need_relax (ep->X_add_symbol, 1))
4246208737Sjmallett	    {
4247208737Sjmallett	      relax_start (ep->X_add_symbol);
4248208737Sjmallett	      macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", reg,
4249208737Sjmallett			   mips_gp_register, BFD_RELOC_GPREL16);
4250208737Sjmallett	      relax_switch ();
4251208737Sjmallett	    }
4252179404Sobrien
4253208737Sjmallett	  if (*used_at == 0 && !mips_opts.noat)
4254179404Sobrien	    {
4255179404Sobrien	      macro_build (ep, "lui", "t,u", reg, BFD_RELOC_MIPS_HIGHEST);
4256179404Sobrien	      macro_build (ep, "lui", "t,u", AT, BFD_RELOC_HI16_S);
4257179404Sobrien	      macro_build (ep, "daddiu", "t,r,j", reg, reg,
4258179404Sobrien			   BFD_RELOC_MIPS_HIGHER);
4259179404Sobrien	      macro_build (ep, "daddiu", "t,r,j", AT, AT, BFD_RELOC_LO16);
4260179404Sobrien	      macro_build (NULL, "dsll32", "d,w,<", reg, reg, 0);
4261179404Sobrien	      macro_build (NULL, "daddu", "d,v,t", reg, reg, AT);
4262179404Sobrien	      *used_at = 1;
4263179404Sobrien	    }
4264179404Sobrien	  else
4265179404Sobrien	    {
4266179404Sobrien	      macro_build (ep, "lui", "t,u", reg, BFD_RELOC_MIPS_HIGHEST);
4267179404Sobrien	      macro_build (ep, "daddiu", "t,r,j", reg, reg,
4268179404Sobrien			   BFD_RELOC_MIPS_HIGHER);
4269179404Sobrien	      macro_build (NULL, "dsll", "d,w,<", reg, reg, 16);
4270179404Sobrien	      macro_build (ep, "daddiu", "t,r,j", reg, reg, BFD_RELOC_HI16_S);
4271179404Sobrien	      macro_build (NULL, "dsll", "d,w,<", reg, reg, 16);
4272179404Sobrien	      macro_build (ep, "daddiu", "t,r,j", reg, reg, BFD_RELOC_LO16);
4273179404Sobrien	    }
4274208737Sjmallett
4275208737Sjmallett	  if (mips_relax.sequence)
4276208737Sjmallett	    relax_end ();
4277179404Sobrien	}
4278179404Sobrien      else
4279179404Sobrien	{
4280179404Sobrien	  if ((valueT) ep->X_add_number <= MAX_GPREL_OFFSET
4281208737Sjmallett	      && !nopic_need_relax (ep->X_add_symbol, 1))
4282179404Sobrien	    {
4283179404Sobrien	      relax_start (ep->X_add_symbol);
4284179404Sobrien	      macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", reg,
4285179404Sobrien			   mips_gp_register, BFD_RELOC_GPREL16);
4286179404Sobrien	      relax_switch ();
4287179404Sobrien	    }
4288179404Sobrien	  macro_build_lui (ep, reg);
4289179404Sobrien	  macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j",
4290179404Sobrien		       reg, reg, BFD_RELOC_LO16);
4291179404Sobrien	  if (mips_relax.sequence)
4292179404Sobrien	    relax_end ();
4293179404Sobrien	}
4294179404Sobrien    }
4295208737Sjmallett  else if (!mips_big_got)
4296179404Sobrien    {
4297179404Sobrien      expressionS ex;
4298179404Sobrien
4299179404Sobrien      /* If this is a reference to an external symbol, we want
4300179404Sobrien	   lw		$reg,<sym>($gp)		(BFD_RELOC_MIPS_GOT16)
4301179404Sobrien	 Otherwise we want
4302179404Sobrien	   lw		$reg,<sym>($gp)		(BFD_RELOC_MIPS_GOT16)
4303179404Sobrien	   nop
4304179404Sobrien	   addiu	$reg,$reg,<sym>		(BFD_RELOC_LO16)
4305179404Sobrien	 If there is a constant, it must be added in after.
4306179404Sobrien
4307179404Sobrien	 If we have NewABI, we want
4308179404Sobrien	   lw		$reg,<sym+cst>($gp)	(BFD_RELOC_MIPS_GOT_DISP)
4309179404Sobrien         unless we're referencing a global symbol with a non-zero
4310179404Sobrien         offset, in which case cst must be added separately.  */
4311179404Sobrien      if (HAVE_NEWABI)
4312179404Sobrien	{
4313179404Sobrien	  if (ep->X_add_number)
4314179404Sobrien	    {
4315179404Sobrien	      ex.X_add_number = ep->X_add_number;
4316179404Sobrien	      ep->X_add_number = 0;
4317179404Sobrien	      relax_start (ep->X_add_symbol);
4318179404Sobrien	      macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
4319179404Sobrien			   BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
4320179404Sobrien	      if (ex.X_add_number < -0x8000 || ex.X_add_number >= 0x8000)
4321179404Sobrien		as_bad (_("PIC code offset overflow (max 16 signed bits)"));
4322179404Sobrien	      ex.X_op = O_constant;
4323179404Sobrien	      macro_build (&ex, ADDRESS_ADDI_INSN, "t,r,j",
4324179404Sobrien			   reg, reg, BFD_RELOC_LO16);
4325179404Sobrien	      ep->X_add_number = ex.X_add_number;
4326179404Sobrien	      relax_switch ();
4327179404Sobrien	    }
4328179404Sobrien	  macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
4329179404Sobrien		       BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
4330179404Sobrien	  if (mips_relax.sequence)
4331179404Sobrien	    relax_end ();
4332179404Sobrien	}
4333179404Sobrien      else
4334179404Sobrien	{
4335179404Sobrien	  ex.X_add_number = ep->X_add_number;
4336179404Sobrien	  ep->X_add_number = 0;
4337179404Sobrien	  macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
4338179404Sobrien		       BFD_RELOC_MIPS_GOT16, mips_gp_register);
4339208737Sjmallett	  load_delay_nop ();
4340179404Sobrien	  relax_start (ep->X_add_symbol);
4341179404Sobrien	  relax_switch ();
4342179404Sobrien	  macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", reg, reg,
4343179404Sobrien		       BFD_RELOC_LO16);
4344179404Sobrien	  relax_end ();
4345179404Sobrien
4346179404Sobrien	  if (ex.X_add_number != 0)
4347179404Sobrien	    {
4348179404Sobrien	      if (ex.X_add_number < -0x8000 || ex.X_add_number >= 0x8000)
4349179404Sobrien		as_bad (_("PIC code offset overflow (max 16 signed bits)"));
4350179404Sobrien	      ex.X_op = O_constant;
4351179404Sobrien	      macro_build (&ex, ADDRESS_ADDI_INSN, "t,r,j",
4352179404Sobrien			   reg, reg, BFD_RELOC_LO16);
4353179404Sobrien	    }
4354179404Sobrien	}
4355179404Sobrien    }
4356208737Sjmallett  else if (mips_big_got)
4357179404Sobrien    {
4358179404Sobrien      expressionS ex;
4359179404Sobrien
4360179404Sobrien      /* This is the large GOT case.  If this is a reference to an
4361179404Sobrien	 external symbol, we want
4362179404Sobrien	   lui		$reg,<sym>		(BFD_RELOC_MIPS_GOT_HI16)
4363179404Sobrien	   addu		$reg,$reg,$gp
4364179404Sobrien	   lw		$reg,<sym>($reg)	(BFD_RELOC_MIPS_GOT_LO16)
4365179404Sobrien
4366179404Sobrien	 Otherwise, for a reference to a local symbol in old ABI, we want
4367179404Sobrien	   lw		$reg,<sym>($gp)		(BFD_RELOC_MIPS_GOT16)
4368179404Sobrien	   nop
4369179404Sobrien	   addiu	$reg,$reg,<sym>		(BFD_RELOC_LO16)
4370179404Sobrien	 If there is a constant, it must be added in after.
4371179404Sobrien
4372179404Sobrien	 In the NewABI, for local symbols, with or without offsets, we want:
4373179404Sobrien	   lw		$reg,<sym>($gp)		(BFD_RELOC_MIPS_GOT_PAGE)
4374179404Sobrien	   addiu	$reg,$reg,<sym>		(BFD_RELOC_MIPS_GOT_OFST)
4375179404Sobrien      */
4376179404Sobrien      if (HAVE_NEWABI)
4377179404Sobrien	{
4378179404Sobrien	  ex.X_add_number = ep->X_add_number;
4379179404Sobrien	  ep->X_add_number = 0;
4380179404Sobrien	  relax_start (ep->X_add_symbol);
4381179404Sobrien	  macro_build (ep, "lui", "t,u", reg, BFD_RELOC_MIPS_GOT_HI16);
4382179404Sobrien	  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
4383179404Sobrien		       reg, reg, mips_gp_register);
4384179404Sobrien	  macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)",
4385179404Sobrien		       reg, BFD_RELOC_MIPS_GOT_LO16, reg);
4386179404Sobrien	  if (ex.X_add_number < -0x8000 || ex.X_add_number >= 0x8000)
4387179404Sobrien	    as_bad (_("PIC code offset overflow (max 16 signed bits)"));
4388179404Sobrien	  else if (ex.X_add_number)
4389179404Sobrien	    {
4390179404Sobrien	      ex.X_op = O_constant;
4391179404Sobrien	      macro_build (&ex, ADDRESS_ADDI_INSN, "t,r,j", reg, reg,
4392179404Sobrien			   BFD_RELOC_LO16);
4393179404Sobrien	    }
4394179404Sobrien
4395179404Sobrien	  ep->X_add_number = ex.X_add_number;
4396179404Sobrien	  relax_switch ();
4397179404Sobrien	  macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
4398179404Sobrien		       BFD_RELOC_MIPS_GOT_PAGE, mips_gp_register);
4399179404Sobrien	  macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", reg, reg,
4400179404Sobrien		       BFD_RELOC_MIPS_GOT_OFST);
4401179404Sobrien	  relax_end ();
4402179404Sobrien	}
4403179404Sobrien      else
4404179404Sobrien	{
4405179404Sobrien	  ex.X_add_number = ep->X_add_number;
4406179404Sobrien	  ep->X_add_number = 0;
4407179404Sobrien	  relax_start (ep->X_add_symbol);
4408179404Sobrien	  macro_build (ep, "lui", "t,u", reg, BFD_RELOC_MIPS_GOT_HI16);
4409179404Sobrien	  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
4410179404Sobrien		       reg, reg, mips_gp_register);
4411179404Sobrien	  macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)",
4412179404Sobrien		       reg, BFD_RELOC_MIPS_GOT_LO16, reg);
4413179404Sobrien	  relax_switch ();
4414179404Sobrien	  if (reg_needs_delay (mips_gp_register))
4415179404Sobrien	    {
4416179404Sobrien	      /* We need a nop before loading from $gp.  This special
4417179404Sobrien		 check is required because the lui which starts the main
4418179404Sobrien		 instruction stream does not refer to $gp, and so will not
4419179404Sobrien		 insert the nop which may be required.  */
4420179404Sobrien	      macro_build (NULL, "nop", "");
4421179404Sobrien	    }
4422179404Sobrien	  macro_build (ep, ADDRESS_LOAD_INSN, "t,o(b)", reg,
4423179404Sobrien		       BFD_RELOC_MIPS_GOT16, mips_gp_register);
4424208737Sjmallett	  load_delay_nop ();
4425179404Sobrien	  macro_build (ep, ADDRESS_ADDI_INSN, "t,r,j", reg, reg,
4426179404Sobrien		       BFD_RELOC_LO16);
4427179404Sobrien	  relax_end ();
4428179404Sobrien
4429179404Sobrien	  if (ex.X_add_number != 0)
4430179404Sobrien	    {
4431179404Sobrien	      if (ex.X_add_number < -0x8000 || ex.X_add_number >= 0x8000)
4432179404Sobrien		as_bad (_("PIC code offset overflow (max 16 signed bits)"));
4433179404Sobrien	      ex.X_op = O_constant;
4434179404Sobrien	      macro_build (&ex, ADDRESS_ADDI_INSN, "t,r,j", reg, reg,
4435179404Sobrien			   BFD_RELOC_LO16);
4436179404Sobrien	    }
4437179404Sobrien	}
4438179404Sobrien    }
4439179404Sobrien  else
4440179404Sobrien    abort ();
4441208737Sjmallett
4442208737Sjmallett  if (mips_opts.noat && *used_at == 1)
4443208737Sjmallett    as_bad (_("Macro used $at after \".set noat\""));
4444179404Sobrien}
4445179404Sobrien
4446179404Sobrien/* Move the contents of register SOURCE into register DEST.  */
4447179404Sobrien
4448179404Sobrienstatic void
4449179404Sobrienmove_register (int dest, int source)
4450179404Sobrien{
4451179404Sobrien  macro_build (NULL, HAVE_32BIT_GPRS ? "addu" : "daddu", "d,v,t",
4452179404Sobrien	       dest, source, 0);
4453179404Sobrien}
4454179404Sobrien
4455179404Sobrien/* Emit an SVR4 PIC sequence to load address LOCAL into DEST, where
4456179404Sobrien   LOCAL is the sum of a symbol and a 16-bit or 32-bit displacement.
4457179404Sobrien   The two alternatives are:
4458179404Sobrien
4459179404Sobrien   Global symbol		Local sybmol
4460179404Sobrien   -------------		------------
4461179404Sobrien   lw DEST,%got(SYMBOL)		lw DEST,%got(SYMBOL + OFFSET)
4462179404Sobrien   ...				...
4463179404Sobrien   addiu DEST,DEST,OFFSET	addiu DEST,DEST,%lo(SYMBOL + OFFSET)
4464179404Sobrien
4465179404Sobrien   load_got_offset emits the first instruction and add_got_offset
4466179404Sobrien   emits the second for a 16-bit offset or add_got_offset_hilo emits
4467179404Sobrien   a sequence to add a 32-bit offset using a scratch register.  */
4468179404Sobrien
4469179404Sobrienstatic void
4470179404Sobrienload_got_offset (int dest, expressionS *local)
4471179404Sobrien{
4472179404Sobrien  expressionS global;
4473179404Sobrien
4474179404Sobrien  global = *local;
4475179404Sobrien  global.X_add_number = 0;
4476179404Sobrien
4477179404Sobrien  relax_start (local->X_add_symbol);
4478179404Sobrien  macro_build (&global, ADDRESS_LOAD_INSN, "t,o(b)", dest,
4479179404Sobrien	       BFD_RELOC_MIPS_GOT16, mips_gp_register);
4480179404Sobrien  relax_switch ();
4481179404Sobrien  macro_build (local, ADDRESS_LOAD_INSN, "t,o(b)", dest,
4482179404Sobrien	       BFD_RELOC_MIPS_GOT16, mips_gp_register);
4483179404Sobrien  relax_end ();
4484179404Sobrien}
4485179404Sobrien
4486179404Sobrienstatic void
4487179404Sobrienadd_got_offset (int dest, expressionS *local)
4488179404Sobrien{
4489179404Sobrien  expressionS global;
4490179404Sobrien
4491179404Sobrien  global.X_op = O_constant;
4492179404Sobrien  global.X_op_symbol = NULL;
4493179404Sobrien  global.X_add_symbol = NULL;
4494179404Sobrien  global.X_add_number = local->X_add_number;
4495179404Sobrien
4496179404Sobrien  relax_start (local->X_add_symbol);
4497179404Sobrien  macro_build (&global, ADDRESS_ADDI_INSN, "t,r,j",
4498179404Sobrien	       dest, dest, BFD_RELOC_LO16);
4499179404Sobrien  relax_switch ();
4500179404Sobrien  macro_build (local, ADDRESS_ADDI_INSN, "t,r,j", dest, dest, BFD_RELOC_LO16);
4501179404Sobrien  relax_end ();
4502179404Sobrien}
4503179404Sobrien
4504179404Sobrienstatic void
4505179404Sobrienadd_got_offset_hilo (int dest, expressionS *local, int tmp)
4506179404Sobrien{
4507179404Sobrien  expressionS global;
4508179404Sobrien  int hold_mips_optimize;
4509179404Sobrien
4510179404Sobrien  global.X_op = O_constant;
4511179404Sobrien  global.X_op_symbol = NULL;
4512179404Sobrien  global.X_add_symbol = NULL;
4513179404Sobrien  global.X_add_number = local->X_add_number;
4514179404Sobrien
4515179404Sobrien  relax_start (local->X_add_symbol);
4516179404Sobrien  load_register (tmp, &global, HAVE_64BIT_ADDRESSES);
4517179404Sobrien  relax_switch ();
4518179404Sobrien  /* Set mips_optimize around the lui instruction to avoid
4519179404Sobrien     inserting an unnecessary nop after the lw.  */
4520179404Sobrien  hold_mips_optimize = mips_optimize;
4521179404Sobrien  mips_optimize = 2;
4522179404Sobrien  macro_build_lui (&global, tmp);
4523179404Sobrien  mips_optimize = hold_mips_optimize;
4524179404Sobrien  macro_build (local, ADDRESS_ADDI_INSN, "t,r,j", tmp, tmp, BFD_RELOC_LO16);
4525179404Sobrien  relax_end ();
4526179404Sobrien
4527179404Sobrien  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", dest, dest, tmp);
4528179404Sobrien}
4529179404Sobrien
4530179404Sobrien/*
4531179404Sobrien *			Build macros
4532179404Sobrien *   This routine implements the seemingly endless macro or synthesized
4533179404Sobrien * instructions and addressing modes in the mips assembly language. Many
4534179404Sobrien * of these macros are simple and are similar to each other. These could
4535179404Sobrien * probably be handled by some kind of table or grammar approach instead of
4536179404Sobrien * this verbose method. Others are not simple macros but are more like
4537179404Sobrien * optimizing code generation.
4538179404Sobrien *   One interesting optimization is when several store macros appear
4539179404Sobrien * consecutively that would load AT with the upper half of the same address.
4540179404Sobrien * The ensuing load upper instructions are ommited. This implies some kind
4541179404Sobrien * of global optimization. We currently only optimize within a single macro.
4542179404Sobrien *   For many of the load and store macros if the address is specified as a
4543179404Sobrien * constant expression in the first 64k of memory (ie ld $2,0x4000c) we
4544179404Sobrien * first load register 'at' with zero and use it as the base register. The
4545179404Sobrien * mips assembler simply uses register $zero. Just one tiny optimization
4546179404Sobrien * we're missing.
4547179404Sobrien */
4548179404Sobrienstatic void
4549179404Sobrienmacro (struct mips_cl_insn *ip)
4550179404Sobrien{
4551218822Sdim  int treg, sreg, dreg, breg;
4552179404Sobrien  int tempreg;
4553179404Sobrien  int mask;
4554179404Sobrien  int used_at = 0;
4555179404Sobrien  expressionS expr1;
4556179404Sobrien  const char *s;
4557179404Sobrien  const char *s2;
4558179404Sobrien  const char *fmt;
4559179404Sobrien  int likely = 0;
4560179404Sobrien  int dbl = 0;
4561179404Sobrien  int coproc = 0;
4562179404Sobrien  int lr = 0;
4563179404Sobrien  int imm = 0;
4564179404Sobrien  int call = 0;
4565179404Sobrien  int off;
4566179404Sobrien  offsetT maxnum;
4567179404Sobrien  bfd_reloc_code_real_type r;
4568179404Sobrien  int hold_mips_optimize;
4569179404Sobrien
4570179404Sobrien  assert (! mips_opts.mips16);
4571179404Sobrien
4572179404Sobrien  treg = (ip->insn_opcode >> 16) & 0x1f;
4573179404Sobrien  dreg = (ip->insn_opcode >> 11) & 0x1f;
4574179404Sobrien  sreg = breg = (ip->insn_opcode >> 21) & 0x1f;
4575179404Sobrien  mask = ip->insn_mo->mask;
4576179404Sobrien
4577179404Sobrien  expr1.X_op = O_constant;
4578179404Sobrien  expr1.X_op_symbol = NULL;
4579179404Sobrien  expr1.X_add_symbol = NULL;
4580179404Sobrien  expr1.X_add_number = 1;
4581179404Sobrien
4582179404Sobrien  switch (mask)
4583179404Sobrien    {
4584179404Sobrien    case M_DABS:
4585179404Sobrien      dbl = 1;
4586179404Sobrien    case M_ABS:
4587179404Sobrien      /* bgez $a0,.+12
4588179404Sobrien	 move v0,$a0
4589179404Sobrien	 sub v0,$zero,$a0
4590179404Sobrien	 */
4591179404Sobrien
4592208737Sjmallett      start_noreorder ();
4593179404Sobrien
4594179404Sobrien      expr1.X_add_number = 8;
4595179404Sobrien      macro_build (&expr1, "bgez", "s,p", sreg);
4596179404Sobrien      if (dreg == sreg)
4597179404Sobrien	macro_build (NULL, "nop", "", 0);
4598179404Sobrien      else
4599179404Sobrien	move_register (dreg, sreg);
4600179404Sobrien      macro_build (NULL, dbl ? "dsub" : "sub", "d,v,t", dreg, 0, sreg);
4601179404Sobrien
4602208737Sjmallett      end_noreorder ();
4603208737Sjmallett      break;
4604179404Sobrien
4605179404Sobrien    case M_ADD_I:
4606179404Sobrien      s = "addi";
4607179404Sobrien      s2 = "add";
4608179404Sobrien      goto do_addi;
4609179404Sobrien    case M_ADDU_I:
4610179404Sobrien      s = "addiu";
4611179404Sobrien      s2 = "addu";
4612179404Sobrien      goto do_addi;
4613179404Sobrien    case M_DADD_I:
4614179404Sobrien      dbl = 1;
4615179404Sobrien      s = "daddi";
4616179404Sobrien      s2 = "dadd";
4617179404Sobrien      goto do_addi;
4618179404Sobrien    case M_DADDU_I:
4619179404Sobrien      dbl = 1;
4620179404Sobrien      s = "daddiu";
4621179404Sobrien      s2 = "daddu";
4622179404Sobrien    do_addi:
4623179404Sobrien      if (imm_expr.X_op == O_constant
4624179404Sobrien	  && imm_expr.X_add_number >= -0x8000
4625179404Sobrien	  && imm_expr.X_add_number < 0x8000)
4626179404Sobrien	{
4627179404Sobrien	  macro_build (&imm_expr, s, "t,r,j", treg, sreg, BFD_RELOC_LO16);
4628208737Sjmallett	  break;
4629179404Sobrien	}
4630208737Sjmallett      used_at = 1;
4631179404Sobrien      load_register (AT, &imm_expr, dbl);
4632179404Sobrien      macro_build (NULL, s2, "d,v,t", treg, sreg, AT);
4633179404Sobrien      break;
4634179404Sobrien
4635179404Sobrien    case M_AND_I:
4636179404Sobrien      s = "andi";
4637179404Sobrien      s2 = "and";
4638179404Sobrien      goto do_bit;
4639179404Sobrien    case M_OR_I:
4640179404Sobrien      s = "ori";
4641179404Sobrien      s2 = "or";
4642179404Sobrien      goto do_bit;
4643179404Sobrien    case M_NOR_I:
4644179404Sobrien      s = "";
4645179404Sobrien      s2 = "nor";
4646179404Sobrien      goto do_bit;
4647179404Sobrien    case M_XOR_I:
4648179404Sobrien      s = "xori";
4649179404Sobrien      s2 = "xor";
4650179404Sobrien    do_bit:
4651179404Sobrien      if (imm_expr.X_op == O_constant
4652179404Sobrien	  && imm_expr.X_add_number >= 0
4653179404Sobrien	  && imm_expr.X_add_number < 0x10000)
4654179404Sobrien	{
4655179404Sobrien	  if (mask != M_NOR_I)
4656179404Sobrien	    macro_build (&imm_expr, s, "t,r,i", treg, sreg, BFD_RELOC_LO16);
4657179404Sobrien	  else
4658179404Sobrien	    {
4659179404Sobrien	      macro_build (&imm_expr, "ori", "t,r,i",
4660179404Sobrien			   treg, sreg, BFD_RELOC_LO16);
4661179404Sobrien	      macro_build (NULL, "nor", "d,v,t", treg, treg, 0);
4662179404Sobrien	    }
4663208737Sjmallett	  break;
4664179404Sobrien	}
4665179404Sobrien
4666208737Sjmallett      used_at = 1;
4667179404Sobrien      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
4668179404Sobrien      macro_build (NULL, s2, "d,v,t", treg, sreg, AT);
4669179404Sobrien      break;
4670179404Sobrien
4671218822Sdim    case M_BALIGN:
4672218822Sdim      switch (imm_expr.X_add_number)
4673218822Sdim	{
4674218822Sdim	case 0:
4675218822Sdim	  macro_build (NULL, "nop", "");
4676218822Sdim	  break;
4677218822Sdim	case 2:
4678218822Sdim	  macro_build (NULL, "packrl.ph", "d,s,t", treg, treg, sreg);
4679218822Sdim	  break;
4680218822Sdim	default:
4681218822Sdim	  macro_build (NULL, "balign", "t,s,2", treg, sreg,
4682218822Sdim		       (int)imm_expr.X_add_number);
4683218822Sdim	  break;
4684218822Sdim	}
4685218822Sdim      break;
4686218822Sdim
4687179404Sobrien    case M_BEQ_I:
4688179404Sobrien      s = "beq";
4689179404Sobrien      goto beq_i;
4690179404Sobrien    case M_BEQL_I:
4691179404Sobrien      s = "beql";
4692179404Sobrien      likely = 1;
4693179404Sobrien      goto beq_i;
4694179404Sobrien    case M_BNE_I:
4695179404Sobrien      s = "bne";
4696179404Sobrien      goto beq_i;
4697179404Sobrien    case M_BNEL_I:
4698179404Sobrien      s = "bnel";
4699179404Sobrien      likely = 1;
4700179404Sobrien    beq_i:
4701179404Sobrien      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
4702179404Sobrien	{
4703179404Sobrien	  macro_build (&offset_expr, s, "s,t,p", sreg, 0);
4704208737Sjmallett	  break;
4705179404Sobrien	}
4706208737Sjmallett      used_at = 1;
4707179404Sobrien      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
4708179404Sobrien      macro_build (&offset_expr, s, "s,t,p", sreg, AT);
4709179404Sobrien      break;
4710179404Sobrien
4711179404Sobrien    case M_BGEL:
4712179404Sobrien      likely = 1;
4713179404Sobrien    case M_BGE:
4714179404Sobrien      if (treg == 0)
4715179404Sobrien	{
4716179404Sobrien	  macro_build (&offset_expr, likely ? "bgezl" : "bgez", "s,p", sreg);
4717208737Sjmallett	  break;
4718179404Sobrien	}
4719179404Sobrien      if (sreg == 0)
4720179404Sobrien	{
4721179404Sobrien	  macro_build (&offset_expr, likely ? "blezl" : "blez", "s,p", treg);
4722208737Sjmallett	  break;
4723179404Sobrien	}
4724208737Sjmallett      used_at = 1;
4725179404Sobrien      macro_build (NULL, "slt", "d,v,t", AT, sreg, treg);
4726179404Sobrien      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
4727179404Sobrien      break;
4728179404Sobrien
4729179404Sobrien    case M_BGTL_I:
4730179404Sobrien      likely = 1;
4731179404Sobrien    case M_BGT_I:
4732179404Sobrien      /* check for > max integer */
4733179404Sobrien      maxnum = 0x7fffffff;
4734179404Sobrien      if (HAVE_64BIT_GPRS && sizeof (maxnum) > 4)
4735179404Sobrien	{
4736179404Sobrien	  maxnum <<= 16;
4737179404Sobrien	  maxnum |= 0xffff;
4738179404Sobrien	  maxnum <<= 16;
4739179404Sobrien	  maxnum |= 0xffff;
4740179404Sobrien	}
4741179404Sobrien      if (imm_expr.X_op == O_constant
4742179404Sobrien	  && imm_expr.X_add_number >= maxnum
4743179404Sobrien	  && (HAVE_32BIT_GPRS || sizeof (maxnum) > 4))
4744179404Sobrien	{
4745179404Sobrien	do_false:
4746179404Sobrien	  /* result is always false */
4747179404Sobrien	  if (! likely)
4748179404Sobrien	    macro_build (NULL, "nop", "", 0);
4749179404Sobrien	  else
4750179404Sobrien	    macro_build (&offset_expr, "bnel", "s,t,p", 0, 0);
4751208737Sjmallett	  break;
4752179404Sobrien	}
4753179404Sobrien      if (imm_expr.X_op != O_constant)
4754179404Sobrien	as_bad (_("Unsupported large constant"));
4755179404Sobrien      ++imm_expr.X_add_number;
4756179404Sobrien      /* FALLTHROUGH */
4757179404Sobrien    case M_BGE_I:
4758179404Sobrien    case M_BGEL_I:
4759179404Sobrien      if (mask == M_BGEL_I)
4760179404Sobrien	likely = 1;
4761179404Sobrien      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
4762179404Sobrien	{
4763179404Sobrien	  macro_build (&offset_expr, likely ? "bgezl" : "bgez", "s,p", sreg);
4764208737Sjmallett	  break;
4765179404Sobrien	}
4766179404Sobrien      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
4767179404Sobrien	{
4768179404Sobrien	  macro_build (&offset_expr, likely ? "bgtzl" : "bgtz", "s,p", sreg);
4769208737Sjmallett	  break;
4770179404Sobrien	}
4771179404Sobrien      maxnum = 0x7fffffff;
4772179404Sobrien      if (HAVE_64BIT_GPRS && sizeof (maxnum) > 4)
4773179404Sobrien	{
4774179404Sobrien	  maxnum <<= 16;
4775179404Sobrien	  maxnum |= 0xffff;
4776179404Sobrien	  maxnum <<= 16;
4777179404Sobrien	  maxnum |= 0xffff;
4778179404Sobrien	}
4779179404Sobrien      maxnum = - maxnum - 1;
4780179404Sobrien      if (imm_expr.X_op == O_constant
4781179404Sobrien	  && imm_expr.X_add_number <= maxnum
4782179404Sobrien	  && (HAVE_32BIT_GPRS || sizeof (maxnum) > 4))
4783179404Sobrien	{
4784179404Sobrien	do_true:
4785179404Sobrien	  /* result is always true */
4786179404Sobrien	  as_warn (_("Branch %s is always true"), ip->insn_mo->name);
4787179404Sobrien	  macro_build (&offset_expr, "b", "p");
4788208737Sjmallett	  break;
4789179404Sobrien	}
4790208737Sjmallett      used_at = 1;
4791179404Sobrien      set_at (sreg, 0);
4792179404Sobrien      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
4793179404Sobrien      break;
4794179404Sobrien
4795179404Sobrien    case M_BGEUL:
4796179404Sobrien      likely = 1;
4797179404Sobrien    case M_BGEU:
4798179404Sobrien      if (treg == 0)
4799179404Sobrien	goto do_true;
4800179404Sobrien      if (sreg == 0)
4801179404Sobrien	{
4802179404Sobrien	  macro_build (&offset_expr, likely ? "beql" : "beq",
4803179404Sobrien		       "s,t,p", 0, treg);
4804208737Sjmallett	  break;
4805179404Sobrien	}
4806208737Sjmallett      used_at = 1;
4807179404Sobrien      macro_build (NULL, "sltu", "d,v,t", AT, sreg, treg);
4808179404Sobrien      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
4809179404Sobrien      break;
4810179404Sobrien
4811179404Sobrien    case M_BGTUL_I:
4812179404Sobrien      likely = 1;
4813179404Sobrien    case M_BGTU_I:
4814179404Sobrien      if (sreg == 0
4815179404Sobrien	  || (HAVE_32BIT_GPRS
4816179404Sobrien	      && imm_expr.X_op == O_constant
4817179404Sobrien	      && imm_expr.X_add_number == (offsetT) 0xffffffff))
4818179404Sobrien	goto do_false;
4819179404Sobrien      if (imm_expr.X_op != O_constant)
4820179404Sobrien	as_bad (_("Unsupported large constant"));
4821179404Sobrien      ++imm_expr.X_add_number;
4822179404Sobrien      /* FALLTHROUGH */
4823179404Sobrien    case M_BGEU_I:
4824179404Sobrien    case M_BGEUL_I:
4825179404Sobrien      if (mask == M_BGEUL_I)
4826179404Sobrien	likely = 1;
4827179404Sobrien      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
4828179404Sobrien	goto do_true;
4829179404Sobrien      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
4830179404Sobrien	{
4831179404Sobrien	  macro_build (&offset_expr, likely ? "bnel" : "bne",
4832179404Sobrien		       "s,t,p", sreg, 0);
4833208737Sjmallett	  break;
4834179404Sobrien	}
4835208737Sjmallett      used_at = 1;
4836179404Sobrien      set_at (sreg, 1);
4837179404Sobrien      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
4838179404Sobrien      break;
4839179404Sobrien
4840179404Sobrien    case M_BGTL:
4841179404Sobrien      likely = 1;
4842179404Sobrien    case M_BGT:
4843179404Sobrien      if (treg == 0)
4844179404Sobrien	{
4845179404Sobrien	  macro_build (&offset_expr, likely ? "bgtzl" : "bgtz", "s,p", sreg);
4846208737Sjmallett	  break;
4847179404Sobrien	}
4848179404Sobrien      if (sreg == 0)
4849179404Sobrien	{
4850179404Sobrien	  macro_build (&offset_expr, likely ? "bltzl" : "bltz", "s,p", treg);
4851208737Sjmallett	  break;
4852179404Sobrien	}
4853208737Sjmallett      used_at = 1;
4854179404Sobrien      macro_build (NULL, "slt", "d,v,t", AT, treg, sreg);
4855179404Sobrien      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
4856179404Sobrien      break;
4857179404Sobrien
4858179404Sobrien    case M_BGTUL:
4859179404Sobrien      likely = 1;
4860179404Sobrien    case M_BGTU:
4861179404Sobrien      if (treg == 0)
4862179404Sobrien	{
4863179404Sobrien	  macro_build (&offset_expr, likely ? "bnel" : "bne",
4864179404Sobrien		       "s,t,p", sreg, 0);
4865208737Sjmallett	  break;
4866179404Sobrien	}
4867179404Sobrien      if (sreg == 0)
4868179404Sobrien	goto do_false;
4869208737Sjmallett      used_at = 1;
4870179404Sobrien      macro_build (NULL, "sltu", "d,v,t", AT, treg, sreg);
4871179404Sobrien      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
4872179404Sobrien      break;
4873179404Sobrien
4874179404Sobrien    case M_BLEL:
4875179404Sobrien      likely = 1;
4876179404Sobrien    case M_BLE:
4877179404Sobrien      if (treg == 0)
4878179404Sobrien	{
4879179404Sobrien	  macro_build (&offset_expr, likely ? "blezl" : "blez", "s,p", sreg);
4880208737Sjmallett	  break;
4881179404Sobrien	}
4882179404Sobrien      if (sreg == 0)
4883179404Sobrien	{
4884179404Sobrien	  macro_build (&offset_expr, likely ? "bgezl" : "bgez", "s,p", treg);
4885208737Sjmallett	  break;
4886179404Sobrien	}
4887208737Sjmallett      used_at = 1;
4888179404Sobrien      macro_build (NULL, "slt", "d,v,t", AT, treg, sreg);
4889179404Sobrien      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
4890179404Sobrien      break;
4891179404Sobrien
4892179404Sobrien    case M_BLEL_I:
4893179404Sobrien      likely = 1;
4894179404Sobrien    case M_BLE_I:
4895179404Sobrien      maxnum = 0x7fffffff;
4896179404Sobrien      if (HAVE_64BIT_GPRS && sizeof (maxnum) > 4)
4897179404Sobrien	{
4898179404Sobrien	  maxnum <<= 16;
4899179404Sobrien	  maxnum |= 0xffff;
4900179404Sobrien	  maxnum <<= 16;
4901179404Sobrien	  maxnum |= 0xffff;
4902179404Sobrien	}
4903179404Sobrien      if (imm_expr.X_op == O_constant
4904179404Sobrien	  && imm_expr.X_add_number >= maxnum
4905179404Sobrien	  && (HAVE_32BIT_GPRS || sizeof (maxnum) > 4))
4906179404Sobrien	goto do_true;
4907179404Sobrien      if (imm_expr.X_op != O_constant)
4908179404Sobrien	as_bad (_("Unsupported large constant"));
4909179404Sobrien      ++imm_expr.X_add_number;
4910179404Sobrien      /* FALLTHROUGH */
4911179404Sobrien    case M_BLT_I:
4912179404Sobrien    case M_BLTL_I:
4913179404Sobrien      if (mask == M_BLTL_I)
4914179404Sobrien	likely = 1;
4915179404Sobrien      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
4916179404Sobrien	{
4917179404Sobrien	  macro_build (&offset_expr, likely ? "bltzl" : "bltz", "s,p", sreg);
4918208737Sjmallett	  break;
4919179404Sobrien	}
4920179404Sobrien      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
4921179404Sobrien	{
4922179404Sobrien	  macro_build (&offset_expr, likely ? "blezl" : "blez", "s,p", sreg);
4923208737Sjmallett	  break;
4924179404Sobrien	}
4925208737Sjmallett      used_at = 1;
4926179404Sobrien      set_at (sreg, 0);
4927179404Sobrien      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
4928179404Sobrien      break;
4929179404Sobrien
4930179404Sobrien    case M_BLEUL:
4931179404Sobrien      likely = 1;
4932179404Sobrien    case M_BLEU:
4933179404Sobrien      if (treg == 0)
4934179404Sobrien	{
4935179404Sobrien	  macro_build (&offset_expr, likely ? "beql" : "beq",
4936179404Sobrien		       "s,t,p", sreg, 0);
4937208737Sjmallett	  break;
4938179404Sobrien	}
4939179404Sobrien      if (sreg == 0)
4940179404Sobrien	goto do_true;
4941208737Sjmallett      used_at = 1;
4942179404Sobrien      macro_build (NULL, "sltu", "d,v,t", AT, treg, sreg);
4943179404Sobrien      macro_build (&offset_expr, likely ? "beql" : "beq", "s,t,p", AT, 0);
4944179404Sobrien      break;
4945179404Sobrien
4946179404Sobrien    case M_BLEUL_I:
4947179404Sobrien      likely = 1;
4948179404Sobrien    case M_BLEU_I:
4949179404Sobrien      if (sreg == 0
4950179404Sobrien	  || (HAVE_32BIT_GPRS
4951179404Sobrien	      && imm_expr.X_op == O_constant
4952179404Sobrien	      && imm_expr.X_add_number == (offsetT) 0xffffffff))
4953179404Sobrien	goto do_true;
4954179404Sobrien      if (imm_expr.X_op != O_constant)
4955179404Sobrien	as_bad (_("Unsupported large constant"));
4956179404Sobrien      ++imm_expr.X_add_number;
4957179404Sobrien      /* FALLTHROUGH */
4958179404Sobrien    case M_BLTU_I:
4959179404Sobrien    case M_BLTUL_I:
4960179404Sobrien      if (mask == M_BLTUL_I)
4961179404Sobrien	likely = 1;
4962179404Sobrien      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
4963179404Sobrien	goto do_false;
4964179404Sobrien      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
4965179404Sobrien	{
4966179404Sobrien	  macro_build (&offset_expr, likely ? "beql" : "beq",
4967179404Sobrien		       "s,t,p", sreg, 0);
4968208737Sjmallett	  break;
4969179404Sobrien	}
4970208737Sjmallett      used_at = 1;
4971179404Sobrien      set_at (sreg, 1);
4972179404Sobrien      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
4973179404Sobrien      break;
4974179404Sobrien
4975179404Sobrien    case M_BLTL:
4976179404Sobrien      likely = 1;
4977179404Sobrien    case M_BLT:
4978179404Sobrien      if (treg == 0)
4979179404Sobrien	{
4980179404Sobrien	  macro_build (&offset_expr, likely ? "bltzl" : "bltz", "s,p", sreg);
4981208737Sjmallett	  break;
4982179404Sobrien	}
4983179404Sobrien      if (sreg == 0)
4984179404Sobrien	{
4985179404Sobrien	  macro_build (&offset_expr, likely ? "bgtzl" : "bgtz", "s,p", treg);
4986208737Sjmallett	  break;
4987179404Sobrien	}
4988208737Sjmallett      used_at = 1;
4989179404Sobrien      macro_build (NULL, "slt", "d,v,t", AT, sreg, treg);
4990179404Sobrien      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
4991179404Sobrien      break;
4992179404Sobrien
4993179404Sobrien    case M_BLTUL:
4994179404Sobrien      likely = 1;
4995179404Sobrien    case M_BLTU:
4996179404Sobrien      if (treg == 0)
4997179404Sobrien	goto do_false;
4998179404Sobrien      if (sreg == 0)
4999179404Sobrien	{
5000179404Sobrien	  macro_build (&offset_expr, likely ? "bnel" : "bne",
5001179404Sobrien		       "s,t,p", 0, treg);
5002208737Sjmallett	  break;
5003179404Sobrien	}
5004208737Sjmallett      used_at = 1;
5005179404Sobrien      macro_build (NULL, "sltu", "d,v,t", AT, sreg, treg);
5006179404Sobrien      macro_build (&offset_expr, likely ? "bnel" : "bne", "s,t,p", AT, 0);
5007179404Sobrien      break;
5008179404Sobrien
5009179404Sobrien    case M_DEXT:
5010179404Sobrien      {
5011179404Sobrien	unsigned long pos;
5012179404Sobrien	unsigned long size;
5013179404Sobrien
5014179404Sobrien        if (imm_expr.X_op != O_constant || imm2_expr.X_op != O_constant)
5015179404Sobrien	  {
5016179404Sobrien	    as_bad (_("Unsupported large constant"));
5017179404Sobrien	    pos = size = 1;
5018179404Sobrien	  }
5019179404Sobrien	else
5020179404Sobrien	  {
5021179404Sobrien	    pos = (unsigned long) imm_expr.X_add_number;
5022179404Sobrien	    size = (unsigned long) imm2_expr.X_add_number;
5023179404Sobrien	  }
5024179404Sobrien
5025179404Sobrien	if (pos > 63)
5026179404Sobrien	  {
5027179404Sobrien	    as_bad (_("Improper position (%lu)"), pos);
5028179404Sobrien	    pos = 1;
5029179404Sobrien	  }
5030179404Sobrien        if (size == 0 || size > 64
5031179404Sobrien	    || (pos + size - 1) > 63)
5032179404Sobrien	  {
5033179404Sobrien	    as_bad (_("Improper extract size (%lu, position %lu)"),
5034179404Sobrien		    size, pos);
5035179404Sobrien	    size = 1;
5036179404Sobrien	  }
5037179404Sobrien
5038179404Sobrien	if (size <= 32 && pos < 32)
5039179404Sobrien	  {
5040179404Sobrien	    s = "dext";
5041179404Sobrien	    fmt = "t,r,+A,+C";
5042179404Sobrien	  }
5043179404Sobrien	else if (size <= 32)
5044179404Sobrien	  {
5045179404Sobrien	    s = "dextu";
5046179404Sobrien	    fmt = "t,r,+E,+H";
5047179404Sobrien	  }
5048179404Sobrien	else
5049179404Sobrien	  {
5050179404Sobrien	    s = "dextm";
5051179404Sobrien	    fmt = "t,r,+A,+G";
5052179404Sobrien	  }
5053179404Sobrien	macro_build ((expressionS *) NULL, s, fmt, treg, sreg, pos, size - 1);
5054179404Sobrien      }
5055208737Sjmallett      break;
5056179404Sobrien
5057179404Sobrien    case M_DINS:
5058179404Sobrien      {
5059179404Sobrien	unsigned long pos;
5060179404Sobrien	unsigned long size;
5061179404Sobrien
5062179404Sobrien        if (imm_expr.X_op != O_constant || imm2_expr.X_op != O_constant)
5063179404Sobrien	  {
5064179404Sobrien	    as_bad (_("Unsupported large constant"));
5065179404Sobrien	    pos = size = 1;
5066179404Sobrien	  }
5067179404Sobrien	else
5068179404Sobrien	  {
5069179404Sobrien	    pos = (unsigned long) imm_expr.X_add_number;
5070179404Sobrien	    size = (unsigned long) imm2_expr.X_add_number;
5071179404Sobrien	  }
5072179404Sobrien
5073179404Sobrien	if (pos > 63)
5074179404Sobrien	  {
5075179404Sobrien	    as_bad (_("Improper position (%lu)"), pos);
5076179404Sobrien	    pos = 1;
5077179404Sobrien	  }
5078179404Sobrien        if (size == 0 || size > 64
5079179404Sobrien	    || (pos + size - 1) > 63)
5080179404Sobrien	  {
5081179404Sobrien	    as_bad (_("Improper insert size (%lu, position %lu)"),
5082179404Sobrien		    size, pos);
5083179404Sobrien	    size = 1;
5084179404Sobrien	  }
5085179404Sobrien
5086179404Sobrien	if (pos < 32 && (pos + size - 1) < 32)
5087179404Sobrien	  {
5088179404Sobrien	    s = "dins";
5089179404Sobrien	    fmt = "t,r,+A,+B";
5090179404Sobrien	  }
5091179404Sobrien	else if (pos >= 32)
5092179404Sobrien	  {
5093179404Sobrien	    s = "dinsu";
5094179404Sobrien	    fmt = "t,r,+E,+F";
5095179404Sobrien	  }
5096179404Sobrien	else
5097179404Sobrien	  {
5098179404Sobrien	    s = "dinsm";
5099179404Sobrien	    fmt = "t,r,+A,+F";
5100179404Sobrien	  }
5101179404Sobrien	macro_build ((expressionS *) NULL, s, fmt, treg, sreg, pos,
5102179404Sobrien		     pos + size - 1);
5103179404Sobrien      }
5104208737Sjmallett      break;
5105179404Sobrien
5106179404Sobrien    case M_DDIV_3:
5107179404Sobrien      dbl = 1;
5108179404Sobrien    case M_DIV_3:
5109179404Sobrien      s = "mflo";
5110179404Sobrien      goto do_div3;
5111179404Sobrien    case M_DREM_3:
5112179404Sobrien      dbl = 1;
5113179404Sobrien    case M_REM_3:
5114179404Sobrien      s = "mfhi";
5115179404Sobrien    do_div3:
5116179404Sobrien      if (treg == 0)
5117179404Sobrien	{
5118179404Sobrien	  as_warn (_("Divide by zero."));
5119179404Sobrien	  if (mips_trap)
5120179404Sobrien	    macro_build (NULL, "teq", "s,t,q", 0, 0, 7);
5121179404Sobrien	  else
5122179404Sobrien	    macro_build (NULL, "break", "c", 7);
5123208737Sjmallett	  break;
5124179404Sobrien	}
5125179404Sobrien
5126208737Sjmallett      start_noreorder ();
5127179404Sobrien      if (mips_trap)
5128179404Sobrien	{
5129179404Sobrien	  macro_build (NULL, "teq", "s,t,q", treg, 0, 7);
5130179404Sobrien	  macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
5131179404Sobrien	}
5132179404Sobrien      else
5133179404Sobrien	{
5134179404Sobrien	  expr1.X_add_number = 8;
5135179404Sobrien	  macro_build (&expr1, "bne", "s,t,p", treg, 0);
5136179404Sobrien	  macro_build (NULL, dbl ? "ddiv" : "div", "z,s,t", sreg, treg);
5137179404Sobrien	  macro_build (NULL, "break", "c", 7);
5138179404Sobrien	}
5139179404Sobrien      expr1.X_add_number = -1;
5140208737Sjmallett      used_at = 1;
5141179404Sobrien      load_register (AT, &expr1, dbl);
5142179404Sobrien      expr1.X_add_number = mips_trap ? (dbl ? 12 : 8) : (dbl ? 20 : 16);
5143179404Sobrien      macro_build (&expr1, "bne", "s,t,p", treg, AT);
5144179404Sobrien      if (dbl)
5145179404Sobrien	{
5146179404Sobrien	  expr1.X_add_number = 1;
5147179404Sobrien	  load_register (AT, &expr1, dbl);
5148179404Sobrien	  macro_build (NULL, "dsll32", "d,w,<", AT, AT, 31);
5149179404Sobrien	}
5150179404Sobrien      else
5151179404Sobrien	{
5152179404Sobrien	  expr1.X_add_number = 0x80000000;
5153179404Sobrien	  macro_build (&expr1, "lui", "t,u", AT, BFD_RELOC_HI16);
5154179404Sobrien	}
5155179404Sobrien      if (mips_trap)
5156179404Sobrien	{
5157179404Sobrien	  macro_build (NULL, "teq", "s,t,q", sreg, AT, 6);
5158179404Sobrien	  /* We want to close the noreorder block as soon as possible, so
5159179404Sobrien	     that later insns are available for delay slot filling.  */
5160208737Sjmallett	  end_noreorder ();
5161179404Sobrien	}
5162179404Sobrien      else
5163179404Sobrien	{
5164179404Sobrien	  expr1.X_add_number = 8;
5165179404Sobrien	  macro_build (&expr1, "bne", "s,t,p", sreg, AT);
5166179404Sobrien	  macro_build (NULL, "nop", "", 0);
5167179404Sobrien
5168179404Sobrien	  /* We want to close the noreorder block as soon as possible, so
5169179404Sobrien	     that later insns are available for delay slot filling.  */
5170208737Sjmallett	  end_noreorder ();
5171179404Sobrien
5172179404Sobrien	  macro_build (NULL, "break", "c", 6);
5173179404Sobrien	}
5174179404Sobrien      macro_build (NULL, s, "d", dreg);
5175179404Sobrien      break;
5176179404Sobrien
5177179404Sobrien    case M_DIV_3I:
5178179404Sobrien      s = "div";
5179179404Sobrien      s2 = "mflo";
5180179404Sobrien      goto do_divi;
5181179404Sobrien    case M_DIVU_3I:
5182179404Sobrien      s = "divu";
5183179404Sobrien      s2 = "mflo";
5184179404Sobrien      goto do_divi;
5185179404Sobrien    case M_REM_3I:
5186179404Sobrien      s = "div";
5187179404Sobrien      s2 = "mfhi";
5188179404Sobrien      goto do_divi;
5189179404Sobrien    case M_REMU_3I:
5190179404Sobrien      s = "divu";
5191179404Sobrien      s2 = "mfhi";
5192179404Sobrien      goto do_divi;
5193179404Sobrien    case M_DDIV_3I:
5194179404Sobrien      dbl = 1;
5195179404Sobrien      s = "ddiv";
5196179404Sobrien      s2 = "mflo";
5197179404Sobrien      goto do_divi;
5198179404Sobrien    case M_DDIVU_3I:
5199179404Sobrien      dbl = 1;
5200179404Sobrien      s = "ddivu";
5201179404Sobrien      s2 = "mflo";
5202179404Sobrien      goto do_divi;
5203179404Sobrien    case M_DREM_3I:
5204179404Sobrien      dbl = 1;
5205179404Sobrien      s = "ddiv";
5206179404Sobrien      s2 = "mfhi";
5207179404Sobrien      goto do_divi;
5208179404Sobrien    case M_DREMU_3I:
5209179404Sobrien      dbl = 1;
5210179404Sobrien      s = "ddivu";
5211179404Sobrien      s2 = "mfhi";
5212179404Sobrien    do_divi:
5213179404Sobrien      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
5214179404Sobrien	{
5215179404Sobrien	  as_warn (_("Divide by zero."));
5216179404Sobrien	  if (mips_trap)
5217179404Sobrien	    macro_build (NULL, "teq", "s,t,q", 0, 0, 7);
5218179404Sobrien	  else
5219179404Sobrien	    macro_build (NULL, "break", "c", 7);
5220208737Sjmallett	  break;
5221179404Sobrien	}
5222179404Sobrien      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 1)
5223179404Sobrien	{
5224179404Sobrien	  if (strcmp (s2, "mflo") == 0)
5225179404Sobrien	    move_register (dreg, sreg);
5226179404Sobrien	  else
5227179404Sobrien	    move_register (dreg, 0);
5228208737Sjmallett	  break;
5229179404Sobrien	}
5230179404Sobrien      if (imm_expr.X_op == O_constant
5231179404Sobrien	  && imm_expr.X_add_number == -1
5232179404Sobrien	  && s[strlen (s) - 1] != 'u')
5233179404Sobrien	{
5234179404Sobrien	  if (strcmp (s2, "mflo") == 0)
5235179404Sobrien	    {
5236179404Sobrien	      macro_build (NULL, dbl ? "dneg" : "neg", "d,w", dreg, sreg);
5237179404Sobrien	    }
5238179404Sobrien	  else
5239179404Sobrien	    move_register (dreg, 0);
5240208737Sjmallett	  break;
5241179404Sobrien	}
5242179404Sobrien
5243208737Sjmallett      used_at = 1;
5244179404Sobrien      load_register (AT, &imm_expr, dbl);
5245179404Sobrien      macro_build (NULL, s, "z,s,t", sreg, AT);
5246179404Sobrien      macro_build (NULL, s2, "d", dreg);
5247179404Sobrien      break;
5248179404Sobrien
5249179404Sobrien    case M_DIVU_3:
5250179404Sobrien      s = "divu";
5251179404Sobrien      s2 = "mflo";
5252179404Sobrien      goto do_divu3;
5253179404Sobrien    case M_REMU_3:
5254179404Sobrien      s = "divu";
5255179404Sobrien      s2 = "mfhi";
5256179404Sobrien      goto do_divu3;
5257179404Sobrien    case M_DDIVU_3:
5258179404Sobrien      s = "ddivu";
5259179404Sobrien      s2 = "mflo";
5260179404Sobrien      goto do_divu3;
5261179404Sobrien    case M_DREMU_3:
5262179404Sobrien      s = "ddivu";
5263179404Sobrien      s2 = "mfhi";
5264179404Sobrien    do_divu3:
5265208737Sjmallett      start_noreorder ();
5266179404Sobrien      if (mips_trap)
5267179404Sobrien	{
5268179404Sobrien	  macro_build (NULL, "teq", "s,t,q", treg, 0, 7);
5269179404Sobrien	  macro_build (NULL, s, "z,s,t", sreg, treg);
5270179404Sobrien	  /* We want to close the noreorder block as soon as possible, so
5271179404Sobrien	     that later insns are available for delay slot filling.  */
5272208737Sjmallett	  end_noreorder ();
5273179404Sobrien	}
5274179404Sobrien      else
5275179404Sobrien	{
5276179404Sobrien	  expr1.X_add_number = 8;
5277179404Sobrien	  macro_build (&expr1, "bne", "s,t,p", treg, 0);
5278179404Sobrien	  macro_build (NULL, s, "z,s,t", sreg, treg);
5279179404Sobrien
5280179404Sobrien	  /* We want to close the noreorder block as soon as possible, so
5281179404Sobrien	     that later insns are available for delay slot filling.  */
5282208737Sjmallett	  end_noreorder ();
5283179404Sobrien	  macro_build (NULL, "break", "c", 7);
5284179404Sobrien	}
5285179404Sobrien      macro_build (NULL, s2, "d", dreg);
5286208737Sjmallett      break;
5287179404Sobrien
5288179404Sobrien    case M_DLCA_AB:
5289179404Sobrien      dbl = 1;
5290179404Sobrien    case M_LCA_AB:
5291179404Sobrien      call = 1;
5292179404Sobrien      goto do_la;
5293179404Sobrien    case M_DLA_AB:
5294179404Sobrien      dbl = 1;
5295179404Sobrien    case M_LA_AB:
5296179404Sobrien    do_la:
5297179404Sobrien      /* Load the address of a symbol into a register.  If breg is not
5298179404Sobrien	 zero, we then add a base register to it.  */
5299179404Sobrien
5300179404Sobrien      if (dbl && HAVE_32BIT_GPRS)
5301179404Sobrien	as_warn (_("dla used to load 32-bit register"));
5302179404Sobrien
5303179404Sobrien      if (! dbl && HAVE_64BIT_OBJECTS)
5304179404Sobrien	as_warn (_("la used to load 64-bit address"));
5305179404Sobrien
5306179404Sobrien      if (offset_expr.X_op == O_constant
5307179404Sobrien	  && offset_expr.X_add_number >= -0x8000
5308179404Sobrien	  && offset_expr.X_add_number < 0x8000)
5309179404Sobrien	{
5310208737Sjmallett	  macro_build (&offset_expr, ADDRESS_ADDI_INSN,
5311179404Sobrien		       "t,r,j", treg, sreg, BFD_RELOC_LO16);
5312208737Sjmallett	  break;
5313179404Sobrien	}
5314179404Sobrien
5315208737Sjmallett      if (!mips_opts.noat && (treg == breg))
5316179404Sobrien	{
5317179404Sobrien	  tempreg = AT;
5318179404Sobrien	  used_at = 1;
5319179404Sobrien	}
5320179404Sobrien      else
5321179404Sobrien	{
5322179404Sobrien	  tempreg = treg;
5323179404Sobrien	}
5324179404Sobrien
5325179404Sobrien      if (offset_expr.X_op != O_symbol
5326179404Sobrien	  && offset_expr.X_op != O_constant)
5327179404Sobrien	{
5328179404Sobrien	  as_bad (_("expression too complex"));
5329179404Sobrien	  offset_expr.X_op = O_constant;
5330179404Sobrien	}
5331179404Sobrien
5332179404Sobrien      if (offset_expr.X_op == O_constant)
5333208737Sjmallett	load_register (tempreg, &offset_expr, HAVE_64BIT_ADDRESSES);
5334179404Sobrien      else if (mips_pic == NO_PIC)
5335179404Sobrien	{
5336179404Sobrien	  /* If this is a reference to a GP relative symbol, we want
5337179404Sobrien	       addiu	$tempreg,$gp,<sym>	(BFD_RELOC_GPREL16)
5338179404Sobrien	     Otherwise we want
5339179404Sobrien	       lui	$tempreg,<sym>		(BFD_RELOC_HI16_S)
5340179404Sobrien	       addiu	$tempreg,$tempreg,<sym>	(BFD_RELOC_LO16)
5341179404Sobrien	     If we have a constant, we need two instructions anyhow,
5342179404Sobrien	     so we may as well always use the latter form.
5343179404Sobrien
5344208737Sjmallett	     With 64bit address space and a usable $at we want
5345208737Sjmallett	       lui	$tempreg,<sym>		(BFD_RELOC_MIPS_HIGHEST)
5346208737Sjmallett	       lui	$at,<sym>		(BFD_RELOC_HI16_S)
5347208737Sjmallett	       daddiu	$tempreg,<sym>		(BFD_RELOC_MIPS_HIGHER)
5348208737Sjmallett	       daddiu	$at,<sym>		(BFD_RELOC_LO16)
5349208737Sjmallett	       dsll32	$tempreg,0
5350208737Sjmallett	       daddu	$tempreg,$tempreg,$at
5351179404Sobrien
5352208737Sjmallett	     If $at is already in use, we use a path which is suboptimal
5353208737Sjmallett	     on superscalar processors.
5354208737Sjmallett	       lui	$tempreg,<sym>		(BFD_RELOC_MIPS_HIGHEST)
5355208737Sjmallett	       daddiu	$tempreg,<sym>		(BFD_RELOC_MIPS_HIGHER)
5356208737Sjmallett	       dsll	$tempreg,16
5357208737Sjmallett	       daddiu	$tempreg,<sym>		(BFD_RELOC_HI16_S)
5358208737Sjmallett	       dsll	$tempreg,16
5359208737Sjmallett	       daddiu	$tempreg,<sym>		(BFD_RELOC_LO16)
5360208737Sjmallett
5361208737Sjmallett	     For GP relative symbols in 64bit address space we can use
5362208737Sjmallett	     the same sequence as in 32bit address space.  */
5363208737Sjmallett	  if (HAVE_64BIT_SYMBOLS)
5364179404Sobrien	    {
5365208737Sjmallett	      if ((valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET
5366208737Sjmallett		  && !nopic_need_relax (offset_expr.X_add_symbol, 1))
5367208737Sjmallett		{
5368208737Sjmallett		  relax_start (offset_expr.X_add_symbol);
5369208737Sjmallett		  macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
5370208737Sjmallett			       tempreg, mips_gp_register, BFD_RELOC_GPREL16);
5371208737Sjmallett		  relax_switch ();
5372208737Sjmallett		}
5373179404Sobrien
5374208737Sjmallett	      if (used_at == 0 && !mips_opts.noat)
5375179404Sobrien		{
5376179404Sobrien		  macro_build (&offset_expr, "lui", "t,u",
5377179404Sobrien			       tempreg, BFD_RELOC_MIPS_HIGHEST);
5378179404Sobrien		  macro_build (&offset_expr, "lui", "t,u",
5379179404Sobrien			       AT, BFD_RELOC_HI16_S);
5380179404Sobrien		  macro_build (&offset_expr, "daddiu", "t,r,j",
5381179404Sobrien			       tempreg, tempreg, BFD_RELOC_MIPS_HIGHER);
5382179404Sobrien		  macro_build (&offset_expr, "daddiu", "t,r,j",
5383179404Sobrien			       AT, AT, BFD_RELOC_LO16);
5384179404Sobrien		  macro_build (NULL, "dsll32", "d,w,<", tempreg, tempreg, 0);
5385179404Sobrien		  macro_build (NULL, "daddu", "d,v,t", tempreg, tempreg, AT);
5386179404Sobrien		  used_at = 1;
5387179404Sobrien		}
5388179404Sobrien	      else
5389179404Sobrien		{
5390179404Sobrien		  macro_build (&offset_expr, "lui", "t,u",
5391179404Sobrien			       tempreg, BFD_RELOC_MIPS_HIGHEST);
5392179404Sobrien		  macro_build (&offset_expr, "daddiu", "t,r,j",
5393179404Sobrien			       tempreg, tempreg, BFD_RELOC_MIPS_HIGHER);
5394179404Sobrien		  macro_build (NULL, "dsll", "d,w,<", tempreg, tempreg, 16);
5395179404Sobrien		  macro_build (&offset_expr, "daddiu", "t,r,j",
5396179404Sobrien			       tempreg, tempreg, BFD_RELOC_HI16_S);
5397179404Sobrien		  macro_build (NULL, "dsll", "d,w,<", tempreg, tempreg, 16);
5398179404Sobrien		  macro_build (&offset_expr, "daddiu", "t,r,j",
5399179404Sobrien			       tempreg, tempreg, BFD_RELOC_LO16);
5400179404Sobrien		}
5401208737Sjmallett
5402208737Sjmallett	      if (mips_relax.sequence)
5403208737Sjmallett		relax_end ();
5404179404Sobrien	    }
5405179404Sobrien	  else
5406179404Sobrien	    {
5407179404Sobrien	      if ((valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET
5408208737Sjmallett		  && !nopic_need_relax (offset_expr.X_add_symbol, 1))
5409179404Sobrien		{
5410179404Sobrien		  relax_start (offset_expr.X_add_symbol);
5411179404Sobrien		  macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
5412179404Sobrien			       tempreg, mips_gp_register, BFD_RELOC_GPREL16);
5413179404Sobrien		  relax_switch ();
5414179404Sobrien		}
5415208737Sjmallett	      if (!IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
5416208737Sjmallett		as_bad (_("offset too large"));
5417179404Sobrien	      macro_build_lui (&offset_expr, tempreg);
5418179404Sobrien	      macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
5419179404Sobrien			   tempreg, tempreg, BFD_RELOC_LO16);
5420179404Sobrien	      if (mips_relax.sequence)
5421179404Sobrien		relax_end ();
5422179404Sobrien	    }
5423179404Sobrien	}
5424208737Sjmallett      else if (!mips_big_got && !HAVE_NEWABI)
5425179404Sobrien	{
5426179404Sobrien	  int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT16;
5427179404Sobrien
5428179404Sobrien	  /* If this is a reference to an external symbol, and there
5429179404Sobrien	     is no constant, we want
5430179404Sobrien	       lw	$tempreg,<sym>($gp)	(BFD_RELOC_MIPS_GOT16)
5431179404Sobrien	     or for lca or if tempreg is PIC_CALL_REG
5432179404Sobrien	       lw	$tempreg,<sym>($gp)	(BFD_RELOC_MIPS_CALL16)
5433179404Sobrien	     For a local symbol, we want
5434179404Sobrien	       lw	$tempreg,<sym>($gp)	(BFD_RELOC_MIPS_GOT16)
5435179404Sobrien	       nop
5436179404Sobrien	       addiu	$tempreg,$tempreg,<sym>	(BFD_RELOC_LO16)
5437179404Sobrien
5438179404Sobrien	     If we have a small constant, and this is a reference to
5439179404Sobrien	     an external symbol, we want
5440179404Sobrien	       lw	$tempreg,<sym>($gp)	(BFD_RELOC_MIPS_GOT16)
5441179404Sobrien	       nop
5442179404Sobrien	       addiu	$tempreg,$tempreg,<constant>
5443179404Sobrien	     For a local symbol, we want the same instruction
5444179404Sobrien	     sequence, but we output a BFD_RELOC_LO16 reloc on the
5445179404Sobrien	     addiu instruction.
5446179404Sobrien
5447179404Sobrien	     If we have a large constant, and this is a reference to
5448179404Sobrien	     an external symbol, we want
5449179404Sobrien	       lw	$tempreg,<sym>($gp)	(BFD_RELOC_MIPS_GOT16)
5450179404Sobrien	       lui	$at,<hiconstant>
5451179404Sobrien	       addiu	$at,$at,<loconstant>
5452179404Sobrien	       addu	$tempreg,$tempreg,$at
5453179404Sobrien	     For a local symbol, we want the same instruction
5454179404Sobrien	     sequence, but we output a BFD_RELOC_LO16 reloc on the
5455179404Sobrien	     addiu instruction.
5456179404Sobrien	   */
5457179404Sobrien
5458179404Sobrien	  if (offset_expr.X_add_number == 0)
5459179404Sobrien	    {
5460208737Sjmallett	      if (mips_pic == SVR4_PIC
5461208737Sjmallett		  && breg == 0
5462208737Sjmallett		  && (call || tempreg == PIC_CALL_REG))
5463179404Sobrien		lw_reloc_type = (int) BFD_RELOC_MIPS_CALL16;
5464179404Sobrien
5465179404Sobrien	      relax_start (offset_expr.X_add_symbol);
5466179404Sobrien	      macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
5467179404Sobrien			   lw_reloc_type, mips_gp_register);
5468179404Sobrien	      if (breg != 0)
5469179404Sobrien		{
5470179404Sobrien		  /* We're going to put in an addu instruction using
5471179404Sobrien		     tempreg, so we may as well insert the nop right
5472179404Sobrien		     now.  */
5473208737Sjmallett		  load_delay_nop ();
5474179404Sobrien		}
5475179404Sobrien	      relax_switch ();
5476179404Sobrien	      macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
5477179404Sobrien			   tempreg, BFD_RELOC_MIPS_GOT16, mips_gp_register);
5478208737Sjmallett	      load_delay_nop ();
5479179404Sobrien	      macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
5480179404Sobrien			   tempreg, tempreg, BFD_RELOC_LO16);
5481179404Sobrien	      relax_end ();
5482179404Sobrien	      /* FIXME: If breg == 0, and the next instruction uses
5483179404Sobrien		 $tempreg, then if this variant case is used an extra
5484179404Sobrien		 nop will be generated.  */
5485179404Sobrien	    }
5486179404Sobrien	  else if (offset_expr.X_add_number >= -0x8000
5487179404Sobrien		   && offset_expr.X_add_number < 0x8000)
5488179404Sobrien	    {
5489179404Sobrien	      load_got_offset (tempreg, &offset_expr);
5490208737Sjmallett	      load_delay_nop ();
5491179404Sobrien	      add_got_offset (tempreg, &offset_expr);
5492179404Sobrien	    }
5493179404Sobrien	  else
5494179404Sobrien	    {
5495179404Sobrien	      expr1.X_add_number = offset_expr.X_add_number;
5496179404Sobrien	      offset_expr.X_add_number =
5497179404Sobrien		((offset_expr.X_add_number + 0x8000) & 0xffff) - 0x8000;
5498179404Sobrien	      load_got_offset (tempreg, &offset_expr);
5499179404Sobrien	      offset_expr.X_add_number = expr1.X_add_number;
5500179404Sobrien	      /* If we are going to add in a base register, and the
5501179404Sobrien		 target register and the base register are the same,
5502179404Sobrien		 then we are using AT as a temporary register.  Since
5503179404Sobrien		 we want to load the constant into AT, we add our
5504179404Sobrien		 current AT (from the global offset table) and the
5505179404Sobrien		 register into the register now, and pretend we were
5506179404Sobrien		 not using a base register.  */
5507179404Sobrien	      if (breg == treg)
5508179404Sobrien		{
5509208737Sjmallett		  load_delay_nop ();
5510179404Sobrien		  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
5511179404Sobrien			       treg, AT, breg);
5512179404Sobrien		  breg = 0;
5513179404Sobrien		  tempreg = treg;
5514179404Sobrien		}
5515179404Sobrien	      add_got_offset_hilo (tempreg, &offset_expr, AT);
5516179404Sobrien	      used_at = 1;
5517179404Sobrien	    }
5518179404Sobrien	}
5519208737Sjmallett      else if (!mips_big_got && HAVE_NEWABI)
5520179404Sobrien	{
5521179404Sobrien	  int add_breg_early = 0;
5522179404Sobrien
5523179404Sobrien	  /* If this is a reference to an external, and there is no
5524179404Sobrien	     constant, or local symbol (*), with or without a
5525179404Sobrien	     constant, we want
5526179404Sobrien	       lw	$tempreg,<sym>($gp)	(BFD_RELOC_MIPS_GOT_DISP)
5527179404Sobrien	     or for lca or if tempreg is PIC_CALL_REG
5528179404Sobrien	       lw	$tempreg,<sym>($gp)	(BFD_RELOC_MIPS_CALL16)
5529179404Sobrien
5530179404Sobrien	     If we have a small constant, and this is a reference to
5531179404Sobrien	     an external symbol, we want
5532179404Sobrien	       lw	$tempreg,<sym>($gp)	(BFD_RELOC_MIPS_GOT_DISP)
5533179404Sobrien	       addiu	$tempreg,$tempreg,<constant>
5534179404Sobrien
5535179404Sobrien	     If we have a large constant, and this is a reference to
5536179404Sobrien	     an external symbol, we want
5537179404Sobrien	       lw	$tempreg,<sym>($gp)	(BFD_RELOC_MIPS_GOT_DISP)
5538179404Sobrien	       lui	$at,<hiconstant>
5539179404Sobrien	       addiu	$at,$at,<loconstant>
5540179404Sobrien	       addu	$tempreg,$tempreg,$at
5541179404Sobrien
5542179404Sobrien	     (*) Other assemblers seem to prefer GOT_PAGE/GOT_OFST for
5543179404Sobrien	     local symbols, even though it introduces an additional
5544179404Sobrien	     instruction.  */
5545179404Sobrien
5546179404Sobrien	  if (offset_expr.X_add_number)
5547179404Sobrien	    {
5548179404Sobrien	      expr1.X_add_number = offset_expr.X_add_number;
5549179404Sobrien	      offset_expr.X_add_number = 0;
5550179404Sobrien
5551179404Sobrien	      relax_start (offset_expr.X_add_symbol);
5552179404Sobrien	      macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
5553179404Sobrien			   BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
5554179404Sobrien
5555179404Sobrien	      if (expr1.X_add_number >= -0x8000
5556179404Sobrien		  && expr1.X_add_number < 0x8000)
5557179404Sobrien		{
5558179404Sobrien		  macro_build (&expr1, ADDRESS_ADDI_INSN, "t,r,j",
5559179404Sobrien			       tempreg, tempreg, BFD_RELOC_LO16);
5560179404Sobrien		}
5561179404Sobrien	      else if (IS_SEXT_32BIT_NUM (expr1.X_add_number + 0x8000))
5562179404Sobrien		{
5563179404Sobrien		  int dreg;
5564179404Sobrien
5565179404Sobrien		  /* If we are going to add in a base register, and the
5566179404Sobrien		     target register and the base register are the same,
5567179404Sobrien		     then we are using AT as a temporary register.  Since
5568179404Sobrien		     we want to load the constant into AT, we add our
5569179404Sobrien		     current AT (from the global offset table) and the
5570179404Sobrien		     register into the register now, and pretend we were
5571179404Sobrien		     not using a base register.  */
5572179404Sobrien		  if (breg != treg)
5573179404Sobrien		    dreg = tempreg;
5574179404Sobrien		  else
5575179404Sobrien		    {
5576179404Sobrien		      assert (tempreg == AT);
5577179404Sobrien		      macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
5578179404Sobrien				   treg, AT, breg);
5579179404Sobrien		      dreg = treg;
5580179404Sobrien		      add_breg_early = 1;
5581179404Sobrien		    }
5582179404Sobrien
5583179404Sobrien		  load_register (AT, &expr1, HAVE_64BIT_ADDRESSES);
5584179404Sobrien		  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
5585179404Sobrien			       dreg, dreg, AT);
5586179404Sobrien
5587179404Sobrien		  used_at = 1;
5588179404Sobrien		}
5589179404Sobrien	      else
5590179404Sobrien		as_bad (_("PIC code offset overflow (max 32 signed bits)"));
5591179404Sobrien
5592179404Sobrien	      relax_switch ();
5593179404Sobrien	      offset_expr.X_add_number = expr1.X_add_number;
5594179404Sobrien
5595179404Sobrien	      macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
5596179404Sobrien			   BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
5597179404Sobrien	      if (add_breg_early)
5598179404Sobrien		{
5599179404Sobrien		  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
5600179404Sobrien			       treg, tempreg, breg);
5601179404Sobrien		  breg = 0;
5602179404Sobrien		  tempreg = treg;
5603179404Sobrien		}
5604179404Sobrien	      relax_end ();
5605179404Sobrien	    }
5606179404Sobrien	  else if (breg == 0 && (call || tempreg == PIC_CALL_REG))
5607179404Sobrien	    {
5608179404Sobrien	      relax_start (offset_expr.X_add_symbol);
5609179404Sobrien	      macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
5610179404Sobrien			   BFD_RELOC_MIPS_CALL16, mips_gp_register);
5611179404Sobrien	      relax_switch ();
5612179404Sobrien	      macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
5613179404Sobrien			   BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
5614179404Sobrien	      relax_end ();
5615179404Sobrien	    }
5616179404Sobrien	  else
5617179404Sobrien	    {
5618179404Sobrien	      macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
5619179404Sobrien			   BFD_RELOC_MIPS_GOT_DISP, mips_gp_register);
5620179404Sobrien	    }
5621179404Sobrien	}
5622208737Sjmallett      else if (mips_big_got && !HAVE_NEWABI)
5623179404Sobrien	{
5624179404Sobrien	  int gpdelay;
5625179404Sobrien	  int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16;
5626179404Sobrien	  int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16;
5627179404Sobrien	  int local_reloc_type = (int) BFD_RELOC_MIPS_GOT16;
5628179404Sobrien
5629179404Sobrien	  /* This is the large GOT case.  If this is a reference to an
5630179404Sobrien	     external symbol, and there is no constant, we want
5631179404Sobrien	       lui	$tempreg,<sym>		(BFD_RELOC_MIPS_GOT_HI16)
5632179404Sobrien	       addu	$tempreg,$tempreg,$gp
5633179404Sobrien	       lw	$tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
5634179404Sobrien	     or for lca or if tempreg is PIC_CALL_REG
5635179404Sobrien	       lui	$tempreg,<sym>		(BFD_RELOC_MIPS_CALL_HI16)
5636179404Sobrien	       addu	$tempreg,$tempreg,$gp
5637179404Sobrien	       lw	$tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_CALL_LO16)
5638179404Sobrien	     For a local symbol, we want
5639179404Sobrien	       lw	$tempreg,<sym>($gp)	(BFD_RELOC_MIPS_GOT16)
5640179404Sobrien	       nop
5641179404Sobrien	       addiu	$tempreg,$tempreg,<sym>	(BFD_RELOC_LO16)
5642179404Sobrien
5643179404Sobrien	     If we have a small constant, and this is a reference to
5644179404Sobrien	     an external symbol, we want
5645179404Sobrien	       lui	$tempreg,<sym>		(BFD_RELOC_MIPS_GOT_HI16)
5646179404Sobrien	       addu	$tempreg,$tempreg,$gp
5647179404Sobrien	       lw	$tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
5648179404Sobrien	       nop
5649179404Sobrien	       addiu	$tempreg,$tempreg,<constant>
5650179404Sobrien	     For a local symbol, we want
5651179404Sobrien	       lw	$tempreg,<sym>($gp)	(BFD_RELOC_MIPS_GOT16)
5652179404Sobrien	       nop
5653179404Sobrien	       addiu	$tempreg,$tempreg,<constant> (BFD_RELOC_LO16)
5654179404Sobrien
5655179404Sobrien	     If we have a large constant, and this is a reference to
5656179404Sobrien	     an external symbol, we want
5657179404Sobrien	       lui	$tempreg,<sym>		(BFD_RELOC_MIPS_GOT_HI16)
5658179404Sobrien	       addu	$tempreg,$tempreg,$gp
5659179404Sobrien	       lw	$tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
5660179404Sobrien	       lui	$at,<hiconstant>
5661179404Sobrien	       addiu	$at,$at,<loconstant>
5662179404Sobrien	       addu	$tempreg,$tempreg,$at
5663179404Sobrien	     For a local symbol, we want
5664179404Sobrien	       lw	$tempreg,<sym>($gp)	(BFD_RELOC_MIPS_GOT16)
5665179404Sobrien	       lui	$at,<hiconstant>
5666179404Sobrien	       addiu	$at,$at,<loconstant>	(BFD_RELOC_LO16)
5667179404Sobrien	       addu	$tempreg,$tempreg,$at
5668179404Sobrien	  */
5669179404Sobrien
5670179404Sobrien	  expr1.X_add_number = offset_expr.X_add_number;
5671179404Sobrien	  offset_expr.X_add_number = 0;
5672179404Sobrien	  relax_start (offset_expr.X_add_symbol);
5673179404Sobrien	  gpdelay = reg_needs_delay (mips_gp_register);
5674179404Sobrien	  if (expr1.X_add_number == 0 && breg == 0
5675179404Sobrien	      && (call || tempreg == PIC_CALL_REG))
5676179404Sobrien	    {
5677179404Sobrien	      lui_reloc_type = (int) BFD_RELOC_MIPS_CALL_HI16;
5678179404Sobrien	      lw_reloc_type = (int) BFD_RELOC_MIPS_CALL_LO16;
5679179404Sobrien	    }
5680179404Sobrien	  macro_build (&offset_expr, "lui", "t,u", tempreg, lui_reloc_type);
5681179404Sobrien	  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
5682179404Sobrien		       tempreg, tempreg, mips_gp_register);
5683179404Sobrien	  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
5684179404Sobrien		       tempreg, lw_reloc_type, tempreg);
5685179404Sobrien	  if (expr1.X_add_number == 0)
5686179404Sobrien	    {
5687179404Sobrien	      if (breg != 0)
5688179404Sobrien		{
5689179404Sobrien		  /* We're going to put in an addu instruction using
5690179404Sobrien		     tempreg, so we may as well insert the nop right
5691179404Sobrien		     now.  */
5692208737Sjmallett		  load_delay_nop ();
5693179404Sobrien		}
5694179404Sobrien	    }
5695179404Sobrien	  else if (expr1.X_add_number >= -0x8000
5696179404Sobrien		   && expr1.X_add_number < 0x8000)
5697179404Sobrien	    {
5698208737Sjmallett	      load_delay_nop ();
5699179404Sobrien	      macro_build (&expr1, ADDRESS_ADDI_INSN, "t,r,j",
5700179404Sobrien			   tempreg, tempreg, BFD_RELOC_LO16);
5701179404Sobrien	    }
5702179404Sobrien	  else
5703179404Sobrien	    {
5704179404Sobrien	      int dreg;
5705179404Sobrien
5706179404Sobrien	      /* If we are going to add in a base register, and the
5707179404Sobrien		 target register and the base register are the same,
5708179404Sobrien		 then we are using AT as a temporary register.  Since
5709179404Sobrien		 we want to load the constant into AT, we add our
5710179404Sobrien		 current AT (from the global offset table) and the
5711179404Sobrien		 register into the register now, and pretend we were
5712179404Sobrien		 not using a base register.  */
5713179404Sobrien	      if (breg != treg)
5714179404Sobrien		dreg = tempreg;
5715179404Sobrien	      else
5716179404Sobrien		{
5717179404Sobrien		  assert (tempreg == AT);
5718208737Sjmallett		  load_delay_nop ();
5719179404Sobrien		  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
5720179404Sobrien			       treg, AT, breg);
5721179404Sobrien		  dreg = treg;
5722179404Sobrien		}
5723179404Sobrien
5724179404Sobrien	      load_register (AT, &expr1, HAVE_64BIT_ADDRESSES);
5725179404Sobrien	      macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", dreg, dreg, AT);
5726179404Sobrien
5727179404Sobrien	      used_at = 1;
5728179404Sobrien	    }
5729179404Sobrien	  offset_expr.X_add_number =
5730179404Sobrien	    ((expr1.X_add_number + 0x8000) & 0xffff) - 0x8000;
5731179404Sobrien	  relax_switch ();
5732179404Sobrien
5733179404Sobrien	  if (gpdelay)
5734179404Sobrien	    {
5735179404Sobrien	      /* This is needed because this instruction uses $gp, but
5736179404Sobrien		 the first instruction on the main stream does not.  */
5737179404Sobrien	      macro_build (NULL, "nop", "");
5738179404Sobrien	    }
5739179404Sobrien
5740179404Sobrien	  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
5741179404Sobrien		       local_reloc_type, mips_gp_register);
5742179404Sobrien	  if (expr1.X_add_number >= -0x8000
5743179404Sobrien	      && expr1.X_add_number < 0x8000)
5744179404Sobrien	    {
5745208737Sjmallett	      load_delay_nop ();
5746179404Sobrien	      macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
5747179404Sobrien			   tempreg, tempreg, BFD_RELOC_LO16);
5748179404Sobrien	      /* FIXME: If add_number is 0, and there was no base
5749179404Sobrien		 register, the external symbol case ended with a load,
5750179404Sobrien		 so if the symbol turns out to not be external, and
5751179404Sobrien		 the next instruction uses tempreg, an unnecessary nop
5752179404Sobrien		 will be inserted.  */
5753179404Sobrien	    }
5754179404Sobrien	  else
5755179404Sobrien	    {
5756179404Sobrien	      if (breg == treg)
5757179404Sobrien		{
5758179404Sobrien		  /* We must add in the base register now, as in the
5759179404Sobrien		     external symbol case.  */
5760179404Sobrien		  assert (tempreg == AT);
5761208737Sjmallett		  load_delay_nop ();
5762179404Sobrien		  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
5763179404Sobrien			       treg, AT, breg);
5764179404Sobrien		  tempreg = treg;
5765179404Sobrien		  /* We set breg to 0 because we have arranged to add
5766179404Sobrien		     it in in both cases.  */
5767179404Sobrien		  breg = 0;
5768179404Sobrien		}
5769179404Sobrien
5770179404Sobrien	      macro_build_lui (&expr1, AT);
5771179404Sobrien	      macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
5772179404Sobrien			   AT, AT, BFD_RELOC_LO16);
5773179404Sobrien	      macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
5774179404Sobrien			   tempreg, tempreg, AT);
5775208737Sjmallett	      used_at = 1;
5776179404Sobrien	    }
5777179404Sobrien	  relax_end ();
5778179404Sobrien	}
5779208737Sjmallett      else if (mips_big_got && HAVE_NEWABI)
5780179404Sobrien	{
5781179404Sobrien	  int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16;
5782179404Sobrien	  int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16;
5783179404Sobrien	  int add_breg_early = 0;
5784179404Sobrien
5785179404Sobrien	  /* This is the large GOT case.  If this is a reference to an
5786179404Sobrien	     external symbol, and there is no constant, we want
5787179404Sobrien	       lui	$tempreg,<sym>		(BFD_RELOC_MIPS_GOT_HI16)
5788179404Sobrien	       add	$tempreg,$tempreg,$gp
5789179404Sobrien	       lw	$tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
5790179404Sobrien	     or for lca or if tempreg is PIC_CALL_REG
5791179404Sobrien	       lui	$tempreg,<sym>		(BFD_RELOC_MIPS_CALL_HI16)
5792179404Sobrien	       add	$tempreg,$tempreg,$gp
5793179404Sobrien	       lw	$tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_CALL_LO16)
5794179404Sobrien
5795179404Sobrien	     If we have a small constant, and this is a reference to
5796179404Sobrien	     an external symbol, we want
5797179404Sobrien	       lui	$tempreg,<sym>		(BFD_RELOC_MIPS_GOT_HI16)
5798179404Sobrien	       add	$tempreg,$tempreg,$gp
5799179404Sobrien	       lw	$tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
5800179404Sobrien	       addi	$tempreg,$tempreg,<constant>
5801179404Sobrien
5802179404Sobrien	     If we have a large constant, and this is a reference to
5803179404Sobrien	     an external symbol, we want
5804179404Sobrien	       lui	$tempreg,<sym>		(BFD_RELOC_MIPS_GOT_HI16)
5805179404Sobrien	       addu	$tempreg,$tempreg,$gp
5806179404Sobrien	       lw	$tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
5807179404Sobrien	       lui	$at,<hiconstant>
5808179404Sobrien	       addi	$at,$at,<loconstant>
5809179404Sobrien	       add	$tempreg,$tempreg,$at
5810179404Sobrien
5811179404Sobrien	     If we have NewABI, and we know it's a local symbol, we want
5812179404Sobrien	       lw	$reg,<sym>($gp)		(BFD_RELOC_MIPS_GOT_PAGE)
5813179404Sobrien	       addiu	$reg,$reg,<sym>		(BFD_RELOC_MIPS_GOT_OFST)
5814179404Sobrien	     otherwise we have to resort to GOT_HI16/GOT_LO16.  */
5815179404Sobrien
5816179404Sobrien	  relax_start (offset_expr.X_add_symbol);
5817179404Sobrien
5818179404Sobrien	  expr1.X_add_number = offset_expr.X_add_number;
5819179404Sobrien	  offset_expr.X_add_number = 0;
5820179404Sobrien
5821179404Sobrien	  if (expr1.X_add_number == 0 && breg == 0
5822179404Sobrien	      && (call || tempreg == PIC_CALL_REG))
5823179404Sobrien	    {
5824179404Sobrien	      lui_reloc_type = (int) BFD_RELOC_MIPS_CALL_HI16;
5825179404Sobrien	      lw_reloc_type = (int) BFD_RELOC_MIPS_CALL_LO16;
5826179404Sobrien	    }
5827179404Sobrien	  macro_build (&offset_expr, "lui", "t,u", tempreg, lui_reloc_type);
5828179404Sobrien	  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
5829179404Sobrien		       tempreg, tempreg, mips_gp_register);
5830179404Sobrien	  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
5831179404Sobrien		       tempreg, lw_reloc_type, tempreg);
5832179404Sobrien
5833179404Sobrien	  if (expr1.X_add_number == 0)
5834179404Sobrien	    ;
5835179404Sobrien	  else if (expr1.X_add_number >= -0x8000
5836179404Sobrien		   && expr1.X_add_number < 0x8000)
5837179404Sobrien	    {
5838179404Sobrien	      macro_build (&expr1, ADDRESS_ADDI_INSN, "t,r,j",
5839179404Sobrien			   tempreg, tempreg, BFD_RELOC_LO16);
5840179404Sobrien	    }
5841179404Sobrien	  else if (IS_SEXT_32BIT_NUM (expr1.X_add_number + 0x8000))
5842179404Sobrien	    {
5843179404Sobrien	      int dreg;
5844179404Sobrien
5845179404Sobrien	      /* If we are going to add in a base register, and the
5846179404Sobrien		 target register and the base register are the same,
5847179404Sobrien		 then we are using AT as a temporary register.  Since
5848179404Sobrien		 we want to load the constant into AT, we add our
5849179404Sobrien		 current AT (from the global offset table) and the
5850179404Sobrien		 register into the register now, and pretend we were
5851179404Sobrien		 not using a base register.  */
5852179404Sobrien	      if (breg != treg)
5853179404Sobrien		dreg = tempreg;
5854179404Sobrien	      else
5855179404Sobrien		{
5856179404Sobrien		  assert (tempreg == AT);
5857179404Sobrien		  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
5858179404Sobrien			       treg, AT, breg);
5859179404Sobrien		  dreg = treg;
5860179404Sobrien		  add_breg_early = 1;
5861179404Sobrien		}
5862179404Sobrien
5863179404Sobrien	      load_register (AT, &expr1, HAVE_64BIT_ADDRESSES);
5864179404Sobrien	      macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", dreg, dreg, AT);
5865179404Sobrien
5866179404Sobrien	      used_at = 1;
5867179404Sobrien	    }
5868179404Sobrien	  else
5869179404Sobrien	    as_bad (_("PIC code offset overflow (max 32 signed bits)"));
5870179404Sobrien
5871179404Sobrien	  relax_switch ();
5872179404Sobrien	  offset_expr.X_add_number = expr1.X_add_number;
5873179404Sobrien	  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
5874179404Sobrien		       BFD_RELOC_MIPS_GOT_PAGE, mips_gp_register);
5875179404Sobrien	  macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", tempreg,
5876179404Sobrien		       tempreg, BFD_RELOC_MIPS_GOT_OFST);
5877179404Sobrien	  if (add_breg_early)
5878179404Sobrien	    {
5879179404Sobrien	      macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
5880179404Sobrien			   treg, tempreg, breg);
5881179404Sobrien	      breg = 0;
5882179404Sobrien	      tempreg = treg;
5883179404Sobrien	    }
5884179404Sobrien	  relax_end ();
5885179404Sobrien	}
5886179404Sobrien      else
5887179404Sobrien	abort ();
5888179404Sobrien
5889179404Sobrien      if (breg != 0)
5890208737Sjmallett	macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", treg, tempreg, breg);
5891179404Sobrien      break;
5892179404Sobrien
5893179404Sobrien    case M_J_A:
5894179404Sobrien      /* The j instruction may not be used in PIC code, since it
5895179404Sobrien	 requires an absolute address.  We convert it to a b
5896179404Sobrien	 instruction.  */
5897179404Sobrien      if (mips_pic == NO_PIC)
5898179404Sobrien	macro_build (&offset_expr, "j", "a");
5899179404Sobrien      else
5900179404Sobrien	macro_build (&offset_expr, "b", "p");
5901208737Sjmallett      break;
5902179404Sobrien
5903179404Sobrien      /* The jal instructions must be handled as macros because when
5904179404Sobrien	 generating PIC code they expand to multi-instruction
5905179404Sobrien	 sequences.  Normally they are simple instructions.  */
5906179404Sobrien    case M_JAL_1:
5907179404Sobrien      dreg = RA;
5908179404Sobrien      /* Fall through.  */
5909179404Sobrien    case M_JAL_2:
5910208737Sjmallett      if (mips_pic == NO_PIC)
5911179404Sobrien	macro_build (NULL, "jalr", "d,s", dreg, sreg);
5912208737Sjmallett      else
5913179404Sobrien	{
5914179404Sobrien	  if (sreg != PIC_CALL_REG)
5915179404Sobrien	    as_warn (_("MIPS PIC call to register other than $25"));
5916179404Sobrien
5917179404Sobrien	  macro_build (NULL, "jalr", "d,s", dreg, sreg);
5918208737Sjmallett	  if (mips_pic == SVR4_PIC && !HAVE_NEWABI)
5919179404Sobrien	    {
5920179404Sobrien	      if (mips_cprestore_offset < 0)
5921179404Sobrien		as_warn (_("No .cprestore pseudo-op used in PIC code"));
5922179404Sobrien	      else
5923179404Sobrien		{
5924179404Sobrien		  if (! mips_frame_reg_valid)
5925179404Sobrien		    {
5926179404Sobrien		      as_warn (_("No .frame pseudo-op used in PIC code"));
5927179404Sobrien		      /* Quiet this warning.  */
5928179404Sobrien		      mips_frame_reg_valid = 1;
5929179404Sobrien		    }
5930179404Sobrien		  if (! mips_cprestore_valid)
5931179404Sobrien		    {
5932179404Sobrien		      as_warn (_("No .cprestore pseudo-op used in PIC code"));
5933179404Sobrien		      /* Quiet this warning.  */
5934179404Sobrien		      mips_cprestore_valid = 1;
5935179404Sobrien		    }
5936179404Sobrien		  expr1.X_add_number = mips_cprestore_offset;
5937179404Sobrien  		  macro_build_ldst_constoffset (&expr1, ADDRESS_LOAD_INSN,
5938179404Sobrien						mips_gp_register,
5939179404Sobrien						mips_frame_reg,
5940179404Sobrien						HAVE_64BIT_ADDRESSES);
5941179404Sobrien		}
5942179404Sobrien	    }
5943179404Sobrien	}
5944179404Sobrien
5945208737Sjmallett      break;
5946179404Sobrien
5947179404Sobrien    case M_JAL_A:
5948179404Sobrien      if (mips_pic == NO_PIC)
5949179404Sobrien	macro_build (&offset_expr, "jal", "a");
5950179404Sobrien      else if (mips_pic == SVR4_PIC)
5951179404Sobrien	{
5952179404Sobrien	  /* If this is a reference to an external symbol, and we are
5953179404Sobrien	     using a small GOT, we want
5954179404Sobrien	       lw	$25,<sym>($gp)		(BFD_RELOC_MIPS_CALL16)
5955179404Sobrien	       nop
5956179404Sobrien	       jalr	$ra,$25
5957179404Sobrien	       nop
5958179404Sobrien	       lw	$gp,cprestore($sp)
5959179404Sobrien	     The cprestore value is set using the .cprestore
5960179404Sobrien	     pseudo-op.  If we are using a big GOT, we want
5961179404Sobrien	       lui	$25,<sym>		(BFD_RELOC_MIPS_CALL_HI16)
5962179404Sobrien	       addu	$25,$25,$gp
5963179404Sobrien	       lw	$25,<sym>($25)		(BFD_RELOC_MIPS_CALL_LO16)
5964179404Sobrien	       nop
5965179404Sobrien	       jalr	$ra,$25
5966179404Sobrien	       nop
5967179404Sobrien	       lw	$gp,cprestore($sp)
5968179404Sobrien	     If the symbol is not external, we want
5969179404Sobrien	       lw	$25,<sym>($gp)		(BFD_RELOC_MIPS_GOT16)
5970179404Sobrien	       nop
5971179404Sobrien	       addiu	$25,$25,<sym>		(BFD_RELOC_LO16)
5972179404Sobrien	       jalr	$ra,$25
5973179404Sobrien	       nop
5974179404Sobrien	       lw $gp,cprestore($sp)
5975179404Sobrien
5976179404Sobrien	     For NewABI, we use the same CALL16 or CALL_HI16/CALL_LO16
5977179404Sobrien	     sequences above, minus nops, unless the symbol is local,
5978179404Sobrien	     which enables us to use GOT_PAGE/GOT_OFST (big got) or
5979179404Sobrien	     GOT_DISP.  */
5980179404Sobrien	  if (HAVE_NEWABI)
5981179404Sobrien	    {
5982179404Sobrien	      if (! mips_big_got)
5983179404Sobrien		{
5984179404Sobrien		  relax_start (offset_expr.X_add_symbol);
5985179404Sobrien		  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
5986179404Sobrien			       PIC_CALL_REG, BFD_RELOC_MIPS_CALL16,
5987179404Sobrien			       mips_gp_register);
5988179404Sobrien		  relax_switch ();
5989179404Sobrien		  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
5990179404Sobrien			       PIC_CALL_REG, BFD_RELOC_MIPS_GOT_DISP,
5991179404Sobrien			       mips_gp_register);
5992179404Sobrien		  relax_end ();
5993179404Sobrien		}
5994179404Sobrien	      else
5995179404Sobrien		{
5996179404Sobrien		  relax_start (offset_expr.X_add_symbol);
5997179404Sobrien		  macro_build (&offset_expr, "lui", "t,u", PIC_CALL_REG,
5998179404Sobrien			       BFD_RELOC_MIPS_CALL_HI16);
5999179404Sobrien		  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", PIC_CALL_REG,
6000179404Sobrien			       PIC_CALL_REG, mips_gp_register);
6001179404Sobrien		  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
6002179404Sobrien			       PIC_CALL_REG, BFD_RELOC_MIPS_CALL_LO16,
6003179404Sobrien			       PIC_CALL_REG);
6004179404Sobrien		  relax_switch ();
6005179404Sobrien		  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
6006179404Sobrien			       PIC_CALL_REG, BFD_RELOC_MIPS_GOT_PAGE,
6007179404Sobrien			       mips_gp_register);
6008179404Sobrien		  macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
6009179404Sobrien			       PIC_CALL_REG, PIC_CALL_REG,
6010179404Sobrien			       BFD_RELOC_MIPS_GOT_OFST);
6011179404Sobrien		  relax_end ();
6012179404Sobrien		}
6013179404Sobrien
6014179404Sobrien	      macro_build_jalr (&offset_expr);
6015179404Sobrien	    }
6016179404Sobrien	  else
6017179404Sobrien	    {
6018179404Sobrien	      relax_start (offset_expr.X_add_symbol);
6019179404Sobrien	      if (! mips_big_got)
6020179404Sobrien		{
6021179404Sobrien		  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
6022179404Sobrien			       PIC_CALL_REG, BFD_RELOC_MIPS_CALL16,
6023179404Sobrien			       mips_gp_register);
6024208737Sjmallett		  load_delay_nop ();
6025179404Sobrien		  relax_switch ();
6026179404Sobrien		}
6027179404Sobrien	      else
6028179404Sobrien		{
6029179404Sobrien		  int gpdelay;
6030179404Sobrien
6031179404Sobrien		  gpdelay = reg_needs_delay (mips_gp_register);
6032179404Sobrien		  macro_build (&offset_expr, "lui", "t,u", PIC_CALL_REG,
6033179404Sobrien			       BFD_RELOC_MIPS_CALL_HI16);
6034179404Sobrien		  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", PIC_CALL_REG,
6035179404Sobrien			       PIC_CALL_REG, mips_gp_register);
6036179404Sobrien		  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
6037179404Sobrien			       PIC_CALL_REG, BFD_RELOC_MIPS_CALL_LO16,
6038179404Sobrien			       PIC_CALL_REG);
6039208737Sjmallett		  load_delay_nop ();
6040179404Sobrien		  relax_switch ();
6041179404Sobrien		  if (gpdelay)
6042179404Sobrien		    macro_build (NULL, "nop", "");
6043179404Sobrien		}
6044179404Sobrien	      macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
6045179404Sobrien			   PIC_CALL_REG, BFD_RELOC_MIPS_GOT16,
6046179404Sobrien			   mips_gp_register);
6047208737Sjmallett	      load_delay_nop ();
6048179404Sobrien	      macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j",
6049179404Sobrien			   PIC_CALL_REG, PIC_CALL_REG, BFD_RELOC_LO16);
6050179404Sobrien	      relax_end ();
6051179404Sobrien	      macro_build_jalr (&offset_expr);
6052179404Sobrien
6053179404Sobrien	      if (mips_cprestore_offset < 0)
6054179404Sobrien		as_warn (_("No .cprestore pseudo-op used in PIC code"));
6055179404Sobrien	      else
6056179404Sobrien		{
6057179404Sobrien		  if (! mips_frame_reg_valid)
6058179404Sobrien		    {
6059179404Sobrien		      as_warn (_("No .frame pseudo-op used in PIC code"));
6060179404Sobrien		      /* Quiet this warning.  */
6061179404Sobrien		      mips_frame_reg_valid = 1;
6062179404Sobrien		    }
6063179404Sobrien		  if (! mips_cprestore_valid)
6064179404Sobrien		    {
6065179404Sobrien		      as_warn (_("No .cprestore pseudo-op used in PIC code"));
6066179404Sobrien		      /* Quiet this warning.  */
6067179404Sobrien		      mips_cprestore_valid = 1;
6068179404Sobrien		    }
6069179404Sobrien		  if (mips_opts.noreorder)
6070179404Sobrien		    macro_build (NULL, "nop", "");
6071179404Sobrien		  expr1.X_add_number = mips_cprestore_offset;
6072179404Sobrien  		  macro_build_ldst_constoffset (&expr1, ADDRESS_LOAD_INSN,
6073179404Sobrien						mips_gp_register,
6074179404Sobrien						mips_frame_reg,
6075179404Sobrien						HAVE_64BIT_ADDRESSES);
6076179404Sobrien		}
6077179404Sobrien	    }
6078179404Sobrien	}
6079218822Sdim      else if (mips_pic == VXWORKS_PIC)
6080218822Sdim	as_bad (_("Non-PIC jump used in PIC library"));
6081179404Sobrien      else
6082179404Sobrien	abort ();
6083179404Sobrien
6084208737Sjmallett      break;
6085179404Sobrien
6086179404Sobrien    case M_LB_AB:
6087179404Sobrien      s = "lb";
6088179404Sobrien      goto ld;
6089179404Sobrien    case M_LBU_AB:
6090179404Sobrien      s = "lbu";
6091179404Sobrien      goto ld;
6092179404Sobrien    case M_LH_AB:
6093179404Sobrien      s = "lh";
6094179404Sobrien      goto ld;
6095179404Sobrien    case M_LHU_AB:
6096179404Sobrien      s = "lhu";
6097179404Sobrien      goto ld;
6098179404Sobrien    case M_LW_AB:
6099179404Sobrien      s = "lw";
6100179404Sobrien      goto ld;
6101179404Sobrien    case M_LWC0_AB:
6102179404Sobrien      s = "lwc0";
6103179404Sobrien      /* Itbl support may require additional care here.  */
6104179404Sobrien      coproc = 1;
6105179404Sobrien      goto ld;
6106179404Sobrien    case M_LWC1_AB:
6107179404Sobrien      s = "lwc1";
6108179404Sobrien      /* Itbl support may require additional care here.  */
6109179404Sobrien      coproc = 1;
6110179404Sobrien      goto ld;
6111179404Sobrien    case M_LWC2_AB:
6112179404Sobrien      s = "lwc2";
6113179404Sobrien      /* Itbl support may require additional care here.  */
6114179404Sobrien      coproc = 1;
6115179404Sobrien      goto ld;
6116179404Sobrien    case M_LWC3_AB:
6117179404Sobrien      s = "lwc3";
6118179404Sobrien      /* Itbl support may require additional care here.  */
6119179404Sobrien      coproc = 1;
6120179404Sobrien      goto ld;
6121179404Sobrien    case M_LWL_AB:
6122179404Sobrien      s = "lwl";
6123179404Sobrien      lr = 1;
6124179404Sobrien      goto ld;
6125179404Sobrien    case M_LWR_AB:
6126179404Sobrien      s = "lwr";
6127179404Sobrien      lr = 1;
6128179404Sobrien      goto ld;
6129179404Sobrien    case M_LDC1_AB:
6130179404Sobrien      if (mips_opts.arch == CPU_R4650)
6131179404Sobrien	{
6132179404Sobrien	  as_bad (_("opcode not supported on this processor"));
6133208737Sjmallett	  break;
6134179404Sobrien	}
6135179404Sobrien      s = "ldc1";
6136179404Sobrien      /* Itbl support may require additional care here.  */
6137179404Sobrien      coproc = 1;
6138179404Sobrien      goto ld;
6139179404Sobrien    case M_LDC2_AB:
6140179404Sobrien      s = "ldc2";
6141179404Sobrien      /* Itbl support may require additional care here.  */
6142179404Sobrien      coproc = 1;
6143179404Sobrien      goto ld;
6144179404Sobrien    case M_LDC3_AB:
6145179404Sobrien      s = "ldc3";
6146179404Sobrien      /* Itbl support may require additional care here.  */
6147179404Sobrien      coproc = 1;
6148179404Sobrien      goto ld;
6149179404Sobrien    case M_LDL_AB:
6150179404Sobrien      s = "ldl";
6151179404Sobrien      lr = 1;
6152179404Sobrien      goto ld;
6153179404Sobrien    case M_LDR_AB:
6154179404Sobrien      s = "ldr";
6155179404Sobrien      lr = 1;
6156179404Sobrien      goto ld;
6157179404Sobrien    case M_LL_AB:
6158179404Sobrien      s = "ll";
6159179404Sobrien      goto ld;
6160179404Sobrien    case M_LLD_AB:
6161179404Sobrien      s = "lld";
6162179404Sobrien      goto ld;
6163179404Sobrien    case M_LWU_AB:
6164179404Sobrien      s = "lwu";
6165179404Sobrien    ld:
6166208737Sjmallett      if (mips_opts.arch == CPU_OCTEON
6167208737Sjmallett	   && octeon_error_on_unsupported
6168208737Sjmallett           && (mask == M_LDC1_AB || mask == M_LDC2_AB || mask == M_LDC3_AB
6169208737Sjmallett               || mask == M_L_DOB || mask == M_L_DAB
6170208737Sjmallett               || mask == M_LI_D || mask == M_LI_DD
6171208737Sjmallett               || mask == M_LI_S || mask == M_LI_SS))
6172208737Sjmallett        {
6173208737Sjmallett          as_bad (_("opcode not implemented in Octeon `%s'"), ip->insn_mo->name);
6174208737Sjmallett          return;
6175208737Sjmallett        }
6176179404Sobrien      if (breg == treg || coproc || lr)
6177179404Sobrien	{
6178179404Sobrien	  tempreg = AT;
6179179404Sobrien	  used_at = 1;
6180179404Sobrien	}
6181179404Sobrien      else
6182179404Sobrien	{
6183179404Sobrien	  tempreg = treg;
6184179404Sobrien	}
6185179404Sobrien      goto ld_st;
6186179404Sobrien    case M_SB_AB:
6187179404Sobrien      s = "sb";
6188179404Sobrien      goto st;
6189179404Sobrien    case M_SH_AB:
6190179404Sobrien      s = "sh";
6191179404Sobrien      goto st;
6192179404Sobrien    case M_SW_AB:
6193179404Sobrien      s = "sw";
6194179404Sobrien      goto st;
6195179404Sobrien    case M_SWC0_AB:
6196179404Sobrien      s = "swc0";
6197179404Sobrien      /* Itbl support may require additional care here.  */
6198179404Sobrien      coproc = 1;
6199179404Sobrien      goto st;
6200179404Sobrien    case M_SWC1_AB:
6201179404Sobrien      s = "swc1";
6202179404Sobrien      /* Itbl support may require additional care here.  */
6203179404Sobrien      coproc = 1;
6204179404Sobrien      goto st;
6205179404Sobrien    case M_SWC2_AB:
6206179404Sobrien      s = "swc2";
6207179404Sobrien      /* Itbl support may require additional care here.  */
6208179404Sobrien      coproc = 1;
6209179404Sobrien      goto st;
6210179404Sobrien    case M_SWC3_AB:
6211179404Sobrien      s = "swc3";
6212179404Sobrien      /* Itbl support may require additional care here.  */
6213179404Sobrien      coproc = 1;
6214179404Sobrien      goto st;
6215179404Sobrien    case M_SWL_AB:
6216179404Sobrien      s = "swl";
6217179404Sobrien      goto st;
6218179404Sobrien    case M_SWR_AB:
6219179404Sobrien      s = "swr";
6220179404Sobrien      goto st;
6221179404Sobrien    case M_SC_AB:
6222179404Sobrien      s = "sc";
6223179404Sobrien      goto st;
6224179404Sobrien    case M_SCD_AB:
6225179404Sobrien      s = "scd";
6226179404Sobrien      goto st;
6227218822Sdim    case M_CACHE_AB:
6228218822Sdim      s = "cache";
6229218822Sdim      goto st;
6230179404Sobrien    case M_SDC1_AB:
6231179404Sobrien      if (mips_opts.arch == CPU_R4650)
6232179404Sobrien	{
6233179404Sobrien	  as_bad (_("opcode not supported on this processor"));
6234208737Sjmallett	  break;
6235179404Sobrien	}
6236179404Sobrien      s = "sdc1";
6237179404Sobrien      coproc = 1;
6238179404Sobrien      /* Itbl support may require additional care here.  */
6239179404Sobrien      goto st;
6240179404Sobrien    case M_SDC2_AB:
6241179404Sobrien      s = "sdc2";
6242179404Sobrien      /* Itbl support may require additional care here.  */
6243179404Sobrien      coproc = 1;
6244179404Sobrien      goto st;
6245179404Sobrien    case M_SDC3_AB:
6246179404Sobrien      s = "sdc3";
6247179404Sobrien      /* Itbl support may require additional care here.  */
6248179404Sobrien      coproc = 1;
6249179404Sobrien      goto st;
6250179404Sobrien    case M_SDL_AB:
6251179404Sobrien      s = "sdl";
6252179404Sobrien      goto st;
6253179404Sobrien    case M_SDR_AB:
6254179404Sobrien      s = "sdr";
6255179404Sobrien    st:
6256208737Sjmallett      if (mips_opts.arch == CPU_OCTEON
6257208737Sjmallett	  && octeon_error_on_unsupported
6258208737Sjmallett          && (mask == M_SWC0_AB || mask == M_SWC1_AB || mask == M_SWC2_AB
6259208737Sjmallett              || mask == M_SDC1_AB || mask == M_SDC2_AB || mask == M_SDC3_AB
6260208737Sjmallett              || mask == M_S_DAB || mask == M_S_DOB))
6261208737Sjmallett        {
6262208737Sjmallett          as_bad (_("opcode not implemented in Octeon `%s'"), ip->insn_mo->name);
6263208737Sjmallett          return;
6264208737Sjmallett        }
6265179404Sobrien      tempreg = AT;
6266179404Sobrien      used_at = 1;
6267179404Sobrien    ld_st:
6268179404Sobrien      /* Itbl support may require additional care here.  */
6269179404Sobrien      if (mask == M_LWC1_AB
6270179404Sobrien	  || mask == M_SWC1_AB
6271179404Sobrien	  || mask == M_LDC1_AB
6272179404Sobrien	  || mask == M_SDC1_AB
6273179404Sobrien	  || mask == M_L_DAB
6274179404Sobrien	  || mask == M_S_DAB)
6275179404Sobrien	fmt = "T,o(b)";
6276218822Sdim      else if (mask == M_CACHE_AB)
6277218822Sdim	fmt = "k,o(b)";
6278179404Sobrien      else if (coproc)
6279179404Sobrien	fmt = "E,o(b)";
6280179404Sobrien      else
6281179404Sobrien	fmt = "t,o(b)";
6282179404Sobrien
6283179404Sobrien      if (offset_expr.X_op != O_constant
6284179404Sobrien	  && offset_expr.X_op != O_symbol)
6285179404Sobrien	{
6286179404Sobrien	  as_bad (_("expression too complex"));
6287179404Sobrien	  offset_expr.X_op = O_constant;
6288179404Sobrien	}
6289179404Sobrien
6290208737Sjmallett      if (HAVE_32BIT_ADDRESSES
6291208737Sjmallett	  && !IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
6292208737Sjmallett	{
6293208737Sjmallett	  char value [32];
6294208737Sjmallett
6295208737Sjmallett	  sprintf_vma (value, offset_expr.X_add_number);
6296208737Sjmallett	  as_bad (_("Number (0x%s) larger than 32 bits"), value);
6297208737Sjmallett	}
6298208737Sjmallett
6299179404Sobrien      /* A constant expression in PIC code can be handled just as it
6300179404Sobrien	 is in non PIC code.  */
6301208737Sjmallett      if (offset_expr.X_op == O_constant)
6302179404Sobrien	{
6303208737Sjmallett	  expr1.X_add_number = ((offset_expr.X_add_number + 0x8000)
6304208737Sjmallett				& ~(bfd_vma) 0xffff);
6305208737Sjmallett	  normalize_address_expr (&expr1);
6306208737Sjmallett	  load_register (tempreg, &expr1, HAVE_64BIT_ADDRESSES);
6307208737Sjmallett	  if (breg != 0)
6308208737Sjmallett	    macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
6309208737Sjmallett			 tempreg, tempreg, breg);
6310208737Sjmallett	  macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, tempreg);
6311208737Sjmallett	}
6312208737Sjmallett      else if (mips_pic == NO_PIC)
6313208737Sjmallett	{
6314179404Sobrien	  /* If this is a reference to a GP relative symbol, and there
6315179404Sobrien	     is no base register, we want
6316179404Sobrien	       <op>	$treg,<sym>($gp)	(BFD_RELOC_GPREL16)
6317179404Sobrien	     Otherwise, if there is no base register, we want
6318179404Sobrien	       lui	$tempreg,<sym>		(BFD_RELOC_HI16_S)
6319179404Sobrien	       <op>	$treg,<sym>($tempreg)	(BFD_RELOC_LO16)
6320179404Sobrien	     If we have a constant, we need two instructions anyhow,
6321179404Sobrien	     so we always use the latter form.
6322179404Sobrien
6323179404Sobrien	     If we have a base register, and this is a reference to a
6324179404Sobrien	     GP relative symbol, we want
6325179404Sobrien	       addu	$tempreg,$breg,$gp
6326179404Sobrien	       <op>	$treg,<sym>($tempreg)	(BFD_RELOC_GPREL16)
6327179404Sobrien	     Otherwise we want
6328179404Sobrien	       lui	$tempreg,<sym>		(BFD_RELOC_HI16_S)
6329179404Sobrien	       addu	$tempreg,$tempreg,$breg
6330179404Sobrien	       <op>	$treg,<sym>($tempreg)	(BFD_RELOC_LO16)
6331179404Sobrien	     With a constant we always use the latter case.
6332179404Sobrien
6333179404Sobrien	     With 64bit address space and no base register and $at usable,
6334179404Sobrien	     we want
6335179404Sobrien	       lui	$tempreg,<sym>		(BFD_RELOC_MIPS_HIGHEST)
6336179404Sobrien	       lui	$at,<sym>		(BFD_RELOC_HI16_S)
6337179404Sobrien	       daddiu	$tempreg,<sym>		(BFD_RELOC_MIPS_HIGHER)
6338179404Sobrien	       dsll32	$tempreg,0
6339179404Sobrien	       daddu	$tempreg,$at
6340179404Sobrien	       <op>	$treg,<sym>($tempreg)	(BFD_RELOC_LO16)
6341179404Sobrien	     If we have a base register, we want
6342179404Sobrien	       lui	$tempreg,<sym>		(BFD_RELOC_MIPS_HIGHEST)
6343179404Sobrien	       lui	$at,<sym>		(BFD_RELOC_HI16_S)
6344179404Sobrien	       daddiu	$tempreg,<sym>		(BFD_RELOC_MIPS_HIGHER)
6345179404Sobrien	       daddu	$at,$breg
6346179404Sobrien	       dsll32	$tempreg,0
6347179404Sobrien	       daddu	$tempreg,$at
6348179404Sobrien	       <op>	$treg,<sym>($tempreg)	(BFD_RELOC_LO16)
6349179404Sobrien
6350179404Sobrien	     Without $at we can't generate the optimal path for superscalar
6351179404Sobrien	     processors here since this would require two temporary registers.
6352179404Sobrien	       lui	$tempreg,<sym>		(BFD_RELOC_MIPS_HIGHEST)
6353179404Sobrien	       daddiu	$tempreg,<sym>		(BFD_RELOC_MIPS_HIGHER)
6354179404Sobrien	       dsll	$tempreg,16
6355179404Sobrien	       daddiu	$tempreg,<sym>		(BFD_RELOC_HI16_S)
6356179404Sobrien	       dsll	$tempreg,16
6357179404Sobrien	       <op>	$treg,<sym>($tempreg)	(BFD_RELOC_LO16)
6358179404Sobrien	     If we have a base register, we want
6359179404Sobrien	       lui	$tempreg,<sym>		(BFD_RELOC_MIPS_HIGHEST)
6360179404Sobrien	       daddiu	$tempreg,<sym>		(BFD_RELOC_MIPS_HIGHER)
6361179404Sobrien	       dsll	$tempreg,16
6362179404Sobrien	       daddiu	$tempreg,<sym>		(BFD_RELOC_HI16_S)
6363179404Sobrien	       dsll	$tempreg,16
6364179404Sobrien	       daddu	$tempreg,$tempreg,$breg
6365179404Sobrien	       <op>	$treg,<sym>($tempreg)	(BFD_RELOC_LO16)
6366179404Sobrien
6367208737Sjmallett	     For GP relative symbols in 64bit address space we can use
6368208737Sjmallett	     the same sequence as in 32bit address space.  */
6369208737Sjmallett	  if (HAVE_64BIT_SYMBOLS)
6370179404Sobrien	    {
6371208737Sjmallett	      if ((valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET
6372208737Sjmallett		  && !nopic_need_relax (offset_expr.X_add_symbol, 1))
6373208737Sjmallett		{
6374208737Sjmallett		  relax_start (offset_expr.X_add_symbol);
6375208737Sjmallett		  if (breg == 0)
6376208737Sjmallett		    {
6377208737Sjmallett		      macro_build (&offset_expr, s, fmt, treg,
6378208737Sjmallett				   BFD_RELOC_GPREL16, mips_gp_register);
6379208737Sjmallett		    }
6380208737Sjmallett		  else
6381208737Sjmallett		    {
6382208737Sjmallett		      macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
6383208737Sjmallett				   tempreg, breg, mips_gp_register);
6384208737Sjmallett		      macro_build (&offset_expr, s, fmt, treg,
6385208737Sjmallett				   BFD_RELOC_GPREL16, tempreg);
6386208737Sjmallett		    }
6387208737Sjmallett		  relax_switch ();
6388208737Sjmallett		}
6389179404Sobrien
6390208737Sjmallett	      if (used_at == 0 && !mips_opts.noat)
6391179404Sobrien		{
6392179404Sobrien		  macro_build (&offset_expr, "lui", "t,u", tempreg,
6393179404Sobrien			       BFD_RELOC_MIPS_HIGHEST);
6394179404Sobrien		  macro_build (&offset_expr, "lui", "t,u", AT,
6395179404Sobrien			       BFD_RELOC_HI16_S);
6396179404Sobrien		  macro_build (&offset_expr, "daddiu", "t,r,j", tempreg,
6397179404Sobrien			       tempreg, BFD_RELOC_MIPS_HIGHER);
6398179404Sobrien		  if (breg != 0)
6399179404Sobrien		    macro_build (NULL, "daddu", "d,v,t", AT, AT, breg);
6400179404Sobrien		  macro_build (NULL, "dsll32", "d,w,<", tempreg, tempreg, 0);
6401179404Sobrien		  macro_build (NULL, "daddu", "d,v,t", tempreg, tempreg, AT);
6402179404Sobrien		  macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16,
6403179404Sobrien			       tempreg);
6404179404Sobrien		  used_at = 1;
6405179404Sobrien		}
6406179404Sobrien	      else
6407179404Sobrien		{
6408179404Sobrien		  macro_build (&offset_expr, "lui", "t,u", tempreg,
6409179404Sobrien			       BFD_RELOC_MIPS_HIGHEST);
6410179404Sobrien		  macro_build (&offset_expr, "daddiu", "t,r,j", tempreg,
6411179404Sobrien			       tempreg, BFD_RELOC_MIPS_HIGHER);
6412179404Sobrien		  macro_build (NULL, "dsll", "d,w,<", tempreg, tempreg, 16);
6413179404Sobrien		  macro_build (&offset_expr, "daddiu", "t,r,j", tempreg,
6414179404Sobrien			       tempreg, BFD_RELOC_HI16_S);
6415179404Sobrien		  macro_build (NULL, "dsll", "d,w,<", tempreg, tempreg, 16);
6416179404Sobrien		  if (breg != 0)
6417179404Sobrien		    macro_build (NULL, "daddu", "d,v,t",
6418179404Sobrien				 tempreg, tempreg, breg);
6419179404Sobrien		  macro_build (&offset_expr, s, fmt, treg,
6420179404Sobrien			       BFD_RELOC_LO16, tempreg);
6421179404Sobrien		}
6422179404Sobrien
6423208737Sjmallett	      if (mips_relax.sequence)
6424208737Sjmallett		relax_end ();
6425208737Sjmallett	      break;
6426179404Sobrien	    }
6427179404Sobrien
6428179404Sobrien	  if (breg == 0)
6429179404Sobrien	    {
6430179404Sobrien	      if ((valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET
6431208737Sjmallett		  && !nopic_need_relax (offset_expr.X_add_symbol, 1))
6432179404Sobrien		{
6433179404Sobrien		  relax_start (offset_expr.X_add_symbol);
6434179404Sobrien		  macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_GPREL16,
6435179404Sobrien			       mips_gp_register);
6436179404Sobrien		  relax_switch ();
6437179404Sobrien		}
6438179404Sobrien	      macro_build_lui (&offset_expr, tempreg);
6439179404Sobrien	      macro_build (&offset_expr, s, fmt, treg,
6440179404Sobrien			   BFD_RELOC_LO16, tempreg);
6441179404Sobrien	      if (mips_relax.sequence)
6442179404Sobrien		relax_end ();
6443179404Sobrien	    }
6444179404Sobrien	  else
6445179404Sobrien	    {
6446179404Sobrien	      if ((valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET
6447208737Sjmallett		  && !nopic_need_relax (offset_expr.X_add_symbol, 1))
6448179404Sobrien		{
6449179404Sobrien		  relax_start (offset_expr.X_add_symbol);
6450179404Sobrien		  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
6451179404Sobrien			       tempreg, breg, mips_gp_register);
6452179404Sobrien		  macro_build (&offset_expr, s, fmt, treg,
6453179404Sobrien			       BFD_RELOC_GPREL16, tempreg);
6454179404Sobrien		  relax_switch ();
6455179404Sobrien		}
6456179404Sobrien	      macro_build_lui (&offset_expr, tempreg);
6457179404Sobrien	      macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
6458179404Sobrien			   tempreg, tempreg, breg);
6459179404Sobrien	      macro_build (&offset_expr, s, fmt, treg,
6460179404Sobrien			   BFD_RELOC_LO16, tempreg);
6461179404Sobrien	      if (mips_relax.sequence)
6462179404Sobrien		relax_end ();
6463179404Sobrien	    }
6464179404Sobrien	}
6465208737Sjmallett      else if (!mips_big_got)
6466179404Sobrien	{
6467179404Sobrien	  int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT16;
6468179404Sobrien
6469179404Sobrien	  /* If this is a reference to an external symbol, we want
6470179404Sobrien	       lw	$tempreg,<sym>($gp)	(BFD_RELOC_MIPS_GOT16)
6471179404Sobrien	       nop
6472179404Sobrien	       <op>	$treg,0($tempreg)
6473179404Sobrien	     Otherwise we want
6474179404Sobrien	       lw	$tempreg,<sym>($gp)	(BFD_RELOC_MIPS_GOT16)
6475179404Sobrien	       nop
6476179404Sobrien	       addiu	$tempreg,$tempreg,<sym>	(BFD_RELOC_LO16)
6477179404Sobrien	       <op>	$treg,0($tempreg)
6478179404Sobrien
6479179404Sobrien	     For NewABI, we want
6480179404Sobrien	       lw	$tempreg,<sym>($gp)	(BFD_RELOC_MIPS_GOT_PAGE)
6481179404Sobrien	       <op>	$treg,<sym>($tempreg)   (BFD_RELOC_MIPS_GOT_OFST)
6482179404Sobrien
6483179404Sobrien	     If there is a base register, we add it to $tempreg before
6484179404Sobrien	     the <op>.  If there is a constant, we stick it in the
6485179404Sobrien	     <op> instruction.  We don't handle constants larger than
6486179404Sobrien	     16 bits, because we have no way to load the upper 16 bits
6487179404Sobrien	     (actually, we could handle them for the subset of cases
6488179404Sobrien	     in which we are not using $at).  */
6489179404Sobrien	  assert (offset_expr.X_op == O_symbol);
6490179404Sobrien	  if (HAVE_NEWABI)
6491179404Sobrien	    {
6492179404Sobrien	      macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
6493179404Sobrien			   BFD_RELOC_MIPS_GOT_PAGE, mips_gp_register);
6494179404Sobrien	      if (breg != 0)
6495179404Sobrien		macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
6496179404Sobrien			     tempreg, tempreg, breg);
6497179404Sobrien	      macro_build (&offset_expr, s, fmt, treg,
6498179404Sobrien			   BFD_RELOC_MIPS_GOT_OFST, tempreg);
6499179404Sobrien	      break;
6500179404Sobrien	    }
6501179404Sobrien	  expr1.X_add_number = offset_expr.X_add_number;
6502179404Sobrien	  offset_expr.X_add_number = 0;
6503179404Sobrien	  if (expr1.X_add_number < -0x8000
6504179404Sobrien	      || expr1.X_add_number >= 0x8000)
6505179404Sobrien	    as_bad (_("PIC code offset overflow (max 16 signed bits)"));
6506179404Sobrien	  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
6507179404Sobrien		       lw_reloc_type, mips_gp_register);
6508208737Sjmallett	  load_delay_nop ();
6509179404Sobrien	  relax_start (offset_expr.X_add_symbol);
6510179404Sobrien	  relax_switch ();
6511179404Sobrien	  macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", tempreg,
6512179404Sobrien		       tempreg, BFD_RELOC_LO16);
6513179404Sobrien	  relax_end ();
6514179404Sobrien	  if (breg != 0)
6515179404Sobrien	    macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
6516179404Sobrien			 tempreg, tempreg, breg);
6517179404Sobrien	  macro_build (&expr1, s, fmt, treg, BFD_RELOC_LO16, tempreg);
6518179404Sobrien	}
6519208737Sjmallett      else if (mips_big_got && !HAVE_NEWABI)
6520179404Sobrien	{
6521179404Sobrien	  int gpdelay;
6522179404Sobrien
6523179404Sobrien	  /* If this is a reference to an external symbol, we want
6524179404Sobrien	       lui	$tempreg,<sym>		(BFD_RELOC_MIPS_GOT_HI16)
6525179404Sobrien	       addu	$tempreg,$tempreg,$gp
6526179404Sobrien	       lw	$tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
6527179404Sobrien	       <op>	$treg,0($tempreg)
6528179404Sobrien	     Otherwise we want
6529179404Sobrien	       lw	$tempreg,<sym>($gp)	(BFD_RELOC_MIPS_GOT16)
6530179404Sobrien	       nop
6531179404Sobrien	       addiu	$tempreg,$tempreg,<sym>	(BFD_RELOC_LO16)
6532179404Sobrien	       <op>	$treg,0($tempreg)
6533179404Sobrien	     If there is a base register, we add it to $tempreg before
6534179404Sobrien	     the <op>.  If there is a constant, we stick it in the
6535179404Sobrien	     <op> instruction.  We don't handle constants larger than
6536179404Sobrien	     16 bits, because we have no way to load the upper 16 bits
6537179404Sobrien	     (actually, we could handle them for the subset of cases
6538179404Sobrien	     in which we are not using $at).  */
6539179404Sobrien	  assert (offset_expr.X_op == O_symbol);
6540179404Sobrien	  expr1.X_add_number = offset_expr.X_add_number;
6541179404Sobrien	  offset_expr.X_add_number = 0;
6542179404Sobrien	  if (expr1.X_add_number < -0x8000
6543179404Sobrien	      || expr1.X_add_number >= 0x8000)
6544179404Sobrien	    as_bad (_("PIC code offset overflow (max 16 signed bits)"));
6545179404Sobrien	  gpdelay = reg_needs_delay (mips_gp_register);
6546179404Sobrien	  relax_start (offset_expr.X_add_symbol);
6547179404Sobrien	  macro_build (&offset_expr, "lui", "t,u", tempreg,
6548179404Sobrien		       BFD_RELOC_MIPS_GOT_HI16);
6549179404Sobrien	  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", tempreg, tempreg,
6550179404Sobrien		       mips_gp_register);
6551179404Sobrien	  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
6552179404Sobrien		       BFD_RELOC_MIPS_GOT_LO16, tempreg);
6553179404Sobrien	  relax_switch ();
6554179404Sobrien	  if (gpdelay)
6555179404Sobrien	    macro_build (NULL, "nop", "");
6556179404Sobrien	  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
6557179404Sobrien		       BFD_RELOC_MIPS_GOT16, mips_gp_register);
6558208737Sjmallett	  load_delay_nop ();
6559179404Sobrien	  macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", tempreg,
6560179404Sobrien		       tempreg, BFD_RELOC_LO16);
6561179404Sobrien	  relax_end ();
6562179404Sobrien
6563179404Sobrien	  if (breg != 0)
6564179404Sobrien	    macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
6565179404Sobrien			 tempreg, tempreg, breg);
6566179404Sobrien	  macro_build (&expr1, s, fmt, treg, BFD_RELOC_LO16, tempreg);
6567179404Sobrien	}
6568208737Sjmallett      else if (mips_big_got && HAVE_NEWABI)
6569179404Sobrien	{
6570179404Sobrien	  /* If this is a reference to an external symbol, we want
6571179404Sobrien	       lui	$tempreg,<sym>		(BFD_RELOC_MIPS_GOT_HI16)
6572179404Sobrien	       add	$tempreg,$tempreg,$gp
6573179404Sobrien	       lw	$tempreg,<sym>($tempreg) (BFD_RELOC_MIPS_GOT_LO16)
6574179404Sobrien	       <op>	$treg,<ofst>($tempreg)
6575179404Sobrien	     Otherwise, for local symbols, we want:
6576179404Sobrien	       lw	$tempreg,<sym>($gp)	(BFD_RELOC_MIPS_GOT_PAGE)
6577179404Sobrien	       <op>	$treg,<sym>($tempreg)   (BFD_RELOC_MIPS_GOT_OFST)  */
6578179404Sobrien	  assert (offset_expr.X_op == O_symbol);
6579179404Sobrien	  expr1.X_add_number = offset_expr.X_add_number;
6580179404Sobrien	  offset_expr.X_add_number = 0;
6581179404Sobrien	  if (expr1.X_add_number < -0x8000
6582179404Sobrien	      || expr1.X_add_number >= 0x8000)
6583179404Sobrien	    as_bad (_("PIC code offset overflow (max 16 signed bits)"));
6584179404Sobrien	  relax_start (offset_expr.X_add_symbol);
6585179404Sobrien	  macro_build (&offset_expr, "lui", "t,u", tempreg,
6586179404Sobrien		       BFD_RELOC_MIPS_GOT_HI16);
6587179404Sobrien	  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", tempreg, tempreg,
6588179404Sobrien		       mips_gp_register);
6589179404Sobrien	  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
6590179404Sobrien		       BFD_RELOC_MIPS_GOT_LO16, tempreg);
6591179404Sobrien	  if (breg != 0)
6592179404Sobrien	    macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
6593179404Sobrien			 tempreg, tempreg, breg);
6594179404Sobrien	  macro_build (&expr1, s, fmt, treg, BFD_RELOC_LO16, tempreg);
6595179404Sobrien
6596179404Sobrien	  relax_switch ();
6597179404Sobrien	  offset_expr.X_add_number = expr1.X_add_number;
6598179404Sobrien	  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", tempreg,
6599179404Sobrien		       BFD_RELOC_MIPS_GOT_PAGE, mips_gp_register);
6600179404Sobrien	  if (breg != 0)
6601179404Sobrien	    macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
6602179404Sobrien			 tempreg, tempreg, breg);
6603179404Sobrien	  macro_build (&offset_expr, s, fmt, treg,
6604179404Sobrien		       BFD_RELOC_MIPS_GOT_OFST, tempreg);
6605179404Sobrien	  relax_end ();
6606179404Sobrien	}
6607179404Sobrien      else
6608179404Sobrien	abort ();
6609179404Sobrien
6610179404Sobrien      break;
6611179404Sobrien
6612179404Sobrien    case M_LI:
6613179404Sobrien    case M_LI_S:
6614179404Sobrien      load_register (treg, &imm_expr, 0);
6615208737Sjmallett      break;
6616179404Sobrien
6617179404Sobrien    case M_DLI:
6618179404Sobrien      load_register (treg, &imm_expr, 1);
6619208737Sjmallett      break;
6620179404Sobrien
6621179404Sobrien    case M_LI_SS:
6622179404Sobrien      if (imm_expr.X_op == O_constant)
6623179404Sobrien	{
6624208737Sjmallett	  used_at = 1;
6625179404Sobrien	  load_register (AT, &imm_expr, 0);
6626179404Sobrien	  macro_build (NULL, "mtc1", "t,G", AT, treg);
6627179404Sobrien	  break;
6628179404Sobrien	}
6629179404Sobrien      else
6630179404Sobrien	{
6631179404Sobrien	  assert (offset_expr.X_op == O_symbol
6632179404Sobrien		  && strcmp (segment_name (S_GET_SEGMENT
6633179404Sobrien					   (offset_expr.X_add_symbol)),
6634179404Sobrien			     ".lit4") == 0
6635179404Sobrien		  && offset_expr.X_add_number == 0);
6636179404Sobrien	  macro_build (&offset_expr, "lwc1", "T,o(b)", treg,
6637179404Sobrien		       BFD_RELOC_MIPS_LITERAL, mips_gp_register);
6638208737Sjmallett	  break;
6639179404Sobrien	}
6640179404Sobrien
6641179404Sobrien    case M_LI_D:
6642179404Sobrien      /* Check if we have a constant in IMM_EXPR.  If the GPRs are 64 bits
6643179404Sobrien         wide, IMM_EXPR is the entire value.  Otherwise IMM_EXPR is the high
6644179404Sobrien         order 32 bits of the value and the low order 32 bits are either
6645179404Sobrien         zero or in OFFSET_EXPR.  */
6646179404Sobrien      if (imm_expr.X_op == O_constant || imm_expr.X_op == O_big)
6647179404Sobrien	{
6648179404Sobrien	  if (HAVE_64BIT_GPRS)
6649179404Sobrien	    load_register (treg, &imm_expr, 1);
6650179404Sobrien	  else
6651179404Sobrien	    {
6652179404Sobrien	      int hreg, lreg;
6653179404Sobrien
6654179404Sobrien	      if (target_big_endian)
6655179404Sobrien		{
6656179404Sobrien		  hreg = treg;
6657179404Sobrien		  lreg = treg + 1;
6658179404Sobrien		}
6659179404Sobrien	      else
6660179404Sobrien		{
6661179404Sobrien		  hreg = treg + 1;
6662179404Sobrien		  lreg = treg;
6663179404Sobrien		}
6664179404Sobrien
6665179404Sobrien	      if (hreg <= 31)
6666179404Sobrien		load_register (hreg, &imm_expr, 0);
6667179404Sobrien	      if (lreg <= 31)
6668179404Sobrien		{
6669179404Sobrien		  if (offset_expr.X_op == O_absent)
6670179404Sobrien		    move_register (lreg, 0);
6671179404Sobrien		  else
6672179404Sobrien		    {
6673179404Sobrien		      assert (offset_expr.X_op == O_constant);
6674179404Sobrien		      load_register (lreg, &offset_expr, 0);
6675179404Sobrien		    }
6676179404Sobrien		}
6677179404Sobrien	    }
6678208737Sjmallett	  break;
6679179404Sobrien	}
6680179404Sobrien
6681179404Sobrien      /* We know that sym is in the .rdata section.  First we get the
6682179404Sobrien	 upper 16 bits of the address.  */
6683179404Sobrien      if (mips_pic == NO_PIC)
6684179404Sobrien	{
6685179404Sobrien	  macro_build_lui (&offset_expr, AT);
6686208737Sjmallett	  used_at = 1;
6687179404Sobrien	}
6688208737Sjmallett      else
6689179404Sobrien	{
6690179404Sobrien	  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", AT,
6691179404Sobrien		       BFD_RELOC_MIPS_GOT16, mips_gp_register);
6692208737Sjmallett	  used_at = 1;
6693179404Sobrien	}
6694179404Sobrien
6695179404Sobrien      /* Now we load the register(s).  */
6696179404Sobrien      if (HAVE_64BIT_GPRS)
6697208737Sjmallett	{
6698208737Sjmallett	  used_at = 1;
6699208737Sjmallett	  macro_build (&offset_expr, "ld", "t,o(b)", treg, BFD_RELOC_LO16, AT);
6700208737Sjmallett	}
6701179404Sobrien      else
6702179404Sobrien	{
6703208737Sjmallett	  used_at = 1;
6704179404Sobrien	  macro_build (&offset_expr, "lw", "t,o(b)", treg, BFD_RELOC_LO16, AT);
6705179404Sobrien	  if (treg != RA)
6706179404Sobrien	    {
6707179404Sobrien	      /* FIXME: How in the world do we deal with the possible
6708179404Sobrien		 overflow here?  */
6709179404Sobrien	      offset_expr.X_add_number += 4;
6710179404Sobrien	      macro_build (&offset_expr, "lw", "t,o(b)",
6711179404Sobrien			   treg + 1, BFD_RELOC_LO16, AT);
6712179404Sobrien	    }
6713179404Sobrien	}
6714179404Sobrien      break;
6715179404Sobrien
6716179404Sobrien    case M_LI_DD:
6717179404Sobrien      /* Check if we have a constant in IMM_EXPR.  If the FPRs are 64 bits
6718179404Sobrien         wide, IMM_EXPR is the entire value and the GPRs are known to be 64
6719179404Sobrien         bits wide as well.  Otherwise IMM_EXPR is the high order 32 bits of
6720179404Sobrien         the value and the low order 32 bits are either zero or in
6721179404Sobrien         OFFSET_EXPR.  */
6722179404Sobrien      if (imm_expr.X_op == O_constant || imm_expr.X_op == O_big)
6723179404Sobrien	{
6724208737Sjmallett	  used_at = 1;
6725179404Sobrien	  load_register (AT, &imm_expr, HAVE_64BIT_FPRS);
6726179404Sobrien	  if (HAVE_64BIT_FPRS)
6727179404Sobrien	    {
6728179404Sobrien	      assert (HAVE_64BIT_GPRS);
6729179404Sobrien	      macro_build (NULL, "dmtc1", "t,S", AT, treg);
6730179404Sobrien	    }
6731179404Sobrien	  else
6732179404Sobrien	    {
6733179404Sobrien	      macro_build (NULL, "mtc1", "t,G", AT, treg + 1);
6734179404Sobrien	      if (offset_expr.X_op == O_absent)
6735179404Sobrien		macro_build (NULL, "mtc1", "t,G", 0, treg);
6736179404Sobrien	      else
6737179404Sobrien		{
6738179404Sobrien		  assert (offset_expr.X_op == O_constant);
6739179404Sobrien		  load_register (AT, &offset_expr, 0);
6740179404Sobrien		  macro_build (NULL, "mtc1", "t,G", AT, treg);
6741179404Sobrien		}
6742179404Sobrien	    }
6743179404Sobrien	  break;
6744179404Sobrien	}
6745179404Sobrien
6746179404Sobrien      assert (offset_expr.X_op == O_symbol
6747179404Sobrien	      && offset_expr.X_add_number == 0);
6748179404Sobrien      s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol));
6749179404Sobrien      if (strcmp (s, ".lit8") == 0)
6750179404Sobrien	{
6751179404Sobrien	  if (mips_opts.isa != ISA_MIPS1)
6752179404Sobrien	    {
6753179404Sobrien	      macro_build (&offset_expr, "ldc1", "T,o(b)", treg,
6754179404Sobrien			   BFD_RELOC_MIPS_LITERAL, mips_gp_register);
6755208737Sjmallett	      break;
6756179404Sobrien	    }
6757179404Sobrien	  breg = mips_gp_register;
6758179404Sobrien	  r = BFD_RELOC_MIPS_LITERAL;
6759179404Sobrien	  goto dob;
6760179404Sobrien	}
6761179404Sobrien      else
6762179404Sobrien	{
6763179404Sobrien	  assert (strcmp (s, RDATA_SECTION_NAME) == 0);
6764208737Sjmallett	  used_at = 1;
6765208737Sjmallett	  if (mips_pic != NO_PIC)
6766179404Sobrien	    macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", AT,
6767179404Sobrien			 BFD_RELOC_MIPS_GOT16, mips_gp_register);
6768179404Sobrien	  else
6769179404Sobrien	    {
6770179404Sobrien	      /* FIXME: This won't work for a 64 bit address.  */
6771179404Sobrien	      macro_build_lui (&offset_expr, AT);
6772179404Sobrien	    }
6773179404Sobrien
6774179404Sobrien	  if (mips_opts.isa != ISA_MIPS1)
6775179404Sobrien	    {
6776179404Sobrien	      macro_build (&offset_expr, "ldc1", "T,o(b)",
6777179404Sobrien			   treg, BFD_RELOC_LO16, AT);
6778179404Sobrien	      break;
6779179404Sobrien	    }
6780179404Sobrien	  breg = AT;
6781179404Sobrien	  r = BFD_RELOC_LO16;
6782179404Sobrien	  goto dob;
6783179404Sobrien	}
6784179404Sobrien
6785179404Sobrien    case M_L_DOB:
6786179404Sobrien      if (mips_opts.arch == CPU_R4650)
6787179404Sobrien	{
6788179404Sobrien	  as_bad (_("opcode not supported on this processor"));
6789208737Sjmallett	  break;
6790179404Sobrien	}
6791179404Sobrien      /* Even on a big endian machine $fn comes before $fn+1.  We have
6792179404Sobrien	 to adjust when loading from memory.  */
6793179404Sobrien      r = BFD_RELOC_LO16;
6794179404Sobrien    dob:
6795179404Sobrien      assert (mips_opts.isa == ISA_MIPS1);
6796179404Sobrien      macro_build (&offset_expr, "lwc1", "T,o(b)",
6797179404Sobrien		   target_big_endian ? treg + 1 : treg, r, breg);
6798179404Sobrien      /* FIXME: A possible overflow which I don't know how to deal
6799179404Sobrien	 with.  */
6800179404Sobrien      offset_expr.X_add_number += 4;
6801179404Sobrien      macro_build (&offset_expr, "lwc1", "T,o(b)",
6802179404Sobrien		   target_big_endian ? treg : treg + 1, r, breg);
6803179404Sobrien      break;
6804179404Sobrien
6805179404Sobrien    case M_L_DAB:
6806179404Sobrien      /*
6807179404Sobrien       * The MIPS assembler seems to check for X_add_number not
6808179404Sobrien       * being double aligned and generating:
6809179404Sobrien       *	lui	at,%hi(foo+1)
6810179404Sobrien       *	addu	at,at,v1
6811179404Sobrien       *	addiu	at,at,%lo(foo+1)
6812179404Sobrien       *	lwc1	f2,0(at)
6813179404Sobrien       *	lwc1	f3,4(at)
6814179404Sobrien       * But, the resulting address is the same after relocation so why
6815179404Sobrien       * generate the extra instruction?
6816179404Sobrien       */
6817179404Sobrien      if (mips_opts.arch == CPU_R4650)
6818179404Sobrien	{
6819179404Sobrien	  as_bad (_("opcode not supported on this processor"));
6820208737Sjmallett	  break;
6821179404Sobrien	}
6822179404Sobrien      /* Itbl support may require additional care here.  */
6823179404Sobrien      coproc = 1;
6824179404Sobrien      if (mips_opts.isa != ISA_MIPS1)
6825179404Sobrien	{
6826179404Sobrien	  s = "ldc1";
6827179404Sobrien	  goto ld;
6828179404Sobrien	}
6829179404Sobrien
6830179404Sobrien      s = "lwc1";
6831179404Sobrien      fmt = "T,o(b)";
6832179404Sobrien      goto ldd_std;
6833179404Sobrien
6834179404Sobrien    case M_S_DAB:
6835179404Sobrien      if (mips_opts.arch == CPU_R4650)
6836179404Sobrien	{
6837179404Sobrien	  as_bad (_("opcode not supported on this processor"));
6838208737Sjmallett	  break;
6839179404Sobrien	}
6840179404Sobrien
6841179404Sobrien      if (mips_opts.isa != ISA_MIPS1)
6842179404Sobrien	{
6843179404Sobrien	  s = "sdc1";
6844179404Sobrien	  goto st;
6845179404Sobrien	}
6846179404Sobrien
6847179404Sobrien      s = "swc1";
6848179404Sobrien      fmt = "T,o(b)";
6849179404Sobrien      /* Itbl support may require additional care here.  */
6850179404Sobrien      coproc = 1;
6851179404Sobrien      goto ldd_std;
6852179404Sobrien
6853179404Sobrien    case M_LD_AB:
6854179404Sobrien      if (HAVE_64BIT_GPRS)
6855179404Sobrien	{
6856179404Sobrien	  s = "ld";
6857179404Sobrien	  goto ld;
6858179404Sobrien	}
6859179404Sobrien
6860179404Sobrien      s = "lw";
6861179404Sobrien      fmt = "t,o(b)";
6862179404Sobrien      goto ldd_std;
6863179404Sobrien
6864179404Sobrien    case M_SD_AB:
6865179404Sobrien      if (HAVE_64BIT_GPRS)
6866179404Sobrien	{
6867179404Sobrien	  s = "sd";
6868179404Sobrien	  goto st;
6869179404Sobrien	}
6870179404Sobrien
6871179404Sobrien      s = "sw";
6872179404Sobrien      fmt = "t,o(b)";
6873179404Sobrien
6874179404Sobrien    ldd_std:
6875179404Sobrien      if (offset_expr.X_op != O_symbol
6876179404Sobrien	  && offset_expr.X_op != O_constant)
6877179404Sobrien	{
6878179404Sobrien	  as_bad (_("expression too complex"));
6879179404Sobrien	  offset_expr.X_op = O_constant;
6880179404Sobrien	}
6881179404Sobrien
6882208737Sjmallett      if (HAVE_32BIT_ADDRESSES
6883208737Sjmallett	  && !IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
6884208737Sjmallett	{
6885208737Sjmallett	  char value [32];
6886208737Sjmallett
6887208737Sjmallett	  sprintf_vma (value, offset_expr.X_add_number);
6888208737Sjmallett	  as_bad (_("Number (0x%s) larger than 32 bits"), value);
6889208737Sjmallett	}
6890208737Sjmallett
6891179404Sobrien      /* Even on a big endian machine $fn comes before $fn+1.  We have
6892179404Sobrien	 to adjust when loading from memory.  We set coproc if we must
6893179404Sobrien	 load $fn+1 first.  */
6894179404Sobrien      /* Itbl support may require additional care here.  */
6895179404Sobrien      if (! target_big_endian)
6896179404Sobrien	coproc = 0;
6897179404Sobrien
6898179404Sobrien      if (mips_pic == NO_PIC
6899179404Sobrien	  || offset_expr.X_op == O_constant)
6900179404Sobrien	{
6901179404Sobrien	  /* If this is a reference to a GP relative symbol, we want
6902179404Sobrien	       <op>	$treg,<sym>($gp)	(BFD_RELOC_GPREL16)
6903179404Sobrien	       <op>	$treg+1,<sym>+4($gp)	(BFD_RELOC_GPREL16)
6904179404Sobrien	     If we have a base register, we use this
6905179404Sobrien	       addu	$at,$breg,$gp
6906179404Sobrien	       <op>	$treg,<sym>($at)	(BFD_RELOC_GPREL16)
6907179404Sobrien	       <op>	$treg+1,<sym>+4($at)	(BFD_RELOC_GPREL16)
6908179404Sobrien	     If this is not a GP relative symbol, we want
6909179404Sobrien	       lui	$at,<sym>		(BFD_RELOC_HI16_S)
6910179404Sobrien	       <op>	$treg,<sym>($at)	(BFD_RELOC_LO16)
6911179404Sobrien	       <op>	$treg+1,<sym>+4($at)	(BFD_RELOC_LO16)
6912179404Sobrien	     If there is a base register, we add it to $at after the
6913179404Sobrien	     lui instruction.  If there is a constant, we always use
6914179404Sobrien	     the last case.  */
6915208737Sjmallett	  if (offset_expr.X_op == O_symbol
6916208737Sjmallett	      && (valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET
6917208737Sjmallett	      && !nopic_need_relax (offset_expr.X_add_symbol, 1))
6918179404Sobrien	    {
6919179404Sobrien	      relax_start (offset_expr.X_add_symbol);
6920179404Sobrien	      if (breg == 0)
6921179404Sobrien		{
6922179404Sobrien		  tempreg = mips_gp_register;
6923179404Sobrien		}
6924179404Sobrien	      else
6925179404Sobrien		{
6926179404Sobrien		  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
6927179404Sobrien			       AT, breg, mips_gp_register);
6928179404Sobrien		  tempreg = AT;
6929179404Sobrien		  used_at = 1;
6930179404Sobrien		}
6931179404Sobrien
6932179404Sobrien	      /* Itbl support may require additional care here.  */
6933179404Sobrien	      macro_build (&offset_expr, s, fmt, coproc ? treg + 1 : treg,
6934179404Sobrien			   BFD_RELOC_GPREL16, tempreg);
6935179404Sobrien	      offset_expr.X_add_number += 4;
6936179404Sobrien
6937179404Sobrien	      /* Set mips_optimize to 2 to avoid inserting an
6938179404Sobrien                 undesired nop.  */
6939179404Sobrien	      hold_mips_optimize = mips_optimize;
6940179404Sobrien	      mips_optimize = 2;
6941179404Sobrien	      /* Itbl support may require additional care here.  */
6942179404Sobrien	      macro_build (&offset_expr, s, fmt, coproc ? treg : treg + 1,
6943179404Sobrien			   BFD_RELOC_GPREL16, tempreg);
6944179404Sobrien	      mips_optimize = hold_mips_optimize;
6945179404Sobrien
6946179404Sobrien	      relax_switch ();
6947179404Sobrien
6948179404Sobrien	      /* We just generated two relocs.  When tc_gen_reloc
6949179404Sobrien		 handles this case, it will skip the first reloc and
6950179404Sobrien		 handle the second.  The second reloc already has an
6951179404Sobrien		 extra addend of 4, which we added above.  We must
6952179404Sobrien		 subtract it out, and then subtract another 4 to make
6953179404Sobrien		 the first reloc come out right.  The second reloc
6954179404Sobrien		 will come out right because we are going to add 4 to
6955179404Sobrien		 offset_expr when we build its instruction below.
6956179404Sobrien
6957179404Sobrien		 If we have a symbol, then we don't want to include
6958179404Sobrien		 the offset, because it will wind up being included
6959179404Sobrien		 when we generate the reloc.  */
6960179404Sobrien
6961179404Sobrien	      if (offset_expr.X_op == O_constant)
6962179404Sobrien		offset_expr.X_add_number -= 8;
6963179404Sobrien	      else
6964179404Sobrien		{
6965179404Sobrien		  offset_expr.X_add_number = -4;
6966179404Sobrien		  offset_expr.X_op = O_constant;
6967179404Sobrien		}
6968179404Sobrien	    }
6969208737Sjmallett	  used_at = 1;
6970179404Sobrien	  macro_build_lui (&offset_expr, AT);
6971179404Sobrien	  if (breg != 0)
6972179404Sobrien	    macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
6973179404Sobrien	  /* Itbl support may require additional care here.  */
6974179404Sobrien	  macro_build (&offset_expr, s, fmt, coproc ? treg + 1 : treg,
6975179404Sobrien		       BFD_RELOC_LO16, AT);
6976179404Sobrien	  /* FIXME: How do we handle overflow here?  */
6977179404Sobrien	  offset_expr.X_add_number += 4;
6978179404Sobrien	  /* Itbl support may require additional care here.  */
6979179404Sobrien	  macro_build (&offset_expr, s, fmt, coproc ? treg : treg + 1,
6980179404Sobrien		       BFD_RELOC_LO16, AT);
6981179404Sobrien	  if (mips_relax.sequence)
6982179404Sobrien	    relax_end ();
6983179404Sobrien	}
6984208737Sjmallett      else if (!mips_big_got)
6985179404Sobrien	{
6986179404Sobrien	  /* If this is a reference to an external symbol, we want
6987179404Sobrien	       lw	$at,<sym>($gp)		(BFD_RELOC_MIPS_GOT16)
6988179404Sobrien	       nop
6989179404Sobrien	       <op>	$treg,0($at)
6990179404Sobrien	       <op>	$treg+1,4($at)
6991179404Sobrien	     Otherwise we want
6992179404Sobrien	       lw	$at,<sym>($gp)		(BFD_RELOC_MIPS_GOT16)
6993179404Sobrien	       nop
6994179404Sobrien	       <op>	$treg,<sym>($at)	(BFD_RELOC_LO16)
6995179404Sobrien	       <op>	$treg+1,<sym>+4($at)	(BFD_RELOC_LO16)
6996179404Sobrien	     If there is a base register we add it to $at before the
6997179404Sobrien	     lwc1 instructions.  If there is a constant we include it
6998179404Sobrien	     in the lwc1 instructions.  */
6999179404Sobrien	  used_at = 1;
7000179404Sobrien	  expr1.X_add_number = offset_expr.X_add_number;
7001179404Sobrien	  if (expr1.X_add_number < -0x8000
7002179404Sobrien	      || expr1.X_add_number >= 0x8000 - 4)
7003179404Sobrien	    as_bad (_("PIC code offset overflow (max 16 signed bits)"));
7004179404Sobrien	  load_got_offset (AT, &offset_expr);
7005208737Sjmallett	  load_delay_nop ();
7006179404Sobrien	  if (breg != 0)
7007179404Sobrien	    macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
7008179404Sobrien
7009179404Sobrien	  /* Set mips_optimize to 2 to avoid inserting an undesired
7010179404Sobrien             nop.  */
7011179404Sobrien	  hold_mips_optimize = mips_optimize;
7012179404Sobrien	  mips_optimize = 2;
7013179404Sobrien
7014179404Sobrien	  /* Itbl support may require additional care here.  */
7015179404Sobrien	  relax_start (offset_expr.X_add_symbol);
7016179404Sobrien	  macro_build (&expr1, s, fmt, coproc ? treg + 1 : treg,
7017179404Sobrien		       BFD_RELOC_LO16, AT);
7018179404Sobrien	  expr1.X_add_number += 4;
7019179404Sobrien	  macro_build (&expr1, s, fmt, coproc ? treg : treg + 1,
7020179404Sobrien		       BFD_RELOC_LO16, AT);
7021179404Sobrien	  relax_switch ();
7022179404Sobrien	  macro_build (&offset_expr, s, fmt, coproc ? treg + 1 : treg,
7023179404Sobrien		       BFD_RELOC_LO16, AT);
7024179404Sobrien	  offset_expr.X_add_number += 4;
7025179404Sobrien	  macro_build (&offset_expr, s, fmt, coproc ? treg : treg + 1,
7026179404Sobrien		       BFD_RELOC_LO16, AT);
7027179404Sobrien	  relax_end ();
7028179404Sobrien
7029179404Sobrien	  mips_optimize = hold_mips_optimize;
7030179404Sobrien	}
7031208737Sjmallett      else if (mips_big_got)
7032179404Sobrien	{
7033179404Sobrien	  int gpdelay;
7034179404Sobrien
7035179404Sobrien	  /* If this is a reference to an external symbol, we want
7036179404Sobrien	       lui	$at,<sym>		(BFD_RELOC_MIPS_GOT_HI16)
7037179404Sobrien	       addu	$at,$at,$gp
7038179404Sobrien	       lw	$at,<sym>($at)		(BFD_RELOC_MIPS_GOT_LO16)
7039179404Sobrien	       nop
7040179404Sobrien	       <op>	$treg,0($at)
7041179404Sobrien	       <op>	$treg+1,4($at)
7042179404Sobrien	     Otherwise we want
7043179404Sobrien	       lw	$at,<sym>($gp)		(BFD_RELOC_MIPS_GOT16)
7044179404Sobrien	       nop
7045179404Sobrien	       <op>	$treg,<sym>($at)	(BFD_RELOC_LO16)
7046179404Sobrien	       <op>	$treg+1,<sym>+4($at)	(BFD_RELOC_LO16)
7047179404Sobrien	     If there is a base register we add it to $at before the
7048179404Sobrien	     lwc1 instructions.  If there is a constant we include it
7049179404Sobrien	     in the lwc1 instructions.  */
7050179404Sobrien	  used_at = 1;
7051179404Sobrien	  expr1.X_add_number = offset_expr.X_add_number;
7052179404Sobrien	  offset_expr.X_add_number = 0;
7053179404Sobrien	  if (expr1.X_add_number < -0x8000
7054179404Sobrien	      || expr1.X_add_number >= 0x8000 - 4)
7055179404Sobrien	    as_bad (_("PIC code offset overflow (max 16 signed bits)"));
7056179404Sobrien	  gpdelay = reg_needs_delay (mips_gp_register);
7057179404Sobrien	  relax_start (offset_expr.X_add_symbol);
7058179404Sobrien	  macro_build (&offset_expr, "lui", "t,u",
7059179404Sobrien		       AT, BFD_RELOC_MIPS_GOT_HI16);
7060179404Sobrien	  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t",
7061179404Sobrien		       AT, AT, mips_gp_register);
7062179404Sobrien	  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)",
7063179404Sobrien		       AT, BFD_RELOC_MIPS_GOT_LO16, AT);
7064208737Sjmallett	  load_delay_nop ();
7065179404Sobrien	  if (breg != 0)
7066179404Sobrien	    macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
7067179404Sobrien	  /* Itbl support may require additional care here.  */
7068179404Sobrien	  macro_build (&expr1, s, fmt, coproc ? treg + 1 : treg,
7069179404Sobrien		       BFD_RELOC_LO16, AT);
7070179404Sobrien	  expr1.X_add_number += 4;
7071179404Sobrien
7072179404Sobrien	  /* Set mips_optimize to 2 to avoid inserting an undesired
7073179404Sobrien             nop.  */
7074179404Sobrien	  hold_mips_optimize = mips_optimize;
7075179404Sobrien	  mips_optimize = 2;
7076179404Sobrien	  /* Itbl support may require additional care here.  */
7077179404Sobrien	  macro_build (&expr1, s, fmt, coproc ? treg : treg + 1,
7078179404Sobrien		       BFD_RELOC_LO16, AT);
7079179404Sobrien	  mips_optimize = hold_mips_optimize;
7080179404Sobrien	  expr1.X_add_number -= 4;
7081179404Sobrien
7082179404Sobrien	  relax_switch ();
7083179404Sobrien	  offset_expr.X_add_number = expr1.X_add_number;
7084179404Sobrien	  if (gpdelay)
7085179404Sobrien	    macro_build (NULL, "nop", "");
7086179404Sobrien	  macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", AT,
7087179404Sobrien		       BFD_RELOC_MIPS_GOT16, mips_gp_register);
7088208737Sjmallett	  load_delay_nop ();
7089179404Sobrien	  if (breg != 0)
7090179404Sobrien	    macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, breg, AT);
7091179404Sobrien	  /* Itbl support may require additional care here.  */
7092179404Sobrien	  macro_build (&offset_expr, s, fmt, coproc ? treg + 1 : treg,
7093179404Sobrien		       BFD_RELOC_LO16, AT);
7094179404Sobrien	  offset_expr.X_add_number += 4;
7095179404Sobrien
7096179404Sobrien	  /* Set mips_optimize to 2 to avoid inserting an undesired
7097179404Sobrien             nop.  */
7098179404Sobrien	  hold_mips_optimize = mips_optimize;
7099179404Sobrien	  mips_optimize = 2;
7100179404Sobrien	  /* Itbl support may require additional care here.  */
7101179404Sobrien	  macro_build (&offset_expr, s, fmt, coproc ? treg : treg + 1,
7102179404Sobrien		       BFD_RELOC_LO16, AT);
7103179404Sobrien	  mips_optimize = hold_mips_optimize;
7104179404Sobrien	  relax_end ();
7105179404Sobrien	}
7106179404Sobrien      else
7107179404Sobrien	abort ();
7108179404Sobrien
7109179404Sobrien      break;
7110179404Sobrien
7111179404Sobrien    case M_LD_OB:
7112179404Sobrien      s = "lw";
7113179404Sobrien      goto sd_ob;
7114179404Sobrien    case M_SD_OB:
7115179404Sobrien      s = "sw";
7116179404Sobrien    sd_ob:
7117179404Sobrien      assert (HAVE_32BIT_ADDRESSES);
7118179404Sobrien      macro_build (&offset_expr, s, "t,o(b)", treg, BFD_RELOC_LO16, breg);
7119179404Sobrien      offset_expr.X_add_number += 4;
7120179404Sobrien      macro_build (&offset_expr, s, "t,o(b)", treg + 1, BFD_RELOC_LO16, breg);
7121208737Sjmallett      break;
7122179404Sobrien
7123208737Sjmallett    case M_SAA_AB:
7124208737Sjmallett      s = "saa";
7125208737Sjmallett      goto saa_saad;
7126208737Sjmallett
7127208737Sjmallett    case M_SAAD_AB:
7128208737Sjmallett      s = "saad";
7129208737Sjmallett
7130208737Sjmallett      saa_saad:
7131208737Sjmallett      /* The "saa/saad" instructions are new in CN58XX. These instructions
7132208737Sjmallett	 do not specify offset. When invoked with address or symbol, then
7133208737Sjmallett	 load the address or value of symbol in a register using the dla macro
7134208737Sjmallett	 into AT, and pass the register for emitting "saa/saad" instruction.
7135208737Sjmallett	 This will get expanded to
7136208737Sjmallett
7137208737Sjmallett	    dla AT, constant/label
7138208737Sjmallett	    saa/saad $treg,(AT)  */
7139208737Sjmallett      {
7140208737Sjmallett	char *name = "dla";
7141208737Sjmallett	char *fmt = "t,A(b)";
7142208737Sjmallett	const struct mips_opcode *mo;
7143208737Sjmallett  	struct mips_cl_insn insn;
7144208737Sjmallett
7145208737Sjmallett	mo = hash_find (op_hash, name);
7146208737Sjmallett	assert (strcmp (name, mo->name) == 0);
7147208737Sjmallett	assert (strcmp (fmt, mo->args) == 0);
7148208737Sjmallett	create_insn (&insn, mo);
7149208737Sjmallett
7150208737Sjmallett	insn.insn_opcode = insn.insn_mo->match;
7151208737Sjmallett
7152208737Sjmallett	used_at = 1;
7153208737Sjmallett	INSERT_OPERAND (RT, insn, AT);
7154208737Sjmallett	if (breg)
7155208737Sjmallett	  INSERT_OPERAND (RS, insn, breg);
7156208737Sjmallett
7157208737Sjmallett	/* The address part is forwarded through the global offset_expr. */
7158208737Sjmallett	macro (&insn);
7159208737Sjmallett
7160208737Sjmallett	macro_build (NULL, s, "t,(b)", treg, AT);
7161208737Sjmallett	break;
7162208737Sjmallett     }
7163208737Sjmallett
7164179404Sobrien   /* New code added to support COPZ instructions.
7165179404Sobrien      This code builds table entries out of the macros in mip_opcodes.
7166179404Sobrien      R4000 uses interlocks to handle coproc delays.
7167179404Sobrien      Other chips (like the R3000) require nops to be inserted for delays.
7168179404Sobrien
7169179404Sobrien      FIXME: Currently, we require that the user handle delays.
7170179404Sobrien      In order to fill delay slots for non-interlocked chips,
7171179404Sobrien      we must have a way to specify delays based on the coprocessor.
7172179404Sobrien      Eg. 4 cycles if load coproc reg from memory, 1 if in cache, etc.
7173179404Sobrien      What are the side-effects of the cop instruction?
7174179404Sobrien      What cache support might we have and what are its effects?
7175179404Sobrien      Both coprocessor & memory require delays. how long???
7176179404Sobrien      What registers are read/set/modified?
7177179404Sobrien
7178179404Sobrien      If an itbl is provided to interpret cop instructions,
7179179404Sobrien      this knowledge can be encoded in the itbl spec.  */
7180179404Sobrien
7181179404Sobrien    case M_COP0:
7182179404Sobrien      s = "c0";
7183179404Sobrien      goto copz;
7184179404Sobrien    case M_COP1:
7185179404Sobrien      s = "c1";
7186179404Sobrien      goto copz;
7187179404Sobrien    case M_COP2:
7188179404Sobrien      s = "c2";
7189179404Sobrien      goto copz;
7190179404Sobrien    case M_COP3:
7191179404Sobrien      s = "c3";
7192179404Sobrien    copz:
7193208737Sjmallett      if (!strcmp (s,"c2") && mips_opts.arch == CPU_OCTEON
7194208737Sjmallett	  && octeon_error_on_unsupported)
7195208737Sjmallett        {
7196208737Sjmallett          as_bad (_("opcode not implemented in Octeon `%s'"), ip->insn_mo->name);
7197208737Sjmallett          return;
7198208737Sjmallett        }
7199179404Sobrien      /* For now we just do C (same as Cz).  The parameter will be
7200179404Sobrien         stored in insn_opcode by mips_ip.  */
7201179404Sobrien      macro_build (NULL, s, "C", ip->insn_opcode);
7202208737Sjmallett      break;
7203179404Sobrien
7204179404Sobrien    case M_MOVE:
7205179404Sobrien      move_register (dreg, sreg);
7206208737Sjmallett      break;
7207179404Sobrien
7208179404Sobrien#ifdef LOSING_COMPILER
7209179404Sobrien    default:
7210179404Sobrien      /* Try and see if this is a new itbl instruction.
7211179404Sobrien         This code builds table entries out of the macros in mip_opcodes.
7212179404Sobrien         FIXME: For now we just assemble the expression and pass it's
7213179404Sobrien         value along as a 32-bit immediate.
7214179404Sobrien         We may want to have the assembler assemble this value,
7215179404Sobrien         so that we gain the assembler's knowledge of delay slots,
7216179404Sobrien         symbols, etc.
7217179404Sobrien         Would it be more efficient to use mask (id) here? */
7218179404Sobrien      if (itbl_have_entries
7219179404Sobrien	  && (immed_expr = itbl_assemble (ip->insn_mo->name, "")))
7220179404Sobrien	{
7221179404Sobrien	  s = ip->insn_mo->name;
7222179404Sobrien	  s2 = "cop3";
7223179404Sobrien	  coproc = ITBL_DECODE_PNUM (immed_expr);;
7224179404Sobrien	  macro_build (&immed_expr, s, "C");
7225208737Sjmallett	  break;
7226179404Sobrien	}
7227179404Sobrien      macro2 (ip);
7228208737Sjmallett      break;
7229179404Sobrien    }
7230208737Sjmallett  if (mips_opts.noat && used_at)
7231208737Sjmallett    as_bad (_("Macro used $at after \".set noat\""));
7232179404Sobrien}
7233179404Sobrien
7234179404Sobrienstatic void
7235179404Sobrienmacro2 (struct mips_cl_insn *ip)
7236179404Sobrien{
7237218822Sdim  int treg, sreg, dreg, breg;
7238179404Sobrien  int tempreg;
7239179404Sobrien  int mask;
7240179404Sobrien  int used_at;
7241179404Sobrien  expressionS expr1;
7242179404Sobrien  const char *s;
7243179404Sobrien  const char *s2;
7244179404Sobrien  const char *fmt;
7245179404Sobrien  int likely = 0;
7246179404Sobrien  int dbl = 0;
7247179404Sobrien  int coproc = 0;
7248179404Sobrien  int lr = 0;
7249179404Sobrien  int imm = 0;
7250179404Sobrien  int off;
7251179404Sobrien  offsetT maxnum;
7252179404Sobrien  bfd_reloc_code_real_type r;
7253179404Sobrien
7254179404Sobrien  treg = (ip->insn_opcode >> 16) & 0x1f;
7255179404Sobrien  dreg = (ip->insn_opcode >> 11) & 0x1f;
7256179404Sobrien  sreg = breg = (ip->insn_opcode >> 21) & 0x1f;
7257179404Sobrien  mask = ip->insn_mo->mask;
7258179404Sobrien
7259179404Sobrien  expr1.X_op = O_constant;
7260179404Sobrien  expr1.X_op_symbol = NULL;
7261179404Sobrien  expr1.X_add_symbol = NULL;
7262179404Sobrien  expr1.X_add_number = 1;
7263179404Sobrien
7264179404Sobrien  switch (mask)
7265179404Sobrien    {
7266179404Sobrien#endif /* LOSING_COMPILER */
7267179404Sobrien
7268179404Sobrien    case M_DMUL:
7269179404Sobrien      dbl = 1;
7270179404Sobrien    case M_MUL:
7271179404Sobrien      macro_build (NULL, dbl ? "dmultu" : "multu", "s,t", sreg, treg);
7272179404Sobrien      macro_build (NULL, "mflo", "d", dreg);
7273208737Sjmallett      break;
7274179404Sobrien
7275179404Sobrien    case M_DMUL_I:
7276179404Sobrien      dbl = 1;
7277179404Sobrien    case M_MUL_I:
7278179404Sobrien      /* The MIPS assembler some times generates shifts and adds.  I'm
7279179404Sobrien	 not trying to be that fancy. GCC should do this for us
7280179404Sobrien	 anyway.  */
7281208737Sjmallett      used_at = 1;
7282179404Sobrien      load_register (AT, &imm_expr, dbl);
7283179404Sobrien      macro_build (NULL, dbl ? "dmult" : "mult", "s,t", sreg, AT);
7284179404Sobrien      macro_build (NULL, "mflo", "d", dreg);
7285179404Sobrien      break;
7286179404Sobrien
7287179404Sobrien    case M_DMULO_I:
7288179404Sobrien      dbl = 1;
7289179404Sobrien    case M_MULO_I:
7290179404Sobrien      imm = 1;
7291179404Sobrien      goto do_mulo;
7292179404Sobrien
7293179404Sobrien    case M_DMULO:
7294179404Sobrien      dbl = 1;
7295179404Sobrien    case M_MULO:
7296179404Sobrien    do_mulo:
7297208737Sjmallett      start_noreorder ();
7298208737Sjmallett      used_at = 1;
7299179404Sobrien      if (imm)
7300179404Sobrien	load_register (AT, &imm_expr, dbl);
7301179404Sobrien      macro_build (NULL, dbl ? "dmult" : "mult", "s,t", sreg, imm ? AT : treg);
7302179404Sobrien      macro_build (NULL, "mflo", "d", dreg);
7303179404Sobrien      macro_build (NULL, dbl ? "dsra32" : "sra", "d,w,<", dreg, dreg, RA);
7304179404Sobrien      macro_build (NULL, "mfhi", "d", AT);
7305179404Sobrien      if (mips_trap)
7306179404Sobrien	macro_build (NULL, "tne", "s,t,q", dreg, AT, 6);
7307179404Sobrien      else
7308179404Sobrien	{
7309179404Sobrien	  expr1.X_add_number = 8;
7310179404Sobrien	  macro_build (&expr1, "beq", "s,t,p", dreg, AT);
7311179404Sobrien	  macro_build (NULL, "nop", "", 0);
7312179404Sobrien	  macro_build (NULL, "break", "c", 6);
7313179404Sobrien	}
7314208737Sjmallett      end_noreorder ();
7315179404Sobrien      macro_build (NULL, "mflo", "d", dreg);
7316179404Sobrien      break;
7317179404Sobrien
7318179404Sobrien    case M_DMULOU_I:
7319179404Sobrien      dbl = 1;
7320179404Sobrien    case M_MULOU_I:
7321179404Sobrien      imm = 1;
7322179404Sobrien      goto do_mulou;
7323179404Sobrien
7324179404Sobrien    case M_DMULOU:
7325179404Sobrien      dbl = 1;
7326179404Sobrien    case M_MULOU:
7327179404Sobrien    do_mulou:
7328208737Sjmallett      start_noreorder ();
7329208737Sjmallett      used_at = 1;
7330179404Sobrien      if (imm)
7331179404Sobrien	load_register (AT, &imm_expr, dbl);
7332179404Sobrien      macro_build (NULL, dbl ? "dmultu" : "multu", "s,t",
7333179404Sobrien		   sreg, imm ? AT : treg);
7334179404Sobrien      macro_build (NULL, "mfhi", "d", AT);
7335179404Sobrien      macro_build (NULL, "mflo", "d", dreg);
7336179404Sobrien      if (mips_trap)
7337179404Sobrien	macro_build (NULL, "tne", "s,t,q", AT, 0, 6);
7338179404Sobrien      else
7339179404Sobrien	{
7340179404Sobrien	  expr1.X_add_number = 8;
7341179404Sobrien	  macro_build (&expr1, "beq", "s,t,p", AT, 0);
7342179404Sobrien	  macro_build (NULL, "nop", "", 0);
7343179404Sobrien	  macro_build (NULL, "break", "c", 6);
7344179404Sobrien	}
7345208737Sjmallett      end_noreorder ();
7346179404Sobrien      break;
7347179404Sobrien
7348179404Sobrien    case M_DROL:
7349179404Sobrien      if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
7350179404Sobrien	{
7351179404Sobrien	  if (dreg == sreg)
7352179404Sobrien	    {
7353179404Sobrien	      tempreg = AT;
7354179404Sobrien	      used_at = 1;
7355179404Sobrien	    }
7356179404Sobrien	  else
7357179404Sobrien	    {
7358179404Sobrien	      tempreg = dreg;
7359179404Sobrien	    }
7360179404Sobrien	  macro_build (NULL, "dnegu", "d,w", tempreg, treg);
7361179404Sobrien	  macro_build (NULL, "drorv", "d,t,s", dreg, sreg, tempreg);
7362208737Sjmallett	  break;
7363179404Sobrien	}
7364208737Sjmallett      used_at = 1;
7365179404Sobrien      macro_build (NULL, "dsubu", "d,v,t", AT, 0, treg);
7366179404Sobrien      macro_build (NULL, "dsrlv", "d,t,s", AT, sreg, AT);
7367179404Sobrien      macro_build (NULL, "dsllv", "d,t,s", dreg, sreg, treg);
7368179404Sobrien      macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
7369179404Sobrien      break;
7370179404Sobrien
7371179404Sobrien    case M_ROL:
7372179404Sobrien      if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
7373179404Sobrien	{
7374179404Sobrien	  if (dreg == sreg)
7375179404Sobrien	    {
7376179404Sobrien	      tempreg = AT;
7377179404Sobrien	      used_at = 1;
7378179404Sobrien	    }
7379179404Sobrien	  else
7380179404Sobrien	    {
7381179404Sobrien	      tempreg = dreg;
7382179404Sobrien	    }
7383179404Sobrien	  macro_build (NULL, "negu", "d,w", tempreg, treg);
7384179404Sobrien	  macro_build (NULL, "rorv", "d,t,s", dreg, sreg, tempreg);
7385208737Sjmallett	  break;
7386179404Sobrien	}
7387208737Sjmallett      used_at = 1;
7388179404Sobrien      macro_build (NULL, "subu", "d,v,t", AT, 0, treg);
7389179404Sobrien      macro_build (NULL, "srlv", "d,t,s", AT, sreg, AT);
7390179404Sobrien      macro_build (NULL, "sllv", "d,t,s", dreg, sreg, treg);
7391179404Sobrien      macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
7392179404Sobrien      break;
7393179404Sobrien
7394179404Sobrien    case M_DROL_I:
7395179404Sobrien      {
7396179404Sobrien	unsigned int rot;
7397179404Sobrien	char *l, *r;
7398179404Sobrien
7399179404Sobrien	if (imm_expr.X_op != O_constant)
7400179404Sobrien	  as_bad (_("Improper rotate count"));
7401179404Sobrien	rot = imm_expr.X_add_number & 0x3f;
7402179404Sobrien	if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
7403179404Sobrien	  {
7404179404Sobrien	    rot = (64 - rot) & 0x3f;
7405179404Sobrien	    if (rot >= 32)
7406179404Sobrien	      macro_build (NULL, "dror32", "d,w,<", dreg, sreg, rot - 32);
7407179404Sobrien	    else
7408179404Sobrien	      macro_build (NULL, "dror", "d,w,<", dreg, sreg, rot);
7409208737Sjmallett	    break;
7410179404Sobrien	  }
7411179404Sobrien	if (rot == 0)
7412179404Sobrien	  {
7413179404Sobrien	    macro_build (NULL, "dsrl", "d,w,<", dreg, sreg, 0);
7414208737Sjmallett	    break;
7415179404Sobrien	  }
7416179404Sobrien	l = (rot < 0x20) ? "dsll" : "dsll32";
7417179404Sobrien	r = ((0x40 - rot) < 0x20) ? "dsrl" : "dsrl32";
7418179404Sobrien	rot &= 0x1f;
7419208737Sjmallett	used_at = 1;
7420179404Sobrien	macro_build (NULL, l, "d,w,<", AT, sreg, rot);
7421179404Sobrien	macro_build (NULL, r, "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
7422179404Sobrien	macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
7423179404Sobrien      }
7424179404Sobrien      break;
7425179404Sobrien
7426179404Sobrien    case M_ROL_I:
7427179404Sobrien      {
7428179404Sobrien	unsigned int rot;
7429179404Sobrien
7430179404Sobrien	if (imm_expr.X_op != O_constant)
7431179404Sobrien	  as_bad (_("Improper rotate count"));
7432179404Sobrien	rot = imm_expr.X_add_number & 0x1f;
7433179404Sobrien	if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
7434179404Sobrien	  {
7435179404Sobrien	    macro_build (NULL, "ror", "d,w,<", dreg, sreg, (32 - rot) & 0x1f);
7436208737Sjmallett	    break;
7437179404Sobrien	  }
7438179404Sobrien	if (rot == 0)
7439179404Sobrien	  {
7440179404Sobrien	    macro_build (NULL, "srl", "d,w,<", dreg, sreg, 0);
7441208737Sjmallett	    break;
7442179404Sobrien	  }
7443208737Sjmallett	used_at = 1;
7444179404Sobrien	macro_build (NULL, "sll", "d,w,<", AT, sreg, rot);
7445179404Sobrien	macro_build (NULL, "srl", "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
7446179404Sobrien	macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
7447179404Sobrien      }
7448179404Sobrien      break;
7449179404Sobrien
7450179404Sobrien    case M_DROR:
7451179404Sobrien      if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
7452179404Sobrien	{
7453179404Sobrien	  macro_build (NULL, "drorv", "d,t,s", dreg, sreg, treg);
7454208737Sjmallett	  break;
7455179404Sobrien	}
7456208737Sjmallett      used_at = 1;
7457179404Sobrien      macro_build (NULL, "dsubu", "d,v,t", AT, 0, treg);
7458179404Sobrien      macro_build (NULL, "dsllv", "d,t,s", AT, sreg, AT);
7459179404Sobrien      macro_build (NULL, "dsrlv", "d,t,s", dreg, sreg, treg);
7460179404Sobrien      macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
7461179404Sobrien      break;
7462179404Sobrien
7463179404Sobrien    case M_ROR:
7464179404Sobrien      if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
7465179404Sobrien	{
7466179404Sobrien	  macro_build (NULL, "rorv", "d,t,s", dreg, sreg, treg);
7467208737Sjmallett	  break;
7468179404Sobrien	}
7469208737Sjmallett      used_at = 1;
7470179404Sobrien      macro_build (NULL, "subu", "d,v,t", AT, 0, treg);
7471179404Sobrien      macro_build (NULL, "sllv", "d,t,s", AT, sreg, AT);
7472179404Sobrien      macro_build (NULL, "srlv", "d,t,s", dreg, sreg, treg);
7473179404Sobrien      macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
7474179404Sobrien      break;
7475179404Sobrien
7476179404Sobrien    case M_DROR_I:
7477179404Sobrien      {
7478179404Sobrien	unsigned int rot;
7479179404Sobrien	char *l, *r;
7480179404Sobrien
7481179404Sobrien	if (imm_expr.X_op != O_constant)
7482179404Sobrien	  as_bad (_("Improper rotate count"));
7483179404Sobrien	rot = imm_expr.X_add_number & 0x3f;
7484179404Sobrien	if (ISA_HAS_DROR (mips_opts.isa) || CPU_HAS_DROR (mips_opts.arch))
7485179404Sobrien	  {
7486179404Sobrien	    if (rot >= 32)
7487179404Sobrien	      macro_build (NULL, "dror32", "d,w,<", dreg, sreg, rot - 32);
7488179404Sobrien	    else
7489179404Sobrien	      macro_build (NULL, "dror", "d,w,<", dreg, sreg, rot);
7490208737Sjmallett	    break;
7491179404Sobrien	  }
7492179404Sobrien	if (rot == 0)
7493179404Sobrien	  {
7494179404Sobrien	    macro_build (NULL, "dsrl", "d,w,<", dreg, sreg, 0);
7495208737Sjmallett	    break;
7496179404Sobrien	  }
7497179404Sobrien	r = (rot < 0x20) ? "dsrl" : "dsrl32";
7498179404Sobrien	l = ((0x40 - rot) < 0x20) ? "dsll" : "dsll32";
7499179404Sobrien	rot &= 0x1f;
7500208737Sjmallett	used_at = 1;
7501179404Sobrien	macro_build (NULL, r, "d,w,<", AT, sreg, rot);
7502179404Sobrien	macro_build (NULL, l, "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
7503179404Sobrien	macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
7504179404Sobrien      }
7505179404Sobrien      break;
7506179404Sobrien
7507179404Sobrien    case M_ROR_I:
7508179404Sobrien      {
7509179404Sobrien	unsigned int rot;
7510179404Sobrien
7511179404Sobrien	if (imm_expr.X_op != O_constant)
7512179404Sobrien	  as_bad (_("Improper rotate count"));
7513179404Sobrien	rot = imm_expr.X_add_number & 0x1f;
7514179404Sobrien	if (ISA_HAS_ROR (mips_opts.isa) || CPU_HAS_ROR (mips_opts.arch))
7515179404Sobrien	  {
7516179404Sobrien	    macro_build (NULL, "ror", "d,w,<", dreg, sreg, rot);
7517208737Sjmallett	    break;
7518179404Sobrien	  }
7519179404Sobrien	if (rot == 0)
7520179404Sobrien	  {
7521179404Sobrien	    macro_build (NULL, "srl", "d,w,<", dreg, sreg, 0);
7522208737Sjmallett	    break;
7523179404Sobrien	  }
7524208737Sjmallett	used_at = 1;
7525179404Sobrien	macro_build (NULL, "srl", "d,w,<", AT, sreg, rot);
7526179404Sobrien	macro_build (NULL, "sll", "d,w,<", dreg, sreg, (0x20 - rot) & 0x1f);
7527179404Sobrien	macro_build (NULL, "or", "d,v,t", dreg, dreg, AT);
7528179404Sobrien      }
7529179404Sobrien      break;
7530179404Sobrien
7531179404Sobrien    case M_S_DOB:
7532179404Sobrien      if (mips_opts.arch == CPU_R4650)
7533179404Sobrien	{
7534179404Sobrien	  as_bad (_("opcode not supported on this processor"));
7535208737Sjmallett	  break;
7536179404Sobrien	}
7537179404Sobrien      assert (mips_opts.isa == ISA_MIPS1);
7538179404Sobrien      /* Even on a big endian machine $fn comes before $fn+1.  We have
7539179404Sobrien	 to adjust when storing to memory.  */
7540179404Sobrien      macro_build (&offset_expr, "swc1", "T,o(b)",
7541179404Sobrien		   target_big_endian ? treg + 1 : treg, BFD_RELOC_LO16, breg);
7542179404Sobrien      offset_expr.X_add_number += 4;
7543179404Sobrien      macro_build (&offset_expr, "swc1", "T,o(b)",
7544179404Sobrien		   target_big_endian ? treg : treg + 1, BFD_RELOC_LO16, breg);
7545208737Sjmallett      break;
7546179404Sobrien
7547179404Sobrien    case M_SEQ:
7548179404Sobrien      if (sreg == 0)
7549179404Sobrien	macro_build (&expr1, "sltiu", "t,r,j", dreg, treg, BFD_RELOC_LO16);
7550179404Sobrien      else if (treg == 0)
7551179404Sobrien	macro_build (&expr1, "sltiu", "t,r,j", dreg, sreg, BFD_RELOC_LO16);
7552179404Sobrien      else
7553179404Sobrien	{
7554179404Sobrien	  macro_build (NULL, "xor", "d,v,t", dreg, sreg, treg);
7555179404Sobrien	  macro_build (&expr1, "sltiu", "t,r,j", dreg, dreg, BFD_RELOC_LO16);
7556179404Sobrien	}
7557208737Sjmallett      break;
7558179404Sobrien
7559179404Sobrien    case M_SEQ_I:
7560179404Sobrien      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
7561179404Sobrien	{
7562179404Sobrien	  macro_build (&expr1, "sltiu", "t,r,j", dreg, sreg, BFD_RELOC_LO16);
7563208737Sjmallett	  break;
7564179404Sobrien	}
7565179404Sobrien      if (sreg == 0)
7566179404Sobrien	{
7567179404Sobrien	  as_warn (_("Instruction %s: result is always false"),
7568179404Sobrien		   ip->insn_mo->name);
7569179404Sobrien	  move_register (dreg, 0);
7570208737Sjmallett	  break;
7571179404Sobrien	}
7572179404Sobrien      if (imm_expr.X_op == O_constant
7573179404Sobrien	  && imm_expr.X_add_number >= 0
7574179404Sobrien	  && imm_expr.X_add_number < 0x10000)
7575179404Sobrien	{
7576179404Sobrien	  macro_build (&imm_expr, "xori", "t,r,i", dreg, sreg, BFD_RELOC_LO16);
7577179404Sobrien	}
7578179404Sobrien      else if (imm_expr.X_op == O_constant
7579179404Sobrien	       && imm_expr.X_add_number > -0x8000
7580179404Sobrien	       && imm_expr.X_add_number < 0)
7581179404Sobrien	{
7582179404Sobrien	  imm_expr.X_add_number = -imm_expr.X_add_number;
7583179404Sobrien	  macro_build (&imm_expr, HAVE_32BIT_GPRS ? "addiu" : "daddiu",
7584179404Sobrien		       "t,r,j", dreg, sreg, BFD_RELOC_LO16);
7585179404Sobrien	}
7586179404Sobrien      else
7587179404Sobrien	{
7588179404Sobrien	  load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
7589179404Sobrien	  macro_build (NULL, "xor", "d,v,t", dreg, sreg, AT);
7590179404Sobrien	  used_at = 1;
7591179404Sobrien	}
7592179404Sobrien      macro_build (&expr1, "sltiu", "t,r,j", dreg, dreg, BFD_RELOC_LO16);
7593208737Sjmallett      break;
7594179404Sobrien
7595179404Sobrien    case M_SGE:		/* sreg >= treg <==> not (sreg < treg) */
7596179404Sobrien      s = "slt";
7597179404Sobrien      goto sge;
7598179404Sobrien    case M_SGEU:
7599179404Sobrien      s = "sltu";
7600179404Sobrien    sge:
7601179404Sobrien      macro_build (NULL, s, "d,v,t", dreg, sreg, treg);
7602179404Sobrien      macro_build (&expr1, "xori", "t,r,i", dreg, dreg, BFD_RELOC_LO16);
7603208737Sjmallett      break;
7604179404Sobrien
7605179404Sobrien    case M_SGE_I:		/* sreg >= I <==> not (sreg < I) */
7606179404Sobrien    case M_SGEU_I:
7607179404Sobrien      if (imm_expr.X_op == O_constant
7608179404Sobrien	  && imm_expr.X_add_number >= -0x8000
7609179404Sobrien	  && imm_expr.X_add_number < 0x8000)
7610179404Sobrien	{
7611179404Sobrien	  macro_build (&imm_expr, mask == M_SGE_I ? "slti" : "sltiu", "t,r,j",
7612179404Sobrien		       dreg, sreg, BFD_RELOC_LO16);
7613179404Sobrien	}
7614179404Sobrien      else
7615179404Sobrien	{
7616179404Sobrien	  load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
7617179404Sobrien	  macro_build (NULL, mask == M_SGE_I ? "slt" : "sltu", "d,v,t",
7618179404Sobrien		       dreg, sreg, AT);
7619179404Sobrien	  used_at = 1;
7620179404Sobrien	}
7621179404Sobrien      macro_build (&expr1, "xori", "t,r,i", dreg, dreg, BFD_RELOC_LO16);
7622208737Sjmallett      break;
7623179404Sobrien
7624179404Sobrien    case M_SGT:		/* sreg > treg  <==>  treg < sreg */
7625179404Sobrien      s = "slt";
7626179404Sobrien      goto sgt;
7627179404Sobrien    case M_SGTU:
7628179404Sobrien      s = "sltu";
7629179404Sobrien    sgt:
7630179404Sobrien      macro_build (NULL, s, "d,v,t", dreg, treg, sreg);
7631208737Sjmallett      break;
7632179404Sobrien
7633179404Sobrien    case M_SGT_I:		/* sreg > I  <==>  I < sreg */
7634179404Sobrien      s = "slt";
7635179404Sobrien      goto sgti;
7636179404Sobrien    case M_SGTU_I:
7637179404Sobrien      s = "sltu";
7638179404Sobrien    sgti:
7639208737Sjmallett      used_at = 1;
7640179404Sobrien      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
7641179404Sobrien      macro_build (NULL, s, "d,v,t", dreg, AT, sreg);
7642179404Sobrien      break;
7643179404Sobrien
7644179404Sobrien    case M_SLE:	/* sreg <= treg  <==>  treg >= sreg  <==>  not (treg < sreg) */
7645179404Sobrien      s = "slt";
7646179404Sobrien      goto sle;
7647179404Sobrien    case M_SLEU:
7648179404Sobrien      s = "sltu";
7649179404Sobrien    sle:
7650179404Sobrien      macro_build (NULL, s, "d,v,t", dreg, treg, sreg);
7651179404Sobrien      macro_build (&expr1, "xori", "t,r,i", dreg, dreg, BFD_RELOC_LO16);
7652208737Sjmallett      break;
7653179404Sobrien
7654179404Sobrien    case M_SLE_I:	/* sreg <= I <==> I >= sreg <==> not (I < sreg) */
7655179404Sobrien      s = "slt";
7656179404Sobrien      goto slei;
7657179404Sobrien    case M_SLEU_I:
7658179404Sobrien      s = "sltu";
7659179404Sobrien    slei:
7660208737Sjmallett      used_at = 1;
7661179404Sobrien      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
7662179404Sobrien      macro_build (NULL, s, "d,v,t", dreg, AT, sreg);
7663179404Sobrien      macro_build (&expr1, "xori", "t,r,i", dreg, dreg, BFD_RELOC_LO16);
7664179404Sobrien      break;
7665179404Sobrien
7666179404Sobrien    case M_SLT_I:
7667179404Sobrien      if (imm_expr.X_op == O_constant
7668179404Sobrien	  && imm_expr.X_add_number >= -0x8000
7669179404Sobrien	  && imm_expr.X_add_number < 0x8000)
7670179404Sobrien	{
7671179404Sobrien	  macro_build (&imm_expr, "slti", "t,r,j", dreg, sreg, BFD_RELOC_LO16);
7672208737Sjmallett	  break;
7673179404Sobrien	}
7674208737Sjmallett      used_at = 1;
7675179404Sobrien      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
7676179404Sobrien      macro_build (NULL, "slt", "d,v,t", dreg, sreg, AT);
7677179404Sobrien      break;
7678179404Sobrien
7679179404Sobrien    case M_SLTU_I:
7680179404Sobrien      if (imm_expr.X_op == O_constant
7681179404Sobrien	  && imm_expr.X_add_number >= -0x8000
7682179404Sobrien	  && imm_expr.X_add_number < 0x8000)
7683179404Sobrien	{
7684179404Sobrien	  macro_build (&imm_expr, "sltiu", "t,r,j", dreg, sreg,
7685179404Sobrien		       BFD_RELOC_LO16);
7686208737Sjmallett	  break;
7687179404Sobrien	}
7688208737Sjmallett      used_at = 1;
7689179404Sobrien      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
7690179404Sobrien      macro_build (NULL, "sltu", "d,v,t", dreg, sreg, AT);
7691179404Sobrien      break;
7692179404Sobrien
7693179404Sobrien    case M_SNE:
7694179404Sobrien      if (sreg == 0)
7695179404Sobrien	macro_build (NULL, "sltu", "d,v,t", dreg, 0, treg);
7696179404Sobrien      else if (treg == 0)
7697179404Sobrien	macro_build (NULL, "sltu", "d,v,t", dreg, 0, sreg);
7698179404Sobrien      else
7699179404Sobrien	{
7700179404Sobrien	  macro_build (NULL, "xor", "d,v,t", dreg, sreg, treg);
7701179404Sobrien	  macro_build (NULL, "sltu", "d,v,t", dreg, 0, dreg);
7702179404Sobrien	}
7703208737Sjmallett      break;
7704179404Sobrien
7705179404Sobrien    case M_SNE_I:
7706179404Sobrien      if (imm_expr.X_op == O_constant && imm_expr.X_add_number == 0)
7707179404Sobrien	{
7708179404Sobrien	  macro_build (NULL, "sltu", "d,v,t", dreg, 0, sreg);
7709208737Sjmallett	  break;
7710179404Sobrien	}
7711179404Sobrien      if (sreg == 0)
7712179404Sobrien	{
7713179404Sobrien	  as_warn (_("Instruction %s: result is always true"),
7714179404Sobrien		   ip->insn_mo->name);
7715179404Sobrien	  macro_build (&expr1, HAVE_32BIT_GPRS ? "addiu" : "daddiu", "t,r,j",
7716179404Sobrien		       dreg, 0, BFD_RELOC_LO16);
7717208737Sjmallett	  break;
7718179404Sobrien	}
7719179404Sobrien      if (imm_expr.X_op == O_constant
7720179404Sobrien	  && imm_expr.X_add_number >= 0
7721179404Sobrien	  && imm_expr.X_add_number < 0x10000)
7722179404Sobrien	{
7723179404Sobrien	  macro_build (&imm_expr, "xori", "t,r,i", dreg, sreg, BFD_RELOC_LO16);
7724179404Sobrien	}
7725179404Sobrien      else if (imm_expr.X_op == O_constant
7726179404Sobrien	       && imm_expr.X_add_number > -0x8000
7727179404Sobrien	       && imm_expr.X_add_number < 0)
7728179404Sobrien	{
7729179404Sobrien	  imm_expr.X_add_number = -imm_expr.X_add_number;
7730179404Sobrien	  macro_build (&imm_expr, HAVE_32BIT_GPRS ? "addiu" : "daddiu",
7731179404Sobrien		       "t,r,j", dreg, sreg, BFD_RELOC_LO16);
7732179404Sobrien	}
7733179404Sobrien      else
7734179404Sobrien	{
7735179404Sobrien	  load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
7736179404Sobrien	  macro_build (NULL, "xor", "d,v,t", dreg, sreg, AT);
7737179404Sobrien	  used_at = 1;
7738179404Sobrien	}
7739179404Sobrien      macro_build (NULL, "sltu", "d,v,t", dreg, 0, dreg);
7740208737Sjmallett      break;
7741179404Sobrien
7742179404Sobrien    case M_DSUB_I:
7743179404Sobrien      dbl = 1;
7744179404Sobrien    case M_SUB_I:
7745179404Sobrien      if (imm_expr.X_op == O_constant
7746179404Sobrien	  && imm_expr.X_add_number > -0x8000
7747179404Sobrien	  && imm_expr.X_add_number <= 0x8000)
7748179404Sobrien	{
7749179404Sobrien	  imm_expr.X_add_number = -imm_expr.X_add_number;
7750179404Sobrien	  macro_build (&imm_expr, dbl ? "daddi" : "addi", "t,r,j",
7751179404Sobrien		       dreg, sreg, BFD_RELOC_LO16);
7752208737Sjmallett	  break;
7753179404Sobrien	}
7754208737Sjmallett      used_at = 1;
7755179404Sobrien      load_register (AT, &imm_expr, dbl);
7756179404Sobrien      macro_build (NULL, dbl ? "dsub" : "sub", "d,v,t", dreg, sreg, AT);
7757179404Sobrien      break;
7758179404Sobrien
7759179404Sobrien    case M_DSUBU_I:
7760179404Sobrien      dbl = 1;
7761179404Sobrien    case M_SUBU_I:
7762179404Sobrien      if (imm_expr.X_op == O_constant
7763179404Sobrien	  && imm_expr.X_add_number > -0x8000
7764179404Sobrien	  && imm_expr.X_add_number <= 0x8000)
7765179404Sobrien	{
7766179404Sobrien	  imm_expr.X_add_number = -imm_expr.X_add_number;
7767179404Sobrien	  macro_build (&imm_expr, dbl ? "daddiu" : "addiu", "t,r,j",
7768179404Sobrien		       dreg, sreg, BFD_RELOC_LO16);
7769208737Sjmallett	  break;
7770179404Sobrien	}
7771208737Sjmallett      used_at = 1;
7772179404Sobrien      load_register (AT, &imm_expr, dbl);
7773179404Sobrien      macro_build (NULL, dbl ? "dsubu" : "subu", "d,v,t", dreg, sreg, AT);
7774179404Sobrien      break;
7775179404Sobrien
7776179404Sobrien    case M_TEQ_I:
7777179404Sobrien      s = "teq";
7778179404Sobrien      goto trap;
7779179404Sobrien    case M_TGE_I:
7780179404Sobrien      s = "tge";
7781179404Sobrien      goto trap;
7782179404Sobrien    case M_TGEU_I:
7783179404Sobrien      s = "tgeu";
7784179404Sobrien      goto trap;
7785179404Sobrien    case M_TLT_I:
7786179404Sobrien      s = "tlt";
7787179404Sobrien      goto trap;
7788179404Sobrien    case M_TLTU_I:
7789179404Sobrien      s = "tltu";
7790179404Sobrien      goto trap;
7791179404Sobrien    case M_TNE_I:
7792179404Sobrien      s = "tne";
7793179404Sobrien    trap:
7794208737Sjmallett      used_at = 1;
7795179404Sobrien      load_register (AT, &imm_expr, HAVE_64BIT_GPRS);
7796179404Sobrien      macro_build (NULL, s, "s,t", sreg, AT);
7797179404Sobrien      break;
7798179404Sobrien
7799179404Sobrien    case M_TRUNCWS:
7800179404Sobrien    case M_TRUNCWD:
7801208737Sjmallett      if (mips_opts.arch == CPU_OCTEON && octeon_error_on_unsupported)
7802208737Sjmallett        {
7803208737Sjmallett          as_bad (_("opcode not implemented in Octeon `%s'"), ip->insn_mo->name);
7804208737Sjmallett          return;
7805208737Sjmallett        }
7806179404Sobrien      assert (mips_opts.isa == ISA_MIPS1);
7807208737Sjmallett      used_at = 1;
7808179404Sobrien      sreg = (ip->insn_opcode >> 11) & 0x1f;	/* floating reg */
7809179404Sobrien      dreg = (ip->insn_opcode >> 06) & 0x1f;	/* floating reg */
7810179404Sobrien
7811179404Sobrien      /*
7812179404Sobrien       * Is the double cfc1 instruction a bug in the mips assembler;
7813179404Sobrien       * or is there a reason for it?
7814179404Sobrien       */
7815208737Sjmallett      start_noreorder ();
7816179404Sobrien      macro_build (NULL, "cfc1", "t,G", treg, RA);
7817179404Sobrien      macro_build (NULL, "cfc1", "t,G", treg, RA);
7818179404Sobrien      macro_build (NULL, "nop", "");
7819179404Sobrien      expr1.X_add_number = 3;
7820179404Sobrien      macro_build (&expr1, "ori", "t,r,i", AT, treg, BFD_RELOC_LO16);
7821179404Sobrien      expr1.X_add_number = 2;
7822179404Sobrien      macro_build (&expr1, "xori", "t,r,i", AT, AT, BFD_RELOC_LO16);
7823179404Sobrien      macro_build (NULL, "ctc1", "t,G", AT, RA);
7824179404Sobrien      macro_build (NULL, "nop", "");
7825179404Sobrien      macro_build (NULL, mask == M_TRUNCWD ? "cvt.w.d" : "cvt.w.s", "D,S",
7826179404Sobrien		   dreg, sreg);
7827179404Sobrien      macro_build (NULL, "ctc1", "t,G", treg, RA);
7828179404Sobrien      macro_build (NULL, "nop", "");
7829208737Sjmallett      end_noreorder ();
7830179404Sobrien      break;
7831179404Sobrien
7832179404Sobrien    case M_ULH:
7833179404Sobrien      s = "lb";
7834179404Sobrien      goto ulh;
7835179404Sobrien    case M_ULHU:
7836179404Sobrien      s = "lbu";
7837179404Sobrien    ulh:
7838208737Sjmallett      used_at = 1;
7839179404Sobrien      if (offset_expr.X_add_number >= 0x7fff)
7840179404Sobrien	as_bad (_("operand overflow"));
7841208737Sjmallett      /* Expand the ulh to "lb, lbu, ins" instead of "lb, lbu, sll, ori". */
7842179404Sobrien      if (! target_big_endian)
7843179404Sobrien	++offset_expr.X_add_number;
7844179404Sobrien      macro_build (&offset_expr, s, "t,o(b)", AT, BFD_RELOC_LO16, breg);
7845179404Sobrien      if (! target_big_endian)
7846179404Sobrien	--offset_expr.X_add_number;
7847179404Sobrien      else
7848179404Sobrien	++offset_expr.X_add_number;
7849179404Sobrien      macro_build (&offset_expr, "lbu", "t,o(b)", treg, BFD_RELOC_LO16, breg);
7850208737Sjmallett      if (ISA_HAS_INS (mips_opts.isa))
7851208737Sjmallett	macro_build (NULL, "ins", "t,r,+A,+B", treg, AT, 8, 31);
7852208737Sjmallett      else
7853208737Sjmallett	{
7854208737Sjmallett          macro_build (NULL, "sll", "d,w,<", AT, AT, 8);
7855208737Sjmallett          macro_build (NULL, "or", "d,v,t", treg, treg, AT);
7856208737Sjmallett	}
7857179404Sobrien      break;
7858179404Sobrien
7859179404Sobrien    case M_ULD:
7860179404Sobrien      s = "ldl";
7861179404Sobrien      s2 = "ldr";
7862179404Sobrien      off = 7;
7863179404Sobrien      goto ulw;
7864179404Sobrien    case M_ULW:
7865179404Sobrien      s = "lwl";
7866179404Sobrien      s2 = "lwr";
7867179404Sobrien      off = 3;
7868179404Sobrien    ulw:
7869179404Sobrien      if (offset_expr.X_add_number >= 0x8000 - off)
7870179404Sobrien	as_bad (_("operand overflow"));
7871179404Sobrien      if (treg != breg)
7872179404Sobrien	tempreg = treg;
7873179404Sobrien      else
7874208737Sjmallett	{
7875208737Sjmallett	  used_at = 1;
7876208737Sjmallett	  tempreg = AT;
7877208737Sjmallett	}
7878208737Sjmallett
7879208737Sjmallett      /* For small variables the compiler uses gp_rel to load the value of
7880208737Sjmallett	 the variables. While parsing instructions "uld $2,%gp_rel(var)($28)"
7881208737Sjmallett	 the offset_reloc[0] is set to BFD_RELOC_GPREL16. Use this relocation
7882208737Sjmallett	 type while emitting instructions otherwise use BFD_RELOC_LO16.  */
7883208737Sjmallett      if (offset_reloc[0] == BFD_RELOC_UNUSED)
7884208737Sjmallett	offset_reloc[0] = BFD_RELOC_LO16;
7885208737Sjmallett
7886208737Sjmallett      if (octeon_use_unalign && mips_opts.arch == CPU_OCTEON)
7887208737Sjmallett	{
7888208737Sjmallett	  /* Reset used_at as tempreg is not used while generating Octeon
7889208737Sjmallett	     unaligned load/store.  */
7890208737Sjmallett	  used_at = 0;
7891208737Sjmallett	  macro_build (&offset_expr, (mask == M_ULW ? "ulw" : "uld"), "t,o(b)",
7892208737Sjmallett		       treg, offset_reloc[0], breg);
7893208737Sjmallett	  break;
7894208737Sjmallett	}
7895208737Sjmallett
7896179404Sobrien      if (! target_big_endian)
7897179404Sobrien	offset_expr.X_add_number += off;
7898208737Sjmallett      macro_build (&offset_expr, s, "t,o(b)", tempreg, offset_reloc[0], breg);
7899179404Sobrien      if (! target_big_endian)
7900179404Sobrien	offset_expr.X_add_number -= off;
7901179404Sobrien      else
7902179404Sobrien	offset_expr.X_add_number += off;
7903208737Sjmallett      macro_build (&offset_expr, s2, "t,o(b)", tempreg, offset_reloc[0], breg);
7904179404Sobrien
7905179404Sobrien      /* If necessary, move the result in tempreg the final destination.  */
7906179404Sobrien      if (treg == tempreg)
7907208737Sjmallett        break;
7908179404Sobrien      /* Protect second load's delay slot.  */
7909208737Sjmallett      load_delay_nop ();
7910179404Sobrien      move_register (treg, tempreg);
7911179404Sobrien      break;
7912179404Sobrien
7913179404Sobrien    case M_ULD_A:
7914179404Sobrien      s = "ldl";
7915179404Sobrien      s2 = "ldr";
7916179404Sobrien      off = 7;
7917179404Sobrien      goto ulwa;
7918179404Sobrien    case M_ULW_A:
7919179404Sobrien      s = "lwl";
7920179404Sobrien      s2 = "lwr";
7921179404Sobrien      off = 3;
7922179404Sobrien    ulwa:
7923179404Sobrien      used_at = 1;
7924179404Sobrien      load_address (AT, &offset_expr, &used_at);
7925179404Sobrien      if (breg != 0)
7926179404Sobrien	macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
7927208737Sjmallett
7928208737Sjmallett      /* For small variables the compiler uses gp_rel to load the value of
7929208737Sjmallett	 the variables. While parsing instructions "uld $2,%gp_rel(var)($28)"
7930208737Sjmallett	 the offset_reloc[0] is set to BFD_RELOC_GPREL16. Use this relocation
7931208737Sjmallett	 type while emitting instructions otherwise use BFD_RELOC_LO16.  */
7932208737Sjmallett      if (offset_reloc[0] == BFD_RELOC_UNUSED)
7933208737Sjmallett	offset_reloc[0] = BFD_RELOC_LO16;
7934208737Sjmallett
7935208737Sjmallett      if (octeon_use_unalign && mips_opts.arch == CPU_OCTEON)
7936208737Sjmallett	{
7937208737Sjmallett	  macro_build (&offset_expr, (mask == M_ULW_A ? "ulw" : "uld"),
7938208737Sjmallett		       "t,o(b)", treg, offset_reloc[0], AT);
7939208737Sjmallett	  break;
7940208737Sjmallett	}
7941208737Sjmallett
7942179404Sobrien      if (! target_big_endian)
7943179404Sobrien	expr1.X_add_number = off;
7944179404Sobrien      else
7945179404Sobrien	expr1.X_add_number = 0;
7946208737Sjmallett      macro_build (&expr1, s, "t,o(b)", treg, offset_reloc[0], AT);
7947179404Sobrien      if (! target_big_endian)
7948179404Sobrien	expr1.X_add_number = 0;
7949179404Sobrien      else
7950179404Sobrien	expr1.X_add_number = off;
7951208737Sjmallett      macro_build (&expr1, s2, "t,o(b)", treg, offset_reloc[0], AT);
7952179404Sobrien      break;
7953179404Sobrien
7954179404Sobrien    case M_ULH_A:
7955179404Sobrien    case M_ULHU_A:
7956179404Sobrien      used_at = 1;
7957179404Sobrien      load_address (AT, &offset_expr, &used_at);
7958179404Sobrien      if (breg != 0)
7959179404Sobrien	macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
7960208737Sjmallett
7961208737Sjmallett      if (ISA_HAS_INS (mips_opts.isa))
7962208737Sjmallett	{
7963208737Sjmallett	  if (target_big_endian)
7964208737Sjmallett	    expr1.X_add_number = 1;
7965208737Sjmallett	  else
7966208737Sjmallett	    expr1.X_add_number = 0;
7967208737Sjmallett	  macro_build (&expr1, "lbu", "t,o(b)", treg, BFD_RELOC_LO16, AT);
7968208737Sjmallett	  if (target_big_endian)
7969208737Sjmallett	    expr1.X_add_number = 0;
7970208737Sjmallett	  else
7971208737Sjmallett	    expr1.X_add_number = 1;
7972208737Sjmallett	  macro_build (&expr1, mask == M_ULH_A ? "lb" : "lbu", "t,o(b)",
7973208737Sjmallett		       AT, BFD_RELOC_LO16, AT);
7974208737Sjmallett	  macro_build (NULL, "ins", "t,r,+A,+B", treg, AT, 8, 31);
7975208737Sjmallett	  break;
7976208737Sjmallett	}
7977179404Sobrien      if (target_big_endian)
7978179404Sobrien	expr1.X_add_number = 0;
7979179404Sobrien      macro_build (&expr1, mask == M_ULH_A ? "lb" : "lbu", "t,o(b)",
7980179404Sobrien		   treg, BFD_RELOC_LO16, AT);
7981179404Sobrien      if (target_big_endian)
7982179404Sobrien	expr1.X_add_number = 1;
7983179404Sobrien      else
7984179404Sobrien	expr1.X_add_number = 0;
7985179404Sobrien      macro_build (&expr1, "lbu", "t,o(b)", AT, BFD_RELOC_LO16, AT);
7986179404Sobrien      macro_build (NULL, "sll", "d,w,<", treg, treg, 8);
7987179404Sobrien      macro_build (NULL, "or", "d,v,t", treg, treg, AT);
7988179404Sobrien      break;
7989179404Sobrien
7990179404Sobrien    case M_USH:
7991208737Sjmallett      used_at = 1;
7992179404Sobrien      if (offset_expr.X_add_number >= 0x7fff)
7993179404Sobrien	as_bad (_("operand overflow"));
7994179404Sobrien      if (target_big_endian)
7995179404Sobrien	++offset_expr.X_add_number;
7996179404Sobrien      macro_build (&offset_expr, "sb", "t,o(b)", treg, BFD_RELOC_LO16, breg);
7997179404Sobrien      macro_build (NULL, "srl", "d,w,<", AT, treg, 8);
7998179404Sobrien      if (target_big_endian)
7999179404Sobrien	--offset_expr.X_add_number;
8000179404Sobrien      else
8001179404Sobrien	++offset_expr.X_add_number;
8002179404Sobrien      macro_build (&offset_expr, "sb", "t,o(b)", AT, BFD_RELOC_LO16, breg);
8003179404Sobrien      break;
8004179404Sobrien
8005179404Sobrien    case M_USD:
8006179404Sobrien      s = "sdl";
8007179404Sobrien      s2 = "sdr";
8008179404Sobrien      off = 7;
8009179404Sobrien      goto usw;
8010179404Sobrien    case M_USW:
8011179404Sobrien      s = "swl";
8012179404Sobrien      s2 = "swr";
8013179404Sobrien      off = 3;
8014179404Sobrien    usw:
8015179404Sobrien      if (offset_expr.X_add_number >= 0x8000 - off)
8016179404Sobrien	as_bad (_("operand overflow"));
8017208737Sjmallett
8018208737Sjmallett      /* For small variables the compiler uses gp_rel to load the value of
8019208737Sjmallett	 the variables. While parsing instructions "uld $2,%gp_rel(var)($28)"
8020208737Sjmallett	 the offset_reloc[0] is set to BFD_RELOC_GPREL16. Use this relocation
8021208737Sjmallett	 type while emitting instructions otherwise use BFD_RELOC_LO16.  */
8022208737Sjmallett      if (offset_reloc[0] == BFD_RELOC_UNUSED)
8023208737Sjmallett	offset_reloc[0] = BFD_RELOC_LO16;
8024208737Sjmallett
8025208737Sjmallett      if (octeon_use_unalign && mips_opts.arch == CPU_OCTEON)
8026208737Sjmallett	{
8027208737Sjmallett	  macro_build (&offset_expr, (mask == M_USD ? "usd" : "usw"),
8028208737Sjmallett		       "t,o(b)", treg, offset_reloc[0], breg);
8029208737Sjmallett	  break;
8030208737Sjmallett	}
8031179404Sobrien      if (! target_big_endian)
8032179404Sobrien	offset_expr.X_add_number += off;
8033208737Sjmallett      macro_build (&offset_expr, s, "t,o(b)", treg, offset_reloc[0], breg);
8034179404Sobrien      if (! target_big_endian)
8035179404Sobrien	offset_expr.X_add_number -= off;
8036179404Sobrien      else
8037179404Sobrien	offset_expr.X_add_number += off;
8038208737Sjmallett      macro_build (&offset_expr, s2, "t,o(b)", treg, offset_reloc[0], breg);
8039208737Sjmallett      break;
8040179404Sobrien
8041179404Sobrien    case M_USD_A:
8042179404Sobrien      s = "sdl";
8043179404Sobrien      s2 = "sdr";
8044179404Sobrien      off = 7;
8045179404Sobrien      goto uswa;
8046179404Sobrien    case M_USW_A:
8047179404Sobrien      s = "swl";
8048179404Sobrien      s2 = "swr";
8049179404Sobrien      off = 3;
8050179404Sobrien    uswa:
8051179404Sobrien      used_at = 1;
8052179404Sobrien      load_address (AT, &offset_expr, &used_at);
8053179404Sobrien      if (breg != 0)
8054179404Sobrien	macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
8055208737Sjmallett
8056208737Sjmallett      /* For small variables the compiler uses gp_rel to load the value of
8057208737Sjmallett	 the variables. While parsing instructions "uld $2,%gp_rel(var)($28)"
8058208737Sjmallett	 the offset_reloc[0] is set to BFD_RELOC_GPREL16. Use this relocation
8059208737Sjmallett	 type while emitting instructions otherwise use BFD_RELOC_LO16.  */
8060208737Sjmallett      if (offset_reloc[0] == BFD_RELOC_UNUSED)
8061208737Sjmallett	offset_reloc[0] = BFD_RELOC_LO16;
8062208737Sjmallett
8063208737Sjmallett      if (octeon_use_unalign && mips_opts.arch == CPU_OCTEON)
8064208737Sjmallett	{
8065208737Sjmallett	  macro_build (&offset_expr, (mask == M_USW_A ? "usw" : "usd"),
8066208737Sjmallett		       "t,o(b)", treg, offset_reloc[0], AT);
8067208737Sjmallett	  break;
8068208737Sjmallett	}
8069179404Sobrien      if (! target_big_endian)
8070179404Sobrien	expr1.X_add_number = off;
8071179404Sobrien      else
8072179404Sobrien	expr1.X_add_number = 0;
8073208737Sjmallett      macro_build (&expr1, s, "t,o(b)", treg, offset_reloc[0], AT);
8074179404Sobrien      if (! target_big_endian)
8075179404Sobrien	expr1.X_add_number = 0;
8076179404Sobrien      else
8077179404Sobrien	expr1.X_add_number = off;
8078208737Sjmallett      macro_build (&expr1, s2, "t,o(b)", treg, offset_reloc[0], AT);
8079179404Sobrien      break;
8080179404Sobrien
8081179404Sobrien    case M_USH_A:
8082179404Sobrien      used_at = 1;
8083179404Sobrien      load_address (AT, &offset_expr, &used_at);
8084179404Sobrien      if (breg != 0)
8085179404Sobrien	macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", AT, AT, breg);
8086179404Sobrien      if (! target_big_endian)
8087179404Sobrien	expr1.X_add_number = 0;
8088179404Sobrien      macro_build (&expr1, "sb", "t,o(b)", treg, BFD_RELOC_LO16, AT);
8089179404Sobrien      macro_build (NULL, "srl", "d,w,<", treg, treg, 8);
8090179404Sobrien      if (! target_big_endian)
8091179404Sobrien	expr1.X_add_number = 1;
8092179404Sobrien      else
8093179404Sobrien	expr1.X_add_number = 0;
8094179404Sobrien      macro_build (&expr1, "sb", "t,o(b)", treg, BFD_RELOC_LO16, AT);
8095179404Sobrien      if (! target_big_endian)
8096179404Sobrien	expr1.X_add_number = 0;
8097179404Sobrien      else
8098179404Sobrien	expr1.X_add_number = 1;
8099179404Sobrien      macro_build (&expr1, "lbu", "t,o(b)", AT, BFD_RELOC_LO16, AT);
8100179404Sobrien      macro_build (NULL, "sll", "d,w,<", treg, treg, 8);
8101179404Sobrien      macro_build (NULL, "or", "d,v,t", treg, treg, AT);
8102179404Sobrien      break;
8103179404Sobrien
8104179404Sobrien    default:
8105179404Sobrien      /* FIXME: Check if this is one of the itbl macros, since they
8106179404Sobrien	 are added dynamically.  */
8107179404Sobrien      as_bad (_("Macro %s not implemented yet"), ip->insn_mo->name);
8108179404Sobrien      break;
8109179404Sobrien    }
8110208737Sjmallett  if (mips_opts.noat && used_at)
8111208737Sjmallett    as_bad (_("Macro used $at after \".set noat\""));
8112179404Sobrien}
8113179404Sobrien
8114179404Sobrien/* Implement macros in mips16 mode.  */
8115179404Sobrien
8116179404Sobrienstatic void
8117179404Sobrienmips16_macro (struct mips_cl_insn *ip)
8118179404Sobrien{
8119179404Sobrien  int mask;
8120179404Sobrien  int xreg, yreg, zreg, tmp;
8121179404Sobrien  expressionS expr1;
8122179404Sobrien  int dbl;
8123179404Sobrien  const char *s, *s2, *s3;
8124179404Sobrien
8125179404Sobrien  mask = ip->insn_mo->mask;
8126179404Sobrien
8127208737Sjmallett  xreg = MIPS16_EXTRACT_OPERAND (RX, *ip);
8128208737Sjmallett  yreg = MIPS16_EXTRACT_OPERAND (RY, *ip);
8129208737Sjmallett  zreg = MIPS16_EXTRACT_OPERAND (RZ, *ip);
8130179404Sobrien
8131179404Sobrien  expr1.X_op = O_constant;
8132179404Sobrien  expr1.X_op_symbol = NULL;
8133179404Sobrien  expr1.X_add_symbol = NULL;
8134179404Sobrien  expr1.X_add_number = 1;
8135179404Sobrien
8136179404Sobrien  dbl = 0;
8137179404Sobrien
8138179404Sobrien  switch (mask)
8139179404Sobrien    {
8140179404Sobrien    default:
8141179404Sobrien      internalError ();
8142179404Sobrien
8143179404Sobrien    case M_DDIV_3:
8144179404Sobrien      dbl = 1;
8145179404Sobrien    case M_DIV_3:
8146179404Sobrien      s = "mflo";
8147179404Sobrien      goto do_div3;
8148179404Sobrien    case M_DREM_3:
8149179404Sobrien      dbl = 1;
8150179404Sobrien    case M_REM_3:
8151179404Sobrien      s = "mfhi";
8152179404Sobrien    do_div3:
8153208737Sjmallett      start_noreorder ();
8154179404Sobrien      macro_build (NULL, dbl ? "ddiv" : "div", "0,x,y", xreg, yreg);
8155179404Sobrien      expr1.X_add_number = 2;
8156179404Sobrien      macro_build (&expr1, "bnez", "x,p", yreg);
8157179404Sobrien      macro_build (NULL, "break", "6", 7);
8158179404Sobrien
8159179404Sobrien      /* FIXME: The normal code checks for of -1 / -0x80000000 here,
8160179404Sobrien         since that causes an overflow.  We should do that as well,
8161179404Sobrien         but I don't see how to do the comparisons without a temporary
8162179404Sobrien         register.  */
8163208737Sjmallett      end_noreorder ();
8164179404Sobrien      macro_build (NULL, s, "x", zreg);
8165179404Sobrien      break;
8166179404Sobrien
8167179404Sobrien    case M_DIVU_3:
8168179404Sobrien      s = "divu";
8169179404Sobrien      s2 = "mflo";
8170179404Sobrien      goto do_divu3;
8171179404Sobrien    case M_REMU_3:
8172179404Sobrien      s = "divu";
8173179404Sobrien      s2 = "mfhi";
8174179404Sobrien      goto do_divu3;
8175179404Sobrien    case M_DDIVU_3:
8176179404Sobrien      s = "ddivu";
8177179404Sobrien      s2 = "mflo";
8178179404Sobrien      goto do_divu3;
8179179404Sobrien    case M_DREMU_3:
8180179404Sobrien      s = "ddivu";
8181179404Sobrien      s2 = "mfhi";
8182179404Sobrien    do_divu3:
8183208737Sjmallett      start_noreorder ();
8184179404Sobrien      macro_build (NULL, s, "0,x,y", xreg, yreg);
8185179404Sobrien      expr1.X_add_number = 2;
8186179404Sobrien      macro_build (&expr1, "bnez", "x,p", yreg);
8187179404Sobrien      macro_build (NULL, "break", "6", 7);
8188208737Sjmallett      end_noreorder ();
8189179404Sobrien      macro_build (NULL, s2, "x", zreg);
8190179404Sobrien      break;
8191179404Sobrien
8192179404Sobrien    case M_DMUL:
8193179404Sobrien      dbl = 1;
8194179404Sobrien    case M_MUL:
8195179404Sobrien      macro_build (NULL, dbl ? "dmultu" : "multu", "x,y", xreg, yreg);
8196179404Sobrien      macro_build (NULL, "mflo", "x", zreg);
8197208737Sjmallett      break;
8198179404Sobrien
8199179404Sobrien    case M_DSUBU_I:
8200179404Sobrien      dbl = 1;
8201179404Sobrien      goto do_subu;
8202179404Sobrien    case M_SUBU_I:
8203179404Sobrien    do_subu:
8204179404Sobrien      if (imm_expr.X_op != O_constant)
8205179404Sobrien	as_bad (_("Unsupported large constant"));
8206179404Sobrien      imm_expr.X_add_number = -imm_expr.X_add_number;
8207179404Sobrien      macro_build (&imm_expr, dbl ? "daddiu" : "addiu", "y,x,4", yreg, xreg);
8208179404Sobrien      break;
8209179404Sobrien
8210179404Sobrien    case M_SUBU_I_2:
8211179404Sobrien      if (imm_expr.X_op != O_constant)
8212179404Sobrien	as_bad (_("Unsupported large constant"));
8213179404Sobrien      imm_expr.X_add_number = -imm_expr.X_add_number;
8214179404Sobrien      macro_build (&imm_expr, "addiu", "x,k", xreg);
8215179404Sobrien      break;
8216179404Sobrien
8217179404Sobrien    case M_DSUBU_I_2:
8218179404Sobrien      if (imm_expr.X_op != O_constant)
8219179404Sobrien	as_bad (_("Unsupported large constant"));
8220179404Sobrien      imm_expr.X_add_number = -imm_expr.X_add_number;
8221179404Sobrien      macro_build (&imm_expr, "daddiu", "y,j", yreg);
8222179404Sobrien      break;
8223179404Sobrien
8224179404Sobrien    case M_BEQ:
8225179404Sobrien      s = "cmp";
8226179404Sobrien      s2 = "bteqz";
8227179404Sobrien      goto do_branch;
8228179404Sobrien    case M_BNE:
8229179404Sobrien      s = "cmp";
8230179404Sobrien      s2 = "btnez";
8231179404Sobrien      goto do_branch;
8232179404Sobrien    case M_BLT:
8233179404Sobrien      s = "slt";
8234179404Sobrien      s2 = "btnez";
8235179404Sobrien      goto do_branch;
8236179404Sobrien    case M_BLTU:
8237179404Sobrien      s = "sltu";
8238179404Sobrien      s2 = "btnez";
8239179404Sobrien      goto do_branch;
8240179404Sobrien    case M_BLE:
8241179404Sobrien      s = "slt";
8242179404Sobrien      s2 = "bteqz";
8243179404Sobrien      goto do_reverse_branch;
8244179404Sobrien    case M_BLEU:
8245179404Sobrien      s = "sltu";
8246179404Sobrien      s2 = "bteqz";
8247179404Sobrien      goto do_reverse_branch;
8248179404Sobrien    case M_BGE:
8249179404Sobrien      s = "slt";
8250179404Sobrien      s2 = "bteqz";
8251179404Sobrien      goto do_branch;
8252179404Sobrien    case M_BGEU:
8253179404Sobrien      s = "sltu";
8254179404Sobrien      s2 = "bteqz";
8255179404Sobrien      goto do_branch;
8256179404Sobrien    case M_BGT:
8257179404Sobrien      s = "slt";
8258179404Sobrien      s2 = "btnez";
8259179404Sobrien      goto do_reverse_branch;
8260179404Sobrien    case M_BGTU:
8261179404Sobrien      s = "sltu";
8262179404Sobrien      s2 = "btnez";
8263179404Sobrien
8264179404Sobrien    do_reverse_branch:
8265179404Sobrien      tmp = xreg;
8266179404Sobrien      xreg = yreg;
8267179404Sobrien      yreg = tmp;
8268179404Sobrien
8269179404Sobrien    do_branch:
8270179404Sobrien      macro_build (NULL, s, "x,y", xreg, yreg);
8271179404Sobrien      macro_build (&offset_expr, s2, "p");
8272179404Sobrien      break;
8273179404Sobrien
8274179404Sobrien    case M_BEQ_I:
8275179404Sobrien      s = "cmpi";
8276179404Sobrien      s2 = "bteqz";
8277179404Sobrien      s3 = "x,U";
8278179404Sobrien      goto do_branch_i;
8279179404Sobrien    case M_BNE_I:
8280179404Sobrien      s = "cmpi";
8281179404Sobrien      s2 = "btnez";
8282179404Sobrien      s3 = "x,U";
8283179404Sobrien      goto do_branch_i;
8284179404Sobrien    case M_BLT_I:
8285179404Sobrien      s = "slti";
8286179404Sobrien      s2 = "btnez";
8287179404Sobrien      s3 = "x,8";
8288179404Sobrien      goto do_branch_i;
8289179404Sobrien    case M_BLTU_I:
8290179404Sobrien      s = "sltiu";
8291179404Sobrien      s2 = "btnez";
8292179404Sobrien      s3 = "x,8";
8293179404Sobrien      goto do_branch_i;
8294179404Sobrien    case M_BLE_I:
8295179404Sobrien      s = "slti";
8296179404Sobrien      s2 = "btnez";
8297179404Sobrien      s3 = "x,8";
8298179404Sobrien      goto do_addone_branch_i;
8299179404Sobrien    case M_BLEU_I:
8300179404Sobrien      s = "sltiu";
8301179404Sobrien      s2 = "btnez";
8302179404Sobrien      s3 = "x,8";
8303179404Sobrien      goto do_addone_branch_i;
8304179404Sobrien    case M_BGE_I:
8305179404Sobrien      s = "slti";
8306179404Sobrien      s2 = "bteqz";
8307179404Sobrien      s3 = "x,8";
8308179404Sobrien      goto do_branch_i;
8309179404Sobrien    case M_BGEU_I:
8310179404Sobrien      s = "sltiu";
8311179404Sobrien      s2 = "bteqz";
8312179404Sobrien      s3 = "x,8";
8313179404Sobrien      goto do_branch_i;
8314179404Sobrien    case M_BGT_I:
8315179404Sobrien      s = "slti";
8316179404Sobrien      s2 = "bteqz";
8317179404Sobrien      s3 = "x,8";
8318179404Sobrien      goto do_addone_branch_i;
8319179404Sobrien    case M_BGTU_I:
8320179404Sobrien      s = "sltiu";
8321179404Sobrien      s2 = "bteqz";
8322179404Sobrien      s3 = "x,8";
8323179404Sobrien
8324179404Sobrien    do_addone_branch_i:
8325179404Sobrien      if (imm_expr.X_op != O_constant)
8326179404Sobrien	as_bad (_("Unsupported large constant"));
8327179404Sobrien      ++imm_expr.X_add_number;
8328179404Sobrien
8329179404Sobrien    do_branch_i:
8330179404Sobrien      macro_build (&imm_expr, s, s3, xreg);
8331179404Sobrien      macro_build (&offset_expr, s2, "p");
8332179404Sobrien      break;
8333179404Sobrien
8334179404Sobrien    case M_ABS:
8335179404Sobrien      expr1.X_add_number = 0;
8336179404Sobrien      macro_build (&expr1, "slti", "x,8", yreg);
8337179404Sobrien      if (xreg != yreg)
8338179404Sobrien	move_register (xreg, yreg);
8339179404Sobrien      expr1.X_add_number = 2;
8340179404Sobrien      macro_build (&expr1, "bteqz", "p");
8341179404Sobrien      macro_build (NULL, "neg", "x,w", xreg, xreg);
8342179404Sobrien    }
8343179404Sobrien}
8344179404Sobrien
8345179404Sobrien/* For consistency checking, verify that all bits are specified either
8346179404Sobrien   by the match/mask part of the instruction definition, or by the
8347179404Sobrien   operand list.  */
8348179404Sobrienstatic int
8349179404Sobrienvalidate_mips_insn (const struct mips_opcode *opc)
8350179404Sobrien{
8351179404Sobrien  const char *p = opc->args;
8352179404Sobrien  char c;
8353179404Sobrien  unsigned long used_bits = opc->mask;
8354179404Sobrien
8355179404Sobrien  if ((used_bits & opc->match) != opc->match)
8356179404Sobrien    {
8357179404Sobrien      as_bad (_("internal: bad mips opcode (mask error): %s %s"),
8358179404Sobrien	      opc->name, opc->args);
8359179404Sobrien      return 0;
8360179404Sobrien    }
8361179404Sobrien#define USE_BITS(mask,shift)	(used_bits |= ((mask) << (shift)))
8362179404Sobrien  while (*p)
8363179404Sobrien    switch (c = *p++)
8364179404Sobrien      {
8365179404Sobrien      case ',': break;
8366179404Sobrien      case '(': break;
8367179404Sobrien      case ')': break;
8368208737Sjmallett      case '^': USE_BITS (OP_MASK_BITIND,       OP_SH_BITIND);   break;
8369208737Sjmallett      case '~': USE_BITS (OP_MASK_BITIND,       OP_SH_BITIND);   break;
8370179404Sobrien      case '+':
8371179404Sobrien    	switch (c = *p++)
8372179404Sobrien	  {
8373218822Sdim	  case '1': USE_BITS (OP_MASK_UDI1,     OP_SH_UDI1); 	break;
8374218822Sdim	  case '2': USE_BITS (OP_MASK_UDI2,	OP_SH_UDI2); 	break;
8375218822Sdim	  case '3': USE_BITS (OP_MASK_UDI3,	OP_SH_UDI3); 	break;
8376218822Sdim	  case '4': USE_BITS (OP_MASK_UDI4,	OP_SH_UDI4); 	break;
8377179404Sobrien	  case 'A': USE_BITS (OP_MASK_SHAMT,	OP_SH_SHAMT);	break;
8378179404Sobrien	  case 'B': USE_BITS (OP_MASK_INSMSB,	OP_SH_INSMSB);	break;
8379179404Sobrien	  case 'C': USE_BITS (OP_MASK_EXTMSBD,	OP_SH_EXTMSBD);	break;
8380179404Sobrien	  case 'D': USE_BITS (OP_MASK_RD,	OP_SH_RD);
8381179404Sobrien		    USE_BITS (OP_MASK_SEL,	OP_SH_SEL);	break;
8382179404Sobrien	  case 'E': USE_BITS (OP_MASK_SHAMT,	OP_SH_SHAMT);	break;
8383179404Sobrien	  case 'F': USE_BITS (OP_MASK_INSMSB,	OP_SH_INSMSB);	break;
8384179404Sobrien	  case 'G': USE_BITS (OP_MASK_EXTMSBD,	OP_SH_EXTMSBD);	break;
8385179404Sobrien	  case 'H': USE_BITS (OP_MASK_EXTMSBD,	OP_SH_EXTMSBD);	break;
8386179404Sobrien	  case 'I': break;
8387208737Sjmallett	  case 't': USE_BITS (OP_MASK_RT,	OP_SH_RT);	break;
8388208737Sjmallett	  case 'T': USE_BITS (OP_MASK_RT,	OP_SH_RT);
8389208737Sjmallett		    USE_BITS (OP_MASK_SEL,	OP_SH_SEL);	break;
8390179404Sobrien	  default:
8391179404Sobrien	    as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
8392179404Sobrien		    c, opc->name, opc->args);
8393179404Sobrien	    return 0;
8394179404Sobrien	  }
8395179404Sobrien	break;
8396179404Sobrien      case '<': USE_BITS (OP_MASK_SHAMT,	OP_SH_SHAMT);	break;
8397179404Sobrien      case '>':	USE_BITS (OP_MASK_SHAMT,	OP_SH_SHAMT);	break;
8398179404Sobrien      case 'A': break;
8399179404Sobrien      case 'B': USE_BITS (OP_MASK_CODE20,       OP_SH_CODE20);  break;
8400179404Sobrien      case 'C':	USE_BITS (OP_MASK_COPZ,		OP_SH_COPZ);	break;
8401179404Sobrien      case 'D':	USE_BITS (OP_MASK_FD,		OP_SH_FD);	break;
8402179404Sobrien      case 'E':	USE_BITS (OP_MASK_RT,		OP_SH_RT);	break;
8403179404Sobrien      case 'F': break;
8404179404Sobrien      case 'G':	USE_BITS (OP_MASK_RD,		OP_SH_RD);	break;
8405179404Sobrien      case 'H': USE_BITS (OP_MASK_SEL,		OP_SH_SEL);	break;
8406179404Sobrien      case 'I': break;
8407179404Sobrien      case 'J': USE_BITS (OP_MASK_CODE19,       OP_SH_CODE19);  break;
8408179404Sobrien      case 'K':	USE_BITS (OP_MASK_RD,		OP_SH_RD);	break;
8409179404Sobrien      case 'L': break;
8410179404Sobrien      case 'M':	USE_BITS (OP_MASK_CCC,		OP_SH_CCC);	break;
8411179404Sobrien      case 'N':	USE_BITS (OP_MASK_BCC,		OP_SH_BCC);	break;
8412179404Sobrien      case 'O':	USE_BITS (OP_MASK_ALN,		OP_SH_ALN);	break;
8413179404Sobrien      case 'Q':	USE_BITS (OP_MASK_VSEL,		OP_SH_VSEL);
8414179404Sobrien		USE_BITS (OP_MASK_FT,		OP_SH_FT);	break;
8415179404Sobrien      case 'R':	USE_BITS (OP_MASK_FR,		OP_SH_FR);	break;
8416179404Sobrien      case 'S':	USE_BITS (OP_MASK_FS,		OP_SH_FS);	break;
8417179404Sobrien      case 'T':	USE_BITS (OP_MASK_FT,		OP_SH_FT);	break;
8418179404Sobrien      case 'V':	USE_BITS (OP_MASK_FS,		OP_SH_FS);	break;
8419179404Sobrien      case 'W':	USE_BITS (OP_MASK_FT,		OP_SH_FT);	break;
8420179404Sobrien      case 'X':	USE_BITS (OP_MASK_FD,		OP_SH_FD);	break;
8421179404Sobrien      case 'Y':	USE_BITS (OP_MASK_FS,		OP_SH_FS);	break;
8422179404Sobrien      case 'Z':	USE_BITS (OP_MASK_FT,		OP_SH_FT);	break;
8423179404Sobrien      case 'a':	USE_BITS (OP_MASK_TARGET,	OP_SH_TARGET);	break;
8424179404Sobrien      case 'b':	USE_BITS (OP_MASK_RS,		OP_SH_RS);	break;
8425179404Sobrien      case 'c':	USE_BITS (OP_MASK_CODE,		OP_SH_CODE);	break;
8426179404Sobrien      case 'd':	USE_BITS (OP_MASK_RD,		OP_SH_RD);	break;
8427179404Sobrien      case 'f': break;
8428179404Sobrien      case 'h':	USE_BITS (OP_MASK_PREFX,	OP_SH_PREFX);	break;
8429179404Sobrien      case 'i':	USE_BITS (OP_MASK_IMMEDIATE,	OP_SH_IMMEDIATE); break;
8430179404Sobrien      case 'j':	USE_BITS (OP_MASK_DELTA,	OP_SH_DELTA);	break;
8431179404Sobrien      case 'k':	USE_BITS (OP_MASK_CACHE,	OP_SH_CACHE);	break;
8432179404Sobrien      case 'l': break;
8433179404Sobrien      case 'o': USE_BITS (OP_MASK_DELTA,	OP_SH_DELTA);	break;
8434179404Sobrien      case 'p':	USE_BITS (OP_MASK_DELTA,	OP_SH_DELTA);	break;
8435179404Sobrien      case 'q':	USE_BITS (OP_MASK_CODE2,	OP_SH_CODE2);	break;
8436179404Sobrien      case 'r': USE_BITS (OP_MASK_RS,		OP_SH_RS);	break;
8437179404Sobrien      case 's':	USE_BITS (OP_MASK_RS,		OP_SH_RS);	break;
8438179404Sobrien      case 't':	USE_BITS (OP_MASK_RT,		OP_SH_RT);	break;
8439179404Sobrien      case 'u':	USE_BITS (OP_MASK_IMMEDIATE,	OP_SH_IMMEDIATE); break;
8440179404Sobrien      case 'v':	USE_BITS (OP_MASK_RS,		OP_SH_RS);	break;
8441179404Sobrien      case 'w':	USE_BITS (OP_MASK_RT,		OP_SH_RT);	break;
8442179404Sobrien      case 'x': break;
8443208737Sjmallett      case 'y': USE_BITS (OP_MASK_CODE2,        OP_SH_CODE2);   break;
8444179404Sobrien      case 'z': break;
8445179404Sobrien      case 'P': USE_BITS (OP_MASK_PERFREG,	OP_SH_PERFREG);	break;
8446179404Sobrien      case 'U': USE_BITS (OP_MASK_RD,           OP_SH_RD);
8447179404Sobrien	        USE_BITS (OP_MASK_RT,           OP_SH_RT);	break;
8448179404Sobrien      case 'e': USE_BITS (OP_MASK_VECBYTE,	OP_SH_VECBYTE);	break;
8449179404Sobrien      case '%': USE_BITS (OP_MASK_VECALIGN,	OP_SH_VECALIGN); break;
8450179404Sobrien      case '[': break;
8451179404Sobrien      case ']': break;
8452218822Sdim      case '2': USE_BITS (OP_MASK_BP,		OP_SH_BP);	break;
8453208737Sjmallett      case '3': USE_BITS (OP_MASK_SA3,  	OP_SH_SA3);	break;
8454208737Sjmallett      case '4': USE_BITS (OP_MASK_SA4,  	OP_SH_SA4);	break;
8455208737Sjmallett      case '5': USE_BITS (OP_MASK_IMM8, 	OP_SH_IMM8);	break;
8456208737Sjmallett      case '6': USE_BITS (OP_MASK_RS,		OP_SH_RS);	break;
8457208737Sjmallett      case '7': USE_BITS (OP_MASK_DSPACC,	OP_SH_DSPACC);	break;
8458208737Sjmallett      case '8': USE_BITS (OP_MASK_WRDSP,	OP_SH_WRDSP);	break;
8459208737Sjmallett      case '9': USE_BITS (OP_MASK_DSPACC_S,	OP_SH_DSPACC_S);break;
8460208737Sjmallett      case '0': USE_BITS (OP_MASK_DSPSFT,	OP_SH_DSPSFT);	break;
8461208737Sjmallett      case '\'': USE_BITS (OP_MASK_RDDSP,	OP_SH_RDDSP);	break;
8462208737Sjmallett      case ':': USE_BITS (OP_MASK_DSPSFT_7,	OP_SH_DSPSFT_7);break;
8463208737Sjmallett      case '@': USE_BITS (OP_MASK_IMM10,	OP_SH_IMM10);	break;
8464208737Sjmallett      case '!': USE_BITS (OP_MASK_MT_U,		OP_SH_MT_U);	break;
8465208737Sjmallett      case '$': USE_BITS (OP_MASK_MT_H,		OP_SH_MT_H);	break;
8466208737Sjmallett      case '*': USE_BITS (OP_MASK_MTACC_T,	OP_SH_MTACC_T);	break;
8467208737Sjmallett      case '&': USE_BITS (OP_MASK_MTACC_D,	OP_SH_MTACC_D);	break;
8468208737Sjmallett      case 'g': USE_BITS (OP_MASK_RD,		OP_SH_RD);	break;
8469179404Sobrien      default:
8470179404Sobrien	as_bad (_("internal: bad mips opcode (unknown operand type `%c'): %s %s"),
8471179404Sobrien		c, opc->name, opc->args);
8472179404Sobrien	return 0;
8473179404Sobrien      }
8474179404Sobrien#undef USE_BITS
8475179404Sobrien  if (used_bits != 0xffffffff)
8476179404Sobrien    {
8477179404Sobrien      as_bad (_("internal: bad mips opcode (bits 0x%lx undefined): %s %s"),
8478179404Sobrien	      ~used_bits & 0xffffffff, opc->name, opc->args);
8479179404Sobrien      return 0;
8480179404Sobrien    }
8481179404Sobrien  return 1;
8482179404Sobrien}
8483179404Sobrien
8484218822Sdim/* UDI immediates.  */
8485218822Sdimstruct mips_immed {
8486218822Sdim  char		type;
8487218822Sdim  unsigned int	shift;
8488218822Sdim  unsigned long	mask;
8489218822Sdim  const char *	desc;
8490218822Sdim};
8491218822Sdim
8492218822Sdimstatic const struct mips_immed mips_immed[] = {
8493218822Sdim  { '1',	OP_SH_UDI1,	OP_MASK_UDI1,		0},
8494218822Sdim  { '2',	OP_SH_UDI2,	OP_MASK_UDI2,		0},
8495218822Sdim  { '3',	OP_SH_UDI3,	OP_MASK_UDI3,		0},
8496218822Sdim  { '4',	OP_SH_UDI4,	OP_MASK_UDI4,		0},
8497218822Sdim  { 0,0,0,0 }
8498218822Sdim};
8499218822Sdim
8500218822Sdim/* Check whether an odd floating-point register is allowed.  */
8501218822Sdimstatic int
8502218822Sdimmips_oddfpreg_ok (const struct mips_opcode *insn, int argnum)
8503218822Sdim{
8504218822Sdim  const char *s = insn->name;
8505218822Sdim
8506218822Sdim  if (insn->pinfo == INSN_MACRO)
8507218822Sdim    /* Let a macro pass, we'll catch it later when it is expanded.  */
8508218822Sdim    return 1;
8509218822Sdim
8510218822Sdim  if (ISA_HAS_ODD_SINGLE_FPR (mips_opts.isa))
8511218822Sdim    {
8512218822Sdim      /* Allow odd registers for single-precision ops.  */
8513218822Sdim      switch (insn->pinfo & (FP_S | FP_D))
8514218822Sdim	{
8515218822Sdim	case FP_S:
8516218822Sdim	case 0:
8517218822Sdim	  return 1;	/* both single precision - ok */
8518218822Sdim	case FP_D:
8519218822Sdim	  return 0;	/* both double precision - fail */
8520218822Sdim	default:
8521218822Sdim	  break;
8522218822Sdim	}
8523218822Sdim
8524218822Sdim      /* Cvt.w.x and cvt.x.w allow an odd register for a 'w' or 's' operand.  */
8525218822Sdim      s = strchr (insn->name, '.');
8526218822Sdim      if (argnum == 2)
8527218822Sdim	s = s != NULL ? strchr (s + 1, '.') : NULL;
8528218822Sdim      return (s != NULL && (s[1] == 'w' || s[1] == 's'));
8529218822Sdim    }
8530218822Sdim
8531218822Sdim  /* Single-precision coprocessor loads and moves are OK too.  */
8532218822Sdim  if ((insn->pinfo & FP_S)
8533218822Sdim      && (insn->pinfo & (INSN_COPROC_MEMORY_DELAY | INSN_STORE_MEMORY
8534218822Sdim			 | INSN_LOAD_COPROC_DELAY | INSN_COPROC_MOVE_DELAY)))
8535218822Sdim    return 1;
8536218822Sdim
8537218822Sdim  return 0;
8538218822Sdim}
8539218822Sdim
8540179404Sobrien/* This routine assembles an instruction into its binary format.  As a
8541179404Sobrien   side effect, it sets one of the global variables imm_reloc or
8542179404Sobrien   offset_reloc to the type of relocation to do if one of the operands
8543179404Sobrien   is an address expression.  */
8544179404Sobrien
8545179404Sobrienstatic void
8546179404Sobrienmips_ip (char *str, struct mips_cl_insn *ip)
8547179404Sobrien{
8548179404Sobrien  char *s;
8549179404Sobrien  const char *args;
8550179404Sobrien  char c = 0;
8551179404Sobrien  struct mips_opcode *insn;
8552179404Sobrien  char *argsStart;
8553179404Sobrien  unsigned int regno;
8554179404Sobrien  unsigned int lastregno = 0;
8555179404Sobrien  unsigned int lastpos = 0;
8556179404Sobrien  unsigned int limlo, limhi;
8557179404Sobrien  char *s_reset;
8558179404Sobrien  char save_c = 0;
8559208737Sjmallett  offsetT min_range, max_range;
8560218822Sdim  int argnum;
8561218822Sdim  unsigned int rtype;
8562179404Sobrien
8563179404Sobrien  insn_error = NULL;
8564179404Sobrien
8565179404Sobrien  /* If the instruction contains a '.', we first try to match an instruction
8566179404Sobrien     including the '.'.  Then we try again without the '.'.  */
8567179404Sobrien  insn = NULL;
8568179404Sobrien  for (s = str; *s != '\0' && !ISSPACE (*s); ++s)
8569179404Sobrien    continue;
8570179404Sobrien
8571179404Sobrien  /* If we stopped on whitespace, then replace the whitespace with null for
8572179404Sobrien     the call to hash_find.  Save the character we replaced just in case we
8573179404Sobrien     have to re-parse the instruction.  */
8574179404Sobrien  if (ISSPACE (*s))
8575179404Sobrien    {
8576179404Sobrien      save_c = *s;
8577179404Sobrien      *s++ = '\0';
8578179404Sobrien    }
8579179404Sobrien
8580179404Sobrien  insn = (struct mips_opcode *) hash_find (op_hash, str);
8581179404Sobrien
8582179404Sobrien  /* If we didn't find the instruction in the opcode table, try again, but
8583179404Sobrien     this time with just the instruction up to, but not including the
8584179404Sobrien     first '.'.  */
8585179404Sobrien  if (insn == NULL)
8586179404Sobrien    {
8587179404Sobrien      /* Restore the character we overwrite above (if any).  */
8588179404Sobrien      if (save_c)
8589179404Sobrien	*(--s) = save_c;
8590179404Sobrien
8591179404Sobrien      /* Scan up to the first '.' or whitespace.  */
8592179404Sobrien      for (s = str;
8593179404Sobrien	   *s != '\0' && *s != '.' && !ISSPACE (*s);
8594179404Sobrien	   ++s)
8595179404Sobrien	continue;
8596179404Sobrien
8597179404Sobrien      /* If we did not find a '.', then we can quit now.  */
8598179404Sobrien      if (*s != '.')
8599179404Sobrien	{
8600179404Sobrien	  insn_error = "unrecognized opcode";
8601179404Sobrien	  return;
8602179404Sobrien	}
8603179404Sobrien
8604179404Sobrien      /* Lookup the instruction in the hash table.  */
8605179404Sobrien      *s++ = '\0';
8606179404Sobrien      if ((insn = (struct mips_opcode *) hash_find (op_hash, str)) == NULL)
8607179404Sobrien	{
8608179404Sobrien	  insn_error = "unrecognized opcode";
8609179404Sobrien	  return;
8610179404Sobrien	}
8611179404Sobrien    }
8612179404Sobrien
8613179404Sobrien  argsStart = s;
8614179404Sobrien  for (;;)
8615179404Sobrien    {
8616179404Sobrien      bfd_boolean ok;
8617179404Sobrien
8618179404Sobrien      assert (strcmp (insn->name, str) == 0);
8619179404Sobrien
8620179404Sobrien      if (OPCODE_IS_MEMBER (insn,
8621179404Sobrien			    (mips_opts.isa
8622218822Sdim			     /* We don't check for mips_opts.mips16 here since
8623218822Sdim			        we want to allow jalx if -mips16 was specified
8624218822Sdim			        on the command line.  */
8625179404Sobrien			     | (file_ase_mips16 ? INSN_MIPS16 : 0)
8626179404Sobrien	      		     | (mips_opts.ase_mdmx ? INSN_MDMX : 0)
8627208737Sjmallett	      		     | (mips_opts.ase_dsp ? INSN_DSP : 0)
8628218822Sdim	      		     | ((mips_opts.ase_dsp && ISA_SUPPORTS_DSP64_ASE)
8629218822Sdim				? INSN_DSP64 : 0)
8630218822Sdim	      		     | (mips_opts.ase_dspr2 ? INSN_DSPR2 : 0)
8631208737Sjmallett	      		     | (mips_opts.ase_mt ? INSN_MT : 0)
8632218822Sdim			     | (mips_opts.ase_mips3d ? INSN_MIPS3D : 0)
8633218822Sdim			     | (mips_opts.ase_smartmips ? INSN_SMARTMIPS : 0)),
8634179404Sobrien			    mips_opts.arch))
8635179404Sobrien	ok = TRUE;
8636179404Sobrien      else
8637179404Sobrien	ok = FALSE;
8638179404Sobrien
8639179404Sobrien      if (insn->pinfo != INSN_MACRO)
8640179404Sobrien	{
8641179404Sobrien	  if (mips_opts.arch == CPU_R4650 && (insn->pinfo & FP_D) != 0)
8642179404Sobrien	    ok = FALSE;
8643208737Sjmallett
8644208737Sjmallett	  if (mips_opts.arch == CPU_OCTEON
8645208737Sjmallett	      && octeon_error_on_unsupported
8646208737Sjmallett	      && ((insn->pinfo & FP_D) != 0
8647208737Sjmallett	          || (insn->pinfo & FP_S) !=0
8648208737Sjmallett	          || strcmp (insn->name, "prefx") == 0))
8649208737Sjmallett	    {
8650208737Sjmallett	      insn_error = "opcode not implemented in Octeon";
8651208737Sjmallett	      return;
8652208737Sjmallett	    }
8653208737Sjmallett
8654208737Sjmallett	  if (mips_opts.arch == CPU_OCTEON
8655208737Sjmallett	      && octeon_error_on_unsupported
8656208737Sjmallett	      && (strcmp (insn->name, "swc2") == 0
8657208737Sjmallett		  || strcmp (insn->name, "lwc2") == 0
8658208737Sjmallett		  || strcmp (insn->name, "sdc2") == 0
8659208737Sjmallett		  || strcmp (insn->name, "ldc2") == 0
8660208737Sjmallett		  || strcmp (insn->name, "bc2f") == 0
8661208737Sjmallett		  || strcmp (insn->name, "bc2t") == 0
8662208737Sjmallett		  || strcmp (insn->name, "mfc2") == 0
8663208737Sjmallett		  || strcmp (insn->name, "mtc2") == 0
8664208737Sjmallett		  || strcmp (insn->name, "ctc2") == 0
8665208737Sjmallett		  || strcmp (insn->name, "cfc2") == 0
8666208737Sjmallett		  || strcmp (insn->name, "mfhc2") == 0
8667208737Sjmallett		  || strcmp (insn->name, "mthc2") == 0))
8668208737Sjmallett	    {
8669208737Sjmallett	      insn_error = "opcode not implemented in Octeon";
8670208737Sjmallett	      return;
8671208737Sjmallett	    }
8672208737Sjmallett
8673208737Sjmallett	  /* Issue a warning message for Octeon unaligned load/store
8674208737Sjmallett	     instructions used when octeon_use_unalign is not set.  */
8675208737Sjmallett	  if (mips_opts.arch == CPU_OCTEON && ! octeon_use_unalign
8676208737Sjmallett              && (strcmp (insn->name, "ulw") == 0
8677208737Sjmallett                  || strcmp (insn->name, "uld") == 0
8678208737Sjmallett                  || strcmp (insn->name, "usw") == 0
8679208737Sjmallett                  || strcmp (insn->name, "usd") == 0))
8680208737Sjmallett            {
8681208737Sjmallett              static char buf[120];
8682208737Sjmallett              sprintf (buf, _("Octeon specific unaligned load/store instructions are not allowed with -mno-octeon-useun"));
8683208737Sjmallett              insn_error = buf;
8684208737Sjmallett              return;
8685208737Sjmallett            }
8686208737Sjmallett
8687208737Sjmallett	  /* Issue a warning message for MIPS unaligned load/store
8688208737Sjmallett	     instructions used when octeon_use_unalign is set.  */
8689208737Sjmallett          if (mips_opts.arch == CPU_OCTEON && octeon_use_unalign
8690208737Sjmallett              && (strcmp (insn->name, "lwl") == 0
8691208737Sjmallett                  || strcmp (insn->name, "lwr") == 0
8692208737Sjmallett                  || strcmp (insn->name, "ldl") == 0
8693208737Sjmallett                  || strcmp (insn->name, "ldr") == 0
8694208737Sjmallett                  || strcmp (insn->name, "sdl") == 0
8695208737Sjmallett                  || strcmp (insn->name, "sdr") == 0
8696208737Sjmallett                  || strcmp (insn->name, "swr") == 0
8697208737Sjmallett                  || strcmp (insn->name, "swl") == 0))
8698208737Sjmallett            {
8699208737Sjmallett              static char buf[100];
8700208737Sjmallett              sprintf (buf, _("Unaligned load/store instructions are not allowed with -mocteon-useun"));
8701208737Sjmallett              insn_error = buf;
8702208737Sjmallett              return;
8703208737Sjmallett            }
8704179404Sobrien	}
8705179404Sobrien
8706208737Sjmallett      /* Octeon has its own version of dmtc2/dmfc2 instructions, error on
8707208737Sjmallett	 other formats.  */
8708208737Sjmallett      if (mips_opts.arch == CPU_OCTEON
8709208737Sjmallett	  && (strcmp (insn->name, "dmtc2") == 0
8710208737Sjmallett	      || strcmp (insn->name, "dmfc2") == 0)
8711208737Sjmallett	  && (insn->membership & INSN_OCTEON) != INSN_OCTEON)
8712208737Sjmallett	{
8713208737Sjmallett	  static char buf[100];
8714208737Sjmallett	  sprintf (buf,
8715208737Sjmallett		   _("opcode not supported in %s"),
8716208737Sjmallett		     mips_cpu_info_from_arch (mips_opts.arch)->name);
8717208737Sjmallett	  insn_error = buf;
8718208737Sjmallett	  ok = FALSE;
8719208737Sjmallett	}
8720208737Sjmallett
8721179404Sobrien      if (! ok)
8722179404Sobrien	{
8723179404Sobrien	  if (insn + 1 < &mips_opcodes[NUMOPCODES]
8724179404Sobrien	      && strcmp (insn->name, insn[1].name) == 0)
8725179404Sobrien	    {
8726179404Sobrien	      ++insn;
8727179404Sobrien	      continue;
8728179404Sobrien	    }
8729179404Sobrien	  else
8730179404Sobrien	    {
8731179404Sobrien	      if (!insn_error)
8732179404Sobrien		{
8733179404Sobrien		  static char buf[100];
8734179404Sobrien		  sprintf (buf,
8735179404Sobrien			   _("opcode not supported on this processor: %s (%s)"),
8736179404Sobrien			   mips_cpu_info_from_arch (mips_opts.arch)->name,
8737179404Sobrien			   mips_cpu_info_from_isa (mips_opts.isa)->name);
8738179404Sobrien		  insn_error = buf;
8739179404Sobrien		}
8740179404Sobrien	      if (save_c)
8741179404Sobrien		*(--s) = save_c;
8742179404Sobrien	      return;
8743179404Sobrien	    }
8744179404Sobrien	}
8745179404Sobrien
8746208737Sjmallett      create_insn (ip, insn);
8747179404Sobrien      insn_error = NULL;
8748218822Sdim      argnum = 1;
8749179404Sobrien      for (args = insn->args;; ++args)
8750179404Sobrien	{
8751179404Sobrien	  int is_mdmx;
8752179404Sobrien
8753179404Sobrien	  s += strspn (s, " \t");
8754179404Sobrien	  is_mdmx = 0;
8755179404Sobrien	  switch (*args)
8756179404Sobrien	    {
8757179404Sobrien	    case '\0':		/* end of args */
8758179404Sobrien	      if (*s == '\0')
8759179404Sobrien		return;
8760179404Sobrien	      break;
8761179404Sobrien
8762218822Sdim	    case '2': /* dsp 2-bit unsigned immediate in bit 11 */
8763218822Sdim	      my_getExpression (&imm_expr, s);
8764218822Sdim	      check_absolute_expr (ip, &imm_expr);
8765218822Sdim	      if ((unsigned long) imm_expr.X_add_number != 1
8766218822Sdim		  && (unsigned long) imm_expr.X_add_number != 3)
8767218822Sdim		{
8768218822Sdim		  as_bad (_("BALIGN immediate not 1 or 3 (%lu)"),
8769218822Sdim			  (unsigned long) imm_expr.X_add_number);
8770218822Sdim		}
8771218822Sdim	      INSERT_OPERAND (BP, *ip, imm_expr.X_add_number);
8772218822Sdim	      imm_expr.X_op = O_absent;
8773218822Sdim	      s = expr_end;
8774218822Sdim	      continue;
8775218822Sdim
8776208737Sjmallett	    case '3': /* dsp 3-bit unsigned immediate in bit 21 */
8777208737Sjmallett	      my_getExpression (&imm_expr, s);
8778208737Sjmallett	      check_absolute_expr (ip, &imm_expr);
8779208737Sjmallett	      if (imm_expr.X_add_number & ~OP_MASK_SA3)
8780208737Sjmallett		{
8781218822Sdim		  as_bad (_("DSP immediate not in range 0..%d (%lu)"),
8782218822Sdim			  OP_MASK_SA3, (unsigned long) imm_expr.X_add_number);
8783208737Sjmallett		}
8784218822Sdim	      INSERT_OPERAND (SA3, *ip, imm_expr.X_add_number);
8785208737Sjmallett	      imm_expr.X_op = O_absent;
8786208737Sjmallett	      s = expr_end;
8787208737Sjmallett	      continue;
8788208737Sjmallett
8789208737Sjmallett	    case '4': /* dsp 4-bit unsigned immediate in bit 21 */
8790208737Sjmallett	      my_getExpression (&imm_expr, s);
8791208737Sjmallett	      check_absolute_expr (ip, &imm_expr);
8792208737Sjmallett	      if (imm_expr.X_add_number & ~OP_MASK_SA4)
8793208737Sjmallett		{
8794218822Sdim		  as_bad (_("DSP immediate not in range 0..%d (%lu)"),
8795218822Sdim			  OP_MASK_SA4, (unsigned long) imm_expr.X_add_number);
8796208737Sjmallett		}
8797218822Sdim	      INSERT_OPERAND (SA4, *ip, imm_expr.X_add_number);
8798208737Sjmallett	      imm_expr.X_op = O_absent;
8799208737Sjmallett	      s = expr_end;
8800208737Sjmallett	      continue;
8801208737Sjmallett
8802208737Sjmallett	    case '5': /* dsp 8-bit unsigned immediate in bit 16 */
8803208737Sjmallett	      my_getExpression (&imm_expr, s);
8804208737Sjmallett	      check_absolute_expr (ip, &imm_expr);
8805208737Sjmallett	      if (imm_expr.X_add_number & ~OP_MASK_IMM8)
8806208737Sjmallett		{
8807218822Sdim		  as_bad (_("DSP immediate not in range 0..%d (%lu)"),
8808218822Sdim			  OP_MASK_IMM8, (unsigned long) imm_expr.X_add_number);
8809208737Sjmallett		}
8810218822Sdim	      INSERT_OPERAND (IMM8, *ip, imm_expr.X_add_number);
8811208737Sjmallett	      imm_expr.X_op = O_absent;
8812208737Sjmallett	      s = expr_end;
8813208737Sjmallett	      continue;
8814208737Sjmallett
8815208737Sjmallett	    case '6': /* dsp 5-bit unsigned immediate in bit 21 */
8816208737Sjmallett	      my_getExpression (&imm_expr, s);
8817208737Sjmallett	      check_absolute_expr (ip, &imm_expr);
8818208737Sjmallett	      if (imm_expr.X_add_number & ~OP_MASK_RS)
8819208737Sjmallett		{
8820218822Sdim		  as_bad (_("DSP immediate not in range 0..%d (%lu)"),
8821218822Sdim			  OP_MASK_RS, (unsigned long) imm_expr.X_add_number);
8822208737Sjmallett		}
8823218822Sdim	      INSERT_OPERAND (RS, *ip, imm_expr.X_add_number);
8824208737Sjmallett	      imm_expr.X_op = O_absent;
8825208737Sjmallett	      s = expr_end;
8826208737Sjmallett	      continue;
8827208737Sjmallett
8828208737Sjmallett	    case '7': /* four dsp accumulators in bits 11,12 */
8829208737Sjmallett	      if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
8830208737Sjmallett		  s[3] >= '0' && s[3] <= '3')
8831208737Sjmallett		{
8832208737Sjmallett		  regno = s[3] - '0';
8833208737Sjmallett		  s += 4;
8834218822Sdim		  INSERT_OPERAND (DSPACC, *ip, regno);
8835208737Sjmallett		  continue;
8836208737Sjmallett		}
8837208737Sjmallett	      else
8838208737Sjmallett		as_bad (_("Invalid dsp acc register"));
8839208737Sjmallett	      break;
8840208737Sjmallett
8841208737Sjmallett	    case '8': /* dsp 6-bit unsigned immediate in bit 11 */
8842208737Sjmallett	      my_getExpression (&imm_expr, s);
8843208737Sjmallett	      check_absolute_expr (ip, &imm_expr);
8844208737Sjmallett	      if (imm_expr.X_add_number & ~OP_MASK_WRDSP)
8845208737Sjmallett		{
8846218822Sdim		  as_bad (_("DSP immediate not in range 0..%d (%lu)"),
8847218822Sdim			  OP_MASK_WRDSP,
8848218822Sdim			  (unsigned long) imm_expr.X_add_number);
8849208737Sjmallett		}
8850218822Sdim	      INSERT_OPERAND (WRDSP, *ip, imm_expr.X_add_number);
8851208737Sjmallett	      imm_expr.X_op = O_absent;
8852208737Sjmallett	      s = expr_end;
8853208737Sjmallett	      continue;
8854208737Sjmallett
8855208737Sjmallett	    case '9': /* four dsp accumulators in bits 21,22 */
8856208737Sjmallett	      if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
8857208737Sjmallett		  s[3] >= '0' && s[3] <= '3')
8858208737Sjmallett		{
8859208737Sjmallett		  regno = s[3] - '0';
8860208737Sjmallett		  s += 4;
8861218822Sdim		  INSERT_OPERAND (DSPACC_S, *ip, regno);
8862208737Sjmallett		  continue;
8863208737Sjmallett		}
8864208737Sjmallett	      else
8865208737Sjmallett		as_bad (_("Invalid dsp acc register"));
8866208737Sjmallett	      break;
8867208737Sjmallett
8868208737Sjmallett	    case '0': /* dsp 6-bit signed immediate in bit 20 */
8869208737Sjmallett	      my_getExpression (&imm_expr, s);
8870208737Sjmallett	      check_absolute_expr (ip, &imm_expr);
8871208737Sjmallett	      min_range = -((OP_MASK_DSPSFT + 1) >> 1);
8872208737Sjmallett	      max_range = ((OP_MASK_DSPSFT + 1) >> 1) - 1;
8873208737Sjmallett	      if (imm_expr.X_add_number < min_range ||
8874208737Sjmallett		  imm_expr.X_add_number > max_range)
8875208737Sjmallett		{
8876218822Sdim		  as_bad (_("DSP immediate not in range %ld..%ld (%ld)"),
8877218822Sdim			  (long) min_range, (long) max_range,
8878218822Sdim			  (long) imm_expr.X_add_number);
8879208737Sjmallett		}
8880218822Sdim	      INSERT_OPERAND (DSPSFT, *ip, imm_expr.X_add_number);
8881208737Sjmallett	      imm_expr.X_op = O_absent;
8882208737Sjmallett	      s = expr_end;
8883208737Sjmallett	      continue;
8884208737Sjmallett
8885208737Sjmallett	    case '\'': /* dsp 6-bit unsigned immediate in bit 16 */
8886208737Sjmallett	      my_getExpression (&imm_expr, s);
8887208737Sjmallett	      check_absolute_expr (ip, &imm_expr);
8888208737Sjmallett	      if (imm_expr.X_add_number & ~OP_MASK_RDDSP)
8889208737Sjmallett		{
8890218822Sdim		  as_bad (_("DSP immediate not in range 0..%d (%lu)"),
8891218822Sdim			  OP_MASK_RDDSP,
8892218822Sdim			  (unsigned long) imm_expr.X_add_number);
8893208737Sjmallett		}
8894218822Sdim	      INSERT_OPERAND (RDDSP, *ip, imm_expr.X_add_number);
8895208737Sjmallett	      imm_expr.X_op = O_absent;
8896208737Sjmallett	      s = expr_end;
8897208737Sjmallett	      continue;
8898208737Sjmallett
8899208737Sjmallett	    case ':': /* dsp 7-bit signed immediate in bit 19 */
8900208737Sjmallett	      my_getExpression (&imm_expr, s);
8901208737Sjmallett	      check_absolute_expr (ip, &imm_expr);
8902208737Sjmallett	      min_range = -((OP_MASK_DSPSFT_7 + 1) >> 1);
8903208737Sjmallett	      max_range = ((OP_MASK_DSPSFT_7 + 1) >> 1) - 1;
8904208737Sjmallett	      if (imm_expr.X_add_number < min_range ||
8905208737Sjmallett		  imm_expr.X_add_number > max_range)
8906208737Sjmallett		{
8907218822Sdim		  as_bad (_("DSP immediate not in range %ld..%ld (%ld)"),
8908218822Sdim			  (long) min_range, (long) max_range,
8909218822Sdim			  (long) imm_expr.X_add_number);
8910208737Sjmallett		}
8911218822Sdim	      INSERT_OPERAND (DSPSFT_7, *ip, imm_expr.X_add_number);
8912208737Sjmallett	      imm_expr.X_op = O_absent;
8913208737Sjmallett	      s = expr_end;
8914208737Sjmallett	      continue;
8915208737Sjmallett
8916208737Sjmallett	    case '@': /* dsp 10-bit signed immediate in bit 16 */
8917208737Sjmallett	      my_getExpression (&imm_expr, s);
8918208737Sjmallett	      check_absolute_expr (ip, &imm_expr);
8919208737Sjmallett	      min_range = -((OP_MASK_IMM10 + 1) >> 1);
8920208737Sjmallett	      max_range = ((OP_MASK_IMM10 + 1) >> 1) - 1;
8921208737Sjmallett	      if (imm_expr.X_add_number < min_range ||
8922208737Sjmallett		  imm_expr.X_add_number > max_range)
8923208737Sjmallett		{
8924218822Sdim		  as_bad (_("DSP immediate not in range %ld..%ld (%ld)"),
8925218822Sdim			  (long) min_range, (long) max_range,
8926218822Sdim			  (long) imm_expr.X_add_number);
8927208737Sjmallett		}
8928218822Sdim	      INSERT_OPERAND (IMM10, *ip, imm_expr.X_add_number);
8929208737Sjmallett	      imm_expr.X_op = O_absent;
8930208737Sjmallett	      s = expr_end;
8931208737Sjmallett	      continue;
8932208737Sjmallett
8933218822Sdim            case '!': /* MT usermode flag bit.  */
8934208737Sjmallett	      my_getExpression (&imm_expr, s);
8935208737Sjmallett	      check_absolute_expr (ip, &imm_expr);
8936208737Sjmallett	      if (imm_expr.X_add_number & ~OP_MASK_MT_U)
8937218822Sdim		as_bad (_("MT usermode bit not 0 or 1 (%lu)"),
8938218822Sdim			(unsigned long) imm_expr.X_add_number);
8939218822Sdim	      INSERT_OPERAND (MT_U, *ip, imm_expr.X_add_number);
8940208737Sjmallett	      imm_expr.X_op = O_absent;
8941208737Sjmallett	      s = expr_end;
8942208737Sjmallett	      continue;
8943208737Sjmallett
8944218822Sdim            case '$': /* MT load high flag bit.  */
8945208737Sjmallett	      my_getExpression (&imm_expr, s);
8946208737Sjmallett	      check_absolute_expr (ip, &imm_expr);
8947208737Sjmallett	      if (imm_expr.X_add_number & ~OP_MASK_MT_H)
8948218822Sdim		as_bad (_("MT load high bit not 0 or 1 (%lu)"),
8949218822Sdim			(unsigned long) imm_expr.X_add_number);
8950218822Sdim	      INSERT_OPERAND (MT_H, *ip, imm_expr.X_add_number);
8951208737Sjmallett	      imm_expr.X_op = O_absent;
8952208737Sjmallett	      s = expr_end;
8953208737Sjmallett	      continue;
8954208737Sjmallett
8955208737Sjmallett	    case '*': /* four dsp accumulators in bits 18,19 */
8956208737Sjmallett	      if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
8957208737Sjmallett		  s[3] >= '0' && s[3] <= '3')
8958208737Sjmallett		{
8959208737Sjmallett		  regno = s[3] - '0';
8960208737Sjmallett		  s += 4;
8961218822Sdim		  INSERT_OPERAND (MTACC_T, *ip, regno);
8962208737Sjmallett		  continue;
8963208737Sjmallett		}
8964208737Sjmallett	      else
8965208737Sjmallett		as_bad (_("Invalid dsp/smartmips acc register"));
8966208737Sjmallett	      break;
8967208737Sjmallett
8968208737Sjmallett	    case '&': /* four dsp accumulators in bits 13,14 */
8969208737Sjmallett	      if (s[0] == '$' && s[1] == 'a' && s[2] == 'c' &&
8970208737Sjmallett		  s[3] >= '0' && s[3] <= '3')
8971208737Sjmallett		{
8972208737Sjmallett		  regno = s[3] - '0';
8973208737Sjmallett		  s += 4;
8974218822Sdim		  INSERT_OPERAND (MTACC_D, *ip, regno);
8975208737Sjmallett		  continue;
8976208737Sjmallett		}
8977208737Sjmallett	      else
8978208737Sjmallett		as_bad (_("Invalid dsp/smartmips acc register"));
8979208737Sjmallett	      break;
8980208737Sjmallett
8981179404Sobrien	    case ',':
8982218822Sdim	      ++argnum;
8983179404Sobrien	      if (*s++ == *args)
8984179404Sobrien		continue;
8985179404Sobrien	      s--;
8986179404Sobrien	      switch (*++args)
8987179404Sobrien		{
8988179404Sobrien		case 'r':
8989179404Sobrien		case 'v':
8990208737Sjmallett		  INSERT_OPERAND (RS, *ip, lastregno);
8991179404Sobrien		  continue;
8992179404Sobrien
8993179404Sobrien		case 'w':
8994208737Sjmallett		  INSERT_OPERAND (RT, *ip, lastregno);
8995179404Sobrien		  continue;
8996179404Sobrien
8997179404Sobrien		case 'W':
8998208737Sjmallett		  INSERT_OPERAND (FT, *ip, lastregno);
8999179404Sobrien		  continue;
9000179404Sobrien
9001179404Sobrien		case 'V':
9002208737Sjmallett		  INSERT_OPERAND (FS, *ip, lastregno);
9003179404Sobrien		  continue;
9004179404Sobrien		}
9005179404Sobrien	      break;
9006179404Sobrien
9007179404Sobrien	    case '(':
9008179404Sobrien	      /* Handle optional base register.
9009179404Sobrien		 Either the base register is omitted or
9010179404Sobrien		 we must have a left paren.  */
9011179404Sobrien	      /* This is dependent on the next operand specifier
9012179404Sobrien		 is a base register specification.  */
9013179404Sobrien	      assert (args[1] == 'b' || args[1] == '5'
9014179404Sobrien		      || args[1] == '-' || args[1] == '4');
9015179404Sobrien	      if (*s == '\0')
9016179404Sobrien		return;
9017179404Sobrien
9018179404Sobrien	    case ')':		/* these must match exactly */
9019179404Sobrien	    case '[':
9020179404Sobrien	    case ']':
9021179404Sobrien	      if (*s++ == *args)
9022179404Sobrien		continue;
9023179404Sobrien	      break;
9024179404Sobrien
9025179404Sobrien	    case '+':		/* Opcode extension character.  */
9026179404Sobrien	      switch (*++args)
9027179404Sobrien		{
9028218822Sdim		case '1':	/* UDI immediates.  */
9029218822Sdim		case '2':
9030218822Sdim		case '3':
9031218822Sdim		case '4':
9032218822Sdim		  {
9033218822Sdim		    const struct mips_immed *imm = mips_immed;
9034218822Sdim
9035218822Sdim		    while (imm->type && imm->type != *args)
9036218822Sdim		      ++imm;
9037218822Sdim		    if (! imm->type)
9038218822Sdim		      internalError ();
9039218822Sdim		    my_getExpression (&imm_expr, s);
9040218822Sdim		    check_absolute_expr (ip, &imm_expr);
9041218822Sdim		    if ((unsigned long) imm_expr.X_add_number & ~imm->mask)
9042218822Sdim		      {
9043218822Sdim		        as_warn (_("Illegal %s number (%lu, 0x%lx)"),
9044218822Sdim				 imm->desc ? imm->desc : ip->insn_mo->name,
9045218822Sdim				 (unsigned long) imm_expr.X_add_number,
9046218822Sdim				 (unsigned long) imm_expr.X_add_number);
9047218822Sdim			      imm_expr.X_add_number &= imm->mask;
9048218822Sdim		      }
9049218822Sdim		    ip->insn_opcode |= ((unsigned long) imm_expr.X_add_number
9050218822Sdim					<< imm->shift);
9051218822Sdim		    imm_expr.X_op = O_absent;
9052218822Sdim		    s = expr_end;
9053218822Sdim		  }
9054218822Sdim		  continue;
9055218822Sdim
9056179404Sobrien		case 'A':		/* ins/ext position, becomes LSB.  */
9057179404Sobrien		  limlo = 0;
9058179404Sobrien		  limhi = 31;
9059179404Sobrien		  goto do_lsb;
9060179404Sobrien		case 'E':
9061179404Sobrien		  limlo = 32;
9062179404Sobrien		  limhi = 63;
9063179404Sobrien		  goto do_lsb;
9064179404Sobriendo_lsb:
9065179404Sobrien		  my_getExpression (&imm_expr, s);
9066179404Sobrien		  check_absolute_expr (ip, &imm_expr);
9067179404Sobrien		  if ((unsigned long) imm_expr.X_add_number < limlo
9068179404Sobrien		      || (unsigned long) imm_expr.X_add_number > limhi)
9069179404Sobrien		    {
9070179404Sobrien		      as_bad (_("Improper position (%lu)"),
9071179404Sobrien			      (unsigned long) imm_expr.X_add_number);
9072179404Sobrien		      imm_expr.X_add_number = limlo;
9073179404Sobrien		    }
9074179404Sobrien		  lastpos = imm_expr.X_add_number;
9075208737Sjmallett		  INSERT_OPERAND (SHAMT, *ip, imm_expr.X_add_number);
9076179404Sobrien		  imm_expr.X_op = O_absent;
9077179404Sobrien		  s = expr_end;
9078179404Sobrien		  continue;
9079179404Sobrien
9080179404Sobrien		case 'B':		/* ins size, becomes MSB.  */
9081179404Sobrien		  limlo = 1;
9082179404Sobrien		  limhi = 32;
9083179404Sobrien		  goto do_msb;
9084179404Sobrien		case 'F':
9085179404Sobrien		  limlo = 33;
9086179404Sobrien		  limhi = 64;
9087179404Sobrien		  goto do_msb;
9088179404Sobriendo_msb:
9089179404Sobrien		  my_getExpression (&imm_expr, s);
9090179404Sobrien		  check_absolute_expr (ip, &imm_expr);
9091179404Sobrien		  /* Check for negative input so that small negative numbers
9092179404Sobrien		     will not succeed incorrectly.  The checks against
9093179404Sobrien		     (pos+size) transitively check "size" itself,
9094179404Sobrien		     assuming that "pos" is reasonable.  */
9095179404Sobrien		  if ((long) imm_expr.X_add_number < 0
9096179404Sobrien		      || ((unsigned long) imm_expr.X_add_number
9097179404Sobrien			  + lastpos) < limlo
9098179404Sobrien		      || ((unsigned long) imm_expr.X_add_number
9099179404Sobrien			  + lastpos) > limhi)
9100179404Sobrien		    {
9101179404Sobrien		      as_bad (_("Improper insert size (%lu, position %lu)"),
9102179404Sobrien			      (unsigned long) imm_expr.X_add_number,
9103179404Sobrien			      (unsigned long) lastpos);
9104179404Sobrien		      imm_expr.X_add_number = limlo - lastpos;
9105179404Sobrien		    }
9106208737Sjmallett		  INSERT_OPERAND (INSMSB, *ip,
9107208737Sjmallett				 lastpos + imm_expr.X_add_number - 1);
9108179404Sobrien		  imm_expr.X_op = O_absent;
9109179404Sobrien		  s = expr_end;
9110179404Sobrien		  continue;
9111179404Sobrien
9112179404Sobrien		case 'C':		/* ext size, becomes MSBD.  */
9113179404Sobrien		  limlo = 1;
9114179404Sobrien		  limhi = 32;
9115179404Sobrien		  goto do_msbd;
9116179404Sobrien		case 'G':
9117179404Sobrien		  limlo = 33;
9118179404Sobrien		  limhi = 64;
9119179404Sobrien		  goto do_msbd;
9120179404Sobrien		case 'H':
9121179404Sobrien		  limlo = 33;
9122179404Sobrien		  limhi = 64;
9123179404Sobrien		  goto do_msbd;
9124179404Sobriendo_msbd:
9125179404Sobrien		  my_getExpression (&imm_expr, s);
9126179404Sobrien		  check_absolute_expr (ip, &imm_expr);
9127179404Sobrien		  /* Check for negative input so that small negative numbers
9128179404Sobrien		     will not succeed incorrectly.  The checks against
9129179404Sobrien		     (pos+size) transitively check "size" itself,
9130179404Sobrien		     assuming that "pos" is reasonable.  */
9131179404Sobrien		  if ((long) imm_expr.X_add_number < 0
9132179404Sobrien		      || ((unsigned long) imm_expr.X_add_number
9133179404Sobrien			  + lastpos) < limlo
9134179404Sobrien		      || ((unsigned long) imm_expr.X_add_number
9135179404Sobrien			  + lastpos) > limhi)
9136179404Sobrien		    {
9137179404Sobrien		      as_bad (_("Improper extract size (%lu, position %lu)"),
9138179404Sobrien			      (unsigned long) imm_expr.X_add_number,
9139179404Sobrien			      (unsigned long) lastpos);
9140179404Sobrien		      imm_expr.X_add_number = limlo - lastpos;
9141179404Sobrien		    }
9142208737Sjmallett		  INSERT_OPERAND (EXTMSBD, *ip, imm_expr.X_add_number - 1);
9143179404Sobrien		  imm_expr.X_op = O_absent;
9144179404Sobrien		  s = expr_end;
9145179404Sobrien		  continue;
9146179404Sobrien
9147179404Sobrien		case 'D':
9148179404Sobrien		  /* +D is for disassembly only; never match.  */
9149179404Sobrien		  break;
9150179404Sobrien
9151179404Sobrien		case 'I':
9152179404Sobrien		  /* "+I" is like "I", except that imm2_expr is used.  */
9153179404Sobrien		  my_getExpression (&imm2_expr, s);
9154179404Sobrien		  if (imm2_expr.X_op != O_big
9155179404Sobrien		      && imm2_expr.X_op != O_constant)
9156179404Sobrien		  insn_error = _("absolute expression required");
9157208737Sjmallett		  if (HAVE_32BIT_GPRS)
9158208737Sjmallett		    normalize_constant_expr (&imm2_expr);
9159179404Sobrien		  s = expr_end;
9160179404Sobrien		  continue;
9161179404Sobrien
9162218822Sdim		case 'T': /* Coprocessor register.  */
9163208737Sjmallett		  /* +T is for disassembly only; never match.  */
9164208737Sjmallett		  break;
9165208737Sjmallett
9166218822Sdim		case 't': /* Coprocessor register number.  */
9167208737Sjmallett		  if (s[0] == '$' && ISDIGIT (s[1]))
9168208737Sjmallett		    {
9169208737Sjmallett		      ++s;
9170208737Sjmallett		      regno = 0;
9171208737Sjmallett		      do
9172208737Sjmallett		        {
9173208737Sjmallett			  regno *= 10;
9174208737Sjmallett			  regno += *s - '0';
9175208737Sjmallett			  ++s;
9176208737Sjmallett			}
9177208737Sjmallett		      while (ISDIGIT (*s));
9178208737Sjmallett		      if (regno > 31)
9179208737Sjmallett			as_bad (_("Invalid register number (%d)"), regno);
9180208737Sjmallett		      else
9181208737Sjmallett			{
9182218822Sdim			  INSERT_OPERAND (RT, *ip, regno);
9183208737Sjmallett			  continue;
9184208737Sjmallett			}
9185208737Sjmallett		    }
9186208737Sjmallett		  else
9187208737Sjmallett		    as_bad (_("Invalid coprocessor 0 register number"));
9188208737Sjmallett		  break;
9189208737Sjmallett
9190179404Sobrien		default:
9191179404Sobrien		  as_bad (_("internal: bad mips opcode (unknown extension operand type `+%c'): %s %s"),
9192179404Sobrien		    *args, insn->name, insn->args);
9193179404Sobrien		  /* Further processing is fruitless.  */
9194179404Sobrien		  return;
9195179404Sobrien		}
9196179404Sobrien	      break;
9197179404Sobrien
9198179404Sobrien	    case '<':		/* must be at least one digit */
9199179404Sobrien	      /*
9200179404Sobrien	       * According to the manual, if the shift amount is greater
9201179404Sobrien	       * than 31 or less than 0, then the shift amount should be
9202179404Sobrien	       * mod 32.  In reality the mips assembler issues an error.
9203179404Sobrien	       * We issue a warning and mask out all but the low 5 bits.
9204179404Sobrien	       */
9205179404Sobrien	      my_getExpression (&imm_expr, s);
9206179404Sobrien	      check_absolute_expr (ip, &imm_expr);
9207179404Sobrien	      if ((unsigned long) imm_expr.X_add_number > 31)
9208208737Sjmallett		as_warn (_("Improper shift amount (%lu)"),
9209208737Sjmallett			 (unsigned long) imm_expr.X_add_number);
9210208737Sjmallett	      INSERT_OPERAND (SHAMT, *ip, imm_expr.X_add_number);
9211179404Sobrien	      imm_expr.X_op = O_absent;
9212179404Sobrien	      s = expr_end;
9213179404Sobrien	      continue;
9214179404Sobrien
9215179404Sobrien	    case '>':		/* shift amount minus 32 */
9216179404Sobrien	      my_getExpression (&imm_expr, s);
9217179404Sobrien	      check_absolute_expr (ip, &imm_expr);
9218179404Sobrien	      if ((unsigned long) imm_expr.X_add_number < 32
9219179404Sobrien		  || (unsigned long) imm_expr.X_add_number > 63)
9220179404Sobrien		break;
9221208737Sjmallett	      INSERT_OPERAND (SHAMT, *ip, imm_expr.X_add_number - 32);
9222179404Sobrien	      imm_expr.X_op = O_absent;
9223179404Sobrien	      s = expr_end;
9224179404Sobrien	      continue;
9225179404Sobrien
9226208737Sjmallett             case '^':           /* must be at least one digit */
9227208737Sjmallett	      /* Decode 5-bits of bbit0/1's bit index amount. If the value is
9228208737Sjmallett		 greater than 31, issue a warning and mask out all but the low
9229208737Sjmallett		 5 bits.  */
9230179404Sobrien	      my_getExpression (&imm_expr, s);
9231179404Sobrien	      check_absolute_expr (ip, &imm_expr);
9232179404Sobrien	      if ((unsigned long) imm_expr.X_add_number > 31)
9233179404Sobrien		{
9234208737Sjmallett		  as_warn (_("Improper bit index amount (%lu)"),
9235179404Sobrien			   (unsigned long) imm_expr.X_add_number);
9236208737Sjmallett		  imm_expr.X_add_number &= OP_MASK_BITIND;
9237179404Sobrien		}
9238208737Sjmallett	      ip->insn_opcode |= imm_expr.X_add_number << OP_SH_BITIND;
9239208737Sjmallett	      imm_expr.X_op = O_absent;
9240208737Sjmallett	      s = expr_end;
9241208737Sjmallett	      continue;
9242208737Sjmallett
9243208737Sjmallett            case '~':           /* bit index minus 32 */
9244208737Sjmallett	      my_getExpression (&imm_expr, s);
9245208737Sjmallett	      check_absolute_expr (ip, &imm_expr);
9246208737Sjmallett	      if ((unsigned long) imm_expr.X_add_number < 32
9247208737Sjmallett	          || (unsigned long) imm_expr.X_add_number > 63)
9248208737Sjmallett	        break;
9249208737Sjmallett	      ip->insn_opcode |= (imm_expr.X_add_number - 32) << OP_SH_BITIND;
9250208737Sjmallett	      imm_expr.X_op = O_absent;
9251208737Sjmallett	      s = expr_end;
9252208737Sjmallett	      continue;
9253208737Sjmallett
9254208737Sjmallett	    case 'k':		/* cache code */
9255208737Sjmallett	    case 'h':		/* prefx code */
9256208737Sjmallett	      my_getExpression (&imm_expr, s);
9257208737Sjmallett	      check_absolute_expr (ip, &imm_expr);
9258208737Sjmallett	      if ((unsigned long) imm_expr.X_add_number > 31)
9259208737Sjmallett		as_warn (_("Invalid value for `%s' (%lu)"),
9260208737Sjmallett			 ip->insn_mo->name,
9261208737Sjmallett			 (unsigned long) imm_expr.X_add_number);
9262179404Sobrien	      if (*args == 'k')
9263208737Sjmallett		INSERT_OPERAND (CACHE, *ip, imm_expr.X_add_number);
9264179404Sobrien	      else
9265208737Sjmallett		INSERT_OPERAND (PREFX, *ip, imm_expr.X_add_number);
9266179404Sobrien	      imm_expr.X_op = O_absent;
9267179404Sobrien	      s = expr_end;
9268179404Sobrien	      continue;
9269179404Sobrien
9270179404Sobrien	    case 'c':		/* break code */
9271179404Sobrien	      my_getExpression (&imm_expr, s);
9272179404Sobrien	      check_absolute_expr (ip, &imm_expr);
9273218822Sdim	      if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE)
9274218822Sdim		as_warn (_("Code for %s not in range 0..1023 (%lu)"),
9275218822Sdim			 ip->insn_mo->name,
9276208737Sjmallett			 (unsigned long) imm_expr.X_add_number);
9277208737Sjmallett	      INSERT_OPERAND (CODE, *ip, imm_expr.X_add_number);
9278179404Sobrien	      imm_expr.X_op = O_absent;
9279179404Sobrien	      s = expr_end;
9280179404Sobrien	      continue;
9281179404Sobrien
9282179404Sobrien	    case 'q':		/* lower break code */
9283179404Sobrien	      my_getExpression (&imm_expr, s);
9284179404Sobrien	      check_absolute_expr (ip, &imm_expr);
9285218822Sdim	      if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE2)
9286218822Sdim		as_warn (_("Lower code for %s not in range 0..1023 (%lu)"),
9287218822Sdim			 ip->insn_mo->name,
9288208737Sjmallett			 (unsigned long) imm_expr.X_add_number);
9289208737Sjmallett	      INSERT_OPERAND (CODE2, *ip, imm_expr.X_add_number);
9290208737Sjmallett	      imm_expr.X_op = O_absent;
9291208737Sjmallett	      s = expr_end;
9292208737Sjmallett	      continue;
9293208737Sjmallett
9294208737Sjmallett	    case 'y':
9295208737Sjmallett	      /* Decode 10-bits of seqi/snei's signed constant offset. Issue
9296208737Sjmallett		 a warning message if the value is not within the range.  */
9297208737Sjmallett	      my_getExpression (&imm_expr, s);
9298208737Sjmallett	      check_absolute_expr (ip, &imm_expr);
9299208737Sjmallett	      if (((unsigned long) imm_expr.X_add_number + 0x200) > 1023)
9300179404Sobrien		{
9301208737Sjmallett		  as_warn (_("Illegal 10-bit signed constant (%lu)"),
9302179404Sobrien			   (unsigned long) imm_expr.X_add_number);
9303208737Sjmallett		 	   imm_expr.X_add_number &= OP_MASK_CODE2;
9304179404Sobrien		}
9305208737Sjmallett	      ip->insn_opcode |= (imm_expr.X_add_number & OP_MASK_CODE2)
9306208737Sjmallett				  << OP_SH_CODE2;
9307179404Sobrien	      imm_expr.X_op = O_absent;
9308179404Sobrien	      s = expr_end;
9309179404Sobrien	      continue;
9310179404Sobrien
9311179404Sobrien	    case 'B':           /* 20-bit syscall/break code.  */
9312179404Sobrien	      my_getExpression (&imm_expr, s);
9313179404Sobrien	      check_absolute_expr (ip, &imm_expr);
9314179404Sobrien	      if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE20)
9315218822Sdim		as_warn (_("Code for %s not in range 0..1048575 (%lu)"),
9316218822Sdim			 ip->insn_mo->name,
9317179404Sobrien			 (unsigned long) imm_expr.X_add_number);
9318208737Sjmallett	      INSERT_OPERAND (CODE20, *ip, imm_expr.X_add_number);
9319179404Sobrien	      imm_expr.X_op = O_absent;
9320179404Sobrien	      s = expr_end;
9321179404Sobrien	      continue;
9322179404Sobrien
9323179404Sobrien	    case 'C':           /* Coprocessor code */
9324179404Sobrien	      my_getExpression (&imm_expr, s);
9325179404Sobrien	      check_absolute_expr (ip, &imm_expr);
9326218822Sdim	      if ((unsigned long) imm_expr.X_add_number > OP_MASK_COPZ)
9327179404Sobrien		{
9328179404Sobrien		  as_warn (_("Coproccesor code > 25 bits (%lu)"),
9329179404Sobrien			   (unsigned long) imm_expr.X_add_number);
9330218822Sdim		  imm_expr.X_add_number &= OP_MASK_COPZ;
9331179404Sobrien		}
9332218822Sdim	      INSERT_OPERAND (COPZ, *ip, imm_expr.X_add_number);
9333179404Sobrien	      imm_expr.X_op = O_absent;
9334179404Sobrien	      s = expr_end;
9335179404Sobrien	      continue;
9336179404Sobrien
9337179404Sobrien	    case 'J':           /* 19-bit wait code.  */
9338179404Sobrien	      my_getExpression (&imm_expr, s);
9339179404Sobrien	      check_absolute_expr (ip, &imm_expr);
9340179404Sobrien	      if ((unsigned long) imm_expr.X_add_number > OP_MASK_CODE19)
9341218822Sdim		{
9342218822Sdim		  as_warn (_("Illegal 19-bit code (%lu)"),
9343218822Sdim			   (unsigned long) imm_expr.X_add_number);
9344218822Sdim		  imm_expr.X_add_number &= OP_MASK_CODE19;
9345218822Sdim		}
9346208737Sjmallett	      INSERT_OPERAND (CODE19, *ip, imm_expr.X_add_number);
9347179404Sobrien	      imm_expr.X_op = O_absent;
9348179404Sobrien	      s = expr_end;
9349179404Sobrien	      continue;
9350179404Sobrien
9351218822Sdim	    case 'P':		/* Performance register.  */
9352179404Sobrien	      my_getExpression (&imm_expr, s);
9353179404Sobrien	      check_absolute_expr (ip, &imm_expr);
9354179404Sobrien	      if (imm_expr.X_add_number != 0 && imm_expr.X_add_number != 1)
9355208737Sjmallett		as_warn (_("Invalid performance register (%lu)"),
9356208737Sjmallett			 (unsigned long) imm_expr.X_add_number);
9357208737Sjmallett	      INSERT_OPERAND (PERFREG, *ip, imm_expr.X_add_number);
9358179404Sobrien	      imm_expr.X_op = O_absent;
9359179404Sobrien	      s = expr_end;
9360179404Sobrien	      continue;
9361179404Sobrien
9362218822Sdim	    case 'G':		/* Coprocessor destination register.  */
9363218822Sdim	      if (((ip->insn_opcode >> OP_SH_OP) & OP_MASK_OP) == OP_OP_COP0)
9364218822Sdim		ok = reg_lookup (&s, RTYPE_NUM | RTYPE_CP0, &regno);
9365218822Sdim	      else
9366218822Sdim		ok = reg_lookup (&s, RTYPE_NUM | RTYPE_GP, &regno);
9367218822Sdim	      INSERT_OPERAND (RD, *ip, regno);
9368218822Sdim	      if (ok)
9369218822Sdim		{
9370218822Sdim		  lastregno = regno;
9371218822Sdim		  continue;
9372218822Sdim		}
9373218822Sdim	      else
9374218822Sdim		break;
9375218822Sdim
9376179404Sobrien	    case 'b':		/* base register */
9377179404Sobrien	    case 'd':		/* destination register */
9378179404Sobrien	    case 's':		/* source register */
9379179404Sobrien	    case 't':		/* target register */
9380179404Sobrien	    case 'r':		/* both target and source */
9381179404Sobrien	    case 'v':		/* both dest and source */
9382179404Sobrien	    case 'w':		/* both dest and target */
9383179404Sobrien	    case 'E':		/* coprocessor target register */
9384179404Sobrien	    case 'K':		/* 'rdhwr' destination register */
9385179404Sobrien	    case 'x':		/* ignore register name */
9386179404Sobrien	    case 'z':		/* must be zero register */
9387179404Sobrien	    case 'U':           /* destination register (clo/clz).  */
9388208737Sjmallett	    case 'g':		/* coprocessor destination register */
9389218822Sdim	      s_reset = s;
9390218822Sdim	      if (*args == 'E' || *args == 'K')
9391218822Sdim		ok = reg_lookup (&s, RTYPE_NUM, &regno);
9392218822Sdim	      else
9393179404Sobrien		{
9394218822Sdim		  ok = reg_lookup (&s, RTYPE_NUM | RTYPE_GP, &regno);
9395218822Sdim		  if (regno == AT && ! mips_opts.noat)
9396218822Sdim		    as_warn ("Used $at without \".set noat\"");
9397218822Sdim		}
9398218822Sdim	      if (ok)
9399218822Sdim		{
9400179404Sobrien		  c = *args;
9401179404Sobrien		  if (*s == ' ')
9402179404Sobrien		    ++s;
9403179404Sobrien		  if (args[1] != *s)
9404179404Sobrien		    {
9405179404Sobrien		      if (c == 'r' || c == 'v' || c == 'w')
9406179404Sobrien			{
9407179404Sobrien			  regno = lastregno;
9408179404Sobrien			  s = s_reset;
9409179404Sobrien			  ++args;
9410179404Sobrien			}
9411179404Sobrien		    }
9412179404Sobrien		  /* 'z' only matches $0.  */
9413179404Sobrien		  if (c == 'z' && regno != 0)
9414179404Sobrien		    break;
9415179404Sobrien
9416179404Sobrien	/* Now that we have assembled one operand, we use the args string
9417179404Sobrien	 * to figure out where it goes in the instruction.  */
9418179404Sobrien		  switch (c)
9419179404Sobrien		    {
9420179404Sobrien		    case 'r':
9421179404Sobrien		    case 's':
9422179404Sobrien		    case 'v':
9423179404Sobrien		    case 'b':
9424208737Sjmallett		      INSERT_OPERAND (RS, *ip, regno);
9425179404Sobrien		      break;
9426179404Sobrien		    case 'd':
9427179404Sobrien		    case 'G':
9428179404Sobrien		    case 'K':
9429208737Sjmallett		    case 'g':
9430208737Sjmallett		      INSERT_OPERAND (RD, *ip, regno);
9431179404Sobrien		      break;
9432179404Sobrien		    case 'U':
9433208737Sjmallett		      INSERT_OPERAND (RD, *ip, regno);
9434208737Sjmallett		      INSERT_OPERAND (RT, *ip, regno);
9435179404Sobrien		      break;
9436179404Sobrien		    case 'w':
9437179404Sobrien		    case 't':
9438179404Sobrien		    case 'E':
9439208737Sjmallett		      INSERT_OPERAND (RT, *ip, regno);
9440179404Sobrien		      break;
9441179404Sobrien		    case 'x':
9442179404Sobrien		      /* This case exists because on the r3000 trunc
9443179404Sobrien			 expands into a macro which requires a gp
9444179404Sobrien			 register.  On the r6000 or r4000 it is
9445179404Sobrien			 assembled into a single instruction which
9446179404Sobrien			 ignores the register.  Thus the insn version
9447179404Sobrien			 is MIPS_ISA2 and uses 'x', and the macro
9448179404Sobrien			 version is MIPS_ISA1 and uses 't'.  */
9449179404Sobrien		      break;
9450179404Sobrien		    case 'z':
9451179404Sobrien		      /* This case is for the div instruction, which
9452179404Sobrien			 acts differently if the destination argument
9453179404Sobrien			 is $0.  This only matches $0, and is checked
9454179404Sobrien			 outside the switch.  */
9455179404Sobrien		      break;
9456179404Sobrien		    case 'D':
9457179404Sobrien		      /* Itbl operand; not yet implemented. FIXME ?? */
9458179404Sobrien		      break;
9459179404Sobrien		      /* What about all other operands like 'i', which
9460179404Sobrien			 can be specified in the opcode table? */
9461179404Sobrien		    }
9462179404Sobrien		  lastregno = regno;
9463179404Sobrien		  continue;
9464179404Sobrien		}
9465179404Sobrien	      switch (*args++)
9466179404Sobrien		{
9467179404Sobrien		case 'r':
9468179404Sobrien		case 'v':
9469208737Sjmallett		  INSERT_OPERAND (RS, *ip, lastregno);
9470179404Sobrien		  continue;
9471179404Sobrien		case 'w':
9472208737Sjmallett		  INSERT_OPERAND (RT, *ip, lastregno);
9473179404Sobrien		  continue;
9474179404Sobrien		}
9475179404Sobrien	      break;
9476179404Sobrien
9477179404Sobrien	    case 'O':		/* MDMX alignment immediate constant.  */
9478179404Sobrien	      my_getExpression (&imm_expr, s);
9479179404Sobrien	      check_absolute_expr (ip, &imm_expr);
9480179404Sobrien	      if ((unsigned long) imm_expr.X_add_number > OP_MASK_ALN)
9481208737Sjmallett		as_warn ("Improper align amount (%ld), using low bits",
9482208737Sjmallett			 (long) imm_expr.X_add_number);
9483208737Sjmallett	      INSERT_OPERAND (ALN, *ip, imm_expr.X_add_number);
9484179404Sobrien	      imm_expr.X_op = O_absent;
9485179404Sobrien	      s = expr_end;
9486179404Sobrien	      continue;
9487179404Sobrien
9488179404Sobrien	    case 'Q':		/* MDMX vector, element sel, or const.  */
9489179404Sobrien	      if (s[0] != '$')
9490179404Sobrien		{
9491179404Sobrien		  /* MDMX Immediate.  */
9492179404Sobrien		  my_getExpression (&imm_expr, s);
9493179404Sobrien		  check_absolute_expr (ip, &imm_expr);
9494179404Sobrien		  if ((unsigned long) imm_expr.X_add_number > OP_MASK_FT)
9495208737Sjmallett		    as_warn (_("Invalid MDMX Immediate (%ld)"),
9496208737Sjmallett			     (long) imm_expr.X_add_number);
9497208737Sjmallett		  INSERT_OPERAND (FT, *ip, imm_expr.X_add_number);
9498179404Sobrien		  if (ip->insn_opcode & (OP_MASK_VSEL << OP_SH_VSEL))
9499179404Sobrien		    ip->insn_opcode |= MDMX_FMTSEL_IMM_QH << OP_SH_VSEL;
9500179404Sobrien		  else
9501179404Sobrien		    ip->insn_opcode |= MDMX_FMTSEL_IMM_OB << OP_SH_VSEL;
9502179404Sobrien		  imm_expr.X_op = O_absent;
9503179404Sobrien		  s = expr_end;
9504179404Sobrien		  continue;
9505179404Sobrien		}
9506179404Sobrien	      /* Not MDMX Immediate.  Fall through.  */
9507179404Sobrien	    case 'X':           /* MDMX destination register.  */
9508179404Sobrien	    case 'Y':           /* MDMX source register.  */
9509179404Sobrien	    case 'Z':           /* MDMX target register.  */
9510179404Sobrien	      is_mdmx = 1;
9511179404Sobrien	    case 'D':		/* floating point destination register */
9512179404Sobrien	    case 'S':		/* floating point source register */
9513179404Sobrien	    case 'T':		/* floating point target register */
9514179404Sobrien	    case 'R':		/* floating point source register */
9515179404Sobrien	    case 'V':
9516179404Sobrien	    case 'W':
9517218822Sdim	      rtype = RTYPE_FPU;
9518218822Sdim	      if (is_mdmx
9519218822Sdim		  || (mips_opts.ase_mdmx
9520218822Sdim		      && (ip->insn_mo->pinfo & FP_D)
9521218822Sdim		      && (ip->insn_mo->pinfo & (INSN_COPROC_MOVE_DELAY
9522218822Sdim						| INSN_COPROC_MEMORY_DELAY
9523218822Sdim						| INSN_LOAD_COPROC_DELAY
9524218822Sdim						| INSN_LOAD_MEMORY_DELAY
9525218822Sdim						| INSN_STORE_MEMORY))))
9526218822Sdim		rtype |= RTYPE_VEC;
9527179404Sobrien	      s_reset = s;
9528218822Sdim	      if (mips_opts.arch == CPU_OCTEON && octeon_error_on_unsupported)
9529179404Sobrien		{
9530218822Sdim		  insn_error = "opcode not implemented in Octeon";
9531218822Sdim		  return;
9532218822Sdim		}
9533218822Sdim	      if (reg_lookup (&s, rtype, &regno))
9534218822Sdim		{
9535179404Sobrien		  if ((regno & 1) != 0
9536179404Sobrien		      && HAVE_32BIT_FPRS
9537218822Sdim		      && ! mips_oddfpreg_ok (ip->insn_mo, argnum))
9538179404Sobrien		    as_warn (_("Float register should be even, was %d"),
9539179404Sobrien			     regno);
9540179404Sobrien
9541179404Sobrien		  c = *args;
9542179404Sobrien		  if (*s == ' ')
9543179404Sobrien		    ++s;
9544179404Sobrien		  if (args[1] != *s)
9545179404Sobrien		    {
9546179404Sobrien		      if (c == 'V' || c == 'W')
9547179404Sobrien			{
9548179404Sobrien			  regno = lastregno;
9549179404Sobrien			  s = s_reset;
9550179404Sobrien			  ++args;
9551179404Sobrien			}
9552179404Sobrien		    }
9553179404Sobrien		  switch (c)
9554179404Sobrien		    {
9555179404Sobrien		    case 'D':
9556179404Sobrien		    case 'X':
9557208737Sjmallett		      INSERT_OPERAND (FD, *ip, regno);
9558179404Sobrien		      break;
9559179404Sobrien		    case 'V':
9560179404Sobrien		    case 'S':
9561179404Sobrien		    case 'Y':
9562208737Sjmallett		      INSERT_OPERAND (FS, *ip, regno);
9563179404Sobrien		      break;
9564179404Sobrien		    case 'Q':
9565179404Sobrien		      /* This is like 'Z', but also needs to fix the MDMX
9566179404Sobrien			 vector/scalar select bits.  Note that the
9567179404Sobrien			 scalar immediate case is handled above.  */
9568179404Sobrien		      if (*s == '[')
9569179404Sobrien			{
9570179404Sobrien			  int is_qh = (ip->insn_opcode & (1 << OP_SH_VSEL));
9571179404Sobrien			  int max_el = (is_qh ? 3 : 7);
9572179404Sobrien			  s++;
9573179404Sobrien			  my_getExpression(&imm_expr, s);
9574179404Sobrien			  check_absolute_expr (ip, &imm_expr);
9575179404Sobrien			  s = expr_end;
9576179404Sobrien			  if (imm_expr.X_add_number > max_el)
9577179404Sobrien			    as_bad(_("Bad element selector %ld"),
9578179404Sobrien				   (long) imm_expr.X_add_number);
9579179404Sobrien			  imm_expr.X_add_number &= max_el;
9580179404Sobrien			  ip->insn_opcode |= (imm_expr.X_add_number
9581179404Sobrien					      << (OP_SH_VSEL +
9582179404Sobrien						  (is_qh ? 2 : 1)));
9583208737Sjmallett			  imm_expr.X_op = O_absent;
9584179404Sobrien			  if (*s != ']')
9585179404Sobrien			    as_warn(_("Expecting ']' found '%s'"), s);
9586179404Sobrien			  else
9587179404Sobrien			    s++;
9588179404Sobrien			}
9589179404Sobrien		      else
9590179404Sobrien                        {
9591179404Sobrien                          if (ip->insn_opcode & (OP_MASK_VSEL << OP_SH_VSEL))
9592179404Sobrien                            ip->insn_opcode |= (MDMX_FMTSEL_VEC_QH
9593179404Sobrien						<< OP_SH_VSEL);
9594179404Sobrien			  else
9595179404Sobrien			    ip->insn_opcode |= (MDMX_FMTSEL_VEC_OB <<
9596179404Sobrien						OP_SH_VSEL);
9597179404Sobrien			}
9598179404Sobrien                      /* Fall through */
9599179404Sobrien		    case 'W':
9600179404Sobrien		    case 'T':
9601179404Sobrien		    case 'Z':
9602208737Sjmallett		      INSERT_OPERAND (FT, *ip, regno);
9603179404Sobrien		      break;
9604179404Sobrien		    case 'R':
9605208737Sjmallett		      INSERT_OPERAND (FR, *ip, regno);
9606179404Sobrien		      break;
9607179404Sobrien		    }
9608179404Sobrien		  lastregno = regno;
9609179404Sobrien		  continue;
9610179404Sobrien		}
9611179404Sobrien
9612179404Sobrien	      switch (*args++)
9613179404Sobrien		{
9614179404Sobrien		case 'V':
9615208737Sjmallett		  INSERT_OPERAND (FS, *ip, lastregno);
9616179404Sobrien		  continue;
9617179404Sobrien		case 'W':
9618208737Sjmallett		  INSERT_OPERAND (FT, *ip, lastregno);
9619179404Sobrien		  continue;
9620179404Sobrien		}
9621179404Sobrien	      break;
9622179404Sobrien
9623179404Sobrien	    case 'I':
9624179404Sobrien	      my_getExpression (&imm_expr, s);
9625179404Sobrien	      if (imm_expr.X_op != O_big
9626179404Sobrien		  && imm_expr.X_op != O_constant)
9627179404Sobrien		insn_error = _("absolute expression required");
9628208737Sjmallett	      if (HAVE_32BIT_GPRS)
9629208737Sjmallett		normalize_constant_expr (&imm_expr);
9630179404Sobrien	      s = expr_end;
9631179404Sobrien	      continue;
9632179404Sobrien
9633179404Sobrien	    case 'A':
9634179404Sobrien	      my_getExpression (&offset_expr, s);
9635208737Sjmallett	      normalize_address_expr (&offset_expr);
9636179404Sobrien	      *imm_reloc = BFD_RELOC_32;
9637179404Sobrien	      s = expr_end;
9638179404Sobrien	      continue;
9639179404Sobrien
9640179404Sobrien	    case 'F':
9641179404Sobrien	    case 'L':
9642179404Sobrien	    case 'f':
9643179404Sobrien	    case 'l':
9644179404Sobrien	      {
9645179404Sobrien		int f64;
9646179404Sobrien		int using_gprs;
9647179404Sobrien		char *save_in;
9648179404Sobrien		char *err;
9649179404Sobrien		unsigned char temp[8];
9650179404Sobrien		int len;
9651179404Sobrien		unsigned int length;
9652179404Sobrien		segT seg;
9653179404Sobrien		subsegT subseg;
9654179404Sobrien		char *p;
9655179404Sobrien
9656179404Sobrien		/* These only appear as the last operand in an
9657179404Sobrien		   instruction, and every instruction that accepts
9658179404Sobrien		   them in any variant accepts them in all variants.
9659179404Sobrien		   This means we don't have to worry about backing out
9660179404Sobrien		   any changes if the instruction does not match.
9661179404Sobrien
9662179404Sobrien		   The difference between them is the size of the
9663179404Sobrien		   floating point constant and where it goes.  For 'F'
9664179404Sobrien		   and 'L' the constant is 64 bits; for 'f' and 'l' it
9665179404Sobrien		   is 32 bits.  Where the constant is placed is based
9666179404Sobrien		   on how the MIPS assembler does things:
9667179404Sobrien		    F -- .rdata
9668179404Sobrien		    L -- .lit8
9669179404Sobrien		    f -- immediate value
9670179404Sobrien		    l -- .lit4
9671179404Sobrien
9672179404Sobrien		    The .lit4 and .lit8 sections are only used if
9673179404Sobrien		    permitted by the -G argument.
9674179404Sobrien
9675179404Sobrien		    The code below needs to know whether the target register
9676179404Sobrien		    is 32 or 64 bits wide.  It relies on the fact 'f' and
9677179404Sobrien		    'F' are used with GPR-based instructions and 'l' and
9678179404Sobrien		    'L' are used with FPR-based instructions.  */
9679179404Sobrien
9680179404Sobrien		f64 = *args == 'F' || *args == 'L';
9681179404Sobrien		using_gprs = *args == 'F' || *args == 'f';
9682179404Sobrien
9683179404Sobrien		save_in = input_line_pointer;
9684179404Sobrien		input_line_pointer = s;
9685179404Sobrien		err = md_atof (f64 ? 'd' : 'f', (char *) temp, &len);
9686179404Sobrien		length = len;
9687179404Sobrien		s = input_line_pointer;
9688179404Sobrien		input_line_pointer = save_in;
9689179404Sobrien		if (err != NULL && *err != '\0')
9690179404Sobrien		  {
9691179404Sobrien		    as_bad (_("Bad floating point constant: %s"), err);
9692179404Sobrien		    memset (temp, '\0', sizeof temp);
9693179404Sobrien		    length = f64 ? 8 : 4;
9694179404Sobrien		  }
9695179404Sobrien
9696179404Sobrien		assert (length == (unsigned) (f64 ? 8 : 4));
9697179404Sobrien
9698179404Sobrien		if (*args == 'f'
9699179404Sobrien		    || (*args == 'l'
9700208737Sjmallett			&& (g_switch_value < 4
9701179404Sobrien			    || (temp[0] == 0 && temp[1] == 0)
9702179404Sobrien			    || (temp[2] == 0 && temp[3] == 0))))
9703179404Sobrien		  {
9704179404Sobrien		    imm_expr.X_op = O_constant;
9705179404Sobrien		    if (! target_big_endian)
9706179404Sobrien		      imm_expr.X_add_number = bfd_getl32 (temp);
9707179404Sobrien		    else
9708179404Sobrien		      imm_expr.X_add_number = bfd_getb32 (temp);
9709179404Sobrien		  }
9710179404Sobrien		else if (length > 4
9711179404Sobrien			 && ! mips_disable_float_construction
9712179404Sobrien			 /* Constants can only be constructed in GPRs and
9713179404Sobrien			    copied to FPRs if the GPRs are at least as wide
9714179404Sobrien			    as the FPRs.  Force the constant into memory if
9715179404Sobrien			    we are using 64-bit FPRs but the GPRs are only
9716179404Sobrien			    32 bits wide.  */
9717179404Sobrien			 && (using_gprs
9718179404Sobrien			     || ! (HAVE_64BIT_FPRS && HAVE_32BIT_GPRS))
9719179404Sobrien			 && ((temp[0] == 0 && temp[1] == 0)
9720179404Sobrien			     || (temp[2] == 0 && temp[3] == 0))
9721179404Sobrien			 && ((temp[4] == 0 && temp[5] == 0)
9722179404Sobrien			     || (temp[6] == 0 && temp[7] == 0)))
9723179404Sobrien		  {
9724179404Sobrien		    /* The value is simple enough to load with a couple of
9725179404Sobrien                       instructions.  If using 32-bit registers, set
9726179404Sobrien                       imm_expr to the high order 32 bits and offset_expr to
9727179404Sobrien                       the low order 32 bits.  Otherwise, set imm_expr to
9728179404Sobrien                       the entire 64 bit constant.  */
9729179404Sobrien		    if (using_gprs ? HAVE_32BIT_GPRS : HAVE_32BIT_FPRS)
9730179404Sobrien		      {
9731179404Sobrien			imm_expr.X_op = O_constant;
9732179404Sobrien			offset_expr.X_op = O_constant;
9733179404Sobrien			if (! target_big_endian)
9734179404Sobrien			  {
9735179404Sobrien			    imm_expr.X_add_number = bfd_getl32 (temp + 4);
9736179404Sobrien			    offset_expr.X_add_number = bfd_getl32 (temp);
9737179404Sobrien			  }
9738179404Sobrien			else
9739179404Sobrien			  {
9740179404Sobrien			    imm_expr.X_add_number = bfd_getb32 (temp);
9741179404Sobrien			    offset_expr.X_add_number = bfd_getb32 (temp + 4);
9742179404Sobrien			  }
9743179404Sobrien			if (offset_expr.X_add_number == 0)
9744179404Sobrien			  offset_expr.X_op = O_absent;
9745179404Sobrien		      }
9746179404Sobrien		    else if (sizeof (imm_expr.X_add_number) > 4)
9747179404Sobrien		      {
9748179404Sobrien			imm_expr.X_op = O_constant;
9749179404Sobrien			if (! target_big_endian)
9750179404Sobrien			  imm_expr.X_add_number = bfd_getl64 (temp);
9751179404Sobrien			else
9752179404Sobrien			  imm_expr.X_add_number = bfd_getb64 (temp);
9753179404Sobrien		      }
9754179404Sobrien		    else
9755179404Sobrien		      {
9756179404Sobrien			imm_expr.X_op = O_big;
9757179404Sobrien			imm_expr.X_add_number = 4;
9758179404Sobrien			if (! target_big_endian)
9759179404Sobrien			  {
9760179404Sobrien			    generic_bignum[0] = bfd_getl16 (temp);
9761179404Sobrien			    generic_bignum[1] = bfd_getl16 (temp + 2);
9762179404Sobrien			    generic_bignum[2] = bfd_getl16 (temp + 4);
9763179404Sobrien			    generic_bignum[3] = bfd_getl16 (temp + 6);
9764179404Sobrien			  }
9765179404Sobrien			else
9766179404Sobrien			  {
9767179404Sobrien			    generic_bignum[0] = bfd_getb16 (temp + 6);
9768179404Sobrien			    generic_bignum[1] = bfd_getb16 (temp + 4);
9769179404Sobrien			    generic_bignum[2] = bfd_getb16 (temp + 2);
9770179404Sobrien			    generic_bignum[3] = bfd_getb16 (temp);
9771179404Sobrien			  }
9772179404Sobrien		      }
9773179404Sobrien		  }
9774179404Sobrien		else
9775179404Sobrien		  {
9776179404Sobrien		    const char *newname;
9777179404Sobrien		    segT new_seg;
9778179404Sobrien
9779179404Sobrien		    /* Switch to the right section.  */
9780179404Sobrien		    seg = now_seg;
9781179404Sobrien		    subseg = now_subseg;
9782179404Sobrien		    switch (*args)
9783179404Sobrien		      {
9784179404Sobrien		      default: /* unused default case avoids warnings.  */
9785179404Sobrien		      case 'L':
9786179404Sobrien			newname = RDATA_SECTION_NAME;
9787208737Sjmallett			if (g_switch_value >= 8)
9788179404Sobrien			  newname = ".lit8";
9789179404Sobrien			break;
9790179404Sobrien		      case 'F':
9791208737Sjmallett			newname = RDATA_SECTION_NAME;
9792179404Sobrien			break;
9793179404Sobrien		      case 'l':
9794208737Sjmallett			assert (g_switch_value >= 4);
9795179404Sobrien			newname = ".lit4";
9796179404Sobrien			break;
9797179404Sobrien		      }
9798179404Sobrien		    new_seg = subseg_new (newname, (subsegT) 0);
9799218822Sdim		    if (IS_ELF)
9800179404Sobrien		      bfd_set_section_flags (stdoutput, new_seg,
9801179404Sobrien					     (SEC_ALLOC
9802179404Sobrien					      | SEC_LOAD
9803179404Sobrien					      | SEC_READONLY
9804179404Sobrien					      | SEC_DATA));
9805179404Sobrien		    frag_align (*args == 'l' ? 2 : 3, 0, 0);
9806218822Sdim		    if (IS_ELF && strcmp (TARGET_OS, "elf") != 0)
9807179404Sobrien		      record_alignment (new_seg, 4);
9808179404Sobrien		    else
9809179404Sobrien		      record_alignment (new_seg, *args == 'l' ? 2 : 3);
9810179404Sobrien		    if (seg == now_seg)
9811179404Sobrien		      as_bad (_("Can't use floating point insn in this section"));
9812179404Sobrien
9813179404Sobrien		    /* Set the argument to the current address in the
9814179404Sobrien		       section.  */
9815179404Sobrien		    offset_expr.X_op = O_symbol;
9816179404Sobrien		    offset_expr.X_add_symbol =
9817179404Sobrien		      symbol_new ("L0\001", now_seg,
9818179404Sobrien				  (valueT) frag_now_fix (), frag_now);
9819179404Sobrien		    offset_expr.X_add_number = 0;
9820179404Sobrien
9821179404Sobrien		    /* Put the floating point number into the section.  */
9822179404Sobrien		    p = frag_more ((int) length);
9823179404Sobrien		    memcpy (p, temp, length);
9824179404Sobrien
9825179404Sobrien		    /* Switch back to the original section.  */
9826179404Sobrien		    subseg_set (seg, subseg);
9827179404Sobrien		  }
9828179404Sobrien	      }
9829179404Sobrien	      continue;
9830179404Sobrien
9831179404Sobrien	    case 'i':		/* 16 bit unsigned immediate */
9832179404Sobrien	    case 'j':		/* 16 bit signed immediate */
9833179404Sobrien	      *imm_reloc = BFD_RELOC_LO16;
9834179404Sobrien	      if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0)
9835179404Sobrien		{
9836179404Sobrien		  int more;
9837179404Sobrien		  offsetT minval, maxval;
9838179404Sobrien
9839179404Sobrien		  more = (insn + 1 < &mips_opcodes[NUMOPCODES]
9840179404Sobrien			  && strcmp (insn->name, insn[1].name) == 0);
9841179404Sobrien
9842179404Sobrien		  /* If the expression was written as an unsigned number,
9843179404Sobrien		     only treat it as signed if there are no more
9844179404Sobrien		     alternatives.  */
9845179404Sobrien		  if (more
9846179404Sobrien		      && *args == 'j'
9847179404Sobrien		      && sizeof (imm_expr.X_add_number) <= 4
9848179404Sobrien		      && imm_expr.X_op == O_constant
9849179404Sobrien		      && imm_expr.X_add_number < 0
9850179404Sobrien		      && imm_expr.X_unsigned
9851179404Sobrien		      && HAVE_64BIT_GPRS)
9852179404Sobrien		    break;
9853179404Sobrien
9854179404Sobrien		  /* For compatibility with older assemblers, we accept
9855179404Sobrien		     0x8000-0xffff as signed 16-bit numbers when only
9856179404Sobrien		     signed numbers are allowed.  */
9857179404Sobrien		  if (*args == 'i')
9858179404Sobrien		    minval = 0, maxval = 0xffff;
9859179404Sobrien		  else if (more)
9860179404Sobrien		    minval = -0x8000, maxval = 0x7fff;
9861179404Sobrien		  else
9862179404Sobrien		    minval = -0x8000, maxval = 0xffff;
9863179404Sobrien
9864179404Sobrien		  if (imm_expr.X_op != O_constant
9865179404Sobrien		      || imm_expr.X_add_number < minval
9866179404Sobrien		      || imm_expr.X_add_number > maxval)
9867179404Sobrien		    {
9868179404Sobrien		      if (more)
9869179404Sobrien			break;
9870179404Sobrien		      if (imm_expr.X_op == O_constant
9871179404Sobrien			  || imm_expr.X_op == O_big)
9872179404Sobrien			as_bad (_("expression out of range"));
9873179404Sobrien		    }
9874179404Sobrien		}
9875179404Sobrien	      s = expr_end;
9876179404Sobrien	      continue;
9877179404Sobrien
9878179404Sobrien	    case 'o':		/* 16 bit offset */
9879179404Sobrien	      /* Check whether there is only a single bracketed expression
9880179404Sobrien		 left.  If so, it must be the base register and the
9881179404Sobrien		 constant must be zero.  */
9882179404Sobrien	      if (*s == '(' && strchr (s + 1, '(') == 0)
9883179404Sobrien		{
9884179404Sobrien		  offset_expr.X_op = O_constant;
9885179404Sobrien		  offset_expr.X_add_number = 0;
9886179404Sobrien		  continue;
9887179404Sobrien		}
9888179404Sobrien
9889179404Sobrien	      /* If this value won't fit into a 16 bit offset, then go
9890179404Sobrien		 find a macro that will generate the 32 bit offset
9891179404Sobrien		 code pattern.  */
9892179404Sobrien	      if (my_getSmallExpression (&offset_expr, offset_reloc, s) == 0
9893179404Sobrien		  && (offset_expr.X_op != O_constant
9894179404Sobrien		      || offset_expr.X_add_number >= 0x8000
9895179404Sobrien		      || offset_expr.X_add_number < -0x8000))
9896179404Sobrien		break;
9897179404Sobrien
9898179404Sobrien	      s = expr_end;
9899179404Sobrien	      continue;
9900179404Sobrien
9901179404Sobrien	    case 'p':		/* pc relative offset */
9902179404Sobrien	      *offset_reloc = BFD_RELOC_16_PCREL_S2;
9903179404Sobrien	      my_getExpression (&offset_expr, s);
9904179404Sobrien	      s = expr_end;
9905179404Sobrien	      continue;
9906179404Sobrien
9907179404Sobrien	    case 'u':		/* upper 16 bits */
9908179404Sobrien	      if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0
9909179404Sobrien		  && imm_expr.X_op == O_constant
9910179404Sobrien		  && (imm_expr.X_add_number < 0
9911179404Sobrien		      || imm_expr.X_add_number >= 0x10000))
9912179404Sobrien		as_bad (_("lui expression not in range 0..65535"));
9913179404Sobrien	      s = expr_end;
9914179404Sobrien	      continue;
9915179404Sobrien
9916179404Sobrien	    case 'a':		/* 26 bit address */
9917179404Sobrien	      my_getExpression (&offset_expr, s);
9918179404Sobrien	      s = expr_end;
9919179404Sobrien	      *offset_reloc = BFD_RELOC_MIPS_JMP;
9920179404Sobrien	      continue;
9921179404Sobrien
9922179404Sobrien	    case 'N':		/* 3 bit branch condition code */
9923179404Sobrien	    case 'M':		/* 3 bit compare condition code */
9924218822Sdim	      rtype = RTYPE_CCC;
9925218822Sdim	      if (ip->insn_mo->pinfo & (FP_D| FP_S))
9926218822Sdim		rtype |= RTYPE_FCC;
9927218822Sdim	      if (!reg_lookup (&s, rtype, &regno))
9928179404Sobrien		break;
9929179404Sobrien	      if ((strcmp(str + strlen(str) - 3, ".ps") == 0
9930179404Sobrien		   || strcmp(str + strlen(str) - 5, "any2f") == 0
9931179404Sobrien		   || strcmp(str + strlen(str) - 5, "any2t") == 0)
9932179404Sobrien		  && (regno & 1) != 0)
9933179404Sobrien		as_warn(_("Condition code register should be even for %s, was %d"),
9934179404Sobrien			str, regno);
9935179404Sobrien	      if ((strcmp(str + strlen(str) - 5, "any4f") == 0
9936179404Sobrien		   || strcmp(str + strlen(str) - 5, "any4t") == 0)
9937179404Sobrien		  && (regno & 3) != 0)
9938179404Sobrien		as_warn(_("Condition code register should be 0 or 4 for %s, was %d"),
9939179404Sobrien			str, regno);
9940179404Sobrien	      if (*args == 'N')
9941208737Sjmallett		INSERT_OPERAND (BCC, *ip, regno);
9942179404Sobrien	      else
9943208737Sjmallett		INSERT_OPERAND (CCC, *ip, regno);
9944179404Sobrien	      continue;
9945179404Sobrien
9946179404Sobrien	    case 'H':
9947179404Sobrien	      if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
9948179404Sobrien		s += 2;
9949179404Sobrien	      if (ISDIGIT (*s))
9950179404Sobrien		{
9951179404Sobrien		  c = 0;
9952179404Sobrien		  do
9953179404Sobrien		    {
9954179404Sobrien		      c *= 10;
9955179404Sobrien		      c += *s - '0';
9956179404Sobrien		      ++s;
9957179404Sobrien		    }
9958179404Sobrien		  while (ISDIGIT (*s));
9959179404Sobrien		}
9960179404Sobrien	      else
9961179404Sobrien		c = 8; /* Invalid sel value.  */
9962179404Sobrien
9963179404Sobrien	      if (c > 7)
9964179404Sobrien		as_bad (_("invalid coprocessor sub-selection value (0-7)"));
9965179404Sobrien	      ip->insn_opcode |= c;
9966179404Sobrien	      continue;
9967179404Sobrien
9968179404Sobrien	    case 'e':
9969179404Sobrien	      /* Must be at least one digit.  */
9970179404Sobrien	      my_getExpression (&imm_expr, s);
9971179404Sobrien	      check_absolute_expr (ip, &imm_expr);
9972179404Sobrien
9973179404Sobrien	      if ((unsigned long) imm_expr.X_add_number
9974179404Sobrien		  > (unsigned long) OP_MASK_VECBYTE)
9975179404Sobrien		{
9976179404Sobrien		  as_bad (_("bad byte vector index (%ld)"),
9977179404Sobrien			   (long) imm_expr.X_add_number);
9978179404Sobrien		  imm_expr.X_add_number = 0;
9979179404Sobrien		}
9980179404Sobrien
9981208737Sjmallett	      INSERT_OPERAND (VECBYTE, *ip, imm_expr.X_add_number);
9982179404Sobrien	      imm_expr.X_op = O_absent;
9983179404Sobrien	      s = expr_end;
9984179404Sobrien	      continue;
9985179404Sobrien
9986179404Sobrien	    case '%':
9987179404Sobrien	      my_getExpression (&imm_expr, s);
9988179404Sobrien	      check_absolute_expr (ip, &imm_expr);
9989179404Sobrien
9990179404Sobrien	      if ((unsigned long) imm_expr.X_add_number
9991179404Sobrien		  > (unsigned long) OP_MASK_VECALIGN)
9992179404Sobrien		{
9993179404Sobrien		  as_bad (_("bad byte vector index (%ld)"),
9994179404Sobrien			   (long) imm_expr.X_add_number);
9995179404Sobrien		  imm_expr.X_add_number = 0;
9996179404Sobrien		}
9997179404Sobrien
9998208737Sjmallett	      INSERT_OPERAND (VECALIGN, *ip, imm_expr.X_add_number);
9999179404Sobrien	      imm_expr.X_op = O_absent;
10000179404Sobrien	      s = expr_end;
10001179404Sobrien	      continue;
10002179404Sobrien
10003179404Sobrien	    default:
10004179404Sobrien	      as_bad (_("bad char = '%c'\n"), *args);
10005179404Sobrien	      internalError ();
10006179404Sobrien	    }
10007179404Sobrien	  break;
10008179404Sobrien	}
10009179404Sobrien      /* Args don't match.  */
10010179404Sobrien      if (insn + 1 < &mips_opcodes[NUMOPCODES] &&
10011179404Sobrien	  !strcmp (insn->name, insn[1].name))
10012179404Sobrien	{
10013179404Sobrien	  ++insn;
10014179404Sobrien	  s = argsStart;
10015179404Sobrien	  insn_error = _("illegal operands");
10016179404Sobrien	  continue;
10017179404Sobrien	}
10018179404Sobrien      if (save_c)
10019179404Sobrien	*(--s) = save_c;
10020179404Sobrien      insn_error = _("illegal operands");
10021179404Sobrien      return;
10022179404Sobrien    }
10023179404Sobrien}
10024179404Sobrien
10025208737Sjmallett#define SKIP_SPACE_TABS(S) { while (*(S) == ' ' || *(S) == '\t') ++(S); }
10026208737Sjmallett
10027179404Sobrien/* This routine assembles an instruction into its binary format when
10028179404Sobrien   assembling for the mips16.  As a side effect, it sets one of the
10029179404Sobrien   global variables imm_reloc or offset_reloc to the type of
10030179404Sobrien   relocation to do if one of the operands is an address expression.
10031179404Sobrien   It also sets mips16_small and mips16_ext if the user explicitly
10032179404Sobrien   requested a small or extended instruction.  */
10033179404Sobrien
10034179404Sobrienstatic void
10035179404Sobrienmips16_ip (char *str, struct mips_cl_insn *ip)
10036179404Sobrien{
10037179404Sobrien  char *s;
10038179404Sobrien  const char *args;
10039179404Sobrien  struct mips_opcode *insn;
10040179404Sobrien  char *argsstart;
10041179404Sobrien  unsigned int regno;
10042179404Sobrien  unsigned int lastregno = 0;
10043179404Sobrien  char *s_reset;
10044208737Sjmallett  size_t i;
10045179404Sobrien
10046179404Sobrien  insn_error = NULL;
10047179404Sobrien
10048179404Sobrien  mips16_small = FALSE;
10049179404Sobrien  mips16_ext = FALSE;
10050179404Sobrien
10051179404Sobrien  for (s = str; ISLOWER (*s); ++s)
10052179404Sobrien    ;
10053179404Sobrien  switch (*s)
10054179404Sobrien    {
10055179404Sobrien    case '\0':
10056179404Sobrien      break;
10057179404Sobrien
10058179404Sobrien    case ' ':
10059179404Sobrien      *s++ = '\0';
10060179404Sobrien      break;
10061179404Sobrien
10062179404Sobrien    case '.':
10063179404Sobrien      if (s[1] == 't' && s[2] == ' ')
10064179404Sobrien	{
10065179404Sobrien	  *s = '\0';
10066179404Sobrien	  mips16_small = TRUE;
10067179404Sobrien	  s += 3;
10068179404Sobrien	  break;
10069179404Sobrien	}
10070179404Sobrien      else if (s[1] == 'e' && s[2] == ' ')
10071179404Sobrien	{
10072179404Sobrien	  *s = '\0';
10073179404Sobrien	  mips16_ext = TRUE;
10074179404Sobrien	  s += 3;
10075179404Sobrien	  break;
10076179404Sobrien	}
10077179404Sobrien      /* Fall through.  */
10078179404Sobrien    default:
10079179404Sobrien      insn_error = _("unknown opcode");
10080179404Sobrien      return;
10081179404Sobrien    }
10082179404Sobrien
10083179404Sobrien  if (mips_opts.noautoextend && ! mips16_ext)
10084179404Sobrien    mips16_small = TRUE;
10085179404Sobrien
10086179404Sobrien  if ((insn = (struct mips_opcode *) hash_find (mips16_op_hash, str)) == NULL)
10087179404Sobrien    {
10088179404Sobrien      insn_error = _("unrecognized opcode");
10089179404Sobrien      return;
10090179404Sobrien    }
10091179404Sobrien
10092179404Sobrien  argsstart = s;
10093179404Sobrien  for (;;)
10094179404Sobrien    {
10095218822Sdim      bfd_boolean ok;
10096218822Sdim
10097179404Sobrien      assert (strcmp (insn->name, str) == 0);
10098179404Sobrien
10099218822Sdim      if (OPCODE_IS_MEMBER (insn, mips_opts.isa, mips_opts.arch))
10100218822Sdim	ok = TRUE;
10101218822Sdim      else
10102218822Sdim	ok = FALSE;
10103218822Sdim
10104218822Sdim      if (! ok)
10105218822Sdim	{
10106218822Sdim	  if (insn + 1 < &mips16_opcodes[bfd_mips16_num_opcodes]
10107218822Sdim	      && strcmp (insn->name, insn[1].name) == 0)
10108218822Sdim	    {
10109218822Sdim	      ++insn;
10110218822Sdim	      continue;
10111218822Sdim	    }
10112218822Sdim	  else
10113218822Sdim	    {
10114218822Sdim	      if (!insn_error)
10115218822Sdim		{
10116218822Sdim		  static char buf[100];
10117218822Sdim		  sprintf (buf,
10118218822Sdim			   _("opcode not supported on this processor: %s (%s)"),
10119218822Sdim			   mips_cpu_info_from_arch (mips_opts.arch)->name,
10120218822Sdim			   mips_cpu_info_from_isa (mips_opts.isa)->name);
10121218822Sdim		  insn_error = buf;
10122218822Sdim		}
10123218822Sdim	      return;
10124218822Sdim	    }
10125218822Sdim	}
10126218822Sdim
10127208737Sjmallett      create_insn (ip, insn);
10128179404Sobrien      imm_expr.X_op = O_absent;
10129179404Sobrien      imm_reloc[0] = BFD_RELOC_UNUSED;
10130179404Sobrien      imm_reloc[1] = BFD_RELOC_UNUSED;
10131179404Sobrien      imm_reloc[2] = BFD_RELOC_UNUSED;
10132179404Sobrien      imm2_expr.X_op = O_absent;
10133179404Sobrien      offset_expr.X_op = O_absent;
10134179404Sobrien      offset_reloc[0] = BFD_RELOC_UNUSED;
10135179404Sobrien      offset_reloc[1] = BFD_RELOC_UNUSED;
10136179404Sobrien      offset_reloc[2] = BFD_RELOC_UNUSED;
10137179404Sobrien      for (args = insn->args; 1; ++args)
10138179404Sobrien	{
10139179404Sobrien	  int c;
10140179404Sobrien
10141179404Sobrien	  if (*s == ' ')
10142179404Sobrien	    ++s;
10143179404Sobrien
10144179404Sobrien	  /* In this switch statement we call break if we did not find
10145179404Sobrien             a match, continue if we did find a match, or return if we
10146179404Sobrien             are done.  */
10147179404Sobrien
10148179404Sobrien	  c = *args;
10149179404Sobrien	  switch (c)
10150179404Sobrien	    {
10151179404Sobrien	    case '\0':
10152179404Sobrien	      if (*s == '\0')
10153179404Sobrien		{
10154179404Sobrien		  /* Stuff the immediate value in now, if we can.  */
10155179404Sobrien		  if (imm_expr.X_op == O_constant
10156179404Sobrien		      && *imm_reloc > BFD_RELOC_UNUSED
10157179404Sobrien		      && insn->pinfo != INSN_MACRO)
10158179404Sobrien		    {
10159218822Sdim		      valueT tmp;
10160218822Sdim
10161218822Sdim		      switch (*offset_reloc)
10162218822Sdim			{
10163218822Sdim			  case BFD_RELOC_MIPS16_HI16_S:
10164218822Sdim			    tmp = (imm_expr.X_add_number + 0x8000) >> 16;
10165218822Sdim			    break;
10166218822Sdim
10167218822Sdim			  case BFD_RELOC_MIPS16_HI16:
10168218822Sdim			    tmp = imm_expr.X_add_number >> 16;
10169218822Sdim			    break;
10170218822Sdim
10171218822Sdim			  case BFD_RELOC_MIPS16_LO16:
10172218822Sdim			    tmp = ((imm_expr.X_add_number + 0x8000) & 0xffff)
10173218822Sdim				  - 0x8000;
10174218822Sdim			    break;
10175218822Sdim
10176218822Sdim			  case BFD_RELOC_UNUSED:
10177218822Sdim			    tmp = imm_expr.X_add_number;
10178218822Sdim			    break;
10179218822Sdim
10180218822Sdim			  default:
10181218822Sdim			    internalError ();
10182218822Sdim			}
10183208737Sjmallett		      *offset_reloc = BFD_RELOC_UNUSED;
10184208737Sjmallett
10185179404Sobrien		      mips16_immed (NULL, 0, *imm_reloc - BFD_RELOC_UNUSED,
10186218822Sdim				    tmp, TRUE, mips16_small,
10187179404Sobrien				    mips16_ext, &ip->insn_opcode,
10188179404Sobrien				    &ip->use_extend, &ip->extend);
10189179404Sobrien		      imm_expr.X_op = O_absent;
10190179404Sobrien		      *imm_reloc = BFD_RELOC_UNUSED;
10191179404Sobrien		    }
10192179404Sobrien
10193179404Sobrien		  return;
10194179404Sobrien		}
10195179404Sobrien	      break;
10196179404Sobrien
10197179404Sobrien	    case ',':
10198179404Sobrien	      if (*s++ == c)
10199179404Sobrien		continue;
10200179404Sobrien	      s--;
10201179404Sobrien	      switch (*++args)
10202179404Sobrien		{
10203179404Sobrien		case 'v':
10204208737Sjmallett		  MIPS16_INSERT_OPERAND (RX, *ip, lastregno);
10205179404Sobrien		  continue;
10206179404Sobrien		case 'w':
10207208737Sjmallett		  MIPS16_INSERT_OPERAND (RY, *ip, lastregno);
10208179404Sobrien		  continue;
10209179404Sobrien		}
10210179404Sobrien	      break;
10211179404Sobrien
10212179404Sobrien	    case '(':
10213179404Sobrien	    case ')':
10214179404Sobrien	      if (*s++ == c)
10215179404Sobrien		continue;
10216179404Sobrien	      break;
10217179404Sobrien
10218179404Sobrien	    case 'v':
10219179404Sobrien	    case 'w':
10220179404Sobrien	      if (s[0] != '$')
10221179404Sobrien		{
10222179404Sobrien		  if (c == 'v')
10223208737Sjmallett		    MIPS16_INSERT_OPERAND (RX, *ip, lastregno);
10224179404Sobrien		  else
10225208737Sjmallett		    MIPS16_INSERT_OPERAND (RY, *ip, lastregno);
10226179404Sobrien		  ++args;
10227179404Sobrien		  continue;
10228179404Sobrien		}
10229179404Sobrien	      /* Fall through.  */
10230179404Sobrien	    case 'x':
10231179404Sobrien	    case 'y':
10232179404Sobrien	    case 'z':
10233179404Sobrien	    case 'Z':
10234179404Sobrien	    case '0':
10235179404Sobrien	    case 'S':
10236179404Sobrien	    case 'R':
10237179404Sobrien	    case 'X':
10238179404Sobrien	    case 'Y':
10239218822Sdim  	      s_reset = s;
10240218822Sdim	      if (!reg_lookup (&s, RTYPE_NUM | RTYPE_GP, &regno))
10241179404Sobrien		{
10242218822Sdim		  if (c == 'v' || c == 'w')
10243179404Sobrien		    {
10244218822Sdim		      if (c == 'v')
10245218822Sdim			MIPS16_INSERT_OPERAND (RX, *ip, lastregno);
10246218822Sdim		      else
10247218822Sdim			MIPS16_INSERT_OPERAND (RY, *ip, lastregno);
10248218822Sdim		      ++args;
10249218822Sdim		      continue;
10250179404Sobrien		    }
10251218822Sdim		  break;
10252179404Sobrien		}
10253179404Sobrien
10254179404Sobrien	      if (*s == ' ')
10255179404Sobrien		++s;
10256179404Sobrien	      if (args[1] != *s)
10257179404Sobrien		{
10258179404Sobrien		  if (c == 'v' || c == 'w')
10259179404Sobrien		    {
10260179404Sobrien		      regno = mips16_to_32_reg_map[lastregno];
10261179404Sobrien		      s = s_reset;
10262179404Sobrien		      ++args;
10263179404Sobrien		    }
10264179404Sobrien		}
10265179404Sobrien
10266179404Sobrien	      switch (c)
10267179404Sobrien		{
10268179404Sobrien		case 'x':
10269179404Sobrien		case 'y':
10270179404Sobrien		case 'z':
10271179404Sobrien		case 'v':
10272179404Sobrien		case 'w':
10273179404Sobrien		case 'Z':
10274179404Sobrien		  regno = mips32_to_16_reg_map[regno];
10275179404Sobrien		  break;
10276179404Sobrien
10277179404Sobrien		case '0':
10278179404Sobrien		  if (regno != 0)
10279179404Sobrien		    regno = ILLEGAL_REG;
10280179404Sobrien		  break;
10281179404Sobrien
10282179404Sobrien		case 'S':
10283179404Sobrien		  if (regno != SP)
10284179404Sobrien		    regno = ILLEGAL_REG;
10285179404Sobrien		  break;
10286179404Sobrien
10287179404Sobrien		case 'R':
10288179404Sobrien		  if (regno != RA)
10289179404Sobrien		    regno = ILLEGAL_REG;
10290179404Sobrien		  break;
10291179404Sobrien
10292179404Sobrien		case 'X':
10293179404Sobrien		case 'Y':
10294179404Sobrien		  if (regno == AT && ! mips_opts.noat)
10295179404Sobrien		    as_warn (_("used $at without \".set noat\""));
10296179404Sobrien		  break;
10297179404Sobrien
10298179404Sobrien		default:
10299179404Sobrien		  internalError ();
10300179404Sobrien		}
10301179404Sobrien
10302179404Sobrien	      if (regno == ILLEGAL_REG)
10303179404Sobrien		break;
10304179404Sobrien
10305179404Sobrien	      switch (c)
10306179404Sobrien		{
10307179404Sobrien		case 'x':
10308179404Sobrien		case 'v':
10309208737Sjmallett		  MIPS16_INSERT_OPERAND (RX, *ip, regno);
10310179404Sobrien		  break;
10311179404Sobrien		case 'y':
10312179404Sobrien		case 'w':
10313208737Sjmallett		  MIPS16_INSERT_OPERAND (RY, *ip, regno);
10314179404Sobrien		  break;
10315179404Sobrien		case 'z':
10316208737Sjmallett		  MIPS16_INSERT_OPERAND (RZ, *ip, regno);
10317179404Sobrien		  break;
10318179404Sobrien		case 'Z':
10319208737Sjmallett		  MIPS16_INSERT_OPERAND (MOVE32Z, *ip, regno);
10320179404Sobrien		case '0':
10321179404Sobrien		case 'S':
10322179404Sobrien		case 'R':
10323179404Sobrien		  break;
10324179404Sobrien		case 'X':
10325208737Sjmallett		  MIPS16_INSERT_OPERAND (REGR32, *ip, regno);
10326179404Sobrien		  break;
10327179404Sobrien		case 'Y':
10328179404Sobrien		  regno = ((regno & 7) << 2) | ((regno & 0x18) >> 3);
10329208737Sjmallett		  MIPS16_INSERT_OPERAND (REG32R, *ip, regno);
10330179404Sobrien		  break;
10331179404Sobrien		default:
10332179404Sobrien		  internalError ();
10333179404Sobrien		}
10334179404Sobrien
10335179404Sobrien	      lastregno = regno;
10336179404Sobrien	      continue;
10337179404Sobrien
10338179404Sobrien	    case 'P':
10339179404Sobrien	      if (strncmp (s, "$pc", 3) == 0)
10340179404Sobrien		{
10341179404Sobrien		  s += 3;
10342179404Sobrien		  continue;
10343179404Sobrien		}
10344179404Sobrien	      break;
10345179404Sobrien
10346179404Sobrien	    case '5':
10347179404Sobrien	    case 'H':
10348179404Sobrien	    case 'W':
10349179404Sobrien	    case 'D':
10350179404Sobrien	    case 'j':
10351179404Sobrien	    case 'V':
10352179404Sobrien	    case 'C':
10353179404Sobrien	    case 'U':
10354179404Sobrien	    case 'k':
10355179404Sobrien	    case 'K':
10356208737Sjmallett	      i = my_getSmallExpression (&imm_expr, imm_reloc, s);
10357208737Sjmallett	      if (i > 0)
10358179404Sobrien		{
10359208737Sjmallett		  if (imm_expr.X_op != O_constant)
10360179404Sobrien		    {
10361179404Sobrien		      mips16_ext = TRUE;
10362179404Sobrien		      ip->use_extend = TRUE;
10363179404Sobrien		      ip->extend = 0;
10364179404Sobrien		    }
10365208737Sjmallett		  else
10366208737Sjmallett		    {
10367208737Sjmallett		      /* We need to relax this instruction.  */
10368208737Sjmallett		      *offset_reloc = *imm_reloc;
10369208737Sjmallett		      *imm_reloc = (int) BFD_RELOC_UNUSED + c;
10370208737Sjmallett		    }
10371208737Sjmallett		  s = expr_end;
10372208737Sjmallett		  continue;
10373179404Sobrien		}
10374208737Sjmallett	      *imm_reloc = BFD_RELOC_UNUSED;
10375208737Sjmallett	      /* Fall through.  */
10376208737Sjmallett	    case '<':
10377208737Sjmallett	    case '>':
10378208737Sjmallett	    case '[':
10379208737Sjmallett	    case ']':
10380208737Sjmallett	    case '4':
10381208737Sjmallett	    case '8':
10382208737Sjmallett	      my_getExpression (&imm_expr, s);
10383179404Sobrien	      if (imm_expr.X_op == O_register)
10384179404Sobrien		{
10385179404Sobrien		  /* What we thought was an expression turned out to
10386179404Sobrien                     be a register.  */
10387179404Sobrien
10388179404Sobrien		  if (s[0] == '(' && args[1] == '(')
10389179404Sobrien		    {
10390179404Sobrien		      /* It looks like the expression was omitted
10391179404Sobrien			 before a register indirection, which means
10392179404Sobrien			 that the expression is implicitly zero.  We
10393179404Sobrien			 still set up imm_expr, so that we handle
10394179404Sobrien			 explicit extensions correctly.  */
10395179404Sobrien		      imm_expr.X_op = O_constant;
10396179404Sobrien		      imm_expr.X_add_number = 0;
10397179404Sobrien		      *imm_reloc = (int) BFD_RELOC_UNUSED + c;
10398179404Sobrien		      continue;
10399179404Sobrien		    }
10400179404Sobrien
10401179404Sobrien		  break;
10402179404Sobrien		}
10403179404Sobrien
10404179404Sobrien	      /* We need to relax this instruction.  */
10405179404Sobrien	      *imm_reloc = (int) BFD_RELOC_UNUSED + c;
10406179404Sobrien	      s = expr_end;
10407179404Sobrien	      continue;
10408179404Sobrien
10409179404Sobrien	    case 'p':
10410179404Sobrien	    case 'q':
10411179404Sobrien	    case 'A':
10412179404Sobrien	    case 'B':
10413179404Sobrien	    case 'E':
10414179404Sobrien	      /* We use offset_reloc rather than imm_reloc for the PC
10415179404Sobrien                 relative operands.  This lets macros with both
10416179404Sobrien                 immediate and address operands work correctly.  */
10417179404Sobrien	      my_getExpression (&offset_expr, s);
10418179404Sobrien
10419179404Sobrien	      if (offset_expr.X_op == O_register)
10420179404Sobrien		break;
10421179404Sobrien
10422179404Sobrien	      /* We need to relax this instruction.  */
10423179404Sobrien	      *offset_reloc = (int) BFD_RELOC_UNUSED + c;
10424179404Sobrien	      s = expr_end;
10425179404Sobrien	      continue;
10426179404Sobrien
10427179404Sobrien	    case '6':		/* break code */
10428179404Sobrien	      my_getExpression (&imm_expr, s);
10429179404Sobrien	      check_absolute_expr (ip, &imm_expr);
10430179404Sobrien	      if ((unsigned long) imm_expr.X_add_number > 63)
10431208737Sjmallett		as_warn (_("Invalid value for `%s' (%lu)"),
10432208737Sjmallett			 ip->insn_mo->name,
10433208737Sjmallett			 (unsigned long) imm_expr.X_add_number);
10434208737Sjmallett	      MIPS16_INSERT_OPERAND (IMM6, *ip, imm_expr.X_add_number);
10435179404Sobrien	      imm_expr.X_op = O_absent;
10436179404Sobrien	      s = expr_end;
10437179404Sobrien	      continue;
10438179404Sobrien
10439179404Sobrien	    case 'a':		/* 26 bit address */
10440179404Sobrien	      my_getExpression (&offset_expr, s);
10441179404Sobrien	      s = expr_end;
10442179404Sobrien	      *offset_reloc = BFD_RELOC_MIPS16_JMP;
10443179404Sobrien	      ip->insn_opcode <<= 16;
10444179404Sobrien	      continue;
10445179404Sobrien
10446179404Sobrien	    case 'l':		/* register list for entry macro */
10447179404Sobrien	    case 'L':		/* register list for exit macro */
10448179404Sobrien	      {
10449179404Sobrien		int mask;
10450179404Sobrien
10451179404Sobrien		if (c == 'l')
10452179404Sobrien		  mask = 0;
10453179404Sobrien		else
10454179404Sobrien		  mask = 7 << 3;
10455179404Sobrien		while (*s != '\0')
10456179404Sobrien		  {
10457218822Sdim		    unsigned int freg, reg1, reg2;
10458179404Sobrien
10459179404Sobrien		    while (*s == ' ' || *s == ',')
10460179404Sobrien		      ++s;
10461218822Sdim		    if (reg_lookup (&s, RTYPE_GP | RTYPE_NUM, &reg1))
10462218822Sdim		      freg = 0;
10463218822Sdim		    else if (reg_lookup (&s, RTYPE_FPU, &reg1))
10464218822Sdim		      freg = 1;
10465218822Sdim		    else
10466179404Sobrien		      {
10467179404Sobrien			as_bad (_("can't parse register list"));
10468179404Sobrien			break;
10469179404Sobrien		      }
10470179404Sobrien		    if (*s == ' ')
10471179404Sobrien		      ++s;
10472179404Sobrien		    if (*s != '-')
10473179404Sobrien		      reg2 = reg1;
10474179404Sobrien		    else
10475179404Sobrien		      {
10476179404Sobrien			++s;
10477218822Sdim			if (!reg_lookup (&s, freg ? RTYPE_FPU
10478218822Sdim					 : (RTYPE_GP | RTYPE_NUM), &reg2))
10479179404Sobrien			  {
10480218822Sdim			    as_bad (_("invalid register list"));
10481218822Sdim			    break;
10482179404Sobrien			  }
10483179404Sobrien		      }
10484179404Sobrien		    if (freg && reg1 == 0 && reg2 == 0 && c == 'L')
10485179404Sobrien		      {
10486179404Sobrien			mask &= ~ (7 << 3);
10487179404Sobrien			mask |= 5 << 3;
10488179404Sobrien		      }
10489179404Sobrien		    else if (freg && reg1 == 0 && reg2 == 1 && c == 'L')
10490179404Sobrien		      {
10491179404Sobrien			mask &= ~ (7 << 3);
10492179404Sobrien			mask |= 6 << 3;
10493179404Sobrien		      }
10494179404Sobrien		    else if (reg1 == 4 && reg2 >= 4 && reg2 <= 7 && c != 'L')
10495179404Sobrien		      mask |= (reg2 - 3) << 3;
10496179404Sobrien		    else if (reg1 == 16 && reg2 >= 16 && reg2 <= 17)
10497179404Sobrien		      mask |= (reg2 - 15) << 1;
10498179404Sobrien		    else if (reg1 == RA && reg2 == RA)
10499179404Sobrien		      mask |= 1;
10500179404Sobrien		    else
10501179404Sobrien		      {
10502179404Sobrien			as_bad (_("invalid register list"));
10503179404Sobrien			break;
10504179404Sobrien		      }
10505179404Sobrien		  }
10506179404Sobrien		/* The mask is filled in in the opcode table for the
10507179404Sobrien                   benefit of the disassembler.  We remove it before
10508179404Sobrien                   applying the actual mask.  */
10509179404Sobrien		ip->insn_opcode &= ~ ((7 << 3) << MIPS16OP_SH_IMM6);
10510179404Sobrien		ip->insn_opcode |= mask << MIPS16OP_SH_IMM6;
10511179404Sobrien	      }
10512179404Sobrien	    continue;
10513179404Sobrien
10514208737Sjmallett	    case 'm':		/* Register list for save insn.  */
10515208737Sjmallett	    case 'M':		/* Register list for restore insn.  */
10516208737Sjmallett	      {
10517208737Sjmallett		int opcode = 0;
10518208737Sjmallett		int framesz = 0, seen_framesz = 0;
10519208737Sjmallett		int args = 0, statics = 0, sregs = 0;
10520208737Sjmallett
10521208737Sjmallett		while (*s != '\0')
10522208737Sjmallett		  {
10523208737Sjmallett		    unsigned int reg1, reg2;
10524208737Sjmallett
10525208737Sjmallett		    SKIP_SPACE_TABS (s);
10526208737Sjmallett		    while (*s == ',')
10527208737Sjmallett		      ++s;
10528208737Sjmallett		    SKIP_SPACE_TABS (s);
10529208737Sjmallett
10530208737Sjmallett		    my_getExpression (&imm_expr, s);
10531208737Sjmallett		    if (imm_expr.X_op == O_constant)
10532208737Sjmallett		      {
10533208737Sjmallett			/* Handle the frame size.  */
10534208737Sjmallett			if (seen_framesz)
10535208737Sjmallett			  {
10536208737Sjmallett			    as_bad (_("more than one frame size in list"));
10537208737Sjmallett			    break;
10538208737Sjmallett			  }
10539208737Sjmallett			seen_framesz = 1;
10540208737Sjmallett			framesz = imm_expr.X_add_number;
10541208737Sjmallett			imm_expr.X_op = O_absent;
10542208737Sjmallett			s = expr_end;
10543208737Sjmallett			continue;
10544208737Sjmallett		      }
10545208737Sjmallett
10546218822Sdim		    if (! reg_lookup (&s, RTYPE_GP | RTYPE_NUM, &reg1))
10547208737Sjmallett		      {
10548208737Sjmallett			as_bad (_("can't parse register list"));
10549208737Sjmallett			break;
10550208737Sjmallett		      }
10551208737Sjmallett
10552218822Sdim		    while (*s == ' ')
10553218822Sdim		      ++s;
10554218822Sdim
10555208737Sjmallett		    if (*s != '-')
10556208737Sjmallett		      reg2 = reg1;
10557208737Sjmallett		    else
10558208737Sjmallett		      {
10559208737Sjmallett			++s;
10560218822Sdim			if (! reg_lookup (&s, RTYPE_GP | RTYPE_NUM, &reg2)
10561218822Sdim			    || reg2 < reg1)
10562208737Sjmallett			  {
10563208737Sjmallett			    as_bad (_("can't parse register list"));
10564208737Sjmallett			    break;
10565208737Sjmallett			  }
10566208737Sjmallett		      }
10567208737Sjmallett
10568208737Sjmallett		    while (reg1 <= reg2)
10569208737Sjmallett		      {
10570208737Sjmallett			if (reg1 >= 4 && reg1 <= 7)
10571208737Sjmallett			  {
10572218822Sdim			    if (!seen_framesz)
10573208737Sjmallett				/* args $a0-$a3 */
10574208737Sjmallett				args |= 1 << (reg1 - 4);
10575208737Sjmallett			    else
10576208737Sjmallett				/* statics $a0-$a3 */
10577208737Sjmallett				statics |= 1 << (reg1 - 4);
10578208737Sjmallett			  }
10579208737Sjmallett			else if ((reg1 >= 16 && reg1 <= 23) || reg1 == 30)
10580208737Sjmallett			  {
10581208737Sjmallett			    /* $s0-$s8 */
10582208737Sjmallett			    sregs |= 1 << ((reg1 == 30) ? 8 : (reg1 - 16));
10583208737Sjmallett			  }
10584208737Sjmallett			else if (reg1 == 31)
10585208737Sjmallett			  {
10586208737Sjmallett			    /* Add $ra to insn.  */
10587208737Sjmallett			    opcode |= 0x40;
10588208737Sjmallett			  }
10589208737Sjmallett			else
10590208737Sjmallett			  {
10591208737Sjmallett			    as_bad (_("unexpected register in list"));
10592208737Sjmallett			    break;
10593208737Sjmallett			  }
10594208737Sjmallett			if (++reg1 == 24)
10595208737Sjmallett			  reg1 = 30;
10596208737Sjmallett		      }
10597208737Sjmallett		  }
10598208737Sjmallett
10599208737Sjmallett		/* Encode args/statics combination.  */
10600208737Sjmallett		if (args & statics)
10601208737Sjmallett		  as_bad (_("arg/static registers overlap"));
10602208737Sjmallett		else if (args == 0xf)
10603208737Sjmallett		  /* All $a0-$a3 are args.  */
10604208737Sjmallett		  opcode |= MIPS16_ALL_ARGS << 16;
10605208737Sjmallett		else if (statics == 0xf)
10606208737Sjmallett		  /* All $a0-$a3 are statics.  */
10607208737Sjmallett		  opcode |= MIPS16_ALL_STATICS << 16;
10608208737Sjmallett		else
10609208737Sjmallett		  {
10610208737Sjmallett		    int narg = 0, nstat = 0;
10611208737Sjmallett
10612208737Sjmallett		    /* Count arg registers.  */
10613208737Sjmallett		    while (args & 0x1)
10614208737Sjmallett		      {
10615208737Sjmallett			args >>= 1;
10616208737Sjmallett			narg++;
10617208737Sjmallett		      }
10618208737Sjmallett		    if (args != 0)
10619208737Sjmallett		      as_bad (_("invalid arg register list"));
10620208737Sjmallett
10621208737Sjmallett		    /* Count static registers.  */
10622208737Sjmallett		    while (statics & 0x8)
10623208737Sjmallett		      {
10624208737Sjmallett			statics = (statics << 1) & 0xf;
10625208737Sjmallett			nstat++;
10626208737Sjmallett		      }
10627208737Sjmallett		    if (statics != 0)
10628208737Sjmallett		      as_bad (_("invalid static register list"));
10629208737Sjmallett
10630208737Sjmallett		    /* Encode args/statics.  */
10631208737Sjmallett		    opcode |= ((narg << 2) | nstat) << 16;
10632208737Sjmallett		  }
10633208737Sjmallett
10634208737Sjmallett		/* Encode $s0/$s1.  */
10635208737Sjmallett		if (sregs & (1 << 0))		/* $s0 */
10636208737Sjmallett		  opcode |= 0x20;
10637208737Sjmallett		if (sregs & (1 << 1))		/* $s1 */
10638208737Sjmallett		  opcode |= 0x10;
10639208737Sjmallett		sregs >>= 2;
10640208737Sjmallett
10641208737Sjmallett		if (sregs != 0)
10642208737Sjmallett		  {
10643208737Sjmallett		    /* Count regs $s2-$s8.  */
10644208737Sjmallett		    int nsreg = 0;
10645208737Sjmallett		    while (sregs & 1)
10646208737Sjmallett		      {
10647208737Sjmallett			sregs >>= 1;
10648208737Sjmallett			nsreg++;
10649208737Sjmallett		      }
10650208737Sjmallett		    if (sregs != 0)
10651208737Sjmallett		      as_bad (_("invalid static register list"));
10652208737Sjmallett		    /* Encode $s2-$s8. */
10653208737Sjmallett		    opcode |= nsreg << 24;
10654208737Sjmallett		  }
10655208737Sjmallett
10656208737Sjmallett		/* Encode frame size.  */
10657208737Sjmallett		if (!seen_framesz)
10658208737Sjmallett		  as_bad (_("missing frame size"));
10659208737Sjmallett		else if ((framesz & 7) != 0 || framesz < 0
10660208737Sjmallett			 || framesz > 0xff * 8)
10661208737Sjmallett		  as_bad (_("invalid frame size"));
10662208737Sjmallett		else if (framesz != 128 || (opcode >> 16) != 0)
10663208737Sjmallett		  {
10664208737Sjmallett		    framesz /= 8;
10665208737Sjmallett		    opcode |= (((framesz & 0xf0) << 16)
10666208737Sjmallett			     | (framesz & 0x0f));
10667208737Sjmallett		  }
10668208737Sjmallett
10669208737Sjmallett		/* Finally build the instruction.  */
10670208737Sjmallett		if ((opcode >> 16) != 0 || framesz == 0)
10671208737Sjmallett		  {
10672208737Sjmallett		    ip->use_extend = TRUE;
10673208737Sjmallett		    ip->extend = opcode >> 16;
10674208737Sjmallett		  }
10675208737Sjmallett		ip->insn_opcode |= opcode & 0x7f;
10676208737Sjmallett	      }
10677208737Sjmallett	    continue;
10678208737Sjmallett
10679179404Sobrien	    case 'e':		/* extend code */
10680179404Sobrien	      my_getExpression (&imm_expr, s);
10681179404Sobrien	      check_absolute_expr (ip, &imm_expr);
10682179404Sobrien	      if ((unsigned long) imm_expr.X_add_number > 0x7ff)
10683179404Sobrien		{
10684179404Sobrien		  as_warn (_("Invalid value for `%s' (%lu)"),
10685179404Sobrien			   ip->insn_mo->name,
10686179404Sobrien			   (unsigned long) imm_expr.X_add_number);
10687179404Sobrien		  imm_expr.X_add_number &= 0x7ff;
10688179404Sobrien		}
10689179404Sobrien	      ip->insn_opcode |= imm_expr.X_add_number;
10690179404Sobrien	      imm_expr.X_op = O_absent;
10691179404Sobrien	      s = expr_end;
10692179404Sobrien	      continue;
10693179404Sobrien
10694179404Sobrien	    default:
10695179404Sobrien	      internalError ();
10696179404Sobrien	    }
10697179404Sobrien	  break;
10698179404Sobrien	}
10699179404Sobrien
10700179404Sobrien      /* Args don't match.  */
10701179404Sobrien      if (insn + 1 < &mips16_opcodes[bfd_mips16_num_opcodes] &&
10702179404Sobrien	  strcmp (insn->name, insn[1].name) == 0)
10703179404Sobrien	{
10704179404Sobrien	  ++insn;
10705179404Sobrien	  s = argsstart;
10706179404Sobrien	  continue;
10707179404Sobrien	}
10708179404Sobrien
10709179404Sobrien      insn_error = _("illegal operands");
10710179404Sobrien
10711179404Sobrien      return;
10712179404Sobrien    }
10713179404Sobrien}
10714179404Sobrien
10715179404Sobrien/* This structure holds information we know about a mips16 immediate
10716179404Sobrien   argument type.  */
10717179404Sobrien
10718179404Sobrienstruct mips16_immed_operand
10719179404Sobrien{
10720179404Sobrien  /* The type code used in the argument string in the opcode table.  */
10721179404Sobrien  int type;
10722179404Sobrien  /* The number of bits in the short form of the opcode.  */
10723179404Sobrien  int nbits;
10724179404Sobrien  /* The number of bits in the extended form of the opcode.  */
10725179404Sobrien  int extbits;
10726179404Sobrien  /* The amount by which the short form is shifted when it is used;
10727179404Sobrien     for example, the sw instruction has a shift count of 2.  */
10728179404Sobrien  int shift;
10729179404Sobrien  /* The amount by which the short form is shifted when it is stored
10730179404Sobrien     into the instruction code.  */
10731179404Sobrien  int op_shift;
10732179404Sobrien  /* Non-zero if the short form is unsigned.  */
10733179404Sobrien  int unsp;
10734179404Sobrien  /* Non-zero if the extended form is unsigned.  */
10735179404Sobrien  int extu;
10736179404Sobrien  /* Non-zero if the value is PC relative.  */
10737179404Sobrien  int pcrel;
10738179404Sobrien};
10739179404Sobrien
10740179404Sobrien/* The mips16 immediate operand types.  */
10741179404Sobrien
10742179404Sobrienstatic const struct mips16_immed_operand mips16_immed_operands[] =
10743179404Sobrien{
10744179404Sobrien  { '<',  3,  5, 0, MIPS16OP_SH_RZ,   1, 1, 0 },
10745179404Sobrien  { '>',  3,  5, 0, MIPS16OP_SH_RX,   1, 1, 0 },
10746179404Sobrien  { '[',  3,  6, 0, MIPS16OP_SH_RZ,   1, 1, 0 },
10747179404Sobrien  { ']',  3,  6, 0, MIPS16OP_SH_RX,   1, 1, 0 },
10748179404Sobrien  { '4',  4, 15, 0, MIPS16OP_SH_IMM4, 0, 0, 0 },
10749179404Sobrien  { '5',  5, 16, 0, MIPS16OP_SH_IMM5, 1, 0, 0 },
10750179404Sobrien  { 'H',  5, 16, 1, MIPS16OP_SH_IMM5, 1, 0, 0 },
10751179404Sobrien  { 'W',  5, 16, 2, MIPS16OP_SH_IMM5, 1, 0, 0 },
10752179404Sobrien  { 'D',  5, 16, 3, MIPS16OP_SH_IMM5, 1, 0, 0 },
10753179404Sobrien  { 'j',  5, 16, 0, MIPS16OP_SH_IMM5, 0, 0, 0 },
10754179404Sobrien  { '8',  8, 16, 0, MIPS16OP_SH_IMM8, 1, 0, 0 },
10755179404Sobrien  { 'V',  8, 16, 2, MIPS16OP_SH_IMM8, 1, 0, 0 },
10756179404Sobrien  { 'C',  8, 16, 3, MIPS16OP_SH_IMM8, 1, 0, 0 },
10757179404Sobrien  { 'U',  8, 16, 0, MIPS16OP_SH_IMM8, 1, 1, 0 },
10758179404Sobrien  { 'k',  8, 16, 0, MIPS16OP_SH_IMM8, 0, 0, 0 },
10759179404Sobrien  { 'K',  8, 16, 3, MIPS16OP_SH_IMM8, 0, 0, 0 },
10760179404Sobrien  { 'p',  8, 16, 0, MIPS16OP_SH_IMM8, 0, 0, 1 },
10761179404Sobrien  { 'q', 11, 16, 0, MIPS16OP_SH_IMM8, 0, 0, 1 },
10762179404Sobrien  { 'A',  8, 16, 2, MIPS16OP_SH_IMM8, 1, 0, 1 },
10763179404Sobrien  { 'B',  5, 16, 3, MIPS16OP_SH_IMM5, 1, 0, 1 },
10764179404Sobrien  { 'E',  5, 16, 2, MIPS16OP_SH_IMM5, 1, 0, 1 }
10765179404Sobrien};
10766179404Sobrien
10767179404Sobrien#define MIPS16_NUM_IMMED \
10768179404Sobrien  (sizeof mips16_immed_operands / sizeof mips16_immed_operands[0])
10769179404Sobrien
10770179404Sobrien/* Handle a mips16 instruction with an immediate value.  This or's the
10771179404Sobrien   small immediate value into *INSN.  It sets *USE_EXTEND to indicate
10772179404Sobrien   whether an extended value is needed; if one is needed, it sets
10773179404Sobrien   *EXTEND to the value.  The argument type is TYPE.  The value is VAL.
10774179404Sobrien   If SMALL is true, an unextended opcode was explicitly requested.
10775179404Sobrien   If EXT is true, an extended opcode was explicitly requested.  If
10776179404Sobrien   WARN is true, warn if EXT does not match reality.  */
10777179404Sobrien
10778179404Sobrienstatic void
10779179404Sobrienmips16_immed (char *file, unsigned int line, int type, offsetT val,
10780179404Sobrien	      bfd_boolean warn, bfd_boolean small, bfd_boolean ext,
10781179404Sobrien	      unsigned long *insn, bfd_boolean *use_extend,
10782179404Sobrien	      unsigned short *extend)
10783179404Sobrien{
10784218822Sdim  const struct mips16_immed_operand *op;
10785179404Sobrien  int mintiny, maxtiny;
10786179404Sobrien  bfd_boolean needext;
10787179404Sobrien
10788179404Sobrien  op = mips16_immed_operands;
10789179404Sobrien  while (op->type != type)
10790179404Sobrien    {
10791179404Sobrien      ++op;
10792179404Sobrien      assert (op < mips16_immed_operands + MIPS16_NUM_IMMED);
10793179404Sobrien    }
10794179404Sobrien
10795179404Sobrien  if (op->unsp)
10796179404Sobrien    {
10797179404Sobrien      if (type == '<' || type == '>' || type == '[' || type == ']')
10798179404Sobrien	{
10799179404Sobrien	  mintiny = 1;
10800179404Sobrien	  maxtiny = 1 << op->nbits;
10801179404Sobrien	}
10802179404Sobrien      else
10803179404Sobrien	{
10804179404Sobrien	  mintiny = 0;
10805179404Sobrien	  maxtiny = (1 << op->nbits) - 1;
10806179404Sobrien	}
10807179404Sobrien    }
10808179404Sobrien  else
10809179404Sobrien    {
10810179404Sobrien      mintiny = - (1 << (op->nbits - 1));
10811179404Sobrien      maxtiny = (1 << (op->nbits - 1)) - 1;
10812179404Sobrien    }
10813179404Sobrien
10814179404Sobrien  /* Branch offsets have an implicit 0 in the lowest bit.  */
10815179404Sobrien  if (type == 'p' || type == 'q')
10816179404Sobrien    val /= 2;
10817179404Sobrien
10818179404Sobrien  if ((val & ((1 << op->shift) - 1)) != 0
10819179404Sobrien      || val < (mintiny << op->shift)
10820179404Sobrien      || val > (maxtiny << op->shift))
10821179404Sobrien    needext = TRUE;
10822179404Sobrien  else
10823179404Sobrien    needext = FALSE;
10824179404Sobrien
10825179404Sobrien  if (warn && ext && ! needext)
10826179404Sobrien    as_warn_where (file, line,
10827179404Sobrien		   _("extended operand requested but not required"));
10828179404Sobrien  if (small && needext)
10829179404Sobrien    as_bad_where (file, line, _("invalid unextended operand value"));
10830179404Sobrien
10831179404Sobrien  if (small || (! ext && ! needext))
10832179404Sobrien    {
10833179404Sobrien      int insnval;
10834179404Sobrien
10835179404Sobrien      *use_extend = FALSE;
10836179404Sobrien      insnval = ((val >> op->shift) & ((1 << op->nbits) - 1));
10837179404Sobrien      insnval <<= op->op_shift;
10838179404Sobrien      *insn |= insnval;
10839179404Sobrien    }
10840179404Sobrien  else
10841179404Sobrien    {
10842179404Sobrien      long minext, maxext;
10843179404Sobrien      int extval;
10844179404Sobrien
10845179404Sobrien      if (op->extu)
10846179404Sobrien	{
10847179404Sobrien	  minext = 0;
10848179404Sobrien	  maxext = (1 << op->extbits) - 1;
10849179404Sobrien	}
10850179404Sobrien      else
10851179404Sobrien	{
10852179404Sobrien	  minext = - (1 << (op->extbits - 1));
10853179404Sobrien	  maxext = (1 << (op->extbits - 1)) - 1;
10854179404Sobrien	}
10855179404Sobrien      if (val < minext || val > maxext)
10856179404Sobrien	as_bad_where (file, line,
10857179404Sobrien		      _("operand value out of range for instruction"));
10858179404Sobrien
10859179404Sobrien      *use_extend = TRUE;
10860179404Sobrien      if (op->extbits == 16)
10861179404Sobrien	{
10862179404Sobrien	  extval = ((val >> 11) & 0x1f) | (val & 0x7e0);
10863179404Sobrien	  val &= 0x1f;
10864179404Sobrien	}
10865179404Sobrien      else if (op->extbits == 15)
10866179404Sobrien	{
10867179404Sobrien	  extval = ((val >> 11) & 0xf) | (val & 0x7f0);
10868179404Sobrien	  val &= 0xf;
10869179404Sobrien	}
10870179404Sobrien      else
10871179404Sobrien	{
10872179404Sobrien	  extval = ((val & 0x1f) << 6) | (val & 0x20);
10873179404Sobrien	  val = 0;
10874179404Sobrien	}
10875179404Sobrien
10876179404Sobrien      *extend = (unsigned short) extval;
10877179404Sobrien      *insn |= val;
10878179404Sobrien    }
10879179404Sobrien}
10880179404Sobrien
10881208737Sjmallettstruct percent_op_match
10882179404Sobrien{
10883179404Sobrien  const char *str;
10884179404Sobrien  bfd_reloc_code_real_type reloc;
10885208737Sjmallett};
10886208737Sjmallett
10887208737Sjmallettstatic const struct percent_op_match mips_percent_op[] =
10888179404Sobrien{
10889179404Sobrien  {"%lo", BFD_RELOC_LO16},
10890179404Sobrien#ifdef OBJ_ELF
10891179404Sobrien  {"%call_hi", BFD_RELOC_MIPS_CALL_HI16},
10892179404Sobrien  {"%call_lo", BFD_RELOC_MIPS_CALL_LO16},
10893179404Sobrien  {"%call16", BFD_RELOC_MIPS_CALL16},
10894179404Sobrien  {"%got_disp", BFD_RELOC_MIPS_GOT_DISP},
10895179404Sobrien  {"%got_page", BFD_RELOC_MIPS_GOT_PAGE},
10896179404Sobrien  {"%got_ofst", BFD_RELOC_MIPS_GOT_OFST},
10897179404Sobrien  {"%got_hi", BFD_RELOC_MIPS_GOT_HI16},
10898179404Sobrien  {"%got_lo", BFD_RELOC_MIPS_GOT_LO16},
10899179404Sobrien  {"%got", BFD_RELOC_MIPS_GOT16},
10900179404Sobrien  {"%gp_rel", BFD_RELOC_GPREL16},
10901179404Sobrien  {"%half", BFD_RELOC_16},
10902179404Sobrien  {"%highest", BFD_RELOC_MIPS_HIGHEST},
10903179404Sobrien  {"%higher", BFD_RELOC_MIPS_HIGHER},
10904179404Sobrien  {"%neg", BFD_RELOC_MIPS_SUB},
10905218822Sdim  {"%tlsgd", BFD_RELOC_MIPS_TLS_GD},
10906218822Sdim  {"%tlsldm", BFD_RELOC_MIPS_TLS_LDM},
10907218822Sdim  {"%dtprel_hi", BFD_RELOC_MIPS_TLS_DTPREL_HI16},
10908218822Sdim  {"%dtprel_lo", BFD_RELOC_MIPS_TLS_DTPREL_LO16},
10909218822Sdim  {"%tprel_hi", BFD_RELOC_MIPS_TLS_TPREL_HI16},
10910218822Sdim  {"%tprel_lo", BFD_RELOC_MIPS_TLS_TPREL_LO16},
10911218822Sdim  {"%gottprel", BFD_RELOC_MIPS_TLS_GOTTPREL},
10912179404Sobrien#endif
10913179404Sobrien  {"%hi", BFD_RELOC_HI16_S}
10914179404Sobrien};
10915179404Sobrien
10916218822Sdimstatic const struct percent_op_match mips16_percent_op[] =
10917218822Sdim{
10918218822Sdim  {"%lo", BFD_RELOC_MIPS16_LO16},
10919218822Sdim  {"%gprel", BFD_RELOC_MIPS16_GPREL},
10920218822Sdim  {"%hi", BFD_RELOC_MIPS16_HI16_S}
10921218822Sdim};
10922218822Sdim
10923218822Sdim
10924179404Sobrien/* Return true if *STR points to a relocation operator.  When returning true,
10925179404Sobrien   move *STR over the operator and store its relocation code in *RELOC.
10926179404Sobrien   Leave both *STR and *RELOC alone when returning false.  */
10927179404Sobrien
10928179404Sobrienstatic bfd_boolean
10929179404Sobrienparse_relocation (char **str, bfd_reloc_code_real_type *reloc)
10930179404Sobrien{
10931208737Sjmallett  const struct percent_op_match *percent_op;
10932208737Sjmallett  size_t limit, i;
10933179404Sobrien
10934218822Sdim  if (mips_opts.mips16)
10935218822Sdim    {
10936218822Sdim      percent_op = mips16_percent_op;
10937218822Sdim      limit = ARRAY_SIZE (mips16_percent_op);
10938218822Sdim    }
10939218822Sdim  else
10940218822Sdim    {
10941218822Sdim      percent_op = mips_percent_op;
10942218822Sdim      limit = ARRAY_SIZE (mips_percent_op);
10943218822Sdim    }
10944208737Sjmallett
10945208737Sjmallett  for (i = 0; i < limit; i++)
10946179404Sobrien    if (strncasecmp (*str, percent_op[i].str, strlen (percent_op[i].str)) == 0)
10947179404Sobrien      {
10948208737Sjmallett	int len = strlen (percent_op[i].str);
10949208737Sjmallett
10950208737Sjmallett	if (!ISSPACE ((*str)[len]) && (*str)[len] != '(')
10951208737Sjmallett	  continue;
10952208737Sjmallett
10953179404Sobrien	*str += strlen (percent_op[i].str);
10954179404Sobrien	*reloc = percent_op[i].reloc;
10955179404Sobrien
10956179404Sobrien	/* Check whether the output BFD supports this relocation.
10957179404Sobrien	   If not, issue an error and fall back on something safe.  */
10958179404Sobrien	if (!bfd_reloc_type_lookup (stdoutput, percent_op[i].reloc))
10959179404Sobrien	  {
10960179404Sobrien	    as_bad ("relocation %s isn't supported by the current ABI",
10961179404Sobrien		    percent_op[i].str);
10962208737Sjmallett	    *reloc = BFD_RELOC_UNUSED;
10963179404Sobrien	  }
10964179404Sobrien	return TRUE;
10965179404Sobrien      }
10966179404Sobrien  return FALSE;
10967179404Sobrien}
10968179404Sobrien
10969179404Sobrien
10970179404Sobrien/* Parse string STR as a 16-bit relocatable operand.  Store the
10971179404Sobrien   expression in *EP and the relocations in the array starting
10972179404Sobrien   at RELOC.  Return the number of relocation operators used.
10973179404Sobrien
10974208737Sjmallett   On exit, EXPR_END points to the first character after the expression.  */
10975179404Sobrien
10976179404Sobrienstatic size_t
10977179404Sobrienmy_getSmallExpression (expressionS *ep, bfd_reloc_code_real_type *reloc,
10978179404Sobrien		       char *str)
10979179404Sobrien{
10980179404Sobrien  bfd_reloc_code_real_type reversed_reloc[3];
10981179404Sobrien  size_t reloc_index, i;
10982179404Sobrien  int crux_depth, str_depth;
10983179404Sobrien  char *crux;
10984179404Sobrien
10985179404Sobrien  /* Search for the start of the main expression, recoding relocations
10986179404Sobrien     in REVERSED_RELOC.  End the loop with CRUX pointing to the start
10987179404Sobrien     of the main expression and with CRUX_DEPTH containing the number
10988179404Sobrien     of open brackets at that point.  */
10989179404Sobrien  reloc_index = -1;
10990179404Sobrien  str_depth = 0;
10991179404Sobrien  do
10992179404Sobrien    {
10993179404Sobrien      reloc_index++;
10994179404Sobrien      crux = str;
10995179404Sobrien      crux_depth = str_depth;
10996179404Sobrien
10997179404Sobrien      /* Skip over whitespace and brackets, keeping count of the number
10998179404Sobrien	 of brackets.  */
10999179404Sobrien      while (*str == ' ' || *str == '\t' || *str == '(')
11000179404Sobrien	if (*str++ == '(')
11001179404Sobrien	  str_depth++;
11002179404Sobrien    }
11003179404Sobrien  while (*str == '%'
11004179404Sobrien	 && reloc_index < (HAVE_NEWABI ? 3 : 1)
11005179404Sobrien	 && parse_relocation (&str, &reversed_reloc[reloc_index]));
11006179404Sobrien
11007179404Sobrien  my_getExpression (ep, crux);
11008179404Sobrien  str = expr_end;
11009179404Sobrien
11010179404Sobrien  /* Match every open bracket.  */
11011179404Sobrien  while (crux_depth > 0 && (*str == ')' || *str == ' ' || *str == '\t'))
11012179404Sobrien    if (*str++ == ')')
11013179404Sobrien      crux_depth--;
11014179404Sobrien
11015179404Sobrien  if (crux_depth > 0)
11016179404Sobrien    as_bad ("unclosed '('");
11017179404Sobrien
11018179404Sobrien  expr_end = str;
11019179404Sobrien
11020208737Sjmallett  if (reloc_index != 0)
11021179404Sobrien    {
11022179404Sobrien      prev_reloc_op_frag = frag_now;
11023179404Sobrien      for (i = 0; i < reloc_index; i++)
11024179404Sobrien	reloc[i] = reversed_reloc[reloc_index - 1 - i];
11025179404Sobrien    }
11026179404Sobrien
11027179404Sobrien  return reloc_index;
11028179404Sobrien}
11029179404Sobrien
11030179404Sobrienstatic void
11031179404Sobrienmy_getExpression (expressionS *ep, char *str)
11032179404Sobrien{
11033179404Sobrien  char *save_in;
11034179404Sobrien  valueT val;
11035179404Sobrien
11036179404Sobrien  save_in = input_line_pointer;
11037179404Sobrien  input_line_pointer = str;
11038179404Sobrien  expression (ep);
11039179404Sobrien  expr_end = input_line_pointer;
11040179404Sobrien  input_line_pointer = save_in;
11041179404Sobrien
11042179404Sobrien  /* If we are in mips16 mode, and this is an expression based on `.',
11043179404Sobrien     then we bump the value of the symbol by 1 since that is how other
11044179404Sobrien     text symbols are handled.  We don't bother to handle complex
11045179404Sobrien     expressions, just `.' plus or minus a constant.  */
11046179404Sobrien  if (mips_opts.mips16
11047179404Sobrien      && ep->X_op == O_symbol
11048179404Sobrien      && strcmp (S_GET_NAME (ep->X_add_symbol), FAKE_LABEL_NAME) == 0
11049179404Sobrien      && S_GET_SEGMENT (ep->X_add_symbol) == now_seg
11050179404Sobrien      && symbol_get_frag (ep->X_add_symbol) == frag_now
11051179404Sobrien      && symbol_constant_p (ep->X_add_symbol)
11052179404Sobrien      && (val = S_GET_VALUE (ep->X_add_symbol)) == frag_now_fix ())
11053179404Sobrien    S_SET_VALUE (ep->X_add_symbol, val + 1);
11054179404Sobrien}
11055179404Sobrien
11056179404Sobrien/* Turn a string in input_line_pointer into a floating point constant
11057179404Sobrien   of type TYPE, and store the appropriate bytes in *LITP.  The number
11058179404Sobrien   of LITTLENUMS emitted is stored in *SIZEP.  An error message is
11059179404Sobrien   returned, or NULL on OK.  */
11060179404Sobrien
11061179404Sobrienchar *
11062179404Sobrienmd_atof (int type, char *litP, int *sizeP)
11063179404Sobrien{
11064179404Sobrien  int prec;
11065179404Sobrien  LITTLENUM_TYPE words[4];
11066179404Sobrien  char *t;
11067179404Sobrien  int i;
11068179404Sobrien
11069179404Sobrien  switch (type)
11070179404Sobrien    {
11071179404Sobrien    case 'f':
11072179404Sobrien      prec = 2;
11073179404Sobrien      break;
11074179404Sobrien
11075179404Sobrien    case 'd':
11076179404Sobrien      prec = 4;
11077179404Sobrien      break;
11078179404Sobrien
11079179404Sobrien    default:
11080179404Sobrien      *sizeP = 0;
11081179404Sobrien      return _("bad call to md_atof");
11082179404Sobrien    }
11083179404Sobrien
11084179404Sobrien  t = atof_ieee (input_line_pointer, type, words);
11085179404Sobrien  if (t)
11086179404Sobrien    input_line_pointer = t;
11087179404Sobrien
11088179404Sobrien  *sizeP = prec * 2;
11089179404Sobrien
11090179404Sobrien  if (! target_big_endian)
11091179404Sobrien    {
11092179404Sobrien      for (i = prec - 1; i >= 0; i--)
11093179404Sobrien	{
11094179404Sobrien	  md_number_to_chars (litP, words[i], 2);
11095179404Sobrien	  litP += 2;
11096179404Sobrien	}
11097179404Sobrien    }
11098179404Sobrien  else
11099179404Sobrien    {
11100179404Sobrien      for (i = 0; i < prec; i++)
11101179404Sobrien	{
11102179404Sobrien	  md_number_to_chars (litP, words[i], 2);
11103179404Sobrien	  litP += 2;
11104179404Sobrien	}
11105179404Sobrien    }
11106179404Sobrien
11107179404Sobrien  return NULL;
11108179404Sobrien}
11109179404Sobrien
11110179404Sobrienvoid
11111179404Sobrienmd_number_to_chars (char *buf, valueT val, int n)
11112179404Sobrien{
11113179404Sobrien  if (target_big_endian)
11114179404Sobrien    number_to_chars_bigendian (buf, val, n);
11115179404Sobrien  else
11116179404Sobrien    number_to_chars_littleendian (buf, val, n);
11117179404Sobrien}
11118179404Sobrien
11119179404Sobrien#ifdef OBJ_ELF
11120179404Sobrienstatic int support_64bit_objects(void)
11121179404Sobrien{
11122179404Sobrien  const char **list, **l;
11123179404Sobrien  int yes;
11124179404Sobrien
11125179404Sobrien  list = bfd_target_list ();
11126179404Sobrien  for (l = list; *l != NULL; l++)
11127179404Sobrien#ifdef TE_TMIPS
11128179404Sobrien    /* This is traditional mips */
11129179404Sobrien    if (strcmp (*l, "elf64-tradbigmips") == 0
11130179404Sobrien	|| strcmp (*l, "elf64-tradlittlemips") == 0)
11131179404Sobrien#else
11132179404Sobrien    if (strcmp (*l, "elf64-bigmips") == 0
11133179404Sobrien	|| strcmp (*l, "elf64-littlemips") == 0)
11134179404Sobrien#endif
11135179404Sobrien      break;
11136179404Sobrien  yes = (*l != NULL);
11137179404Sobrien  free (list);
11138179404Sobrien  return yes;
11139179404Sobrien}
11140179404Sobrien#endif /* OBJ_ELF */
11141179404Sobrien
11142179404Sobrienconst char *md_shortopts = "O::g::G:";
11143179404Sobrien
11144179404Sobrienstruct option md_longopts[] =
11145179404Sobrien{
11146179404Sobrien  /* Options which specify architecture.  */
11147179404Sobrien#define OPTION_ARCH_BASE    (OPTION_MD_BASE)
11148179404Sobrien#define OPTION_MARCH (OPTION_ARCH_BASE + 0)
11149179404Sobrien  {"march", required_argument, NULL, OPTION_MARCH},
11150179404Sobrien#define OPTION_MTUNE (OPTION_ARCH_BASE + 1)
11151179404Sobrien  {"mtune", required_argument, NULL, OPTION_MTUNE},
11152179404Sobrien#define OPTION_MIPS1 (OPTION_ARCH_BASE + 2)
11153179404Sobrien  {"mips0", no_argument, NULL, OPTION_MIPS1},
11154179404Sobrien  {"mips1", no_argument, NULL, OPTION_MIPS1},
11155179404Sobrien#define OPTION_MIPS2 (OPTION_ARCH_BASE + 3)
11156179404Sobrien  {"mips2", no_argument, NULL, OPTION_MIPS2},
11157179404Sobrien#define OPTION_MIPS3 (OPTION_ARCH_BASE + 4)
11158179404Sobrien  {"mips3", no_argument, NULL, OPTION_MIPS3},
11159179404Sobrien#define OPTION_MIPS4 (OPTION_ARCH_BASE + 5)
11160179404Sobrien  {"mips4", no_argument, NULL, OPTION_MIPS4},
11161179404Sobrien#define OPTION_MIPS5 (OPTION_ARCH_BASE + 6)
11162179404Sobrien  {"mips5", no_argument, NULL, OPTION_MIPS5},
11163179404Sobrien#define OPTION_MIPS32 (OPTION_ARCH_BASE + 7)
11164179404Sobrien  {"mips32", no_argument, NULL, OPTION_MIPS32},
11165179404Sobrien#define OPTION_MIPS64 (OPTION_ARCH_BASE + 8)
11166179404Sobrien  {"mips64", no_argument, NULL, OPTION_MIPS64},
11167179404Sobrien#define OPTION_MIPS32R2 (OPTION_ARCH_BASE + 9)
11168179404Sobrien  {"mips32r2", no_argument, NULL, OPTION_MIPS32R2},
11169179404Sobrien#define OPTION_MIPS64R2 (OPTION_ARCH_BASE + 10)
11170179404Sobrien  {"mips64r2", no_argument, NULL, OPTION_MIPS64R2},
11171179404Sobrien
11172179404Sobrien  /* Options which specify Application Specific Extensions (ASEs).  */
11173179404Sobrien#define OPTION_ASE_BASE (OPTION_ARCH_BASE + 11)
11174179404Sobrien#define OPTION_MIPS16 (OPTION_ASE_BASE + 0)
11175179404Sobrien  {"mips16", no_argument, NULL, OPTION_MIPS16},
11176179404Sobrien#define OPTION_NO_MIPS16 (OPTION_ASE_BASE + 1)
11177179404Sobrien  {"no-mips16", no_argument, NULL, OPTION_NO_MIPS16},
11178179404Sobrien#define OPTION_MIPS3D (OPTION_ASE_BASE + 2)
11179179404Sobrien  {"mips3d", no_argument, NULL, OPTION_MIPS3D},
11180179404Sobrien#define OPTION_NO_MIPS3D (OPTION_ASE_BASE + 3)
11181179404Sobrien  {"no-mips3d", no_argument, NULL, OPTION_NO_MIPS3D},
11182179404Sobrien#define OPTION_MDMX (OPTION_ASE_BASE + 4)
11183179404Sobrien  {"mdmx", no_argument, NULL, OPTION_MDMX},
11184179404Sobrien#define OPTION_NO_MDMX (OPTION_ASE_BASE + 5)
11185179404Sobrien  {"no-mdmx", no_argument, NULL, OPTION_NO_MDMX},
11186208737Sjmallett#define OPTION_DSP (OPTION_ASE_BASE + 6)
11187208737Sjmallett  {"mdsp", no_argument, NULL, OPTION_DSP},
11188208737Sjmallett#define OPTION_NO_DSP (OPTION_ASE_BASE + 7)
11189208737Sjmallett  {"mno-dsp", no_argument, NULL, OPTION_NO_DSP},
11190208737Sjmallett#define OPTION_MT (OPTION_ASE_BASE + 8)
11191208737Sjmallett  {"mmt", no_argument, NULL, OPTION_MT},
11192208737Sjmallett#define OPTION_NO_MT (OPTION_ASE_BASE + 9)
11193208737Sjmallett  {"mno-mt", no_argument, NULL, OPTION_NO_MT},
11194218822Sdim#define OPTION_SMARTMIPS (OPTION_ASE_BASE + 10)
11195218822Sdim  {"msmartmips", no_argument, NULL, OPTION_SMARTMIPS},
11196218822Sdim#define OPTION_NO_SMARTMIPS (OPTION_ASE_BASE + 11)
11197218822Sdim  {"mno-smartmips", no_argument, NULL, OPTION_NO_SMARTMIPS},
11198218822Sdim#define OPTION_DSPR2 (OPTION_ASE_BASE + 12)
11199218822Sdim  {"mdspr2", no_argument, NULL, OPTION_DSPR2},
11200218822Sdim#define OPTION_NO_DSPR2 (OPTION_ASE_BASE + 13)
11201218822Sdim  {"mno-dspr2", no_argument, NULL, OPTION_NO_DSPR2},
11202179404Sobrien
11203179404Sobrien  /* Old-style architecture options.  Don't add more of these.  */
11204218822Sdim#define OPTION_COMPAT_ARCH_BASE (OPTION_ASE_BASE + 14)
11205179404Sobrien#define OPTION_M4650 (OPTION_COMPAT_ARCH_BASE + 0)
11206179404Sobrien  {"m4650", no_argument, NULL, OPTION_M4650},
11207179404Sobrien#define OPTION_NO_M4650 (OPTION_COMPAT_ARCH_BASE + 1)
11208179404Sobrien  {"no-m4650", no_argument, NULL, OPTION_NO_M4650},
11209179404Sobrien#define OPTION_M4010 (OPTION_COMPAT_ARCH_BASE + 2)
11210179404Sobrien  {"m4010", no_argument, NULL, OPTION_M4010},
11211179404Sobrien#define OPTION_NO_M4010 (OPTION_COMPAT_ARCH_BASE + 3)
11212179404Sobrien  {"no-m4010", no_argument, NULL, OPTION_NO_M4010},
11213179404Sobrien#define OPTION_M4100 (OPTION_COMPAT_ARCH_BASE + 4)
11214179404Sobrien  {"m4100", no_argument, NULL, OPTION_M4100},
11215179404Sobrien#define OPTION_NO_M4100 (OPTION_COMPAT_ARCH_BASE + 5)
11216179404Sobrien  {"no-m4100", no_argument, NULL, OPTION_NO_M4100},
11217179404Sobrien#define OPTION_M3900 (OPTION_COMPAT_ARCH_BASE + 6)
11218179404Sobrien  {"m3900", no_argument, NULL, OPTION_M3900},
11219179404Sobrien#define OPTION_NO_M3900 (OPTION_COMPAT_ARCH_BASE + 7)
11220179404Sobrien  {"no-m3900", no_argument, NULL, OPTION_NO_M3900},
11221179404Sobrien
11222179404Sobrien  /* Options which enable bug fixes.  */
11223179404Sobrien#define OPTION_FIX_BASE    (OPTION_COMPAT_ARCH_BASE + 8)
11224179404Sobrien#define OPTION_M7000_HILO_FIX (OPTION_FIX_BASE + 0)
11225179404Sobrien  {"mfix7000", no_argument, NULL, OPTION_M7000_HILO_FIX},
11226179404Sobrien#define OPTION_MNO_7000_HILO_FIX (OPTION_FIX_BASE + 1)
11227179404Sobrien  {"no-fix-7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
11228179404Sobrien  {"mno-fix7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX},
11229179404Sobrien#define OPTION_FIX_VR4120 (OPTION_FIX_BASE + 2)
11230179404Sobrien#define OPTION_NO_FIX_VR4120 (OPTION_FIX_BASE + 3)
11231179404Sobrien  {"mfix-vr4120",    no_argument, NULL, OPTION_FIX_VR4120},
11232179404Sobrien  {"mno-fix-vr4120", no_argument, NULL, OPTION_NO_FIX_VR4120},
11233208737Sjmallett#define OPTION_FIX_VR4130 (OPTION_FIX_BASE + 4)
11234208737Sjmallett#define OPTION_NO_FIX_VR4130 (OPTION_FIX_BASE + 5)
11235208737Sjmallett  {"mfix-vr4130",    no_argument, NULL, OPTION_FIX_VR4130},
11236208737Sjmallett  {"mno-fix-vr4130", no_argument, NULL, OPTION_NO_FIX_VR4130},
11237179404Sobrien
11238179404Sobrien  /* Miscellaneous options.  */
11239208737Sjmallett#define OPTION_MISC_BASE (OPTION_FIX_BASE + 6)
11240208737Sjmallett#define OPTION_TRAP (OPTION_MISC_BASE + 0)
11241179404Sobrien  {"trap", no_argument, NULL, OPTION_TRAP},
11242179404Sobrien  {"no-break", no_argument, NULL, OPTION_TRAP},
11243208737Sjmallett#define OPTION_BREAK (OPTION_MISC_BASE + 1)
11244179404Sobrien  {"break", no_argument, NULL, OPTION_BREAK},
11245179404Sobrien  {"no-trap", no_argument, NULL, OPTION_BREAK},
11246208737Sjmallett#define OPTION_EB (OPTION_MISC_BASE + 2)
11247179404Sobrien  {"EB", no_argument, NULL, OPTION_EB},
11248208737Sjmallett#define OPTION_EL (OPTION_MISC_BASE + 3)
11249179404Sobrien  {"EL", no_argument, NULL, OPTION_EL},
11250208737Sjmallett#define OPTION_FP32 (OPTION_MISC_BASE + 4)
11251179404Sobrien  {"mfp32", no_argument, NULL, OPTION_FP32},
11252208737Sjmallett#define OPTION_GP32 (OPTION_MISC_BASE + 5)
11253179404Sobrien  {"mgp32", no_argument, NULL, OPTION_GP32},
11254208737Sjmallett#define OPTION_CONSTRUCT_FLOATS (OPTION_MISC_BASE + 6)
11255179404Sobrien  {"construct-floats", no_argument, NULL, OPTION_CONSTRUCT_FLOATS},
11256208737Sjmallett#define OPTION_NO_CONSTRUCT_FLOATS (OPTION_MISC_BASE + 7)
11257179404Sobrien  {"no-construct-floats", no_argument, NULL, OPTION_NO_CONSTRUCT_FLOATS},
11258208737Sjmallett#define OPTION_FP64 (OPTION_MISC_BASE + 8)
11259179404Sobrien  {"mfp64", no_argument, NULL, OPTION_FP64},
11260208737Sjmallett#define OPTION_GP64 (OPTION_MISC_BASE + 9)
11261179404Sobrien  {"mgp64", no_argument, NULL, OPTION_GP64},
11262208737Sjmallett#define OPTION_RELAX_BRANCH (OPTION_MISC_BASE + 10)
11263208737Sjmallett#define OPTION_NO_RELAX_BRANCH (OPTION_MISC_BASE + 11)
11264179404Sobrien  {"relax-branch", no_argument, NULL, OPTION_RELAX_BRANCH},
11265179404Sobrien  {"no-relax-branch", no_argument, NULL, OPTION_NO_RELAX_BRANCH},
11266208737Sjmallett#define OPTION_MSHARED (OPTION_MISC_BASE + 12)
11267208737Sjmallett#define OPTION_MNO_SHARED (OPTION_MISC_BASE + 13)
11268208737Sjmallett  {"mshared", no_argument, NULL, OPTION_MSHARED},
11269208737Sjmallett  {"mno-shared", no_argument, NULL, OPTION_MNO_SHARED},
11270208737Sjmallett#define OPTION_MSYM32 (OPTION_MISC_BASE + 14)
11271208737Sjmallett#define OPTION_MNO_SYM32 (OPTION_MISC_BASE + 15)
11272208737Sjmallett  {"msym32", no_argument, NULL, OPTION_MSYM32},
11273208737Sjmallett  {"mno-sym32", no_argument, NULL, OPTION_MNO_SYM32},
11274179404Sobrien
11275179404Sobrien  /* ELF-specific options.  */
11276179404Sobrien#ifdef OBJ_ELF
11277208737Sjmallett#define OPTION_ELF_BASE    (OPTION_MISC_BASE + 16)
11278179404Sobrien#define OPTION_CALL_SHARED (OPTION_ELF_BASE + 0)
11279179404Sobrien  {"KPIC",        no_argument, NULL, OPTION_CALL_SHARED},
11280179404Sobrien  {"call_shared", no_argument, NULL, OPTION_CALL_SHARED},
11281179404Sobrien#define OPTION_NON_SHARED  (OPTION_ELF_BASE + 1)
11282179404Sobrien  {"non_shared",  no_argument, NULL, OPTION_NON_SHARED},
11283179404Sobrien#define OPTION_XGOT        (OPTION_ELF_BASE + 2)
11284179404Sobrien  {"xgot",        no_argument, NULL, OPTION_XGOT},
11285179404Sobrien#define OPTION_MABI        (OPTION_ELF_BASE + 3)
11286179404Sobrien  {"mabi", required_argument, NULL, OPTION_MABI},
11287179404Sobrien#define OPTION_32 	   (OPTION_ELF_BASE + 4)
11288179404Sobrien  {"32",          no_argument, NULL, OPTION_32},
11289179404Sobrien#define OPTION_N32 	   (OPTION_ELF_BASE + 5)
11290179404Sobrien  {"n32",         no_argument, NULL, OPTION_N32},
11291179404Sobrien#define OPTION_64          (OPTION_ELF_BASE + 6)
11292179404Sobrien  {"64",          no_argument, NULL, OPTION_64},
11293179404Sobrien#define OPTION_MDEBUG      (OPTION_ELF_BASE + 7)
11294179404Sobrien  {"mdebug", no_argument, NULL, OPTION_MDEBUG},
11295179404Sobrien#define OPTION_NO_MDEBUG   (OPTION_ELF_BASE + 8)
11296179404Sobrien  {"no-mdebug", no_argument, NULL, OPTION_NO_MDEBUG},
11297179404Sobrien#define OPTION_PDR	   (OPTION_ELF_BASE + 9)
11298179404Sobrien  {"mpdr", no_argument, NULL, OPTION_PDR},
11299179404Sobrien#define OPTION_NO_PDR	   (OPTION_ELF_BASE + 10)
11300179404Sobrien  {"mno-pdr", no_argument, NULL, OPTION_NO_PDR},
11301218822Sdim#define OPTION_MVXWORKS_PIC (OPTION_ELF_BASE + 11)
11302218822Sdim  {"mvxworks-pic", no_argument, NULL, OPTION_MVXWORKS_PIC},
11303179404Sobrien#endif /* OBJ_ELF */
11304179404Sobrien
11305208737Sjmallett#define OPTION_MOCTEON_UNSUPPORTED (OPTION_MISC_BASE + 28)
11306208737Sjmallett#define OPTION_NO_MOCTEON_UNSUPPORTED (OPTION_MISC_BASE + 29)
11307208737Sjmallett  {"mocteon-unsupported", no_argument, NULL, OPTION_MOCTEON_UNSUPPORTED},
11308208737Sjmallett  {"mno-octeon-unsupported", no_argument, NULL, OPTION_NO_MOCTEON_UNSUPPORTED},
11309208737Sjmallett
11310208737Sjmallett#define OPTION_MOCTEON_USEUN (OPTION_MISC_BASE + 30)
11311208737Sjmallett#define OPTION_NO_MOCTEON_USEUN (OPTION_MISC_BASE + 31)
11312208737Sjmallett  {"mocteon-useun", no_argument, NULL, OPTION_MOCTEON_USEUN},
11313208737Sjmallett  {"mno-octeon-useun", no_argument, NULL, OPTION_NO_MOCTEON_USEUN},
11314208737Sjmallett
11315179404Sobrien  {NULL, no_argument, NULL, 0}
11316179404Sobrien};
11317179404Sobriensize_t md_longopts_size = sizeof (md_longopts);
11318179404Sobrien
11319179404Sobrien/* Set STRING_PTR (either &mips_arch_string or &mips_tune_string) to
11320179404Sobrien   NEW_VALUE.  Warn if another value was already specified.  Note:
11321179404Sobrien   we have to defer parsing the -march and -mtune arguments in order
11322179404Sobrien   to handle 'from-abi' correctly, since the ABI might be specified
11323179404Sobrien   in a later argument.  */
11324179404Sobrien
11325179404Sobrienstatic void
11326179404Sobrienmips_set_option_string (const char **string_ptr, const char *new_value)
11327179404Sobrien{
11328179404Sobrien  if (*string_ptr != 0 && strcasecmp (*string_ptr, new_value) != 0)
11329179404Sobrien    as_warn (_("A different %s was already specified, is now %s"),
11330179404Sobrien	     string_ptr == &mips_arch_string ? "-march" : "-mtune",
11331179404Sobrien	     new_value);
11332179404Sobrien
11333179404Sobrien  *string_ptr = new_value;
11334179404Sobrien}
11335179404Sobrien
11336179404Sobrienint
11337179404Sobrienmd_parse_option (int c, char *arg)
11338179404Sobrien{
11339179404Sobrien  switch (c)
11340179404Sobrien    {
11341179404Sobrien    case OPTION_CONSTRUCT_FLOATS:
11342179404Sobrien      mips_disable_float_construction = 0;
11343179404Sobrien      break;
11344179404Sobrien
11345179404Sobrien    case OPTION_NO_CONSTRUCT_FLOATS:
11346179404Sobrien      mips_disable_float_construction = 1;
11347179404Sobrien      break;
11348179404Sobrien
11349179404Sobrien    case OPTION_TRAP:
11350179404Sobrien      mips_trap = 1;
11351179404Sobrien      break;
11352179404Sobrien
11353179404Sobrien    case OPTION_BREAK:
11354179404Sobrien      mips_trap = 0;
11355179404Sobrien      break;
11356179404Sobrien
11357179404Sobrien    case OPTION_EB:
11358179404Sobrien      target_big_endian = 1;
11359179404Sobrien      break;
11360179404Sobrien
11361179404Sobrien    case OPTION_EL:
11362179404Sobrien      target_big_endian = 0;
11363179404Sobrien      break;
11364179404Sobrien
11365208737Sjmallett    case OPTION_MOCTEON_UNSUPPORTED:
11366208737Sjmallett      octeon_error_on_unsupported = 1;
11367208737Sjmallett      break;
11368208737Sjmallett
11369208737Sjmallett    case OPTION_NO_MOCTEON_UNSUPPORTED:
11370208737Sjmallett      octeon_error_on_unsupported = 0;
11371208737Sjmallett      break;
11372208737Sjmallett
11373208737Sjmallett    case OPTION_MOCTEON_USEUN:
11374208737Sjmallett      octeon_use_unalign = 1;
11375208737Sjmallett      break;
11376208737Sjmallett
11377208737Sjmallett    case OPTION_NO_MOCTEON_USEUN:
11378208737Sjmallett      octeon_use_unalign = 0;
11379208737Sjmallett      break;
11380208737Sjmallett
11381179404Sobrien    case 'O':
11382218822Sdim      if (arg && arg[0] == '0')
11383179404Sobrien	mips_optimize = 1;
11384179404Sobrien      else
11385179404Sobrien	mips_optimize = 2;
11386179404Sobrien      break;
11387179404Sobrien
11388179404Sobrien    case 'g':
11389179404Sobrien      if (arg == NULL)
11390179404Sobrien	mips_debug = 2;
11391179404Sobrien      else
11392179404Sobrien	mips_debug = atoi (arg);
11393179404Sobrien      break;
11394179404Sobrien
11395179404Sobrien    case OPTION_MIPS1:
11396179404Sobrien      file_mips_isa = ISA_MIPS1;
11397179404Sobrien      break;
11398179404Sobrien
11399179404Sobrien    case OPTION_MIPS2:
11400179404Sobrien      file_mips_isa = ISA_MIPS2;
11401179404Sobrien      break;
11402179404Sobrien
11403179404Sobrien    case OPTION_MIPS3:
11404179404Sobrien      file_mips_isa = ISA_MIPS3;
11405179404Sobrien      break;
11406179404Sobrien
11407179404Sobrien    case OPTION_MIPS4:
11408179404Sobrien      file_mips_isa = ISA_MIPS4;
11409179404Sobrien      break;
11410179404Sobrien
11411179404Sobrien    case OPTION_MIPS5:
11412179404Sobrien      file_mips_isa = ISA_MIPS5;
11413179404Sobrien      break;
11414179404Sobrien
11415179404Sobrien    case OPTION_MIPS32:
11416179404Sobrien      file_mips_isa = ISA_MIPS32;
11417179404Sobrien      break;
11418179404Sobrien
11419179404Sobrien    case OPTION_MIPS32R2:
11420179404Sobrien      file_mips_isa = ISA_MIPS32R2;
11421179404Sobrien      break;
11422179404Sobrien
11423179404Sobrien    case OPTION_MIPS64R2:
11424179404Sobrien      file_mips_isa = ISA_MIPS64R2;
11425179404Sobrien      break;
11426179404Sobrien
11427179404Sobrien    case OPTION_MIPS64:
11428179404Sobrien      file_mips_isa = ISA_MIPS64;
11429179404Sobrien      break;
11430179404Sobrien
11431179404Sobrien    case OPTION_MTUNE:
11432179404Sobrien      mips_set_option_string (&mips_tune_string, arg);
11433179404Sobrien      break;
11434179404Sobrien
11435179404Sobrien    case OPTION_MARCH:
11436179404Sobrien      mips_set_option_string (&mips_arch_string, arg);
11437179404Sobrien      break;
11438179404Sobrien
11439179404Sobrien    case OPTION_M4650:
11440179404Sobrien      mips_set_option_string (&mips_arch_string, "4650");
11441179404Sobrien      mips_set_option_string (&mips_tune_string, "4650");
11442179404Sobrien      break;
11443179404Sobrien
11444179404Sobrien    case OPTION_NO_M4650:
11445179404Sobrien      break;
11446179404Sobrien
11447179404Sobrien    case OPTION_M4010:
11448179404Sobrien      mips_set_option_string (&mips_arch_string, "4010");
11449179404Sobrien      mips_set_option_string (&mips_tune_string, "4010");
11450179404Sobrien      break;
11451179404Sobrien
11452179404Sobrien    case OPTION_NO_M4010:
11453179404Sobrien      break;
11454179404Sobrien
11455179404Sobrien    case OPTION_M4100:
11456179404Sobrien      mips_set_option_string (&mips_arch_string, "4100");
11457179404Sobrien      mips_set_option_string (&mips_tune_string, "4100");
11458179404Sobrien      break;
11459179404Sobrien
11460179404Sobrien    case OPTION_NO_M4100:
11461179404Sobrien      break;
11462179404Sobrien
11463179404Sobrien    case OPTION_M3900:
11464179404Sobrien      mips_set_option_string (&mips_arch_string, "3900");
11465179404Sobrien      mips_set_option_string (&mips_tune_string, "3900");
11466179404Sobrien      break;
11467179404Sobrien
11468179404Sobrien    case OPTION_NO_M3900:
11469179404Sobrien      break;
11470179404Sobrien
11471179404Sobrien    case OPTION_MDMX:
11472179404Sobrien      mips_opts.ase_mdmx = 1;
11473179404Sobrien      break;
11474179404Sobrien
11475179404Sobrien    case OPTION_NO_MDMX:
11476179404Sobrien      mips_opts.ase_mdmx = 0;
11477179404Sobrien      break;
11478179404Sobrien
11479208737Sjmallett    case OPTION_DSP:
11480208737Sjmallett      mips_opts.ase_dsp = 1;
11481218822Sdim      mips_opts.ase_dspr2 = 0;
11482208737Sjmallett      break;
11483208737Sjmallett
11484208737Sjmallett    case OPTION_NO_DSP:
11485208737Sjmallett      mips_opts.ase_dsp = 0;
11486218822Sdim      mips_opts.ase_dspr2 = 0;
11487208737Sjmallett      break;
11488208737Sjmallett
11489218822Sdim    case OPTION_DSPR2:
11490218822Sdim      mips_opts.ase_dspr2 = 1;
11491218822Sdim      mips_opts.ase_dsp = 1;
11492218822Sdim      break;
11493218822Sdim
11494218822Sdim    case OPTION_NO_DSPR2:
11495218822Sdim      mips_opts.ase_dspr2 = 0;
11496218822Sdim      mips_opts.ase_dsp = 0;
11497218822Sdim      break;
11498218822Sdim
11499208737Sjmallett    case OPTION_MT:
11500208737Sjmallett      mips_opts.ase_mt = 1;
11501208737Sjmallett      break;
11502208737Sjmallett
11503208737Sjmallett    case OPTION_NO_MT:
11504208737Sjmallett      mips_opts.ase_mt = 0;
11505208737Sjmallett      break;
11506208737Sjmallett
11507179404Sobrien    case OPTION_MIPS16:
11508179404Sobrien      mips_opts.mips16 = 1;
11509208737Sjmallett      mips_no_prev_insn ();
11510179404Sobrien      break;
11511179404Sobrien
11512179404Sobrien    case OPTION_NO_MIPS16:
11513179404Sobrien      mips_opts.mips16 = 0;
11514208737Sjmallett      mips_no_prev_insn ();
11515179404Sobrien      break;
11516179404Sobrien
11517179404Sobrien    case OPTION_MIPS3D:
11518179404Sobrien      mips_opts.ase_mips3d = 1;
11519179404Sobrien      break;
11520179404Sobrien
11521179404Sobrien    case OPTION_NO_MIPS3D:
11522179404Sobrien      mips_opts.ase_mips3d = 0;
11523179404Sobrien      break;
11524179404Sobrien
11525218822Sdim    case OPTION_SMARTMIPS:
11526218822Sdim      mips_opts.ase_smartmips = 1;
11527218822Sdim      break;
11528218822Sdim
11529218822Sdim    case OPTION_NO_SMARTMIPS:
11530218822Sdim      mips_opts.ase_smartmips = 0;
11531218822Sdim      break;
11532218822Sdim
11533179404Sobrien    case OPTION_FIX_VR4120:
11534179404Sobrien      mips_fix_vr4120 = 1;
11535179404Sobrien      break;
11536179404Sobrien
11537179404Sobrien    case OPTION_NO_FIX_VR4120:
11538179404Sobrien      mips_fix_vr4120 = 0;
11539179404Sobrien      break;
11540179404Sobrien
11541208737Sjmallett    case OPTION_FIX_VR4130:
11542208737Sjmallett      mips_fix_vr4130 = 1;
11543208737Sjmallett      break;
11544208737Sjmallett
11545208737Sjmallett    case OPTION_NO_FIX_VR4130:
11546208737Sjmallett      mips_fix_vr4130 = 0;
11547208737Sjmallett      break;
11548208737Sjmallett
11549179404Sobrien    case OPTION_RELAX_BRANCH:
11550179404Sobrien      mips_relax_branch = 1;
11551179404Sobrien      break;
11552179404Sobrien
11553179404Sobrien    case OPTION_NO_RELAX_BRANCH:
11554179404Sobrien      mips_relax_branch = 0;
11555179404Sobrien      break;
11556179404Sobrien
11557208737Sjmallett    case OPTION_MSHARED:
11558208737Sjmallett      mips_in_shared = TRUE;
11559208737Sjmallett      break;
11560208737Sjmallett
11561208737Sjmallett    case OPTION_MNO_SHARED:
11562208737Sjmallett      mips_in_shared = FALSE;
11563208737Sjmallett      break;
11564208737Sjmallett
11565208737Sjmallett    case OPTION_MSYM32:
11566208737Sjmallett      mips_opts.sym32 = TRUE;
11567208737Sjmallett      break;
11568208737Sjmallett
11569208737Sjmallett    case OPTION_MNO_SYM32:
11570208737Sjmallett      mips_opts.sym32 = FALSE;
11571208737Sjmallett      break;
11572208737Sjmallett
11573179404Sobrien#ifdef OBJ_ELF
11574179404Sobrien      /* When generating ELF code, we permit -KPIC and -call_shared to
11575179404Sobrien	 select SVR4_PIC, and -non_shared to select no PIC.  This is
11576179404Sobrien	 intended to be compatible with Irix 5.  */
11577179404Sobrien    case OPTION_CALL_SHARED:
11578218822Sdim      if (!IS_ELF)
11579179404Sobrien	{
11580179404Sobrien	  as_bad (_("-call_shared is supported only for ELF format"));
11581179404Sobrien	  return 0;
11582179404Sobrien	}
11583179404Sobrien      mips_pic = SVR4_PIC;
11584179404Sobrien      mips_abicalls = TRUE;
11585179404Sobrien      break;
11586179404Sobrien
11587179404Sobrien    case OPTION_NON_SHARED:
11588218822Sdim      if (!IS_ELF)
11589179404Sobrien	{
11590179404Sobrien	  as_bad (_("-non_shared is supported only for ELF format"));
11591179404Sobrien	  return 0;
11592179404Sobrien	}
11593179404Sobrien      mips_pic = NO_PIC;
11594179404Sobrien      mips_abicalls = FALSE;
11595179404Sobrien      break;
11596179404Sobrien
11597208737Sjmallett      /* The -xgot option tells the assembler to use 32 bit offsets
11598208737Sjmallett         when accessing the got in SVR4_PIC mode.  It is for Irix
11599179404Sobrien         compatibility.  */
11600179404Sobrien    case OPTION_XGOT:
11601179404Sobrien      mips_big_got = 1;
11602179404Sobrien      break;
11603179404Sobrien#endif /* OBJ_ELF */
11604179404Sobrien
11605179404Sobrien    case 'G':
11606208737Sjmallett      g_switch_value = atoi (arg);
11607179404Sobrien      g_switch_seen = 1;
11608179404Sobrien      break;
11609179404Sobrien
11610179404Sobrien#ifdef OBJ_ELF
11611179404Sobrien      /* The -32, -n32 and -64 options are shortcuts for -mabi=32, -mabi=n32
11612179404Sobrien	 and -mabi=64.  */
11613179404Sobrien    case OPTION_32:
11614218822Sdim      if (!IS_ELF)
11615179404Sobrien	{
11616179404Sobrien	  as_bad (_("-32 is supported for ELF format only"));
11617179404Sobrien	  return 0;
11618179404Sobrien	}
11619179404Sobrien      mips_abi = O32_ABI;
11620179404Sobrien      break;
11621179404Sobrien
11622179404Sobrien    case OPTION_N32:
11623218822Sdim      if (!IS_ELF)
11624179404Sobrien	{
11625179404Sobrien	  as_bad (_("-n32 is supported for ELF format only"));
11626179404Sobrien	  return 0;
11627179404Sobrien	}
11628179404Sobrien      mips_abi = N32_ABI;
11629179404Sobrien      break;
11630179404Sobrien
11631179404Sobrien    case OPTION_64:
11632218822Sdim      if (!IS_ELF)
11633179404Sobrien	{
11634179404Sobrien	  as_bad (_("-64 is supported for ELF format only"));
11635179404Sobrien	  return 0;
11636179404Sobrien	}
11637179404Sobrien      mips_abi = N64_ABI;
11638218822Sdim      if (!support_64bit_objects())
11639179404Sobrien	as_fatal (_("No compiled in support for 64 bit object file format"));
11640179404Sobrien      break;
11641179404Sobrien#endif /* OBJ_ELF */
11642179404Sobrien
11643179404Sobrien    case OPTION_GP32:
11644179404Sobrien      file_mips_gp32 = 1;
11645179404Sobrien      break;
11646179404Sobrien
11647179404Sobrien    case OPTION_GP64:
11648179404Sobrien      file_mips_gp32 = 0;
11649179404Sobrien      break;
11650179404Sobrien
11651179404Sobrien    case OPTION_FP32:
11652179404Sobrien      file_mips_fp32 = 1;
11653179404Sobrien      break;
11654179404Sobrien
11655179404Sobrien    case OPTION_FP64:
11656179404Sobrien      file_mips_fp32 = 0;
11657179404Sobrien      break;
11658179404Sobrien
11659179404Sobrien#ifdef OBJ_ELF
11660179404Sobrien    case OPTION_MABI:
11661218822Sdim      if (!IS_ELF)
11662179404Sobrien	{
11663179404Sobrien	  as_bad (_("-mabi is supported for ELF format only"));
11664179404Sobrien	  return 0;
11665179404Sobrien	}
11666179404Sobrien      if (strcmp (arg, "32") == 0)
11667179404Sobrien	mips_abi = O32_ABI;
11668179404Sobrien      else if (strcmp (arg, "o64") == 0)
11669179404Sobrien	mips_abi = O64_ABI;
11670179404Sobrien      else if (strcmp (arg, "n32") == 0)
11671179404Sobrien	mips_abi = N32_ABI;
11672179404Sobrien      else if (strcmp (arg, "64") == 0)
11673179404Sobrien	{
11674179404Sobrien	  mips_abi = N64_ABI;
11675179404Sobrien	  if (! support_64bit_objects())
11676179404Sobrien	    as_fatal (_("No compiled in support for 64 bit object file "
11677179404Sobrien			"format"));
11678179404Sobrien	}
11679179404Sobrien      else if (strcmp (arg, "eabi") == 0)
11680179404Sobrien	mips_abi = EABI_ABI;
11681179404Sobrien      else
11682179404Sobrien	{
11683179404Sobrien	  as_fatal (_("invalid abi -mabi=%s"), arg);
11684179404Sobrien	  return 0;
11685179404Sobrien	}
11686179404Sobrien      break;
11687179404Sobrien#endif /* OBJ_ELF */
11688179404Sobrien
11689179404Sobrien    case OPTION_M7000_HILO_FIX:
11690179404Sobrien      mips_7000_hilo_fix = TRUE;
11691179404Sobrien      break;
11692179404Sobrien
11693179404Sobrien    case OPTION_MNO_7000_HILO_FIX:
11694179404Sobrien      mips_7000_hilo_fix = FALSE;
11695179404Sobrien      break;
11696179404Sobrien
11697179404Sobrien#ifdef OBJ_ELF
11698179404Sobrien    case OPTION_MDEBUG:
11699179404Sobrien      mips_flag_mdebug = TRUE;
11700179404Sobrien      break;
11701179404Sobrien
11702179404Sobrien    case OPTION_NO_MDEBUG:
11703179404Sobrien      mips_flag_mdebug = FALSE;
11704179404Sobrien      break;
11705179404Sobrien
11706179404Sobrien    case OPTION_PDR:
11707179404Sobrien      mips_flag_pdr = TRUE;
11708179404Sobrien      break;
11709179404Sobrien
11710179404Sobrien    case OPTION_NO_PDR:
11711179404Sobrien      mips_flag_pdr = FALSE;
11712179404Sobrien      break;
11713218822Sdim
11714218822Sdim    case OPTION_MVXWORKS_PIC:
11715218822Sdim      mips_pic = VXWORKS_PIC;
11716218822Sdim      break;
11717179404Sobrien#endif /* OBJ_ELF */
11718179404Sobrien
11719179404Sobrien    default:
11720179404Sobrien      return 0;
11721179404Sobrien    }
11722179404Sobrien
11723179404Sobrien  return 1;
11724179404Sobrien}
11725179404Sobrien
11726179404Sobrien/* Set up globals to generate code for the ISA or processor
11727179404Sobrien   described by INFO.  */
11728179404Sobrien
11729179404Sobrienstatic void
11730179404Sobrienmips_set_architecture (const struct mips_cpu_info *info)
11731179404Sobrien{
11732179404Sobrien  if (info != 0)
11733179404Sobrien    {
11734179404Sobrien      file_mips_arch = info->cpu;
11735179404Sobrien      mips_opts.arch = info->cpu;
11736179404Sobrien      mips_opts.isa = info->isa;
11737179404Sobrien    }
11738179404Sobrien}
11739179404Sobrien
11740179404Sobrien
11741179404Sobrien/* Likewise for tuning.  */
11742179404Sobrien
11743179404Sobrienstatic void
11744179404Sobrienmips_set_tune (const struct mips_cpu_info *info)
11745179404Sobrien{
11746179404Sobrien  if (info != 0)
11747179404Sobrien    mips_tune = info->cpu;
11748179404Sobrien}
11749179404Sobrien
11750179404Sobrien
11751179404Sobrienvoid
11752179404Sobrienmips_after_parse_args (void)
11753179404Sobrien{
11754179404Sobrien  const struct mips_cpu_info *arch_info = 0;
11755179404Sobrien  const struct mips_cpu_info *tune_info = 0;
11756179404Sobrien
11757179404Sobrien  /* GP relative stuff not working for PE */
11758208737Sjmallett  if (strncmp (TARGET_OS, "pe", 2) == 0)
11759179404Sobrien    {
11760208737Sjmallett      if (g_switch_seen && g_switch_value != 0)
11761179404Sobrien	as_bad (_("-G not supported in this configuration."));
11762179404Sobrien      g_switch_value = 0;
11763179404Sobrien    }
11764179404Sobrien
11765179404Sobrien  if (mips_abi == NO_ABI)
11766179404Sobrien    mips_abi = MIPS_DEFAULT_ABI;
11767179404Sobrien
11768179404Sobrien  /* The following code determines the architecture and register size.
11769179404Sobrien     Similar code was added to GCC 3.3 (see override_options() in
11770179404Sobrien     config/mips/mips.c).  The GAS and GCC code should be kept in sync
11771179404Sobrien     as much as possible.  */
11772179404Sobrien
11773179404Sobrien  if (mips_arch_string != 0)
11774179404Sobrien    arch_info = mips_parse_cpu ("-march", mips_arch_string);
11775179404Sobrien
11776179404Sobrien  if (file_mips_isa != ISA_UNKNOWN)
11777179404Sobrien    {
11778179404Sobrien      /* Handle -mipsN.  At this point, file_mips_isa contains the
11779179404Sobrien	 ISA level specified by -mipsN, while arch_info->isa contains
11780179404Sobrien	 the -march selection (if any).  */
11781179404Sobrien      if (arch_info != 0)
11782179404Sobrien	{
11783179404Sobrien	  /* -march takes precedence over -mipsN, since it is more descriptive.
11784179404Sobrien	     There's no harm in specifying both as long as the ISA levels
11785179404Sobrien	     are the same.  */
11786179404Sobrien	  if (file_mips_isa != arch_info->isa)
11787179404Sobrien	    as_bad (_("-%s conflicts with the other architecture options, which imply -%s"),
11788179404Sobrien		    mips_cpu_info_from_isa (file_mips_isa)->name,
11789179404Sobrien		    mips_cpu_info_from_isa (arch_info->isa)->name);
11790179404Sobrien	}
11791179404Sobrien      else
11792179404Sobrien	arch_info = mips_cpu_info_from_isa (file_mips_isa);
11793179404Sobrien    }
11794179404Sobrien
11795179404Sobrien  if (arch_info == 0)
11796179404Sobrien    arch_info = mips_parse_cpu ("default CPU", MIPS_CPU_STRING_DEFAULT);
11797179404Sobrien
11798179404Sobrien  if (ABI_NEEDS_64BIT_REGS (mips_abi) && !ISA_HAS_64BIT_REGS (arch_info->isa))
11799179404Sobrien    as_bad ("-march=%s is not compatible with the selected ABI",
11800179404Sobrien	    arch_info->name);
11801179404Sobrien
11802179404Sobrien  mips_set_architecture (arch_info);
11803179404Sobrien
11804179404Sobrien  /* Optimize for file_mips_arch, unless -mtune selects a different processor.  */
11805179404Sobrien  if (mips_tune_string != 0)
11806179404Sobrien    tune_info = mips_parse_cpu ("-mtune", mips_tune_string);
11807179404Sobrien
11808179404Sobrien  if (tune_info == 0)
11809179404Sobrien    mips_set_tune (arch_info);
11810179404Sobrien  else
11811179404Sobrien    mips_set_tune (tune_info);
11812179404Sobrien
11813179404Sobrien  if (file_mips_gp32 >= 0)
11814179404Sobrien    {
11815179404Sobrien      /* The user specified the size of the integer registers.  Make sure
11816179404Sobrien	 it agrees with the ABI and ISA.  */
11817179404Sobrien      if (file_mips_gp32 == 0 && !ISA_HAS_64BIT_REGS (mips_opts.isa))
11818179404Sobrien	as_bad (_("-mgp64 used with a 32-bit processor"));
11819179404Sobrien      else if (file_mips_gp32 == 1 && ABI_NEEDS_64BIT_REGS (mips_abi))
11820179404Sobrien	as_bad (_("-mgp32 used with a 64-bit ABI"));
11821179404Sobrien      else if (file_mips_gp32 == 0 && ABI_NEEDS_32BIT_REGS (mips_abi))
11822179404Sobrien	as_bad (_("-mgp64 used with a 32-bit ABI"));
11823179404Sobrien    }
11824179404Sobrien  else
11825179404Sobrien    {
11826179404Sobrien      /* Infer the integer register size from the ABI and processor.
11827179404Sobrien	 Restrict ourselves to 32-bit registers if that's all the
11828179404Sobrien	 processor has, or if the ABI cannot handle 64-bit registers.  */
11829179404Sobrien      file_mips_gp32 = (ABI_NEEDS_32BIT_REGS (mips_abi)
11830179404Sobrien			|| !ISA_HAS_64BIT_REGS (mips_opts.isa));
11831179404Sobrien    }
11832179404Sobrien
11833218822Sdim  switch (file_mips_fp32)
11834218822Sdim    {
11835218822Sdim    default:
11836218822Sdim    case -1:
11837218822Sdim      /* No user specified float register size.
11838218822Sdim	 ??? GAS treats single-float processors as though they had 64-bit
11839218822Sdim	 float registers (although it complains when double-precision
11840218822Sdim	 instructions are used).  As things stand, saying they have 32-bit
11841218822Sdim	 registers would lead to spurious "register must be even" messages.
11842218822Sdim	 So here we assume float registers are never smaller than the
11843218822Sdim	 integer ones.  */
11844218822Sdim      if (file_mips_gp32 == 0)
11845218822Sdim	/* 64-bit integer registers implies 64-bit float registers.  */
11846218822Sdim	file_mips_fp32 = 0;
11847218822Sdim      else if ((mips_opts.ase_mips3d > 0 || mips_opts.ase_mdmx > 0)
11848218822Sdim	       && ISA_HAS_64BIT_FPRS (mips_opts.isa))
11849218822Sdim	/* -mips3d and -mdmx imply 64-bit float registers, if possible.  */
11850218822Sdim	file_mips_fp32 = 0;
11851218822Sdim      else
11852218822Sdim	/* 32-bit float registers.  */
11853218822Sdim	file_mips_fp32 = 1;
11854218822Sdim      break;
11855179404Sobrien
11856218822Sdim    /* The user specified the size of the float registers.  Check if it
11857218822Sdim       agrees with the ABI and ISA.  */
11858218822Sdim    case 0:
11859218822Sdim      if (!ISA_HAS_64BIT_FPRS (mips_opts.isa))
11860218822Sdim	as_bad (_("-mfp64 used with a 32-bit fpu"));
11861218822Sdim      else if (ABI_NEEDS_32BIT_REGS (mips_abi)
11862218822Sdim	       && !ISA_HAS_MXHC1 (mips_opts.isa))
11863218822Sdim	as_warn (_("-mfp64 used with a 32-bit ABI"));
11864218822Sdim      break;
11865218822Sdim    case 1:
11866218822Sdim      if (ABI_NEEDS_64BIT_REGS (mips_abi))
11867218822Sdim	as_warn (_("-mfp32 used with a 64-bit ABI"));
11868218822Sdim      break;
11869218822Sdim    }
11870218822Sdim
11871179404Sobrien  /* End of GCC-shared inference code.  */
11872179404Sobrien
11873179404Sobrien  /* This flag is set when we have a 64-bit capable CPU but use only
11874179404Sobrien     32-bit wide registers.  Note that EABI does not use it.  */
11875179404Sobrien  if (ISA_HAS_64BIT_REGS (mips_opts.isa)
11876179404Sobrien      && ((mips_abi == NO_ABI && file_mips_gp32 == 1)
11877179404Sobrien	  || mips_abi == O32_ABI))
11878179404Sobrien    mips_32bitmode = 1;
11879179404Sobrien
11880179404Sobrien  if (mips_opts.isa == ISA_MIPS1 && mips_trap)
11881179404Sobrien    as_bad (_("trap exception not supported at ISA 1"));
11882179404Sobrien
11883179404Sobrien  /* If the selected architecture includes support for ASEs, enable
11884179404Sobrien     generation of code for them.  */
11885179404Sobrien  if (mips_opts.mips16 == -1)
11886179404Sobrien    mips_opts.mips16 = (CPU_HAS_MIPS16 (file_mips_arch)) ? 1 : 0;
11887179404Sobrien  if (mips_opts.ase_mips3d == -1)
11888218822Sdim    mips_opts.ase_mips3d = ((arch_info->flags & MIPS_CPU_ASE_MIPS3D)
11889218822Sdim			    && file_mips_fp32 == 0) ? 1 : 0;
11890218822Sdim  if (mips_opts.ase_mips3d && file_mips_fp32 == 1)
11891218822Sdim    as_bad (_("-mfp32 used with -mips3d"));
11892218822Sdim
11893179404Sobrien  if (mips_opts.ase_mdmx == -1)
11894218822Sdim    mips_opts.ase_mdmx = ((arch_info->flags & MIPS_CPU_ASE_MDMX)
11895218822Sdim			  && file_mips_fp32 == 0) ? 1 : 0;
11896218822Sdim  if (mips_opts.ase_mdmx && file_mips_fp32 == 1)
11897218822Sdim    as_bad (_("-mfp32 used with -mdmx"));
11898218822Sdim
11899218822Sdim  if (mips_opts.ase_smartmips == -1)
11900218822Sdim    mips_opts.ase_smartmips = (arch_info->flags & MIPS_CPU_ASE_SMARTMIPS) ? 1 : 0;
11901218822Sdim  if (mips_opts.ase_smartmips && !ISA_SUPPORTS_SMARTMIPS)
11902218822Sdim      as_warn ("%s ISA does not support SmartMIPS",
11903218822Sdim	       mips_cpu_info_from_isa (mips_opts.isa)->name);
11904218822Sdim
11905208737Sjmallett  if (mips_opts.ase_dsp == -1)
11906218822Sdim    mips_opts.ase_dsp = (arch_info->flags & MIPS_CPU_ASE_DSP) ? 1 : 0;
11907218822Sdim  if (mips_opts.ase_dsp && !ISA_SUPPORTS_DSP_ASE)
11908218822Sdim      as_warn ("%s ISA does not support DSP ASE",
11909218822Sdim	       mips_cpu_info_from_isa (mips_opts.isa)->name);
11910218822Sdim
11911218822Sdim  if (mips_opts.ase_dspr2 == -1)
11912218822Sdim    {
11913218822Sdim      mips_opts.ase_dspr2 = (arch_info->flags & MIPS_CPU_ASE_DSPR2) ? 1 : 0;
11914218822Sdim      mips_opts.ase_dsp = (arch_info->flags & MIPS_CPU_ASE_DSP) ? 1 : 0;
11915218822Sdim    }
11916218822Sdim  if (mips_opts.ase_dspr2 && !ISA_SUPPORTS_DSPR2_ASE)
11917218822Sdim      as_warn ("%s ISA does not support DSP R2 ASE",
11918218822Sdim	       mips_cpu_info_from_isa (mips_opts.isa)->name);
11919218822Sdim
11920208737Sjmallett  if (mips_opts.ase_mt == -1)
11921218822Sdim    mips_opts.ase_mt = (arch_info->flags & MIPS_CPU_ASE_MT) ? 1 : 0;
11922218822Sdim  if (mips_opts.ase_mt && !ISA_SUPPORTS_MT_ASE)
11923218822Sdim      as_warn ("%s ISA does not support MT ASE",
11924218822Sdim	       mips_cpu_info_from_isa (mips_opts.isa)->name);
11925179404Sobrien
11926179404Sobrien  file_mips_isa = mips_opts.isa;
11927179404Sobrien  file_ase_mips16 = mips_opts.mips16;
11928179404Sobrien  file_ase_mips3d = mips_opts.ase_mips3d;
11929179404Sobrien  file_ase_mdmx = mips_opts.ase_mdmx;
11930218822Sdim  file_ase_smartmips = mips_opts.ase_smartmips;
11931208737Sjmallett  file_ase_dsp = mips_opts.ase_dsp;
11932218822Sdim  file_ase_dspr2 = mips_opts.ase_dspr2;
11933208737Sjmallett  file_ase_mt = mips_opts.ase_mt;
11934179404Sobrien  mips_opts.gp32 = file_mips_gp32;
11935179404Sobrien  mips_opts.fp32 = file_mips_fp32;
11936179404Sobrien
11937179404Sobrien  if (mips_flag_mdebug < 0)
11938179404Sobrien    {
11939179404Sobrien#ifdef OBJ_MAYBE_ECOFF
11940179404Sobrien      if (OUTPUT_FLAVOR == bfd_target_ecoff_flavour)
11941179404Sobrien	mips_flag_mdebug = 1;
11942179404Sobrien      else
11943179404Sobrien#endif /* OBJ_MAYBE_ECOFF */
11944179404Sobrien	mips_flag_mdebug = 0;
11945179404Sobrien    }
11946179404Sobrien}
11947179404Sobrien
11948179404Sobrienvoid
11949179404Sobrienmips_init_after_args (void)
11950179404Sobrien{
11951179404Sobrien  /* initialize opcodes */
11952179404Sobrien  bfd_mips_num_opcodes = bfd_mips_num_builtin_opcodes;
11953179404Sobrien  mips_opcodes = (struct mips_opcode *) mips_builtin_opcodes;
11954179404Sobrien}
11955179404Sobrien
11956179404Sobrienlong
11957179404Sobrienmd_pcrel_from (fixS *fixP)
11958179404Sobrien{
11959179404Sobrien  valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
11960179404Sobrien  switch (fixP->fx_r_type)
11961179404Sobrien    {
11962179404Sobrien    case BFD_RELOC_16_PCREL_S2:
11963179404Sobrien    case BFD_RELOC_MIPS_JMP:
11964179404Sobrien      /* Return the address of the delay slot.  */
11965179404Sobrien      return addr + 4;
11966179404Sobrien    default:
11967218822Sdim      /* We have no relocation type for PC relative MIPS16 instructions.  */
11968218822Sdim      if (fixP->fx_addsy && S_GET_SEGMENT (fixP->fx_addsy) != now_seg)
11969218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
11970218822Sdim		      _("PC relative MIPS16 instruction references a different section"));
11971179404Sobrien      return addr;
11972179404Sobrien    }
11973179404Sobrien}
11974179404Sobrien
11975179404Sobrien/* This is called before the symbol table is processed.  In order to
11976179404Sobrien   work with gcc when using mips-tfile, we must keep all local labels.
11977179404Sobrien   However, in other cases, we want to discard them.  If we were
11978179404Sobrien   called with -g, but we didn't see any debugging information, it may
11979179404Sobrien   mean that gcc is smuggling debugging information through to
11980179404Sobrien   mips-tfile, in which case we must generate all local labels.  */
11981179404Sobrien
11982179404Sobrienvoid
11983179404Sobrienmips_frob_file_before_adjust (void)
11984179404Sobrien{
11985179404Sobrien#ifndef NO_ECOFF_DEBUGGING
11986179404Sobrien  if (ECOFF_DEBUGGING
11987179404Sobrien      && mips_debug != 0
11988179404Sobrien      && ! ecoff_debugging_seen)
11989179404Sobrien    flag_keep_locals = 1;
11990179404Sobrien#endif
11991179404Sobrien}
11992179404Sobrien
11993208737Sjmallett/* Sort any unmatched HI16 and GOT16 relocs so that they immediately precede
11994218822Sdim   the corresponding LO16 reloc.  This is called before md_apply_fix and
11995208737Sjmallett   tc_gen_reloc.  Unmatched relocs can only be generated by use of explicit
11996208737Sjmallett   relocation operators.
11997179404Sobrien
11998208737Sjmallett   For our purposes, a %lo() expression matches a %got() or %hi()
11999208737Sjmallett   expression if:
12000208737Sjmallett
12001208737Sjmallett      (a) it refers to the same symbol; and
12002208737Sjmallett      (b) the offset applied in the %lo() expression is no lower than
12003208737Sjmallett	  the offset applied in the %got() or %hi().
12004208737Sjmallett
12005208737Sjmallett   (b) allows us to cope with code like:
12006208737Sjmallett
12007208737Sjmallett	lui	$4,%hi(foo)
12008208737Sjmallett	lh	$4,%lo(foo+2)($4)
12009208737Sjmallett
12010208737Sjmallett   ...which is legal on RELA targets, and has a well-defined behaviour
12011208737Sjmallett   if the user knows that adding 2 to "foo" will not induce a carry to
12012208737Sjmallett   the high 16 bits.
12013208737Sjmallett
12014208737Sjmallett   When several %lo()s match a particular %got() or %hi(), we use the
12015208737Sjmallett   following rules to distinguish them:
12016208737Sjmallett
12017208737Sjmallett     (1) %lo()s with smaller offsets are a better match than %lo()s with
12018208737Sjmallett         higher offsets.
12019208737Sjmallett
12020208737Sjmallett     (2) %lo()s with no matching %got() or %hi() are better than those
12021208737Sjmallett         that already have a matching %got() or %hi().
12022208737Sjmallett
12023208737Sjmallett     (3) later %lo()s are better than earlier %lo()s.
12024208737Sjmallett
12025208737Sjmallett   These rules are applied in order.
12026208737Sjmallett
12027208737Sjmallett   (1) means, among other things, that %lo()s with identical offsets are
12028208737Sjmallett   chosen if they exist.
12029208737Sjmallett
12030208737Sjmallett   (2) means that we won't associate several high-part relocations with
12031208737Sjmallett   the same low-part relocation unless there's no alternative.  Having
12032208737Sjmallett   several high parts for the same low part is a GNU extension; this rule
12033208737Sjmallett   allows careful users to avoid it.
12034208737Sjmallett
12035208737Sjmallett   (3) is purely cosmetic.  mips_hi_fixup_list is is in reverse order,
12036208737Sjmallett   with the last high-part relocation being at the front of the list.
12037208737Sjmallett   It therefore makes sense to choose the last matching low-part
12038208737Sjmallett   relocation, all other things being equal.  It's also easier
12039208737Sjmallett   to code that way.  */
12040208737Sjmallett
12041179404Sobrienvoid
12042179404Sobrienmips_frob_file (void)
12043179404Sobrien{
12044179404Sobrien  struct mips_hi_fixup *l;
12045179404Sobrien
12046179404Sobrien  for (l = mips_hi_fixup_list; l != NULL; l = l->next)
12047179404Sobrien    {
12048179404Sobrien      segment_info_type *seginfo;
12049208737Sjmallett      bfd_boolean matched_lo_p;
12050208737Sjmallett      fixS **hi_pos, **lo_pos, **pos;
12051179404Sobrien
12052179404Sobrien      assert (reloc_needs_lo_p (l->fixp->fx_r_type));
12053179404Sobrien
12054179404Sobrien      /* If a GOT16 relocation turns out to be against a global symbol,
12055179404Sobrien	 there isn't supposed to be a matching LO.  */
12056179404Sobrien      if (l->fixp->fx_r_type == BFD_RELOC_MIPS_GOT16
12057179404Sobrien	  && !pic_need_relax (l->fixp->fx_addsy, l->seg))
12058179404Sobrien	continue;
12059179404Sobrien
12060179404Sobrien      /* Check quickly whether the next fixup happens to be a matching %lo.  */
12061179404Sobrien      if (fixup_has_matching_lo_p (l->fixp))
12062179404Sobrien	continue;
12063179404Sobrien
12064179404Sobrien      seginfo = seg_info (l->seg);
12065208737Sjmallett
12066208737Sjmallett      /* Set HI_POS to the position of this relocation in the chain.
12067208737Sjmallett	 Set LO_POS to the position of the chosen low-part relocation.
12068208737Sjmallett	 MATCHED_LO_P is true on entry to the loop if *POS is a low-part
12069208737Sjmallett	 relocation that matches an immediately-preceding high-part
12070208737Sjmallett	 relocation.  */
12071208737Sjmallett      hi_pos = NULL;
12072208737Sjmallett      lo_pos = NULL;
12073208737Sjmallett      matched_lo_p = FALSE;
12074208737Sjmallett      for (pos = &seginfo->fix_root; *pos != NULL; pos = &(*pos)->fx_next)
12075179404Sobrien	{
12076208737Sjmallett	  if (*pos == l->fixp)
12077208737Sjmallett	    hi_pos = pos;
12078179404Sobrien
12079218822Sdim	  if (((*pos)->fx_r_type == BFD_RELOC_LO16
12080218822Sdim	       || (*pos)->fx_r_type == BFD_RELOC_MIPS16_LO16)
12081208737Sjmallett	      && (*pos)->fx_addsy == l->fixp->fx_addsy
12082208737Sjmallett	      && (*pos)->fx_offset >= l->fixp->fx_offset
12083208737Sjmallett	      && (lo_pos == NULL
12084208737Sjmallett		  || (*pos)->fx_offset < (*lo_pos)->fx_offset
12085208737Sjmallett		  || (!matched_lo_p
12086208737Sjmallett		      && (*pos)->fx_offset == (*lo_pos)->fx_offset)))
12087208737Sjmallett	    lo_pos = pos;
12088179404Sobrien
12089208737Sjmallett	  matched_lo_p = (reloc_needs_lo_p ((*pos)->fx_r_type)
12090208737Sjmallett			  && fixup_has_matching_lo_p (*pos));
12091208737Sjmallett	}
12092179404Sobrien
12093208737Sjmallett      /* If we found a match, remove the high-part relocation from its
12094208737Sjmallett	 current position and insert it before the low-part relocation.
12095208737Sjmallett	 Make the offsets match so that fixup_has_matching_lo_p()
12096208737Sjmallett	 will return true.
12097179404Sobrien
12098208737Sjmallett	 We don't warn about unmatched high-part relocations since some
12099208737Sjmallett	 versions of gcc have been known to emit dead "lui ...%hi(...)"
12100208737Sjmallett	 instructions.  */
12101208737Sjmallett      if (lo_pos != NULL)
12102208737Sjmallett	{
12103208737Sjmallett	  l->fixp->fx_offset = (*lo_pos)->fx_offset;
12104208737Sjmallett	  if (l->fixp->fx_next != *lo_pos)
12105208737Sjmallett	    {
12106208737Sjmallett	      *hi_pos = l->fixp->fx_next;
12107208737Sjmallett	      l->fixp->fx_next = *lo_pos;
12108208737Sjmallett	      *lo_pos = l->fixp;
12109179404Sobrien	    }
12110179404Sobrien	}
12111179404Sobrien    }
12112179404Sobrien}
12113179404Sobrien
12114208737Sjmallett/* We may have combined relocations without symbols in the N32/N64 ABI.
12115179404Sobrien   We have to prevent gas from dropping them.  */
12116179404Sobrien
12117179404Sobrienint
12118179404Sobrienmips_force_relocation (fixS *fixp)
12119179404Sobrien{
12120179404Sobrien  if (generic_force_reloc (fixp))
12121179404Sobrien    return 1;
12122179404Sobrien
12123179404Sobrien  if (HAVE_NEWABI
12124179404Sobrien      && S_GET_SEGMENT (fixp->fx_addsy) == bfd_abs_section_ptr
12125179404Sobrien      && (fixp->fx_r_type == BFD_RELOC_MIPS_SUB
12126179404Sobrien	  || fixp->fx_r_type == BFD_RELOC_HI16_S
12127179404Sobrien	  || fixp->fx_r_type == BFD_RELOC_LO16))
12128179404Sobrien    return 1;
12129179404Sobrien
12130208737Sjmallett  return 0;
12131179404Sobrien}
12132179404Sobrien
12133179404Sobrien/* Apply a fixup to the object file.  */
12134179404Sobrien
12135179404Sobrienvoid
12136218822Sdimmd_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
12137179404Sobrien{
12138179404Sobrien  bfd_byte *buf;
12139179404Sobrien  long insn;
12140179404Sobrien  reloc_howto_type *howto;
12141179404Sobrien
12142179404Sobrien  /* We ignore generic BFD relocations we don't know about.  */
12143179404Sobrien  howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
12144179404Sobrien  if (! howto)
12145179404Sobrien    return;
12146179404Sobrien
12147179404Sobrien  assert (fixP->fx_size == 4
12148179404Sobrien	  || fixP->fx_r_type == BFD_RELOC_16
12149179404Sobrien	  || fixP->fx_r_type == BFD_RELOC_64
12150179404Sobrien	  || fixP->fx_r_type == BFD_RELOC_CTOR
12151179404Sobrien	  || fixP->fx_r_type == BFD_RELOC_MIPS_SUB
12152179404Sobrien	  || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
12153218822Sdim	  || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
12154218822Sdim	  || fixP->fx_r_type == BFD_RELOC_MIPS_TLS_DTPREL64);
12155179404Sobrien
12156179404Sobrien  buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where);
12157179404Sobrien
12158218822Sdim  assert (!fixP->fx_pcrel || fixP->fx_r_type == BFD_RELOC_16_PCREL_S2);
12159208737Sjmallett
12160208737Sjmallett  /* Don't treat parts of a composite relocation as done.  There are two
12161208737Sjmallett     reasons for this:
12162208737Sjmallett
12163208737Sjmallett     (1) The second and third parts will be against 0 (RSS_UNDEF) but
12164208737Sjmallett	 should nevertheless be emitted if the first part is.
12165208737Sjmallett
12166208737Sjmallett     (2) In normal usage, composite relocations are never assembly-time
12167208737Sjmallett	 constants.  The easiest way of dealing with the pathological
12168208737Sjmallett	 exceptions is to generate a relocation against STN_UNDEF and
12169208737Sjmallett	 leave everything up to the linker.  */
12170218822Sdim  if (fixP->fx_addsy == NULL && !fixP->fx_pcrel && fixP->fx_tcbit == 0)
12171179404Sobrien    fixP->fx_done = 1;
12172179404Sobrien
12173179404Sobrien  switch (fixP->fx_r_type)
12174179404Sobrien    {
12175218822Sdim    case BFD_RELOC_MIPS_TLS_GD:
12176218822Sdim    case BFD_RELOC_MIPS_TLS_LDM:
12177218822Sdim    case BFD_RELOC_MIPS_TLS_DTPREL32:
12178218822Sdim    case BFD_RELOC_MIPS_TLS_DTPREL64:
12179218822Sdim    case BFD_RELOC_MIPS_TLS_DTPREL_HI16:
12180218822Sdim    case BFD_RELOC_MIPS_TLS_DTPREL_LO16:
12181218822Sdim    case BFD_RELOC_MIPS_TLS_GOTTPREL:
12182218822Sdim    case BFD_RELOC_MIPS_TLS_TPREL_HI16:
12183218822Sdim    case BFD_RELOC_MIPS_TLS_TPREL_LO16:
12184218822Sdim      S_SET_THREAD_LOCAL (fixP->fx_addsy);
12185218822Sdim      /* fall through */
12186218822Sdim
12187179404Sobrien    case BFD_RELOC_MIPS_JMP:
12188179404Sobrien    case BFD_RELOC_MIPS_SHIFT5:
12189179404Sobrien    case BFD_RELOC_MIPS_SHIFT6:
12190179404Sobrien    case BFD_RELOC_MIPS_GOT_DISP:
12191179404Sobrien    case BFD_RELOC_MIPS_GOT_PAGE:
12192179404Sobrien    case BFD_RELOC_MIPS_GOT_OFST:
12193179404Sobrien    case BFD_RELOC_MIPS_SUB:
12194179404Sobrien    case BFD_RELOC_MIPS_INSERT_A:
12195179404Sobrien    case BFD_RELOC_MIPS_INSERT_B:
12196179404Sobrien    case BFD_RELOC_MIPS_DELETE:
12197179404Sobrien    case BFD_RELOC_MIPS_HIGHEST:
12198179404Sobrien    case BFD_RELOC_MIPS_HIGHER:
12199179404Sobrien    case BFD_RELOC_MIPS_SCN_DISP:
12200179404Sobrien    case BFD_RELOC_MIPS_REL16:
12201179404Sobrien    case BFD_RELOC_MIPS_RELGOT:
12202179404Sobrien    case BFD_RELOC_MIPS_JALR:
12203179404Sobrien    case BFD_RELOC_HI16:
12204179404Sobrien    case BFD_RELOC_HI16_S:
12205179404Sobrien    case BFD_RELOC_GPREL16:
12206179404Sobrien    case BFD_RELOC_MIPS_LITERAL:
12207179404Sobrien    case BFD_RELOC_MIPS_CALL16:
12208179404Sobrien    case BFD_RELOC_MIPS_GOT16:
12209179404Sobrien    case BFD_RELOC_GPREL32:
12210179404Sobrien    case BFD_RELOC_MIPS_GOT_HI16:
12211179404Sobrien    case BFD_RELOC_MIPS_GOT_LO16:
12212179404Sobrien    case BFD_RELOC_MIPS_CALL_HI16:
12213179404Sobrien    case BFD_RELOC_MIPS_CALL_LO16:
12214179404Sobrien    case BFD_RELOC_MIPS16_GPREL:
12215218822Sdim    case BFD_RELOC_MIPS16_HI16:
12216218822Sdim    case BFD_RELOC_MIPS16_HI16_S:
12217179404Sobrien    case BFD_RELOC_MIPS16_JMP:
12218218822Sdim      /* Nothing needed to do.  The value comes from the reloc entry.  */
12219179404Sobrien      break;
12220179404Sobrien
12221179404Sobrien    case BFD_RELOC_64:
12222179404Sobrien      /* This is handled like BFD_RELOC_32, but we output a sign
12223179404Sobrien         extended value if we are only 32 bits.  */
12224208737Sjmallett      if (fixP->fx_done)
12225179404Sobrien	{
12226179404Sobrien	  if (8 <= sizeof (valueT))
12227208737Sjmallett	    md_number_to_chars ((char *) buf, *valP, 8);
12228179404Sobrien	  else
12229179404Sobrien	    {
12230179404Sobrien	      valueT hiv;
12231179404Sobrien
12232179404Sobrien	      if ((*valP & 0x80000000) != 0)
12233179404Sobrien		hiv = 0xffffffff;
12234179404Sobrien	      else
12235179404Sobrien		hiv = 0;
12236208737Sjmallett	      md_number_to_chars ((char *)(buf + (target_big_endian ? 4 : 0)),
12237179404Sobrien				  *valP, 4);
12238208737Sjmallett	      md_number_to_chars ((char *)(buf + (target_big_endian ? 0 : 4)),
12239179404Sobrien				  hiv, 4);
12240179404Sobrien	    }
12241179404Sobrien	}
12242179404Sobrien      break;
12243179404Sobrien
12244179404Sobrien    case BFD_RELOC_RVA:
12245179404Sobrien    case BFD_RELOC_32:
12246218822Sdim    case BFD_RELOC_16:
12247179404Sobrien      /* If we are deleting this reloc entry, we must fill in the
12248179404Sobrien	 value now.  This can happen if we have a .word which is not
12249218822Sdim	 resolved when it appears but is later defined.  */
12250208737Sjmallett      if (fixP->fx_done)
12251218822Sdim	md_number_to_chars ((char *) buf, *valP, fixP->fx_size);
12252179404Sobrien      break;
12253179404Sobrien
12254179404Sobrien    case BFD_RELOC_LO16:
12255218822Sdim    case BFD_RELOC_MIPS16_LO16:
12256208737Sjmallett      /* FIXME: Now that embedded-PIC is gone, some of this code/comment
12257208737Sjmallett	 may be safe to remove, but if so it's not obvious.  */
12258179404Sobrien      /* When handling an embedded PIC switch statement, we can wind
12259179404Sobrien	 up deleting a LO16 reloc.  See the 'o' case in mips_ip.  */
12260179404Sobrien      if (fixP->fx_done)
12261179404Sobrien	{
12262179404Sobrien	  if (*valP + 0x8000 > 0xffff)
12263179404Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
12264179404Sobrien			  _("relocation overflow"));
12265179404Sobrien	  if (target_big_endian)
12266179404Sobrien	    buf += 2;
12267208737Sjmallett	  md_number_to_chars ((char *) buf, *valP, 2);
12268179404Sobrien	}
12269179404Sobrien      break;
12270179404Sobrien
12271179404Sobrien    case BFD_RELOC_16_PCREL_S2:
12272179404Sobrien      if ((*valP & 0x3) != 0)
12273179404Sobrien	as_bad_where (fixP->fx_file, fixP->fx_line,
12274208737Sjmallett		      _("Branch to misaligned address (%lx)"), (long) *valP);
12275179404Sobrien
12276218822Sdim      /* We need to save the bits in the instruction since fixup_segment()
12277218822Sdim	 might be deleting the relocation entry (i.e., a branch within
12278218822Sdim	 the current segment).  */
12279179404Sobrien      if (! fixP->fx_done)
12280179404Sobrien	break;
12281179404Sobrien
12282218822Sdim      /* Update old instruction data.  */
12283179404Sobrien      if (target_big_endian)
12284179404Sobrien	insn = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
12285179404Sobrien      else
12286179404Sobrien	insn = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
12287179404Sobrien
12288179404Sobrien      if (*valP + 0x20000 <= 0x3ffff)
12289179404Sobrien	{
12290179404Sobrien	  insn |= (*valP >> 2) & 0xffff;
12291208737Sjmallett	  md_number_to_chars ((char *) buf, insn, 4);
12292179404Sobrien	}
12293179404Sobrien      else if (mips_pic == NO_PIC
12294179404Sobrien	       && fixP->fx_done
12295179404Sobrien	       && fixP->fx_frag->fr_address >= text_section->vma
12296179404Sobrien	       && (fixP->fx_frag->fr_address
12297218822Sdim		   < text_section->vma + bfd_get_section_size (text_section))
12298179404Sobrien	       && ((insn & 0xffff0000) == 0x10000000	 /* beq $0,$0 */
12299179404Sobrien		   || (insn & 0xffff0000) == 0x04010000	 /* bgez $0 */
12300179404Sobrien		   || (insn & 0xffff0000) == 0x04110000)) /* bgezal $0 */
12301179404Sobrien	{
12302179404Sobrien	  /* The branch offset is too large.  If this is an
12303179404Sobrien             unconditional branch, and we are not generating PIC code,
12304179404Sobrien             we can convert it to an absolute jump instruction.  */
12305179404Sobrien	  if ((insn & 0xffff0000) == 0x04110000)	 /* bgezal $0 */
12306179404Sobrien	    insn = 0x0c000000;	/* jal */
12307179404Sobrien	  else
12308179404Sobrien	    insn = 0x08000000;	/* j */
12309179404Sobrien	  fixP->fx_r_type = BFD_RELOC_MIPS_JMP;
12310179404Sobrien	  fixP->fx_done = 0;
12311179404Sobrien	  fixP->fx_addsy = section_symbol (text_section);
12312179404Sobrien	  *valP += md_pcrel_from (fixP);
12313208737Sjmallett	  md_number_to_chars ((char *) buf, insn, 4);
12314179404Sobrien	}
12315179404Sobrien      else
12316179404Sobrien	{
12317179404Sobrien	  /* If we got here, we have branch-relaxation disabled,
12318179404Sobrien	     and there's nothing we can do to fix this instruction
12319179404Sobrien	     without turning it into a longer sequence.  */
12320179404Sobrien	  as_bad_where (fixP->fx_file, fixP->fx_line,
12321179404Sobrien			_("Branch out of range"));
12322179404Sobrien	}
12323179404Sobrien      break;
12324179404Sobrien
12325179404Sobrien    case BFD_RELOC_VTABLE_INHERIT:
12326179404Sobrien      fixP->fx_done = 0;
12327179404Sobrien      if (fixP->fx_addsy
12328179404Sobrien          && !S_IS_DEFINED (fixP->fx_addsy)
12329179404Sobrien          && !S_IS_WEAK (fixP->fx_addsy))
12330179404Sobrien        S_SET_WEAK (fixP->fx_addsy);
12331179404Sobrien      break;
12332179404Sobrien
12333179404Sobrien    case BFD_RELOC_VTABLE_ENTRY:
12334179404Sobrien      fixP->fx_done = 0;
12335179404Sobrien      break;
12336179404Sobrien
12337179404Sobrien    default:
12338179404Sobrien      internalError ();
12339179404Sobrien    }
12340179404Sobrien
12341179404Sobrien  /* Remember value for tc_gen_reloc.  */
12342179404Sobrien  fixP->fx_addnumber = *valP;
12343179404Sobrien}
12344179404Sobrien
12345179404Sobrienstatic symbolS *
12346179404Sobrienget_symbol (void)
12347179404Sobrien{
12348179404Sobrien  int c;
12349179404Sobrien  char *name;
12350179404Sobrien  symbolS *p;
12351179404Sobrien
12352179404Sobrien  name = input_line_pointer;
12353179404Sobrien  c = get_symbol_end ();
12354179404Sobrien  p = (symbolS *) symbol_find_or_make (name);
12355179404Sobrien  *input_line_pointer = c;
12356179404Sobrien  return p;
12357179404Sobrien}
12358179404Sobrien
12359179404Sobrien/* Align the current frag to a given power of two.  The MIPS assembler
12360179404Sobrien   also automatically adjusts any preceding label.  */
12361179404Sobrien
12362179404Sobrienstatic void
12363179404Sobrienmips_align (int to, int fill, symbolS *label)
12364179404Sobrien{
12365208737Sjmallett  mips_emit_delays ();
12366179404Sobrien  frag_align (to, fill, 0);
12367179404Sobrien  record_alignment (now_seg, to);
12368179404Sobrien  if (label != NULL)
12369179404Sobrien    {
12370179404Sobrien      assert (S_GET_SEGMENT (label) == now_seg);
12371179404Sobrien      symbol_set_frag (label, frag_now);
12372179404Sobrien      S_SET_VALUE (label, (valueT) frag_now_fix ());
12373179404Sobrien    }
12374179404Sobrien}
12375179404Sobrien
12376179404Sobrien/* Align to a given power of two.  .align 0 turns off the automatic
12377179404Sobrien   alignment used by the data creating pseudo-ops.  */
12378179404Sobrien
12379179404Sobrienstatic void
12380179404Sobriens_align (int x ATTRIBUTE_UNUSED)
12381179404Sobrien{
12382218822Sdim  int temp;
12383218822Sdim  long temp_fill;
12384179404Sobrien  long max_alignment = 15;
12385179404Sobrien
12386218822Sdim  /* o Note that the assembler pulls down any immediately preceding label
12387179404Sobrien       to the aligned address.
12388218822Sdim     o It's not documented but auto alignment is reinstated by
12389179404Sobrien       a .align pseudo instruction.
12390218822Sdim     o Note also that after auto alignment is turned off the mips assembler
12391179404Sobrien       issues an error on attempt to assemble an improperly aligned data item.
12392218822Sdim       We don't.  */
12393179404Sobrien
12394179404Sobrien  temp = get_absolute_expression ();
12395179404Sobrien  if (temp > max_alignment)
12396179404Sobrien    as_bad (_("Alignment too large: %d. assumed."), temp = max_alignment);
12397179404Sobrien  else if (temp < 0)
12398179404Sobrien    {
12399179404Sobrien      as_warn (_("Alignment negative: 0 assumed."));
12400179404Sobrien      temp = 0;
12401179404Sobrien    }
12402179404Sobrien  if (*input_line_pointer == ',')
12403179404Sobrien    {
12404179404Sobrien      ++input_line_pointer;
12405179404Sobrien      temp_fill = get_absolute_expression ();
12406179404Sobrien    }
12407179404Sobrien  else
12408179404Sobrien    temp_fill = 0;
12409179404Sobrien  if (temp)
12410179404Sobrien    {
12411218822Sdim      segment_info_type *si = seg_info (now_seg);
12412218822Sdim      struct insn_label_list *l = si->label_list;
12413218822Sdim      /* Auto alignment should be switched on by next section change.  */
12414179404Sobrien      auto_align = 1;
12415218822Sdim      mips_align (temp, (int) temp_fill, l != NULL ? l->label : NULL);
12416179404Sobrien    }
12417179404Sobrien  else
12418179404Sobrien    {
12419179404Sobrien      auto_align = 0;
12420179404Sobrien    }
12421179404Sobrien
12422179404Sobrien  demand_empty_rest_of_line ();
12423179404Sobrien}
12424179404Sobrien
12425179404Sobrienstatic void
12426179404Sobriens_change_sec (int sec)
12427179404Sobrien{
12428179404Sobrien  segT seg;
12429179404Sobrien
12430179404Sobrien#ifdef OBJ_ELF
12431179404Sobrien  /* The ELF backend needs to know that we are changing sections, so
12432179404Sobrien     that .previous works correctly.  We could do something like check
12433179404Sobrien     for an obj_section_change_hook macro, but that might be confusing
12434179404Sobrien     as it would not be appropriate to use it in the section changing
12435179404Sobrien     functions in read.c, since obj-elf.c intercepts those.  FIXME:
12436179404Sobrien     This should be cleaner, somehow.  */
12437218822Sdim  if (IS_ELF)
12438218822Sdim    obj_elf_section_change_hook ();
12439179404Sobrien#endif
12440179404Sobrien
12441208737Sjmallett  mips_emit_delays ();
12442179404Sobrien  switch (sec)
12443179404Sobrien    {
12444179404Sobrien    case 't':
12445179404Sobrien      s_text (0);
12446179404Sobrien      break;
12447179404Sobrien    case 'd':
12448179404Sobrien      s_data (0);
12449179404Sobrien      break;
12450179404Sobrien    case 'b':
12451179404Sobrien      subseg_set (bss_section, (subsegT) get_absolute_expression ());
12452179404Sobrien      demand_empty_rest_of_line ();
12453179404Sobrien      break;
12454179404Sobrien
12455179404Sobrien    case 'r':
12456208737Sjmallett      seg = subseg_new (RDATA_SECTION_NAME,
12457208737Sjmallett			(subsegT) get_absolute_expression ());
12458218822Sdim      if (IS_ELF)
12459179404Sobrien	{
12460208737Sjmallett	  bfd_set_section_flags (stdoutput, seg, (SEC_ALLOC | SEC_LOAD
12461208737Sjmallett						  | SEC_READONLY | SEC_RELOC
12462208737Sjmallett						  | SEC_DATA));
12463208737Sjmallett	  if (strcmp (TARGET_OS, "elf") != 0)
12464208737Sjmallett	    record_alignment (seg, 4);
12465179404Sobrien	}
12466208737Sjmallett      demand_empty_rest_of_line ();
12467179404Sobrien      break;
12468179404Sobrien
12469179404Sobrien    case 's':
12470208737Sjmallett      seg = subseg_new (".sdata", (subsegT) get_absolute_expression ());
12471218822Sdim      if (IS_ELF)
12472179404Sobrien	{
12473208737Sjmallett	  bfd_set_section_flags (stdoutput, seg,
12474208737Sjmallett				 SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA);
12475208737Sjmallett	  if (strcmp (TARGET_OS, "elf") != 0)
12476208737Sjmallett	    record_alignment (seg, 4);
12477179404Sobrien	}
12478208737Sjmallett      demand_empty_rest_of_line ();
12479208737Sjmallett      break;
12480179404Sobrien    }
12481179404Sobrien
12482179404Sobrien  auto_align = 1;
12483179404Sobrien}
12484179404Sobrien
12485179404Sobrienvoid
12486179404Sobriens_change_section (int ignore ATTRIBUTE_UNUSED)
12487179404Sobrien{
12488179404Sobrien#ifdef OBJ_ELF
12489179404Sobrien  char *section_name;
12490179404Sobrien  char c;
12491179404Sobrien  char next_c = 0;
12492179404Sobrien  int section_type;
12493179404Sobrien  int section_flag;
12494179404Sobrien  int section_entry_size;
12495179404Sobrien  int section_alignment;
12496179404Sobrien
12497218822Sdim  if (!IS_ELF)
12498179404Sobrien    return;
12499179404Sobrien
12500179404Sobrien  section_name = input_line_pointer;
12501179404Sobrien  c = get_symbol_end ();
12502179404Sobrien  if (c)
12503179404Sobrien    next_c = *(input_line_pointer + 1);
12504179404Sobrien
12505179404Sobrien  /* Do we have .section Name<,"flags">?  */
12506179404Sobrien  if (c != ',' || (c == ',' && next_c == '"'))
12507179404Sobrien    {
12508179404Sobrien      /* just after name is now '\0'.  */
12509179404Sobrien      *input_line_pointer = c;
12510179404Sobrien      input_line_pointer = section_name;
12511179404Sobrien      obj_elf_section (ignore);
12512179404Sobrien      return;
12513179404Sobrien    }
12514179404Sobrien  input_line_pointer++;
12515179404Sobrien
12516179404Sobrien  /* Do we have .section Name<,type><,flag><,entry_size><,alignment>  */
12517179404Sobrien  if (c == ',')
12518179404Sobrien    section_type = get_absolute_expression ();
12519179404Sobrien  else
12520179404Sobrien    section_type = 0;
12521179404Sobrien  if (*input_line_pointer++ == ',')
12522179404Sobrien    section_flag = get_absolute_expression ();
12523179404Sobrien  else
12524179404Sobrien    section_flag = 0;
12525179404Sobrien  if (*input_line_pointer++ == ',')
12526179404Sobrien    section_entry_size = get_absolute_expression ();
12527179404Sobrien  else
12528179404Sobrien    section_entry_size = 0;
12529179404Sobrien  if (*input_line_pointer++ == ',')
12530179404Sobrien    section_alignment = get_absolute_expression ();
12531179404Sobrien  else
12532179404Sobrien    section_alignment = 0;
12533179404Sobrien
12534179404Sobrien  section_name = xstrdup (section_name);
12535179404Sobrien
12536179404Sobrien  /* When using the generic form of .section (as implemented by obj-elf.c),
12537179404Sobrien     there's no way to set the section type to SHT_MIPS_DWARF.  Users have
12538179404Sobrien     traditionally had to fall back on the more common @progbits instead.
12539179404Sobrien
12540179404Sobrien     There's nothing really harmful in this, since bfd will correct
12541179404Sobrien     SHT_PROGBITS to SHT_MIPS_DWARF before writing out the file.  But it
12542218822Sdim     means that, for backwards compatibility, the special_section entries
12543179404Sobrien     for dwarf sections must use SHT_PROGBITS rather than SHT_MIPS_DWARF.
12544179404Sobrien
12545179404Sobrien     Even so, we shouldn't force users of the MIPS .section syntax to
12546179404Sobrien     incorrectly label the sections as SHT_PROGBITS.  The best compromise
12547179404Sobrien     seems to be to map SHT_MIPS_DWARF to SHT_PROGBITS before calling the
12548179404Sobrien     generic type-checking code.  */
12549179404Sobrien  if (section_type == SHT_MIPS_DWARF)
12550179404Sobrien    section_type = SHT_PROGBITS;
12551179404Sobrien
12552179404Sobrien  obj_elf_change_section (section_name, section_type, section_flag,
12553179404Sobrien			  section_entry_size, 0, 0, 0);
12554179404Sobrien
12555179404Sobrien  if (now_seg->name != section_name)
12556179404Sobrien    free (section_name);
12557179404Sobrien#endif /* OBJ_ELF */
12558179404Sobrien}
12559179404Sobrien
12560179404Sobrienvoid
12561179404Sobrienmips_enable_auto_align (void)
12562179404Sobrien{
12563179404Sobrien  auto_align = 1;
12564179404Sobrien}
12565179404Sobrien
12566179404Sobrienstatic void
12567179404Sobriens_cons (int log_size)
12568179404Sobrien{
12569218822Sdim  segment_info_type *si = seg_info (now_seg);
12570218822Sdim  struct insn_label_list *l = si->label_list;
12571179404Sobrien  symbolS *label;
12572179404Sobrien
12573218822Sdim  label = l != NULL ? l->label : NULL;
12574208737Sjmallett  mips_emit_delays ();
12575179404Sobrien  if (log_size > 0 && auto_align)
12576179404Sobrien    mips_align (log_size, 0, label);
12577179404Sobrien  mips_clear_insn_labels ();
12578179404Sobrien  cons (1 << log_size);
12579179404Sobrien}
12580179404Sobrien
12581179404Sobrienstatic void
12582179404Sobriens_float_cons (int type)
12583179404Sobrien{
12584218822Sdim  segment_info_type *si = seg_info (now_seg);
12585218822Sdim  struct insn_label_list *l = si->label_list;
12586179404Sobrien  symbolS *label;
12587179404Sobrien
12588218822Sdim  label = l != NULL ? l->label : NULL;
12589179404Sobrien
12590208737Sjmallett  mips_emit_delays ();
12591179404Sobrien
12592179404Sobrien  if (auto_align)
12593179404Sobrien    {
12594179404Sobrien      if (type == 'd')
12595179404Sobrien	mips_align (3, 0, label);
12596179404Sobrien      else
12597179404Sobrien	mips_align (2, 0, label);
12598179404Sobrien    }
12599179404Sobrien
12600179404Sobrien  mips_clear_insn_labels ();
12601179404Sobrien
12602179404Sobrien  float_cons (type);
12603179404Sobrien}
12604179404Sobrien
12605179404Sobrien/* Handle .globl.  We need to override it because on Irix 5 you are
12606179404Sobrien   permitted to say
12607179404Sobrien       .globl foo .text
12608179404Sobrien   where foo is an undefined symbol, to mean that foo should be
12609179404Sobrien   considered to be the address of a function.  */
12610179404Sobrien
12611179404Sobrienstatic void
12612179404Sobriens_mips_globl (int x ATTRIBUTE_UNUSED)
12613179404Sobrien{
12614179404Sobrien  char *name;
12615179404Sobrien  int c;
12616179404Sobrien  symbolS *symbolP;
12617179404Sobrien  flagword flag;
12618179404Sobrien
12619208737Sjmallett  do
12620179404Sobrien    {
12621208737Sjmallett      name = input_line_pointer;
12622208737Sjmallett      c = get_symbol_end ();
12623208737Sjmallett      symbolP = symbol_find_or_make (name);
12624208737Sjmallett      S_SET_EXTERNAL (symbolP);
12625179404Sobrien
12626179404Sobrien      *input_line_pointer = c;
12627208737Sjmallett      SKIP_WHITESPACE ();
12628179404Sobrien
12629208737Sjmallett      /* On Irix 5, every global symbol that is not explicitly labelled as
12630208737Sjmallett         being a function is apparently labelled as being an object.  */
12631208737Sjmallett      flag = BSF_OBJECT;
12632208737Sjmallett
12633208737Sjmallett      if (!is_end_of_line[(unsigned char) *input_line_pointer]
12634208737Sjmallett	  && (*input_line_pointer != ','))
12635208737Sjmallett	{
12636208737Sjmallett	  char *secname;
12637208737Sjmallett	  asection *sec;
12638208737Sjmallett
12639208737Sjmallett	  secname = input_line_pointer;
12640208737Sjmallett	  c = get_symbol_end ();
12641208737Sjmallett	  sec = bfd_get_section_by_name (stdoutput, secname);
12642208737Sjmallett	  if (sec == NULL)
12643208737Sjmallett	    as_bad (_("%s: no such section"), secname);
12644208737Sjmallett	  *input_line_pointer = c;
12645208737Sjmallett
12646208737Sjmallett	  if (sec != NULL && (sec->flags & SEC_CODE) != 0)
12647208737Sjmallett	    flag = BSF_FUNCTION;
12648208737Sjmallett	}
12649208737Sjmallett
12650208737Sjmallett      symbol_get_bfdsym (symbolP)->flags |= flag;
12651208737Sjmallett
12652208737Sjmallett      c = *input_line_pointer;
12653208737Sjmallett      if (c == ',')
12654208737Sjmallett	{
12655208737Sjmallett	  input_line_pointer++;
12656208737Sjmallett	  SKIP_WHITESPACE ();
12657208737Sjmallett	  if (is_end_of_line[(unsigned char) *input_line_pointer])
12658208737Sjmallett	    c = '\n';
12659208737Sjmallett	}
12660179404Sobrien    }
12661208737Sjmallett  while (c == ',');
12662179404Sobrien
12663179404Sobrien  demand_empty_rest_of_line ();
12664179404Sobrien}
12665179404Sobrien
12666179404Sobrienstatic void
12667179404Sobriens_option (int x ATTRIBUTE_UNUSED)
12668179404Sobrien{
12669179404Sobrien  char *opt;
12670179404Sobrien  char c;
12671179404Sobrien
12672179404Sobrien  opt = input_line_pointer;
12673179404Sobrien  c = get_symbol_end ();
12674179404Sobrien
12675179404Sobrien  if (*opt == 'O')
12676179404Sobrien    {
12677179404Sobrien      /* FIXME: What does this mean?  */
12678179404Sobrien    }
12679179404Sobrien  else if (strncmp (opt, "pic", 3) == 0)
12680179404Sobrien    {
12681179404Sobrien      int i;
12682179404Sobrien
12683179404Sobrien      i = atoi (opt + 3);
12684179404Sobrien      if (i == 0)
12685179404Sobrien	mips_pic = NO_PIC;
12686179404Sobrien      else if (i == 2)
12687179404Sobrien	{
12688179404Sobrien	mips_pic = SVR4_PIC;
12689179404Sobrien	  mips_abicalls = TRUE;
12690179404Sobrien	}
12691179404Sobrien      else
12692179404Sobrien	as_bad (_(".option pic%d not supported"), i);
12693179404Sobrien
12694208737Sjmallett      if (mips_pic == SVR4_PIC)
12695179404Sobrien	{
12696179404Sobrien	  if (g_switch_seen && g_switch_value != 0)
12697179404Sobrien	    as_warn (_("-G may not be used with SVR4 PIC code"));
12698179404Sobrien	  g_switch_value = 0;
12699179404Sobrien	  bfd_set_gp_size (stdoutput, 0);
12700179404Sobrien	}
12701179404Sobrien    }
12702179404Sobrien  else
12703179404Sobrien    as_warn (_("Unrecognized option \"%s\""), opt);
12704179404Sobrien
12705179404Sobrien  *input_line_pointer = c;
12706179404Sobrien  demand_empty_rest_of_line ();
12707179404Sobrien}
12708179404Sobrien
12709179404Sobrien/* This structure is used to hold a stack of .set values.  */
12710179404Sobrien
12711179404Sobrienstruct mips_option_stack
12712179404Sobrien{
12713179404Sobrien  struct mips_option_stack *next;
12714179404Sobrien  struct mips_set_options options;
12715179404Sobrien};
12716179404Sobrien
12717179404Sobrienstatic struct mips_option_stack *mips_opts_stack;
12718179404Sobrien
12719179404Sobrien/* Handle the .set pseudo-op.  */
12720179404Sobrien
12721179404Sobrienstatic void
12722179404Sobriens_mipsset (int x ATTRIBUTE_UNUSED)
12723179404Sobrien{
12724179404Sobrien  char *name = input_line_pointer, ch;
12725179404Sobrien
12726179404Sobrien  while (!is_end_of_line[(unsigned char) *input_line_pointer])
12727179404Sobrien    ++input_line_pointer;
12728179404Sobrien  ch = *input_line_pointer;
12729179404Sobrien  *input_line_pointer = '\0';
12730179404Sobrien
12731179404Sobrien  if (strcmp (name, "reorder") == 0)
12732179404Sobrien    {
12733208737Sjmallett      if (mips_opts.noreorder)
12734208737Sjmallett	end_noreorder ();
12735179404Sobrien    }
12736179404Sobrien  else if (strcmp (name, "noreorder") == 0)
12737179404Sobrien    {
12738208737Sjmallett      if (!mips_opts.noreorder)
12739208737Sjmallett	start_noreorder ();
12740179404Sobrien    }
12741179404Sobrien  else if (strcmp (name, "at") == 0)
12742179404Sobrien    {
12743179404Sobrien      mips_opts.noat = 0;
12744179404Sobrien    }
12745179404Sobrien  else if (strcmp (name, "noat") == 0)
12746179404Sobrien    {
12747179404Sobrien      mips_opts.noat = 1;
12748179404Sobrien    }
12749179404Sobrien  else if (strcmp (name, "macro") == 0)
12750179404Sobrien    {
12751179404Sobrien      mips_opts.warn_about_macros = 0;
12752179404Sobrien    }
12753179404Sobrien  else if (strcmp (name, "nomacro") == 0)
12754179404Sobrien    {
12755179404Sobrien      if (mips_opts.noreorder == 0)
12756179404Sobrien	as_bad (_("`noreorder' must be set before `nomacro'"));
12757179404Sobrien      mips_opts.warn_about_macros = 1;
12758179404Sobrien    }
12759179404Sobrien  else if (strcmp (name, "move") == 0 || strcmp (name, "novolatile") == 0)
12760179404Sobrien    {
12761179404Sobrien      mips_opts.nomove = 0;
12762179404Sobrien    }
12763179404Sobrien  else if (strcmp (name, "nomove") == 0 || strcmp (name, "volatile") == 0)
12764179404Sobrien    {
12765179404Sobrien      mips_opts.nomove = 1;
12766179404Sobrien    }
12767179404Sobrien  else if (strcmp (name, "bopt") == 0)
12768179404Sobrien    {
12769179404Sobrien      mips_opts.nobopt = 0;
12770179404Sobrien    }
12771179404Sobrien  else if (strcmp (name, "nobopt") == 0)
12772179404Sobrien    {
12773179404Sobrien      mips_opts.nobopt = 1;
12774179404Sobrien    }
12775218822Sdim  else if (strcmp (name, "gp=default") == 0)
12776218822Sdim    mips_opts.gp32 = file_mips_gp32;
12777218822Sdim  else if (strcmp (name, "gp=32") == 0)
12778218822Sdim    mips_opts.gp32 = 1;
12779218822Sdim  else if (strcmp (name, "gp=64") == 0)
12780218822Sdim    {
12781218822Sdim      if (!ISA_HAS_64BIT_REGS (mips_opts.isa))
12782218822Sdim	as_warn ("%s isa does not support 64-bit registers",
12783218822Sdim		 mips_cpu_info_from_isa (mips_opts.isa)->name);
12784218822Sdim      mips_opts.gp32 = 0;
12785218822Sdim    }
12786218822Sdim  else if (strcmp (name, "fp=default") == 0)
12787218822Sdim    mips_opts.fp32 = file_mips_fp32;
12788218822Sdim  else if (strcmp (name, "fp=32") == 0)
12789218822Sdim    mips_opts.fp32 = 1;
12790218822Sdim  else if (strcmp (name, "fp=64") == 0)
12791218822Sdim    {
12792218822Sdim      if (!ISA_HAS_64BIT_FPRS (mips_opts.isa))
12793218822Sdim	as_warn ("%s isa does not support 64-bit floating point registers",
12794218822Sdim		 mips_cpu_info_from_isa (mips_opts.isa)->name);
12795218822Sdim      mips_opts.fp32 = 0;
12796218822Sdim    }
12797179404Sobrien  else if (strcmp (name, "mips16") == 0
12798179404Sobrien	   || strcmp (name, "MIPS-16") == 0)
12799179404Sobrien    mips_opts.mips16 = 1;
12800179404Sobrien  else if (strcmp (name, "nomips16") == 0
12801179404Sobrien	   || strcmp (name, "noMIPS-16") == 0)
12802179404Sobrien    mips_opts.mips16 = 0;
12803218822Sdim  else if (strcmp (name, "smartmips") == 0)
12804218822Sdim    {
12805218822Sdim      if (!ISA_SUPPORTS_SMARTMIPS)
12806218822Sdim	as_warn ("%s ISA does not support SmartMIPS ASE",
12807218822Sdim		 mips_cpu_info_from_isa (mips_opts.isa)->name);
12808218822Sdim      mips_opts.ase_smartmips = 1;
12809218822Sdim    }
12810218822Sdim  else if (strcmp (name, "nosmartmips") == 0)
12811218822Sdim    mips_opts.ase_smartmips = 0;
12812179404Sobrien  else if (strcmp (name, "mips3d") == 0)
12813179404Sobrien    mips_opts.ase_mips3d = 1;
12814179404Sobrien  else if (strcmp (name, "nomips3d") == 0)
12815179404Sobrien    mips_opts.ase_mips3d = 0;
12816179404Sobrien  else if (strcmp (name, "mdmx") == 0)
12817179404Sobrien    mips_opts.ase_mdmx = 1;
12818179404Sobrien  else if (strcmp (name, "nomdmx") == 0)
12819179404Sobrien    mips_opts.ase_mdmx = 0;
12820208737Sjmallett  else if (strcmp (name, "dsp") == 0)
12821218822Sdim    {
12822218822Sdim      if (!ISA_SUPPORTS_DSP_ASE)
12823218822Sdim	as_warn ("%s ISA does not support DSP ASE",
12824218822Sdim		 mips_cpu_info_from_isa (mips_opts.isa)->name);
12825218822Sdim      mips_opts.ase_dsp = 1;
12826218822Sdim      mips_opts.ase_dspr2 = 0;
12827218822Sdim    }
12828208737Sjmallett  else if (strcmp (name, "nodsp") == 0)
12829218822Sdim    {
12830218822Sdim      mips_opts.ase_dsp = 0;
12831218822Sdim      mips_opts.ase_dspr2 = 0;
12832218822Sdim    }
12833218822Sdim  else if (strcmp (name, "dspr2") == 0)
12834218822Sdim    {
12835218822Sdim      if (!ISA_SUPPORTS_DSPR2_ASE)
12836218822Sdim	as_warn ("%s ISA does not support DSP R2 ASE",
12837218822Sdim		 mips_cpu_info_from_isa (mips_opts.isa)->name);
12838218822Sdim      mips_opts.ase_dspr2 = 1;
12839218822Sdim      mips_opts.ase_dsp = 1;
12840218822Sdim    }
12841218822Sdim  else if (strcmp (name, "nodspr2") == 0)
12842218822Sdim    {
12843218822Sdim      mips_opts.ase_dspr2 = 0;
12844218822Sdim      mips_opts.ase_dsp = 0;
12845218822Sdim    }
12846208737Sjmallett  else if (strcmp (name, "mt") == 0)
12847218822Sdim    {
12848218822Sdim      if (!ISA_SUPPORTS_MT_ASE)
12849218822Sdim	as_warn ("%s ISA does not support MT ASE",
12850218822Sdim		 mips_cpu_info_from_isa (mips_opts.isa)->name);
12851218822Sdim      mips_opts.ase_mt = 1;
12852218822Sdim    }
12853208737Sjmallett  else if (strcmp (name, "nomt") == 0)
12854208737Sjmallett    mips_opts.ase_mt = 0;
12855179404Sobrien  else if (strncmp (name, "mips", 4) == 0 || strncmp (name, "arch=", 5) == 0)
12856179404Sobrien    {
12857179404Sobrien      int reset = 0;
12858179404Sobrien
12859179404Sobrien      /* Permit the user to change the ISA and architecture on the fly.
12860179404Sobrien	 Needless to say, misuse can cause serious problems.  */
12861208737Sjmallett      if (strcmp (name, "mips0") == 0 || strcmp (name, "arch=default") == 0)
12862179404Sobrien	{
12863179404Sobrien	  reset = 1;
12864179404Sobrien	  mips_opts.isa = file_mips_isa;
12865179404Sobrien	  mips_opts.arch = file_mips_arch;
12866179404Sobrien	}
12867179404Sobrien      else if (strncmp (name, "arch=", 5) == 0)
12868179404Sobrien	{
12869179404Sobrien	  const struct mips_cpu_info *p;
12870179404Sobrien
12871179404Sobrien	  p = mips_parse_cpu("internal use", name + 5);
12872179404Sobrien	  if (!p)
12873179404Sobrien	    as_bad (_("unknown architecture %s"), name + 5);
12874179404Sobrien	  else
12875179404Sobrien	    {
12876179404Sobrien	      mips_opts.arch = p->cpu;
12877179404Sobrien	      mips_opts.isa = p->isa;
12878179404Sobrien	    }
12879179404Sobrien	}
12880208737Sjmallett      else if (strncmp (name, "mips", 4) == 0)
12881208737Sjmallett	{
12882208737Sjmallett	  const struct mips_cpu_info *p;
12883208737Sjmallett
12884208737Sjmallett	  p = mips_parse_cpu("internal use", name);
12885208737Sjmallett	  if (!p)
12886208737Sjmallett	    as_bad (_("unknown ISA level %s"), name + 4);
12887208737Sjmallett	  else
12888208737Sjmallett	    {
12889208737Sjmallett	      mips_opts.arch = p->cpu;
12890208737Sjmallett	      mips_opts.isa = p->isa;
12891208737Sjmallett	    }
12892208737Sjmallett	}
12893179404Sobrien      else
12894208737Sjmallett	as_bad (_("unknown ISA or architecture %s"), name);
12895179404Sobrien
12896179404Sobrien      switch (mips_opts.isa)
12897179404Sobrien	{
12898179404Sobrien	case  0:
12899179404Sobrien	  break;
12900179404Sobrien	case ISA_MIPS1:
12901179404Sobrien	case ISA_MIPS2:
12902179404Sobrien	case ISA_MIPS32:
12903179404Sobrien	case ISA_MIPS32R2:
12904179404Sobrien	  mips_opts.gp32 = 1;
12905179404Sobrien	  mips_opts.fp32 = 1;
12906179404Sobrien	  break;
12907179404Sobrien	case ISA_MIPS3:
12908179404Sobrien	case ISA_MIPS4:
12909179404Sobrien	case ISA_MIPS5:
12910179404Sobrien	case ISA_MIPS64:
12911179404Sobrien	case ISA_MIPS64R2:
12912179404Sobrien	  mips_opts.gp32 = 0;
12913179404Sobrien	  mips_opts.fp32 = 0;
12914179404Sobrien	  break;
12915179404Sobrien	default:
12916179404Sobrien	  as_bad (_("unknown ISA level %s"), name + 4);
12917179404Sobrien	  break;
12918179404Sobrien	}
12919179404Sobrien      if (reset)
12920179404Sobrien	{
12921179404Sobrien	  mips_opts.gp32 = file_mips_gp32;
12922179404Sobrien	  mips_opts.fp32 = file_mips_fp32;
12923179404Sobrien	}
12924179404Sobrien    }
12925179404Sobrien  else if (strcmp (name, "autoextend") == 0)
12926179404Sobrien    mips_opts.noautoextend = 0;
12927179404Sobrien  else if (strcmp (name, "noautoextend") == 0)
12928179404Sobrien    mips_opts.noautoextend = 1;
12929179404Sobrien  else if (strcmp (name, "push") == 0)
12930179404Sobrien    {
12931179404Sobrien      struct mips_option_stack *s;
12932179404Sobrien
12933179404Sobrien      s = (struct mips_option_stack *) xmalloc (sizeof *s);
12934179404Sobrien      s->next = mips_opts_stack;
12935179404Sobrien      s->options = mips_opts;
12936179404Sobrien      mips_opts_stack = s;
12937179404Sobrien    }
12938179404Sobrien  else if (strcmp (name, "pop") == 0)
12939179404Sobrien    {
12940179404Sobrien      struct mips_option_stack *s;
12941179404Sobrien
12942179404Sobrien      s = mips_opts_stack;
12943179404Sobrien      if (s == NULL)
12944179404Sobrien	as_bad (_(".set pop with no .set push"));
12945179404Sobrien      else
12946179404Sobrien	{
12947179404Sobrien	  /* If we're changing the reorder mode we need to handle
12948179404Sobrien             delay slots correctly.  */
12949179404Sobrien	  if (s->options.noreorder && ! mips_opts.noreorder)
12950208737Sjmallett	    start_noreorder ();
12951179404Sobrien	  else if (! s->options.noreorder && mips_opts.noreorder)
12952208737Sjmallett	    end_noreorder ();
12953179404Sobrien
12954179404Sobrien	  mips_opts = s->options;
12955179404Sobrien	  mips_opts_stack = s->next;
12956179404Sobrien	  free (s);
12957179404Sobrien	}
12958179404Sobrien    }
12959208737Sjmallett  else if (strcmp (name, "sym32") == 0)
12960208737Sjmallett    mips_opts.sym32 = TRUE;
12961208737Sjmallett  else if (strcmp (name, "nosym32") == 0)
12962208737Sjmallett    mips_opts.sym32 = FALSE;
12963218822Sdim  else if (strchr (name, ','))
12964218822Sdim    {
12965218822Sdim      /* Generic ".set" directive; use the generic handler.  */
12966218822Sdim      *input_line_pointer = ch;
12967218822Sdim      input_line_pointer = name;
12968218822Sdim      s_set (0);
12969218822Sdim      return;
12970218822Sdim    }
12971179404Sobrien  else
12972179404Sobrien    {
12973179404Sobrien      as_warn (_("Tried to set unrecognized symbol: %s\n"), name);
12974179404Sobrien    }
12975179404Sobrien  *input_line_pointer = ch;
12976179404Sobrien  demand_empty_rest_of_line ();
12977179404Sobrien}
12978179404Sobrien
12979179404Sobrien/* Handle the .abicalls pseudo-op.  I believe this is equivalent to
12980179404Sobrien   .option pic2.  It means to generate SVR4 PIC calls.  */
12981179404Sobrien
12982179404Sobrienstatic void
12983179404Sobriens_abicalls (int ignore ATTRIBUTE_UNUSED)
12984179404Sobrien{
12985179404Sobrien  mips_pic = SVR4_PIC;
12986179404Sobrien  mips_abicalls = TRUE;
12987208737Sjmallett
12988208737Sjmallett  if (g_switch_seen && g_switch_value != 0)
12989208737Sjmallett    as_warn (_("-G may not be used with SVR4 PIC code"));
12990208737Sjmallett  g_switch_value = 0;
12991208737Sjmallett
12992179404Sobrien  bfd_set_gp_size (stdoutput, 0);
12993179404Sobrien  demand_empty_rest_of_line ();
12994179404Sobrien}
12995179404Sobrien
12996179404Sobrien/* Handle the .cpload pseudo-op.  This is used when generating SVR4
12997179404Sobrien   PIC code.  It sets the $gp register for the function based on the
12998179404Sobrien   function address, which is in the register named in the argument.
12999179404Sobrien   This uses a relocation against _gp_disp, which is handled specially
13000179404Sobrien   by the linker.  The result is:
13001179404Sobrien	lui	$gp,%hi(_gp_disp)
13002179404Sobrien	addiu	$gp,$gp,%lo(_gp_disp)
13003179404Sobrien	addu	$gp,$gp,.cpload argument
13004208737Sjmallett   The .cpload argument is normally $25 == $t9.
13005179404Sobrien
13006208737Sjmallett   The -mno-shared option changes this to:
13007208737Sjmallett	lui	$gp,%hi(__gnu_local_gp)
13008208737Sjmallett	addiu	$gp,$gp,%lo(__gnu_local_gp)
13009208737Sjmallett   and the argument is ignored.  This saves an instruction, but the
13010208737Sjmallett   resulting code is not position independent; it uses an absolute
13011208737Sjmallett   address for __gnu_local_gp.  Thus code assembled with -mno-shared
13012208737Sjmallett   can go into an ordinary executable, but not into a shared library.  */
13013208737Sjmallett
13014179404Sobrienstatic void
13015179404Sobriens_cpload (int ignore ATTRIBUTE_UNUSED)
13016179404Sobrien{
13017179404Sobrien  expressionS ex;
13018208737Sjmallett  int reg;
13019208737Sjmallett  int in_shared;
13020179404Sobrien
13021179404Sobrien  /* If we are not generating SVR4 PIC code, or if this is NewABI code,
13022179404Sobrien     .cpload is ignored.  */
13023179404Sobrien  if (mips_pic != SVR4_PIC || HAVE_NEWABI)
13024179404Sobrien    {
13025179404Sobrien      s_ignore (0);
13026179404Sobrien      return;
13027179404Sobrien    }
13028179404Sobrien
13029179404Sobrien  /* .cpload should be in a .set noreorder section.  */
13030179404Sobrien  if (mips_opts.noreorder == 0)
13031179404Sobrien    as_warn (_(".cpload not in noreorder section"));
13032179404Sobrien
13033208737Sjmallett  reg = tc_get_register (0);
13034208737Sjmallett
13035208737Sjmallett  /* If we need to produce a 64-bit address, we are better off using
13036208737Sjmallett     the default instruction sequence.  */
13037208737Sjmallett  in_shared = mips_in_shared || HAVE_64BIT_SYMBOLS;
13038208737Sjmallett
13039179404Sobrien  ex.X_op = O_symbol;
13040208737Sjmallett  ex.X_add_symbol = symbol_find_or_make (in_shared ? "_gp_disp" :
13041208737Sjmallett                                         "__gnu_local_gp");
13042179404Sobrien  ex.X_op_symbol = NULL;
13043179404Sobrien  ex.X_add_number = 0;
13044179404Sobrien
13045179404Sobrien  /* In ELF, this symbol is implicitly an STT_OBJECT symbol.  */
13046179404Sobrien  symbol_get_bfdsym (ex.X_add_symbol)->flags |= BSF_OBJECT;
13047179404Sobrien
13048179404Sobrien  macro_start ();
13049179404Sobrien  macro_build_lui (&ex, mips_gp_register);
13050179404Sobrien  macro_build (&ex, "addiu", "t,r,j", mips_gp_register,
13051179404Sobrien	       mips_gp_register, BFD_RELOC_LO16);
13052208737Sjmallett  if (in_shared)
13053208737Sjmallett    macro_build (NULL, "addu", "d,v,t", mips_gp_register,
13054208737Sjmallett		 mips_gp_register, reg);
13055179404Sobrien  macro_end ();
13056179404Sobrien
13057179404Sobrien  demand_empty_rest_of_line ();
13058179404Sobrien}
13059179404Sobrien
13060179404Sobrien/* Handle the .cpsetup pseudo-op defined for NewABI PIC code.  The syntax is:
13061179404Sobrien     .cpsetup $reg1, offset|$reg2, label
13062179404Sobrien
13063179404Sobrien   If offset is given, this results in:
13064179404Sobrien     sd		$gp, offset($sp)
13065179404Sobrien     lui	$gp, %hi(%neg(%gp_rel(label)))
13066179404Sobrien     addiu	$gp, $gp, %lo(%neg(%gp_rel(label)))
13067179404Sobrien     daddu	$gp, $gp, $reg1
13068179404Sobrien
13069179404Sobrien   If $reg2 is given, this results in:
13070179404Sobrien     daddu	$reg2, $gp, $0
13071179404Sobrien     lui	$gp, %hi(%neg(%gp_rel(label)))
13072179404Sobrien     addiu	$gp, $gp, %lo(%neg(%gp_rel(label)))
13073179404Sobrien     daddu	$gp, $gp, $reg1
13074208737Sjmallett   $reg1 is normally $25 == $t9.
13075208737Sjmallett
13076208737Sjmallett   The -mno-shared option replaces the last three instructions with
13077208737Sjmallett	lui	$gp,%hi(_gp)
13078218822Sdim	addiu	$gp,$gp,%lo(_gp)  */
13079208737Sjmallett
13080179404Sobrienstatic void
13081179404Sobriens_cpsetup (int ignore ATTRIBUTE_UNUSED)
13082179404Sobrien{
13083179404Sobrien  expressionS ex_off;
13084179404Sobrien  expressionS ex_sym;
13085179404Sobrien  int reg1;
13086179404Sobrien
13087179404Sobrien  /* If we are not generating SVR4 PIC code, .cpsetup is ignored.
13088179404Sobrien     We also need NewABI support.  */
13089179404Sobrien  if (mips_pic != SVR4_PIC || ! HAVE_NEWABI)
13090179404Sobrien    {
13091179404Sobrien      s_ignore (0);
13092179404Sobrien      return;
13093179404Sobrien    }
13094179404Sobrien
13095179404Sobrien  reg1 = tc_get_register (0);
13096179404Sobrien  SKIP_WHITESPACE ();
13097179404Sobrien  if (*input_line_pointer != ',')
13098179404Sobrien    {
13099179404Sobrien      as_bad (_("missing argument separator ',' for .cpsetup"));
13100179404Sobrien      return;
13101179404Sobrien    }
13102179404Sobrien  else
13103179404Sobrien    ++input_line_pointer;
13104179404Sobrien  SKIP_WHITESPACE ();
13105179404Sobrien  if (*input_line_pointer == '$')
13106179404Sobrien    {
13107179404Sobrien      mips_cpreturn_register = tc_get_register (0);
13108179404Sobrien      mips_cpreturn_offset = -1;
13109179404Sobrien    }
13110179404Sobrien  else
13111179404Sobrien    {
13112179404Sobrien      mips_cpreturn_offset = get_absolute_expression ();
13113179404Sobrien      mips_cpreturn_register = -1;
13114179404Sobrien    }
13115179404Sobrien  SKIP_WHITESPACE ();
13116179404Sobrien  if (*input_line_pointer != ',')
13117179404Sobrien    {
13118179404Sobrien      as_bad (_("missing argument separator ',' for .cpsetup"));
13119179404Sobrien      return;
13120179404Sobrien    }
13121179404Sobrien  else
13122179404Sobrien    ++input_line_pointer;
13123179404Sobrien  SKIP_WHITESPACE ();
13124179404Sobrien  expression (&ex_sym);
13125179404Sobrien
13126179404Sobrien  macro_start ();
13127179404Sobrien  if (mips_cpreturn_register == -1)
13128179404Sobrien    {
13129179404Sobrien      ex_off.X_op = O_constant;
13130179404Sobrien      ex_off.X_add_symbol = NULL;
13131179404Sobrien      ex_off.X_op_symbol = NULL;
13132179404Sobrien      ex_off.X_add_number = mips_cpreturn_offset;
13133179404Sobrien
13134179404Sobrien      macro_build (&ex_off, "sd", "t,o(b)", mips_gp_register,
13135179404Sobrien		   BFD_RELOC_LO16, SP);
13136179404Sobrien    }
13137179404Sobrien  else
13138179404Sobrien    macro_build (NULL, "daddu", "d,v,t", mips_cpreturn_register,
13139179404Sobrien		 mips_gp_register, 0);
13140179404Sobrien
13141208737Sjmallett  if (mips_in_shared || HAVE_64BIT_SYMBOLS)
13142208737Sjmallett    {
13143208737Sjmallett      macro_build (&ex_sym, "lui", "t,u", mips_gp_register,
13144208737Sjmallett		   -1, BFD_RELOC_GPREL16, BFD_RELOC_MIPS_SUB,
13145208737Sjmallett		   BFD_RELOC_HI16_S);
13146179404Sobrien
13147208737Sjmallett      macro_build (&ex_sym, "addiu", "t,r,j", mips_gp_register,
13148208737Sjmallett		   mips_gp_register, -1, BFD_RELOC_GPREL16,
13149208737Sjmallett		   BFD_RELOC_MIPS_SUB, BFD_RELOC_LO16);
13150179404Sobrien
13151208737Sjmallett      macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", mips_gp_register,
13152208737Sjmallett		   mips_gp_register, reg1);
13153208737Sjmallett    }
13154208737Sjmallett  else
13155208737Sjmallett    {
13156208737Sjmallett      expressionS ex;
13157208737Sjmallett
13158208737Sjmallett      ex.X_op = O_symbol;
13159208737Sjmallett      ex.X_add_symbol = symbol_find_or_make ("__gnu_local_gp");
13160208737Sjmallett      ex.X_op_symbol = NULL;
13161208737Sjmallett      ex.X_add_number = 0;
13162208737Sjmallett
13163208737Sjmallett      /* In ELF, this symbol is implicitly an STT_OBJECT symbol.  */
13164208737Sjmallett      symbol_get_bfdsym (ex.X_add_symbol)->flags |= BSF_OBJECT;
13165208737Sjmallett
13166208737Sjmallett      macro_build_lui (&ex, mips_gp_register);
13167208737Sjmallett      macro_build (&ex, "addiu", "t,r,j", mips_gp_register,
13168208737Sjmallett		   mips_gp_register, BFD_RELOC_LO16);
13169208737Sjmallett    }
13170208737Sjmallett
13171179404Sobrien  macro_end ();
13172179404Sobrien
13173179404Sobrien  demand_empty_rest_of_line ();
13174179404Sobrien}
13175179404Sobrien
13176179404Sobrienstatic void
13177179404Sobriens_cplocal (int ignore ATTRIBUTE_UNUSED)
13178179404Sobrien{
13179179404Sobrien  /* If we are not generating SVR4 PIC code, or if this is not NewABI code,
13180218822Sdim     .cplocal is ignored.  */
13181179404Sobrien  if (mips_pic != SVR4_PIC || ! HAVE_NEWABI)
13182179404Sobrien    {
13183179404Sobrien      s_ignore (0);
13184179404Sobrien      return;
13185179404Sobrien    }
13186179404Sobrien
13187179404Sobrien  mips_gp_register = tc_get_register (0);
13188179404Sobrien  demand_empty_rest_of_line ();
13189179404Sobrien}
13190179404Sobrien
13191179404Sobrien/* Handle the .cprestore pseudo-op.  This stores $gp into a given
13192179404Sobrien   offset from $sp.  The offset is remembered, and after making a PIC
13193179404Sobrien   call $gp is restored from that location.  */
13194179404Sobrien
13195179404Sobrienstatic void
13196179404Sobriens_cprestore (int ignore ATTRIBUTE_UNUSED)
13197179404Sobrien{
13198179404Sobrien  expressionS ex;
13199179404Sobrien
13200179404Sobrien  /* If we are not generating SVR4 PIC code, or if this is NewABI code,
13201179404Sobrien     .cprestore is ignored.  */
13202179404Sobrien  if (mips_pic != SVR4_PIC || HAVE_NEWABI)
13203179404Sobrien    {
13204179404Sobrien      s_ignore (0);
13205179404Sobrien      return;
13206179404Sobrien    }
13207179404Sobrien
13208179404Sobrien  mips_cprestore_offset = get_absolute_expression ();
13209179404Sobrien  mips_cprestore_valid = 1;
13210179404Sobrien
13211179404Sobrien  ex.X_op = O_constant;
13212179404Sobrien  ex.X_add_symbol = NULL;
13213179404Sobrien  ex.X_op_symbol = NULL;
13214179404Sobrien  ex.X_add_number = mips_cprestore_offset;
13215179404Sobrien
13216179404Sobrien  macro_start ();
13217179404Sobrien  macro_build_ldst_constoffset (&ex, ADDRESS_STORE_INSN, mips_gp_register,
13218179404Sobrien				SP, HAVE_64BIT_ADDRESSES);
13219179404Sobrien  macro_end ();
13220179404Sobrien
13221179404Sobrien  demand_empty_rest_of_line ();
13222179404Sobrien}
13223179404Sobrien
13224179404Sobrien/* Handle the .cpreturn pseudo-op defined for NewABI PIC code. If an offset
13225179404Sobrien   was given in the preceding .cpsetup, it results in:
13226179404Sobrien     ld		$gp, offset($sp)
13227179404Sobrien
13228179404Sobrien   If a register $reg2 was given there, it results in:
13229218822Sdim     daddu	$gp, $reg2, $0  */
13230218822Sdim
13231179404Sobrienstatic void
13232179404Sobriens_cpreturn (int ignore ATTRIBUTE_UNUSED)
13233179404Sobrien{
13234179404Sobrien  expressionS ex;
13235179404Sobrien
13236179404Sobrien  /* If we are not generating SVR4 PIC code, .cpreturn is ignored.
13237179404Sobrien     We also need NewABI support.  */
13238179404Sobrien  if (mips_pic != SVR4_PIC || ! HAVE_NEWABI)
13239179404Sobrien    {
13240179404Sobrien      s_ignore (0);
13241179404Sobrien      return;
13242179404Sobrien    }
13243179404Sobrien
13244179404Sobrien  macro_start ();
13245179404Sobrien  if (mips_cpreturn_register == -1)
13246179404Sobrien    {
13247179404Sobrien      ex.X_op = O_constant;
13248179404Sobrien      ex.X_add_symbol = NULL;
13249179404Sobrien      ex.X_op_symbol = NULL;
13250179404Sobrien      ex.X_add_number = mips_cpreturn_offset;
13251179404Sobrien
13252179404Sobrien      macro_build (&ex, "ld", "t,o(b)", mips_gp_register, BFD_RELOC_LO16, SP);
13253179404Sobrien    }
13254179404Sobrien  else
13255179404Sobrien    macro_build (NULL, "daddu", "d,v,t", mips_gp_register,
13256179404Sobrien		 mips_cpreturn_register, 0);
13257179404Sobrien  macro_end ();
13258179404Sobrien
13259179404Sobrien  demand_empty_rest_of_line ();
13260179404Sobrien}
13261179404Sobrien
13262218822Sdim/* Handle the .dtprelword and .dtpreldword pseudo-ops.  They generate
13263218822Sdim   a 32-bit or 64-bit DTP-relative relocation (BYTES says which) for
13264218822Sdim   use in DWARF debug information.  */
13265218822Sdim
13266218822Sdimstatic void
13267218822Sdims_dtprel_internal (size_t bytes)
13268218822Sdim{
13269218822Sdim  expressionS ex;
13270218822Sdim  char *p;
13271218822Sdim
13272218822Sdim  expression (&ex);
13273218822Sdim
13274218822Sdim  if (ex.X_op != O_symbol)
13275218822Sdim    {
13276218822Sdim      as_bad (_("Unsupported use of %s"), (bytes == 8
13277218822Sdim					   ? ".dtpreldword"
13278218822Sdim					   : ".dtprelword"));
13279218822Sdim      ignore_rest_of_line ();
13280218822Sdim    }
13281218822Sdim
13282218822Sdim  p = frag_more (bytes);
13283218822Sdim  md_number_to_chars (p, 0, bytes);
13284218822Sdim  fix_new_exp (frag_now, p - frag_now->fr_literal, bytes, &ex, FALSE,
13285218822Sdim	       (bytes == 8
13286218822Sdim		? BFD_RELOC_MIPS_TLS_DTPREL64
13287218822Sdim		: BFD_RELOC_MIPS_TLS_DTPREL32));
13288218822Sdim
13289218822Sdim  demand_empty_rest_of_line ();
13290218822Sdim}
13291218822Sdim
13292218822Sdim/* Handle .dtprelword.  */
13293218822Sdim
13294218822Sdimstatic void
13295218822Sdims_dtprelword (int ignore ATTRIBUTE_UNUSED)
13296218822Sdim{
13297218822Sdim  s_dtprel_internal (4);
13298218822Sdim}
13299218822Sdim
13300218822Sdim/* Handle .dtpreldword.  */
13301218822Sdim
13302218822Sdimstatic void
13303218822Sdims_dtpreldword (int ignore ATTRIBUTE_UNUSED)
13304218822Sdim{
13305218822Sdim  s_dtprel_internal (8);
13306218822Sdim}
13307218822Sdim
13308179404Sobrien/* Handle the .gpvalue pseudo-op.  This is used when generating NewABI PIC
13309179404Sobrien   code.  It sets the offset to use in gp_rel relocations.  */
13310179404Sobrien
13311179404Sobrienstatic void
13312179404Sobriens_gpvalue (int ignore ATTRIBUTE_UNUSED)
13313179404Sobrien{
13314179404Sobrien  /* If we are not generating SVR4 PIC code, .gpvalue is ignored.
13315179404Sobrien     We also need NewABI support.  */
13316179404Sobrien  if (mips_pic != SVR4_PIC || ! HAVE_NEWABI)
13317179404Sobrien    {
13318179404Sobrien      s_ignore (0);
13319179404Sobrien      return;
13320179404Sobrien    }
13321179404Sobrien
13322179404Sobrien  mips_gprel_offset = get_absolute_expression ();
13323179404Sobrien
13324179404Sobrien  demand_empty_rest_of_line ();
13325179404Sobrien}
13326179404Sobrien
13327179404Sobrien/* Handle the .gpword pseudo-op.  This is used when generating PIC
13328179404Sobrien   code.  It generates a 32 bit GP relative reloc.  */
13329179404Sobrien
13330179404Sobrienstatic void
13331179404Sobriens_gpword (int ignore ATTRIBUTE_UNUSED)
13332179404Sobrien{
13333218822Sdim  segment_info_type *si;
13334218822Sdim  struct insn_label_list *l;
13335179404Sobrien  symbolS *label;
13336179404Sobrien  expressionS ex;
13337179404Sobrien  char *p;
13338179404Sobrien
13339179404Sobrien  /* When not generating PIC code, this is treated as .word.  */
13340179404Sobrien  if (mips_pic != SVR4_PIC)
13341179404Sobrien    {
13342179404Sobrien      s_cons (2);
13343179404Sobrien      return;
13344179404Sobrien    }
13345179404Sobrien
13346218822Sdim  si = seg_info (now_seg);
13347218822Sdim  l = si->label_list;
13348218822Sdim  label = l != NULL ? l->label : NULL;
13349208737Sjmallett  mips_emit_delays ();
13350179404Sobrien  if (auto_align)
13351179404Sobrien    mips_align (2, 0, label);
13352179404Sobrien  mips_clear_insn_labels ();
13353179404Sobrien
13354179404Sobrien  expression (&ex);
13355179404Sobrien
13356179404Sobrien  if (ex.X_op != O_symbol || ex.X_add_number != 0)
13357179404Sobrien    {
13358179404Sobrien      as_bad (_("Unsupported use of .gpword"));
13359179404Sobrien      ignore_rest_of_line ();
13360179404Sobrien    }
13361179404Sobrien
13362179404Sobrien  p = frag_more (4);
13363179404Sobrien  md_number_to_chars (p, 0, 4);
13364179404Sobrien  fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &ex, FALSE,
13365179404Sobrien	       BFD_RELOC_GPREL32);
13366179404Sobrien
13367179404Sobrien  demand_empty_rest_of_line ();
13368179404Sobrien}
13369179404Sobrien
13370179404Sobrienstatic void
13371179404Sobriens_gpdword (int ignore ATTRIBUTE_UNUSED)
13372179404Sobrien{
13373218822Sdim  segment_info_type *si;
13374218822Sdim  struct insn_label_list *l;
13375179404Sobrien  symbolS *label;
13376179404Sobrien  expressionS ex;
13377179404Sobrien  char *p;
13378179404Sobrien
13379179404Sobrien  /* When not generating PIC code, this is treated as .dword.  */
13380179404Sobrien  if (mips_pic != SVR4_PIC)
13381179404Sobrien    {
13382179404Sobrien      s_cons (3);
13383179404Sobrien      return;
13384179404Sobrien    }
13385179404Sobrien
13386218822Sdim  si = seg_info (now_seg);
13387218822Sdim  l = si->label_list;
13388218822Sdim  label = l != NULL ? l->label : NULL;
13389208737Sjmallett  mips_emit_delays ();
13390179404Sobrien  if (auto_align)
13391179404Sobrien    mips_align (3, 0, label);
13392179404Sobrien  mips_clear_insn_labels ();
13393179404Sobrien
13394179404Sobrien  expression (&ex);
13395179404Sobrien
13396179404Sobrien  if (ex.X_op != O_symbol || ex.X_add_number != 0)
13397179404Sobrien    {
13398179404Sobrien      as_bad (_("Unsupported use of .gpdword"));
13399179404Sobrien      ignore_rest_of_line ();
13400179404Sobrien    }
13401179404Sobrien
13402179404Sobrien  p = frag_more (8);
13403179404Sobrien  md_number_to_chars (p, 0, 8);
13404179404Sobrien  fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &ex, FALSE,
13405208737Sjmallett	       BFD_RELOC_GPREL32)->fx_tcbit = 1;
13406179404Sobrien
13407179404Sobrien  /* GPREL32 composed with 64 gives a 64-bit GP offset.  */
13408208737Sjmallett  fix_new (frag_now, p - frag_now->fr_literal, 8, NULL, 0,
13409208737Sjmallett	   FALSE, BFD_RELOC_64)->fx_tcbit = 1;
13410179404Sobrien
13411179404Sobrien  demand_empty_rest_of_line ();
13412179404Sobrien}
13413179404Sobrien
13414179404Sobrien/* Handle the .cpadd pseudo-op.  This is used when dealing with switch
13415179404Sobrien   tables in SVR4 PIC code.  */
13416179404Sobrien
13417179404Sobrienstatic void
13418179404Sobriens_cpadd (int ignore ATTRIBUTE_UNUSED)
13419179404Sobrien{
13420179404Sobrien  int reg;
13421179404Sobrien
13422179404Sobrien  /* This is ignored when not generating SVR4 PIC code.  */
13423179404Sobrien  if (mips_pic != SVR4_PIC)
13424179404Sobrien    {
13425179404Sobrien      s_ignore (0);
13426179404Sobrien      return;
13427179404Sobrien    }
13428179404Sobrien
13429179404Sobrien  /* Add $gp to the register named as an argument.  */
13430179404Sobrien  macro_start ();
13431179404Sobrien  reg = tc_get_register (0);
13432179404Sobrien  macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", reg, reg, mips_gp_register);
13433179404Sobrien  macro_end ();
13434179404Sobrien
13435179404Sobrien  demand_empty_rest_of_line ();
13436179404Sobrien}
13437179404Sobrien
13438179404Sobrien/* Handle the .insn pseudo-op.  This marks instruction labels in
13439179404Sobrien   mips16 mode.  This permits the linker to handle them specially,
13440179404Sobrien   such as generating jalx instructions when needed.  We also make
13441179404Sobrien   them odd for the duration of the assembly, in order to generate the
13442179404Sobrien   right sort of code.  We will make them even in the adjust_symtab
13443179404Sobrien   routine, while leaving them marked.  This is convenient for the
13444179404Sobrien   debugger and the disassembler.  The linker knows to make them odd
13445179404Sobrien   again.  */
13446179404Sobrien
13447179404Sobrienstatic void
13448179404Sobriens_insn (int ignore ATTRIBUTE_UNUSED)
13449179404Sobrien{
13450179404Sobrien  mips16_mark_labels ();
13451179404Sobrien
13452179404Sobrien  demand_empty_rest_of_line ();
13453179404Sobrien}
13454179404Sobrien
13455179404Sobrien/* Handle a .stabn directive.  We need these in order to mark a label
13456179404Sobrien   as being a mips16 text label correctly.  Sometimes the compiler
13457179404Sobrien   will emit a label, followed by a .stabn, and then switch sections.
13458179404Sobrien   If the label and .stabn are in mips16 mode, then the label is
13459179404Sobrien   really a mips16 text label.  */
13460179404Sobrien
13461179404Sobrienstatic void
13462179404Sobriens_mips_stab (int type)
13463179404Sobrien{
13464179404Sobrien  if (type == 'n')
13465179404Sobrien    mips16_mark_labels ();
13466179404Sobrien
13467179404Sobrien  s_stab (type);
13468179404Sobrien}
13469179404Sobrien
13470218822Sdim/* Handle the .weakext pseudo-op as defined in Kane and Heinrich.  */
13471179404Sobrien
13472179404Sobrienstatic void
13473179404Sobriens_mips_weakext (int ignore ATTRIBUTE_UNUSED)
13474179404Sobrien{
13475179404Sobrien  char *name;
13476179404Sobrien  int c;
13477179404Sobrien  symbolS *symbolP;
13478179404Sobrien  expressionS exp;
13479179404Sobrien
13480179404Sobrien  name = input_line_pointer;
13481179404Sobrien  c = get_symbol_end ();
13482179404Sobrien  symbolP = symbol_find_or_make (name);
13483179404Sobrien  S_SET_WEAK (symbolP);
13484179404Sobrien  *input_line_pointer = c;
13485179404Sobrien
13486179404Sobrien  SKIP_WHITESPACE ();
13487179404Sobrien
13488179404Sobrien  if (! is_end_of_line[(unsigned char) *input_line_pointer])
13489179404Sobrien    {
13490179404Sobrien      if (S_IS_DEFINED (symbolP))
13491179404Sobrien	{
13492179404Sobrien	  as_bad ("ignoring attempt to redefine symbol %s",
13493179404Sobrien		  S_GET_NAME (symbolP));
13494179404Sobrien	  ignore_rest_of_line ();
13495179404Sobrien	  return;
13496179404Sobrien	}
13497179404Sobrien
13498179404Sobrien      if (*input_line_pointer == ',')
13499179404Sobrien	{
13500179404Sobrien	  ++input_line_pointer;
13501179404Sobrien	  SKIP_WHITESPACE ();
13502179404Sobrien	}
13503179404Sobrien
13504179404Sobrien      expression (&exp);
13505179404Sobrien      if (exp.X_op != O_symbol)
13506179404Sobrien	{
13507179404Sobrien	  as_bad ("bad .weakext directive");
13508179404Sobrien	  ignore_rest_of_line ();
13509179404Sobrien	  return;
13510179404Sobrien	}
13511179404Sobrien      symbol_set_value_expression (symbolP, &exp);
13512179404Sobrien    }
13513179404Sobrien
13514179404Sobrien  demand_empty_rest_of_line ();
13515179404Sobrien}
13516179404Sobrien
13517179404Sobrien/* Parse a register string into a number.  Called from the ECOFF code
13518179404Sobrien   to parse .frame.  The argument is non-zero if this is the frame
13519179404Sobrien   register, so that we can record it in mips_frame_reg.  */
13520179404Sobrien
13521179404Sobrienint
13522179404Sobrientc_get_register (int frame)
13523179404Sobrien{
13524218822Sdim  unsigned int reg;
13525179404Sobrien
13526179404Sobrien  SKIP_WHITESPACE ();
13527218822Sdim  if (! reg_lookup (&input_line_pointer, RWARN | RTYPE_NUM | RTYPE_GP, &reg))
13528218822Sdim    reg = 0;
13529179404Sobrien  if (frame)
13530179404Sobrien    {
13531179404Sobrien      mips_frame_reg = reg != 0 ? reg : SP;
13532179404Sobrien      mips_frame_reg_valid = 1;
13533179404Sobrien      mips_cprestore_valid = 0;
13534179404Sobrien    }
13535179404Sobrien  return reg;
13536179404Sobrien}
13537179404Sobrien
13538179404SobrienvalueT
13539179404Sobrienmd_section_align (asection *seg, valueT addr)
13540179404Sobrien{
13541179404Sobrien  int align = bfd_get_section_alignment (stdoutput, seg);
13542179404Sobrien
13543218822Sdim  if (IS_ELF)
13544218822Sdim    {
13545218822Sdim      /* We don't need to align ELF sections to the full alignment.
13546218822Sdim	 However, Irix 5 may prefer that we align them at least to a 16
13547218822Sdim	 byte boundary.  We don't bother to align the sections if we
13548218822Sdim	 are targeted for an embedded system.  */
13549218822Sdim      if (strcmp (TARGET_OS, "elf") == 0)
13550218822Sdim        return addr;
13551218822Sdim      if (align > 4)
13552218822Sdim        align = 4;
13553218822Sdim    }
13554179404Sobrien
13555179404Sobrien  return ((addr + (1 << align) - 1) & (-1 << align));
13556179404Sobrien}
13557179404Sobrien
13558179404Sobrien/* Utility routine, called from above as well.  If called while the
13559179404Sobrien   input file is still being read, it's only an approximation.  (For
13560179404Sobrien   example, a symbol may later become defined which appeared to be
13561179404Sobrien   undefined earlier.)  */
13562179404Sobrien
13563179404Sobrienstatic int
13564179404Sobriennopic_need_relax (symbolS *sym, int before_relaxing)
13565179404Sobrien{
13566179404Sobrien  if (sym == 0)
13567179404Sobrien    return 0;
13568179404Sobrien
13569208737Sjmallett  if (g_switch_value > 0)
13570179404Sobrien    {
13571179404Sobrien      const char *symname;
13572179404Sobrien      int change;
13573179404Sobrien
13574179404Sobrien      /* Find out whether this symbol can be referenced off the $gp
13575179404Sobrien	 register.  It can be if it is smaller than the -G size or if
13576179404Sobrien	 it is in the .sdata or .sbss section.  Certain symbols can
13577179404Sobrien	 not be referenced off the $gp, although it appears as though
13578179404Sobrien	 they can.  */
13579179404Sobrien      symname = S_GET_NAME (sym);
13580179404Sobrien      if (symname != (const char *) NULL
13581179404Sobrien	  && (strcmp (symname, "eprol") == 0
13582179404Sobrien	      || strcmp (symname, "etext") == 0
13583179404Sobrien	      || strcmp (symname, "_gp") == 0
13584179404Sobrien	      || strcmp (symname, "edata") == 0
13585179404Sobrien	      || strcmp (symname, "_fbss") == 0
13586179404Sobrien	      || strcmp (symname, "_fdata") == 0
13587179404Sobrien	      || strcmp (symname, "_ftext") == 0
13588179404Sobrien	      || strcmp (symname, "end") == 0
13589179404Sobrien	      || strcmp (symname, "_gp_disp") == 0))
13590179404Sobrien	change = 1;
13591179404Sobrien      else if ((! S_IS_DEFINED (sym) || S_IS_COMMON (sym))
13592179404Sobrien	       && (0
13593179404Sobrien#ifndef NO_ECOFF_DEBUGGING
13594179404Sobrien		   || (symbol_get_obj (sym)->ecoff_extern_size != 0
13595179404Sobrien		       && (symbol_get_obj (sym)->ecoff_extern_size
13596179404Sobrien			   <= g_switch_value))
13597179404Sobrien#endif
13598179404Sobrien		   /* We must defer this decision until after the whole
13599179404Sobrien		      file has been read, since there might be a .extern
13600179404Sobrien		      after the first use of this symbol.  */
13601179404Sobrien		   || (before_relaxing
13602179404Sobrien#ifndef NO_ECOFF_DEBUGGING
13603179404Sobrien		       && symbol_get_obj (sym)->ecoff_extern_size == 0
13604179404Sobrien#endif
13605179404Sobrien		       && S_GET_VALUE (sym) == 0)
13606179404Sobrien		   || (S_GET_VALUE (sym) != 0
13607179404Sobrien		       && S_GET_VALUE (sym) <= g_switch_value)))
13608179404Sobrien	change = 0;
13609179404Sobrien      else
13610179404Sobrien	{
13611179404Sobrien	  const char *segname;
13612179404Sobrien
13613179404Sobrien	  segname = segment_name (S_GET_SEGMENT (sym));
13614179404Sobrien	  assert (strcmp (segname, ".lit8") != 0
13615179404Sobrien		  && strcmp (segname, ".lit4") != 0);
13616179404Sobrien	  change = (strcmp (segname, ".sdata") != 0
13617179404Sobrien		    && strcmp (segname, ".sbss") != 0
13618179404Sobrien		    && strncmp (segname, ".sdata.", 7) != 0
13619218822Sdim		    && strncmp (segname, ".sbss.", 6) != 0
13620218822Sdim		    && strncmp (segname, ".gnu.linkonce.sb.", 17) != 0
13621179404Sobrien		    && strncmp (segname, ".gnu.linkonce.s.", 16) != 0);
13622179404Sobrien	}
13623179404Sobrien      return change;
13624179404Sobrien    }
13625179404Sobrien  else
13626179404Sobrien    /* We are not optimizing for the $gp register.  */
13627179404Sobrien    return 1;
13628179404Sobrien}
13629179404Sobrien
13630179404Sobrien
13631179404Sobrien/* Return true if the given symbol should be considered local for SVR4 PIC.  */
13632179404Sobrien
13633179404Sobrienstatic bfd_boolean
13634179404Sobrienpic_need_relax (symbolS *sym, asection *segtype)
13635179404Sobrien{
13636179404Sobrien  asection *symsec;
13637179404Sobrien
13638179404Sobrien  /* Handle the case of a symbol equated to another symbol.  */
13639179404Sobrien  while (symbol_equated_reloc_p (sym))
13640179404Sobrien    {
13641179404Sobrien      symbolS *n;
13642179404Sobrien
13643218822Sdim      /* It's possible to get a loop here in a badly written program.  */
13644179404Sobrien      n = symbol_get_value_expression (sym)->X_add_symbol;
13645179404Sobrien      if (n == sym)
13646179404Sobrien	break;
13647179404Sobrien      sym = n;
13648179404Sobrien    }
13649179404Sobrien
13650218822Sdim  if (symbol_section_p (sym))
13651218822Sdim    return TRUE;
13652218822Sdim
13653179404Sobrien  symsec = S_GET_SEGMENT (sym);
13654179404Sobrien
13655179404Sobrien  /* This must duplicate the test in adjust_reloc_syms.  */
13656179404Sobrien  return (symsec != &bfd_und_section
13657179404Sobrien	  && symsec != &bfd_abs_section
13658218822Sdim	  && !bfd_is_com_section (symsec)
13659218822Sdim	  && !s_is_linkonce (sym, segtype)
13660179404Sobrien#ifdef OBJ_ELF
13661179404Sobrien	  /* A global or weak symbol is treated as external.  */
13662218822Sdim	  && (!IS_ELF || (! S_IS_WEAK (sym) && ! S_IS_EXTERNAL (sym)))
13663179404Sobrien#endif
13664179404Sobrien	  );
13665179404Sobrien}
13666179404Sobrien
13667179404Sobrien
13668179404Sobrien/* Given a mips16 variant frag FRAGP, return non-zero if it needs an
13669179404Sobrien   extended opcode.  SEC is the section the frag is in.  */
13670179404Sobrien
13671179404Sobrienstatic int
13672179404Sobrienmips16_extended_frag (fragS *fragp, asection *sec, long stretch)
13673179404Sobrien{
13674179404Sobrien  int type;
13675218822Sdim  const struct mips16_immed_operand *op;
13676179404Sobrien  offsetT val;
13677179404Sobrien  int mintiny, maxtiny;
13678179404Sobrien  segT symsec;
13679179404Sobrien  fragS *sym_frag;
13680179404Sobrien
13681179404Sobrien  if (RELAX_MIPS16_USER_SMALL (fragp->fr_subtype))
13682179404Sobrien    return 0;
13683179404Sobrien  if (RELAX_MIPS16_USER_EXT (fragp->fr_subtype))
13684179404Sobrien    return 1;
13685179404Sobrien
13686179404Sobrien  type = RELAX_MIPS16_TYPE (fragp->fr_subtype);
13687179404Sobrien  op = mips16_immed_operands;
13688179404Sobrien  while (op->type != type)
13689179404Sobrien    {
13690179404Sobrien      ++op;
13691179404Sobrien      assert (op < mips16_immed_operands + MIPS16_NUM_IMMED);
13692179404Sobrien    }
13693179404Sobrien
13694179404Sobrien  if (op->unsp)
13695179404Sobrien    {
13696179404Sobrien      if (type == '<' || type == '>' || type == '[' || type == ']')
13697179404Sobrien	{
13698179404Sobrien	  mintiny = 1;
13699179404Sobrien	  maxtiny = 1 << op->nbits;
13700179404Sobrien	}
13701179404Sobrien      else
13702179404Sobrien	{
13703179404Sobrien	  mintiny = 0;
13704179404Sobrien	  maxtiny = (1 << op->nbits) - 1;
13705179404Sobrien	}
13706179404Sobrien    }
13707179404Sobrien  else
13708179404Sobrien    {
13709179404Sobrien      mintiny = - (1 << (op->nbits - 1));
13710179404Sobrien      maxtiny = (1 << (op->nbits - 1)) - 1;
13711179404Sobrien    }
13712179404Sobrien
13713179404Sobrien  sym_frag = symbol_get_frag (fragp->fr_symbol);
13714179404Sobrien  val = S_GET_VALUE (fragp->fr_symbol);
13715179404Sobrien  symsec = S_GET_SEGMENT (fragp->fr_symbol);
13716179404Sobrien
13717179404Sobrien  if (op->pcrel)
13718179404Sobrien    {
13719179404Sobrien      addressT addr;
13720179404Sobrien
13721179404Sobrien      /* We won't have the section when we are called from
13722179404Sobrien         mips_relax_frag.  However, we will always have been called
13723179404Sobrien         from md_estimate_size_before_relax first.  If this is a
13724179404Sobrien         branch to a different section, we mark it as such.  If SEC is
13725179404Sobrien         NULL, and the frag is not marked, then it must be a branch to
13726179404Sobrien         the same section.  */
13727179404Sobrien      if (sec == NULL)
13728179404Sobrien	{
13729179404Sobrien	  if (RELAX_MIPS16_LONG_BRANCH (fragp->fr_subtype))
13730179404Sobrien	    return 1;
13731179404Sobrien	}
13732179404Sobrien      else
13733179404Sobrien	{
13734179404Sobrien	  /* Must have been called from md_estimate_size_before_relax.  */
13735179404Sobrien	  if (symsec != sec)
13736179404Sobrien	    {
13737179404Sobrien	      fragp->fr_subtype =
13738179404Sobrien		RELAX_MIPS16_MARK_LONG_BRANCH (fragp->fr_subtype);
13739179404Sobrien
13740179404Sobrien	      /* FIXME: We should support this, and let the linker
13741179404Sobrien                 catch branches and loads that are out of range.  */
13742179404Sobrien	      as_bad_where (fragp->fr_file, fragp->fr_line,
13743179404Sobrien			    _("unsupported PC relative reference to different section"));
13744179404Sobrien
13745179404Sobrien	      return 1;
13746179404Sobrien	    }
13747179404Sobrien	  if (fragp != sym_frag && sym_frag->fr_address == 0)
13748179404Sobrien	    /* Assume non-extended on the first relaxation pass.
13749179404Sobrien	       The address we have calculated will be bogus if this is
13750179404Sobrien	       a forward branch to another frag, as the forward frag
13751179404Sobrien	       will have fr_address == 0.  */
13752179404Sobrien	    return 0;
13753179404Sobrien	}
13754179404Sobrien
13755179404Sobrien      /* In this case, we know for sure that the symbol fragment is in
13756179404Sobrien	 the same section.  If the relax_marker of the symbol fragment
13757179404Sobrien	 differs from the relax_marker of this fragment, we have not
13758179404Sobrien	 yet adjusted the symbol fragment fr_address.  We want to add
13759179404Sobrien	 in STRETCH in order to get a better estimate of the address.
13760179404Sobrien	 This particularly matters because of the shift bits.  */
13761179404Sobrien      if (stretch != 0
13762179404Sobrien	  && sym_frag->relax_marker != fragp->relax_marker)
13763179404Sobrien	{
13764179404Sobrien	  fragS *f;
13765179404Sobrien
13766179404Sobrien	  /* Adjust stretch for any alignment frag.  Note that if have
13767179404Sobrien             been expanding the earlier code, the symbol may be
13768179404Sobrien             defined in what appears to be an earlier frag.  FIXME:
13769179404Sobrien             This doesn't handle the fr_subtype field, which specifies
13770179404Sobrien             a maximum number of bytes to skip when doing an
13771179404Sobrien             alignment.  */
13772179404Sobrien	  for (f = fragp; f != NULL && f != sym_frag; f = f->fr_next)
13773179404Sobrien	    {
13774179404Sobrien	      if (f->fr_type == rs_align || f->fr_type == rs_align_code)
13775179404Sobrien		{
13776179404Sobrien		  if (stretch < 0)
13777179404Sobrien		    stretch = - ((- stretch)
13778179404Sobrien				 & ~ ((1 << (int) f->fr_offset) - 1));
13779179404Sobrien		  else
13780179404Sobrien		    stretch &= ~ ((1 << (int) f->fr_offset) - 1);
13781179404Sobrien		  if (stretch == 0)
13782179404Sobrien		    break;
13783179404Sobrien		}
13784179404Sobrien	    }
13785179404Sobrien	  if (f != NULL)
13786179404Sobrien	    val += stretch;
13787179404Sobrien	}
13788179404Sobrien
13789179404Sobrien      addr = fragp->fr_address + fragp->fr_fix;
13790179404Sobrien
13791179404Sobrien      /* The base address rules are complicated.  The base address of
13792179404Sobrien         a branch is the following instruction.  The base address of a
13793179404Sobrien         PC relative load or add is the instruction itself, but if it
13794179404Sobrien         is in a delay slot (in which case it can not be extended) use
13795179404Sobrien         the address of the instruction whose delay slot it is in.  */
13796179404Sobrien      if (type == 'p' || type == 'q')
13797179404Sobrien	{
13798179404Sobrien	  addr += 2;
13799179404Sobrien
13800179404Sobrien	  /* If we are currently assuming that this frag should be
13801179404Sobrien	     extended, then, the current address is two bytes
13802179404Sobrien	     higher.  */
13803179404Sobrien	  if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
13804179404Sobrien	    addr += 2;
13805179404Sobrien
13806179404Sobrien	  /* Ignore the low bit in the target, since it will be set
13807179404Sobrien             for a text label.  */
13808179404Sobrien	  if ((val & 1) != 0)
13809179404Sobrien	    --val;
13810179404Sobrien	}
13811179404Sobrien      else if (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype))
13812179404Sobrien	addr -= 4;
13813179404Sobrien      else if (RELAX_MIPS16_DSLOT (fragp->fr_subtype))
13814179404Sobrien	addr -= 2;
13815179404Sobrien
13816179404Sobrien      val -= addr & ~ ((1 << op->shift) - 1);
13817179404Sobrien
13818179404Sobrien      /* Branch offsets have an implicit 0 in the lowest bit.  */
13819179404Sobrien      if (type == 'p' || type == 'q')
13820179404Sobrien	val /= 2;
13821179404Sobrien
13822179404Sobrien      /* If any of the shifted bits are set, we must use an extended
13823179404Sobrien         opcode.  If the address depends on the size of this
13824179404Sobrien         instruction, this can lead to a loop, so we arrange to always
13825179404Sobrien         use an extended opcode.  We only check this when we are in
13826179404Sobrien         the main relaxation loop, when SEC is NULL.  */
13827179404Sobrien      if ((val & ((1 << op->shift) - 1)) != 0 && sec == NULL)
13828179404Sobrien	{
13829179404Sobrien	  fragp->fr_subtype =
13830179404Sobrien	    RELAX_MIPS16_MARK_LONG_BRANCH (fragp->fr_subtype);
13831179404Sobrien	  return 1;
13832179404Sobrien	}
13833179404Sobrien
13834179404Sobrien      /* If we are about to mark a frag as extended because the value
13835179404Sobrien         is precisely maxtiny + 1, then there is a chance of an
13836179404Sobrien         infinite loop as in the following code:
13837179404Sobrien	     la	$4,foo
13838179404Sobrien	     .skip	1020
13839179404Sobrien	     .align	2
13840179404Sobrien	   foo:
13841179404Sobrien	 In this case when the la is extended, foo is 0x3fc bytes
13842179404Sobrien	 away, so the la can be shrunk, but then foo is 0x400 away, so
13843179404Sobrien	 the la must be extended.  To avoid this loop, we mark the
13844179404Sobrien	 frag as extended if it was small, and is about to become
13845179404Sobrien	 extended with a value of maxtiny + 1.  */
13846179404Sobrien      if (val == ((maxtiny + 1) << op->shift)
13847179404Sobrien	  && ! RELAX_MIPS16_EXTENDED (fragp->fr_subtype)
13848179404Sobrien	  && sec == NULL)
13849179404Sobrien	{
13850179404Sobrien	  fragp->fr_subtype =
13851179404Sobrien	    RELAX_MIPS16_MARK_LONG_BRANCH (fragp->fr_subtype);
13852179404Sobrien	  return 1;
13853179404Sobrien	}
13854179404Sobrien    }
13855179404Sobrien  else if (symsec != absolute_section && sec != NULL)
13856179404Sobrien    as_bad_where (fragp->fr_file, fragp->fr_line, _("unsupported relocation"));
13857179404Sobrien
13858179404Sobrien  if ((val & ((1 << op->shift) - 1)) != 0
13859179404Sobrien      || val < (mintiny << op->shift)
13860179404Sobrien      || val > (maxtiny << op->shift))
13861179404Sobrien    return 1;
13862179404Sobrien  else
13863179404Sobrien    return 0;
13864179404Sobrien}
13865179404Sobrien
13866179404Sobrien/* Compute the length of a branch sequence, and adjust the
13867179404Sobrien   RELAX_BRANCH_TOOFAR bit accordingly.  If FRAGP is NULL, the
13868179404Sobrien   worst-case length is computed, with UPDATE being used to indicate
13869179404Sobrien   whether an unconditional (-1), branch-likely (+1) or regular (0)
13870179404Sobrien   branch is to be computed.  */
13871179404Sobrienstatic int
13872179404Sobrienrelaxed_branch_length (fragS *fragp, asection *sec, int update)
13873179404Sobrien{
13874179404Sobrien  bfd_boolean toofar;
13875179404Sobrien  int length;
13876179404Sobrien
13877179404Sobrien  if (fragp
13878179404Sobrien      && S_IS_DEFINED (fragp->fr_symbol)
13879179404Sobrien      && sec == S_GET_SEGMENT (fragp->fr_symbol))
13880179404Sobrien    {
13881179404Sobrien      addressT addr;
13882179404Sobrien      offsetT val;
13883179404Sobrien
13884179404Sobrien      val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset;
13885179404Sobrien
13886179404Sobrien      addr = fragp->fr_address + fragp->fr_fix + 4;
13887179404Sobrien
13888179404Sobrien      val -= addr;
13889179404Sobrien
13890179404Sobrien      toofar = val < - (0x8000 << 2) || val >= (0x8000 << 2);
13891179404Sobrien    }
13892179404Sobrien  else if (fragp)
13893179404Sobrien    /* If the symbol is not defined or it's in a different segment,
13894179404Sobrien       assume the user knows what's going on and emit a short
13895179404Sobrien       branch.  */
13896179404Sobrien    toofar = FALSE;
13897179404Sobrien  else
13898179404Sobrien    toofar = TRUE;
13899179404Sobrien
13900179404Sobrien  if (fragp && update && toofar != RELAX_BRANCH_TOOFAR (fragp->fr_subtype))
13901179404Sobrien    fragp->fr_subtype
13902179404Sobrien      = RELAX_BRANCH_ENCODE (RELAX_BRANCH_UNCOND (fragp->fr_subtype),
13903179404Sobrien			     RELAX_BRANCH_LIKELY (fragp->fr_subtype),
13904179404Sobrien			     RELAX_BRANCH_LINK (fragp->fr_subtype),
13905179404Sobrien			     toofar);
13906179404Sobrien
13907179404Sobrien  length = 4;
13908179404Sobrien  if (toofar)
13909179404Sobrien    {
13910179404Sobrien      if (fragp ? RELAX_BRANCH_LIKELY (fragp->fr_subtype) : (update > 0))
13911179404Sobrien	length += 8;
13912179404Sobrien
13913179404Sobrien      if (mips_pic != NO_PIC)
13914179404Sobrien	{
13915179404Sobrien	  /* Additional space for PIC loading of target address.  */
13916179404Sobrien	  length += 8;
13917179404Sobrien	  if (mips_opts.isa == ISA_MIPS1)
13918179404Sobrien	    /* Additional space for $at-stabilizing nop.  */
13919179404Sobrien	    length += 4;
13920179404Sobrien	}
13921179404Sobrien
13922179404Sobrien      /* If branch is conditional.  */
13923179404Sobrien      if (fragp ? !RELAX_BRANCH_UNCOND (fragp->fr_subtype) : (update >= 0))
13924179404Sobrien	length += 8;
13925179404Sobrien    }
13926179404Sobrien
13927179404Sobrien  return length;
13928179404Sobrien}
13929179404Sobrien
13930179404Sobrien/* Estimate the size of a frag before relaxing.  Unless this is the
13931179404Sobrien   mips16, we are not really relaxing here, and the final size is
13932179404Sobrien   encoded in the subtype information.  For the mips16, we have to
13933179404Sobrien   decide whether we are using an extended opcode or not.  */
13934179404Sobrien
13935179404Sobrienint
13936179404Sobrienmd_estimate_size_before_relax (fragS *fragp, asection *segtype)
13937179404Sobrien{
13938179404Sobrien  int change;
13939179404Sobrien
13940179404Sobrien  if (RELAX_BRANCH_P (fragp->fr_subtype))
13941179404Sobrien    {
13942179404Sobrien
13943179404Sobrien      fragp->fr_var = relaxed_branch_length (fragp, segtype, FALSE);
13944179404Sobrien
13945179404Sobrien      return fragp->fr_var;
13946179404Sobrien    }
13947179404Sobrien
13948179404Sobrien  if (RELAX_MIPS16_P (fragp->fr_subtype))
13949179404Sobrien    /* We don't want to modify the EXTENDED bit here; it might get us
13950179404Sobrien       into infinite loops.  We change it only in mips_relax_frag().  */
13951179404Sobrien    return (RELAX_MIPS16_EXTENDED (fragp->fr_subtype) ? 4 : 2);
13952179404Sobrien
13953179404Sobrien  if (mips_pic == NO_PIC)
13954179404Sobrien    change = nopic_need_relax (fragp->fr_symbol, 0);
13955179404Sobrien  else if (mips_pic == SVR4_PIC)
13956179404Sobrien    change = pic_need_relax (fragp->fr_symbol, segtype);
13957218822Sdim  else if (mips_pic == VXWORKS_PIC)
13958218822Sdim    /* For vxworks, GOT16 relocations never have a corresponding LO16.  */
13959218822Sdim    change = 0;
13960179404Sobrien  else
13961179404Sobrien    abort ();
13962179404Sobrien
13963179404Sobrien  if (change)
13964179404Sobrien    {
13965179404Sobrien      fragp->fr_subtype |= RELAX_USE_SECOND;
13966179404Sobrien      return -RELAX_FIRST (fragp->fr_subtype);
13967179404Sobrien    }
13968179404Sobrien  else
13969179404Sobrien    return -RELAX_SECOND (fragp->fr_subtype);
13970179404Sobrien}
13971179404Sobrien
13972179404Sobrien/* This is called to see whether a reloc against a defined symbol
13973208737Sjmallett   should be converted into a reloc against a section.  */
13974179404Sobrien
13975179404Sobrienint
13976179404Sobrienmips_fix_adjustable (fixS *fixp)
13977179404Sobrien{
13978179404Sobrien  if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
13979179404Sobrien      || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
13980179404Sobrien    return 0;
13981179404Sobrien
13982179404Sobrien  if (fixp->fx_addsy == NULL)
13983179404Sobrien    return 1;
13984179404Sobrien
13985185925Simp  /* If symbol SYM is in a mergeable section, relocations of the form
13986185925Simp     SYM + 0 can usually be made section-relative.  The mergeable data
13987185925Simp     is then identified by the section offset rather than by the symbol.
13988185925Simp
13989185925Simp     However, if we're generating REL LO16 relocations, the offset is split
13990185925Simp     between the LO16 and parterning high part relocation.  The linker will
13991185925Simp     need to recalculate the complete offset in order to correctly identify
13992185925Simp     the merge data.
13993185925Simp
13994185925Simp     The linker has traditionally not looked for the parterning high part
13995185925Simp     relocation, and has thus allowed orphaned R_MIPS_LO16 relocations to be
13996185925Simp     placed anywhere.  Rather than break backwards compatibility by changing
13997185925Simp     this, it seems better not to force the issue, and instead keep the
13998185925Simp     original symbol.  This will work with either linker behavior.  */
13999185925Simp  if ((fixp->fx_r_type == BFD_RELOC_LO16
14000218822Sdim       || fixp->fx_r_type == BFD_RELOC_MIPS16_LO16
14001185925Simp       || reloc_needs_lo_p (fixp->fx_r_type))
14002185925Simp      && HAVE_IN_PLACE_ADDENDS
14003185925Simp      && (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE) != 0)
14004185925Simp    return 0;
14005185925Simp
14006179404Sobrien#ifdef OBJ_ELF
14007218822Sdim  /* R_MIPS16_26 relocations against non-MIPS16 functions might resolve
14008218822Sdim     to a floating-point stub.  The same is true for non-R_MIPS16_26
14009218822Sdim     relocations against MIPS16 functions; in this case, the stub becomes
14010218822Sdim     the function's canonical address.
14011218822Sdim
14012218822Sdim     Floating-point stubs are stored in unique .mips16.call.* or
14013218822Sdim     .mips16.fn.* sections.  If a stub T for function F is in section S,
14014218822Sdim     the first relocation in section S must be against F; this is how the
14015218822Sdim     linker determines the target function.  All relocations that might
14016218822Sdim     resolve to T must also be against F.  We therefore have the following
14017218822Sdim     restrictions, which are given in an intentionally-redundant way:
14018218822Sdim
14019218822Sdim       1. We cannot reduce R_MIPS16_26 relocations against non-MIPS16
14020218822Sdim	  symbols.
14021218822Sdim
14022218822Sdim       2. We cannot reduce a stub's relocations against non-MIPS16 symbols
14023218822Sdim	  if that stub might be used.
14024218822Sdim
14025218822Sdim       3. We cannot reduce non-R_MIPS16_26 relocations against MIPS16
14026218822Sdim	  symbols.
14027218822Sdim
14028218822Sdim       4. We cannot reduce a stub's relocations against MIPS16 symbols if
14029218822Sdim	  that stub might be used.
14030218822Sdim
14031218822Sdim     There is a further restriction:
14032218822Sdim
14033218822Sdim       5. We cannot reduce R_MIPS16_26 relocations against MIPS16 symbols
14034218822Sdim	  on targets with in-place addends; the relocation field cannot
14035218822Sdim	  encode the low bit.
14036218822Sdim
14037218822Sdim     For simplicity, we deal with (3)-(5) by not reducing _any_ relocation
14038218822Sdim     against a MIPS16 symbol.
14039218822Sdim
14040218822Sdim     We deal with (1)-(2) by saying that, if there's a R_MIPS16_26
14041218822Sdim     relocation against some symbol R, no relocation against R may be
14042218822Sdim     reduced.  (Note that this deals with (2) as well as (1) because
14043218822Sdim     relocations against global symbols will never be reduced on ELF
14044218822Sdim     targets.)  This approach is a little simpler than trying to detect
14045218822Sdim     stub sections, and gives the "all or nothing" per-symbol consistency
14046218822Sdim     that we have for MIPS16 symbols.  */
14047218822Sdim  if (IS_ELF
14048218822Sdim      && fixp->fx_subsy == NULL
14049218822Sdim      && (S_GET_OTHER (fixp->fx_addsy) == STO_MIPS16
14050218822Sdim	  || *symbol_get_tc (fixp->fx_addsy)))
14051179404Sobrien    return 0;
14052179404Sobrien#endif
14053179404Sobrien
14054179404Sobrien  return 1;
14055179404Sobrien}
14056179404Sobrien
14057179404Sobrien/* Translate internal representation of relocation info to BFD target
14058179404Sobrien   format.  */
14059179404Sobrien
14060179404Sobrienarelent **
14061179404Sobrientc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
14062179404Sobrien{
14063179404Sobrien  static arelent *retval[4];
14064179404Sobrien  arelent *reloc;
14065179404Sobrien  bfd_reloc_code_real_type code;
14066179404Sobrien
14067179404Sobrien  memset (retval, 0, sizeof(retval));
14068179404Sobrien  reloc = retval[0] = (arelent *) xcalloc (1, sizeof (arelent));
14069179404Sobrien  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
14070179404Sobrien  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
14071179404Sobrien  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
14072179404Sobrien
14073208737Sjmallett  if (fixp->fx_pcrel)
14074179404Sobrien    {
14075208737Sjmallett      assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2);
14076179404Sobrien
14077208737Sjmallett      /* At this point, fx_addnumber is "symbol offset - pcrel address".
14078208737Sjmallett	 Relocations want only the symbol offset.  */
14079208737Sjmallett      reloc->addend = fixp->fx_addnumber + reloc->address;
14080218822Sdim      if (!IS_ELF)
14081179404Sobrien	{
14082208737Sjmallett	  /* A gruesome hack which is a result of the gruesome gas
14083208737Sjmallett	     reloc handling.  What's worse, for COFF (as opposed to
14084208737Sjmallett	     ECOFF), we might need yet another copy of reloc->address.
14085208737Sjmallett	     See bfd_install_relocation.  */
14086208737Sjmallett	  reloc->addend += reloc->address;
14087179404Sobrien	}
14088179404Sobrien    }
14089179404Sobrien  else
14090179404Sobrien    reloc->addend = fixp->fx_addnumber;
14091179404Sobrien
14092179404Sobrien  /* Since the old MIPS ELF ABI uses Rel instead of Rela, encode the vtable
14093179404Sobrien     entry to be used in the relocation's section offset.  */
14094179404Sobrien  if (! HAVE_NEWABI && fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
14095179404Sobrien    {
14096179404Sobrien      reloc->address = reloc->addend;
14097179404Sobrien      reloc->addend = 0;
14098179404Sobrien    }
14099179404Sobrien
14100179404Sobrien  code = fixp->fx_r_type;
14101179404Sobrien
14102208737Sjmallett  reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
14103179404Sobrien  if (reloc->howto == NULL)
14104179404Sobrien    {
14105179404Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
14106179404Sobrien		    _("Can not represent %s relocation in this object file format"),
14107179404Sobrien		    bfd_get_reloc_code_name (code));
14108179404Sobrien      retval[0] = NULL;
14109179404Sobrien    }
14110179404Sobrien
14111179404Sobrien  return retval;
14112179404Sobrien}
14113179404Sobrien
14114179404Sobrien/* Relax a machine dependent frag.  This returns the amount by which
14115179404Sobrien   the current size of the frag should change.  */
14116179404Sobrien
14117179404Sobrienint
14118179404Sobrienmips_relax_frag (asection *sec, fragS *fragp, long stretch)
14119179404Sobrien{
14120179404Sobrien  if (RELAX_BRANCH_P (fragp->fr_subtype))
14121179404Sobrien    {
14122179404Sobrien      offsetT old_var = fragp->fr_var;
14123179404Sobrien
14124179404Sobrien      fragp->fr_var = relaxed_branch_length (fragp, sec, TRUE);
14125179404Sobrien
14126179404Sobrien      return fragp->fr_var - old_var;
14127179404Sobrien    }
14128179404Sobrien
14129179404Sobrien  if (! RELAX_MIPS16_P (fragp->fr_subtype))
14130179404Sobrien    return 0;
14131179404Sobrien
14132179404Sobrien  if (mips16_extended_frag (fragp, NULL, stretch))
14133179404Sobrien    {
14134179404Sobrien      if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
14135179404Sobrien	return 0;
14136179404Sobrien      fragp->fr_subtype = RELAX_MIPS16_MARK_EXTENDED (fragp->fr_subtype);
14137179404Sobrien      return 2;
14138179404Sobrien    }
14139179404Sobrien  else
14140179404Sobrien    {
14141179404Sobrien      if (! RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
14142179404Sobrien	return 0;
14143179404Sobrien      fragp->fr_subtype = RELAX_MIPS16_CLEAR_EXTENDED (fragp->fr_subtype);
14144179404Sobrien      return -2;
14145179404Sobrien    }
14146179404Sobrien
14147179404Sobrien  return 0;
14148179404Sobrien}
14149179404Sobrien
14150179404Sobrien/* Convert a machine dependent frag.  */
14151179404Sobrien
14152179404Sobrienvoid
14153179404Sobrienmd_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
14154179404Sobrien{
14155179404Sobrien  if (RELAX_BRANCH_P (fragp->fr_subtype))
14156179404Sobrien    {
14157179404Sobrien      bfd_byte *buf;
14158179404Sobrien      unsigned long insn;
14159179404Sobrien      expressionS exp;
14160179404Sobrien      fixS *fixp;
14161179404Sobrien
14162179404Sobrien      buf = (bfd_byte *)fragp->fr_literal + fragp->fr_fix;
14163179404Sobrien
14164179404Sobrien      if (target_big_endian)
14165179404Sobrien	insn = bfd_getb32 (buf);
14166179404Sobrien      else
14167179404Sobrien	insn = bfd_getl32 (buf);
14168179404Sobrien
14169179404Sobrien      if (!RELAX_BRANCH_TOOFAR (fragp->fr_subtype))
14170179404Sobrien	{
14171179404Sobrien	  /* We generate a fixup instead of applying it right now
14172179404Sobrien	     because, if there are linker relaxations, we're going to
14173179404Sobrien	     need the relocations.  */
14174179404Sobrien	  exp.X_op = O_symbol;
14175179404Sobrien	  exp.X_add_symbol = fragp->fr_symbol;
14176179404Sobrien	  exp.X_add_number = fragp->fr_offset;
14177179404Sobrien
14178179404Sobrien	  fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
14179218822Sdim			      4, &exp, TRUE, BFD_RELOC_16_PCREL_S2);
14180179404Sobrien	  fixp->fx_file = fragp->fr_file;
14181179404Sobrien	  fixp->fx_line = fragp->fr_line;
14182179404Sobrien
14183208737Sjmallett	  md_number_to_chars ((char *) buf, insn, 4);
14184179404Sobrien	  buf += 4;
14185179404Sobrien	}
14186179404Sobrien      else
14187179404Sobrien	{
14188179404Sobrien	  int i;
14189179404Sobrien
14190179404Sobrien	  as_warn_where (fragp->fr_file, fragp->fr_line,
14191179404Sobrien			 _("relaxed out-of-range branch into a jump"));
14192179404Sobrien
14193179404Sobrien	  if (RELAX_BRANCH_UNCOND (fragp->fr_subtype))
14194179404Sobrien	    goto uncond;
14195179404Sobrien
14196179404Sobrien	  if (!RELAX_BRANCH_LIKELY (fragp->fr_subtype))
14197179404Sobrien	    {
14198179404Sobrien	      /* Reverse the branch.  */
14199179404Sobrien	      switch ((insn >> 28) & 0xf)
14200179404Sobrien		{
14201179404Sobrien		case 4:
14202179404Sobrien		  /* bc[0-3][tf]l? and bc1any[24][ft] instructions can
14203179404Sobrien		     have the condition reversed by tweaking a single
14204179404Sobrien		     bit, and their opcodes all have 0x4???????.  */
14205179404Sobrien		  assert ((insn & 0xf1000000) == 0x41000000);
14206179404Sobrien		  insn ^= 0x00010000;
14207179404Sobrien		  break;
14208179404Sobrien
14209179404Sobrien		case 0:
14210179404Sobrien		  /* bltz	0x04000000	bgez	0x04010000
14211218822Sdim		     bltzal	0x04100000	bgezal	0x04110000  */
14212179404Sobrien		  assert ((insn & 0xfc0e0000) == 0x04000000);
14213179404Sobrien		  insn ^= 0x00010000;
14214179404Sobrien		  break;
14215179404Sobrien
14216179404Sobrien		case 1:
14217179404Sobrien		  /* beq	0x10000000	bne	0x14000000
14218218822Sdim		     blez	0x18000000	bgtz	0x1c000000  */
14219179404Sobrien		  insn ^= 0x04000000;
14220179404Sobrien		  break;
14221179404Sobrien
14222179404Sobrien		default:
14223179404Sobrien		  abort ();
14224179404Sobrien		}
14225179404Sobrien	    }
14226179404Sobrien
14227179404Sobrien	  if (RELAX_BRANCH_LINK (fragp->fr_subtype))
14228179404Sobrien	    {
14229179404Sobrien	      /* Clear the and-link bit.  */
14230179404Sobrien	      assert ((insn & 0xfc1c0000) == 0x04100000);
14231179404Sobrien
14232218822Sdim	      /* bltzal		0x04100000	bgezal	0x04110000
14233218822Sdim		 bltzall	0x04120000	bgezall	0x04130000  */
14234179404Sobrien	      insn &= ~0x00100000;
14235179404Sobrien	    }
14236179404Sobrien
14237179404Sobrien	  /* Branch over the branch (if the branch was likely) or the
14238179404Sobrien	     full jump (not likely case).  Compute the offset from the
14239179404Sobrien	     current instruction to branch to.  */
14240179404Sobrien	  if (RELAX_BRANCH_LIKELY (fragp->fr_subtype))
14241179404Sobrien	    i = 16;
14242179404Sobrien	  else
14243179404Sobrien	    {
14244179404Sobrien	      /* How many bytes in instructions we've already emitted?  */
14245179404Sobrien	      i = buf - (bfd_byte *)fragp->fr_literal - fragp->fr_fix;
14246179404Sobrien	      /* How many bytes in instructions from here to the end?  */
14247179404Sobrien	      i = fragp->fr_var - i;
14248179404Sobrien	    }
14249179404Sobrien	  /* Convert to instruction count.  */
14250179404Sobrien	  i >>= 2;
14251179404Sobrien	  /* Branch counts from the next instruction.  */
14252179404Sobrien	  i--;
14253179404Sobrien	  insn |= i;
14254179404Sobrien	  /* Branch over the jump.  */
14255208737Sjmallett	  md_number_to_chars ((char *) buf, insn, 4);
14256179404Sobrien	  buf += 4;
14257179404Sobrien
14258218822Sdim	  /* nop */
14259208737Sjmallett	  md_number_to_chars ((char *) buf, 0, 4);
14260179404Sobrien	  buf += 4;
14261179404Sobrien
14262179404Sobrien	  if (RELAX_BRANCH_LIKELY (fragp->fr_subtype))
14263179404Sobrien	    {
14264179404Sobrien	      /* beql $0, $0, 2f */
14265179404Sobrien	      insn = 0x50000000;
14266179404Sobrien	      /* Compute the PC offset from the current instruction to
14267179404Sobrien		 the end of the variable frag.  */
14268179404Sobrien	      /* How many bytes in instructions we've already emitted?  */
14269179404Sobrien	      i = buf - (bfd_byte *)fragp->fr_literal - fragp->fr_fix;
14270179404Sobrien	      /* How many bytes in instructions from here to the end?  */
14271179404Sobrien	      i = fragp->fr_var - i;
14272179404Sobrien	      /* Convert to instruction count.  */
14273179404Sobrien	      i >>= 2;
14274179404Sobrien	      /* Don't decrement i, because we want to branch over the
14275179404Sobrien		 delay slot.  */
14276179404Sobrien
14277179404Sobrien	      insn |= i;
14278208737Sjmallett	      md_number_to_chars ((char *) buf, insn, 4);
14279179404Sobrien	      buf += 4;
14280179404Sobrien
14281208737Sjmallett	      md_number_to_chars ((char *) buf, 0, 4);
14282179404Sobrien	      buf += 4;
14283179404Sobrien	    }
14284179404Sobrien
14285179404Sobrien	uncond:
14286179404Sobrien	  if (mips_pic == NO_PIC)
14287179404Sobrien	    {
14288179404Sobrien	      /* j or jal.  */
14289179404Sobrien	      insn = (RELAX_BRANCH_LINK (fragp->fr_subtype)
14290179404Sobrien		      ? 0x0c000000 : 0x08000000);
14291179404Sobrien	      exp.X_op = O_symbol;
14292179404Sobrien	      exp.X_add_symbol = fragp->fr_symbol;
14293179404Sobrien	      exp.X_add_number = fragp->fr_offset;
14294179404Sobrien
14295179404Sobrien	      fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
14296218822Sdim				  4, &exp, FALSE, BFD_RELOC_MIPS_JMP);
14297179404Sobrien	      fixp->fx_file = fragp->fr_file;
14298179404Sobrien	      fixp->fx_line = fragp->fr_line;
14299179404Sobrien
14300208737Sjmallett	      md_number_to_chars ((char *) buf, insn, 4);
14301179404Sobrien	      buf += 4;
14302179404Sobrien	    }
14303179404Sobrien	  else
14304179404Sobrien	    {
14305179404Sobrien	      /* lw/ld $at, <sym>($gp)  R_MIPS_GOT16 */
14306179404Sobrien	      insn = HAVE_64BIT_ADDRESSES ? 0xdf810000 : 0x8f810000;
14307179404Sobrien	      exp.X_op = O_symbol;
14308179404Sobrien	      exp.X_add_symbol = fragp->fr_symbol;
14309179404Sobrien	      exp.X_add_number = fragp->fr_offset;
14310179404Sobrien
14311179404Sobrien	      if (fragp->fr_offset)
14312179404Sobrien		{
14313179404Sobrien		  exp.X_add_symbol = make_expr_symbol (&exp);
14314179404Sobrien		  exp.X_add_number = 0;
14315179404Sobrien		}
14316179404Sobrien
14317179404Sobrien	      fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
14318218822Sdim				  4, &exp, FALSE, BFD_RELOC_MIPS_GOT16);
14319179404Sobrien	      fixp->fx_file = fragp->fr_file;
14320179404Sobrien	      fixp->fx_line = fragp->fr_line;
14321179404Sobrien
14322208737Sjmallett	      md_number_to_chars ((char *) buf, insn, 4);
14323179404Sobrien	      buf += 4;
14324179404Sobrien
14325179404Sobrien	      if (mips_opts.isa == ISA_MIPS1)
14326179404Sobrien		{
14327179404Sobrien		  /* nop */
14328208737Sjmallett		  md_number_to_chars ((char *) buf, 0, 4);
14329179404Sobrien		  buf += 4;
14330179404Sobrien		}
14331179404Sobrien
14332179404Sobrien	      /* d/addiu $at, $at, <sym>  R_MIPS_LO16 */
14333179404Sobrien	      insn = HAVE_64BIT_ADDRESSES ? 0x64210000 : 0x24210000;
14334179404Sobrien
14335179404Sobrien	      fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
14336218822Sdim				  4, &exp, FALSE, BFD_RELOC_LO16);
14337179404Sobrien	      fixp->fx_file = fragp->fr_file;
14338179404Sobrien	      fixp->fx_line = fragp->fr_line;
14339179404Sobrien
14340208737Sjmallett	      md_number_to_chars ((char *) buf, insn, 4);
14341179404Sobrien	      buf += 4;
14342179404Sobrien
14343179404Sobrien	      /* j(al)r $at.  */
14344179404Sobrien	      if (RELAX_BRANCH_LINK (fragp->fr_subtype))
14345179404Sobrien		insn = 0x0020f809;
14346179404Sobrien	      else
14347179404Sobrien		insn = 0x00200008;
14348179404Sobrien
14349208737Sjmallett	      md_number_to_chars ((char *) buf, insn, 4);
14350179404Sobrien	      buf += 4;
14351179404Sobrien	    }
14352179404Sobrien	}
14353179404Sobrien
14354179404Sobrien      assert (buf == (bfd_byte *)fragp->fr_literal
14355179404Sobrien	      + fragp->fr_fix + fragp->fr_var);
14356179404Sobrien
14357179404Sobrien      fragp->fr_fix += fragp->fr_var;
14358179404Sobrien
14359179404Sobrien      return;
14360179404Sobrien    }
14361179404Sobrien
14362179404Sobrien  if (RELAX_MIPS16_P (fragp->fr_subtype))
14363179404Sobrien    {
14364179404Sobrien      int type;
14365218822Sdim      const struct mips16_immed_operand *op;
14366179404Sobrien      bfd_boolean small, ext;
14367179404Sobrien      offsetT val;
14368179404Sobrien      bfd_byte *buf;
14369179404Sobrien      unsigned long insn;
14370179404Sobrien      bfd_boolean use_extend;
14371179404Sobrien      unsigned short extend;
14372179404Sobrien
14373179404Sobrien      type = RELAX_MIPS16_TYPE (fragp->fr_subtype);
14374179404Sobrien      op = mips16_immed_operands;
14375179404Sobrien      while (op->type != type)
14376179404Sobrien	++op;
14377179404Sobrien
14378179404Sobrien      if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
14379179404Sobrien	{
14380179404Sobrien	  small = FALSE;
14381179404Sobrien	  ext = TRUE;
14382179404Sobrien	}
14383179404Sobrien      else
14384179404Sobrien	{
14385179404Sobrien	  small = TRUE;
14386179404Sobrien	  ext = FALSE;
14387179404Sobrien	}
14388179404Sobrien
14389179404Sobrien      resolve_symbol_value (fragp->fr_symbol);
14390179404Sobrien      val = S_GET_VALUE (fragp->fr_symbol);
14391179404Sobrien      if (op->pcrel)
14392179404Sobrien	{
14393179404Sobrien	  addressT addr;
14394179404Sobrien
14395179404Sobrien	  addr = fragp->fr_address + fragp->fr_fix;
14396179404Sobrien
14397179404Sobrien	  /* The rules for the base address of a PC relative reloc are
14398179404Sobrien             complicated; see mips16_extended_frag.  */
14399179404Sobrien	  if (type == 'p' || type == 'q')
14400179404Sobrien	    {
14401179404Sobrien	      addr += 2;
14402179404Sobrien	      if (ext)
14403179404Sobrien		addr += 2;
14404179404Sobrien	      /* Ignore the low bit in the target, since it will be
14405179404Sobrien                 set for a text label.  */
14406179404Sobrien	      if ((val & 1) != 0)
14407179404Sobrien		--val;
14408179404Sobrien	    }
14409179404Sobrien	  else if (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype))
14410179404Sobrien	    addr -= 4;
14411179404Sobrien	  else if (RELAX_MIPS16_DSLOT (fragp->fr_subtype))
14412179404Sobrien	    addr -= 2;
14413179404Sobrien
14414179404Sobrien	  addr &= ~ (addressT) ((1 << op->shift) - 1);
14415179404Sobrien	  val -= addr;
14416179404Sobrien
14417179404Sobrien	  /* Make sure the section winds up with the alignment we have
14418179404Sobrien             assumed.  */
14419179404Sobrien	  if (op->shift > 0)
14420179404Sobrien	    record_alignment (asec, op->shift);
14421179404Sobrien	}
14422179404Sobrien
14423179404Sobrien      if (ext
14424179404Sobrien	  && (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype)
14425179404Sobrien	      || RELAX_MIPS16_DSLOT (fragp->fr_subtype)))
14426179404Sobrien	as_warn_where (fragp->fr_file, fragp->fr_line,
14427179404Sobrien		       _("extended instruction in delay slot"));
14428179404Sobrien
14429179404Sobrien      buf = (bfd_byte *) (fragp->fr_literal + fragp->fr_fix);
14430179404Sobrien
14431179404Sobrien      if (target_big_endian)
14432179404Sobrien	insn = bfd_getb16 (buf);
14433179404Sobrien      else
14434179404Sobrien	insn = bfd_getl16 (buf);
14435179404Sobrien
14436179404Sobrien      mips16_immed (fragp->fr_file, fragp->fr_line, type, val,
14437179404Sobrien		    RELAX_MIPS16_USER_EXT (fragp->fr_subtype),
14438179404Sobrien		    small, ext, &insn, &use_extend, &extend);
14439179404Sobrien
14440179404Sobrien      if (use_extend)
14441179404Sobrien	{
14442208737Sjmallett	  md_number_to_chars ((char *) buf, 0xf000 | extend, 2);
14443179404Sobrien	  fragp->fr_fix += 2;
14444179404Sobrien	  buf += 2;
14445179404Sobrien	}
14446179404Sobrien
14447208737Sjmallett      md_number_to_chars ((char *) buf, insn, 2);
14448179404Sobrien      fragp->fr_fix += 2;
14449179404Sobrien      buf += 2;
14450179404Sobrien    }
14451179404Sobrien  else
14452179404Sobrien    {
14453179404Sobrien      int first, second;
14454179404Sobrien      fixS *fixp;
14455179404Sobrien
14456179404Sobrien      first = RELAX_FIRST (fragp->fr_subtype);
14457179404Sobrien      second = RELAX_SECOND (fragp->fr_subtype);
14458179404Sobrien      fixp = (fixS *) fragp->fr_opcode;
14459179404Sobrien
14460179404Sobrien      /* Possibly emit a warning if we've chosen the longer option.  */
14461179404Sobrien      if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0)
14462179404Sobrien	  == ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0))
14463179404Sobrien	{
14464179404Sobrien	  const char *msg = macro_warning (fragp->fr_subtype);
14465179404Sobrien	  if (msg != 0)
14466179404Sobrien	    as_warn_where (fragp->fr_file, fragp->fr_line, msg);
14467179404Sobrien	}
14468179404Sobrien
14469179404Sobrien      /* Go through all the fixups for the first sequence.  Disable them
14470179404Sobrien	 (by marking them as done) if we're going to use the second
14471179404Sobrien	 sequence instead.  */
14472179404Sobrien      while (fixp
14473179404Sobrien	     && fixp->fx_frag == fragp
14474179404Sobrien	     && fixp->fx_where < fragp->fr_fix - second)
14475179404Sobrien	{
14476179404Sobrien	  if (fragp->fr_subtype & RELAX_USE_SECOND)
14477179404Sobrien	    fixp->fx_done = 1;
14478179404Sobrien	  fixp = fixp->fx_next;
14479179404Sobrien	}
14480179404Sobrien
14481179404Sobrien      /* Go through the fixups for the second sequence.  Disable them if
14482179404Sobrien	 we're going to use the first sequence, otherwise adjust their
14483179404Sobrien	 addresses to account for the relaxation.  */
14484179404Sobrien      while (fixp && fixp->fx_frag == fragp)
14485179404Sobrien	{
14486179404Sobrien	  if (fragp->fr_subtype & RELAX_USE_SECOND)
14487179404Sobrien	    fixp->fx_where -= first;
14488179404Sobrien	  else
14489179404Sobrien	    fixp->fx_done = 1;
14490179404Sobrien	  fixp = fixp->fx_next;
14491179404Sobrien	}
14492179404Sobrien
14493179404Sobrien      /* Now modify the frag contents.  */
14494179404Sobrien      if (fragp->fr_subtype & RELAX_USE_SECOND)
14495179404Sobrien	{
14496179404Sobrien	  char *start;
14497179404Sobrien
14498179404Sobrien	  start = fragp->fr_literal + fragp->fr_fix - first - second;
14499179404Sobrien	  memmove (start, start + first, second);
14500179404Sobrien	  fragp->fr_fix -= first;
14501179404Sobrien	}
14502179404Sobrien      else
14503179404Sobrien	fragp->fr_fix -= second;
14504179404Sobrien    }
14505179404Sobrien}
14506179404Sobrien
14507179404Sobrien#ifdef OBJ_ELF
14508179404Sobrien
14509179404Sobrien/* This function is called after the relocs have been generated.
14510179404Sobrien   We've been storing mips16 text labels as odd.  Here we convert them
14511179404Sobrien   back to even for the convenience of the debugger.  */
14512179404Sobrien
14513179404Sobrienvoid
14514179404Sobrienmips_frob_file_after_relocs (void)
14515179404Sobrien{
14516179404Sobrien  asymbol **syms;
14517179404Sobrien  unsigned int count, i;
14518179404Sobrien
14519218822Sdim  if (!IS_ELF)
14520179404Sobrien    return;
14521179404Sobrien
14522179404Sobrien  syms = bfd_get_outsymbols (stdoutput);
14523179404Sobrien  count = bfd_get_symcount (stdoutput);
14524179404Sobrien  for (i = 0; i < count; i++, syms++)
14525179404Sobrien    {
14526179404Sobrien      if (elf_symbol (*syms)->internal_elf_sym.st_other == STO_MIPS16
14527179404Sobrien	  && ((*syms)->value & 1) != 0)
14528179404Sobrien	{
14529179404Sobrien	  (*syms)->value &= ~1;
14530179404Sobrien	  /* If the symbol has an odd size, it was probably computed
14531179404Sobrien	     incorrectly, so adjust that as well.  */
14532179404Sobrien	  if ((elf_symbol (*syms)->internal_elf_sym.st_size & 1) != 0)
14533179404Sobrien	    ++elf_symbol (*syms)->internal_elf_sym.st_size;
14534179404Sobrien	}
14535179404Sobrien    }
14536179404Sobrien}
14537179404Sobrien
14538179404Sobrien#endif
14539179404Sobrien
14540179404Sobrien/* This function is called whenever a label is defined.  It is used
14541179404Sobrien   when handling branch delays; if a branch has a label, we assume we
14542179404Sobrien   can not move it.  */
14543179404Sobrien
14544179404Sobrienvoid
14545179404Sobrienmips_define_label (symbolS *sym)
14546179404Sobrien{
14547218822Sdim  segment_info_type *si = seg_info (now_seg);
14548179404Sobrien  struct insn_label_list *l;
14549179404Sobrien
14550179404Sobrien  if (free_insn_labels == NULL)
14551179404Sobrien    l = (struct insn_label_list *) xmalloc (sizeof *l);
14552179404Sobrien  else
14553179404Sobrien    {
14554179404Sobrien      l = free_insn_labels;
14555179404Sobrien      free_insn_labels = l->next;
14556179404Sobrien    }
14557179404Sobrien
14558179404Sobrien  l->label = sym;
14559218822Sdim  l->next = si->label_list;
14560218822Sdim  si->label_list = l;
14561218822Sdim
14562218822Sdim#ifdef OBJ_ELF
14563218822Sdim  dwarf2_emit_label (sym);
14564218822Sdim#endif
14565179404Sobrien}
14566179404Sobrien
14567179404Sobrien#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
14568179404Sobrien
14569179404Sobrien/* Some special processing for a MIPS ELF file.  */
14570179404Sobrien
14571179404Sobrienvoid
14572179404Sobrienmips_elf_final_processing (void)
14573179404Sobrien{
14574179404Sobrien  /* Write out the register information.  */
14575179404Sobrien  if (mips_abi != N64_ABI)
14576179404Sobrien    {
14577179404Sobrien      Elf32_RegInfo s;
14578179404Sobrien
14579179404Sobrien      s.ri_gprmask = mips_gprmask;
14580179404Sobrien      s.ri_cprmask[0] = mips_cprmask[0];
14581179404Sobrien      s.ri_cprmask[1] = mips_cprmask[1];
14582179404Sobrien      s.ri_cprmask[2] = mips_cprmask[2];
14583179404Sobrien      s.ri_cprmask[3] = mips_cprmask[3];
14584179404Sobrien      /* The gp_value field is set by the MIPS ELF backend.  */
14585179404Sobrien
14586179404Sobrien      bfd_mips_elf32_swap_reginfo_out (stdoutput, &s,
14587179404Sobrien				       ((Elf32_External_RegInfo *)
14588179404Sobrien					mips_regmask_frag));
14589179404Sobrien    }
14590179404Sobrien  else
14591179404Sobrien    {
14592179404Sobrien      Elf64_Internal_RegInfo s;
14593179404Sobrien
14594179404Sobrien      s.ri_gprmask = mips_gprmask;
14595179404Sobrien      s.ri_pad = 0;
14596179404Sobrien      s.ri_cprmask[0] = mips_cprmask[0];
14597179404Sobrien      s.ri_cprmask[1] = mips_cprmask[1];
14598179404Sobrien      s.ri_cprmask[2] = mips_cprmask[2];
14599179404Sobrien      s.ri_cprmask[3] = mips_cprmask[3];
14600179404Sobrien      /* The gp_value field is set by the MIPS ELF backend.  */
14601179404Sobrien
14602179404Sobrien      bfd_mips_elf64_swap_reginfo_out (stdoutput, &s,
14603179404Sobrien				       ((Elf64_External_RegInfo *)
14604179404Sobrien					mips_regmask_frag));
14605179404Sobrien    }
14606179404Sobrien
14607179404Sobrien  /* Set the MIPS ELF flag bits.  FIXME: There should probably be some
14608179404Sobrien     sort of BFD interface for this.  */
14609179404Sobrien  if (mips_any_noreorder)
14610179404Sobrien    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_NOREORDER;
14611179404Sobrien  if (mips_pic != NO_PIC)
14612179404Sobrien    {
14613179404Sobrien    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_PIC;
14614179404Sobrien      elf_elfheader (stdoutput)->e_flags |= EF_MIPS_CPIC;
14615179404Sobrien    }
14616179404Sobrien  if (mips_abicalls)
14617179404Sobrien    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_CPIC;
14618179404Sobrien
14619179404Sobrien  /* Set MIPS ELF flags for ASEs.  */
14620208737Sjmallett  /* We may need to define a new flag for DSP ASE, and set this flag when
14621208737Sjmallett     file_ase_dsp is true.  */
14622218822Sdim  /* Same for DSP R2.  */
14623208737Sjmallett  /* We may need to define a new flag for MT ASE, and set this flag when
14624208737Sjmallett     file_ase_mt is true.  */
14625179404Sobrien  if (file_ase_mips16)
14626179404Sobrien    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_M16;
14627179404Sobrien#if 0 /* XXX FIXME */
14628179404Sobrien  if (file_ase_mips3d)
14629179404Sobrien    elf_elfheader (stdoutput)->e_flags |= ???;
14630179404Sobrien#endif
14631179404Sobrien  if (file_ase_mdmx)
14632179404Sobrien    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ARCH_ASE_MDMX;
14633179404Sobrien
14634179404Sobrien  /* Set the MIPS ELF ABI flags.  */
14635179404Sobrien  if (mips_abi == O32_ABI && USE_E_MIPS_ABI_O32)
14636179404Sobrien    elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_O32;
14637179404Sobrien  else if (mips_abi == O64_ABI)
14638179404Sobrien    elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_O64;
14639179404Sobrien  else if (mips_abi == EABI_ABI)
14640179404Sobrien    {
14641179404Sobrien      if (!file_mips_gp32)
14642179404Sobrien	elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI64;
14643179404Sobrien      else
14644179404Sobrien	elf_elfheader (stdoutput)->e_flags |= E_MIPS_ABI_EABI32;
14645179404Sobrien    }
14646179404Sobrien  else if (mips_abi == N32_ABI)
14647179404Sobrien    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_ABI2;
14648179404Sobrien
14649179404Sobrien  /* Nothing to do for N64_ABI.  */
14650179404Sobrien
14651179404Sobrien  if (mips_32bitmode)
14652179404Sobrien    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_32BITMODE;
14653218822Sdim
14654218822Sdim#if 0 /* XXX FIXME */
14655218822Sdim  /* 32 bit code with 64 bit FP registers.  */
14656218822Sdim  if (!file_mips_fp32 && ABI_NEEDS_32BIT_REGS (mips_abi))
14657218822Sdim    elf_elfheader (stdoutput)->e_flags |= ???;
14658218822Sdim#endif
14659179404Sobrien}
14660179404Sobrien
14661179404Sobrien#endif /* OBJ_ELF || OBJ_MAYBE_ELF */
14662179404Sobrien
14663179404Sobrientypedef struct proc {
14664208737Sjmallett  symbolS *func_sym;
14665208737Sjmallett  symbolS *func_end_sym;
14666179404Sobrien  unsigned long reg_mask;
14667179404Sobrien  unsigned long reg_offset;
14668179404Sobrien  unsigned long fpreg_mask;
14669179404Sobrien  unsigned long fpreg_offset;
14670179404Sobrien  unsigned long frame_offset;
14671179404Sobrien  unsigned long frame_reg;
14672179404Sobrien  unsigned long pc_reg;
14673179404Sobrien} procS;
14674179404Sobrien
14675179404Sobrienstatic procS cur_proc;
14676179404Sobrienstatic procS *cur_proc_ptr;
14677179404Sobrienstatic int numprocs;
14678179404Sobrien
14679179404Sobrien/* Fill in an rs_align_code fragment.  */
14680179404Sobrien
14681179404Sobrienvoid
14682179404Sobrienmips_handle_align (fragS *fragp)
14683179404Sobrien{
14684179404Sobrien  if (fragp->fr_type != rs_align_code)
14685179404Sobrien    return;
14686179404Sobrien
14687179404Sobrien  if (mips_opts.mips16)
14688179404Sobrien    {
14689179404Sobrien      static const unsigned char be_nop[] = { 0x65, 0x00 };
14690179404Sobrien      static const unsigned char le_nop[] = { 0x00, 0x65 };
14691179404Sobrien
14692179404Sobrien      int bytes;
14693179404Sobrien      char *p;
14694179404Sobrien
14695179404Sobrien      bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
14696179404Sobrien      p = fragp->fr_literal + fragp->fr_fix;
14697179404Sobrien
14698179404Sobrien      if (bytes & 1)
14699179404Sobrien	{
14700179404Sobrien	  *p++ = 0;
14701179404Sobrien	  fragp->fr_fix++;
14702179404Sobrien	}
14703179404Sobrien
14704179404Sobrien      memcpy (p, (target_big_endian ? be_nop : le_nop), 2);
14705179404Sobrien      fragp->fr_var = 2;
14706179404Sobrien    }
14707179404Sobrien
14708179404Sobrien  /* For mips32, a nop is a zero, which we trivially get by doing nothing.  */
14709179404Sobrien}
14710179404Sobrien
14711179404Sobrienstatic void
14712179404Sobrienmd_obj_begin (void)
14713179404Sobrien{
14714179404Sobrien}
14715179404Sobrien
14716179404Sobrienstatic void
14717179404Sobrienmd_obj_end (void)
14718179404Sobrien{
14719218822Sdim  /* Check for premature end, nesting errors, etc.  */
14720179404Sobrien  if (cur_proc_ptr)
14721179404Sobrien    as_warn (_("missing .end at end of assembly"));
14722179404Sobrien}
14723179404Sobrien
14724179404Sobrienstatic long
14725179404Sobrienget_number (void)
14726179404Sobrien{
14727179404Sobrien  int negative = 0;
14728179404Sobrien  long val = 0;
14729179404Sobrien
14730179404Sobrien  if (*input_line_pointer == '-')
14731179404Sobrien    {
14732179404Sobrien      ++input_line_pointer;
14733179404Sobrien      negative = 1;
14734179404Sobrien    }
14735179404Sobrien  if (!ISDIGIT (*input_line_pointer))
14736179404Sobrien    as_bad (_("expected simple number"));
14737179404Sobrien  if (input_line_pointer[0] == '0')
14738179404Sobrien    {
14739179404Sobrien      if (input_line_pointer[1] == 'x')
14740179404Sobrien	{
14741179404Sobrien	  input_line_pointer += 2;
14742179404Sobrien	  while (ISXDIGIT (*input_line_pointer))
14743179404Sobrien	    {
14744179404Sobrien	      val <<= 4;
14745179404Sobrien	      val |= hex_value (*input_line_pointer++);
14746179404Sobrien	    }
14747179404Sobrien	  return negative ? -val : val;
14748179404Sobrien	}
14749179404Sobrien      else
14750179404Sobrien	{
14751179404Sobrien	  ++input_line_pointer;
14752179404Sobrien	  while (ISDIGIT (*input_line_pointer))
14753179404Sobrien	    {
14754179404Sobrien	      val <<= 3;
14755179404Sobrien	      val |= *input_line_pointer++ - '0';
14756179404Sobrien	    }
14757179404Sobrien	  return negative ? -val : val;
14758179404Sobrien	}
14759179404Sobrien    }
14760179404Sobrien  if (!ISDIGIT (*input_line_pointer))
14761179404Sobrien    {
14762179404Sobrien      printf (_(" *input_line_pointer == '%c' 0x%02x\n"),
14763179404Sobrien	      *input_line_pointer, *input_line_pointer);
14764179404Sobrien      as_warn (_("invalid number"));
14765179404Sobrien      return -1;
14766179404Sobrien    }
14767179404Sobrien  while (ISDIGIT (*input_line_pointer))
14768179404Sobrien    {
14769179404Sobrien      val *= 10;
14770179404Sobrien      val += *input_line_pointer++ - '0';
14771179404Sobrien    }
14772179404Sobrien  return negative ? -val : val;
14773179404Sobrien}
14774179404Sobrien
14775179404Sobrien/* The .file directive; just like the usual .file directive, but there
14776179404Sobrien   is an initial number which is the ECOFF file index.  In the non-ECOFF
14777179404Sobrien   case .file implies DWARF-2.  */
14778179404Sobrien
14779179404Sobrienstatic void
14780179404Sobriens_mips_file (int x ATTRIBUTE_UNUSED)
14781179404Sobrien{
14782179404Sobrien  static int first_file_directive = 0;
14783179404Sobrien
14784179404Sobrien  if (ECOFF_DEBUGGING)
14785179404Sobrien    {
14786179404Sobrien      get_number ();
14787179404Sobrien      s_app_file (0);
14788179404Sobrien    }
14789179404Sobrien  else
14790179404Sobrien    {
14791179404Sobrien      char *filename;
14792179404Sobrien
14793179404Sobrien      filename = dwarf2_directive_file (0);
14794179404Sobrien
14795179404Sobrien      /* Versions of GCC up to 3.1 start files with a ".file"
14796179404Sobrien	 directive even for stabs output.  Make sure that this
14797179404Sobrien	 ".file" is handled.  Note that you need a version of GCC
14798179404Sobrien         after 3.1 in order to support DWARF-2 on MIPS.  */
14799179404Sobrien      if (filename != NULL && ! first_file_directive)
14800179404Sobrien	{
14801179404Sobrien	  (void) new_logical_line (filename, -1);
14802218822Sdim	  s_app_file_string (filename, 0);
14803179404Sobrien	}
14804179404Sobrien      first_file_directive = 1;
14805179404Sobrien    }
14806179404Sobrien}
14807179404Sobrien
14808179404Sobrien/* The .loc directive, implying DWARF-2.  */
14809179404Sobrien
14810179404Sobrienstatic void
14811179404Sobriens_mips_loc (int x ATTRIBUTE_UNUSED)
14812179404Sobrien{
14813179404Sobrien  if (!ECOFF_DEBUGGING)
14814179404Sobrien    dwarf2_directive_loc (0);
14815179404Sobrien}
14816179404Sobrien
14817179404Sobrien/* The .end directive.  */
14818179404Sobrien
14819179404Sobrienstatic void
14820179404Sobriens_mips_end (int x ATTRIBUTE_UNUSED)
14821179404Sobrien{
14822179404Sobrien  symbolS *p;
14823179404Sobrien
14824179404Sobrien  /* Following functions need their own .frame and .cprestore directives.  */
14825179404Sobrien  mips_frame_reg_valid = 0;
14826179404Sobrien  mips_cprestore_valid = 0;
14827179404Sobrien
14828179404Sobrien  if (!is_end_of_line[(unsigned char) *input_line_pointer])
14829179404Sobrien    {
14830179404Sobrien      p = get_symbol ();
14831179404Sobrien      demand_empty_rest_of_line ();
14832179404Sobrien    }
14833179404Sobrien  else
14834179404Sobrien    p = NULL;
14835179404Sobrien
14836179404Sobrien  if ((bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) == 0)
14837179404Sobrien    as_warn (_(".end not in text section"));
14838179404Sobrien
14839179404Sobrien  if (!cur_proc_ptr)
14840179404Sobrien    {
14841179404Sobrien      as_warn (_(".end directive without a preceding .ent directive."));
14842179404Sobrien      demand_empty_rest_of_line ();
14843179404Sobrien      return;
14844179404Sobrien    }
14845179404Sobrien
14846179404Sobrien  if (p != NULL)
14847179404Sobrien    {
14848179404Sobrien      assert (S_GET_NAME (p));
14849208737Sjmallett      if (strcmp (S_GET_NAME (p), S_GET_NAME (cur_proc_ptr->func_sym)))
14850179404Sobrien	as_warn (_(".end symbol does not match .ent symbol."));
14851179404Sobrien
14852179404Sobrien      if (debug_type == DEBUG_STABS)
14853179404Sobrien	stabs_generate_asm_endfunc (S_GET_NAME (p),
14854179404Sobrien				    S_GET_NAME (p));
14855179404Sobrien    }
14856179404Sobrien  else
14857179404Sobrien    as_warn (_(".end directive missing or unknown symbol"));
14858179404Sobrien
14859179404Sobrien#ifdef OBJ_ELF
14860208737Sjmallett  /* Create an expression to calculate the size of the function.  */
14861208737Sjmallett  if (p && cur_proc_ptr)
14862208737Sjmallett    {
14863208737Sjmallett      OBJ_SYMFIELD_TYPE *obj = symbol_get_obj (p);
14864208737Sjmallett      expressionS *exp = xmalloc (sizeof (expressionS));
14865208737Sjmallett
14866208737Sjmallett      obj->size = exp;
14867208737Sjmallett      exp->X_op = O_subtract;
14868208737Sjmallett      exp->X_add_symbol = symbol_temp_new_now ();
14869208737Sjmallett      exp->X_op_symbol = p;
14870208737Sjmallett      exp->X_add_number = 0;
14871208737Sjmallett
14872208737Sjmallett      cur_proc_ptr->func_end_sym = exp->X_add_symbol;
14873208737Sjmallett    }
14874208737Sjmallett
14875179404Sobrien  /* Generate a .pdr section.  */
14876218822Sdim  if (IS_ELF && !ECOFF_DEBUGGING && mips_flag_pdr)
14877179404Sobrien    {
14878179404Sobrien      segT saved_seg = now_seg;
14879179404Sobrien      subsegT saved_subseg = now_subseg;
14880179404Sobrien      valueT dot;
14881179404Sobrien      expressionS exp;
14882179404Sobrien      char *fragp;
14883179404Sobrien
14884179404Sobrien      dot = frag_now_fix ();
14885179404Sobrien
14886179404Sobrien#ifdef md_flush_pending_output
14887179404Sobrien      md_flush_pending_output ();
14888179404Sobrien#endif
14889179404Sobrien
14890179404Sobrien      assert (pdr_seg);
14891179404Sobrien      subseg_set (pdr_seg, 0);
14892179404Sobrien
14893179404Sobrien      /* Write the symbol.  */
14894179404Sobrien      exp.X_op = O_symbol;
14895179404Sobrien      exp.X_add_symbol = p;
14896179404Sobrien      exp.X_add_number = 0;
14897179404Sobrien      emit_expr (&exp, 4);
14898179404Sobrien
14899179404Sobrien      fragp = frag_more (7 * 4);
14900179404Sobrien
14901179404Sobrien      md_number_to_chars (fragp, cur_proc_ptr->reg_mask, 4);
14902179404Sobrien      md_number_to_chars (fragp + 4, cur_proc_ptr->reg_offset, 4);
14903179404Sobrien      md_number_to_chars (fragp + 8, cur_proc_ptr->fpreg_mask, 4);
14904179404Sobrien      md_number_to_chars (fragp + 12, cur_proc_ptr->fpreg_offset, 4);
14905179404Sobrien      md_number_to_chars (fragp + 16, cur_proc_ptr->frame_offset, 4);
14906179404Sobrien      md_number_to_chars (fragp + 20, cur_proc_ptr->frame_reg, 4);
14907179404Sobrien      md_number_to_chars (fragp + 24, cur_proc_ptr->pc_reg, 4);
14908179404Sobrien
14909179404Sobrien      subseg_set (saved_seg, saved_subseg);
14910179404Sobrien    }
14911179404Sobrien#endif /* OBJ_ELF */
14912179404Sobrien
14913179404Sobrien  cur_proc_ptr = NULL;
14914179404Sobrien}
14915179404Sobrien
14916179404Sobrien/* The .aent and .ent directives.  */
14917179404Sobrien
14918179404Sobrienstatic void
14919179404Sobriens_mips_ent (int aent)
14920179404Sobrien{
14921179404Sobrien  symbolS *symbolP;
14922179404Sobrien
14923179404Sobrien  symbolP = get_symbol ();
14924179404Sobrien  if (*input_line_pointer == ',')
14925179404Sobrien    ++input_line_pointer;
14926179404Sobrien  SKIP_WHITESPACE ();
14927179404Sobrien  if (ISDIGIT (*input_line_pointer)
14928179404Sobrien      || *input_line_pointer == '-')
14929179404Sobrien    get_number ();
14930179404Sobrien
14931179404Sobrien  if ((bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) == 0)
14932179404Sobrien    as_warn (_(".ent or .aent not in text section."));
14933179404Sobrien
14934179404Sobrien  if (!aent && cur_proc_ptr)
14935179404Sobrien    as_warn (_("missing .end"));
14936179404Sobrien
14937179404Sobrien  if (!aent)
14938179404Sobrien    {
14939179404Sobrien      /* This function needs its own .frame and .cprestore directives.  */
14940179404Sobrien      mips_frame_reg_valid = 0;
14941179404Sobrien      mips_cprestore_valid = 0;
14942179404Sobrien
14943179404Sobrien      cur_proc_ptr = &cur_proc;
14944179404Sobrien      memset (cur_proc_ptr, '\0', sizeof (procS));
14945179404Sobrien
14946208737Sjmallett      cur_proc_ptr->func_sym = symbolP;
14947179404Sobrien
14948179404Sobrien      symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
14949179404Sobrien
14950179404Sobrien      ++numprocs;
14951179404Sobrien
14952179404Sobrien      if (debug_type == DEBUG_STABS)
14953179404Sobrien        stabs_generate_asm_func (S_GET_NAME (symbolP),
14954179404Sobrien				 S_GET_NAME (symbolP));
14955179404Sobrien    }
14956179404Sobrien
14957179404Sobrien  demand_empty_rest_of_line ();
14958179404Sobrien}
14959179404Sobrien
14960179404Sobrien/* The .frame directive. If the mdebug section is present (IRIX 5 native)
14961179404Sobrien   then ecoff.c (ecoff_directive_frame) is used. For embedded targets,
14962179404Sobrien   s_mips_frame is used so that we can set the PDR information correctly.
14963179404Sobrien   We can't use the ecoff routines because they make reference to the ecoff
14964179404Sobrien   symbol table (in the mdebug section).  */
14965179404Sobrien
14966179404Sobrienstatic void
14967179404Sobriens_mips_frame (int ignore ATTRIBUTE_UNUSED)
14968179404Sobrien{
14969179404Sobrien#ifdef OBJ_ELF
14970218822Sdim  if (IS_ELF && !ECOFF_DEBUGGING)
14971179404Sobrien    {
14972179404Sobrien      long val;
14973179404Sobrien
14974179404Sobrien      if (cur_proc_ptr == (procS *) NULL)
14975179404Sobrien	{
14976179404Sobrien	  as_warn (_(".frame outside of .ent"));
14977179404Sobrien	  demand_empty_rest_of_line ();
14978179404Sobrien	  return;
14979179404Sobrien	}
14980179404Sobrien
14981179404Sobrien      cur_proc_ptr->frame_reg = tc_get_register (1);
14982179404Sobrien
14983179404Sobrien      SKIP_WHITESPACE ();
14984179404Sobrien      if (*input_line_pointer++ != ','
14985179404Sobrien	  || get_absolute_expression_and_terminator (&val) != ',')
14986179404Sobrien	{
14987179404Sobrien	  as_warn (_("Bad .frame directive"));
14988179404Sobrien	  --input_line_pointer;
14989179404Sobrien	  demand_empty_rest_of_line ();
14990179404Sobrien	  return;
14991179404Sobrien	}
14992179404Sobrien
14993179404Sobrien      cur_proc_ptr->frame_offset = val;
14994179404Sobrien      cur_proc_ptr->pc_reg = tc_get_register (0);
14995179404Sobrien
14996179404Sobrien      demand_empty_rest_of_line ();
14997179404Sobrien    }
14998179404Sobrien  else
14999179404Sobrien#endif /* OBJ_ELF */
15000179404Sobrien    s_ignore (ignore);
15001179404Sobrien}
15002179404Sobrien
15003179404Sobrien/* The .fmask and .mask directives. If the mdebug section is present
15004179404Sobrien   (IRIX 5 native) then ecoff.c (ecoff_directive_mask) is used. For
15005179404Sobrien   embedded targets, s_mips_mask is used so that we can set the PDR
15006179404Sobrien   information correctly. We can't use the ecoff routines because they
15007179404Sobrien   make reference to the ecoff symbol table (in the mdebug section).  */
15008179404Sobrien
15009179404Sobrienstatic void
15010179404Sobriens_mips_mask (int reg_type)
15011179404Sobrien{
15012179404Sobrien#ifdef OBJ_ELF
15013218822Sdim  if (IS_ELF && !ECOFF_DEBUGGING)
15014179404Sobrien    {
15015179404Sobrien      long mask, off;
15016179404Sobrien
15017179404Sobrien      if (cur_proc_ptr == (procS *) NULL)
15018179404Sobrien	{
15019179404Sobrien	  as_warn (_(".mask/.fmask outside of .ent"));
15020179404Sobrien	  demand_empty_rest_of_line ();
15021179404Sobrien	  return;
15022179404Sobrien	}
15023179404Sobrien
15024179404Sobrien      if (get_absolute_expression_and_terminator (&mask) != ',')
15025179404Sobrien	{
15026179404Sobrien	  as_warn (_("Bad .mask/.fmask directive"));
15027179404Sobrien	  --input_line_pointer;
15028179404Sobrien	  demand_empty_rest_of_line ();
15029179404Sobrien	  return;
15030179404Sobrien	}
15031179404Sobrien
15032179404Sobrien      off = get_absolute_expression ();
15033179404Sobrien
15034179404Sobrien      if (reg_type == 'F')
15035179404Sobrien	{
15036179404Sobrien	  cur_proc_ptr->fpreg_mask = mask;
15037179404Sobrien	  cur_proc_ptr->fpreg_offset = off;
15038179404Sobrien	}
15039179404Sobrien      else
15040179404Sobrien	{
15041179404Sobrien	  cur_proc_ptr->reg_mask = mask;
15042179404Sobrien	  cur_proc_ptr->reg_offset = off;
15043179404Sobrien	}
15044179404Sobrien
15045179404Sobrien      demand_empty_rest_of_line ();
15046179404Sobrien    }
15047179404Sobrien  else
15048179404Sobrien#endif /* OBJ_ELF */
15049179404Sobrien    s_ignore (reg_type);
15050179404Sobrien}
15051179404Sobrien
15052179404Sobrien/* A table describing all the processors gas knows about.  Names are
15053179404Sobrien   matched in the order listed.
15054179404Sobrien
15055179404Sobrien   To ease comparison, please keep this table in the same order as
15056179404Sobrien   gcc's mips_cpu_info_table[].  */
15057179404Sobrienstatic const struct mips_cpu_info mips_cpu_info_table[] =
15058179404Sobrien{
15059179404Sobrien  /* Entries for generic ISAs */
15060218822Sdim  { "mips1",          MIPS_CPU_IS_ISA,		ISA_MIPS1,      CPU_R3000 },
15061218822Sdim  { "mips2",          MIPS_CPU_IS_ISA,		ISA_MIPS2,      CPU_R6000 },
15062218822Sdim  { "mips3",          MIPS_CPU_IS_ISA,		ISA_MIPS3,      CPU_R4000 },
15063218822Sdim  { "mips4",          MIPS_CPU_IS_ISA,		ISA_MIPS4,      CPU_R8000 },
15064218822Sdim  { "mips5",          MIPS_CPU_IS_ISA,		ISA_MIPS5,      CPU_MIPS5 },
15065218822Sdim  { "mips32",         MIPS_CPU_IS_ISA,		ISA_MIPS32,     CPU_MIPS32 },
15066218822Sdim  { "mips32r2",       MIPS_CPU_IS_ISA,		ISA_MIPS32R2,   CPU_MIPS32R2 },
15067218822Sdim  { "mips64",         MIPS_CPU_IS_ISA,		ISA_MIPS64,     CPU_MIPS64 },
15068218822Sdim  { "mips64r2",       MIPS_CPU_IS_ISA,		ISA_MIPS64R2,   CPU_MIPS64R2 },
15069179404Sobrien
15070179404Sobrien  /* MIPS I */
15071218822Sdim  { "r3000",          0,			ISA_MIPS1,      CPU_R3000 },
15072218822Sdim  { "r2000",          0,			ISA_MIPS1,      CPU_R3000 },
15073218822Sdim  { "r3900",          0,			ISA_MIPS1,      CPU_R3900 },
15074179404Sobrien
15075179404Sobrien  /* MIPS II */
15076218822Sdim  { "r6000",          0,			ISA_MIPS2,      CPU_R6000 },
15077179404Sobrien
15078179404Sobrien  /* MIPS III */
15079218822Sdim  { "r4000",          0,			ISA_MIPS3,      CPU_R4000 },
15080218822Sdim  { "r4010",          0,			ISA_MIPS2,      CPU_R4010 },
15081218822Sdim  { "vr4100",         0,			ISA_MIPS3,      CPU_VR4100 },
15082218822Sdim  { "vr4111",         0,			ISA_MIPS3,      CPU_R4111 },
15083218822Sdim  { "vr4120",         0,			ISA_MIPS3,      CPU_VR4120 },
15084218822Sdim  { "vr4130",         0,			ISA_MIPS3,      CPU_VR4120 },
15085218822Sdim  { "vr4181",         0,			ISA_MIPS3,      CPU_R4111 },
15086218822Sdim  { "vr4300",         0,			ISA_MIPS3,      CPU_R4300 },
15087218822Sdim  { "r4400",          0,			ISA_MIPS3,      CPU_R4400 },
15088218822Sdim  { "r4600",          0,			ISA_MIPS3,      CPU_R4600 },
15089218822Sdim  { "orion",          0,			ISA_MIPS3,      CPU_R4600 },
15090218822Sdim  { "r4650",          0,			ISA_MIPS3,      CPU_R4650 },
15091179404Sobrien
15092179404Sobrien  /* MIPS IV */
15093218822Sdim  { "r8000",          0,			ISA_MIPS4,      CPU_R8000 },
15094218822Sdim  { "r10000",         0,			ISA_MIPS4,      CPU_R10000 },
15095218822Sdim  { "r12000",         0,			ISA_MIPS4,      CPU_R12000 },
15096218822Sdim  { "vr5000",         0,			ISA_MIPS4,      CPU_R5000 },
15097218822Sdim  { "vr5400",         0,			ISA_MIPS4,      CPU_VR5400 },
15098218822Sdim  { "vr5500",         0,			ISA_MIPS4,      CPU_VR5500 },
15099218822Sdim  { "rm5200",         0,			ISA_MIPS4,      CPU_R5000 },
15100218822Sdim  { "rm5230",         0,			ISA_MIPS4,      CPU_R5000 },
15101218822Sdim  { "rm5231",         0,			ISA_MIPS4,      CPU_R5000 },
15102218822Sdim  { "rm5261",         0,			ISA_MIPS4,      CPU_R5000 },
15103218822Sdim  { "rm5721",         0,			ISA_MIPS4,      CPU_R5000 },
15104218822Sdim  { "rm7000",         0,			ISA_MIPS4,      CPU_RM7000 },
15105218822Sdim  { "rm9000",         0,			ISA_MIPS4,      CPU_RM9000 },
15106179404Sobrien
15107179404Sobrien  /* MIPS 32 */
15108218822Sdim  { "4kc",            0,			ISA_MIPS32,	CPU_MIPS32 },
15109218822Sdim  { "4km",            0,			ISA_MIPS32,	CPU_MIPS32 },
15110218822Sdim  { "4kp",            0,			ISA_MIPS32,	CPU_MIPS32 },
15111218822Sdim  { "4ksc",           MIPS_CPU_ASE_SMARTMIPS,	ISA_MIPS32,	CPU_MIPS32 },
15112179404Sobrien
15113218822Sdim  /* MIPS 32 Release 2 */
15114218822Sdim  { "4kec",           0,			ISA_MIPS32R2,   CPU_MIPS32R2 },
15115218822Sdim  { "4kem",           0,			ISA_MIPS32R2,   CPU_MIPS32R2 },
15116218822Sdim  { "4kep",           0,			ISA_MIPS32R2,   CPU_MIPS32R2 },
15117218822Sdim  { "4ksd",           MIPS_CPU_ASE_SMARTMIPS,	ISA_MIPS32R2,   CPU_MIPS32R2 },
15118218822Sdim  { "m4k",            0,			ISA_MIPS32R2,   CPU_MIPS32R2 },
15119218822Sdim  { "m4kp",           0,			ISA_MIPS32R2,   CPU_MIPS32R2 },
15120218822Sdim  { "24kc",           0,			ISA_MIPS32R2,   CPU_MIPS32R2 },
15121218822Sdim  { "24kf",           0,			ISA_MIPS32R2,   CPU_MIPS32R2 },
15122218822Sdim  { "24kx",           0,			ISA_MIPS32R2,   CPU_MIPS32R2 },
15123218822Sdim  /* 24KE is a 24K with DSP ASE, other ASEs are optional.  */
15124218822Sdim  { "24kec",          MIPS_CPU_ASE_DSP,		ISA_MIPS32R2,	CPU_MIPS32R2 },
15125218822Sdim  { "24kef",          MIPS_CPU_ASE_DSP,		ISA_MIPS32R2,	CPU_MIPS32R2 },
15126218822Sdim  { "24kex",          MIPS_CPU_ASE_DSP,		ISA_MIPS32R2,	CPU_MIPS32R2 },
15127218822Sdim  /* 34K is a 24K with DSP and MT ASE, other ASEs are optional.  */
15128218822Sdim  { "34kc",           MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
15129218822Sdim						ISA_MIPS32R2,	CPU_MIPS32R2 },
15130218822Sdim  { "34kf",           MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
15131218822Sdim						ISA_MIPS32R2,	CPU_MIPS32R2 },
15132218822Sdim  { "34kx",           MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_MT,
15133218822Sdim						ISA_MIPS32R2,	CPU_MIPS32R2 },
15134218822Sdim  /* 74K with DSP and DSPR2 ASE, other ASEs are optional.  */
15135218822Sdim  { "74kc",           MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2,
15136218822Sdim						ISA_MIPS32R2,	CPU_MIPS32R2 },
15137218822Sdim  { "74kf",           MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2,
15138218822Sdim						ISA_MIPS32R2,	CPU_MIPS32R2 },
15139218822Sdim  { "74kx",           MIPS_CPU_ASE_DSP | MIPS_CPU_ASE_DSPR2,
15140218822Sdim						ISA_MIPS32R2,	CPU_MIPS32R2 },
15141208737Sjmallett
15142179404Sobrien  /* MIPS 64 */
15143218822Sdim  { "5kc",            0,			ISA_MIPS64,	CPU_MIPS64 },
15144218822Sdim  { "5kf",            0,			ISA_MIPS64,	CPU_MIPS64 },
15145218822Sdim  { "20kc",           MIPS_CPU_ASE_MIPS3D,	ISA_MIPS64,	CPU_MIPS64 },
15146218822Sdim  { "25kf",           MIPS_CPU_ASE_MIPS3D,	ISA_MIPS64,     CPU_MIPS64 },
15147179404Sobrien
15148218822Sdim  /* MIPS 64 Release 2 */
15149218822Sdim
15150179404Sobrien  /* Broadcom SB-1 CPU core */
15151218822Sdim  { "sb1",            MIPS_CPU_ASE_MIPS3D | MIPS_CPU_ASE_MDMX,
15152218822Sdim						ISA_MIPS64,	CPU_SB1 },
15153218822Sdim  /* Broadcom SB-1A CPU core */
15154218822Sdim  { "sb1a",           MIPS_CPU_ASE_MIPS3D | MIPS_CPU_ASE_MDMX,
15155218822Sdim						ISA_MIPS64,	CPU_SB1 },
15156179404Sobrien
15157208737Sjmallett  /* Cavium Networks Octeon CPU core */
15158208737Sjmallett  { "octeon",         0,      ISA_MIPS64R2,   CPU_OCTEON },
15159314573Semaste  { "octeon+",        0,      ISA_MIPS64R2,   CPU_OCTEON },
15160208737Sjmallett
15161179404Sobrien  /* End marker */
15162179404Sobrien  { NULL, 0, 0, 0 }
15163179404Sobrien};
15164179404Sobrien
15165179404Sobrien
15166179404Sobrien/* Return true if GIVEN is the same as CANONICAL, or if it is CANONICAL
15167179404Sobrien   with a final "000" replaced by "k".  Ignore case.
15168179404Sobrien
15169179404Sobrien   Note: this function is shared between GCC and GAS.  */
15170179404Sobrien
15171179404Sobrienstatic bfd_boolean
15172179404Sobrienmips_strict_matching_cpu_name_p (const char *canonical, const char *given)
15173179404Sobrien{
15174179404Sobrien  while (*given != 0 && TOLOWER (*given) == TOLOWER (*canonical))
15175179404Sobrien    given++, canonical++;
15176179404Sobrien
15177179404Sobrien  return ((*given == 0 && *canonical == 0)
15178179404Sobrien	  || (strcmp (canonical, "000") == 0 && strcasecmp (given, "k") == 0));
15179179404Sobrien}
15180179404Sobrien
15181179404Sobrien
15182179404Sobrien/* Return true if GIVEN matches CANONICAL, where GIVEN is a user-supplied
15183179404Sobrien   CPU name.  We've traditionally allowed a lot of variation here.
15184179404Sobrien
15185179404Sobrien   Note: this function is shared between GCC and GAS.  */
15186179404Sobrien
15187179404Sobrienstatic bfd_boolean
15188179404Sobrienmips_matching_cpu_name_p (const char *canonical, const char *given)
15189179404Sobrien{
15190179404Sobrien  /* First see if the name matches exactly, or with a final "000"
15191179404Sobrien     turned into "k".  */
15192179404Sobrien  if (mips_strict_matching_cpu_name_p (canonical, given))
15193179404Sobrien    return TRUE;
15194179404Sobrien
15195179404Sobrien  /* If not, try comparing based on numerical designation alone.
15196179404Sobrien     See if GIVEN is an unadorned number, or 'r' followed by a number.  */
15197179404Sobrien  if (TOLOWER (*given) == 'r')
15198179404Sobrien    given++;
15199179404Sobrien  if (!ISDIGIT (*given))
15200179404Sobrien    return FALSE;
15201179404Sobrien
15202179404Sobrien  /* Skip over some well-known prefixes in the canonical name,
15203179404Sobrien     hoping to find a number there too.  */
15204179404Sobrien  if (TOLOWER (canonical[0]) == 'v' && TOLOWER (canonical[1]) == 'r')
15205179404Sobrien    canonical += 2;
15206179404Sobrien  else if (TOLOWER (canonical[0]) == 'r' && TOLOWER (canonical[1]) == 'm')
15207179404Sobrien    canonical += 2;
15208179404Sobrien  else if (TOLOWER (canonical[0]) == 'r')
15209179404Sobrien    canonical += 1;
15210179404Sobrien
15211179404Sobrien  return mips_strict_matching_cpu_name_p (canonical, given);
15212179404Sobrien}
15213179404Sobrien
15214179404Sobrien
15215179404Sobrien/* Parse an option that takes the name of a processor as its argument.
15216179404Sobrien   OPTION is the name of the option and CPU_STRING is the argument.
15217179404Sobrien   Return the corresponding processor enumeration if the CPU_STRING is
15218179404Sobrien   recognized, otherwise report an error and return null.
15219179404Sobrien
15220179404Sobrien   A similar function exists in GCC.  */
15221179404Sobrien
15222179404Sobrienstatic const struct mips_cpu_info *
15223179404Sobrienmips_parse_cpu (const char *option, const char *cpu_string)
15224179404Sobrien{
15225179404Sobrien  const struct mips_cpu_info *p;
15226179404Sobrien
15227179404Sobrien  /* 'from-abi' selects the most compatible architecture for the given
15228179404Sobrien     ABI: MIPS I for 32-bit ABIs and MIPS III for 64-bit ABIs.  For the
15229179404Sobrien     EABIs, we have to decide whether we're using the 32-bit or 64-bit
15230179404Sobrien     version.  Look first at the -mgp options, if given, otherwise base
15231179404Sobrien     the choice on MIPS_DEFAULT_64BIT.
15232179404Sobrien
15233179404Sobrien     Treat NO_ABI like the EABIs.  One reason to do this is that the
15234179404Sobrien     plain 'mips' and 'mips64' configs have 'from-abi' as their default
15235179404Sobrien     architecture.  This code picks MIPS I for 'mips' and MIPS III for
15236179404Sobrien     'mips64', just as we did in the days before 'from-abi'.  */
15237179404Sobrien  if (strcasecmp (cpu_string, "from-abi") == 0)
15238179404Sobrien    {
15239179404Sobrien      if (ABI_NEEDS_32BIT_REGS (mips_abi))
15240179404Sobrien	return mips_cpu_info_from_isa (ISA_MIPS1);
15241179404Sobrien
15242179404Sobrien      if (ABI_NEEDS_64BIT_REGS (mips_abi))
15243179404Sobrien	return mips_cpu_info_from_isa (ISA_MIPS3);
15244179404Sobrien
15245179404Sobrien      if (file_mips_gp32 >= 0)
15246179404Sobrien	return mips_cpu_info_from_isa (file_mips_gp32 ? ISA_MIPS1 : ISA_MIPS3);
15247179404Sobrien
15248179404Sobrien      return mips_cpu_info_from_isa (MIPS_DEFAULT_64BIT
15249179404Sobrien				     ? ISA_MIPS3
15250179404Sobrien				     : ISA_MIPS1);
15251179404Sobrien    }
15252179404Sobrien
15253179404Sobrien  /* 'default' has traditionally been a no-op.  Probably not very useful.  */
15254179404Sobrien  if (strcasecmp (cpu_string, "default") == 0)
15255179404Sobrien    return 0;
15256179404Sobrien
15257179404Sobrien  for (p = mips_cpu_info_table; p->name != 0; p++)
15258179404Sobrien    if (mips_matching_cpu_name_p (p->name, cpu_string))
15259179404Sobrien      return p;
15260179404Sobrien
15261179404Sobrien  as_bad ("Bad value (%s) for %s", cpu_string, option);
15262179404Sobrien  return 0;
15263179404Sobrien}
15264179404Sobrien
15265179404Sobrien/* Return the canonical processor information for ISA (a member of the
15266179404Sobrien   ISA_MIPS* enumeration).  */
15267179404Sobrien
15268179404Sobrienstatic const struct mips_cpu_info *
15269179404Sobrienmips_cpu_info_from_isa (int isa)
15270179404Sobrien{
15271179404Sobrien  int i;
15272179404Sobrien
15273179404Sobrien  for (i = 0; mips_cpu_info_table[i].name != NULL; i++)
15274218822Sdim    if ((mips_cpu_info_table[i].flags & MIPS_CPU_IS_ISA)
15275179404Sobrien	&& isa == mips_cpu_info_table[i].isa)
15276179404Sobrien      return (&mips_cpu_info_table[i]);
15277179404Sobrien
15278179404Sobrien  return NULL;
15279179404Sobrien}
15280179404Sobrien
15281179404Sobrienstatic const struct mips_cpu_info *
15282179404Sobrienmips_cpu_info_from_arch (int arch)
15283179404Sobrien{
15284179404Sobrien  int i;
15285179404Sobrien
15286179404Sobrien  for (i = 0; mips_cpu_info_table[i].name != NULL; i++)
15287179404Sobrien    if (arch == mips_cpu_info_table[i].cpu)
15288179404Sobrien      return (&mips_cpu_info_table[i]);
15289179404Sobrien
15290179404Sobrien  return NULL;
15291179404Sobrien}
15292179404Sobrien
15293179404Sobrienstatic void
15294179404Sobrienshow (FILE *stream, const char *string, int *col_p, int *first_p)
15295179404Sobrien{
15296179404Sobrien  if (*first_p)
15297179404Sobrien    {
15298179404Sobrien      fprintf (stream, "%24s", "");
15299179404Sobrien      *col_p = 24;
15300179404Sobrien    }
15301179404Sobrien  else
15302179404Sobrien    {
15303179404Sobrien      fprintf (stream, ", ");
15304179404Sobrien      *col_p += 2;
15305179404Sobrien    }
15306179404Sobrien
15307179404Sobrien  if (*col_p + strlen (string) > 72)
15308179404Sobrien    {
15309179404Sobrien      fprintf (stream, "\n%24s", "");
15310179404Sobrien      *col_p = 24;
15311179404Sobrien    }
15312179404Sobrien
15313179404Sobrien  fprintf (stream, "%s", string);
15314179404Sobrien  *col_p += strlen (string);
15315179404Sobrien
15316179404Sobrien  *first_p = 0;
15317179404Sobrien}
15318179404Sobrien
15319179404Sobrienvoid
15320179404Sobrienmd_show_usage (FILE *stream)
15321179404Sobrien{
15322179404Sobrien  int column, first;
15323179404Sobrien  size_t i;
15324179404Sobrien
15325179404Sobrien  fprintf (stream, _("\
15326179404SobrienMIPS options:\n\
15327179404Sobrien-EB			generate big endian output\n\
15328179404Sobrien-EL			generate little endian output\n\
15329179404Sobrien-g, -g2			do not remove unneeded NOPs or swap branches\n\
15330179404Sobrien-G NUM			allow referencing objects up to NUM bytes\n\
15331179404Sobrien			implicitly with the gp register [default 8]\n"));
15332179404Sobrien  fprintf (stream, _("\
15333179404Sobrien-mips1			generate MIPS ISA I instructions\n\
15334179404Sobrien-mips2			generate MIPS ISA II instructions\n\
15335179404Sobrien-mips3			generate MIPS ISA III instructions\n\
15336179404Sobrien-mips4			generate MIPS ISA IV instructions\n\
15337179404Sobrien-mips5                  generate MIPS ISA V instructions\n\
15338179404Sobrien-mips32                 generate MIPS32 ISA instructions\n\
15339179404Sobrien-mips32r2               generate MIPS32 release 2 ISA instructions\n\
15340179404Sobrien-mips64                 generate MIPS64 ISA instructions\n\
15341179404Sobrien-mips64r2               generate MIPS64 release 2 ISA instructions\n\
15342179404Sobrien-march=CPU/-mtune=CPU	generate code/schedule for CPU, where CPU is one of:\n"));
15343179404Sobrien
15344179404Sobrien  first = 1;
15345179404Sobrien
15346179404Sobrien  for (i = 0; mips_cpu_info_table[i].name != NULL; i++)
15347179404Sobrien    show (stream, mips_cpu_info_table[i].name, &column, &first);
15348179404Sobrien  show (stream, "from-abi", &column, &first);
15349179404Sobrien  fputc ('\n', stream);
15350179404Sobrien
15351179404Sobrien  fprintf (stream, _("\
15352179404Sobrien-mCPU			equivalent to -march=CPU -mtune=CPU. Deprecated.\n\
15353179404Sobrien-no-mCPU		don't generate code specific to CPU.\n\
15354179404Sobrien			For -mCPU and -no-mCPU, CPU must be one of:\n"));
15355179404Sobrien
15356179404Sobrien  first = 1;
15357179404Sobrien
15358179404Sobrien  show (stream, "3900", &column, &first);
15359179404Sobrien  show (stream, "4010", &column, &first);
15360179404Sobrien  show (stream, "4100", &column, &first);
15361179404Sobrien  show (stream, "4650", &column, &first);
15362179404Sobrien  fputc ('\n', stream);
15363179404Sobrien
15364179404Sobrien  fprintf (stream, _("\
15365179404Sobrien-mips16			generate mips16 instructions\n\
15366179404Sobrien-no-mips16		do not generate mips16 instructions\n"));
15367179404Sobrien  fprintf (stream, _("\
15368218822Sdim-msmartmips		generate smartmips instructions\n\
15369218822Sdim-mno-smartmips		do not generate smartmips instructions\n"));
15370218822Sdim  fprintf (stream, _("\
15371208737Sjmallett-mdsp			generate DSP instructions\n\
15372208737Sjmallett-mno-dsp		do not generate DSP instructions\n"));
15373208737Sjmallett  fprintf (stream, _("\
15374218822Sdim-mdspr2			generate DSP R2 instructions\n\
15375218822Sdim-mno-dspr2		do not generate DSP R2 instructions\n"));
15376218822Sdim  fprintf (stream, _("\
15377208737Sjmallett-mmt			generate MT instructions\n\
15378208737Sjmallett-mno-mt			do not generate MT instructions\n"));
15379208737Sjmallett  fprintf (stream, _("\
15380179404Sobrien-mfix-vr4120		work around certain VR4120 errata\n\
15381208737Sjmallett-mfix-vr4130		work around VR4130 mflo/mfhi errata\n\
15382179404Sobrien-mgp32			use 32-bit GPRs, regardless of the chosen ISA\n\
15383179404Sobrien-mfp32			use 32-bit FPRs, regardless of the chosen ISA\n\
15384208737Sjmallett-msym32			assume all symbols have 32-bit values\n\
15385179404Sobrien-O0			remove unneeded NOPs, do not swap branches\n\
15386179404Sobrien-O			remove unneeded NOPs and swap branches\n\
15387179404Sobrien--[no-]construct-floats [dis]allow floating point values to be constructed\n\
15388179404Sobrien--trap, --no-break	trap exception on div by 0 and mult overflow\n\
15389179404Sobrien--break, --no-trap	break exception on div by 0 and mult overflow\n"));
15390179404Sobrien#ifdef OBJ_ELF
15391179404Sobrien  fprintf (stream, _("\
15392179404Sobrien-KPIC, -call_shared	generate SVR4 position independent code\n\
15393218822Sdim-mvxworks-pic		generate VxWorks position independent code\n\
15394179404Sobrien-non_shared		do not generate position independent code\n\
15395179404Sobrien-xgot			assume a 32 bit GOT\n\
15396179404Sobrien-mpdr, -mno-pdr		enable/disable creation of .pdr sections\n\
15397208737Sjmallett-mshared, -mno-shared   disable/enable .cpload optimization for\n\
15398218822Sdim                        position dependent (non shared) code\n\
15399179404Sobrien-mabi=ABI		create ABI conformant object file for:\n"));
15400179404Sobrien
15401179404Sobrien  first = 1;
15402179404Sobrien
15403179404Sobrien  show (stream, "32", &column, &first);
15404179404Sobrien  show (stream, "o64", &column, &first);
15405179404Sobrien  show (stream, "n32", &column, &first);
15406179404Sobrien  show (stream, "64", &column, &first);
15407179404Sobrien  show (stream, "eabi", &column, &first);
15408179404Sobrien
15409179404Sobrien  fputc ('\n', stream);
15410179404Sobrien
15411179404Sobrien  fprintf (stream, _("\
15412179404Sobrien-32			create o32 ABI object file (default)\n\
15413179404Sobrien-n32			create n32 ABI object file\n\
15414179404Sobrien-64			create 64 ABI object file\n"));
15415179404Sobrien#endif
15416208737Sjmallett  fprintf (stream, _("\
15417208737Sjmallett-mocteon-unsupported    error on unsupported Octeon instructions\n\
15418208737Sjmallett-mno-octeon-unsupported do not error on unsupported Octeon instructions\n"));
15419208737Sjmallett  fprintf (stream, _("\
15420208737Sjmallett-mocteon-useun    generate Octeon unaligned load/store instructions\n\
15421208737Sjmallett-mno-octeon-useun generate MIPS unaligned load/store instructions\n"));
15422179404Sobrien}
15423179404Sobrien
15424179404Sobrienint
15425179404Sobrienmips_dwarf2_addr_size (void)
15426179404Sobrien{
15427208737Sjmallett  if (HAVE_64BIT_SYMBOLS)
15428179404Sobrien    return 8;
15429179404Sobrien  else
15430179404Sobrien    return 4;
15431179404Sobrien}
15432208737Sjmallett
15433208737Sjmallett/* Standard calling conventions leave the CFA at SP on entry.  */
15434208737Sjmallettvoid
15435208737Sjmallettmips_cfi_frame_initial_instructions (void)
15436208737Sjmallett{
15437208737Sjmallett  cfi_add_CFA_def_cfa_register (SP);
15438208737Sjmallett}
15439208737Sjmallett
15440218822Sdimint
15441218822Sdimtc_mips_regname_to_dw2regnum (char *regname)
15442218822Sdim{
15443218822Sdim  unsigned int regnum = -1;
15444218822Sdim  unsigned int reg;
15445218822Sdim
15446218822Sdim  if (reg_lookup (&regname, RTYPE_GP | RTYPE_NUM, &reg))
15447218822Sdim    regnum = reg;
15448218822Sdim
15449218822Sdim  return regnum;
15450218822Sdim}
15451