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
2287300333Spfgstatic void
2288300333Spfgs_inst(int unused ATTRIBUTE_UNUSED)
2289300333Spfg{
2290300333Spfg	expressionS exp;
2291300333Spfg
2292300333Spfg	if (thumb_mode) {
2293300333Spfg		as_bad(".inst not implemented for Thumb mode");
2294300333Spfg		ignore_rest_of_line();
2295300333Spfg		return;
2296300333Spfg	}
2297300333Spfg
2298300333Spfg	if (is_it_end_of_statement()) {
2299300333Spfg		demand_empty_rest_of_line();
2300300333Spfg		return;
2301300333Spfg	}
2302300333Spfg
2303300333Spfg	do {
2304300333Spfg		expression(&exp);
2305300333Spfg
2306300333Spfg		if (exp.X_op != O_constant)
2307300333Spfg			as_bad("constant expression required");
2308300333Spfg		else
2309300333Spfg			emit_expr(&exp, 4);
2310300333Spfg
2311300333Spfg	} while (*input_line_pointer++ == ',');
2312300333Spfg
2313300333Spfg	/* Put terminator back into stream. */
2314300333Spfg	input_line_pointer--;
2315300333Spfg	demand_empty_rest_of_line();
2316300333Spfg}
2317300333Spfg
2318218822Sdim/* Directives: Instruction set selection.  */
2319130561Sobrien
2320218822Sdim#ifdef OBJ_ELF
2321218822Sdim/* This code is to handle mapping symbols as defined in the ARM ELF spec.
2322218822Sdim   (See "Mapping symbols", section 4.5.5, ARM AAELF version 1.0).
2323218822Sdim   Note that previously, $a and $t has type STT_FUNC (BSF_OBJECT flag),
2324218822Sdim   and $d has type STT_OBJECT (BSF_OBJECT flag). Now all three are untyped.  */
2325130561Sobrien
2326130561Sobrienstatic enum mstate mapstate = MAP_UNDEFINED;
2327130561Sobrien
2328218822Sdimvoid
2329130561Sobrienmapping_state (enum mstate state)
2330130561Sobrien{
2331130561Sobrien  symbolS * symbolP;
2332130561Sobrien  const char * symname;
2333130561Sobrien  int type;
2334130561Sobrien
2335130561Sobrien  if (mapstate == state)
2336130561Sobrien    /* The mapping symbol has already been emitted.
2337130561Sobrien       There is nothing else to do.  */
2338130561Sobrien    return;
2339130561Sobrien
2340130561Sobrien  mapstate = state;
2341130561Sobrien
2342130561Sobrien  switch (state)
2343130561Sobrien    {
2344130561Sobrien    case MAP_DATA:
2345130561Sobrien      symname = "$d";
2346218822Sdim      type = BSF_NO_FLAGS;
2347130561Sobrien      break;
2348130561Sobrien    case MAP_ARM:
2349130561Sobrien      symname = "$a";
2350218822Sdim      type = BSF_NO_FLAGS;
2351130561Sobrien      break;
2352130561Sobrien    case MAP_THUMB:
2353130561Sobrien      symname = "$t";
2354218822Sdim      type = BSF_NO_FLAGS;
2355130561Sobrien      break;
2356130561Sobrien    case MAP_UNDEFINED:
2357218822Sdim      return;
2358130561Sobrien    default:
2359130561Sobrien      abort ();
2360130561Sobrien    }
2361130561Sobrien
2362218822Sdim  seg_info (now_seg)->tc_segment_info_data.mapstate = state;
2363130561Sobrien
2364130561Sobrien  symbolP = symbol_new (symname, now_seg, (valueT) frag_now_fix (), frag_now);
2365130561Sobrien  symbol_table_insert (symbolP);
2366130561Sobrien  symbol_get_bfdsym (symbolP)->flags |= type | BSF_LOCAL;
2367218822Sdim
2368130561Sobrien  switch (state)
2369130561Sobrien    {
2370130561Sobrien    case MAP_ARM:
2371130561Sobrien      THUMB_SET_FUNC (symbolP, 0);
2372130561Sobrien      ARM_SET_THUMB (symbolP, 0);
2373130561Sobrien      ARM_SET_INTERWORK (symbolP, support_interwork);
2374130561Sobrien      break;
2375218822Sdim
2376130561Sobrien    case MAP_THUMB:
2377130561Sobrien      THUMB_SET_FUNC (symbolP, 1);
2378130561Sobrien      ARM_SET_THUMB (symbolP, 1);
2379130561Sobrien      ARM_SET_INTERWORK (symbolP, support_interwork);
2380130561Sobrien      break;
2381218822Sdim
2382130561Sobrien    case MAP_DATA:
2383130561Sobrien    default:
2384130561Sobrien      return;
2385130561Sobrien    }
2386130561Sobrien}
2387218822Sdim#else
2388218822Sdim#define mapping_state(x) /* nothing */
2389218822Sdim#endif
2390130561Sobrien
2391218822Sdim/* Find the real, Thumb encoded start of a Thumb function.  */
2392130561Sobrien
2393218822Sdimstatic symbolS *
2394218822Sdimfind_real_start (symbolS * symbolP)
2395130561Sobrien{
2396218822Sdim  char *       real_start;
2397218822Sdim  const char * name = S_GET_NAME (symbolP);
2398218822Sdim  symbolS *    new_target;
2399130561Sobrien
2400218822Sdim  /* This definition must agree with the one in gcc/config/arm/thumb.c.	 */
2401218822Sdim#define STUB_NAME ".real_start_of"
2402130561Sobrien
2403218822Sdim  if (name == NULL)
2404218822Sdim    abort ();
2405130561Sobrien
2406218822Sdim  /* The compiler may generate BL instructions to local labels because
2407218822Sdim     it needs to perform a branch to a far away location. These labels
2408218822Sdim     do not have a corresponding ".real_start_of" label.  We check
2409218822Sdim     both for S_IS_LOCAL and for a leading dot, to give a way to bypass
2410218822Sdim     the ".real_start_of" convention for nonlocal branches.  */
2411218822Sdim  if (S_IS_LOCAL (symbolP) || name[0] == '.')
2412218822Sdim    return symbolP;
2413130561Sobrien
2414218822Sdim  real_start = ACONCAT ((STUB_NAME, name, NULL));
2415218822Sdim  new_target = symbol_find (real_start);
2416130561Sobrien
2417218822Sdim  if (new_target == NULL)
2418218822Sdim    {
2419218822Sdim      as_warn ("Failed to find real start of function: %s\n", name);
2420218822Sdim      new_target = symbolP;
2421218822Sdim    }
2422218822Sdim
2423218822Sdim  return new_target;
242460484Sobrien}
242560484Sobrien
242660484Sobrienstatic void
2427218822Sdimopcode_select (int width)
2428130561Sobrien{
2429218822Sdim  switch (width)
2430218822Sdim    {
2431218822Sdim    case 16:
2432218822Sdim      if (! thumb_mode)
2433218822Sdim	{
2434218822Sdim	  if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v4t))
2435218822Sdim	    as_bad (_("selected processor does not support THUMB opcodes"));
2436130561Sobrien
2437218822Sdim	  thumb_mode = 1;
2438218822Sdim	  /* No need to force the alignment, since we will have been
2439218822Sdim	     coming from ARM mode, which is word-aligned.  */
2440218822Sdim	  record_alignment (now_seg, 1);
2441218822Sdim	}
2442218822Sdim      mapping_state (MAP_THUMB);
2443218822Sdim      break;
2444130561Sobrien
2445218822Sdim    case 32:
2446218822Sdim      if (thumb_mode)
2447130561Sobrien	{
2448218822Sdim	  if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1))
2449218822Sdim	    as_bad (_("selected processor does not support ARM opcodes"));
2450130561Sobrien
2451218822Sdim	  thumb_mode = 0;
2452130561Sobrien
2453218822Sdim	  if (!need_pass_2)
2454218822Sdim	    frag_align (2, 0, 0);
2455130561Sobrien
2456218822Sdim	  record_alignment (now_seg, 1);
2457130561Sobrien	}
2458218822Sdim      mapping_state (MAP_ARM);
2459218822Sdim      break;
2460218822Sdim
2461218822Sdim    default:
2462218822Sdim      as_bad (_("invalid instruction size selected (%d)"), width);
2463130561Sobrien    }
2464130561Sobrien}
2465130561Sobrien
2466130561Sobrienstatic void
2467218822Sdims_arm (int ignore ATTRIBUTE_UNUSED)
246860484Sobrien{
2469218822Sdim  opcode_select (32);
247060484Sobrien  demand_empty_rest_of_line ();
247160484Sobrien}
247260484Sobrien
247360484Sobrienstatic void
2474218822Sdims_thumb (int ignore ATTRIBUTE_UNUSED)
247560484Sobrien{
2476218822Sdim  opcode_select (16);
247760484Sobrien  demand_empty_rest_of_line ();
247860484Sobrien}
247960484Sobrien
248060484Sobrienstatic void
2481218822Sdims_code (int unused ATTRIBUTE_UNUSED)
248260484Sobrien{
2483218822Sdim  int temp;
248460484Sobrien
248560484Sobrien  temp = get_absolute_expression ();
2486218822Sdim  switch (temp)
248760484Sobrien    {
2488218822Sdim    case 16:
2489218822Sdim    case 32:
2490218822Sdim      opcode_select (temp);
2491218822Sdim      break;
249260484Sobrien
2493218822Sdim    default:
2494218822Sdim      as_bad (_("invalid operand to .code directive (%d) (expecting 16 or 32)"), temp);
249560484Sobrien    }
249660484Sobrien}
249760484Sobrien
249860484Sobrienstatic void
2499218822Sdims_force_thumb (int ignore ATTRIBUTE_UNUSED)
250060484Sobrien{
250160484Sobrien  /* If we are not already in thumb mode go into it, EVEN if
250260484Sobrien     the target processor does not support thumb instructions.
250360484Sobrien     This is used by gcc/config/arm/lib1funcs.asm for example
250460484Sobrien     to compile interworking support functions even if the
2505218822Sdim     target processor should not support interworking.	*/
250660484Sobrien  if (! thumb_mode)
250760484Sobrien    {
250860484Sobrien      thumb_mode = 2;
250960484Sobrien      record_alignment (now_seg, 1);
251060484Sobrien    }
251177298Sobrien
251260484Sobrien  demand_empty_rest_of_line ();
251360484Sobrien}
251460484Sobrien
251560484Sobrienstatic void
2516218822Sdims_thumb_func (int ignore ATTRIBUTE_UNUSED)
251760484Sobrien{
2518218822Sdim  s_thumb (0);
251977298Sobrien
252060484Sobrien  /* The following label is the name/address of the start of a Thumb function.
2521218822Sdim     We need to know this for the interworking support.	 */
2522130561Sobrien  label_is_thumb_function_name = TRUE;
252360484Sobrien}
252460484Sobrien
252560484Sobrien/* Perform a .set directive, but also mark the alias as
252660484Sobrien   being a thumb function.  */
252760484Sobrien
252860484Sobrienstatic void
2529218822Sdims_thumb_set (int equiv)
253060484Sobrien{
253160484Sobrien  /* XXX the following is a duplicate of the code for s_set() in read.c
253260484Sobrien     We cannot just call that code as we need to get at the symbol that
253360484Sobrien     is created.  */
2534218822Sdim  char *    name;
2535218822Sdim  char	    delim;
2536218822Sdim  char *    end_name;
2537218822Sdim  symbolS * symbolP;
253860484Sobrien
253977298Sobrien  /* Especial apologies for the random logic:
254077298Sobrien     This just grew, and could be parsed much more simply!
254177298Sobrien     Dean - in haste.  */
2542218822Sdim  name	    = input_line_pointer;
2543218822Sdim  delim	    = get_symbol_end ();
254460484Sobrien  end_name  = input_line_pointer;
254560484Sobrien  *end_name = delim;
254677298Sobrien
254760484Sobrien  if (*input_line_pointer != ',')
254860484Sobrien    {
254960484Sobrien      *end_name = 0;
255089857Sobrien      as_bad (_("expected comma after name \"%s\""), name);
255160484Sobrien      *end_name = delim;
255260484Sobrien      ignore_rest_of_line ();
255360484Sobrien      return;
255460484Sobrien    }
255560484Sobrien
255660484Sobrien  input_line_pointer++;
255760484Sobrien  *end_name = 0;
255860484Sobrien
255960484Sobrien  if (name[0] == '.' && name[1] == '\0')
256060484Sobrien    {
256177298Sobrien      /* XXX - this should not happen to .thumb_set.  */
256260484Sobrien      abort ();
256360484Sobrien    }
256460484Sobrien
256560484Sobrien  if ((symbolP = symbol_find (name)) == NULL
256660484Sobrien      && (symbolP = md_undefined_symbol (name)) == NULL)
256760484Sobrien    {
256860484Sobrien#ifndef NO_LISTING
256960484Sobrien      /* When doing symbol listings, play games with dummy fragments living
257060484Sobrien	 outside the normal fragment chain to record the file and line info
2571218822Sdim	 for this symbol.  */
257260484Sobrien      if (listing & LISTING_SYMBOLS)
257360484Sobrien	{
257460484Sobrien	  extern struct list_info_struct * listing_tail;
2575218822Sdim	  fragS * dummy_frag = xmalloc (sizeof (fragS));
257677298Sobrien
257777298Sobrien	  memset (dummy_frag, 0, sizeof (fragS));
257860484Sobrien	  dummy_frag->fr_type = rs_fill;
257960484Sobrien	  dummy_frag->line = listing_tail;
258060484Sobrien	  symbolP = symbol_new (name, undefined_section, 0, dummy_frag);
258160484Sobrien	  dummy_frag->fr_symbol = symbolP;
258260484Sobrien	}
258360484Sobrien      else
258460484Sobrien#endif
258577298Sobrien	symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag);
258677298Sobrien
258760484Sobrien#ifdef OBJ_COFF
258877298Sobrien      /* "set" symbols are local unless otherwise specified.  */
258960484Sobrien      SF_SET_LOCAL (symbolP);
259077298Sobrien#endif /* OBJ_COFF  */
259177298Sobrien    }				/* Make a new symbol.  */
259260484Sobrien
259360484Sobrien  symbol_table_insert (symbolP);
259460484Sobrien
259560484Sobrien  * end_name = delim;
259660484Sobrien
259760484Sobrien  if (equiv
259860484Sobrien      && S_IS_DEFINED (symbolP)
259960484Sobrien      && S_GET_SEGMENT (symbolP) != reg_section)
260060484Sobrien    as_bad (_("symbol `%s' already defined"), S_GET_NAME (symbolP));
260160484Sobrien
260260484Sobrien  pseudo_set (symbolP);
260377298Sobrien
260460484Sobrien  demand_empty_rest_of_line ();
260560484Sobrien
2606218822Sdim  /* XXX Now we come to the Thumb specific bit of code.	 */
260777298Sobrien
260860484Sobrien  THUMB_SET_FUNC (symbolP, 1);
260960484Sobrien  ARM_SET_THUMB (symbolP, 1);
261060484Sobrien#if defined OBJ_ELF || defined OBJ_COFF
261160484Sobrien  ARM_SET_INTERWORK (symbolP, support_interwork);
261260484Sobrien#endif
261360484Sobrien}
261460484Sobrien
2615218822Sdim/* Directives: Mode selection.  */
2616218822Sdim
2617218822Sdim/* .syntax [unified|divided] - choose the new unified syntax
2618218822Sdim   (same for Arm and Thumb encoding, modulo slight differences in what
2619218822Sdim   can be represented) or the old divergent syntax for each mode.  */
262060484Sobrienstatic void
2621218822Sdims_syntax (int unused ATTRIBUTE_UNUSED)
262260484Sobrien{
2623218822Sdim  char *name, delim;
262477298Sobrien
2625218822Sdim  name = input_line_pointer;
2626218822Sdim  delim = get_symbol_end ();
262760484Sobrien
2628218822Sdim  if (!strcasecmp (name, "unified"))
2629218822Sdim    unified_syntax = TRUE;
2630218822Sdim  else if (!strcasecmp (name, "divided"))
2631218822Sdim    unified_syntax = FALSE;
2632218822Sdim  else
2633218822Sdim    {
2634218822Sdim      as_bad (_("unrecognized syntax mode \"%s\""), name);
2635218822Sdim      return;
263660484Sobrien    }
2637218822Sdim  *input_line_pointer = delim;
263860484Sobrien  demand_empty_rest_of_line ();
263960484Sobrien}
264060484Sobrien
2641218822Sdim/* Directives: sectioning and alignment.  */
264260484Sobrien
2643218822Sdim/* Same as s_align_ptwo but align 0 => align 2.	 */
2644218822Sdim
264560484Sobrienstatic void
2646218822Sdims_align (int unused ATTRIBUTE_UNUSED)
264760484Sobrien{
2648218822Sdim  int temp;
2649218822Sdim  bfd_boolean fill_p;
2650218822Sdim  long temp_fill;
2651218822Sdim  long max_alignment = 15;
265260484Sobrien
265360484Sobrien  temp = get_absolute_expression ();
2654218822Sdim  if (temp > max_alignment)
2655218822Sdim    as_bad (_("alignment too large: %d assumed"), temp = max_alignment);
2656218822Sdim  else if (temp < 0)
265760484Sobrien    {
2658218822Sdim      as_bad (_("alignment negative. 0 assumed."));
2659218822Sdim      temp = 0;
2660218822Sdim    }
266160484Sobrien
2662218822Sdim  if (*input_line_pointer == ',')
2663218822Sdim    {
2664218822Sdim      input_line_pointer++;
2665218822Sdim      temp_fill = get_absolute_expression ();
2666218822Sdim      fill_p = TRUE;
266760484Sobrien    }
2668218822Sdim  else
2669218822Sdim    {
2670218822Sdim      fill_p = FALSE;
2671218822Sdim      temp_fill = 0;
2672218822Sdim    }
267360484Sobrien
2674218822Sdim  if (!temp)
2675218822Sdim    temp = 2;
267660484Sobrien
2677218822Sdim  /* Only make a frag if we HAVE to.  */
2678218822Sdim  if (temp && !need_pass_2)
267960484Sobrien    {
2680218822Sdim      if (!fill_p && subseg_text_p (now_seg))
2681218822Sdim	frag_align_code (temp, 0);
2682218822Sdim      else
2683218822Sdim	frag_align (temp, (int) temp_fill, 0);
268460484Sobrien    }
2685218822Sdim  demand_empty_rest_of_line ();
268660484Sobrien
2687218822Sdim  record_alignment (now_seg, temp);
2688218822Sdim}
268960484Sobrien
2690218822Sdimstatic void
2691218822Sdims_bss (int ignore ATTRIBUTE_UNUSED)
2692218822Sdim{
2693218822Sdim  /* We don't support putting frags in the BSS segment, we fake it by
2694218822Sdim     marking in_bss, then looking at s_skip for clues.	*/
2695218822Sdim  subseg_set (bss_section, 0);
2696218822Sdim  demand_empty_rest_of_line ();
2697218822Sdim  mapping_state (MAP_DATA);
269860484Sobrien}
269960484Sobrien
2700218822Sdimstatic void
2701218822Sdims_even (int ignore ATTRIBUTE_UNUSED)
270260484Sobrien{
2703218822Sdim  /* Never make frag if expect extra pass.  */
2704218822Sdim  if (!need_pass_2)
2705218822Sdim    frag_align (1, 0, 0);
270660484Sobrien
2707218822Sdim  record_alignment (now_seg, 1);
270860484Sobrien
2709218822Sdim  demand_empty_rest_of_line ();
271060484Sobrien}
271160484Sobrien
2712218822Sdim/* Directives: Literal pools.  */
2713130561Sobrien
2714218822Sdimstatic literal_pool *
2715218822Sdimfind_literal_pool (void)
2716130561Sobrien{
2717218822Sdim  literal_pool * pool;
2718130561Sobrien
2719218822Sdim  for (pool = list_of_pools; pool != NULL; pool = pool->next)
2720130561Sobrien    {
2721218822Sdim      if (pool->section == now_seg
2722218822Sdim	  && pool->sub_section == now_subseg)
2723218822Sdim	break;
2724130561Sobrien    }
2725130561Sobrien
2726218822Sdim  return pool;
2727130561Sobrien}
2728130561Sobrien
2729218822Sdimstatic literal_pool *
2730218822Sdimfind_or_make_literal_pool (void)
273161843Sobrien{
2732218822Sdim  /* Next literal pool ID number.  */
2733218822Sdim  static unsigned int latest_pool_num = 1;
2734218822Sdim  literal_pool *      pool;
273561843Sobrien
2736218822Sdim  pool = find_literal_pool ();
273761843Sobrien
2738218822Sdim  if (pool == NULL)
273961843Sobrien    {
2740218822Sdim      /* Create a new pool.  */
2741218822Sdim      pool = xmalloc (sizeof (* pool));
2742218822Sdim      if (! pool)
2743218822Sdim	return NULL;
274461843Sobrien
2745218822Sdim      pool->next_free_entry = 0;
2746218822Sdim      pool->section	    = now_seg;
2747218822Sdim      pool->sub_section	    = now_subseg;
2748218822Sdim      pool->next	    = list_of_pools;
2749218822Sdim      pool->symbol	    = NULL;
275061843Sobrien
2751218822Sdim      /* Add it to the list.  */
2752218822Sdim      list_of_pools = pool;
2753218822Sdim    }
275477298Sobrien
2755218822Sdim  /* New pools, and emptied pools, will have a NULL symbol.  */
2756218822Sdim  if (pool->symbol == NULL)
2757218822Sdim    {
2758218822Sdim      pool->symbol = symbol_create (FAKE_LABEL_NAME, undefined_section,
2759218822Sdim				    (valueT) 0, &zero_address_frag);
2760218822Sdim      pool->id = latest_pool_num ++;
2761218822Sdim    }
276261843Sobrien
2763218822Sdim  /* Done.  */
2764218822Sdim  return pool;
276561843Sobrien}
276661843Sobrien
2767218822Sdim/* Add the literal in the global 'inst'
2768218822Sdim   structure to the relevent literal pool.  */
276977298Sobrien
277060484Sobrienstatic int
2771218822Sdimadd_to_lit_pool (void)
277260484Sobrien{
2773218822Sdim  literal_pool * pool;
2774218822Sdim  unsigned int entry;
277577298Sobrien
2776218822Sdim  pool = find_or_make_literal_pool ();
277761843Sobrien
2778218822Sdim  /* Check if this literal value is already in the pool.  */
2779218822Sdim  for (entry = 0; entry < pool->next_free_entry; entry ++)
278060484Sobrien    {
2781218822Sdim      if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
2782218822Sdim	  && (inst.reloc.exp.X_op == O_constant)
2783218822Sdim	  && (pool->literals[entry].X_add_number
2784218822Sdim	      == inst.reloc.exp.X_add_number)
2785218822Sdim	  && (pool->literals[entry].X_unsigned
2786218822Sdim	      == inst.reloc.exp.X_unsigned))
2787218822Sdim	break;
278861843Sobrien
2789218822Sdim      if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
2790218822Sdim	  && (inst.reloc.exp.X_op == O_symbol)
2791218822Sdim	  && (pool->literals[entry].X_add_number
2792218822Sdim	      == inst.reloc.exp.X_add_number)
2793218822Sdim	  && (pool->literals[entry].X_add_symbol
2794218822Sdim	      == inst.reloc.exp.X_add_symbol)
2795218822Sdim	  && (pool->literals[entry].X_op_symbol
2796218822Sdim	      == inst.reloc.exp.X_op_symbol))
2797218822Sdim	break;
279860484Sobrien    }
279960484Sobrien
2800218822Sdim  /* Do we need to create a new entry?	*/
2801218822Sdim  if (entry == pool->next_free_entry)
280289857Sobrien    {
2803218822Sdim      if (entry >= MAX_LITERAL_POOL_SIZE)
280460484Sobrien	{
2805218822Sdim	  inst.error = _("literal pool overflow");
280689857Sobrien	  return FAIL;
280789857Sobrien	}
2808218822Sdim
2809218822Sdim      pool->literals[entry] = inst.reloc.exp;
2810218822Sdim      pool->next_free_entry += 1;
281160484Sobrien    }
281260484Sobrien
2813218822Sdim  inst.reloc.exp.X_op	      = O_symbol;
2814218822Sdim  inst.reloc.exp.X_add_number = ((int) entry) * 4;
2815218822Sdim  inst.reloc.exp.X_add_symbol = pool->symbol;
2816218822Sdim
281760484Sobrien  return SUCCESS;
281860484Sobrien}
281960484Sobrien
2820218822Sdim/* Can't use symbol_new here, so have to create a symbol and then at
2821218822Sdim   a later date assign it a value. Thats what these functions do.  */
2822218822Sdim
2823218822Sdimstatic void
2824218822Sdimsymbol_locate (symbolS *    symbolP,
2825218822Sdim	       const char * name,	/* It is copied, the caller can modify.	 */
2826218822Sdim	       segT	    segment,	/* Segment identifier (SEG_<something>).  */
2827218822Sdim	       valueT	    valu,	/* Symbol value.  */
2828218822Sdim	       fragS *	    frag)	/* Associated fragment.	 */
282960484Sobrien{
2830218822Sdim  unsigned int name_length;
2831218822Sdim  char * preserved_copy_of_name;
283260484Sobrien
2833218822Sdim  name_length = strlen (name) + 1;   /* +1 for \0.  */
2834218822Sdim  obstack_grow (&notes, name, name_length);
2835218822Sdim  preserved_copy_of_name = obstack_finish (&notes);
283660484Sobrien
2837218822Sdim#ifdef tc_canonicalize_symbol_name
2838218822Sdim  preserved_copy_of_name =
2839218822Sdim    tc_canonicalize_symbol_name (preserved_copy_of_name);
2840218822Sdim#endif
284160484Sobrien
2842218822Sdim  S_SET_NAME (symbolP, preserved_copy_of_name);
284360484Sobrien
2844218822Sdim  S_SET_SEGMENT (symbolP, segment);
2845218822Sdim  S_SET_VALUE (symbolP, valu);
2846218822Sdim  symbol_clear_list_pointers (symbolP);
284760484Sobrien
2848218822Sdim  symbol_set_frag (symbolP, frag);
284960484Sobrien
2850218822Sdim  /* Link to end of symbol chain.  */
2851218822Sdim  {
2852218822Sdim    extern int symbol_table_frozen;
285360484Sobrien
2854218822Sdim    if (symbol_table_frozen)
2855218822Sdim      abort ();
2856218822Sdim  }
285760484Sobrien
2858218822Sdim  symbol_append (symbolP, symbol_lastP, & symbol_rootP, & symbol_lastP);
285960484Sobrien
2860218822Sdim  obj_symbol_new_hook (symbolP);
286160484Sobrien
2862218822Sdim#ifdef tc_symbol_new_hook
2863218822Sdim  tc_symbol_new_hook (symbolP);
2864218822Sdim#endif
286560484Sobrien
2866218822Sdim#ifdef DEBUG_SYMS
2867218822Sdim  verify_symbol_chain (symbol_rootP, symbol_lastP);
2868218822Sdim#endif /* DEBUG_SYMS  */
2869218822Sdim}
287060484Sobrien
287160484Sobrien
2872218822Sdimstatic void
2873218822Sdims_ltorg (int ignored ATTRIBUTE_UNUSED)
287460484Sobrien{
2875218822Sdim  unsigned int entry;
2876218822Sdim  literal_pool * pool;
2877218822Sdim  char sym_name[20];
287860484Sobrien
2879218822Sdim  pool = find_literal_pool ();
2880218822Sdim  if (pool == NULL
2881218822Sdim      || pool->symbol == NULL
2882218822Sdim      || pool->next_free_entry == 0)
2883218822Sdim    return;
288460484Sobrien
2885218822Sdim  mapping_state (MAP_DATA);
288660484Sobrien
2887218822Sdim  /* Align pool as you have word accesses.
2888218822Sdim     Only make a frag if we have to.  */
2889218822Sdim  if (!need_pass_2)
2890218822Sdim    frag_align (2, 0, 0);
289177298Sobrien
2892218822Sdim  record_alignment (now_seg, 2);
289377298Sobrien
2894218822Sdim  sprintf (sym_name, "$$lit_\002%x", pool->id);
289577298Sobrien
2896218822Sdim  symbol_locate (pool->symbol, sym_name, now_seg,
2897218822Sdim		 (valueT) frag_now_fix (), frag_now);
2898218822Sdim  symbol_table_insert (pool->symbol);
289960484Sobrien
2900218822Sdim  ARM_SET_THUMB (pool->symbol, thumb_mode);
290160484Sobrien
2902218822Sdim#if defined OBJ_COFF || defined OBJ_ELF
2903218822Sdim  ARM_SET_INTERWORK (pool->symbol, support_interwork);
2904218822Sdim#endif
290560484Sobrien
2906218822Sdim  for (entry = 0; entry < pool->next_free_entry; entry ++)
2907218822Sdim    /* First output the expression in the instruction to the pool.  */
2908218822Sdim    emit_expr (&(pool->literals[entry]), 4); /* .word  */
290960484Sobrien
2910218822Sdim  /* Mark the pool as empty.  */
2911218822Sdim  pool->next_free_entry = 0;
2912218822Sdim  pool->symbol = NULL;
291360484Sobrien}
291460484Sobrien
2915218822Sdim#ifdef OBJ_ELF
2916218822Sdim/* Forward declarations for functions below, in the MD interface
2917218822Sdim   section.  */
2918218822Sdimstatic void fix_new_arm (fragS *, int, short, expressionS *, int, int);
2919218822Sdimstatic valueT create_unwind_entry (int);
2920218822Sdimstatic void start_unwind_section (const segT, int);
2921218822Sdimstatic void add_unwind_opcode (valueT, int);
2922218822Sdimstatic void flush_pending_unwind (void);
2923218822Sdim
2924218822Sdim/* Directives: Data.  */
2925218822Sdim
2926218822Sdimstatic void
2927218822Sdims_arm_elf_cons (int nbytes)
292860484Sobrien{
2929218822Sdim  expressionS exp;
293060484Sobrien
2931218822Sdim#ifdef md_flush_pending_output
2932218822Sdim  md_flush_pending_output ();
2933218822Sdim#endif
2934218822Sdim
2935218822Sdim  if (is_it_end_of_statement ())
293660484Sobrien    {
2937218822Sdim      demand_empty_rest_of_line ();
2938218822Sdim      return;
2939218822Sdim    }
294060484Sobrien
2941218822Sdim#ifdef md_cons_align
2942218822Sdim  md_cons_align (nbytes);
2943218822Sdim#endif
294460484Sobrien
2945218822Sdim  mapping_state (MAP_DATA);
2946218822Sdim  do
2947218822Sdim    {
2948218822Sdim      int reloc;
2949218822Sdim      char *base = input_line_pointer;
295060484Sobrien
2951218822Sdim      expression (& exp);
295260484Sobrien
2953218822Sdim      if (exp.X_op != O_symbol)
2954218822Sdim	emit_expr (&exp, (unsigned int) nbytes);
2955218822Sdim      else
295660484Sobrien	{
2957218822Sdim	  char *before_reloc = input_line_pointer;
2958218822Sdim	  reloc = parse_reloc (&input_line_pointer);
2959218822Sdim	  if (reloc == -1)
296060484Sobrien	    {
2961218822Sdim	      as_bad (_("unrecognized relocation suffix"));
2962218822Sdim	      ignore_rest_of_line ();
2963218822Sdim	      return;
2964130561Sobrien	    }
2965218822Sdim	  else if (reloc == BFD_RELOC_UNUSED)
2966218822Sdim	    emit_expr (&exp, (unsigned int) nbytes);
2967218822Sdim	  else
2968130561Sobrien	    {
2969218822Sdim	      reloc_howto_type *howto = bfd_reloc_type_lookup (stdoutput, reloc);
2970218822Sdim	      int size = bfd_get_reloc_size (howto);
2971130561Sobrien
2972218822Sdim	      if (reloc == BFD_RELOC_ARM_PLT32)
297360484Sobrien		{
2974218822Sdim		  as_bad (_("(plt) is only valid on branch targets"));
2975218822Sdim		  reloc = BFD_RELOC_UNUSED;
2976218822Sdim		  size = 0;
2977218822Sdim		}
2978130561Sobrien
2979218822Sdim	      if (size > nbytes)
2980218822Sdim		as_bad (_("%s relocations do not fit in %d bytes"),
2981218822Sdim			howto->name, nbytes);
2982130561Sobrien	      else
2983130561Sobrien		{
2984218822Sdim		  /* We've parsed an expression stopping at O_symbol.
2985218822Sdim		     But there may be more expression left now that we
2986218822Sdim		     have parsed the relocation marker.  Parse it again.
2987218822Sdim		     XXX Surely there is a cleaner way to do this.  */
2988218822Sdim		  char *p = input_line_pointer;
2989218822Sdim		  int offset;
2990218822Sdim		  char *save_buf = alloca (input_line_pointer - base);
2991218822Sdim		  memcpy (save_buf, base, input_line_pointer - base);
2992218822Sdim		  memmove (base + (input_line_pointer - before_reloc),
2993218822Sdim			   base, before_reloc - base);
2994130561Sobrien
2995218822Sdim		  input_line_pointer = base + (input_line_pointer-before_reloc);
2996218822Sdim		  expression (&exp);
2997218822Sdim		  memcpy (base, save_buf, p - base);
2998130561Sobrien
2999218822Sdim		  offset = nbytes - size;
3000218822Sdim		  p = frag_more ((int) nbytes);
3001218822Sdim		  fix_new_exp (frag_now, p - frag_now->fr_literal + offset,
3002218822Sdim			       size, &exp, 0, reloc);
3003130561Sobrien		}
300460484Sobrien	    }
300560484Sobrien	}
3006218822Sdim    }
3007218822Sdim  while (*input_line_pointer++ == ',');
300860484Sobrien
3009218822Sdim  /* Put terminator back into stream.  */
3010218822Sdim  input_line_pointer --;
3011218822Sdim  demand_empty_rest_of_line ();
3012218822Sdim}
301360484Sobrien
301477298Sobrien
3015218822Sdim/* Parse a .rel31 directive.  */
301660484Sobrien
3017218822Sdimstatic void
3018218822Sdims_arm_rel31 (int ignored ATTRIBUTE_UNUSED)
3019218822Sdim{
3020218822Sdim  expressionS exp;
3021218822Sdim  char *p;
3022218822Sdim  valueT highbit;
302360484Sobrien
3024218822Sdim  highbit = 0;
3025218822Sdim  if (*input_line_pointer == '1')
3026218822Sdim    highbit = 0x80000000;
3027218822Sdim  else if (*input_line_pointer != '0')
3028218822Sdim    as_bad (_("expected 0 or 1"));
302960484Sobrien
3030218822Sdim  input_line_pointer++;
3031218822Sdim  if (*input_line_pointer != ',')
3032218822Sdim    as_bad (_("missing comma"));
3033218822Sdim  input_line_pointer++;
303460484Sobrien
3035218822Sdim#ifdef md_flush_pending_output
3036218822Sdim  md_flush_pending_output ();
3037218822Sdim#endif
303860484Sobrien
3039218822Sdim#ifdef md_cons_align
3040218822Sdim  md_cons_align (4);
3041218822Sdim#endif
304260484Sobrien
3043218822Sdim  mapping_state (MAP_DATA);
304460484Sobrien
3045218822Sdim  expression (&exp);
304660484Sobrien
3047218822Sdim  p = frag_more (4);
3048218822Sdim  md_number_to_chars (p, highbit, 4);
3049218822Sdim  fix_new_arm (frag_now, p - frag_now->fr_literal, 4, &exp, 1,
3050218822Sdim	       BFD_RELOC_ARM_PREL31);
3051130561Sobrien
3052218822Sdim  demand_empty_rest_of_line ();
3053218822Sdim}
3054130561Sobrien
3055218822Sdim/* Directives: AEABI stack-unwind tables.  */
3056130561Sobrien
3057218822Sdim/* Parse an unwind_fnstart directive.  Simply records the current location.  */
3058130561Sobrien
3059218822Sdimstatic void
3060218822Sdims_arm_unwind_fnstart (int ignored ATTRIBUTE_UNUSED)
3061218822Sdim{
3062218822Sdim  demand_empty_rest_of_line ();
3063218822Sdim  /* Mark the start of the function.  */
3064218822Sdim  unwind.proc_start = expr_build_dot ();
3065130561Sobrien
3066218822Sdim  /* Reset the rest of the unwind info.	 */
3067218822Sdim  unwind.opcode_count = 0;
3068218822Sdim  unwind.table_entry = NULL;
3069218822Sdim  unwind.personality_routine = NULL;
3070218822Sdim  unwind.personality_index = -1;
3071218822Sdim  unwind.frame_size = 0;
3072218822Sdim  unwind.fp_offset = 0;
3073218822Sdim  unwind.fp_reg = 13;
3074218822Sdim  unwind.fp_used = 0;
3075218822Sdim  unwind.sp_restored = 0;
3076130561Sobrien}
3077130561Sobrien
3078130561Sobrien
3079218822Sdim/* Parse a handlerdata directive.  Creates the exception handling table entry
3080218822Sdim   for the function.  */
3081130561Sobrien
3082218822Sdimstatic void
3083218822Sdims_arm_unwind_handlerdata (int ignored ATTRIBUTE_UNUSED)
3084218822Sdim{
3085218822Sdim  demand_empty_rest_of_line ();
3086218822Sdim  if (unwind.table_entry)
3087218822Sdim    as_bad (_("dupicate .handlerdata directive"));
3088130561Sobrien
3089218822Sdim  create_unwind_entry (1);
3090218822Sdim}
3091130561Sobrien
3092218822Sdim/* Parse an unwind_fnend directive.  Generates the index table entry.  */
3093130561Sobrien
3094218822Sdimstatic void
3095218822Sdims_arm_unwind_fnend (int ignored ATTRIBUTE_UNUSED)
3096218822Sdim{
3097218822Sdim  long where;
3098218822Sdim  char *ptr;
3099218822Sdim  valueT val;
3100130561Sobrien
3101218822Sdim  demand_empty_rest_of_line ();
3102130561Sobrien
3103218822Sdim  /* Add eh table entry.  */
3104218822Sdim  if (unwind.table_entry == NULL)
3105218822Sdim    val = create_unwind_entry (0);
3106218822Sdim  else
3107218822Sdim    val = 0;
3108130561Sobrien
3109218822Sdim  /* Add index table entry.  This is two words.	 */
3110218822Sdim  start_unwind_section (unwind.saved_seg, 1);
3111218822Sdim  frag_align (2, 0, 0);
3112218822Sdim  record_alignment (now_seg, 2);
3113130561Sobrien
3114218822Sdim  ptr = frag_more (8);
3115247386Sandrew  memset(ptr, 0, 8);
3116218822Sdim  where = frag_now_fix () - 8;
3117130561Sobrien
3118218822Sdim  /* Self relative offset of the function start.  */
3119218822Sdim  fix_new (frag_now, where, 4, unwind.proc_start, 0, 1,
3120218822Sdim	   BFD_RELOC_ARM_PREL31);
3121130561Sobrien
3122218822Sdim  /* Indicate dependency on EHABI-defined personality routines to the
3123218822Sdim     linker, if it hasn't been done already.  */
3124218822Sdim  if (unwind.personality_index >= 0 && unwind.personality_index < 3
3125218822Sdim      && !(marked_pr_dependency & (1 << unwind.personality_index)))
3126218822Sdim    {
3127218822Sdim      static const char *const name[] = {
3128218822Sdim	"__aeabi_unwind_cpp_pr0",
3129218822Sdim	"__aeabi_unwind_cpp_pr1",
3130218822Sdim	"__aeabi_unwind_cpp_pr2"
3131218822Sdim      };
3132218822Sdim      symbolS *pr = symbol_find_or_make (name[unwind.personality_index]);
3133218822Sdim      fix_new (frag_now, where, 0, pr, 0, 1, BFD_RELOC_NONE);
3134218822Sdim      marked_pr_dependency |= 1 << unwind.personality_index;
3135218822Sdim      seg_info (now_seg)->tc_segment_info_data.marked_pr_dependency
3136218822Sdim	= marked_pr_dependency;
3137218822Sdim    }
3138130561Sobrien
3139218822Sdim  if (val)
3140218822Sdim    /* Inline exception table entry.  */
3141218822Sdim    md_number_to_chars (ptr + 4, val, 4);
3142130561Sobrien  else
3143218822Sdim    /* Self relative offset of the table entry.	 */
3144218822Sdim    fix_new (frag_now, where + 4, 4, unwind.table_entry, 0, 1,
3145218822Sdim	     BFD_RELOC_ARM_PREL31);
3146130561Sobrien
3147218822Sdim  /* Restore the original section.  */
3148218822Sdim  subseg_set (unwind.saved_seg, unwind.saved_subseg);
3149130561Sobrien}
3150130561Sobrien
3151218822Sdim
3152218822Sdim/* Parse an unwind_cantunwind directive.  */
3153218822Sdim
315460484Sobrienstatic void
3155218822Sdims_arm_unwind_cantunwind (int ignored ATTRIBUTE_UNUSED)
315660484Sobrien{
3157218822Sdim  demand_empty_rest_of_line ();
3158218822Sdim  if (unwind.personality_routine || unwind.personality_index != -1)
3159218822Sdim    as_bad (_("personality routine specified for cantunwind frame"));
3160218822Sdim
3161218822Sdim  unwind.personality_index = -2;
316260484Sobrien}
316360484Sobrien
3164218822Sdim
3165218822Sdim/* Parse a personalityindex directive.	*/
3166218822Sdim
316760484Sobrienstatic void
3168218822Sdims_arm_unwind_personalityindex (int ignored ATTRIBUTE_UNUSED)
316960484Sobrien{
3170218822Sdim  expressionS exp;
317177298Sobrien
3172218822Sdim  if (unwind.personality_routine || unwind.personality_index != -1)
3173218822Sdim    as_bad (_("duplicate .personalityindex directive"));
317460484Sobrien
3175218822Sdim  expression (&exp);
317660484Sobrien
3177218822Sdim  if (exp.X_op != O_constant
3178218822Sdim      || exp.X_add_number < 0 || exp.X_add_number > 15)
317960484Sobrien    {
3180218822Sdim      as_bad (_("bad personality routine number"));
3181218822Sdim      ignore_rest_of_line ();
318260484Sobrien      return;
318360484Sobrien    }
318460484Sobrien
3185218822Sdim  unwind.personality_index = exp.X_add_number;
318661843Sobrien
3187218822Sdim  demand_empty_rest_of_line ();
3188218822Sdim}
318977298Sobrien
319061843Sobrien
3191218822Sdim/* Parse a personality directive.  */
319277298Sobrien
3193218822Sdimstatic void
3194218822Sdims_arm_unwind_personality (int ignored ATTRIBUTE_UNUSED)
3195218822Sdim{
3196218822Sdim  char *name, *p, c;
3197218822Sdim
3198218822Sdim  if (unwind.personality_routine || unwind.personality_index != -1)
3199218822Sdim    as_bad (_("duplicate .personality directive"));
3200218822Sdim
3201218822Sdim  name = input_line_pointer;
3202218822Sdim  c = get_symbol_end ();
3203218822Sdim  p = input_line_pointer;
3204218822Sdim  unwind.personality_routine = symbol_find_or_make (name);
3205218822Sdim  *p = c;
3206218822Sdim  demand_empty_rest_of_line ();
320760484Sobrien}
320860484Sobrien
320977298Sobrien
3210218822Sdim/* Parse a directive saving core registers.  */
3211218822Sdim
321260484Sobrienstatic void
3213218822Sdims_arm_unwind_save_core (void)
321460484Sobrien{
3215218822Sdim  valueT op;
3216218822Sdim  long range;
3217218822Sdim  int n;
321860484Sobrien
3219218822Sdim  range = parse_reg_list (&input_line_pointer);
3220218822Sdim  if (range == FAIL)
322161843Sobrien    {
3222218822Sdim      as_bad (_("expected register list"));
3223218822Sdim      ignore_rest_of_line ();
322461843Sobrien      return;
322561843Sobrien    }
322661843Sobrien
3227218822Sdim  demand_empty_rest_of_line ();
322860484Sobrien
3229218822Sdim  /* Turn .unwind_movsp ip followed by .unwind_save {..., ip, ...}
3230218822Sdim     into .unwind_save {..., sp...}.  We aren't bothered about the value of
3231218822Sdim     ip because it is clobbered by calls.  */
3232218822Sdim  if (unwind.sp_restored && unwind.fp_reg == 12
3233218822Sdim      && (range & 0x3000) == 0x1000)
323460484Sobrien    {
3235218822Sdim      unwind.opcode_count--;
3236218822Sdim      unwind.sp_restored = 0;
3237218822Sdim      range = (range | 0x2000) & ~0x1000;
3238218822Sdim      unwind.pending_offset = 0;
323961843Sobrien    }
324060484Sobrien
3241218822Sdim  /* Pop r4-r15.  */
3242218822Sdim  if (range & 0xfff0)
324361843Sobrien    {
3244218822Sdim      /* See if we can use the short opcodes.  These pop a block of up to 8
3245218822Sdim	 registers starting with r4, plus maybe r14.  */
3246218822Sdim      for (n = 0; n < 8; n++)
3247218822Sdim	{
3248218822Sdim	  /* Break at the first non-saved register.	 */
3249218822Sdim	  if ((range & (1 << (n + 4))) == 0)
3250218822Sdim	    break;
3251218822Sdim	}
3252218822Sdim      /* See if there are any other bits set.  */
3253218822Sdim      if (n == 0 || (range & (0xfff0 << n) & 0xbff0) != 0)
3254218822Sdim	{
3255218822Sdim	  /* Use the long form.  */
3256218822Sdim	  op = 0x8000 | ((range >> 4) & 0xfff);
3257218822Sdim	  add_unwind_opcode (op, 2);
3258218822Sdim	}
3259218822Sdim      else
3260218822Sdim	{
3261218822Sdim	  /* Use the short form.  */
3262218822Sdim	  if (range & 0x4000)
3263218822Sdim	    op = 0xa8; /* Pop r14.	*/
3264218822Sdim	  else
3265218822Sdim	    op = 0xa0; /* Do not pop r14.  */
3266218822Sdim	  op |= (n - 1);
3267218822Sdim	  add_unwind_opcode (op, 1);
3268218822Sdim	}
326960484Sobrien    }
327061843Sobrien
3271218822Sdim  /* Pop r0-r3.	 */
3272218822Sdim  if (range & 0xf)
327361843Sobrien    {
3274218822Sdim      op = 0xb100 | (range & 0xf);
3275218822Sdim      add_unwind_opcode (op, 2);
327661843Sobrien    }
327777298Sobrien
3278218822Sdim  /* Record the number of bytes pushed.	 */
3279218822Sdim  for (n = 0; n < 16; n++)
328061843Sobrien    {
3281218822Sdim      if (range & (1 << n))
3282218822Sdim	unwind.frame_size += 4;
328361843Sobrien    }
3284218822Sdim}
328577298Sobrien
328677298Sobrien
3287218822Sdim/* Parse a directive saving FPA registers.  */
328877298Sobrien
328960484Sobrienstatic void
3290218822Sdims_arm_unwind_save_fpa (int reg)
329160484Sobrien{
3292218822Sdim  expressionS exp;
3293218822Sdim  int num_regs;
3294218822Sdim  valueT op;
329560484Sobrien
3296218822Sdim  /* Get Number of registers to transfer.  */
3297218822Sdim  if (skip_past_comma (&input_line_pointer) != FAIL)
3298218822Sdim    expression (&exp);
3299218822Sdim  else
3300218822Sdim    exp.X_op = O_illegal;
330160484Sobrien
3302218822Sdim  if (exp.X_op != O_constant)
330360484Sobrien    {
3304218822Sdim      as_bad (_("expected , <constant>"));
3305218822Sdim      ignore_rest_of_line ();
330660484Sobrien      return;
330760484Sobrien    }
330860484Sobrien
3309218822Sdim  num_regs = exp.X_add_number;
331060484Sobrien
3311218822Sdim  if (num_regs < 1 || num_regs > 4)
331260484Sobrien    {
3313218822Sdim      as_bad (_("number of registers must be in the range [1:4]"));
3314218822Sdim      ignore_rest_of_line ();
331560484Sobrien      return;
331660484Sobrien    }
331760484Sobrien
3318218822Sdim  demand_empty_rest_of_line ();
331960484Sobrien
3320218822Sdim  if (reg == 4)
332160484Sobrien    {
3322218822Sdim      /* Short form.  */
3323218822Sdim      op = 0xb4 | (num_regs - 1);
3324218822Sdim      add_unwind_opcode (op, 1);
332560484Sobrien    }
3326218822Sdim  else
332760484Sobrien    {
3328218822Sdim      /* Long form.  */
3329218822Sdim      op = 0xc800 | (reg << 4) | (num_regs - 1);
3330218822Sdim      add_unwind_opcode (op, 2);
333160484Sobrien    }
3332218822Sdim  unwind.frame_size += num_regs * 12;
333360484Sobrien}
333460484Sobrien
3335218822Sdim
3336218822Sdim/* Parse a directive saving VFP registers for ARMv6 and above.  */
3337218822Sdim
333860484Sobrienstatic void
3339218822Sdims_arm_unwind_save_vfp_armv6 (void)
334060484Sobrien{
3341218822Sdim  int count;
3342218822Sdim  unsigned int start;
3343218822Sdim  valueT op;
3344218822Sdim  int num_vfpv3_regs = 0;
3345218822Sdim  int num_regs_below_16;
334677298Sobrien
3347218822Sdim  count = parse_vfp_reg_list (&input_line_pointer, &start, REGLIST_VFP_D);
3348218822Sdim  if (count == FAIL)
334960484Sobrien    {
3350218822Sdim      as_bad (_("expected register list"));
3351218822Sdim      ignore_rest_of_line ();
335260484Sobrien      return;
335360484Sobrien    }
335460484Sobrien
3355218822Sdim  demand_empty_rest_of_line ();
335660484Sobrien
3357218822Sdim  /* We always generate FSTMD/FLDMD-style unwinding opcodes (rather
3358218822Sdim     than FSTMX/FLDMX-style ones).  */
335960484Sobrien
3360218822Sdim  /* Generate opcode for (VFPv3) registers numbered in the range 16 .. 31.  */
3361218822Sdim  if (start >= 16)
3362218822Sdim    num_vfpv3_regs = count;
3363218822Sdim  else if (start + count > 16)
3364218822Sdim    num_vfpv3_regs = start + count - 16;
336560484Sobrien
3366218822Sdim  if (num_vfpv3_regs > 0)
336760484Sobrien    {
3368218822Sdim      int start_offset = start > 16 ? start - 16 : 0;
3369218822Sdim      op = 0xc800 | (start_offset << 4) | (num_vfpv3_regs - 1);
3370218822Sdim      add_unwind_opcode (op, 2);
337160484Sobrien    }
337260484Sobrien
3373218822Sdim  /* Generate opcode for registers numbered in the range 0 .. 15.  */
3374218822Sdim  num_regs_below_16 = num_vfpv3_regs > 0 ? 16 - (int) start : count;
3375218822Sdim  assert (num_regs_below_16 + num_vfpv3_regs == count);
3376218822Sdim  if (num_regs_below_16 > 0)
337760484Sobrien    {
3378218822Sdim      op = 0xc900 | (start << 4) | (num_regs_below_16 - 1);
3379218822Sdim      add_unwind_opcode (op, 2);
338060484Sobrien    }
338160484Sobrien
3382218822Sdim  unwind.frame_size += count * 8;
338360484Sobrien}
338460484Sobrien
3385218822Sdim
3386218822Sdim/* Parse a directive saving VFP registers for pre-ARMv6.  */
3387218822Sdim
338860484Sobrienstatic void
3389218822Sdims_arm_unwind_save_vfp (void)
339060484Sobrien{
3391218822Sdim  int count;
3392218822Sdim  unsigned int reg;
3393218822Sdim  valueT op;
339460484Sobrien
3395218822Sdim  count = parse_vfp_reg_list (&input_line_pointer, &reg, REGLIST_VFP_D);
3396218822Sdim  if (count == FAIL)
339760484Sobrien    {
3398218822Sdim      as_bad (_("expected register list"));
3399218822Sdim      ignore_rest_of_line ();
340060484Sobrien      return;
340160484Sobrien    }
340260484Sobrien
3403218822Sdim  demand_empty_rest_of_line ();
340460484Sobrien
3405218822Sdim  if (reg == 8)
340660484Sobrien    {
3407218822Sdim      /* Short form.  */
3408218822Sdim      op = 0xb8 | (count - 1);
3409218822Sdim      add_unwind_opcode (op, 1);
341060484Sobrien    }
3411218822Sdim  else
341260484Sobrien    {
3413218822Sdim      /* Long form.  */
3414218822Sdim      op = 0xb300 | (reg << 4) | (count - 1);
3415218822Sdim      add_unwind_opcode (op, 2);
341660484Sobrien    }
3417218822Sdim  unwind.frame_size += count * 8 + 4;
341860484Sobrien}
341960484Sobrien
342077298Sobrien
3421218822Sdim/* Parse a directive saving iWMMXt data registers.  */
342277298Sobrien
3423218822Sdimstatic void
3424218822Sdims_arm_unwind_save_mmxwr (void)
342577298Sobrien{
3426218822Sdim  int reg;
3427218822Sdim  int hi_reg;
3428218822Sdim  int i;
3429218822Sdim  unsigned mask = 0;
3430218822Sdim  valueT op;
343177298Sobrien
3432218822Sdim  if (*input_line_pointer == '{')
3433218822Sdim    input_line_pointer++;
343477298Sobrien
3435218822Sdim  do
3436218822Sdim    {
3437218822Sdim      reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWR);
343877298Sobrien
3439218822Sdim      if (reg == FAIL)
3440218822Sdim	{
3441218822Sdim	  as_bad (_(reg_expected_msgs[REG_TYPE_MMXWR]));
3442218822Sdim	  goto error;
3443218822Sdim	}
344477298Sobrien
3445218822Sdim      if (mask >> reg)
3446218822Sdim	as_tsktsk (_("register list not in ascending order"));
3447218822Sdim      mask |= 1 << reg;
3448218822Sdim
3449218822Sdim      if (*input_line_pointer == '-')
3450218822Sdim	{
3451218822Sdim	  input_line_pointer++;
3452218822Sdim	  hi_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWR);
3453218822Sdim	  if (hi_reg == FAIL)
3454218822Sdim	    {
3455218822Sdim	      as_bad (_(reg_expected_msgs[REG_TYPE_MMXWR]));
3456218822Sdim	      goto error;
3457218822Sdim	    }
3458218822Sdim	  else if (reg >= hi_reg)
3459218822Sdim	    {
3460218822Sdim	      as_bad (_("bad register range"));
3461218822Sdim	      goto error;
3462218822Sdim	    }
3463218822Sdim	  for (; reg < hi_reg; reg++)
3464218822Sdim	    mask |= 1 << reg;
3465218822Sdim	}
346677298Sobrien    }
3467218822Sdim  while (skip_past_comma (&input_line_pointer) != FAIL);
346877298Sobrien
3469218822Sdim  if (*input_line_pointer == '}')
3470218822Sdim    input_line_pointer++;
347177298Sobrien
3472218822Sdim  demand_empty_rest_of_line ();
347377298Sobrien
3474218822Sdim  /* Generate any deferred opcodes because we're going to be looking at
3475218822Sdim     the list.	*/
3476218822Sdim  flush_pending_unwind ();
347777298Sobrien
3478218822Sdim  for (i = 0; i < 16; i++)
3479218822Sdim    {
3480218822Sdim      if (mask & (1 << i))
3481218822Sdim	unwind.frame_size += 8;
3482218822Sdim    }
348377298Sobrien
3484218822Sdim  /* Attempt to combine with a previous opcode.	 We do this because gcc
3485218822Sdim     likes to output separate unwind directives for a single block of
3486218822Sdim     registers.	 */
3487218822Sdim  if (unwind.opcode_count > 0)
348877298Sobrien    {
3489218822Sdim      i = unwind.opcodes[unwind.opcode_count - 1];
3490218822Sdim      if ((i & 0xf8) == 0xc0)
349177298Sobrien	{
3492218822Sdim	  i &= 7;
3493218822Sdim	  /* Only merge if the blocks are contiguous.  */
3494218822Sdim	  if (i < 6)
349577298Sobrien	    {
3496218822Sdim	      if ((mask & 0xfe00) == (1 << 9))
3497218822Sdim		{
3498218822Sdim		  mask |= ((1 << (i + 11)) - 1) & 0xfc00;
3499218822Sdim		  unwind.opcode_count--;
3500218822Sdim		}
350177298Sobrien	    }
3502218822Sdim	  else if (i == 6 && unwind.opcode_count >= 2)
350377298Sobrien	    {
3504218822Sdim	      i = unwind.opcodes[unwind.opcode_count - 2];
3505218822Sdim	      reg = i >> 4;
3506218822Sdim	      i &= 0xf;
350777298Sobrien
3508218822Sdim	      op = 0xffff << (reg - 1);
3509218822Sdim	      if (reg > 0
3510218822Sdim		  && ((mask & op) == (1u << (reg - 1))))
3511104834Sobrien		{
3512218822Sdim		  op = (1 << (reg + i + 1)) - 1;
3513218822Sdim		  op &= ~((1 << reg) - 1);
3514218822Sdim		  mask |= op;
3515218822Sdim		  unwind.opcode_count -= 2;
3516104834Sobrien		}
351777298Sobrien	    }
351877298Sobrien	}
3519218822Sdim    }
3520218822Sdim
3521218822Sdim  hi_reg = 15;
3522218822Sdim  /* We want to generate opcodes in the order the registers have been
3523218822Sdim     saved, ie. descending order.  */
3524218822Sdim  for (reg = 15; reg >= -1; reg--)
3525218822Sdim    {
3526218822Sdim      /* Save registers in blocks.  */
3527218822Sdim      if (reg < 0
3528218822Sdim	  || !(mask & (1 << reg)))
352977298Sobrien	{
3530218822Sdim	  /* We found an unsaved reg.  Generate opcodes to save the
3531218822Sdim	     preceeding block.	*/
3532218822Sdim	  if (reg != hi_reg)
353377298Sobrien	    {
3534218822Sdim	      if (reg == 9)
3535218822Sdim		{
3536218822Sdim		  /* Short form.  */
3537218822Sdim		  op = 0xc0 | (hi_reg - 10);
3538218822Sdim		  add_unwind_opcode (op, 1);
3539218822Sdim		}
3540218822Sdim	      else
3541218822Sdim		{
3542218822Sdim		  /* Long form.	 */
3543218822Sdim		  op = 0xc600 | ((reg + 1) << 4) | ((hi_reg - reg) - 1);
3544218822Sdim		  add_unwind_opcode (op, 2);
3545218822Sdim		}
354677298Sobrien	    }
3547218822Sdim	  hi_reg = reg - 1;
3548218822Sdim	}
3549218822Sdim    }
355077298Sobrien
3551218822Sdim  return;
3552218822Sdimerror:
3553218822Sdim  ignore_rest_of_line ();
3554218822Sdim}
355577298Sobrien
3556218822Sdimstatic void
3557218822Sdims_arm_unwind_save_mmxwcg (void)
3558218822Sdim{
3559218822Sdim  int reg;
3560218822Sdim  int hi_reg;
3561218822Sdim  unsigned mask = 0;
3562218822Sdim  valueT op;
356377298Sobrien
3564218822Sdim  if (*input_line_pointer == '{')
3565218822Sdim    input_line_pointer++;
356677298Sobrien
3567218822Sdim  do
3568218822Sdim    {
3569218822Sdim      reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWCG);
357077298Sobrien
3571218822Sdim      if (reg == FAIL)
3572218822Sdim	{
3573218822Sdim	  as_bad (_(reg_expected_msgs[REG_TYPE_MMXWCG]));
3574218822Sdim	  goto error;
3575218822Sdim	}
357677298Sobrien
3577218822Sdim      reg -= 8;
3578218822Sdim      if (mask >> reg)
3579218822Sdim	as_tsktsk (_("register list not in ascending order"));
3580218822Sdim      mask |= 1 << reg;
3581218822Sdim
3582218822Sdim      if (*input_line_pointer == '-')
3583218822Sdim	{
3584218822Sdim	  input_line_pointer++;
3585218822Sdim	  hi_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWCG);
3586218822Sdim	  if (hi_reg == FAIL)
358777298Sobrien	    {
3588218822Sdim	      as_bad (_(reg_expected_msgs[REG_TYPE_MMXWCG]));
3589218822Sdim	      goto error;
359077298Sobrien	    }
3591218822Sdim	  else if (reg >= hi_reg)
3592218822Sdim	    {
3593218822Sdim	      as_bad (_("bad register range"));
3594218822Sdim	      goto error;
3595218822Sdim	    }
3596218822Sdim	  for (; reg < hi_reg; reg++)
3597218822Sdim	    mask |= 1 << reg;
359877298Sobrien	}
359977298Sobrien    }
3600218822Sdim  while (skip_past_comma (&input_line_pointer) != FAIL);
360177298Sobrien
3602218822Sdim  if (*input_line_pointer == '}')
3603218822Sdim    input_line_pointer++;
360477298Sobrien
3605218822Sdim  demand_empty_rest_of_line ();
360677298Sobrien
3607218822Sdim  /* Generate any deferred opcodes because we're going to be looking at
3608218822Sdim     the list.	*/
3609218822Sdim  flush_pending_unwind ();
361077298Sobrien
3611218822Sdim  for (reg = 0; reg < 16; reg++)
3612218822Sdim    {
3613218822Sdim      if (mask & (1 << reg))
3614218822Sdim	unwind.frame_size += 4;
3615218822Sdim    }
3616218822Sdim  op = 0xc700 | mask;
3617218822Sdim  add_unwind_opcode (op, 2);
3618218822Sdim  return;
3619218822Sdimerror:
3620218822Sdim  ignore_rest_of_line ();
362177298Sobrien}
362277298Sobrien
362377298Sobrien
3624218822Sdim/* Parse an unwind_save directive.
3625218822Sdim   If the argument is non-zero, this is a .vsave directive.  */
3626218822Sdim
362777298Sobrienstatic void
3628218822Sdims_arm_unwind_save (int arch_v6)
362977298Sobrien{
3630218822Sdim  char *peek;
3631218822Sdim  struct reg_entry *reg;
3632218822Sdim  bfd_boolean had_brace = FALSE;
363377298Sobrien
3634218822Sdim  /* Figure out what sort of save we have.  */
3635218822Sdim  peek = input_line_pointer;
363677298Sobrien
3637218822Sdim  if (*peek == '{')
3638218822Sdim    {
3639218822Sdim      had_brace = TRUE;
3640218822Sdim      peek++;
3641218822Sdim    }
364277298Sobrien
3643218822Sdim  reg = arm_reg_parse_multi (&peek);
364477298Sobrien
3645218822Sdim  if (!reg)
3646218822Sdim    {
3647218822Sdim      as_bad (_("register expected"));
3648218822Sdim      ignore_rest_of_line ();
3649218822Sdim      return;
3650218822Sdim    }
3651218822Sdim
3652218822Sdim  switch (reg->type)
3653218822Sdim    {
3654218822Sdim    case REG_TYPE_FN:
3655218822Sdim      if (had_brace)
3656218822Sdim	{
3657218822Sdim	  as_bad (_("FPA .unwind_save does not take a register list"));
3658218822Sdim	  ignore_rest_of_line ();
3659218822Sdim	  return;
3660218822Sdim	}
3661218822Sdim      s_arm_unwind_save_fpa (reg->number);
3662218822Sdim      return;
3663218822Sdim
3664218822Sdim    case REG_TYPE_RN:	  s_arm_unwind_save_core ();   return;
3665218822Sdim    case REG_TYPE_VFD:
3666218822Sdim      if (arch_v6)
3667218822Sdim        s_arm_unwind_save_vfp_armv6 ();
3668218822Sdim      else
3669218822Sdim        s_arm_unwind_save_vfp ();
3670218822Sdim      return;
3671218822Sdim    case REG_TYPE_MMXWR:  s_arm_unwind_save_mmxwr ();  return;
3672218822Sdim    case REG_TYPE_MMXWCG: s_arm_unwind_save_mmxwcg (); return;
3673218822Sdim
3674218822Sdim    default:
3675218822Sdim      as_bad (_(".unwind_save does not support this kind of register"));
3676218822Sdim      ignore_rest_of_line ();
3677218822Sdim    }
367877298Sobrien}
367977298Sobrien
368077298Sobrien
3681218822Sdim/* Parse an unwind_movsp directive.  */
3682218822Sdim
368377298Sobrienstatic void
3684218822Sdims_arm_unwind_movsp (int ignored ATTRIBUTE_UNUSED)
368577298Sobrien{
3686218822Sdim  int reg;
3687218822Sdim  valueT op;
3688218822Sdim  int offset;
368977298Sobrien
3690218822Sdim  reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN);
3691218822Sdim  if (reg == FAIL)
369277298Sobrien    {
3693218822Sdim      as_bad (_(reg_expected_msgs[REG_TYPE_RN]));
3694218822Sdim      ignore_rest_of_line ();
369577298Sobrien      return;
369677298Sobrien    }
369777298Sobrien
3698218822Sdim  /* Optional constant.	 */
3699218822Sdim  if (skip_past_comma (&input_line_pointer) != FAIL)
370077298Sobrien    {
3701218822Sdim      if (immediate_for_directive (&offset) == FAIL)
3702218822Sdim	return;
3703218822Sdim    }
3704218822Sdim  else
3705218822Sdim    offset = 0;
3706218822Sdim
3707218822Sdim  demand_empty_rest_of_line ();
3708218822Sdim
3709218822Sdim  if (reg == REG_SP || reg == REG_PC)
3710218822Sdim    {
3711218822Sdim      as_bad (_("SP and PC not permitted in .unwind_movsp directive"));
371277298Sobrien      return;
371377298Sobrien    }
371477298Sobrien
3715218822Sdim  if (unwind.fp_reg != REG_SP)
3716218822Sdim    as_bad (_("unexpected .unwind_movsp directive"));
371777298Sobrien
3718218822Sdim  /* Generate opcode to restore the value.  */
3719218822Sdim  op = 0x90 | reg;
3720218822Sdim  add_unwind_opcode (op, 1);
3721218822Sdim
3722218822Sdim  /* Record the information for later.	*/
3723218822Sdim  unwind.fp_reg = reg;
3724218822Sdim  unwind.fp_offset = unwind.frame_size - offset;
3725218822Sdim  unwind.sp_restored = 1;
372677298Sobrien}
372777298Sobrien
3728218822Sdim/* Parse an unwind_pad directive.  */
372977298Sobrien
373077298Sobrienstatic void
3731218822Sdims_arm_unwind_pad (int ignored ATTRIBUTE_UNUSED)
373277298Sobrien{
3733218822Sdim  int offset;
373477298Sobrien
3735218822Sdim  if (immediate_for_directive (&offset) == FAIL)
3736218822Sdim    return;
373777298Sobrien
3738218822Sdim  if (offset & 3)
3739218822Sdim    {
3740218822Sdim      as_bad (_("stack increment must be multiple of 4"));
3741218822Sdim      ignore_rest_of_line ();
3742218822Sdim      return;
3743218822Sdim    }
374477298Sobrien
3745218822Sdim  /* Don't generate any opcodes, just record the details for later.  */
3746218822Sdim  unwind.frame_size += offset;
3747218822Sdim  unwind.pending_offset += offset;
374877298Sobrien
3749218822Sdim  demand_empty_rest_of_line ();
375077298Sobrien}
375177298Sobrien
3752218822Sdim/* Parse an unwind_setfp directive.  */
375377298Sobrien
375477298Sobrienstatic void
3755218822Sdims_arm_unwind_setfp (int ignored ATTRIBUTE_UNUSED)
375677298Sobrien{
3757218822Sdim  int sp_reg;
3758218822Sdim  int fp_reg;
3759218822Sdim  int offset;
376077298Sobrien
3761218822Sdim  fp_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN);
3762218822Sdim  if (skip_past_comma (&input_line_pointer) == FAIL)
3763218822Sdim    sp_reg = FAIL;
3764218822Sdim  else
3765218822Sdim    sp_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN);
376677298Sobrien
3767218822Sdim  if (fp_reg == FAIL || sp_reg == FAIL)
3768218822Sdim    {
3769218822Sdim      as_bad (_("expected <reg>, <reg>"));
3770218822Sdim      ignore_rest_of_line ();
3771218822Sdim      return;
3772218822Sdim    }
377377298Sobrien
3774218822Sdim  /* Optional constant.	 */
3775218822Sdim  if (skip_past_comma (&input_line_pointer) != FAIL)
3776218822Sdim    {
3777218822Sdim      if (immediate_for_directive (&offset) == FAIL)
3778218822Sdim	return;
3779218822Sdim    }
3780218822Sdim  else
3781218822Sdim    offset = 0;
378277298Sobrien
3783218822Sdim  demand_empty_rest_of_line ();
3784218822Sdim
3785218822Sdim  if (sp_reg != 13 && sp_reg != unwind.fp_reg)
3786218822Sdim    {
3787218822Sdim      as_bad (_("register must be either sp or set by a previous"
3788218822Sdim		"unwind_movsp directive"));
3789218822Sdim      return;
3790218822Sdim    }
3791218822Sdim
3792218822Sdim  /* Don't generate any opcodes, just record the information for later.	 */
3793218822Sdim  unwind.fp_reg = fp_reg;
3794218822Sdim  unwind.fp_used = 1;
3795218822Sdim  if (sp_reg == 13)
3796218822Sdim    unwind.fp_offset = unwind.frame_size - offset;
379777298Sobrien  else
3798218822Sdim    unwind.fp_offset -= offset;
379977298Sobrien}
380077298Sobrien
3801218822Sdim/* Parse an unwind_raw directive.  */
380277298Sobrien
380377298Sobrienstatic void
3804218822Sdims_arm_unwind_raw (int ignored ATTRIBUTE_UNUSED)
380577298Sobrien{
3806218822Sdim  expressionS exp;
3807218822Sdim  /* This is an arbitrary limit.	 */
3808218822Sdim  unsigned char op[16];
3809218822Sdim  int count;
381077298Sobrien
3811218822Sdim  expression (&exp);
3812218822Sdim  if (exp.X_op == O_constant
3813218822Sdim      && skip_past_comma (&input_line_pointer) != FAIL)
381477298Sobrien    {
3815218822Sdim      unwind.frame_size += exp.X_add_number;
3816218822Sdim      expression (&exp);
381777298Sobrien    }
3818218822Sdim  else
3819218822Sdim    exp.X_op = O_illegal;
382077298Sobrien
3821218822Sdim  if (exp.X_op != O_constant)
382277298Sobrien    {
3823218822Sdim      as_bad (_("expected <offset>, <opcode>"));
3824218822Sdim      ignore_rest_of_line ();
382577298Sobrien      return;
382677298Sobrien    }
382777298Sobrien
3828218822Sdim  count = 0;
382977298Sobrien
3830218822Sdim  /* Parse the opcode.	*/
3831218822Sdim  for (;;)
383277298Sobrien    {
3833218822Sdim      if (count >= 16)
3834218822Sdim	{
3835218822Sdim	  as_bad (_("unwind opcode too long"));
3836218822Sdim	  ignore_rest_of_line ();
3837218822Sdim	}
3838218822Sdim      if (exp.X_op != O_constant || exp.X_add_number & ~0xff)
3839218822Sdim	{
3840218822Sdim	  as_bad (_("invalid unwind opcode"));
3841218822Sdim	  ignore_rest_of_line ();
3842218822Sdim	  return;
3843218822Sdim	}
3844218822Sdim      op[count++] = exp.X_add_number;
384577298Sobrien
3846218822Sdim      /* Parse the next byte.  */
3847218822Sdim      if (skip_past_comma (&input_line_pointer) == FAIL)
3848218822Sdim	break;
384977298Sobrien
3850218822Sdim      expression (&exp);
385177298Sobrien    }
385277298Sobrien
3853218822Sdim  /* Add the opcode bytes in reverse order.  */
3854218822Sdim  while (count--)
3855218822Sdim    add_unwind_opcode (op[count], 1);
3856218822Sdim
3857218822Sdim  demand_empty_rest_of_line ();
385877298Sobrien}
385977298Sobrien
386077298Sobrien
3861218822Sdim/* Parse a .eabi_attribute directive.  */
3862218822Sdim
386377298Sobrienstatic void
3864218822Sdims_arm_eabi_attribute (int ignored ATTRIBUTE_UNUSED)
386577298Sobrien{
3866218822Sdim  s_vendor_attribute (OBJ_ATTR_PROC);
3867218822Sdim}
3868218822Sdim#endif /* OBJ_ELF */
386977298Sobrien
3870218822Sdimstatic void s_arm_arch (int);
3871218822Sdimstatic void s_arm_object_arch (int);
3872218822Sdimstatic void s_arm_cpu (int);
3873218822Sdimstatic void s_arm_fpu (int);
3874300304Spfgstatic void s_arm_arch_extension (int);
387577298Sobrien
3876218822Sdim#ifdef TE_PE
387777298Sobrien
3878218822Sdimstatic void
3879218822Sdimpe_directive_secrel (int dummy ATTRIBUTE_UNUSED)
3880218822Sdim{
3881218822Sdim  expressionS exp;
388277298Sobrien
3883218822Sdim  do
3884218822Sdim    {
3885218822Sdim      expression (&exp);
3886218822Sdim      if (exp.X_op == O_symbol)
3887218822Sdim	exp.X_op = O_secrel;
3888218822Sdim
3889218822Sdim      emit_expr (&exp, 4);
3890218822Sdim    }
3891218822Sdim  while (*input_line_pointer++ == ',');
3892218822Sdim
3893218822Sdim  input_line_pointer--;
3894218822Sdim  demand_empty_rest_of_line ();
389577298Sobrien}
3896218822Sdim#endif /* TE_PE */
389777298Sobrien
3898218822Sdim/* This table describes all the machine specific pseudo-ops the assembler
3899218822Sdim   has to support.  The fields are:
3900218822Sdim     pseudo-op name without dot
3901218822Sdim     function to call to execute this pseudo-op
3902218822Sdim     Integer arg to pass to the function.  */
390377298Sobrien
3904218822Sdimconst pseudo_typeS md_pseudo_table[] =
390577298Sobrien{
3906218822Sdim  /* Never called because '.req' does not start a line.	 */
3907218822Sdim  { "req",	   s_req,	  0 },
3908218822Sdim  /* Following two are likewise never called.  */
3909218822Sdim  { "dn",	   s_dn,          0 },
3910218822Sdim  { "qn",          s_qn,          0 },
3911218822Sdim  { "unreq",	   s_unreq,	  0 },
3912218822Sdim  { "bss",	   s_bss,	  0 },
3913218822Sdim  { "align",	   s_align,	  0 },
3914218822Sdim  { "arm",	   s_arm,	  0 },
3915218822Sdim  { "thumb",	   s_thumb,	  0 },
3916218822Sdim  { "code",	   s_code,	  0 },
3917218822Sdim  { "force_thumb", s_force_thumb, 0 },
3918218822Sdim  { "thumb_func",  s_thumb_func,  0 },
3919218822Sdim  { "thumb_set",   s_thumb_set,	  0 },
3920218822Sdim  { "even",	   s_even,	  0 },
3921218822Sdim  { "ltorg",	   s_ltorg,	  0 },
3922218822Sdim  { "pool",	   s_ltorg,	  0 },
3923218822Sdim  { "syntax",	   s_syntax,	  0 },
3924218822Sdim  { "cpu",	   s_arm_cpu,	  0 },
3925218822Sdim  { "arch",	   s_arm_arch,	  0 },
3926218822Sdim  { "object_arch", s_arm_object_arch,	0 },
3927218822Sdim  { "fpu",	   s_arm_fpu,	  0 },
3928300304Spfg  { "arch_extension",	   s_arm_arch_extension,	  0 },
3929300333Spfg  { "inst",	   s_inst,	  0 },
3930218822Sdim#ifdef OBJ_ELF
3931218822Sdim  { "word",	   s_arm_elf_cons, 4 },
3932218822Sdim  { "long",	   s_arm_elf_cons, 4 },
3933218822Sdim  { "rel31",	   s_arm_rel31,	  0 },
3934218822Sdim  { "fnstart",		s_arm_unwind_fnstart,	0 },
3935218822Sdim  { "fnend",		s_arm_unwind_fnend,	0 },
3936218822Sdim  { "cantunwind",	s_arm_unwind_cantunwind, 0 },
3937218822Sdim  { "personality",	s_arm_unwind_personality, 0 },
3938218822Sdim  { "personalityindex",	s_arm_unwind_personalityindex, 0 },
3939218822Sdim  { "handlerdata",	s_arm_unwind_handlerdata, 0 },
3940218822Sdim  { "save",		s_arm_unwind_save,	0 },
3941218822Sdim  { "vsave",		s_arm_unwind_save,	1 },
3942218822Sdim  { "movsp",		s_arm_unwind_movsp,	0 },
3943218822Sdim  { "pad",		s_arm_unwind_pad,	0 },
3944218822Sdim  { "setfp",		s_arm_unwind_setfp,	0 },
3945218822Sdim  { "unwind_raw",	s_arm_unwind_raw,	0 },
3946218822Sdim  { "eabi_attribute",	s_arm_eabi_attribute,	0 },
3947218822Sdim#else
3948218822Sdim  { "word",	   cons, 4},
394977298Sobrien
3950218822Sdim  /* These are used for dwarf.  */
3951218822Sdim  {"2byte", cons, 2},
3952218822Sdim  {"4byte", cons, 4},
3953218822Sdim  {"8byte", cons, 8},
3954218822Sdim  /* These are used for dwarf2.  */
3955218822Sdim  { "file", (void (*) (int)) dwarf2_directive_file, 0 },
3956218822Sdim  { "loc",  dwarf2_directive_loc,  0 },
3957218822Sdim  { "loc_mark_labels", dwarf2_directive_loc_mark_labels, 0 },
3958218822Sdim#endif
3959218822Sdim  { "extend",	   float_cons, 'x' },
3960218822Sdim  { "ldouble",	   float_cons, 'x' },
3961218822Sdim  { "packed",	   float_cons, 'p' },
3962218822Sdim#ifdef TE_PE
3963218822Sdim  {"secrel32", pe_directive_secrel, 0},
3964218822Sdim#endif
3965218822Sdim  { 0, 0, 0 }
3966218822Sdim};
3967218822Sdim
3968218822Sdim/* Parser functions used exclusively in instruction operands.  */
3969218822Sdim
3970218822Sdim/* Generic immediate-value read function for use in insn parsing.
3971218822Sdim   STR points to the beginning of the immediate (the leading #);
3972218822Sdim   VAL receives the value; if the value is outside [MIN, MAX]
3973218822Sdim   issue an error.  PREFIX_OPT is true if the immediate prefix is
3974218822Sdim   optional.  */
3975218822Sdim
3976218822Sdimstatic int
3977218822Sdimparse_immediate (char **str, int *val, int min, int max,
3978218822Sdim		 bfd_boolean prefix_opt)
3979218822Sdim{
3980218822Sdim  expressionS exp;
3981218822Sdim  my_get_expression (&exp, str, prefix_opt ? GE_OPT_PREFIX : GE_IMM_PREFIX);
3982218822Sdim  if (exp.X_op != O_constant)
398377298Sobrien    {
3984218822Sdim      inst.error = _("constant expression required");
3985218822Sdim      return FAIL;
398677298Sobrien    }
3987218822Sdim
3988218822Sdim  if (exp.X_add_number < min || exp.X_add_number > max)
398977298Sobrien    {
3990218822Sdim      inst.error = _("immediate value out of range");
3991218822Sdim      return FAIL;
399277298Sobrien    }
3993218822Sdim
3994218822Sdim  *val = exp.X_add_number;
3995218822Sdim  return SUCCESS;
3996218822Sdim}
3997218822Sdim
3998218822Sdim/* Less-generic immediate-value read function with the possibility of loading a
3999218822Sdim   big (64-bit) immediate, as required by Neon VMOV, VMVN and logic immediate
4000218822Sdim   instructions. Puts the result directly in inst.operands[i].  */
4001218822Sdim
4002218822Sdimstatic int
4003218822Sdimparse_big_immediate (char **str, int i)
4004218822Sdim{
4005218822Sdim  expressionS exp;
4006218822Sdim  char *ptr = *str;
4007218822Sdim
4008218822Sdim  my_get_expression (&exp, &ptr, GE_OPT_PREFIX_BIG);
4009218822Sdim
4010218822Sdim  if (exp.X_op == O_constant)
401177298Sobrien    {
4012218822Sdim      inst.operands[i].imm = exp.X_add_number & 0xffffffff;
4013218822Sdim      /* If we're on a 64-bit host, then a 64-bit number can be returned using
4014218822Sdim	 O_constant.  We have to be careful not to break compilation for
4015218822Sdim	 32-bit X_add_number, though.  */
4016218822Sdim      if ((exp.X_add_number & ~0xffffffffl) != 0)
4017218822Sdim	{
4018218822Sdim          /* X >> 32 is illegal if sizeof (exp.X_add_number) == 4.  */
4019218822Sdim	  inst.operands[i].reg = ((exp.X_add_number >> 16) >> 16) & 0xffffffff;
4020218822Sdim	  inst.operands[i].regisimm = 1;
4021218822Sdim	}
402277298Sobrien    }
4023218822Sdim  else if (exp.X_op == O_big
4024218822Sdim           && LITTLENUM_NUMBER_OF_BITS * exp.X_add_number > 32
4025218822Sdim           && LITTLENUM_NUMBER_OF_BITS * exp.X_add_number <= 64)
4026218822Sdim    {
4027218822Sdim      unsigned parts = 32 / LITTLENUM_NUMBER_OF_BITS, j, idx = 0;
4028218822Sdim      /* Bignums have their least significant bits in
4029218822Sdim         generic_bignum[0]. Make sure we put 32 bits in imm and
4030218822Sdim         32 bits in reg,  in a (hopefully) portable way.  */
4031218822Sdim      assert (parts != 0);
4032218822Sdim      inst.operands[i].imm = 0;
4033218822Sdim      for (j = 0; j < parts; j++, idx++)
4034218822Sdim        inst.operands[i].imm |= generic_bignum[idx]
4035218822Sdim                                << (LITTLENUM_NUMBER_OF_BITS * j);
4036218822Sdim      inst.operands[i].reg = 0;
4037218822Sdim      for (j = 0; j < parts; j++, idx++)
4038218822Sdim        inst.operands[i].reg |= generic_bignum[idx]
4039218822Sdim                                << (LITTLENUM_NUMBER_OF_BITS * j);
4040218822Sdim      inst.operands[i].regisimm = 1;
4041218822Sdim    }
404277298Sobrien  else
4043218822Sdim    return FAIL;
4044218822Sdim
4045218822Sdim  *str = ptr;
4046218822Sdim
4047218822Sdim  return SUCCESS;
404877298Sobrien}
404977298Sobrien
4050218822Sdim/* Returns the pseudo-register number of an FPA immediate constant,
4051218822Sdim   or FAIL if there isn't a valid constant here.  */
405277298Sobrien
4053218822Sdimstatic int
4054218822Sdimparse_fpa_immediate (char ** str)
405577298Sobrien{
4056218822Sdim  LITTLENUM_TYPE words[MAX_LITTLENUMS];
4057218822Sdim  char *	 save_in;
4058218822Sdim  expressionS	 exp;
4059218822Sdim  int		 i;
4060218822Sdim  int		 j;
406177298Sobrien
4062218822Sdim  /* First try and match exact strings, this is to guarantee
4063218822Sdim     that some formats will work even for cross assembly.  */
406477298Sobrien
4065218822Sdim  for (i = 0; fp_const[i]; i++)
406677298Sobrien    {
4067218822Sdim      if (strncmp (*str, fp_const[i], strlen (fp_const[i])) == 0)
4068218822Sdim	{
4069218822Sdim	  char *start = *str;
407077298Sobrien
4071218822Sdim	  *str += strlen (fp_const[i]);
4072218822Sdim	  if (is_end_of_line[(unsigned char) **str])
4073218822Sdim	    return i + 8;
4074218822Sdim	  *str = start;
4075218822Sdim	}
407677298Sobrien    }
407777298Sobrien
4078218822Sdim  /* Just because we didn't get a match doesn't mean that the constant
4079218822Sdim     isn't valid, just that it is in a format that we don't
4080218822Sdim     automatically recognize.  Try parsing it with the standard
4081218822Sdim     expression routines.  */
4082218822Sdim
4083218822Sdim  memset (words, 0, MAX_LITTLENUMS * sizeof (LITTLENUM_TYPE));
4084218822Sdim
4085218822Sdim  /* Look for a raw floating point number.  */
4086218822Sdim  if ((save_in = atof_ieee (*str, 'x', words)) != NULL
4087218822Sdim      && is_end_of_line[(unsigned char) *save_in])
408877298Sobrien    {
4089218822Sdim      for (i = 0; i < NUM_FLOAT_VALS; i++)
4090218822Sdim	{
4091218822Sdim	  for (j = 0; j < MAX_LITTLENUMS; j++)
4092218822Sdim	    {
4093218822Sdim	      if (words[j] != fp_values[i][j])
4094218822Sdim		break;
4095218822Sdim	    }
409677298Sobrien
4097218822Sdim	  if (j == MAX_LITTLENUMS)
4098218822Sdim	    {
4099218822Sdim	      *str = save_in;
4100218822Sdim	      return i + 8;
4101218822Sdim	    }
4102218822Sdim	}
410377298Sobrien    }
410477298Sobrien
4105218822Sdim  /* Try and parse a more complex expression, this will probably fail
4106218822Sdim     unless the code uses a floating point prefix (eg "0f").  */
4107218822Sdim  save_in = input_line_pointer;
4108218822Sdim  input_line_pointer = *str;
4109218822Sdim  if (expression (&exp) == absolute_section
4110218822Sdim      && exp.X_op == O_big
4111218822Sdim      && exp.X_add_number < 0)
411277298Sobrien    {
4113218822Sdim      /* FIXME: 5 = X_PRECISION, should be #define'd where we can use it.
4114218822Sdim	 Ditto for 15.	*/
4115218822Sdim      if (gen_to_words (words, 5, (long) 15) == 0)
411677298Sobrien	{
4117218822Sdim	  for (i = 0; i < NUM_FLOAT_VALS; i++)
4118218822Sdim	    {
4119218822Sdim	      for (j = 0; j < MAX_LITTLENUMS; j++)
4120218822Sdim		{
4121218822Sdim		  if (words[j] != fp_values[i][j])
4122218822Sdim		    break;
4123218822Sdim		}
4124218822Sdim
4125218822Sdim	      if (j == MAX_LITTLENUMS)
4126218822Sdim		{
4127218822Sdim		  *str = input_line_pointer;
4128218822Sdim		  input_line_pointer = save_in;
4129218822Sdim		  return i + 8;
4130218822Sdim		}
4131218822Sdim	    }
413277298Sobrien	}
413377298Sobrien    }
413477298Sobrien
4135218822Sdim  *str = input_line_pointer;
4136218822Sdim  input_line_pointer = save_in;
4137218822Sdim  inst.error = _("invalid FPA immediate expression");
4138218822Sdim  return FAIL;
413977298Sobrien}
414077298Sobrien
4141218822Sdim/* Returns 1 if a number has "quarter-precision" float format
4142218822Sdim   0baBbbbbbc defgh000 00000000 00000000.  */
414377298Sobrien
4144218822Sdimstatic int
4145218822Sdimis_quarter_float (unsigned imm)
414677298Sobrien{
4147218822Sdim  int bs = (imm & 0x20000000) ? 0x3e000000 : 0x40000000;
4148218822Sdim  return (imm & 0x7ffff) == 0 && ((imm & 0x7e000000) ^ bs) == 0;
4149218822Sdim}
415077298Sobrien
4151218822Sdim/* Parse an 8-bit "quarter-precision" floating point number of the form:
4152218822Sdim   0baBbbbbbc defgh000 00000000 00000000.
4153218822Sdim   The zero and minus-zero cases need special handling, since they can't be
4154218822Sdim   encoded in the "quarter-precision" float format, but can nonetheless be
4155218822Sdim   loaded as integer constants.  */
4156218822Sdim
4157218822Sdimstatic unsigned
4158218822Sdimparse_qfloat_immediate (char **ccp, int *immed)
4159218822Sdim{
4160218822Sdim  char *str = *ccp;
4161218822Sdim  char *fpnum;
4162218822Sdim  LITTLENUM_TYPE words[MAX_LITTLENUMS];
4163218822Sdim  int found_fpchar = 0;
4164218822Sdim
4165218822Sdim  skip_past_char (&str, '#');
4166218822Sdim
4167218822Sdim  /* We must not accidentally parse an integer as a floating-point number. Make
4168218822Sdim     sure that the value we parse is not an integer by checking for special
4169218822Sdim     characters '.' or 'e'.
4170218822Sdim     FIXME: This is a horrible hack, but doing better is tricky because type
4171218822Sdim     information isn't in a very usable state at parse time.  */
4172218822Sdim  fpnum = str;
4173218822Sdim  skip_whitespace (fpnum);
4174218822Sdim
4175218822Sdim  if (strncmp (fpnum, "0x", 2) == 0)
4176218822Sdim    return FAIL;
4177218822Sdim  else
417877298Sobrien    {
4179218822Sdim      for (; *fpnum != '\0' && *fpnum != ' ' && *fpnum != '\n'; fpnum++)
4180218822Sdim        if (*fpnum == '.' || *fpnum == 'e' || *fpnum == 'E')
4181218822Sdim          {
4182218822Sdim            found_fpchar = 1;
4183218822Sdim            break;
4184218822Sdim          }
4185218822Sdim
4186218822Sdim      if (!found_fpchar)
4187218822Sdim        return FAIL;
418877298Sobrien    }
4189218822Sdim
4190218822Sdim  if ((str = atof_ieee (str, 's', words)) != NULL)
4191218822Sdim    {
4192218822Sdim      unsigned fpword = 0;
4193218822Sdim      int i;
4194218822Sdim
4195218822Sdim      /* Our FP word must be 32 bits (single-precision FP).  */
4196218822Sdim      for (i = 0; i < 32 / LITTLENUM_NUMBER_OF_BITS; i++)
4197218822Sdim        {
4198218822Sdim          fpword <<= LITTLENUM_NUMBER_OF_BITS;
4199218822Sdim          fpword |= words[i];
4200218822Sdim        }
4201218822Sdim
4202218822Sdim      if (is_quarter_float (fpword) || (fpword & 0x7fffffff) == 0)
4203218822Sdim        *immed = fpword;
4204218822Sdim      else
4205218822Sdim        return FAIL;
420677298Sobrien
4207218822Sdim      *ccp = str;
4208218822Sdim
4209218822Sdim      return SUCCESS;
421077298Sobrien    }
4211218822Sdim
4212218822Sdim  return FAIL;
4213218822Sdim}
421477298Sobrien
4215218822Sdim/* Shift operands.  */
4216218822Sdimenum shift_kind
4217218822Sdim{
4218218822Sdim  SHIFT_LSL, SHIFT_LSR, SHIFT_ASR, SHIFT_ROR, SHIFT_RRX
4219218822Sdim};
4220218822Sdim
4221218822Sdimstruct asm_shift_name
4222218822Sdim{
4223218822Sdim  const char	  *name;
4224218822Sdim  enum shift_kind  kind;
4225218822Sdim};
4226218822Sdim
4227218822Sdim/* Third argument to parse_shift.  */
4228218822Sdimenum parse_shift_mode
4229218822Sdim{
4230218822Sdim  NO_SHIFT_RESTRICT,		/* Any kind of shift is accepted.  */
4231218822Sdim  SHIFT_IMMEDIATE,		/* Shift operand must be an immediate.	*/
4232218822Sdim  SHIFT_LSL_OR_ASR_IMMEDIATE,	/* Shift must be LSL or ASR immediate.	*/
4233218822Sdim  SHIFT_ASR_IMMEDIATE,		/* Shift must be ASR immediate.	 */
4234218822Sdim  SHIFT_LSL_IMMEDIATE,		/* Shift must be LSL immediate.	 */
4235218822Sdim};
4236218822Sdim
4237218822Sdim/* Parse a <shift> specifier on an ARM data processing instruction.
4238218822Sdim   This has three forms:
4239218822Sdim
4240218822Sdim     (LSL|LSR|ASL|ASR|ROR) Rs
4241218822Sdim     (LSL|LSR|ASL|ASR|ROR) #imm
4242218822Sdim     RRX
4243218822Sdim
4244218822Sdim   Note that ASL is assimilated to LSL in the instruction encoding, and
4245218822Sdim   RRX to ROR #0 (which cannot be written as such).  */
4246218822Sdim
4247218822Sdimstatic int
4248218822Sdimparse_shift (char **str, int i, enum parse_shift_mode mode)
4249218822Sdim{
4250218822Sdim  const struct asm_shift_name *shift_name;
4251218822Sdim  enum shift_kind shift;
4252218822Sdim  char *s = *str;
4253218822Sdim  char *p = s;
4254218822Sdim  int reg;
4255218822Sdim
4256218822Sdim  for (p = *str; ISALPHA (*p); p++)
4257218822Sdim    ;
4258218822Sdim
4259218822Sdim  if (p == *str)
426077298Sobrien    {
4261218822Sdim      inst.error = _("shift expression expected");
4262218822Sdim      return FAIL;
426377298Sobrien    }
426477298Sobrien
4265218822Sdim  shift_name = hash_find_n (arm_shift_hsh, *str, p - *str);
4266218822Sdim
4267218822Sdim  if (shift_name == NULL)
426877298Sobrien    {
4269218822Sdim      inst.error = _("shift expression expected");
4270218822Sdim      return FAIL;
427177298Sobrien    }
427277298Sobrien
4273218822Sdim  shift = shift_name->kind;
4274218822Sdim
4275218822Sdim  switch (mode)
427677298Sobrien    {
4277218822Sdim    case NO_SHIFT_RESTRICT:
4278218822Sdim    case SHIFT_IMMEDIATE:   break;
4279218822Sdim
4280218822Sdim    case SHIFT_LSL_OR_ASR_IMMEDIATE:
4281218822Sdim      if (shift != SHIFT_LSL && shift != SHIFT_ASR)
4282218822Sdim	{
4283218822Sdim	  inst.error = _("'LSL' or 'ASR' required");
4284218822Sdim	  return FAIL;
4285218822Sdim	}
4286218822Sdim      break;
4287218822Sdim
4288218822Sdim    case SHIFT_LSL_IMMEDIATE:
4289218822Sdim      if (shift != SHIFT_LSL)
4290218822Sdim	{
4291218822Sdim	  inst.error = _("'LSL' required");
4292218822Sdim	  return FAIL;
4293218822Sdim	}
4294218822Sdim      break;
4295218822Sdim
4296218822Sdim    case SHIFT_ASR_IMMEDIATE:
4297218822Sdim      if (shift != SHIFT_ASR)
4298218822Sdim	{
4299218822Sdim	  inst.error = _("'ASR' required");
4300218822Sdim	  return FAIL;
4301218822Sdim	}
4302218822Sdim      break;
4303218822Sdim
4304218822Sdim    default: abort ();
430577298Sobrien    }
430677298Sobrien
4307218822Sdim  if (shift != SHIFT_RRX)
430877298Sobrien    {
4309218822Sdim      /* Whitespace can appear here if the next thing is a bare digit.	*/
4310218822Sdim      skip_whitespace (p);
4311218822Sdim
4312218822Sdim      if (mode == NO_SHIFT_RESTRICT
4313218822Sdim	  && (reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL)
431477298Sobrien	{
4315218822Sdim	  inst.operands[i].imm = reg;
4316218822Sdim	  inst.operands[i].immisreg = 1;
431777298Sobrien	}
4318218822Sdim      else if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
4319218822Sdim	return FAIL;
432077298Sobrien    }
4321218822Sdim  inst.operands[i].shift_kind = shift;
4322218822Sdim  inst.operands[i].shifted = 1;
4323218822Sdim  *str = p;
4324218822Sdim  return SUCCESS;
432589857Sobrien}
432677298Sobrien
4327218822Sdim/* Parse a <shifter_operand> for an ARM data processing instruction:
4328218822Sdim
4329218822Sdim      #<immediate>
4330218822Sdim      #<immediate>, <rotate>
4331218822Sdim      <Rm>
4332218822Sdim      <Rm>, <shift>
4333218822Sdim
4334218822Sdim   where <shift> is defined by parse_shift above, and <rotate> is a
4335218822Sdim   multiple of 2 between 0 and 30.  Validation of immediate operands
4336218822Sdim   is deferred to md_apply_fix.  */
4337218822Sdim
4338218822Sdimstatic int
4339218822Sdimparse_shifter_operand (char **str, int i)
434089857Sobrien{
4341218822Sdim  int value;
4342218822Sdim  expressionS expr;
434389857Sobrien
4344218822Sdim  if ((value = arm_reg_parse (str, REG_TYPE_RN)) != FAIL)
4345218822Sdim    {
4346218822Sdim      inst.operands[i].reg = value;
4347218822Sdim      inst.operands[i].isreg = 1;
434889857Sobrien
4349218822Sdim      /* parse_shift will override this if appropriate */
4350218822Sdim      inst.reloc.exp.X_op = O_constant;
4351218822Sdim      inst.reloc.exp.X_add_number = 0;
4352218822Sdim
4353218822Sdim      if (skip_past_comma (str) == FAIL)
4354218822Sdim	return SUCCESS;
4355218822Sdim
4356218822Sdim      /* Shift operation on register.  */
4357218822Sdim      return parse_shift (str, i, NO_SHIFT_RESTRICT);
4358218822Sdim    }
4359218822Sdim
4360218822Sdim  if (my_get_expression (&inst.reloc.exp, str, GE_IMM_PREFIX))
4361218822Sdim    return FAIL;
4362218822Sdim
4363218822Sdim  if (skip_past_comma (str) == SUCCESS)
436489857Sobrien    {
4365218822Sdim      /* #x, y -- ie explicit rotation by Y.  */
4366218822Sdim      if (my_get_expression (&expr, str, GE_NO_PREFIX))
4367218822Sdim	return FAIL;
4368218822Sdim
4369218822Sdim      if (expr.X_op != O_constant || inst.reloc.exp.X_op != O_constant)
4370218822Sdim	{
4371218822Sdim	  inst.error = _("constant expression expected");
4372218822Sdim	  return FAIL;
4373218822Sdim	}
4374218822Sdim
4375218822Sdim      value = expr.X_add_number;
4376218822Sdim      if (value < 0 || value > 30 || value % 2 != 0)
4377218822Sdim	{
4378218822Sdim	  inst.error = _("invalid rotation");
4379218822Sdim	  return FAIL;
4380218822Sdim	}
4381218822Sdim      if (inst.reloc.exp.X_add_number < 0 || inst.reloc.exp.X_add_number > 255)
4382218822Sdim	{
4383218822Sdim	  inst.error = _("invalid constant");
4384218822Sdim	  return FAIL;
4385218822Sdim	}
4386218822Sdim
4387218822Sdim      /* Convert to decoded value.  md_apply_fix will put it back.  */
4388218822Sdim      inst.reloc.exp.X_add_number
4389218822Sdim	= (((inst.reloc.exp.X_add_number << (32 - value))
4390218822Sdim	    | (inst.reloc.exp.X_add_number >> value)) & 0xffffffff);
439189857Sobrien    }
439289857Sobrien
4393218822Sdim  inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
4394218822Sdim  inst.reloc.pc_rel = 0;
4395218822Sdim  return SUCCESS;
439677298Sobrien}
439777298Sobrien
4398218822Sdim/* Group relocation information.  Each entry in the table contains the
4399218822Sdim   textual name of the relocation as may appear in assembler source
4400218822Sdim   and must end with a colon.
4401218822Sdim   Along with this textual name are the relocation codes to be used if
4402218822Sdim   the corresponding instruction is an ALU instruction (ADD or SUB only),
4403218822Sdim   an LDR, an LDRS, or an LDC.  */
4404130561Sobrien
4405218822Sdimstruct group_reloc_table_entry
4406130561Sobrien{
4407218822Sdim  const char *name;
4408218822Sdim  int alu_code;
4409218822Sdim  int ldr_code;
4410218822Sdim  int ldrs_code;
4411218822Sdim  int ldc_code;
4412218822Sdim};
4413130561Sobrien
4414218822Sdimtypedef enum
4415218822Sdim{
4416218822Sdim  /* Varieties of non-ALU group relocation.  */
4417130561Sobrien
4418218822Sdim  GROUP_LDR,
4419218822Sdim  GROUP_LDRS,
4420218822Sdim  GROUP_LDC
4421218822Sdim} group_reloc_type;
4422218822Sdim
4423218822Sdimstatic struct group_reloc_table_entry group_reloc_table[] =
4424218822Sdim  { /* Program counter relative: */
4425218822Sdim    { "pc_g0_nc",
4426218822Sdim      BFD_RELOC_ARM_ALU_PC_G0_NC,	/* ALU */
4427218822Sdim      0,				/* LDR */
4428218822Sdim      0,				/* LDRS */
4429218822Sdim      0 },				/* LDC */
4430218822Sdim    { "pc_g0",
4431218822Sdim      BFD_RELOC_ARM_ALU_PC_G0,		/* ALU */
4432218822Sdim      BFD_RELOC_ARM_LDR_PC_G0,		/* LDR */
4433218822Sdim      BFD_RELOC_ARM_LDRS_PC_G0,		/* LDRS */
4434218822Sdim      BFD_RELOC_ARM_LDC_PC_G0 },	/* LDC */
4435218822Sdim    { "pc_g1_nc",
4436218822Sdim      BFD_RELOC_ARM_ALU_PC_G1_NC,	/* ALU */
4437218822Sdim      0,				/* LDR */
4438218822Sdim      0,				/* LDRS */
4439218822Sdim      0 },				/* LDC */
4440218822Sdim    { "pc_g1",
4441218822Sdim      BFD_RELOC_ARM_ALU_PC_G1,		/* ALU */
4442218822Sdim      BFD_RELOC_ARM_LDR_PC_G1, 		/* LDR */
4443218822Sdim      BFD_RELOC_ARM_LDRS_PC_G1,		/* LDRS */
4444218822Sdim      BFD_RELOC_ARM_LDC_PC_G1 },	/* LDC */
4445218822Sdim    { "pc_g2",
4446218822Sdim      BFD_RELOC_ARM_ALU_PC_G2,		/* ALU */
4447218822Sdim      BFD_RELOC_ARM_LDR_PC_G2,		/* LDR */
4448218822Sdim      BFD_RELOC_ARM_LDRS_PC_G2,		/* LDRS */
4449218822Sdim      BFD_RELOC_ARM_LDC_PC_G2 },	/* LDC */
4450218822Sdim    /* Section base relative */
4451218822Sdim    { "sb_g0_nc",
4452218822Sdim      BFD_RELOC_ARM_ALU_SB_G0_NC,	/* ALU */
4453218822Sdim      0,				/* LDR */
4454218822Sdim      0,				/* LDRS */
4455218822Sdim      0 },				/* LDC */
4456218822Sdim    { "sb_g0",
4457218822Sdim      BFD_RELOC_ARM_ALU_SB_G0,		/* ALU */
4458218822Sdim      BFD_RELOC_ARM_LDR_SB_G0,		/* LDR */
4459218822Sdim      BFD_RELOC_ARM_LDRS_SB_G0,		/* LDRS */
4460218822Sdim      BFD_RELOC_ARM_LDC_SB_G0 },	/* LDC */
4461218822Sdim    { "sb_g1_nc",
4462218822Sdim      BFD_RELOC_ARM_ALU_SB_G1_NC,	/* ALU */
4463218822Sdim      0,				/* LDR */
4464218822Sdim      0,				/* LDRS */
4465218822Sdim      0 },				/* LDC */
4466218822Sdim    { "sb_g1",
4467218822Sdim      BFD_RELOC_ARM_ALU_SB_G1,		/* ALU */
4468218822Sdim      BFD_RELOC_ARM_LDR_SB_G1, 		/* LDR */
4469218822Sdim      BFD_RELOC_ARM_LDRS_SB_G1,		/* LDRS */
4470218822Sdim      BFD_RELOC_ARM_LDC_SB_G1 },	/* LDC */
4471218822Sdim    { "sb_g2",
4472218822Sdim      BFD_RELOC_ARM_ALU_SB_G2,		/* ALU */
4473218822Sdim      BFD_RELOC_ARM_LDR_SB_G2,		/* LDR */
4474218822Sdim      BFD_RELOC_ARM_LDRS_SB_G2,		/* LDRS */
4475218822Sdim      BFD_RELOC_ARM_LDC_SB_G2 }	};	/* LDC */
4476218822Sdim
4477218822Sdim/* Given the address of a pointer pointing to the textual name of a group
4478218822Sdim   relocation as may appear in assembler source, attempt to find its details
4479218822Sdim   in group_reloc_table.  The pointer will be updated to the character after
4480218822Sdim   the trailing colon.  On failure, FAIL will be returned; SUCCESS
4481218822Sdim   otherwise.  On success, *entry will be updated to point at the relevant
4482218822Sdim   group_reloc_table entry. */
4483218822Sdim
4484218822Sdimstatic int
4485218822Sdimfind_group_reloc_table_entry (char **str, struct group_reloc_table_entry **out)
4486218822Sdim{
4487218822Sdim  unsigned int i;
4488218822Sdim  for (i = 0; i < ARRAY_SIZE (group_reloc_table); i++)
4489130561Sobrien    {
4490218822Sdim      int length = strlen (group_reloc_table[i].name);
4491130561Sobrien
4492218822Sdim      if (strncasecmp (group_reloc_table[i].name, *str, length) == 0 &&
4493218822Sdim          (*str)[length] == ':')
4494218822Sdim        {
4495218822Sdim          *out = &group_reloc_table[i];
4496218822Sdim          *str += (length + 1);
4497218822Sdim          return SUCCESS;
4498218822Sdim        }
4499130561Sobrien    }
4500130561Sobrien
4501218822Sdim  return FAIL;
4502130561Sobrien}
4503130561Sobrien
4504218822Sdim/* Parse a <shifter_operand> for an ARM data processing instruction
4505218822Sdim   (as for parse_shifter_operand) where group relocations are allowed:
4506130561Sobrien
4507218822Sdim      #<immediate>
4508218822Sdim      #<immediate>, <rotate>
4509218822Sdim      #:<group_reloc>:<expression>
4510218822Sdim      <Rm>
4511218822Sdim      <Rm>, <shift>
4512218822Sdim
4513218822Sdim   where <group_reloc> is one of the strings defined in group_reloc_table.
4514218822Sdim   The hashes are optional.
4515218822Sdim
4516218822Sdim   Everything else is as for parse_shifter_operand.  */
4517218822Sdim
4518218822Sdimstatic parse_operand_result
4519218822Sdimparse_shifter_operand_group_reloc (char **str, int i)
4520130561Sobrien{
4521218822Sdim  /* Determine if we have the sequence of characters #: or just :
4522218822Sdim     coming next.  If we do, then we check for a group relocation.
4523218822Sdim     If we don't, punt the whole lot to parse_shifter_operand.  */
4524130561Sobrien
4525218822Sdim  if (((*str)[0] == '#' && (*str)[1] == ':')
4526218822Sdim      || (*str)[0] == ':')
4527130561Sobrien    {
4528218822Sdim      struct group_reloc_table_entry *entry;
4529130561Sobrien
4530218822Sdim      if ((*str)[0] == '#')
4531218822Sdim        (*str) += 2;
4532218822Sdim      else
4533218822Sdim        (*str)++;
4534130561Sobrien
4535218822Sdim      /* Try to parse a group relocation.  Anything else is an error.  */
4536218822Sdim      if (find_group_reloc_table_entry (str, &entry) == FAIL)
4537218822Sdim        {
4538218822Sdim          inst.error = _("unknown group relocation");
4539218822Sdim          return PARSE_OPERAND_FAIL_NO_BACKTRACK;
4540218822Sdim        }
4541218822Sdim
4542218822Sdim      /* We now have the group relocation table entry corresponding to
4543218822Sdim         the name in the assembler source.  Next, we parse the expression.  */
4544218822Sdim      if (my_get_expression (&inst.reloc.exp, str, GE_NO_PREFIX))
4545218822Sdim        return PARSE_OPERAND_FAIL_NO_BACKTRACK;
4546218822Sdim
4547218822Sdim      /* Record the relocation type (always the ALU variant here).  */
4548218822Sdim      inst.reloc.type = entry->alu_code;
4549218822Sdim      assert (inst.reloc.type != 0);
4550218822Sdim
4551218822Sdim      return PARSE_OPERAND_SUCCESS;
4552130561Sobrien    }
4553218822Sdim  else
4554218822Sdim    return parse_shifter_operand (str, i) == SUCCESS
4555218822Sdim           ? PARSE_OPERAND_SUCCESS : PARSE_OPERAND_FAIL;
4556130561Sobrien
4557218822Sdim  /* Never reached.  */
4558130561Sobrien}
4559130561Sobrien
4560218822Sdim/* Parse all forms of an ARM address expression.  Information is written
4561218822Sdim   to inst.operands[i] and/or inst.reloc.
4562130561Sobrien
4563218822Sdim   Preindexed addressing (.preind=1):
4564130561Sobrien
4565218822Sdim   [Rn, #offset]       .reg=Rn .reloc.exp=offset
4566218822Sdim   [Rn, +/-Rm]	       .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
4567218822Sdim   [Rn, +/-Rm, shift]  .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
4568218822Sdim		       .shift_kind=shift .reloc.exp=shift_imm
4569130561Sobrien
4570218822Sdim   These three may have a trailing ! which causes .writeback to be set also.
4571130561Sobrien
4572218822Sdim   Postindexed addressing (.postind=1, .writeback=1):
4573218822Sdim
4574218822Sdim   [Rn], #offset       .reg=Rn .reloc.exp=offset
4575218822Sdim   [Rn], +/-Rm	       .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
4576218822Sdim   [Rn], +/-Rm, shift  .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
4577218822Sdim		       .shift_kind=shift .reloc.exp=shift_imm
4578218822Sdim
4579218822Sdim   Unindexed addressing (.preind=0, .postind=0):
4580218822Sdim
4581218822Sdim   [Rn], {option}      .reg=Rn .imm=option .immisreg=0
4582218822Sdim
4583218822Sdim   Other:
4584218822Sdim
4585218822Sdim   [Rn]{!}	       shorthand for [Rn,#0]{!}
4586218822Sdim   =immediate	       .isreg=0 .reloc.exp=immediate
4587218822Sdim   label	       .reg=PC .reloc.pc_rel=1 .reloc.exp=label
4588218822Sdim
4589218822Sdim  It is the caller's responsibility to check for addressing modes not
4590218822Sdim  supported by the instruction, and to set inst.reloc.type.  */
4591218822Sdim
4592218822Sdimstatic parse_operand_result
4593218822Sdimparse_address_main (char **str, int i, int group_relocations,
4594218822Sdim                    group_reloc_type group_type)
4595130561Sobrien{
4596218822Sdim  char *p = *str;
4597218822Sdim  int reg;
4598130561Sobrien
4599218822Sdim  if (skip_past_char (&p, '[') == FAIL)
4600130561Sobrien    {
4601218822Sdim      if (skip_past_char (&p, '=') == FAIL)
4602218822Sdim	{
4603218822Sdim	  /* bare address - translate to PC-relative offset */
4604218822Sdim	  inst.reloc.pc_rel = 1;
4605218822Sdim	  inst.operands[i].reg = REG_PC;
4606218822Sdim	  inst.operands[i].isreg = 1;
4607218822Sdim	  inst.operands[i].preind = 1;
4608218822Sdim	}
4609218822Sdim      /* else a load-constant pseudo op, no special treatment needed here */
4610218822Sdim
4611218822Sdim      if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX))
4612218822Sdim	return PARSE_OPERAND_FAIL;
4613218822Sdim
4614218822Sdim      *str = p;
4615218822Sdim      return PARSE_OPERAND_SUCCESS;
4616130561Sobrien    }
4617218822Sdim
4618218822Sdim  if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
4619130561Sobrien    {
4620218822Sdim      inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
4621218822Sdim      return PARSE_OPERAND_FAIL;
4622130561Sobrien    }
4623218822Sdim  inst.operands[i].reg = reg;
4624218822Sdim  inst.operands[i].isreg = 1;
4625130561Sobrien
4626218822Sdim  if (skip_past_comma (&p) == SUCCESS)
4627130561Sobrien    {
4628218822Sdim      inst.operands[i].preind = 1;
4629218822Sdim
4630218822Sdim      if (*p == '+') p++;
4631218822Sdim      else if (*p == '-') p++, inst.operands[i].negative = 1;
4632218822Sdim
4633218822Sdim      if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL)
4634218822Sdim	{
4635218822Sdim	  inst.operands[i].imm = reg;
4636218822Sdim	  inst.operands[i].immisreg = 1;
4637218822Sdim
4638218822Sdim	  if (skip_past_comma (&p) == SUCCESS)
4639218822Sdim	    if (parse_shift (&p, i, SHIFT_IMMEDIATE) == FAIL)
4640218822Sdim	      return PARSE_OPERAND_FAIL;
4641218822Sdim	}
4642218822Sdim      else if (skip_past_char (&p, ':') == SUCCESS)
4643218822Sdim        {
4644218822Sdim          /* FIXME: '@' should be used here, but it's filtered out by generic
4645218822Sdim             code before we get to see it here. This may be subject to
4646218822Sdim             change.  */
4647218822Sdim          expressionS exp;
4648218822Sdim          my_get_expression (&exp, &p, GE_NO_PREFIX);
4649218822Sdim          if (exp.X_op != O_constant)
4650218822Sdim            {
4651218822Sdim              inst.error = _("alignment must be constant");
4652218822Sdim              return PARSE_OPERAND_FAIL;
4653218822Sdim            }
4654218822Sdim          inst.operands[i].imm = exp.X_add_number << 8;
4655218822Sdim          inst.operands[i].immisalign = 1;
4656218822Sdim          /* Alignments are not pre-indexes.  */
4657218822Sdim          inst.operands[i].preind = 0;
4658218822Sdim        }
4659218822Sdim      else
4660218822Sdim	{
4661218822Sdim	  if (inst.operands[i].negative)
4662218822Sdim	    {
4663218822Sdim	      inst.operands[i].negative = 0;
4664218822Sdim	      p--;
4665218822Sdim	    }
4666218822Sdim
4667218822Sdim	  if (group_relocations &&
4668218822Sdim              ((*p == '#' && *(p + 1) == ':') || *p == ':'))
4669218822Sdim
4670218822Sdim	    {
4671218822Sdim	      struct group_reloc_table_entry *entry;
4672218822Sdim
4673218822Sdim              /* Skip over the #: or : sequence.  */
4674218822Sdim              if (*p == '#')
4675218822Sdim                p += 2;
4676218822Sdim              else
4677218822Sdim                p++;
4678218822Sdim
4679218822Sdim	      /* Try to parse a group relocation.  Anything else is an
4680218822Sdim                 error.  */
4681218822Sdim	      if (find_group_reloc_table_entry (&p, &entry) == FAIL)
4682218822Sdim		{
4683218822Sdim		  inst.error = _("unknown group relocation");
4684218822Sdim		  return PARSE_OPERAND_FAIL_NO_BACKTRACK;
4685218822Sdim		}
4686218822Sdim
4687218822Sdim	      /* We now have the group relocation table entry corresponding to
4688218822Sdim		 the name in the assembler source.  Next, we parse the
4689218822Sdim                 expression.  */
4690218822Sdim	      if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX))
4691218822Sdim		return PARSE_OPERAND_FAIL_NO_BACKTRACK;
4692218822Sdim
4693218822Sdim	      /* Record the relocation type.  */
4694218822Sdim              switch (group_type)
4695218822Sdim                {
4696218822Sdim                  case GROUP_LDR:
4697218822Sdim	            inst.reloc.type = entry->ldr_code;
4698218822Sdim                    break;
4699218822Sdim
4700218822Sdim                  case GROUP_LDRS:
4701218822Sdim	            inst.reloc.type = entry->ldrs_code;
4702218822Sdim                    break;
4703218822Sdim
4704218822Sdim                  case GROUP_LDC:
4705218822Sdim	            inst.reloc.type = entry->ldc_code;
4706218822Sdim                    break;
4707218822Sdim
4708218822Sdim                  default:
4709218822Sdim                    assert (0);
4710218822Sdim                }
4711218822Sdim
4712218822Sdim              if (inst.reloc.type == 0)
4713218822Sdim		{
4714218822Sdim		  inst.error = _("this group relocation is not allowed on this instruction");
4715218822Sdim		  return PARSE_OPERAND_FAIL_NO_BACKTRACK;
4716218822Sdim		}
4717218822Sdim            }
4718218822Sdim          else
4719218822Sdim	    if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
4720218822Sdim	      return PARSE_OPERAND_FAIL;
4721218822Sdim	}
4722130561Sobrien    }
4723272476Sandrew  else if (skip_past_char (&p, ':') == SUCCESS)
4724272476Sandrew    {
4725272476Sandrew      /* FIXME: '@' should be used here, but it's filtered out by generic
4726272476Sandrew         code before we get to see it here. This may be subject to
4727272476Sandrew         change.  */
4728272476Sandrew      expressionS exp;
4729272476Sandrew      my_get_expression (&exp, &p, GE_NO_PREFIX);
4730272476Sandrew      if (exp.X_op != O_constant)
4731272476Sandrew        {
4732272476Sandrew          inst.error = _("alignment must be constant");
4733272476Sandrew          return PARSE_OPERAND_FAIL;
4734272476Sandrew        }
4735272476Sandrew      inst.operands[i].imm = exp.X_add_number << 8;
4736272476Sandrew      inst.operands[i].immisalign = 1;
4737272476Sandrew      /* Alignments are not pre-indexes.  */
4738272476Sandrew      inst.operands[i].preind = 0;
4739272476Sandrew    }
4740218822Sdim
4741218822Sdim  if (skip_past_char (&p, ']') == FAIL)
4742130561Sobrien    {
4743218822Sdim      inst.error = _("']' expected");
4744218822Sdim      return PARSE_OPERAND_FAIL;
4745130561Sobrien    }
4746218822Sdim
4747218822Sdim  if (skip_past_char (&p, '!') == SUCCESS)
4748218822Sdim    inst.operands[i].writeback = 1;
4749218822Sdim
4750218822Sdim  else if (skip_past_comma (&p) == SUCCESS)
4751130561Sobrien    {
4752218822Sdim      if (skip_past_char (&p, '{') == SUCCESS)
4753218822Sdim	{
4754218822Sdim	  /* [Rn], {expr} - unindexed, with option */
4755218822Sdim	  if (parse_immediate (&p, &inst.operands[i].imm,
4756218822Sdim			       0, 255, TRUE) == FAIL)
4757218822Sdim	    return PARSE_OPERAND_FAIL;
4758218822Sdim
4759218822Sdim	  if (skip_past_char (&p, '}') == FAIL)
4760218822Sdim	    {
4761218822Sdim	      inst.error = _("'}' expected at end of 'option' field");
4762218822Sdim	      return PARSE_OPERAND_FAIL;
4763218822Sdim	    }
4764218822Sdim	  if (inst.operands[i].preind)
4765218822Sdim	    {
4766218822Sdim	      inst.error = _("cannot combine index with option");
4767218822Sdim	      return PARSE_OPERAND_FAIL;
4768218822Sdim	    }
4769218822Sdim	  *str = p;
4770218822Sdim	  return PARSE_OPERAND_SUCCESS;
4771218822Sdim	}
4772218822Sdim      else
4773218822Sdim	{
4774218822Sdim	  inst.operands[i].postind = 1;
4775218822Sdim	  inst.operands[i].writeback = 1;
4776218822Sdim
4777218822Sdim	  if (inst.operands[i].preind)
4778218822Sdim	    {
4779218822Sdim	      inst.error = _("cannot combine pre- and post-indexing");
4780218822Sdim	      return PARSE_OPERAND_FAIL;
4781218822Sdim	    }
4782218822Sdim
4783218822Sdim	  if (*p == '+') p++;
4784218822Sdim	  else if (*p == '-') p++, inst.operands[i].negative = 1;
4785218822Sdim
4786218822Sdim	  if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL)
4787218822Sdim	    {
4788218822Sdim              /* We might be using the immediate for alignment already. If we
4789218822Sdim                 are, OR the register number into the low-order bits.  */
4790218822Sdim              if (inst.operands[i].immisalign)
4791218822Sdim	        inst.operands[i].imm |= reg;
4792218822Sdim              else
4793218822Sdim                inst.operands[i].imm = reg;
4794218822Sdim	      inst.operands[i].immisreg = 1;
4795218822Sdim
4796218822Sdim	      if (skip_past_comma (&p) == SUCCESS)
4797218822Sdim		if (parse_shift (&p, i, SHIFT_IMMEDIATE) == FAIL)
4798218822Sdim		  return PARSE_OPERAND_FAIL;
4799218822Sdim	    }
4800218822Sdim	  else
4801218822Sdim	    {
4802218822Sdim	      if (inst.operands[i].negative)
4803218822Sdim		{
4804218822Sdim		  inst.operands[i].negative = 0;
4805218822Sdim		  p--;
4806218822Sdim		}
4807218822Sdim	      if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
4808218822Sdim		return PARSE_OPERAND_FAIL;
4809218822Sdim	    }
4810218822Sdim	}
4811130561Sobrien    }
4812130561Sobrien
4813218822Sdim  /* If at this point neither .preind nor .postind is set, we have a
4814218822Sdim     bare [Rn]{!}, which is shorthand for [Rn,#0]{!}.  */
4815218822Sdim  if (inst.operands[i].preind == 0 && inst.operands[i].postind == 0)
4816130561Sobrien    {
4817218822Sdim      inst.operands[i].preind = 1;
4818218822Sdim      inst.reloc.exp.X_op = O_constant;
4819218822Sdim      inst.reloc.exp.X_add_number = 0;
4820130561Sobrien    }
4821218822Sdim  *str = p;
4822218822Sdim  return PARSE_OPERAND_SUCCESS;
4823130561Sobrien}
4824130561Sobrien
4825218822Sdimstatic int
4826218822Sdimparse_address (char **str, int i)
4827130561Sobrien{
4828218822Sdim  return parse_address_main (str, i, 0, 0) == PARSE_OPERAND_SUCCESS
4829218822Sdim         ? SUCCESS : FAIL;
4830130561Sobrien}
4831130561Sobrien
4832218822Sdimstatic parse_operand_result
4833218822Sdimparse_address_group_reloc (char **str, int i, group_reloc_type type)
4834130561Sobrien{
4835218822Sdim  return parse_address_main (str, i, 1, type);
4836130561Sobrien}
4837130561Sobrien
4838218822Sdim/* Parse an operand for a MOVW or MOVT instruction.  */
4839218822Sdimstatic int
4840218822Sdimparse_half (char **str)
4841130561Sobrien{
4842218822Sdim  char * p;
4843218822Sdim
4844218822Sdim  p = *str;
4845218822Sdim  skip_past_char (&p, '#');
4846218822Sdim  if (strncasecmp (p, ":lower16:", 9) == 0)
4847218822Sdim    inst.reloc.type = BFD_RELOC_ARM_MOVW;
4848218822Sdim  else if (strncasecmp (p, ":upper16:", 9) == 0)
4849218822Sdim    inst.reloc.type = BFD_RELOC_ARM_MOVT;
4850130561Sobrien
4851218822Sdim  if (inst.reloc.type != BFD_RELOC_UNUSED)
4852130561Sobrien    {
4853218822Sdim      p += 9;
4854218822Sdim      skip_whitespace(p);
4855130561Sobrien    }
4856218822Sdim
4857218822Sdim  if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX))
4858218822Sdim    return FAIL;
4859218822Sdim
4860218822Sdim  if (inst.reloc.type == BFD_RELOC_UNUSED)
4861130561Sobrien    {
4862218822Sdim      if (inst.reloc.exp.X_op != O_constant)
4863218822Sdim	{
4864218822Sdim	  inst.error = _("constant expression expected");
4865218822Sdim	  return FAIL;
4866218822Sdim	}
4867218822Sdim      if (inst.reloc.exp.X_add_number < 0
4868218822Sdim	  || inst.reloc.exp.X_add_number > 0xffff)
4869218822Sdim	{
4870218822Sdim	  inst.error = _("immediate value out of range");
4871218822Sdim	  return FAIL;
4872218822Sdim	}
4873130561Sobrien    }
4874218822Sdim  *str = p;
4875218822Sdim  return SUCCESS;
4876218822Sdim}
4877130561Sobrien
4878218822Sdim/* Miscellaneous. */
4879218822Sdim
4880218822Sdim/* Parse a PSR flag operand.  The value returned is FAIL on syntax error,
4881218822Sdim   or a bitmask suitable to be or-ed into the ARM msr instruction.  */
4882218822Sdimstatic int
4883218822Sdimparse_psr (char **str)
4884218822Sdim{
4885218822Sdim  char *p;
4886218822Sdim  unsigned long psr_field;
4887218822Sdim  const struct asm_psr *psr;
4888218822Sdim  char *start;
4889218822Sdim
4890218822Sdim  /* CPSR's and SPSR's can now be lowercase.  This is just a convenience
4891218822Sdim     feature for ease of use and backwards compatibility.  */
4892218822Sdim  p = *str;
4893218822Sdim  if (strncasecmp (p, "SPSR", 4) == 0)
4894218822Sdim    psr_field = SPSR_BIT;
4895218822Sdim  else if (strncasecmp (p, "CPSR", 4) == 0)
4896218822Sdim    psr_field = 0;
4897130561Sobrien  else
4898130561Sobrien    {
4899218822Sdim      start = p;
4900218822Sdim      do
4901218822Sdim	p++;
4902218822Sdim      while (ISALNUM (*p) || *p == '_');
4903218822Sdim
4904218822Sdim      psr = hash_find_n (arm_v7m_psr_hsh, start, p - start);
4905218822Sdim      if (!psr)
4906218822Sdim	return FAIL;
4907218822Sdim
4908218822Sdim      *str = p;
4909218822Sdim      return psr->field;
4910130561Sobrien    }
4911218822Sdim
4912218822Sdim  p += 4;
4913218822Sdim  if (*p == '_')
4914130561Sobrien    {
4915218822Sdim      /* A suffix follows.  */
4916218822Sdim      p++;
4917218822Sdim      start = p;
4918218822Sdim
4919218822Sdim      do
4920218822Sdim	p++;
4921218822Sdim      while (ISALNUM (*p) || *p == '_');
4922218822Sdim
4923218822Sdim      psr = hash_find_n (arm_psr_hsh, start, p - start);
4924218822Sdim      if (!psr)
4925218822Sdim	goto error;
4926218822Sdim
4927218822Sdim      psr_field |= psr->field;
4928130561Sobrien    }
4929218822Sdim  else
4930130561Sobrien    {
4931218822Sdim      if (ISALNUM (*p))
4932218822Sdim	goto error;    /* Garbage after "[CS]PSR".  */
4933218822Sdim
4934218822Sdim      psr_field |= (PSR_c | PSR_f);
4935130561Sobrien    }
4936218822Sdim  *str = p;
4937218822Sdim  return psr_field;
4938130561Sobrien
4939218822Sdim error:
4940218822Sdim  inst.error = _("flag for {c}psr instruction expected");
4941218822Sdim  return FAIL;
4942130561Sobrien}
4943130561Sobrien
4944218822Sdim/* Parse the flags argument to CPSI[ED].  Returns FAIL on error, or a
4945218822Sdim   value suitable for splatting into the AIF field of the instruction.	*/
4946130561Sobrien
4947218822Sdimstatic int
4948218822Sdimparse_cps_flags (char **str)
4949130561Sobrien{
4950218822Sdim  int val = 0;
4951218822Sdim  int saw_a_flag = 0;
4952218822Sdim  char *s = *str;
4953130561Sobrien
4954218822Sdim  for (;;)
4955218822Sdim    switch (*s++)
4956218822Sdim      {
4957218822Sdim      case '\0': case ',':
4958218822Sdim	goto done;
4959130561Sobrien
4960218822Sdim      case 'a': case 'A': saw_a_flag = 1; val |= 0x4; break;
4961218822Sdim      case 'i': case 'I': saw_a_flag = 1; val |= 0x2; break;
4962218822Sdim      case 'f': case 'F': saw_a_flag = 1; val |= 0x1; break;
4963130561Sobrien
4964218822Sdim      default:
4965218822Sdim	inst.error = _("unrecognized CPS flag");
4966218822Sdim	return FAIL;
4967218822Sdim      }
4968218822Sdim
4969218822Sdim done:
4970218822Sdim  if (saw_a_flag == 0)
4971130561Sobrien    {
4972218822Sdim      inst.error = _("missing CPS flags");
4973218822Sdim      return FAIL;
4974130561Sobrien    }
4975130561Sobrien
4976218822Sdim  *str = s - 1;
4977218822Sdim  return val;
4978130561Sobrien}
4979130561Sobrien
4980218822Sdim/* Parse an endian specifier ("BE" or "LE", case insensitive);
4981218822Sdim   returns 0 for big-endian, 1 for little-endian, FAIL for an error.  */
4982130561Sobrien
4983218822Sdimstatic int
4984218822Sdimparse_endian_specifier (char **str)
4985130561Sobrien{
4986218822Sdim  int little_endian;
4987218822Sdim  char *s = *str;
4988218822Sdim
4989218822Sdim  if (strncasecmp (s, "BE", 2))
4990218822Sdim    little_endian = 0;
4991218822Sdim  else if (strncasecmp (s, "LE", 2))
4992218822Sdim    little_endian = 1;
4993218822Sdim  else
4994130561Sobrien    {
4995218822Sdim      inst.error = _("valid endian specifiers are be or le");
4996218822Sdim      return FAIL;
4997130561Sobrien    }
4998130561Sobrien
4999218822Sdim  if (ISALNUM (s[2]) || s[2] == '_')
5000130561Sobrien    {
5001218822Sdim      inst.error = _("valid endian specifiers are be or le");
5002218822Sdim      return FAIL;
5003130561Sobrien    }
5004130561Sobrien
5005218822Sdim  *str = s + 2;
5006218822Sdim  return little_endian;
5007130561Sobrien}
5008130561Sobrien
5009218822Sdim/* Parse a rotation specifier: ROR #0, #8, #16, #24.  *val receives a
5010218822Sdim   value suitable for poking into the rotate field of an sxt or sxta
5011218822Sdim   instruction, or FAIL on error.  */
5012130561Sobrien
5013218822Sdimstatic int
5014218822Sdimparse_ror (char **str)
5015130561Sobrien{
5016218822Sdim  int rot;
5017218822Sdim  char *s = *str;
5018218822Sdim
5019218822Sdim  if (strncasecmp (s, "ROR", 3) == 0)
5020218822Sdim    s += 3;
5021218822Sdim  else
5022130561Sobrien    {
5023218822Sdim      inst.error = _("missing rotation field after comma");
5024218822Sdim      return FAIL;
5025130561Sobrien    }
5026218822Sdim
5027218822Sdim  if (parse_immediate (&s, &rot, 0, 24, FALSE) == FAIL)
5028218822Sdim    return FAIL;
5029218822Sdim
5030218822Sdim  switch (rot)
5031130561Sobrien    {
5032218822Sdim    case  0: *str = s; return 0x0;
5033218822Sdim    case  8: *str = s; return 0x1;
5034218822Sdim    case 16: *str = s; return 0x2;
5035218822Sdim    case 24: *str = s; return 0x3;
5036218822Sdim
5037218822Sdim    default:
5038218822Sdim      inst.error = _("rotation can only be 0, 8, 16, or 24");
5039218822Sdim      return FAIL;
5040130561Sobrien    }
5041218822Sdim}
5042130561Sobrien
5043218822Sdim/* Parse a conditional code (from conds[] below).  The value returned is in the
5044218822Sdim   range 0 .. 14, or FAIL.  */
5045218822Sdimstatic int
5046218822Sdimparse_cond (char **str)
5047218822Sdim{
5048218822Sdim  char *p, *q;
5049218822Sdim  const struct asm_cond *c;
5050130561Sobrien
5051218822Sdim  p = q = *str;
5052218822Sdim  while (ISALPHA (*q))
5053218822Sdim    q++;
5054130561Sobrien
5055218822Sdim  c = hash_find_n (arm_cond_hsh, p, q - p);
5056218822Sdim  if (!c)
5057218822Sdim    {
5058218822Sdim      inst.error = _("condition required");
5059218822Sdim      return FAIL;
5060218822Sdim    }
5061130561Sobrien
5062218822Sdim  *str = q;
5063218822Sdim  return c->value;
5064130561Sobrien}
5065130561Sobrien
5066218822Sdim/* Parse an option for a barrier instruction.  Returns the encoding for the
5067218822Sdim   option, or FAIL.  */
5068130561Sobrienstatic int
5069218822Sdimparse_barrier (char **str)
5070130561Sobrien{
5071218822Sdim  char *p, *q;
5072218822Sdim  const struct asm_barrier_opt *o;
5073130561Sobrien
5074218822Sdim  p = q = *str;
5075218822Sdim  while (ISALPHA (*q))
5076218822Sdim    q++;
5077130561Sobrien
5078218822Sdim  o = hash_find_n (arm_barrier_opt_hsh, p, q - p);
5079218822Sdim  if (!o)
5080218822Sdim    return FAIL;
5081130561Sobrien
5082218822Sdim  *str = q;
5083218822Sdim  return o->value;
5084130561Sobrien}
5085130561Sobrien
5086218822Sdim/* Parse the operands of a table branch instruction.  Similar to a memory
5087218822Sdim   operand.  */
5088218822Sdimstatic int
5089218822Sdimparse_tb (char **str)
5090218822Sdim{
5091218822Sdim  char * p = *str;
5092218822Sdim  int reg;
5093130561Sobrien
5094218822Sdim  if (skip_past_char (&p, '[') == FAIL)
5095130561Sobrien    {
5096218822Sdim      inst.error = _("'[' expected");
5097218822Sdim      return FAIL;
5098130561Sobrien    }
5099130561Sobrien
5100218822Sdim  if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
5101130561Sobrien    {
5102218822Sdim      inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
5103218822Sdim      return FAIL;
5104130561Sobrien    }
5105218822Sdim  inst.operands[0].reg = reg;
5106218822Sdim
5107218822Sdim  if (skip_past_comma (&p) == FAIL)
5108130561Sobrien    {
5109218822Sdim      inst.error = _("',' expected");
5110218822Sdim      return FAIL;
5111130561Sobrien    }
5112130561Sobrien
5113218822Sdim  if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
5114130561Sobrien    {
5115218822Sdim      inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
5116218822Sdim      return FAIL;
5117130561Sobrien    }
5118218822Sdim  inst.operands[0].imm = reg;
5119218822Sdim
5120218822Sdim  if (skip_past_comma (&p) == SUCCESS)
5121130561Sobrien    {
5122218822Sdim      if (parse_shift (&p, 0, SHIFT_LSL_IMMEDIATE) == FAIL)
5123218822Sdim	return FAIL;
5124218822Sdim      if (inst.reloc.exp.X_add_number != 1)
5125218822Sdim	{
5126218822Sdim	  inst.error = _("invalid shift");
5127218822Sdim	  return FAIL;
5128218822Sdim	}
5129218822Sdim      inst.operands[0].shifted = 1;
5130130561Sobrien    }
5131218822Sdim
5132218822Sdim  if (skip_past_char (&p, ']') == FAIL)
5133130561Sobrien    {
5134218822Sdim      inst.error = _("']' expected");
5135218822Sdim      return FAIL;
5136130561Sobrien    }
5137218822Sdim  *str = p;
5138218822Sdim  return SUCCESS;
5139218822Sdim}
5140130561Sobrien
5141218822Sdim/* Parse the operands of a Neon VMOV instruction. See do_neon_mov for more
5142218822Sdim   information on the types the operands can take and how they are encoded.
5143218822Sdim   Up to four operands may be read; this function handles setting the
5144218822Sdim   ".present" field for each read operand itself.
5145218822Sdim   Updates STR and WHICH_OPERAND if parsing is successful and returns SUCCESS,
5146218822Sdim   else returns FAIL.  */
5147218822Sdim
5148218822Sdimstatic int
5149218822Sdimparse_neon_mov (char **str, int *which_operand)
5150218822Sdim{
5151218822Sdim  int i = *which_operand, val;
5152218822Sdim  enum arm_reg_type rtype;
5153218822Sdim  char *ptr = *str;
5154218822Sdim  struct neon_type_el optype;
5155130561Sobrien
5156218822Sdim  if ((val = parse_scalar (&ptr, 8, &optype)) != FAIL)
5157130561Sobrien    {
5158218822Sdim      /* Case 4: VMOV<c><q>.<size> <Dn[x]>, <Rd>.  */
5159218822Sdim      inst.operands[i].reg = val;
5160218822Sdim      inst.operands[i].isscalar = 1;
5161218822Sdim      inst.operands[i].vectype = optype;
5162218822Sdim      inst.operands[i++].present = 1;
5163130561Sobrien
5164218822Sdim      if (skip_past_comma (&ptr) == FAIL)
5165218822Sdim        goto wanted_comma;
5166130561Sobrien
5167218822Sdim      if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) == FAIL)
5168218822Sdim        goto wanted_arm;
5169218822Sdim
5170218822Sdim      inst.operands[i].reg = val;
5171218822Sdim      inst.operands[i].isreg = 1;
5172218822Sdim      inst.operands[i].present = 1;
5173130561Sobrien    }
5174218822Sdim  else if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_NSDQ, &rtype, &optype))
5175218822Sdim           != FAIL)
5176218822Sdim    {
5177218822Sdim      /* Cases 0, 1, 2, 3, 5 (D only).  */
5178218822Sdim      if (skip_past_comma (&ptr) == FAIL)
5179218822Sdim        goto wanted_comma;
5180218822Sdim
5181218822Sdim      inst.operands[i].reg = val;
5182218822Sdim      inst.operands[i].isreg = 1;
5183218822Sdim      inst.operands[i].isquad = (rtype == REG_TYPE_NQ);
5184218822Sdim      inst.operands[i].issingle = (rtype == REG_TYPE_VFS);
5185218822Sdim      inst.operands[i].isvec = 1;
5186218822Sdim      inst.operands[i].vectype = optype;
5187218822Sdim      inst.operands[i++].present = 1;
5188130561Sobrien
5189218822Sdim      if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) != FAIL)
5190218822Sdim        {
5191218822Sdim          /* Case 5: VMOV<c><q> <Dm>, <Rd>, <Rn>.
5192218822Sdim             Case 13: VMOV <Sd>, <Rm>  */
5193218822Sdim          inst.operands[i].reg = val;
5194218822Sdim          inst.operands[i].isreg = 1;
5195218822Sdim          inst.operands[i].present = 1;
5196130561Sobrien
5197218822Sdim          if (rtype == REG_TYPE_NQ)
5198218822Sdim            {
5199218822Sdim              first_error (_("can't use Neon quad register here"));
5200218822Sdim              return FAIL;
5201218822Sdim            }
5202218822Sdim          else if (rtype != REG_TYPE_VFS)
5203218822Sdim            {
5204218822Sdim              i++;
5205218822Sdim              if (skip_past_comma (&ptr) == FAIL)
5206218822Sdim                goto wanted_comma;
5207218822Sdim              if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) == FAIL)
5208218822Sdim                goto wanted_arm;
5209218822Sdim              inst.operands[i].reg = val;
5210218822Sdim              inst.operands[i].isreg = 1;
5211218822Sdim              inst.operands[i].present = 1;
5212218822Sdim            }
5213218822Sdim        }
5214218822Sdim      else if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_NSDQ, &rtype,
5215218822Sdim                                           &optype)) != FAIL)
5216218822Sdim        {
5217218822Sdim          /* Case 0: VMOV<c><q> <Qd>, <Qm>
5218218822Sdim             Case 1: VMOV<c><q> <Dd>, <Dm>
5219218822Sdim             Case 8: VMOV.F32 <Sd>, <Sm>
5220218822Sdim             Case 15: VMOV <Sd>, <Se>, <Rn>, <Rm>  */
5221130561Sobrien
5222218822Sdim          inst.operands[i].reg = val;
5223218822Sdim          inst.operands[i].isreg = 1;
5224218822Sdim          inst.operands[i].isquad = (rtype == REG_TYPE_NQ);
5225218822Sdim          inst.operands[i].issingle = (rtype == REG_TYPE_VFS);
5226218822Sdim          inst.operands[i].isvec = 1;
5227218822Sdim          inst.operands[i].vectype = optype;
5228218822Sdim          inst.operands[i].present = 1;
5229218822Sdim
5230218822Sdim          if (skip_past_comma (&ptr) == SUCCESS)
5231218822Sdim            {
5232218822Sdim              /* Case 15.  */
5233218822Sdim              i++;
5234130561Sobrien
5235218822Sdim              if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) == FAIL)
5236218822Sdim                goto wanted_arm;
5237218822Sdim
5238218822Sdim              inst.operands[i].reg = val;
5239218822Sdim              inst.operands[i].isreg = 1;
5240218822Sdim              inst.operands[i++].present = 1;
5241218822Sdim
5242218822Sdim              if (skip_past_comma (&ptr) == FAIL)
5243218822Sdim                goto wanted_comma;
5244218822Sdim
5245218822Sdim              if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) == FAIL)
5246218822Sdim                goto wanted_arm;
5247218822Sdim
5248218822Sdim              inst.operands[i].reg = val;
5249218822Sdim              inst.operands[i].isreg = 1;
5250318776Smmel              inst.operands[i].present = 1;
5251218822Sdim            }
5252218822Sdim        }
5253318776Smmel      else if (parse_qfloat_immediate (&ptr, &inst.operands[i].imm) == SUCCESS)
5254318776Smmel          /* Case 2: VMOV<c><q>.<dt> <Qd>, #<float-imm>
5255318776Smmel             Case 3: VMOV<c><q>.<dt> <Dd>, #<float-imm>
5256318776Smmel             Case 10: VMOV.F32 <Sd>, #<imm>
5257318776Smmel             Case 11: VMOV.F64 <Dd>, #<imm>  */
5258318776Smmel        inst.operands[i].immisfloat = 1;
5259248459Sandrew      else if (parse_big_immediate (&ptr, i) == SUCCESS)
5260248459Sandrew          /* Case 2: VMOV<c><q>.<dt> <Qd>, #<imm>
5261248459Sandrew             Case 3: VMOV<c><q>.<dt> <Dd>, #<imm>  */
5262248459Sandrew        ;
5263218822Sdim      else
5264218822Sdim        {
5265218822Sdim          first_error (_("expected <Rm> or <Dm> or <Qm> operand"));
5266218822Sdim          return FAIL;
5267218822Sdim        }
5268130561Sobrien    }
5269218822Sdim  else if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) != FAIL)
5270130561Sobrien    {
5271218822Sdim      /* Cases 6, 7.  */
5272218822Sdim      inst.operands[i].reg = val;
5273218822Sdim      inst.operands[i].isreg = 1;
5274218822Sdim      inst.operands[i++].present = 1;
5275218822Sdim
5276218822Sdim      if (skip_past_comma (&ptr) == FAIL)
5277218822Sdim        goto wanted_comma;
5278218822Sdim
5279218822Sdim      if ((val = parse_scalar (&ptr, 8, &optype)) != FAIL)
5280218822Sdim        {
5281218822Sdim          /* Case 6: VMOV<c><q>.<dt> <Rd>, <Dn[x]>  */
5282218822Sdim          inst.operands[i].reg = val;
5283218822Sdim          inst.operands[i].isscalar = 1;
5284218822Sdim          inst.operands[i].present = 1;
5285218822Sdim          inst.operands[i].vectype = optype;
5286218822Sdim        }
5287218822Sdim      else if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) != FAIL)
5288218822Sdim        {
5289218822Sdim          /* Case 7: VMOV<c><q> <Rd>, <Rn>, <Dm>  */
5290218822Sdim          inst.operands[i].reg = val;
5291218822Sdim          inst.operands[i].isreg = 1;
5292218822Sdim          inst.operands[i++].present = 1;
5293218822Sdim
5294218822Sdim          if (skip_past_comma (&ptr) == FAIL)
5295218822Sdim            goto wanted_comma;
5296218822Sdim
5297218822Sdim          if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_VFSD, &rtype, &optype))
5298218822Sdim              == FAIL)
5299218822Sdim            {
5300218822Sdim              first_error (_(reg_expected_msgs[REG_TYPE_VFSD]));
5301218822Sdim              return FAIL;
5302218822Sdim            }
5303218822Sdim
5304218822Sdim          inst.operands[i].reg = val;
5305218822Sdim          inst.operands[i].isreg = 1;
5306218822Sdim          inst.operands[i].isvec = 1;
5307218822Sdim          inst.operands[i].issingle = (rtype == REG_TYPE_VFS);
5308218822Sdim          inst.operands[i].vectype = optype;
5309218822Sdim          inst.operands[i].present = 1;
5310218822Sdim
5311218822Sdim          if (rtype == REG_TYPE_VFS)
5312218822Sdim            {
5313218822Sdim              /* Case 14.  */
5314218822Sdim              i++;
5315218822Sdim              if (skip_past_comma (&ptr) == FAIL)
5316218822Sdim                goto wanted_comma;
5317218822Sdim              if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_VFS, NULL,
5318218822Sdim                                              &optype)) == FAIL)
5319218822Sdim                {
5320218822Sdim                  first_error (_(reg_expected_msgs[REG_TYPE_VFS]));
5321218822Sdim                  return FAIL;
5322218822Sdim                }
5323218822Sdim              inst.operands[i].reg = val;
5324218822Sdim              inst.operands[i].isreg = 1;
5325218822Sdim              inst.operands[i].isvec = 1;
5326218822Sdim              inst.operands[i].issingle = 1;
5327218822Sdim              inst.operands[i].vectype = optype;
5328218822Sdim              inst.operands[i].present = 1;
5329218822Sdim            }
5330218822Sdim        }
5331218822Sdim      else if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_VFS, NULL, &optype))
5332218822Sdim               != FAIL)
5333218822Sdim        {
5334218822Sdim          /* Case 13.  */
5335218822Sdim          inst.operands[i].reg = val;
5336218822Sdim          inst.operands[i].isreg = 1;
5337218822Sdim          inst.operands[i].isvec = 1;
5338218822Sdim          inst.operands[i].issingle = 1;
5339218822Sdim          inst.operands[i].vectype = optype;
5340318776Smmel          inst.operands[i].present = 1;
5341218822Sdim        }
5342130561Sobrien    }
5343130561Sobrien  else
5344130561Sobrien    {
5345218822Sdim      first_error (_("parse error"));
5346218822Sdim      return FAIL;
5347130561Sobrien    }
5348130561Sobrien
5349218822Sdim  /* Successfully parsed the operands. Update args.  */
5350218822Sdim  *which_operand = i;
5351218822Sdim  *str = ptr;
5352218822Sdim  return SUCCESS;
5353130561Sobrien
5354218822Sdim  wanted_comma:
5355218822Sdim  first_error (_("expected comma"));
5356218822Sdim  return FAIL;
5357130561Sobrien
5358218822Sdim  wanted_arm:
5359218822Sdim  first_error (_(reg_expected_msgs[REG_TYPE_RN]));
5360218822Sdim  return FAIL;
5361130561Sobrien}
5362130561Sobrien
5363218822Sdim/* Matcher codes for parse_operands.  */
5364218822Sdimenum operand_parse_code
5365130561Sobrien{
5366218822Sdim  OP_stop,	/* end of line */
5367130561Sobrien
5368218822Sdim  OP_RR,	/* ARM register */
5369218822Sdim  OP_RRnpc,	/* ARM register, not r15 */
5370218822Sdim  OP_RRnpcb,	/* ARM register, not r15, in square brackets */
5371218822Sdim  OP_RRw,	/* ARM register, not r15, optional trailing ! */
5372218822Sdim  OP_RCP,	/* Coprocessor number */
5373218822Sdim  OP_RCN,	/* Coprocessor register */
5374218822Sdim  OP_RF,	/* FPA register */
5375218822Sdim  OP_RVS,	/* VFP single precision register */
5376218822Sdim  OP_RVD,	/* VFP double precision register (0..15) */
5377218822Sdim  OP_RND,       /* Neon double precision register (0..31) */
5378218822Sdim  OP_RNQ,	/* Neon quad precision register */
5379218822Sdim  OP_RVSD,	/* VFP single or double precision register */
5380218822Sdim  OP_RNDQ,      /* Neon double or quad precision register */
5381218822Sdim  OP_RNSDQ,	/* Neon single, double or quad precision register */
5382218822Sdim  OP_RNSC,      /* Neon scalar D[X] */
5383218822Sdim  OP_RVC,	/* VFP control register */
5384218822Sdim  OP_RMF,	/* Maverick F register */
5385218822Sdim  OP_RMD,	/* Maverick D register */
5386218822Sdim  OP_RMFX,	/* Maverick FX register */
5387218822Sdim  OP_RMDX,	/* Maverick DX register */
5388218822Sdim  OP_RMAX,	/* Maverick AX register */
5389218822Sdim  OP_RMDS,	/* Maverick DSPSC register */
5390218822Sdim  OP_RIWR,	/* iWMMXt wR register */
5391218822Sdim  OP_RIWC,	/* iWMMXt wC register */
5392218822Sdim  OP_RIWG,	/* iWMMXt wCG register */
5393218822Sdim  OP_RXA,	/* XScale accumulator register */
5394130561Sobrien
5395218822Sdim  OP_REGLST,	/* ARM register list */
5396218822Sdim  OP_VRSLST,	/* VFP single-precision register list */
5397218822Sdim  OP_VRDLST,	/* VFP double-precision register list */
5398218822Sdim  OP_VRSDLST,   /* VFP single or double-precision register list (& quad) */
5399218822Sdim  OP_NRDLST,    /* Neon double-precision register list (d0-d31, qN aliases) */
5400218822Sdim  OP_NSTRLST,   /* Neon element/structure list */
5401130561Sobrien
5402218822Sdim  OP_NILO,      /* Neon immediate/logic operands 2 or 2+3. (VBIC, VORR...)  */
5403218822Sdim  OP_RNDQ_I0,   /* Neon D or Q reg, or immediate zero.  */
5404218822Sdim  OP_RVSD_I0,	/* VFP S or D reg, or immediate zero.  */
5405218822Sdim  OP_RR_RNSC,   /* ARM reg or Neon scalar.  */
5406218822Sdim  OP_RNSDQ_RNSC, /* Vector S, D or Q reg, or Neon scalar.  */
5407218822Sdim  OP_RNDQ_RNSC, /* Neon D or Q reg, or Neon scalar.  */
5408218822Sdim  OP_RND_RNSC,  /* Neon D reg, or Neon scalar.  */
5409218822Sdim  OP_VMOV,      /* Neon VMOV operands.  */
5410218822Sdim  OP_RNDQ_IMVNb,/* Neon D or Q reg, or immediate good for VMVN.  */
5411218822Sdim  OP_RNDQ_I63b, /* Neon D or Q reg, or immediate for shift.  */
5412218822Sdim  OP_RIWR_I32z, /* iWMMXt wR register, or immediate 0 .. 32 for iWMMXt2.  */
5413130561Sobrien
5414218822Sdim  OP_I0,        /* immediate zero */
5415218822Sdim  OP_I7,	/* immediate value 0 .. 7 */
5416218822Sdim  OP_I15,	/*		   0 .. 15 */
5417218822Sdim  OP_I16,	/*		   1 .. 16 */
5418218822Sdim  OP_I16z,      /*                 0 .. 16 */
5419218822Sdim  OP_I31,	/*		   0 .. 31 */
5420218822Sdim  OP_I31w,	/*		   0 .. 31, optional trailing ! */
5421218822Sdim  OP_I32,	/*		   1 .. 32 */
5422218822Sdim  OP_I32z,	/*		   0 .. 32 */
5423218822Sdim  OP_I63,	/*		   0 .. 63 */
5424218822Sdim  OP_I63s,	/*		 -64 .. 63 */
5425218822Sdim  OP_I64,	/*		   1 .. 64 */
5426218822Sdim  OP_I64z,	/*		   0 .. 64 */
5427218822Sdim  OP_I255,	/*		   0 .. 255 */
5428130561Sobrien
5429218822Sdim  OP_I4b,	/* immediate, prefix optional, 1 .. 4 */
5430218822Sdim  OP_I7b,	/*			       0 .. 7 */
5431218822Sdim  OP_I15b,	/*			       0 .. 15 */
5432218822Sdim  OP_I31b,	/*			       0 .. 31 */
5433130561Sobrien
5434218822Sdim  OP_SH,	/* shifter operand */
5435218822Sdim  OP_SHG,	/* shifter operand with possible group relocation */
5436218822Sdim  OP_ADDR,	/* Memory address expression (any mode) */
5437218822Sdim  OP_ADDRGLDR,	/* Mem addr expr (any mode) with possible LDR group reloc */
5438218822Sdim  OP_ADDRGLDRS, /* Mem addr expr (any mode) with possible LDRS group reloc */
5439218822Sdim  OP_ADDRGLDC,  /* Mem addr expr (any mode) with possible LDC group reloc */
5440218822Sdim  OP_EXP,	/* arbitrary expression */
5441218822Sdim  OP_EXPi,	/* same, with optional immediate prefix */
5442218822Sdim  OP_EXPr,	/* same, with optional relocation suffix */
5443218822Sdim  OP_HALF,	/* 0 .. 65535 or low/high reloc.  */
5444130561Sobrien
5445218822Sdim  OP_CPSF,	/* CPS flags */
5446218822Sdim  OP_ENDI,	/* Endianness specifier */
5447218822Sdim  OP_PSR,	/* CPSR/SPSR mask for msr */
5448218822Sdim  OP_COND,	/* conditional code */
5449218822Sdim  OP_TB,	/* Table branch.  */
5450130561Sobrien
5451218822Sdim  OP_RVC_PSR,	/* CPSR/SPSR mask for msr, or VFP control register.  */
5452218822Sdim  OP_APSR_RR,   /* ARM register or "APSR_nzcv".  */
5453130561Sobrien
5454218822Sdim  OP_RRnpc_I0,	/* ARM register or literal 0 */
5455218822Sdim  OP_RR_EXr,	/* ARM register or expression with opt. reloc suff. */
5456218822Sdim  OP_RR_EXi,	/* ARM register or expression with imm prefix */
5457218822Sdim  OP_RF_IF,	/* FPA register or immediate */
5458218822Sdim  OP_RIWR_RIWC, /* iWMMXt R or C reg */
5459218822Sdim  OP_RIWC_RIWG, /* iWMMXt wC or wCG reg */
5460130561Sobrien
5461218822Sdim  /* Optional operands.	 */
5462218822Sdim  OP_oI7b,	 /* immediate, prefix optional, 0 .. 7 */
5463218822Sdim  OP_oI31b,	 /*				0 .. 31 */
5464218822Sdim  OP_oI32b,      /*                             1 .. 32 */
5465218822Sdim  OP_oIffffb,	 /*				0 .. 65535 */
5466218822Sdim  OP_oI255c,	 /*	  curly-brace enclosed, 0 .. 255 */
5467130561Sobrien
5468218822Sdim  OP_oRR,	 /* ARM register */
5469218822Sdim  OP_oRRnpc,	 /* ARM register, not the PC */
5470218822Sdim  OP_oRRw,	 /* ARM register, not r15, optional trailing ! */
5471218822Sdim  OP_oRND,       /* Optional Neon double precision register */
5472218822Sdim  OP_oRNQ,       /* Optional Neon quad precision register */
5473218822Sdim  OP_oRNDQ,      /* Optional Neon double or quad precision register */
5474218822Sdim  OP_oRNSDQ,	 /* Optional single, double or quad precision vector register */
5475218822Sdim  OP_oSHll,	 /* LSL immediate */
5476218822Sdim  OP_oSHar,	 /* ASR immediate */
5477218822Sdim  OP_oSHllar,	 /* LSL or ASR immediate */
5478218822Sdim  OP_oROR,	 /* ROR 0/8/16/24 */
5479218822Sdim  OP_oBARRIER,	 /* Option argument for a barrier instruction.  */
5480130561Sobrien
5481218822Sdim  OP_FIRST_OPTIONAL = OP_oI7b
5482218822Sdim};
5483130561Sobrien
5484218822Sdim/* Generic instruction operand parser.	This does no encoding and no
5485218822Sdim   semantic validation; it merely squirrels values away in the inst
5486218822Sdim   structure.  Returns SUCCESS or FAIL depending on whether the
5487218822Sdim   specified grammar matched.  */
5488218822Sdimstatic int
5489218822Sdimparse_operands (char *str, const unsigned char *pattern)
5490218822Sdim{
5491218822Sdim  unsigned const char *upat = pattern;
5492218822Sdim  char *backtrack_pos = 0;
5493218822Sdim  const char *backtrack_error = 0;
5494218822Sdim  int i, val, backtrack_index = 0;
5495218822Sdim  enum arm_reg_type rtype;
5496218822Sdim  parse_operand_result result;
5497130561Sobrien
5498218822Sdim#define po_char_or_fail(chr) do {		\
5499218822Sdim  if (skip_past_char (&str, chr) == FAIL)	\
5500218822Sdim    goto bad_args;				\
5501218822Sdim} while (0)
5502130561Sobrien
5503218822Sdim#define po_reg_or_fail(regtype) do {				\
5504218822Sdim  val = arm_typed_reg_parse (&str, regtype, &rtype,		\
5505218822Sdim  			     &inst.operands[i].vectype);	\
5506218822Sdim  if (val == FAIL)						\
5507218822Sdim    {								\
5508218822Sdim      first_error (_(reg_expected_msgs[regtype]));		\
5509218822Sdim      goto failure;						\
5510218822Sdim    }								\
5511218822Sdim  inst.operands[i].reg = val;					\
5512218822Sdim  inst.operands[i].isreg = 1;					\
5513218822Sdim  inst.operands[i].isquad = (rtype == REG_TYPE_NQ);		\
5514218822Sdim  inst.operands[i].issingle = (rtype == REG_TYPE_VFS);		\
5515218822Sdim  inst.operands[i].isvec = (rtype == REG_TYPE_VFS		\
5516218822Sdim                            || rtype == REG_TYPE_VFD		\
5517218822Sdim                            || rtype == REG_TYPE_NQ);		\
5518218822Sdim} while (0)
5519130561Sobrien
5520218822Sdim#define po_reg_or_goto(regtype, label) do {			\
5521218822Sdim  val = arm_typed_reg_parse (&str, regtype, &rtype,		\
5522218822Sdim                             &inst.operands[i].vectype);	\
5523218822Sdim  if (val == FAIL)						\
5524218822Sdim    goto label;							\
5525218822Sdim								\
5526218822Sdim  inst.operands[i].reg = val;					\
5527218822Sdim  inst.operands[i].isreg = 1;					\
5528218822Sdim  inst.operands[i].isquad = (rtype == REG_TYPE_NQ);		\
5529218822Sdim  inst.operands[i].issingle = (rtype == REG_TYPE_VFS);		\
5530218822Sdim  inst.operands[i].isvec = (rtype == REG_TYPE_VFS		\
5531218822Sdim                            || rtype == REG_TYPE_VFD		\
5532218822Sdim                            || rtype == REG_TYPE_NQ);		\
5533218822Sdim} while (0)
5534130561Sobrien
5535218822Sdim#define po_imm_or_fail(min, max, popt) do {			\
5536218822Sdim  if (parse_immediate (&str, &val, min, max, popt) == FAIL)	\
5537218822Sdim    goto failure;						\
5538218822Sdim  inst.operands[i].imm = val;					\
5539218822Sdim} while (0)
5540130561Sobrien
5541218822Sdim#define po_scalar_or_goto(elsz, label) do {			\
5542218822Sdim  val = parse_scalar (&str, elsz, &inst.operands[i].vectype);	\
5543218822Sdim  if (val == FAIL)						\
5544218822Sdim    goto label;							\
5545218822Sdim  inst.operands[i].reg = val;					\
5546218822Sdim  inst.operands[i].isscalar = 1;				\
5547218822Sdim} while (0)
5548130561Sobrien
5549218822Sdim#define po_misc_or_fail(expr) do {		\
5550218822Sdim  if (expr)					\
5551218822Sdim    goto failure;				\
5552218822Sdim} while (0)
5553130561Sobrien
5554218822Sdim#define po_misc_or_fail_no_backtrack(expr) do {	\
5555218822Sdim  result = expr;				\
5556218822Sdim  if (result == PARSE_OPERAND_FAIL_NO_BACKTRACK)\
5557218822Sdim    backtrack_pos = 0;				\
5558218822Sdim  if (result != PARSE_OPERAND_SUCCESS)		\
5559218822Sdim    goto failure;				\
5560218822Sdim} while (0)
5561130561Sobrien
5562130561Sobrien  skip_whitespace (str);
5563130561Sobrien
5564218822Sdim  for (i = 0; upat[i] != OP_stop; i++)
5565130561Sobrien    {
5566218822Sdim      if (upat[i] >= OP_FIRST_OPTIONAL)
5567130561Sobrien	{
5568218822Sdim	  /* Remember where we are in case we need to backtrack.  */
5569218822Sdim	  assert (!backtrack_pos);
5570218822Sdim	  backtrack_pos = str;
5571218822Sdim	  backtrack_error = inst.error;
5572218822Sdim	  backtrack_index = i;
5573130561Sobrien	}
5574130561Sobrien
5575218822Sdim      if (i > 0 && (i > 1 || inst.operands[0].present))
5576218822Sdim	po_char_or_fail (',');
5577130561Sobrien
5578218822Sdim      switch (upat[i])
5579218822Sdim	{
5580218822Sdim	  /* Registers */
5581218822Sdim	case OP_oRRnpc:
5582218822Sdim	case OP_RRnpc:
5583218822Sdim	case OP_oRR:
5584218822Sdim	case OP_RR:    po_reg_or_fail (REG_TYPE_RN);	  break;
5585218822Sdim	case OP_RCP:   po_reg_or_fail (REG_TYPE_CP);	  break;
5586218822Sdim	case OP_RCN:   po_reg_or_fail (REG_TYPE_CN);	  break;
5587218822Sdim	case OP_RF:    po_reg_or_fail (REG_TYPE_FN);	  break;
5588218822Sdim	case OP_RVS:   po_reg_or_fail (REG_TYPE_VFS);	  break;
5589218822Sdim	case OP_RVD:   po_reg_or_fail (REG_TYPE_VFD);	  break;
5590218822Sdim        case OP_oRND:
5591218822Sdim	case OP_RND:   po_reg_or_fail (REG_TYPE_VFD);	  break;
5592218822Sdim	case OP_RVC:
5593218822Sdim	  po_reg_or_goto (REG_TYPE_VFC, coproc_reg);
5594218822Sdim	  break;
5595218822Sdim	  /* Also accept generic coprocessor regs for unknown registers.  */
5596218822Sdim	  coproc_reg:
5597218822Sdim	  po_reg_or_fail (REG_TYPE_CN);
5598218822Sdim	  break;
5599218822Sdim	case OP_RMF:   po_reg_or_fail (REG_TYPE_MVF);	  break;
5600218822Sdim	case OP_RMD:   po_reg_or_fail (REG_TYPE_MVD);	  break;
5601218822Sdim	case OP_RMFX:  po_reg_or_fail (REG_TYPE_MVFX);	  break;
5602218822Sdim	case OP_RMDX:  po_reg_or_fail (REG_TYPE_MVDX);	  break;
5603218822Sdim	case OP_RMAX:  po_reg_or_fail (REG_TYPE_MVAX);	  break;
5604218822Sdim	case OP_RMDS:  po_reg_or_fail (REG_TYPE_DSPSC);	  break;
5605218822Sdim	case OP_RIWR:  po_reg_or_fail (REG_TYPE_MMXWR);	  break;
5606218822Sdim	case OP_RIWC:  po_reg_or_fail (REG_TYPE_MMXWC);	  break;
5607218822Sdim	case OP_RIWG:  po_reg_or_fail (REG_TYPE_MMXWCG);  break;
5608218822Sdim	case OP_RXA:   po_reg_or_fail (REG_TYPE_XSCALE);  break;
5609218822Sdim        case OP_oRNQ:
5610218822Sdim	case OP_RNQ:   po_reg_or_fail (REG_TYPE_NQ);      break;
5611218822Sdim        case OP_oRNDQ:
5612218822Sdim	case OP_RNDQ:  po_reg_or_fail (REG_TYPE_NDQ);     break;
5613218822Sdim        case OP_RVSD:  po_reg_or_fail (REG_TYPE_VFSD);    break;
5614218822Sdim        case OP_oRNSDQ:
5615218822Sdim        case OP_RNSDQ: po_reg_or_fail (REG_TYPE_NSDQ);    break;
5616130561Sobrien
5617218822Sdim        /* Neon scalar. Using an element size of 8 means that some invalid
5618218822Sdim           scalars are accepted here, so deal with those in later code.  */
5619218822Sdim        case OP_RNSC:  po_scalar_or_goto (8, failure);    break;
5620130561Sobrien
5621218822Sdim        /* WARNING: We can expand to two operands here. This has the potential
5622218822Sdim           to totally confuse the backtracking mechanism! It will be OK at
5623218822Sdim           least as long as we don't try to use optional args as well,
5624218822Sdim           though.  */
5625218822Sdim        case OP_NILO:
5626218822Sdim          {
5627218822Sdim            po_reg_or_goto (REG_TYPE_NDQ, try_imm);
5628218822Sdim	    inst.operands[i].present = 1;
5629218822Sdim            i++;
5630218822Sdim            skip_past_comma (&str);
5631218822Sdim            po_reg_or_goto (REG_TYPE_NDQ, one_reg_only);
5632218822Sdim            break;
5633218822Sdim            one_reg_only:
5634218822Sdim            /* Optional register operand was omitted. Unfortunately, it's in
5635218822Sdim               operands[i-1] and we need it to be in inst.operands[i]. Fix that
5636218822Sdim               here (this is a bit grotty).  */
5637218822Sdim            inst.operands[i] = inst.operands[i-1];
5638218822Sdim            inst.operands[i-1].present = 0;
5639218822Sdim            break;
5640218822Sdim            try_imm:
5641218822Sdim	    /* There's a possibility of getting a 64-bit immediate here, so
5642218822Sdim	       we need special handling.  */
5643218822Sdim	    if (parse_big_immediate (&str, i) == FAIL)
5644218822Sdim	      {
5645218822Sdim		inst.error = _("immediate value is out of range");
5646218822Sdim		goto failure;
5647218822Sdim	      }
5648218822Sdim          }
5649218822Sdim          break;
5650130561Sobrien
5651218822Sdim        case OP_RNDQ_I0:
5652218822Sdim          {
5653218822Sdim            po_reg_or_goto (REG_TYPE_NDQ, try_imm0);
5654218822Sdim            break;
5655218822Sdim            try_imm0:
5656218822Sdim            po_imm_or_fail (0, 0, TRUE);
5657218822Sdim          }
5658218822Sdim          break;
5659130561Sobrien
5660218822Sdim        case OP_RVSD_I0:
5661218822Sdim          po_reg_or_goto (REG_TYPE_VFSD, try_imm0);
5662218822Sdim          break;
5663130561Sobrien
5664218822Sdim        case OP_RR_RNSC:
5665218822Sdim          {
5666218822Sdim            po_scalar_or_goto (8, try_rr);
5667218822Sdim            break;
5668218822Sdim            try_rr:
5669218822Sdim            po_reg_or_fail (REG_TYPE_RN);
5670218822Sdim          }
5671218822Sdim          break;
5672130561Sobrien
5673218822Sdim        case OP_RNSDQ_RNSC:
5674218822Sdim          {
5675218822Sdim            po_scalar_or_goto (8, try_nsdq);
5676218822Sdim            break;
5677218822Sdim            try_nsdq:
5678218822Sdim            po_reg_or_fail (REG_TYPE_NSDQ);
5679218822Sdim          }
5680218822Sdim          break;
5681130561Sobrien
5682218822Sdim        case OP_RNDQ_RNSC:
5683218822Sdim          {
5684218822Sdim            po_scalar_or_goto (8, try_ndq);
5685218822Sdim            break;
5686218822Sdim            try_ndq:
5687218822Sdim            po_reg_or_fail (REG_TYPE_NDQ);
5688218822Sdim          }
5689218822Sdim          break;
5690130561Sobrien
5691218822Sdim        case OP_RND_RNSC:
5692218822Sdim          {
5693218822Sdim            po_scalar_or_goto (8, try_vfd);
5694218822Sdim            break;
5695218822Sdim            try_vfd:
5696218822Sdim            po_reg_or_fail (REG_TYPE_VFD);
5697218822Sdim          }
5698218822Sdim          break;
5699130561Sobrien
5700218822Sdim        case OP_VMOV:
5701218822Sdim          /* WARNING: parse_neon_mov can move the operand counter, i. If we're
5702218822Sdim             not careful then bad things might happen.  */
5703218822Sdim          po_misc_or_fail (parse_neon_mov (&str, &i) == FAIL);
5704218822Sdim          break;
5705130561Sobrien
5706218822Sdim        case OP_RNDQ_IMVNb:
5707218822Sdim          {
5708218822Sdim            po_reg_or_goto (REG_TYPE_NDQ, try_mvnimm);
5709218822Sdim            break;
5710218822Sdim            try_mvnimm:
5711218822Sdim            /* There's a possibility of getting a 64-bit immediate here, so
5712218822Sdim               we need special handling.  */
5713218822Sdim            if (parse_big_immediate (&str, i) == FAIL)
5714218822Sdim              {
5715218822Sdim                inst.error = _("immediate value is out of range");
5716218822Sdim                goto failure;
5717218822Sdim              }
5718218822Sdim          }
5719218822Sdim          break;
5720130561Sobrien
5721218822Sdim        case OP_RNDQ_I63b:
5722218822Sdim          {
5723218822Sdim            po_reg_or_goto (REG_TYPE_NDQ, try_shimm);
5724218822Sdim            break;
5725218822Sdim            try_shimm:
5726218822Sdim            po_imm_or_fail (0, 63, TRUE);
5727218822Sdim          }
5728218822Sdim          break;
5729130561Sobrien
5730218822Sdim	case OP_RRnpcb:
5731218822Sdim	  po_char_or_fail ('[');
5732218822Sdim	  po_reg_or_fail  (REG_TYPE_RN);
5733218822Sdim	  po_char_or_fail (']');
5734218822Sdim	  break;
5735130561Sobrien
5736218822Sdim	case OP_RRw:
5737218822Sdim	case OP_oRRw:
5738218822Sdim	  po_reg_or_fail (REG_TYPE_RN);
5739218822Sdim	  if (skip_past_char (&str, '!') == SUCCESS)
5740218822Sdim	    inst.operands[i].writeback = 1;
5741218822Sdim	  break;
5742130561Sobrien
5743218822Sdim	  /* Immediates */
5744218822Sdim	case OP_I7:	 po_imm_or_fail (  0,	   7, FALSE);	break;
5745218822Sdim	case OP_I15:	 po_imm_or_fail (  0,	  15, FALSE);	break;
5746218822Sdim	case OP_I16:	 po_imm_or_fail (  1,	  16, FALSE);	break;
5747218822Sdim        case OP_I16z:	 po_imm_or_fail (  0,     16, FALSE);   break;
5748218822Sdim	case OP_I31:	 po_imm_or_fail (  0,	  31, FALSE);	break;
5749218822Sdim	case OP_I32:	 po_imm_or_fail (  1,	  32, FALSE);	break;
5750218822Sdim        case OP_I32z:	 po_imm_or_fail (  0,     32, FALSE);   break;
5751218822Sdim	case OP_I63s:	 po_imm_or_fail (-64,	  63, FALSE);	break;
5752218822Sdim        case OP_I63:	 po_imm_or_fail (  0,     63, FALSE);   break;
5753218822Sdim        case OP_I64:	 po_imm_or_fail (  1,     64, FALSE);   break;
5754218822Sdim        case OP_I64z:	 po_imm_or_fail (  0,     64, FALSE);   break;
5755218822Sdim	case OP_I255:	 po_imm_or_fail (  0,	 255, FALSE);	break;
5756130561Sobrien
5757218822Sdim	case OP_I4b:	 po_imm_or_fail (  1,	   4, TRUE);	break;
5758218822Sdim	case OP_oI7b:
5759218822Sdim	case OP_I7b:	 po_imm_or_fail (  0,	   7, TRUE);	break;
5760218822Sdim	case OP_I15b:	 po_imm_or_fail (  0,	  15, TRUE);	break;
5761218822Sdim	case OP_oI31b:
5762218822Sdim	case OP_I31b:	 po_imm_or_fail (  0,	  31, TRUE);	break;
5763218822Sdim        case OP_oI32b:   po_imm_or_fail (  1,     32, TRUE);    break;
5764218822Sdim	case OP_oIffffb: po_imm_or_fail (  0, 0xffff, TRUE);	break;
5765130561Sobrien
5766218822Sdim	  /* Immediate variants */
5767218822Sdim	case OP_oI255c:
5768218822Sdim	  po_char_or_fail ('{');
5769218822Sdim	  po_imm_or_fail (0, 255, TRUE);
5770218822Sdim	  po_char_or_fail ('}');
5771218822Sdim	  break;
5772130561Sobrien
5773218822Sdim	case OP_I31w:
5774218822Sdim	  /* The expression parser chokes on a trailing !, so we have
5775218822Sdim	     to find it first and zap it.  */
5776218822Sdim	  {
5777218822Sdim	    char *s = str;
5778218822Sdim	    while (*s && *s != ',')
5779218822Sdim	      s++;
5780218822Sdim	    if (s[-1] == '!')
5781218822Sdim	      {
5782218822Sdim		s[-1] = '\0';
5783218822Sdim		inst.operands[i].writeback = 1;
5784218822Sdim	      }
5785218822Sdim	    po_imm_or_fail (0, 31, TRUE);
5786218822Sdim	    if (str == s - 1)
5787218822Sdim	      str = s;
5788218822Sdim	  }
5789218822Sdim	  break;
5790130561Sobrien
5791218822Sdim	  /* Expressions */
5792218822Sdim	case OP_EXPi:	EXPi:
5793218822Sdim	  po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str,
5794218822Sdim					      GE_OPT_PREFIX));
5795218822Sdim	  break;
5796130561Sobrien
5797218822Sdim	case OP_EXP:
5798218822Sdim	  po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str,
5799218822Sdim					      GE_NO_PREFIX));
5800218822Sdim	  break;
5801130561Sobrien
5802218822Sdim	case OP_EXPr:	EXPr:
5803218822Sdim	  po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str,
5804218822Sdim					      GE_NO_PREFIX));
5805218822Sdim	  if (inst.reloc.exp.X_op == O_symbol)
5806218822Sdim	    {
5807218822Sdim	      val = parse_reloc (&str);
5808218822Sdim	      if (val == -1)
5809218822Sdim		{
5810218822Sdim		  inst.error = _("unrecognized relocation suffix");
5811218822Sdim		  goto failure;
5812218822Sdim		}
5813218822Sdim	      else if (val != BFD_RELOC_UNUSED)
5814218822Sdim		{
5815218822Sdim		  inst.operands[i].imm = val;
5816218822Sdim		  inst.operands[i].hasreloc = 1;
5817218822Sdim		}
5818218822Sdim	    }
5819218822Sdim	  break;
5820218822Sdim
5821218822Sdim	  /* Operand for MOVW or MOVT.  */
5822218822Sdim	case OP_HALF:
5823218822Sdim	  po_misc_or_fail (parse_half (&str));
5824218822Sdim	  break;
5825218822Sdim
5826218822Sdim	  /* Register or expression */
5827218822Sdim	case OP_RR_EXr:	  po_reg_or_goto (REG_TYPE_RN, EXPr); break;
5828218822Sdim	case OP_RR_EXi:	  po_reg_or_goto (REG_TYPE_RN, EXPi); break;
5829218822Sdim
5830218822Sdim	  /* Register or immediate */
5831218822Sdim	case OP_RRnpc_I0: po_reg_or_goto (REG_TYPE_RN, I0);   break;
5832218822Sdim	I0:		  po_imm_or_fail (0, 0, FALSE);	      break;
5833218822Sdim
5834218822Sdim	case OP_RF_IF:    po_reg_or_goto (REG_TYPE_FN, IF);   break;
5835218822Sdim	IF:
5836218822Sdim	  if (!is_immediate_prefix (*str))
5837218822Sdim	    goto bad_args;
5838218822Sdim	  str++;
5839218822Sdim	  val = parse_fpa_immediate (&str);
5840218822Sdim	  if (val == FAIL)
5841218822Sdim	    goto failure;
5842218822Sdim	  /* FPA immediates are encoded as registers 8-15.
5843218822Sdim	     parse_fpa_immediate has already applied the offset.  */
5844218822Sdim	  inst.operands[i].reg = val;
5845218822Sdim	  inst.operands[i].isreg = 1;
5846218822Sdim	  break;
5847218822Sdim
5848218822Sdim	case OP_RIWR_I32z: po_reg_or_goto (REG_TYPE_MMXWR, I32z); break;
5849218822Sdim	I32z:		  po_imm_or_fail (0, 32, FALSE);	  break;
5850218822Sdim
5851218822Sdim	  /* Two kinds of register */
5852218822Sdim	case OP_RIWR_RIWC:
5853130561Sobrien	  {
5854218822Sdim	    struct reg_entry *rege = arm_reg_parse_multi (&str);
5855218822Sdim	    if (!rege
5856218822Sdim		|| (rege->type != REG_TYPE_MMXWR
5857218822Sdim		    && rege->type != REG_TYPE_MMXWC
5858218822Sdim		    && rege->type != REG_TYPE_MMXWCG))
5859218822Sdim	      {
5860218822Sdim		inst.error = _("iWMMXt data or control register expected");
5861218822Sdim		goto failure;
5862218822Sdim	      }
5863218822Sdim	    inst.operands[i].reg = rege->number;
5864218822Sdim	    inst.operands[i].isreg = (rege->type == REG_TYPE_MMXWR);
5865130561Sobrien	  }
5866218822Sdim	  break;
5867130561Sobrien
5868218822Sdim	case OP_RIWC_RIWG:
5869218822Sdim	  {
5870218822Sdim	    struct reg_entry *rege = arm_reg_parse_multi (&str);
5871218822Sdim	    if (!rege
5872218822Sdim		|| (rege->type != REG_TYPE_MMXWC
5873218822Sdim		    && rege->type != REG_TYPE_MMXWCG))
5874218822Sdim	      {
5875218822Sdim		inst.error = _("iWMMXt control register expected");
5876218822Sdim		goto failure;
5877218822Sdim	      }
5878218822Sdim	    inst.operands[i].reg = rege->number;
5879218822Sdim	    inst.operands[i].isreg = 1;
5880218822Sdim	  }
5881218822Sdim	  break;
588277298Sobrien
5883218822Sdim	  /* Misc */
5884218822Sdim	case OP_CPSF:	 val = parse_cps_flags (&str);		break;
5885218822Sdim	case OP_ENDI:	 val = parse_endian_specifier (&str);	break;
5886218822Sdim	case OP_oROR:	 val = parse_ror (&str);		break;
5887218822Sdim	case OP_PSR:	 val = parse_psr (&str);		break;
5888218822Sdim	case OP_COND:	 val = parse_cond (&str);		break;
5889218822Sdim	case OP_oBARRIER:val = parse_barrier (&str);		break;
589077298Sobrien
5891218822Sdim        case OP_RVC_PSR:
5892218822Sdim          po_reg_or_goto (REG_TYPE_VFC, try_psr);
5893218822Sdim          inst.operands[i].isvec = 1;  /* Mark VFP control reg as vector.  */
5894218822Sdim          break;
5895218822Sdim          try_psr:
5896218822Sdim          val = parse_psr (&str);
5897218822Sdim          break;
589877298Sobrien
5899218822Sdim        case OP_APSR_RR:
5900218822Sdim          po_reg_or_goto (REG_TYPE_RN, try_apsr);
5901218822Sdim          break;
5902218822Sdim          try_apsr:
5903218822Sdim          /* Parse "APSR_nvzc" operand (for FMSTAT-equivalent MRS
5904218822Sdim             instruction).  */
5905218822Sdim          if (strncasecmp (str, "APSR_", 5) == 0)
5906218822Sdim            {
5907218822Sdim              unsigned found = 0;
5908218822Sdim              str += 5;
5909218822Sdim              while (found < 15)
5910218822Sdim                switch (*str++)
5911218822Sdim                  {
5912218822Sdim                  case 'c': found = (found & 1) ? 16 : found | 1; break;
5913218822Sdim                  case 'n': found = (found & 2) ? 16 : found | 2; break;
5914218822Sdim                  case 'z': found = (found & 4) ? 16 : found | 4; break;
5915218822Sdim                  case 'v': found = (found & 8) ? 16 : found | 8; break;
5916218822Sdim                  default: found = 16;
5917218822Sdim                  }
5918218822Sdim              if (found != 15)
5919218822Sdim                goto failure;
5920218822Sdim              inst.operands[i].isvec = 1;
5921218822Sdim            }
5922218822Sdim          else
5923218822Sdim            goto failure;
5924218822Sdim          break;
592577298Sobrien
5926218822Sdim	case OP_TB:
5927218822Sdim	  po_misc_or_fail (parse_tb (&str));
5928218822Sdim	  break;
592977298Sobrien
5930218822Sdim	  /* Register lists */
5931218822Sdim	case OP_REGLST:
5932218822Sdim	  val = parse_reg_list (&str);
5933218822Sdim	  if (*str == '^')
5934218822Sdim	    {
5935218822Sdim	      inst.operands[1].writeback = 1;
5936218822Sdim	      str++;
5937218822Sdim	    }
5938218822Sdim	  break;
593977298Sobrien
5940218822Sdim	case OP_VRSLST:
5941218822Sdim	  val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_S);
5942218822Sdim	  break;
594377298Sobrien
5944218822Sdim	case OP_VRDLST:
5945218822Sdim	  val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_D);
5946218822Sdim	  break;
594777298Sobrien
5948218822Sdim        case OP_VRSDLST:
5949218822Sdim          /* Allow Q registers too.  */
5950218822Sdim          val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
5951218822Sdim                                    REGLIST_NEON_D);
5952218822Sdim          if (val == FAIL)
5953218822Sdim            {
5954218822Sdim              inst.error = NULL;
5955218822Sdim              val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
5956218822Sdim                                        REGLIST_VFP_S);
5957218822Sdim              inst.operands[i].issingle = 1;
5958218822Sdim            }
5959218822Sdim          break;
596077298Sobrien
5961218822Sdim        case OP_NRDLST:
5962218822Sdim          val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
5963218822Sdim                                    REGLIST_NEON_D);
5964218822Sdim          break;
596577298Sobrien
5966218822Sdim	case OP_NSTRLST:
5967218822Sdim          val = parse_neon_el_struct_list (&str, &inst.operands[i].reg,
5968218822Sdim                                           &inst.operands[i].vectype);
5969218822Sdim          break;
597077298Sobrien
5971218822Sdim	  /* Addressing modes */
5972218822Sdim	case OP_ADDR:
5973218822Sdim	  po_misc_or_fail (parse_address (&str, i));
5974218822Sdim	  break;
597577298Sobrien
5976218822Sdim	case OP_ADDRGLDR:
5977218822Sdim	  po_misc_or_fail_no_backtrack (
5978218822Sdim            parse_address_group_reloc (&str, i, GROUP_LDR));
5979218822Sdim	  break;
598077298Sobrien
5981218822Sdim	case OP_ADDRGLDRS:
5982218822Sdim	  po_misc_or_fail_no_backtrack (
5983218822Sdim            parse_address_group_reloc (&str, i, GROUP_LDRS));
5984218822Sdim	  break;
598577298Sobrien
5986218822Sdim	case OP_ADDRGLDC:
5987218822Sdim	  po_misc_or_fail_no_backtrack (
5988218822Sdim            parse_address_group_reloc (&str, i, GROUP_LDC));
5989218822Sdim	  break;
599077298Sobrien
5991218822Sdim	case OP_SH:
5992218822Sdim	  po_misc_or_fail (parse_shifter_operand (&str, i));
5993218822Sdim	  break;
599477298Sobrien
5995218822Sdim	case OP_SHG:
5996218822Sdim	  po_misc_or_fail_no_backtrack (
5997218822Sdim            parse_shifter_operand_group_reloc (&str, i));
5998218822Sdim	  break;
599977298Sobrien
6000218822Sdim	case OP_oSHll:
6001218822Sdim	  po_misc_or_fail (parse_shift (&str, i, SHIFT_LSL_IMMEDIATE));
6002218822Sdim	  break;
600377298Sobrien
6004218822Sdim	case OP_oSHar:
6005218822Sdim	  po_misc_or_fail (parse_shift (&str, i, SHIFT_ASR_IMMEDIATE));
6006218822Sdim	  break;
600777298Sobrien
6008218822Sdim	case OP_oSHllar:
6009218822Sdim	  po_misc_or_fail (parse_shift (&str, i, SHIFT_LSL_OR_ASR_IMMEDIATE));
6010218822Sdim	  break;
601177298Sobrien
6012218822Sdim	default:
6013218822Sdim	  as_fatal ("unhandled operand code %d", upat[i]);
6014218822Sdim	}
601577298Sobrien
6016218822Sdim      /* Various value-based sanity checks and shared operations.  We
6017218822Sdim	 do not signal immediate failures for the register constraints;
6018218822Sdim	 this allows a syntax error to take precedence.	 */
6019218822Sdim      switch (upat[i])
6020104834Sobrien	{
6021218822Sdim	case OP_oRRnpc:
6022218822Sdim	case OP_RRnpc:
6023218822Sdim	case OP_RRnpcb:
6024218822Sdim	case OP_RRw:
6025218822Sdim	case OP_oRRw:
6026218822Sdim	case OP_RRnpc_I0:
6027218822Sdim	  if (inst.operands[i].isreg && inst.operands[i].reg == REG_PC)
6028218822Sdim	    inst.error = BAD_PC;
6029218822Sdim	  break;
603077298Sobrien
6031218822Sdim	case OP_CPSF:
6032218822Sdim	case OP_ENDI:
6033218822Sdim	case OP_oROR:
6034218822Sdim	case OP_PSR:
6035218822Sdim        case OP_RVC_PSR:
6036218822Sdim	case OP_COND:
6037218822Sdim	case OP_oBARRIER:
6038218822Sdim	case OP_REGLST:
6039218822Sdim	case OP_VRSLST:
6040218822Sdim	case OP_VRDLST:
6041218822Sdim        case OP_VRSDLST:
6042218822Sdim        case OP_NRDLST:
6043218822Sdim        case OP_NSTRLST:
6044218822Sdim	  if (val == FAIL)
6045218822Sdim	    goto failure;
6046218822Sdim	  inst.operands[i].imm = val;
6047218822Sdim	  break;
604877298Sobrien
6049218822Sdim	default:
6050218822Sdim	  break;
6051218822Sdim	}
605277298Sobrien
6053218822Sdim      /* If we get here, this operand was successfully parsed.	*/
6054218822Sdim      inst.operands[i].present = 1;
6055218822Sdim      continue;
605677298Sobrien
6057218822Sdim    bad_args:
6058218822Sdim      inst.error = BAD_ARGS;
605977298Sobrien
6060218822Sdim    failure:
6061218822Sdim      if (!backtrack_pos)
6062218822Sdim	{
6063218822Sdim	  /* The parse routine should already have set inst.error, but set a
6064218822Sdim	     defaut here just in case.  */
6065218822Sdim	  if (!inst.error)
6066218822Sdim	    inst.error = _("syntax error");
6067218822Sdim	  return FAIL;
6068218822Sdim	}
606977298Sobrien
6070218822Sdim      /* Do not backtrack over a trailing optional argument that
6071218822Sdim	 absorbed some text.  We will only fail again, with the
6072218822Sdim	 'garbage following instruction' error message, which is
6073218822Sdim	 probably less helpful than the current one.  */
6074218822Sdim      if (backtrack_index == i && backtrack_pos != str
6075218822Sdim	  && upat[i+1] == OP_stop)
6076218822Sdim	{
6077218822Sdim	  if (!inst.error)
6078218822Sdim	    inst.error = _("syntax error");
6079218822Sdim	  return FAIL;
6080218822Sdim	}
608177298Sobrien
6082218822Sdim      /* Try again, skipping the optional argument at backtrack_pos.  */
6083218822Sdim      str = backtrack_pos;
6084218822Sdim      inst.error = backtrack_error;
6085218822Sdim      inst.operands[backtrack_index].present = 0;
6086218822Sdim      i = backtrack_index;
6087218822Sdim      backtrack_pos = 0;
608877298Sobrien    }
608977298Sobrien
6090218822Sdim  /* Check that we have parsed all the arguments.  */
6091218822Sdim  if (*str != '\0' && !inst.error)
6092218822Sdim    inst.error = _("garbage following instruction");
609377298Sobrien
6094218822Sdim  return inst.error ? FAIL : SUCCESS;
609577298Sobrien}
609677298Sobrien
6097218822Sdim#undef po_char_or_fail
6098218822Sdim#undef po_reg_or_fail
6099218822Sdim#undef po_reg_or_goto
6100218822Sdim#undef po_imm_or_fail
6101218822Sdim#undef po_scalar_or_fail
6102218822Sdim
6103218822Sdim/* Shorthand macro for instruction encoding functions issuing errors.  */
6104218822Sdim#define constraint(expr, err) do {		\
6105218822Sdim  if (expr)					\
6106218822Sdim    {						\
6107218822Sdim      inst.error = err;				\
6108218822Sdim      return;					\
6109218822Sdim    }						\
6110218822Sdim} while (0)
611177298Sobrien
6112218822Sdim/* Functions for operand encoding.  ARM, then Thumb.  */
6113218822Sdim
6114274856Sdim#define rotate_left(v, n) (v << (n % 32) | v >> ((32 - n) % 32))
6115218822Sdim
6116218822Sdim/* If VAL can be encoded in the immediate field of an ARM instruction,
6117218822Sdim   return the encoded form.  Otherwise, return FAIL.  */
6118218822Sdim
6119218822Sdimstatic unsigned int
6120218822Sdimencode_arm_immediate (unsigned int val)
612177298Sobrien{
6122218822Sdim  unsigned int a, i;
612377298Sobrien
6124218822Sdim  for (i = 0; i < 32; i += 2)
6125218822Sdim    if ((a = rotate_left (val, i)) <= 0xff)
6126218822Sdim      return a | (i << 7); /* 12-bit pack: [shift-cnt,const].  */
612777298Sobrien
6128218822Sdim  return FAIL;
6129218822Sdim}
613077298Sobrien
6131218822Sdim/* If VAL can be encoded in the immediate field of a Thumb32 instruction,
6132218822Sdim   return the encoded form.  Otherwise, return FAIL.  */
6133218822Sdimstatic unsigned int
6134218822Sdimencode_thumb32_immediate (unsigned int val)
6135218822Sdim{
6136218822Sdim  unsigned int a, i;
613777298Sobrien
6138218822Sdim  if (val <= 0xff)
6139218822Sdim    return val;
6140218822Sdim
6141218822Sdim  for (i = 1; i <= 24; i++)
614277298Sobrien    {
6143218822Sdim      a = val >> i;
6144218822Sdim      if ((val & ~(0xff << i)) == 0)
6145218822Sdim	return ((val >> i) & 0x7f) | ((32 - i) << 7);
614677298Sobrien    }
614777298Sobrien
6148218822Sdim  a = val & 0xff;
6149218822Sdim  if (val == ((a << 16) | a))
6150218822Sdim    return 0x100 | a;
6151218822Sdim  if (val == ((a << 24) | (a << 16) | (a << 8) | a))
6152218822Sdim    return 0x300 | a;
615377298Sobrien
6154218822Sdim  a = val & 0xff00;
6155218822Sdim  if (val == ((a << 16) | a))
6156218822Sdim    return 0x200 | (a >> 8);
6157218822Sdim
6158218822Sdim  return FAIL;
6159218822Sdim}
6160218822Sdim/* Encode a VFP SP or DP register number into inst.instruction.  */
6161218822Sdim
6162218822Sdimstatic void
6163218822Sdimencode_arm_vfp_reg (int reg, enum vfp_reg_pos pos)
6164218822Sdim{
6165218822Sdim  if ((pos == VFP_REG_Dd || pos == VFP_REG_Dn || pos == VFP_REG_Dm)
6166218822Sdim      && reg > 15)
616777298Sobrien    {
6168218822Sdim      if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v3))
6169218822Sdim        {
6170218822Sdim          if (thumb_mode)
6171218822Sdim            ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
6172218822Sdim                                    fpu_vfp_ext_v3);
6173218822Sdim          else
6174218822Sdim            ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used,
6175218822Sdim                                    fpu_vfp_ext_v3);
6176218822Sdim        }
6177218822Sdim      else
6178218822Sdim        {
6179218822Sdim          first_error (_("D register out of range for selected VFP version"));
6180218822Sdim          return;
6181218822Sdim        }
618277298Sobrien    }
618377298Sobrien
6184218822Sdim  switch (pos)
6185218822Sdim    {
6186218822Sdim    case VFP_REG_Sd:
6187218822Sdim      inst.instruction |= ((reg >> 1) << 12) | ((reg & 1) << 22);
6188218822Sdim      break;
618977298Sobrien
6190218822Sdim    case VFP_REG_Sn:
6191218822Sdim      inst.instruction |= ((reg >> 1) << 16) | ((reg & 1) << 7);
6192218822Sdim      break;
619377298Sobrien
6194218822Sdim    case VFP_REG_Sm:
6195218822Sdim      inst.instruction |= ((reg >> 1) << 0) | ((reg & 1) << 5);
6196218822Sdim      break;
6197218822Sdim
6198218822Sdim    case VFP_REG_Dd:
6199218822Sdim      inst.instruction |= ((reg & 15) << 12) | ((reg >> 4) << 22);
6200218822Sdim      break;
6201218822Sdim
6202218822Sdim    case VFP_REG_Dn:
6203218822Sdim      inst.instruction |= ((reg & 15) << 16) | ((reg >> 4) << 7);
6204218822Sdim      break;
6205218822Sdim
6206218822Sdim    case VFP_REG_Dm:
6207218822Sdim      inst.instruction |= (reg & 15) | ((reg >> 4) << 5);
6208218822Sdim      break;
6209218822Sdim
6210218822Sdim    default:
6211218822Sdim      abort ();
6212218822Sdim    }
621377298Sobrien}
621477298Sobrien
6215218822Sdim/* Encode a <shift> in an ARM-format instruction.  The immediate,
6216218822Sdim   if any, is handled by md_apply_fix.	 */
6217130561Sobrienstatic void
6218218822Sdimencode_arm_shift (int i)
6219130561Sobrien{
6220218822Sdim  if (inst.operands[i].shift_kind == SHIFT_RRX)
6221218822Sdim    inst.instruction |= SHIFT_ROR << 5;
6222218822Sdim  else
6223218822Sdim    {
6224218822Sdim      inst.instruction |= inst.operands[i].shift_kind << 5;
6225218822Sdim      if (inst.operands[i].immisreg)
6226218822Sdim	{
6227218822Sdim	  inst.instruction |= SHIFT_BY_REG;
6228218822Sdim	  inst.instruction |= inst.operands[i].imm << 8;
6229218822Sdim	}
6230218822Sdim      else
6231218822Sdim	inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
6232218822Sdim    }
6233130561Sobrien}
6234130561Sobrien
6235130561Sobrienstatic void
6236218822Sdimencode_arm_shifter_operand (int i)
6237130561Sobrien{
6238218822Sdim  if (inst.operands[i].isreg)
6239218822Sdim    {
6240218822Sdim      inst.instruction |= inst.operands[i].reg;
6241218822Sdim      encode_arm_shift (i);
6242218822Sdim    }
6243218822Sdim  else
6244218822Sdim    inst.instruction |= INST_IMMEDIATE;
6245130561Sobrien}
6246130561Sobrien
6247218822Sdim/* Subroutine of encode_arm_addr_mode_2 and encode_arm_addr_mode_3.  */
6248130561Sobrienstatic void
6249218822Sdimencode_arm_addr_mode_common (int i, bfd_boolean is_t)
6250130561Sobrien{
6251218822Sdim  assert (inst.operands[i].isreg);
6252218822Sdim  inst.instruction |= inst.operands[i].reg << 16;
6253130561Sobrien
6254218822Sdim  if (inst.operands[i].preind)
6255218822Sdim    {
6256218822Sdim      if (is_t)
6257218822Sdim	{
6258218822Sdim	  inst.error = _("instruction does not accept preindexed addressing");
6259218822Sdim	  return;
6260218822Sdim	}
6261218822Sdim      inst.instruction |= PRE_INDEX;
6262218822Sdim      if (inst.operands[i].writeback)
6263218822Sdim	inst.instruction |= WRITE_BACK;
6264130561Sobrien
6265218822Sdim    }
6266218822Sdim  else if (inst.operands[i].postind)
6267218822Sdim    {
6268218822Sdim      assert (inst.operands[i].writeback);
6269218822Sdim      if (is_t)
6270218822Sdim	inst.instruction |= WRITE_BACK;
6271218822Sdim    }
6272218822Sdim  else /* unindexed - only for coprocessor */
6273218822Sdim    {
6274218822Sdim      inst.error = _("instruction does not accept unindexed addressing");
6275218822Sdim      return;
6276218822Sdim    }
6277130561Sobrien
6278218822Sdim  if (((inst.instruction & WRITE_BACK) || !(inst.instruction & PRE_INDEX))
6279218822Sdim      && (((inst.instruction & 0x000f0000) >> 16)
6280218822Sdim	  == ((inst.instruction & 0x0000f000) >> 12)))
6281218822Sdim    as_warn ((inst.instruction & LOAD_BIT)
6282218822Sdim	     ? _("destination register same as write-back base")
6283218822Sdim	     : _("source register same as write-back base"));
6284218822Sdim}
6285218822Sdim
6286218822Sdim/* inst.operands[i] was set up by parse_address.  Encode it into an
6287218822Sdim   ARM-format mode 2 load or store instruction.	 If is_t is true,
6288218822Sdim   reject forms that cannot be used with a T instruction (i.e. not
6289218822Sdim   post-indexed).  */
6290218822Sdimstatic void
6291218822Sdimencode_arm_addr_mode_2 (int i, bfd_boolean is_t)
6292130561Sobrien{
6293218822Sdim  encode_arm_addr_mode_common (i, is_t);
6294130561Sobrien
6295218822Sdim  if (inst.operands[i].immisreg)
6296130561Sobrien    {
6297218822Sdim      inst.instruction |= INST_IMMEDIATE;  /* yes, this is backwards */
6298218822Sdim      inst.instruction |= inst.operands[i].imm;
6299218822Sdim      if (!inst.operands[i].negative)
6300218822Sdim	inst.instruction |= INDEX_UP;
6301218822Sdim      if (inst.operands[i].shifted)
6302218822Sdim	{
6303218822Sdim	  if (inst.operands[i].shift_kind == SHIFT_RRX)
6304218822Sdim	    inst.instruction |= SHIFT_ROR << 5;
6305218822Sdim	  else
6306218822Sdim	    {
6307218822Sdim	      inst.instruction |= inst.operands[i].shift_kind << 5;
6308218822Sdim	      inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
6309218822Sdim	    }
6310218822Sdim	}
6311130561Sobrien    }
6312218822Sdim  else /* immediate offset in inst.reloc */
6313130561Sobrien    {
6314218822Sdim      if (inst.reloc.type == BFD_RELOC_UNUSED)
6315218822Sdim	inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
6316130561Sobrien    }
6317218822Sdim}
6318218822Sdim
6319218822Sdim/* inst.operands[i] was set up by parse_address.  Encode it into an
6320218822Sdim   ARM-format mode 3 load or store instruction.	 Reject forms that
6321218822Sdim   cannot be used with such instructions.  If is_t is true, reject
6322218822Sdim   forms that cannot be used with a T instruction (i.e. not
6323218822Sdim   post-indexed).  */
6324218822Sdimstatic void
6325218822Sdimencode_arm_addr_mode_3 (int i, bfd_boolean is_t)
6326218822Sdim{
6327218822Sdim  if (inst.operands[i].immisreg && inst.operands[i].shifted)
6328130561Sobrien    {
6329218822Sdim      inst.error = _("instruction does not accept scaled register index");
6330218822Sdim      return;
6331218822Sdim    }
6332130561Sobrien
6333218822Sdim  encode_arm_addr_mode_common (i, is_t);
6334218822Sdim
6335218822Sdim  if (inst.operands[i].immisreg)
6336218822Sdim    {
6337218822Sdim      inst.instruction |= inst.operands[i].imm;
6338218822Sdim      if (!inst.operands[i].negative)
6339218822Sdim	inst.instruction |= INDEX_UP;
6340130561Sobrien    }
6341218822Sdim  else /* immediate offset in inst.reloc */
6342218822Sdim    {
6343218822Sdim      inst.instruction |= HWOFFSET_IMM;
6344218822Sdim      if (inst.reloc.type == BFD_RELOC_UNUSED)
6345218822Sdim	inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
6346218822Sdim    }
6347130561Sobrien}
6348130561Sobrien
6349218822Sdim/* inst.operands[i] was set up by parse_address.  Encode it into an
6350218822Sdim   ARM-format instruction.  Reject all forms which cannot be encoded
6351218822Sdim   into a coprocessor load/store instruction.  If wb_ok is false,
6352218822Sdim   reject use of writeback; if unind_ok is false, reject use of
6353218822Sdim   unindexed addressing.  If reloc_override is not 0, use it instead
6354218822Sdim   of BFD_ARM_CP_OFF_IMM, unless the initial relocation is a group one
6355218822Sdim   (in which case it is preserved).  */
6356218822Sdim
6357218822Sdimstatic int
6358218822Sdimencode_arm_cp_address (int i, int wb_ok, int unind_ok, int reloc_override)
6359130561Sobrien{
6360218822Sdim  inst.instruction |= inst.operands[i].reg << 16;
6361130561Sobrien
6362218822Sdim  assert (!(inst.operands[i].preind && inst.operands[i].postind));
6363130561Sobrien
6364218822Sdim  if (!inst.operands[i].preind && !inst.operands[i].postind) /* unindexed */
6365218822Sdim    {
6366218822Sdim      assert (!inst.operands[i].writeback);
6367218822Sdim      if (!unind_ok)
6368218822Sdim	{
6369218822Sdim	  inst.error = _("instruction does not support unindexed addressing");
6370218822Sdim	  return FAIL;
6371218822Sdim	}
6372218822Sdim      inst.instruction |= inst.operands[i].imm;
6373218822Sdim      inst.instruction |= INDEX_UP;
6374218822Sdim      return SUCCESS;
6375218822Sdim    }
6376130561Sobrien
6377218822Sdim  if (inst.operands[i].preind)
6378218822Sdim    inst.instruction |= PRE_INDEX;
6379218822Sdim
6380218822Sdim  if (inst.operands[i].writeback)
6381130561Sobrien    {
6382218822Sdim      if (inst.operands[i].reg == REG_PC)
6383218822Sdim	{
6384218822Sdim	  inst.error = _("pc may not be used with write-back");
6385218822Sdim	  return FAIL;
6386218822Sdim	}
6387218822Sdim      if (!wb_ok)
6388218822Sdim	{
6389218822Sdim	  inst.error = _("instruction does not support writeback");
6390218822Sdim	  return FAIL;
6391218822Sdim	}
6392218822Sdim      inst.instruction |= WRITE_BACK;
6393130561Sobrien    }
6394130561Sobrien
6395218822Sdim  if (reloc_override)
6396218822Sdim    inst.reloc.type = reloc_override;
6397218822Sdim  else if ((inst.reloc.type < BFD_RELOC_ARM_ALU_PC_G0_NC
6398218822Sdim            || inst.reloc.type > BFD_RELOC_ARM_LDC_SB_G2)
6399218822Sdim           && inst.reloc.type != BFD_RELOC_ARM_LDR_PC_G0)
6400130561Sobrien    {
6401218822Sdim      if (thumb_mode)
6402218822Sdim        inst.reloc.type = BFD_RELOC_ARM_T32_CP_OFF_IMM;
6403218822Sdim      else
6404218822Sdim        inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
6405130561Sobrien    }
6406218822Sdim
6407218822Sdim  return SUCCESS;
6408130561Sobrien}
6409130561Sobrien
6410218822Sdim/* inst.reloc.exp describes an "=expr" load pseudo-operation.
6411218822Sdim   Determine whether it can be performed with a move instruction; if
6412218822Sdim   it can, convert inst.instruction to that move instruction and
6413218822Sdim   return 1; if it can't, convert inst.instruction to a literal-pool
6414218822Sdim   load and return 0.  If this is not a valid thing to do in the
6415218822Sdim   current context, set inst.error and return 1.
6416218822Sdim
6417218822Sdim   inst.operands[i] describes the destination register.	 */
6418218822Sdim
6419218822Sdimstatic int
6420218822Sdimmove_or_literal_pool (int i, bfd_boolean thumb_p, bfd_boolean mode_3)
6421130561Sobrien{
6422218822Sdim  unsigned long tbit;
6423130561Sobrien
6424218822Sdim  if (thumb_p)
6425218822Sdim    tbit = (inst.instruction > 0xffff) ? THUMB2_LOAD_BIT : THUMB_LOAD_BIT;
6426218822Sdim  else
6427218822Sdim    tbit = LOAD_BIT;
6428130561Sobrien
6429218822Sdim  if ((inst.instruction & tbit) == 0)
6430218822Sdim    {
6431218822Sdim      inst.error = _("invalid pseudo operation");
6432218822Sdim      return 1;
6433218822Sdim    }
6434218822Sdim  if (inst.reloc.exp.X_op != O_constant && inst.reloc.exp.X_op != O_symbol)
6435218822Sdim    {
6436218822Sdim      inst.error = _("constant expression expected");
6437218822Sdim      return 1;
6438218822Sdim    }
6439218822Sdim  if (inst.reloc.exp.X_op == O_constant)
6440218822Sdim    {
6441218822Sdim      if (thumb_p)
6442218822Sdim	{
6443218822Sdim	  if (!unified_syntax && (inst.reloc.exp.X_add_number & ~0xFF) == 0)
6444218822Sdim	    {
6445218822Sdim	      /* This can be done with a mov(1) instruction.  */
6446218822Sdim	      inst.instruction	= T_OPCODE_MOV_I8 | (inst.operands[i].reg << 8);
6447218822Sdim	      inst.instruction |= inst.reloc.exp.X_add_number;
6448218822Sdim	      return 1;
6449218822Sdim	    }
6450218822Sdim	}
6451218822Sdim      else
6452218822Sdim	{
6453218822Sdim	  int value = encode_arm_immediate (inst.reloc.exp.X_add_number);
6454218822Sdim	  if (value != FAIL)
6455218822Sdim	    {
6456218822Sdim	      /* This can be done with a mov instruction.  */
6457218822Sdim	      inst.instruction &= LITERAL_MASK;
6458218822Sdim	      inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT);
6459218822Sdim	      inst.instruction |= value & 0xfff;
6460218822Sdim	      return 1;
6461218822Sdim	    }
6462218822Sdim
6463218822Sdim	  value = encode_arm_immediate (~inst.reloc.exp.X_add_number);
6464218822Sdim	  if (value != FAIL)
6465218822Sdim	    {
6466218822Sdim	      /* This can be done with a mvn instruction.  */
6467218822Sdim	      inst.instruction &= LITERAL_MASK;
6468218822Sdim	      inst.instruction |= INST_IMMEDIATE | (OPCODE_MVN << DATA_OP_SHIFT);
6469218822Sdim	      inst.instruction |= value & 0xfff;
6470218822Sdim	      return 1;
6471218822Sdim	    }
6472218822Sdim	}
6473218822Sdim    }
6474218822Sdim
6475218822Sdim  if (add_to_lit_pool () == FAIL)
6476218822Sdim    {
6477218822Sdim      inst.error = _("literal pool insertion failed");
6478218822Sdim      return 1;
6479218822Sdim    }
6480218822Sdim  inst.operands[1].reg = REG_PC;
6481218822Sdim  inst.operands[1].isreg = 1;
6482218822Sdim  inst.operands[1].preind = 1;
6483218822Sdim  inst.reloc.pc_rel = 1;
6484218822Sdim  inst.reloc.type = (thumb_p
6485218822Sdim		     ? BFD_RELOC_ARM_THUMB_OFFSET
6486218822Sdim		     : (mode_3
6487218822Sdim			? BFD_RELOC_ARM_HWLITERAL
6488218822Sdim			: BFD_RELOC_ARM_LITERAL));
6489218822Sdim  return 0;
6490130561Sobrien}
6491130561Sobrien
6492218822Sdim/* Functions for instruction encoding, sorted by subarchitecture.
6493218822Sdim   First some generics; their names are taken from the conventional
6494218822Sdim   bit positions for register arguments in ARM format instructions.  */
6495218822Sdim
6496130561Sobrienstatic void
6497218822Sdimdo_noargs (void)
6498130561Sobrien{
6499130561Sobrien}
6500130561Sobrien
6501130561Sobrienstatic void
6502218822Sdimdo_rd (void)
6503130561Sobrien{
6504218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6505130561Sobrien}
6506130561Sobrien
6507130561Sobrienstatic void
6508218822Sdimdo_rd_rm (void)
6509130561Sobrien{
6510218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6511218822Sdim  inst.instruction |= inst.operands[1].reg;
6512130561Sobrien}
6513130561Sobrien
6514130561Sobrienstatic void
6515218822Sdimdo_rd_rn (void)
6516130561Sobrien{
6517218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6518218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
6519130561Sobrien}
6520130561Sobrien
6521130561Sobrienstatic void
6522218822Sdimdo_rn_rd (void)
6523130561Sobrien{
6524218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
6525218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
6526130561Sobrien}
6527130561Sobrien
6528130561Sobrienstatic void
6529218822Sdimdo_rd_rm_rn (void)
6530130561Sobrien{
6531218822Sdim  unsigned Rn = inst.operands[2].reg;
6532218822Sdim  /* Enforce restrictions on SWP instruction.  */
6533218822Sdim  if ((inst.instruction & 0x0fbfffff) == 0x01000090)
6534218822Sdim    constraint (Rn == inst.operands[0].reg || Rn == inst.operands[1].reg,
6535218822Sdim		_("Rn must not overlap other operands"));
6536218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6537218822Sdim  inst.instruction |= inst.operands[1].reg;
6538218822Sdim  inst.instruction |= Rn << 16;
6539130561Sobrien}
6540130561Sobrien
6541130561Sobrienstatic void
6542218822Sdimdo_rd_rn_rm (void)
6543130561Sobrien{
6544218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6545218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
6546218822Sdim  inst.instruction |= inst.operands[2].reg;
6547130561Sobrien}
6548130561Sobrien
6549130561Sobrienstatic void
6550218822Sdimdo_rm_rd_rn (void)
6551130561Sobrien{
6552218822Sdim  inst.instruction |= inst.operands[0].reg;
6553218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
6554218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
6555130561Sobrien}
6556130561Sobrien
6557130561Sobrienstatic void
6558218822Sdimdo_imm0 (void)
6559130561Sobrien{
6560218822Sdim  inst.instruction |= inst.operands[0].imm;
6561130561Sobrien}
6562130561Sobrien
6563130561Sobrienstatic void
6564218822Sdimdo_rd_cpaddr (void)
6565130561Sobrien{
6566218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6567218822Sdim  encode_arm_cp_address (1, TRUE, TRUE, 0);
6568130561Sobrien}
6569130561Sobrien
6570218822Sdim/* ARM instructions, in alphabetical order by function name (except
6571218822Sdim   that wrapper functions appear immediately after the function they
6572218822Sdim   wrap).  */
6573218822Sdim
6574218822Sdim/* This is a pseudo-op of the form "adr rd, label" to be converted
6575218822Sdim   into a relative address of the form "add rd, pc, #label-.-8".  */
6576218822Sdim
6577130561Sobrienstatic void
6578218822Sdimdo_adr (void)
6579130561Sobrien{
6580218822Sdim  inst.instruction |= (inst.operands[0].reg << 12);  /* Rd */
6581218822Sdim
6582218822Sdim  /* Frag hacking will turn this into a sub instruction if the offset turns
6583218822Sdim     out to be negative.  */
6584218822Sdim  inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
6585218822Sdim  inst.reloc.pc_rel = 1;
6586218822Sdim  inst.reloc.exp.X_add_number -= 8;
6587130561Sobrien}
6588130561Sobrien
6589218822Sdim/* This is a pseudo-op of the form "adrl rd, label" to be converted
6590218822Sdim   into a relative address of the form:
6591218822Sdim   add rd, pc, #low(label-.-8)"
6592218822Sdim   add rd, rd, #high(label-.-8)"  */
6593218822Sdim
6594130561Sobrienstatic void
6595218822Sdimdo_adrl (void)
6596130561Sobrien{
6597218822Sdim  inst.instruction |= (inst.operands[0].reg << 12);  /* Rd */
6598130561Sobrien
6599218822Sdim  /* Frag hacking will turn this into a sub instruction if the offset turns
6600218822Sdim     out to be negative.  */
6601218822Sdim  inst.reloc.type	       = BFD_RELOC_ARM_ADRL_IMMEDIATE;
6602218822Sdim  inst.reloc.pc_rel	       = 1;
6603218822Sdim  inst.size		       = INSN_SIZE * 2;
6604218822Sdim  inst.reloc.exp.X_add_number -= 8;
6605130561Sobrien}
6606130561Sobrien
6607130561Sobrienstatic void
6608218822Sdimdo_arit (void)
6609130561Sobrien{
6610218822Sdim  if (!inst.operands[1].present)
6611218822Sdim    inst.operands[1].reg = inst.operands[0].reg;
6612218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6613218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
6614218822Sdim  encode_arm_shifter_operand (2);
6615130561Sobrien}
6616130561Sobrien
6617130561Sobrienstatic void
6618218822Sdimdo_barrier (void)
6619130561Sobrien{
6620218822Sdim  if (inst.operands[0].present)
6621130561Sobrien    {
6622218822Sdim      constraint ((inst.instruction & 0xf0) != 0x40
6623272472Sandrew		  && (inst.instruction & 0xf0) != 0x50
6624218822Sdim		  && inst.operands[0].imm != 0xf,
6625218822Sdim		  "bad barrier type");
6626218822Sdim      inst.instruction |= inst.operands[0].imm;
6627130561Sobrien    }
6628130561Sobrien  else
6629218822Sdim    inst.instruction |= 0xf;
6630130561Sobrien}
6631130561Sobrien
6632130561Sobrienstatic void
6633218822Sdimdo_bfc (void)
6634130561Sobrien{
6635218822Sdim  unsigned int msb = inst.operands[1].imm + inst.operands[2].imm;
6636218822Sdim  constraint (msb > 32, _("bit-field extends past end of register"));
6637218822Sdim  /* The instruction encoding stores the LSB and MSB,
6638218822Sdim     not the LSB and width.  */
6639218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6640218822Sdim  inst.instruction |= inst.operands[1].imm << 7;
6641218822Sdim  inst.instruction |= (msb - 1) << 16;
6642130561Sobrien}
6643130561Sobrien
6644130561Sobrienstatic void
6645218822Sdimdo_bfi (void)
6646130561Sobrien{
6647218822Sdim  unsigned int msb;
6648218822Sdim
6649218822Sdim  /* #0 in second position is alternative syntax for bfc, which is
6650218822Sdim     the same instruction but with REG_PC in the Rm field.  */
6651218822Sdim  if (!inst.operands[1].isreg)
6652218822Sdim    inst.operands[1].reg = REG_PC;
6653218822Sdim
6654218822Sdim  msb = inst.operands[2].imm + inst.operands[3].imm;
6655218822Sdim  constraint (msb > 32, _("bit-field extends past end of register"));
6656218822Sdim  /* The instruction encoding stores the LSB and MSB,
6657218822Sdim     not the LSB and width.  */
6658218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6659218822Sdim  inst.instruction |= inst.operands[1].reg;
6660218822Sdim  inst.instruction |= inst.operands[2].imm << 7;
6661218822Sdim  inst.instruction |= (msb - 1) << 16;
6662130561Sobrien}
6663130561Sobrien
6664130561Sobrienstatic void
6665218822Sdimdo_bfx (void)
6666130561Sobrien{
6667218822Sdim  constraint (inst.operands[2].imm + inst.operands[3].imm > 32,
6668218822Sdim	      _("bit-field extends past end of register"));
6669218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6670218822Sdim  inst.instruction |= inst.operands[1].reg;
6671218822Sdim  inst.instruction |= inst.operands[2].imm << 7;
6672218822Sdim  inst.instruction |= (inst.operands[3].imm - 1) << 16;
6673130561Sobrien}
6674130561Sobrien
6675218822Sdim/* ARM V5 breakpoint instruction (argument parse)
6676218822Sdim     BKPT <16 bit unsigned immediate>
6677218822Sdim     Instruction is not conditional.
6678218822Sdim	The bit pattern given in insns[] has the COND_ALWAYS condition,
6679218822Sdim	and it is an error if the caller tried to override that.  */
6680218822Sdim
6681130561Sobrienstatic void
6682218822Sdimdo_bkpt (void)
6683130561Sobrien{
6684218822Sdim  /* Top 12 of 16 bits to bits 19:8.  */
6685218822Sdim  inst.instruction |= (inst.operands[0].imm & 0xfff0) << 4;
6686130561Sobrien
6687218822Sdim  /* Bottom 4 of 16 bits to bits 3:0.  */
6688218822Sdim  inst.instruction |= inst.operands[0].imm & 0xf;
6689218822Sdim}
6690130561Sobrien
6691218822Sdimstatic void
6692218822Sdimencode_branch (int default_reloc)
6693218822Sdim{
6694218822Sdim  if (inst.operands[0].hasreloc)
6695218822Sdim    {
6696218822Sdim      constraint (inst.operands[0].imm != BFD_RELOC_ARM_PLT32,
6697218822Sdim		  _("the only suffix valid here is '(plt)'"));
6698218822Sdim      inst.reloc.type	= BFD_RELOC_ARM_PLT32;
6699218822Sdim    }
6700218822Sdim  else
6701218822Sdim    {
6702218822Sdim      inst.reloc.type = default_reloc;
6703218822Sdim    }
6704218822Sdim  inst.reloc.pc_rel = 1;
6705130561Sobrien}
6706130561Sobrien
6707130561Sobrienstatic void
6708218822Sdimdo_branch (void)
6709130561Sobrien{
6710218822Sdim#ifdef OBJ_ELF
6711218822Sdim  if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4)
6712218822Sdim    encode_branch (BFD_RELOC_ARM_PCREL_JUMP);
6713218822Sdim  else
6714218822Sdim#endif
6715218822Sdim    encode_branch (BFD_RELOC_ARM_PCREL_BRANCH);
6716218822Sdim}
6717130561Sobrien
6718218822Sdimstatic void
6719218822Sdimdo_bl (void)
6720218822Sdim{
6721218822Sdim#ifdef OBJ_ELF
6722218822Sdim  if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4)
6723218822Sdim    {
6724218822Sdim      if (inst.cond == COND_ALWAYS)
6725218822Sdim	encode_branch (BFD_RELOC_ARM_PCREL_CALL);
6726218822Sdim      else
6727218822Sdim	encode_branch (BFD_RELOC_ARM_PCREL_JUMP);
6728218822Sdim    }
6729218822Sdim  else
6730218822Sdim#endif
6731218822Sdim    encode_branch (BFD_RELOC_ARM_PCREL_BRANCH);
6732130561Sobrien}
6733130561Sobrien
6734218822Sdim/* ARM V5 branch-link-exchange instruction (argument parse)
6735218822Sdim     BLX <target_addr>		ie BLX(1)
6736218822Sdim     BLX{<condition>} <Rm>	ie BLX(2)
6737218822Sdim   Unfortunately, there are two different opcodes for this mnemonic.
6738218822Sdim   So, the insns[].value is not used, and the code here zaps values
6739218822Sdim	into inst.instruction.
6740218822Sdim   Also, the <target_addr> can be 25 bits, hence has its own reloc.  */
674177298Sobrien
674277298Sobrienstatic void
6743218822Sdimdo_blx (void)
674477298Sobrien{
6745218822Sdim  if (inst.operands[0].isreg)
6746218822Sdim    {
6747218822Sdim      /* Arg is a register; the opcode provided by insns[] is correct.
6748218822Sdim	 It is not illegal to do "blx pc", just useless.  */
6749218822Sdim      if (inst.operands[0].reg == REG_PC)
6750218822Sdim	as_tsktsk (_("use of r15 in blx in ARM mode is not really useful"));
675177298Sobrien
6752218822Sdim      inst.instruction |= inst.operands[0].reg;
6753218822Sdim    }
6754218822Sdim  else
6755218822Sdim    {
6756218822Sdim      /* Arg is an address; this instruction cannot be executed
6757218822Sdim	 conditionally, and the opcode must be adjusted.  */
6758218822Sdim      constraint (inst.cond != COND_ALWAYS, BAD_COND);
6759218822Sdim      inst.instruction = 0xfa000000;
6760218822Sdim#ifdef OBJ_ELF
6761218822Sdim      if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4)
6762218822Sdim	encode_branch (BFD_RELOC_ARM_PCREL_CALL);
6763218822Sdim      else
6764218822Sdim#endif
6765218822Sdim	encode_branch (BFD_RELOC_ARM_PCREL_BLX);
6766218822Sdim    }
6767218822Sdim}
676877298Sobrien
6769218822Sdimstatic void
6770218822Sdimdo_bx (void)
6771218822Sdim{
6772218822Sdim  if (inst.operands[0].reg == REG_PC)
6773218822Sdim    as_tsktsk (_("use of r15 in bx in ARM mode is not really useful"));
677477298Sobrien
6775218822Sdim  inst.instruction |= inst.operands[0].reg;
677677298Sobrien}
677777298Sobrien
677877298Sobrien
6779218822Sdim/* ARM v5TEJ.  Jump to Jazelle code.  */
678077298Sobrien
678177298Sobrienstatic void
6782218822Sdimdo_bxj (void)
678377298Sobrien{
6784218822Sdim  if (inst.operands[0].reg == REG_PC)
6785218822Sdim    as_tsktsk (_("use of r15 in bxj is not really useful"));
678677298Sobrien
6787218822Sdim  inst.instruction |= inst.operands[0].reg;
6788218822Sdim}
678977298Sobrien
6790218822Sdim/* Co-processor data operation:
6791218822Sdim      CDP{cond} <coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>{, <opcode_2>}
6792218822Sdim      CDP2	<coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>{, <opcode_2>}	 */
6793218822Sdimstatic void
6794218822Sdimdo_cdp (void)
6795218822Sdim{
6796218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
6797218822Sdim  inst.instruction |= inst.operands[1].imm << 20;
6798218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
6799218822Sdim  inst.instruction |= inst.operands[3].reg << 16;
6800218822Sdim  inst.instruction |= inst.operands[4].reg;
6801218822Sdim  inst.instruction |= inst.operands[5].imm << 5;
6802218822Sdim}
680377298Sobrien
6804218822Sdimstatic void
6805218822Sdimdo_cmp (void)
6806218822Sdim{
6807218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
6808218822Sdim  encode_arm_shifter_operand (1);
680977298Sobrien}
681077298Sobrien
6811218822Sdim/* Transfer between coprocessor and ARM registers.
6812218822Sdim   MRC{cond} <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>{, <opcode_2>}
6813218822Sdim   MRC2
6814218822Sdim   MCR{cond}
6815218822Sdim   MCR2
681677298Sobrien
6817218822Sdim   No special properties.  */
681877298Sobrien
681977298Sobrienstatic void
6820218822Sdimdo_co_reg (void)
682177298Sobrien{
6822218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
6823218822Sdim  inst.instruction |= inst.operands[1].imm << 21;
6824275584Sandrew  /* If this is a vector we are using the APSR_nzcv syntax, encode as r15 */
6825275584Sandrew  if (inst.operands[2].isvec != 0)
6826275584Sandrew    inst.instruction |= 15 << 12;
6827275584Sandrew  else
6828275584Sandrew    inst.instruction |= inst.operands[2].reg << 12;
6829218822Sdim  inst.instruction |= inst.operands[3].reg << 16;
6830218822Sdim  inst.instruction |= inst.operands[4].reg;
6831218822Sdim  inst.instruction |= inst.operands[5].imm << 5;
6832218822Sdim}
683377298Sobrien
6834218822Sdim/* Transfer between coprocessor register and pair of ARM registers.
6835218822Sdim   MCRR{cond} <coproc>, <opcode>, <Rd>, <Rn>, <CRm>.
6836218822Sdim   MCRR2
6837218822Sdim   MRRC{cond}
6838218822Sdim   MRRC2
683977298Sobrien
6840218822Sdim   Two XScale instructions are special cases of these:
684177298Sobrien
6842218822Sdim     MAR{cond} acc0, <RdLo>, <RdHi> == MCRR{cond} p0, #0, <RdLo>, <RdHi>, c0
6843218822Sdim     MRA{cond} acc0, <RdLo>, <RdHi> == MRRC{cond} p0, #0, <RdLo>, <RdHi>, c0
684477298Sobrien
6845218822Sdim   Result unpredicatable if Rd or Rn is R15.  */
684677298Sobrien
6847218822Sdimstatic void
6848218822Sdimdo_co_reg2c (void)
6849218822Sdim{
6850218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
6851218822Sdim  inst.instruction |= inst.operands[1].imm << 4;
6852218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
6853218822Sdim  inst.instruction |= inst.operands[3].reg << 16;
6854218822Sdim  inst.instruction |= inst.operands[4].reg;
6855218822Sdim}
685677298Sobrien
6857218822Sdimstatic void
6858218822Sdimdo_cpsi (void)
6859218822Sdim{
6860218822Sdim  inst.instruction |= inst.operands[0].imm << 6;
6861218822Sdim  if (inst.operands[1].present)
6862218822Sdim    {
6863218822Sdim      inst.instruction |= CPSI_MMOD;
6864218822Sdim      inst.instruction |= inst.operands[1].imm;
6865218822Sdim    }
686677298Sobrien}
686777298Sobrien
6868218822Sdimstatic void
6869218822Sdimdo_dbg (void)
6870218822Sdim{
6871218822Sdim  inst.instruction |= inst.operands[0].imm;
6872218822Sdim}
687377298Sobrien
6874218822Sdimstatic void
6875218822Sdimdo_it (void)
6876218822Sdim{
6877218822Sdim  /* There is no IT instruction in ARM mode.  We
6878218822Sdim     process it but do not generate code for it.  */
6879218822Sdim  inst.size = 0;
6880218822Sdim}
688177298Sobrien
688277298Sobrienstatic void
6883218822Sdimdo_ldmstm (void)
688477298Sobrien{
6885218822Sdim  int base_reg = inst.operands[0].reg;
6886218822Sdim  int range = inst.operands[1].imm;
688777298Sobrien
6888218822Sdim  inst.instruction |= base_reg << 16;
6889218822Sdim  inst.instruction |= range;
689077298Sobrien
6891218822Sdim  if (inst.operands[1].writeback)
6892218822Sdim    inst.instruction |= LDM_TYPE_2_OR_3;
689377298Sobrien
6894218822Sdim  if (inst.operands[0].writeback)
689577298Sobrien    {
6896218822Sdim      inst.instruction |= WRITE_BACK;
6897218822Sdim      /* Check for unpredictable uses of writeback.  */
6898218822Sdim      if (inst.instruction & LOAD_BIT)
689977298Sobrien	{
6900218822Sdim	  /* Not allowed in LDM type 2.	 */
6901218822Sdim	  if ((inst.instruction & LDM_TYPE_2_OR_3)
6902218822Sdim	      && ((range & (1 << REG_PC)) == 0))
6903218822Sdim	    as_warn (_("writeback of base register is UNPREDICTABLE"));
6904218822Sdim	  /* Only allowed if base reg not in list for other types.  */
6905218822Sdim	  else if (range & (1 << base_reg))
6906218822Sdim	    as_warn (_("writeback of base register when in register list is UNPREDICTABLE"));
690777298Sobrien	}
6908218822Sdim      else /* STM.  */
690977298Sobrien	{
6910218822Sdim	  /* Not allowed for type 2.  */
6911218822Sdim	  if (inst.instruction & LDM_TYPE_2_OR_3)
6912218822Sdim	    as_warn (_("writeback of base register is UNPREDICTABLE"));
6913218822Sdim	  /* Only allowed if base reg not in list, or first in list.  */
6914218822Sdim	  else if ((range & (1 << base_reg))
6915218822Sdim		   && (range & ((1 << base_reg) - 1)))
6916218822Sdim	    as_warn (_("if writeback register is in list, it must be the lowest reg in the list"));
691777298Sobrien	}
691877298Sobrien    }
6919218822Sdim}
692077298Sobrien
6921218822Sdim/* ARMv5TE load-consecutive (argument parse)
6922218822Sdim   Mode is like LDRH.
692377298Sobrien
6924218822Sdim     LDRccD R, mode
6925218822Sdim     STRccD R, mode.  */
692677298Sobrien
6927218822Sdimstatic void
6928218822Sdimdo_ldrd (void)
6929218822Sdim{
6930218822Sdim  constraint (inst.operands[0].reg % 2 != 0,
6931218822Sdim	      _("first destination register must be even"));
6932218822Sdim  constraint (inst.operands[1].present
6933218822Sdim	      && inst.operands[1].reg != inst.operands[0].reg + 1,
6934218822Sdim	      _("can only load two consecutive registers"));
6935218822Sdim  constraint (inst.operands[0].reg == REG_LR, _("r14 not allowed here"));
6936218822Sdim  constraint (!inst.operands[2].isreg, _("'[' expected"));
693777298Sobrien
6938218822Sdim  if (!inst.operands[1].present)
6939218822Sdim    inst.operands[1].reg = inst.operands[0].reg + 1;
6940218822Sdim
6941218822Sdim  if (inst.instruction & LOAD_BIT)
6942218822Sdim    {
6943218822Sdim      /* encode_arm_addr_mode_3 will diagnose overlap between the base
6944218822Sdim	 register and the first register written; we have to diagnose
6945218822Sdim	 overlap between the base and the second register written here.	 */
694677298Sobrien
6947218822Sdim      if (inst.operands[2].reg == inst.operands[1].reg
6948218822Sdim	  && (inst.operands[2].writeback || inst.operands[2].postind))
6949218822Sdim	as_warn (_("base register written back, and overlaps "
6950218822Sdim		   "second destination register"));
695177298Sobrien
6952218822Sdim      /* For an index-register load, the index register must not overlap the
6953218822Sdim	 destination (even if not write-back).	*/
6954218822Sdim      else if (inst.operands[2].immisreg
6955218822Sdim	       && ((unsigned) inst.operands[2].imm == inst.operands[0].reg
6956218822Sdim		   || (unsigned) inst.operands[2].imm == inst.operands[1].reg))
6957218822Sdim	as_warn (_("index register overlaps destination register"));
695877298Sobrien    }
695977298Sobrien
6960218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6961218822Sdim  encode_arm_addr_mode_3 (2, /*is_t=*/FALSE);
696277298Sobrien}
696377298Sobrien
6964218822Sdimstatic void
6965218822Sdimdo_ldrex (void)
6966218822Sdim{
6967218822Sdim  constraint (!inst.operands[1].isreg || !inst.operands[1].preind
6968218822Sdim	      || inst.operands[1].postind || inst.operands[1].writeback
6969218822Sdim	      || inst.operands[1].immisreg || inst.operands[1].shifted
6970218822Sdim	      || inst.operands[1].negative
6971218822Sdim	      /* This can arise if the programmer has written
6972218822Sdim		   strex rN, rM, foo
6973218822Sdim		 or if they have mistakenly used a register name as the last
6974218822Sdim		 operand,  eg:
6975218822Sdim		   strex rN, rM, rX
6976218822Sdim		 It is very difficult to distinguish between these two cases
6977218822Sdim		 because "rX" might actually be a label. ie the register
6978218822Sdim		 name has been occluded by a symbol of the same name. So we
6979218822Sdim		 just generate a general 'bad addressing mode' type error
6980218822Sdim		 message and leave it up to the programmer to discover the
6981218822Sdim		 true cause and fix their mistake.  */
6982218822Sdim	      || (inst.operands[1].reg == REG_PC),
6983218822Sdim	      BAD_ADDR_MODE);
698477298Sobrien
6985218822Sdim  constraint (inst.reloc.exp.X_op != O_constant
6986218822Sdim	      || inst.reloc.exp.X_add_number != 0,
6987218822Sdim	      _("offset must be zero in ARM encoding"));
698877298Sobrien
6989218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6990218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
6991218822Sdim  inst.reloc.type = BFD_RELOC_UNUSED;
6992218822Sdim}
6993218822Sdim
699477298Sobrienstatic void
6995218822Sdimdo_ldrexd (void)
699677298Sobrien{
6997218822Sdim  constraint (inst.operands[0].reg % 2 != 0,
6998218822Sdim	      _("even register required"));
6999218822Sdim  constraint (inst.operands[1].present
7000218822Sdim	      && inst.operands[1].reg != inst.operands[0].reg + 1,
7001218822Sdim	      _("can only load two consecutive registers"));
7002218822Sdim  /* If op 1 were present and equal to PC, this function wouldn't
7003218822Sdim     have been called in the first place.  */
7004218822Sdim  constraint (inst.operands[0].reg == REG_LR, _("r14 not allowed here"));
700577298Sobrien
7006218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7007218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
7008218822Sdim}
700977298Sobrien
7010218822Sdimstatic void
7011218822Sdimdo_ldst (void)
7012218822Sdim{
7013218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7014218822Sdim  if (!inst.operands[1].isreg)
7015218822Sdim    if (move_or_literal_pool (0, /*thumb_p=*/FALSE, /*mode_3=*/FALSE))
701677298Sobrien      return;
7017218822Sdim  encode_arm_addr_mode_2 (1, /*is_t=*/FALSE);
7018218822Sdim}
701977298Sobrien
7020218822Sdimstatic void
7021218822Sdimdo_ldstt (void)
7022218822Sdim{
7023218822Sdim  /* ldrt/strt always use post-indexed addressing.  Turn [Rn] into [Rn]! and
7024218822Sdim     reject [Rn,...].  */
7025218822Sdim  if (inst.operands[1].preind)
702677298Sobrien    {
7027218822Sdim      constraint (inst.reloc.exp.X_op != O_constant ||
7028218822Sdim		  inst.reloc.exp.X_add_number != 0,
7029218822Sdim		  _("this instruction requires a post-indexed address"));
703077298Sobrien
7031218822Sdim      inst.operands[1].preind = 0;
7032218822Sdim      inst.operands[1].postind = 1;
7033218822Sdim      inst.operands[1].writeback = 1;
703477298Sobrien    }
7035218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7036218822Sdim  encode_arm_addr_mode_2 (1, /*is_t=*/TRUE);
7037218822Sdim}
703877298Sobrien
7039218822Sdim/* Halfword and signed-byte load/store operations.  */
7040218822Sdim
7041218822Sdimstatic void
7042218822Sdimdo_ldstv4 (void)
7043218822Sdim{
7044218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7045218822Sdim  if (!inst.operands[1].isreg)
7046218822Sdim    if (move_or_literal_pool (0, /*thumb_p=*/FALSE, /*mode_3=*/TRUE))
704777298Sobrien      return;
7048218822Sdim  encode_arm_addr_mode_3 (1, /*is_t=*/FALSE);
7049218822Sdim}
705077298Sobrien
7051218822Sdimstatic void
7052218822Sdimdo_ldsttv4 (void)
7053218822Sdim{
7054218822Sdim  /* ldrt/strt always use post-indexed addressing.  Turn [Rn] into [Rn]! and
7055218822Sdim     reject [Rn,...].  */
7056218822Sdim  if (inst.operands[1].preind)
705789857Sobrien    {
7058218822Sdim      constraint (inst.reloc.exp.X_op != O_constant ||
7059218822Sdim		  inst.reloc.exp.X_add_number != 0,
7060218822Sdim		  _("this instruction requires a post-indexed address"));
706189857Sobrien
7062218822Sdim      inst.operands[1].preind = 0;
7063218822Sdim      inst.operands[1].postind = 1;
7064218822Sdim      inst.operands[1].writeback = 1;
706589857Sobrien    }
7066218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7067218822Sdim  encode_arm_addr_mode_3 (1, /*is_t=*/TRUE);
7068218822Sdim}
706989857Sobrien
7070218822Sdim/* Co-processor register load/store.
7071218822Sdim   Format: <LDC|STC>{cond}[L] CP#,CRd,<address>	 */
7072218822Sdimstatic void
7073218822Sdimdo_lstc (void)
7074218822Sdim{
7075218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
7076218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
7077218822Sdim  encode_arm_cp_address (2, TRUE, TRUE, 0);
707877298Sobrien}
707977298Sobrien
7080218822Sdimstatic void
7081218822Sdimdo_mlas (void)
708260484Sobrien{
7083218822Sdim  /* This restriction does not apply to mls (nor to mla in v6 or later).  */
7084218822Sdim  if (inst.operands[0].reg == inst.operands[1].reg
7085218822Sdim      && !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6)
7086218822Sdim      && !(inst.instruction & 0x00400000))
7087218822Sdim    as_tsktsk (_("Rd and Rm should be different in mla"));
708860484Sobrien
7089218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7090218822Sdim  inst.instruction |= inst.operands[1].reg;
7091218822Sdim  inst.instruction |= inst.operands[2].reg << 8;
7092218822Sdim  inst.instruction |= inst.operands[3].reg << 12;
7093218822Sdim}
709477298Sobrien
7095218822Sdimstatic void
7096218822Sdimdo_mov (void)
7097218822Sdim{
7098218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7099218822Sdim  encode_arm_shifter_operand (1);
7100218822Sdim}
710160484Sobrien
7102218822Sdim/* ARM V6T2 16-bit immediate register load: MOV[WT]{cond} Rd, #<imm16>.	 */
7103218822Sdimstatic void
7104218822Sdimdo_mov16 (void)
7105218822Sdim{
7106218822Sdim  bfd_vma imm;
7107218822Sdim  bfd_boolean top;
710860484Sobrien
7109218822Sdim  top = (inst.instruction & 0x00400000) != 0;
7110218822Sdim  constraint (top && inst.reloc.type == BFD_RELOC_ARM_MOVW,
7111218822Sdim	      _(":lower16: not allowed this instruction"));
7112218822Sdim  constraint (!top && inst.reloc.type == BFD_RELOC_ARM_MOVT,
7113218822Sdim	      _(":upper16: not allowed instruction"));
7114218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7115218822Sdim  if (inst.reloc.type == BFD_RELOC_UNUSED)
711660484Sobrien    {
7117218822Sdim      imm = inst.reloc.exp.X_add_number;
7118218822Sdim      /* The value is in two pieces: 0:11, 16:19.  */
7119218822Sdim      inst.instruction |= (imm & 0x00000fff);
7120218822Sdim      inst.instruction |= (imm & 0x0000f000) << 4;
712160484Sobrien    }
712260484Sobrien}
712360484Sobrien
7124218822Sdimstatic void do_vfp_nsyn_opcode (const char *);
712577298Sobrien
712660484Sobrienstatic int
7127218822Sdimdo_vfp_nsyn_mrs (void)
712860484Sobrien{
7129218822Sdim  if (inst.operands[0].isvec)
713060484Sobrien    {
7131218822Sdim      if (inst.operands[1].reg != 1)
7132218822Sdim        first_error (_("operand 1 must be FPSCR"));
7133218822Sdim      memset (&inst.operands[0], '\0', sizeof (inst.operands[0]));
7134218822Sdim      memset (&inst.operands[1], '\0', sizeof (inst.operands[1]));
7135218822Sdim      do_vfp_nsyn_opcode ("fmstat");
713660484Sobrien    }
7137218822Sdim  else if (inst.operands[1].isvec)
7138218822Sdim    do_vfp_nsyn_opcode ("fmrx");
7139218822Sdim  else
7140218822Sdim    return FAIL;
7141218822Sdim
7142218822Sdim  return SUCCESS;
714360484Sobrien}
714460484Sobrien
714560484Sobrienstatic int
7146218822Sdimdo_vfp_nsyn_msr (void)
714760484Sobrien{
7148218822Sdim  if (inst.operands[0].isvec)
7149218822Sdim    do_vfp_nsyn_opcode ("fmxr");
7150218822Sdim  else
7151218822Sdim    return FAIL;
715277298Sobrien
7153218822Sdim  return SUCCESS;
7154218822Sdim}
715560484Sobrien
7156248466Sandrewstatic void
7157248460Sandrewdo_vfp_vmrs (void)
7158248460Sandrew{
7159248460Sandrew  int rt;
7160248460Sandrew
7161248460Sandrew  /* The destination register can be r0-r14 or APSR_nzcv */
7162248460Sandrew  if (inst.operands[0].reg > 14)
7163248460Sandrew    {
7164248460Sandrew      inst.error = BAD_PC;
7165248466Sandrew      return;
7166248460Sandrew    }
7167248460Sandrew
7168248460Sandrew  /* If the destination is r13 and not in ARM mode then unprefictable */
7169248460Sandrew  if (thumb_mode && inst.operands[0].reg == REG_SP)
7170248460Sandrew    {
7171248460Sandrew      inst.error = BAD_SP;
7172248466Sandrew      return;
7173248460Sandrew    }
7174248460Sandrew
7175248460Sandrew  /* If the destination is APSR_nzcv */
7176248460Sandrew  if (inst.operands[0].isvec && inst.operands[1].reg != 1)
7177248460Sandrew    {
7178248460Sandrew      inst.error = BAD_VMRS;
7179248466Sandrew      return;
7180248460Sandrew    }
7181248460Sandrew
7182248460Sandrew  if (inst.operands[0].isvec)
7183248460Sandrew    rt = 15;
7184248460Sandrew  else
7185248460Sandrew    rt = inst.operands[0].reg;
7186248460Sandrew
7187248460Sandrew  /* Or in the registers to use */
7188248460Sandrew  inst.instruction |= rt << 12;
7189248460Sandrew  inst.instruction |= inst.operands[1].reg << 16;
7190248460Sandrew}
7191248460Sandrew
7192248466Sandrewstatic void
7193248460Sandrewdo_vfp_vmsr (void)
7194248460Sandrew{
7195248460Sandrew  /* The destination register can be r0-r14 or APSR_nzcv */
7196248460Sandrew  if (inst.operands[1].reg > 14)
7197248460Sandrew    {
7198248460Sandrew      inst.error = BAD_PC;
7199248466Sandrew      return;
7200248460Sandrew    }
7201248460Sandrew
7202248460Sandrew  /* If the destination is r13 and not in ARM mode then unprefictable */
7203248460Sandrew  if (thumb_mode && inst.operands[0].reg == REG_SP)
7204248460Sandrew    {
7205248460Sandrew      inst.error = BAD_SP;
7206248466Sandrew      return;
7207248460Sandrew    }
7208248460Sandrew
7209248460Sandrew  /* Or in the registers to use */
7210248460Sandrew  inst.instruction |= inst.operands[1].reg << 12;
7211248460Sandrew  inst.instruction |= inst.operands[0].reg << 16;
7212248460Sandrew}
7213248460Sandrew
7214218822Sdimstatic void
7215218822Sdimdo_mrs (void)
7216218822Sdim{
7217218822Sdim  if (do_vfp_nsyn_mrs () == SUCCESS)
7218218822Sdim    return;
721989857Sobrien
7220218822Sdim  /* mrs only accepts CPSR/SPSR/CPSR_all/SPSR_all.  */
7221218822Sdim  constraint ((inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f))
7222218822Sdim	      != (PSR_c|PSR_f),
7223218822Sdim	      _("'CPSR' or 'SPSR' expected"));
7224218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7225218822Sdim  inst.instruction |= (inst.operands[1].imm & SPSR_BIT);
7226218822Sdim}
722760484Sobrien
7228218822Sdim/* Two possible forms:
7229218822Sdim      "{C|S}PSR_<field>, Rm",
7230218822Sdim      "{C|S}PSR_f, #expression".  */
7231218822Sdim
7232218822Sdimstatic void
7233218822Sdimdo_msr (void)
7234218822Sdim{
7235218822Sdim  if (do_vfp_nsyn_msr () == SUCCESS)
7236218822Sdim    return;
7237218822Sdim
7238218822Sdim  inst.instruction |= inst.operands[0].imm;
7239218822Sdim  if (inst.operands[1].isreg)
7240218822Sdim    inst.instruction |= inst.operands[1].reg;
7241218822Sdim  else
724260484Sobrien    {
7243218822Sdim      inst.instruction |= INST_IMMEDIATE;
7244218822Sdim      inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
7245218822Sdim      inst.reloc.pc_rel = 0;
724660484Sobrien    }
724760484Sobrien}
724860484Sobrien
7249218822Sdimstatic void
7250218822Sdimdo_mul (void)
725189857Sobrien{
7252218822Sdim  if (!inst.operands[2].present)
7253218822Sdim    inst.operands[2].reg = inst.operands[0].reg;
7254218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7255218822Sdim  inst.instruction |= inst.operands[1].reg;
7256218822Sdim  inst.instruction |= inst.operands[2].reg << 8;
7257218822Sdim
7258218822Sdim  if (inst.operands[0].reg == inst.operands[1].reg
7259218822Sdim      && !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6))
7260218822Sdim    as_tsktsk (_("Rd and Rm should be different in mul"));
726189857Sobrien}
726289857Sobrien
7263218822Sdim/* Long Multiply Parser
7264218822Sdim   UMULL RdLo, RdHi, Rm, Rs
7265218822Sdim   SMULL RdLo, RdHi, Rm, Rs
7266218822Sdim   UMLAL RdLo, RdHi, Rm, Rs
7267218822Sdim   SMLAL RdLo, RdHi, Rm, Rs.  */
726860484Sobrien
7269218822Sdimstatic void
7270218822Sdimdo_mull (void)
727160484Sobrien{
7272218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7273218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7274218822Sdim  inst.instruction |= inst.operands[2].reg;
7275218822Sdim  inst.instruction |= inst.operands[3].reg << 8;
727677298Sobrien
7277254449Sandrew  /* rdhi, rdlo and rm must all be different prior to ARMv6.  */
7278218822Sdim  if (inst.operands[0].reg == inst.operands[1].reg
7279254449Sandrew      || ((inst.operands[0].reg == inst.operands[2].reg
7280218822Sdim      || inst.operands[1].reg == inst.operands[2].reg)
7281254449Sandrew      && !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6)))
7282218822Sdim    as_tsktsk (_("rdhi, rdlo and rm must all be different"));
7283218822Sdim}
728477298Sobrien
7285218822Sdimstatic void
7286218822Sdimdo_nop (void)
7287218822Sdim{
7288218822Sdim  if (inst.operands[0].present)
728960484Sobrien    {
7290218822Sdim      /* Architectural NOP hints are CPSR sets with no bits selected.  */
7291218822Sdim      inst.instruction &= 0xf0000000;
7292218822Sdim      inst.instruction |= 0x0320f000 + inst.operands[0].imm;
729360484Sobrien    }
7294218822Sdim}
729560484Sobrien
7296218822Sdim/* ARM V6 Pack Halfword Bottom Top instruction (argument parse).
7297218822Sdim   PKHBT {<cond>} <Rd>, <Rn>, <Rm> {, LSL #<shift_imm>}
7298218822Sdim   Condition defaults to COND_ALWAYS.
7299218822Sdim   Error if Rd, Rn or Rm are R15.  */
730077298Sobrien
7301218822Sdimstatic void
7302218822Sdimdo_pkhbt (void)
7303218822Sdim{
7304218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7305218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7306218822Sdim  inst.instruction |= inst.operands[2].reg;
7307218822Sdim  if (inst.operands[3].present)
7308218822Sdim    encode_arm_shift (3);
7309218822Sdim}
731060484Sobrien
7311218822Sdim/* ARM V6 PKHTB (Argument Parse).  */
731260484Sobrien
7313218822Sdimstatic void
7314218822Sdimdo_pkhtb (void)
7315218822Sdim{
7316218822Sdim  if (!inst.operands[3].present)
7317130561Sobrien    {
7318218822Sdim      /* If the shift specifier is omitted, turn the instruction
7319218822Sdim	 into pkhbt rd, rm, rn. */
7320218822Sdim      inst.instruction &= 0xfff00010;
7321218822Sdim      inst.instruction |= inst.operands[0].reg << 12;
7322218822Sdim      inst.instruction |= inst.operands[1].reg;
7323218822Sdim      inst.instruction |= inst.operands[2].reg << 16;
7324130561Sobrien    }
7325218822Sdim  else
7326130561Sobrien    {
7327218822Sdim      inst.instruction |= inst.operands[0].reg << 12;
7328218822Sdim      inst.instruction |= inst.operands[1].reg << 16;
7329218822Sdim      inst.instruction |= inst.operands[2].reg;
7330218822Sdim      encode_arm_shift (3);
7331130561Sobrien    }
7332218822Sdim}
733360484Sobrien
7334218822Sdim/* ARMv5TE: Preload-Cache
733560484Sobrien
7336218822Sdim    PLD <addr_mode>
733760484Sobrien
7338218822Sdim  Syntactically, like LDR with B=1, W=0, L=1.  */
733960484Sobrien
7340218822Sdimstatic void
7341218822Sdimdo_pld (void)
7342218822Sdim{
7343218822Sdim  constraint (!inst.operands[0].isreg,
7344218822Sdim	      _("'[' expected after PLD mnemonic"));
7345218822Sdim  constraint (inst.operands[0].postind,
7346218822Sdim	      _("post-indexed expression used in preload instruction"));
7347218822Sdim  constraint (inst.operands[0].writeback,
7348218822Sdim	      _("writeback used in preload instruction"));
7349218822Sdim  constraint (!inst.operands[0].preind,
7350218822Sdim	      _("unindexed addressing used in preload instruction"));
7351218822Sdim  encode_arm_addr_mode_2 (0, /*is_t=*/FALSE);
7352218822Sdim}
735360484Sobrien
7354218822Sdim/* ARMv7: PLI <addr_mode>  */
7355218822Sdimstatic void
7356218822Sdimdo_pli (void)
7357218822Sdim{
7358218822Sdim  constraint (!inst.operands[0].isreg,
7359218822Sdim	      _("'[' expected after PLI mnemonic"));
7360218822Sdim  constraint (inst.operands[0].postind,
7361218822Sdim	      _("post-indexed expression used in preload instruction"));
7362218822Sdim  constraint (inst.operands[0].writeback,
7363218822Sdim	      _("writeback used in preload instruction"));
7364218822Sdim  constraint (!inst.operands[0].preind,
7365218822Sdim	      _("unindexed addressing used in preload instruction"));
7366218822Sdim  encode_arm_addr_mode_2 (0, /*is_t=*/FALSE);
7367218822Sdim  inst.instruction &= ~PRE_INDEX;
7368218822Sdim}
736977298Sobrien
7370218822Sdimstatic void
7371218822Sdimdo_push_pop (void)
7372218822Sdim{
7373218822Sdim  inst.operands[1] = inst.operands[0];
7374218822Sdim  memset (&inst.operands[0], 0, sizeof inst.operands[0]);
7375218822Sdim  inst.operands[0].isreg = 1;
7376218822Sdim  inst.operands[0].writeback = 1;
7377218822Sdim  inst.operands[0].reg = REG_SP;
7378218822Sdim  do_ldmstm ();
7379218822Sdim}
738077298Sobrien
7381218822Sdim/* ARM V6 RFE (Return from Exception) loads the PC and CPSR from the
7382218822Sdim   word at the specified address and the following word
7383218822Sdim   respectively.
7384218822Sdim   Unconditionally executed.
7385218822Sdim   Error if Rn is R15.	*/
738677298Sobrien
7387218822Sdimstatic void
7388218822Sdimdo_rfe (void)
7389218822Sdim{
7390218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7391218822Sdim  if (inst.operands[0].writeback)
7392218822Sdim    inst.instruction |= WRITE_BACK;
739360484Sobrien}
739460484Sobrien
7395218822Sdim/* ARM V6 ssat (argument parse).  */
739677298Sobrien
7397218822Sdimstatic void
7398218822Sdimdo_ssat (void)
739960484Sobrien{
7400218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7401218822Sdim  inst.instruction |= (inst.operands[1].imm - 1) << 16;
7402218822Sdim  inst.instruction |= inst.operands[2].reg;
740360484Sobrien
7404218822Sdim  if (inst.operands[3].present)
7405218822Sdim    encode_arm_shift (3);
7406218822Sdim}
740760484Sobrien
7408218822Sdim/* ARM V6 usat (argument parse).  */
740960484Sobrien
7410218822Sdimstatic void
7411218822Sdimdo_usat (void)
7412218822Sdim{
7413218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7414218822Sdim  inst.instruction |= inst.operands[1].imm << 16;
7415218822Sdim  inst.instruction |= inst.operands[2].reg;
741660484Sobrien
7417218822Sdim  if (inst.operands[3].present)
7418218822Sdim    encode_arm_shift (3);
7419218822Sdim}
742060484Sobrien
7421218822Sdim/* ARM V6 ssat16 (argument parse).  */
742260484Sobrien
7423218822Sdimstatic void
7424218822Sdimdo_ssat16 (void)
7425218822Sdim{
7426218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7427218822Sdim  inst.instruction |= ((inst.operands[1].imm - 1) << 16);
7428218822Sdim  inst.instruction |= inst.operands[2].reg;
7429218822Sdim}
743060484Sobrien
7431218822Sdimstatic void
7432218822Sdimdo_usat16 (void)
7433218822Sdim{
7434218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7435218822Sdim  inst.instruction |= inst.operands[1].imm << 16;
7436218822Sdim  inst.instruction |= inst.operands[2].reg;
7437218822Sdim}
743860484Sobrien
7439218822Sdim/* ARM V6 SETEND (argument parse).  Sets the E bit in the CPSR while
7440218822Sdim   preserving the other bits.
744160484Sobrien
7442218822Sdim   setend <endian_specifier>, where <endian_specifier> is either
7443218822Sdim   BE or LE.  */
744460484Sobrien
7445218822Sdimstatic void
7446218822Sdimdo_setend (void)
7447218822Sdim{
7448218822Sdim  if (inst.operands[0].imm)
7449218822Sdim    inst.instruction |= 0x200;
7450218822Sdim}
745160484Sobrien
7452218822Sdimstatic void
7453218822Sdimdo_shift (void)
7454218822Sdim{
7455218822Sdim  unsigned int Rm = (inst.operands[1].present
7456218822Sdim		     ? inst.operands[1].reg
7457218822Sdim		     : inst.operands[0].reg);
745860484Sobrien
7459218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7460218822Sdim  inst.instruction |= Rm;
7461218822Sdim  if (inst.operands[2].isreg)  /* Rd, {Rm,} Rs */
7462218822Sdim    {
7463218822Sdim      inst.instruction |= inst.operands[2].reg << 8;
7464218822Sdim      inst.instruction |= SHIFT_BY_REG;
746560484Sobrien    }
7466218822Sdim  else
7467218822Sdim    inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
7468218822Sdim}
746960484Sobrien
7470218822Sdimstatic void
7471218822Sdimdo_smc (void)
7472218822Sdim{
7473218822Sdim  inst.reloc.type = BFD_RELOC_ARM_SMC;
7474218822Sdim  inst.reloc.pc_rel = 0;
7475218822Sdim}
747660484Sobrien
7477218822Sdimstatic void
7478218822Sdimdo_swi (void)
7479218822Sdim{
7480218822Sdim  inst.reloc.type = BFD_RELOC_ARM_SWI;
7481218822Sdim  inst.reloc.pc_rel = 0;
748260484Sobrien}
748360484Sobrien
7484218822Sdim/* ARM V5E (El Segundo) signed-multiply-accumulate (argument parse)
7485218822Sdim   SMLAxy{cond} Rd,Rm,Rs,Rn
7486218822Sdim   SMLAWy{cond} Rd,Rm,Rs,Rn
7487218822Sdim   Error if any register is R15.  */
7488218822Sdim
7489218822Sdimstatic void
7490218822Sdimdo_smla (void)
749160484Sobrien{
7492218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7493218822Sdim  inst.instruction |= inst.operands[1].reg;
7494218822Sdim  inst.instruction |= inst.operands[2].reg << 8;
7495218822Sdim  inst.instruction |= inst.operands[3].reg << 12;
7496218822Sdim}
749760484Sobrien
7498218822Sdim/* ARM V5E (El Segundo) signed-multiply-accumulate-long (argument parse)
7499218822Sdim   SMLALxy{cond} Rdlo,Rdhi,Rm,Rs
7500218822Sdim   Error if any register is R15.
7501218822Sdim   Warning if Rdlo == Rdhi.  */
750277298Sobrien
7503218822Sdimstatic void
7504218822Sdimdo_smlal (void)
7505218822Sdim{
7506218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7507218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7508218822Sdim  inst.instruction |= inst.operands[2].reg;
7509218822Sdim  inst.instruction |= inst.operands[3].reg << 8;
7510218822Sdim
7511218822Sdim  if (inst.operands[0].reg == inst.operands[1].reg)
7512218822Sdim    as_tsktsk (_("rdhi and rdlo must be different"));
7513218822Sdim}
7514218822Sdim
7515218822Sdim/* ARM V5E (El Segundo) signed-multiply (argument parse)
7516218822Sdim   SMULxy{cond} Rd,Rm,Rs
7517218822Sdim   Error if any register is R15.  */
7518218822Sdim
7519218822Sdimstatic void
7520218822Sdimdo_smul (void)
7521218822Sdim{
7522218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7523218822Sdim  inst.instruction |= inst.operands[1].reg;
7524218822Sdim  inst.instruction |= inst.operands[2].reg << 8;
7525218822Sdim}
7526218822Sdim
7527218822Sdim/* ARM V6 srs (argument parse).  The variable fields in the encoding are
7528218822Sdim   the same for both ARM and Thumb-2.  */
7529218822Sdim
7530218822Sdimstatic void
7531218822Sdimdo_srs (void)
7532218822Sdim{
7533218822Sdim  int reg;
7534218822Sdim
7535218822Sdim  if (inst.operands[0].present)
753660484Sobrien    {
7537218822Sdim      reg = inst.operands[0].reg;
7538218822Sdim      constraint (reg != 13, _("SRS base register must be r13"));
753960484Sobrien    }
754060484Sobrien  else
7541218822Sdim    reg = 13;
754277298Sobrien
7543218822Sdim  inst.instruction |= reg << 16;
7544218822Sdim  inst.instruction |= inst.operands[1].imm;
7545218822Sdim  if (inst.operands[0].writeback || inst.operands[1].writeback)
7546218822Sdim    inst.instruction |= WRITE_BACK;
7547218822Sdim}
754860484Sobrien
7549218822Sdim/* ARM V6 strex (argument parse).  */
755060484Sobrien
7551218822Sdimstatic void
7552218822Sdimdo_strex (void)
7553218822Sdim{
7554218822Sdim  constraint (!inst.operands[2].isreg || !inst.operands[2].preind
7555218822Sdim	      || inst.operands[2].postind || inst.operands[2].writeback
7556218822Sdim	      || inst.operands[2].immisreg || inst.operands[2].shifted
7557218822Sdim	      || inst.operands[2].negative
7558218822Sdim	      /* See comment in do_ldrex().  */
7559218822Sdim	      || (inst.operands[2].reg == REG_PC),
7560218822Sdim	      BAD_ADDR_MODE);
756177298Sobrien
7562218822Sdim  constraint (inst.operands[0].reg == inst.operands[1].reg
7563218822Sdim	      || inst.operands[0].reg == inst.operands[2].reg, BAD_OVERLAP);
756460484Sobrien
7565218822Sdim  constraint (inst.reloc.exp.X_op != O_constant
7566218822Sdim	      || inst.reloc.exp.X_add_number != 0,
7567218822Sdim	      _("offset must be zero in ARM encoding"));
756860484Sobrien
7569218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7570218822Sdim  inst.instruction |= inst.operands[1].reg;
7571218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
7572218822Sdim  inst.reloc.type = BFD_RELOC_UNUSED;
7573218822Sdim}
757460484Sobrien
7575218822Sdimstatic void
7576218822Sdimdo_strexd (void)
7577218822Sdim{
7578218822Sdim  constraint (inst.operands[1].reg % 2 != 0,
7579218822Sdim	      _("even register required"));
7580218822Sdim  constraint (inst.operands[2].present
7581218822Sdim	      && inst.operands[2].reg != inst.operands[1].reg + 1,
7582218822Sdim	      _("can only store two consecutive registers"));
7583218822Sdim  /* If op 2 were present and equal to PC, this function wouldn't
7584218822Sdim     have been called in the first place.  */
7585218822Sdim  constraint (inst.operands[1].reg == REG_LR, _("r14 not allowed here"));
758660484Sobrien
7587218822Sdim  constraint (inst.operands[0].reg == inst.operands[1].reg
7588218822Sdim	      || inst.operands[0].reg == inst.operands[1].reg + 1
7589218822Sdim	      || inst.operands[0].reg == inst.operands[3].reg,
7590218822Sdim	      BAD_OVERLAP);
759160484Sobrien
7592218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7593218822Sdim  inst.instruction |= inst.operands[1].reg;
7594218822Sdim  inst.instruction |= inst.operands[3].reg << 16;
759560484Sobrien}
759660484Sobrien
7597218822Sdim/* ARM V6 SXTAH extracts a 16-bit value from a register, sign
7598218822Sdim   extends it to 32-bits, and adds the result to a value in another
7599218822Sdim   register.  You can specify a rotation by 0, 8, 16, or 24 bits
7600218822Sdim   before extracting the 16-bit value.
7601218822Sdim   SXTAH{<cond>} <Rd>, <Rn>, <Rm>{, <rotation>}
7602218822Sdim   Condition defaults to COND_ALWAYS.
7603218822Sdim   Error if any register uses R15.  */
7604218822Sdim
7605218822Sdimstatic void
7606218822Sdimdo_sxtah (void)
760760484Sobrien{
7608218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7609218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7610218822Sdim  inst.instruction |= inst.operands[2].reg;
7611218822Sdim  inst.instruction |= inst.operands[3].imm << 10;
7612218822Sdim}
761360484Sobrien
7614218822Sdim/* ARM V6 SXTH.
761560484Sobrien
7616218822Sdim   SXTH {<cond>} <Rd>, <Rm>{, <rotation>}
7617218822Sdim   Condition defaults to COND_ALWAYS.
7618218822Sdim   Error if any register uses R15.  */
761960484Sobrien
7620218822Sdimstatic void
7621218822Sdimdo_sxth (void)
7622218822Sdim{
7623218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7624218822Sdim  inst.instruction |= inst.operands[1].reg;
7625218822Sdim  inst.instruction |= inst.operands[2].imm << 10;
7626218822Sdim}
7627218822Sdim
7628218822Sdim/* VFP instructions.  In a logical order: SP variant first, monad
7629218822Sdim   before dyad, arithmetic then move then load/store.  */
763060484Sobrien
7631218822Sdimstatic void
7632218822Sdimdo_vfp_sp_monadic (void)
7633218822Sdim{
7634218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7635218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sm);
7636218822Sdim}
763760484Sobrien
7638218822Sdimstatic void
7639218822Sdimdo_vfp_sp_dyadic (void)
7640218822Sdim{
7641218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7642218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sn);
7643218822Sdim  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Sm);
7644218822Sdim}
764560484Sobrien
7646218822Sdimstatic void
7647218822Sdimdo_vfp_sp_compare_z (void)
7648218822Sdim{
7649218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7650218822Sdim}
765160484Sobrien
7652218822Sdimstatic void
7653218822Sdimdo_vfp_dp_sp_cvt (void)
7654218822Sdim{
7655218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7656218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sm);
7657218822Sdim}
765860484Sobrien
7659218822Sdimstatic void
7660218822Sdimdo_vfp_sp_dp_cvt (void)
7661218822Sdim{
7662218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7663218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dm);
766460484Sobrien}
766560484Sobrien
766660484Sobrienstatic void
7667218822Sdimdo_vfp_reg_from_sp (void)
766860484Sobrien{
7669218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7670218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sn);
7671218822Sdim}
767260484Sobrien
7673218822Sdimstatic void
7674218822Sdimdo_vfp_reg2_from_sp2 (void)
7675218822Sdim{
7676218822Sdim  constraint (inst.operands[2].imm != 2,
7677218822Sdim	      _("only two consecutive VFP SP registers allowed here"));
7678218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7679218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7680218822Sdim  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Sm);
7681218822Sdim}
768260484Sobrien
7683218822Sdimstatic void
7684218822Sdimdo_vfp_sp_from_reg (void)
7685218822Sdim{
7686218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sn);
7687218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
768860484Sobrien}
768960484Sobrien
769060484Sobrienstatic void
7691218822Sdimdo_vfp_sp2_from_reg2 (void)
769260484Sobrien{
7693218822Sdim  constraint (inst.operands[0].imm != 2,
7694218822Sdim	      _("only two consecutive VFP SP registers allowed here"));
7695218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sm);
7696218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
7697218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
7698218822Sdim}
769960484Sobrien
7700218822Sdimstatic void
7701218822Sdimdo_vfp_sp_ldst (void)
7702218822Sdim{
7703218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7704218822Sdim  encode_arm_cp_address (1, FALSE, TRUE, 0);
7705218822Sdim}
770677298Sobrien
7707218822Sdimstatic void
7708218822Sdimdo_vfp_dp_ldst (void)
7709218822Sdim{
7710218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7711218822Sdim  encode_arm_cp_address (1, FALSE, TRUE, 0);
7712218822Sdim}
771377298Sobrien
7714218822Sdim
7715218822Sdimstatic void
7716218822Sdimvfp_sp_ldstm (enum vfp_ldstm_type ldstm_type)
7717218822Sdim{
7718218822Sdim  if (inst.operands[0].writeback)
7719218822Sdim    inst.instruction |= WRITE_BACK;
7720218822Sdim  else
7721218822Sdim    constraint (ldstm_type != VFP_LDSTMIA,
7722218822Sdim		_("this addressing mode requires base-register writeback"));
7723218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7724218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sd);
7725218822Sdim  inst.instruction |= inst.operands[1].imm;
772660484Sobrien}
772760484Sobrien
772860484Sobrienstatic void
7729218822Sdimvfp_dp_ldstm (enum vfp_ldstm_type ldstm_type)
773060484Sobrien{
7731218822Sdim  int count;
773260484Sobrien
7733218822Sdim  if (inst.operands[0].writeback)
7734218822Sdim    inst.instruction |= WRITE_BACK;
7735218822Sdim  else
7736218822Sdim    constraint (ldstm_type != VFP_LDSTMIA && ldstm_type != VFP_LDSTMIAX,
7737218822Sdim		_("this addressing mode requires base-register writeback"));
773860484Sobrien
7739218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7740218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dd);
774189857Sobrien
7742218822Sdim  count = inst.operands[1].imm << 1;
7743218822Sdim  if (ldstm_type == VFP_LDSTMIAX || ldstm_type == VFP_LDSTMDBX)
7744218822Sdim    count += 1;
774577298Sobrien
7746218822Sdim  inst.instruction |= count;
774760484Sobrien}
774860484Sobrien
774960484Sobrienstatic void
7750218822Sdimdo_vfp_sp_ldstmia (void)
775160484Sobrien{
7752218822Sdim  vfp_sp_ldstm (VFP_LDSTMIA);
7753218822Sdim}
775460484Sobrien
7755218822Sdimstatic void
7756218822Sdimdo_vfp_sp_ldstmdb (void)
7757218822Sdim{
7758218822Sdim  vfp_sp_ldstm (VFP_LDSTMDB);
7759218822Sdim}
776060484Sobrien
7761218822Sdimstatic void
7762218822Sdimdo_vfp_dp_ldstmia (void)
7763218822Sdim{
7764218822Sdim  vfp_dp_ldstm (VFP_LDSTMIA);
7765218822Sdim}
776660484Sobrien
7767218822Sdimstatic void
7768218822Sdimdo_vfp_dp_ldstmdb (void)
7769218822Sdim{
7770218822Sdim  vfp_dp_ldstm (VFP_LDSTMDB);
777160484Sobrien}
777260484Sobrien
777360484Sobrienstatic void
7774218822Sdimdo_vfp_xp_ldstmia (void)
777560484Sobrien{
7776218822Sdim  vfp_dp_ldstm (VFP_LDSTMIAX);
7777218822Sdim}
777860484Sobrien
7779218822Sdimstatic void
7780218822Sdimdo_vfp_xp_ldstmdb (void)
7781218822Sdim{
7782218822Sdim  vfp_dp_ldstm (VFP_LDSTMDBX);
7783218822Sdim}
778460484Sobrien
7785218822Sdimstatic void
7786218822Sdimdo_vfp_dp_rd_rm (void)
7787218822Sdim{
7788218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7789218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dm);
7790218822Sdim}
779160484Sobrien
7792218822Sdimstatic void
7793218822Sdimdo_vfp_dp_rn_rd (void)
7794218822Sdim{
7795218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dn);
7796218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dd);
779760484Sobrien}
779860484Sobrien
7799218822Sdimstatic void
7800218822Sdimdo_vfp_dp_rd_rn (void)
780160484Sobrien{
7802218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7803218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dn);
7804218822Sdim}
780560484Sobrien
7806218822Sdimstatic void
7807218822Sdimdo_vfp_dp_rd_rn_rm (void)
7808218822Sdim{
7809218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7810218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dn);
7811218822Sdim  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Dm);
7812218822Sdim}
781360484Sobrien
7814218822Sdimstatic void
7815218822Sdimdo_vfp_dp_rd (void)
7816218822Sdim{
7817218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7818218822Sdim}
781960484Sobrien
7820218822Sdimstatic void
7821218822Sdimdo_vfp_dp_rm_rd_rn (void)
7822218822Sdim{
7823218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dm);
7824218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dd);
7825218822Sdim  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Dn);
7826218822Sdim}
782760484Sobrien
7828218822Sdim/* VFPv3 instructions.  */
7829218822Sdimstatic void
7830218822Sdimdo_vfp_sp_const (void)
7831218822Sdim{
7832218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7833218822Sdim  inst.instruction |= (inst.operands[1].imm & 0xf0) << 12;
7834218822Sdim  inst.instruction |= (inst.operands[1].imm & 0x0f);
7835218822Sdim}
783660484Sobrien
7837218822Sdimstatic void
7838218822Sdimdo_vfp_dp_const (void)
7839218822Sdim{
7840218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7841218822Sdim  inst.instruction |= (inst.operands[1].imm & 0xf0) << 12;
7842218822Sdim  inst.instruction |= (inst.operands[1].imm & 0x0f);
7843218822Sdim}
784460484Sobrien
7845218822Sdimstatic void
7846218822Sdimvfp_conv (int srcsize)
7847218822Sdim{
7848218822Sdim  unsigned immbits = srcsize - inst.operands[1].imm;
7849218822Sdim  inst.instruction |= (immbits & 1) << 5;
7850218822Sdim  inst.instruction |= (immbits >> 1);
7851218822Sdim}
785277298Sobrien
7853218822Sdimstatic void
7854218822Sdimdo_vfp_sp_conv_16 (void)
7855218822Sdim{
7856218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7857218822Sdim  vfp_conv (16);
7858218822Sdim}
785977298Sobrien
7860218822Sdimstatic void
7861218822Sdimdo_vfp_dp_conv_16 (void)
7862218822Sdim{
7863218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7864218822Sdim  vfp_conv (16);
7865218822Sdim}
786660484Sobrien
7867218822Sdimstatic void
7868218822Sdimdo_vfp_sp_conv_32 (void)
7869218822Sdim{
7870218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7871218822Sdim  vfp_conv (32);
787260484Sobrien}
787360484Sobrien
787460484Sobrienstatic void
7875218822Sdimdo_vfp_dp_conv_32 (void)
787660484Sobrien{
7877218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7878218822Sdim  vfp_conv (32);
7879218822Sdim}
788060484Sobrien
7881218822Sdim
7882218822Sdim/* FPA instructions.  Also in a logical order.	*/
788389857Sobrien
7884218822Sdimstatic void
7885218822Sdimdo_fpa_cmp (void)
7886218822Sdim{
7887218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7888218822Sdim  inst.instruction |= inst.operands[1].reg;
7889218822Sdim}
789089857Sobrien
7891218822Sdimstatic void
7892218822Sdimdo_fpa_ldmstm (void)
7893218822Sdim{
7894218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7895218822Sdim  switch (inst.operands[1].imm)
789689857Sobrien    {
7897218822Sdim    case 1: inst.instruction |= CP_T_X;		 break;
7898218822Sdim    case 2: inst.instruction |= CP_T_Y;		 break;
7899218822Sdim    case 3: inst.instruction |= CP_T_Y | CP_T_X; break;
7900218822Sdim    case 4:					 break;
7901218822Sdim    default: abort ();
790289857Sobrien    }
790389857Sobrien
7904218822Sdim  if (inst.instruction & (PRE_INDEX | INDEX_UP))
790589857Sobrien    {
7906218822Sdim      /* The instruction specified "ea" or "fd", so we can only accept
7907218822Sdim	 [Rn]{!}.  The instruction does not really support stacking or
7908218822Sdim	 unstacking, so we have to emulate these by setting appropriate
7909218822Sdim	 bits and offsets.  */
7910218822Sdim      constraint (inst.reloc.exp.X_op != O_constant
7911218822Sdim		  || inst.reloc.exp.X_add_number != 0,
7912218822Sdim		  _("this instruction does not support indexing"));
791389857Sobrien
7914218822Sdim      if ((inst.instruction & PRE_INDEX) || inst.operands[2].writeback)
7915218822Sdim	inst.reloc.exp.X_add_number = 12 * inst.operands[1].imm;
791689857Sobrien
7917218822Sdim      if (!(inst.instruction & INDEX_UP))
7918218822Sdim	inst.reloc.exp.X_add_number = -inst.reloc.exp.X_add_number;
791989857Sobrien
7920218822Sdim      if (!(inst.instruction & PRE_INDEX) && inst.operands[2].writeback)
7921218822Sdim	{
7922218822Sdim	  inst.operands[2].preind = 0;
7923218822Sdim	  inst.operands[2].postind = 1;
7924218822Sdim	}
7925218822Sdim    }
792689857Sobrien
7927218822Sdim  encode_arm_cp_address (2, TRUE, TRUE, 0);
7928218822Sdim}
792989857Sobrien
7930218822Sdim
7931218822Sdim/* iWMMXt instructions: strictly in alphabetical order.	 */
793289857Sobrien
7933218822Sdimstatic void
7934218822Sdimdo_iwmmxt_tandorc (void)
7935218822Sdim{
7936218822Sdim  constraint (inst.operands[0].reg != REG_PC, _("only r15 allowed here"));
7937218822Sdim}
793889857Sobrien
7939218822Sdimstatic void
7940218822Sdimdo_iwmmxt_textrc (void)
7941218822Sdim{
7942218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7943218822Sdim  inst.instruction |= inst.operands[1].imm;
7944218822Sdim}
794589857Sobrien
7946218822Sdimstatic void
7947218822Sdimdo_iwmmxt_textrm (void)
7948218822Sdim{
7949218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7950218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7951218822Sdim  inst.instruction |= inst.operands[2].imm;
7952218822Sdim}
795389857Sobrien
7954218822Sdimstatic void
7955218822Sdimdo_iwmmxt_tinsr (void)
7956218822Sdim{
7957218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7958218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
7959218822Sdim  inst.instruction |= inst.operands[2].imm;
7960218822Sdim}
796189857Sobrien
7962218822Sdimstatic void
7963218822Sdimdo_iwmmxt_tmia (void)
7964218822Sdim{
7965218822Sdim  inst.instruction |= inst.operands[0].reg << 5;
7966218822Sdim  inst.instruction |= inst.operands[1].reg;
7967218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
7968218822Sdim}
796989857Sobrien
7970218822Sdimstatic void
7971218822Sdimdo_iwmmxt_waligni (void)
7972218822Sdim{
7973218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7974218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7975218822Sdim  inst.instruction |= inst.operands[2].reg;
7976218822Sdim  inst.instruction |= inst.operands[3].imm << 20;
7977218822Sdim}
797889857Sobrien
7979218822Sdimstatic void
7980218822Sdimdo_iwmmxt_wmerge (void)
7981218822Sdim{
7982218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7983218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7984218822Sdim  inst.instruction |= inst.operands[2].reg;
7985218822Sdim  inst.instruction |= inst.operands[3].imm << 21;
7986218822Sdim}
798789857Sobrien
7988218822Sdimstatic void
7989218822Sdimdo_iwmmxt_wmov (void)
7990218822Sdim{
7991218822Sdim  /* WMOV rD, rN is an alias for WOR rD, rN, rN.  */
7992218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7993218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7994218822Sdim  inst.instruction |= inst.operands[1].reg;
7995218822Sdim}
799689857Sobrien
7997218822Sdimstatic void
7998218822Sdimdo_iwmmxt_wldstbh (void)
7999218822Sdim{
8000218822Sdim  int reloc;
8001218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
8002218822Sdim  if (thumb_mode)
8003218822Sdim    reloc = BFD_RELOC_ARM_T32_CP_OFF_IMM_S2;
8004218822Sdim  else
8005218822Sdim    reloc = BFD_RELOC_ARM_CP_OFF_IMM_S2;
8006218822Sdim  encode_arm_cp_address (1, TRUE, FALSE, reloc);
8007218822Sdim}
8008218822Sdim
8009218822Sdimstatic void
8010218822Sdimdo_iwmmxt_wldstw (void)
8011218822Sdim{
8012218822Sdim  /* RIWR_RIWC clears .isreg for a control register.  */
8013218822Sdim  if (!inst.operands[0].isreg)
8014218822Sdim    {
8015218822Sdim      constraint (inst.cond != COND_ALWAYS, BAD_COND);
8016218822Sdim      inst.instruction |= 0xf0000000;
801789857Sobrien    }
801860484Sobrien
8019218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
8020218822Sdim  encode_arm_cp_address (1, TRUE, TRUE, 0);
8021218822Sdim}
802260484Sobrien
8023218822Sdimstatic void
8024218822Sdimdo_iwmmxt_wldstd (void)
8025218822Sdim{
8026218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
8027218822Sdim  if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2)
8028218822Sdim      && inst.operands[1].immisreg)
8029218822Sdim    {
8030218822Sdim      inst.instruction &= ~0x1a000ff;
8031218822Sdim      inst.instruction |= (0xf << 28);
8032218822Sdim      if (inst.operands[1].preind)
8033218822Sdim	inst.instruction |= PRE_INDEX;
8034218822Sdim      if (!inst.operands[1].negative)
8035218822Sdim	inst.instruction |= INDEX_UP;
8036218822Sdim      if (inst.operands[1].writeback)
8037218822Sdim	inst.instruction |= WRITE_BACK;
8038218822Sdim      inst.instruction |= inst.operands[1].reg << 16;
8039218822Sdim      inst.instruction |= inst.reloc.exp.X_add_number << 4;
8040218822Sdim      inst.instruction |= inst.operands[1].imm;
8041218822Sdim    }
8042218822Sdim  else
8043218822Sdim    encode_arm_cp_address (1, TRUE, FALSE, 0);
8044218822Sdim}
804589857Sobrien
8046218822Sdimstatic void
8047218822Sdimdo_iwmmxt_wshufh (void)
8048218822Sdim{
8049218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
8050218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
8051218822Sdim  inst.instruction |= ((inst.operands[2].imm & 0xf0) << 16);
8052218822Sdim  inst.instruction |= (inst.operands[2].imm & 0x0f);
8053218822Sdim}
805489857Sobrien
8055218822Sdimstatic void
8056218822Sdimdo_iwmmxt_wzero (void)
8057218822Sdim{
8058218822Sdim  /* WZERO reg is an alias for WANDN reg, reg, reg.  */
8059218822Sdim  inst.instruction |= inst.operands[0].reg;
8060218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
8061218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
8062218822Sdim}
806389857Sobrien
8064218822Sdimstatic void
8065218822Sdimdo_iwmmxt_wrwrwr_or_imm5 (void)
8066218822Sdim{
8067218822Sdim  if (inst.operands[2].isreg)
8068218822Sdim    do_rd_rn_rm ();
8069218822Sdim  else {
8070218822Sdim    constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2),
8071218822Sdim		_("immediate operand requires iWMMXt2"));
8072218822Sdim    do_rd_rn ();
8073218822Sdim    if (inst.operands[2].imm == 0)
8074218822Sdim      {
8075218822Sdim	switch ((inst.instruction >> 20) & 0xf)
8076218822Sdim	  {
8077218822Sdim	  case 4:
8078218822Sdim	  case 5:
8079218822Sdim	  case 6:
8080218822Sdim	  case 7:
8081218822Sdim	    /* w...h wrd, wrn, #0 -> wrorh wrd, wrn, #16.  */
8082218822Sdim	    inst.operands[2].imm = 16;
8083218822Sdim	    inst.instruction = (inst.instruction & 0xff0fffff) | (0x7 << 20);
8084218822Sdim	    break;
8085218822Sdim	  case 8:
8086218822Sdim	  case 9:
8087218822Sdim	  case 10:
8088218822Sdim	  case 11:
8089218822Sdim	    /* w...w wrd, wrn, #0 -> wrorw wrd, wrn, #32.  */
8090218822Sdim	    inst.operands[2].imm = 32;
8091218822Sdim	    inst.instruction = (inst.instruction & 0xff0fffff) | (0xb << 20);
8092218822Sdim	    break;
8093218822Sdim	  case 12:
8094218822Sdim	  case 13:
8095218822Sdim	  case 14:
8096218822Sdim	  case 15:
809789857Sobrien	    {
8098218822Sdim	      /* w...d wrd, wrn, #0 -> wor wrd, wrn, wrn.  */
8099218822Sdim	      unsigned long wrn;
8100218822Sdim	      wrn = (inst.instruction >> 16) & 0xf;
8101218822Sdim	      inst.instruction &= 0xff0fff0f;
8102218822Sdim	      inst.instruction |= wrn;
8103218822Sdim	      /* Bail out here; the instruction is now assembled.  */
810489857Sobrien	      return;
810589857Sobrien	    }
8106218822Sdim	  }
8107218822Sdim      }
8108218822Sdim    /* Map 32 -> 0, etc.  */
8109218822Sdim    inst.operands[2].imm &= 0x1f;
8110218822Sdim    inst.instruction |= (0xf << 28) | ((inst.operands[2].imm & 0x10) << 4) | (inst.operands[2].imm & 0xf);
8111218822Sdim  }
8112218822Sdim}
8113218822Sdim
8114218822Sdim/* Cirrus Maverick instructions.  Simple 2-, 3-, and 4-register
8115218822Sdim   operations first, then control, shift, and load/store.  */
811689857Sobrien
8117218822Sdim/* Insns like "foo X,Y,Z".  */
811889857Sobrien
8119218822Sdimstatic void
8120218822Sdimdo_mav_triple (void)
8121218822Sdim{
8122218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
8123218822Sdim  inst.instruction |= inst.operands[1].reg;
8124218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
8125218822Sdim}
812689857Sobrien
8127218822Sdim/* Insns like "foo W,X,Y,Z".
8128218822Sdim    where W=MVAX[0:3] and X,Y,Z=MVFX[0:15].  */
812989857Sobrien
8130218822Sdimstatic void
8131218822Sdimdo_mav_quad (void)
8132218822Sdim{
8133218822Sdim  inst.instruction |= inst.operands[0].reg << 5;
8134218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
8135218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
8136218822Sdim  inst.instruction |= inst.operands[3].reg;
8137218822Sdim}
813860484Sobrien
8139218822Sdim/* cfmvsc32<cond> DSPSC,MVDX[15:0].  */
8140218822Sdimstatic void
8141218822Sdimdo_mav_dspsc (void)
8142218822Sdim{
8143218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
814489857Sobrien}
814589857Sobrien
8146218822Sdim/* Maverick shift immediate instructions.
8147218822Sdim   cfsh32<cond> MVFX[15:0],MVFX[15:0],Shift[6:0].
8148218822Sdim   cfsh64<cond> MVDX[15:0],MVDX[15:0],Shift[6:0].  */
8149218822Sdim
815089857Sobrienstatic void
8151218822Sdimdo_mav_shift (void)
815289857Sobrien{
8153218822Sdim  int imm = inst.operands[2].imm;
815489857Sobrien
8155218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
8156218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
815777298Sobrien
8158218822Sdim  /* Bits 0-3 of the insn should have bits 0-3 of the immediate.
8159218822Sdim     Bits 5-7 of the insn should have bits 4-6 of the immediate.
8160218822Sdim     Bit 4 should be 0.	 */
8161218822Sdim  imm = (imm & 0xf) | ((imm & 0x70) << 1);
816260484Sobrien
8163218822Sdim  inst.instruction |= imm;
8164218822Sdim}
8165218822Sdim
8166218822Sdim/* XScale instructions.	 Also sorted arithmetic before move.  */
816760484Sobrien
8168218822Sdim/* Xscale multiply-accumulate (argument parse)
8169218822Sdim     MIAcc   acc0,Rm,Rs
8170218822Sdim     MIAPHcc acc0,Rm,Rs
8171218822Sdim     MIAxycc acc0,Rm,Rs.  */
817260484Sobrien
8173218822Sdimstatic void
8174218822Sdimdo_xsc_mia (void)
8175218822Sdim{
8176218822Sdim  inst.instruction |= inst.operands[1].reg;
8177218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
8178218822Sdim}
817960484Sobrien
8180218822Sdim/* Xscale move-accumulator-register (argument parse)
818160484Sobrien
8182218822Sdim     MARcc   acc0,RdLo,RdHi.  */
818360484Sobrien
8184218822Sdimstatic void
8185218822Sdimdo_xsc_mar (void)
8186218822Sdim{
8187218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
8188218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
8189218822Sdim}
819089857Sobrien
8191218822Sdim/* Xscale move-register-accumulator (argument parse)
819289857Sobrien
8193218822Sdim     MRAcc   RdLo,RdHi,acc0.  */
819489857Sobrien
8195218822Sdimstatic void
8196218822Sdimdo_xsc_mra (void)
8197218822Sdim{
8198218822Sdim  constraint (inst.operands[0].reg == inst.operands[1].reg, BAD_OVERLAP);
8199218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
8200218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
8201218822Sdim}
8202218822Sdim
8203218822Sdim/* Encoding functions relevant only to Thumb.  */
820489857Sobrien
8205218822Sdim/* inst.operands[i] is a shifted-register operand; encode
8206218822Sdim   it into inst.instruction in the format used by Thumb32.  */
820789857Sobrien
8208218822Sdimstatic void
8209218822Sdimencode_thumb32_shifted_operand (int i)
8210218822Sdim{
8211218822Sdim  unsigned int value = inst.reloc.exp.X_add_number;
8212218822Sdim  unsigned int shift = inst.operands[i].shift_kind;
8213218822Sdim
8214218822Sdim  constraint (inst.operands[i].immisreg,
8215218822Sdim	      _("shift by register not allowed in thumb mode"));
8216218822Sdim  inst.instruction |= inst.operands[i].reg;
8217218822Sdim  if (shift == SHIFT_RRX)
8218218822Sdim    inst.instruction |= SHIFT_ROR << 4;
821989857Sobrien  else
822089857Sobrien    {
8221218822Sdim      constraint (inst.reloc.exp.X_op != O_constant,
8222218822Sdim		  _("expression too complex"));
8223218822Sdim
8224218822Sdim      constraint (value > 32
8225218822Sdim		  || (value == 32 && (shift == SHIFT_LSL
8226218822Sdim				      || shift == SHIFT_ROR)),
8227218822Sdim		  _("shift expression is too large"));
8228218822Sdim
8229218822Sdim      if (value == 0)
8230218822Sdim	shift = SHIFT_LSL;
8231218822Sdim      else if (value == 32)
8232218822Sdim	value = 0;
8233218822Sdim
8234218822Sdim      inst.instruction |= shift << 4;
8235218822Sdim      inst.instruction |= (value & 0x1c) << 10;
8236218822Sdim      inst.instruction |= (value & 0x03) << 6;
823789857Sobrien    }
823889857Sobrien}
823989857Sobrien
8240218822Sdim
8241218822Sdim/* inst.operands[i] was set up by parse_address.  Encode it into a
8242218822Sdim   Thumb32 format load or store instruction.  Reject forms that cannot
8243218822Sdim   be used with such instructions.  If is_t is true, reject forms that
8244218822Sdim   cannot be used with a T instruction; if is_d is true, reject forms
8245218822Sdim   that cannot be used with a D instruction.  */
8246218822Sdim
8247218822Sdimstatic void
8248218822Sdimencode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
824989857Sobrien{
8250218822Sdim  bfd_boolean is_pc = (inst.operands[i].reg == REG_PC);
825189857Sobrien
8252218822Sdim  constraint (!inst.operands[i].isreg,
8253218822Sdim	      _("Instruction does not support =N addresses"));
8254218822Sdim
8255218822Sdim  inst.instruction |= inst.operands[i].reg << 16;
8256218822Sdim  if (inst.operands[i].immisreg)
825789857Sobrien    {
8258218822Sdim      constraint (is_pc, _("cannot use register index with PC-relative addressing"));
8259218822Sdim      constraint (is_t || is_d, _("cannot use register index with this instruction"));
8260218822Sdim      constraint (inst.operands[i].negative,
8261218822Sdim		  _("Thumb does not support negative register indexing"));
8262218822Sdim      constraint (inst.operands[i].postind,
8263218822Sdim		  _("Thumb does not support register post-indexing"));
8264218822Sdim      constraint (inst.operands[i].writeback,
8265218822Sdim		  _("Thumb does not support register indexing with writeback"));
8266218822Sdim      constraint (inst.operands[i].shifted && inst.operands[i].shift_kind != SHIFT_LSL,
8267218822Sdim		  _("Thumb supports only LSL in shifted register indexing"));
826889857Sobrien
8269218822Sdim      inst.instruction |= inst.operands[i].imm;
8270218822Sdim      if (inst.operands[i].shifted)
827189857Sobrien	{
8272218822Sdim	  constraint (inst.reloc.exp.X_op != O_constant,
8273218822Sdim		      _("expression too complex"));
8274218822Sdim	  constraint (inst.reloc.exp.X_add_number < 0
8275218822Sdim		      || inst.reloc.exp.X_add_number > 3,
8276218822Sdim		      _("shift out of range"));
8277218822Sdim	  inst.instruction |= inst.reloc.exp.X_add_number << 4;
8278218822Sdim	}
8279218822Sdim      inst.reloc.type = BFD_RELOC_UNUSED;
8280218822Sdim    }
8281218822Sdim  else if (inst.operands[i].preind)
8282218822Sdim    {
8283218822Sdim      constraint (is_pc && inst.operands[i].writeback,
8284218822Sdim		  _("cannot use writeback with PC-relative addressing"));
8285218822Sdim      constraint (is_t && inst.operands[i].writeback,
8286218822Sdim		  _("cannot use writeback with this instruction"));
828789857Sobrien
8288218822Sdim      if (is_d)
8289218822Sdim	{
8290218822Sdim	  inst.instruction |= 0x01000000;
8291218822Sdim	  if (inst.operands[i].writeback)
8292218822Sdim	    inst.instruction |= 0x00200000;
829389857Sobrien	}
829489857Sobrien      else
829589857Sobrien	{
8296218822Sdim	  inst.instruction |= 0x00000c00;
8297218822Sdim	  if (inst.operands[i].writeback)
8298218822Sdim	    inst.instruction |= 0x00000100;
829989857Sobrien	}
8300218822Sdim      inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_IMM;
8301218822Sdim    }
8302218822Sdim  else if (inst.operands[i].postind)
8303218822Sdim    {
8304218822Sdim      assert (inst.operands[i].writeback);
8305218822Sdim      constraint (is_pc, _("cannot use post-indexing with PC-relative addressing"));
8306218822Sdim      constraint (is_t, _("cannot use post-indexing with this instruction"));
830789857Sobrien
8308218822Sdim      if (is_d)
8309218822Sdim	inst.instruction |= 0x00200000;
8310218822Sdim      else
8311218822Sdim	inst.instruction |= 0x00000900;
8312218822Sdim      inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_IMM;
8313218822Sdim    }
8314218822Sdim  else /* unindexed - only for coprocessor */
8315218822Sdim    inst.error = _("instruction does not accept unindexed addressing");
8316218822Sdim}
831789857Sobrien
8318218822Sdim/* Table of Thumb instructions which exist in both 16- and 32-bit
8319218822Sdim   encodings (the latter only in post-V6T2 cores).  The index is the
8320218822Sdim   value used in the insns table below.  When there is more than one
8321218822Sdim   possible 16-bit encoding for the instruction, this table always
8322218822Sdim   holds variant (1).
8323218822Sdim   Also contains several pseudo-instructions used during relaxation.  */
8324218822Sdim#define T16_32_TAB				\
8325218822Sdim  X(adc,   4140, eb400000),			\
8326218822Sdim  X(adcs,  4140, eb500000),			\
8327218822Sdim  X(add,   1c00, eb000000),			\
8328218822Sdim  X(adds,  1c00, eb100000),			\
8329218822Sdim  X(addi,  0000, f1000000),			\
8330218822Sdim  X(addis, 0000, f1100000),			\
8331218822Sdim  X(add_pc,000f, f20f0000),			\
8332218822Sdim  X(add_sp,000d, f10d0000),			\
8333218822Sdim  X(adr,   000f, f20f0000),			\
8334218822Sdim  X(and,   4000, ea000000),			\
8335218822Sdim  X(ands,  4000, ea100000),			\
8336218822Sdim  X(asr,   1000, fa40f000),			\
8337218822Sdim  X(asrs,  1000, fa50f000),			\
8338218822Sdim  X(b,     e000, f000b000),			\
8339218822Sdim  X(bcond, d000, f0008000),			\
8340218822Sdim  X(bic,   4380, ea200000),			\
8341218822Sdim  X(bics,  4380, ea300000),			\
8342218822Sdim  X(cmn,   42c0, eb100f00),			\
8343218822Sdim  X(cmp,   2800, ebb00f00),			\
8344218822Sdim  X(cpsie, b660, f3af8400),			\
8345218822Sdim  X(cpsid, b670, f3af8600),			\
8346218822Sdim  X(cpy,   4600, ea4f0000),			\
8347218822Sdim  X(dec_sp,80dd, f1ad0d00),			\
8348218822Sdim  X(eor,   4040, ea800000),			\
8349218822Sdim  X(eors,  4040, ea900000),			\
8350218822Sdim  X(inc_sp,00dd, f10d0d00),			\
8351218822Sdim  X(ldmia, c800, e8900000),			\
8352218822Sdim  X(ldr,   6800, f8500000),			\
8353218822Sdim  X(ldrb,  7800, f8100000),			\
8354218822Sdim  X(ldrh,  8800, f8300000),			\
8355218822Sdim  X(ldrsb, 5600, f9100000),			\
8356218822Sdim  X(ldrsh, 5e00, f9300000),			\
8357218822Sdim  X(ldr_pc,4800, f85f0000),			\
8358218822Sdim  X(ldr_pc2,4800, f85f0000),			\
8359218822Sdim  X(ldr_sp,9800, f85d0000),			\
8360218822Sdim  X(lsl,   0000, fa00f000),			\
8361218822Sdim  X(lsls,  0000, fa10f000),			\
8362218822Sdim  X(lsr,   0800, fa20f000),			\
8363218822Sdim  X(lsrs,  0800, fa30f000),			\
8364218822Sdim  X(mov,   2000, ea4f0000),			\
8365218822Sdim  X(movs,  2000, ea5f0000),			\
8366218822Sdim  X(mul,   4340, fb00f000),                     \
8367218822Sdim  X(muls,  4340, ffffffff), /* no 32b muls */	\
8368218822Sdim  X(mvn,   43c0, ea6f0000),			\
8369218822Sdim  X(mvns,  43c0, ea7f0000),			\
8370218822Sdim  X(neg,   4240, f1c00000), /* rsb #0 */	\
8371218822Sdim  X(negs,  4240, f1d00000), /* rsbs #0 */	\
8372218822Sdim  X(orr,   4300, ea400000),			\
8373218822Sdim  X(orrs,  4300, ea500000),			\
8374218822Sdim  X(pop,   bc00, e8bd0000), /* ldmia sp!,... */	\
8375218822Sdim  X(push,  b400, e92d0000), /* stmdb sp!,... */	\
8376218822Sdim  X(rev,   ba00, fa90f080),			\
8377218822Sdim  X(rev16, ba40, fa90f090),			\
8378218822Sdim  X(revsh, bac0, fa90f0b0),			\
8379218822Sdim  X(ror,   41c0, fa60f000),			\
8380218822Sdim  X(rors,  41c0, fa70f000),			\
8381218822Sdim  X(sbc,   4180, eb600000),			\
8382218822Sdim  X(sbcs,  4180, eb700000),			\
8383218822Sdim  X(stmia, c000, e8800000),			\
8384218822Sdim  X(str,   6000, f8400000),			\
8385218822Sdim  X(strb,  7000, f8000000),			\
8386218822Sdim  X(strh,  8000, f8200000),			\
8387218822Sdim  X(str_sp,9000, f84d0000),			\
8388218822Sdim  X(sub,   1e00, eba00000),			\
8389218822Sdim  X(subs,  1e00, ebb00000),			\
8390218822Sdim  X(subi,  8000, f1a00000),			\
8391218822Sdim  X(subis, 8000, f1b00000),			\
8392218822Sdim  X(sxtb,  b240, fa4ff080),			\
8393218822Sdim  X(sxth,  b200, fa0ff080),			\
8394218822Sdim  X(tst,   4200, ea100f00),			\
8395218822Sdim  X(uxtb,  b2c0, fa5ff080),			\
8396218822Sdim  X(uxth,  b280, fa1ff080),			\
8397218822Sdim  X(nop,   bf00, f3af8000),			\
8398218822Sdim  X(yield, bf10, f3af8001),			\
8399218822Sdim  X(wfe,   bf20, f3af8002),			\
8400218822Sdim  X(wfi,   bf30, f3af8003),			\
8401218822Sdim  X(sev,   bf40, f3af9004), /* typo, 8004? */
840289857Sobrien
8403218822Sdim/* To catch errors in encoding functions, the codes are all offset by
8404218822Sdim   0xF800, putting them in one of the 32-bit prefix ranges, ergo undefined
8405218822Sdim   as 16-bit instructions.  */
8406218822Sdim#define X(a,b,c) T_MNEM_##a
8407218822Sdimenum t16_32_codes { T16_32_OFFSET = 0xF7FF, T16_32_TAB };
8408218822Sdim#undef X
840989857Sobrien
8410218822Sdim#define X(a,b,c) 0x##b
8411218822Sdimstatic const unsigned short thumb_op16[] = { T16_32_TAB };
8412218822Sdim#define THUMB_OP16(n) (thumb_op16[(n) - (T16_32_OFFSET + 1)])
8413218822Sdim#undef X
841489857Sobrien
8415218822Sdim#define X(a,b,c) 0x##c
8416218822Sdimstatic const unsigned int thumb_op32[] = { T16_32_TAB };
8417218822Sdim#define THUMB_OP32(n) (thumb_op32[(n) - (T16_32_OFFSET + 1)])
8418218822Sdim#define THUMB_SETS_FLAGS(n) (THUMB_OP32 (n) & 0x00100000)
8419218822Sdim#undef X
8420218822Sdim#undef T16_32_TAB
8421218822Sdim
8422218822Sdim/* Thumb instruction encoders, in alphabetical order.  */
8423218822Sdim
8424218822Sdim/* ADDW or SUBW.  */
842589857Sobrienstatic void
8426218822Sdimdo_t_add_sub_w (void)
842789857Sobrien{
8428218822Sdim  int Rd, Rn;
842989857Sobrien
8430218822Sdim  Rd = inst.operands[0].reg;
8431218822Sdim  Rn = inst.operands[1].reg;
843289857Sobrien
8433218822Sdim  constraint (Rd == 15, _("PC not allowed as destination"));
8434218822Sdim  inst.instruction |= (Rn << 16) | (Rd << 8);
8435218822Sdim  inst.reloc.type = BFD_RELOC_ARM_T32_IMM12;
8436218822Sdim}
843789857Sobrien
8438218822Sdim/* Parse an add or subtract instruction.  We get here with inst.instruction
8439218822Sdim   equalling any of THUMB_OPCODE_add, adds, sub, or subs.  */
844089857Sobrien
8441218822Sdimstatic void
8442218822Sdimdo_t_add_sub (void)
8443218822Sdim{
8444218822Sdim  int Rd, Rs, Rn;
844589857Sobrien
8446218822Sdim  Rd = inst.operands[0].reg;
8447218822Sdim  Rs = (inst.operands[1].present
8448218822Sdim	? inst.operands[1].reg    /* Rd, Rs, foo */
8449218822Sdim	: inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
845089857Sobrien
8451218822Sdim  if (unified_syntax)
8452218822Sdim    {
8453218822Sdim      bfd_boolean flags;
8454218822Sdim      bfd_boolean narrow;
8455218822Sdim      int opcode;
845689857Sobrien
8457218822Sdim      flags = (inst.instruction == T_MNEM_adds
8458218822Sdim	       || inst.instruction == T_MNEM_subs);
8459218822Sdim      if (flags)
8460218822Sdim	narrow = (current_it_mask == 0);
8461218822Sdim      else
8462218822Sdim	narrow = (current_it_mask != 0);
8463218822Sdim      if (!inst.operands[2].isreg)
846460484Sobrien	{
8465218822Sdim	  int add;
846677298Sobrien
8467218822Sdim	  add = (inst.instruction == T_MNEM_add
8468218822Sdim		 || inst.instruction == T_MNEM_adds);
8469218822Sdim	  opcode = 0;
8470218822Sdim	  if (inst.size_req != 4)
847160484Sobrien	    {
8472218822Sdim	      /* Attempt to use a narrow opcode, with relaxation if
8473218822Sdim	         appropriate.  */
8474218822Sdim	      if (Rd == REG_SP && Rs == REG_SP && !flags)
8475218822Sdim		opcode = add ? T_MNEM_inc_sp : T_MNEM_dec_sp;
8476218822Sdim	      else if (Rd <= 7 && Rs == REG_SP && add && !flags)
8477218822Sdim		opcode = T_MNEM_add_sp;
8478218822Sdim	      else if (Rd <= 7 && Rs == REG_PC && add && !flags)
8479218822Sdim		opcode = T_MNEM_add_pc;
8480218822Sdim	      else if (Rd <= 7 && Rs <= 7 && narrow)
8481218822Sdim		{
8482218822Sdim		  if (flags)
8483218822Sdim		    opcode = add ? T_MNEM_addis : T_MNEM_subis;
8484218822Sdim		  else
8485218822Sdim		    opcode = add ? T_MNEM_addi : T_MNEM_subi;
8486218822Sdim		}
8487218822Sdim	      if (opcode)
8488218822Sdim		{
8489218822Sdim		  inst.instruction = THUMB_OP16(opcode);
8490218822Sdim		  inst.instruction |= (Rd << 4) | Rs;
8491218822Sdim		  inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
8492218822Sdim		  if (inst.size_req != 2)
8493218822Sdim		    inst.relax = opcode;
8494218822Sdim		}
8495218822Sdim	      else
8496218822Sdim		constraint (inst.size_req == 2, BAD_HIREG);
849760484Sobrien	    }
8498218822Sdim	  if (inst.size_req == 4
8499218822Sdim	      || (inst.size_req != 2 && !opcode))
850060484Sobrien	    {
8501218822Sdim	      if (Rd == REG_PC)
850277298Sobrien		{
8503218822Sdim		  constraint (Rs != REG_LR || inst.instruction != T_MNEM_subs,
8504218822Sdim			     _("only SUBS PC, LR, #const allowed"));
8505218822Sdim		  constraint (inst.reloc.exp.X_op != O_constant,
8506218822Sdim			      _("expression too complex"));
8507218822Sdim		  constraint (inst.reloc.exp.X_add_number < 0
8508218822Sdim			      || inst.reloc.exp.X_add_number > 0xff,
8509218822Sdim			     _("immediate value out of range"));
8510218822Sdim		  inst.instruction = T2_SUBS_PC_LR
8511218822Sdim				     | inst.reloc.exp.X_add_number;
8512218822Sdim		  inst.reloc.type = BFD_RELOC_UNUSED;
8513218822Sdim		  return;
851477298Sobrien		}
8515218822Sdim	      else if (Rs == REG_PC)
8516218822Sdim		{
8517218822Sdim		  /* Always use addw/subw.  */
8518218822Sdim		  inst.instruction = add ? 0xf20f0000 : 0xf2af0000;
8519218822Sdim		  inst.reloc.type = BFD_RELOC_ARM_T32_IMM12;
8520218822Sdim		}
8521218822Sdim	      else
8522218822Sdim		{
8523218822Sdim		  inst.instruction = THUMB_OP32 (inst.instruction);
8524218822Sdim		  inst.instruction = (inst.instruction & 0xe1ffffff)
8525218822Sdim				     | 0x10000000;
8526218822Sdim		  if (flags)
8527218822Sdim		    inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
8528218822Sdim		  else
8529218822Sdim		    inst.reloc.type = BFD_RELOC_ARM_T32_ADD_IMM;
8530218822Sdim		}
8531218822Sdim	      inst.instruction |= Rd << 8;
8532218822Sdim	      inst.instruction |= Rs << 16;
853360484Sobrien	    }
853460484Sobrien	}
853560484Sobrien      else
853660484Sobrien	{
8537218822Sdim	  Rn = inst.operands[2].reg;
8538218822Sdim	  /* See if we can do this with a 16-bit instruction.  */
8539218822Sdim	  if (!inst.operands[2].shifted && inst.size_req != 4)
854060484Sobrien	    {
8541218822Sdim	      if (Rd > 7 || Rs > 7 || Rn > 7)
8542218822Sdim		narrow = FALSE;
854360484Sobrien
8544218822Sdim	      if (narrow)
8545218822Sdim		{
8546218822Sdim		  inst.instruction = ((inst.instruction == T_MNEM_adds
8547218822Sdim				       || inst.instruction == T_MNEM_add)
8548218822Sdim				      ? T_OPCODE_ADD_R3
8549218822Sdim				      : T_OPCODE_SUB_R3);
8550218822Sdim		  inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
8551218822Sdim		  return;
8552218822Sdim		}
855360484Sobrien
8554218822Sdim	      if (inst.instruction == T_MNEM_add)
8555218822Sdim		{
8556218822Sdim		  if (Rd == Rs)
8557218822Sdim		    {
8558218822Sdim		      inst.instruction = T_OPCODE_ADD_HI;
8559218822Sdim		      inst.instruction |= (Rd & 8) << 4;
8560218822Sdim		      inst.instruction |= (Rd & 7);
8561218822Sdim		      inst.instruction |= Rn << 3;
8562218822Sdim		      return;
8563218822Sdim		    }
8564218822Sdim		  /* ... because addition is commutative! */
8565218822Sdim		  else if (Rd == Rn)
8566218822Sdim		    {
8567218822Sdim		      inst.instruction = T_OPCODE_ADD_HI;
8568218822Sdim		      inst.instruction |= (Rd & 8) << 4;
8569218822Sdim		      inst.instruction |= (Rd & 7);
8570218822Sdim		      inst.instruction |= Rs << 3;
8571218822Sdim		      return;
8572218822Sdim		    }
8573218822Sdim		}
857460484Sobrien	    }
8575218822Sdim	  /* If we get here, it can't be done in 16 bits.  */
8576218822Sdim	  constraint (inst.operands[2].shifted && inst.operands[2].immisreg,
8577218822Sdim		      _("shift must be constant"));
8578218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
8579218822Sdim	  inst.instruction |= Rd << 8;
8580218822Sdim	  inst.instruction |= Rs << 16;
8581218822Sdim	  encode_thumb32_shifted_operand (2);
858260484Sobrien	}
858360484Sobrien    }
8584218822Sdim  else
858560484Sobrien    {
8586218822Sdim      constraint (inst.instruction == T_MNEM_adds
8587218822Sdim		  || inst.instruction == T_MNEM_subs,
8588218822Sdim		  BAD_THUMB32);
8589218822Sdim
8590218822Sdim      if (!inst.operands[2].isreg) /* Rd, Rs, #imm */
859189857Sobrien	{
8592218822Sdim	  constraint ((Rd > 7 && (Rd != REG_SP || Rs != REG_SP))
8593218822Sdim		      || (Rs > 7 && Rs != REG_SP && Rs != REG_PC),
8594218822Sdim		      BAD_HIREG);
8595218822Sdim
8596218822Sdim	  inst.instruction = (inst.instruction == T_MNEM_add
8597218822Sdim			      ? 0x0000 : 0x8000);
8598218822Sdim	  inst.instruction |= (Rd << 4) | Rs;
8599218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
860089857Sobrien	  return;
860189857Sobrien	}
860289857Sobrien
8603218822Sdim      Rn = inst.operands[2].reg;
8604218822Sdim      constraint (inst.operands[2].shifted, _("unshifted register required"));
860560484Sobrien
8606218822Sdim      /* We now have Rd, Rs, and Rn set to registers.  */
8607218822Sdim      if (Rd > 7 || Rs > 7 || Rn > 7)
860860484Sobrien	{
8609218822Sdim	  /* Can't do this for SUB.	 */
8610218822Sdim	  constraint (inst.instruction == T_MNEM_sub, BAD_HIREG);
8611218822Sdim	  inst.instruction = T_OPCODE_ADD_HI;
8612218822Sdim	  inst.instruction |= (Rd & 8) << 4;
8613218822Sdim	  inst.instruction |= (Rd & 7);
8614218822Sdim	  if (Rs == Rd)
8615218822Sdim	    inst.instruction |= Rn << 3;
8616218822Sdim	  else if (Rn == Rd)
8617218822Sdim	    inst.instruction |= Rs << 3;
8618218822Sdim	  else
8619218822Sdim	    constraint (1, _("dest must overlap one source register"));
862060484Sobrien	}
8621218822Sdim      else
862260484Sobrien	{
8623218822Sdim	  inst.instruction = (inst.instruction == T_MNEM_add
8624218822Sdim			      ? T_OPCODE_ADD_R3 : T_OPCODE_SUB_R3);
8625218822Sdim	  inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
862660484Sobrien	}
8627218822Sdim    }
8628218822Sdim}
862980016Sobrien
8630218822Sdimstatic void
8631218822Sdimdo_t_adr (void)
8632218822Sdim{
8633218822Sdim  if (unified_syntax && inst.size_req == 0 && inst.operands[0].reg <= 7)
8634218822Sdim    {
8635218822Sdim      /* Defer to section relaxation.  */
8636218822Sdim      inst.relax = inst.instruction;
8637218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
8638218822Sdim      inst.instruction |= inst.operands[0].reg << 4;
8639218822Sdim    }
8640218822Sdim  else if (unified_syntax && inst.size_req != 2)
8641218822Sdim    {
8642218822Sdim      /* Generate a 32-bit opcode.  */
8643218822Sdim      inst.instruction = THUMB_OP32 (inst.instruction);
8644218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
8645218822Sdim      inst.reloc.type = BFD_RELOC_ARM_T32_ADD_PC12;
864680016Sobrien      inst.reloc.pc_rel = 1;
864760484Sobrien    }
864860484Sobrien  else
864960484Sobrien    {
8650218822Sdim      /* Generate a 16-bit opcode.  */
8651218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
8652218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
8653218822Sdim      inst.reloc.exp.X_add_number -= 4; /* PC relative adjust.  */
8654218822Sdim      inst.reloc.pc_rel = 1;
865560484Sobrien
8656218822Sdim      inst.instruction |= inst.operands[0].reg << 4;
865760484Sobrien    }
865860484Sobrien}
865960484Sobrien
8660218822Sdim/* Arithmetic instructions for which there is just one 16-bit
8661218822Sdim   instruction encoding, and it allows only two low registers.
8662218822Sdim   For maximal compatibility with ARM syntax, we allow three register
8663218822Sdim   operands even when Thumb-32 instructions are not available, as long
8664218822Sdim   as the first two are identical.  For instance, both "sbc r0,r1" and
8665218822Sdim   "sbc r0,r0,r1" are allowed.  */
8666218822Sdimstatic void
8667218822Sdimdo_t_arit3 (void)
866860484Sobrien{
8669218822Sdim  int Rd, Rs, Rn;
867060484Sobrien
8671218822Sdim  Rd = inst.operands[0].reg;
8672218822Sdim  Rs = (inst.operands[1].present
8673218822Sdim	? inst.operands[1].reg    /* Rd, Rs, foo */
8674218822Sdim	: inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
8675218822Sdim  Rn = inst.operands[2].reg;
8676218822Sdim
8677218822Sdim  if (unified_syntax)
867860484Sobrien    {
8679218822Sdim      if (!inst.operands[2].isreg)
868060484Sobrien	{
8681218822Sdim	  /* For an immediate, we always generate a 32-bit opcode;
8682218822Sdim	     section relaxation will shrink it later if possible.  */
8683218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
8684218822Sdim	  inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
8685218822Sdim	  inst.instruction |= Rd << 8;
8686218822Sdim	  inst.instruction |= Rs << 16;
8687218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
8688218822Sdim	}
8689218822Sdim      else
8690218822Sdim	{
8691218822Sdim	  bfd_boolean narrow;
869277298Sobrien
8693218822Sdim	  /* See if we can do this with a 16-bit instruction.  */
8694218822Sdim	  if (THUMB_SETS_FLAGS (inst.instruction))
8695218822Sdim	    narrow = current_it_mask == 0;
8696218822Sdim	  else
8697218822Sdim	    narrow = current_it_mask != 0;
869877298Sobrien
8699218822Sdim	  if (Rd > 7 || Rn > 7 || Rs > 7)
8700218822Sdim	    narrow = FALSE;
8701218822Sdim	  if (inst.operands[2].shifted)
8702218822Sdim	    narrow = FALSE;
8703218822Sdim	  if (inst.size_req == 4)
8704218822Sdim	    narrow = FALSE;
870560484Sobrien
8706218822Sdim	  if (narrow
8707218822Sdim	      && Rd == Rs)
8708218822Sdim	    {
8709218822Sdim	      inst.instruction = THUMB_OP16 (inst.instruction);
8710218822Sdim	      inst.instruction |= Rd;
8711218822Sdim	      inst.instruction |= Rn << 3;
8712218822Sdim	      return;
8713218822Sdim	    }
871477298Sobrien
8715218822Sdim	  /* If we get here, it can't be done in 16 bits.  */
8716218822Sdim	  constraint (inst.operands[2].shifted
8717218822Sdim		      && inst.operands[2].immisreg,
8718218822Sdim		      _("shift must be constant"));
8719218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
8720218822Sdim	  inst.instruction |= Rd << 8;
8721218822Sdim	  inst.instruction |= Rs << 16;
8722218822Sdim	  encode_thumb32_shifted_operand (2);
8723218822Sdim	}
8724218822Sdim    }
8725218822Sdim  else
8726218822Sdim    {
8727218822Sdim      /* On its face this is a lie - the instruction does set the
8728218822Sdim	 flags.  However, the only supported mnemonic in this mode
8729218822Sdim	 says it doesn't.  */
8730218822Sdim      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
873177298Sobrien
8732218822Sdim      constraint (!inst.operands[2].isreg || inst.operands[2].shifted,
8733218822Sdim		  _("unshifted register required"));
8734218822Sdim      constraint (Rd > 7 || Rs > 7 || Rn > 7, BAD_HIREG);
8735218822Sdim      constraint (Rd != Rs,
8736218822Sdim		  _("dest and source1 must be the same register"));
873760484Sobrien
8738218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
8739218822Sdim      inst.instruction |= Rd;
8740218822Sdim      inst.instruction |= Rn << 3;
8741218822Sdim    }
8742218822Sdim}
874360484Sobrien
8744218822Sdim/* Similarly, but for instructions where the arithmetic operation is
8745218822Sdim   commutative, so we can allow either of them to be different from
8746218822Sdim   the destination operand in a 16-bit instruction.  For instance, all
8747218822Sdim   three of "adc r0,r1", "adc r0,r0,r1", and "adc r0,r1,r0" are
8748218822Sdim   accepted.  */
8749218822Sdimstatic void
8750218822Sdimdo_t_arit3c (void)
8751218822Sdim{
8752218822Sdim  int Rd, Rs, Rn;
875360484Sobrien
8754218822Sdim  Rd = inst.operands[0].reg;
8755218822Sdim  Rs = (inst.operands[1].present
8756218822Sdim	? inst.operands[1].reg    /* Rd, Rs, foo */
8757218822Sdim	: inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
8758218822Sdim  Rn = inst.operands[2].reg;
875960484Sobrien
8760218822Sdim  if (unified_syntax)
8761218822Sdim    {
8762218822Sdim      if (!inst.operands[2].isreg)
8763218822Sdim	{
8764218822Sdim	  /* For an immediate, we always generate a 32-bit opcode;
8765218822Sdim	     section relaxation will shrink it later if possible.  */
8766218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
8767218822Sdim	  inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
8768218822Sdim	  inst.instruction |= Rd << 8;
8769218822Sdim	  inst.instruction |= Rs << 16;
8770218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
877160484Sobrien	}
877260484Sobrien      else
877360484Sobrien	{
8774218822Sdim	  bfd_boolean narrow;
877560484Sobrien
8776218822Sdim	  /* See if we can do this with a 16-bit instruction.  */
8777218822Sdim	  if (THUMB_SETS_FLAGS (inst.instruction))
8778218822Sdim	    narrow = current_it_mask == 0;
8779218822Sdim	  else
8780218822Sdim	    narrow = current_it_mask != 0;
878160484Sobrien
8782218822Sdim	  if (Rd > 7 || Rn > 7 || Rs > 7)
8783218822Sdim	    narrow = FALSE;
8784218822Sdim	  if (inst.operands[2].shifted)
8785218822Sdim	    narrow = FALSE;
8786218822Sdim	  if (inst.size_req == 4)
8787218822Sdim	    narrow = FALSE;
8788218822Sdim
8789218822Sdim	  if (narrow)
879060484Sobrien	    {
8791218822Sdim	      if (Rd == Rs)
879260484Sobrien		{
8793218822Sdim		  inst.instruction = THUMB_OP16 (inst.instruction);
8794218822Sdim		  inst.instruction |= Rd;
8795218822Sdim		  inst.instruction |= Rn << 3;
8796218822Sdim		  return;
879760484Sobrien		}
8798218822Sdim	      if (Rd == Rn)
879960484Sobrien		{
8800218822Sdim		  inst.instruction = THUMB_OP16 (inst.instruction);
8801218822Sdim		  inst.instruction |= Rd;
8802218822Sdim		  inst.instruction |= Rs << 3;
8803218822Sdim		  return;
880460484Sobrien		}
880560484Sobrien	    }
880660484Sobrien
8807218822Sdim	  /* If we get here, it can't be done in 16 bits.  */
8808218822Sdim	  constraint (inst.operands[2].shifted
8809218822Sdim		      && inst.operands[2].immisreg,
8810218822Sdim		      _("shift must be constant"));
8811218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
8812218822Sdim	  inst.instruction |= Rd << 8;
8813218822Sdim	  inst.instruction |= Rs << 16;
8814218822Sdim	  encode_thumb32_shifted_operand (2);
881560484Sobrien	}
8816218822Sdim    }
8817218822Sdim  else
8818218822Sdim    {
8819218822Sdim      /* On its face this is a lie - the instruction does set the
8820218822Sdim	 flags.  However, the only supported mnemonic in this mode
8821218822Sdim	 says it doesn't.  */
8822218822Sdim      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
882360484Sobrien
8824218822Sdim      constraint (!inst.operands[2].isreg || inst.operands[2].shifted,
8825218822Sdim		  _("unshifted register required"));
8826218822Sdim      constraint (Rd > 7 || Rs > 7 || Rn > 7, BAD_HIREG);
882760484Sobrien
8828218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
8829218822Sdim      inst.instruction |= Rd;
8830218822Sdim
8831218822Sdim      if (Rd == Rs)
8832218822Sdim	inst.instruction |= Rn << 3;
8833218822Sdim      else if (Rd == Rn)
8834218822Sdim	inst.instruction |= Rs << 3;
8835218822Sdim      else
8836218822Sdim	constraint (1, _("dest must overlap one source register"));
883777298Sobrien    }
8838218822Sdim}
883960484Sobrien
8840218822Sdimstatic void
8841218822Sdimdo_t_barrier (void)
8842218822Sdim{
8843218822Sdim  if (inst.operands[0].present)
8844218822Sdim    {
8845218822Sdim      constraint ((inst.instruction & 0xf0) != 0x40
8846218822Sdim		  && inst.operands[0].imm != 0xf,
8847218822Sdim		  "bad barrier type");
8848218822Sdim      inst.instruction |= inst.operands[0].imm;
8849218822Sdim    }
8850218822Sdim  else
8851218822Sdim    inst.instruction |= 0xf;
885260484Sobrien}
885360484Sobrien
885460484Sobrienstatic void
8855218822Sdimdo_t_bfc (void)
885660484Sobrien{
8857218822Sdim  unsigned int msb = inst.operands[1].imm + inst.operands[2].imm;
8858218822Sdim  constraint (msb > 32, _("bit-field extends past end of register"));
8859218822Sdim  /* The instruction encoding stores the LSB and MSB,
8860218822Sdim     not the LSB and width.  */
8861218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
8862218822Sdim  inst.instruction |= (inst.operands[1].imm & 0x1c) << 10;
8863218822Sdim  inst.instruction |= (inst.operands[1].imm & 0x03) << 6;
8864218822Sdim  inst.instruction |= msb - 1;
8865218822Sdim}
886660484Sobrien
8867218822Sdimstatic void
8868218822Sdimdo_t_bfi (void)
8869218822Sdim{
8870218822Sdim  unsigned int msb;
887160484Sobrien
8872218822Sdim  /* #0 in second position is alternative syntax for bfc, which is
8873218822Sdim     the same instruction but with REG_PC in the Rm field.  */
8874218822Sdim  if (!inst.operands[1].isreg)
8875218822Sdim    inst.operands[1].reg = REG_PC;
887660484Sobrien
8877218822Sdim  msb = inst.operands[2].imm + inst.operands[3].imm;
8878218822Sdim  constraint (msb > 32, _("bit-field extends past end of register"));
8879218822Sdim  /* The instruction encoding stores the LSB and MSB,
8880218822Sdim     not the LSB and width.  */
8881218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
8882218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
8883218822Sdim  inst.instruction |= (inst.operands[2].imm & 0x1c) << 10;
8884218822Sdim  inst.instruction |= (inst.operands[2].imm & 0x03) << 6;
8885218822Sdim  inst.instruction |= msb - 1;
8886218822Sdim}
888760484Sobrien
8888218822Sdimstatic void
8889218822Sdimdo_t_bfx (void)
8890218822Sdim{
8891218822Sdim  constraint (inst.operands[2].imm + inst.operands[3].imm > 32,
8892218822Sdim	      _("bit-field extends past end of register"));
8893218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
8894218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
8895218822Sdim  inst.instruction |= (inst.operands[2].imm & 0x1c) << 10;
8896218822Sdim  inst.instruction |= (inst.operands[2].imm & 0x03) << 6;
8897218822Sdim  inst.instruction |= inst.operands[3].imm - 1;
8898218822Sdim}
889960484Sobrien
8900218822Sdim/* ARM V5 Thumb BLX (argument parse)
8901218822Sdim	BLX <target_addr>	which is BLX(1)
8902218822Sdim	BLX <Rm>		which is BLX(2)
8903218822Sdim   Unfortunately, there are two different opcodes for this mnemonic.
8904218822Sdim   So, the insns[].value is not used, and the code here zaps values
8905218822Sdim	into inst.instruction.
890660484Sobrien
8907218822Sdim   ??? How to take advantage of the additional two bits of displacement
8908218822Sdim   available in Thumb32 mode?  Need new relocation?  */
8909218822Sdim
8910218822Sdimstatic void
8911218822Sdimdo_t_blx (void)
8912218822Sdim{
8913218822Sdim  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
8914218822Sdim  if (inst.operands[0].isreg)
8915218822Sdim    /* We have a register, so this is BLX(2).  */
8916218822Sdim    inst.instruction |= inst.operands[0].reg << 3;
8917218822Sdim  else
891860484Sobrien    {
8919218822Sdim      /* No register.  This must be BLX(1).  */
8920218822Sdim      inst.instruction = 0xf000e800;
8921218822Sdim#ifdef OBJ_ELF
8922218822Sdim      if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4)
8923218822Sdim	inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH23;
8924218822Sdim      else
8925218822Sdim#endif
8926218822Sdim	inst.reloc.type = BFD_RELOC_THUMB_PCREL_BLX;
8927218822Sdim      inst.reloc.pc_rel = 1;
892860484Sobrien    }
8929218822Sdim}
893060484Sobrien
8931218822Sdimstatic void
8932218822Sdimdo_t_branch (void)
8933218822Sdim{
8934218822Sdim  int opcode;
8935218822Sdim  int cond;
8936218822Sdim
8937218822Sdim  if (current_it_mask)
893860484Sobrien    {
8939218822Sdim      /* Conditional branches inside IT blocks are encoded as unconditional
8940218822Sdim         branches.  */
8941218822Sdim      cond = COND_ALWAYS;
8942218822Sdim      /* A branch must be the last instruction in an IT block.  */
8943218822Sdim      constraint (current_it_mask != 0x10, BAD_BRANCH);
894460484Sobrien    }
8945218822Sdim  else
8946218822Sdim    cond = inst.cond;
894760484Sobrien
8948218822Sdim  if (cond != COND_ALWAYS)
8949218822Sdim    opcode = T_MNEM_bcond;
8950218822Sdim  else
8951218822Sdim    opcode = inst.instruction;
8952218822Sdim
8953218822Sdim  if (unified_syntax && inst.size_req == 4)
8954130561Sobrien    {
8955218822Sdim      inst.instruction = THUMB_OP32(opcode);
8956218822Sdim      if (cond == COND_ALWAYS)
8957218822Sdim	inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH25;
8958218822Sdim      else
8959130561Sobrien	{
8960218822Sdim	  assert (cond != 0xF);
8961218822Sdim	  inst.instruction |= cond << 22;
8962218822Sdim	  inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH20;
8963130561Sobrien	}
8964218822Sdim    }
8965218822Sdim  else
8966218822Sdim    {
8967218822Sdim      inst.instruction = THUMB_OP16(opcode);
8968218822Sdim      if (cond == COND_ALWAYS)
8969218822Sdim	inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH12;
8970218822Sdim      else
8971130561Sobrien	{
8972218822Sdim	  inst.instruction |= cond << 8;
8973218822Sdim	  inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH9;
8974130561Sobrien	}
8975218822Sdim      /* Allow section relaxation.  */
8976218822Sdim      if (unified_syntax && inst.size_req != 2)
8977218822Sdim	inst.relax = opcode;
8978130561Sobrien    }
8979130561Sobrien
8980218822Sdim  inst.reloc.pc_rel = 1;
898160484Sobrien}
898260484Sobrien
898360484Sobrienstatic void
8984218822Sdimdo_t_bkpt (void)
898560484Sobrien{
8986218822Sdim  constraint (inst.cond != COND_ALWAYS,
8987218822Sdim	      _("instruction is always unconditional"));
8988218822Sdim  if (inst.operands[0].present)
8989218822Sdim    {
8990218822Sdim      constraint (inst.operands[0].imm > 255,
8991218822Sdim		  _("immediate value out of range"));
8992218822Sdim      inst.instruction |= inst.operands[0].imm;
8993218822Sdim    }
8994218822Sdim}
899577298Sobrien
8996218822Sdimstatic void
8997218822Sdimdo_t_branch23 (void)
8998218822Sdim{
8999218822Sdim  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
9000218822Sdim  inst.reloc.type   = BFD_RELOC_THUMB_PCREL_BRANCH23;
9001218822Sdim  inst.reloc.pc_rel = 1;
900260484Sobrien
9003218822Sdim  /* If the destination of the branch is a defined symbol which does not have
9004218822Sdim     the THUMB_FUNC attribute, then we must be calling a function which has
9005218822Sdim     the (interfacearm) attribute.  We look for the Thumb entry point to that
9006218822Sdim     function and change the branch to refer to that function instead.	*/
9007218822Sdim  if (	 inst.reloc.exp.X_op == O_symbol
9008218822Sdim      && inst.reloc.exp.X_add_symbol != NULL
9009218822Sdim      && S_IS_DEFINED (inst.reloc.exp.X_add_symbol)
9010218822Sdim      && ! THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol))
9011218822Sdim    inst.reloc.exp.X_add_symbol =
9012218822Sdim      find_real_start (inst.reloc.exp.X_add_symbol);
9013218822Sdim}
901460484Sobrien
9015218822Sdimstatic void
9016218822Sdimdo_t_bx (void)
9017218822Sdim{
9018218822Sdim  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
9019218822Sdim  inst.instruction |= inst.operands[0].reg << 3;
9020218822Sdim  /* ??? FIXME: Should add a hacky reloc here if reg is REG_PC.	 The reloc
9021218822Sdim     should cause the alignment to be checked once it is known.	 This is
9022218822Sdim     because BX PC only works if the instruction is word aligned.  */
902360484Sobrien}
902460484Sobrien
902560484Sobrienstatic void
9026218822Sdimdo_t_bxj (void)
902760484Sobrien{
9028218822Sdim  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
9029218822Sdim  if (inst.operands[0].reg == REG_PC)
9030218822Sdim    as_tsktsk (_("use of r15 in bxj is not really useful"));
903177298Sobrien
9032218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
9033218822Sdim}
903460484Sobrien
9035218822Sdimstatic void
9036218822Sdimdo_t_clz (void)
9037218822Sdim{
9038218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
9039218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
9040218822Sdim  inst.instruction |= inst.operands[1].reg;
9041218822Sdim}
904260484Sobrien
9043218822Sdimstatic void
9044218822Sdimdo_t_cps (void)
9045218822Sdim{
9046218822Sdim  constraint (current_it_mask, BAD_NOT_IT);
9047218822Sdim  inst.instruction |= inst.operands[0].imm;
9048218822Sdim}
904960484Sobrien
9050218822Sdimstatic void
9051218822Sdimdo_t_cpsi (void)
9052218822Sdim{
9053218822Sdim  constraint (current_it_mask, BAD_NOT_IT);
9054218822Sdim  if (unified_syntax
9055218822Sdim      && (inst.operands[1].present || inst.size_req == 4)
9056218822Sdim      && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6_notm))
905760484Sobrien    {
9058218822Sdim      unsigned int imod = (inst.instruction & 0x0030) >> 4;
9059218822Sdim      inst.instruction = 0xf3af8000;
9060218822Sdim      inst.instruction |= imod << 9;
9061218822Sdim      inst.instruction |= inst.operands[0].imm << 5;
9062218822Sdim      if (inst.operands[1].present)
9063218822Sdim	inst.instruction |= 0x100 | inst.operands[1].imm;
906460484Sobrien    }
9065218822Sdim  else
906660484Sobrien    {
9067218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1)
9068218822Sdim		  && (inst.operands[0].imm & 4),
9069218822Sdim		  _("selected processor does not support 'A' form "
9070218822Sdim		    "of this instruction"));
9071218822Sdim      constraint (inst.operands[1].present || inst.size_req == 4,
9072218822Sdim		  _("Thumb does not support the 2-argument "
9073218822Sdim		    "form of this instruction"));
9074218822Sdim      inst.instruction |= inst.operands[0].imm;
907560484Sobrien    }
9076218822Sdim}
907760484Sobrien
9078218822Sdim/* THUMB CPY instruction (argument parse).  */
907960484Sobrien
9080218822Sdimstatic void
9081218822Sdimdo_t_cpy (void)
9082218822Sdim{
9083218822Sdim  if (inst.size_req == 4)
908460484Sobrien    {
9085218822Sdim      inst.instruction = THUMB_OP32 (T_MNEM_mov);
9086218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
9087218822Sdim      inst.instruction |= inst.operands[1].reg;
908860484Sobrien    }
9089218822Sdim  else
909060484Sobrien    {
9091218822Sdim      inst.instruction |= (inst.operands[0].reg & 0x8) << 4;
9092218822Sdim      inst.instruction |= (inst.operands[0].reg & 0x7);
9093218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
909460484Sobrien    }
9095218822Sdim}
909660484Sobrien
9097218822Sdimstatic void
9098218822Sdimdo_t_cbz (void)
9099218822Sdim{
9100218822Sdim  constraint (current_it_mask, BAD_NOT_IT);
9101218822Sdim  constraint (inst.operands[0].reg > 7, BAD_HIREG);
9102218822Sdim  inst.instruction |= inst.operands[0].reg;
9103218822Sdim  inst.reloc.pc_rel = 1;
9104218822Sdim  inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH7;
910560484Sobrien}
910660484Sobrien
910760484Sobrienstatic void
9108218822Sdimdo_t_dbg (void)
910960484Sobrien{
9110218822Sdim  inst.instruction |= inst.operands[0].imm;
9111218822Sdim}
911277298Sobrien
9113218822Sdimstatic void
9114218822Sdimdo_t_div (void)
9115218822Sdim{
9116218822Sdim  if (!inst.operands[1].present)
9117218822Sdim    inst.operands[1].reg = inst.operands[0].reg;
9118218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
9119218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
9120218822Sdim  inst.instruction |= inst.operands[2].reg;
9121218822Sdim}
912277298Sobrien
9123218822Sdimstatic void
9124218822Sdimdo_t_hint (void)
9125218822Sdim{
9126218822Sdim  if (unified_syntax && inst.size_req == 4)
9127218822Sdim    inst.instruction = THUMB_OP32 (inst.instruction);
9128218822Sdim  else
9129218822Sdim    inst.instruction = THUMB_OP16 (inst.instruction);
913060484Sobrien}
913160484Sobrien
913260484Sobrienstatic void
9133218822Sdimdo_t_it (void)
913460484Sobrien{
9135218822Sdim  unsigned int cond = inst.operands[0].imm;
913660484Sobrien
9137218822Sdim  constraint (current_it_mask, BAD_NOT_IT);
9138218822Sdim  current_it_mask = (inst.instruction & 0xf) | 0x10;
9139218822Sdim  current_cc = cond;
914060484Sobrien
9141218822Sdim  /* If the condition is a negative condition, invert the mask.  */
9142218822Sdim  if ((cond & 0x1) == 0x0)
914360484Sobrien    {
9144218822Sdim      unsigned int mask = inst.instruction & 0x000f;
9145218822Sdim
9146218822Sdim      if ((mask & 0x7) == 0)
9147218822Sdim	/* no conversion needed */;
9148218822Sdim      else if ((mask & 0x3) == 0)
9149218822Sdim	mask ^= 0x8;
9150218822Sdim      else if ((mask & 0x1) == 0)
9151218822Sdim	mask ^= 0xC;
9152218822Sdim      else
9153218822Sdim	mask ^= 0xE;
9154218822Sdim
9155218822Sdim      inst.instruction &= 0xfff0;
9156218822Sdim      inst.instruction |= mask;
915760484Sobrien    }
915860484Sobrien
9159218822Sdim  inst.instruction |= cond << 4;
916060484Sobrien}
916160484Sobrien
9162218822Sdim/* Helper function used for both push/pop and ldm/stm.  */
916360484Sobrienstatic void
9164218822Sdimencode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback)
916560484Sobrien{
9166218822Sdim  bfd_boolean load;
916760484Sobrien
9168218822Sdim  load = (inst.instruction & (1 << 20)) != 0;
916960484Sobrien
9170218822Sdim  if (mask & (1 << 13))
9171218822Sdim    inst.error =  _("SP not allowed in register list");
9172218822Sdim  if (load)
917360484Sobrien    {
9174218822Sdim      if (mask & (1 << 14)
9175218822Sdim	  && mask & (1 << 15))
9176218822Sdim	inst.error = _("LR and PC should not both be in register list");
917760484Sobrien
9178218822Sdim      if ((mask & (1 << base)) != 0
9179218822Sdim	  && writeback)
9180218822Sdim	as_warn (_("base register should not be in register list "
9181218822Sdim		   "when written back"));
918260484Sobrien    }
9183218822Sdim  else
918460484Sobrien    {
9185218822Sdim      if (mask & (1 << 15))
9186218822Sdim	inst.error = _("PC not allowed in register list");
918760484Sobrien
9188218822Sdim      if (mask & (1 << base))
9189218822Sdim	as_warn (_("value stored for r%d is UNPREDICTABLE"), base);
919060484Sobrien    }
919160484Sobrien
9192218822Sdim  if ((mask & (mask - 1)) == 0)
919360484Sobrien    {
9194218822Sdim      /* Single register transfers implemented as str/ldr.  */
9195218822Sdim      if (writeback)
919660484Sobrien	{
9197218822Sdim	  if (inst.instruction & (1 << 23))
9198218822Sdim	    inst.instruction = 0x00000b04; /* ia! -> [base], #4 */
9199218822Sdim	  else
9200218822Sdim	    inst.instruction = 0x00000d04; /* db! -> [base, #-4]! */
920160484Sobrien	}
9202218822Sdim      else
9203218822Sdim	{
9204218822Sdim	  if (inst.instruction & (1 << 23))
9205218822Sdim	    inst.instruction = 0x00800000; /* ia -> [base] */
9206218822Sdim	  else
9207218822Sdim	    inst.instruction = 0x00000c04; /* db -> [base, #-4] */
9208218822Sdim	}
920960484Sobrien
9210218822Sdim      inst.instruction |= 0xf8400000;
9211218822Sdim      if (load)
9212218822Sdim	inst.instruction |= 0x00100000;
921360484Sobrien
9214218822Sdim      mask = ffs(mask) - 1;
9215218822Sdim      mask <<= 12;
921660484Sobrien    }
9217218822Sdim  else if (writeback)
9218218822Sdim    inst.instruction |= WRITE_BACK;
921960484Sobrien
9220218822Sdim  inst.instruction |= mask;
9221218822Sdim  inst.instruction |= base << 16;
922260484Sobrien}
922360484Sobrien
922460484Sobrienstatic void
9225218822Sdimdo_t_ldmstm (void)
922660484Sobrien{
9227218822Sdim  /* This really doesn't seem worth it.  */
9228218822Sdim  constraint (inst.reloc.type != BFD_RELOC_UNUSED,
9229218822Sdim	      _("expression too complex"));
9230218822Sdim  constraint (inst.operands[1].writeback,
9231218822Sdim	      _("Thumb load/store multiple does not support {reglist}^"));
923260484Sobrien
9233218822Sdim  if (unified_syntax)
923460484Sobrien    {
9235218822Sdim      bfd_boolean narrow;
9236218822Sdim      unsigned mask;
923760484Sobrien
9238218822Sdim      narrow = FALSE;
9239218822Sdim      /* See if we can use a 16-bit instruction.  */
9240218822Sdim      if (inst.instruction < 0xffff /* not ldmdb/stmdb */
9241218822Sdim	  && inst.size_req != 4
9242218822Sdim	  && !(inst.operands[1].imm & ~0xff))
9243218822Sdim	{
9244218822Sdim	  mask = 1 << inst.operands[0].reg;
924560484Sobrien
9246218822Sdim	  if (inst.operands[0].reg <= 7
9247218822Sdim	      && (inst.instruction == T_MNEM_stmia
9248218822Sdim		  ? inst.operands[0].writeback
9249218822Sdim		  : (inst.operands[0].writeback
9250218822Sdim		     == !(inst.operands[1].imm & mask))))
9251218822Sdim	    {
9252218822Sdim	      if (inst.instruction == T_MNEM_stmia
9253218822Sdim		  && (inst.operands[1].imm & mask)
9254218822Sdim		  && (inst.operands[1].imm & (mask - 1)))
9255218822Sdim		as_warn (_("value stored for r%d is UNPREDICTABLE"),
9256218822Sdim			 inst.operands[0].reg);
925760484Sobrien
9258218822Sdim	      inst.instruction = THUMB_OP16 (inst.instruction);
9259218822Sdim	      inst.instruction |= inst.operands[0].reg << 8;
9260218822Sdim	      inst.instruction |= inst.operands[1].imm;
9261218822Sdim	      narrow = TRUE;
9262218822Sdim	    }
9263218822Sdim	  else if (inst.operands[0] .reg == REG_SP
9264218822Sdim		   && inst.operands[0].writeback)
9265218822Sdim	    {
9266218822Sdim	      inst.instruction = THUMB_OP16 (inst.instruction == T_MNEM_stmia
9267218822Sdim					     ? T_MNEM_push : T_MNEM_pop);
9268218822Sdim	      inst.instruction |= inst.operands[1].imm;
9269218822Sdim	      narrow = TRUE;
9270218822Sdim	    }
9271218822Sdim	}
927260484Sobrien
9273218822Sdim      if (!narrow)
9274218822Sdim	{
9275218822Sdim	  if (inst.instruction < 0xffff)
9276218822Sdim	    inst.instruction = THUMB_OP32 (inst.instruction);
9277218822Sdim
9278218822Sdim	  encode_thumb2_ldmstm(inst.operands[0].reg, inst.operands[1].imm,
9279218822Sdim			       inst.operands[0].writeback);
9280218822Sdim	}
928160484Sobrien    }
9282218822Sdim  else
928360484Sobrien    {
9284218822Sdim      constraint (inst.operands[0].reg > 7
9285218822Sdim		  || (inst.operands[1].imm & ~0xff), BAD_HIREG);
9286218822Sdim      constraint (inst.instruction != T_MNEM_ldmia
9287218822Sdim		  && inst.instruction != T_MNEM_stmia,
9288218822Sdim		  _("Thumb-2 instruction only valid in unified syntax"));
9289218822Sdim      if (inst.instruction == T_MNEM_stmia)
929060484Sobrien	{
9291218822Sdim	  if (!inst.operands[0].writeback)
9292218822Sdim	    as_warn (_("this instruction will write back the base register"));
9293218822Sdim	  if ((inst.operands[1].imm & (1 << inst.operands[0].reg))
9294218822Sdim	      && (inst.operands[1].imm & ((1 << inst.operands[0].reg) - 1)))
9295218822Sdim	    as_warn (_("value stored for r%d is UNPREDICTABLE"),
9296218822Sdim		     inst.operands[0].reg);
929760484Sobrien	}
9298218822Sdim      else
9299218822Sdim	{
9300218822Sdim	  if (!inst.operands[0].writeback
9301218822Sdim	      && !(inst.operands[1].imm & (1 << inst.operands[0].reg)))
9302218822Sdim	    as_warn (_("this instruction will write back the base register"));
9303218822Sdim	  else if (inst.operands[0].writeback
9304218822Sdim		   && (inst.operands[1].imm & (1 << inst.operands[0].reg)))
9305218822Sdim	    as_warn (_("this instruction will not write back the base register"));
9306218822Sdim	}
9307218822Sdim
9308218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
9309218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
9310218822Sdim      inst.instruction |= inst.operands[1].imm;
931160484Sobrien    }
931260484Sobrien}
931360484Sobrien
931460484Sobrienstatic void
9315218822Sdimdo_t_ldrex (void)
931660484Sobrien{
9317218822Sdim  constraint (!inst.operands[1].isreg || !inst.operands[1].preind
9318218822Sdim	      || inst.operands[1].postind || inst.operands[1].writeback
9319218822Sdim	      || inst.operands[1].immisreg || inst.operands[1].shifted
9320218822Sdim	      || inst.operands[1].negative,
9321218822Sdim	      BAD_ADDR_MODE);
932260484Sobrien
9323218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9324218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
9325218822Sdim  inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_U8;
9326218822Sdim}
932760484Sobrien
9328218822Sdimstatic void
9329218822Sdimdo_t_ldrexd (void)
9330218822Sdim{
9331218822Sdim  if (!inst.operands[1].present)
933260484Sobrien    {
9333218822Sdim      constraint (inst.operands[0].reg == REG_LR,
9334218822Sdim		  _("r14 not allowed as first register "
9335218822Sdim		    "when second register is omitted"));
9336218822Sdim      inst.operands[1].reg = inst.operands[0].reg + 1;
933760484Sobrien    }
9338218822Sdim  constraint (inst.operands[0].reg == inst.operands[1].reg,
9339218822Sdim	      BAD_OVERLAP);
934060484Sobrien
9341218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9342218822Sdim  inst.instruction |= inst.operands[1].reg << 8;
9343218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
934460484Sobrien}
934560484Sobrien
934660484Sobrienstatic void
9347218822Sdimdo_t_ldst (void)
934860484Sobrien{
9349218822Sdim  unsigned long opcode;
9350218822Sdim  int Rn;
935160484Sobrien
9352218822Sdim  opcode = inst.instruction;
9353218822Sdim  if (unified_syntax)
935460484Sobrien    {
9355218822Sdim      if (!inst.operands[1].isreg)
9356218822Sdim	{
9357218822Sdim	  if (opcode <= 0xffff)
9358218822Sdim	    inst.instruction = THUMB_OP32 (opcode);
9359218822Sdim	  if (move_or_literal_pool (0, /*thumb_p=*/TRUE, /*mode_3=*/FALSE))
9360218822Sdim	    return;
9361218822Sdim	}
9362218822Sdim      if (inst.operands[1].isreg
9363218822Sdim	  && !inst.operands[1].writeback
9364218822Sdim	  && !inst.operands[1].shifted && !inst.operands[1].postind
9365218822Sdim	  && !inst.operands[1].negative && inst.operands[0].reg <= 7
9366218822Sdim	  && opcode <= 0xffff
9367218822Sdim	  && inst.size_req != 4)
9368218822Sdim	{
9369218822Sdim	  /* Insn may have a 16-bit form.  */
9370218822Sdim	  Rn = inst.operands[1].reg;
9371218822Sdim	  if (inst.operands[1].immisreg)
9372218822Sdim	    {
9373218822Sdim	      inst.instruction = THUMB_OP16 (opcode);
9374218822Sdim	      /* [Rn, Ri] */
9375218822Sdim	      if (Rn <= 7 && inst.operands[1].imm <= 7)
9376218822Sdim		goto op16;
9377218822Sdim	    }
9378218822Sdim	  else if ((Rn <= 7 && opcode != T_MNEM_ldrsh
9379218822Sdim		    && opcode != T_MNEM_ldrsb)
9380218822Sdim		   || ((Rn == REG_PC || Rn == REG_SP) && opcode == T_MNEM_ldr)
9381218822Sdim		   || (Rn == REG_SP && opcode == T_MNEM_str))
9382218822Sdim	    {
9383218822Sdim	      /* [Rn, #const] */
9384218822Sdim	      if (Rn > 7)
9385218822Sdim		{
9386218822Sdim		  if (Rn == REG_PC)
9387218822Sdim		    {
9388218822Sdim		      if (inst.reloc.pc_rel)
9389218822Sdim			opcode = T_MNEM_ldr_pc2;
9390218822Sdim		      else
9391218822Sdim			opcode = T_MNEM_ldr_pc;
9392218822Sdim		    }
9393218822Sdim		  else
9394218822Sdim		    {
9395218822Sdim		      if (opcode == T_MNEM_ldr)
9396218822Sdim			opcode = T_MNEM_ldr_sp;
9397218822Sdim		      else
9398218822Sdim			opcode = T_MNEM_str_sp;
9399218822Sdim		    }
9400218822Sdim		  inst.instruction = inst.operands[0].reg << 8;
9401218822Sdim		}
9402218822Sdim	      else
9403218822Sdim		{
9404218822Sdim		  inst.instruction = inst.operands[0].reg;
9405218822Sdim		  inst.instruction |= inst.operands[1].reg << 3;
9406218822Sdim		}
9407218822Sdim	      inst.instruction |= THUMB_OP16 (opcode);
9408218822Sdim	      if (inst.size_req == 2)
9409218822Sdim		inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
9410218822Sdim	      else
9411218822Sdim		inst.relax = opcode;
9412218822Sdim	      return;
9413218822Sdim	    }
9414218822Sdim	}
9415218822Sdim      /* Definitely a 32-bit variant.  */
9416218822Sdim      inst.instruction = THUMB_OP32 (opcode);
9417218822Sdim      inst.instruction |= inst.operands[0].reg << 12;
9418218822Sdim      encode_thumb32_addr_mode (1, /*is_t=*/FALSE, /*is_d=*/FALSE);
941960484Sobrien      return;
942060484Sobrien    }
942160484Sobrien
9422218822Sdim  constraint (inst.operands[0].reg > 7, BAD_HIREG);
9423218822Sdim
9424218822Sdim  if (inst.instruction == T_MNEM_ldrsh || inst.instruction == T_MNEM_ldrsb)
942560484Sobrien    {
9426218822Sdim      /* Only [Rn,Rm] is acceptable.  */
9427218822Sdim      constraint (inst.operands[1].reg > 7 || inst.operands[1].imm > 7, BAD_HIREG);
9428218822Sdim      constraint (!inst.operands[1].isreg || !inst.operands[1].immisreg
9429218822Sdim		  || inst.operands[1].postind || inst.operands[1].shifted
9430218822Sdim		  || inst.operands[1].negative,
9431218822Sdim		  _("Thumb does not support this addressing mode"));
9432218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
9433218822Sdim      goto op16;
9434218822Sdim    }
9435218822Sdim
9436218822Sdim  inst.instruction = THUMB_OP16 (inst.instruction);
9437218822Sdim  if (!inst.operands[1].isreg)
9438218822Sdim    if (move_or_literal_pool (0, /*thumb_p=*/TRUE, /*mode_3=*/FALSE))
943960484Sobrien      return;
944060484Sobrien
9441218822Sdim  constraint (!inst.operands[1].preind
9442218822Sdim	      || inst.operands[1].shifted
9443218822Sdim	      || inst.operands[1].writeback,
9444218822Sdim	      _("Thumb does not support this addressing mode"));
9445218822Sdim  if (inst.operands[1].reg == REG_PC || inst.operands[1].reg == REG_SP)
9446218822Sdim    {
9447218822Sdim      constraint (inst.instruction & 0x0600,
9448218822Sdim		  _("byte or halfword not valid for base register"));
9449218822Sdim      constraint (inst.operands[1].reg == REG_PC
9450218822Sdim		  && !(inst.instruction & THUMB_LOAD_BIT),
9451218822Sdim		  _("r15 based store not allowed"));
9452218822Sdim      constraint (inst.operands[1].immisreg,
9453218822Sdim		  _("invalid base register for register offset"));
945460484Sobrien
9455218822Sdim      if (inst.operands[1].reg == REG_PC)
9456218822Sdim	inst.instruction = T_OPCODE_LDR_PC;
9457218822Sdim      else if (inst.instruction & THUMB_LOAD_BIT)
9458218822Sdim	inst.instruction = T_OPCODE_LDR_SP;
9459218822Sdim      else
9460218822Sdim	inst.instruction = T_OPCODE_STR_SP;
946160484Sobrien
9462218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
9463218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
946460484Sobrien      return;
946560484Sobrien    }
946660484Sobrien
9467218822Sdim  constraint (inst.operands[1].reg > 7, BAD_HIREG);
9468218822Sdim  if (!inst.operands[1].immisreg)
946960484Sobrien    {
9470218822Sdim      /* Immediate offset.  */
9471218822Sdim      inst.instruction |= inst.operands[0].reg;
9472218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
9473218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
947460484Sobrien      return;
947560484Sobrien    }
947660484Sobrien
9477218822Sdim  /* Register offset.  */
9478218822Sdim  constraint (inst.operands[1].imm > 7, BAD_HIREG);
9479218822Sdim  constraint (inst.operands[1].negative,
9480218822Sdim	      _("Thumb does not support this addressing mode"));
9481218822Sdim
9482218822Sdim op16:
9483218822Sdim  switch (inst.instruction)
948460484Sobrien    {
9485218822Sdim    case T_OPCODE_STR_IW: inst.instruction = T_OPCODE_STR_RW; break;
9486218822Sdim    case T_OPCODE_STR_IH: inst.instruction = T_OPCODE_STR_RH; break;
9487218822Sdim    case T_OPCODE_STR_IB: inst.instruction = T_OPCODE_STR_RB; break;
9488218822Sdim    case T_OPCODE_LDR_IW: inst.instruction = T_OPCODE_LDR_RW; break;
9489218822Sdim    case T_OPCODE_LDR_IH: inst.instruction = T_OPCODE_LDR_RH; break;
9490218822Sdim    case T_OPCODE_LDR_IB: inst.instruction = T_OPCODE_LDR_RB; break;
9491218822Sdim    case 0x5600 /* ldrsb */:
9492218822Sdim    case 0x5e00 /* ldrsh */: break;
9493218822Sdim    default: abort ();
949460484Sobrien    }
949560484Sobrien
9496218822Sdim  inst.instruction |= inst.operands[0].reg;
9497218822Sdim  inst.instruction |= inst.operands[1].reg << 3;
9498218822Sdim  inst.instruction |= inst.operands[1].imm << 6;
9499218822Sdim}
950060484Sobrien
9501218822Sdimstatic void
9502218822Sdimdo_t_ldstd (void)
9503218822Sdim{
9504218822Sdim  if (!inst.operands[1].present)
950560484Sobrien    {
9506218822Sdim      inst.operands[1].reg = inst.operands[0].reg + 1;
9507218822Sdim      constraint (inst.operands[0].reg == REG_LR,
9508218822Sdim		  _("r14 not allowed here"));
950960484Sobrien    }
9510218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9511218822Sdim  inst.instruction |= inst.operands[1].reg << 8;
9512218822Sdim  encode_thumb32_addr_mode (2, /*is_t=*/FALSE, /*is_d=*/TRUE);
9513218822Sdim
9514218822Sdim}
951560484Sobrien
9516218822Sdimstatic void
9517218822Sdimdo_t_ldstt (void)
9518218822Sdim{
9519218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9520218822Sdim  encode_thumb32_addr_mode (1, /*is_t=*/TRUE, /*is_d=*/FALSE);
9521218822Sdim}
952260484Sobrien
9523218822Sdimstatic void
9524218822Sdimdo_t_mla (void)
9525218822Sdim{
9526218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
9527218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
9528218822Sdim  inst.instruction |= inst.operands[2].reg;
9529218822Sdim  inst.instruction |= inst.operands[3].reg << 12;
9530218822Sdim}
953160484Sobrien
9532218822Sdimstatic void
9533218822Sdimdo_t_mlal (void)
9534218822Sdim{
9535218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9536218822Sdim  inst.instruction |= inst.operands[1].reg << 8;
9537218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
9538218822Sdim  inst.instruction |= inst.operands[3].reg;
9539218822Sdim}
954060484Sobrien
9541218822Sdimstatic void
9542218822Sdimdo_t_mov_cmp (void)
9543218822Sdim{
9544218822Sdim  if (unified_syntax)
9545218822Sdim    {
9546218822Sdim      int r0off = (inst.instruction == T_MNEM_mov
9547218822Sdim		   || inst.instruction == T_MNEM_movs) ? 8 : 16;
9548218822Sdim      unsigned long opcode;
9549218822Sdim      bfd_boolean narrow;
9550218822Sdim      bfd_boolean low_regs;
955160484Sobrien
9552218822Sdim      low_regs = (inst.operands[0].reg <= 7 && inst.operands[1].reg <= 7);
9553218822Sdim      opcode = inst.instruction;
9554218822Sdim      if (current_it_mask)
9555218822Sdim	narrow = opcode != T_MNEM_movs;
9556218822Sdim      else
9557218822Sdim	narrow = opcode != T_MNEM_movs || low_regs;
9558218822Sdim      if (inst.size_req == 4
9559218822Sdim	  || inst.operands[1].shifted)
9560218822Sdim	narrow = FALSE;
956160484Sobrien
9562218822Sdim      /* MOVS PC, LR is encoded as SUBS PC, LR, #0.  */
9563218822Sdim      if (opcode == T_MNEM_movs && inst.operands[1].isreg
9564218822Sdim	  && !inst.operands[1].shifted
9565218822Sdim	  && inst.operands[0].reg == REG_PC
9566218822Sdim	  && inst.operands[1].reg == REG_LR)
956760484Sobrien	{
9568218822Sdim	  inst.instruction = T2_SUBS_PC_LR;
956960484Sobrien	  return;
957060484Sobrien	}
957160484Sobrien
9572218822Sdim      if (!inst.operands[1].isreg)
957360484Sobrien	{
9574218822Sdim	  /* Immediate operand.  */
9575218822Sdim	  if (current_it_mask == 0 && opcode == T_MNEM_mov)
9576218822Sdim	    narrow = 0;
9577218822Sdim	  if (low_regs && narrow)
957860484Sobrien	    {
9579218822Sdim	      inst.instruction = THUMB_OP16 (opcode);
9580218822Sdim	      inst.instruction |= inst.operands[0].reg << 8;
9581218822Sdim	      if (inst.size_req == 2)
9582218822Sdim		inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
9583218822Sdim	      else
9584218822Sdim		inst.relax = opcode;
958560484Sobrien	    }
9586218822Sdim	  else
9587218822Sdim	    {
9588218822Sdim	      inst.instruction = THUMB_OP32 (inst.instruction);
9589218822Sdim	      inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
9590218822Sdim	      inst.instruction |= inst.operands[0].reg << r0off;
9591218822Sdim	      inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
9592218822Sdim	    }
959360484Sobrien	}
9594218822Sdim      else if (inst.operands[1].shifted && inst.operands[1].immisreg
9595218822Sdim	       && (inst.instruction == T_MNEM_mov
9596218822Sdim		   || inst.instruction == T_MNEM_movs))
9597218822Sdim	{
9598218822Sdim	  /* Register shifts are encoded as separate shift instructions.  */
9599218822Sdim	  bfd_boolean flags = (inst.instruction == T_MNEM_movs);
960060484Sobrien
9601218822Sdim	  if (current_it_mask)
9602218822Sdim	    narrow = !flags;
9603218822Sdim	  else
9604218822Sdim	    narrow = flags;
9605218822Sdim
9606218822Sdim	  if (inst.size_req == 4)
9607218822Sdim	    narrow = FALSE;
9608218822Sdim
9609218822Sdim	  if (!low_regs || inst.operands[1].imm > 7)
9610218822Sdim	    narrow = FALSE;
9611218822Sdim
9612218822Sdim	  if (inst.operands[0].reg != inst.operands[1].reg)
9613218822Sdim	    narrow = FALSE;
9614218822Sdim
9615218822Sdim	  switch (inst.operands[1].shift_kind)
9616218822Sdim	    {
9617218822Sdim	    case SHIFT_LSL:
9618218822Sdim	      opcode = narrow ? T_OPCODE_LSL_R : THUMB_OP32 (T_MNEM_lsl);
9619218822Sdim	      break;
9620218822Sdim	    case SHIFT_ASR:
9621218822Sdim	      opcode = narrow ? T_OPCODE_ASR_R : THUMB_OP32 (T_MNEM_asr);
9622218822Sdim	      break;
9623218822Sdim	    case SHIFT_LSR:
9624218822Sdim	      opcode = narrow ? T_OPCODE_LSR_R : THUMB_OP32 (T_MNEM_lsr);
9625218822Sdim	      break;
9626218822Sdim	    case SHIFT_ROR:
9627218822Sdim	      opcode = narrow ? T_OPCODE_ROR_R : THUMB_OP32 (T_MNEM_ror);
9628218822Sdim	      break;
9629218822Sdim	    default:
9630218822Sdim	      abort();
9631218822Sdim	    }
9632218822Sdim
9633218822Sdim	  inst.instruction = opcode;
9634218822Sdim	  if (narrow)
9635218822Sdim	    {
9636218822Sdim	      inst.instruction |= inst.operands[0].reg;
9637218822Sdim	      inst.instruction |= inst.operands[1].imm << 3;
9638218822Sdim	    }
9639218822Sdim	  else
9640218822Sdim	    {
9641218822Sdim	      if (flags)
9642218822Sdim		inst.instruction |= CONDS_BIT;
9643218822Sdim
9644218822Sdim	      inst.instruction |= inst.operands[0].reg << 8;
9645218822Sdim	      inst.instruction |= inst.operands[1].reg << 16;
9646218822Sdim	      inst.instruction |= inst.operands[1].imm;
9647218822Sdim	    }
964860484Sobrien	}
9649218822Sdim      else if (!narrow)
965060484Sobrien	{
9651218822Sdim	  /* Some mov with immediate shift have narrow variants.
9652218822Sdim	     Register shifts are handled above.  */
9653218822Sdim	  if (low_regs && inst.operands[1].shifted
9654218822Sdim	      && (inst.instruction == T_MNEM_mov
9655218822Sdim		  || inst.instruction == T_MNEM_movs))
965660484Sobrien	    {
9657218822Sdim	      if (current_it_mask)
9658218822Sdim		narrow = (inst.instruction == T_MNEM_mov);
9659218822Sdim	      else
9660218822Sdim		narrow = (inst.instruction == T_MNEM_movs);
966160484Sobrien	    }
9662218822Sdim
9663218822Sdim	  if (narrow)
9664218822Sdim	    {
9665218822Sdim	      switch (inst.operands[1].shift_kind)
9666218822Sdim		{
9667218822Sdim		case SHIFT_LSL: inst.instruction = T_OPCODE_LSL_I; break;
9668218822Sdim		case SHIFT_LSR: inst.instruction = T_OPCODE_LSR_I; break;
9669218822Sdim		case SHIFT_ASR: inst.instruction = T_OPCODE_ASR_I; break;
9670218822Sdim		default: narrow = FALSE; break;
9671218822Sdim		}
9672218822Sdim	    }
9673218822Sdim
9674218822Sdim	  if (narrow)
9675218822Sdim	    {
9676218822Sdim	      inst.instruction |= inst.operands[0].reg;
9677218822Sdim	      inst.instruction |= inst.operands[1].reg << 3;
9678218822Sdim	      inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
9679218822Sdim	    }
968060484Sobrien	  else
968160484Sobrien	    {
9682218822Sdim	      inst.instruction = THUMB_OP32 (inst.instruction);
9683218822Sdim	      inst.instruction |= inst.operands[0].reg << r0off;
9684218822Sdim	      encode_thumb32_shifted_operand (1);
968560484Sobrien	    }
968660484Sobrien	}
9687218822Sdim      else
9688218822Sdim	switch (inst.instruction)
9689218822Sdim	  {
9690218822Sdim	  case T_MNEM_mov:
9691218822Sdim	    inst.instruction = T_OPCODE_MOV_HR;
9692218822Sdim	    inst.instruction |= (inst.operands[0].reg & 0x8) << 4;
9693218822Sdim	    inst.instruction |= (inst.operands[0].reg & 0x7);
9694218822Sdim	    inst.instruction |= inst.operands[1].reg << 3;
9695218822Sdim	    break;
969660484Sobrien
9697218822Sdim	  case T_MNEM_movs:
9698218822Sdim	    /* We know we have low registers at this point.
9699218822Sdim	       Generate ADD Rd, Rs, #0.  */
9700218822Sdim	    inst.instruction = T_OPCODE_ADD_I3;
9701218822Sdim	    inst.instruction |= inst.operands[0].reg;
9702218822Sdim	    inst.instruction |= inst.operands[1].reg << 3;
9703218822Sdim	    break;
9704218822Sdim
9705218822Sdim	  case T_MNEM_cmp:
9706218822Sdim	    if (low_regs)
9707218822Sdim	      {
9708218822Sdim		inst.instruction = T_OPCODE_CMP_LR;
9709218822Sdim		inst.instruction |= inst.operands[0].reg;
9710218822Sdim		inst.instruction |= inst.operands[1].reg << 3;
9711218822Sdim	      }
9712218822Sdim	    else
9713218822Sdim	      {
9714218822Sdim		inst.instruction = T_OPCODE_CMP_HR;
9715218822Sdim		inst.instruction |= (inst.operands[0].reg & 0x8) << 4;
9716218822Sdim		inst.instruction |= (inst.operands[0].reg & 0x7);
9717218822Sdim		inst.instruction |= inst.operands[1].reg << 3;
9718218822Sdim	      }
9719218822Sdim	    break;
9720218822Sdim	  }
9721218822Sdim      return;
972260484Sobrien    }
9723218822Sdim
9724218822Sdim  inst.instruction = THUMB_OP16 (inst.instruction);
9725218822Sdim  if (inst.operands[1].isreg)
972660484Sobrien    {
9727218822Sdim      if (inst.operands[0].reg < 8 && inst.operands[1].reg < 8)
9728218822Sdim	{
9729218822Sdim	  /* A move of two lowregs is encoded as ADD Rd, Rs, #0
9730218822Sdim	     since a MOV instruction produces unpredictable results.  */
9731218822Sdim	  if (inst.instruction == T_OPCODE_MOV_I8)
9732218822Sdim	    inst.instruction = T_OPCODE_ADD_I3;
9733218822Sdim	  else
9734218822Sdim	    inst.instruction = T_OPCODE_CMP_LR;
9735218822Sdim
9736218822Sdim	  inst.instruction |= inst.operands[0].reg;
9737218822Sdim	  inst.instruction |= inst.operands[1].reg << 3;
9738218822Sdim	}
9739218822Sdim      else
9740218822Sdim	{
9741218822Sdim	  if (inst.instruction == T_OPCODE_MOV_I8)
9742218822Sdim	    inst.instruction = T_OPCODE_MOV_HR;
9743218822Sdim	  else
9744218822Sdim	    inst.instruction = T_OPCODE_CMP_HR;
9745218822Sdim	  do_t_cpy ();
9746218822Sdim	}
974760484Sobrien    }
9748218822Sdim  else
9749218822Sdim    {
9750218822Sdim      constraint (inst.operands[0].reg > 7,
9751218822Sdim		  _("only lo regs allowed with immediate"));
9752218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
9753218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
9754218822Sdim    }
975560484Sobrien}
975660484Sobrien
975760484Sobrienstatic void
9758218822Sdimdo_t_mov16 (void)
975960484Sobrien{
9760218822Sdim  bfd_vma imm;
9761218822Sdim  bfd_boolean top;
976260484Sobrien
9763218822Sdim  top = (inst.instruction & 0x00800000) != 0;
9764218822Sdim  if (inst.reloc.type == BFD_RELOC_ARM_MOVW)
976560484Sobrien    {
9766218822Sdim      constraint (top, _(":lower16: not allowed this instruction"));
9767218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVW;
976860484Sobrien    }
9769218822Sdim  else if (inst.reloc.type == BFD_RELOC_ARM_MOVT)
977060484Sobrien    {
9771218822Sdim      constraint (!top, _(":upper16: not allowed this instruction"));
9772218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVT;
977360484Sobrien    }
977460484Sobrien
9775218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
9776218822Sdim  if (inst.reloc.type == BFD_RELOC_UNUSED)
977760484Sobrien    {
9778218822Sdim      imm = inst.reloc.exp.X_add_number;
9779218822Sdim      inst.instruction |= (imm & 0xf000) << 4;
9780218822Sdim      inst.instruction |= (imm & 0x0800) << 15;
9781218822Sdim      inst.instruction |= (imm & 0x0700) << 4;
9782218822Sdim      inst.instruction |= (imm & 0x00ff);
978360484Sobrien    }
978460484Sobrien}
978560484Sobrien
978660484Sobrienstatic void
9787218822Sdimdo_t_mvn_tst (void)
978860484Sobrien{
9789218822Sdim  if (unified_syntax)
9790218822Sdim    {
9791218822Sdim      int r0off = (inst.instruction == T_MNEM_mvn
9792218822Sdim		   || inst.instruction == T_MNEM_mvns) ? 8 : 16;
9793218822Sdim      bfd_boolean narrow;
979460484Sobrien
9795218822Sdim      if (inst.size_req == 4
9796218822Sdim	  || inst.instruction > 0xffff
9797218822Sdim	  || inst.operands[1].shifted
9798218822Sdim	  || inst.operands[0].reg > 7 || inst.operands[1].reg > 7)
9799218822Sdim	narrow = FALSE;
9800218822Sdim      else if (inst.instruction == T_MNEM_cmn)
9801218822Sdim	narrow = TRUE;
9802218822Sdim      else if (THUMB_SETS_FLAGS (inst.instruction))
9803218822Sdim	narrow = (current_it_mask == 0);
9804218822Sdim      else
9805218822Sdim	narrow = (current_it_mask != 0);
9806218822Sdim
9807218822Sdim      if (!inst.operands[1].isreg)
9808218822Sdim	{
9809218822Sdim	  /* For an immediate, we always generate a 32-bit opcode;
9810218822Sdim	     section relaxation will shrink it later if possible.  */
9811218822Sdim	  if (inst.instruction < 0xffff)
9812218822Sdim	    inst.instruction = THUMB_OP32 (inst.instruction);
9813218822Sdim	  inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
9814218822Sdim	  inst.instruction |= inst.operands[0].reg << r0off;
9815218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
9816218822Sdim	}
9817218822Sdim      else
9818218822Sdim	{
9819218822Sdim	  /* See if we can do this with a 16-bit instruction.  */
9820218822Sdim	  if (narrow)
9821218822Sdim	    {
9822218822Sdim	      inst.instruction = THUMB_OP16 (inst.instruction);
9823218822Sdim	      inst.instruction |= inst.operands[0].reg;
9824218822Sdim	      inst.instruction |= inst.operands[1].reg << 3;
9825218822Sdim	    }
9826218822Sdim	  else
9827218822Sdim	    {
9828218822Sdim	      constraint (inst.operands[1].shifted
9829218822Sdim			  && inst.operands[1].immisreg,
9830218822Sdim			  _("shift must be constant"));
9831218822Sdim	      if (inst.instruction < 0xffff)
9832218822Sdim		inst.instruction = THUMB_OP32 (inst.instruction);
9833218822Sdim	      inst.instruction |= inst.operands[0].reg << r0off;
9834218822Sdim	      encode_thumb32_shifted_operand (1);
9835218822Sdim	    }
9836218822Sdim	}
9837218822Sdim    }
9838218822Sdim  else
983960484Sobrien    {
9840218822Sdim      constraint (inst.instruction > 0xffff
9841218822Sdim		  || inst.instruction == T_MNEM_mvns, BAD_THUMB32);
9842218822Sdim      constraint (!inst.operands[1].isreg || inst.operands[1].shifted,
9843218822Sdim		  _("unshifted register required"));
9844218822Sdim      constraint (inst.operands[0].reg > 7 || inst.operands[1].reg > 7,
9845218822Sdim		  BAD_HIREG);
984660484Sobrien
9847218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
9848218822Sdim      inst.instruction |= inst.operands[0].reg;
9849218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
985060484Sobrien    }
985189857Sobrien}
985289857Sobrien
985389857Sobrienstatic void
9854218822Sdimdo_t_mrs (void)
985589857Sobrien{
9856218822Sdim  int flags;
985789857Sobrien
9858218822Sdim  if (do_vfp_nsyn_mrs () == SUCCESS)
9859218822Sdim    return;
9860218822Sdim
9861218822Sdim  flags = inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f|SPSR_BIT);
9862218822Sdim  if (flags == 0)
986389857Sobrien    {
9864218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7m),
9865218822Sdim		  _("selected processor does not support "
9866218822Sdim		    "requested special purpose register"));
986789857Sobrien    }
9868218822Sdim  else
986960484Sobrien    {
9870218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1),
9871218822Sdim		  _("selected processor does not support "
9872218822Sdim		    "requested special purpose register %x"));
9873218822Sdim      /* mrs only accepts CPSR/SPSR/CPSR_all/SPSR_all.  */
9874218822Sdim      constraint ((flags & ~SPSR_BIT) != (PSR_c|PSR_f),
9875218822Sdim		  _("'CPSR' or 'SPSR' expected"));
987660484Sobrien    }
9877218822Sdim
9878218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
9879218822Sdim  inst.instruction |= (flags & SPSR_BIT) >> 2;
9880218822Sdim  inst.instruction |= inst.operands[1].imm & 0xff;
988160484Sobrien}
988260484Sobrien
988360484Sobrienstatic void
9884218822Sdimdo_t_msr (void)
988560484Sobrien{
9886218822Sdim  int flags;
988760484Sobrien
9888218822Sdim  if (do_vfp_nsyn_msr () == SUCCESS)
9889218822Sdim    return;
9890218822Sdim
9891218822Sdim  constraint (!inst.operands[1].isreg,
9892218822Sdim	      _("Thumb encoding does not support an immediate here"));
9893218822Sdim  flags = inst.operands[0].imm;
9894218822Sdim  if (flags & ~0xff)
989560484Sobrien    {
9896218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1),
9897218822Sdim		  _("selected processor does not support "
9898218822Sdim		    "requested special purpose register"));
989960484Sobrien    }
9900218822Sdim  else
990160484Sobrien    {
9902218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7m),
9903218822Sdim		  _("selected processor does not support "
9904218822Sdim		    "requested special purpose register"));
9905218822Sdim      flags |= PSR_f;
990660484Sobrien    }
9907218822Sdim  inst.instruction |= (flags & SPSR_BIT) >> 2;
9908218822Sdim  inst.instruction |= (flags & ~SPSR_BIT) >> 8;
9909218822Sdim  inst.instruction |= (flags & 0xff);
9910218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
991160484Sobrien}
991260484Sobrien
991360484Sobrienstatic void
9914218822Sdimdo_t_mul (void)
991560484Sobrien{
9916218822Sdim  if (!inst.operands[2].present)
9917218822Sdim    inst.operands[2].reg = inst.operands[0].reg;
991860484Sobrien
9919218822Sdim  /* There is no 32-bit MULS and no 16-bit MUL. */
9920218822Sdim  if (unified_syntax && inst.instruction == T_MNEM_mul)
992160484Sobrien    {
9922218822Sdim      inst.instruction = THUMB_OP32 (inst.instruction);
9923218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
9924218822Sdim      inst.instruction |= inst.operands[1].reg << 16;
9925218822Sdim      inst.instruction |= inst.operands[2].reg << 0;
992660484Sobrien    }
9927218822Sdim  else
9928218822Sdim    {
9929218822Sdim      constraint (!unified_syntax
9930218822Sdim		  && inst.instruction == T_MNEM_muls, BAD_THUMB32);
9931218822Sdim      constraint (inst.operands[0].reg > 7 || inst.operands[1].reg > 7,
9932218822Sdim		  BAD_HIREG);
993360484Sobrien
9934218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
9935218822Sdim      inst.instruction |= inst.operands[0].reg;
9936218822Sdim
9937218822Sdim      if (inst.operands[0].reg == inst.operands[1].reg)
9938218822Sdim	inst.instruction |= inst.operands[2].reg << 3;
9939218822Sdim      else if (inst.operands[0].reg == inst.operands[2].reg)
9940218822Sdim	inst.instruction |= inst.operands[1].reg << 3;
9941218822Sdim      else
9942218822Sdim	constraint (1, _("dest must overlap one source register"));
9943218822Sdim    }
994489857Sobrien}
994589857Sobrien
9946218822Sdimstatic void
9947218822Sdimdo_t_mull (void)
994889857Sobrien{
9949218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9950218822Sdim  inst.instruction |= inst.operands[1].reg << 8;
9951218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
9952218822Sdim  inst.instruction |= inst.operands[3].reg;
995389857Sobrien
9954218822Sdim  if (inst.operands[0].reg == inst.operands[1].reg)
9955218822Sdim    as_tsktsk (_("rdhi and rdlo must be different"));
9956218822Sdim}
9957218822Sdim
9958218822Sdimstatic void
9959218822Sdimdo_t_nop (void)
9960218822Sdim{
9961218822Sdim  if (unified_syntax)
996260484Sobrien    {
9963218822Sdim      if (inst.size_req == 4 || inst.operands[0].imm > 15)
996489857Sobrien	{
9965218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
9966218822Sdim	  inst.instruction |= inst.operands[0].imm;
996789857Sobrien	}
9968218822Sdim      else
9969218822Sdim	{
9970218822Sdim	  inst.instruction = THUMB_OP16 (inst.instruction);
9971218822Sdim	  inst.instruction |= inst.operands[0].imm << 4;
9972218822Sdim	}
997389857Sobrien    }
9974218822Sdim  else
9975218822Sdim    {
9976218822Sdim      constraint (inst.operands[0].present,
9977218822Sdim		  _("Thumb does not support NOP with hints"));
9978218822Sdim      inst.instruction = 0x46c0;
9979218822Sdim    }
998089857Sobrien}
998189857Sobrien
9982218822Sdimstatic void
9983218822Sdimdo_t_neg (void)
998489857Sobrien{
9985218822Sdim  if (unified_syntax)
998689857Sobrien    {
9987218822Sdim      bfd_boolean narrow;
998889857Sobrien
9989218822Sdim      if (THUMB_SETS_FLAGS (inst.instruction))
9990218822Sdim	narrow = (current_it_mask == 0);
9991218822Sdim      else
9992218822Sdim	narrow = (current_it_mask != 0);
9993218822Sdim      if (inst.operands[0].reg > 7 || inst.operands[1].reg > 7)
9994218822Sdim	narrow = FALSE;
9995218822Sdim      if (inst.size_req == 4)
9996218822Sdim	narrow = FALSE;
999789857Sobrien
9998218822Sdim      if (!narrow)
9999218822Sdim	{
10000218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
10001218822Sdim	  inst.instruction |= inst.operands[0].reg << 8;
10002218822Sdim	  inst.instruction |= inst.operands[1].reg << 16;
1000389857Sobrien	}
10004218822Sdim      else
10005218822Sdim	{
10006218822Sdim	  inst.instruction = THUMB_OP16 (inst.instruction);
10007218822Sdim	  inst.instruction |= inst.operands[0].reg;
10008218822Sdim	  inst.instruction |= inst.operands[1].reg << 3;
10009218822Sdim	}
1001089857Sobrien    }
10011218822Sdim  else
10012218822Sdim    {
10013218822Sdim      constraint (inst.operands[0].reg > 7 || inst.operands[1].reg > 7,
10014218822Sdim		  BAD_HIREG);
10015218822Sdim      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
1001689857Sobrien
10017218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
10018218822Sdim      inst.instruction |= inst.operands[0].reg;
10019218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
10020218822Sdim    }
1002189857Sobrien}
1002289857Sobrien
1002389857Sobrienstatic void
10024218822Sdimdo_t_pkhbt (void)
1002589857Sobrien{
10026218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10027218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
10028218822Sdim  inst.instruction |= inst.operands[2].reg;
10029218822Sdim  if (inst.operands[3].present)
1003089857Sobrien    {
10031218822Sdim      unsigned int val = inst.reloc.exp.X_add_number;
10032218822Sdim      constraint (inst.reloc.exp.X_op != O_constant,
10033218822Sdim		  _("expression too complex"));
10034218822Sdim      inst.instruction |= (val & 0x1c) << 10;
10035218822Sdim      inst.instruction |= (val & 0x03) << 6;
1003660484Sobrien    }
10037218822Sdim}
1003860484Sobrien
10039218822Sdimstatic void
10040218822Sdimdo_t_pkhtb (void)
10041218822Sdim{
10042218822Sdim  if (!inst.operands[3].present)
10043218822Sdim    inst.instruction &= ~0x00000020;
10044218822Sdim  do_t_pkhbt ();
1004589857Sobrien}
1004689857Sobrien
1004789857Sobrienstatic void
10048218822Sdimdo_t_pld (void)
1004989857Sobrien{
10050218822Sdim  encode_thumb32_addr_mode (0, /*is_t=*/FALSE, /*is_d=*/FALSE);
10051218822Sdim}
1005289857Sobrien
10053218822Sdimstatic void
10054218822Sdimdo_t_push_pop (void)
10055218822Sdim{
10056218822Sdim  unsigned mask;
10057218822Sdim
10058218822Sdim  constraint (inst.operands[0].writeback,
10059218822Sdim	      _("push/pop do not support {reglist}^"));
10060218822Sdim  constraint (inst.reloc.type != BFD_RELOC_UNUSED,
10061218822Sdim	      _("expression too complex"));
1006289857Sobrien
10063218822Sdim  mask = inst.operands[0].imm;
10064218822Sdim  if ((mask & ~0xff) == 0)
10065218822Sdim    inst.instruction = THUMB_OP16 (inst.instruction) | mask;
10066218822Sdim  else if ((inst.instruction == T_MNEM_push
10067218822Sdim	    && (mask & ~0xff) == 1 << REG_LR)
10068218822Sdim	   || (inst.instruction == T_MNEM_pop
10069218822Sdim	       && (mask & ~0xff) == 1 << REG_PC))
1007089857Sobrien    {
10071218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
10072218822Sdim      inst.instruction |= THUMB_PP_PC_LR;
10073218822Sdim      inst.instruction |= mask & 0xff;
10074218822Sdim    }
10075218822Sdim  else if (unified_syntax)
10076218822Sdim    {
10077218822Sdim      inst.instruction = THUMB_OP32 (inst.instruction);
10078218822Sdim      encode_thumb2_ldmstm(13, mask, TRUE);
10079218822Sdim    }
10080218822Sdim  else
10081218822Sdim    {
10082218822Sdim      inst.error = _("invalid register list to push/pop instruction");
1008389857Sobrien      return;
1008489857Sobrien    }
10085218822Sdim}
1008689857Sobrien
10087218822Sdimstatic void
10088218822Sdimdo_t_rbit (void)
10089218822Sdim{
10090218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10091218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
1009289857Sobrien}
1009389857Sobrien
1009489857Sobrienstatic void
10095223484Sdimdo_t_rd_rm (void)
10096223484Sdim{
10097223484Sdim  inst.instruction |= inst.operands[0].reg << 8;
10098223484Sdim  inst.instruction |= inst.operands[1].reg;
10099223484Sdim}
10100223484Sdim
10101223484Sdimstatic void
10102218822Sdimdo_t_rev (void)
1010389857Sobrien{
10104218822Sdim  if (inst.operands[0].reg <= 7 && inst.operands[1].reg <= 7
10105218822Sdim      && inst.size_req != 4)
1010689857Sobrien    {
10107218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
10108218822Sdim      inst.instruction |= inst.operands[0].reg;
10109218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
1011089857Sobrien    }
10111218822Sdim  else if (unified_syntax)
10112218822Sdim    {
10113218822Sdim      inst.instruction = THUMB_OP32 (inst.instruction);
10114218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
10115218822Sdim      inst.instruction |= inst.operands[1].reg << 16;
10116218822Sdim      inst.instruction |= inst.operands[1].reg;
10117218822Sdim    }
10118218822Sdim  else
10119218822Sdim    inst.error = BAD_HIREG;
1012089857Sobrien}
1012189857Sobrien
1012289857Sobrienstatic void
10123218822Sdimdo_t_rsb (void)
1012489857Sobrien{
10125218822Sdim  int Rd, Rs;
1012689857Sobrien
10127218822Sdim  Rd = inst.operands[0].reg;
10128218822Sdim  Rs = (inst.operands[1].present
10129218822Sdim	? inst.operands[1].reg    /* Rd, Rs, foo */
10130218822Sdim	: inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
1013189857Sobrien
10132218822Sdim  inst.instruction |= Rd << 8;
10133218822Sdim  inst.instruction |= Rs << 16;
10134218822Sdim  if (!inst.operands[2].isreg)
1013589857Sobrien    {
10136218822Sdim      bfd_boolean narrow;
1013789857Sobrien
10138218822Sdim      if ((inst.instruction & 0x00100000) != 0)
10139218822Sdim	narrow = (current_it_mask == 0);
10140218822Sdim      else
10141218822Sdim	narrow = (current_it_mask != 0);
1014289857Sobrien
10143218822Sdim      if (Rd > 7 || Rs > 7)
10144218822Sdim	narrow = FALSE;
1014589857Sobrien
10146218822Sdim      if (inst.size_req == 4 || !unified_syntax)
10147218822Sdim	narrow = FALSE;
1014889857Sobrien
10149218822Sdim      if (inst.reloc.exp.X_op != O_constant
10150218822Sdim	  || inst.reloc.exp.X_add_number != 0)
10151218822Sdim	narrow = FALSE;
10152218822Sdim
10153218822Sdim      /* Turn rsb #0 into 16-bit neg.  We should probably do this via
10154218822Sdim         relaxation, but it doesn't seem worth the hassle.  */
10155218822Sdim      if (narrow)
10156218822Sdim	{
10157218822Sdim	  inst.reloc.type = BFD_RELOC_UNUSED;
10158218822Sdim	  inst.instruction = THUMB_OP16 (T_MNEM_negs);
10159218822Sdim	  inst.instruction |= Rs << 3;
10160218822Sdim	  inst.instruction |= Rd;
10161218822Sdim	}
10162218822Sdim      else
10163218822Sdim	{
10164218822Sdim	  inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
10165218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
10166218822Sdim	}
1016789857Sobrien    }
10168218822Sdim  else
10169218822Sdim    encode_thumb32_shifted_operand (2);
10170218822Sdim}
1017189857Sobrien
10172218822Sdimstatic void
10173218822Sdimdo_t_setend (void)
10174218822Sdim{
10175218822Sdim  constraint (current_it_mask, BAD_NOT_IT);
10176218822Sdim  if (inst.operands[0].imm)
10177218822Sdim    inst.instruction |= 0x8;
1017889857Sobrien}
1017989857Sobrien
1018089857Sobrienstatic void
10181218822Sdimdo_t_shift (void)
1018289857Sobrien{
10183218822Sdim  if (!inst.operands[1].present)
10184218822Sdim    inst.operands[1].reg = inst.operands[0].reg;
1018589857Sobrien
10186218822Sdim  if (unified_syntax)
1018789857Sobrien    {
10188218822Sdim      bfd_boolean narrow;
10189218822Sdim      int shift_kind;
10190218822Sdim
10191218822Sdim      switch (inst.instruction)
10192218822Sdim	{
10193218822Sdim	case T_MNEM_asr:
10194218822Sdim	case T_MNEM_asrs: shift_kind = SHIFT_ASR; break;
10195218822Sdim	case T_MNEM_lsl:
10196218822Sdim	case T_MNEM_lsls: shift_kind = SHIFT_LSL; break;
10197218822Sdim	case T_MNEM_lsr:
10198218822Sdim	case T_MNEM_lsrs: shift_kind = SHIFT_LSR; break;
10199218822Sdim	case T_MNEM_ror:
10200218822Sdim	case T_MNEM_rors: shift_kind = SHIFT_ROR; break;
10201218822Sdim	default: abort ();
10202218822Sdim	}
10203218822Sdim
10204218822Sdim      if (THUMB_SETS_FLAGS (inst.instruction))
10205218822Sdim	narrow = (current_it_mask == 0);
10206218822Sdim      else
10207218822Sdim	narrow = (current_it_mask != 0);
10208218822Sdim      if (inst.operands[0].reg > 7 || inst.operands[1].reg > 7)
10209218822Sdim	narrow = FALSE;
10210218822Sdim      if (!inst.operands[2].isreg && shift_kind == SHIFT_ROR)
10211218822Sdim	narrow = FALSE;
10212218822Sdim      if (inst.operands[2].isreg
10213218822Sdim	  && (inst.operands[1].reg != inst.operands[0].reg
10214218822Sdim	      || inst.operands[2].reg > 7))
10215218822Sdim	narrow = FALSE;
10216218822Sdim      if (inst.size_req == 4)
10217218822Sdim	narrow = FALSE;
10218218822Sdim
10219218822Sdim      if (!narrow)
10220218822Sdim	{
10221218822Sdim	  if (inst.operands[2].isreg)
10222218822Sdim	    {
10223218822Sdim	      inst.instruction = THUMB_OP32 (inst.instruction);
10224218822Sdim	      inst.instruction |= inst.operands[0].reg << 8;
10225218822Sdim	      inst.instruction |= inst.operands[1].reg << 16;
10226218822Sdim	      inst.instruction |= inst.operands[2].reg;
10227218822Sdim	    }
10228218822Sdim	  else
10229218822Sdim	    {
10230218822Sdim	      inst.operands[1].shifted = 1;
10231218822Sdim	      inst.operands[1].shift_kind = shift_kind;
10232218822Sdim	      inst.instruction = THUMB_OP32 (THUMB_SETS_FLAGS (inst.instruction)
10233218822Sdim					     ? T_MNEM_movs : T_MNEM_mov);
10234218822Sdim	      inst.instruction |= inst.operands[0].reg << 8;
10235218822Sdim	      encode_thumb32_shifted_operand (1);
10236218822Sdim	      /* Prevent the incorrect generation of an ARM_IMMEDIATE fixup.  */
10237218822Sdim	      inst.reloc.type = BFD_RELOC_UNUSED;
10238218822Sdim	    }
10239218822Sdim	}
10240218822Sdim      else
10241218822Sdim	{
10242218822Sdim	  if (inst.operands[2].isreg)
10243218822Sdim	    {
10244218822Sdim	      switch (shift_kind)
10245218822Sdim		{
10246218822Sdim		case SHIFT_ASR: inst.instruction = T_OPCODE_ASR_R; break;
10247218822Sdim		case SHIFT_LSL: inst.instruction = T_OPCODE_LSL_R; break;
10248218822Sdim		case SHIFT_LSR: inst.instruction = T_OPCODE_LSR_R; break;
10249218822Sdim		case SHIFT_ROR: inst.instruction = T_OPCODE_ROR_R; break;
10250218822Sdim		default: abort ();
10251218822Sdim		}
10252218822Sdim
10253218822Sdim	      inst.instruction |= inst.operands[0].reg;
10254218822Sdim	      inst.instruction |= inst.operands[2].reg << 3;
10255218822Sdim	    }
10256218822Sdim	  else
10257218822Sdim	    {
10258218822Sdim	      switch (shift_kind)
10259218822Sdim		{
10260218822Sdim		case SHIFT_ASR: inst.instruction = T_OPCODE_ASR_I; break;
10261218822Sdim		case SHIFT_LSL: inst.instruction = T_OPCODE_LSL_I; break;
10262218822Sdim		case SHIFT_LSR: inst.instruction = T_OPCODE_LSR_I; break;
10263218822Sdim		default: abort ();
10264218822Sdim		}
10265218822Sdim	      inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
10266218822Sdim	      inst.instruction |= inst.operands[0].reg;
10267218822Sdim	      inst.instruction |= inst.operands[1].reg << 3;
10268218822Sdim	    }
10269218822Sdim	}
1027089857Sobrien    }
10271218822Sdim  else
10272218822Sdim    {
10273218822Sdim      constraint (inst.operands[0].reg > 7
10274218822Sdim		  || inst.operands[1].reg > 7, BAD_HIREG);
10275218822Sdim      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
1027689857Sobrien
10277218822Sdim      if (inst.operands[2].isreg)  /* Rd, {Rs,} Rn */
10278218822Sdim	{
10279218822Sdim	  constraint (inst.operands[2].reg > 7, BAD_HIREG);
10280218822Sdim	  constraint (inst.operands[0].reg != inst.operands[1].reg,
10281218822Sdim		      _("source1 and dest must be same register"));
10282218822Sdim
10283218822Sdim	  switch (inst.instruction)
10284218822Sdim	    {
10285218822Sdim	    case T_MNEM_asr: inst.instruction = T_OPCODE_ASR_R; break;
10286218822Sdim	    case T_MNEM_lsl: inst.instruction = T_OPCODE_LSL_R; break;
10287218822Sdim	    case T_MNEM_lsr: inst.instruction = T_OPCODE_LSR_R; break;
10288218822Sdim	    case T_MNEM_ror: inst.instruction = T_OPCODE_ROR_R; break;
10289218822Sdim	    default: abort ();
10290218822Sdim	    }
10291218822Sdim
10292218822Sdim	  inst.instruction |= inst.operands[0].reg;
10293218822Sdim	  inst.instruction |= inst.operands[2].reg << 3;
10294218822Sdim	}
10295218822Sdim      else
10296218822Sdim	{
10297218822Sdim	  switch (inst.instruction)
10298218822Sdim	    {
10299218822Sdim	    case T_MNEM_asr: inst.instruction = T_OPCODE_ASR_I; break;
10300218822Sdim	    case T_MNEM_lsl: inst.instruction = T_OPCODE_LSL_I; break;
10301218822Sdim	    case T_MNEM_lsr: inst.instruction = T_OPCODE_LSR_I; break;
10302218822Sdim	    case T_MNEM_ror: inst.error = _("ror #imm not supported"); return;
10303218822Sdim	    default: abort ();
10304218822Sdim	    }
10305218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
10306218822Sdim	  inst.instruction |= inst.operands[0].reg;
10307218822Sdim	  inst.instruction |= inst.operands[1].reg << 3;
10308218822Sdim	}
1030989857Sobrien    }
10310218822Sdim}
1031189857Sobrien
10312218822Sdimstatic void
10313218822Sdimdo_t_simd (void)
10314218822Sdim{
10315218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10316218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
10317218822Sdim  inst.instruction |= inst.operands[2].reg;
1031889857Sobrien}
1031989857Sobrien
1032089857Sobrienstatic void
10321218822Sdimdo_t_smc (void)
1032289857Sobrien{
10323218822Sdim  unsigned int value = inst.reloc.exp.X_add_number;
10324218822Sdim  constraint (inst.reloc.exp.X_op != O_constant,
10325218822Sdim	      _("expression too complex"));
10326218822Sdim  inst.reloc.type = BFD_RELOC_UNUSED;
10327218822Sdim  inst.instruction |= (value & 0xf000) >> 12;
10328218822Sdim  inst.instruction |= (value & 0x0ff0);
10329218822Sdim  inst.instruction |= (value & 0x000f) << 16;
1033060484Sobrien}
1033160484Sobrien
1033260484Sobrienstatic void
10333218822Sdimdo_t_ssat (void)
10334130561Sobrien{
10335218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10336218822Sdim  inst.instruction |= inst.operands[1].imm - 1;
10337218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
10338130561Sobrien
10339218822Sdim  if (inst.operands[3].present)
10340130561Sobrien    {
10341218822Sdim      constraint (inst.reloc.exp.X_op != O_constant,
10342218822Sdim		  _("expression too complex"));
10343130561Sobrien
10344218822Sdim      if (inst.reloc.exp.X_add_number != 0)
10345218822Sdim	{
10346218822Sdim	  if (inst.operands[3].shift_kind == SHIFT_ASR)
10347218822Sdim	    inst.instruction |= 0x00200000;  /* sh bit */
10348218822Sdim	  inst.instruction |= (inst.reloc.exp.X_add_number & 0x1c) << 10;
10349218822Sdim	  inst.instruction |= (inst.reloc.exp.X_add_number & 0x03) << 6;
10350218822Sdim	}
10351218822Sdim      inst.reloc.type = BFD_RELOC_UNUSED;
10352130561Sobrien    }
10353218822Sdim}
10354130561Sobrien
10355218822Sdimstatic void
10356218822Sdimdo_t_ssat16 (void)
10357218822Sdim{
10358218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10359218822Sdim  inst.instruction |= inst.operands[1].imm - 1;
10360218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
10361130561Sobrien}
10362130561Sobrien
10363130561Sobrienstatic void
10364218822Sdimdo_t_strex (void)
1036560484Sobrien{
10366218822Sdim  constraint (!inst.operands[2].isreg || !inst.operands[2].preind
10367218822Sdim	      || inst.operands[2].postind || inst.operands[2].writeback
10368218822Sdim	      || inst.operands[2].immisreg || inst.operands[2].shifted
10369218822Sdim	      || inst.operands[2].negative,
10370218822Sdim	      BAD_ADDR_MODE);
1037160484Sobrien
10372218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10373218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
10374218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
10375218822Sdim  inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_U8;
1037660484Sobrien}
1037760484Sobrien
1037889857Sobrienstatic void
10379218822Sdimdo_t_strexd (void)
1038089857Sobrien{
10381218822Sdim  if (!inst.operands[2].present)
10382218822Sdim    inst.operands[2].reg = inst.operands[1].reg + 1;
1038389857Sobrien
10384218822Sdim  constraint (inst.operands[0].reg == inst.operands[1].reg
10385218822Sdim	      || inst.operands[0].reg == inst.operands[2].reg
10386218822Sdim	      || inst.operands[0].reg == inst.operands[3].reg
10387218822Sdim	      || inst.operands[1].reg == inst.operands[2].reg,
10388218822Sdim	      BAD_OVERLAP);
1038989857Sobrien
10390218822Sdim  inst.instruction |= inst.operands[0].reg;
10391218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
10392218822Sdim  inst.instruction |= inst.operands[2].reg << 8;
10393218822Sdim  inst.instruction |= inst.operands[3].reg << 16;
10394218822Sdim}
1039589857Sobrien
10396218822Sdimstatic void
10397218822Sdimdo_t_sxtah (void)
10398218822Sdim{
10399218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10400218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
10401218822Sdim  inst.instruction |= inst.operands[2].reg;
10402218822Sdim  inst.instruction |= inst.operands[3].imm << 4;
1040389857Sobrien}
1040489857Sobrien
1040589857Sobrienstatic void
10406218822Sdimdo_t_sxth (void)
1040789857Sobrien{
10408218822Sdim  if (inst.instruction <= 0xffff && inst.size_req != 4
10409218822Sdim      && inst.operands[0].reg <= 7 && inst.operands[1].reg <= 7
10410218822Sdim      && (!inst.operands[2].present || inst.operands[2].imm == 0))
1041189857Sobrien    {
10412218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
10413218822Sdim      inst.instruction |= inst.operands[0].reg;
10414218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
1041589857Sobrien    }
10416218822Sdim  else if (unified_syntax)
10417218822Sdim    {
10418218822Sdim      if (inst.instruction <= 0xffff)
10419218822Sdim	inst.instruction = THUMB_OP32 (inst.instruction);
10420218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
10421218822Sdim      inst.instruction |= inst.operands[1].reg;
10422218822Sdim      inst.instruction |= inst.operands[2].imm << 4;
10423218822Sdim    }
10424218822Sdim  else
10425218822Sdim    {
10426218822Sdim      constraint (inst.operands[2].present && inst.operands[2].imm != 0,
10427218822Sdim		  _("Thumb encoding does not support rotation"));
10428218822Sdim      constraint (1, BAD_HIREG);
10429218822Sdim    }
10430218822Sdim}
1043189857Sobrien
10432218822Sdimstatic void
10433218822Sdimdo_t_swi (void)
10434218822Sdim{
10435218822Sdim  inst.reloc.type = BFD_RELOC_ARM_SWI;
1043689857Sobrien}
1043789857Sobrien
1043889857Sobrienstatic void
10439218822Sdimdo_t_tb (void)
1044089857Sobrien{
10441218822Sdim  int half;
1044289857Sobrien
10443218822Sdim  half = (inst.instruction & 0x10) != 0;
10444218822Sdim  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
10445218822Sdim  constraint (inst.operands[0].immisreg,
10446218822Sdim	      _("instruction requires register index"));
10447218822Sdim  constraint (inst.operands[0].imm == 15,
10448218822Sdim	      _("PC is not a valid index register"));
10449218822Sdim  constraint (!half && inst.operands[0].shifted,
10450218822Sdim	      _("instruction does not allow shifted index"));
10451218822Sdim  inst.instruction |= (inst.operands[0].reg << 16) | inst.operands[0].imm;
1045289857Sobrien}
1045389857Sobrien
10454218822Sdimstatic void
10455218822Sdimdo_t_usat (void)
1045689857Sobrien{
10457218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10458218822Sdim  inst.instruction |= inst.operands[1].imm;
10459218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
1046089857Sobrien
10461218822Sdim  if (inst.operands[3].present)
1046289857Sobrien    {
10463218822Sdim      constraint (inst.reloc.exp.X_op != O_constant,
10464218822Sdim		  _("expression too complex"));
10465218822Sdim      if (inst.reloc.exp.X_add_number != 0)
10466218822Sdim	{
10467218822Sdim	  if (inst.operands[3].shift_kind == SHIFT_ASR)
10468218822Sdim	    inst.instruction |= 0x00200000;  /* sh bit */
1046989857Sobrien
10470218822Sdim	  inst.instruction |= (inst.reloc.exp.X_add_number & 0x1c) << 10;
10471218822Sdim	  inst.instruction |= (inst.reloc.exp.X_add_number & 0x03) << 6;
1047289857Sobrien	}
10473218822Sdim      inst.reloc.type = BFD_RELOC_UNUSED;
1047489857Sobrien    }
1047589857Sobrien}
1047689857Sobrien
10477218822Sdimstatic void
10478218822Sdimdo_t_usat16 (void)
1047989857Sobrien{
10480218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10481218822Sdim  inst.instruction |= inst.operands[1].imm;
10482218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
10483218822Sdim}
1048489857Sobrien
10485218822Sdim/* Neon instruction encoder helpers.  */
10486218822Sdim
10487218822Sdim/* Encodings for the different types for various Neon opcodes.  */
1048889857Sobrien
10489218822Sdim/* An "invalid" code for the following tables.  */
10490218822Sdim#define N_INV -1u
1049189857Sobrien
10492218822Sdimstruct neon_tab_entry
10493218822Sdim{
10494218822Sdim  unsigned integer;
10495218822Sdim  unsigned float_or_poly;
10496218822Sdim  unsigned scalar_or_imm;
10497218822Sdim};
10498218822Sdim
10499218822Sdim/* Map overloaded Neon opcodes to their respective encodings.  */
10500218822Sdim#define NEON_ENC_TAB					\
10501218822Sdim  X(vabd,	0x0000700, 0x1200d00, N_INV),		\
10502218822Sdim  X(vmax,	0x0000600, 0x0000f00, N_INV),		\
10503218822Sdim  X(vmin,	0x0000610, 0x0200f00, N_INV),		\
10504218822Sdim  X(vpadd,	0x0000b10, 0x1000d00, N_INV),		\
10505218822Sdim  X(vpmax,	0x0000a00, 0x1000f00, N_INV),		\
10506218822Sdim  X(vpmin,	0x0000a10, 0x1200f00, N_INV),		\
10507218822Sdim  X(vadd,	0x0000800, 0x0000d00, N_INV),		\
10508218822Sdim  X(vsub,	0x1000800, 0x0200d00, N_INV),		\
10509218822Sdim  X(vceq,	0x1000810, 0x0000e00, 0x1b10100),	\
10510218822Sdim  X(vcge,	0x0000310, 0x1000e00, 0x1b10080),	\
10511218822Sdim  X(vcgt,	0x0000300, 0x1200e00, 0x1b10000),	\
10512218822Sdim  /* Register variants of the following two instructions are encoded as
10513218822Sdim     vcge / vcgt with the operands reversed. */  	\
10514218822Sdim  X(vclt,	0x0000300, 0x1200e00, 0x1b10200),	\
10515218822Sdim  X(vcle,	0x0000310, 0x1000e00, 0x1b10180),	\
10516218822Sdim  X(vmla,	0x0000900, 0x0000d10, 0x0800040),	\
10517218822Sdim  X(vmls,	0x1000900, 0x0200d10, 0x0800440),	\
10518218822Sdim  X(vmul,	0x0000910, 0x1000d10, 0x0800840),	\
10519218822Sdim  X(vmull,	0x0800c00, 0x0800e00, 0x0800a40), /* polynomial not float.  */ \
10520218822Sdim  X(vmlal,	0x0800800, N_INV,     0x0800240),	\
10521218822Sdim  X(vmlsl,	0x0800a00, N_INV,     0x0800640),	\
10522218822Sdim  X(vqdmlal,	0x0800900, N_INV,     0x0800340),	\
10523218822Sdim  X(vqdmlsl,	0x0800b00, N_INV,     0x0800740),	\
10524218822Sdim  X(vqdmull,	0x0800d00, N_INV,     0x0800b40),	\
10525218822Sdim  X(vqdmulh,    0x0000b00, N_INV,     0x0800c40),	\
10526218822Sdim  X(vqrdmulh,   0x1000b00, N_INV,     0x0800d40),	\
10527218822Sdim  X(vshl,	0x0000400, N_INV,     0x0800510),	\
10528218822Sdim  X(vqshl,	0x0000410, N_INV,     0x0800710),	\
10529218822Sdim  X(vand,	0x0000110, N_INV,     0x0800030),	\
10530218822Sdim  X(vbic,	0x0100110, N_INV,     0x0800030),	\
10531218822Sdim  X(veor,	0x1000110, N_INV,     N_INV),		\
10532218822Sdim  X(vorn,	0x0300110, N_INV,     0x0800010),	\
10533218822Sdim  X(vorr,	0x0200110, N_INV,     0x0800010),	\
10534218822Sdim  X(vmvn,	0x1b00580, N_INV,     0x0800030),	\
10535218822Sdim  X(vshll,	0x1b20300, N_INV,     0x0800a10), /* max shift, immediate.  */ \
10536218822Sdim  X(vcvt,       0x1b30600, N_INV,     0x0800e10), /* integer, fixed-point.  */ \
10537218822Sdim  X(vdup,       0xe800b10, N_INV,     0x1b00c00), /* arm, scalar.  */ \
10538218822Sdim  X(vld1,       0x0200000, 0x0a00000, 0x0a00c00), /* interlv, lane, dup.  */ \
10539218822Sdim  X(vst1,	0x0000000, 0x0800000, N_INV),		\
10540218822Sdim  X(vld2,	0x0200100, 0x0a00100, 0x0a00d00),	\
10541218822Sdim  X(vst2,	0x0000100, 0x0800100, N_INV),		\
10542218822Sdim  X(vld3,	0x0200200, 0x0a00200, 0x0a00e00),	\
10543218822Sdim  X(vst3,	0x0000200, 0x0800200, N_INV),		\
10544218822Sdim  X(vld4,	0x0200300, 0x0a00300, 0x0a00f00),	\
10545218822Sdim  X(vst4,	0x0000300, 0x0800300, N_INV),		\
10546218822Sdim  X(vmovn,	0x1b20200, N_INV,     N_INV),		\
10547218822Sdim  X(vtrn,	0x1b20080, N_INV,     N_INV),		\
10548218822Sdim  X(vqmovn,	0x1b20200, N_INV,     N_INV),		\
10549218822Sdim  X(vqmovun,	0x1b20240, N_INV,     N_INV),		\
10550218822Sdim  X(vnmul,      0xe200a40, 0xe200b40, N_INV),		\
10551218822Sdim  X(vnmla,      0xe000a40, 0xe000b40, N_INV),		\
10552218822Sdim  X(vnmls,      0xe100a40, 0xe100b40, N_INV),		\
10553218822Sdim  X(vcmp,	0xeb40a40, 0xeb40b40, N_INV),		\
10554218822Sdim  X(vcmpz,	0xeb50a40, 0xeb50b40, N_INV),		\
10555218822Sdim  X(vcmpe,	0xeb40ac0, 0xeb40bc0, N_INV),		\
10556218822Sdim  X(vcmpez,     0xeb50ac0, 0xeb50bc0, N_INV)
1055789857Sobrien
10558218822Sdimenum neon_opc
10559218822Sdim{
10560218822Sdim#define X(OPC,I,F,S) N_MNEM_##OPC
10561218822SdimNEON_ENC_TAB
10562218822Sdim#undef X
10563218822Sdim};
1056489857Sobrien
10565218822Sdimstatic const struct neon_tab_entry neon_enc_tab[] =
1056689857Sobrien{
10567218822Sdim#define X(OPC,I,F,S) { (I), (F), (S) }
10568218822SdimNEON_ENC_TAB
10569218822Sdim#undef X
10570218822Sdim};
1057189857Sobrien
10572218822Sdim#define NEON_ENC_INTEGER(X) (neon_enc_tab[(X) & 0x0fffffff].integer)
10573218822Sdim#define NEON_ENC_ARMREG(X)  (neon_enc_tab[(X) & 0x0fffffff].integer)
10574218822Sdim#define NEON_ENC_POLY(X)    (neon_enc_tab[(X) & 0x0fffffff].float_or_poly)
10575218822Sdim#define NEON_ENC_FLOAT(X)   (neon_enc_tab[(X) & 0x0fffffff].float_or_poly)
10576218822Sdim#define NEON_ENC_SCALAR(X)  (neon_enc_tab[(X) & 0x0fffffff].scalar_or_imm)
10577218822Sdim#define NEON_ENC_IMMED(X)   (neon_enc_tab[(X) & 0x0fffffff].scalar_or_imm)
10578218822Sdim#define NEON_ENC_INTERLV(X) (neon_enc_tab[(X) & 0x0fffffff].integer)
10579218822Sdim#define NEON_ENC_LANE(X)    (neon_enc_tab[(X) & 0x0fffffff].float_or_poly)
10580218822Sdim#define NEON_ENC_DUP(X)     (neon_enc_tab[(X) & 0x0fffffff].scalar_or_imm)
10581218822Sdim#define NEON_ENC_SINGLE(X) \
10582218822Sdim  ((neon_enc_tab[(X) & 0x0fffffff].integer) | ((X) & 0xf0000000))
10583218822Sdim#define NEON_ENC_DOUBLE(X) \
10584218822Sdim  ((neon_enc_tab[(X) & 0x0fffffff].float_or_poly) | ((X) & 0xf0000000))
1058589857Sobrien
10586218822Sdim/* Define shapes for instruction operands. The following mnemonic characters
10587218822Sdim   are used in this table:
1058889857Sobrien
10589218822Sdim     F - VFP S<n> register
10590218822Sdim     D - Neon D<n> register
10591218822Sdim     Q - Neon Q<n> register
10592218822Sdim     I - Immediate
10593218822Sdim     S - Scalar
10594218822Sdim     R - ARM register
10595218822Sdim     L - D<n> register list
10596218822Sdim
10597218822Sdim   This table is used to generate various data:
10598218822Sdim     - enumerations of the form NS_DDR to be used as arguments to
10599218822Sdim       neon_select_shape.
10600218822Sdim     - a table classifying shapes into single, double, quad, mixed.
10601218822Sdim     - a table used to drive neon_select_shape.
10602218822Sdim*/
1060389857Sobrien
10604218822Sdim#define NEON_SHAPE_DEF			\
10605218822Sdim  X(3, (D, D, D), DOUBLE),		\
10606218822Sdim  X(3, (Q, Q, Q), QUAD),		\
10607218822Sdim  X(3, (D, D, I), DOUBLE),		\
10608218822Sdim  X(3, (Q, Q, I), QUAD),		\
10609218822Sdim  X(3, (D, D, S), DOUBLE),		\
10610218822Sdim  X(3, (Q, Q, S), QUAD),		\
10611218822Sdim  X(2, (D, D), DOUBLE),			\
10612218822Sdim  X(2, (Q, Q), QUAD),			\
10613218822Sdim  X(2, (D, S), DOUBLE),			\
10614218822Sdim  X(2, (Q, S), QUAD),			\
10615218822Sdim  X(2, (D, R), DOUBLE),			\
10616218822Sdim  X(2, (Q, R), QUAD),			\
10617218822Sdim  X(2, (D, I), DOUBLE),			\
10618218822Sdim  X(2, (Q, I), QUAD),			\
10619218822Sdim  X(3, (D, L, D), DOUBLE),		\
10620218822Sdim  X(2, (D, Q), MIXED),			\
10621218822Sdim  X(2, (Q, D), MIXED),			\
10622218822Sdim  X(3, (D, Q, I), MIXED),		\
10623218822Sdim  X(3, (Q, D, I), MIXED),		\
10624218822Sdim  X(3, (Q, D, D), MIXED),		\
10625218822Sdim  X(3, (D, Q, Q), MIXED),		\
10626218822Sdim  X(3, (Q, Q, D), MIXED),		\
10627218822Sdim  X(3, (Q, D, S), MIXED),		\
10628218822Sdim  X(3, (D, Q, S), MIXED),		\
10629218822Sdim  X(4, (D, D, D, I), DOUBLE),		\
10630218822Sdim  X(4, (Q, Q, Q, I), QUAD),		\
10631218822Sdim  X(2, (F, F), SINGLE),			\
10632218822Sdim  X(3, (F, F, F), SINGLE),		\
10633218822Sdim  X(2, (F, I), SINGLE),			\
10634218822Sdim  X(2, (F, D), MIXED),			\
10635218822Sdim  X(2, (D, F), MIXED),			\
10636218822Sdim  X(3, (F, F, I), MIXED),		\
10637218822Sdim  X(4, (R, R, F, F), SINGLE),		\
10638218822Sdim  X(4, (F, F, R, R), SINGLE),		\
10639218822Sdim  X(3, (D, R, R), DOUBLE),		\
10640218822Sdim  X(3, (R, R, D), DOUBLE),		\
10641218822Sdim  X(2, (S, R), SINGLE),			\
10642218822Sdim  X(2, (R, S), SINGLE),			\
10643218822Sdim  X(2, (F, R), SINGLE),			\
10644218822Sdim  X(2, (R, F), SINGLE)
10645218822Sdim
10646218822Sdim#define S2(A,B)		NS_##A##B
10647218822Sdim#define S3(A,B,C)	NS_##A##B##C
10648218822Sdim#define S4(A,B,C,D)	NS_##A##B##C##D
10649218822Sdim
10650218822Sdim#define X(N, L, C) S##N L
10651218822Sdim
10652218822Sdimenum neon_shape
1065389857Sobrien{
10654218822Sdim  NEON_SHAPE_DEF,
10655218822Sdim  NS_NULL
10656218822Sdim};
1065789857Sobrien
10658218822Sdim#undef X
10659218822Sdim#undef S2
10660218822Sdim#undef S3
10661218822Sdim#undef S4
1066289857Sobrien
10663218822Sdimenum neon_shape_class
10664218822Sdim{
10665218822Sdim  SC_SINGLE,
10666218822Sdim  SC_DOUBLE,
10667218822Sdim  SC_QUAD,
10668218822Sdim  SC_MIXED
10669218822Sdim};
1067089857Sobrien
10671218822Sdim#define X(N, L, C) SC_##C
1067289857Sobrien
10673218822Sdimstatic enum neon_shape_class neon_shape_class[] =
1067489857Sobrien{
10675218822Sdim  NEON_SHAPE_DEF
10676218822Sdim};
1067789857Sobrien
10678218822Sdim#undef X
1067989857Sobrien
10680218822Sdimenum neon_shape_el
10681218822Sdim{
10682218822Sdim  SE_F,
10683218822Sdim  SE_D,
10684218822Sdim  SE_Q,
10685218822Sdim  SE_I,
10686218822Sdim  SE_S,
10687218822Sdim  SE_R,
10688218822Sdim  SE_L
10689218822Sdim};
1069089857Sobrien
10691218822Sdim/* Register widths of above.  */
10692218822Sdimstatic unsigned neon_shape_el_size[] =
10693218822Sdim{
10694218822Sdim  32,
10695218822Sdim  64,
10696218822Sdim  128,
10697218822Sdim  0,
10698218822Sdim  32,
10699218822Sdim  32,
10700218822Sdim  0
10701218822Sdim};
1070289857Sobrien
10703218822Sdimstruct neon_shape_info
1070489857Sobrien{
10705218822Sdim  unsigned els;
10706218822Sdim  enum neon_shape_el el[NEON_MAX_TYPE_ELS];
10707218822Sdim};
1070889857Sobrien
10709218822Sdim#define S2(A,B)		{ SE_##A, SE_##B }
10710218822Sdim#define S3(A,B,C)	{ SE_##A, SE_##B, SE_##C }
10711218822Sdim#define S4(A,B,C,D)	{ SE_##A, SE_##B, SE_##C, SE_##D }
1071289857Sobrien
10713218822Sdim#define X(N, L, C) { N, S##N L }
1071489857Sobrien
10715218822Sdimstatic struct neon_shape_info neon_shape_tab[] =
1071689857Sobrien{
10717218822Sdim  NEON_SHAPE_DEF
10718218822Sdim};
1071989857Sobrien
10720218822Sdim#undef X
10721218822Sdim#undef S2
10722218822Sdim#undef S3
10723218822Sdim#undef S4
1072489857Sobrien
10725218822Sdim/* Bit masks used in type checking given instructions.
10726218822Sdim  'N_EQK' means the type must be the same as (or based on in some way) the key
10727218822Sdim   type, which itself is marked with the 'N_KEY' bit. If the 'N_EQK' bit is
10728218822Sdim   set, various other bits can be set as well in order to modify the meaning of
10729218822Sdim   the type constraint.  */
1073089857Sobrien
10731218822Sdimenum neon_type_mask
10732218822Sdim{
10733218822Sdim  N_S8   = 0x000001,
10734218822Sdim  N_S16  = 0x000002,
10735218822Sdim  N_S32  = 0x000004,
10736218822Sdim  N_S64  = 0x000008,
10737218822Sdim  N_U8   = 0x000010,
10738218822Sdim  N_U16  = 0x000020,
10739218822Sdim  N_U32  = 0x000040,
10740218822Sdim  N_U64  = 0x000080,
10741218822Sdim  N_I8   = 0x000100,
10742218822Sdim  N_I16  = 0x000200,
10743218822Sdim  N_I32  = 0x000400,
10744218822Sdim  N_I64  = 0x000800,
10745218822Sdim  N_8    = 0x001000,
10746218822Sdim  N_16   = 0x002000,
10747218822Sdim  N_32   = 0x004000,
10748218822Sdim  N_64   = 0x008000,
10749218822Sdim  N_P8   = 0x010000,
10750218822Sdim  N_P16  = 0x020000,
10751218822Sdim  N_F32  = 0x040000,
10752218822Sdim  N_F64  = 0x080000,
10753218822Sdim  N_KEY  = 0x100000, /* key element (main type specifier).  */
10754218822Sdim  N_EQK  = 0x200000, /* given operand has the same type & size as the key.  */
10755218822Sdim  N_VFP  = 0x400000, /* VFP mode: operand size must match register width.  */
10756218822Sdim  N_DBL  = 0x000001, /* if N_EQK, this operand is twice the size.  */
10757218822Sdim  N_HLF  = 0x000002, /* if N_EQK, this operand is half the size.  */
10758218822Sdim  N_SGN  = 0x000004, /* if N_EQK, this operand is forced to be signed.  */
10759218822Sdim  N_UNS  = 0x000008, /* if N_EQK, this operand is forced to be unsigned.  */
10760218822Sdim  N_INT  = 0x000010, /* if N_EQK, this operand is forced to be integer.  */
10761218822Sdim  N_FLT  = 0x000020, /* if N_EQK, this operand is forced to be float.  */
10762218822Sdim  N_SIZ  = 0x000040, /* if N_EQK, this operand is forced to be size-only.  */
10763218822Sdim  N_UTYP = 0,
10764218822Sdim  N_MAX_NONSPECIAL = N_F64
10765218822Sdim};
1076689857Sobrien
10767218822Sdim#define N_ALLMODS  (N_DBL | N_HLF | N_SGN | N_UNS | N_INT | N_FLT | N_SIZ)
1076889857Sobrien
10769218822Sdim#define N_SU_ALL   (N_S8 | N_S16 | N_S32 | N_S64 | N_U8 | N_U16 | N_U32 | N_U64)
10770218822Sdim#define N_SU_32    (N_S8 | N_S16 | N_S32 | N_U8 | N_U16 | N_U32)
10771218822Sdim#define N_SU_16_64 (N_S16 | N_S32 | N_S64 | N_U16 | N_U32 | N_U64)
10772218822Sdim#define N_SUF_32   (N_SU_32 | N_F32)
10773218822Sdim#define N_I_ALL    (N_I8 | N_I16 | N_I32 | N_I64)
10774218822Sdim#define N_IF_32    (N_I8 | N_I16 | N_I32 | N_F32)
1077589857Sobrien
10776218822Sdim/* Pass this as the first type argument to neon_check_type to ignore types
10777218822Sdim   altogether.  */
10778218822Sdim#define N_IGNORE_TYPE (N_KEY | N_EQK)
1077989857Sobrien
10780218822Sdim/* Select a "shape" for the current instruction (describing register types or
10781218822Sdim   sizes) from a list of alternatives. Return NS_NULL if the current instruction
10782218822Sdim   doesn't fit. For non-polymorphic shapes, checking is usually done as a
10783218822Sdim   function of operand parsing, so this function doesn't need to be called.
10784218822Sdim   Shapes should be listed in order of decreasing length.  */
1078589857Sobrien
10786218822Sdimstatic enum neon_shape
10787218822Sdimneon_select_shape (enum neon_shape shape, ...)
10788218822Sdim{
10789218822Sdim  va_list ap;
10790218822Sdim  enum neon_shape first_shape = shape;
1079189857Sobrien
10792218822Sdim  /* Fix missing optional operands. FIXME: we don't know at this point how
10793218822Sdim     many arguments we should have, so this makes the assumption that we have
10794218822Sdim     > 1. This is true of all current Neon opcodes, I think, but may not be
10795218822Sdim     true in the future.  */
10796218822Sdim  if (!inst.operands[1].present)
10797218822Sdim    inst.operands[1] = inst.operands[0];
1079889857Sobrien
10799218822Sdim  va_start (ap, shape);
10800218822Sdim
10801218822Sdim  for (; shape != NS_NULL; shape = va_arg (ap, int))
10802218822Sdim    {
10803218822Sdim      unsigned j;
10804218822Sdim      int matches = 1;
1080589857Sobrien
10806218822Sdim      for (j = 0; j < neon_shape_tab[shape].els; j++)
10807218822Sdim        {
10808218822Sdim          if (!inst.operands[j].present)
10809218822Sdim            {
10810218822Sdim              matches = 0;
10811218822Sdim              break;
10812218822Sdim            }
1081389857Sobrien
10814218822Sdim          switch (neon_shape_tab[shape].el[j])
10815218822Sdim            {
10816218822Sdim            case SE_F:
10817218822Sdim              if (!(inst.operands[j].isreg
10818218822Sdim                    && inst.operands[j].isvec
10819218822Sdim                    && inst.operands[j].issingle
10820218822Sdim                    && !inst.operands[j].isquad))
10821218822Sdim                matches = 0;
10822218822Sdim              break;
1082389857Sobrien
10824218822Sdim            case SE_D:
10825218822Sdim              if (!(inst.operands[j].isreg
10826218822Sdim                    && inst.operands[j].isvec
10827218822Sdim                    && !inst.operands[j].isquad
10828218822Sdim                    && !inst.operands[j].issingle))
10829218822Sdim                matches = 0;
10830218822Sdim              break;
1083189857Sobrien
10832218822Sdim            case SE_R:
10833218822Sdim              if (!(inst.operands[j].isreg
10834218822Sdim                    && !inst.operands[j].isvec))
10835218822Sdim                matches = 0;
10836218822Sdim              break;
1083789857Sobrien
10838218822Sdim            case SE_Q:
10839218822Sdim              if (!(inst.operands[j].isreg
10840218822Sdim                    && inst.operands[j].isvec
10841218822Sdim                    && inst.operands[j].isquad
10842218822Sdim                    && !inst.operands[j].issingle))
10843218822Sdim                matches = 0;
10844218822Sdim              break;
1084589857Sobrien
10846218822Sdim            case SE_I:
10847218822Sdim              if (!(!inst.operands[j].isreg
10848218822Sdim                    && !inst.operands[j].isscalar))
10849218822Sdim                matches = 0;
10850218822Sdim              break;
1085189857Sobrien
10852218822Sdim            case SE_S:
10853218822Sdim              if (!(!inst.operands[j].isreg
10854218822Sdim                    && inst.operands[j].isscalar))
10855218822Sdim                matches = 0;
10856218822Sdim              break;
10857218822Sdim
10858218822Sdim            case SE_L:
10859218822Sdim              break;
10860218822Sdim            }
10861218822Sdim        }
10862218822Sdim      if (matches)
10863218822Sdim        break;
1086489857Sobrien    }
10865218822Sdim
10866218822Sdim  va_end (ap);
1086789857Sobrien
10868218822Sdim  if (shape == NS_NULL && first_shape != NS_NULL)
10869218822Sdim    first_error (_("invalid instruction shape"));
1087089857Sobrien
10871218822Sdim  return shape;
10872218822Sdim}
1087389857Sobrien
10874218822Sdim/* True if SHAPE is predominantly a quadword operation (most of the time, this
10875218822Sdim   means the Q bit should be set).  */
1087689857Sobrien
10877218822Sdimstatic int
10878218822Sdimneon_quad (enum neon_shape shape)
10879218822Sdim{
10880218822Sdim  return neon_shape_class[shape] == SC_QUAD;
10881218822Sdim}
10882218822Sdim
10883218822Sdimstatic void
10884218822Sdimneon_modify_type_size (unsigned typebits, enum neon_el_type *g_type,
10885218822Sdim                       unsigned *g_size)
10886218822Sdim{
10887218822Sdim  /* Allow modification to be made to types which are constrained to be
10888218822Sdim     based on the key element, based on bits set alongside N_EQK.  */
10889218822Sdim  if ((typebits & N_EQK) != 0)
1089089857Sobrien    {
10891218822Sdim      if ((typebits & N_HLF) != 0)
10892218822Sdim	*g_size /= 2;
10893218822Sdim      else if ((typebits & N_DBL) != 0)
10894218822Sdim	*g_size *= 2;
10895218822Sdim      if ((typebits & N_SGN) != 0)
10896218822Sdim	*g_type = NT_signed;
10897218822Sdim      else if ((typebits & N_UNS) != 0)
10898218822Sdim        *g_type = NT_unsigned;
10899218822Sdim      else if ((typebits & N_INT) != 0)
10900218822Sdim        *g_type = NT_integer;
10901218822Sdim      else if ((typebits & N_FLT) != 0)
10902218822Sdim        *g_type = NT_float;
10903218822Sdim      else if ((typebits & N_SIZ) != 0)
10904218822Sdim        *g_type = NT_untyped;
1090589857Sobrien    }
10906218822Sdim}
10907218822Sdim
10908218822Sdim/* Return operand OPNO promoted by bits set in THISARG. KEY should be the "key"
10909218822Sdim   operand type, i.e. the single type specified in a Neon instruction when it
10910218822Sdim   is the only one given.  */
1091189857Sobrien
10912218822Sdimstatic struct neon_type_el
10913218822Sdimneon_type_promote (struct neon_type_el *key, unsigned thisarg)
10914218822Sdim{
10915218822Sdim  struct neon_type_el dest = *key;
10916218822Sdim
10917218822Sdim  assert ((thisarg & N_EQK) != 0);
10918218822Sdim
10919218822Sdim  neon_modify_type_size (thisarg, &dest.type, &dest.size);
10920218822Sdim
10921218822Sdim  return dest;
1092289857Sobrien}
1092389857Sobrien
10924218822Sdim/* Convert Neon type and size into compact bitmask representation.  */
10925218822Sdim
10926218822Sdimstatic enum neon_type_mask
10927218822Sdimtype_chk_of_el_type (enum neon_el_type type, unsigned size)
1092889857Sobrien{
10929218822Sdim  switch (type)
10930218822Sdim    {
10931218822Sdim    case NT_untyped:
10932218822Sdim      switch (size)
10933218822Sdim        {
10934218822Sdim        case 8:  return N_8;
10935218822Sdim        case 16: return N_16;
10936218822Sdim        case 32: return N_32;
10937218822Sdim        case 64: return N_64;
10938218822Sdim        default: ;
10939218822Sdim        }
10940218822Sdim      break;
1094189857Sobrien
10942218822Sdim    case NT_integer:
10943218822Sdim      switch (size)
10944218822Sdim        {
10945218822Sdim        case 8:  return N_I8;
10946218822Sdim        case 16: return N_I16;
10947218822Sdim        case 32: return N_I32;
10948218822Sdim        case 64: return N_I64;
10949218822Sdim        default: ;
10950218822Sdim        }
10951218822Sdim      break;
1095289857Sobrien
10953218822Sdim    case NT_float:
10954218822Sdim      switch (size)
10955218822Sdim        {
10956218822Sdim        case 32: return N_F32;
10957218822Sdim        case 64: return N_F64;
10958218822Sdim        default: ;
10959218822Sdim        }
10960218822Sdim      break;
1096189857Sobrien
10962218822Sdim    case NT_poly:
10963218822Sdim      switch (size)
10964218822Sdim        {
10965218822Sdim        case 8:  return N_P8;
10966218822Sdim        case 16: return N_P16;
10967218822Sdim        default: ;
10968218822Sdim        }
10969218822Sdim      break;
1097089857Sobrien
10971218822Sdim    case NT_signed:
10972218822Sdim      switch (size)
10973218822Sdim        {
10974218822Sdim        case 8:  return N_S8;
10975218822Sdim        case 16: return N_S16;
10976218822Sdim        case 32: return N_S32;
10977218822Sdim        case 64: return N_S64;
10978218822Sdim        default: ;
10979218822Sdim        }
10980218822Sdim      break;
1098189857Sobrien
10982218822Sdim    case NT_unsigned:
10983218822Sdim      switch (size)
10984218822Sdim        {
10985218822Sdim        case 8:  return N_U8;
10986218822Sdim        case 16: return N_U16;
10987218822Sdim        case 32: return N_U32;
10988218822Sdim        case 64: return N_U64;
10989218822Sdim        default: ;
10990218822Sdim        }
10991218822Sdim      break;
1099289857Sobrien
10993218822Sdim    default: ;
10994218822Sdim    }
10995218822Sdim
10996218822Sdim  return N_UTYP;
10997218822Sdim}
1099889857Sobrien
10999218822Sdim/* Convert compact Neon bitmask type representation to a type and size. Only
11000218822Sdim   handles the case where a single bit is set in the mask.  */
1100189857Sobrien
11002218822Sdimstatic int
11003218822Sdimel_type_of_type_chk (enum neon_el_type *type, unsigned *size,
11004218822Sdim                     enum neon_type_mask mask)
11005218822Sdim{
11006218822Sdim  if ((mask & N_EQK) != 0)
11007218822Sdim    return FAIL;
1100889857Sobrien
11009218822Sdim  if ((mask & (N_S8 | N_U8 | N_I8 | N_8 | N_P8)) != 0)
11010218822Sdim    *size = 8;
11011218822Sdim  else if ((mask & (N_S16 | N_U16 | N_I16 | N_16 | N_P16)) != 0)
11012218822Sdim    *size = 16;
11013218822Sdim  else if ((mask & (N_S32 | N_U32 | N_I32 | N_32 | N_F32)) != 0)
11014218822Sdim    *size = 32;
11015218822Sdim  else if ((mask & (N_S64 | N_U64 | N_I64 | N_64 | N_F64)) != 0)
11016218822Sdim    *size = 64;
11017218822Sdim  else
11018218822Sdim    return FAIL;
1101989857Sobrien
11020218822Sdim  if ((mask & (N_S8 | N_S16 | N_S32 | N_S64)) != 0)
11021218822Sdim    *type = NT_signed;
11022218822Sdim  else if ((mask & (N_U8 | N_U16 | N_U32 | N_U64)) != 0)
11023218822Sdim    *type = NT_unsigned;
11024218822Sdim  else if ((mask & (N_I8 | N_I16 | N_I32 | N_I64)) != 0)
11025218822Sdim    *type = NT_integer;
11026218822Sdim  else if ((mask & (N_8 | N_16 | N_32 | N_64)) != 0)
11027218822Sdim    *type = NT_untyped;
11028218822Sdim  else if ((mask & (N_P8 | N_P16)) != 0)
11029218822Sdim    *type = NT_poly;
11030218822Sdim  else if ((mask & (N_F32 | N_F64)) != 0)
11031218822Sdim    *type = NT_float;
11032218822Sdim  else
11033218822Sdim    return FAIL;
11034218822Sdim
11035218822Sdim  return SUCCESS;
11036218822Sdim}
1103789857Sobrien
11038218822Sdim/* Modify a bitmask of allowed types. This is only needed for type
11039218822Sdim   relaxation.  */
1104089857Sobrien
11041218822Sdimstatic unsigned
11042218822Sdimmodify_types_allowed (unsigned allowed, unsigned mods)
11043218822Sdim{
11044218822Sdim  unsigned size;
11045218822Sdim  enum neon_el_type type;
11046218822Sdim  unsigned destmask;
11047218822Sdim  int i;
11048218822Sdim
11049218822Sdim  destmask = 0;
11050218822Sdim
11051218822Sdim  for (i = 1; i <= N_MAX_NONSPECIAL; i <<= 1)
11052218822Sdim    {
11053218822Sdim      if (el_type_of_type_chk (&type, &size, allowed & i) == SUCCESS)
11054218822Sdim        {
11055218822Sdim          neon_modify_type_size (mods, &type, &size);
11056218822Sdim          destmask |= type_chk_of_el_type (type, size);
11057218822Sdim        }
11058218822Sdim    }
11059218822Sdim
11060218822Sdim  return destmask;
11061218822Sdim}
1106289857Sobrien
11063218822Sdim/* Check type and return type classification.
11064218822Sdim   The manual states (paraphrase): If one datatype is given, it indicates the
11065218822Sdim   type given in:
11066218822Sdim    - the second operand, if there is one
11067218822Sdim    - the operand, if there is no second operand
11068218822Sdim    - the result, if there are no operands.
11069218822Sdim   This isn't quite good enough though, so we use a concept of a "key" datatype
11070218822Sdim   which is set on a per-instruction basis, which is the one which matters when
11071218822Sdim   only one data type is written.
11072218822Sdim   Note: this function has side-effects (e.g. filling in missing operands). All
11073218822Sdim   Neon instructions should call it before performing bit encoding.  */
1107489857Sobrien
11075218822Sdimstatic struct neon_type_el
11076218822Sdimneon_check_type (unsigned els, enum neon_shape ns, ...)
11077218822Sdim{
11078218822Sdim  va_list ap;
11079218822Sdim  unsigned i, pass, key_el = 0;
11080218822Sdim  unsigned types[NEON_MAX_TYPE_ELS];
11081218822Sdim  enum neon_el_type k_type = NT_invtype;
11082218822Sdim  unsigned k_size = -1u;
11083218822Sdim  struct neon_type_el badtype = {NT_invtype, -1};
11084218822Sdim  unsigned key_allowed = 0;
1108589857Sobrien
11086218822Sdim  /* Optional registers in Neon instructions are always (not) in operand 1.
11087218822Sdim     Fill in the missing operand here, if it was omitted.  */
11088218822Sdim  if (els > 1 && !inst.operands[1].present)
11089218822Sdim    inst.operands[1] = inst.operands[0];
1109089857Sobrien
11091218822Sdim  /* Suck up all the varargs.  */
11092218822Sdim  va_start (ap, ns);
11093218822Sdim  for (i = 0; i < els; i++)
11094218822Sdim    {
11095218822Sdim      unsigned thisarg = va_arg (ap, unsigned);
11096218822Sdim      if (thisarg == N_IGNORE_TYPE)
11097218822Sdim        {
11098218822Sdim          va_end (ap);
11099218822Sdim          return badtype;
11100218822Sdim        }
11101218822Sdim      types[i] = thisarg;
11102218822Sdim      if ((thisarg & N_KEY) != 0)
11103218822Sdim        key_el = i;
1110489857Sobrien    }
11105218822Sdim  va_end (ap);
1110689857Sobrien
11107218822Sdim  if (inst.vectype.elems > 0)
11108218822Sdim    for (i = 0; i < els; i++)
11109218822Sdim      if (inst.operands[i].vectype.type != NT_invtype)
11110218822Sdim        {
11111218822Sdim          first_error (_("types specified in both the mnemonic and operands"));
11112218822Sdim          return badtype;
11113218822Sdim        }
11114218822Sdim
11115218822Sdim  /* Duplicate inst.vectype elements here as necessary.
11116218822Sdim     FIXME: No idea if this is exactly the same as the ARM assembler,
11117218822Sdim     particularly when an insn takes one register and one non-register
11118218822Sdim     operand. */
11119218822Sdim  if (inst.vectype.elems == 1 && els > 1)
1112089857Sobrien    {
11121218822Sdim      unsigned j;
11122218822Sdim      inst.vectype.elems = els;
11123218822Sdim      inst.vectype.el[key_el] = inst.vectype.el[0];
11124218822Sdim      for (j = 0; j < els; j++)
11125218822Sdim        if (j != key_el)
11126218822Sdim          inst.vectype.el[j] = neon_type_promote (&inst.vectype.el[key_el],
11127218822Sdim                                                  types[j]);
1112889857Sobrien    }
11129218822Sdim  else if (inst.vectype.elems == 0 && els > 0)
11130218822Sdim    {
11131218822Sdim      unsigned j;
11132218822Sdim      /* No types were given after the mnemonic, so look for types specified
11133218822Sdim         after each operand. We allow some flexibility here; as long as the
11134218822Sdim         "key" operand has a type, we can infer the others.  */
11135218822Sdim      for (j = 0; j < els; j++)
11136218822Sdim        if (inst.operands[j].vectype.type != NT_invtype)
11137218822Sdim          inst.vectype.el[j] = inst.operands[j].vectype;
1113889857Sobrien
11139218822Sdim      if (inst.operands[key_el].vectype.type != NT_invtype)
11140218822Sdim        {
11141218822Sdim          for (j = 0; j < els; j++)
11142218822Sdim            if (inst.operands[j].vectype.type == NT_invtype)
11143218822Sdim              inst.vectype.el[j] = neon_type_promote (&inst.vectype.el[key_el],
11144218822Sdim                                                      types[j]);
11145218822Sdim        }
11146218822Sdim      else
11147218822Sdim        {
11148218822Sdim          first_error (_("operand types can't be inferred"));
11149218822Sdim          return badtype;
11150218822Sdim        }
11151218822Sdim    }
11152218822Sdim  else if (inst.vectype.elems != els)
11153218822Sdim    {
11154218822Sdim      first_error (_("type specifier has the wrong number of parts"));
11155218822Sdim      return badtype;
11156218822Sdim    }
1115789857Sobrien
11158218822Sdim  for (pass = 0; pass < 2; pass++)
11159218822Sdim    {
11160218822Sdim      for (i = 0; i < els; i++)
11161218822Sdim        {
11162218822Sdim          unsigned thisarg = types[i];
11163218822Sdim          unsigned types_allowed = ((thisarg & N_EQK) != 0 && pass != 0)
11164218822Sdim            ? modify_types_allowed (key_allowed, thisarg) : thisarg;
11165218822Sdim          enum neon_el_type g_type = inst.vectype.el[i].type;
11166218822Sdim          unsigned g_size = inst.vectype.el[i].size;
1116789857Sobrien
11168218822Sdim          /* Decay more-specific signed & unsigned types to sign-insensitive
11169218822Sdim	     integer types if sign-specific variants are unavailable.  */
11170218822Sdim          if ((g_type == NT_signed || g_type == NT_unsigned)
11171218822Sdim	      && (types_allowed & N_SU_ALL) == 0)
11172218822Sdim	    g_type = NT_integer;
1117389857Sobrien
11174218822Sdim          /* If only untyped args are allowed, decay any more specific types to
11175218822Sdim	     them. Some instructions only care about signs for some element
11176218822Sdim	     sizes, so handle that properly.  */
11177218822Sdim          if ((g_size == 8 && (types_allowed & N_8) != 0)
11178218822Sdim	      || (g_size == 16 && (types_allowed & N_16) != 0)
11179218822Sdim	      || (g_size == 32 && (types_allowed & N_32) != 0)
11180218822Sdim	      || (g_size == 64 && (types_allowed & N_64) != 0))
11181218822Sdim	    g_type = NT_untyped;
11182218822Sdim
11183218822Sdim          if (pass == 0)
11184218822Sdim            {
11185218822Sdim              if ((thisarg & N_KEY) != 0)
11186218822Sdim                {
11187218822Sdim                  k_type = g_type;
11188218822Sdim                  k_size = g_size;
11189218822Sdim                  key_allowed = thisarg & ~N_KEY;
11190218822Sdim                }
11191218822Sdim            }
11192218822Sdim          else
11193218822Sdim            {
11194218822Sdim              if ((thisarg & N_VFP) != 0)
11195218822Sdim                {
11196218822Sdim                  enum neon_shape_el regshape = neon_shape_tab[ns].el[i];
11197218822Sdim                  unsigned regwidth = neon_shape_el_size[regshape], match;
11198218822Sdim
11199218822Sdim                  /* In VFP mode, operands must match register widths. If we
11200218822Sdim                     have a key operand, use its width, else use the width of
11201218822Sdim                     the current operand.  */
11202218822Sdim                  if (k_size != -1u)
11203218822Sdim                    match = k_size;
11204218822Sdim                  else
11205218822Sdim                    match = g_size;
11206218822Sdim
11207218822Sdim                  if (regwidth != match)
11208218822Sdim                    {
11209218822Sdim                      first_error (_("operand size must match register width"));
11210218822Sdim                      return badtype;
11211218822Sdim                    }
11212218822Sdim                }
11213218822Sdim
11214218822Sdim              if ((thisarg & N_EQK) == 0)
11215218822Sdim                {
11216218822Sdim                  unsigned given_type = type_chk_of_el_type (g_type, g_size);
11217218822Sdim
11218218822Sdim                  if ((given_type & types_allowed) == 0)
11219218822Sdim                    {
11220218822Sdim	              first_error (_("bad type in Neon instruction"));
11221218822Sdim	              return badtype;
11222218822Sdim                    }
11223218822Sdim                }
11224218822Sdim              else
11225218822Sdim                {
11226218822Sdim                  enum neon_el_type mod_k_type = k_type;
11227218822Sdim                  unsigned mod_k_size = k_size;
11228218822Sdim                  neon_modify_type_size (thisarg, &mod_k_type, &mod_k_size);
11229218822Sdim                  if (g_type != mod_k_type || g_size != mod_k_size)
11230218822Sdim                    {
11231218822Sdim                      first_error (_("inconsistent types in Neon instruction"));
11232218822Sdim                      return badtype;
11233218822Sdim                    }
11234218822Sdim                }
11235218822Sdim            }
11236218822Sdim        }
1123789857Sobrien    }
1123889857Sobrien
11239218822Sdim  return inst.vectype.el[key_el];
1124089857Sobrien}
1124189857Sobrien
11242218822Sdim/* Neon-style VFP instruction forwarding.  */
11243218822Sdim
11244218822Sdim/* Thumb VFP instructions have 0xE in the condition field.  */
11245218822Sdim
1124689857Sobrienstatic void
11247218822Sdimdo_vfp_cond_or_thumb (void)
1124889857Sobrien{
11249218822Sdim  if (thumb_mode)
11250218822Sdim    inst.instruction |= 0xe0000000;
11251218822Sdim  else
11252218822Sdim    inst.instruction |= inst.cond << 28;
11253218822Sdim}
1125489857Sobrien
11255218822Sdim/* Look up and encode a simple mnemonic, for use as a helper function for the
11256218822Sdim   Neon-style VFP syntax.  This avoids duplication of bits of the insns table,
11257218822Sdim   etc.  It is assumed that operand parsing has already been done, and that the
11258218822Sdim   operands are in the form expected by the given opcode (this isn't necessarily
11259218822Sdim   the same as the form in which they were parsed, hence some massaging must
11260218822Sdim   take place before this function is called).
11261218822Sdim   Checks current arch version against that in the looked-up opcode.  */
1126289857Sobrien
11263218822Sdimstatic void
11264218822Sdimdo_vfp_nsyn_opcode (const char *opname)
11265218822Sdim{
11266218822Sdim  const struct asm_opcode *opcode;
11267218822Sdim
11268218822Sdim  opcode = hash_find (arm_ops_hsh, opname);
1126989857Sobrien
11270218822Sdim  if (!opcode)
11271218822Sdim    abort ();
1127289857Sobrien
11273218822Sdim  constraint (!ARM_CPU_HAS_FEATURE (cpu_variant,
11274218822Sdim                thumb_mode ? *opcode->tvariant : *opcode->avariant),
11275218822Sdim              _(BAD_FPU));
11276218822Sdim
11277218822Sdim  if (thumb_mode)
1127889857Sobrien    {
11279218822Sdim      inst.instruction = opcode->tvalue;
11280218822Sdim      opcode->tencode ();
1128189857Sobrien    }
11282218822Sdim  else
1128389857Sobrien    {
11284218822Sdim      inst.instruction = (inst.cond << 28) | opcode->avalue;
11285218822Sdim      opcode->aencode ();
1128689857Sobrien    }
1128789857Sobrien}
1128889857Sobrien
1128989857Sobrienstatic void
11290218822Sdimdo_vfp_nsyn_add_sub (enum neon_shape rs)
1129189857Sobrien{
11292218822Sdim  int is_add = (inst.instruction & 0x0fffffff) == N_MNEM_vadd;
1129389857Sobrien
11294218822Sdim  if (rs == NS_FFF)
11295218822Sdim    {
11296218822Sdim      if (is_add)
11297218822Sdim        do_vfp_nsyn_opcode ("fadds");
11298218822Sdim      else
11299218822Sdim        do_vfp_nsyn_opcode ("fsubs");
11300218822Sdim    }
11301218822Sdim  else
11302218822Sdim    {
11303218822Sdim      if (is_add)
11304218822Sdim        do_vfp_nsyn_opcode ("faddd");
11305218822Sdim      else
11306218822Sdim        do_vfp_nsyn_opcode ("fsubd");
11307218822Sdim    }
11308218822Sdim}
1130989857Sobrien
11310218822Sdim/* Check operand types to see if this is a VFP instruction, and if so call
11311218822Sdim   PFN ().  */
1131289857Sobrien
11313218822Sdimstatic int
11314218822Sdimtry_vfp_nsyn (int args, void (*pfn) (enum neon_shape))
11315218822Sdim{
11316218822Sdim  enum neon_shape rs;
11317218822Sdim  struct neon_type_el et;
1131889857Sobrien
11319218822Sdim  switch (args)
1132089857Sobrien    {
11321218822Sdim    case 2:
11322218822Sdim      rs = neon_select_shape (NS_FF, NS_DD, NS_NULL);
11323218822Sdim      et = neon_check_type (2, rs,
11324218822Sdim        N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
11325218822Sdim      break;
11326218822Sdim
11327218822Sdim    case 3:
11328218822Sdim      rs = neon_select_shape (NS_FFF, NS_DDD, NS_NULL);
11329218822Sdim      et = neon_check_type (3, rs,
11330218822Sdim        N_EQK | N_VFP, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
11331218822Sdim      break;
11332218822Sdim
11333218822Sdim    default:
11334218822Sdim      abort ();
1133589857Sobrien    }
1133689857Sobrien
11337218822Sdim  if (et.type != NT_invtype)
1133889857Sobrien    {
11339218822Sdim      pfn (rs);
11340218822Sdim      return SUCCESS;
1134189857Sobrien    }
11342218822Sdim  else
11343218822Sdim    inst.error = NULL;
1134489857Sobrien
11345218822Sdim  return FAIL;
1134689857Sobrien}
1134789857Sobrien
1134889857Sobrienstatic void
11349218822Sdimdo_vfp_nsyn_mla_mls (enum neon_shape rs)
1135089857Sobrien{
11351218822Sdim  int is_mla = (inst.instruction & 0x0fffffff) == N_MNEM_vmla;
11352218822Sdim
11353218822Sdim  if (rs == NS_FFF)
11354218822Sdim    {
11355218822Sdim      if (is_mla)
11356218822Sdim        do_vfp_nsyn_opcode ("fmacs");
11357218822Sdim      else
11358218822Sdim        do_vfp_nsyn_opcode ("fmscs");
11359218822Sdim    }
11360218822Sdim  else
11361218822Sdim    {
11362218822Sdim      if (is_mla)
11363218822Sdim        do_vfp_nsyn_opcode ("fmacd");
11364218822Sdim      else
11365218822Sdim        do_vfp_nsyn_opcode ("fmscd");
11366218822Sdim    }
1136789857Sobrien}
1136889857Sobrien
1136989857Sobrienstatic void
11370218822Sdimdo_vfp_nsyn_mul (enum neon_shape rs)
1137189857Sobrien{
11372218822Sdim  if (rs == NS_FFF)
11373218822Sdim    do_vfp_nsyn_opcode ("fmuls");
11374218822Sdim  else
11375218822Sdim    do_vfp_nsyn_opcode ("fmuld");
1137689857Sobrien}
1137789857Sobrien
1137889857Sobrienstatic void
11379218822Sdimdo_vfp_nsyn_abs_neg (enum neon_shape rs)
1138089857Sobrien{
11381218822Sdim  int is_neg = (inst.instruction & 0x80) != 0;
11382218822Sdim  neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_VFP | N_KEY);
11383218822Sdim
11384218822Sdim  if (rs == NS_FF)
11385218822Sdim    {
11386218822Sdim      if (is_neg)
11387218822Sdim        do_vfp_nsyn_opcode ("fnegs");
11388218822Sdim      else
11389218822Sdim        do_vfp_nsyn_opcode ("fabss");
11390218822Sdim    }
11391218822Sdim  else
11392218822Sdim    {
11393218822Sdim      if (is_neg)
11394218822Sdim        do_vfp_nsyn_opcode ("fnegd");
11395218822Sdim      else
11396218822Sdim        do_vfp_nsyn_opcode ("fabsd");
11397218822Sdim    }
1139889857Sobrien}
1139989857Sobrien
11400218822Sdim/* Encode single-precision (only!) VFP fldm/fstm instructions. Double precision
11401218822Sdim   insns belong to Neon, and are handled elsewhere.  */
11402218822Sdim
1140389857Sobrienstatic void
11404218822Sdimdo_vfp_nsyn_ldm_stm (int is_dbmode)
1140589857Sobrien{
11406218822Sdim  int is_ldm = (inst.instruction & (1 << 20)) != 0;
11407218822Sdim  if (is_ldm)
11408218822Sdim    {
11409218822Sdim      if (is_dbmode)
11410218822Sdim        do_vfp_nsyn_opcode ("fldmdbs");
11411218822Sdim      else
11412218822Sdim        do_vfp_nsyn_opcode ("fldmias");
11413218822Sdim    }
11414218822Sdim  else
11415218822Sdim    {
11416218822Sdim      if (is_dbmode)
11417218822Sdim        do_vfp_nsyn_opcode ("fstmdbs");
11418218822Sdim      else
11419218822Sdim        do_vfp_nsyn_opcode ("fstmias");
11420218822Sdim    }
1142189857Sobrien}
1142289857Sobrien
1142389857Sobrienstatic void
11424218822Sdimdo_vfp_nsyn_sqrt (void)
1142589857Sobrien{
11426218822Sdim  enum neon_shape rs = neon_select_shape (NS_FF, NS_DD, NS_NULL);
11427218822Sdim  neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
11428218822Sdim
11429218822Sdim  if (rs == NS_FF)
11430218822Sdim    do_vfp_nsyn_opcode ("fsqrts");
11431218822Sdim  else
11432218822Sdim    do_vfp_nsyn_opcode ("fsqrtd");
1143389857Sobrien}
1143489857Sobrien
1143589857Sobrienstatic void
11436218822Sdimdo_vfp_nsyn_div (void)
1143789857Sobrien{
11438218822Sdim  enum neon_shape rs = neon_select_shape (NS_FFF, NS_DDD, NS_NULL);
11439218822Sdim  neon_check_type (3, rs, N_EQK | N_VFP, N_EQK | N_VFP,
11440218822Sdim    N_F32 | N_F64 | N_KEY | N_VFP);
11441218822Sdim
11442218822Sdim  if (rs == NS_FFF)
11443218822Sdim    do_vfp_nsyn_opcode ("fdivs");
11444218822Sdim  else
11445218822Sdim    do_vfp_nsyn_opcode ("fdivd");
1144689857Sobrien}
1144789857Sobrien
1144889857Sobrienstatic void
11449218822Sdimdo_vfp_nsyn_nmul (void)
1145089857Sobrien{
11451218822Sdim  enum neon_shape rs = neon_select_shape (NS_FFF, NS_DDD, NS_NULL);
11452218822Sdim  neon_check_type (3, rs, N_EQK | N_VFP, N_EQK | N_VFP,
11453218822Sdim    N_F32 | N_F64 | N_KEY | N_VFP);
11454218822Sdim
11455218822Sdim  if (rs == NS_FFF)
1145689857Sobrien    {
11457218822Sdim      inst.instruction = NEON_ENC_SINGLE (inst.instruction);
11458218822Sdim      do_vfp_sp_dyadic ();
1145989857Sobrien    }
11460218822Sdim  else
11461218822Sdim    {
11462218822Sdim      inst.instruction = NEON_ENC_DOUBLE (inst.instruction);
11463218822Sdim      do_vfp_dp_rd_rn_rm ();
11464218822Sdim    }
11465218822Sdim  do_vfp_cond_or_thumb ();
1146689857Sobrien}
1146789857Sobrien
1146889857Sobrienstatic void
11469218822Sdimdo_vfp_nsyn_cmp (void)
1147089857Sobrien{
11471218822Sdim  if (inst.operands[1].isreg)
1147289857Sobrien    {
11473218822Sdim      enum neon_shape rs = neon_select_shape (NS_FF, NS_DD, NS_NULL);
11474218822Sdim      neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
11475218822Sdim
11476218822Sdim      if (rs == NS_FF)
11477218822Sdim        {
11478218822Sdim          inst.instruction = NEON_ENC_SINGLE (inst.instruction);
11479218822Sdim          do_vfp_sp_monadic ();
11480218822Sdim        }
11481218822Sdim      else
11482218822Sdim        {
11483218822Sdim          inst.instruction = NEON_ENC_DOUBLE (inst.instruction);
11484218822Sdim          do_vfp_dp_rd_rm ();
11485218822Sdim        }
1148689857Sobrien    }
11487218822Sdim  else
11488218822Sdim    {
11489218822Sdim      enum neon_shape rs = neon_select_shape (NS_FI, NS_DI, NS_NULL);
11490218822Sdim      neon_check_type (2, rs, N_F32 | N_F64 | N_KEY | N_VFP, N_EQK);
1149189857Sobrien
11492218822Sdim      switch (inst.instruction & 0x0fffffff)
11493218822Sdim        {
11494218822Sdim        case N_MNEM_vcmp:
11495218822Sdim          inst.instruction += N_MNEM_vcmpz - N_MNEM_vcmp;
11496218822Sdim          break;
11497218822Sdim        case N_MNEM_vcmpe:
11498218822Sdim          inst.instruction += N_MNEM_vcmpez - N_MNEM_vcmpe;
11499218822Sdim          break;
11500218822Sdim        default:
11501218822Sdim          abort ();
11502218822Sdim        }
11503218822Sdim
11504218822Sdim      if (rs == NS_FI)
11505218822Sdim        {
11506218822Sdim          inst.instruction = NEON_ENC_SINGLE (inst.instruction);
11507218822Sdim          do_vfp_sp_compare_z ();
11508218822Sdim        }
11509218822Sdim      else
11510218822Sdim        {
11511218822Sdim          inst.instruction = NEON_ENC_DOUBLE (inst.instruction);
11512218822Sdim          do_vfp_dp_rd ();
11513218822Sdim        }
11514218822Sdim    }
11515218822Sdim  do_vfp_cond_or_thumb ();
1151689857Sobrien}
1151789857Sobrien
1151889857Sobrienstatic void
11519218822Sdimnsyn_insert_sp (void)
1152089857Sobrien{
11521218822Sdim  inst.operands[1] = inst.operands[0];
11522218822Sdim  memset (&inst.operands[0], '\0', sizeof (inst.operands[0]));
11523218822Sdim  inst.operands[0].reg = 13;
11524218822Sdim  inst.operands[0].isreg = 1;
11525218822Sdim  inst.operands[0].writeback = 1;
11526218822Sdim  inst.operands[0].present = 1;
11527218822Sdim}
1152889857Sobrien
11529218822Sdimstatic void
11530218822Sdimdo_vfp_nsyn_push (void)
11531218822Sdim{
11532218822Sdim  nsyn_insert_sp ();
11533218822Sdim  if (inst.operands[1].issingle)
11534218822Sdim    do_vfp_nsyn_opcode ("fstmdbs");
11535218822Sdim  else
11536218822Sdim    do_vfp_nsyn_opcode ("fstmdbd");
1153789857Sobrien}
1153889857Sobrien
1153989857Sobrienstatic void
11540218822Sdimdo_vfp_nsyn_pop (void)
1154189857Sobrien{
11542218822Sdim  nsyn_insert_sp ();
11543218822Sdim  if (inst.operands[1].issingle)
11544218822Sdim    do_vfp_nsyn_opcode ("fldmias");
11545218822Sdim  else
11546218822Sdim    do_vfp_nsyn_opcode ("fldmiad");
11547218822Sdim}
1154889857Sobrien
11549218822Sdim/* Fix up Neon data-processing instructions, ORing in the correct bits for
11550218822Sdim   ARM mode or Thumb mode and moving the encoded bit 24 to bit 28.  */
1155189857Sobrien
11552218822Sdimstatic unsigned
11553218822Sdimneon_dp_fixup (unsigned i)
11554218822Sdim{
11555218822Sdim  if (thumb_mode)
1155689857Sobrien    {
11557218822Sdim      /* The U bit is at bit 24 by default. Move to bit 28 in Thumb mode.  */
11558218822Sdim      if (i & (1 << 24))
11559218822Sdim        i |= 1 << 28;
11560218822Sdim
11561218822Sdim      i &= ~(1 << 24);
11562218822Sdim
11563218822Sdim      i |= 0xef000000;
1156489857Sobrien    }
11565218822Sdim  else
11566218822Sdim    i |= 0xf2000000;
11567218822Sdim
11568218822Sdim  return i;
11569218822Sdim}
1157089857Sobrien
11571218822Sdim/* Turn a size (8, 16, 32, 64) into the respective bit number minus 3
11572218822Sdim   (0, 1, 2, 3).  */
11573218822Sdim
11574218822Sdimstatic unsigned
11575218822Sdimneon_logbits (unsigned x)
11576218822Sdim{
11577218822Sdim  return ffs (x) - 4;
1157889857Sobrien}
1157989857Sobrien
11580218822Sdim#define LOW4(R) ((R) & 0xf)
11581218822Sdim#define HI1(R) (((R) >> 4) & 1)
1158260484Sobrien
11583218822Sdim/* Encode insns with bit pattern:
1158477298Sobrien
11585218822Sdim  |28/24|23|22 |21 20|19 16|15 12|11    8|7|6|5|4|3  0|
11586218822Sdim  |  U  |x |D  |size | Rn  | Rd  |x x x x|N|Q|M|x| Rm |
11587218822Sdim
11588218822Sdim  SIZE is passed in bits. -1 means size field isn't changed, in case it has a
11589218822Sdim  different meaning for some instruction.  */
11590218822Sdim
11591218822Sdimstatic void
11592218822Sdimneon_three_same (int isquad, int ubit, int size)
1159360484Sobrien{
11594218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
11595218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
11596218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
11597218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
11598218822Sdim  inst.instruction |= LOW4 (inst.operands[2].reg);
11599218822Sdim  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
11600218822Sdim  inst.instruction |= (isquad != 0) << 6;
11601218822Sdim  inst.instruction |= (ubit != 0) << 24;
11602218822Sdim  if (size != -1)
11603218822Sdim    inst.instruction |= neon_logbits (size) << 20;
11604218822Sdim
11605218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
11606218822Sdim}
1160760484Sobrien
11608218822Sdim/* Encode instructions of the form:
1160960484Sobrien
11610218822Sdim  |28/24|23|22|21 20|19 18|17 16|15 12|11      7|6|5|4|3  0|
11611218822Sdim  |  U  |x |D |x  x |size |x  x | Rd  |x x x x x|Q|M|x| Rm |
1161260484Sobrien
11613218822Sdim  Don't write size if SIZE == -1.  */
1161460484Sobrien
11615218822Sdimstatic void
11616218822Sdimneon_two_same (int qbit, int ubit, int size)
11617218822Sdim{
11618218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
11619218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
11620218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg);
11621218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 5;
11622218822Sdim  inst.instruction |= (qbit != 0) << 6;
11623218822Sdim  inst.instruction |= (ubit != 0) << 24;
1162460484Sobrien
11625218822Sdim  if (size != -1)
11626218822Sdim    inst.instruction |= neon_logbits (size) << 18;
11627218822Sdim
11628218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1162960484Sobrien}
1163060484Sobrien
11631218822Sdim/* Neon instruction encoders, in approximate order of appearance.  */
1163277298Sobrien
1163360484Sobrienstatic void
11634218822Sdimdo_neon_dyadic_i_su (void)
1163560484Sobrien{
11636218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11637218822Sdim  struct neon_type_el et = neon_check_type (3, rs,
11638218822Sdim    N_EQK, N_EQK, N_SU_32 | N_KEY);
11639218822Sdim  neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
11640218822Sdim}
1164160484Sobrien
11642218822Sdimstatic void
11643218822Sdimdo_neon_dyadic_i64_su (void)
11644218822Sdim{
11645218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11646218822Sdim  struct neon_type_el et = neon_check_type (3, rs,
11647218822Sdim    N_EQK, N_EQK, N_SU_ALL | N_KEY);
11648218822Sdim  neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
11649218822Sdim}
1165060484Sobrien
11651218822Sdimstatic void
11652218822Sdimneon_imm_shift (int write_ubit, int uval, int isquad, struct neon_type_el et,
11653218822Sdim                unsigned immbits)
11654218822Sdim{
11655218822Sdim  unsigned size = et.size >> 3;
11656218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
11657218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
11658218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg);
11659218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 5;
11660218822Sdim  inst.instruction |= (isquad != 0) << 6;
11661218822Sdim  inst.instruction |= immbits << 16;
11662218822Sdim  inst.instruction |= (size >> 3) << 7;
11663218822Sdim  inst.instruction |= (size & 0x7) << 19;
11664218822Sdim  if (write_ubit)
11665218822Sdim    inst.instruction |= (uval != 0) << 24;
11666218822Sdim
11667218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
11668218822Sdim}
11669218822Sdim
11670218822Sdimstatic void
11671218822Sdimdo_neon_shl_imm (void)
11672218822Sdim{
11673218822Sdim  if (!inst.operands[2].isreg)
1167460484Sobrien    {
11675218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
11676218822Sdim      struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_KEY | N_I_ALL);
11677218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
11678218822Sdim      neon_imm_shift (FALSE, 0, neon_quad (rs), et, inst.operands[2].imm);
1167960484Sobrien    }
11680218822Sdim  else
11681218822Sdim    {
11682218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11683218822Sdim      struct neon_type_el et = neon_check_type (3, rs,
11684218822Sdim        N_EQK, N_SU_ALL | N_KEY, N_EQK | N_SGN);
11685218822Sdim      unsigned int tmp;
1168660484Sobrien
11687218822Sdim      /* VSHL/VQSHL 3-register variants have syntax such as:
11688218822Sdim           vshl.xx Dd, Dm, Dn
11689218822Sdim         whereas other 3-register operations encoded by neon_three_same have
11690218822Sdim         syntax like:
11691218822Sdim           vadd.xx Dd, Dn, Dm
11692218822Sdim         (i.e. with Dn & Dm reversed). Swap operands[1].reg and operands[2].reg
11693218822Sdim         here.  */
11694218822Sdim      tmp = inst.operands[2].reg;
11695218822Sdim      inst.operands[2].reg = inst.operands[1].reg;
11696218822Sdim      inst.operands[1].reg = tmp;
11697218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
11698218822Sdim      neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
11699218822Sdim    }
11700218822Sdim}
11701218822Sdim
11702218822Sdimstatic void
11703218822Sdimdo_neon_qshl_imm (void)
11704218822Sdim{
11705218822Sdim  if (!inst.operands[2].isreg)
1170660484Sobrien    {
11707218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
11708218822Sdim      struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_SU_ALL | N_KEY);
11709218822Sdim
11710218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
11711218822Sdim      neon_imm_shift (TRUE, et.type == NT_unsigned, neon_quad (rs), et,
11712218822Sdim                      inst.operands[2].imm);
1171360484Sobrien    }
1171460484Sobrien  else
1171560484Sobrien    {
11716218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11717218822Sdim      struct neon_type_el et = neon_check_type (3, rs,
11718218822Sdim        N_EQK, N_SU_ALL | N_KEY, N_EQK | N_SGN);
11719218822Sdim      unsigned int tmp;
1172060484Sobrien
11721218822Sdim      /* See note in do_neon_shl_imm.  */
11722218822Sdim      tmp = inst.operands[2].reg;
11723218822Sdim      inst.operands[2].reg = inst.operands[1].reg;
11724218822Sdim      inst.operands[1].reg = tmp;
11725218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
11726218822Sdim      neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
11727218822Sdim    }
11728218822Sdim}
11729218822Sdim
11730218822Sdimstatic void
11731218822Sdimdo_neon_rshl (void)
11732218822Sdim{
11733218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11734218822Sdim  struct neon_type_el et = neon_check_type (3, rs,
11735218822Sdim    N_EQK, N_EQK, N_SU_ALL | N_KEY);
11736218822Sdim  unsigned int tmp;
11737218822Sdim
11738218822Sdim  tmp = inst.operands[2].reg;
11739218822Sdim  inst.operands[2].reg = inst.operands[1].reg;
11740218822Sdim  inst.operands[1].reg = tmp;
11741218822Sdim  neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
11742218822Sdim}
11743218822Sdim
11744218822Sdimstatic int
11745218822Sdimneon_cmode_for_logic_imm (unsigned immediate, unsigned *immbits, int size)
11746218822Sdim{
11747218822Sdim  /* Handle .I8 pseudo-instructions.  */
11748218822Sdim  if (size == 8)
11749218822Sdim    {
11750218822Sdim      /* Unfortunately, this will make everything apart from zero out-of-range.
11751218822Sdim         FIXME is this the intended semantics? There doesn't seem much point in
11752218822Sdim         accepting .I8 if so.  */
11753218822Sdim      immediate |= immediate << 8;
11754218822Sdim      size = 16;
11755218822Sdim    }
11756218822Sdim
11757218822Sdim  if (size >= 32)
11758218822Sdim    {
11759218822Sdim      if (immediate == (immediate & 0x000000ff))
1176060484Sobrien	{
11761218822Sdim	  *immbits = immediate;
11762218822Sdim	  return 0x1;
1176360484Sobrien	}
11764218822Sdim      else if (immediate == (immediate & 0x0000ff00))
1176560484Sobrien	{
11766218822Sdim	  *immbits = immediate >> 8;
11767218822Sdim	  return 0x3;
1176860484Sobrien	}
11769218822Sdim      else if (immediate == (immediate & 0x00ff0000))
1177060484Sobrien	{
11771218822Sdim	  *immbits = immediate >> 16;
11772218822Sdim	  return 0x5;
1177360484Sobrien	}
11774218822Sdim      else if (immediate == (immediate & 0xff000000))
1177560484Sobrien	{
11776218822Sdim	  *immbits = immediate >> 24;
11777218822Sdim	  return 0x7;
1177860484Sobrien	}
11779218822Sdim      if ((immediate & 0xffff) != (immediate >> 16))
11780218822Sdim	goto bad_immediate;
11781218822Sdim      immediate &= 0xffff;
1178260484Sobrien    }
11783218822Sdim
11784218822Sdim  if (immediate == (immediate & 0x000000ff))
1178560484Sobrien    {
11786218822Sdim      *immbits = immediate;
11787218822Sdim      return 0x9;
11788218822Sdim    }
11789218822Sdim  else if (immediate == (immediate & 0x0000ff00))
11790218822Sdim    {
11791218822Sdim      *immbits = immediate >> 8;
11792218822Sdim      return 0xb;
11793218822Sdim    }
1179460484Sobrien
11795218822Sdim  bad_immediate:
11796218822Sdim  first_error (_("immediate value out of range"));
11797218822Sdim  return FAIL;
11798218822Sdim}
1179960484Sobrien
11800218822Sdim/* True if IMM has form 0bAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD for bits
11801218822Sdim   A, B, C, D.  */
1180260484Sobrien
11803218822Sdimstatic int
11804218822Sdimneon_bits_same_in_bytes (unsigned imm)
11805218822Sdim{
11806218822Sdim  return ((imm & 0x000000ff) == 0 || (imm & 0x000000ff) == 0x000000ff)
11807218822Sdim         && ((imm & 0x0000ff00) == 0 || (imm & 0x0000ff00) == 0x0000ff00)
11808218822Sdim         && ((imm & 0x00ff0000) == 0 || (imm & 0x00ff0000) == 0x00ff0000)
11809218822Sdim         && ((imm & 0xff000000) == 0 || (imm & 0xff000000) == 0xff000000);
11810218822Sdim}
1181160484Sobrien
11812218822Sdim/* For immediate of above form, return 0bABCD.  */
1181360484Sobrien
11814218822Sdimstatic unsigned
11815218822Sdimneon_squash_bits (unsigned imm)
11816218822Sdim{
11817218822Sdim  return (imm & 0x01) | ((imm & 0x0100) >> 7) | ((imm & 0x010000) >> 14)
11818218822Sdim         | ((imm & 0x01000000) >> 21);
11819218822Sdim}
1182060484Sobrien
11821218822Sdim/* Compress quarter-float representation to 0b...000 abcdefgh.  */
1182277298Sobrien
11823218822Sdimstatic unsigned
11824218822Sdimneon_qfloat_bits (unsigned imm)
11825218822Sdim{
11826218822Sdim  return ((imm >> 19) & 0x7f) | ((imm >> 24) & 0x80);
1182760484Sobrien}
1182860484Sobrien
11829218822Sdim/* Returns CMODE. IMMBITS [7:0] is set to bits suitable for inserting into
11830218822Sdim   the instruction. *OP is passed as the initial value of the op field, and
11831218822Sdim   may be set to a different value depending on the constant (i.e.
11832218822Sdim   "MOV I64, 0bAAAAAAAABBBB..." which uses OP = 1 despite being MOV not
11833218822Sdim   MVN).  If the immediate looks like a repeated parttern then also
11834218822Sdim   try smaller element sizes.  */
11835218822Sdim
11836218822Sdimstatic int
11837218822Sdimneon_cmode_for_move_imm (unsigned immlo, unsigned immhi, int float_p,
11838218822Sdim			 unsigned *immbits, int *op, int size,
11839218822Sdim			 enum neon_el_type type)
1184060484Sobrien{
11841218822Sdim  /* Only permit float immediates (including 0.0/-0.0) if the operand type is
11842218822Sdim     float.  */
11843218822Sdim  if (type == NT_float && !float_p)
11844218822Sdim    return FAIL;
1184560484Sobrien
11846218822Sdim  if (type == NT_float && is_quarter_float (immlo) && immhi == 0)
1184760484Sobrien    {
11848218822Sdim      if (size != 32 || *op == 1)
11849218822Sdim        return FAIL;
11850218822Sdim      *immbits = neon_qfloat_bits (immlo);
11851218822Sdim      return 0xf;
1185260484Sobrien    }
1185360484Sobrien
11854218822Sdim  if (size == 64)
1185560484Sobrien    {
11856218822Sdim      if (neon_bits_same_in_bytes (immhi)
11857218822Sdim	  && neon_bits_same_in_bytes (immlo))
11858218822Sdim	{
11859218822Sdim	  if (*op == 1)
11860218822Sdim	    return FAIL;
11861218822Sdim	  *immbits = (neon_squash_bits (immhi) << 4)
11862218822Sdim		     | neon_squash_bits (immlo);
11863218822Sdim	  *op = 1;
11864218822Sdim	  return 0xe;
11865218822Sdim	}
11866218822Sdim
11867218822Sdim      if (immhi != immlo)
11868218822Sdim	return FAIL;
1186960484Sobrien    }
11870218822Sdim
11871218822Sdim  if (size >= 32)
1187260484Sobrien    {
11873218822Sdim      if (immlo == (immlo & 0x000000ff))
1187460484Sobrien	{
11875218822Sdim	  *immbits = immlo;
11876218822Sdim	  return 0x0;
1187760484Sobrien	}
11878218822Sdim      else if (immlo == (immlo & 0x0000ff00))
1187960484Sobrien	{
11880218822Sdim	  *immbits = immlo >> 8;
11881218822Sdim	  return 0x2;
1188260484Sobrien	}
11883218822Sdim      else if (immlo == (immlo & 0x00ff0000))
1188460484Sobrien	{
11885218822Sdim	  *immbits = immlo >> 16;
11886218822Sdim	  return 0x4;
1188760484Sobrien	}
11888218822Sdim      else if (immlo == (immlo & 0xff000000))
1188960484Sobrien	{
11890218822Sdim	  *immbits = immlo >> 24;
11891218822Sdim	  return 0x6;
1189260484Sobrien	}
11893218822Sdim      else if (immlo == ((immlo & 0x0000ff00) | 0x000000ff))
11894218822Sdim	{
11895218822Sdim	  *immbits = (immlo >> 8) & 0xff;
11896218822Sdim	  return 0xc;
11897218822Sdim	}
11898218822Sdim      else if (immlo == ((immlo & 0x00ff0000) | 0x0000ffff))
11899218822Sdim	{
11900218822Sdim	  *immbits = (immlo >> 16) & 0xff;
11901218822Sdim	  return 0xd;
11902218822Sdim	}
1190360484Sobrien
11904218822Sdim      if ((immlo & 0xffff) != (immlo >> 16))
11905218822Sdim	return FAIL;
11906218822Sdim      immlo &= 0xffff;
1190760484Sobrien    }
11908218822Sdim
11909218822Sdim  if (size >= 16)
1191060484Sobrien    {
11911218822Sdim      if (immlo == (immlo & 0x000000ff))
1191260484Sobrien	{
11913218822Sdim	  *immbits = immlo;
11914218822Sdim	  return 0x8;
1191560484Sobrien	}
11916218822Sdim      else if (immlo == (immlo & 0x0000ff00))
1191760484Sobrien	{
11918218822Sdim	  *immbits = immlo >> 8;
11919218822Sdim	  return 0xa;
1192060484Sobrien	}
1192160484Sobrien
11922218822Sdim      if ((immlo & 0xff) != (immlo >> 8))
11923218822Sdim	return FAIL;
11924218822Sdim      immlo &= 0xff;
11925218822Sdim    }
1192660484Sobrien
11927218822Sdim  if (immlo == (immlo & 0x000000ff))
11928218822Sdim    {
11929218822Sdim      /* Don't allow MVN with 8-bit immediate.  */
11930218822Sdim      if (*op == 1)
11931218822Sdim	return FAIL;
11932218822Sdim      *immbits = immlo;
11933218822Sdim      return 0xe;
11934218822Sdim    }
1193560484Sobrien
11936218822Sdim  return FAIL;
11937218822Sdim}
1193860484Sobrien
11939218822Sdim/* Write immediate bits [7:0] to the following locations:
1194060484Sobrien
11941218822Sdim  |28/24|23     19|18 16|15                    4|3     0|
11942218822Sdim  |  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|
1194377298Sobrien
11944218822Sdim  This function is used by VMOV/VMVN/VORR/VBIC.  */
1194560484Sobrien
1194660484Sobrienstatic void
11947218822Sdimneon_write_immbits (unsigned immbits)
1194860484Sobrien{
11949218822Sdim  inst.instruction |= immbits & 0xf;
11950218822Sdim  inst.instruction |= ((immbits >> 4) & 0x7) << 16;
11951218822Sdim  inst.instruction |= ((immbits >> 7) & 0x1) << 24;
11952218822Sdim}
1195360484Sobrien
11954218822Sdim/* Invert low-order SIZE bits of XHI:XLO.  */
1195560484Sobrien
11956218822Sdimstatic void
11957218822Sdimneon_invert_size (unsigned *xlo, unsigned *xhi, int size)
11958218822Sdim{
11959218822Sdim  unsigned immlo = xlo ? *xlo : 0;
11960218822Sdim  unsigned immhi = xhi ? *xhi : 0;
1196160484Sobrien
11962218822Sdim  switch (size)
1196360484Sobrien    {
11964218822Sdim    case 8:
11965218822Sdim      immlo = (~immlo) & 0xff;
11966218822Sdim      break;
1196760484Sobrien
11968218822Sdim    case 16:
11969218822Sdim      immlo = (~immlo) & 0xffff;
11970218822Sdim      break;
1197160484Sobrien
11972218822Sdim    case 64:
11973218822Sdim      immhi = (~immhi) & 0xffffffff;
11974218822Sdim      /* fall through.  */
1197560484Sobrien
11976218822Sdim    case 32:
11977218822Sdim      immlo = (~immlo) & 0xffffffff;
11978218822Sdim      break;
1197960484Sobrien
11980218822Sdim    default:
11981218822Sdim      abort ();
1198260484Sobrien    }
11983218822Sdim
11984218822Sdim  if (xlo)
11985218822Sdim    *xlo = immlo;
11986218822Sdim
11987218822Sdim  if (xhi)
11988218822Sdim    *xhi = immhi;
11989218822Sdim}
11990218822Sdim
11991218822Sdimstatic void
11992218822Sdimdo_neon_logic (void)
11993218822Sdim{
11994218822Sdim  if (inst.operands[2].present && inst.operands[2].isreg)
11995218822Sdim    {
11996218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11997218822Sdim      neon_check_type (3, rs, N_IGNORE_TYPE);
11998218822Sdim      /* U bit and size field were set as part of the bitmask.  */
11999218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12000218822Sdim      neon_three_same (neon_quad (rs), 0, -1);
12001218822Sdim    }
1200260484Sobrien  else
1200360484Sobrien    {
12004218822Sdim      enum neon_shape rs = neon_select_shape (NS_DI, NS_QI, NS_NULL);
12005218822Sdim      struct neon_type_el et = neon_check_type (2, rs,
12006218822Sdim        N_I8 | N_I16 | N_I32 | N_I64 | N_F32 | N_KEY, N_EQK);
12007218822Sdim      enum neon_opc opcode = inst.instruction & 0x0fffffff;
12008218822Sdim      unsigned immbits;
12009218822Sdim      int cmode;
12010218822Sdim
12011218822Sdim      if (et.type == NT_invtype)
12012218822Sdim        return;
12013218822Sdim
12014218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
12015218822Sdim
12016218822Sdim      immbits = inst.operands[1].imm;
12017218822Sdim      if (et.size == 64)
1201860484Sobrien	{
12019218822Sdim	  /* .i64 is a pseudo-op, so the immediate must be a repeating
12020218822Sdim	     pattern.  */
12021218822Sdim	  if (immbits != (inst.operands[1].regisimm ?
12022218822Sdim			  inst.operands[1].reg : 0))
12023218822Sdim	    {
12024218822Sdim	      /* Set immbits to an invalid constant.  */
12025218822Sdim	      immbits = 0xdeadbeef;
12026218822Sdim	    }
1202760484Sobrien	}
1202860484Sobrien
12029218822Sdim      switch (opcode)
12030218822Sdim        {
12031218822Sdim        case N_MNEM_vbic:
12032218822Sdim          cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
12033218822Sdim          break;
12034218822Sdim
12035218822Sdim        case N_MNEM_vorr:
12036218822Sdim          cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
12037218822Sdim          break;
12038218822Sdim
12039218822Sdim        case N_MNEM_vand:
12040218822Sdim          /* Pseudo-instruction for VBIC.  */
12041218822Sdim          neon_invert_size (&immbits, 0, et.size);
12042218822Sdim          cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
12043218822Sdim          break;
12044218822Sdim
12045218822Sdim        case N_MNEM_vorn:
12046218822Sdim          /* Pseudo-instruction for VORR.  */
12047218822Sdim          neon_invert_size (&immbits, 0, et.size);
12048218822Sdim          cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
12049218822Sdim          break;
12050218822Sdim
12051218822Sdim        default:
12052218822Sdim          abort ();
12053218822Sdim        }
1205460484Sobrien
12055218822Sdim      if (cmode == FAIL)
12056218822Sdim        return;
1205760484Sobrien
12058218822Sdim      inst.instruction |= neon_quad (rs) << 6;
12059218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12060218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12061218822Sdim      inst.instruction |= cmode << 8;
12062218822Sdim      neon_write_immbits (immbits);
12063218822Sdim
12064218822Sdim      inst.instruction = neon_dp_fixup (inst.instruction);
1206560484Sobrien    }
12066218822Sdim}
1206760484Sobrien
12068218822Sdimstatic void
12069218822Sdimdo_neon_bitfield (void)
12070218822Sdim{
12071218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
12072218822Sdim  neon_check_type (3, rs, N_IGNORE_TYPE);
12073218822Sdim  neon_three_same (neon_quad (rs), 0, -1);
1207460484Sobrien}
1207560484Sobrien
1207660484Sobrienstatic void
12077218822Sdimneon_dyadic_misc (enum neon_el_type ubit_meaning, unsigned types,
12078218822Sdim                  unsigned destbits)
1207960484Sobrien{
12080218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
12081218822Sdim  struct neon_type_el et = neon_check_type (3, rs, N_EQK | destbits, N_EQK,
12082218822Sdim                                            types | N_KEY);
12083218822Sdim  if (et.type == NT_float)
1208460484Sobrien    {
12085218822Sdim      inst.instruction = NEON_ENC_FLOAT (inst.instruction);
12086218822Sdim      neon_three_same (neon_quad (rs), 0, -1);
1208760484Sobrien    }
12088218822Sdim  else
1208960484Sobrien    {
12090218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12091218822Sdim      neon_three_same (neon_quad (rs), et.type == ubit_meaning, et.size);
1209260484Sobrien    }
12093218822Sdim}
1209489857Sobrien
12095218822Sdimstatic void
12096218822Sdimdo_neon_dyadic_if_su (void)
12097218822Sdim{
12098218822Sdim  neon_dyadic_misc (NT_unsigned, N_SUF_32, 0);
12099218822Sdim}
1210060484Sobrien
12101218822Sdimstatic void
12102218822Sdimdo_neon_dyadic_if_su_d (void)
12103218822Sdim{
12104218822Sdim  /* This version only allow D registers, but that constraint is enforced during
12105218822Sdim     operand parsing so we don't need to do anything extra here.  */
12106218822Sdim  neon_dyadic_misc (NT_unsigned, N_SUF_32, 0);
12107218822Sdim}
1210860484Sobrien
12109218822Sdimstatic void
12110218822Sdimdo_neon_dyadic_if_i_d (void)
12111218822Sdim{
12112218822Sdim  /* The "untyped" case can't happen. Do this to stop the "U" bit being
12113218822Sdim     affected if we specify unsigned args.  */
12114218822Sdim  neon_dyadic_misc (NT_untyped, N_IF_32, 0);
12115218822Sdim}
1211660484Sobrien
12117218822Sdimenum vfp_or_neon_is_neon_bits
12118218822Sdim{
12119218822Sdim  NEON_CHECK_CC = 1,
12120218822Sdim  NEON_CHECK_ARCH = 2
12121218822Sdim};
1212277298Sobrien
12123218822Sdim/* Call this function if an instruction which may have belonged to the VFP or
12124218822Sdim   Neon instruction sets, but turned out to be a Neon instruction (due to the
12125218822Sdim   operand types involved, etc.). We have to check and/or fix-up a couple of
12126218822Sdim   things:
1212760484Sobrien
12128218822Sdim     - Make sure the user hasn't attempted to make a Neon instruction
12129218822Sdim       conditional.
12130218822Sdim     - Alter the value in the condition code field if necessary.
12131218822Sdim     - Make sure that the arch supports Neon instructions.
1213260484Sobrien
12133218822Sdim   Which of these operations take place depends on bits from enum
12134218822Sdim   vfp_or_neon_is_neon_bits.
1213560484Sobrien
12136218822Sdim   WARNING: This function has side effects! If NEON_CHECK_CC is used and the
12137218822Sdim   current instruction's condition is COND_ALWAYS, the condition field is
12138218822Sdim   changed to inst.uncond_value. This is necessary because instructions shared
12139218822Sdim   between VFP and Neon may be conditional for the VFP variants only, and the
12140218822Sdim   unconditional Neon version must have, e.g., 0xF in the condition field.  */
1214160484Sobrien
12142218822Sdimstatic int
12143218822Sdimvfp_or_neon_is_neon (unsigned check)
12144218822Sdim{
12145218822Sdim  /* Conditions are always legal in Thumb mode (IT blocks).  */
12146218822Sdim  if (!thumb_mode && (check & NEON_CHECK_CC))
12147218822Sdim    {
12148218822Sdim      if (inst.cond != COND_ALWAYS)
12149218822Sdim        {
12150218822Sdim          first_error (_(BAD_COND));
12151218822Sdim          return FAIL;
12152218822Sdim        }
12153218822Sdim      if (inst.uncond_value != -1)
12154218822Sdim        inst.instruction |= inst.uncond_value << 28;
1215560484Sobrien    }
12156218822Sdim
12157218822Sdim  if ((check & NEON_CHECK_ARCH)
12158218822Sdim      && !ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1))
1215960484Sobrien    {
12160218822Sdim      first_error (_(BAD_FPU));
12161218822Sdim      return FAIL;
1216260484Sobrien    }
12163218822Sdim
12164218822Sdim  return SUCCESS;
12165218822Sdim}
1216660484Sobrien
12167218822Sdimstatic void
12168218822Sdimdo_neon_addsub_if_i (void)
12169218822Sdim{
12170218822Sdim  if (try_vfp_nsyn (3, do_vfp_nsyn_add_sub) == SUCCESS)
12171218822Sdim    return;
1217260484Sobrien
12173218822Sdim  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12174218822Sdim    return;
1217560484Sobrien
12176218822Sdim  /* The "untyped" case can't happen. Do this to stop the "U" bit being
12177218822Sdim     affected if we specify unsigned args.  */
12178218822Sdim  neon_dyadic_misc (NT_untyped, N_IF_32 | N_I64, 0);
12179218822Sdim}
1218060484Sobrien
12181218822Sdim/* Swaps operands 1 and 2. If operand 1 (optional arg) was omitted, we want the
12182218822Sdim   result to be:
12183218822Sdim     V<op> A,B     (A is operand 0, B is operand 2)
12184218822Sdim   to mean:
12185218822Sdim     V<op> A,B,A
12186218822Sdim   not:
12187218822Sdim     V<op> A,B,B
12188218822Sdim   so handle that case specially.  */
1218960484Sobrien
12190218822Sdimstatic void
12191218822Sdimneon_exchange_operands (void)
12192218822Sdim{
12193218822Sdim  void *scratch = alloca (sizeof (inst.operands[0]));
12194218822Sdim  if (inst.operands[1].present)
12195218822Sdim    {
12196218822Sdim      /* Swap operands[1] and operands[2].  */
12197218822Sdim      memcpy (scratch, &inst.operands[1], sizeof (inst.operands[0]));
12198218822Sdim      inst.operands[1] = inst.operands[2];
12199218822Sdim      memcpy (&inst.operands[2], scratch, sizeof (inst.operands[0]));
1220060484Sobrien    }
12201218822Sdim  else
1220260484Sobrien    {
12203218822Sdim      inst.operands[1] = inst.operands[2];
12204218822Sdim      inst.operands[2] = inst.operands[0];
1220560484Sobrien    }
12206218822Sdim}
12207218822Sdim
12208218822Sdimstatic void
12209218822Sdimneon_compare (unsigned regtypes, unsigned immtypes, int invert)
12210218822Sdim{
12211218822Sdim  if (inst.operands[2].isreg)
1221260484Sobrien    {
12213218822Sdim      if (invert)
12214218822Sdim        neon_exchange_operands ();
12215218822Sdim      neon_dyadic_misc (NT_unsigned, regtypes, N_SIZ);
1221660484Sobrien    }
1221760484Sobrien  else
1221860484Sobrien    {
12219218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
12220218822Sdim      struct neon_type_el et = neon_check_type (2, rs,
12221218822Sdim        N_EQK | N_SIZ, immtypes | N_KEY);
1222260484Sobrien
12223218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
12224218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12225218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12226218822Sdim      inst.instruction |= LOW4 (inst.operands[1].reg);
12227218822Sdim      inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12228218822Sdim      inst.instruction |= neon_quad (rs) << 6;
12229218822Sdim      inst.instruction |= (et.type == NT_float) << 10;
12230218822Sdim      inst.instruction |= neon_logbits (et.size) << 18;
12231218822Sdim
12232218822Sdim      inst.instruction = neon_dp_fixup (inst.instruction);
1223360484Sobrien    }
12234218822Sdim}
1223560484Sobrien
12236218822Sdimstatic void
12237218822Sdimdo_neon_cmp (void)
12238218822Sdim{
12239218822Sdim  neon_compare (N_SUF_32, N_S8 | N_S16 | N_S32 | N_F32, FALSE);
1224060484Sobrien}
1224160484Sobrien
12242218822Sdimstatic void
12243218822Sdimdo_neon_cmp_inv (void)
12244218822Sdim{
12245218822Sdim  neon_compare (N_SUF_32, N_S8 | N_S16 | N_S32 | N_F32, TRUE);
12246218822Sdim}
1224789857Sobrien
12248218822Sdimstatic void
12249218822Sdimdo_neon_ceq (void)
12250218822Sdim{
12251218822Sdim  neon_compare (N_IF_32, N_IF_32, FALSE);
12252218822Sdim}
1225389857Sobrien
12254218822Sdim/* For multiply instructions, we have the possibility of 16-bit or 32-bit
12255218822Sdim   scalars, which are encoded in 5 bits, M : Rm.
12256218822Sdim   For 16-bit scalars, the register is encoded in Rm[2:0] and the index in
12257218822Sdim   M:Rm[3], and for 32-bit scalars, the register is encoded in Rm[3:0] and the
12258218822Sdim   index in M.  */
1225989857Sobrien
12260218822Sdimstatic unsigned
12261218822Sdimneon_scalar_for_mul (unsigned scalar, unsigned elsize)
1226289857Sobrien{
12263218822Sdim  unsigned regno = NEON_SCALAR_REG (scalar);
12264218822Sdim  unsigned elno = NEON_SCALAR_INDEX (scalar);
1226589857Sobrien
12266218822Sdim  switch (elsize)
1226789857Sobrien    {
12268218822Sdim    case 16:
12269218822Sdim      if (regno > 7 || elno > 3)
12270218822Sdim        goto bad_scalar;
12271218822Sdim      return regno | (elno << 3);
12272218822Sdim
12273218822Sdim    case 32:
12274218822Sdim      if (regno > 15 || elno > 1)
12275218822Sdim        goto bad_scalar;
12276218822Sdim      return regno | (elno << 4);
1227789857Sobrien
12278218822Sdim    default:
12279218822Sdim    bad_scalar:
12280218822Sdim      first_error (_("scalar out of range for multiply instruction"));
1228189857Sobrien    }
1228289857Sobrien
12283218822Sdim  return 0;
12284218822Sdim}
1228599461Sobrien
12286218822Sdim/* Encode multiply / multiply-accumulate scalar instructions.  */
12287104834Sobrien
12288218822Sdimstatic void
12289218822Sdimneon_mul_mac (struct neon_type_el et, int ubit)
12290218822Sdim{
12291218822Sdim  unsigned scalar;
12292218822Sdim
12293218822Sdim  /* Give a more helpful error message if we have an invalid type.  */
12294218822Sdim  if (et.type == NT_invtype)
12295218822Sdim    return;
12296218822Sdim
12297218822Sdim  scalar = neon_scalar_for_mul (inst.operands[2].reg, et.size);
12298218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12299218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12300218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
12301218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
12302218822Sdim  inst.instruction |= LOW4 (scalar);
12303218822Sdim  inst.instruction |= HI1 (scalar) << 5;
12304218822Sdim  inst.instruction |= (et.type == NT_float) << 8;
12305218822Sdim  inst.instruction |= neon_logbits (et.size) << 20;
12306218822Sdim  inst.instruction |= (ubit != 0) << 24;
12307218822Sdim
12308218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1230989857Sobrien}
1231089857Sobrien
12311218822Sdimstatic void
12312218822Sdimdo_neon_mac_maybe_scalar (void)
12313218822Sdim{
12314218822Sdim  if (try_vfp_nsyn (3, do_vfp_nsyn_mla_mls) == SUCCESS)
12315218822Sdim    return;
1231689857Sobrien
12317218822Sdim  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12318218822Sdim    return;
1231989857Sobrien
12320218822Sdim  if (inst.operands[2].isscalar)
12321218822Sdim    {
12322218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDS, NS_QQS, NS_NULL);
12323218822Sdim      struct neon_type_el et = neon_check_type (3, rs,
12324218822Sdim        N_EQK, N_EQK, N_I16 | N_I32 | N_F32 | N_KEY);
12325218822Sdim      inst.instruction = NEON_ENC_SCALAR (inst.instruction);
12326218822Sdim      neon_mul_mac (et, neon_quad (rs));
12327218822Sdim    }
12328218822Sdim  else
12329218822Sdim    {
12330218822Sdim      /* The "untyped" case can't happen.  Do this to stop the "U" bit being
12331218822Sdim	 affected if we specify unsigned args.  */
12332218822Sdim      neon_dyadic_misc (NT_untyped, N_IF_32, 0);
12333218822Sdim    }
12334218822Sdim}
12335218822Sdim
1233660484Sobrienstatic void
12337218822Sdimdo_neon_tst (void)
1233889857Sobrien{
12339218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
12340218822Sdim  struct neon_type_el et = neon_check_type (3, rs,
12341218822Sdim    N_EQK, N_EQK, N_8 | N_16 | N_32 | N_KEY);
12342218822Sdim  neon_three_same (neon_quad (rs), 0, et.size);
1234389857Sobrien}
1234489857Sobrien
12345218822Sdim/* VMUL with 3 registers allows the P8 type. The scalar version supports the
12346218822Sdim   same types as the MAC equivalents. The polynomial type for this instruction
12347218822Sdim   is encoded the same as the integer type.  */
12348218822Sdim
1234989857Sobrienstatic void
12350218822Sdimdo_neon_mul (void)
1235189857Sobrien{
12352218822Sdim  if (try_vfp_nsyn (3, do_vfp_nsyn_mul) == SUCCESS)
12353218822Sdim    return;
12354218822Sdim
12355218822Sdim  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12356218822Sdim    return;
12357218822Sdim
12358218822Sdim  if (inst.operands[2].isscalar)
12359218822Sdim    do_neon_mac_maybe_scalar ();
12360218822Sdim  else
12361218822Sdim    neon_dyadic_misc (NT_poly, N_I8 | N_I16 | N_I32 | N_F32 | N_P8, 0);
1236289857Sobrien}
1236389857Sobrien
1236489857Sobrienstatic void
12365218822Sdimdo_neon_qdmulh (void)
1236689857Sobrien{
12367218822Sdim  if (inst.operands[2].isscalar)
12368218822Sdim    {
12369218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDS, NS_QQS, NS_NULL);
12370218822Sdim      struct neon_type_el et = neon_check_type (3, rs,
12371218822Sdim        N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
12372218822Sdim      inst.instruction = NEON_ENC_SCALAR (inst.instruction);
12373218822Sdim      neon_mul_mac (et, neon_quad (rs));
12374218822Sdim    }
12375218822Sdim  else
12376218822Sdim    {
12377218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
12378218822Sdim      struct neon_type_el et = neon_check_type (3, rs,
12379218822Sdim        N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
12380218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12381218822Sdim      /* The U bit (rounding) comes from bit mask.  */
12382218822Sdim      neon_three_same (neon_quad (rs), 0, et.size);
12383218822Sdim    }
1238489857Sobrien}
1238589857Sobrien
1238689857Sobrienstatic void
12387218822Sdimdo_neon_fcmp_absolute (void)
1238889857Sobrien{
12389218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
12390218822Sdim  neon_check_type (3, rs, N_EQK, N_EQK, N_F32 | N_KEY);
12391218822Sdim  /* Size field comes from bit mask.  */
12392218822Sdim  neon_three_same (neon_quad (rs), 1, -1);
1239389857Sobrien}
1239489857Sobrien
1239589857Sobrienstatic void
12396218822Sdimdo_neon_fcmp_absolute_inv (void)
1239789857Sobrien{
12398218822Sdim  neon_exchange_operands ();
12399218822Sdim  do_neon_fcmp_absolute ();
1240089857Sobrien}
1240189857Sobrien
1240289857Sobrienstatic void
12403218822Sdimdo_neon_step (void)
1240489857Sobrien{
12405218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
12406218822Sdim  neon_check_type (3, rs, N_EQK, N_EQK, N_F32 | N_KEY);
12407218822Sdim  neon_three_same (neon_quad (rs), 0, -1);
1240889857Sobrien}
1240989857Sobrien
1241089857Sobrienstatic void
12411218822Sdimdo_neon_abs_neg (void)
1241289857Sobrien{
12413218822Sdim  enum neon_shape rs;
12414218822Sdim  struct neon_type_el et;
12415218822Sdim
12416218822Sdim  if (try_vfp_nsyn (2, do_vfp_nsyn_abs_neg) == SUCCESS)
12417218822Sdim    return;
12418218822Sdim
12419218822Sdim  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12420218822Sdim    return;
12421218822Sdim
12422218822Sdim  rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
12423218822Sdim  et = neon_check_type (2, rs, N_EQK, N_S8 | N_S16 | N_S32 | N_F32 | N_KEY);
12424218822Sdim
12425218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12426218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12427218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg);
12428218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12429218822Sdim  inst.instruction |= neon_quad (rs) << 6;
12430218822Sdim  inst.instruction |= (et.type == NT_float) << 10;
12431218822Sdim  inst.instruction |= neon_logbits (et.size) << 18;
12432218822Sdim
12433218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1243489857Sobrien}
1243589857Sobrien
1243689857Sobrienstatic void
12437218822Sdimdo_neon_sli (void)
1243889857Sobrien{
12439218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
12440218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
12441218822Sdim    N_EQK, N_8 | N_16 | N_32 | N_64 | N_KEY);
12442218822Sdim  int imm = inst.operands[2].imm;
12443218822Sdim  constraint (imm < 0 || (unsigned)imm >= et.size,
12444218822Sdim              _("immediate out of range for insert"));
12445218822Sdim  neon_imm_shift (FALSE, 0, neon_quad (rs), et, imm);
1244689857Sobrien}
1244789857Sobrien
1244889857Sobrienstatic void
12449218822Sdimdo_neon_sri (void)
1245089857Sobrien{
12451218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
12452218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
12453218822Sdim    N_EQK, N_8 | N_16 | N_32 | N_64 | N_KEY);
12454218822Sdim  int imm = inst.operands[2].imm;
12455218822Sdim  constraint (imm < 1 || (unsigned)imm > et.size,
12456218822Sdim              _("immediate out of range for insert"));
12457218822Sdim  neon_imm_shift (FALSE, 0, neon_quad (rs), et, et.size - imm);
1245889857Sobrien}
1245989857Sobrien
1246089857Sobrienstatic void
12461218822Sdimdo_neon_qshlu_imm (void)
1246289857Sobrien{
12463218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
12464218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
12465218822Sdim    N_EQK | N_UNS, N_S8 | N_S16 | N_S32 | N_S64 | N_KEY);
12466218822Sdim  int imm = inst.operands[2].imm;
12467218822Sdim  constraint (imm < 0 || (unsigned)imm >= et.size,
12468218822Sdim              _("immediate out of range for shift"));
12469218822Sdim  /* Only encodes the 'U present' variant of the instruction.
12470218822Sdim     In this case, signed types have OP (bit 8) set to 0.
12471218822Sdim     Unsigned types have OP set to 1.  */
12472218822Sdim  inst.instruction |= (et.type == NT_unsigned) << 8;
12473218822Sdim  /* The rest of the bits are the same as other immediate shifts.  */
12474218822Sdim  neon_imm_shift (FALSE, 0, neon_quad (rs), et, imm);
1247589857Sobrien}
1247689857Sobrien
1247789857Sobrienstatic void
12478218822Sdimdo_neon_qmovn (void)
1247989857Sobrien{
12480218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQ,
12481218822Sdim    N_EQK | N_HLF, N_SU_16_64 | N_KEY);
12482218822Sdim  /* Saturating move where operands can be signed or unsigned, and the
12483218822Sdim     destination has the same signedness.  */
12484218822Sdim  inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12485218822Sdim  if (et.type == NT_unsigned)
12486218822Sdim    inst.instruction |= 0xc0;
12487218822Sdim  else
12488218822Sdim    inst.instruction |= 0x80;
12489218822Sdim  neon_two_same (0, 1, et.size / 2);
1249089857Sobrien}
1249189857Sobrien
1249289857Sobrienstatic void
12493218822Sdimdo_neon_qmovun (void)
1249489857Sobrien{
12495218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQ,
12496218822Sdim    N_EQK | N_HLF | N_UNS, N_S16 | N_S32 | N_S64 | N_KEY);
12497218822Sdim  /* Saturating move with unsigned results. Operands must be signed.  */
12498218822Sdim  inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12499218822Sdim  neon_two_same (0, 1, et.size / 2);
1250089857Sobrien}
1250189857Sobrien
1250289857Sobrienstatic void
12503218822Sdimdo_neon_rshift_sat_narrow (void)
1250489857Sobrien{
12505218822Sdim  /* FIXME: Types for narrowing. If operands are signed, results can be signed
12506218822Sdim     or unsigned. If operands are unsigned, results must also be unsigned.  */
12507218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQI,
12508218822Sdim    N_EQK | N_HLF, N_SU_16_64 | N_KEY);
12509218822Sdim  int imm = inst.operands[2].imm;
12510218822Sdim  /* This gets the bounds check, size encoding and immediate bits calculation
12511218822Sdim     right.  */
12512218822Sdim  et.size /= 2;
12513218822Sdim
12514218822Sdim  /* VQ{R}SHRN.I<size> <Dd>, <Qm>, #0 is a synonym for
12515218822Sdim     VQMOVN.I<size> <Dd>, <Qm>.  */
12516218822Sdim  if (imm == 0)
12517218822Sdim    {
12518218822Sdim      inst.operands[2].present = 0;
12519218822Sdim      inst.instruction = N_MNEM_vqmovn;
12520218822Sdim      do_neon_qmovn ();
12521218822Sdim      return;
12522218822Sdim    }
12523218822Sdim
12524218822Sdim  constraint (imm < 1 || (unsigned)imm > et.size,
12525218822Sdim              _("immediate out of range"));
12526218822Sdim  neon_imm_shift (TRUE, et.type == NT_unsigned, 0, et, et.size - imm);
1252789857Sobrien}
1252889857Sobrien
1252989857Sobrienstatic void
12530218822Sdimdo_neon_rshift_sat_narrow_u (void)
1253189857Sobrien{
12532218822Sdim  /* FIXME: Types for narrowing. If operands are signed, results can be signed
12533218822Sdim     or unsigned. If operands are unsigned, results must also be unsigned.  */
12534218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQI,
12535218822Sdim    N_EQK | N_HLF | N_UNS, N_S16 | N_S32 | N_S64 | N_KEY);
12536218822Sdim  int imm = inst.operands[2].imm;
12537218822Sdim  /* This gets the bounds check, size encoding and immediate bits calculation
12538218822Sdim     right.  */
12539218822Sdim  et.size /= 2;
12540218822Sdim
12541218822Sdim  /* VQSHRUN.I<size> <Dd>, <Qm>, #0 is a synonym for
12542218822Sdim     VQMOVUN.I<size> <Dd>, <Qm>.  */
12543218822Sdim  if (imm == 0)
12544218822Sdim    {
12545218822Sdim      inst.operands[2].present = 0;
12546218822Sdim      inst.instruction = N_MNEM_vqmovun;
12547218822Sdim      do_neon_qmovun ();
12548218822Sdim      return;
12549218822Sdim    }
12550218822Sdim
12551218822Sdim  constraint (imm < 1 || (unsigned)imm > et.size,
12552218822Sdim              _("immediate out of range"));
12553218822Sdim  /* FIXME: The manual is kind of unclear about what value U should have in
12554218822Sdim     VQ{R}SHRUN instructions, but U=0, op=0 definitely encodes VRSHR, so it
12555218822Sdim     must be 1.  */
12556218822Sdim  neon_imm_shift (TRUE, 1, 0, et, et.size - imm);
1255789857Sobrien}
1255889857Sobrien
1255989857Sobrienstatic void
12560218822Sdimdo_neon_movn (void)
1256189857Sobrien{
12562218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQ,
12563218822Sdim    N_EQK | N_HLF, N_I16 | N_I32 | N_I64 | N_KEY);
12564218822Sdim  inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12565218822Sdim  neon_two_same (0, 1, et.size / 2);
1256689857Sobrien}
1256789857Sobrien
1256889857Sobrienstatic void
12569218822Sdimdo_neon_rshift_narrow (void)
1257089857Sobrien{
12571218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQI,
12572218822Sdim    N_EQK | N_HLF, N_I16 | N_I32 | N_I64 | N_KEY);
12573218822Sdim  int imm = inst.operands[2].imm;
12574218822Sdim  /* This gets the bounds check, size encoding and immediate bits calculation
12575218822Sdim     right.  */
12576218822Sdim  et.size /= 2;
12577218822Sdim
12578218822Sdim  /* If immediate is zero then we are a pseudo-instruction for
12579218822Sdim     VMOVN.I<size> <Dd>, <Qm>  */
12580218822Sdim  if (imm == 0)
12581218822Sdim    {
12582218822Sdim      inst.operands[2].present = 0;
12583218822Sdim      inst.instruction = N_MNEM_vmovn;
12584218822Sdim      do_neon_movn ();
12585218822Sdim      return;
12586218822Sdim    }
12587218822Sdim
12588218822Sdim  constraint (imm < 1 || (unsigned)imm > et.size,
12589218822Sdim              _("immediate out of range for narrowing operation"));
12590218822Sdim  neon_imm_shift (FALSE, 0, 0, et, et.size - imm);
1259189857Sobrien}
1259289857Sobrien
1259389857Sobrienstatic void
12594218822Sdimdo_neon_shll (void)
1259589857Sobrien{
12596218822Sdim  /* FIXME: Type checking when lengthening.  */
12597218822Sdim  struct neon_type_el et = neon_check_type (2, NS_QDI,
12598218822Sdim    N_EQK | N_DBL, N_I8 | N_I16 | N_I32 | N_KEY);
12599218822Sdim  unsigned imm = inst.operands[2].imm;
12600218822Sdim
12601218822Sdim  if (imm == et.size)
12602218822Sdim    {
12603218822Sdim      /* Maximum shift variant.  */
12604218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12605218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12606218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12607218822Sdim      inst.instruction |= LOW4 (inst.operands[1].reg);
12608218822Sdim      inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12609218822Sdim      inst.instruction |= neon_logbits (et.size) << 18;
12610218822Sdim
12611218822Sdim      inst.instruction = neon_dp_fixup (inst.instruction);
12612218822Sdim    }
12613218822Sdim  else
12614218822Sdim    {
12615218822Sdim      /* A more-specific type check for non-max versions.  */
12616218822Sdim      et = neon_check_type (2, NS_QDI,
12617218822Sdim        N_EQK | N_DBL, N_SU_32 | N_KEY);
12618218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
12619218822Sdim      neon_imm_shift (TRUE, et.type == NT_unsigned, 0, et, imm);
12620218822Sdim    }
1262189857Sobrien}
1262289857Sobrien
12623218822Sdim/* Check the various types for the VCVT instruction, and return which version
12624218822Sdim   the current instruction is.  */
12625218822Sdim
12626218822Sdimstatic int
12627218822Sdimneon_cvt_flavour (enum neon_shape rs)
12628218822Sdim{
12629218822Sdim#define CVT_VAR(C,X,Y)							\
12630218822Sdim  et = neon_check_type (2, rs, whole_reg | (X), whole_reg | (Y));	\
12631218822Sdim  if (et.type != NT_invtype)						\
12632218822Sdim    {									\
12633218822Sdim      inst.error = NULL;						\
12634218822Sdim      return (C);							\
12635218822Sdim    }
12636218822Sdim  struct neon_type_el et;
12637218822Sdim  unsigned whole_reg = (rs == NS_FFI || rs == NS_FD || rs == NS_DF
12638218822Sdim                        || rs == NS_FF) ? N_VFP : 0;
12639218822Sdim  /* The instruction versions which take an immediate take one register
12640218822Sdim     argument, which is extended to the width of the full register. Thus the
12641218822Sdim     "source" and "destination" registers must have the same width.  Hack that
12642218822Sdim     here by making the size equal to the key (wider, in this case) operand.  */
12643218822Sdim  unsigned key = (rs == NS_QQI || rs == NS_DDI || rs == NS_FFI) ? N_KEY : 0;
12644218822Sdim
12645218822Sdim  CVT_VAR (0, N_S32, N_F32);
12646218822Sdim  CVT_VAR (1, N_U32, N_F32);
12647218822Sdim  CVT_VAR (2, N_F32, N_S32);
12648218822Sdim  CVT_VAR (3, N_F32, N_U32);
12649218822Sdim
12650218822Sdim  whole_reg = N_VFP;
12651218822Sdim
12652218822Sdim  /* VFP instructions.  */
12653218822Sdim  CVT_VAR (4, N_F32, N_F64);
12654218822Sdim  CVT_VAR (5, N_F64, N_F32);
12655218822Sdim  CVT_VAR (6, N_S32, N_F64 | key);
12656218822Sdim  CVT_VAR (7, N_U32, N_F64 | key);
12657218822Sdim  CVT_VAR (8, N_F64 | key, N_S32);
12658218822Sdim  CVT_VAR (9, N_F64 | key, N_U32);
12659218822Sdim  /* VFP instructions with bitshift.  */
12660218822Sdim  CVT_VAR (10, N_F32 | key, N_S16);
12661218822Sdim  CVT_VAR (11, N_F32 | key, N_U16);
12662218822Sdim  CVT_VAR (12, N_F64 | key, N_S16);
12663218822Sdim  CVT_VAR (13, N_F64 | key, N_U16);
12664218822Sdim  CVT_VAR (14, N_S16, N_F32 | key);
12665218822Sdim  CVT_VAR (15, N_U16, N_F32 | key);
12666218822Sdim  CVT_VAR (16, N_S16, N_F64 | key);
12667218822Sdim  CVT_VAR (17, N_U16, N_F64 | key);
12668218822Sdim
12669218822Sdim  return -1;
12670218822Sdim#undef CVT_VAR
12671218822Sdim}
12672218822Sdim
12673218822Sdim/* Neon-syntax VFP conversions.  */
12674218822Sdim
1267589857Sobrienstatic void
12676218822Sdimdo_vfp_nsyn_cvt (enum neon_shape rs, int flavour)
1267789857Sobrien{
12678218822Sdim  const char *opname = 0;
12679218822Sdim
12680218822Sdim  if (rs == NS_DDI || rs == NS_QQI || rs == NS_FFI)
12681218822Sdim    {
12682218822Sdim      /* Conversions with immediate bitshift.  */
12683218822Sdim      const char *enc[] =
12684218822Sdim        {
12685218822Sdim          "ftosls",
12686218822Sdim          "ftouls",
12687218822Sdim          "fsltos",
12688218822Sdim          "fultos",
12689218822Sdim          NULL,
12690218822Sdim          NULL,
12691218822Sdim          "ftosld",
12692218822Sdim          "ftould",
12693218822Sdim          "fsltod",
12694218822Sdim          "fultod",
12695218822Sdim          "fshtos",
12696218822Sdim          "fuhtos",
12697218822Sdim          "fshtod",
12698218822Sdim          "fuhtod",
12699218822Sdim          "ftoshs",
12700218822Sdim          "ftouhs",
12701218822Sdim          "ftoshd",
12702218822Sdim          "ftouhd"
12703218822Sdim        };
12704218822Sdim
12705218822Sdim      if (flavour >= 0 && flavour < (int) ARRAY_SIZE (enc))
12706218822Sdim        {
12707218822Sdim          opname = enc[flavour];
12708218822Sdim          constraint (inst.operands[0].reg != inst.operands[1].reg,
12709218822Sdim                      _("operands 0 and 1 must be the same register"));
12710218822Sdim          inst.operands[1] = inst.operands[2];
12711218822Sdim          memset (&inst.operands[2], '\0', sizeof (inst.operands[2]));
12712218822Sdim        }
12713218822Sdim    }
12714218822Sdim  else
12715218822Sdim    {
12716218822Sdim      /* Conversions without bitshift.  */
12717218822Sdim      const char *enc[] =
12718218822Sdim        {
12719256790Sandrew          "ftosizs",
12720256790Sandrew          "ftouizs",
12721218822Sdim          "fsitos",
12722218822Sdim          "fuitos",
12723218822Sdim          "fcvtsd",
12724218822Sdim          "fcvtds",
12725256790Sandrew          "ftosizd",
12726256790Sandrew          "ftouizd",
12727218822Sdim          "fsitod",
12728218822Sdim          "fuitod"
12729218822Sdim        };
12730218822Sdim
12731218822Sdim      if (flavour >= 0 && flavour < (int) ARRAY_SIZE (enc))
12732218822Sdim        opname = enc[flavour];
12733218822Sdim    }
12734218822Sdim
12735218822Sdim  if (opname)
12736218822Sdim    do_vfp_nsyn_opcode (opname);
1273789857Sobrien}
1273889857Sobrien
1273989857Sobrienstatic void
12740218822Sdimdo_vfp_nsyn_cvtz (void)
1274189857Sobrien{
12742218822Sdim  enum neon_shape rs = neon_select_shape (NS_FF, NS_FD, NS_NULL);
12743218822Sdim  int flavour = neon_cvt_flavour (rs);
12744218822Sdim  const char *enc[] =
12745218822Sdim    {
12746218822Sdim      "ftosizs",
12747218822Sdim      "ftouizs",
12748218822Sdim      NULL,
12749218822Sdim      NULL,
12750218822Sdim      NULL,
12751218822Sdim      NULL,
12752218822Sdim      "ftosizd",
12753218822Sdim      "ftouizd"
12754218822Sdim    };
12755218822Sdim
12756218822Sdim  if (flavour >= 0 && flavour < (int) ARRAY_SIZE (enc) && enc[flavour])
12757218822Sdim    do_vfp_nsyn_opcode (enc[flavour]);
1275889857Sobrien}
1275989857Sobrien
1276089857Sobrienstatic void
12761218822Sdimdo_neon_cvt (void)
1276289857Sobrien{
12763218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_FFI, NS_DD, NS_QQ,
12764218822Sdim    NS_FD, NS_DF, NS_FF, NS_NULL);
12765218822Sdim  int flavour = neon_cvt_flavour (rs);
12766218822Sdim
12767218822Sdim  /* VFP rather than Neon conversions.  */
12768218822Sdim  if (flavour >= 4)
12769218822Sdim    {
12770218822Sdim      do_vfp_nsyn_cvt (rs, flavour);
12771218822Sdim      return;
12772218822Sdim    }
12773218822Sdim
12774218822Sdim  switch (rs)
12775218822Sdim    {
12776218822Sdim    case NS_DDI:
12777218822Sdim    case NS_QQI:
12778218822Sdim      {
12779218822Sdim        if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12780218822Sdim          return;
12781218822Sdim
12782218822Sdim        /* Fixed-point conversion with #0 immediate is encoded as an
12783218822Sdim           integer conversion.  */
12784218822Sdim        if (inst.operands[2].present && inst.operands[2].imm == 0)
12785218822Sdim          goto int_encode;
12786218822Sdim        unsigned immbits = 32 - inst.operands[2].imm;
12787218822Sdim        unsigned enctab[] = { 0x0000100, 0x1000100, 0x0, 0x1000000 };
12788218822Sdim        inst.instruction = NEON_ENC_IMMED (inst.instruction);
12789218822Sdim        if (flavour != -1)
12790218822Sdim          inst.instruction |= enctab[flavour];
12791218822Sdim        inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12792218822Sdim        inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12793218822Sdim        inst.instruction |= LOW4 (inst.operands[1].reg);
12794218822Sdim        inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12795218822Sdim        inst.instruction |= neon_quad (rs) << 6;
12796218822Sdim        inst.instruction |= 1 << 21;
12797218822Sdim        inst.instruction |= immbits << 16;
12798218822Sdim
12799218822Sdim        inst.instruction = neon_dp_fixup (inst.instruction);
12800218822Sdim      }
12801218822Sdim      break;
12802218822Sdim
12803218822Sdim    case NS_DD:
12804218822Sdim    case NS_QQ:
12805218822Sdim    int_encode:
12806218822Sdim      {
12807218822Sdim        unsigned enctab[] = { 0x100, 0x180, 0x0, 0x080 };
12808218822Sdim
12809218822Sdim        inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12810218822Sdim
12811218822Sdim        if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12812218822Sdim          return;
12813218822Sdim
12814218822Sdim        if (flavour != -1)
12815218822Sdim          inst.instruction |= enctab[flavour];
12816218822Sdim
12817218822Sdim        inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12818218822Sdim        inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12819218822Sdim        inst.instruction |= LOW4 (inst.operands[1].reg);
12820218822Sdim        inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12821218822Sdim        inst.instruction |= neon_quad (rs) << 6;
12822218822Sdim        inst.instruction |= 2 << 18;
12823218822Sdim
12824218822Sdim        inst.instruction = neon_dp_fixup (inst.instruction);
12825218822Sdim      }
12826218822Sdim    break;
12827218822Sdim
12828218822Sdim    default:
12829218822Sdim      /* Some VFP conversions go here (s32 <-> f32, u32 <-> f32).  */
12830218822Sdim      do_vfp_nsyn_cvt (rs, flavour);
12831218822Sdim    }
1283289857Sobrien}
1283389857Sobrien
1283489857Sobrienstatic void
12835218822Sdimneon_move_immediate (void)
1283689857Sobrien{
12837218822Sdim  enum neon_shape rs = neon_select_shape (NS_DI, NS_QI, NS_NULL);
12838218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
12839218822Sdim    N_I8 | N_I16 | N_I32 | N_I64 | N_F32 | N_KEY, N_EQK);
12840218822Sdim  unsigned immlo, immhi = 0, immbits;
12841218822Sdim  int op, cmode, float_p;
12842218822Sdim
12843218822Sdim  constraint (et.type == NT_invtype,
12844218822Sdim              _("operand size must be specified for immediate VMOV"));
12845218822Sdim
12846218822Sdim  /* We start out as an MVN instruction if OP = 1, MOV otherwise.  */
12847218822Sdim  op = (inst.instruction & (1 << 5)) != 0;
12848218822Sdim
12849218822Sdim  immlo = inst.operands[1].imm;
12850218822Sdim  if (inst.operands[1].regisimm)
12851218822Sdim    immhi = inst.operands[1].reg;
12852218822Sdim
12853218822Sdim  constraint (et.size < 32 && (immlo & ~((1 << et.size) - 1)) != 0,
12854218822Sdim              _("immediate has bits set outside the operand size"));
12855218822Sdim
12856218822Sdim  float_p = inst.operands[1].immisfloat;
12857218822Sdim
12858218822Sdim  if ((cmode = neon_cmode_for_move_imm (immlo, immhi, float_p, &immbits, &op,
12859218822Sdim                                        et.size, et.type)) == FAIL)
12860218822Sdim    {
12861218822Sdim      /* Invert relevant bits only.  */
12862218822Sdim      neon_invert_size (&immlo, &immhi, et.size);
12863218822Sdim      /* Flip from VMOV/VMVN to VMVN/VMOV. Some immediate types are unavailable
12864218822Sdim         with one or the other; those cases are caught by
12865218822Sdim         neon_cmode_for_move_imm.  */
12866218822Sdim      op = !op;
12867218822Sdim      if ((cmode = neon_cmode_for_move_imm (immlo, immhi, float_p, &immbits,
12868218822Sdim					    &op, et.size, et.type)) == FAIL)
12869218822Sdim        {
12870218822Sdim          first_error (_("immediate out of range"));
12871218822Sdim          return;
12872218822Sdim        }
12873218822Sdim    }
12874218822Sdim
12875218822Sdim  inst.instruction &= ~(1 << 5);
12876218822Sdim  inst.instruction |= op << 5;
12877218822Sdim
12878218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12879218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12880218822Sdim  inst.instruction |= neon_quad (rs) << 6;
12881218822Sdim  inst.instruction |= cmode << 8;
12882218822Sdim
12883218822Sdim  neon_write_immbits (immbits);
1288489857Sobrien}
1288589857Sobrien
1288689857Sobrienstatic void
12887218822Sdimdo_neon_mvn (void)
1288889857Sobrien{
12889218822Sdim  if (inst.operands[1].isreg)
12890218822Sdim    {
12891218822Sdim      enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
12892218822Sdim
12893218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12894218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12895218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12896218822Sdim      inst.instruction |= LOW4 (inst.operands[1].reg);
12897218822Sdim      inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12898218822Sdim      inst.instruction |= neon_quad (rs) << 6;
12899218822Sdim    }
12900218822Sdim  else
12901218822Sdim    {
12902218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
12903218822Sdim      neon_move_immediate ();
12904218822Sdim    }
12905218822Sdim
12906218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1290789857Sobrien}
1290889857Sobrien
12909218822Sdim/* Encode instructions of form:
12910218822Sdim
12911218822Sdim  |28/24|23|22|21 20|19 16|15 12|11    8|7|6|5|4|3  0|
12912218822Sdim  |  U  |x |D |size | Rn  | Rd  |x x x x|N|x|M|x| Rm |
12913218822Sdim
12914218822Sdim*/
12915218822Sdim
1291689857Sobrienstatic void
12917218822Sdimneon_mixed_length (struct neon_type_el et, unsigned size)
1291889857Sobrien{
12919218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12920218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12921218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
12922218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
12923218822Sdim  inst.instruction |= LOW4 (inst.operands[2].reg);
12924218822Sdim  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
12925218822Sdim  inst.instruction |= (et.type == NT_unsigned) << 24;
12926218822Sdim  inst.instruction |= neon_logbits (size) << 20;
12927218822Sdim
12928218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1292989857Sobrien}
1293089857Sobrien
1293189857Sobrienstatic void
12932218822Sdimdo_neon_dyadic_long (void)
1293389857Sobrien{
12934218822Sdim  /* FIXME: Type checking for lengthening op.  */
12935218822Sdim  struct neon_type_el et = neon_check_type (3, NS_QDD,
12936218822Sdim    N_EQK | N_DBL, N_EQK, N_SU_32 | N_KEY);
12937218822Sdim  neon_mixed_length (et, et.size);
1293889857Sobrien}
1293989857Sobrien
1294089857Sobrienstatic void
12941218822Sdimdo_neon_abal (void)
1294289857Sobrien{
12943218822Sdim  struct neon_type_el et = neon_check_type (3, NS_QDD,
12944218822Sdim    N_EQK | N_INT | N_DBL, N_EQK, N_SU_32 | N_KEY);
12945218822Sdim  neon_mixed_length (et, et.size);
1294689857Sobrien}
1294789857Sobrien
1294889857Sobrienstatic void
12949218822Sdimneon_mac_reg_scalar_long (unsigned regtypes, unsigned scalartypes)
1295089857Sobrien{
12951218822Sdim  if (inst.operands[2].isscalar)
12952218822Sdim    {
12953218822Sdim      struct neon_type_el et = neon_check_type (3, NS_QDS,
12954218822Sdim        N_EQK | N_DBL, N_EQK, regtypes | N_KEY);
12955218822Sdim      inst.instruction = NEON_ENC_SCALAR (inst.instruction);
12956218822Sdim      neon_mul_mac (et, et.type == NT_unsigned);
12957218822Sdim    }
12958218822Sdim  else
12959218822Sdim    {
12960218822Sdim      struct neon_type_el et = neon_check_type (3, NS_QDD,
12961218822Sdim        N_EQK | N_DBL, N_EQK, scalartypes | N_KEY);
12962218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12963218822Sdim      neon_mixed_length (et, et.size);
12964218822Sdim    }
1296589857Sobrien}
1296689857Sobrien
1296789857Sobrienstatic void
12968218822Sdimdo_neon_mac_maybe_scalar_long (void)
1296989857Sobrien{
12970218822Sdim  neon_mac_reg_scalar_long (N_S16 | N_S32 | N_U16 | N_U32, N_SU_32);
1297189857Sobrien}
1297289857Sobrien
1297389857Sobrienstatic void
12974218822Sdimdo_neon_dyadic_wide (void)
1297589857Sobrien{
12976218822Sdim  struct neon_type_el et = neon_check_type (3, NS_QQD,
12977218822Sdim    N_EQK | N_DBL, N_EQK | N_DBL, N_SU_32 | N_KEY);
12978218822Sdim  neon_mixed_length (et, et.size);
1297989857Sobrien}
1298089857Sobrien
1298189857Sobrienstatic void
12982218822Sdimdo_neon_dyadic_narrow (void)
1298389857Sobrien{
12984218822Sdim  struct neon_type_el et = neon_check_type (3, NS_QDD,
12985218822Sdim    N_EQK | N_DBL, N_EQK, N_I16 | N_I32 | N_I64 | N_KEY);
12986218822Sdim  /* Operand sign is unimportant, and the U bit is part of the opcode,
12987218822Sdim     so force the operand type to integer.  */
12988218822Sdim  et.type = NT_integer;
12989218822Sdim  neon_mixed_length (et, et.size / 2);
1299089857Sobrien}
1299189857Sobrien
1299289857Sobrienstatic void
12993218822Sdimdo_neon_mul_sat_scalar_long (void)
1299489857Sobrien{
12995218822Sdim  neon_mac_reg_scalar_long (N_S16 | N_S32, N_S16 | N_S32);
1299689857Sobrien}
1299789857Sobrien
1299889857Sobrienstatic void
12999218822Sdimdo_neon_vmull (void)
1300089857Sobrien{
13001218822Sdim  if (inst.operands[2].isscalar)
13002218822Sdim    do_neon_mac_maybe_scalar_long ();
13003218822Sdim  else
13004218822Sdim    {
13005218822Sdim      struct neon_type_el et = neon_check_type (3, NS_QDD,
13006218822Sdim        N_EQK | N_DBL, N_EQK, N_SU_32 | N_P8 | N_KEY);
13007218822Sdim      if (et.type == NT_poly)
13008218822Sdim        inst.instruction = NEON_ENC_POLY (inst.instruction);
13009218822Sdim      else
13010218822Sdim        inst.instruction = NEON_ENC_INTEGER (inst.instruction);
13011218822Sdim      /* For polynomial encoding, size field must be 0b00 and the U bit must be
13012218822Sdim         zero. Should be OK as-is.  */
13013218822Sdim      neon_mixed_length (et, et.size);
13014218822Sdim    }
1301589857Sobrien}
1301689857Sobrien
1301789857Sobrienstatic void
13018218822Sdimdo_neon_ext (void)
1301989857Sobrien{
13020218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDDI, NS_QQQI, NS_NULL);
13021218822Sdim  struct neon_type_el et = neon_check_type (3, rs,
13022218822Sdim    N_EQK, N_EQK, N_8 | N_16 | N_32 | N_64 | N_KEY);
13023218822Sdim  unsigned imm = (inst.operands[3].imm * et.size) / 8;
13024218822Sdim  constraint (imm >= (neon_quad (rs) ? 16 : 8), _("shift out of range"));
13025218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
13026218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
13027218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
13028218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
13029218822Sdim  inst.instruction |= LOW4 (inst.operands[2].reg);
13030218822Sdim  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
13031218822Sdim  inst.instruction |= neon_quad (rs) << 6;
13032218822Sdim  inst.instruction |= imm << 8;
13033218822Sdim
13034218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1303589857Sobrien}
1303689857Sobrien
1303789857Sobrienstatic void
13038218822Sdimdo_neon_rev (void)
1303989857Sobrien{
13040218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13041218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13042218822Sdim    N_EQK, N_8 | N_16 | N_32 | N_KEY);
13043218822Sdim  unsigned op = (inst.instruction >> 7) & 3;
13044218822Sdim  /* N (width of reversed regions) is encoded as part of the bitmask. We
13045218822Sdim     extract it here to check the elements to be reversed are smaller.
13046218822Sdim     Otherwise we'd get a reserved instruction.  */
13047218822Sdim  unsigned elsize = (op == 2) ? 16 : (op == 1) ? 32 : (op == 0) ? 64 : 0;
13048218822Sdim  assert (elsize != 0);
13049218822Sdim  constraint (et.size >= elsize,
13050218822Sdim              _("elements must be smaller than reversal region"));
13051218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1305289857Sobrien}
1305389857Sobrien
1305489857Sobrienstatic void
13055218822Sdimdo_neon_dup (void)
1305689857Sobrien{
13057218822Sdim  if (inst.operands[1].isscalar)
13058218822Sdim    {
13059218822Sdim      enum neon_shape rs = neon_select_shape (NS_DS, NS_QS, NS_NULL);
13060218822Sdim      struct neon_type_el et = neon_check_type (2, rs,
13061218822Sdim        N_EQK, N_8 | N_16 | N_32 | N_KEY);
13062218822Sdim      unsigned sizebits = et.size >> 3;
13063218822Sdim      unsigned dm = NEON_SCALAR_REG (inst.operands[1].reg);
13064218822Sdim      int logsize = neon_logbits (et.size);
13065218822Sdim      unsigned x = NEON_SCALAR_INDEX (inst.operands[1].reg) << logsize;
13066218822Sdim
13067218822Sdim      if (vfp_or_neon_is_neon (NEON_CHECK_CC) == FAIL)
13068218822Sdim        return;
13069218822Sdim
13070218822Sdim      inst.instruction = NEON_ENC_SCALAR (inst.instruction);
13071218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
13072218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
13073218822Sdim      inst.instruction |= LOW4 (dm);
13074218822Sdim      inst.instruction |= HI1 (dm) << 5;
13075218822Sdim      inst.instruction |= neon_quad (rs) << 6;
13076218822Sdim      inst.instruction |= x << 17;
13077218822Sdim      inst.instruction |= sizebits << 16;
13078218822Sdim
13079218822Sdim      inst.instruction = neon_dp_fixup (inst.instruction);
13080218822Sdim    }
13081218822Sdim  else
13082218822Sdim    {
13083218822Sdim      enum neon_shape rs = neon_select_shape (NS_DR, NS_QR, NS_NULL);
13084218822Sdim      struct neon_type_el et = neon_check_type (2, rs,
13085218822Sdim        N_8 | N_16 | N_32 | N_KEY, N_EQK);
13086218822Sdim      /* Duplicate ARM register to lanes of vector.  */
13087218822Sdim      inst.instruction = NEON_ENC_ARMREG (inst.instruction);
13088218822Sdim      switch (et.size)
13089218822Sdim        {
13090218822Sdim        case 8:  inst.instruction |= 0x400000; break;
13091218822Sdim        case 16: inst.instruction |= 0x000020; break;
13092218822Sdim        case 32: inst.instruction |= 0x000000; break;
13093218822Sdim        default: break;
13094218822Sdim        }
13095218822Sdim      inst.instruction |= LOW4 (inst.operands[1].reg) << 12;
13096218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 16;
13097218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 7;
13098218822Sdim      inst.instruction |= neon_quad (rs) << 21;
13099218822Sdim      /* The encoding for this instruction is identical for the ARM and Thumb
13100218822Sdim         variants, except for the condition field.  */
13101218822Sdim      do_vfp_cond_or_thumb ();
13102218822Sdim    }
1310389857Sobrien}
1310489857Sobrien
13105218822Sdim/* VMOV has particularly many variations. It can be one of:
13106218822Sdim     0. VMOV<c><q> <Qd>, <Qm>
13107218822Sdim     1. VMOV<c><q> <Dd>, <Dm>
13108218822Sdim   (Register operations, which are VORR with Rm = Rn.)
13109218822Sdim     2. VMOV<c><q>.<dt> <Qd>, #<imm>
13110218822Sdim     3. VMOV<c><q>.<dt> <Dd>, #<imm>
13111218822Sdim   (Immediate loads.)
13112218822Sdim     4. VMOV<c><q>.<size> <Dn[x]>, <Rd>
13113218822Sdim   (ARM register to scalar.)
13114218822Sdim     5. VMOV<c><q> <Dm>, <Rd>, <Rn>
13115218822Sdim   (Two ARM registers to vector.)
13116218822Sdim     6. VMOV<c><q>.<dt> <Rd>, <Dn[x]>
13117218822Sdim   (Scalar to ARM register.)
13118218822Sdim     7. VMOV<c><q> <Rd>, <Rn>, <Dm>
13119218822Sdim   (Vector to two ARM registers.)
13120218822Sdim     8. VMOV.F32 <Sd>, <Sm>
13121218822Sdim     9. VMOV.F64 <Dd>, <Dm>
13122218822Sdim   (VFP register moves.)
13123218822Sdim    10. VMOV.F32 <Sd>, #imm
13124218822Sdim    11. VMOV.F64 <Dd>, #imm
13125218822Sdim   (VFP float immediate load.)
13126218822Sdim    12. VMOV <Rd>, <Sm>
13127218822Sdim   (VFP single to ARM reg.)
13128218822Sdim    13. VMOV <Sd>, <Rm>
13129218822Sdim   (ARM reg to VFP single.)
13130218822Sdim    14. VMOV <Rd>, <Re>, <Sn>, <Sm>
13131218822Sdim   (Two ARM regs to two VFP singles.)
13132218822Sdim    15. VMOV <Sd>, <Se>, <Rn>, <Rm>
13133218822Sdim   (Two VFP singles to two ARM regs.)
13134218822Sdim
13135218822Sdim   These cases can be disambiguated using neon_select_shape, except cases 1/9
13136218822Sdim   and 3/11 which depend on the operand type too.
13137218822Sdim
13138218822Sdim   All the encoded bits are hardcoded by this function.
13139218822Sdim
13140218822Sdim   Cases 4, 6 may be used with VFPv1 and above (only 32-bit transfers!).
13141218822Sdim   Cases 5, 7 may be used with VFPv2 and above.
13142218822Sdim
13143218822Sdim   FIXME: Some of the checking may be a bit sloppy (in a couple of cases you
13144218822Sdim   can specify a type where it doesn't make sense to, and is ignored).
13145218822Sdim*/
13146218822Sdim
1314789857Sobrienstatic void
13148218822Sdimdo_neon_mov (void)
1314989857Sobrien{
13150218822Sdim  enum neon_shape rs = neon_select_shape (NS_RRFF, NS_FFRR, NS_DRR, NS_RRD,
13151218822Sdim    NS_QQ, NS_DD, NS_QI, NS_DI, NS_SR, NS_RS, NS_FF, NS_FI, NS_RF, NS_FR,
13152218822Sdim    NS_NULL);
13153218822Sdim  struct neon_type_el et;
13154218822Sdim  const char *ldconst = 0;
1315589857Sobrien
13156218822Sdim  switch (rs)
1315789857Sobrien    {
13158218822Sdim    case NS_DD:  /* case 1/9.  */
13159218822Sdim      et = neon_check_type (2, rs, N_EQK, N_F64 | N_KEY);
13160218822Sdim      /* It is not an error here if no type is given.  */
13161218822Sdim      inst.error = NULL;
13162218822Sdim      if (et.type == NT_float && et.size == 64)
13163218822Sdim        {
13164218822Sdim          do_vfp_nsyn_opcode ("fcpyd");
13165218822Sdim          break;
13166218822Sdim        }
13167218822Sdim      /* fall through.  */
1316889857Sobrien
13169218822Sdim    case NS_QQ:  /* case 0/1.  */
13170218822Sdim      {
13171218822Sdim        if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
13172218822Sdim          return;
13173218822Sdim        /* The architecture manual I have doesn't explicitly state which
13174218822Sdim           value the U bit should have for register->register moves, but
13175218822Sdim           the equivalent VORR instruction has U = 0, so do that.  */
13176218822Sdim        inst.instruction = 0x0200110;
13177218822Sdim        inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
13178218822Sdim        inst.instruction |= HI1 (inst.operands[0].reg) << 22;
13179218822Sdim        inst.instruction |= LOW4 (inst.operands[1].reg);
13180218822Sdim        inst.instruction |= HI1 (inst.operands[1].reg) << 5;
13181218822Sdim        inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
13182218822Sdim        inst.instruction |= HI1 (inst.operands[1].reg) << 7;
13183218822Sdim        inst.instruction |= neon_quad (rs) << 6;
13184218822Sdim
13185218822Sdim        inst.instruction = neon_dp_fixup (inst.instruction);
13186218822Sdim      }
13187218822Sdim      break;
13188218822Sdim
13189218822Sdim    case NS_DI:  /* case 3/11.  */
13190218822Sdim      et = neon_check_type (2, rs, N_EQK, N_F64 | N_KEY);
13191218822Sdim      inst.error = NULL;
13192218822Sdim      if (et.type == NT_float && et.size == 64)
13193218822Sdim        {
13194218822Sdim          /* case 11 (fconstd).  */
13195218822Sdim          ldconst = "fconstd";
13196218822Sdim          goto encode_fconstd;
13197218822Sdim        }
13198218822Sdim      /* fall through.  */
13199218822Sdim
13200218822Sdim    case NS_QI:  /* case 2/3.  */
13201218822Sdim      if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
13202218822Sdim        return;
13203218822Sdim      inst.instruction = 0x0800010;
13204218822Sdim      neon_move_immediate ();
13205218822Sdim      inst.instruction = neon_dp_fixup (inst.instruction);
13206218822Sdim      break;
13207218822Sdim
13208218822Sdim    case NS_SR:  /* case 4.  */
13209218822Sdim      {
13210218822Sdim        unsigned bcdebits = 0;
13211218822Sdim        struct neon_type_el et = neon_check_type (2, NS_NULL,
13212218822Sdim          N_8 | N_16 | N_32 | N_KEY, N_EQK);
13213218822Sdim        int logsize = neon_logbits (et.size);
13214218822Sdim        unsigned dn = NEON_SCALAR_REG (inst.operands[0].reg);
13215218822Sdim        unsigned x = NEON_SCALAR_INDEX (inst.operands[0].reg);
13216218822Sdim
13217218822Sdim        constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v1),
13218218822Sdim                    _(BAD_FPU));
13219218822Sdim        constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1)
13220218822Sdim                    && et.size != 32, _(BAD_FPU));
13221218822Sdim        constraint (et.type == NT_invtype, _("bad type for scalar"));
13222218822Sdim        constraint (x >= 64 / et.size, _("scalar index out of range"));
13223218822Sdim
13224218822Sdim        switch (et.size)
13225218822Sdim          {
13226218822Sdim          case 8:  bcdebits = 0x8; break;
13227218822Sdim          case 16: bcdebits = 0x1; break;
13228218822Sdim          case 32: bcdebits = 0x0; break;
13229218822Sdim          default: ;
13230218822Sdim          }
13231218822Sdim
13232218822Sdim        bcdebits |= x << logsize;
13233218822Sdim
13234218822Sdim        inst.instruction = 0xe000b10;
13235218822Sdim        do_vfp_cond_or_thumb ();
13236218822Sdim        inst.instruction |= LOW4 (dn) << 16;
13237218822Sdim        inst.instruction |= HI1 (dn) << 7;
13238218822Sdim        inst.instruction |= inst.operands[1].reg << 12;
13239218822Sdim        inst.instruction |= (bcdebits & 3) << 5;
13240218822Sdim        inst.instruction |= (bcdebits >> 2) << 21;
13241218822Sdim      }
13242218822Sdim      break;
13243218822Sdim
13244218822Sdim    case NS_DRR:  /* case 5 (fmdrr).  */
13245218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v2),
13246218822Sdim                  _(BAD_FPU));
13247218822Sdim
13248218822Sdim      inst.instruction = 0xc400b10;
13249218822Sdim      do_vfp_cond_or_thumb ();
13250218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg);
13251218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 5;
13252218822Sdim      inst.instruction |= inst.operands[1].reg << 12;
13253218822Sdim      inst.instruction |= inst.operands[2].reg << 16;
13254218822Sdim      break;
13255218822Sdim
13256218822Sdim    case NS_RS:  /* case 6.  */
13257218822Sdim      {
13258218822Sdim        struct neon_type_el et = neon_check_type (2, NS_NULL,
13259218822Sdim          N_EQK, N_S8 | N_S16 | N_U8 | N_U16 | N_32 | N_KEY);
13260218822Sdim        unsigned logsize = neon_logbits (et.size);
13261218822Sdim        unsigned dn = NEON_SCALAR_REG (inst.operands[1].reg);
13262218822Sdim        unsigned x = NEON_SCALAR_INDEX (inst.operands[1].reg);
13263218822Sdim        unsigned abcdebits = 0;
13264218822Sdim
13265218822Sdim        constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v1),
13266218822Sdim                    _(BAD_FPU));
13267218822Sdim        constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1)
13268218822Sdim                    && et.size != 32, _(BAD_FPU));
13269218822Sdim        constraint (et.type == NT_invtype, _("bad type for scalar"));
13270218822Sdim        constraint (x >= 64 / et.size, _("scalar index out of range"));
13271218822Sdim
13272218822Sdim        switch (et.size)
13273218822Sdim          {
13274218822Sdim          case 8:  abcdebits = (et.type == NT_signed) ? 0x08 : 0x18; break;
13275218822Sdim          case 16: abcdebits = (et.type == NT_signed) ? 0x01 : 0x11; break;
13276218822Sdim          case 32: abcdebits = 0x00; break;
13277218822Sdim          default: ;
13278218822Sdim          }
13279218822Sdim
13280218822Sdim        abcdebits |= x << logsize;
13281218822Sdim        inst.instruction = 0xe100b10;
13282218822Sdim        do_vfp_cond_or_thumb ();
13283218822Sdim        inst.instruction |= LOW4 (dn) << 16;
13284218822Sdim        inst.instruction |= HI1 (dn) << 7;
13285218822Sdim        inst.instruction |= inst.operands[0].reg << 12;
13286218822Sdim        inst.instruction |= (abcdebits & 3) << 5;
13287218822Sdim        inst.instruction |= (abcdebits >> 2) << 21;
13288218822Sdim      }
13289218822Sdim      break;
13290218822Sdim
13291218822Sdim    case NS_RRD:  /* case 7 (fmrrd).  */
13292218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v2),
13293218822Sdim                  _(BAD_FPU));
13294218822Sdim
13295218822Sdim      inst.instruction = 0xc500b10;
13296218822Sdim      do_vfp_cond_or_thumb ();
13297218822Sdim      inst.instruction |= inst.operands[0].reg << 12;
13298218822Sdim      inst.instruction |= inst.operands[1].reg << 16;
13299218822Sdim      inst.instruction |= LOW4 (inst.operands[2].reg);
13300218822Sdim      inst.instruction |= HI1 (inst.operands[2].reg) << 5;
13301218822Sdim      break;
13302218822Sdim
13303218822Sdim    case NS_FF:  /* case 8 (fcpys).  */
13304218822Sdim      do_vfp_nsyn_opcode ("fcpys");
13305218822Sdim      break;
13306218822Sdim
13307218822Sdim    case NS_FI:  /* case 10 (fconsts).  */
13308218822Sdim      ldconst = "fconsts";
13309218822Sdim      encode_fconstd:
13310218822Sdim      if (is_quarter_float (inst.operands[1].imm))
13311218822Sdim        {
13312218822Sdim          inst.operands[1].imm = neon_qfloat_bits (inst.operands[1].imm);
13313218822Sdim          do_vfp_nsyn_opcode (ldconst);
13314218822Sdim        }
13315218822Sdim      else
13316218822Sdim        first_error (_("immediate out of range"));
13317218822Sdim      break;
13318218822Sdim
13319218822Sdim    case NS_RF:  /* case 12 (fmrs).  */
13320218822Sdim      do_vfp_nsyn_opcode ("fmrs");
13321218822Sdim      break;
13322218822Sdim
13323218822Sdim    case NS_FR:  /* case 13 (fmsr).  */
13324218822Sdim      do_vfp_nsyn_opcode ("fmsr");
13325218822Sdim      break;
13326218822Sdim
13327218822Sdim    /* The encoders for the fmrrs and fmsrr instructions expect three operands
13328218822Sdim       (one of which is a list), but we have parsed four.  Do some fiddling to
13329218822Sdim       make the operands what do_vfp_reg2_from_sp2 and do_vfp_sp2_from_reg2
13330218822Sdim       expect.  */
13331218822Sdim    case NS_RRFF:  /* case 14 (fmrrs).  */
13332218822Sdim      constraint (inst.operands[3].reg != inst.operands[2].reg + 1,
13333218822Sdim                  _("VFP registers must be adjacent"));
13334218822Sdim      inst.operands[2].imm = 2;
13335218822Sdim      memset (&inst.operands[3], '\0', sizeof (inst.operands[3]));
13336218822Sdim      do_vfp_nsyn_opcode ("fmrrs");
13337218822Sdim      break;
13338218822Sdim
13339218822Sdim    case NS_FFRR:  /* case 15 (fmsrr).  */
13340218822Sdim      constraint (inst.operands[1].reg != inst.operands[0].reg + 1,
13341218822Sdim                  _("VFP registers must be adjacent"));
13342218822Sdim      inst.operands[1] = inst.operands[2];
13343218822Sdim      inst.operands[2] = inst.operands[3];
13344218822Sdim      inst.operands[0].imm = 2;
13345218822Sdim      memset (&inst.operands[3], '\0', sizeof (inst.operands[3]));
13346218822Sdim      do_vfp_nsyn_opcode ("fmsrr");
13347218822Sdim      break;
13348218822Sdim
13349218822Sdim    default:
13350218822Sdim      abort ();
13351218822Sdim    }
13352218822Sdim}
13353218822Sdim
13354218822Sdimstatic void
13355218822Sdimdo_neon_rshift_round_imm (void)
13356218822Sdim{
13357218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
13358218822Sdim  struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_SU_ALL | N_KEY);
13359218822Sdim  int imm = inst.operands[2].imm;
13360218822Sdim
13361218822Sdim  /* imm == 0 case is encoded as VMOV for V{R}SHR.  */
13362218822Sdim  if (imm == 0)
13363218822Sdim    {
13364218822Sdim      inst.operands[2].present = 0;
13365218822Sdim      do_neon_mov ();
1336689857Sobrien      return;
1336789857Sobrien    }
1336889857Sobrien
13369218822Sdim  constraint (imm < 1 || (unsigned)imm > et.size,
13370218822Sdim              _("immediate out of range for shift"));
13371218822Sdim  neon_imm_shift (TRUE, et.type == NT_unsigned, neon_quad (rs), et,
13372218822Sdim                  et.size - imm);
1337389857Sobrien}
1337489857Sobrien
1337589857Sobrienstatic void
13376218822Sdimdo_neon_movl (void)
1337789857Sobrien{
13378218822Sdim  struct neon_type_el et = neon_check_type (2, NS_QD,
13379218822Sdim    N_EQK | N_DBL, N_SU_32 | N_KEY);
13380218822Sdim  unsigned sizebits = et.size >> 3;
13381218822Sdim  inst.instruction |= sizebits << 19;
13382218822Sdim  neon_two_same (0, et.type == NT_unsigned, -1);
13383218822Sdim}
1338489857Sobrien
13385218822Sdimstatic void
13386218822Sdimdo_neon_trn (void)
13387218822Sdim{
13388218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13389218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13390218822Sdim    N_EQK, N_8 | N_16 | N_32 | N_KEY);
13391218822Sdim  inst.instruction = NEON_ENC_INTEGER (inst.instruction);
13392218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
13393218822Sdim}
13394218822Sdim
13395218822Sdimstatic void
13396218822Sdimdo_neon_zip_uzp (void)
13397218822Sdim{
13398218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13399218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13400218822Sdim    N_EQK, N_8 | N_16 | N_32 | N_KEY);
13401218822Sdim  if (rs == NS_DD && et.size == 32)
1340289857Sobrien    {
13403218822Sdim      /* Special case: encode as VTRN.32 <Dd>, <Dm>.  */
13404218822Sdim      inst.instruction = N_MNEM_vtrn;
13405218822Sdim      do_neon_trn ();
1340689857Sobrien      return;
1340789857Sobrien    }
13408218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
13409218822Sdim}
1341089857Sobrien
13411218822Sdimstatic void
13412218822Sdimdo_neon_sat_abs_neg (void)
13413218822Sdim{
13414218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13415218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13416218822Sdim    N_EQK, N_S8 | N_S16 | N_S32 | N_KEY);
13417218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1341889857Sobrien}
1341989857Sobrien
1342089857Sobrienstatic void
13421218822Sdimdo_neon_pair_long (void)
1342289857Sobrien{
13423218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13424218822Sdim  struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_SU_32 | N_KEY);
13425218822Sdim  /* Unsigned is encoded in OP field (bit 7) for these instruction.  */
13426218822Sdim  inst.instruction |= (et.type == NT_unsigned) << 7;
13427218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1342889857Sobrien}
1342989857Sobrien
1343089857Sobrienstatic void
13431218822Sdimdo_neon_recip_est (void)
1343289857Sobrien{
13433218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13434218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13435218822Sdim    N_EQK | N_FLT, N_F32 | N_U32 | N_KEY);
13436218822Sdim  inst.instruction |= (et.type == NT_float) << 8;
13437218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1343889857Sobrien}
1343989857Sobrien
1344089857Sobrienstatic void
13441218822Sdimdo_neon_cls (void)
1344289857Sobrien{
13443218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13444218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13445218822Sdim    N_EQK, N_S8 | N_S16 | N_S32 | N_KEY);
13446218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1344789857Sobrien}
1344889857Sobrien
1344989857Sobrienstatic void
13450218822Sdimdo_neon_clz (void)
1345189857Sobrien{
13452218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13453218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13454218822Sdim    N_EQK, N_I8 | N_I16 | N_I32 | N_KEY);
13455218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1345689857Sobrien}
1345789857Sobrien
1345889857Sobrienstatic void
13459218822Sdimdo_neon_cnt (void)
1346089857Sobrien{
13461218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13462218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13463218822Sdim    N_EQK | N_INT, N_8 | N_KEY);
13464218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1346589857Sobrien}
1346689857Sobrien
1346789857Sobrienstatic void
13468218822Sdimdo_neon_swp (void)
1346989857Sobrien{
13470218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13471218822Sdim  neon_two_same (neon_quad (rs), 1, -1);
1347289857Sobrien}
1347389857Sobrien
13474218822Sdimstatic void
13475218822Sdimdo_neon_tbl_tbx (void)
13476218822Sdim{
13477218822Sdim  unsigned listlenbits;
13478218822Sdim  neon_check_type (3, NS_DLD, N_EQK, N_EQK, N_8 | N_KEY);
13479218822Sdim
13480218822Sdim  if (inst.operands[1].imm < 1 || inst.operands[1].imm > 4)
13481218822Sdim    {
13482218822Sdim      first_error (_("bad list length for table lookup"));
13483218822Sdim      return;
13484218822Sdim    }
13485218822Sdim
13486218822Sdim  listlenbits = inst.operands[1].imm - 1;
13487218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
13488218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
13489218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
13490218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
13491218822Sdim  inst.instruction |= LOW4 (inst.operands[2].reg);
13492218822Sdim  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
13493218822Sdim  inst.instruction |= listlenbits << 8;
13494218822Sdim
13495218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
13496218822Sdim}
1349789857Sobrien
1349889857Sobrienstatic void
13499218822Sdimdo_neon_ldm_stm (void)
1350089857Sobrien{
13501218822Sdim  /* P, U and L bits are part of bitmask.  */
13502218822Sdim  int is_dbmode = (inst.instruction & (1 << 24)) != 0;
13503218822Sdim  unsigned offsetbits = inst.operands[1].imm * 2;
1350489857Sobrien
13505218822Sdim  if (inst.operands[1].issingle)
13506218822Sdim    {
13507218822Sdim      do_vfp_nsyn_ldm_stm (is_dbmode);
13508218822Sdim      return;
13509218822Sdim    }
1351089857Sobrien
13511218822Sdim  constraint (is_dbmode && !inst.operands[0].writeback,
13512218822Sdim              _("writeback (!) must be used for VLDMDB and VSTMDB"));
1351389857Sobrien
13514218822Sdim  constraint (inst.operands[1].imm < 1 || inst.operands[1].imm > 16,
13515218822Sdim              _("register list must contain at least 1 and at most 16 "
13516218822Sdim                "registers"));
13517218822Sdim
13518218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
13519218822Sdim  inst.instruction |= inst.operands[0].writeback << 21;
13520218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 12;
13521218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 22;
13522218822Sdim
13523218822Sdim  inst.instruction |= offsetbits;
13524218822Sdim
13525218822Sdim  do_vfp_cond_or_thumb ();
13526218822Sdim}
13527218822Sdim
13528218822Sdimstatic void
13529218822Sdimdo_neon_ldr_str (void)
13530218822Sdim{
13531218822Sdim  int is_ldr = (inst.instruction & (1 << 20)) != 0;
13532218822Sdim
13533218822Sdim  if (inst.operands[0].issingle)
1353489857Sobrien    {
13535218822Sdim      if (is_ldr)
13536218822Sdim        do_vfp_nsyn_opcode ("flds");
13537218822Sdim      else
13538218822Sdim        do_vfp_nsyn_opcode ("fsts");
1353989857Sobrien    }
1354089857Sobrien  else
13541218822Sdim    {
13542218822Sdim      if (is_ldr)
13543218822Sdim        do_vfp_nsyn_opcode ("fldd");
13544218822Sdim      else
13545218822Sdim        do_vfp_nsyn_opcode ("fstd");
13546218822Sdim    }
1354789857Sobrien}
1354889857Sobrien
13549218822Sdim/* "interleave" version also handles non-interleaving register VLD1/VST1
13550218822Sdim   instructions.  */
1355189857Sobrien
1355289857Sobrienstatic void
13553218822Sdimdo_neon_ld_st_interleave (void)
1355489857Sobrien{
13555218822Sdim  struct neon_type_el et = neon_check_type (1, NS_NULL,
13556218822Sdim                                            N_8 | N_16 | N_32 | N_64);
13557218822Sdim  unsigned alignbits = 0;
13558218822Sdim  unsigned idx;
13559218822Sdim  /* The bits in this table go:
13560218822Sdim     0: register stride of one (0) or two (1)
13561218822Sdim     1,2: register list length, minus one (1, 2, 3, 4).
13562218822Sdim     3,4: <n> in instruction type, minus one (VLD<n> / VST<n>).
13563218822Sdim     We use -1 for invalid entries.  */
13564218822Sdim  const int typetable[] =
13565218822Sdim    {
13566218822Sdim      0x7,  -1, 0xa,  -1, 0x6,  -1, 0x2,  -1, /* VLD1 / VST1.  */
13567218822Sdim       -1,  -1, 0x8, 0x9,  -1,  -1, 0x3,  -1, /* VLD2 / VST2.  */
13568218822Sdim       -1,  -1,  -1,  -1, 0x4, 0x5,  -1,  -1, /* VLD3 / VST3.  */
13569218822Sdim       -1,  -1,  -1,  -1,  -1,  -1, 0x0, 0x1  /* VLD4 / VST4.  */
13570218822Sdim    };
13571218822Sdim  int typebits;
1357289857Sobrien
13573218822Sdim  if (et.type == NT_invtype)
13574218822Sdim    return;
1357589857Sobrien
13576218822Sdim  if (inst.operands[1].immisalign)
13577218822Sdim    switch (inst.operands[1].imm >> 8)
13578218822Sdim      {
13579218822Sdim      case 64: alignbits = 1; break;
13580218822Sdim      case 128:
13581218822Sdim        if (NEON_REGLIST_LENGTH (inst.operands[0].imm) == 3)
13582218822Sdim          goto bad_alignment;
13583218822Sdim        alignbits = 2;
13584218822Sdim        break;
13585218822Sdim      case 256:
13586218822Sdim        if (NEON_REGLIST_LENGTH (inst.operands[0].imm) == 3)
13587218822Sdim          goto bad_alignment;
13588218822Sdim        alignbits = 3;
13589218822Sdim        break;
13590218822Sdim      default:
13591218822Sdim      bad_alignment:
13592218822Sdim        first_error (_("bad alignment"));
13593218822Sdim        return;
13594218822Sdim      }
1359589857Sobrien
13596218822Sdim  inst.instruction |= alignbits << 4;
13597218822Sdim  inst.instruction |= neon_logbits (et.size) << 6;
13598218822Sdim
13599218822Sdim  /* Bits [4:6] of the immediate in a list specifier encode register stride
13600218822Sdim     (minus 1) in bit 4, and list length in bits [5:6]. We put the <n> of
13601218822Sdim     VLD<n>/VST<n> in bits [9:8] of the initial bitmask. Suck it out here, look
13602218822Sdim     up the right value for "type" in a table based on this value and the given
13603218822Sdim     list style, then stick it back.  */
13604218822Sdim  idx = ((inst.operands[0].imm >> 4) & 7)
13605218822Sdim        | (((inst.instruction >> 8) & 3) << 3);
13606218822Sdim
13607218822Sdim  typebits = typetable[idx];
13608218822Sdim
13609218822Sdim  constraint (typebits == -1, _("bad list type for instruction"));
13610218822Sdim
13611218822Sdim  inst.instruction &= ~0xf00;
13612218822Sdim  inst.instruction |= typebits << 8;
13613218822Sdim}
13614218822Sdim
13615218822Sdim/* Check alignment is valid for do_neon_ld_st_lane and do_neon_ld_dup.
13616218822Sdim   *DO_ALIGN is set to 1 if the relevant alignment bit should be set, 0
13617218822Sdim   otherwise. The variable arguments are a list of pairs of legal (size, align)
13618218822Sdim   values, terminated with -1.  */
13619218822Sdim
13620218822Sdimstatic int
13621218822Sdimneon_alignment_bit (int size, int align, int *do_align, ...)
13622218822Sdim{
13623218822Sdim  va_list ap;
13624218822Sdim  int result = FAIL, thissize, thisalign;
13625218822Sdim
13626218822Sdim  if (!inst.operands[1].immisalign)
1362789857Sobrien    {
13628218822Sdim      *do_align = 0;
13629218822Sdim      return SUCCESS;
1363089857Sobrien    }
13631218822Sdim
13632218822Sdim  va_start (ap, do_align);
13633218822Sdim
13634218822Sdim  do
13635218822Sdim    {
13636218822Sdim      thissize = va_arg (ap, int);
13637218822Sdim      if (thissize == -1)
13638218822Sdim        break;
13639218822Sdim      thisalign = va_arg (ap, int);
13640218822Sdim
13641218822Sdim      if (size == thissize && align == thisalign)
13642218822Sdim        result = SUCCESS;
13643218822Sdim    }
13644218822Sdim  while (result != SUCCESS);
13645218822Sdim
13646218822Sdim  va_end (ap);
13647218822Sdim
13648218822Sdim  if (result == SUCCESS)
13649218822Sdim    *do_align = 1;
1365089857Sobrien  else
13651218822Sdim    first_error (_("unsupported alignment for instruction"));
13652218822Sdim
13653218822Sdim  return result;
1365489857Sobrien}
1365589857Sobrien
1365689857Sobrienstatic void
13657218822Sdimdo_neon_ld_st_lane (void)
1365889857Sobrien{
13659218822Sdim  struct neon_type_el et = neon_check_type (1, NS_NULL, N_8 | N_16 | N_32);
13660218822Sdim  int align_good, do_align = 0;
13661218822Sdim  int logsize = neon_logbits (et.size);
13662218822Sdim  int align = inst.operands[1].imm >> 8;
13663218822Sdim  int n = (inst.instruction >> 8) & 3;
13664218822Sdim  int max_el = 64 / et.size;
13665218822Sdim
13666218822Sdim  if (et.type == NT_invtype)
13667218822Sdim    return;
13668218822Sdim
13669218822Sdim  constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != n + 1,
13670218822Sdim              _("bad list length"));
13671218822Sdim  constraint (NEON_LANE (inst.operands[0].imm) >= max_el,
13672218822Sdim              _("scalar index out of range"));
13673218822Sdim  constraint (n != 0 && NEON_REG_STRIDE (inst.operands[0].imm) == 2
13674218822Sdim              && et.size == 8,
13675218822Sdim              _("stride of 2 unavailable when element size is 8"));
13676218822Sdim
13677218822Sdim  switch (n)
13678218822Sdim    {
13679218822Sdim    case 0:  /* VLD1 / VST1.  */
13680218822Sdim      align_good = neon_alignment_bit (et.size, align, &do_align, 16, 16,
13681218822Sdim                                       32, 32, -1);
13682218822Sdim      if (align_good == FAIL)
13683218822Sdim        return;
13684218822Sdim      if (do_align)
13685218822Sdim        {
13686218822Sdim          unsigned alignbits = 0;
13687218822Sdim          switch (et.size)
13688218822Sdim            {
13689218822Sdim            case 16: alignbits = 0x1; break;
13690218822Sdim            case 32: alignbits = 0x3; break;
13691218822Sdim            default: ;
13692218822Sdim            }
13693218822Sdim          inst.instruction |= alignbits << 4;
13694218822Sdim        }
13695218822Sdim      break;
1369689857Sobrien
13697218822Sdim    case 1:  /* VLD2 / VST2.  */
13698218822Sdim      align_good = neon_alignment_bit (et.size, align, &do_align, 8, 16, 16, 32,
13699218822Sdim                                       32, 64, -1);
13700218822Sdim      if (align_good == FAIL)
13701218822Sdim        return;
13702218822Sdim      if (do_align)
13703218822Sdim        inst.instruction |= 1 << 4;
13704218822Sdim      break;
1370589857Sobrien
13706218822Sdim    case 2:  /* VLD3 / VST3.  */
13707218822Sdim      constraint (inst.operands[1].immisalign,
13708218822Sdim                  _("can't use alignment with this instruction"));
13709218822Sdim      break;
1371089857Sobrien
13711218822Sdim    case 3:  /* VLD4 / VST4.  */
13712218822Sdim      align_good = neon_alignment_bit (et.size, align, &do_align, 8, 32,
13713218822Sdim                                       16, 64, 32, 64, 32, 128, -1);
13714218822Sdim      if (align_good == FAIL)
13715218822Sdim        return;
13716218822Sdim      if (do_align)
13717218822Sdim        {
13718218822Sdim          unsigned alignbits = 0;
13719218822Sdim          switch (et.size)
13720218822Sdim            {
13721218822Sdim            case 8:  alignbits = 0x1; break;
13722218822Sdim            case 16: alignbits = 0x1; break;
13723218822Sdim            case 32: alignbits = (align == 64) ? 0x1 : 0x2; break;
13724218822Sdim            default: ;
13725218822Sdim            }
13726218822Sdim          inst.instruction |= alignbits << 4;
13727218822Sdim        }
13728218822Sdim      break;
13729218822Sdim
13730218822Sdim    default: ;
1373189857Sobrien    }
13732218822Sdim
13733218822Sdim  /* Reg stride of 2 is encoded in bit 5 when size==16, bit 6 when size==32.  */
13734218822Sdim  if (n != 0 && NEON_REG_STRIDE (inst.operands[0].imm) == 2)
13735218822Sdim    inst.instruction |= 1 << (4 + logsize);
13736218822Sdim
13737218822Sdim  inst.instruction |= NEON_LANE (inst.operands[0].imm) << (logsize + 5);
13738218822Sdim  inst.instruction |= logsize << 10;
1373989857Sobrien}
1374089857Sobrien
13741218822Sdim/* Encode single n-element structure to all lanes VLD<n> instructions.  */
1374289857Sobrien
1374389857Sobrienstatic void
13744218822Sdimdo_neon_ld_dup (void)
1374589857Sobrien{
13746218822Sdim  struct neon_type_el et = neon_check_type (1, NS_NULL, N_8 | N_16 | N_32);
13747218822Sdim  int align_good, do_align = 0;
1374889857Sobrien
13749218822Sdim  if (et.type == NT_invtype)
13750218822Sdim    return;
1375189857Sobrien
13752218822Sdim  switch ((inst.instruction >> 8) & 3)
13753218822Sdim    {
13754218822Sdim    case 0:  /* VLD1.  */
13755218822Sdim      assert (NEON_REG_STRIDE (inst.operands[0].imm) != 2);
13756218822Sdim      align_good = neon_alignment_bit (et.size, inst.operands[1].imm >> 8,
13757218822Sdim                                       &do_align, 16, 16, 32, 32, -1);
13758218822Sdim      if (align_good == FAIL)
13759218822Sdim        return;
13760218822Sdim      switch (NEON_REGLIST_LENGTH (inst.operands[0].imm))
13761218822Sdim        {
13762218822Sdim        case 1: break;
13763218822Sdim        case 2: inst.instruction |= 1 << 5; break;
13764218822Sdim        default: first_error (_("bad list length")); return;
13765218822Sdim        }
13766218822Sdim      inst.instruction |= neon_logbits (et.size) << 6;
13767218822Sdim      break;
1376889857Sobrien
13769218822Sdim    case 1:  /* VLD2.  */
13770218822Sdim      align_good = neon_alignment_bit (et.size, inst.operands[1].imm >> 8,
13771218822Sdim                                       &do_align, 8, 16, 16, 32, 32, 64, -1);
13772218822Sdim      if (align_good == FAIL)
13773218822Sdim        return;
13774218822Sdim      constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 2,
13775218822Sdim                  _("bad list length"));
13776218822Sdim      if (NEON_REG_STRIDE (inst.operands[0].imm) == 2)
13777218822Sdim        inst.instruction |= 1 << 5;
13778218822Sdim      inst.instruction |= neon_logbits (et.size) << 6;
13779218822Sdim      break;
13780218822Sdim
13781218822Sdim    case 2:  /* VLD3.  */
13782218822Sdim      constraint (inst.operands[1].immisalign,
13783218822Sdim                  _("can't use alignment with this instruction"));
13784218822Sdim      constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 3,
13785218822Sdim                  _("bad list length"));
13786218822Sdim      if (NEON_REG_STRIDE (inst.operands[0].imm) == 2)
13787218822Sdim        inst.instruction |= 1 << 5;
13788218822Sdim      inst.instruction |= neon_logbits (et.size) << 6;
13789218822Sdim      break;
13790218822Sdim
13791218822Sdim    case 3:  /* VLD4.  */
13792218822Sdim      {
13793218822Sdim        int align = inst.operands[1].imm >> 8;
13794218822Sdim        align_good = neon_alignment_bit (et.size, align, &do_align, 8, 32,
13795218822Sdim                                         16, 64, 32, 64, 32, 128, -1);
13796218822Sdim        if (align_good == FAIL)
13797218822Sdim          return;
13798218822Sdim        constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 4,
13799218822Sdim                    _("bad list length"));
13800218822Sdim        if (NEON_REG_STRIDE (inst.operands[0].imm) == 2)
13801218822Sdim          inst.instruction |= 1 << 5;
13802218822Sdim        if (et.size == 32 && align == 128)
13803218822Sdim          inst.instruction |= 0x3 << 6;
13804218822Sdim        else
13805218822Sdim          inst.instruction |= neon_logbits (et.size) << 6;
13806218822Sdim      }
13807218822Sdim      break;
13808218822Sdim
13809218822Sdim    default: ;
1381089857Sobrien    }
1381189857Sobrien
13812218822Sdim  inst.instruction |= do_align << 4;
13813218822Sdim}
1381489857Sobrien
13815218822Sdim/* Disambiguate VLD<n> and VST<n> instructions, and fill in common bits (those
13816218822Sdim   apart from bits [11:4].  */
1381789857Sobrien
13818218822Sdimstatic void
13819218822Sdimdo_neon_ldx_stx (void)
13820218822Sdim{
13821218822Sdim  switch (NEON_LANE (inst.operands[0].imm))
1382289857Sobrien    {
13823218822Sdim    case NEON_INTERLEAVE_LANES:
13824218822Sdim      inst.instruction = NEON_ENC_INTERLV (inst.instruction);
13825218822Sdim      do_neon_ld_st_interleave ();
13826218822Sdim      break;
13827218822Sdim
13828218822Sdim    case NEON_ALL_LANES:
13829218822Sdim      inst.instruction = NEON_ENC_DUP (inst.instruction);
13830218822Sdim      do_neon_ld_dup ();
13831218822Sdim      break;
13832218822Sdim
13833218822Sdim    default:
13834218822Sdim      inst.instruction = NEON_ENC_LANE (inst.instruction);
13835218822Sdim      do_neon_ld_st_lane ();
1383689857Sobrien    }
1383789857Sobrien
13838218822Sdim  /* L bit comes from bit mask.  */
13839218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
13840218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
13841218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
13842218822Sdim
13843218822Sdim  if (inst.operands[1].postind)
1384489857Sobrien    {
13845218822Sdim      int postreg = inst.operands[1].imm & 0xf;
13846218822Sdim      constraint (!inst.operands[1].immisreg,
13847218822Sdim                  _("post-index must be a register"));
13848218822Sdim      constraint (postreg == 0xd || postreg == 0xf,
13849218822Sdim                  _("bad register for post-index"));
13850218822Sdim      inst.instruction |= postreg;
1385189857Sobrien    }
13852218822Sdim  else if (inst.operands[1].writeback)
13853218822Sdim    {
13854218822Sdim      inst.instruction |= 0xd;
13855218822Sdim    }
13856218822Sdim  else
13857218822Sdim    inst.instruction |= 0xf;
13858218822Sdim
13859218822Sdim  if (thumb_mode)
13860218822Sdim    inst.instruction |= 0xf9000000;
13861218822Sdim  else
13862218822Sdim    inst.instruction |= 0xf4000000;
13863218822Sdim}
1386489857Sobrien
13865218822Sdim
13866218822Sdim/* Overall per-instruction processing.	*/
1386789857Sobrien
13868218822Sdim/* We need to be able to fix up arbitrary expressions in some statements.
13869218822Sdim   This is so that we can handle symbols that are an arbitrary distance from
13870218822Sdim   the pc.  The most common cases are of the form ((+/-sym -/+ . - 8) & mask),
13871218822Sdim   which returns part of an address in a form which will be valid for
13872218822Sdim   a data instruction.	We do this by pushing the expression into a symbol
13873218822Sdim   in the expr_section, and creating a fix for that.  */
13874218822Sdim
13875218822Sdimstatic void
13876218822Sdimfix_new_arm (fragS *	   frag,
13877218822Sdim	     int	   where,
13878218822Sdim	     short int	   size,
13879218822Sdim	     expressionS * exp,
13880218822Sdim	     int	   pc_rel,
13881218822Sdim	     int	   reloc)
13882218822Sdim{
13883218822Sdim  fixS *	   new_fix;
13884218822Sdim
13885218822Sdim  switch (exp->X_op)
1388689857Sobrien    {
13887218822Sdim    case O_constant:
13888218822Sdim    case O_symbol:
13889218822Sdim    case O_add:
13890218822Sdim    case O_subtract:
13891218822Sdim      new_fix = fix_new_exp (frag, where, size, exp, pc_rel, reloc);
13892218822Sdim      break;
1389389857Sobrien
13894218822Sdim    default:
13895218822Sdim      new_fix = fix_new (frag, where, size, make_expr_symbol (exp), 0,
13896218822Sdim			 pc_rel, reloc);
13897218822Sdim      break;
1389889857Sobrien    }
1389989857Sobrien
13900218822Sdim  /* Mark whether the fix is to a THUMB instruction, or an ARM
13901218822Sdim     instruction.  */
13902218822Sdim  new_fix->tc_fix_data = thumb_mode;
1390389857Sobrien}
1390489857Sobrien
13905218822Sdim/* Create a frg for an instruction requiring relaxation.  */
13906218822Sdimstatic void
13907218822Sdimoutput_relax_insn (void)
1390889857Sobrien{
13909218822Sdim  char * to;
13910218822Sdim  symbolS *sym;
1391189857Sobrien  int offset;
1391289857Sobrien
13913218822Sdim  /* The size of the instruction is unknown, so tie the debug info to the
13914218822Sdim     start of the instruction.  */
13915218822Sdim  dwarf2_emit_insn (0);
1391689857Sobrien
13917218822Sdim  switch (inst.reloc.exp.X_op)
13918218822Sdim    {
13919218822Sdim    case O_symbol:
13920218822Sdim      sym = inst.reloc.exp.X_add_symbol;
13921218822Sdim      offset = inst.reloc.exp.X_add_number;
13922218822Sdim      break;
13923218822Sdim    case O_constant:
13924218822Sdim      sym = NULL;
13925218822Sdim      offset = inst.reloc.exp.X_add_number;
13926218822Sdim      break;
13927218822Sdim    default:
13928218822Sdim      sym = make_expr_symbol (&inst.reloc.exp);
13929218822Sdim      offset = 0;
13930218822Sdim      break;
13931218822Sdim  }
13932218822Sdim  to = frag_var (rs_machine_dependent, INSN_SIZE, THUMB_SIZE,
13933218822Sdim		 inst.relax, sym, offset, NULL/*offset, opcode*/);
13934218822Sdim  md_number_to_chars (to, inst.instruction, THUMB_SIZE);
13935218822Sdim}
1393689857Sobrien
13937218822Sdim/* Write a 32-bit thumb instruction to buf.  */
13938218822Sdimstatic void
13939218822Sdimput_thumb32_insn (char * buf, unsigned long insn)
13940218822Sdim{
13941218822Sdim  md_number_to_chars (buf, insn >> 16, THUMB_SIZE);
13942218822Sdim  md_number_to_chars (buf + THUMB_SIZE, insn, THUMB_SIZE);
13943218822Sdim}
1394489857Sobrien
13945218822Sdimstatic void
13946218822Sdimoutput_inst (const char * str)
13947218822Sdim{
13948218822Sdim  char * to = NULL;
1394989857Sobrien
13950218822Sdim  if (inst.error)
1395189857Sobrien    {
13952218822Sdim      as_bad ("%s -- `%s'", inst.error, str);
13953218822Sdim      return;
1395489857Sobrien    }
13955218822Sdim  if (inst.relax) {
13956218822Sdim      output_relax_insn();
13957218822Sdim      return;
13958218822Sdim  }
13959218822Sdim  if (inst.size == 0)
13960218822Sdim    return;
1396189857Sobrien
13962218822Sdim  to = frag_more (inst.size);
1396389857Sobrien
13964218822Sdim  if (thumb_mode && (inst.size > THUMB_SIZE))
1396589857Sobrien    {
13966218822Sdim      assert (inst.size == (2 * THUMB_SIZE));
13967218822Sdim      put_thumb32_insn (to, inst.instruction);
1396889857Sobrien    }
13969218822Sdim  else if (inst.size > INSN_SIZE)
13970218822Sdim    {
13971218822Sdim      assert (inst.size == (2 * INSN_SIZE));
13972218822Sdim      md_number_to_chars (to, inst.instruction, INSN_SIZE);
13973218822Sdim      md_number_to_chars (to + INSN_SIZE, inst.instruction, INSN_SIZE);
13974218822Sdim    }
13975218822Sdim  else
13976218822Sdim    md_number_to_chars (to, inst.instruction, inst.size);
1397789857Sobrien
13978218822Sdim  if (inst.reloc.type != BFD_RELOC_UNUSED)
13979218822Sdim    fix_new_arm (frag_now, to - frag_now->fr_literal,
13980218822Sdim		 inst.size, & inst.reloc.exp, inst.reloc.pc_rel,
13981218822Sdim		 inst.reloc.type);
1398289857Sobrien
13983218822Sdim  dwarf2_emit_insn (inst.size);
1398489857Sobrien}
1398589857Sobrien
13986218822Sdim/* Tag values used in struct asm_opcode's tag field.  */
13987218822Sdimenum opcode_tag
13988218822Sdim{
13989218822Sdim  OT_unconditional,	/* Instruction cannot be conditionalized.
13990218822Sdim			   The ARM condition field is still 0xE.  */
13991218822Sdim  OT_unconditionalF,	/* Instruction cannot be conditionalized
13992218822Sdim			   and carries 0xF in its ARM condition field.  */
13993218822Sdim  OT_csuffix,		/* Instruction takes a conditional suffix.  */
13994218822Sdim  OT_csuffixF,		/* Some forms of the instruction take a conditional
13995218822Sdim                           suffix, others place 0xF where the condition field
13996218822Sdim                           would be.  */
13997218822Sdim  OT_cinfix3,		/* Instruction takes a conditional infix,
13998218822Sdim			   beginning at character index 3.  (In
13999218822Sdim			   unified mode, it becomes a suffix.)  */
14000218822Sdim  OT_cinfix3_deprecated, /* The same as OT_cinfix3.  This is used for
14001218822Sdim			    tsts, cmps, cmns, and teqs. */
14002218822Sdim  OT_cinfix3_legacy,	/* Legacy instruction takes a conditional infix at
14003218822Sdim			   character index 3, even in unified mode.  Used for
14004218822Sdim			   legacy instructions where suffix and infix forms
14005218822Sdim			   may be ambiguous.  */
14006218822Sdim  OT_csuf_or_in3,	/* Instruction takes either a conditional
14007218822Sdim			   suffix or an infix at character index 3.  */
14008218822Sdim  OT_odd_infix_unc,	/* This is the unconditional variant of an
14009218822Sdim			   instruction that takes a conditional infix
14010218822Sdim			   at an unusual position.  In unified mode,
14011218822Sdim			   this variant will accept a suffix.  */
14012218822Sdim  OT_odd_infix_0	/* Values greater than or equal to OT_odd_infix_0
14013218822Sdim			   are the conditional variants of instructions that
14014218822Sdim			   take conditional infixes in unusual positions.
14015218822Sdim			   The infix appears at character index
14016218822Sdim			   (tag - OT_odd_infix_0).  These are not accepted
14017218822Sdim			   in unified mode.  */
14018218822Sdim};
1401989857Sobrien
14020218822Sdim/* Subroutine of md_assemble, responsible for looking up the primary
14021218822Sdim   opcode from the mnemonic the user wrote.  STR points to the
14022218822Sdim   beginning of the mnemonic.
14023218822Sdim
14024218822Sdim   This is not simply a hash table lookup, because of conditional
14025218822Sdim   variants.  Most instructions have conditional variants, which are
14026218822Sdim   expressed with a _conditional affix_ to the mnemonic.  If we were
14027218822Sdim   to encode each conditional variant as a literal string in the opcode
14028218822Sdim   table, it would have approximately 20,000 entries.
14029218822Sdim
14030218822Sdim   Most mnemonics take this affix as a suffix, and in unified syntax,
14031218822Sdim   'most' is upgraded to 'all'.  However, in the divided syntax, some
14032218822Sdim   instructions take the affix as an infix, notably the s-variants of
14033218822Sdim   the arithmetic instructions.  Of those instructions, all but six
14034218822Sdim   have the infix appear after the third character of the mnemonic.
14035218822Sdim
14036218822Sdim   Accordingly, the algorithm for looking up primary opcodes given
14037218822Sdim   an identifier is:
14038218822Sdim
14039218822Sdim   1. Look up the identifier in the opcode table.
14040218822Sdim      If we find a match, go to step U.
14041218822Sdim
14042218822Sdim   2. Look up the last two characters of the identifier in the
14043218822Sdim      conditions table.  If we find a match, look up the first N-2
14044218822Sdim      characters of the identifier in the opcode table.  If we
14045218822Sdim      find a match, go to step CE.
14046218822Sdim
14047218822Sdim   3. Look up the fourth and fifth characters of the identifier in
14048218822Sdim      the conditions table.  If we find a match, extract those
14049218822Sdim      characters from the identifier, and look up the remaining
14050218822Sdim      characters in the opcode table.  If we find a match, go
14051218822Sdim      to step CM.
14052218822Sdim
14053218822Sdim   4. Fail.
14054218822Sdim
14055218822Sdim   U. Examine the tag field of the opcode structure, in case this is
14056218822Sdim      one of the six instructions with its conditional infix in an
14057218822Sdim      unusual place.  If it is, the tag tells us where to find the
14058218822Sdim      infix; look it up in the conditions table and set inst.cond
14059218822Sdim      accordingly.  Otherwise, this is an unconditional instruction.
14060218822Sdim      Again set inst.cond accordingly.  Return the opcode structure.
14061218822Sdim
14062218822Sdim  CE. Examine the tag field to make sure this is an instruction that
14063218822Sdim      should receive a conditional suffix.  If it is not, fail.
14064218822Sdim      Otherwise, set inst.cond from the suffix we already looked up,
14065218822Sdim      and return the opcode structure.
14066218822Sdim
14067218822Sdim  CM. Examine the tag field to make sure this is an instruction that
14068218822Sdim      should receive a conditional infix after the third character.
14069218822Sdim      If it is not, fail.  Otherwise, undo the edits to the current
14070218822Sdim      line of input and proceed as for case CE.  */
14071218822Sdim
14072218822Sdimstatic const struct asm_opcode *
14073218822Sdimopcode_lookup (char **str)
1407489857Sobrien{
14075218822Sdim  char *end, *base;
14076218822Sdim  char *affix;
14077218822Sdim  const struct asm_opcode *opcode;
14078218822Sdim  const struct asm_cond *cond;
14079218822Sdim  char save[2];
14080218822Sdim  bfd_boolean neon_supported;
14081218822Sdim
14082218822Sdim  neon_supported = ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1);
1408389857Sobrien
14084218822Sdim  /* Scan up to the end of the mnemonic, which must end in white space,
14085218822Sdim     '.' (in unified mode, or for Neon instructions), or end of string.  */
14086218822Sdim  for (base = end = *str; *end != '\0'; end++)
14087218822Sdim    if (*end == ' ' || ((unified_syntax || neon_supported) && *end == '.'))
14088218822Sdim      break;
1408989857Sobrien
14090218822Sdim  if (end == base)
14091218822Sdim    return 0;
1409289857Sobrien
14093218822Sdim  /* Handle a possible width suffix and/or Neon type suffix.  */
14094218822Sdim  if (end[0] == '.')
1409589857Sobrien    {
14096218822Sdim      int offset = 2;
14097218822Sdim
14098218822Sdim      /* The .w and .n suffixes are only valid if the unified syntax is in
14099218822Sdim         use.  */
14100218822Sdim      if (unified_syntax && end[1] == 'w')
14101218822Sdim	inst.size_req = 4;
14102218822Sdim      else if (unified_syntax && end[1] == 'n')
14103218822Sdim	inst.size_req = 2;
14104218822Sdim      else
14105218822Sdim        offset = 0;
1410689857Sobrien
14107218822Sdim      inst.vectype.elems = 0;
1410889857Sobrien
14109218822Sdim      *str = end + offset;
1411089857Sobrien
14111218822Sdim      if (end[offset] == '.')
1411289857Sobrien	{
14113218822Sdim	  /* See if we have a Neon type suffix (possible in either unified or
14114218822Sdim             non-unified ARM syntax mode).  */
14115218822Sdim          if (parse_neon_type (&inst.vectype, str) == FAIL)
14116218822Sdim	    return 0;
14117218822Sdim        }
14118218822Sdim      else if (end[offset] != '\0' && end[offset] != ' ')
14119218822Sdim        return 0;
14120218822Sdim    }
14121218822Sdim  else
14122218822Sdim    *str = end;
1412389857Sobrien
14124218822Sdim  /* Look for unaffixed or special-case affixed mnemonic.  */
14125218822Sdim  opcode = hash_find_n (arm_ops_hsh, base, end - base);
14126218822Sdim  if (opcode)
14127218822Sdim    {
14128218822Sdim      /* step U */
14129218822Sdim      if (opcode->tag < OT_odd_infix_0)
1413089857Sobrien	{
14131218822Sdim	  inst.cond = COND_ALWAYS;
14132218822Sdim	  return opcode;
1413389857Sobrien	}
14134218822Sdim
14135218822Sdim      if (unified_syntax)
14136218822Sdim	as_warn (_("conditional infixes are deprecated in unified syntax"));
14137218822Sdim      affix = base + (opcode->tag - OT_odd_infix_0);
14138218822Sdim      cond = hash_find_n (arm_cond_hsh, affix, 2);
14139218822Sdim      assert (cond);
14140218822Sdim
14141218822Sdim      inst.cond = cond->value;
14142218822Sdim      return opcode;
1414389857Sobrien    }
14144218822Sdim
14145218822Sdim  /* Cannot have a conditional suffix on a mnemonic of less than two
14146218822Sdim     characters.  */
14147218822Sdim  if (end - base < 3)
14148218822Sdim    return 0;
14149218822Sdim
14150218822Sdim  /* Look for suffixed mnemonic.  */
14151218822Sdim  affix = end - 2;
14152218822Sdim  cond = hash_find_n (arm_cond_hsh, affix, 2);
14153218822Sdim  opcode = hash_find_n (arm_ops_hsh, base, affix - base);
14154218822Sdim  if (opcode && cond)
1415589857Sobrien    {
14156218822Sdim      /* step CE */
14157218822Sdim      switch (opcode->tag)
1415889857Sobrien	{
14159218822Sdim	case OT_cinfix3_legacy:
14160218822Sdim	  /* Ignore conditional suffixes matched on infix only mnemonics.  */
14161218822Sdim	  break;
1416289857Sobrien
14163218822Sdim	case OT_cinfix3:
14164218822Sdim	case OT_cinfix3_deprecated:
14165218822Sdim	case OT_odd_infix_unc:
14166218822Sdim	  if (!unified_syntax)
14167218822Sdim	    return 0;
14168218822Sdim	  /* else fall through */
1416989857Sobrien
14170218822Sdim	case OT_csuffix:
14171218822Sdim        case OT_csuffixF:
14172218822Sdim	case OT_csuf_or_in3:
14173218822Sdim	  inst.cond = cond->value;
14174218822Sdim	  return opcode;
14175218822Sdim
14176218822Sdim	case OT_unconditional:
14177218822Sdim	case OT_unconditionalF:
14178218822Sdim	  if (thumb_mode)
14179218822Sdim	    {
14180218822Sdim	      inst.cond = cond->value;
14181218822Sdim	    }
14182218822Sdim	  else
14183218822Sdim	    {
14184218822Sdim	      /* delayed diagnostic */
14185218822Sdim	      inst.error = BAD_COND;
14186218822Sdim	      inst.cond = COND_ALWAYS;
14187218822Sdim	    }
14188218822Sdim	  return opcode;
14189218822Sdim
14190218822Sdim	default:
14191218822Sdim	  return 0;
14192218822Sdim	}
1419389857Sobrien    }
1419489857Sobrien
14195218822Sdim  /* Cannot have a usual-position infix on a mnemonic of less than
14196218822Sdim     six characters (five would be a suffix).  */
14197218822Sdim  if (end - base < 6)
14198218822Sdim    return 0;
1419989857Sobrien
14200218822Sdim  /* Look for infixed mnemonic in the usual position.  */
14201218822Sdim  affix = base + 3;
14202218822Sdim  cond = hash_find_n (arm_cond_hsh, affix, 2);
14203218822Sdim  if (!cond)
14204218822Sdim    return 0;
1420589857Sobrien
14206218822Sdim  memcpy (save, affix, 2);
14207218822Sdim  memmove (affix, affix + 2, (end - affix) - 2);
14208218822Sdim  opcode = hash_find_n (arm_ops_hsh, base, (end - base) - 2);
14209218822Sdim  memmove (affix + 2, affix, (end - affix) - 2);
14210218822Sdim  memcpy (affix, save, 2);
14211218822Sdim
14212218822Sdim  if (opcode
14213218822Sdim      && (opcode->tag == OT_cinfix3
14214218822Sdim	  || opcode->tag == OT_cinfix3_deprecated
14215218822Sdim	  || opcode->tag == OT_csuf_or_in3
14216218822Sdim	  || opcode->tag == OT_cinfix3_legacy))
14217218822Sdim    {
14218218822Sdim      /* step CM */
14219218822Sdim      if (unified_syntax
14220218822Sdim	  && (opcode->tag == OT_cinfix3
14221218822Sdim	      || opcode->tag == OT_cinfix3_deprecated))
14222218822Sdim	as_warn (_("conditional infixes are deprecated in unified syntax"));
14223218822Sdim
14224218822Sdim      inst.cond = cond->value;
14225218822Sdim      return opcode;
14226218822Sdim    }
14227218822Sdim
14228218822Sdim  return 0;
1422989857Sobrien}
1423089857Sobrien
14231218822Sdimvoid
14232218822Sdimmd_assemble (char *str)
1423360484Sobrien{
14234218822Sdim  char *p = str;
14235218822Sdim  const struct asm_opcode * opcode;
1423660484Sobrien
14237218822Sdim  /* Align the previous label if needed.  */
14238218822Sdim  if (last_label_seen != NULL)
14239218822Sdim    {
14240218822Sdim      symbol_set_frag (last_label_seen, frag_now);
14241218822Sdim      S_SET_VALUE (last_label_seen, (valueT) frag_now_fix ());
14242218822Sdim      S_SET_SEGMENT (last_label_seen, now_seg);
14243218822Sdim    }
1424477298Sobrien
14245218822Sdim  memset (&inst, '\0', sizeof (inst));
14246218822Sdim  inst.reloc.type = BFD_RELOC_UNUSED;
1424760484Sobrien
14248218822Sdim  opcode = opcode_lookup (&p);
14249218822Sdim  if (!opcode)
14250218822Sdim    {
14251218822Sdim      /* It wasn't an instruction, but it might be a register alias of
14252218822Sdim	 the form alias .req reg, or a Neon .dn/.qn directive.  */
14253218822Sdim      if (!create_register_alias (str, p)
14254218822Sdim          && !create_neon_reg_alias (str, p))
14255218822Sdim	as_bad (_("bad instruction `%s'"), str);
1425660484Sobrien
1425777298Sobrien      return;
1425860484Sobrien    }
1425960484Sobrien
14260218822Sdim  if (opcode->tag == OT_cinfix3_deprecated)
14261218822Sdim    as_warn (_("s suffix on comparison instruction is deprecated"));
14262218822Sdim
14263218822Sdim  /* The value which unconditional instructions should have in place of the
14264218822Sdim     condition field.  */
14265218822Sdim  inst.uncond_value = (opcode->tag == OT_csuffixF) ? 0xf : -1;
14266218822Sdim
14267218822Sdim  if (thumb_mode)
1426860484Sobrien    {
14269218822Sdim      arm_feature_set variant;
14270218822Sdim
14271218822Sdim      variant = cpu_variant;
14272218822Sdim      /* Only allow coprocessor instructions on Thumb-2 capable devices.  */
14273218822Sdim      if (!ARM_CPU_HAS_FEATURE (variant, arm_arch_t2))
14274218822Sdim	ARM_CLEAR_FEATURE (variant, variant, fpu_any_hard);
14275218822Sdim      /* Check that this instruction is supported for this CPU.  */
14276218822Sdim      if (!opcode->tvariant
14277218822Sdim	  || (thumb_mode == 1
14278218822Sdim	      && !ARM_CPU_HAS_FEATURE (variant, *opcode->tvariant)))
1427960484Sobrien	{
14280218822Sdim	  as_bad (_("selected processor does not support `%s'"), str);
1428160484Sobrien	  return;
1428260484Sobrien	}
14283218822Sdim      if (inst.cond != COND_ALWAYS && !unified_syntax
14284218822Sdim	  && opcode->tencode != do_t_branch)
14285218822Sdim	{
14286218822Sdim	  as_bad (_("Thumb does not support conditional execution"));
14287218822Sdim	  return;
14288218822Sdim	}
1428960484Sobrien
14290218822Sdim      if (!ARM_CPU_HAS_FEATURE (variant, arm_ext_v6t2) && !inst.size_req)
14291218822Sdim	{
14292218822Sdim	  /* Implicit require narrow instructions on Thumb-1.  This avoids
14293218822Sdim	     relaxation accidentally introducing Thumb-2 instructions.  */
14294218822Sdim	  if (opcode->tencode != do_t_blx && opcode->tencode != do_t_branch23)
14295218822Sdim	    inst.size_req = 2;
14296218822Sdim	}
1429760484Sobrien
14298218822Sdim      /* Check conditional suffixes.  */
14299218822Sdim      if (current_it_mask)
1430060484Sobrien	{
14301218822Sdim	  int cond;
14302218822Sdim	  cond = current_cc ^ ((current_it_mask >> 4) & 1) ^ 1;
14303218822Sdim	  current_it_mask <<= 1;
14304218822Sdim	  current_it_mask &= 0x1f;
14305218822Sdim	  /* The BKPT instruction is unconditional even in an IT block.  */
14306218822Sdim	  if (!inst.error
14307218822Sdim	      && cond != inst.cond && opcode->tencode != do_t_bkpt)
14308218822Sdim	    {
14309218822Sdim	      as_bad (_("incorrect condition in IT block"));
14310218822Sdim	      return;
14311218822Sdim	    }
14312218822Sdim	}
14313218822Sdim      else if (inst.cond != COND_ALWAYS && opcode->tencode != do_t_branch)
14314218822Sdim	{
14315218822Sdim	  as_bad (_("thumb conditional instrunction not in IT block"));
1431660484Sobrien	  return;
1431760484Sobrien	}
1431860484Sobrien
14319218822Sdim      mapping_state (MAP_THUMB);
14320218822Sdim      inst.instruction = opcode->tvalue;
1432160484Sobrien
14322218822Sdim      if (!parse_operands (p, opcode->operands))
14323218822Sdim	opcode->tencode ();
1432460484Sobrien
14325218822Sdim      /* Clear current_it_mask at the end of an IT block.  */
14326218822Sdim      if (current_it_mask == 0x10)
14327218822Sdim	current_it_mask = 0;
1432860484Sobrien
14329218822Sdim      if (!(inst.error || inst.relax))
14330218822Sdim	{
14331218822Sdim	  assert (inst.instruction < 0xe800 || inst.instruction > 0xffff);
14332218822Sdim	  inst.size = (inst.instruction > 0xffff ? 4 : 2);
14333218822Sdim	  if (inst.size_req && inst.size_req != inst.size)
14334218822Sdim	    {
14335218822Sdim	      as_bad (_("cannot honor width suffix -- `%s'"), str);
14336218822Sdim	      return;
14337218822Sdim	    }
14338218822Sdim	}
14339218822Sdim
14340218822Sdim      /* Something has gone badly wrong if we try to relax a fixed size
14341218822Sdim         instruction.  */
14342218822Sdim      assert (inst.size_req == 0 || !inst.relax);
14343218822Sdim
14344218822Sdim      ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
14345218822Sdim			      *opcode->tvariant);
14346218822Sdim      /* Many Thumb-2 instructions also have Thumb-1 variants, so explicitly
14347218822Sdim	 set those bits when Thumb-2 32-bit instructions are seen.  ie.
14348218822Sdim	 anything other than bl/blx.
14349218822Sdim	 This is overly pessimistic for relaxable instructions.  */
14350218822Sdim      if ((inst.size == 4 && (inst.instruction & 0xf800e800) != 0xf000e800)
14351218822Sdim	  || inst.relax)
14352218822Sdim	ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
14353218822Sdim				arm_ext_v6t2);
14354218822Sdim    }
14355218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1))
14356218822Sdim    {
14357218822Sdim      /* Check that this instruction is supported for this CPU.  */
14358218822Sdim      if (!opcode->avariant ||
14359218822Sdim	  !ARM_CPU_HAS_FEATURE (cpu_variant, *opcode->avariant))
14360218822Sdim	{
14361218822Sdim	  as_bad (_("selected processor does not support `%s'"), str);
14362218822Sdim	  return;
14363218822Sdim	}
14364218822Sdim      if (inst.size_req)
14365218822Sdim	{
14366218822Sdim	  as_bad (_("width suffixes are invalid in ARM mode -- `%s'"), str);
14367218822Sdim	  return;
14368218822Sdim	}
14369218822Sdim
14370218822Sdim      mapping_state (MAP_ARM);
14371218822Sdim      inst.instruction = opcode->avalue;
14372218822Sdim      if (opcode->tag == OT_unconditionalF)
14373218822Sdim	inst.instruction |= 0xF << 28;
14374218822Sdim      else
14375218822Sdim	inst.instruction |= inst.cond << 28;
14376218822Sdim      inst.size = INSN_SIZE;
14377218822Sdim      if (!parse_operands (p, opcode->operands))
14378218822Sdim	opcode->aencode ();
14379218822Sdim      /* Arm mode bx is marked as both v4T and v5 because it's still required
14380218822Sdim         on a hypothetical non-thumb v5 core.  */
14381218822Sdim      if (ARM_CPU_HAS_FEATURE (*opcode->avariant, arm_ext_v4t)
14382218822Sdim	  || ARM_CPU_HAS_FEATURE (*opcode->avariant, arm_ext_v5))
14383218822Sdim	ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used, arm_ext_v4t);
14384218822Sdim      else
14385218822Sdim	ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used,
14386218822Sdim				*opcode->avariant);
14387218822Sdim    }
14388218822Sdim  else
14389218822Sdim    {
14390218822Sdim      as_bad (_("attempt to use an ARM instruction on a Thumb-only processor "
14391218822Sdim		"-- `%s'"), str);
14392218822Sdim      return;
14393218822Sdim    }
14394218822Sdim  output_inst (str);
1439560484Sobrien}
1439660484Sobrien
14397218822Sdim/* Various frobbings of labels and their addresses.  */
14398218822Sdim
14399218822Sdimvoid
14400218822Sdimarm_start_line_hook (void)
1440160484Sobrien{
14402218822Sdim  last_label_seen = NULL;
1440360484Sobrien}
1440460484Sobrien
14405218822Sdimvoid
14406218822Sdimarm_frob_label (symbolS * sym)
1440760484Sobrien{
14408218822Sdim  last_label_seen = sym;
1440960484Sobrien
14410218822Sdim  ARM_SET_THUMB (sym, thumb_mode);
1441160484Sobrien
14412218822Sdim#if defined OBJ_COFF || defined OBJ_ELF
14413218822Sdim  ARM_SET_INTERWORK (sym, support_interwork);
14414218822Sdim#endif
1441560484Sobrien
14416218822Sdim  /* Note - do not allow local symbols (.Lxxx) to be labeled
14417218822Sdim     as Thumb functions.  This is because these labels, whilst
14418218822Sdim     they exist inside Thumb code, are not the entry points for
14419218822Sdim     possible ARM->Thumb calls.	 Also, these labels can be used
14420218822Sdim     as part of a computed goto or switch statement.  eg gcc
14421218822Sdim     can generate code that looks like this:
1442260484Sobrien
14423218822Sdim		ldr  r2, [pc, .Laaa]
14424218822Sdim		lsl  r3, r3, #2
14425218822Sdim		ldr  r2, [r3, r2]
14426218822Sdim		mov  pc, r2
1442760484Sobrien
14428218822Sdim       .Lbbb:  .word .Lxxx
14429218822Sdim       .Lccc:  .word .Lyyy
14430218822Sdim       ..etc...
14431218822Sdim       .Laaa:	.word Lbbb
1443277298Sobrien
14433218822Sdim     The first instruction loads the address of the jump table.
14434218822Sdim     The second instruction converts a table index into a byte offset.
14435218822Sdim     The third instruction gets the jump address out of the table.
14436218822Sdim     The fourth instruction performs the jump.
1443760484Sobrien
14438218822Sdim     If the address stored at .Laaa is that of a symbol which has the
14439218822Sdim     Thumb_Func bit set, then the linker will arrange for this address
14440218822Sdim     to have the bottom bit set, which in turn would mean that the
14441218822Sdim     address computation performed by the third instruction would end
14442218822Sdim     up with the bottom bit set.  Since the ARM is capable of unaligned
14443218822Sdim     word loads, the instruction would then load the incorrect address
14444218822Sdim     out of the jump table, and chaos would ensue.  */
14445218822Sdim  if (label_is_thumb_function_name
14446218822Sdim      && (S_GET_NAME (sym)[0] != '.' || S_GET_NAME (sym)[1] != 'L')
14447218822Sdim      && (bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0)
14448218822Sdim    {
14449218822Sdim      /* When the address of a Thumb function is taken the bottom
14450218822Sdim	 bit of that address should be set.  This will allow
14451218822Sdim	 interworking between Arm and Thumb functions to work
14452218822Sdim	 correctly.  */
1445377298Sobrien
14454218822Sdim      THUMB_SET_FUNC (sym, 1);
14455218822Sdim
14456218822Sdim      label_is_thumb_function_name = FALSE;
14457218822Sdim    }
14458218822Sdim
14459218822Sdim  dwarf2_emit_label (sym);
14460218822Sdim}
14461218822Sdim
14462218822Sdimint
14463218822Sdimarm_data_in_code (void)
14464218822Sdim{
14465218822Sdim  if (thumb_mode && ! strncmp (input_line_pointer + 1, "data:", 5))
1446660484Sobrien    {
14467218822Sdim      *input_line_pointer = '/';
14468218822Sdim      input_line_pointer += 5;
14469218822Sdim      *input_line_pointer = 0;
14470218822Sdim      return 1;
1447160484Sobrien    }
1447260484Sobrien
14473218822Sdim  return 0;
1447460484Sobrien}
1447560484Sobrien
14476218822Sdimchar *
14477218822Sdimarm_canonicalize_symbol_name (char * name)
1447860484Sobrien{
14479218822Sdim  int len;
1448077298Sobrien
14481218822Sdim  if (thumb_mode && (len = strlen (name)) > 5
14482218822Sdim      && streq (name + len - 5, "/data"))
14483218822Sdim    *(name + len - 5) = 0;
1448460484Sobrien
14485218822Sdim  return name;
1448660484Sobrien}
14487218822Sdim
14488218822Sdim/* Table of all register names defined by default.  The user can
14489218822Sdim   define additional names with .req.  Note that all register names
14490218822Sdim   should appear in both upper and lowercase variants.	Some registers
14491218822Sdim   also have mixed-case names.	*/
1449260484Sobrien
14493218822Sdim#define REGDEF(s,n,t) { #s, n, REG_TYPE_##t, TRUE, 0 }
14494218822Sdim#define REGNUM(p,n,t) REGDEF(p##n, n, t)
14495218822Sdim#define REGNUM2(p,n,t) REGDEF(p##n, 2 * n, t)
14496218822Sdim#define REGSET(p,t) \
14497218822Sdim  REGNUM(p, 0,t), REGNUM(p, 1,t), REGNUM(p, 2,t), REGNUM(p, 3,t), \
14498218822Sdim  REGNUM(p, 4,t), REGNUM(p, 5,t), REGNUM(p, 6,t), REGNUM(p, 7,t), \
14499218822Sdim  REGNUM(p, 8,t), REGNUM(p, 9,t), REGNUM(p,10,t), REGNUM(p,11,t), \
14500218822Sdim  REGNUM(p,12,t), REGNUM(p,13,t), REGNUM(p,14,t), REGNUM(p,15,t)
14501218822Sdim#define REGSETH(p,t) \
14502218822Sdim  REGNUM(p,16,t), REGNUM(p,17,t), REGNUM(p,18,t), REGNUM(p,19,t), \
14503218822Sdim  REGNUM(p,20,t), REGNUM(p,21,t), REGNUM(p,22,t), REGNUM(p,23,t), \
14504218822Sdim  REGNUM(p,24,t), REGNUM(p,25,t), REGNUM(p,26,t), REGNUM(p,27,t), \
14505218822Sdim  REGNUM(p,28,t), REGNUM(p,29,t), REGNUM(p,30,t), REGNUM(p,31,t)
14506218822Sdim#define REGSET2(p,t) \
14507218822Sdim  REGNUM2(p, 0,t), REGNUM2(p, 1,t), REGNUM2(p, 2,t), REGNUM2(p, 3,t), \
14508218822Sdim  REGNUM2(p, 4,t), REGNUM2(p, 5,t), REGNUM2(p, 6,t), REGNUM2(p, 7,t), \
14509218822Sdim  REGNUM2(p, 8,t), REGNUM2(p, 9,t), REGNUM2(p,10,t), REGNUM2(p,11,t), \
14510218822Sdim  REGNUM2(p,12,t), REGNUM2(p,13,t), REGNUM2(p,14,t), REGNUM2(p,15,t)
14511218822Sdim
14512218822Sdimstatic const struct reg_entry reg_names[] =
1451360484Sobrien{
14514218822Sdim  /* ARM integer registers.  */
14515218822Sdim  REGSET(r, RN), REGSET(R, RN),
1451660484Sobrien
14517218822Sdim  /* ATPCS synonyms.  */
14518218822Sdim  REGDEF(a1,0,RN), REGDEF(a2,1,RN), REGDEF(a3, 2,RN), REGDEF(a4, 3,RN),
14519218822Sdim  REGDEF(v1,4,RN), REGDEF(v2,5,RN), REGDEF(v3, 6,RN), REGDEF(v4, 7,RN),
14520218822Sdim  REGDEF(v5,8,RN), REGDEF(v6,9,RN), REGDEF(v7,10,RN), REGDEF(v8,11,RN),
1452160484Sobrien
14522218822Sdim  REGDEF(A1,0,RN), REGDEF(A2,1,RN), REGDEF(A3, 2,RN), REGDEF(A4, 3,RN),
14523218822Sdim  REGDEF(V1,4,RN), REGDEF(V2,5,RN), REGDEF(V3, 6,RN), REGDEF(V4, 7,RN),
14524218822Sdim  REGDEF(V5,8,RN), REGDEF(V6,9,RN), REGDEF(V7,10,RN), REGDEF(V8,11,RN),
1452560484Sobrien
14526218822Sdim  /* Well-known aliases.  */
14527218822Sdim  REGDEF(wr, 7,RN), REGDEF(sb, 9,RN), REGDEF(sl,10,RN), REGDEF(fp,11,RN),
14528218822Sdim  REGDEF(ip,12,RN), REGDEF(sp,13,RN), REGDEF(lr,14,RN), REGDEF(pc,15,RN),
1452960484Sobrien
14530218822Sdim  REGDEF(WR, 7,RN), REGDEF(SB, 9,RN), REGDEF(SL,10,RN), REGDEF(FP,11,RN),
14531218822Sdim  REGDEF(IP,12,RN), REGDEF(SP,13,RN), REGDEF(LR,14,RN), REGDEF(PC,15,RN),
1453260484Sobrien
14533218822Sdim  /* Coprocessor numbers.  */
14534218822Sdim  REGSET(p, CP), REGSET(P, CP),
1453560484Sobrien
14536218822Sdim  /* Coprocessor register numbers.  The "cr" variants are for backward
14537218822Sdim     compatibility.  */
14538218822Sdim  REGSET(c,  CN), REGSET(C, CN),
14539218822Sdim  REGSET(cr, CN), REGSET(CR, CN),
1454060484Sobrien
14541218822Sdim  /* FPA registers.  */
14542218822Sdim  REGNUM(f,0,FN), REGNUM(f,1,FN), REGNUM(f,2,FN), REGNUM(f,3,FN),
14543218822Sdim  REGNUM(f,4,FN), REGNUM(f,5,FN), REGNUM(f,6,FN), REGNUM(f,7, FN),
1454460484Sobrien
14545218822Sdim  REGNUM(F,0,FN), REGNUM(F,1,FN), REGNUM(F,2,FN), REGNUM(F,3,FN),
14546218822Sdim  REGNUM(F,4,FN), REGNUM(F,5,FN), REGNUM(F,6,FN), REGNUM(F,7, FN),
1454760484Sobrien
14548218822Sdim  /* VFP SP registers.	*/
14549218822Sdim  REGSET(s,VFS),  REGSET(S,VFS),
14550218822Sdim  REGSETH(s,VFS), REGSETH(S,VFS),
1455160484Sobrien
14552218822Sdim  /* VFP DP Registers.	*/
14553218822Sdim  REGSET(d,VFD),  REGSET(D,VFD),
14554218822Sdim  /* Extra Neon DP registers.  */
14555218822Sdim  REGSETH(d,VFD), REGSETH(D,VFD),
1455660484Sobrien
14557218822Sdim  /* Neon QP registers.  */
14558218822Sdim  REGSET2(q,NQ),  REGSET2(Q,NQ),
1455960484Sobrien
14560218822Sdim  /* VFP control registers.  */
14561218822Sdim  REGDEF(fpsid,0,VFC), REGDEF(fpscr,1,VFC), REGDEF(fpexc,8,VFC),
14562218822Sdim  REGDEF(FPSID,0,VFC), REGDEF(FPSCR,1,VFC), REGDEF(FPEXC,8,VFC),
14563218822Sdim  REGDEF(fpinst,9,VFC), REGDEF(fpinst2,10,VFC),
14564218822Sdim  REGDEF(FPINST,9,VFC), REGDEF(FPINST2,10,VFC),
14565218822Sdim  REGDEF(mvfr0,7,VFC), REGDEF(mvfr1,6,VFC),
14566218822Sdim  REGDEF(MVFR0,7,VFC), REGDEF(MVFR1,6,VFC),
1456760484Sobrien
14568218822Sdim  /* Maverick DSP coprocessor registers.  */
14569218822Sdim  REGSET(mvf,MVF),  REGSET(mvd,MVD),  REGSET(mvfx,MVFX),  REGSET(mvdx,MVDX),
14570218822Sdim  REGSET(MVF,MVF),  REGSET(MVD,MVD),  REGSET(MVFX,MVFX),  REGSET(MVDX,MVDX),
1457160484Sobrien
14572218822Sdim  REGNUM(mvax,0,MVAX), REGNUM(mvax,1,MVAX),
14573218822Sdim  REGNUM(mvax,2,MVAX), REGNUM(mvax,3,MVAX),
14574218822Sdim  REGDEF(dspsc,0,DSPSC),
1457560484Sobrien
14576218822Sdim  REGNUM(MVAX,0,MVAX), REGNUM(MVAX,1,MVAX),
14577218822Sdim  REGNUM(MVAX,2,MVAX), REGNUM(MVAX,3,MVAX),
14578218822Sdim  REGDEF(DSPSC,0,DSPSC),
1457960484Sobrien
14580218822Sdim  /* iWMMXt data registers - p0, c0-15.	 */
14581218822Sdim  REGSET(wr,MMXWR), REGSET(wR,MMXWR), REGSET(WR, MMXWR),
1458260484Sobrien
14583218822Sdim  /* iWMMXt control registers - p1, c0-3.  */
14584218822Sdim  REGDEF(wcid,	0,MMXWC),  REGDEF(wCID,	 0,MMXWC),  REGDEF(WCID,  0,MMXWC),
14585218822Sdim  REGDEF(wcon,	1,MMXWC),  REGDEF(wCon,	 1,MMXWC),  REGDEF(WCON,  1,MMXWC),
14586218822Sdim  REGDEF(wcssf, 2,MMXWC),  REGDEF(wCSSF, 2,MMXWC),  REGDEF(WCSSF, 2,MMXWC),
14587218822Sdim  REGDEF(wcasf, 3,MMXWC),  REGDEF(wCASF, 3,MMXWC),  REGDEF(WCASF, 3,MMXWC),
1458860484Sobrien
14589218822Sdim  /* iWMMXt scalar (constant/offset) registers - p1, c8-11.  */
14590218822Sdim  REGDEF(wcgr0, 8,MMXWCG),  REGDEF(wCGR0, 8,MMXWCG),  REGDEF(WCGR0, 8,MMXWCG),
14591218822Sdim  REGDEF(wcgr1, 9,MMXWCG),  REGDEF(wCGR1, 9,MMXWCG),  REGDEF(WCGR1, 9,MMXWCG),
14592218822Sdim  REGDEF(wcgr2,10,MMXWCG),  REGDEF(wCGR2,10,MMXWCG),  REGDEF(WCGR2,10,MMXWCG),
14593218822Sdim  REGDEF(wcgr3,11,MMXWCG),  REGDEF(wCGR3,11,MMXWCG),  REGDEF(WCGR3,11,MMXWCG),
1459460484Sobrien
14595218822Sdim  /* XScale accumulator registers.  */
14596218822Sdim  REGNUM(acc,0,XSCALE), REGNUM(ACC,0,XSCALE),
14597218822Sdim};
14598218822Sdim#undef REGDEF
14599218822Sdim#undef REGNUM
14600218822Sdim#undef REGSET
1460160484Sobrien
14602218822Sdim/* Table of all PSR suffixes.  Bare "CPSR" and "SPSR" are handled
14603218822Sdim   within psr_required_here.  */
14604218822Sdimstatic const struct asm_psr psrs[] =
14605218822Sdim{
14606218822Sdim  /* Backward compatibility notation.  Note that "all" is no longer
14607218822Sdim     truly all possible PSR bits.  */
14608218822Sdim  {"all",  PSR_c | PSR_f},
14609218822Sdim  {"flg",  PSR_f},
14610218822Sdim  {"ctl",  PSR_c},
1461160484Sobrien
14612218822Sdim  /* Individual flags.	*/
14613218822Sdim  {"f",	   PSR_f},
14614218822Sdim  {"c",	   PSR_c},
14615218822Sdim  {"x",	   PSR_x},
14616218822Sdim  {"s",	   PSR_s},
14617218822Sdim  /* Combinations of flags.  */
14618218822Sdim  {"fs",   PSR_f | PSR_s},
14619218822Sdim  {"fx",   PSR_f | PSR_x},
14620218822Sdim  {"fc",   PSR_f | PSR_c},
14621218822Sdim  {"sf",   PSR_s | PSR_f},
14622218822Sdim  {"sx",   PSR_s | PSR_x},
14623218822Sdim  {"sc",   PSR_s | PSR_c},
14624218822Sdim  {"xf",   PSR_x | PSR_f},
14625218822Sdim  {"xs",   PSR_x | PSR_s},
14626218822Sdim  {"xc",   PSR_x | PSR_c},
14627218822Sdim  {"cf",   PSR_c | PSR_f},
14628218822Sdim  {"cs",   PSR_c | PSR_s},
14629218822Sdim  {"cx",   PSR_c | PSR_x},
14630218822Sdim  {"fsx",  PSR_f | PSR_s | PSR_x},
14631218822Sdim  {"fsc",  PSR_f | PSR_s | PSR_c},
14632218822Sdim  {"fxs",  PSR_f | PSR_x | PSR_s},
14633218822Sdim  {"fxc",  PSR_f | PSR_x | PSR_c},
14634218822Sdim  {"fcs",  PSR_f | PSR_c | PSR_s},
14635218822Sdim  {"fcx",  PSR_f | PSR_c | PSR_x},
14636218822Sdim  {"sfx",  PSR_s | PSR_f | PSR_x},
14637218822Sdim  {"sfc",  PSR_s | PSR_f | PSR_c},
14638218822Sdim  {"sxf",  PSR_s | PSR_x | PSR_f},
14639218822Sdim  {"sxc",  PSR_s | PSR_x | PSR_c},
14640218822Sdim  {"scf",  PSR_s | PSR_c | PSR_f},
14641218822Sdim  {"scx",  PSR_s | PSR_c | PSR_x},
14642218822Sdim  {"xfs",  PSR_x | PSR_f | PSR_s},
14643218822Sdim  {"xfc",  PSR_x | PSR_f | PSR_c},
14644218822Sdim  {"xsf",  PSR_x | PSR_s | PSR_f},
14645218822Sdim  {"xsc",  PSR_x | PSR_s | PSR_c},
14646218822Sdim  {"xcf",  PSR_x | PSR_c | PSR_f},
14647218822Sdim  {"xcs",  PSR_x | PSR_c | PSR_s},
14648218822Sdim  {"cfs",  PSR_c | PSR_f | PSR_s},
14649218822Sdim  {"cfx",  PSR_c | PSR_f | PSR_x},
14650218822Sdim  {"csf",  PSR_c | PSR_s | PSR_f},
14651218822Sdim  {"csx",  PSR_c | PSR_s | PSR_x},
14652218822Sdim  {"cxf",  PSR_c | PSR_x | PSR_f},
14653218822Sdim  {"cxs",  PSR_c | PSR_x | PSR_s},
14654218822Sdim  {"fsxc", PSR_f | PSR_s | PSR_x | PSR_c},
14655218822Sdim  {"fscx", PSR_f | PSR_s | PSR_c | PSR_x},
14656218822Sdim  {"fxsc", PSR_f | PSR_x | PSR_s | PSR_c},
14657218822Sdim  {"fxcs", PSR_f | PSR_x | PSR_c | PSR_s},
14658218822Sdim  {"fcsx", PSR_f | PSR_c | PSR_s | PSR_x},
14659218822Sdim  {"fcxs", PSR_f | PSR_c | PSR_x | PSR_s},
14660218822Sdim  {"sfxc", PSR_s | PSR_f | PSR_x | PSR_c},
14661218822Sdim  {"sfcx", PSR_s | PSR_f | PSR_c | PSR_x},
14662218822Sdim  {"sxfc", PSR_s | PSR_x | PSR_f | PSR_c},
14663218822Sdim  {"sxcf", PSR_s | PSR_x | PSR_c | PSR_f},
14664218822Sdim  {"scfx", PSR_s | PSR_c | PSR_f | PSR_x},
14665218822Sdim  {"scxf", PSR_s | PSR_c | PSR_x | PSR_f},
14666218822Sdim  {"xfsc", PSR_x | PSR_f | PSR_s | PSR_c},
14667218822Sdim  {"xfcs", PSR_x | PSR_f | PSR_c | PSR_s},
14668218822Sdim  {"xsfc", PSR_x | PSR_s | PSR_f | PSR_c},
14669218822Sdim  {"xscf", PSR_x | PSR_s | PSR_c | PSR_f},
14670218822Sdim  {"xcfs", PSR_x | PSR_c | PSR_f | PSR_s},
14671218822Sdim  {"xcsf", PSR_x | PSR_c | PSR_s | PSR_f},
14672218822Sdim  {"cfsx", PSR_c | PSR_f | PSR_s | PSR_x},
14673218822Sdim  {"cfxs", PSR_c | PSR_f | PSR_x | PSR_s},
14674218822Sdim  {"csfx", PSR_c | PSR_s | PSR_f | PSR_x},
14675218822Sdim  {"csxf", PSR_c | PSR_s | PSR_x | PSR_f},
14676218822Sdim  {"cxfs", PSR_c | PSR_x | PSR_f | PSR_s},
14677218822Sdim  {"cxsf", PSR_c | PSR_x | PSR_s | PSR_f},
14678218822Sdim};
1467960484Sobrien
14680218822Sdim/* Table of V7M psr names.  */
14681218822Sdimstatic const struct asm_psr v7m_psrs[] =
1468260484Sobrien{
14683218822Sdim  {"apsr",	  0 }, {"APSR",		0 },
14684218822Sdim  {"iapsr",	  1 }, {"IAPSR",	1 },
14685218822Sdim  {"eapsr",	  2 }, {"EAPSR",	2 },
14686218822Sdim  {"psr",	  3 }, {"PSR",		3 },
14687218822Sdim  {"xpsr",	  3 }, {"XPSR",		3 }, {"xPSR",	  3 },
14688218822Sdim  {"ipsr",	  5 }, {"IPSR",		5 },
14689218822Sdim  {"epsr",	  6 }, {"EPSR",		6 },
14690218822Sdim  {"iepsr",	  7 }, {"IEPSR",	7 },
14691218822Sdim  {"msp",	  8 }, {"MSP",		8 },
14692218822Sdim  {"psp",	  9 }, {"PSP",		9 },
14693218822Sdim  {"primask",	  16}, {"PRIMASK",	16},
14694218822Sdim  {"basepri",	  17}, {"BASEPRI",	17},
14695218822Sdim  {"basepri_max", 18}, {"BASEPRI_MAX",	18},
14696218822Sdim  {"faultmask",	  19}, {"FAULTMASK",	19},
14697218822Sdim  {"control",	  20}, {"CONTROL",	20}
14698218822Sdim};
1469960484Sobrien
14700218822Sdim/* Table of all shift-in-operand names.	 */
14701218822Sdimstatic const struct asm_shift_name shift_names [] =
1470260484Sobrien{
14703218822Sdim  { "asl", SHIFT_LSL },	 { "ASL", SHIFT_LSL },
14704218822Sdim  { "lsl", SHIFT_LSL },	 { "LSL", SHIFT_LSL },
14705218822Sdim  { "lsr", SHIFT_LSR },	 { "LSR", SHIFT_LSR },
14706218822Sdim  { "asr", SHIFT_ASR },	 { "ASR", SHIFT_ASR },
14707218822Sdim  { "ror", SHIFT_ROR },	 { "ROR", SHIFT_ROR },
14708218822Sdim  { "rrx", SHIFT_RRX },	 { "RRX", SHIFT_RRX }
14709218822Sdim};
1471060484Sobrien
14711218822Sdim/* Table of all explicit relocation names.  */
14712218822Sdim#ifdef OBJ_ELF
14713218822Sdimstatic struct reloc_entry reloc_names[] =
1471460484Sobrien{
14715218822Sdim  { "got",     BFD_RELOC_ARM_GOT32   },	 { "GOT",     BFD_RELOC_ARM_GOT32   },
14716218822Sdim  { "gotoff",  BFD_RELOC_ARM_GOTOFF  },	 { "GOTOFF",  BFD_RELOC_ARM_GOTOFF  },
14717218822Sdim  { "plt",     BFD_RELOC_ARM_PLT32   },	 { "PLT",     BFD_RELOC_ARM_PLT32   },
14718218822Sdim  { "target1", BFD_RELOC_ARM_TARGET1 },	 { "TARGET1", BFD_RELOC_ARM_TARGET1 },
14719218822Sdim  { "target2", BFD_RELOC_ARM_TARGET2 },	 { "TARGET2", BFD_RELOC_ARM_TARGET2 },
14720218822Sdim  { "sbrel",   BFD_RELOC_ARM_SBREL32 },	 { "SBREL",   BFD_RELOC_ARM_SBREL32 },
14721218822Sdim  { "tlsgd",   BFD_RELOC_ARM_TLS_GD32},  { "TLSGD",   BFD_RELOC_ARM_TLS_GD32},
14722218822Sdim  { "tlsldm",  BFD_RELOC_ARM_TLS_LDM32}, { "TLSLDM",  BFD_RELOC_ARM_TLS_LDM32},
14723218822Sdim  { "tlsldo",  BFD_RELOC_ARM_TLS_LDO32}, { "TLSLDO",  BFD_RELOC_ARM_TLS_LDO32},
14724218822Sdim  { "gottpoff",BFD_RELOC_ARM_TLS_IE32},  { "GOTTPOFF",BFD_RELOC_ARM_TLS_IE32},
14725218822Sdim  { "tpoff",   BFD_RELOC_ARM_TLS_LE32},  { "TPOFF",   BFD_RELOC_ARM_TLS_LE32}
14726218822Sdim};
14727218822Sdim#endif
1472860484Sobrien
14729218822Sdim/* Table of all conditional affixes.  0xF is not defined as a condition code.  */
14730218822Sdimstatic const struct asm_cond conds[] =
1473160484Sobrien{
14732218822Sdim  {"eq", 0x0},
14733218822Sdim  {"ne", 0x1},
14734218822Sdim  {"cs", 0x2}, {"hs", 0x2},
14735218822Sdim  {"cc", 0x3}, {"ul", 0x3}, {"lo", 0x3},
14736218822Sdim  {"mi", 0x4},
14737218822Sdim  {"pl", 0x5},
14738218822Sdim  {"vs", 0x6},
14739218822Sdim  {"vc", 0x7},
14740218822Sdim  {"hi", 0x8},
14741218822Sdim  {"ls", 0x9},
14742218822Sdim  {"ge", 0xa},
14743218822Sdim  {"lt", 0xb},
14744218822Sdim  {"gt", 0xc},
14745218822Sdim  {"le", 0xd},
14746218822Sdim  {"al", 0xe}
14747218822Sdim};
1474860484Sobrien
14749218822Sdimstatic struct asm_barrier_opt barrier_opt_names[] =
14750218822Sdim{
14751272473Sandrew  { "sy",    0xf },
14752272473Sandrew  { "un",    0x7 },
14753272473Sandrew  { "st",    0xe },
14754272473Sandrew  { "unst",  0x6 },
14755272473Sandrew  { "ish",   0xb },
14756272473Sandrew  { "sh",    0xb },
14757272473Sandrew  { "ishst", 0xa },
14758272473Sandrew  { "shst",  0xa },
14759272473Sandrew  { "nsh",   0x7 },
14760272473Sandrew  { "nshst", 0x6 },
14761272473Sandrew  { "osh",   0x3 },
14762272473Sandrew  { "oshst", 0x2 }
14763218822Sdim};
1476460484Sobrien
14765218822Sdim/* Table of ARM-format instructions.	*/
1476660484Sobrien
14767218822Sdim/* Macros for gluing together operand strings.  N.B. In all cases
14768218822Sdim   other than OPS0, the trailing OP_stop comes from default
14769218822Sdim   zero-initialization of the unspecified elements of the array.  */
14770218822Sdim#define OPS0()		  { OP_stop, }
14771218822Sdim#define OPS1(a)		  { OP_##a, }
14772218822Sdim#define OPS2(a,b)	  { OP_##a,OP_##b, }
14773218822Sdim#define OPS3(a,b,c)	  { OP_##a,OP_##b,OP_##c, }
14774218822Sdim#define OPS4(a,b,c,d)	  { OP_##a,OP_##b,OP_##c,OP_##d, }
14775218822Sdim#define OPS5(a,b,c,d,e)	  { OP_##a,OP_##b,OP_##c,OP_##d,OP_##e, }
14776218822Sdim#define OPS6(a,b,c,d,e,f) { OP_##a,OP_##b,OP_##c,OP_##d,OP_##e,OP_##f, }
1477760484Sobrien
14778218822Sdim/* These macros abstract out the exact format of the mnemonic table and
14779218822Sdim   save some repeated characters.  */
1478060484Sobrien
14781218822Sdim/* The normal sort of mnemonic; has a Thumb variant; takes a conditional suffix.  */
14782218822Sdim#define TxCE(mnem, op, top, nops, ops, ae, te) \
14783218822Sdim  { #mnem, OPS##nops ops, OT_csuffix, 0x##op, top, ARM_VARIANT, \
14784218822Sdim    THUMB_VARIANT, do_##ae, do_##te }
1478560484Sobrien
14786218822Sdim/* Two variants of the above - TCE for a numeric Thumb opcode, tCE for
14787218822Sdim   a T_MNEM_xyz enumerator.  */
14788218822Sdim#define TCE(mnem, aop, top, nops, ops, ae, te) \
14789218822Sdim       TxCE(mnem, aop, 0x##top, nops, ops, ae, te)
14790218822Sdim#define tCE(mnem, aop, top, nops, ops, ae, te) \
14791218822Sdim       TxCE(mnem, aop, T_MNEM_##top, nops, ops, ae, te)
1479260484Sobrien
14793218822Sdim/* Second most common sort of mnemonic: has a Thumb variant, takes a conditional
14794218822Sdim   infix after the third character.  */
14795218822Sdim#define TxC3(mnem, op, top, nops, ops, ae, te) \
14796218822Sdim  { #mnem, OPS##nops ops, OT_cinfix3, 0x##op, top, ARM_VARIANT, \
14797218822Sdim    THUMB_VARIANT, do_##ae, do_##te }
14798218822Sdim#define TxC3w(mnem, op, top, nops, ops, ae, te) \
14799218822Sdim  { #mnem, OPS##nops ops, OT_cinfix3_deprecated, 0x##op, top, ARM_VARIANT, \
14800218822Sdim    THUMB_VARIANT, do_##ae, do_##te }
14801218822Sdim#define TC3(mnem, aop, top, nops, ops, ae, te) \
14802218822Sdim       TxC3(mnem, aop, 0x##top, nops, ops, ae, te)
14803218822Sdim#define TC3w(mnem, aop, top, nops, ops, ae, te) \
14804218822Sdim       TxC3w(mnem, aop, 0x##top, nops, ops, ae, te)
14805218822Sdim#define tC3(mnem, aop, top, nops, ops, ae, te) \
14806218822Sdim       TxC3(mnem, aop, T_MNEM_##top, nops, ops, ae, te)
14807218822Sdim#define tC3w(mnem, aop, top, nops, ops, ae, te) \
14808218822Sdim       TxC3w(mnem, aop, T_MNEM_##top, nops, ops, ae, te)
1480960484Sobrien
14810218822Sdim/* Mnemonic with a conditional infix in an unusual place.  Each and every variant has to
14811218822Sdim   appear in the condition table.  */
14812218822Sdim#define TxCM_(m1, m2, m3, op, top, nops, ops, ae, te)	\
14813218822Sdim  { #m1 #m2 #m3, OPS##nops ops, sizeof(#m2) == 1 ? OT_odd_infix_unc : OT_odd_infix_0 + sizeof(#m1) - 1, \
14814218822Sdim    0x##op, top, ARM_VARIANT, THUMB_VARIANT, do_##ae, do_##te }
1481560484Sobrien
14816218822Sdim#define TxCM(m1, m2, op, top, nops, ops, ae, te)	\
14817218822Sdim  TxCM_(m1,   , m2, op, top, nops, ops, ae, te),	\
14818218822Sdim  TxCM_(m1, eq, m2, op, top, nops, ops, ae, te),	\
14819218822Sdim  TxCM_(m1, ne, m2, op, top, nops, ops, ae, te),	\
14820218822Sdim  TxCM_(m1, cs, m2, op, top, nops, ops, ae, te),	\
14821218822Sdim  TxCM_(m1, hs, m2, op, top, nops, ops, ae, te),	\
14822218822Sdim  TxCM_(m1, cc, m2, op, top, nops, ops, ae, te),	\
14823218822Sdim  TxCM_(m1, ul, m2, op, top, nops, ops, ae, te),	\
14824218822Sdim  TxCM_(m1, lo, m2, op, top, nops, ops, ae, te),	\
14825218822Sdim  TxCM_(m1, mi, m2, op, top, nops, ops, ae, te),	\
14826218822Sdim  TxCM_(m1, pl, m2, op, top, nops, ops, ae, te),	\
14827218822Sdim  TxCM_(m1, vs, m2, op, top, nops, ops, ae, te),	\
14828218822Sdim  TxCM_(m1, vc, m2, op, top, nops, ops, ae, te),	\
14829218822Sdim  TxCM_(m1, hi, m2, op, top, nops, ops, ae, te),	\
14830218822Sdim  TxCM_(m1, ls, m2, op, top, nops, ops, ae, te),	\
14831218822Sdim  TxCM_(m1, ge, m2, op, top, nops, ops, ae, te),	\
14832218822Sdim  TxCM_(m1, lt, m2, op, top, nops, ops, ae, te),	\
14833218822Sdim  TxCM_(m1, gt, m2, op, top, nops, ops, ae, te),	\
14834218822Sdim  TxCM_(m1, le, m2, op, top, nops, ops, ae, te),	\
14835218822Sdim  TxCM_(m1, al, m2, op, top, nops, ops, ae, te)
1483660484Sobrien
14837218822Sdim#define TCM(m1,m2, aop, top, nops, ops, ae, te)		\
14838218822Sdim       TxCM(m1,m2, aop, 0x##top, nops, ops, ae, te)
14839218822Sdim#define tCM(m1,m2, aop, top, nops, ops, ae, te)			\
14840218822Sdim       TxCM(m1,m2, aop, T_MNEM_##top, nops, ops, ae, te)
1484160484Sobrien
14842218822Sdim/* Mnemonic that cannot be conditionalized.  The ARM condition-code
14843218822Sdim   field is still 0xE.  Many of the Thumb variants can be executed
14844218822Sdim   conditionally, so this is checked separately.  */
14845218822Sdim#define TUE(mnem, op, top, nops, ops, ae, te)				\
14846218822Sdim  { #mnem, OPS##nops ops, OT_unconditional, 0x##op, 0x##top, ARM_VARIANT, \
14847218822Sdim    THUMB_VARIANT, do_##ae, do_##te }
1484860484Sobrien
14849218822Sdim/* Mnemonic that cannot be conditionalized, and bears 0xF in its ARM
14850218822Sdim   condition code field.  */
14851218822Sdim#define TUF(mnem, op, top, nops, ops, ae, te)				\
14852218822Sdim  { #mnem, OPS##nops ops, OT_unconditionalF, 0x##op, 0x##top, ARM_VARIANT, \
14853218822Sdim    THUMB_VARIANT, do_##ae, do_##te }
1485460484Sobrien
14855218822Sdim/* ARM-only variants of all the above.  */
14856218822Sdim#define CE(mnem,  op, nops, ops, ae)	\
14857218822Sdim  { #mnem, OPS##nops ops, OT_csuffix, 0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
1485860484Sobrien
14859218822Sdim#define C3(mnem, op, nops, ops, ae)	\
14860218822Sdim  { #mnem, OPS##nops ops, OT_cinfix3, 0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
1486160484Sobrien
14862218822Sdim/* Legacy mnemonics that always have conditional infix after the third
14863218822Sdim   character.  */
14864218822Sdim#define CL(mnem, op, nops, ops, ae)	\
14865218822Sdim  { #mnem, OPS##nops ops, OT_cinfix3_legacy, \
14866218822Sdim    0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
1486760484Sobrien
14868218822Sdim/* Coprocessor instructions.  Isomorphic between Arm and Thumb-2.  */
14869218822Sdim#define cCE(mnem,  op, nops, ops, ae)	\
14870218822Sdim  { #mnem, OPS##nops ops, OT_csuffix, 0x##op, 0xe##op, ARM_VARIANT, ARM_VARIANT, do_##ae, do_##ae }
1487177298Sobrien
14872218822Sdim/* Legacy coprocessor instructions where conditional infix and conditional
14873218822Sdim   suffix are ambiguous.  For consistency this includes all FPA instructions,
14874218822Sdim   not just the potentially ambiguous ones.  */
14875218822Sdim#define cCL(mnem, op, nops, ops, ae)	\
14876218822Sdim  { #mnem, OPS##nops ops, OT_cinfix3_legacy, \
14877218822Sdim    0x##op, 0xe##op, ARM_VARIANT, ARM_VARIANT, do_##ae, do_##ae }
1487860484Sobrien
14879218822Sdim/* Coprocessor, takes either a suffix or a position-3 infix
14880218822Sdim   (for an FPA corner case). */
14881218822Sdim#define C3E(mnem, op, nops, ops, ae) \
14882218822Sdim  { #mnem, OPS##nops ops, OT_csuf_or_in3, \
14883218822Sdim    0x##op, 0xe##op, ARM_VARIANT, ARM_VARIANT, do_##ae, do_##ae }
1488460484Sobrien
14885218822Sdim#define xCM_(m1, m2, m3, op, nops, ops, ae)	\
14886218822Sdim  { #m1 #m2 #m3, OPS##nops ops, \
14887218822Sdim    sizeof(#m2) == 1 ? OT_odd_infix_unc : OT_odd_infix_0 + sizeof(#m1) - 1, \
14888218822Sdim    0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
1488960484Sobrien
14890218822Sdim#define CM(m1, m2, op, nops, ops, ae)	\
14891218822Sdim  xCM_(m1,   , m2, op, nops, ops, ae),	\
14892218822Sdim  xCM_(m1, eq, m2, op, nops, ops, ae),	\
14893218822Sdim  xCM_(m1, ne, m2, op, nops, ops, ae),	\
14894218822Sdim  xCM_(m1, cs, m2, op, nops, ops, ae),	\
14895218822Sdim  xCM_(m1, hs, m2, op, nops, ops, ae),	\
14896218822Sdim  xCM_(m1, cc, m2, op, nops, ops, ae),	\
14897218822Sdim  xCM_(m1, ul, m2, op, nops, ops, ae),	\
14898218822Sdim  xCM_(m1, lo, m2, op, nops, ops, ae),	\
14899218822Sdim  xCM_(m1, mi, m2, op, nops, ops, ae),	\
14900218822Sdim  xCM_(m1, pl, m2, op, nops, ops, ae),	\
14901218822Sdim  xCM_(m1, vs, m2, op, nops, ops, ae),	\
14902218822Sdim  xCM_(m1, vc, m2, op, nops, ops, ae),	\
14903218822Sdim  xCM_(m1, hi, m2, op, nops, ops, ae),	\
14904218822Sdim  xCM_(m1, ls, m2, op, nops, ops, ae),	\
14905218822Sdim  xCM_(m1, ge, m2, op, nops, ops, ae),	\
14906218822Sdim  xCM_(m1, lt, m2, op, nops, ops, ae),	\
14907218822Sdim  xCM_(m1, gt, m2, op, nops, ops, ae),	\
14908218822Sdim  xCM_(m1, le, m2, op, nops, ops, ae),	\
14909218822Sdim  xCM_(m1, al, m2, op, nops, ops, ae)
1491060484Sobrien
14911218822Sdim#define UE(mnem, op, nops, ops, ae)	\
14912218822Sdim  { #mnem, OPS##nops ops, OT_unconditional, 0x##op, 0, ARM_VARIANT, 0, do_##ae, NULL }
1491360484Sobrien
14914218822Sdim#define UF(mnem, op, nops, ops, ae)	\
14915218822Sdim  { #mnem, OPS##nops ops, OT_unconditionalF, 0x##op, 0, ARM_VARIANT, 0, do_##ae, NULL }
1491660484Sobrien
14917218822Sdim/* Neon data-processing. ARM versions are unconditional with cond=0xf.
14918218822Sdim   The Thumb and ARM variants are mostly the same (bits 0-23 and 24/28), so we
14919218822Sdim   use the same encoding function for each.  */
14920218822Sdim#define NUF(mnem, op, nops, ops, enc)					\
14921218822Sdim  { #mnem, OPS##nops ops, OT_unconditionalF, 0x##op, 0x##op,		\
14922218822Sdim    ARM_VARIANT, THUMB_VARIANT, do_##enc, do_##enc }
1492360484Sobrien
14924218822Sdim/* Neon data processing, version which indirects through neon_enc_tab for
14925218822Sdim   the various overloaded versions of opcodes.  */
14926218822Sdim#define nUF(mnem, op, nops, ops, enc)					\
14927218822Sdim  { #mnem, OPS##nops ops, OT_unconditionalF, N_MNEM_##op, N_MNEM_##op,	\
14928218822Sdim    ARM_VARIANT, THUMB_VARIANT, do_##enc, do_##enc }
14929218822Sdim
14930218822Sdim/* Neon insn with conditional suffix for the ARM version, non-overloaded
14931218822Sdim   version.  */
14932218822Sdim#define NCE_tag(mnem, op, nops, ops, enc, tag)				\
14933218822Sdim  { #mnem, OPS##nops ops, tag, 0x##op, 0x##op, ARM_VARIANT,		\
14934218822Sdim    THUMB_VARIANT, do_##enc, do_##enc }
14935218822Sdim
14936218822Sdim#define NCE(mnem, op, nops, ops, enc)					\
14937218822Sdim  NCE_tag(mnem, op, nops, ops, enc, OT_csuffix)
14938218822Sdim
14939218822Sdim#define NCEF(mnem, op, nops, ops, enc)					\
14940218822Sdim  NCE_tag(mnem, op, nops, ops, enc, OT_csuffixF)
14941218822Sdim
14942218822Sdim/* Neon insn with conditional suffix for the ARM version, overloaded types.  */
14943218822Sdim#define nCE_tag(mnem, op, nops, ops, enc, tag)				\
14944218822Sdim  { #mnem, OPS##nops ops, tag, N_MNEM_##op, N_MNEM_##op,		\
14945218822Sdim    ARM_VARIANT, THUMB_VARIANT, do_##enc, do_##enc }
14946218822Sdim
14947218822Sdim#define nCE(mnem, op, nops, ops, enc)					\
14948218822Sdim  nCE_tag(mnem, op, nops, ops, enc, OT_csuffix)
14949218822Sdim
14950218822Sdim#define nCEF(mnem, op, nops, ops, enc)					\
14951218822Sdim  nCE_tag(mnem, op, nops, ops, enc, OT_csuffixF)
14952218822Sdim
14953218822Sdim#define do_0 0
14954218822Sdim
14955218822Sdim/* Thumb-only, unconditional.  */
14956218822Sdim#define UT(mnem,  op, nops, ops, te) TUE(mnem,  0, op, nops, ops, 0, te)
14957218822Sdim
14958218822Sdimstatic const struct asm_opcode insns[] =
1495989857Sobrien{
14960218822Sdim#define ARM_VARIANT &arm_ext_v1 /* Core ARM Instructions.  */
14961218822Sdim#define THUMB_VARIANT &arm_ext_v4t
14962218822Sdim tCE(and,	0000000, and,      3, (RR, oRR, SH), arit, t_arit3c),
14963218822Sdim tC3(ands,	0100000, ands,	   3, (RR, oRR, SH), arit, t_arit3c),
14964218822Sdim tCE(eor,	0200000, eor,	   3, (RR, oRR, SH), arit, t_arit3c),
14965218822Sdim tC3(eors,	0300000, eors,	   3, (RR, oRR, SH), arit, t_arit3c),
14966218822Sdim tCE(sub,	0400000, sub,	   3, (RR, oRR, SH), arit, t_add_sub),
14967218822Sdim tC3(subs,	0500000, subs,	   3, (RR, oRR, SH), arit, t_add_sub),
14968218822Sdim tCE(add,	0800000, add,	   3, (RR, oRR, SHG), arit, t_add_sub),
14969218822Sdim tC3(adds,	0900000, adds,	   3, (RR, oRR, SHG), arit, t_add_sub),
14970218822Sdim tCE(adc,	0a00000, adc,	   3, (RR, oRR, SH), arit, t_arit3c),
14971218822Sdim tC3(adcs,	0b00000, adcs,	   3, (RR, oRR, SH), arit, t_arit3c),
14972218822Sdim tCE(sbc,	0c00000, sbc,	   3, (RR, oRR, SH), arit, t_arit3),
14973218822Sdim tC3(sbcs,	0d00000, sbcs,	   3, (RR, oRR, SH), arit, t_arit3),
14974218822Sdim tCE(orr,	1800000, orr,	   3, (RR, oRR, SH), arit, t_arit3c),
14975218822Sdim tC3(orrs,	1900000, orrs,	   3, (RR, oRR, SH), arit, t_arit3c),
14976218822Sdim tCE(bic,	1c00000, bic,	   3, (RR, oRR, SH), arit, t_arit3),
14977218822Sdim tC3(bics,	1d00000, bics,	   3, (RR, oRR, SH), arit, t_arit3),
1497889857Sobrien
14979218822Sdim /* The p-variants of tst/cmp/cmn/teq (below) are the pre-V6 mechanism
14980218822Sdim    for setting PSR flag bits.  They are obsolete in V6 and do not
14981218822Sdim    have Thumb equivalents. */
14982218822Sdim tCE(tst,	1100000, tst,	   2, (RR, SH),      cmp,  t_mvn_tst),
14983218822Sdim tC3w(tsts,	1100000, tst,	   2, (RR, SH),      cmp,  t_mvn_tst),
14984218822Sdim  CL(tstp,	110f000,     	   2, (RR, SH),      cmp),
14985218822Sdim tCE(cmp,	1500000, cmp,	   2, (RR, SH),      cmp,  t_mov_cmp),
14986218822Sdim tC3w(cmps,	1500000, cmp,	   2, (RR, SH),      cmp,  t_mov_cmp),
14987218822Sdim  CL(cmpp,	150f000,     	   2, (RR, SH),      cmp),
14988218822Sdim tCE(cmn,	1700000, cmn,	   2, (RR, SH),      cmp,  t_mvn_tst),
14989218822Sdim tC3w(cmns,	1700000, cmn,	   2, (RR, SH),      cmp,  t_mvn_tst),
14990218822Sdim  CL(cmnp,	170f000,     	   2, (RR, SH),      cmp),
1499189857Sobrien
14992218822Sdim tCE(mov,	1a00000, mov,	   2, (RR, SH),      mov,  t_mov_cmp),
14993218822Sdim tC3(movs,	1b00000, movs,	   2, (RR, SH),      mov,  t_mov_cmp),
14994218822Sdim tCE(mvn,	1e00000, mvn,	   2, (RR, SH),      mov,  t_mvn_tst),
14995218822Sdim tC3(mvns,	1f00000, mvns,	   2, (RR, SH),      mov,  t_mvn_tst),
14996218822Sdim
14997218822Sdim tCE(ldr,	4100000, ldr,	   2, (RR, ADDRGLDR),ldst, t_ldst),
14998218822Sdim tC3(ldrb,	4500000, ldrb,	   2, (RR, ADDRGLDR),ldst, t_ldst),
14999218822Sdim tCE(str,	4000000, str,	   2, (RR, ADDRGLDR),ldst, t_ldst),
15000218822Sdim tC3(strb,	4400000, strb,	   2, (RR, ADDRGLDR),ldst, t_ldst),
15001218822Sdim
15002218822Sdim tCE(stm,	8800000, stmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
15003218822Sdim tC3(stmia,	8800000, stmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
15004218822Sdim tC3(stmea,	8800000, stmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
15005218822Sdim tCE(ldm,	8900000, ldmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
15006218822Sdim tC3(ldmia,	8900000, ldmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
15007218822Sdim tC3(ldmfd,	8900000, ldmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
15008218822Sdim
15009218822Sdim TCE(swi,	f000000, df00,     1, (EXPi),        swi, t_swi),
15010218822Sdim TCE(svc,	f000000, df00,     1, (EXPi),        swi, t_swi),
15011218822Sdim tCE(b,		a000000, b,	   1, (EXPr),	     branch, t_branch),
15012218822Sdim TCE(bl,	b000000, f000f800, 1, (EXPr),	     bl, t_branch23),
15013218822Sdim
15014218822Sdim  /* Pseudo ops.  */
15015218822Sdim tCE(adr,	28f0000, adr,	   2, (RR, EXP),     adr,  t_adr),
15016218822Sdim  C3(adrl,	28f0000,           2, (RR, EXP),     adrl),
15017218822Sdim tCE(nop,	1a00000, nop,	   1, (oI255c),	     nop,  t_nop),
15018218822Sdim
15019218822Sdim  /* Thumb-compatibility pseudo ops.  */
15020218822Sdim tCE(lsl,	1a00000, lsl,	   3, (RR, oRR, SH), shift, t_shift),
15021218822Sdim tC3(lsls,	1b00000, lsls,	   3, (RR, oRR, SH), shift, t_shift),
15022218822Sdim tCE(lsr,	1a00020, lsr,	   3, (RR, oRR, SH), shift, t_shift),
15023218822Sdim tC3(lsrs,	1b00020, lsrs,	   3, (RR, oRR, SH), shift, t_shift),
15024218822Sdim tCE(asr,	1a00040, asr,	   3, (RR, oRR, SH), shift, t_shift),
15025218822Sdim tC3(asrs,      1b00040, asrs,     3, (RR, oRR, SH), shift, t_shift),
15026218822Sdim tCE(ror,	1a00060, ror,	   3, (RR, oRR, SH), shift, t_shift),
15027218822Sdim tC3(rors,	1b00060, rors,	   3, (RR, oRR, SH), shift, t_shift),
15028218822Sdim tCE(neg,	2600000, neg,	   2, (RR, RR),      rd_rn, t_neg),
15029218822Sdim tC3(negs,	2700000, negs,	   2, (RR, RR),      rd_rn, t_neg),
15030218822Sdim tCE(push,	92d0000, push,     1, (REGLST),	     push_pop, t_push_pop),
15031218822Sdim tCE(pop,	8bd0000, pop,	   1, (REGLST),	     push_pop, t_push_pop),
15032218822Sdim
15033218822Sdim /* These may simplify to neg.  */
15034218822Sdim TCE(rsb,	0600000, ebc00000, 3, (RR, oRR, SH), arit, t_rsb),
15035218822Sdim TC3(rsbs,	0700000, ebd00000, 3, (RR, oRR, SH), arit, t_rsb),
15036218822Sdim
15037223484Sdim TCE(rrx,      1a00060, ea4f0030, 2, (RR, RR),      rd_rm, t_rd_rm),
15038223484Sdim TCE(rrxs,     1b00060, ea5f0030, 2, (RR, RR),      rd_rm, t_rd_rm),
15039223484Sdim
15040218822Sdim#undef THUMB_VARIANT
15041218822Sdim#define THUMB_VARIANT &arm_ext_v6
15042218822Sdim TCE(cpy,       1a00000, 4600,     2, (RR, RR),      rd_rm, t_cpy),
15043218822Sdim
15044218822Sdim /* V1 instructions with no Thumb analogue prior to V6T2.  */
15045218822Sdim#undef THUMB_VARIANT
15046218822Sdim#define THUMB_VARIANT &arm_ext_v6t2
15047218822Sdim TCE(teq,	1300000, ea900f00, 2, (RR, SH),      cmp,  t_mvn_tst),
15048218822Sdim TC3w(teqs,	1300000, ea900f00, 2, (RR, SH),      cmp,  t_mvn_tst),
15049218822Sdim  CL(teqp,	130f000,           2, (RR, SH),      cmp),
15050218822Sdim
15051218822Sdim TC3(ldrt,	4300000, f8500e00, 2, (RR, ADDR),    ldstt, t_ldstt),
15052218822Sdim TC3(ldrbt,	4700000, f8100e00, 2, (RR, ADDR),    ldstt, t_ldstt),
15053218822Sdim TC3(strt,	4200000, f8400e00, 2, (RR, ADDR),    ldstt, t_ldstt),
15054218822Sdim TC3(strbt,	4600000, f8000e00, 2, (RR, ADDR),    ldstt, t_ldstt),
15055218822Sdim
15056218822Sdim TC3(stmdb,	9000000, e9000000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
15057218822Sdim TC3(stmfd,     9000000, e9000000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
15058218822Sdim
15059218822Sdim TC3(ldmdb,	9100000, e9100000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
15060218822Sdim TC3(ldmea,	9100000, e9100000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
15061218822Sdim
15062218822Sdim /* V1 instructions with no Thumb analogue at all.  */
15063218822Sdim  CE(rsc,	0e00000,	   3, (RR, oRR, SH), arit),
15064218822Sdim  C3(rscs,	0f00000,	   3, (RR, oRR, SH), arit),
15065218822Sdim
15066218822Sdim  C3(stmib,	9800000,	   2, (RRw, REGLST), ldmstm),
15067218822Sdim  C3(stmfa,	9800000,	   2, (RRw, REGLST), ldmstm),
15068218822Sdim  C3(stmda,	8000000,	   2, (RRw, REGLST), ldmstm),
15069218822Sdim  C3(stmed,	8000000,	   2, (RRw, REGLST), ldmstm),
15070218822Sdim  C3(ldmib,	9900000,	   2, (RRw, REGLST), ldmstm),
15071218822Sdim  C3(ldmed,	9900000,	   2, (RRw, REGLST), ldmstm),
15072218822Sdim  C3(ldmda,	8100000,	   2, (RRw, REGLST), ldmstm),
15073218822Sdim  C3(ldmfa,	8100000,	   2, (RRw, REGLST), ldmstm),
15074218822Sdim
15075218822Sdim#undef ARM_VARIANT
15076218822Sdim#define ARM_VARIANT &arm_ext_v2	/* ARM 2 - multiplies.	*/
15077218822Sdim#undef THUMB_VARIANT
15078218822Sdim#define THUMB_VARIANT &arm_ext_v4t
15079218822Sdim tCE(mul,	0000090, mul,	   3, (RRnpc, RRnpc, oRR), mul, t_mul),
15080218822Sdim tC3(muls,	0100090, muls,	   3, (RRnpc, RRnpc, oRR), mul, t_mul),
15081218822Sdim
15082218822Sdim#undef THUMB_VARIANT
15083218822Sdim#define THUMB_VARIANT &arm_ext_v6t2
15084218822Sdim TCE(mla,	0200090, fb000000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mlas, t_mla),
15085218822Sdim  C3(mlas,	0300090,           4, (RRnpc, RRnpc, RRnpc, RRnpc), mlas),
15086218822Sdim
15087218822Sdim  /* Generic coprocessor instructions.	*/
15088218822Sdim TCE(cdp,	e000000, ee000000, 6, (RCP, I15b, RCN, RCN, RCN, oI7b), cdp,    cdp),
15089218822Sdim TCE(ldc,	c100000, ec100000, 3, (RCP, RCN, ADDRGLDC),	        lstc,   lstc),
15090218822Sdim TC3(ldcl,	c500000, ec500000, 3, (RCP, RCN, ADDRGLDC),	        lstc,   lstc),
15091218822Sdim TCE(stc,	c000000, ec000000, 3, (RCP, RCN, ADDRGLDC),	        lstc,   lstc),
15092218822Sdim TC3(stcl,	c400000, ec400000, 3, (RCP, RCN, ADDRGLDC),	        lstc,   lstc),
15093218822Sdim TCE(mcr,	e000010, ee000010, 6, (RCP, I7b, RR, RCN, RCN, oI7b),   co_reg, co_reg),
15094275415Sandrew TCE(mrc,	e100010, ee100010, 6, (RCP, I7b, APSR_RR, RCN, RCN, oI7b),   co_reg, co_reg),
15095218822Sdim
15096218822Sdim#undef ARM_VARIANT
15097218822Sdim#define ARM_VARIANT &arm_ext_v2s /* ARM 3 - swp instructions.  */
15098218822Sdim  CE(swp,	1000090,           3, (RRnpc, RRnpc, RRnpcb), rd_rm_rn),
15099218822Sdim  C3(swpb,	1400090,           3, (RRnpc, RRnpc, RRnpcb), rd_rm_rn),
15100218822Sdim
15101218822Sdim#undef ARM_VARIANT
15102218822Sdim#define ARM_VARIANT &arm_ext_v3	/* ARM 6 Status register instructions.	*/
15103218822Sdim TCE(mrs,	10f0000, f3ef8000, 2, (APSR_RR, RVC_PSR), mrs, t_mrs),
15104218822Sdim TCE(msr,	120f000, f3808000, 2, (RVC_PSR, RR_EXi), msr, t_msr),
15105218822Sdim
15106218822Sdim#undef ARM_VARIANT
15107218822Sdim#define ARM_VARIANT &arm_ext_v3m	 /* ARM 7M long multiplies.  */
15108218822Sdim TCE(smull,	0c00090, fb800000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull, t_mull),
15109218822Sdim  CM(smull,s,	0d00090,           4, (RRnpc, RRnpc, RRnpc, RRnpc), mull),
15110218822Sdim TCE(umull,	0800090, fba00000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull, t_mull),
15111218822Sdim  CM(umull,s,	0900090,           4, (RRnpc, RRnpc, RRnpc, RRnpc), mull),
15112218822Sdim TCE(smlal,	0e00090, fbc00000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull, t_mull),
15113218822Sdim  CM(smlal,s,	0f00090,           4, (RRnpc, RRnpc, RRnpc, RRnpc), mull),
15114218822Sdim TCE(umlal,	0a00090, fbe00000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull, t_mull),
15115218822Sdim  CM(umlal,s,	0b00090,           4, (RRnpc, RRnpc, RRnpc, RRnpc), mull),
15116218822Sdim
15117218822Sdim#undef ARM_VARIANT
15118218822Sdim#define ARM_VARIANT &arm_ext_v4	/* ARM Architecture 4.	*/
15119218822Sdim#undef THUMB_VARIANT
15120218822Sdim#define THUMB_VARIANT &arm_ext_v4t
15121218822Sdim tC3(ldrh,	01000b0, ldrh,     2, (RR, ADDRGLDRS), ldstv4, t_ldst),
15122218822Sdim tC3(strh,	00000b0, strh,     2, (RR, ADDRGLDRS), ldstv4, t_ldst),
15123218822Sdim tC3(ldrsh,	01000f0, ldrsh,    2, (RR, ADDRGLDRS), ldstv4, t_ldst),
15124218822Sdim tC3(ldrsb,	01000d0, ldrsb,    2, (RR, ADDRGLDRS), ldstv4, t_ldst),
15125218822Sdim tCM(ld,sh,	01000f0, ldrsh,    2, (RR, ADDRGLDRS), ldstv4, t_ldst),
15126218822Sdim tCM(ld,sb,	01000d0, ldrsb,    2, (RR, ADDRGLDRS), ldstv4, t_ldst),
15127218822Sdim
15128218822Sdim#undef ARM_VARIANT
15129218822Sdim#define ARM_VARIANT &arm_ext_v4t_5
15130218822Sdim  /* ARM Architecture 4T.  */
15131218822Sdim  /* Note: bx (and blx) are required on V5, even if the processor does
15132218822Sdim     not support Thumb.	 */
15133218822Sdim TCE(bx,	12fff10, 4700, 1, (RR),	bx, t_bx),
15134218822Sdim
15135218822Sdim#undef ARM_VARIANT
15136218822Sdim#define ARM_VARIANT &arm_ext_v5 /*  ARM Architecture 5T.	 */
15137218822Sdim#undef THUMB_VARIANT
15138218822Sdim#define THUMB_VARIANT &arm_ext_v5t
15139218822Sdim  /* Note: blx has 2 variants; the .value coded here is for
15140218822Sdim     BLX(2).  Only this variant has conditional execution.  */
15141218822Sdim TCE(blx,	12fff30, 4780, 1, (RR_EXr),			    blx,  t_blx),
15142218822Sdim TUE(bkpt,	1200070, be00, 1, (oIffffb),			    bkpt, t_bkpt),
15143218822Sdim
15144218822Sdim#undef THUMB_VARIANT
15145218822Sdim#define THUMB_VARIANT &arm_ext_v6t2
15146218822Sdim TCE(clz,	16f0f10, fab0f080, 2, (RRnpc, RRnpc),		        rd_rm,  t_clz),
15147218822Sdim TUF(ldc2,	c100000, fc100000, 3, (RCP, RCN, ADDRGLDC),	        lstc,	lstc),
15148218822Sdim TUF(ldc2l,	c500000, fc500000, 3, (RCP, RCN, ADDRGLDC),		        lstc,	lstc),
15149218822Sdim TUF(stc2,	c000000, fc000000, 3, (RCP, RCN, ADDRGLDC),	        lstc,	lstc),
15150218822Sdim TUF(stc2l,	c400000, fc400000, 3, (RCP, RCN, ADDRGLDC),		        lstc,	lstc),
15151218822Sdim TUF(cdp2,	e000000, fe000000, 6, (RCP, I15b, RCN, RCN, RCN, oI7b), cdp,    cdp),
15152218822Sdim TUF(mcr2,	e000010, fe000010, 6, (RCP, I7b, RR, RCN, RCN, oI7b),   co_reg, co_reg),
15153275415Sandrew TUF(mrc2,	e100010, fe100010, 6, (RCP, I7b, APSR_RR, RCN, RCN, oI7b),   co_reg, co_reg),
15154218822Sdim
15155218822Sdim#undef ARM_VARIANT
15156218822Sdim#define ARM_VARIANT &arm_ext_v5exp /*  ARM Architecture 5TExP.  */
15157218822Sdim TCE(smlabb,	1000080, fb100000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15158218822Sdim TCE(smlatb,	10000a0, fb100020, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15159218822Sdim TCE(smlabt,	10000c0, fb100010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15160218822Sdim TCE(smlatt,	10000e0, fb100030, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15161218822Sdim
15162218822Sdim TCE(smlawb,	1200080, fb300000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15163218822Sdim TCE(smlawt,	12000c0, fb300010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15164218822Sdim
15165218822Sdim TCE(smlalbb,	1400080, fbc00080, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smlal, t_mlal),
15166218822Sdim TCE(smlaltb,	14000a0, fbc000a0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smlal, t_mlal),
15167218822Sdim TCE(smlalbt,	14000c0, fbc00090, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smlal, t_mlal),
15168218822Sdim TCE(smlaltt,	14000e0, fbc000b0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smlal, t_mlal),
15169218822Sdim
15170218822Sdim TCE(smulbb,	1600080, fb10f000, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15171218822Sdim TCE(smultb,	16000a0, fb10f020, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15172218822Sdim TCE(smulbt,	16000c0, fb10f010, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15173218822Sdim TCE(smultt,	16000e0, fb10f030, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15174218822Sdim
15175218822Sdim TCE(smulwb,	12000a0, fb30f000, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15176218822Sdim TCE(smulwt,	12000e0, fb30f010, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15177218822Sdim
15178218822Sdim TCE(qadd,	1000050, fa80f080, 3, (RRnpc, RRnpc, RRnpc),	    rd_rm_rn, rd_rm_rn),
15179218822Sdim TCE(qdadd,	1400050, fa80f090, 3, (RRnpc, RRnpc, RRnpc),	    rd_rm_rn, rd_rm_rn),
15180218822Sdim TCE(qsub,	1200050, fa80f0a0, 3, (RRnpc, RRnpc, RRnpc),	    rd_rm_rn, rd_rm_rn),
15181218822Sdim TCE(qdsub,	1600050, fa80f0b0, 3, (RRnpc, RRnpc, RRnpc),	    rd_rm_rn, rd_rm_rn),
15182218822Sdim
15183218822Sdim#undef ARM_VARIANT
15184218822Sdim#define ARM_VARIANT &arm_ext_v5e /*  ARM Architecture 5TE.  */
15185218822Sdim TUF(pld,	450f000, f810f000, 1, (ADDR),		     pld,  t_pld),
15186218822Sdim TC3(ldrd,	00000d0, e8500000, 3, (RRnpc, oRRnpc, ADDRGLDRS), ldrd, t_ldstd),
15187218822Sdim TC3(strd,	00000f0, e8400000, 3, (RRnpc, oRRnpc, ADDRGLDRS), ldrd, t_ldstd),
15188218822Sdim
15189218822Sdim TCE(mcrr,	c400000, ec400000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
15190218822Sdim TCE(mrrc,	c500000, ec500000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
15191218822Sdim
15192218822Sdim#undef ARM_VARIANT
15193218822Sdim#define ARM_VARIANT &arm_ext_v5j /*  ARM Architecture 5TEJ.  */
15194218822Sdim TCE(bxj,	12fff20, f3c08f00, 1, (RR),			  bxj, t_bxj),
15195218822Sdim
15196218822Sdim#undef ARM_VARIANT
15197218822Sdim#define ARM_VARIANT &arm_ext_v6 /*  ARM V6.  */
15198218822Sdim#undef THUMB_VARIANT
15199218822Sdim#define THUMB_VARIANT &arm_ext_v6
15200218822Sdim TUF(cpsie,     1080000, b660,     2, (CPSF, oI31b),              cpsi,   t_cpsi),
15201218822Sdim TUF(cpsid,     10c0000, b670,     2, (CPSF, oI31b),              cpsi,   t_cpsi),
15202218822Sdim tCE(rev,       6bf0f30, rev,      2, (RRnpc, RRnpc),             rd_rm,  t_rev),
15203218822Sdim tCE(rev16,     6bf0fb0, rev16,    2, (RRnpc, RRnpc),             rd_rm,  t_rev),
15204218822Sdim tCE(revsh,     6ff0fb0, revsh,    2, (RRnpc, RRnpc),             rd_rm,  t_rev),
15205218822Sdim tCE(sxth,      6bf0070, sxth,     3, (RRnpc, RRnpc, oROR),       sxth,   t_sxth),
15206218822Sdim tCE(uxth,      6ff0070, uxth,     3, (RRnpc, RRnpc, oROR),       sxth,   t_sxth),
15207218822Sdim tCE(sxtb,      6af0070, sxtb,     3, (RRnpc, RRnpc, oROR),       sxth,   t_sxth),
15208218822Sdim tCE(uxtb,      6ef0070, uxtb,     3, (RRnpc, RRnpc, oROR),       sxth,   t_sxth),
15209218822Sdim TUF(setend,    1010000, b650,     1, (ENDI),                     setend, t_setend),
15210218822Sdim
15211218822Sdim#undef THUMB_VARIANT
15212218822Sdim#define THUMB_VARIANT &arm_ext_v6t2
15213218822Sdim TCE(ldrex,	1900f9f, e8500f00, 2, (RRnpc, ADDR),		  ldrex, t_ldrex),
15214218822Sdim TCE(strex,	1800f90, e8400000, 3, (RRnpc, RRnpc, ADDR),	   strex,  t_strex),
15215218822Sdim TUF(mcrr2,	c400000, fc400000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
15216218822Sdim TUF(mrrc2,	c500000, fc500000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
15217218822Sdim
15218218822Sdim TCE(ssat,	6a00010, f3000000, 4, (RRnpc, I32, RRnpc, oSHllar),ssat,   t_ssat),
15219218822Sdim TCE(usat,	6e00010, f3800000, 4, (RRnpc, I31, RRnpc, oSHllar),usat,   t_usat),
15220218822Sdim
15221218822Sdim/*  ARM V6 not included in V7M (eg. integer SIMD).  */
15222218822Sdim#undef THUMB_VARIANT
15223218822Sdim#define THUMB_VARIANT &arm_ext_v6_notm
15224218822Sdim TUF(cps,	1020000, f3af8100, 1, (I31b),			  imm0, t_cps),
15225218822Sdim TCE(pkhbt,	6800010, eac00000, 4, (RRnpc, RRnpc, RRnpc, oSHll),   pkhbt, t_pkhbt),
15226218822Sdim TCE(pkhtb,	6800050, eac00020, 4, (RRnpc, RRnpc, RRnpc, oSHar),   pkhtb, t_pkhtb),
15227218822Sdim TCE(qadd16,	6200f10, fa90f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15228218822Sdim TCE(qadd8,	6200f90, fa80f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15229218822Sdim TCE(qaddsubx,	6200f30, faa0f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15230218822Sdim TCE(qsub16,	6200f70, fad0f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15231218822Sdim TCE(qsub8,	6200ff0, fac0f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15232218822Sdim TCE(qsubaddx,	6200f50, fae0f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15233218822Sdim TCE(sadd16,	6100f10, fa90f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15234218822Sdim TCE(sadd8,	6100f90, fa80f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15235218822Sdim TCE(saddsubx,	6100f30, faa0f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15236218822Sdim TCE(shadd16,	6300f10, fa90f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15237218822Sdim TCE(shadd8,	6300f90, fa80f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15238218822Sdim TCE(shaddsubx, 6300f30, faa0f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15239218822Sdim TCE(shsub16,	6300f70, fad0f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15240218822Sdim TCE(shsub8,	6300ff0, fac0f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15241218822Sdim TCE(shsubaddx, 6300f50, fae0f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15242218822Sdim TCE(ssub16,	6100f70, fad0f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15243218822Sdim TCE(ssub8,	6100ff0, fac0f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15244218822Sdim TCE(ssubaddx,	6100f50, fae0f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15245218822Sdim TCE(uadd16,	6500f10, fa90f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15246218822Sdim TCE(uadd8,	6500f90, fa80f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15247218822Sdim TCE(uaddsubx,	6500f30, faa0f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15248218822Sdim TCE(uhadd16,	6700f10, fa90f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15249218822Sdim TCE(uhadd8,	6700f90, fa80f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15250218822Sdim TCE(uhaddsubx, 6700f30, faa0f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15251218822Sdim TCE(uhsub16,	6700f70, fad0f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15252218822Sdim TCE(uhsub8,	6700ff0, fac0f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15253218822Sdim TCE(uhsubaddx, 6700f50, fae0f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15254218822Sdim TCE(uqadd16,	6600f10, fa90f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15255218822Sdim TCE(uqadd8,	6600f90, fa80f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15256218822Sdim TCE(uqaddsubx, 6600f30, faa0f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15257218822Sdim TCE(uqsub16,	6600f70, fad0f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15258218822Sdim TCE(uqsub8,	6600ff0, fac0f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15259218822Sdim TCE(uqsubaddx, 6600f50, fae0f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15260218822Sdim TCE(usub16,	6500f70, fad0f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15261218822Sdim TCE(usub8,	6500ff0, fac0f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15262218822Sdim TCE(usubaddx,	6500f50, fae0f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15263218822Sdim TUF(rfeia,	8900a00, e990c000, 1, (RRw),			   rfe, rfe),
15264218822Sdim  UF(rfeib,	9900a00,           1, (RRw),			   rfe),
15265218822Sdim  UF(rfeda,	8100a00,           1, (RRw),			   rfe),
15266218822Sdim TUF(rfedb,	9100a00, e810c000, 1, (RRw),			   rfe, rfe),
15267218822Sdim TUF(rfefd,	8900a00, e990c000, 1, (RRw),			   rfe, rfe),
15268218822Sdim  UF(rfefa,	9900a00,           1, (RRw),			   rfe),
15269218822Sdim  UF(rfeea,	8100a00,           1, (RRw),			   rfe),
15270218822Sdim TUF(rfeed,	9100a00, e810c000, 1, (RRw),			   rfe, rfe),
15271218822Sdim TCE(sxtah,	6b00070, fa00f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15272218822Sdim TCE(sxtab16,	6800070, fa20f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15273218822Sdim TCE(sxtab,	6a00070, fa40f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15274218822Sdim TCE(sxtb16,	68f0070, fa2ff080, 3, (RRnpc, RRnpc, oROR),	   sxth,  t_sxth),
15275218822Sdim TCE(uxtah,	6f00070, fa10f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15276218822Sdim TCE(uxtab16,	6c00070, fa30f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15277218822Sdim TCE(uxtab,	6e00070, fa50f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15278218822Sdim TCE(uxtb16,	6cf0070, fa3ff080, 3, (RRnpc, RRnpc, oROR),	   sxth,  t_sxth),
15279218822Sdim TCE(sel,	6800fb0, faa0f080, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15280218822Sdim TCE(smlad,	7000010, fb200000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15281218822Sdim TCE(smladx,	7000030, fb200010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15282218822Sdim TCE(smlald,	7400010, fbc000c0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,t_mlal),
15283218822Sdim TCE(smlaldx,	7400030, fbc000d0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,t_mlal),
15284218822Sdim TCE(smlsd,	7000050, fb400000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15285218822Sdim TCE(smlsdx,	7000070, fb400010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15286218822Sdim TCE(smlsld,	7400050, fbd000c0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,t_mlal),
15287218822Sdim TCE(smlsldx,	7400070, fbd000d0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,t_mlal),
15288218822Sdim TCE(smmla,	7500010, fb500000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15289218822Sdim TCE(smmlar,	7500030, fb500010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15290218822Sdim TCE(smmls,	75000d0, fb600000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15291218822Sdim TCE(smmlsr,	75000f0, fb600010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15292218822Sdim TCE(smmul,	750f010, fb50f000, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15293218822Sdim TCE(smmulr,	750f030, fb50f010, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15294218822Sdim TCE(smuad,	700f010, fb20f000, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15295218822Sdim TCE(smuadx,	700f030, fb20f010, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15296218822Sdim TCE(smusd,	700f050, fb40f000, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15297218822Sdim TCE(smusdx,	700f070, fb40f010, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15298218822Sdim TUF(srsia,	8c00500, e980c000, 2, (oRRw, I31w),		   srs,  srs),
15299218822Sdim  UF(srsib,	9c00500,           2, (oRRw, I31w),		   srs),
15300218822Sdim  UF(srsda,	8400500,	   2, (oRRw, I31w),		   srs),
15301218822Sdim TUF(srsdb,	9400500, e800c000, 2, (oRRw, I31w),		   srs,  srs),
15302218822Sdim TCE(ssat16,	6a00f30, f3200000, 3, (RRnpc, I16, RRnpc),	   ssat16, t_ssat16),
15303218822Sdim TCE(umaal,	0400090, fbe00060, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,  t_mlal),
15304218822Sdim TCE(usad8,	780f010, fb70f000, 3, (RRnpc, RRnpc, RRnpc),	   smul,   t_simd),
15305218822Sdim TCE(usada8,	7800010, fb700000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla,   t_mla),
15306218822Sdim TCE(usat16,	6e00f30, f3a00000, 3, (RRnpc, I15, RRnpc),	   usat16, t_usat16),
15307218822Sdim
15308218822Sdim#undef ARM_VARIANT
15309218822Sdim#define ARM_VARIANT &arm_ext_v6k
15310218822Sdim#undef THUMB_VARIANT
15311218822Sdim#define THUMB_VARIANT &arm_ext_v6k
15312218822Sdim tCE(yield,	320f001, yield,    0, (), noargs, t_hint),
15313218822Sdim tCE(wfe,	320f002, wfe,      0, (), noargs, t_hint),
15314218822Sdim tCE(wfi,	320f003, wfi,      0, (), noargs, t_hint),
15315218822Sdim tCE(sev,	320f004, sev,      0, (), noargs, t_hint),
15316218822Sdim
15317218822Sdim#undef THUMB_VARIANT
15318218822Sdim#define THUMB_VARIANT &arm_ext_v6_notm
15319218822Sdim TCE(ldrexd,	1b00f9f, e8d0007f, 3, (RRnpc, oRRnpc, RRnpcb),        ldrexd, t_ldrexd),
15320218822Sdim TCE(strexd,	1a00f90, e8c00070, 4, (RRnpc, RRnpc, oRRnpc, RRnpcb), strexd, t_strexd),
15321218822Sdim
15322218822Sdim#undef THUMB_VARIANT
15323218822Sdim#define THUMB_VARIANT &arm_ext_v6t2
15324218822Sdim TCE(ldrexb,	1d00f9f, e8d00f4f, 2, (RRnpc, RRnpcb),	              rd_rn,  rd_rn),
15325218822Sdim TCE(ldrexh,	1f00f9f, e8d00f5f, 2, (RRnpc, RRnpcb),	              rd_rn,  rd_rn),
15326218822Sdim TCE(strexb,	1c00f90, e8c00f40, 3, (RRnpc, RRnpc, ADDR),           strex,  rm_rd_rn),
15327218822Sdim TCE(strexh,	1e00f90, e8c00f50, 3, (RRnpc, RRnpc, ADDR),           strex,  rm_rd_rn),
15328218822Sdim TUF(clrex,	57ff01f, f3bf8f2f, 0, (),			      noargs, noargs),
15329218822Sdim
15330218822Sdim#undef ARM_VARIANT
15331218822Sdim#define ARM_VARIANT &arm_ext_v6z
15332218822Sdim TCE(smc,	1600070, f7f08000, 1, (EXPi), smc, t_smc),
15333218822Sdim
15334218822Sdim#undef ARM_VARIANT
15335218822Sdim#define ARM_VARIANT &arm_ext_v6t2
15336218822Sdim TCE(bfc,	7c0001f, f36f0000, 3, (RRnpc, I31, I32),	   bfc, t_bfc),
15337218822Sdim TCE(bfi,	7c00010, f3600000, 4, (RRnpc, RRnpc_I0, I31, I32), bfi, t_bfi),
15338218822Sdim TCE(sbfx,	7a00050, f3400000, 4, (RR, RR, I31, I32),	   bfx, t_bfx),
15339218822Sdim TCE(ubfx,	7e00050, f3c00000, 4, (RR, RR, I31, I32),	   bfx, t_bfx),
15340218822Sdim
15341218822Sdim TCE(mls,	0600090, fb000010, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mlas, t_mla),
15342218822Sdim TCE(movw,	3000000, f2400000, 2, (RRnpc, HALF),		    mov16, t_mov16),
15343218822Sdim TCE(movt,	3400000, f2c00000, 2, (RRnpc, HALF),		    mov16, t_mov16),
15344218822Sdim TCE(rbit,	6ff0f30, fa90f0a0, 2, (RR, RR),			    rd_rm, t_rbit),
15345218822Sdim
15346218822Sdim TC3(ldrht,	03000b0, f8300e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
15347218822Sdim TC3(ldrsht,	03000f0, f9300e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
15348218822Sdim TC3(ldrsbt,	03000d0, f9100e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
15349218822Sdim TC3(strht,	02000b0, f8200e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
15350218822Sdim
15351218822Sdim  UT(cbnz,      b900,    2, (RR, EXP), t_cbz),
15352218822Sdim  UT(cbz,       b100,    2, (RR, EXP), t_cbz),
15353218822Sdim /* ARM does not really have an IT instruction, so always allow it.  */
15354218822Sdim#undef ARM_VARIANT
15355218822Sdim#define ARM_VARIANT &arm_ext_v1
15356218822Sdim TUE(it,        0, bf08, 1, (COND),    it, t_it),
15357218822Sdim TUE(itt,       0, bf0c, 1, (COND),    it, t_it),
15358218822Sdim TUE(ite,       0, bf04, 1, (COND),    it, t_it),
15359218822Sdim TUE(ittt,      0, bf0e, 1, (COND),    it, t_it),
15360218822Sdim TUE(itet,      0, bf06, 1, (COND),    it, t_it),
15361218822Sdim TUE(itte,      0, bf0a, 1, (COND),    it, t_it),
15362218822Sdim TUE(itee,      0, bf02, 1, (COND),    it, t_it),
15363218822Sdim TUE(itttt,     0, bf0f, 1, (COND),    it, t_it),
15364218822Sdim TUE(itett,     0, bf07, 1, (COND),    it, t_it),
15365218822Sdim TUE(ittet,     0, bf0b, 1, (COND),    it, t_it),
15366218822Sdim TUE(iteet,     0, bf03, 1, (COND),    it, t_it),
15367218822Sdim TUE(ittte,     0, bf0d, 1, (COND),    it, t_it),
15368218822Sdim TUE(itete,     0, bf05, 1, (COND),    it, t_it),
15369218822Sdim TUE(ittee,     0, bf09, 1, (COND),    it, t_it),
15370218822Sdim TUE(iteee,     0, bf01, 1, (COND),    it, t_it),
15371218822Sdim
15372218822Sdim /* Thumb2 only instructions.  */
15373218822Sdim#undef ARM_VARIANT
15374218822Sdim#define ARM_VARIANT NULL
15375218822Sdim
15376218822Sdim TCE(addw,	0, f2000000, 3, (RR, RR, EXPi), 0, t_add_sub_w),
15377218822Sdim TCE(subw,	0, f2a00000, 3, (RR, RR, EXPi), 0, t_add_sub_w),
15378218822Sdim TCE(tbb,       0, e8d0f000, 1, (TB), 0, t_tb),
15379218822Sdim TCE(tbh,       0, e8d0f010, 1, (TB), 0, t_tb),
15380218822Sdim
15381218822Sdim /* Thumb-2 hardware division instructions (R and M profiles only).  */
15382218822Sdim#undef THUMB_VARIANT
15383218822Sdim#define THUMB_VARIANT &arm_ext_div
15384218822Sdim TCE(sdiv,	0, fb90f0f0, 3, (RR, oRR, RR), 0, t_div),
15385218822Sdim TCE(udiv,	0, fbb0f0f0, 3, (RR, oRR, RR), 0, t_div),
15386218822Sdim
15387218822Sdim /* ARM V7 instructions.  */
15388218822Sdim#undef ARM_VARIANT
15389218822Sdim#define ARM_VARIANT &arm_ext_v7
15390218822Sdim#undef THUMB_VARIANT
15391218822Sdim#define THUMB_VARIANT &arm_ext_v7
15392218822Sdim TUF(pli,	450f000, f910f000, 1, (ADDR),	  pli,	    t_pld),
15393218822Sdim TCE(dbg,	320f0f0, f3af80f0, 1, (I15),	  dbg,	    t_dbg),
15394218822Sdim TUF(dmb,	57ff050, f3bf8f50, 1, (oBARRIER), barrier,  t_barrier),
15395218822Sdim TUF(dsb,	57ff040, f3bf8f40, 1, (oBARRIER), barrier,  t_barrier),
15396218822Sdim TUF(isb,	57ff060, f3bf8f60, 1, (oBARRIER), barrier,  t_barrier),
15397218822Sdim
15398218822Sdim#undef ARM_VARIANT
15399218822Sdim#define ARM_VARIANT &fpu_fpa_ext_v1  /* Core FPA instruction set (V1).  */
15400218822Sdim cCE(wfs,	e200110, 1, (RR),	     rd),
15401218822Sdim cCE(rfs,	e300110, 1, (RR),	     rd),
15402218822Sdim cCE(wfc,	e400110, 1, (RR),	     rd),
15403218822Sdim cCE(rfc,	e500110, 1, (RR),	     rd),
15404218822Sdim
15405218822Sdim cCL(ldfs,	c100100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15406218822Sdim cCL(ldfd,	c108100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15407218822Sdim cCL(ldfe,	c500100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15408218822Sdim cCL(ldfp,	c508100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15409218822Sdim
15410218822Sdim cCL(stfs,	c000100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15411218822Sdim cCL(stfd,	c008100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15412218822Sdim cCL(stfe,	c400100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15413218822Sdim cCL(stfp,	c408100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15414218822Sdim
15415218822Sdim cCL(mvfs,	e008100, 2, (RF, RF_IF),     rd_rm),
15416218822Sdim cCL(mvfsp,	e008120, 2, (RF, RF_IF),     rd_rm),
15417218822Sdim cCL(mvfsm,	e008140, 2, (RF, RF_IF),     rd_rm),
15418218822Sdim cCL(mvfsz,	e008160, 2, (RF, RF_IF),     rd_rm),
15419218822Sdim cCL(mvfd,	e008180, 2, (RF, RF_IF),     rd_rm),
15420218822Sdim cCL(mvfdp,	e0081a0, 2, (RF, RF_IF),     rd_rm),
15421218822Sdim cCL(mvfdm,	e0081c0, 2, (RF, RF_IF),     rd_rm),
15422218822Sdim cCL(mvfdz,	e0081e0, 2, (RF, RF_IF),     rd_rm),
15423218822Sdim cCL(mvfe,	e088100, 2, (RF, RF_IF),     rd_rm),
15424218822Sdim cCL(mvfep,	e088120, 2, (RF, RF_IF),     rd_rm),
15425218822Sdim cCL(mvfem,	e088140, 2, (RF, RF_IF),     rd_rm),
15426218822Sdim cCL(mvfez,	e088160, 2, (RF, RF_IF),     rd_rm),
15427218822Sdim
15428218822Sdim cCL(mnfs,	e108100, 2, (RF, RF_IF),     rd_rm),
15429218822Sdim cCL(mnfsp,	e108120, 2, (RF, RF_IF),     rd_rm),
15430218822Sdim cCL(mnfsm,	e108140, 2, (RF, RF_IF),     rd_rm),
15431218822Sdim cCL(mnfsz,	e108160, 2, (RF, RF_IF),     rd_rm),
15432218822Sdim cCL(mnfd,	e108180, 2, (RF, RF_IF),     rd_rm),
15433218822Sdim cCL(mnfdp,	e1081a0, 2, (RF, RF_IF),     rd_rm),
15434218822Sdim cCL(mnfdm,	e1081c0, 2, (RF, RF_IF),     rd_rm),
15435218822Sdim cCL(mnfdz,	e1081e0, 2, (RF, RF_IF),     rd_rm),
15436218822Sdim cCL(mnfe,	e188100, 2, (RF, RF_IF),     rd_rm),
15437218822Sdim cCL(mnfep,	e188120, 2, (RF, RF_IF),     rd_rm),
15438218822Sdim cCL(mnfem,	e188140, 2, (RF, RF_IF),     rd_rm),
15439218822Sdim cCL(mnfez,	e188160, 2, (RF, RF_IF),     rd_rm),
15440218822Sdim
15441218822Sdim cCL(abss,	e208100, 2, (RF, RF_IF),     rd_rm),
15442218822Sdim cCL(abssp,	e208120, 2, (RF, RF_IF),     rd_rm),
15443218822Sdim cCL(abssm,	e208140, 2, (RF, RF_IF),     rd_rm),
15444218822Sdim cCL(abssz,	e208160, 2, (RF, RF_IF),     rd_rm),
15445218822Sdim cCL(absd,	e208180, 2, (RF, RF_IF),     rd_rm),
15446218822Sdim cCL(absdp,	e2081a0, 2, (RF, RF_IF),     rd_rm),
15447218822Sdim cCL(absdm,	e2081c0, 2, (RF, RF_IF),     rd_rm),
15448218822Sdim cCL(absdz,	e2081e0, 2, (RF, RF_IF),     rd_rm),
15449218822Sdim cCL(abse,	e288100, 2, (RF, RF_IF),     rd_rm),
15450218822Sdim cCL(absep,	e288120, 2, (RF, RF_IF),     rd_rm),
15451218822Sdim cCL(absem,	e288140, 2, (RF, RF_IF),     rd_rm),
15452218822Sdim cCL(absez,	e288160, 2, (RF, RF_IF),     rd_rm),
15453218822Sdim
15454218822Sdim cCL(rnds,	e308100, 2, (RF, RF_IF),     rd_rm),
15455218822Sdim cCL(rndsp,	e308120, 2, (RF, RF_IF),     rd_rm),
15456218822Sdim cCL(rndsm,	e308140, 2, (RF, RF_IF),     rd_rm),
15457218822Sdim cCL(rndsz,	e308160, 2, (RF, RF_IF),     rd_rm),
15458218822Sdim cCL(rndd,	e308180, 2, (RF, RF_IF),     rd_rm),
15459218822Sdim cCL(rnddp,	e3081a0, 2, (RF, RF_IF),     rd_rm),
15460218822Sdim cCL(rnddm,	e3081c0, 2, (RF, RF_IF),     rd_rm),
15461218822Sdim cCL(rnddz,	e3081e0, 2, (RF, RF_IF),     rd_rm),
15462218822Sdim cCL(rnde,	e388100, 2, (RF, RF_IF),     rd_rm),
15463218822Sdim cCL(rndep,	e388120, 2, (RF, RF_IF),     rd_rm),
15464218822Sdim cCL(rndem,	e388140, 2, (RF, RF_IF),     rd_rm),
15465218822Sdim cCL(rndez,	e388160, 2, (RF, RF_IF),     rd_rm),
15466218822Sdim
15467218822Sdim cCL(sqts,	e408100, 2, (RF, RF_IF),     rd_rm),
15468218822Sdim cCL(sqtsp,	e408120, 2, (RF, RF_IF),     rd_rm),
15469218822Sdim cCL(sqtsm,	e408140, 2, (RF, RF_IF),     rd_rm),
15470218822Sdim cCL(sqtsz,	e408160, 2, (RF, RF_IF),     rd_rm),
15471218822Sdim cCL(sqtd,	e408180, 2, (RF, RF_IF),     rd_rm),
15472218822Sdim cCL(sqtdp,	e4081a0, 2, (RF, RF_IF),     rd_rm),
15473218822Sdim cCL(sqtdm,	e4081c0, 2, (RF, RF_IF),     rd_rm),
15474218822Sdim cCL(sqtdz,	e4081e0, 2, (RF, RF_IF),     rd_rm),
15475218822Sdim cCL(sqte,	e488100, 2, (RF, RF_IF),     rd_rm),
15476218822Sdim cCL(sqtep,	e488120, 2, (RF, RF_IF),     rd_rm),
15477218822Sdim cCL(sqtem,	e488140, 2, (RF, RF_IF),     rd_rm),
15478218822Sdim cCL(sqtez,	e488160, 2, (RF, RF_IF),     rd_rm),
15479218822Sdim
15480218822Sdim cCL(logs,	e508100, 2, (RF, RF_IF),     rd_rm),
15481218822Sdim cCL(logsp,	e508120, 2, (RF, RF_IF),     rd_rm),
15482218822Sdim cCL(logsm,	e508140, 2, (RF, RF_IF),     rd_rm),
15483218822Sdim cCL(logsz,	e508160, 2, (RF, RF_IF),     rd_rm),
15484218822Sdim cCL(logd,	e508180, 2, (RF, RF_IF),     rd_rm),
15485218822Sdim cCL(logdp,	e5081a0, 2, (RF, RF_IF),     rd_rm),
15486218822Sdim cCL(logdm,	e5081c0, 2, (RF, RF_IF),     rd_rm),
15487218822Sdim cCL(logdz,	e5081e0, 2, (RF, RF_IF),     rd_rm),
15488218822Sdim cCL(loge,	e588100, 2, (RF, RF_IF),     rd_rm),
15489218822Sdim cCL(logep,	e588120, 2, (RF, RF_IF),     rd_rm),
15490218822Sdim cCL(logem,	e588140, 2, (RF, RF_IF),     rd_rm),
15491218822Sdim cCL(logez,	e588160, 2, (RF, RF_IF),     rd_rm),
15492218822Sdim
15493218822Sdim cCL(lgns,	e608100, 2, (RF, RF_IF),     rd_rm),
15494218822Sdim cCL(lgnsp,	e608120, 2, (RF, RF_IF),     rd_rm),
15495218822Sdim cCL(lgnsm,	e608140, 2, (RF, RF_IF),     rd_rm),
15496218822Sdim cCL(lgnsz,	e608160, 2, (RF, RF_IF),     rd_rm),
15497218822Sdim cCL(lgnd,	e608180, 2, (RF, RF_IF),     rd_rm),
15498218822Sdim cCL(lgndp,	e6081a0, 2, (RF, RF_IF),     rd_rm),
15499218822Sdim cCL(lgndm,	e6081c0, 2, (RF, RF_IF),     rd_rm),
15500218822Sdim cCL(lgndz,	e6081e0, 2, (RF, RF_IF),     rd_rm),
15501218822Sdim cCL(lgne,	e688100, 2, (RF, RF_IF),     rd_rm),
15502218822Sdim cCL(lgnep,	e688120, 2, (RF, RF_IF),     rd_rm),
15503218822Sdim cCL(lgnem,	e688140, 2, (RF, RF_IF),     rd_rm),
15504218822Sdim cCL(lgnez,	e688160, 2, (RF, RF_IF),     rd_rm),
15505218822Sdim
15506218822Sdim cCL(exps,	e708100, 2, (RF, RF_IF),     rd_rm),
15507218822Sdim cCL(expsp,	e708120, 2, (RF, RF_IF),     rd_rm),
15508218822Sdim cCL(expsm,	e708140, 2, (RF, RF_IF),     rd_rm),
15509218822Sdim cCL(expsz,	e708160, 2, (RF, RF_IF),     rd_rm),
15510218822Sdim cCL(expd,	e708180, 2, (RF, RF_IF),     rd_rm),
15511218822Sdim cCL(expdp,	e7081a0, 2, (RF, RF_IF),     rd_rm),
15512218822Sdim cCL(expdm,	e7081c0, 2, (RF, RF_IF),     rd_rm),
15513218822Sdim cCL(expdz,	e7081e0, 2, (RF, RF_IF),     rd_rm),
15514218822Sdim cCL(expe,	e788100, 2, (RF, RF_IF),     rd_rm),
15515218822Sdim cCL(expep,	e788120, 2, (RF, RF_IF),     rd_rm),
15516218822Sdim cCL(expem,	e788140, 2, (RF, RF_IF),     rd_rm),
15517218822Sdim cCL(expdz,	e788160, 2, (RF, RF_IF),     rd_rm),
15518218822Sdim
15519218822Sdim cCL(sins,	e808100, 2, (RF, RF_IF),     rd_rm),
15520218822Sdim cCL(sinsp,	e808120, 2, (RF, RF_IF),     rd_rm),
15521218822Sdim cCL(sinsm,	e808140, 2, (RF, RF_IF),     rd_rm),
15522218822Sdim cCL(sinsz,	e808160, 2, (RF, RF_IF),     rd_rm),
15523218822Sdim cCL(sind,	e808180, 2, (RF, RF_IF),     rd_rm),
15524218822Sdim cCL(sindp,	e8081a0, 2, (RF, RF_IF),     rd_rm),
15525218822Sdim cCL(sindm,	e8081c0, 2, (RF, RF_IF),     rd_rm),
15526218822Sdim cCL(sindz,	e8081e0, 2, (RF, RF_IF),     rd_rm),
15527218822Sdim cCL(sine,	e888100, 2, (RF, RF_IF),     rd_rm),
15528218822Sdim cCL(sinep,	e888120, 2, (RF, RF_IF),     rd_rm),
15529218822Sdim cCL(sinem,	e888140, 2, (RF, RF_IF),     rd_rm),
15530218822Sdim cCL(sinez,	e888160, 2, (RF, RF_IF),     rd_rm),
15531218822Sdim
15532218822Sdim cCL(coss,	e908100, 2, (RF, RF_IF),     rd_rm),
15533218822Sdim cCL(cossp,	e908120, 2, (RF, RF_IF),     rd_rm),
15534218822Sdim cCL(cossm,	e908140, 2, (RF, RF_IF),     rd_rm),
15535218822Sdim cCL(cossz,	e908160, 2, (RF, RF_IF),     rd_rm),
15536218822Sdim cCL(cosd,	e908180, 2, (RF, RF_IF),     rd_rm),
15537218822Sdim cCL(cosdp,	e9081a0, 2, (RF, RF_IF),     rd_rm),
15538218822Sdim cCL(cosdm,	e9081c0, 2, (RF, RF_IF),     rd_rm),
15539218822Sdim cCL(cosdz,	e9081e0, 2, (RF, RF_IF),     rd_rm),
15540218822Sdim cCL(cose,	e988100, 2, (RF, RF_IF),     rd_rm),
15541218822Sdim cCL(cosep,	e988120, 2, (RF, RF_IF),     rd_rm),
15542218822Sdim cCL(cosem,	e988140, 2, (RF, RF_IF),     rd_rm),
15543218822Sdim cCL(cosez,	e988160, 2, (RF, RF_IF),     rd_rm),
15544218822Sdim
15545218822Sdim cCL(tans,	ea08100, 2, (RF, RF_IF),     rd_rm),
15546218822Sdim cCL(tansp,	ea08120, 2, (RF, RF_IF),     rd_rm),
15547218822Sdim cCL(tansm,	ea08140, 2, (RF, RF_IF),     rd_rm),
15548218822Sdim cCL(tansz,	ea08160, 2, (RF, RF_IF),     rd_rm),
15549218822Sdim cCL(tand,	ea08180, 2, (RF, RF_IF),     rd_rm),
15550218822Sdim cCL(tandp,	ea081a0, 2, (RF, RF_IF),     rd_rm),
15551218822Sdim cCL(tandm,	ea081c0, 2, (RF, RF_IF),     rd_rm),
15552218822Sdim cCL(tandz,	ea081e0, 2, (RF, RF_IF),     rd_rm),
15553218822Sdim cCL(tane,	ea88100, 2, (RF, RF_IF),     rd_rm),
15554218822Sdim cCL(tanep,	ea88120, 2, (RF, RF_IF),     rd_rm),
15555218822Sdim cCL(tanem,	ea88140, 2, (RF, RF_IF),     rd_rm),
15556218822Sdim cCL(tanez,	ea88160, 2, (RF, RF_IF),     rd_rm),
15557218822Sdim
15558218822Sdim cCL(asns,	eb08100, 2, (RF, RF_IF),     rd_rm),
15559218822Sdim cCL(asnsp,	eb08120, 2, (RF, RF_IF),     rd_rm),
15560218822Sdim cCL(asnsm,	eb08140, 2, (RF, RF_IF),     rd_rm),
15561218822Sdim cCL(asnsz,	eb08160, 2, (RF, RF_IF),     rd_rm),
15562218822Sdim cCL(asnd,	eb08180, 2, (RF, RF_IF),     rd_rm),
15563218822Sdim cCL(asndp,	eb081a0, 2, (RF, RF_IF),     rd_rm),
15564218822Sdim cCL(asndm,	eb081c0, 2, (RF, RF_IF),     rd_rm),
15565218822Sdim cCL(asndz,	eb081e0, 2, (RF, RF_IF),     rd_rm),
15566218822Sdim cCL(asne,	eb88100, 2, (RF, RF_IF),     rd_rm),
15567218822Sdim cCL(asnep,	eb88120, 2, (RF, RF_IF),     rd_rm),
15568218822Sdim cCL(asnem,	eb88140, 2, (RF, RF_IF),     rd_rm),
15569218822Sdim cCL(asnez,	eb88160, 2, (RF, RF_IF),     rd_rm),
15570218822Sdim
15571218822Sdim cCL(acss,	ec08100, 2, (RF, RF_IF),     rd_rm),
15572218822Sdim cCL(acssp,	ec08120, 2, (RF, RF_IF),     rd_rm),
15573218822Sdim cCL(acssm,	ec08140, 2, (RF, RF_IF),     rd_rm),
15574218822Sdim cCL(acssz,	ec08160, 2, (RF, RF_IF),     rd_rm),
15575218822Sdim cCL(acsd,	ec08180, 2, (RF, RF_IF),     rd_rm),
15576218822Sdim cCL(acsdp,	ec081a0, 2, (RF, RF_IF),     rd_rm),
15577218822Sdim cCL(acsdm,	ec081c0, 2, (RF, RF_IF),     rd_rm),
15578218822Sdim cCL(acsdz,	ec081e0, 2, (RF, RF_IF),     rd_rm),
15579218822Sdim cCL(acse,	ec88100, 2, (RF, RF_IF),     rd_rm),
15580218822Sdim cCL(acsep,	ec88120, 2, (RF, RF_IF),     rd_rm),
15581218822Sdim cCL(acsem,	ec88140, 2, (RF, RF_IF),     rd_rm),
15582218822Sdim cCL(acsez,	ec88160, 2, (RF, RF_IF),     rd_rm),
15583218822Sdim
15584218822Sdim cCL(atns,	ed08100, 2, (RF, RF_IF),     rd_rm),
15585218822Sdim cCL(atnsp,	ed08120, 2, (RF, RF_IF),     rd_rm),
15586218822Sdim cCL(atnsm,	ed08140, 2, (RF, RF_IF),     rd_rm),
15587218822Sdim cCL(atnsz,	ed08160, 2, (RF, RF_IF),     rd_rm),
15588218822Sdim cCL(atnd,	ed08180, 2, (RF, RF_IF),     rd_rm),
15589218822Sdim cCL(atndp,	ed081a0, 2, (RF, RF_IF),     rd_rm),
15590218822Sdim cCL(atndm,	ed081c0, 2, (RF, RF_IF),     rd_rm),
15591218822Sdim cCL(atndz,	ed081e0, 2, (RF, RF_IF),     rd_rm),
15592218822Sdim cCL(atne,	ed88100, 2, (RF, RF_IF),     rd_rm),
15593218822Sdim cCL(atnep,	ed88120, 2, (RF, RF_IF),     rd_rm),
15594218822Sdim cCL(atnem,	ed88140, 2, (RF, RF_IF),     rd_rm),
15595218822Sdim cCL(atnez,	ed88160, 2, (RF, RF_IF),     rd_rm),
15596218822Sdim
15597218822Sdim cCL(urds,	ee08100, 2, (RF, RF_IF),     rd_rm),
15598218822Sdim cCL(urdsp,	ee08120, 2, (RF, RF_IF),     rd_rm),
15599218822Sdim cCL(urdsm,	ee08140, 2, (RF, RF_IF),     rd_rm),
15600218822Sdim cCL(urdsz,	ee08160, 2, (RF, RF_IF),     rd_rm),
15601218822Sdim cCL(urdd,	ee08180, 2, (RF, RF_IF),     rd_rm),
15602218822Sdim cCL(urddp,	ee081a0, 2, (RF, RF_IF),     rd_rm),
15603218822Sdim cCL(urddm,	ee081c0, 2, (RF, RF_IF),     rd_rm),
15604218822Sdim cCL(urddz,	ee081e0, 2, (RF, RF_IF),     rd_rm),
15605218822Sdim cCL(urde,	ee88100, 2, (RF, RF_IF),     rd_rm),
15606218822Sdim cCL(urdep,	ee88120, 2, (RF, RF_IF),     rd_rm),
15607218822Sdim cCL(urdem,	ee88140, 2, (RF, RF_IF),     rd_rm),
15608218822Sdim cCL(urdez,	ee88160, 2, (RF, RF_IF),     rd_rm),
15609218822Sdim
15610218822Sdim cCL(nrms,	ef08100, 2, (RF, RF_IF),     rd_rm),
15611218822Sdim cCL(nrmsp,	ef08120, 2, (RF, RF_IF),     rd_rm),
15612218822Sdim cCL(nrmsm,	ef08140, 2, (RF, RF_IF),     rd_rm),
15613218822Sdim cCL(nrmsz,	ef08160, 2, (RF, RF_IF),     rd_rm),
15614218822Sdim cCL(nrmd,	ef08180, 2, (RF, RF_IF),     rd_rm),
15615218822Sdim cCL(nrmdp,	ef081a0, 2, (RF, RF_IF),     rd_rm),
15616218822Sdim cCL(nrmdm,	ef081c0, 2, (RF, RF_IF),     rd_rm),
15617218822Sdim cCL(nrmdz,	ef081e0, 2, (RF, RF_IF),     rd_rm),
15618218822Sdim cCL(nrme,	ef88100, 2, (RF, RF_IF),     rd_rm),
15619218822Sdim cCL(nrmep,	ef88120, 2, (RF, RF_IF),     rd_rm),
15620218822Sdim cCL(nrmem,	ef88140, 2, (RF, RF_IF),     rd_rm),
15621218822Sdim cCL(nrmez,	ef88160, 2, (RF, RF_IF),     rd_rm),
15622218822Sdim
15623218822Sdim cCL(adfs,	e000100, 3, (RF, RF, RF_IF), rd_rn_rm),
15624218822Sdim cCL(adfsp,	e000120, 3, (RF, RF, RF_IF), rd_rn_rm),
15625218822Sdim cCL(adfsm,	e000140, 3, (RF, RF, RF_IF), rd_rn_rm),
15626218822Sdim cCL(adfsz,	e000160, 3, (RF, RF, RF_IF), rd_rn_rm),
15627218822Sdim cCL(adfd,	e000180, 3, (RF, RF, RF_IF), rd_rn_rm),
15628218822Sdim cCL(adfdp,	e0001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15629218822Sdim cCL(adfdm,	e0001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15630218822Sdim cCL(adfdz,	e0001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15631218822Sdim cCL(adfe,	e080100, 3, (RF, RF, RF_IF), rd_rn_rm),
15632218822Sdim cCL(adfep,	e080120, 3, (RF, RF, RF_IF), rd_rn_rm),
15633218822Sdim cCL(adfem,	e080140, 3, (RF, RF, RF_IF), rd_rn_rm),
15634218822Sdim cCL(adfez,	e080160, 3, (RF, RF, RF_IF), rd_rn_rm),
15635218822Sdim
15636218822Sdim cCL(sufs,	e200100, 3, (RF, RF, RF_IF), rd_rn_rm),
15637218822Sdim cCL(sufsp,	e200120, 3, (RF, RF, RF_IF), rd_rn_rm),
15638218822Sdim cCL(sufsm,	e200140, 3, (RF, RF, RF_IF), rd_rn_rm),
15639218822Sdim cCL(sufsz,	e200160, 3, (RF, RF, RF_IF), rd_rn_rm),
15640218822Sdim cCL(sufd,	e200180, 3, (RF, RF, RF_IF), rd_rn_rm),
15641218822Sdim cCL(sufdp,	e2001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15642218822Sdim cCL(sufdm,	e2001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15643218822Sdim cCL(sufdz,	e2001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15644218822Sdim cCL(sufe,	e280100, 3, (RF, RF, RF_IF), rd_rn_rm),
15645218822Sdim cCL(sufep,	e280120, 3, (RF, RF, RF_IF), rd_rn_rm),
15646218822Sdim cCL(sufem,	e280140, 3, (RF, RF, RF_IF), rd_rn_rm),
15647218822Sdim cCL(sufez,	e280160, 3, (RF, RF, RF_IF), rd_rn_rm),
15648218822Sdim
15649218822Sdim cCL(rsfs,	e300100, 3, (RF, RF, RF_IF), rd_rn_rm),
15650218822Sdim cCL(rsfsp,	e300120, 3, (RF, RF, RF_IF), rd_rn_rm),
15651218822Sdim cCL(rsfsm,	e300140, 3, (RF, RF, RF_IF), rd_rn_rm),
15652218822Sdim cCL(rsfsz,	e300160, 3, (RF, RF, RF_IF), rd_rn_rm),
15653218822Sdim cCL(rsfd,	e300180, 3, (RF, RF, RF_IF), rd_rn_rm),
15654218822Sdim cCL(rsfdp,	e3001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15655218822Sdim cCL(rsfdm,	e3001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15656218822Sdim cCL(rsfdz,	e3001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15657218822Sdim cCL(rsfe,	e380100, 3, (RF, RF, RF_IF), rd_rn_rm),
15658218822Sdim cCL(rsfep,	e380120, 3, (RF, RF, RF_IF), rd_rn_rm),
15659218822Sdim cCL(rsfem,	e380140, 3, (RF, RF, RF_IF), rd_rn_rm),
15660218822Sdim cCL(rsfez,	e380160, 3, (RF, RF, RF_IF), rd_rn_rm),
15661218822Sdim
15662218822Sdim cCL(mufs,	e100100, 3, (RF, RF, RF_IF), rd_rn_rm),
15663218822Sdim cCL(mufsp,	e100120, 3, (RF, RF, RF_IF), rd_rn_rm),
15664218822Sdim cCL(mufsm,	e100140, 3, (RF, RF, RF_IF), rd_rn_rm),
15665218822Sdim cCL(mufsz,	e100160, 3, (RF, RF, RF_IF), rd_rn_rm),
15666218822Sdim cCL(mufd,	e100180, 3, (RF, RF, RF_IF), rd_rn_rm),
15667218822Sdim cCL(mufdp,	e1001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15668218822Sdim cCL(mufdm,	e1001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15669218822Sdim cCL(mufdz,	e1001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15670218822Sdim cCL(mufe,	e180100, 3, (RF, RF, RF_IF), rd_rn_rm),
15671218822Sdim cCL(mufep,	e180120, 3, (RF, RF, RF_IF), rd_rn_rm),
15672218822Sdim cCL(mufem,	e180140, 3, (RF, RF, RF_IF), rd_rn_rm),
15673218822Sdim cCL(mufez,	e180160, 3, (RF, RF, RF_IF), rd_rn_rm),
15674218822Sdim
15675218822Sdim cCL(dvfs,	e400100, 3, (RF, RF, RF_IF), rd_rn_rm),
15676218822Sdim cCL(dvfsp,	e400120, 3, (RF, RF, RF_IF), rd_rn_rm),
15677218822Sdim cCL(dvfsm,	e400140, 3, (RF, RF, RF_IF), rd_rn_rm),
15678218822Sdim cCL(dvfsz,	e400160, 3, (RF, RF, RF_IF), rd_rn_rm),
15679218822Sdim cCL(dvfd,	e400180, 3, (RF, RF, RF_IF), rd_rn_rm),
15680218822Sdim cCL(dvfdp,	e4001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15681218822Sdim cCL(dvfdm,	e4001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15682218822Sdim cCL(dvfdz,	e4001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15683218822Sdim cCL(dvfe,	e480100, 3, (RF, RF, RF_IF), rd_rn_rm),
15684218822Sdim cCL(dvfep,	e480120, 3, (RF, RF, RF_IF), rd_rn_rm),
15685218822Sdim cCL(dvfem,	e480140, 3, (RF, RF, RF_IF), rd_rn_rm),
15686218822Sdim cCL(dvfez,	e480160, 3, (RF, RF, RF_IF), rd_rn_rm),
15687218822Sdim
15688218822Sdim cCL(rdfs,	e500100, 3, (RF, RF, RF_IF), rd_rn_rm),
15689218822Sdim cCL(rdfsp,	e500120, 3, (RF, RF, RF_IF), rd_rn_rm),
15690218822Sdim cCL(rdfsm,	e500140, 3, (RF, RF, RF_IF), rd_rn_rm),
15691218822Sdim cCL(rdfsz,	e500160, 3, (RF, RF, RF_IF), rd_rn_rm),
15692218822Sdim cCL(rdfd,	e500180, 3, (RF, RF, RF_IF), rd_rn_rm),
15693218822Sdim cCL(rdfdp,	e5001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15694218822Sdim cCL(rdfdm,	e5001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15695218822Sdim cCL(rdfdz,	e5001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15696218822Sdim cCL(rdfe,	e580100, 3, (RF, RF, RF_IF), rd_rn_rm),
15697218822Sdim cCL(rdfep,	e580120, 3, (RF, RF, RF_IF), rd_rn_rm),
15698218822Sdim cCL(rdfem,	e580140, 3, (RF, RF, RF_IF), rd_rn_rm),
15699218822Sdim cCL(rdfez,	e580160, 3, (RF, RF, RF_IF), rd_rn_rm),
15700218822Sdim
15701218822Sdim cCL(pows,	e600100, 3, (RF, RF, RF_IF), rd_rn_rm),
15702218822Sdim cCL(powsp,	e600120, 3, (RF, RF, RF_IF), rd_rn_rm),
15703218822Sdim cCL(powsm,	e600140, 3, (RF, RF, RF_IF), rd_rn_rm),
15704218822Sdim cCL(powsz,	e600160, 3, (RF, RF, RF_IF), rd_rn_rm),
15705218822Sdim cCL(powd,	e600180, 3, (RF, RF, RF_IF), rd_rn_rm),
15706218822Sdim cCL(powdp,	e6001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15707218822Sdim cCL(powdm,	e6001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15708218822Sdim cCL(powdz,	e6001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15709218822Sdim cCL(powe,	e680100, 3, (RF, RF, RF_IF), rd_rn_rm),
15710218822Sdim cCL(powep,	e680120, 3, (RF, RF, RF_IF), rd_rn_rm),
15711218822Sdim cCL(powem,	e680140, 3, (RF, RF, RF_IF), rd_rn_rm),
15712218822Sdim cCL(powez,	e680160, 3, (RF, RF, RF_IF), rd_rn_rm),
15713218822Sdim
15714218822Sdim cCL(rpws,	e700100, 3, (RF, RF, RF_IF), rd_rn_rm),
15715218822Sdim cCL(rpwsp,	e700120, 3, (RF, RF, RF_IF), rd_rn_rm),
15716218822Sdim cCL(rpwsm,	e700140, 3, (RF, RF, RF_IF), rd_rn_rm),
15717218822Sdim cCL(rpwsz,	e700160, 3, (RF, RF, RF_IF), rd_rn_rm),
15718218822Sdim cCL(rpwd,	e700180, 3, (RF, RF, RF_IF), rd_rn_rm),
15719218822Sdim cCL(rpwdp,	e7001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15720218822Sdim cCL(rpwdm,	e7001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15721218822Sdim cCL(rpwdz,	e7001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15722218822Sdim cCL(rpwe,	e780100, 3, (RF, RF, RF_IF), rd_rn_rm),
15723218822Sdim cCL(rpwep,	e780120, 3, (RF, RF, RF_IF), rd_rn_rm),
15724218822Sdim cCL(rpwem,	e780140, 3, (RF, RF, RF_IF), rd_rn_rm),
15725218822Sdim cCL(rpwez,	e780160, 3, (RF, RF, RF_IF), rd_rn_rm),
15726218822Sdim
15727218822Sdim cCL(rmfs,	e800100, 3, (RF, RF, RF_IF), rd_rn_rm),
15728218822Sdim cCL(rmfsp,	e800120, 3, (RF, RF, RF_IF), rd_rn_rm),
15729218822Sdim cCL(rmfsm,	e800140, 3, (RF, RF, RF_IF), rd_rn_rm),
15730218822Sdim cCL(rmfsz,	e800160, 3, (RF, RF, RF_IF), rd_rn_rm),
15731218822Sdim cCL(rmfd,	e800180, 3, (RF, RF, RF_IF), rd_rn_rm),
15732218822Sdim cCL(rmfdp,	e8001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15733218822Sdim cCL(rmfdm,	e8001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15734218822Sdim cCL(rmfdz,	e8001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15735218822Sdim cCL(rmfe,	e880100, 3, (RF, RF, RF_IF), rd_rn_rm),
15736218822Sdim cCL(rmfep,	e880120, 3, (RF, RF, RF_IF), rd_rn_rm),
15737218822Sdim cCL(rmfem,	e880140, 3, (RF, RF, RF_IF), rd_rn_rm),
15738218822Sdim cCL(rmfez,	e880160, 3, (RF, RF, RF_IF), rd_rn_rm),
15739218822Sdim
15740218822Sdim cCL(fmls,	e900100, 3, (RF, RF, RF_IF), rd_rn_rm),
15741218822Sdim cCL(fmlsp,	e900120, 3, (RF, RF, RF_IF), rd_rn_rm),
15742218822Sdim cCL(fmlsm,	e900140, 3, (RF, RF, RF_IF), rd_rn_rm),
15743218822Sdim cCL(fmlsz,	e900160, 3, (RF, RF, RF_IF), rd_rn_rm),
15744218822Sdim cCL(fmld,	e900180, 3, (RF, RF, RF_IF), rd_rn_rm),
15745218822Sdim cCL(fmldp,	e9001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15746218822Sdim cCL(fmldm,	e9001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15747218822Sdim cCL(fmldz,	e9001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15748218822Sdim cCL(fmle,	e980100, 3, (RF, RF, RF_IF), rd_rn_rm),
15749218822Sdim cCL(fmlep,	e980120, 3, (RF, RF, RF_IF), rd_rn_rm),
15750218822Sdim cCL(fmlem,	e980140, 3, (RF, RF, RF_IF), rd_rn_rm),
15751218822Sdim cCL(fmlez,	e980160, 3, (RF, RF, RF_IF), rd_rn_rm),
15752218822Sdim
15753218822Sdim cCL(fdvs,	ea00100, 3, (RF, RF, RF_IF), rd_rn_rm),
15754218822Sdim cCL(fdvsp,	ea00120, 3, (RF, RF, RF_IF), rd_rn_rm),
15755218822Sdim cCL(fdvsm,	ea00140, 3, (RF, RF, RF_IF), rd_rn_rm),
15756218822Sdim cCL(fdvsz,	ea00160, 3, (RF, RF, RF_IF), rd_rn_rm),
15757218822Sdim cCL(fdvd,	ea00180, 3, (RF, RF, RF_IF), rd_rn_rm),
15758218822Sdim cCL(fdvdp,	ea001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15759218822Sdim cCL(fdvdm,	ea001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15760218822Sdim cCL(fdvdz,	ea001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15761218822Sdim cCL(fdve,	ea80100, 3, (RF, RF, RF_IF), rd_rn_rm),
15762218822Sdim cCL(fdvep,	ea80120, 3, (RF, RF, RF_IF), rd_rn_rm),
15763218822Sdim cCL(fdvem,	ea80140, 3, (RF, RF, RF_IF), rd_rn_rm),
15764218822Sdim cCL(fdvez,	ea80160, 3, (RF, RF, RF_IF), rd_rn_rm),
15765218822Sdim
15766218822Sdim cCL(frds,	eb00100, 3, (RF, RF, RF_IF), rd_rn_rm),
15767218822Sdim cCL(frdsp,	eb00120, 3, (RF, RF, RF_IF), rd_rn_rm),
15768218822Sdim cCL(frdsm,	eb00140, 3, (RF, RF, RF_IF), rd_rn_rm),
15769218822Sdim cCL(frdsz,	eb00160, 3, (RF, RF, RF_IF), rd_rn_rm),
15770218822Sdim cCL(frdd,	eb00180, 3, (RF, RF, RF_IF), rd_rn_rm),
15771218822Sdim cCL(frddp,	eb001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15772218822Sdim cCL(frddm,	eb001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15773218822Sdim cCL(frddz,	eb001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15774218822Sdim cCL(frde,	eb80100, 3, (RF, RF, RF_IF), rd_rn_rm),
15775218822Sdim cCL(frdep,	eb80120, 3, (RF, RF, RF_IF), rd_rn_rm),
15776218822Sdim cCL(frdem,	eb80140, 3, (RF, RF, RF_IF), rd_rn_rm),
15777218822Sdim cCL(frdez,	eb80160, 3, (RF, RF, RF_IF), rd_rn_rm),
15778218822Sdim
15779218822Sdim cCL(pols,	ec00100, 3, (RF, RF, RF_IF), rd_rn_rm),
15780218822Sdim cCL(polsp,	ec00120, 3, (RF, RF, RF_IF), rd_rn_rm),
15781218822Sdim cCL(polsm,	ec00140, 3, (RF, RF, RF_IF), rd_rn_rm),
15782218822Sdim cCL(polsz,	ec00160, 3, (RF, RF, RF_IF), rd_rn_rm),
15783218822Sdim cCL(pold,	ec00180, 3, (RF, RF, RF_IF), rd_rn_rm),
15784218822Sdim cCL(poldp,	ec001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15785218822Sdim cCL(poldm,	ec001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15786218822Sdim cCL(poldz,	ec001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15787218822Sdim cCL(pole,	ec80100, 3, (RF, RF, RF_IF), rd_rn_rm),
15788218822Sdim cCL(polep,	ec80120, 3, (RF, RF, RF_IF), rd_rn_rm),
15789218822Sdim cCL(polem,	ec80140, 3, (RF, RF, RF_IF), rd_rn_rm),
15790218822Sdim cCL(polez,	ec80160, 3, (RF, RF, RF_IF), rd_rn_rm),
15791218822Sdim
15792218822Sdim cCE(cmf,	e90f110, 2, (RF, RF_IF),     fpa_cmp),
15793218822Sdim C3E(cmfe,	ed0f110, 2, (RF, RF_IF),     fpa_cmp),
15794218822Sdim cCE(cnf,	eb0f110, 2, (RF, RF_IF),     fpa_cmp),
15795218822Sdim C3E(cnfe,	ef0f110, 2, (RF, RF_IF),     fpa_cmp),
15796218822Sdim
15797218822Sdim cCL(flts,	e000110, 2, (RF, RR),	     rn_rd),
15798218822Sdim cCL(fltsp,	e000130, 2, (RF, RR),	     rn_rd),
15799218822Sdim cCL(fltsm,	e000150, 2, (RF, RR),	     rn_rd),
15800218822Sdim cCL(fltsz,	e000170, 2, (RF, RR),	     rn_rd),
15801218822Sdim cCL(fltd,	e000190, 2, (RF, RR),	     rn_rd),
15802218822Sdim cCL(fltdp,	e0001b0, 2, (RF, RR),	     rn_rd),
15803218822Sdim cCL(fltdm,	e0001d0, 2, (RF, RR),	     rn_rd),
15804218822Sdim cCL(fltdz,	e0001f0, 2, (RF, RR),	     rn_rd),
15805218822Sdim cCL(flte,	e080110, 2, (RF, RR),	     rn_rd),
15806218822Sdim cCL(fltep,	e080130, 2, (RF, RR),	     rn_rd),
15807218822Sdim cCL(fltem,	e080150, 2, (RF, RR),	     rn_rd),
15808218822Sdim cCL(fltez,	e080170, 2, (RF, RR),	     rn_rd),
15809218822Sdim
15810218822Sdim  /* The implementation of the FIX instruction is broken on some
15811218822Sdim     assemblers, in that it accepts a precision specifier as well as a
15812218822Sdim     rounding specifier, despite the fact that this is meaningless.
15813218822Sdim     To be more compatible, we accept it as well, though of course it
15814218822Sdim     does not set any bits.  */
15815218822Sdim cCE(fix,	e100110, 2, (RR, RF),	     rd_rm),
15816218822Sdim cCL(fixp,	e100130, 2, (RR, RF),	     rd_rm),
15817218822Sdim cCL(fixm,	e100150, 2, (RR, RF),	     rd_rm),
15818218822Sdim cCL(fixz,	e100170, 2, (RR, RF),	     rd_rm),
15819218822Sdim cCL(fixsp,	e100130, 2, (RR, RF),	     rd_rm),
15820218822Sdim cCL(fixsm,	e100150, 2, (RR, RF),	     rd_rm),
15821218822Sdim cCL(fixsz,	e100170, 2, (RR, RF),	     rd_rm),
15822218822Sdim cCL(fixdp,	e100130, 2, (RR, RF),	     rd_rm),
15823218822Sdim cCL(fixdm,	e100150, 2, (RR, RF),	     rd_rm),
15824218822Sdim cCL(fixdz,	e100170, 2, (RR, RF),	     rd_rm),
15825218822Sdim cCL(fixep,	e100130, 2, (RR, RF),	     rd_rm),
15826218822Sdim cCL(fixem,	e100150, 2, (RR, RF),	     rd_rm),
15827218822Sdim cCL(fixez,	e100170, 2, (RR, RF),	     rd_rm),
15828218822Sdim
15829218822Sdim  /* Instructions that were new with the real FPA, call them V2.  */
15830218822Sdim#undef ARM_VARIANT
15831218822Sdim#define ARM_VARIANT &fpu_fpa_ext_v2
15832218822Sdim cCE(lfm,	c100200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15833218822Sdim cCL(lfmfd,	c900200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15834218822Sdim cCL(lfmea,	d100200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15835218822Sdim cCE(sfm,	c000200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15836218822Sdim cCL(sfmfd,	d000200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15837218822Sdim cCL(sfmea,	c800200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15838218822Sdim
15839218822Sdim#undef ARM_VARIANT
15840218822Sdim#define ARM_VARIANT &fpu_vfp_ext_v1xd  /* VFP V1xD (single precision).  */
15841218822Sdim  /* Moves and type conversions.  */
15842218822Sdim cCE(fcpys,	eb00a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15843218822Sdim cCE(fmrs,	e100a10, 2, (RR, RVS),	      vfp_reg_from_sp),
15844218822Sdim cCE(fmsr,	e000a10, 2, (RVS, RR),	      vfp_sp_from_reg),
15845218822Sdim cCE(fmstat,	ef1fa10, 0, (),		      noargs),
15846218822Sdim cCE(fsitos,	eb80ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15847218822Sdim cCE(fuitos,	eb80a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15848218822Sdim cCE(ftosis,	ebd0a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15849218822Sdim cCE(ftosizs,	ebd0ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15850218822Sdim cCE(ftouis,	ebc0a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15851218822Sdim cCE(ftouizs,	ebc0ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15852218822Sdim cCE(fmrx,	ef00a10, 2, (RR, RVC),	      rd_rn),
15853218822Sdim cCE(fmxr,	ee00a10, 2, (RVC, RR),	      rn_rd),
15854248460Sandrew cCE(vmrs,	ef00a10, 2, (APSR_RR, RVC),   vfp_vmrs),
15855248460Sandrew cCE(vmsr,	ee00a10, 2, (RVC, RR),        vfp_vmsr),
15856218822Sdim
15857218822Sdim  /* Memory operations.	 */
15858218822Sdim cCE(flds,	d100a00, 2, (RVS, ADDRGLDC),  vfp_sp_ldst),
15859218822Sdim cCE(fsts,	d000a00, 2, (RVS, ADDRGLDC),  vfp_sp_ldst),
15860218822Sdim cCE(fldmias,	c900a00, 2, (RRw, VRSLST),    vfp_sp_ldstmia),
15861218822Sdim cCE(fldmfds,	c900a00, 2, (RRw, VRSLST),    vfp_sp_ldstmia),
15862218822Sdim cCE(fldmdbs,	d300a00, 2, (RRw, VRSLST),    vfp_sp_ldstmdb),
15863218822Sdim cCE(fldmeas,	d300a00, 2, (RRw, VRSLST),    vfp_sp_ldstmdb),
15864218822Sdim cCE(fldmiax,	c900b00, 2, (RRw, VRDLST),    vfp_xp_ldstmia),
15865218822Sdim cCE(fldmfdx,	c900b00, 2, (RRw, VRDLST),    vfp_xp_ldstmia),
15866218822Sdim cCE(fldmdbx,	d300b00, 2, (RRw, VRDLST),    vfp_xp_ldstmdb),
15867218822Sdim cCE(fldmeax,	d300b00, 2, (RRw, VRDLST),    vfp_xp_ldstmdb),
15868218822Sdim cCE(fstmias,	c800a00, 2, (RRw, VRSLST),    vfp_sp_ldstmia),
15869218822Sdim cCE(fstmeas,	c800a00, 2, (RRw, VRSLST),    vfp_sp_ldstmia),
15870218822Sdim cCE(fstmdbs,	d200a00, 2, (RRw, VRSLST),    vfp_sp_ldstmdb),
15871218822Sdim cCE(fstmfds,	d200a00, 2, (RRw, VRSLST),    vfp_sp_ldstmdb),
15872218822Sdim cCE(fstmiax,	c800b00, 2, (RRw, VRDLST),    vfp_xp_ldstmia),
15873218822Sdim cCE(fstmeax,	c800b00, 2, (RRw, VRDLST),    vfp_xp_ldstmia),
15874218822Sdim cCE(fstmdbx,	d200b00, 2, (RRw, VRDLST),    vfp_xp_ldstmdb),
15875218822Sdim cCE(fstmfdx,	d200b00, 2, (RRw, VRDLST),    vfp_xp_ldstmdb),
15876218822Sdim
15877218822Sdim  /* Monadic operations.  */
15878218822Sdim cCE(fabss,	eb00ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15879218822Sdim cCE(fnegs,	eb10a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15880218822Sdim cCE(fsqrts,	eb10ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15881218822Sdim
15882218822Sdim  /* Dyadic operations.	 */
15883218822Sdim cCE(fadds,	e300a00, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15884218822Sdim cCE(fsubs,	e300a40, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15885218822Sdim cCE(fmuls,	e200a00, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15886218822Sdim cCE(fdivs,	e800a00, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15887218822Sdim cCE(fmacs,	e000a00, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15888218822Sdim cCE(fmscs,	e100a00, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15889218822Sdim cCE(fnmuls,	e200a40, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15890218822Sdim cCE(fnmacs,	e000a40, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15891218822Sdim cCE(fnmscs,	e100a40, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15892218822Sdim
15893218822Sdim  /* Comparisons.  */
15894218822Sdim cCE(fcmps,	eb40a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15895218822Sdim cCE(fcmpzs,	eb50a40, 1, (RVS),	      vfp_sp_compare_z),
15896218822Sdim cCE(fcmpes,	eb40ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15897218822Sdim cCE(fcmpezs,	eb50ac0, 1, (RVS),	      vfp_sp_compare_z),
15898218822Sdim
15899218822Sdim#undef ARM_VARIANT
15900218822Sdim#define ARM_VARIANT &fpu_vfp_ext_v1 /* VFP V1 (Double precision).  */
15901218822Sdim  /* Moves and type conversions.  */
15902218822Sdim cCE(fcpyd,	eb00b40, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15903218822Sdim cCE(fcvtds,	eb70ac0, 2, (RVD, RVS),	      vfp_dp_sp_cvt),
15904218822Sdim cCE(fcvtsd,	eb70bc0, 2, (RVS, RVD),	      vfp_sp_dp_cvt),
15905218822Sdim cCE(fmdhr,	e200b10, 2, (RVD, RR),	      vfp_dp_rn_rd),
15906218822Sdim cCE(fmdlr,	e000b10, 2, (RVD, RR),	      vfp_dp_rn_rd),
15907218822Sdim cCE(fmrdh,	e300b10, 2, (RR, RVD),	      vfp_dp_rd_rn),
15908218822Sdim cCE(fmrdl,	e100b10, 2, (RR, RVD),	      vfp_dp_rd_rn),
15909218822Sdim cCE(fsitod,	eb80bc0, 2, (RVD, RVS),	      vfp_dp_sp_cvt),
15910218822Sdim cCE(fuitod,	eb80b40, 2, (RVD, RVS),	      vfp_dp_sp_cvt),
15911218822Sdim cCE(ftosid,	ebd0b40, 2, (RVS, RVD),	      vfp_sp_dp_cvt),
15912218822Sdim cCE(ftosizd,	ebd0bc0, 2, (RVS, RVD),	      vfp_sp_dp_cvt),
15913218822Sdim cCE(ftouid,	ebc0b40, 2, (RVS, RVD),	      vfp_sp_dp_cvt),
15914218822Sdim cCE(ftouizd,	ebc0bc0, 2, (RVS, RVD),	      vfp_sp_dp_cvt),
15915218822Sdim
15916218822Sdim  /* Memory operations.	 */
15917218822Sdim cCE(fldd,	d100b00, 2, (RVD, ADDRGLDC),  vfp_dp_ldst),
15918218822Sdim cCE(fstd,	d000b00, 2, (RVD, ADDRGLDC),  vfp_dp_ldst),
15919218822Sdim cCE(fldmiad,	c900b00, 2, (RRw, VRDLST),    vfp_dp_ldstmia),
15920218822Sdim cCE(fldmfdd,	c900b00, 2, (RRw, VRDLST),    vfp_dp_ldstmia),
15921218822Sdim cCE(fldmdbd,	d300b00, 2, (RRw, VRDLST),    vfp_dp_ldstmdb),
15922218822Sdim cCE(fldmead,	d300b00, 2, (RRw, VRDLST),    vfp_dp_ldstmdb),
15923218822Sdim cCE(fstmiad,	c800b00, 2, (RRw, VRDLST),    vfp_dp_ldstmia),
15924218822Sdim cCE(fstmead,	c800b00, 2, (RRw, VRDLST),    vfp_dp_ldstmia),
15925218822Sdim cCE(fstmdbd,	d200b00, 2, (RRw, VRDLST),    vfp_dp_ldstmdb),
15926218822Sdim cCE(fstmfdd,	d200b00, 2, (RRw, VRDLST),    vfp_dp_ldstmdb),
15927218822Sdim
15928218822Sdim  /* Monadic operations.  */
15929218822Sdim cCE(fabsd,	eb00bc0, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15930218822Sdim cCE(fnegd,	eb10b40, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15931218822Sdim cCE(fsqrtd,	eb10bc0, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15932218822Sdim
15933218822Sdim  /* Dyadic operations.	 */
15934218822Sdim cCE(faddd,	e300b00, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15935218822Sdim cCE(fsubd,	e300b40, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15936218822Sdim cCE(fmuld,	e200b00, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15937218822Sdim cCE(fdivd,	e800b00, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15938218822Sdim cCE(fmacd,	e000b00, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15939218822Sdim cCE(fmscd,	e100b00, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15940218822Sdim cCE(fnmuld,	e200b40, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15941218822Sdim cCE(fnmacd,	e000b40, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15942218822Sdim cCE(fnmscd,	e100b40, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15943218822Sdim
15944218822Sdim  /* Comparisons.  */
15945218822Sdim cCE(fcmpd,	eb40b40, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15946218822Sdim cCE(fcmpzd,	eb50b40, 1, (RVD),	      vfp_dp_rd),
15947218822Sdim cCE(fcmped,	eb40bc0, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15948218822Sdim cCE(fcmpezd,	eb50bc0, 1, (RVD),	      vfp_dp_rd),
15949218822Sdim
15950218822Sdim#undef ARM_VARIANT
15951218822Sdim#define ARM_VARIANT &fpu_vfp_ext_v2
15952218822Sdim cCE(fmsrr,	c400a10, 3, (VRSLST, RR, RR), vfp_sp2_from_reg2),
15953218822Sdim cCE(fmrrs,	c500a10, 3, (RR, RR, VRSLST), vfp_reg2_from_sp2),
15954218822Sdim cCE(fmdrr,	c400b10, 3, (RVD, RR, RR),    vfp_dp_rm_rd_rn),
15955218822Sdim cCE(fmrrd,	c500b10, 3, (RR, RR, RVD),    vfp_dp_rd_rn_rm),
15956218822Sdim
15957218822Sdim/* Instructions which may belong to either the Neon or VFP instruction sets.
15958218822Sdim   Individual encoder functions perform additional architecture checks.  */
15959218822Sdim#undef ARM_VARIANT
15960218822Sdim#define ARM_VARIANT &fpu_vfp_ext_v1xd
15961218822Sdim#undef THUMB_VARIANT
15962218822Sdim#define THUMB_VARIANT &fpu_vfp_ext_v1xd
15963218822Sdim  /* These mnemonics are unique to VFP.  */
15964218822Sdim NCE(vsqrt,     0,       2, (RVSD, RVSD),       vfp_nsyn_sqrt),
15965218822Sdim NCE(vdiv,      0,       3, (RVSD, RVSD, RVSD), vfp_nsyn_div),
15966218822Sdim nCE(vnmul,     vnmul,   3, (RVSD, RVSD, RVSD), vfp_nsyn_nmul),
15967218822Sdim nCE(vnmla,     vnmla,   3, (RVSD, RVSD, RVSD), vfp_nsyn_nmul),
15968218822Sdim nCE(vnmls,     vnmls,   3, (RVSD, RVSD, RVSD), vfp_nsyn_nmul),
15969218822Sdim nCE(vcmp,      vcmp,    2, (RVSD, RVSD_I0),    vfp_nsyn_cmp),
15970218822Sdim nCE(vcmpe,     vcmpe,   2, (RVSD, RVSD_I0),    vfp_nsyn_cmp),
15971218822Sdim NCE(vpush,     0,       1, (VRSDLST),          vfp_nsyn_push),
15972218822Sdim NCE(vpop,      0,       1, (VRSDLST),          vfp_nsyn_pop),
15973218822Sdim NCE(vcvtz,     0,       2, (RVSD, RVSD),       vfp_nsyn_cvtz),
15974218822Sdim
15975218822Sdim  /* Mnemonics shared by Neon and VFP.  */
15976218822Sdim nCEF(vmul,     vmul,    3, (RNSDQ, oRNSDQ, RNSDQ_RNSC), neon_mul),
15977218822Sdim nCEF(vmla,     vmla,    3, (RNSDQ, oRNSDQ, RNSDQ_RNSC), neon_mac_maybe_scalar),
15978218822Sdim nCEF(vmls,     vmls,    3, (RNSDQ, oRNSDQ, RNSDQ_RNSC), neon_mac_maybe_scalar),
15979218822Sdim
15980218822Sdim nCEF(vadd,     vadd,    3, (RNSDQ, oRNSDQ, RNSDQ), neon_addsub_if_i),
15981218822Sdim nCEF(vsub,     vsub,    3, (RNSDQ, oRNSDQ, RNSDQ), neon_addsub_if_i),
15982218822Sdim
15983218822Sdim NCEF(vabs,     1b10300, 2, (RNSDQ, RNSDQ), neon_abs_neg),
15984218822Sdim NCEF(vneg,     1b10380, 2, (RNSDQ, RNSDQ), neon_abs_neg),
15985218822Sdim
15986218822Sdim NCE(vldm,      c900b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15987218822Sdim NCE(vldmia,    c900b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15988218822Sdim NCE(vldmdb,    d100b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15989218822Sdim NCE(vstm,      c800b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15990218822Sdim NCE(vstmia,    c800b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15991218822Sdim NCE(vstmdb,    d000b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15992218822Sdim NCE(vldr,      d100b00, 2, (RVSD, ADDRGLDC), neon_ldr_str),
15993218822Sdim NCE(vstr,      d000b00, 2, (RVSD, ADDRGLDC), neon_ldr_str),
15994218822Sdim
15995218822Sdim nCEF(vcvt,     vcvt,    3, (RNSDQ, RNSDQ, oI32b), neon_cvt),
15996218822Sdim
15997218822Sdim  /* NOTE: All VMOV encoding is special-cased!  */
15998218822Sdim NCE(vmov,      0,       1, (VMOV), neon_mov),
15999218822Sdim NCE(vmovq,     0,       1, (VMOV), neon_mov),
16000218822Sdim
16001218822Sdim#undef THUMB_VARIANT
16002218822Sdim#define THUMB_VARIANT &fpu_neon_ext_v1
16003218822Sdim#undef ARM_VARIANT
16004218822Sdim#define ARM_VARIANT &fpu_neon_ext_v1
16005218822Sdim  /* Data processing with three registers of the same length.  */
16006218822Sdim  /* integer ops, valid types S8 S16 S32 U8 U16 U32.  */
16007218822Sdim NUF(vaba,      0000710, 3, (RNDQ, RNDQ,  RNDQ), neon_dyadic_i_su),
16008218822Sdim NUF(vabaq,     0000710, 3, (RNQ,  RNQ,   RNQ),  neon_dyadic_i_su),
16009218822Sdim NUF(vhadd,     0000000, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i_su),
16010218822Sdim NUF(vhaddq,    0000000, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i_su),
16011218822Sdim NUF(vrhadd,    0000100, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i_su),
16012218822Sdim NUF(vrhaddq,   0000100, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i_su),
16013218822Sdim NUF(vhsub,     0000200, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i_su),
16014218822Sdim NUF(vhsubq,    0000200, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i_su),
16015218822Sdim  /* integer ops, valid types S8 S16 S32 S64 U8 U16 U32 U64.  */
16016218822Sdim NUF(vqadd,     0000010, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i64_su),
16017218822Sdim NUF(vqaddq,    0000010, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i64_su),
16018218822Sdim NUF(vqsub,     0000210, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i64_su),
16019218822Sdim NUF(vqsubq,    0000210, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i64_su),
16020218822Sdim NUF(vrshl,     0000500, 3, (RNDQ, oRNDQ, RNDQ), neon_rshl),
16021218822Sdim NUF(vrshlq,    0000500, 3, (RNQ,  oRNQ,  RNQ),  neon_rshl),
16022218822Sdim NUF(vqrshl,    0000510, 3, (RNDQ, oRNDQ, RNDQ), neon_rshl),
16023218822Sdim NUF(vqrshlq,   0000510, 3, (RNQ,  oRNQ,  RNQ),  neon_rshl),
16024218822Sdim  /* If not immediate, fall back to neon_dyadic_i64_su.
16025218822Sdim     shl_imm should accept I8 I16 I32 I64,
16026218822Sdim     qshl_imm should accept S8 S16 S32 S64 U8 U16 U32 U64.  */
16027218822Sdim nUF(vshl,      vshl,    3, (RNDQ, oRNDQ, RNDQ_I63b), neon_shl_imm),
16028218822Sdim nUF(vshlq,     vshl,    3, (RNQ,  oRNQ,  RNDQ_I63b), neon_shl_imm),
16029218822Sdim nUF(vqshl,     vqshl,   3, (RNDQ, oRNDQ, RNDQ_I63b), neon_qshl_imm),
16030218822Sdim nUF(vqshlq,    vqshl,   3, (RNQ,  oRNQ,  RNDQ_I63b), neon_qshl_imm),
16031218822Sdim  /* Logic ops, types optional & ignored.  */
16032218822Sdim nUF(vand,      vand,    2, (RNDQ, NILO),        neon_logic),
16033218822Sdim nUF(vandq,     vand,    2, (RNQ,  NILO),        neon_logic),
16034218822Sdim nUF(vbic,      vbic,    2, (RNDQ, NILO),        neon_logic),
16035218822Sdim nUF(vbicq,     vbic,    2, (RNQ,  NILO),        neon_logic),
16036218822Sdim nUF(vorr,      vorr,    2, (RNDQ, NILO),        neon_logic),
16037218822Sdim nUF(vorrq,     vorr,    2, (RNQ,  NILO),        neon_logic),
16038218822Sdim nUF(vorn,      vorn,    2, (RNDQ, NILO),        neon_logic),
16039218822Sdim nUF(vornq,     vorn,    2, (RNQ,  NILO),        neon_logic),
16040218822Sdim nUF(veor,      veor,    3, (RNDQ, oRNDQ, RNDQ), neon_logic),
16041218822Sdim nUF(veorq,     veor,    3, (RNQ,  oRNQ,  RNQ),  neon_logic),
16042218822Sdim  /* Bitfield ops, untyped.  */
16043218822Sdim NUF(vbsl,      1100110, 3, (RNDQ, RNDQ, RNDQ), neon_bitfield),
16044218822Sdim NUF(vbslq,     1100110, 3, (RNQ,  RNQ,  RNQ),  neon_bitfield),
16045218822Sdim NUF(vbit,      1200110, 3, (RNDQ, RNDQ, RNDQ), neon_bitfield),
16046218822Sdim NUF(vbitq,     1200110, 3, (RNQ,  RNQ,  RNQ),  neon_bitfield),
16047218822Sdim NUF(vbif,      1300110, 3, (RNDQ, RNDQ, RNDQ), neon_bitfield),
16048218822Sdim NUF(vbifq,     1300110, 3, (RNQ,  RNQ,  RNQ),  neon_bitfield),
16049218822Sdim  /* Int and float variants, types S8 S16 S32 U8 U16 U32 F32.  */
16050218822Sdim nUF(vabd,      vabd,    3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_if_su),
16051218822Sdim nUF(vabdq,     vabd,    3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_if_su),
16052218822Sdim nUF(vmax,      vmax,    3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_if_su),
16053218822Sdim nUF(vmaxq,     vmax,    3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_if_su),
16054218822Sdim nUF(vmin,      vmin,    3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_if_su),
16055218822Sdim nUF(vminq,     vmin,    3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_if_su),
16056218822Sdim  /* Comparisons. Types S8 S16 S32 U8 U16 U32 F32. Non-immediate versions fall
16057218822Sdim     back to neon_dyadic_if_su.  */
16058218822Sdim nUF(vcge,      vcge,    3, (RNDQ, oRNDQ, RNDQ_I0), neon_cmp),
16059218822Sdim nUF(vcgeq,     vcge,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_cmp),
16060218822Sdim nUF(vcgt,      vcgt,    3, (RNDQ, oRNDQ, RNDQ_I0), neon_cmp),
16061218822Sdim nUF(vcgtq,     vcgt,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_cmp),
16062218822Sdim nUF(vclt,      vclt,    3, (RNDQ, oRNDQ, RNDQ_I0), neon_cmp_inv),
16063218822Sdim nUF(vcltq,     vclt,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_cmp_inv),
16064218822Sdim nUF(vcle,      vcle,    3, (RNDQ, oRNDQ, RNDQ_I0), neon_cmp_inv),
16065218822Sdim nUF(vcleq,     vcle,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_cmp_inv),
16066218822Sdim  /* Comparison. Type I8 I16 I32 F32.  */
16067218822Sdim nUF(vceq,      vceq,    3, (RNDQ, oRNDQ, RNDQ_I0), neon_ceq),
16068218822Sdim nUF(vceqq,     vceq,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_ceq),
16069218822Sdim  /* As above, D registers only.  */
16070218822Sdim nUF(vpmax,     vpmax,   3, (RND, oRND, RND), neon_dyadic_if_su_d),
16071218822Sdim nUF(vpmin,     vpmin,   3, (RND, oRND, RND), neon_dyadic_if_su_d),
16072218822Sdim  /* Int and float variants, signedness unimportant.  */
16073218822Sdim nUF(vmlaq,     vmla,    3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_mac_maybe_scalar),
16074218822Sdim nUF(vmlsq,     vmls,    3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_mac_maybe_scalar),
16075218822Sdim nUF(vpadd,     vpadd,   3, (RND,  oRND,  RND),       neon_dyadic_if_i_d),
16076218822Sdim  /* Add/sub take types I8 I16 I32 I64 F32.  */
16077218822Sdim nUF(vaddq,     vadd,    3, (RNQ,  oRNQ,  RNQ),  neon_addsub_if_i),
16078218822Sdim nUF(vsubq,     vsub,    3, (RNQ,  oRNQ,  RNQ),  neon_addsub_if_i),
16079218822Sdim  /* vtst takes sizes 8, 16, 32.  */
16080218822Sdim NUF(vtst,      0000810, 3, (RNDQ, oRNDQ, RNDQ), neon_tst),
16081218822Sdim NUF(vtstq,     0000810, 3, (RNQ,  oRNQ,  RNQ),  neon_tst),
16082218822Sdim  /* VMUL takes I8 I16 I32 F32 P8.  */
16083218822Sdim nUF(vmulq,     vmul,     3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_mul),
16084218822Sdim  /* VQD{R}MULH takes S16 S32.  */
16085218822Sdim nUF(vqdmulh,   vqdmulh,  3, (RNDQ, oRNDQ, RNDQ_RNSC), neon_qdmulh),
16086218822Sdim nUF(vqdmulhq,  vqdmulh,  3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_qdmulh),
16087218822Sdim nUF(vqrdmulh,  vqrdmulh, 3, (RNDQ, oRNDQ, RNDQ_RNSC), neon_qdmulh),
16088218822Sdim nUF(vqrdmulhq, vqrdmulh, 3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_qdmulh),
16089218822Sdim NUF(vacge,     0000e10,  3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute),
16090218822Sdim NUF(vacgeq,    0000e10,  3, (RNQ,  oRNQ,  RNQ),  neon_fcmp_absolute),
16091218822Sdim NUF(vacgt,     0200e10,  3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute),
16092218822Sdim NUF(vacgtq,    0200e10,  3, (RNQ,  oRNQ,  RNQ),  neon_fcmp_absolute),
16093218822Sdim NUF(vaclt,     0200e10,  3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute_inv),
16094218822Sdim NUF(vacltq,    0200e10,  3, (RNQ,  oRNQ,  RNQ),  neon_fcmp_absolute_inv),
16095218822Sdim NUF(vacle,     0000e10,  3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute_inv),
16096218822Sdim NUF(vacleq,    0000e10,  3, (RNQ,  oRNQ,  RNQ),  neon_fcmp_absolute_inv),
16097218822Sdim NUF(vrecps,    0000f10,  3, (RNDQ, oRNDQ, RNDQ), neon_step),
16098218822Sdim NUF(vrecpsq,   0000f10,  3, (RNQ,  oRNQ,  RNQ),  neon_step),
16099218822Sdim NUF(vrsqrts,   0200f10,  3, (RNDQ, oRNDQ, RNDQ), neon_step),
16100218822Sdim NUF(vrsqrtsq,  0200f10,  3, (RNQ,  oRNQ,  RNQ),  neon_step),
16101218822Sdim
16102218822Sdim  /* Two address, int/float. Types S8 S16 S32 F32.  */
16103218822Sdim NUF(vabsq,     1b10300, 2, (RNQ,  RNQ),      neon_abs_neg),
16104218822Sdim NUF(vnegq,     1b10380, 2, (RNQ,  RNQ),      neon_abs_neg),
16105218822Sdim
16106218822Sdim  /* Data processing with two registers and a shift amount.  */
16107218822Sdim  /* Right shifts, and variants with rounding.
16108218822Sdim     Types accepted S8 S16 S32 S64 U8 U16 U32 U64.  */
16109218822Sdim NUF(vshr,      0800010, 3, (RNDQ, oRNDQ, I64z), neon_rshift_round_imm),
16110218822Sdim NUF(vshrq,     0800010, 3, (RNQ,  oRNQ,  I64z), neon_rshift_round_imm),
16111218822Sdim NUF(vrshr,     0800210, 3, (RNDQ, oRNDQ, I64z), neon_rshift_round_imm),
16112218822Sdim NUF(vrshrq,    0800210, 3, (RNQ,  oRNQ,  I64z), neon_rshift_round_imm),
16113218822Sdim NUF(vsra,      0800110, 3, (RNDQ, oRNDQ, I64),  neon_rshift_round_imm),
16114218822Sdim NUF(vsraq,     0800110, 3, (RNQ,  oRNQ,  I64),  neon_rshift_round_imm),
16115218822Sdim NUF(vrsra,     0800310, 3, (RNDQ, oRNDQ, I64),  neon_rshift_round_imm),
16116218822Sdim NUF(vrsraq,    0800310, 3, (RNQ,  oRNQ,  I64),  neon_rshift_round_imm),
16117218822Sdim  /* Shift and insert. Sizes accepted 8 16 32 64.  */
16118218822Sdim NUF(vsli,      1800510, 3, (RNDQ, oRNDQ, I63), neon_sli),
16119218822Sdim NUF(vsliq,     1800510, 3, (RNQ,  oRNQ,  I63), neon_sli),
16120218822Sdim NUF(vsri,      1800410, 3, (RNDQ, oRNDQ, I64), neon_sri),
16121218822Sdim NUF(vsriq,     1800410, 3, (RNQ,  oRNQ,  I64), neon_sri),
16122218822Sdim  /* QSHL{U} immediate accepts S8 S16 S32 S64 U8 U16 U32 U64.  */
16123218822Sdim NUF(vqshlu,    1800610, 3, (RNDQ, oRNDQ, I63), neon_qshlu_imm),
16124218822Sdim NUF(vqshluq,   1800610, 3, (RNQ,  oRNQ,  I63), neon_qshlu_imm),
16125218822Sdim  /* Right shift immediate, saturating & narrowing, with rounding variants.
16126218822Sdim     Types accepted S16 S32 S64 U16 U32 U64.  */
16127218822Sdim NUF(vqshrn,    0800910, 3, (RND, RNQ, I32z), neon_rshift_sat_narrow),
16128218822Sdim NUF(vqrshrn,   0800950, 3, (RND, RNQ, I32z), neon_rshift_sat_narrow),
16129218822Sdim  /* As above, unsigned. Types accepted S16 S32 S64.  */
16130218822Sdim NUF(vqshrun,   0800810, 3, (RND, RNQ, I32z), neon_rshift_sat_narrow_u),
16131218822Sdim NUF(vqrshrun,  0800850, 3, (RND, RNQ, I32z), neon_rshift_sat_narrow_u),
16132218822Sdim  /* Right shift narrowing. Types accepted I16 I32 I64.  */
16133218822Sdim NUF(vshrn,     0800810, 3, (RND, RNQ, I32z), neon_rshift_narrow),
16134218822Sdim NUF(vrshrn,    0800850, 3, (RND, RNQ, I32z), neon_rshift_narrow),
16135218822Sdim  /* Special case. Types S8 S16 S32 U8 U16 U32. Handles max shift variant.  */
16136218822Sdim nUF(vshll,     vshll,   3, (RNQ, RND, I32),  neon_shll),
16137218822Sdim  /* CVT with optional immediate for fixed-point variant.  */
16138218822Sdim nUF(vcvtq,     vcvt,    3, (RNQ, RNQ, oI32b), neon_cvt),
16139218822Sdim
16140218822Sdim nUF(vmvn,      vmvn,    2, (RNDQ, RNDQ_IMVNb), neon_mvn),
16141218822Sdim nUF(vmvnq,     vmvn,    2, (RNQ,  RNDQ_IMVNb), neon_mvn),
16142218822Sdim
16143218822Sdim  /* Data processing, three registers of different lengths.  */
16144218822Sdim  /* Dyadic, long insns. Types S8 S16 S32 U8 U16 U32.  */
16145218822Sdim NUF(vabal,     0800500, 3, (RNQ, RND, RND),  neon_abal),
16146218822Sdim NUF(vabdl,     0800700, 3, (RNQ, RND, RND),  neon_dyadic_long),
16147218822Sdim NUF(vaddl,     0800000, 3, (RNQ, RND, RND),  neon_dyadic_long),
16148218822Sdim NUF(vsubl,     0800200, 3, (RNQ, RND, RND),  neon_dyadic_long),
16149218822Sdim  /* If not scalar, fall back to neon_dyadic_long.
16150218822Sdim     Vector types as above, scalar types S16 S32 U16 U32.  */
16151218822Sdim nUF(vmlal,     vmlal,   3, (RNQ, RND, RND_RNSC), neon_mac_maybe_scalar_long),
16152218822Sdim nUF(vmlsl,     vmlsl,   3, (RNQ, RND, RND_RNSC), neon_mac_maybe_scalar_long),
16153218822Sdim  /* Dyadic, widening insns. Types S8 S16 S32 U8 U16 U32.  */
16154218822Sdim NUF(vaddw,     0800100, 3, (RNQ, oRNQ, RND), neon_dyadic_wide),
16155218822Sdim NUF(vsubw,     0800300, 3, (RNQ, oRNQ, RND), neon_dyadic_wide),
16156218822Sdim  /* Dyadic, narrowing insns. Types I16 I32 I64.  */
16157218822Sdim NUF(vaddhn,    0800400, 3, (RND, RNQ, RNQ),  neon_dyadic_narrow),
16158218822Sdim NUF(vraddhn,   1800400, 3, (RND, RNQ, RNQ),  neon_dyadic_narrow),
16159218822Sdim NUF(vsubhn,    0800600, 3, (RND, RNQ, RNQ),  neon_dyadic_narrow),
16160218822Sdim NUF(vrsubhn,   1800600, 3, (RND, RNQ, RNQ),  neon_dyadic_narrow),
16161218822Sdim  /* Saturating doubling multiplies. Types S16 S32.  */
16162218822Sdim nUF(vqdmlal,   vqdmlal, 3, (RNQ, RND, RND_RNSC), neon_mul_sat_scalar_long),
16163218822Sdim nUF(vqdmlsl,   vqdmlsl, 3, (RNQ, RND, RND_RNSC), neon_mul_sat_scalar_long),
16164218822Sdim nUF(vqdmull,   vqdmull, 3, (RNQ, RND, RND_RNSC), neon_mul_sat_scalar_long),
16165218822Sdim  /* VMULL. Vector types S8 S16 S32 U8 U16 U32 P8, scalar types
16166218822Sdim     S16 S32 U16 U32.  */
16167218822Sdim nUF(vmull,     vmull,   3, (RNQ, RND, RND_RNSC), neon_vmull),
16168218822Sdim
16169218822Sdim  /* Extract. Size 8.  */
16170218822Sdim NUF(vext,      0b00000, 4, (RNDQ, oRNDQ, RNDQ, I15), neon_ext),
16171218822Sdim NUF(vextq,     0b00000, 4, (RNQ,  oRNQ,  RNQ,  I15), neon_ext),
16172218822Sdim
16173218822Sdim  /* Two registers, miscellaneous.  */
16174218822Sdim  /* Reverse. Sizes 8 16 32 (must be < size in opcode).  */
16175218822Sdim NUF(vrev64,    1b00000, 2, (RNDQ, RNDQ),     neon_rev),
16176218822Sdim NUF(vrev64q,   1b00000, 2, (RNQ,  RNQ),      neon_rev),
16177218822Sdim NUF(vrev32,    1b00080, 2, (RNDQ, RNDQ),     neon_rev),
16178218822Sdim NUF(vrev32q,   1b00080, 2, (RNQ,  RNQ),      neon_rev),
16179218822Sdim NUF(vrev16,    1b00100, 2, (RNDQ, RNDQ),     neon_rev),
16180218822Sdim NUF(vrev16q,   1b00100, 2, (RNQ,  RNQ),      neon_rev),
16181218822Sdim  /* Vector replicate. Sizes 8 16 32.  */
16182218822Sdim nCE(vdup,      vdup,    2, (RNDQ, RR_RNSC),  neon_dup),
16183218822Sdim nCE(vdupq,     vdup,    2, (RNQ,  RR_RNSC),  neon_dup),
16184218822Sdim  /* VMOVL. Types S8 S16 S32 U8 U16 U32.  */
16185218822Sdim NUF(vmovl,     0800a10, 2, (RNQ, RND),       neon_movl),
16186218822Sdim  /* VMOVN. Types I16 I32 I64.  */
16187218822Sdim nUF(vmovn,     vmovn,   2, (RND, RNQ),       neon_movn),
16188218822Sdim  /* VQMOVN. Types S16 S32 S64 U16 U32 U64.  */
16189218822Sdim nUF(vqmovn,    vqmovn,  2, (RND, RNQ),       neon_qmovn),
16190218822Sdim  /* VQMOVUN. Types S16 S32 S64.  */
16191218822Sdim nUF(vqmovun,   vqmovun, 2, (RND, RNQ),       neon_qmovun),
16192218822Sdim  /* VZIP / VUZP. Sizes 8 16 32.  */
16193218822Sdim NUF(vzip,      1b20180, 2, (RNDQ, RNDQ),     neon_zip_uzp),
16194218822Sdim NUF(vzipq,     1b20180, 2, (RNQ,  RNQ),      neon_zip_uzp),
16195218822Sdim NUF(vuzp,      1b20100, 2, (RNDQ, RNDQ),     neon_zip_uzp),
16196218822Sdim NUF(vuzpq,     1b20100, 2, (RNQ,  RNQ),      neon_zip_uzp),
16197218822Sdim  /* VQABS / VQNEG. Types S8 S16 S32.  */
16198218822Sdim NUF(vqabs,     1b00700, 2, (RNDQ, RNDQ),     neon_sat_abs_neg),
16199218822Sdim NUF(vqabsq,    1b00700, 2, (RNQ,  RNQ),      neon_sat_abs_neg),
16200218822Sdim NUF(vqneg,     1b00780, 2, (RNDQ, RNDQ),     neon_sat_abs_neg),
16201218822Sdim NUF(vqnegq,    1b00780, 2, (RNQ,  RNQ),      neon_sat_abs_neg),
16202218822Sdim  /* Pairwise, lengthening. Types S8 S16 S32 U8 U16 U32.  */
16203218822Sdim NUF(vpadal,    1b00600, 2, (RNDQ, RNDQ),     neon_pair_long),
16204218822Sdim NUF(vpadalq,   1b00600, 2, (RNQ,  RNQ),      neon_pair_long),
16205218822Sdim NUF(vpaddl,    1b00200, 2, (RNDQ, RNDQ),     neon_pair_long),
16206218822Sdim NUF(vpaddlq,   1b00200, 2, (RNQ,  RNQ),      neon_pair_long),
16207218822Sdim  /* Reciprocal estimates. Types U32 F32.  */
16208218822Sdim NUF(vrecpe,    1b30400, 2, (RNDQ, RNDQ),     neon_recip_est),
16209218822Sdim NUF(vrecpeq,   1b30400, 2, (RNQ,  RNQ),      neon_recip_est),
16210218822Sdim NUF(vrsqrte,   1b30480, 2, (RNDQ, RNDQ),     neon_recip_est),
16211218822Sdim NUF(vrsqrteq,  1b30480, 2, (RNQ,  RNQ),      neon_recip_est),
16212218822Sdim  /* VCLS. Types S8 S16 S32.  */
16213218822Sdim NUF(vcls,      1b00400, 2, (RNDQ, RNDQ),     neon_cls),
16214218822Sdim NUF(vclsq,     1b00400, 2, (RNQ,  RNQ),      neon_cls),
16215218822Sdim  /* VCLZ. Types I8 I16 I32.  */
16216218822Sdim NUF(vclz,      1b00480, 2, (RNDQ, RNDQ),     neon_clz),
16217218822Sdim NUF(vclzq,     1b00480, 2, (RNQ,  RNQ),      neon_clz),
16218218822Sdim  /* VCNT. Size 8.  */
16219218822Sdim NUF(vcnt,      1b00500, 2, (RNDQ, RNDQ),     neon_cnt),
16220218822Sdim NUF(vcntq,     1b00500, 2, (RNQ,  RNQ),      neon_cnt),
16221218822Sdim  /* Two address, untyped.  */
16222218822Sdim NUF(vswp,      1b20000, 2, (RNDQ, RNDQ),     neon_swp),
16223218822Sdim NUF(vswpq,     1b20000, 2, (RNQ,  RNQ),      neon_swp),
16224218822Sdim  /* VTRN. Sizes 8 16 32.  */
16225218822Sdim nUF(vtrn,      vtrn,    2, (RNDQ, RNDQ),     neon_trn),
16226218822Sdim nUF(vtrnq,     vtrn,    2, (RNQ,  RNQ),      neon_trn),
16227218822Sdim
16228218822Sdim  /* Table lookup. Size 8.  */
16229218822Sdim NUF(vtbl,      1b00800, 3, (RND, NRDLST, RND), neon_tbl_tbx),
16230218822Sdim NUF(vtbx,      1b00840, 3, (RND, NRDLST, RND), neon_tbl_tbx),
16231218822Sdim
16232218822Sdim#undef THUMB_VARIANT
16233218822Sdim#define THUMB_VARIANT &fpu_vfp_v3_or_neon_ext
16234218822Sdim#undef ARM_VARIANT
16235218822Sdim#define ARM_VARIANT &fpu_vfp_v3_or_neon_ext
16236218822Sdim  /* Neon element/structure load/store.  */
16237218822Sdim nUF(vld1,      vld1,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16238218822Sdim nUF(vst1,      vst1,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16239218822Sdim nUF(vld2,      vld2,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16240218822Sdim nUF(vst2,      vst2,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16241218822Sdim nUF(vld3,      vld3,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16242218822Sdim nUF(vst3,      vst3,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16243218822Sdim nUF(vld4,      vld4,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16244218822Sdim nUF(vst4,      vst4,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16245218822Sdim
16246218822Sdim#undef THUMB_VARIANT
16247218822Sdim#define THUMB_VARIANT &fpu_vfp_ext_v3
16248218822Sdim#undef ARM_VARIANT
16249218822Sdim#define ARM_VARIANT &fpu_vfp_ext_v3
16250218822Sdim cCE(fconsts,   eb00a00, 2, (RVS, I255),      vfp_sp_const),
16251218822Sdim cCE(fconstd,   eb00b00, 2, (RVD, I255),      vfp_dp_const),
16252218822Sdim cCE(fshtos,    eba0a40, 2, (RVS, I16z),      vfp_sp_conv_16),
16253218822Sdim cCE(fshtod,    eba0b40, 2, (RVD, I16z),      vfp_dp_conv_16),
16254218822Sdim cCE(fsltos,    eba0ac0, 2, (RVS, I32),       vfp_sp_conv_32),
16255218822Sdim cCE(fsltod,    eba0bc0, 2, (RVD, I32),       vfp_dp_conv_32),
16256218822Sdim cCE(fuhtos,    ebb0a40, 2, (RVS, I16z),      vfp_sp_conv_16),
16257218822Sdim cCE(fuhtod,    ebb0b40, 2, (RVD, I16z),      vfp_dp_conv_16),
16258218822Sdim cCE(fultos,    ebb0ac0, 2, (RVS, I32),       vfp_sp_conv_32),
16259218822Sdim cCE(fultod,    ebb0bc0, 2, (RVD, I32),       vfp_dp_conv_32),
16260218822Sdim cCE(ftoshs,    ebe0a40, 2, (RVS, I16z),      vfp_sp_conv_16),
16261218822Sdim cCE(ftoshd,    ebe0b40, 2, (RVD, I16z),      vfp_dp_conv_16),
16262218822Sdim cCE(ftosls,    ebe0ac0, 2, (RVS, I32),       vfp_sp_conv_32),
16263218822Sdim cCE(ftosld,    ebe0bc0, 2, (RVD, I32),       vfp_dp_conv_32),
16264218822Sdim cCE(ftouhs,    ebf0a40, 2, (RVS, I16z),      vfp_sp_conv_16),
16265218822Sdim cCE(ftouhd,    ebf0b40, 2, (RVD, I16z),      vfp_dp_conv_16),
16266218822Sdim cCE(ftouls,    ebf0ac0, 2, (RVS, I32),       vfp_sp_conv_32),
16267218822Sdim cCE(ftould,    ebf0bc0, 2, (RVD, I32),       vfp_dp_conv_32),
16268218822Sdim
16269218822Sdim#undef THUMB_VARIANT
16270218822Sdim#undef ARM_VARIANT
16271218822Sdim#define ARM_VARIANT &arm_cext_xscale /* Intel XScale extensions.	 */
16272218822Sdim cCE(mia,	e200010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16273218822Sdim cCE(miaph,	e280010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16274218822Sdim cCE(miabb,	e2c0010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16275218822Sdim cCE(miabt,	e2d0010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16276218822Sdim cCE(miatb,	e2e0010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16277218822Sdim cCE(miatt,	e2f0010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16278218822Sdim cCE(mar,	c400000, 3, (RXA, RRnpc, RRnpc), xsc_mar),
16279218822Sdim cCE(mra,	c500000, 3, (RRnpc, RRnpc, RXA), xsc_mra),
16280218822Sdim
16281218822Sdim#undef ARM_VARIANT
16282218822Sdim#define ARM_VARIANT &arm_cext_iwmmxt /* Intel Wireless MMX technology.  */
16283218822Sdim cCE(tandcb,	e13f130, 1, (RR),		    iwmmxt_tandorc),
16284218822Sdim cCE(tandch,	e53f130, 1, (RR),		    iwmmxt_tandorc),
16285218822Sdim cCE(tandcw,	e93f130, 1, (RR),		    iwmmxt_tandorc),
16286218822Sdim cCE(tbcstb,	e400010, 2, (RIWR, RR),		    rn_rd),
16287218822Sdim cCE(tbcsth,	e400050, 2, (RIWR, RR),		    rn_rd),
16288218822Sdim cCE(tbcstw,	e400090, 2, (RIWR, RR),		    rn_rd),
16289218822Sdim cCE(textrcb,	e130170, 2, (RR, I7),		    iwmmxt_textrc),
16290218822Sdim cCE(textrch,	e530170, 2, (RR, I7),		    iwmmxt_textrc),
16291218822Sdim cCE(textrcw,	e930170, 2, (RR, I7),		    iwmmxt_textrc),
16292218822Sdim cCE(textrmub,	e100070, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16293218822Sdim cCE(textrmuh,	e500070, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16294218822Sdim cCE(textrmuw,	e900070, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16295218822Sdim cCE(textrmsb,	e100078, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16296218822Sdim cCE(textrmsh,	e500078, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16297218822Sdim cCE(textrmsw,	e900078, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16298218822Sdim cCE(tinsrb,	e600010, 3, (RIWR, RR, I7),	    iwmmxt_tinsr),
16299218822Sdim cCE(tinsrh,	e600050, 3, (RIWR, RR, I7),	    iwmmxt_tinsr),
16300218822Sdim cCE(tinsrw,	e600090, 3, (RIWR, RR, I7),	    iwmmxt_tinsr),
16301218822Sdim cCE(tmcr,	e000110, 2, (RIWC_RIWG, RR),	    rn_rd),
16302218822Sdim cCE(tmcrr,	c400000, 3, (RIWR, RR, RR),	    rm_rd_rn),
16303218822Sdim cCE(tmia,	e200010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16304218822Sdim cCE(tmiaph,	e280010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16305218822Sdim cCE(tmiabb,	e2c0010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16306218822Sdim cCE(tmiabt,	e2d0010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16307218822Sdim cCE(tmiatb,	e2e0010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16308218822Sdim cCE(tmiatt,	e2f0010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16309218822Sdim cCE(tmovmskb,	e100030, 2, (RR, RIWR),		    rd_rn),
16310218822Sdim cCE(tmovmskh,	e500030, 2, (RR, RIWR),		    rd_rn),
16311218822Sdim cCE(tmovmskw,	e900030, 2, (RR, RIWR),		    rd_rn),
16312218822Sdim cCE(tmrc,	e100110, 2, (RR, RIWC_RIWG),	    rd_rn),
16313218822Sdim cCE(tmrrc,	c500000, 3, (RR, RR, RIWR),	    rd_rn_rm),
16314218822Sdim cCE(torcb,	e13f150, 1, (RR),		    iwmmxt_tandorc),
16315218822Sdim cCE(torch,	e53f150, 1, (RR),		    iwmmxt_tandorc),
16316218822Sdim cCE(torcw,	e93f150, 1, (RR),		    iwmmxt_tandorc),
16317218822Sdim cCE(waccb,	e0001c0, 2, (RIWR, RIWR),	    rd_rn),
16318218822Sdim cCE(wacch,	e4001c0, 2, (RIWR, RIWR),	    rd_rn),
16319218822Sdim cCE(waccw,	e8001c0, 2, (RIWR, RIWR),	    rd_rn),
16320218822Sdim cCE(waddbss,	e300180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16321218822Sdim cCE(waddb,	e000180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16322218822Sdim cCE(waddbus,	e100180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16323218822Sdim cCE(waddhss,	e700180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16324218822Sdim cCE(waddh,	e400180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16325218822Sdim cCE(waddhus,	e500180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16326218822Sdim cCE(waddwss,	eb00180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16327218822Sdim cCE(waddw,	e800180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16328218822Sdim cCE(waddwus,	e900180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16329218822Sdim cCE(waligni,	e000020, 4, (RIWR, RIWR, RIWR, I7), iwmmxt_waligni),
16330218822Sdim cCE(walignr0,	e800020, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16331218822Sdim cCE(walignr1,	e900020, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16332218822Sdim cCE(walignr2,	ea00020, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16333218822Sdim cCE(walignr3,	eb00020, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16334218822Sdim cCE(wand,	e200000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16335218822Sdim cCE(wandn,	e300000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16336218822Sdim cCE(wavg2b,	e800000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16337218822Sdim cCE(wavg2br,	e900000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16338218822Sdim cCE(wavg2h,	ec00000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16339218822Sdim cCE(wavg2hr,	ed00000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16340218822Sdim cCE(wcmpeqb,	e000060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16341218822Sdim cCE(wcmpeqh,	e400060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16342218822Sdim cCE(wcmpeqw,	e800060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16343218822Sdim cCE(wcmpgtub,	e100060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16344218822Sdim cCE(wcmpgtuh,	e500060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16345218822Sdim cCE(wcmpgtuw,	e900060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16346218822Sdim cCE(wcmpgtsb,	e300060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16347218822Sdim cCE(wcmpgtsh,	e700060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16348218822Sdim cCE(wcmpgtsw,	eb00060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16349218822Sdim cCE(wldrb,	c100000, 2, (RIWR, ADDR),	    iwmmxt_wldstbh),
16350218822Sdim cCE(wldrh,	c500000, 2, (RIWR, ADDR),	    iwmmxt_wldstbh),
16351218822Sdim cCE(wldrw,	c100100, 2, (RIWR_RIWC, ADDR),	    iwmmxt_wldstw),
16352218822Sdim cCE(wldrd,	c500100, 2, (RIWR, ADDR),	    iwmmxt_wldstd),
16353218822Sdim cCE(wmacs,	e600100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16354218822Sdim cCE(wmacsz,	e700100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16355218822Sdim cCE(wmacu,	e400100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16356218822Sdim cCE(wmacuz,	e500100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16357218822Sdim cCE(wmadds,	ea00100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16358218822Sdim cCE(wmaddu,	e800100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16359218822Sdim cCE(wmaxsb,	e200160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16360218822Sdim cCE(wmaxsh,	e600160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16361218822Sdim cCE(wmaxsw,	ea00160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16362218822Sdim cCE(wmaxub,	e000160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16363218822Sdim cCE(wmaxuh,	e400160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16364218822Sdim cCE(wmaxuw,	e800160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16365218822Sdim cCE(wminsb,	e300160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16366218822Sdim cCE(wminsh,	e700160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16367218822Sdim cCE(wminsw,	eb00160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16368218822Sdim cCE(wminub,	e100160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16369218822Sdim cCE(wminuh,	e500160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16370218822Sdim cCE(wminuw,	e900160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16371218822Sdim cCE(wmov,	e000000, 2, (RIWR, RIWR),	    iwmmxt_wmov),
16372218822Sdim cCE(wmulsm,	e300100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16373218822Sdim cCE(wmulsl,	e200100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16374218822Sdim cCE(wmulum,	e100100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16375218822Sdim cCE(wmulul,	e000100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16376218822Sdim cCE(wor,	e000000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16377218822Sdim cCE(wpackhss,	e700080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16378218822Sdim cCE(wpackhus,	e500080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16379218822Sdim cCE(wpackwss,	eb00080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16380218822Sdim cCE(wpackwus,	e900080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16381218822Sdim cCE(wpackdss,	ef00080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16382218822Sdim cCE(wpackdus,	ed00080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16383218822Sdim cCE(wrorh,	e700040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16384218822Sdim cCE(wrorhg,	e700148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16385218822Sdim cCE(wrorw,	eb00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16386218822Sdim cCE(wrorwg,	eb00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16387218822Sdim cCE(wrord,	ef00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16388218822Sdim cCE(wrordg,	ef00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16389218822Sdim cCE(wsadb,	e000120, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16390218822Sdim cCE(wsadbz,	e100120, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16391218822Sdim cCE(wsadh,	e400120, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16392218822Sdim cCE(wsadhz,	e500120, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16393218822Sdim cCE(wshufh,	e0001e0, 3, (RIWR, RIWR, I255),	    iwmmxt_wshufh),
16394218822Sdim cCE(wsllh,	e500040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16395218822Sdim cCE(wsllhg,	e500148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16396218822Sdim cCE(wsllw,	e900040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16397218822Sdim cCE(wsllwg,	e900148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16398218822Sdim cCE(wslld,	ed00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16399218822Sdim cCE(wslldg,	ed00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16400218822Sdim cCE(wsrah,	e400040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16401218822Sdim cCE(wsrahg,	e400148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16402218822Sdim cCE(wsraw,	e800040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16403218822Sdim cCE(wsrawg,	e800148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16404218822Sdim cCE(wsrad,	ec00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16405218822Sdim cCE(wsradg,	ec00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16406218822Sdim cCE(wsrlh,	e600040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16407218822Sdim cCE(wsrlhg,	e600148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16408218822Sdim cCE(wsrlw,	ea00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16409218822Sdim cCE(wsrlwg,	ea00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16410218822Sdim cCE(wsrld,	ee00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16411218822Sdim cCE(wsrldg,	ee00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16412218822Sdim cCE(wstrb,	c000000, 2, (RIWR, ADDR),	    iwmmxt_wldstbh),
16413218822Sdim cCE(wstrh,	c400000, 2, (RIWR, ADDR),	    iwmmxt_wldstbh),
16414218822Sdim cCE(wstrw,	c000100, 2, (RIWR_RIWC, ADDR),	    iwmmxt_wldstw),
16415218822Sdim cCE(wstrd,	c400100, 2, (RIWR, ADDR),	    iwmmxt_wldstd),
16416218822Sdim cCE(wsubbss,	e3001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16417218822Sdim cCE(wsubb,	e0001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16418218822Sdim cCE(wsubbus,	e1001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16419218822Sdim cCE(wsubhss,	e7001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16420218822Sdim cCE(wsubh,	e4001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16421218822Sdim cCE(wsubhus,	e5001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16422218822Sdim cCE(wsubwss,	eb001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16423218822Sdim cCE(wsubw,	e8001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16424218822Sdim cCE(wsubwus,	e9001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16425218822Sdim cCE(wunpckehub,e0000c0, 2, (RIWR, RIWR),	    rd_rn),
16426218822Sdim cCE(wunpckehuh,e4000c0, 2, (RIWR, RIWR),	    rd_rn),
16427218822Sdim cCE(wunpckehuw,e8000c0, 2, (RIWR, RIWR),	    rd_rn),
16428218822Sdim cCE(wunpckehsb,e2000c0, 2, (RIWR, RIWR),	    rd_rn),
16429218822Sdim cCE(wunpckehsh,e6000c0, 2, (RIWR, RIWR),	    rd_rn),
16430218822Sdim cCE(wunpckehsw,ea000c0, 2, (RIWR, RIWR),	    rd_rn),
16431218822Sdim cCE(wunpckihb, e1000c0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16432218822Sdim cCE(wunpckihh, e5000c0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16433218822Sdim cCE(wunpckihw, e9000c0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16434218822Sdim cCE(wunpckelub,e0000e0, 2, (RIWR, RIWR),	    rd_rn),
16435218822Sdim cCE(wunpckeluh,e4000e0, 2, (RIWR, RIWR),	    rd_rn),
16436218822Sdim cCE(wunpckeluw,e8000e0, 2, (RIWR, RIWR),	    rd_rn),
16437218822Sdim cCE(wunpckelsb,e2000e0, 2, (RIWR, RIWR),	    rd_rn),
16438218822Sdim cCE(wunpckelsh,e6000e0, 2, (RIWR, RIWR),	    rd_rn),
16439218822Sdim cCE(wunpckelsw,ea000e0, 2, (RIWR, RIWR),	    rd_rn),
16440218822Sdim cCE(wunpckilb, e1000e0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16441218822Sdim cCE(wunpckilh, e5000e0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16442218822Sdim cCE(wunpckilw, e9000e0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16443218822Sdim cCE(wxor,	e100000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16444218822Sdim cCE(wzero,	e300000, 1, (RIWR),		    iwmmxt_wzero),
16445218822Sdim
16446218822Sdim#undef ARM_VARIANT
16447218822Sdim#define ARM_VARIANT &arm_cext_iwmmxt2 /* Intel Wireless MMX technology, version 2.  */
16448218822Sdim cCE(torvscb,   e13f190, 1, (RR),		    iwmmxt_tandorc),
16449218822Sdim cCE(torvsch,   e53f190, 1, (RR),		    iwmmxt_tandorc),
16450218822Sdim cCE(torvscw,   e93f190, 1, (RR),		    iwmmxt_tandorc),
16451218822Sdim cCE(wabsb,     e2001c0, 2, (RIWR, RIWR),           rd_rn),
16452218822Sdim cCE(wabsh,     e6001c0, 2, (RIWR, RIWR),           rd_rn),
16453218822Sdim cCE(wabsw,     ea001c0, 2, (RIWR, RIWR),           rd_rn),
16454218822Sdim cCE(wabsdiffb, e1001c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16455218822Sdim cCE(wabsdiffh, e5001c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16456218822Sdim cCE(wabsdiffw, e9001c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16457218822Sdim cCE(waddbhusl, e2001a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16458218822Sdim cCE(waddbhusm, e6001a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16459218822Sdim cCE(waddhc,    e600180, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16460218822Sdim cCE(waddwc,    ea00180, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16461218822Sdim cCE(waddsubhx, ea001a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16462218822Sdim cCE(wavg4,	e400000, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16463218822Sdim cCE(wavg4r,    e500000, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16464218822Sdim cCE(wmaddsn,   ee00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16465218822Sdim cCE(wmaddsx,   eb00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16466218822Sdim cCE(wmaddun,   ec00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16467218822Sdim cCE(wmaddux,   e900100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16468218822Sdim cCE(wmerge,    e000080, 4, (RIWR, RIWR, RIWR, I7), iwmmxt_wmerge),
16469218822Sdim cCE(wmiabb,    e0000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16470218822Sdim cCE(wmiabt,    e1000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16471218822Sdim cCE(wmiatb,    e2000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16472218822Sdim cCE(wmiatt,    e3000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16473218822Sdim cCE(wmiabbn,   e4000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16474218822Sdim cCE(wmiabtn,   e5000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16475218822Sdim cCE(wmiatbn,   e6000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16476218822Sdim cCE(wmiattn,   e7000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16477218822Sdim cCE(wmiawbb,   e800120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16478218822Sdim cCE(wmiawbt,   e900120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16479218822Sdim cCE(wmiawtb,   ea00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16480218822Sdim cCE(wmiawtt,   eb00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16481218822Sdim cCE(wmiawbbn,  ec00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16482218822Sdim cCE(wmiawbtn,  ed00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16483218822Sdim cCE(wmiawtbn,  ee00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16484218822Sdim cCE(wmiawttn,  ef00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16485218822Sdim cCE(wmulsmr,   ef00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16486218822Sdim cCE(wmulumr,   ed00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16487218822Sdim cCE(wmulwumr,  ec000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16488218822Sdim cCE(wmulwsmr,  ee000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16489218822Sdim cCE(wmulwum,   ed000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16490218822Sdim cCE(wmulwsm,   ef000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16491218822Sdim cCE(wmulwl,    eb000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16492218822Sdim cCE(wqmiabb,   e8000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16493218822Sdim cCE(wqmiabt,   e9000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16494218822Sdim cCE(wqmiatb,   ea000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16495218822Sdim cCE(wqmiatt,   eb000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16496218822Sdim cCE(wqmiabbn,  ec000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16497218822Sdim cCE(wqmiabtn,  ed000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16498218822Sdim cCE(wqmiatbn,  ee000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16499218822Sdim cCE(wqmiattn,  ef000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16500218822Sdim cCE(wqmulm,    e100080, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16501218822Sdim cCE(wqmulmr,   e300080, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16502218822Sdim cCE(wqmulwm,   ec000e0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16503218822Sdim cCE(wqmulwmr,  ee000e0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16504218822Sdim cCE(wsubaddhx, ed001c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16505218822Sdim
16506218822Sdim#undef ARM_VARIANT
16507218822Sdim#define ARM_VARIANT &arm_cext_maverick /* Cirrus Maverick instructions.	*/
16508218822Sdim cCE(cfldrs,	c100400, 2, (RMF, ADDRGLDC),	      rd_cpaddr),
16509218822Sdim cCE(cfldrd,	c500400, 2, (RMD, ADDRGLDC),	      rd_cpaddr),
16510218822Sdim cCE(cfldr32,	c100500, 2, (RMFX, ADDRGLDC),	      rd_cpaddr),
16511218822Sdim cCE(cfldr64,	c500500, 2, (RMDX, ADDRGLDC),	      rd_cpaddr),
16512218822Sdim cCE(cfstrs,	c000400, 2, (RMF, ADDRGLDC),	      rd_cpaddr),
16513218822Sdim cCE(cfstrd,	c400400, 2, (RMD, ADDRGLDC),	      rd_cpaddr),
16514218822Sdim cCE(cfstr32,	c000500, 2, (RMFX, ADDRGLDC),	      rd_cpaddr),
16515218822Sdim cCE(cfstr64,	c400500, 2, (RMDX, ADDRGLDC),	      rd_cpaddr),
16516218822Sdim cCE(cfmvsr,	e000450, 2, (RMF, RR),		      rn_rd),
16517218822Sdim cCE(cfmvrs,	e100450, 2, (RR, RMF),		      rd_rn),
16518218822Sdim cCE(cfmvdlr,	e000410, 2, (RMD, RR),		      rn_rd),
16519218822Sdim cCE(cfmvrdl,	e100410, 2, (RR, RMD),		      rd_rn),
16520218822Sdim cCE(cfmvdhr,	e000430, 2, (RMD, RR),		      rn_rd),
16521218822Sdim cCE(cfmvrdh,	e100430, 2, (RR, RMD),		      rd_rn),
16522218822Sdim cCE(cfmv64lr,	e000510, 2, (RMDX, RR),		      rn_rd),
16523218822Sdim cCE(cfmvr64l,	e100510, 2, (RR, RMDX),		      rd_rn),
16524218822Sdim cCE(cfmv64hr,	e000530, 2, (RMDX, RR),		      rn_rd),
16525218822Sdim cCE(cfmvr64h,	e100530, 2, (RR, RMDX),		      rd_rn),
16526218822Sdim cCE(cfmval32,	e200440, 2, (RMAX, RMFX),	      rd_rn),
16527218822Sdim cCE(cfmv32al,	e100440, 2, (RMFX, RMAX),	      rd_rn),
16528218822Sdim cCE(cfmvam32,	e200460, 2, (RMAX, RMFX),	      rd_rn),
16529218822Sdim cCE(cfmv32am,	e100460, 2, (RMFX, RMAX),	      rd_rn),
16530218822Sdim cCE(cfmvah32,	e200480, 2, (RMAX, RMFX),	      rd_rn),
16531218822Sdim cCE(cfmv32ah,	e100480, 2, (RMFX, RMAX),	      rd_rn),
16532218822Sdim cCE(cfmva32,	e2004a0, 2, (RMAX, RMFX),	      rd_rn),
16533218822Sdim cCE(cfmv32a,	e1004a0, 2, (RMFX, RMAX),	      rd_rn),
16534218822Sdim cCE(cfmva64,	e2004c0, 2, (RMAX, RMDX),	      rd_rn),
16535218822Sdim cCE(cfmv64a,	e1004c0, 2, (RMDX, RMAX),	      rd_rn),
16536218822Sdim cCE(cfmvsc32,	e2004e0, 2, (RMDS, RMDX),	      mav_dspsc),
16537218822Sdim cCE(cfmv32sc,	e1004e0, 2, (RMDX, RMDS),	      rd),
16538218822Sdim cCE(cfcpys,	e000400, 2, (RMF, RMF),		      rd_rn),
16539218822Sdim cCE(cfcpyd,	e000420, 2, (RMD, RMD),		      rd_rn),
16540218822Sdim cCE(cfcvtsd,	e000460, 2, (RMD, RMF),		      rd_rn),
16541218822Sdim cCE(cfcvtds,	e000440, 2, (RMF, RMD),		      rd_rn),
16542218822Sdim cCE(cfcvt32s,	e000480, 2, (RMF, RMFX),	      rd_rn),
16543218822Sdim cCE(cfcvt32d,	e0004a0, 2, (RMD, RMFX),	      rd_rn),
16544218822Sdim cCE(cfcvt64s,	e0004c0, 2, (RMF, RMDX),	      rd_rn),
16545218822Sdim cCE(cfcvt64d,	e0004e0, 2, (RMD, RMDX),	      rd_rn),
16546218822Sdim cCE(cfcvts32,	e100580, 2, (RMFX, RMF),	      rd_rn),
16547218822Sdim cCE(cfcvtd32,	e1005a0, 2, (RMFX, RMD),	      rd_rn),
16548218822Sdim cCE(cftruncs32,e1005c0, 2, (RMFX, RMF),	      rd_rn),
16549218822Sdim cCE(cftruncd32,e1005e0, 2, (RMFX, RMD),	      rd_rn),
16550218822Sdim cCE(cfrshl32,	e000550, 3, (RMFX, RMFX, RR),	      mav_triple),
16551218822Sdim cCE(cfrshl64,	e000570, 3, (RMDX, RMDX, RR),	      mav_triple),
16552218822Sdim cCE(cfsh32,	e000500, 3, (RMFX, RMFX, I63s),	      mav_shift),
16553218822Sdim cCE(cfsh64,	e200500, 3, (RMDX, RMDX, I63s),	      mav_shift),
16554218822Sdim cCE(cfcmps,	e100490, 3, (RR, RMF, RMF),	      rd_rn_rm),
16555218822Sdim cCE(cfcmpd,	e1004b0, 3, (RR, RMD, RMD),	      rd_rn_rm),
16556218822Sdim cCE(cfcmp32,	e100590, 3, (RR, RMFX, RMFX),	      rd_rn_rm),
16557218822Sdim cCE(cfcmp64,	e1005b0, 3, (RR, RMDX, RMDX),	      rd_rn_rm),
16558218822Sdim cCE(cfabss,	e300400, 2, (RMF, RMF),		      rd_rn),
16559218822Sdim cCE(cfabsd,	e300420, 2, (RMD, RMD),		      rd_rn),
16560218822Sdim cCE(cfnegs,	e300440, 2, (RMF, RMF),		      rd_rn),
16561218822Sdim cCE(cfnegd,	e300460, 2, (RMD, RMD),		      rd_rn),
16562218822Sdim cCE(cfadds,	e300480, 3, (RMF, RMF, RMF),	      rd_rn_rm),
16563218822Sdim cCE(cfaddd,	e3004a0, 3, (RMD, RMD, RMD),	      rd_rn_rm),
16564218822Sdim cCE(cfsubs,	e3004c0, 3, (RMF, RMF, RMF),	      rd_rn_rm),
16565218822Sdim cCE(cfsubd,	e3004e0, 3, (RMD, RMD, RMD),	      rd_rn_rm),
16566218822Sdim cCE(cfmuls,	e100400, 3, (RMF, RMF, RMF),	      rd_rn_rm),
16567218822Sdim cCE(cfmuld,	e100420, 3, (RMD, RMD, RMD),	      rd_rn_rm),
16568218822Sdim cCE(cfabs32,	e300500, 2, (RMFX, RMFX),	      rd_rn),
16569218822Sdim cCE(cfabs64,	e300520, 2, (RMDX, RMDX),	      rd_rn),
16570218822Sdim cCE(cfneg32,	e300540, 2, (RMFX, RMFX),	      rd_rn),
16571218822Sdim cCE(cfneg64,	e300560, 2, (RMDX, RMDX),	      rd_rn),
16572218822Sdim cCE(cfadd32,	e300580, 3, (RMFX, RMFX, RMFX),	      rd_rn_rm),
16573218822Sdim cCE(cfadd64,	e3005a0, 3, (RMDX, RMDX, RMDX),	      rd_rn_rm),
16574218822Sdim cCE(cfsub32,	e3005c0, 3, (RMFX, RMFX, RMFX),	      rd_rn_rm),
16575218822Sdim cCE(cfsub64,	e3005e0, 3, (RMDX, RMDX, RMDX),	      rd_rn_rm),
16576218822Sdim cCE(cfmul32,	e100500, 3, (RMFX, RMFX, RMFX),	      rd_rn_rm),
16577218822Sdim cCE(cfmul64,	e100520, 3, (RMDX, RMDX, RMDX),	      rd_rn_rm),
16578218822Sdim cCE(cfmac32,	e100540, 3, (RMFX, RMFX, RMFX),	      rd_rn_rm),
16579218822Sdim cCE(cfmsc32,	e100560, 3, (RMFX, RMFX, RMFX),	      rd_rn_rm),
16580218822Sdim cCE(cfmadd32,	e000600, 4, (RMAX, RMFX, RMFX, RMFX), mav_quad),
16581218822Sdim cCE(cfmsub32,	e100600, 4, (RMAX, RMFX, RMFX, RMFX), mav_quad),
16582218822Sdim cCE(cfmadda32, e200600, 4, (RMAX, RMAX, RMFX, RMFX), mav_quad),
16583218822Sdim cCE(cfmsuba32, e300600, 4, (RMAX, RMAX, RMFX, RMFX), mav_quad),
16584218822Sdim};
16585218822Sdim#undef ARM_VARIANT
16586218822Sdim#undef THUMB_VARIANT
16587218822Sdim#undef TCE
16588218822Sdim#undef TCM
16589218822Sdim#undef TUE
16590218822Sdim#undef TUF
16591218822Sdim#undef TCC
16592218822Sdim#undef cCE
16593218822Sdim#undef cCL
16594218822Sdim#undef C3E
16595218822Sdim#undef CE
16596218822Sdim#undef CM
16597218822Sdim#undef UE
16598218822Sdim#undef UF
16599218822Sdim#undef UT
16600218822Sdim#undef NUF
16601218822Sdim#undef nUF
16602218822Sdim#undef NCE
16603218822Sdim#undef nCE
16604218822Sdim#undef OPS0
16605218822Sdim#undef OPS1
16606218822Sdim#undef OPS2
16607218822Sdim#undef OPS3
16608218822Sdim#undef OPS4
16609218822Sdim#undef OPS5
16610218822Sdim#undef OPS6
16611218822Sdim#undef do_0
16612218822Sdim
16613218822Sdim/* MD interface: bits in the object file.  */
16614218822Sdim
16615218822Sdim/* Turn an integer of n bytes (in val) into a stream of bytes appropriate
16616218822Sdim   for use in the a.out file, and stores them in the array pointed to by buf.
16617218822Sdim   This knows about the endian-ness of the target machine and does
16618218822Sdim   THE RIGHT THING, whatever it is.  Possible values for n are 1 (byte)
16619218822Sdim   2 (short) and 4 (long)  Floating numbers are put out as a series of
16620218822Sdim   LITTLENUMS (shorts, here at least).	*/
16621218822Sdim
16622218822Sdimvoid
16623218822Sdimmd_number_to_chars (char * buf, valueT val, int n)
16624218822Sdim{
16625218822Sdim  if (target_big_endian)
16626218822Sdim    number_to_chars_bigendian (buf, val, n);
16627218822Sdim  else
16628218822Sdim    number_to_chars_littleendian (buf, val, n);
1662989857Sobrien}
1663089857Sobrien
16631218822Sdimstatic valueT
16632218822Sdimmd_chars_to_number (char * buf, int n)
1663360484Sobrien{
16634218822Sdim  valueT result = 0;
16635218822Sdim  unsigned char * where = (unsigned char *) buf;
1663660484Sobrien
16637218822Sdim  if (target_big_endian)
16638130561Sobrien    {
16639218822Sdim      while (n--)
16640218822Sdim	{
16641218822Sdim	  result <<= 8;
16642218822Sdim	  result |= (*where++ & 255);
16643218822Sdim	}
16644130561Sobrien    }
16645218822Sdim  else
16646218822Sdim    {
16647218822Sdim      while (n--)
16648218822Sdim	{
16649218822Sdim	  result <<= 8;
16650218822Sdim	  result |= (where[n] & 255);
16651218822Sdim	}
16652218822Sdim    }
16653218822Sdim
16654218822Sdim  return result;
1665560484Sobrien}
1665660484Sobrien
16657218822Sdim/* MD interface: Sections.  */
1665889857Sobrien
16659218822Sdim/* Estimate the size of a frag before relaxing.  Assume everything fits in
16660218822Sdim   2 bytes.  */
1666189857Sobrien
16662218822Sdimint
16663218822Sdimmd_estimate_size_before_relax (fragS * fragp,
16664218822Sdim			       segT    segtype ATTRIBUTE_UNUSED)
1666589857Sobrien{
16666218822Sdim  fragp->fr_var = 2;
16667218822Sdim  return 2;
16668218822Sdim}
1666989857Sobrien
16670218822Sdim/* Convert a machine dependent frag.  */
1667189857Sobrien
16672218822Sdimvoid
16673218822Sdimmd_convert_frag (bfd *abfd, segT asec ATTRIBUTE_UNUSED, fragS *fragp)
16674218822Sdim{
16675218822Sdim  unsigned long insn;
16676218822Sdim  unsigned long old_op;
16677218822Sdim  char *buf;
16678218822Sdim  expressionS exp;
16679218822Sdim  fixS *fixp;
16680218822Sdim  int reloc_type;
16681218822Sdim  int pc_rel;
16682218822Sdim  int opcode;
1668389857Sobrien
16684218822Sdim  buf = fragp->fr_literal + fragp->fr_fix;
16685218822Sdim
16686218822Sdim  old_op = bfd_get_16(abfd, buf);
16687218822Sdim  if (fragp->fr_symbol) {
16688218822Sdim      exp.X_op = O_symbol;
16689218822Sdim      exp.X_add_symbol = fragp->fr_symbol;
16690218822Sdim  } else {
16691218822Sdim      exp.X_op = O_constant;
16692218822Sdim  }
16693218822Sdim  exp.X_add_number = fragp->fr_offset;
16694218822Sdim  opcode = fragp->fr_subtype;
16695218822Sdim  switch (opcode)
1669689857Sobrien    {
16697218822Sdim    case T_MNEM_ldr_pc:
16698218822Sdim    case T_MNEM_ldr_pc2:
16699218822Sdim    case T_MNEM_ldr_sp:
16700218822Sdim    case T_MNEM_str_sp:
16701218822Sdim    case T_MNEM_ldr:
16702218822Sdim    case T_MNEM_ldrb:
16703218822Sdim    case T_MNEM_ldrh:
16704218822Sdim    case T_MNEM_str:
16705218822Sdim    case T_MNEM_strb:
16706218822Sdim    case T_MNEM_strh:
16707218822Sdim      if (fragp->fr_var == 4)
1670889857Sobrien	{
16709218822Sdim	  insn = THUMB_OP32(opcode);
16710218822Sdim	  if ((old_op >> 12) == 4 || (old_op >> 12) == 9)
1671189857Sobrien	    {
16712218822Sdim	      insn |= (old_op & 0x700) << 4;
1671389857Sobrien	    }
16714218822Sdim	  else
1671589857Sobrien	    {
16716218822Sdim	      insn |= (old_op & 7) << 12;
16717218822Sdim	      insn |= (old_op & 0x38) << 13;
1671889857Sobrien	    }
16719218822Sdim	  insn |= 0x00000c00;
16720218822Sdim	  put_thumb32_insn (buf, insn);
16721218822Sdim	  reloc_type = BFD_RELOC_ARM_T32_OFFSET_IMM;
16722218822Sdim	}
16723218822Sdim      else
16724218822Sdim	{
16725218822Sdim	  reloc_type = BFD_RELOC_ARM_THUMB_OFFSET;
16726218822Sdim	}
16727218822Sdim      pc_rel = (opcode == T_MNEM_ldr_pc2);
16728218822Sdim      break;
16729218822Sdim    case T_MNEM_adr:
16730218822Sdim      if (fragp->fr_var == 4)
16731218822Sdim	{
16732218822Sdim	  insn = THUMB_OP32 (opcode);
16733218822Sdim	  insn |= (old_op & 0xf0) << 4;
16734218822Sdim	  put_thumb32_insn (buf, insn);
16735218822Sdim	  reloc_type = BFD_RELOC_ARM_T32_ADD_PC12;
16736218822Sdim	}
16737218822Sdim      else
16738218822Sdim	{
16739218822Sdim	  reloc_type = BFD_RELOC_ARM_THUMB_ADD;
16740218822Sdim	  exp.X_add_number -= 4;
16741218822Sdim	}
16742218822Sdim      pc_rel = 1;
16743218822Sdim      break;
16744218822Sdim    case T_MNEM_mov:
16745218822Sdim    case T_MNEM_movs:
16746218822Sdim    case T_MNEM_cmp:
16747218822Sdim    case T_MNEM_cmn:
16748218822Sdim      if (fragp->fr_var == 4)
16749218822Sdim	{
16750218822Sdim	  int r0off = (opcode == T_MNEM_mov
16751218822Sdim		       || opcode == T_MNEM_movs) ? 0 : 8;
16752218822Sdim	  insn = THUMB_OP32 (opcode);
16753218822Sdim	  insn = (insn & 0xe1ffffff) | 0x10000000;
16754218822Sdim	  insn |= (old_op & 0x700) << r0off;
16755218822Sdim	  put_thumb32_insn (buf, insn);
16756218822Sdim	  reloc_type = BFD_RELOC_ARM_T32_IMMEDIATE;
16757218822Sdim	}
16758218822Sdim      else
16759218822Sdim	{
16760218822Sdim	  reloc_type = BFD_RELOC_ARM_THUMB_IMM;
16761218822Sdim	}
16762218822Sdim      pc_rel = 0;
16763218822Sdim      break;
16764218822Sdim    case T_MNEM_b:
16765218822Sdim      if (fragp->fr_var == 4)
16766218822Sdim	{
16767218822Sdim	  insn = THUMB_OP32(opcode);
16768218822Sdim	  put_thumb32_insn (buf, insn);
16769218822Sdim	  reloc_type = BFD_RELOC_THUMB_PCREL_BRANCH25;
16770218822Sdim	}
16771218822Sdim      else
16772218822Sdim	reloc_type = BFD_RELOC_THUMB_PCREL_BRANCH12;
16773218822Sdim      pc_rel = 1;
16774218822Sdim      break;
16775218822Sdim    case T_MNEM_bcond:
16776218822Sdim      if (fragp->fr_var == 4)
16777218822Sdim	{
16778218822Sdim	  insn = THUMB_OP32(opcode);
16779218822Sdim	  insn |= (old_op & 0xf00) << 14;
16780218822Sdim	  put_thumb32_insn (buf, insn);
16781218822Sdim	  reloc_type = BFD_RELOC_THUMB_PCREL_BRANCH20;
16782218822Sdim	}
16783218822Sdim      else
16784218822Sdim	reloc_type = BFD_RELOC_THUMB_PCREL_BRANCH9;
16785218822Sdim      pc_rel = 1;
16786218822Sdim      break;
16787218822Sdim    case T_MNEM_add_sp:
16788218822Sdim    case T_MNEM_add_pc:
16789218822Sdim    case T_MNEM_inc_sp:
16790218822Sdim    case T_MNEM_dec_sp:
16791218822Sdim      if (fragp->fr_var == 4)
16792218822Sdim	{
16793218822Sdim	  /* ??? Choose between add and addw.  */
16794218822Sdim	  insn = THUMB_OP32 (opcode);
16795218822Sdim	  insn |= (old_op & 0xf0) << 4;
16796218822Sdim	  put_thumb32_insn (buf, insn);
16797218822Sdim	  if (opcode == T_MNEM_add_pc)
16798218822Sdim	    reloc_type = BFD_RELOC_ARM_T32_IMM12;
1679989857Sobrien	  else
16800218822Sdim	    reloc_type = BFD_RELOC_ARM_T32_ADD_IMM;
16801218822Sdim	}
16802218822Sdim      else
16803218822Sdim	reloc_type = BFD_RELOC_ARM_THUMB_ADD;
16804218822Sdim      pc_rel = 0;
16805218822Sdim      break;
1680689857Sobrien
16807218822Sdim    case T_MNEM_addi:
16808218822Sdim    case T_MNEM_addis:
16809218822Sdim    case T_MNEM_subi:
16810218822Sdim    case T_MNEM_subis:
16811218822Sdim      if (fragp->fr_var == 4)
16812218822Sdim	{
16813218822Sdim	  insn = THUMB_OP32 (opcode);
16814218822Sdim	  insn |= (old_op & 0xf0) << 4;
16815218822Sdim	  insn |= (old_op & 0xf) << 16;
16816218822Sdim	  put_thumb32_insn (buf, insn);
16817218822Sdim	  if (insn & (1 << 20))
16818218822Sdim	    reloc_type = BFD_RELOC_ARM_T32_ADD_IMM;
16819218822Sdim	  else
16820218822Sdim	    reloc_type = BFD_RELOC_ARM_T32_IMMEDIATE;
1682189857Sobrien	}
1682289857Sobrien      else
16823218822Sdim	reloc_type = BFD_RELOC_ARM_THUMB_ADD;
16824218822Sdim      pc_rel = 0;
16825218822Sdim      break;
16826218822Sdim    default:
16827218822Sdim      abort();
1682889857Sobrien    }
16829218822Sdim  fixp = fix_new_exp (fragp, fragp->fr_fix, fragp->fr_var, &exp, pc_rel,
16830218822Sdim		      reloc_type);
16831218822Sdim  fixp->fx_file = fragp->fr_file;
16832218822Sdim  fixp->fx_line = fragp->fr_line;
16833218822Sdim  fragp->fr_fix += fragp->fr_var;
1683489857Sobrien}
16835104834Sobrien
16836218822Sdim/* Return the size of a relaxable immediate operand instruction.
16837218822Sdim   SHIFT and SIZE specify the form of the allowable immediate.  */
16838218822Sdimstatic int
16839218822Sdimrelax_immediate (fragS *fragp, int size, int shift)
1684060484Sobrien{
16841218822Sdim  offsetT offset;
16842218822Sdim  offsetT mask;
16843218822Sdim  offsetT low;
1684460484Sobrien
16845218822Sdim  /* ??? Should be able to do better than this.  */
16846218822Sdim  if (fragp->fr_symbol)
16847218822Sdim    return 4;
16848218822Sdim
16849218822Sdim  low = (1 << shift) - 1;
16850218822Sdim  mask = (1 << (shift + size)) - (1 << shift);
16851218822Sdim  offset = fragp->fr_offset;
16852218822Sdim  /* Force misaligned offsets to 32-bit variant.  */
16853218822Sdim  if (offset & low)
16854218822Sdim    return 4;
16855218822Sdim  if (offset & ~mask)
16856218822Sdim    return 4;
16857218822Sdim  return 2;
1685860484Sobrien}
1685960484Sobrien
16860218822Sdim/* Get the address of a symbol during relaxation.  */
16861218822Sdimstatic addressT
16862218822Sdimrelaxed_symbol_addr(fragS *fragp, long stretch)
1686389857Sobrien{
16864218822Sdim  fragS *sym_frag;
16865218822Sdim  addressT addr;
16866218822Sdim  symbolS *sym;
1686789857Sobrien
16868218822Sdim  sym = fragp->fr_symbol;
16869218822Sdim  sym_frag = symbol_get_frag (sym);
16870218822Sdim  know (S_GET_SEGMENT (sym) != absolute_section
16871218822Sdim	|| sym_frag == &zero_address_frag);
16872218822Sdim  addr = S_GET_VALUE (sym) + fragp->fr_offset;
1687389857Sobrien
16874218822Sdim  /* If frag has yet to be reached on this pass, assume it will
16875218822Sdim     move by STRETCH just as we did.  If this is not so, it will
16876218822Sdim     be because some frag between grows, and that will force
16877218822Sdim     another pass.  */
1687889857Sobrien
16879218822Sdim  if (stretch != 0
16880218822Sdim      && sym_frag->relax_marker != fragp->relax_marker)
16881218822Sdim    addr += stretch;
1688289857Sobrien
16883218822Sdim  return addr;
16884218822Sdim}
1688589857Sobrien
16886218822Sdim/* Return the size of a relaxable adr pseudo-instruction or PC-relative
16887218822Sdim   load.  */
16888218822Sdimstatic int
16889218822Sdimrelax_adr (fragS *fragp, asection *sec, long stretch)
16890218822Sdim{
16891218822Sdim  addressT addr;
16892218822Sdim  offsetT val;
1689389857Sobrien
16894218822Sdim  /* Assume worst case for symbols not known to be in the same section.  */
16895218822Sdim  if (!S_IS_DEFINED(fragp->fr_symbol)
16896218822Sdim      || sec != S_GET_SEGMENT (fragp->fr_symbol))
16897218822Sdim    return 4;
16898218822Sdim
16899218822Sdim  val = relaxed_symbol_addr(fragp, stretch);
16900218822Sdim  addr = fragp->fr_address + fragp->fr_fix;
16901218822Sdim  addr = (addr + 4) & ~3;
16902218822Sdim  /* Force misaligned targets to 32-bit variant.  */
16903218822Sdim  if (val & 3)
16904218822Sdim    return 4;
16905218822Sdim  val -= addr;
16906218822Sdim  if (val < 0 || val > 1020)
16907218822Sdim    return 4;
16908218822Sdim  return 2;
1690989857Sobrien}
1691089857Sobrien
16911218822Sdim/* Return the size of a relaxable add/sub immediate instruction.  */
16912218822Sdimstatic int
16913218822Sdimrelax_addsub (fragS *fragp, asection *sec)
16914130561Sobrien{
16915218822Sdim  char *buf;
16916218822Sdim  int op;
16917130561Sobrien
16918218822Sdim  buf = fragp->fr_literal + fragp->fr_fix;
16919218822Sdim  op = bfd_get_16(sec->owner, buf);
16920218822Sdim  if ((op & 0xf) == ((op >> 4) & 0xf))
16921218822Sdim    return relax_immediate (fragp, 8, 0);
16922218822Sdim  else
16923218822Sdim    return relax_immediate (fragp, 3, 0);
16924218822Sdim}
16925130561Sobrien
16926130561Sobrien
16927218822Sdim/* Return the size of a relaxable branch instruction.  BITS is the
16928218822Sdim   size of the offset field in the narrow instruction.  */
16929130561Sobrien
16930218822Sdimstatic int
16931218822Sdimrelax_branch (fragS *fragp, asection *sec, int bits, long stretch)
16932218822Sdim{
16933218822Sdim  addressT addr;
16934218822Sdim  offsetT val;
16935218822Sdim  offsetT limit;
16936130561Sobrien
16937218822Sdim  /* Assume worst case for symbols not known to be in the same section.  */
16938218822Sdim  if (!S_IS_DEFINED(fragp->fr_symbol)
16939218822Sdim      || sec != S_GET_SEGMENT (fragp->fr_symbol))
16940218822Sdim    return 4;
16941130561Sobrien
16942218822Sdim  val = relaxed_symbol_addr(fragp, stretch);
16943218822Sdim  addr = fragp->fr_address + fragp->fr_fix + 4;
16944218822Sdim  val -= addr;
16945130561Sobrien
16946218822Sdim  /* Offset is a signed value *2 */
16947218822Sdim  limit = 1 << bits;
16948218822Sdim  if (val >= limit || val < -limit)
16949218822Sdim    return 4;
16950218822Sdim  return 2;
16951130561Sobrien}
16952130561Sobrien
16953218822Sdim
16954218822Sdim/* Relax a machine dependent frag.  This returns the amount by which
16955218822Sdim   the current size of the frag should change.  */
16956218822Sdim
16957218822Sdimint
16958218822Sdimarm_relax_frag (asection *sec, fragS *fragp, long stretch)
1695960484Sobrien{
16960218822Sdim  int oldsize;
16961218822Sdim  int newsize;
1696277298Sobrien
16963218822Sdim  oldsize = fragp->fr_var;
16964218822Sdim  switch (fragp->fr_subtype)
16965218822Sdim    {
16966218822Sdim    case T_MNEM_ldr_pc2:
16967218822Sdim      newsize = relax_adr(fragp, sec, stretch);
16968218822Sdim      break;
16969218822Sdim    case T_MNEM_ldr_pc:
16970218822Sdim    case T_MNEM_ldr_sp:
16971218822Sdim    case T_MNEM_str_sp:
16972218822Sdim      newsize = relax_immediate(fragp, 8, 2);
16973218822Sdim      break;
16974218822Sdim    case T_MNEM_ldr:
16975218822Sdim    case T_MNEM_str:
16976218822Sdim      newsize = relax_immediate(fragp, 5, 2);
16977218822Sdim      break;
16978218822Sdim    case T_MNEM_ldrh:
16979218822Sdim    case T_MNEM_strh:
16980218822Sdim      newsize = relax_immediate(fragp, 5, 1);
16981218822Sdim      break;
16982218822Sdim    case T_MNEM_ldrb:
16983218822Sdim    case T_MNEM_strb:
16984218822Sdim      newsize = relax_immediate(fragp, 5, 0);
16985218822Sdim      break;
16986218822Sdim    case T_MNEM_adr:
16987218822Sdim      newsize = relax_adr(fragp, sec, stretch);
16988218822Sdim      break;
16989218822Sdim    case T_MNEM_mov:
16990218822Sdim    case T_MNEM_movs:
16991218822Sdim    case T_MNEM_cmp:
16992218822Sdim    case T_MNEM_cmn:
16993218822Sdim      newsize = relax_immediate(fragp, 8, 0);
16994218822Sdim      break;
16995218822Sdim    case T_MNEM_b:
16996218822Sdim      newsize = relax_branch(fragp, sec, 11, stretch);
16997218822Sdim      break;
16998218822Sdim    case T_MNEM_bcond:
16999218822Sdim      newsize = relax_branch(fragp, sec, 8, stretch);
17000218822Sdim      break;
17001218822Sdim    case T_MNEM_add_sp:
17002218822Sdim    case T_MNEM_add_pc:
17003218822Sdim      newsize = relax_immediate (fragp, 8, 2);
17004218822Sdim      break;
17005218822Sdim    case T_MNEM_inc_sp:
17006218822Sdim    case T_MNEM_dec_sp:
17007218822Sdim      newsize = relax_immediate (fragp, 7, 2);
17008218822Sdim      break;
17009218822Sdim    case T_MNEM_addi:
17010218822Sdim    case T_MNEM_addis:
17011218822Sdim    case T_MNEM_subi:
17012218822Sdim    case T_MNEM_subis:
17013218822Sdim      newsize = relax_addsub (fragp, sec);
17014218822Sdim      break;
17015218822Sdim    default:
17016218822Sdim      abort();
17017218822Sdim    }
1701877298Sobrien
17019218822Sdim  fragp->fr_var = newsize;
17020218822Sdim  /* Freeze wide instructions that are at or before the same location as
17021218822Sdim     in the previous pass.  This avoids infinite loops.
17022218822Sdim     Don't freeze them unconditionally because targets may be artificialy
17023218822Sdim     misaligned by the expansion of preceeding frags.  */
17024218822Sdim  if (stretch <= 0 && newsize > 2)
17025218822Sdim    {
17026218822Sdim      md_convert_frag (sec->owner, sec, fragp);
17027218822Sdim      frag_wane(fragp);
17028218822Sdim    }
1702960484Sobrien
17030218822Sdim  return newsize - oldsize;
17031218822Sdim}
1703260484Sobrien
17033218822Sdim/* Round up a section size to the appropriate boundary.	 */
1703460484Sobrien
17035218822SdimvalueT
17036218822Sdimmd_section_align (segT	 segment ATTRIBUTE_UNUSED,
17037218822Sdim		  valueT size)
17038218822Sdim{
17039218822Sdim#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
17040218822Sdim  if (OUTPUT_FLAVOR == bfd_target_aout_flavour)
1704189857Sobrien    {
17042218822Sdim      /* For a.out, force the section size to be aligned.  If we don't do
17043218822Sdim	 this, BFD will align it for us, but it will not write out the
17044218822Sdim	 final bytes of the section.  This may be a bug in BFD, but it is
17045218822Sdim	 easier to fix it here since that is how the other a.out targets
17046218822Sdim	 work.  */
17047218822Sdim      int align;
1704889857Sobrien
17049218822Sdim      align = bfd_get_section_alignment (stdoutput, segment);
17050218822Sdim      size = ((size + (1 << align) - 1) & ((valueT) -1 << align));
1705189857Sobrien    }
17052218822Sdim#endif
1705389857Sobrien
17054218822Sdim  return size;
17055218822Sdim}
17056218822Sdim
17057218822Sdim/* This is called from HANDLE_ALIGN in write.c.	 Fill in the contents
17058218822Sdim   of an rs_align_code fragment.  */
17059218822Sdim
17060218822Sdimvoid
17061218822Sdimarm_handle_align (fragS * fragP)
17062218822Sdim{
17063218822Sdim  static char const arm_noop[4] = { 0x00, 0x00, 0xa0, 0xe1 };
17064218822Sdim  static char const thumb_noop[2] = { 0xc0, 0x46 };
17065218822Sdim  static char const arm_bigend_noop[4] = { 0xe1, 0xa0, 0x00, 0x00 };
17066218822Sdim  static char const thumb_bigend_noop[2] = { 0x46, 0xc0 };
17067218822Sdim
17068218822Sdim  int bytes, fix, noop_size;
17069218822Sdim  char * p;
17070218822Sdim  const char * noop;
17071218822Sdim
17072218822Sdim  if (fragP->fr_type != rs_align_code)
17073218822Sdim    return;
17074218822Sdim
17075218822Sdim  bytes = fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix;
17076218822Sdim  p = fragP->fr_literal + fragP->fr_fix;
17077218822Sdim  fix = 0;
17078218822Sdim
17079218822Sdim  if (bytes > MAX_MEM_FOR_RS_ALIGN_CODE)
17080218822Sdim    bytes &= MAX_MEM_FOR_RS_ALIGN_CODE;
17081218822Sdim
17082218822Sdim  if (fragP->tc_frag_data)
1708389857Sobrien    {
17084218822Sdim      if (target_big_endian)
17085218822Sdim	noop = thumb_bigend_noop;
17086218822Sdim      else
17087218822Sdim	noop = thumb_noop;
17088218822Sdim      noop_size = sizeof (thumb_noop);
1708989857Sobrien    }
17090218822Sdim  else
1709189857Sobrien    {
17092218822Sdim      if (target_big_endian)
17093218822Sdim	noop = arm_bigend_noop;
1709489857Sobrien      else
17095218822Sdim	noop = arm_noop;
17096218822Sdim      noop_size = sizeof (arm_noop);
1709789857Sobrien    }
1709889857Sobrien
17099218822Sdim  if (bytes & (noop_size - 1))
1710089857Sobrien    {
17101218822Sdim      fix = bytes & (noop_size - 1);
17102218822Sdim      memset (p, 0, fix);
17103218822Sdim      p += fix;
17104218822Sdim      bytes -= fix;
1710589857Sobrien    }
1710689857Sobrien
17107218822Sdim  while (bytes >= noop_size)
17108218822Sdim    {
17109218822Sdim      memcpy (p, noop, noop_size);
17110218822Sdim      p += noop_size;
17111218822Sdim      bytes -= noop_size;
17112218822Sdim      fix += noop_size;
17113218822Sdim    }
1711489857Sobrien
17115218822Sdim  fragP->fr_fix += fix;
17116218822Sdim  fragP->fr_var = noop_size;
17117218822Sdim}
1711889857Sobrien
17119218822Sdim/* Called from md_do_align.  Used to create an alignment
17120218822Sdim   frag in a code section.  */
1712177298Sobrien
17122218822Sdimvoid
17123218822Sdimarm_frag_align_code (int n, int max)
17124218822Sdim{
17125218822Sdim  char * p;
17126130561Sobrien
17127218822Sdim  /* We assume that there will never be a requirement
17128218822Sdim     to support alignments greater than 32 bytes.  */
17129218822Sdim  if (max > MAX_MEM_FOR_RS_ALIGN_CODE)
17130218822Sdim    as_fatal (_("alignments greater than 32 bytes not supported in .text sections."));
1713160484Sobrien
17132218822Sdim  p = frag_var (rs_align_code,
17133218822Sdim		MAX_MEM_FOR_RS_ALIGN_CODE,
17134218822Sdim		1,
17135218822Sdim		(relax_substateT) max,
17136218822Sdim		(symbolS *) NULL,
17137218822Sdim		(offsetT) n,
17138218822Sdim		(char *) NULL);
17139218822Sdim  *p = 0;
17140218822Sdim}
1714189857Sobrien
17142218822Sdim/* Perform target specific initialisation of a frag.  */
1714377298Sobrien
17144218822Sdimvoid
17145218822Sdimarm_init_frag (fragS * fragP)
17146218822Sdim{
17147218822Sdim  /* Record whether this frag is in an ARM or a THUMB area.  */
17148218822Sdim  fragP->tc_frag_data = thumb_mode;
17149218822Sdim}
1715077298Sobrien
17151218822Sdim#ifdef OBJ_ELF
17152218822Sdim/* When we change sections we need to issue a new mapping symbol.  */
1715377298Sobrien
17154218822Sdimvoid
17155218822Sdimarm_elf_change_section (void)
17156218822Sdim{
17157218822Sdim  flagword flags;
17158218822Sdim  segment_info_type *seginfo;
1715977298Sobrien
17160218822Sdim  /* Link an unlinked unwind index table section to the .text section.	*/
17161218822Sdim  if (elf_section_type (now_seg) == SHT_ARM_EXIDX
17162218822Sdim      && elf_linked_to_section (now_seg) == NULL)
17163218822Sdim    elf_linked_to_section (now_seg) = text_section;
1716477298Sobrien
17165218822Sdim  if (!SEG_NORMAL (now_seg))
17166218822Sdim    return;
1716777298Sobrien
17168218822Sdim  flags = bfd_get_section_flags (stdoutput, now_seg);
1716989857Sobrien
17170218822Sdim  /* We can ignore sections that only contain debug info.  */
17171218822Sdim  if ((flags & SEC_ALLOC) == 0)
17172218822Sdim    return;
1717377298Sobrien
17174218822Sdim  seginfo = seg_info (now_seg);
17175218822Sdim  mapstate = seginfo->tc_segment_info_data.mapstate;
17176218822Sdim  marked_pr_dependency = seginfo->tc_segment_info_data.marked_pr_dependency;
17177218822Sdim}
17178218822Sdim
17179218822Sdimint
17180218822Sdimarm_elf_section_type (const char * str, size_t len)
17181218822Sdim{
17182218822Sdim  if (len == 5 && strncmp (str, "exidx", 5) == 0)
17183218822Sdim    return SHT_ARM_EXIDX;
17184218822Sdim
17185218822Sdim  return -1;
17186218822Sdim}
17187218822Sdim
17188218822Sdim/* Code to deal with unwinding tables.	*/
17189218822Sdim
17190218822Sdimstatic void add_unwind_adjustsp (offsetT);
17191218822Sdim
17192218822Sdim/* Cenerate and deferred unwind frame offset.  */
17193218822Sdim
17194218822Sdimstatic void
17195218822Sdimflush_pending_unwind (void)
17196218822Sdim{
17197218822Sdim  offsetT offset;
17198218822Sdim
17199218822Sdim  offset = unwind.pending_offset;
17200218822Sdim  unwind.pending_offset = 0;
17201218822Sdim  if (offset != 0)
17202218822Sdim    add_unwind_adjustsp (offset);
17203218822Sdim}
17204218822Sdim
17205218822Sdim/* Add an opcode to this list for this function.  Two-byte opcodes should
17206218822Sdim   be passed as op[0] << 8 | op[1].  The list of opcodes is built in reverse
17207218822Sdim   order.  */
17208218822Sdim
17209218822Sdimstatic void
17210218822Sdimadd_unwind_opcode (valueT op, int length)
17211218822Sdim{
17212218822Sdim  /* Add any deferred stack adjustment.	 */
17213218822Sdim  if (unwind.pending_offset)
17214218822Sdim    flush_pending_unwind ();
17215218822Sdim
17216218822Sdim  unwind.sp_restored = 0;
17217218822Sdim
17218218822Sdim  if (unwind.opcode_count + length > unwind.opcode_alloc)
1721960484Sobrien    {
17220218822Sdim      unwind.opcode_alloc += ARM_OPCODE_CHUNK_SIZE;
17221218822Sdim      if (unwind.opcodes)
17222218822Sdim	unwind.opcodes = xrealloc (unwind.opcodes,
17223218822Sdim				   unwind.opcode_alloc);
1722478828Sobrien      else
17225218822Sdim	unwind.opcodes = xmalloc (unwind.opcode_alloc);
1722660484Sobrien    }
17227218822Sdim  while (length > 0)
1722878828Sobrien    {
17229218822Sdim      length--;
17230218822Sdim      unwind.opcodes[unwind.opcode_count] = op & 0xff;
17231218822Sdim      op >>= 8;
17232218822Sdim      unwind.opcode_count++;
1723378828Sobrien    }
17234218822Sdim}
1723577298Sobrien
17236218822Sdim/* Add unwind opcodes to adjust the stack pointer.  */
17237130561Sobrien
17238218822Sdimstatic void
17239218822Sdimadd_unwind_adjustsp (offsetT offset)
17240218822Sdim{
17241218822Sdim  valueT op;
17242130561Sobrien
17243218822Sdim  if (offset > 0x200)
17244218822Sdim    {
17245218822Sdim      /* We need at most 5 bytes to hold a 32-bit value in a uleb128.  */
17246218822Sdim      char bytes[5];
17247218822Sdim      int n;
17248218822Sdim      valueT o;
17249130561Sobrien
17250218822Sdim      /* Long form: 0xb2, uleb128.  */
17251218822Sdim      /* This might not fit in a word so add the individual bytes,
17252218822Sdim	 remembering the list is built in reverse order.  */
17253218822Sdim      o = (valueT) ((offset - 0x204) >> 2);
17254218822Sdim      if (o == 0)
17255218822Sdim	add_unwind_opcode (0, 1);
17256130561Sobrien
17257218822Sdim      /* Calculate the uleb128 encoding of the offset.	*/
17258218822Sdim      n = 0;
17259218822Sdim      while (o)
17260218822Sdim	{
17261218822Sdim	  bytes[n] = o & 0x7f;
17262218822Sdim	  o >>= 7;
17263218822Sdim	  if (o)
17264218822Sdim	    bytes[n] |= 0x80;
17265218822Sdim	  n++;
17266218822Sdim	}
17267218822Sdim      /* Add the insn.	*/
17268218822Sdim      for (; n; n--)
17269218822Sdim	add_unwind_opcode (bytes[n - 1], 1);
17270218822Sdim      add_unwind_opcode (0xb2, 1);
17271218822Sdim    }
17272218822Sdim  else if (offset > 0x100)
17273218822Sdim    {
17274218822Sdim      /* Two short opcodes.  */
17275218822Sdim      add_unwind_opcode (0x3f, 1);
17276218822Sdim      op = (offset - 0x104) >> 2;
17277218822Sdim      add_unwind_opcode (op, 1);
17278218822Sdim    }
17279218822Sdim  else if (offset > 0)
17280218822Sdim    {
17281218822Sdim      /* Short opcode.	*/
17282218822Sdim      op = (offset - 4) >> 2;
17283218822Sdim      add_unwind_opcode (op, 1);
17284218822Sdim    }
17285218822Sdim  else if (offset < 0)
17286218822Sdim    {
17287218822Sdim      offset = -offset;
17288218822Sdim      while (offset > 0x100)
17289218822Sdim	{
17290218822Sdim	  add_unwind_opcode (0x7f, 1);
17291218822Sdim	  offset -= 0x100;
17292218822Sdim	}
17293218822Sdim      op = ((offset - 4) >> 2) | 0x40;
17294218822Sdim      add_unwind_opcode (op, 1);
17295218822Sdim    }
17296218822Sdim}
17297130561Sobrien
17298218822Sdim/* Finish the list of unwind opcodes for this function.	 */
17299218822Sdimstatic void
17300218822Sdimfinish_unwind_opcodes (void)
17301218822Sdim{
17302218822Sdim  valueT op;
17303130561Sobrien
17304218822Sdim  if (unwind.fp_used)
17305218822Sdim    {
17306218822Sdim      /* Adjust sp as necessary.  */
17307218822Sdim      unwind.pending_offset += unwind.fp_offset - unwind.frame_size;
17308218822Sdim      flush_pending_unwind ();
17309130561Sobrien
17310218822Sdim      /* After restoring sp from the frame pointer.  */
17311218822Sdim      op = 0x90 | unwind.fp_reg;
17312218822Sdim      add_unwind_opcode (op, 1);
17313218822Sdim    }
17314218822Sdim  else
17315218822Sdim    flush_pending_unwind ();
1731660484Sobrien}
1731760484Sobrien
1731877298Sobrien
17319218822Sdim/* Start an exception table entry.  If idx is nonzero this is an index table
17320218822Sdim   entry.  */
17321218822Sdim
17322218822Sdimstatic void
17323218822Sdimstart_unwind_section (const segT text_seg, int idx)
1732460484Sobrien{
17325218822Sdim  const char * text_name;
17326218822Sdim  const char * prefix;
17327218822Sdim  const char * prefix_once;
17328218822Sdim  const char * group_name;
17329218822Sdim  size_t prefix_len;
17330218822Sdim  size_t text_len;
17331218822Sdim  char * sec_name;
17332218822Sdim  size_t sec_name_len;
17333218822Sdim  int type;
17334218822Sdim  int flags;
17335218822Sdim  int linkonce;
17336218822Sdim
17337218822Sdim  if (idx)
17338218822Sdim    {
17339218822Sdim      prefix = ELF_STRING_ARM_unwind;
17340218822Sdim      prefix_once = ELF_STRING_ARM_unwind_once;
17341218822Sdim      type = SHT_ARM_EXIDX;
17342218822Sdim    }
1734360484Sobrien  else
17344218822Sdim    {
17345218822Sdim      prefix = ELF_STRING_ARM_unwind_info;
17346218822Sdim      prefix_once = ELF_STRING_ARM_unwind_info_once;
17347218822Sdim      type = SHT_PROGBITS;
17348218822Sdim    }
17349218822Sdim
17350218822Sdim  text_name = segment_name (text_seg);
17351218822Sdim  if (streq (text_name, ".text"))
17352218822Sdim    text_name = "";
17353218822Sdim
17354218822Sdim  if (strncmp (text_name, ".gnu.linkonce.t.",
17355218822Sdim	       strlen (".gnu.linkonce.t.")) == 0)
17356218822Sdim    {
17357218822Sdim      prefix = prefix_once;
17358218822Sdim      text_name += strlen (".gnu.linkonce.t.");
17359218822Sdim    }
17360218822Sdim
17361218822Sdim  prefix_len = strlen (prefix);
17362218822Sdim  text_len = strlen (text_name);
17363218822Sdim  sec_name_len = prefix_len + text_len;
17364218822Sdim  sec_name = xmalloc (sec_name_len + 1);
17365218822Sdim  memcpy (sec_name, prefix, prefix_len);
17366218822Sdim  memcpy (sec_name + prefix_len, text_name, text_len);
17367218822Sdim  sec_name[prefix_len + text_len] = '\0';
17368218822Sdim
17369218822Sdim  flags = SHF_ALLOC;
17370218822Sdim  linkonce = 0;
17371218822Sdim  group_name = 0;
17372218822Sdim
17373218822Sdim  /* Handle COMDAT group.  */
17374218822Sdim  if (prefix != prefix_once && (text_seg->flags & SEC_LINK_ONCE) != 0)
17375218822Sdim    {
17376218822Sdim      group_name = elf_group_name (text_seg);
17377218822Sdim      if (group_name == NULL)
17378218822Sdim	{
17379218822Sdim	  as_bad ("Group section `%s' has no group signature",
17380218822Sdim		  segment_name (text_seg));
17381218822Sdim	  ignore_rest_of_line ();
17382218822Sdim	  return;
17383218822Sdim	}
17384218822Sdim      flags |= SHF_GROUP;
17385218822Sdim      linkonce = 1;
17386218822Sdim    }
17387218822Sdim
17388218822Sdim  obj_elf_change_section (sec_name, type, flags, 0, group_name, linkonce, 0);
17389218822Sdim
17390218822Sdim  /* Set the setion link for index tables.  */
17391218822Sdim  if (idx)
17392218822Sdim    elf_linked_to_section (now_seg) = text_seg;
1739360484Sobrien}
1739460484Sobrien
17395218822Sdim
17396218822Sdim/* Start an unwind table entry.	 HAVE_DATA is nonzero if we have additional
17397218822Sdim   personality routine data.  Returns zero, or the index table value for
17398218822Sdim   and inline entry.  */
17399218822Sdim
1740077298Sobrienstatic valueT
17401218822Sdimcreate_unwind_entry (int have_data)
1740260484Sobrien{
17403218822Sdim  int size;
17404218822Sdim  addressT where;
17405218822Sdim  char *ptr;
17406218822Sdim  /* The current word of data.	*/
17407218822Sdim  valueT data;
17408218822Sdim  /* The number of bytes left in this word.  */
17409218822Sdim  int n;
1741060484Sobrien
17411218822Sdim  finish_unwind_opcodes ();
17412218822Sdim
17413218822Sdim  /* Remember the current text section.	 */
17414218822Sdim  unwind.saved_seg = now_seg;
17415218822Sdim  unwind.saved_subseg = now_subseg;
17416218822Sdim
17417218822Sdim  start_unwind_section (now_seg, 0);
17418218822Sdim
17419218822Sdim  if (unwind.personality_routine == NULL)
1742060484Sobrien    {
17421218822Sdim      if (unwind.personality_index == -2)
1742260484Sobrien	{
17423218822Sdim	  if (have_data)
17424218822Sdim	    as_bad (_("handerdata in cantunwind frame"));
17425218822Sdim	  return 1; /* EXIDX_CANTUNWIND.  */
1742660484Sobrien	}
17427218822Sdim
17428218822Sdim      /* Use a default personality routine if none is specified.  */
17429218822Sdim      if (unwind.personality_index == -1)
1743060484Sobrien	{
17431218822Sdim	  if (unwind.opcode_count > 3)
17432218822Sdim	    unwind.personality_index = 1;
17433218822Sdim	  else
17434218822Sdim	    unwind.personality_index = 0;
1743560484Sobrien	}
1743660484Sobrien
17437218822Sdim      /* Space for the personality routine entry.  */
17438218822Sdim      if (unwind.personality_index == 0)
17439218822Sdim	{
17440218822Sdim	  if (unwind.opcode_count > 3)
17441218822Sdim	    as_bad (_("too many unwind opcodes for personality routine 0"));
1744260484Sobrien
17443218822Sdim	  if (!have_data)
17444218822Sdim	    {
17445218822Sdim	      /* All the data is inline in the index table.  */
17446218822Sdim	      data = 0x80;
17447218822Sdim	      n = 3;
17448218822Sdim	      while (unwind.opcode_count > 0)
17449218822Sdim		{
17450218822Sdim		  unwind.opcode_count--;
17451218822Sdim		  data = (data << 8) | unwind.opcodes[unwind.opcode_count];
17452218822Sdim		  n--;
17453218822Sdim		}
1745460484Sobrien
17455218822Sdim	      /* Pad with "finish" opcodes.  */
17456218822Sdim	      while (n--)
17457218822Sdim		data = (data << 8) | 0xb0;
1745860484Sobrien
17459218822Sdim	      return data;
17460218822Sdim	    }
17461218822Sdim	  size = 0;
17462218822Sdim	}
17463218822Sdim      else
17464218822Sdim	/* We get two opcodes "free" in the first word.	 */
17465218822Sdim	size = unwind.opcode_count - 2;
17466218822Sdim    }
17467218822Sdim  else
17468218822Sdim    /* An extra byte is required for the opcode count.	*/
17469218822Sdim    size = unwind.opcode_count + 1;
1747060484Sobrien
17471218822Sdim  size = (size + 3) >> 2;
17472218822Sdim  if (size > 0xff)
17473218822Sdim    as_bad (_("too many unwind opcodes"));
1747460484Sobrien
17475218822Sdim  frag_align (2, 0, 0);
17476218822Sdim  record_alignment (now_seg, 2);
17477218822Sdim  unwind.table_entry = expr_build_dot ();
17478218822Sdim
17479218822Sdim  /* Allocate the table entry.	*/
17480218822Sdim  ptr = frag_more ((size << 2) + 4);
17481247386Sandrew  memset(ptr, 0, (size << 2) + 4);
17482218822Sdim  where = frag_now_fix () - ((size << 2) + 4);
17483218822Sdim
17484218822Sdim  switch (unwind.personality_index)
1748560484Sobrien    {
17486218822Sdim    case -1:
17487218822Sdim      /* ??? Should this be a PLT generating relocation?  */
17488218822Sdim      /* Custom personality routine.  */
17489218822Sdim      fix_new (frag_now, where, 4, unwind.personality_routine, 0, 1,
17490218822Sdim	       BFD_RELOC_ARM_PREL31);
1749160484Sobrien
17492218822Sdim      where += 4;
17493218822Sdim      ptr += 4;
17494218822Sdim
17495218822Sdim      /* Set the first byte to the number of additional words.	*/
17496218822Sdim      data = size - 1;
17497218822Sdim      n = 3;
1749860484Sobrien      break;
1749960484Sobrien
17500218822Sdim    /* ABI defined personality routines.  */
17501218822Sdim    case 0:
17502218822Sdim      /* Three opcodes bytes are packed into the first word.  */
17503218822Sdim      data = 0x80;
17504218822Sdim      n = 3;
1750560484Sobrien      break;
1750660484Sobrien
17507218822Sdim    case 1:
17508218822Sdim    case 2:
17509218822Sdim      /* The size and first two opcode bytes go in the first word.  */
17510218822Sdim      data = ((0x80 + unwind.personality_index) << 8) | size;
17511218822Sdim      n = 2;
1751260484Sobrien      break;
1751360484Sobrien
1751460484Sobrien    default:
17515218822Sdim      /* Should never happen.  */
17516218822Sdim      abort ();
1751760484Sobrien    }
1751860484Sobrien
17519218822Sdim  /* Pack the opcodes into words (MSB first), reversing the list at the same
17520218822Sdim     time.  */
17521218822Sdim  while (unwind.opcode_count > 0)
1752260484Sobrien    {
17523218822Sdim      if (n == 0)
1752460484Sobrien	{
17525218822Sdim	  md_number_to_chars (ptr, data, 4);
17526218822Sdim	  ptr += 4;
17527218822Sdim	  n = 4;
17528218822Sdim	  data = 0;
1752960484Sobrien	}
17530218822Sdim      unwind.opcode_count--;
17531218822Sdim      n--;
17532218822Sdim      data = (data << 8) | unwind.opcodes[unwind.opcode_count];
1753360484Sobrien    }
17534218822Sdim
17535218822Sdim  /* Finish off the last word.	*/
17536218822Sdim  if (n < 4)
1753760484Sobrien    {
17538218822Sdim      /* Pad with "finish" opcodes.  */
17539218822Sdim      while (n--)
17540218822Sdim	data = (data << 8) | 0xb0;
17541218822Sdim
17542218822Sdim      md_number_to_chars (ptr, data, 4);
1754360484Sobrien    }
1754460484Sobrien
17545218822Sdim  if (!have_data)
17546218822Sdim    {
17547218822Sdim      /* Add an empty descriptor if there is no user-specified data.   */
17548218822Sdim      ptr = frag_more (4);
17549218822Sdim      md_number_to_chars (ptr, 0, 4);
17550218822Sdim    }
17551218822Sdim
1755260484Sobrien  return 0;
1755360484Sobrien}
1755460484Sobrien
1755577298Sobrien
17556218822Sdim/* Initialize the DWARF-2 unwind information for this procedure.  */
17557218822Sdim
17558218822Sdimvoid
17559218822Sdimtc_arm_frame_initial_instructions (void)
17560218822Sdim{
17561218822Sdim  cfi_add_CFA_def_cfa (REG_SP, 0);
17562218822Sdim}
17563218822Sdim#endif /* OBJ_ELF */
17564218822Sdim
17565218822Sdim/* Convert REGNAME to a DWARF-2 register number.  */
17566218822Sdim
17567218822Sdimint
17568218822Sdimtc_arm_regname_to_dw2regnum (char *regname)
17569218822Sdim{
17570218822Sdim  int reg = arm_reg_parse (&regname, REG_TYPE_RN);
17571218822Sdim
17572218822Sdim  if (reg == FAIL)
17573218822Sdim    return -1;
17574218822Sdim
17575218822Sdim  return reg;
17576218822Sdim}
17577218822Sdim
17578218822Sdim#ifdef TE_PE
17579218822Sdimvoid
17580218822Sdimtc_pe_dwarf2_emit_offset (symbolS *symbol, unsigned int size)
17581218822Sdim{
17582218822Sdim  expressionS expr;
17583218822Sdim
17584218822Sdim  expr.X_op = O_secrel;
17585218822Sdim  expr.X_add_symbol = symbol;
17586218822Sdim  expr.X_add_number = 0;
17587218822Sdim  emit_expr (&expr, size);
17588218822Sdim}
17589218822Sdim#endif
17590218822Sdim
17591218822Sdim/* MD interface: Symbol and relocation handling.  */
17592218822Sdim
17593218822Sdim/* Return the address within the segment that a PC-relative fixup is
17594218822Sdim   relative to.  For ARM, PC-relative fixups applied to instructions
17595218822Sdim   are generally relative to the location of the fixup plus 8 bytes.
17596218822Sdim   Thumb branches are offset by 4, and Thumb loads relative to PC
17597218822Sdim   require special handling.  */
17598218822Sdim
1759960484Sobrienlong
17600218822Sdimmd_pcrel_from_section (fixS * fixP, segT seg)
1760160484Sobrien{
17602218822Sdim  offsetT base = fixP->fx_where + fixP->fx_frag->fr_address;
1760377298Sobrien
17604218822Sdim  /* If this is pc-relative and we are going to emit a relocation
17605218822Sdim     then we just want to put out any pipeline compensation that the linker
17606218822Sdim     will need.  Otherwise we want to use the calculated base.
17607218822Sdim     For WinCE we skip the bias for externals as well, since this
17608218822Sdim     is how the MS ARM-CE assembler behaves and we want to be compatible.  */
17609218822Sdim  if (fixP->fx_pcrel
17610218822Sdim      && ((fixP->fx_addsy && S_GET_SEGMENT (fixP->fx_addsy) != seg)
17611218822Sdim	  || (arm_force_relocation (fixP)
17612218822Sdim#ifdef TE_WINCE
17613218822Sdim	      && !S_IS_EXTERNAL (fixP->fx_addsy)
17614218822Sdim#endif
17615218822Sdim	      )))
17616218822Sdim    base = 0;
17617218822Sdim
17618218822Sdim  switch (fixP->fx_r_type)
1761960484Sobrien    {
17620218822Sdim      /* PC relative addressing on the Thumb is slightly odd as the
17621218822Sdim	 bottom two bits of the PC are forced to zero for the
17622218822Sdim	 calculation.  This happens *after* application of the
17623218822Sdim	 pipeline offset.  However, Thumb adrl already adjusts for
17624218822Sdim	 this, so we need not do it again.  */
17625218822Sdim    case BFD_RELOC_ARM_THUMB_ADD:
17626218822Sdim      return base & ~3;
1762760484Sobrien
17628218822Sdim    case BFD_RELOC_ARM_THUMB_OFFSET:
17629218822Sdim    case BFD_RELOC_ARM_T32_OFFSET_IMM:
17630218822Sdim    case BFD_RELOC_ARM_T32_ADD_PC12:
17631218822Sdim    case BFD_RELOC_ARM_T32_CP_OFF_IMM:
17632218822Sdim      return (base + 4) & ~3;
17633218822Sdim
17634218822Sdim      /* Thumb branches are simply offset by +4.  */
17635218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH7:
17636218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH9:
17637218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH12:
17638218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH20:
17639218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH23:
17640218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH25:
17641218822Sdim    case BFD_RELOC_THUMB_PCREL_BLX:
17642218822Sdim      return base + 4;
17643218822Sdim
17644218822Sdim      /* ARM mode branches are offset by +8.  However, the Windows CE
17645218822Sdim	 loader expects the relocation not to take this into account.  */
17646218822Sdim    case BFD_RELOC_ARM_PCREL_BRANCH:
17647218822Sdim    case BFD_RELOC_ARM_PCREL_CALL:
17648218822Sdim    case BFD_RELOC_ARM_PCREL_JUMP:
17649218822Sdim    case BFD_RELOC_ARM_PCREL_BLX:
17650218822Sdim    case BFD_RELOC_ARM_PLT32:
1765160484Sobrien#ifdef TE_WINCE
17652218822Sdim      /* When handling fixups immediately, because we have already
17653218822Sdim         discovered the value of a symbol, or the address of the frag involved
17654218822Sdim	 we must account for the offset by +8, as the OS loader will never see the reloc.
17655218822Sdim         see fixup_segment() in write.c
17656218822Sdim         The S_IS_EXTERNAL test handles the case of global symbols.
17657218822Sdim         Those need the calculated base, not just the pipe compensation the linker will need.  */
17658218822Sdim      if (fixP->fx_pcrel
17659218822Sdim	  && fixP->fx_addsy != NULL
17660218822Sdim	  && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
17661218822Sdim	  && (S_IS_EXTERNAL (fixP->fx_addsy) || !arm_force_relocation (fixP)))
17662218822Sdim	return base + 8;
17663218822Sdim      return base;
1766460484Sobrien#else
17665218822Sdim      return base + 8;
1766660484Sobrien#endif
1766760484Sobrien
17668218822Sdim      /* ARM mode loads relative to PC are also offset by +8.  Unlike
17669218822Sdim	 branches, the Windows CE loader *does* expect the relocation
17670218822Sdim	 to take this into account.  */
17671218822Sdim    case BFD_RELOC_ARM_OFFSET_IMM:
17672218822Sdim    case BFD_RELOC_ARM_OFFSET_IMM8:
17673218822Sdim    case BFD_RELOC_ARM_HWLITERAL:
17674218822Sdim    case BFD_RELOC_ARM_LITERAL:
17675218822Sdim    case BFD_RELOC_ARM_CP_OFF_IMM:
17676218822Sdim      return base + 8;
1767777298Sobrien
17678218822Sdim
17679218822Sdim      /* Other PC-relative relocations are un-offset.  */
17680218822Sdim    default:
17681218822Sdim      return base;
17682218822Sdim    }
1768360484Sobrien}
1768460484Sobrien
1768577298Sobrien/* Under ELF we need to default _GLOBAL_OFFSET_TABLE.
1768677298Sobrien   Otherwise we have no need to default values of symbols.  */
1768760484Sobrien
1768860484SobriensymbolS *
17689218822Sdimmd_undefined_symbol (char * name ATTRIBUTE_UNUSED)
1769060484Sobrien{
1769160484Sobrien#ifdef OBJ_ELF
1769260484Sobrien  if (name[0] == '_' && name[1] == 'G'
1769360484Sobrien      && streq (name, GLOBAL_OFFSET_TABLE_NAME))
1769460484Sobrien    {
1769560484Sobrien      if (!GOT_symbol)
1769660484Sobrien	{
1769760484Sobrien	  if (symbol_find (name))
1769860484Sobrien	    as_bad ("GOT already in the symbol table");
1769977298Sobrien
1770060484Sobrien	  GOT_symbol = symbol_new (name, undefined_section,
1770177298Sobrien				   (valueT) 0, & zero_address_frag);
1770260484Sobrien	}
1770377298Sobrien
1770460484Sobrien      return GOT_symbol;
1770560484Sobrien    }
1770660484Sobrien#endif
1770777298Sobrien
1770860484Sobrien  return 0;
1770960484Sobrien}
1771060484Sobrien
17711218822Sdim/* Subroutine of md_apply_fix.	 Check to see if an immediate can be
17712218822Sdim   computed as two separate immediate values, added together.  We
17713218822Sdim   already know that this value cannot be computed by just one ARM
17714218822Sdim   instruction.	 */
1771560484Sobrien
17716218822Sdimstatic unsigned int
17717218822Sdimvalidate_immediate_twopart (unsigned int   val,
17718218822Sdim			    unsigned int * highpart)
17719218822Sdim{
17720218822Sdim  unsigned int a;
17721218822Sdim  unsigned int i;
17722218822Sdim
17723218822Sdim  for (i = 0; i < 32; i += 2)
17724218822Sdim    if (((a = rotate_left (val, i)) & 0xff) != 0)
17725218822Sdim      {
17726218822Sdim	if (a & 0xff00)
17727218822Sdim	  {
17728218822Sdim	    if (a & ~ 0xffff)
17729218822Sdim	      continue;
17730218822Sdim	    * highpart = (a  >> 8) | ((i + 24) << 7);
17731218822Sdim	  }
17732218822Sdim	else if (a & 0xff0000)
17733218822Sdim	  {
17734218822Sdim	    if (a & 0xff000000)
17735218822Sdim	      continue;
17736218822Sdim	    * highpart = (a >> 16) | ((i + 16) << 7);
17737218822Sdim	  }
17738218822Sdim	else
17739218822Sdim	  {
17740218822Sdim	    assert (a & 0xff000000);
17741218822Sdim	    * highpart = (a >> 24) | ((i + 8) << 7);
17742218822Sdim	  }
17743218822Sdim
17744218822Sdim	return (a & 0xff) | (i << 7);
17745218822Sdim      }
17746218822Sdim
17747218822Sdim  return FAIL;
17748218822Sdim}
17749218822Sdim
1775060484Sobrienstatic int
17751218822Sdimvalidate_offset_imm (unsigned int val, int hwse)
1775260484Sobrien{
17753218822Sdim  if ((hwse && val > 255) || val > 4095)
17754218822Sdim    return FAIL;
17755218822Sdim  return val;
17756218822Sdim}
1775760484Sobrien
17758218822Sdim/* Subroutine of md_apply_fix.	 Do those data_ops which can take a
17759218822Sdim   negative immediate constant by altering the instruction.  A bit of
17760218822Sdim   a hack really.
17761218822Sdim	MOV <-> MVN
17762218822Sdim	AND <-> BIC
17763218822Sdim	ADC <-> SBC
17764218822Sdim	by inverting the second operand, and
17765218822Sdim	ADD <-> SUB
17766218822Sdim	CMP <-> CMN
17767218822Sdim	by negating the second operand.	 */
17768218822Sdim
17769218822Sdimstatic int
17770218822Sdimnegate_data_op (unsigned long * instruction,
17771218822Sdim		unsigned long	value)
17772218822Sdim{
17773218822Sdim  int op, new_inst;
17774218822Sdim  unsigned long negated, inverted;
17775218822Sdim
17776218822Sdim  negated = encode_arm_immediate (-value);
17777218822Sdim  inverted = encode_arm_immediate (~value);
17778218822Sdim
17779218822Sdim  op = (*instruction >> DATA_OP_SHIFT) & 0xf;
17780218822Sdim  switch (op)
17781218822Sdim    {
17782218822Sdim      /* First negates.	 */
17783218822Sdim    case OPCODE_SUB:		 /* ADD <-> SUB	 */
17784218822Sdim      new_inst = OPCODE_ADD;
17785218822Sdim      value = negated;
17786218822Sdim      break;
17787218822Sdim
17788218822Sdim    case OPCODE_ADD:
17789218822Sdim      new_inst = OPCODE_SUB;
17790218822Sdim      value = negated;
17791218822Sdim      break;
17792218822Sdim
17793218822Sdim    case OPCODE_CMP:		 /* CMP <-> CMN	 */
17794218822Sdim      new_inst = OPCODE_CMN;
17795218822Sdim      value = negated;
17796218822Sdim      break;
17797218822Sdim
17798218822Sdim    case OPCODE_CMN:
17799218822Sdim      new_inst = OPCODE_CMP;
17800218822Sdim      value = negated;
17801218822Sdim      break;
17802218822Sdim
17803218822Sdim      /* Now Inverted ops.  */
17804218822Sdim    case OPCODE_MOV:		 /* MOV <-> MVN	 */
17805218822Sdim      new_inst = OPCODE_MVN;
17806218822Sdim      value = inverted;
17807218822Sdim      break;
17808218822Sdim
17809218822Sdim    case OPCODE_MVN:
17810218822Sdim      new_inst = OPCODE_MOV;
17811218822Sdim      value = inverted;
17812218822Sdim      break;
17813218822Sdim
17814218822Sdim    case OPCODE_AND:		 /* AND <-> BIC	 */
17815218822Sdim      new_inst = OPCODE_BIC;
17816218822Sdim      value = inverted;
17817218822Sdim      break;
17818218822Sdim
17819218822Sdim    case OPCODE_BIC:
17820218822Sdim      new_inst = OPCODE_AND;
17821218822Sdim      value = inverted;
17822218822Sdim      break;
17823218822Sdim
17824218822Sdim    case OPCODE_ADC:		  /* ADC <-> SBC  */
17825218822Sdim      new_inst = OPCODE_SBC;
17826218822Sdim      value = inverted;
17827218822Sdim      break;
17828218822Sdim
17829218822Sdim    case OPCODE_SBC:
17830218822Sdim      new_inst = OPCODE_ADC;
17831218822Sdim      value = inverted;
17832218822Sdim      break;
17833218822Sdim
17834218822Sdim      /* We cannot do anything.	 */
17835218822Sdim    default:
17836218822Sdim      return FAIL;
17837218822Sdim    }
17838218822Sdim
17839218822Sdim  if (value == (unsigned) FAIL)
1784060484Sobrien    return FAIL;
1784160484Sobrien
17842218822Sdim  *instruction &= OPCODE_MASK;
17843218822Sdim  *instruction |= new_inst << DATA_OP_SHIFT;
17844218822Sdim  return value;
17845218822Sdim}
1784660484Sobrien
17847218822Sdim/* Like negate_data_op, but for Thumb-2.   */
1784877298Sobrien
17849218822Sdimstatic unsigned int
17850218822Sdimthumb32_negate_data_op (offsetT *instruction, unsigned int value)
17851218822Sdim{
17852218822Sdim  int op, new_inst;
17853218822Sdim  int rd;
17854218822Sdim  unsigned int negated, inverted;
17855218822Sdim
17856218822Sdim  negated = encode_thumb32_immediate (-value);
17857218822Sdim  inverted = encode_thumb32_immediate (~value);
17858218822Sdim
17859218822Sdim  rd = (*instruction >> 8) & 0xf;
17860218822Sdim  op = (*instruction >> T2_DATA_OP_SHIFT) & 0xf;
17861218822Sdim  switch (op)
1786260484Sobrien    {
17863218822Sdim      /* ADD <-> SUB.  Includes CMP <-> CMN.  */
17864218822Sdim    case T2_OPCODE_SUB:
17865218822Sdim      new_inst = T2_OPCODE_ADD;
17866218822Sdim      value = negated;
17867218822Sdim      break;
17868218822Sdim
17869218822Sdim    case T2_OPCODE_ADD:
17870218822Sdim      new_inst = T2_OPCODE_SUB;
17871218822Sdim      value = negated;
17872218822Sdim      break;
17873218822Sdim
17874218822Sdim      /* ORR <-> ORN.  Includes MOV <-> MVN.  */
17875218822Sdim    case T2_OPCODE_ORR:
17876218822Sdim      new_inst = T2_OPCODE_ORN;
17877218822Sdim      value = inverted;
17878218822Sdim      break;
17879218822Sdim
17880218822Sdim    case T2_OPCODE_ORN:
17881218822Sdim      new_inst = T2_OPCODE_ORR;
17882218822Sdim      value = inverted;
17883218822Sdim      break;
17884218822Sdim
17885218822Sdim      /* AND <-> BIC.  TST has no inverted equivalent.  */
17886218822Sdim    case T2_OPCODE_AND:
17887218822Sdim      new_inst = T2_OPCODE_BIC;
17888218822Sdim      if (rd == 15)
17889218822Sdim	value = FAIL;
17890218822Sdim      else
17891218822Sdim	value = inverted;
17892218822Sdim      break;
17893218822Sdim
17894218822Sdim    case T2_OPCODE_BIC:
17895218822Sdim      new_inst = T2_OPCODE_AND;
17896218822Sdim      value = inverted;
17897218822Sdim      break;
17898218822Sdim
17899218822Sdim      /* ADC <-> SBC  */
17900218822Sdim    case T2_OPCODE_ADC:
17901218822Sdim      new_inst = T2_OPCODE_SBC;
17902218822Sdim      value = inverted;
17903218822Sdim      break;
17904218822Sdim
17905218822Sdim    case T2_OPCODE_SBC:
17906218822Sdim      new_inst = T2_OPCODE_ADC;
17907218822Sdim      value = inverted;
17908218822Sdim      break;
17909218822Sdim
17910218822Sdim      /* We cannot do anything.	 */
17911218822Sdim    default:
17912218822Sdim      return FAIL;
1791360484Sobrien    }
1791460484Sobrien
17915218822Sdim  if (value == (unsigned int)FAIL)
17916218822Sdim    return FAIL;
17917218822Sdim
17918218822Sdim  *instruction &= T2_OPCODE_MASK;
17919218822Sdim  *instruction |= new_inst << T2_DATA_OP_SHIFT;
17920218822Sdim  return value;
1792160484Sobrien}
1792260484Sobrien
17923218822Sdim/* Read a 32-bit thumb instruction from buf.  */
17924218822Sdimstatic unsigned long
17925218822Sdimget_thumb32_insn (char * buf)
1792689857Sobrien{
17927218822Sdim  unsigned long insn;
17928218822Sdim  insn = md_chars_to_number (buf, THUMB_SIZE) << 16;
17929218822Sdim  insn |= md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
1793089857Sobrien
17931218822Sdim  return insn;
17932218822Sdim}
1793389857Sobrien
17934218822Sdim
17935218822Sdim/* We usually want to set the low bit on the address of thumb function
17936218822Sdim   symbols.  In particular .word foo - . should have the low bit set.
17937218822Sdim   Generic code tries to fold the difference of two symbols to
17938218822Sdim   a constant.  Prevent this and force a relocation when the first symbols
17939218822Sdim   is a thumb function.  */
17940218822Sdimint
17941218822Sdimarm_optimize_expr (expressionS *l, operatorT op, expressionS *r)
17942218822Sdim{
17943218822Sdim  if (op == O_subtract
17944218822Sdim      && l->X_op == O_symbol
17945218822Sdim      && r->X_op == O_symbol
17946218822Sdim      && THUMB_IS_FUNC (l->X_add_symbol))
17947218822Sdim    {
17948218822Sdim      l->X_op = O_subtract;
17949218822Sdim      l->X_op_symbol = r->X_add_symbol;
17950218822Sdim      l->X_add_number -= r->X_add_number;
17951218822Sdim      return 1;
17952218822Sdim    }
17953218822Sdim  /* Process as normal.  */
17954218822Sdim  return 0;
1795589857Sobrien}
1795689857Sobrien
1795789857Sobrienvoid
17958218822Sdimmd_apply_fix (fixS *	fixP,
17959218822Sdim	       valueT * valP,
17960218822Sdim	       segT	seg)
1796160484Sobrien{
17962218822Sdim  offsetT	 value = * valP;
17963218822Sdim  offsetT	 newval;
17964218822Sdim  unsigned int	 newimm;
17965218822Sdim  unsigned long	 temp;
17966218822Sdim  int		 sign;
17967218822Sdim  char *	 buf = fixP->fx_where + fixP->fx_frag->fr_literal;
1796860484Sobrien
17969218822Sdim  assert (fixP->fx_r_type <= BFD_RELOC_UNUSED);
1797060484Sobrien
1797160484Sobrien  /* Note whether this will delete the relocation.  */
17972218822Sdim
1797360484Sobrien  if (fixP->fx_addsy == 0 && !fixP->fx_pcrel)
1797460484Sobrien    fixP->fx_done = 1;
1797560484Sobrien
17976218822Sdim  /* On a 64-bit host, silently truncate 'value' to 32 bits for
17977218822Sdim     consistency with the behavior on 32-bit hosts.  Remember value
17978218822Sdim     for emit_reloc.  */
17979218822Sdim  value &= 0xffffffff;
17980218822Sdim  value ^= 0x80000000;
17981218822Sdim  value -= 0x80000000;
1798260484Sobrien
17983218822Sdim  *valP = value;
1798477298Sobrien  fixP->fx_addnumber = value;
1798560484Sobrien
17986218822Sdim  /* Same treatment for fixP->fx_offset.  */
17987218822Sdim  fixP->fx_offset &= 0xffffffff;
17988218822Sdim  fixP->fx_offset ^= 0x80000000;
17989218822Sdim  fixP->fx_offset -= 0x80000000;
17990218822Sdim
1799160484Sobrien  switch (fixP->fx_r_type)
1799260484Sobrien    {
17993218822Sdim    case BFD_RELOC_NONE:
17994218822Sdim      /* This will need to go in the object file.  */
17995218822Sdim      fixP->fx_done = 0;
17996218822Sdim      break;
17997218822Sdim
1799860484Sobrien    case BFD_RELOC_ARM_IMMEDIATE:
17999218822Sdim      /* We claim that this fixup has been processed here,
18000218822Sdim	 even if in fact we generate an error because we do
18001218822Sdim	 not have a reloc for it, so tc_gen_reloc will reject it.  */
18002218822Sdim      fixP->fx_done = 1;
18003218822Sdim
18004218822Sdim      if (fixP->fx_addsy
18005218822Sdim	  && ! S_IS_DEFINED (fixP->fx_addsy))
18006218822Sdim	{
18007218822Sdim	  as_bad_where (fixP->fx_file, fixP->fx_line,
18008218822Sdim			_("undefined symbol %s used as an immediate value"),
18009218822Sdim			S_GET_NAME (fixP->fx_addsy));
18010218822Sdim	  break;
18011218822Sdim	}
18012218822Sdim
18013218822Sdim      newimm = encode_arm_immediate (value);
1801460484Sobrien      temp = md_chars_to_number (buf, INSN_SIZE);
1801560484Sobrien
1801660484Sobrien      /* If the instruction will fail, see if we can fix things up by
1801760484Sobrien	 changing the opcode.  */
1801860484Sobrien      if (newimm == (unsigned int) FAIL
1801960484Sobrien	  && (newimm = negate_data_op (&temp, value)) == (unsigned int) FAIL)
1802060484Sobrien	{
1802160484Sobrien	  as_bad_where (fixP->fx_file, fixP->fx_line,
1802260484Sobrien			_("invalid constant (%lx) after fixup"),
1802360484Sobrien			(unsigned long) value);
1802460484Sobrien	  break;
1802560484Sobrien	}
1802660484Sobrien
1802760484Sobrien      newimm |= (temp & 0xfffff000);
1802860484Sobrien      md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
1802960484Sobrien      break;
1803060484Sobrien
1803160484Sobrien    case BFD_RELOC_ARM_ADRL_IMMEDIATE:
1803260484Sobrien      {
1803360484Sobrien	unsigned int highpart = 0;
1803477298Sobrien	unsigned int newinsn  = 0xe1a00000; /* nop.  */
18035130561Sobrien
18036218822Sdim	newimm = encode_arm_immediate (value);
1803760484Sobrien	temp = md_chars_to_number (buf, INSN_SIZE);
1803860484Sobrien
1803960484Sobrien	/* If the instruction will fail, see if we can fix things up by
18040218822Sdim	   changing the opcode.	 */
1804160484Sobrien	if (newimm == (unsigned int) FAIL
1804260484Sobrien	    && (newimm = negate_data_op (& temp, value)) == (unsigned int) FAIL)
1804360484Sobrien	  {
1804477298Sobrien	    /* No ?  OK - try using two ADD instructions to generate
18045218822Sdim	       the value.  */
1804660484Sobrien	    newimm = validate_immediate_twopart (value, & highpart);
1804760484Sobrien
1804877298Sobrien	    /* Yes - then make sure that the second instruction is
18049218822Sdim	       also an add.  */
1805060484Sobrien	    if (newimm != (unsigned int) FAIL)
1805160484Sobrien	      newinsn = temp;
1805260484Sobrien	    /* Still No ?  Try using a negated value.  */
1805368765Sobrien	    else if ((newimm = validate_immediate_twopart (- value, & highpart)) != (unsigned int) FAIL)
1805477298Sobrien	      temp = newinsn = (temp & OPCODE_MASK) | OPCODE_SUB << DATA_OP_SHIFT;
1805560484Sobrien	    /* Otherwise - give up.  */
1805660484Sobrien	    else
1805760484Sobrien	      {
1805860484Sobrien		as_bad_where (fixP->fx_file, fixP->fx_line,
1805989857Sobrien			      _("unable to compute ADRL instructions for PC offset of 0x%lx"),
18060130561Sobrien			      (long) value);
1806160484Sobrien		break;
1806260484Sobrien	      }
1806360484Sobrien
1806477298Sobrien	    /* Replace the first operand in the 2nd instruction (which
1806577298Sobrien	       is the PC) with the destination register.  We have
1806677298Sobrien	       already added in the PC in the first instruction and we
1806777298Sobrien	       do not want to do it again.  */
1806860484Sobrien	    newinsn &= ~ 0xf0000;
1806960484Sobrien	    newinsn |= ((newinsn & 0x0f000) << 4);
1807060484Sobrien	  }
1807160484Sobrien
1807260484Sobrien	newimm |= (temp & 0xfffff000);
1807360484Sobrien	md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
1807460484Sobrien
1807560484Sobrien	highpart |= (newinsn & 0xfffff000);
1807660484Sobrien	md_number_to_chars (buf + INSN_SIZE, (valueT) highpart, INSN_SIZE);
1807760484Sobrien      }
1807860484Sobrien      break;
1807960484Sobrien
1808060484Sobrien    case BFD_RELOC_ARM_OFFSET_IMM:
18081218822Sdim      if (!fixP->fx_done && seg->use_rela_p)
18082218822Sdim	value = 0;
18083218822Sdim
18084218822Sdim    case BFD_RELOC_ARM_LITERAL:
1808560484Sobrien      sign = value >= 0;
1808677298Sobrien
1808760484Sobrien      if (value < 0)
1808860484Sobrien	value = - value;
1808977298Sobrien
1809060484Sobrien      if (validate_offset_imm (value, 0) == FAIL)
1809177298Sobrien	{
18092218822Sdim	  if (fixP->fx_r_type == BFD_RELOC_ARM_LITERAL)
18093218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
18094218822Sdim			  _("invalid literal constant: pool needs to be closer"));
18095218822Sdim	  else
18096218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
18097218822Sdim			  _("bad immediate value for offset (%ld)"),
18098218822Sdim			  (long) value);
1809977298Sobrien	  break;
1810077298Sobrien	}
1810160484Sobrien
1810260484Sobrien      newval = md_chars_to_number (buf, INSN_SIZE);
1810360484Sobrien      newval &= 0xff7ff000;
1810460484Sobrien      newval |= value | (sign ? INDEX_UP : 0);
1810560484Sobrien      md_number_to_chars (buf, newval, INSN_SIZE);
1810660484Sobrien      break;
1810760484Sobrien
1810877298Sobrien    case BFD_RELOC_ARM_OFFSET_IMM8:
1810977298Sobrien    case BFD_RELOC_ARM_HWLITERAL:
1811060484Sobrien      sign = value >= 0;
1811177298Sobrien
1811260484Sobrien      if (value < 0)
1811360484Sobrien	value = - value;
1811460484Sobrien
1811560484Sobrien      if (validate_offset_imm (value, 1) == FAIL)
1811677298Sobrien	{
1811777298Sobrien	  if (fixP->fx_r_type == BFD_RELOC_ARM_HWLITERAL)
1811877298Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
1811977298Sobrien			  _("invalid literal constant: pool needs to be closer"));
1812077298Sobrien	  else
18121218822Sdim	    as_bad (_("bad immediate value for 8-bit offset (%ld)"),
1812260484Sobrien		    (long) value);
1812377298Sobrien	  break;
1812477298Sobrien	}
1812560484Sobrien
1812660484Sobrien      newval = md_chars_to_number (buf, INSN_SIZE);
1812760484Sobrien      newval &= 0xff7ff0f0;
1812860484Sobrien      newval |= ((value >> 4) << 8) | (value & 0xf) | (sign ? INDEX_UP : 0);
1812960484Sobrien      md_number_to_chars (buf, newval, INSN_SIZE);
1813060484Sobrien      break;
1813160484Sobrien
18132218822Sdim    case BFD_RELOC_ARM_T32_OFFSET_U8:
18133218822Sdim      if (value < 0 || value > 1020 || value % 4 != 0)
18134218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18135218822Sdim		      _("bad immediate value for offset (%ld)"), (long) value);
18136218822Sdim      value /= 4;
1813777298Sobrien
18138218822Sdim      newval = md_chars_to_number (buf+2, THUMB_SIZE);
18139218822Sdim      newval |= value;
18140218822Sdim      md_number_to_chars (buf+2, newval, THUMB_SIZE);
18141218822Sdim      break;
1814260484Sobrien
18143218822Sdim    case BFD_RELOC_ARM_T32_OFFSET_IMM:
18144218822Sdim      /* This is a complicated relocation used for all varieties of Thumb32
18145218822Sdim	 load/store instruction with immediate offset:
18146218822Sdim
18147218822Sdim	 1110 100P u1WL NNNN XXXX YYYY iiii iiii - +/-(U) pre/post(P) 8-bit,
18148218822Sdim	                                           *4, optional writeback(W)
18149218822Sdim						   (doubleword load/store)
18150218822Sdim
18151218822Sdim	 1111 100S uTTL 1111 XXXX iiii iiii iiii - +/-(U) 12-bit PC-rel
18152218822Sdim	 1111 100S 0TTL NNNN XXXX 1Pu1 iiii iiii - +/-(U) pre/post(P) 8-bit
18153218822Sdim	 1111 100S 0TTL NNNN XXXX 1110 iiii iiii - positive 8-bit (T instruction)
18154218822Sdim	 1111 100S 1TTL NNNN XXXX iiii iiii iiii - positive 12-bit
18155218822Sdim	 1111 100S 0TTL NNNN XXXX 1100 iiii iiii - negative 8-bit
18156218822Sdim
18157218822Sdim	 Uppercase letters indicate bits that are already encoded at
18158218822Sdim	 this point.  Lowercase letters are our problem.  For the
18159218822Sdim	 second block of instructions, the secondary opcode nybble
18160218822Sdim	 (bits 8..11) is present, and bit 23 is zero, even if this is
18161218822Sdim	 a PC-relative operation.  */
18162218822Sdim      newval = md_chars_to_number (buf, THUMB_SIZE);
18163218822Sdim      newval <<= 16;
18164218822Sdim      newval |= md_chars_to_number (buf+THUMB_SIZE, THUMB_SIZE);
18165218822Sdim
18166218822Sdim      if ((newval & 0xf0000000) == 0xe0000000)
1816760484Sobrien	{
18168218822Sdim	  /* Doubleword load/store: 8-bit offset, scaled by 4.  */
18169218822Sdim	  if (value >= 0)
18170218822Sdim	    newval |= (1 << 23);
18171218822Sdim	  else
18172218822Sdim	    value = -value;
18173218822Sdim	  if (value % 4 != 0)
18174218822Sdim	    {
18175218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18176218822Sdim			    _("offset not a multiple of 4"));
18177218822Sdim	      break;
18178218822Sdim	    }
18179218822Sdim	  value /= 4;
18180218822Sdim	  if (value > 0xff)
18181218822Sdim	    {
18182218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18183218822Sdim			    _("offset out of range"));
18184218822Sdim	      break;
18185218822Sdim	    }
18186218822Sdim	  newval &= ~0xff;
1818760484Sobrien	}
18188218822Sdim      else if ((newval & 0x000f0000) == 0x000f0000)
18189218822Sdim	{
18190218822Sdim	  /* PC-relative, 12-bit offset.  */
18191218822Sdim	  if (value >= 0)
18192218822Sdim	    newval |= (1 << 23);
18193218822Sdim	  else
18194218822Sdim	    value = -value;
18195218822Sdim	  if (value > 0xfff)
18196218822Sdim	    {
18197218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18198218822Sdim			    _("offset out of range"));
18199218822Sdim	      break;
18200218822Sdim	    }
18201218822Sdim	  newval &= ~0xfff;
18202218822Sdim	}
18203218822Sdim      else if ((newval & 0x00000100) == 0x00000100)
18204218822Sdim	{
18205218822Sdim	  /* Writeback: 8-bit, +/- offset.  */
18206218822Sdim	  if (value >= 0)
18207218822Sdim	    newval |= (1 << 9);
18208218822Sdim	  else
18209218822Sdim	    value = -value;
18210218822Sdim	  if (value > 0xff)
18211218822Sdim	    {
18212218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18213218822Sdim			    _("offset out of range"));
18214218822Sdim	      break;
18215218822Sdim	    }
18216218822Sdim	  newval &= ~0xff;
18217218822Sdim	}
18218218822Sdim      else if ((newval & 0x00000f00) == 0x00000e00)
18219218822Sdim	{
18220218822Sdim	  /* T-instruction: positive 8-bit offset.  */
18221218822Sdim	  if (value < 0 || value > 0xff)
18222218822Sdim	    {
18223218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18224218822Sdim			    _("offset out of range"));
18225218822Sdim	      break;
18226218822Sdim	    }
18227218822Sdim	  newval &= ~0xff;
18228218822Sdim	  newval |= value;
18229218822Sdim	}
18230218822Sdim      else
18231218822Sdim	{
18232218822Sdim	  /* Positive 12-bit or negative 8-bit offset.  */
18233218822Sdim	  int limit;
18234218822Sdim	  if (value >= 0)
18235218822Sdim	    {
18236218822Sdim	      newval |= (1 << 23);
18237218822Sdim	      limit = 0xfff;
18238218822Sdim	    }
18239218822Sdim	  else
18240218822Sdim	    {
18241218822Sdim	      value = -value;
18242218822Sdim	      limit = 0xff;
18243218822Sdim	    }
18244218822Sdim	  if (value > limit)
18245218822Sdim	    {
18246218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18247218822Sdim			    _("offset out of range"));
18248218822Sdim	      break;
18249218822Sdim	    }
18250218822Sdim	  newval &= ~limit;
18251218822Sdim	}
1825260484Sobrien
18253218822Sdim      newval |= value;
18254218822Sdim      md_number_to_chars (buf, (newval >> 16) & 0xffff, THUMB_SIZE);
18255218822Sdim      md_number_to_chars (buf + THUMB_SIZE, newval & 0xffff, THUMB_SIZE);
1825660484Sobrien      break;
1825760484Sobrien
1825860484Sobrien    case BFD_RELOC_ARM_SHIFT_IMM:
1825960484Sobrien      newval = md_chars_to_number (buf, INSN_SIZE);
1826060484Sobrien      if (((unsigned long) value) > 32
1826177298Sobrien	  || (value == 32
1826260484Sobrien	      && (((newval & 0x60) == 0) || (newval & 0x60) == 0x60)))
1826360484Sobrien	{
1826460484Sobrien	  as_bad_where (fixP->fx_file, fixP->fx_line,
1826560484Sobrien			_("shift expression is too large"));
1826660484Sobrien	  break;
1826760484Sobrien	}
1826860484Sobrien
1826960484Sobrien      if (value == 0)
18270218822Sdim	/* Shifts of zero must be done as lsl.	*/
1827177298Sobrien	newval &= ~0x60;
1827260484Sobrien      else if (value == 32)
1827360484Sobrien	value = 0;
1827460484Sobrien      newval &= 0xfffff07f;
1827560484Sobrien      newval |= (value & 0x1f) << 7;
1827677298Sobrien      md_number_to_chars (buf, newval, INSN_SIZE);
1827760484Sobrien      break;
1827860484Sobrien
18279218822Sdim    case BFD_RELOC_ARM_T32_IMMEDIATE:
18280218822Sdim    case BFD_RELOC_ARM_T32_ADD_IMM:
18281218822Sdim    case BFD_RELOC_ARM_T32_IMM12:
18282218822Sdim    case BFD_RELOC_ARM_T32_ADD_PC12:
18283218822Sdim      /* We claim that this fixup has been processed here,
18284218822Sdim	 even if in fact we generate an error because we do
18285218822Sdim	 not have a reloc for it, so tc_gen_reloc will reject it.  */
18286218822Sdim      fixP->fx_done = 1;
18287218822Sdim
18288218822Sdim      if (fixP->fx_addsy
18289218822Sdim	  && ! S_IS_DEFINED (fixP->fx_addsy))
18290218822Sdim	{
18291218822Sdim	  as_bad_where (fixP->fx_file, fixP->fx_line,
18292218822Sdim			_("undefined symbol %s used as an immediate value"),
18293218822Sdim			S_GET_NAME (fixP->fx_addsy));
18294218822Sdim	  break;
18295218822Sdim	}
18296218822Sdim
18297218822Sdim      newval = md_chars_to_number (buf, THUMB_SIZE);
18298218822Sdim      newval <<= 16;
18299218822Sdim      newval |= md_chars_to_number (buf+2, THUMB_SIZE);
18300218822Sdim
18301218822Sdim      newimm = FAIL;
18302218822Sdim      if (fixP->fx_r_type == BFD_RELOC_ARM_T32_IMMEDIATE
18303218822Sdim	  || fixP->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM)
18304218822Sdim	{
18305218822Sdim	  newimm = encode_thumb32_immediate (value);
18306218822Sdim	  if (newimm == (unsigned int) FAIL)
18307218822Sdim	    newimm = thumb32_negate_data_op (&newval, value);
18308218822Sdim	}
18309218822Sdim      if (fixP->fx_r_type != BFD_RELOC_ARM_T32_IMMEDIATE
18310218822Sdim	  && newimm == (unsigned int) FAIL)
18311218822Sdim	{
18312218822Sdim	  /* Turn add/sum into addw/subw.  */
18313218822Sdim	  if (fixP->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM)
18314218822Sdim	    newval = (newval & 0xfeffffff) | 0x02000000;
18315218822Sdim
18316218822Sdim	  /* 12 bit immediate for addw/subw.  */
18317218822Sdim	  if (value < 0)
18318218822Sdim	    {
18319218822Sdim	      value = -value;
18320218822Sdim	      newval ^= 0x00a00000;
18321218822Sdim	    }
18322218822Sdim	  if (value > 0xfff)
18323218822Sdim	    newimm = (unsigned int) FAIL;
18324218822Sdim	  else
18325218822Sdim	    newimm = value;
18326218822Sdim	}
18327218822Sdim
18328218822Sdim      if (newimm == (unsigned int)FAIL)
18329218822Sdim	{
18330218822Sdim	  as_bad_where (fixP->fx_file, fixP->fx_line,
18331218822Sdim			_("invalid constant (%lx) after fixup"),
18332218822Sdim			(unsigned long) value);
18333218822Sdim	  break;
18334218822Sdim	}
18335218822Sdim
18336218822Sdim      newval |= (newimm & 0x800) << 15;
18337218822Sdim      newval |= (newimm & 0x700) << 4;
18338218822Sdim      newval |= (newimm & 0x0ff);
18339218822Sdim
18340218822Sdim      md_number_to_chars (buf,   (valueT) ((newval >> 16) & 0xffff), THUMB_SIZE);
18341218822Sdim      md_number_to_chars (buf+2, (valueT) (newval & 0xffff), THUMB_SIZE);
18342218822Sdim      break;
18343218822Sdim
18344218822Sdim    case BFD_RELOC_ARM_SMC:
18345218822Sdim      if (((unsigned long) value) > 0xffff)
18346218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18347218822Sdim		      _("invalid smc expression"));
18348218822Sdim      newval = md_chars_to_number (buf, INSN_SIZE);
18349218822Sdim      newval |= (value & 0xf) | ((value & 0xfff0) << 4);
18350218822Sdim      md_number_to_chars (buf, newval, INSN_SIZE);
18351218822Sdim      break;
18352218822Sdim
1835360484Sobrien    case BFD_RELOC_ARM_SWI:
18354218822Sdim      if (fixP->tc_fix_data != 0)
1835560484Sobrien	{
1835660484Sobrien	  if (((unsigned long) value) > 0xff)
1835760484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
1835889857Sobrien			  _("invalid swi expression"));
18359218822Sdim	  newval = md_chars_to_number (buf, THUMB_SIZE);
1836060484Sobrien	  newval |= value;
1836160484Sobrien	  md_number_to_chars (buf, newval, THUMB_SIZE);
1836260484Sobrien	}
1836360484Sobrien      else
1836460484Sobrien	{
1836560484Sobrien	  if (((unsigned long) value) > 0x00ffffff)
1836677298Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
1836789857Sobrien			  _("invalid swi expression"));
18368218822Sdim	  newval = md_chars_to_number (buf, INSN_SIZE);
1836960484Sobrien	  newval |= value;
1837077298Sobrien	  md_number_to_chars (buf, newval, INSN_SIZE);
1837160484Sobrien	}
1837260484Sobrien      break;
1837360484Sobrien
1837460484Sobrien    case BFD_RELOC_ARM_MULTI:
1837560484Sobrien      if (((unsigned long) value) > 0xffff)
1837660484Sobrien	as_bad_where (fixP->fx_file, fixP->fx_line,
1837789857Sobrien		      _("invalid expression in load/store multiple"));
1837860484Sobrien      newval = value | md_chars_to_number (buf, INSN_SIZE);
1837960484Sobrien      md_number_to_chars (buf, newval, INSN_SIZE);
1838060484Sobrien      break;
1838160484Sobrien
18382218822Sdim#ifdef OBJ_ELF
18383218822Sdim    case BFD_RELOC_ARM_PCREL_CALL:
1838460484Sobrien      newval = md_chars_to_number (buf, INSN_SIZE);
18385218822Sdim      if ((newval & 0xf0000000) == 0xf0000000)
18386218822Sdim	temp = 1;
18387218822Sdim      else
18388218822Sdim	temp = 3;
18389218822Sdim      goto arm_branch_common;
1839060484Sobrien
18391218822Sdim    case BFD_RELOC_ARM_PCREL_JUMP:
18392218822Sdim    case BFD_RELOC_ARM_PLT32:
1839360484Sobrien#endif
18394218822Sdim    case BFD_RELOC_ARM_PCREL_BRANCH:
18395218822Sdim      temp = 3;
18396218822Sdim      goto arm_branch_common;
1839760484Sobrien
18398218822Sdim    case BFD_RELOC_ARM_PCREL_BLX:
18399218822Sdim      temp = 1;
18400218822Sdim    arm_branch_common:
1840160484Sobrien      /* We are going to store value (shifted right by two) in the
18402218822Sdim	 instruction, in a 24 bit, signed field.  Bits 26 through 32 either
18403218822Sdim	 all clear or all set and bit 0 must be clear.  For B/BL bit 1 must
18404218822Sdim	 also be be clear.  */
18405218822Sdim      if (value & temp)
18406218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18407218822Sdim		      _("misaligned branch destination"));
18408218822Sdim      if ((value & (offsetT)0xfe000000) != (offsetT)0
18409218822Sdim	  && (value & (offsetT)0xfe000000) != (offsetT)0xfe000000)
18410218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18411218822Sdim		      _("branch out of range"));
18412218822Sdim
18413218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
1841460484Sobrien	{
18415218822Sdim	  newval = md_chars_to_number (buf, INSN_SIZE);
18416218822Sdim	  newval |= (value >> 2) & 0x00ffffff;
18417218822Sdim	  /* Set the H bit on BLX instructions.  */
18418218822Sdim	  if (temp == 1)
1841960484Sobrien	    {
18420218822Sdim	      if (value & 2)
18421218822Sdim		newval |= 0x01000000;
18422218822Sdim	      else
18423218822Sdim		newval &= ~0x01000000;
1842460484Sobrien	    }
18425218822Sdim	  md_number_to_chars (buf, newval, INSN_SIZE);
18426218822Sdim	}
18427218822Sdim      break;
1842877298Sobrien
18429218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH7: /* CBZ */
18430218822Sdim      /* CBZ can only branch forward.  */
18431218822Sdim
18432218822Sdim      /* Attempts to use CBZ to branch to the next instruction
18433218822Sdim         (which, strictly speaking, are prohibited) will be turned into
18434218822Sdim         no-ops.
18435218822Sdim
18436218822Sdim	 FIXME: It may be better to remove the instruction completely and
18437218822Sdim	 perform relaxation.  */
18438218822Sdim      if (value == -2)
18439218822Sdim	{
18440218822Sdim	  newval = md_chars_to_number (buf, THUMB_SIZE);
18441218822Sdim	  newval = 0xbf00; /* NOP encoding T1 */
18442218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18443218822Sdim	}
18444218822Sdim      else
18445218822Sdim	{
18446218822Sdim	  if (value & ~0x7e)
1844760484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18448218822Sdim		          _("branch out of range"));
18449218822Sdim
18450218822Sdim          if (fixP->fx_done || !seg->use_rela_p)
18451218822Sdim	    {
18452218822Sdim	      newval = md_chars_to_number (buf, THUMB_SIZE);
18453218822Sdim	      newval |= ((value & 0x3e) << 2) | ((value & 0x40) << 3);
18454218822Sdim	      md_number_to_chars (buf, newval, THUMB_SIZE);
18455218822Sdim	    }
1845660484Sobrien	}
18457218822Sdim      break;
1845860484Sobrien
18459218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH9: /* Conditional branch.	*/
18460218822Sdim      if ((value & ~0xff) && ((value & ~0xff) != ~0xff))
1846160484Sobrien	as_bad_where (fixP->fx_file, fixP->fx_line,
18462218822Sdim		      _("branch out of range"));
1846377298Sobrien
18464218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18465218822Sdim	{
18466218822Sdim	  newval = md_chars_to_number (buf, THUMB_SIZE);
18467218822Sdim	  newval |= (value & 0x1ff) >> 1;
18468218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18469218822Sdim	}
1847060484Sobrien      break;
1847160484Sobrien
18472218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH12: /* Unconditional branch.  */
18473218822Sdim      if ((value & ~0x7ff) && ((value & ~0x7ff) != ~0x7ff))
18474218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18475218822Sdim		      _("branch out of range"));
1847660484Sobrien
18477218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18478218822Sdim	{
18479218822Sdim	  newval = md_chars_to_number (buf, THUMB_SIZE);
18480218822Sdim	  newval |= (value & 0xfff) >> 1;
18481218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18482218822Sdim	}
1848377298Sobrien      break;
1848477298Sobrien
18485218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH20:
18486218822Sdim      if ((value & ~0x1fffff) && ((value & ~0x1fffff) != ~0x1fffff))
18487218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18488218822Sdim		      _("conditional branch out of range"));
1848960484Sobrien
18490218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18491218822Sdim	{
18492218822Sdim	  offsetT newval2;
18493218822Sdim	  addressT S, J1, J2, lo, hi;
1849460484Sobrien
18495218822Sdim	  S  = (value & 0x00100000) >> 20;
18496218822Sdim	  J2 = (value & 0x00080000) >> 19;
18497218822Sdim	  J1 = (value & 0x00040000) >> 18;
18498218822Sdim	  hi = (value & 0x0003f000) >> 12;
18499218822Sdim	  lo = (value & 0x00000ffe) >> 1;
1850060484Sobrien
18501218822Sdim	  newval   = md_chars_to_number (buf, THUMB_SIZE);
18502218822Sdim	  newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
18503218822Sdim	  newval  |= (S << 10) | hi;
18504218822Sdim	  newval2 |= (J1 << 13) | (J2 << 11) | lo;
18505218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18506218822Sdim	  md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
18507218822Sdim	}
1850860484Sobrien      break;
1850960484Sobrien
1851077298Sobrien    case BFD_RELOC_THUMB_PCREL_BLX:
1851160484Sobrien    case BFD_RELOC_THUMB_PCREL_BRANCH23:
18512218822Sdim      if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff))
18513218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18514218822Sdim		      _("branch out of range"));
1851560484Sobrien
18516218822Sdim      if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
18517218822Sdim	/* For a BLX instruction, make sure that the relocation is rounded up
18518218822Sdim	   to a word boundary.  This follows the semantics of the instruction
18519218822Sdim	   which specifies that bit 1 of the target address will come from bit
18520218822Sdim	   1 of the base address.  */
18521218822Sdim	value = (value + 1) & ~ 1;
18522104834Sobrien
18523218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18524218822Sdim	{
18525218822Sdim	  offsetT newval2;
1852660484Sobrien
18527218822Sdim	  newval   = md_chars_to_number (buf, THUMB_SIZE);
18528218822Sdim	  newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
18529218822Sdim	  newval  |= (value & 0x7fffff) >> 12;
18530218822Sdim	  newval2 |= (value & 0xfff) >> 1;
18531218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18532218822Sdim	  md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
18533218822Sdim	}
1853460484Sobrien      break;
1853560484Sobrien
18536218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH25:
18537218822Sdim      if ((value & ~0x1ffffff) && ((value & ~0x1ffffff) != ~0x1ffffff))
18538218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18539218822Sdim		      _("branch out of range"));
18540218822Sdim
18541218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
1854277298Sobrien	{
18543218822Sdim	  offsetT newval2;
18544218822Sdim	  addressT S, I1, I2, lo, hi;
18545218822Sdim
18546218822Sdim	  S  = (value & 0x01000000) >> 24;
18547218822Sdim	  I1 = (value & 0x00800000) >> 23;
18548218822Sdim	  I2 = (value & 0x00400000) >> 22;
18549218822Sdim	  hi = (value & 0x003ff000) >> 12;
18550218822Sdim	  lo = (value & 0x00000ffe) >> 1;
18551218822Sdim
18552218822Sdim	  I1 = !(I1 ^ S);
18553218822Sdim	  I2 = !(I2 ^ S);
18554218822Sdim
18555218822Sdim	  newval   = md_chars_to_number (buf, THUMB_SIZE);
18556218822Sdim	  newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
18557218822Sdim	  newval  |= (S << 10) | hi;
18558218822Sdim	  newval2 |= (I1 << 13) | (I2 << 11) | lo;
18559218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18560218822Sdim	  md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
1856177298Sobrien	}
1856260484Sobrien      break;
1856360484Sobrien
18564218822Sdim    case BFD_RELOC_8:
18565218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18566218822Sdim	md_number_to_chars (buf, value, 1);
18567218822Sdim      break;
18568218822Sdim
1856960484Sobrien    case BFD_RELOC_16:
18570218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
1857160484Sobrien	md_number_to_chars (buf, value, 2);
1857260484Sobrien      break;
1857360484Sobrien
1857460484Sobrien#ifdef OBJ_ELF
18575218822Sdim    case BFD_RELOC_ARM_TLS_GD32:
18576218822Sdim    case BFD_RELOC_ARM_TLS_LE32:
18577218822Sdim    case BFD_RELOC_ARM_TLS_IE32:
18578218822Sdim    case BFD_RELOC_ARM_TLS_LDM32:
18579218822Sdim    case BFD_RELOC_ARM_TLS_LDO32:
18580218822Sdim      S_SET_THREAD_LOCAL (fixP->fx_addsy);
18581218822Sdim      /* fall through */
18582218822Sdim
1858360484Sobrien    case BFD_RELOC_ARM_GOT32:
1858460484Sobrien    case BFD_RELOC_ARM_GOTOFF:
18585218822Sdim    case BFD_RELOC_ARM_TARGET2:
18586218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18587218822Sdim	md_number_to_chars (buf, 0, 4);
1858877298Sobrien      break;
1858960484Sobrien#endif
1859060484Sobrien
1859160484Sobrien    case BFD_RELOC_RVA:
1859260484Sobrien    case BFD_RELOC_32:
18593218822Sdim    case BFD_RELOC_ARM_TARGET1:
18594218822Sdim    case BFD_RELOC_ARM_ROSEGREL32:
18595218822Sdim    case BFD_RELOC_ARM_SBREL32:
18596218822Sdim    case BFD_RELOC_32_PCREL:
18597218822Sdim#ifdef TE_PE
18598218822Sdim    case BFD_RELOC_32_SECREL:
18599218822Sdim#endif
18600218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18601218822Sdim#ifdef TE_WINCE
18602218822Sdim	/* For WinCE we only do this for pcrel fixups.  */
18603218822Sdim	if (fixP->fx_done || fixP->fx_pcrel)
18604218822Sdim#endif
1860577298Sobrien	  md_number_to_chars (buf, value, 4);
1860660484Sobrien      break;
1860760484Sobrien
1860860484Sobrien#ifdef OBJ_ELF
18609218822Sdim    case BFD_RELOC_ARM_PREL31:
18610218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18611218822Sdim	{
18612218822Sdim	  newval = md_chars_to_number (buf, 4) & 0x80000000;
18613218822Sdim	  if ((value ^ (value >> 1)) & 0x40000000)
18614218822Sdim	    {
18615218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18616218822Sdim			    _("rel31 relocation overflow"));
18617218822Sdim	    }
18618218822Sdim	  newval |= value & 0x7fffffff;
18619218822Sdim	  md_number_to_chars (buf, newval, 4);
18620218822Sdim	}
1862160484Sobrien      break;
1862260484Sobrien#endif
1862360484Sobrien
1862460484Sobrien    case BFD_RELOC_ARM_CP_OFF_IMM:
18625218822Sdim    case BFD_RELOC_ARM_T32_CP_OFF_IMM:
1862660484Sobrien      if (value < -1023 || value > 1023 || (value & 3))
1862760484Sobrien	as_bad_where (fixP->fx_file, fixP->fx_line,
18628218822Sdim		      _("co-processor offset out of range"));
18629218822Sdim    cp_off_common:
18630218822Sdim      sign = value >= 0;
1863160484Sobrien      if (value < 0)
1863260484Sobrien	value = -value;
18633218822Sdim      if (fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM
18634218822Sdim	  || fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM_S2)
18635218822Sdim	newval = md_chars_to_number (buf, INSN_SIZE);
18636218822Sdim      else
18637218822Sdim	newval = get_thumb32_insn (buf);
18638218822Sdim      newval &= 0xff7fff00;
1863977298Sobrien      newval |= (value >> 2) | (sign ? INDEX_UP : 0);
18640218822Sdim      if (fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM
18641218822Sdim	  || fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM_S2)
18642218822Sdim	md_number_to_chars (buf, newval, INSN_SIZE);
18643218822Sdim      else
18644218822Sdim	put_thumb32_insn (buf, newval);
1864560484Sobrien      break;
1864660484Sobrien
18647130561Sobrien    case BFD_RELOC_ARM_CP_OFF_IMM_S2:
18648218822Sdim    case BFD_RELOC_ARM_T32_CP_OFF_IMM_S2:
18649130561Sobrien      if (value < -255 || value > 255)
18650218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18651218822Sdim		      _("co-processor offset out of range"));
18652218822Sdim      value *= 4;
18653218822Sdim      goto cp_off_common;
18654130561Sobrien
1865560484Sobrien    case BFD_RELOC_ARM_THUMB_OFFSET:
1865660484Sobrien      newval = md_chars_to_number (buf, THUMB_SIZE);
1865777298Sobrien      /* Exactly what ranges, and where the offset is inserted depends
1865877298Sobrien	 on the type of instruction, we can establish this from the
1865977298Sobrien	 top 4 bits.  */
1866060484Sobrien      switch (newval >> 12)
1866160484Sobrien	{
1866277298Sobrien	case 4: /* PC load.  */
1866360484Sobrien	  /* Thumb PC loads are somewhat odd, bit 1 of the PC is
18664218822Sdim	     forced to zero for these loads; md_pcrel_from has already
18665218822Sdim	     compensated for this.  */
18666218822Sdim	  if (value & 3)
1866760484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18668218822Sdim			  _("invalid offset, target not word aligned (0x%08lX)"),
18669218822Sdim			  (((unsigned long) fixP->fx_frag->fr_address
18670218822Sdim			    + (unsigned long) fixP->fx_where) & ~3)
18671218822Sdim			  + (unsigned long) value);
1867260484Sobrien
18673218822Sdim	  if (value & ~0x3fc)
1867460484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18675130561Sobrien			  _("invalid offset, value too big (0x%08lX)"),
18676130561Sobrien			  (long) value);
1867760484Sobrien
18678218822Sdim	  newval |= value >> 2;
1867960484Sobrien	  break;
1868060484Sobrien
1868177298Sobrien	case 9: /* SP load/store.  */
1868260484Sobrien	  if (value & ~0x3fc)
1868360484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18684130561Sobrien			  _("invalid offset, value too big (0x%08lX)"),
18685130561Sobrien			  (long) value);
1868660484Sobrien	  newval |= value >> 2;
1868760484Sobrien	  break;
1868860484Sobrien
1868977298Sobrien	case 6: /* Word load/store.  */
1869060484Sobrien	  if (value & ~0x7c)
1869160484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18692130561Sobrien			  _("invalid offset, value too big (0x%08lX)"),
18693130561Sobrien			  (long) value);
1869477298Sobrien	  newval |= value << 4; /* 6 - 2.  */
1869560484Sobrien	  break;
1869660484Sobrien
1869777298Sobrien	case 7: /* Byte load/store.  */
1869860484Sobrien	  if (value & ~0x1f)
1869960484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18700130561Sobrien			  _("invalid offset, value too big (0x%08lX)"),
18701130561Sobrien			  (long) value);
1870260484Sobrien	  newval |= value << 6;
1870360484Sobrien	  break;
1870460484Sobrien
18705218822Sdim	case 8: /* Halfword load/store.	 */
1870660484Sobrien	  if (value & ~0x3e)
1870760484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18708130561Sobrien			  _("invalid offset, value too big (0x%08lX)"),
18709130561Sobrien			  (long) value);
1871077298Sobrien	  newval |= value << 5; /* 6 - 1.  */
1871160484Sobrien	  break;
1871260484Sobrien
1871360484Sobrien	default:
1871460484Sobrien	  as_bad_where (fixP->fx_file, fixP->fx_line,
1871560484Sobrien			"Unable to process relocation for thumb opcode: %lx",
1871660484Sobrien			(unsigned long) newval);
1871760484Sobrien	  break;
1871860484Sobrien	}
1871960484Sobrien      md_number_to_chars (buf, newval, THUMB_SIZE);
1872060484Sobrien      break;
1872160484Sobrien
1872260484Sobrien    case BFD_RELOC_ARM_THUMB_ADD:
1872360484Sobrien      /* This is a complicated relocation, since we use it for all of
18724218822Sdim	 the following immediate relocations:
1872560484Sobrien
1872677298Sobrien	    3bit ADD/SUB
1872777298Sobrien	    8bit ADD/SUB
1872877298Sobrien	    9bit ADD/SUB SP word-aligned
1872977298Sobrien	   10bit ADD PC/SP word-aligned
1873077298Sobrien
18731218822Sdim	 The type of instruction being processed is encoded in the
18732218822Sdim	 instruction field:
1873377298Sobrien
1873477298Sobrien	   0x8000  SUB
1873577298Sobrien	   0x00F0  Rd
1873677298Sobrien	   0x000F  Rs
1873760484Sobrien      */
1873860484Sobrien      newval = md_chars_to_number (buf, THUMB_SIZE);
1873960484Sobrien      {
1874077298Sobrien	int rd = (newval >> 4) & 0xf;
1874177298Sobrien	int rs = newval & 0xf;
18742218822Sdim	int subtract = !!(newval & 0x8000);
1874360484Sobrien
18744218822Sdim	/* Check for HI regs, only very restricted cases allowed:
18745218822Sdim	   Adjusting SP, and using PC or SP to get an address.	*/
18746218822Sdim	if ((rd > 7 && (rd != REG_SP || rs != REG_SP))
18747218822Sdim	    || (rs > 7 && rs != REG_SP && rs != REG_PC))
18748218822Sdim	  as_bad_where (fixP->fx_file, fixP->fx_line,
18749218822Sdim			_("invalid Hi register with immediate"));
18750218822Sdim
18751218822Sdim	/* If value is negative, choose the opposite instruction.  */
18752218822Sdim	if (value < 0)
18753218822Sdim	  {
18754218822Sdim	    value = -value;
18755218822Sdim	    subtract = !subtract;
18756218822Sdim	    if (value < 0)
18757218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18758218822Sdim			    _("immediate value out of range"));
18759218822Sdim	  }
18760218822Sdim
1876177298Sobrien	if (rd == REG_SP)
1876277298Sobrien	  {
1876377298Sobrien	    if (value & ~0x1fc)
1876477298Sobrien	      as_bad_where (fixP->fx_file, fixP->fx_line,
1876589857Sobrien			    _("invalid immediate for stack address calculation"));
1876677298Sobrien	    newval = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
1876777298Sobrien	    newval |= value >> 2;
1876877298Sobrien	  }
1876977298Sobrien	else if (rs == REG_PC || rs == REG_SP)
1877077298Sobrien	  {
18771218822Sdim	    if (subtract || value & ~0x3fc)
1877277298Sobrien	      as_bad_where (fixP->fx_file, fixP->fx_line,
1877389857Sobrien			    _("invalid immediate for address calculation (value = 0x%08lX)"),
1877460484Sobrien			    (unsigned long) value);
1877577298Sobrien	    newval = (rs == REG_PC ? T_OPCODE_ADD_PC : T_OPCODE_ADD_SP);
1877677298Sobrien	    newval |= rd << 8;
1877777298Sobrien	    newval |= value >> 2;
1877877298Sobrien	  }
1877977298Sobrien	else if (rs == rd)
1878077298Sobrien	  {
1878177298Sobrien	    if (value & ~0xff)
1878277298Sobrien	      as_bad_where (fixP->fx_file, fixP->fx_line,
18783218822Sdim			    _("immediate value out of range"));
1878477298Sobrien	    newval = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8;
1878577298Sobrien	    newval |= (rd << 8) | value;
1878677298Sobrien	  }
1878777298Sobrien	else
1878877298Sobrien	  {
1878977298Sobrien	    if (value & ~0x7)
1879077298Sobrien	      as_bad_where (fixP->fx_file, fixP->fx_line,
18791218822Sdim			    _("immediate value out of range"));
1879277298Sobrien	    newval = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
1879377298Sobrien	    newval |= rd | (rs << 3) | (value << 6);
1879477298Sobrien	  }
1879560484Sobrien      }
1879677298Sobrien      md_number_to_chars (buf, newval, THUMB_SIZE);
1879760484Sobrien      break;
1879860484Sobrien
1879960484Sobrien    case BFD_RELOC_ARM_THUMB_IMM:
1880060484Sobrien      newval = md_chars_to_number (buf, THUMB_SIZE);
18801218822Sdim      if (value < 0 || value > 255)
18802218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18803218822Sdim		      _("invalid immediate: %ld is too large"),
18804218822Sdim		      (long) value);
18805218822Sdim      newval |= value;
1880677298Sobrien      md_number_to_chars (buf, newval, THUMB_SIZE);
1880760484Sobrien      break;
1880860484Sobrien
1880960484Sobrien    case BFD_RELOC_ARM_THUMB_SHIFT:
18810218822Sdim      /* 5bit shift value (0..32).  LSL cannot take 32.	 */
18811218822Sdim      newval = md_chars_to_number (buf, THUMB_SIZE) & 0xf83f;
18812218822Sdim      temp = newval & 0xf800;
18813218822Sdim      if (value < 0 || value > 32 || (value == 32 && temp == T_OPCODE_LSL_I))
1881460484Sobrien	as_bad_where (fixP->fx_file, fixP->fx_line,
18815218822Sdim		      _("invalid shift value: %ld"), (long) value);
18816218822Sdim      /* Shifts of zero must be encoded as LSL.	 */
18817218822Sdim      if (value == 0)
18818218822Sdim	newval = (newval & 0x003f) | T_OPCODE_LSL_I;
18819218822Sdim      /* Shifts of 32 are encoded as zero.  */
18820218822Sdim      else if (value == 32)
18821218822Sdim	value = 0;
1882260484Sobrien      newval |= value << 6;
1882377298Sobrien      md_number_to_chars (buf, newval, THUMB_SIZE);
1882460484Sobrien      break;
1882560484Sobrien
1882660484Sobrien    case BFD_RELOC_VTABLE_INHERIT:
1882760484Sobrien    case BFD_RELOC_VTABLE_ENTRY:
1882860484Sobrien      fixP->fx_done = 0;
1882989857Sobrien      return;
1883060484Sobrien
18831218822Sdim    case BFD_RELOC_ARM_MOVW:
18832218822Sdim    case BFD_RELOC_ARM_MOVT:
18833218822Sdim    case BFD_RELOC_ARM_THUMB_MOVW:
18834218822Sdim    case BFD_RELOC_ARM_THUMB_MOVT:
18835218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18836218822Sdim	{
18837218822Sdim	  /* REL format relocations are limited to a 16-bit addend.  */
18838218822Sdim	  if (!fixP->fx_done)
18839218822Sdim	    {
18840218822Sdim	      if (value < -0x1000 || value > 0xffff)
18841218822Sdim		  as_bad_where (fixP->fx_file, fixP->fx_line,
18842218822Sdim				_("offset too big"));
18843218822Sdim	    }
18844218822Sdim	  else if (fixP->fx_r_type == BFD_RELOC_ARM_MOVT
18845218822Sdim		   || fixP->fx_r_type == BFD_RELOC_ARM_THUMB_MOVT)
18846218822Sdim	    {
18847218822Sdim	      value >>= 16;
18848218822Sdim	    }
18849218822Sdim
18850218822Sdim	  if (fixP->fx_r_type == BFD_RELOC_ARM_THUMB_MOVW
18851218822Sdim	      || fixP->fx_r_type == BFD_RELOC_ARM_THUMB_MOVT)
18852218822Sdim	    {
18853218822Sdim	      newval = get_thumb32_insn (buf);
18854218822Sdim	      newval &= 0xfbf08f00;
18855218822Sdim	      newval |= (value & 0xf000) << 4;
18856218822Sdim	      newval |= (value & 0x0800) << 15;
18857218822Sdim	      newval |= (value & 0x0700) << 4;
18858218822Sdim	      newval |= (value & 0x00ff);
18859218822Sdim	      put_thumb32_insn (buf, newval);
18860218822Sdim	    }
18861218822Sdim	  else
18862218822Sdim	    {
18863218822Sdim	      newval = md_chars_to_number (buf, 4);
18864218822Sdim	      newval &= 0xfff0f000;
18865218822Sdim	      newval |= value & 0x0fff;
18866218822Sdim	      newval |= (value & 0xf000) << 4;
18867218822Sdim	      md_number_to_chars (buf, newval, 4);
18868218822Sdim	    }
18869218822Sdim	}
18870218822Sdim      return;
18871218822Sdim
18872218822Sdim   case BFD_RELOC_ARM_ALU_PC_G0_NC:
18873218822Sdim   case BFD_RELOC_ARM_ALU_PC_G0:
18874218822Sdim   case BFD_RELOC_ARM_ALU_PC_G1_NC:
18875218822Sdim   case BFD_RELOC_ARM_ALU_PC_G1:
18876218822Sdim   case BFD_RELOC_ARM_ALU_PC_G2:
18877218822Sdim   case BFD_RELOC_ARM_ALU_SB_G0_NC:
18878218822Sdim   case BFD_RELOC_ARM_ALU_SB_G0:
18879218822Sdim   case BFD_RELOC_ARM_ALU_SB_G1_NC:
18880218822Sdim   case BFD_RELOC_ARM_ALU_SB_G1:
18881218822Sdim   case BFD_RELOC_ARM_ALU_SB_G2:
18882218822Sdim     assert (!fixP->fx_done);
18883218822Sdim     if (!seg->use_rela_p)
18884218822Sdim       {
18885218822Sdim         bfd_vma insn;
18886218822Sdim         bfd_vma encoded_addend;
18887218822Sdim         bfd_vma addend_abs = abs (value);
18888218822Sdim
18889218822Sdim         /* Check that the absolute value of the addend can be
18890218822Sdim            expressed as an 8-bit constant plus a rotation.  */
18891218822Sdim         encoded_addend = encode_arm_immediate (addend_abs);
18892218822Sdim         if (encoded_addend == (unsigned int) FAIL)
18893218822Sdim	   as_bad_where (fixP->fx_file, fixP->fx_line,
18894218822Sdim	                 _("the offset 0x%08lX is not representable"),
18895218822Sdim                         (unsigned long) addend_abs);
18896218822Sdim
18897218822Sdim         /* Extract the instruction.  */
18898218822Sdim         insn = md_chars_to_number (buf, INSN_SIZE);
18899218822Sdim
18900218822Sdim         /* If the addend is positive, use an ADD instruction.
18901218822Sdim            Otherwise use a SUB.  Take care not to destroy the S bit.  */
18902218822Sdim         insn &= 0xff1fffff;
18903218822Sdim         if (value < 0)
18904218822Sdim           insn |= 1 << 22;
18905218822Sdim         else
18906218822Sdim           insn |= 1 << 23;
18907218822Sdim
18908218822Sdim         /* Place the encoded addend into the first 12 bits of the
18909218822Sdim            instruction.  */
18910218822Sdim         insn &= 0xfffff000;
18911218822Sdim         insn |= encoded_addend;
18912218822Sdim
18913218822Sdim         /* Update the instruction.  */
18914218822Sdim         md_number_to_chars (buf, insn, INSN_SIZE);
18915218822Sdim       }
18916218822Sdim     break;
18917218822Sdim
18918218822Sdim    case BFD_RELOC_ARM_LDR_PC_G0:
18919218822Sdim    case BFD_RELOC_ARM_LDR_PC_G1:
18920218822Sdim    case BFD_RELOC_ARM_LDR_PC_G2:
18921218822Sdim    case BFD_RELOC_ARM_LDR_SB_G0:
18922218822Sdim    case BFD_RELOC_ARM_LDR_SB_G1:
18923218822Sdim    case BFD_RELOC_ARM_LDR_SB_G2:
18924218822Sdim      assert (!fixP->fx_done);
18925218822Sdim      if (!seg->use_rela_p)
18926218822Sdim        {
18927218822Sdim          bfd_vma insn;
18928218822Sdim          bfd_vma addend_abs = abs (value);
18929218822Sdim
18930218822Sdim          /* Check that the absolute value of the addend can be
18931218822Sdim             encoded in 12 bits.  */
18932218822Sdim          if (addend_abs >= 0x1000)
18933218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
18934218822Sdim	  	          _("bad offset 0x%08lX (only 12 bits available for the magnitude)"),
18935218822Sdim                          (unsigned long) addend_abs);
18936218822Sdim
18937218822Sdim          /* Extract the instruction.  */
18938218822Sdim          insn = md_chars_to_number (buf, INSN_SIZE);
18939218822Sdim
18940218822Sdim          /* If the addend is negative, clear bit 23 of the instruction.
18941218822Sdim             Otherwise set it.  */
18942218822Sdim          if (value < 0)
18943218822Sdim            insn &= ~(1 << 23);
18944218822Sdim          else
18945218822Sdim            insn |= 1 << 23;
18946218822Sdim
18947218822Sdim          /* Place the absolute value of the addend into the first 12 bits
18948218822Sdim             of the instruction.  */
18949218822Sdim          insn &= 0xfffff000;
18950218822Sdim          insn |= addend_abs;
18951218822Sdim
18952218822Sdim          /* Update the instruction.  */
18953218822Sdim          md_number_to_chars (buf, insn, INSN_SIZE);
18954218822Sdim        }
18955218822Sdim      break;
18956218822Sdim
18957218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G0:
18958218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G1:
18959218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G2:
18960218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G0:
18961218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G1:
18962218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G2:
18963218822Sdim      assert (!fixP->fx_done);
18964218822Sdim      if (!seg->use_rela_p)
18965218822Sdim        {
18966218822Sdim          bfd_vma insn;
18967218822Sdim          bfd_vma addend_abs = abs (value);
18968218822Sdim
18969218822Sdim          /* Check that the absolute value of the addend can be
18970218822Sdim             encoded in 8 bits.  */
18971218822Sdim          if (addend_abs >= 0x100)
18972218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
18973218822Sdim	  	          _("bad offset 0x%08lX (only 8 bits available for the magnitude)"),
18974218822Sdim                          (unsigned long) addend_abs);
18975218822Sdim
18976218822Sdim          /* Extract the instruction.  */
18977218822Sdim          insn = md_chars_to_number (buf, INSN_SIZE);
18978218822Sdim
18979218822Sdim          /* If the addend is negative, clear bit 23 of the instruction.
18980218822Sdim             Otherwise set it.  */
18981218822Sdim          if (value < 0)
18982218822Sdim            insn &= ~(1 << 23);
18983218822Sdim          else
18984218822Sdim            insn |= 1 << 23;
18985218822Sdim
18986218822Sdim          /* Place the first four bits of the absolute value of the addend
18987218822Sdim             into the first 4 bits of the instruction, and the remaining
18988218822Sdim             four into bits 8 .. 11.  */
18989218822Sdim          insn &= 0xfffff0f0;
18990218822Sdim          insn |= (addend_abs & 0xf) | ((addend_abs & 0xf0) << 4);
18991218822Sdim
18992218822Sdim          /* Update the instruction.  */
18993218822Sdim          md_number_to_chars (buf, insn, INSN_SIZE);
18994218822Sdim        }
18995218822Sdim      break;
18996218822Sdim
18997218822Sdim    case BFD_RELOC_ARM_LDC_PC_G0:
18998218822Sdim    case BFD_RELOC_ARM_LDC_PC_G1:
18999218822Sdim    case BFD_RELOC_ARM_LDC_PC_G2:
19000218822Sdim    case BFD_RELOC_ARM_LDC_SB_G0:
19001218822Sdim    case BFD_RELOC_ARM_LDC_SB_G1:
19002218822Sdim    case BFD_RELOC_ARM_LDC_SB_G2:
19003218822Sdim      assert (!fixP->fx_done);
19004218822Sdim      if (!seg->use_rela_p)
19005218822Sdim        {
19006218822Sdim          bfd_vma insn;
19007218822Sdim          bfd_vma addend_abs = abs (value);
19008218822Sdim
19009218822Sdim          /* Check that the absolute value of the addend is a multiple of
19010218822Sdim             four and, when divided by four, fits in 8 bits.  */
19011218822Sdim          if (addend_abs & 0x3)
19012218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
19013218822Sdim	  	          _("bad offset 0x%08lX (must be word-aligned)"),
19014218822Sdim                          (unsigned long) addend_abs);
19015218822Sdim
19016218822Sdim          if ((addend_abs >> 2) > 0xff)
19017218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
19018218822Sdim	  	          _("bad offset 0x%08lX (must be an 8-bit number of words)"),
19019218822Sdim                          (unsigned long) addend_abs);
19020218822Sdim
19021218822Sdim          /* Extract the instruction.  */
19022218822Sdim          insn = md_chars_to_number (buf, INSN_SIZE);
19023218822Sdim
19024218822Sdim          /* If the addend is negative, clear bit 23 of the instruction.
19025218822Sdim             Otherwise set it.  */
19026218822Sdim          if (value < 0)
19027218822Sdim            insn &= ~(1 << 23);
19028218822Sdim          else
19029218822Sdim            insn |= 1 << 23;
19030218822Sdim
19031218822Sdim          /* Place the addend (divided by four) into the first eight
19032218822Sdim             bits of the instruction.  */
19033218822Sdim          insn &= 0xfffffff0;
19034218822Sdim          insn |= addend_abs >> 2;
19035218822Sdim
19036218822Sdim          /* Update the instruction.  */
19037218822Sdim          md_number_to_chars (buf, insn, INSN_SIZE);
19038218822Sdim        }
19039218822Sdim      break;
19040218822Sdim
19041218822Sdim    case BFD_RELOC_UNUSED:
1904260484Sobrien    default:
1904360484Sobrien      as_bad_where (fixP->fx_file, fixP->fx_line,
1904489857Sobrien		    _("bad relocation fixup type (%d)"), fixP->fx_r_type);
1904560484Sobrien    }
1904660484Sobrien}
1904760484Sobrien
1904860484Sobrien/* Translate internal representation of relocation info to BFD target
1904960484Sobrien   format.  */
1905077298Sobrien
1905160484Sobrienarelent *
19052218822Sdimtc_gen_reloc (asection *section, fixS *fixp)
1905360484Sobrien{
1905460484Sobrien  arelent * reloc;
1905560484Sobrien  bfd_reloc_code_real_type code;
1905660484Sobrien
19057218822Sdim  reloc = xmalloc (sizeof (arelent));
1905860484Sobrien
19059218822Sdim  reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
1906060484Sobrien  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
1906160484Sobrien  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
1906260484Sobrien
19063218822Sdim  if (fixp->fx_pcrel)
19064218822Sdim    {
19065218822Sdim      if (section->use_rela_p)
19066218822Sdim	fixp->fx_offset -= md_pcrel_from_section (fixp, section);
19067218822Sdim      else
19068218822Sdim	fixp->fx_offset = reloc->address;
19069218822Sdim    }
1907060484Sobrien  reloc->addend = fixp->fx_offset;
1907160484Sobrien
1907260484Sobrien  switch (fixp->fx_r_type)
1907360484Sobrien    {
1907460484Sobrien    case BFD_RELOC_8:
1907560484Sobrien      if (fixp->fx_pcrel)
1907660484Sobrien	{
1907760484Sobrien	  code = BFD_RELOC_8_PCREL;
1907860484Sobrien	  break;
1907960484Sobrien	}
1908060484Sobrien
1908160484Sobrien    case BFD_RELOC_16:
1908260484Sobrien      if (fixp->fx_pcrel)
1908360484Sobrien	{
1908460484Sobrien	  code = BFD_RELOC_16_PCREL;
1908560484Sobrien	  break;
1908660484Sobrien	}
1908760484Sobrien
1908860484Sobrien    case BFD_RELOC_32:
1908960484Sobrien      if (fixp->fx_pcrel)
1909060484Sobrien	{
1909160484Sobrien	  code = BFD_RELOC_32_PCREL;
1909260484Sobrien	  break;
1909360484Sobrien	}
1909460484Sobrien
19095218822Sdim    case BFD_RELOC_ARM_MOVW:
19096218822Sdim      if (fixp->fx_pcrel)
19097218822Sdim	{
19098218822Sdim	  code = BFD_RELOC_ARM_MOVW_PCREL;
19099218822Sdim	  break;
19100218822Sdim	}
19101218822Sdim
19102218822Sdim    case BFD_RELOC_ARM_MOVT:
19103218822Sdim      if (fixp->fx_pcrel)
19104218822Sdim	{
19105218822Sdim	  code = BFD_RELOC_ARM_MOVT_PCREL;
19106218822Sdim	  break;
19107218822Sdim	}
19108218822Sdim
19109218822Sdim    case BFD_RELOC_ARM_THUMB_MOVW:
19110218822Sdim      if (fixp->fx_pcrel)
19111218822Sdim	{
19112218822Sdim	  code = BFD_RELOC_ARM_THUMB_MOVW_PCREL;
19113218822Sdim	  break;
19114218822Sdim	}
19115218822Sdim
19116218822Sdim    case BFD_RELOC_ARM_THUMB_MOVT:
19117218822Sdim      if (fixp->fx_pcrel)
19118218822Sdim	{
19119218822Sdim	  code = BFD_RELOC_ARM_THUMB_MOVT_PCREL;
19120218822Sdim	  break;
19121218822Sdim	}
19122218822Sdim
19123218822Sdim    case BFD_RELOC_NONE:
1912460484Sobrien    case BFD_RELOC_ARM_PCREL_BRANCH:
1912577298Sobrien    case BFD_RELOC_ARM_PCREL_BLX:
1912677298Sobrien    case BFD_RELOC_RVA:
19127218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH7:
1912860484Sobrien    case BFD_RELOC_THUMB_PCREL_BRANCH9:
1912960484Sobrien    case BFD_RELOC_THUMB_PCREL_BRANCH12:
19130218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH20:
1913160484Sobrien    case BFD_RELOC_THUMB_PCREL_BRANCH23:
19132218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH25:
1913377298Sobrien    case BFD_RELOC_THUMB_PCREL_BLX:
1913460484Sobrien    case BFD_RELOC_VTABLE_ENTRY:
1913560484Sobrien    case BFD_RELOC_VTABLE_INHERIT:
19136218822Sdim#ifdef TE_PE
19137218822Sdim    case BFD_RELOC_32_SECREL:
19138218822Sdim#endif
1913960484Sobrien      code = fixp->fx_r_type;
1914060484Sobrien      break;
1914160484Sobrien
1914260484Sobrien    case BFD_RELOC_ARM_LITERAL:
1914360484Sobrien    case BFD_RELOC_ARM_HWLITERAL:
19144130561Sobrien      /* If this is called then the a literal has
19145130561Sobrien	 been referenced across a section boundary.  */
1914660484Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
19147130561Sobrien		    _("literal referenced across section boundary"));
1914860484Sobrien      return NULL;
1914960484Sobrien
1915060484Sobrien#ifdef OBJ_ELF
1915160484Sobrien    case BFD_RELOC_ARM_GOT32:
1915260484Sobrien    case BFD_RELOC_ARM_GOTOFF:
1915360484Sobrien    case BFD_RELOC_ARM_PLT32:
19154218822Sdim    case BFD_RELOC_ARM_TARGET1:
19155218822Sdim    case BFD_RELOC_ARM_ROSEGREL32:
19156218822Sdim    case BFD_RELOC_ARM_SBREL32:
19157218822Sdim    case BFD_RELOC_ARM_PREL31:
19158218822Sdim    case BFD_RELOC_ARM_TARGET2:
19159218822Sdim    case BFD_RELOC_ARM_TLS_LE32:
19160218822Sdim    case BFD_RELOC_ARM_TLS_LDO32:
19161218822Sdim    case BFD_RELOC_ARM_PCREL_CALL:
19162218822Sdim    case BFD_RELOC_ARM_PCREL_JUMP:
19163218822Sdim    case BFD_RELOC_ARM_ALU_PC_G0_NC:
19164218822Sdim    case BFD_RELOC_ARM_ALU_PC_G0:
19165218822Sdim    case BFD_RELOC_ARM_ALU_PC_G1_NC:
19166218822Sdim    case BFD_RELOC_ARM_ALU_PC_G1:
19167218822Sdim    case BFD_RELOC_ARM_ALU_PC_G2:
19168218822Sdim    case BFD_RELOC_ARM_LDR_PC_G0:
19169218822Sdim    case BFD_RELOC_ARM_LDR_PC_G1:
19170218822Sdim    case BFD_RELOC_ARM_LDR_PC_G2:
19171218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G0:
19172218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G1:
19173218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G2:
19174218822Sdim    case BFD_RELOC_ARM_LDC_PC_G0:
19175218822Sdim    case BFD_RELOC_ARM_LDC_PC_G1:
19176218822Sdim    case BFD_RELOC_ARM_LDC_PC_G2:
19177218822Sdim    case BFD_RELOC_ARM_ALU_SB_G0_NC:
19178218822Sdim    case BFD_RELOC_ARM_ALU_SB_G0:
19179218822Sdim    case BFD_RELOC_ARM_ALU_SB_G1_NC:
19180218822Sdim    case BFD_RELOC_ARM_ALU_SB_G1:
19181218822Sdim    case BFD_RELOC_ARM_ALU_SB_G2:
19182218822Sdim    case BFD_RELOC_ARM_LDR_SB_G0:
19183218822Sdim    case BFD_RELOC_ARM_LDR_SB_G1:
19184218822Sdim    case BFD_RELOC_ARM_LDR_SB_G2:
19185218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G0:
19186218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G1:
19187218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G2:
19188218822Sdim    case BFD_RELOC_ARM_LDC_SB_G0:
19189218822Sdim    case BFD_RELOC_ARM_LDC_SB_G1:
19190218822Sdim    case BFD_RELOC_ARM_LDC_SB_G2:
1919177298Sobrien      code = fixp->fx_r_type;
1919277298Sobrien      break;
19193218822Sdim
19194218822Sdim    case BFD_RELOC_ARM_TLS_GD32:
19195218822Sdim    case BFD_RELOC_ARM_TLS_IE32:
19196218822Sdim    case BFD_RELOC_ARM_TLS_LDM32:
19197218822Sdim      /* BFD will include the symbol's address in the addend.
19198218822Sdim	 But we don't want that, so subtract it out again here.  */
19199218822Sdim      if (!S_IS_COMMON (fixp->fx_addsy))
19200218822Sdim	reloc->addend -= (*reloc->sym_ptr_ptr)->value;
19201218822Sdim      code = fixp->fx_r_type;
19202218822Sdim      break;
1920360484Sobrien#endif
1920460484Sobrien
1920560484Sobrien    case BFD_RELOC_ARM_IMMEDIATE:
1920660484Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
19207130561Sobrien		    _("internal relocation (type: IMMEDIATE) not fixed up"));
1920860484Sobrien      return NULL;
1920960484Sobrien
1921060484Sobrien    case BFD_RELOC_ARM_ADRL_IMMEDIATE:
1921160484Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
1921277298Sobrien		    _("ADRL used for a symbol not defined in the same file"));
1921360484Sobrien      return NULL;
1921460484Sobrien
1921560484Sobrien    case BFD_RELOC_ARM_OFFSET_IMM:
19216218822Sdim      if (section->use_rela_p)
19217218822Sdim	{
19218218822Sdim	  code = fixp->fx_r_type;
19219218822Sdim	  break;
19220218822Sdim	}
19221218822Sdim
19222130561Sobrien      if (fixp->fx_addsy != NULL
19223130561Sobrien	  && !S_IS_DEFINED (fixp->fx_addsy)
19224130561Sobrien	  && S_IS_LOCAL (fixp->fx_addsy))
19225130561Sobrien	{
19226130561Sobrien	  as_bad_where (fixp->fx_file, fixp->fx_line,
19227130561Sobrien			_("undefined local label `%s'"),
19228130561Sobrien			S_GET_NAME (fixp->fx_addsy));
19229130561Sobrien	  return NULL;
19230130561Sobrien	}
19231130561Sobrien
1923260484Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
19233130561Sobrien		    _("internal_relocation (type: OFFSET_IMM) not fixed up"));
1923460484Sobrien      return NULL;
1923560484Sobrien
1923660484Sobrien    default:
1923760484Sobrien      {
1923860484Sobrien	char * type;
1923977298Sobrien
1924060484Sobrien	switch (fixp->fx_r_type)
1924160484Sobrien	  {
19242218822Sdim	  case BFD_RELOC_NONE:		   type = "NONE";	  break;
1924360484Sobrien	  case BFD_RELOC_ARM_OFFSET_IMM8:  type = "OFFSET_IMM8";  break;
19244218822Sdim	  case BFD_RELOC_ARM_SHIFT_IMM:	   type = "SHIFT_IMM";	  break;
19245218822Sdim	  case BFD_RELOC_ARM_SMC:	   type = "SMC";	  break;
19246218822Sdim	  case BFD_RELOC_ARM_SWI:	   type = "SWI";	  break;
19247218822Sdim	  case BFD_RELOC_ARM_MULTI:	   type = "MULTI";	  break;
19248218822Sdim	  case BFD_RELOC_ARM_CP_OFF_IMM:   type = "CP_OFF_IMM";	  break;
19249218822Sdim	  case BFD_RELOC_ARM_T32_CP_OFF_IMM: type = "T32_CP_OFF_IMM"; break;
19250218822Sdim	  case BFD_RELOC_ARM_THUMB_ADD:	   type = "THUMB_ADD";	  break;
1925160484Sobrien	  case BFD_RELOC_ARM_THUMB_SHIFT:  type = "THUMB_SHIFT";  break;
19252218822Sdim	  case BFD_RELOC_ARM_THUMB_IMM:	   type = "THUMB_IMM";	  break;
1925360484Sobrien	  case BFD_RELOC_ARM_THUMB_OFFSET: type = "THUMB_OFFSET"; break;
19254218822Sdim	  default:			   type = _("<unknown>"); break;
1925560484Sobrien	  }
1925660484Sobrien	as_bad_where (fixp->fx_file, fixp->fx_line,
1925789857Sobrien		      _("cannot represent %s relocation in this object file format"),
1925877298Sobrien		      type);
1925960484Sobrien	return NULL;
1926060484Sobrien      }
1926160484Sobrien    }
1926260484Sobrien
1926360484Sobrien#ifdef OBJ_ELF
19264130561Sobrien  if ((code == BFD_RELOC_32_PCREL || code == BFD_RELOC_32)
1926577298Sobrien      && GOT_symbol
1926677298Sobrien      && fixp->fx_addsy == GOT_symbol)
1926777298Sobrien    {
1926877298Sobrien      code = BFD_RELOC_ARM_GOTPC;
1926977298Sobrien      reloc->addend = fixp->fx_offset = reloc->address;
1927077298Sobrien    }
1927160484Sobrien#endif
1927277298Sobrien
1927360484Sobrien  reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
1927460484Sobrien
1927560484Sobrien  if (reloc->howto == NULL)
1927660484Sobrien    {
1927760484Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
1927889857Sobrien		    _("cannot represent %s relocation in this object file format"),
1927960484Sobrien		    bfd_get_reloc_code_name (code));
1928060484Sobrien      return NULL;
1928160484Sobrien    }
1928260484Sobrien
1928377298Sobrien  /* HACK: Since arm ELF uses Rel instead of Rela, encode the
1928477298Sobrien     vtable entry to be used in the relocation's section offset.  */
1928577298Sobrien  if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
1928677298Sobrien    reloc->address = fixp->fx_offset;
1928760484Sobrien
1928860484Sobrien  return reloc;
1928960484Sobrien}
1929060484Sobrien
19291218822Sdim/* This fix_new is called by cons via TC_CONS_FIX_NEW.	*/
1929260484Sobrien
19293218822Sdimvoid
19294218822Sdimcons_fix_new_arm (fragS *	frag,
19295218822Sdim		  int		where,
19296218822Sdim		  int		size,
19297218822Sdim		  expressionS * exp)
1929860484Sobrien{
19299218822Sdim  bfd_reloc_code_real_type type;
19300218822Sdim  int pcrel = 0;
1930177298Sobrien
19302218822Sdim  /* Pick a reloc.
19303218822Sdim     FIXME: @@ Should look at CPU word size.  */
19304218822Sdim  switch (size)
1930560484Sobrien    {
19306218822Sdim    case 1:
19307218822Sdim      type = BFD_RELOC_8;
19308218822Sdim      break;
19309218822Sdim    case 2:
19310218822Sdim      type = BFD_RELOC_16;
19311218822Sdim      break;
19312218822Sdim    case 4:
19313218822Sdim    default:
19314218822Sdim      type = BFD_RELOC_32;
19315218822Sdim      break;
19316218822Sdim    case 8:
19317218822Sdim      type = BFD_RELOC_64;
19318218822Sdim      break;
1931960484Sobrien    }
1932060484Sobrien
19321218822Sdim#ifdef TE_PE
19322218822Sdim  if (exp->X_op == O_secrel)
19323218822Sdim  {
19324218822Sdim    exp->X_op = O_symbol;
19325218822Sdim    type = BFD_RELOC_32_SECREL;
19326218822Sdim  }
19327218822Sdim#endif
1932877298Sobrien
19329218822Sdim  fix_new_exp (frag, where, (int) size, exp, pcrel, type);
19330218822Sdim}
19331218822Sdim
19332218822Sdim#if defined OBJ_COFF || defined OBJ_ELF
19333218822Sdimvoid
19334218822Sdimarm_validate_fix (fixS * fixP)
19335218822Sdim{
19336218822Sdim  /* If the destination of the branch is a defined symbol which does not have
19337218822Sdim     the THUMB_FUNC attribute, then we must be calling a function which has
19338218822Sdim     the (interfacearm) attribute.  We look for the Thumb entry point to that
19339218822Sdim     function and change the branch to refer to that function instead.	*/
19340218822Sdim  if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23
19341218822Sdim      && fixP->fx_addsy != NULL
19342218822Sdim      && S_IS_DEFINED (fixP->fx_addsy)
19343218822Sdim      && ! THUMB_IS_FUNC (fixP->fx_addsy))
1934460484Sobrien    {
19345218822Sdim      fixP->fx_addsy = find_real_start (fixP->fx_addsy);
1934660484Sobrien    }
19347218822Sdim}
19348218822Sdim#endif
1934960484Sobrien
19350218822Sdimint
19351218822Sdimarm_force_relocation (struct fix * fixp)
19352218822Sdim{
19353218822Sdim#if defined (OBJ_COFF) && defined (TE_PE)
19354218822Sdim  if (fixp->fx_r_type == BFD_RELOC_RVA)
19355218822Sdim    return 1;
19356218822Sdim#endif
1935760484Sobrien
19358218822Sdim  /* Resolve these relocations even if the symbol is extern or weak.  */
19359218822Sdim  if (fixp->fx_r_type == BFD_RELOC_ARM_IMMEDIATE
19360218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_OFFSET_IMM
19361218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE
19362218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM
19363218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_T32_IMMEDIATE
19364218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_T32_IMM12
19365218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_T32_ADD_PC12)
19366218822Sdim    return 0;
19367218822Sdim
19368218822Sdim  /* Always leave these relocations for the linker.  */
19369218822Sdim  if ((fixp->fx_r_type >= BFD_RELOC_ARM_ALU_PC_G0_NC
19370218822Sdim       && fixp->fx_r_type <= BFD_RELOC_ARM_LDC_SB_G2)
19371218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_LDR_PC_G0)
19372218822Sdim    return 1;
19373218822Sdim
19374218822Sdim  /* Always generate relocations against function symbols.  */
19375218822Sdim  if (fixp->fx_r_type == BFD_RELOC_32
19376218822Sdim      && fixp->fx_addsy
19377218822Sdim      && (symbol_get_bfdsym (fixp->fx_addsy)->flags & BSF_FUNCTION))
19378218822Sdim    return 1;
19379218822Sdim
19380218822Sdim  return generic_force_reloc (fixp);
19381218822Sdim}
19382218822Sdim
19383218822Sdim#if defined (OBJ_ELF) || defined (OBJ_COFF)
19384218822Sdim/* Relocations against function names must be left unadjusted,
19385218822Sdim   so that the linker can use this information to generate interworking
19386218822Sdim   stubs.  The MIPS version of this function
19387218822Sdim   also prevents relocations that are mips-16 specific, but I do not
19388218822Sdim   know why it does this.
19389218822Sdim
19390218822Sdim   FIXME:
19391218822Sdim   There is one other problem that ought to be addressed here, but
19392218822Sdim   which currently is not:  Taking the address of a label (rather
19393218822Sdim   than a function) and then later jumping to that address.  Such
19394218822Sdim   addresses also ought to have their bottom bit set (assuming that
19395218822Sdim   they reside in Thumb code), but at the moment they will not.	 */
19396218822Sdim
19397218822Sdimbfd_boolean
19398218822Sdimarm_fix_adjustable (fixS * fixP)
19399218822Sdim{
19400218822Sdim  if (fixP->fx_addsy == NULL)
19401218822Sdim    return 1;
19402218822Sdim
19403218822Sdim  /* Preserve relocations against symbols with function type.  */
19404218822Sdim  if (symbol_get_bfdsym (fixP->fx_addsy)->flags & BSF_FUNCTION)
19405218822Sdim    return 0;
19406218822Sdim
19407218822Sdim  if (THUMB_IS_FUNC (fixP->fx_addsy)
19408218822Sdim      && fixP->fx_subsy == NULL)
19409218822Sdim    return 0;
19410218822Sdim
19411218822Sdim  /* We need the symbol name for the VTABLE entries.  */
19412218822Sdim  if (	 fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
19413218822Sdim      || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
19414218822Sdim    return 0;
19415218822Sdim
19416218822Sdim  /* Don't allow symbols to be discarded on GOT related relocs.	 */
19417218822Sdim  if (fixP->fx_r_type == BFD_RELOC_ARM_PLT32
19418218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_GOT32
19419218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_GOTOFF
19420218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_GD32
19421218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LE32
19422218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_IE32
19423218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDM32
19424218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDO32
19425218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TARGET2)
19426218822Sdim    return 0;
19427218822Sdim
19428218822Sdim  /* Similarly for group relocations.  */
19429218822Sdim  if ((fixP->fx_r_type >= BFD_RELOC_ARM_ALU_PC_G0_NC
19430218822Sdim       && fixP->fx_r_type <= BFD_RELOC_ARM_LDC_SB_G2)
19431218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_LDR_PC_G0)
19432218822Sdim    return 0;
19433218822Sdim
19434272519Sandrew  if (fixP->fx_r_type == BFD_RELOC_ARM_MOVW
19435272519Sandrew      || fixP->fx_r_type == BFD_RELOC_ARM_MOVT
19436272519Sandrew      || fixP->fx_r_type == BFD_RELOC_ARM_THUMB_MOVW
19437272519Sandrew      || fixP->fx_r_type == BFD_RELOC_ARM_THUMB_MOVT)
19438272519Sandrew    return 0;
19439272519Sandrew
19440218822Sdim  return 1;
19441218822Sdim}
19442218822Sdim#endif /* defined (OBJ_ELF) || defined (OBJ_COFF) */
19443218822Sdim
1944477298Sobrien#ifdef OBJ_ELF
19445218822Sdim
19446218822Sdimconst char *
19447218822Sdimelf32_arm_target_format (void)
19448218822Sdim{
19449218822Sdim#ifdef TE_SYMBIAN
19450218822Sdim  return (target_big_endian
19451218822Sdim	  ? "elf32-bigarm-symbian"
19452218822Sdim	  : "elf32-littlearm-symbian");
19453218822Sdim#elif defined (TE_VXWORKS)
19454218822Sdim  return (target_big_endian
19455218822Sdim	  ? "elf32-bigarm-vxworks"
19456218822Sdim	  : "elf32-littlearm-vxworks");
19457218822Sdim#else
19458218822Sdim  if (target_big_endian)
19459218822Sdim    return "elf32-bigarm";
19460218822Sdim  else
19461218822Sdim    return "elf32-littlearm";
1946277298Sobrien#endif
1946360484Sobrien}
1946460484Sobrien
1946560484Sobrienvoid
19466218822Sdimarmelf_frob_symbol (symbolS * symp,
19467218822Sdim		    int *     puntp)
1946860484Sobrien{
19469218822Sdim  elf_frob_symbol (symp, puntp);
19470218822Sdim}
1947177298Sobrien#endif
1947260484Sobrien
19473218822Sdim/* MD interface: Finalization.	*/
1947460484Sobrien
19475218822Sdim/* A good place to do this, although this was probably not intended
19476218822Sdim   for this kind of use.  We need to dump the literal pool before
19477218822Sdim   references are made to a null symbol pointer.  */
1947860484Sobrien
19479218822Sdimvoid
19480218822Sdimarm_cleanup (void)
19481218822Sdim{
19482218822Sdim  literal_pool * pool;
1948377298Sobrien
19484218822Sdim  for (pool = list_of_pools; pool; pool = pool->next)
1948560484Sobrien    {
19486218822Sdim      /* Put it at the end of the relevent section.  */
19487218822Sdim      subseg_set (pool->section, pool->sub_section);
19488218822Sdim#ifdef OBJ_ELF
19489218822Sdim      arm_elf_change_section ();
19490218822Sdim#endif
19491218822Sdim      s_ltorg (0);
1949260484Sobrien    }
19493218822Sdim}
1949460484Sobrien
19495218822Sdim/* Adjust the symbol table.  This marks Thumb symbols as distinct from
19496218822Sdim   ARM ones.  */
1949760484Sobrien
19498218822Sdimvoid
19499218822Sdimarm_adjust_symtab (void)
19500218822Sdim{
19501218822Sdim#ifdef OBJ_COFF
19502218822Sdim  symbolS * sym;
1950377298Sobrien
19504218822Sdim  for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
19505218822Sdim    {
19506218822Sdim      if (ARM_IS_THUMB (sym))
1950760484Sobrien	{
19508218822Sdim	  if (THUMB_IS_FUNC (sym))
1950977298Sobrien	    {
19510218822Sdim	      /* Mark the symbol as a Thumb function.  */
19511218822Sdim	      if (   S_GET_STORAGE_CLASS (sym) == C_STAT
19512218822Sdim		  || S_GET_STORAGE_CLASS (sym) == C_LABEL)  /* This can happen!	 */
19513218822Sdim		S_SET_STORAGE_CLASS (sym, C_THUMBSTATFUNC);
19514218822Sdim
19515218822Sdim	      else if (S_GET_STORAGE_CLASS (sym) == C_EXT)
19516218822Sdim		S_SET_STORAGE_CLASS (sym, C_THUMBEXTFUNC);
19517218822Sdim	      else
19518218822Sdim		as_bad (_("%s: unexpected function type: %d"),
19519218822Sdim			S_GET_NAME (sym), S_GET_STORAGE_CLASS (sym));
1952077298Sobrien	    }
19521218822Sdim	  else switch (S_GET_STORAGE_CLASS (sym))
19522218822Sdim	    {
19523218822Sdim	    case C_EXT:
19524218822Sdim	      S_SET_STORAGE_CLASS (sym, C_THUMBEXT);
19525218822Sdim	      break;
19526218822Sdim	    case C_STAT:
19527218822Sdim	      S_SET_STORAGE_CLASS (sym, C_THUMBSTAT);
19528218822Sdim	      break;
19529218822Sdim	    case C_LABEL:
19530218822Sdim	      S_SET_STORAGE_CLASS (sym, C_THUMBLABEL);
19531218822Sdim	      break;
19532218822Sdim	    default:
19533218822Sdim	      /* Do nothing.  */
19534218822Sdim	      break;
19535218822Sdim	    }
19536218822Sdim	}
1953760484Sobrien
19538218822Sdim      if (ARM_IS_INTERWORK (sym))
19539218822Sdim	coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_flags = 0xFF;
1954060484Sobrien    }
19541218822Sdim#endif
19542218822Sdim#ifdef OBJ_ELF
19543218822Sdim  symbolS * sym;
19544218822Sdim  char	    bind;
19545218822Sdim
19546218822Sdim  for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
1954760484Sobrien    {
19548218822Sdim      if (ARM_IS_THUMB (sym))
19549218822Sdim	{
19550218822Sdim	  elf_symbol_type * elf_sym;
1955160484Sobrien
19552218822Sdim	  elf_sym = elf_symbol (symbol_get_bfdsym (sym));
19553218822Sdim	  bind = ELF_ST_BIND (elf_sym->internal_elf_sym.st_info);
1955477298Sobrien
19555218822Sdim	  if (! bfd_is_arm_special_symbol_name (elf_sym->symbol.name,
19556218822Sdim		BFD_ARM_SPECIAL_SYM_TYPE_ANY))
1955760484Sobrien	    {
19558218822Sdim	      /* If it's a .thumb_func, declare it as so,
19559218822Sdim		 otherwise tag label as .code 16.  */
19560218822Sdim	      if (THUMB_IS_FUNC (sym))
19561218822Sdim		elf_sym->internal_elf_sym.st_info =
19562218822Sdim		  ELF_ST_INFO (bind, STT_ARM_TFUNC);
19563218822Sdim	      else if (EF_ARM_EABI_VERSION (meabi_flags) < EF_ARM_EABI_VER4)
19564218822Sdim		elf_sym->internal_elf_sym.st_info =
19565218822Sdim		  ELF_ST_INFO (bind, STT_ARM_16BIT);
1956660484Sobrien	    }
1956760484Sobrien	}
1956860484Sobrien    }
19569218822Sdim#endif
19570218822Sdim}
1957160484Sobrien
19572218822Sdim/* MD interface: Initialization.  */
1957360484Sobrien
19574218822Sdimstatic void
19575218822Sdimset_constant_flonums (void)
19576218822Sdim{
19577218822Sdim  int i;
19578218822Sdim
19579218822Sdim  for (i = 0; i < NUM_FLOAT_VALS; i++)
19580218822Sdim    if (atof_ieee ((char *) fp_const[i], 'x', fp_values[i]) == NULL)
19581218822Sdim      abort ();
1958289857Sobrien}
1958377298Sobrien
19584218822Sdim/* Auto-select Thumb mode if it's the only available instruction set for the
19585218822Sdim   given architecture.  */
19586218822Sdim
19587218822Sdimstatic void
19588218822Sdimautoselect_thumb_from_cpu_variant (void)
19589218822Sdim{
19590218822Sdim  if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1))
19591218822Sdim    opcode_select (16);
19592218822Sdim}
19593218822Sdim
19594218822Sdimvoid
19595218822Sdimmd_begin (void)
19596218822Sdim{
19597218822Sdim  unsigned mach;
19598218822Sdim  unsigned int i;
19599218822Sdim
19600218822Sdim  if (	 (arm_ops_hsh = hash_new ()) == NULL
19601218822Sdim      || (arm_cond_hsh = hash_new ()) == NULL
19602218822Sdim      || (arm_shift_hsh = hash_new ()) == NULL
19603218822Sdim      || (arm_psr_hsh = hash_new ()) == NULL
19604218822Sdim      || (arm_v7m_psr_hsh = hash_new ()) == NULL
19605218822Sdim      || (arm_reg_hsh = hash_new ()) == NULL
19606218822Sdim      || (arm_reloc_hsh = hash_new ()) == NULL
19607218822Sdim      || (arm_barrier_opt_hsh = hash_new ()) == NULL)
19608218822Sdim    as_fatal (_("virtual memory exhausted"));
19609218822Sdim
19610218822Sdim  for (i = 0; i < sizeof (insns) / sizeof (struct asm_opcode); i++)
19611218822Sdim    hash_insert (arm_ops_hsh, insns[i].template, (PTR) (insns + i));
19612218822Sdim  for (i = 0; i < sizeof (conds) / sizeof (struct asm_cond); i++)
19613218822Sdim    hash_insert (arm_cond_hsh, conds[i].template, (PTR) (conds + i));
19614218822Sdim  for (i = 0; i < sizeof (shift_names) / sizeof (struct asm_shift_name); i++)
19615218822Sdim    hash_insert (arm_shift_hsh, shift_names[i].name, (PTR) (shift_names + i));
19616218822Sdim  for (i = 0; i < sizeof (psrs) / sizeof (struct asm_psr); i++)
19617218822Sdim    hash_insert (arm_psr_hsh, psrs[i].template, (PTR) (psrs + i));
19618218822Sdim  for (i = 0; i < sizeof (v7m_psrs) / sizeof (struct asm_psr); i++)
19619218822Sdim    hash_insert (arm_v7m_psr_hsh, v7m_psrs[i].template, (PTR) (v7m_psrs + i));
19620218822Sdim  for (i = 0; i < sizeof (reg_names) / sizeof (struct reg_entry); i++)
19621218822Sdim    hash_insert (arm_reg_hsh, reg_names[i].name, (PTR) (reg_names + i));
19622218822Sdim  for (i = 0;
19623218822Sdim       i < sizeof (barrier_opt_names) / sizeof (struct asm_barrier_opt);
19624218822Sdim       i++)
19625218822Sdim    hash_insert (arm_barrier_opt_hsh, barrier_opt_names[i].template,
19626218822Sdim		 (PTR) (barrier_opt_names + i));
19627218822Sdim#ifdef OBJ_ELF
19628218822Sdim  for (i = 0; i < sizeof (reloc_names) / sizeof (struct reloc_entry); i++)
19629218822Sdim    hash_insert (arm_reloc_hsh, reloc_names[i].name, (PTR) (reloc_names + i));
19630218822Sdim#endif
19631218822Sdim
19632218822Sdim  set_constant_flonums ();
19633218822Sdim
19634218822Sdim  /* Set the cpu variant based on the command-line options.  We prefer
19635218822Sdim     -mcpu= over -march= if both are set (as for GCC); and we prefer
19636218822Sdim     -mfpu= over any other way of setting the floating point unit.
19637218822Sdim     Use of legacy options with new options are faulted.  */
19638218822Sdim  if (legacy_cpu)
19639218822Sdim    {
19640218822Sdim      if (mcpu_cpu_opt || march_cpu_opt)
19641218822Sdim	as_bad (_("use of old and new-style options to set CPU type"));
19642218822Sdim
19643218822Sdim      mcpu_cpu_opt = legacy_cpu;
19644218822Sdim    }
19645218822Sdim  else if (!mcpu_cpu_opt)
19646218822Sdim    mcpu_cpu_opt = march_cpu_opt;
19647218822Sdim
19648218822Sdim  if (legacy_fpu)
19649218822Sdim    {
19650218822Sdim      if (mfpu_opt)
19651218822Sdim	as_bad (_("use of old and new-style options to set FPU type"));
19652218822Sdim
19653218822Sdim      mfpu_opt = legacy_fpu;
19654218822Sdim    }
19655218822Sdim  else if (!mfpu_opt)
19656218822Sdim    {
19657218822Sdim#if !(defined (TE_LINUX) || defined (TE_NetBSD) || defined (TE_VXWORKS))
19658218822Sdim      /* Some environments specify a default FPU.  If they don't, infer it
19659218822Sdim	 from the processor.  */
19660218822Sdim      if (mcpu_fpu_opt)
19661218822Sdim	mfpu_opt = mcpu_fpu_opt;
19662218822Sdim      else
19663218822Sdim	mfpu_opt = march_fpu_opt;
19664218822Sdim#else
19665218822Sdim      mfpu_opt = &fpu_default;
19666218822Sdim#endif
19667218822Sdim    }
19668218822Sdim
19669218822Sdim  if (!mfpu_opt)
19670218822Sdim    {
19671218822Sdim      if (mcpu_cpu_opt != NULL)
19672218822Sdim	mfpu_opt = &fpu_default;
19673218822Sdim      else if (mcpu_fpu_opt != NULL && ARM_CPU_HAS_FEATURE (*mcpu_fpu_opt, arm_ext_v5))
19674218822Sdim	mfpu_opt = &fpu_arch_vfp_v2;
19675218822Sdim      else
19676218822Sdim	mfpu_opt = &fpu_arch_fpa;
19677218822Sdim    }
19678218822Sdim
19679218822Sdim#ifdef CPU_DEFAULT
19680218822Sdim  if (!mcpu_cpu_opt)
19681218822Sdim    {
19682218822Sdim      mcpu_cpu_opt = &cpu_default;
19683218822Sdim      selected_cpu = cpu_default;
19684218822Sdim    }
19685218822Sdim#else
19686218822Sdim  if (mcpu_cpu_opt)
19687218822Sdim    selected_cpu = *mcpu_cpu_opt;
19688218822Sdim  else
19689218822Sdim    mcpu_cpu_opt = &arm_arch_any;
19690218822Sdim#endif
19691218822Sdim
19692218822Sdim  ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
19693218822Sdim
19694218822Sdim  autoselect_thumb_from_cpu_variant ();
19695218822Sdim
19696218822Sdim  arm_arch_used = thumb_arch_used = arm_arch_none;
19697218822Sdim
19698218822Sdim#if defined OBJ_COFF || defined OBJ_ELF
19699218822Sdim  {
19700218822Sdim    unsigned int flags = 0;
19701218822Sdim
19702218822Sdim#if defined OBJ_ELF
19703218822Sdim    flags = meabi_flags;
19704218822Sdim
19705218822Sdim    switch (meabi_flags)
19706218822Sdim      {
19707218822Sdim      case EF_ARM_EABI_UNKNOWN:
19708218822Sdim#endif
19709218822Sdim	/* Set the flags in the private structure.  */
19710218822Sdim	if (uses_apcs_26)      flags |= F_APCS26;
19711218822Sdim	if (support_interwork) flags |= F_INTERWORK;
19712218822Sdim	if (uses_apcs_float)   flags |= F_APCS_FLOAT;
19713218822Sdim	if (pic_code)	       flags |= F_PIC;
19714218822Sdim	if (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_any_hard))
19715218822Sdim	  flags |= F_SOFT_FLOAT;
19716218822Sdim
19717218822Sdim	switch (mfloat_abi_opt)
19718218822Sdim	  {
19719218822Sdim	  case ARM_FLOAT_ABI_SOFT:
19720218822Sdim	  case ARM_FLOAT_ABI_SOFTFP:
19721218822Sdim	    flags |= F_SOFT_FLOAT;
19722218822Sdim	    break;
19723218822Sdim
19724218822Sdim	  case ARM_FLOAT_ABI_HARD:
19725218822Sdim	    if (flags & F_SOFT_FLOAT)
19726218822Sdim	      as_bad (_("hard-float conflicts with specified fpu"));
19727218822Sdim	    break;
19728218822Sdim	  }
19729218822Sdim
19730218822Sdim	/* Using pure-endian doubles (even if soft-float).	*/
19731218822Sdim	if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_endian_pure))
19732218822Sdim	  flags |= F_VFP_FLOAT;
19733218822Sdim
19734218822Sdim#if defined OBJ_ELF
19735218822Sdim	if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_arch_maverick))
19736218822Sdim	    flags |= EF_ARM_MAVERICK_FLOAT;
19737218822Sdim	break;
19738218822Sdim
19739218822Sdim      case EF_ARM_EABI_VER4:
19740218822Sdim      case EF_ARM_EABI_VER5:
19741218822Sdim	/* No additional flags to set.	*/
19742218822Sdim	break;
19743218822Sdim
19744218822Sdim      default:
19745218822Sdim	abort ();
19746218822Sdim      }
19747218822Sdim#endif
19748218822Sdim    bfd_set_private_flags (stdoutput, flags);
19749218822Sdim
19750218822Sdim    /* We have run out flags in the COFF header to encode the
19751218822Sdim       status of ATPCS support, so instead we create a dummy,
19752218822Sdim       empty, debug section called .arm.atpcs.	*/
19753218822Sdim    if (atpcs)
19754218822Sdim      {
19755218822Sdim	asection * sec;
19756218822Sdim
19757218822Sdim	sec = bfd_make_section (stdoutput, ".arm.atpcs");
19758218822Sdim
19759218822Sdim	if (sec != NULL)
19760218822Sdim	  {
19761218822Sdim	    bfd_set_section_flags
19762218822Sdim	      (stdoutput, sec, SEC_READONLY | SEC_DEBUGGING /* | SEC_HAS_CONTENTS */);
19763218822Sdim	    bfd_set_section_size (stdoutput, sec, 0);
19764218822Sdim	    bfd_set_section_contents (stdoutput, sec, NULL, 0, 0);
19765218822Sdim	  }
19766218822Sdim      }
19767218822Sdim  }
19768218822Sdim#endif
19769218822Sdim
19770218822Sdim  /* Record the CPU type as well.  */
19771218822Sdim  if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2))
19772218822Sdim    mach = bfd_mach_arm_iWMMXt2;
19773218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt))
19774218822Sdim    mach = bfd_mach_arm_iWMMXt;
19775218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_xscale))
19776218822Sdim    mach = bfd_mach_arm_XScale;
19777218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_maverick))
19778218822Sdim    mach = bfd_mach_arm_ep9312;
19779218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v5e))
19780218822Sdim    mach = bfd_mach_arm_5TE;
19781218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v5))
19782218822Sdim    {
19783218822Sdim      if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v4t))
19784218822Sdim	mach = bfd_mach_arm_5T;
19785218822Sdim      else
19786218822Sdim	mach = bfd_mach_arm_5;
19787218822Sdim    }
19788218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v4))
19789218822Sdim    {
19790218822Sdim      if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v4t))
19791218822Sdim	mach = bfd_mach_arm_4T;
19792218822Sdim      else
19793218822Sdim	mach = bfd_mach_arm_4;
19794218822Sdim    }
19795218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v3m))
19796218822Sdim    mach = bfd_mach_arm_3M;
19797218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v3))
19798218822Sdim    mach = bfd_mach_arm_3;
19799218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v2s))
19800218822Sdim    mach = bfd_mach_arm_2a;
19801218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v2))
19802218822Sdim    mach = bfd_mach_arm_2;
19803218822Sdim  else
19804218822Sdim    mach = bfd_mach_arm_unknown;
19805218822Sdim
19806218822Sdim  bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
19807218822Sdim}
19808218822Sdim
19809218822Sdim/* Command line processing.  */
19810218822Sdim
1981189857Sobrien/* md_parse_option
1981289857Sobrien      Invocation line includes a switch not recognized by the base assembler.
19813104834Sobrien      See if it's a processor-specific option.
1981477298Sobrien
1981589857Sobrien      This routine is somewhat complicated by the need for backwards
1981689857Sobrien      compatibility (since older releases of gcc can't be changed).
1981789857Sobrien      The new options try to make the interface as compatible as
1981889857Sobrien      possible with GCC.
1981977298Sobrien
1982089857Sobrien      New options (supported) are:
1982160484Sobrien
1982289857Sobrien	      -mcpu=<cpu name>		 Assemble for selected processor
1982389857Sobrien	      -march=<architecture name> Assemble for selected architecture
1982489857Sobrien	      -mfpu=<fpu architecture>	 Assemble for selected FPU.
1982589857Sobrien	      -EB/-mbig-endian		 Big-endian
1982689857Sobrien	      -EL/-mlittle-endian	 Little-endian
1982789857Sobrien	      -k			 Generate PIC code
1982889857Sobrien	      -mthumb			 Start in Thumb mode
1982989857Sobrien	      -mthumb-interwork		 Code supports ARM/Thumb interworking
1983077298Sobrien
19831130561Sobrien      For now we will also provide support for:
1983260484Sobrien
1983389857Sobrien	      -mapcs-32			 32-bit Program counter
1983489857Sobrien	      -mapcs-26			 26-bit Program counter
1983589857Sobrien	      -macps-float		 Floats passed in FP registers
1983689857Sobrien	      -mapcs-reentrant		 Reentrant code
1983789857Sobrien	      -matpcs
1983889857Sobrien      (sometime these will probably be replaced with -mapcs=<list of options>
1983989857Sobrien      and -matpcs=<list of options>)
1984060484Sobrien
1984189857Sobrien      The remaining options are only supported for back-wards compatibility.
1984277298Sobrien      Cpu variants, the arm part is optional:
19843218822Sdim	      -m[arm]1		      Currently not supported.
19844218822Sdim	      -m[arm]2, -m[arm]250    Arm 2 and Arm 250 processor
19845218822Sdim	      -m[arm]3		      Arm 3 processor
19846218822Sdim	      -m[arm]6[xx],	      Arm 6 processors
19847218822Sdim	      -m[arm]7[xx][t][[d]m]   Arm 7 processors
19848218822Sdim	      -m[arm]8[10]	      Arm 8 processors
19849218822Sdim	      -m[arm]9[20][tdmi]      Arm 9 processors
19850218822Sdim	      -mstrongarm[110[0]]     StrongARM processors
19851218822Sdim	      -mxscale		      XScale processors
19852218822Sdim	      -m[arm]v[2345[t[e]]]    Arm architectures
19853218822Sdim	      -mall		      All (except the ARM1)
1985477298Sobrien      FP variants:
19855218822Sdim	      -mfpa10, -mfpa11	      FPA10 and 11 co-processor instructions
19856218822Sdim	      -mfpe-old		      (No float load/store multiples)
1985789857Sobrien	      -mvfpxd		      VFP Single precision
1985889857Sobrien	      -mvfp		      All VFP
19859218822Sdim	      -mno-fpu		      Disable all floating point instructions
1986060484Sobrien
1986189857Sobrien      The following CPU names are recognized:
1986289857Sobrien	      arm1, arm2, arm250, arm3, arm6, arm600, arm610, arm620,
1986389857Sobrien	      arm7, arm7m, arm7d, arm7dm, arm7di, arm7dmi, arm70, arm700,
1986489857Sobrien	      arm700i, arm710 arm710t, arm720, arm720t, arm740t, arm710c,
1986589857Sobrien	      arm7100, arm7500, arm7500fe, arm7tdmi, arm8, arm810, arm9,
1986689857Sobrien	      arm920, arm920t, arm940t, arm946, arm966, arm9tdmi, arm9e,
1986789857Sobrien	      arm10t arm10e, arm1020t, arm1020e, arm10200e,
1986889857Sobrien	      strongarm, strongarm110, strongarm1100, strongarm1110, xscale.
1986989857Sobrien
1987089857Sobrien      */
1987189857Sobrien
19872104834Sobrienconst char * md_shortopts = "m:k";
1987377298Sobrien
1987489857Sobrien#ifdef ARM_BI_ENDIAN
1987589857Sobrien#define OPTION_EB (OPTION_MD_BASE + 0)
1987689857Sobrien#define OPTION_EL (OPTION_MD_BASE + 1)
1987789857Sobrien#else
1987889857Sobrien#if TARGET_BYTES_BIG_ENDIAN
1987989857Sobrien#define OPTION_EB (OPTION_MD_BASE + 0)
1988089857Sobrien#else
1988189857Sobrien#define OPTION_EL (OPTION_MD_BASE + 1)
1988289857Sobrien#endif
1988389857Sobrien#endif
1988489857Sobrien
1988560484Sobrienstruct option md_longopts[] =
1988660484Sobrien{
1988789857Sobrien#ifdef OPTION_EB
1988860484Sobrien  {"EB", no_argument, NULL, OPTION_EB},
1988989857Sobrien#endif
1989089857Sobrien#ifdef OPTION_EL
1989160484Sobrien  {"EL", no_argument, NULL, OPTION_EL},
1989260484Sobrien#endif
1989360484Sobrien  {NULL, no_argument, NULL, 0}
1989460484Sobrien};
1989577298Sobrien
1989660484Sobriensize_t md_longopts_size = sizeof (md_longopts);
1989760484Sobrien
1989889857Sobrienstruct arm_option_table
1989960484Sobrien{
1990089857Sobrien  char *option;		/* Option name to match.  */
1990189857Sobrien  char *help;		/* Help information.  */
19902218822Sdim  int  *var;		/* Variable to change.	*/
19903218822Sdim  int	value;		/* What to change it to.  */
1990489857Sobrien  char *deprecated;	/* If non-null, print this message.  */
1990589857Sobrien};
1990660484Sobrien
19907104834Sobrienstruct arm_option_table arm_opts[] =
1990889857Sobrien{
19909218822Sdim  {"k",	     N_("generate PIC code"),	   &pic_code,	 1, NULL},
19910218822Sdim  {"mthumb", N_("assemble Thumb code"),	   &thumb_mode,	 1, NULL},
1991189857Sobrien  {"mthumb-interwork", N_("support ARM/Thumb interworking"),
1991289857Sobrien   &support_interwork, 1, NULL},
1991389857Sobrien  {"mapcs-32", N_("code uses 32-bit program counter"), &uses_apcs_26, 0, NULL},
1991489857Sobrien  {"mapcs-26", N_("code uses 26-bit program counter"), &uses_apcs_26, 1, NULL},
1991589857Sobrien  {"mapcs-float", N_("floating point args are in fp regs"), &uses_apcs_float,
1991689857Sobrien   1, NULL},
1991789857Sobrien  {"mapcs-reentrant", N_("re-entrant code"), &pic_code, 1, NULL},
1991889857Sobrien  {"matpcs", N_("code is ATPCS conformant"), &atpcs, 1, NULL},
1991989857Sobrien  {"mbig-endian", N_("assemble for big-endian"), &target_big_endian, 1, NULL},
19920218822Sdim  {"mlittle-endian", N_("assemble for little-endian"), &target_big_endian, 0,
1992189857Sobrien   NULL},
1992289857Sobrien
19923218822Sdim  /* These are recognized by the assembler, but have no affect on code.	 */
1992489857Sobrien  {"mapcs-frame", N_("use frame pointer"), NULL, 0, NULL},
1992589857Sobrien  {"mapcs-stack-check", N_("use stack size checking"), NULL, 0, NULL},
19926218822Sdim  {NULL, NULL, NULL, 0, NULL}
19927218822Sdim};
1992889857Sobrien
19929218822Sdimstruct arm_legacy_option_table
19930218822Sdim{
19931218822Sdim  char *option;				/* Option name to match.  */
19932218822Sdim  const arm_feature_set	**var;		/* Variable to change.	*/
19933218822Sdim  const arm_feature_set	value;		/* What to change it to.  */
19934218822Sdim  char *deprecated;			/* If non-null, print this message.  */
19935218822Sdim};
19936218822Sdim
19937218822Sdimconst struct arm_legacy_option_table arm_legacy_opts[] =
19938218822Sdim{
1993989857Sobrien  /* DON'T add any new processors to this list -- we want the whole list
1994089857Sobrien     to go away...  Add them to the processors table instead.  */
19941218822Sdim  {"marm1",	 &legacy_cpu, ARM_ARCH_V1,  N_("use -mcpu=arm1")},
19942218822Sdim  {"m1",	 &legacy_cpu, ARM_ARCH_V1,  N_("use -mcpu=arm1")},
19943218822Sdim  {"marm2",	 &legacy_cpu, ARM_ARCH_V2,  N_("use -mcpu=arm2")},
19944218822Sdim  {"m2",	 &legacy_cpu, ARM_ARCH_V2,  N_("use -mcpu=arm2")},
19945218822Sdim  {"marm250",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm250")},
19946218822Sdim  {"m250",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm250")},
19947218822Sdim  {"marm3",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm3")},
19948218822Sdim  {"m3",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm3")},
19949218822Sdim  {"marm6",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm6")},
19950218822Sdim  {"m6",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm6")},
19951218822Sdim  {"marm600",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm600")},
19952218822Sdim  {"m600",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm600")},
19953218822Sdim  {"marm610",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm610")},
19954218822Sdim  {"m610",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm610")},
19955218822Sdim  {"marm620",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm620")},
19956218822Sdim  {"m620",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm620")},
19957218822Sdim  {"marm7",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7")},
19958218822Sdim  {"m7",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7")},
19959218822Sdim  {"marm70",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm70")},
19960218822Sdim  {"m70",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm70")},
19961218822Sdim  {"marm700",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm700")},
19962218822Sdim  {"m700",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm700")},
19963218822Sdim  {"marm700i",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm700i")},
19964218822Sdim  {"m700i",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm700i")},
19965218822Sdim  {"marm710",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm710")},
19966218822Sdim  {"m710",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm710")},
19967218822Sdim  {"marm710c",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm710c")},
19968218822Sdim  {"m710c",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm710c")},
19969218822Sdim  {"marm720",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm720")},
19970218822Sdim  {"m720",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm720")},
19971218822Sdim  {"marm7d",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7d")},
19972218822Sdim  {"m7d",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7d")},
19973218822Sdim  {"marm7di",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7di")},
19974218822Sdim  {"m7di",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7di")},
19975218822Sdim  {"marm7m",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7m")},
19976218822Sdim  {"m7m",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7m")},
19977218822Sdim  {"marm7dm",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dm")},
19978218822Sdim  {"m7dm",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dm")},
19979218822Sdim  {"marm7dmi",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dmi")},
19980218822Sdim  {"m7dmi",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dmi")},
19981218822Sdim  {"marm7100",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7100")},
19982218822Sdim  {"m7100",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7100")},
19983218822Sdim  {"marm7500",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7500")},
19984218822Sdim  {"m7500",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7500")},
19985218822Sdim  {"marm7500fe", &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7500fe")},
19986218822Sdim  {"m7500fe",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7500fe")},
19987218822Sdim  {"marm7t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
19988218822Sdim  {"m7t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
19989218822Sdim  {"marm7tdmi",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
19990218822Sdim  {"m7tdmi",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
19991218822Sdim  {"marm710t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm710t")},
19992218822Sdim  {"m710t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm710t")},
19993218822Sdim  {"marm720t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm720t")},
19994218822Sdim  {"m720t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm720t")},
19995218822Sdim  {"marm740t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm740t")},
19996218822Sdim  {"m740t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm740t")},
19997218822Sdim  {"marm8",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -mcpu=arm8")},
19998218822Sdim  {"m8",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -mcpu=arm8")},
19999218822Sdim  {"marm810",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -mcpu=arm810")},
20000218822Sdim  {"m810",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -mcpu=arm810")},
20001218822Sdim  {"marm9",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9")},
20002218822Sdim  {"m9",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9")},
20003218822Sdim  {"marm9tdmi",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9tdmi")},
20004218822Sdim  {"m9tdmi",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9tdmi")},
20005218822Sdim  {"marm920",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm920")},
20006218822Sdim  {"m920",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm920")},
20007218822Sdim  {"marm940",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm940")},
20008218822Sdim  {"m940",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm940")},
20009218822Sdim  {"mstrongarm", &legacy_cpu, ARM_ARCH_V4,  N_("use -mcpu=strongarm")},
20010218822Sdim  {"mstrongarm110", &legacy_cpu, ARM_ARCH_V4,
2001189857Sobrien   N_("use -mcpu=strongarm110")},
20012218822Sdim  {"mstrongarm1100", &legacy_cpu, ARM_ARCH_V4,
2001389857Sobrien   N_("use -mcpu=strongarm1100")},
20014218822Sdim  {"mstrongarm1110", &legacy_cpu, ARM_ARCH_V4,
2001589857Sobrien   N_("use -mcpu=strongarm1110")},
20016218822Sdim  {"mxscale",	 &legacy_cpu, ARM_ARCH_XSCALE, N_("use -mcpu=xscale")},
20017218822Sdim  {"miwmmxt",	 &legacy_cpu, ARM_ARCH_IWMMXT, N_("use -mcpu=iwmmxt")},
20018218822Sdim  {"mall",	 &legacy_cpu, ARM_ANY,	       N_("use -mcpu=all")},
2001989857Sobrien
2002089857Sobrien  /* Architecture variants -- don't add any more to this list either.  */
20021218822Sdim  {"mv2",	 &legacy_cpu, ARM_ARCH_V2,  N_("use -march=armv2")},
20022218822Sdim  {"marmv2",	 &legacy_cpu, ARM_ARCH_V2,  N_("use -march=armv2")},
20023218822Sdim  {"mv2a",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -march=armv2a")},
20024218822Sdim  {"marmv2a",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -march=armv2a")},
20025218822Sdim  {"mv3",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -march=armv3")},
20026218822Sdim  {"marmv3",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -march=armv3")},
20027218822Sdim  {"mv3m",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -march=armv3m")},
20028218822Sdim  {"marmv3m",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -march=armv3m")},
20029218822Sdim  {"mv4",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -march=armv4")},
20030218822Sdim  {"marmv4",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -march=armv4")},
20031218822Sdim  {"mv4t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -march=armv4t")},
20032218822Sdim  {"marmv4t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -march=armv4t")},
20033218822Sdim  {"mv5",	 &legacy_cpu, ARM_ARCH_V5,  N_("use -march=armv5")},
20034218822Sdim  {"marmv5",	 &legacy_cpu, ARM_ARCH_V5,  N_("use -march=armv5")},
20035218822Sdim  {"mv5t",	 &legacy_cpu, ARM_ARCH_V5T, N_("use -march=armv5t")},
20036218822Sdim  {"marmv5t",	 &legacy_cpu, ARM_ARCH_V5T, N_("use -march=armv5t")},
20037218822Sdim  {"mv5e",	 &legacy_cpu, ARM_ARCH_V5TE, N_("use -march=armv5te")},
20038218822Sdim  {"marmv5e",	 &legacy_cpu, ARM_ARCH_V5TE, N_("use -march=armv5te")},
2003989857Sobrien
20040218822Sdim  /* Floating point variants -- don't add any more to this list either.	 */
20041218822Sdim  {"mfpe-old", &legacy_fpu, FPU_ARCH_FPE, N_("use -mfpu=fpe")},
20042218822Sdim  {"mfpa10",   &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa10")},
20043218822Sdim  {"mfpa11",   &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa11")},
20044218822Sdim  {"mno-fpu",  &legacy_fpu, ARM_ARCH_NONE,
2004589857Sobrien   N_("use either -mfpu=softfpa or -mfpu=softvfp")},
2004689857Sobrien
20047218822Sdim  {NULL, NULL, ARM_ARCH_NONE, NULL}
2004889857Sobrien};
2004989857Sobrien
2005089857Sobrienstruct arm_cpu_option_table
2005189857Sobrien{
2005289857Sobrien  char *name;
20053218822Sdim  const arm_feature_set	value;
2005489857Sobrien  /* For some CPUs we assume an FPU unless the user explicitly sets
20055218822Sdim     -mfpu=...	*/
20056218822Sdim  const arm_feature_set	default_fpu;
20057218822Sdim  /* The canonical name of the CPU, or NULL to use NAME converted to upper
20058218822Sdim     case.  */
20059218822Sdim  const char *canonical_name;
2006089857Sobrien};
2006189857Sobrien
2006289857Sobrien/* This list should, at a minimum, contain all the cpu names
2006389857Sobrien   recognized by GCC.  */
20064218822Sdimstatic const struct arm_cpu_option_table arm_cpus[] =
2006589857Sobrien{
20066218822Sdim  {"all",		ARM_ANY,	 FPU_ARCH_FPA,    NULL},
20067218822Sdim  {"arm1",		ARM_ARCH_V1,	 FPU_ARCH_FPA,    NULL},
20068218822Sdim  {"arm2",		ARM_ARCH_V2,	 FPU_ARCH_FPA,    NULL},
20069218822Sdim  {"arm250",		ARM_ARCH_V2S,	 FPU_ARCH_FPA,    NULL},
20070218822Sdim  {"arm3",		ARM_ARCH_V2S,	 FPU_ARCH_FPA,    NULL},
20071218822Sdim  {"arm6",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20072218822Sdim  {"arm60",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20073218822Sdim  {"arm600",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20074218822Sdim  {"arm610",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20075218822Sdim  {"arm620",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20076218822Sdim  {"arm7",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20077218822Sdim  {"arm7m",		ARM_ARCH_V3M,	 FPU_ARCH_FPA,    NULL},
20078218822Sdim  {"arm7d",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20079218822Sdim  {"arm7dm",		ARM_ARCH_V3M,	 FPU_ARCH_FPA,    NULL},
20080218822Sdim  {"arm7di",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20081218822Sdim  {"arm7dmi",		ARM_ARCH_V3M,	 FPU_ARCH_FPA,    NULL},
20082218822Sdim  {"arm70",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20083218822Sdim  {"arm700",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20084218822Sdim  {"arm700i",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20085218822Sdim  {"arm710",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20086218822Sdim  {"arm710t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20087218822Sdim  {"arm720",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20088218822Sdim  {"arm720t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20089218822Sdim  {"arm740t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20090218822Sdim  {"arm710c",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20091218822Sdim  {"arm7100",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20092218822Sdim  {"arm7500",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20093218822Sdim  {"arm7500fe",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20094218822Sdim  {"arm7t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20095218822Sdim  {"arm7tdmi",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20096218822Sdim  {"arm7tdmi-s",	ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20097218822Sdim  {"arm8",		ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
20098218822Sdim  {"arm810",		ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
20099218822Sdim  {"strongarm",		ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
20100218822Sdim  {"strongarm1",	ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
20101218822Sdim  {"strongarm110",	ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
20102218822Sdim  {"strongarm1100",	ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
20103218822Sdim  {"strongarm1110",	ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
20104218822Sdim  {"arm9",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20105218822Sdim  {"arm920",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    "ARM920T"},
20106218822Sdim  {"arm920t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20107218822Sdim  {"arm922t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20108218822Sdim  {"arm940t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20109218822Sdim  {"arm9tdmi",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,	  NULL},
2011089857Sobrien  /* For V5 or later processors we default to using VFP; but the user
20111218822Sdim     should really set the FPU type explicitly.	 */
20112218822Sdim  {"arm9e-r0",		ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL},
20113218822Sdim  {"arm9e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
20114218822Sdim  {"arm926ej",		ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP_V2, "ARM926EJ-S"},
20115218822Sdim  {"arm926ejs",		ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP_V2, "ARM926EJ-S"},
20116218822Sdim  {"arm926ej-s",	ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP_V2, NULL},
20117218822Sdim  {"arm946e-r0",	ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL},
20118218822Sdim  {"arm946e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, "ARM946E-S"},
20119218822Sdim  {"arm946e-s",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
20120218822Sdim  {"arm966e-r0",	ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL},
20121218822Sdim  {"arm966e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, "ARM966E-S"},
20122218822Sdim  {"arm966e-s",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
20123218822Sdim  {"arm968e-s",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
20124218822Sdim  {"arm10t",		ARM_ARCH_V5T,	 FPU_ARCH_VFP_V1, NULL},
20125218822Sdim  {"arm10tdmi",		ARM_ARCH_V5T,	 FPU_ARCH_VFP_V1, NULL},
20126218822Sdim  {"arm10e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
20127218822Sdim  {"arm1020",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, "ARM1020E"},
20128218822Sdim  {"arm1020t",		ARM_ARCH_V5T,	 FPU_ARCH_VFP_V1, NULL},
20129218822Sdim  {"arm1020e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
20130218822Sdim  {"arm1022e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
20131218822Sdim  {"arm1026ejs",	ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP_V2, "ARM1026EJ-S"},
20132218822Sdim  {"arm1026ej-s",	ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP_V2, NULL},
20133218822Sdim  {"arm1136js",		ARM_ARCH_V6,	 FPU_NONE,	  "ARM1136J-S"},
20134218822Sdim  {"arm1136j-s",	ARM_ARCH_V6,	 FPU_NONE,	  NULL},
20135218822Sdim  {"arm1136jfs",	ARM_ARCH_V6,	 FPU_ARCH_VFP_V2, "ARM1136JF-S"},
20136218822Sdim  {"arm1136jf-s",	ARM_ARCH_V6,	 FPU_ARCH_VFP_V2, NULL},
20137218822Sdim  {"mpcore",		ARM_ARCH_V6K,	 FPU_ARCH_VFP_V2, NULL},
20138218822Sdim  {"mpcorenovfp",	ARM_ARCH_V6K,	 FPU_NONE,	  NULL},
20139218822Sdim  {"arm1156t2-s",	ARM_ARCH_V6T2,	 FPU_NONE,	  NULL},
20140218822Sdim  {"arm1156t2f-s",	ARM_ARCH_V6T2,	 FPU_ARCH_VFP_V2, NULL},
20141218822Sdim  {"arm1176jz-s",	ARM_ARCH_V6ZK,	 FPU_NONE,	  NULL},
20142218822Sdim  {"arm1176jzf-s",	ARM_ARCH_V6ZK,	 FPU_ARCH_VFP_V2, NULL},
20143218822Sdim  {"cortex-a8",		ARM_ARCH_V7A,	 ARM_FEATURE(0, FPU_VFP_V3
20144218822Sdim                                                        | FPU_NEON_EXT_V1),
20145218822Sdim                                                          NULL},
20146239272Sgonzo  {"cortex-a9",		ARM_ARCH_V7A,	 ARM_FEATURE(0, FPU_VFP_V3
20147239272Sgonzo                                                        | FPU_NEON_EXT_V1),
20148239272Sgonzo                                                          NULL},
20149218822Sdim  {"cortex-r4",		ARM_ARCH_V7R,	 FPU_NONE,	  NULL},
20150218822Sdim  {"cortex-m3",		ARM_ARCH_V7M,	 FPU_NONE,	  NULL},
2015189857Sobrien  /* ??? XSCALE is really an architecture.  */
20152218822Sdim  {"xscale",		ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL},
20153130561Sobrien  /* ??? iwmmxt is not a processor.  */
20154218822Sdim  {"iwmmxt",		ARM_ARCH_IWMMXT, FPU_ARCH_VFP_V2, NULL},
20155218822Sdim  {"iwmmxt2",		ARM_ARCH_IWMMXT2,FPU_ARCH_VFP_V2, NULL},
20156218822Sdim  {"i80200",		ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL},
2015789857Sobrien  /* Maverick */
20158218822Sdim  {"ep9312",	ARM_FEATURE(ARM_AEXT_V4T, ARM_CEXT_MAVERICK), FPU_ARCH_MAVERICK, "ARM920T"},
20159218822Sdim  {NULL,		ARM_ARCH_NONE,	 ARM_ARCH_NONE, NULL}
2016089857Sobrien};
20161104834Sobrien
2016289857Sobrienstruct arm_arch_option_table
2016389857Sobrien{
2016489857Sobrien  char *name;
20165218822Sdim  const arm_feature_set	value;
20166218822Sdim  const arm_feature_set	default_fpu;
2016789857Sobrien};
2016889857Sobrien
2016989857Sobrien/* This list should, at a minimum, contain all the architecture names
2017089857Sobrien   recognized by GCC.  */
20171218822Sdimstatic const struct arm_arch_option_table arm_archs[] =
2017289857Sobrien{
2017389857Sobrien  {"all",		ARM_ANY,	 FPU_ARCH_FPA},
2017489857Sobrien  {"armv1",		ARM_ARCH_V1,	 FPU_ARCH_FPA},
2017589857Sobrien  {"armv2",		ARM_ARCH_V2,	 FPU_ARCH_FPA},
2017689857Sobrien  {"armv2a",		ARM_ARCH_V2S,	 FPU_ARCH_FPA},
2017789857Sobrien  {"armv2s",		ARM_ARCH_V2S,	 FPU_ARCH_FPA},
2017889857Sobrien  {"armv3",		ARM_ARCH_V3,	 FPU_ARCH_FPA},
2017989857Sobrien  {"armv3m",		ARM_ARCH_V3M,	 FPU_ARCH_FPA},
2018089857Sobrien  {"armv4",		ARM_ARCH_V4,	 FPU_ARCH_FPA},
2018189857Sobrien  {"armv4xm",		ARM_ARCH_V4xM,	 FPU_ARCH_FPA},
2018289857Sobrien  {"armv4t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA},
2018389857Sobrien  {"armv4txm",		ARM_ARCH_V4TxM,	 FPU_ARCH_FPA},
2018489857Sobrien  {"armv5",		ARM_ARCH_V5,	 FPU_ARCH_VFP},
2018589857Sobrien  {"armv5t",		ARM_ARCH_V5T,	 FPU_ARCH_VFP},
2018689857Sobrien  {"armv5txm",		ARM_ARCH_V5TxM,	 FPU_ARCH_VFP},
2018789857Sobrien  {"armv5te",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP},
2018889857Sobrien  {"armv5texp",		ARM_ARCH_V5TExP, FPU_ARCH_VFP},
20189218822Sdim  {"armv5tej",		ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP},
20190218822Sdim  {"armv6",		ARM_ARCH_V6,	 FPU_ARCH_VFP},
20191218822Sdim  {"armv6j",		ARM_ARCH_V6,	 FPU_ARCH_VFP},
20192218822Sdim  {"armv6k",		ARM_ARCH_V6K,	 FPU_ARCH_VFP},
20193218822Sdim  {"armv6z",		ARM_ARCH_V6Z,	 FPU_ARCH_VFP},
20194218822Sdim  {"armv6zk",		ARM_ARCH_V6ZK,	 FPU_ARCH_VFP},
20195218822Sdim  {"armv6t2",		ARM_ARCH_V6T2,	 FPU_ARCH_VFP},
20196218822Sdim  {"armv6kt2",		ARM_ARCH_V6KT2,	 FPU_ARCH_VFP},
20197218822Sdim  {"armv6zt2",		ARM_ARCH_V6ZT2,	 FPU_ARCH_VFP},
20198218822Sdim  {"armv6zkt2",		ARM_ARCH_V6ZKT2, FPU_ARCH_VFP},
20199218822Sdim  {"armv7",		ARM_ARCH_V7,	 FPU_ARCH_VFP},
20200218822Sdim  /* The official spelling of the ARMv7 profile variants is the dashed form.
20201218822Sdim     Accept the non-dashed form for compatibility with old toolchains.  */
20202218822Sdim  {"armv7a",		ARM_ARCH_V7A,	 FPU_ARCH_VFP},
20203218822Sdim  {"armv7r",		ARM_ARCH_V7R,	 FPU_ARCH_VFP},
20204218822Sdim  {"armv7m",		ARM_ARCH_V7M,	 FPU_ARCH_VFP},
20205218822Sdim  {"armv7-a",		ARM_ARCH_V7A,	 FPU_ARCH_VFP},
20206218822Sdim  {"armv7-r",		ARM_ARCH_V7R,	 FPU_ARCH_VFP},
20207218822Sdim  {"armv7-m",		ARM_ARCH_V7M,	 FPU_ARCH_VFP},
2020889857Sobrien  {"xscale",		ARM_ARCH_XSCALE, FPU_ARCH_VFP},
20209130561Sobrien  {"iwmmxt",		ARM_ARCH_IWMMXT, FPU_ARCH_VFP},
20210218822Sdim  {"iwmmxt2",		ARM_ARCH_IWMMXT2,FPU_ARCH_VFP},
20211218822Sdim  {NULL,		ARM_ARCH_NONE,	 ARM_ARCH_NONE}
2021289857Sobrien};
2021389857Sobrien
2021489857Sobrien/* ISA extensions in the co-processor space.  */
20215218822Sdimstruct arm_option_cpu_value_table
2021689857Sobrien{
2021789857Sobrien  char *name;
20218218822Sdim  const arm_feature_set value;
2021989857Sobrien};
2022089857Sobrien
20221218822Sdimstatic const struct arm_option_cpu_value_table arm_extensions[] =
2022289857Sobrien{
20223218822Sdim  {"maverick",		ARM_FEATURE (0, ARM_CEXT_MAVERICK)},
20224218822Sdim  {"xscale",		ARM_FEATURE (0, ARM_CEXT_XSCALE)},
20225218822Sdim  {"iwmmxt",		ARM_FEATURE (0, ARM_CEXT_IWMMXT)},
20226218822Sdim  {"iwmmxt2",		ARM_FEATURE (0, ARM_CEXT_IWMMXT2)},
20227269394Sian  {"sec",		ARM_FEATURE (ARM_EXT_V6Z, 0)},
20228218822Sdim  {NULL,		ARM_ARCH_NONE}
2022989857Sobrien};
2023089857Sobrien
2023189857Sobrien/* This list should, at a minimum, contain all the fpu names
2023289857Sobrien   recognized by GCC.  */
20233218822Sdimstatic const struct arm_option_cpu_value_table arm_fpus[] =
2023489857Sobrien{
2023589857Sobrien  {"softfpa",		FPU_NONE},
2023689857Sobrien  {"fpe",		FPU_ARCH_FPE},
2023789857Sobrien  {"fpe2",		FPU_ARCH_FPE},
2023889857Sobrien  {"fpe3",		FPU_ARCH_FPA},	/* Third release supports LFM/SFM.  */
2023989857Sobrien  {"fpa",		FPU_ARCH_FPA},
2024089857Sobrien  {"fpa10",		FPU_ARCH_FPA},
2024189857Sobrien  {"fpa11",		FPU_ARCH_FPA},
2024289857Sobrien  {"arm7500fe",		FPU_ARCH_FPA},
2024389857Sobrien  {"softvfp",		FPU_ARCH_VFP},
2024489857Sobrien  {"softvfp+vfp",	FPU_ARCH_VFP_V2},
2024589857Sobrien  {"vfp",		FPU_ARCH_VFP_V2},
20246244274Sandrew  {"vfpv2",		FPU_ARCH_VFP_V2},
2024789857Sobrien  {"vfp9",		FPU_ARCH_VFP_V2},
20248218822Sdim  {"vfp3",              FPU_ARCH_VFP_V3},
20249239272Sgonzo  {"vfpv3",             FPU_ARCH_VFP_V3},
2025089857Sobrien  {"vfp10",		FPU_ARCH_VFP_V2},
2025189857Sobrien  {"vfp10-r0",		FPU_ARCH_VFP_V1},
2025289857Sobrien  {"vfpxd",		FPU_ARCH_VFP_V1xD},
2025389857Sobrien  {"arm1020t",		FPU_ARCH_VFP_V1},
2025489857Sobrien  {"arm1020e",		FPU_ARCH_VFP_V2},
20255130561Sobrien  {"arm1136jfs",	FPU_ARCH_VFP_V2},
20256218822Sdim  {"arm1136jf-s",	FPU_ARCH_VFP_V2},
20257130561Sobrien  {"maverick",		FPU_ARCH_MAVERICK},
20258218822Sdim  {"neon",              FPU_ARCH_VFP_V3_PLUS_NEON_V1},
20259218822Sdim  {NULL,		ARM_ARCH_NONE}
2026089857Sobrien};
2026189857Sobrien
20262218822Sdimstruct arm_option_value_table
20263130561Sobrien{
20264130561Sobrien  char *name;
20265218822Sdim  long value;
20266130561Sobrien};
20267130561Sobrien
20268218822Sdimstatic const struct arm_option_value_table arm_float_abis[] =
20269130561Sobrien{
20270130561Sobrien  {"hard",	ARM_FLOAT_ABI_HARD},
20271130561Sobrien  {"softfp",	ARM_FLOAT_ABI_SOFTFP},
20272130561Sobrien  {"soft",	ARM_FLOAT_ABI_SOFT},
20273218822Sdim  {NULL,	0}
20274130561Sobrien};
20275130561Sobrien
20276218822Sdim#ifdef OBJ_ELF
20277218822Sdim/* We only know how to output GNU and ver 4/5 (AAELF) formats.  */
20278218822Sdimstatic const struct arm_option_value_table arm_eabis[] =
20279218822Sdim{
20280218822Sdim  {"gnu",	EF_ARM_EABI_UNKNOWN},
20281218822Sdim  {"4",		EF_ARM_EABI_VER4},
20282218822Sdim  {"5",		EF_ARM_EABI_VER5},
20283218822Sdim  {NULL,	0}
20284218822Sdim};
20285218822Sdim#endif
20286218822Sdim
2028789857Sobrienstruct arm_long_option_table
2028889857Sobrien{
20289218822Sdim  char * option;		/* Substring to match.	*/
20290218822Sdim  char * help;			/* Help information.  */
20291218822Sdim  int (* func) (char * subopt);	/* Function to decode sub-option.  */
20292218822Sdim  char * deprecated;		/* If non-null, print this message.  */
2029389857Sobrien};
2029489857Sobrien
2029589857Sobrienstatic int
20296218822Sdimarm_parse_extension (char * str, const arm_feature_set **opt_p)
2029789857Sobrien{
20298218822Sdim  arm_feature_set *ext_set = xmalloc (sizeof (arm_feature_set));
20299218822Sdim
20300218822Sdim  /* Copy the feature set, so that we can modify it.  */
20301218822Sdim  *ext_set = **opt_p;
20302218822Sdim  *opt_p = ext_set;
20303218822Sdim
2030489857Sobrien  while (str != NULL && *str != 0)
2030560484Sobrien    {
20306218822Sdim      const struct arm_option_cpu_value_table * opt;
20307218822Sdim      char * ext;
2030889857Sobrien      int optlen;
2030960484Sobrien
2031089857Sobrien      if (*str != '+')
2031160484Sobrien	{
2031289857Sobrien	  as_bad (_("invalid architectural extension"));
2031389857Sobrien	  return 0;
2031489857Sobrien	}
2031560484Sobrien
2031689857Sobrien      str++;
2031789857Sobrien      ext = strchr (str, '+');
2031860484Sobrien
2031989857Sobrien      if (ext != NULL)
2032089857Sobrien	optlen = ext - str;
2032189857Sobrien      else
2032289857Sobrien	optlen = strlen (str);
2032377298Sobrien
2032489857Sobrien      if (optlen == 0)
2032589857Sobrien	{
2032689857Sobrien	  as_bad (_("missing architectural extension"));
2032789857Sobrien	  return 0;
2032889857Sobrien	}
2032960484Sobrien
2033089857Sobrien      for (opt = arm_extensions; opt->name != NULL; opt++)
2033189857Sobrien	if (strncmp (opt->name, str, optlen) == 0)
2033289857Sobrien	  {
20333218822Sdim	    ARM_MERGE_FEATURE_SETS (*ext_set, *ext_set, opt->value);
2033489857Sobrien	    break;
2033589857Sobrien	  }
2033660484Sobrien
2033789857Sobrien      if (opt->name == NULL)
2033889857Sobrien	{
2033989857Sobrien	  as_bad (_("unknown architectural extnsion `%s'"), str);
2034089857Sobrien	  return 0;
2034189857Sobrien	}
2034277298Sobrien
2034389857Sobrien      str = ext;
2034489857Sobrien    };
2034560484Sobrien
2034689857Sobrien  return 1;
2034789857Sobrien}
2034860484Sobrien
2034989857Sobrienstatic int
20350218822Sdimarm_parse_cpu (char * str)
2035189857Sobrien{
20352218822Sdim  const struct arm_cpu_option_table * opt;
20353218822Sdim  char * ext = strchr (str, '+');
2035489857Sobrien  int optlen;
2035577298Sobrien
2035689857Sobrien  if (ext != NULL)
2035789857Sobrien    optlen = ext - str;
2035889857Sobrien  else
2035989857Sobrien    optlen = strlen (str);
2036077298Sobrien
2036189857Sobrien  if (optlen == 0)
2036289857Sobrien    {
2036389857Sobrien      as_bad (_("missing cpu name `%s'"), str);
2036489857Sobrien      return 0;
2036589857Sobrien    }
2036660484Sobrien
2036789857Sobrien  for (opt = arm_cpus; opt->name != NULL; opt++)
2036889857Sobrien    if (strncmp (opt->name, str, optlen) == 0)
2036989857Sobrien      {
20370218822Sdim	mcpu_cpu_opt = &opt->value;
20371218822Sdim	mcpu_fpu_opt = &opt->default_fpu;
20372218822Sdim	if (opt->canonical_name)
20373218822Sdim	  strcpy(selected_cpu_name, opt->canonical_name);
20374218822Sdim	else
20375218822Sdim	  {
20376218822Sdim	    int i;
20377218822Sdim	    for (i = 0; i < optlen; i++)
20378218822Sdim	      selected_cpu_name[i] = TOUPPER (opt->name[i]);
20379218822Sdim	    selected_cpu_name[i] = 0;
20380218822Sdim	  }
2038160484Sobrien
2038289857Sobrien	if (ext != NULL)
2038389857Sobrien	  return arm_parse_extension (ext, &mcpu_cpu_opt);
2038460484Sobrien
2038589857Sobrien	return 1;
2038689857Sobrien      }
2038760484Sobrien
2038889857Sobrien  as_bad (_("unknown cpu `%s'"), str);
2038989857Sobrien  return 0;
2039089857Sobrien}
2039160484Sobrien
2039289857Sobrienstatic int
20393218822Sdimarm_parse_arch (char * str)
2039489857Sobrien{
20395218822Sdim  const struct arm_arch_option_table *opt;
2039689857Sobrien  char *ext = strchr (str, '+');
2039789857Sobrien  int optlen;
2039860484Sobrien
2039989857Sobrien  if (ext != NULL)
2040089857Sobrien    optlen = ext - str;
2040189857Sobrien  else
2040289857Sobrien    optlen = strlen (str);
2040360484Sobrien
2040489857Sobrien  if (optlen == 0)
2040589857Sobrien    {
2040689857Sobrien      as_bad (_("missing architecture name `%s'"), str);
2040789857Sobrien      return 0;
2040889857Sobrien    }
2040977298Sobrien
2041089857Sobrien  for (opt = arm_archs; opt->name != NULL; opt++)
20411269393Sian    if (strncmp (opt->name, str, optlen) == 0)
2041289857Sobrien      {
20413218822Sdim	march_cpu_opt = &opt->value;
20414218822Sdim	march_fpu_opt = &opt->default_fpu;
20415218822Sdim	strcpy(selected_cpu_name, opt->name);
2041660484Sobrien
2041789857Sobrien	if (ext != NULL)
2041889857Sobrien	  return arm_parse_extension (ext, &march_cpu_opt);
2041977298Sobrien
2042089857Sobrien	return 1;
2042189857Sobrien      }
2042260484Sobrien
2042389857Sobrien  as_bad (_("unknown architecture `%s'\n"), str);
2042489857Sobrien  return 0;
2042589857Sobrien}
2042677298Sobrien
2042789857Sobrienstatic int
20428218822Sdimarm_parse_fpu (char * str)
2042989857Sobrien{
20430218822Sdim  const struct arm_option_cpu_value_table * opt;
2043177298Sobrien
2043289857Sobrien  for (opt = arm_fpus; opt->name != NULL; opt++)
20433218822Sdim    if (streq (opt->name, str))
2043489857Sobrien      {
20435218822Sdim	mfpu_opt = &opt->value;
2043689857Sobrien	return 1;
2043789857Sobrien      }
2043877298Sobrien
2043989857Sobrien  as_bad (_("unknown floating point format `%s'\n"), str);
2044089857Sobrien  return 0;
2044189857Sobrien}
2044277298Sobrien
20443130561Sobrienstatic int
20444218822Sdimarm_parse_float_abi (char * str)
20445130561Sobrien{
20446218822Sdim  const struct arm_option_value_table * opt;
20447130561Sobrien
20448130561Sobrien  for (opt = arm_float_abis; opt->name != NULL; opt++)
20449218822Sdim    if (streq (opt->name, str))
20450130561Sobrien      {
20451130561Sobrien	mfloat_abi_opt = opt->value;
20452130561Sobrien	return 1;
20453130561Sobrien      }
20454130561Sobrien
20455130561Sobrien  as_bad (_("unknown floating point abi `%s'\n"), str);
20456130561Sobrien  return 0;
20457130561Sobrien}
20458130561Sobrien
20459218822Sdim#ifdef OBJ_ELF
20460218822Sdimstatic int
20461218822Sdimarm_parse_eabi (char * str)
20462218822Sdim{
20463218822Sdim  const struct arm_option_value_table *opt;
20464218822Sdim
20465218822Sdim  for (opt = arm_eabis; opt->name != NULL; opt++)
20466218822Sdim    if (streq (opt->name, str))
20467218822Sdim      {
20468218822Sdim	meabi_flags = opt->value;
20469218822Sdim	return 1;
20470218822Sdim      }
20471218822Sdim  as_bad (_("unknown EABI `%s'\n"), str);
20472218822Sdim  return 0;
20473218822Sdim}
20474218822Sdim#endif
20475218822Sdim
2047689857Sobrienstruct arm_long_option_table arm_long_opts[] =
2047789857Sobrien{
2047889857Sobrien  {"mcpu=", N_("<cpu name>\t  assemble for CPU <cpu name>"),
2047989857Sobrien   arm_parse_cpu, NULL},
2048089857Sobrien  {"march=", N_("<arch name>\t  assemble for architecture <arch name>"),
2048189857Sobrien   arm_parse_arch, NULL},
2048289857Sobrien  {"mfpu=", N_("<fpu name>\t  assemble for FPU architecture <fpu name>"),
2048389857Sobrien   arm_parse_fpu, NULL},
20484130561Sobrien  {"mfloat-abi=", N_("<abi>\t  assemble for floating point ABI <abi>"),
20485130561Sobrien   arm_parse_float_abi, NULL},
20486218822Sdim#ifdef OBJ_ELF
20487218822Sdim  {"meabi=", N_("<ver>\t  assemble for eabi version <ver>"),
20488218822Sdim   arm_parse_eabi, NULL},
20489218822Sdim#endif
2049089857Sobrien  {NULL, NULL, 0, NULL}
2049189857Sobrien};
2049277298Sobrien
2049389857Sobrienint
20494218822Sdimmd_parse_option (int c, char * arg)
2049589857Sobrien{
2049689857Sobrien  struct arm_option_table *opt;
20497218822Sdim  const struct arm_legacy_option_table *fopt;
2049889857Sobrien  struct arm_long_option_table *lopt;
2049977298Sobrien
2050089857Sobrien  switch (c)
2050189857Sobrien    {
2050289857Sobrien#ifdef OPTION_EB
2050389857Sobrien    case OPTION_EB:
2050489857Sobrien      target_big_endian = 1;
2050589857Sobrien      break;
2050689857Sobrien#endif
2050760484Sobrien
2050889857Sobrien#ifdef OPTION_EL
2050989857Sobrien    case OPTION_EL:
2051089857Sobrien      target_big_endian = 0;
2051189857Sobrien      break;
2051289857Sobrien#endif
2051377298Sobrien
2051489857Sobrien    case 'a':
20515104834Sobrien      /* Listing option.  Just ignore these, we don't support additional
20516218822Sdim	 ones.	*/
2051789857Sobrien      return 0;
2051877298Sobrien
2051989857Sobrien    default:
2052089857Sobrien      for (opt = arm_opts; opt->option != NULL; opt++)
2052189857Sobrien	{
2052289857Sobrien	  if (c == opt->option[0]
2052389857Sobrien	      && ((arg == NULL && opt->option[1] == 0)
20524218822Sdim		  || streq (arg, opt->option + 1)))
2052589857Sobrien	    {
2052689857Sobrien#if WARN_DEPRECATED
2052789857Sobrien	      /* If the option is deprecated, tell the user.  */
2052889857Sobrien	      if (opt->deprecated != NULL)
2052989857Sobrien		as_tsktsk (_("option `-%c%s' is deprecated: %s"), c,
2053089857Sobrien			   arg ? arg : "", _(opt->deprecated));
2053189857Sobrien#endif
2053289857Sobrien
2053389857Sobrien	      if (opt->var != NULL)
2053489857Sobrien		*opt->var = opt->value;
2053589857Sobrien
2053689857Sobrien	      return 1;
2053760484Sobrien	    }
2053860484Sobrien	}
2053960484Sobrien
20540218822Sdim      for (fopt = arm_legacy_opts; fopt->option != NULL; fopt++)
20541218822Sdim	{
20542218822Sdim	  if (c == fopt->option[0]
20543218822Sdim	      && ((arg == NULL && fopt->option[1] == 0)
20544218822Sdim		  || streq (arg, fopt->option + 1)))
20545218822Sdim	    {
20546218822Sdim#if WARN_DEPRECATED
20547218822Sdim	      /* If the option is deprecated, tell the user.  */
20548218822Sdim	      if (fopt->deprecated != NULL)
20549218822Sdim		as_tsktsk (_("option `-%c%s' is deprecated: %s"), c,
20550218822Sdim			   arg ? arg : "", _(fopt->deprecated));
20551218822Sdim#endif
20552218822Sdim
20553218822Sdim	      if (fopt->var != NULL)
20554218822Sdim		*fopt->var = &fopt->value;
20555218822Sdim
20556218822Sdim	      return 1;
20557218822Sdim	    }
20558218822Sdim	}
20559218822Sdim
2056089857Sobrien      for (lopt = arm_long_opts; lopt->option != NULL; lopt++)
2056189857Sobrien	{
20562104834Sobrien	  /* These options are expected to have an argument.  */
2056389857Sobrien	  if (c == lopt->option[0]
2056489857Sobrien	      && arg != NULL
20565104834Sobrien	      && strncmp (arg, lopt->option + 1,
2056689857Sobrien			  strlen (lopt->option + 1)) == 0)
2056789857Sobrien	    {
2056889857Sobrien#if WARN_DEPRECATED
2056989857Sobrien	      /* If the option is deprecated, tell the user.  */
2057089857Sobrien	      if (lopt->deprecated != NULL)
2057189857Sobrien		as_tsktsk (_("option `-%c%s' is deprecated: %s"), c, arg,
2057289857Sobrien			   _(lopt->deprecated));
2057360484Sobrien#endif
2057477298Sobrien
2057589857Sobrien	      /* Call the sup-option parser.  */
20576218822Sdim	      return lopt->func (arg + strlen (lopt->option) - 1);
2057789857Sobrien	    }
2057889857Sobrien	}
2057989857Sobrien
2058060484Sobrien      return 0;
2058160484Sobrien    }
2058260484Sobrien
2058377298Sobrien  return 1;
2058460484Sobrien}
2058560484Sobrien
2058660484Sobrienvoid
20587218822Sdimmd_show_usage (FILE * fp)
2058860484Sobrien{
2058989857Sobrien  struct arm_option_table *opt;
2059089857Sobrien  struct arm_long_option_table *lopt;
2059189857Sobrien
2059289857Sobrien  fprintf (fp, _(" ARM-specific assembler options:\n"));
2059389857Sobrien
2059489857Sobrien  for (opt = arm_opts; opt->option != NULL; opt++)
2059589857Sobrien    if (opt->help != NULL)
2059689857Sobrien      fprintf (fp, "  -%-23s%s\n", opt->option, _(opt->help));
2059789857Sobrien
2059889857Sobrien  for (lopt = arm_long_opts; lopt->option != NULL; lopt++)
2059989857Sobrien    if (lopt->help != NULL)
2060089857Sobrien      fprintf (fp, "  -%s%s\n", lopt->option, _(lopt->help));
2060189857Sobrien
2060289857Sobrien#ifdef OPTION_EB
2060360484Sobrien  fprintf (fp, _("\
2060489857Sobrien  -EB                     assemble code for a big-endian cpu\n"));
2060577298Sobrien#endif
2060689857Sobrien
2060789857Sobrien#ifdef OPTION_EL
2060860484Sobrien  fprintf (fp, _("\
2060989857Sobrien  -EL                     assemble code for a little-endian cpu\n"));
2061060484Sobrien#endif
2061160484Sobrien}
2061260484Sobrien
2061360484Sobrien
20614218822Sdim#ifdef OBJ_ELF
20615218822Sdimtypedef struct
2061660484Sobrien{
20617218822Sdim  int val;
20618218822Sdim  arm_feature_set flags;
20619218822Sdim} cpu_arch_ver_table;
2062060484Sobrien
20621218822Sdim/* Mapping from CPU features to EABI CPU arch values.  Table must be sorted
20622218822Sdim   least features first.  */
20623218822Sdimstatic const cpu_arch_ver_table cpu_arch_ver[] =
2062460484Sobrien{
20625218822Sdim    {1, ARM_ARCH_V4},
20626218822Sdim    {2, ARM_ARCH_V4T},
20627218822Sdim    {3, ARM_ARCH_V5},
20628218822Sdim    {4, ARM_ARCH_V5TE},
20629218822Sdim    {5, ARM_ARCH_V5TEJ},
20630218822Sdim    {6, ARM_ARCH_V6},
20631218822Sdim    {7, ARM_ARCH_V6Z},
20632218822Sdim    {8, ARM_ARCH_V6K},
20633218822Sdim    {9, ARM_ARCH_V6T2},
20634218822Sdim    {10, ARM_ARCH_V7A},
20635218822Sdim    {10, ARM_ARCH_V7R},
20636218822Sdim    {10, ARM_ARCH_V7M},
20637218822Sdim    {0, ARM_ARCH_NONE}
20638218822Sdim};
2063977298Sobrien
20640218822Sdim/* Set the public EABI object attributes.  */
20641218822Sdimstatic void
20642218822Sdimaeabi_set_public_attributes (void)
2064360484Sobrien{
20644218822Sdim  int arch;
20645218822Sdim  arm_feature_set flags;
20646218822Sdim  arm_feature_set tmp;
20647218822Sdim  const cpu_arch_ver_table *p;
2064877298Sobrien
20649218822Sdim  /* Choose the architecture based on the capabilities of the requested cpu
20650218822Sdim     (if any) and/or the instructions actually used.  */
20651218822Sdim  ARM_MERGE_FEATURE_SETS (flags, arm_arch_used, thumb_arch_used);
20652218822Sdim  ARM_MERGE_FEATURE_SETS (flags, flags, *mfpu_opt);
20653218822Sdim  ARM_MERGE_FEATURE_SETS (flags, flags, selected_cpu);
20654218822Sdim  /*Allow the user to override the reported architecture.  */
20655218822Sdim  if (object_arch)
20656130561Sobrien    {
20657218822Sdim      ARM_CLEAR_FEATURE (flags, flags, arm_arch_any);
20658218822Sdim      ARM_MERGE_FEATURE_SETS (flags, flags, *object_arch);
20659130561Sobrien    }
2066060484Sobrien
20661218822Sdim  tmp = flags;
20662218822Sdim  arch = 0;
20663218822Sdim  for (p = cpu_arch_ver; p->val; p++)
2066460484Sobrien    {
20665218822Sdim      if (ARM_CPU_HAS_FEATURE (tmp, p->flags))
2066677298Sobrien	{
20667218822Sdim	  arch = p->val;
20668218822Sdim	  ARM_CLEAR_FEATURE (tmp, tmp, p->flags);
2066977298Sobrien	}
2067060484Sobrien    }
2067160484Sobrien
20672218822Sdim  /* Tag_CPU_name.  */
20673218822Sdim  if (selected_cpu_name[0])
2067460484Sobrien    {
20675218822Sdim      char *p;
20676218822Sdim
20677218822Sdim      p = selected_cpu_name;
20678218822Sdim      if (strncmp(p, "armv", 4) == 0)
2067977298Sobrien	{
20680218822Sdim	  int i;
20681218822Sdim
20682218822Sdim	  p += 4;
20683218822Sdim	  for (i = 0; p[i]; i++)
20684218822Sdim	    p[i] = TOUPPER (p[i]);
2068577298Sobrien	}
20686218822Sdim      bfd_elf_add_proc_attr_string (stdoutput, 5, p);
2068777298Sobrien    }
20688218822Sdim  /* Tag_CPU_arch.  */
20689218822Sdim  bfd_elf_add_proc_attr_int (stdoutput, 6, arch);
20690218822Sdim  /* Tag_CPU_arch_profile.  */
20691218822Sdim  if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7a))
20692218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 7, 'A');
20693218822Sdim  else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7r))
20694218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 7, 'R');
20695218822Sdim  else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7m))
20696218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 7, 'M');
20697218822Sdim  /* Tag_ARM_ISA_use.  */
20698218822Sdim  if (ARM_CPU_HAS_FEATURE (arm_arch_used, arm_arch_full))
20699218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 8, 1);
20700218822Sdim  /* Tag_THUMB_ISA_use.  */
20701218822Sdim  if (ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_full))
20702218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 9,
20703218822Sdim	ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_t2) ? 2 : 1);
20704218822Sdim  /* Tag_VFP_arch.  */
20705218822Sdim  if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v3)
20706218822Sdim      || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v3))
20707218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 10, 3);
20708218822Sdim  else if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v2)
20709218822Sdim           || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v2))
20710218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 10, 2);
20711218822Sdim  else if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v1)
20712218822Sdim           || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v1)
20713218822Sdim           || ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v1xd)
20714218822Sdim           || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v1xd))
20715218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 10, 1);
20716218822Sdim  /* Tag_WMMX_arch.  */
20717218822Sdim  if (ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_cext_iwmmxt)
20718218822Sdim      || ARM_CPU_HAS_FEATURE (arm_arch_used, arm_cext_iwmmxt))
20719218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 11, 1);
20720218822Sdim  /* Tag_NEON_arch.  */
20721218822Sdim  if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_neon_ext_v1)
20722218822Sdim      || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_neon_ext_v1))
20723218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 12, 1);
2072460484Sobrien}
2072560484Sobrien
20726218822Sdim/* Add the default contents for the .ARM.attributes section.  */
20727218822Sdimvoid
20728218822Sdimarm_md_end (void)
2072960484Sobrien{
20730218822Sdim  if (EF_ARM_EABI_VERSION (meabi_flags) < EF_ARM_EABI_VER4)
20731218822Sdim    return;
2073277298Sobrien
20733218822Sdim  aeabi_set_public_attributes ();
2073460484Sobrien}
20735218822Sdim#endif /* OBJ_ELF */
2073660484Sobrien
2073760484Sobrien
20738218822Sdim/* Parse a .cpu directive.  */
2073960484Sobrien
20740218822Sdimstatic void
20741218822Sdims_arm_cpu (int ignored ATTRIBUTE_UNUSED)
2074260484Sobrien{
20743218822Sdim  const struct arm_cpu_option_table *opt;
20744218822Sdim  char *name;
20745218822Sdim  char saved_char;
2074660484Sobrien
20747218822Sdim  name = input_line_pointer;
20748218822Sdim  while (*input_line_pointer && !ISSPACE(*input_line_pointer))
20749218822Sdim    input_line_pointer++;
20750218822Sdim  saved_char = *input_line_pointer;
20751218822Sdim  *input_line_pointer = 0;
20752130561Sobrien
20753218822Sdim  /* Skip the first "all" entry.  */
20754218822Sdim  for (opt = arm_cpus + 1; opt->name != NULL; opt++)
20755218822Sdim    if (streq (opt->name, name))
20756218822Sdim      {
20757218822Sdim	mcpu_cpu_opt = &opt->value;
20758218822Sdim	selected_cpu = opt->value;
20759218822Sdim	if (opt->canonical_name)
20760218822Sdim	  strcpy(selected_cpu_name, opt->canonical_name);
20761218822Sdim	else
20762218822Sdim	  {
20763218822Sdim	    int i;
20764218822Sdim	    for (i = 0; opt->name[i]; i++)
20765218822Sdim	      selected_cpu_name[i] = TOUPPER (opt->name[i]);
20766218822Sdim	    selected_cpu_name[i] = 0;
20767218822Sdim	  }
20768218822Sdim	ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
20769218822Sdim	*input_line_pointer = saved_char;
20770218822Sdim	demand_empty_rest_of_line ();
20771218822Sdim	return;
20772218822Sdim      }
20773218822Sdim  as_bad (_("unknown cpu `%s'"), name);
20774218822Sdim  *input_line_pointer = saved_char;
20775218822Sdim  ignore_rest_of_line ();
2077660484Sobrien}
2077760484Sobrien
2077877298Sobrien
20779218822Sdim/* Parse a .arch directive.  */
20780130561Sobrien
20781218822Sdimstatic void
20782218822Sdims_arm_arch (int ignored ATTRIBUTE_UNUSED)
2078360484Sobrien{
20784218822Sdim  const struct arm_arch_option_table *opt;
20785218822Sdim  char saved_char;
20786218822Sdim  char *name;
2078777298Sobrien
20788218822Sdim  name = input_line_pointer;
20789218822Sdim  while (*input_line_pointer && !ISSPACE(*input_line_pointer))
20790218822Sdim    input_line_pointer++;
20791218822Sdim  saved_char = *input_line_pointer;
20792218822Sdim  *input_line_pointer = 0;
2079377298Sobrien
20794218822Sdim  /* Skip the first "all" entry.  */
20795218822Sdim  for (opt = arm_archs + 1; opt->name != NULL; opt++)
20796218822Sdim    if (streq (opt->name, name))
20797218822Sdim      {
20798218822Sdim	mcpu_cpu_opt = &opt->value;
20799218822Sdim	selected_cpu = opt->value;
20800218822Sdim	strcpy(selected_cpu_name, opt->name);
20801218822Sdim	ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
20802218822Sdim	*input_line_pointer = saved_char;
20803218822Sdim	demand_empty_rest_of_line ();
20804218822Sdim	return;
20805218822Sdim      }
2080660484Sobrien
20807218822Sdim  as_bad (_("unknown architecture `%s'\n"), name);
20808218822Sdim  *input_line_pointer = saved_char;
20809218822Sdim  ignore_rest_of_line ();
2081060484Sobrien}
2081160484Sobrien
20812269394Sian/* Parse a .arch_extension directive.  */
2081360484Sobrien
20814269394Sianstatic void
20815269394Sians_arm_arch_extension (int ignored ATTRIBUTE_UNUSED)
20816269394Sian{
20817269394Sian  const struct arm_option_cpu_value_table *opt;
20818269394Sian  char saved_char;
20819269394Sian  char *name;
20820269394Sian
20821269394Sian  name = input_line_pointer;
20822269394Sian  while (*input_line_pointer && !ISSPACE(*input_line_pointer))
20823269394Sian    input_line_pointer++;
20824269394Sian  saved_char = *input_line_pointer;
20825269394Sian  *input_line_pointer = 0;
20826269394Sian
20827269394Sian  for (opt = arm_extensions; opt->name != NULL; opt++)
20828269394Sian    if (streq (opt->name, name))
20829269394Sian      {
20830269394Sian	ARM_MERGE_FEATURE_SETS (cpu_variant, cpu_variant, opt->value);
20831269394Sian	*input_line_pointer = saved_char;
20832269394Sian	demand_empty_rest_of_line ();
20833269394Sian	return;
20834269394Sian      }
20835269394Sian
20836269394Sian  as_bad (_("unknown architecture `%s'\n"), name);
20837269394Sian  *input_line_pointer = saved_char;
20838269394Sian  ignore_rest_of_line ();
20839269394Sian}
20840269394Sian
20841218822Sdim/* Parse a .object_arch directive.  */
2084260484Sobrien
2084360484Sobrienstatic void
20844218822Sdims_arm_object_arch (int ignored ATTRIBUTE_UNUSED)
2084560484Sobrien{
20846218822Sdim  const struct arm_arch_option_table *opt;
20847218822Sdim  char saved_char;
20848218822Sdim  char *name;
2084960484Sobrien
20850218822Sdim  name = input_line_pointer;
20851218822Sdim  while (*input_line_pointer && !ISSPACE(*input_line_pointer))
20852218822Sdim    input_line_pointer++;
20853218822Sdim  saved_char = *input_line_pointer;
20854218822Sdim  *input_line_pointer = 0;
2085560484Sobrien
20856218822Sdim  /* Skip the first "all" entry.  */
20857218822Sdim  for (opt = arm_archs + 1; opt->name != NULL; opt++)
20858218822Sdim    if (streq (opt->name, name))
20859218822Sdim      {
20860218822Sdim	object_arch = &opt->value;
20861218822Sdim	*input_line_pointer = saved_char;
20862218822Sdim	demand_empty_rest_of_line ();
20863218822Sdim	return;
20864218822Sdim      }
2086560484Sobrien
20866218822Sdim  as_bad (_("unknown architecture `%s'\n"), name);
20867218822Sdim  *input_line_pointer = saved_char;
20868218822Sdim  ignore_rest_of_line ();
2086960484Sobrien}
2087060484Sobrien
2087178828Sobrien
20872218822Sdim/* Parse a .fpu directive.  */
2087378828Sobrien
20874218822Sdimstatic void
20875218822Sdims_arm_fpu (int ignored ATTRIBUTE_UNUSED)
2087678828Sobrien{
20877218822Sdim  const struct arm_option_cpu_value_table *opt;
20878218822Sdim  char saved_char;
20879218822Sdim  char *name;
2088078828Sobrien
20881218822Sdim  name = input_line_pointer;
20882218822Sdim  while (*input_line_pointer && !ISSPACE(*input_line_pointer))
20883218822Sdim    input_line_pointer++;
20884218822Sdim  saved_char = *input_line_pointer;
20885218822Sdim  *input_line_pointer = 0;
20886218822Sdim
20887218822Sdim  for (opt = arm_fpus; opt->name != NULL; opt++)
20888218822Sdim    if (streq (opt->name, name))
20889218822Sdim      {
20890218822Sdim	mfpu_opt = &opt->value;
20891218822Sdim	ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
20892218822Sdim	*input_line_pointer = saved_char;
20893218822Sdim	demand_empty_rest_of_line ();
20894218822Sdim	return;
20895218822Sdim      }
20896104834Sobrien
20897218822Sdim  as_bad (_("unknown floating point format `%s'\n"), name);
20898218822Sdim  *input_line_pointer = saved_char;
20899218822Sdim  ignore_rest_of_line ();
2090078828Sobrien}
2090178828Sobrien
20902218822Sdim/* Copy symbol information.  */
2090378828Sobrienvoid
20904218822Sdimarm_copy_symbol_attributes (symbolS *dest, symbolS *src)
2090578828Sobrien{
20906218822Sdim  ARM_GET_FLAG (dest) = ARM_GET_FLAG (src);
2090778828Sobrien}
20908