tc-arm.c revision 248460
160484Sobrien/* tc-arm.c -- Assemble for the ARM
2218822Sdim   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
3218822Sdim   2004, 2005, 2006
477298Sobrien   Free Software Foundation, Inc.
560484Sobrien   Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
660484Sobrien	Modified by David Taylor (dtaylor@armltd.co.uk)
789857Sobrien	Cirrus coprocessor mods by Aldy Hernandez (aldyh@redhat.com)
8130561Sobrien	Cirrus coprocessor fixes by Petko Manolov (petkan@nucleusys.com)
9130561Sobrien	Cirrus coprocessor fixes by Vladimir Ivanov (vladitx@nucleusys.com)
1060484Sobrien
1160484Sobrien   This file is part of GAS, the GNU Assembler.
1260484Sobrien
1360484Sobrien   GAS is free software; you can redistribute it and/or modify
1460484Sobrien   it under the terms of the GNU General Public License as published by
1560484Sobrien   the Free Software Foundation; either version 2, or (at your option)
1660484Sobrien   any later version.
1760484Sobrien
1860484Sobrien   GAS is distributed in the hope that it will be useful,
1960484Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
20218822Sdim   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
2160484Sobrien   GNU General Public License for more details.
2260484Sobrien
2360484Sobrien   You should have received a copy of the GNU General Public License
2460484Sobrien   along with GAS; see the file COPYING.  If not, write to the Free
25218822Sdim   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
26218822Sdim   02110-1301, USA.  */
2760484Sobrien
28218822Sdim#include <limits.h>
29218822Sdim#include <stdarg.h>
30218822Sdim#define	 NO_RELOC 0
3160484Sobrien#include "as.h"
3289857Sobrien#include "safe-ctype.h"
3360484Sobrien#include "subsegs.h"
3460484Sobrien#include "obstack.h"
3560484Sobrien
36218822Sdim#include "opcode/arm.h"
37218822Sdim
3860484Sobrien#ifdef OBJ_ELF
3960484Sobrien#include "elf/arm.h"
40218822Sdim#include "dw2gencfi.h"
4160484Sobrien#endif
4260484Sobrien
43218822Sdim#include "dwarf2dbg.h"
4460484Sobrien
45218822Sdim#define WARN_DEPRECATED 1
4660484Sobrien
47218822Sdim#ifdef OBJ_ELF
48218822Sdim/* Must be at least the size of the largest unwind opcode (currently two).  */
49218822Sdim#define ARM_OPCODE_CHUNK_SIZE 8
5060484Sobrien
51218822Sdim/* This structure holds the unwinding state.  */
5289857Sobrien
53218822Sdimstatic struct
54218822Sdim{
55218822Sdim  symbolS *	  proc_start;
56218822Sdim  symbolS *	  table_entry;
57218822Sdim  symbolS *	  personality_routine;
58218822Sdim  int		  personality_index;
59218822Sdim  /* The segment containing the function.  */
60218822Sdim  segT		  saved_seg;
61218822Sdim  subsegT	  saved_subseg;
62218822Sdim  /* Opcodes generated from this function.  */
63218822Sdim  unsigned char * opcodes;
64218822Sdim  int		  opcode_count;
65218822Sdim  int		  opcode_alloc;
66218822Sdim  /* The number of bytes pushed to the stack.  */
67218822Sdim  offsetT	  frame_size;
68218822Sdim  /* We don't add stack adjustment opcodes immediately so that we can merge
69218822Sdim     multiple adjustments.  We can also omit the final adjustment
70218822Sdim     when using a frame pointer.  */
71218822Sdim  offsetT	  pending_offset;
72218822Sdim  /* These two fields are set by both unwind_movsp and unwind_setfp.  They
73218822Sdim     hold the reg+offset to use when restoring sp from a frame pointer.	 */
74218822Sdim  offsetT	  fp_offset;
75218822Sdim  int		  fp_reg;
76218822Sdim  /* Nonzero if an unwind_setfp directive has been seen.  */
77218822Sdim  unsigned	  fp_used:1;
78218822Sdim  /* Nonzero if the last opcode restores sp from fp_reg.  */
79218822Sdim  unsigned	  sp_restored:1;
80218822Sdim} unwind;
8189857Sobrien
82218822Sdim/* Bit N indicates that an R_ARM_NONE relocation has been output for
83218822Sdim   __aeabi_unwind_cpp_prN already if set. This enables dependencies to be
84218822Sdim   emitted only once per section, to save unnecessary bloat.  */
85218822Sdimstatic unsigned int marked_pr_dependency = 0;
8660484Sobrien
87218822Sdim#endif /* OBJ_ELF */
8860484Sobrien
89218822Sdim/* Results from operand parsing worker functions.  */
9060484Sobrien
91218822Sdimtypedef enum
92218822Sdim{
93218822Sdim  PARSE_OPERAND_SUCCESS,
94218822Sdim  PARSE_OPERAND_FAIL,
95218822Sdim  PARSE_OPERAND_FAIL_NO_BACKTRACK
96218822Sdim} parse_operand_result;
9789857Sobrien
98130561Sobrienenum arm_float_abi
99130561Sobrien{
100130561Sobrien  ARM_FLOAT_ABI_HARD,
101130561Sobrien  ARM_FLOAT_ABI_SOFTFP,
102130561Sobrien  ARM_FLOAT_ABI_SOFT
103130561Sobrien};
104130561Sobrien
105218822Sdim/* Types of processor to assemble for.	*/
10660484Sobrien#ifndef CPU_DEFAULT
10777298Sobrien#if defined __XSCALE__
108218822Sdim#define CPU_DEFAULT	ARM_ARCH_XSCALE
10977298Sobrien#else
11060484Sobrien#if defined __thumb__
111218822Sdim#define CPU_DEFAULT	ARM_ARCH_V5T
11260484Sobrien#endif
11360484Sobrien#endif
11477298Sobrien#endif
11560484Sobrien
11660484Sobrien#ifndef FPU_DEFAULT
117218822Sdim# ifdef TE_LINUX
118218822Sdim#  define FPU_DEFAULT FPU_ARCH_FPA
119218822Sdim# elif defined (TE_NetBSD)
120218822Sdim#  ifdef OBJ_ELF
121218822Sdim#   define FPU_DEFAULT FPU_ARCH_VFP	/* Soft-float, but VFP order.  */
122218822Sdim#  else
123218822Sdim    /* Legacy a.out format.  */
124218822Sdim#   define FPU_DEFAULT FPU_ARCH_FPA	/* Soft-float, but FPA order.  */
125218822Sdim#  endif
126218822Sdim# elif defined (TE_VXWORKS)
127218822Sdim#  define FPU_DEFAULT FPU_ARCH_VFP	/* Soft-float, VFP order.  */
128218822Sdim# else
129218822Sdim   /* For backwards compatibility, default to FPA.  */
130218822Sdim#  define FPU_DEFAULT FPU_ARCH_FPA
131218822Sdim# endif
132218822Sdim#endif /* ifndef FPU_DEFAULT */
13360484Sobrien
134218822Sdim#define streq(a, b)	      (strcmp (a, b) == 0)
13560484Sobrien
136218822Sdimstatic arm_feature_set cpu_variant;
137218822Sdimstatic arm_feature_set arm_arch_used;
138218822Sdimstatic arm_feature_set thumb_arch_used;
13960484Sobrien
14077298Sobrien/* Flags stored in private area of BFD structure.  */
141218822Sdimstatic int uses_apcs_26	     = FALSE;
142218822Sdimstatic int atpcs	     = FALSE;
143130561Sobrienstatic int support_interwork = FALSE;
144130561Sobrienstatic int uses_apcs_float   = FALSE;
145218822Sdimstatic int pic_code	     = FALSE;
14660484Sobrien
14789857Sobrien/* Variables that we set while parsing command-line options.  Once all
14889857Sobrien   options have been read we re-process these values to set the real
14989857Sobrien   assembly flags.  */
150218822Sdimstatic const arm_feature_set *legacy_cpu = NULL;
151218822Sdimstatic const arm_feature_set *legacy_fpu = NULL;
15289857Sobrien
153218822Sdimstatic const arm_feature_set *mcpu_cpu_opt = NULL;
154218822Sdimstatic const arm_feature_set *mcpu_fpu_opt = NULL;
155218822Sdimstatic const arm_feature_set *march_cpu_opt = NULL;
156218822Sdimstatic const arm_feature_set *march_fpu_opt = NULL;
157218822Sdimstatic const arm_feature_set *mfpu_opt = NULL;
158218822Sdimstatic const arm_feature_set *object_arch = NULL;
15989857Sobrien
160218822Sdim/* Constants for known architecture features.  */
161218822Sdimstatic const arm_feature_set fpu_default = FPU_DEFAULT;
162218822Sdimstatic const arm_feature_set fpu_arch_vfp_v1 = FPU_ARCH_VFP_V1;
163218822Sdimstatic const arm_feature_set fpu_arch_vfp_v2 = FPU_ARCH_VFP_V2;
164218822Sdimstatic const arm_feature_set fpu_arch_vfp_v3 = FPU_ARCH_VFP_V3;
165218822Sdimstatic const arm_feature_set fpu_arch_neon_v1 = FPU_ARCH_NEON_V1;
166218822Sdimstatic const arm_feature_set fpu_arch_fpa = FPU_ARCH_FPA;
167218822Sdimstatic const arm_feature_set fpu_any_hard = FPU_ANY_HARD;
168218822Sdimstatic const arm_feature_set fpu_arch_maverick = FPU_ARCH_MAVERICK;
169218822Sdimstatic const arm_feature_set fpu_endian_pure = FPU_ARCH_ENDIAN_PURE;
17060484Sobrien
171218822Sdim#ifdef CPU_DEFAULT
172218822Sdimstatic const arm_feature_set cpu_default = CPU_DEFAULT;
173218822Sdim#endif
17460484Sobrien
175218822Sdimstatic const arm_feature_set arm_ext_v1 = ARM_FEATURE (ARM_EXT_V1, 0);
176218822Sdimstatic const arm_feature_set arm_ext_v2 = ARM_FEATURE (ARM_EXT_V1, 0);
177218822Sdimstatic const arm_feature_set arm_ext_v2s = ARM_FEATURE (ARM_EXT_V2S, 0);
178218822Sdimstatic const arm_feature_set arm_ext_v3 = ARM_FEATURE (ARM_EXT_V3, 0);
179218822Sdimstatic const arm_feature_set arm_ext_v3m = ARM_FEATURE (ARM_EXT_V3M, 0);
180218822Sdimstatic const arm_feature_set arm_ext_v4 = ARM_FEATURE (ARM_EXT_V4, 0);
181218822Sdimstatic const arm_feature_set arm_ext_v4t = ARM_FEATURE (ARM_EXT_V4T, 0);
182218822Sdimstatic const arm_feature_set arm_ext_v5 = ARM_FEATURE (ARM_EXT_V5, 0);
183218822Sdimstatic const arm_feature_set arm_ext_v4t_5 =
184218822Sdim  ARM_FEATURE (ARM_EXT_V4T | ARM_EXT_V5, 0);
185218822Sdimstatic const arm_feature_set arm_ext_v5t = ARM_FEATURE (ARM_EXT_V5T, 0);
186218822Sdimstatic const arm_feature_set arm_ext_v5e = ARM_FEATURE (ARM_EXT_V5E, 0);
187218822Sdimstatic const arm_feature_set arm_ext_v5exp = ARM_FEATURE (ARM_EXT_V5ExP, 0);
188218822Sdimstatic const arm_feature_set arm_ext_v5j = ARM_FEATURE (ARM_EXT_V5J, 0);
189218822Sdimstatic const arm_feature_set arm_ext_v6 = ARM_FEATURE (ARM_EXT_V6, 0);
190218822Sdimstatic const arm_feature_set arm_ext_v6k = ARM_FEATURE (ARM_EXT_V6K, 0);
191218822Sdimstatic const arm_feature_set arm_ext_v6z = ARM_FEATURE (ARM_EXT_V6Z, 0);
192218822Sdimstatic const arm_feature_set arm_ext_v6t2 = ARM_FEATURE (ARM_EXT_V6T2, 0);
193218822Sdimstatic const arm_feature_set arm_ext_v6_notm = ARM_FEATURE (ARM_EXT_V6_NOTM, 0);
194218822Sdimstatic const arm_feature_set arm_ext_div = ARM_FEATURE (ARM_EXT_DIV, 0);
195218822Sdimstatic const arm_feature_set arm_ext_v7 = ARM_FEATURE (ARM_EXT_V7, 0);
196218822Sdimstatic const arm_feature_set arm_ext_v7a = ARM_FEATURE (ARM_EXT_V7A, 0);
197218822Sdimstatic const arm_feature_set arm_ext_v7r = ARM_FEATURE (ARM_EXT_V7R, 0);
198218822Sdimstatic const arm_feature_set arm_ext_v7m = ARM_FEATURE (ARM_EXT_V7M, 0);
19960484Sobrien
200218822Sdimstatic const arm_feature_set arm_arch_any = ARM_ANY;
201218822Sdimstatic const arm_feature_set arm_arch_full = ARM_FEATURE (-1, -1);
202218822Sdimstatic const arm_feature_set arm_arch_t2 = ARM_ARCH_THUMB2;
203218822Sdimstatic const arm_feature_set arm_arch_none = ARM_ARCH_NONE;
20460484Sobrien
205218822Sdimstatic const arm_feature_set arm_cext_iwmmxt2 =
206218822Sdim  ARM_FEATURE (0, ARM_CEXT_IWMMXT2);
207218822Sdimstatic const arm_feature_set arm_cext_iwmmxt =
208218822Sdim  ARM_FEATURE (0, ARM_CEXT_IWMMXT);
209218822Sdimstatic const arm_feature_set arm_cext_xscale =
210218822Sdim  ARM_FEATURE (0, ARM_CEXT_XSCALE);
211218822Sdimstatic const arm_feature_set arm_cext_maverick =
212218822Sdim  ARM_FEATURE (0, ARM_CEXT_MAVERICK);
213218822Sdimstatic const arm_feature_set fpu_fpa_ext_v1 = ARM_FEATURE (0, FPU_FPA_EXT_V1);
214218822Sdimstatic const arm_feature_set fpu_fpa_ext_v2 = ARM_FEATURE (0, FPU_FPA_EXT_V2);
215218822Sdimstatic const arm_feature_set fpu_vfp_ext_v1xd =
216218822Sdim  ARM_FEATURE (0, FPU_VFP_EXT_V1xD);
217218822Sdimstatic const arm_feature_set fpu_vfp_ext_v1 = ARM_FEATURE (0, FPU_VFP_EXT_V1);
218218822Sdimstatic const arm_feature_set fpu_vfp_ext_v2 = ARM_FEATURE (0, FPU_VFP_EXT_V2);
219218822Sdimstatic const arm_feature_set fpu_vfp_ext_v3 = ARM_FEATURE (0, FPU_VFP_EXT_V3);
220218822Sdimstatic const arm_feature_set fpu_neon_ext_v1 = ARM_FEATURE (0, FPU_NEON_EXT_V1);
221218822Sdimstatic const arm_feature_set fpu_vfp_v3_or_neon_ext =
222218822Sdim  ARM_FEATURE (0, FPU_NEON_EXT_V1 | FPU_VFP_EXT_V3);
22360484Sobrien
224218822Sdimstatic int mfloat_abi_opt = -1;
225218822Sdim/* Record user cpu selection for object attributes.  */
226218822Sdimstatic arm_feature_set selected_cpu = ARM_ARCH_NONE;
227218822Sdim/* Must be long enough to hold any of the names in arm_cpus.  */
228218822Sdimstatic char selected_cpu_name[16];
229218822Sdim#ifdef OBJ_ELF
230218822Sdim# ifdef EABI_DEFAULT
231218822Sdimstatic int meabi_flags = EABI_DEFAULT;
232218822Sdim# else
233218822Sdimstatic int meabi_flags = EF_ARM_EABI_UNKNOWN;
234218822Sdim# endif
23560484Sobrien
236218822Sdimbfd_boolean
237218822Sdimarm_is_eabi(void)
238218822Sdim{
239218822Sdim  return (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4);
240218822Sdim}
241218822Sdim#endif
24260484Sobrien
24360484Sobrien#ifdef OBJ_ELF
244218822Sdim/* Pre-defined "_GLOBAL_OFFSET_TABLE_"	*/
24577298SobriensymbolS * GOT_symbol;
24660484Sobrien#endif
24760484Sobrien
24877298Sobrien/* 0: assemble for ARM,
24977298Sobrien   1: assemble for Thumb,
25077298Sobrien   2: assemble for Thumb even though target CPU does not support thumb
25177298Sobrien      instructions.  */
25277298Sobrienstatic int thumb_mode = 0;
25377298Sobrien
254218822Sdim/* If unified_syntax is true, we are processing the new unified
255218822Sdim   ARM/Thumb syntax.  Important differences from the old ARM mode:
25660484Sobrien
257218822Sdim     - Immediate operands do not require a # prefix.
258218822Sdim     - Conditional affixes always appear at the end of the
259218822Sdim       instruction.  (For backward compatibility, those instructions
260218822Sdim       that formerly had them in the middle, continue to accept them
261218822Sdim       there.)
262218822Sdim     - The IT instruction may appear, and if it does is validated
263218822Sdim       against subsequent conditional affixes.  It does not generate
264218822Sdim       machine code.
26560484Sobrien
266218822Sdim   Important differences from the old Thumb mode:
26760484Sobrien
268218822Sdim     - Immediate operands do not require a # prefix.
269218822Sdim     - Most of the V6T2 instructions are only available in unified mode.
270218822Sdim     - The .N and .W suffixes are recognized and honored (it is an error
271218822Sdim       if they cannot be honored).
272218822Sdim     - All instructions set the flags if and only if they have an 's' affix.
273218822Sdim     - Conditional affixes may be used.  They are validated against
274218822Sdim       preceding IT instructions.  Unlike ARM mode, you cannot use a
275218822Sdim       conditional affix except in the scope of an IT instruction.  */
276218822Sdim
277218822Sdimstatic bfd_boolean unified_syntax = FALSE;
278218822Sdim
279218822Sdimenum neon_el_type
28060484Sobrien{
281218822Sdim  NT_invtype,
282218822Sdim  NT_untyped,
283218822Sdim  NT_integer,
284218822Sdim  NT_float,
285218822Sdim  NT_poly,
286218822Sdim  NT_signed,
287218822Sdim  NT_unsigned
28860484Sobrien};
28960484Sobrien
290218822Sdimstruct neon_type_el
29160484Sobrien{
292218822Sdim  enum neon_el_type type;
293218822Sdim  unsigned size;
29460484Sobrien};
29560484Sobrien
296218822Sdim#define NEON_MAX_TYPE_ELS 4
297218822Sdim
298218822Sdimstruct neon_type
29977298Sobrien{
300218822Sdim  struct neon_type_el el[NEON_MAX_TYPE_ELS];
301218822Sdim  unsigned elems;
30277298Sobrien};
30377298Sobrien
304218822Sdimstruct arm_it
30577298Sobrien{
306218822Sdim  const char *	error;
307218822Sdim  unsigned long instruction;
308218822Sdim  int		size;
309218822Sdim  int		size_req;
310218822Sdim  int		cond;
311218822Sdim  /* "uncond_value" is set to the value in place of the conditional field in
312218822Sdim     unconditional versions of the instruction, or -1 if nothing is
313218822Sdim     appropriate.  */
314218822Sdim  int		uncond_value;
315218822Sdim  struct neon_type vectype;
316218822Sdim  /* Set to the opcode if the instruction needs relaxation.
317218822Sdim     Zero if the instruction is not relaxed.  */
318218822Sdim  unsigned long	relax;
319218822Sdim  struct
320218822Sdim  {
321218822Sdim    bfd_reloc_code_real_type type;
322218822Sdim    expressionS		     exp;
323218822Sdim    int			     pc_rel;
324218822Sdim  } reloc;
32577298Sobrien
326218822Sdim  struct
327218822Sdim  {
328218822Sdim    unsigned reg;
329218822Sdim    signed int imm;
330218822Sdim    struct neon_type_el vectype;
331218822Sdim    unsigned present	: 1;  /* Operand present.  */
332218822Sdim    unsigned isreg	: 1;  /* Operand was a register.  */
333218822Sdim    unsigned immisreg	: 1;  /* .imm field is a second register.  */
334218822Sdim    unsigned isscalar   : 1;  /* Operand is a (Neon) scalar.  */
335218822Sdim    unsigned immisalign : 1;  /* Immediate is an alignment specifier.  */
336218822Sdim    unsigned immisfloat : 1;  /* Immediate was parsed as a float.  */
337218822Sdim    /* Note: we abuse "regisimm" to mean "is Neon register" in VMOV
338218822Sdim       instructions. This allows us to disambiguate ARM <-> vector insns.  */
339218822Sdim    unsigned regisimm   : 1;  /* 64-bit immediate, reg forms high 32 bits.  */
340218822Sdim    unsigned isvec      : 1;  /* Is a single, double or quad VFP/Neon reg.  */
341218822Sdim    unsigned isquad     : 1;  /* Operand is Neon quad-precision register.  */
342218822Sdim    unsigned issingle   : 1;  /* Operand is VFP single-precision register.  */
343218822Sdim    unsigned hasreloc	: 1;  /* Operand has relocation suffix.  */
344218822Sdim    unsigned writeback	: 1;  /* Operand has trailing !  */
345218822Sdim    unsigned preind	: 1;  /* Preindexed address.  */
346218822Sdim    unsigned postind	: 1;  /* Postindexed address.  */
347218822Sdim    unsigned negative	: 1;  /* Index register was negated.  */
348218822Sdim    unsigned shifted	: 1;  /* Shift applied to operation.  */
349218822Sdim    unsigned shift_kind : 3;  /* Shift operation (enum shift_kind).  */
350218822Sdim  } operands[6];
35177298Sobrien};
35277298Sobrien
353218822Sdimstatic struct arm_it inst;
35460484Sobrien
35560484Sobrien#define NUM_FLOAT_VALS 8
35660484Sobrien
35789857Sobrienconst char * fp_const[] =
35860484Sobrien{
35960484Sobrien  "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0", 0
36060484Sobrien};
36160484Sobrien
362218822Sdim/* Number of littlenums required to hold an extended precision number.	*/
36360484Sobrien#define MAX_LITTLENUMS 6
36460484Sobrien
36560484SobrienLITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS];
36660484Sobrien
36760484Sobrien#define FAIL	(-1)
36860484Sobrien#define SUCCESS (0)
36960484Sobrien
37060484Sobrien#define SUFF_S 1
37160484Sobrien#define SUFF_D 2
37260484Sobrien#define SUFF_E 3
37360484Sobrien#define SUFF_P 4
37460484Sobrien
375218822Sdim#define CP_T_X	 0x00008000
376218822Sdim#define CP_T_Y	 0x00400000
37760484Sobrien
378218822Sdim#define CONDS_BIT	 0x00100000
379218822Sdim#define LOAD_BIT	 0x00100000
38060484Sobrien
38177298Sobrien#define DOUBLE_LOAD_FLAG 0x00000001
38277298Sobrien
38360484Sobrienstruct asm_cond
38460484Sobrien{
385218822Sdim  const char *	template;
38660484Sobrien  unsigned long value;
38760484Sobrien};
38860484Sobrien
389218822Sdim#define COND_ALWAYS 0xE
39060484Sobrien
391218822Sdimstruct asm_psr
39260484Sobrien{
393218822Sdim  const char *template;
394218822Sdim  unsigned long field;
39560484Sobrien};
39660484Sobrien
397218822Sdimstruct asm_barrier_opt
39860484Sobrien{
399130561Sobrien  const char *template;
400218822Sdim  unsigned long value;
40160484Sobrien};
40260484Sobrien
403130561Sobrien/* The bit that distinguishes CPSR and SPSR.  */
40477298Sobrien#define SPSR_BIT   (1 << 22)
40560484Sobrien
406218822Sdim/* The individual PSR flag bits.  */
407218822Sdim#define PSR_c	(1 << 16)
408218822Sdim#define PSR_x	(1 << 17)
409218822Sdim#define PSR_s	(1 << 18)
410218822Sdim#define PSR_f	(1 << 19)
41177298Sobrien
412218822Sdimstruct reloc_entry
41360484Sobrien{
414218822Sdim  char *name;
415218822Sdim  bfd_reloc_code_real_type reloc;
41660484Sobrien};
41760484Sobrien
418218822Sdimenum vfp_reg_pos
419130561Sobrien{
420218822Sdim  VFP_REG_Sd, VFP_REG_Sm, VFP_REG_Sn,
42189857Sobrien  VFP_REG_Dd, VFP_REG_Dm, VFP_REG_Dn
42289857Sobrien};
42389857Sobrien
42489857Sobrienenum vfp_ldstm_type
42589857Sobrien{
42689857Sobrien  VFP_LDSTMIA, VFP_LDSTMDB, VFP_LDSTMIAX, VFP_LDSTMDBX
42789857Sobrien};
42889857Sobrien
429218822Sdim/* Bits for DEFINED field in neon_typed_alias.  */
430218822Sdim#define NTA_HASTYPE  1
431218822Sdim#define NTA_HASINDEX 2
432218822Sdim
433218822Sdimstruct neon_typed_alias
43489857Sobrien{
435218822Sdim  unsigned char defined;
436218822Sdim  unsigned char index;
437218822Sdim  struct neon_type_el eltype;
43889857Sobrien};
43989857Sobrien
440218822Sdim/* ARM register categories.  This includes coprocessor numbers and various
441218822Sdim   architecture extensions' registers.	*/
442218822Sdimenum arm_reg_type
44389857Sobrien{
444218822Sdim  REG_TYPE_RN,
445218822Sdim  REG_TYPE_CP,
446218822Sdim  REG_TYPE_CN,
447218822Sdim  REG_TYPE_FN,
448218822Sdim  REG_TYPE_VFS,
449218822Sdim  REG_TYPE_VFD,
450218822Sdim  REG_TYPE_NQ,
451218822Sdim  REG_TYPE_VFSD,
452218822Sdim  REG_TYPE_NDQ,
453218822Sdim  REG_TYPE_NSDQ,
454218822Sdim  REG_TYPE_VFC,
455218822Sdim  REG_TYPE_MVF,
456218822Sdim  REG_TYPE_MVD,
457218822Sdim  REG_TYPE_MVFX,
458218822Sdim  REG_TYPE_MVDX,
459218822Sdim  REG_TYPE_MVAX,
460218822Sdim  REG_TYPE_DSPSC,
461218822Sdim  REG_TYPE_MMXWR,
462218822Sdim  REG_TYPE_MMXWC,
463218822Sdim  REG_TYPE_MMXWCG,
464218822Sdim  REG_TYPE_XSCALE,
46589857Sobrien};
46689857Sobrien
467218822Sdim/* Structure for a hash table entry for a register.
468218822Sdim   If TYPE is REG_TYPE_VFD or REG_TYPE_NQ, the NEON field can point to extra
469218822Sdim   information which states whether a vector type or index is specified (for a
470218822Sdim   register alias created with .dn or .qn). Otherwise NEON should be NULL.  */
47189857Sobrienstruct reg_entry
47289857Sobrien{
473218822Sdim  const char        *name;
474218822Sdim  unsigned char      number;
475218822Sdim  unsigned char      type;
476218822Sdim  unsigned char      builtin;
477218822Sdim  struct neon_typed_alias *neon;
47889857Sobrien};
47989857Sobrien
480218822Sdim/* Diagnostics used when we don't get a register of the expected type.	*/
481218822Sdimconst char *const reg_expected_msgs[] =
482218822Sdim{
483218822Sdim  N_("ARM register expected"),
484218822Sdim  N_("bad or missing co-processor number"),
485218822Sdim  N_("co-processor register expected"),
486218822Sdim  N_("FPA register expected"),
487218822Sdim  N_("VFP single precision register expected"),
488218822Sdim  N_("VFP/Neon double precision register expected"),
489218822Sdim  N_("Neon quad precision register expected"),
490218822Sdim  N_("VFP single or double precision register expected"),
491218822Sdim  N_("Neon double or quad precision register expected"),
492218822Sdim  N_("VFP single, double or Neon quad precision register expected"),
493218822Sdim  N_("VFP system register expected"),
494218822Sdim  N_("Maverick MVF register expected"),
495218822Sdim  N_("Maverick MVD register expected"),
496218822Sdim  N_("Maverick MVFX register expected"),
497218822Sdim  N_("Maverick MVDX register expected"),
498218822Sdim  N_("Maverick MVAX register expected"),
499218822Sdim  N_("Maverick DSPSC register expected"),
500218822Sdim  N_("iWMMXt data register expected"),
501218822Sdim  N_("iWMMXt control register expected"),
502218822Sdim  N_("iWMMXt scalar register expected"),
503218822Sdim  N_("XScale accumulator register expected"),
504218822Sdim};
505218822Sdim
50689857Sobrien/* Some well known registers that we refer to directly elsewhere.  */
507218822Sdim#define REG_SP	13
508218822Sdim#define REG_LR	14
50989857Sobrien#define REG_PC	15
51089857Sobrien
511218822Sdim/* ARM instructions take 4bytes in the object file, Thumb instructions
512218822Sdim   take 2:  */
513218822Sdim#define INSN_SIZE	4
514130561Sobrien
515218822Sdimstruct asm_opcode
51689857Sobrien{
517218822Sdim  /* Basic string to match.  */
518218822Sdim  const char *template;
51989857Sobrien
520218822Sdim  /* Parameters to instruction.	 */
521218822Sdim  unsigned char operands[8];
522130561Sobrien
523218822Sdim  /* Conditional tag - see opcode_lookup.  */
524218822Sdim  unsigned int tag : 4;
525130561Sobrien
526218822Sdim  /* Basic instruction code.  */
527218822Sdim  unsigned int avalue : 28;
528130561Sobrien
529218822Sdim  /* Thumb-format instruction code.  */
530218822Sdim  unsigned int tvalue;
53189857Sobrien
532218822Sdim  /* Which architecture variant provides this instruction.  */
533218822Sdim  const arm_feature_set *avariant;
534218822Sdim  const arm_feature_set *tvariant;
53589857Sobrien
536218822Sdim  /* Function to call to encode instruction in ARM format.  */
537218822Sdim  void (* aencode) (void);
53889857Sobrien
539218822Sdim  /* Function to call to encode instruction in Thumb format.  */
540218822Sdim  void (* tencode) (void);
54189857Sobrien};
54289857Sobrien
543218822Sdim/* Defines for various bits that we will want to toggle.  */
544218822Sdim#define INST_IMMEDIATE	0x02000000
545218822Sdim#define OFFSET_REG	0x02000000
546218822Sdim#define HWOFFSET_IMM	0x00400000
547218822Sdim#define SHIFT_BY_REG	0x00000010
548218822Sdim#define PRE_INDEX	0x01000000
549218822Sdim#define INDEX_UP	0x00800000
550218822Sdim#define WRITE_BACK	0x00200000
551218822Sdim#define LDM_TYPE_2_OR_3	0x00400000
552218822Sdim#define CPSI_MMOD	0x00020000
55389857Sobrien
554218822Sdim#define LITERAL_MASK	0xf000f000
555218822Sdim#define OPCODE_MASK	0xfe1fffff
556218822Sdim#define V4_STR_BIT	0x00000020
55789857Sobrien
558218822Sdim#define T2_SUBS_PC_LR	0xf3de8f00
55989857Sobrien
560218822Sdim#define DATA_OP_SHIFT	21
56189857Sobrien
562218822Sdim#define T2_OPCODE_MASK	0xfe1fffff
563218822Sdim#define T2_DATA_OP_SHIFT 21
56489857Sobrien
565218822Sdim/* Codes to distinguish the arithmetic instructions.  */
566218822Sdim#define OPCODE_AND	0
567218822Sdim#define OPCODE_EOR	1
568218822Sdim#define OPCODE_SUB	2
569218822Sdim#define OPCODE_RSB	3
570218822Sdim#define OPCODE_ADD	4
571218822Sdim#define OPCODE_ADC	5
572218822Sdim#define OPCODE_SBC	6
573218822Sdim#define OPCODE_RSC	7
574218822Sdim#define OPCODE_TST	8
575218822Sdim#define OPCODE_TEQ	9
576218822Sdim#define OPCODE_CMP	10
577218822Sdim#define OPCODE_CMN	11
578218822Sdim#define OPCODE_ORR	12
579218822Sdim#define OPCODE_MOV	13
580218822Sdim#define OPCODE_BIC	14
581218822Sdim#define OPCODE_MVN	15
58289857Sobrien
583218822Sdim#define T2_OPCODE_AND	0
584218822Sdim#define T2_OPCODE_BIC	1
585218822Sdim#define T2_OPCODE_ORR	2
586218822Sdim#define T2_OPCODE_ORN	3
587218822Sdim#define T2_OPCODE_EOR	4
588218822Sdim#define T2_OPCODE_ADD	8
589218822Sdim#define T2_OPCODE_ADC	10
590218822Sdim#define T2_OPCODE_SBC	11
591218822Sdim#define T2_OPCODE_SUB	13
592218822Sdim#define T2_OPCODE_RSB	14
59389857Sobrien
594218822Sdim#define T_OPCODE_MUL 0x4340
595218822Sdim#define T_OPCODE_TST 0x4200
596218822Sdim#define T_OPCODE_CMN 0x42c0
597218822Sdim#define T_OPCODE_NEG 0x4240
598218822Sdim#define T_OPCODE_MVN 0x43c0
59989857Sobrien
600218822Sdim#define T_OPCODE_ADD_R3	0x1800
601218822Sdim#define T_OPCODE_SUB_R3 0x1a00
602218822Sdim#define T_OPCODE_ADD_HI 0x4400
603218822Sdim#define T_OPCODE_ADD_ST 0xb000
604218822Sdim#define T_OPCODE_SUB_ST 0xb080
605218822Sdim#define T_OPCODE_ADD_SP 0xa800
606218822Sdim#define T_OPCODE_ADD_PC 0xa000
607218822Sdim#define T_OPCODE_ADD_I8 0x3000
608218822Sdim#define T_OPCODE_SUB_I8 0x3800
609218822Sdim#define T_OPCODE_ADD_I3 0x1c00
610218822Sdim#define T_OPCODE_SUB_I3 0x1e00
61189857Sobrien
612218822Sdim#define T_OPCODE_ASR_R	0x4100
613218822Sdim#define T_OPCODE_LSL_R	0x4080
614218822Sdim#define T_OPCODE_LSR_R	0x40c0
615218822Sdim#define T_OPCODE_ROR_R	0x41c0
616218822Sdim#define T_OPCODE_ASR_I	0x1000
617218822Sdim#define T_OPCODE_LSL_I	0x0000
618218822Sdim#define T_OPCODE_LSR_I	0x0800
61989857Sobrien
620218822Sdim#define T_OPCODE_MOV_I8	0x2000
621218822Sdim#define T_OPCODE_CMP_I8 0x2800
622218822Sdim#define T_OPCODE_CMP_LR 0x4280
623218822Sdim#define T_OPCODE_MOV_HR 0x4600
624218822Sdim#define T_OPCODE_CMP_HR 0x4500
62589857Sobrien
626218822Sdim#define T_OPCODE_LDR_PC 0x4800
627218822Sdim#define T_OPCODE_LDR_SP 0x9800
628218822Sdim#define T_OPCODE_STR_SP 0x9000
629218822Sdim#define T_OPCODE_LDR_IW 0x6800
630218822Sdim#define T_OPCODE_STR_IW 0x6000
631218822Sdim#define T_OPCODE_LDR_IH 0x8800
632218822Sdim#define T_OPCODE_STR_IH 0x8000
633218822Sdim#define T_OPCODE_LDR_IB 0x7800
634218822Sdim#define T_OPCODE_STR_IB 0x7000
635218822Sdim#define T_OPCODE_LDR_RW 0x5800
636218822Sdim#define T_OPCODE_STR_RW 0x5000
637218822Sdim#define T_OPCODE_LDR_RH 0x5a00
638218822Sdim#define T_OPCODE_STR_RH 0x5200
639218822Sdim#define T_OPCODE_LDR_RB 0x5c00
640218822Sdim#define T_OPCODE_STR_RB 0x5400
64189857Sobrien
642218822Sdim#define T_OPCODE_PUSH	0xb400
643218822Sdim#define T_OPCODE_POP	0xbc00
64460484Sobrien
645218822Sdim#define T_OPCODE_BRANCH 0xe000
64677298Sobrien
647218822Sdim#define THUMB_SIZE	2	/* Size of thumb instruction.  */
648218822Sdim#define THUMB_PP_PC_LR 0x0100
649218822Sdim#define THUMB_LOAD_BIT 0x0800
650218822Sdim#define THUMB2_LOAD_BIT 0x00100000
65177298Sobrien
652218822Sdim#define BAD_ARGS	_("bad arguments to instruction")
653218822Sdim#define BAD_PC		_("r15 not allowed here")
654248460Sandrew#define BAD_SP		_("r13 not allowed here")
655218822Sdim#define BAD_COND	_("instruction cannot be conditional")
656218822Sdim#define BAD_OVERLAP	_("registers may not be the same")
657218822Sdim#define BAD_HIREG	_("lo register required")
658218822Sdim#define BAD_THUMB32	_("instruction not supported in Thumb16 mode")
659218822Sdim#define BAD_ADDR_MODE   _("instruction does not accept this addressing mode");
660218822Sdim#define BAD_BRANCH	_("branch must be last instruction in IT block")
661218822Sdim#define BAD_NOT_IT	_("instruction not allowed in IT block")
662218822Sdim#define BAD_FPU		_("selected FPU does not support instruction")
663248460Sandrew#define BAD_VMRS	_("APSR_nzcv may only be used with fpscr")
66477298Sobrien
665218822Sdimstatic struct hash_control *arm_ops_hsh;
666218822Sdimstatic struct hash_control *arm_cond_hsh;
667218822Sdimstatic struct hash_control *arm_shift_hsh;
668218822Sdimstatic struct hash_control *arm_psr_hsh;
669218822Sdimstatic struct hash_control *arm_v7m_psr_hsh;
670218822Sdimstatic struct hash_control *arm_reg_hsh;
671218822Sdimstatic struct hash_control *arm_reloc_hsh;
672218822Sdimstatic struct hash_control *arm_barrier_opt_hsh;
67377298Sobrien
674218822Sdim/* Stuff needed to resolve the label ambiguity
675218822Sdim   As:
676218822Sdim     ...
677218822Sdim     label:   <insn>
678218822Sdim   may differ from:
679218822Sdim     ...
680218822Sdim     label:
681218822Sdim	      <insn>
682218822Sdim*/
68389857Sobrien
684218822SdimsymbolS *  last_label_seen;
685218822Sdimstatic int label_is_thumb_function_name = FALSE;
686218822Sdim
687218822Sdim/* Literal pool structure.  Held on a per-section
688218822Sdim   and per-sub-section basis.  */
68989857Sobrien
690218822Sdim#define MAX_LITERAL_POOL_SIZE 1024
691218822Sdimtypedef struct literal_pool
692218822Sdim{
693218822Sdim  expressionS	 literals [MAX_LITERAL_POOL_SIZE];
694218822Sdim  unsigned int	 next_free_entry;
695218822Sdim  unsigned int	 id;
696218822Sdim  symbolS *	 symbol;
697218822Sdim  segT		 section;
698218822Sdim  subsegT	 sub_section;
699218822Sdim  struct literal_pool * next;
700218822Sdim} literal_pool;
70189857Sobrien
702218822Sdim/* Pointer to a linked list of literal pools.  */
703218822Sdimliteral_pool * list_of_pools = NULL;
70489857Sobrien
705218822Sdim/* State variables for IT block handling.  */
706218822Sdimstatic bfd_boolean current_it_mask = 0;
707218822Sdimstatic int current_cc;
70889857Sobrien
709218822Sdim
710218822Sdim/* Pure syntax.	 */
71189857Sobrien
712218822Sdim/* This array holds the chars that always start a comment.  If the
713218822Sdim   pre-processor is disabled, these aren't very useful.	 */
714218822Sdimconst char comment_chars[] = "@";
715130561Sobrien
716218822Sdim/* This array holds the chars that only start a comment at the beginning of
717218822Sdim   a line.  If the line seems to have the form '# 123 filename'
718218822Sdim   .line and .file directives will appear in the pre-processed output.	*/
719218822Sdim/* Note that input_file.c hand checks for '#' at the beginning of the
720218822Sdim   first line of the input file.  This is because the compiler outputs
721218822Sdim   #NO_APP at the beginning of its output.  */
722218822Sdim/* Also note that comments like this one will always work.  */
723218822Sdimconst char line_comment_chars[] = "#";
724130561Sobrien
725218822Sdimconst char line_separator_chars[] = ";";
72660484Sobrien
727218822Sdim/* Chars that can be used to separate mant
728218822Sdim   from exp in floating point numbers.	*/
729218822Sdimconst char EXP_CHARS[] = "eE";
73089857Sobrien
731218822Sdim/* Chars that mean this number is a floating point constant.  */
732218822Sdim/* As in 0f12.456  */
733218822Sdim/* or	 0d1.2345e12  */
73489857Sobrien
735218822Sdimconst char FLT_CHARS[] = "rRsSfFdDxXeEpP";
73689857Sobrien
737218822Sdim/* Prefix characters that indicate the start of an immediate
738218822Sdim   value.  */
739218822Sdim#define is_immediate_prefix(C) ((C) == '#' || (C) == '$')
74089857Sobrien
741218822Sdim/* Separator character handling.  */
74289857Sobrien
743218822Sdim#define skip_whitespace(str)  do { if (*(str) == ' ') ++(str); } while (0)
74460484Sobrien
745218822Sdimstatic inline int
746218822Sdimskip_past_char (char ** str, char c)
747218822Sdim{
748218822Sdim  if (**str == c)
749218822Sdim    {
750218822Sdim      (*str)++;
751218822Sdim      return SUCCESS;
752218822Sdim    }
753218822Sdim  else
754218822Sdim    return FAIL;
755218822Sdim}
756218822Sdim#define skip_past_comma(str) skip_past_char (str, ',')
757130561Sobrien
758218822Sdim/* Arithmetic expressions (possibly involving symbols).	 */
75960484Sobrien
760218822Sdim/* Return TRUE if anything in the expression is a bignum.  */
76160484Sobrien
762218822Sdimstatic int
763218822Sdimwalk_no_bignums (symbolS * sp)
764218822Sdim{
765218822Sdim  if (symbol_get_value_expression (sp)->X_op == O_big)
766218822Sdim    return 1;
76789857Sobrien
768218822Sdim  if (symbol_get_value_expression (sp)->X_add_symbol)
769218822Sdim    {
770218822Sdim      return (walk_no_bignums (symbol_get_value_expression (sp)->X_add_symbol)
771218822Sdim	      || (symbol_get_value_expression (sp)->X_op_symbol
772218822Sdim		  && walk_no_bignums (symbol_get_value_expression (sp)->X_op_symbol)));
773218822Sdim    }
77489857Sobrien
775218822Sdim  return 0;
776218822Sdim}
77789857Sobrien
778218822Sdimstatic int in_my_get_expression = 0;
77989857Sobrien
780218822Sdim/* Third argument to my_get_expression.	 */
781218822Sdim#define GE_NO_PREFIX 0
782218822Sdim#define GE_IMM_PREFIX 1
783218822Sdim#define GE_OPT_PREFIX 2
784218822Sdim/* This is a bit of a hack. Use an optional prefix, and also allow big (64-bit)
785218822Sdim   immediates, as can be used in Neon VMVN and VMOV immediate instructions.  */
786218822Sdim#define GE_OPT_PREFIX_BIG 3
78789857Sobrien
788218822Sdimstatic int
789218822Sdimmy_get_expression (expressionS * ep, char ** str, int prefix_mode)
79077298Sobrien{
791218822Sdim  char * save_in;
792218822Sdim  segT	 seg;
79360484Sobrien
794218822Sdim  /* In unified syntax, all prefixes are optional.  */
795218822Sdim  if (unified_syntax)
796218822Sdim    prefix_mode = (prefix_mode == GE_OPT_PREFIX_BIG) ? prefix_mode
797218822Sdim                  : GE_OPT_PREFIX;
79860484Sobrien
799218822Sdim  switch (prefix_mode)
800218822Sdim    {
801218822Sdim    case GE_NO_PREFIX: break;
802218822Sdim    case GE_IMM_PREFIX:
803218822Sdim      if (!is_immediate_prefix (**str))
804218822Sdim	{
805218822Sdim	  inst.error = _("immediate expression requires a # prefix");
806218822Sdim	  return FAIL;
807218822Sdim	}
808218822Sdim      (*str)++;
809218822Sdim      break;
810218822Sdim    case GE_OPT_PREFIX:
811218822Sdim    case GE_OPT_PREFIX_BIG:
812218822Sdim      if (is_immediate_prefix (**str))
813218822Sdim	(*str)++;
814218822Sdim      break;
815218822Sdim    default: abort ();
816218822Sdim    }
81760484Sobrien
818218822Sdim  memset (ep, 0, sizeof (expressionS));
81960484Sobrien
820218822Sdim  save_in = input_line_pointer;
821218822Sdim  input_line_pointer = *str;
822218822Sdim  in_my_get_expression = 1;
823218822Sdim  seg = expression (ep);
824218822Sdim  in_my_get_expression = 0;
82560484Sobrien
826218822Sdim  if (ep->X_op == O_illegal)
827218822Sdim    {
828218822Sdim      /* We found a bad expression in md_operand().  */
829218822Sdim      *str = input_line_pointer;
830218822Sdim      input_line_pointer = save_in;
831218822Sdim      if (inst.error == NULL)
832218822Sdim	inst.error = _("bad expression");
833218822Sdim      return 1;
834218822Sdim    }
835218822Sdim
836218822Sdim#ifdef OBJ_AOUT
837218822Sdim  if (seg != absolute_section
838218822Sdim      && seg != text_section
839218822Sdim      && seg != data_section
840218822Sdim      && seg != bss_section
841218822Sdim      && seg != undefined_section)
842218822Sdim    {
843218822Sdim      inst.error = _("bad segment");
844218822Sdim      *str = input_line_pointer;
845218822Sdim      input_line_pointer = save_in;
846218822Sdim      return 1;
847218822Sdim    }
848218822Sdim#endif
849218822Sdim
850218822Sdim  /* Get rid of any bignums now, so that we don't generate an error for which
851218822Sdim     we can't establish a line number later on.	 Big numbers are never valid
852218822Sdim     in instructions, which is where this routine is always called.  */
853218822Sdim  if (prefix_mode != GE_OPT_PREFIX_BIG
854218822Sdim      && (ep->X_op == O_big
855218822Sdim          || (ep->X_add_symbol
856218822Sdim	      && (walk_no_bignums (ep->X_add_symbol)
857218822Sdim	          || (ep->X_op_symbol
858218822Sdim		      && walk_no_bignums (ep->X_op_symbol))))))
859218822Sdim    {
860218822Sdim      inst.error = _("invalid constant");
861218822Sdim      *str = input_line_pointer;
862218822Sdim      input_line_pointer = save_in;
863218822Sdim      return 1;
864218822Sdim    }
865218822Sdim
866218822Sdim  *str = input_line_pointer;
867218822Sdim  input_line_pointer = save_in;
868218822Sdim  return 0;
869218822Sdim}
870218822Sdim
871218822Sdim/* Turn a string in input_line_pointer into a floating point constant
872218822Sdim   of type TYPE, and store the appropriate bytes in *LITP.  The number
873218822Sdim   of LITTLENUMS emitted is stored in *SIZEP.  An error message is
874218822Sdim   returned, or NULL on OK.
875218822Sdim
876218822Sdim   Note that fp constants aren't represent in the normal way on the ARM.
877218822Sdim   In big endian mode, things are as expected.	However, in little endian
878218822Sdim   mode fp constants are big-endian word-wise, and little-endian byte-wise
879218822Sdim   within the words.  For example, (double) 1.1 in big endian mode is
880218822Sdim   the byte sequence 3f f1 99 99 99 99 99 9a, and in little endian mode is
881218822Sdim   the byte sequence 99 99 f1 3f 9a 99 99 99.
882218822Sdim
883218822Sdim   ??? The format of 12 byte floats is uncertain according to gcc's arm.h.  */
884218822Sdim
885218822Sdimchar *
886218822Sdimmd_atof (int type, char * litP, int * sizeP)
88760484Sobrien{
888218822Sdim  int prec;
889218822Sdim  LITTLENUM_TYPE words[MAX_LITTLENUMS];
890218822Sdim  char *t;
891218822Sdim  int i;
89277298Sobrien
893218822Sdim  switch (type)
894218822Sdim    {
895218822Sdim    case 'f':
896218822Sdim    case 'F':
897218822Sdim    case 's':
898218822Sdim    case 'S':
899218822Sdim      prec = 2;
900218822Sdim      break;
90189857Sobrien
902218822Sdim    case 'd':
903218822Sdim    case 'D':
904218822Sdim    case 'r':
905218822Sdim    case 'R':
906218822Sdim      prec = 4;
907218822Sdim      break;
90889857Sobrien
909218822Sdim    case 'x':
910218822Sdim    case 'X':
911218822Sdim      prec = 6;
912218822Sdim      break;
91389857Sobrien
914218822Sdim    case 'p':
915218822Sdim    case 'P':
916218822Sdim      prec = 6;
917218822Sdim      break;
91889857Sobrien
919218822Sdim    default:
920218822Sdim      *sizeP = 0;
921218822Sdim      return _("bad call to MD_ATOF()");
922218822Sdim    }
92389857Sobrien
924218822Sdim  t = atof_ieee (input_line_pointer, type, words);
925218822Sdim  if (t)
926218822Sdim    input_line_pointer = t;
927218822Sdim  *sizeP = prec * 2;
92877298Sobrien
929218822Sdim  if (target_big_endian)
930218822Sdim    {
931218822Sdim      for (i = 0; i < prec; i++)
932218822Sdim	{
933218822Sdim	  md_number_to_chars (litP, (valueT) words[i], 2);
934218822Sdim	  litP += 2;
935218822Sdim	}
936218822Sdim    }
937218822Sdim  else
938218822Sdim    {
939218822Sdim      if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_endian_pure))
940218822Sdim	for (i = prec - 1; i >= 0; i--)
941218822Sdim	  {
942218822Sdim	    md_number_to_chars (litP, (valueT) words[i], 2);
943218822Sdim	    litP += 2;
944218822Sdim	  }
945218822Sdim      else
946218822Sdim	/* For a 4 byte float the order of elements in `words' is 1 0.
947218822Sdim	   For an 8 byte float the order is 1 0 3 2.  */
948218822Sdim	for (i = 0; i < prec; i += 2)
949218822Sdim	  {
950218822Sdim	    md_number_to_chars (litP, (valueT) words[i + 1], 2);
951218822Sdim	    md_number_to_chars (litP + 2, (valueT) words[i], 2);
952218822Sdim	    litP += 4;
953218822Sdim	  }
954218822Sdim    }
95560484Sobrien
956218822Sdim  return 0;
957218822Sdim}
95860484Sobrien
959218822Sdim/* We handle all bad expressions here, so that we can report the faulty
960218822Sdim   instruction in the error message.  */
961218822Sdimvoid
962218822Sdimmd_operand (expressionS * expr)
963218822Sdim{
964218822Sdim  if (in_my_get_expression)
965218822Sdim    expr->X_op = O_illegal;
966218822Sdim}
96760484Sobrien
968218822Sdim/* Immediate values.  */
96960484Sobrien
970218822Sdim/* Generic immediate-value read function for use in directives.
971218822Sdim   Accepts anything that 'expression' can fold to a constant.
972218822Sdim   *val receives the number.  */
973218822Sdim#ifdef OBJ_ELF
974218822Sdimstatic int
975218822Sdimimmediate_for_directive (int *val)
976218822Sdim{
977218822Sdim  expressionS exp;
978218822Sdim  exp.X_op = O_illegal;
97960484Sobrien
980218822Sdim  if (is_immediate_prefix (*input_line_pointer))
981218822Sdim    {
982218822Sdim      input_line_pointer++;
983218822Sdim      expression (&exp);
984218822Sdim    }
98560484Sobrien
986218822Sdim  if (exp.X_op != O_constant)
987218822Sdim    {
988218822Sdim      as_bad (_("expected #constant"));
989218822Sdim      ignore_rest_of_line ();
990218822Sdim      return FAIL;
991218822Sdim    }
992218822Sdim  *val = exp.X_add_number;
993218822Sdim  return SUCCESS;
994218822Sdim}
995218822Sdim#endif
99660484Sobrien
997218822Sdim/* Register parsing.  */
99877298Sobrien
999218822Sdim/* Generic register parser.  CCP points to what should be the
1000218822Sdim   beginning of a register name.  If it is indeed a valid register
1001218822Sdim   name, advance CCP over it and return the reg_entry structure;
1002218822Sdim   otherwise return NULL.  Does not issue diagnostics.	*/
100377298Sobrien
1004218822Sdimstatic struct reg_entry *
1005218822Sdimarm_reg_parse_multi (char **ccp)
1006218822Sdim{
1007218822Sdim  char *start = *ccp;
1008218822Sdim  char *p;
1009218822Sdim  struct reg_entry *reg;
101077298Sobrien
1011218822Sdim#ifdef REGISTER_PREFIX
1012218822Sdim  if (*start != REGISTER_PREFIX)
1013218822Sdim    return NULL;
1014218822Sdim  start++;
1015218822Sdim#endif
1016218822Sdim#ifdef OPTIONAL_REGISTER_PREFIX
1017218822Sdim  if (*start == OPTIONAL_REGISTER_PREFIX)
1018218822Sdim    start++;
1019218822Sdim#endif
102077298Sobrien
1021218822Sdim  p = start;
1022218822Sdim  if (!ISALPHA (*p) || !is_name_beginner (*p))
1023218822Sdim    return NULL;
102477298Sobrien
1025218822Sdim  do
1026218822Sdim    p++;
1027218822Sdim  while (ISALPHA (*p) || ISDIGIT (*p) || *p == '_');
102877298Sobrien
1029218822Sdim  reg = (struct reg_entry *) hash_find_n (arm_reg_hsh, start, p - start);
103077298Sobrien
1031218822Sdim  if (!reg)
1032218822Sdim    return NULL;
103377298Sobrien
1034218822Sdim  *ccp = p;
1035218822Sdim  return reg;
1036218822Sdim}
103789857Sobrien
1038218822Sdimstatic int
1039218822Sdimarm_reg_alt_syntax (char **ccp, char *start, struct reg_entry *reg,
1040218822Sdim                    enum arm_reg_type type)
1041218822Sdim{
1042218822Sdim  /* Alternative syntaxes are accepted for a few register classes.  */
1043218822Sdim  switch (type)
1044218822Sdim    {
1045218822Sdim    case REG_TYPE_MVF:
1046218822Sdim    case REG_TYPE_MVD:
1047218822Sdim    case REG_TYPE_MVFX:
1048218822Sdim    case REG_TYPE_MVDX:
1049218822Sdim      /* Generic coprocessor register names are allowed for these.  */
1050218822Sdim      if (reg && reg->type == REG_TYPE_CN)
1051218822Sdim	return reg->number;
1052218822Sdim      break;
105389857Sobrien
1054218822Sdim    case REG_TYPE_CP:
1055218822Sdim      /* For backward compatibility, a bare number is valid here.  */
1056218822Sdim      {
1057218822Sdim	unsigned long processor = strtoul (start, ccp, 10);
1058218822Sdim	if (*ccp != start && processor <= 15)
1059218822Sdim	  return processor;
1060218822Sdim      }
106189857Sobrien
1062218822Sdim    case REG_TYPE_MMXWC:
1063218822Sdim      /* WC includes WCG.  ??? I'm not sure this is true for all
1064218822Sdim	 instructions that take WC registers.  */
1065218822Sdim      if (reg && reg->type == REG_TYPE_MMXWCG)
1066218822Sdim	return reg->number;
1067218822Sdim      break;
1068130561Sobrien
1069218822Sdim    default:
1070218822Sdim      break;
1071218822Sdim    }
107289857Sobrien
1073218822Sdim  return FAIL;
1074218822Sdim}
107589857Sobrien
1076218822Sdim/* As arm_reg_parse_multi, but the register must be of type TYPE, and the
1077218822Sdim   return value is the register number or FAIL.  */
107889857Sobrien
1079218822Sdimstatic int
1080218822Sdimarm_reg_parse (char **ccp, enum arm_reg_type type)
1081218822Sdim{
1082218822Sdim  char *start = *ccp;
1083218822Sdim  struct reg_entry *reg = arm_reg_parse_multi (ccp);
1084218822Sdim  int ret;
108589857Sobrien
1086218822Sdim  /* Do not allow a scalar (reg+index) to parse as a register.  */
1087218822Sdim  if (reg && reg->neon && (reg->neon->defined & NTA_HASINDEX))
1088218822Sdim    return FAIL;
108989857Sobrien
1090218822Sdim  if (reg && reg->type == type)
1091218822Sdim    return reg->number;
109289857Sobrien
1093218822Sdim  if ((ret = arm_reg_alt_syntax (ccp, start, reg, type)) != FAIL)
1094218822Sdim    return ret;
109589857Sobrien
1096218822Sdim  *ccp = start;
1097218822Sdim  return FAIL;
1098218822Sdim}
109989857Sobrien
1100218822Sdim/* Parse a Neon type specifier. *STR should point at the leading '.'
1101218822Sdim   character. Does no verification at this stage that the type fits the opcode
1102218822Sdim   properly. E.g.,
110389857Sobrien
1104218822Sdim     .i32.i32.s16
1105218822Sdim     .s32.f32
1106218822Sdim     .u16
110789857Sobrien
1108218822Sdim   Can all be legally parsed by this function.
110989857Sobrien
1110218822Sdim   Fills in neon_type struct pointer with parsed information, and updates STR
1111218822Sdim   to point after the parsed type specifier. Returns SUCCESS if this was a legal
1112218822Sdim   type, FAIL if not.  */
111389857Sobrien
1114218822Sdimstatic int
1115218822Sdimparse_neon_type (struct neon_type *type, char **str)
1116218822Sdim{
1117218822Sdim  char *ptr = *str;
111889857Sobrien
1119218822Sdim  if (type)
1120218822Sdim    type->elems = 0;
112189857Sobrien
1122218822Sdim  while (type->elems < NEON_MAX_TYPE_ELS)
1123218822Sdim    {
1124218822Sdim      enum neon_el_type thistype = NT_untyped;
1125218822Sdim      unsigned thissize = -1u;
112689857Sobrien
1127218822Sdim      if (*ptr != '.')
1128218822Sdim	break;
112989857Sobrien
1130218822Sdim      ptr++;
113189857Sobrien
1132218822Sdim      /* Just a size without an explicit type.  */
1133218822Sdim      if (ISDIGIT (*ptr))
1134218822Sdim	goto parsesize;
113589857Sobrien
1136218822Sdim      switch (TOLOWER (*ptr))
1137218822Sdim	{
1138218822Sdim	case 'i': thistype = NT_integer; break;
1139218822Sdim	case 'f': thistype = NT_float; break;
1140218822Sdim	case 'p': thistype = NT_poly; break;
1141218822Sdim	case 's': thistype = NT_signed; break;
1142218822Sdim	case 'u': thistype = NT_unsigned; break;
1143218822Sdim        case 'd':
1144218822Sdim          thistype = NT_float;
1145218822Sdim          thissize = 64;
1146218822Sdim          ptr++;
1147218822Sdim          goto done;
1148218822Sdim	default:
1149218822Sdim	  as_bad (_("unexpected character `%c' in type specifier"), *ptr);
1150218822Sdim	  return FAIL;
1151218822Sdim	}
115289857Sobrien
1153218822Sdim      ptr++;
115489857Sobrien
1155218822Sdim      /* .f is an abbreviation for .f32.  */
1156218822Sdim      if (thistype == NT_float && !ISDIGIT (*ptr))
1157218822Sdim	thissize = 32;
1158218822Sdim      else
1159218822Sdim	{
1160218822Sdim	parsesize:
1161218822Sdim	  thissize = strtoul (ptr, &ptr, 10);
116289857Sobrien
1163218822Sdim	  if (thissize != 8 && thissize != 16 && thissize != 32
1164218822Sdim              && thissize != 64)
1165218822Sdim            {
1166218822Sdim              as_bad (_("bad size %d in type specifier"), thissize);
1167218822Sdim	      return FAIL;
1168218822Sdim	    }
1169218822Sdim	}
117089857Sobrien
1171218822Sdim      done:
1172218822Sdim      if (type)
1173218822Sdim        {
1174218822Sdim          type->el[type->elems].type = thistype;
1175218822Sdim	  type->el[type->elems].size = thissize;
1176218822Sdim	  type->elems++;
1177218822Sdim	}
1178218822Sdim    }
117989857Sobrien
1180218822Sdim  /* Empty/missing type is not a successful parse.  */
1181218822Sdim  if (type->elems == 0)
1182218822Sdim    return FAIL;
118389857Sobrien
1184218822Sdim  *str = ptr;
118589857Sobrien
1186218822Sdim  return SUCCESS;
1187218822Sdim}
118889857Sobrien
1189218822Sdim/* Errors may be set multiple times during parsing or bit encoding
1190218822Sdim   (particularly in the Neon bits), but usually the earliest error which is set
1191218822Sdim   will be the most meaningful. Avoid overwriting it with later (cascading)
1192218822Sdim   errors by calling this function.  */
119389857Sobrien
1194218822Sdimstatic void
1195218822Sdimfirst_error (const char *err)
1196218822Sdim{
1197218822Sdim  if (!inst.error)
1198218822Sdim    inst.error = err;
1199218822Sdim}
120089857Sobrien
1201218822Sdim/* Parse a single type, e.g. ".s32", leading period included.  */
1202218822Sdimstatic int
1203218822Sdimparse_neon_operand_type (struct neon_type_el *vectype, char **ccp)
1204218822Sdim{
1205218822Sdim  char *str = *ccp;
1206218822Sdim  struct neon_type optype;
120789857Sobrien
1208218822Sdim  if (*str == '.')
1209218822Sdim    {
1210218822Sdim      if (parse_neon_type (&optype, &str) == SUCCESS)
1211218822Sdim        {
1212218822Sdim          if (optype.elems == 1)
1213218822Sdim            *vectype = optype.el[0];
1214218822Sdim          else
1215218822Sdim            {
1216218822Sdim              first_error (_("only one type should be specified for operand"));
1217218822Sdim              return FAIL;
1218218822Sdim            }
1219218822Sdim        }
1220218822Sdim      else
1221218822Sdim        {
1222218822Sdim          first_error (_("vector type expected"));
1223218822Sdim          return FAIL;
1224218822Sdim        }
1225218822Sdim    }
1226218822Sdim  else
1227218822Sdim    return FAIL;
1228218822Sdim
1229218822Sdim  *ccp = str;
1230218822Sdim
1231218822Sdim  return SUCCESS;
1232218822Sdim}
123389857Sobrien
1234218822Sdim/* Special meanings for indices (which have a range of 0-7), which will fit into
1235218822Sdim   a 4-bit integer.  */
123689857Sobrien
1237218822Sdim#define NEON_ALL_LANES		15
1238218822Sdim#define NEON_INTERLEAVE_LANES	14
123989857Sobrien
1240218822Sdim/* Parse either a register or a scalar, with an optional type. Return the
1241218822Sdim   register number, and optionally fill in the actual type of the register
1242218822Sdim   when multiple alternatives were given (NEON_TYPE_NDQ) in *RTYPE, and
1243218822Sdim   type/index information in *TYPEINFO.  */
124489857Sobrien
1245218822Sdimstatic int
1246218822Sdimparse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type,
1247218822Sdim                           enum arm_reg_type *rtype,
1248218822Sdim                           struct neon_typed_alias *typeinfo)
1249218822Sdim{
1250218822Sdim  char *str = *ccp;
1251218822Sdim  struct reg_entry *reg = arm_reg_parse_multi (&str);
1252218822Sdim  struct neon_typed_alias atype;
1253218822Sdim  struct neon_type_el parsetype;
125489857Sobrien
1255218822Sdim  atype.defined = 0;
1256218822Sdim  atype.index = -1;
1257218822Sdim  atype.eltype.type = NT_invtype;
1258218822Sdim  atype.eltype.size = -1;
125989857Sobrien
1260218822Sdim  /* Try alternate syntax for some types of register. Note these are mutually
1261218822Sdim     exclusive with the Neon syntax extensions.  */
1262218822Sdim  if (reg == NULL)
1263218822Sdim    {
1264218822Sdim      int altreg = arm_reg_alt_syntax (&str, *ccp, reg, type);
1265218822Sdim      if (altreg != FAIL)
1266218822Sdim        *ccp = str;
1267218822Sdim      if (typeinfo)
1268218822Sdim        *typeinfo = atype;
1269218822Sdim      return altreg;
1270218822Sdim    }
127189857Sobrien
1272218822Sdim  /* Undo polymorphism when a set of register types may be accepted.  */
1273218822Sdim  if ((type == REG_TYPE_NDQ
1274218822Sdim       && (reg->type == REG_TYPE_NQ || reg->type == REG_TYPE_VFD))
1275218822Sdim      || (type == REG_TYPE_VFSD
1276218822Sdim          && (reg->type == REG_TYPE_VFS || reg->type == REG_TYPE_VFD))
1277218822Sdim      || (type == REG_TYPE_NSDQ
1278218822Sdim          && (reg->type == REG_TYPE_VFS || reg->type == REG_TYPE_VFD
1279218822Sdim              || reg->type == REG_TYPE_NQ))
1280218822Sdim      || (type == REG_TYPE_MMXWC
1281218822Sdim	  && (reg->type == REG_TYPE_MMXWCG)))
1282218822Sdim    type = reg->type;
128389857Sobrien
1284218822Sdim  if (type != reg->type)
1285218822Sdim    return FAIL;
128689857Sobrien
1287218822Sdim  if (reg->neon)
1288218822Sdim    atype = *reg->neon;
1289218822Sdim
1290218822Sdim  if (parse_neon_operand_type (&parsetype, &str) == SUCCESS)
1291218822Sdim    {
1292218822Sdim      if ((atype.defined & NTA_HASTYPE) != 0)
1293218822Sdim        {
1294218822Sdim          first_error (_("can't redefine type for operand"));
1295218822Sdim          return FAIL;
1296218822Sdim        }
1297218822Sdim      atype.defined |= NTA_HASTYPE;
1298218822Sdim      atype.eltype = parsetype;
1299218822Sdim    }
1300218822Sdim
1301218822Sdim  if (skip_past_char (&str, '[') == SUCCESS)
1302218822Sdim    {
1303218822Sdim      if (type != REG_TYPE_VFD)
1304218822Sdim        {
1305218822Sdim          first_error (_("only D registers may be indexed"));
1306218822Sdim          return FAIL;
1307218822Sdim        }
1308218822Sdim
1309218822Sdim      if ((atype.defined & NTA_HASINDEX) != 0)
1310218822Sdim        {
1311218822Sdim          first_error (_("can't change index for operand"));
1312218822Sdim          return FAIL;
1313218822Sdim        }
131489857Sobrien
1315218822Sdim      atype.defined |= NTA_HASINDEX;
131689857Sobrien
1317218822Sdim      if (skip_past_char (&str, ']') == SUCCESS)
1318218822Sdim        atype.index = NEON_ALL_LANES;
1319218822Sdim      else
1320218822Sdim        {
1321218822Sdim          expressionS exp;
132289857Sobrien
1323218822Sdim          my_get_expression (&exp, &str, GE_NO_PREFIX);
132489857Sobrien
1325218822Sdim          if (exp.X_op != O_constant)
1326218822Sdim            {
1327218822Sdim              first_error (_("constant expression required"));
1328218822Sdim              return FAIL;
1329218822Sdim            }
133089857Sobrien
1331218822Sdim          if (skip_past_char (&str, ']') == FAIL)
1332218822Sdim            return FAIL;
133389857Sobrien
1334218822Sdim          atype.index = exp.X_add_number;
1335218822Sdim        }
1336218822Sdim    }
1337218822Sdim
1338218822Sdim  if (typeinfo)
1339218822Sdim    *typeinfo = atype;
1340218822Sdim
1341218822Sdim  if (rtype)
1342218822Sdim    *rtype = type;
1343218822Sdim
1344218822Sdim  *ccp = str;
1345218822Sdim
1346218822Sdim  return reg->number;
1347218822Sdim}
134889857Sobrien
1349218822Sdim/* Like arm_reg_parse, but allow allow the following extra features:
1350218822Sdim    - If RTYPE is non-zero, return the (possibly restricted) type of the
1351218822Sdim      register (e.g. Neon double or quad reg when either has been requested).
1352218822Sdim    - If this is a Neon vector type with additional type information, fill
1353218822Sdim      in the struct pointed to by VECTYPE (if non-NULL).
1354218822Sdim   This function will fault on encountering a scalar.
1355218822Sdim*/
135689857Sobrien
1357218822Sdimstatic int
1358218822Sdimarm_typed_reg_parse (char **ccp, enum arm_reg_type type,
1359218822Sdim                     enum arm_reg_type *rtype, struct neon_type_el *vectype)
1360218822Sdim{
1361218822Sdim  struct neon_typed_alias atype;
1362218822Sdim  char *str = *ccp;
1363218822Sdim  int reg = parse_typed_reg_or_scalar (&str, type, rtype, &atype);
136489857Sobrien
1365218822Sdim  if (reg == FAIL)
1366218822Sdim    return FAIL;
136789857Sobrien
1368218822Sdim  /* Do not allow a scalar (reg+index) to parse as a register.  */
1369218822Sdim  if ((atype.defined & NTA_HASINDEX) != 0)
1370218822Sdim    {
1371218822Sdim      first_error (_("register operand expected, but got scalar"));
1372218822Sdim      return FAIL;
1373218822Sdim    }
1374130561Sobrien
1375218822Sdim  if (vectype)
1376218822Sdim    *vectype = atype.eltype;
137760484Sobrien
1378218822Sdim  *ccp = str;
137960484Sobrien
1380218822Sdim  return reg;
1381218822Sdim}
138289857Sobrien
1383218822Sdim#define NEON_SCALAR_REG(X)	((X) >> 4)
1384218822Sdim#define NEON_SCALAR_INDEX(X)	((X) & 15)
138560484Sobrien
1386218822Sdim/* Parse a Neon scalar. Most of the time when we're parsing a scalar, we don't
1387218822Sdim   have enough information to be able to do a good job bounds-checking. So, we
1388218822Sdim   just do easy checks here, and do further checks later.  */
138960484Sobrien
1390218822Sdimstatic int
1391218822Sdimparse_scalar (char **ccp, int elsize, struct neon_type_el *type)
1392218822Sdim{
1393218822Sdim  int reg;
1394218822Sdim  char *str = *ccp;
1395218822Sdim  struct neon_typed_alias atype;
1396218822Sdim
1397218822Sdim  reg = parse_typed_reg_or_scalar (&str, REG_TYPE_VFD, NULL, &atype);
1398218822Sdim
1399218822Sdim  if (reg == FAIL || (atype.defined & NTA_HASINDEX) == 0)
1400218822Sdim    return FAIL;
1401218822Sdim
1402218822Sdim  if (atype.index == NEON_ALL_LANES)
1403218822Sdim    {
1404218822Sdim      first_error (_("scalar must have an index"));
1405218822Sdim      return FAIL;
1406218822Sdim    }
1407218822Sdim  else if (atype.index >= 64 / elsize)
1408218822Sdim    {
1409218822Sdim      first_error (_("scalar index out of range"));
1410218822Sdim      return FAIL;
1411218822Sdim    }
1412218822Sdim
1413218822Sdim  if (type)
1414218822Sdim    *type = atype.eltype;
1415218822Sdim
1416218822Sdim  *ccp = str;
1417218822Sdim
1418218822Sdim  return reg * 16 + atype.index;
1419218822Sdim}
142060484Sobrien
1421218822Sdim/* Parse an ARM register list.  Returns the bitmask, or FAIL.  */
1422218822Sdimstatic long
1423218822Sdimparse_reg_list (char ** strp)
1424218822Sdim{
1425218822Sdim  char * str = * strp;
1426218822Sdim  long	 range = 0;
1427218822Sdim  int	 another_range;
142889857Sobrien
1429218822Sdim  /* We come back here if we get ranges concatenated by '+' or '|'.  */
1430218822Sdim  do
1431218822Sdim    {
1432218822Sdim      another_range = 0;
1433130561Sobrien
1434218822Sdim      if (*str == '{')
1435218822Sdim	{
1436218822Sdim	  int in_range = 0;
1437218822Sdim	  int cur_reg = -1;
143860484Sobrien
1439218822Sdim	  str++;
1440218822Sdim	  do
1441218822Sdim	    {
1442218822Sdim	      int reg;
144360484Sobrien
1444218822Sdim	      if ((reg = arm_reg_parse (&str, REG_TYPE_RN)) == FAIL)
1445218822Sdim		{
1446218822Sdim		  first_error (_(reg_expected_msgs[REG_TYPE_RN]));
1447218822Sdim		  return FAIL;
1448218822Sdim		}
144960484Sobrien
1450218822Sdim	      if (in_range)
1451218822Sdim		{
1452218822Sdim		  int i;
145360484Sobrien
1454218822Sdim		  if (reg <= cur_reg)
1455218822Sdim		    {
1456218822Sdim		      first_error (_("bad range in register list"));
1457218822Sdim		      return FAIL;
1458218822Sdim		    }
145960484Sobrien
1460218822Sdim		  for (i = cur_reg + 1; i < reg; i++)
1461218822Sdim		    {
1462218822Sdim		      if (range & (1 << i))
1463218822Sdim			as_tsktsk
1464218822Sdim			  (_("Warning: duplicated register (r%d) in register list"),
1465218822Sdim			   i);
1466218822Sdim		      else
1467218822Sdim			range |= 1 << i;
1468218822Sdim		    }
1469218822Sdim		  in_range = 0;
1470218822Sdim		}
147160484Sobrien
1472218822Sdim	      if (range & (1 << reg))
1473218822Sdim		as_tsktsk (_("Warning: duplicated register (r%d) in register list"),
1474218822Sdim			   reg);
1475218822Sdim	      else if (reg <= cur_reg)
1476218822Sdim		as_tsktsk (_("Warning: register range not in ascending order"));
147760484Sobrien
1478218822Sdim	      range |= 1 << reg;
1479218822Sdim	      cur_reg = reg;
1480218822Sdim	    }
1481218822Sdim	  while (skip_past_comma (&str) != FAIL
1482218822Sdim		 || (in_range = 1, *str++ == '-'));
1483218822Sdim	  str--;
148460484Sobrien
1485218822Sdim	  if (*str++ != '}')
1486218822Sdim	    {
1487218822Sdim	      first_error (_("missing `}'"));
1488218822Sdim	      return FAIL;
1489218822Sdim	    }
1490218822Sdim	}
1491218822Sdim      else
1492218822Sdim	{
1493218822Sdim	  expressionS expr;
149460484Sobrien
1495218822Sdim	  if (my_get_expression (&expr, &str, GE_NO_PREFIX))
1496218822Sdim	    return FAIL;
149760484Sobrien
1498218822Sdim	  if (expr.X_op == O_constant)
1499218822Sdim	    {
1500218822Sdim	      if (expr.X_add_number
1501218822Sdim		  != (expr.X_add_number & 0x0000ffff))
1502218822Sdim		{
1503218822Sdim		  inst.error = _("invalid register mask");
1504218822Sdim		  return FAIL;
1505218822Sdim		}
150660484Sobrien
1507218822Sdim	      if ((range & expr.X_add_number) != 0)
1508218822Sdim		{
1509218822Sdim		  int regno = range & expr.X_add_number;
151060484Sobrien
1511218822Sdim		  regno &= -regno;
1512218822Sdim		  regno = (1 << regno) - 1;
1513218822Sdim		  as_tsktsk
1514218822Sdim		    (_("Warning: duplicated register (r%d) in register list"),
1515218822Sdim		     regno);
1516218822Sdim		}
151760484Sobrien
1518218822Sdim	      range |= expr.X_add_number;
1519218822Sdim	    }
1520218822Sdim	  else
1521218822Sdim	    {
1522218822Sdim	      if (inst.reloc.type != 0)
1523218822Sdim		{
1524218822Sdim		  inst.error = _("expression too complex");
1525218822Sdim		  return FAIL;
1526218822Sdim		}
152760484Sobrien
1528218822Sdim	      memcpy (&inst.reloc.exp, &expr, sizeof (expressionS));
1529218822Sdim	      inst.reloc.type = BFD_RELOC_ARM_MULTI;
1530218822Sdim	      inst.reloc.pc_rel = 0;
1531218822Sdim	    }
1532218822Sdim	}
153360484Sobrien
1534218822Sdim      if (*str == '|' || *str == '+')
1535218822Sdim	{
1536218822Sdim	  str++;
1537218822Sdim	  another_range = 1;
1538218822Sdim	}
1539218822Sdim    }
1540218822Sdim  while (another_range);
154177298Sobrien
1542218822Sdim  *strp = str;
1543218822Sdim  return range;
1544218822Sdim}
154577298Sobrien
1546218822Sdim/* Types of registers in a list.  */
154777298Sobrien
1548218822Sdimenum reg_list_els
1549218822Sdim{
1550218822Sdim  REGLIST_VFP_S,
1551218822Sdim  REGLIST_VFP_D,
1552218822Sdim  REGLIST_NEON_D
155360484Sobrien};
155460484Sobrien
1555218822Sdim/* Parse a VFP register list.  If the string is invalid return FAIL.
1556218822Sdim   Otherwise return the number of registers, and set PBASE to the first
1557218822Sdim   register.  Parses registers of type ETYPE.
1558218822Sdim   If REGLIST_NEON_D is used, several syntax enhancements are enabled:
1559218822Sdim     - Q registers can be used to specify pairs of D registers
1560218822Sdim     - { } can be omitted from around a singleton register list
1561218822Sdim         FIXME: This is not implemented, as it would require backtracking in
1562218822Sdim         some cases, e.g.:
1563218822Sdim           vtbl.8 d3,d4,d5
1564218822Sdim         This could be done (the meaning isn't really ambiguous), but doesn't
1565218822Sdim         fit in well with the current parsing framework.
1566218822Sdim     - 32 D registers may be used (also true for VFPv3).
1567218822Sdim   FIXME: Types are ignored in these register lists, which is probably a
1568218822Sdim   bug.  */
1569218822Sdim
1570218822Sdimstatic int
1571218822Sdimparse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
157260484Sobrien{
1573218822Sdim  char *str = *ccp;
1574218822Sdim  int base_reg;
1575218822Sdim  int new_base;
1576218822Sdim  enum arm_reg_type regtype = 0;
1577218822Sdim  int max_regs = 0;
1578218822Sdim  int count = 0;
1579218822Sdim  int warned = 0;
1580218822Sdim  unsigned long mask = 0;
1581218822Sdim  int i;
1582130561Sobrien
1583218822Sdim  if (*str != '{')
1584218822Sdim    {
1585218822Sdim      inst.error = _("expecting {");
1586218822Sdim      return FAIL;
1587218822Sdim    }
158860484Sobrien
1589218822Sdim  str++;
159060484Sobrien
1591218822Sdim  switch (etype)
1592218822Sdim    {
1593218822Sdim    case REGLIST_VFP_S:
1594218822Sdim      regtype = REG_TYPE_VFS;
1595218822Sdim      max_regs = 32;
1596218822Sdim      break;
1597218822Sdim
1598218822Sdim    case REGLIST_VFP_D:
1599218822Sdim      regtype = REG_TYPE_VFD;
1600218822Sdim      break;
1601218822Sdim
1602218822Sdim    case REGLIST_NEON_D:
1603218822Sdim      regtype = REG_TYPE_NDQ;
1604218822Sdim      break;
1605218822Sdim    }
160660484Sobrien
1607218822Sdim  if (etype != REGLIST_VFP_S)
1608218822Sdim    {
1609218822Sdim      /* VFPv3 allows 32 D registers.  */
1610218822Sdim      if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v3))
1611218822Sdim        {
1612218822Sdim          max_regs = 32;
1613218822Sdim          if (thumb_mode)
1614218822Sdim            ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
1615218822Sdim                                    fpu_vfp_ext_v3);
1616218822Sdim          else
1617218822Sdim            ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used,
1618218822Sdim                                    fpu_vfp_ext_v3);
1619218822Sdim        }
1620218822Sdim      else
1621218822Sdim        max_regs = 16;
1622218822Sdim    }
162360484Sobrien
1624218822Sdim  base_reg = max_regs;
162560484Sobrien
1626218822Sdim  do
1627218822Sdim    {
1628218822Sdim      int setmask = 1, addregs = 1;
162960484Sobrien
1630218822Sdim      new_base = arm_typed_reg_parse (&str, regtype, &regtype, NULL);
163160484Sobrien
1632218822Sdim      if (new_base == FAIL)
1633218822Sdim	{
1634218822Sdim	  first_error (_(reg_expected_msgs[regtype]));
1635218822Sdim	  return FAIL;
1636218822Sdim	}
1637218822Sdim
1638218822Sdim      if (new_base >= max_regs)
1639218822Sdim        {
1640218822Sdim          first_error (_("register out of range in list"));
1641218822Sdim          return FAIL;
1642218822Sdim        }
1643218822Sdim
1644218822Sdim      /* Note: a value of 2 * n is returned for the register Q<n>.  */
1645218822Sdim      if (regtype == REG_TYPE_NQ)
1646218822Sdim        {
1647218822Sdim          setmask = 3;
1648218822Sdim          addregs = 2;
1649218822Sdim        }
165089857Sobrien
1651218822Sdim      if (new_base < base_reg)
1652218822Sdim	base_reg = new_base;
165360484Sobrien
1654218822Sdim      if (mask & (setmask << new_base))
1655218822Sdim	{
1656218822Sdim	  first_error (_("invalid register list"));
1657218822Sdim	  return FAIL;
1658218822Sdim	}
165960484Sobrien
1660218822Sdim      if ((mask >> new_base) != 0 && ! warned)
1661218822Sdim	{
1662218822Sdim	  as_tsktsk (_("register list not in ascending order"));
1663218822Sdim	  warned = 1;
1664218822Sdim	}
166560484Sobrien
1666218822Sdim      mask |= setmask << new_base;
1667218822Sdim      count += addregs;
166860484Sobrien
1669218822Sdim      if (*str == '-') /* We have the start of a range expression */
1670218822Sdim	{
1671218822Sdim	  int high_range;
167260484Sobrien
1673218822Sdim	  str++;
167477298Sobrien
1675218822Sdim	  if ((high_range = arm_typed_reg_parse (&str, regtype, NULL, NULL))
1676218822Sdim              == FAIL)
1677218822Sdim	    {
1678218822Sdim	      inst.error = gettext (reg_expected_msgs[regtype]);
1679218822Sdim	      return FAIL;
1680218822Sdim	    }
168177298Sobrien
1682218822Sdim          if (high_range >= max_regs)
1683218822Sdim            {
1684218822Sdim              first_error (_("register out of range in list"));
1685218822Sdim              return FAIL;
1686218822Sdim            }
168777298Sobrien
1688218822Sdim          if (regtype == REG_TYPE_NQ)
1689218822Sdim            high_range = high_range + 1;
1690218822Sdim
1691218822Sdim	  if (high_range <= new_base)
1692218822Sdim	    {
1693218822Sdim	      inst.error = _("register range not in ascending order");
1694218822Sdim	      return FAIL;
1695218822Sdim	    }
1696218822Sdim
1697218822Sdim	  for (new_base += addregs; new_base <= high_range; new_base += addregs)
1698218822Sdim	    {
1699218822Sdim	      if (mask & (setmask << new_base))
1700218822Sdim		{
1701218822Sdim		  inst.error = _("invalid register list");
1702218822Sdim		  return FAIL;
1703218822Sdim		}
1704218822Sdim
1705218822Sdim	      mask |= setmask << new_base;
1706218822Sdim	      count += addregs;
1707218822Sdim	    }
1708218822Sdim	}
1709218822Sdim    }
1710218822Sdim  while (skip_past_comma (&str) != FAIL);
1711218822Sdim
1712218822Sdim  str++;
1713218822Sdim
1714218822Sdim  /* Sanity check -- should have raised a parse error above.  */
1715218822Sdim  if (count == 0 || count > max_regs)
1716218822Sdim    abort ();
1717218822Sdim
1718218822Sdim  *pbase = base_reg;
1719218822Sdim
1720218822Sdim  /* Final test -- the registers must be consecutive.  */
1721218822Sdim  mask >>= base_reg;
1722218822Sdim  for (i = 0; i < count; i++)
1723130561Sobrien    {
1724218822Sdim      if ((mask & (1u << i)) == 0)
1725218822Sdim	{
1726218822Sdim	  inst.error = _("non-contiguous register range");
1727218822Sdim	  return FAIL;
1728218822Sdim	}
1729130561Sobrien    }
173060484Sobrien
1731218822Sdim  *ccp = str;
1732218822Sdim
1733218822Sdim  return count;
1734130561Sobrien}
1735130561Sobrien
1736218822Sdim/* True if two alias types are the same.  */
1737218822Sdim
1738218822Sdimstatic int
1739218822Sdimneon_alias_types_same (struct neon_typed_alias *a, struct neon_typed_alias *b)
1740130561Sobrien{
1741218822Sdim  if (!a && !b)
1742218822Sdim    return 1;
1743218822Sdim
1744218822Sdim  if (!a || !b)
1745218822Sdim    return 0;
1746130561Sobrien
1747218822Sdim  if (a->defined != b->defined)
1748218822Sdim    return 0;
1749218822Sdim
1750218822Sdim  if ((a->defined & NTA_HASTYPE) != 0
1751218822Sdim      && (a->eltype.type != b->eltype.type
1752218822Sdim          || a->eltype.size != b->eltype.size))
1753218822Sdim    return 0;
1754130561Sobrien
1755218822Sdim  if ((a->defined & NTA_HASINDEX) != 0
1756218822Sdim      && (a->index != b->index))
1757218822Sdim    return 0;
1758218822Sdim
1759218822Sdim  return 1;
1760218822Sdim}
1761218822Sdim
1762218822Sdim/* Parse element/structure lists for Neon VLD<n> and VST<n> instructions.
1763218822Sdim   The base register is put in *PBASE.
1764218822Sdim   The lane (or one of the NEON_*_LANES constants) is placed in bits [3:0] of
1765218822Sdim   the return value.
1766218822Sdim   The register stride (minus one) is put in bit 4 of the return value.
1767218822Sdim   Bits [6:5] encode the list length (minus one).
1768218822Sdim   The type of the list elements is put in *ELTYPE, if non-NULL.  */
1769218822Sdim
1770218822Sdim#define NEON_LANE(X)		((X) & 0xf)
1771218822Sdim#define NEON_REG_STRIDE(X)	((((X) >> 4) & 1) + 1)
1772218822Sdim#define NEON_REGLIST_LENGTH(X)	((((X) >> 5) & 3) + 1)
1773218822Sdim
1774218822Sdimstatic int
1775218822Sdimparse_neon_el_struct_list (char **str, unsigned *pbase,
1776218822Sdim                           struct neon_type_el *eltype)
1777218822Sdim{
1778218822Sdim  char *ptr = *str;
1779218822Sdim  int base_reg = -1;
1780218822Sdim  int reg_incr = -1;
1781218822Sdim  int count = 0;
1782218822Sdim  int lane = -1;
1783218822Sdim  int leading_brace = 0;
1784218822Sdim  enum arm_reg_type rtype = REG_TYPE_NDQ;
1785218822Sdim  int addregs = 1;
1786218822Sdim  const char *const incr_error = "register stride must be 1 or 2";
1787218822Sdim  const char *const type_error = "mismatched element/structure types in list";
1788218822Sdim  struct neon_typed_alias firsttype;
1789218822Sdim
1790218822Sdim  if (skip_past_char (&ptr, '{') == SUCCESS)
1791218822Sdim    leading_brace = 1;
1792218822Sdim
1793218822Sdim  do
1794130561Sobrien    {
1795218822Sdim      struct neon_typed_alias atype;
1796218822Sdim      int getreg = parse_typed_reg_or_scalar (&ptr, rtype, &rtype, &atype);
1797130561Sobrien
1798218822Sdim      if (getreg == FAIL)
1799218822Sdim        {
1800218822Sdim          first_error (_(reg_expected_msgs[rtype]));
1801218822Sdim          return FAIL;
1802218822Sdim        }
1803218822Sdim
1804218822Sdim      if (base_reg == -1)
1805218822Sdim        {
1806218822Sdim          base_reg = getreg;
1807218822Sdim          if (rtype == REG_TYPE_NQ)
1808218822Sdim            {
1809218822Sdim              reg_incr = 1;
1810218822Sdim              addregs = 2;
1811218822Sdim            }
1812218822Sdim          firsttype = atype;
1813218822Sdim        }
1814218822Sdim      else if (reg_incr == -1)
1815218822Sdim        {
1816218822Sdim          reg_incr = getreg - base_reg;
1817218822Sdim          if (reg_incr < 1 || reg_incr > 2)
1818218822Sdim            {
1819218822Sdim              first_error (_(incr_error));
1820218822Sdim              return FAIL;
1821218822Sdim            }
1822218822Sdim        }
1823218822Sdim      else if (getreg != base_reg + reg_incr * count)
1824218822Sdim        {
1825218822Sdim          first_error (_(incr_error));
1826218822Sdim          return FAIL;
1827218822Sdim        }
1828130561Sobrien
1829218822Sdim      if (!neon_alias_types_same (&atype, &firsttype))
1830218822Sdim        {
1831218822Sdim          first_error (_(type_error));
1832218822Sdim          return FAIL;
1833218822Sdim        }
1834218822Sdim
1835218822Sdim      /* Handle Dn-Dm or Qn-Qm syntax. Can only be used with non-indexed list
1836218822Sdim         modes.  */
1837218822Sdim      if (ptr[0] == '-')
1838218822Sdim        {
1839218822Sdim          struct neon_typed_alias htype;
1840218822Sdim          int hireg, dregs = (rtype == REG_TYPE_NQ) ? 2 : 1;
1841218822Sdim          if (lane == -1)
1842218822Sdim            lane = NEON_INTERLEAVE_LANES;
1843218822Sdim          else if (lane != NEON_INTERLEAVE_LANES)
1844218822Sdim            {
1845218822Sdim              first_error (_(type_error));
1846218822Sdim              return FAIL;
1847218822Sdim            }
1848218822Sdim          if (reg_incr == -1)
1849218822Sdim            reg_incr = 1;
1850218822Sdim          else if (reg_incr != 1)
1851218822Sdim            {
1852218822Sdim              first_error (_("don't use Rn-Rm syntax with non-unit stride"));
1853218822Sdim              return FAIL;
1854218822Sdim            }
1855218822Sdim          ptr++;
1856218822Sdim          hireg = parse_typed_reg_or_scalar (&ptr, rtype, NULL, &htype);
1857218822Sdim          if (hireg == FAIL)
1858218822Sdim            {
1859218822Sdim              first_error (_(reg_expected_msgs[rtype]));
1860218822Sdim              return FAIL;
1861218822Sdim            }
1862218822Sdim          if (!neon_alias_types_same (&htype, &firsttype))
1863218822Sdim            {
1864218822Sdim              first_error (_(type_error));
1865218822Sdim              return FAIL;
1866218822Sdim            }
1867218822Sdim          count += hireg + dregs - getreg;
1868218822Sdim          continue;
1869218822Sdim        }
1870218822Sdim
1871218822Sdim      /* If we're using Q registers, we can't use [] or [n] syntax.  */
1872218822Sdim      if (rtype == REG_TYPE_NQ)
1873218822Sdim        {
1874218822Sdim          count += 2;
1875218822Sdim          continue;
1876218822Sdim        }
1877218822Sdim
1878218822Sdim      if ((atype.defined & NTA_HASINDEX) != 0)
1879218822Sdim        {
1880218822Sdim          if (lane == -1)
1881218822Sdim            lane = atype.index;
1882218822Sdim          else if (lane != atype.index)
1883218822Sdim            {
1884218822Sdim              first_error (_(type_error));
1885218822Sdim              return FAIL;
1886218822Sdim            }
1887218822Sdim        }
1888218822Sdim      else if (lane == -1)
1889218822Sdim        lane = NEON_INTERLEAVE_LANES;
1890218822Sdim      else if (lane != NEON_INTERLEAVE_LANES)
1891218822Sdim        {
1892218822Sdim          first_error (_(type_error));
1893218822Sdim          return FAIL;
1894218822Sdim        }
1895218822Sdim      count++;
1896130561Sobrien    }
1897218822Sdim  while ((count != 1 || leading_brace) && skip_past_comma (&ptr) != FAIL);
1898218822Sdim
1899218822Sdim  /* No lane set by [x]. We must be interleaving structures.  */
1900218822Sdim  if (lane == -1)
1901218822Sdim    lane = NEON_INTERLEAVE_LANES;
1902218822Sdim
1903218822Sdim  /* Sanity check.  */
1904218822Sdim  if (lane == -1 || base_reg == -1 || count < 1 || count > 4
1905218822Sdim      || (count > 1 && reg_incr == -1))
1906218822Sdim    {
1907218822Sdim      first_error (_("error parsing element/structure list"));
1908218822Sdim      return FAIL;
1909218822Sdim    }
1910130561Sobrien
1911218822Sdim  if ((count > 1 || leading_brace) && skip_past_char (&ptr, '}') == FAIL)
1912130561Sobrien    {
1913218822Sdim      first_error (_("expected }"));
1914218822Sdim      return FAIL;
1915130561Sobrien    }
1916218822Sdim
1917218822Sdim  if (reg_incr == -1)
1918218822Sdim    reg_incr = 1;
1919130561Sobrien
1920218822Sdim  if (eltype)
1921218822Sdim    *eltype = firsttype.eltype;
1922218822Sdim
1923218822Sdim  *pbase = base_reg;
1924218822Sdim  *str = ptr;
1925218822Sdim
1926218822Sdim  return lane | ((reg_incr - 1) << 4) | ((count - 1) << 5);
1927130561Sobrien}
1928130561Sobrien
1929218822Sdim/* Parse an explicit relocation suffix on an expression.  This is
1930218822Sdim   either nothing, or a word in parentheses.  Note that if !OBJ_ELF,
1931218822Sdim   arm_reloc_hsh contains no entries, so this function can only
1932218822Sdim   succeed if there is no () after the word.  Returns -1 on error,
1933218822Sdim   BFD_RELOC_UNUSED if there wasn't any suffix.	 */
193460484Sobrienstatic int
1935218822Sdimparse_reloc (char **str)
193660484Sobrien{
1937218822Sdim  struct reloc_entry *r;
1938218822Sdim  char *p, *q;
193960484Sobrien
1940218822Sdim  if (**str != '(')
1941218822Sdim    return BFD_RELOC_UNUSED;
194260484Sobrien
1943218822Sdim  p = *str + 1;
1944218822Sdim  q = p;
194578828Sobrien
1946218822Sdim  while (*q && *q != ')' && *q != ',')
1947218822Sdim    q++;
1948218822Sdim  if (*q != ')')
1949218822Sdim    return -1;
195060484Sobrien
1951218822Sdim  if ((r = hash_find_n (arm_reloc_hsh, p, q - p)) == NULL)
1952218822Sdim    return -1;
1953218822Sdim
1954218822Sdim  *str = q + 1;
1955218822Sdim  return r->reloc;
1956218822Sdim}
1957218822Sdim
1958218822Sdim/* Directives: register aliases.  */
1959218822Sdim
1960218822Sdimstatic struct reg_entry *
1961218822Sdiminsert_reg_alias (char *str, int number, int type)
1962218822Sdim{
1963218822Sdim  struct reg_entry *new;
1964218822Sdim  const char *name;
1965218822Sdim
1966218822Sdim  if ((new = hash_find (arm_reg_hsh, str)) != 0)
196760484Sobrien    {
1968218822Sdim      if (new->builtin)
1969218822Sdim	as_warn (_("ignoring attempt to redefine built-in register '%s'"), str);
197060484Sobrien
1971218822Sdim      /* Only warn about a redefinition if it's not defined as the
1972218822Sdim	 same register.	 */
1973218822Sdim      else if (new->number != number || new->type != type)
1974218822Sdim	as_warn (_("ignoring redefinition of register alias '%s'"), str);
1975218822Sdim
1976218822Sdim      return 0;
197760484Sobrien    }
197860484Sobrien
1979218822Sdim  name = xstrdup (str);
1980218822Sdim  new = xmalloc (sizeof (struct reg_entry));
198160484Sobrien
1982218822Sdim  new->name = name;
1983218822Sdim  new->number = number;
1984218822Sdim  new->type = type;
1985218822Sdim  new->builtin = FALSE;
1986218822Sdim  new->neon = NULL;
1987218822Sdim
1988218822Sdim  if (hash_insert (arm_reg_hsh, name, (PTR) new))
1989218822Sdim    abort ();
1990218822Sdim
1991218822Sdim  return new;
199260484Sobrien}
199377298Sobrien
199460484Sobrienstatic void
1995218822Sdiminsert_neon_reg_alias (char *str, int number, int type,
1996218822Sdim                       struct neon_typed_alias *atype)
199760484Sobrien{
1998218822Sdim  struct reg_entry *reg = insert_reg_alias (str, number, type);
1999218822Sdim
2000218822Sdim  if (!reg)
2001218822Sdim    {
2002218822Sdim      first_error (_("attempt to redefine typed alias"));
2003218822Sdim      return;
2004218822Sdim    }
2005218822Sdim
2006218822Sdim  if (atype)
2007218822Sdim    {
2008218822Sdim      reg->neon = xmalloc (sizeof (struct neon_typed_alias));
2009218822Sdim      *reg->neon = *atype;
2010218822Sdim    }
2011218822Sdim}
201260484Sobrien
2013218822Sdim/* Look for the .req directive.	 This is of the form:
201460484Sobrien
2015218822Sdim	new_register_name .req existing_register_name
201660484Sobrien
2017218822Sdim   If we find one, or if it looks sufficiently like one that we want to
2018218822Sdim   handle any error here, return non-zero.  Otherwise return zero.  */
201960484Sobrien
2020218822Sdimstatic int
2021218822Sdimcreate_register_alias (char * newname, char *p)
2022218822Sdim{
2023218822Sdim  struct reg_entry *old;
2024218822Sdim  char *oldname, *nbuf;
2025218822Sdim  size_t nlen;
202660484Sobrien
2027218822Sdim  /* The input scrubber ensures that whitespace after the mnemonic is
2028218822Sdim     collapsed to single spaces.  */
2029218822Sdim  oldname = p;
2030218822Sdim  if (strncmp (oldname, " .req ", 6) != 0)
2031218822Sdim    return 0;
203260484Sobrien
2033218822Sdim  oldname += 6;
2034218822Sdim  if (*oldname == '\0')
2035218822Sdim    return 0;
203660484Sobrien
2037218822Sdim  old = hash_find (arm_reg_hsh, oldname);
2038218822Sdim  if (!old)
2039218822Sdim    {
2040218822Sdim      as_warn (_("unknown register '%s' -- .req ignored"), oldname);
2041218822Sdim      return 1;
2042218822Sdim    }
204360484Sobrien
2044218822Sdim  /* If TC_CASE_SENSITIVE is defined, then newname already points to
2045218822Sdim     the desired alias name, and p points to its end.  If not, then
2046218822Sdim     the desired alias name is in the global original_case_string.  */
2047218822Sdim#ifdef TC_CASE_SENSITIVE
2048218822Sdim  nlen = p - newname;
2049218822Sdim#else
2050218822Sdim  newname = original_case_string;
2051218822Sdim  nlen = strlen (newname);
205260484Sobrien#endif
205377298Sobrien
2054218822Sdim  nbuf = alloca (nlen + 1);
2055218822Sdim  memcpy (nbuf, newname, nlen);
2056218822Sdim  nbuf[nlen] = '\0';
205760484Sobrien
2058218822Sdim  /* Create aliases under the new name as stated; an all-lowercase
2059218822Sdim     version of the new name; and an all-uppercase version of the new
2060218822Sdim     name.  */
2061218822Sdim  insert_reg_alias (nbuf, old->number, old->type);
206277298Sobrien
2063218822Sdim  for (p = nbuf; *p; p++)
2064218822Sdim    *p = TOUPPER (*p);
206577298Sobrien
2066218822Sdim  if (strncmp (nbuf, newname, nlen))
2067218822Sdim    insert_reg_alias (nbuf, old->number, old->type);
206877298Sobrien
2069218822Sdim  for (p = nbuf; *p; p++)
2070218822Sdim    *p = TOLOWER (*p);
207177298Sobrien
2072218822Sdim  if (strncmp (nbuf, newname, nlen))
2073218822Sdim    insert_reg_alias (nbuf, old->number, old->type);
2074218822Sdim
2075218822Sdim  return 1;
207660484Sobrien}
207760484Sobrien
2078218822Sdim/* Create a Neon typed/indexed register alias using directives, e.g.:
2079218822Sdim     X .dn d5.s32[1]
2080218822Sdim     Y .qn 6.s16
2081218822Sdim     Z .dn d7
2082218822Sdim     T .dn Z[0]
2083218822Sdim   These typed registers can be used instead of the types specified after the
2084218822Sdim   Neon mnemonic, so long as all operands given have types. Types can also be
2085218822Sdim   specified directly, e.g.:
2086218822Sdim     vadd d0.s32, d1.s32, d2.s32
2087218822Sdim*/
208877298Sobrien
2089218822Sdimstatic int
2090218822Sdimcreate_neon_reg_alias (char *newname, char *p)
209160484Sobrien{
2092218822Sdim  enum arm_reg_type basetype;
2093218822Sdim  struct reg_entry *basereg;
2094218822Sdim  struct reg_entry mybasereg;
2095218822Sdim  struct neon_type ntype;
2096218822Sdim  struct neon_typed_alias typeinfo;
2097218822Sdim  char *namebuf, *nameend;
2098218822Sdim  int namelen;
2099218822Sdim
2100218822Sdim  typeinfo.defined = 0;
2101218822Sdim  typeinfo.eltype.type = NT_invtype;
2102218822Sdim  typeinfo.eltype.size = -1;
2103218822Sdim  typeinfo.index = -1;
2104218822Sdim
2105218822Sdim  nameend = p;
2106218822Sdim
2107218822Sdim  if (strncmp (p, " .dn ", 5) == 0)
2108218822Sdim    basetype = REG_TYPE_VFD;
2109218822Sdim  else if (strncmp (p, " .qn ", 5) == 0)
2110218822Sdim    basetype = REG_TYPE_NQ;
2111218822Sdim  else
2112218822Sdim    return 0;
2113218822Sdim
2114218822Sdim  p += 5;
2115218822Sdim
2116218822Sdim  if (*p == '\0')
2117218822Sdim    return 0;
2118218822Sdim
2119218822Sdim  basereg = arm_reg_parse_multi (&p);
212077298Sobrien
2121218822Sdim  if (basereg && basereg->type != basetype)
2122218822Sdim    {
2123218822Sdim      as_bad (_("bad type for register"));
2124218822Sdim      return 0;
2125218822Sdim    }
212660484Sobrien
2127218822Sdim  if (basereg == NULL)
2128218822Sdim    {
2129218822Sdim      expressionS exp;
2130218822Sdim      /* Try parsing as an integer.  */
2131218822Sdim      my_get_expression (&exp, &p, GE_NO_PREFIX);
2132218822Sdim      if (exp.X_op != O_constant)
2133218822Sdim        {
2134218822Sdim          as_bad (_("expression must be constant"));
2135218822Sdim          return 0;
2136218822Sdim        }
2137218822Sdim      basereg = &mybasereg;
2138218822Sdim      basereg->number = (basetype == REG_TYPE_NQ) ? exp.X_add_number * 2
2139218822Sdim                                                  : exp.X_add_number;
2140218822Sdim      basereg->neon = 0;
2141218822Sdim    }
214277298Sobrien
2143218822Sdim  if (basereg->neon)
2144218822Sdim    typeinfo = *basereg->neon;
2145218822Sdim
2146218822Sdim  if (parse_neon_type (&ntype, &p) == SUCCESS)
2147218822Sdim    {
2148218822Sdim      /* We got a type.  */
2149218822Sdim      if (typeinfo.defined & NTA_HASTYPE)
2150218822Sdim        {
2151218822Sdim          as_bad (_("can't redefine the type of a register alias"));
2152218822Sdim          return 0;
2153218822Sdim        }
2154218822Sdim
2155218822Sdim      typeinfo.defined |= NTA_HASTYPE;
2156218822Sdim      if (ntype.elems != 1)
2157218822Sdim        {
2158218822Sdim          as_bad (_("you must specify a single type only"));
2159218822Sdim          return 0;
2160218822Sdim        }
2161218822Sdim      typeinfo.eltype = ntype.el[0];
2162218822Sdim    }
2163218822Sdim
2164218822Sdim  if (skip_past_char (&p, '[') == SUCCESS)
2165218822Sdim    {
2166218822Sdim      expressionS exp;
2167218822Sdim      /* We got a scalar index.  */
2168218822Sdim
2169218822Sdim      if (typeinfo.defined & NTA_HASINDEX)
2170218822Sdim        {
2171218822Sdim          as_bad (_("can't redefine the index of a scalar alias"));
2172218822Sdim          return 0;
2173218822Sdim        }
2174218822Sdim
2175218822Sdim      my_get_expression (&exp, &p, GE_NO_PREFIX);
2176218822Sdim
2177218822Sdim      if (exp.X_op != O_constant)
2178218822Sdim        {
2179218822Sdim          as_bad (_("scalar index must be constant"));
2180218822Sdim          return 0;
2181218822Sdim        }
2182218822Sdim
2183218822Sdim      typeinfo.defined |= NTA_HASINDEX;
2184218822Sdim      typeinfo.index = exp.X_add_number;
2185218822Sdim
2186218822Sdim      if (skip_past_char (&p, ']') == FAIL)
2187218822Sdim        {
2188218822Sdim          as_bad (_("expecting ]"));
2189218822Sdim          return 0;
2190218822Sdim        }
2191218822Sdim    }
2192218822Sdim
2193218822Sdim  namelen = nameend - newname;
2194218822Sdim  namebuf = alloca (namelen + 1);
2195218822Sdim  strncpy (namebuf, newname, namelen);
2196218822Sdim  namebuf[namelen] = '\0';
2197218822Sdim
2198218822Sdim  insert_neon_reg_alias (namebuf, basereg->number, basetype,
2199218822Sdim                         typeinfo.defined != 0 ? &typeinfo : NULL);
2200218822Sdim
2201218822Sdim  /* Insert name in all uppercase.  */
2202218822Sdim  for (p = namebuf; *p; p++)
2203218822Sdim    *p = TOUPPER (*p);
2204218822Sdim
2205218822Sdim  if (strncmp (namebuf, newname, namelen))
2206218822Sdim    insert_neon_reg_alias (namebuf, basereg->number, basetype,
2207218822Sdim                           typeinfo.defined != 0 ? &typeinfo : NULL);
2208218822Sdim
2209218822Sdim  /* Insert name in all lowercase.  */
2210218822Sdim  for (p = namebuf; *p; p++)
2211218822Sdim    *p = TOLOWER (*p);
2212218822Sdim
2213218822Sdim  if (strncmp (namebuf, newname, namelen))
2214218822Sdim    insert_neon_reg_alias (namebuf, basereg->number, basetype,
2215218822Sdim                           typeinfo.defined != 0 ? &typeinfo : NULL);
2216218822Sdim
2217218822Sdim  return 1;
221860484Sobrien}
221960484Sobrien
2220218822Sdim/* Should never be called, as .req goes between the alias and the
2221218822Sdim   register name, not at the beginning of the line.  */
2222218822Sdimstatic void
2223218822Sdims_req (int a ATTRIBUTE_UNUSED)
222460484Sobrien{
2225218822Sdim  as_bad (_("invalid syntax for .req directive"));
222660484Sobrien}
222760484Sobrien
2228218822Sdimstatic void
2229218822Sdims_dn (int a ATTRIBUTE_UNUSED)
2230218822Sdim{
2231218822Sdim  as_bad (_("invalid syntax for .dn directive"));
2232218822Sdim}
2233130561Sobrien
2234218822Sdimstatic void
2235218822Sdims_qn (int a ATTRIBUTE_UNUSED)
2236218822Sdim{
2237218822Sdim  as_bad (_("invalid syntax for .qn directive"));
2238218822Sdim}
2239130561Sobrien
2240218822Sdim/* The .unreq directive deletes an alias which was previously defined
2241218822Sdim   by .req.  For example:
2242130561Sobrien
2243218822Sdim       my_alias .req r11
2244218822Sdim       .unreq my_alias	  */
2245130561Sobrien
2246218822Sdimstatic void
2247218822Sdims_unreq (int a ATTRIBUTE_UNUSED)
2248218822Sdim{
2249218822Sdim  char * name;
2250218822Sdim  char saved_char;
2251130561Sobrien
2252218822Sdim  name = input_line_pointer;
2253130561Sobrien
2254218822Sdim  while (*input_line_pointer != 0
2255218822Sdim	 && *input_line_pointer != ' '
2256218822Sdim	 && *input_line_pointer != '\n')
2257218822Sdim    ++input_line_pointer;
2258130561Sobrien
2259218822Sdim  saved_char = *input_line_pointer;
2260218822Sdim  *input_line_pointer = 0;
2261130561Sobrien
2262218822Sdim  if (!*name)
2263218822Sdim    as_bad (_("invalid syntax for .unreq directive"));
2264218822Sdim  else
2265218822Sdim    {
2266218822Sdim      struct reg_entry *reg = hash_find (arm_reg_hsh, name);
2267130561Sobrien
2268218822Sdim      if (!reg)
2269218822Sdim	as_bad (_("unknown register alias '%s'"), name);
2270218822Sdim      else if (reg->builtin)
2271218822Sdim	as_warn (_("ignoring attempt to undefine built-in register '%s'"),
2272218822Sdim		 name);
2273218822Sdim      else
2274218822Sdim	{
2275218822Sdim	  hash_delete (arm_reg_hsh, name);
2276218822Sdim	  free ((char *) reg->name);
2277218822Sdim          if (reg->neon)
2278218822Sdim            free (reg->neon);
2279218822Sdim	  free (reg);
2280218822Sdim	}
2281218822Sdim    }
2282130561Sobrien
2283218822Sdim  *input_line_pointer = saved_char;
2284218822Sdim  demand_empty_rest_of_line ();
2285218822Sdim}
2286130561Sobrien
2287218822Sdim/* Directives: Instruction set selection.  */
2288130561Sobrien
2289218822Sdim#ifdef OBJ_ELF
2290218822Sdim/* This code is to handle mapping symbols as defined in the ARM ELF spec.
2291218822Sdim   (See "Mapping symbols", section 4.5.5, ARM AAELF version 1.0).
2292218822Sdim   Note that previously, $a and $t has type STT_FUNC (BSF_OBJECT flag),
2293218822Sdim   and $d has type STT_OBJECT (BSF_OBJECT flag). Now all three are untyped.  */
2294130561Sobrien
2295130561Sobrienstatic enum mstate mapstate = MAP_UNDEFINED;
2296130561Sobrien
2297218822Sdimvoid
2298130561Sobrienmapping_state (enum mstate state)
2299130561Sobrien{
2300130561Sobrien  symbolS * symbolP;
2301130561Sobrien  const char * symname;
2302130561Sobrien  int type;
2303130561Sobrien
2304130561Sobrien  if (mapstate == state)
2305130561Sobrien    /* The mapping symbol has already been emitted.
2306130561Sobrien       There is nothing else to do.  */
2307130561Sobrien    return;
2308130561Sobrien
2309130561Sobrien  mapstate = state;
2310130561Sobrien
2311130561Sobrien  switch (state)
2312130561Sobrien    {
2313130561Sobrien    case MAP_DATA:
2314130561Sobrien      symname = "$d";
2315218822Sdim      type = BSF_NO_FLAGS;
2316130561Sobrien      break;
2317130561Sobrien    case MAP_ARM:
2318130561Sobrien      symname = "$a";
2319218822Sdim      type = BSF_NO_FLAGS;
2320130561Sobrien      break;
2321130561Sobrien    case MAP_THUMB:
2322130561Sobrien      symname = "$t";
2323218822Sdim      type = BSF_NO_FLAGS;
2324130561Sobrien      break;
2325130561Sobrien    case MAP_UNDEFINED:
2326218822Sdim      return;
2327130561Sobrien    default:
2328130561Sobrien      abort ();
2329130561Sobrien    }
2330130561Sobrien
2331218822Sdim  seg_info (now_seg)->tc_segment_info_data.mapstate = state;
2332130561Sobrien
2333130561Sobrien  symbolP = symbol_new (symname, now_seg, (valueT) frag_now_fix (), frag_now);
2334130561Sobrien  symbol_table_insert (symbolP);
2335130561Sobrien  symbol_get_bfdsym (symbolP)->flags |= type | BSF_LOCAL;
2336218822Sdim
2337130561Sobrien  switch (state)
2338130561Sobrien    {
2339130561Sobrien    case MAP_ARM:
2340130561Sobrien      THUMB_SET_FUNC (symbolP, 0);
2341130561Sobrien      ARM_SET_THUMB (symbolP, 0);
2342130561Sobrien      ARM_SET_INTERWORK (symbolP, support_interwork);
2343130561Sobrien      break;
2344218822Sdim
2345130561Sobrien    case MAP_THUMB:
2346130561Sobrien      THUMB_SET_FUNC (symbolP, 1);
2347130561Sobrien      ARM_SET_THUMB (symbolP, 1);
2348130561Sobrien      ARM_SET_INTERWORK (symbolP, support_interwork);
2349130561Sobrien      break;
2350218822Sdim
2351130561Sobrien    case MAP_DATA:
2352130561Sobrien    default:
2353130561Sobrien      return;
2354130561Sobrien    }
2355130561Sobrien}
2356218822Sdim#else
2357218822Sdim#define mapping_state(x) /* nothing */
2358218822Sdim#endif
2359130561Sobrien
2360218822Sdim/* Find the real, Thumb encoded start of a Thumb function.  */
2361130561Sobrien
2362218822Sdimstatic symbolS *
2363218822Sdimfind_real_start (symbolS * symbolP)
2364130561Sobrien{
2365218822Sdim  char *       real_start;
2366218822Sdim  const char * name = S_GET_NAME (symbolP);
2367218822Sdim  symbolS *    new_target;
2368130561Sobrien
2369218822Sdim  /* This definition must agree with the one in gcc/config/arm/thumb.c.	 */
2370218822Sdim#define STUB_NAME ".real_start_of"
2371130561Sobrien
2372218822Sdim  if (name == NULL)
2373218822Sdim    abort ();
2374130561Sobrien
2375218822Sdim  /* The compiler may generate BL instructions to local labels because
2376218822Sdim     it needs to perform a branch to a far away location. These labels
2377218822Sdim     do not have a corresponding ".real_start_of" label.  We check
2378218822Sdim     both for S_IS_LOCAL and for a leading dot, to give a way to bypass
2379218822Sdim     the ".real_start_of" convention for nonlocal branches.  */
2380218822Sdim  if (S_IS_LOCAL (symbolP) || name[0] == '.')
2381218822Sdim    return symbolP;
2382130561Sobrien
2383218822Sdim  real_start = ACONCAT ((STUB_NAME, name, NULL));
2384218822Sdim  new_target = symbol_find (real_start);
2385130561Sobrien
2386218822Sdim  if (new_target == NULL)
2387218822Sdim    {
2388218822Sdim      as_warn ("Failed to find real start of function: %s\n", name);
2389218822Sdim      new_target = symbolP;
2390218822Sdim    }
2391218822Sdim
2392218822Sdim  return new_target;
239360484Sobrien}
239460484Sobrien
239560484Sobrienstatic void
2396218822Sdimopcode_select (int width)
2397130561Sobrien{
2398218822Sdim  switch (width)
2399218822Sdim    {
2400218822Sdim    case 16:
2401218822Sdim      if (! thumb_mode)
2402218822Sdim	{
2403218822Sdim	  if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v4t))
2404218822Sdim	    as_bad (_("selected processor does not support THUMB opcodes"));
2405130561Sobrien
2406218822Sdim	  thumb_mode = 1;
2407218822Sdim	  /* No need to force the alignment, since we will have been
2408218822Sdim	     coming from ARM mode, which is word-aligned.  */
2409218822Sdim	  record_alignment (now_seg, 1);
2410218822Sdim	}
2411218822Sdim      mapping_state (MAP_THUMB);
2412218822Sdim      break;
2413130561Sobrien
2414218822Sdim    case 32:
2415218822Sdim      if (thumb_mode)
2416130561Sobrien	{
2417218822Sdim	  if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1))
2418218822Sdim	    as_bad (_("selected processor does not support ARM opcodes"));
2419130561Sobrien
2420218822Sdim	  thumb_mode = 0;
2421130561Sobrien
2422218822Sdim	  if (!need_pass_2)
2423218822Sdim	    frag_align (2, 0, 0);
2424130561Sobrien
2425218822Sdim	  record_alignment (now_seg, 1);
2426130561Sobrien	}
2427218822Sdim      mapping_state (MAP_ARM);
2428218822Sdim      break;
2429218822Sdim
2430218822Sdim    default:
2431218822Sdim      as_bad (_("invalid instruction size selected (%d)"), width);
2432130561Sobrien    }
2433130561Sobrien}
2434130561Sobrien
2435130561Sobrienstatic void
2436218822Sdims_arm (int ignore ATTRIBUTE_UNUSED)
243760484Sobrien{
2438218822Sdim  opcode_select (32);
243960484Sobrien  demand_empty_rest_of_line ();
244060484Sobrien}
244160484Sobrien
244260484Sobrienstatic void
2443218822Sdims_thumb (int ignore ATTRIBUTE_UNUSED)
244460484Sobrien{
2445218822Sdim  opcode_select (16);
244660484Sobrien  demand_empty_rest_of_line ();
244760484Sobrien}
244860484Sobrien
244960484Sobrienstatic void
2450218822Sdims_code (int unused ATTRIBUTE_UNUSED)
245160484Sobrien{
2452218822Sdim  int temp;
245360484Sobrien
245460484Sobrien  temp = get_absolute_expression ();
2455218822Sdim  switch (temp)
245660484Sobrien    {
2457218822Sdim    case 16:
2458218822Sdim    case 32:
2459218822Sdim      opcode_select (temp);
2460218822Sdim      break;
246160484Sobrien
2462218822Sdim    default:
2463218822Sdim      as_bad (_("invalid operand to .code directive (%d) (expecting 16 or 32)"), temp);
246460484Sobrien    }
246560484Sobrien}
246660484Sobrien
246760484Sobrienstatic void
2468218822Sdims_force_thumb (int ignore ATTRIBUTE_UNUSED)
246960484Sobrien{
247060484Sobrien  /* If we are not already in thumb mode go into it, EVEN if
247160484Sobrien     the target processor does not support thumb instructions.
247260484Sobrien     This is used by gcc/config/arm/lib1funcs.asm for example
247360484Sobrien     to compile interworking support functions even if the
2474218822Sdim     target processor should not support interworking.	*/
247560484Sobrien  if (! thumb_mode)
247660484Sobrien    {
247760484Sobrien      thumb_mode = 2;
247860484Sobrien      record_alignment (now_seg, 1);
247960484Sobrien    }
248077298Sobrien
248160484Sobrien  demand_empty_rest_of_line ();
248260484Sobrien}
248360484Sobrien
248460484Sobrienstatic void
2485218822Sdims_thumb_func (int ignore ATTRIBUTE_UNUSED)
248660484Sobrien{
2487218822Sdim  s_thumb (0);
248877298Sobrien
248960484Sobrien  /* The following label is the name/address of the start of a Thumb function.
2490218822Sdim     We need to know this for the interworking support.	 */
2491130561Sobrien  label_is_thumb_function_name = TRUE;
249260484Sobrien}
249360484Sobrien
249460484Sobrien/* Perform a .set directive, but also mark the alias as
249560484Sobrien   being a thumb function.  */
249660484Sobrien
249760484Sobrienstatic void
2498218822Sdims_thumb_set (int equiv)
249960484Sobrien{
250060484Sobrien  /* XXX the following is a duplicate of the code for s_set() in read.c
250160484Sobrien     We cannot just call that code as we need to get at the symbol that
250260484Sobrien     is created.  */
2503218822Sdim  char *    name;
2504218822Sdim  char	    delim;
2505218822Sdim  char *    end_name;
2506218822Sdim  symbolS * symbolP;
250760484Sobrien
250877298Sobrien  /* Especial apologies for the random logic:
250977298Sobrien     This just grew, and could be parsed much more simply!
251077298Sobrien     Dean - in haste.  */
2511218822Sdim  name	    = input_line_pointer;
2512218822Sdim  delim	    = get_symbol_end ();
251360484Sobrien  end_name  = input_line_pointer;
251460484Sobrien  *end_name = delim;
251577298Sobrien
251660484Sobrien  if (*input_line_pointer != ',')
251760484Sobrien    {
251860484Sobrien      *end_name = 0;
251989857Sobrien      as_bad (_("expected comma after name \"%s\""), name);
252060484Sobrien      *end_name = delim;
252160484Sobrien      ignore_rest_of_line ();
252260484Sobrien      return;
252360484Sobrien    }
252460484Sobrien
252560484Sobrien  input_line_pointer++;
252660484Sobrien  *end_name = 0;
252760484Sobrien
252860484Sobrien  if (name[0] == '.' && name[1] == '\0')
252960484Sobrien    {
253077298Sobrien      /* XXX - this should not happen to .thumb_set.  */
253160484Sobrien      abort ();
253260484Sobrien    }
253360484Sobrien
253460484Sobrien  if ((symbolP = symbol_find (name)) == NULL
253560484Sobrien      && (symbolP = md_undefined_symbol (name)) == NULL)
253660484Sobrien    {
253760484Sobrien#ifndef NO_LISTING
253860484Sobrien      /* When doing symbol listings, play games with dummy fragments living
253960484Sobrien	 outside the normal fragment chain to record the file and line info
2540218822Sdim	 for this symbol.  */
254160484Sobrien      if (listing & LISTING_SYMBOLS)
254260484Sobrien	{
254360484Sobrien	  extern struct list_info_struct * listing_tail;
2544218822Sdim	  fragS * dummy_frag = xmalloc (sizeof (fragS));
254577298Sobrien
254677298Sobrien	  memset (dummy_frag, 0, sizeof (fragS));
254760484Sobrien	  dummy_frag->fr_type = rs_fill;
254860484Sobrien	  dummy_frag->line = listing_tail;
254960484Sobrien	  symbolP = symbol_new (name, undefined_section, 0, dummy_frag);
255060484Sobrien	  dummy_frag->fr_symbol = symbolP;
255160484Sobrien	}
255260484Sobrien      else
255360484Sobrien#endif
255477298Sobrien	symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag);
255577298Sobrien
255660484Sobrien#ifdef OBJ_COFF
255777298Sobrien      /* "set" symbols are local unless otherwise specified.  */
255860484Sobrien      SF_SET_LOCAL (symbolP);
255977298Sobrien#endif /* OBJ_COFF  */
256077298Sobrien    }				/* Make a new symbol.  */
256160484Sobrien
256260484Sobrien  symbol_table_insert (symbolP);
256360484Sobrien
256460484Sobrien  * end_name = delim;
256560484Sobrien
256660484Sobrien  if (equiv
256760484Sobrien      && S_IS_DEFINED (symbolP)
256860484Sobrien      && S_GET_SEGMENT (symbolP) != reg_section)
256960484Sobrien    as_bad (_("symbol `%s' already defined"), S_GET_NAME (symbolP));
257060484Sobrien
257160484Sobrien  pseudo_set (symbolP);
257277298Sobrien
257360484Sobrien  demand_empty_rest_of_line ();
257460484Sobrien
2575218822Sdim  /* XXX Now we come to the Thumb specific bit of code.	 */
257677298Sobrien
257760484Sobrien  THUMB_SET_FUNC (symbolP, 1);
257860484Sobrien  ARM_SET_THUMB (symbolP, 1);
257960484Sobrien#if defined OBJ_ELF || defined OBJ_COFF
258060484Sobrien  ARM_SET_INTERWORK (symbolP, support_interwork);
258160484Sobrien#endif
258260484Sobrien}
258360484Sobrien
2584218822Sdim/* Directives: Mode selection.  */
2585218822Sdim
2586218822Sdim/* .syntax [unified|divided] - choose the new unified syntax
2587218822Sdim   (same for Arm and Thumb encoding, modulo slight differences in what
2588218822Sdim   can be represented) or the old divergent syntax for each mode.  */
258960484Sobrienstatic void
2590218822Sdims_syntax (int unused ATTRIBUTE_UNUSED)
259160484Sobrien{
2592218822Sdim  char *name, delim;
259377298Sobrien
2594218822Sdim  name = input_line_pointer;
2595218822Sdim  delim = get_symbol_end ();
259660484Sobrien
2597218822Sdim  if (!strcasecmp (name, "unified"))
2598218822Sdim    unified_syntax = TRUE;
2599218822Sdim  else if (!strcasecmp (name, "divided"))
2600218822Sdim    unified_syntax = FALSE;
2601218822Sdim  else
2602218822Sdim    {
2603218822Sdim      as_bad (_("unrecognized syntax mode \"%s\""), name);
2604218822Sdim      return;
260560484Sobrien    }
2606218822Sdim  *input_line_pointer = delim;
260760484Sobrien  demand_empty_rest_of_line ();
260860484Sobrien}
260960484Sobrien
2610218822Sdim/* Directives: sectioning and alignment.  */
261160484Sobrien
2612218822Sdim/* Same as s_align_ptwo but align 0 => align 2.	 */
2613218822Sdim
261460484Sobrienstatic void
2615218822Sdims_align (int unused ATTRIBUTE_UNUSED)
261660484Sobrien{
2617218822Sdim  int temp;
2618218822Sdim  bfd_boolean fill_p;
2619218822Sdim  long temp_fill;
2620218822Sdim  long max_alignment = 15;
262160484Sobrien
262260484Sobrien  temp = get_absolute_expression ();
2623218822Sdim  if (temp > max_alignment)
2624218822Sdim    as_bad (_("alignment too large: %d assumed"), temp = max_alignment);
2625218822Sdim  else if (temp < 0)
262660484Sobrien    {
2627218822Sdim      as_bad (_("alignment negative. 0 assumed."));
2628218822Sdim      temp = 0;
2629218822Sdim    }
263060484Sobrien
2631218822Sdim  if (*input_line_pointer == ',')
2632218822Sdim    {
2633218822Sdim      input_line_pointer++;
2634218822Sdim      temp_fill = get_absolute_expression ();
2635218822Sdim      fill_p = TRUE;
263660484Sobrien    }
2637218822Sdim  else
2638218822Sdim    {
2639218822Sdim      fill_p = FALSE;
2640218822Sdim      temp_fill = 0;
2641218822Sdim    }
264260484Sobrien
2643218822Sdim  if (!temp)
2644218822Sdim    temp = 2;
264560484Sobrien
2646218822Sdim  /* Only make a frag if we HAVE to.  */
2647218822Sdim  if (temp && !need_pass_2)
264860484Sobrien    {
2649218822Sdim      if (!fill_p && subseg_text_p (now_seg))
2650218822Sdim	frag_align_code (temp, 0);
2651218822Sdim      else
2652218822Sdim	frag_align (temp, (int) temp_fill, 0);
265360484Sobrien    }
2654218822Sdim  demand_empty_rest_of_line ();
265560484Sobrien
2656218822Sdim  record_alignment (now_seg, temp);
2657218822Sdim}
265860484Sobrien
2659218822Sdimstatic void
2660218822Sdims_bss (int ignore ATTRIBUTE_UNUSED)
2661218822Sdim{
2662218822Sdim  /* We don't support putting frags in the BSS segment, we fake it by
2663218822Sdim     marking in_bss, then looking at s_skip for clues.	*/
2664218822Sdim  subseg_set (bss_section, 0);
2665218822Sdim  demand_empty_rest_of_line ();
2666218822Sdim  mapping_state (MAP_DATA);
266760484Sobrien}
266860484Sobrien
2669218822Sdimstatic void
2670218822Sdims_even (int ignore ATTRIBUTE_UNUSED)
267160484Sobrien{
2672218822Sdim  /* Never make frag if expect extra pass.  */
2673218822Sdim  if (!need_pass_2)
2674218822Sdim    frag_align (1, 0, 0);
267560484Sobrien
2676218822Sdim  record_alignment (now_seg, 1);
267760484Sobrien
2678218822Sdim  demand_empty_rest_of_line ();
267960484Sobrien}
268060484Sobrien
2681218822Sdim/* Directives: Literal pools.  */
2682130561Sobrien
2683218822Sdimstatic literal_pool *
2684218822Sdimfind_literal_pool (void)
2685130561Sobrien{
2686218822Sdim  literal_pool * pool;
2687130561Sobrien
2688218822Sdim  for (pool = list_of_pools; pool != NULL; pool = pool->next)
2689130561Sobrien    {
2690218822Sdim      if (pool->section == now_seg
2691218822Sdim	  && pool->sub_section == now_subseg)
2692218822Sdim	break;
2693130561Sobrien    }
2694130561Sobrien
2695218822Sdim  return pool;
2696130561Sobrien}
2697130561Sobrien
2698218822Sdimstatic literal_pool *
2699218822Sdimfind_or_make_literal_pool (void)
270061843Sobrien{
2701218822Sdim  /* Next literal pool ID number.  */
2702218822Sdim  static unsigned int latest_pool_num = 1;
2703218822Sdim  literal_pool *      pool;
270461843Sobrien
2705218822Sdim  pool = find_literal_pool ();
270661843Sobrien
2707218822Sdim  if (pool == NULL)
270861843Sobrien    {
2709218822Sdim      /* Create a new pool.  */
2710218822Sdim      pool = xmalloc (sizeof (* pool));
2711218822Sdim      if (! pool)
2712218822Sdim	return NULL;
271361843Sobrien
2714218822Sdim      pool->next_free_entry = 0;
2715218822Sdim      pool->section	    = now_seg;
2716218822Sdim      pool->sub_section	    = now_subseg;
2717218822Sdim      pool->next	    = list_of_pools;
2718218822Sdim      pool->symbol	    = NULL;
271961843Sobrien
2720218822Sdim      /* Add it to the list.  */
2721218822Sdim      list_of_pools = pool;
2722218822Sdim    }
272377298Sobrien
2724218822Sdim  /* New pools, and emptied pools, will have a NULL symbol.  */
2725218822Sdim  if (pool->symbol == NULL)
2726218822Sdim    {
2727218822Sdim      pool->symbol = symbol_create (FAKE_LABEL_NAME, undefined_section,
2728218822Sdim				    (valueT) 0, &zero_address_frag);
2729218822Sdim      pool->id = latest_pool_num ++;
2730218822Sdim    }
273161843Sobrien
2732218822Sdim  /* Done.  */
2733218822Sdim  return pool;
273461843Sobrien}
273561843Sobrien
2736218822Sdim/* Add the literal in the global 'inst'
2737218822Sdim   structure to the relevent literal pool.  */
273877298Sobrien
273960484Sobrienstatic int
2740218822Sdimadd_to_lit_pool (void)
274160484Sobrien{
2742218822Sdim  literal_pool * pool;
2743218822Sdim  unsigned int entry;
274477298Sobrien
2745218822Sdim  pool = find_or_make_literal_pool ();
274661843Sobrien
2747218822Sdim  /* Check if this literal value is already in the pool.  */
2748218822Sdim  for (entry = 0; entry < pool->next_free_entry; entry ++)
274960484Sobrien    {
2750218822Sdim      if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
2751218822Sdim	  && (inst.reloc.exp.X_op == O_constant)
2752218822Sdim	  && (pool->literals[entry].X_add_number
2753218822Sdim	      == inst.reloc.exp.X_add_number)
2754218822Sdim	  && (pool->literals[entry].X_unsigned
2755218822Sdim	      == inst.reloc.exp.X_unsigned))
2756218822Sdim	break;
275761843Sobrien
2758218822Sdim      if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
2759218822Sdim	  && (inst.reloc.exp.X_op == O_symbol)
2760218822Sdim	  && (pool->literals[entry].X_add_number
2761218822Sdim	      == inst.reloc.exp.X_add_number)
2762218822Sdim	  && (pool->literals[entry].X_add_symbol
2763218822Sdim	      == inst.reloc.exp.X_add_symbol)
2764218822Sdim	  && (pool->literals[entry].X_op_symbol
2765218822Sdim	      == inst.reloc.exp.X_op_symbol))
2766218822Sdim	break;
276760484Sobrien    }
276860484Sobrien
2769218822Sdim  /* Do we need to create a new entry?	*/
2770218822Sdim  if (entry == pool->next_free_entry)
277189857Sobrien    {
2772218822Sdim      if (entry >= MAX_LITERAL_POOL_SIZE)
277360484Sobrien	{
2774218822Sdim	  inst.error = _("literal pool overflow");
277589857Sobrien	  return FAIL;
277689857Sobrien	}
2777218822Sdim
2778218822Sdim      pool->literals[entry] = inst.reloc.exp;
2779218822Sdim      pool->next_free_entry += 1;
278060484Sobrien    }
278160484Sobrien
2782218822Sdim  inst.reloc.exp.X_op	      = O_symbol;
2783218822Sdim  inst.reloc.exp.X_add_number = ((int) entry) * 4;
2784218822Sdim  inst.reloc.exp.X_add_symbol = pool->symbol;
2785218822Sdim
278660484Sobrien  return SUCCESS;
278760484Sobrien}
278860484Sobrien
2789218822Sdim/* Can't use symbol_new here, so have to create a symbol and then at
2790218822Sdim   a later date assign it a value. Thats what these functions do.  */
2791218822Sdim
2792218822Sdimstatic void
2793218822Sdimsymbol_locate (symbolS *    symbolP,
2794218822Sdim	       const char * name,	/* It is copied, the caller can modify.	 */
2795218822Sdim	       segT	    segment,	/* Segment identifier (SEG_<something>).  */
2796218822Sdim	       valueT	    valu,	/* Symbol value.  */
2797218822Sdim	       fragS *	    frag)	/* Associated fragment.	 */
279860484Sobrien{
2799218822Sdim  unsigned int name_length;
2800218822Sdim  char * preserved_copy_of_name;
280160484Sobrien
2802218822Sdim  name_length = strlen (name) + 1;   /* +1 for \0.  */
2803218822Sdim  obstack_grow (&notes, name, name_length);
2804218822Sdim  preserved_copy_of_name = obstack_finish (&notes);
280560484Sobrien
2806218822Sdim#ifdef tc_canonicalize_symbol_name
2807218822Sdim  preserved_copy_of_name =
2808218822Sdim    tc_canonicalize_symbol_name (preserved_copy_of_name);
2809218822Sdim#endif
281060484Sobrien
2811218822Sdim  S_SET_NAME (symbolP, preserved_copy_of_name);
281260484Sobrien
2813218822Sdim  S_SET_SEGMENT (symbolP, segment);
2814218822Sdim  S_SET_VALUE (symbolP, valu);
2815218822Sdim  symbol_clear_list_pointers (symbolP);
281660484Sobrien
2817218822Sdim  symbol_set_frag (symbolP, frag);
281860484Sobrien
2819218822Sdim  /* Link to end of symbol chain.  */
2820218822Sdim  {
2821218822Sdim    extern int symbol_table_frozen;
282260484Sobrien
2823218822Sdim    if (symbol_table_frozen)
2824218822Sdim      abort ();
2825218822Sdim  }
282660484Sobrien
2827218822Sdim  symbol_append (symbolP, symbol_lastP, & symbol_rootP, & symbol_lastP);
282860484Sobrien
2829218822Sdim  obj_symbol_new_hook (symbolP);
283060484Sobrien
2831218822Sdim#ifdef tc_symbol_new_hook
2832218822Sdim  tc_symbol_new_hook (symbolP);
2833218822Sdim#endif
283460484Sobrien
2835218822Sdim#ifdef DEBUG_SYMS
2836218822Sdim  verify_symbol_chain (symbol_rootP, symbol_lastP);
2837218822Sdim#endif /* DEBUG_SYMS  */
2838218822Sdim}
283960484Sobrien
284060484Sobrien
2841218822Sdimstatic void
2842218822Sdims_ltorg (int ignored ATTRIBUTE_UNUSED)
284360484Sobrien{
2844218822Sdim  unsigned int entry;
2845218822Sdim  literal_pool * pool;
2846218822Sdim  char sym_name[20];
284760484Sobrien
2848218822Sdim  pool = find_literal_pool ();
2849218822Sdim  if (pool == NULL
2850218822Sdim      || pool->symbol == NULL
2851218822Sdim      || pool->next_free_entry == 0)
2852218822Sdim    return;
285360484Sobrien
2854218822Sdim  mapping_state (MAP_DATA);
285560484Sobrien
2856218822Sdim  /* Align pool as you have word accesses.
2857218822Sdim     Only make a frag if we have to.  */
2858218822Sdim  if (!need_pass_2)
2859218822Sdim    frag_align (2, 0, 0);
286077298Sobrien
2861218822Sdim  record_alignment (now_seg, 2);
286277298Sobrien
2863218822Sdim  sprintf (sym_name, "$$lit_\002%x", pool->id);
286477298Sobrien
2865218822Sdim  symbol_locate (pool->symbol, sym_name, now_seg,
2866218822Sdim		 (valueT) frag_now_fix (), frag_now);
2867218822Sdim  symbol_table_insert (pool->symbol);
286860484Sobrien
2869218822Sdim  ARM_SET_THUMB (pool->symbol, thumb_mode);
287060484Sobrien
2871218822Sdim#if defined OBJ_COFF || defined OBJ_ELF
2872218822Sdim  ARM_SET_INTERWORK (pool->symbol, support_interwork);
2873218822Sdim#endif
287460484Sobrien
2875218822Sdim  for (entry = 0; entry < pool->next_free_entry; entry ++)
2876218822Sdim    /* First output the expression in the instruction to the pool.  */
2877218822Sdim    emit_expr (&(pool->literals[entry]), 4); /* .word  */
287860484Sobrien
2879218822Sdim  /* Mark the pool as empty.  */
2880218822Sdim  pool->next_free_entry = 0;
2881218822Sdim  pool->symbol = NULL;
288260484Sobrien}
288360484Sobrien
2884218822Sdim#ifdef OBJ_ELF
2885218822Sdim/* Forward declarations for functions below, in the MD interface
2886218822Sdim   section.  */
2887218822Sdimstatic void fix_new_arm (fragS *, int, short, expressionS *, int, int);
2888218822Sdimstatic valueT create_unwind_entry (int);
2889218822Sdimstatic void start_unwind_section (const segT, int);
2890218822Sdimstatic void add_unwind_opcode (valueT, int);
2891218822Sdimstatic void flush_pending_unwind (void);
2892218822Sdim
2893218822Sdim/* Directives: Data.  */
2894218822Sdim
2895218822Sdimstatic void
2896218822Sdims_arm_elf_cons (int nbytes)
289760484Sobrien{
2898218822Sdim  expressionS exp;
289960484Sobrien
2900218822Sdim#ifdef md_flush_pending_output
2901218822Sdim  md_flush_pending_output ();
2902218822Sdim#endif
2903218822Sdim
2904218822Sdim  if (is_it_end_of_statement ())
290560484Sobrien    {
2906218822Sdim      demand_empty_rest_of_line ();
2907218822Sdim      return;
2908218822Sdim    }
290960484Sobrien
2910218822Sdim#ifdef md_cons_align
2911218822Sdim  md_cons_align (nbytes);
2912218822Sdim#endif
291360484Sobrien
2914218822Sdim  mapping_state (MAP_DATA);
2915218822Sdim  do
2916218822Sdim    {
2917218822Sdim      int reloc;
2918218822Sdim      char *base = input_line_pointer;
291960484Sobrien
2920218822Sdim      expression (& exp);
292160484Sobrien
2922218822Sdim      if (exp.X_op != O_symbol)
2923218822Sdim	emit_expr (&exp, (unsigned int) nbytes);
2924218822Sdim      else
292560484Sobrien	{
2926218822Sdim	  char *before_reloc = input_line_pointer;
2927218822Sdim	  reloc = parse_reloc (&input_line_pointer);
2928218822Sdim	  if (reloc == -1)
292960484Sobrien	    {
2930218822Sdim	      as_bad (_("unrecognized relocation suffix"));
2931218822Sdim	      ignore_rest_of_line ();
2932218822Sdim	      return;
2933130561Sobrien	    }
2934218822Sdim	  else if (reloc == BFD_RELOC_UNUSED)
2935218822Sdim	    emit_expr (&exp, (unsigned int) nbytes);
2936218822Sdim	  else
2937130561Sobrien	    {
2938218822Sdim	      reloc_howto_type *howto = bfd_reloc_type_lookup (stdoutput, reloc);
2939218822Sdim	      int size = bfd_get_reloc_size (howto);
2940130561Sobrien
2941218822Sdim	      if (reloc == BFD_RELOC_ARM_PLT32)
294260484Sobrien		{
2943218822Sdim		  as_bad (_("(plt) is only valid on branch targets"));
2944218822Sdim		  reloc = BFD_RELOC_UNUSED;
2945218822Sdim		  size = 0;
2946218822Sdim		}
2947130561Sobrien
2948218822Sdim	      if (size > nbytes)
2949218822Sdim		as_bad (_("%s relocations do not fit in %d bytes"),
2950218822Sdim			howto->name, nbytes);
2951130561Sobrien	      else
2952130561Sobrien		{
2953218822Sdim		  /* We've parsed an expression stopping at O_symbol.
2954218822Sdim		     But there may be more expression left now that we
2955218822Sdim		     have parsed the relocation marker.  Parse it again.
2956218822Sdim		     XXX Surely there is a cleaner way to do this.  */
2957218822Sdim		  char *p = input_line_pointer;
2958218822Sdim		  int offset;
2959218822Sdim		  char *save_buf = alloca (input_line_pointer - base);
2960218822Sdim		  memcpy (save_buf, base, input_line_pointer - base);
2961218822Sdim		  memmove (base + (input_line_pointer - before_reloc),
2962218822Sdim			   base, before_reloc - base);
2963130561Sobrien
2964218822Sdim		  input_line_pointer = base + (input_line_pointer-before_reloc);
2965218822Sdim		  expression (&exp);
2966218822Sdim		  memcpy (base, save_buf, p - base);
2967130561Sobrien
2968218822Sdim		  offset = nbytes - size;
2969218822Sdim		  p = frag_more ((int) nbytes);
2970218822Sdim		  fix_new_exp (frag_now, p - frag_now->fr_literal + offset,
2971218822Sdim			       size, &exp, 0, reloc);
2972130561Sobrien		}
297360484Sobrien	    }
297460484Sobrien	}
2975218822Sdim    }
2976218822Sdim  while (*input_line_pointer++ == ',');
297760484Sobrien
2978218822Sdim  /* Put terminator back into stream.  */
2979218822Sdim  input_line_pointer --;
2980218822Sdim  demand_empty_rest_of_line ();
2981218822Sdim}
298260484Sobrien
298377298Sobrien
2984218822Sdim/* Parse a .rel31 directive.  */
298560484Sobrien
2986218822Sdimstatic void
2987218822Sdims_arm_rel31 (int ignored ATTRIBUTE_UNUSED)
2988218822Sdim{
2989218822Sdim  expressionS exp;
2990218822Sdim  char *p;
2991218822Sdim  valueT highbit;
299260484Sobrien
2993218822Sdim  highbit = 0;
2994218822Sdim  if (*input_line_pointer == '1')
2995218822Sdim    highbit = 0x80000000;
2996218822Sdim  else if (*input_line_pointer != '0')
2997218822Sdim    as_bad (_("expected 0 or 1"));
299860484Sobrien
2999218822Sdim  input_line_pointer++;
3000218822Sdim  if (*input_line_pointer != ',')
3001218822Sdim    as_bad (_("missing comma"));
3002218822Sdim  input_line_pointer++;
300360484Sobrien
3004218822Sdim#ifdef md_flush_pending_output
3005218822Sdim  md_flush_pending_output ();
3006218822Sdim#endif
300760484Sobrien
3008218822Sdim#ifdef md_cons_align
3009218822Sdim  md_cons_align (4);
3010218822Sdim#endif
301160484Sobrien
3012218822Sdim  mapping_state (MAP_DATA);
301360484Sobrien
3014218822Sdim  expression (&exp);
301560484Sobrien
3016218822Sdim  p = frag_more (4);
3017218822Sdim  md_number_to_chars (p, highbit, 4);
3018218822Sdim  fix_new_arm (frag_now, p - frag_now->fr_literal, 4, &exp, 1,
3019218822Sdim	       BFD_RELOC_ARM_PREL31);
3020130561Sobrien
3021218822Sdim  demand_empty_rest_of_line ();
3022218822Sdim}
3023130561Sobrien
3024218822Sdim/* Directives: AEABI stack-unwind tables.  */
3025130561Sobrien
3026218822Sdim/* Parse an unwind_fnstart directive.  Simply records the current location.  */
3027130561Sobrien
3028218822Sdimstatic void
3029218822Sdims_arm_unwind_fnstart (int ignored ATTRIBUTE_UNUSED)
3030218822Sdim{
3031218822Sdim  demand_empty_rest_of_line ();
3032218822Sdim  /* Mark the start of the function.  */
3033218822Sdim  unwind.proc_start = expr_build_dot ();
3034130561Sobrien
3035218822Sdim  /* Reset the rest of the unwind info.	 */
3036218822Sdim  unwind.opcode_count = 0;
3037218822Sdim  unwind.table_entry = NULL;
3038218822Sdim  unwind.personality_routine = NULL;
3039218822Sdim  unwind.personality_index = -1;
3040218822Sdim  unwind.frame_size = 0;
3041218822Sdim  unwind.fp_offset = 0;
3042218822Sdim  unwind.fp_reg = 13;
3043218822Sdim  unwind.fp_used = 0;
3044218822Sdim  unwind.sp_restored = 0;
3045130561Sobrien}
3046130561Sobrien
3047130561Sobrien
3048218822Sdim/* Parse a handlerdata directive.  Creates the exception handling table entry
3049218822Sdim   for the function.  */
3050130561Sobrien
3051218822Sdimstatic void
3052218822Sdims_arm_unwind_handlerdata (int ignored ATTRIBUTE_UNUSED)
3053218822Sdim{
3054218822Sdim  demand_empty_rest_of_line ();
3055218822Sdim  if (unwind.table_entry)
3056218822Sdim    as_bad (_("dupicate .handlerdata directive"));
3057130561Sobrien
3058218822Sdim  create_unwind_entry (1);
3059218822Sdim}
3060130561Sobrien
3061218822Sdim/* Parse an unwind_fnend directive.  Generates the index table entry.  */
3062130561Sobrien
3063218822Sdimstatic void
3064218822Sdims_arm_unwind_fnend (int ignored ATTRIBUTE_UNUSED)
3065218822Sdim{
3066218822Sdim  long where;
3067218822Sdim  char *ptr;
3068218822Sdim  valueT val;
3069130561Sobrien
3070218822Sdim  demand_empty_rest_of_line ();
3071130561Sobrien
3072218822Sdim  /* Add eh table entry.  */
3073218822Sdim  if (unwind.table_entry == NULL)
3074218822Sdim    val = create_unwind_entry (0);
3075218822Sdim  else
3076218822Sdim    val = 0;
3077130561Sobrien
3078218822Sdim  /* Add index table entry.  This is two words.	 */
3079218822Sdim  start_unwind_section (unwind.saved_seg, 1);
3080218822Sdim  frag_align (2, 0, 0);
3081218822Sdim  record_alignment (now_seg, 2);
3082130561Sobrien
3083218822Sdim  ptr = frag_more (8);
3084247386Sandrew  memset(ptr, 0, 8);
3085218822Sdim  where = frag_now_fix () - 8;
3086130561Sobrien
3087218822Sdim  /* Self relative offset of the function start.  */
3088218822Sdim  fix_new (frag_now, where, 4, unwind.proc_start, 0, 1,
3089218822Sdim	   BFD_RELOC_ARM_PREL31);
3090130561Sobrien
3091218822Sdim  /* Indicate dependency on EHABI-defined personality routines to the
3092218822Sdim     linker, if it hasn't been done already.  */
3093218822Sdim  if (unwind.personality_index >= 0 && unwind.personality_index < 3
3094218822Sdim      && !(marked_pr_dependency & (1 << unwind.personality_index)))
3095218822Sdim    {
3096218822Sdim      static const char *const name[] = {
3097218822Sdim	"__aeabi_unwind_cpp_pr0",
3098218822Sdim	"__aeabi_unwind_cpp_pr1",
3099218822Sdim	"__aeabi_unwind_cpp_pr2"
3100218822Sdim      };
3101218822Sdim      symbolS *pr = symbol_find_or_make (name[unwind.personality_index]);
3102218822Sdim      fix_new (frag_now, where, 0, pr, 0, 1, BFD_RELOC_NONE);
3103218822Sdim      marked_pr_dependency |= 1 << unwind.personality_index;
3104218822Sdim      seg_info (now_seg)->tc_segment_info_data.marked_pr_dependency
3105218822Sdim	= marked_pr_dependency;
3106218822Sdim    }
3107130561Sobrien
3108218822Sdim  if (val)
3109218822Sdim    /* Inline exception table entry.  */
3110218822Sdim    md_number_to_chars (ptr + 4, val, 4);
3111130561Sobrien  else
3112218822Sdim    /* Self relative offset of the table entry.	 */
3113218822Sdim    fix_new (frag_now, where + 4, 4, unwind.table_entry, 0, 1,
3114218822Sdim	     BFD_RELOC_ARM_PREL31);
3115130561Sobrien
3116218822Sdim  /* Restore the original section.  */
3117218822Sdim  subseg_set (unwind.saved_seg, unwind.saved_subseg);
3118130561Sobrien}
3119130561Sobrien
3120218822Sdim
3121218822Sdim/* Parse an unwind_cantunwind directive.  */
3122218822Sdim
312360484Sobrienstatic void
3124218822Sdims_arm_unwind_cantunwind (int ignored ATTRIBUTE_UNUSED)
312560484Sobrien{
3126218822Sdim  demand_empty_rest_of_line ();
3127218822Sdim  if (unwind.personality_routine || unwind.personality_index != -1)
3128218822Sdim    as_bad (_("personality routine specified for cantunwind frame"));
3129218822Sdim
3130218822Sdim  unwind.personality_index = -2;
313160484Sobrien}
313260484Sobrien
3133218822Sdim
3134218822Sdim/* Parse a personalityindex directive.	*/
3135218822Sdim
313660484Sobrienstatic void
3137218822Sdims_arm_unwind_personalityindex (int ignored ATTRIBUTE_UNUSED)
313860484Sobrien{
3139218822Sdim  expressionS exp;
314077298Sobrien
3141218822Sdim  if (unwind.personality_routine || unwind.personality_index != -1)
3142218822Sdim    as_bad (_("duplicate .personalityindex directive"));
314360484Sobrien
3144218822Sdim  expression (&exp);
314560484Sobrien
3146218822Sdim  if (exp.X_op != O_constant
3147218822Sdim      || exp.X_add_number < 0 || exp.X_add_number > 15)
314860484Sobrien    {
3149218822Sdim      as_bad (_("bad personality routine number"));
3150218822Sdim      ignore_rest_of_line ();
315160484Sobrien      return;
315260484Sobrien    }
315360484Sobrien
3154218822Sdim  unwind.personality_index = exp.X_add_number;
315561843Sobrien
3156218822Sdim  demand_empty_rest_of_line ();
3157218822Sdim}
315877298Sobrien
315961843Sobrien
3160218822Sdim/* Parse a personality directive.  */
316177298Sobrien
3162218822Sdimstatic void
3163218822Sdims_arm_unwind_personality (int ignored ATTRIBUTE_UNUSED)
3164218822Sdim{
3165218822Sdim  char *name, *p, c;
3166218822Sdim
3167218822Sdim  if (unwind.personality_routine || unwind.personality_index != -1)
3168218822Sdim    as_bad (_("duplicate .personality directive"));
3169218822Sdim
3170218822Sdim  name = input_line_pointer;
3171218822Sdim  c = get_symbol_end ();
3172218822Sdim  p = input_line_pointer;
3173218822Sdim  unwind.personality_routine = symbol_find_or_make (name);
3174218822Sdim  *p = c;
3175218822Sdim  demand_empty_rest_of_line ();
317660484Sobrien}
317760484Sobrien
317877298Sobrien
3179218822Sdim/* Parse a directive saving core registers.  */
3180218822Sdim
318160484Sobrienstatic void
3182218822Sdims_arm_unwind_save_core (void)
318360484Sobrien{
3184218822Sdim  valueT op;
3185218822Sdim  long range;
3186218822Sdim  int n;
318760484Sobrien
3188218822Sdim  range = parse_reg_list (&input_line_pointer);
3189218822Sdim  if (range == FAIL)
319061843Sobrien    {
3191218822Sdim      as_bad (_("expected register list"));
3192218822Sdim      ignore_rest_of_line ();
319361843Sobrien      return;
319461843Sobrien    }
319561843Sobrien
3196218822Sdim  demand_empty_rest_of_line ();
319760484Sobrien
3198218822Sdim  /* Turn .unwind_movsp ip followed by .unwind_save {..., ip, ...}
3199218822Sdim     into .unwind_save {..., sp...}.  We aren't bothered about the value of
3200218822Sdim     ip because it is clobbered by calls.  */
3201218822Sdim  if (unwind.sp_restored && unwind.fp_reg == 12
3202218822Sdim      && (range & 0x3000) == 0x1000)
320360484Sobrien    {
3204218822Sdim      unwind.opcode_count--;
3205218822Sdim      unwind.sp_restored = 0;
3206218822Sdim      range = (range | 0x2000) & ~0x1000;
3207218822Sdim      unwind.pending_offset = 0;
320861843Sobrien    }
320960484Sobrien
3210218822Sdim  /* Pop r4-r15.  */
3211218822Sdim  if (range & 0xfff0)
321261843Sobrien    {
3213218822Sdim      /* See if we can use the short opcodes.  These pop a block of up to 8
3214218822Sdim	 registers starting with r4, plus maybe r14.  */
3215218822Sdim      for (n = 0; n < 8; n++)
3216218822Sdim	{
3217218822Sdim	  /* Break at the first non-saved register.	 */
3218218822Sdim	  if ((range & (1 << (n + 4))) == 0)
3219218822Sdim	    break;
3220218822Sdim	}
3221218822Sdim      /* See if there are any other bits set.  */
3222218822Sdim      if (n == 0 || (range & (0xfff0 << n) & 0xbff0) != 0)
3223218822Sdim	{
3224218822Sdim	  /* Use the long form.  */
3225218822Sdim	  op = 0x8000 | ((range >> 4) & 0xfff);
3226218822Sdim	  add_unwind_opcode (op, 2);
3227218822Sdim	}
3228218822Sdim      else
3229218822Sdim	{
3230218822Sdim	  /* Use the short form.  */
3231218822Sdim	  if (range & 0x4000)
3232218822Sdim	    op = 0xa8; /* Pop r14.	*/
3233218822Sdim	  else
3234218822Sdim	    op = 0xa0; /* Do not pop r14.  */
3235218822Sdim	  op |= (n - 1);
3236218822Sdim	  add_unwind_opcode (op, 1);
3237218822Sdim	}
323860484Sobrien    }
323961843Sobrien
3240218822Sdim  /* Pop r0-r3.	 */
3241218822Sdim  if (range & 0xf)
324261843Sobrien    {
3243218822Sdim      op = 0xb100 | (range & 0xf);
3244218822Sdim      add_unwind_opcode (op, 2);
324561843Sobrien    }
324677298Sobrien
3247218822Sdim  /* Record the number of bytes pushed.	 */
3248218822Sdim  for (n = 0; n < 16; n++)
324961843Sobrien    {
3250218822Sdim      if (range & (1 << n))
3251218822Sdim	unwind.frame_size += 4;
325261843Sobrien    }
3253218822Sdim}
325477298Sobrien
325577298Sobrien
3256218822Sdim/* Parse a directive saving FPA registers.  */
325777298Sobrien
325860484Sobrienstatic void
3259218822Sdims_arm_unwind_save_fpa (int reg)
326060484Sobrien{
3261218822Sdim  expressionS exp;
3262218822Sdim  int num_regs;
3263218822Sdim  valueT op;
326460484Sobrien
3265218822Sdim  /* Get Number of registers to transfer.  */
3266218822Sdim  if (skip_past_comma (&input_line_pointer) != FAIL)
3267218822Sdim    expression (&exp);
3268218822Sdim  else
3269218822Sdim    exp.X_op = O_illegal;
327060484Sobrien
3271218822Sdim  if (exp.X_op != O_constant)
327260484Sobrien    {
3273218822Sdim      as_bad (_("expected , <constant>"));
3274218822Sdim      ignore_rest_of_line ();
327560484Sobrien      return;
327660484Sobrien    }
327760484Sobrien
3278218822Sdim  num_regs = exp.X_add_number;
327960484Sobrien
3280218822Sdim  if (num_regs < 1 || num_regs > 4)
328160484Sobrien    {
3282218822Sdim      as_bad (_("number of registers must be in the range [1:4]"));
3283218822Sdim      ignore_rest_of_line ();
328460484Sobrien      return;
328560484Sobrien    }
328660484Sobrien
3287218822Sdim  demand_empty_rest_of_line ();
328860484Sobrien
3289218822Sdim  if (reg == 4)
329060484Sobrien    {
3291218822Sdim      /* Short form.  */
3292218822Sdim      op = 0xb4 | (num_regs - 1);
3293218822Sdim      add_unwind_opcode (op, 1);
329460484Sobrien    }
3295218822Sdim  else
329660484Sobrien    {
3297218822Sdim      /* Long form.  */
3298218822Sdim      op = 0xc800 | (reg << 4) | (num_regs - 1);
3299218822Sdim      add_unwind_opcode (op, 2);
330060484Sobrien    }
3301218822Sdim  unwind.frame_size += num_regs * 12;
330260484Sobrien}
330360484Sobrien
3304218822Sdim
3305218822Sdim/* Parse a directive saving VFP registers for ARMv6 and above.  */
3306218822Sdim
330760484Sobrienstatic void
3308218822Sdims_arm_unwind_save_vfp_armv6 (void)
330960484Sobrien{
3310218822Sdim  int count;
3311218822Sdim  unsigned int start;
3312218822Sdim  valueT op;
3313218822Sdim  int num_vfpv3_regs = 0;
3314218822Sdim  int num_regs_below_16;
331577298Sobrien
3316218822Sdim  count = parse_vfp_reg_list (&input_line_pointer, &start, REGLIST_VFP_D);
3317218822Sdim  if (count == FAIL)
331860484Sobrien    {
3319218822Sdim      as_bad (_("expected register list"));
3320218822Sdim      ignore_rest_of_line ();
332160484Sobrien      return;
332260484Sobrien    }
332360484Sobrien
3324218822Sdim  demand_empty_rest_of_line ();
332560484Sobrien
3326218822Sdim  /* We always generate FSTMD/FLDMD-style unwinding opcodes (rather
3327218822Sdim     than FSTMX/FLDMX-style ones).  */
332860484Sobrien
3329218822Sdim  /* Generate opcode for (VFPv3) registers numbered in the range 16 .. 31.  */
3330218822Sdim  if (start >= 16)
3331218822Sdim    num_vfpv3_regs = count;
3332218822Sdim  else if (start + count > 16)
3333218822Sdim    num_vfpv3_regs = start + count - 16;
333460484Sobrien
3335218822Sdim  if (num_vfpv3_regs > 0)
333660484Sobrien    {
3337218822Sdim      int start_offset = start > 16 ? start - 16 : 0;
3338218822Sdim      op = 0xc800 | (start_offset << 4) | (num_vfpv3_regs - 1);
3339218822Sdim      add_unwind_opcode (op, 2);
334060484Sobrien    }
334160484Sobrien
3342218822Sdim  /* Generate opcode for registers numbered in the range 0 .. 15.  */
3343218822Sdim  num_regs_below_16 = num_vfpv3_regs > 0 ? 16 - (int) start : count;
3344218822Sdim  assert (num_regs_below_16 + num_vfpv3_regs == count);
3345218822Sdim  if (num_regs_below_16 > 0)
334660484Sobrien    {
3347218822Sdim      op = 0xc900 | (start << 4) | (num_regs_below_16 - 1);
3348218822Sdim      add_unwind_opcode (op, 2);
334960484Sobrien    }
335060484Sobrien
3351218822Sdim  unwind.frame_size += count * 8;
335260484Sobrien}
335360484Sobrien
3354218822Sdim
3355218822Sdim/* Parse a directive saving VFP registers for pre-ARMv6.  */
3356218822Sdim
335760484Sobrienstatic void
3358218822Sdims_arm_unwind_save_vfp (void)
335960484Sobrien{
3360218822Sdim  int count;
3361218822Sdim  unsigned int reg;
3362218822Sdim  valueT op;
336360484Sobrien
3364218822Sdim  count = parse_vfp_reg_list (&input_line_pointer, &reg, REGLIST_VFP_D);
3365218822Sdim  if (count == FAIL)
336660484Sobrien    {
3367218822Sdim      as_bad (_("expected register list"));
3368218822Sdim      ignore_rest_of_line ();
336960484Sobrien      return;
337060484Sobrien    }
337160484Sobrien
3372218822Sdim  demand_empty_rest_of_line ();
337360484Sobrien
3374218822Sdim  if (reg == 8)
337560484Sobrien    {
3376218822Sdim      /* Short form.  */
3377218822Sdim      op = 0xb8 | (count - 1);
3378218822Sdim      add_unwind_opcode (op, 1);
337960484Sobrien    }
3380218822Sdim  else
338160484Sobrien    {
3382218822Sdim      /* Long form.  */
3383218822Sdim      op = 0xb300 | (reg << 4) | (count - 1);
3384218822Sdim      add_unwind_opcode (op, 2);
338560484Sobrien    }
3386218822Sdim  unwind.frame_size += count * 8 + 4;
338760484Sobrien}
338860484Sobrien
338977298Sobrien
3390218822Sdim/* Parse a directive saving iWMMXt data registers.  */
339177298Sobrien
3392218822Sdimstatic void
3393218822Sdims_arm_unwind_save_mmxwr (void)
339477298Sobrien{
3395218822Sdim  int reg;
3396218822Sdim  int hi_reg;
3397218822Sdim  int i;
3398218822Sdim  unsigned mask = 0;
3399218822Sdim  valueT op;
340077298Sobrien
3401218822Sdim  if (*input_line_pointer == '{')
3402218822Sdim    input_line_pointer++;
340377298Sobrien
3404218822Sdim  do
3405218822Sdim    {
3406218822Sdim      reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWR);
340777298Sobrien
3408218822Sdim      if (reg == FAIL)
3409218822Sdim	{
3410218822Sdim	  as_bad (_(reg_expected_msgs[REG_TYPE_MMXWR]));
3411218822Sdim	  goto error;
3412218822Sdim	}
341377298Sobrien
3414218822Sdim      if (mask >> reg)
3415218822Sdim	as_tsktsk (_("register list not in ascending order"));
3416218822Sdim      mask |= 1 << reg;
3417218822Sdim
3418218822Sdim      if (*input_line_pointer == '-')
3419218822Sdim	{
3420218822Sdim	  input_line_pointer++;
3421218822Sdim	  hi_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWR);
3422218822Sdim	  if (hi_reg == FAIL)
3423218822Sdim	    {
3424218822Sdim	      as_bad (_(reg_expected_msgs[REG_TYPE_MMXWR]));
3425218822Sdim	      goto error;
3426218822Sdim	    }
3427218822Sdim	  else if (reg >= hi_reg)
3428218822Sdim	    {
3429218822Sdim	      as_bad (_("bad register range"));
3430218822Sdim	      goto error;
3431218822Sdim	    }
3432218822Sdim	  for (; reg < hi_reg; reg++)
3433218822Sdim	    mask |= 1 << reg;
3434218822Sdim	}
343577298Sobrien    }
3436218822Sdim  while (skip_past_comma (&input_line_pointer) != FAIL);
343777298Sobrien
3438218822Sdim  if (*input_line_pointer == '}')
3439218822Sdim    input_line_pointer++;
344077298Sobrien
3441218822Sdim  demand_empty_rest_of_line ();
344277298Sobrien
3443218822Sdim  /* Generate any deferred opcodes because we're going to be looking at
3444218822Sdim     the list.	*/
3445218822Sdim  flush_pending_unwind ();
344677298Sobrien
3447218822Sdim  for (i = 0; i < 16; i++)
3448218822Sdim    {
3449218822Sdim      if (mask & (1 << i))
3450218822Sdim	unwind.frame_size += 8;
3451218822Sdim    }
345277298Sobrien
3453218822Sdim  /* Attempt to combine with a previous opcode.	 We do this because gcc
3454218822Sdim     likes to output separate unwind directives for a single block of
3455218822Sdim     registers.	 */
3456218822Sdim  if (unwind.opcode_count > 0)
345777298Sobrien    {
3458218822Sdim      i = unwind.opcodes[unwind.opcode_count - 1];
3459218822Sdim      if ((i & 0xf8) == 0xc0)
346077298Sobrien	{
3461218822Sdim	  i &= 7;
3462218822Sdim	  /* Only merge if the blocks are contiguous.  */
3463218822Sdim	  if (i < 6)
346477298Sobrien	    {
3465218822Sdim	      if ((mask & 0xfe00) == (1 << 9))
3466218822Sdim		{
3467218822Sdim		  mask |= ((1 << (i + 11)) - 1) & 0xfc00;
3468218822Sdim		  unwind.opcode_count--;
3469218822Sdim		}
347077298Sobrien	    }
3471218822Sdim	  else if (i == 6 && unwind.opcode_count >= 2)
347277298Sobrien	    {
3473218822Sdim	      i = unwind.opcodes[unwind.opcode_count - 2];
3474218822Sdim	      reg = i >> 4;
3475218822Sdim	      i &= 0xf;
347677298Sobrien
3477218822Sdim	      op = 0xffff << (reg - 1);
3478218822Sdim	      if (reg > 0
3479218822Sdim		  && ((mask & op) == (1u << (reg - 1))))
3480104834Sobrien		{
3481218822Sdim		  op = (1 << (reg + i + 1)) - 1;
3482218822Sdim		  op &= ~((1 << reg) - 1);
3483218822Sdim		  mask |= op;
3484218822Sdim		  unwind.opcode_count -= 2;
3485104834Sobrien		}
348677298Sobrien	    }
348777298Sobrien	}
3488218822Sdim    }
3489218822Sdim
3490218822Sdim  hi_reg = 15;
3491218822Sdim  /* We want to generate opcodes in the order the registers have been
3492218822Sdim     saved, ie. descending order.  */
3493218822Sdim  for (reg = 15; reg >= -1; reg--)
3494218822Sdim    {
3495218822Sdim      /* Save registers in blocks.  */
3496218822Sdim      if (reg < 0
3497218822Sdim	  || !(mask & (1 << reg)))
349877298Sobrien	{
3499218822Sdim	  /* We found an unsaved reg.  Generate opcodes to save the
3500218822Sdim	     preceeding block.	*/
3501218822Sdim	  if (reg != hi_reg)
350277298Sobrien	    {
3503218822Sdim	      if (reg == 9)
3504218822Sdim		{
3505218822Sdim		  /* Short form.  */
3506218822Sdim		  op = 0xc0 | (hi_reg - 10);
3507218822Sdim		  add_unwind_opcode (op, 1);
3508218822Sdim		}
3509218822Sdim	      else
3510218822Sdim		{
3511218822Sdim		  /* Long form.	 */
3512218822Sdim		  op = 0xc600 | ((reg + 1) << 4) | ((hi_reg - reg) - 1);
3513218822Sdim		  add_unwind_opcode (op, 2);
3514218822Sdim		}
351577298Sobrien	    }
3516218822Sdim	  hi_reg = reg - 1;
3517218822Sdim	}
3518218822Sdim    }
351977298Sobrien
3520218822Sdim  return;
3521218822Sdimerror:
3522218822Sdim  ignore_rest_of_line ();
3523218822Sdim}
352477298Sobrien
3525218822Sdimstatic void
3526218822Sdims_arm_unwind_save_mmxwcg (void)
3527218822Sdim{
3528218822Sdim  int reg;
3529218822Sdim  int hi_reg;
3530218822Sdim  unsigned mask = 0;
3531218822Sdim  valueT op;
353277298Sobrien
3533218822Sdim  if (*input_line_pointer == '{')
3534218822Sdim    input_line_pointer++;
353577298Sobrien
3536218822Sdim  do
3537218822Sdim    {
3538218822Sdim      reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWCG);
353977298Sobrien
3540218822Sdim      if (reg == FAIL)
3541218822Sdim	{
3542218822Sdim	  as_bad (_(reg_expected_msgs[REG_TYPE_MMXWCG]));
3543218822Sdim	  goto error;
3544218822Sdim	}
354577298Sobrien
3546218822Sdim      reg -= 8;
3547218822Sdim      if (mask >> reg)
3548218822Sdim	as_tsktsk (_("register list not in ascending order"));
3549218822Sdim      mask |= 1 << reg;
3550218822Sdim
3551218822Sdim      if (*input_line_pointer == '-')
3552218822Sdim	{
3553218822Sdim	  input_line_pointer++;
3554218822Sdim	  hi_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWCG);
3555218822Sdim	  if (hi_reg == FAIL)
355677298Sobrien	    {
3557218822Sdim	      as_bad (_(reg_expected_msgs[REG_TYPE_MMXWCG]));
3558218822Sdim	      goto error;
355977298Sobrien	    }
3560218822Sdim	  else if (reg >= hi_reg)
3561218822Sdim	    {
3562218822Sdim	      as_bad (_("bad register range"));
3563218822Sdim	      goto error;
3564218822Sdim	    }
3565218822Sdim	  for (; reg < hi_reg; reg++)
3566218822Sdim	    mask |= 1 << reg;
356777298Sobrien	}
356877298Sobrien    }
3569218822Sdim  while (skip_past_comma (&input_line_pointer) != FAIL);
357077298Sobrien
3571218822Sdim  if (*input_line_pointer == '}')
3572218822Sdim    input_line_pointer++;
357377298Sobrien
3574218822Sdim  demand_empty_rest_of_line ();
357577298Sobrien
3576218822Sdim  /* Generate any deferred opcodes because we're going to be looking at
3577218822Sdim     the list.	*/
3578218822Sdim  flush_pending_unwind ();
357977298Sobrien
3580218822Sdim  for (reg = 0; reg < 16; reg++)
3581218822Sdim    {
3582218822Sdim      if (mask & (1 << reg))
3583218822Sdim	unwind.frame_size += 4;
3584218822Sdim    }
3585218822Sdim  op = 0xc700 | mask;
3586218822Sdim  add_unwind_opcode (op, 2);
3587218822Sdim  return;
3588218822Sdimerror:
3589218822Sdim  ignore_rest_of_line ();
359077298Sobrien}
359177298Sobrien
359277298Sobrien
3593218822Sdim/* Parse an unwind_save directive.
3594218822Sdim   If the argument is non-zero, this is a .vsave directive.  */
3595218822Sdim
359677298Sobrienstatic void
3597218822Sdims_arm_unwind_save (int arch_v6)
359877298Sobrien{
3599218822Sdim  char *peek;
3600218822Sdim  struct reg_entry *reg;
3601218822Sdim  bfd_boolean had_brace = FALSE;
360277298Sobrien
3603218822Sdim  /* Figure out what sort of save we have.  */
3604218822Sdim  peek = input_line_pointer;
360577298Sobrien
3606218822Sdim  if (*peek == '{')
3607218822Sdim    {
3608218822Sdim      had_brace = TRUE;
3609218822Sdim      peek++;
3610218822Sdim    }
361177298Sobrien
3612218822Sdim  reg = arm_reg_parse_multi (&peek);
361377298Sobrien
3614218822Sdim  if (!reg)
3615218822Sdim    {
3616218822Sdim      as_bad (_("register expected"));
3617218822Sdim      ignore_rest_of_line ();
3618218822Sdim      return;
3619218822Sdim    }
3620218822Sdim
3621218822Sdim  switch (reg->type)
3622218822Sdim    {
3623218822Sdim    case REG_TYPE_FN:
3624218822Sdim      if (had_brace)
3625218822Sdim	{
3626218822Sdim	  as_bad (_("FPA .unwind_save does not take a register list"));
3627218822Sdim	  ignore_rest_of_line ();
3628218822Sdim	  return;
3629218822Sdim	}
3630218822Sdim      s_arm_unwind_save_fpa (reg->number);
3631218822Sdim      return;
3632218822Sdim
3633218822Sdim    case REG_TYPE_RN:	  s_arm_unwind_save_core ();   return;
3634218822Sdim    case REG_TYPE_VFD:
3635218822Sdim      if (arch_v6)
3636218822Sdim        s_arm_unwind_save_vfp_armv6 ();
3637218822Sdim      else
3638218822Sdim        s_arm_unwind_save_vfp ();
3639218822Sdim      return;
3640218822Sdim    case REG_TYPE_MMXWR:  s_arm_unwind_save_mmxwr ();  return;
3641218822Sdim    case REG_TYPE_MMXWCG: s_arm_unwind_save_mmxwcg (); return;
3642218822Sdim
3643218822Sdim    default:
3644218822Sdim      as_bad (_(".unwind_save does not support this kind of register"));
3645218822Sdim      ignore_rest_of_line ();
3646218822Sdim    }
364777298Sobrien}
364877298Sobrien
364977298Sobrien
3650218822Sdim/* Parse an unwind_movsp directive.  */
3651218822Sdim
365277298Sobrienstatic void
3653218822Sdims_arm_unwind_movsp (int ignored ATTRIBUTE_UNUSED)
365477298Sobrien{
3655218822Sdim  int reg;
3656218822Sdim  valueT op;
3657218822Sdim  int offset;
365877298Sobrien
3659218822Sdim  reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN);
3660218822Sdim  if (reg == FAIL)
366177298Sobrien    {
3662218822Sdim      as_bad (_(reg_expected_msgs[REG_TYPE_RN]));
3663218822Sdim      ignore_rest_of_line ();
366477298Sobrien      return;
366577298Sobrien    }
366677298Sobrien
3667218822Sdim  /* Optional constant.	 */
3668218822Sdim  if (skip_past_comma (&input_line_pointer) != FAIL)
366977298Sobrien    {
3670218822Sdim      if (immediate_for_directive (&offset) == FAIL)
3671218822Sdim	return;
3672218822Sdim    }
3673218822Sdim  else
3674218822Sdim    offset = 0;
3675218822Sdim
3676218822Sdim  demand_empty_rest_of_line ();
3677218822Sdim
3678218822Sdim  if (reg == REG_SP || reg == REG_PC)
3679218822Sdim    {
3680218822Sdim      as_bad (_("SP and PC not permitted in .unwind_movsp directive"));
368177298Sobrien      return;
368277298Sobrien    }
368377298Sobrien
3684218822Sdim  if (unwind.fp_reg != REG_SP)
3685218822Sdim    as_bad (_("unexpected .unwind_movsp directive"));
368677298Sobrien
3687218822Sdim  /* Generate opcode to restore the value.  */
3688218822Sdim  op = 0x90 | reg;
3689218822Sdim  add_unwind_opcode (op, 1);
3690218822Sdim
3691218822Sdim  /* Record the information for later.	*/
3692218822Sdim  unwind.fp_reg = reg;
3693218822Sdim  unwind.fp_offset = unwind.frame_size - offset;
3694218822Sdim  unwind.sp_restored = 1;
369577298Sobrien}
369677298Sobrien
3697218822Sdim/* Parse an unwind_pad directive.  */
369877298Sobrien
369977298Sobrienstatic void
3700218822Sdims_arm_unwind_pad (int ignored ATTRIBUTE_UNUSED)
370177298Sobrien{
3702218822Sdim  int offset;
370377298Sobrien
3704218822Sdim  if (immediate_for_directive (&offset) == FAIL)
3705218822Sdim    return;
370677298Sobrien
3707218822Sdim  if (offset & 3)
3708218822Sdim    {
3709218822Sdim      as_bad (_("stack increment must be multiple of 4"));
3710218822Sdim      ignore_rest_of_line ();
3711218822Sdim      return;
3712218822Sdim    }
371377298Sobrien
3714218822Sdim  /* Don't generate any opcodes, just record the details for later.  */
3715218822Sdim  unwind.frame_size += offset;
3716218822Sdim  unwind.pending_offset += offset;
371777298Sobrien
3718218822Sdim  demand_empty_rest_of_line ();
371977298Sobrien}
372077298Sobrien
3721218822Sdim/* Parse an unwind_setfp directive.  */
372277298Sobrien
372377298Sobrienstatic void
3724218822Sdims_arm_unwind_setfp (int ignored ATTRIBUTE_UNUSED)
372577298Sobrien{
3726218822Sdim  int sp_reg;
3727218822Sdim  int fp_reg;
3728218822Sdim  int offset;
372977298Sobrien
3730218822Sdim  fp_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN);
3731218822Sdim  if (skip_past_comma (&input_line_pointer) == FAIL)
3732218822Sdim    sp_reg = FAIL;
3733218822Sdim  else
3734218822Sdim    sp_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN);
373577298Sobrien
3736218822Sdim  if (fp_reg == FAIL || sp_reg == FAIL)
3737218822Sdim    {
3738218822Sdim      as_bad (_("expected <reg>, <reg>"));
3739218822Sdim      ignore_rest_of_line ();
3740218822Sdim      return;
3741218822Sdim    }
374277298Sobrien
3743218822Sdim  /* Optional constant.	 */
3744218822Sdim  if (skip_past_comma (&input_line_pointer) != FAIL)
3745218822Sdim    {
3746218822Sdim      if (immediate_for_directive (&offset) == FAIL)
3747218822Sdim	return;
3748218822Sdim    }
3749218822Sdim  else
3750218822Sdim    offset = 0;
375177298Sobrien
3752218822Sdim  demand_empty_rest_of_line ();
3753218822Sdim
3754218822Sdim  if (sp_reg != 13 && sp_reg != unwind.fp_reg)
3755218822Sdim    {
3756218822Sdim      as_bad (_("register must be either sp or set by a previous"
3757218822Sdim		"unwind_movsp directive"));
3758218822Sdim      return;
3759218822Sdim    }
3760218822Sdim
3761218822Sdim  /* Don't generate any opcodes, just record the information for later.	 */
3762218822Sdim  unwind.fp_reg = fp_reg;
3763218822Sdim  unwind.fp_used = 1;
3764218822Sdim  if (sp_reg == 13)
3765218822Sdim    unwind.fp_offset = unwind.frame_size - offset;
376677298Sobrien  else
3767218822Sdim    unwind.fp_offset -= offset;
376877298Sobrien}
376977298Sobrien
3770218822Sdim/* Parse an unwind_raw directive.  */
377177298Sobrien
377277298Sobrienstatic void
3773218822Sdims_arm_unwind_raw (int ignored ATTRIBUTE_UNUSED)
377477298Sobrien{
3775218822Sdim  expressionS exp;
3776218822Sdim  /* This is an arbitrary limit.	 */
3777218822Sdim  unsigned char op[16];
3778218822Sdim  int count;
377977298Sobrien
3780218822Sdim  expression (&exp);
3781218822Sdim  if (exp.X_op == O_constant
3782218822Sdim      && skip_past_comma (&input_line_pointer) != FAIL)
378377298Sobrien    {
3784218822Sdim      unwind.frame_size += exp.X_add_number;
3785218822Sdim      expression (&exp);
378677298Sobrien    }
3787218822Sdim  else
3788218822Sdim    exp.X_op = O_illegal;
378977298Sobrien
3790218822Sdim  if (exp.X_op != O_constant)
379177298Sobrien    {
3792218822Sdim      as_bad (_("expected <offset>, <opcode>"));
3793218822Sdim      ignore_rest_of_line ();
379477298Sobrien      return;
379577298Sobrien    }
379677298Sobrien
3797218822Sdim  count = 0;
379877298Sobrien
3799218822Sdim  /* Parse the opcode.	*/
3800218822Sdim  for (;;)
380177298Sobrien    {
3802218822Sdim      if (count >= 16)
3803218822Sdim	{
3804218822Sdim	  as_bad (_("unwind opcode too long"));
3805218822Sdim	  ignore_rest_of_line ();
3806218822Sdim	}
3807218822Sdim      if (exp.X_op != O_constant || exp.X_add_number & ~0xff)
3808218822Sdim	{
3809218822Sdim	  as_bad (_("invalid unwind opcode"));
3810218822Sdim	  ignore_rest_of_line ();
3811218822Sdim	  return;
3812218822Sdim	}
3813218822Sdim      op[count++] = exp.X_add_number;
381477298Sobrien
3815218822Sdim      /* Parse the next byte.  */
3816218822Sdim      if (skip_past_comma (&input_line_pointer) == FAIL)
3817218822Sdim	break;
381877298Sobrien
3819218822Sdim      expression (&exp);
382077298Sobrien    }
382177298Sobrien
3822218822Sdim  /* Add the opcode bytes in reverse order.  */
3823218822Sdim  while (count--)
3824218822Sdim    add_unwind_opcode (op[count], 1);
3825218822Sdim
3826218822Sdim  demand_empty_rest_of_line ();
382777298Sobrien}
382877298Sobrien
382977298Sobrien
3830218822Sdim/* Parse a .eabi_attribute directive.  */
3831218822Sdim
383277298Sobrienstatic void
3833218822Sdims_arm_eabi_attribute (int ignored ATTRIBUTE_UNUSED)
383477298Sobrien{
3835218822Sdim  s_vendor_attribute (OBJ_ATTR_PROC);
3836218822Sdim}
3837218822Sdim#endif /* OBJ_ELF */
383877298Sobrien
3839218822Sdimstatic void s_arm_arch (int);
3840218822Sdimstatic void s_arm_object_arch (int);
3841218822Sdimstatic void s_arm_cpu (int);
3842218822Sdimstatic void s_arm_fpu (int);
384377298Sobrien
3844218822Sdim#ifdef TE_PE
384577298Sobrien
3846218822Sdimstatic void
3847218822Sdimpe_directive_secrel (int dummy ATTRIBUTE_UNUSED)
3848218822Sdim{
3849218822Sdim  expressionS exp;
385077298Sobrien
3851218822Sdim  do
3852218822Sdim    {
3853218822Sdim      expression (&exp);
3854218822Sdim      if (exp.X_op == O_symbol)
3855218822Sdim	exp.X_op = O_secrel;
3856218822Sdim
3857218822Sdim      emit_expr (&exp, 4);
3858218822Sdim    }
3859218822Sdim  while (*input_line_pointer++ == ',');
3860218822Sdim
3861218822Sdim  input_line_pointer--;
3862218822Sdim  demand_empty_rest_of_line ();
386377298Sobrien}
3864218822Sdim#endif /* TE_PE */
386577298Sobrien
3866218822Sdim/* This table describes all the machine specific pseudo-ops the assembler
3867218822Sdim   has to support.  The fields are:
3868218822Sdim     pseudo-op name without dot
3869218822Sdim     function to call to execute this pseudo-op
3870218822Sdim     Integer arg to pass to the function.  */
387177298Sobrien
3872218822Sdimconst pseudo_typeS md_pseudo_table[] =
387377298Sobrien{
3874218822Sdim  /* Never called because '.req' does not start a line.	 */
3875218822Sdim  { "req",	   s_req,	  0 },
3876218822Sdim  /* Following two are likewise never called.  */
3877218822Sdim  { "dn",	   s_dn,          0 },
3878218822Sdim  { "qn",          s_qn,          0 },
3879218822Sdim  { "unreq",	   s_unreq,	  0 },
3880218822Sdim  { "bss",	   s_bss,	  0 },
3881218822Sdim  { "align",	   s_align,	  0 },
3882218822Sdim  { "arm",	   s_arm,	  0 },
3883218822Sdim  { "thumb",	   s_thumb,	  0 },
3884218822Sdim  { "code",	   s_code,	  0 },
3885218822Sdim  { "force_thumb", s_force_thumb, 0 },
3886218822Sdim  { "thumb_func",  s_thumb_func,  0 },
3887218822Sdim  { "thumb_set",   s_thumb_set,	  0 },
3888218822Sdim  { "even",	   s_even,	  0 },
3889218822Sdim  { "ltorg",	   s_ltorg,	  0 },
3890218822Sdim  { "pool",	   s_ltorg,	  0 },
3891218822Sdim  { "syntax",	   s_syntax,	  0 },
3892218822Sdim  { "cpu",	   s_arm_cpu,	  0 },
3893218822Sdim  { "arch",	   s_arm_arch,	  0 },
3894218822Sdim  { "object_arch", s_arm_object_arch,	0 },
3895218822Sdim  { "fpu",	   s_arm_fpu,	  0 },
3896218822Sdim#ifdef OBJ_ELF
3897218822Sdim  { "word",	   s_arm_elf_cons, 4 },
3898218822Sdim  { "long",	   s_arm_elf_cons, 4 },
3899218822Sdim  { "rel31",	   s_arm_rel31,	  0 },
3900218822Sdim  { "fnstart",		s_arm_unwind_fnstart,	0 },
3901218822Sdim  { "fnend",		s_arm_unwind_fnend,	0 },
3902218822Sdim  { "cantunwind",	s_arm_unwind_cantunwind, 0 },
3903218822Sdim  { "personality",	s_arm_unwind_personality, 0 },
3904218822Sdim  { "personalityindex",	s_arm_unwind_personalityindex, 0 },
3905218822Sdim  { "handlerdata",	s_arm_unwind_handlerdata, 0 },
3906218822Sdim  { "save",		s_arm_unwind_save,	0 },
3907218822Sdim  { "vsave",		s_arm_unwind_save,	1 },
3908218822Sdim  { "movsp",		s_arm_unwind_movsp,	0 },
3909218822Sdim  { "pad",		s_arm_unwind_pad,	0 },
3910218822Sdim  { "setfp",		s_arm_unwind_setfp,	0 },
3911218822Sdim  { "unwind_raw",	s_arm_unwind_raw,	0 },
3912218822Sdim  { "eabi_attribute",	s_arm_eabi_attribute,	0 },
3913218822Sdim#else
3914218822Sdim  { "word",	   cons, 4},
391577298Sobrien
3916218822Sdim  /* These are used for dwarf.  */
3917218822Sdim  {"2byte", cons, 2},
3918218822Sdim  {"4byte", cons, 4},
3919218822Sdim  {"8byte", cons, 8},
3920218822Sdim  /* These are used for dwarf2.  */
3921218822Sdim  { "file", (void (*) (int)) dwarf2_directive_file, 0 },
3922218822Sdim  { "loc",  dwarf2_directive_loc,  0 },
3923218822Sdim  { "loc_mark_labels", dwarf2_directive_loc_mark_labels, 0 },
3924218822Sdim#endif
3925218822Sdim  { "extend",	   float_cons, 'x' },
3926218822Sdim  { "ldouble",	   float_cons, 'x' },
3927218822Sdim  { "packed",	   float_cons, 'p' },
3928218822Sdim#ifdef TE_PE
3929218822Sdim  {"secrel32", pe_directive_secrel, 0},
3930218822Sdim#endif
3931218822Sdim  { 0, 0, 0 }
3932218822Sdim};
3933218822Sdim
3934218822Sdim/* Parser functions used exclusively in instruction operands.  */
3935218822Sdim
3936218822Sdim/* Generic immediate-value read function for use in insn parsing.
3937218822Sdim   STR points to the beginning of the immediate (the leading #);
3938218822Sdim   VAL receives the value; if the value is outside [MIN, MAX]
3939218822Sdim   issue an error.  PREFIX_OPT is true if the immediate prefix is
3940218822Sdim   optional.  */
3941218822Sdim
3942218822Sdimstatic int
3943218822Sdimparse_immediate (char **str, int *val, int min, int max,
3944218822Sdim		 bfd_boolean prefix_opt)
3945218822Sdim{
3946218822Sdim  expressionS exp;
3947218822Sdim  my_get_expression (&exp, str, prefix_opt ? GE_OPT_PREFIX : GE_IMM_PREFIX);
3948218822Sdim  if (exp.X_op != O_constant)
394977298Sobrien    {
3950218822Sdim      inst.error = _("constant expression required");
3951218822Sdim      return FAIL;
395277298Sobrien    }
3953218822Sdim
3954218822Sdim  if (exp.X_add_number < min || exp.X_add_number > max)
395577298Sobrien    {
3956218822Sdim      inst.error = _("immediate value out of range");
3957218822Sdim      return FAIL;
395877298Sobrien    }
3959218822Sdim
3960218822Sdim  *val = exp.X_add_number;
3961218822Sdim  return SUCCESS;
3962218822Sdim}
3963218822Sdim
3964218822Sdim/* Less-generic immediate-value read function with the possibility of loading a
3965218822Sdim   big (64-bit) immediate, as required by Neon VMOV, VMVN and logic immediate
3966218822Sdim   instructions. Puts the result directly in inst.operands[i].  */
3967218822Sdim
3968218822Sdimstatic int
3969218822Sdimparse_big_immediate (char **str, int i)
3970218822Sdim{
3971218822Sdim  expressionS exp;
3972218822Sdim  char *ptr = *str;
3973218822Sdim
3974218822Sdim  my_get_expression (&exp, &ptr, GE_OPT_PREFIX_BIG);
3975218822Sdim
3976218822Sdim  if (exp.X_op == O_constant)
397777298Sobrien    {
3978218822Sdim      inst.operands[i].imm = exp.X_add_number & 0xffffffff;
3979218822Sdim      /* If we're on a 64-bit host, then a 64-bit number can be returned using
3980218822Sdim	 O_constant.  We have to be careful not to break compilation for
3981218822Sdim	 32-bit X_add_number, though.  */
3982218822Sdim      if ((exp.X_add_number & ~0xffffffffl) != 0)
3983218822Sdim	{
3984218822Sdim          /* X >> 32 is illegal if sizeof (exp.X_add_number) == 4.  */
3985218822Sdim	  inst.operands[i].reg = ((exp.X_add_number >> 16) >> 16) & 0xffffffff;
3986218822Sdim	  inst.operands[i].regisimm = 1;
3987218822Sdim	}
398877298Sobrien    }
3989218822Sdim  else if (exp.X_op == O_big
3990218822Sdim           && LITTLENUM_NUMBER_OF_BITS * exp.X_add_number > 32
3991218822Sdim           && LITTLENUM_NUMBER_OF_BITS * exp.X_add_number <= 64)
3992218822Sdim    {
3993218822Sdim      unsigned parts = 32 / LITTLENUM_NUMBER_OF_BITS, j, idx = 0;
3994218822Sdim      /* Bignums have their least significant bits in
3995218822Sdim         generic_bignum[0]. Make sure we put 32 bits in imm and
3996218822Sdim         32 bits in reg,  in a (hopefully) portable way.  */
3997218822Sdim      assert (parts != 0);
3998218822Sdim      inst.operands[i].imm = 0;
3999218822Sdim      for (j = 0; j < parts; j++, idx++)
4000218822Sdim        inst.operands[i].imm |= generic_bignum[idx]
4001218822Sdim                                << (LITTLENUM_NUMBER_OF_BITS * j);
4002218822Sdim      inst.operands[i].reg = 0;
4003218822Sdim      for (j = 0; j < parts; j++, idx++)
4004218822Sdim        inst.operands[i].reg |= generic_bignum[idx]
4005218822Sdim                                << (LITTLENUM_NUMBER_OF_BITS * j);
4006218822Sdim      inst.operands[i].regisimm = 1;
4007218822Sdim    }
400877298Sobrien  else
4009218822Sdim    return FAIL;
4010218822Sdim
4011218822Sdim  *str = ptr;
4012218822Sdim
4013218822Sdim  return SUCCESS;
401477298Sobrien}
401577298Sobrien
4016218822Sdim/* Returns the pseudo-register number of an FPA immediate constant,
4017218822Sdim   or FAIL if there isn't a valid constant here.  */
401877298Sobrien
4019218822Sdimstatic int
4020218822Sdimparse_fpa_immediate (char ** str)
402177298Sobrien{
4022218822Sdim  LITTLENUM_TYPE words[MAX_LITTLENUMS];
4023218822Sdim  char *	 save_in;
4024218822Sdim  expressionS	 exp;
4025218822Sdim  int		 i;
4026218822Sdim  int		 j;
402777298Sobrien
4028218822Sdim  /* First try and match exact strings, this is to guarantee
4029218822Sdim     that some formats will work even for cross assembly.  */
403077298Sobrien
4031218822Sdim  for (i = 0; fp_const[i]; i++)
403277298Sobrien    {
4033218822Sdim      if (strncmp (*str, fp_const[i], strlen (fp_const[i])) == 0)
4034218822Sdim	{
4035218822Sdim	  char *start = *str;
403677298Sobrien
4037218822Sdim	  *str += strlen (fp_const[i]);
4038218822Sdim	  if (is_end_of_line[(unsigned char) **str])
4039218822Sdim	    return i + 8;
4040218822Sdim	  *str = start;
4041218822Sdim	}
404277298Sobrien    }
404377298Sobrien
4044218822Sdim  /* Just because we didn't get a match doesn't mean that the constant
4045218822Sdim     isn't valid, just that it is in a format that we don't
4046218822Sdim     automatically recognize.  Try parsing it with the standard
4047218822Sdim     expression routines.  */
4048218822Sdim
4049218822Sdim  memset (words, 0, MAX_LITTLENUMS * sizeof (LITTLENUM_TYPE));
4050218822Sdim
4051218822Sdim  /* Look for a raw floating point number.  */
4052218822Sdim  if ((save_in = atof_ieee (*str, 'x', words)) != NULL
4053218822Sdim      && is_end_of_line[(unsigned char) *save_in])
405477298Sobrien    {
4055218822Sdim      for (i = 0; i < NUM_FLOAT_VALS; i++)
4056218822Sdim	{
4057218822Sdim	  for (j = 0; j < MAX_LITTLENUMS; j++)
4058218822Sdim	    {
4059218822Sdim	      if (words[j] != fp_values[i][j])
4060218822Sdim		break;
4061218822Sdim	    }
406277298Sobrien
4063218822Sdim	  if (j == MAX_LITTLENUMS)
4064218822Sdim	    {
4065218822Sdim	      *str = save_in;
4066218822Sdim	      return i + 8;
4067218822Sdim	    }
4068218822Sdim	}
406977298Sobrien    }
407077298Sobrien
4071218822Sdim  /* Try and parse a more complex expression, this will probably fail
4072218822Sdim     unless the code uses a floating point prefix (eg "0f").  */
4073218822Sdim  save_in = input_line_pointer;
4074218822Sdim  input_line_pointer = *str;
4075218822Sdim  if (expression (&exp) == absolute_section
4076218822Sdim      && exp.X_op == O_big
4077218822Sdim      && exp.X_add_number < 0)
407877298Sobrien    {
4079218822Sdim      /* FIXME: 5 = X_PRECISION, should be #define'd where we can use it.
4080218822Sdim	 Ditto for 15.	*/
4081218822Sdim      if (gen_to_words (words, 5, (long) 15) == 0)
408277298Sobrien	{
4083218822Sdim	  for (i = 0; i < NUM_FLOAT_VALS; i++)
4084218822Sdim	    {
4085218822Sdim	      for (j = 0; j < MAX_LITTLENUMS; j++)
4086218822Sdim		{
4087218822Sdim		  if (words[j] != fp_values[i][j])
4088218822Sdim		    break;
4089218822Sdim		}
4090218822Sdim
4091218822Sdim	      if (j == MAX_LITTLENUMS)
4092218822Sdim		{
4093218822Sdim		  *str = input_line_pointer;
4094218822Sdim		  input_line_pointer = save_in;
4095218822Sdim		  return i + 8;
4096218822Sdim		}
4097218822Sdim	    }
409877298Sobrien	}
409977298Sobrien    }
410077298Sobrien
4101218822Sdim  *str = input_line_pointer;
4102218822Sdim  input_line_pointer = save_in;
4103218822Sdim  inst.error = _("invalid FPA immediate expression");
4104218822Sdim  return FAIL;
410577298Sobrien}
410677298Sobrien
4107218822Sdim/* Returns 1 if a number has "quarter-precision" float format
4108218822Sdim   0baBbbbbbc defgh000 00000000 00000000.  */
410977298Sobrien
4110218822Sdimstatic int
4111218822Sdimis_quarter_float (unsigned imm)
411277298Sobrien{
4113218822Sdim  int bs = (imm & 0x20000000) ? 0x3e000000 : 0x40000000;
4114218822Sdim  return (imm & 0x7ffff) == 0 && ((imm & 0x7e000000) ^ bs) == 0;
4115218822Sdim}
411677298Sobrien
4117218822Sdim/* Parse an 8-bit "quarter-precision" floating point number of the form:
4118218822Sdim   0baBbbbbbc defgh000 00000000 00000000.
4119218822Sdim   The zero and minus-zero cases need special handling, since they can't be
4120218822Sdim   encoded in the "quarter-precision" float format, but can nonetheless be
4121218822Sdim   loaded as integer constants.  */
4122218822Sdim
4123218822Sdimstatic unsigned
4124218822Sdimparse_qfloat_immediate (char **ccp, int *immed)
4125218822Sdim{
4126218822Sdim  char *str = *ccp;
4127218822Sdim  char *fpnum;
4128218822Sdim  LITTLENUM_TYPE words[MAX_LITTLENUMS];
4129218822Sdim  int found_fpchar = 0;
4130218822Sdim
4131218822Sdim  skip_past_char (&str, '#');
4132218822Sdim
4133218822Sdim  /* We must not accidentally parse an integer as a floating-point number. Make
4134218822Sdim     sure that the value we parse is not an integer by checking for special
4135218822Sdim     characters '.' or 'e'.
4136218822Sdim     FIXME: This is a horrible hack, but doing better is tricky because type
4137218822Sdim     information isn't in a very usable state at parse time.  */
4138218822Sdim  fpnum = str;
4139218822Sdim  skip_whitespace (fpnum);
4140218822Sdim
4141218822Sdim  if (strncmp (fpnum, "0x", 2) == 0)
4142218822Sdim    return FAIL;
4143218822Sdim  else
414477298Sobrien    {
4145218822Sdim      for (; *fpnum != '\0' && *fpnum != ' ' && *fpnum != '\n'; fpnum++)
4146218822Sdim        if (*fpnum == '.' || *fpnum == 'e' || *fpnum == 'E')
4147218822Sdim          {
4148218822Sdim            found_fpchar = 1;
4149218822Sdim            break;
4150218822Sdim          }
4151218822Sdim
4152218822Sdim      if (!found_fpchar)
4153218822Sdim        return FAIL;
415477298Sobrien    }
4155218822Sdim
4156218822Sdim  if ((str = atof_ieee (str, 's', words)) != NULL)
4157218822Sdim    {
4158218822Sdim      unsigned fpword = 0;
4159218822Sdim      int i;
4160218822Sdim
4161218822Sdim      /* Our FP word must be 32 bits (single-precision FP).  */
4162218822Sdim      for (i = 0; i < 32 / LITTLENUM_NUMBER_OF_BITS; i++)
4163218822Sdim        {
4164218822Sdim          fpword <<= LITTLENUM_NUMBER_OF_BITS;
4165218822Sdim          fpword |= words[i];
4166218822Sdim        }
4167218822Sdim
4168218822Sdim      if (is_quarter_float (fpword) || (fpword & 0x7fffffff) == 0)
4169218822Sdim        *immed = fpword;
4170218822Sdim      else
4171218822Sdim        return FAIL;
417277298Sobrien
4173218822Sdim      *ccp = str;
4174218822Sdim
4175218822Sdim      return SUCCESS;
417677298Sobrien    }
4177218822Sdim
4178218822Sdim  return FAIL;
4179218822Sdim}
418077298Sobrien
4181218822Sdim/* Shift operands.  */
4182218822Sdimenum shift_kind
4183218822Sdim{
4184218822Sdim  SHIFT_LSL, SHIFT_LSR, SHIFT_ASR, SHIFT_ROR, SHIFT_RRX
4185218822Sdim};
4186218822Sdim
4187218822Sdimstruct asm_shift_name
4188218822Sdim{
4189218822Sdim  const char	  *name;
4190218822Sdim  enum shift_kind  kind;
4191218822Sdim};
4192218822Sdim
4193218822Sdim/* Third argument to parse_shift.  */
4194218822Sdimenum parse_shift_mode
4195218822Sdim{
4196218822Sdim  NO_SHIFT_RESTRICT,		/* Any kind of shift is accepted.  */
4197218822Sdim  SHIFT_IMMEDIATE,		/* Shift operand must be an immediate.	*/
4198218822Sdim  SHIFT_LSL_OR_ASR_IMMEDIATE,	/* Shift must be LSL or ASR immediate.	*/
4199218822Sdim  SHIFT_ASR_IMMEDIATE,		/* Shift must be ASR immediate.	 */
4200218822Sdim  SHIFT_LSL_IMMEDIATE,		/* Shift must be LSL immediate.	 */
4201218822Sdim};
4202218822Sdim
4203218822Sdim/* Parse a <shift> specifier on an ARM data processing instruction.
4204218822Sdim   This has three forms:
4205218822Sdim
4206218822Sdim     (LSL|LSR|ASL|ASR|ROR) Rs
4207218822Sdim     (LSL|LSR|ASL|ASR|ROR) #imm
4208218822Sdim     RRX
4209218822Sdim
4210218822Sdim   Note that ASL is assimilated to LSL in the instruction encoding, and
4211218822Sdim   RRX to ROR #0 (which cannot be written as such).  */
4212218822Sdim
4213218822Sdimstatic int
4214218822Sdimparse_shift (char **str, int i, enum parse_shift_mode mode)
4215218822Sdim{
4216218822Sdim  const struct asm_shift_name *shift_name;
4217218822Sdim  enum shift_kind shift;
4218218822Sdim  char *s = *str;
4219218822Sdim  char *p = s;
4220218822Sdim  int reg;
4221218822Sdim
4222218822Sdim  for (p = *str; ISALPHA (*p); p++)
4223218822Sdim    ;
4224218822Sdim
4225218822Sdim  if (p == *str)
422677298Sobrien    {
4227218822Sdim      inst.error = _("shift expression expected");
4228218822Sdim      return FAIL;
422977298Sobrien    }
423077298Sobrien
4231218822Sdim  shift_name = hash_find_n (arm_shift_hsh, *str, p - *str);
4232218822Sdim
4233218822Sdim  if (shift_name == NULL)
423477298Sobrien    {
4235218822Sdim      inst.error = _("shift expression expected");
4236218822Sdim      return FAIL;
423777298Sobrien    }
423877298Sobrien
4239218822Sdim  shift = shift_name->kind;
4240218822Sdim
4241218822Sdim  switch (mode)
424277298Sobrien    {
4243218822Sdim    case NO_SHIFT_RESTRICT:
4244218822Sdim    case SHIFT_IMMEDIATE:   break;
4245218822Sdim
4246218822Sdim    case SHIFT_LSL_OR_ASR_IMMEDIATE:
4247218822Sdim      if (shift != SHIFT_LSL && shift != SHIFT_ASR)
4248218822Sdim	{
4249218822Sdim	  inst.error = _("'LSL' or 'ASR' required");
4250218822Sdim	  return FAIL;
4251218822Sdim	}
4252218822Sdim      break;
4253218822Sdim
4254218822Sdim    case SHIFT_LSL_IMMEDIATE:
4255218822Sdim      if (shift != SHIFT_LSL)
4256218822Sdim	{
4257218822Sdim	  inst.error = _("'LSL' required");
4258218822Sdim	  return FAIL;
4259218822Sdim	}
4260218822Sdim      break;
4261218822Sdim
4262218822Sdim    case SHIFT_ASR_IMMEDIATE:
4263218822Sdim      if (shift != SHIFT_ASR)
4264218822Sdim	{
4265218822Sdim	  inst.error = _("'ASR' required");
4266218822Sdim	  return FAIL;
4267218822Sdim	}
4268218822Sdim      break;
4269218822Sdim
4270218822Sdim    default: abort ();
427177298Sobrien    }
427277298Sobrien
4273218822Sdim  if (shift != SHIFT_RRX)
427477298Sobrien    {
4275218822Sdim      /* Whitespace can appear here if the next thing is a bare digit.	*/
4276218822Sdim      skip_whitespace (p);
4277218822Sdim
4278218822Sdim      if (mode == NO_SHIFT_RESTRICT
4279218822Sdim	  && (reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL)
428077298Sobrien	{
4281218822Sdim	  inst.operands[i].imm = reg;
4282218822Sdim	  inst.operands[i].immisreg = 1;
428377298Sobrien	}
4284218822Sdim      else if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
4285218822Sdim	return FAIL;
428677298Sobrien    }
4287218822Sdim  inst.operands[i].shift_kind = shift;
4288218822Sdim  inst.operands[i].shifted = 1;
4289218822Sdim  *str = p;
4290218822Sdim  return SUCCESS;
429189857Sobrien}
429277298Sobrien
4293218822Sdim/* Parse a <shifter_operand> for an ARM data processing instruction:
4294218822Sdim
4295218822Sdim      #<immediate>
4296218822Sdim      #<immediate>, <rotate>
4297218822Sdim      <Rm>
4298218822Sdim      <Rm>, <shift>
4299218822Sdim
4300218822Sdim   where <shift> is defined by parse_shift above, and <rotate> is a
4301218822Sdim   multiple of 2 between 0 and 30.  Validation of immediate operands
4302218822Sdim   is deferred to md_apply_fix.  */
4303218822Sdim
4304218822Sdimstatic int
4305218822Sdimparse_shifter_operand (char **str, int i)
430689857Sobrien{
4307218822Sdim  int value;
4308218822Sdim  expressionS expr;
430989857Sobrien
4310218822Sdim  if ((value = arm_reg_parse (str, REG_TYPE_RN)) != FAIL)
4311218822Sdim    {
4312218822Sdim      inst.operands[i].reg = value;
4313218822Sdim      inst.operands[i].isreg = 1;
431489857Sobrien
4315218822Sdim      /* parse_shift will override this if appropriate */
4316218822Sdim      inst.reloc.exp.X_op = O_constant;
4317218822Sdim      inst.reloc.exp.X_add_number = 0;
4318218822Sdim
4319218822Sdim      if (skip_past_comma (str) == FAIL)
4320218822Sdim	return SUCCESS;
4321218822Sdim
4322218822Sdim      /* Shift operation on register.  */
4323218822Sdim      return parse_shift (str, i, NO_SHIFT_RESTRICT);
4324218822Sdim    }
4325218822Sdim
4326218822Sdim  if (my_get_expression (&inst.reloc.exp, str, GE_IMM_PREFIX))
4327218822Sdim    return FAIL;
4328218822Sdim
4329218822Sdim  if (skip_past_comma (str) == SUCCESS)
433089857Sobrien    {
4331218822Sdim      /* #x, y -- ie explicit rotation by Y.  */
4332218822Sdim      if (my_get_expression (&expr, str, GE_NO_PREFIX))
4333218822Sdim	return FAIL;
4334218822Sdim
4335218822Sdim      if (expr.X_op != O_constant || inst.reloc.exp.X_op != O_constant)
4336218822Sdim	{
4337218822Sdim	  inst.error = _("constant expression expected");
4338218822Sdim	  return FAIL;
4339218822Sdim	}
4340218822Sdim
4341218822Sdim      value = expr.X_add_number;
4342218822Sdim      if (value < 0 || value > 30 || value % 2 != 0)
4343218822Sdim	{
4344218822Sdim	  inst.error = _("invalid rotation");
4345218822Sdim	  return FAIL;
4346218822Sdim	}
4347218822Sdim      if (inst.reloc.exp.X_add_number < 0 || inst.reloc.exp.X_add_number > 255)
4348218822Sdim	{
4349218822Sdim	  inst.error = _("invalid constant");
4350218822Sdim	  return FAIL;
4351218822Sdim	}
4352218822Sdim
4353218822Sdim      /* Convert to decoded value.  md_apply_fix will put it back.  */
4354218822Sdim      inst.reloc.exp.X_add_number
4355218822Sdim	= (((inst.reloc.exp.X_add_number << (32 - value))
4356218822Sdim	    | (inst.reloc.exp.X_add_number >> value)) & 0xffffffff);
435789857Sobrien    }
435889857Sobrien
4359218822Sdim  inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
4360218822Sdim  inst.reloc.pc_rel = 0;
4361218822Sdim  return SUCCESS;
436277298Sobrien}
436377298Sobrien
4364218822Sdim/* Group relocation information.  Each entry in the table contains the
4365218822Sdim   textual name of the relocation as may appear in assembler source
4366218822Sdim   and must end with a colon.
4367218822Sdim   Along with this textual name are the relocation codes to be used if
4368218822Sdim   the corresponding instruction is an ALU instruction (ADD or SUB only),
4369218822Sdim   an LDR, an LDRS, or an LDC.  */
4370130561Sobrien
4371218822Sdimstruct group_reloc_table_entry
4372130561Sobrien{
4373218822Sdim  const char *name;
4374218822Sdim  int alu_code;
4375218822Sdim  int ldr_code;
4376218822Sdim  int ldrs_code;
4377218822Sdim  int ldc_code;
4378218822Sdim};
4379130561Sobrien
4380218822Sdimtypedef enum
4381218822Sdim{
4382218822Sdim  /* Varieties of non-ALU group relocation.  */
4383130561Sobrien
4384218822Sdim  GROUP_LDR,
4385218822Sdim  GROUP_LDRS,
4386218822Sdim  GROUP_LDC
4387218822Sdim} group_reloc_type;
4388218822Sdim
4389218822Sdimstatic struct group_reloc_table_entry group_reloc_table[] =
4390218822Sdim  { /* Program counter relative: */
4391218822Sdim    { "pc_g0_nc",
4392218822Sdim      BFD_RELOC_ARM_ALU_PC_G0_NC,	/* ALU */
4393218822Sdim      0,				/* LDR */
4394218822Sdim      0,				/* LDRS */
4395218822Sdim      0 },				/* LDC */
4396218822Sdim    { "pc_g0",
4397218822Sdim      BFD_RELOC_ARM_ALU_PC_G0,		/* ALU */
4398218822Sdim      BFD_RELOC_ARM_LDR_PC_G0,		/* LDR */
4399218822Sdim      BFD_RELOC_ARM_LDRS_PC_G0,		/* LDRS */
4400218822Sdim      BFD_RELOC_ARM_LDC_PC_G0 },	/* LDC */
4401218822Sdim    { "pc_g1_nc",
4402218822Sdim      BFD_RELOC_ARM_ALU_PC_G1_NC,	/* ALU */
4403218822Sdim      0,				/* LDR */
4404218822Sdim      0,				/* LDRS */
4405218822Sdim      0 },				/* LDC */
4406218822Sdim    { "pc_g1",
4407218822Sdim      BFD_RELOC_ARM_ALU_PC_G1,		/* ALU */
4408218822Sdim      BFD_RELOC_ARM_LDR_PC_G1, 		/* LDR */
4409218822Sdim      BFD_RELOC_ARM_LDRS_PC_G1,		/* LDRS */
4410218822Sdim      BFD_RELOC_ARM_LDC_PC_G1 },	/* LDC */
4411218822Sdim    { "pc_g2",
4412218822Sdim      BFD_RELOC_ARM_ALU_PC_G2,		/* ALU */
4413218822Sdim      BFD_RELOC_ARM_LDR_PC_G2,		/* LDR */
4414218822Sdim      BFD_RELOC_ARM_LDRS_PC_G2,		/* LDRS */
4415218822Sdim      BFD_RELOC_ARM_LDC_PC_G2 },	/* LDC */
4416218822Sdim    /* Section base relative */
4417218822Sdim    { "sb_g0_nc",
4418218822Sdim      BFD_RELOC_ARM_ALU_SB_G0_NC,	/* ALU */
4419218822Sdim      0,				/* LDR */
4420218822Sdim      0,				/* LDRS */
4421218822Sdim      0 },				/* LDC */
4422218822Sdim    { "sb_g0",
4423218822Sdim      BFD_RELOC_ARM_ALU_SB_G0,		/* ALU */
4424218822Sdim      BFD_RELOC_ARM_LDR_SB_G0,		/* LDR */
4425218822Sdim      BFD_RELOC_ARM_LDRS_SB_G0,		/* LDRS */
4426218822Sdim      BFD_RELOC_ARM_LDC_SB_G0 },	/* LDC */
4427218822Sdim    { "sb_g1_nc",
4428218822Sdim      BFD_RELOC_ARM_ALU_SB_G1_NC,	/* ALU */
4429218822Sdim      0,				/* LDR */
4430218822Sdim      0,				/* LDRS */
4431218822Sdim      0 },				/* LDC */
4432218822Sdim    { "sb_g1",
4433218822Sdim      BFD_RELOC_ARM_ALU_SB_G1,		/* ALU */
4434218822Sdim      BFD_RELOC_ARM_LDR_SB_G1, 		/* LDR */
4435218822Sdim      BFD_RELOC_ARM_LDRS_SB_G1,		/* LDRS */
4436218822Sdim      BFD_RELOC_ARM_LDC_SB_G1 },	/* LDC */
4437218822Sdim    { "sb_g2",
4438218822Sdim      BFD_RELOC_ARM_ALU_SB_G2,		/* ALU */
4439218822Sdim      BFD_RELOC_ARM_LDR_SB_G2,		/* LDR */
4440218822Sdim      BFD_RELOC_ARM_LDRS_SB_G2,		/* LDRS */
4441218822Sdim      BFD_RELOC_ARM_LDC_SB_G2 }	};	/* LDC */
4442218822Sdim
4443218822Sdim/* Given the address of a pointer pointing to the textual name of a group
4444218822Sdim   relocation as may appear in assembler source, attempt to find its details
4445218822Sdim   in group_reloc_table.  The pointer will be updated to the character after
4446218822Sdim   the trailing colon.  On failure, FAIL will be returned; SUCCESS
4447218822Sdim   otherwise.  On success, *entry will be updated to point at the relevant
4448218822Sdim   group_reloc_table entry. */
4449218822Sdim
4450218822Sdimstatic int
4451218822Sdimfind_group_reloc_table_entry (char **str, struct group_reloc_table_entry **out)
4452218822Sdim{
4453218822Sdim  unsigned int i;
4454218822Sdim  for (i = 0; i < ARRAY_SIZE (group_reloc_table); i++)
4455130561Sobrien    {
4456218822Sdim      int length = strlen (group_reloc_table[i].name);
4457130561Sobrien
4458218822Sdim      if (strncasecmp (group_reloc_table[i].name, *str, length) == 0 &&
4459218822Sdim          (*str)[length] == ':')
4460218822Sdim        {
4461218822Sdim          *out = &group_reloc_table[i];
4462218822Sdim          *str += (length + 1);
4463218822Sdim          return SUCCESS;
4464218822Sdim        }
4465130561Sobrien    }
4466130561Sobrien
4467218822Sdim  return FAIL;
4468130561Sobrien}
4469130561Sobrien
4470218822Sdim/* Parse a <shifter_operand> for an ARM data processing instruction
4471218822Sdim   (as for parse_shifter_operand) where group relocations are allowed:
4472130561Sobrien
4473218822Sdim      #<immediate>
4474218822Sdim      #<immediate>, <rotate>
4475218822Sdim      #:<group_reloc>:<expression>
4476218822Sdim      <Rm>
4477218822Sdim      <Rm>, <shift>
4478218822Sdim
4479218822Sdim   where <group_reloc> is one of the strings defined in group_reloc_table.
4480218822Sdim   The hashes are optional.
4481218822Sdim
4482218822Sdim   Everything else is as for parse_shifter_operand.  */
4483218822Sdim
4484218822Sdimstatic parse_operand_result
4485218822Sdimparse_shifter_operand_group_reloc (char **str, int i)
4486130561Sobrien{
4487218822Sdim  /* Determine if we have the sequence of characters #: or just :
4488218822Sdim     coming next.  If we do, then we check for a group relocation.
4489218822Sdim     If we don't, punt the whole lot to parse_shifter_operand.  */
4490130561Sobrien
4491218822Sdim  if (((*str)[0] == '#' && (*str)[1] == ':')
4492218822Sdim      || (*str)[0] == ':')
4493130561Sobrien    {
4494218822Sdim      struct group_reloc_table_entry *entry;
4495130561Sobrien
4496218822Sdim      if ((*str)[0] == '#')
4497218822Sdim        (*str) += 2;
4498218822Sdim      else
4499218822Sdim        (*str)++;
4500130561Sobrien
4501218822Sdim      /* Try to parse a group relocation.  Anything else is an error.  */
4502218822Sdim      if (find_group_reloc_table_entry (str, &entry) == FAIL)
4503218822Sdim        {
4504218822Sdim          inst.error = _("unknown group relocation");
4505218822Sdim          return PARSE_OPERAND_FAIL_NO_BACKTRACK;
4506218822Sdim        }
4507218822Sdim
4508218822Sdim      /* We now have the group relocation table entry corresponding to
4509218822Sdim         the name in the assembler source.  Next, we parse the expression.  */
4510218822Sdim      if (my_get_expression (&inst.reloc.exp, str, GE_NO_PREFIX))
4511218822Sdim        return PARSE_OPERAND_FAIL_NO_BACKTRACK;
4512218822Sdim
4513218822Sdim      /* Record the relocation type (always the ALU variant here).  */
4514218822Sdim      inst.reloc.type = entry->alu_code;
4515218822Sdim      assert (inst.reloc.type != 0);
4516218822Sdim
4517218822Sdim      return PARSE_OPERAND_SUCCESS;
4518130561Sobrien    }
4519218822Sdim  else
4520218822Sdim    return parse_shifter_operand (str, i) == SUCCESS
4521218822Sdim           ? PARSE_OPERAND_SUCCESS : PARSE_OPERAND_FAIL;
4522130561Sobrien
4523218822Sdim  /* Never reached.  */
4524130561Sobrien}
4525130561Sobrien
4526218822Sdim/* Parse all forms of an ARM address expression.  Information is written
4527218822Sdim   to inst.operands[i] and/or inst.reloc.
4528130561Sobrien
4529218822Sdim   Preindexed addressing (.preind=1):
4530130561Sobrien
4531218822Sdim   [Rn, #offset]       .reg=Rn .reloc.exp=offset
4532218822Sdim   [Rn, +/-Rm]	       .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
4533218822Sdim   [Rn, +/-Rm, shift]  .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
4534218822Sdim		       .shift_kind=shift .reloc.exp=shift_imm
4535130561Sobrien
4536218822Sdim   These three may have a trailing ! which causes .writeback to be set also.
4537130561Sobrien
4538218822Sdim   Postindexed addressing (.postind=1, .writeback=1):
4539218822Sdim
4540218822Sdim   [Rn], #offset       .reg=Rn .reloc.exp=offset
4541218822Sdim   [Rn], +/-Rm	       .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
4542218822Sdim   [Rn], +/-Rm, shift  .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
4543218822Sdim		       .shift_kind=shift .reloc.exp=shift_imm
4544218822Sdim
4545218822Sdim   Unindexed addressing (.preind=0, .postind=0):
4546218822Sdim
4547218822Sdim   [Rn], {option}      .reg=Rn .imm=option .immisreg=0
4548218822Sdim
4549218822Sdim   Other:
4550218822Sdim
4551218822Sdim   [Rn]{!}	       shorthand for [Rn,#0]{!}
4552218822Sdim   =immediate	       .isreg=0 .reloc.exp=immediate
4553218822Sdim   label	       .reg=PC .reloc.pc_rel=1 .reloc.exp=label
4554218822Sdim
4555218822Sdim  It is the caller's responsibility to check for addressing modes not
4556218822Sdim  supported by the instruction, and to set inst.reloc.type.  */
4557218822Sdim
4558218822Sdimstatic parse_operand_result
4559218822Sdimparse_address_main (char **str, int i, int group_relocations,
4560218822Sdim                    group_reloc_type group_type)
4561130561Sobrien{
4562218822Sdim  char *p = *str;
4563218822Sdim  int reg;
4564130561Sobrien
4565218822Sdim  if (skip_past_char (&p, '[') == FAIL)
4566130561Sobrien    {
4567218822Sdim      if (skip_past_char (&p, '=') == FAIL)
4568218822Sdim	{
4569218822Sdim	  /* bare address - translate to PC-relative offset */
4570218822Sdim	  inst.reloc.pc_rel = 1;
4571218822Sdim	  inst.operands[i].reg = REG_PC;
4572218822Sdim	  inst.operands[i].isreg = 1;
4573218822Sdim	  inst.operands[i].preind = 1;
4574218822Sdim	}
4575218822Sdim      /* else a load-constant pseudo op, no special treatment needed here */
4576218822Sdim
4577218822Sdim      if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX))
4578218822Sdim	return PARSE_OPERAND_FAIL;
4579218822Sdim
4580218822Sdim      *str = p;
4581218822Sdim      return PARSE_OPERAND_SUCCESS;
4582130561Sobrien    }
4583218822Sdim
4584218822Sdim  if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
4585130561Sobrien    {
4586218822Sdim      inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
4587218822Sdim      return PARSE_OPERAND_FAIL;
4588130561Sobrien    }
4589218822Sdim  inst.operands[i].reg = reg;
4590218822Sdim  inst.operands[i].isreg = 1;
4591130561Sobrien
4592218822Sdim  if (skip_past_comma (&p) == SUCCESS)
4593130561Sobrien    {
4594218822Sdim      inst.operands[i].preind = 1;
4595218822Sdim
4596218822Sdim      if (*p == '+') p++;
4597218822Sdim      else if (*p == '-') p++, inst.operands[i].negative = 1;
4598218822Sdim
4599218822Sdim      if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL)
4600218822Sdim	{
4601218822Sdim	  inst.operands[i].imm = reg;
4602218822Sdim	  inst.operands[i].immisreg = 1;
4603218822Sdim
4604218822Sdim	  if (skip_past_comma (&p) == SUCCESS)
4605218822Sdim	    if (parse_shift (&p, i, SHIFT_IMMEDIATE) == FAIL)
4606218822Sdim	      return PARSE_OPERAND_FAIL;
4607218822Sdim	}
4608218822Sdim      else if (skip_past_char (&p, ':') == SUCCESS)
4609218822Sdim        {
4610218822Sdim          /* FIXME: '@' should be used here, but it's filtered out by generic
4611218822Sdim             code before we get to see it here. This may be subject to
4612218822Sdim             change.  */
4613218822Sdim          expressionS exp;
4614218822Sdim          my_get_expression (&exp, &p, GE_NO_PREFIX);
4615218822Sdim          if (exp.X_op != O_constant)
4616218822Sdim            {
4617218822Sdim              inst.error = _("alignment must be constant");
4618218822Sdim              return PARSE_OPERAND_FAIL;
4619218822Sdim            }
4620218822Sdim          inst.operands[i].imm = exp.X_add_number << 8;
4621218822Sdim          inst.operands[i].immisalign = 1;
4622218822Sdim          /* Alignments are not pre-indexes.  */
4623218822Sdim          inst.operands[i].preind = 0;
4624218822Sdim        }
4625218822Sdim      else
4626218822Sdim	{
4627218822Sdim	  if (inst.operands[i].negative)
4628218822Sdim	    {
4629218822Sdim	      inst.operands[i].negative = 0;
4630218822Sdim	      p--;
4631218822Sdim	    }
4632218822Sdim
4633218822Sdim	  if (group_relocations &&
4634218822Sdim              ((*p == '#' && *(p + 1) == ':') || *p == ':'))
4635218822Sdim
4636218822Sdim	    {
4637218822Sdim	      struct group_reloc_table_entry *entry;
4638218822Sdim
4639218822Sdim              /* Skip over the #: or : sequence.  */
4640218822Sdim              if (*p == '#')
4641218822Sdim                p += 2;
4642218822Sdim              else
4643218822Sdim                p++;
4644218822Sdim
4645218822Sdim	      /* Try to parse a group relocation.  Anything else is an
4646218822Sdim                 error.  */
4647218822Sdim	      if (find_group_reloc_table_entry (&p, &entry) == FAIL)
4648218822Sdim		{
4649218822Sdim		  inst.error = _("unknown group relocation");
4650218822Sdim		  return PARSE_OPERAND_FAIL_NO_BACKTRACK;
4651218822Sdim		}
4652218822Sdim
4653218822Sdim	      /* We now have the group relocation table entry corresponding to
4654218822Sdim		 the name in the assembler source.  Next, we parse the
4655218822Sdim                 expression.  */
4656218822Sdim	      if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX))
4657218822Sdim		return PARSE_OPERAND_FAIL_NO_BACKTRACK;
4658218822Sdim
4659218822Sdim	      /* Record the relocation type.  */
4660218822Sdim              switch (group_type)
4661218822Sdim                {
4662218822Sdim                  case GROUP_LDR:
4663218822Sdim	            inst.reloc.type = entry->ldr_code;
4664218822Sdim                    break;
4665218822Sdim
4666218822Sdim                  case GROUP_LDRS:
4667218822Sdim	            inst.reloc.type = entry->ldrs_code;
4668218822Sdim                    break;
4669218822Sdim
4670218822Sdim                  case GROUP_LDC:
4671218822Sdim	            inst.reloc.type = entry->ldc_code;
4672218822Sdim                    break;
4673218822Sdim
4674218822Sdim                  default:
4675218822Sdim                    assert (0);
4676218822Sdim                }
4677218822Sdim
4678218822Sdim              if (inst.reloc.type == 0)
4679218822Sdim		{
4680218822Sdim		  inst.error = _("this group relocation is not allowed on this instruction");
4681218822Sdim		  return PARSE_OPERAND_FAIL_NO_BACKTRACK;
4682218822Sdim		}
4683218822Sdim            }
4684218822Sdim          else
4685218822Sdim	    if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
4686218822Sdim	      return PARSE_OPERAND_FAIL;
4687218822Sdim	}
4688130561Sobrien    }
4689218822Sdim
4690218822Sdim  if (skip_past_char (&p, ']') == FAIL)
4691130561Sobrien    {
4692218822Sdim      inst.error = _("']' expected");
4693218822Sdim      return PARSE_OPERAND_FAIL;
4694130561Sobrien    }
4695218822Sdim
4696218822Sdim  if (skip_past_char (&p, '!') == SUCCESS)
4697218822Sdim    inst.operands[i].writeback = 1;
4698218822Sdim
4699218822Sdim  else if (skip_past_comma (&p) == SUCCESS)
4700130561Sobrien    {
4701218822Sdim      if (skip_past_char (&p, '{') == SUCCESS)
4702218822Sdim	{
4703218822Sdim	  /* [Rn], {expr} - unindexed, with option */
4704218822Sdim	  if (parse_immediate (&p, &inst.operands[i].imm,
4705218822Sdim			       0, 255, TRUE) == FAIL)
4706218822Sdim	    return PARSE_OPERAND_FAIL;
4707218822Sdim
4708218822Sdim	  if (skip_past_char (&p, '}') == FAIL)
4709218822Sdim	    {
4710218822Sdim	      inst.error = _("'}' expected at end of 'option' field");
4711218822Sdim	      return PARSE_OPERAND_FAIL;
4712218822Sdim	    }
4713218822Sdim	  if (inst.operands[i].preind)
4714218822Sdim	    {
4715218822Sdim	      inst.error = _("cannot combine index with option");
4716218822Sdim	      return PARSE_OPERAND_FAIL;
4717218822Sdim	    }
4718218822Sdim	  *str = p;
4719218822Sdim	  return PARSE_OPERAND_SUCCESS;
4720218822Sdim	}
4721218822Sdim      else
4722218822Sdim	{
4723218822Sdim	  inst.operands[i].postind = 1;
4724218822Sdim	  inst.operands[i].writeback = 1;
4725218822Sdim
4726218822Sdim	  if (inst.operands[i].preind)
4727218822Sdim	    {
4728218822Sdim	      inst.error = _("cannot combine pre- and post-indexing");
4729218822Sdim	      return PARSE_OPERAND_FAIL;
4730218822Sdim	    }
4731218822Sdim
4732218822Sdim	  if (*p == '+') p++;
4733218822Sdim	  else if (*p == '-') p++, inst.operands[i].negative = 1;
4734218822Sdim
4735218822Sdim	  if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL)
4736218822Sdim	    {
4737218822Sdim              /* We might be using the immediate for alignment already. If we
4738218822Sdim                 are, OR the register number into the low-order bits.  */
4739218822Sdim              if (inst.operands[i].immisalign)
4740218822Sdim	        inst.operands[i].imm |= reg;
4741218822Sdim              else
4742218822Sdim                inst.operands[i].imm = reg;
4743218822Sdim	      inst.operands[i].immisreg = 1;
4744218822Sdim
4745218822Sdim	      if (skip_past_comma (&p) == SUCCESS)
4746218822Sdim		if (parse_shift (&p, i, SHIFT_IMMEDIATE) == FAIL)
4747218822Sdim		  return PARSE_OPERAND_FAIL;
4748218822Sdim	    }
4749218822Sdim	  else
4750218822Sdim	    {
4751218822Sdim	      if (inst.operands[i].negative)
4752218822Sdim		{
4753218822Sdim		  inst.operands[i].negative = 0;
4754218822Sdim		  p--;
4755218822Sdim		}
4756218822Sdim	      if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
4757218822Sdim		return PARSE_OPERAND_FAIL;
4758218822Sdim	    }
4759218822Sdim	}
4760130561Sobrien    }
4761130561Sobrien
4762218822Sdim  /* If at this point neither .preind nor .postind is set, we have a
4763218822Sdim     bare [Rn]{!}, which is shorthand for [Rn,#0]{!}.  */
4764218822Sdim  if (inst.operands[i].preind == 0 && inst.operands[i].postind == 0)
4765130561Sobrien    {
4766218822Sdim      inst.operands[i].preind = 1;
4767218822Sdim      inst.reloc.exp.X_op = O_constant;
4768218822Sdim      inst.reloc.exp.X_add_number = 0;
4769130561Sobrien    }
4770218822Sdim  *str = p;
4771218822Sdim  return PARSE_OPERAND_SUCCESS;
4772130561Sobrien}
4773130561Sobrien
4774218822Sdimstatic int
4775218822Sdimparse_address (char **str, int i)
4776130561Sobrien{
4777218822Sdim  return parse_address_main (str, i, 0, 0) == PARSE_OPERAND_SUCCESS
4778218822Sdim         ? SUCCESS : FAIL;
4779130561Sobrien}
4780130561Sobrien
4781218822Sdimstatic parse_operand_result
4782218822Sdimparse_address_group_reloc (char **str, int i, group_reloc_type type)
4783130561Sobrien{
4784218822Sdim  return parse_address_main (str, i, 1, type);
4785130561Sobrien}
4786130561Sobrien
4787218822Sdim/* Parse an operand for a MOVW or MOVT instruction.  */
4788218822Sdimstatic int
4789218822Sdimparse_half (char **str)
4790130561Sobrien{
4791218822Sdim  char * p;
4792218822Sdim
4793218822Sdim  p = *str;
4794218822Sdim  skip_past_char (&p, '#');
4795218822Sdim  if (strncasecmp (p, ":lower16:", 9) == 0)
4796218822Sdim    inst.reloc.type = BFD_RELOC_ARM_MOVW;
4797218822Sdim  else if (strncasecmp (p, ":upper16:", 9) == 0)
4798218822Sdim    inst.reloc.type = BFD_RELOC_ARM_MOVT;
4799130561Sobrien
4800218822Sdim  if (inst.reloc.type != BFD_RELOC_UNUSED)
4801130561Sobrien    {
4802218822Sdim      p += 9;
4803218822Sdim      skip_whitespace(p);
4804130561Sobrien    }
4805218822Sdim
4806218822Sdim  if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX))
4807218822Sdim    return FAIL;
4808218822Sdim
4809218822Sdim  if (inst.reloc.type == BFD_RELOC_UNUSED)
4810130561Sobrien    {
4811218822Sdim      if (inst.reloc.exp.X_op != O_constant)
4812218822Sdim	{
4813218822Sdim	  inst.error = _("constant expression expected");
4814218822Sdim	  return FAIL;
4815218822Sdim	}
4816218822Sdim      if (inst.reloc.exp.X_add_number < 0
4817218822Sdim	  || inst.reloc.exp.X_add_number > 0xffff)
4818218822Sdim	{
4819218822Sdim	  inst.error = _("immediate value out of range");
4820218822Sdim	  return FAIL;
4821218822Sdim	}
4822130561Sobrien    }
4823218822Sdim  *str = p;
4824218822Sdim  return SUCCESS;
4825218822Sdim}
4826130561Sobrien
4827218822Sdim/* Miscellaneous. */
4828218822Sdim
4829218822Sdim/* Parse a PSR flag operand.  The value returned is FAIL on syntax error,
4830218822Sdim   or a bitmask suitable to be or-ed into the ARM msr instruction.  */
4831218822Sdimstatic int
4832218822Sdimparse_psr (char **str)
4833218822Sdim{
4834218822Sdim  char *p;
4835218822Sdim  unsigned long psr_field;
4836218822Sdim  const struct asm_psr *psr;
4837218822Sdim  char *start;
4838218822Sdim
4839218822Sdim  /* CPSR's and SPSR's can now be lowercase.  This is just a convenience
4840218822Sdim     feature for ease of use and backwards compatibility.  */
4841218822Sdim  p = *str;
4842218822Sdim  if (strncasecmp (p, "SPSR", 4) == 0)
4843218822Sdim    psr_field = SPSR_BIT;
4844218822Sdim  else if (strncasecmp (p, "CPSR", 4) == 0)
4845218822Sdim    psr_field = 0;
4846130561Sobrien  else
4847130561Sobrien    {
4848218822Sdim      start = p;
4849218822Sdim      do
4850218822Sdim	p++;
4851218822Sdim      while (ISALNUM (*p) || *p == '_');
4852218822Sdim
4853218822Sdim      psr = hash_find_n (arm_v7m_psr_hsh, start, p - start);
4854218822Sdim      if (!psr)
4855218822Sdim	return FAIL;
4856218822Sdim
4857218822Sdim      *str = p;
4858218822Sdim      return psr->field;
4859130561Sobrien    }
4860218822Sdim
4861218822Sdim  p += 4;
4862218822Sdim  if (*p == '_')
4863130561Sobrien    {
4864218822Sdim      /* A suffix follows.  */
4865218822Sdim      p++;
4866218822Sdim      start = p;
4867218822Sdim
4868218822Sdim      do
4869218822Sdim	p++;
4870218822Sdim      while (ISALNUM (*p) || *p == '_');
4871218822Sdim
4872218822Sdim      psr = hash_find_n (arm_psr_hsh, start, p - start);
4873218822Sdim      if (!psr)
4874218822Sdim	goto error;
4875218822Sdim
4876218822Sdim      psr_field |= psr->field;
4877130561Sobrien    }
4878218822Sdim  else
4879130561Sobrien    {
4880218822Sdim      if (ISALNUM (*p))
4881218822Sdim	goto error;    /* Garbage after "[CS]PSR".  */
4882218822Sdim
4883218822Sdim      psr_field |= (PSR_c | PSR_f);
4884130561Sobrien    }
4885218822Sdim  *str = p;
4886218822Sdim  return psr_field;
4887130561Sobrien
4888218822Sdim error:
4889218822Sdim  inst.error = _("flag for {c}psr instruction expected");
4890218822Sdim  return FAIL;
4891130561Sobrien}
4892130561Sobrien
4893218822Sdim/* Parse the flags argument to CPSI[ED].  Returns FAIL on error, or a
4894218822Sdim   value suitable for splatting into the AIF field of the instruction.	*/
4895130561Sobrien
4896218822Sdimstatic int
4897218822Sdimparse_cps_flags (char **str)
4898130561Sobrien{
4899218822Sdim  int val = 0;
4900218822Sdim  int saw_a_flag = 0;
4901218822Sdim  char *s = *str;
4902130561Sobrien
4903218822Sdim  for (;;)
4904218822Sdim    switch (*s++)
4905218822Sdim      {
4906218822Sdim      case '\0': case ',':
4907218822Sdim	goto done;
4908130561Sobrien
4909218822Sdim      case 'a': case 'A': saw_a_flag = 1; val |= 0x4; break;
4910218822Sdim      case 'i': case 'I': saw_a_flag = 1; val |= 0x2; break;
4911218822Sdim      case 'f': case 'F': saw_a_flag = 1; val |= 0x1; break;
4912130561Sobrien
4913218822Sdim      default:
4914218822Sdim	inst.error = _("unrecognized CPS flag");
4915218822Sdim	return FAIL;
4916218822Sdim      }
4917218822Sdim
4918218822Sdim done:
4919218822Sdim  if (saw_a_flag == 0)
4920130561Sobrien    {
4921218822Sdim      inst.error = _("missing CPS flags");
4922218822Sdim      return FAIL;
4923130561Sobrien    }
4924130561Sobrien
4925218822Sdim  *str = s - 1;
4926218822Sdim  return val;
4927130561Sobrien}
4928130561Sobrien
4929218822Sdim/* Parse an endian specifier ("BE" or "LE", case insensitive);
4930218822Sdim   returns 0 for big-endian, 1 for little-endian, FAIL for an error.  */
4931130561Sobrien
4932218822Sdimstatic int
4933218822Sdimparse_endian_specifier (char **str)
4934130561Sobrien{
4935218822Sdim  int little_endian;
4936218822Sdim  char *s = *str;
4937218822Sdim
4938218822Sdim  if (strncasecmp (s, "BE", 2))
4939218822Sdim    little_endian = 0;
4940218822Sdim  else if (strncasecmp (s, "LE", 2))
4941218822Sdim    little_endian = 1;
4942218822Sdim  else
4943130561Sobrien    {
4944218822Sdim      inst.error = _("valid endian specifiers are be or le");
4945218822Sdim      return FAIL;
4946130561Sobrien    }
4947130561Sobrien
4948218822Sdim  if (ISALNUM (s[2]) || s[2] == '_')
4949130561Sobrien    {
4950218822Sdim      inst.error = _("valid endian specifiers are be or le");
4951218822Sdim      return FAIL;
4952130561Sobrien    }
4953130561Sobrien
4954218822Sdim  *str = s + 2;
4955218822Sdim  return little_endian;
4956130561Sobrien}
4957130561Sobrien
4958218822Sdim/* Parse a rotation specifier: ROR #0, #8, #16, #24.  *val receives a
4959218822Sdim   value suitable for poking into the rotate field of an sxt or sxta
4960218822Sdim   instruction, or FAIL on error.  */
4961130561Sobrien
4962218822Sdimstatic int
4963218822Sdimparse_ror (char **str)
4964130561Sobrien{
4965218822Sdim  int rot;
4966218822Sdim  char *s = *str;
4967218822Sdim
4968218822Sdim  if (strncasecmp (s, "ROR", 3) == 0)
4969218822Sdim    s += 3;
4970218822Sdim  else
4971130561Sobrien    {
4972218822Sdim      inst.error = _("missing rotation field after comma");
4973218822Sdim      return FAIL;
4974130561Sobrien    }
4975218822Sdim
4976218822Sdim  if (parse_immediate (&s, &rot, 0, 24, FALSE) == FAIL)
4977218822Sdim    return FAIL;
4978218822Sdim
4979218822Sdim  switch (rot)
4980130561Sobrien    {
4981218822Sdim    case  0: *str = s; return 0x0;
4982218822Sdim    case  8: *str = s; return 0x1;
4983218822Sdim    case 16: *str = s; return 0x2;
4984218822Sdim    case 24: *str = s; return 0x3;
4985218822Sdim
4986218822Sdim    default:
4987218822Sdim      inst.error = _("rotation can only be 0, 8, 16, or 24");
4988218822Sdim      return FAIL;
4989130561Sobrien    }
4990218822Sdim}
4991130561Sobrien
4992218822Sdim/* Parse a conditional code (from conds[] below).  The value returned is in the
4993218822Sdim   range 0 .. 14, or FAIL.  */
4994218822Sdimstatic int
4995218822Sdimparse_cond (char **str)
4996218822Sdim{
4997218822Sdim  char *p, *q;
4998218822Sdim  const struct asm_cond *c;
4999130561Sobrien
5000218822Sdim  p = q = *str;
5001218822Sdim  while (ISALPHA (*q))
5002218822Sdim    q++;
5003130561Sobrien
5004218822Sdim  c = hash_find_n (arm_cond_hsh, p, q - p);
5005218822Sdim  if (!c)
5006218822Sdim    {
5007218822Sdim      inst.error = _("condition required");
5008218822Sdim      return FAIL;
5009218822Sdim    }
5010130561Sobrien
5011218822Sdim  *str = q;
5012218822Sdim  return c->value;
5013130561Sobrien}
5014130561Sobrien
5015218822Sdim/* Parse an option for a barrier instruction.  Returns the encoding for the
5016218822Sdim   option, or FAIL.  */
5017130561Sobrienstatic int
5018218822Sdimparse_barrier (char **str)
5019130561Sobrien{
5020218822Sdim  char *p, *q;
5021218822Sdim  const struct asm_barrier_opt *o;
5022130561Sobrien
5023218822Sdim  p = q = *str;
5024218822Sdim  while (ISALPHA (*q))
5025218822Sdim    q++;
5026130561Sobrien
5027218822Sdim  o = hash_find_n (arm_barrier_opt_hsh, p, q - p);
5028218822Sdim  if (!o)
5029218822Sdim    return FAIL;
5030130561Sobrien
5031218822Sdim  *str = q;
5032218822Sdim  return o->value;
5033130561Sobrien}
5034130561Sobrien
5035218822Sdim/* Parse the operands of a table branch instruction.  Similar to a memory
5036218822Sdim   operand.  */
5037218822Sdimstatic int
5038218822Sdimparse_tb (char **str)
5039218822Sdim{
5040218822Sdim  char * p = *str;
5041218822Sdim  int reg;
5042130561Sobrien
5043218822Sdim  if (skip_past_char (&p, '[') == FAIL)
5044130561Sobrien    {
5045218822Sdim      inst.error = _("'[' expected");
5046218822Sdim      return FAIL;
5047130561Sobrien    }
5048130561Sobrien
5049218822Sdim  if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
5050130561Sobrien    {
5051218822Sdim      inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
5052218822Sdim      return FAIL;
5053130561Sobrien    }
5054218822Sdim  inst.operands[0].reg = reg;
5055218822Sdim
5056218822Sdim  if (skip_past_comma (&p) == FAIL)
5057130561Sobrien    {
5058218822Sdim      inst.error = _("',' expected");
5059218822Sdim      return FAIL;
5060130561Sobrien    }
5061130561Sobrien
5062218822Sdim  if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
5063130561Sobrien    {
5064218822Sdim      inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
5065218822Sdim      return FAIL;
5066130561Sobrien    }
5067218822Sdim  inst.operands[0].imm = reg;
5068218822Sdim
5069218822Sdim  if (skip_past_comma (&p) == SUCCESS)
5070130561Sobrien    {
5071218822Sdim      if (parse_shift (&p, 0, SHIFT_LSL_IMMEDIATE) == FAIL)
5072218822Sdim	return FAIL;
5073218822Sdim      if (inst.reloc.exp.X_add_number != 1)
5074218822Sdim	{
5075218822Sdim	  inst.error = _("invalid shift");
5076218822Sdim	  return FAIL;
5077218822Sdim	}
5078218822Sdim      inst.operands[0].shifted = 1;
5079130561Sobrien    }
5080218822Sdim
5081218822Sdim  if (skip_past_char (&p, ']') == FAIL)
5082130561Sobrien    {
5083218822Sdim      inst.error = _("']' expected");
5084218822Sdim      return FAIL;
5085130561Sobrien    }
5086218822Sdim  *str = p;
5087218822Sdim  return SUCCESS;
5088218822Sdim}
5089130561Sobrien
5090218822Sdim/* Parse the operands of a Neon VMOV instruction. See do_neon_mov for more
5091218822Sdim   information on the types the operands can take and how they are encoded.
5092218822Sdim   Up to four operands may be read; this function handles setting the
5093218822Sdim   ".present" field for each read operand itself.
5094218822Sdim   Updates STR and WHICH_OPERAND if parsing is successful and returns SUCCESS,
5095218822Sdim   else returns FAIL.  */
5096218822Sdim
5097218822Sdimstatic int
5098218822Sdimparse_neon_mov (char **str, int *which_operand)
5099218822Sdim{
5100218822Sdim  int i = *which_operand, val;
5101218822Sdim  enum arm_reg_type rtype;
5102218822Sdim  char *ptr = *str;
5103218822Sdim  struct neon_type_el optype;
5104130561Sobrien
5105218822Sdim  if ((val = parse_scalar (&ptr, 8, &optype)) != FAIL)
5106130561Sobrien    {
5107218822Sdim      /* Case 4: VMOV<c><q>.<size> <Dn[x]>, <Rd>.  */
5108218822Sdim      inst.operands[i].reg = val;
5109218822Sdim      inst.operands[i].isscalar = 1;
5110218822Sdim      inst.operands[i].vectype = optype;
5111218822Sdim      inst.operands[i++].present = 1;
5112130561Sobrien
5113218822Sdim      if (skip_past_comma (&ptr) == FAIL)
5114218822Sdim        goto wanted_comma;
5115130561Sobrien
5116218822Sdim      if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) == FAIL)
5117218822Sdim        goto wanted_arm;
5118218822Sdim
5119218822Sdim      inst.operands[i].reg = val;
5120218822Sdim      inst.operands[i].isreg = 1;
5121218822Sdim      inst.operands[i].present = 1;
5122130561Sobrien    }
5123218822Sdim  else if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_NSDQ, &rtype, &optype))
5124218822Sdim           != FAIL)
5125218822Sdim    {
5126218822Sdim      /* Cases 0, 1, 2, 3, 5 (D only).  */
5127218822Sdim      if (skip_past_comma (&ptr) == FAIL)
5128218822Sdim        goto wanted_comma;
5129218822Sdim
5130218822Sdim      inst.operands[i].reg = val;
5131218822Sdim      inst.operands[i].isreg = 1;
5132218822Sdim      inst.operands[i].isquad = (rtype == REG_TYPE_NQ);
5133218822Sdim      inst.operands[i].issingle = (rtype == REG_TYPE_VFS);
5134218822Sdim      inst.operands[i].isvec = 1;
5135218822Sdim      inst.operands[i].vectype = optype;
5136218822Sdim      inst.operands[i++].present = 1;
5137130561Sobrien
5138218822Sdim      if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) != FAIL)
5139218822Sdim        {
5140218822Sdim          /* Case 5: VMOV<c><q> <Dm>, <Rd>, <Rn>.
5141218822Sdim             Case 13: VMOV <Sd>, <Rm>  */
5142218822Sdim          inst.operands[i].reg = val;
5143218822Sdim          inst.operands[i].isreg = 1;
5144218822Sdim          inst.operands[i].present = 1;
5145130561Sobrien
5146218822Sdim          if (rtype == REG_TYPE_NQ)
5147218822Sdim            {
5148218822Sdim              first_error (_("can't use Neon quad register here"));
5149218822Sdim              return FAIL;
5150218822Sdim            }
5151218822Sdim          else if (rtype != REG_TYPE_VFS)
5152218822Sdim            {
5153218822Sdim              i++;
5154218822Sdim              if (skip_past_comma (&ptr) == FAIL)
5155218822Sdim                goto wanted_comma;
5156218822Sdim              if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) == FAIL)
5157218822Sdim                goto wanted_arm;
5158218822Sdim              inst.operands[i].reg = val;
5159218822Sdim              inst.operands[i].isreg = 1;
5160218822Sdim              inst.operands[i].present = 1;
5161218822Sdim            }
5162218822Sdim        }
5163218822Sdim      else if (parse_qfloat_immediate (&ptr, &inst.operands[i].imm) == SUCCESS)
5164218822Sdim          /* Case 2: VMOV<c><q>.<dt> <Qd>, #<float-imm>
5165218822Sdim             Case 3: VMOV<c><q>.<dt> <Dd>, #<float-imm>
5166218822Sdim             Case 10: VMOV.F32 <Sd>, #<imm>
5167218822Sdim             Case 11: VMOV.F64 <Dd>, #<imm>  */
5168218822Sdim        inst.operands[i].immisfloat = 1;
5169218822Sdim      else if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_NSDQ, &rtype,
5170218822Sdim                                           &optype)) != FAIL)
5171218822Sdim        {
5172218822Sdim          /* Case 0: VMOV<c><q> <Qd>, <Qm>
5173218822Sdim             Case 1: VMOV<c><q> <Dd>, <Dm>
5174218822Sdim             Case 8: VMOV.F32 <Sd>, <Sm>
5175218822Sdim             Case 15: VMOV <Sd>, <Se>, <Rn>, <Rm>  */
5176130561Sobrien
5177218822Sdim          inst.operands[i].reg = val;
5178218822Sdim          inst.operands[i].isreg = 1;
5179218822Sdim          inst.operands[i].isquad = (rtype == REG_TYPE_NQ);
5180218822Sdim          inst.operands[i].issingle = (rtype == REG_TYPE_VFS);
5181218822Sdim          inst.operands[i].isvec = 1;
5182218822Sdim          inst.operands[i].vectype = optype;
5183218822Sdim          inst.operands[i].present = 1;
5184218822Sdim
5185218822Sdim          if (skip_past_comma (&ptr) == SUCCESS)
5186218822Sdim            {
5187218822Sdim              /* Case 15.  */
5188218822Sdim              i++;
5189130561Sobrien
5190218822Sdim              if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) == FAIL)
5191218822Sdim                goto wanted_arm;
5192218822Sdim
5193218822Sdim              inst.operands[i].reg = val;
5194218822Sdim              inst.operands[i].isreg = 1;
5195218822Sdim              inst.operands[i++].present = 1;
5196218822Sdim
5197218822Sdim              if (skip_past_comma (&ptr) == FAIL)
5198218822Sdim                goto wanted_comma;
5199218822Sdim
5200218822Sdim              if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) == FAIL)
5201218822Sdim                goto wanted_arm;
5202218822Sdim
5203218822Sdim              inst.operands[i].reg = val;
5204218822Sdim              inst.operands[i].isreg = 1;
5205218822Sdim              inst.operands[i++].present = 1;
5206218822Sdim            }
5207218822Sdim        }
5208248459Sandrew      else if (parse_big_immediate (&ptr, i) == SUCCESS)
5209248459Sandrew          /* Case 2: VMOV<c><q>.<dt> <Qd>, #<imm>
5210248459Sandrew             Case 3: VMOV<c><q>.<dt> <Dd>, #<imm>  */
5211248459Sandrew        ;
5212218822Sdim      else
5213218822Sdim        {
5214218822Sdim          first_error (_("expected <Rm> or <Dm> or <Qm> operand"));
5215218822Sdim          return FAIL;
5216218822Sdim        }
5217130561Sobrien    }
5218218822Sdim  else if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) != FAIL)
5219130561Sobrien    {
5220218822Sdim      /* Cases 6, 7.  */
5221218822Sdim      inst.operands[i].reg = val;
5222218822Sdim      inst.operands[i].isreg = 1;
5223218822Sdim      inst.operands[i++].present = 1;
5224218822Sdim
5225218822Sdim      if (skip_past_comma (&ptr) == FAIL)
5226218822Sdim        goto wanted_comma;
5227218822Sdim
5228218822Sdim      if ((val = parse_scalar (&ptr, 8, &optype)) != FAIL)
5229218822Sdim        {
5230218822Sdim          /* Case 6: VMOV<c><q>.<dt> <Rd>, <Dn[x]>  */
5231218822Sdim          inst.operands[i].reg = val;
5232218822Sdim          inst.operands[i].isscalar = 1;
5233218822Sdim          inst.operands[i].present = 1;
5234218822Sdim          inst.operands[i].vectype = optype;
5235218822Sdim        }
5236218822Sdim      else if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) != FAIL)
5237218822Sdim        {
5238218822Sdim          /* Case 7: VMOV<c><q> <Rd>, <Rn>, <Dm>  */
5239218822Sdim          inst.operands[i].reg = val;
5240218822Sdim          inst.operands[i].isreg = 1;
5241218822Sdim          inst.operands[i++].present = 1;
5242218822Sdim
5243218822Sdim          if (skip_past_comma (&ptr) == FAIL)
5244218822Sdim            goto wanted_comma;
5245218822Sdim
5246218822Sdim          if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_VFSD, &rtype, &optype))
5247218822Sdim              == FAIL)
5248218822Sdim            {
5249218822Sdim              first_error (_(reg_expected_msgs[REG_TYPE_VFSD]));
5250218822Sdim              return FAIL;
5251218822Sdim            }
5252218822Sdim
5253218822Sdim          inst.operands[i].reg = val;
5254218822Sdim          inst.operands[i].isreg = 1;
5255218822Sdim          inst.operands[i].isvec = 1;
5256218822Sdim          inst.operands[i].issingle = (rtype == REG_TYPE_VFS);
5257218822Sdim          inst.operands[i].vectype = optype;
5258218822Sdim          inst.operands[i].present = 1;
5259218822Sdim
5260218822Sdim          if (rtype == REG_TYPE_VFS)
5261218822Sdim            {
5262218822Sdim              /* Case 14.  */
5263218822Sdim              i++;
5264218822Sdim              if (skip_past_comma (&ptr) == FAIL)
5265218822Sdim                goto wanted_comma;
5266218822Sdim              if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_VFS, NULL,
5267218822Sdim                                              &optype)) == FAIL)
5268218822Sdim                {
5269218822Sdim                  first_error (_(reg_expected_msgs[REG_TYPE_VFS]));
5270218822Sdim                  return FAIL;
5271218822Sdim                }
5272218822Sdim              inst.operands[i].reg = val;
5273218822Sdim              inst.operands[i].isreg = 1;
5274218822Sdim              inst.operands[i].isvec = 1;
5275218822Sdim              inst.operands[i].issingle = 1;
5276218822Sdim              inst.operands[i].vectype = optype;
5277218822Sdim              inst.operands[i].present = 1;
5278218822Sdim            }
5279218822Sdim        }
5280218822Sdim      else if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_VFS, NULL, &optype))
5281218822Sdim               != FAIL)
5282218822Sdim        {
5283218822Sdim          /* Case 13.  */
5284218822Sdim          inst.operands[i].reg = val;
5285218822Sdim          inst.operands[i].isreg = 1;
5286218822Sdim          inst.operands[i].isvec = 1;
5287218822Sdim          inst.operands[i].issingle = 1;
5288218822Sdim          inst.operands[i].vectype = optype;
5289218822Sdim          inst.operands[i++].present = 1;
5290218822Sdim        }
5291130561Sobrien    }
5292130561Sobrien  else
5293130561Sobrien    {
5294218822Sdim      first_error (_("parse error"));
5295218822Sdim      return FAIL;
5296130561Sobrien    }
5297130561Sobrien
5298218822Sdim  /* Successfully parsed the operands. Update args.  */
5299218822Sdim  *which_operand = i;
5300218822Sdim  *str = ptr;
5301218822Sdim  return SUCCESS;
5302130561Sobrien
5303218822Sdim  wanted_comma:
5304218822Sdim  first_error (_("expected comma"));
5305218822Sdim  return FAIL;
5306130561Sobrien
5307218822Sdim  wanted_arm:
5308218822Sdim  first_error (_(reg_expected_msgs[REG_TYPE_RN]));
5309218822Sdim  return FAIL;
5310130561Sobrien}
5311130561Sobrien
5312218822Sdim/* Matcher codes for parse_operands.  */
5313218822Sdimenum operand_parse_code
5314130561Sobrien{
5315218822Sdim  OP_stop,	/* end of line */
5316130561Sobrien
5317218822Sdim  OP_RR,	/* ARM register */
5318218822Sdim  OP_RRnpc,	/* ARM register, not r15 */
5319218822Sdim  OP_RRnpcb,	/* ARM register, not r15, in square brackets */
5320218822Sdim  OP_RRw,	/* ARM register, not r15, optional trailing ! */
5321218822Sdim  OP_RCP,	/* Coprocessor number */
5322218822Sdim  OP_RCN,	/* Coprocessor register */
5323218822Sdim  OP_RF,	/* FPA register */
5324218822Sdim  OP_RVS,	/* VFP single precision register */
5325218822Sdim  OP_RVD,	/* VFP double precision register (0..15) */
5326218822Sdim  OP_RND,       /* Neon double precision register (0..31) */
5327218822Sdim  OP_RNQ,	/* Neon quad precision register */
5328218822Sdim  OP_RVSD,	/* VFP single or double precision register */
5329218822Sdim  OP_RNDQ,      /* Neon double or quad precision register */
5330218822Sdim  OP_RNSDQ,	/* Neon single, double or quad precision register */
5331218822Sdim  OP_RNSC,      /* Neon scalar D[X] */
5332218822Sdim  OP_RVC,	/* VFP control register */
5333218822Sdim  OP_RMF,	/* Maverick F register */
5334218822Sdim  OP_RMD,	/* Maverick D register */
5335218822Sdim  OP_RMFX,	/* Maverick FX register */
5336218822Sdim  OP_RMDX,	/* Maverick DX register */
5337218822Sdim  OP_RMAX,	/* Maverick AX register */
5338218822Sdim  OP_RMDS,	/* Maverick DSPSC register */
5339218822Sdim  OP_RIWR,	/* iWMMXt wR register */
5340218822Sdim  OP_RIWC,	/* iWMMXt wC register */
5341218822Sdim  OP_RIWG,	/* iWMMXt wCG register */
5342218822Sdim  OP_RXA,	/* XScale accumulator register */
5343130561Sobrien
5344218822Sdim  OP_REGLST,	/* ARM register list */
5345218822Sdim  OP_VRSLST,	/* VFP single-precision register list */
5346218822Sdim  OP_VRDLST,	/* VFP double-precision register list */
5347218822Sdim  OP_VRSDLST,   /* VFP single or double-precision register list (& quad) */
5348218822Sdim  OP_NRDLST,    /* Neon double-precision register list (d0-d31, qN aliases) */
5349218822Sdim  OP_NSTRLST,   /* Neon element/structure list */
5350130561Sobrien
5351218822Sdim  OP_NILO,      /* Neon immediate/logic operands 2 or 2+3. (VBIC, VORR...)  */
5352218822Sdim  OP_RNDQ_I0,   /* Neon D or Q reg, or immediate zero.  */
5353218822Sdim  OP_RVSD_I0,	/* VFP S or D reg, or immediate zero.  */
5354218822Sdim  OP_RR_RNSC,   /* ARM reg or Neon scalar.  */
5355218822Sdim  OP_RNSDQ_RNSC, /* Vector S, D or Q reg, or Neon scalar.  */
5356218822Sdim  OP_RNDQ_RNSC, /* Neon D or Q reg, or Neon scalar.  */
5357218822Sdim  OP_RND_RNSC,  /* Neon D reg, or Neon scalar.  */
5358218822Sdim  OP_VMOV,      /* Neon VMOV operands.  */
5359218822Sdim  OP_RNDQ_IMVNb,/* Neon D or Q reg, or immediate good for VMVN.  */
5360218822Sdim  OP_RNDQ_I63b, /* Neon D or Q reg, or immediate for shift.  */
5361218822Sdim  OP_RIWR_I32z, /* iWMMXt wR register, or immediate 0 .. 32 for iWMMXt2.  */
5362130561Sobrien
5363218822Sdim  OP_I0,        /* immediate zero */
5364218822Sdim  OP_I7,	/* immediate value 0 .. 7 */
5365218822Sdim  OP_I15,	/*		   0 .. 15 */
5366218822Sdim  OP_I16,	/*		   1 .. 16 */
5367218822Sdim  OP_I16z,      /*                 0 .. 16 */
5368218822Sdim  OP_I31,	/*		   0 .. 31 */
5369218822Sdim  OP_I31w,	/*		   0 .. 31, optional trailing ! */
5370218822Sdim  OP_I32,	/*		   1 .. 32 */
5371218822Sdim  OP_I32z,	/*		   0 .. 32 */
5372218822Sdim  OP_I63,	/*		   0 .. 63 */
5373218822Sdim  OP_I63s,	/*		 -64 .. 63 */
5374218822Sdim  OP_I64,	/*		   1 .. 64 */
5375218822Sdim  OP_I64z,	/*		   0 .. 64 */
5376218822Sdim  OP_I255,	/*		   0 .. 255 */
5377130561Sobrien
5378218822Sdim  OP_I4b,	/* immediate, prefix optional, 1 .. 4 */
5379218822Sdim  OP_I7b,	/*			       0 .. 7 */
5380218822Sdim  OP_I15b,	/*			       0 .. 15 */
5381218822Sdim  OP_I31b,	/*			       0 .. 31 */
5382130561Sobrien
5383218822Sdim  OP_SH,	/* shifter operand */
5384218822Sdim  OP_SHG,	/* shifter operand with possible group relocation */
5385218822Sdim  OP_ADDR,	/* Memory address expression (any mode) */
5386218822Sdim  OP_ADDRGLDR,	/* Mem addr expr (any mode) with possible LDR group reloc */
5387218822Sdim  OP_ADDRGLDRS, /* Mem addr expr (any mode) with possible LDRS group reloc */
5388218822Sdim  OP_ADDRGLDC,  /* Mem addr expr (any mode) with possible LDC group reloc */
5389218822Sdim  OP_EXP,	/* arbitrary expression */
5390218822Sdim  OP_EXPi,	/* same, with optional immediate prefix */
5391218822Sdim  OP_EXPr,	/* same, with optional relocation suffix */
5392218822Sdim  OP_HALF,	/* 0 .. 65535 or low/high reloc.  */
5393130561Sobrien
5394218822Sdim  OP_CPSF,	/* CPS flags */
5395218822Sdim  OP_ENDI,	/* Endianness specifier */
5396218822Sdim  OP_PSR,	/* CPSR/SPSR mask for msr */
5397218822Sdim  OP_COND,	/* conditional code */
5398218822Sdim  OP_TB,	/* Table branch.  */
5399130561Sobrien
5400218822Sdim  OP_RVC_PSR,	/* CPSR/SPSR mask for msr, or VFP control register.  */
5401218822Sdim  OP_APSR_RR,   /* ARM register or "APSR_nzcv".  */
5402130561Sobrien
5403218822Sdim  OP_RRnpc_I0,	/* ARM register or literal 0 */
5404218822Sdim  OP_RR_EXr,	/* ARM register or expression with opt. reloc suff. */
5405218822Sdim  OP_RR_EXi,	/* ARM register or expression with imm prefix */
5406218822Sdim  OP_RF_IF,	/* FPA register or immediate */
5407218822Sdim  OP_RIWR_RIWC, /* iWMMXt R or C reg */
5408218822Sdim  OP_RIWC_RIWG, /* iWMMXt wC or wCG reg */
5409130561Sobrien
5410218822Sdim  /* Optional operands.	 */
5411218822Sdim  OP_oI7b,	 /* immediate, prefix optional, 0 .. 7 */
5412218822Sdim  OP_oI31b,	 /*				0 .. 31 */
5413218822Sdim  OP_oI32b,      /*                             1 .. 32 */
5414218822Sdim  OP_oIffffb,	 /*				0 .. 65535 */
5415218822Sdim  OP_oI255c,	 /*	  curly-brace enclosed, 0 .. 255 */
5416130561Sobrien
5417218822Sdim  OP_oRR,	 /* ARM register */
5418218822Sdim  OP_oRRnpc,	 /* ARM register, not the PC */
5419218822Sdim  OP_oRRw,	 /* ARM register, not r15, optional trailing ! */
5420218822Sdim  OP_oRND,       /* Optional Neon double precision register */
5421218822Sdim  OP_oRNQ,       /* Optional Neon quad precision register */
5422218822Sdim  OP_oRNDQ,      /* Optional Neon double or quad precision register */
5423218822Sdim  OP_oRNSDQ,	 /* Optional single, double or quad precision vector register */
5424218822Sdim  OP_oSHll,	 /* LSL immediate */
5425218822Sdim  OP_oSHar,	 /* ASR immediate */
5426218822Sdim  OP_oSHllar,	 /* LSL or ASR immediate */
5427218822Sdim  OP_oROR,	 /* ROR 0/8/16/24 */
5428218822Sdim  OP_oBARRIER,	 /* Option argument for a barrier instruction.  */
5429130561Sobrien
5430218822Sdim  OP_FIRST_OPTIONAL = OP_oI7b
5431218822Sdim};
5432130561Sobrien
5433218822Sdim/* Generic instruction operand parser.	This does no encoding and no
5434218822Sdim   semantic validation; it merely squirrels values away in the inst
5435218822Sdim   structure.  Returns SUCCESS or FAIL depending on whether the
5436218822Sdim   specified grammar matched.  */
5437218822Sdimstatic int
5438218822Sdimparse_operands (char *str, const unsigned char *pattern)
5439218822Sdim{
5440218822Sdim  unsigned const char *upat = pattern;
5441218822Sdim  char *backtrack_pos = 0;
5442218822Sdim  const char *backtrack_error = 0;
5443218822Sdim  int i, val, backtrack_index = 0;
5444218822Sdim  enum arm_reg_type rtype;
5445218822Sdim  parse_operand_result result;
5446130561Sobrien
5447218822Sdim#define po_char_or_fail(chr) do {		\
5448218822Sdim  if (skip_past_char (&str, chr) == FAIL)	\
5449218822Sdim    goto bad_args;				\
5450218822Sdim} while (0)
5451130561Sobrien
5452218822Sdim#define po_reg_or_fail(regtype) do {				\
5453218822Sdim  val = arm_typed_reg_parse (&str, regtype, &rtype,		\
5454218822Sdim  			     &inst.operands[i].vectype);	\
5455218822Sdim  if (val == FAIL)						\
5456218822Sdim    {								\
5457218822Sdim      first_error (_(reg_expected_msgs[regtype]));		\
5458218822Sdim      goto failure;						\
5459218822Sdim    }								\
5460218822Sdim  inst.operands[i].reg = val;					\
5461218822Sdim  inst.operands[i].isreg = 1;					\
5462218822Sdim  inst.operands[i].isquad = (rtype == REG_TYPE_NQ);		\
5463218822Sdim  inst.operands[i].issingle = (rtype == REG_TYPE_VFS);		\
5464218822Sdim  inst.operands[i].isvec = (rtype == REG_TYPE_VFS		\
5465218822Sdim                            || rtype == REG_TYPE_VFD		\
5466218822Sdim                            || rtype == REG_TYPE_NQ);		\
5467218822Sdim} while (0)
5468130561Sobrien
5469218822Sdim#define po_reg_or_goto(regtype, label) do {			\
5470218822Sdim  val = arm_typed_reg_parse (&str, regtype, &rtype,		\
5471218822Sdim                             &inst.operands[i].vectype);	\
5472218822Sdim  if (val == FAIL)						\
5473218822Sdim    goto label;							\
5474218822Sdim								\
5475218822Sdim  inst.operands[i].reg = val;					\
5476218822Sdim  inst.operands[i].isreg = 1;					\
5477218822Sdim  inst.operands[i].isquad = (rtype == REG_TYPE_NQ);		\
5478218822Sdim  inst.operands[i].issingle = (rtype == REG_TYPE_VFS);		\
5479218822Sdim  inst.operands[i].isvec = (rtype == REG_TYPE_VFS		\
5480218822Sdim                            || rtype == REG_TYPE_VFD		\
5481218822Sdim                            || rtype == REG_TYPE_NQ);		\
5482218822Sdim} while (0)
5483130561Sobrien
5484218822Sdim#define po_imm_or_fail(min, max, popt) do {			\
5485218822Sdim  if (parse_immediate (&str, &val, min, max, popt) == FAIL)	\
5486218822Sdim    goto failure;						\
5487218822Sdim  inst.operands[i].imm = val;					\
5488218822Sdim} while (0)
5489130561Sobrien
5490218822Sdim#define po_scalar_or_goto(elsz, label) do {			\
5491218822Sdim  val = parse_scalar (&str, elsz, &inst.operands[i].vectype);	\
5492218822Sdim  if (val == FAIL)						\
5493218822Sdim    goto label;							\
5494218822Sdim  inst.operands[i].reg = val;					\
5495218822Sdim  inst.operands[i].isscalar = 1;				\
5496218822Sdim} while (0)
5497130561Sobrien
5498218822Sdim#define po_misc_or_fail(expr) do {		\
5499218822Sdim  if (expr)					\
5500218822Sdim    goto failure;				\
5501218822Sdim} while (0)
5502130561Sobrien
5503218822Sdim#define po_misc_or_fail_no_backtrack(expr) do {	\
5504218822Sdim  result = expr;				\
5505218822Sdim  if (result == PARSE_OPERAND_FAIL_NO_BACKTRACK)\
5506218822Sdim    backtrack_pos = 0;				\
5507218822Sdim  if (result != PARSE_OPERAND_SUCCESS)		\
5508218822Sdim    goto failure;				\
5509218822Sdim} while (0)
5510130561Sobrien
5511130561Sobrien  skip_whitespace (str);
5512130561Sobrien
5513218822Sdim  for (i = 0; upat[i] != OP_stop; i++)
5514130561Sobrien    {
5515218822Sdim      if (upat[i] >= OP_FIRST_OPTIONAL)
5516130561Sobrien	{
5517218822Sdim	  /* Remember where we are in case we need to backtrack.  */
5518218822Sdim	  assert (!backtrack_pos);
5519218822Sdim	  backtrack_pos = str;
5520218822Sdim	  backtrack_error = inst.error;
5521218822Sdim	  backtrack_index = i;
5522130561Sobrien	}
5523130561Sobrien
5524218822Sdim      if (i > 0 && (i > 1 || inst.operands[0].present))
5525218822Sdim	po_char_or_fail (',');
5526130561Sobrien
5527218822Sdim      switch (upat[i])
5528218822Sdim	{
5529218822Sdim	  /* Registers */
5530218822Sdim	case OP_oRRnpc:
5531218822Sdim	case OP_RRnpc:
5532218822Sdim	case OP_oRR:
5533218822Sdim	case OP_RR:    po_reg_or_fail (REG_TYPE_RN);	  break;
5534218822Sdim	case OP_RCP:   po_reg_or_fail (REG_TYPE_CP);	  break;
5535218822Sdim	case OP_RCN:   po_reg_or_fail (REG_TYPE_CN);	  break;
5536218822Sdim	case OP_RF:    po_reg_or_fail (REG_TYPE_FN);	  break;
5537218822Sdim	case OP_RVS:   po_reg_or_fail (REG_TYPE_VFS);	  break;
5538218822Sdim	case OP_RVD:   po_reg_or_fail (REG_TYPE_VFD);	  break;
5539218822Sdim        case OP_oRND:
5540218822Sdim	case OP_RND:   po_reg_or_fail (REG_TYPE_VFD);	  break;
5541218822Sdim	case OP_RVC:
5542218822Sdim	  po_reg_or_goto (REG_TYPE_VFC, coproc_reg);
5543218822Sdim	  break;
5544218822Sdim	  /* Also accept generic coprocessor regs for unknown registers.  */
5545218822Sdim	  coproc_reg:
5546218822Sdim	  po_reg_or_fail (REG_TYPE_CN);
5547218822Sdim	  break;
5548218822Sdim	case OP_RMF:   po_reg_or_fail (REG_TYPE_MVF);	  break;
5549218822Sdim	case OP_RMD:   po_reg_or_fail (REG_TYPE_MVD);	  break;
5550218822Sdim	case OP_RMFX:  po_reg_or_fail (REG_TYPE_MVFX);	  break;
5551218822Sdim	case OP_RMDX:  po_reg_or_fail (REG_TYPE_MVDX);	  break;
5552218822Sdim	case OP_RMAX:  po_reg_or_fail (REG_TYPE_MVAX);	  break;
5553218822Sdim	case OP_RMDS:  po_reg_or_fail (REG_TYPE_DSPSC);	  break;
5554218822Sdim	case OP_RIWR:  po_reg_or_fail (REG_TYPE_MMXWR);	  break;
5555218822Sdim	case OP_RIWC:  po_reg_or_fail (REG_TYPE_MMXWC);	  break;
5556218822Sdim	case OP_RIWG:  po_reg_or_fail (REG_TYPE_MMXWCG);  break;
5557218822Sdim	case OP_RXA:   po_reg_or_fail (REG_TYPE_XSCALE);  break;
5558218822Sdim        case OP_oRNQ:
5559218822Sdim	case OP_RNQ:   po_reg_or_fail (REG_TYPE_NQ);      break;
5560218822Sdim        case OP_oRNDQ:
5561218822Sdim	case OP_RNDQ:  po_reg_or_fail (REG_TYPE_NDQ);     break;
5562218822Sdim        case OP_RVSD:  po_reg_or_fail (REG_TYPE_VFSD);    break;
5563218822Sdim        case OP_oRNSDQ:
5564218822Sdim        case OP_RNSDQ: po_reg_or_fail (REG_TYPE_NSDQ);    break;
5565130561Sobrien
5566218822Sdim        /* Neon scalar. Using an element size of 8 means that some invalid
5567218822Sdim           scalars are accepted here, so deal with those in later code.  */
5568218822Sdim        case OP_RNSC:  po_scalar_or_goto (8, failure);    break;
5569130561Sobrien
5570218822Sdim        /* WARNING: We can expand to two operands here. This has the potential
5571218822Sdim           to totally confuse the backtracking mechanism! It will be OK at
5572218822Sdim           least as long as we don't try to use optional args as well,
5573218822Sdim           though.  */
5574218822Sdim        case OP_NILO:
5575218822Sdim          {
5576218822Sdim            po_reg_or_goto (REG_TYPE_NDQ, try_imm);
5577218822Sdim	    inst.operands[i].present = 1;
5578218822Sdim            i++;
5579218822Sdim            skip_past_comma (&str);
5580218822Sdim            po_reg_or_goto (REG_TYPE_NDQ, one_reg_only);
5581218822Sdim            break;
5582218822Sdim            one_reg_only:
5583218822Sdim            /* Optional register operand was omitted. Unfortunately, it's in
5584218822Sdim               operands[i-1] and we need it to be in inst.operands[i]. Fix that
5585218822Sdim               here (this is a bit grotty).  */
5586218822Sdim            inst.operands[i] = inst.operands[i-1];
5587218822Sdim            inst.operands[i-1].present = 0;
5588218822Sdim            break;
5589218822Sdim            try_imm:
5590218822Sdim	    /* There's a possibility of getting a 64-bit immediate here, so
5591218822Sdim	       we need special handling.  */
5592218822Sdim	    if (parse_big_immediate (&str, i) == FAIL)
5593218822Sdim	      {
5594218822Sdim		inst.error = _("immediate value is out of range");
5595218822Sdim		goto failure;
5596218822Sdim	      }
5597218822Sdim          }
5598218822Sdim          break;
5599130561Sobrien
5600218822Sdim        case OP_RNDQ_I0:
5601218822Sdim          {
5602218822Sdim            po_reg_or_goto (REG_TYPE_NDQ, try_imm0);
5603218822Sdim            break;
5604218822Sdim            try_imm0:
5605218822Sdim            po_imm_or_fail (0, 0, TRUE);
5606218822Sdim          }
5607218822Sdim          break;
5608130561Sobrien
5609218822Sdim        case OP_RVSD_I0:
5610218822Sdim          po_reg_or_goto (REG_TYPE_VFSD, try_imm0);
5611218822Sdim          break;
5612130561Sobrien
5613218822Sdim        case OP_RR_RNSC:
5614218822Sdim          {
5615218822Sdim            po_scalar_or_goto (8, try_rr);
5616218822Sdim            break;
5617218822Sdim            try_rr:
5618218822Sdim            po_reg_or_fail (REG_TYPE_RN);
5619218822Sdim          }
5620218822Sdim          break;
5621130561Sobrien
5622218822Sdim        case OP_RNSDQ_RNSC:
5623218822Sdim          {
5624218822Sdim            po_scalar_or_goto (8, try_nsdq);
5625218822Sdim            break;
5626218822Sdim            try_nsdq:
5627218822Sdim            po_reg_or_fail (REG_TYPE_NSDQ);
5628218822Sdim          }
5629218822Sdim          break;
5630130561Sobrien
5631218822Sdim        case OP_RNDQ_RNSC:
5632218822Sdim          {
5633218822Sdim            po_scalar_or_goto (8, try_ndq);
5634218822Sdim            break;
5635218822Sdim            try_ndq:
5636218822Sdim            po_reg_or_fail (REG_TYPE_NDQ);
5637218822Sdim          }
5638218822Sdim          break;
5639130561Sobrien
5640218822Sdim        case OP_RND_RNSC:
5641218822Sdim          {
5642218822Sdim            po_scalar_or_goto (8, try_vfd);
5643218822Sdim            break;
5644218822Sdim            try_vfd:
5645218822Sdim            po_reg_or_fail (REG_TYPE_VFD);
5646218822Sdim          }
5647218822Sdim          break;
5648130561Sobrien
5649218822Sdim        case OP_VMOV:
5650218822Sdim          /* WARNING: parse_neon_mov can move the operand counter, i. If we're
5651218822Sdim             not careful then bad things might happen.  */
5652218822Sdim          po_misc_or_fail (parse_neon_mov (&str, &i) == FAIL);
5653218822Sdim          break;
5654130561Sobrien
5655218822Sdim        case OP_RNDQ_IMVNb:
5656218822Sdim          {
5657218822Sdim            po_reg_or_goto (REG_TYPE_NDQ, try_mvnimm);
5658218822Sdim            break;
5659218822Sdim            try_mvnimm:
5660218822Sdim            /* There's a possibility of getting a 64-bit immediate here, so
5661218822Sdim               we need special handling.  */
5662218822Sdim            if (parse_big_immediate (&str, i) == FAIL)
5663218822Sdim              {
5664218822Sdim                inst.error = _("immediate value is out of range");
5665218822Sdim                goto failure;
5666218822Sdim              }
5667218822Sdim          }
5668218822Sdim          break;
5669130561Sobrien
5670218822Sdim        case OP_RNDQ_I63b:
5671218822Sdim          {
5672218822Sdim            po_reg_or_goto (REG_TYPE_NDQ, try_shimm);
5673218822Sdim            break;
5674218822Sdim            try_shimm:
5675218822Sdim            po_imm_or_fail (0, 63, TRUE);
5676218822Sdim          }
5677218822Sdim          break;
5678130561Sobrien
5679218822Sdim	case OP_RRnpcb:
5680218822Sdim	  po_char_or_fail ('[');
5681218822Sdim	  po_reg_or_fail  (REG_TYPE_RN);
5682218822Sdim	  po_char_or_fail (']');
5683218822Sdim	  break;
5684130561Sobrien
5685218822Sdim	case OP_RRw:
5686218822Sdim	case OP_oRRw:
5687218822Sdim	  po_reg_or_fail (REG_TYPE_RN);
5688218822Sdim	  if (skip_past_char (&str, '!') == SUCCESS)
5689218822Sdim	    inst.operands[i].writeback = 1;
5690218822Sdim	  break;
5691130561Sobrien
5692218822Sdim	  /* Immediates */
5693218822Sdim	case OP_I7:	 po_imm_or_fail (  0,	   7, FALSE);	break;
5694218822Sdim	case OP_I15:	 po_imm_or_fail (  0,	  15, FALSE);	break;
5695218822Sdim	case OP_I16:	 po_imm_or_fail (  1,	  16, FALSE);	break;
5696218822Sdim        case OP_I16z:	 po_imm_or_fail (  0,     16, FALSE);   break;
5697218822Sdim	case OP_I31:	 po_imm_or_fail (  0,	  31, FALSE);	break;
5698218822Sdim	case OP_I32:	 po_imm_or_fail (  1,	  32, FALSE);	break;
5699218822Sdim        case OP_I32z:	 po_imm_or_fail (  0,     32, FALSE);   break;
5700218822Sdim	case OP_I63s:	 po_imm_or_fail (-64,	  63, FALSE);	break;
5701218822Sdim        case OP_I63:	 po_imm_or_fail (  0,     63, FALSE);   break;
5702218822Sdim        case OP_I64:	 po_imm_or_fail (  1,     64, FALSE);   break;
5703218822Sdim        case OP_I64z:	 po_imm_or_fail (  0,     64, FALSE);   break;
5704218822Sdim	case OP_I255:	 po_imm_or_fail (  0,	 255, FALSE);	break;
5705130561Sobrien
5706218822Sdim	case OP_I4b:	 po_imm_or_fail (  1,	   4, TRUE);	break;
5707218822Sdim	case OP_oI7b:
5708218822Sdim	case OP_I7b:	 po_imm_or_fail (  0,	   7, TRUE);	break;
5709218822Sdim	case OP_I15b:	 po_imm_or_fail (  0,	  15, TRUE);	break;
5710218822Sdim	case OP_oI31b:
5711218822Sdim	case OP_I31b:	 po_imm_or_fail (  0,	  31, TRUE);	break;
5712218822Sdim        case OP_oI32b:   po_imm_or_fail (  1,     32, TRUE);    break;
5713218822Sdim	case OP_oIffffb: po_imm_or_fail (  0, 0xffff, TRUE);	break;
5714130561Sobrien
5715218822Sdim	  /* Immediate variants */
5716218822Sdim	case OP_oI255c:
5717218822Sdim	  po_char_or_fail ('{');
5718218822Sdim	  po_imm_or_fail (0, 255, TRUE);
5719218822Sdim	  po_char_or_fail ('}');
5720218822Sdim	  break;
5721130561Sobrien
5722218822Sdim	case OP_I31w:
5723218822Sdim	  /* The expression parser chokes on a trailing !, so we have
5724218822Sdim	     to find it first and zap it.  */
5725218822Sdim	  {
5726218822Sdim	    char *s = str;
5727218822Sdim	    while (*s && *s != ',')
5728218822Sdim	      s++;
5729218822Sdim	    if (s[-1] == '!')
5730218822Sdim	      {
5731218822Sdim		s[-1] = '\0';
5732218822Sdim		inst.operands[i].writeback = 1;
5733218822Sdim	      }
5734218822Sdim	    po_imm_or_fail (0, 31, TRUE);
5735218822Sdim	    if (str == s - 1)
5736218822Sdim	      str = s;
5737218822Sdim	  }
5738218822Sdim	  break;
5739130561Sobrien
5740218822Sdim	  /* Expressions */
5741218822Sdim	case OP_EXPi:	EXPi:
5742218822Sdim	  po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str,
5743218822Sdim					      GE_OPT_PREFIX));
5744218822Sdim	  break;
5745130561Sobrien
5746218822Sdim	case OP_EXP:
5747218822Sdim	  po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str,
5748218822Sdim					      GE_NO_PREFIX));
5749218822Sdim	  break;
5750130561Sobrien
5751218822Sdim	case OP_EXPr:	EXPr:
5752218822Sdim	  po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str,
5753218822Sdim					      GE_NO_PREFIX));
5754218822Sdim	  if (inst.reloc.exp.X_op == O_symbol)
5755218822Sdim	    {
5756218822Sdim	      val = parse_reloc (&str);
5757218822Sdim	      if (val == -1)
5758218822Sdim		{
5759218822Sdim		  inst.error = _("unrecognized relocation suffix");
5760218822Sdim		  goto failure;
5761218822Sdim		}
5762218822Sdim	      else if (val != BFD_RELOC_UNUSED)
5763218822Sdim		{
5764218822Sdim		  inst.operands[i].imm = val;
5765218822Sdim		  inst.operands[i].hasreloc = 1;
5766218822Sdim		}
5767218822Sdim	    }
5768218822Sdim	  break;
5769218822Sdim
5770218822Sdim	  /* Operand for MOVW or MOVT.  */
5771218822Sdim	case OP_HALF:
5772218822Sdim	  po_misc_or_fail (parse_half (&str));
5773218822Sdim	  break;
5774218822Sdim
5775218822Sdim	  /* Register or expression */
5776218822Sdim	case OP_RR_EXr:	  po_reg_or_goto (REG_TYPE_RN, EXPr); break;
5777218822Sdim	case OP_RR_EXi:	  po_reg_or_goto (REG_TYPE_RN, EXPi); break;
5778218822Sdim
5779218822Sdim	  /* Register or immediate */
5780218822Sdim	case OP_RRnpc_I0: po_reg_or_goto (REG_TYPE_RN, I0);   break;
5781218822Sdim	I0:		  po_imm_or_fail (0, 0, FALSE);	      break;
5782218822Sdim
5783218822Sdim	case OP_RF_IF:    po_reg_or_goto (REG_TYPE_FN, IF);   break;
5784218822Sdim	IF:
5785218822Sdim	  if (!is_immediate_prefix (*str))
5786218822Sdim	    goto bad_args;
5787218822Sdim	  str++;
5788218822Sdim	  val = parse_fpa_immediate (&str);
5789218822Sdim	  if (val == FAIL)
5790218822Sdim	    goto failure;
5791218822Sdim	  /* FPA immediates are encoded as registers 8-15.
5792218822Sdim	     parse_fpa_immediate has already applied the offset.  */
5793218822Sdim	  inst.operands[i].reg = val;
5794218822Sdim	  inst.operands[i].isreg = 1;
5795218822Sdim	  break;
5796218822Sdim
5797218822Sdim	case OP_RIWR_I32z: po_reg_or_goto (REG_TYPE_MMXWR, I32z); break;
5798218822Sdim	I32z:		  po_imm_or_fail (0, 32, FALSE);	  break;
5799218822Sdim
5800218822Sdim	  /* Two kinds of register */
5801218822Sdim	case OP_RIWR_RIWC:
5802130561Sobrien	  {
5803218822Sdim	    struct reg_entry *rege = arm_reg_parse_multi (&str);
5804218822Sdim	    if (!rege
5805218822Sdim		|| (rege->type != REG_TYPE_MMXWR
5806218822Sdim		    && rege->type != REG_TYPE_MMXWC
5807218822Sdim		    && rege->type != REG_TYPE_MMXWCG))
5808218822Sdim	      {
5809218822Sdim		inst.error = _("iWMMXt data or control register expected");
5810218822Sdim		goto failure;
5811218822Sdim	      }
5812218822Sdim	    inst.operands[i].reg = rege->number;
5813218822Sdim	    inst.operands[i].isreg = (rege->type == REG_TYPE_MMXWR);
5814130561Sobrien	  }
5815218822Sdim	  break;
5816130561Sobrien
5817218822Sdim	case OP_RIWC_RIWG:
5818218822Sdim	  {
5819218822Sdim	    struct reg_entry *rege = arm_reg_parse_multi (&str);
5820218822Sdim	    if (!rege
5821218822Sdim		|| (rege->type != REG_TYPE_MMXWC
5822218822Sdim		    && rege->type != REG_TYPE_MMXWCG))
5823218822Sdim	      {
5824218822Sdim		inst.error = _("iWMMXt control register expected");
5825218822Sdim		goto failure;
5826218822Sdim	      }
5827218822Sdim	    inst.operands[i].reg = rege->number;
5828218822Sdim	    inst.operands[i].isreg = 1;
5829218822Sdim	  }
5830218822Sdim	  break;
583177298Sobrien
5832218822Sdim	  /* Misc */
5833218822Sdim	case OP_CPSF:	 val = parse_cps_flags (&str);		break;
5834218822Sdim	case OP_ENDI:	 val = parse_endian_specifier (&str);	break;
5835218822Sdim	case OP_oROR:	 val = parse_ror (&str);		break;
5836218822Sdim	case OP_PSR:	 val = parse_psr (&str);		break;
5837218822Sdim	case OP_COND:	 val = parse_cond (&str);		break;
5838218822Sdim	case OP_oBARRIER:val = parse_barrier (&str);		break;
583977298Sobrien
5840218822Sdim        case OP_RVC_PSR:
5841218822Sdim          po_reg_or_goto (REG_TYPE_VFC, try_psr);
5842218822Sdim          inst.operands[i].isvec = 1;  /* Mark VFP control reg as vector.  */
5843218822Sdim          break;
5844218822Sdim          try_psr:
5845218822Sdim          val = parse_psr (&str);
5846218822Sdim          break;
584777298Sobrien
5848218822Sdim        case OP_APSR_RR:
5849218822Sdim          po_reg_or_goto (REG_TYPE_RN, try_apsr);
5850218822Sdim          break;
5851218822Sdim          try_apsr:
5852218822Sdim          /* Parse "APSR_nvzc" operand (for FMSTAT-equivalent MRS
5853218822Sdim             instruction).  */
5854218822Sdim          if (strncasecmp (str, "APSR_", 5) == 0)
5855218822Sdim            {
5856218822Sdim              unsigned found = 0;
5857218822Sdim              str += 5;
5858218822Sdim              while (found < 15)
5859218822Sdim                switch (*str++)
5860218822Sdim                  {
5861218822Sdim                  case 'c': found = (found & 1) ? 16 : found | 1; break;
5862218822Sdim                  case 'n': found = (found & 2) ? 16 : found | 2; break;
5863218822Sdim                  case 'z': found = (found & 4) ? 16 : found | 4; break;
5864218822Sdim                  case 'v': found = (found & 8) ? 16 : found | 8; break;
5865218822Sdim                  default: found = 16;
5866218822Sdim                  }
5867218822Sdim              if (found != 15)
5868218822Sdim                goto failure;
5869218822Sdim              inst.operands[i].isvec = 1;
5870218822Sdim            }
5871218822Sdim          else
5872218822Sdim            goto failure;
5873218822Sdim          break;
587477298Sobrien
5875218822Sdim	case OP_TB:
5876218822Sdim	  po_misc_or_fail (parse_tb (&str));
5877218822Sdim	  break;
587877298Sobrien
5879218822Sdim	  /* Register lists */
5880218822Sdim	case OP_REGLST:
5881218822Sdim	  val = parse_reg_list (&str);
5882218822Sdim	  if (*str == '^')
5883218822Sdim	    {
5884218822Sdim	      inst.operands[1].writeback = 1;
5885218822Sdim	      str++;
5886218822Sdim	    }
5887218822Sdim	  break;
588877298Sobrien
5889218822Sdim	case OP_VRSLST:
5890218822Sdim	  val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_S);
5891218822Sdim	  break;
589277298Sobrien
5893218822Sdim	case OP_VRDLST:
5894218822Sdim	  val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_D);
5895218822Sdim	  break;
589677298Sobrien
5897218822Sdim        case OP_VRSDLST:
5898218822Sdim          /* Allow Q registers too.  */
5899218822Sdim          val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
5900218822Sdim                                    REGLIST_NEON_D);
5901218822Sdim          if (val == FAIL)
5902218822Sdim            {
5903218822Sdim              inst.error = NULL;
5904218822Sdim              val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
5905218822Sdim                                        REGLIST_VFP_S);
5906218822Sdim              inst.operands[i].issingle = 1;
5907218822Sdim            }
5908218822Sdim          break;
590977298Sobrien
5910218822Sdim        case OP_NRDLST:
5911218822Sdim          val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
5912218822Sdim                                    REGLIST_NEON_D);
5913218822Sdim          break;
591477298Sobrien
5915218822Sdim	case OP_NSTRLST:
5916218822Sdim          val = parse_neon_el_struct_list (&str, &inst.operands[i].reg,
5917218822Sdim                                           &inst.operands[i].vectype);
5918218822Sdim          break;
591977298Sobrien
5920218822Sdim	  /* Addressing modes */
5921218822Sdim	case OP_ADDR:
5922218822Sdim	  po_misc_or_fail (parse_address (&str, i));
5923218822Sdim	  break;
592477298Sobrien
5925218822Sdim	case OP_ADDRGLDR:
5926218822Sdim	  po_misc_or_fail_no_backtrack (
5927218822Sdim            parse_address_group_reloc (&str, i, GROUP_LDR));
5928218822Sdim	  break;
592977298Sobrien
5930218822Sdim	case OP_ADDRGLDRS:
5931218822Sdim	  po_misc_or_fail_no_backtrack (
5932218822Sdim            parse_address_group_reloc (&str, i, GROUP_LDRS));
5933218822Sdim	  break;
593477298Sobrien
5935218822Sdim	case OP_ADDRGLDC:
5936218822Sdim	  po_misc_or_fail_no_backtrack (
5937218822Sdim            parse_address_group_reloc (&str, i, GROUP_LDC));
5938218822Sdim	  break;
593977298Sobrien
5940218822Sdim	case OP_SH:
5941218822Sdim	  po_misc_or_fail (parse_shifter_operand (&str, i));
5942218822Sdim	  break;
594377298Sobrien
5944218822Sdim	case OP_SHG:
5945218822Sdim	  po_misc_or_fail_no_backtrack (
5946218822Sdim            parse_shifter_operand_group_reloc (&str, i));
5947218822Sdim	  break;
594877298Sobrien
5949218822Sdim	case OP_oSHll:
5950218822Sdim	  po_misc_or_fail (parse_shift (&str, i, SHIFT_LSL_IMMEDIATE));
5951218822Sdim	  break;
595277298Sobrien
5953218822Sdim	case OP_oSHar:
5954218822Sdim	  po_misc_or_fail (parse_shift (&str, i, SHIFT_ASR_IMMEDIATE));
5955218822Sdim	  break;
595677298Sobrien
5957218822Sdim	case OP_oSHllar:
5958218822Sdim	  po_misc_or_fail (parse_shift (&str, i, SHIFT_LSL_OR_ASR_IMMEDIATE));
5959218822Sdim	  break;
596077298Sobrien
5961218822Sdim	default:
5962218822Sdim	  as_fatal ("unhandled operand code %d", upat[i]);
5963218822Sdim	}
596477298Sobrien
5965218822Sdim      /* Various value-based sanity checks and shared operations.  We
5966218822Sdim	 do not signal immediate failures for the register constraints;
5967218822Sdim	 this allows a syntax error to take precedence.	 */
5968218822Sdim      switch (upat[i])
5969104834Sobrien	{
5970218822Sdim	case OP_oRRnpc:
5971218822Sdim	case OP_RRnpc:
5972218822Sdim	case OP_RRnpcb:
5973218822Sdim	case OP_RRw:
5974218822Sdim	case OP_oRRw:
5975218822Sdim	case OP_RRnpc_I0:
5976218822Sdim	  if (inst.operands[i].isreg && inst.operands[i].reg == REG_PC)
5977218822Sdim	    inst.error = BAD_PC;
5978218822Sdim	  break;
597977298Sobrien
5980218822Sdim	case OP_CPSF:
5981218822Sdim	case OP_ENDI:
5982218822Sdim	case OP_oROR:
5983218822Sdim	case OP_PSR:
5984218822Sdim        case OP_RVC_PSR:
5985218822Sdim	case OP_COND:
5986218822Sdim	case OP_oBARRIER:
5987218822Sdim	case OP_REGLST:
5988218822Sdim	case OP_VRSLST:
5989218822Sdim	case OP_VRDLST:
5990218822Sdim        case OP_VRSDLST:
5991218822Sdim        case OP_NRDLST:
5992218822Sdim        case OP_NSTRLST:
5993218822Sdim	  if (val == FAIL)
5994218822Sdim	    goto failure;
5995218822Sdim	  inst.operands[i].imm = val;
5996218822Sdim	  break;
599777298Sobrien
5998218822Sdim	default:
5999218822Sdim	  break;
6000218822Sdim	}
600177298Sobrien
6002218822Sdim      /* If we get here, this operand was successfully parsed.	*/
6003218822Sdim      inst.operands[i].present = 1;
6004218822Sdim      continue;
600577298Sobrien
6006218822Sdim    bad_args:
6007218822Sdim      inst.error = BAD_ARGS;
600877298Sobrien
6009218822Sdim    failure:
6010218822Sdim      if (!backtrack_pos)
6011218822Sdim	{
6012218822Sdim	  /* The parse routine should already have set inst.error, but set a
6013218822Sdim	     defaut here just in case.  */
6014218822Sdim	  if (!inst.error)
6015218822Sdim	    inst.error = _("syntax error");
6016218822Sdim	  return FAIL;
6017218822Sdim	}
601877298Sobrien
6019218822Sdim      /* Do not backtrack over a trailing optional argument that
6020218822Sdim	 absorbed some text.  We will only fail again, with the
6021218822Sdim	 'garbage following instruction' error message, which is
6022218822Sdim	 probably less helpful than the current one.  */
6023218822Sdim      if (backtrack_index == i && backtrack_pos != str
6024218822Sdim	  && upat[i+1] == OP_stop)
6025218822Sdim	{
6026218822Sdim	  if (!inst.error)
6027218822Sdim	    inst.error = _("syntax error");
6028218822Sdim	  return FAIL;
6029218822Sdim	}
603077298Sobrien
6031218822Sdim      /* Try again, skipping the optional argument at backtrack_pos.  */
6032218822Sdim      str = backtrack_pos;
6033218822Sdim      inst.error = backtrack_error;
6034218822Sdim      inst.operands[backtrack_index].present = 0;
6035218822Sdim      i = backtrack_index;
6036218822Sdim      backtrack_pos = 0;
603777298Sobrien    }
603877298Sobrien
6039218822Sdim  /* Check that we have parsed all the arguments.  */
6040218822Sdim  if (*str != '\0' && !inst.error)
6041218822Sdim    inst.error = _("garbage following instruction");
604277298Sobrien
6043218822Sdim  return inst.error ? FAIL : SUCCESS;
604477298Sobrien}
604577298Sobrien
6046218822Sdim#undef po_char_or_fail
6047218822Sdim#undef po_reg_or_fail
6048218822Sdim#undef po_reg_or_goto
6049218822Sdim#undef po_imm_or_fail
6050218822Sdim#undef po_scalar_or_fail
6051218822Sdim
6052218822Sdim/* Shorthand macro for instruction encoding functions issuing errors.  */
6053218822Sdim#define constraint(expr, err) do {		\
6054218822Sdim  if (expr)					\
6055218822Sdim    {						\
6056218822Sdim      inst.error = err;				\
6057218822Sdim      return;					\
6058218822Sdim    }						\
6059218822Sdim} while (0)
606077298Sobrien
6061218822Sdim/* Functions for operand encoding.  ARM, then Thumb.  */
6062218822Sdim
6063218822Sdim#define rotate_left(v, n) (v << n | v >> (32 - n))
6064218822Sdim
6065218822Sdim/* If VAL can be encoded in the immediate field of an ARM instruction,
6066218822Sdim   return the encoded form.  Otherwise, return FAIL.  */
6067218822Sdim
6068218822Sdimstatic unsigned int
6069218822Sdimencode_arm_immediate (unsigned int val)
607077298Sobrien{
6071218822Sdim  unsigned int a, i;
607277298Sobrien
6073218822Sdim  for (i = 0; i < 32; i += 2)
6074218822Sdim    if ((a = rotate_left (val, i)) <= 0xff)
6075218822Sdim      return a | (i << 7); /* 12-bit pack: [shift-cnt,const].  */
607677298Sobrien
6077218822Sdim  return FAIL;
6078218822Sdim}
607977298Sobrien
6080218822Sdim/* If VAL can be encoded in the immediate field of a Thumb32 instruction,
6081218822Sdim   return the encoded form.  Otherwise, return FAIL.  */
6082218822Sdimstatic unsigned int
6083218822Sdimencode_thumb32_immediate (unsigned int val)
6084218822Sdim{
6085218822Sdim  unsigned int a, i;
608677298Sobrien
6087218822Sdim  if (val <= 0xff)
6088218822Sdim    return val;
6089218822Sdim
6090218822Sdim  for (i = 1; i <= 24; i++)
609177298Sobrien    {
6092218822Sdim      a = val >> i;
6093218822Sdim      if ((val & ~(0xff << i)) == 0)
6094218822Sdim	return ((val >> i) & 0x7f) | ((32 - i) << 7);
609577298Sobrien    }
609677298Sobrien
6097218822Sdim  a = val & 0xff;
6098218822Sdim  if (val == ((a << 16) | a))
6099218822Sdim    return 0x100 | a;
6100218822Sdim  if (val == ((a << 24) | (a << 16) | (a << 8) | a))
6101218822Sdim    return 0x300 | a;
610277298Sobrien
6103218822Sdim  a = val & 0xff00;
6104218822Sdim  if (val == ((a << 16) | a))
6105218822Sdim    return 0x200 | (a >> 8);
6106218822Sdim
6107218822Sdim  return FAIL;
6108218822Sdim}
6109218822Sdim/* Encode a VFP SP or DP register number into inst.instruction.  */
6110218822Sdim
6111218822Sdimstatic void
6112218822Sdimencode_arm_vfp_reg (int reg, enum vfp_reg_pos pos)
6113218822Sdim{
6114218822Sdim  if ((pos == VFP_REG_Dd || pos == VFP_REG_Dn || pos == VFP_REG_Dm)
6115218822Sdim      && reg > 15)
611677298Sobrien    {
6117218822Sdim      if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v3))
6118218822Sdim        {
6119218822Sdim          if (thumb_mode)
6120218822Sdim            ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
6121218822Sdim                                    fpu_vfp_ext_v3);
6122218822Sdim          else
6123218822Sdim            ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used,
6124218822Sdim                                    fpu_vfp_ext_v3);
6125218822Sdim        }
6126218822Sdim      else
6127218822Sdim        {
6128218822Sdim          first_error (_("D register out of range for selected VFP version"));
6129218822Sdim          return;
6130218822Sdim        }
613177298Sobrien    }
613277298Sobrien
6133218822Sdim  switch (pos)
6134218822Sdim    {
6135218822Sdim    case VFP_REG_Sd:
6136218822Sdim      inst.instruction |= ((reg >> 1) << 12) | ((reg & 1) << 22);
6137218822Sdim      break;
613877298Sobrien
6139218822Sdim    case VFP_REG_Sn:
6140218822Sdim      inst.instruction |= ((reg >> 1) << 16) | ((reg & 1) << 7);
6141218822Sdim      break;
614277298Sobrien
6143218822Sdim    case VFP_REG_Sm:
6144218822Sdim      inst.instruction |= ((reg >> 1) << 0) | ((reg & 1) << 5);
6145218822Sdim      break;
6146218822Sdim
6147218822Sdim    case VFP_REG_Dd:
6148218822Sdim      inst.instruction |= ((reg & 15) << 12) | ((reg >> 4) << 22);
6149218822Sdim      break;
6150218822Sdim
6151218822Sdim    case VFP_REG_Dn:
6152218822Sdim      inst.instruction |= ((reg & 15) << 16) | ((reg >> 4) << 7);
6153218822Sdim      break;
6154218822Sdim
6155218822Sdim    case VFP_REG_Dm:
6156218822Sdim      inst.instruction |= (reg & 15) | ((reg >> 4) << 5);
6157218822Sdim      break;
6158218822Sdim
6159218822Sdim    default:
6160218822Sdim      abort ();
6161218822Sdim    }
616277298Sobrien}
616377298Sobrien
6164218822Sdim/* Encode a <shift> in an ARM-format instruction.  The immediate,
6165218822Sdim   if any, is handled by md_apply_fix.	 */
6166130561Sobrienstatic void
6167218822Sdimencode_arm_shift (int i)
6168130561Sobrien{
6169218822Sdim  if (inst.operands[i].shift_kind == SHIFT_RRX)
6170218822Sdim    inst.instruction |= SHIFT_ROR << 5;
6171218822Sdim  else
6172218822Sdim    {
6173218822Sdim      inst.instruction |= inst.operands[i].shift_kind << 5;
6174218822Sdim      if (inst.operands[i].immisreg)
6175218822Sdim	{
6176218822Sdim	  inst.instruction |= SHIFT_BY_REG;
6177218822Sdim	  inst.instruction |= inst.operands[i].imm << 8;
6178218822Sdim	}
6179218822Sdim      else
6180218822Sdim	inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
6181218822Sdim    }
6182130561Sobrien}
6183130561Sobrien
6184130561Sobrienstatic void
6185218822Sdimencode_arm_shifter_operand (int i)
6186130561Sobrien{
6187218822Sdim  if (inst.operands[i].isreg)
6188218822Sdim    {
6189218822Sdim      inst.instruction |= inst.operands[i].reg;
6190218822Sdim      encode_arm_shift (i);
6191218822Sdim    }
6192218822Sdim  else
6193218822Sdim    inst.instruction |= INST_IMMEDIATE;
6194130561Sobrien}
6195130561Sobrien
6196218822Sdim/* Subroutine of encode_arm_addr_mode_2 and encode_arm_addr_mode_3.  */
6197130561Sobrienstatic void
6198218822Sdimencode_arm_addr_mode_common (int i, bfd_boolean is_t)
6199130561Sobrien{
6200218822Sdim  assert (inst.operands[i].isreg);
6201218822Sdim  inst.instruction |= inst.operands[i].reg << 16;
6202130561Sobrien
6203218822Sdim  if (inst.operands[i].preind)
6204218822Sdim    {
6205218822Sdim      if (is_t)
6206218822Sdim	{
6207218822Sdim	  inst.error = _("instruction does not accept preindexed addressing");
6208218822Sdim	  return;
6209218822Sdim	}
6210218822Sdim      inst.instruction |= PRE_INDEX;
6211218822Sdim      if (inst.operands[i].writeback)
6212218822Sdim	inst.instruction |= WRITE_BACK;
6213130561Sobrien
6214218822Sdim    }
6215218822Sdim  else if (inst.operands[i].postind)
6216218822Sdim    {
6217218822Sdim      assert (inst.operands[i].writeback);
6218218822Sdim      if (is_t)
6219218822Sdim	inst.instruction |= WRITE_BACK;
6220218822Sdim    }
6221218822Sdim  else /* unindexed - only for coprocessor */
6222218822Sdim    {
6223218822Sdim      inst.error = _("instruction does not accept unindexed addressing");
6224218822Sdim      return;
6225218822Sdim    }
6226130561Sobrien
6227218822Sdim  if (((inst.instruction & WRITE_BACK) || !(inst.instruction & PRE_INDEX))
6228218822Sdim      && (((inst.instruction & 0x000f0000) >> 16)
6229218822Sdim	  == ((inst.instruction & 0x0000f000) >> 12)))
6230218822Sdim    as_warn ((inst.instruction & LOAD_BIT)
6231218822Sdim	     ? _("destination register same as write-back base")
6232218822Sdim	     : _("source register same as write-back base"));
6233218822Sdim}
6234218822Sdim
6235218822Sdim/* inst.operands[i] was set up by parse_address.  Encode it into an
6236218822Sdim   ARM-format mode 2 load or store instruction.	 If is_t is true,
6237218822Sdim   reject forms that cannot be used with a T instruction (i.e. not
6238218822Sdim   post-indexed).  */
6239218822Sdimstatic void
6240218822Sdimencode_arm_addr_mode_2 (int i, bfd_boolean is_t)
6241130561Sobrien{
6242218822Sdim  encode_arm_addr_mode_common (i, is_t);
6243130561Sobrien
6244218822Sdim  if (inst.operands[i].immisreg)
6245130561Sobrien    {
6246218822Sdim      inst.instruction |= INST_IMMEDIATE;  /* yes, this is backwards */
6247218822Sdim      inst.instruction |= inst.operands[i].imm;
6248218822Sdim      if (!inst.operands[i].negative)
6249218822Sdim	inst.instruction |= INDEX_UP;
6250218822Sdim      if (inst.operands[i].shifted)
6251218822Sdim	{
6252218822Sdim	  if (inst.operands[i].shift_kind == SHIFT_RRX)
6253218822Sdim	    inst.instruction |= SHIFT_ROR << 5;
6254218822Sdim	  else
6255218822Sdim	    {
6256218822Sdim	      inst.instruction |= inst.operands[i].shift_kind << 5;
6257218822Sdim	      inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
6258218822Sdim	    }
6259218822Sdim	}
6260130561Sobrien    }
6261218822Sdim  else /* immediate offset in inst.reloc */
6262130561Sobrien    {
6263218822Sdim      if (inst.reloc.type == BFD_RELOC_UNUSED)
6264218822Sdim	inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
6265130561Sobrien    }
6266218822Sdim}
6267218822Sdim
6268218822Sdim/* inst.operands[i] was set up by parse_address.  Encode it into an
6269218822Sdim   ARM-format mode 3 load or store instruction.	 Reject forms that
6270218822Sdim   cannot be used with such instructions.  If is_t is true, reject
6271218822Sdim   forms that cannot be used with a T instruction (i.e. not
6272218822Sdim   post-indexed).  */
6273218822Sdimstatic void
6274218822Sdimencode_arm_addr_mode_3 (int i, bfd_boolean is_t)
6275218822Sdim{
6276218822Sdim  if (inst.operands[i].immisreg && inst.operands[i].shifted)
6277130561Sobrien    {
6278218822Sdim      inst.error = _("instruction does not accept scaled register index");
6279218822Sdim      return;
6280218822Sdim    }
6281130561Sobrien
6282218822Sdim  encode_arm_addr_mode_common (i, is_t);
6283218822Sdim
6284218822Sdim  if (inst.operands[i].immisreg)
6285218822Sdim    {
6286218822Sdim      inst.instruction |= inst.operands[i].imm;
6287218822Sdim      if (!inst.operands[i].negative)
6288218822Sdim	inst.instruction |= INDEX_UP;
6289130561Sobrien    }
6290218822Sdim  else /* immediate offset in inst.reloc */
6291218822Sdim    {
6292218822Sdim      inst.instruction |= HWOFFSET_IMM;
6293218822Sdim      if (inst.reloc.type == BFD_RELOC_UNUSED)
6294218822Sdim	inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
6295218822Sdim    }
6296130561Sobrien}
6297130561Sobrien
6298218822Sdim/* inst.operands[i] was set up by parse_address.  Encode it into an
6299218822Sdim   ARM-format instruction.  Reject all forms which cannot be encoded
6300218822Sdim   into a coprocessor load/store instruction.  If wb_ok is false,
6301218822Sdim   reject use of writeback; if unind_ok is false, reject use of
6302218822Sdim   unindexed addressing.  If reloc_override is not 0, use it instead
6303218822Sdim   of BFD_ARM_CP_OFF_IMM, unless the initial relocation is a group one
6304218822Sdim   (in which case it is preserved).  */
6305218822Sdim
6306218822Sdimstatic int
6307218822Sdimencode_arm_cp_address (int i, int wb_ok, int unind_ok, int reloc_override)
6308130561Sobrien{
6309218822Sdim  inst.instruction |= inst.operands[i].reg << 16;
6310130561Sobrien
6311218822Sdim  assert (!(inst.operands[i].preind && inst.operands[i].postind));
6312130561Sobrien
6313218822Sdim  if (!inst.operands[i].preind && !inst.operands[i].postind) /* unindexed */
6314218822Sdim    {
6315218822Sdim      assert (!inst.operands[i].writeback);
6316218822Sdim      if (!unind_ok)
6317218822Sdim	{
6318218822Sdim	  inst.error = _("instruction does not support unindexed addressing");
6319218822Sdim	  return FAIL;
6320218822Sdim	}
6321218822Sdim      inst.instruction |= inst.operands[i].imm;
6322218822Sdim      inst.instruction |= INDEX_UP;
6323218822Sdim      return SUCCESS;
6324218822Sdim    }
6325130561Sobrien
6326218822Sdim  if (inst.operands[i].preind)
6327218822Sdim    inst.instruction |= PRE_INDEX;
6328218822Sdim
6329218822Sdim  if (inst.operands[i].writeback)
6330130561Sobrien    {
6331218822Sdim      if (inst.operands[i].reg == REG_PC)
6332218822Sdim	{
6333218822Sdim	  inst.error = _("pc may not be used with write-back");
6334218822Sdim	  return FAIL;
6335218822Sdim	}
6336218822Sdim      if (!wb_ok)
6337218822Sdim	{
6338218822Sdim	  inst.error = _("instruction does not support writeback");
6339218822Sdim	  return FAIL;
6340218822Sdim	}
6341218822Sdim      inst.instruction |= WRITE_BACK;
6342130561Sobrien    }
6343130561Sobrien
6344218822Sdim  if (reloc_override)
6345218822Sdim    inst.reloc.type = reloc_override;
6346218822Sdim  else if ((inst.reloc.type < BFD_RELOC_ARM_ALU_PC_G0_NC
6347218822Sdim            || inst.reloc.type > BFD_RELOC_ARM_LDC_SB_G2)
6348218822Sdim           && inst.reloc.type != BFD_RELOC_ARM_LDR_PC_G0)
6349130561Sobrien    {
6350218822Sdim      if (thumb_mode)
6351218822Sdim        inst.reloc.type = BFD_RELOC_ARM_T32_CP_OFF_IMM;
6352218822Sdim      else
6353218822Sdim        inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
6354130561Sobrien    }
6355218822Sdim
6356218822Sdim  return SUCCESS;
6357130561Sobrien}
6358130561Sobrien
6359218822Sdim/* inst.reloc.exp describes an "=expr" load pseudo-operation.
6360218822Sdim   Determine whether it can be performed with a move instruction; if
6361218822Sdim   it can, convert inst.instruction to that move instruction and
6362218822Sdim   return 1; if it can't, convert inst.instruction to a literal-pool
6363218822Sdim   load and return 0.  If this is not a valid thing to do in the
6364218822Sdim   current context, set inst.error and return 1.
6365218822Sdim
6366218822Sdim   inst.operands[i] describes the destination register.	 */
6367218822Sdim
6368218822Sdimstatic int
6369218822Sdimmove_or_literal_pool (int i, bfd_boolean thumb_p, bfd_boolean mode_3)
6370130561Sobrien{
6371218822Sdim  unsigned long tbit;
6372130561Sobrien
6373218822Sdim  if (thumb_p)
6374218822Sdim    tbit = (inst.instruction > 0xffff) ? THUMB2_LOAD_BIT : THUMB_LOAD_BIT;
6375218822Sdim  else
6376218822Sdim    tbit = LOAD_BIT;
6377130561Sobrien
6378218822Sdim  if ((inst.instruction & tbit) == 0)
6379218822Sdim    {
6380218822Sdim      inst.error = _("invalid pseudo operation");
6381218822Sdim      return 1;
6382218822Sdim    }
6383218822Sdim  if (inst.reloc.exp.X_op != O_constant && inst.reloc.exp.X_op != O_symbol)
6384218822Sdim    {
6385218822Sdim      inst.error = _("constant expression expected");
6386218822Sdim      return 1;
6387218822Sdim    }
6388218822Sdim  if (inst.reloc.exp.X_op == O_constant)
6389218822Sdim    {
6390218822Sdim      if (thumb_p)
6391218822Sdim	{
6392218822Sdim	  if (!unified_syntax && (inst.reloc.exp.X_add_number & ~0xFF) == 0)
6393218822Sdim	    {
6394218822Sdim	      /* This can be done with a mov(1) instruction.  */
6395218822Sdim	      inst.instruction	= T_OPCODE_MOV_I8 | (inst.operands[i].reg << 8);
6396218822Sdim	      inst.instruction |= inst.reloc.exp.X_add_number;
6397218822Sdim	      return 1;
6398218822Sdim	    }
6399218822Sdim	}
6400218822Sdim      else
6401218822Sdim	{
6402218822Sdim	  int value = encode_arm_immediate (inst.reloc.exp.X_add_number);
6403218822Sdim	  if (value != FAIL)
6404218822Sdim	    {
6405218822Sdim	      /* This can be done with a mov instruction.  */
6406218822Sdim	      inst.instruction &= LITERAL_MASK;
6407218822Sdim	      inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT);
6408218822Sdim	      inst.instruction |= value & 0xfff;
6409218822Sdim	      return 1;
6410218822Sdim	    }
6411218822Sdim
6412218822Sdim	  value = encode_arm_immediate (~inst.reloc.exp.X_add_number);
6413218822Sdim	  if (value != FAIL)
6414218822Sdim	    {
6415218822Sdim	      /* This can be done with a mvn instruction.  */
6416218822Sdim	      inst.instruction &= LITERAL_MASK;
6417218822Sdim	      inst.instruction |= INST_IMMEDIATE | (OPCODE_MVN << DATA_OP_SHIFT);
6418218822Sdim	      inst.instruction |= value & 0xfff;
6419218822Sdim	      return 1;
6420218822Sdim	    }
6421218822Sdim	}
6422218822Sdim    }
6423218822Sdim
6424218822Sdim  if (add_to_lit_pool () == FAIL)
6425218822Sdim    {
6426218822Sdim      inst.error = _("literal pool insertion failed");
6427218822Sdim      return 1;
6428218822Sdim    }
6429218822Sdim  inst.operands[1].reg = REG_PC;
6430218822Sdim  inst.operands[1].isreg = 1;
6431218822Sdim  inst.operands[1].preind = 1;
6432218822Sdim  inst.reloc.pc_rel = 1;
6433218822Sdim  inst.reloc.type = (thumb_p
6434218822Sdim		     ? BFD_RELOC_ARM_THUMB_OFFSET
6435218822Sdim		     : (mode_3
6436218822Sdim			? BFD_RELOC_ARM_HWLITERAL
6437218822Sdim			: BFD_RELOC_ARM_LITERAL));
6438218822Sdim  return 0;
6439130561Sobrien}
6440130561Sobrien
6441218822Sdim/* Functions for instruction encoding, sorted by subarchitecture.
6442218822Sdim   First some generics; their names are taken from the conventional
6443218822Sdim   bit positions for register arguments in ARM format instructions.  */
6444218822Sdim
6445130561Sobrienstatic void
6446218822Sdimdo_noargs (void)
6447130561Sobrien{
6448130561Sobrien}
6449130561Sobrien
6450130561Sobrienstatic void
6451218822Sdimdo_rd (void)
6452130561Sobrien{
6453218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6454130561Sobrien}
6455130561Sobrien
6456130561Sobrienstatic void
6457218822Sdimdo_rd_rm (void)
6458130561Sobrien{
6459218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6460218822Sdim  inst.instruction |= inst.operands[1].reg;
6461130561Sobrien}
6462130561Sobrien
6463130561Sobrienstatic void
6464218822Sdimdo_rd_rn (void)
6465130561Sobrien{
6466218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6467218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
6468130561Sobrien}
6469130561Sobrien
6470130561Sobrienstatic void
6471218822Sdimdo_rn_rd (void)
6472130561Sobrien{
6473218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
6474218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
6475130561Sobrien}
6476130561Sobrien
6477130561Sobrienstatic void
6478218822Sdimdo_rd_rm_rn (void)
6479130561Sobrien{
6480218822Sdim  unsigned Rn = inst.operands[2].reg;
6481218822Sdim  /* Enforce restrictions on SWP instruction.  */
6482218822Sdim  if ((inst.instruction & 0x0fbfffff) == 0x01000090)
6483218822Sdim    constraint (Rn == inst.operands[0].reg || Rn == inst.operands[1].reg,
6484218822Sdim		_("Rn must not overlap other operands"));
6485218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6486218822Sdim  inst.instruction |= inst.operands[1].reg;
6487218822Sdim  inst.instruction |= Rn << 16;
6488130561Sobrien}
6489130561Sobrien
6490130561Sobrienstatic void
6491218822Sdimdo_rd_rn_rm (void)
6492130561Sobrien{
6493218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6494218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
6495218822Sdim  inst.instruction |= inst.operands[2].reg;
6496130561Sobrien}
6497130561Sobrien
6498130561Sobrienstatic void
6499218822Sdimdo_rm_rd_rn (void)
6500130561Sobrien{
6501218822Sdim  inst.instruction |= inst.operands[0].reg;
6502218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
6503218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
6504130561Sobrien}
6505130561Sobrien
6506130561Sobrienstatic void
6507218822Sdimdo_imm0 (void)
6508130561Sobrien{
6509218822Sdim  inst.instruction |= inst.operands[0].imm;
6510130561Sobrien}
6511130561Sobrien
6512130561Sobrienstatic void
6513218822Sdimdo_rd_cpaddr (void)
6514130561Sobrien{
6515218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6516218822Sdim  encode_arm_cp_address (1, TRUE, TRUE, 0);
6517130561Sobrien}
6518130561Sobrien
6519218822Sdim/* ARM instructions, in alphabetical order by function name (except
6520218822Sdim   that wrapper functions appear immediately after the function they
6521218822Sdim   wrap).  */
6522218822Sdim
6523218822Sdim/* This is a pseudo-op of the form "adr rd, label" to be converted
6524218822Sdim   into a relative address of the form "add rd, pc, #label-.-8".  */
6525218822Sdim
6526130561Sobrienstatic void
6527218822Sdimdo_adr (void)
6528130561Sobrien{
6529218822Sdim  inst.instruction |= (inst.operands[0].reg << 12);  /* Rd */
6530218822Sdim
6531218822Sdim  /* Frag hacking will turn this into a sub instruction if the offset turns
6532218822Sdim     out to be negative.  */
6533218822Sdim  inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
6534218822Sdim  inst.reloc.pc_rel = 1;
6535218822Sdim  inst.reloc.exp.X_add_number -= 8;
6536130561Sobrien}
6537130561Sobrien
6538218822Sdim/* This is a pseudo-op of the form "adrl rd, label" to be converted
6539218822Sdim   into a relative address of the form:
6540218822Sdim   add rd, pc, #low(label-.-8)"
6541218822Sdim   add rd, rd, #high(label-.-8)"  */
6542218822Sdim
6543130561Sobrienstatic void
6544218822Sdimdo_adrl (void)
6545130561Sobrien{
6546218822Sdim  inst.instruction |= (inst.operands[0].reg << 12);  /* Rd */
6547130561Sobrien
6548218822Sdim  /* Frag hacking will turn this into a sub instruction if the offset turns
6549218822Sdim     out to be negative.  */
6550218822Sdim  inst.reloc.type	       = BFD_RELOC_ARM_ADRL_IMMEDIATE;
6551218822Sdim  inst.reloc.pc_rel	       = 1;
6552218822Sdim  inst.size		       = INSN_SIZE * 2;
6553218822Sdim  inst.reloc.exp.X_add_number -= 8;
6554130561Sobrien}
6555130561Sobrien
6556130561Sobrienstatic void
6557218822Sdimdo_arit (void)
6558130561Sobrien{
6559218822Sdim  if (!inst.operands[1].present)
6560218822Sdim    inst.operands[1].reg = inst.operands[0].reg;
6561218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6562218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
6563218822Sdim  encode_arm_shifter_operand (2);
6564130561Sobrien}
6565130561Sobrien
6566130561Sobrienstatic void
6567218822Sdimdo_barrier (void)
6568130561Sobrien{
6569218822Sdim  if (inst.operands[0].present)
6570130561Sobrien    {
6571218822Sdim      constraint ((inst.instruction & 0xf0) != 0x40
6572218822Sdim		  && inst.operands[0].imm != 0xf,
6573218822Sdim		  "bad barrier type");
6574218822Sdim      inst.instruction |= inst.operands[0].imm;
6575130561Sobrien    }
6576130561Sobrien  else
6577218822Sdim    inst.instruction |= 0xf;
6578130561Sobrien}
6579130561Sobrien
6580130561Sobrienstatic void
6581218822Sdimdo_bfc (void)
6582130561Sobrien{
6583218822Sdim  unsigned int msb = inst.operands[1].imm + inst.operands[2].imm;
6584218822Sdim  constraint (msb > 32, _("bit-field extends past end of register"));
6585218822Sdim  /* The instruction encoding stores the LSB and MSB,
6586218822Sdim     not the LSB and width.  */
6587218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6588218822Sdim  inst.instruction |= inst.operands[1].imm << 7;
6589218822Sdim  inst.instruction |= (msb - 1) << 16;
6590130561Sobrien}
6591130561Sobrien
6592130561Sobrienstatic void
6593218822Sdimdo_bfi (void)
6594130561Sobrien{
6595218822Sdim  unsigned int msb;
6596218822Sdim
6597218822Sdim  /* #0 in second position is alternative syntax for bfc, which is
6598218822Sdim     the same instruction but with REG_PC in the Rm field.  */
6599218822Sdim  if (!inst.operands[1].isreg)
6600218822Sdim    inst.operands[1].reg = REG_PC;
6601218822Sdim
6602218822Sdim  msb = inst.operands[2].imm + inst.operands[3].imm;
6603218822Sdim  constraint (msb > 32, _("bit-field extends past end of register"));
6604218822Sdim  /* The instruction encoding stores the LSB and MSB,
6605218822Sdim     not the LSB and width.  */
6606218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6607218822Sdim  inst.instruction |= inst.operands[1].reg;
6608218822Sdim  inst.instruction |= inst.operands[2].imm << 7;
6609218822Sdim  inst.instruction |= (msb - 1) << 16;
6610130561Sobrien}
6611130561Sobrien
6612130561Sobrienstatic void
6613218822Sdimdo_bfx (void)
6614130561Sobrien{
6615218822Sdim  constraint (inst.operands[2].imm + inst.operands[3].imm > 32,
6616218822Sdim	      _("bit-field extends past end of register"));
6617218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6618218822Sdim  inst.instruction |= inst.operands[1].reg;
6619218822Sdim  inst.instruction |= inst.operands[2].imm << 7;
6620218822Sdim  inst.instruction |= (inst.operands[3].imm - 1) << 16;
6621130561Sobrien}
6622130561Sobrien
6623218822Sdim/* ARM V5 breakpoint instruction (argument parse)
6624218822Sdim     BKPT <16 bit unsigned immediate>
6625218822Sdim     Instruction is not conditional.
6626218822Sdim	The bit pattern given in insns[] has the COND_ALWAYS condition,
6627218822Sdim	and it is an error if the caller tried to override that.  */
6628218822Sdim
6629130561Sobrienstatic void
6630218822Sdimdo_bkpt (void)
6631130561Sobrien{
6632218822Sdim  /* Top 12 of 16 bits to bits 19:8.  */
6633218822Sdim  inst.instruction |= (inst.operands[0].imm & 0xfff0) << 4;
6634130561Sobrien
6635218822Sdim  /* Bottom 4 of 16 bits to bits 3:0.  */
6636218822Sdim  inst.instruction |= inst.operands[0].imm & 0xf;
6637218822Sdim}
6638130561Sobrien
6639218822Sdimstatic void
6640218822Sdimencode_branch (int default_reloc)
6641218822Sdim{
6642218822Sdim  if (inst.operands[0].hasreloc)
6643218822Sdim    {
6644218822Sdim      constraint (inst.operands[0].imm != BFD_RELOC_ARM_PLT32,
6645218822Sdim		  _("the only suffix valid here is '(plt)'"));
6646218822Sdim      inst.reloc.type	= BFD_RELOC_ARM_PLT32;
6647218822Sdim    }
6648218822Sdim  else
6649218822Sdim    {
6650218822Sdim      inst.reloc.type = default_reloc;
6651218822Sdim    }
6652218822Sdim  inst.reloc.pc_rel = 1;
6653130561Sobrien}
6654130561Sobrien
6655130561Sobrienstatic void
6656218822Sdimdo_branch (void)
6657130561Sobrien{
6658218822Sdim#ifdef OBJ_ELF
6659218822Sdim  if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4)
6660218822Sdim    encode_branch (BFD_RELOC_ARM_PCREL_JUMP);
6661218822Sdim  else
6662218822Sdim#endif
6663218822Sdim    encode_branch (BFD_RELOC_ARM_PCREL_BRANCH);
6664218822Sdim}
6665130561Sobrien
6666218822Sdimstatic void
6667218822Sdimdo_bl (void)
6668218822Sdim{
6669218822Sdim#ifdef OBJ_ELF
6670218822Sdim  if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4)
6671218822Sdim    {
6672218822Sdim      if (inst.cond == COND_ALWAYS)
6673218822Sdim	encode_branch (BFD_RELOC_ARM_PCREL_CALL);
6674218822Sdim      else
6675218822Sdim	encode_branch (BFD_RELOC_ARM_PCREL_JUMP);
6676218822Sdim    }
6677218822Sdim  else
6678218822Sdim#endif
6679218822Sdim    encode_branch (BFD_RELOC_ARM_PCREL_BRANCH);
6680130561Sobrien}
6681130561Sobrien
6682218822Sdim/* ARM V5 branch-link-exchange instruction (argument parse)
6683218822Sdim     BLX <target_addr>		ie BLX(1)
6684218822Sdim     BLX{<condition>} <Rm>	ie BLX(2)
6685218822Sdim   Unfortunately, there are two different opcodes for this mnemonic.
6686218822Sdim   So, the insns[].value is not used, and the code here zaps values
6687218822Sdim	into inst.instruction.
6688218822Sdim   Also, the <target_addr> can be 25 bits, hence has its own reloc.  */
668977298Sobrien
669077298Sobrienstatic void
6691218822Sdimdo_blx (void)
669277298Sobrien{
6693218822Sdim  if (inst.operands[0].isreg)
6694218822Sdim    {
6695218822Sdim      /* Arg is a register; the opcode provided by insns[] is correct.
6696218822Sdim	 It is not illegal to do "blx pc", just useless.  */
6697218822Sdim      if (inst.operands[0].reg == REG_PC)
6698218822Sdim	as_tsktsk (_("use of r15 in blx in ARM mode is not really useful"));
669977298Sobrien
6700218822Sdim      inst.instruction |= inst.operands[0].reg;
6701218822Sdim    }
6702218822Sdim  else
6703218822Sdim    {
6704218822Sdim      /* Arg is an address; this instruction cannot be executed
6705218822Sdim	 conditionally, and the opcode must be adjusted.  */
6706218822Sdim      constraint (inst.cond != COND_ALWAYS, BAD_COND);
6707218822Sdim      inst.instruction = 0xfa000000;
6708218822Sdim#ifdef OBJ_ELF
6709218822Sdim      if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4)
6710218822Sdim	encode_branch (BFD_RELOC_ARM_PCREL_CALL);
6711218822Sdim      else
6712218822Sdim#endif
6713218822Sdim	encode_branch (BFD_RELOC_ARM_PCREL_BLX);
6714218822Sdim    }
6715218822Sdim}
671677298Sobrien
6717218822Sdimstatic void
6718218822Sdimdo_bx (void)
6719218822Sdim{
6720218822Sdim  if (inst.operands[0].reg == REG_PC)
6721218822Sdim    as_tsktsk (_("use of r15 in bx in ARM mode is not really useful"));
672277298Sobrien
6723218822Sdim  inst.instruction |= inst.operands[0].reg;
672477298Sobrien}
672577298Sobrien
672677298Sobrien
6727218822Sdim/* ARM v5TEJ.  Jump to Jazelle code.  */
672877298Sobrien
672977298Sobrienstatic void
6730218822Sdimdo_bxj (void)
673177298Sobrien{
6732218822Sdim  if (inst.operands[0].reg == REG_PC)
6733218822Sdim    as_tsktsk (_("use of r15 in bxj is not really useful"));
673477298Sobrien
6735218822Sdim  inst.instruction |= inst.operands[0].reg;
6736218822Sdim}
673777298Sobrien
6738218822Sdim/* Co-processor data operation:
6739218822Sdim      CDP{cond} <coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>{, <opcode_2>}
6740218822Sdim      CDP2	<coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>{, <opcode_2>}	 */
6741218822Sdimstatic void
6742218822Sdimdo_cdp (void)
6743218822Sdim{
6744218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
6745218822Sdim  inst.instruction |= inst.operands[1].imm << 20;
6746218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
6747218822Sdim  inst.instruction |= inst.operands[3].reg << 16;
6748218822Sdim  inst.instruction |= inst.operands[4].reg;
6749218822Sdim  inst.instruction |= inst.operands[5].imm << 5;
6750218822Sdim}
675177298Sobrien
6752218822Sdimstatic void
6753218822Sdimdo_cmp (void)
6754218822Sdim{
6755218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
6756218822Sdim  encode_arm_shifter_operand (1);
675777298Sobrien}
675877298Sobrien
6759218822Sdim/* Transfer between coprocessor and ARM registers.
6760218822Sdim   MRC{cond} <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>{, <opcode_2>}
6761218822Sdim   MRC2
6762218822Sdim   MCR{cond}
6763218822Sdim   MCR2
676477298Sobrien
6765218822Sdim   No special properties.  */
676677298Sobrien
676777298Sobrienstatic void
6768218822Sdimdo_co_reg (void)
676977298Sobrien{
6770218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
6771218822Sdim  inst.instruction |= inst.operands[1].imm << 21;
6772218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
6773218822Sdim  inst.instruction |= inst.operands[3].reg << 16;
6774218822Sdim  inst.instruction |= inst.operands[4].reg;
6775218822Sdim  inst.instruction |= inst.operands[5].imm << 5;
6776218822Sdim}
677777298Sobrien
6778218822Sdim/* Transfer between coprocessor register and pair of ARM registers.
6779218822Sdim   MCRR{cond} <coproc>, <opcode>, <Rd>, <Rn>, <CRm>.
6780218822Sdim   MCRR2
6781218822Sdim   MRRC{cond}
6782218822Sdim   MRRC2
678377298Sobrien
6784218822Sdim   Two XScale instructions are special cases of these:
678577298Sobrien
6786218822Sdim     MAR{cond} acc0, <RdLo>, <RdHi> == MCRR{cond} p0, #0, <RdLo>, <RdHi>, c0
6787218822Sdim     MRA{cond} acc0, <RdLo>, <RdHi> == MRRC{cond} p0, #0, <RdLo>, <RdHi>, c0
678877298Sobrien
6789218822Sdim   Result unpredicatable if Rd or Rn is R15.  */
679077298Sobrien
6791218822Sdimstatic void
6792218822Sdimdo_co_reg2c (void)
6793218822Sdim{
6794218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
6795218822Sdim  inst.instruction |= inst.operands[1].imm << 4;
6796218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
6797218822Sdim  inst.instruction |= inst.operands[3].reg << 16;
6798218822Sdim  inst.instruction |= inst.operands[4].reg;
6799218822Sdim}
680077298Sobrien
6801218822Sdimstatic void
6802218822Sdimdo_cpsi (void)
6803218822Sdim{
6804218822Sdim  inst.instruction |= inst.operands[0].imm << 6;
6805218822Sdim  if (inst.operands[1].present)
6806218822Sdim    {
6807218822Sdim      inst.instruction |= CPSI_MMOD;
6808218822Sdim      inst.instruction |= inst.operands[1].imm;
6809218822Sdim    }
681077298Sobrien}
681177298Sobrien
6812218822Sdimstatic void
6813218822Sdimdo_dbg (void)
6814218822Sdim{
6815218822Sdim  inst.instruction |= inst.operands[0].imm;
6816218822Sdim}
681777298Sobrien
6818218822Sdimstatic void
6819218822Sdimdo_it (void)
6820218822Sdim{
6821218822Sdim  /* There is no IT instruction in ARM mode.  We
6822218822Sdim     process it but do not generate code for it.  */
6823218822Sdim  inst.size = 0;
6824218822Sdim}
682577298Sobrien
682677298Sobrienstatic void
6827218822Sdimdo_ldmstm (void)
682877298Sobrien{
6829218822Sdim  int base_reg = inst.operands[0].reg;
6830218822Sdim  int range = inst.operands[1].imm;
683177298Sobrien
6832218822Sdim  inst.instruction |= base_reg << 16;
6833218822Sdim  inst.instruction |= range;
683477298Sobrien
6835218822Sdim  if (inst.operands[1].writeback)
6836218822Sdim    inst.instruction |= LDM_TYPE_2_OR_3;
683777298Sobrien
6838218822Sdim  if (inst.operands[0].writeback)
683977298Sobrien    {
6840218822Sdim      inst.instruction |= WRITE_BACK;
6841218822Sdim      /* Check for unpredictable uses of writeback.  */
6842218822Sdim      if (inst.instruction & LOAD_BIT)
684377298Sobrien	{
6844218822Sdim	  /* Not allowed in LDM type 2.	 */
6845218822Sdim	  if ((inst.instruction & LDM_TYPE_2_OR_3)
6846218822Sdim	      && ((range & (1 << REG_PC)) == 0))
6847218822Sdim	    as_warn (_("writeback of base register is UNPREDICTABLE"));
6848218822Sdim	  /* Only allowed if base reg not in list for other types.  */
6849218822Sdim	  else if (range & (1 << base_reg))
6850218822Sdim	    as_warn (_("writeback of base register when in register list is UNPREDICTABLE"));
685177298Sobrien	}
6852218822Sdim      else /* STM.  */
685377298Sobrien	{
6854218822Sdim	  /* Not allowed for type 2.  */
6855218822Sdim	  if (inst.instruction & LDM_TYPE_2_OR_3)
6856218822Sdim	    as_warn (_("writeback of base register is UNPREDICTABLE"));
6857218822Sdim	  /* Only allowed if base reg not in list, or first in list.  */
6858218822Sdim	  else if ((range & (1 << base_reg))
6859218822Sdim		   && (range & ((1 << base_reg) - 1)))
6860218822Sdim	    as_warn (_("if writeback register is in list, it must be the lowest reg in the list"));
686177298Sobrien	}
686277298Sobrien    }
6863218822Sdim}
686477298Sobrien
6865218822Sdim/* ARMv5TE load-consecutive (argument parse)
6866218822Sdim   Mode is like LDRH.
686777298Sobrien
6868218822Sdim     LDRccD R, mode
6869218822Sdim     STRccD R, mode.  */
687077298Sobrien
6871218822Sdimstatic void
6872218822Sdimdo_ldrd (void)
6873218822Sdim{
6874218822Sdim  constraint (inst.operands[0].reg % 2 != 0,
6875218822Sdim	      _("first destination register must be even"));
6876218822Sdim  constraint (inst.operands[1].present
6877218822Sdim	      && inst.operands[1].reg != inst.operands[0].reg + 1,
6878218822Sdim	      _("can only load two consecutive registers"));
6879218822Sdim  constraint (inst.operands[0].reg == REG_LR, _("r14 not allowed here"));
6880218822Sdim  constraint (!inst.operands[2].isreg, _("'[' expected"));
688177298Sobrien
6882218822Sdim  if (!inst.operands[1].present)
6883218822Sdim    inst.operands[1].reg = inst.operands[0].reg + 1;
6884218822Sdim
6885218822Sdim  if (inst.instruction & LOAD_BIT)
6886218822Sdim    {
6887218822Sdim      /* encode_arm_addr_mode_3 will diagnose overlap between the base
6888218822Sdim	 register and the first register written; we have to diagnose
6889218822Sdim	 overlap between the base and the second register written here.	 */
689077298Sobrien
6891218822Sdim      if (inst.operands[2].reg == inst.operands[1].reg
6892218822Sdim	  && (inst.operands[2].writeback || inst.operands[2].postind))
6893218822Sdim	as_warn (_("base register written back, and overlaps "
6894218822Sdim		   "second destination register"));
689577298Sobrien
6896218822Sdim      /* For an index-register load, the index register must not overlap the
6897218822Sdim	 destination (even if not write-back).	*/
6898218822Sdim      else if (inst.operands[2].immisreg
6899218822Sdim	       && ((unsigned) inst.operands[2].imm == inst.operands[0].reg
6900218822Sdim		   || (unsigned) inst.operands[2].imm == inst.operands[1].reg))
6901218822Sdim	as_warn (_("index register overlaps destination register"));
690277298Sobrien    }
690377298Sobrien
6904218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6905218822Sdim  encode_arm_addr_mode_3 (2, /*is_t=*/FALSE);
690677298Sobrien}
690777298Sobrien
6908218822Sdimstatic void
6909218822Sdimdo_ldrex (void)
6910218822Sdim{
6911218822Sdim  constraint (!inst.operands[1].isreg || !inst.operands[1].preind
6912218822Sdim	      || inst.operands[1].postind || inst.operands[1].writeback
6913218822Sdim	      || inst.operands[1].immisreg || inst.operands[1].shifted
6914218822Sdim	      || inst.operands[1].negative
6915218822Sdim	      /* This can arise if the programmer has written
6916218822Sdim		   strex rN, rM, foo
6917218822Sdim		 or if they have mistakenly used a register name as the last
6918218822Sdim		 operand,  eg:
6919218822Sdim		   strex rN, rM, rX
6920218822Sdim		 It is very difficult to distinguish between these two cases
6921218822Sdim		 because "rX" might actually be a label. ie the register
6922218822Sdim		 name has been occluded by a symbol of the same name. So we
6923218822Sdim		 just generate a general 'bad addressing mode' type error
6924218822Sdim		 message and leave it up to the programmer to discover the
6925218822Sdim		 true cause and fix their mistake.  */
6926218822Sdim	      || (inst.operands[1].reg == REG_PC),
6927218822Sdim	      BAD_ADDR_MODE);
692877298Sobrien
6929218822Sdim  constraint (inst.reloc.exp.X_op != O_constant
6930218822Sdim	      || inst.reloc.exp.X_add_number != 0,
6931218822Sdim	      _("offset must be zero in ARM encoding"));
693277298Sobrien
6933218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6934218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
6935218822Sdim  inst.reloc.type = BFD_RELOC_UNUSED;
6936218822Sdim}
6937218822Sdim
693877298Sobrienstatic void
6939218822Sdimdo_ldrexd (void)
694077298Sobrien{
6941218822Sdim  constraint (inst.operands[0].reg % 2 != 0,
6942218822Sdim	      _("even register required"));
6943218822Sdim  constraint (inst.operands[1].present
6944218822Sdim	      && inst.operands[1].reg != inst.operands[0].reg + 1,
6945218822Sdim	      _("can only load two consecutive registers"));
6946218822Sdim  /* If op 1 were present and equal to PC, this function wouldn't
6947218822Sdim     have been called in the first place.  */
6948218822Sdim  constraint (inst.operands[0].reg == REG_LR, _("r14 not allowed here"));
694977298Sobrien
6950218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6951218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
6952218822Sdim}
695377298Sobrien
6954218822Sdimstatic void
6955218822Sdimdo_ldst (void)
6956218822Sdim{
6957218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6958218822Sdim  if (!inst.operands[1].isreg)
6959218822Sdim    if (move_or_literal_pool (0, /*thumb_p=*/FALSE, /*mode_3=*/FALSE))
696077298Sobrien      return;
6961218822Sdim  encode_arm_addr_mode_2 (1, /*is_t=*/FALSE);
6962218822Sdim}
696377298Sobrien
6964218822Sdimstatic void
6965218822Sdimdo_ldstt (void)
6966218822Sdim{
6967218822Sdim  /* ldrt/strt always use post-indexed addressing.  Turn [Rn] into [Rn]! and
6968218822Sdim     reject [Rn,...].  */
6969218822Sdim  if (inst.operands[1].preind)
697077298Sobrien    {
6971218822Sdim      constraint (inst.reloc.exp.X_op != O_constant ||
6972218822Sdim		  inst.reloc.exp.X_add_number != 0,
6973218822Sdim		  _("this instruction requires a post-indexed address"));
697477298Sobrien
6975218822Sdim      inst.operands[1].preind = 0;
6976218822Sdim      inst.operands[1].postind = 1;
6977218822Sdim      inst.operands[1].writeback = 1;
697877298Sobrien    }
6979218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6980218822Sdim  encode_arm_addr_mode_2 (1, /*is_t=*/TRUE);
6981218822Sdim}
698277298Sobrien
6983218822Sdim/* Halfword and signed-byte load/store operations.  */
6984218822Sdim
6985218822Sdimstatic void
6986218822Sdimdo_ldstv4 (void)
6987218822Sdim{
6988218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6989218822Sdim  if (!inst.operands[1].isreg)
6990218822Sdim    if (move_or_literal_pool (0, /*thumb_p=*/FALSE, /*mode_3=*/TRUE))
699177298Sobrien      return;
6992218822Sdim  encode_arm_addr_mode_3 (1, /*is_t=*/FALSE);
6993218822Sdim}
699477298Sobrien
6995218822Sdimstatic void
6996218822Sdimdo_ldsttv4 (void)
6997218822Sdim{
6998218822Sdim  /* ldrt/strt always use post-indexed addressing.  Turn [Rn] into [Rn]! and
6999218822Sdim     reject [Rn,...].  */
7000218822Sdim  if (inst.operands[1].preind)
700189857Sobrien    {
7002218822Sdim      constraint (inst.reloc.exp.X_op != O_constant ||
7003218822Sdim		  inst.reloc.exp.X_add_number != 0,
7004218822Sdim		  _("this instruction requires a post-indexed address"));
700589857Sobrien
7006218822Sdim      inst.operands[1].preind = 0;
7007218822Sdim      inst.operands[1].postind = 1;
7008218822Sdim      inst.operands[1].writeback = 1;
700989857Sobrien    }
7010218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7011218822Sdim  encode_arm_addr_mode_3 (1, /*is_t=*/TRUE);
7012218822Sdim}
701389857Sobrien
7014218822Sdim/* Co-processor register load/store.
7015218822Sdim   Format: <LDC|STC>{cond}[L] CP#,CRd,<address>	 */
7016218822Sdimstatic void
7017218822Sdimdo_lstc (void)
7018218822Sdim{
7019218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
7020218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
7021218822Sdim  encode_arm_cp_address (2, TRUE, TRUE, 0);
702277298Sobrien}
702377298Sobrien
7024218822Sdimstatic void
7025218822Sdimdo_mlas (void)
702660484Sobrien{
7027218822Sdim  /* This restriction does not apply to mls (nor to mla in v6 or later).  */
7028218822Sdim  if (inst.operands[0].reg == inst.operands[1].reg
7029218822Sdim      && !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6)
7030218822Sdim      && !(inst.instruction & 0x00400000))
7031218822Sdim    as_tsktsk (_("Rd and Rm should be different in mla"));
703260484Sobrien
7033218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7034218822Sdim  inst.instruction |= inst.operands[1].reg;
7035218822Sdim  inst.instruction |= inst.operands[2].reg << 8;
7036218822Sdim  inst.instruction |= inst.operands[3].reg << 12;
7037218822Sdim}
703877298Sobrien
7039218822Sdimstatic void
7040218822Sdimdo_mov (void)
7041218822Sdim{
7042218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7043218822Sdim  encode_arm_shifter_operand (1);
7044218822Sdim}
704560484Sobrien
7046218822Sdim/* ARM V6T2 16-bit immediate register load: MOV[WT]{cond} Rd, #<imm16>.	 */
7047218822Sdimstatic void
7048218822Sdimdo_mov16 (void)
7049218822Sdim{
7050218822Sdim  bfd_vma imm;
7051218822Sdim  bfd_boolean top;
705260484Sobrien
7053218822Sdim  top = (inst.instruction & 0x00400000) != 0;
7054218822Sdim  constraint (top && inst.reloc.type == BFD_RELOC_ARM_MOVW,
7055218822Sdim	      _(":lower16: not allowed this instruction"));
7056218822Sdim  constraint (!top && inst.reloc.type == BFD_RELOC_ARM_MOVT,
7057218822Sdim	      _(":upper16: not allowed instruction"));
7058218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7059218822Sdim  if (inst.reloc.type == BFD_RELOC_UNUSED)
706060484Sobrien    {
7061218822Sdim      imm = inst.reloc.exp.X_add_number;
7062218822Sdim      /* The value is in two pieces: 0:11, 16:19.  */
7063218822Sdim      inst.instruction |= (imm & 0x00000fff);
7064218822Sdim      inst.instruction |= (imm & 0x0000f000) << 4;
706560484Sobrien    }
706660484Sobrien}
706760484Sobrien
7068218822Sdimstatic void do_vfp_nsyn_opcode (const char *);
706977298Sobrien
707060484Sobrienstatic int
7071218822Sdimdo_vfp_nsyn_mrs (void)
707260484Sobrien{
7073218822Sdim  if (inst.operands[0].isvec)
707460484Sobrien    {
7075218822Sdim      if (inst.operands[1].reg != 1)
7076218822Sdim        first_error (_("operand 1 must be FPSCR"));
7077218822Sdim      memset (&inst.operands[0], '\0', sizeof (inst.operands[0]));
7078218822Sdim      memset (&inst.operands[1], '\0', sizeof (inst.operands[1]));
7079218822Sdim      do_vfp_nsyn_opcode ("fmstat");
708060484Sobrien    }
7081218822Sdim  else if (inst.operands[1].isvec)
7082218822Sdim    do_vfp_nsyn_opcode ("fmrx");
7083218822Sdim  else
7084218822Sdim    return FAIL;
7085218822Sdim
7086218822Sdim  return SUCCESS;
708760484Sobrien}
708860484Sobrien
708960484Sobrienstatic int
7090218822Sdimdo_vfp_nsyn_msr (void)
709160484Sobrien{
7092218822Sdim  if (inst.operands[0].isvec)
7093218822Sdim    do_vfp_nsyn_opcode ("fmxr");
7094218822Sdim  else
7095218822Sdim    return FAIL;
709677298Sobrien
7097218822Sdim  return SUCCESS;
7098218822Sdim}
709960484Sobrien
7100248460Sandrewstatic int
7101248460Sandrewdo_vfp_vmrs (void)
7102248460Sandrew{
7103248460Sandrew  int rt;
7104248460Sandrew
7105248460Sandrew  /* The destination register can be r0-r14 or APSR_nzcv */
7106248460Sandrew  if (inst.operands[0].reg > 14)
7107248460Sandrew    {
7108248460Sandrew      inst.error = BAD_PC;
7109248460Sandrew      return FAIL;
7110248460Sandrew    }
7111248460Sandrew
7112248460Sandrew  /* If the destination is r13 and not in ARM mode then unprefictable */
7113248460Sandrew  if (thumb_mode && inst.operands[0].reg == REG_SP)
7114248460Sandrew    {
7115248460Sandrew      inst.error = BAD_SP;
7116248460Sandrew      return FAIL;
7117248460Sandrew    }
7118248460Sandrew
7119248460Sandrew  /* If the destination is APSR_nzcv */
7120248460Sandrew  if (inst.operands[0].isvec && inst.operands[1].reg != 1)
7121248460Sandrew    {
7122248460Sandrew      inst.error = BAD_VMRS;
7123248460Sandrew      return FAIL;
7124248460Sandrew    }
7125248460Sandrew
7126248460Sandrew  if (inst.operands[0].isvec)
7127248460Sandrew    rt = 15;
7128248460Sandrew  else
7129248460Sandrew    rt = inst.operands[0].reg;
7130248460Sandrew
7131248460Sandrew  /* Or in the registers to use */
7132248460Sandrew  inst.instruction |= rt << 12;
7133248460Sandrew  inst.instruction |= inst.operands[1].reg << 16;
7134248460Sandrew
7135248460Sandrew  return SUCCESS;
7136248460Sandrew}
7137248460Sandrew
7138248460Sandrewstatic int
7139248460Sandrewdo_vfp_vmsr (void)
7140248460Sandrew{
7141248460Sandrew  /* The destination register can be r0-r14 or APSR_nzcv */
7142248460Sandrew  if (inst.operands[1].reg > 14)
7143248460Sandrew    {
7144248460Sandrew      inst.error = BAD_PC;
7145248460Sandrew      return FAIL;
7146248460Sandrew    }
7147248460Sandrew
7148248460Sandrew  /* If the destination is r13 and not in ARM mode then unprefictable */
7149248460Sandrew  if (thumb_mode && inst.operands[0].reg == REG_SP)
7150248460Sandrew    {
7151248460Sandrew      inst.error = BAD_SP;
7152248460Sandrew      return FAIL;
7153248460Sandrew    }
7154248460Sandrew
7155248460Sandrew  /* Or in the registers to use */
7156248460Sandrew  inst.instruction |= inst.operands[1].reg << 12;
7157248460Sandrew  inst.instruction |= inst.operands[0].reg << 16;
7158248460Sandrew
7159248460Sandrew  return SUCCESS;
7160248460Sandrew}
7161248460Sandrew
7162218822Sdimstatic void
7163218822Sdimdo_mrs (void)
7164218822Sdim{
7165218822Sdim  if (do_vfp_nsyn_mrs () == SUCCESS)
7166218822Sdim    return;
716789857Sobrien
7168218822Sdim  /* mrs only accepts CPSR/SPSR/CPSR_all/SPSR_all.  */
7169218822Sdim  constraint ((inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f))
7170218822Sdim	      != (PSR_c|PSR_f),
7171218822Sdim	      _("'CPSR' or 'SPSR' expected"));
7172218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7173218822Sdim  inst.instruction |= (inst.operands[1].imm & SPSR_BIT);
7174218822Sdim}
717560484Sobrien
7176218822Sdim/* Two possible forms:
7177218822Sdim      "{C|S}PSR_<field>, Rm",
7178218822Sdim      "{C|S}PSR_f, #expression".  */
7179218822Sdim
7180218822Sdimstatic void
7181218822Sdimdo_msr (void)
7182218822Sdim{
7183218822Sdim  if (do_vfp_nsyn_msr () == SUCCESS)
7184218822Sdim    return;
7185218822Sdim
7186218822Sdim  inst.instruction |= inst.operands[0].imm;
7187218822Sdim  if (inst.operands[1].isreg)
7188218822Sdim    inst.instruction |= inst.operands[1].reg;
7189218822Sdim  else
719060484Sobrien    {
7191218822Sdim      inst.instruction |= INST_IMMEDIATE;
7192218822Sdim      inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
7193218822Sdim      inst.reloc.pc_rel = 0;
719460484Sobrien    }
719560484Sobrien}
719660484Sobrien
7197218822Sdimstatic void
7198218822Sdimdo_mul (void)
719989857Sobrien{
7200218822Sdim  if (!inst.operands[2].present)
7201218822Sdim    inst.operands[2].reg = inst.operands[0].reg;
7202218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7203218822Sdim  inst.instruction |= inst.operands[1].reg;
7204218822Sdim  inst.instruction |= inst.operands[2].reg << 8;
7205218822Sdim
7206218822Sdim  if (inst.operands[0].reg == inst.operands[1].reg
7207218822Sdim      && !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6))
7208218822Sdim    as_tsktsk (_("Rd and Rm should be different in mul"));
720989857Sobrien}
721089857Sobrien
7211218822Sdim/* Long Multiply Parser
7212218822Sdim   UMULL RdLo, RdHi, Rm, Rs
7213218822Sdim   SMULL RdLo, RdHi, Rm, Rs
7214218822Sdim   UMLAL RdLo, RdHi, Rm, Rs
7215218822Sdim   SMLAL RdLo, RdHi, Rm, Rs.  */
721660484Sobrien
7217218822Sdimstatic void
7218218822Sdimdo_mull (void)
721960484Sobrien{
7220218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7221218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7222218822Sdim  inst.instruction |= inst.operands[2].reg;
7223218822Sdim  inst.instruction |= inst.operands[3].reg << 8;
722477298Sobrien
7225218822Sdim  /* rdhi, rdlo and rm must all be different.  */
7226218822Sdim  if (inst.operands[0].reg == inst.operands[1].reg
7227218822Sdim      || inst.operands[0].reg == inst.operands[2].reg
7228218822Sdim      || inst.operands[1].reg == inst.operands[2].reg)
7229218822Sdim    as_tsktsk (_("rdhi, rdlo and rm must all be different"));
7230218822Sdim}
723177298Sobrien
7232218822Sdimstatic void
7233218822Sdimdo_nop (void)
7234218822Sdim{
7235218822Sdim  if (inst.operands[0].present)
723660484Sobrien    {
7237218822Sdim      /* Architectural NOP hints are CPSR sets with no bits selected.  */
7238218822Sdim      inst.instruction &= 0xf0000000;
7239218822Sdim      inst.instruction |= 0x0320f000 + inst.operands[0].imm;
724060484Sobrien    }
7241218822Sdim}
724260484Sobrien
7243218822Sdim/* ARM V6 Pack Halfword Bottom Top instruction (argument parse).
7244218822Sdim   PKHBT {<cond>} <Rd>, <Rn>, <Rm> {, LSL #<shift_imm>}
7245218822Sdim   Condition defaults to COND_ALWAYS.
7246218822Sdim   Error if Rd, Rn or Rm are R15.  */
724777298Sobrien
7248218822Sdimstatic void
7249218822Sdimdo_pkhbt (void)
7250218822Sdim{
7251218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7252218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7253218822Sdim  inst.instruction |= inst.operands[2].reg;
7254218822Sdim  if (inst.operands[3].present)
7255218822Sdim    encode_arm_shift (3);
7256218822Sdim}
725760484Sobrien
7258218822Sdim/* ARM V6 PKHTB (Argument Parse).  */
725960484Sobrien
7260218822Sdimstatic void
7261218822Sdimdo_pkhtb (void)
7262218822Sdim{
7263218822Sdim  if (!inst.operands[3].present)
7264130561Sobrien    {
7265218822Sdim      /* If the shift specifier is omitted, turn the instruction
7266218822Sdim	 into pkhbt rd, rm, rn. */
7267218822Sdim      inst.instruction &= 0xfff00010;
7268218822Sdim      inst.instruction |= inst.operands[0].reg << 12;
7269218822Sdim      inst.instruction |= inst.operands[1].reg;
7270218822Sdim      inst.instruction |= inst.operands[2].reg << 16;
7271130561Sobrien    }
7272218822Sdim  else
7273130561Sobrien    {
7274218822Sdim      inst.instruction |= inst.operands[0].reg << 12;
7275218822Sdim      inst.instruction |= inst.operands[1].reg << 16;
7276218822Sdim      inst.instruction |= inst.operands[2].reg;
7277218822Sdim      encode_arm_shift (3);
7278130561Sobrien    }
7279218822Sdim}
728060484Sobrien
7281218822Sdim/* ARMv5TE: Preload-Cache
728260484Sobrien
7283218822Sdim    PLD <addr_mode>
728460484Sobrien
7285218822Sdim  Syntactically, like LDR with B=1, W=0, L=1.  */
728660484Sobrien
7287218822Sdimstatic void
7288218822Sdimdo_pld (void)
7289218822Sdim{
7290218822Sdim  constraint (!inst.operands[0].isreg,
7291218822Sdim	      _("'[' expected after PLD mnemonic"));
7292218822Sdim  constraint (inst.operands[0].postind,
7293218822Sdim	      _("post-indexed expression used in preload instruction"));
7294218822Sdim  constraint (inst.operands[0].writeback,
7295218822Sdim	      _("writeback used in preload instruction"));
7296218822Sdim  constraint (!inst.operands[0].preind,
7297218822Sdim	      _("unindexed addressing used in preload instruction"));
7298218822Sdim  encode_arm_addr_mode_2 (0, /*is_t=*/FALSE);
7299218822Sdim}
730060484Sobrien
7301218822Sdim/* ARMv7: PLI <addr_mode>  */
7302218822Sdimstatic void
7303218822Sdimdo_pli (void)
7304218822Sdim{
7305218822Sdim  constraint (!inst.operands[0].isreg,
7306218822Sdim	      _("'[' expected after PLI mnemonic"));
7307218822Sdim  constraint (inst.operands[0].postind,
7308218822Sdim	      _("post-indexed expression used in preload instruction"));
7309218822Sdim  constraint (inst.operands[0].writeback,
7310218822Sdim	      _("writeback used in preload instruction"));
7311218822Sdim  constraint (!inst.operands[0].preind,
7312218822Sdim	      _("unindexed addressing used in preload instruction"));
7313218822Sdim  encode_arm_addr_mode_2 (0, /*is_t=*/FALSE);
7314218822Sdim  inst.instruction &= ~PRE_INDEX;
7315218822Sdim}
731677298Sobrien
7317218822Sdimstatic void
7318218822Sdimdo_push_pop (void)
7319218822Sdim{
7320218822Sdim  inst.operands[1] = inst.operands[0];
7321218822Sdim  memset (&inst.operands[0], 0, sizeof inst.operands[0]);
7322218822Sdim  inst.operands[0].isreg = 1;
7323218822Sdim  inst.operands[0].writeback = 1;
7324218822Sdim  inst.operands[0].reg = REG_SP;
7325218822Sdim  do_ldmstm ();
7326218822Sdim}
732777298Sobrien
7328218822Sdim/* ARM V6 RFE (Return from Exception) loads the PC and CPSR from the
7329218822Sdim   word at the specified address and the following word
7330218822Sdim   respectively.
7331218822Sdim   Unconditionally executed.
7332218822Sdim   Error if Rn is R15.	*/
733377298Sobrien
7334218822Sdimstatic void
7335218822Sdimdo_rfe (void)
7336218822Sdim{
7337218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7338218822Sdim  if (inst.operands[0].writeback)
7339218822Sdim    inst.instruction |= WRITE_BACK;
734060484Sobrien}
734160484Sobrien
7342218822Sdim/* ARM V6 ssat (argument parse).  */
734377298Sobrien
7344218822Sdimstatic void
7345218822Sdimdo_ssat (void)
734660484Sobrien{
7347218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7348218822Sdim  inst.instruction |= (inst.operands[1].imm - 1) << 16;
7349218822Sdim  inst.instruction |= inst.operands[2].reg;
735060484Sobrien
7351218822Sdim  if (inst.operands[3].present)
7352218822Sdim    encode_arm_shift (3);
7353218822Sdim}
735460484Sobrien
7355218822Sdim/* ARM V6 usat (argument parse).  */
735660484Sobrien
7357218822Sdimstatic void
7358218822Sdimdo_usat (void)
7359218822Sdim{
7360218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7361218822Sdim  inst.instruction |= inst.operands[1].imm << 16;
7362218822Sdim  inst.instruction |= inst.operands[2].reg;
736360484Sobrien
7364218822Sdim  if (inst.operands[3].present)
7365218822Sdim    encode_arm_shift (3);
7366218822Sdim}
736760484Sobrien
7368218822Sdim/* ARM V6 ssat16 (argument parse).  */
736960484Sobrien
7370218822Sdimstatic void
7371218822Sdimdo_ssat16 (void)
7372218822Sdim{
7373218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7374218822Sdim  inst.instruction |= ((inst.operands[1].imm - 1) << 16);
7375218822Sdim  inst.instruction |= inst.operands[2].reg;
7376218822Sdim}
737760484Sobrien
7378218822Sdimstatic void
7379218822Sdimdo_usat16 (void)
7380218822Sdim{
7381218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7382218822Sdim  inst.instruction |= inst.operands[1].imm << 16;
7383218822Sdim  inst.instruction |= inst.operands[2].reg;
7384218822Sdim}
738560484Sobrien
7386218822Sdim/* ARM V6 SETEND (argument parse).  Sets the E bit in the CPSR while
7387218822Sdim   preserving the other bits.
738860484Sobrien
7389218822Sdim   setend <endian_specifier>, where <endian_specifier> is either
7390218822Sdim   BE or LE.  */
739160484Sobrien
7392218822Sdimstatic void
7393218822Sdimdo_setend (void)
7394218822Sdim{
7395218822Sdim  if (inst.operands[0].imm)
7396218822Sdim    inst.instruction |= 0x200;
7397218822Sdim}
739860484Sobrien
7399218822Sdimstatic void
7400218822Sdimdo_shift (void)
7401218822Sdim{
7402218822Sdim  unsigned int Rm = (inst.operands[1].present
7403218822Sdim		     ? inst.operands[1].reg
7404218822Sdim		     : inst.operands[0].reg);
740560484Sobrien
7406218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7407218822Sdim  inst.instruction |= Rm;
7408218822Sdim  if (inst.operands[2].isreg)  /* Rd, {Rm,} Rs */
7409218822Sdim    {
7410218822Sdim      inst.instruction |= inst.operands[2].reg << 8;
7411218822Sdim      inst.instruction |= SHIFT_BY_REG;
741260484Sobrien    }
7413218822Sdim  else
7414218822Sdim    inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
7415218822Sdim}
741660484Sobrien
7417218822Sdimstatic void
7418218822Sdimdo_smc (void)
7419218822Sdim{
7420218822Sdim  inst.reloc.type = BFD_RELOC_ARM_SMC;
7421218822Sdim  inst.reloc.pc_rel = 0;
7422218822Sdim}
742360484Sobrien
7424218822Sdimstatic void
7425218822Sdimdo_swi (void)
7426218822Sdim{
7427218822Sdim  inst.reloc.type = BFD_RELOC_ARM_SWI;
7428218822Sdim  inst.reloc.pc_rel = 0;
742960484Sobrien}
743060484Sobrien
7431218822Sdim/* ARM V5E (El Segundo) signed-multiply-accumulate (argument parse)
7432218822Sdim   SMLAxy{cond} Rd,Rm,Rs,Rn
7433218822Sdim   SMLAWy{cond} Rd,Rm,Rs,Rn
7434218822Sdim   Error if any register is R15.  */
7435218822Sdim
7436218822Sdimstatic void
7437218822Sdimdo_smla (void)
743860484Sobrien{
7439218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7440218822Sdim  inst.instruction |= inst.operands[1].reg;
7441218822Sdim  inst.instruction |= inst.operands[2].reg << 8;
7442218822Sdim  inst.instruction |= inst.operands[3].reg << 12;
7443218822Sdim}
744460484Sobrien
7445218822Sdim/* ARM V5E (El Segundo) signed-multiply-accumulate-long (argument parse)
7446218822Sdim   SMLALxy{cond} Rdlo,Rdhi,Rm,Rs
7447218822Sdim   Error if any register is R15.
7448218822Sdim   Warning if Rdlo == Rdhi.  */
744977298Sobrien
7450218822Sdimstatic void
7451218822Sdimdo_smlal (void)
7452218822Sdim{
7453218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7454218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7455218822Sdim  inst.instruction |= inst.operands[2].reg;
7456218822Sdim  inst.instruction |= inst.operands[3].reg << 8;
7457218822Sdim
7458218822Sdim  if (inst.operands[0].reg == inst.operands[1].reg)
7459218822Sdim    as_tsktsk (_("rdhi and rdlo must be different"));
7460218822Sdim}
7461218822Sdim
7462218822Sdim/* ARM V5E (El Segundo) signed-multiply (argument parse)
7463218822Sdim   SMULxy{cond} Rd,Rm,Rs
7464218822Sdim   Error if any register is R15.  */
7465218822Sdim
7466218822Sdimstatic void
7467218822Sdimdo_smul (void)
7468218822Sdim{
7469218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7470218822Sdim  inst.instruction |= inst.operands[1].reg;
7471218822Sdim  inst.instruction |= inst.operands[2].reg << 8;
7472218822Sdim}
7473218822Sdim
7474218822Sdim/* ARM V6 srs (argument parse).  The variable fields in the encoding are
7475218822Sdim   the same for both ARM and Thumb-2.  */
7476218822Sdim
7477218822Sdimstatic void
7478218822Sdimdo_srs (void)
7479218822Sdim{
7480218822Sdim  int reg;
7481218822Sdim
7482218822Sdim  if (inst.operands[0].present)
748360484Sobrien    {
7484218822Sdim      reg = inst.operands[0].reg;
7485218822Sdim      constraint (reg != 13, _("SRS base register must be r13"));
748660484Sobrien    }
748760484Sobrien  else
7488218822Sdim    reg = 13;
748977298Sobrien
7490218822Sdim  inst.instruction |= reg << 16;
7491218822Sdim  inst.instruction |= inst.operands[1].imm;
7492218822Sdim  if (inst.operands[0].writeback || inst.operands[1].writeback)
7493218822Sdim    inst.instruction |= WRITE_BACK;
7494218822Sdim}
749560484Sobrien
7496218822Sdim/* ARM V6 strex (argument parse).  */
749760484Sobrien
7498218822Sdimstatic void
7499218822Sdimdo_strex (void)
7500218822Sdim{
7501218822Sdim  constraint (!inst.operands[2].isreg || !inst.operands[2].preind
7502218822Sdim	      || inst.operands[2].postind || inst.operands[2].writeback
7503218822Sdim	      || inst.operands[2].immisreg || inst.operands[2].shifted
7504218822Sdim	      || inst.operands[2].negative
7505218822Sdim	      /* See comment in do_ldrex().  */
7506218822Sdim	      || (inst.operands[2].reg == REG_PC),
7507218822Sdim	      BAD_ADDR_MODE);
750877298Sobrien
7509218822Sdim  constraint (inst.operands[0].reg == inst.operands[1].reg
7510218822Sdim	      || inst.operands[0].reg == inst.operands[2].reg, BAD_OVERLAP);
751160484Sobrien
7512218822Sdim  constraint (inst.reloc.exp.X_op != O_constant
7513218822Sdim	      || inst.reloc.exp.X_add_number != 0,
7514218822Sdim	      _("offset must be zero in ARM encoding"));
751560484Sobrien
7516218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7517218822Sdim  inst.instruction |= inst.operands[1].reg;
7518218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
7519218822Sdim  inst.reloc.type = BFD_RELOC_UNUSED;
7520218822Sdim}
752160484Sobrien
7522218822Sdimstatic void
7523218822Sdimdo_strexd (void)
7524218822Sdim{
7525218822Sdim  constraint (inst.operands[1].reg % 2 != 0,
7526218822Sdim	      _("even register required"));
7527218822Sdim  constraint (inst.operands[2].present
7528218822Sdim	      && inst.operands[2].reg != inst.operands[1].reg + 1,
7529218822Sdim	      _("can only store two consecutive registers"));
7530218822Sdim  /* If op 2 were present and equal to PC, this function wouldn't
7531218822Sdim     have been called in the first place.  */
7532218822Sdim  constraint (inst.operands[1].reg == REG_LR, _("r14 not allowed here"));
753360484Sobrien
7534218822Sdim  constraint (inst.operands[0].reg == inst.operands[1].reg
7535218822Sdim	      || inst.operands[0].reg == inst.operands[1].reg + 1
7536218822Sdim	      || inst.operands[0].reg == inst.operands[3].reg,
7537218822Sdim	      BAD_OVERLAP);
753860484Sobrien
7539218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7540218822Sdim  inst.instruction |= inst.operands[1].reg;
7541218822Sdim  inst.instruction |= inst.operands[3].reg << 16;
754260484Sobrien}
754360484Sobrien
7544218822Sdim/* ARM V6 SXTAH extracts a 16-bit value from a register, sign
7545218822Sdim   extends it to 32-bits, and adds the result to a value in another
7546218822Sdim   register.  You can specify a rotation by 0, 8, 16, or 24 bits
7547218822Sdim   before extracting the 16-bit value.
7548218822Sdim   SXTAH{<cond>} <Rd>, <Rn>, <Rm>{, <rotation>}
7549218822Sdim   Condition defaults to COND_ALWAYS.
7550218822Sdim   Error if any register uses R15.  */
7551218822Sdim
7552218822Sdimstatic void
7553218822Sdimdo_sxtah (void)
755460484Sobrien{
7555218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7556218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7557218822Sdim  inst.instruction |= inst.operands[2].reg;
7558218822Sdim  inst.instruction |= inst.operands[3].imm << 10;
7559218822Sdim}
756060484Sobrien
7561218822Sdim/* ARM V6 SXTH.
756260484Sobrien
7563218822Sdim   SXTH {<cond>} <Rd>, <Rm>{, <rotation>}
7564218822Sdim   Condition defaults to COND_ALWAYS.
7565218822Sdim   Error if any register uses R15.  */
756660484Sobrien
7567218822Sdimstatic void
7568218822Sdimdo_sxth (void)
7569218822Sdim{
7570218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7571218822Sdim  inst.instruction |= inst.operands[1].reg;
7572218822Sdim  inst.instruction |= inst.operands[2].imm << 10;
7573218822Sdim}
7574218822Sdim
7575218822Sdim/* VFP instructions.  In a logical order: SP variant first, monad
7576218822Sdim   before dyad, arithmetic then move then load/store.  */
757760484Sobrien
7578218822Sdimstatic void
7579218822Sdimdo_vfp_sp_monadic (void)
7580218822Sdim{
7581218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7582218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sm);
7583218822Sdim}
758460484Sobrien
7585218822Sdimstatic void
7586218822Sdimdo_vfp_sp_dyadic (void)
7587218822Sdim{
7588218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7589218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sn);
7590218822Sdim  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Sm);
7591218822Sdim}
759260484Sobrien
7593218822Sdimstatic void
7594218822Sdimdo_vfp_sp_compare_z (void)
7595218822Sdim{
7596218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7597218822Sdim}
759860484Sobrien
7599218822Sdimstatic void
7600218822Sdimdo_vfp_dp_sp_cvt (void)
7601218822Sdim{
7602218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7603218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sm);
7604218822Sdim}
760560484Sobrien
7606218822Sdimstatic void
7607218822Sdimdo_vfp_sp_dp_cvt (void)
7608218822Sdim{
7609218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7610218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dm);
761160484Sobrien}
761260484Sobrien
761360484Sobrienstatic void
7614218822Sdimdo_vfp_reg_from_sp (void)
761560484Sobrien{
7616218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7617218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sn);
7618218822Sdim}
761960484Sobrien
7620218822Sdimstatic void
7621218822Sdimdo_vfp_reg2_from_sp2 (void)
7622218822Sdim{
7623218822Sdim  constraint (inst.operands[2].imm != 2,
7624218822Sdim	      _("only two consecutive VFP SP registers allowed here"));
7625218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7626218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7627218822Sdim  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Sm);
7628218822Sdim}
762960484Sobrien
7630218822Sdimstatic void
7631218822Sdimdo_vfp_sp_from_reg (void)
7632218822Sdim{
7633218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sn);
7634218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
763560484Sobrien}
763660484Sobrien
763760484Sobrienstatic void
7638218822Sdimdo_vfp_sp2_from_reg2 (void)
763960484Sobrien{
7640218822Sdim  constraint (inst.operands[0].imm != 2,
7641218822Sdim	      _("only two consecutive VFP SP registers allowed here"));
7642218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sm);
7643218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
7644218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
7645218822Sdim}
764660484Sobrien
7647218822Sdimstatic void
7648218822Sdimdo_vfp_sp_ldst (void)
7649218822Sdim{
7650218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7651218822Sdim  encode_arm_cp_address (1, FALSE, TRUE, 0);
7652218822Sdim}
765377298Sobrien
7654218822Sdimstatic void
7655218822Sdimdo_vfp_dp_ldst (void)
7656218822Sdim{
7657218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7658218822Sdim  encode_arm_cp_address (1, FALSE, TRUE, 0);
7659218822Sdim}
766077298Sobrien
7661218822Sdim
7662218822Sdimstatic void
7663218822Sdimvfp_sp_ldstm (enum vfp_ldstm_type ldstm_type)
7664218822Sdim{
7665218822Sdim  if (inst.operands[0].writeback)
7666218822Sdim    inst.instruction |= WRITE_BACK;
7667218822Sdim  else
7668218822Sdim    constraint (ldstm_type != VFP_LDSTMIA,
7669218822Sdim		_("this addressing mode requires base-register writeback"));
7670218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7671218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sd);
7672218822Sdim  inst.instruction |= inst.operands[1].imm;
767360484Sobrien}
767460484Sobrien
767560484Sobrienstatic void
7676218822Sdimvfp_dp_ldstm (enum vfp_ldstm_type ldstm_type)
767760484Sobrien{
7678218822Sdim  int count;
767960484Sobrien
7680218822Sdim  if (inst.operands[0].writeback)
7681218822Sdim    inst.instruction |= WRITE_BACK;
7682218822Sdim  else
7683218822Sdim    constraint (ldstm_type != VFP_LDSTMIA && ldstm_type != VFP_LDSTMIAX,
7684218822Sdim		_("this addressing mode requires base-register writeback"));
768560484Sobrien
7686218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7687218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dd);
768889857Sobrien
7689218822Sdim  count = inst.operands[1].imm << 1;
7690218822Sdim  if (ldstm_type == VFP_LDSTMIAX || ldstm_type == VFP_LDSTMDBX)
7691218822Sdim    count += 1;
769277298Sobrien
7693218822Sdim  inst.instruction |= count;
769460484Sobrien}
769560484Sobrien
769660484Sobrienstatic void
7697218822Sdimdo_vfp_sp_ldstmia (void)
769860484Sobrien{
7699218822Sdim  vfp_sp_ldstm (VFP_LDSTMIA);
7700218822Sdim}
770160484Sobrien
7702218822Sdimstatic void
7703218822Sdimdo_vfp_sp_ldstmdb (void)
7704218822Sdim{
7705218822Sdim  vfp_sp_ldstm (VFP_LDSTMDB);
7706218822Sdim}
770760484Sobrien
7708218822Sdimstatic void
7709218822Sdimdo_vfp_dp_ldstmia (void)
7710218822Sdim{
7711218822Sdim  vfp_dp_ldstm (VFP_LDSTMIA);
7712218822Sdim}
771360484Sobrien
7714218822Sdimstatic void
7715218822Sdimdo_vfp_dp_ldstmdb (void)
7716218822Sdim{
7717218822Sdim  vfp_dp_ldstm (VFP_LDSTMDB);
771860484Sobrien}
771960484Sobrien
772060484Sobrienstatic void
7721218822Sdimdo_vfp_xp_ldstmia (void)
772260484Sobrien{
7723218822Sdim  vfp_dp_ldstm (VFP_LDSTMIAX);
7724218822Sdim}
772560484Sobrien
7726218822Sdimstatic void
7727218822Sdimdo_vfp_xp_ldstmdb (void)
7728218822Sdim{
7729218822Sdim  vfp_dp_ldstm (VFP_LDSTMDBX);
7730218822Sdim}
773160484Sobrien
7732218822Sdimstatic void
7733218822Sdimdo_vfp_dp_rd_rm (void)
7734218822Sdim{
7735218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7736218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dm);
7737218822Sdim}
773860484Sobrien
7739218822Sdimstatic void
7740218822Sdimdo_vfp_dp_rn_rd (void)
7741218822Sdim{
7742218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dn);
7743218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dd);
774460484Sobrien}
774560484Sobrien
7746218822Sdimstatic void
7747218822Sdimdo_vfp_dp_rd_rn (void)
774860484Sobrien{
7749218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7750218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dn);
7751218822Sdim}
775260484Sobrien
7753218822Sdimstatic void
7754218822Sdimdo_vfp_dp_rd_rn_rm (void)
7755218822Sdim{
7756218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7757218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dn);
7758218822Sdim  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Dm);
7759218822Sdim}
776060484Sobrien
7761218822Sdimstatic void
7762218822Sdimdo_vfp_dp_rd (void)
7763218822Sdim{
7764218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7765218822Sdim}
776660484Sobrien
7767218822Sdimstatic void
7768218822Sdimdo_vfp_dp_rm_rd_rn (void)
7769218822Sdim{
7770218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dm);
7771218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dd);
7772218822Sdim  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Dn);
7773218822Sdim}
777460484Sobrien
7775218822Sdim/* VFPv3 instructions.  */
7776218822Sdimstatic void
7777218822Sdimdo_vfp_sp_const (void)
7778218822Sdim{
7779218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7780218822Sdim  inst.instruction |= (inst.operands[1].imm & 0xf0) << 12;
7781218822Sdim  inst.instruction |= (inst.operands[1].imm & 0x0f);
7782218822Sdim}
778360484Sobrien
7784218822Sdimstatic void
7785218822Sdimdo_vfp_dp_const (void)
7786218822Sdim{
7787218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7788218822Sdim  inst.instruction |= (inst.operands[1].imm & 0xf0) << 12;
7789218822Sdim  inst.instruction |= (inst.operands[1].imm & 0x0f);
7790218822Sdim}
779160484Sobrien
7792218822Sdimstatic void
7793218822Sdimvfp_conv (int srcsize)
7794218822Sdim{
7795218822Sdim  unsigned immbits = srcsize - inst.operands[1].imm;
7796218822Sdim  inst.instruction |= (immbits & 1) << 5;
7797218822Sdim  inst.instruction |= (immbits >> 1);
7798218822Sdim}
779977298Sobrien
7800218822Sdimstatic void
7801218822Sdimdo_vfp_sp_conv_16 (void)
7802218822Sdim{
7803218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7804218822Sdim  vfp_conv (16);
7805218822Sdim}
780677298Sobrien
7807218822Sdimstatic void
7808218822Sdimdo_vfp_dp_conv_16 (void)
7809218822Sdim{
7810218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7811218822Sdim  vfp_conv (16);
7812218822Sdim}
781360484Sobrien
7814218822Sdimstatic void
7815218822Sdimdo_vfp_sp_conv_32 (void)
7816218822Sdim{
7817218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7818218822Sdim  vfp_conv (32);
781960484Sobrien}
782060484Sobrien
782160484Sobrienstatic void
7822218822Sdimdo_vfp_dp_conv_32 (void)
782360484Sobrien{
7824218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7825218822Sdim  vfp_conv (32);
7826218822Sdim}
782760484Sobrien
7828218822Sdim
7829218822Sdim/* FPA instructions.  Also in a logical order.	*/
783089857Sobrien
7831218822Sdimstatic void
7832218822Sdimdo_fpa_cmp (void)
7833218822Sdim{
7834218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7835218822Sdim  inst.instruction |= inst.operands[1].reg;
7836218822Sdim}
783789857Sobrien
7838218822Sdimstatic void
7839218822Sdimdo_fpa_ldmstm (void)
7840218822Sdim{
7841218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7842218822Sdim  switch (inst.operands[1].imm)
784389857Sobrien    {
7844218822Sdim    case 1: inst.instruction |= CP_T_X;		 break;
7845218822Sdim    case 2: inst.instruction |= CP_T_Y;		 break;
7846218822Sdim    case 3: inst.instruction |= CP_T_Y | CP_T_X; break;
7847218822Sdim    case 4:					 break;
7848218822Sdim    default: abort ();
784989857Sobrien    }
785089857Sobrien
7851218822Sdim  if (inst.instruction & (PRE_INDEX | INDEX_UP))
785289857Sobrien    {
7853218822Sdim      /* The instruction specified "ea" or "fd", so we can only accept
7854218822Sdim	 [Rn]{!}.  The instruction does not really support stacking or
7855218822Sdim	 unstacking, so we have to emulate these by setting appropriate
7856218822Sdim	 bits and offsets.  */
7857218822Sdim      constraint (inst.reloc.exp.X_op != O_constant
7858218822Sdim		  || inst.reloc.exp.X_add_number != 0,
7859218822Sdim		  _("this instruction does not support indexing"));
786089857Sobrien
7861218822Sdim      if ((inst.instruction & PRE_INDEX) || inst.operands[2].writeback)
7862218822Sdim	inst.reloc.exp.X_add_number = 12 * inst.operands[1].imm;
786389857Sobrien
7864218822Sdim      if (!(inst.instruction & INDEX_UP))
7865218822Sdim	inst.reloc.exp.X_add_number = -inst.reloc.exp.X_add_number;
786689857Sobrien
7867218822Sdim      if (!(inst.instruction & PRE_INDEX) && inst.operands[2].writeback)
7868218822Sdim	{
7869218822Sdim	  inst.operands[2].preind = 0;
7870218822Sdim	  inst.operands[2].postind = 1;
7871218822Sdim	}
7872218822Sdim    }
787389857Sobrien
7874218822Sdim  encode_arm_cp_address (2, TRUE, TRUE, 0);
7875218822Sdim}
787689857Sobrien
7877218822Sdim
7878218822Sdim/* iWMMXt instructions: strictly in alphabetical order.	 */
787989857Sobrien
7880218822Sdimstatic void
7881218822Sdimdo_iwmmxt_tandorc (void)
7882218822Sdim{
7883218822Sdim  constraint (inst.operands[0].reg != REG_PC, _("only r15 allowed here"));
7884218822Sdim}
788589857Sobrien
7886218822Sdimstatic void
7887218822Sdimdo_iwmmxt_textrc (void)
7888218822Sdim{
7889218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7890218822Sdim  inst.instruction |= inst.operands[1].imm;
7891218822Sdim}
789289857Sobrien
7893218822Sdimstatic void
7894218822Sdimdo_iwmmxt_textrm (void)
7895218822Sdim{
7896218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7897218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7898218822Sdim  inst.instruction |= inst.operands[2].imm;
7899218822Sdim}
790089857Sobrien
7901218822Sdimstatic void
7902218822Sdimdo_iwmmxt_tinsr (void)
7903218822Sdim{
7904218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7905218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
7906218822Sdim  inst.instruction |= inst.operands[2].imm;
7907218822Sdim}
790889857Sobrien
7909218822Sdimstatic void
7910218822Sdimdo_iwmmxt_tmia (void)
7911218822Sdim{
7912218822Sdim  inst.instruction |= inst.operands[0].reg << 5;
7913218822Sdim  inst.instruction |= inst.operands[1].reg;
7914218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
7915218822Sdim}
791689857Sobrien
7917218822Sdimstatic void
7918218822Sdimdo_iwmmxt_waligni (void)
7919218822Sdim{
7920218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7921218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7922218822Sdim  inst.instruction |= inst.operands[2].reg;
7923218822Sdim  inst.instruction |= inst.operands[3].imm << 20;
7924218822Sdim}
792589857Sobrien
7926218822Sdimstatic void
7927218822Sdimdo_iwmmxt_wmerge (void)
7928218822Sdim{
7929218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7930218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7931218822Sdim  inst.instruction |= inst.operands[2].reg;
7932218822Sdim  inst.instruction |= inst.operands[3].imm << 21;
7933218822Sdim}
793489857Sobrien
7935218822Sdimstatic void
7936218822Sdimdo_iwmmxt_wmov (void)
7937218822Sdim{
7938218822Sdim  /* WMOV rD, rN is an alias for WOR rD, rN, rN.  */
7939218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7940218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7941218822Sdim  inst.instruction |= inst.operands[1].reg;
7942218822Sdim}
794389857Sobrien
7944218822Sdimstatic void
7945218822Sdimdo_iwmmxt_wldstbh (void)
7946218822Sdim{
7947218822Sdim  int reloc;
7948218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7949218822Sdim  if (thumb_mode)
7950218822Sdim    reloc = BFD_RELOC_ARM_T32_CP_OFF_IMM_S2;
7951218822Sdim  else
7952218822Sdim    reloc = BFD_RELOC_ARM_CP_OFF_IMM_S2;
7953218822Sdim  encode_arm_cp_address (1, TRUE, FALSE, reloc);
7954218822Sdim}
7955218822Sdim
7956218822Sdimstatic void
7957218822Sdimdo_iwmmxt_wldstw (void)
7958218822Sdim{
7959218822Sdim  /* RIWR_RIWC clears .isreg for a control register.  */
7960218822Sdim  if (!inst.operands[0].isreg)
7961218822Sdim    {
7962218822Sdim      constraint (inst.cond != COND_ALWAYS, BAD_COND);
7963218822Sdim      inst.instruction |= 0xf0000000;
796489857Sobrien    }
796560484Sobrien
7966218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7967218822Sdim  encode_arm_cp_address (1, TRUE, TRUE, 0);
7968218822Sdim}
796960484Sobrien
7970218822Sdimstatic void
7971218822Sdimdo_iwmmxt_wldstd (void)
7972218822Sdim{
7973218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7974218822Sdim  if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2)
7975218822Sdim      && inst.operands[1].immisreg)
7976218822Sdim    {
7977218822Sdim      inst.instruction &= ~0x1a000ff;
7978218822Sdim      inst.instruction |= (0xf << 28);
7979218822Sdim      if (inst.operands[1].preind)
7980218822Sdim	inst.instruction |= PRE_INDEX;
7981218822Sdim      if (!inst.operands[1].negative)
7982218822Sdim	inst.instruction |= INDEX_UP;
7983218822Sdim      if (inst.operands[1].writeback)
7984218822Sdim	inst.instruction |= WRITE_BACK;
7985218822Sdim      inst.instruction |= inst.operands[1].reg << 16;
7986218822Sdim      inst.instruction |= inst.reloc.exp.X_add_number << 4;
7987218822Sdim      inst.instruction |= inst.operands[1].imm;
7988218822Sdim    }
7989218822Sdim  else
7990218822Sdim    encode_arm_cp_address (1, TRUE, FALSE, 0);
7991218822Sdim}
799289857Sobrien
7993218822Sdimstatic void
7994218822Sdimdo_iwmmxt_wshufh (void)
7995218822Sdim{
7996218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7997218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7998218822Sdim  inst.instruction |= ((inst.operands[2].imm & 0xf0) << 16);
7999218822Sdim  inst.instruction |= (inst.operands[2].imm & 0x0f);
8000218822Sdim}
800189857Sobrien
8002218822Sdimstatic void
8003218822Sdimdo_iwmmxt_wzero (void)
8004218822Sdim{
8005218822Sdim  /* WZERO reg is an alias for WANDN reg, reg, reg.  */
8006218822Sdim  inst.instruction |= inst.operands[0].reg;
8007218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
8008218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
8009218822Sdim}
801089857Sobrien
8011218822Sdimstatic void
8012218822Sdimdo_iwmmxt_wrwrwr_or_imm5 (void)
8013218822Sdim{
8014218822Sdim  if (inst.operands[2].isreg)
8015218822Sdim    do_rd_rn_rm ();
8016218822Sdim  else {
8017218822Sdim    constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2),
8018218822Sdim		_("immediate operand requires iWMMXt2"));
8019218822Sdim    do_rd_rn ();
8020218822Sdim    if (inst.operands[2].imm == 0)
8021218822Sdim      {
8022218822Sdim	switch ((inst.instruction >> 20) & 0xf)
8023218822Sdim	  {
8024218822Sdim	  case 4:
8025218822Sdim	  case 5:
8026218822Sdim	  case 6:
8027218822Sdim	  case 7:
8028218822Sdim	    /* w...h wrd, wrn, #0 -> wrorh wrd, wrn, #16.  */
8029218822Sdim	    inst.operands[2].imm = 16;
8030218822Sdim	    inst.instruction = (inst.instruction & 0xff0fffff) | (0x7 << 20);
8031218822Sdim	    break;
8032218822Sdim	  case 8:
8033218822Sdim	  case 9:
8034218822Sdim	  case 10:
8035218822Sdim	  case 11:
8036218822Sdim	    /* w...w wrd, wrn, #0 -> wrorw wrd, wrn, #32.  */
8037218822Sdim	    inst.operands[2].imm = 32;
8038218822Sdim	    inst.instruction = (inst.instruction & 0xff0fffff) | (0xb << 20);
8039218822Sdim	    break;
8040218822Sdim	  case 12:
8041218822Sdim	  case 13:
8042218822Sdim	  case 14:
8043218822Sdim	  case 15:
804489857Sobrien	    {
8045218822Sdim	      /* w...d wrd, wrn, #0 -> wor wrd, wrn, wrn.  */
8046218822Sdim	      unsigned long wrn;
8047218822Sdim	      wrn = (inst.instruction >> 16) & 0xf;
8048218822Sdim	      inst.instruction &= 0xff0fff0f;
8049218822Sdim	      inst.instruction |= wrn;
8050218822Sdim	      /* Bail out here; the instruction is now assembled.  */
805189857Sobrien	      return;
805289857Sobrien	    }
8053218822Sdim	  }
8054218822Sdim      }
8055218822Sdim    /* Map 32 -> 0, etc.  */
8056218822Sdim    inst.operands[2].imm &= 0x1f;
8057218822Sdim    inst.instruction |= (0xf << 28) | ((inst.operands[2].imm & 0x10) << 4) | (inst.operands[2].imm & 0xf);
8058218822Sdim  }
8059218822Sdim}
8060218822Sdim
8061218822Sdim/* Cirrus Maverick instructions.  Simple 2-, 3-, and 4-register
8062218822Sdim   operations first, then control, shift, and load/store.  */
806389857Sobrien
8064218822Sdim/* Insns like "foo X,Y,Z".  */
806589857Sobrien
8066218822Sdimstatic void
8067218822Sdimdo_mav_triple (void)
8068218822Sdim{
8069218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
8070218822Sdim  inst.instruction |= inst.operands[1].reg;
8071218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
8072218822Sdim}
807389857Sobrien
8074218822Sdim/* Insns like "foo W,X,Y,Z".
8075218822Sdim    where W=MVAX[0:3] and X,Y,Z=MVFX[0:15].  */
807689857Sobrien
8077218822Sdimstatic void
8078218822Sdimdo_mav_quad (void)
8079218822Sdim{
8080218822Sdim  inst.instruction |= inst.operands[0].reg << 5;
8081218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
8082218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
8083218822Sdim  inst.instruction |= inst.operands[3].reg;
8084218822Sdim}
808560484Sobrien
8086218822Sdim/* cfmvsc32<cond> DSPSC,MVDX[15:0].  */
8087218822Sdimstatic void
8088218822Sdimdo_mav_dspsc (void)
8089218822Sdim{
8090218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
809189857Sobrien}
809289857Sobrien
8093218822Sdim/* Maverick shift immediate instructions.
8094218822Sdim   cfsh32<cond> MVFX[15:0],MVFX[15:0],Shift[6:0].
8095218822Sdim   cfsh64<cond> MVDX[15:0],MVDX[15:0],Shift[6:0].  */
8096218822Sdim
809789857Sobrienstatic void
8098218822Sdimdo_mav_shift (void)
809989857Sobrien{
8100218822Sdim  int imm = inst.operands[2].imm;
810189857Sobrien
8102218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
8103218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
810477298Sobrien
8105218822Sdim  /* Bits 0-3 of the insn should have bits 0-3 of the immediate.
8106218822Sdim     Bits 5-7 of the insn should have bits 4-6 of the immediate.
8107218822Sdim     Bit 4 should be 0.	 */
8108218822Sdim  imm = (imm & 0xf) | ((imm & 0x70) << 1);
810960484Sobrien
8110218822Sdim  inst.instruction |= imm;
8111218822Sdim}
8112218822Sdim
8113218822Sdim/* XScale instructions.	 Also sorted arithmetic before move.  */
811460484Sobrien
8115218822Sdim/* Xscale multiply-accumulate (argument parse)
8116218822Sdim     MIAcc   acc0,Rm,Rs
8117218822Sdim     MIAPHcc acc0,Rm,Rs
8118218822Sdim     MIAxycc acc0,Rm,Rs.  */
811960484Sobrien
8120218822Sdimstatic void
8121218822Sdimdo_xsc_mia (void)
8122218822Sdim{
8123218822Sdim  inst.instruction |= inst.operands[1].reg;
8124218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
8125218822Sdim}
812660484Sobrien
8127218822Sdim/* Xscale move-accumulator-register (argument parse)
812860484Sobrien
8129218822Sdim     MARcc   acc0,RdLo,RdHi.  */
813060484Sobrien
8131218822Sdimstatic void
8132218822Sdimdo_xsc_mar (void)
8133218822Sdim{
8134218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
8135218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
8136218822Sdim}
813789857Sobrien
8138218822Sdim/* Xscale move-register-accumulator (argument parse)
813989857Sobrien
8140218822Sdim     MRAcc   RdLo,RdHi,acc0.  */
814189857Sobrien
8142218822Sdimstatic void
8143218822Sdimdo_xsc_mra (void)
8144218822Sdim{
8145218822Sdim  constraint (inst.operands[0].reg == inst.operands[1].reg, BAD_OVERLAP);
8146218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
8147218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
8148218822Sdim}
8149218822Sdim
8150218822Sdim/* Encoding functions relevant only to Thumb.  */
815189857Sobrien
8152218822Sdim/* inst.operands[i] is a shifted-register operand; encode
8153218822Sdim   it into inst.instruction in the format used by Thumb32.  */
815489857Sobrien
8155218822Sdimstatic void
8156218822Sdimencode_thumb32_shifted_operand (int i)
8157218822Sdim{
8158218822Sdim  unsigned int value = inst.reloc.exp.X_add_number;
8159218822Sdim  unsigned int shift = inst.operands[i].shift_kind;
8160218822Sdim
8161218822Sdim  constraint (inst.operands[i].immisreg,
8162218822Sdim	      _("shift by register not allowed in thumb mode"));
8163218822Sdim  inst.instruction |= inst.operands[i].reg;
8164218822Sdim  if (shift == SHIFT_RRX)
8165218822Sdim    inst.instruction |= SHIFT_ROR << 4;
816689857Sobrien  else
816789857Sobrien    {
8168218822Sdim      constraint (inst.reloc.exp.X_op != O_constant,
8169218822Sdim		  _("expression too complex"));
8170218822Sdim
8171218822Sdim      constraint (value > 32
8172218822Sdim		  || (value == 32 && (shift == SHIFT_LSL
8173218822Sdim				      || shift == SHIFT_ROR)),
8174218822Sdim		  _("shift expression is too large"));
8175218822Sdim
8176218822Sdim      if (value == 0)
8177218822Sdim	shift = SHIFT_LSL;
8178218822Sdim      else if (value == 32)
8179218822Sdim	value = 0;
8180218822Sdim
8181218822Sdim      inst.instruction |= shift << 4;
8182218822Sdim      inst.instruction |= (value & 0x1c) << 10;
8183218822Sdim      inst.instruction |= (value & 0x03) << 6;
818489857Sobrien    }
818589857Sobrien}
818689857Sobrien
8187218822Sdim
8188218822Sdim/* inst.operands[i] was set up by parse_address.  Encode it into a
8189218822Sdim   Thumb32 format load or store instruction.  Reject forms that cannot
8190218822Sdim   be used with such instructions.  If is_t is true, reject forms that
8191218822Sdim   cannot be used with a T instruction; if is_d is true, reject forms
8192218822Sdim   that cannot be used with a D instruction.  */
8193218822Sdim
8194218822Sdimstatic void
8195218822Sdimencode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
819689857Sobrien{
8197218822Sdim  bfd_boolean is_pc = (inst.operands[i].reg == REG_PC);
819889857Sobrien
8199218822Sdim  constraint (!inst.operands[i].isreg,
8200218822Sdim	      _("Instruction does not support =N addresses"));
8201218822Sdim
8202218822Sdim  inst.instruction |= inst.operands[i].reg << 16;
8203218822Sdim  if (inst.operands[i].immisreg)
820489857Sobrien    {
8205218822Sdim      constraint (is_pc, _("cannot use register index with PC-relative addressing"));
8206218822Sdim      constraint (is_t || is_d, _("cannot use register index with this instruction"));
8207218822Sdim      constraint (inst.operands[i].negative,
8208218822Sdim		  _("Thumb does not support negative register indexing"));
8209218822Sdim      constraint (inst.operands[i].postind,
8210218822Sdim		  _("Thumb does not support register post-indexing"));
8211218822Sdim      constraint (inst.operands[i].writeback,
8212218822Sdim		  _("Thumb does not support register indexing with writeback"));
8213218822Sdim      constraint (inst.operands[i].shifted && inst.operands[i].shift_kind != SHIFT_LSL,
8214218822Sdim		  _("Thumb supports only LSL in shifted register indexing"));
821589857Sobrien
8216218822Sdim      inst.instruction |= inst.operands[i].imm;
8217218822Sdim      if (inst.operands[i].shifted)
821889857Sobrien	{
8219218822Sdim	  constraint (inst.reloc.exp.X_op != O_constant,
8220218822Sdim		      _("expression too complex"));
8221218822Sdim	  constraint (inst.reloc.exp.X_add_number < 0
8222218822Sdim		      || inst.reloc.exp.X_add_number > 3,
8223218822Sdim		      _("shift out of range"));
8224218822Sdim	  inst.instruction |= inst.reloc.exp.X_add_number << 4;
8225218822Sdim	}
8226218822Sdim      inst.reloc.type = BFD_RELOC_UNUSED;
8227218822Sdim    }
8228218822Sdim  else if (inst.operands[i].preind)
8229218822Sdim    {
8230218822Sdim      constraint (is_pc && inst.operands[i].writeback,
8231218822Sdim		  _("cannot use writeback with PC-relative addressing"));
8232218822Sdim      constraint (is_t && inst.operands[i].writeback,
8233218822Sdim		  _("cannot use writeback with this instruction"));
823489857Sobrien
8235218822Sdim      if (is_d)
8236218822Sdim	{
8237218822Sdim	  inst.instruction |= 0x01000000;
8238218822Sdim	  if (inst.operands[i].writeback)
8239218822Sdim	    inst.instruction |= 0x00200000;
824089857Sobrien	}
824189857Sobrien      else
824289857Sobrien	{
8243218822Sdim	  inst.instruction |= 0x00000c00;
8244218822Sdim	  if (inst.operands[i].writeback)
8245218822Sdim	    inst.instruction |= 0x00000100;
824689857Sobrien	}
8247218822Sdim      inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_IMM;
8248218822Sdim    }
8249218822Sdim  else if (inst.operands[i].postind)
8250218822Sdim    {
8251218822Sdim      assert (inst.operands[i].writeback);
8252218822Sdim      constraint (is_pc, _("cannot use post-indexing with PC-relative addressing"));
8253218822Sdim      constraint (is_t, _("cannot use post-indexing with this instruction"));
825489857Sobrien
8255218822Sdim      if (is_d)
8256218822Sdim	inst.instruction |= 0x00200000;
8257218822Sdim      else
8258218822Sdim	inst.instruction |= 0x00000900;
8259218822Sdim      inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_IMM;
8260218822Sdim    }
8261218822Sdim  else /* unindexed - only for coprocessor */
8262218822Sdim    inst.error = _("instruction does not accept unindexed addressing");
8263218822Sdim}
826489857Sobrien
8265218822Sdim/* Table of Thumb instructions which exist in both 16- and 32-bit
8266218822Sdim   encodings (the latter only in post-V6T2 cores).  The index is the
8267218822Sdim   value used in the insns table below.  When there is more than one
8268218822Sdim   possible 16-bit encoding for the instruction, this table always
8269218822Sdim   holds variant (1).
8270218822Sdim   Also contains several pseudo-instructions used during relaxation.  */
8271218822Sdim#define T16_32_TAB				\
8272218822Sdim  X(adc,   4140, eb400000),			\
8273218822Sdim  X(adcs,  4140, eb500000),			\
8274218822Sdim  X(add,   1c00, eb000000),			\
8275218822Sdim  X(adds,  1c00, eb100000),			\
8276218822Sdim  X(addi,  0000, f1000000),			\
8277218822Sdim  X(addis, 0000, f1100000),			\
8278218822Sdim  X(add_pc,000f, f20f0000),			\
8279218822Sdim  X(add_sp,000d, f10d0000),			\
8280218822Sdim  X(adr,   000f, f20f0000),			\
8281218822Sdim  X(and,   4000, ea000000),			\
8282218822Sdim  X(ands,  4000, ea100000),			\
8283218822Sdim  X(asr,   1000, fa40f000),			\
8284218822Sdim  X(asrs,  1000, fa50f000),			\
8285218822Sdim  X(b,     e000, f000b000),			\
8286218822Sdim  X(bcond, d000, f0008000),			\
8287218822Sdim  X(bic,   4380, ea200000),			\
8288218822Sdim  X(bics,  4380, ea300000),			\
8289218822Sdim  X(cmn,   42c0, eb100f00),			\
8290218822Sdim  X(cmp,   2800, ebb00f00),			\
8291218822Sdim  X(cpsie, b660, f3af8400),			\
8292218822Sdim  X(cpsid, b670, f3af8600),			\
8293218822Sdim  X(cpy,   4600, ea4f0000),			\
8294218822Sdim  X(dec_sp,80dd, f1ad0d00),			\
8295218822Sdim  X(eor,   4040, ea800000),			\
8296218822Sdim  X(eors,  4040, ea900000),			\
8297218822Sdim  X(inc_sp,00dd, f10d0d00),			\
8298218822Sdim  X(ldmia, c800, e8900000),			\
8299218822Sdim  X(ldr,   6800, f8500000),			\
8300218822Sdim  X(ldrb,  7800, f8100000),			\
8301218822Sdim  X(ldrh,  8800, f8300000),			\
8302218822Sdim  X(ldrsb, 5600, f9100000),			\
8303218822Sdim  X(ldrsh, 5e00, f9300000),			\
8304218822Sdim  X(ldr_pc,4800, f85f0000),			\
8305218822Sdim  X(ldr_pc2,4800, f85f0000),			\
8306218822Sdim  X(ldr_sp,9800, f85d0000),			\
8307218822Sdim  X(lsl,   0000, fa00f000),			\
8308218822Sdim  X(lsls,  0000, fa10f000),			\
8309218822Sdim  X(lsr,   0800, fa20f000),			\
8310218822Sdim  X(lsrs,  0800, fa30f000),			\
8311218822Sdim  X(mov,   2000, ea4f0000),			\
8312218822Sdim  X(movs,  2000, ea5f0000),			\
8313218822Sdim  X(mul,   4340, fb00f000),                     \
8314218822Sdim  X(muls,  4340, ffffffff), /* no 32b muls */	\
8315218822Sdim  X(mvn,   43c0, ea6f0000),			\
8316218822Sdim  X(mvns,  43c0, ea7f0000),			\
8317218822Sdim  X(neg,   4240, f1c00000), /* rsb #0 */	\
8318218822Sdim  X(negs,  4240, f1d00000), /* rsbs #0 */	\
8319218822Sdim  X(orr,   4300, ea400000),			\
8320218822Sdim  X(orrs,  4300, ea500000),			\
8321218822Sdim  X(pop,   bc00, e8bd0000), /* ldmia sp!,... */	\
8322218822Sdim  X(push,  b400, e92d0000), /* stmdb sp!,... */	\
8323218822Sdim  X(rev,   ba00, fa90f080),			\
8324218822Sdim  X(rev16, ba40, fa90f090),			\
8325218822Sdim  X(revsh, bac0, fa90f0b0),			\
8326218822Sdim  X(ror,   41c0, fa60f000),			\
8327218822Sdim  X(rors,  41c0, fa70f000),			\
8328218822Sdim  X(sbc,   4180, eb600000),			\
8329218822Sdim  X(sbcs,  4180, eb700000),			\
8330218822Sdim  X(stmia, c000, e8800000),			\
8331218822Sdim  X(str,   6000, f8400000),			\
8332218822Sdim  X(strb,  7000, f8000000),			\
8333218822Sdim  X(strh,  8000, f8200000),			\
8334218822Sdim  X(str_sp,9000, f84d0000),			\
8335218822Sdim  X(sub,   1e00, eba00000),			\
8336218822Sdim  X(subs,  1e00, ebb00000),			\
8337218822Sdim  X(subi,  8000, f1a00000),			\
8338218822Sdim  X(subis, 8000, f1b00000),			\
8339218822Sdim  X(sxtb,  b240, fa4ff080),			\
8340218822Sdim  X(sxth,  b200, fa0ff080),			\
8341218822Sdim  X(tst,   4200, ea100f00),			\
8342218822Sdim  X(uxtb,  b2c0, fa5ff080),			\
8343218822Sdim  X(uxth,  b280, fa1ff080),			\
8344218822Sdim  X(nop,   bf00, f3af8000),			\
8345218822Sdim  X(yield, bf10, f3af8001),			\
8346218822Sdim  X(wfe,   bf20, f3af8002),			\
8347218822Sdim  X(wfi,   bf30, f3af8003),			\
8348218822Sdim  X(sev,   bf40, f3af9004), /* typo, 8004? */
834989857Sobrien
8350218822Sdim/* To catch errors in encoding functions, the codes are all offset by
8351218822Sdim   0xF800, putting them in one of the 32-bit prefix ranges, ergo undefined
8352218822Sdim   as 16-bit instructions.  */
8353218822Sdim#define X(a,b,c) T_MNEM_##a
8354218822Sdimenum t16_32_codes { T16_32_OFFSET = 0xF7FF, T16_32_TAB };
8355218822Sdim#undef X
835689857Sobrien
8357218822Sdim#define X(a,b,c) 0x##b
8358218822Sdimstatic const unsigned short thumb_op16[] = { T16_32_TAB };
8359218822Sdim#define THUMB_OP16(n) (thumb_op16[(n) - (T16_32_OFFSET + 1)])
8360218822Sdim#undef X
836189857Sobrien
8362218822Sdim#define X(a,b,c) 0x##c
8363218822Sdimstatic const unsigned int thumb_op32[] = { T16_32_TAB };
8364218822Sdim#define THUMB_OP32(n) (thumb_op32[(n) - (T16_32_OFFSET + 1)])
8365218822Sdim#define THUMB_SETS_FLAGS(n) (THUMB_OP32 (n) & 0x00100000)
8366218822Sdim#undef X
8367218822Sdim#undef T16_32_TAB
8368218822Sdim
8369218822Sdim/* Thumb instruction encoders, in alphabetical order.  */
8370218822Sdim
8371218822Sdim/* ADDW or SUBW.  */
837289857Sobrienstatic void
8373218822Sdimdo_t_add_sub_w (void)
837489857Sobrien{
8375218822Sdim  int Rd, Rn;
837689857Sobrien
8377218822Sdim  Rd = inst.operands[0].reg;
8378218822Sdim  Rn = inst.operands[1].reg;
837989857Sobrien
8380218822Sdim  constraint (Rd == 15, _("PC not allowed as destination"));
8381218822Sdim  inst.instruction |= (Rn << 16) | (Rd << 8);
8382218822Sdim  inst.reloc.type = BFD_RELOC_ARM_T32_IMM12;
8383218822Sdim}
838489857Sobrien
8385218822Sdim/* Parse an add or subtract instruction.  We get here with inst.instruction
8386218822Sdim   equalling any of THUMB_OPCODE_add, adds, sub, or subs.  */
838789857Sobrien
8388218822Sdimstatic void
8389218822Sdimdo_t_add_sub (void)
8390218822Sdim{
8391218822Sdim  int Rd, Rs, Rn;
839289857Sobrien
8393218822Sdim  Rd = inst.operands[0].reg;
8394218822Sdim  Rs = (inst.operands[1].present
8395218822Sdim	? inst.operands[1].reg    /* Rd, Rs, foo */
8396218822Sdim	: inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
839789857Sobrien
8398218822Sdim  if (unified_syntax)
8399218822Sdim    {
8400218822Sdim      bfd_boolean flags;
8401218822Sdim      bfd_boolean narrow;
8402218822Sdim      int opcode;
840389857Sobrien
8404218822Sdim      flags = (inst.instruction == T_MNEM_adds
8405218822Sdim	       || inst.instruction == T_MNEM_subs);
8406218822Sdim      if (flags)
8407218822Sdim	narrow = (current_it_mask == 0);
8408218822Sdim      else
8409218822Sdim	narrow = (current_it_mask != 0);
8410218822Sdim      if (!inst.operands[2].isreg)
841160484Sobrien	{
8412218822Sdim	  int add;
841377298Sobrien
8414218822Sdim	  add = (inst.instruction == T_MNEM_add
8415218822Sdim		 || inst.instruction == T_MNEM_adds);
8416218822Sdim	  opcode = 0;
8417218822Sdim	  if (inst.size_req != 4)
841860484Sobrien	    {
8419218822Sdim	      /* Attempt to use a narrow opcode, with relaxation if
8420218822Sdim	         appropriate.  */
8421218822Sdim	      if (Rd == REG_SP && Rs == REG_SP && !flags)
8422218822Sdim		opcode = add ? T_MNEM_inc_sp : T_MNEM_dec_sp;
8423218822Sdim	      else if (Rd <= 7 && Rs == REG_SP && add && !flags)
8424218822Sdim		opcode = T_MNEM_add_sp;
8425218822Sdim	      else if (Rd <= 7 && Rs == REG_PC && add && !flags)
8426218822Sdim		opcode = T_MNEM_add_pc;
8427218822Sdim	      else if (Rd <= 7 && Rs <= 7 && narrow)
8428218822Sdim		{
8429218822Sdim		  if (flags)
8430218822Sdim		    opcode = add ? T_MNEM_addis : T_MNEM_subis;
8431218822Sdim		  else
8432218822Sdim		    opcode = add ? T_MNEM_addi : T_MNEM_subi;
8433218822Sdim		}
8434218822Sdim	      if (opcode)
8435218822Sdim		{
8436218822Sdim		  inst.instruction = THUMB_OP16(opcode);
8437218822Sdim		  inst.instruction |= (Rd << 4) | Rs;
8438218822Sdim		  inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
8439218822Sdim		  if (inst.size_req != 2)
8440218822Sdim		    inst.relax = opcode;
8441218822Sdim		}
8442218822Sdim	      else
8443218822Sdim		constraint (inst.size_req == 2, BAD_HIREG);
844460484Sobrien	    }
8445218822Sdim	  if (inst.size_req == 4
8446218822Sdim	      || (inst.size_req != 2 && !opcode))
844760484Sobrien	    {
8448218822Sdim	      if (Rd == REG_PC)
844977298Sobrien		{
8450218822Sdim		  constraint (Rs != REG_LR || inst.instruction != T_MNEM_subs,
8451218822Sdim			     _("only SUBS PC, LR, #const allowed"));
8452218822Sdim		  constraint (inst.reloc.exp.X_op != O_constant,
8453218822Sdim			      _("expression too complex"));
8454218822Sdim		  constraint (inst.reloc.exp.X_add_number < 0
8455218822Sdim			      || inst.reloc.exp.X_add_number > 0xff,
8456218822Sdim			     _("immediate value out of range"));
8457218822Sdim		  inst.instruction = T2_SUBS_PC_LR
8458218822Sdim				     | inst.reloc.exp.X_add_number;
8459218822Sdim		  inst.reloc.type = BFD_RELOC_UNUSED;
8460218822Sdim		  return;
846177298Sobrien		}
8462218822Sdim	      else if (Rs == REG_PC)
8463218822Sdim		{
8464218822Sdim		  /* Always use addw/subw.  */
8465218822Sdim		  inst.instruction = add ? 0xf20f0000 : 0xf2af0000;
8466218822Sdim		  inst.reloc.type = BFD_RELOC_ARM_T32_IMM12;
8467218822Sdim		}
8468218822Sdim	      else
8469218822Sdim		{
8470218822Sdim		  inst.instruction = THUMB_OP32 (inst.instruction);
8471218822Sdim		  inst.instruction = (inst.instruction & 0xe1ffffff)
8472218822Sdim				     | 0x10000000;
8473218822Sdim		  if (flags)
8474218822Sdim		    inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
8475218822Sdim		  else
8476218822Sdim		    inst.reloc.type = BFD_RELOC_ARM_T32_ADD_IMM;
8477218822Sdim		}
8478218822Sdim	      inst.instruction |= Rd << 8;
8479218822Sdim	      inst.instruction |= Rs << 16;
848060484Sobrien	    }
848160484Sobrien	}
848260484Sobrien      else
848360484Sobrien	{
8484218822Sdim	  Rn = inst.operands[2].reg;
8485218822Sdim	  /* See if we can do this with a 16-bit instruction.  */
8486218822Sdim	  if (!inst.operands[2].shifted && inst.size_req != 4)
848760484Sobrien	    {
8488218822Sdim	      if (Rd > 7 || Rs > 7 || Rn > 7)
8489218822Sdim		narrow = FALSE;
849060484Sobrien
8491218822Sdim	      if (narrow)
8492218822Sdim		{
8493218822Sdim		  inst.instruction = ((inst.instruction == T_MNEM_adds
8494218822Sdim				       || inst.instruction == T_MNEM_add)
8495218822Sdim				      ? T_OPCODE_ADD_R3
8496218822Sdim				      : T_OPCODE_SUB_R3);
8497218822Sdim		  inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
8498218822Sdim		  return;
8499218822Sdim		}
850060484Sobrien
8501218822Sdim	      if (inst.instruction == T_MNEM_add)
8502218822Sdim		{
8503218822Sdim		  if (Rd == Rs)
8504218822Sdim		    {
8505218822Sdim		      inst.instruction = T_OPCODE_ADD_HI;
8506218822Sdim		      inst.instruction |= (Rd & 8) << 4;
8507218822Sdim		      inst.instruction |= (Rd & 7);
8508218822Sdim		      inst.instruction |= Rn << 3;
8509218822Sdim		      return;
8510218822Sdim		    }
8511218822Sdim		  /* ... because addition is commutative! */
8512218822Sdim		  else if (Rd == Rn)
8513218822Sdim		    {
8514218822Sdim		      inst.instruction = T_OPCODE_ADD_HI;
8515218822Sdim		      inst.instruction |= (Rd & 8) << 4;
8516218822Sdim		      inst.instruction |= (Rd & 7);
8517218822Sdim		      inst.instruction |= Rs << 3;
8518218822Sdim		      return;
8519218822Sdim		    }
8520218822Sdim		}
852160484Sobrien	    }
8522218822Sdim	  /* If we get here, it can't be done in 16 bits.  */
8523218822Sdim	  constraint (inst.operands[2].shifted && inst.operands[2].immisreg,
8524218822Sdim		      _("shift must be constant"));
8525218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
8526218822Sdim	  inst.instruction |= Rd << 8;
8527218822Sdim	  inst.instruction |= Rs << 16;
8528218822Sdim	  encode_thumb32_shifted_operand (2);
852960484Sobrien	}
853060484Sobrien    }
8531218822Sdim  else
853260484Sobrien    {
8533218822Sdim      constraint (inst.instruction == T_MNEM_adds
8534218822Sdim		  || inst.instruction == T_MNEM_subs,
8535218822Sdim		  BAD_THUMB32);
8536218822Sdim
8537218822Sdim      if (!inst.operands[2].isreg) /* Rd, Rs, #imm */
853889857Sobrien	{
8539218822Sdim	  constraint ((Rd > 7 && (Rd != REG_SP || Rs != REG_SP))
8540218822Sdim		      || (Rs > 7 && Rs != REG_SP && Rs != REG_PC),
8541218822Sdim		      BAD_HIREG);
8542218822Sdim
8543218822Sdim	  inst.instruction = (inst.instruction == T_MNEM_add
8544218822Sdim			      ? 0x0000 : 0x8000);
8545218822Sdim	  inst.instruction |= (Rd << 4) | Rs;
8546218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
854789857Sobrien	  return;
854889857Sobrien	}
854989857Sobrien
8550218822Sdim      Rn = inst.operands[2].reg;
8551218822Sdim      constraint (inst.operands[2].shifted, _("unshifted register required"));
855260484Sobrien
8553218822Sdim      /* We now have Rd, Rs, and Rn set to registers.  */
8554218822Sdim      if (Rd > 7 || Rs > 7 || Rn > 7)
855560484Sobrien	{
8556218822Sdim	  /* Can't do this for SUB.	 */
8557218822Sdim	  constraint (inst.instruction == T_MNEM_sub, BAD_HIREG);
8558218822Sdim	  inst.instruction = T_OPCODE_ADD_HI;
8559218822Sdim	  inst.instruction |= (Rd & 8) << 4;
8560218822Sdim	  inst.instruction |= (Rd & 7);
8561218822Sdim	  if (Rs == Rd)
8562218822Sdim	    inst.instruction |= Rn << 3;
8563218822Sdim	  else if (Rn == Rd)
8564218822Sdim	    inst.instruction |= Rs << 3;
8565218822Sdim	  else
8566218822Sdim	    constraint (1, _("dest must overlap one source register"));
856760484Sobrien	}
8568218822Sdim      else
856960484Sobrien	{
8570218822Sdim	  inst.instruction = (inst.instruction == T_MNEM_add
8571218822Sdim			      ? T_OPCODE_ADD_R3 : T_OPCODE_SUB_R3);
8572218822Sdim	  inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
857360484Sobrien	}
8574218822Sdim    }
8575218822Sdim}
857680016Sobrien
8577218822Sdimstatic void
8578218822Sdimdo_t_adr (void)
8579218822Sdim{
8580218822Sdim  if (unified_syntax && inst.size_req == 0 && inst.operands[0].reg <= 7)
8581218822Sdim    {
8582218822Sdim      /* Defer to section relaxation.  */
8583218822Sdim      inst.relax = inst.instruction;
8584218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
8585218822Sdim      inst.instruction |= inst.operands[0].reg << 4;
8586218822Sdim    }
8587218822Sdim  else if (unified_syntax && inst.size_req != 2)
8588218822Sdim    {
8589218822Sdim      /* Generate a 32-bit opcode.  */
8590218822Sdim      inst.instruction = THUMB_OP32 (inst.instruction);
8591218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
8592218822Sdim      inst.reloc.type = BFD_RELOC_ARM_T32_ADD_PC12;
859380016Sobrien      inst.reloc.pc_rel = 1;
859460484Sobrien    }
859560484Sobrien  else
859660484Sobrien    {
8597218822Sdim      /* Generate a 16-bit opcode.  */
8598218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
8599218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
8600218822Sdim      inst.reloc.exp.X_add_number -= 4; /* PC relative adjust.  */
8601218822Sdim      inst.reloc.pc_rel = 1;
860260484Sobrien
8603218822Sdim      inst.instruction |= inst.operands[0].reg << 4;
860460484Sobrien    }
860560484Sobrien}
860660484Sobrien
8607218822Sdim/* Arithmetic instructions for which there is just one 16-bit
8608218822Sdim   instruction encoding, and it allows only two low registers.
8609218822Sdim   For maximal compatibility with ARM syntax, we allow three register
8610218822Sdim   operands even when Thumb-32 instructions are not available, as long
8611218822Sdim   as the first two are identical.  For instance, both "sbc r0,r1" and
8612218822Sdim   "sbc r0,r0,r1" are allowed.  */
8613218822Sdimstatic void
8614218822Sdimdo_t_arit3 (void)
861560484Sobrien{
8616218822Sdim  int Rd, Rs, Rn;
861760484Sobrien
8618218822Sdim  Rd = inst.operands[0].reg;
8619218822Sdim  Rs = (inst.operands[1].present
8620218822Sdim	? inst.operands[1].reg    /* Rd, Rs, foo */
8621218822Sdim	: inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
8622218822Sdim  Rn = inst.operands[2].reg;
8623218822Sdim
8624218822Sdim  if (unified_syntax)
862560484Sobrien    {
8626218822Sdim      if (!inst.operands[2].isreg)
862760484Sobrien	{
8628218822Sdim	  /* For an immediate, we always generate a 32-bit opcode;
8629218822Sdim	     section relaxation will shrink it later if possible.  */
8630218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
8631218822Sdim	  inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
8632218822Sdim	  inst.instruction |= Rd << 8;
8633218822Sdim	  inst.instruction |= Rs << 16;
8634218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
8635218822Sdim	}
8636218822Sdim      else
8637218822Sdim	{
8638218822Sdim	  bfd_boolean narrow;
863977298Sobrien
8640218822Sdim	  /* See if we can do this with a 16-bit instruction.  */
8641218822Sdim	  if (THUMB_SETS_FLAGS (inst.instruction))
8642218822Sdim	    narrow = current_it_mask == 0;
8643218822Sdim	  else
8644218822Sdim	    narrow = current_it_mask != 0;
864577298Sobrien
8646218822Sdim	  if (Rd > 7 || Rn > 7 || Rs > 7)
8647218822Sdim	    narrow = FALSE;
8648218822Sdim	  if (inst.operands[2].shifted)
8649218822Sdim	    narrow = FALSE;
8650218822Sdim	  if (inst.size_req == 4)
8651218822Sdim	    narrow = FALSE;
865260484Sobrien
8653218822Sdim	  if (narrow
8654218822Sdim	      && Rd == Rs)
8655218822Sdim	    {
8656218822Sdim	      inst.instruction = THUMB_OP16 (inst.instruction);
8657218822Sdim	      inst.instruction |= Rd;
8658218822Sdim	      inst.instruction |= Rn << 3;
8659218822Sdim	      return;
8660218822Sdim	    }
866177298Sobrien
8662218822Sdim	  /* If we get here, it can't be done in 16 bits.  */
8663218822Sdim	  constraint (inst.operands[2].shifted
8664218822Sdim		      && inst.operands[2].immisreg,
8665218822Sdim		      _("shift must be constant"));
8666218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
8667218822Sdim	  inst.instruction |= Rd << 8;
8668218822Sdim	  inst.instruction |= Rs << 16;
8669218822Sdim	  encode_thumb32_shifted_operand (2);
8670218822Sdim	}
8671218822Sdim    }
8672218822Sdim  else
8673218822Sdim    {
8674218822Sdim      /* On its face this is a lie - the instruction does set the
8675218822Sdim	 flags.  However, the only supported mnemonic in this mode
8676218822Sdim	 says it doesn't.  */
8677218822Sdim      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
867877298Sobrien
8679218822Sdim      constraint (!inst.operands[2].isreg || inst.operands[2].shifted,
8680218822Sdim		  _("unshifted register required"));
8681218822Sdim      constraint (Rd > 7 || Rs > 7 || Rn > 7, BAD_HIREG);
8682218822Sdim      constraint (Rd != Rs,
8683218822Sdim		  _("dest and source1 must be the same register"));
868460484Sobrien
8685218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
8686218822Sdim      inst.instruction |= Rd;
8687218822Sdim      inst.instruction |= Rn << 3;
8688218822Sdim    }
8689218822Sdim}
869060484Sobrien
8691218822Sdim/* Similarly, but for instructions where the arithmetic operation is
8692218822Sdim   commutative, so we can allow either of them to be different from
8693218822Sdim   the destination operand in a 16-bit instruction.  For instance, all
8694218822Sdim   three of "adc r0,r1", "adc r0,r0,r1", and "adc r0,r1,r0" are
8695218822Sdim   accepted.  */
8696218822Sdimstatic void
8697218822Sdimdo_t_arit3c (void)
8698218822Sdim{
8699218822Sdim  int Rd, Rs, Rn;
870060484Sobrien
8701218822Sdim  Rd = inst.operands[0].reg;
8702218822Sdim  Rs = (inst.operands[1].present
8703218822Sdim	? inst.operands[1].reg    /* Rd, Rs, foo */
8704218822Sdim	: inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
8705218822Sdim  Rn = inst.operands[2].reg;
870660484Sobrien
8707218822Sdim  if (unified_syntax)
8708218822Sdim    {
8709218822Sdim      if (!inst.operands[2].isreg)
8710218822Sdim	{
8711218822Sdim	  /* For an immediate, we always generate a 32-bit opcode;
8712218822Sdim	     section relaxation will shrink it later if possible.  */
8713218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
8714218822Sdim	  inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
8715218822Sdim	  inst.instruction |= Rd << 8;
8716218822Sdim	  inst.instruction |= Rs << 16;
8717218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
871860484Sobrien	}
871960484Sobrien      else
872060484Sobrien	{
8721218822Sdim	  bfd_boolean narrow;
872260484Sobrien
8723218822Sdim	  /* See if we can do this with a 16-bit instruction.  */
8724218822Sdim	  if (THUMB_SETS_FLAGS (inst.instruction))
8725218822Sdim	    narrow = current_it_mask == 0;
8726218822Sdim	  else
8727218822Sdim	    narrow = current_it_mask != 0;
872860484Sobrien
8729218822Sdim	  if (Rd > 7 || Rn > 7 || Rs > 7)
8730218822Sdim	    narrow = FALSE;
8731218822Sdim	  if (inst.operands[2].shifted)
8732218822Sdim	    narrow = FALSE;
8733218822Sdim	  if (inst.size_req == 4)
8734218822Sdim	    narrow = FALSE;
8735218822Sdim
8736218822Sdim	  if (narrow)
873760484Sobrien	    {
8738218822Sdim	      if (Rd == Rs)
873960484Sobrien		{
8740218822Sdim		  inst.instruction = THUMB_OP16 (inst.instruction);
8741218822Sdim		  inst.instruction |= Rd;
8742218822Sdim		  inst.instruction |= Rn << 3;
8743218822Sdim		  return;
874460484Sobrien		}
8745218822Sdim	      if (Rd == Rn)
874660484Sobrien		{
8747218822Sdim		  inst.instruction = THUMB_OP16 (inst.instruction);
8748218822Sdim		  inst.instruction |= Rd;
8749218822Sdim		  inst.instruction |= Rs << 3;
8750218822Sdim		  return;
875160484Sobrien		}
875260484Sobrien	    }
875360484Sobrien
8754218822Sdim	  /* If we get here, it can't be done in 16 bits.  */
8755218822Sdim	  constraint (inst.operands[2].shifted
8756218822Sdim		      && inst.operands[2].immisreg,
8757218822Sdim		      _("shift must be constant"));
8758218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
8759218822Sdim	  inst.instruction |= Rd << 8;
8760218822Sdim	  inst.instruction |= Rs << 16;
8761218822Sdim	  encode_thumb32_shifted_operand (2);
876260484Sobrien	}
8763218822Sdim    }
8764218822Sdim  else
8765218822Sdim    {
8766218822Sdim      /* On its face this is a lie - the instruction does set the
8767218822Sdim	 flags.  However, the only supported mnemonic in this mode
8768218822Sdim	 says it doesn't.  */
8769218822Sdim      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
877060484Sobrien
8771218822Sdim      constraint (!inst.operands[2].isreg || inst.operands[2].shifted,
8772218822Sdim		  _("unshifted register required"));
8773218822Sdim      constraint (Rd > 7 || Rs > 7 || Rn > 7, BAD_HIREG);
877460484Sobrien
8775218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
8776218822Sdim      inst.instruction |= Rd;
8777218822Sdim
8778218822Sdim      if (Rd == Rs)
8779218822Sdim	inst.instruction |= Rn << 3;
8780218822Sdim      else if (Rd == Rn)
8781218822Sdim	inst.instruction |= Rs << 3;
8782218822Sdim      else
8783218822Sdim	constraint (1, _("dest must overlap one source register"));
878477298Sobrien    }
8785218822Sdim}
878660484Sobrien
8787218822Sdimstatic void
8788218822Sdimdo_t_barrier (void)
8789218822Sdim{
8790218822Sdim  if (inst.operands[0].present)
8791218822Sdim    {
8792218822Sdim      constraint ((inst.instruction & 0xf0) != 0x40
8793218822Sdim		  && inst.operands[0].imm != 0xf,
8794218822Sdim		  "bad barrier type");
8795218822Sdim      inst.instruction |= inst.operands[0].imm;
8796218822Sdim    }
8797218822Sdim  else
8798218822Sdim    inst.instruction |= 0xf;
879960484Sobrien}
880060484Sobrien
880160484Sobrienstatic void
8802218822Sdimdo_t_bfc (void)
880360484Sobrien{
8804218822Sdim  unsigned int msb = inst.operands[1].imm + inst.operands[2].imm;
8805218822Sdim  constraint (msb > 32, _("bit-field extends past end of register"));
8806218822Sdim  /* The instruction encoding stores the LSB and MSB,
8807218822Sdim     not the LSB and width.  */
8808218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
8809218822Sdim  inst.instruction |= (inst.operands[1].imm & 0x1c) << 10;
8810218822Sdim  inst.instruction |= (inst.operands[1].imm & 0x03) << 6;
8811218822Sdim  inst.instruction |= msb - 1;
8812218822Sdim}
881360484Sobrien
8814218822Sdimstatic void
8815218822Sdimdo_t_bfi (void)
8816218822Sdim{
8817218822Sdim  unsigned int msb;
881860484Sobrien
8819218822Sdim  /* #0 in second position is alternative syntax for bfc, which is
8820218822Sdim     the same instruction but with REG_PC in the Rm field.  */
8821218822Sdim  if (!inst.operands[1].isreg)
8822218822Sdim    inst.operands[1].reg = REG_PC;
882360484Sobrien
8824218822Sdim  msb = inst.operands[2].imm + inst.operands[3].imm;
8825218822Sdim  constraint (msb > 32, _("bit-field extends past end of register"));
8826218822Sdim  /* The instruction encoding stores the LSB and MSB,
8827218822Sdim     not the LSB and width.  */
8828218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
8829218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
8830218822Sdim  inst.instruction |= (inst.operands[2].imm & 0x1c) << 10;
8831218822Sdim  inst.instruction |= (inst.operands[2].imm & 0x03) << 6;
8832218822Sdim  inst.instruction |= msb - 1;
8833218822Sdim}
883460484Sobrien
8835218822Sdimstatic void
8836218822Sdimdo_t_bfx (void)
8837218822Sdim{
8838218822Sdim  constraint (inst.operands[2].imm + inst.operands[3].imm > 32,
8839218822Sdim	      _("bit-field extends past end of register"));
8840218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
8841218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
8842218822Sdim  inst.instruction |= (inst.operands[2].imm & 0x1c) << 10;
8843218822Sdim  inst.instruction |= (inst.operands[2].imm & 0x03) << 6;
8844218822Sdim  inst.instruction |= inst.operands[3].imm - 1;
8845218822Sdim}
884660484Sobrien
8847218822Sdim/* ARM V5 Thumb BLX (argument parse)
8848218822Sdim	BLX <target_addr>	which is BLX(1)
8849218822Sdim	BLX <Rm>		which is BLX(2)
8850218822Sdim   Unfortunately, there are two different opcodes for this mnemonic.
8851218822Sdim   So, the insns[].value is not used, and the code here zaps values
8852218822Sdim	into inst.instruction.
885360484Sobrien
8854218822Sdim   ??? How to take advantage of the additional two bits of displacement
8855218822Sdim   available in Thumb32 mode?  Need new relocation?  */
8856218822Sdim
8857218822Sdimstatic void
8858218822Sdimdo_t_blx (void)
8859218822Sdim{
8860218822Sdim  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
8861218822Sdim  if (inst.operands[0].isreg)
8862218822Sdim    /* We have a register, so this is BLX(2).  */
8863218822Sdim    inst.instruction |= inst.operands[0].reg << 3;
8864218822Sdim  else
886560484Sobrien    {
8866218822Sdim      /* No register.  This must be BLX(1).  */
8867218822Sdim      inst.instruction = 0xf000e800;
8868218822Sdim#ifdef OBJ_ELF
8869218822Sdim      if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4)
8870218822Sdim	inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH23;
8871218822Sdim      else
8872218822Sdim#endif
8873218822Sdim	inst.reloc.type = BFD_RELOC_THUMB_PCREL_BLX;
8874218822Sdim      inst.reloc.pc_rel = 1;
887560484Sobrien    }
8876218822Sdim}
887760484Sobrien
8878218822Sdimstatic void
8879218822Sdimdo_t_branch (void)
8880218822Sdim{
8881218822Sdim  int opcode;
8882218822Sdim  int cond;
8883218822Sdim
8884218822Sdim  if (current_it_mask)
888560484Sobrien    {
8886218822Sdim      /* Conditional branches inside IT blocks are encoded as unconditional
8887218822Sdim         branches.  */
8888218822Sdim      cond = COND_ALWAYS;
8889218822Sdim      /* A branch must be the last instruction in an IT block.  */
8890218822Sdim      constraint (current_it_mask != 0x10, BAD_BRANCH);
889160484Sobrien    }
8892218822Sdim  else
8893218822Sdim    cond = inst.cond;
889460484Sobrien
8895218822Sdim  if (cond != COND_ALWAYS)
8896218822Sdim    opcode = T_MNEM_bcond;
8897218822Sdim  else
8898218822Sdim    opcode = inst.instruction;
8899218822Sdim
8900218822Sdim  if (unified_syntax && inst.size_req == 4)
8901130561Sobrien    {
8902218822Sdim      inst.instruction = THUMB_OP32(opcode);
8903218822Sdim      if (cond == COND_ALWAYS)
8904218822Sdim	inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH25;
8905218822Sdim      else
8906130561Sobrien	{
8907218822Sdim	  assert (cond != 0xF);
8908218822Sdim	  inst.instruction |= cond << 22;
8909218822Sdim	  inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH20;
8910130561Sobrien	}
8911218822Sdim    }
8912218822Sdim  else
8913218822Sdim    {
8914218822Sdim      inst.instruction = THUMB_OP16(opcode);
8915218822Sdim      if (cond == COND_ALWAYS)
8916218822Sdim	inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH12;
8917218822Sdim      else
8918130561Sobrien	{
8919218822Sdim	  inst.instruction |= cond << 8;
8920218822Sdim	  inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH9;
8921130561Sobrien	}
8922218822Sdim      /* Allow section relaxation.  */
8923218822Sdim      if (unified_syntax && inst.size_req != 2)
8924218822Sdim	inst.relax = opcode;
8925130561Sobrien    }
8926130561Sobrien
8927218822Sdim  inst.reloc.pc_rel = 1;
892860484Sobrien}
892960484Sobrien
893060484Sobrienstatic void
8931218822Sdimdo_t_bkpt (void)
893260484Sobrien{
8933218822Sdim  constraint (inst.cond != COND_ALWAYS,
8934218822Sdim	      _("instruction is always unconditional"));
8935218822Sdim  if (inst.operands[0].present)
8936218822Sdim    {
8937218822Sdim      constraint (inst.operands[0].imm > 255,
8938218822Sdim		  _("immediate value out of range"));
8939218822Sdim      inst.instruction |= inst.operands[0].imm;
8940218822Sdim    }
8941218822Sdim}
894277298Sobrien
8943218822Sdimstatic void
8944218822Sdimdo_t_branch23 (void)
8945218822Sdim{
8946218822Sdim  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
8947218822Sdim  inst.reloc.type   = BFD_RELOC_THUMB_PCREL_BRANCH23;
8948218822Sdim  inst.reloc.pc_rel = 1;
894960484Sobrien
8950218822Sdim  /* If the destination of the branch is a defined symbol which does not have
8951218822Sdim     the THUMB_FUNC attribute, then we must be calling a function which has
8952218822Sdim     the (interfacearm) attribute.  We look for the Thumb entry point to that
8953218822Sdim     function and change the branch to refer to that function instead.	*/
8954218822Sdim  if (	 inst.reloc.exp.X_op == O_symbol
8955218822Sdim      && inst.reloc.exp.X_add_symbol != NULL
8956218822Sdim      && S_IS_DEFINED (inst.reloc.exp.X_add_symbol)
8957218822Sdim      && ! THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol))
8958218822Sdim    inst.reloc.exp.X_add_symbol =
8959218822Sdim      find_real_start (inst.reloc.exp.X_add_symbol);
8960218822Sdim}
896160484Sobrien
8962218822Sdimstatic void
8963218822Sdimdo_t_bx (void)
8964218822Sdim{
8965218822Sdim  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
8966218822Sdim  inst.instruction |= inst.operands[0].reg << 3;
8967218822Sdim  /* ??? FIXME: Should add a hacky reloc here if reg is REG_PC.	 The reloc
8968218822Sdim     should cause the alignment to be checked once it is known.	 This is
8969218822Sdim     because BX PC only works if the instruction is word aligned.  */
897060484Sobrien}
897160484Sobrien
897260484Sobrienstatic void
8973218822Sdimdo_t_bxj (void)
897460484Sobrien{
8975218822Sdim  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
8976218822Sdim  if (inst.operands[0].reg == REG_PC)
8977218822Sdim    as_tsktsk (_("use of r15 in bxj is not really useful"));
897877298Sobrien
8979218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
8980218822Sdim}
898160484Sobrien
8982218822Sdimstatic void
8983218822Sdimdo_t_clz (void)
8984218822Sdim{
8985218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
8986218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
8987218822Sdim  inst.instruction |= inst.operands[1].reg;
8988218822Sdim}
898960484Sobrien
8990218822Sdimstatic void
8991218822Sdimdo_t_cps (void)
8992218822Sdim{
8993218822Sdim  constraint (current_it_mask, BAD_NOT_IT);
8994218822Sdim  inst.instruction |= inst.operands[0].imm;
8995218822Sdim}
899660484Sobrien
8997218822Sdimstatic void
8998218822Sdimdo_t_cpsi (void)
8999218822Sdim{
9000218822Sdim  constraint (current_it_mask, BAD_NOT_IT);
9001218822Sdim  if (unified_syntax
9002218822Sdim      && (inst.operands[1].present || inst.size_req == 4)
9003218822Sdim      && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6_notm))
900460484Sobrien    {
9005218822Sdim      unsigned int imod = (inst.instruction & 0x0030) >> 4;
9006218822Sdim      inst.instruction = 0xf3af8000;
9007218822Sdim      inst.instruction |= imod << 9;
9008218822Sdim      inst.instruction |= inst.operands[0].imm << 5;
9009218822Sdim      if (inst.operands[1].present)
9010218822Sdim	inst.instruction |= 0x100 | inst.operands[1].imm;
901160484Sobrien    }
9012218822Sdim  else
901360484Sobrien    {
9014218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1)
9015218822Sdim		  && (inst.operands[0].imm & 4),
9016218822Sdim		  _("selected processor does not support 'A' form "
9017218822Sdim		    "of this instruction"));
9018218822Sdim      constraint (inst.operands[1].present || inst.size_req == 4,
9019218822Sdim		  _("Thumb does not support the 2-argument "
9020218822Sdim		    "form of this instruction"));
9021218822Sdim      inst.instruction |= inst.operands[0].imm;
902260484Sobrien    }
9023218822Sdim}
902460484Sobrien
9025218822Sdim/* THUMB CPY instruction (argument parse).  */
902660484Sobrien
9027218822Sdimstatic void
9028218822Sdimdo_t_cpy (void)
9029218822Sdim{
9030218822Sdim  if (inst.size_req == 4)
903160484Sobrien    {
9032218822Sdim      inst.instruction = THUMB_OP32 (T_MNEM_mov);
9033218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
9034218822Sdim      inst.instruction |= inst.operands[1].reg;
903560484Sobrien    }
9036218822Sdim  else
903760484Sobrien    {
9038218822Sdim      inst.instruction |= (inst.operands[0].reg & 0x8) << 4;
9039218822Sdim      inst.instruction |= (inst.operands[0].reg & 0x7);
9040218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
904160484Sobrien    }
9042218822Sdim}
904360484Sobrien
9044218822Sdimstatic void
9045218822Sdimdo_t_cbz (void)
9046218822Sdim{
9047218822Sdim  constraint (current_it_mask, BAD_NOT_IT);
9048218822Sdim  constraint (inst.operands[0].reg > 7, BAD_HIREG);
9049218822Sdim  inst.instruction |= inst.operands[0].reg;
9050218822Sdim  inst.reloc.pc_rel = 1;
9051218822Sdim  inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH7;
905260484Sobrien}
905360484Sobrien
905460484Sobrienstatic void
9055218822Sdimdo_t_dbg (void)
905660484Sobrien{
9057218822Sdim  inst.instruction |= inst.operands[0].imm;
9058218822Sdim}
905977298Sobrien
9060218822Sdimstatic void
9061218822Sdimdo_t_div (void)
9062218822Sdim{
9063218822Sdim  if (!inst.operands[1].present)
9064218822Sdim    inst.operands[1].reg = inst.operands[0].reg;
9065218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
9066218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
9067218822Sdim  inst.instruction |= inst.operands[2].reg;
9068218822Sdim}
906977298Sobrien
9070218822Sdimstatic void
9071218822Sdimdo_t_hint (void)
9072218822Sdim{
9073218822Sdim  if (unified_syntax && inst.size_req == 4)
9074218822Sdim    inst.instruction = THUMB_OP32 (inst.instruction);
9075218822Sdim  else
9076218822Sdim    inst.instruction = THUMB_OP16 (inst.instruction);
907760484Sobrien}
907860484Sobrien
907960484Sobrienstatic void
9080218822Sdimdo_t_it (void)
908160484Sobrien{
9082218822Sdim  unsigned int cond = inst.operands[0].imm;
908360484Sobrien
9084218822Sdim  constraint (current_it_mask, BAD_NOT_IT);
9085218822Sdim  current_it_mask = (inst.instruction & 0xf) | 0x10;
9086218822Sdim  current_cc = cond;
908760484Sobrien
9088218822Sdim  /* If the condition is a negative condition, invert the mask.  */
9089218822Sdim  if ((cond & 0x1) == 0x0)
909060484Sobrien    {
9091218822Sdim      unsigned int mask = inst.instruction & 0x000f;
9092218822Sdim
9093218822Sdim      if ((mask & 0x7) == 0)
9094218822Sdim	/* no conversion needed */;
9095218822Sdim      else if ((mask & 0x3) == 0)
9096218822Sdim	mask ^= 0x8;
9097218822Sdim      else if ((mask & 0x1) == 0)
9098218822Sdim	mask ^= 0xC;
9099218822Sdim      else
9100218822Sdim	mask ^= 0xE;
9101218822Sdim
9102218822Sdim      inst.instruction &= 0xfff0;
9103218822Sdim      inst.instruction |= mask;
910460484Sobrien    }
910560484Sobrien
9106218822Sdim  inst.instruction |= cond << 4;
910760484Sobrien}
910860484Sobrien
9109218822Sdim/* Helper function used for both push/pop and ldm/stm.  */
911060484Sobrienstatic void
9111218822Sdimencode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback)
911260484Sobrien{
9113218822Sdim  bfd_boolean load;
911460484Sobrien
9115218822Sdim  load = (inst.instruction & (1 << 20)) != 0;
911660484Sobrien
9117218822Sdim  if (mask & (1 << 13))
9118218822Sdim    inst.error =  _("SP not allowed in register list");
9119218822Sdim  if (load)
912060484Sobrien    {
9121218822Sdim      if (mask & (1 << 14)
9122218822Sdim	  && mask & (1 << 15))
9123218822Sdim	inst.error = _("LR and PC should not both be in register list");
912460484Sobrien
9125218822Sdim      if ((mask & (1 << base)) != 0
9126218822Sdim	  && writeback)
9127218822Sdim	as_warn (_("base register should not be in register list "
9128218822Sdim		   "when written back"));
912960484Sobrien    }
9130218822Sdim  else
913160484Sobrien    {
9132218822Sdim      if (mask & (1 << 15))
9133218822Sdim	inst.error = _("PC not allowed in register list");
913460484Sobrien
9135218822Sdim      if (mask & (1 << base))
9136218822Sdim	as_warn (_("value stored for r%d is UNPREDICTABLE"), base);
913760484Sobrien    }
913860484Sobrien
9139218822Sdim  if ((mask & (mask - 1)) == 0)
914060484Sobrien    {
9141218822Sdim      /* Single register transfers implemented as str/ldr.  */
9142218822Sdim      if (writeback)
914360484Sobrien	{
9144218822Sdim	  if (inst.instruction & (1 << 23))
9145218822Sdim	    inst.instruction = 0x00000b04; /* ia! -> [base], #4 */
9146218822Sdim	  else
9147218822Sdim	    inst.instruction = 0x00000d04; /* db! -> [base, #-4]! */
914860484Sobrien	}
9149218822Sdim      else
9150218822Sdim	{
9151218822Sdim	  if (inst.instruction & (1 << 23))
9152218822Sdim	    inst.instruction = 0x00800000; /* ia -> [base] */
9153218822Sdim	  else
9154218822Sdim	    inst.instruction = 0x00000c04; /* db -> [base, #-4] */
9155218822Sdim	}
915660484Sobrien
9157218822Sdim      inst.instruction |= 0xf8400000;
9158218822Sdim      if (load)
9159218822Sdim	inst.instruction |= 0x00100000;
916060484Sobrien
9161218822Sdim      mask = ffs(mask) - 1;
9162218822Sdim      mask <<= 12;
916360484Sobrien    }
9164218822Sdim  else if (writeback)
9165218822Sdim    inst.instruction |= WRITE_BACK;
916660484Sobrien
9167218822Sdim  inst.instruction |= mask;
9168218822Sdim  inst.instruction |= base << 16;
916960484Sobrien}
917060484Sobrien
917160484Sobrienstatic void
9172218822Sdimdo_t_ldmstm (void)
917360484Sobrien{
9174218822Sdim  /* This really doesn't seem worth it.  */
9175218822Sdim  constraint (inst.reloc.type != BFD_RELOC_UNUSED,
9176218822Sdim	      _("expression too complex"));
9177218822Sdim  constraint (inst.operands[1].writeback,
9178218822Sdim	      _("Thumb load/store multiple does not support {reglist}^"));
917960484Sobrien
9180218822Sdim  if (unified_syntax)
918160484Sobrien    {
9182218822Sdim      bfd_boolean narrow;
9183218822Sdim      unsigned mask;
918460484Sobrien
9185218822Sdim      narrow = FALSE;
9186218822Sdim      /* See if we can use a 16-bit instruction.  */
9187218822Sdim      if (inst.instruction < 0xffff /* not ldmdb/stmdb */
9188218822Sdim	  && inst.size_req != 4
9189218822Sdim	  && !(inst.operands[1].imm & ~0xff))
9190218822Sdim	{
9191218822Sdim	  mask = 1 << inst.operands[0].reg;
919260484Sobrien
9193218822Sdim	  if (inst.operands[0].reg <= 7
9194218822Sdim	      && (inst.instruction == T_MNEM_stmia
9195218822Sdim		  ? inst.operands[0].writeback
9196218822Sdim		  : (inst.operands[0].writeback
9197218822Sdim		     == !(inst.operands[1].imm & mask))))
9198218822Sdim	    {
9199218822Sdim	      if (inst.instruction == T_MNEM_stmia
9200218822Sdim		  && (inst.operands[1].imm & mask)
9201218822Sdim		  && (inst.operands[1].imm & (mask - 1)))
9202218822Sdim		as_warn (_("value stored for r%d is UNPREDICTABLE"),
9203218822Sdim			 inst.operands[0].reg);
920460484Sobrien
9205218822Sdim	      inst.instruction = THUMB_OP16 (inst.instruction);
9206218822Sdim	      inst.instruction |= inst.operands[0].reg << 8;
9207218822Sdim	      inst.instruction |= inst.operands[1].imm;
9208218822Sdim	      narrow = TRUE;
9209218822Sdim	    }
9210218822Sdim	  else if (inst.operands[0] .reg == REG_SP
9211218822Sdim		   && inst.operands[0].writeback)
9212218822Sdim	    {
9213218822Sdim	      inst.instruction = THUMB_OP16 (inst.instruction == T_MNEM_stmia
9214218822Sdim					     ? T_MNEM_push : T_MNEM_pop);
9215218822Sdim	      inst.instruction |= inst.operands[1].imm;
9216218822Sdim	      narrow = TRUE;
9217218822Sdim	    }
9218218822Sdim	}
921960484Sobrien
9220218822Sdim      if (!narrow)
9221218822Sdim	{
9222218822Sdim	  if (inst.instruction < 0xffff)
9223218822Sdim	    inst.instruction = THUMB_OP32 (inst.instruction);
9224218822Sdim
9225218822Sdim	  encode_thumb2_ldmstm(inst.operands[0].reg, inst.operands[1].imm,
9226218822Sdim			       inst.operands[0].writeback);
9227218822Sdim	}
922860484Sobrien    }
9229218822Sdim  else
923060484Sobrien    {
9231218822Sdim      constraint (inst.operands[0].reg > 7
9232218822Sdim		  || (inst.operands[1].imm & ~0xff), BAD_HIREG);
9233218822Sdim      constraint (inst.instruction != T_MNEM_ldmia
9234218822Sdim		  && inst.instruction != T_MNEM_stmia,
9235218822Sdim		  _("Thumb-2 instruction only valid in unified syntax"));
9236218822Sdim      if (inst.instruction == T_MNEM_stmia)
923760484Sobrien	{
9238218822Sdim	  if (!inst.operands[0].writeback)
9239218822Sdim	    as_warn (_("this instruction will write back the base register"));
9240218822Sdim	  if ((inst.operands[1].imm & (1 << inst.operands[0].reg))
9241218822Sdim	      && (inst.operands[1].imm & ((1 << inst.operands[0].reg) - 1)))
9242218822Sdim	    as_warn (_("value stored for r%d is UNPREDICTABLE"),
9243218822Sdim		     inst.operands[0].reg);
924460484Sobrien	}
9245218822Sdim      else
9246218822Sdim	{
9247218822Sdim	  if (!inst.operands[0].writeback
9248218822Sdim	      && !(inst.operands[1].imm & (1 << inst.operands[0].reg)))
9249218822Sdim	    as_warn (_("this instruction will write back the base register"));
9250218822Sdim	  else if (inst.operands[0].writeback
9251218822Sdim		   && (inst.operands[1].imm & (1 << inst.operands[0].reg)))
9252218822Sdim	    as_warn (_("this instruction will not write back the base register"));
9253218822Sdim	}
9254218822Sdim
9255218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
9256218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
9257218822Sdim      inst.instruction |= inst.operands[1].imm;
925860484Sobrien    }
925960484Sobrien}
926060484Sobrien
926160484Sobrienstatic void
9262218822Sdimdo_t_ldrex (void)
926360484Sobrien{
9264218822Sdim  constraint (!inst.operands[1].isreg || !inst.operands[1].preind
9265218822Sdim	      || inst.operands[1].postind || inst.operands[1].writeback
9266218822Sdim	      || inst.operands[1].immisreg || inst.operands[1].shifted
9267218822Sdim	      || inst.operands[1].negative,
9268218822Sdim	      BAD_ADDR_MODE);
926960484Sobrien
9270218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9271218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
9272218822Sdim  inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_U8;
9273218822Sdim}
927460484Sobrien
9275218822Sdimstatic void
9276218822Sdimdo_t_ldrexd (void)
9277218822Sdim{
9278218822Sdim  if (!inst.operands[1].present)
927960484Sobrien    {
9280218822Sdim      constraint (inst.operands[0].reg == REG_LR,
9281218822Sdim		  _("r14 not allowed as first register "
9282218822Sdim		    "when second register is omitted"));
9283218822Sdim      inst.operands[1].reg = inst.operands[0].reg + 1;
928460484Sobrien    }
9285218822Sdim  constraint (inst.operands[0].reg == inst.operands[1].reg,
9286218822Sdim	      BAD_OVERLAP);
928760484Sobrien
9288218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9289218822Sdim  inst.instruction |= inst.operands[1].reg << 8;
9290218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
929160484Sobrien}
929260484Sobrien
929360484Sobrienstatic void
9294218822Sdimdo_t_ldst (void)
929560484Sobrien{
9296218822Sdim  unsigned long opcode;
9297218822Sdim  int Rn;
929860484Sobrien
9299218822Sdim  opcode = inst.instruction;
9300218822Sdim  if (unified_syntax)
930160484Sobrien    {
9302218822Sdim      if (!inst.operands[1].isreg)
9303218822Sdim	{
9304218822Sdim	  if (opcode <= 0xffff)
9305218822Sdim	    inst.instruction = THUMB_OP32 (opcode);
9306218822Sdim	  if (move_or_literal_pool (0, /*thumb_p=*/TRUE, /*mode_3=*/FALSE))
9307218822Sdim	    return;
9308218822Sdim	}
9309218822Sdim      if (inst.operands[1].isreg
9310218822Sdim	  && !inst.operands[1].writeback
9311218822Sdim	  && !inst.operands[1].shifted && !inst.operands[1].postind
9312218822Sdim	  && !inst.operands[1].negative && inst.operands[0].reg <= 7
9313218822Sdim	  && opcode <= 0xffff
9314218822Sdim	  && inst.size_req != 4)
9315218822Sdim	{
9316218822Sdim	  /* Insn may have a 16-bit form.  */
9317218822Sdim	  Rn = inst.operands[1].reg;
9318218822Sdim	  if (inst.operands[1].immisreg)
9319218822Sdim	    {
9320218822Sdim	      inst.instruction = THUMB_OP16 (opcode);
9321218822Sdim	      /* [Rn, Ri] */
9322218822Sdim	      if (Rn <= 7 && inst.operands[1].imm <= 7)
9323218822Sdim		goto op16;
9324218822Sdim	    }
9325218822Sdim	  else if ((Rn <= 7 && opcode != T_MNEM_ldrsh
9326218822Sdim		    && opcode != T_MNEM_ldrsb)
9327218822Sdim		   || ((Rn == REG_PC || Rn == REG_SP) && opcode == T_MNEM_ldr)
9328218822Sdim		   || (Rn == REG_SP && opcode == T_MNEM_str))
9329218822Sdim	    {
9330218822Sdim	      /* [Rn, #const] */
9331218822Sdim	      if (Rn > 7)
9332218822Sdim		{
9333218822Sdim		  if (Rn == REG_PC)
9334218822Sdim		    {
9335218822Sdim		      if (inst.reloc.pc_rel)
9336218822Sdim			opcode = T_MNEM_ldr_pc2;
9337218822Sdim		      else
9338218822Sdim			opcode = T_MNEM_ldr_pc;
9339218822Sdim		    }
9340218822Sdim		  else
9341218822Sdim		    {
9342218822Sdim		      if (opcode == T_MNEM_ldr)
9343218822Sdim			opcode = T_MNEM_ldr_sp;
9344218822Sdim		      else
9345218822Sdim			opcode = T_MNEM_str_sp;
9346218822Sdim		    }
9347218822Sdim		  inst.instruction = inst.operands[0].reg << 8;
9348218822Sdim		}
9349218822Sdim	      else
9350218822Sdim		{
9351218822Sdim		  inst.instruction = inst.operands[0].reg;
9352218822Sdim		  inst.instruction |= inst.operands[1].reg << 3;
9353218822Sdim		}
9354218822Sdim	      inst.instruction |= THUMB_OP16 (opcode);
9355218822Sdim	      if (inst.size_req == 2)
9356218822Sdim		inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
9357218822Sdim	      else
9358218822Sdim		inst.relax = opcode;
9359218822Sdim	      return;
9360218822Sdim	    }
9361218822Sdim	}
9362218822Sdim      /* Definitely a 32-bit variant.  */
9363218822Sdim      inst.instruction = THUMB_OP32 (opcode);
9364218822Sdim      inst.instruction |= inst.operands[0].reg << 12;
9365218822Sdim      encode_thumb32_addr_mode (1, /*is_t=*/FALSE, /*is_d=*/FALSE);
936660484Sobrien      return;
936760484Sobrien    }
936860484Sobrien
9369218822Sdim  constraint (inst.operands[0].reg > 7, BAD_HIREG);
9370218822Sdim
9371218822Sdim  if (inst.instruction == T_MNEM_ldrsh || inst.instruction == T_MNEM_ldrsb)
937260484Sobrien    {
9373218822Sdim      /* Only [Rn,Rm] is acceptable.  */
9374218822Sdim      constraint (inst.operands[1].reg > 7 || inst.operands[1].imm > 7, BAD_HIREG);
9375218822Sdim      constraint (!inst.operands[1].isreg || !inst.operands[1].immisreg
9376218822Sdim		  || inst.operands[1].postind || inst.operands[1].shifted
9377218822Sdim		  || inst.operands[1].negative,
9378218822Sdim		  _("Thumb does not support this addressing mode"));
9379218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
9380218822Sdim      goto op16;
9381218822Sdim    }
9382218822Sdim
9383218822Sdim  inst.instruction = THUMB_OP16 (inst.instruction);
9384218822Sdim  if (!inst.operands[1].isreg)
9385218822Sdim    if (move_or_literal_pool (0, /*thumb_p=*/TRUE, /*mode_3=*/FALSE))
938660484Sobrien      return;
938760484Sobrien
9388218822Sdim  constraint (!inst.operands[1].preind
9389218822Sdim	      || inst.operands[1].shifted
9390218822Sdim	      || inst.operands[1].writeback,
9391218822Sdim	      _("Thumb does not support this addressing mode"));
9392218822Sdim  if (inst.operands[1].reg == REG_PC || inst.operands[1].reg == REG_SP)
9393218822Sdim    {
9394218822Sdim      constraint (inst.instruction & 0x0600,
9395218822Sdim		  _("byte or halfword not valid for base register"));
9396218822Sdim      constraint (inst.operands[1].reg == REG_PC
9397218822Sdim		  && !(inst.instruction & THUMB_LOAD_BIT),
9398218822Sdim		  _("r15 based store not allowed"));
9399218822Sdim      constraint (inst.operands[1].immisreg,
9400218822Sdim		  _("invalid base register for register offset"));
940160484Sobrien
9402218822Sdim      if (inst.operands[1].reg == REG_PC)
9403218822Sdim	inst.instruction = T_OPCODE_LDR_PC;
9404218822Sdim      else if (inst.instruction & THUMB_LOAD_BIT)
9405218822Sdim	inst.instruction = T_OPCODE_LDR_SP;
9406218822Sdim      else
9407218822Sdim	inst.instruction = T_OPCODE_STR_SP;
940860484Sobrien
9409218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
9410218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
941160484Sobrien      return;
941260484Sobrien    }
941360484Sobrien
9414218822Sdim  constraint (inst.operands[1].reg > 7, BAD_HIREG);
9415218822Sdim  if (!inst.operands[1].immisreg)
941660484Sobrien    {
9417218822Sdim      /* Immediate offset.  */
9418218822Sdim      inst.instruction |= inst.operands[0].reg;
9419218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
9420218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
942160484Sobrien      return;
942260484Sobrien    }
942360484Sobrien
9424218822Sdim  /* Register offset.  */
9425218822Sdim  constraint (inst.operands[1].imm > 7, BAD_HIREG);
9426218822Sdim  constraint (inst.operands[1].negative,
9427218822Sdim	      _("Thumb does not support this addressing mode"));
9428218822Sdim
9429218822Sdim op16:
9430218822Sdim  switch (inst.instruction)
943160484Sobrien    {
9432218822Sdim    case T_OPCODE_STR_IW: inst.instruction = T_OPCODE_STR_RW; break;
9433218822Sdim    case T_OPCODE_STR_IH: inst.instruction = T_OPCODE_STR_RH; break;
9434218822Sdim    case T_OPCODE_STR_IB: inst.instruction = T_OPCODE_STR_RB; break;
9435218822Sdim    case T_OPCODE_LDR_IW: inst.instruction = T_OPCODE_LDR_RW; break;
9436218822Sdim    case T_OPCODE_LDR_IH: inst.instruction = T_OPCODE_LDR_RH; break;
9437218822Sdim    case T_OPCODE_LDR_IB: inst.instruction = T_OPCODE_LDR_RB; break;
9438218822Sdim    case 0x5600 /* ldrsb */:
9439218822Sdim    case 0x5e00 /* ldrsh */: break;
9440218822Sdim    default: abort ();
944160484Sobrien    }
944260484Sobrien
9443218822Sdim  inst.instruction |= inst.operands[0].reg;
9444218822Sdim  inst.instruction |= inst.operands[1].reg << 3;
9445218822Sdim  inst.instruction |= inst.operands[1].imm << 6;
9446218822Sdim}
944760484Sobrien
9448218822Sdimstatic void
9449218822Sdimdo_t_ldstd (void)
9450218822Sdim{
9451218822Sdim  if (!inst.operands[1].present)
945260484Sobrien    {
9453218822Sdim      inst.operands[1].reg = inst.operands[0].reg + 1;
9454218822Sdim      constraint (inst.operands[0].reg == REG_LR,
9455218822Sdim		  _("r14 not allowed here"));
945660484Sobrien    }
9457218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9458218822Sdim  inst.instruction |= inst.operands[1].reg << 8;
9459218822Sdim  encode_thumb32_addr_mode (2, /*is_t=*/FALSE, /*is_d=*/TRUE);
9460218822Sdim
9461218822Sdim}
946260484Sobrien
9463218822Sdimstatic void
9464218822Sdimdo_t_ldstt (void)
9465218822Sdim{
9466218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9467218822Sdim  encode_thumb32_addr_mode (1, /*is_t=*/TRUE, /*is_d=*/FALSE);
9468218822Sdim}
946960484Sobrien
9470218822Sdimstatic void
9471218822Sdimdo_t_mla (void)
9472218822Sdim{
9473218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
9474218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
9475218822Sdim  inst.instruction |= inst.operands[2].reg;
9476218822Sdim  inst.instruction |= inst.operands[3].reg << 12;
9477218822Sdim}
947860484Sobrien
9479218822Sdimstatic void
9480218822Sdimdo_t_mlal (void)
9481218822Sdim{
9482218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9483218822Sdim  inst.instruction |= inst.operands[1].reg << 8;
9484218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
9485218822Sdim  inst.instruction |= inst.operands[3].reg;
9486218822Sdim}
948760484Sobrien
9488218822Sdimstatic void
9489218822Sdimdo_t_mov_cmp (void)
9490218822Sdim{
9491218822Sdim  if (unified_syntax)
9492218822Sdim    {
9493218822Sdim      int r0off = (inst.instruction == T_MNEM_mov
9494218822Sdim		   || inst.instruction == T_MNEM_movs) ? 8 : 16;
9495218822Sdim      unsigned long opcode;
9496218822Sdim      bfd_boolean narrow;
9497218822Sdim      bfd_boolean low_regs;
949860484Sobrien
9499218822Sdim      low_regs = (inst.operands[0].reg <= 7 && inst.operands[1].reg <= 7);
9500218822Sdim      opcode = inst.instruction;
9501218822Sdim      if (current_it_mask)
9502218822Sdim	narrow = opcode != T_MNEM_movs;
9503218822Sdim      else
9504218822Sdim	narrow = opcode != T_MNEM_movs || low_regs;
9505218822Sdim      if (inst.size_req == 4
9506218822Sdim	  || inst.operands[1].shifted)
9507218822Sdim	narrow = FALSE;
950860484Sobrien
9509218822Sdim      /* MOVS PC, LR is encoded as SUBS PC, LR, #0.  */
9510218822Sdim      if (opcode == T_MNEM_movs && inst.operands[1].isreg
9511218822Sdim	  && !inst.operands[1].shifted
9512218822Sdim	  && inst.operands[0].reg == REG_PC
9513218822Sdim	  && inst.operands[1].reg == REG_LR)
951460484Sobrien	{
9515218822Sdim	  inst.instruction = T2_SUBS_PC_LR;
951660484Sobrien	  return;
951760484Sobrien	}
951860484Sobrien
9519218822Sdim      if (!inst.operands[1].isreg)
952060484Sobrien	{
9521218822Sdim	  /* Immediate operand.  */
9522218822Sdim	  if (current_it_mask == 0 && opcode == T_MNEM_mov)
9523218822Sdim	    narrow = 0;
9524218822Sdim	  if (low_regs && narrow)
952560484Sobrien	    {
9526218822Sdim	      inst.instruction = THUMB_OP16 (opcode);
9527218822Sdim	      inst.instruction |= inst.operands[0].reg << 8;
9528218822Sdim	      if (inst.size_req == 2)
9529218822Sdim		inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
9530218822Sdim	      else
9531218822Sdim		inst.relax = opcode;
953260484Sobrien	    }
9533218822Sdim	  else
9534218822Sdim	    {
9535218822Sdim	      inst.instruction = THUMB_OP32 (inst.instruction);
9536218822Sdim	      inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
9537218822Sdim	      inst.instruction |= inst.operands[0].reg << r0off;
9538218822Sdim	      inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
9539218822Sdim	    }
954060484Sobrien	}
9541218822Sdim      else if (inst.operands[1].shifted && inst.operands[1].immisreg
9542218822Sdim	       && (inst.instruction == T_MNEM_mov
9543218822Sdim		   || inst.instruction == T_MNEM_movs))
9544218822Sdim	{
9545218822Sdim	  /* Register shifts are encoded as separate shift instructions.  */
9546218822Sdim	  bfd_boolean flags = (inst.instruction == T_MNEM_movs);
954760484Sobrien
9548218822Sdim	  if (current_it_mask)
9549218822Sdim	    narrow = !flags;
9550218822Sdim	  else
9551218822Sdim	    narrow = flags;
9552218822Sdim
9553218822Sdim	  if (inst.size_req == 4)
9554218822Sdim	    narrow = FALSE;
9555218822Sdim
9556218822Sdim	  if (!low_regs || inst.operands[1].imm > 7)
9557218822Sdim	    narrow = FALSE;
9558218822Sdim
9559218822Sdim	  if (inst.operands[0].reg != inst.operands[1].reg)
9560218822Sdim	    narrow = FALSE;
9561218822Sdim
9562218822Sdim	  switch (inst.operands[1].shift_kind)
9563218822Sdim	    {
9564218822Sdim	    case SHIFT_LSL:
9565218822Sdim	      opcode = narrow ? T_OPCODE_LSL_R : THUMB_OP32 (T_MNEM_lsl);
9566218822Sdim	      break;
9567218822Sdim	    case SHIFT_ASR:
9568218822Sdim	      opcode = narrow ? T_OPCODE_ASR_R : THUMB_OP32 (T_MNEM_asr);
9569218822Sdim	      break;
9570218822Sdim	    case SHIFT_LSR:
9571218822Sdim	      opcode = narrow ? T_OPCODE_LSR_R : THUMB_OP32 (T_MNEM_lsr);
9572218822Sdim	      break;
9573218822Sdim	    case SHIFT_ROR:
9574218822Sdim	      opcode = narrow ? T_OPCODE_ROR_R : THUMB_OP32 (T_MNEM_ror);
9575218822Sdim	      break;
9576218822Sdim	    default:
9577218822Sdim	      abort();
9578218822Sdim	    }
9579218822Sdim
9580218822Sdim	  inst.instruction = opcode;
9581218822Sdim	  if (narrow)
9582218822Sdim	    {
9583218822Sdim	      inst.instruction |= inst.operands[0].reg;
9584218822Sdim	      inst.instruction |= inst.operands[1].imm << 3;
9585218822Sdim	    }
9586218822Sdim	  else
9587218822Sdim	    {
9588218822Sdim	      if (flags)
9589218822Sdim		inst.instruction |= CONDS_BIT;
9590218822Sdim
9591218822Sdim	      inst.instruction |= inst.operands[0].reg << 8;
9592218822Sdim	      inst.instruction |= inst.operands[1].reg << 16;
9593218822Sdim	      inst.instruction |= inst.operands[1].imm;
9594218822Sdim	    }
959560484Sobrien	}
9596218822Sdim      else if (!narrow)
959760484Sobrien	{
9598218822Sdim	  /* Some mov with immediate shift have narrow variants.
9599218822Sdim	     Register shifts are handled above.  */
9600218822Sdim	  if (low_regs && inst.operands[1].shifted
9601218822Sdim	      && (inst.instruction == T_MNEM_mov
9602218822Sdim		  || inst.instruction == T_MNEM_movs))
960360484Sobrien	    {
9604218822Sdim	      if (current_it_mask)
9605218822Sdim		narrow = (inst.instruction == T_MNEM_mov);
9606218822Sdim	      else
9607218822Sdim		narrow = (inst.instruction == T_MNEM_movs);
960860484Sobrien	    }
9609218822Sdim
9610218822Sdim	  if (narrow)
9611218822Sdim	    {
9612218822Sdim	      switch (inst.operands[1].shift_kind)
9613218822Sdim		{
9614218822Sdim		case SHIFT_LSL: inst.instruction = T_OPCODE_LSL_I; break;
9615218822Sdim		case SHIFT_LSR: inst.instruction = T_OPCODE_LSR_I; break;
9616218822Sdim		case SHIFT_ASR: inst.instruction = T_OPCODE_ASR_I; break;
9617218822Sdim		default: narrow = FALSE; break;
9618218822Sdim		}
9619218822Sdim	    }
9620218822Sdim
9621218822Sdim	  if (narrow)
9622218822Sdim	    {
9623218822Sdim	      inst.instruction |= inst.operands[0].reg;
9624218822Sdim	      inst.instruction |= inst.operands[1].reg << 3;
9625218822Sdim	      inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
9626218822Sdim	    }
962760484Sobrien	  else
962860484Sobrien	    {
9629218822Sdim	      inst.instruction = THUMB_OP32 (inst.instruction);
9630218822Sdim	      inst.instruction |= inst.operands[0].reg << r0off;
9631218822Sdim	      encode_thumb32_shifted_operand (1);
963260484Sobrien	    }
963360484Sobrien	}
9634218822Sdim      else
9635218822Sdim	switch (inst.instruction)
9636218822Sdim	  {
9637218822Sdim	  case T_MNEM_mov:
9638218822Sdim	    inst.instruction = T_OPCODE_MOV_HR;
9639218822Sdim	    inst.instruction |= (inst.operands[0].reg & 0x8) << 4;
9640218822Sdim	    inst.instruction |= (inst.operands[0].reg & 0x7);
9641218822Sdim	    inst.instruction |= inst.operands[1].reg << 3;
9642218822Sdim	    break;
964360484Sobrien
9644218822Sdim	  case T_MNEM_movs:
9645218822Sdim	    /* We know we have low registers at this point.
9646218822Sdim	       Generate ADD Rd, Rs, #0.  */
9647218822Sdim	    inst.instruction = T_OPCODE_ADD_I3;
9648218822Sdim	    inst.instruction |= inst.operands[0].reg;
9649218822Sdim	    inst.instruction |= inst.operands[1].reg << 3;
9650218822Sdim	    break;
9651218822Sdim
9652218822Sdim	  case T_MNEM_cmp:
9653218822Sdim	    if (low_regs)
9654218822Sdim	      {
9655218822Sdim		inst.instruction = T_OPCODE_CMP_LR;
9656218822Sdim		inst.instruction |= inst.operands[0].reg;
9657218822Sdim		inst.instruction |= inst.operands[1].reg << 3;
9658218822Sdim	      }
9659218822Sdim	    else
9660218822Sdim	      {
9661218822Sdim		inst.instruction = T_OPCODE_CMP_HR;
9662218822Sdim		inst.instruction |= (inst.operands[0].reg & 0x8) << 4;
9663218822Sdim		inst.instruction |= (inst.operands[0].reg & 0x7);
9664218822Sdim		inst.instruction |= inst.operands[1].reg << 3;
9665218822Sdim	      }
9666218822Sdim	    break;
9667218822Sdim	  }
9668218822Sdim      return;
966960484Sobrien    }
9670218822Sdim
9671218822Sdim  inst.instruction = THUMB_OP16 (inst.instruction);
9672218822Sdim  if (inst.operands[1].isreg)
967360484Sobrien    {
9674218822Sdim      if (inst.operands[0].reg < 8 && inst.operands[1].reg < 8)
9675218822Sdim	{
9676218822Sdim	  /* A move of two lowregs is encoded as ADD Rd, Rs, #0
9677218822Sdim	     since a MOV instruction produces unpredictable results.  */
9678218822Sdim	  if (inst.instruction == T_OPCODE_MOV_I8)
9679218822Sdim	    inst.instruction = T_OPCODE_ADD_I3;
9680218822Sdim	  else
9681218822Sdim	    inst.instruction = T_OPCODE_CMP_LR;
9682218822Sdim
9683218822Sdim	  inst.instruction |= inst.operands[0].reg;
9684218822Sdim	  inst.instruction |= inst.operands[1].reg << 3;
9685218822Sdim	}
9686218822Sdim      else
9687218822Sdim	{
9688218822Sdim	  if (inst.instruction == T_OPCODE_MOV_I8)
9689218822Sdim	    inst.instruction = T_OPCODE_MOV_HR;
9690218822Sdim	  else
9691218822Sdim	    inst.instruction = T_OPCODE_CMP_HR;
9692218822Sdim	  do_t_cpy ();
9693218822Sdim	}
969460484Sobrien    }
9695218822Sdim  else
9696218822Sdim    {
9697218822Sdim      constraint (inst.operands[0].reg > 7,
9698218822Sdim		  _("only lo regs allowed with immediate"));
9699218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
9700218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
9701218822Sdim    }
970260484Sobrien}
970360484Sobrien
970460484Sobrienstatic void
9705218822Sdimdo_t_mov16 (void)
970660484Sobrien{
9707218822Sdim  bfd_vma imm;
9708218822Sdim  bfd_boolean top;
970960484Sobrien
9710218822Sdim  top = (inst.instruction & 0x00800000) != 0;
9711218822Sdim  if (inst.reloc.type == BFD_RELOC_ARM_MOVW)
971260484Sobrien    {
9713218822Sdim      constraint (top, _(":lower16: not allowed this instruction"));
9714218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVW;
971560484Sobrien    }
9716218822Sdim  else if (inst.reloc.type == BFD_RELOC_ARM_MOVT)
971760484Sobrien    {
9718218822Sdim      constraint (!top, _(":upper16: not allowed this instruction"));
9719218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVT;
972060484Sobrien    }
972160484Sobrien
9722218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
9723218822Sdim  if (inst.reloc.type == BFD_RELOC_UNUSED)
972460484Sobrien    {
9725218822Sdim      imm = inst.reloc.exp.X_add_number;
9726218822Sdim      inst.instruction |= (imm & 0xf000) << 4;
9727218822Sdim      inst.instruction |= (imm & 0x0800) << 15;
9728218822Sdim      inst.instruction |= (imm & 0x0700) << 4;
9729218822Sdim      inst.instruction |= (imm & 0x00ff);
973060484Sobrien    }
973160484Sobrien}
973260484Sobrien
973360484Sobrienstatic void
9734218822Sdimdo_t_mvn_tst (void)
973560484Sobrien{
9736218822Sdim  if (unified_syntax)
9737218822Sdim    {
9738218822Sdim      int r0off = (inst.instruction == T_MNEM_mvn
9739218822Sdim		   || inst.instruction == T_MNEM_mvns) ? 8 : 16;
9740218822Sdim      bfd_boolean narrow;
974160484Sobrien
9742218822Sdim      if (inst.size_req == 4
9743218822Sdim	  || inst.instruction > 0xffff
9744218822Sdim	  || inst.operands[1].shifted
9745218822Sdim	  || inst.operands[0].reg > 7 || inst.operands[1].reg > 7)
9746218822Sdim	narrow = FALSE;
9747218822Sdim      else if (inst.instruction == T_MNEM_cmn)
9748218822Sdim	narrow = TRUE;
9749218822Sdim      else if (THUMB_SETS_FLAGS (inst.instruction))
9750218822Sdim	narrow = (current_it_mask == 0);
9751218822Sdim      else
9752218822Sdim	narrow = (current_it_mask != 0);
9753218822Sdim
9754218822Sdim      if (!inst.operands[1].isreg)
9755218822Sdim	{
9756218822Sdim	  /* For an immediate, we always generate a 32-bit opcode;
9757218822Sdim	     section relaxation will shrink it later if possible.  */
9758218822Sdim	  if (inst.instruction < 0xffff)
9759218822Sdim	    inst.instruction = THUMB_OP32 (inst.instruction);
9760218822Sdim	  inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
9761218822Sdim	  inst.instruction |= inst.operands[0].reg << r0off;
9762218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
9763218822Sdim	}
9764218822Sdim      else
9765218822Sdim	{
9766218822Sdim	  /* See if we can do this with a 16-bit instruction.  */
9767218822Sdim	  if (narrow)
9768218822Sdim	    {
9769218822Sdim	      inst.instruction = THUMB_OP16 (inst.instruction);
9770218822Sdim	      inst.instruction |= inst.operands[0].reg;
9771218822Sdim	      inst.instruction |= inst.operands[1].reg << 3;
9772218822Sdim	    }
9773218822Sdim	  else
9774218822Sdim	    {
9775218822Sdim	      constraint (inst.operands[1].shifted
9776218822Sdim			  && inst.operands[1].immisreg,
9777218822Sdim			  _("shift must be constant"));
9778218822Sdim	      if (inst.instruction < 0xffff)
9779218822Sdim		inst.instruction = THUMB_OP32 (inst.instruction);
9780218822Sdim	      inst.instruction |= inst.operands[0].reg << r0off;
9781218822Sdim	      encode_thumb32_shifted_operand (1);
9782218822Sdim	    }
9783218822Sdim	}
9784218822Sdim    }
9785218822Sdim  else
978660484Sobrien    {
9787218822Sdim      constraint (inst.instruction > 0xffff
9788218822Sdim		  || inst.instruction == T_MNEM_mvns, BAD_THUMB32);
9789218822Sdim      constraint (!inst.operands[1].isreg || inst.operands[1].shifted,
9790218822Sdim		  _("unshifted register required"));
9791218822Sdim      constraint (inst.operands[0].reg > 7 || inst.operands[1].reg > 7,
9792218822Sdim		  BAD_HIREG);
979360484Sobrien
9794218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
9795218822Sdim      inst.instruction |= inst.operands[0].reg;
9796218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
979760484Sobrien    }
979889857Sobrien}
979989857Sobrien
980089857Sobrienstatic void
9801218822Sdimdo_t_mrs (void)
980289857Sobrien{
9803218822Sdim  int flags;
980489857Sobrien
9805218822Sdim  if (do_vfp_nsyn_mrs () == SUCCESS)
9806218822Sdim    return;
9807218822Sdim
9808218822Sdim  flags = inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f|SPSR_BIT);
9809218822Sdim  if (flags == 0)
981089857Sobrien    {
9811218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7m),
9812218822Sdim		  _("selected processor does not support "
9813218822Sdim		    "requested special purpose register"));
981489857Sobrien    }
9815218822Sdim  else
981660484Sobrien    {
9817218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1),
9818218822Sdim		  _("selected processor does not support "
9819218822Sdim		    "requested special purpose register %x"));
9820218822Sdim      /* mrs only accepts CPSR/SPSR/CPSR_all/SPSR_all.  */
9821218822Sdim      constraint ((flags & ~SPSR_BIT) != (PSR_c|PSR_f),
9822218822Sdim		  _("'CPSR' or 'SPSR' expected"));
982360484Sobrien    }
9824218822Sdim
9825218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
9826218822Sdim  inst.instruction |= (flags & SPSR_BIT) >> 2;
9827218822Sdim  inst.instruction |= inst.operands[1].imm & 0xff;
982860484Sobrien}
982960484Sobrien
983060484Sobrienstatic void
9831218822Sdimdo_t_msr (void)
983260484Sobrien{
9833218822Sdim  int flags;
983460484Sobrien
9835218822Sdim  if (do_vfp_nsyn_msr () == SUCCESS)
9836218822Sdim    return;
9837218822Sdim
9838218822Sdim  constraint (!inst.operands[1].isreg,
9839218822Sdim	      _("Thumb encoding does not support an immediate here"));
9840218822Sdim  flags = inst.operands[0].imm;
9841218822Sdim  if (flags & ~0xff)
984260484Sobrien    {
9843218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1),
9844218822Sdim		  _("selected processor does not support "
9845218822Sdim		    "requested special purpose register"));
984660484Sobrien    }
9847218822Sdim  else
984860484Sobrien    {
9849218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7m),
9850218822Sdim		  _("selected processor does not support "
9851218822Sdim		    "requested special purpose register"));
9852218822Sdim      flags |= PSR_f;
985360484Sobrien    }
9854218822Sdim  inst.instruction |= (flags & SPSR_BIT) >> 2;
9855218822Sdim  inst.instruction |= (flags & ~SPSR_BIT) >> 8;
9856218822Sdim  inst.instruction |= (flags & 0xff);
9857218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
985860484Sobrien}
985960484Sobrien
986060484Sobrienstatic void
9861218822Sdimdo_t_mul (void)
986260484Sobrien{
9863218822Sdim  if (!inst.operands[2].present)
9864218822Sdim    inst.operands[2].reg = inst.operands[0].reg;
986560484Sobrien
9866218822Sdim  /* There is no 32-bit MULS and no 16-bit MUL. */
9867218822Sdim  if (unified_syntax && inst.instruction == T_MNEM_mul)
986860484Sobrien    {
9869218822Sdim      inst.instruction = THUMB_OP32 (inst.instruction);
9870218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
9871218822Sdim      inst.instruction |= inst.operands[1].reg << 16;
9872218822Sdim      inst.instruction |= inst.operands[2].reg << 0;
987360484Sobrien    }
9874218822Sdim  else
9875218822Sdim    {
9876218822Sdim      constraint (!unified_syntax
9877218822Sdim		  && inst.instruction == T_MNEM_muls, BAD_THUMB32);
9878218822Sdim      constraint (inst.operands[0].reg > 7 || inst.operands[1].reg > 7,
9879218822Sdim		  BAD_HIREG);
988060484Sobrien
9881218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
9882218822Sdim      inst.instruction |= inst.operands[0].reg;
9883218822Sdim
9884218822Sdim      if (inst.operands[0].reg == inst.operands[1].reg)
9885218822Sdim	inst.instruction |= inst.operands[2].reg << 3;
9886218822Sdim      else if (inst.operands[0].reg == inst.operands[2].reg)
9887218822Sdim	inst.instruction |= inst.operands[1].reg << 3;
9888218822Sdim      else
9889218822Sdim	constraint (1, _("dest must overlap one source register"));
9890218822Sdim    }
989189857Sobrien}
989289857Sobrien
9893218822Sdimstatic void
9894218822Sdimdo_t_mull (void)
989589857Sobrien{
9896218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9897218822Sdim  inst.instruction |= inst.operands[1].reg << 8;
9898218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
9899218822Sdim  inst.instruction |= inst.operands[3].reg;
990089857Sobrien
9901218822Sdim  if (inst.operands[0].reg == inst.operands[1].reg)
9902218822Sdim    as_tsktsk (_("rdhi and rdlo must be different"));
9903218822Sdim}
9904218822Sdim
9905218822Sdimstatic void
9906218822Sdimdo_t_nop (void)
9907218822Sdim{
9908218822Sdim  if (unified_syntax)
990960484Sobrien    {
9910218822Sdim      if (inst.size_req == 4 || inst.operands[0].imm > 15)
991189857Sobrien	{
9912218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
9913218822Sdim	  inst.instruction |= inst.operands[0].imm;
991489857Sobrien	}
9915218822Sdim      else
9916218822Sdim	{
9917218822Sdim	  inst.instruction = THUMB_OP16 (inst.instruction);
9918218822Sdim	  inst.instruction |= inst.operands[0].imm << 4;
9919218822Sdim	}
992089857Sobrien    }
9921218822Sdim  else
9922218822Sdim    {
9923218822Sdim      constraint (inst.operands[0].present,
9924218822Sdim		  _("Thumb does not support NOP with hints"));
9925218822Sdim      inst.instruction = 0x46c0;
9926218822Sdim    }
992789857Sobrien}
992889857Sobrien
9929218822Sdimstatic void
9930218822Sdimdo_t_neg (void)
993189857Sobrien{
9932218822Sdim  if (unified_syntax)
993389857Sobrien    {
9934218822Sdim      bfd_boolean narrow;
993589857Sobrien
9936218822Sdim      if (THUMB_SETS_FLAGS (inst.instruction))
9937218822Sdim	narrow = (current_it_mask == 0);
9938218822Sdim      else
9939218822Sdim	narrow = (current_it_mask != 0);
9940218822Sdim      if (inst.operands[0].reg > 7 || inst.operands[1].reg > 7)
9941218822Sdim	narrow = FALSE;
9942218822Sdim      if (inst.size_req == 4)
9943218822Sdim	narrow = FALSE;
994489857Sobrien
9945218822Sdim      if (!narrow)
9946218822Sdim	{
9947218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
9948218822Sdim	  inst.instruction |= inst.operands[0].reg << 8;
9949218822Sdim	  inst.instruction |= inst.operands[1].reg << 16;
995089857Sobrien	}
9951218822Sdim      else
9952218822Sdim	{
9953218822Sdim	  inst.instruction = THUMB_OP16 (inst.instruction);
9954218822Sdim	  inst.instruction |= inst.operands[0].reg;
9955218822Sdim	  inst.instruction |= inst.operands[1].reg << 3;
9956218822Sdim	}
995789857Sobrien    }
9958218822Sdim  else
9959218822Sdim    {
9960218822Sdim      constraint (inst.operands[0].reg > 7 || inst.operands[1].reg > 7,
9961218822Sdim		  BAD_HIREG);
9962218822Sdim      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
996389857Sobrien
9964218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
9965218822Sdim      inst.instruction |= inst.operands[0].reg;
9966218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
9967218822Sdim    }
996889857Sobrien}
996989857Sobrien
997089857Sobrienstatic void
9971218822Sdimdo_t_pkhbt (void)
997289857Sobrien{
9973218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
9974218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
9975218822Sdim  inst.instruction |= inst.operands[2].reg;
9976218822Sdim  if (inst.operands[3].present)
997789857Sobrien    {
9978218822Sdim      unsigned int val = inst.reloc.exp.X_add_number;
9979218822Sdim      constraint (inst.reloc.exp.X_op != O_constant,
9980218822Sdim		  _("expression too complex"));
9981218822Sdim      inst.instruction |= (val & 0x1c) << 10;
9982218822Sdim      inst.instruction |= (val & 0x03) << 6;
998360484Sobrien    }
9984218822Sdim}
998560484Sobrien
9986218822Sdimstatic void
9987218822Sdimdo_t_pkhtb (void)
9988218822Sdim{
9989218822Sdim  if (!inst.operands[3].present)
9990218822Sdim    inst.instruction &= ~0x00000020;
9991218822Sdim  do_t_pkhbt ();
999289857Sobrien}
999389857Sobrien
999489857Sobrienstatic void
9995218822Sdimdo_t_pld (void)
999689857Sobrien{
9997218822Sdim  encode_thumb32_addr_mode (0, /*is_t=*/FALSE, /*is_d=*/FALSE);
9998218822Sdim}
999989857Sobrien
10000218822Sdimstatic void
10001218822Sdimdo_t_push_pop (void)
10002218822Sdim{
10003218822Sdim  unsigned mask;
10004218822Sdim
10005218822Sdim  constraint (inst.operands[0].writeback,
10006218822Sdim	      _("push/pop do not support {reglist}^"));
10007218822Sdim  constraint (inst.reloc.type != BFD_RELOC_UNUSED,
10008218822Sdim	      _("expression too complex"));
1000989857Sobrien
10010218822Sdim  mask = inst.operands[0].imm;
10011218822Sdim  if ((mask & ~0xff) == 0)
10012218822Sdim    inst.instruction = THUMB_OP16 (inst.instruction) | mask;
10013218822Sdim  else if ((inst.instruction == T_MNEM_push
10014218822Sdim	    && (mask & ~0xff) == 1 << REG_LR)
10015218822Sdim	   || (inst.instruction == T_MNEM_pop
10016218822Sdim	       && (mask & ~0xff) == 1 << REG_PC))
1001789857Sobrien    {
10018218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
10019218822Sdim      inst.instruction |= THUMB_PP_PC_LR;
10020218822Sdim      inst.instruction |= mask & 0xff;
10021218822Sdim    }
10022218822Sdim  else if (unified_syntax)
10023218822Sdim    {
10024218822Sdim      inst.instruction = THUMB_OP32 (inst.instruction);
10025218822Sdim      encode_thumb2_ldmstm(13, mask, TRUE);
10026218822Sdim    }
10027218822Sdim  else
10028218822Sdim    {
10029218822Sdim      inst.error = _("invalid register list to push/pop instruction");
1003089857Sobrien      return;
1003189857Sobrien    }
10032218822Sdim}
1003389857Sobrien
10034218822Sdimstatic void
10035218822Sdimdo_t_rbit (void)
10036218822Sdim{
10037218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10038218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
1003989857Sobrien}
1004089857Sobrien
1004189857Sobrienstatic void
10042223484Sdimdo_t_rd_rm (void)
10043223484Sdim{
10044223484Sdim  inst.instruction |= inst.operands[0].reg << 8;
10045223484Sdim  inst.instruction |= inst.operands[1].reg;
10046223484Sdim}
10047223484Sdim
10048223484Sdimstatic void
10049218822Sdimdo_t_rev (void)
1005089857Sobrien{
10051218822Sdim  if (inst.operands[0].reg <= 7 && inst.operands[1].reg <= 7
10052218822Sdim      && inst.size_req != 4)
1005389857Sobrien    {
10054218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
10055218822Sdim      inst.instruction |= inst.operands[0].reg;
10056218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
1005789857Sobrien    }
10058218822Sdim  else if (unified_syntax)
10059218822Sdim    {
10060218822Sdim      inst.instruction = THUMB_OP32 (inst.instruction);
10061218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
10062218822Sdim      inst.instruction |= inst.operands[1].reg << 16;
10063218822Sdim      inst.instruction |= inst.operands[1].reg;
10064218822Sdim    }
10065218822Sdim  else
10066218822Sdim    inst.error = BAD_HIREG;
1006789857Sobrien}
1006889857Sobrien
1006989857Sobrienstatic void
10070218822Sdimdo_t_rsb (void)
1007189857Sobrien{
10072218822Sdim  int Rd, Rs;
1007389857Sobrien
10074218822Sdim  Rd = inst.operands[0].reg;
10075218822Sdim  Rs = (inst.operands[1].present
10076218822Sdim	? inst.operands[1].reg    /* Rd, Rs, foo */
10077218822Sdim	: inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
1007889857Sobrien
10079218822Sdim  inst.instruction |= Rd << 8;
10080218822Sdim  inst.instruction |= Rs << 16;
10081218822Sdim  if (!inst.operands[2].isreg)
1008289857Sobrien    {
10083218822Sdim      bfd_boolean narrow;
1008489857Sobrien
10085218822Sdim      if ((inst.instruction & 0x00100000) != 0)
10086218822Sdim	narrow = (current_it_mask == 0);
10087218822Sdim      else
10088218822Sdim	narrow = (current_it_mask != 0);
1008989857Sobrien
10090218822Sdim      if (Rd > 7 || Rs > 7)
10091218822Sdim	narrow = FALSE;
1009289857Sobrien
10093218822Sdim      if (inst.size_req == 4 || !unified_syntax)
10094218822Sdim	narrow = FALSE;
1009589857Sobrien
10096218822Sdim      if (inst.reloc.exp.X_op != O_constant
10097218822Sdim	  || inst.reloc.exp.X_add_number != 0)
10098218822Sdim	narrow = FALSE;
10099218822Sdim
10100218822Sdim      /* Turn rsb #0 into 16-bit neg.  We should probably do this via
10101218822Sdim         relaxation, but it doesn't seem worth the hassle.  */
10102218822Sdim      if (narrow)
10103218822Sdim	{
10104218822Sdim	  inst.reloc.type = BFD_RELOC_UNUSED;
10105218822Sdim	  inst.instruction = THUMB_OP16 (T_MNEM_negs);
10106218822Sdim	  inst.instruction |= Rs << 3;
10107218822Sdim	  inst.instruction |= Rd;
10108218822Sdim	}
10109218822Sdim      else
10110218822Sdim	{
10111218822Sdim	  inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
10112218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
10113218822Sdim	}
1011489857Sobrien    }
10115218822Sdim  else
10116218822Sdim    encode_thumb32_shifted_operand (2);
10117218822Sdim}
1011889857Sobrien
10119218822Sdimstatic void
10120218822Sdimdo_t_setend (void)
10121218822Sdim{
10122218822Sdim  constraint (current_it_mask, BAD_NOT_IT);
10123218822Sdim  if (inst.operands[0].imm)
10124218822Sdim    inst.instruction |= 0x8;
1012589857Sobrien}
1012689857Sobrien
1012789857Sobrienstatic void
10128218822Sdimdo_t_shift (void)
1012989857Sobrien{
10130218822Sdim  if (!inst.operands[1].present)
10131218822Sdim    inst.operands[1].reg = inst.operands[0].reg;
1013289857Sobrien
10133218822Sdim  if (unified_syntax)
1013489857Sobrien    {
10135218822Sdim      bfd_boolean narrow;
10136218822Sdim      int shift_kind;
10137218822Sdim
10138218822Sdim      switch (inst.instruction)
10139218822Sdim	{
10140218822Sdim	case T_MNEM_asr:
10141218822Sdim	case T_MNEM_asrs: shift_kind = SHIFT_ASR; break;
10142218822Sdim	case T_MNEM_lsl:
10143218822Sdim	case T_MNEM_lsls: shift_kind = SHIFT_LSL; break;
10144218822Sdim	case T_MNEM_lsr:
10145218822Sdim	case T_MNEM_lsrs: shift_kind = SHIFT_LSR; break;
10146218822Sdim	case T_MNEM_ror:
10147218822Sdim	case T_MNEM_rors: shift_kind = SHIFT_ROR; break;
10148218822Sdim	default: abort ();
10149218822Sdim	}
10150218822Sdim
10151218822Sdim      if (THUMB_SETS_FLAGS (inst.instruction))
10152218822Sdim	narrow = (current_it_mask == 0);
10153218822Sdim      else
10154218822Sdim	narrow = (current_it_mask != 0);
10155218822Sdim      if (inst.operands[0].reg > 7 || inst.operands[1].reg > 7)
10156218822Sdim	narrow = FALSE;
10157218822Sdim      if (!inst.operands[2].isreg && shift_kind == SHIFT_ROR)
10158218822Sdim	narrow = FALSE;
10159218822Sdim      if (inst.operands[2].isreg
10160218822Sdim	  && (inst.operands[1].reg != inst.operands[0].reg
10161218822Sdim	      || inst.operands[2].reg > 7))
10162218822Sdim	narrow = FALSE;
10163218822Sdim      if (inst.size_req == 4)
10164218822Sdim	narrow = FALSE;
10165218822Sdim
10166218822Sdim      if (!narrow)
10167218822Sdim	{
10168218822Sdim	  if (inst.operands[2].isreg)
10169218822Sdim	    {
10170218822Sdim	      inst.instruction = THUMB_OP32 (inst.instruction);
10171218822Sdim	      inst.instruction |= inst.operands[0].reg << 8;
10172218822Sdim	      inst.instruction |= inst.operands[1].reg << 16;
10173218822Sdim	      inst.instruction |= inst.operands[2].reg;
10174218822Sdim	    }
10175218822Sdim	  else
10176218822Sdim	    {
10177218822Sdim	      inst.operands[1].shifted = 1;
10178218822Sdim	      inst.operands[1].shift_kind = shift_kind;
10179218822Sdim	      inst.instruction = THUMB_OP32 (THUMB_SETS_FLAGS (inst.instruction)
10180218822Sdim					     ? T_MNEM_movs : T_MNEM_mov);
10181218822Sdim	      inst.instruction |= inst.operands[0].reg << 8;
10182218822Sdim	      encode_thumb32_shifted_operand (1);
10183218822Sdim	      /* Prevent the incorrect generation of an ARM_IMMEDIATE fixup.  */
10184218822Sdim	      inst.reloc.type = BFD_RELOC_UNUSED;
10185218822Sdim	    }
10186218822Sdim	}
10187218822Sdim      else
10188218822Sdim	{
10189218822Sdim	  if (inst.operands[2].isreg)
10190218822Sdim	    {
10191218822Sdim	      switch (shift_kind)
10192218822Sdim		{
10193218822Sdim		case SHIFT_ASR: inst.instruction = T_OPCODE_ASR_R; break;
10194218822Sdim		case SHIFT_LSL: inst.instruction = T_OPCODE_LSL_R; break;
10195218822Sdim		case SHIFT_LSR: inst.instruction = T_OPCODE_LSR_R; break;
10196218822Sdim		case SHIFT_ROR: inst.instruction = T_OPCODE_ROR_R; break;
10197218822Sdim		default: abort ();
10198218822Sdim		}
10199218822Sdim
10200218822Sdim	      inst.instruction |= inst.operands[0].reg;
10201218822Sdim	      inst.instruction |= inst.operands[2].reg << 3;
10202218822Sdim	    }
10203218822Sdim	  else
10204218822Sdim	    {
10205218822Sdim	      switch (shift_kind)
10206218822Sdim		{
10207218822Sdim		case SHIFT_ASR: inst.instruction = T_OPCODE_ASR_I; break;
10208218822Sdim		case SHIFT_LSL: inst.instruction = T_OPCODE_LSL_I; break;
10209218822Sdim		case SHIFT_LSR: inst.instruction = T_OPCODE_LSR_I; break;
10210218822Sdim		default: abort ();
10211218822Sdim		}
10212218822Sdim	      inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
10213218822Sdim	      inst.instruction |= inst.operands[0].reg;
10214218822Sdim	      inst.instruction |= inst.operands[1].reg << 3;
10215218822Sdim	    }
10216218822Sdim	}
1021789857Sobrien    }
10218218822Sdim  else
10219218822Sdim    {
10220218822Sdim      constraint (inst.operands[0].reg > 7
10221218822Sdim		  || inst.operands[1].reg > 7, BAD_HIREG);
10222218822Sdim      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
1022389857Sobrien
10224218822Sdim      if (inst.operands[2].isreg)  /* Rd, {Rs,} Rn */
10225218822Sdim	{
10226218822Sdim	  constraint (inst.operands[2].reg > 7, BAD_HIREG);
10227218822Sdim	  constraint (inst.operands[0].reg != inst.operands[1].reg,
10228218822Sdim		      _("source1 and dest must be same register"));
10229218822Sdim
10230218822Sdim	  switch (inst.instruction)
10231218822Sdim	    {
10232218822Sdim	    case T_MNEM_asr: inst.instruction = T_OPCODE_ASR_R; break;
10233218822Sdim	    case T_MNEM_lsl: inst.instruction = T_OPCODE_LSL_R; break;
10234218822Sdim	    case T_MNEM_lsr: inst.instruction = T_OPCODE_LSR_R; break;
10235218822Sdim	    case T_MNEM_ror: inst.instruction = T_OPCODE_ROR_R; break;
10236218822Sdim	    default: abort ();
10237218822Sdim	    }
10238218822Sdim
10239218822Sdim	  inst.instruction |= inst.operands[0].reg;
10240218822Sdim	  inst.instruction |= inst.operands[2].reg << 3;
10241218822Sdim	}
10242218822Sdim      else
10243218822Sdim	{
10244218822Sdim	  switch (inst.instruction)
10245218822Sdim	    {
10246218822Sdim	    case T_MNEM_asr: inst.instruction = T_OPCODE_ASR_I; break;
10247218822Sdim	    case T_MNEM_lsl: inst.instruction = T_OPCODE_LSL_I; break;
10248218822Sdim	    case T_MNEM_lsr: inst.instruction = T_OPCODE_LSR_I; break;
10249218822Sdim	    case T_MNEM_ror: inst.error = _("ror #imm not supported"); return;
10250218822Sdim	    default: abort ();
10251218822Sdim	    }
10252218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
10253218822Sdim	  inst.instruction |= inst.operands[0].reg;
10254218822Sdim	  inst.instruction |= inst.operands[1].reg << 3;
10255218822Sdim	}
1025689857Sobrien    }
10257218822Sdim}
1025889857Sobrien
10259218822Sdimstatic void
10260218822Sdimdo_t_simd (void)
10261218822Sdim{
10262218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10263218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
10264218822Sdim  inst.instruction |= inst.operands[2].reg;
1026589857Sobrien}
1026689857Sobrien
1026789857Sobrienstatic void
10268218822Sdimdo_t_smc (void)
1026989857Sobrien{
10270218822Sdim  unsigned int value = inst.reloc.exp.X_add_number;
10271218822Sdim  constraint (inst.reloc.exp.X_op != O_constant,
10272218822Sdim	      _("expression too complex"));
10273218822Sdim  inst.reloc.type = BFD_RELOC_UNUSED;
10274218822Sdim  inst.instruction |= (value & 0xf000) >> 12;
10275218822Sdim  inst.instruction |= (value & 0x0ff0);
10276218822Sdim  inst.instruction |= (value & 0x000f) << 16;
1027760484Sobrien}
1027860484Sobrien
1027960484Sobrienstatic void
10280218822Sdimdo_t_ssat (void)
10281130561Sobrien{
10282218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10283218822Sdim  inst.instruction |= inst.operands[1].imm - 1;
10284218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
10285130561Sobrien
10286218822Sdim  if (inst.operands[3].present)
10287130561Sobrien    {
10288218822Sdim      constraint (inst.reloc.exp.X_op != O_constant,
10289218822Sdim		  _("expression too complex"));
10290130561Sobrien
10291218822Sdim      if (inst.reloc.exp.X_add_number != 0)
10292218822Sdim	{
10293218822Sdim	  if (inst.operands[3].shift_kind == SHIFT_ASR)
10294218822Sdim	    inst.instruction |= 0x00200000;  /* sh bit */
10295218822Sdim	  inst.instruction |= (inst.reloc.exp.X_add_number & 0x1c) << 10;
10296218822Sdim	  inst.instruction |= (inst.reloc.exp.X_add_number & 0x03) << 6;
10297218822Sdim	}
10298218822Sdim      inst.reloc.type = BFD_RELOC_UNUSED;
10299130561Sobrien    }
10300218822Sdim}
10301130561Sobrien
10302218822Sdimstatic void
10303218822Sdimdo_t_ssat16 (void)
10304218822Sdim{
10305218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10306218822Sdim  inst.instruction |= inst.operands[1].imm - 1;
10307218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
10308130561Sobrien}
10309130561Sobrien
10310130561Sobrienstatic void
10311218822Sdimdo_t_strex (void)
1031260484Sobrien{
10313218822Sdim  constraint (!inst.operands[2].isreg || !inst.operands[2].preind
10314218822Sdim	      || inst.operands[2].postind || inst.operands[2].writeback
10315218822Sdim	      || inst.operands[2].immisreg || inst.operands[2].shifted
10316218822Sdim	      || inst.operands[2].negative,
10317218822Sdim	      BAD_ADDR_MODE);
1031860484Sobrien
10319218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10320218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
10321218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
10322218822Sdim  inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_U8;
1032360484Sobrien}
1032460484Sobrien
1032589857Sobrienstatic void
10326218822Sdimdo_t_strexd (void)
1032789857Sobrien{
10328218822Sdim  if (!inst.operands[2].present)
10329218822Sdim    inst.operands[2].reg = inst.operands[1].reg + 1;
1033089857Sobrien
10331218822Sdim  constraint (inst.operands[0].reg == inst.operands[1].reg
10332218822Sdim	      || inst.operands[0].reg == inst.operands[2].reg
10333218822Sdim	      || inst.operands[0].reg == inst.operands[3].reg
10334218822Sdim	      || inst.operands[1].reg == inst.operands[2].reg,
10335218822Sdim	      BAD_OVERLAP);
1033689857Sobrien
10337218822Sdim  inst.instruction |= inst.operands[0].reg;
10338218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
10339218822Sdim  inst.instruction |= inst.operands[2].reg << 8;
10340218822Sdim  inst.instruction |= inst.operands[3].reg << 16;
10341218822Sdim}
1034289857Sobrien
10343218822Sdimstatic void
10344218822Sdimdo_t_sxtah (void)
10345218822Sdim{
10346218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10347218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
10348218822Sdim  inst.instruction |= inst.operands[2].reg;
10349218822Sdim  inst.instruction |= inst.operands[3].imm << 4;
1035089857Sobrien}
1035189857Sobrien
1035289857Sobrienstatic void
10353218822Sdimdo_t_sxth (void)
1035489857Sobrien{
10355218822Sdim  if (inst.instruction <= 0xffff && inst.size_req != 4
10356218822Sdim      && inst.operands[0].reg <= 7 && inst.operands[1].reg <= 7
10357218822Sdim      && (!inst.operands[2].present || inst.operands[2].imm == 0))
1035889857Sobrien    {
10359218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
10360218822Sdim      inst.instruction |= inst.operands[0].reg;
10361218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
1036289857Sobrien    }
10363218822Sdim  else if (unified_syntax)
10364218822Sdim    {
10365218822Sdim      if (inst.instruction <= 0xffff)
10366218822Sdim	inst.instruction = THUMB_OP32 (inst.instruction);
10367218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
10368218822Sdim      inst.instruction |= inst.operands[1].reg;
10369218822Sdim      inst.instruction |= inst.operands[2].imm << 4;
10370218822Sdim    }
10371218822Sdim  else
10372218822Sdim    {
10373218822Sdim      constraint (inst.operands[2].present && inst.operands[2].imm != 0,
10374218822Sdim		  _("Thumb encoding does not support rotation"));
10375218822Sdim      constraint (1, BAD_HIREG);
10376218822Sdim    }
10377218822Sdim}
1037889857Sobrien
10379218822Sdimstatic void
10380218822Sdimdo_t_swi (void)
10381218822Sdim{
10382218822Sdim  inst.reloc.type = BFD_RELOC_ARM_SWI;
1038389857Sobrien}
1038489857Sobrien
1038589857Sobrienstatic void
10386218822Sdimdo_t_tb (void)
1038789857Sobrien{
10388218822Sdim  int half;
1038989857Sobrien
10390218822Sdim  half = (inst.instruction & 0x10) != 0;
10391218822Sdim  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
10392218822Sdim  constraint (inst.operands[0].immisreg,
10393218822Sdim	      _("instruction requires register index"));
10394218822Sdim  constraint (inst.operands[0].imm == 15,
10395218822Sdim	      _("PC is not a valid index register"));
10396218822Sdim  constraint (!half && inst.operands[0].shifted,
10397218822Sdim	      _("instruction does not allow shifted index"));
10398218822Sdim  inst.instruction |= (inst.operands[0].reg << 16) | inst.operands[0].imm;
1039989857Sobrien}
1040089857Sobrien
10401218822Sdimstatic void
10402218822Sdimdo_t_usat (void)
1040389857Sobrien{
10404218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10405218822Sdim  inst.instruction |= inst.operands[1].imm;
10406218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
1040789857Sobrien
10408218822Sdim  if (inst.operands[3].present)
1040989857Sobrien    {
10410218822Sdim      constraint (inst.reloc.exp.X_op != O_constant,
10411218822Sdim		  _("expression too complex"));
10412218822Sdim      if (inst.reloc.exp.X_add_number != 0)
10413218822Sdim	{
10414218822Sdim	  if (inst.operands[3].shift_kind == SHIFT_ASR)
10415218822Sdim	    inst.instruction |= 0x00200000;  /* sh bit */
1041689857Sobrien
10417218822Sdim	  inst.instruction |= (inst.reloc.exp.X_add_number & 0x1c) << 10;
10418218822Sdim	  inst.instruction |= (inst.reloc.exp.X_add_number & 0x03) << 6;
1041989857Sobrien	}
10420218822Sdim      inst.reloc.type = BFD_RELOC_UNUSED;
1042189857Sobrien    }
1042289857Sobrien}
1042389857Sobrien
10424218822Sdimstatic void
10425218822Sdimdo_t_usat16 (void)
1042689857Sobrien{
10427218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10428218822Sdim  inst.instruction |= inst.operands[1].imm;
10429218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
10430218822Sdim}
1043189857Sobrien
10432218822Sdim/* Neon instruction encoder helpers.  */
10433218822Sdim
10434218822Sdim/* Encodings for the different types for various Neon opcodes.  */
1043589857Sobrien
10436218822Sdim/* An "invalid" code for the following tables.  */
10437218822Sdim#define N_INV -1u
1043889857Sobrien
10439218822Sdimstruct neon_tab_entry
10440218822Sdim{
10441218822Sdim  unsigned integer;
10442218822Sdim  unsigned float_or_poly;
10443218822Sdim  unsigned scalar_or_imm;
10444218822Sdim};
10445218822Sdim
10446218822Sdim/* Map overloaded Neon opcodes to their respective encodings.  */
10447218822Sdim#define NEON_ENC_TAB					\
10448218822Sdim  X(vabd,	0x0000700, 0x1200d00, N_INV),		\
10449218822Sdim  X(vmax,	0x0000600, 0x0000f00, N_INV),		\
10450218822Sdim  X(vmin,	0x0000610, 0x0200f00, N_INV),		\
10451218822Sdim  X(vpadd,	0x0000b10, 0x1000d00, N_INV),		\
10452218822Sdim  X(vpmax,	0x0000a00, 0x1000f00, N_INV),		\
10453218822Sdim  X(vpmin,	0x0000a10, 0x1200f00, N_INV),		\
10454218822Sdim  X(vadd,	0x0000800, 0x0000d00, N_INV),		\
10455218822Sdim  X(vsub,	0x1000800, 0x0200d00, N_INV),		\
10456218822Sdim  X(vceq,	0x1000810, 0x0000e00, 0x1b10100),	\
10457218822Sdim  X(vcge,	0x0000310, 0x1000e00, 0x1b10080),	\
10458218822Sdim  X(vcgt,	0x0000300, 0x1200e00, 0x1b10000),	\
10459218822Sdim  /* Register variants of the following two instructions are encoded as
10460218822Sdim     vcge / vcgt with the operands reversed. */  	\
10461218822Sdim  X(vclt,	0x0000300, 0x1200e00, 0x1b10200),	\
10462218822Sdim  X(vcle,	0x0000310, 0x1000e00, 0x1b10180),	\
10463218822Sdim  X(vmla,	0x0000900, 0x0000d10, 0x0800040),	\
10464218822Sdim  X(vmls,	0x1000900, 0x0200d10, 0x0800440),	\
10465218822Sdim  X(vmul,	0x0000910, 0x1000d10, 0x0800840),	\
10466218822Sdim  X(vmull,	0x0800c00, 0x0800e00, 0x0800a40), /* polynomial not float.  */ \
10467218822Sdim  X(vmlal,	0x0800800, N_INV,     0x0800240),	\
10468218822Sdim  X(vmlsl,	0x0800a00, N_INV,     0x0800640),	\
10469218822Sdim  X(vqdmlal,	0x0800900, N_INV,     0x0800340),	\
10470218822Sdim  X(vqdmlsl,	0x0800b00, N_INV,     0x0800740),	\
10471218822Sdim  X(vqdmull,	0x0800d00, N_INV,     0x0800b40),	\
10472218822Sdim  X(vqdmulh,    0x0000b00, N_INV,     0x0800c40),	\
10473218822Sdim  X(vqrdmulh,   0x1000b00, N_INV,     0x0800d40),	\
10474218822Sdim  X(vshl,	0x0000400, N_INV,     0x0800510),	\
10475218822Sdim  X(vqshl,	0x0000410, N_INV,     0x0800710),	\
10476218822Sdim  X(vand,	0x0000110, N_INV,     0x0800030),	\
10477218822Sdim  X(vbic,	0x0100110, N_INV,     0x0800030),	\
10478218822Sdim  X(veor,	0x1000110, N_INV,     N_INV),		\
10479218822Sdim  X(vorn,	0x0300110, N_INV,     0x0800010),	\
10480218822Sdim  X(vorr,	0x0200110, N_INV,     0x0800010),	\
10481218822Sdim  X(vmvn,	0x1b00580, N_INV,     0x0800030),	\
10482218822Sdim  X(vshll,	0x1b20300, N_INV,     0x0800a10), /* max shift, immediate.  */ \
10483218822Sdim  X(vcvt,       0x1b30600, N_INV,     0x0800e10), /* integer, fixed-point.  */ \
10484218822Sdim  X(vdup,       0xe800b10, N_INV,     0x1b00c00), /* arm, scalar.  */ \
10485218822Sdim  X(vld1,       0x0200000, 0x0a00000, 0x0a00c00), /* interlv, lane, dup.  */ \
10486218822Sdim  X(vst1,	0x0000000, 0x0800000, N_INV),		\
10487218822Sdim  X(vld2,	0x0200100, 0x0a00100, 0x0a00d00),	\
10488218822Sdim  X(vst2,	0x0000100, 0x0800100, N_INV),		\
10489218822Sdim  X(vld3,	0x0200200, 0x0a00200, 0x0a00e00),	\
10490218822Sdim  X(vst3,	0x0000200, 0x0800200, N_INV),		\
10491218822Sdim  X(vld4,	0x0200300, 0x0a00300, 0x0a00f00),	\
10492218822Sdim  X(vst4,	0x0000300, 0x0800300, N_INV),		\
10493218822Sdim  X(vmovn,	0x1b20200, N_INV,     N_INV),		\
10494218822Sdim  X(vtrn,	0x1b20080, N_INV,     N_INV),		\
10495218822Sdim  X(vqmovn,	0x1b20200, N_INV,     N_INV),		\
10496218822Sdim  X(vqmovun,	0x1b20240, N_INV,     N_INV),		\
10497218822Sdim  X(vnmul,      0xe200a40, 0xe200b40, N_INV),		\
10498218822Sdim  X(vnmla,      0xe000a40, 0xe000b40, N_INV),		\
10499218822Sdim  X(vnmls,      0xe100a40, 0xe100b40, N_INV),		\
10500218822Sdim  X(vcmp,	0xeb40a40, 0xeb40b40, N_INV),		\
10501218822Sdim  X(vcmpz,	0xeb50a40, 0xeb50b40, N_INV),		\
10502218822Sdim  X(vcmpe,	0xeb40ac0, 0xeb40bc0, N_INV),		\
10503218822Sdim  X(vcmpez,     0xeb50ac0, 0xeb50bc0, N_INV)
1050489857Sobrien
10505218822Sdimenum neon_opc
10506218822Sdim{
10507218822Sdim#define X(OPC,I,F,S) N_MNEM_##OPC
10508218822SdimNEON_ENC_TAB
10509218822Sdim#undef X
10510218822Sdim};
1051189857Sobrien
10512218822Sdimstatic const struct neon_tab_entry neon_enc_tab[] =
1051389857Sobrien{
10514218822Sdim#define X(OPC,I,F,S) { (I), (F), (S) }
10515218822SdimNEON_ENC_TAB
10516218822Sdim#undef X
10517218822Sdim};
1051889857Sobrien
10519218822Sdim#define NEON_ENC_INTEGER(X) (neon_enc_tab[(X) & 0x0fffffff].integer)
10520218822Sdim#define NEON_ENC_ARMREG(X)  (neon_enc_tab[(X) & 0x0fffffff].integer)
10521218822Sdim#define NEON_ENC_POLY(X)    (neon_enc_tab[(X) & 0x0fffffff].float_or_poly)
10522218822Sdim#define NEON_ENC_FLOAT(X)   (neon_enc_tab[(X) & 0x0fffffff].float_or_poly)
10523218822Sdim#define NEON_ENC_SCALAR(X)  (neon_enc_tab[(X) & 0x0fffffff].scalar_or_imm)
10524218822Sdim#define NEON_ENC_IMMED(X)   (neon_enc_tab[(X) & 0x0fffffff].scalar_or_imm)
10525218822Sdim#define NEON_ENC_INTERLV(X) (neon_enc_tab[(X) & 0x0fffffff].integer)
10526218822Sdim#define NEON_ENC_LANE(X)    (neon_enc_tab[(X) & 0x0fffffff].float_or_poly)
10527218822Sdim#define NEON_ENC_DUP(X)     (neon_enc_tab[(X) & 0x0fffffff].scalar_or_imm)
10528218822Sdim#define NEON_ENC_SINGLE(X) \
10529218822Sdim  ((neon_enc_tab[(X) & 0x0fffffff].integer) | ((X) & 0xf0000000))
10530218822Sdim#define NEON_ENC_DOUBLE(X) \
10531218822Sdim  ((neon_enc_tab[(X) & 0x0fffffff].float_or_poly) | ((X) & 0xf0000000))
1053289857Sobrien
10533218822Sdim/* Define shapes for instruction operands. The following mnemonic characters
10534218822Sdim   are used in this table:
1053589857Sobrien
10536218822Sdim     F - VFP S<n> register
10537218822Sdim     D - Neon D<n> register
10538218822Sdim     Q - Neon Q<n> register
10539218822Sdim     I - Immediate
10540218822Sdim     S - Scalar
10541218822Sdim     R - ARM register
10542218822Sdim     L - D<n> register list
10543218822Sdim
10544218822Sdim   This table is used to generate various data:
10545218822Sdim     - enumerations of the form NS_DDR to be used as arguments to
10546218822Sdim       neon_select_shape.
10547218822Sdim     - a table classifying shapes into single, double, quad, mixed.
10548218822Sdim     - a table used to drive neon_select_shape.
10549218822Sdim*/
1055089857Sobrien
10551218822Sdim#define NEON_SHAPE_DEF			\
10552218822Sdim  X(3, (D, D, D), DOUBLE),		\
10553218822Sdim  X(3, (Q, Q, Q), QUAD),		\
10554218822Sdim  X(3, (D, D, I), DOUBLE),		\
10555218822Sdim  X(3, (Q, Q, I), QUAD),		\
10556218822Sdim  X(3, (D, D, S), DOUBLE),		\
10557218822Sdim  X(3, (Q, Q, S), QUAD),		\
10558218822Sdim  X(2, (D, D), DOUBLE),			\
10559218822Sdim  X(2, (Q, Q), QUAD),			\
10560218822Sdim  X(2, (D, S), DOUBLE),			\
10561218822Sdim  X(2, (Q, S), QUAD),			\
10562218822Sdim  X(2, (D, R), DOUBLE),			\
10563218822Sdim  X(2, (Q, R), QUAD),			\
10564218822Sdim  X(2, (D, I), DOUBLE),			\
10565218822Sdim  X(2, (Q, I), QUAD),			\
10566218822Sdim  X(3, (D, L, D), DOUBLE),		\
10567218822Sdim  X(2, (D, Q), MIXED),			\
10568218822Sdim  X(2, (Q, D), MIXED),			\
10569218822Sdim  X(3, (D, Q, I), MIXED),		\
10570218822Sdim  X(3, (Q, D, I), MIXED),		\
10571218822Sdim  X(3, (Q, D, D), MIXED),		\
10572218822Sdim  X(3, (D, Q, Q), MIXED),		\
10573218822Sdim  X(3, (Q, Q, D), MIXED),		\
10574218822Sdim  X(3, (Q, D, S), MIXED),		\
10575218822Sdim  X(3, (D, Q, S), MIXED),		\
10576218822Sdim  X(4, (D, D, D, I), DOUBLE),		\
10577218822Sdim  X(4, (Q, Q, Q, I), QUAD),		\
10578218822Sdim  X(2, (F, F), SINGLE),			\
10579218822Sdim  X(3, (F, F, F), SINGLE),		\
10580218822Sdim  X(2, (F, I), SINGLE),			\
10581218822Sdim  X(2, (F, D), MIXED),			\
10582218822Sdim  X(2, (D, F), MIXED),			\
10583218822Sdim  X(3, (F, F, I), MIXED),		\
10584218822Sdim  X(4, (R, R, F, F), SINGLE),		\
10585218822Sdim  X(4, (F, F, R, R), SINGLE),		\
10586218822Sdim  X(3, (D, R, R), DOUBLE),		\
10587218822Sdim  X(3, (R, R, D), DOUBLE),		\
10588218822Sdim  X(2, (S, R), SINGLE),			\
10589218822Sdim  X(2, (R, S), SINGLE),			\
10590218822Sdim  X(2, (F, R), SINGLE),			\
10591218822Sdim  X(2, (R, F), SINGLE)
10592218822Sdim
10593218822Sdim#define S2(A,B)		NS_##A##B
10594218822Sdim#define S3(A,B,C)	NS_##A##B##C
10595218822Sdim#define S4(A,B,C,D)	NS_##A##B##C##D
10596218822Sdim
10597218822Sdim#define X(N, L, C) S##N L
10598218822Sdim
10599218822Sdimenum neon_shape
1060089857Sobrien{
10601218822Sdim  NEON_SHAPE_DEF,
10602218822Sdim  NS_NULL
10603218822Sdim};
1060489857Sobrien
10605218822Sdim#undef X
10606218822Sdim#undef S2
10607218822Sdim#undef S3
10608218822Sdim#undef S4
1060989857Sobrien
10610218822Sdimenum neon_shape_class
10611218822Sdim{
10612218822Sdim  SC_SINGLE,
10613218822Sdim  SC_DOUBLE,
10614218822Sdim  SC_QUAD,
10615218822Sdim  SC_MIXED
10616218822Sdim};
1061789857Sobrien
10618218822Sdim#define X(N, L, C) SC_##C
1061989857Sobrien
10620218822Sdimstatic enum neon_shape_class neon_shape_class[] =
1062189857Sobrien{
10622218822Sdim  NEON_SHAPE_DEF
10623218822Sdim};
1062489857Sobrien
10625218822Sdim#undef X
1062689857Sobrien
10627218822Sdimenum neon_shape_el
10628218822Sdim{
10629218822Sdim  SE_F,
10630218822Sdim  SE_D,
10631218822Sdim  SE_Q,
10632218822Sdim  SE_I,
10633218822Sdim  SE_S,
10634218822Sdim  SE_R,
10635218822Sdim  SE_L
10636218822Sdim};
1063789857Sobrien
10638218822Sdim/* Register widths of above.  */
10639218822Sdimstatic unsigned neon_shape_el_size[] =
10640218822Sdim{
10641218822Sdim  32,
10642218822Sdim  64,
10643218822Sdim  128,
10644218822Sdim  0,
10645218822Sdim  32,
10646218822Sdim  32,
10647218822Sdim  0
10648218822Sdim};
1064989857Sobrien
10650218822Sdimstruct neon_shape_info
1065189857Sobrien{
10652218822Sdim  unsigned els;
10653218822Sdim  enum neon_shape_el el[NEON_MAX_TYPE_ELS];
10654218822Sdim};
1065589857Sobrien
10656218822Sdim#define S2(A,B)		{ SE_##A, SE_##B }
10657218822Sdim#define S3(A,B,C)	{ SE_##A, SE_##B, SE_##C }
10658218822Sdim#define S4(A,B,C,D)	{ SE_##A, SE_##B, SE_##C, SE_##D }
1065989857Sobrien
10660218822Sdim#define X(N, L, C) { N, S##N L }
1066189857Sobrien
10662218822Sdimstatic struct neon_shape_info neon_shape_tab[] =
1066389857Sobrien{
10664218822Sdim  NEON_SHAPE_DEF
10665218822Sdim};
1066689857Sobrien
10667218822Sdim#undef X
10668218822Sdim#undef S2
10669218822Sdim#undef S3
10670218822Sdim#undef S4
1067189857Sobrien
10672218822Sdim/* Bit masks used in type checking given instructions.
10673218822Sdim  'N_EQK' means the type must be the same as (or based on in some way) the key
10674218822Sdim   type, which itself is marked with the 'N_KEY' bit. If the 'N_EQK' bit is
10675218822Sdim   set, various other bits can be set as well in order to modify the meaning of
10676218822Sdim   the type constraint.  */
1067789857Sobrien
10678218822Sdimenum neon_type_mask
10679218822Sdim{
10680218822Sdim  N_S8   = 0x000001,
10681218822Sdim  N_S16  = 0x000002,
10682218822Sdim  N_S32  = 0x000004,
10683218822Sdim  N_S64  = 0x000008,
10684218822Sdim  N_U8   = 0x000010,
10685218822Sdim  N_U16  = 0x000020,
10686218822Sdim  N_U32  = 0x000040,
10687218822Sdim  N_U64  = 0x000080,
10688218822Sdim  N_I8   = 0x000100,
10689218822Sdim  N_I16  = 0x000200,
10690218822Sdim  N_I32  = 0x000400,
10691218822Sdim  N_I64  = 0x000800,
10692218822Sdim  N_8    = 0x001000,
10693218822Sdim  N_16   = 0x002000,
10694218822Sdim  N_32   = 0x004000,
10695218822Sdim  N_64   = 0x008000,
10696218822Sdim  N_P8   = 0x010000,
10697218822Sdim  N_P16  = 0x020000,
10698218822Sdim  N_F32  = 0x040000,
10699218822Sdim  N_F64  = 0x080000,
10700218822Sdim  N_KEY  = 0x100000, /* key element (main type specifier).  */
10701218822Sdim  N_EQK  = 0x200000, /* given operand has the same type & size as the key.  */
10702218822Sdim  N_VFP  = 0x400000, /* VFP mode: operand size must match register width.  */
10703218822Sdim  N_DBL  = 0x000001, /* if N_EQK, this operand is twice the size.  */
10704218822Sdim  N_HLF  = 0x000002, /* if N_EQK, this operand is half the size.  */
10705218822Sdim  N_SGN  = 0x000004, /* if N_EQK, this operand is forced to be signed.  */
10706218822Sdim  N_UNS  = 0x000008, /* if N_EQK, this operand is forced to be unsigned.  */
10707218822Sdim  N_INT  = 0x000010, /* if N_EQK, this operand is forced to be integer.  */
10708218822Sdim  N_FLT  = 0x000020, /* if N_EQK, this operand is forced to be float.  */
10709218822Sdim  N_SIZ  = 0x000040, /* if N_EQK, this operand is forced to be size-only.  */
10710218822Sdim  N_UTYP = 0,
10711218822Sdim  N_MAX_NONSPECIAL = N_F64
10712218822Sdim};
1071389857Sobrien
10714218822Sdim#define N_ALLMODS  (N_DBL | N_HLF | N_SGN | N_UNS | N_INT | N_FLT | N_SIZ)
1071589857Sobrien
10716218822Sdim#define N_SU_ALL   (N_S8 | N_S16 | N_S32 | N_S64 | N_U8 | N_U16 | N_U32 | N_U64)
10717218822Sdim#define N_SU_32    (N_S8 | N_S16 | N_S32 | N_U8 | N_U16 | N_U32)
10718218822Sdim#define N_SU_16_64 (N_S16 | N_S32 | N_S64 | N_U16 | N_U32 | N_U64)
10719218822Sdim#define N_SUF_32   (N_SU_32 | N_F32)
10720218822Sdim#define N_I_ALL    (N_I8 | N_I16 | N_I32 | N_I64)
10721218822Sdim#define N_IF_32    (N_I8 | N_I16 | N_I32 | N_F32)
1072289857Sobrien
10723218822Sdim/* Pass this as the first type argument to neon_check_type to ignore types
10724218822Sdim   altogether.  */
10725218822Sdim#define N_IGNORE_TYPE (N_KEY | N_EQK)
1072689857Sobrien
10727218822Sdim/* Select a "shape" for the current instruction (describing register types or
10728218822Sdim   sizes) from a list of alternatives. Return NS_NULL if the current instruction
10729218822Sdim   doesn't fit. For non-polymorphic shapes, checking is usually done as a
10730218822Sdim   function of operand parsing, so this function doesn't need to be called.
10731218822Sdim   Shapes should be listed in order of decreasing length.  */
1073289857Sobrien
10733218822Sdimstatic enum neon_shape
10734218822Sdimneon_select_shape (enum neon_shape shape, ...)
10735218822Sdim{
10736218822Sdim  va_list ap;
10737218822Sdim  enum neon_shape first_shape = shape;
1073889857Sobrien
10739218822Sdim  /* Fix missing optional operands. FIXME: we don't know at this point how
10740218822Sdim     many arguments we should have, so this makes the assumption that we have
10741218822Sdim     > 1. This is true of all current Neon opcodes, I think, but may not be
10742218822Sdim     true in the future.  */
10743218822Sdim  if (!inst.operands[1].present)
10744218822Sdim    inst.operands[1] = inst.operands[0];
1074589857Sobrien
10746218822Sdim  va_start (ap, shape);
10747218822Sdim
10748218822Sdim  for (; shape != NS_NULL; shape = va_arg (ap, int))
10749218822Sdim    {
10750218822Sdim      unsigned j;
10751218822Sdim      int matches = 1;
1075289857Sobrien
10753218822Sdim      for (j = 0; j < neon_shape_tab[shape].els; j++)
10754218822Sdim        {
10755218822Sdim          if (!inst.operands[j].present)
10756218822Sdim            {
10757218822Sdim              matches = 0;
10758218822Sdim              break;
10759218822Sdim            }
1076089857Sobrien
10761218822Sdim          switch (neon_shape_tab[shape].el[j])
10762218822Sdim            {
10763218822Sdim            case SE_F:
10764218822Sdim              if (!(inst.operands[j].isreg
10765218822Sdim                    && inst.operands[j].isvec
10766218822Sdim                    && inst.operands[j].issingle
10767218822Sdim                    && !inst.operands[j].isquad))
10768218822Sdim                matches = 0;
10769218822Sdim              break;
1077089857Sobrien
10771218822Sdim            case SE_D:
10772218822Sdim              if (!(inst.operands[j].isreg
10773218822Sdim                    && inst.operands[j].isvec
10774218822Sdim                    && !inst.operands[j].isquad
10775218822Sdim                    && !inst.operands[j].issingle))
10776218822Sdim                matches = 0;
10777218822Sdim              break;
1077889857Sobrien
10779218822Sdim            case SE_R:
10780218822Sdim              if (!(inst.operands[j].isreg
10781218822Sdim                    && !inst.operands[j].isvec))
10782218822Sdim                matches = 0;
10783218822Sdim              break;
1078489857Sobrien
10785218822Sdim            case SE_Q:
10786218822Sdim              if (!(inst.operands[j].isreg
10787218822Sdim                    && inst.operands[j].isvec
10788218822Sdim                    && inst.operands[j].isquad
10789218822Sdim                    && !inst.operands[j].issingle))
10790218822Sdim                matches = 0;
10791218822Sdim              break;
1079289857Sobrien
10793218822Sdim            case SE_I:
10794218822Sdim              if (!(!inst.operands[j].isreg
10795218822Sdim                    && !inst.operands[j].isscalar))
10796218822Sdim                matches = 0;
10797218822Sdim              break;
1079889857Sobrien
10799218822Sdim            case SE_S:
10800218822Sdim              if (!(!inst.operands[j].isreg
10801218822Sdim                    && inst.operands[j].isscalar))
10802218822Sdim                matches = 0;
10803218822Sdim              break;
10804218822Sdim
10805218822Sdim            case SE_L:
10806218822Sdim              break;
10807218822Sdim            }
10808218822Sdim        }
10809218822Sdim      if (matches)
10810218822Sdim        break;
1081189857Sobrien    }
10812218822Sdim
10813218822Sdim  va_end (ap);
1081489857Sobrien
10815218822Sdim  if (shape == NS_NULL && first_shape != NS_NULL)
10816218822Sdim    first_error (_("invalid instruction shape"));
1081789857Sobrien
10818218822Sdim  return shape;
10819218822Sdim}
1082089857Sobrien
10821218822Sdim/* True if SHAPE is predominantly a quadword operation (most of the time, this
10822218822Sdim   means the Q bit should be set).  */
1082389857Sobrien
10824218822Sdimstatic int
10825218822Sdimneon_quad (enum neon_shape shape)
10826218822Sdim{
10827218822Sdim  return neon_shape_class[shape] == SC_QUAD;
10828218822Sdim}
10829218822Sdim
10830218822Sdimstatic void
10831218822Sdimneon_modify_type_size (unsigned typebits, enum neon_el_type *g_type,
10832218822Sdim                       unsigned *g_size)
10833218822Sdim{
10834218822Sdim  /* Allow modification to be made to types which are constrained to be
10835218822Sdim     based on the key element, based on bits set alongside N_EQK.  */
10836218822Sdim  if ((typebits & N_EQK) != 0)
1083789857Sobrien    {
10838218822Sdim      if ((typebits & N_HLF) != 0)
10839218822Sdim	*g_size /= 2;
10840218822Sdim      else if ((typebits & N_DBL) != 0)
10841218822Sdim	*g_size *= 2;
10842218822Sdim      if ((typebits & N_SGN) != 0)
10843218822Sdim	*g_type = NT_signed;
10844218822Sdim      else if ((typebits & N_UNS) != 0)
10845218822Sdim        *g_type = NT_unsigned;
10846218822Sdim      else if ((typebits & N_INT) != 0)
10847218822Sdim        *g_type = NT_integer;
10848218822Sdim      else if ((typebits & N_FLT) != 0)
10849218822Sdim        *g_type = NT_float;
10850218822Sdim      else if ((typebits & N_SIZ) != 0)
10851218822Sdim        *g_type = NT_untyped;
1085289857Sobrien    }
10853218822Sdim}
10854218822Sdim
10855218822Sdim/* Return operand OPNO promoted by bits set in THISARG. KEY should be the "key"
10856218822Sdim   operand type, i.e. the single type specified in a Neon instruction when it
10857218822Sdim   is the only one given.  */
1085889857Sobrien
10859218822Sdimstatic struct neon_type_el
10860218822Sdimneon_type_promote (struct neon_type_el *key, unsigned thisarg)
10861218822Sdim{
10862218822Sdim  struct neon_type_el dest = *key;
10863218822Sdim
10864218822Sdim  assert ((thisarg & N_EQK) != 0);
10865218822Sdim
10866218822Sdim  neon_modify_type_size (thisarg, &dest.type, &dest.size);
10867218822Sdim
10868218822Sdim  return dest;
1086989857Sobrien}
1087089857Sobrien
10871218822Sdim/* Convert Neon type and size into compact bitmask representation.  */
10872218822Sdim
10873218822Sdimstatic enum neon_type_mask
10874218822Sdimtype_chk_of_el_type (enum neon_el_type type, unsigned size)
1087589857Sobrien{
10876218822Sdim  switch (type)
10877218822Sdim    {
10878218822Sdim    case NT_untyped:
10879218822Sdim      switch (size)
10880218822Sdim        {
10881218822Sdim        case 8:  return N_8;
10882218822Sdim        case 16: return N_16;
10883218822Sdim        case 32: return N_32;
10884218822Sdim        case 64: return N_64;
10885218822Sdim        default: ;
10886218822Sdim        }
10887218822Sdim      break;
1088889857Sobrien
10889218822Sdim    case NT_integer:
10890218822Sdim      switch (size)
10891218822Sdim        {
10892218822Sdim        case 8:  return N_I8;
10893218822Sdim        case 16: return N_I16;
10894218822Sdim        case 32: return N_I32;
10895218822Sdim        case 64: return N_I64;
10896218822Sdim        default: ;
10897218822Sdim        }
10898218822Sdim      break;
1089989857Sobrien
10900218822Sdim    case NT_float:
10901218822Sdim      switch (size)
10902218822Sdim        {
10903218822Sdim        case 32: return N_F32;
10904218822Sdim        case 64: return N_F64;
10905218822Sdim        default: ;
10906218822Sdim        }
10907218822Sdim      break;
1090889857Sobrien
10909218822Sdim    case NT_poly:
10910218822Sdim      switch (size)
10911218822Sdim        {
10912218822Sdim        case 8:  return N_P8;
10913218822Sdim        case 16: return N_P16;
10914218822Sdim        default: ;
10915218822Sdim        }
10916218822Sdim      break;
1091789857Sobrien
10918218822Sdim    case NT_signed:
10919218822Sdim      switch (size)
10920218822Sdim        {
10921218822Sdim        case 8:  return N_S8;
10922218822Sdim        case 16: return N_S16;
10923218822Sdim        case 32: return N_S32;
10924218822Sdim        case 64: return N_S64;
10925218822Sdim        default: ;
10926218822Sdim        }
10927218822Sdim      break;
1092889857Sobrien
10929218822Sdim    case NT_unsigned:
10930218822Sdim      switch (size)
10931218822Sdim        {
10932218822Sdim        case 8:  return N_U8;
10933218822Sdim        case 16: return N_U16;
10934218822Sdim        case 32: return N_U32;
10935218822Sdim        case 64: return N_U64;
10936218822Sdim        default: ;
10937218822Sdim        }
10938218822Sdim      break;
1093989857Sobrien
10940218822Sdim    default: ;
10941218822Sdim    }
10942218822Sdim
10943218822Sdim  return N_UTYP;
10944218822Sdim}
1094589857Sobrien
10946218822Sdim/* Convert compact Neon bitmask type representation to a type and size. Only
10947218822Sdim   handles the case where a single bit is set in the mask.  */
1094889857Sobrien
10949218822Sdimstatic int
10950218822Sdimel_type_of_type_chk (enum neon_el_type *type, unsigned *size,
10951218822Sdim                     enum neon_type_mask mask)
10952218822Sdim{
10953218822Sdim  if ((mask & N_EQK) != 0)
10954218822Sdim    return FAIL;
1095589857Sobrien
10956218822Sdim  if ((mask & (N_S8 | N_U8 | N_I8 | N_8 | N_P8)) != 0)
10957218822Sdim    *size = 8;
10958218822Sdim  else if ((mask & (N_S16 | N_U16 | N_I16 | N_16 | N_P16)) != 0)
10959218822Sdim    *size = 16;
10960218822Sdim  else if ((mask & (N_S32 | N_U32 | N_I32 | N_32 | N_F32)) != 0)
10961218822Sdim    *size = 32;
10962218822Sdim  else if ((mask & (N_S64 | N_U64 | N_I64 | N_64 | N_F64)) != 0)
10963218822Sdim    *size = 64;
10964218822Sdim  else
10965218822Sdim    return FAIL;
1096689857Sobrien
10967218822Sdim  if ((mask & (N_S8 | N_S16 | N_S32 | N_S64)) != 0)
10968218822Sdim    *type = NT_signed;
10969218822Sdim  else if ((mask & (N_U8 | N_U16 | N_U32 | N_U64)) != 0)
10970218822Sdim    *type = NT_unsigned;
10971218822Sdim  else if ((mask & (N_I8 | N_I16 | N_I32 | N_I64)) != 0)
10972218822Sdim    *type = NT_integer;
10973218822Sdim  else if ((mask & (N_8 | N_16 | N_32 | N_64)) != 0)
10974218822Sdim    *type = NT_untyped;
10975218822Sdim  else if ((mask & (N_P8 | N_P16)) != 0)
10976218822Sdim    *type = NT_poly;
10977218822Sdim  else if ((mask & (N_F32 | N_F64)) != 0)
10978218822Sdim    *type = NT_float;
10979218822Sdim  else
10980218822Sdim    return FAIL;
10981218822Sdim
10982218822Sdim  return SUCCESS;
10983218822Sdim}
1098489857Sobrien
10985218822Sdim/* Modify a bitmask of allowed types. This is only needed for type
10986218822Sdim   relaxation.  */
1098789857Sobrien
10988218822Sdimstatic unsigned
10989218822Sdimmodify_types_allowed (unsigned allowed, unsigned mods)
10990218822Sdim{
10991218822Sdim  unsigned size;
10992218822Sdim  enum neon_el_type type;
10993218822Sdim  unsigned destmask;
10994218822Sdim  int i;
10995218822Sdim
10996218822Sdim  destmask = 0;
10997218822Sdim
10998218822Sdim  for (i = 1; i <= N_MAX_NONSPECIAL; i <<= 1)
10999218822Sdim    {
11000218822Sdim      if (el_type_of_type_chk (&type, &size, allowed & i) == SUCCESS)
11001218822Sdim        {
11002218822Sdim          neon_modify_type_size (mods, &type, &size);
11003218822Sdim          destmask |= type_chk_of_el_type (type, size);
11004218822Sdim        }
11005218822Sdim    }
11006218822Sdim
11007218822Sdim  return destmask;
11008218822Sdim}
1100989857Sobrien
11010218822Sdim/* Check type and return type classification.
11011218822Sdim   The manual states (paraphrase): If one datatype is given, it indicates the
11012218822Sdim   type given in:
11013218822Sdim    - the second operand, if there is one
11014218822Sdim    - the operand, if there is no second operand
11015218822Sdim    - the result, if there are no operands.
11016218822Sdim   This isn't quite good enough though, so we use a concept of a "key" datatype
11017218822Sdim   which is set on a per-instruction basis, which is the one which matters when
11018218822Sdim   only one data type is written.
11019218822Sdim   Note: this function has side-effects (e.g. filling in missing operands). All
11020218822Sdim   Neon instructions should call it before performing bit encoding.  */
1102189857Sobrien
11022218822Sdimstatic struct neon_type_el
11023218822Sdimneon_check_type (unsigned els, enum neon_shape ns, ...)
11024218822Sdim{
11025218822Sdim  va_list ap;
11026218822Sdim  unsigned i, pass, key_el = 0;
11027218822Sdim  unsigned types[NEON_MAX_TYPE_ELS];
11028218822Sdim  enum neon_el_type k_type = NT_invtype;
11029218822Sdim  unsigned k_size = -1u;
11030218822Sdim  struct neon_type_el badtype = {NT_invtype, -1};
11031218822Sdim  unsigned key_allowed = 0;
1103289857Sobrien
11033218822Sdim  /* Optional registers in Neon instructions are always (not) in operand 1.
11034218822Sdim     Fill in the missing operand here, if it was omitted.  */
11035218822Sdim  if (els > 1 && !inst.operands[1].present)
11036218822Sdim    inst.operands[1] = inst.operands[0];
1103789857Sobrien
11038218822Sdim  /* Suck up all the varargs.  */
11039218822Sdim  va_start (ap, ns);
11040218822Sdim  for (i = 0; i < els; i++)
11041218822Sdim    {
11042218822Sdim      unsigned thisarg = va_arg (ap, unsigned);
11043218822Sdim      if (thisarg == N_IGNORE_TYPE)
11044218822Sdim        {
11045218822Sdim          va_end (ap);
11046218822Sdim          return badtype;
11047218822Sdim        }
11048218822Sdim      types[i] = thisarg;
11049218822Sdim      if ((thisarg & N_KEY) != 0)
11050218822Sdim        key_el = i;
1105189857Sobrien    }
11052218822Sdim  va_end (ap);
1105389857Sobrien
11054218822Sdim  if (inst.vectype.elems > 0)
11055218822Sdim    for (i = 0; i < els; i++)
11056218822Sdim      if (inst.operands[i].vectype.type != NT_invtype)
11057218822Sdim        {
11058218822Sdim          first_error (_("types specified in both the mnemonic and operands"));
11059218822Sdim          return badtype;
11060218822Sdim        }
11061218822Sdim
11062218822Sdim  /* Duplicate inst.vectype elements here as necessary.
11063218822Sdim     FIXME: No idea if this is exactly the same as the ARM assembler,
11064218822Sdim     particularly when an insn takes one register and one non-register
11065218822Sdim     operand. */
11066218822Sdim  if (inst.vectype.elems == 1 && els > 1)
1106789857Sobrien    {
11068218822Sdim      unsigned j;
11069218822Sdim      inst.vectype.elems = els;
11070218822Sdim      inst.vectype.el[key_el] = inst.vectype.el[0];
11071218822Sdim      for (j = 0; j < els; j++)
11072218822Sdim        if (j != key_el)
11073218822Sdim          inst.vectype.el[j] = neon_type_promote (&inst.vectype.el[key_el],
11074218822Sdim                                                  types[j]);
1107589857Sobrien    }
11076218822Sdim  else if (inst.vectype.elems == 0 && els > 0)
11077218822Sdim    {
11078218822Sdim      unsigned j;
11079218822Sdim      /* No types were given after the mnemonic, so look for types specified
11080218822Sdim         after each operand. We allow some flexibility here; as long as the
11081218822Sdim         "key" operand has a type, we can infer the others.  */
11082218822Sdim      for (j = 0; j < els; j++)
11083218822Sdim        if (inst.operands[j].vectype.type != NT_invtype)
11084218822Sdim          inst.vectype.el[j] = inst.operands[j].vectype;
1108589857Sobrien
11086218822Sdim      if (inst.operands[key_el].vectype.type != NT_invtype)
11087218822Sdim        {
11088218822Sdim          for (j = 0; j < els; j++)
11089218822Sdim            if (inst.operands[j].vectype.type == NT_invtype)
11090218822Sdim              inst.vectype.el[j] = neon_type_promote (&inst.vectype.el[key_el],
11091218822Sdim                                                      types[j]);
11092218822Sdim        }
11093218822Sdim      else
11094218822Sdim        {
11095218822Sdim          first_error (_("operand types can't be inferred"));
11096218822Sdim          return badtype;
11097218822Sdim        }
11098218822Sdim    }
11099218822Sdim  else if (inst.vectype.elems != els)
11100218822Sdim    {
11101218822Sdim      first_error (_("type specifier has the wrong number of parts"));
11102218822Sdim      return badtype;
11103218822Sdim    }
1110489857Sobrien
11105218822Sdim  for (pass = 0; pass < 2; pass++)
11106218822Sdim    {
11107218822Sdim      for (i = 0; i < els; i++)
11108218822Sdim        {
11109218822Sdim          unsigned thisarg = types[i];
11110218822Sdim          unsigned types_allowed = ((thisarg & N_EQK) != 0 && pass != 0)
11111218822Sdim            ? modify_types_allowed (key_allowed, thisarg) : thisarg;
11112218822Sdim          enum neon_el_type g_type = inst.vectype.el[i].type;
11113218822Sdim          unsigned g_size = inst.vectype.el[i].size;
1111489857Sobrien
11115218822Sdim          /* Decay more-specific signed & unsigned types to sign-insensitive
11116218822Sdim	     integer types if sign-specific variants are unavailable.  */
11117218822Sdim          if ((g_type == NT_signed || g_type == NT_unsigned)
11118218822Sdim	      && (types_allowed & N_SU_ALL) == 0)
11119218822Sdim	    g_type = NT_integer;
1112089857Sobrien
11121218822Sdim          /* If only untyped args are allowed, decay any more specific types to
11122218822Sdim	     them. Some instructions only care about signs for some element
11123218822Sdim	     sizes, so handle that properly.  */
11124218822Sdim          if ((g_size == 8 && (types_allowed & N_8) != 0)
11125218822Sdim	      || (g_size == 16 && (types_allowed & N_16) != 0)
11126218822Sdim	      || (g_size == 32 && (types_allowed & N_32) != 0)
11127218822Sdim	      || (g_size == 64 && (types_allowed & N_64) != 0))
11128218822Sdim	    g_type = NT_untyped;
11129218822Sdim
11130218822Sdim          if (pass == 0)
11131218822Sdim            {
11132218822Sdim              if ((thisarg & N_KEY) != 0)
11133218822Sdim                {
11134218822Sdim                  k_type = g_type;
11135218822Sdim                  k_size = g_size;
11136218822Sdim                  key_allowed = thisarg & ~N_KEY;
11137218822Sdim                }
11138218822Sdim            }
11139218822Sdim          else
11140218822Sdim            {
11141218822Sdim              if ((thisarg & N_VFP) != 0)
11142218822Sdim                {
11143218822Sdim                  enum neon_shape_el regshape = neon_shape_tab[ns].el[i];
11144218822Sdim                  unsigned regwidth = neon_shape_el_size[regshape], match;
11145218822Sdim
11146218822Sdim                  /* In VFP mode, operands must match register widths. If we
11147218822Sdim                     have a key operand, use its width, else use the width of
11148218822Sdim                     the current operand.  */
11149218822Sdim                  if (k_size != -1u)
11150218822Sdim                    match = k_size;
11151218822Sdim                  else
11152218822Sdim                    match = g_size;
11153218822Sdim
11154218822Sdim                  if (regwidth != match)
11155218822Sdim                    {
11156218822Sdim                      first_error (_("operand size must match register width"));
11157218822Sdim                      return badtype;
11158218822Sdim                    }
11159218822Sdim                }
11160218822Sdim
11161218822Sdim              if ((thisarg & N_EQK) == 0)
11162218822Sdim                {
11163218822Sdim                  unsigned given_type = type_chk_of_el_type (g_type, g_size);
11164218822Sdim
11165218822Sdim                  if ((given_type & types_allowed) == 0)
11166218822Sdim                    {
11167218822Sdim	              first_error (_("bad type in Neon instruction"));
11168218822Sdim	              return badtype;
11169218822Sdim                    }
11170218822Sdim                }
11171218822Sdim              else
11172218822Sdim                {
11173218822Sdim                  enum neon_el_type mod_k_type = k_type;
11174218822Sdim                  unsigned mod_k_size = k_size;
11175218822Sdim                  neon_modify_type_size (thisarg, &mod_k_type, &mod_k_size);
11176218822Sdim                  if (g_type != mod_k_type || g_size != mod_k_size)
11177218822Sdim                    {
11178218822Sdim                      first_error (_("inconsistent types in Neon instruction"));
11179218822Sdim                      return badtype;
11180218822Sdim                    }
11181218822Sdim                }
11182218822Sdim            }
11183218822Sdim        }
1118489857Sobrien    }
1118589857Sobrien
11186218822Sdim  return inst.vectype.el[key_el];
1118789857Sobrien}
1118889857Sobrien
11189218822Sdim/* Neon-style VFP instruction forwarding.  */
11190218822Sdim
11191218822Sdim/* Thumb VFP instructions have 0xE in the condition field.  */
11192218822Sdim
1119389857Sobrienstatic void
11194218822Sdimdo_vfp_cond_or_thumb (void)
1119589857Sobrien{
11196218822Sdim  if (thumb_mode)
11197218822Sdim    inst.instruction |= 0xe0000000;
11198218822Sdim  else
11199218822Sdim    inst.instruction |= inst.cond << 28;
11200218822Sdim}
1120189857Sobrien
11202218822Sdim/* Look up and encode a simple mnemonic, for use as a helper function for the
11203218822Sdim   Neon-style VFP syntax.  This avoids duplication of bits of the insns table,
11204218822Sdim   etc.  It is assumed that operand parsing has already been done, and that the
11205218822Sdim   operands are in the form expected by the given opcode (this isn't necessarily
11206218822Sdim   the same as the form in which they were parsed, hence some massaging must
11207218822Sdim   take place before this function is called).
11208218822Sdim   Checks current arch version against that in the looked-up opcode.  */
1120989857Sobrien
11210218822Sdimstatic void
11211218822Sdimdo_vfp_nsyn_opcode (const char *opname)
11212218822Sdim{
11213218822Sdim  const struct asm_opcode *opcode;
11214218822Sdim
11215218822Sdim  opcode = hash_find (arm_ops_hsh, opname);
1121689857Sobrien
11217218822Sdim  if (!opcode)
11218218822Sdim    abort ();
1121989857Sobrien
11220218822Sdim  constraint (!ARM_CPU_HAS_FEATURE (cpu_variant,
11221218822Sdim                thumb_mode ? *opcode->tvariant : *opcode->avariant),
11222218822Sdim              _(BAD_FPU));
11223218822Sdim
11224218822Sdim  if (thumb_mode)
1122589857Sobrien    {
11226218822Sdim      inst.instruction = opcode->tvalue;
11227218822Sdim      opcode->tencode ();
1122889857Sobrien    }
11229218822Sdim  else
1123089857Sobrien    {
11231218822Sdim      inst.instruction = (inst.cond << 28) | opcode->avalue;
11232218822Sdim      opcode->aencode ();
1123389857Sobrien    }
1123489857Sobrien}
1123589857Sobrien
1123689857Sobrienstatic void
11237218822Sdimdo_vfp_nsyn_add_sub (enum neon_shape rs)
1123889857Sobrien{
11239218822Sdim  int is_add = (inst.instruction & 0x0fffffff) == N_MNEM_vadd;
1124089857Sobrien
11241218822Sdim  if (rs == NS_FFF)
11242218822Sdim    {
11243218822Sdim      if (is_add)
11244218822Sdim        do_vfp_nsyn_opcode ("fadds");
11245218822Sdim      else
11246218822Sdim        do_vfp_nsyn_opcode ("fsubs");
11247218822Sdim    }
11248218822Sdim  else
11249218822Sdim    {
11250218822Sdim      if (is_add)
11251218822Sdim        do_vfp_nsyn_opcode ("faddd");
11252218822Sdim      else
11253218822Sdim        do_vfp_nsyn_opcode ("fsubd");
11254218822Sdim    }
11255218822Sdim}
1125689857Sobrien
11257218822Sdim/* Check operand types to see if this is a VFP instruction, and if so call
11258218822Sdim   PFN ().  */
1125989857Sobrien
11260218822Sdimstatic int
11261218822Sdimtry_vfp_nsyn (int args, void (*pfn) (enum neon_shape))
11262218822Sdim{
11263218822Sdim  enum neon_shape rs;
11264218822Sdim  struct neon_type_el et;
1126589857Sobrien
11266218822Sdim  switch (args)
1126789857Sobrien    {
11268218822Sdim    case 2:
11269218822Sdim      rs = neon_select_shape (NS_FF, NS_DD, NS_NULL);
11270218822Sdim      et = neon_check_type (2, rs,
11271218822Sdim        N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
11272218822Sdim      break;
11273218822Sdim
11274218822Sdim    case 3:
11275218822Sdim      rs = neon_select_shape (NS_FFF, NS_DDD, NS_NULL);
11276218822Sdim      et = neon_check_type (3, rs,
11277218822Sdim        N_EQK | N_VFP, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
11278218822Sdim      break;
11279218822Sdim
11280218822Sdim    default:
11281218822Sdim      abort ();
1128289857Sobrien    }
1128389857Sobrien
11284218822Sdim  if (et.type != NT_invtype)
1128589857Sobrien    {
11286218822Sdim      pfn (rs);
11287218822Sdim      return SUCCESS;
1128889857Sobrien    }
11289218822Sdim  else
11290218822Sdim    inst.error = NULL;
1129189857Sobrien
11292218822Sdim  return FAIL;
1129389857Sobrien}
1129489857Sobrien
1129589857Sobrienstatic void
11296218822Sdimdo_vfp_nsyn_mla_mls (enum neon_shape rs)
1129789857Sobrien{
11298218822Sdim  int is_mla = (inst.instruction & 0x0fffffff) == N_MNEM_vmla;
11299218822Sdim
11300218822Sdim  if (rs == NS_FFF)
11301218822Sdim    {
11302218822Sdim      if (is_mla)
11303218822Sdim        do_vfp_nsyn_opcode ("fmacs");
11304218822Sdim      else
11305218822Sdim        do_vfp_nsyn_opcode ("fmscs");
11306218822Sdim    }
11307218822Sdim  else
11308218822Sdim    {
11309218822Sdim      if (is_mla)
11310218822Sdim        do_vfp_nsyn_opcode ("fmacd");
11311218822Sdim      else
11312218822Sdim        do_vfp_nsyn_opcode ("fmscd");
11313218822Sdim    }
1131489857Sobrien}
1131589857Sobrien
1131689857Sobrienstatic void
11317218822Sdimdo_vfp_nsyn_mul (enum neon_shape rs)
1131889857Sobrien{
11319218822Sdim  if (rs == NS_FFF)
11320218822Sdim    do_vfp_nsyn_opcode ("fmuls");
11321218822Sdim  else
11322218822Sdim    do_vfp_nsyn_opcode ("fmuld");
1132389857Sobrien}
1132489857Sobrien
1132589857Sobrienstatic void
11326218822Sdimdo_vfp_nsyn_abs_neg (enum neon_shape rs)
1132789857Sobrien{
11328218822Sdim  int is_neg = (inst.instruction & 0x80) != 0;
11329218822Sdim  neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_VFP | N_KEY);
11330218822Sdim
11331218822Sdim  if (rs == NS_FF)
11332218822Sdim    {
11333218822Sdim      if (is_neg)
11334218822Sdim        do_vfp_nsyn_opcode ("fnegs");
11335218822Sdim      else
11336218822Sdim        do_vfp_nsyn_opcode ("fabss");
11337218822Sdim    }
11338218822Sdim  else
11339218822Sdim    {
11340218822Sdim      if (is_neg)
11341218822Sdim        do_vfp_nsyn_opcode ("fnegd");
11342218822Sdim      else
11343218822Sdim        do_vfp_nsyn_opcode ("fabsd");
11344218822Sdim    }
1134589857Sobrien}
1134689857Sobrien
11347218822Sdim/* Encode single-precision (only!) VFP fldm/fstm instructions. Double precision
11348218822Sdim   insns belong to Neon, and are handled elsewhere.  */
11349218822Sdim
1135089857Sobrienstatic void
11351218822Sdimdo_vfp_nsyn_ldm_stm (int is_dbmode)
1135289857Sobrien{
11353218822Sdim  int is_ldm = (inst.instruction & (1 << 20)) != 0;
11354218822Sdim  if (is_ldm)
11355218822Sdim    {
11356218822Sdim      if (is_dbmode)
11357218822Sdim        do_vfp_nsyn_opcode ("fldmdbs");
11358218822Sdim      else
11359218822Sdim        do_vfp_nsyn_opcode ("fldmias");
11360218822Sdim    }
11361218822Sdim  else
11362218822Sdim    {
11363218822Sdim      if (is_dbmode)
11364218822Sdim        do_vfp_nsyn_opcode ("fstmdbs");
11365218822Sdim      else
11366218822Sdim        do_vfp_nsyn_opcode ("fstmias");
11367218822Sdim    }
1136889857Sobrien}
1136989857Sobrien
1137089857Sobrienstatic void
11371218822Sdimdo_vfp_nsyn_sqrt (void)
1137289857Sobrien{
11373218822Sdim  enum neon_shape rs = neon_select_shape (NS_FF, NS_DD, NS_NULL);
11374218822Sdim  neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
11375218822Sdim
11376218822Sdim  if (rs == NS_FF)
11377218822Sdim    do_vfp_nsyn_opcode ("fsqrts");
11378218822Sdim  else
11379218822Sdim    do_vfp_nsyn_opcode ("fsqrtd");
1138089857Sobrien}
1138189857Sobrien
1138289857Sobrienstatic void
11383218822Sdimdo_vfp_nsyn_div (void)
1138489857Sobrien{
11385218822Sdim  enum neon_shape rs = neon_select_shape (NS_FFF, NS_DDD, NS_NULL);
11386218822Sdim  neon_check_type (3, rs, N_EQK | N_VFP, N_EQK | N_VFP,
11387218822Sdim    N_F32 | N_F64 | N_KEY | N_VFP);
11388218822Sdim
11389218822Sdim  if (rs == NS_FFF)
11390218822Sdim    do_vfp_nsyn_opcode ("fdivs");
11391218822Sdim  else
11392218822Sdim    do_vfp_nsyn_opcode ("fdivd");
1139389857Sobrien}
1139489857Sobrien
1139589857Sobrienstatic void
11396218822Sdimdo_vfp_nsyn_nmul (void)
1139789857Sobrien{
11398218822Sdim  enum neon_shape rs = neon_select_shape (NS_FFF, NS_DDD, NS_NULL);
11399218822Sdim  neon_check_type (3, rs, N_EQK | N_VFP, N_EQK | N_VFP,
11400218822Sdim    N_F32 | N_F64 | N_KEY | N_VFP);
11401218822Sdim
11402218822Sdim  if (rs == NS_FFF)
1140389857Sobrien    {
11404218822Sdim      inst.instruction = NEON_ENC_SINGLE (inst.instruction);
11405218822Sdim      do_vfp_sp_dyadic ();
1140689857Sobrien    }
11407218822Sdim  else
11408218822Sdim    {
11409218822Sdim      inst.instruction = NEON_ENC_DOUBLE (inst.instruction);
11410218822Sdim      do_vfp_dp_rd_rn_rm ();
11411218822Sdim    }
11412218822Sdim  do_vfp_cond_or_thumb ();
1141389857Sobrien}
1141489857Sobrien
1141589857Sobrienstatic void
11416218822Sdimdo_vfp_nsyn_cmp (void)
1141789857Sobrien{
11418218822Sdim  if (inst.operands[1].isreg)
1141989857Sobrien    {
11420218822Sdim      enum neon_shape rs = neon_select_shape (NS_FF, NS_DD, NS_NULL);
11421218822Sdim      neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
11422218822Sdim
11423218822Sdim      if (rs == NS_FF)
11424218822Sdim        {
11425218822Sdim          inst.instruction = NEON_ENC_SINGLE (inst.instruction);
11426218822Sdim          do_vfp_sp_monadic ();
11427218822Sdim        }
11428218822Sdim      else
11429218822Sdim        {
11430218822Sdim          inst.instruction = NEON_ENC_DOUBLE (inst.instruction);
11431218822Sdim          do_vfp_dp_rd_rm ();
11432218822Sdim        }
1143389857Sobrien    }
11434218822Sdim  else
11435218822Sdim    {
11436218822Sdim      enum neon_shape rs = neon_select_shape (NS_FI, NS_DI, NS_NULL);
11437218822Sdim      neon_check_type (2, rs, N_F32 | N_F64 | N_KEY | N_VFP, N_EQK);
1143889857Sobrien
11439218822Sdim      switch (inst.instruction & 0x0fffffff)
11440218822Sdim        {
11441218822Sdim        case N_MNEM_vcmp:
11442218822Sdim          inst.instruction += N_MNEM_vcmpz - N_MNEM_vcmp;
11443218822Sdim          break;
11444218822Sdim        case N_MNEM_vcmpe:
11445218822Sdim          inst.instruction += N_MNEM_vcmpez - N_MNEM_vcmpe;
11446218822Sdim          break;
11447218822Sdim        default:
11448218822Sdim          abort ();
11449218822Sdim        }
11450218822Sdim
11451218822Sdim      if (rs == NS_FI)
11452218822Sdim        {
11453218822Sdim          inst.instruction = NEON_ENC_SINGLE (inst.instruction);
11454218822Sdim          do_vfp_sp_compare_z ();
11455218822Sdim        }
11456218822Sdim      else
11457218822Sdim        {
11458218822Sdim          inst.instruction = NEON_ENC_DOUBLE (inst.instruction);
11459218822Sdim          do_vfp_dp_rd ();
11460218822Sdim        }
11461218822Sdim    }
11462218822Sdim  do_vfp_cond_or_thumb ();
1146389857Sobrien}
1146489857Sobrien
1146589857Sobrienstatic void
11466218822Sdimnsyn_insert_sp (void)
1146789857Sobrien{
11468218822Sdim  inst.operands[1] = inst.operands[0];
11469218822Sdim  memset (&inst.operands[0], '\0', sizeof (inst.operands[0]));
11470218822Sdim  inst.operands[0].reg = 13;
11471218822Sdim  inst.operands[0].isreg = 1;
11472218822Sdim  inst.operands[0].writeback = 1;
11473218822Sdim  inst.operands[0].present = 1;
11474218822Sdim}
1147589857Sobrien
11476218822Sdimstatic void
11477218822Sdimdo_vfp_nsyn_push (void)
11478218822Sdim{
11479218822Sdim  nsyn_insert_sp ();
11480218822Sdim  if (inst.operands[1].issingle)
11481218822Sdim    do_vfp_nsyn_opcode ("fstmdbs");
11482218822Sdim  else
11483218822Sdim    do_vfp_nsyn_opcode ("fstmdbd");
1148489857Sobrien}
1148589857Sobrien
1148689857Sobrienstatic void
11487218822Sdimdo_vfp_nsyn_pop (void)
1148889857Sobrien{
11489218822Sdim  nsyn_insert_sp ();
11490218822Sdim  if (inst.operands[1].issingle)
11491218822Sdim    do_vfp_nsyn_opcode ("fldmias");
11492218822Sdim  else
11493218822Sdim    do_vfp_nsyn_opcode ("fldmiad");
11494218822Sdim}
1149589857Sobrien
11496218822Sdim/* Fix up Neon data-processing instructions, ORing in the correct bits for
11497218822Sdim   ARM mode or Thumb mode and moving the encoded bit 24 to bit 28.  */
1149889857Sobrien
11499218822Sdimstatic unsigned
11500218822Sdimneon_dp_fixup (unsigned i)
11501218822Sdim{
11502218822Sdim  if (thumb_mode)
1150389857Sobrien    {
11504218822Sdim      /* The U bit is at bit 24 by default. Move to bit 28 in Thumb mode.  */
11505218822Sdim      if (i & (1 << 24))
11506218822Sdim        i |= 1 << 28;
11507218822Sdim
11508218822Sdim      i &= ~(1 << 24);
11509218822Sdim
11510218822Sdim      i |= 0xef000000;
1151189857Sobrien    }
11512218822Sdim  else
11513218822Sdim    i |= 0xf2000000;
11514218822Sdim
11515218822Sdim  return i;
11516218822Sdim}
1151789857Sobrien
11518218822Sdim/* Turn a size (8, 16, 32, 64) into the respective bit number minus 3
11519218822Sdim   (0, 1, 2, 3).  */
11520218822Sdim
11521218822Sdimstatic unsigned
11522218822Sdimneon_logbits (unsigned x)
11523218822Sdim{
11524218822Sdim  return ffs (x) - 4;
1152589857Sobrien}
1152689857Sobrien
11527218822Sdim#define LOW4(R) ((R) & 0xf)
11528218822Sdim#define HI1(R) (((R) >> 4) & 1)
1152960484Sobrien
11530218822Sdim/* Encode insns with bit pattern:
1153177298Sobrien
11532218822Sdim  |28/24|23|22 |21 20|19 16|15 12|11    8|7|6|5|4|3  0|
11533218822Sdim  |  U  |x |D  |size | Rn  | Rd  |x x x x|N|Q|M|x| Rm |
11534218822Sdim
11535218822Sdim  SIZE is passed in bits. -1 means size field isn't changed, in case it has a
11536218822Sdim  different meaning for some instruction.  */
11537218822Sdim
11538218822Sdimstatic void
11539218822Sdimneon_three_same (int isquad, int ubit, int size)
1154060484Sobrien{
11541218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
11542218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
11543218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
11544218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
11545218822Sdim  inst.instruction |= LOW4 (inst.operands[2].reg);
11546218822Sdim  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
11547218822Sdim  inst.instruction |= (isquad != 0) << 6;
11548218822Sdim  inst.instruction |= (ubit != 0) << 24;
11549218822Sdim  if (size != -1)
11550218822Sdim    inst.instruction |= neon_logbits (size) << 20;
11551218822Sdim
11552218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
11553218822Sdim}
1155460484Sobrien
11555218822Sdim/* Encode instructions of the form:
1155660484Sobrien
11557218822Sdim  |28/24|23|22|21 20|19 18|17 16|15 12|11      7|6|5|4|3  0|
11558218822Sdim  |  U  |x |D |x  x |size |x  x | Rd  |x x x x x|Q|M|x| Rm |
1155960484Sobrien
11560218822Sdim  Don't write size if SIZE == -1.  */
1156160484Sobrien
11562218822Sdimstatic void
11563218822Sdimneon_two_same (int qbit, int ubit, int size)
11564218822Sdim{
11565218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
11566218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
11567218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg);
11568218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 5;
11569218822Sdim  inst.instruction |= (qbit != 0) << 6;
11570218822Sdim  inst.instruction |= (ubit != 0) << 24;
1157160484Sobrien
11572218822Sdim  if (size != -1)
11573218822Sdim    inst.instruction |= neon_logbits (size) << 18;
11574218822Sdim
11575218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1157660484Sobrien}
1157760484Sobrien
11578218822Sdim/* Neon instruction encoders, in approximate order of appearance.  */
1157977298Sobrien
1158060484Sobrienstatic void
11581218822Sdimdo_neon_dyadic_i_su (void)
1158260484Sobrien{
11583218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11584218822Sdim  struct neon_type_el et = neon_check_type (3, rs,
11585218822Sdim    N_EQK, N_EQK, N_SU_32 | N_KEY);
11586218822Sdim  neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
11587218822Sdim}
1158860484Sobrien
11589218822Sdimstatic void
11590218822Sdimdo_neon_dyadic_i64_su (void)
11591218822Sdim{
11592218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11593218822Sdim  struct neon_type_el et = neon_check_type (3, rs,
11594218822Sdim    N_EQK, N_EQK, N_SU_ALL | N_KEY);
11595218822Sdim  neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
11596218822Sdim}
1159760484Sobrien
11598218822Sdimstatic void
11599218822Sdimneon_imm_shift (int write_ubit, int uval, int isquad, struct neon_type_el et,
11600218822Sdim                unsigned immbits)
11601218822Sdim{
11602218822Sdim  unsigned size = et.size >> 3;
11603218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
11604218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
11605218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg);
11606218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 5;
11607218822Sdim  inst.instruction |= (isquad != 0) << 6;
11608218822Sdim  inst.instruction |= immbits << 16;
11609218822Sdim  inst.instruction |= (size >> 3) << 7;
11610218822Sdim  inst.instruction |= (size & 0x7) << 19;
11611218822Sdim  if (write_ubit)
11612218822Sdim    inst.instruction |= (uval != 0) << 24;
11613218822Sdim
11614218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
11615218822Sdim}
11616218822Sdim
11617218822Sdimstatic void
11618218822Sdimdo_neon_shl_imm (void)
11619218822Sdim{
11620218822Sdim  if (!inst.operands[2].isreg)
1162160484Sobrien    {
11622218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
11623218822Sdim      struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_KEY | N_I_ALL);
11624218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
11625218822Sdim      neon_imm_shift (FALSE, 0, neon_quad (rs), et, inst.operands[2].imm);
1162660484Sobrien    }
11627218822Sdim  else
11628218822Sdim    {
11629218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11630218822Sdim      struct neon_type_el et = neon_check_type (3, rs,
11631218822Sdim        N_EQK, N_SU_ALL | N_KEY, N_EQK | N_SGN);
11632218822Sdim      unsigned int tmp;
1163360484Sobrien
11634218822Sdim      /* VSHL/VQSHL 3-register variants have syntax such as:
11635218822Sdim           vshl.xx Dd, Dm, Dn
11636218822Sdim         whereas other 3-register operations encoded by neon_three_same have
11637218822Sdim         syntax like:
11638218822Sdim           vadd.xx Dd, Dn, Dm
11639218822Sdim         (i.e. with Dn & Dm reversed). Swap operands[1].reg and operands[2].reg
11640218822Sdim         here.  */
11641218822Sdim      tmp = inst.operands[2].reg;
11642218822Sdim      inst.operands[2].reg = inst.operands[1].reg;
11643218822Sdim      inst.operands[1].reg = tmp;
11644218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
11645218822Sdim      neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
11646218822Sdim    }
11647218822Sdim}
11648218822Sdim
11649218822Sdimstatic void
11650218822Sdimdo_neon_qshl_imm (void)
11651218822Sdim{
11652218822Sdim  if (!inst.operands[2].isreg)
1165360484Sobrien    {
11654218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
11655218822Sdim      struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_SU_ALL | N_KEY);
11656218822Sdim
11657218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
11658218822Sdim      neon_imm_shift (TRUE, et.type == NT_unsigned, neon_quad (rs), et,
11659218822Sdim                      inst.operands[2].imm);
1166060484Sobrien    }
1166160484Sobrien  else
1166260484Sobrien    {
11663218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11664218822Sdim      struct neon_type_el et = neon_check_type (3, rs,
11665218822Sdim        N_EQK, N_SU_ALL | N_KEY, N_EQK | N_SGN);
11666218822Sdim      unsigned int tmp;
1166760484Sobrien
11668218822Sdim      /* See note in do_neon_shl_imm.  */
11669218822Sdim      tmp = inst.operands[2].reg;
11670218822Sdim      inst.operands[2].reg = inst.operands[1].reg;
11671218822Sdim      inst.operands[1].reg = tmp;
11672218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
11673218822Sdim      neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
11674218822Sdim    }
11675218822Sdim}
11676218822Sdim
11677218822Sdimstatic void
11678218822Sdimdo_neon_rshl (void)
11679218822Sdim{
11680218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11681218822Sdim  struct neon_type_el et = neon_check_type (3, rs,
11682218822Sdim    N_EQK, N_EQK, N_SU_ALL | N_KEY);
11683218822Sdim  unsigned int tmp;
11684218822Sdim
11685218822Sdim  tmp = inst.operands[2].reg;
11686218822Sdim  inst.operands[2].reg = inst.operands[1].reg;
11687218822Sdim  inst.operands[1].reg = tmp;
11688218822Sdim  neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
11689218822Sdim}
11690218822Sdim
11691218822Sdimstatic int
11692218822Sdimneon_cmode_for_logic_imm (unsigned immediate, unsigned *immbits, int size)
11693218822Sdim{
11694218822Sdim  /* Handle .I8 pseudo-instructions.  */
11695218822Sdim  if (size == 8)
11696218822Sdim    {
11697218822Sdim      /* Unfortunately, this will make everything apart from zero out-of-range.
11698218822Sdim         FIXME is this the intended semantics? There doesn't seem much point in
11699218822Sdim         accepting .I8 if so.  */
11700218822Sdim      immediate |= immediate << 8;
11701218822Sdim      size = 16;
11702218822Sdim    }
11703218822Sdim
11704218822Sdim  if (size >= 32)
11705218822Sdim    {
11706218822Sdim      if (immediate == (immediate & 0x000000ff))
1170760484Sobrien	{
11708218822Sdim	  *immbits = immediate;
11709218822Sdim	  return 0x1;
1171060484Sobrien	}
11711218822Sdim      else if (immediate == (immediate & 0x0000ff00))
1171260484Sobrien	{
11713218822Sdim	  *immbits = immediate >> 8;
11714218822Sdim	  return 0x3;
1171560484Sobrien	}
11716218822Sdim      else if (immediate == (immediate & 0x00ff0000))
1171760484Sobrien	{
11718218822Sdim	  *immbits = immediate >> 16;
11719218822Sdim	  return 0x5;
1172060484Sobrien	}
11721218822Sdim      else if (immediate == (immediate & 0xff000000))
1172260484Sobrien	{
11723218822Sdim	  *immbits = immediate >> 24;
11724218822Sdim	  return 0x7;
1172560484Sobrien	}
11726218822Sdim      if ((immediate & 0xffff) != (immediate >> 16))
11727218822Sdim	goto bad_immediate;
11728218822Sdim      immediate &= 0xffff;
1172960484Sobrien    }
11730218822Sdim
11731218822Sdim  if (immediate == (immediate & 0x000000ff))
1173260484Sobrien    {
11733218822Sdim      *immbits = immediate;
11734218822Sdim      return 0x9;
11735218822Sdim    }
11736218822Sdim  else if (immediate == (immediate & 0x0000ff00))
11737218822Sdim    {
11738218822Sdim      *immbits = immediate >> 8;
11739218822Sdim      return 0xb;
11740218822Sdim    }
1174160484Sobrien
11742218822Sdim  bad_immediate:
11743218822Sdim  first_error (_("immediate value out of range"));
11744218822Sdim  return FAIL;
11745218822Sdim}
1174660484Sobrien
11747218822Sdim/* True if IMM has form 0bAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD for bits
11748218822Sdim   A, B, C, D.  */
1174960484Sobrien
11750218822Sdimstatic int
11751218822Sdimneon_bits_same_in_bytes (unsigned imm)
11752218822Sdim{
11753218822Sdim  return ((imm & 0x000000ff) == 0 || (imm & 0x000000ff) == 0x000000ff)
11754218822Sdim         && ((imm & 0x0000ff00) == 0 || (imm & 0x0000ff00) == 0x0000ff00)
11755218822Sdim         && ((imm & 0x00ff0000) == 0 || (imm & 0x00ff0000) == 0x00ff0000)
11756218822Sdim         && ((imm & 0xff000000) == 0 || (imm & 0xff000000) == 0xff000000);
11757218822Sdim}
1175860484Sobrien
11759218822Sdim/* For immediate of above form, return 0bABCD.  */
1176060484Sobrien
11761218822Sdimstatic unsigned
11762218822Sdimneon_squash_bits (unsigned imm)
11763218822Sdim{
11764218822Sdim  return (imm & 0x01) | ((imm & 0x0100) >> 7) | ((imm & 0x010000) >> 14)
11765218822Sdim         | ((imm & 0x01000000) >> 21);
11766218822Sdim}
1176760484Sobrien
11768218822Sdim/* Compress quarter-float representation to 0b...000 abcdefgh.  */
1176977298Sobrien
11770218822Sdimstatic unsigned
11771218822Sdimneon_qfloat_bits (unsigned imm)
11772218822Sdim{
11773218822Sdim  return ((imm >> 19) & 0x7f) | ((imm >> 24) & 0x80);
1177460484Sobrien}
1177560484Sobrien
11776218822Sdim/* Returns CMODE. IMMBITS [7:0] is set to bits suitable for inserting into
11777218822Sdim   the instruction. *OP is passed as the initial value of the op field, and
11778218822Sdim   may be set to a different value depending on the constant (i.e.
11779218822Sdim   "MOV I64, 0bAAAAAAAABBBB..." which uses OP = 1 despite being MOV not
11780218822Sdim   MVN).  If the immediate looks like a repeated parttern then also
11781218822Sdim   try smaller element sizes.  */
11782218822Sdim
11783218822Sdimstatic int
11784218822Sdimneon_cmode_for_move_imm (unsigned immlo, unsigned immhi, int float_p,
11785218822Sdim			 unsigned *immbits, int *op, int size,
11786218822Sdim			 enum neon_el_type type)
1178760484Sobrien{
11788218822Sdim  /* Only permit float immediates (including 0.0/-0.0) if the operand type is
11789218822Sdim     float.  */
11790218822Sdim  if (type == NT_float && !float_p)
11791218822Sdim    return FAIL;
1179260484Sobrien
11793218822Sdim  if (type == NT_float && is_quarter_float (immlo) && immhi == 0)
1179460484Sobrien    {
11795218822Sdim      if (size != 32 || *op == 1)
11796218822Sdim        return FAIL;
11797218822Sdim      *immbits = neon_qfloat_bits (immlo);
11798218822Sdim      return 0xf;
1179960484Sobrien    }
1180060484Sobrien
11801218822Sdim  if (size == 64)
1180260484Sobrien    {
11803218822Sdim      if (neon_bits_same_in_bytes (immhi)
11804218822Sdim	  && neon_bits_same_in_bytes (immlo))
11805218822Sdim	{
11806218822Sdim	  if (*op == 1)
11807218822Sdim	    return FAIL;
11808218822Sdim	  *immbits = (neon_squash_bits (immhi) << 4)
11809218822Sdim		     | neon_squash_bits (immlo);
11810218822Sdim	  *op = 1;
11811218822Sdim	  return 0xe;
11812218822Sdim	}
11813218822Sdim
11814218822Sdim      if (immhi != immlo)
11815218822Sdim	return FAIL;
1181660484Sobrien    }
11817218822Sdim
11818218822Sdim  if (size >= 32)
1181960484Sobrien    {
11820218822Sdim      if (immlo == (immlo & 0x000000ff))
1182160484Sobrien	{
11822218822Sdim	  *immbits = immlo;
11823218822Sdim	  return 0x0;
1182460484Sobrien	}
11825218822Sdim      else if (immlo == (immlo & 0x0000ff00))
1182660484Sobrien	{
11827218822Sdim	  *immbits = immlo >> 8;
11828218822Sdim	  return 0x2;
1182960484Sobrien	}
11830218822Sdim      else if (immlo == (immlo & 0x00ff0000))
1183160484Sobrien	{
11832218822Sdim	  *immbits = immlo >> 16;
11833218822Sdim	  return 0x4;
1183460484Sobrien	}
11835218822Sdim      else if (immlo == (immlo & 0xff000000))
1183660484Sobrien	{
11837218822Sdim	  *immbits = immlo >> 24;
11838218822Sdim	  return 0x6;
1183960484Sobrien	}
11840218822Sdim      else if (immlo == ((immlo & 0x0000ff00) | 0x000000ff))
11841218822Sdim	{
11842218822Sdim	  *immbits = (immlo >> 8) & 0xff;
11843218822Sdim	  return 0xc;
11844218822Sdim	}
11845218822Sdim      else if (immlo == ((immlo & 0x00ff0000) | 0x0000ffff))
11846218822Sdim	{
11847218822Sdim	  *immbits = (immlo >> 16) & 0xff;
11848218822Sdim	  return 0xd;
11849218822Sdim	}
1185060484Sobrien
11851218822Sdim      if ((immlo & 0xffff) != (immlo >> 16))
11852218822Sdim	return FAIL;
11853218822Sdim      immlo &= 0xffff;
1185460484Sobrien    }
11855218822Sdim
11856218822Sdim  if (size >= 16)
1185760484Sobrien    {
11858218822Sdim      if (immlo == (immlo & 0x000000ff))
1185960484Sobrien	{
11860218822Sdim	  *immbits = immlo;
11861218822Sdim	  return 0x8;
1186260484Sobrien	}
11863218822Sdim      else if (immlo == (immlo & 0x0000ff00))
1186460484Sobrien	{
11865218822Sdim	  *immbits = immlo >> 8;
11866218822Sdim	  return 0xa;
1186760484Sobrien	}
1186860484Sobrien
11869218822Sdim      if ((immlo & 0xff) != (immlo >> 8))
11870218822Sdim	return FAIL;
11871218822Sdim      immlo &= 0xff;
11872218822Sdim    }
1187360484Sobrien
11874218822Sdim  if (immlo == (immlo & 0x000000ff))
11875218822Sdim    {
11876218822Sdim      /* Don't allow MVN with 8-bit immediate.  */
11877218822Sdim      if (*op == 1)
11878218822Sdim	return FAIL;
11879218822Sdim      *immbits = immlo;
11880218822Sdim      return 0xe;
11881218822Sdim    }
1188260484Sobrien
11883218822Sdim  return FAIL;
11884218822Sdim}
1188560484Sobrien
11886218822Sdim/* Write immediate bits [7:0] to the following locations:
1188760484Sobrien
11888218822Sdim  |28/24|23     19|18 16|15                    4|3     0|
11889218822Sdim  |  a  |x x x x x|b c d|x x x x x x x x x x x x|e f g h|
1189077298Sobrien
11891218822Sdim  This function is used by VMOV/VMVN/VORR/VBIC.  */
1189260484Sobrien
1189360484Sobrienstatic void
11894218822Sdimneon_write_immbits (unsigned immbits)
1189560484Sobrien{
11896218822Sdim  inst.instruction |= immbits & 0xf;
11897218822Sdim  inst.instruction |= ((immbits >> 4) & 0x7) << 16;
11898218822Sdim  inst.instruction |= ((immbits >> 7) & 0x1) << 24;
11899218822Sdim}
1190060484Sobrien
11901218822Sdim/* Invert low-order SIZE bits of XHI:XLO.  */
1190260484Sobrien
11903218822Sdimstatic void
11904218822Sdimneon_invert_size (unsigned *xlo, unsigned *xhi, int size)
11905218822Sdim{
11906218822Sdim  unsigned immlo = xlo ? *xlo : 0;
11907218822Sdim  unsigned immhi = xhi ? *xhi : 0;
1190860484Sobrien
11909218822Sdim  switch (size)
1191060484Sobrien    {
11911218822Sdim    case 8:
11912218822Sdim      immlo = (~immlo) & 0xff;
11913218822Sdim      break;
1191460484Sobrien
11915218822Sdim    case 16:
11916218822Sdim      immlo = (~immlo) & 0xffff;
11917218822Sdim      break;
1191860484Sobrien
11919218822Sdim    case 64:
11920218822Sdim      immhi = (~immhi) & 0xffffffff;
11921218822Sdim      /* fall through.  */
1192260484Sobrien
11923218822Sdim    case 32:
11924218822Sdim      immlo = (~immlo) & 0xffffffff;
11925218822Sdim      break;
1192660484Sobrien
11927218822Sdim    default:
11928218822Sdim      abort ();
1192960484Sobrien    }
11930218822Sdim
11931218822Sdim  if (xlo)
11932218822Sdim    *xlo = immlo;
11933218822Sdim
11934218822Sdim  if (xhi)
11935218822Sdim    *xhi = immhi;
11936218822Sdim}
11937218822Sdim
11938218822Sdimstatic void
11939218822Sdimdo_neon_logic (void)
11940218822Sdim{
11941218822Sdim  if (inst.operands[2].present && inst.operands[2].isreg)
11942218822Sdim    {
11943218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11944218822Sdim      neon_check_type (3, rs, N_IGNORE_TYPE);
11945218822Sdim      /* U bit and size field were set as part of the bitmask.  */
11946218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
11947218822Sdim      neon_three_same (neon_quad (rs), 0, -1);
11948218822Sdim    }
1194960484Sobrien  else
1195060484Sobrien    {
11951218822Sdim      enum neon_shape rs = neon_select_shape (NS_DI, NS_QI, NS_NULL);
11952218822Sdim      struct neon_type_el et = neon_check_type (2, rs,
11953218822Sdim        N_I8 | N_I16 | N_I32 | N_I64 | N_F32 | N_KEY, N_EQK);
11954218822Sdim      enum neon_opc opcode = inst.instruction & 0x0fffffff;
11955218822Sdim      unsigned immbits;
11956218822Sdim      int cmode;
11957218822Sdim
11958218822Sdim      if (et.type == NT_invtype)
11959218822Sdim        return;
11960218822Sdim
11961218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
11962218822Sdim
11963218822Sdim      immbits = inst.operands[1].imm;
11964218822Sdim      if (et.size == 64)
1196560484Sobrien	{
11966218822Sdim	  /* .i64 is a pseudo-op, so the immediate must be a repeating
11967218822Sdim	     pattern.  */
11968218822Sdim	  if (immbits != (inst.operands[1].regisimm ?
11969218822Sdim			  inst.operands[1].reg : 0))
11970218822Sdim	    {
11971218822Sdim	      /* Set immbits to an invalid constant.  */
11972218822Sdim	      immbits = 0xdeadbeef;
11973218822Sdim	    }
1197460484Sobrien	}
1197560484Sobrien
11976218822Sdim      switch (opcode)
11977218822Sdim        {
11978218822Sdim        case N_MNEM_vbic:
11979218822Sdim          cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
11980218822Sdim          break;
11981218822Sdim
11982218822Sdim        case N_MNEM_vorr:
11983218822Sdim          cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
11984218822Sdim          break;
11985218822Sdim
11986218822Sdim        case N_MNEM_vand:
11987218822Sdim          /* Pseudo-instruction for VBIC.  */
11988218822Sdim          neon_invert_size (&immbits, 0, et.size);
11989218822Sdim          cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
11990218822Sdim          break;
11991218822Sdim
11992218822Sdim        case N_MNEM_vorn:
11993218822Sdim          /* Pseudo-instruction for VORR.  */
11994218822Sdim          neon_invert_size (&immbits, 0, et.size);
11995218822Sdim          cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
11996218822Sdim          break;
11997218822Sdim
11998218822Sdim        default:
11999218822Sdim          abort ();
12000218822Sdim        }
1200160484Sobrien
12002218822Sdim      if (cmode == FAIL)
12003218822Sdim        return;
1200460484Sobrien
12005218822Sdim      inst.instruction |= neon_quad (rs) << 6;
12006218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12007218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12008218822Sdim      inst.instruction |= cmode << 8;
12009218822Sdim      neon_write_immbits (immbits);
12010218822Sdim
12011218822Sdim      inst.instruction = neon_dp_fixup (inst.instruction);
1201260484Sobrien    }
12013218822Sdim}
1201460484Sobrien
12015218822Sdimstatic void
12016218822Sdimdo_neon_bitfield (void)
12017218822Sdim{
12018218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
12019218822Sdim  neon_check_type (3, rs, N_IGNORE_TYPE);
12020218822Sdim  neon_three_same (neon_quad (rs), 0, -1);
1202160484Sobrien}
1202260484Sobrien
1202360484Sobrienstatic void
12024218822Sdimneon_dyadic_misc (enum neon_el_type ubit_meaning, unsigned types,
12025218822Sdim                  unsigned destbits)
1202660484Sobrien{
12027218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
12028218822Sdim  struct neon_type_el et = neon_check_type (3, rs, N_EQK | destbits, N_EQK,
12029218822Sdim                                            types | N_KEY);
12030218822Sdim  if (et.type == NT_float)
1203160484Sobrien    {
12032218822Sdim      inst.instruction = NEON_ENC_FLOAT (inst.instruction);
12033218822Sdim      neon_three_same (neon_quad (rs), 0, -1);
1203460484Sobrien    }
12035218822Sdim  else
1203660484Sobrien    {
12037218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12038218822Sdim      neon_three_same (neon_quad (rs), et.type == ubit_meaning, et.size);
1203960484Sobrien    }
12040218822Sdim}
1204189857Sobrien
12042218822Sdimstatic void
12043218822Sdimdo_neon_dyadic_if_su (void)
12044218822Sdim{
12045218822Sdim  neon_dyadic_misc (NT_unsigned, N_SUF_32, 0);
12046218822Sdim}
1204760484Sobrien
12048218822Sdimstatic void
12049218822Sdimdo_neon_dyadic_if_su_d (void)
12050218822Sdim{
12051218822Sdim  /* This version only allow D registers, but that constraint is enforced during
12052218822Sdim     operand parsing so we don't need to do anything extra here.  */
12053218822Sdim  neon_dyadic_misc (NT_unsigned, N_SUF_32, 0);
12054218822Sdim}
1205560484Sobrien
12056218822Sdimstatic void
12057218822Sdimdo_neon_dyadic_if_i_d (void)
12058218822Sdim{
12059218822Sdim  /* The "untyped" case can't happen. Do this to stop the "U" bit being
12060218822Sdim     affected if we specify unsigned args.  */
12061218822Sdim  neon_dyadic_misc (NT_untyped, N_IF_32, 0);
12062218822Sdim}
1206360484Sobrien
12064218822Sdimenum vfp_or_neon_is_neon_bits
12065218822Sdim{
12066218822Sdim  NEON_CHECK_CC = 1,
12067218822Sdim  NEON_CHECK_ARCH = 2
12068218822Sdim};
1206977298Sobrien
12070218822Sdim/* Call this function if an instruction which may have belonged to the VFP or
12071218822Sdim   Neon instruction sets, but turned out to be a Neon instruction (due to the
12072218822Sdim   operand types involved, etc.). We have to check and/or fix-up a couple of
12073218822Sdim   things:
1207460484Sobrien
12075218822Sdim     - Make sure the user hasn't attempted to make a Neon instruction
12076218822Sdim       conditional.
12077218822Sdim     - Alter the value in the condition code field if necessary.
12078218822Sdim     - Make sure that the arch supports Neon instructions.
1207960484Sobrien
12080218822Sdim   Which of these operations take place depends on bits from enum
12081218822Sdim   vfp_or_neon_is_neon_bits.
1208260484Sobrien
12083218822Sdim   WARNING: This function has side effects! If NEON_CHECK_CC is used and the
12084218822Sdim   current instruction's condition is COND_ALWAYS, the condition field is
12085218822Sdim   changed to inst.uncond_value. This is necessary because instructions shared
12086218822Sdim   between VFP and Neon may be conditional for the VFP variants only, and the
12087218822Sdim   unconditional Neon version must have, e.g., 0xF in the condition field.  */
1208860484Sobrien
12089218822Sdimstatic int
12090218822Sdimvfp_or_neon_is_neon (unsigned check)
12091218822Sdim{
12092218822Sdim  /* Conditions are always legal in Thumb mode (IT blocks).  */
12093218822Sdim  if (!thumb_mode && (check & NEON_CHECK_CC))
12094218822Sdim    {
12095218822Sdim      if (inst.cond != COND_ALWAYS)
12096218822Sdim        {
12097218822Sdim          first_error (_(BAD_COND));
12098218822Sdim          return FAIL;
12099218822Sdim        }
12100218822Sdim      if (inst.uncond_value != -1)
12101218822Sdim        inst.instruction |= inst.uncond_value << 28;
1210260484Sobrien    }
12103218822Sdim
12104218822Sdim  if ((check & NEON_CHECK_ARCH)
12105218822Sdim      && !ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1))
1210660484Sobrien    {
12107218822Sdim      first_error (_(BAD_FPU));
12108218822Sdim      return FAIL;
1210960484Sobrien    }
12110218822Sdim
12111218822Sdim  return SUCCESS;
12112218822Sdim}
1211360484Sobrien
12114218822Sdimstatic void
12115218822Sdimdo_neon_addsub_if_i (void)
12116218822Sdim{
12117218822Sdim  if (try_vfp_nsyn (3, do_vfp_nsyn_add_sub) == SUCCESS)
12118218822Sdim    return;
1211960484Sobrien
12120218822Sdim  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12121218822Sdim    return;
1212260484Sobrien
12123218822Sdim  /* The "untyped" case can't happen. Do this to stop the "U" bit being
12124218822Sdim     affected if we specify unsigned args.  */
12125218822Sdim  neon_dyadic_misc (NT_untyped, N_IF_32 | N_I64, 0);
12126218822Sdim}
1212760484Sobrien
12128218822Sdim/* Swaps operands 1 and 2. If operand 1 (optional arg) was omitted, we want the
12129218822Sdim   result to be:
12130218822Sdim     V<op> A,B     (A is operand 0, B is operand 2)
12131218822Sdim   to mean:
12132218822Sdim     V<op> A,B,A
12133218822Sdim   not:
12134218822Sdim     V<op> A,B,B
12135218822Sdim   so handle that case specially.  */
1213660484Sobrien
12137218822Sdimstatic void
12138218822Sdimneon_exchange_operands (void)
12139218822Sdim{
12140218822Sdim  void *scratch = alloca (sizeof (inst.operands[0]));
12141218822Sdim  if (inst.operands[1].present)
12142218822Sdim    {
12143218822Sdim      /* Swap operands[1] and operands[2].  */
12144218822Sdim      memcpy (scratch, &inst.operands[1], sizeof (inst.operands[0]));
12145218822Sdim      inst.operands[1] = inst.operands[2];
12146218822Sdim      memcpy (&inst.operands[2], scratch, sizeof (inst.operands[0]));
1214760484Sobrien    }
12148218822Sdim  else
1214960484Sobrien    {
12150218822Sdim      inst.operands[1] = inst.operands[2];
12151218822Sdim      inst.operands[2] = inst.operands[0];
1215260484Sobrien    }
12153218822Sdim}
12154218822Sdim
12155218822Sdimstatic void
12156218822Sdimneon_compare (unsigned regtypes, unsigned immtypes, int invert)
12157218822Sdim{
12158218822Sdim  if (inst.operands[2].isreg)
1215960484Sobrien    {
12160218822Sdim      if (invert)
12161218822Sdim        neon_exchange_operands ();
12162218822Sdim      neon_dyadic_misc (NT_unsigned, regtypes, N_SIZ);
1216360484Sobrien    }
1216460484Sobrien  else
1216560484Sobrien    {
12166218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
12167218822Sdim      struct neon_type_el et = neon_check_type (2, rs,
12168218822Sdim        N_EQK | N_SIZ, immtypes | N_KEY);
1216960484Sobrien
12170218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
12171218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12172218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12173218822Sdim      inst.instruction |= LOW4 (inst.operands[1].reg);
12174218822Sdim      inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12175218822Sdim      inst.instruction |= neon_quad (rs) << 6;
12176218822Sdim      inst.instruction |= (et.type == NT_float) << 10;
12177218822Sdim      inst.instruction |= neon_logbits (et.size) << 18;
12178218822Sdim
12179218822Sdim      inst.instruction = neon_dp_fixup (inst.instruction);
1218060484Sobrien    }
12181218822Sdim}
1218260484Sobrien
12183218822Sdimstatic void
12184218822Sdimdo_neon_cmp (void)
12185218822Sdim{
12186218822Sdim  neon_compare (N_SUF_32, N_S8 | N_S16 | N_S32 | N_F32, FALSE);
1218760484Sobrien}
1218860484Sobrien
12189218822Sdimstatic void
12190218822Sdimdo_neon_cmp_inv (void)
12191218822Sdim{
12192218822Sdim  neon_compare (N_SUF_32, N_S8 | N_S16 | N_S32 | N_F32, TRUE);
12193218822Sdim}
1219489857Sobrien
12195218822Sdimstatic void
12196218822Sdimdo_neon_ceq (void)
12197218822Sdim{
12198218822Sdim  neon_compare (N_IF_32, N_IF_32, FALSE);
12199218822Sdim}
1220089857Sobrien
12201218822Sdim/* For multiply instructions, we have the possibility of 16-bit or 32-bit
12202218822Sdim   scalars, which are encoded in 5 bits, M : Rm.
12203218822Sdim   For 16-bit scalars, the register is encoded in Rm[2:0] and the index in
12204218822Sdim   M:Rm[3], and for 32-bit scalars, the register is encoded in Rm[3:0] and the
12205218822Sdim   index in M.  */
1220689857Sobrien
12207218822Sdimstatic unsigned
12208218822Sdimneon_scalar_for_mul (unsigned scalar, unsigned elsize)
1220989857Sobrien{
12210218822Sdim  unsigned regno = NEON_SCALAR_REG (scalar);
12211218822Sdim  unsigned elno = NEON_SCALAR_INDEX (scalar);
1221289857Sobrien
12213218822Sdim  switch (elsize)
1221489857Sobrien    {
12215218822Sdim    case 16:
12216218822Sdim      if (regno > 7 || elno > 3)
12217218822Sdim        goto bad_scalar;
12218218822Sdim      return regno | (elno << 3);
12219218822Sdim
12220218822Sdim    case 32:
12221218822Sdim      if (regno > 15 || elno > 1)
12222218822Sdim        goto bad_scalar;
12223218822Sdim      return regno | (elno << 4);
1222489857Sobrien
12225218822Sdim    default:
12226218822Sdim    bad_scalar:
12227218822Sdim      first_error (_("scalar out of range for multiply instruction"));
1222889857Sobrien    }
1222989857Sobrien
12230218822Sdim  return 0;
12231218822Sdim}
1223299461Sobrien
12233218822Sdim/* Encode multiply / multiply-accumulate scalar instructions.  */
12234104834Sobrien
12235218822Sdimstatic void
12236218822Sdimneon_mul_mac (struct neon_type_el et, int ubit)
12237218822Sdim{
12238218822Sdim  unsigned scalar;
12239218822Sdim
12240218822Sdim  /* Give a more helpful error message if we have an invalid type.  */
12241218822Sdim  if (et.type == NT_invtype)
12242218822Sdim    return;
12243218822Sdim
12244218822Sdim  scalar = neon_scalar_for_mul (inst.operands[2].reg, et.size);
12245218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12246218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12247218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
12248218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
12249218822Sdim  inst.instruction |= LOW4 (scalar);
12250218822Sdim  inst.instruction |= HI1 (scalar) << 5;
12251218822Sdim  inst.instruction |= (et.type == NT_float) << 8;
12252218822Sdim  inst.instruction |= neon_logbits (et.size) << 20;
12253218822Sdim  inst.instruction |= (ubit != 0) << 24;
12254218822Sdim
12255218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1225689857Sobrien}
1225789857Sobrien
12258218822Sdimstatic void
12259218822Sdimdo_neon_mac_maybe_scalar (void)
12260218822Sdim{
12261218822Sdim  if (try_vfp_nsyn (3, do_vfp_nsyn_mla_mls) == SUCCESS)
12262218822Sdim    return;
1226389857Sobrien
12264218822Sdim  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12265218822Sdim    return;
1226689857Sobrien
12267218822Sdim  if (inst.operands[2].isscalar)
12268218822Sdim    {
12269218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDS, NS_QQS, NS_NULL);
12270218822Sdim      struct neon_type_el et = neon_check_type (3, rs,
12271218822Sdim        N_EQK, N_EQK, N_I16 | N_I32 | N_F32 | N_KEY);
12272218822Sdim      inst.instruction = NEON_ENC_SCALAR (inst.instruction);
12273218822Sdim      neon_mul_mac (et, neon_quad (rs));
12274218822Sdim    }
12275218822Sdim  else
12276218822Sdim    {
12277218822Sdim      /* The "untyped" case can't happen.  Do this to stop the "U" bit being
12278218822Sdim	 affected if we specify unsigned args.  */
12279218822Sdim      neon_dyadic_misc (NT_untyped, N_IF_32, 0);
12280218822Sdim    }
12281218822Sdim}
12282218822Sdim
1228360484Sobrienstatic void
12284218822Sdimdo_neon_tst (void)
1228589857Sobrien{
12286218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
12287218822Sdim  struct neon_type_el et = neon_check_type (3, rs,
12288218822Sdim    N_EQK, N_EQK, N_8 | N_16 | N_32 | N_KEY);
12289218822Sdim  neon_three_same (neon_quad (rs), 0, et.size);
1229089857Sobrien}
1229189857Sobrien
12292218822Sdim/* VMUL with 3 registers allows the P8 type. The scalar version supports the
12293218822Sdim   same types as the MAC equivalents. The polynomial type for this instruction
12294218822Sdim   is encoded the same as the integer type.  */
12295218822Sdim
1229689857Sobrienstatic void
12297218822Sdimdo_neon_mul (void)
1229889857Sobrien{
12299218822Sdim  if (try_vfp_nsyn (3, do_vfp_nsyn_mul) == SUCCESS)
12300218822Sdim    return;
12301218822Sdim
12302218822Sdim  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12303218822Sdim    return;
12304218822Sdim
12305218822Sdim  if (inst.operands[2].isscalar)
12306218822Sdim    do_neon_mac_maybe_scalar ();
12307218822Sdim  else
12308218822Sdim    neon_dyadic_misc (NT_poly, N_I8 | N_I16 | N_I32 | N_F32 | N_P8, 0);
1230989857Sobrien}
1231089857Sobrien
1231189857Sobrienstatic void
12312218822Sdimdo_neon_qdmulh (void)
1231389857Sobrien{
12314218822Sdim  if (inst.operands[2].isscalar)
12315218822Sdim    {
12316218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDS, NS_QQS, NS_NULL);
12317218822Sdim      struct neon_type_el et = neon_check_type (3, rs,
12318218822Sdim        N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
12319218822Sdim      inst.instruction = NEON_ENC_SCALAR (inst.instruction);
12320218822Sdim      neon_mul_mac (et, neon_quad (rs));
12321218822Sdim    }
12322218822Sdim  else
12323218822Sdim    {
12324218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
12325218822Sdim      struct neon_type_el et = neon_check_type (3, rs,
12326218822Sdim        N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
12327218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12328218822Sdim      /* The U bit (rounding) comes from bit mask.  */
12329218822Sdim      neon_three_same (neon_quad (rs), 0, et.size);
12330218822Sdim    }
1233189857Sobrien}
1233289857Sobrien
1233389857Sobrienstatic void
12334218822Sdimdo_neon_fcmp_absolute (void)
1233589857Sobrien{
12336218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
12337218822Sdim  neon_check_type (3, rs, N_EQK, N_EQK, N_F32 | N_KEY);
12338218822Sdim  /* Size field comes from bit mask.  */
12339218822Sdim  neon_three_same (neon_quad (rs), 1, -1);
1234089857Sobrien}
1234189857Sobrien
1234289857Sobrienstatic void
12343218822Sdimdo_neon_fcmp_absolute_inv (void)
1234489857Sobrien{
12345218822Sdim  neon_exchange_operands ();
12346218822Sdim  do_neon_fcmp_absolute ();
1234789857Sobrien}
1234889857Sobrien
1234989857Sobrienstatic void
12350218822Sdimdo_neon_step (void)
1235189857Sobrien{
12352218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
12353218822Sdim  neon_check_type (3, rs, N_EQK, N_EQK, N_F32 | N_KEY);
12354218822Sdim  neon_three_same (neon_quad (rs), 0, -1);
1235589857Sobrien}
1235689857Sobrien
1235789857Sobrienstatic void
12358218822Sdimdo_neon_abs_neg (void)
1235989857Sobrien{
12360218822Sdim  enum neon_shape rs;
12361218822Sdim  struct neon_type_el et;
12362218822Sdim
12363218822Sdim  if (try_vfp_nsyn (2, do_vfp_nsyn_abs_neg) == SUCCESS)
12364218822Sdim    return;
12365218822Sdim
12366218822Sdim  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12367218822Sdim    return;
12368218822Sdim
12369218822Sdim  rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
12370218822Sdim  et = neon_check_type (2, rs, N_EQK, N_S8 | N_S16 | N_S32 | N_F32 | N_KEY);
12371218822Sdim
12372218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12373218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12374218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg);
12375218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12376218822Sdim  inst.instruction |= neon_quad (rs) << 6;
12377218822Sdim  inst.instruction |= (et.type == NT_float) << 10;
12378218822Sdim  inst.instruction |= neon_logbits (et.size) << 18;
12379218822Sdim
12380218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1238189857Sobrien}
1238289857Sobrien
1238389857Sobrienstatic void
12384218822Sdimdo_neon_sli (void)
1238589857Sobrien{
12386218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
12387218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
12388218822Sdim    N_EQK, N_8 | N_16 | N_32 | N_64 | N_KEY);
12389218822Sdim  int imm = inst.operands[2].imm;
12390218822Sdim  constraint (imm < 0 || (unsigned)imm >= et.size,
12391218822Sdim              _("immediate out of range for insert"));
12392218822Sdim  neon_imm_shift (FALSE, 0, neon_quad (rs), et, imm);
1239389857Sobrien}
1239489857Sobrien
1239589857Sobrienstatic void
12396218822Sdimdo_neon_sri (void)
1239789857Sobrien{
12398218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
12399218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
12400218822Sdim    N_EQK, N_8 | N_16 | N_32 | N_64 | N_KEY);
12401218822Sdim  int imm = inst.operands[2].imm;
12402218822Sdim  constraint (imm < 1 || (unsigned)imm > et.size,
12403218822Sdim              _("immediate out of range for insert"));
12404218822Sdim  neon_imm_shift (FALSE, 0, neon_quad (rs), et, et.size - imm);
1240589857Sobrien}
1240689857Sobrien
1240789857Sobrienstatic void
12408218822Sdimdo_neon_qshlu_imm (void)
1240989857Sobrien{
12410218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
12411218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
12412218822Sdim    N_EQK | N_UNS, N_S8 | N_S16 | N_S32 | N_S64 | N_KEY);
12413218822Sdim  int imm = inst.operands[2].imm;
12414218822Sdim  constraint (imm < 0 || (unsigned)imm >= et.size,
12415218822Sdim              _("immediate out of range for shift"));
12416218822Sdim  /* Only encodes the 'U present' variant of the instruction.
12417218822Sdim     In this case, signed types have OP (bit 8) set to 0.
12418218822Sdim     Unsigned types have OP set to 1.  */
12419218822Sdim  inst.instruction |= (et.type == NT_unsigned) << 8;
12420218822Sdim  /* The rest of the bits are the same as other immediate shifts.  */
12421218822Sdim  neon_imm_shift (FALSE, 0, neon_quad (rs), et, imm);
1242289857Sobrien}
1242389857Sobrien
1242489857Sobrienstatic void
12425218822Sdimdo_neon_qmovn (void)
1242689857Sobrien{
12427218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQ,
12428218822Sdim    N_EQK | N_HLF, N_SU_16_64 | N_KEY);
12429218822Sdim  /* Saturating move where operands can be signed or unsigned, and the
12430218822Sdim     destination has the same signedness.  */
12431218822Sdim  inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12432218822Sdim  if (et.type == NT_unsigned)
12433218822Sdim    inst.instruction |= 0xc0;
12434218822Sdim  else
12435218822Sdim    inst.instruction |= 0x80;
12436218822Sdim  neon_two_same (0, 1, et.size / 2);
1243789857Sobrien}
1243889857Sobrien
1243989857Sobrienstatic void
12440218822Sdimdo_neon_qmovun (void)
1244189857Sobrien{
12442218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQ,
12443218822Sdim    N_EQK | N_HLF | N_UNS, N_S16 | N_S32 | N_S64 | N_KEY);
12444218822Sdim  /* Saturating move with unsigned results. Operands must be signed.  */
12445218822Sdim  inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12446218822Sdim  neon_two_same (0, 1, et.size / 2);
1244789857Sobrien}
1244889857Sobrien
1244989857Sobrienstatic void
12450218822Sdimdo_neon_rshift_sat_narrow (void)
1245189857Sobrien{
12452218822Sdim  /* FIXME: Types for narrowing. If operands are signed, results can be signed
12453218822Sdim     or unsigned. If operands are unsigned, results must also be unsigned.  */
12454218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQI,
12455218822Sdim    N_EQK | N_HLF, N_SU_16_64 | N_KEY);
12456218822Sdim  int imm = inst.operands[2].imm;
12457218822Sdim  /* This gets the bounds check, size encoding and immediate bits calculation
12458218822Sdim     right.  */
12459218822Sdim  et.size /= 2;
12460218822Sdim
12461218822Sdim  /* VQ{R}SHRN.I<size> <Dd>, <Qm>, #0 is a synonym for
12462218822Sdim     VQMOVN.I<size> <Dd>, <Qm>.  */
12463218822Sdim  if (imm == 0)
12464218822Sdim    {
12465218822Sdim      inst.operands[2].present = 0;
12466218822Sdim      inst.instruction = N_MNEM_vqmovn;
12467218822Sdim      do_neon_qmovn ();
12468218822Sdim      return;
12469218822Sdim    }
12470218822Sdim
12471218822Sdim  constraint (imm < 1 || (unsigned)imm > et.size,
12472218822Sdim              _("immediate out of range"));
12473218822Sdim  neon_imm_shift (TRUE, et.type == NT_unsigned, 0, et, et.size - imm);
1247489857Sobrien}
1247589857Sobrien
1247689857Sobrienstatic void
12477218822Sdimdo_neon_rshift_sat_narrow_u (void)
1247889857Sobrien{
12479218822Sdim  /* FIXME: Types for narrowing. If operands are signed, results can be signed
12480218822Sdim     or unsigned. If operands are unsigned, results must also be unsigned.  */
12481218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQI,
12482218822Sdim    N_EQK | N_HLF | N_UNS, N_S16 | N_S32 | N_S64 | N_KEY);
12483218822Sdim  int imm = inst.operands[2].imm;
12484218822Sdim  /* This gets the bounds check, size encoding and immediate bits calculation
12485218822Sdim     right.  */
12486218822Sdim  et.size /= 2;
12487218822Sdim
12488218822Sdim  /* VQSHRUN.I<size> <Dd>, <Qm>, #0 is a synonym for
12489218822Sdim     VQMOVUN.I<size> <Dd>, <Qm>.  */
12490218822Sdim  if (imm == 0)
12491218822Sdim    {
12492218822Sdim      inst.operands[2].present = 0;
12493218822Sdim      inst.instruction = N_MNEM_vqmovun;
12494218822Sdim      do_neon_qmovun ();
12495218822Sdim      return;
12496218822Sdim    }
12497218822Sdim
12498218822Sdim  constraint (imm < 1 || (unsigned)imm > et.size,
12499218822Sdim              _("immediate out of range"));
12500218822Sdim  /* FIXME: The manual is kind of unclear about what value U should have in
12501218822Sdim     VQ{R}SHRUN instructions, but U=0, op=0 definitely encodes VRSHR, so it
12502218822Sdim     must be 1.  */
12503218822Sdim  neon_imm_shift (TRUE, 1, 0, et, et.size - imm);
1250489857Sobrien}
1250589857Sobrien
1250689857Sobrienstatic void
12507218822Sdimdo_neon_movn (void)
1250889857Sobrien{
12509218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQ,
12510218822Sdim    N_EQK | N_HLF, N_I16 | N_I32 | N_I64 | N_KEY);
12511218822Sdim  inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12512218822Sdim  neon_two_same (0, 1, et.size / 2);
1251389857Sobrien}
1251489857Sobrien
1251589857Sobrienstatic void
12516218822Sdimdo_neon_rshift_narrow (void)
1251789857Sobrien{
12518218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQI,
12519218822Sdim    N_EQK | N_HLF, N_I16 | N_I32 | N_I64 | N_KEY);
12520218822Sdim  int imm = inst.operands[2].imm;
12521218822Sdim  /* This gets the bounds check, size encoding and immediate bits calculation
12522218822Sdim     right.  */
12523218822Sdim  et.size /= 2;
12524218822Sdim
12525218822Sdim  /* If immediate is zero then we are a pseudo-instruction for
12526218822Sdim     VMOVN.I<size> <Dd>, <Qm>  */
12527218822Sdim  if (imm == 0)
12528218822Sdim    {
12529218822Sdim      inst.operands[2].present = 0;
12530218822Sdim      inst.instruction = N_MNEM_vmovn;
12531218822Sdim      do_neon_movn ();
12532218822Sdim      return;
12533218822Sdim    }
12534218822Sdim
12535218822Sdim  constraint (imm < 1 || (unsigned)imm > et.size,
12536218822Sdim              _("immediate out of range for narrowing operation"));
12537218822Sdim  neon_imm_shift (FALSE, 0, 0, et, et.size - imm);
1253889857Sobrien}
1253989857Sobrien
1254089857Sobrienstatic void
12541218822Sdimdo_neon_shll (void)
1254289857Sobrien{
12543218822Sdim  /* FIXME: Type checking when lengthening.  */
12544218822Sdim  struct neon_type_el et = neon_check_type (2, NS_QDI,
12545218822Sdim    N_EQK | N_DBL, N_I8 | N_I16 | N_I32 | N_KEY);
12546218822Sdim  unsigned imm = inst.operands[2].imm;
12547218822Sdim
12548218822Sdim  if (imm == et.size)
12549218822Sdim    {
12550218822Sdim      /* Maximum shift variant.  */
12551218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12552218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12553218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12554218822Sdim      inst.instruction |= LOW4 (inst.operands[1].reg);
12555218822Sdim      inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12556218822Sdim      inst.instruction |= neon_logbits (et.size) << 18;
12557218822Sdim
12558218822Sdim      inst.instruction = neon_dp_fixup (inst.instruction);
12559218822Sdim    }
12560218822Sdim  else
12561218822Sdim    {
12562218822Sdim      /* A more-specific type check for non-max versions.  */
12563218822Sdim      et = neon_check_type (2, NS_QDI,
12564218822Sdim        N_EQK | N_DBL, N_SU_32 | N_KEY);
12565218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
12566218822Sdim      neon_imm_shift (TRUE, et.type == NT_unsigned, 0, et, imm);
12567218822Sdim    }
1256889857Sobrien}
1256989857Sobrien
12570218822Sdim/* Check the various types for the VCVT instruction, and return which version
12571218822Sdim   the current instruction is.  */
12572218822Sdim
12573218822Sdimstatic int
12574218822Sdimneon_cvt_flavour (enum neon_shape rs)
12575218822Sdim{
12576218822Sdim#define CVT_VAR(C,X,Y)							\
12577218822Sdim  et = neon_check_type (2, rs, whole_reg | (X), whole_reg | (Y));	\
12578218822Sdim  if (et.type != NT_invtype)						\
12579218822Sdim    {									\
12580218822Sdim      inst.error = NULL;						\
12581218822Sdim      return (C);							\
12582218822Sdim    }
12583218822Sdim  struct neon_type_el et;
12584218822Sdim  unsigned whole_reg = (rs == NS_FFI || rs == NS_FD || rs == NS_DF
12585218822Sdim                        || rs == NS_FF) ? N_VFP : 0;
12586218822Sdim  /* The instruction versions which take an immediate take one register
12587218822Sdim     argument, which is extended to the width of the full register. Thus the
12588218822Sdim     "source" and "destination" registers must have the same width.  Hack that
12589218822Sdim     here by making the size equal to the key (wider, in this case) operand.  */
12590218822Sdim  unsigned key = (rs == NS_QQI || rs == NS_DDI || rs == NS_FFI) ? N_KEY : 0;
12591218822Sdim
12592218822Sdim  CVT_VAR (0, N_S32, N_F32);
12593218822Sdim  CVT_VAR (1, N_U32, N_F32);
12594218822Sdim  CVT_VAR (2, N_F32, N_S32);
12595218822Sdim  CVT_VAR (3, N_F32, N_U32);
12596218822Sdim
12597218822Sdim  whole_reg = N_VFP;
12598218822Sdim
12599218822Sdim  /* VFP instructions.  */
12600218822Sdim  CVT_VAR (4, N_F32, N_F64);
12601218822Sdim  CVT_VAR (5, N_F64, N_F32);
12602218822Sdim  CVT_VAR (6, N_S32, N_F64 | key);
12603218822Sdim  CVT_VAR (7, N_U32, N_F64 | key);
12604218822Sdim  CVT_VAR (8, N_F64 | key, N_S32);
12605218822Sdim  CVT_VAR (9, N_F64 | key, N_U32);
12606218822Sdim  /* VFP instructions with bitshift.  */
12607218822Sdim  CVT_VAR (10, N_F32 | key, N_S16);
12608218822Sdim  CVT_VAR (11, N_F32 | key, N_U16);
12609218822Sdim  CVT_VAR (12, N_F64 | key, N_S16);
12610218822Sdim  CVT_VAR (13, N_F64 | key, N_U16);
12611218822Sdim  CVT_VAR (14, N_S16, N_F32 | key);
12612218822Sdim  CVT_VAR (15, N_U16, N_F32 | key);
12613218822Sdim  CVT_VAR (16, N_S16, N_F64 | key);
12614218822Sdim  CVT_VAR (17, N_U16, N_F64 | key);
12615218822Sdim
12616218822Sdim  return -1;
12617218822Sdim#undef CVT_VAR
12618218822Sdim}
12619218822Sdim
12620218822Sdim/* Neon-syntax VFP conversions.  */
12621218822Sdim
1262289857Sobrienstatic void
12623218822Sdimdo_vfp_nsyn_cvt (enum neon_shape rs, int flavour)
1262489857Sobrien{
12625218822Sdim  const char *opname = 0;
12626218822Sdim
12627218822Sdim  if (rs == NS_DDI || rs == NS_QQI || rs == NS_FFI)
12628218822Sdim    {
12629218822Sdim      /* Conversions with immediate bitshift.  */
12630218822Sdim      const char *enc[] =
12631218822Sdim        {
12632218822Sdim          "ftosls",
12633218822Sdim          "ftouls",
12634218822Sdim          "fsltos",
12635218822Sdim          "fultos",
12636218822Sdim          NULL,
12637218822Sdim          NULL,
12638218822Sdim          "ftosld",
12639218822Sdim          "ftould",
12640218822Sdim          "fsltod",
12641218822Sdim          "fultod",
12642218822Sdim          "fshtos",
12643218822Sdim          "fuhtos",
12644218822Sdim          "fshtod",
12645218822Sdim          "fuhtod",
12646218822Sdim          "ftoshs",
12647218822Sdim          "ftouhs",
12648218822Sdim          "ftoshd",
12649218822Sdim          "ftouhd"
12650218822Sdim        };
12651218822Sdim
12652218822Sdim      if (flavour >= 0 && flavour < (int) ARRAY_SIZE (enc))
12653218822Sdim        {
12654218822Sdim          opname = enc[flavour];
12655218822Sdim          constraint (inst.operands[0].reg != inst.operands[1].reg,
12656218822Sdim                      _("operands 0 and 1 must be the same register"));
12657218822Sdim          inst.operands[1] = inst.operands[2];
12658218822Sdim          memset (&inst.operands[2], '\0', sizeof (inst.operands[2]));
12659218822Sdim        }
12660218822Sdim    }
12661218822Sdim  else
12662218822Sdim    {
12663218822Sdim      /* Conversions without bitshift.  */
12664218822Sdim      const char *enc[] =
12665218822Sdim        {
12666218822Sdim          "ftosis",
12667218822Sdim          "ftouis",
12668218822Sdim          "fsitos",
12669218822Sdim          "fuitos",
12670218822Sdim          "fcvtsd",
12671218822Sdim          "fcvtds",
12672218822Sdim          "ftosid",
12673218822Sdim          "ftouid",
12674218822Sdim          "fsitod",
12675218822Sdim          "fuitod"
12676218822Sdim        };
12677218822Sdim
12678218822Sdim      if (flavour >= 0 && flavour < (int) ARRAY_SIZE (enc))
12679218822Sdim        opname = enc[flavour];
12680218822Sdim    }
12681218822Sdim
12682218822Sdim  if (opname)
12683218822Sdim    do_vfp_nsyn_opcode (opname);
1268489857Sobrien}
1268589857Sobrien
1268689857Sobrienstatic void
12687218822Sdimdo_vfp_nsyn_cvtz (void)
1268889857Sobrien{
12689218822Sdim  enum neon_shape rs = neon_select_shape (NS_FF, NS_FD, NS_NULL);
12690218822Sdim  int flavour = neon_cvt_flavour (rs);
12691218822Sdim  const char *enc[] =
12692218822Sdim    {
12693218822Sdim      "ftosizs",
12694218822Sdim      "ftouizs",
12695218822Sdim      NULL,
12696218822Sdim      NULL,
12697218822Sdim      NULL,
12698218822Sdim      NULL,
12699218822Sdim      "ftosizd",
12700218822Sdim      "ftouizd"
12701218822Sdim    };
12702218822Sdim
12703218822Sdim  if (flavour >= 0 && flavour < (int) ARRAY_SIZE (enc) && enc[flavour])
12704218822Sdim    do_vfp_nsyn_opcode (enc[flavour]);
1270589857Sobrien}
1270689857Sobrien
1270789857Sobrienstatic void
12708218822Sdimdo_neon_cvt (void)
1270989857Sobrien{
12710218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_FFI, NS_DD, NS_QQ,
12711218822Sdim    NS_FD, NS_DF, NS_FF, NS_NULL);
12712218822Sdim  int flavour = neon_cvt_flavour (rs);
12713218822Sdim
12714218822Sdim  /* VFP rather than Neon conversions.  */
12715218822Sdim  if (flavour >= 4)
12716218822Sdim    {
12717218822Sdim      do_vfp_nsyn_cvt (rs, flavour);
12718218822Sdim      return;
12719218822Sdim    }
12720218822Sdim
12721218822Sdim  switch (rs)
12722218822Sdim    {
12723218822Sdim    case NS_DDI:
12724218822Sdim    case NS_QQI:
12725218822Sdim      {
12726218822Sdim        if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12727218822Sdim          return;
12728218822Sdim
12729218822Sdim        /* Fixed-point conversion with #0 immediate is encoded as an
12730218822Sdim           integer conversion.  */
12731218822Sdim        if (inst.operands[2].present && inst.operands[2].imm == 0)
12732218822Sdim          goto int_encode;
12733218822Sdim        unsigned immbits = 32 - inst.operands[2].imm;
12734218822Sdim        unsigned enctab[] = { 0x0000100, 0x1000100, 0x0, 0x1000000 };
12735218822Sdim        inst.instruction = NEON_ENC_IMMED (inst.instruction);
12736218822Sdim        if (flavour != -1)
12737218822Sdim          inst.instruction |= enctab[flavour];
12738218822Sdim        inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12739218822Sdim        inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12740218822Sdim        inst.instruction |= LOW4 (inst.operands[1].reg);
12741218822Sdim        inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12742218822Sdim        inst.instruction |= neon_quad (rs) << 6;
12743218822Sdim        inst.instruction |= 1 << 21;
12744218822Sdim        inst.instruction |= immbits << 16;
12745218822Sdim
12746218822Sdim        inst.instruction = neon_dp_fixup (inst.instruction);
12747218822Sdim      }
12748218822Sdim      break;
12749218822Sdim
12750218822Sdim    case NS_DD:
12751218822Sdim    case NS_QQ:
12752218822Sdim    int_encode:
12753218822Sdim      {
12754218822Sdim        unsigned enctab[] = { 0x100, 0x180, 0x0, 0x080 };
12755218822Sdim
12756218822Sdim        inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12757218822Sdim
12758218822Sdim        if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12759218822Sdim          return;
12760218822Sdim
12761218822Sdim        if (flavour != -1)
12762218822Sdim          inst.instruction |= enctab[flavour];
12763218822Sdim
12764218822Sdim        inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12765218822Sdim        inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12766218822Sdim        inst.instruction |= LOW4 (inst.operands[1].reg);
12767218822Sdim        inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12768218822Sdim        inst.instruction |= neon_quad (rs) << 6;
12769218822Sdim        inst.instruction |= 2 << 18;
12770218822Sdim
12771218822Sdim        inst.instruction = neon_dp_fixup (inst.instruction);
12772218822Sdim      }
12773218822Sdim    break;
12774218822Sdim
12775218822Sdim    default:
12776218822Sdim      /* Some VFP conversions go here (s32 <-> f32, u32 <-> f32).  */
12777218822Sdim      do_vfp_nsyn_cvt (rs, flavour);
12778218822Sdim    }
1277989857Sobrien}
1278089857Sobrien
1278189857Sobrienstatic void
12782218822Sdimneon_move_immediate (void)
1278389857Sobrien{
12784218822Sdim  enum neon_shape rs = neon_select_shape (NS_DI, NS_QI, NS_NULL);
12785218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
12786218822Sdim    N_I8 | N_I16 | N_I32 | N_I64 | N_F32 | N_KEY, N_EQK);
12787218822Sdim  unsigned immlo, immhi = 0, immbits;
12788218822Sdim  int op, cmode, float_p;
12789218822Sdim
12790218822Sdim  constraint (et.type == NT_invtype,
12791218822Sdim              _("operand size must be specified for immediate VMOV"));
12792218822Sdim
12793218822Sdim  /* We start out as an MVN instruction if OP = 1, MOV otherwise.  */
12794218822Sdim  op = (inst.instruction & (1 << 5)) != 0;
12795218822Sdim
12796218822Sdim  immlo = inst.operands[1].imm;
12797218822Sdim  if (inst.operands[1].regisimm)
12798218822Sdim    immhi = inst.operands[1].reg;
12799218822Sdim
12800218822Sdim  constraint (et.size < 32 && (immlo & ~((1 << et.size) - 1)) != 0,
12801218822Sdim              _("immediate has bits set outside the operand size"));
12802218822Sdim
12803218822Sdim  float_p = inst.operands[1].immisfloat;
12804218822Sdim
12805218822Sdim  if ((cmode = neon_cmode_for_move_imm (immlo, immhi, float_p, &immbits, &op,
12806218822Sdim                                        et.size, et.type)) == FAIL)
12807218822Sdim    {
12808218822Sdim      /* Invert relevant bits only.  */
12809218822Sdim      neon_invert_size (&immlo, &immhi, et.size);
12810218822Sdim      /* Flip from VMOV/VMVN to VMVN/VMOV. Some immediate types are unavailable
12811218822Sdim         with one or the other; those cases are caught by
12812218822Sdim         neon_cmode_for_move_imm.  */
12813218822Sdim      op = !op;
12814218822Sdim      if ((cmode = neon_cmode_for_move_imm (immlo, immhi, float_p, &immbits,
12815218822Sdim					    &op, et.size, et.type)) == FAIL)
12816218822Sdim        {
12817218822Sdim          first_error (_("immediate out of range"));
12818218822Sdim          return;
12819218822Sdim        }
12820218822Sdim    }
12821218822Sdim
12822218822Sdim  inst.instruction &= ~(1 << 5);
12823218822Sdim  inst.instruction |= op << 5;
12824218822Sdim
12825218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12826218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12827218822Sdim  inst.instruction |= neon_quad (rs) << 6;
12828218822Sdim  inst.instruction |= cmode << 8;
12829218822Sdim
12830218822Sdim  neon_write_immbits (immbits);
1283189857Sobrien}
1283289857Sobrien
1283389857Sobrienstatic void
12834218822Sdimdo_neon_mvn (void)
1283589857Sobrien{
12836218822Sdim  if (inst.operands[1].isreg)
12837218822Sdim    {
12838218822Sdim      enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
12839218822Sdim
12840218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12841218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12842218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12843218822Sdim      inst.instruction |= LOW4 (inst.operands[1].reg);
12844218822Sdim      inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12845218822Sdim      inst.instruction |= neon_quad (rs) << 6;
12846218822Sdim    }
12847218822Sdim  else
12848218822Sdim    {
12849218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
12850218822Sdim      neon_move_immediate ();
12851218822Sdim    }
12852218822Sdim
12853218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1285489857Sobrien}
1285589857Sobrien
12856218822Sdim/* Encode instructions of form:
12857218822Sdim
12858218822Sdim  |28/24|23|22|21 20|19 16|15 12|11    8|7|6|5|4|3  0|
12859218822Sdim  |  U  |x |D |size | Rn  | Rd  |x x x x|N|x|M|x| Rm |
12860218822Sdim
12861218822Sdim*/
12862218822Sdim
1286389857Sobrienstatic void
12864218822Sdimneon_mixed_length (struct neon_type_el et, unsigned size)
1286589857Sobrien{
12866218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12867218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12868218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
12869218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
12870218822Sdim  inst.instruction |= LOW4 (inst.operands[2].reg);
12871218822Sdim  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
12872218822Sdim  inst.instruction |= (et.type == NT_unsigned) << 24;
12873218822Sdim  inst.instruction |= neon_logbits (size) << 20;
12874218822Sdim
12875218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1287689857Sobrien}
1287789857Sobrien
1287889857Sobrienstatic void
12879218822Sdimdo_neon_dyadic_long (void)
1288089857Sobrien{
12881218822Sdim  /* FIXME: Type checking for lengthening op.  */
12882218822Sdim  struct neon_type_el et = neon_check_type (3, NS_QDD,
12883218822Sdim    N_EQK | N_DBL, N_EQK, N_SU_32 | N_KEY);
12884218822Sdim  neon_mixed_length (et, et.size);
1288589857Sobrien}
1288689857Sobrien
1288789857Sobrienstatic void
12888218822Sdimdo_neon_abal (void)
1288989857Sobrien{
12890218822Sdim  struct neon_type_el et = neon_check_type (3, NS_QDD,
12891218822Sdim    N_EQK | N_INT | N_DBL, N_EQK, N_SU_32 | N_KEY);
12892218822Sdim  neon_mixed_length (et, et.size);
1289389857Sobrien}
1289489857Sobrien
1289589857Sobrienstatic void
12896218822Sdimneon_mac_reg_scalar_long (unsigned regtypes, unsigned scalartypes)
1289789857Sobrien{
12898218822Sdim  if (inst.operands[2].isscalar)
12899218822Sdim    {
12900218822Sdim      struct neon_type_el et = neon_check_type (3, NS_QDS,
12901218822Sdim        N_EQK | N_DBL, N_EQK, regtypes | N_KEY);
12902218822Sdim      inst.instruction = NEON_ENC_SCALAR (inst.instruction);
12903218822Sdim      neon_mul_mac (et, et.type == NT_unsigned);
12904218822Sdim    }
12905218822Sdim  else
12906218822Sdim    {
12907218822Sdim      struct neon_type_el et = neon_check_type (3, NS_QDD,
12908218822Sdim        N_EQK | N_DBL, N_EQK, scalartypes | N_KEY);
12909218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12910218822Sdim      neon_mixed_length (et, et.size);
12911218822Sdim    }
1291289857Sobrien}
1291389857Sobrien
1291489857Sobrienstatic void
12915218822Sdimdo_neon_mac_maybe_scalar_long (void)
1291689857Sobrien{
12917218822Sdim  neon_mac_reg_scalar_long (N_S16 | N_S32 | N_U16 | N_U32, N_SU_32);
1291889857Sobrien}
1291989857Sobrien
1292089857Sobrienstatic void
12921218822Sdimdo_neon_dyadic_wide (void)
1292289857Sobrien{
12923218822Sdim  struct neon_type_el et = neon_check_type (3, NS_QQD,
12924218822Sdim    N_EQK | N_DBL, N_EQK | N_DBL, N_SU_32 | N_KEY);
12925218822Sdim  neon_mixed_length (et, et.size);
1292689857Sobrien}
1292789857Sobrien
1292889857Sobrienstatic void
12929218822Sdimdo_neon_dyadic_narrow (void)
1293089857Sobrien{
12931218822Sdim  struct neon_type_el et = neon_check_type (3, NS_QDD,
12932218822Sdim    N_EQK | N_DBL, N_EQK, N_I16 | N_I32 | N_I64 | N_KEY);
12933218822Sdim  /* Operand sign is unimportant, and the U bit is part of the opcode,
12934218822Sdim     so force the operand type to integer.  */
12935218822Sdim  et.type = NT_integer;
12936218822Sdim  neon_mixed_length (et, et.size / 2);
1293789857Sobrien}
1293889857Sobrien
1293989857Sobrienstatic void
12940218822Sdimdo_neon_mul_sat_scalar_long (void)
1294189857Sobrien{
12942218822Sdim  neon_mac_reg_scalar_long (N_S16 | N_S32, N_S16 | N_S32);
1294389857Sobrien}
1294489857Sobrien
1294589857Sobrienstatic void
12946218822Sdimdo_neon_vmull (void)
1294789857Sobrien{
12948218822Sdim  if (inst.operands[2].isscalar)
12949218822Sdim    do_neon_mac_maybe_scalar_long ();
12950218822Sdim  else
12951218822Sdim    {
12952218822Sdim      struct neon_type_el et = neon_check_type (3, NS_QDD,
12953218822Sdim        N_EQK | N_DBL, N_EQK, N_SU_32 | N_P8 | N_KEY);
12954218822Sdim      if (et.type == NT_poly)
12955218822Sdim        inst.instruction = NEON_ENC_POLY (inst.instruction);
12956218822Sdim      else
12957218822Sdim        inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12958218822Sdim      /* For polynomial encoding, size field must be 0b00 and the U bit must be
12959218822Sdim         zero. Should be OK as-is.  */
12960218822Sdim      neon_mixed_length (et, et.size);
12961218822Sdim    }
1296289857Sobrien}
1296389857Sobrien
1296489857Sobrienstatic void
12965218822Sdimdo_neon_ext (void)
1296689857Sobrien{
12967218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDDI, NS_QQQI, NS_NULL);
12968218822Sdim  struct neon_type_el et = neon_check_type (3, rs,
12969218822Sdim    N_EQK, N_EQK, N_8 | N_16 | N_32 | N_64 | N_KEY);
12970218822Sdim  unsigned imm = (inst.operands[3].imm * et.size) / 8;
12971218822Sdim  constraint (imm >= (neon_quad (rs) ? 16 : 8), _("shift out of range"));
12972218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12973218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12974218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
12975218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
12976218822Sdim  inst.instruction |= LOW4 (inst.operands[2].reg);
12977218822Sdim  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
12978218822Sdim  inst.instruction |= neon_quad (rs) << 6;
12979218822Sdim  inst.instruction |= imm << 8;
12980218822Sdim
12981218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1298289857Sobrien}
1298389857Sobrien
1298489857Sobrienstatic void
12985218822Sdimdo_neon_rev (void)
1298689857Sobrien{
12987218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
12988218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
12989218822Sdim    N_EQK, N_8 | N_16 | N_32 | N_KEY);
12990218822Sdim  unsigned op = (inst.instruction >> 7) & 3;
12991218822Sdim  /* N (width of reversed regions) is encoded as part of the bitmask. We
12992218822Sdim     extract it here to check the elements to be reversed are smaller.
12993218822Sdim     Otherwise we'd get a reserved instruction.  */
12994218822Sdim  unsigned elsize = (op == 2) ? 16 : (op == 1) ? 32 : (op == 0) ? 64 : 0;
12995218822Sdim  assert (elsize != 0);
12996218822Sdim  constraint (et.size >= elsize,
12997218822Sdim              _("elements must be smaller than reversal region"));
12998218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1299989857Sobrien}
1300089857Sobrien
1300189857Sobrienstatic void
13002218822Sdimdo_neon_dup (void)
1300389857Sobrien{
13004218822Sdim  if (inst.operands[1].isscalar)
13005218822Sdim    {
13006218822Sdim      enum neon_shape rs = neon_select_shape (NS_DS, NS_QS, NS_NULL);
13007218822Sdim      struct neon_type_el et = neon_check_type (2, rs,
13008218822Sdim        N_EQK, N_8 | N_16 | N_32 | N_KEY);
13009218822Sdim      unsigned sizebits = et.size >> 3;
13010218822Sdim      unsigned dm = NEON_SCALAR_REG (inst.operands[1].reg);
13011218822Sdim      int logsize = neon_logbits (et.size);
13012218822Sdim      unsigned x = NEON_SCALAR_INDEX (inst.operands[1].reg) << logsize;
13013218822Sdim
13014218822Sdim      if (vfp_or_neon_is_neon (NEON_CHECK_CC) == FAIL)
13015218822Sdim        return;
13016218822Sdim
13017218822Sdim      inst.instruction = NEON_ENC_SCALAR (inst.instruction);
13018218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
13019218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
13020218822Sdim      inst.instruction |= LOW4 (dm);
13021218822Sdim      inst.instruction |= HI1 (dm) << 5;
13022218822Sdim      inst.instruction |= neon_quad (rs) << 6;
13023218822Sdim      inst.instruction |= x << 17;
13024218822Sdim      inst.instruction |= sizebits << 16;
13025218822Sdim
13026218822Sdim      inst.instruction = neon_dp_fixup (inst.instruction);
13027218822Sdim    }
13028218822Sdim  else
13029218822Sdim    {
13030218822Sdim      enum neon_shape rs = neon_select_shape (NS_DR, NS_QR, NS_NULL);
13031218822Sdim      struct neon_type_el et = neon_check_type (2, rs,
13032218822Sdim        N_8 | N_16 | N_32 | N_KEY, N_EQK);
13033218822Sdim      /* Duplicate ARM register to lanes of vector.  */
13034218822Sdim      inst.instruction = NEON_ENC_ARMREG (inst.instruction);
13035218822Sdim      switch (et.size)
13036218822Sdim        {
13037218822Sdim        case 8:  inst.instruction |= 0x400000; break;
13038218822Sdim        case 16: inst.instruction |= 0x000020; break;
13039218822Sdim        case 32: inst.instruction |= 0x000000; break;
13040218822Sdim        default: break;
13041218822Sdim        }
13042218822Sdim      inst.instruction |= LOW4 (inst.operands[1].reg) << 12;
13043218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 16;
13044218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 7;
13045218822Sdim      inst.instruction |= neon_quad (rs) << 21;
13046218822Sdim      /* The encoding for this instruction is identical for the ARM and Thumb
13047218822Sdim         variants, except for the condition field.  */
13048218822Sdim      do_vfp_cond_or_thumb ();
13049218822Sdim    }
1305089857Sobrien}
1305189857Sobrien
13052218822Sdim/* VMOV has particularly many variations. It can be one of:
13053218822Sdim     0. VMOV<c><q> <Qd>, <Qm>
13054218822Sdim     1. VMOV<c><q> <Dd>, <Dm>
13055218822Sdim   (Register operations, which are VORR with Rm = Rn.)
13056218822Sdim     2. VMOV<c><q>.<dt> <Qd>, #<imm>
13057218822Sdim     3. VMOV<c><q>.<dt> <Dd>, #<imm>
13058218822Sdim   (Immediate loads.)
13059218822Sdim     4. VMOV<c><q>.<size> <Dn[x]>, <Rd>
13060218822Sdim   (ARM register to scalar.)
13061218822Sdim     5. VMOV<c><q> <Dm>, <Rd>, <Rn>
13062218822Sdim   (Two ARM registers to vector.)
13063218822Sdim     6. VMOV<c><q>.<dt> <Rd>, <Dn[x]>
13064218822Sdim   (Scalar to ARM register.)
13065218822Sdim     7. VMOV<c><q> <Rd>, <Rn>, <Dm>
13066218822Sdim   (Vector to two ARM registers.)
13067218822Sdim     8. VMOV.F32 <Sd>, <Sm>
13068218822Sdim     9. VMOV.F64 <Dd>, <Dm>
13069218822Sdim   (VFP register moves.)
13070218822Sdim    10. VMOV.F32 <Sd>, #imm
13071218822Sdim    11. VMOV.F64 <Dd>, #imm
13072218822Sdim   (VFP float immediate load.)
13073218822Sdim    12. VMOV <Rd>, <Sm>
13074218822Sdim   (VFP single to ARM reg.)
13075218822Sdim    13. VMOV <Sd>, <Rm>
13076218822Sdim   (ARM reg to VFP single.)
13077218822Sdim    14. VMOV <Rd>, <Re>, <Sn>, <Sm>
13078218822Sdim   (Two ARM regs to two VFP singles.)
13079218822Sdim    15. VMOV <Sd>, <Se>, <Rn>, <Rm>
13080218822Sdim   (Two VFP singles to two ARM regs.)
13081218822Sdim
13082218822Sdim   These cases can be disambiguated using neon_select_shape, except cases 1/9
13083218822Sdim   and 3/11 which depend on the operand type too.
13084218822Sdim
13085218822Sdim   All the encoded bits are hardcoded by this function.
13086218822Sdim
13087218822Sdim   Cases 4, 6 may be used with VFPv1 and above (only 32-bit transfers!).
13088218822Sdim   Cases 5, 7 may be used with VFPv2 and above.
13089218822Sdim
13090218822Sdim   FIXME: Some of the checking may be a bit sloppy (in a couple of cases you
13091218822Sdim   can specify a type where it doesn't make sense to, and is ignored).
13092218822Sdim*/
13093218822Sdim
1309489857Sobrienstatic void
13095218822Sdimdo_neon_mov (void)
1309689857Sobrien{
13097218822Sdim  enum neon_shape rs = neon_select_shape (NS_RRFF, NS_FFRR, NS_DRR, NS_RRD,
13098218822Sdim    NS_QQ, NS_DD, NS_QI, NS_DI, NS_SR, NS_RS, NS_FF, NS_FI, NS_RF, NS_FR,
13099218822Sdim    NS_NULL);
13100218822Sdim  struct neon_type_el et;
13101218822Sdim  const char *ldconst = 0;
1310289857Sobrien
13103218822Sdim  switch (rs)
1310489857Sobrien    {
13105218822Sdim    case NS_DD:  /* case 1/9.  */
13106218822Sdim      et = neon_check_type (2, rs, N_EQK, N_F64 | N_KEY);
13107218822Sdim      /* It is not an error here if no type is given.  */
13108218822Sdim      inst.error = NULL;
13109218822Sdim      if (et.type == NT_float && et.size == 64)
13110218822Sdim        {
13111218822Sdim          do_vfp_nsyn_opcode ("fcpyd");
13112218822Sdim          break;
13113218822Sdim        }
13114218822Sdim      /* fall through.  */
1311589857Sobrien
13116218822Sdim    case NS_QQ:  /* case 0/1.  */
13117218822Sdim      {
13118218822Sdim        if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
13119218822Sdim          return;
13120218822Sdim        /* The architecture manual I have doesn't explicitly state which
13121218822Sdim           value the U bit should have for register->register moves, but
13122218822Sdim           the equivalent VORR instruction has U = 0, so do that.  */
13123218822Sdim        inst.instruction = 0x0200110;
13124218822Sdim        inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
13125218822Sdim        inst.instruction |= HI1 (inst.operands[0].reg) << 22;
13126218822Sdim        inst.instruction |= LOW4 (inst.operands[1].reg);
13127218822Sdim        inst.instruction |= HI1 (inst.operands[1].reg) << 5;
13128218822Sdim        inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
13129218822Sdim        inst.instruction |= HI1 (inst.operands[1].reg) << 7;
13130218822Sdim        inst.instruction |= neon_quad (rs) << 6;
13131218822Sdim
13132218822Sdim        inst.instruction = neon_dp_fixup (inst.instruction);
13133218822Sdim      }
13134218822Sdim      break;
13135218822Sdim
13136218822Sdim    case NS_DI:  /* case 3/11.  */
13137218822Sdim      et = neon_check_type (2, rs, N_EQK, N_F64 | N_KEY);
13138218822Sdim      inst.error = NULL;
13139218822Sdim      if (et.type == NT_float && et.size == 64)
13140218822Sdim        {
13141218822Sdim          /* case 11 (fconstd).  */
13142218822Sdim          ldconst = "fconstd";
13143218822Sdim          goto encode_fconstd;
13144218822Sdim        }
13145218822Sdim      /* fall through.  */
13146218822Sdim
13147218822Sdim    case NS_QI:  /* case 2/3.  */
13148218822Sdim      if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
13149218822Sdim        return;
13150218822Sdim      inst.instruction = 0x0800010;
13151218822Sdim      neon_move_immediate ();
13152218822Sdim      inst.instruction = neon_dp_fixup (inst.instruction);
13153218822Sdim      break;
13154218822Sdim
13155218822Sdim    case NS_SR:  /* case 4.  */
13156218822Sdim      {
13157218822Sdim        unsigned bcdebits = 0;
13158218822Sdim        struct neon_type_el et = neon_check_type (2, NS_NULL,
13159218822Sdim          N_8 | N_16 | N_32 | N_KEY, N_EQK);
13160218822Sdim        int logsize = neon_logbits (et.size);
13161218822Sdim        unsigned dn = NEON_SCALAR_REG (inst.operands[0].reg);
13162218822Sdim        unsigned x = NEON_SCALAR_INDEX (inst.operands[0].reg);
13163218822Sdim
13164218822Sdim        constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v1),
13165218822Sdim                    _(BAD_FPU));
13166218822Sdim        constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1)
13167218822Sdim                    && et.size != 32, _(BAD_FPU));
13168218822Sdim        constraint (et.type == NT_invtype, _("bad type for scalar"));
13169218822Sdim        constraint (x >= 64 / et.size, _("scalar index out of range"));
13170218822Sdim
13171218822Sdim        switch (et.size)
13172218822Sdim          {
13173218822Sdim          case 8:  bcdebits = 0x8; break;
13174218822Sdim          case 16: bcdebits = 0x1; break;
13175218822Sdim          case 32: bcdebits = 0x0; break;
13176218822Sdim          default: ;
13177218822Sdim          }
13178218822Sdim
13179218822Sdim        bcdebits |= x << logsize;
13180218822Sdim
13181218822Sdim        inst.instruction = 0xe000b10;
13182218822Sdim        do_vfp_cond_or_thumb ();
13183218822Sdim        inst.instruction |= LOW4 (dn) << 16;
13184218822Sdim        inst.instruction |= HI1 (dn) << 7;
13185218822Sdim        inst.instruction |= inst.operands[1].reg << 12;
13186218822Sdim        inst.instruction |= (bcdebits & 3) << 5;
13187218822Sdim        inst.instruction |= (bcdebits >> 2) << 21;
13188218822Sdim      }
13189218822Sdim      break;
13190218822Sdim
13191218822Sdim    case NS_DRR:  /* case 5 (fmdrr).  */
13192218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v2),
13193218822Sdim                  _(BAD_FPU));
13194218822Sdim
13195218822Sdim      inst.instruction = 0xc400b10;
13196218822Sdim      do_vfp_cond_or_thumb ();
13197218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg);
13198218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 5;
13199218822Sdim      inst.instruction |= inst.operands[1].reg << 12;
13200218822Sdim      inst.instruction |= inst.operands[2].reg << 16;
13201218822Sdim      break;
13202218822Sdim
13203218822Sdim    case NS_RS:  /* case 6.  */
13204218822Sdim      {
13205218822Sdim        struct neon_type_el et = neon_check_type (2, NS_NULL,
13206218822Sdim          N_EQK, N_S8 | N_S16 | N_U8 | N_U16 | N_32 | N_KEY);
13207218822Sdim        unsigned logsize = neon_logbits (et.size);
13208218822Sdim        unsigned dn = NEON_SCALAR_REG (inst.operands[1].reg);
13209218822Sdim        unsigned x = NEON_SCALAR_INDEX (inst.operands[1].reg);
13210218822Sdim        unsigned abcdebits = 0;
13211218822Sdim
13212218822Sdim        constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v1),
13213218822Sdim                    _(BAD_FPU));
13214218822Sdim        constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1)
13215218822Sdim                    && et.size != 32, _(BAD_FPU));
13216218822Sdim        constraint (et.type == NT_invtype, _("bad type for scalar"));
13217218822Sdim        constraint (x >= 64 / et.size, _("scalar index out of range"));
13218218822Sdim
13219218822Sdim        switch (et.size)
13220218822Sdim          {
13221218822Sdim          case 8:  abcdebits = (et.type == NT_signed) ? 0x08 : 0x18; break;
13222218822Sdim          case 16: abcdebits = (et.type == NT_signed) ? 0x01 : 0x11; break;
13223218822Sdim          case 32: abcdebits = 0x00; break;
13224218822Sdim          default: ;
13225218822Sdim          }
13226218822Sdim
13227218822Sdim        abcdebits |= x << logsize;
13228218822Sdim        inst.instruction = 0xe100b10;
13229218822Sdim        do_vfp_cond_or_thumb ();
13230218822Sdim        inst.instruction |= LOW4 (dn) << 16;
13231218822Sdim        inst.instruction |= HI1 (dn) << 7;
13232218822Sdim        inst.instruction |= inst.operands[0].reg << 12;
13233218822Sdim        inst.instruction |= (abcdebits & 3) << 5;
13234218822Sdim        inst.instruction |= (abcdebits >> 2) << 21;
13235218822Sdim      }
13236218822Sdim      break;
13237218822Sdim
13238218822Sdim    case NS_RRD:  /* case 7 (fmrrd).  */
13239218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v2),
13240218822Sdim                  _(BAD_FPU));
13241218822Sdim
13242218822Sdim      inst.instruction = 0xc500b10;
13243218822Sdim      do_vfp_cond_or_thumb ();
13244218822Sdim      inst.instruction |= inst.operands[0].reg << 12;
13245218822Sdim      inst.instruction |= inst.operands[1].reg << 16;
13246218822Sdim      inst.instruction |= LOW4 (inst.operands[2].reg);
13247218822Sdim      inst.instruction |= HI1 (inst.operands[2].reg) << 5;
13248218822Sdim      break;
13249218822Sdim
13250218822Sdim    case NS_FF:  /* case 8 (fcpys).  */
13251218822Sdim      do_vfp_nsyn_opcode ("fcpys");
13252218822Sdim      break;
13253218822Sdim
13254218822Sdim    case NS_FI:  /* case 10 (fconsts).  */
13255218822Sdim      ldconst = "fconsts";
13256218822Sdim      encode_fconstd:
13257218822Sdim      if (is_quarter_float (inst.operands[1].imm))
13258218822Sdim        {
13259218822Sdim          inst.operands[1].imm = neon_qfloat_bits (inst.operands[1].imm);
13260218822Sdim          do_vfp_nsyn_opcode (ldconst);
13261218822Sdim        }
13262218822Sdim      else
13263218822Sdim        first_error (_("immediate out of range"));
13264218822Sdim      break;
13265218822Sdim
13266218822Sdim    case NS_RF:  /* case 12 (fmrs).  */
13267218822Sdim      do_vfp_nsyn_opcode ("fmrs");
13268218822Sdim      break;
13269218822Sdim
13270218822Sdim    case NS_FR:  /* case 13 (fmsr).  */
13271218822Sdim      do_vfp_nsyn_opcode ("fmsr");
13272218822Sdim      break;
13273218822Sdim
13274218822Sdim    /* The encoders for the fmrrs and fmsrr instructions expect three operands
13275218822Sdim       (one of which is a list), but we have parsed four.  Do some fiddling to
13276218822Sdim       make the operands what do_vfp_reg2_from_sp2 and do_vfp_sp2_from_reg2
13277218822Sdim       expect.  */
13278218822Sdim    case NS_RRFF:  /* case 14 (fmrrs).  */
13279218822Sdim      constraint (inst.operands[3].reg != inst.operands[2].reg + 1,
13280218822Sdim                  _("VFP registers must be adjacent"));
13281218822Sdim      inst.operands[2].imm = 2;
13282218822Sdim      memset (&inst.operands[3], '\0', sizeof (inst.operands[3]));
13283218822Sdim      do_vfp_nsyn_opcode ("fmrrs");
13284218822Sdim      break;
13285218822Sdim
13286218822Sdim    case NS_FFRR:  /* case 15 (fmsrr).  */
13287218822Sdim      constraint (inst.operands[1].reg != inst.operands[0].reg + 1,
13288218822Sdim                  _("VFP registers must be adjacent"));
13289218822Sdim      inst.operands[1] = inst.operands[2];
13290218822Sdim      inst.operands[2] = inst.operands[3];
13291218822Sdim      inst.operands[0].imm = 2;
13292218822Sdim      memset (&inst.operands[3], '\0', sizeof (inst.operands[3]));
13293218822Sdim      do_vfp_nsyn_opcode ("fmsrr");
13294218822Sdim      break;
13295218822Sdim
13296218822Sdim    default:
13297218822Sdim      abort ();
13298218822Sdim    }
13299218822Sdim}
13300218822Sdim
13301218822Sdimstatic void
13302218822Sdimdo_neon_rshift_round_imm (void)
13303218822Sdim{
13304218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
13305218822Sdim  struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_SU_ALL | N_KEY);
13306218822Sdim  int imm = inst.operands[2].imm;
13307218822Sdim
13308218822Sdim  /* imm == 0 case is encoded as VMOV for V{R}SHR.  */
13309218822Sdim  if (imm == 0)
13310218822Sdim    {
13311218822Sdim      inst.operands[2].present = 0;
13312218822Sdim      do_neon_mov ();
1331389857Sobrien      return;
1331489857Sobrien    }
1331589857Sobrien
13316218822Sdim  constraint (imm < 1 || (unsigned)imm > et.size,
13317218822Sdim              _("immediate out of range for shift"));
13318218822Sdim  neon_imm_shift (TRUE, et.type == NT_unsigned, neon_quad (rs), et,
13319218822Sdim                  et.size - imm);
1332089857Sobrien}
1332189857Sobrien
1332289857Sobrienstatic void
13323218822Sdimdo_neon_movl (void)
1332489857Sobrien{
13325218822Sdim  struct neon_type_el et = neon_check_type (2, NS_QD,
13326218822Sdim    N_EQK | N_DBL, N_SU_32 | N_KEY);
13327218822Sdim  unsigned sizebits = et.size >> 3;
13328218822Sdim  inst.instruction |= sizebits << 19;
13329218822Sdim  neon_two_same (0, et.type == NT_unsigned, -1);
13330218822Sdim}
1333189857Sobrien
13332218822Sdimstatic void
13333218822Sdimdo_neon_trn (void)
13334218822Sdim{
13335218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13336218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13337218822Sdim    N_EQK, N_8 | N_16 | N_32 | N_KEY);
13338218822Sdim  inst.instruction = NEON_ENC_INTEGER (inst.instruction);
13339218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
13340218822Sdim}
13341218822Sdim
13342218822Sdimstatic void
13343218822Sdimdo_neon_zip_uzp (void)
13344218822Sdim{
13345218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13346218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13347218822Sdim    N_EQK, N_8 | N_16 | N_32 | N_KEY);
13348218822Sdim  if (rs == NS_DD && et.size == 32)
1334989857Sobrien    {
13350218822Sdim      /* Special case: encode as VTRN.32 <Dd>, <Dm>.  */
13351218822Sdim      inst.instruction = N_MNEM_vtrn;
13352218822Sdim      do_neon_trn ();
1335389857Sobrien      return;
1335489857Sobrien    }
13355218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
13356218822Sdim}
1335789857Sobrien
13358218822Sdimstatic void
13359218822Sdimdo_neon_sat_abs_neg (void)
13360218822Sdim{
13361218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13362218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13363218822Sdim    N_EQK, N_S8 | N_S16 | N_S32 | N_KEY);
13364218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1336589857Sobrien}
1336689857Sobrien
1336789857Sobrienstatic void
13368218822Sdimdo_neon_pair_long (void)
1336989857Sobrien{
13370218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13371218822Sdim  struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_SU_32 | N_KEY);
13372218822Sdim  /* Unsigned is encoded in OP field (bit 7) for these instruction.  */
13373218822Sdim  inst.instruction |= (et.type == NT_unsigned) << 7;
13374218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1337589857Sobrien}
1337689857Sobrien
1337789857Sobrienstatic void
13378218822Sdimdo_neon_recip_est (void)
1337989857Sobrien{
13380218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13381218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13382218822Sdim    N_EQK | N_FLT, N_F32 | N_U32 | N_KEY);
13383218822Sdim  inst.instruction |= (et.type == NT_float) << 8;
13384218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1338589857Sobrien}
1338689857Sobrien
1338789857Sobrienstatic void
13388218822Sdimdo_neon_cls (void)
1338989857Sobrien{
13390218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13391218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13392218822Sdim    N_EQK, N_S8 | N_S16 | N_S32 | N_KEY);
13393218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1339489857Sobrien}
1339589857Sobrien
1339689857Sobrienstatic void
13397218822Sdimdo_neon_clz (void)
1339889857Sobrien{
13399218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13400218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13401218822Sdim    N_EQK, N_I8 | N_I16 | N_I32 | N_KEY);
13402218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1340389857Sobrien}
1340489857Sobrien
1340589857Sobrienstatic void
13406218822Sdimdo_neon_cnt (void)
1340789857Sobrien{
13408218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13409218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13410218822Sdim    N_EQK | N_INT, N_8 | N_KEY);
13411218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1341289857Sobrien}
1341389857Sobrien
1341489857Sobrienstatic void
13415218822Sdimdo_neon_swp (void)
1341689857Sobrien{
13417218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13418218822Sdim  neon_two_same (neon_quad (rs), 1, -1);
1341989857Sobrien}
1342089857Sobrien
13421218822Sdimstatic void
13422218822Sdimdo_neon_tbl_tbx (void)
13423218822Sdim{
13424218822Sdim  unsigned listlenbits;
13425218822Sdim  neon_check_type (3, NS_DLD, N_EQK, N_EQK, N_8 | N_KEY);
13426218822Sdim
13427218822Sdim  if (inst.operands[1].imm < 1 || inst.operands[1].imm > 4)
13428218822Sdim    {
13429218822Sdim      first_error (_("bad list length for table lookup"));
13430218822Sdim      return;
13431218822Sdim    }
13432218822Sdim
13433218822Sdim  listlenbits = inst.operands[1].imm - 1;
13434218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
13435218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
13436218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
13437218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
13438218822Sdim  inst.instruction |= LOW4 (inst.operands[2].reg);
13439218822Sdim  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
13440218822Sdim  inst.instruction |= listlenbits << 8;
13441218822Sdim
13442218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
13443218822Sdim}
1344489857Sobrien
1344589857Sobrienstatic void
13446218822Sdimdo_neon_ldm_stm (void)
1344789857Sobrien{
13448218822Sdim  /* P, U and L bits are part of bitmask.  */
13449218822Sdim  int is_dbmode = (inst.instruction & (1 << 24)) != 0;
13450218822Sdim  unsigned offsetbits = inst.operands[1].imm * 2;
1345189857Sobrien
13452218822Sdim  if (inst.operands[1].issingle)
13453218822Sdim    {
13454218822Sdim      do_vfp_nsyn_ldm_stm (is_dbmode);
13455218822Sdim      return;
13456218822Sdim    }
1345789857Sobrien
13458218822Sdim  constraint (is_dbmode && !inst.operands[0].writeback,
13459218822Sdim              _("writeback (!) must be used for VLDMDB and VSTMDB"));
1346089857Sobrien
13461218822Sdim  constraint (inst.operands[1].imm < 1 || inst.operands[1].imm > 16,
13462218822Sdim              _("register list must contain at least 1 and at most 16 "
13463218822Sdim                "registers"));
13464218822Sdim
13465218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
13466218822Sdim  inst.instruction |= inst.operands[0].writeback << 21;
13467218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 12;
13468218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 22;
13469218822Sdim
13470218822Sdim  inst.instruction |= offsetbits;
13471218822Sdim
13472218822Sdim  do_vfp_cond_or_thumb ();
13473218822Sdim}
13474218822Sdim
13475218822Sdimstatic void
13476218822Sdimdo_neon_ldr_str (void)
13477218822Sdim{
13478218822Sdim  int is_ldr = (inst.instruction & (1 << 20)) != 0;
13479218822Sdim
13480218822Sdim  if (inst.operands[0].issingle)
1348189857Sobrien    {
13482218822Sdim      if (is_ldr)
13483218822Sdim        do_vfp_nsyn_opcode ("flds");
13484218822Sdim      else
13485218822Sdim        do_vfp_nsyn_opcode ("fsts");
1348689857Sobrien    }
1348789857Sobrien  else
13488218822Sdim    {
13489218822Sdim      if (is_ldr)
13490218822Sdim        do_vfp_nsyn_opcode ("fldd");
13491218822Sdim      else
13492218822Sdim        do_vfp_nsyn_opcode ("fstd");
13493218822Sdim    }
1349489857Sobrien}
1349589857Sobrien
13496218822Sdim/* "interleave" version also handles non-interleaving register VLD1/VST1
13497218822Sdim   instructions.  */
1349889857Sobrien
1349989857Sobrienstatic void
13500218822Sdimdo_neon_ld_st_interleave (void)
1350189857Sobrien{
13502218822Sdim  struct neon_type_el et = neon_check_type (1, NS_NULL,
13503218822Sdim                                            N_8 | N_16 | N_32 | N_64);
13504218822Sdim  unsigned alignbits = 0;
13505218822Sdim  unsigned idx;
13506218822Sdim  /* The bits in this table go:
13507218822Sdim     0: register stride of one (0) or two (1)
13508218822Sdim     1,2: register list length, minus one (1, 2, 3, 4).
13509218822Sdim     3,4: <n> in instruction type, minus one (VLD<n> / VST<n>).
13510218822Sdim     We use -1 for invalid entries.  */
13511218822Sdim  const int typetable[] =
13512218822Sdim    {
13513218822Sdim      0x7,  -1, 0xa,  -1, 0x6,  -1, 0x2,  -1, /* VLD1 / VST1.  */
13514218822Sdim       -1,  -1, 0x8, 0x9,  -1,  -1, 0x3,  -1, /* VLD2 / VST2.  */
13515218822Sdim       -1,  -1,  -1,  -1, 0x4, 0x5,  -1,  -1, /* VLD3 / VST3.  */
13516218822Sdim       -1,  -1,  -1,  -1,  -1,  -1, 0x0, 0x1  /* VLD4 / VST4.  */
13517218822Sdim    };
13518218822Sdim  int typebits;
1351989857Sobrien
13520218822Sdim  if (et.type == NT_invtype)
13521218822Sdim    return;
1352289857Sobrien
13523218822Sdim  if (inst.operands[1].immisalign)
13524218822Sdim    switch (inst.operands[1].imm >> 8)
13525218822Sdim      {
13526218822Sdim      case 64: alignbits = 1; break;
13527218822Sdim      case 128:
13528218822Sdim        if (NEON_REGLIST_LENGTH (inst.operands[0].imm) == 3)
13529218822Sdim          goto bad_alignment;
13530218822Sdim        alignbits = 2;
13531218822Sdim        break;
13532218822Sdim      case 256:
13533218822Sdim        if (NEON_REGLIST_LENGTH (inst.operands[0].imm) == 3)
13534218822Sdim          goto bad_alignment;
13535218822Sdim        alignbits = 3;
13536218822Sdim        break;
13537218822Sdim      default:
13538218822Sdim      bad_alignment:
13539218822Sdim        first_error (_("bad alignment"));
13540218822Sdim        return;
13541218822Sdim      }
1354289857Sobrien
13543218822Sdim  inst.instruction |= alignbits << 4;
13544218822Sdim  inst.instruction |= neon_logbits (et.size) << 6;
13545218822Sdim
13546218822Sdim  /* Bits [4:6] of the immediate in a list specifier encode register stride
13547218822Sdim     (minus 1) in bit 4, and list length in bits [5:6]. We put the <n> of
13548218822Sdim     VLD<n>/VST<n> in bits [9:8] of the initial bitmask. Suck it out here, look
13549218822Sdim     up the right value for "type" in a table based on this value and the given
13550218822Sdim     list style, then stick it back.  */
13551218822Sdim  idx = ((inst.operands[0].imm >> 4) & 7)
13552218822Sdim        | (((inst.instruction >> 8) & 3) << 3);
13553218822Sdim
13554218822Sdim  typebits = typetable[idx];
13555218822Sdim
13556218822Sdim  constraint (typebits == -1, _("bad list type for instruction"));
13557218822Sdim
13558218822Sdim  inst.instruction &= ~0xf00;
13559218822Sdim  inst.instruction |= typebits << 8;
13560218822Sdim}
13561218822Sdim
13562218822Sdim/* Check alignment is valid for do_neon_ld_st_lane and do_neon_ld_dup.
13563218822Sdim   *DO_ALIGN is set to 1 if the relevant alignment bit should be set, 0
13564218822Sdim   otherwise. The variable arguments are a list of pairs of legal (size, align)
13565218822Sdim   values, terminated with -1.  */
13566218822Sdim
13567218822Sdimstatic int
13568218822Sdimneon_alignment_bit (int size, int align, int *do_align, ...)
13569218822Sdim{
13570218822Sdim  va_list ap;
13571218822Sdim  int result = FAIL, thissize, thisalign;
13572218822Sdim
13573218822Sdim  if (!inst.operands[1].immisalign)
1357489857Sobrien    {
13575218822Sdim      *do_align = 0;
13576218822Sdim      return SUCCESS;
1357789857Sobrien    }
13578218822Sdim
13579218822Sdim  va_start (ap, do_align);
13580218822Sdim
13581218822Sdim  do
13582218822Sdim    {
13583218822Sdim      thissize = va_arg (ap, int);
13584218822Sdim      if (thissize == -1)
13585218822Sdim        break;
13586218822Sdim      thisalign = va_arg (ap, int);
13587218822Sdim
13588218822Sdim      if (size == thissize && align == thisalign)
13589218822Sdim        result = SUCCESS;
13590218822Sdim    }
13591218822Sdim  while (result != SUCCESS);
13592218822Sdim
13593218822Sdim  va_end (ap);
13594218822Sdim
13595218822Sdim  if (result == SUCCESS)
13596218822Sdim    *do_align = 1;
1359789857Sobrien  else
13598218822Sdim    first_error (_("unsupported alignment for instruction"));
13599218822Sdim
13600218822Sdim  return result;
1360189857Sobrien}
1360289857Sobrien
1360389857Sobrienstatic void
13604218822Sdimdo_neon_ld_st_lane (void)
1360589857Sobrien{
13606218822Sdim  struct neon_type_el et = neon_check_type (1, NS_NULL, N_8 | N_16 | N_32);
13607218822Sdim  int align_good, do_align = 0;
13608218822Sdim  int logsize = neon_logbits (et.size);
13609218822Sdim  int align = inst.operands[1].imm >> 8;
13610218822Sdim  int n = (inst.instruction >> 8) & 3;
13611218822Sdim  int max_el = 64 / et.size;
13612218822Sdim
13613218822Sdim  if (et.type == NT_invtype)
13614218822Sdim    return;
13615218822Sdim
13616218822Sdim  constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != n + 1,
13617218822Sdim              _("bad list length"));
13618218822Sdim  constraint (NEON_LANE (inst.operands[0].imm) >= max_el,
13619218822Sdim              _("scalar index out of range"));
13620218822Sdim  constraint (n != 0 && NEON_REG_STRIDE (inst.operands[0].imm) == 2
13621218822Sdim              && et.size == 8,
13622218822Sdim              _("stride of 2 unavailable when element size is 8"));
13623218822Sdim
13624218822Sdim  switch (n)
13625218822Sdim    {
13626218822Sdim    case 0:  /* VLD1 / VST1.  */
13627218822Sdim      align_good = neon_alignment_bit (et.size, align, &do_align, 16, 16,
13628218822Sdim                                       32, 32, -1);
13629218822Sdim      if (align_good == FAIL)
13630218822Sdim        return;
13631218822Sdim      if (do_align)
13632218822Sdim        {
13633218822Sdim          unsigned alignbits = 0;
13634218822Sdim          switch (et.size)
13635218822Sdim            {
13636218822Sdim            case 16: alignbits = 0x1; break;
13637218822Sdim            case 32: alignbits = 0x3; break;
13638218822Sdim            default: ;
13639218822Sdim            }
13640218822Sdim          inst.instruction |= alignbits << 4;
13641218822Sdim        }
13642218822Sdim      break;
1364389857Sobrien
13644218822Sdim    case 1:  /* VLD2 / VST2.  */
13645218822Sdim      align_good = neon_alignment_bit (et.size, align, &do_align, 8, 16, 16, 32,
13646218822Sdim                                       32, 64, -1);
13647218822Sdim      if (align_good == FAIL)
13648218822Sdim        return;
13649218822Sdim      if (do_align)
13650218822Sdim        inst.instruction |= 1 << 4;
13651218822Sdim      break;
1365289857Sobrien
13653218822Sdim    case 2:  /* VLD3 / VST3.  */
13654218822Sdim      constraint (inst.operands[1].immisalign,
13655218822Sdim                  _("can't use alignment with this instruction"));
13656218822Sdim      break;
1365789857Sobrien
13658218822Sdim    case 3:  /* VLD4 / VST4.  */
13659218822Sdim      align_good = neon_alignment_bit (et.size, align, &do_align, 8, 32,
13660218822Sdim                                       16, 64, 32, 64, 32, 128, -1);
13661218822Sdim      if (align_good == FAIL)
13662218822Sdim        return;
13663218822Sdim      if (do_align)
13664218822Sdim        {
13665218822Sdim          unsigned alignbits = 0;
13666218822Sdim          switch (et.size)
13667218822Sdim            {
13668218822Sdim            case 8:  alignbits = 0x1; break;
13669218822Sdim            case 16: alignbits = 0x1; break;
13670218822Sdim            case 32: alignbits = (align == 64) ? 0x1 : 0x2; break;
13671218822Sdim            default: ;
13672218822Sdim            }
13673218822Sdim          inst.instruction |= alignbits << 4;
13674218822Sdim        }
13675218822Sdim      break;
13676218822Sdim
13677218822Sdim    default: ;
1367889857Sobrien    }
13679218822Sdim
13680218822Sdim  /* Reg stride of 2 is encoded in bit 5 when size==16, bit 6 when size==32.  */
13681218822Sdim  if (n != 0 && NEON_REG_STRIDE (inst.operands[0].imm) == 2)
13682218822Sdim    inst.instruction |= 1 << (4 + logsize);
13683218822Sdim
13684218822Sdim  inst.instruction |= NEON_LANE (inst.operands[0].imm) << (logsize + 5);
13685218822Sdim  inst.instruction |= logsize << 10;
1368689857Sobrien}
1368789857Sobrien
13688218822Sdim/* Encode single n-element structure to all lanes VLD<n> instructions.  */
1368989857Sobrien
1369089857Sobrienstatic void
13691218822Sdimdo_neon_ld_dup (void)
1369289857Sobrien{
13693218822Sdim  struct neon_type_el et = neon_check_type (1, NS_NULL, N_8 | N_16 | N_32);
13694218822Sdim  int align_good, do_align = 0;
1369589857Sobrien
13696218822Sdim  if (et.type == NT_invtype)
13697218822Sdim    return;
1369889857Sobrien
13699218822Sdim  switch ((inst.instruction >> 8) & 3)
13700218822Sdim    {
13701218822Sdim    case 0:  /* VLD1.  */
13702218822Sdim      assert (NEON_REG_STRIDE (inst.operands[0].imm) != 2);
13703218822Sdim      align_good = neon_alignment_bit (et.size, inst.operands[1].imm >> 8,
13704218822Sdim                                       &do_align, 16, 16, 32, 32, -1);
13705218822Sdim      if (align_good == FAIL)
13706218822Sdim        return;
13707218822Sdim      switch (NEON_REGLIST_LENGTH (inst.operands[0].imm))
13708218822Sdim        {
13709218822Sdim        case 1: break;
13710218822Sdim        case 2: inst.instruction |= 1 << 5; break;
13711218822Sdim        default: first_error (_("bad list length")); return;
13712218822Sdim        }
13713218822Sdim      inst.instruction |= neon_logbits (et.size) << 6;
13714218822Sdim      break;
1371589857Sobrien
13716218822Sdim    case 1:  /* VLD2.  */
13717218822Sdim      align_good = neon_alignment_bit (et.size, inst.operands[1].imm >> 8,
13718218822Sdim                                       &do_align, 8, 16, 16, 32, 32, 64, -1);
13719218822Sdim      if (align_good == FAIL)
13720218822Sdim        return;
13721218822Sdim      constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 2,
13722218822Sdim                  _("bad list length"));
13723218822Sdim      if (NEON_REG_STRIDE (inst.operands[0].imm) == 2)
13724218822Sdim        inst.instruction |= 1 << 5;
13725218822Sdim      inst.instruction |= neon_logbits (et.size) << 6;
13726218822Sdim      break;
13727218822Sdim
13728218822Sdim    case 2:  /* VLD3.  */
13729218822Sdim      constraint (inst.operands[1].immisalign,
13730218822Sdim                  _("can't use alignment with this instruction"));
13731218822Sdim      constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 3,
13732218822Sdim                  _("bad list length"));
13733218822Sdim      if (NEON_REG_STRIDE (inst.operands[0].imm) == 2)
13734218822Sdim        inst.instruction |= 1 << 5;
13735218822Sdim      inst.instruction |= neon_logbits (et.size) << 6;
13736218822Sdim      break;
13737218822Sdim
13738218822Sdim    case 3:  /* VLD4.  */
13739218822Sdim      {
13740218822Sdim        int align = inst.operands[1].imm >> 8;
13741218822Sdim        align_good = neon_alignment_bit (et.size, align, &do_align, 8, 32,
13742218822Sdim                                         16, 64, 32, 64, 32, 128, -1);
13743218822Sdim        if (align_good == FAIL)
13744218822Sdim          return;
13745218822Sdim        constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 4,
13746218822Sdim                    _("bad list length"));
13747218822Sdim        if (NEON_REG_STRIDE (inst.operands[0].imm) == 2)
13748218822Sdim          inst.instruction |= 1 << 5;
13749218822Sdim        if (et.size == 32 && align == 128)
13750218822Sdim          inst.instruction |= 0x3 << 6;
13751218822Sdim        else
13752218822Sdim          inst.instruction |= neon_logbits (et.size) << 6;
13753218822Sdim      }
13754218822Sdim      break;
13755218822Sdim
13756218822Sdim    default: ;
1375789857Sobrien    }
1375889857Sobrien
13759218822Sdim  inst.instruction |= do_align << 4;
13760218822Sdim}
1376189857Sobrien
13762218822Sdim/* Disambiguate VLD<n> and VST<n> instructions, and fill in common bits (those
13763218822Sdim   apart from bits [11:4].  */
1376489857Sobrien
13765218822Sdimstatic void
13766218822Sdimdo_neon_ldx_stx (void)
13767218822Sdim{
13768218822Sdim  switch (NEON_LANE (inst.operands[0].imm))
1376989857Sobrien    {
13770218822Sdim    case NEON_INTERLEAVE_LANES:
13771218822Sdim      inst.instruction = NEON_ENC_INTERLV (inst.instruction);
13772218822Sdim      do_neon_ld_st_interleave ();
13773218822Sdim      break;
13774218822Sdim
13775218822Sdim    case NEON_ALL_LANES:
13776218822Sdim      inst.instruction = NEON_ENC_DUP (inst.instruction);
13777218822Sdim      do_neon_ld_dup ();
13778218822Sdim      break;
13779218822Sdim
13780218822Sdim    default:
13781218822Sdim      inst.instruction = NEON_ENC_LANE (inst.instruction);
13782218822Sdim      do_neon_ld_st_lane ();
1378389857Sobrien    }
1378489857Sobrien
13785218822Sdim  /* L bit comes from bit mask.  */
13786218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
13787218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
13788218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
13789218822Sdim
13790218822Sdim  if (inst.operands[1].postind)
1379189857Sobrien    {
13792218822Sdim      int postreg = inst.operands[1].imm & 0xf;
13793218822Sdim      constraint (!inst.operands[1].immisreg,
13794218822Sdim                  _("post-index must be a register"));
13795218822Sdim      constraint (postreg == 0xd || postreg == 0xf,
13796218822Sdim                  _("bad register for post-index"));
13797218822Sdim      inst.instruction |= postreg;
1379889857Sobrien    }
13799218822Sdim  else if (inst.operands[1].writeback)
13800218822Sdim    {
13801218822Sdim      inst.instruction |= 0xd;
13802218822Sdim    }
13803218822Sdim  else
13804218822Sdim    inst.instruction |= 0xf;
13805218822Sdim
13806218822Sdim  if (thumb_mode)
13807218822Sdim    inst.instruction |= 0xf9000000;
13808218822Sdim  else
13809218822Sdim    inst.instruction |= 0xf4000000;
13810218822Sdim}
1381189857Sobrien
13812218822Sdim
13813218822Sdim/* Overall per-instruction processing.	*/
1381489857Sobrien
13815218822Sdim/* We need to be able to fix up arbitrary expressions in some statements.
13816218822Sdim   This is so that we can handle symbols that are an arbitrary distance from
13817218822Sdim   the pc.  The most common cases are of the form ((+/-sym -/+ . - 8) & mask),
13818218822Sdim   which returns part of an address in a form which will be valid for
13819218822Sdim   a data instruction.	We do this by pushing the expression into a symbol
13820218822Sdim   in the expr_section, and creating a fix for that.  */
13821218822Sdim
13822218822Sdimstatic void
13823218822Sdimfix_new_arm (fragS *	   frag,
13824218822Sdim	     int	   where,
13825218822Sdim	     short int	   size,
13826218822Sdim	     expressionS * exp,
13827218822Sdim	     int	   pc_rel,
13828218822Sdim	     int	   reloc)
13829218822Sdim{
13830218822Sdim  fixS *	   new_fix;
13831218822Sdim
13832218822Sdim  switch (exp->X_op)
1383389857Sobrien    {
13834218822Sdim    case O_constant:
13835218822Sdim    case O_symbol:
13836218822Sdim    case O_add:
13837218822Sdim    case O_subtract:
13838218822Sdim      new_fix = fix_new_exp (frag, where, size, exp, pc_rel, reloc);
13839218822Sdim      break;
1384089857Sobrien
13841218822Sdim    default:
13842218822Sdim      new_fix = fix_new (frag, where, size, make_expr_symbol (exp), 0,
13843218822Sdim			 pc_rel, reloc);
13844218822Sdim      break;
1384589857Sobrien    }
1384689857Sobrien
13847218822Sdim  /* Mark whether the fix is to a THUMB instruction, or an ARM
13848218822Sdim     instruction.  */
13849218822Sdim  new_fix->tc_fix_data = thumb_mode;
1385089857Sobrien}
1385189857Sobrien
13852218822Sdim/* Create a frg for an instruction requiring relaxation.  */
13853218822Sdimstatic void
13854218822Sdimoutput_relax_insn (void)
1385589857Sobrien{
13856218822Sdim  char * to;
13857218822Sdim  symbolS *sym;
1385889857Sobrien  int offset;
1385989857Sobrien
13860218822Sdim  /* The size of the instruction is unknown, so tie the debug info to the
13861218822Sdim     start of the instruction.  */
13862218822Sdim  dwarf2_emit_insn (0);
1386389857Sobrien
13864218822Sdim  switch (inst.reloc.exp.X_op)
13865218822Sdim    {
13866218822Sdim    case O_symbol:
13867218822Sdim      sym = inst.reloc.exp.X_add_symbol;
13868218822Sdim      offset = inst.reloc.exp.X_add_number;
13869218822Sdim      break;
13870218822Sdim    case O_constant:
13871218822Sdim      sym = NULL;
13872218822Sdim      offset = inst.reloc.exp.X_add_number;
13873218822Sdim      break;
13874218822Sdim    default:
13875218822Sdim      sym = make_expr_symbol (&inst.reloc.exp);
13876218822Sdim      offset = 0;
13877218822Sdim      break;
13878218822Sdim  }
13879218822Sdim  to = frag_var (rs_machine_dependent, INSN_SIZE, THUMB_SIZE,
13880218822Sdim		 inst.relax, sym, offset, NULL/*offset, opcode*/);
13881218822Sdim  md_number_to_chars (to, inst.instruction, THUMB_SIZE);
13882218822Sdim}
1388389857Sobrien
13884218822Sdim/* Write a 32-bit thumb instruction to buf.  */
13885218822Sdimstatic void
13886218822Sdimput_thumb32_insn (char * buf, unsigned long insn)
13887218822Sdim{
13888218822Sdim  md_number_to_chars (buf, insn >> 16, THUMB_SIZE);
13889218822Sdim  md_number_to_chars (buf + THUMB_SIZE, insn, THUMB_SIZE);
13890218822Sdim}
1389189857Sobrien
13892218822Sdimstatic void
13893218822Sdimoutput_inst (const char * str)
13894218822Sdim{
13895218822Sdim  char * to = NULL;
1389689857Sobrien
13897218822Sdim  if (inst.error)
1389889857Sobrien    {
13899218822Sdim      as_bad ("%s -- `%s'", inst.error, str);
13900218822Sdim      return;
1390189857Sobrien    }
13902218822Sdim  if (inst.relax) {
13903218822Sdim      output_relax_insn();
13904218822Sdim      return;
13905218822Sdim  }
13906218822Sdim  if (inst.size == 0)
13907218822Sdim    return;
1390889857Sobrien
13909218822Sdim  to = frag_more (inst.size);
1391089857Sobrien
13911218822Sdim  if (thumb_mode && (inst.size > THUMB_SIZE))
1391289857Sobrien    {
13913218822Sdim      assert (inst.size == (2 * THUMB_SIZE));
13914218822Sdim      put_thumb32_insn (to, inst.instruction);
1391589857Sobrien    }
13916218822Sdim  else if (inst.size > INSN_SIZE)
13917218822Sdim    {
13918218822Sdim      assert (inst.size == (2 * INSN_SIZE));
13919218822Sdim      md_number_to_chars (to, inst.instruction, INSN_SIZE);
13920218822Sdim      md_number_to_chars (to + INSN_SIZE, inst.instruction, INSN_SIZE);
13921218822Sdim    }
13922218822Sdim  else
13923218822Sdim    md_number_to_chars (to, inst.instruction, inst.size);
1392489857Sobrien
13925218822Sdim  if (inst.reloc.type != BFD_RELOC_UNUSED)
13926218822Sdim    fix_new_arm (frag_now, to - frag_now->fr_literal,
13927218822Sdim		 inst.size, & inst.reloc.exp, inst.reloc.pc_rel,
13928218822Sdim		 inst.reloc.type);
1392989857Sobrien
13930218822Sdim  dwarf2_emit_insn (inst.size);
1393189857Sobrien}
1393289857Sobrien
13933218822Sdim/* Tag values used in struct asm_opcode's tag field.  */
13934218822Sdimenum opcode_tag
13935218822Sdim{
13936218822Sdim  OT_unconditional,	/* Instruction cannot be conditionalized.
13937218822Sdim			   The ARM condition field is still 0xE.  */
13938218822Sdim  OT_unconditionalF,	/* Instruction cannot be conditionalized
13939218822Sdim			   and carries 0xF in its ARM condition field.  */
13940218822Sdim  OT_csuffix,		/* Instruction takes a conditional suffix.  */
13941218822Sdim  OT_csuffixF,		/* Some forms of the instruction take a conditional
13942218822Sdim                           suffix, others place 0xF where the condition field
13943218822Sdim                           would be.  */
13944218822Sdim  OT_cinfix3,		/* Instruction takes a conditional infix,
13945218822Sdim			   beginning at character index 3.  (In
13946218822Sdim			   unified mode, it becomes a suffix.)  */
13947218822Sdim  OT_cinfix3_deprecated, /* The same as OT_cinfix3.  This is used for
13948218822Sdim			    tsts, cmps, cmns, and teqs. */
13949218822Sdim  OT_cinfix3_legacy,	/* Legacy instruction takes a conditional infix at
13950218822Sdim			   character index 3, even in unified mode.  Used for
13951218822Sdim			   legacy instructions where suffix and infix forms
13952218822Sdim			   may be ambiguous.  */
13953218822Sdim  OT_csuf_or_in3,	/* Instruction takes either a conditional
13954218822Sdim			   suffix or an infix at character index 3.  */
13955218822Sdim  OT_odd_infix_unc,	/* This is the unconditional variant of an
13956218822Sdim			   instruction that takes a conditional infix
13957218822Sdim			   at an unusual position.  In unified mode,
13958218822Sdim			   this variant will accept a suffix.  */
13959218822Sdim  OT_odd_infix_0	/* Values greater than or equal to OT_odd_infix_0
13960218822Sdim			   are the conditional variants of instructions that
13961218822Sdim			   take conditional infixes in unusual positions.
13962218822Sdim			   The infix appears at character index
13963218822Sdim			   (tag - OT_odd_infix_0).  These are not accepted
13964218822Sdim			   in unified mode.  */
13965218822Sdim};
1396689857Sobrien
13967218822Sdim/* Subroutine of md_assemble, responsible for looking up the primary
13968218822Sdim   opcode from the mnemonic the user wrote.  STR points to the
13969218822Sdim   beginning of the mnemonic.
13970218822Sdim
13971218822Sdim   This is not simply a hash table lookup, because of conditional
13972218822Sdim   variants.  Most instructions have conditional variants, which are
13973218822Sdim   expressed with a _conditional affix_ to the mnemonic.  If we were
13974218822Sdim   to encode each conditional variant as a literal string in the opcode
13975218822Sdim   table, it would have approximately 20,000 entries.
13976218822Sdim
13977218822Sdim   Most mnemonics take this affix as a suffix, and in unified syntax,
13978218822Sdim   'most' is upgraded to 'all'.  However, in the divided syntax, some
13979218822Sdim   instructions take the affix as an infix, notably the s-variants of
13980218822Sdim   the arithmetic instructions.  Of those instructions, all but six
13981218822Sdim   have the infix appear after the third character of the mnemonic.
13982218822Sdim
13983218822Sdim   Accordingly, the algorithm for looking up primary opcodes given
13984218822Sdim   an identifier is:
13985218822Sdim
13986218822Sdim   1. Look up the identifier in the opcode table.
13987218822Sdim      If we find a match, go to step U.
13988218822Sdim
13989218822Sdim   2. Look up the last two characters of the identifier in the
13990218822Sdim      conditions table.  If we find a match, look up the first N-2
13991218822Sdim      characters of the identifier in the opcode table.  If we
13992218822Sdim      find a match, go to step CE.
13993218822Sdim
13994218822Sdim   3. Look up the fourth and fifth characters of the identifier in
13995218822Sdim      the conditions table.  If we find a match, extract those
13996218822Sdim      characters from the identifier, and look up the remaining
13997218822Sdim      characters in the opcode table.  If we find a match, go
13998218822Sdim      to step CM.
13999218822Sdim
14000218822Sdim   4. Fail.
14001218822Sdim
14002218822Sdim   U. Examine the tag field of the opcode structure, in case this is
14003218822Sdim      one of the six instructions with its conditional infix in an
14004218822Sdim      unusual place.  If it is, the tag tells us where to find the
14005218822Sdim      infix; look it up in the conditions table and set inst.cond
14006218822Sdim      accordingly.  Otherwise, this is an unconditional instruction.
14007218822Sdim      Again set inst.cond accordingly.  Return the opcode structure.
14008218822Sdim
14009218822Sdim  CE. Examine the tag field to make sure this is an instruction that
14010218822Sdim      should receive a conditional suffix.  If it is not, fail.
14011218822Sdim      Otherwise, set inst.cond from the suffix we already looked up,
14012218822Sdim      and return the opcode structure.
14013218822Sdim
14014218822Sdim  CM. Examine the tag field to make sure this is an instruction that
14015218822Sdim      should receive a conditional infix after the third character.
14016218822Sdim      If it is not, fail.  Otherwise, undo the edits to the current
14017218822Sdim      line of input and proceed as for case CE.  */
14018218822Sdim
14019218822Sdimstatic const struct asm_opcode *
14020218822Sdimopcode_lookup (char **str)
1402189857Sobrien{
14022218822Sdim  char *end, *base;
14023218822Sdim  char *affix;
14024218822Sdim  const struct asm_opcode *opcode;
14025218822Sdim  const struct asm_cond *cond;
14026218822Sdim  char save[2];
14027218822Sdim  bfd_boolean neon_supported;
14028218822Sdim
14029218822Sdim  neon_supported = ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1);
1403089857Sobrien
14031218822Sdim  /* Scan up to the end of the mnemonic, which must end in white space,
14032218822Sdim     '.' (in unified mode, or for Neon instructions), or end of string.  */
14033218822Sdim  for (base = end = *str; *end != '\0'; end++)
14034218822Sdim    if (*end == ' ' || ((unified_syntax || neon_supported) && *end == '.'))
14035218822Sdim      break;
1403689857Sobrien
14037218822Sdim  if (end == base)
14038218822Sdim    return 0;
1403989857Sobrien
14040218822Sdim  /* Handle a possible width suffix and/or Neon type suffix.  */
14041218822Sdim  if (end[0] == '.')
1404289857Sobrien    {
14043218822Sdim      int offset = 2;
14044218822Sdim
14045218822Sdim      /* The .w and .n suffixes are only valid if the unified syntax is in
14046218822Sdim         use.  */
14047218822Sdim      if (unified_syntax && end[1] == 'w')
14048218822Sdim	inst.size_req = 4;
14049218822Sdim      else if (unified_syntax && end[1] == 'n')
14050218822Sdim	inst.size_req = 2;
14051218822Sdim      else
14052218822Sdim        offset = 0;
1405389857Sobrien
14054218822Sdim      inst.vectype.elems = 0;
1405589857Sobrien
14056218822Sdim      *str = end + offset;
1405789857Sobrien
14058218822Sdim      if (end[offset] == '.')
1405989857Sobrien	{
14060218822Sdim	  /* See if we have a Neon type suffix (possible in either unified or
14061218822Sdim             non-unified ARM syntax mode).  */
14062218822Sdim          if (parse_neon_type (&inst.vectype, str) == FAIL)
14063218822Sdim	    return 0;
14064218822Sdim        }
14065218822Sdim      else if (end[offset] != '\0' && end[offset] != ' ')
14066218822Sdim        return 0;
14067218822Sdim    }
14068218822Sdim  else
14069218822Sdim    *str = end;
1407089857Sobrien
14071218822Sdim  /* Look for unaffixed or special-case affixed mnemonic.  */
14072218822Sdim  opcode = hash_find_n (arm_ops_hsh, base, end - base);
14073218822Sdim  if (opcode)
14074218822Sdim    {
14075218822Sdim      /* step U */
14076218822Sdim      if (opcode->tag < OT_odd_infix_0)
1407789857Sobrien	{
14078218822Sdim	  inst.cond = COND_ALWAYS;
14079218822Sdim	  return opcode;
1408089857Sobrien	}
14081218822Sdim
14082218822Sdim      if (unified_syntax)
14083218822Sdim	as_warn (_("conditional infixes are deprecated in unified syntax"));
14084218822Sdim      affix = base + (opcode->tag - OT_odd_infix_0);
14085218822Sdim      cond = hash_find_n (arm_cond_hsh, affix, 2);
14086218822Sdim      assert (cond);
14087218822Sdim
14088218822Sdim      inst.cond = cond->value;
14089218822Sdim      return opcode;
1409089857Sobrien    }
14091218822Sdim
14092218822Sdim  /* Cannot have a conditional suffix on a mnemonic of less than two
14093218822Sdim     characters.  */
14094218822Sdim  if (end - base < 3)
14095218822Sdim    return 0;
14096218822Sdim
14097218822Sdim  /* Look for suffixed mnemonic.  */
14098218822Sdim  affix = end - 2;
14099218822Sdim  cond = hash_find_n (arm_cond_hsh, affix, 2);
14100218822Sdim  opcode = hash_find_n (arm_ops_hsh, base, affix - base);
14101218822Sdim  if (opcode && cond)
1410289857Sobrien    {
14103218822Sdim      /* step CE */
14104218822Sdim      switch (opcode->tag)
1410589857Sobrien	{
14106218822Sdim	case OT_cinfix3_legacy:
14107218822Sdim	  /* Ignore conditional suffixes matched on infix only mnemonics.  */
14108218822Sdim	  break;
1410989857Sobrien
14110218822Sdim	case OT_cinfix3:
14111218822Sdim	case OT_cinfix3_deprecated:
14112218822Sdim	case OT_odd_infix_unc:
14113218822Sdim	  if (!unified_syntax)
14114218822Sdim	    return 0;
14115218822Sdim	  /* else fall through */
1411689857Sobrien
14117218822Sdim	case OT_csuffix:
14118218822Sdim        case OT_csuffixF:
14119218822Sdim	case OT_csuf_or_in3:
14120218822Sdim	  inst.cond = cond->value;
14121218822Sdim	  return opcode;
14122218822Sdim
14123218822Sdim	case OT_unconditional:
14124218822Sdim	case OT_unconditionalF:
14125218822Sdim	  if (thumb_mode)
14126218822Sdim	    {
14127218822Sdim	      inst.cond = cond->value;
14128218822Sdim	    }
14129218822Sdim	  else
14130218822Sdim	    {
14131218822Sdim	      /* delayed diagnostic */
14132218822Sdim	      inst.error = BAD_COND;
14133218822Sdim	      inst.cond = COND_ALWAYS;
14134218822Sdim	    }
14135218822Sdim	  return opcode;
14136218822Sdim
14137218822Sdim	default:
14138218822Sdim	  return 0;
14139218822Sdim	}
1414089857Sobrien    }
1414189857Sobrien
14142218822Sdim  /* Cannot have a usual-position infix on a mnemonic of less than
14143218822Sdim     six characters (five would be a suffix).  */
14144218822Sdim  if (end - base < 6)
14145218822Sdim    return 0;
1414689857Sobrien
14147218822Sdim  /* Look for infixed mnemonic in the usual position.  */
14148218822Sdim  affix = base + 3;
14149218822Sdim  cond = hash_find_n (arm_cond_hsh, affix, 2);
14150218822Sdim  if (!cond)
14151218822Sdim    return 0;
1415289857Sobrien
14153218822Sdim  memcpy (save, affix, 2);
14154218822Sdim  memmove (affix, affix + 2, (end - affix) - 2);
14155218822Sdim  opcode = hash_find_n (arm_ops_hsh, base, (end - base) - 2);
14156218822Sdim  memmove (affix + 2, affix, (end - affix) - 2);
14157218822Sdim  memcpy (affix, save, 2);
14158218822Sdim
14159218822Sdim  if (opcode
14160218822Sdim      && (opcode->tag == OT_cinfix3
14161218822Sdim	  || opcode->tag == OT_cinfix3_deprecated
14162218822Sdim	  || opcode->tag == OT_csuf_or_in3
14163218822Sdim	  || opcode->tag == OT_cinfix3_legacy))
14164218822Sdim    {
14165218822Sdim      /* step CM */
14166218822Sdim      if (unified_syntax
14167218822Sdim	  && (opcode->tag == OT_cinfix3
14168218822Sdim	      || opcode->tag == OT_cinfix3_deprecated))
14169218822Sdim	as_warn (_("conditional infixes are deprecated in unified syntax"));
14170218822Sdim
14171218822Sdim      inst.cond = cond->value;
14172218822Sdim      return opcode;
14173218822Sdim    }
14174218822Sdim
14175218822Sdim  return 0;
1417689857Sobrien}
1417789857Sobrien
14178218822Sdimvoid
14179218822Sdimmd_assemble (char *str)
1418060484Sobrien{
14181218822Sdim  char *p = str;
14182218822Sdim  const struct asm_opcode * opcode;
1418360484Sobrien
14184218822Sdim  /* Align the previous label if needed.  */
14185218822Sdim  if (last_label_seen != NULL)
14186218822Sdim    {
14187218822Sdim      symbol_set_frag (last_label_seen, frag_now);
14188218822Sdim      S_SET_VALUE (last_label_seen, (valueT) frag_now_fix ());
14189218822Sdim      S_SET_SEGMENT (last_label_seen, now_seg);
14190218822Sdim    }
1419177298Sobrien
14192218822Sdim  memset (&inst, '\0', sizeof (inst));
14193218822Sdim  inst.reloc.type = BFD_RELOC_UNUSED;
1419460484Sobrien
14195218822Sdim  opcode = opcode_lookup (&p);
14196218822Sdim  if (!opcode)
14197218822Sdim    {
14198218822Sdim      /* It wasn't an instruction, but it might be a register alias of
14199218822Sdim	 the form alias .req reg, or a Neon .dn/.qn directive.  */
14200218822Sdim      if (!create_register_alias (str, p)
14201218822Sdim          && !create_neon_reg_alias (str, p))
14202218822Sdim	as_bad (_("bad instruction `%s'"), str);
1420360484Sobrien
1420477298Sobrien      return;
1420560484Sobrien    }
1420660484Sobrien
14207218822Sdim  if (opcode->tag == OT_cinfix3_deprecated)
14208218822Sdim    as_warn (_("s suffix on comparison instruction is deprecated"));
14209218822Sdim
14210218822Sdim  /* The value which unconditional instructions should have in place of the
14211218822Sdim     condition field.  */
14212218822Sdim  inst.uncond_value = (opcode->tag == OT_csuffixF) ? 0xf : -1;
14213218822Sdim
14214218822Sdim  if (thumb_mode)
1421560484Sobrien    {
14216218822Sdim      arm_feature_set variant;
14217218822Sdim
14218218822Sdim      variant = cpu_variant;
14219218822Sdim      /* Only allow coprocessor instructions on Thumb-2 capable devices.  */
14220218822Sdim      if (!ARM_CPU_HAS_FEATURE (variant, arm_arch_t2))
14221218822Sdim	ARM_CLEAR_FEATURE (variant, variant, fpu_any_hard);
14222218822Sdim      /* Check that this instruction is supported for this CPU.  */
14223218822Sdim      if (!opcode->tvariant
14224218822Sdim	  || (thumb_mode == 1
14225218822Sdim	      && !ARM_CPU_HAS_FEATURE (variant, *opcode->tvariant)))
1422660484Sobrien	{
14227218822Sdim	  as_bad (_("selected processor does not support `%s'"), str);
1422860484Sobrien	  return;
1422960484Sobrien	}
14230218822Sdim      if (inst.cond != COND_ALWAYS && !unified_syntax
14231218822Sdim	  && opcode->tencode != do_t_branch)
14232218822Sdim	{
14233218822Sdim	  as_bad (_("Thumb does not support conditional execution"));
14234218822Sdim	  return;
14235218822Sdim	}
1423660484Sobrien
14237218822Sdim      if (!ARM_CPU_HAS_FEATURE (variant, arm_ext_v6t2) && !inst.size_req)
14238218822Sdim	{
14239218822Sdim	  /* Implicit require narrow instructions on Thumb-1.  This avoids
14240218822Sdim	     relaxation accidentally introducing Thumb-2 instructions.  */
14241218822Sdim	  if (opcode->tencode != do_t_blx && opcode->tencode != do_t_branch23)
14242218822Sdim	    inst.size_req = 2;
14243218822Sdim	}
1424460484Sobrien
14245218822Sdim      /* Check conditional suffixes.  */
14246218822Sdim      if (current_it_mask)
1424760484Sobrien	{
14248218822Sdim	  int cond;
14249218822Sdim	  cond = current_cc ^ ((current_it_mask >> 4) & 1) ^ 1;
14250218822Sdim	  current_it_mask <<= 1;
14251218822Sdim	  current_it_mask &= 0x1f;
14252218822Sdim	  /* The BKPT instruction is unconditional even in an IT block.  */
14253218822Sdim	  if (!inst.error
14254218822Sdim	      && cond != inst.cond && opcode->tencode != do_t_bkpt)
14255218822Sdim	    {
14256218822Sdim	      as_bad (_("incorrect condition in IT block"));
14257218822Sdim	      return;
14258218822Sdim	    }
14259218822Sdim	}
14260218822Sdim      else if (inst.cond != COND_ALWAYS && opcode->tencode != do_t_branch)
14261218822Sdim	{
14262218822Sdim	  as_bad (_("thumb conditional instrunction not in IT block"));
1426360484Sobrien	  return;
1426460484Sobrien	}
1426560484Sobrien
14266218822Sdim      mapping_state (MAP_THUMB);
14267218822Sdim      inst.instruction = opcode->tvalue;
1426860484Sobrien
14269218822Sdim      if (!parse_operands (p, opcode->operands))
14270218822Sdim	opcode->tencode ();
1427160484Sobrien
14272218822Sdim      /* Clear current_it_mask at the end of an IT block.  */
14273218822Sdim      if (current_it_mask == 0x10)
14274218822Sdim	current_it_mask = 0;
1427560484Sobrien
14276218822Sdim      if (!(inst.error || inst.relax))
14277218822Sdim	{
14278218822Sdim	  assert (inst.instruction < 0xe800 || inst.instruction > 0xffff);
14279218822Sdim	  inst.size = (inst.instruction > 0xffff ? 4 : 2);
14280218822Sdim	  if (inst.size_req && inst.size_req != inst.size)
14281218822Sdim	    {
14282218822Sdim	      as_bad (_("cannot honor width suffix -- `%s'"), str);
14283218822Sdim	      return;
14284218822Sdim	    }
14285218822Sdim	}
14286218822Sdim
14287218822Sdim      /* Something has gone badly wrong if we try to relax a fixed size
14288218822Sdim         instruction.  */
14289218822Sdim      assert (inst.size_req == 0 || !inst.relax);
14290218822Sdim
14291218822Sdim      ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
14292218822Sdim			      *opcode->tvariant);
14293218822Sdim      /* Many Thumb-2 instructions also have Thumb-1 variants, so explicitly
14294218822Sdim	 set those bits when Thumb-2 32-bit instructions are seen.  ie.
14295218822Sdim	 anything other than bl/blx.
14296218822Sdim	 This is overly pessimistic for relaxable instructions.  */
14297218822Sdim      if ((inst.size == 4 && (inst.instruction & 0xf800e800) != 0xf000e800)
14298218822Sdim	  || inst.relax)
14299218822Sdim	ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
14300218822Sdim				arm_ext_v6t2);
14301218822Sdim    }
14302218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1))
14303218822Sdim    {
14304218822Sdim      /* Check that this instruction is supported for this CPU.  */
14305218822Sdim      if (!opcode->avariant ||
14306218822Sdim	  !ARM_CPU_HAS_FEATURE (cpu_variant, *opcode->avariant))
14307218822Sdim	{
14308218822Sdim	  as_bad (_("selected processor does not support `%s'"), str);
14309218822Sdim	  return;
14310218822Sdim	}
14311218822Sdim      if (inst.size_req)
14312218822Sdim	{
14313218822Sdim	  as_bad (_("width suffixes are invalid in ARM mode -- `%s'"), str);
14314218822Sdim	  return;
14315218822Sdim	}
14316218822Sdim
14317218822Sdim      mapping_state (MAP_ARM);
14318218822Sdim      inst.instruction = opcode->avalue;
14319218822Sdim      if (opcode->tag == OT_unconditionalF)
14320218822Sdim	inst.instruction |= 0xF << 28;
14321218822Sdim      else
14322218822Sdim	inst.instruction |= inst.cond << 28;
14323218822Sdim      inst.size = INSN_SIZE;
14324218822Sdim      if (!parse_operands (p, opcode->operands))
14325218822Sdim	opcode->aencode ();
14326218822Sdim      /* Arm mode bx is marked as both v4T and v5 because it's still required
14327218822Sdim         on a hypothetical non-thumb v5 core.  */
14328218822Sdim      if (ARM_CPU_HAS_FEATURE (*opcode->avariant, arm_ext_v4t)
14329218822Sdim	  || ARM_CPU_HAS_FEATURE (*opcode->avariant, arm_ext_v5))
14330218822Sdim	ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used, arm_ext_v4t);
14331218822Sdim      else
14332218822Sdim	ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used,
14333218822Sdim				*opcode->avariant);
14334218822Sdim    }
14335218822Sdim  else
14336218822Sdim    {
14337218822Sdim      as_bad (_("attempt to use an ARM instruction on a Thumb-only processor "
14338218822Sdim		"-- `%s'"), str);
14339218822Sdim      return;
14340218822Sdim    }
14341218822Sdim  output_inst (str);
1434260484Sobrien}
1434360484Sobrien
14344218822Sdim/* Various frobbings of labels and their addresses.  */
14345218822Sdim
14346218822Sdimvoid
14347218822Sdimarm_start_line_hook (void)
1434860484Sobrien{
14349218822Sdim  last_label_seen = NULL;
1435060484Sobrien}
1435160484Sobrien
14352218822Sdimvoid
14353218822Sdimarm_frob_label (symbolS * sym)
1435460484Sobrien{
14355218822Sdim  last_label_seen = sym;
1435660484Sobrien
14357218822Sdim  ARM_SET_THUMB (sym, thumb_mode);
1435860484Sobrien
14359218822Sdim#if defined OBJ_COFF || defined OBJ_ELF
14360218822Sdim  ARM_SET_INTERWORK (sym, support_interwork);
14361218822Sdim#endif
1436260484Sobrien
14363218822Sdim  /* Note - do not allow local symbols (.Lxxx) to be labeled
14364218822Sdim     as Thumb functions.  This is because these labels, whilst
14365218822Sdim     they exist inside Thumb code, are not the entry points for
14366218822Sdim     possible ARM->Thumb calls.	 Also, these labels can be used
14367218822Sdim     as part of a computed goto or switch statement.  eg gcc
14368218822Sdim     can generate code that looks like this:
1436960484Sobrien
14370218822Sdim		ldr  r2, [pc, .Laaa]
14371218822Sdim		lsl  r3, r3, #2
14372218822Sdim		ldr  r2, [r3, r2]
14373218822Sdim		mov  pc, r2
1437460484Sobrien
14375218822Sdim       .Lbbb:  .word .Lxxx
14376218822Sdim       .Lccc:  .word .Lyyy
14377218822Sdim       ..etc...
14378218822Sdim       .Laaa:	.word Lbbb
1437977298Sobrien
14380218822Sdim     The first instruction loads the address of the jump table.
14381218822Sdim     The second instruction converts a table index into a byte offset.
14382218822Sdim     The third instruction gets the jump address out of the table.
14383218822Sdim     The fourth instruction performs the jump.
1438460484Sobrien
14385218822Sdim     If the address stored at .Laaa is that of a symbol which has the
14386218822Sdim     Thumb_Func bit set, then the linker will arrange for this address
14387218822Sdim     to have the bottom bit set, which in turn would mean that the
14388218822Sdim     address computation performed by the third instruction would end
14389218822Sdim     up with the bottom bit set.  Since the ARM is capable of unaligned
14390218822Sdim     word loads, the instruction would then load the incorrect address
14391218822Sdim     out of the jump table, and chaos would ensue.  */
14392218822Sdim  if (label_is_thumb_function_name
14393218822Sdim      && (S_GET_NAME (sym)[0] != '.' || S_GET_NAME (sym)[1] != 'L')
14394218822Sdim      && (bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0)
14395218822Sdim    {
14396218822Sdim      /* When the address of a Thumb function is taken the bottom
14397218822Sdim	 bit of that address should be set.  This will allow
14398218822Sdim	 interworking between Arm and Thumb functions to work
14399218822Sdim	 correctly.  */
1440077298Sobrien
14401218822Sdim      THUMB_SET_FUNC (sym, 1);
14402218822Sdim
14403218822Sdim      label_is_thumb_function_name = FALSE;
14404218822Sdim    }
14405218822Sdim
14406218822Sdim  dwarf2_emit_label (sym);
14407218822Sdim}
14408218822Sdim
14409218822Sdimint
14410218822Sdimarm_data_in_code (void)
14411218822Sdim{
14412218822Sdim  if (thumb_mode && ! strncmp (input_line_pointer + 1, "data:", 5))
1441360484Sobrien    {
14414218822Sdim      *input_line_pointer = '/';
14415218822Sdim      input_line_pointer += 5;
14416218822Sdim      *input_line_pointer = 0;
14417218822Sdim      return 1;
1441860484Sobrien    }
1441960484Sobrien
14420218822Sdim  return 0;
1442160484Sobrien}
1442260484Sobrien
14423218822Sdimchar *
14424218822Sdimarm_canonicalize_symbol_name (char * name)
1442560484Sobrien{
14426218822Sdim  int len;
1442777298Sobrien
14428218822Sdim  if (thumb_mode && (len = strlen (name)) > 5
14429218822Sdim      && streq (name + len - 5, "/data"))
14430218822Sdim    *(name + len - 5) = 0;
1443160484Sobrien
14432218822Sdim  return name;
1443360484Sobrien}
14434218822Sdim
14435218822Sdim/* Table of all register names defined by default.  The user can
14436218822Sdim   define additional names with .req.  Note that all register names
14437218822Sdim   should appear in both upper and lowercase variants.	Some registers
14438218822Sdim   also have mixed-case names.	*/
1443960484Sobrien
14440218822Sdim#define REGDEF(s,n,t) { #s, n, REG_TYPE_##t, TRUE, 0 }
14441218822Sdim#define REGNUM(p,n,t) REGDEF(p##n, n, t)
14442218822Sdim#define REGNUM2(p,n,t) REGDEF(p##n, 2 * n, t)
14443218822Sdim#define REGSET(p,t) \
14444218822Sdim  REGNUM(p, 0,t), REGNUM(p, 1,t), REGNUM(p, 2,t), REGNUM(p, 3,t), \
14445218822Sdim  REGNUM(p, 4,t), REGNUM(p, 5,t), REGNUM(p, 6,t), REGNUM(p, 7,t), \
14446218822Sdim  REGNUM(p, 8,t), REGNUM(p, 9,t), REGNUM(p,10,t), REGNUM(p,11,t), \
14447218822Sdim  REGNUM(p,12,t), REGNUM(p,13,t), REGNUM(p,14,t), REGNUM(p,15,t)
14448218822Sdim#define REGSETH(p,t) \
14449218822Sdim  REGNUM(p,16,t), REGNUM(p,17,t), REGNUM(p,18,t), REGNUM(p,19,t), \
14450218822Sdim  REGNUM(p,20,t), REGNUM(p,21,t), REGNUM(p,22,t), REGNUM(p,23,t), \
14451218822Sdim  REGNUM(p,24,t), REGNUM(p,25,t), REGNUM(p,26,t), REGNUM(p,27,t), \
14452218822Sdim  REGNUM(p,28,t), REGNUM(p,29,t), REGNUM(p,30,t), REGNUM(p,31,t)
14453218822Sdim#define REGSET2(p,t) \
14454218822Sdim  REGNUM2(p, 0,t), REGNUM2(p, 1,t), REGNUM2(p, 2,t), REGNUM2(p, 3,t), \
14455218822Sdim  REGNUM2(p, 4,t), REGNUM2(p, 5,t), REGNUM2(p, 6,t), REGNUM2(p, 7,t), \
14456218822Sdim  REGNUM2(p, 8,t), REGNUM2(p, 9,t), REGNUM2(p,10,t), REGNUM2(p,11,t), \
14457218822Sdim  REGNUM2(p,12,t), REGNUM2(p,13,t), REGNUM2(p,14,t), REGNUM2(p,15,t)
14458218822Sdim
14459218822Sdimstatic const struct reg_entry reg_names[] =
1446060484Sobrien{
14461218822Sdim  /* ARM integer registers.  */
14462218822Sdim  REGSET(r, RN), REGSET(R, RN),
1446360484Sobrien
14464218822Sdim  /* ATPCS synonyms.  */
14465218822Sdim  REGDEF(a1,0,RN), REGDEF(a2,1,RN), REGDEF(a3, 2,RN), REGDEF(a4, 3,RN),
14466218822Sdim  REGDEF(v1,4,RN), REGDEF(v2,5,RN), REGDEF(v3, 6,RN), REGDEF(v4, 7,RN),
14467218822Sdim  REGDEF(v5,8,RN), REGDEF(v6,9,RN), REGDEF(v7,10,RN), REGDEF(v8,11,RN),
1446860484Sobrien
14469218822Sdim  REGDEF(A1,0,RN), REGDEF(A2,1,RN), REGDEF(A3, 2,RN), REGDEF(A4, 3,RN),
14470218822Sdim  REGDEF(V1,4,RN), REGDEF(V2,5,RN), REGDEF(V3, 6,RN), REGDEF(V4, 7,RN),
14471218822Sdim  REGDEF(V5,8,RN), REGDEF(V6,9,RN), REGDEF(V7,10,RN), REGDEF(V8,11,RN),
1447260484Sobrien
14473218822Sdim  /* Well-known aliases.  */
14474218822Sdim  REGDEF(wr, 7,RN), REGDEF(sb, 9,RN), REGDEF(sl,10,RN), REGDEF(fp,11,RN),
14475218822Sdim  REGDEF(ip,12,RN), REGDEF(sp,13,RN), REGDEF(lr,14,RN), REGDEF(pc,15,RN),
1447660484Sobrien
14477218822Sdim  REGDEF(WR, 7,RN), REGDEF(SB, 9,RN), REGDEF(SL,10,RN), REGDEF(FP,11,RN),
14478218822Sdim  REGDEF(IP,12,RN), REGDEF(SP,13,RN), REGDEF(LR,14,RN), REGDEF(PC,15,RN),
1447960484Sobrien
14480218822Sdim  /* Coprocessor numbers.  */
14481218822Sdim  REGSET(p, CP), REGSET(P, CP),
1448260484Sobrien
14483218822Sdim  /* Coprocessor register numbers.  The "cr" variants are for backward
14484218822Sdim     compatibility.  */
14485218822Sdim  REGSET(c,  CN), REGSET(C, CN),
14486218822Sdim  REGSET(cr, CN), REGSET(CR, CN),
1448760484Sobrien
14488218822Sdim  /* FPA registers.  */
14489218822Sdim  REGNUM(f,0,FN), REGNUM(f,1,FN), REGNUM(f,2,FN), REGNUM(f,3,FN),
14490218822Sdim  REGNUM(f,4,FN), REGNUM(f,5,FN), REGNUM(f,6,FN), REGNUM(f,7, FN),
1449160484Sobrien
14492218822Sdim  REGNUM(F,0,FN), REGNUM(F,1,FN), REGNUM(F,2,FN), REGNUM(F,3,FN),
14493218822Sdim  REGNUM(F,4,FN), REGNUM(F,5,FN), REGNUM(F,6,FN), REGNUM(F,7, FN),
1449460484Sobrien
14495218822Sdim  /* VFP SP registers.	*/
14496218822Sdim  REGSET(s,VFS),  REGSET(S,VFS),
14497218822Sdim  REGSETH(s,VFS), REGSETH(S,VFS),
1449860484Sobrien
14499218822Sdim  /* VFP DP Registers.	*/
14500218822Sdim  REGSET(d,VFD),  REGSET(D,VFD),
14501218822Sdim  /* Extra Neon DP registers.  */
14502218822Sdim  REGSETH(d,VFD), REGSETH(D,VFD),
1450360484Sobrien
14504218822Sdim  /* Neon QP registers.  */
14505218822Sdim  REGSET2(q,NQ),  REGSET2(Q,NQ),
1450660484Sobrien
14507218822Sdim  /* VFP control registers.  */
14508218822Sdim  REGDEF(fpsid,0,VFC), REGDEF(fpscr,1,VFC), REGDEF(fpexc,8,VFC),
14509218822Sdim  REGDEF(FPSID,0,VFC), REGDEF(FPSCR,1,VFC), REGDEF(FPEXC,8,VFC),
14510218822Sdim  REGDEF(fpinst,9,VFC), REGDEF(fpinst2,10,VFC),
14511218822Sdim  REGDEF(FPINST,9,VFC), REGDEF(FPINST2,10,VFC),
14512218822Sdim  REGDEF(mvfr0,7,VFC), REGDEF(mvfr1,6,VFC),
14513218822Sdim  REGDEF(MVFR0,7,VFC), REGDEF(MVFR1,6,VFC),
1451460484Sobrien
14515218822Sdim  /* Maverick DSP coprocessor registers.  */
14516218822Sdim  REGSET(mvf,MVF),  REGSET(mvd,MVD),  REGSET(mvfx,MVFX),  REGSET(mvdx,MVDX),
14517218822Sdim  REGSET(MVF,MVF),  REGSET(MVD,MVD),  REGSET(MVFX,MVFX),  REGSET(MVDX,MVDX),
1451860484Sobrien
14519218822Sdim  REGNUM(mvax,0,MVAX), REGNUM(mvax,1,MVAX),
14520218822Sdim  REGNUM(mvax,2,MVAX), REGNUM(mvax,3,MVAX),
14521218822Sdim  REGDEF(dspsc,0,DSPSC),
1452260484Sobrien
14523218822Sdim  REGNUM(MVAX,0,MVAX), REGNUM(MVAX,1,MVAX),
14524218822Sdim  REGNUM(MVAX,2,MVAX), REGNUM(MVAX,3,MVAX),
14525218822Sdim  REGDEF(DSPSC,0,DSPSC),
1452660484Sobrien
14527218822Sdim  /* iWMMXt data registers - p0, c0-15.	 */
14528218822Sdim  REGSET(wr,MMXWR), REGSET(wR,MMXWR), REGSET(WR, MMXWR),
1452960484Sobrien
14530218822Sdim  /* iWMMXt control registers - p1, c0-3.  */
14531218822Sdim  REGDEF(wcid,	0,MMXWC),  REGDEF(wCID,	 0,MMXWC),  REGDEF(WCID,  0,MMXWC),
14532218822Sdim  REGDEF(wcon,	1,MMXWC),  REGDEF(wCon,	 1,MMXWC),  REGDEF(WCON,  1,MMXWC),
14533218822Sdim  REGDEF(wcssf, 2,MMXWC),  REGDEF(wCSSF, 2,MMXWC),  REGDEF(WCSSF, 2,MMXWC),
14534218822Sdim  REGDEF(wcasf, 3,MMXWC),  REGDEF(wCASF, 3,MMXWC),  REGDEF(WCASF, 3,MMXWC),
1453560484Sobrien
14536218822Sdim  /* iWMMXt scalar (constant/offset) registers - p1, c8-11.  */
14537218822Sdim  REGDEF(wcgr0, 8,MMXWCG),  REGDEF(wCGR0, 8,MMXWCG),  REGDEF(WCGR0, 8,MMXWCG),
14538218822Sdim  REGDEF(wcgr1, 9,MMXWCG),  REGDEF(wCGR1, 9,MMXWCG),  REGDEF(WCGR1, 9,MMXWCG),
14539218822Sdim  REGDEF(wcgr2,10,MMXWCG),  REGDEF(wCGR2,10,MMXWCG),  REGDEF(WCGR2,10,MMXWCG),
14540218822Sdim  REGDEF(wcgr3,11,MMXWCG),  REGDEF(wCGR3,11,MMXWCG),  REGDEF(WCGR3,11,MMXWCG),
1454160484Sobrien
14542218822Sdim  /* XScale accumulator registers.  */
14543218822Sdim  REGNUM(acc,0,XSCALE), REGNUM(ACC,0,XSCALE),
14544218822Sdim};
14545218822Sdim#undef REGDEF
14546218822Sdim#undef REGNUM
14547218822Sdim#undef REGSET
1454860484Sobrien
14549218822Sdim/* Table of all PSR suffixes.  Bare "CPSR" and "SPSR" are handled
14550218822Sdim   within psr_required_here.  */
14551218822Sdimstatic const struct asm_psr psrs[] =
14552218822Sdim{
14553218822Sdim  /* Backward compatibility notation.  Note that "all" is no longer
14554218822Sdim     truly all possible PSR bits.  */
14555218822Sdim  {"all",  PSR_c | PSR_f},
14556218822Sdim  {"flg",  PSR_f},
14557218822Sdim  {"ctl",  PSR_c},
1455860484Sobrien
14559218822Sdim  /* Individual flags.	*/
14560218822Sdim  {"f",	   PSR_f},
14561218822Sdim  {"c",	   PSR_c},
14562218822Sdim  {"x",	   PSR_x},
14563218822Sdim  {"s",	   PSR_s},
14564218822Sdim  /* Combinations of flags.  */
14565218822Sdim  {"fs",   PSR_f | PSR_s},
14566218822Sdim  {"fx",   PSR_f | PSR_x},
14567218822Sdim  {"fc",   PSR_f | PSR_c},
14568218822Sdim  {"sf",   PSR_s | PSR_f},
14569218822Sdim  {"sx",   PSR_s | PSR_x},
14570218822Sdim  {"sc",   PSR_s | PSR_c},
14571218822Sdim  {"xf",   PSR_x | PSR_f},
14572218822Sdim  {"xs",   PSR_x | PSR_s},
14573218822Sdim  {"xc",   PSR_x | PSR_c},
14574218822Sdim  {"cf",   PSR_c | PSR_f},
14575218822Sdim  {"cs",   PSR_c | PSR_s},
14576218822Sdim  {"cx",   PSR_c | PSR_x},
14577218822Sdim  {"fsx",  PSR_f | PSR_s | PSR_x},
14578218822Sdim  {"fsc",  PSR_f | PSR_s | PSR_c},
14579218822Sdim  {"fxs",  PSR_f | PSR_x | PSR_s},
14580218822Sdim  {"fxc",  PSR_f | PSR_x | PSR_c},
14581218822Sdim  {"fcs",  PSR_f | PSR_c | PSR_s},
14582218822Sdim  {"fcx",  PSR_f | PSR_c | PSR_x},
14583218822Sdim  {"sfx",  PSR_s | PSR_f | PSR_x},
14584218822Sdim  {"sfc",  PSR_s | PSR_f | PSR_c},
14585218822Sdim  {"sxf",  PSR_s | PSR_x | PSR_f},
14586218822Sdim  {"sxc",  PSR_s | PSR_x | PSR_c},
14587218822Sdim  {"scf",  PSR_s | PSR_c | PSR_f},
14588218822Sdim  {"scx",  PSR_s | PSR_c | PSR_x},
14589218822Sdim  {"xfs",  PSR_x | PSR_f | PSR_s},
14590218822Sdim  {"xfc",  PSR_x | PSR_f | PSR_c},
14591218822Sdim  {"xsf",  PSR_x | PSR_s | PSR_f},
14592218822Sdim  {"xsc",  PSR_x | PSR_s | PSR_c},
14593218822Sdim  {"xcf",  PSR_x | PSR_c | PSR_f},
14594218822Sdim  {"xcs",  PSR_x | PSR_c | PSR_s},
14595218822Sdim  {"cfs",  PSR_c | PSR_f | PSR_s},
14596218822Sdim  {"cfx",  PSR_c | PSR_f | PSR_x},
14597218822Sdim  {"csf",  PSR_c | PSR_s | PSR_f},
14598218822Sdim  {"csx",  PSR_c | PSR_s | PSR_x},
14599218822Sdim  {"cxf",  PSR_c | PSR_x | PSR_f},
14600218822Sdim  {"cxs",  PSR_c | PSR_x | PSR_s},
14601218822Sdim  {"fsxc", PSR_f | PSR_s | PSR_x | PSR_c},
14602218822Sdim  {"fscx", PSR_f | PSR_s | PSR_c | PSR_x},
14603218822Sdim  {"fxsc", PSR_f | PSR_x | PSR_s | PSR_c},
14604218822Sdim  {"fxcs", PSR_f | PSR_x | PSR_c | PSR_s},
14605218822Sdim  {"fcsx", PSR_f | PSR_c | PSR_s | PSR_x},
14606218822Sdim  {"fcxs", PSR_f | PSR_c | PSR_x | PSR_s},
14607218822Sdim  {"sfxc", PSR_s | PSR_f | PSR_x | PSR_c},
14608218822Sdim  {"sfcx", PSR_s | PSR_f | PSR_c | PSR_x},
14609218822Sdim  {"sxfc", PSR_s | PSR_x | PSR_f | PSR_c},
14610218822Sdim  {"sxcf", PSR_s | PSR_x | PSR_c | PSR_f},
14611218822Sdim  {"scfx", PSR_s | PSR_c | PSR_f | PSR_x},
14612218822Sdim  {"scxf", PSR_s | PSR_c | PSR_x | PSR_f},
14613218822Sdim  {"xfsc", PSR_x | PSR_f | PSR_s | PSR_c},
14614218822Sdim  {"xfcs", PSR_x | PSR_f | PSR_c | PSR_s},
14615218822Sdim  {"xsfc", PSR_x | PSR_s | PSR_f | PSR_c},
14616218822Sdim  {"xscf", PSR_x | PSR_s | PSR_c | PSR_f},
14617218822Sdim  {"xcfs", PSR_x | PSR_c | PSR_f | PSR_s},
14618218822Sdim  {"xcsf", PSR_x | PSR_c | PSR_s | PSR_f},
14619218822Sdim  {"cfsx", PSR_c | PSR_f | PSR_s | PSR_x},
14620218822Sdim  {"cfxs", PSR_c | PSR_f | PSR_x | PSR_s},
14621218822Sdim  {"csfx", PSR_c | PSR_s | PSR_f | PSR_x},
14622218822Sdim  {"csxf", PSR_c | PSR_s | PSR_x | PSR_f},
14623218822Sdim  {"cxfs", PSR_c | PSR_x | PSR_f | PSR_s},
14624218822Sdim  {"cxsf", PSR_c | PSR_x | PSR_s | PSR_f},
14625218822Sdim};
1462660484Sobrien
14627218822Sdim/* Table of V7M psr names.  */
14628218822Sdimstatic const struct asm_psr v7m_psrs[] =
1462960484Sobrien{
14630218822Sdim  {"apsr",	  0 }, {"APSR",		0 },
14631218822Sdim  {"iapsr",	  1 }, {"IAPSR",	1 },
14632218822Sdim  {"eapsr",	  2 }, {"EAPSR",	2 },
14633218822Sdim  {"psr",	  3 }, {"PSR",		3 },
14634218822Sdim  {"xpsr",	  3 }, {"XPSR",		3 }, {"xPSR",	  3 },
14635218822Sdim  {"ipsr",	  5 }, {"IPSR",		5 },
14636218822Sdim  {"epsr",	  6 }, {"EPSR",		6 },
14637218822Sdim  {"iepsr",	  7 }, {"IEPSR",	7 },
14638218822Sdim  {"msp",	  8 }, {"MSP",		8 },
14639218822Sdim  {"psp",	  9 }, {"PSP",		9 },
14640218822Sdim  {"primask",	  16}, {"PRIMASK",	16},
14641218822Sdim  {"basepri",	  17}, {"BASEPRI",	17},
14642218822Sdim  {"basepri_max", 18}, {"BASEPRI_MAX",	18},
14643218822Sdim  {"faultmask",	  19}, {"FAULTMASK",	19},
14644218822Sdim  {"control",	  20}, {"CONTROL",	20}
14645218822Sdim};
1464660484Sobrien
14647218822Sdim/* Table of all shift-in-operand names.	 */
14648218822Sdimstatic const struct asm_shift_name shift_names [] =
1464960484Sobrien{
14650218822Sdim  { "asl", SHIFT_LSL },	 { "ASL", SHIFT_LSL },
14651218822Sdim  { "lsl", SHIFT_LSL },	 { "LSL", SHIFT_LSL },
14652218822Sdim  { "lsr", SHIFT_LSR },	 { "LSR", SHIFT_LSR },
14653218822Sdim  { "asr", SHIFT_ASR },	 { "ASR", SHIFT_ASR },
14654218822Sdim  { "ror", SHIFT_ROR },	 { "ROR", SHIFT_ROR },
14655218822Sdim  { "rrx", SHIFT_RRX },	 { "RRX", SHIFT_RRX }
14656218822Sdim};
1465760484Sobrien
14658218822Sdim/* Table of all explicit relocation names.  */
14659218822Sdim#ifdef OBJ_ELF
14660218822Sdimstatic struct reloc_entry reloc_names[] =
1466160484Sobrien{
14662218822Sdim  { "got",     BFD_RELOC_ARM_GOT32   },	 { "GOT",     BFD_RELOC_ARM_GOT32   },
14663218822Sdim  { "gotoff",  BFD_RELOC_ARM_GOTOFF  },	 { "GOTOFF",  BFD_RELOC_ARM_GOTOFF  },
14664218822Sdim  { "plt",     BFD_RELOC_ARM_PLT32   },	 { "PLT",     BFD_RELOC_ARM_PLT32   },
14665218822Sdim  { "target1", BFD_RELOC_ARM_TARGET1 },	 { "TARGET1", BFD_RELOC_ARM_TARGET1 },
14666218822Sdim  { "target2", BFD_RELOC_ARM_TARGET2 },	 { "TARGET2", BFD_RELOC_ARM_TARGET2 },
14667218822Sdim  { "sbrel",   BFD_RELOC_ARM_SBREL32 },	 { "SBREL",   BFD_RELOC_ARM_SBREL32 },
14668218822Sdim  { "tlsgd",   BFD_RELOC_ARM_TLS_GD32},  { "TLSGD",   BFD_RELOC_ARM_TLS_GD32},
14669218822Sdim  { "tlsldm",  BFD_RELOC_ARM_TLS_LDM32}, { "TLSLDM",  BFD_RELOC_ARM_TLS_LDM32},
14670218822Sdim  { "tlsldo",  BFD_RELOC_ARM_TLS_LDO32}, { "TLSLDO",  BFD_RELOC_ARM_TLS_LDO32},
14671218822Sdim  { "gottpoff",BFD_RELOC_ARM_TLS_IE32},  { "GOTTPOFF",BFD_RELOC_ARM_TLS_IE32},
14672218822Sdim  { "tpoff",   BFD_RELOC_ARM_TLS_LE32},  { "TPOFF",   BFD_RELOC_ARM_TLS_LE32}
14673218822Sdim};
14674218822Sdim#endif
1467560484Sobrien
14676218822Sdim/* Table of all conditional affixes.  0xF is not defined as a condition code.  */
14677218822Sdimstatic const struct asm_cond conds[] =
1467860484Sobrien{
14679218822Sdim  {"eq", 0x0},
14680218822Sdim  {"ne", 0x1},
14681218822Sdim  {"cs", 0x2}, {"hs", 0x2},
14682218822Sdim  {"cc", 0x3}, {"ul", 0x3}, {"lo", 0x3},
14683218822Sdim  {"mi", 0x4},
14684218822Sdim  {"pl", 0x5},
14685218822Sdim  {"vs", 0x6},
14686218822Sdim  {"vc", 0x7},
14687218822Sdim  {"hi", 0x8},
14688218822Sdim  {"ls", 0x9},
14689218822Sdim  {"ge", 0xa},
14690218822Sdim  {"lt", 0xb},
14691218822Sdim  {"gt", 0xc},
14692218822Sdim  {"le", 0xd},
14693218822Sdim  {"al", 0xe}
14694218822Sdim};
1469560484Sobrien
14696218822Sdimstatic struct asm_barrier_opt barrier_opt_names[] =
14697218822Sdim{
14698218822Sdim  { "sy",   0xf },
14699218822Sdim  { "un",   0x7 },
14700218822Sdim  { "st",   0xe },
14701218822Sdim  { "unst", 0x6 }
14702218822Sdim};
1470360484Sobrien
14704218822Sdim/* Table of ARM-format instructions.	*/
1470560484Sobrien
14706218822Sdim/* Macros for gluing together operand strings.  N.B. In all cases
14707218822Sdim   other than OPS0, the trailing OP_stop comes from default
14708218822Sdim   zero-initialization of the unspecified elements of the array.  */
14709218822Sdim#define OPS0()		  { OP_stop, }
14710218822Sdim#define OPS1(a)		  { OP_##a, }
14711218822Sdim#define OPS2(a,b)	  { OP_##a,OP_##b, }
14712218822Sdim#define OPS3(a,b,c)	  { OP_##a,OP_##b,OP_##c, }
14713218822Sdim#define OPS4(a,b,c,d)	  { OP_##a,OP_##b,OP_##c,OP_##d, }
14714218822Sdim#define OPS5(a,b,c,d,e)	  { OP_##a,OP_##b,OP_##c,OP_##d,OP_##e, }
14715218822Sdim#define OPS6(a,b,c,d,e,f) { OP_##a,OP_##b,OP_##c,OP_##d,OP_##e,OP_##f, }
1471660484Sobrien
14717218822Sdim/* These macros abstract out the exact format of the mnemonic table and
14718218822Sdim   save some repeated characters.  */
1471960484Sobrien
14720218822Sdim/* The normal sort of mnemonic; has a Thumb variant; takes a conditional suffix.  */
14721218822Sdim#define TxCE(mnem, op, top, nops, ops, ae, te) \
14722218822Sdim  { #mnem, OPS##nops ops, OT_csuffix, 0x##op, top, ARM_VARIANT, \
14723218822Sdim    THUMB_VARIANT, do_##ae, do_##te }
1472460484Sobrien
14725218822Sdim/* Two variants of the above - TCE for a numeric Thumb opcode, tCE for
14726218822Sdim   a T_MNEM_xyz enumerator.  */
14727218822Sdim#define TCE(mnem, aop, top, nops, ops, ae, te) \
14728218822Sdim       TxCE(mnem, aop, 0x##top, nops, ops, ae, te)
14729218822Sdim#define tCE(mnem, aop, top, nops, ops, ae, te) \
14730218822Sdim       TxCE(mnem, aop, T_MNEM_##top, nops, ops, ae, te)
1473160484Sobrien
14732218822Sdim/* Second most common sort of mnemonic: has a Thumb variant, takes a conditional
14733218822Sdim   infix after the third character.  */
14734218822Sdim#define TxC3(mnem, op, top, nops, ops, ae, te) \
14735218822Sdim  { #mnem, OPS##nops ops, OT_cinfix3, 0x##op, top, ARM_VARIANT, \
14736218822Sdim    THUMB_VARIANT, do_##ae, do_##te }
14737218822Sdim#define TxC3w(mnem, op, top, nops, ops, ae, te) \
14738218822Sdim  { #mnem, OPS##nops ops, OT_cinfix3_deprecated, 0x##op, top, ARM_VARIANT, \
14739218822Sdim    THUMB_VARIANT, do_##ae, do_##te }
14740218822Sdim#define TC3(mnem, aop, top, nops, ops, ae, te) \
14741218822Sdim       TxC3(mnem, aop, 0x##top, nops, ops, ae, te)
14742218822Sdim#define TC3w(mnem, aop, top, nops, ops, ae, te) \
14743218822Sdim       TxC3w(mnem, aop, 0x##top, nops, ops, ae, te)
14744218822Sdim#define tC3(mnem, aop, top, nops, ops, ae, te) \
14745218822Sdim       TxC3(mnem, aop, T_MNEM_##top, nops, ops, ae, te)
14746218822Sdim#define tC3w(mnem, aop, top, nops, ops, ae, te) \
14747218822Sdim       TxC3w(mnem, aop, T_MNEM_##top, nops, ops, ae, te)
1474860484Sobrien
14749218822Sdim/* Mnemonic with a conditional infix in an unusual place.  Each and every variant has to
14750218822Sdim   appear in the condition table.  */
14751218822Sdim#define TxCM_(m1, m2, m3, op, top, nops, ops, ae, te)	\
14752218822Sdim  { #m1 #m2 #m3, OPS##nops ops, sizeof(#m2) == 1 ? OT_odd_infix_unc : OT_odd_infix_0 + sizeof(#m1) - 1, \
14753218822Sdim    0x##op, top, ARM_VARIANT, THUMB_VARIANT, do_##ae, do_##te }
1475460484Sobrien
14755218822Sdim#define TxCM(m1, m2, op, top, nops, ops, ae, te)	\
14756218822Sdim  TxCM_(m1,   , m2, op, top, nops, ops, ae, te),	\
14757218822Sdim  TxCM_(m1, eq, m2, op, top, nops, ops, ae, te),	\
14758218822Sdim  TxCM_(m1, ne, m2, op, top, nops, ops, ae, te),	\
14759218822Sdim  TxCM_(m1, cs, m2, op, top, nops, ops, ae, te),	\
14760218822Sdim  TxCM_(m1, hs, m2, op, top, nops, ops, ae, te),	\
14761218822Sdim  TxCM_(m1, cc, m2, op, top, nops, ops, ae, te),	\
14762218822Sdim  TxCM_(m1, ul, m2, op, top, nops, ops, ae, te),	\
14763218822Sdim  TxCM_(m1, lo, m2, op, top, nops, ops, ae, te),	\
14764218822Sdim  TxCM_(m1, mi, m2, op, top, nops, ops, ae, te),	\
14765218822Sdim  TxCM_(m1, pl, m2, op, top, nops, ops, ae, te),	\
14766218822Sdim  TxCM_(m1, vs, m2, op, top, nops, ops, ae, te),	\
14767218822Sdim  TxCM_(m1, vc, m2, op, top, nops, ops, ae, te),	\
14768218822Sdim  TxCM_(m1, hi, m2, op, top, nops, ops, ae, te),	\
14769218822Sdim  TxCM_(m1, ls, m2, op, top, nops, ops, ae, te),	\
14770218822Sdim  TxCM_(m1, ge, m2, op, top, nops, ops, ae, te),	\
14771218822Sdim  TxCM_(m1, lt, m2, op, top, nops, ops, ae, te),	\
14772218822Sdim  TxCM_(m1, gt, m2, op, top, nops, ops, ae, te),	\
14773218822Sdim  TxCM_(m1, le, m2, op, top, nops, ops, ae, te),	\
14774218822Sdim  TxCM_(m1, al, m2, op, top, nops, ops, ae, te)
1477560484Sobrien
14776218822Sdim#define TCM(m1,m2, aop, top, nops, ops, ae, te)		\
14777218822Sdim       TxCM(m1,m2, aop, 0x##top, nops, ops, ae, te)
14778218822Sdim#define tCM(m1,m2, aop, top, nops, ops, ae, te)			\
14779218822Sdim       TxCM(m1,m2, aop, T_MNEM_##top, nops, ops, ae, te)
1478060484Sobrien
14781218822Sdim/* Mnemonic that cannot be conditionalized.  The ARM condition-code
14782218822Sdim   field is still 0xE.  Many of the Thumb variants can be executed
14783218822Sdim   conditionally, so this is checked separately.  */
14784218822Sdim#define TUE(mnem, op, top, nops, ops, ae, te)				\
14785218822Sdim  { #mnem, OPS##nops ops, OT_unconditional, 0x##op, 0x##top, ARM_VARIANT, \
14786218822Sdim    THUMB_VARIANT, do_##ae, do_##te }
1478760484Sobrien
14788218822Sdim/* Mnemonic that cannot be conditionalized, and bears 0xF in its ARM
14789218822Sdim   condition code field.  */
14790218822Sdim#define TUF(mnem, op, top, nops, ops, ae, te)				\
14791218822Sdim  { #mnem, OPS##nops ops, OT_unconditionalF, 0x##op, 0x##top, ARM_VARIANT, \
14792218822Sdim    THUMB_VARIANT, do_##ae, do_##te }
1479360484Sobrien
14794218822Sdim/* ARM-only variants of all the above.  */
14795218822Sdim#define CE(mnem,  op, nops, ops, ae)	\
14796218822Sdim  { #mnem, OPS##nops ops, OT_csuffix, 0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
1479760484Sobrien
14798218822Sdim#define C3(mnem, op, nops, ops, ae)	\
14799218822Sdim  { #mnem, OPS##nops ops, OT_cinfix3, 0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
1480060484Sobrien
14801218822Sdim/* Legacy mnemonics that always have conditional infix after the third
14802218822Sdim   character.  */
14803218822Sdim#define CL(mnem, op, nops, ops, ae)	\
14804218822Sdim  { #mnem, OPS##nops ops, OT_cinfix3_legacy, \
14805218822Sdim    0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
1480660484Sobrien
14807218822Sdim/* Coprocessor instructions.  Isomorphic between Arm and Thumb-2.  */
14808218822Sdim#define cCE(mnem,  op, nops, ops, ae)	\
14809218822Sdim  { #mnem, OPS##nops ops, OT_csuffix, 0x##op, 0xe##op, ARM_VARIANT, ARM_VARIANT, do_##ae, do_##ae }
1481077298Sobrien
14811218822Sdim/* Legacy coprocessor instructions where conditional infix and conditional
14812218822Sdim   suffix are ambiguous.  For consistency this includes all FPA instructions,
14813218822Sdim   not just the potentially ambiguous ones.  */
14814218822Sdim#define cCL(mnem, op, nops, ops, ae)	\
14815218822Sdim  { #mnem, OPS##nops ops, OT_cinfix3_legacy, \
14816218822Sdim    0x##op, 0xe##op, ARM_VARIANT, ARM_VARIANT, do_##ae, do_##ae }
1481760484Sobrien
14818218822Sdim/* Coprocessor, takes either a suffix or a position-3 infix
14819218822Sdim   (for an FPA corner case). */
14820218822Sdim#define C3E(mnem, op, nops, ops, ae) \
14821218822Sdim  { #mnem, OPS##nops ops, OT_csuf_or_in3, \
14822218822Sdim    0x##op, 0xe##op, ARM_VARIANT, ARM_VARIANT, do_##ae, do_##ae }
1482360484Sobrien
14824218822Sdim#define xCM_(m1, m2, m3, op, nops, ops, ae)	\
14825218822Sdim  { #m1 #m2 #m3, OPS##nops ops, \
14826218822Sdim    sizeof(#m2) == 1 ? OT_odd_infix_unc : OT_odd_infix_0 + sizeof(#m1) - 1, \
14827218822Sdim    0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
1482860484Sobrien
14829218822Sdim#define CM(m1, m2, op, nops, ops, ae)	\
14830218822Sdim  xCM_(m1,   , m2, op, nops, ops, ae),	\
14831218822Sdim  xCM_(m1, eq, m2, op, nops, ops, ae),	\
14832218822Sdim  xCM_(m1, ne, m2, op, nops, ops, ae),	\
14833218822Sdim  xCM_(m1, cs, m2, op, nops, ops, ae),	\
14834218822Sdim  xCM_(m1, hs, m2, op, nops, ops, ae),	\
14835218822Sdim  xCM_(m1, cc, m2, op, nops, ops, ae),	\
14836218822Sdim  xCM_(m1, ul, m2, op, nops, ops, ae),	\
14837218822Sdim  xCM_(m1, lo, m2, op, nops, ops, ae),	\
14838218822Sdim  xCM_(m1, mi, m2, op, nops, ops, ae),	\
14839218822Sdim  xCM_(m1, pl, m2, op, nops, ops, ae),	\
14840218822Sdim  xCM_(m1, vs, m2, op, nops, ops, ae),	\
14841218822Sdim  xCM_(m1, vc, m2, op, nops, ops, ae),	\
14842218822Sdim  xCM_(m1, hi, m2, op, nops, ops, ae),	\
14843218822Sdim  xCM_(m1, ls, m2, op, nops, ops, ae),	\
14844218822Sdim  xCM_(m1, ge, m2, op, nops, ops, ae),	\
14845218822Sdim  xCM_(m1, lt, m2, op, nops, ops, ae),	\
14846218822Sdim  xCM_(m1, gt, m2, op, nops, ops, ae),	\
14847218822Sdim  xCM_(m1, le, m2, op, nops, ops, ae),	\
14848218822Sdim  xCM_(m1, al, m2, op, nops, ops, ae)
1484960484Sobrien
14850218822Sdim#define UE(mnem, op, nops, ops, ae)	\
14851218822Sdim  { #mnem, OPS##nops ops, OT_unconditional, 0x##op, 0, ARM_VARIANT, 0, do_##ae, NULL }
1485260484Sobrien
14853218822Sdim#define UF(mnem, op, nops, ops, ae)	\
14854218822Sdim  { #mnem, OPS##nops ops, OT_unconditionalF, 0x##op, 0, ARM_VARIANT, 0, do_##ae, NULL }
1485560484Sobrien
14856218822Sdim/* Neon data-processing. ARM versions are unconditional with cond=0xf.
14857218822Sdim   The Thumb and ARM variants are mostly the same (bits 0-23 and 24/28), so we
14858218822Sdim   use the same encoding function for each.  */
14859218822Sdim#define NUF(mnem, op, nops, ops, enc)					\
14860218822Sdim  { #mnem, OPS##nops ops, OT_unconditionalF, 0x##op, 0x##op,		\
14861218822Sdim    ARM_VARIANT, THUMB_VARIANT, do_##enc, do_##enc }
1486260484Sobrien
14863218822Sdim/* Neon data processing, version which indirects through neon_enc_tab for
14864218822Sdim   the various overloaded versions of opcodes.  */
14865218822Sdim#define nUF(mnem, op, nops, ops, enc)					\
14866218822Sdim  { #mnem, OPS##nops ops, OT_unconditionalF, N_MNEM_##op, N_MNEM_##op,	\
14867218822Sdim    ARM_VARIANT, THUMB_VARIANT, do_##enc, do_##enc }
14868218822Sdim
14869218822Sdim/* Neon insn with conditional suffix for the ARM version, non-overloaded
14870218822Sdim   version.  */
14871218822Sdim#define NCE_tag(mnem, op, nops, ops, enc, tag)				\
14872218822Sdim  { #mnem, OPS##nops ops, tag, 0x##op, 0x##op, ARM_VARIANT,		\
14873218822Sdim    THUMB_VARIANT, do_##enc, do_##enc }
14874218822Sdim
14875218822Sdim#define NCE(mnem, op, nops, ops, enc)					\
14876218822Sdim  NCE_tag(mnem, op, nops, ops, enc, OT_csuffix)
14877218822Sdim
14878218822Sdim#define NCEF(mnem, op, nops, ops, enc)					\
14879218822Sdim  NCE_tag(mnem, op, nops, ops, enc, OT_csuffixF)
14880218822Sdim
14881218822Sdim/* Neon insn with conditional suffix for the ARM version, overloaded types.  */
14882218822Sdim#define nCE_tag(mnem, op, nops, ops, enc, tag)				\
14883218822Sdim  { #mnem, OPS##nops ops, tag, N_MNEM_##op, N_MNEM_##op,		\
14884218822Sdim    ARM_VARIANT, THUMB_VARIANT, do_##enc, do_##enc }
14885218822Sdim
14886218822Sdim#define nCE(mnem, op, nops, ops, enc)					\
14887218822Sdim  nCE_tag(mnem, op, nops, ops, enc, OT_csuffix)
14888218822Sdim
14889218822Sdim#define nCEF(mnem, op, nops, ops, enc)					\
14890218822Sdim  nCE_tag(mnem, op, nops, ops, enc, OT_csuffixF)
14891218822Sdim
14892218822Sdim#define do_0 0
14893218822Sdim
14894218822Sdim/* Thumb-only, unconditional.  */
14895218822Sdim#define UT(mnem,  op, nops, ops, te) TUE(mnem,  0, op, nops, ops, 0, te)
14896218822Sdim
14897218822Sdimstatic const struct asm_opcode insns[] =
1489889857Sobrien{
14899218822Sdim#define ARM_VARIANT &arm_ext_v1 /* Core ARM Instructions.  */
14900218822Sdim#define THUMB_VARIANT &arm_ext_v4t
14901218822Sdim tCE(and,	0000000, and,      3, (RR, oRR, SH), arit, t_arit3c),
14902218822Sdim tC3(ands,	0100000, ands,	   3, (RR, oRR, SH), arit, t_arit3c),
14903218822Sdim tCE(eor,	0200000, eor,	   3, (RR, oRR, SH), arit, t_arit3c),
14904218822Sdim tC3(eors,	0300000, eors,	   3, (RR, oRR, SH), arit, t_arit3c),
14905218822Sdim tCE(sub,	0400000, sub,	   3, (RR, oRR, SH), arit, t_add_sub),
14906218822Sdim tC3(subs,	0500000, subs,	   3, (RR, oRR, SH), arit, t_add_sub),
14907218822Sdim tCE(add,	0800000, add,	   3, (RR, oRR, SHG), arit, t_add_sub),
14908218822Sdim tC3(adds,	0900000, adds,	   3, (RR, oRR, SHG), arit, t_add_sub),
14909218822Sdim tCE(adc,	0a00000, adc,	   3, (RR, oRR, SH), arit, t_arit3c),
14910218822Sdim tC3(adcs,	0b00000, adcs,	   3, (RR, oRR, SH), arit, t_arit3c),
14911218822Sdim tCE(sbc,	0c00000, sbc,	   3, (RR, oRR, SH), arit, t_arit3),
14912218822Sdim tC3(sbcs,	0d00000, sbcs,	   3, (RR, oRR, SH), arit, t_arit3),
14913218822Sdim tCE(orr,	1800000, orr,	   3, (RR, oRR, SH), arit, t_arit3c),
14914218822Sdim tC3(orrs,	1900000, orrs,	   3, (RR, oRR, SH), arit, t_arit3c),
14915218822Sdim tCE(bic,	1c00000, bic,	   3, (RR, oRR, SH), arit, t_arit3),
14916218822Sdim tC3(bics,	1d00000, bics,	   3, (RR, oRR, SH), arit, t_arit3),
1491789857Sobrien
14918218822Sdim /* The p-variants of tst/cmp/cmn/teq (below) are the pre-V6 mechanism
14919218822Sdim    for setting PSR flag bits.  They are obsolete in V6 and do not
14920218822Sdim    have Thumb equivalents. */
14921218822Sdim tCE(tst,	1100000, tst,	   2, (RR, SH),      cmp,  t_mvn_tst),
14922218822Sdim tC3w(tsts,	1100000, tst,	   2, (RR, SH),      cmp,  t_mvn_tst),
14923218822Sdim  CL(tstp,	110f000,     	   2, (RR, SH),      cmp),
14924218822Sdim tCE(cmp,	1500000, cmp,	   2, (RR, SH),      cmp,  t_mov_cmp),
14925218822Sdim tC3w(cmps,	1500000, cmp,	   2, (RR, SH),      cmp,  t_mov_cmp),
14926218822Sdim  CL(cmpp,	150f000,     	   2, (RR, SH),      cmp),
14927218822Sdim tCE(cmn,	1700000, cmn,	   2, (RR, SH),      cmp,  t_mvn_tst),
14928218822Sdim tC3w(cmns,	1700000, cmn,	   2, (RR, SH),      cmp,  t_mvn_tst),
14929218822Sdim  CL(cmnp,	170f000,     	   2, (RR, SH),      cmp),
1493089857Sobrien
14931218822Sdim tCE(mov,	1a00000, mov,	   2, (RR, SH),      mov,  t_mov_cmp),
14932218822Sdim tC3(movs,	1b00000, movs,	   2, (RR, SH),      mov,  t_mov_cmp),
14933218822Sdim tCE(mvn,	1e00000, mvn,	   2, (RR, SH),      mov,  t_mvn_tst),
14934218822Sdim tC3(mvns,	1f00000, mvns,	   2, (RR, SH),      mov,  t_mvn_tst),
14935218822Sdim
14936218822Sdim tCE(ldr,	4100000, ldr,	   2, (RR, ADDRGLDR),ldst, t_ldst),
14937218822Sdim tC3(ldrb,	4500000, ldrb,	   2, (RR, ADDRGLDR),ldst, t_ldst),
14938218822Sdim tCE(str,	4000000, str,	   2, (RR, ADDRGLDR),ldst, t_ldst),
14939218822Sdim tC3(strb,	4400000, strb,	   2, (RR, ADDRGLDR),ldst, t_ldst),
14940218822Sdim
14941218822Sdim tCE(stm,	8800000, stmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
14942218822Sdim tC3(stmia,	8800000, stmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
14943218822Sdim tC3(stmea,	8800000, stmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
14944218822Sdim tCE(ldm,	8900000, ldmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
14945218822Sdim tC3(ldmia,	8900000, ldmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
14946218822Sdim tC3(ldmfd,	8900000, ldmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
14947218822Sdim
14948218822Sdim TCE(swi,	f000000, df00,     1, (EXPi),        swi, t_swi),
14949218822Sdim TCE(svc,	f000000, df00,     1, (EXPi),        swi, t_swi),
14950218822Sdim tCE(b,		a000000, b,	   1, (EXPr),	     branch, t_branch),
14951218822Sdim TCE(bl,	b000000, f000f800, 1, (EXPr),	     bl, t_branch23),
14952218822Sdim
14953218822Sdim  /* Pseudo ops.  */
14954218822Sdim tCE(adr,	28f0000, adr,	   2, (RR, EXP),     adr,  t_adr),
14955218822Sdim  C3(adrl,	28f0000,           2, (RR, EXP),     adrl),
14956218822Sdim tCE(nop,	1a00000, nop,	   1, (oI255c),	     nop,  t_nop),
14957218822Sdim
14958218822Sdim  /* Thumb-compatibility pseudo ops.  */
14959218822Sdim tCE(lsl,	1a00000, lsl,	   3, (RR, oRR, SH), shift, t_shift),
14960218822Sdim tC3(lsls,	1b00000, lsls,	   3, (RR, oRR, SH), shift, t_shift),
14961218822Sdim tCE(lsr,	1a00020, lsr,	   3, (RR, oRR, SH), shift, t_shift),
14962218822Sdim tC3(lsrs,	1b00020, lsrs,	   3, (RR, oRR, SH), shift, t_shift),
14963218822Sdim tCE(asr,	1a00040, asr,	   3, (RR, oRR, SH), shift, t_shift),
14964218822Sdim tC3(asrs,      1b00040, asrs,     3, (RR, oRR, SH), shift, t_shift),
14965218822Sdim tCE(ror,	1a00060, ror,	   3, (RR, oRR, SH), shift, t_shift),
14966218822Sdim tC3(rors,	1b00060, rors,	   3, (RR, oRR, SH), shift, t_shift),
14967218822Sdim tCE(neg,	2600000, neg,	   2, (RR, RR),      rd_rn, t_neg),
14968218822Sdim tC3(negs,	2700000, negs,	   2, (RR, RR),      rd_rn, t_neg),
14969218822Sdim tCE(push,	92d0000, push,     1, (REGLST),	     push_pop, t_push_pop),
14970218822Sdim tCE(pop,	8bd0000, pop,	   1, (REGLST),	     push_pop, t_push_pop),
14971218822Sdim
14972218822Sdim /* These may simplify to neg.  */
14973218822Sdim TCE(rsb,	0600000, ebc00000, 3, (RR, oRR, SH), arit, t_rsb),
14974218822Sdim TC3(rsbs,	0700000, ebd00000, 3, (RR, oRR, SH), arit, t_rsb),
14975218822Sdim
14976223484Sdim TCE(rrx,      1a00060, ea4f0030, 2, (RR, RR),      rd_rm, t_rd_rm),
14977223484Sdim TCE(rrxs,     1b00060, ea5f0030, 2, (RR, RR),      rd_rm, t_rd_rm),
14978223484Sdim
14979218822Sdim#undef THUMB_VARIANT
14980218822Sdim#define THUMB_VARIANT &arm_ext_v6
14981218822Sdim TCE(cpy,       1a00000, 4600,     2, (RR, RR),      rd_rm, t_cpy),
14982218822Sdim
14983218822Sdim /* V1 instructions with no Thumb analogue prior to V6T2.  */
14984218822Sdim#undef THUMB_VARIANT
14985218822Sdim#define THUMB_VARIANT &arm_ext_v6t2
14986218822Sdim TCE(teq,	1300000, ea900f00, 2, (RR, SH),      cmp,  t_mvn_tst),
14987218822Sdim TC3w(teqs,	1300000, ea900f00, 2, (RR, SH),      cmp,  t_mvn_tst),
14988218822Sdim  CL(teqp,	130f000,           2, (RR, SH),      cmp),
14989218822Sdim
14990218822Sdim TC3(ldrt,	4300000, f8500e00, 2, (RR, ADDR),    ldstt, t_ldstt),
14991218822Sdim TC3(ldrbt,	4700000, f8100e00, 2, (RR, ADDR),    ldstt, t_ldstt),
14992218822Sdim TC3(strt,	4200000, f8400e00, 2, (RR, ADDR),    ldstt, t_ldstt),
14993218822Sdim TC3(strbt,	4600000, f8000e00, 2, (RR, ADDR),    ldstt, t_ldstt),
14994218822Sdim
14995218822Sdim TC3(stmdb,	9000000, e9000000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
14996218822Sdim TC3(stmfd,     9000000, e9000000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
14997218822Sdim
14998218822Sdim TC3(ldmdb,	9100000, e9100000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
14999218822Sdim TC3(ldmea,	9100000, e9100000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
15000218822Sdim
15001218822Sdim /* V1 instructions with no Thumb analogue at all.  */
15002218822Sdim  CE(rsc,	0e00000,	   3, (RR, oRR, SH), arit),
15003218822Sdim  C3(rscs,	0f00000,	   3, (RR, oRR, SH), arit),
15004218822Sdim
15005218822Sdim  C3(stmib,	9800000,	   2, (RRw, REGLST), ldmstm),
15006218822Sdim  C3(stmfa,	9800000,	   2, (RRw, REGLST), ldmstm),
15007218822Sdim  C3(stmda,	8000000,	   2, (RRw, REGLST), ldmstm),
15008218822Sdim  C3(stmed,	8000000,	   2, (RRw, REGLST), ldmstm),
15009218822Sdim  C3(ldmib,	9900000,	   2, (RRw, REGLST), ldmstm),
15010218822Sdim  C3(ldmed,	9900000,	   2, (RRw, REGLST), ldmstm),
15011218822Sdim  C3(ldmda,	8100000,	   2, (RRw, REGLST), ldmstm),
15012218822Sdim  C3(ldmfa,	8100000,	   2, (RRw, REGLST), ldmstm),
15013218822Sdim
15014218822Sdim#undef ARM_VARIANT
15015218822Sdim#define ARM_VARIANT &arm_ext_v2	/* ARM 2 - multiplies.	*/
15016218822Sdim#undef THUMB_VARIANT
15017218822Sdim#define THUMB_VARIANT &arm_ext_v4t
15018218822Sdim tCE(mul,	0000090, mul,	   3, (RRnpc, RRnpc, oRR), mul, t_mul),
15019218822Sdim tC3(muls,	0100090, muls,	   3, (RRnpc, RRnpc, oRR), mul, t_mul),
15020218822Sdim
15021218822Sdim#undef THUMB_VARIANT
15022218822Sdim#define THUMB_VARIANT &arm_ext_v6t2
15023218822Sdim TCE(mla,	0200090, fb000000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mlas, t_mla),
15024218822Sdim  C3(mlas,	0300090,           4, (RRnpc, RRnpc, RRnpc, RRnpc), mlas),
15025218822Sdim
15026218822Sdim  /* Generic coprocessor instructions.	*/
15027218822Sdim TCE(cdp,	e000000, ee000000, 6, (RCP, I15b, RCN, RCN, RCN, oI7b), cdp,    cdp),
15028218822Sdim TCE(ldc,	c100000, ec100000, 3, (RCP, RCN, ADDRGLDC),	        lstc,   lstc),
15029218822Sdim TC3(ldcl,	c500000, ec500000, 3, (RCP, RCN, ADDRGLDC),	        lstc,   lstc),
15030218822Sdim TCE(stc,	c000000, ec000000, 3, (RCP, RCN, ADDRGLDC),	        lstc,   lstc),
15031218822Sdim TC3(stcl,	c400000, ec400000, 3, (RCP, RCN, ADDRGLDC),	        lstc,   lstc),
15032218822Sdim TCE(mcr,	e000010, ee000010, 6, (RCP, I7b, RR, RCN, RCN, oI7b),   co_reg, co_reg),
15033218822Sdim TCE(mrc,	e100010, ee100010, 6, (RCP, I7b, RR, RCN, RCN, oI7b),   co_reg, co_reg),
15034218822Sdim
15035218822Sdim#undef ARM_VARIANT
15036218822Sdim#define ARM_VARIANT &arm_ext_v2s /* ARM 3 - swp instructions.  */
15037218822Sdim  CE(swp,	1000090,           3, (RRnpc, RRnpc, RRnpcb), rd_rm_rn),
15038218822Sdim  C3(swpb,	1400090,           3, (RRnpc, RRnpc, RRnpcb), rd_rm_rn),
15039218822Sdim
15040218822Sdim#undef ARM_VARIANT
15041218822Sdim#define ARM_VARIANT &arm_ext_v3	/* ARM 6 Status register instructions.	*/
15042218822Sdim TCE(mrs,	10f0000, f3ef8000, 2, (APSR_RR, RVC_PSR), mrs, t_mrs),
15043218822Sdim TCE(msr,	120f000, f3808000, 2, (RVC_PSR, RR_EXi), msr, t_msr),
15044218822Sdim
15045218822Sdim#undef ARM_VARIANT
15046218822Sdim#define ARM_VARIANT &arm_ext_v3m	 /* ARM 7M long multiplies.  */
15047218822Sdim TCE(smull,	0c00090, fb800000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull, t_mull),
15048218822Sdim  CM(smull,s,	0d00090,           4, (RRnpc, RRnpc, RRnpc, RRnpc), mull),
15049218822Sdim TCE(umull,	0800090, fba00000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull, t_mull),
15050218822Sdim  CM(umull,s,	0900090,           4, (RRnpc, RRnpc, RRnpc, RRnpc), mull),
15051218822Sdim TCE(smlal,	0e00090, fbc00000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull, t_mull),
15052218822Sdim  CM(smlal,s,	0f00090,           4, (RRnpc, RRnpc, RRnpc, RRnpc), mull),
15053218822Sdim TCE(umlal,	0a00090, fbe00000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull, t_mull),
15054218822Sdim  CM(umlal,s,	0b00090,           4, (RRnpc, RRnpc, RRnpc, RRnpc), mull),
15055218822Sdim
15056218822Sdim#undef ARM_VARIANT
15057218822Sdim#define ARM_VARIANT &arm_ext_v4	/* ARM Architecture 4.	*/
15058218822Sdim#undef THUMB_VARIANT
15059218822Sdim#define THUMB_VARIANT &arm_ext_v4t
15060218822Sdim tC3(ldrh,	01000b0, ldrh,     2, (RR, ADDRGLDRS), ldstv4, t_ldst),
15061218822Sdim tC3(strh,	00000b0, strh,     2, (RR, ADDRGLDRS), ldstv4, t_ldst),
15062218822Sdim tC3(ldrsh,	01000f0, ldrsh,    2, (RR, ADDRGLDRS), ldstv4, t_ldst),
15063218822Sdim tC3(ldrsb,	01000d0, ldrsb,    2, (RR, ADDRGLDRS), ldstv4, t_ldst),
15064218822Sdim tCM(ld,sh,	01000f0, ldrsh,    2, (RR, ADDRGLDRS), ldstv4, t_ldst),
15065218822Sdim tCM(ld,sb,	01000d0, ldrsb,    2, (RR, ADDRGLDRS), ldstv4, t_ldst),
15066218822Sdim
15067218822Sdim#undef ARM_VARIANT
15068218822Sdim#define ARM_VARIANT &arm_ext_v4t_5
15069218822Sdim  /* ARM Architecture 4T.  */
15070218822Sdim  /* Note: bx (and blx) are required on V5, even if the processor does
15071218822Sdim     not support Thumb.	 */
15072218822Sdim TCE(bx,	12fff10, 4700, 1, (RR),	bx, t_bx),
15073218822Sdim
15074218822Sdim#undef ARM_VARIANT
15075218822Sdim#define ARM_VARIANT &arm_ext_v5 /*  ARM Architecture 5T.	 */
15076218822Sdim#undef THUMB_VARIANT
15077218822Sdim#define THUMB_VARIANT &arm_ext_v5t
15078218822Sdim  /* Note: blx has 2 variants; the .value coded here is for
15079218822Sdim     BLX(2).  Only this variant has conditional execution.  */
15080218822Sdim TCE(blx,	12fff30, 4780, 1, (RR_EXr),			    blx,  t_blx),
15081218822Sdim TUE(bkpt,	1200070, be00, 1, (oIffffb),			    bkpt, t_bkpt),
15082218822Sdim
15083218822Sdim#undef THUMB_VARIANT
15084218822Sdim#define THUMB_VARIANT &arm_ext_v6t2
15085218822Sdim TCE(clz,	16f0f10, fab0f080, 2, (RRnpc, RRnpc),		        rd_rm,  t_clz),
15086218822Sdim TUF(ldc2,	c100000, fc100000, 3, (RCP, RCN, ADDRGLDC),	        lstc,	lstc),
15087218822Sdim TUF(ldc2l,	c500000, fc500000, 3, (RCP, RCN, ADDRGLDC),		        lstc,	lstc),
15088218822Sdim TUF(stc2,	c000000, fc000000, 3, (RCP, RCN, ADDRGLDC),	        lstc,	lstc),
15089218822Sdim TUF(stc2l,	c400000, fc400000, 3, (RCP, RCN, ADDRGLDC),		        lstc,	lstc),
15090218822Sdim TUF(cdp2,	e000000, fe000000, 6, (RCP, I15b, RCN, RCN, RCN, oI7b), cdp,    cdp),
15091218822Sdim TUF(mcr2,	e000010, fe000010, 6, (RCP, I7b, RR, RCN, RCN, oI7b),   co_reg, co_reg),
15092218822Sdim TUF(mrc2,	e100010, fe100010, 6, (RCP, I7b, RR, RCN, RCN, oI7b),   co_reg, co_reg),
15093218822Sdim
15094218822Sdim#undef ARM_VARIANT
15095218822Sdim#define ARM_VARIANT &arm_ext_v5exp /*  ARM Architecture 5TExP.  */
15096218822Sdim TCE(smlabb,	1000080, fb100000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15097218822Sdim TCE(smlatb,	10000a0, fb100020, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15098218822Sdim TCE(smlabt,	10000c0, fb100010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15099218822Sdim TCE(smlatt,	10000e0, fb100030, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15100218822Sdim
15101218822Sdim TCE(smlawb,	1200080, fb300000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15102218822Sdim TCE(smlawt,	12000c0, fb300010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15103218822Sdim
15104218822Sdim TCE(smlalbb,	1400080, fbc00080, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smlal, t_mlal),
15105218822Sdim TCE(smlaltb,	14000a0, fbc000a0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smlal, t_mlal),
15106218822Sdim TCE(smlalbt,	14000c0, fbc00090, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smlal, t_mlal),
15107218822Sdim TCE(smlaltt,	14000e0, fbc000b0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smlal, t_mlal),
15108218822Sdim
15109218822Sdim TCE(smulbb,	1600080, fb10f000, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15110218822Sdim TCE(smultb,	16000a0, fb10f020, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15111218822Sdim TCE(smulbt,	16000c0, fb10f010, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15112218822Sdim TCE(smultt,	16000e0, fb10f030, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15113218822Sdim
15114218822Sdim TCE(smulwb,	12000a0, fb30f000, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15115218822Sdim TCE(smulwt,	12000e0, fb30f010, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15116218822Sdim
15117218822Sdim TCE(qadd,	1000050, fa80f080, 3, (RRnpc, RRnpc, RRnpc),	    rd_rm_rn, rd_rm_rn),
15118218822Sdim TCE(qdadd,	1400050, fa80f090, 3, (RRnpc, RRnpc, RRnpc),	    rd_rm_rn, rd_rm_rn),
15119218822Sdim TCE(qsub,	1200050, fa80f0a0, 3, (RRnpc, RRnpc, RRnpc),	    rd_rm_rn, rd_rm_rn),
15120218822Sdim TCE(qdsub,	1600050, fa80f0b0, 3, (RRnpc, RRnpc, RRnpc),	    rd_rm_rn, rd_rm_rn),
15121218822Sdim
15122218822Sdim#undef ARM_VARIANT
15123218822Sdim#define ARM_VARIANT &arm_ext_v5e /*  ARM Architecture 5TE.  */
15124218822Sdim TUF(pld,	450f000, f810f000, 1, (ADDR),		     pld,  t_pld),
15125218822Sdim TC3(ldrd,	00000d0, e8500000, 3, (RRnpc, oRRnpc, ADDRGLDRS), ldrd, t_ldstd),
15126218822Sdim TC3(strd,	00000f0, e8400000, 3, (RRnpc, oRRnpc, ADDRGLDRS), ldrd, t_ldstd),
15127218822Sdim
15128218822Sdim TCE(mcrr,	c400000, ec400000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
15129218822Sdim TCE(mrrc,	c500000, ec500000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
15130218822Sdim
15131218822Sdim#undef ARM_VARIANT
15132218822Sdim#define ARM_VARIANT &arm_ext_v5j /*  ARM Architecture 5TEJ.  */
15133218822Sdim TCE(bxj,	12fff20, f3c08f00, 1, (RR),			  bxj, t_bxj),
15134218822Sdim
15135218822Sdim#undef ARM_VARIANT
15136218822Sdim#define ARM_VARIANT &arm_ext_v6 /*  ARM V6.  */
15137218822Sdim#undef THUMB_VARIANT
15138218822Sdim#define THUMB_VARIANT &arm_ext_v6
15139218822Sdim TUF(cpsie,     1080000, b660,     2, (CPSF, oI31b),              cpsi,   t_cpsi),
15140218822Sdim TUF(cpsid,     10c0000, b670,     2, (CPSF, oI31b),              cpsi,   t_cpsi),
15141218822Sdim tCE(rev,       6bf0f30, rev,      2, (RRnpc, RRnpc),             rd_rm,  t_rev),
15142218822Sdim tCE(rev16,     6bf0fb0, rev16,    2, (RRnpc, RRnpc),             rd_rm,  t_rev),
15143218822Sdim tCE(revsh,     6ff0fb0, revsh,    2, (RRnpc, RRnpc),             rd_rm,  t_rev),
15144218822Sdim tCE(sxth,      6bf0070, sxth,     3, (RRnpc, RRnpc, oROR),       sxth,   t_sxth),
15145218822Sdim tCE(uxth,      6ff0070, uxth,     3, (RRnpc, RRnpc, oROR),       sxth,   t_sxth),
15146218822Sdim tCE(sxtb,      6af0070, sxtb,     3, (RRnpc, RRnpc, oROR),       sxth,   t_sxth),
15147218822Sdim tCE(uxtb,      6ef0070, uxtb,     3, (RRnpc, RRnpc, oROR),       sxth,   t_sxth),
15148218822Sdim TUF(setend,    1010000, b650,     1, (ENDI),                     setend, t_setend),
15149218822Sdim
15150218822Sdim#undef THUMB_VARIANT
15151218822Sdim#define THUMB_VARIANT &arm_ext_v6t2
15152218822Sdim TCE(ldrex,	1900f9f, e8500f00, 2, (RRnpc, ADDR),		  ldrex, t_ldrex),
15153218822Sdim TCE(strex,	1800f90, e8400000, 3, (RRnpc, RRnpc, ADDR),	   strex,  t_strex),
15154218822Sdim TUF(mcrr2,	c400000, fc400000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
15155218822Sdim TUF(mrrc2,	c500000, fc500000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
15156218822Sdim
15157218822Sdim TCE(ssat,	6a00010, f3000000, 4, (RRnpc, I32, RRnpc, oSHllar),ssat,   t_ssat),
15158218822Sdim TCE(usat,	6e00010, f3800000, 4, (RRnpc, I31, RRnpc, oSHllar),usat,   t_usat),
15159218822Sdim
15160218822Sdim/*  ARM V6 not included in V7M (eg. integer SIMD).  */
15161218822Sdim#undef THUMB_VARIANT
15162218822Sdim#define THUMB_VARIANT &arm_ext_v6_notm
15163218822Sdim TUF(cps,	1020000, f3af8100, 1, (I31b),			  imm0, t_cps),
15164218822Sdim TCE(pkhbt,	6800010, eac00000, 4, (RRnpc, RRnpc, RRnpc, oSHll),   pkhbt, t_pkhbt),
15165218822Sdim TCE(pkhtb,	6800050, eac00020, 4, (RRnpc, RRnpc, RRnpc, oSHar),   pkhtb, t_pkhtb),
15166218822Sdim TCE(qadd16,	6200f10, fa90f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15167218822Sdim TCE(qadd8,	6200f90, fa80f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15168218822Sdim TCE(qaddsubx,	6200f30, faa0f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15169218822Sdim TCE(qsub16,	6200f70, fad0f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15170218822Sdim TCE(qsub8,	6200ff0, fac0f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15171218822Sdim TCE(qsubaddx,	6200f50, fae0f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15172218822Sdim TCE(sadd16,	6100f10, fa90f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15173218822Sdim TCE(sadd8,	6100f90, fa80f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15174218822Sdim TCE(saddsubx,	6100f30, faa0f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15175218822Sdim TCE(shadd16,	6300f10, fa90f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15176218822Sdim TCE(shadd8,	6300f90, fa80f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15177218822Sdim TCE(shaddsubx, 6300f30, faa0f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15178218822Sdim TCE(shsub16,	6300f70, fad0f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15179218822Sdim TCE(shsub8,	6300ff0, fac0f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15180218822Sdim TCE(shsubaddx, 6300f50, fae0f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15181218822Sdim TCE(ssub16,	6100f70, fad0f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15182218822Sdim TCE(ssub8,	6100ff0, fac0f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15183218822Sdim TCE(ssubaddx,	6100f50, fae0f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15184218822Sdim TCE(uadd16,	6500f10, fa90f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15185218822Sdim TCE(uadd8,	6500f90, fa80f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15186218822Sdim TCE(uaddsubx,	6500f30, faa0f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15187218822Sdim TCE(uhadd16,	6700f10, fa90f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15188218822Sdim TCE(uhadd8,	6700f90, fa80f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15189218822Sdim TCE(uhaddsubx, 6700f30, faa0f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15190218822Sdim TCE(uhsub16,	6700f70, fad0f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15191218822Sdim TCE(uhsub8,	6700ff0, fac0f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15192218822Sdim TCE(uhsubaddx, 6700f50, fae0f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15193218822Sdim TCE(uqadd16,	6600f10, fa90f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15194218822Sdim TCE(uqadd8,	6600f90, fa80f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15195218822Sdim TCE(uqaddsubx, 6600f30, faa0f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15196218822Sdim TCE(uqsub16,	6600f70, fad0f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15197218822Sdim TCE(uqsub8,	6600ff0, fac0f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15198218822Sdim TCE(uqsubaddx, 6600f50, fae0f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15199218822Sdim TCE(usub16,	6500f70, fad0f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15200218822Sdim TCE(usub8,	6500ff0, fac0f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15201218822Sdim TCE(usubaddx,	6500f50, fae0f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15202218822Sdim TUF(rfeia,	8900a00, e990c000, 1, (RRw),			   rfe, rfe),
15203218822Sdim  UF(rfeib,	9900a00,           1, (RRw),			   rfe),
15204218822Sdim  UF(rfeda,	8100a00,           1, (RRw),			   rfe),
15205218822Sdim TUF(rfedb,	9100a00, e810c000, 1, (RRw),			   rfe, rfe),
15206218822Sdim TUF(rfefd,	8900a00, e990c000, 1, (RRw),			   rfe, rfe),
15207218822Sdim  UF(rfefa,	9900a00,           1, (RRw),			   rfe),
15208218822Sdim  UF(rfeea,	8100a00,           1, (RRw),			   rfe),
15209218822Sdim TUF(rfeed,	9100a00, e810c000, 1, (RRw),			   rfe, rfe),
15210218822Sdim TCE(sxtah,	6b00070, fa00f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15211218822Sdim TCE(sxtab16,	6800070, fa20f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15212218822Sdim TCE(sxtab,	6a00070, fa40f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15213218822Sdim TCE(sxtb16,	68f0070, fa2ff080, 3, (RRnpc, RRnpc, oROR),	   sxth,  t_sxth),
15214218822Sdim TCE(uxtah,	6f00070, fa10f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15215218822Sdim TCE(uxtab16,	6c00070, fa30f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15216218822Sdim TCE(uxtab,	6e00070, fa50f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15217218822Sdim TCE(uxtb16,	6cf0070, fa3ff080, 3, (RRnpc, RRnpc, oROR),	   sxth,  t_sxth),
15218218822Sdim TCE(sel,	6800fb0, faa0f080, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15219218822Sdim TCE(smlad,	7000010, fb200000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15220218822Sdim TCE(smladx,	7000030, fb200010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15221218822Sdim TCE(smlald,	7400010, fbc000c0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,t_mlal),
15222218822Sdim TCE(smlaldx,	7400030, fbc000d0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,t_mlal),
15223218822Sdim TCE(smlsd,	7000050, fb400000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15224218822Sdim TCE(smlsdx,	7000070, fb400010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15225218822Sdim TCE(smlsld,	7400050, fbd000c0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,t_mlal),
15226218822Sdim TCE(smlsldx,	7400070, fbd000d0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,t_mlal),
15227218822Sdim TCE(smmla,	7500010, fb500000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15228218822Sdim TCE(smmlar,	7500030, fb500010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15229218822Sdim TCE(smmls,	75000d0, fb600000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15230218822Sdim TCE(smmlsr,	75000f0, fb600010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15231218822Sdim TCE(smmul,	750f010, fb50f000, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15232218822Sdim TCE(smmulr,	750f030, fb50f010, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15233218822Sdim TCE(smuad,	700f010, fb20f000, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15234218822Sdim TCE(smuadx,	700f030, fb20f010, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15235218822Sdim TCE(smusd,	700f050, fb40f000, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15236218822Sdim TCE(smusdx,	700f070, fb40f010, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15237218822Sdim TUF(srsia,	8c00500, e980c000, 2, (oRRw, I31w),		   srs,  srs),
15238218822Sdim  UF(srsib,	9c00500,           2, (oRRw, I31w),		   srs),
15239218822Sdim  UF(srsda,	8400500,	   2, (oRRw, I31w),		   srs),
15240218822Sdim TUF(srsdb,	9400500, e800c000, 2, (oRRw, I31w),		   srs,  srs),
15241218822Sdim TCE(ssat16,	6a00f30, f3200000, 3, (RRnpc, I16, RRnpc),	   ssat16, t_ssat16),
15242218822Sdim TCE(umaal,	0400090, fbe00060, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,  t_mlal),
15243218822Sdim TCE(usad8,	780f010, fb70f000, 3, (RRnpc, RRnpc, RRnpc),	   smul,   t_simd),
15244218822Sdim TCE(usada8,	7800010, fb700000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla,   t_mla),
15245218822Sdim TCE(usat16,	6e00f30, f3a00000, 3, (RRnpc, I15, RRnpc),	   usat16, t_usat16),
15246218822Sdim
15247218822Sdim#undef ARM_VARIANT
15248218822Sdim#define ARM_VARIANT &arm_ext_v6k
15249218822Sdim#undef THUMB_VARIANT
15250218822Sdim#define THUMB_VARIANT &arm_ext_v6k
15251218822Sdim tCE(yield,	320f001, yield,    0, (), noargs, t_hint),
15252218822Sdim tCE(wfe,	320f002, wfe,      0, (), noargs, t_hint),
15253218822Sdim tCE(wfi,	320f003, wfi,      0, (), noargs, t_hint),
15254218822Sdim tCE(sev,	320f004, sev,      0, (), noargs, t_hint),
15255218822Sdim
15256218822Sdim#undef THUMB_VARIANT
15257218822Sdim#define THUMB_VARIANT &arm_ext_v6_notm
15258218822Sdim TCE(ldrexd,	1b00f9f, e8d0007f, 3, (RRnpc, oRRnpc, RRnpcb),        ldrexd, t_ldrexd),
15259218822Sdim TCE(strexd,	1a00f90, e8c00070, 4, (RRnpc, RRnpc, oRRnpc, RRnpcb), strexd, t_strexd),
15260218822Sdim
15261218822Sdim#undef THUMB_VARIANT
15262218822Sdim#define THUMB_VARIANT &arm_ext_v6t2
15263218822Sdim TCE(ldrexb,	1d00f9f, e8d00f4f, 2, (RRnpc, RRnpcb),	              rd_rn,  rd_rn),
15264218822Sdim TCE(ldrexh,	1f00f9f, e8d00f5f, 2, (RRnpc, RRnpcb),	              rd_rn,  rd_rn),
15265218822Sdim TCE(strexb,	1c00f90, e8c00f40, 3, (RRnpc, RRnpc, ADDR),           strex,  rm_rd_rn),
15266218822Sdim TCE(strexh,	1e00f90, e8c00f50, 3, (RRnpc, RRnpc, ADDR),           strex,  rm_rd_rn),
15267218822Sdim TUF(clrex,	57ff01f, f3bf8f2f, 0, (),			      noargs, noargs),
15268218822Sdim
15269218822Sdim#undef ARM_VARIANT
15270218822Sdim#define ARM_VARIANT &arm_ext_v6z
15271218822Sdim TCE(smc,	1600070, f7f08000, 1, (EXPi), smc, t_smc),
15272218822Sdim
15273218822Sdim#undef ARM_VARIANT
15274218822Sdim#define ARM_VARIANT &arm_ext_v6t2
15275218822Sdim TCE(bfc,	7c0001f, f36f0000, 3, (RRnpc, I31, I32),	   bfc, t_bfc),
15276218822Sdim TCE(bfi,	7c00010, f3600000, 4, (RRnpc, RRnpc_I0, I31, I32), bfi, t_bfi),
15277218822Sdim TCE(sbfx,	7a00050, f3400000, 4, (RR, RR, I31, I32),	   bfx, t_bfx),
15278218822Sdim TCE(ubfx,	7e00050, f3c00000, 4, (RR, RR, I31, I32),	   bfx, t_bfx),
15279218822Sdim
15280218822Sdim TCE(mls,	0600090, fb000010, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mlas, t_mla),
15281218822Sdim TCE(movw,	3000000, f2400000, 2, (RRnpc, HALF),		    mov16, t_mov16),
15282218822Sdim TCE(movt,	3400000, f2c00000, 2, (RRnpc, HALF),		    mov16, t_mov16),
15283218822Sdim TCE(rbit,	6ff0f30, fa90f0a0, 2, (RR, RR),			    rd_rm, t_rbit),
15284218822Sdim
15285218822Sdim TC3(ldrht,	03000b0, f8300e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
15286218822Sdim TC3(ldrsht,	03000f0, f9300e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
15287218822Sdim TC3(ldrsbt,	03000d0, f9100e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
15288218822Sdim TC3(strht,	02000b0, f8200e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
15289218822Sdim
15290218822Sdim  UT(cbnz,      b900,    2, (RR, EXP), t_cbz),
15291218822Sdim  UT(cbz,       b100,    2, (RR, EXP), t_cbz),
15292218822Sdim /* ARM does not really have an IT instruction, so always allow it.  */
15293218822Sdim#undef ARM_VARIANT
15294218822Sdim#define ARM_VARIANT &arm_ext_v1
15295218822Sdim TUE(it,        0, bf08, 1, (COND),    it, t_it),
15296218822Sdim TUE(itt,       0, bf0c, 1, (COND),    it, t_it),
15297218822Sdim TUE(ite,       0, bf04, 1, (COND),    it, t_it),
15298218822Sdim TUE(ittt,      0, bf0e, 1, (COND),    it, t_it),
15299218822Sdim TUE(itet,      0, bf06, 1, (COND),    it, t_it),
15300218822Sdim TUE(itte,      0, bf0a, 1, (COND),    it, t_it),
15301218822Sdim TUE(itee,      0, bf02, 1, (COND),    it, t_it),
15302218822Sdim TUE(itttt,     0, bf0f, 1, (COND),    it, t_it),
15303218822Sdim TUE(itett,     0, bf07, 1, (COND),    it, t_it),
15304218822Sdim TUE(ittet,     0, bf0b, 1, (COND),    it, t_it),
15305218822Sdim TUE(iteet,     0, bf03, 1, (COND),    it, t_it),
15306218822Sdim TUE(ittte,     0, bf0d, 1, (COND),    it, t_it),
15307218822Sdim TUE(itete,     0, bf05, 1, (COND),    it, t_it),
15308218822Sdim TUE(ittee,     0, bf09, 1, (COND),    it, t_it),
15309218822Sdim TUE(iteee,     0, bf01, 1, (COND),    it, t_it),
15310218822Sdim
15311218822Sdim /* Thumb2 only instructions.  */
15312218822Sdim#undef ARM_VARIANT
15313218822Sdim#define ARM_VARIANT NULL
15314218822Sdim
15315218822Sdim TCE(addw,	0, f2000000, 3, (RR, RR, EXPi), 0, t_add_sub_w),
15316218822Sdim TCE(subw,	0, f2a00000, 3, (RR, RR, EXPi), 0, t_add_sub_w),
15317218822Sdim TCE(tbb,       0, e8d0f000, 1, (TB), 0, t_tb),
15318218822Sdim TCE(tbh,       0, e8d0f010, 1, (TB), 0, t_tb),
15319218822Sdim
15320218822Sdim /* Thumb-2 hardware division instructions (R and M profiles only).  */
15321218822Sdim#undef THUMB_VARIANT
15322218822Sdim#define THUMB_VARIANT &arm_ext_div
15323218822Sdim TCE(sdiv,	0, fb90f0f0, 3, (RR, oRR, RR), 0, t_div),
15324218822Sdim TCE(udiv,	0, fbb0f0f0, 3, (RR, oRR, RR), 0, t_div),
15325218822Sdim
15326218822Sdim /* ARM V7 instructions.  */
15327218822Sdim#undef ARM_VARIANT
15328218822Sdim#define ARM_VARIANT &arm_ext_v7
15329218822Sdim#undef THUMB_VARIANT
15330218822Sdim#define THUMB_VARIANT &arm_ext_v7
15331218822Sdim TUF(pli,	450f000, f910f000, 1, (ADDR),	  pli,	    t_pld),
15332218822Sdim TCE(dbg,	320f0f0, f3af80f0, 1, (I15),	  dbg,	    t_dbg),
15333218822Sdim TUF(dmb,	57ff050, f3bf8f50, 1, (oBARRIER), barrier,  t_barrier),
15334218822Sdim TUF(dsb,	57ff040, f3bf8f40, 1, (oBARRIER), barrier,  t_barrier),
15335218822Sdim TUF(isb,	57ff060, f3bf8f60, 1, (oBARRIER), barrier,  t_barrier),
15336218822Sdim
15337218822Sdim#undef ARM_VARIANT
15338218822Sdim#define ARM_VARIANT &fpu_fpa_ext_v1  /* Core FPA instruction set (V1).  */
15339218822Sdim cCE(wfs,	e200110, 1, (RR),	     rd),
15340218822Sdim cCE(rfs,	e300110, 1, (RR),	     rd),
15341218822Sdim cCE(wfc,	e400110, 1, (RR),	     rd),
15342218822Sdim cCE(rfc,	e500110, 1, (RR),	     rd),
15343218822Sdim
15344218822Sdim cCL(ldfs,	c100100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15345218822Sdim cCL(ldfd,	c108100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15346218822Sdim cCL(ldfe,	c500100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15347218822Sdim cCL(ldfp,	c508100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15348218822Sdim
15349218822Sdim cCL(stfs,	c000100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15350218822Sdim cCL(stfd,	c008100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15351218822Sdim cCL(stfe,	c400100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15352218822Sdim cCL(stfp,	c408100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15353218822Sdim
15354218822Sdim cCL(mvfs,	e008100, 2, (RF, RF_IF),     rd_rm),
15355218822Sdim cCL(mvfsp,	e008120, 2, (RF, RF_IF),     rd_rm),
15356218822Sdim cCL(mvfsm,	e008140, 2, (RF, RF_IF),     rd_rm),
15357218822Sdim cCL(mvfsz,	e008160, 2, (RF, RF_IF),     rd_rm),
15358218822Sdim cCL(mvfd,	e008180, 2, (RF, RF_IF),     rd_rm),
15359218822Sdim cCL(mvfdp,	e0081a0, 2, (RF, RF_IF),     rd_rm),
15360218822Sdim cCL(mvfdm,	e0081c0, 2, (RF, RF_IF),     rd_rm),
15361218822Sdim cCL(mvfdz,	e0081e0, 2, (RF, RF_IF),     rd_rm),
15362218822Sdim cCL(mvfe,	e088100, 2, (RF, RF_IF),     rd_rm),
15363218822Sdim cCL(mvfep,	e088120, 2, (RF, RF_IF),     rd_rm),
15364218822Sdim cCL(mvfem,	e088140, 2, (RF, RF_IF),     rd_rm),
15365218822Sdim cCL(mvfez,	e088160, 2, (RF, RF_IF),     rd_rm),
15366218822Sdim
15367218822Sdim cCL(mnfs,	e108100, 2, (RF, RF_IF),     rd_rm),
15368218822Sdim cCL(mnfsp,	e108120, 2, (RF, RF_IF),     rd_rm),
15369218822Sdim cCL(mnfsm,	e108140, 2, (RF, RF_IF),     rd_rm),
15370218822Sdim cCL(mnfsz,	e108160, 2, (RF, RF_IF),     rd_rm),
15371218822Sdim cCL(mnfd,	e108180, 2, (RF, RF_IF),     rd_rm),
15372218822Sdim cCL(mnfdp,	e1081a0, 2, (RF, RF_IF),     rd_rm),
15373218822Sdim cCL(mnfdm,	e1081c0, 2, (RF, RF_IF),     rd_rm),
15374218822Sdim cCL(mnfdz,	e1081e0, 2, (RF, RF_IF),     rd_rm),
15375218822Sdim cCL(mnfe,	e188100, 2, (RF, RF_IF),     rd_rm),
15376218822Sdim cCL(mnfep,	e188120, 2, (RF, RF_IF),     rd_rm),
15377218822Sdim cCL(mnfem,	e188140, 2, (RF, RF_IF),     rd_rm),
15378218822Sdim cCL(mnfez,	e188160, 2, (RF, RF_IF),     rd_rm),
15379218822Sdim
15380218822Sdim cCL(abss,	e208100, 2, (RF, RF_IF),     rd_rm),
15381218822Sdim cCL(abssp,	e208120, 2, (RF, RF_IF),     rd_rm),
15382218822Sdim cCL(abssm,	e208140, 2, (RF, RF_IF),     rd_rm),
15383218822Sdim cCL(abssz,	e208160, 2, (RF, RF_IF),     rd_rm),
15384218822Sdim cCL(absd,	e208180, 2, (RF, RF_IF),     rd_rm),
15385218822Sdim cCL(absdp,	e2081a0, 2, (RF, RF_IF),     rd_rm),
15386218822Sdim cCL(absdm,	e2081c0, 2, (RF, RF_IF),     rd_rm),
15387218822Sdim cCL(absdz,	e2081e0, 2, (RF, RF_IF),     rd_rm),
15388218822Sdim cCL(abse,	e288100, 2, (RF, RF_IF),     rd_rm),
15389218822Sdim cCL(absep,	e288120, 2, (RF, RF_IF),     rd_rm),
15390218822Sdim cCL(absem,	e288140, 2, (RF, RF_IF),     rd_rm),
15391218822Sdim cCL(absez,	e288160, 2, (RF, RF_IF),     rd_rm),
15392218822Sdim
15393218822Sdim cCL(rnds,	e308100, 2, (RF, RF_IF),     rd_rm),
15394218822Sdim cCL(rndsp,	e308120, 2, (RF, RF_IF),     rd_rm),
15395218822Sdim cCL(rndsm,	e308140, 2, (RF, RF_IF),     rd_rm),
15396218822Sdim cCL(rndsz,	e308160, 2, (RF, RF_IF),     rd_rm),
15397218822Sdim cCL(rndd,	e308180, 2, (RF, RF_IF),     rd_rm),
15398218822Sdim cCL(rnddp,	e3081a0, 2, (RF, RF_IF),     rd_rm),
15399218822Sdim cCL(rnddm,	e3081c0, 2, (RF, RF_IF),     rd_rm),
15400218822Sdim cCL(rnddz,	e3081e0, 2, (RF, RF_IF),     rd_rm),
15401218822Sdim cCL(rnde,	e388100, 2, (RF, RF_IF),     rd_rm),
15402218822Sdim cCL(rndep,	e388120, 2, (RF, RF_IF),     rd_rm),
15403218822Sdim cCL(rndem,	e388140, 2, (RF, RF_IF),     rd_rm),
15404218822Sdim cCL(rndez,	e388160, 2, (RF, RF_IF),     rd_rm),
15405218822Sdim
15406218822Sdim cCL(sqts,	e408100, 2, (RF, RF_IF),     rd_rm),
15407218822Sdim cCL(sqtsp,	e408120, 2, (RF, RF_IF),     rd_rm),
15408218822Sdim cCL(sqtsm,	e408140, 2, (RF, RF_IF),     rd_rm),
15409218822Sdim cCL(sqtsz,	e408160, 2, (RF, RF_IF),     rd_rm),
15410218822Sdim cCL(sqtd,	e408180, 2, (RF, RF_IF),     rd_rm),
15411218822Sdim cCL(sqtdp,	e4081a0, 2, (RF, RF_IF),     rd_rm),
15412218822Sdim cCL(sqtdm,	e4081c0, 2, (RF, RF_IF),     rd_rm),
15413218822Sdim cCL(sqtdz,	e4081e0, 2, (RF, RF_IF),     rd_rm),
15414218822Sdim cCL(sqte,	e488100, 2, (RF, RF_IF),     rd_rm),
15415218822Sdim cCL(sqtep,	e488120, 2, (RF, RF_IF),     rd_rm),
15416218822Sdim cCL(sqtem,	e488140, 2, (RF, RF_IF),     rd_rm),
15417218822Sdim cCL(sqtez,	e488160, 2, (RF, RF_IF),     rd_rm),
15418218822Sdim
15419218822Sdim cCL(logs,	e508100, 2, (RF, RF_IF),     rd_rm),
15420218822Sdim cCL(logsp,	e508120, 2, (RF, RF_IF),     rd_rm),
15421218822Sdim cCL(logsm,	e508140, 2, (RF, RF_IF),     rd_rm),
15422218822Sdim cCL(logsz,	e508160, 2, (RF, RF_IF),     rd_rm),
15423218822Sdim cCL(logd,	e508180, 2, (RF, RF_IF),     rd_rm),
15424218822Sdim cCL(logdp,	e5081a0, 2, (RF, RF_IF),     rd_rm),
15425218822Sdim cCL(logdm,	e5081c0, 2, (RF, RF_IF),     rd_rm),
15426218822Sdim cCL(logdz,	e5081e0, 2, (RF, RF_IF),     rd_rm),
15427218822Sdim cCL(loge,	e588100, 2, (RF, RF_IF),     rd_rm),
15428218822Sdim cCL(logep,	e588120, 2, (RF, RF_IF),     rd_rm),
15429218822Sdim cCL(logem,	e588140, 2, (RF, RF_IF),     rd_rm),
15430218822Sdim cCL(logez,	e588160, 2, (RF, RF_IF),     rd_rm),
15431218822Sdim
15432218822Sdim cCL(lgns,	e608100, 2, (RF, RF_IF),     rd_rm),
15433218822Sdim cCL(lgnsp,	e608120, 2, (RF, RF_IF),     rd_rm),
15434218822Sdim cCL(lgnsm,	e608140, 2, (RF, RF_IF),     rd_rm),
15435218822Sdim cCL(lgnsz,	e608160, 2, (RF, RF_IF),     rd_rm),
15436218822Sdim cCL(lgnd,	e608180, 2, (RF, RF_IF),     rd_rm),
15437218822Sdim cCL(lgndp,	e6081a0, 2, (RF, RF_IF),     rd_rm),
15438218822Sdim cCL(lgndm,	e6081c0, 2, (RF, RF_IF),     rd_rm),
15439218822Sdim cCL(lgndz,	e6081e0, 2, (RF, RF_IF),     rd_rm),
15440218822Sdim cCL(lgne,	e688100, 2, (RF, RF_IF),     rd_rm),
15441218822Sdim cCL(lgnep,	e688120, 2, (RF, RF_IF),     rd_rm),
15442218822Sdim cCL(lgnem,	e688140, 2, (RF, RF_IF),     rd_rm),
15443218822Sdim cCL(lgnez,	e688160, 2, (RF, RF_IF),     rd_rm),
15444218822Sdim
15445218822Sdim cCL(exps,	e708100, 2, (RF, RF_IF),     rd_rm),
15446218822Sdim cCL(expsp,	e708120, 2, (RF, RF_IF),     rd_rm),
15447218822Sdim cCL(expsm,	e708140, 2, (RF, RF_IF),     rd_rm),
15448218822Sdim cCL(expsz,	e708160, 2, (RF, RF_IF),     rd_rm),
15449218822Sdim cCL(expd,	e708180, 2, (RF, RF_IF),     rd_rm),
15450218822Sdim cCL(expdp,	e7081a0, 2, (RF, RF_IF),     rd_rm),
15451218822Sdim cCL(expdm,	e7081c0, 2, (RF, RF_IF),     rd_rm),
15452218822Sdim cCL(expdz,	e7081e0, 2, (RF, RF_IF),     rd_rm),
15453218822Sdim cCL(expe,	e788100, 2, (RF, RF_IF),     rd_rm),
15454218822Sdim cCL(expep,	e788120, 2, (RF, RF_IF),     rd_rm),
15455218822Sdim cCL(expem,	e788140, 2, (RF, RF_IF),     rd_rm),
15456218822Sdim cCL(expdz,	e788160, 2, (RF, RF_IF),     rd_rm),
15457218822Sdim
15458218822Sdim cCL(sins,	e808100, 2, (RF, RF_IF),     rd_rm),
15459218822Sdim cCL(sinsp,	e808120, 2, (RF, RF_IF),     rd_rm),
15460218822Sdim cCL(sinsm,	e808140, 2, (RF, RF_IF),     rd_rm),
15461218822Sdim cCL(sinsz,	e808160, 2, (RF, RF_IF),     rd_rm),
15462218822Sdim cCL(sind,	e808180, 2, (RF, RF_IF),     rd_rm),
15463218822Sdim cCL(sindp,	e8081a0, 2, (RF, RF_IF),     rd_rm),
15464218822Sdim cCL(sindm,	e8081c0, 2, (RF, RF_IF),     rd_rm),
15465218822Sdim cCL(sindz,	e8081e0, 2, (RF, RF_IF),     rd_rm),
15466218822Sdim cCL(sine,	e888100, 2, (RF, RF_IF),     rd_rm),
15467218822Sdim cCL(sinep,	e888120, 2, (RF, RF_IF),     rd_rm),
15468218822Sdim cCL(sinem,	e888140, 2, (RF, RF_IF),     rd_rm),
15469218822Sdim cCL(sinez,	e888160, 2, (RF, RF_IF),     rd_rm),
15470218822Sdim
15471218822Sdim cCL(coss,	e908100, 2, (RF, RF_IF),     rd_rm),
15472218822Sdim cCL(cossp,	e908120, 2, (RF, RF_IF),     rd_rm),
15473218822Sdim cCL(cossm,	e908140, 2, (RF, RF_IF),     rd_rm),
15474218822Sdim cCL(cossz,	e908160, 2, (RF, RF_IF),     rd_rm),
15475218822Sdim cCL(cosd,	e908180, 2, (RF, RF_IF),     rd_rm),
15476218822Sdim cCL(cosdp,	e9081a0, 2, (RF, RF_IF),     rd_rm),
15477218822Sdim cCL(cosdm,	e9081c0, 2, (RF, RF_IF),     rd_rm),
15478218822Sdim cCL(cosdz,	e9081e0, 2, (RF, RF_IF),     rd_rm),
15479218822Sdim cCL(cose,	e988100, 2, (RF, RF_IF),     rd_rm),
15480218822Sdim cCL(cosep,	e988120, 2, (RF, RF_IF),     rd_rm),
15481218822Sdim cCL(cosem,	e988140, 2, (RF, RF_IF),     rd_rm),
15482218822Sdim cCL(cosez,	e988160, 2, (RF, RF_IF),     rd_rm),
15483218822Sdim
15484218822Sdim cCL(tans,	ea08100, 2, (RF, RF_IF),     rd_rm),
15485218822Sdim cCL(tansp,	ea08120, 2, (RF, RF_IF),     rd_rm),
15486218822Sdim cCL(tansm,	ea08140, 2, (RF, RF_IF),     rd_rm),
15487218822Sdim cCL(tansz,	ea08160, 2, (RF, RF_IF),     rd_rm),
15488218822Sdim cCL(tand,	ea08180, 2, (RF, RF_IF),     rd_rm),
15489218822Sdim cCL(tandp,	ea081a0, 2, (RF, RF_IF),     rd_rm),
15490218822Sdim cCL(tandm,	ea081c0, 2, (RF, RF_IF),     rd_rm),
15491218822Sdim cCL(tandz,	ea081e0, 2, (RF, RF_IF),     rd_rm),
15492218822Sdim cCL(tane,	ea88100, 2, (RF, RF_IF),     rd_rm),
15493218822Sdim cCL(tanep,	ea88120, 2, (RF, RF_IF),     rd_rm),
15494218822Sdim cCL(tanem,	ea88140, 2, (RF, RF_IF),     rd_rm),
15495218822Sdim cCL(tanez,	ea88160, 2, (RF, RF_IF),     rd_rm),
15496218822Sdim
15497218822Sdim cCL(asns,	eb08100, 2, (RF, RF_IF),     rd_rm),
15498218822Sdim cCL(asnsp,	eb08120, 2, (RF, RF_IF),     rd_rm),
15499218822Sdim cCL(asnsm,	eb08140, 2, (RF, RF_IF),     rd_rm),
15500218822Sdim cCL(asnsz,	eb08160, 2, (RF, RF_IF),     rd_rm),
15501218822Sdim cCL(asnd,	eb08180, 2, (RF, RF_IF),     rd_rm),
15502218822Sdim cCL(asndp,	eb081a0, 2, (RF, RF_IF),     rd_rm),
15503218822Sdim cCL(asndm,	eb081c0, 2, (RF, RF_IF),     rd_rm),
15504218822Sdim cCL(asndz,	eb081e0, 2, (RF, RF_IF),     rd_rm),
15505218822Sdim cCL(asne,	eb88100, 2, (RF, RF_IF),     rd_rm),
15506218822Sdim cCL(asnep,	eb88120, 2, (RF, RF_IF),     rd_rm),
15507218822Sdim cCL(asnem,	eb88140, 2, (RF, RF_IF),     rd_rm),
15508218822Sdim cCL(asnez,	eb88160, 2, (RF, RF_IF),     rd_rm),
15509218822Sdim
15510218822Sdim cCL(acss,	ec08100, 2, (RF, RF_IF),     rd_rm),
15511218822Sdim cCL(acssp,	ec08120, 2, (RF, RF_IF),     rd_rm),
15512218822Sdim cCL(acssm,	ec08140, 2, (RF, RF_IF),     rd_rm),
15513218822Sdim cCL(acssz,	ec08160, 2, (RF, RF_IF),     rd_rm),
15514218822Sdim cCL(acsd,	ec08180, 2, (RF, RF_IF),     rd_rm),
15515218822Sdim cCL(acsdp,	ec081a0, 2, (RF, RF_IF),     rd_rm),
15516218822Sdim cCL(acsdm,	ec081c0, 2, (RF, RF_IF),     rd_rm),
15517218822Sdim cCL(acsdz,	ec081e0, 2, (RF, RF_IF),     rd_rm),
15518218822Sdim cCL(acse,	ec88100, 2, (RF, RF_IF),     rd_rm),
15519218822Sdim cCL(acsep,	ec88120, 2, (RF, RF_IF),     rd_rm),
15520218822Sdim cCL(acsem,	ec88140, 2, (RF, RF_IF),     rd_rm),
15521218822Sdim cCL(acsez,	ec88160, 2, (RF, RF_IF),     rd_rm),
15522218822Sdim
15523218822Sdim cCL(atns,	ed08100, 2, (RF, RF_IF),     rd_rm),
15524218822Sdim cCL(atnsp,	ed08120, 2, (RF, RF_IF),     rd_rm),
15525218822Sdim cCL(atnsm,	ed08140, 2, (RF, RF_IF),     rd_rm),
15526218822Sdim cCL(atnsz,	ed08160, 2, (RF, RF_IF),     rd_rm),
15527218822Sdim cCL(atnd,	ed08180, 2, (RF, RF_IF),     rd_rm),
15528218822Sdim cCL(atndp,	ed081a0, 2, (RF, RF_IF),     rd_rm),
15529218822Sdim cCL(atndm,	ed081c0, 2, (RF, RF_IF),     rd_rm),
15530218822Sdim cCL(atndz,	ed081e0, 2, (RF, RF_IF),     rd_rm),
15531218822Sdim cCL(atne,	ed88100, 2, (RF, RF_IF),     rd_rm),
15532218822Sdim cCL(atnep,	ed88120, 2, (RF, RF_IF),     rd_rm),
15533218822Sdim cCL(atnem,	ed88140, 2, (RF, RF_IF),     rd_rm),
15534218822Sdim cCL(atnez,	ed88160, 2, (RF, RF_IF),     rd_rm),
15535218822Sdim
15536218822Sdim cCL(urds,	ee08100, 2, (RF, RF_IF),     rd_rm),
15537218822Sdim cCL(urdsp,	ee08120, 2, (RF, RF_IF),     rd_rm),
15538218822Sdim cCL(urdsm,	ee08140, 2, (RF, RF_IF),     rd_rm),
15539218822Sdim cCL(urdsz,	ee08160, 2, (RF, RF_IF),     rd_rm),
15540218822Sdim cCL(urdd,	ee08180, 2, (RF, RF_IF),     rd_rm),
15541218822Sdim cCL(urddp,	ee081a0, 2, (RF, RF_IF),     rd_rm),
15542218822Sdim cCL(urddm,	ee081c0, 2, (RF, RF_IF),     rd_rm),
15543218822Sdim cCL(urddz,	ee081e0, 2, (RF, RF_IF),     rd_rm),
15544218822Sdim cCL(urde,	ee88100, 2, (RF, RF_IF),     rd_rm),
15545218822Sdim cCL(urdep,	ee88120, 2, (RF, RF_IF),     rd_rm),
15546218822Sdim cCL(urdem,	ee88140, 2, (RF, RF_IF),     rd_rm),
15547218822Sdim cCL(urdez,	ee88160, 2, (RF, RF_IF),     rd_rm),
15548218822Sdim
15549218822Sdim cCL(nrms,	ef08100, 2, (RF, RF_IF),     rd_rm),
15550218822Sdim cCL(nrmsp,	ef08120, 2, (RF, RF_IF),     rd_rm),
15551218822Sdim cCL(nrmsm,	ef08140, 2, (RF, RF_IF),     rd_rm),
15552218822Sdim cCL(nrmsz,	ef08160, 2, (RF, RF_IF),     rd_rm),
15553218822Sdim cCL(nrmd,	ef08180, 2, (RF, RF_IF),     rd_rm),
15554218822Sdim cCL(nrmdp,	ef081a0, 2, (RF, RF_IF),     rd_rm),
15555218822Sdim cCL(nrmdm,	ef081c0, 2, (RF, RF_IF),     rd_rm),
15556218822Sdim cCL(nrmdz,	ef081e0, 2, (RF, RF_IF),     rd_rm),
15557218822Sdim cCL(nrme,	ef88100, 2, (RF, RF_IF),     rd_rm),
15558218822Sdim cCL(nrmep,	ef88120, 2, (RF, RF_IF),     rd_rm),
15559218822Sdim cCL(nrmem,	ef88140, 2, (RF, RF_IF),     rd_rm),
15560218822Sdim cCL(nrmez,	ef88160, 2, (RF, RF_IF),     rd_rm),
15561218822Sdim
15562218822Sdim cCL(adfs,	e000100, 3, (RF, RF, RF_IF), rd_rn_rm),
15563218822Sdim cCL(adfsp,	e000120, 3, (RF, RF, RF_IF), rd_rn_rm),
15564218822Sdim cCL(adfsm,	e000140, 3, (RF, RF, RF_IF), rd_rn_rm),
15565218822Sdim cCL(adfsz,	e000160, 3, (RF, RF, RF_IF), rd_rn_rm),
15566218822Sdim cCL(adfd,	e000180, 3, (RF, RF, RF_IF), rd_rn_rm),
15567218822Sdim cCL(adfdp,	e0001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15568218822Sdim cCL(adfdm,	e0001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15569218822Sdim cCL(adfdz,	e0001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15570218822Sdim cCL(adfe,	e080100, 3, (RF, RF, RF_IF), rd_rn_rm),
15571218822Sdim cCL(adfep,	e080120, 3, (RF, RF, RF_IF), rd_rn_rm),
15572218822Sdim cCL(adfem,	e080140, 3, (RF, RF, RF_IF), rd_rn_rm),
15573218822Sdim cCL(adfez,	e080160, 3, (RF, RF, RF_IF), rd_rn_rm),
15574218822Sdim
15575218822Sdim cCL(sufs,	e200100, 3, (RF, RF, RF_IF), rd_rn_rm),
15576218822Sdim cCL(sufsp,	e200120, 3, (RF, RF, RF_IF), rd_rn_rm),
15577218822Sdim cCL(sufsm,	e200140, 3, (RF, RF, RF_IF), rd_rn_rm),
15578218822Sdim cCL(sufsz,	e200160, 3, (RF, RF, RF_IF), rd_rn_rm),
15579218822Sdim cCL(sufd,	e200180, 3, (RF, RF, RF_IF), rd_rn_rm),
15580218822Sdim cCL(sufdp,	e2001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15581218822Sdim cCL(sufdm,	e2001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15582218822Sdim cCL(sufdz,	e2001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15583218822Sdim cCL(sufe,	e280100, 3, (RF, RF, RF_IF), rd_rn_rm),
15584218822Sdim cCL(sufep,	e280120, 3, (RF, RF, RF_IF), rd_rn_rm),
15585218822Sdim cCL(sufem,	e280140, 3, (RF, RF, RF_IF), rd_rn_rm),
15586218822Sdim cCL(sufez,	e280160, 3, (RF, RF, RF_IF), rd_rn_rm),
15587218822Sdim
15588218822Sdim cCL(rsfs,	e300100, 3, (RF, RF, RF_IF), rd_rn_rm),
15589218822Sdim cCL(rsfsp,	e300120, 3, (RF, RF, RF_IF), rd_rn_rm),
15590218822Sdim cCL(rsfsm,	e300140, 3, (RF, RF, RF_IF), rd_rn_rm),
15591218822Sdim cCL(rsfsz,	e300160, 3, (RF, RF, RF_IF), rd_rn_rm),
15592218822Sdim cCL(rsfd,	e300180, 3, (RF, RF, RF_IF), rd_rn_rm),
15593218822Sdim cCL(rsfdp,	e3001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15594218822Sdim cCL(rsfdm,	e3001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15595218822Sdim cCL(rsfdz,	e3001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15596218822Sdim cCL(rsfe,	e380100, 3, (RF, RF, RF_IF), rd_rn_rm),
15597218822Sdim cCL(rsfep,	e380120, 3, (RF, RF, RF_IF), rd_rn_rm),
15598218822Sdim cCL(rsfem,	e380140, 3, (RF, RF, RF_IF), rd_rn_rm),
15599218822Sdim cCL(rsfez,	e380160, 3, (RF, RF, RF_IF), rd_rn_rm),
15600218822Sdim
15601218822Sdim cCL(mufs,	e100100, 3, (RF, RF, RF_IF), rd_rn_rm),
15602218822Sdim cCL(mufsp,	e100120, 3, (RF, RF, RF_IF), rd_rn_rm),
15603218822Sdim cCL(mufsm,	e100140, 3, (RF, RF, RF_IF), rd_rn_rm),
15604218822Sdim cCL(mufsz,	e100160, 3, (RF, RF, RF_IF), rd_rn_rm),
15605218822Sdim cCL(mufd,	e100180, 3, (RF, RF, RF_IF), rd_rn_rm),
15606218822Sdim cCL(mufdp,	e1001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15607218822Sdim cCL(mufdm,	e1001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15608218822Sdim cCL(mufdz,	e1001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15609218822Sdim cCL(mufe,	e180100, 3, (RF, RF, RF_IF), rd_rn_rm),
15610218822Sdim cCL(mufep,	e180120, 3, (RF, RF, RF_IF), rd_rn_rm),
15611218822Sdim cCL(mufem,	e180140, 3, (RF, RF, RF_IF), rd_rn_rm),
15612218822Sdim cCL(mufez,	e180160, 3, (RF, RF, RF_IF), rd_rn_rm),
15613218822Sdim
15614218822Sdim cCL(dvfs,	e400100, 3, (RF, RF, RF_IF), rd_rn_rm),
15615218822Sdim cCL(dvfsp,	e400120, 3, (RF, RF, RF_IF), rd_rn_rm),
15616218822Sdim cCL(dvfsm,	e400140, 3, (RF, RF, RF_IF), rd_rn_rm),
15617218822Sdim cCL(dvfsz,	e400160, 3, (RF, RF, RF_IF), rd_rn_rm),
15618218822Sdim cCL(dvfd,	e400180, 3, (RF, RF, RF_IF), rd_rn_rm),
15619218822Sdim cCL(dvfdp,	e4001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15620218822Sdim cCL(dvfdm,	e4001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15621218822Sdim cCL(dvfdz,	e4001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15622218822Sdim cCL(dvfe,	e480100, 3, (RF, RF, RF_IF), rd_rn_rm),
15623218822Sdim cCL(dvfep,	e480120, 3, (RF, RF, RF_IF), rd_rn_rm),
15624218822Sdim cCL(dvfem,	e480140, 3, (RF, RF, RF_IF), rd_rn_rm),
15625218822Sdim cCL(dvfez,	e480160, 3, (RF, RF, RF_IF), rd_rn_rm),
15626218822Sdim
15627218822Sdim cCL(rdfs,	e500100, 3, (RF, RF, RF_IF), rd_rn_rm),
15628218822Sdim cCL(rdfsp,	e500120, 3, (RF, RF, RF_IF), rd_rn_rm),
15629218822Sdim cCL(rdfsm,	e500140, 3, (RF, RF, RF_IF), rd_rn_rm),
15630218822Sdim cCL(rdfsz,	e500160, 3, (RF, RF, RF_IF), rd_rn_rm),
15631218822Sdim cCL(rdfd,	e500180, 3, (RF, RF, RF_IF), rd_rn_rm),
15632218822Sdim cCL(rdfdp,	e5001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15633218822Sdim cCL(rdfdm,	e5001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15634218822Sdim cCL(rdfdz,	e5001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15635218822Sdim cCL(rdfe,	e580100, 3, (RF, RF, RF_IF), rd_rn_rm),
15636218822Sdim cCL(rdfep,	e580120, 3, (RF, RF, RF_IF), rd_rn_rm),
15637218822Sdim cCL(rdfem,	e580140, 3, (RF, RF, RF_IF), rd_rn_rm),
15638218822Sdim cCL(rdfez,	e580160, 3, (RF, RF, RF_IF), rd_rn_rm),
15639218822Sdim
15640218822Sdim cCL(pows,	e600100, 3, (RF, RF, RF_IF), rd_rn_rm),
15641218822Sdim cCL(powsp,	e600120, 3, (RF, RF, RF_IF), rd_rn_rm),
15642218822Sdim cCL(powsm,	e600140, 3, (RF, RF, RF_IF), rd_rn_rm),
15643218822Sdim cCL(powsz,	e600160, 3, (RF, RF, RF_IF), rd_rn_rm),
15644218822Sdim cCL(powd,	e600180, 3, (RF, RF, RF_IF), rd_rn_rm),
15645218822Sdim cCL(powdp,	e6001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15646218822Sdim cCL(powdm,	e6001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15647218822Sdim cCL(powdz,	e6001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15648218822Sdim cCL(powe,	e680100, 3, (RF, RF, RF_IF), rd_rn_rm),
15649218822Sdim cCL(powep,	e680120, 3, (RF, RF, RF_IF), rd_rn_rm),
15650218822Sdim cCL(powem,	e680140, 3, (RF, RF, RF_IF), rd_rn_rm),
15651218822Sdim cCL(powez,	e680160, 3, (RF, RF, RF_IF), rd_rn_rm),
15652218822Sdim
15653218822Sdim cCL(rpws,	e700100, 3, (RF, RF, RF_IF), rd_rn_rm),
15654218822Sdim cCL(rpwsp,	e700120, 3, (RF, RF, RF_IF), rd_rn_rm),
15655218822Sdim cCL(rpwsm,	e700140, 3, (RF, RF, RF_IF), rd_rn_rm),
15656218822Sdim cCL(rpwsz,	e700160, 3, (RF, RF, RF_IF), rd_rn_rm),
15657218822Sdim cCL(rpwd,	e700180, 3, (RF, RF, RF_IF), rd_rn_rm),
15658218822Sdim cCL(rpwdp,	e7001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15659218822Sdim cCL(rpwdm,	e7001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15660218822Sdim cCL(rpwdz,	e7001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15661218822Sdim cCL(rpwe,	e780100, 3, (RF, RF, RF_IF), rd_rn_rm),
15662218822Sdim cCL(rpwep,	e780120, 3, (RF, RF, RF_IF), rd_rn_rm),
15663218822Sdim cCL(rpwem,	e780140, 3, (RF, RF, RF_IF), rd_rn_rm),
15664218822Sdim cCL(rpwez,	e780160, 3, (RF, RF, RF_IF), rd_rn_rm),
15665218822Sdim
15666218822Sdim cCL(rmfs,	e800100, 3, (RF, RF, RF_IF), rd_rn_rm),
15667218822Sdim cCL(rmfsp,	e800120, 3, (RF, RF, RF_IF), rd_rn_rm),
15668218822Sdim cCL(rmfsm,	e800140, 3, (RF, RF, RF_IF), rd_rn_rm),
15669218822Sdim cCL(rmfsz,	e800160, 3, (RF, RF, RF_IF), rd_rn_rm),
15670218822Sdim cCL(rmfd,	e800180, 3, (RF, RF, RF_IF), rd_rn_rm),
15671218822Sdim cCL(rmfdp,	e8001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15672218822Sdim cCL(rmfdm,	e8001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15673218822Sdim cCL(rmfdz,	e8001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15674218822Sdim cCL(rmfe,	e880100, 3, (RF, RF, RF_IF), rd_rn_rm),
15675218822Sdim cCL(rmfep,	e880120, 3, (RF, RF, RF_IF), rd_rn_rm),
15676218822Sdim cCL(rmfem,	e880140, 3, (RF, RF, RF_IF), rd_rn_rm),
15677218822Sdim cCL(rmfez,	e880160, 3, (RF, RF, RF_IF), rd_rn_rm),
15678218822Sdim
15679218822Sdim cCL(fmls,	e900100, 3, (RF, RF, RF_IF), rd_rn_rm),
15680218822Sdim cCL(fmlsp,	e900120, 3, (RF, RF, RF_IF), rd_rn_rm),
15681218822Sdim cCL(fmlsm,	e900140, 3, (RF, RF, RF_IF), rd_rn_rm),
15682218822Sdim cCL(fmlsz,	e900160, 3, (RF, RF, RF_IF), rd_rn_rm),
15683218822Sdim cCL(fmld,	e900180, 3, (RF, RF, RF_IF), rd_rn_rm),
15684218822Sdim cCL(fmldp,	e9001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15685218822Sdim cCL(fmldm,	e9001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15686218822Sdim cCL(fmldz,	e9001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15687218822Sdim cCL(fmle,	e980100, 3, (RF, RF, RF_IF), rd_rn_rm),
15688218822Sdim cCL(fmlep,	e980120, 3, (RF, RF, RF_IF), rd_rn_rm),
15689218822Sdim cCL(fmlem,	e980140, 3, (RF, RF, RF_IF), rd_rn_rm),
15690218822Sdim cCL(fmlez,	e980160, 3, (RF, RF, RF_IF), rd_rn_rm),
15691218822Sdim
15692218822Sdim cCL(fdvs,	ea00100, 3, (RF, RF, RF_IF), rd_rn_rm),
15693218822Sdim cCL(fdvsp,	ea00120, 3, (RF, RF, RF_IF), rd_rn_rm),
15694218822Sdim cCL(fdvsm,	ea00140, 3, (RF, RF, RF_IF), rd_rn_rm),
15695218822Sdim cCL(fdvsz,	ea00160, 3, (RF, RF, RF_IF), rd_rn_rm),
15696218822Sdim cCL(fdvd,	ea00180, 3, (RF, RF, RF_IF), rd_rn_rm),
15697218822Sdim cCL(fdvdp,	ea001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15698218822Sdim cCL(fdvdm,	ea001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15699218822Sdim cCL(fdvdz,	ea001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15700218822Sdim cCL(fdve,	ea80100, 3, (RF, RF, RF_IF), rd_rn_rm),
15701218822Sdim cCL(fdvep,	ea80120, 3, (RF, RF, RF_IF), rd_rn_rm),
15702218822Sdim cCL(fdvem,	ea80140, 3, (RF, RF, RF_IF), rd_rn_rm),
15703218822Sdim cCL(fdvez,	ea80160, 3, (RF, RF, RF_IF), rd_rn_rm),
15704218822Sdim
15705218822Sdim cCL(frds,	eb00100, 3, (RF, RF, RF_IF), rd_rn_rm),
15706218822Sdim cCL(frdsp,	eb00120, 3, (RF, RF, RF_IF), rd_rn_rm),
15707218822Sdim cCL(frdsm,	eb00140, 3, (RF, RF, RF_IF), rd_rn_rm),
15708218822Sdim cCL(frdsz,	eb00160, 3, (RF, RF, RF_IF), rd_rn_rm),
15709218822Sdim cCL(frdd,	eb00180, 3, (RF, RF, RF_IF), rd_rn_rm),
15710218822Sdim cCL(frddp,	eb001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15711218822Sdim cCL(frddm,	eb001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15712218822Sdim cCL(frddz,	eb001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15713218822Sdim cCL(frde,	eb80100, 3, (RF, RF, RF_IF), rd_rn_rm),
15714218822Sdim cCL(frdep,	eb80120, 3, (RF, RF, RF_IF), rd_rn_rm),
15715218822Sdim cCL(frdem,	eb80140, 3, (RF, RF, RF_IF), rd_rn_rm),
15716218822Sdim cCL(frdez,	eb80160, 3, (RF, RF, RF_IF), rd_rn_rm),
15717218822Sdim
15718218822Sdim cCL(pols,	ec00100, 3, (RF, RF, RF_IF), rd_rn_rm),
15719218822Sdim cCL(polsp,	ec00120, 3, (RF, RF, RF_IF), rd_rn_rm),
15720218822Sdim cCL(polsm,	ec00140, 3, (RF, RF, RF_IF), rd_rn_rm),
15721218822Sdim cCL(polsz,	ec00160, 3, (RF, RF, RF_IF), rd_rn_rm),
15722218822Sdim cCL(pold,	ec00180, 3, (RF, RF, RF_IF), rd_rn_rm),
15723218822Sdim cCL(poldp,	ec001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15724218822Sdim cCL(poldm,	ec001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15725218822Sdim cCL(poldz,	ec001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15726218822Sdim cCL(pole,	ec80100, 3, (RF, RF, RF_IF), rd_rn_rm),
15727218822Sdim cCL(polep,	ec80120, 3, (RF, RF, RF_IF), rd_rn_rm),
15728218822Sdim cCL(polem,	ec80140, 3, (RF, RF, RF_IF), rd_rn_rm),
15729218822Sdim cCL(polez,	ec80160, 3, (RF, RF, RF_IF), rd_rn_rm),
15730218822Sdim
15731218822Sdim cCE(cmf,	e90f110, 2, (RF, RF_IF),     fpa_cmp),
15732218822Sdim C3E(cmfe,	ed0f110, 2, (RF, RF_IF),     fpa_cmp),
15733218822Sdim cCE(cnf,	eb0f110, 2, (RF, RF_IF),     fpa_cmp),
15734218822Sdim C3E(cnfe,	ef0f110, 2, (RF, RF_IF),     fpa_cmp),
15735218822Sdim
15736218822Sdim cCL(flts,	e000110, 2, (RF, RR),	     rn_rd),
15737218822Sdim cCL(fltsp,	e000130, 2, (RF, RR),	     rn_rd),
15738218822Sdim cCL(fltsm,	e000150, 2, (RF, RR),	     rn_rd),
15739218822Sdim cCL(fltsz,	e000170, 2, (RF, RR),	     rn_rd),
15740218822Sdim cCL(fltd,	e000190, 2, (RF, RR),	     rn_rd),
15741218822Sdim cCL(fltdp,	e0001b0, 2, (RF, RR),	     rn_rd),
15742218822Sdim cCL(fltdm,	e0001d0, 2, (RF, RR),	     rn_rd),
15743218822Sdim cCL(fltdz,	e0001f0, 2, (RF, RR),	     rn_rd),
15744218822Sdim cCL(flte,	e080110, 2, (RF, RR),	     rn_rd),
15745218822Sdim cCL(fltep,	e080130, 2, (RF, RR),	     rn_rd),
15746218822Sdim cCL(fltem,	e080150, 2, (RF, RR),	     rn_rd),
15747218822Sdim cCL(fltez,	e080170, 2, (RF, RR),	     rn_rd),
15748218822Sdim
15749218822Sdim  /* The implementation of the FIX instruction is broken on some
15750218822Sdim     assemblers, in that it accepts a precision specifier as well as a
15751218822Sdim     rounding specifier, despite the fact that this is meaningless.
15752218822Sdim     To be more compatible, we accept it as well, though of course it
15753218822Sdim     does not set any bits.  */
15754218822Sdim cCE(fix,	e100110, 2, (RR, RF),	     rd_rm),
15755218822Sdim cCL(fixp,	e100130, 2, (RR, RF),	     rd_rm),
15756218822Sdim cCL(fixm,	e100150, 2, (RR, RF),	     rd_rm),
15757218822Sdim cCL(fixz,	e100170, 2, (RR, RF),	     rd_rm),
15758218822Sdim cCL(fixsp,	e100130, 2, (RR, RF),	     rd_rm),
15759218822Sdim cCL(fixsm,	e100150, 2, (RR, RF),	     rd_rm),
15760218822Sdim cCL(fixsz,	e100170, 2, (RR, RF),	     rd_rm),
15761218822Sdim cCL(fixdp,	e100130, 2, (RR, RF),	     rd_rm),
15762218822Sdim cCL(fixdm,	e100150, 2, (RR, RF),	     rd_rm),
15763218822Sdim cCL(fixdz,	e100170, 2, (RR, RF),	     rd_rm),
15764218822Sdim cCL(fixep,	e100130, 2, (RR, RF),	     rd_rm),
15765218822Sdim cCL(fixem,	e100150, 2, (RR, RF),	     rd_rm),
15766218822Sdim cCL(fixez,	e100170, 2, (RR, RF),	     rd_rm),
15767218822Sdim
15768218822Sdim  /* Instructions that were new with the real FPA, call them V2.  */
15769218822Sdim#undef ARM_VARIANT
15770218822Sdim#define ARM_VARIANT &fpu_fpa_ext_v2
15771218822Sdim cCE(lfm,	c100200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15772218822Sdim cCL(lfmfd,	c900200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15773218822Sdim cCL(lfmea,	d100200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15774218822Sdim cCE(sfm,	c000200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15775218822Sdim cCL(sfmfd,	d000200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15776218822Sdim cCL(sfmea,	c800200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15777218822Sdim
15778218822Sdim#undef ARM_VARIANT
15779218822Sdim#define ARM_VARIANT &fpu_vfp_ext_v1xd  /* VFP V1xD (single precision).  */
15780218822Sdim  /* Moves and type conversions.  */
15781218822Sdim cCE(fcpys,	eb00a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15782218822Sdim cCE(fmrs,	e100a10, 2, (RR, RVS),	      vfp_reg_from_sp),
15783218822Sdim cCE(fmsr,	e000a10, 2, (RVS, RR),	      vfp_sp_from_reg),
15784218822Sdim cCE(fmstat,	ef1fa10, 0, (),		      noargs),
15785218822Sdim cCE(fsitos,	eb80ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15786218822Sdim cCE(fuitos,	eb80a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15787218822Sdim cCE(ftosis,	ebd0a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15788218822Sdim cCE(ftosizs,	ebd0ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15789218822Sdim cCE(ftouis,	ebc0a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15790218822Sdim cCE(ftouizs,	ebc0ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15791218822Sdim cCE(fmrx,	ef00a10, 2, (RR, RVC),	      rd_rn),
15792218822Sdim cCE(fmxr,	ee00a10, 2, (RVC, RR),	      rn_rd),
15793248460Sandrew cCE(vmrs,	ef00a10, 2, (APSR_RR, RVC),   vfp_vmrs),
15794248460Sandrew cCE(vmsr,	ee00a10, 2, (RVC, RR),        vfp_vmsr),
15795218822Sdim
15796218822Sdim  /* Memory operations.	 */
15797218822Sdim cCE(flds,	d100a00, 2, (RVS, ADDRGLDC),  vfp_sp_ldst),
15798218822Sdim cCE(fsts,	d000a00, 2, (RVS, ADDRGLDC),  vfp_sp_ldst),
15799218822Sdim cCE(fldmias,	c900a00, 2, (RRw, VRSLST),    vfp_sp_ldstmia),
15800218822Sdim cCE(fldmfds,	c900a00, 2, (RRw, VRSLST),    vfp_sp_ldstmia),
15801218822Sdim cCE(fldmdbs,	d300a00, 2, (RRw, VRSLST),    vfp_sp_ldstmdb),
15802218822Sdim cCE(fldmeas,	d300a00, 2, (RRw, VRSLST),    vfp_sp_ldstmdb),
15803218822Sdim cCE(fldmiax,	c900b00, 2, (RRw, VRDLST),    vfp_xp_ldstmia),
15804218822Sdim cCE(fldmfdx,	c900b00, 2, (RRw, VRDLST),    vfp_xp_ldstmia),
15805218822Sdim cCE(fldmdbx,	d300b00, 2, (RRw, VRDLST),    vfp_xp_ldstmdb),
15806218822Sdim cCE(fldmeax,	d300b00, 2, (RRw, VRDLST),    vfp_xp_ldstmdb),
15807218822Sdim cCE(fstmias,	c800a00, 2, (RRw, VRSLST),    vfp_sp_ldstmia),
15808218822Sdim cCE(fstmeas,	c800a00, 2, (RRw, VRSLST),    vfp_sp_ldstmia),
15809218822Sdim cCE(fstmdbs,	d200a00, 2, (RRw, VRSLST),    vfp_sp_ldstmdb),
15810218822Sdim cCE(fstmfds,	d200a00, 2, (RRw, VRSLST),    vfp_sp_ldstmdb),
15811218822Sdim cCE(fstmiax,	c800b00, 2, (RRw, VRDLST),    vfp_xp_ldstmia),
15812218822Sdim cCE(fstmeax,	c800b00, 2, (RRw, VRDLST),    vfp_xp_ldstmia),
15813218822Sdim cCE(fstmdbx,	d200b00, 2, (RRw, VRDLST),    vfp_xp_ldstmdb),
15814218822Sdim cCE(fstmfdx,	d200b00, 2, (RRw, VRDLST),    vfp_xp_ldstmdb),
15815218822Sdim
15816218822Sdim  /* Monadic operations.  */
15817218822Sdim cCE(fabss,	eb00ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15818218822Sdim cCE(fnegs,	eb10a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15819218822Sdim cCE(fsqrts,	eb10ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15820218822Sdim
15821218822Sdim  /* Dyadic operations.	 */
15822218822Sdim cCE(fadds,	e300a00, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15823218822Sdim cCE(fsubs,	e300a40, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15824218822Sdim cCE(fmuls,	e200a00, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15825218822Sdim cCE(fdivs,	e800a00, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15826218822Sdim cCE(fmacs,	e000a00, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15827218822Sdim cCE(fmscs,	e100a00, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15828218822Sdim cCE(fnmuls,	e200a40, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15829218822Sdim cCE(fnmacs,	e000a40, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15830218822Sdim cCE(fnmscs,	e100a40, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15831218822Sdim
15832218822Sdim  /* Comparisons.  */
15833218822Sdim cCE(fcmps,	eb40a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15834218822Sdim cCE(fcmpzs,	eb50a40, 1, (RVS),	      vfp_sp_compare_z),
15835218822Sdim cCE(fcmpes,	eb40ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15836218822Sdim cCE(fcmpezs,	eb50ac0, 1, (RVS),	      vfp_sp_compare_z),
15837218822Sdim
15838218822Sdim#undef ARM_VARIANT
15839218822Sdim#define ARM_VARIANT &fpu_vfp_ext_v1 /* VFP V1 (Double precision).  */
15840218822Sdim  /* Moves and type conversions.  */
15841218822Sdim cCE(fcpyd,	eb00b40, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15842218822Sdim cCE(fcvtds,	eb70ac0, 2, (RVD, RVS),	      vfp_dp_sp_cvt),
15843218822Sdim cCE(fcvtsd,	eb70bc0, 2, (RVS, RVD),	      vfp_sp_dp_cvt),
15844218822Sdim cCE(fmdhr,	e200b10, 2, (RVD, RR),	      vfp_dp_rn_rd),
15845218822Sdim cCE(fmdlr,	e000b10, 2, (RVD, RR),	      vfp_dp_rn_rd),
15846218822Sdim cCE(fmrdh,	e300b10, 2, (RR, RVD),	      vfp_dp_rd_rn),
15847218822Sdim cCE(fmrdl,	e100b10, 2, (RR, RVD),	      vfp_dp_rd_rn),
15848218822Sdim cCE(fsitod,	eb80bc0, 2, (RVD, RVS),	      vfp_dp_sp_cvt),
15849218822Sdim cCE(fuitod,	eb80b40, 2, (RVD, RVS),	      vfp_dp_sp_cvt),
15850218822Sdim cCE(ftosid,	ebd0b40, 2, (RVS, RVD),	      vfp_sp_dp_cvt),
15851218822Sdim cCE(ftosizd,	ebd0bc0, 2, (RVS, RVD),	      vfp_sp_dp_cvt),
15852218822Sdim cCE(ftouid,	ebc0b40, 2, (RVS, RVD),	      vfp_sp_dp_cvt),
15853218822Sdim cCE(ftouizd,	ebc0bc0, 2, (RVS, RVD),	      vfp_sp_dp_cvt),
15854218822Sdim
15855218822Sdim  /* Memory operations.	 */
15856218822Sdim cCE(fldd,	d100b00, 2, (RVD, ADDRGLDC),  vfp_dp_ldst),
15857218822Sdim cCE(fstd,	d000b00, 2, (RVD, ADDRGLDC),  vfp_dp_ldst),
15858218822Sdim cCE(fldmiad,	c900b00, 2, (RRw, VRDLST),    vfp_dp_ldstmia),
15859218822Sdim cCE(fldmfdd,	c900b00, 2, (RRw, VRDLST),    vfp_dp_ldstmia),
15860218822Sdim cCE(fldmdbd,	d300b00, 2, (RRw, VRDLST),    vfp_dp_ldstmdb),
15861218822Sdim cCE(fldmead,	d300b00, 2, (RRw, VRDLST),    vfp_dp_ldstmdb),
15862218822Sdim cCE(fstmiad,	c800b00, 2, (RRw, VRDLST),    vfp_dp_ldstmia),
15863218822Sdim cCE(fstmead,	c800b00, 2, (RRw, VRDLST),    vfp_dp_ldstmia),
15864218822Sdim cCE(fstmdbd,	d200b00, 2, (RRw, VRDLST),    vfp_dp_ldstmdb),
15865218822Sdim cCE(fstmfdd,	d200b00, 2, (RRw, VRDLST),    vfp_dp_ldstmdb),
15866218822Sdim
15867218822Sdim  /* Monadic operations.  */
15868218822Sdim cCE(fabsd,	eb00bc0, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15869218822Sdim cCE(fnegd,	eb10b40, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15870218822Sdim cCE(fsqrtd,	eb10bc0, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15871218822Sdim
15872218822Sdim  /* Dyadic operations.	 */
15873218822Sdim cCE(faddd,	e300b00, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15874218822Sdim cCE(fsubd,	e300b40, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15875218822Sdim cCE(fmuld,	e200b00, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15876218822Sdim cCE(fdivd,	e800b00, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15877218822Sdim cCE(fmacd,	e000b00, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15878218822Sdim cCE(fmscd,	e100b00, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15879218822Sdim cCE(fnmuld,	e200b40, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15880218822Sdim cCE(fnmacd,	e000b40, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15881218822Sdim cCE(fnmscd,	e100b40, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15882218822Sdim
15883218822Sdim  /* Comparisons.  */
15884218822Sdim cCE(fcmpd,	eb40b40, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15885218822Sdim cCE(fcmpzd,	eb50b40, 1, (RVD),	      vfp_dp_rd),
15886218822Sdim cCE(fcmped,	eb40bc0, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15887218822Sdim cCE(fcmpezd,	eb50bc0, 1, (RVD),	      vfp_dp_rd),
15888218822Sdim
15889218822Sdim#undef ARM_VARIANT
15890218822Sdim#define ARM_VARIANT &fpu_vfp_ext_v2
15891218822Sdim cCE(fmsrr,	c400a10, 3, (VRSLST, RR, RR), vfp_sp2_from_reg2),
15892218822Sdim cCE(fmrrs,	c500a10, 3, (RR, RR, VRSLST), vfp_reg2_from_sp2),
15893218822Sdim cCE(fmdrr,	c400b10, 3, (RVD, RR, RR),    vfp_dp_rm_rd_rn),
15894218822Sdim cCE(fmrrd,	c500b10, 3, (RR, RR, RVD),    vfp_dp_rd_rn_rm),
15895218822Sdim
15896218822Sdim/* Instructions which may belong to either the Neon or VFP instruction sets.
15897218822Sdim   Individual encoder functions perform additional architecture checks.  */
15898218822Sdim#undef ARM_VARIANT
15899218822Sdim#define ARM_VARIANT &fpu_vfp_ext_v1xd
15900218822Sdim#undef THUMB_VARIANT
15901218822Sdim#define THUMB_VARIANT &fpu_vfp_ext_v1xd
15902218822Sdim  /* These mnemonics are unique to VFP.  */
15903218822Sdim NCE(vsqrt,     0,       2, (RVSD, RVSD),       vfp_nsyn_sqrt),
15904218822Sdim NCE(vdiv,      0,       3, (RVSD, RVSD, RVSD), vfp_nsyn_div),
15905218822Sdim nCE(vnmul,     vnmul,   3, (RVSD, RVSD, RVSD), vfp_nsyn_nmul),
15906218822Sdim nCE(vnmla,     vnmla,   3, (RVSD, RVSD, RVSD), vfp_nsyn_nmul),
15907218822Sdim nCE(vnmls,     vnmls,   3, (RVSD, RVSD, RVSD), vfp_nsyn_nmul),
15908218822Sdim nCE(vcmp,      vcmp,    2, (RVSD, RVSD_I0),    vfp_nsyn_cmp),
15909218822Sdim nCE(vcmpe,     vcmpe,   2, (RVSD, RVSD_I0),    vfp_nsyn_cmp),
15910218822Sdim NCE(vpush,     0,       1, (VRSDLST),          vfp_nsyn_push),
15911218822Sdim NCE(vpop,      0,       1, (VRSDLST),          vfp_nsyn_pop),
15912218822Sdim NCE(vcvtz,     0,       2, (RVSD, RVSD),       vfp_nsyn_cvtz),
15913218822Sdim
15914218822Sdim  /* Mnemonics shared by Neon and VFP.  */
15915218822Sdim nCEF(vmul,     vmul,    3, (RNSDQ, oRNSDQ, RNSDQ_RNSC), neon_mul),
15916218822Sdim nCEF(vmla,     vmla,    3, (RNSDQ, oRNSDQ, RNSDQ_RNSC), neon_mac_maybe_scalar),
15917218822Sdim nCEF(vmls,     vmls,    3, (RNSDQ, oRNSDQ, RNSDQ_RNSC), neon_mac_maybe_scalar),
15918218822Sdim
15919218822Sdim nCEF(vadd,     vadd,    3, (RNSDQ, oRNSDQ, RNSDQ), neon_addsub_if_i),
15920218822Sdim nCEF(vsub,     vsub,    3, (RNSDQ, oRNSDQ, RNSDQ), neon_addsub_if_i),
15921218822Sdim
15922218822Sdim NCEF(vabs,     1b10300, 2, (RNSDQ, RNSDQ), neon_abs_neg),
15923218822Sdim NCEF(vneg,     1b10380, 2, (RNSDQ, RNSDQ), neon_abs_neg),
15924218822Sdim
15925218822Sdim NCE(vldm,      c900b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15926218822Sdim NCE(vldmia,    c900b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15927218822Sdim NCE(vldmdb,    d100b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15928218822Sdim NCE(vstm,      c800b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15929218822Sdim NCE(vstmia,    c800b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15930218822Sdim NCE(vstmdb,    d000b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15931218822Sdim NCE(vldr,      d100b00, 2, (RVSD, ADDRGLDC), neon_ldr_str),
15932218822Sdim NCE(vstr,      d000b00, 2, (RVSD, ADDRGLDC), neon_ldr_str),
15933218822Sdim
15934218822Sdim nCEF(vcvt,     vcvt,    3, (RNSDQ, RNSDQ, oI32b), neon_cvt),
15935218822Sdim
15936218822Sdim  /* NOTE: All VMOV encoding is special-cased!  */
15937218822Sdim NCE(vmov,      0,       1, (VMOV), neon_mov),
15938218822Sdim NCE(vmovq,     0,       1, (VMOV), neon_mov),
15939218822Sdim
15940218822Sdim#undef THUMB_VARIANT
15941218822Sdim#define THUMB_VARIANT &fpu_neon_ext_v1
15942218822Sdim#undef ARM_VARIANT
15943218822Sdim#define ARM_VARIANT &fpu_neon_ext_v1
15944218822Sdim  /* Data processing with three registers of the same length.  */
15945218822Sdim  /* integer ops, valid types S8 S16 S32 U8 U16 U32.  */
15946218822Sdim NUF(vaba,      0000710, 3, (RNDQ, RNDQ,  RNDQ), neon_dyadic_i_su),
15947218822Sdim NUF(vabaq,     0000710, 3, (RNQ,  RNQ,   RNQ),  neon_dyadic_i_su),
15948218822Sdim NUF(vhadd,     0000000, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i_su),
15949218822Sdim NUF(vhaddq,    0000000, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i_su),
15950218822Sdim NUF(vrhadd,    0000100, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i_su),
15951218822Sdim NUF(vrhaddq,   0000100, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i_su),
15952218822Sdim NUF(vhsub,     0000200, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i_su),
15953218822Sdim NUF(vhsubq,    0000200, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i_su),
15954218822Sdim  /* integer ops, valid types S8 S16 S32 S64 U8 U16 U32 U64.  */
15955218822Sdim NUF(vqadd,     0000010, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i64_su),
15956218822Sdim NUF(vqaddq,    0000010, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i64_su),
15957218822Sdim NUF(vqsub,     0000210, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i64_su),
15958218822Sdim NUF(vqsubq,    0000210, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i64_su),
15959218822Sdim NUF(vrshl,     0000500, 3, (RNDQ, oRNDQ, RNDQ), neon_rshl),
15960218822Sdim NUF(vrshlq,    0000500, 3, (RNQ,  oRNQ,  RNQ),  neon_rshl),
15961218822Sdim NUF(vqrshl,    0000510, 3, (RNDQ, oRNDQ, RNDQ), neon_rshl),
15962218822Sdim NUF(vqrshlq,   0000510, 3, (RNQ,  oRNQ,  RNQ),  neon_rshl),
15963218822Sdim  /* If not immediate, fall back to neon_dyadic_i64_su.
15964218822Sdim     shl_imm should accept I8 I16 I32 I64,
15965218822Sdim     qshl_imm should accept S8 S16 S32 S64 U8 U16 U32 U64.  */
15966218822Sdim nUF(vshl,      vshl,    3, (RNDQ, oRNDQ, RNDQ_I63b), neon_shl_imm),
15967218822Sdim nUF(vshlq,     vshl,    3, (RNQ,  oRNQ,  RNDQ_I63b), neon_shl_imm),
15968218822Sdim nUF(vqshl,     vqshl,   3, (RNDQ, oRNDQ, RNDQ_I63b), neon_qshl_imm),
15969218822Sdim nUF(vqshlq,    vqshl,   3, (RNQ,  oRNQ,  RNDQ_I63b), neon_qshl_imm),
15970218822Sdim  /* Logic ops, types optional & ignored.  */
15971218822Sdim nUF(vand,      vand,    2, (RNDQ, NILO),        neon_logic),
15972218822Sdim nUF(vandq,     vand,    2, (RNQ,  NILO),        neon_logic),
15973218822Sdim nUF(vbic,      vbic,    2, (RNDQ, NILO),        neon_logic),
15974218822Sdim nUF(vbicq,     vbic,    2, (RNQ,  NILO),        neon_logic),
15975218822Sdim nUF(vorr,      vorr,    2, (RNDQ, NILO),        neon_logic),
15976218822Sdim nUF(vorrq,     vorr,    2, (RNQ,  NILO),        neon_logic),
15977218822Sdim nUF(vorn,      vorn,    2, (RNDQ, NILO),        neon_logic),
15978218822Sdim nUF(vornq,     vorn,    2, (RNQ,  NILO),        neon_logic),
15979218822Sdim nUF(veor,      veor,    3, (RNDQ, oRNDQ, RNDQ), neon_logic),
15980218822Sdim nUF(veorq,     veor,    3, (RNQ,  oRNQ,  RNQ),  neon_logic),
15981218822Sdim  /* Bitfield ops, untyped.  */
15982218822Sdim NUF(vbsl,      1100110, 3, (RNDQ, RNDQ, RNDQ), neon_bitfield),
15983218822Sdim NUF(vbslq,     1100110, 3, (RNQ,  RNQ,  RNQ),  neon_bitfield),
15984218822Sdim NUF(vbit,      1200110, 3, (RNDQ, RNDQ, RNDQ), neon_bitfield),
15985218822Sdim NUF(vbitq,     1200110, 3, (RNQ,  RNQ,  RNQ),  neon_bitfield),
15986218822Sdim NUF(vbif,      1300110, 3, (RNDQ, RNDQ, RNDQ), neon_bitfield),
15987218822Sdim NUF(vbifq,     1300110, 3, (RNQ,  RNQ,  RNQ),  neon_bitfield),
15988218822Sdim  /* Int and float variants, types S8 S16 S32 U8 U16 U32 F32.  */
15989218822Sdim nUF(vabd,      vabd,    3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_if_su),
15990218822Sdim nUF(vabdq,     vabd,    3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_if_su),
15991218822Sdim nUF(vmax,      vmax,    3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_if_su),
15992218822Sdim nUF(vmaxq,     vmax,    3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_if_su),
15993218822Sdim nUF(vmin,      vmin,    3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_if_su),
15994218822Sdim nUF(vminq,     vmin,    3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_if_su),
15995218822Sdim  /* Comparisons. Types S8 S16 S32 U8 U16 U32 F32. Non-immediate versions fall
15996218822Sdim     back to neon_dyadic_if_su.  */
15997218822Sdim nUF(vcge,      vcge,    3, (RNDQ, oRNDQ, RNDQ_I0), neon_cmp),
15998218822Sdim nUF(vcgeq,     vcge,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_cmp),
15999218822Sdim nUF(vcgt,      vcgt,    3, (RNDQ, oRNDQ, RNDQ_I0), neon_cmp),
16000218822Sdim nUF(vcgtq,     vcgt,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_cmp),
16001218822Sdim nUF(vclt,      vclt,    3, (RNDQ, oRNDQ, RNDQ_I0), neon_cmp_inv),
16002218822Sdim nUF(vcltq,     vclt,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_cmp_inv),
16003218822Sdim nUF(vcle,      vcle,    3, (RNDQ, oRNDQ, RNDQ_I0), neon_cmp_inv),
16004218822Sdim nUF(vcleq,     vcle,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_cmp_inv),
16005218822Sdim  /* Comparison. Type I8 I16 I32 F32.  */
16006218822Sdim nUF(vceq,      vceq,    3, (RNDQ, oRNDQ, RNDQ_I0), neon_ceq),
16007218822Sdim nUF(vceqq,     vceq,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_ceq),
16008218822Sdim  /* As above, D registers only.  */
16009218822Sdim nUF(vpmax,     vpmax,   3, (RND, oRND, RND), neon_dyadic_if_su_d),
16010218822Sdim nUF(vpmin,     vpmin,   3, (RND, oRND, RND), neon_dyadic_if_su_d),
16011218822Sdim  /* Int and float variants, signedness unimportant.  */
16012218822Sdim nUF(vmlaq,     vmla,    3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_mac_maybe_scalar),
16013218822Sdim nUF(vmlsq,     vmls,    3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_mac_maybe_scalar),
16014218822Sdim nUF(vpadd,     vpadd,   3, (RND,  oRND,  RND),       neon_dyadic_if_i_d),
16015218822Sdim  /* Add/sub take types I8 I16 I32 I64 F32.  */
16016218822Sdim nUF(vaddq,     vadd,    3, (RNQ,  oRNQ,  RNQ),  neon_addsub_if_i),
16017218822Sdim nUF(vsubq,     vsub,    3, (RNQ,  oRNQ,  RNQ),  neon_addsub_if_i),
16018218822Sdim  /* vtst takes sizes 8, 16, 32.  */
16019218822Sdim NUF(vtst,      0000810, 3, (RNDQ, oRNDQ, RNDQ), neon_tst),
16020218822Sdim NUF(vtstq,     0000810, 3, (RNQ,  oRNQ,  RNQ),  neon_tst),
16021218822Sdim  /* VMUL takes I8 I16 I32 F32 P8.  */
16022218822Sdim nUF(vmulq,     vmul,     3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_mul),
16023218822Sdim  /* VQD{R}MULH takes S16 S32.  */
16024218822Sdim nUF(vqdmulh,   vqdmulh,  3, (RNDQ, oRNDQ, RNDQ_RNSC), neon_qdmulh),
16025218822Sdim nUF(vqdmulhq,  vqdmulh,  3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_qdmulh),
16026218822Sdim nUF(vqrdmulh,  vqrdmulh, 3, (RNDQ, oRNDQ, RNDQ_RNSC), neon_qdmulh),
16027218822Sdim nUF(vqrdmulhq, vqrdmulh, 3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_qdmulh),
16028218822Sdim NUF(vacge,     0000e10,  3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute),
16029218822Sdim NUF(vacgeq,    0000e10,  3, (RNQ,  oRNQ,  RNQ),  neon_fcmp_absolute),
16030218822Sdim NUF(vacgt,     0200e10,  3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute),
16031218822Sdim NUF(vacgtq,    0200e10,  3, (RNQ,  oRNQ,  RNQ),  neon_fcmp_absolute),
16032218822Sdim NUF(vaclt,     0200e10,  3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute_inv),
16033218822Sdim NUF(vacltq,    0200e10,  3, (RNQ,  oRNQ,  RNQ),  neon_fcmp_absolute_inv),
16034218822Sdim NUF(vacle,     0000e10,  3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute_inv),
16035218822Sdim NUF(vacleq,    0000e10,  3, (RNQ,  oRNQ,  RNQ),  neon_fcmp_absolute_inv),
16036218822Sdim NUF(vrecps,    0000f10,  3, (RNDQ, oRNDQ, RNDQ), neon_step),
16037218822Sdim NUF(vrecpsq,   0000f10,  3, (RNQ,  oRNQ,  RNQ),  neon_step),
16038218822Sdim NUF(vrsqrts,   0200f10,  3, (RNDQ, oRNDQ, RNDQ), neon_step),
16039218822Sdim NUF(vrsqrtsq,  0200f10,  3, (RNQ,  oRNQ,  RNQ),  neon_step),
16040218822Sdim
16041218822Sdim  /* Two address, int/float. Types S8 S16 S32 F32.  */
16042218822Sdim NUF(vabsq,     1b10300, 2, (RNQ,  RNQ),      neon_abs_neg),
16043218822Sdim NUF(vnegq,     1b10380, 2, (RNQ,  RNQ),      neon_abs_neg),
16044218822Sdim
16045218822Sdim  /* Data processing with two registers and a shift amount.  */
16046218822Sdim  /* Right shifts, and variants with rounding.
16047218822Sdim     Types accepted S8 S16 S32 S64 U8 U16 U32 U64.  */
16048218822Sdim NUF(vshr,      0800010, 3, (RNDQ, oRNDQ, I64z), neon_rshift_round_imm),
16049218822Sdim NUF(vshrq,     0800010, 3, (RNQ,  oRNQ,  I64z), neon_rshift_round_imm),
16050218822Sdim NUF(vrshr,     0800210, 3, (RNDQ, oRNDQ, I64z), neon_rshift_round_imm),
16051218822Sdim NUF(vrshrq,    0800210, 3, (RNQ,  oRNQ,  I64z), neon_rshift_round_imm),
16052218822Sdim NUF(vsra,      0800110, 3, (RNDQ, oRNDQ, I64),  neon_rshift_round_imm),
16053218822Sdim NUF(vsraq,     0800110, 3, (RNQ,  oRNQ,  I64),  neon_rshift_round_imm),
16054218822Sdim NUF(vrsra,     0800310, 3, (RNDQ, oRNDQ, I64),  neon_rshift_round_imm),
16055218822Sdim NUF(vrsraq,    0800310, 3, (RNQ,  oRNQ,  I64),  neon_rshift_round_imm),
16056218822Sdim  /* Shift and insert. Sizes accepted 8 16 32 64.  */
16057218822Sdim NUF(vsli,      1800510, 3, (RNDQ, oRNDQ, I63), neon_sli),
16058218822Sdim NUF(vsliq,     1800510, 3, (RNQ,  oRNQ,  I63), neon_sli),
16059218822Sdim NUF(vsri,      1800410, 3, (RNDQ, oRNDQ, I64), neon_sri),
16060218822Sdim NUF(vsriq,     1800410, 3, (RNQ,  oRNQ,  I64), neon_sri),
16061218822Sdim  /* QSHL{U} immediate accepts S8 S16 S32 S64 U8 U16 U32 U64.  */
16062218822Sdim NUF(vqshlu,    1800610, 3, (RNDQ, oRNDQ, I63), neon_qshlu_imm),
16063218822Sdim NUF(vqshluq,   1800610, 3, (RNQ,  oRNQ,  I63), neon_qshlu_imm),
16064218822Sdim  /* Right shift immediate, saturating & narrowing, with rounding variants.
16065218822Sdim     Types accepted S16 S32 S64 U16 U32 U64.  */
16066218822Sdim NUF(vqshrn,    0800910, 3, (RND, RNQ, I32z), neon_rshift_sat_narrow),
16067218822Sdim NUF(vqrshrn,   0800950, 3, (RND, RNQ, I32z), neon_rshift_sat_narrow),
16068218822Sdim  /* As above, unsigned. Types accepted S16 S32 S64.  */
16069218822Sdim NUF(vqshrun,   0800810, 3, (RND, RNQ, I32z), neon_rshift_sat_narrow_u),
16070218822Sdim NUF(vqrshrun,  0800850, 3, (RND, RNQ, I32z), neon_rshift_sat_narrow_u),
16071218822Sdim  /* Right shift narrowing. Types accepted I16 I32 I64.  */
16072218822Sdim NUF(vshrn,     0800810, 3, (RND, RNQ, I32z), neon_rshift_narrow),
16073218822Sdim NUF(vrshrn,    0800850, 3, (RND, RNQ, I32z), neon_rshift_narrow),
16074218822Sdim  /* Special case. Types S8 S16 S32 U8 U16 U32. Handles max shift variant.  */
16075218822Sdim nUF(vshll,     vshll,   3, (RNQ, RND, I32),  neon_shll),
16076218822Sdim  /* CVT with optional immediate for fixed-point variant.  */
16077218822Sdim nUF(vcvtq,     vcvt,    3, (RNQ, RNQ, oI32b), neon_cvt),
16078218822Sdim
16079218822Sdim nUF(vmvn,      vmvn,    2, (RNDQ, RNDQ_IMVNb), neon_mvn),
16080218822Sdim nUF(vmvnq,     vmvn,    2, (RNQ,  RNDQ_IMVNb), neon_mvn),
16081218822Sdim
16082218822Sdim  /* Data processing, three registers of different lengths.  */
16083218822Sdim  /* Dyadic, long insns. Types S8 S16 S32 U8 U16 U32.  */
16084218822Sdim NUF(vabal,     0800500, 3, (RNQ, RND, RND),  neon_abal),
16085218822Sdim NUF(vabdl,     0800700, 3, (RNQ, RND, RND),  neon_dyadic_long),
16086218822Sdim NUF(vaddl,     0800000, 3, (RNQ, RND, RND),  neon_dyadic_long),
16087218822Sdim NUF(vsubl,     0800200, 3, (RNQ, RND, RND),  neon_dyadic_long),
16088218822Sdim  /* If not scalar, fall back to neon_dyadic_long.
16089218822Sdim     Vector types as above, scalar types S16 S32 U16 U32.  */
16090218822Sdim nUF(vmlal,     vmlal,   3, (RNQ, RND, RND_RNSC), neon_mac_maybe_scalar_long),
16091218822Sdim nUF(vmlsl,     vmlsl,   3, (RNQ, RND, RND_RNSC), neon_mac_maybe_scalar_long),
16092218822Sdim  /* Dyadic, widening insns. Types S8 S16 S32 U8 U16 U32.  */
16093218822Sdim NUF(vaddw,     0800100, 3, (RNQ, oRNQ, RND), neon_dyadic_wide),
16094218822Sdim NUF(vsubw,     0800300, 3, (RNQ, oRNQ, RND), neon_dyadic_wide),
16095218822Sdim  /* Dyadic, narrowing insns. Types I16 I32 I64.  */
16096218822Sdim NUF(vaddhn,    0800400, 3, (RND, RNQ, RNQ),  neon_dyadic_narrow),
16097218822Sdim NUF(vraddhn,   1800400, 3, (RND, RNQ, RNQ),  neon_dyadic_narrow),
16098218822Sdim NUF(vsubhn,    0800600, 3, (RND, RNQ, RNQ),  neon_dyadic_narrow),
16099218822Sdim NUF(vrsubhn,   1800600, 3, (RND, RNQ, RNQ),  neon_dyadic_narrow),
16100218822Sdim  /* Saturating doubling multiplies. Types S16 S32.  */
16101218822Sdim nUF(vqdmlal,   vqdmlal, 3, (RNQ, RND, RND_RNSC), neon_mul_sat_scalar_long),
16102218822Sdim nUF(vqdmlsl,   vqdmlsl, 3, (RNQ, RND, RND_RNSC), neon_mul_sat_scalar_long),
16103218822Sdim nUF(vqdmull,   vqdmull, 3, (RNQ, RND, RND_RNSC), neon_mul_sat_scalar_long),
16104218822Sdim  /* VMULL. Vector types S8 S16 S32 U8 U16 U32 P8, scalar types
16105218822Sdim     S16 S32 U16 U32.  */
16106218822Sdim nUF(vmull,     vmull,   3, (RNQ, RND, RND_RNSC), neon_vmull),
16107218822Sdim
16108218822Sdim  /* Extract. Size 8.  */
16109218822Sdim NUF(vext,      0b00000, 4, (RNDQ, oRNDQ, RNDQ, I15), neon_ext),
16110218822Sdim NUF(vextq,     0b00000, 4, (RNQ,  oRNQ,  RNQ,  I15), neon_ext),
16111218822Sdim
16112218822Sdim  /* Two registers, miscellaneous.  */
16113218822Sdim  /* Reverse. Sizes 8 16 32 (must be < size in opcode).  */
16114218822Sdim NUF(vrev64,    1b00000, 2, (RNDQ, RNDQ),     neon_rev),
16115218822Sdim NUF(vrev64q,   1b00000, 2, (RNQ,  RNQ),      neon_rev),
16116218822Sdim NUF(vrev32,    1b00080, 2, (RNDQ, RNDQ),     neon_rev),
16117218822Sdim NUF(vrev32q,   1b00080, 2, (RNQ,  RNQ),      neon_rev),
16118218822Sdim NUF(vrev16,    1b00100, 2, (RNDQ, RNDQ),     neon_rev),
16119218822Sdim NUF(vrev16q,   1b00100, 2, (RNQ,  RNQ),      neon_rev),
16120218822Sdim  /* Vector replicate. Sizes 8 16 32.  */
16121218822Sdim nCE(vdup,      vdup,    2, (RNDQ, RR_RNSC),  neon_dup),
16122218822Sdim nCE(vdupq,     vdup,    2, (RNQ,  RR_RNSC),  neon_dup),
16123218822Sdim  /* VMOVL. Types S8 S16 S32 U8 U16 U32.  */
16124218822Sdim NUF(vmovl,     0800a10, 2, (RNQ, RND),       neon_movl),
16125218822Sdim  /* VMOVN. Types I16 I32 I64.  */
16126218822Sdim nUF(vmovn,     vmovn,   2, (RND, RNQ),       neon_movn),
16127218822Sdim  /* VQMOVN. Types S16 S32 S64 U16 U32 U64.  */
16128218822Sdim nUF(vqmovn,    vqmovn,  2, (RND, RNQ),       neon_qmovn),
16129218822Sdim  /* VQMOVUN. Types S16 S32 S64.  */
16130218822Sdim nUF(vqmovun,   vqmovun, 2, (RND, RNQ),       neon_qmovun),
16131218822Sdim  /* VZIP / VUZP. Sizes 8 16 32.  */
16132218822Sdim NUF(vzip,      1b20180, 2, (RNDQ, RNDQ),     neon_zip_uzp),
16133218822Sdim NUF(vzipq,     1b20180, 2, (RNQ,  RNQ),      neon_zip_uzp),
16134218822Sdim NUF(vuzp,      1b20100, 2, (RNDQ, RNDQ),     neon_zip_uzp),
16135218822Sdim NUF(vuzpq,     1b20100, 2, (RNQ,  RNQ),      neon_zip_uzp),
16136218822Sdim  /* VQABS / VQNEG. Types S8 S16 S32.  */
16137218822Sdim NUF(vqabs,     1b00700, 2, (RNDQ, RNDQ),     neon_sat_abs_neg),
16138218822Sdim NUF(vqabsq,    1b00700, 2, (RNQ,  RNQ),      neon_sat_abs_neg),
16139218822Sdim NUF(vqneg,     1b00780, 2, (RNDQ, RNDQ),     neon_sat_abs_neg),
16140218822Sdim NUF(vqnegq,    1b00780, 2, (RNQ,  RNQ),      neon_sat_abs_neg),
16141218822Sdim  /* Pairwise, lengthening. Types S8 S16 S32 U8 U16 U32.  */
16142218822Sdim NUF(vpadal,    1b00600, 2, (RNDQ, RNDQ),     neon_pair_long),
16143218822Sdim NUF(vpadalq,   1b00600, 2, (RNQ,  RNQ),      neon_pair_long),
16144218822Sdim NUF(vpaddl,    1b00200, 2, (RNDQ, RNDQ),     neon_pair_long),
16145218822Sdim NUF(vpaddlq,   1b00200, 2, (RNQ,  RNQ),      neon_pair_long),
16146218822Sdim  /* Reciprocal estimates. Types U32 F32.  */
16147218822Sdim NUF(vrecpe,    1b30400, 2, (RNDQ, RNDQ),     neon_recip_est),
16148218822Sdim NUF(vrecpeq,   1b30400, 2, (RNQ,  RNQ),      neon_recip_est),
16149218822Sdim NUF(vrsqrte,   1b30480, 2, (RNDQ, RNDQ),     neon_recip_est),
16150218822Sdim NUF(vrsqrteq,  1b30480, 2, (RNQ,  RNQ),      neon_recip_est),
16151218822Sdim  /* VCLS. Types S8 S16 S32.  */
16152218822Sdim NUF(vcls,      1b00400, 2, (RNDQ, RNDQ),     neon_cls),
16153218822Sdim NUF(vclsq,     1b00400, 2, (RNQ,  RNQ),      neon_cls),
16154218822Sdim  /* VCLZ. Types I8 I16 I32.  */
16155218822Sdim NUF(vclz,      1b00480, 2, (RNDQ, RNDQ),     neon_clz),
16156218822Sdim NUF(vclzq,     1b00480, 2, (RNQ,  RNQ),      neon_clz),
16157218822Sdim  /* VCNT. Size 8.  */
16158218822Sdim NUF(vcnt,      1b00500, 2, (RNDQ, RNDQ),     neon_cnt),
16159218822Sdim NUF(vcntq,     1b00500, 2, (RNQ,  RNQ),      neon_cnt),
16160218822Sdim  /* Two address, untyped.  */
16161218822Sdim NUF(vswp,      1b20000, 2, (RNDQ, RNDQ),     neon_swp),
16162218822Sdim NUF(vswpq,     1b20000, 2, (RNQ,  RNQ),      neon_swp),
16163218822Sdim  /* VTRN. Sizes 8 16 32.  */
16164218822Sdim nUF(vtrn,      vtrn,    2, (RNDQ, RNDQ),     neon_trn),
16165218822Sdim nUF(vtrnq,     vtrn,    2, (RNQ,  RNQ),      neon_trn),
16166218822Sdim
16167218822Sdim  /* Table lookup. Size 8.  */
16168218822Sdim NUF(vtbl,      1b00800, 3, (RND, NRDLST, RND), neon_tbl_tbx),
16169218822Sdim NUF(vtbx,      1b00840, 3, (RND, NRDLST, RND), neon_tbl_tbx),
16170218822Sdim
16171218822Sdim#undef THUMB_VARIANT
16172218822Sdim#define THUMB_VARIANT &fpu_vfp_v3_or_neon_ext
16173218822Sdim#undef ARM_VARIANT
16174218822Sdim#define ARM_VARIANT &fpu_vfp_v3_or_neon_ext
16175218822Sdim  /* Neon element/structure load/store.  */
16176218822Sdim nUF(vld1,      vld1,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16177218822Sdim nUF(vst1,      vst1,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16178218822Sdim nUF(vld2,      vld2,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16179218822Sdim nUF(vst2,      vst2,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16180218822Sdim nUF(vld3,      vld3,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16181218822Sdim nUF(vst3,      vst3,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16182218822Sdim nUF(vld4,      vld4,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16183218822Sdim nUF(vst4,      vst4,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16184218822Sdim
16185218822Sdim#undef THUMB_VARIANT
16186218822Sdim#define THUMB_VARIANT &fpu_vfp_ext_v3
16187218822Sdim#undef ARM_VARIANT
16188218822Sdim#define ARM_VARIANT &fpu_vfp_ext_v3
16189218822Sdim cCE(fconsts,   eb00a00, 2, (RVS, I255),      vfp_sp_const),
16190218822Sdim cCE(fconstd,   eb00b00, 2, (RVD, I255),      vfp_dp_const),
16191218822Sdim cCE(fshtos,    eba0a40, 2, (RVS, I16z),      vfp_sp_conv_16),
16192218822Sdim cCE(fshtod,    eba0b40, 2, (RVD, I16z),      vfp_dp_conv_16),
16193218822Sdim cCE(fsltos,    eba0ac0, 2, (RVS, I32),       vfp_sp_conv_32),
16194218822Sdim cCE(fsltod,    eba0bc0, 2, (RVD, I32),       vfp_dp_conv_32),
16195218822Sdim cCE(fuhtos,    ebb0a40, 2, (RVS, I16z),      vfp_sp_conv_16),
16196218822Sdim cCE(fuhtod,    ebb0b40, 2, (RVD, I16z),      vfp_dp_conv_16),
16197218822Sdim cCE(fultos,    ebb0ac0, 2, (RVS, I32),       vfp_sp_conv_32),
16198218822Sdim cCE(fultod,    ebb0bc0, 2, (RVD, I32),       vfp_dp_conv_32),
16199218822Sdim cCE(ftoshs,    ebe0a40, 2, (RVS, I16z),      vfp_sp_conv_16),
16200218822Sdim cCE(ftoshd,    ebe0b40, 2, (RVD, I16z),      vfp_dp_conv_16),
16201218822Sdim cCE(ftosls,    ebe0ac0, 2, (RVS, I32),       vfp_sp_conv_32),
16202218822Sdim cCE(ftosld,    ebe0bc0, 2, (RVD, I32),       vfp_dp_conv_32),
16203218822Sdim cCE(ftouhs,    ebf0a40, 2, (RVS, I16z),      vfp_sp_conv_16),
16204218822Sdim cCE(ftouhd,    ebf0b40, 2, (RVD, I16z),      vfp_dp_conv_16),
16205218822Sdim cCE(ftouls,    ebf0ac0, 2, (RVS, I32),       vfp_sp_conv_32),
16206218822Sdim cCE(ftould,    ebf0bc0, 2, (RVD, I32),       vfp_dp_conv_32),
16207218822Sdim
16208218822Sdim#undef THUMB_VARIANT
16209218822Sdim#undef ARM_VARIANT
16210218822Sdim#define ARM_VARIANT &arm_cext_xscale /* Intel XScale extensions.	 */
16211218822Sdim cCE(mia,	e200010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16212218822Sdim cCE(miaph,	e280010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16213218822Sdim cCE(miabb,	e2c0010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16214218822Sdim cCE(miabt,	e2d0010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16215218822Sdim cCE(miatb,	e2e0010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16216218822Sdim cCE(miatt,	e2f0010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16217218822Sdim cCE(mar,	c400000, 3, (RXA, RRnpc, RRnpc), xsc_mar),
16218218822Sdim cCE(mra,	c500000, 3, (RRnpc, RRnpc, RXA), xsc_mra),
16219218822Sdim
16220218822Sdim#undef ARM_VARIANT
16221218822Sdim#define ARM_VARIANT &arm_cext_iwmmxt /* Intel Wireless MMX technology.  */
16222218822Sdim cCE(tandcb,	e13f130, 1, (RR),		    iwmmxt_tandorc),
16223218822Sdim cCE(tandch,	e53f130, 1, (RR),		    iwmmxt_tandorc),
16224218822Sdim cCE(tandcw,	e93f130, 1, (RR),		    iwmmxt_tandorc),
16225218822Sdim cCE(tbcstb,	e400010, 2, (RIWR, RR),		    rn_rd),
16226218822Sdim cCE(tbcsth,	e400050, 2, (RIWR, RR),		    rn_rd),
16227218822Sdim cCE(tbcstw,	e400090, 2, (RIWR, RR),		    rn_rd),
16228218822Sdim cCE(textrcb,	e130170, 2, (RR, I7),		    iwmmxt_textrc),
16229218822Sdim cCE(textrch,	e530170, 2, (RR, I7),		    iwmmxt_textrc),
16230218822Sdim cCE(textrcw,	e930170, 2, (RR, I7),		    iwmmxt_textrc),
16231218822Sdim cCE(textrmub,	e100070, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16232218822Sdim cCE(textrmuh,	e500070, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16233218822Sdim cCE(textrmuw,	e900070, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16234218822Sdim cCE(textrmsb,	e100078, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16235218822Sdim cCE(textrmsh,	e500078, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16236218822Sdim cCE(textrmsw,	e900078, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16237218822Sdim cCE(tinsrb,	e600010, 3, (RIWR, RR, I7),	    iwmmxt_tinsr),
16238218822Sdim cCE(tinsrh,	e600050, 3, (RIWR, RR, I7),	    iwmmxt_tinsr),
16239218822Sdim cCE(tinsrw,	e600090, 3, (RIWR, RR, I7),	    iwmmxt_tinsr),
16240218822Sdim cCE(tmcr,	e000110, 2, (RIWC_RIWG, RR),	    rn_rd),
16241218822Sdim cCE(tmcrr,	c400000, 3, (RIWR, RR, RR),	    rm_rd_rn),
16242218822Sdim cCE(tmia,	e200010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16243218822Sdim cCE(tmiaph,	e280010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16244218822Sdim cCE(tmiabb,	e2c0010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16245218822Sdim cCE(tmiabt,	e2d0010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16246218822Sdim cCE(tmiatb,	e2e0010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16247218822Sdim cCE(tmiatt,	e2f0010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16248218822Sdim cCE(tmovmskb,	e100030, 2, (RR, RIWR),		    rd_rn),
16249218822Sdim cCE(tmovmskh,	e500030, 2, (RR, RIWR),		    rd_rn),
16250218822Sdim cCE(tmovmskw,	e900030, 2, (RR, RIWR),		    rd_rn),
16251218822Sdim cCE(tmrc,	e100110, 2, (RR, RIWC_RIWG),	    rd_rn),
16252218822Sdim cCE(tmrrc,	c500000, 3, (RR, RR, RIWR),	    rd_rn_rm),
16253218822Sdim cCE(torcb,	e13f150, 1, (RR),		    iwmmxt_tandorc),
16254218822Sdim cCE(torch,	e53f150, 1, (RR),		    iwmmxt_tandorc),
16255218822Sdim cCE(torcw,	e93f150, 1, (RR),		    iwmmxt_tandorc),
16256218822Sdim cCE(waccb,	e0001c0, 2, (RIWR, RIWR),	    rd_rn),
16257218822Sdim cCE(wacch,	e4001c0, 2, (RIWR, RIWR),	    rd_rn),
16258218822Sdim cCE(waccw,	e8001c0, 2, (RIWR, RIWR),	    rd_rn),
16259218822Sdim cCE(waddbss,	e300180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16260218822Sdim cCE(waddb,	e000180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16261218822Sdim cCE(waddbus,	e100180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16262218822Sdim cCE(waddhss,	e700180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16263218822Sdim cCE(waddh,	e400180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16264218822Sdim cCE(waddhus,	e500180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16265218822Sdim cCE(waddwss,	eb00180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16266218822Sdim cCE(waddw,	e800180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16267218822Sdim cCE(waddwus,	e900180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16268218822Sdim cCE(waligni,	e000020, 4, (RIWR, RIWR, RIWR, I7), iwmmxt_waligni),
16269218822Sdim cCE(walignr0,	e800020, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16270218822Sdim cCE(walignr1,	e900020, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16271218822Sdim cCE(walignr2,	ea00020, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16272218822Sdim cCE(walignr3,	eb00020, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16273218822Sdim cCE(wand,	e200000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16274218822Sdim cCE(wandn,	e300000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16275218822Sdim cCE(wavg2b,	e800000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16276218822Sdim cCE(wavg2br,	e900000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16277218822Sdim cCE(wavg2h,	ec00000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16278218822Sdim cCE(wavg2hr,	ed00000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16279218822Sdim cCE(wcmpeqb,	e000060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16280218822Sdim cCE(wcmpeqh,	e400060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16281218822Sdim cCE(wcmpeqw,	e800060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16282218822Sdim cCE(wcmpgtub,	e100060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16283218822Sdim cCE(wcmpgtuh,	e500060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16284218822Sdim cCE(wcmpgtuw,	e900060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16285218822Sdim cCE(wcmpgtsb,	e300060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16286218822Sdim cCE(wcmpgtsh,	e700060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16287218822Sdim cCE(wcmpgtsw,	eb00060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16288218822Sdim cCE(wldrb,	c100000, 2, (RIWR, ADDR),	    iwmmxt_wldstbh),
16289218822Sdim cCE(wldrh,	c500000, 2, (RIWR, ADDR),	    iwmmxt_wldstbh),
16290218822Sdim cCE(wldrw,	c100100, 2, (RIWR_RIWC, ADDR),	    iwmmxt_wldstw),
16291218822Sdim cCE(wldrd,	c500100, 2, (RIWR, ADDR),	    iwmmxt_wldstd),
16292218822Sdim cCE(wmacs,	e600100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16293218822Sdim cCE(wmacsz,	e700100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16294218822Sdim cCE(wmacu,	e400100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16295218822Sdim cCE(wmacuz,	e500100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16296218822Sdim cCE(wmadds,	ea00100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16297218822Sdim cCE(wmaddu,	e800100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16298218822Sdim cCE(wmaxsb,	e200160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16299218822Sdim cCE(wmaxsh,	e600160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16300218822Sdim cCE(wmaxsw,	ea00160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16301218822Sdim cCE(wmaxub,	e000160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16302218822Sdim cCE(wmaxuh,	e400160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16303218822Sdim cCE(wmaxuw,	e800160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16304218822Sdim cCE(wminsb,	e300160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16305218822Sdim cCE(wminsh,	e700160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16306218822Sdim cCE(wminsw,	eb00160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16307218822Sdim cCE(wminub,	e100160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16308218822Sdim cCE(wminuh,	e500160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16309218822Sdim cCE(wminuw,	e900160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16310218822Sdim cCE(wmov,	e000000, 2, (RIWR, RIWR),	    iwmmxt_wmov),
16311218822Sdim cCE(wmulsm,	e300100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16312218822Sdim cCE(wmulsl,	e200100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16313218822Sdim cCE(wmulum,	e100100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16314218822Sdim cCE(wmulul,	e000100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16315218822Sdim cCE(wor,	e000000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16316218822Sdim cCE(wpackhss,	e700080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16317218822Sdim cCE(wpackhus,	e500080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16318218822Sdim cCE(wpackwss,	eb00080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16319218822Sdim cCE(wpackwus,	e900080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16320218822Sdim cCE(wpackdss,	ef00080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16321218822Sdim cCE(wpackdus,	ed00080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16322218822Sdim cCE(wrorh,	e700040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16323218822Sdim cCE(wrorhg,	e700148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16324218822Sdim cCE(wrorw,	eb00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16325218822Sdim cCE(wrorwg,	eb00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16326218822Sdim cCE(wrord,	ef00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16327218822Sdim cCE(wrordg,	ef00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16328218822Sdim cCE(wsadb,	e000120, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16329218822Sdim cCE(wsadbz,	e100120, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16330218822Sdim cCE(wsadh,	e400120, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16331218822Sdim cCE(wsadhz,	e500120, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16332218822Sdim cCE(wshufh,	e0001e0, 3, (RIWR, RIWR, I255),	    iwmmxt_wshufh),
16333218822Sdim cCE(wsllh,	e500040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16334218822Sdim cCE(wsllhg,	e500148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16335218822Sdim cCE(wsllw,	e900040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16336218822Sdim cCE(wsllwg,	e900148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16337218822Sdim cCE(wslld,	ed00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16338218822Sdim cCE(wslldg,	ed00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16339218822Sdim cCE(wsrah,	e400040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16340218822Sdim cCE(wsrahg,	e400148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16341218822Sdim cCE(wsraw,	e800040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16342218822Sdim cCE(wsrawg,	e800148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16343218822Sdim cCE(wsrad,	ec00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16344218822Sdim cCE(wsradg,	ec00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16345218822Sdim cCE(wsrlh,	e600040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16346218822Sdim cCE(wsrlhg,	e600148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16347218822Sdim cCE(wsrlw,	ea00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16348218822Sdim cCE(wsrlwg,	ea00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16349218822Sdim cCE(wsrld,	ee00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16350218822Sdim cCE(wsrldg,	ee00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16351218822Sdim cCE(wstrb,	c000000, 2, (RIWR, ADDR),	    iwmmxt_wldstbh),
16352218822Sdim cCE(wstrh,	c400000, 2, (RIWR, ADDR),	    iwmmxt_wldstbh),
16353218822Sdim cCE(wstrw,	c000100, 2, (RIWR_RIWC, ADDR),	    iwmmxt_wldstw),
16354218822Sdim cCE(wstrd,	c400100, 2, (RIWR, ADDR),	    iwmmxt_wldstd),
16355218822Sdim cCE(wsubbss,	e3001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16356218822Sdim cCE(wsubb,	e0001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16357218822Sdim cCE(wsubbus,	e1001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16358218822Sdim cCE(wsubhss,	e7001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16359218822Sdim cCE(wsubh,	e4001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16360218822Sdim cCE(wsubhus,	e5001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16361218822Sdim cCE(wsubwss,	eb001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16362218822Sdim cCE(wsubw,	e8001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16363218822Sdim cCE(wsubwus,	e9001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16364218822Sdim cCE(wunpckehub,e0000c0, 2, (RIWR, RIWR),	    rd_rn),
16365218822Sdim cCE(wunpckehuh,e4000c0, 2, (RIWR, RIWR),	    rd_rn),
16366218822Sdim cCE(wunpckehuw,e8000c0, 2, (RIWR, RIWR),	    rd_rn),
16367218822Sdim cCE(wunpckehsb,e2000c0, 2, (RIWR, RIWR),	    rd_rn),
16368218822Sdim cCE(wunpckehsh,e6000c0, 2, (RIWR, RIWR),	    rd_rn),
16369218822Sdim cCE(wunpckehsw,ea000c0, 2, (RIWR, RIWR),	    rd_rn),
16370218822Sdim cCE(wunpckihb, e1000c0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16371218822Sdim cCE(wunpckihh, e5000c0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16372218822Sdim cCE(wunpckihw, e9000c0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16373218822Sdim cCE(wunpckelub,e0000e0, 2, (RIWR, RIWR),	    rd_rn),
16374218822Sdim cCE(wunpckeluh,e4000e0, 2, (RIWR, RIWR),	    rd_rn),
16375218822Sdim cCE(wunpckeluw,e8000e0, 2, (RIWR, RIWR),	    rd_rn),
16376218822Sdim cCE(wunpckelsb,e2000e0, 2, (RIWR, RIWR),	    rd_rn),
16377218822Sdim cCE(wunpckelsh,e6000e0, 2, (RIWR, RIWR),	    rd_rn),
16378218822Sdim cCE(wunpckelsw,ea000e0, 2, (RIWR, RIWR),	    rd_rn),
16379218822Sdim cCE(wunpckilb, e1000e0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16380218822Sdim cCE(wunpckilh, e5000e0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16381218822Sdim cCE(wunpckilw, e9000e0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16382218822Sdim cCE(wxor,	e100000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16383218822Sdim cCE(wzero,	e300000, 1, (RIWR),		    iwmmxt_wzero),
16384218822Sdim
16385218822Sdim#undef ARM_VARIANT
16386218822Sdim#define ARM_VARIANT &arm_cext_iwmmxt2 /* Intel Wireless MMX technology, version 2.  */
16387218822Sdim cCE(torvscb,   e13f190, 1, (RR),		    iwmmxt_tandorc),
16388218822Sdim cCE(torvsch,   e53f190, 1, (RR),		    iwmmxt_tandorc),
16389218822Sdim cCE(torvscw,   e93f190, 1, (RR),		    iwmmxt_tandorc),
16390218822Sdim cCE(wabsb,     e2001c0, 2, (RIWR, RIWR),           rd_rn),
16391218822Sdim cCE(wabsh,     e6001c0, 2, (RIWR, RIWR),           rd_rn),
16392218822Sdim cCE(wabsw,     ea001c0, 2, (RIWR, RIWR),           rd_rn),
16393218822Sdim cCE(wabsdiffb, e1001c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16394218822Sdim cCE(wabsdiffh, e5001c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16395218822Sdim cCE(wabsdiffw, e9001c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16396218822Sdim cCE(waddbhusl, e2001a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16397218822Sdim cCE(waddbhusm, e6001a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16398218822Sdim cCE(waddhc,    e600180, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16399218822Sdim cCE(waddwc,    ea00180, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16400218822Sdim cCE(waddsubhx, ea001a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16401218822Sdim cCE(wavg4,	e400000, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16402218822Sdim cCE(wavg4r,    e500000, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16403218822Sdim cCE(wmaddsn,   ee00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16404218822Sdim cCE(wmaddsx,   eb00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16405218822Sdim cCE(wmaddun,   ec00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16406218822Sdim cCE(wmaddux,   e900100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16407218822Sdim cCE(wmerge,    e000080, 4, (RIWR, RIWR, RIWR, I7), iwmmxt_wmerge),
16408218822Sdim cCE(wmiabb,    e0000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16409218822Sdim cCE(wmiabt,    e1000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16410218822Sdim cCE(wmiatb,    e2000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16411218822Sdim cCE(wmiatt,    e3000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16412218822Sdim cCE(wmiabbn,   e4000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16413218822Sdim cCE(wmiabtn,   e5000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16414218822Sdim cCE(wmiatbn,   e6000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16415218822Sdim cCE(wmiattn,   e7000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16416218822Sdim cCE(wmiawbb,   e800120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16417218822Sdim cCE(wmiawbt,   e900120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16418218822Sdim cCE(wmiawtb,   ea00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16419218822Sdim cCE(wmiawtt,   eb00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16420218822Sdim cCE(wmiawbbn,  ec00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16421218822Sdim cCE(wmiawbtn,  ed00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16422218822Sdim cCE(wmiawtbn,  ee00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16423218822Sdim cCE(wmiawttn,  ef00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16424218822Sdim cCE(wmulsmr,   ef00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16425218822Sdim cCE(wmulumr,   ed00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16426218822Sdim cCE(wmulwumr,  ec000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16427218822Sdim cCE(wmulwsmr,  ee000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16428218822Sdim cCE(wmulwum,   ed000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16429218822Sdim cCE(wmulwsm,   ef000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16430218822Sdim cCE(wmulwl,    eb000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16431218822Sdim cCE(wqmiabb,   e8000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16432218822Sdim cCE(wqmiabt,   e9000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16433218822Sdim cCE(wqmiatb,   ea000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16434218822Sdim cCE(wqmiatt,   eb000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16435218822Sdim cCE(wqmiabbn,  ec000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16436218822Sdim cCE(wqmiabtn,  ed000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16437218822Sdim cCE(wqmiatbn,  ee000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16438218822Sdim cCE(wqmiattn,  ef000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16439218822Sdim cCE(wqmulm,    e100080, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16440218822Sdim cCE(wqmulmr,   e300080, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16441218822Sdim cCE(wqmulwm,   ec000e0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16442218822Sdim cCE(wqmulwmr,  ee000e0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16443218822Sdim cCE(wsubaddhx, ed001c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16444218822Sdim
16445218822Sdim#undef ARM_VARIANT
16446218822Sdim#define ARM_VARIANT &arm_cext_maverick /* Cirrus Maverick instructions.	*/
16447218822Sdim cCE(cfldrs,	c100400, 2, (RMF, ADDRGLDC),	      rd_cpaddr),
16448218822Sdim cCE(cfldrd,	c500400, 2, (RMD, ADDRGLDC),	      rd_cpaddr),
16449218822Sdim cCE(cfldr32,	c100500, 2, (RMFX, ADDRGLDC),	      rd_cpaddr),
16450218822Sdim cCE(cfldr64,	c500500, 2, (RMDX, ADDRGLDC),	      rd_cpaddr),
16451218822Sdim cCE(cfstrs,	c000400, 2, (RMF, ADDRGLDC),	      rd_cpaddr),
16452218822Sdim cCE(cfstrd,	c400400, 2, (RMD, ADDRGLDC),	      rd_cpaddr),
16453218822Sdim cCE(cfstr32,	c000500, 2, (RMFX, ADDRGLDC),	      rd_cpaddr),
16454218822Sdim cCE(cfstr64,	c400500, 2, (RMDX, ADDRGLDC),	      rd_cpaddr),
16455218822Sdim cCE(cfmvsr,	e000450, 2, (RMF, RR),		      rn_rd),
16456218822Sdim cCE(cfmvrs,	e100450, 2, (RR, RMF),		      rd_rn),
16457218822Sdim cCE(cfmvdlr,	e000410, 2, (RMD, RR),		      rn_rd),
16458218822Sdim cCE(cfmvrdl,	e100410, 2, (RR, RMD),		      rd_rn),
16459218822Sdim cCE(cfmvdhr,	e000430, 2, (RMD, RR),		      rn_rd),
16460218822Sdim cCE(cfmvrdh,	e100430, 2, (RR, RMD),		      rd_rn),
16461218822Sdim cCE(cfmv64lr,	e000510, 2, (RMDX, RR),		      rn_rd),
16462218822Sdim cCE(cfmvr64l,	e100510, 2, (RR, RMDX),		      rd_rn),
16463218822Sdim cCE(cfmv64hr,	e000530, 2, (RMDX, RR),		      rn_rd),
16464218822Sdim cCE(cfmvr64h,	e100530, 2, (RR, RMDX),		      rd_rn),
16465218822Sdim cCE(cfmval32,	e200440, 2, (RMAX, RMFX),	      rd_rn),
16466218822Sdim cCE(cfmv32al,	e100440, 2, (RMFX, RMAX),	      rd_rn),
16467218822Sdim cCE(cfmvam32,	e200460, 2, (RMAX, RMFX),	      rd_rn),
16468218822Sdim cCE(cfmv32am,	e100460, 2, (RMFX, RMAX),	      rd_rn),
16469218822Sdim cCE(cfmvah32,	e200480, 2, (RMAX, RMFX),	      rd_rn),
16470218822Sdim cCE(cfmv32ah,	e100480, 2, (RMFX, RMAX),	      rd_rn),
16471218822Sdim cCE(cfmva32,	e2004a0, 2, (RMAX, RMFX),	      rd_rn),
16472218822Sdim cCE(cfmv32a,	e1004a0, 2, (RMFX, RMAX),	      rd_rn),
16473218822Sdim cCE(cfmva64,	e2004c0, 2, (RMAX, RMDX),	      rd_rn),
16474218822Sdim cCE(cfmv64a,	e1004c0, 2, (RMDX, RMAX),	      rd_rn),
16475218822Sdim cCE(cfmvsc32,	e2004e0, 2, (RMDS, RMDX),	      mav_dspsc),
16476218822Sdim cCE(cfmv32sc,	e1004e0, 2, (RMDX, RMDS),	      rd),
16477218822Sdim cCE(cfcpys,	e000400, 2, (RMF, RMF),		      rd_rn),
16478218822Sdim cCE(cfcpyd,	e000420, 2, (RMD, RMD),		      rd_rn),
16479218822Sdim cCE(cfcvtsd,	e000460, 2, (RMD, RMF),		      rd_rn),
16480218822Sdim cCE(cfcvtds,	e000440, 2, (RMF, RMD),		      rd_rn),
16481218822Sdim cCE(cfcvt32s,	e000480, 2, (RMF, RMFX),	      rd_rn),
16482218822Sdim cCE(cfcvt32d,	e0004a0, 2, (RMD, RMFX),	      rd_rn),
16483218822Sdim cCE(cfcvt64s,	e0004c0, 2, (RMF, RMDX),	      rd_rn),
16484218822Sdim cCE(cfcvt64d,	e0004e0, 2, (RMD, RMDX),	      rd_rn),
16485218822Sdim cCE(cfcvts32,	e100580, 2, (RMFX, RMF),	      rd_rn),
16486218822Sdim cCE(cfcvtd32,	e1005a0, 2, (RMFX, RMD),	      rd_rn),
16487218822Sdim cCE(cftruncs32,e1005c0, 2, (RMFX, RMF),	      rd_rn),
16488218822Sdim cCE(cftruncd32,e1005e0, 2, (RMFX, RMD),	      rd_rn),
16489218822Sdim cCE(cfrshl32,	e000550, 3, (RMFX, RMFX, RR),	      mav_triple),
16490218822Sdim cCE(cfrshl64,	e000570, 3, (RMDX, RMDX, RR),	      mav_triple),
16491218822Sdim cCE(cfsh32,	e000500, 3, (RMFX, RMFX, I63s),	      mav_shift),
16492218822Sdim cCE(cfsh64,	e200500, 3, (RMDX, RMDX, I63s),	      mav_shift),
16493218822Sdim cCE(cfcmps,	e100490, 3, (RR, RMF, RMF),	      rd_rn_rm),
16494218822Sdim cCE(cfcmpd,	e1004b0, 3, (RR, RMD, RMD),	      rd_rn_rm),
16495218822Sdim cCE(cfcmp32,	e100590, 3, (RR, RMFX, RMFX),	      rd_rn_rm),
16496218822Sdim cCE(cfcmp64,	e1005b0, 3, (RR, RMDX, RMDX),	      rd_rn_rm),
16497218822Sdim cCE(cfabss,	e300400, 2, (RMF, RMF),		      rd_rn),
16498218822Sdim cCE(cfabsd,	e300420, 2, (RMD, RMD),		      rd_rn),
16499218822Sdim cCE(cfnegs,	e300440, 2, (RMF, RMF),		      rd_rn),
16500218822Sdim cCE(cfnegd,	e300460, 2, (RMD, RMD),		      rd_rn),
16501218822Sdim cCE(cfadds,	e300480, 3, (RMF, RMF, RMF),	      rd_rn_rm),
16502218822Sdim cCE(cfaddd,	e3004a0, 3, (RMD, RMD, RMD),	      rd_rn_rm),
16503218822Sdim cCE(cfsubs,	e3004c0, 3, (RMF, RMF, RMF),	      rd_rn_rm),
16504218822Sdim cCE(cfsubd,	e3004e0, 3, (RMD, RMD, RMD),	      rd_rn_rm),
16505218822Sdim cCE(cfmuls,	e100400, 3, (RMF, RMF, RMF),	      rd_rn_rm),
16506218822Sdim cCE(cfmuld,	e100420, 3, (RMD, RMD, RMD),	      rd_rn_rm),
16507218822Sdim cCE(cfabs32,	e300500, 2, (RMFX, RMFX),	      rd_rn),
16508218822Sdim cCE(cfabs64,	e300520, 2, (RMDX, RMDX),	      rd_rn),
16509218822Sdim cCE(cfneg32,	e300540, 2, (RMFX, RMFX),	      rd_rn),
16510218822Sdim cCE(cfneg64,	e300560, 2, (RMDX, RMDX),	      rd_rn),
16511218822Sdim cCE(cfadd32,	e300580, 3, (RMFX, RMFX, RMFX),	      rd_rn_rm),
16512218822Sdim cCE(cfadd64,	e3005a0, 3, (RMDX, RMDX, RMDX),	      rd_rn_rm),
16513218822Sdim cCE(cfsub32,	e3005c0, 3, (RMFX, RMFX, RMFX),	      rd_rn_rm),
16514218822Sdim cCE(cfsub64,	e3005e0, 3, (RMDX, RMDX, RMDX),	      rd_rn_rm),
16515218822Sdim cCE(cfmul32,	e100500, 3, (RMFX, RMFX, RMFX),	      rd_rn_rm),
16516218822Sdim cCE(cfmul64,	e100520, 3, (RMDX, RMDX, RMDX),	      rd_rn_rm),
16517218822Sdim cCE(cfmac32,	e100540, 3, (RMFX, RMFX, RMFX),	      rd_rn_rm),
16518218822Sdim cCE(cfmsc32,	e100560, 3, (RMFX, RMFX, RMFX),	      rd_rn_rm),
16519218822Sdim cCE(cfmadd32,	e000600, 4, (RMAX, RMFX, RMFX, RMFX), mav_quad),
16520218822Sdim cCE(cfmsub32,	e100600, 4, (RMAX, RMFX, RMFX, RMFX), mav_quad),
16521218822Sdim cCE(cfmadda32, e200600, 4, (RMAX, RMAX, RMFX, RMFX), mav_quad),
16522218822Sdim cCE(cfmsuba32, e300600, 4, (RMAX, RMAX, RMFX, RMFX), mav_quad),
16523218822Sdim};
16524218822Sdim#undef ARM_VARIANT
16525218822Sdim#undef THUMB_VARIANT
16526218822Sdim#undef TCE
16527218822Sdim#undef TCM
16528218822Sdim#undef TUE
16529218822Sdim#undef TUF
16530218822Sdim#undef TCC
16531218822Sdim#undef cCE
16532218822Sdim#undef cCL
16533218822Sdim#undef C3E
16534218822Sdim#undef CE
16535218822Sdim#undef CM
16536218822Sdim#undef UE
16537218822Sdim#undef UF
16538218822Sdim#undef UT
16539218822Sdim#undef NUF
16540218822Sdim#undef nUF
16541218822Sdim#undef NCE
16542218822Sdim#undef nCE
16543218822Sdim#undef OPS0
16544218822Sdim#undef OPS1
16545218822Sdim#undef OPS2
16546218822Sdim#undef OPS3
16547218822Sdim#undef OPS4
16548218822Sdim#undef OPS5
16549218822Sdim#undef OPS6
16550218822Sdim#undef do_0
16551218822Sdim
16552218822Sdim/* MD interface: bits in the object file.  */
16553218822Sdim
16554218822Sdim/* Turn an integer of n bytes (in val) into a stream of bytes appropriate
16555218822Sdim   for use in the a.out file, and stores them in the array pointed to by buf.
16556218822Sdim   This knows about the endian-ness of the target machine and does
16557218822Sdim   THE RIGHT THING, whatever it is.  Possible values for n are 1 (byte)
16558218822Sdim   2 (short) and 4 (long)  Floating numbers are put out as a series of
16559218822Sdim   LITTLENUMS (shorts, here at least).	*/
16560218822Sdim
16561218822Sdimvoid
16562218822Sdimmd_number_to_chars (char * buf, valueT val, int n)
16563218822Sdim{
16564218822Sdim  if (target_big_endian)
16565218822Sdim    number_to_chars_bigendian (buf, val, n);
16566218822Sdim  else
16567218822Sdim    number_to_chars_littleendian (buf, val, n);
1656889857Sobrien}
1656989857Sobrien
16570218822Sdimstatic valueT
16571218822Sdimmd_chars_to_number (char * buf, int n)
1657260484Sobrien{
16573218822Sdim  valueT result = 0;
16574218822Sdim  unsigned char * where = (unsigned char *) buf;
1657560484Sobrien
16576218822Sdim  if (target_big_endian)
16577130561Sobrien    {
16578218822Sdim      while (n--)
16579218822Sdim	{
16580218822Sdim	  result <<= 8;
16581218822Sdim	  result |= (*where++ & 255);
16582218822Sdim	}
16583130561Sobrien    }
16584218822Sdim  else
16585218822Sdim    {
16586218822Sdim      while (n--)
16587218822Sdim	{
16588218822Sdim	  result <<= 8;
16589218822Sdim	  result |= (where[n] & 255);
16590218822Sdim	}
16591218822Sdim    }
16592218822Sdim
16593218822Sdim  return result;
1659460484Sobrien}
1659560484Sobrien
16596218822Sdim/* MD interface: Sections.  */
1659789857Sobrien
16598218822Sdim/* Estimate the size of a frag before relaxing.  Assume everything fits in
16599218822Sdim   2 bytes.  */
1660089857Sobrien
16601218822Sdimint
16602218822Sdimmd_estimate_size_before_relax (fragS * fragp,
16603218822Sdim			       segT    segtype ATTRIBUTE_UNUSED)
1660489857Sobrien{
16605218822Sdim  fragp->fr_var = 2;
16606218822Sdim  return 2;
16607218822Sdim}
1660889857Sobrien
16609218822Sdim/* Convert a machine dependent frag.  */
1661089857Sobrien
16611218822Sdimvoid
16612218822Sdimmd_convert_frag (bfd *abfd, segT asec ATTRIBUTE_UNUSED, fragS *fragp)
16613218822Sdim{
16614218822Sdim  unsigned long insn;
16615218822Sdim  unsigned long old_op;
16616218822Sdim  char *buf;
16617218822Sdim  expressionS exp;
16618218822Sdim  fixS *fixp;
16619218822Sdim  int reloc_type;
16620218822Sdim  int pc_rel;
16621218822Sdim  int opcode;
1662289857Sobrien
16623218822Sdim  buf = fragp->fr_literal + fragp->fr_fix;
16624218822Sdim
16625218822Sdim  old_op = bfd_get_16(abfd, buf);
16626218822Sdim  if (fragp->fr_symbol) {
16627218822Sdim      exp.X_op = O_symbol;
16628218822Sdim      exp.X_add_symbol = fragp->fr_symbol;
16629218822Sdim  } else {
16630218822Sdim      exp.X_op = O_constant;
16631218822Sdim  }
16632218822Sdim  exp.X_add_number = fragp->fr_offset;
16633218822Sdim  opcode = fragp->fr_subtype;
16634218822Sdim  switch (opcode)
1663589857Sobrien    {
16636218822Sdim    case T_MNEM_ldr_pc:
16637218822Sdim    case T_MNEM_ldr_pc2:
16638218822Sdim    case T_MNEM_ldr_sp:
16639218822Sdim    case T_MNEM_str_sp:
16640218822Sdim    case T_MNEM_ldr:
16641218822Sdim    case T_MNEM_ldrb:
16642218822Sdim    case T_MNEM_ldrh:
16643218822Sdim    case T_MNEM_str:
16644218822Sdim    case T_MNEM_strb:
16645218822Sdim    case T_MNEM_strh:
16646218822Sdim      if (fragp->fr_var == 4)
1664789857Sobrien	{
16648218822Sdim	  insn = THUMB_OP32(opcode);
16649218822Sdim	  if ((old_op >> 12) == 4 || (old_op >> 12) == 9)
1665089857Sobrien	    {
16651218822Sdim	      insn |= (old_op & 0x700) << 4;
1665289857Sobrien	    }
16653218822Sdim	  else
1665489857Sobrien	    {
16655218822Sdim	      insn |= (old_op & 7) << 12;
16656218822Sdim	      insn |= (old_op & 0x38) << 13;
1665789857Sobrien	    }
16658218822Sdim	  insn |= 0x00000c00;
16659218822Sdim	  put_thumb32_insn (buf, insn);
16660218822Sdim	  reloc_type = BFD_RELOC_ARM_T32_OFFSET_IMM;
16661218822Sdim	}
16662218822Sdim      else
16663218822Sdim	{
16664218822Sdim	  reloc_type = BFD_RELOC_ARM_THUMB_OFFSET;
16665218822Sdim	}
16666218822Sdim      pc_rel = (opcode == T_MNEM_ldr_pc2);
16667218822Sdim      break;
16668218822Sdim    case T_MNEM_adr:
16669218822Sdim      if (fragp->fr_var == 4)
16670218822Sdim	{
16671218822Sdim	  insn = THUMB_OP32 (opcode);
16672218822Sdim	  insn |= (old_op & 0xf0) << 4;
16673218822Sdim	  put_thumb32_insn (buf, insn);
16674218822Sdim	  reloc_type = BFD_RELOC_ARM_T32_ADD_PC12;
16675218822Sdim	}
16676218822Sdim      else
16677218822Sdim	{
16678218822Sdim	  reloc_type = BFD_RELOC_ARM_THUMB_ADD;
16679218822Sdim	  exp.X_add_number -= 4;
16680218822Sdim	}
16681218822Sdim      pc_rel = 1;
16682218822Sdim      break;
16683218822Sdim    case T_MNEM_mov:
16684218822Sdim    case T_MNEM_movs:
16685218822Sdim    case T_MNEM_cmp:
16686218822Sdim    case T_MNEM_cmn:
16687218822Sdim      if (fragp->fr_var == 4)
16688218822Sdim	{
16689218822Sdim	  int r0off = (opcode == T_MNEM_mov
16690218822Sdim		       || opcode == T_MNEM_movs) ? 0 : 8;
16691218822Sdim	  insn = THUMB_OP32 (opcode);
16692218822Sdim	  insn = (insn & 0xe1ffffff) | 0x10000000;
16693218822Sdim	  insn |= (old_op & 0x700) << r0off;
16694218822Sdim	  put_thumb32_insn (buf, insn);
16695218822Sdim	  reloc_type = BFD_RELOC_ARM_T32_IMMEDIATE;
16696218822Sdim	}
16697218822Sdim      else
16698218822Sdim	{
16699218822Sdim	  reloc_type = BFD_RELOC_ARM_THUMB_IMM;
16700218822Sdim	}
16701218822Sdim      pc_rel = 0;
16702218822Sdim      break;
16703218822Sdim    case T_MNEM_b:
16704218822Sdim      if (fragp->fr_var == 4)
16705218822Sdim	{
16706218822Sdim	  insn = THUMB_OP32(opcode);
16707218822Sdim	  put_thumb32_insn (buf, insn);
16708218822Sdim	  reloc_type = BFD_RELOC_THUMB_PCREL_BRANCH25;
16709218822Sdim	}
16710218822Sdim      else
16711218822Sdim	reloc_type = BFD_RELOC_THUMB_PCREL_BRANCH12;
16712218822Sdim      pc_rel = 1;
16713218822Sdim      break;
16714218822Sdim    case T_MNEM_bcond:
16715218822Sdim      if (fragp->fr_var == 4)
16716218822Sdim	{
16717218822Sdim	  insn = THUMB_OP32(opcode);
16718218822Sdim	  insn |= (old_op & 0xf00) << 14;
16719218822Sdim	  put_thumb32_insn (buf, insn);
16720218822Sdim	  reloc_type = BFD_RELOC_THUMB_PCREL_BRANCH20;
16721218822Sdim	}
16722218822Sdim      else
16723218822Sdim	reloc_type = BFD_RELOC_THUMB_PCREL_BRANCH9;
16724218822Sdim      pc_rel = 1;
16725218822Sdim      break;
16726218822Sdim    case T_MNEM_add_sp:
16727218822Sdim    case T_MNEM_add_pc:
16728218822Sdim    case T_MNEM_inc_sp:
16729218822Sdim    case T_MNEM_dec_sp:
16730218822Sdim      if (fragp->fr_var == 4)
16731218822Sdim	{
16732218822Sdim	  /* ??? Choose between add and addw.  */
16733218822Sdim	  insn = THUMB_OP32 (opcode);
16734218822Sdim	  insn |= (old_op & 0xf0) << 4;
16735218822Sdim	  put_thumb32_insn (buf, insn);
16736218822Sdim	  if (opcode == T_MNEM_add_pc)
16737218822Sdim	    reloc_type = BFD_RELOC_ARM_T32_IMM12;
1673889857Sobrien	  else
16739218822Sdim	    reloc_type = BFD_RELOC_ARM_T32_ADD_IMM;
16740218822Sdim	}
16741218822Sdim      else
16742218822Sdim	reloc_type = BFD_RELOC_ARM_THUMB_ADD;
16743218822Sdim      pc_rel = 0;
16744218822Sdim      break;
1674589857Sobrien
16746218822Sdim    case T_MNEM_addi:
16747218822Sdim    case T_MNEM_addis:
16748218822Sdim    case T_MNEM_subi:
16749218822Sdim    case T_MNEM_subis:
16750218822Sdim      if (fragp->fr_var == 4)
16751218822Sdim	{
16752218822Sdim	  insn = THUMB_OP32 (opcode);
16753218822Sdim	  insn |= (old_op & 0xf0) << 4;
16754218822Sdim	  insn |= (old_op & 0xf) << 16;
16755218822Sdim	  put_thumb32_insn (buf, insn);
16756218822Sdim	  if (insn & (1 << 20))
16757218822Sdim	    reloc_type = BFD_RELOC_ARM_T32_ADD_IMM;
16758218822Sdim	  else
16759218822Sdim	    reloc_type = BFD_RELOC_ARM_T32_IMMEDIATE;
1676089857Sobrien	}
1676189857Sobrien      else
16762218822Sdim	reloc_type = BFD_RELOC_ARM_THUMB_ADD;
16763218822Sdim      pc_rel = 0;
16764218822Sdim      break;
16765218822Sdim    default:
16766218822Sdim      abort();
1676789857Sobrien    }
16768218822Sdim  fixp = fix_new_exp (fragp, fragp->fr_fix, fragp->fr_var, &exp, pc_rel,
16769218822Sdim		      reloc_type);
16770218822Sdim  fixp->fx_file = fragp->fr_file;
16771218822Sdim  fixp->fx_line = fragp->fr_line;
16772218822Sdim  fragp->fr_fix += fragp->fr_var;
1677389857Sobrien}
16774104834Sobrien
16775218822Sdim/* Return the size of a relaxable immediate operand instruction.
16776218822Sdim   SHIFT and SIZE specify the form of the allowable immediate.  */
16777218822Sdimstatic int
16778218822Sdimrelax_immediate (fragS *fragp, int size, int shift)
1677960484Sobrien{
16780218822Sdim  offsetT offset;
16781218822Sdim  offsetT mask;
16782218822Sdim  offsetT low;
1678360484Sobrien
16784218822Sdim  /* ??? Should be able to do better than this.  */
16785218822Sdim  if (fragp->fr_symbol)
16786218822Sdim    return 4;
16787218822Sdim
16788218822Sdim  low = (1 << shift) - 1;
16789218822Sdim  mask = (1 << (shift + size)) - (1 << shift);
16790218822Sdim  offset = fragp->fr_offset;
16791218822Sdim  /* Force misaligned offsets to 32-bit variant.  */
16792218822Sdim  if (offset & low)
16793218822Sdim    return 4;
16794218822Sdim  if (offset & ~mask)
16795218822Sdim    return 4;
16796218822Sdim  return 2;
1679760484Sobrien}
1679860484Sobrien
16799218822Sdim/* Get the address of a symbol during relaxation.  */
16800218822Sdimstatic addressT
16801218822Sdimrelaxed_symbol_addr(fragS *fragp, long stretch)
1680289857Sobrien{
16803218822Sdim  fragS *sym_frag;
16804218822Sdim  addressT addr;
16805218822Sdim  symbolS *sym;
1680689857Sobrien
16807218822Sdim  sym = fragp->fr_symbol;
16808218822Sdim  sym_frag = symbol_get_frag (sym);
16809218822Sdim  know (S_GET_SEGMENT (sym) != absolute_section
16810218822Sdim	|| sym_frag == &zero_address_frag);
16811218822Sdim  addr = S_GET_VALUE (sym) + fragp->fr_offset;
1681289857Sobrien
16813218822Sdim  /* If frag has yet to be reached on this pass, assume it will
16814218822Sdim     move by STRETCH just as we did.  If this is not so, it will
16815218822Sdim     be because some frag between grows, and that will force
16816218822Sdim     another pass.  */
1681789857Sobrien
16818218822Sdim  if (stretch != 0
16819218822Sdim      && sym_frag->relax_marker != fragp->relax_marker)
16820218822Sdim    addr += stretch;
1682189857Sobrien
16822218822Sdim  return addr;
16823218822Sdim}
1682489857Sobrien
16825218822Sdim/* Return the size of a relaxable adr pseudo-instruction or PC-relative
16826218822Sdim   load.  */
16827218822Sdimstatic int
16828218822Sdimrelax_adr (fragS *fragp, asection *sec, long stretch)
16829218822Sdim{
16830218822Sdim  addressT addr;
16831218822Sdim  offsetT val;
1683289857Sobrien
16833218822Sdim  /* Assume worst case for symbols not known to be in the same section.  */
16834218822Sdim  if (!S_IS_DEFINED(fragp->fr_symbol)
16835218822Sdim      || sec != S_GET_SEGMENT (fragp->fr_symbol))
16836218822Sdim    return 4;
16837218822Sdim
16838218822Sdim  val = relaxed_symbol_addr(fragp, stretch);
16839218822Sdim  addr = fragp->fr_address + fragp->fr_fix;
16840218822Sdim  addr = (addr + 4) & ~3;
16841218822Sdim  /* Force misaligned targets to 32-bit variant.  */
16842218822Sdim  if (val & 3)
16843218822Sdim    return 4;
16844218822Sdim  val -= addr;
16845218822Sdim  if (val < 0 || val > 1020)
16846218822Sdim    return 4;
16847218822Sdim  return 2;
1684889857Sobrien}
1684989857Sobrien
16850218822Sdim/* Return the size of a relaxable add/sub immediate instruction.  */
16851218822Sdimstatic int
16852218822Sdimrelax_addsub (fragS *fragp, asection *sec)
16853130561Sobrien{
16854218822Sdim  char *buf;
16855218822Sdim  int op;
16856130561Sobrien
16857218822Sdim  buf = fragp->fr_literal + fragp->fr_fix;
16858218822Sdim  op = bfd_get_16(sec->owner, buf);
16859218822Sdim  if ((op & 0xf) == ((op >> 4) & 0xf))
16860218822Sdim    return relax_immediate (fragp, 8, 0);
16861218822Sdim  else
16862218822Sdim    return relax_immediate (fragp, 3, 0);
16863218822Sdim}
16864130561Sobrien
16865130561Sobrien
16866218822Sdim/* Return the size of a relaxable branch instruction.  BITS is the
16867218822Sdim   size of the offset field in the narrow instruction.  */
16868130561Sobrien
16869218822Sdimstatic int
16870218822Sdimrelax_branch (fragS *fragp, asection *sec, int bits, long stretch)
16871218822Sdim{
16872218822Sdim  addressT addr;
16873218822Sdim  offsetT val;
16874218822Sdim  offsetT limit;
16875130561Sobrien
16876218822Sdim  /* Assume worst case for symbols not known to be in the same section.  */
16877218822Sdim  if (!S_IS_DEFINED(fragp->fr_symbol)
16878218822Sdim      || sec != S_GET_SEGMENT (fragp->fr_symbol))
16879218822Sdim    return 4;
16880130561Sobrien
16881218822Sdim  val = relaxed_symbol_addr(fragp, stretch);
16882218822Sdim  addr = fragp->fr_address + fragp->fr_fix + 4;
16883218822Sdim  val -= addr;
16884130561Sobrien
16885218822Sdim  /* Offset is a signed value *2 */
16886218822Sdim  limit = 1 << bits;
16887218822Sdim  if (val >= limit || val < -limit)
16888218822Sdim    return 4;
16889218822Sdim  return 2;
16890130561Sobrien}
16891130561Sobrien
16892218822Sdim
16893218822Sdim/* Relax a machine dependent frag.  This returns the amount by which
16894218822Sdim   the current size of the frag should change.  */
16895218822Sdim
16896218822Sdimint
16897218822Sdimarm_relax_frag (asection *sec, fragS *fragp, long stretch)
1689860484Sobrien{
16899218822Sdim  int oldsize;
16900218822Sdim  int newsize;
1690177298Sobrien
16902218822Sdim  oldsize = fragp->fr_var;
16903218822Sdim  switch (fragp->fr_subtype)
16904218822Sdim    {
16905218822Sdim    case T_MNEM_ldr_pc2:
16906218822Sdim      newsize = relax_adr(fragp, sec, stretch);
16907218822Sdim      break;
16908218822Sdim    case T_MNEM_ldr_pc:
16909218822Sdim    case T_MNEM_ldr_sp:
16910218822Sdim    case T_MNEM_str_sp:
16911218822Sdim      newsize = relax_immediate(fragp, 8, 2);
16912218822Sdim      break;
16913218822Sdim    case T_MNEM_ldr:
16914218822Sdim    case T_MNEM_str:
16915218822Sdim      newsize = relax_immediate(fragp, 5, 2);
16916218822Sdim      break;
16917218822Sdim    case T_MNEM_ldrh:
16918218822Sdim    case T_MNEM_strh:
16919218822Sdim      newsize = relax_immediate(fragp, 5, 1);
16920218822Sdim      break;
16921218822Sdim    case T_MNEM_ldrb:
16922218822Sdim    case T_MNEM_strb:
16923218822Sdim      newsize = relax_immediate(fragp, 5, 0);
16924218822Sdim      break;
16925218822Sdim    case T_MNEM_adr:
16926218822Sdim      newsize = relax_adr(fragp, sec, stretch);
16927218822Sdim      break;
16928218822Sdim    case T_MNEM_mov:
16929218822Sdim    case T_MNEM_movs:
16930218822Sdim    case T_MNEM_cmp:
16931218822Sdim    case T_MNEM_cmn:
16932218822Sdim      newsize = relax_immediate(fragp, 8, 0);
16933218822Sdim      break;
16934218822Sdim    case T_MNEM_b:
16935218822Sdim      newsize = relax_branch(fragp, sec, 11, stretch);
16936218822Sdim      break;
16937218822Sdim    case T_MNEM_bcond:
16938218822Sdim      newsize = relax_branch(fragp, sec, 8, stretch);
16939218822Sdim      break;
16940218822Sdim    case T_MNEM_add_sp:
16941218822Sdim    case T_MNEM_add_pc:
16942218822Sdim      newsize = relax_immediate (fragp, 8, 2);
16943218822Sdim      break;
16944218822Sdim    case T_MNEM_inc_sp:
16945218822Sdim    case T_MNEM_dec_sp:
16946218822Sdim      newsize = relax_immediate (fragp, 7, 2);
16947218822Sdim      break;
16948218822Sdim    case T_MNEM_addi:
16949218822Sdim    case T_MNEM_addis:
16950218822Sdim    case T_MNEM_subi:
16951218822Sdim    case T_MNEM_subis:
16952218822Sdim      newsize = relax_addsub (fragp, sec);
16953218822Sdim      break;
16954218822Sdim    default:
16955218822Sdim      abort();
16956218822Sdim    }
1695777298Sobrien
16958218822Sdim  fragp->fr_var = newsize;
16959218822Sdim  /* Freeze wide instructions that are at or before the same location as
16960218822Sdim     in the previous pass.  This avoids infinite loops.
16961218822Sdim     Don't freeze them unconditionally because targets may be artificialy
16962218822Sdim     misaligned by the expansion of preceeding frags.  */
16963218822Sdim  if (stretch <= 0 && newsize > 2)
16964218822Sdim    {
16965218822Sdim      md_convert_frag (sec->owner, sec, fragp);
16966218822Sdim      frag_wane(fragp);
16967218822Sdim    }
1696860484Sobrien
16969218822Sdim  return newsize - oldsize;
16970218822Sdim}
1697160484Sobrien
16972218822Sdim/* Round up a section size to the appropriate boundary.	 */
1697360484Sobrien
16974218822SdimvalueT
16975218822Sdimmd_section_align (segT	 segment ATTRIBUTE_UNUSED,
16976218822Sdim		  valueT size)
16977218822Sdim{
16978218822Sdim#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
16979218822Sdim  if (OUTPUT_FLAVOR == bfd_target_aout_flavour)
1698089857Sobrien    {
16981218822Sdim      /* For a.out, force the section size to be aligned.  If we don't do
16982218822Sdim	 this, BFD will align it for us, but it will not write out the
16983218822Sdim	 final bytes of the section.  This may be a bug in BFD, but it is
16984218822Sdim	 easier to fix it here since that is how the other a.out targets
16985218822Sdim	 work.  */
16986218822Sdim      int align;
1698789857Sobrien
16988218822Sdim      align = bfd_get_section_alignment (stdoutput, segment);
16989218822Sdim      size = ((size + (1 << align) - 1) & ((valueT) -1 << align));
1699089857Sobrien    }
16991218822Sdim#endif
1699289857Sobrien
16993218822Sdim  return size;
16994218822Sdim}
16995218822Sdim
16996218822Sdim/* This is called from HANDLE_ALIGN in write.c.	 Fill in the contents
16997218822Sdim   of an rs_align_code fragment.  */
16998218822Sdim
16999218822Sdimvoid
17000218822Sdimarm_handle_align (fragS * fragP)
17001218822Sdim{
17002218822Sdim  static char const arm_noop[4] = { 0x00, 0x00, 0xa0, 0xe1 };
17003218822Sdim  static char const thumb_noop[2] = { 0xc0, 0x46 };
17004218822Sdim  static char const arm_bigend_noop[4] = { 0xe1, 0xa0, 0x00, 0x00 };
17005218822Sdim  static char const thumb_bigend_noop[2] = { 0x46, 0xc0 };
17006218822Sdim
17007218822Sdim  int bytes, fix, noop_size;
17008218822Sdim  char * p;
17009218822Sdim  const char * noop;
17010218822Sdim
17011218822Sdim  if (fragP->fr_type != rs_align_code)
17012218822Sdim    return;
17013218822Sdim
17014218822Sdim  bytes = fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix;
17015218822Sdim  p = fragP->fr_literal + fragP->fr_fix;
17016218822Sdim  fix = 0;
17017218822Sdim
17018218822Sdim  if (bytes > MAX_MEM_FOR_RS_ALIGN_CODE)
17019218822Sdim    bytes &= MAX_MEM_FOR_RS_ALIGN_CODE;
17020218822Sdim
17021218822Sdim  if (fragP->tc_frag_data)
1702289857Sobrien    {
17023218822Sdim      if (target_big_endian)
17024218822Sdim	noop = thumb_bigend_noop;
17025218822Sdim      else
17026218822Sdim	noop = thumb_noop;
17027218822Sdim      noop_size = sizeof (thumb_noop);
1702889857Sobrien    }
17029218822Sdim  else
1703089857Sobrien    {
17031218822Sdim      if (target_big_endian)
17032218822Sdim	noop = arm_bigend_noop;
1703389857Sobrien      else
17034218822Sdim	noop = arm_noop;
17035218822Sdim      noop_size = sizeof (arm_noop);
1703689857Sobrien    }
1703789857Sobrien
17038218822Sdim  if (bytes & (noop_size - 1))
1703989857Sobrien    {
17040218822Sdim      fix = bytes & (noop_size - 1);
17041218822Sdim      memset (p, 0, fix);
17042218822Sdim      p += fix;
17043218822Sdim      bytes -= fix;
1704489857Sobrien    }
1704589857Sobrien
17046218822Sdim  while (bytes >= noop_size)
17047218822Sdim    {
17048218822Sdim      memcpy (p, noop, noop_size);
17049218822Sdim      p += noop_size;
17050218822Sdim      bytes -= noop_size;
17051218822Sdim      fix += noop_size;
17052218822Sdim    }
1705389857Sobrien
17054218822Sdim  fragP->fr_fix += fix;
17055218822Sdim  fragP->fr_var = noop_size;
17056218822Sdim}
1705789857Sobrien
17058218822Sdim/* Called from md_do_align.  Used to create an alignment
17059218822Sdim   frag in a code section.  */
1706077298Sobrien
17061218822Sdimvoid
17062218822Sdimarm_frag_align_code (int n, int max)
17063218822Sdim{
17064218822Sdim  char * p;
17065130561Sobrien
17066218822Sdim  /* We assume that there will never be a requirement
17067218822Sdim     to support alignments greater than 32 bytes.  */
17068218822Sdim  if (max > MAX_MEM_FOR_RS_ALIGN_CODE)
17069218822Sdim    as_fatal (_("alignments greater than 32 bytes not supported in .text sections."));
1707060484Sobrien
17071218822Sdim  p = frag_var (rs_align_code,
17072218822Sdim		MAX_MEM_FOR_RS_ALIGN_CODE,
17073218822Sdim		1,
17074218822Sdim		(relax_substateT) max,
17075218822Sdim		(symbolS *) NULL,
17076218822Sdim		(offsetT) n,
17077218822Sdim		(char *) NULL);
17078218822Sdim  *p = 0;
17079218822Sdim}
1708089857Sobrien
17081218822Sdim/* Perform target specific initialisation of a frag.  */
1708277298Sobrien
17083218822Sdimvoid
17084218822Sdimarm_init_frag (fragS * fragP)
17085218822Sdim{
17086218822Sdim  /* Record whether this frag is in an ARM or a THUMB area.  */
17087218822Sdim  fragP->tc_frag_data = thumb_mode;
17088218822Sdim}
1708977298Sobrien
17090218822Sdim#ifdef OBJ_ELF
17091218822Sdim/* When we change sections we need to issue a new mapping symbol.  */
1709277298Sobrien
17093218822Sdimvoid
17094218822Sdimarm_elf_change_section (void)
17095218822Sdim{
17096218822Sdim  flagword flags;
17097218822Sdim  segment_info_type *seginfo;
1709877298Sobrien
17099218822Sdim  /* Link an unlinked unwind index table section to the .text section.	*/
17100218822Sdim  if (elf_section_type (now_seg) == SHT_ARM_EXIDX
17101218822Sdim      && elf_linked_to_section (now_seg) == NULL)
17102218822Sdim    elf_linked_to_section (now_seg) = text_section;
1710377298Sobrien
17104218822Sdim  if (!SEG_NORMAL (now_seg))
17105218822Sdim    return;
1710677298Sobrien
17107218822Sdim  flags = bfd_get_section_flags (stdoutput, now_seg);
1710889857Sobrien
17109218822Sdim  /* We can ignore sections that only contain debug info.  */
17110218822Sdim  if ((flags & SEC_ALLOC) == 0)
17111218822Sdim    return;
1711277298Sobrien
17113218822Sdim  seginfo = seg_info (now_seg);
17114218822Sdim  mapstate = seginfo->tc_segment_info_data.mapstate;
17115218822Sdim  marked_pr_dependency = seginfo->tc_segment_info_data.marked_pr_dependency;
17116218822Sdim}
17117218822Sdim
17118218822Sdimint
17119218822Sdimarm_elf_section_type (const char * str, size_t len)
17120218822Sdim{
17121218822Sdim  if (len == 5 && strncmp (str, "exidx", 5) == 0)
17122218822Sdim    return SHT_ARM_EXIDX;
17123218822Sdim
17124218822Sdim  return -1;
17125218822Sdim}
17126218822Sdim
17127218822Sdim/* Code to deal with unwinding tables.	*/
17128218822Sdim
17129218822Sdimstatic void add_unwind_adjustsp (offsetT);
17130218822Sdim
17131218822Sdim/* Cenerate and deferred unwind frame offset.  */
17132218822Sdim
17133218822Sdimstatic void
17134218822Sdimflush_pending_unwind (void)
17135218822Sdim{
17136218822Sdim  offsetT offset;
17137218822Sdim
17138218822Sdim  offset = unwind.pending_offset;
17139218822Sdim  unwind.pending_offset = 0;
17140218822Sdim  if (offset != 0)
17141218822Sdim    add_unwind_adjustsp (offset);
17142218822Sdim}
17143218822Sdim
17144218822Sdim/* Add an opcode to this list for this function.  Two-byte opcodes should
17145218822Sdim   be passed as op[0] << 8 | op[1].  The list of opcodes is built in reverse
17146218822Sdim   order.  */
17147218822Sdim
17148218822Sdimstatic void
17149218822Sdimadd_unwind_opcode (valueT op, int length)
17150218822Sdim{
17151218822Sdim  /* Add any deferred stack adjustment.	 */
17152218822Sdim  if (unwind.pending_offset)
17153218822Sdim    flush_pending_unwind ();
17154218822Sdim
17155218822Sdim  unwind.sp_restored = 0;
17156218822Sdim
17157218822Sdim  if (unwind.opcode_count + length > unwind.opcode_alloc)
1715860484Sobrien    {
17159218822Sdim      unwind.opcode_alloc += ARM_OPCODE_CHUNK_SIZE;
17160218822Sdim      if (unwind.opcodes)
17161218822Sdim	unwind.opcodes = xrealloc (unwind.opcodes,
17162218822Sdim				   unwind.opcode_alloc);
1716378828Sobrien      else
17164218822Sdim	unwind.opcodes = xmalloc (unwind.opcode_alloc);
1716560484Sobrien    }
17166218822Sdim  while (length > 0)
1716778828Sobrien    {
17168218822Sdim      length--;
17169218822Sdim      unwind.opcodes[unwind.opcode_count] = op & 0xff;
17170218822Sdim      op >>= 8;
17171218822Sdim      unwind.opcode_count++;
1717278828Sobrien    }
17173218822Sdim}
1717477298Sobrien
17175218822Sdim/* Add unwind opcodes to adjust the stack pointer.  */
17176130561Sobrien
17177218822Sdimstatic void
17178218822Sdimadd_unwind_adjustsp (offsetT offset)
17179218822Sdim{
17180218822Sdim  valueT op;
17181130561Sobrien
17182218822Sdim  if (offset > 0x200)
17183218822Sdim    {
17184218822Sdim      /* We need at most 5 bytes to hold a 32-bit value in a uleb128.  */
17185218822Sdim      char bytes[5];
17186218822Sdim      int n;
17187218822Sdim      valueT o;
17188130561Sobrien
17189218822Sdim      /* Long form: 0xb2, uleb128.  */
17190218822Sdim      /* This might not fit in a word so add the individual bytes,
17191218822Sdim	 remembering the list is built in reverse order.  */
17192218822Sdim      o = (valueT) ((offset - 0x204) >> 2);
17193218822Sdim      if (o == 0)
17194218822Sdim	add_unwind_opcode (0, 1);
17195130561Sobrien
17196218822Sdim      /* Calculate the uleb128 encoding of the offset.	*/
17197218822Sdim      n = 0;
17198218822Sdim      while (o)
17199218822Sdim	{
17200218822Sdim	  bytes[n] = o & 0x7f;
17201218822Sdim	  o >>= 7;
17202218822Sdim	  if (o)
17203218822Sdim	    bytes[n] |= 0x80;
17204218822Sdim	  n++;
17205218822Sdim	}
17206218822Sdim      /* Add the insn.	*/
17207218822Sdim      for (; n; n--)
17208218822Sdim	add_unwind_opcode (bytes[n - 1], 1);
17209218822Sdim      add_unwind_opcode (0xb2, 1);
17210218822Sdim    }
17211218822Sdim  else if (offset > 0x100)
17212218822Sdim    {
17213218822Sdim      /* Two short opcodes.  */
17214218822Sdim      add_unwind_opcode (0x3f, 1);
17215218822Sdim      op = (offset - 0x104) >> 2;
17216218822Sdim      add_unwind_opcode (op, 1);
17217218822Sdim    }
17218218822Sdim  else if (offset > 0)
17219218822Sdim    {
17220218822Sdim      /* Short opcode.	*/
17221218822Sdim      op = (offset - 4) >> 2;
17222218822Sdim      add_unwind_opcode (op, 1);
17223218822Sdim    }
17224218822Sdim  else if (offset < 0)
17225218822Sdim    {
17226218822Sdim      offset = -offset;
17227218822Sdim      while (offset > 0x100)
17228218822Sdim	{
17229218822Sdim	  add_unwind_opcode (0x7f, 1);
17230218822Sdim	  offset -= 0x100;
17231218822Sdim	}
17232218822Sdim      op = ((offset - 4) >> 2) | 0x40;
17233218822Sdim      add_unwind_opcode (op, 1);
17234218822Sdim    }
17235218822Sdim}
17236130561Sobrien
17237218822Sdim/* Finish the list of unwind opcodes for this function.	 */
17238218822Sdimstatic void
17239218822Sdimfinish_unwind_opcodes (void)
17240218822Sdim{
17241218822Sdim  valueT op;
17242130561Sobrien
17243218822Sdim  if (unwind.fp_used)
17244218822Sdim    {
17245218822Sdim      /* Adjust sp as necessary.  */
17246218822Sdim      unwind.pending_offset += unwind.fp_offset - unwind.frame_size;
17247218822Sdim      flush_pending_unwind ();
17248130561Sobrien
17249218822Sdim      /* After restoring sp from the frame pointer.  */
17250218822Sdim      op = 0x90 | unwind.fp_reg;
17251218822Sdim      add_unwind_opcode (op, 1);
17252218822Sdim    }
17253218822Sdim  else
17254218822Sdim    flush_pending_unwind ();
1725560484Sobrien}
1725660484Sobrien
1725777298Sobrien
17258218822Sdim/* Start an exception table entry.  If idx is nonzero this is an index table
17259218822Sdim   entry.  */
17260218822Sdim
17261218822Sdimstatic void
17262218822Sdimstart_unwind_section (const segT text_seg, int idx)
1726360484Sobrien{
17264218822Sdim  const char * text_name;
17265218822Sdim  const char * prefix;
17266218822Sdim  const char * prefix_once;
17267218822Sdim  const char * group_name;
17268218822Sdim  size_t prefix_len;
17269218822Sdim  size_t text_len;
17270218822Sdim  char * sec_name;
17271218822Sdim  size_t sec_name_len;
17272218822Sdim  int type;
17273218822Sdim  int flags;
17274218822Sdim  int linkonce;
17275218822Sdim
17276218822Sdim  if (idx)
17277218822Sdim    {
17278218822Sdim      prefix = ELF_STRING_ARM_unwind;
17279218822Sdim      prefix_once = ELF_STRING_ARM_unwind_once;
17280218822Sdim      type = SHT_ARM_EXIDX;
17281218822Sdim    }
1728260484Sobrien  else
17283218822Sdim    {
17284218822Sdim      prefix = ELF_STRING_ARM_unwind_info;
17285218822Sdim      prefix_once = ELF_STRING_ARM_unwind_info_once;
17286218822Sdim      type = SHT_PROGBITS;
17287218822Sdim    }
17288218822Sdim
17289218822Sdim  text_name = segment_name (text_seg);
17290218822Sdim  if (streq (text_name, ".text"))
17291218822Sdim    text_name = "";
17292218822Sdim
17293218822Sdim  if (strncmp (text_name, ".gnu.linkonce.t.",
17294218822Sdim	       strlen (".gnu.linkonce.t.")) == 0)
17295218822Sdim    {
17296218822Sdim      prefix = prefix_once;
17297218822Sdim      text_name += strlen (".gnu.linkonce.t.");
17298218822Sdim    }
17299218822Sdim
17300218822Sdim  prefix_len = strlen (prefix);
17301218822Sdim  text_len = strlen (text_name);
17302218822Sdim  sec_name_len = prefix_len + text_len;
17303218822Sdim  sec_name = xmalloc (sec_name_len + 1);
17304218822Sdim  memcpy (sec_name, prefix, prefix_len);
17305218822Sdim  memcpy (sec_name + prefix_len, text_name, text_len);
17306218822Sdim  sec_name[prefix_len + text_len] = '\0';
17307218822Sdim
17308218822Sdim  flags = SHF_ALLOC;
17309218822Sdim  linkonce = 0;
17310218822Sdim  group_name = 0;
17311218822Sdim
17312218822Sdim  /* Handle COMDAT group.  */
17313218822Sdim  if (prefix != prefix_once && (text_seg->flags & SEC_LINK_ONCE) != 0)
17314218822Sdim    {
17315218822Sdim      group_name = elf_group_name (text_seg);
17316218822Sdim      if (group_name == NULL)
17317218822Sdim	{
17318218822Sdim	  as_bad ("Group section `%s' has no group signature",
17319218822Sdim		  segment_name (text_seg));
17320218822Sdim	  ignore_rest_of_line ();
17321218822Sdim	  return;
17322218822Sdim	}
17323218822Sdim      flags |= SHF_GROUP;
17324218822Sdim      linkonce = 1;
17325218822Sdim    }
17326218822Sdim
17327218822Sdim  obj_elf_change_section (sec_name, type, flags, 0, group_name, linkonce, 0);
17328218822Sdim
17329218822Sdim  /* Set the setion link for index tables.  */
17330218822Sdim  if (idx)
17331218822Sdim    elf_linked_to_section (now_seg) = text_seg;
1733260484Sobrien}
1733360484Sobrien
17334218822Sdim
17335218822Sdim/* Start an unwind table entry.	 HAVE_DATA is nonzero if we have additional
17336218822Sdim   personality routine data.  Returns zero, or the index table value for
17337218822Sdim   and inline entry.  */
17338218822Sdim
1733977298Sobrienstatic valueT
17340218822Sdimcreate_unwind_entry (int have_data)
1734160484Sobrien{
17342218822Sdim  int size;
17343218822Sdim  addressT where;
17344218822Sdim  char *ptr;
17345218822Sdim  /* The current word of data.	*/
17346218822Sdim  valueT data;
17347218822Sdim  /* The number of bytes left in this word.  */
17348218822Sdim  int n;
1734960484Sobrien
17350218822Sdim  finish_unwind_opcodes ();
17351218822Sdim
17352218822Sdim  /* Remember the current text section.	 */
17353218822Sdim  unwind.saved_seg = now_seg;
17354218822Sdim  unwind.saved_subseg = now_subseg;
17355218822Sdim
17356218822Sdim  start_unwind_section (now_seg, 0);
17357218822Sdim
17358218822Sdim  if (unwind.personality_routine == NULL)
1735960484Sobrien    {
17360218822Sdim      if (unwind.personality_index == -2)
1736160484Sobrien	{
17362218822Sdim	  if (have_data)
17363218822Sdim	    as_bad (_("handerdata in cantunwind frame"));
17364218822Sdim	  return 1; /* EXIDX_CANTUNWIND.  */
1736560484Sobrien	}
17366218822Sdim
17367218822Sdim      /* Use a default personality routine if none is specified.  */
17368218822Sdim      if (unwind.personality_index == -1)
1736960484Sobrien	{
17370218822Sdim	  if (unwind.opcode_count > 3)
17371218822Sdim	    unwind.personality_index = 1;
17372218822Sdim	  else
17373218822Sdim	    unwind.personality_index = 0;
1737460484Sobrien	}
1737560484Sobrien
17376218822Sdim      /* Space for the personality routine entry.  */
17377218822Sdim      if (unwind.personality_index == 0)
17378218822Sdim	{
17379218822Sdim	  if (unwind.opcode_count > 3)
17380218822Sdim	    as_bad (_("too many unwind opcodes for personality routine 0"));
1738160484Sobrien
17382218822Sdim	  if (!have_data)
17383218822Sdim	    {
17384218822Sdim	      /* All the data is inline in the index table.  */
17385218822Sdim	      data = 0x80;
17386218822Sdim	      n = 3;
17387218822Sdim	      while (unwind.opcode_count > 0)
17388218822Sdim		{
17389218822Sdim		  unwind.opcode_count--;
17390218822Sdim		  data = (data << 8) | unwind.opcodes[unwind.opcode_count];
17391218822Sdim		  n--;
17392218822Sdim		}
1739360484Sobrien
17394218822Sdim	      /* Pad with "finish" opcodes.  */
17395218822Sdim	      while (n--)
17396218822Sdim		data = (data << 8) | 0xb0;
1739760484Sobrien
17398218822Sdim	      return data;
17399218822Sdim	    }
17400218822Sdim	  size = 0;
17401218822Sdim	}
17402218822Sdim      else
17403218822Sdim	/* We get two opcodes "free" in the first word.	 */
17404218822Sdim	size = unwind.opcode_count - 2;
17405218822Sdim    }
17406218822Sdim  else
17407218822Sdim    /* An extra byte is required for the opcode count.	*/
17408218822Sdim    size = unwind.opcode_count + 1;
1740960484Sobrien
17410218822Sdim  size = (size + 3) >> 2;
17411218822Sdim  if (size > 0xff)
17412218822Sdim    as_bad (_("too many unwind opcodes"));
1741360484Sobrien
17414218822Sdim  frag_align (2, 0, 0);
17415218822Sdim  record_alignment (now_seg, 2);
17416218822Sdim  unwind.table_entry = expr_build_dot ();
17417218822Sdim
17418218822Sdim  /* Allocate the table entry.	*/
17419218822Sdim  ptr = frag_more ((size << 2) + 4);
17420247386Sandrew  memset(ptr, 0, (size << 2) + 4);
17421218822Sdim  where = frag_now_fix () - ((size << 2) + 4);
17422218822Sdim
17423218822Sdim  switch (unwind.personality_index)
1742460484Sobrien    {
17425218822Sdim    case -1:
17426218822Sdim      /* ??? Should this be a PLT generating relocation?  */
17427218822Sdim      /* Custom personality routine.  */
17428218822Sdim      fix_new (frag_now, where, 4, unwind.personality_routine, 0, 1,
17429218822Sdim	       BFD_RELOC_ARM_PREL31);
1743060484Sobrien
17431218822Sdim      where += 4;
17432218822Sdim      ptr += 4;
17433218822Sdim
17434218822Sdim      /* Set the first byte to the number of additional words.	*/
17435218822Sdim      data = size - 1;
17436218822Sdim      n = 3;
1743760484Sobrien      break;
1743860484Sobrien
17439218822Sdim    /* ABI defined personality routines.  */
17440218822Sdim    case 0:
17441218822Sdim      /* Three opcodes bytes are packed into the first word.  */
17442218822Sdim      data = 0x80;
17443218822Sdim      n = 3;
1744460484Sobrien      break;
1744560484Sobrien
17446218822Sdim    case 1:
17447218822Sdim    case 2:
17448218822Sdim      /* The size and first two opcode bytes go in the first word.  */
17449218822Sdim      data = ((0x80 + unwind.personality_index) << 8) | size;
17450218822Sdim      n = 2;
1745160484Sobrien      break;
1745260484Sobrien
1745360484Sobrien    default:
17454218822Sdim      /* Should never happen.  */
17455218822Sdim      abort ();
1745660484Sobrien    }
1745760484Sobrien
17458218822Sdim  /* Pack the opcodes into words (MSB first), reversing the list at the same
17459218822Sdim     time.  */
17460218822Sdim  while (unwind.opcode_count > 0)
1746160484Sobrien    {
17462218822Sdim      if (n == 0)
1746360484Sobrien	{
17464218822Sdim	  md_number_to_chars (ptr, data, 4);
17465218822Sdim	  ptr += 4;
17466218822Sdim	  n = 4;
17467218822Sdim	  data = 0;
1746860484Sobrien	}
17469218822Sdim      unwind.opcode_count--;
17470218822Sdim      n--;
17471218822Sdim      data = (data << 8) | unwind.opcodes[unwind.opcode_count];
1747260484Sobrien    }
17473218822Sdim
17474218822Sdim  /* Finish off the last word.	*/
17475218822Sdim  if (n < 4)
1747660484Sobrien    {
17477218822Sdim      /* Pad with "finish" opcodes.  */
17478218822Sdim      while (n--)
17479218822Sdim	data = (data << 8) | 0xb0;
17480218822Sdim
17481218822Sdim      md_number_to_chars (ptr, data, 4);
1748260484Sobrien    }
1748360484Sobrien
17484218822Sdim  if (!have_data)
17485218822Sdim    {
17486218822Sdim      /* Add an empty descriptor if there is no user-specified data.   */
17487218822Sdim      ptr = frag_more (4);
17488218822Sdim      md_number_to_chars (ptr, 0, 4);
17489218822Sdim    }
17490218822Sdim
1749160484Sobrien  return 0;
1749260484Sobrien}
1749360484Sobrien
1749477298Sobrien
17495218822Sdim/* Initialize the DWARF-2 unwind information for this procedure.  */
17496218822Sdim
17497218822Sdimvoid
17498218822Sdimtc_arm_frame_initial_instructions (void)
17499218822Sdim{
17500218822Sdim  cfi_add_CFA_def_cfa (REG_SP, 0);
17501218822Sdim}
17502218822Sdim#endif /* OBJ_ELF */
17503218822Sdim
17504218822Sdim/* Convert REGNAME to a DWARF-2 register number.  */
17505218822Sdim
17506218822Sdimint
17507218822Sdimtc_arm_regname_to_dw2regnum (char *regname)
17508218822Sdim{
17509218822Sdim  int reg = arm_reg_parse (&regname, REG_TYPE_RN);
17510218822Sdim
17511218822Sdim  if (reg == FAIL)
17512218822Sdim    return -1;
17513218822Sdim
17514218822Sdim  return reg;
17515218822Sdim}
17516218822Sdim
17517218822Sdim#ifdef TE_PE
17518218822Sdimvoid
17519218822Sdimtc_pe_dwarf2_emit_offset (symbolS *symbol, unsigned int size)
17520218822Sdim{
17521218822Sdim  expressionS expr;
17522218822Sdim
17523218822Sdim  expr.X_op = O_secrel;
17524218822Sdim  expr.X_add_symbol = symbol;
17525218822Sdim  expr.X_add_number = 0;
17526218822Sdim  emit_expr (&expr, size);
17527218822Sdim}
17528218822Sdim#endif
17529218822Sdim
17530218822Sdim/* MD interface: Symbol and relocation handling.  */
17531218822Sdim
17532218822Sdim/* Return the address within the segment that a PC-relative fixup is
17533218822Sdim   relative to.  For ARM, PC-relative fixups applied to instructions
17534218822Sdim   are generally relative to the location of the fixup plus 8 bytes.
17535218822Sdim   Thumb branches are offset by 4, and Thumb loads relative to PC
17536218822Sdim   require special handling.  */
17537218822Sdim
1753860484Sobrienlong
17539218822Sdimmd_pcrel_from_section (fixS * fixP, segT seg)
1754060484Sobrien{
17541218822Sdim  offsetT base = fixP->fx_where + fixP->fx_frag->fr_address;
1754277298Sobrien
17543218822Sdim  /* If this is pc-relative and we are going to emit a relocation
17544218822Sdim     then we just want to put out any pipeline compensation that the linker
17545218822Sdim     will need.  Otherwise we want to use the calculated base.
17546218822Sdim     For WinCE we skip the bias for externals as well, since this
17547218822Sdim     is how the MS ARM-CE assembler behaves and we want to be compatible.  */
17548218822Sdim  if (fixP->fx_pcrel
17549218822Sdim      && ((fixP->fx_addsy && S_GET_SEGMENT (fixP->fx_addsy) != seg)
17550218822Sdim	  || (arm_force_relocation (fixP)
17551218822Sdim#ifdef TE_WINCE
17552218822Sdim	      && !S_IS_EXTERNAL (fixP->fx_addsy)
17553218822Sdim#endif
17554218822Sdim	      )))
17555218822Sdim    base = 0;
17556218822Sdim
17557218822Sdim  switch (fixP->fx_r_type)
1755860484Sobrien    {
17559218822Sdim      /* PC relative addressing on the Thumb is slightly odd as the
17560218822Sdim	 bottom two bits of the PC are forced to zero for the
17561218822Sdim	 calculation.  This happens *after* application of the
17562218822Sdim	 pipeline offset.  However, Thumb adrl already adjusts for
17563218822Sdim	 this, so we need not do it again.  */
17564218822Sdim    case BFD_RELOC_ARM_THUMB_ADD:
17565218822Sdim      return base & ~3;
1756660484Sobrien
17567218822Sdim    case BFD_RELOC_ARM_THUMB_OFFSET:
17568218822Sdim    case BFD_RELOC_ARM_T32_OFFSET_IMM:
17569218822Sdim    case BFD_RELOC_ARM_T32_ADD_PC12:
17570218822Sdim    case BFD_RELOC_ARM_T32_CP_OFF_IMM:
17571218822Sdim      return (base + 4) & ~3;
17572218822Sdim
17573218822Sdim      /* Thumb branches are simply offset by +4.  */
17574218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH7:
17575218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH9:
17576218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH12:
17577218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH20:
17578218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH23:
17579218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH25:
17580218822Sdim    case BFD_RELOC_THUMB_PCREL_BLX:
17581218822Sdim      return base + 4;
17582218822Sdim
17583218822Sdim      /* ARM mode branches are offset by +8.  However, the Windows CE
17584218822Sdim	 loader expects the relocation not to take this into account.  */
17585218822Sdim    case BFD_RELOC_ARM_PCREL_BRANCH:
17586218822Sdim    case BFD_RELOC_ARM_PCREL_CALL:
17587218822Sdim    case BFD_RELOC_ARM_PCREL_JUMP:
17588218822Sdim    case BFD_RELOC_ARM_PCREL_BLX:
17589218822Sdim    case BFD_RELOC_ARM_PLT32:
1759060484Sobrien#ifdef TE_WINCE
17591218822Sdim      /* When handling fixups immediately, because we have already
17592218822Sdim         discovered the value of a symbol, or the address of the frag involved
17593218822Sdim	 we must account for the offset by +8, as the OS loader will never see the reloc.
17594218822Sdim         see fixup_segment() in write.c
17595218822Sdim         The S_IS_EXTERNAL test handles the case of global symbols.
17596218822Sdim         Those need the calculated base, not just the pipe compensation the linker will need.  */
17597218822Sdim      if (fixP->fx_pcrel
17598218822Sdim	  && fixP->fx_addsy != NULL
17599218822Sdim	  && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
17600218822Sdim	  && (S_IS_EXTERNAL (fixP->fx_addsy) || !arm_force_relocation (fixP)))
17601218822Sdim	return base + 8;
17602218822Sdim      return base;
1760360484Sobrien#else
17604218822Sdim      return base + 8;
1760560484Sobrien#endif
1760660484Sobrien
17607218822Sdim      /* ARM mode loads relative to PC are also offset by +8.  Unlike
17608218822Sdim	 branches, the Windows CE loader *does* expect the relocation
17609218822Sdim	 to take this into account.  */
17610218822Sdim    case BFD_RELOC_ARM_OFFSET_IMM:
17611218822Sdim    case BFD_RELOC_ARM_OFFSET_IMM8:
17612218822Sdim    case BFD_RELOC_ARM_HWLITERAL:
17613218822Sdim    case BFD_RELOC_ARM_LITERAL:
17614218822Sdim    case BFD_RELOC_ARM_CP_OFF_IMM:
17615218822Sdim      return base + 8;
1761677298Sobrien
17617218822Sdim
17618218822Sdim      /* Other PC-relative relocations are un-offset.  */
17619218822Sdim    default:
17620218822Sdim      return base;
17621218822Sdim    }
1762260484Sobrien}
1762360484Sobrien
1762477298Sobrien/* Under ELF we need to default _GLOBAL_OFFSET_TABLE.
1762577298Sobrien   Otherwise we have no need to default values of symbols.  */
1762660484Sobrien
1762760484SobriensymbolS *
17628218822Sdimmd_undefined_symbol (char * name ATTRIBUTE_UNUSED)
1762960484Sobrien{
1763060484Sobrien#ifdef OBJ_ELF
1763160484Sobrien  if (name[0] == '_' && name[1] == 'G'
1763260484Sobrien      && streq (name, GLOBAL_OFFSET_TABLE_NAME))
1763360484Sobrien    {
1763460484Sobrien      if (!GOT_symbol)
1763560484Sobrien	{
1763660484Sobrien	  if (symbol_find (name))
1763760484Sobrien	    as_bad ("GOT already in the symbol table");
1763877298Sobrien
1763960484Sobrien	  GOT_symbol = symbol_new (name, undefined_section,
1764077298Sobrien				   (valueT) 0, & zero_address_frag);
1764160484Sobrien	}
1764277298Sobrien
1764360484Sobrien      return GOT_symbol;
1764460484Sobrien    }
1764560484Sobrien#endif
1764677298Sobrien
1764760484Sobrien  return 0;
1764860484Sobrien}
1764960484Sobrien
17650218822Sdim/* Subroutine of md_apply_fix.	 Check to see if an immediate can be
17651218822Sdim   computed as two separate immediate values, added together.  We
17652218822Sdim   already know that this value cannot be computed by just one ARM
17653218822Sdim   instruction.	 */
1765460484Sobrien
17655218822Sdimstatic unsigned int
17656218822Sdimvalidate_immediate_twopart (unsigned int   val,
17657218822Sdim			    unsigned int * highpart)
17658218822Sdim{
17659218822Sdim  unsigned int a;
17660218822Sdim  unsigned int i;
17661218822Sdim
17662218822Sdim  for (i = 0; i < 32; i += 2)
17663218822Sdim    if (((a = rotate_left (val, i)) & 0xff) != 0)
17664218822Sdim      {
17665218822Sdim	if (a & 0xff00)
17666218822Sdim	  {
17667218822Sdim	    if (a & ~ 0xffff)
17668218822Sdim	      continue;
17669218822Sdim	    * highpart = (a  >> 8) | ((i + 24) << 7);
17670218822Sdim	  }
17671218822Sdim	else if (a & 0xff0000)
17672218822Sdim	  {
17673218822Sdim	    if (a & 0xff000000)
17674218822Sdim	      continue;
17675218822Sdim	    * highpart = (a >> 16) | ((i + 16) << 7);
17676218822Sdim	  }
17677218822Sdim	else
17678218822Sdim	  {
17679218822Sdim	    assert (a & 0xff000000);
17680218822Sdim	    * highpart = (a >> 24) | ((i + 8) << 7);
17681218822Sdim	  }
17682218822Sdim
17683218822Sdim	return (a & 0xff) | (i << 7);
17684218822Sdim      }
17685218822Sdim
17686218822Sdim  return FAIL;
17687218822Sdim}
17688218822Sdim
1768960484Sobrienstatic int
17690218822Sdimvalidate_offset_imm (unsigned int val, int hwse)
1769160484Sobrien{
17692218822Sdim  if ((hwse && val > 255) || val > 4095)
17693218822Sdim    return FAIL;
17694218822Sdim  return val;
17695218822Sdim}
1769660484Sobrien
17697218822Sdim/* Subroutine of md_apply_fix.	 Do those data_ops which can take a
17698218822Sdim   negative immediate constant by altering the instruction.  A bit of
17699218822Sdim   a hack really.
17700218822Sdim	MOV <-> MVN
17701218822Sdim	AND <-> BIC
17702218822Sdim	ADC <-> SBC
17703218822Sdim	by inverting the second operand, and
17704218822Sdim	ADD <-> SUB
17705218822Sdim	CMP <-> CMN
17706218822Sdim	by negating the second operand.	 */
17707218822Sdim
17708218822Sdimstatic int
17709218822Sdimnegate_data_op (unsigned long * instruction,
17710218822Sdim		unsigned long	value)
17711218822Sdim{
17712218822Sdim  int op, new_inst;
17713218822Sdim  unsigned long negated, inverted;
17714218822Sdim
17715218822Sdim  negated = encode_arm_immediate (-value);
17716218822Sdim  inverted = encode_arm_immediate (~value);
17717218822Sdim
17718218822Sdim  op = (*instruction >> DATA_OP_SHIFT) & 0xf;
17719218822Sdim  switch (op)
17720218822Sdim    {
17721218822Sdim      /* First negates.	 */
17722218822Sdim    case OPCODE_SUB:		 /* ADD <-> SUB	 */
17723218822Sdim      new_inst = OPCODE_ADD;
17724218822Sdim      value = negated;
17725218822Sdim      break;
17726218822Sdim
17727218822Sdim    case OPCODE_ADD:
17728218822Sdim      new_inst = OPCODE_SUB;
17729218822Sdim      value = negated;
17730218822Sdim      break;
17731218822Sdim
17732218822Sdim    case OPCODE_CMP:		 /* CMP <-> CMN	 */
17733218822Sdim      new_inst = OPCODE_CMN;
17734218822Sdim      value = negated;
17735218822Sdim      break;
17736218822Sdim
17737218822Sdim    case OPCODE_CMN:
17738218822Sdim      new_inst = OPCODE_CMP;
17739218822Sdim      value = negated;
17740218822Sdim      break;
17741218822Sdim
17742218822Sdim      /* Now Inverted ops.  */
17743218822Sdim    case OPCODE_MOV:		 /* MOV <-> MVN	 */
17744218822Sdim      new_inst = OPCODE_MVN;
17745218822Sdim      value = inverted;
17746218822Sdim      break;
17747218822Sdim
17748218822Sdim    case OPCODE_MVN:
17749218822Sdim      new_inst = OPCODE_MOV;
17750218822Sdim      value = inverted;
17751218822Sdim      break;
17752218822Sdim
17753218822Sdim    case OPCODE_AND:		 /* AND <-> BIC	 */
17754218822Sdim      new_inst = OPCODE_BIC;
17755218822Sdim      value = inverted;
17756218822Sdim      break;
17757218822Sdim
17758218822Sdim    case OPCODE_BIC:
17759218822Sdim      new_inst = OPCODE_AND;
17760218822Sdim      value = inverted;
17761218822Sdim      break;
17762218822Sdim
17763218822Sdim    case OPCODE_ADC:		  /* ADC <-> SBC  */
17764218822Sdim      new_inst = OPCODE_SBC;
17765218822Sdim      value = inverted;
17766218822Sdim      break;
17767218822Sdim
17768218822Sdim    case OPCODE_SBC:
17769218822Sdim      new_inst = OPCODE_ADC;
17770218822Sdim      value = inverted;
17771218822Sdim      break;
17772218822Sdim
17773218822Sdim      /* We cannot do anything.	 */
17774218822Sdim    default:
17775218822Sdim      return FAIL;
17776218822Sdim    }
17777218822Sdim
17778218822Sdim  if (value == (unsigned) FAIL)
1777960484Sobrien    return FAIL;
1778060484Sobrien
17781218822Sdim  *instruction &= OPCODE_MASK;
17782218822Sdim  *instruction |= new_inst << DATA_OP_SHIFT;
17783218822Sdim  return value;
17784218822Sdim}
1778560484Sobrien
17786218822Sdim/* Like negate_data_op, but for Thumb-2.   */
1778777298Sobrien
17788218822Sdimstatic unsigned int
17789218822Sdimthumb32_negate_data_op (offsetT *instruction, unsigned int value)
17790218822Sdim{
17791218822Sdim  int op, new_inst;
17792218822Sdim  int rd;
17793218822Sdim  unsigned int negated, inverted;
17794218822Sdim
17795218822Sdim  negated = encode_thumb32_immediate (-value);
17796218822Sdim  inverted = encode_thumb32_immediate (~value);
17797218822Sdim
17798218822Sdim  rd = (*instruction >> 8) & 0xf;
17799218822Sdim  op = (*instruction >> T2_DATA_OP_SHIFT) & 0xf;
17800218822Sdim  switch (op)
1780160484Sobrien    {
17802218822Sdim      /* ADD <-> SUB.  Includes CMP <-> CMN.  */
17803218822Sdim    case T2_OPCODE_SUB:
17804218822Sdim      new_inst = T2_OPCODE_ADD;
17805218822Sdim      value = negated;
17806218822Sdim      break;
17807218822Sdim
17808218822Sdim    case T2_OPCODE_ADD:
17809218822Sdim      new_inst = T2_OPCODE_SUB;
17810218822Sdim      value = negated;
17811218822Sdim      break;
17812218822Sdim
17813218822Sdim      /* ORR <-> ORN.  Includes MOV <-> MVN.  */
17814218822Sdim    case T2_OPCODE_ORR:
17815218822Sdim      new_inst = T2_OPCODE_ORN;
17816218822Sdim      value = inverted;
17817218822Sdim      break;
17818218822Sdim
17819218822Sdim    case T2_OPCODE_ORN:
17820218822Sdim      new_inst = T2_OPCODE_ORR;
17821218822Sdim      value = inverted;
17822218822Sdim      break;
17823218822Sdim
17824218822Sdim      /* AND <-> BIC.  TST has no inverted equivalent.  */
17825218822Sdim    case T2_OPCODE_AND:
17826218822Sdim      new_inst = T2_OPCODE_BIC;
17827218822Sdim      if (rd == 15)
17828218822Sdim	value = FAIL;
17829218822Sdim      else
17830218822Sdim	value = inverted;
17831218822Sdim      break;
17832218822Sdim
17833218822Sdim    case T2_OPCODE_BIC:
17834218822Sdim      new_inst = T2_OPCODE_AND;
17835218822Sdim      value = inverted;
17836218822Sdim      break;
17837218822Sdim
17838218822Sdim      /* ADC <-> SBC  */
17839218822Sdim    case T2_OPCODE_ADC:
17840218822Sdim      new_inst = T2_OPCODE_SBC;
17841218822Sdim      value = inverted;
17842218822Sdim      break;
17843218822Sdim
17844218822Sdim    case T2_OPCODE_SBC:
17845218822Sdim      new_inst = T2_OPCODE_ADC;
17846218822Sdim      value = inverted;
17847218822Sdim      break;
17848218822Sdim
17849218822Sdim      /* We cannot do anything.	 */
17850218822Sdim    default:
17851218822Sdim      return FAIL;
1785260484Sobrien    }
1785360484Sobrien
17854218822Sdim  if (value == (unsigned int)FAIL)
17855218822Sdim    return FAIL;
17856218822Sdim
17857218822Sdim  *instruction &= T2_OPCODE_MASK;
17858218822Sdim  *instruction |= new_inst << T2_DATA_OP_SHIFT;
17859218822Sdim  return value;
1786060484Sobrien}
1786160484Sobrien
17862218822Sdim/* Read a 32-bit thumb instruction from buf.  */
17863218822Sdimstatic unsigned long
17864218822Sdimget_thumb32_insn (char * buf)
1786589857Sobrien{
17866218822Sdim  unsigned long insn;
17867218822Sdim  insn = md_chars_to_number (buf, THUMB_SIZE) << 16;
17868218822Sdim  insn |= md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
1786989857Sobrien
17870218822Sdim  return insn;
17871218822Sdim}
1787289857Sobrien
17873218822Sdim
17874218822Sdim/* We usually want to set the low bit on the address of thumb function
17875218822Sdim   symbols.  In particular .word foo - . should have the low bit set.
17876218822Sdim   Generic code tries to fold the difference of two symbols to
17877218822Sdim   a constant.  Prevent this and force a relocation when the first symbols
17878218822Sdim   is a thumb function.  */
17879218822Sdimint
17880218822Sdimarm_optimize_expr (expressionS *l, operatorT op, expressionS *r)
17881218822Sdim{
17882218822Sdim  if (op == O_subtract
17883218822Sdim      && l->X_op == O_symbol
17884218822Sdim      && r->X_op == O_symbol
17885218822Sdim      && THUMB_IS_FUNC (l->X_add_symbol))
17886218822Sdim    {
17887218822Sdim      l->X_op = O_subtract;
17888218822Sdim      l->X_op_symbol = r->X_add_symbol;
17889218822Sdim      l->X_add_number -= r->X_add_number;
17890218822Sdim      return 1;
17891218822Sdim    }
17892218822Sdim  /* Process as normal.  */
17893218822Sdim  return 0;
1789489857Sobrien}
1789589857Sobrien
1789689857Sobrienvoid
17897218822Sdimmd_apply_fix (fixS *	fixP,
17898218822Sdim	       valueT * valP,
17899218822Sdim	       segT	seg)
1790060484Sobrien{
17901218822Sdim  offsetT	 value = * valP;
17902218822Sdim  offsetT	 newval;
17903218822Sdim  unsigned int	 newimm;
17904218822Sdim  unsigned long	 temp;
17905218822Sdim  int		 sign;
17906218822Sdim  char *	 buf = fixP->fx_where + fixP->fx_frag->fr_literal;
1790760484Sobrien
17908218822Sdim  assert (fixP->fx_r_type <= BFD_RELOC_UNUSED);
1790960484Sobrien
1791060484Sobrien  /* Note whether this will delete the relocation.  */
17911218822Sdim
1791260484Sobrien  if (fixP->fx_addsy == 0 && !fixP->fx_pcrel)
1791360484Sobrien    fixP->fx_done = 1;
1791460484Sobrien
17915218822Sdim  /* On a 64-bit host, silently truncate 'value' to 32 bits for
17916218822Sdim     consistency with the behavior on 32-bit hosts.  Remember value
17917218822Sdim     for emit_reloc.  */
17918218822Sdim  value &= 0xffffffff;
17919218822Sdim  value ^= 0x80000000;
17920218822Sdim  value -= 0x80000000;
1792160484Sobrien
17922218822Sdim  *valP = value;
1792377298Sobrien  fixP->fx_addnumber = value;
1792460484Sobrien
17925218822Sdim  /* Same treatment for fixP->fx_offset.  */
17926218822Sdim  fixP->fx_offset &= 0xffffffff;
17927218822Sdim  fixP->fx_offset ^= 0x80000000;
17928218822Sdim  fixP->fx_offset -= 0x80000000;
17929218822Sdim
1793060484Sobrien  switch (fixP->fx_r_type)
1793160484Sobrien    {
17932218822Sdim    case BFD_RELOC_NONE:
17933218822Sdim      /* This will need to go in the object file.  */
17934218822Sdim      fixP->fx_done = 0;
17935218822Sdim      break;
17936218822Sdim
1793760484Sobrien    case BFD_RELOC_ARM_IMMEDIATE:
17938218822Sdim      /* We claim that this fixup has been processed here,
17939218822Sdim	 even if in fact we generate an error because we do
17940218822Sdim	 not have a reloc for it, so tc_gen_reloc will reject it.  */
17941218822Sdim      fixP->fx_done = 1;
17942218822Sdim
17943218822Sdim      if (fixP->fx_addsy
17944218822Sdim	  && ! S_IS_DEFINED (fixP->fx_addsy))
17945218822Sdim	{
17946218822Sdim	  as_bad_where (fixP->fx_file, fixP->fx_line,
17947218822Sdim			_("undefined symbol %s used as an immediate value"),
17948218822Sdim			S_GET_NAME (fixP->fx_addsy));
17949218822Sdim	  break;
17950218822Sdim	}
17951218822Sdim
17952218822Sdim      newimm = encode_arm_immediate (value);
1795360484Sobrien      temp = md_chars_to_number (buf, INSN_SIZE);
1795460484Sobrien
1795560484Sobrien      /* If the instruction will fail, see if we can fix things up by
1795660484Sobrien	 changing the opcode.  */
1795760484Sobrien      if (newimm == (unsigned int) FAIL
1795860484Sobrien	  && (newimm = negate_data_op (&temp, value)) == (unsigned int) FAIL)
1795960484Sobrien	{
1796060484Sobrien	  as_bad_where (fixP->fx_file, fixP->fx_line,
1796160484Sobrien			_("invalid constant (%lx) after fixup"),
1796260484Sobrien			(unsigned long) value);
1796360484Sobrien	  break;
1796460484Sobrien	}
1796560484Sobrien
1796660484Sobrien      newimm |= (temp & 0xfffff000);
1796760484Sobrien      md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
1796860484Sobrien      break;
1796960484Sobrien
1797060484Sobrien    case BFD_RELOC_ARM_ADRL_IMMEDIATE:
1797160484Sobrien      {
1797260484Sobrien	unsigned int highpart = 0;
1797377298Sobrien	unsigned int newinsn  = 0xe1a00000; /* nop.  */
17974130561Sobrien
17975218822Sdim	newimm = encode_arm_immediate (value);
1797660484Sobrien	temp = md_chars_to_number (buf, INSN_SIZE);
1797760484Sobrien
1797860484Sobrien	/* If the instruction will fail, see if we can fix things up by
17979218822Sdim	   changing the opcode.	 */
1798060484Sobrien	if (newimm == (unsigned int) FAIL
1798160484Sobrien	    && (newimm = negate_data_op (& temp, value)) == (unsigned int) FAIL)
1798260484Sobrien	  {
1798377298Sobrien	    /* No ?  OK - try using two ADD instructions to generate
17984218822Sdim	       the value.  */
1798560484Sobrien	    newimm = validate_immediate_twopart (value, & highpart);
1798660484Sobrien
1798777298Sobrien	    /* Yes - then make sure that the second instruction is
17988218822Sdim	       also an add.  */
1798960484Sobrien	    if (newimm != (unsigned int) FAIL)
1799060484Sobrien	      newinsn = temp;
1799160484Sobrien	    /* Still No ?  Try using a negated value.  */
1799268765Sobrien	    else if ((newimm = validate_immediate_twopart (- value, & highpart)) != (unsigned int) FAIL)
1799377298Sobrien	      temp = newinsn = (temp & OPCODE_MASK) | OPCODE_SUB << DATA_OP_SHIFT;
1799460484Sobrien	    /* Otherwise - give up.  */
1799560484Sobrien	    else
1799660484Sobrien	      {
1799760484Sobrien		as_bad_where (fixP->fx_file, fixP->fx_line,
1799889857Sobrien			      _("unable to compute ADRL instructions for PC offset of 0x%lx"),
17999130561Sobrien			      (long) value);
1800060484Sobrien		break;
1800160484Sobrien	      }
1800260484Sobrien
1800377298Sobrien	    /* Replace the first operand in the 2nd instruction (which
1800477298Sobrien	       is the PC) with the destination register.  We have
1800577298Sobrien	       already added in the PC in the first instruction and we
1800677298Sobrien	       do not want to do it again.  */
1800760484Sobrien	    newinsn &= ~ 0xf0000;
1800860484Sobrien	    newinsn |= ((newinsn & 0x0f000) << 4);
1800960484Sobrien	  }
1801060484Sobrien
1801160484Sobrien	newimm |= (temp & 0xfffff000);
1801260484Sobrien	md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
1801360484Sobrien
1801460484Sobrien	highpart |= (newinsn & 0xfffff000);
1801560484Sobrien	md_number_to_chars (buf + INSN_SIZE, (valueT) highpart, INSN_SIZE);
1801660484Sobrien      }
1801760484Sobrien      break;
1801860484Sobrien
1801960484Sobrien    case BFD_RELOC_ARM_OFFSET_IMM:
18020218822Sdim      if (!fixP->fx_done && seg->use_rela_p)
18021218822Sdim	value = 0;
18022218822Sdim
18023218822Sdim    case BFD_RELOC_ARM_LITERAL:
1802460484Sobrien      sign = value >= 0;
1802577298Sobrien
1802660484Sobrien      if (value < 0)
1802760484Sobrien	value = - value;
1802877298Sobrien
1802960484Sobrien      if (validate_offset_imm (value, 0) == FAIL)
1803077298Sobrien	{
18031218822Sdim	  if (fixP->fx_r_type == BFD_RELOC_ARM_LITERAL)
18032218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
18033218822Sdim			  _("invalid literal constant: pool needs to be closer"));
18034218822Sdim	  else
18035218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
18036218822Sdim			  _("bad immediate value for offset (%ld)"),
18037218822Sdim			  (long) value);
1803877298Sobrien	  break;
1803977298Sobrien	}
1804060484Sobrien
1804160484Sobrien      newval = md_chars_to_number (buf, INSN_SIZE);
1804260484Sobrien      newval &= 0xff7ff000;
1804360484Sobrien      newval |= value | (sign ? INDEX_UP : 0);
1804460484Sobrien      md_number_to_chars (buf, newval, INSN_SIZE);
1804560484Sobrien      break;
1804660484Sobrien
1804777298Sobrien    case BFD_RELOC_ARM_OFFSET_IMM8:
1804877298Sobrien    case BFD_RELOC_ARM_HWLITERAL:
1804960484Sobrien      sign = value >= 0;
1805077298Sobrien
1805160484Sobrien      if (value < 0)
1805260484Sobrien	value = - value;
1805360484Sobrien
1805460484Sobrien      if (validate_offset_imm (value, 1) == FAIL)
1805577298Sobrien	{
1805677298Sobrien	  if (fixP->fx_r_type == BFD_RELOC_ARM_HWLITERAL)
1805777298Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
1805877298Sobrien			  _("invalid literal constant: pool needs to be closer"));
1805977298Sobrien	  else
18060218822Sdim	    as_bad (_("bad immediate value for 8-bit offset (%ld)"),
1806160484Sobrien		    (long) value);
1806277298Sobrien	  break;
1806377298Sobrien	}
1806460484Sobrien
1806560484Sobrien      newval = md_chars_to_number (buf, INSN_SIZE);
1806660484Sobrien      newval &= 0xff7ff0f0;
1806760484Sobrien      newval |= ((value >> 4) << 8) | (value & 0xf) | (sign ? INDEX_UP : 0);
1806860484Sobrien      md_number_to_chars (buf, newval, INSN_SIZE);
1806960484Sobrien      break;
1807060484Sobrien
18071218822Sdim    case BFD_RELOC_ARM_T32_OFFSET_U8:
18072218822Sdim      if (value < 0 || value > 1020 || value % 4 != 0)
18073218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18074218822Sdim		      _("bad immediate value for offset (%ld)"), (long) value);
18075218822Sdim      value /= 4;
1807677298Sobrien
18077218822Sdim      newval = md_chars_to_number (buf+2, THUMB_SIZE);
18078218822Sdim      newval |= value;
18079218822Sdim      md_number_to_chars (buf+2, newval, THUMB_SIZE);
18080218822Sdim      break;
1808160484Sobrien
18082218822Sdim    case BFD_RELOC_ARM_T32_OFFSET_IMM:
18083218822Sdim      /* This is a complicated relocation used for all varieties of Thumb32
18084218822Sdim	 load/store instruction with immediate offset:
18085218822Sdim
18086218822Sdim	 1110 100P u1WL NNNN XXXX YYYY iiii iiii - +/-(U) pre/post(P) 8-bit,
18087218822Sdim	                                           *4, optional writeback(W)
18088218822Sdim						   (doubleword load/store)
18089218822Sdim
18090218822Sdim	 1111 100S uTTL 1111 XXXX iiii iiii iiii - +/-(U) 12-bit PC-rel
18091218822Sdim	 1111 100S 0TTL NNNN XXXX 1Pu1 iiii iiii - +/-(U) pre/post(P) 8-bit
18092218822Sdim	 1111 100S 0TTL NNNN XXXX 1110 iiii iiii - positive 8-bit (T instruction)
18093218822Sdim	 1111 100S 1TTL NNNN XXXX iiii iiii iiii - positive 12-bit
18094218822Sdim	 1111 100S 0TTL NNNN XXXX 1100 iiii iiii - negative 8-bit
18095218822Sdim
18096218822Sdim	 Uppercase letters indicate bits that are already encoded at
18097218822Sdim	 this point.  Lowercase letters are our problem.  For the
18098218822Sdim	 second block of instructions, the secondary opcode nybble
18099218822Sdim	 (bits 8..11) is present, and bit 23 is zero, even if this is
18100218822Sdim	 a PC-relative operation.  */
18101218822Sdim      newval = md_chars_to_number (buf, THUMB_SIZE);
18102218822Sdim      newval <<= 16;
18103218822Sdim      newval |= md_chars_to_number (buf+THUMB_SIZE, THUMB_SIZE);
18104218822Sdim
18105218822Sdim      if ((newval & 0xf0000000) == 0xe0000000)
1810660484Sobrien	{
18107218822Sdim	  /* Doubleword load/store: 8-bit offset, scaled by 4.  */
18108218822Sdim	  if (value >= 0)
18109218822Sdim	    newval |= (1 << 23);
18110218822Sdim	  else
18111218822Sdim	    value = -value;
18112218822Sdim	  if (value % 4 != 0)
18113218822Sdim	    {
18114218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18115218822Sdim			    _("offset not a multiple of 4"));
18116218822Sdim	      break;
18117218822Sdim	    }
18118218822Sdim	  value /= 4;
18119218822Sdim	  if (value > 0xff)
18120218822Sdim	    {
18121218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18122218822Sdim			    _("offset out of range"));
18123218822Sdim	      break;
18124218822Sdim	    }
18125218822Sdim	  newval &= ~0xff;
1812660484Sobrien	}
18127218822Sdim      else if ((newval & 0x000f0000) == 0x000f0000)
18128218822Sdim	{
18129218822Sdim	  /* PC-relative, 12-bit offset.  */
18130218822Sdim	  if (value >= 0)
18131218822Sdim	    newval |= (1 << 23);
18132218822Sdim	  else
18133218822Sdim	    value = -value;
18134218822Sdim	  if (value > 0xfff)
18135218822Sdim	    {
18136218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18137218822Sdim			    _("offset out of range"));
18138218822Sdim	      break;
18139218822Sdim	    }
18140218822Sdim	  newval &= ~0xfff;
18141218822Sdim	}
18142218822Sdim      else if ((newval & 0x00000100) == 0x00000100)
18143218822Sdim	{
18144218822Sdim	  /* Writeback: 8-bit, +/- offset.  */
18145218822Sdim	  if (value >= 0)
18146218822Sdim	    newval |= (1 << 9);
18147218822Sdim	  else
18148218822Sdim	    value = -value;
18149218822Sdim	  if (value > 0xff)
18150218822Sdim	    {
18151218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18152218822Sdim			    _("offset out of range"));
18153218822Sdim	      break;
18154218822Sdim	    }
18155218822Sdim	  newval &= ~0xff;
18156218822Sdim	}
18157218822Sdim      else if ((newval & 0x00000f00) == 0x00000e00)
18158218822Sdim	{
18159218822Sdim	  /* T-instruction: positive 8-bit offset.  */
18160218822Sdim	  if (value < 0 || value > 0xff)
18161218822Sdim	    {
18162218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18163218822Sdim			    _("offset out of range"));
18164218822Sdim	      break;
18165218822Sdim	    }
18166218822Sdim	  newval &= ~0xff;
18167218822Sdim	  newval |= value;
18168218822Sdim	}
18169218822Sdim      else
18170218822Sdim	{
18171218822Sdim	  /* Positive 12-bit or negative 8-bit offset.  */
18172218822Sdim	  int limit;
18173218822Sdim	  if (value >= 0)
18174218822Sdim	    {
18175218822Sdim	      newval |= (1 << 23);
18176218822Sdim	      limit = 0xfff;
18177218822Sdim	    }
18178218822Sdim	  else
18179218822Sdim	    {
18180218822Sdim	      value = -value;
18181218822Sdim	      limit = 0xff;
18182218822Sdim	    }
18183218822Sdim	  if (value > limit)
18184218822Sdim	    {
18185218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18186218822Sdim			    _("offset out of range"));
18187218822Sdim	      break;
18188218822Sdim	    }
18189218822Sdim	  newval &= ~limit;
18190218822Sdim	}
1819160484Sobrien
18192218822Sdim      newval |= value;
18193218822Sdim      md_number_to_chars (buf, (newval >> 16) & 0xffff, THUMB_SIZE);
18194218822Sdim      md_number_to_chars (buf + THUMB_SIZE, newval & 0xffff, THUMB_SIZE);
1819560484Sobrien      break;
1819660484Sobrien
1819760484Sobrien    case BFD_RELOC_ARM_SHIFT_IMM:
1819860484Sobrien      newval = md_chars_to_number (buf, INSN_SIZE);
1819960484Sobrien      if (((unsigned long) value) > 32
1820077298Sobrien	  || (value == 32
1820160484Sobrien	      && (((newval & 0x60) == 0) || (newval & 0x60) == 0x60)))
1820260484Sobrien	{
1820360484Sobrien	  as_bad_where (fixP->fx_file, fixP->fx_line,
1820460484Sobrien			_("shift expression is too large"));
1820560484Sobrien	  break;
1820660484Sobrien	}
1820760484Sobrien
1820860484Sobrien      if (value == 0)
18209218822Sdim	/* Shifts of zero must be done as lsl.	*/
1821077298Sobrien	newval &= ~0x60;
1821160484Sobrien      else if (value == 32)
1821260484Sobrien	value = 0;
1821360484Sobrien      newval &= 0xfffff07f;
1821460484Sobrien      newval |= (value & 0x1f) << 7;
1821577298Sobrien      md_number_to_chars (buf, newval, INSN_SIZE);
1821660484Sobrien      break;
1821760484Sobrien
18218218822Sdim    case BFD_RELOC_ARM_T32_IMMEDIATE:
18219218822Sdim    case BFD_RELOC_ARM_T32_ADD_IMM:
18220218822Sdim    case BFD_RELOC_ARM_T32_IMM12:
18221218822Sdim    case BFD_RELOC_ARM_T32_ADD_PC12:
18222218822Sdim      /* We claim that this fixup has been processed here,
18223218822Sdim	 even if in fact we generate an error because we do
18224218822Sdim	 not have a reloc for it, so tc_gen_reloc will reject it.  */
18225218822Sdim      fixP->fx_done = 1;
18226218822Sdim
18227218822Sdim      if (fixP->fx_addsy
18228218822Sdim	  && ! S_IS_DEFINED (fixP->fx_addsy))
18229218822Sdim	{
18230218822Sdim	  as_bad_where (fixP->fx_file, fixP->fx_line,
18231218822Sdim			_("undefined symbol %s used as an immediate value"),
18232218822Sdim			S_GET_NAME (fixP->fx_addsy));
18233218822Sdim	  break;
18234218822Sdim	}
18235218822Sdim
18236218822Sdim      newval = md_chars_to_number (buf, THUMB_SIZE);
18237218822Sdim      newval <<= 16;
18238218822Sdim      newval |= md_chars_to_number (buf+2, THUMB_SIZE);
18239218822Sdim
18240218822Sdim      newimm = FAIL;
18241218822Sdim      if (fixP->fx_r_type == BFD_RELOC_ARM_T32_IMMEDIATE
18242218822Sdim	  || fixP->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM)
18243218822Sdim	{
18244218822Sdim	  newimm = encode_thumb32_immediate (value);
18245218822Sdim	  if (newimm == (unsigned int) FAIL)
18246218822Sdim	    newimm = thumb32_negate_data_op (&newval, value);
18247218822Sdim	}
18248218822Sdim      if (fixP->fx_r_type != BFD_RELOC_ARM_T32_IMMEDIATE
18249218822Sdim	  && newimm == (unsigned int) FAIL)
18250218822Sdim	{
18251218822Sdim	  /* Turn add/sum into addw/subw.  */
18252218822Sdim	  if (fixP->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM)
18253218822Sdim	    newval = (newval & 0xfeffffff) | 0x02000000;
18254218822Sdim
18255218822Sdim	  /* 12 bit immediate for addw/subw.  */
18256218822Sdim	  if (value < 0)
18257218822Sdim	    {
18258218822Sdim	      value = -value;
18259218822Sdim	      newval ^= 0x00a00000;
18260218822Sdim	    }
18261218822Sdim	  if (value > 0xfff)
18262218822Sdim	    newimm = (unsigned int) FAIL;
18263218822Sdim	  else
18264218822Sdim	    newimm = value;
18265218822Sdim	}
18266218822Sdim
18267218822Sdim      if (newimm == (unsigned int)FAIL)
18268218822Sdim	{
18269218822Sdim	  as_bad_where (fixP->fx_file, fixP->fx_line,
18270218822Sdim			_("invalid constant (%lx) after fixup"),
18271218822Sdim			(unsigned long) value);
18272218822Sdim	  break;
18273218822Sdim	}
18274218822Sdim
18275218822Sdim      newval |= (newimm & 0x800) << 15;
18276218822Sdim      newval |= (newimm & 0x700) << 4;
18277218822Sdim      newval |= (newimm & 0x0ff);
18278218822Sdim
18279218822Sdim      md_number_to_chars (buf,   (valueT) ((newval >> 16) & 0xffff), THUMB_SIZE);
18280218822Sdim      md_number_to_chars (buf+2, (valueT) (newval & 0xffff), THUMB_SIZE);
18281218822Sdim      break;
18282218822Sdim
18283218822Sdim    case BFD_RELOC_ARM_SMC:
18284218822Sdim      if (((unsigned long) value) > 0xffff)
18285218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18286218822Sdim		      _("invalid smc expression"));
18287218822Sdim      newval = md_chars_to_number (buf, INSN_SIZE);
18288218822Sdim      newval |= (value & 0xf) | ((value & 0xfff0) << 4);
18289218822Sdim      md_number_to_chars (buf, newval, INSN_SIZE);
18290218822Sdim      break;
18291218822Sdim
1829260484Sobrien    case BFD_RELOC_ARM_SWI:
18293218822Sdim      if (fixP->tc_fix_data != 0)
1829460484Sobrien	{
1829560484Sobrien	  if (((unsigned long) value) > 0xff)
1829660484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
1829789857Sobrien			  _("invalid swi expression"));
18298218822Sdim	  newval = md_chars_to_number (buf, THUMB_SIZE);
1829960484Sobrien	  newval |= value;
1830060484Sobrien	  md_number_to_chars (buf, newval, THUMB_SIZE);
1830160484Sobrien	}
1830260484Sobrien      else
1830360484Sobrien	{
1830460484Sobrien	  if (((unsigned long) value) > 0x00ffffff)
1830577298Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
1830689857Sobrien			  _("invalid swi expression"));
18307218822Sdim	  newval = md_chars_to_number (buf, INSN_SIZE);
1830860484Sobrien	  newval |= value;
1830977298Sobrien	  md_number_to_chars (buf, newval, INSN_SIZE);
1831060484Sobrien	}
1831160484Sobrien      break;
1831260484Sobrien
1831360484Sobrien    case BFD_RELOC_ARM_MULTI:
1831460484Sobrien      if (((unsigned long) value) > 0xffff)
1831560484Sobrien	as_bad_where (fixP->fx_file, fixP->fx_line,
1831689857Sobrien		      _("invalid expression in load/store multiple"));
1831760484Sobrien      newval = value | md_chars_to_number (buf, INSN_SIZE);
1831860484Sobrien      md_number_to_chars (buf, newval, INSN_SIZE);
1831960484Sobrien      break;
1832060484Sobrien
18321218822Sdim#ifdef OBJ_ELF
18322218822Sdim    case BFD_RELOC_ARM_PCREL_CALL:
1832360484Sobrien      newval = md_chars_to_number (buf, INSN_SIZE);
18324218822Sdim      if ((newval & 0xf0000000) == 0xf0000000)
18325218822Sdim	temp = 1;
18326218822Sdim      else
18327218822Sdim	temp = 3;
18328218822Sdim      goto arm_branch_common;
1832960484Sobrien
18330218822Sdim    case BFD_RELOC_ARM_PCREL_JUMP:
18331218822Sdim    case BFD_RELOC_ARM_PLT32:
1833260484Sobrien#endif
18333218822Sdim    case BFD_RELOC_ARM_PCREL_BRANCH:
18334218822Sdim      temp = 3;
18335218822Sdim      goto arm_branch_common;
1833660484Sobrien
18337218822Sdim    case BFD_RELOC_ARM_PCREL_BLX:
18338218822Sdim      temp = 1;
18339218822Sdim    arm_branch_common:
1834060484Sobrien      /* We are going to store value (shifted right by two) in the
18341218822Sdim	 instruction, in a 24 bit, signed field.  Bits 26 through 32 either
18342218822Sdim	 all clear or all set and bit 0 must be clear.  For B/BL bit 1 must
18343218822Sdim	 also be be clear.  */
18344218822Sdim      if (value & temp)
18345218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18346218822Sdim		      _("misaligned branch destination"));
18347218822Sdim      if ((value & (offsetT)0xfe000000) != (offsetT)0
18348218822Sdim	  && (value & (offsetT)0xfe000000) != (offsetT)0xfe000000)
18349218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18350218822Sdim		      _("branch out of range"));
18351218822Sdim
18352218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
1835360484Sobrien	{
18354218822Sdim	  newval = md_chars_to_number (buf, INSN_SIZE);
18355218822Sdim	  newval |= (value >> 2) & 0x00ffffff;
18356218822Sdim	  /* Set the H bit on BLX instructions.  */
18357218822Sdim	  if (temp == 1)
1835860484Sobrien	    {
18359218822Sdim	      if (value & 2)
18360218822Sdim		newval |= 0x01000000;
18361218822Sdim	      else
18362218822Sdim		newval &= ~0x01000000;
1836360484Sobrien	    }
18364218822Sdim	  md_number_to_chars (buf, newval, INSN_SIZE);
18365218822Sdim	}
18366218822Sdim      break;
1836777298Sobrien
18368218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH7: /* CBZ */
18369218822Sdim      /* CBZ can only branch forward.  */
18370218822Sdim
18371218822Sdim      /* Attempts to use CBZ to branch to the next instruction
18372218822Sdim         (which, strictly speaking, are prohibited) will be turned into
18373218822Sdim         no-ops.
18374218822Sdim
18375218822Sdim	 FIXME: It may be better to remove the instruction completely and
18376218822Sdim	 perform relaxation.  */
18377218822Sdim      if (value == -2)
18378218822Sdim	{
18379218822Sdim	  newval = md_chars_to_number (buf, THUMB_SIZE);
18380218822Sdim	  newval = 0xbf00; /* NOP encoding T1 */
18381218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18382218822Sdim	}
18383218822Sdim      else
18384218822Sdim	{
18385218822Sdim	  if (value & ~0x7e)
1838660484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18387218822Sdim		          _("branch out of range"));
18388218822Sdim
18389218822Sdim          if (fixP->fx_done || !seg->use_rela_p)
18390218822Sdim	    {
18391218822Sdim	      newval = md_chars_to_number (buf, THUMB_SIZE);
18392218822Sdim	      newval |= ((value & 0x3e) << 2) | ((value & 0x40) << 3);
18393218822Sdim	      md_number_to_chars (buf, newval, THUMB_SIZE);
18394218822Sdim	    }
1839560484Sobrien	}
18396218822Sdim      break;
1839760484Sobrien
18398218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH9: /* Conditional branch.	*/
18399218822Sdim      if ((value & ~0xff) && ((value & ~0xff) != ~0xff))
1840060484Sobrien	as_bad_where (fixP->fx_file, fixP->fx_line,
18401218822Sdim		      _("branch out of range"));
1840277298Sobrien
18403218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18404218822Sdim	{
18405218822Sdim	  newval = md_chars_to_number (buf, THUMB_SIZE);
18406218822Sdim	  newval |= (value & 0x1ff) >> 1;
18407218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18408218822Sdim	}
1840960484Sobrien      break;
1841060484Sobrien
18411218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH12: /* Unconditional branch.  */
18412218822Sdim      if ((value & ~0x7ff) && ((value & ~0x7ff) != ~0x7ff))
18413218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18414218822Sdim		      _("branch out of range"));
1841560484Sobrien
18416218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18417218822Sdim	{
18418218822Sdim	  newval = md_chars_to_number (buf, THUMB_SIZE);
18419218822Sdim	  newval |= (value & 0xfff) >> 1;
18420218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18421218822Sdim	}
1842277298Sobrien      break;
1842377298Sobrien
18424218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH20:
18425218822Sdim      if ((value & ~0x1fffff) && ((value & ~0x1fffff) != ~0x1fffff))
18426218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18427218822Sdim		      _("conditional branch out of range"));
1842860484Sobrien
18429218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18430218822Sdim	{
18431218822Sdim	  offsetT newval2;
18432218822Sdim	  addressT S, J1, J2, lo, hi;
1843360484Sobrien
18434218822Sdim	  S  = (value & 0x00100000) >> 20;
18435218822Sdim	  J2 = (value & 0x00080000) >> 19;
18436218822Sdim	  J1 = (value & 0x00040000) >> 18;
18437218822Sdim	  hi = (value & 0x0003f000) >> 12;
18438218822Sdim	  lo = (value & 0x00000ffe) >> 1;
1843960484Sobrien
18440218822Sdim	  newval   = md_chars_to_number (buf, THUMB_SIZE);
18441218822Sdim	  newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
18442218822Sdim	  newval  |= (S << 10) | hi;
18443218822Sdim	  newval2 |= (J1 << 13) | (J2 << 11) | lo;
18444218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18445218822Sdim	  md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
18446218822Sdim	}
1844760484Sobrien      break;
1844860484Sobrien
1844977298Sobrien    case BFD_RELOC_THUMB_PCREL_BLX:
1845060484Sobrien    case BFD_RELOC_THUMB_PCREL_BRANCH23:
18451218822Sdim      if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff))
18452218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18453218822Sdim		      _("branch out of range"));
1845460484Sobrien
18455218822Sdim      if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
18456218822Sdim	/* For a BLX instruction, make sure that the relocation is rounded up
18457218822Sdim	   to a word boundary.  This follows the semantics of the instruction
18458218822Sdim	   which specifies that bit 1 of the target address will come from bit
18459218822Sdim	   1 of the base address.  */
18460218822Sdim	value = (value + 1) & ~ 1;
18461104834Sobrien
18462218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18463218822Sdim	{
18464218822Sdim	  offsetT newval2;
1846560484Sobrien
18466218822Sdim	  newval   = md_chars_to_number (buf, THUMB_SIZE);
18467218822Sdim	  newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
18468218822Sdim	  newval  |= (value & 0x7fffff) >> 12;
18469218822Sdim	  newval2 |= (value & 0xfff) >> 1;
18470218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18471218822Sdim	  md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
18472218822Sdim	}
1847360484Sobrien      break;
1847460484Sobrien
18475218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH25:
18476218822Sdim      if ((value & ~0x1ffffff) && ((value & ~0x1ffffff) != ~0x1ffffff))
18477218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18478218822Sdim		      _("branch out of range"));
18479218822Sdim
18480218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
1848177298Sobrien	{
18482218822Sdim	  offsetT newval2;
18483218822Sdim	  addressT S, I1, I2, lo, hi;
18484218822Sdim
18485218822Sdim	  S  = (value & 0x01000000) >> 24;
18486218822Sdim	  I1 = (value & 0x00800000) >> 23;
18487218822Sdim	  I2 = (value & 0x00400000) >> 22;
18488218822Sdim	  hi = (value & 0x003ff000) >> 12;
18489218822Sdim	  lo = (value & 0x00000ffe) >> 1;
18490218822Sdim
18491218822Sdim	  I1 = !(I1 ^ S);
18492218822Sdim	  I2 = !(I2 ^ S);
18493218822Sdim
18494218822Sdim	  newval   = md_chars_to_number (buf, THUMB_SIZE);
18495218822Sdim	  newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
18496218822Sdim	  newval  |= (S << 10) | hi;
18497218822Sdim	  newval2 |= (I1 << 13) | (I2 << 11) | lo;
18498218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18499218822Sdim	  md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
1850077298Sobrien	}
1850160484Sobrien      break;
1850260484Sobrien
18503218822Sdim    case BFD_RELOC_8:
18504218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18505218822Sdim	md_number_to_chars (buf, value, 1);
18506218822Sdim      break;
18507218822Sdim
1850860484Sobrien    case BFD_RELOC_16:
18509218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
1851060484Sobrien	md_number_to_chars (buf, value, 2);
1851160484Sobrien      break;
1851260484Sobrien
1851360484Sobrien#ifdef OBJ_ELF
18514218822Sdim    case BFD_RELOC_ARM_TLS_GD32:
18515218822Sdim    case BFD_RELOC_ARM_TLS_LE32:
18516218822Sdim    case BFD_RELOC_ARM_TLS_IE32:
18517218822Sdim    case BFD_RELOC_ARM_TLS_LDM32:
18518218822Sdim    case BFD_RELOC_ARM_TLS_LDO32:
18519218822Sdim      S_SET_THREAD_LOCAL (fixP->fx_addsy);
18520218822Sdim      /* fall through */
18521218822Sdim
1852260484Sobrien    case BFD_RELOC_ARM_GOT32:
1852360484Sobrien    case BFD_RELOC_ARM_GOTOFF:
18524218822Sdim    case BFD_RELOC_ARM_TARGET2:
18525218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18526218822Sdim	md_number_to_chars (buf, 0, 4);
1852777298Sobrien      break;
1852860484Sobrien#endif
1852960484Sobrien
1853060484Sobrien    case BFD_RELOC_RVA:
1853160484Sobrien    case BFD_RELOC_32:
18532218822Sdim    case BFD_RELOC_ARM_TARGET1:
18533218822Sdim    case BFD_RELOC_ARM_ROSEGREL32:
18534218822Sdim    case BFD_RELOC_ARM_SBREL32:
18535218822Sdim    case BFD_RELOC_32_PCREL:
18536218822Sdim#ifdef TE_PE
18537218822Sdim    case BFD_RELOC_32_SECREL:
18538218822Sdim#endif
18539218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18540218822Sdim#ifdef TE_WINCE
18541218822Sdim	/* For WinCE we only do this for pcrel fixups.  */
18542218822Sdim	if (fixP->fx_done || fixP->fx_pcrel)
18543218822Sdim#endif
1854477298Sobrien	  md_number_to_chars (buf, value, 4);
1854560484Sobrien      break;
1854660484Sobrien
1854760484Sobrien#ifdef OBJ_ELF
18548218822Sdim    case BFD_RELOC_ARM_PREL31:
18549218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18550218822Sdim	{
18551218822Sdim	  newval = md_chars_to_number (buf, 4) & 0x80000000;
18552218822Sdim	  if ((value ^ (value >> 1)) & 0x40000000)
18553218822Sdim	    {
18554218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18555218822Sdim			    _("rel31 relocation overflow"));
18556218822Sdim	    }
18557218822Sdim	  newval |= value & 0x7fffffff;
18558218822Sdim	  md_number_to_chars (buf, newval, 4);
18559218822Sdim	}
1856060484Sobrien      break;
1856160484Sobrien#endif
1856260484Sobrien
1856360484Sobrien    case BFD_RELOC_ARM_CP_OFF_IMM:
18564218822Sdim    case BFD_RELOC_ARM_T32_CP_OFF_IMM:
1856560484Sobrien      if (value < -1023 || value > 1023 || (value & 3))
1856660484Sobrien	as_bad_where (fixP->fx_file, fixP->fx_line,
18567218822Sdim		      _("co-processor offset out of range"));
18568218822Sdim    cp_off_common:
18569218822Sdim      sign = value >= 0;
1857060484Sobrien      if (value < 0)
1857160484Sobrien	value = -value;
18572218822Sdim      if (fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM
18573218822Sdim	  || fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM_S2)
18574218822Sdim	newval = md_chars_to_number (buf, INSN_SIZE);
18575218822Sdim      else
18576218822Sdim	newval = get_thumb32_insn (buf);
18577218822Sdim      newval &= 0xff7fff00;
1857877298Sobrien      newval |= (value >> 2) | (sign ? INDEX_UP : 0);
18579218822Sdim      if (fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM
18580218822Sdim	  || fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM_S2)
18581218822Sdim	md_number_to_chars (buf, newval, INSN_SIZE);
18582218822Sdim      else
18583218822Sdim	put_thumb32_insn (buf, newval);
1858460484Sobrien      break;
1858560484Sobrien
18586130561Sobrien    case BFD_RELOC_ARM_CP_OFF_IMM_S2:
18587218822Sdim    case BFD_RELOC_ARM_T32_CP_OFF_IMM_S2:
18588130561Sobrien      if (value < -255 || value > 255)
18589218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18590218822Sdim		      _("co-processor offset out of range"));
18591218822Sdim      value *= 4;
18592218822Sdim      goto cp_off_common;
18593130561Sobrien
1859460484Sobrien    case BFD_RELOC_ARM_THUMB_OFFSET:
1859560484Sobrien      newval = md_chars_to_number (buf, THUMB_SIZE);
1859677298Sobrien      /* Exactly what ranges, and where the offset is inserted depends
1859777298Sobrien	 on the type of instruction, we can establish this from the
1859877298Sobrien	 top 4 bits.  */
1859960484Sobrien      switch (newval >> 12)
1860060484Sobrien	{
1860177298Sobrien	case 4: /* PC load.  */
1860260484Sobrien	  /* Thumb PC loads are somewhat odd, bit 1 of the PC is
18603218822Sdim	     forced to zero for these loads; md_pcrel_from has already
18604218822Sdim	     compensated for this.  */
18605218822Sdim	  if (value & 3)
1860660484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18607218822Sdim			  _("invalid offset, target not word aligned (0x%08lX)"),
18608218822Sdim			  (((unsigned long) fixP->fx_frag->fr_address
18609218822Sdim			    + (unsigned long) fixP->fx_where) & ~3)
18610218822Sdim			  + (unsigned long) value);
1861160484Sobrien
18612218822Sdim	  if (value & ~0x3fc)
1861360484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18614130561Sobrien			  _("invalid offset, value too big (0x%08lX)"),
18615130561Sobrien			  (long) value);
1861660484Sobrien
18617218822Sdim	  newval |= value >> 2;
1861860484Sobrien	  break;
1861960484Sobrien
1862077298Sobrien	case 9: /* SP load/store.  */
1862160484Sobrien	  if (value & ~0x3fc)
1862260484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18623130561Sobrien			  _("invalid offset, value too big (0x%08lX)"),
18624130561Sobrien			  (long) value);
1862560484Sobrien	  newval |= value >> 2;
1862660484Sobrien	  break;
1862760484Sobrien
1862877298Sobrien	case 6: /* Word load/store.  */
1862960484Sobrien	  if (value & ~0x7c)
1863060484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18631130561Sobrien			  _("invalid offset, value too big (0x%08lX)"),
18632130561Sobrien			  (long) value);
1863377298Sobrien	  newval |= value << 4; /* 6 - 2.  */
1863460484Sobrien	  break;
1863560484Sobrien
1863677298Sobrien	case 7: /* Byte load/store.  */
1863760484Sobrien	  if (value & ~0x1f)
1863860484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18639130561Sobrien			  _("invalid offset, value too big (0x%08lX)"),
18640130561Sobrien			  (long) value);
1864160484Sobrien	  newval |= value << 6;
1864260484Sobrien	  break;
1864360484Sobrien
18644218822Sdim	case 8: /* Halfword load/store.	 */
1864560484Sobrien	  if (value & ~0x3e)
1864660484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18647130561Sobrien			  _("invalid offset, value too big (0x%08lX)"),
18648130561Sobrien			  (long) value);
1864977298Sobrien	  newval |= value << 5; /* 6 - 1.  */
1865060484Sobrien	  break;
1865160484Sobrien
1865260484Sobrien	default:
1865360484Sobrien	  as_bad_where (fixP->fx_file, fixP->fx_line,
1865460484Sobrien			"Unable to process relocation for thumb opcode: %lx",
1865560484Sobrien			(unsigned long) newval);
1865660484Sobrien	  break;
1865760484Sobrien	}
1865860484Sobrien      md_number_to_chars (buf, newval, THUMB_SIZE);
1865960484Sobrien      break;
1866060484Sobrien
1866160484Sobrien    case BFD_RELOC_ARM_THUMB_ADD:
1866260484Sobrien      /* This is a complicated relocation, since we use it for all of
18663218822Sdim	 the following immediate relocations:
1866460484Sobrien
1866577298Sobrien	    3bit ADD/SUB
1866677298Sobrien	    8bit ADD/SUB
1866777298Sobrien	    9bit ADD/SUB SP word-aligned
1866877298Sobrien	   10bit ADD PC/SP word-aligned
1866977298Sobrien
18670218822Sdim	 The type of instruction being processed is encoded in the
18671218822Sdim	 instruction field:
1867277298Sobrien
1867377298Sobrien	   0x8000  SUB
1867477298Sobrien	   0x00F0  Rd
1867577298Sobrien	   0x000F  Rs
1867660484Sobrien      */
1867760484Sobrien      newval = md_chars_to_number (buf, THUMB_SIZE);
1867860484Sobrien      {
1867977298Sobrien	int rd = (newval >> 4) & 0xf;
1868077298Sobrien	int rs = newval & 0xf;
18681218822Sdim	int subtract = !!(newval & 0x8000);
1868260484Sobrien
18683218822Sdim	/* Check for HI regs, only very restricted cases allowed:
18684218822Sdim	   Adjusting SP, and using PC or SP to get an address.	*/
18685218822Sdim	if ((rd > 7 && (rd != REG_SP || rs != REG_SP))
18686218822Sdim	    || (rs > 7 && rs != REG_SP && rs != REG_PC))
18687218822Sdim	  as_bad_where (fixP->fx_file, fixP->fx_line,
18688218822Sdim			_("invalid Hi register with immediate"));
18689218822Sdim
18690218822Sdim	/* If value is negative, choose the opposite instruction.  */
18691218822Sdim	if (value < 0)
18692218822Sdim	  {
18693218822Sdim	    value = -value;
18694218822Sdim	    subtract = !subtract;
18695218822Sdim	    if (value < 0)
18696218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18697218822Sdim			    _("immediate value out of range"));
18698218822Sdim	  }
18699218822Sdim
1870077298Sobrien	if (rd == REG_SP)
1870177298Sobrien	  {
1870277298Sobrien	    if (value & ~0x1fc)
1870377298Sobrien	      as_bad_where (fixP->fx_file, fixP->fx_line,
1870489857Sobrien			    _("invalid immediate for stack address calculation"));
1870577298Sobrien	    newval = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
1870677298Sobrien	    newval |= value >> 2;
1870777298Sobrien	  }
1870877298Sobrien	else if (rs == REG_PC || rs == REG_SP)
1870977298Sobrien	  {
18710218822Sdim	    if (subtract || value & ~0x3fc)
1871177298Sobrien	      as_bad_where (fixP->fx_file, fixP->fx_line,
1871289857Sobrien			    _("invalid immediate for address calculation (value = 0x%08lX)"),
1871360484Sobrien			    (unsigned long) value);
1871477298Sobrien	    newval = (rs == REG_PC ? T_OPCODE_ADD_PC : T_OPCODE_ADD_SP);
1871577298Sobrien	    newval |= rd << 8;
1871677298Sobrien	    newval |= value >> 2;
1871777298Sobrien	  }
1871877298Sobrien	else if (rs == rd)
1871977298Sobrien	  {
1872077298Sobrien	    if (value & ~0xff)
1872177298Sobrien	      as_bad_where (fixP->fx_file, fixP->fx_line,
18722218822Sdim			    _("immediate value out of range"));
1872377298Sobrien	    newval = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8;
1872477298Sobrien	    newval |= (rd << 8) | value;
1872577298Sobrien	  }
1872677298Sobrien	else
1872777298Sobrien	  {
1872877298Sobrien	    if (value & ~0x7)
1872977298Sobrien	      as_bad_where (fixP->fx_file, fixP->fx_line,
18730218822Sdim			    _("immediate value out of range"));
1873177298Sobrien	    newval = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
1873277298Sobrien	    newval |= rd | (rs << 3) | (value << 6);
1873377298Sobrien	  }
1873460484Sobrien      }
1873577298Sobrien      md_number_to_chars (buf, newval, THUMB_SIZE);
1873660484Sobrien      break;
1873760484Sobrien
1873860484Sobrien    case BFD_RELOC_ARM_THUMB_IMM:
1873960484Sobrien      newval = md_chars_to_number (buf, THUMB_SIZE);
18740218822Sdim      if (value < 0 || value > 255)
18741218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18742218822Sdim		      _("invalid immediate: %ld is too large"),
18743218822Sdim		      (long) value);
18744218822Sdim      newval |= value;
1874577298Sobrien      md_number_to_chars (buf, newval, THUMB_SIZE);
1874660484Sobrien      break;
1874760484Sobrien
1874860484Sobrien    case BFD_RELOC_ARM_THUMB_SHIFT:
18749218822Sdim      /* 5bit shift value (0..32).  LSL cannot take 32.	 */
18750218822Sdim      newval = md_chars_to_number (buf, THUMB_SIZE) & 0xf83f;
18751218822Sdim      temp = newval & 0xf800;
18752218822Sdim      if (value < 0 || value > 32 || (value == 32 && temp == T_OPCODE_LSL_I))
1875360484Sobrien	as_bad_where (fixP->fx_file, fixP->fx_line,
18754218822Sdim		      _("invalid shift value: %ld"), (long) value);
18755218822Sdim      /* Shifts of zero must be encoded as LSL.	 */
18756218822Sdim      if (value == 0)
18757218822Sdim	newval = (newval & 0x003f) | T_OPCODE_LSL_I;
18758218822Sdim      /* Shifts of 32 are encoded as zero.  */
18759218822Sdim      else if (value == 32)
18760218822Sdim	value = 0;
1876160484Sobrien      newval |= value << 6;
1876277298Sobrien      md_number_to_chars (buf, newval, THUMB_SIZE);
1876360484Sobrien      break;
1876460484Sobrien
1876560484Sobrien    case BFD_RELOC_VTABLE_INHERIT:
1876660484Sobrien    case BFD_RELOC_VTABLE_ENTRY:
1876760484Sobrien      fixP->fx_done = 0;
1876889857Sobrien      return;
1876960484Sobrien
18770218822Sdim    case BFD_RELOC_ARM_MOVW:
18771218822Sdim    case BFD_RELOC_ARM_MOVT:
18772218822Sdim    case BFD_RELOC_ARM_THUMB_MOVW:
18773218822Sdim    case BFD_RELOC_ARM_THUMB_MOVT:
18774218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18775218822Sdim	{
18776218822Sdim	  /* REL format relocations are limited to a 16-bit addend.  */
18777218822Sdim	  if (!fixP->fx_done)
18778218822Sdim	    {
18779218822Sdim	      if (value < -0x1000 || value > 0xffff)
18780218822Sdim		  as_bad_where (fixP->fx_file, fixP->fx_line,
18781218822Sdim				_("offset too big"));
18782218822Sdim	    }
18783218822Sdim	  else if (fixP->fx_r_type == BFD_RELOC_ARM_MOVT
18784218822Sdim		   || fixP->fx_r_type == BFD_RELOC_ARM_THUMB_MOVT)
18785218822Sdim	    {
18786218822Sdim	      value >>= 16;
18787218822Sdim	    }
18788218822Sdim
18789218822Sdim	  if (fixP->fx_r_type == BFD_RELOC_ARM_THUMB_MOVW
18790218822Sdim	      || fixP->fx_r_type == BFD_RELOC_ARM_THUMB_MOVT)
18791218822Sdim	    {
18792218822Sdim	      newval = get_thumb32_insn (buf);
18793218822Sdim	      newval &= 0xfbf08f00;
18794218822Sdim	      newval |= (value & 0xf000) << 4;
18795218822Sdim	      newval |= (value & 0x0800) << 15;
18796218822Sdim	      newval |= (value & 0x0700) << 4;
18797218822Sdim	      newval |= (value & 0x00ff);
18798218822Sdim	      put_thumb32_insn (buf, newval);
18799218822Sdim	    }
18800218822Sdim	  else
18801218822Sdim	    {
18802218822Sdim	      newval = md_chars_to_number (buf, 4);
18803218822Sdim	      newval &= 0xfff0f000;
18804218822Sdim	      newval |= value & 0x0fff;
18805218822Sdim	      newval |= (value & 0xf000) << 4;
18806218822Sdim	      md_number_to_chars (buf, newval, 4);
18807218822Sdim	    }
18808218822Sdim	}
18809218822Sdim      return;
18810218822Sdim
18811218822Sdim   case BFD_RELOC_ARM_ALU_PC_G0_NC:
18812218822Sdim   case BFD_RELOC_ARM_ALU_PC_G0:
18813218822Sdim   case BFD_RELOC_ARM_ALU_PC_G1_NC:
18814218822Sdim   case BFD_RELOC_ARM_ALU_PC_G1:
18815218822Sdim   case BFD_RELOC_ARM_ALU_PC_G2:
18816218822Sdim   case BFD_RELOC_ARM_ALU_SB_G0_NC:
18817218822Sdim   case BFD_RELOC_ARM_ALU_SB_G0:
18818218822Sdim   case BFD_RELOC_ARM_ALU_SB_G1_NC:
18819218822Sdim   case BFD_RELOC_ARM_ALU_SB_G1:
18820218822Sdim   case BFD_RELOC_ARM_ALU_SB_G2:
18821218822Sdim     assert (!fixP->fx_done);
18822218822Sdim     if (!seg->use_rela_p)
18823218822Sdim       {
18824218822Sdim         bfd_vma insn;
18825218822Sdim         bfd_vma encoded_addend;
18826218822Sdim         bfd_vma addend_abs = abs (value);
18827218822Sdim
18828218822Sdim         /* Check that the absolute value of the addend can be
18829218822Sdim            expressed as an 8-bit constant plus a rotation.  */
18830218822Sdim         encoded_addend = encode_arm_immediate (addend_abs);
18831218822Sdim         if (encoded_addend == (unsigned int) FAIL)
18832218822Sdim	   as_bad_where (fixP->fx_file, fixP->fx_line,
18833218822Sdim	                 _("the offset 0x%08lX is not representable"),
18834218822Sdim                         (unsigned long) addend_abs);
18835218822Sdim
18836218822Sdim         /* Extract the instruction.  */
18837218822Sdim         insn = md_chars_to_number (buf, INSN_SIZE);
18838218822Sdim
18839218822Sdim         /* If the addend is positive, use an ADD instruction.
18840218822Sdim            Otherwise use a SUB.  Take care not to destroy the S bit.  */
18841218822Sdim         insn &= 0xff1fffff;
18842218822Sdim         if (value < 0)
18843218822Sdim           insn |= 1 << 22;
18844218822Sdim         else
18845218822Sdim           insn |= 1 << 23;
18846218822Sdim
18847218822Sdim         /* Place the encoded addend into the first 12 bits of the
18848218822Sdim            instruction.  */
18849218822Sdim         insn &= 0xfffff000;
18850218822Sdim         insn |= encoded_addend;
18851218822Sdim
18852218822Sdim         /* Update the instruction.  */
18853218822Sdim         md_number_to_chars (buf, insn, INSN_SIZE);
18854218822Sdim       }
18855218822Sdim     break;
18856218822Sdim
18857218822Sdim    case BFD_RELOC_ARM_LDR_PC_G0:
18858218822Sdim    case BFD_RELOC_ARM_LDR_PC_G1:
18859218822Sdim    case BFD_RELOC_ARM_LDR_PC_G2:
18860218822Sdim    case BFD_RELOC_ARM_LDR_SB_G0:
18861218822Sdim    case BFD_RELOC_ARM_LDR_SB_G1:
18862218822Sdim    case BFD_RELOC_ARM_LDR_SB_G2:
18863218822Sdim      assert (!fixP->fx_done);
18864218822Sdim      if (!seg->use_rela_p)
18865218822Sdim        {
18866218822Sdim          bfd_vma insn;
18867218822Sdim          bfd_vma addend_abs = abs (value);
18868218822Sdim
18869218822Sdim          /* Check that the absolute value of the addend can be
18870218822Sdim             encoded in 12 bits.  */
18871218822Sdim          if (addend_abs >= 0x1000)
18872218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
18873218822Sdim	  	          _("bad offset 0x%08lX (only 12 bits available for the magnitude)"),
18874218822Sdim                          (unsigned long) addend_abs);
18875218822Sdim
18876218822Sdim          /* Extract the instruction.  */
18877218822Sdim          insn = md_chars_to_number (buf, INSN_SIZE);
18878218822Sdim
18879218822Sdim          /* If the addend is negative, clear bit 23 of the instruction.
18880218822Sdim             Otherwise set it.  */
18881218822Sdim          if (value < 0)
18882218822Sdim            insn &= ~(1 << 23);
18883218822Sdim          else
18884218822Sdim            insn |= 1 << 23;
18885218822Sdim
18886218822Sdim          /* Place the absolute value of the addend into the first 12 bits
18887218822Sdim             of the instruction.  */
18888218822Sdim          insn &= 0xfffff000;
18889218822Sdim          insn |= addend_abs;
18890218822Sdim
18891218822Sdim          /* Update the instruction.  */
18892218822Sdim          md_number_to_chars (buf, insn, INSN_SIZE);
18893218822Sdim        }
18894218822Sdim      break;
18895218822Sdim
18896218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G0:
18897218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G1:
18898218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G2:
18899218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G0:
18900218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G1:
18901218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G2:
18902218822Sdim      assert (!fixP->fx_done);
18903218822Sdim      if (!seg->use_rela_p)
18904218822Sdim        {
18905218822Sdim          bfd_vma insn;
18906218822Sdim          bfd_vma addend_abs = abs (value);
18907218822Sdim
18908218822Sdim          /* Check that the absolute value of the addend can be
18909218822Sdim             encoded in 8 bits.  */
18910218822Sdim          if (addend_abs >= 0x100)
18911218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
18912218822Sdim	  	          _("bad offset 0x%08lX (only 8 bits available for the magnitude)"),
18913218822Sdim                          (unsigned long) addend_abs);
18914218822Sdim
18915218822Sdim          /* Extract the instruction.  */
18916218822Sdim          insn = md_chars_to_number (buf, INSN_SIZE);
18917218822Sdim
18918218822Sdim          /* If the addend is negative, clear bit 23 of the instruction.
18919218822Sdim             Otherwise set it.  */
18920218822Sdim          if (value < 0)
18921218822Sdim            insn &= ~(1 << 23);
18922218822Sdim          else
18923218822Sdim            insn |= 1 << 23;
18924218822Sdim
18925218822Sdim          /* Place the first four bits of the absolute value of the addend
18926218822Sdim             into the first 4 bits of the instruction, and the remaining
18927218822Sdim             four into bits 8 .. 11.  */
18928218822Sdim          insn &= 0xfffff0f0;
18929218822Sdim          insn |= (addend_abs & 0xf) | ((addend_abs & 0xf0) << 4);
18930218822Sdim
18931218822Sdim          /* Update the instruction.  */
18932218822Sdim          md_number_to_chars (buf, insn, INSN_SIZE);
18933218822Sdim        }
18934218822Sdim      break;
18935218822Sdim
18936218822Sdim    case BFD_RELOC_ARM_LDC_PC_G0:
18937218822Sdim    case BFD_RELOC_ARM_LDC_PC_G1:
18938218822Sdim    case BFD_RELOC_ARM_LDC_PC_G2:
18939218822Sdim    case BFD_RELOC_ARM_LDC_SB_G0:
18940218822Sdim    case BFD_RELOC_ARM_LDC_SB_G1:
18941218822Sdim    case BFD_RELOC_ARM_LDC_SB_G2:
18942218822Sdim      assert (!fixP->fx_done);
18943218822Sdim      if (!seg->use_rela_p)
18944218822Sdim        {
18945218822Sdim          bfd_vma insn;
18946218822Sdim          bfd_vma addend_abs = abs (value);
18947218822Sdim
18948218822Sdim          /* Check that the absolute value of the addend is a multiple of
18949218822Sdim             four and, when divided by four, fits in 8 bits.  */
18950218822Sdim          if (addend_abs & 0x3)
18951218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
18952218822Sdim	  	          _("bad offset 0x%08lX (must be word-aligned)"),
18953218822Sdim                          (unsigned long) addend_abs);
18954218822Sdim
18955218822Sdim          if ((addend_abs >> 2) > 0xff)
18956218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
18957218822Sdim	  	          _("bad offset 0x%08lX (must be an 8-bit number of words)"),
18958218822Sdim                          (unsigned long) addend_abs);
18959218822Sdim
18960218822Sdim          /* Extract the instruction.  */
18961218822Sdim          insn = md_chars_to_number (buf, INSN_SIZE);
18962218822Sdim
18963218822Sdim          /* If the addend is negative, clear bit 23 of the instruction.
18964218822Sdim             Otherwise set it.  */
18965218822Sdim          if (value < 0)
18966218822Sdim            insn &= ~(1 << 23);
18967218822Sdim          else
18968218822Sdim            insn |= 1 << 23;
18969218822Sdim
18970218822Sdim          /* Place the addend (divided by four) into the first eight
18971218822Sdim             bits of the instruction.  */
18972218822Sdim          insn &= 0xfffffff0;
18973218822Sdim          insn |= addend_abs >> 2;
18974218822Sdim
18975218822Sdim          /* Update the instruction.  */
18976218822Sdim          md_number_to_chars (buf, insn, INSN_SIZE);
18977218822Sdim        }
18978218822Sdim      break;
18979218822Sdim
18980218822Sdim    case BFD_RELOC_UNUSED:
1898160484Sobrien    default:
1898260484Sobrien      as_bad_where (fixP->fx_file, fixP->fx_line,
1898389857Sobrien		    _("bad relocation fixup type (%d)"), fixP->fx_r_type);
1898460484Sobrien    }
1898560484Sobrien}
1898660484Sobrien
1898760484Sobrien/* Translate internal representation of relocation info to BFD target
1898860484Sobrien   format.  */
1898977298Sobrien
1899060484Sobrienarelent *
18991218822Sdimtc_gen_reloc (asection *section, fixS *fixp)
1899260484Sobrien{
1899360484Sobrien  arelent * reloc;
1899460484Sobrien  bfd_reloc_code_real_type code;
1899560484Sobrien
18996218822Sdim  reloc = xmalloc (sizeof (arelent));
1899760484Sobrien
18998218822Sdim  reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
1899960484Sobrien  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
1900060484Sobrien  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
1900160484Sobrien
19002218822Sdim  if (fixp->fx_pcrel)
19003218822Sdim    {
19004218822Sdim      if (section->use_rela_p)
19005218822Sdim	fixp->fx_offset -= md_pcrel_from_section (fixp, section);
19006218822Sdim      else
19007218822Sdim	fixp->fx_offset = reloc->address;
19008218822Sdim    }
1900960484Sobrien  reloc->addend = fixp->fx_offset;
1901060484Sobrien
1901160484Sobrien  switch (fixp->fx_r_type)
1901260484Sobrien    {
1901360484Sobrien    case BFD_RELOC_8:
1901460484Sobrien      if (fixp->fx_pcrel)
1901560484Sobrien	{
1901660484Sobrien	  code = BFD_RELOC_8_PCREL;
1901760484Sobrien	  break;
1901860484Sobrien	}
1901960484Sobrien
1902060484Sobrien    case BFD_RELOC_16:
1902160484Sobrien      if (fixp->fx_pcrel)
1902260484Sobrien	{
1902360484Sobrien	  code = BFD_RELOC_16_PCREL;
1902460484Sobrien	  break;
1902560484Sobrien	}
1902660484Sobrien
1902760484Sobrien    case BFD_RELOC_32:
1902860484Sobrien      if (fixp->fx_pcrel)
1902960484Sobrien	{
1903060484Sobrien	  code = BFD_RELOC_32_PCREL;
1903160484Sobrien	  break;
1903260484Sobrien	}
1903360484Sobrien
19034218822Sdim    case BFD_RELOC_ARM_MOVW:
19035218822Sdim      if (fixp->fx_pcrel)
19036218822Sdim	{
19037218822Sdim	  code = BFD_RELOC_ARM_MOVW_PCREL;
19038218822Sdim	  break;
19039218822Sdim	}
19040218822Sdim
19041218822Sdim    case BFD_RELOC_ARM_MOVT:
19042218822Sdim      if (fixp->fx_pcrel)
19043218822Sdim	{
19044218822Sdim	  code = BFD_RELOC_ARM_MOVT_PCREL;
19045218822Sdim	  break;
19046218822Sdim	}
19047218822Sdim
19048218822Sdim    case BFD_RELOC_ARM_THUMB_MOVW:
19049218822Sdim      if (fixp->fx_pcrel)
19050218822Sdim	{
19051218822Sdim	  code = BFD_RELOC_ARM_THUMB_MOVW_PCREL;
19052218822Sdim	  break;
19053218822Sdim	}
19054218822Sdim
19055218822Sdim    case BFD_RELOC_ARM_THUMB_MOVT:
19056218822Sdim      if (fixp->fx_pcrel)
19057218822Sdim	{
19058218822Sdim	  code = BFD_RELOC_ARM_THUMB_MOVT_PCREL;
19059218822Sdim	  break;
19060218822Sdim	}
19061218822Sdim
19062218822Sdim    case BFD_RELOC_NONE:
1906360484Sobrien    case BFD_RELOC_ARM_PCREL_BRANCH:
1906477298Sobrien    case BFD_RELOC_ARM_PCREL_BLX:
1906577298Sobrien    case BFD_RELOC_RVA:
19066218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH7:
1906760484Sobrien    case BFD_RELOC_THUMB_PCREL_BRANCH9:
1906860484Sobrien    case BFD_RELOC_THUMB_PCREL_BRANCH12:
19069218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH20:
1907060484Sobrien    case BFD_RELOC_THUMB_PCREL_BRANCH23:
19071218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH25:
1907277298Sobrien    case BFD_RELOC_THUMB_PCREL_BLX:
1907360484Sobrien    case BFD_RELOC_VTABLE_ENTRY:
1907460484Sobrien    case BFD_RELOC_VTABLE_INHERIT:
19075218822Sdim#ifdef TE_PE
19076218822Sdim    case BFD_RELOC_32_SECREL:
19077218822Sdim#endif
1907860484Sobrien      code = fixp->fx_r_type;
1907960484Sobrien      break;
1908060484Sobrien
1908160484Sobrien    case BFD_RELOC_ARM_LITERAL:
1908260484Sobrien    case BFD_RELOC_ARM_HWLITERAL:
19083130561Sobrien      /* If this is called then the a literal has
19084130561Sobrien	 been referenced across a section boundary.  */
1908560484Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
19086130561Sobrien		    _("literal referenced across section boundary"));
1908760484Sobrien      return NULL;
1908860484Sobrien
1908960484Sobrien#ifdef OBJ_ELF
1909060484Sobrien    case BFD_RELOC_ARM_GOT32:
1909160484Sobrien    case BFD_RELOC_ARM_GOTOFF:
1909260484Sobrien    case BFD_RELOC_ARM_PLT32:
19093218822Sdim    case BFD_RELOC_ARM_TARGET1:
19094218822Sdim    case BFD_RELOC_ARM_ROSEGREL32:
19095218822Sdim    case BFD_RELOC_ARM_SBREL32:
19096218822Sdim    case BFD_RELOC_ARM_PREL31:
19097218822Sdim    case BFD_RELOC_ARM_TARGET2:
19098218822Sdim    case BFD_RELOC_ARM_TLS_LE32:
19099218822Sdim    case BFD_RELOC_ARM_TLS_LDO32:
19100218822Sdim    case BFD_RELOC_ARM_PCREL_CALL:
19101218822Sdim    case BFD_RELOC_ARM_PCREL_JUMP:
19102218822Sdim    case BFD_RELOC_ARM_ALU_PC_G0_NC:
19103218822Sdim    case BFD_RELOC_ARM_ALU_PC_G0:
19104218822Sdim    case BFD_RELOC_ARM_ALU_PC_G1_NC:
19105218822Sdim    case BFD_RELOC_ARM_ALU_PC_G1:
19106218822Sdim    case BFD_RELOC_ARM_ALU_PC_G2:
19107218822Sdim    case BFD_RELOC_ARM_LDR_PC_G0:
19108218822Sdim    case BFD_RELOC_ARM_LDR_PC_G1:
19109218822Sdim    case BFD_RELOC_ARM_LDR_PC_G2:
19110218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G0:
19111218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G1:
19112218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G2:
19113218822Sdim    case BFD_RELOC_ARM_LDC_PC_G0:
19114218822Sdim    case BFD_RELOC_ARM_LDC_PC_G1:
19115218822Sdim    case BFD_RELOC_ARM_LDC_PC_G2:
19116218822Sdim    case BFD_RELOC_ARM_ALU_SB_G0_NC:
19117218822Sdim    case BFD_RELOC_ARM_ALU_SB_G0:
19118218822Sdim    case BFD_RELOC_ARM_ALU_SB_G1_NC:
19119218822Sdim    case BFD_RELOC_ARM_ALU_SB_G1:
19120218822Sdim    case BFD_RELOC_ARM_ALU_SB_G2:
19121218822Sdim    case BFD_RELOC_ARM_LDR_SB_G0:
19122218822Sdim    case BFD_RELOC_ARM_LDR_SB_G1:
19123218822Sdim    case BFD_RELOC_ARM_LDR_SB_G2:
19124218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G0:
19125218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G1:
19126218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G2:
19127218822Sdim    case BFD_RELOC_ARM_LDC_SB_G0:
19128218822Sdim    case BFD_RELOC_ARM_LDC_SB_G1:
19129218822Sdim    case BFD_RELOC_ARM_LDC_SB_G2:
1913077298Sobrien      code = fixp->fx_r_type;
1913177298Sobrien      break;
19132218822Sdim
19133218822Sdim    case BFD_RELOC_ARM_TLS_GD32:
19134218822Sdim    case BFD_RELOC_ARM_TLS_IE32:
19135218822Sdim    case BFD_RELOC_ARM_TLS_LDM32:
19136218822Sdim      /* BFD will include the symbol's address in the addend.
19137218822Sdim	 But we don't want that, so subtract it out again here.  */
19138218822Sdim      if (!S_IS_COMMON (fixp->fx_addsy))
19139218822Sdim	reloc->addend -= (*reloc->sym_ptr_ptr)->value;
19140218822Sdim      code = fixp->fx_r_type;
19141218822Sdim      break;
1914260484Sobrien#endif
1914360484Sobrien
1914460484Sobrien    case BFD_RELOC_ARM_IMMEDIATE:
1914560484Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
19146130561Sobrien		    _("internal relocation (type: IMMEDIATE) not fixed up"));
1914760484Sobrien      return NULL;
1914860484Sobrien
1914960484Sobrien    case BFD_RELOC_ARM_ADRL_IMMEDIATE:
1915060484Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
1915177298Sobrien		    _("ADRL used for a symbol not defined in the same file"));
1915260484Sobrien      return NULL;
1915360484Sobrien
1915460484Sobrien    case BFD_RELOC_ARM_OFFSET_IMM:
19155218822Sdim      if (section->use_rela_p)
19156218822Sdim	{
19157218822Sdim	  code = fixp->fx_r_type;
19158218822Sdim	  break;
19159218822Sdim	}
19160218822Sdim
19161130561Sobrien      if (fixp->fx_addsy != NULL
19162130561Sobrien	  && !S_IS_DEFINED (fixp->fx_addsy)
19163130561Sobrien	  && S_IS_LOCAL (fixp->fx_addsy))
19164130561Sobrien	{
19165130561Sobrien	  as_bad_where (fixp->fx_file, fixp->fx_line,
19166130561Sobrien			_("undefined local label `%s'"),
19167130561Sobrien			S_GET_NAME (fixp->fx_addsy));
19168130561Sobrien	  return NULL;
19169130561Sobrien	}
19170130561Sobrien
1917160484Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
19172130561Sobrien		    _("internal_relocation (type: OFFSET_IMM) not fixed up"));
1917360484Sobrien      return NULL;
1917460484Sobrien
1917560484Sobrien    default:
1917660484Sobrien      {
1917760484Sobrien	char * type;
1917877298Sobrien
1917960484Sobrien	switch (fixp->fx_r_type)
1918060484Sobrien	  {
19181218822Sdim	  case BFD_RELOC_NONE:		   type = "NONE";	  break;
1918260484Sobrien	  case BFD_RELOC_ARM_OFFSET_IMM8:  type = "OFFSET_IMM8";  break;
19183218822Sdim	  case BFD_RELOC_ARM_SHIFT_IMM:	   type = "SHIFT_IMM";	  break;
19184218822Sdim	  case BFD_RELOC_ARM_SMC:	   type = "SMC";	  break;
19185218822Sdim	  case BFD_RELOC_ARM_SWI:	   type = "SWI";	  break;
19186218822Sdim	  case BFD_RELOC_ARM_MULTI:	   type = "MULTI";	  break;
19187218822Sdim	  case BFD_RELOC_ARM_CP_OFF_IMM:   type = "CP_OFF_IMM";	  break;
19188218822Sdim	  case BFD_RELOC_ARM_T32_CP_OFF_IMM: type = "T32_CP_OFF_IMM"; break;
19189218822Sdim	  case BFD_RELOC_ARM_THUMB_ADD:	   type = "THUMB_ADD";	  break;
1919060484Sobrien	  case BFD_RELOC_ARM_THUMB_SHIFT:  type = "THUMB_SHIFT";  break;
19191218822Sdim	  case BFD_RELOC_ARM_THUMB_IMM:	   type = "THUMB_IMM";	  break;
1919260484Sobrien	  case BFD_RELOC_ARM_THUMB_OFFSET: type = "THUMB_OFFSET"; break;
19193218822Sdim	  default:			   type = _("<unknown>"); break;
1919460484Sobrien	  }
1919560484Sobrien	as_bad_where (fixp->fx_file, fixp->fx_line,
1919689857Sobrien		      _("cannot represent %s relocation in this object file format"),
1919777298Sobrien		      type);
1919860484Sobrien	return NULL;
1919960484Sobrien      }
1920060484Sobrien    }
1920160484Sobrien
1920260484Sobrien#ifdef OBJ_ELF
19203130561Sobrien  if ((code == BFD_RELOC_32_PCREL || code == BFD_RELOC_32)
1920477298Sobrien      && GOT_symbol
1920577298Sobrien      && fixp->fx_addsy == GOT_symbol)
1920677298Sobrien    {
1920777298Sobrien      code = BFD_RELOC_ARM_GOTPC;
1920877298Sobrien      reloc->addend = fixp->fx_offset = reloc->address;
1920977298Sobrien    }
1921060484Sobrien#endif
1921177298Sobrien
1921260484Sobrien  reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
1921360484Sobrien
1921460484Sobrien  if (reloc->howto == NULL)
1921560484Sobrien    {
1921660484Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
1921789857Sobrien		    _("cannot represent %s relocation in this object file format"),
1921860484Sobrien		    bfd_get_reloc_code_name (code));
1921960484Sobrien      return NULL;
1922060484Sobrien    }
1922160484Sobrien
1922277298Sobrien  /* HACK: Since arm ELF uses Rel instead of Rela, encode the
1922377298Sobrien     vtable entry to be used in the relocation's section offset.  */
1922477298Sobrien  if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
1922577298Sobrien    reloc->address = fixp->fx_offset;
1922660484Sobrien
1922760484Sobrien  return reloc;
1922860484Sobrien}
1922960484Sobrien
19230218822Sdim/* This fix_new is called by cons via TC_CONS_FIX_NEW.	*/
1923160484Sobrien
19232218822Sdimvoid
19233218822Sdimcons_fix_new_arm (fragS *	frag,
19234218822Sdim		  int		where,
19235218822Sdim		  int		size,
19236218822Sdim		  expressionS * exp)
1923760484Sobrien{
19238218822Sdim  bfd_reloc_code_real_type type;
19239218822Sdim  int pcrel = 0;
1924077298Sobrien
19241218822Sdim  /* Pick a reloc.
19242218822Sdim     FIXME: @@ Should look at CPU word size.  */
19243218822Sdim  switch (size)
1924460484Sobrien    {
19245218822Sdim    case 1:
19246218822Sdim      type = BFD_RELOC_8;
19247218822Sdim      break;
19248218822Sdim    case 2:
19249218822Sdim      type = BFD_RELOC_16;
19250218822Sdim      break;
19251218822Sdim    case 4:
19252218822Sdim    default:
19253218822Sdim      type = BFD_RELOC_32;
19254218822Sdim      break;
19255218822Sdim    case 8:
19256218822Sdim      type = BFD_RELOC_64;
19257218822Sdim      break;
1925860484Sobrien    }
1925960484Sobrien
19260218822Sdim#ifdef TE_PE
19261218822Sdim  if (exp->X_op == O_secrel)
19262218822Sdim  {
19263218822Sdim    exp->X_op = O_symbol;
19264218822Sdim    type = BFD_RELOC_32_SECREL;
19265218822Sdim  }
19266218822Sdim#endif
1926777298Sobrien
19268218822Sdim  fix_new_exp (frag, where, (int) size, exp, pcrel, type);
19269218822Sdim}
19270218822Sdim
19271218822Sdim#if defined OBJ_COFF || defined OBJ_ELF
19272218822Sdimvoid
19273218822Sdimarm_validate_fix (fixS * fixP)
19274218822Sdim{
19275218822Sdim  /* If the destination of the branch is a defined symbol which does not have
19276218822Sdim     the THUMB_FUNC attribute, then we must be calling a function which has
19277218822Sdim     the (interfacearm) attribute.  We look for the Thumb entry point to that
19278218822Sdim     function and change the branch to refer to that function instead.	*/
19279218822Sdim  if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23
19280218822Sdim      && fixP->fx_addsy != NULL
19281218822Sdim      && S_IS_DEFINED (fixP->fx_addsy)
19282218822Sdim      && ! THUMB_IS_FUNC (fixP->fx_addsy))
1928360484Sobrien    {
19284218822Sdim      fixP->fx_addsy = find_real_start (fixP->fx_addsy);
1928560484Sobrien    }
19286218822Sdim}
19287218822Sdim#endif
1928860484Sobrien
19289218822Sdimint
19290218822Sdimarm_force_relocation (struct fix * fixp)
19291218822Sdim{
19292218822Sdim#if defined (OBJ_COFF) && defined (TE_PE)
19293218822Sdim  if (fixp->fx_r_type == BFD_RELOC_RVA)
19294218822Sdim    return 1;
19295218822Sdim#endif
1929660484Sobrien
19297218822Sdim  /* Resolve these relocations even if the symbol is extern or weak.  */
19298218822Sdim  if (fixp->fx_r_type == BFD_RELOC_ARM_IMMEDIATE
19299218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_OFFSET_IMM
19300218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE
19301218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM
19302218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_T32_IMMEDIATE
19303218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_T32_IMM12
19304218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_T32_ADD_PC12)
19305218822Sdim    return 0;
19306218822Sdim
19307218822Sdim  /* Always leave these relocations for the linker.  */
19308218822Sdim  if ((fixp->fx_r_type >= BFD_RELOC_ARM_ALU_PC_G0_NC
19309218822Sdim       && fixp->fx_r_type <= BFD_RELOC_ARM_LDC_SB_G2)
19310218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_LDR_PC_G0)
19311218822Sdim    return 1;
19312218822Sdim
19313218822Sdim  /* Always generate relocations against function symbols.  */
19314218822Sdim  if (fixp->fx_r_type == BFD_RELOC_32
19315218822Sdim      && fixp->fx_addsy
19316218822Sdim      && (symbol_get_bfdsym (fixp->fx_addsy)->flags & BSF_FUNCTION))
19317218822Sdim    return 1;
19318218822Sdim
19319218822Sdim  return generic_force_reloc (fixp);
19320218822Sdim}
19321218822Sdim
19322218822Sdim#if defined (OBJ_ELF) || defined (OBJ_COFF)
19323218822Sdim/* Relocations against function names must be left unadjusted,
19324218822Sdim   so that the linker can use this information to generate interworking
19325218822Sdim   stubs.  The MIPS version of this function
19326218822Sdim   also prevents relocations that are mips-16 specific, but I do not
19327218822Sdim   know why it does this.
19328218822Sdim
19329218822Sdim   FIXME:
19330218822Sdim   There is one other problem that ought to be addressed here, but
19331218822Sdim   which currently is not:  Taking the address of a label (rather
19332218822Sdim   than a function) and then later jumping to that address.  Such
19333218822Sdim   addresses also ought to have their bottom bit set (assuming that
19334218822Sdim   they reside in Thumb code), but at the moment they will not.	 */
19335218822Sdim
19336218822Sdimbfd_boolean
19337218822Sdimarm_fix_adjustable (fixS * fixP)
19338218822Sdim{
19339218822Sdim  if (fixP->fx_addsy == NULL)
19340218822Sdim    return 1;
19341218822Sdim
19342218822Sdim  /* Preserve relocations against symbols with function type.  */
19343218822Sdim  if (symbol_get_bfdsym (fixP->fx_addsy)->flags & BSF_FUNCTION)
19344218822Sdim    return 0;
19345218822Sdim
19346218822Sdim  if (THUMB_IS_FUNC (fixP->fx_addsy)
19347218822Sdim      && fixP->fx_subsy == NULL)
19348218822Sdim    return 0;
19349218822Sdim
19350218822Sdim  /* We need the symbol name for the VTABLE entries.  */
19351218822Sdim  if (	 fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
19352218822Sdim      || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
19353218822Sdim    return 0;
19354218822Sdim
19355218822Sdim  /* Don't allow symbols to be discarded on GOT related relocs.	 */
19356218822Sdim  if (fixP->fx_r_type == BFD_RELOC_ARM_PLT32
19357218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_GOT32
19358218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_GOTOFF
19359218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_GD32
19360218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LE32
19361218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_IE32
19362218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDM32
19363218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDO32
19364218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TARGET2)
19365218822Sdim    return 0;
19366218822Sdim
19367218822Sdim  /* Similarly for group relocations.  */
19368218822Sdim  if ((fixP->fx_r_type >= BFD_RELOC_ARM_ALU_PC_G0_NC
19369218822Sdim       && fixP->fx_r_type <= BFD_RELOC_ARM_LDC_SB_G2)
19370218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_LDR_PC_G0)
19371218822Sdim    return 0;
19372218822Sdim
19373218822Sdim  return 1;
19374218822Sdim}
19375218822Sdim#endif /* defined (OBJ_ELF) || defined (OBJ_COFF) */
19376218822Sdim
1937777298Sobrien#ifdef OBJ_ELF
19378218822Sdim
19379218822Sdimconst char *
19380218822Sdimelf32_arm_target_format (void)
19381218822Sdim{
19382218822Sdim#ifdef TE_SYMBIAN
19383218822Sdim  return (target_big_endian
19384218822Sdim	  ? "elf32-bigarm-symbian"
19385218822Sdim	  : "elf32-littlearm-symbian");
19386218822Sdim#elif defined (TE_VXWORKS)
19387218822Sdim  return (target_big_endian
19388218822Sdim	  ? "elf32-bigarm-vxworks"
19389218822Sdim	  : "elf32-littlearm-vxworks");
19390218822Sdim#else
19391218822Sdim  if (target_big_endian)
19392218822Sdim    return "elf32-bigarm";
19393218822Sdim  else
19394218822Sdim    return "elf32-littlearm";
1939577298Sobrien#endif
1939660484Sobrien}
1939760484Sobrien
1939860484Sobrienvoid
19399218822Sdimarmelf_frob_symbol (symbolS * symp,
19400218822Sdim		    int *     puntp)
1940160484Sobrien{
19402218822Sdim  elf_frob_symbol (symp, puntp);
19403218822Sdim}
1940477298Sobrien#endif
1940560484Sobrien
19406218822Sdim/* MD interface: Finalization.	*/
1940760484Sobrien
19408218822Sdim/* A good place to do this, although this was probably not intended
19409218822Sdim   for this kind of use.  We need to dump the literal pool before
19410218822Sdim   references are made to a null symbol pointer.  */
1941160484Sobrien
19412218822Sdimvoid
19413218822Sdimarm_cleanup (void)
19414218822Sdim{
19415218822Sdim  literal_pool * pool;
1941677298Sobrien
19417218822Sdim  for (pool = list_of_pools; pool; pool = pool->next)
1941860484Sobrien    {
19419218822Sdim      /* Put it at the end of the relevent section.  */
19420218822Sdim      subseg_set (pool->section, pool->sub_section);
19421218822Sdim#ifdef OBJ_ELF
19422218822Sdim      arm_elf_change_section ();
19423218822Sdim#endif
19424218822Sdim      s_ltorg (0);
1942560484Sobrien    }
19426218822Sdim}
1942760484Sobrien
19428218822Sdim/* Adjust the symbol table.  This marks Thumb symbols as distinct from
19429218822Sdim   ARM ones.  */
1943060484Sobrien
19431218822Sdimvoid
19432218822Sdimarm_adjust_symtab (void)
19433218822Sdim{
19434218822Sdim#ifdef OBJ_COFF
19435218822Sdim  symbolS * sym;
1943677298Sobrien
19437218822Sdim  for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
19438218822Sdim    {
19439218822Sdim      if (ARM_IS_THUMB (sym))
1944060484Sobrien	{
19441218822Sdim	  if (THUMB_IS_FUNC (sym))
1944277298Sobrien	    {
19443218822Sdim	      /* Mark the symbol as a Thumb function.  */
19444218822Sdim	      if (   S_GET_STORAGE_CLASS (sym) == C_STAT
19445218822Sdim		  || S_GET_STORAGE_CLASS (sym) == C_LABEL)  /* This can happen!	 */
19446218822Sdim		S_SET_STORAGE_CLASS (sym, C_THUMBSTATFUNC);
19447218822Sdim
19448218822Sdim	      else if (S_GET_STORAGE_CLASS (sym) == C_EXT)
19449218822Sdim		S_SET_STORAGE_CLASS (sym, C_THUMBEXTFUNC);
19450218822Sdim	      else
19451218822Sdim		as_bad (_("%s: unexpected function type: %d"),
19452218822Sdim			S_GET_NAME (sym), S_GET_STORAGE_CLASS (sym));
1945377298Sobrien	    }
19454218822Sdim	  else switch (S_GET_STORAGE_CLASS (sym))
19455218822Sdim	    {
19456218822Sdim	    case C_EXT:
19457218822Sdim	      S_SET_STORAGE_CLASS (sym, C_THUMBEXT);
19458218822Sdim	      break;
19459218822Sdim	    case C_STAT:
19460218822Sdim	      S_SET_STORAGE_CLASS (sym, C_THUMBSTAT);
19461218822Sdim	      break;
19462218822Sdim	    case C_LABEL:
19463218822Sdim	      S_SET_STORAGE_CLASS (sym, C_THUMBLABEL);
19464218822Sdim	      break;
19465218822Sdim	    default:
19466218822Sdim	      /* Do nothing.  */
19467218822Sdim	      break;
19468218822Sdim	    }
19469218822Sdim	}
1947060484Sobrien
19471218822Sdim      if (ARM_IS_INTERWORK (sym))
19472218822Sdim	coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_flags = 0xFF;
1947360484Sobrien    }
19474218822Sdim#endif
19475218822Sdim#ifdef OBJ_ELF
19476218822Sdim  symbolS * sym;
19477218822Sdim  char	    bind;
19478218822Sdim
19479218822Sdim  for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
1948060484Sobrien    {
19481218822Sdim      if (ARM_IS_THUMB (sym))
19482218822Sdim	{
19483218822Sdim	  elf_symbol_type * elf_sym;
1948460484Sobrien
19485218822Sdim	  elf_sym = elf_symbol (symbol_get_bfdsym (sym));
19486218822Sdim	  bind = ELF_ST_BIND (elf_sym->internal_elf_sym.st_info);
1948777298Sobrien
19488218822Sdim	  if (! bfd_is_arm_special_symbol_name (elf_sym->symbol.name,
19489218822Sdim		BFD_ARM_SPECIAL_SYM_TYPE_ANY))
1949060484Sobrien	    {
19491218822Sdim	      /* If it's a .thumb_func, declare it as so,
19492218822Sdim		 otherwise tag label as .code 16.  */
19493218822Sdim	      if (THUMB_IS_FUNC (sym))
19494218822Sdim		elf_sym->internal_elf_sym.st_info =
19495218822Sdim		  ELF_ST_INFO (bind, STT_ARM_TFUNC);
19496218822Sdim	      else if (EF_ARM_EABI_VERSION (meabi_flags) < EF_ARM_EABI_VER4)
19497218822Sdim		elf_sym->internal_elf_sym.st_info =
19498218822Sdim		  ELF_ST_INFO (bind, STT_ARM_16BIT);
1949960484Sobrien	    }
1950060484Sobrien	}
1950160484Sobrien    }
19502218822Sdim#endif
19503218822Sdim}
1950460484Sobrien
19505218822Sdim/* MD interface: Initialization.  */
1950660484Sobrien
19507218822Sdimstatic void
19508218822Sdimset_constant_flonums (void)
19509218822Sdim{
19510218822Sdim  int i;
19511218822Sdim
19512218822Sdim  for (i = 0; i < NUM_FLOAT_VALS; i++)
19513218822Sdim    if (atof_ieee ((char *) fp_const[i], 'x', fp_values[i]) == NULL)
19514218822Sdim      abort ();
1951589857Sobrien}
1951677298Sobrien
19517218822Sdim/* Auto-select Thumb mode if it's the only available instruction set for the
19518218822Sdim   given architecture.  */
19519218822Sdim
19520218822Sdimstatic void
19521218822Sdimautoselect_thumb_from_cpu_variant (void)
19522218822Sdim{
19523218822Sdim  if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1))
19524218822Sdim    opcode_select (16);
19525218822Sdim}
19526218822Sdim
19527218822Sdimvoid
19528218822Sdimmd_begin (void)
19529218822Sdim{
19530218822Sdim  unsigned mach;
19531218822Sdim  unsigned int i;
19532218822Sdim
19533218822Sdim  if (	 (arm_ops_hsh = hash_new ()) == NULL
19534218822Sdim      || (arm_cond_hsh = hash_new ()) == NULL
19535218822Sdim      || (arm_shift_hsh = hash_new ()) == NULL
19536218822Sdim      || (arm_psr_hsh = hash_new ()) == NULL
19537218822Sdim      || (arm_v7m_psr_hsh = hash_new ()) == NULL
19538218822Sdim      || (arm_reg_hsh = hash_new ()) == NULL
19539218822Sdim      || (arm_reloc_hsh = hash_new ()) == NULL
19540218822Sdim      || (arm_barrier_opt_hsh = hash_new ()) == NULL)
19541218822Sdim    as_fatal (_("virtual memory exhausted"));
19542218822Sdim
19543218822Sdim  for (i = 0; i < sizeof (insns) / sizeof (struct asm_opcode); i++)
19544218822Sdim    hash_insert (arm_ops_hsh, insns[i].template, (PTR) (insns + i));
19545218822Sdim  for (i = 0; i < sizeof (conds) / sizeof (struct asm_cond); i++)
19546218822Sdim    hash_insert (arm_cond_hsh, conds[i].template, (PTR) (conds + i));
19547218822Sdim  for (i = 0; i < sizeof (shift_names) / sizeof (struct asm_shift_name); i++)
19548218822Sdim    hash_insert (arm_shift_hsh, shift_names[i].name, (PTR) (shift_names + i));
19549218822Sdim  for (i = 0; i < sizeof (psrs) / sizeof (struct asm_psr); i++)
19550218822Sdim    hash_insert (arm_psr_hsh, psrs[i].template, (PTR) (psrs + i));
19551218822Sdim  for (i = 0; i < sizeof (v7m_psrs) / sizeof (struct asm_psr); i++)
19552218822Sdim    hash_insert (arm_v7m_psr_hsh, v7m_psrs[i].template, (PTR) (v7m_psrs + i));
19553218822Sdim  for (i = 0; i < sizeof (reg_names) / sizeof (struct reg_entry); i++)
19554218822Sdim    hash_insert (arm_reg_hsh, reg_names[i].name, (PTR) (reg_names + i));
19555218822Sdim  for (i = 0;
19556218822Sdim       i < sizeof (barrier_opt_names) / sizeof (struct asm_barrier_opt);
19557218822Sdim       i++)
19558218822Sdim    hash_insert (arm_barrier_opt_hsh, barrier_opt_names[i].template,
19559218822Sdim		 (PTR) (barrier_opt_names + i));
19560218822Sdim#ifdef OBJ_ELF
19561218822Sdim  for (i = 0; i < sizeof (reloc_names) / sizeof (struct reloc_entry); i++)
19562218822Sdim    hash_insert (arm_reloc_hsh, reloc_names[i].name, (PTR) (reloc_names + i));
19563218822Sdim#endif
19564218822Sdim
19565218822Sdim  set_constant_flonums ();
19566218822Sdim
19567218822Sdim  /* Set the cpu variant based on the command-line options.  We prefer
19568218822Sdim     -mcpu= over -march= if both are set (as for GCC); and we prefer
19569218822Sdim     -mfpu= over any other way of setting the floating point unit.
19570218822Sdim     Use of legacy options with new options are faulted.  */
19571218822Sdim  if (legacy_cpu)
19572218822Sdim    {
19573218822Sdim      if (mcpu_cpu_opt || march_cpu_opt)
19574218822Sdim	as_bad (_("use of old and new-style options to set CPU type"));
19575218822Sdim
19576218822Sdim      mcpu_cpu_opt = legacy_cpu;
19577218822Sdim    }
19578218822Sdim  else if (!mcpu_cpu_opt)
19579218822Sdim    mcpu_cpu_opt = march_cpu_opt;
19580218822Sdim
19581218822Sdim  if (legacy_fpu)
19582218822Sdim    {
19583218822Sdim      if (mfpu_opt)
19584218822Sdim	as_bad (_("use of old and new-style options to set FPU type"));
19585218822Sdim
19586218822Sdim      mfpu_opt = legacy_fpu;
19587218822Sdim    }
19588218822Sdim  else if (!mfpu_opt)
19589218822Sdim    {
19590218822Sdim#if !(defined (TE_LINUX) || defined (TE_NetBSD) || defined (TE_VXWORKS))
19591218822Sdim      /* Some environments specify a default FPU.  If they don't, infer it
19592218822Sdim	 from the processor.  */
19593218822Sdim      if (mcpu_fpu_opt)
19594218822Sdim	mfpu_opt = mcpu_fpu_opt;
19595218822Sdim      else
19596218822Sdim	mfpu_opt = march_fpu_opt;
19597218822Sdim#else
19598218822Sdim      mfpu_opt = &fpu_default;
19599218822Sdim#endif
19600218822Sdim    }
19601218822Sdim
19602218822Sdim  if (!mfpu_opt)
19603218822Sdim    {
19604218822Sdim      if (mcpu_cpu_opt != NULL)
19605218822Sdim	mfpu_opt = &fpu_default;
19606218822Sdim      else if (mcpu_fpu_opt != NULL && ARM_CPU_HAS_FEATURE (*mcpu_fpu_opt, arm_ext_v5))
19607218822Sdim	mfpu_opt = &fpu_arch_vfp_v2;
19608218822Sdim      else
19609218822Sdim	mfpu_opt = &fpu_arch_fpa;
19610218822Sdim    }
19611218822Sdim
19612218822Sdim#ifdef CPU_DEFAULT
19613218822Sdim  if (!mcpu_cpu_opt)
19614218822Sdim    {
19615218822Sdim      mcpu_cpu_opt = &cpu_default;
19616218822Sdim      selected_cpu = cpu_default;
19617218822Sdim    }
19618218822Sdim#else
19619218822Sdim  if (mcpu_cpu_opt)
19620218822Sdim    selected_cpu = *mcpu_cpu_opt;
19621218822Sdim  else
19622218822Sdim    mcpu_cpu_opt = &arm_arch_any;
19623218822Sdim#endif
19624218822Sdim
19625218822Sdim  ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
19626218822Sdim
19627218822Sdim  autoselect_thumb_from_cpu_variant ();
19628218822Sdim
19629218822Sdim  arm_arch_used = thumb_arch_used = arm_arch_none;
19630218822Sdim
19631218822Sdim#if defined OBJ_COFF || defined OBJ_ELF
19632218822Sdim  {
19633218822Sdim    unsigned int flags = 0;
19634218822Sdim
19635218822Sdim#if defined OBJ_ELF
19636218822Sdim    flags = meabi_flags;
19637218822Sdim
19638218822Sdim    switch (meabi_flags)
19639218822Sdim      {
19640218822Sdim      case EF_ARM_EABI_UNKNOWN:
19641218822Sdim#endif
19642218822Sdim	/* Set the flags in the private structure.  */
19643218822Sdim	if (uses_apcs_26)      flags |= F_APCS26;
19644218822Sdim	if (support_interwork) flags |= F_INTERWORK;
19645218822Sdim	if (uses_apcs_float)   flags |= F_APCS_FLOAT;
19646218822Sdim	if (pic_code)	       flags |= F_PIC;
19647218822Sdim	if (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_any_hard))
19648218822Sdim	  flags |= F_SOFT_FLOAT;
19649218822Sdim
19650218822Sdim	switch (mfloat_abi_opt)
19651218822Sdim	  {
19652218822Sdim	  case ARM_FLOAT_ABI_SOFT:
19653218822Sdim	  case ARM_FLOAT_ABI_SOFTFP:
19654218822Sdim	    flags |= F_SOFT_FLOAT;
19655218822Sdim	    break;
19656218822Sdim
19657218822Sdim	  case ARM_FLOAT_ABI_HARD:
19658218822Sdim	    if (flags & F_SOFT_FLOAT)
19659218822Sdim	      as_bad (_("hard-float conflicts with specified fpu"));
19660218822Sdim	    break;
19661218822Sdim	  }
19662218822Sdim
19663218822Sdim	/* Using pure-endian doubles (even if soft-float).	*/
19664218822Sdim	if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_endian_pure))
19665218822Sdim	  flags |= F_VFP_FLOAT;
19666218822Sdim
19667218822Sdim#if defined OBJ_ELF
19668218822Sdim	if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_arch_maverick))
19669218822Sdim	    flags |= EF_ARM_MAVERICK_FLOAT;
19670218822Sdim	break;
19671218822Sdim
19672218822Sdim      case EF_ARM_EABI_VER4:
19673218822Sdim      case EF_ARM_EABI_VER5:
19674218822Sdim	/* No additional flags to set.	*/
19675218822Sdim	break;
19676218822Sdim
19677218822Sdim      default:
19678218822Sdim	abort ();
19679218822Sdim      }
19680218822Sdim#endif
19681218822Sdim    bfd_set_private_flags (stdoutput, flags);
19682218822Sdim
19683218822Sdim    /* We have run out flags in the COFF header to encode the
19684218822Sdim       status of ATPCS support, so instead we create a dummy,
19685218822Sdim       empty, debug section called .arm.atpcs.	*/
19686218822Sdim    if (atpcs)
19687218822Sdim      {
19688218822Sdim	asection * sec;
19689218822Sdim
19690218822Sdim	sec = bfd_make_section (stdoutput, ".arm.atpcs");
19691218822Sdim
19692218822Sdim	if (sec != NULL)
19693218822Sdim	  {
19694218822Sdim	    bfd_set_section_flags
19695218822Sdim	      (stdoutput, sec, SEC_READONLY | SEC_DEBUGGING /* | SEC_HAS_CONTENTS */);
19696218822Sdim	    bfd_set_section_size (stdoutput, sec, 0);
19697218822Sdim	    bfd_set_section_contents (stdoutput, sec, NULL, 0, 0);
19698218822Sdim	  }
19699218822Sdim      }
19700218822Sdim  }
19701218822Sdim#endif
19702218822Sdim
19703218822Sdim  /* Record the CPU type as well.  */
19704218822Sdim  if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2))
19705218822Sdim    mach = bfd_mach_arm_iWMMXt2;
19706218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt))
19707218822Sdim    mach = bfd_mach_arm_iWMMXt;
19708218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_xscale))
19709218822Sdim    mach = bfd_mach_arm_XScale;
19710218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_maverick))
19711218822Sdim    mach = bfd_mach_arm_ep9312;
19712218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v5e))
19713218822Sdim    mach = bfd_mach_arm_5TE;
19714218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v5))
19715218822Sdim    {
19716218822Sdim      if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v4t))
19717218822Sdim	mach = bfd_mach_arm_5T;
19718218822Sdim      else
19719218822Sdim	mach = bfd_mach_arm_5;
19720218822Sdim    }
19721218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v4))
19722218822Sdim    {
19723218822Sdim      if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v4t))
19724218822Sdim	mach = bfd_mach_arm_4T;
19725218822Sdim      else
19726218822Sdim	mach = bfd_mach_arm_4;
19727218822Sdim    }
19728218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v3m))
19729218822Sdim    mach = bfd_mach_arm_3M;
19730218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v3))
19731218822Sdim    mach = bfd_mach_arm_3;
19732218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v2s))
19733218822Sdim    mach = bfd_mach_arm_2a;
19734218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v2))
19735218822Sdim    mach = bfd_mach_arm_2;
19736218822Sdim  else
19737218822Sdim    mach = bfd_mach_arm_unknown;
19738218822Sdim
19739218822Sdim  bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
19740218822Sdim}
19741218822Sdim
19742218822Sdim/* Command line processing.  */
19743218822Sdim
1974489857Sobrien/* md_parse_option
1974589857Sobrien      Invocation line includes a switch not recognized by the base assembler.
19746104834Sobrien      See if it's a processor-specific option.
1974777298Sobrien
1974889857Sobrien      This routine is somewhat complicated by the need for backwards
1974989857Sobrien      compatibility (since older releases of gcc can't be changed).
1975089857Sobrien      The new options try to make the interface as compatible as
1975189857Sobrien      possible with GCC.
1975277298Sobrien
1975389857Sobrien      New options (supported) are:
1975460484Sobrien
1975589857Sobrien	      -mcpu=<cpu name>		 Assemble for selected processor
1975689857Sobrien	      -march=<architecture name> Assemble for selected architecture
1975789857Sobrien	      -mfpu=<fpu architecture>	 Assemble for selected FPU.
1975889857Sobrien	      -EB/-mbig-endian		 Big-endian
1975989857Sobrien	      -EL/-mlittle-endian	 Little-endian
1976089857Sobrien	      -k			 Generate PIC code
1976189857Sobrien	      -mthumb			 Start in Thumb mode
1976289857Sobrien	      -mthumb-interwork		 Code supports ARM/Thumb interworking
1976377298Sobrien
19764130561Sobrien      For now we will also provide support for:
1976560484Sobrien
1976689857Sobrien	      -mapcs-32			 32-bit Program counter
1976789857Sobrien	      -mapcs-26			 26-bit Program counter
1976889857Sobrien	      -macps-float		 Floats passed in FP registers
1976989857Sobrien	      -mapcs-reentrant		 Reentrant code
1977089857Sobrien	      -matpcs
1977189857Sobrien      (sometime these will probably be replaced with -mapcs=<list of options>
1977289857Sobrien      and -matpcs=<list of options>)
1977360484Sobrien
1977489857Sobrien      The remaining options are only supported for back-wards compatibility.
1977577298Sobrien      Cpu variants, the arm part is optional:
19776218822Sdim	      -m[arm]1		      Currently not supported.
19777218822Sdim	      -m[arm]2, -m[arm]250    Arm 2 and Arm 250 processor
19778218822Sdim	      -m[arm]3		      Arm 3 processor
19779218822Sdim	      -m[arm]6[xx],	      Arm 6 processors
19780218822Sdim	      -m[arm]7[xx][t][[d]m]   Arm 7 processors
19781218822Sdim	      -m[arm]8[10]	      Arm 8 processors
19782218822Sdim	      -m[arm]9[20][tdmi]      Arm 9 processors
19783218822Sdim	      -mstrongarm[110[0]]     StrongARM processors
19784218822Sdim	      -mxscale		      XScale processors
19785218822Sdim	      -m[arm]v[2345[t[e]]]    Arm architectures
19786218822Sdim	      -mall		      All (except the ARM1)
1978777298Sobrien      FP variants:
19788218822Sdim	      -mfpa10, -mfpa11	      FPA10 and 11 co-processor instructions
19789218822Sdim	      -mfpe-old		      (No float load/store multiples)
1979089857Sobrien	      -mvfpxd		      VFP Single precision
1979189857Sobrien	      -mvfp		      All VFP
19792218822Sdim	      -mno-fpu		      Disable all floating point instructions
1979360484Sobrien
1979489857Sobrien      The following CPU names are recognized:
1979589857Sobrien	      arm1, arm2, arm250, arm3, arm6, arm600, arm610, arm620,
1979689857Sobrien	      arm7, arm7m, arm7d, arm7dm, arm7di, arm7dmi, arm70, arm700,
1979789857Sobrien	      arm700i, arm710 arm710t, arm720, arm720t, arm740t, arm710c,
1979889857Sobrien	      arm7100, arm7500, arm7500fe, arm7tdmi, arm8, arm810, arm9,
1979989857Sobrien	      arm920, arm920t, arm940t, arm946, arm966, arm9tdmi, arm9e,
1980089857Sobrien	      arm10t arm10e, arm1020t, arm1020e, arm10200e,
1980189857Sobrien	      strongarm, strongarm110, strongarm1100, strongarm1110, xscale.
1980289857Sobrien
1980389857Sobrien      */
1980489857Sobrien
19805104834Sobrienconst char * md_shortopts = "m:k";
1980677298Sobrien
1980789857Sobrien#ifdef ARM_BI_ENDIAN
1980889857Sobrien#define OPTION_EB (OPTION_MD_BASE + 0)
1980989857Sobrien#define OPTION_EL (OPTION_MD_BASE + 1)
1981089857Sobrien#else
1981189857Sobrien#if TARGET_BYTES_BIG_ENDIAN
1981289857Sobrien#define OPTION_EB (OPTION_MD_BASE + 0)
1981389857Sobrien#else
1981489857Sobrien#define OPTION_EL (OPTION_MD_BASE + 1)
1981589857Sobrien#endif
1981689857Sobrien#endif
1981789857Sobrien
1981860484Sobrienstruct option md_longopts[] =
1981960484Sobrien{
1982089857Sobrien#ifdef OPTION_EB
1982160484Sobrien  {"EB", no_argument, NULL, OPTION_EB},
1982289857Sobrien#endif
1982389857Sobrien#ifdef OPTION_EL
1982460484Sobrien  {"EL", no_argument, NULL, OPTION_EL},
1982560484Sobrien#endif
1982660484Sobrien  {NULL, no_argument, NULL, 0}
1982760484Sobrien};
1982877298Sobrien
1982960484Sobriensize_t md_longopts_size = sizeof (md_longopts);
1983060484Sobrien
1983189857Sobrienstruct arm_option_table
1983260484Sobrien{
1983389857Sobrien  char *option;		/* Option name to match.  */
1983489857Sobrien  char *help;		/* Help information.  */
19835218822Sdim  int  *var;		/* Variable to change.	*/
19836218822Sdim  int	value;		/* What to change it to.  */
1983789857Sobrien  char *deprecated;	/* If non-null, print this message.  */
1983889857Sobrien};
1983960484Sobrien
19840104834Sobrienstruct arm_option_table arm_opts[] =
1984189857Sobrien{
19842218822Sdim  {"k",	     N_("generate PIC code"),	   &pic_code,	 1, NULL},
19843218822Sdim  {"mthumb", N_("assemble Thumb code"),	   &thumb_mode,	 1, NULL},
1984489857Sobrien  {"mthumb-interwork", N_("support ARM/Thumb interworking"),
1984589857Sobrien   &support_interwork, 1, NULL},
1984689857Sobrien  {"mapcs-32", N_("code uses 32-bit program counter"), &uses_apcs_26, 0, NULL},
1984789857Sobrien  {"mapcs-26", N_("code uses 26-bit program counter"), &uses_apcs_26, 1, NULL},
1984889857Sobrien  {"mapcs-float", N_("floating point args are in fp regs"), &uses_apcs_float,
1984989857Sobrien   1, NULL},
1985089857Sobrien  {"mapcs-reentrant", N_("re-entrant code"), &pic_code, 1, NULL},
1985189857Sobrien  {"matpcs", N_("code is ATPCS conformant"), &atpcs, 1, NULL},
1985289857Sobrien  {"mbig-endian", N_("assemble for big-endian"), &target_big_endian, 1, NULL},
19853218822Sdim  {"mlittle-endian", N_("assemble for little-endian"), &target_big_endian, 0,
1985489857Sobrien   NULL},
1985589857Sobrien
19856218822Sdim  /* These are recognized by the assembler, but have no affect on code.	 */
1985789857Sobrien  {"mapcs-frame", N_("use frame pointer"), NULL, 0, NULL},
1985889857Sobrien  {"mapcs-stack-check", N_("use stack size checking"), NULL, 0, NULL},
19859218822Sdim  {NULL, NULL, NULL, 0, NULL}
19860218822Sdim};
1986189857Sobrien
19862218822Sdimstruct arm_legacy_option_table
19863218822Sdim{
19864218822Sdim  char *option;				/* Option name to match.  */
19865218822Sdim  const arm_feature_set	**var;		/* Variable to change.	*/
19866218822Sdim  const arm_feature_set	value;		/* What to change it to.  */
19867218822Sdim  char *deprecated;			/* If non-null, print this message.  */
19868218822Sdim};
19869218822Sdim
19870218822Sdimconst struct arm_legacy_option_table arm_legacy_opts[] =
19871218822Sdim{
1987289857Sobrien  /* DON'T add any new processors to this list -- we want the whole list
1987389857Sobrien     to go away...  Add them to the processors table instead.  */
19874218822Sdim  {"marm1",	 &legacy_cpu, ARM_ARCH_V1,  N_("use -mcpu=arm1")},
19875218822Sdim  {"m1",	 &legacy_cpu, ARM_ARCH_V1,  N_("use -mcpu=arm1")},
19876218822Sdim  {"marm2",	 &legacy_cpu, ARM_ARCH_V2,  N_("use -mcpu=arm2")},
19877218822Sdim  {"m2",	 &legacy_cpu, ARM_ARCH_V2,  N_("use -mcpu=arm2")},
19878218822Sdim  {"marm250",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm250")},
19879218822Sdim  {"m250",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm250")},
19880218822Sdim  {"marm3",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm3")},
19881218822Sdim  {"m3",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm3")},
19882218822Sdim  {"marm6",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm6")},
19883218822Sdim  {"m6",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm6")},
19884218822Sdim  {"marm600",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm600")},
19885218822Sdim  {"m600",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm600")},
19886218822Sdim  {"marm610",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm610")},
19887218822Sdim  {"m610",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm610")},
19888218822Sdim  {"marm620",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm620")},
19889218822Sdim  {"m620",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm620")},
19890218822Sdim  {"marm7",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7")},
19891218822Sdim  {"m7",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7")},
19892218822Sdim  {"marm70",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm70")},
19893218822Sdim  {"m70",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm70")},
19894218822Sdim  {"marm700",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm700")},
19895218822Sdim  {"m700",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm700")},
19896218822Sdim  {"marm700i",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm700i")},
19897218822Sdim  {"m700i",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm700i")},
19898218822Sdim  {"marm710",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm710")},
19899218822Sdim  {"m710",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm710")},
19900218822Sdim  {"marm710c",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm710c")},
19901218822Sdim  {"m710c",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm710c")},
19902218822Sdim  {"marm720",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm720")},
19903218822Sdim  {"m720",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm720")},
19904218822Sdim  {"marm7d",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7d")},
19905218822Sdim  {"m7d",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7d")},
19906218822Sdim  {"marm7di",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7di")},
19907218822Sdim  {"m7di",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7di")},
19908218822Sdim  {"marm7m",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7m")},
19909218822Sdim  {"m7m",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7m")},
19910218822Sdim  {"marm7dm",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dm")},
19911218822Sdim  {"m7dm",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dm")},
19912218822Sdim  {"marm7dmi",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dmi")},
19913218822Sdim  {"m7dmi",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dmi")},
19914218822Sdim  {"marm7100",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7100")},
19915218822Sdim  {"m7100",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7100")},
19916218822Sdim  {"marm7500",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7500")},
19917218822Sdim  {"m7500",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7500")},
19918218822Sdim  {"marm7500fe", &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7500fe")},
19919218822Sdim  {"m7500fe",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7500fe")},
19920218822Sdim  {"marm7t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
19921218822Sdim  {"m7t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
19922218822Sdim  {"marm7tdmi",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
19923218822Sdim  {"m7tdmi",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
19924218822Sdim  {"marm710t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm710t")},
19925218822Sdim  {"m710t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm710t")},
19926218822Sdim  {"marm720t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm720t")},
19927218822Sdim  {"m720t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm720t")},
19928218822Sdim  {"marm740t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm740t")},
19929218822Sdim  {"m740t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm740t")},
19930218822Sdim  {"marm8",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -mcpu=arm8")},
19931218822Sdim  {"m8",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -mcpu=arm8")},
19932218822Sdim  {"marm810",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -mcpu=arm810")},
19933218822Sdim  {"m810",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -mcpu=arm810")},
19934218822Sdim  {"marm9",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9")},
19935218822Sdim  {"m9",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9")},
19936218822Sdim  {"marm9tdmi",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9tdmi")},
19937218822Sdim  {"m9tdmi",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9tdmi")},
19938218822Sdim  {"marm920",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm920")},
19939218822Sdim  {"m920",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm920")},
19940218822Sdim  {"marm940",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm940")},
19941218822Sdim  {"m940",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm940")},
19942218822Sdim  {"mstrongarm", &legacy_cpu, ARM_ARCH_V4,  N_("use -mcpu=strongarm")},
19943218822Sdim  {"mstrongarm110", &legacy_cpu, ARM_ARCH_V4,
1994489857Sobrien   N_("use -mcpu=strongarm110")},
19945218822Sdim  {"mstrongarm1100", &legacy_cpu, ARM_ARCH_V4,
1994689857Sobrien   N_("use -mcpu=strongarm1100")},
19947218822Sdim  {"mstrongarm1110", &legacy_cpu, ARM_ARCH_V4,
1994889857Sobrien   N_("use -mcpu=strongarm1110")},
19949218822Sdim  {"mxscale",	 &legacy_cpu, ARM_ARCH_XSCALE, N_("use -mcpu=xscale")},
19950218822Sdim  {"miwmmxt",	 &legacy_cpu, ARM_ARCH_IWMMXT, N_("use -mcpu=iwmmxt")},
19951218822Sdim  {"mall",	 &legacy_cpu, ARM_ANY,	       N_("use -mcpu=all")},
1995289857Sobrien
1995389857Sobrien  /* Architecture variants -- don't add any more to this list either.  */
19954218822Sdim  {"mv2",	 &legacy_cpu, ARM_ARCH_V2,  N_("use -march=armv2")},
19955218822Sdim  {"marmv2",	 &legacy_cpu, ARM_ARCH_V2,  N_("use -march=armv2")},
19956218822Sdim  {"mv2a",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -march=armv2a")},
19957218822Sdim  {"marmv2a",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -march=armv2a")},
19958218822Sdim  {"mv3",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -march=armv3")},
19959218822Sdim  {"marmv3",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -march=armv3")},
19960218822Sdim  {"mv3m",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -march=armv3m")},
19961218822Sdim  {"marmv3m",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -march=armv3m")},
19962218822Sdim  {"mv4",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -march=armv4")},
19963218822Sdim  {"marmv4",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -march=armv4")},
19964218822Sdim  {"mv4t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -march=armv4t")},
19965218822Sdim  {"marmv4t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -march=armv4t")},
19966218822Sdim  {"mv5",	 &legacy_cpu, ARM_ARCH_V5,  N_("use -march=armv5")},
19967218822Sdim  {"marmv5",	 &legacy_cpu, ARM_ARCH_V5,  N_("use -march=armv5")},
19968218822Sdim  {"mv5t",	 &legacy_cpu, ARM_ARCH_V5T, N_("use -march=armv5t")},
19969218822Sdim  {"marmv5t",	 &legacy_cpu, ARM_ARCH_V5T, N_("use -march=armv5t")},
19970218822Sdim  {"mv5e",	 &legacy_cpu, ARM_ARCH_V5TE, N_("use -march=armv5te")},
19971218822Sdim  {"marmv5e",	 &legacy_cpu, ARM_ARCH_V5TE, N_("use -march=armv5te")},
1997289857Sobrien
19973218822Sdim  /* Floating point variants -- don't add any more to this list either.	 */
19974218822Sdim  {"mfpe-old", &legacy_fpu, FPU_ARCH_FPE, N_("use -mfpu=fpe")},
19975218822Sdim  {"mfpa10",   &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa10")},
19976218822Sdim  {"mfpa11",   &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa11")},
19977218822Sdim  {"mno-fpu",  &legacy_fpu, ARM_ARCH_NONE,
1997889857Sobrien   N_("use either -mfpu=softfpa or -mfpu=softvfp")},
1997989857Sobrien
19980218822Sdim  {NULL, NULL, ARM_ARCH_NONE, NULL}
1998189857Sobrien};
1998289857Sobrien
1998389857Sobrienstruct arm_cpu_option_table
1998489857Sobrien{
1998589857Sobrien  char *name;
19986218822Sdim  const arm_feature_set	value;
1998789857Sobrien  /* For some CPUs we assume an FPU unless the user explicitly sets
19988218822Sdim     -mfpu=...	*/
19989218822Sdim  const arm_feature_set	default_fpu;
19990218822Sdim  /* The canonical name of the CPU, or NULL to use NAME converted to upper
19991218822Sdim     case.  */
19992218822Sdim  const char *canonical_name;
1999389857Sobrien};
1999489857Sobrien
1999589857Sobrien/* This list should, at a minimum, contain all the cpu names
1999689857Sobrien   recognized by GCC.  */
19997218822Sdimstatic const struct arm_cpu_option_table arm_cpus[] =
1999889857Sobrien{
19999218822Sdim  {"all",		ARM_ANY,	 FPU_ARCH_FPA,    NULL},
20000218822Sdim  {"arm1",		ARM_ARCH_V1,	 FPU_ARCH_FPA,    NULL},
20001218822Sdim  {"arm2",		ARM_ARCH_V2,	 FPU_ARCH_FPA,    NULL},
20002218822Sdim  {"arm250",		ARM_ARCH_V2S,	 FPU_ARCH_FPA,    NULL},
20003218822Sdim  {"arm3",		ARM_ARCH_V2S,	 FPU_ARCH_FPA,    NULL},
20004218822Sdim  {"arm6",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20005218822Sdim  {"arm60",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20006218822Sdim  {"arm600",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20007218822Sdim  {"arm610",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20008218822Sdim  {"arm620",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20009218822Sdim  {"arm7",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20010218822Sdim  {"arm7m",		ARM_ARCH_V3M,	 FPU_ARCH_FPA,    NULL},
20011218822Sdim  {"arm7d",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20012218822Sdim  {"arm7dm",		ARM_ARCH_V3M,	 FPU_ARCH_FPA,    NULL},
20013218822Sdim  {"arm7di",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20014218822Sdim  {"arm7dmi",		ARM_ARCH_V3M,	 FPU_ARCH_FPA,    NULL},
20015218822Sdim  {"arm70",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20016218822Sdim  {"arm700",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20017218822Sdim  {"arm700i",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20018218822Sdim  {"arm710",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20019218822Sdim  {"arm710t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20020218822Sdim  {"arm720",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20021218822Sdim  {"arm720t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20022218822Sdim  {"arm740t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20023218822Sdim  {"arm710c",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20024218822Sdim  {"arm7100",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20025218822Sdim  {"arm7500",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20026218822Sdim  {"arm7500fe",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20027218822Sdim  {"arm7t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20028218822Sdim  {"arm7tdmi",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20029218822Sdim  {"arm7tdmi-s",	ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20030218822Sdim  {"arm8",		ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
20031218822Sdim  {"arm810",		ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
20032218822Sdim  {"strongarm",		ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
20033218822Sdim  {"strongarm1",	ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
20034218822Sdim  {"strongarm110",	ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
20035218822Sdim  {"strongarm1100",	ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
20036218822Sdim  {"strongarm1110",	ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
20037218822Sdim  {"arm9",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20038218822Sdim  {"arm920",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    "ARM920T"},
20039218822Sdim  {"arm920t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20040218822Sdim  {"arm922t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20041218822Sdim  {"arm940t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20042218822Sdim  {"arm9tdmi",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,	  NULL},
2004389857Sobrien  /* For V5 or later processors we default to using VFP; but the user
20044218822Sdim     should really set the FPU type explicitly.	 */
20045218822Sdim  {"arm9e-r0",		ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL},
20046218822Sdim  {"arm9e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
20047218822Sdim  {"arm926ej",		ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP_V2, "ARM926EJ-S"},
20048218822Sdim  {"arm926ejs",		ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP_V2, "ARM926EJ-S"},
20049218822Sdim  {"arm926ej-s",	ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP_V2, NULL},
20050218822Sdim  {"arm946e-r0",	ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL},
20051218822Sdim  {"arm946e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, "ARM946E-S"},
20052218822Sdim  {"arm946e-s",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
20053218822Sdim  {"arm966e-r0",	ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL},
20054218822Sdim  {"arm966e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, "ARM966E-S"},
20055218822Sdim  {"arm966e-s",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
20056218822Sdim  {"arm968e-s",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
20057218822Sdim  {"arm10t",		ARM_ARCH_V5T,	 FPU_ARCH_VFP_V1, NULL},
20058218822Sdim  {"arm10tdmi",		ARM_ARCH_V5T,	 FPU_ARCH_VFP_V1, NULL},
20059218822Sdim  {"arm10e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
20060218822Sdim  {"arm1020",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, "ARM1020E"},
20061218822Sdim  {"arm1020t",		ARM_ARCH_V5T,	 FPU_ARCH_VFP_V1, NULL},
20062218822Sdim  {"arm1020e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
20063218822Sdim  {"arm1022e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
20064218822Sdim  {"arm1026ejs",	ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP_V2, "ARM1026EJ-S"},
20065218822Sdim  {"arm1026ej-s",	ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP_V2, NULL},
20066218822Sdim  {"arm1136js",		ARM_ARCH_V6,	 FPU_NONE,	  "ARM1136J-S"},
20067218822Sdim  {"arm1136j-s",	ARM_ARCH_V6,	 FPU_NONE,	  NULL},
20068218822Sdim  {"arm1136jfs",	ARM_ARCH_V6,	 FPU_ARCH_VFP_V2, "ARM1136JF-S"},
20069218822Sdim  {"arm1136jf-s",	ARM_ARCH_V6,	 FPU_ARCH_VFP_V2, NULL},
20070218822Sdim  {"mpcore",		ARM_ARCH_V6K,	 FPU_ARCH_VFP_V2, NULL},
20071218822Sdim  {"mpcorenovfp",	ARM_ARCH_V6K,	 FPU_NONE,	  NULL},
20072218822Sdim  {"arm1156t2-s",	ARM_ARCH_V6T2,	 FPU_NONE,	  NULL},
20073218822Sdim  {"arm1156t2f-s",	ARM_ARCH_V6T2,	 FPU_ARCH_VFP_V2, NULL},
20074218822Sdim  {"arm1176jz-s",	ARM_ARCH_V6ZK,	 FPU_NONE,	  NULL},
20075218822Sdim  {"arm1176jzf-s",	ARM_ARCH_V6ZK,	 FPU_ARCH_VFP_V2, NULL},
20076218822Sdim  {"cortex-a8",		ARM_ARCH_V7A,	 ARM_FEATURE(0, FPU_VFP_V3
20077218822Sdim                                                        | FPU_NEON_EXT_V1),
20078218822Sdim                                                          NULL},
20079239272Sgonzo  {"cortex-a9",		ARM_ARCH_V7A,	 ARM_FEATURE(0, FPU_VFP_V3
20080239272Sgonzo                                                        | FPU_NEON_EXT_V1),
20081239272Sgonzo                                                          NULL},
20082218822Sdim  {"cortex-r4",		ARM_ARCH_V7R,	 FPU_NONE,	  NULL},
20083218822Sdim  {"cortex-m3",		ARM_ARCH_V7M,	 FPU_NONE,	  NULL},
2008489857Sobrien  /* ??? XSCALE is really an architecture.  */
20085218822Sdim  {"xscale",		ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL},
20086130561Sobrien  /* ??? iwmmxt is not a processor.  */
20087218822Sdim  {"iwmmxt",		ARM_ARCH_IWMMXT, FPU_ARCH_VFP_V2, NULL},
20088218822Sdim  {"iwmmxt2",		ARM_ARCH_IWMMXT2,FPU_ARCH_VFP_V2, NULL},
20089218822Sdim  {"i80200",		ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL},
2009089857Sobrien  /* Maverick */
20091218822Sdim  {"ep9312",	ARM_FEATURE(ARM_AEXT_V4T, ARM_CEXT_MAVERICK), FPU_ARCH_MAVERICK, "ARM920T"},
20092218822Sdim  {NULL,		ARM_ARCH_NONE,	 ARM_ARCH_NONE, NULL}
2009389857Sobrien};
20094104834Sobrien
2009589857Sobrienstruct arm_arch_option_table
2009689857Sobrien{
2009789857Sobrien  char *name;
20098218822Sdim  const arm_feature_set	value;
20099218822Sdim  const arm_feature_set	default_fpu;
2010089857Sobrien};
2010189857Sobrien
2010289857Sobrien/* This list should, at a minimum, contain all the architecture names
2010389857Sobrien   recognized by GCC.  */
20104218822Sdimstatic const struct arm_arch_option_table arm_archs[] =
2010589857Sobrien{
2010689857Sobrien  {"all",		ARM_ANY,	 FPU_ARCH_FPA},
2010789857Sobrien  {"armv1",		ARM_ARCH_V1,	 FPU_ARCH_FPA},
2010889857Sobrien  {"armv2",		ARM_ARCH_V2,	 FPU_ARCH_FPA},
2010989857Sobrien  {"armv2a",		ARM_ARCH_V2S,	 FPU_ARCH_FPA},
2011089857Sobrien  {"armv2s",		ARM_ARCH_V2S,	 FPU_ARCH_FPA},
2011189857Sobrien  {"armv3",		ARM_ARCH_V3,	 FPU_ARCH_FPA},
2011289857Sobrien  {"armv3m",		ARM_ARCH_V3M,	 FPU_ARCH_FPA},
2011389857Sobrien  {"armv4",		ARM_ARCH_V4,	 FPU_ARCH_FPA},
2011489857Sobrien  {"armv4xm",		ARM_ARCH_V4xM,	 FPU_ARCH_FPA},
2011589857Sobrien  {"armv4t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA},
2011689857Sobrien  {"armv4txm",		ARM_ARCH_V4TxM,	 FPU_ARCH_FPA},
2011789857Sobrien  {"armv5",		ARM_ARCH_V5,	 FPU_ARCH_VFP},
2011889857Sobrien  {"armv5t",		ARM_ARCH_V5T,	 FPU_ARCH_VFP},
2011989857Sobrien  {"armv5txm",		ARM_ARCH_V5TxM,	 FPU_ARCH_VFP},
2012089857Sobrien  {"armv5te",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP},
2012189857Sobrien  {"armv5texp",		ARM_ARCH_V5TExP, FPU_ARCH_VFP},
20122218822Sdim  {"armv5tej",		ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP},
20123218822Sdim  {"armv6",		ARM_ARCH_V6,	 FPU_ARCH_VFP},
20124218822Sdim  {"armv6j",		ARM_ARCH_V6,	 FPU_ARCH_VFP},
20125218822Sdim  {"armv6k",		ARM_ARCH_V6K,	 FPU_ARCH_VFP},
20126218822Sdim  {"armv6z",		ARM_ARCH_V6Z,	 FPU_ARCH_VFP},
20127218822Sdim  {"armv6zk",		ARM_ARCH_V6ZK,	 FPU_ARCH_VFP},
20128218822Sdim  {"armv6t2",		ARM_ARCH_V6T2,	 FPU_ARCH_VFP},
20129218822Sdim  {"armv6kt2",		ARM_ARCH_V6KT2,	 FPU_ARCH_VFP},
20130218822Sdim  {"armv6zt2",		ARM_ARCH_V6ZT2,	 FPU_ARCH_VFP},
20131218822Sdim  {"armv6zkt2",		ARM_ARCH_V6ZKT2, FPU_ARCH_VFP},
20132218822Sdim  {"armv7",		ARM_ARCH_V7,	 FPU_ARCH_VFP},
20133218822Sdim  /* The official spelling of the ARMv7 profile variants is the dashed form.
20134218822Sdim     Accept the non-dashed form for compatibility with old toolchains.  */
20135218822Sdim  {"armv7a",		ARM_ARCH_V7A,	 FPU_ARCH_VFP},
20136218822Sdim  {"armv7r",		ARM_ARCH_V7R,	 FPU_ARCH_VFP},
20137218822Sdim  {"armv7m",		ARM_ARCH_V7M,	 FPU_ARCH_VFP},
20138218822Sdim  {"armv7-a",		ARM_ARCH_V7A,	 FPU_ARCH_VFP},
20139218822Sdim  {"armv7-r",		ARM_ARCH_V7R,	 FPU_ARCH_VFP},
20140218822Sdim  {"armv7-m",		ARM_ARCH_V7M,	 FPU_ARCH_VFP},
2014189857Sobrien  {"xscale",		ARM_ARCH_XSCALE, FPU_ARCH_VFP},
20142130561Sobrien  {"iwmmxt",		ARM_ARCH_IWMMXT, FPU_ARCH_VFP},
20143218822Sdim  {"iwmmxt2",		ARM_ARCH_IWMMXT2,FPU_ARCH_VFP},
20144218822Sdim  {NULL,		ARM_ARCH_NONE,	 ARM_ARCH_NONE}
2014589857Sobrien};
2014689857Sobrien
2014789857Sobrien/* ISA extensions in the co-processor space.  */
20148218822Sdimstruct arm_option_cpu_value_table
2014989857Sobrien{
2015089857Sobrien  char *name;
20151218822Sdim  const arm_feature_set value;
2015289857Sobrien};
2015389857Sobrien
20154218822Sdimstatic const struct arm_option_cpu_value_table arm_extensions[] =
2015589857Sobrien{
20156218822Sdim  {"maverick",		ARM_FEATURE (0, ARM_CEXT_MAVERICK)},
20157218822Sdim  {"xscale",		ARM_FEATURE (0, ARM_CEXT_XSCALE)},
20158218822Sdim  {"iwmmxt",		ARM_FEATURE (0, ARM_CEXT_IWMMXT)},
20159218822Sdim  {"iwmmxt2",		ARM_FEATURE (0, ARM_CEXT_IWMMXT2)},
20160218822Sdim  {NULL,		ARM_ARCH_NONE}
2016189857Sobrien};
2016289857Sobrien
2016389857Sobrien/* This list should, at a minimum, contain all the fpu names
2016489857Sobrien   recognized by GCC.  */
20165218822Sdimstatic const struct arm_option_cpu_value_table arm_fpus[] =
2016689857Sobrien{
2016789857Sobrien  {"softfpa",		FPU_NONE},
2016889857Sobrien  {"fpe",		FPU_ARCH_FPE},
2016989857Sobrien  {"fpe2",		FPU_ARCH_FPE},
2017089857Sobrien  {"fpe3",		FPU_ARCH_FPA},	/* Third release supports LFM/SFM.  */
2017189857Sobrien  {"fpa",		FPU_ARCH_FPA},
2017289857Sobrien  {"fpa10",		FPU_ARCH_FPA},
2017389857Sobrien  {"fpa11",		FPU_ARCH_FPA},
2017489857Sobrien  {"arm7500fe",		FPU_ARCH_FPA},
2017589857Sobrien  {"softvfp",		FPU_ARCH_VFP},
2017689857Sobrien  {"softvfp+vfp",	FPU_ARCH_VFP_V2},
2017789857Sobrien  {"vfp",		FPU_ARCH_VFP_V2},
20178244274Sandrew  {"vfpv2",		FPU_ARCH_VFP_V2},
2017989857Sobrien  {"vfp9",		FPU_ARCH_VFP_V2},
20180218822Sdim  {"vfp3",              FPU_ARCH_VFP_V3},
20181239272Sgonzo  {"vfpv3",             FPU_ARCH_VFP_V3},
2018289857Sobrien  {"vfp10",		FPU_ARCH_VFP_V2},
2018389857Sobrien  {"vfp10-r0",		FPU_ARCH_VFP_V1},
2018489857Sobrien  {"vfpxd",		FPU_ARCH_VFP_V1xD},
2018589857Sobrien  {"arm1020t",		FPU_ARCH_VFP_V1},
2018689857Sobrien  {"arm1020e",		FPU_ARCH_VFP_V2},
20187130561Sobrien  {"arm1136jfs",	FPU_ARCH_VFP_V2},
20188218822Sdim  {"arm1136jf-s",	FPU_ARCH_VFP_V2},
20189130561Sobrien  {"maverick",		FPU_ARCH_MAVERICK},
20190218822Sdim  {"neon",              FPU_ARCH_VFP_V3_PLUS_NEON_V1},
20191218822Sdim  {NULL,		ARM_ARCH_NONE}
2019289857Sobrien};
2019389857Sobrien
20194218822Sdimstruct arm_option_value_table
20195130561Sobrien{
20196130561Sobrien  char *name;
20197218822Sdim  long value;
20198130561Sobrien};
20199130561Sobrien
20200218822Sdimstatic const struct arm_option_value_table arm_float_abis[] =
20201130561Sobrien{
20202130561Sobrien  {"hard",	ARM_FLOAT_ABI_HARD},
20203130561Sobrien  {"softfp",	ARM_FLOAT_ABI_SOFTFP},
20204130561Sobrien  {"soft",	ARM_FLOAT_ABI_SOFT},
20205218822Sdim  {NULL,	0}
20206130561Sobrien};
20207130561Sobrien
20208218822Sdim#ifdef OBJ_ELF
20209218822Sdim/* We only know how to output GNU and ver 4/5 (AAELF) formats.  */
20210218822Sdimstatic const struct arm_option_value_table arm_eabis[] =
20211218822Sdim{
20212218822Sdim  {"gnu",	EF_ARM_EABI_UNKNOWN},
20213218822Sdim  {"4",		EF_ARM_EABI_VER4},
20214218822Sdim  {"5",		EF_ARM_EABI_VER5},
20215218822Sdim  {NULL,	0}
20216218822Sdim};
20217218822Sdim#endif
20218218822Sdim
2021989857Sobrienstruct arm_long_option_table
2022089857Sobrien{
20221218822Sdim  char * option;		/* Substring to match.	*/
20222218822Sdim  char * help;			/* Help information.  */
20223218822Sdim  int (* func) (char * subopt);	/* Function to decode sub-option.  */
20224218822Sdim  char * deprecated;		/* If non-null, print this message.  */
2022589857Sobrien};
2022689857Sobrien
2022789857Sobrienstatic int
20228218822Sdimarm_parse_extension (char * str, const arm_feature_set **opt_p)
2022989857Sobrien{
20230218822Sdim  arm_feature_set *ext_set = xmalloc (sizeof (arm_feature_set));
20231218822Sdim
20232218822Sdim  /* Copy the feature set, so that we can modify it.  */
20233218822Sdim  *ext_set = **opt_p;
20234218822Sdim  *opt_p = ext_set;
20235218822Sdim
2023689857Sobrien  while (str != NULL && *str != 0)
2023760484Sobrien    {
20238218822Sdim      const struct arm_option_cpu_value_table * opt;
20239218822Sdim      char * ext;
2024089857Sobrien      int optlen;
2024160484Sobrien
2024289857Sobrien      if (*str != '+')
2024360484Sobrien	{
2024489857Sobrien	  as_bad (_("invalid architectural extension"));
2024589857Sobrien	  return 0;
2024689857Sobrien	}
2024760484Sobrien
2024889857Sobrien      str++;
2024989857Sobrien      ext = strchr (str, '+');
2025060484Sobrien
2025189857Sobrien      if (ext != NULL)
2025289857Sobrien	optlen = ext - str;
2025389857Sobrien      else
2025489857Sobrien	optlen = strlen (str);
2025577298Sobrien
2025689857Sobrien      if (optlen == 0)
2025789857Sobrien	{
2025889857Sobrien	  as_bad (_("missing architectural extension"));
2025989857Sobrien	  return 0;
2026089857Sobrien	}
2026160484Sobrien
2026289857Sobrien      for (opt = arm_extensions; opt->name != NULL; opt++)
2026389857Sobrien	if (strncmp (opt->name, str, optlen) == 0)
2026489857Sobrien	  {
20265218822Sdim	    ARM_MERGE_FEATURE_SETS (*ext_set, *ext_set, opt->value);
2026689857Sobrien	    break;
2026789857Sobrien	  }
2026860484Sobrien
2026989857Sobrien      if (opt->name == NULL)
2027089857Sobrien	{
2027189857Sobrien	  as_bad (_("unknown architectural extnsion `%s'"), str);
2027289857Sobrien	  return 0;
2027389857Sobrien	}
2027477298Sobrien
2027589857Sobrien      str = ext;
2027689857Sobrien    };
2027760484Sobrien
2027889857Sobrien  return 1;
2027989857Sobrien}
2028060484Sobrien
2028189857Sobrienstatic int
20282218822Sdimarm_parse_cpu (char * str)
2028389857Sobrien{
20284218822Sdim  const struct arm_cpu_option_table * opt;
20285218822Sdim  char * ext = strchr (str, '+');
2028689857Sobrien  int optlen;
2028777298Sobrien
2028889857Sobrien  if (ext != NULL)
2028989857Sobrien    optlen = ext - str;
2029089857Sobrien  else
2029189857Sobrien    optlen = strlen (str);
2029277298Sobrien
2029389857Sobrien  if (optlen == 0)
2029489857Sobrien    {
2029589857Sobrien      as_bad (_("missing cpu name `%s'"), str);
2029689857Sobrien      return 0;
2029789857Sobrien    }
2029860484Sobrien
2029989857Sobrien  for (opt = arm_cpus; opt->name != NULL; opt++)
2030089857Sobrien    if (strncmp (opt->name, str, optlen) == 0)
2030189857Sobrien      {
20302218822Sdim	mcpu_cpu_opt = &opt->value;
20303218822Sdim	mcpu_fpu_opt = &opt->default_fpu;
20304218822Sdim	if (opt->canonical_name)
20305218822Sdim	  strcpy(selected_cpu_name, opt->canonical_name);
20306218822Sdim	else
20307218822Sdim	  {
20308218822Sdim	    int i;
20309218822Sdim	    for (i = 0; i < optlen; i++)
20310218822Sdim	      selected_cpu_name[i] = TOUPPER (opt->name[i]);
20311218822Sdim	    selected_cpu_name[i] = 0;
20312218822Sdim	  }
2031360484Sobrien
2031489857Sobrien	if (ext != NULL)
2031589857Sobrien	  return arm_parse_extension (ext, &mcpu_cpu_opt);
2031660484Sobrien
2031789857Sobrien	return 1;
2031889857Sobrien      }
2031960484Sobrien
2032089857Sobrien  as_bad (_("unknown cpu `%s'"), str);
2032189857Sobrien  return 0;
2032289857Sobrien}
2032360484Sobrien
2032489857Sobrienstatic int
20325218822Sdimarm_parse_arch (char * str)
2032689857Sobrien{
20327218822Sdim  const struct arm_arch_option_table *opt;
2032889857Sobrien  char *ext = strchr (str, '+');
2032989857Sobrien  int optlen;
2033060484Sobrien
2033189857Sobrien  if (ext != NULL)
2033289857Sobrien    optlen = ext - str;
2033389857Sobrien  else
2033489857Sobrien    optlen = strlen (str);
2033560484Sobrien
2033689857Sobrien  if (optlen == 0)
2033789857Sobrien    {
2033889857Sobrien      as_bad (_("missing architecture name `%s'"), str);
2033989857Sobrien      return 0;
2034089857Sobrien    }
2034177298Sobrien
2034289857Sobrien  for (opt = arm_archs; opt->name != NULL; opt++)
20343218822Sdim    if (streq (opt->name, str))
2034489857Sobrien      {
20345218822Sdim	march_cpu_opt = &opt->value;
20346218822Sdim	march_fpu_opt = &opt->default_fpu;
20347218822Sdim	strcpy(selected_cpu_name, opt->name);
2034860484Sobrien
2034989857Sobrien	if (ext != NULL)
2035089857Sobrien	  return arm_parse_extension (ext, &march_cpu_opt);
2035177298Sobrien
2035289857Sobrien	return 1;
2035389857Sobrien      }
2035460484Sobrien
2035589857Sobrien  as_bad (_("unknown architecture `%s'\n"), str);
2035689857Sobrien  return 0;
2035789857Sobrien}
2035877298Sobrien
2035989857Sobrienstatic int
20360218822Sdimarm_parse_fpu (char * str)
2036189857Sobrien{
20362218822Sdim  const struct arm_option_cpu_value_table * opt;
2036377298Sobrien
2036489857Sobrien  for (opt = arm_fpus; opt->name != NULL; opt++)
20365218822Sdim    if (streq (opt->name, str))
2036689857Sobrien      {
20367218822Sdim	mfpu_opt = &opt->value;
2036889857Sobrien	return 1;
2036989857Sobrien      }
2037077298Sobrien
2037189857Sobrien  as_bad (_("unknown floating point format `%s'\n"), str);
2037289857Sobrien  return 0;
2037389857Sobrien}
2037477298Sobrien
20375130561Sobrienstatic int
20376218822Sdimarm_parse_float_abi (char * str)
20377130561Sobrien{
20378218822Sdim  const struct arm_option_value_table * opt;
20379130561Sobrien
20380130561Sobrien  for (opt = arm_float_abis; opt->name != NULL; opt++)
20381218822Sdim    if (streq (opt->name, str))
20382130561Sobrien      {
20383130561Sobrien	mfloat_abi_opt = opt->value;
20384130561Sobrien	return 1;
20385130561Sobrien      }
20386130561Sobrien
20387130561Sobrien  as_bad (_("unknown floating point abi `%s'\n"), str);
20388130561Sobrien  return 0;
20389130561Sobrien}
20390130561Sobrien
20391218822Sdim#ifdef OBJ_ELF
20392218822Sdimstatic int
20393218822Sdimarm_parse_eabi (char * str)
20394218822Sdim{
20395218822Sdim  const struct arm_option_value_table *opt;
20396218822Sdim
20397218822Sdim  for (opt = arm_eabis; opt->name != NULL; opt++)
20398218822Sdim    if (streq (opt->name, str))
20399218822Sdim      {
20400218822Sdim	meabi_flags = opt->value;
20401218822Sdim	return 1;
20402218822Sdim      }
20403218822Sdim  as_bad (_("unknown EABI `%s'\n"), str);
20404218822Sdim  return 0;
20405218822Sdim}
20406218822Sdim#endif
20407218822Sdim
2040889857Sobrienstruct arm_long_option_table arm_long_opts[] =
2040989857Sobrien{
2041089857Sobrien  {"mcpu=", N_("<cpu name>\t  assemble for CPU <cpu name>"),
2041189857Sobrien   arm_parse_cpu, NULL},
2041289857Sobrien  {"march=", N_("<arch name>\t  assemble for architecture <arch name>"),
2041389857Sobrien   arm_parse_arch, NULL},
2041489857Sobrien  {"mfpu=", N_("<fpu name>\t  assemble for FPU architecture <fpu name>"),
2041589857Sobrien   arm_parse_fpu, NULL},
20416130561Sobrien  {"mfloat-abi=", N_("<abi>\t  assemble for floating point ABI <abi>"),
20417130561Sobrien   arm_parse_float_abi, NULL},
20418218822Sdim#ifdef OBJ_ELF
20419218822Sdim  {"meabi=", N_("<ver>\t  assemble for eabi version <ver>"),
20420218822Sdim   arm_parse_eabi, NULL},
20421218822Sdim#endif
2042289857Sobrien  {NULL, NULL, 0, NULL}
2042389857Sobrien};
2042477298Sobrien
2042589857Sobrienint
20426218822Sdimmd_parse_option (int c, char * arg)
2042789857Sobrien{
2042889857Sobrien  struct arm_option_table *opt;
20429218822Sdim  const struct arm_legacy_option_table *fopt;
2043089857Sobrien  struct arm_long_option_table *lopt;
2043177298Sobrien
2043289857Sobrien  switch (c)
2043389857Sobrien    {
2043489857Sobrien#ifdef OPTION_EB
2043589857Sobrien    case OPTION_EB:
2043689857Sobrien      target_big_endian = 1;
2043789857Sobrien      break;
2043889857Sobrien#endif
2043960484Sobrien
2044089857Sobrien#ifdef OPTION_EL
2044189857Sobrien    case OPTION_EL:
2044289857Sobrien      target_big_endian = 0;
2044389857Sobrien      break;
2044489857Sobrien#endif
2044577298Sobrien
2044689857Sobrien    case 'a':
20447104834Sobrien      /* Listing option.  Just ignore these, we don't support additional
20448218822Sdim	 ones.	*/
2044989857Sobrien      return 0;
2045077298Sobrien
2045189857Sobrien    default:
2045289857Sobrien      for (opt = arm_opts; opt->option != NULL; opt++)
2045389857Sobrien	{
2045489857Sobrien	  if (c == opt->option[0]
2045589857Sobrien	      && ((arg == NULL && opt->option[1] == 0)
20456218822Sdim		  || streq (arg, opt->option + 1)))
2045789857Sobrien	    {
2045889857Sobrien#if WARN_DEPRECATED
2045989857Sobrien	      /* If the option is deprecated, tell the user.  */
2046089857Sobrien	      if (opt->deprecated != NULL)
2046189857Sobrien		as_tsktsk (_("option `-%c%s' is deprecated: %s"), c,
2046289857Sobrien			   arg ? arg : "", _(opt->deprecated));
2046389857Sobrien#endif
2046489857Sobrien
2046589857Sobrien	      if (opt->var != NULL)
2046689857Sobrien		*opt->var = opt->value;
2046789857Sobrien
2046889857Sobrien	      return 1;
2046960484Sobrien	    }
2047060484Sobrien	}
2047160484Sobrien
20472218822Sdim      for (fopt = arm_legacy_opts; fopt->option != NULL; fopt++)
20473218822Sdim	{
20474218822Sdim	  if (c == fopt->option[0]
20475218822Sdim	      && ((arg == NULL && fopt->option[1] == 0)
20476218822Sdim		  || streq (arg, fopt->option + 1)))
20477218822Sdim	    {
20478218822Sdim#if WARN_DEPRECATED
20479218822Sdim	      /* If the option is deprecated, tell the user.  */
20480218822Sdim	      if (fopt->deprecated != NULL)
20481218822Sdim		as_tsktsk (_("option `-%c%s' is deprecated: %s"), c,
20482218822Sdim			   arg ? arg : "", _(fopt->deprecated));
20483218822Sdim#endif
20484218822Sdim
20485218822Sdim	      if (fopt->var != NULL)
20486218822Sdim		*fopt->var = &fopt->value;
20487218822Sdim
20488218822Sdim	      return 1;
20489218822Sdim	    }
20490218822Sdim	}
20491218822Sdim
2049289857Sobrien      for (lopt = arm_long_opts; lopt->option != NULL; lopt++)
2049389857Sobrien	{
20494104834Sobrien	  /* These options are expected to have an argument.  */
2049589857Sobrien	  if (c == lopt->option[0]
2049689857Sobrien	      && arg != NULL
20497104834Sobrien	      && strncmp (arg, lopt->option + 1,
2049889857Sobrien			  strlen (lopt->option + 1)) == 0)
2049989857Sobrien	    {
2050089857Sobrien#if WARN_DEPRECATED
2050189857Sobrien	      /* If the option is deprecated, tell the user.  */
2050289857Sobrien	      if (lopt->deprecated != NULL)
2050389857Sobrien		as_tsktsk (_("option `-%c%s' is deprecated: %s"), c, arg,
2050489857Sobrien			   _(lopt->deprecated));
2050560484Sobrien#endif
2050677298Sobrien
2050789857Sobrien	      /* Call the sup-option parser.  */
20508218822Sdim	      return lopt->func (arg + strlen (lopt->option) - 1);
2050989857Sobrien	    }
2051089857Sobrien	}
2051189857Sobrien
2051260484Sobrien      return 0;
2051360484Sobrien    }
2051460484Sobrien
2051577298Sobrien  return 1;
2051660484Sobrien}
2051760484Sobrien
2051860484Sobrienvoid
20519218822Sdimmd_show_usage (FILE * fp)
2052060484Sobrien{
2052189857Sobrien  struct arm_option_table *opt;
2052289857Sobrien  struct arm_long_option_table *lopt;
2052389857Sobrien
2052489857Sobrien  fprintf (fp, _(" ARM-specific assembler options:\n"));
2052589857Sobrien
2052689857Sobrien  for (opt = arm_opts; opt->option != NULL; opt++)
2052789857Sobrien    if (opt->help != NULL)
2052889857Sobrien      fprintf (fp, "  -%-23s%s\n", opt->option, _(opt->help));
2052989857Sobrien
2053089857Sobrien  for (lopt = arm_long_opts; lopt->option != NULL; lopt++)
2053189857Sobrien    if (lopt->help != NULL)
2053289857Sobrien      fprintf (fp, "  -%s%s\n", lopt->option, _(lopt->help));
2053389857Sobrien
2053489857Sobrien#ifdef OPTION_EB
2053560484Sobrien  fprintf (fp, _("\
2053689857Sobrien  -EB                     assemble code for a big-endian cpu\n"));
2053777298Sobrien#endif
2053889857Sobrien
2053989857Sobrien#ifdef OPTION_EL
2054060484Sobrien  fprintf (fp, _("\
2054189857Sobrien  -EL                     assemble code for a little-endian cpu\n"));
2054260484Sobrien#endif
2054360484Sobrien}
2054460484Sobrien
2054560484Sobrien
20546218822Sdim#ifdef OBJ_ELF
20547218822Sdimtypedef struct
2054860484Sobrien{
20549218822Sdim  int val;
20550218822Sdim  arm_feature_set flags;
20551218822Sdim} cpu_arch_ver_table;
2055260484Sobrien
20553218822Sdim/* Mapping from CPU features to EABI CPU arch values.  Table must be sorted
20554218822Sdim   least features first.  */
20555218822Sdimstatic const cpu_arch_ver_table cpu_arch_ver[] =
2055660484Sobrien{
20557218822Sdim    {1, ARM_ARCH_V4},
20558218822Sdim    {2, ARM_ARCH_V4T},
20559218822Sdim    {3, ARM_ARCH_V5},
20560218822Sdim    {4, ARM_ARCH_V5TE},
20561218822Sdim    {5, ARM_ARCH_V5TEJ},
20562218822Sdim    {6, ARM_ARCH_V6},
20563218822Sdim    {7, ARM_ARCH_V6Z},
20564218822Sdim    {8, ARM_ARCH_V6K},
20565218822Sdim    {9, ARM_ARCH_V6T2},
20566218822Sdim    {10, ARM_ARCH_V7A},
20567218822Sdim    {10, ARM_ARCH_V7R},
20568218822Sdim    {10, ARM_ARCH_V7M},
20569218822Sdim    {0, ARM_ARCH_NONE}
20570218822Sdim};
2057177298Sobrien
20572218822Sdim/* Set the public EABI object attributes.  */
20573218822Sdimstatic void
20574218822Sdimaeabi_set_public_attributes (void)
2057560484Sobrien{
20576218822Sdim  int arch;
20577218822Sdim  arm_feature_set flags;
20578218822Sdim  arm_feature_set tmp;
20579218822Sdim  const cpu_arch_ver_table *p;
2058077298Sobrien
20581218822Sdim  /* Choose the architecture based on the capabilities of the requested cpu
20582218822Sdim     (if any) and/or the instructions actually used.  */
20583218822Sdim  ARM_MERGE_FEATURE_SETS (flags, arm_arch_used, thumb_arch_used);
20584218822Sdim  ARM_MERGE_FEATURE_SETS (flags, flags, *mfpu_opt);
20585218822Sdim  ARM_MERGE_FEATURE_SETS (flags, flags, selected_cpu);
20586218822Sdim  /*Allow the user to override the reported architecture.  */
20587218822Sdim  if (object_arch)
20588130561Sobrien    {
20589218822Sdim      ARM_CLEAR_FEATURE (flags, flags, arm_arch_any);
20590218822Sdim      ARM_MERGE_FEATURE_SETS (flags, flags, *object_arch);
20591130561Sobrien    }
2059260484Sobrien
20593218822Sdim  tmp = flags;
20594218822Sdim  arch = 0;
20595218822Sdim  for (p = cpu_arch_ver; p->val; p++)
2059660484Sobrien    {
20597218822Sdim      if (ARM_CPU_HAS_FEATURE (tmp, p->flags))
2059877298Sobrien	{
20599218822Sdim	  arch = p->val;
20600218822Sdim	  ARM_CLEAR_FEATURE (tmp, tmp, p->flags);
2060177298Sobrien	}
2060260484Sobrien    }
2060360484Sobrien
20604218822Sdim  /* Tag_CPU_name.  */
20605218822Sdim  if (selected_cpu_name[0])
2060660484Sobrien    {
20607218822Sdim      char *p;
20608218822Sdim
20609218822Sdim      p = selected_cpu_name;
20610218822Sdim      if (strncmp(p, "armv", 4) == 0)
2061177298Sobrien	{
20612218822Sdim	  int i;
20613218822Sdim
20614218822Sdim	  p += 4;
20615218822Sdim	  for (i = 0; p[i]; i++)
20616218822Sdim	    p[i] = TOUPPER (p[i]);
2061777298Sobrien	}
20618218822Sdim      bfd_elf_add_proc_attr_string (stdoutput, 5, p);
2061977298Sobrien    }
20620218822Sdim  /* Tag_CPU_arch.  */
20621218822Sdim  bfd_elf_add_proc_attr_int (stdoutput, 6, arch);
20622218822Sdim  /* Tag_CPU_arch_profile.  */
20623218822Sdim  if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7a))
20624218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 7, 'A');
20625218822Sdim  else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7r))
20626218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 7, 'R');
20627218822Sdim  else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7m))
20628218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 7, 'M');
20629218822Sdim  /* Tag_ARM_ISA_use.  */
20630218822Sdim  if (ARM_CPU_HAS_FEATURE (arm_arch_used, arm_arch_full))
20631218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 8, 1);
20632218822Sdim  /* Tag_THUMB_ISA_use.  */
20633218822Sdim  if (ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_full))
20634218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 9,
20635218822Sdim	ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_t2) ? 2 : 1);
20636218822Sdim  /* Tag_VFP_arch.  */
20637218822Sdim  if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v3)
20638218822Sdim      || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v3))
20639218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 10, 3);
20640218822Sdim  else if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v2)
20641218822Sdim           || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v2))
20642218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 10, 2);
20643218822Sdim  else if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v1)
20644218822Sdim           || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v1)
20645218822Sdim           || ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v1xd)
20646218822Sdim           || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v1xd))
20647218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 10, 1);
20648218822Sdim  /* Tag_WMMX_arch.  */
20649218822Sdim  if (ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_cext_iwmmxt)
20650218822Sdim      || ARM_CPU_HAS_FEATURE (arm_arch_used, arm_cext_iwmmxt))
20651218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 11, 1);
20652218822Sdim  /* Tag_NEON_arch.  */
20653218822Sdim  if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_neon_ext_v1)
20654218822Sdim      || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_neon_ext_v1))
20655218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 12, 1);
2065660484Sobrien}
2065760484Sobrien
20658218822Sdim/* Add the default contents for the .ARM.attributes section.  */
20659218822Sdimvoid
20660218822Sdimarm_md_end (void)
2066160484Sobrien{
20662218822Sdim  if (EF_ARM_EABI_VERSION (meabi_flags) < EF_ARM_EABI_VER4)
20663218822Sdim    return;
2066477298Sobrien
20665218822Sdim  aeabi_set_public_attributes ();
2066660484Sobrien}
20667218822Sdim#endif /* OBJ_ELF */
2066860484Sobrien
2066960484Sobrien
20670218822Sdim/* Parse a .cpu directive.  */
2067160484Sobrien
20672218822Sdimstatic void
20673218822Sdims_arm_cpu (int ignored ATTRIBUTE_UNUSED)
2067460484Sobrien{
20675218822Sdim  const struct arm_cpu_option_table *opt;
20676218822Sdim  char *name;
20677218822Sdim  char saved_char;
2067860484Sobrien
20679218822Sdim  name = input_line_pointer;
20680218822Sdim  while (*input_line_pointer && !ISSPACE(*input_line_pointer))
20681218822Sdim    input_line_pointer++;
20682218822Sdim  saved_char = *input_line_pointer;
20683218822Sdim  *input_line_pointer = 0;
20684130561Sobrien
20685218822Sdim  /* Skip the first "all" entry.  */
20686218822Sdim  for (opt = arm_cpus + 1; opt->name != NULL; opt++)
20687218822Sdim    if (streq (opt->name, name))
20688218822Sdim      {
20689218822Sdim	mcpu_cpu_opt = &opt->value;
20690218822Sdim	selected_cpu = opt->value;
20691218822Sdim	if (opt->canonical_name)
20692218822Sdim	  strcpy(selected_cpu_name, opt->canonical_name);
20693218822Sdim	else
20694218822Sdim	  {
20695218822Sdim	    int i;
20696218822Sdim	    for (i = 0; opt->name[i]; i++)
20697218822Sdim	      selected_cpu_name[i] = TOUPPER (opt->name[i]);
20698218822Sdim	    selected_cpu_name[i] = 0;
20699218822Sdim	  }
20700218822Sdim	ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
20701218822Sdim	*input_line_pointer = saved_char;
20702218822Sdim	demand_empty_rest_of_line ();
20703218822Sdim	return;
20704218822Sdim      }
20705218822Sdim  as_bad (_("unknown cpu `%s'"), name);
20706218822Sdim  *input_line_pointer = saved_char;
20707218822Sdim  ignore_rest_of_line ();
2070860484Sobrien}
2070960484Sobrien
2071077298Sobrien
20711218822Sdim/* Parse a .arch directive.  */
20712130561Sobrien
20713218822Sdimstatic void
20714218822Sdims_arm_arch (int ignored ATTRIBUTE_UNUSED)
2071560484Sobrien{
20716218822Sdim  const struct arm_arch_option_table *opt;
20717218822Sdim  char saved_char;
20718218822Sdim  char *name;
2071977298Sobrien
20720218822Sdim  name = input_line_pointer;
20721218822Sdim  while (*input_line_pointer && !ISSPACE(*input_line_pointer))
20722218822Sdim    input_line_pointer++;
20723218822Sdim  saved_char = *input_line_pointer;
20724218822Sdim  *input_line_pointer = 0;
2072577298Sobrien
20726218822Sdim  /* Skip the first "all" entry.  */
20727218822Sdim  for (opt = arm_archs + 1; opt->name != NULL; opt++)
20728218822Sdim    if (streq (opt->name, name))
20729218822Sdim      {
20730218822Sdim	mcpu_cpu_opt = &opt->value;
20731218822Sdim	selected_cpu = opt->value;
20732218822Sdim	strcpy(selected_cpu_name, opt->name);
20733218822Sdim	ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
20734218822Sdim	*input_line_pointer = saved_char;
20735218822Sdim	demand_empty_rest_of_line ();
20736218822Sdim	return;
20737218822Sdim      }
2073860484Sobrien
20739218822Sdim  as_bad (_("unknown architecture `%s'\n"), name);
20740218822Sdim  *input_line_pointer = saved_char;
20741218822Sdim  ignore_rest_of_line ();
2074260484Sobrien}
2074360484Sobrien
2074460484Sobrien
20745218822Sdim/* Parse a .object_arch directive.  */
2074660484Sobrien
2074760484Sobrienstatic void
20748218822Sdims_arm_object_arch (int ignored ATTRIBUTE_UNUSED)
2074960484Sobrien{
20750218822Sdim  const struct arm_arch_option_table *opt;
20751218822Sdim  char saved_char;
20752218822Sdim  char *name;
2075360484Sobrien
20754218822Sdim  name = input_line_pointer;
20755218822Sdim  while (*input_line_pointer && !ISSPACE(*input_line_pointer))
20756218822Sdim    input_line_pointer++;
20757218822Sdim  saved_char = *input_line_pointer;
20758218822Sdim  *input_line_pointer = 0;
2075960484Sobrien
20760218822Sdim  /* Skip the first "all" entry.  */
20761218822Sdim  for (opt = arm_archs + 1; opt->name != NULL; opt++)
20762218822Sdim    if (streq (opt->name, name))
20763218822Sdim      {
20764218822Sdim	object_arch = &opt->value;
20765218822Sdim	*input_line_pointer = saved_char;
20766218822Sdim	demand_empty_rest_of_line ();
20767218822Sdim	return;
20768218822Sdim      }
2076960484Sobrien
20770218822Sdim  as_bad (_("unknown architecture `%s'\n"), name);
20771218822Sdim  *input_line_pointer = saved_char;
20772218822Sdim  ignore_rest_of_line ();
2077360484Sobrien}
2077460484Sobrien
2077578828Sobrien
20776218822Sdim/* Parse a .fpu directive.  */
2077778828Sobrien
20778218822Sdimstatic void
20779218822Sdims_arm_fpu (int ignored ATTRIBUTE_UNUSED)
2078078828Sobrien{
20781218822Sdim  const struct arm_option_cpu_value_table *opt;
20782218822Sdim  char saved_char;
20783218822Sdim  char *name;
2078478828Sobrien
20785218822Sdim  name = input_line_pointer;
20786218822Sdim  while (*input_line_pointer && !ISSPACE(*input_line_pointer))
20787218822Sdim    input_line_pointer++;
20788218822Sdim  saved_char = *input_line_pointer;
20789218822Sdim  *input_line_pointer = 0;
20790218822Sdim
20791218822Sdim  for (opt = arm_fpus; opt->name != NULL; opt++)
20792218822Sdim    if (streq (opt->name, name))
20793218822Sdim      {
20794218822Sdim	mfpu_opt = &opt->value;
20795218822Sdim	ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
20796218822Sdim	*input_line_pointer = saved_char;
20797218822Sdim	demand_empty_rest_of_line ();
20798218822Sdim	return;
20799218822Sdim      }
20800104834Sobrien
20801218822Sdim  as_bad (_("unknown floating point format `%s'\n"), name);
20802218822Sdim  *input_line_pointer = saved_char;
20803218822Sdim  ignore_rest_of_line ();
2080478828Sobrien}
2080578828Sobrien
20806218822Sdim/* Copy symbol information.  */
2080778828Sobrienvoid
20808218822Sdimarm_copy_symbol_attributes (symbolS *dest, symbolS *src)
2080978828Sobrien{
20810218822Sdim  ARM_GET_FLAG (dest) = ARM_GET_FLAG (src);
2081178828Sobrien}
20812