160484Sobrien/* tc-arm.c -- Assemble for the ARM
2218822Sdim   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
3218822Sdim   2004, 2005, 2006
477298Sobrien   Free Software Foundation, Inc.
560484Sobrien   Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
660484Sobrien	Modified by David Taylor (dtaylor@armltd.co.uk)
789857Sobrien	Cirrus coprocessor mods by Aldy Hernandez (aldyh@redhat.com)
8130561Sobrien	Cirrus coprocessor fixes by Petko Manolov (petkan@nucleusys.com)
9130561Sobrien	Cirrus coprocessor fixes by Vladimir Ivanov (vladitx@nucleusys.com)
1060484Sobrien
1160484Sobrien   This file is part of GAS, the GNU Assembler.
1260484Sobrien
1360484Sobrien   GAS is free software; you can redistribute it and/or modify
1460484Sobrien   it under the terms of the GNU General Public License as published by
1560484Sobrien   the Free Software Foundation; either version 2, or (at your option)
1660484Sobrien   any later version.
1760484Sobrien
1860484Sobrien   GAS is distributed in the hope that it will be useful,
1960484Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
20218822Sdim   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
2160484Sobrien   GNU General Public License for more details.
2260484Sobrien
2360484Sobrien   You should have received a copy of the GNU General Public License
2460484Sobrien   along with GAS; see the file COPYING.  If not, write to the Free
25218822Sdim   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
26218822Sdim   02110-1301, USA.  */
2760484Sobrien
28218822Sdim#include <limits.h>
29218822Sdim#include <stdarg.h>
30218822Sdim#define	 NO_RELOC 0
3160484Sobrien#include "as.h"
3289857Sobrien#include "safe-ctype.h"
3360484Sobrien#include "subsegs.h"
3460484Sobrien#include "obstack.h"
3560484Sobrien
36218822Sdim#include "opcode/arm.h"
37218822Sdim
3860484Sobrien#ifdef OBJ_ELF
3960484Sobrien#include "elf/arm.h"
40218822Sdim#include "dw2gencfi.h"
4160484Sobrien#endif
4260484Sobrien
43218822Sdim#include "dwarf2dbg.h"
4460484Sobrien
45218822Sdim#define WARN_DEPRECATED 1
4660484Sobrien
47218822Sdim#ifdef OBJ_ELF
48218822Sdim/* Must be at least the size of the largest unwind opcode (currently two).  */
49218822Sdim#define ARM_OPCODE_CHUNK_SIZE 8
5060484Sobrien
51218822Sdim/* This structure holds the unwinding state.  */
5289857Sobrien
53218822Sdimstatic struct
54218822Sdim{
55218822Sdim  symbolS *	  proc_start;
56218822Sdim  symbolS *	  table_entry;
57218822Sdim  symbolS *	  personality_routine;
58218822Sdim  int		  personality_index;
59218822Sdim  /* The segment containing the function.  */
60218822Sdim  segT		  saved_seg;
61218822Sdim  subsegT	  saved_subseg;
62218822Sdim  /* Opcodes generated from this function.  */
63218822Sdim  unsigned char * opcodes;
64218822Sdim  int		  opcode_count;
65218822Sdim  int		  opcode_alloc;
66218822Sdim  /* The number of bytes pushed to the stack.  */
67218822Sdim  offsetT	  frame_size;
68218822Sdim  /* We don't add stack adjustment opcodes immediately so that we can merge
69218822Sdim     multiple adjustments.  We can also omit the final adjustment
70218822Sdim     when using a frame pointer.  */
71218822Sdim  offsetT	  pending_offset;
72218822Sdim  /* These two fields are set by both unwind_movsp and unwind_setfp.  They
73218822Sdim     hold the reg+offset to use when restoring sp from a frame pointer.	 */
74218822Sdim  offsetT	  fp_offset;
75218822Sdim  int		  fp_reg;
76218822Sdim  /* Nonzero if an unwind_setfp directive has been seen.  */
77218822Sdim  unsigned	  fp_used:1;
78218822Sdim  /* Nonzero if the last opcode restores sp from fp_reg.  */
79218822Sdim  unsigned	  sp_restored:1;
80218822Sdim} unwind;
8189857Sobrien
82218822Sdim/* Bit N indicates that an R_ARM_NONE relocation has been output for
83218822Sdim   __aeabi_unwind_cpp_prN already if set. This enables dependencies to be
84218822Sdim   emitted only once per section, to save unnecessary bloat.  */
85218822Sdimstatic unsigned int marked_pr_dependency = 0;
8660484Sobrien
87218822Sdim#endif /* OBJ_ELF */
8860484Sobrien
89218822Sdim/* Results from operand parsing worker functions.  */
9060484Sobrien
91218822Sdimtypedef enum
92218822Sdim{
93218822Sdim  PARSE_OPERAND_SUCCESS,
94218822Sdim  PARSE_OPERAND_FAIL,
95218822Sdim  PARSE_OPERAND_FAIL_NO_BACKTRACK
96218822Sdim} parse_operand_result;
9789857Sobrien
98130561Sobrienenum arm_float_abi
99130561Sobrien{
100130561Sobrien  ARM_FLOAT_ABI_HARD,
101130561Sobrien  ARM_FLOAT_ABI_SOFTFP,
102130561Sobrien  ARM_FLOAT_ABI_SOFT
103130561Sobrien};
104130561Sobrien
105218822Sdim/* Types of processor to assemble for.	*/
10660484Sobrien#ifndef CPU_DEFAULT
10777298Sobrien#if defined __XSCALE__
108218822Sdim#define CPU_DEFAULT	ARM_ARCH_XSCALE
10977298Sobrien#else
11060484Sobrien#if defined __thumb__
111218822Sdim#define CPU_DEFAULT	ARM_ARCH_V5T
11260484Sobrien#endif
11360484Sobrien#endif
11477298Sobrien#endif
11560484Sobrien
11660484Sobrien#ifndef FPU_DEFAULT
117218822Sdim# ifdef TE_LINUX
118218822Sdim#  define FPU_DEFAULT FPU_ARCH_FPA
119218822Sdim# elif defined (TE_NetBSD)
120218822Sdim#  ifdef OBJ_ELF
121218822Sdim#   define FPU_DEFAULT FPU_ARCH_VFP	/* Soft-float, but VFP order.  */
122218822Sdim#  else
123218822Sdim    /* Legacy a.out format.  */
124218822Sdim#   define FPU_DEFAULT FPU_ARCH_FPA	/* Soft-float, but FPA order.  */
125218822Sdim#  endif
126218822Sdim# elif defined (TE_VXWORKS)
127218822Sdim#  define FPU_DEFAULT FPU_ARCH_VFP	/* Soft-float, VFP order.  */
128218822Sdim# else
129218822Sdim   /* For backwards compatibility, default to FPA.  */
130218822Sdim#  define FPU_DEFAULT FPU_ARCH_FPA
131218822Sdim# endif
132218822Sdim#endif /* ifndef FPU_DEFAULT */
13360484Sobrien
134218822Sdim#define streq(a, b)	      (strcmp (a, b) == 0)
13560484Sobrien
136218822Sdimstatic arm_feature_set cpu_variant;
137218822Sdimstatic arm_feature_set arm_arch_used;
138218822Sdimstatic arm_feature_set thumb_arch_used;
13960484Sobrien
14077298Sobrien/* Flags stored in private area of BFD structure.  */
141218822Sdimstatic int uses_apcs_26	     = FALSE;
142218822Sdimstatic int atpcs	     = FALSE;
143130561Sobrienstatic int support_interwork = FALSE;
144130561Sobrienstatic int uses_apcs_float   = FALSE;
145218822Sdimstatic int pic_code	     = FALSE;
14660484Sobrien
14789857Sobrien/* Variables that we set while parsing command-line options.  Once all
14889857Sobrien   options have been read we re-process these values to set the real
14989857Sobrien   assembly flags.  */
150218822Sdimstatic const arm_feature_set *legacy_cpu = NULL;
151218822Sdimstatic const arm_feature_set *legacy_fpu = NULL;
15289857Sobrien
153218822Sdimstatic const arm_feature_set *mcpu_cpu_opt = NULL;
154218822Sdimstatic const arm_feature_set *mcpu_fpu_opt = NULL;
155218822Sdimstatic const arm_feature_set *march_cpu_opt = NULL;
156218822Sdimstatic const arm_feature_set *march_fpu_opt = NULL;
157218822Sdimstatic const arm_feature_set *mfpu_opt = NULL;
158218822Sdimstatic const arm_feature_set *object_arch = NULL;
15989857Sobrien
160218822Sdim/* Constants for known architecture features.  */
161218822Sdimstatic const arm_feature_set fpu_default = FPU_DEFAULT;
162218822Sdimstatic const arm_feature_set fpu_arch_vfp_v1 = FPU_ARCH_VFP_V1;
163218822Sdimstatic const arm_feature_set fpu_arch_vfp_v2 = FPU_ARCH_VFP_V2;
164218822Sdimstatic const arm_feature_set fpu_arch_vfp_v3 = FPU_ARCH_VFP_V3;
165218822Sdimstatic const arm_feature_set fpu_arch_neon_v1 = FPU_ARCH_NEON_V1;
166218822Sdimstatic const arm_feature_set fpu_arch_fpa = FPU_ARCH_FPA;
167218822Sdimstatic const arm_feature_set fpu_any_hard = FPU_ANY_HARD;
168218822Sdimstatic const arm_feature_set fpu_arch_maverick = FPU_ARCH_MAVERICK;
169218822Sdimstatic const arm_feature_set fpu_endian_pure = FPU_ARCH_ENDIAN_PURE;
17060484Sobrien
171218822Sdim#ifdef CPU_DEFAULT
172218822Sdimstatic const arm_feature_set cpu_default = CPU_DEFAULT;
173218822Sdim#endif
17460484Sobrien
175218822Sdimstatic const arm_feature_set arm_ext_v1 = ARM_FEATURE (ARM_EXT_V1, 0);
176218822Sdimstatic const arm_feature_set arm_ext_v2 = ARM_FEATURE (ARM_EXT_V1, 0);
177218822Sdimstatic const arm_feature_set arm_ext_v2s = ARM_FEATURE (ARM_EXT_V2S, 0);
178218822Sdimstatic const arm_feature_set arm_ext_v3 = ARM_FEATURE (ARM_EXT_V3, 0);
179218822Sdimstatic const arm_feature_set arm_ext_v3m = ARM_FEATURE (ARM_EXT_V3M, 0);
180218822Sdimstatic const arm_feature_set arm_ext_v4 = ARM_FEATURE (ARM_EXT_V4, 0);
181218822Sdimstatic const arm_feature_set arm_ext_v4t = ARM_FEATURE (ARM_EXT_V4T, 0);
182218822Sdimstatic const arm_feature_set arm_ext_v5 = ARM_FEATURE (ARM_EXT_V5, 0);
183218822Sdimstatic const arm_feature_set arm_ext_v4t_5 =
184218822Sdim  ARM_FEATURE (ARM_EXT_V4T | ARM_EXT_V5, 0);
185218822Sdimstatic const arm_feature_set arm_ext_v5t = ARM_FEATURE (ARM_EXT_V5T, 0);
186218822Sdimstatic const arm_feature_set arm_ext_v5e = ARM_FEATURE (ARM_EXT_V5E, 0);
187218822Sdimstatic const arm_feature_set arm_ext_v5exp = ARM_FEATURE (ARM_EXT_V5ExP, 0);
188218822Sdimstatic const arm_feature_set arm_ext_v5j = ARM_FEATURE (ARM_EXT_V5J, 0);
189218822Sdimstatic const arm_feature_set arm_ext_v6 = ARM_FEATURE (ARM_EXT_V6, 0);
190218822Sdimstatic const arm_feature_set arm_ext_v6k = ARM_FEATURE (ARM_EXT_V6K, 0);
191218822Sdimstatic const arm_feature_set arm_ext_v6z = ARM_FEATURE (ARM_EXT_V6Z, 0);
192218822Sdimstatic const arm_feature_set arm_ext_v6t2 = ARM_FEATURE (ARM_EXT_V6T2, 0);
193218822Sdimstatic const arm_feature_set arm_ext_v6_notm = ARM_FEATURE (ARM_EXT_V6_NOTM, 0);
194218822Sdimstatic const arm_feature_set arm_ext_div = ARM_FEATURE (ARM_EXT_DIV, 0);
195218822Sdimstatic const arm_feature_set arm_ext_v7 = ARM_FEATURE (ARM_EXT_V7, 0);
196218822Sdimstatic const arm_feature_set arm_ext_v7a = ARM_FEATURE (ARM_EXT_V7A, 0);
197218822Sdimstatic const arm_feature_set arm_ext_v7r = ARM_FEATURE (ARM_EXT_V7R, 0);
198218822Sdimstatic const arm_feature_set arm_ext_v7m = ARM_FEATURE (ARM_EXT_V7M, 0);
19960484Sobrien
200218822Sdimstatic const arm_feature_set arm_arch_any = ARM_ANY;
201218822Sdimstatic const arm_feature_set arm_arch_full = ARM_FEATURE (-1, -1);
202218822Sdimstatic const arm_feature_set arm_arch_t2 = ARM_ARCH_THUMB2;
203218822Sdimstatic const arm_feature_set arm_arch_none = ARM_ARCH_NONE;
20460484Sobrien
205218822Sdimstatic const arm_feature_set arm_cext_iwmmxt2 =
206218822Sdim  ARM_FEATURE (0, ARM_CEXT_IWMMXT2);
207218822Sdimstatic const arm_feature_set arm_cext_iwmmxt =
208218822Sdim  ARM_FEATURE (0, ARM_CEXT_IWMMXT);
209218822Sdimstatic const arm_feature_set arm_cext_xscale =
210218822Sdim  ARM_FEATURE (0, ARM_CEXT_XSCALE);
211218822Sdimstatic const arm_feature_set arm_cext_maverick =
212218822Sdim  ARM_FEATURE (0, ARM_CEXT_MAVERICK);
213218822Sdimstatic const arm_feature_set fpu_fpa_ext_v1 = ARM_FEATURE (0, FPU_FPA_EXT_V1);
214218822Sdimstatic const arm_feature_set fpu_fpa_ext_v2 = ARM_FEATURE (0, FPU_FPA_EXT_V2);
215218822Sdimstatic const arm_feature_set fpu_vfp_ext_v1xd =
216218822Sdim  ARM_FEATURE (0, FPU_VFP_EXT_V1xD);
217218822Sdimstatic const arm_feature_set fpu_vfp_ext_v1 = ARM_FEATURE (0, FPU_VFP_EXT_V1);
218218822Sdimstatic const arm_feature_set fpu_vfp_ext_v2 = ARM_FEATURE (0, FPU_VFP_EXT_V2);
219218822Sdimstatic const arm_feature_set fpu_vfp_ext_v3 = ARM_FEATURE (0, FPU_VFP_EXT_V3);
220218822Sdimstatic const arm_feature_set fpu_neon_ext_v1 = ARM_FEATURE (0, FPU_NEON_EXT_V1);
221218822Sdimstatic const arm_feature_set fpu_vfp_v3_or_neon_ext =
222218822Sdim  ARM_FEATURE (0, FPU_NEON_EXT_V1 | FPU_VFP_EXT_V3);
22360484Sobrien
224218822Sdimstatic int mfloat_abi_opt = -1;
225218822Sdim/* Record user cpu selection for object attributes.  */
226218822Sdimstatic arm_feature_set selected_cpu = ARM_ARCH_NONE;
227218822Sdim/* Must be long enough to hold any of the names in arm_cpus.  */
228218822Sdimstatic char selected_cpu_name[16];
229218822Sdim#ifdef OBJ_ELF
230218822Sdim# ifdef EABI_DEFAULT
231218822Sdimstatic int meabi_flags = EABI_DEFAULT;
232218822Sdim# else
233218822Sdimstatic int meabi_flags = EF_ARM_EABI_UNKNOWN;
234218822Sdim# endif
23560484Sobrien
236218822Sdimbfd_boolean
237218822Sdimarm_is_eabi(void)
238218822Sdim{
239218822Sdim  return (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4);
240218822Sdim}
241218822Sdim#endif
24260484Sobrien
24360484Sobrien#ifdef OBJ_ELF
244218822Sdim/* Pre-defined "_GLOBAL_OFFSET_TABLE_"	*/
24577298SobriensymbolS * GOT_symbol;
24660484Sobrien#endif
24760484Sobrien
24877298Sobrien/* 0: assemble for ARM,
24977298Sobrien   1: assemble for Thumb,
25077298Sobrien   2: assemble for Thumb even though target CPU does not support thumb
25177298Sobrien      instructions.  */
25277298Sobrienstatic int thumb_mode = 0;
25377298Sobrien
254218822Sdim/* If unified_syntax is true, we are processing the new unified
255218822Sdim   ARM/Thumb syntax.  Important differences from the old ARM mode:
25660484Sobrien
257218822Sdim     - Immediate operands do not require a # prefix.
258218822Sdim     - Conditional affixes always appear at the end of the
259218822Sdim       instruction.  (For backward compatibility, those instructions
260218822Sdim       that formerly had them in the middle, continue to accept them
261218822Sdim       there.)
262218822Sdim     - The IT instruction may appear, and if it does is validated
263218822Sdim       against subsequent conditional affixes.  It does not generate
264218822Sdim       machine code.
26560484Sobrien
266218822Sdim   Important differences from the old Thumb mode:
26760484Sobrien
268218822Sdim     - Immediate operands do not require a # prefix.
269218822Sdim     - Most of the V6T2 instructions are only available in unified mode.
270218822Sdim     - The .N and .W suffixes are recognized and honored (it is an error
271218822Sdim       if they cannot be honored).
272218822Sdim     - All instructions set the flags if and only if they have an 's' affix.
273218822Sdim     - Conditional affixes may be used.  They are validated against
274218822Sdim       preceding IT instructions.  Unlike ARM mode, you cannot use a
275218822Sdim       conditional affix except in the scope of an IT instruction.  */
276218822Sdim
277218822Sdimstatic bfd_boolean unified_syntax = FALSE;
278218822Sdim
279218822Sdimenum neon_el_type
28060484Sobrien{
281218822Sdim  NT_invtype,
282218822Sdim  NT_untyped,
283218822Sdim  NT_integer,
284218822Sdim  NT_float,
285218822Sdim  NT_poly,
286218822Sdim  NT_signed,
287218822Sdim  NT_unsigned
28860484Sobrien};
28960484Sobrien
290218822Sdimstruct neon_type_el
29160484Sobrien{
292218822Sdim  enum neon_el_type type;
293218822Sdim  unsigned size;
29460484Sobrien};
29560484Sobrien
296218822Sdim#define NEON_MAX_TYPE_ELS 4
297218822Sdim
298218822Sdimstruct neon_type
29977298Sobrien{
300218822Sdim  struct neon_type_el el[NEON_MAX_TYPE_ELS];
301218822Sdim  unsigned elems;
30277298Sobrien};
30377298Sobrien
304218822Sdimstruct arm_it
30577298Sobrien{
306218822Sdim  const char *	error;
307218822Sdim  unsigned long instruction;
308218822Sdim  int		size;
309218822Sdim  int		size_req;
310218822Sdim  int		cond;
311218822Sdim  /* "uncond_value" is set to the value in place of the conditional field in
312218822Sdim     unconditional versions of the instruction, or -1 if nothing is
313218822Sdim     appropriate.  */
314218822Sdim  int		uncond_value;
315218822Sdim  struct neon_type vectype;
316218822Sdim  /* Set to the opcode if the instruction needs relaxation.
317218822Sdim     Zero if the instruction is not relaxed.  */
318218822Sdim  unsigned long	relax;
319218822Sdim  struct
320218822Sdim  {
321218822Sdim    bfd_reloc_code_real_type type;
322218822Sdim    expressionS		     exp;
323218822Sdim    int			     pc_rel;
324218822Sdim  } reloc;
32577298Sobrien
326218822Sdim  struct
327218822Sdim  {
328218822Sdim    unsigned reg;
329218822Sdim    signed int imm;
330218822Sdim    struct neon_type_el vectype;
331218822Sdim    unsigned present	: 1;  /* Operand present.  */
332218822Sdim    unsigned isreg	: 1;  /* Operand was a register.  */
333218822Sdim    unsigned immisreg	: 1;  /* .imm field is a second register.  */
334218822Sdim    unsigned isscalar   : 1;  /* Operand is a (Neon) scalar.  */
335218822Sdim    unsigned immisalign : 1;  /* Immediate is an alignment specifier.  */
336218822Sdim    unsigned immisfloat : 1;  /* Immediate was parsed as a float.  */
337218822Sdim    /* Note: we abuse "regisimm" to mean "is Neon register" in VMOV
338218822Sdim       instructions. This allows us to disambiguate ARM <-> vector insns.  */
339218822Sdim    unsigned regisimm   : 1;  /* 64-bit immediate, reg forms high 32 bits.  */
340218822Sdim    unsigned isvec      : 1;  /* Is a single, double or quad VFP/Neon reg.  */
341218822Sdim    unsigned isquad     : 1;  /* Operand is Neon quad-precision register.  */
342218822Sdim    unsigned issingle   : 1;  /* Operand is VFP single-precision register.  */
343218822Sdim    unsigned hasreloc	: 1;  /* Operand has relocation suffix.  */
344218822Sdim    unsigned writeback	: 1;  /* Operand has trailing !  */
345218822Sdim    unsigned preind	: 1;  /* Preindexed address.  */
346218822Sdim    unsigned postind	: 1;  /* Postindexed address.  */
347218822Sdim    unsigned negative	: 1;  /* Index register was negated.  */
348218822Sdim    unsigned shifted	: 1;  /* Shift applied to operation.  */
349218822Sdim    unsigned shift_kind : 3;  /* Shift operation (enum shift_kind).  */
350218822Sdim  } operands[6];
35177298Sobrien};
35277298Sobrien
353218822Sdimstatic struct arm_it inst;
35460484Sobrien
35560484Sobrien#define NUM_FLOAT_VALS 8
35660484Sobrien
35789857Sobrienconst char * fp_const[] =
35860484Sobrien{
35960484Sobrien  "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0", 0
36060484Sobrien};
36160484Sobrien
362218822Sdim/* Number of littlenums required to hold an extended precision number.	*/
36360484Sobrien#define MAX_LITTLENUMS 6
36460484Sobrien
36560484SobrienLITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS];
36660484Sobrien
36760484Sobrien#define FAIL	(-1)
36860484Sobrien#define SUCCESS (0)
36960484Sobrien
37060484Sobrien#define SUFF_S 1
37160484Sobrien#define SUFF_D 2
37260484Sobrien#define SUFF_E 3
37360484Sobrien#define SUFF_P 4
37460484Sobrien
375218822Sdim#define CP_T_X	 0x00008000
376218822Sdim#define CP_T_Y	 0x00400000
37760484Sobrien
378218822Sdim#define CONDS_BIT	 0x00100000
379218822Sdim#define LOAD_BIT	 0x00100000
38060484Sobrien
38177298Sobrien#define DOUBLE_LOAD_FLAG 0x00000001
38277298Sobrien
38360484Sobrienstruct asm_cond
38460484Sobrien{
385218822Sdim  const char *	template;
38660484Sobrien  unsigned long value;
38760484Sobrien};
38860484Sobrien
389218822Sdim#define COND_ALWAYS 0xE
39060484Sobrien
391218822Sdimstruct asm_psr
39260484Sobrien{
393218822Sdim  const char *template;
394218822Sdim  unsigned long field;
39560484Sobrien};
39660484Sobrien
397218822Sdimstruct asm_barrier_opt
39860484Sobrien{
399130561Sobrien  const char *template;
400218822Sdim  unsigned long value;
40160484Sobrien};
40260484Sobrien
403130561Sobrien/* The bit that distinguishes CPSR and SPSR.  */
40477298Sobrien#define SPSR_BIT   (1 << 22)
40560484Sobrien
406218822Sdim/* The individual PSR flag bits.  */
407218822Sdim#define PSR_c	(1 << 16)
408218822Sdim#define PSR_x	(1 << 17)
409218822Sdim#define PSR_s	(1 << 18)
410218822Sdim#define PSR_f	(1 << 19)
41177298Sobrien
412218822Sdimstruct reloc_entry
41360484Sobrien{
414218822Sdim  char *name;
415218822Sdim  bfd_reloc_code_real_type reloc;
41660484Sobrien};
41760484Sobrien
418218822Sdimenum vfp_reg_pos
419130561Sobrien{
420218822Sdim  VFP_REG_Sd, VFP_REG_Sm, VFP_REG_Sn,
42189857Sobrien  VFP_REG_Dd, VFP_REG_Dm, VFP_REG_Dn
42289857Sobrien};
42389857Sobrien
42489857Sobrienenum vfp_ldstm_type
42589857Sobrien{
42689857Sobrien  VFP_LDSTMIA, VFP_LDSTMDB, VFP_LDSTMIAX, VFP_LDSTMDBX
42789857Sobrien};
42889857Sobrien
429218822Sdim/* Bits for DEFINED field in neon_typed_alias.  */
430218822Sdim#define NTA_HASTYPE  1
431218822Sdim#define NTA_HASINDEX 2
432218822Sdim
433218822Sdimstruct neon_typed_alias
43489857Sobrien{
435218822Sdim  unsigned char defined;
436218822Sdim  unsigned char index;
437218822Sdim  struct neon_type_el eltype;
43889857Sobrien};
43989857Sobrien
440218822Sdim/* ARM register categories.  This includes coprocessor numbers and various
441218822Sdim   architecture extensions' registers.	*/
442218822Sdimenum arm_reg_type
44389857Sobrien{
444218822Sdim  REG_TYPE_RN,
445218822Sdim  REG_TYPE_CP,
446218822Sdim  REG_TYPE_CN,
447218822Sdim  REG_TYPE_FN,
448218822Sdim  REG_TYPE_VFS,
449218822Sdim  REG_TYPE_VFD,
450218822Sdim  REG_TYPE_NQ,
451218822Sdim  REG_TYPE_VFSD,
452218822Sdim  REG_TYPE_NDQ,
453218822Sdim  REG_TYPE_NSDQ,
454218822Sdim  REG_TYPE_VFC,
455218822Sdim  REG_TYPE_MVF,
456218822Sdim  REG_TYPE_MVD,
457218822Sdim  REG_TYPE_MVFX,
458218822Sdim  REG_TYPE_MVDX,
459218822Sdim  REG_TYPE_MVAX,
460218822Sdim  REG_TYPE_DSPSC,
461218822Sdim  REG_TYPE_MMXWR,
462218822Sdim  REG_TYPE_MMXWC,
463218822Sdim  REG_TYPE_MMXWCG,
464218822Sdim  REG_TYPE_XSCALE,
46589857Sobrien};
46689857Sobrien
467218822Sdim/* Structure for a hash table entry for a register.
468218822Sdim   If TYPE is REG_TYPE_VFD or REG_TYPE_NQ, the NEON field can point to extra
469218822Sdim   information which states whether a vector type or index is specified (for a
470218822Sdim   register alias created with .dn or .qn). Otherwise NEON should be NULL.  */
47189857Sobrienstruct reg_entry
47289857Sobrien{
473218822Sdim  const char        *name;
474218822Sdim  unsigned char      number;
475218822Sdim  unsigned char      type;
476218822Sdim  unsigned char      builtin;
477218822Sdim  struct neon_typed_alias *neon;
47889857Sobrien};
47989857Sobrien
480218822Sdim/* Diagnostics used when we don't get a register of the expected type.	*/
481218822Sdimconst char *const reg_expected_msgs[] =
482218822Sdim{
483218822Sdim  N_("ARM register expected"),
484218822Sdim  N_("bad or missing co-processor number"),
485218822Sdim  N_("co-processor register expected"),
486218822Sdim  N_("FPA register expected"),
487218822Sdim  N_("VFP single precision register expected"),
488218822Sdim  N_("VFP/Neon double precision register expected"),
489218822Sdim  N_("Neon quad precision register expected"),
490218822Sdim  N_("VFP single or double precision register expected"),
491218822Sdim  N_("Neon double or quad precision register expected"),
492218822Sdim  N_("VFP single, double or Neon quad precision register expected"),
493218822Sdim  N_("VFP system register expected"),
494218822Sdim  N_("Maverick MVF register expected"),
495218822Sdim  N_("Maverick MVD register expected"),
496218822Sdim  N_("Maverick MVFX register expected"),
497218822Sdim  N_("Maverick MVDX register expected"),
498218822Sdim  N_("Maverick MVAX register expected"),
499218822Sdim  N_("Maverick DSPSC register expected"),
500218822Sdim  N_("iWMMXt data register expected"),
501218822Sdim  N_("iWMMXt control register expected"),
502218822Sdim  N_("iWMMXt scalar register expected"),
503218822Sdim  N_("XScale accumulator register expected"),
504218822Sdim};
505218822Sdim
50689857Sobrien/* Some well known registers that we refer to directly elsewhere.  */
507218822Sdim#define REG_SP	13
508218822Sdim#define REG_LR	14
50989857Sobrien#define REG_PC	15
51089857Sobrien
511218822Sdim/* ARM instructions take 4bytes in the object file, Thumb instructions
512218822Sdim   take 2:  */
513218822Sdim#define INSN_SIZE	4
514130561Sobrien
515218822Sdimstruct asm_opcode
51689857Sobrien{
517218822Sdim  /* Basic string to match.  */
518218822Sdim  const char *template;
51989857Sobrien
520218822Sdim  /* Parameters to instruction.	 */
521218822Sdim  unsigned char operands[8];
522130561Sobrien
523218822Sdim  /* Conditional tag - see opcode_lookup.  */
524218822Sdim  unsigned int tag : 4;
525130561Sobrien
526218822Sdim  /* Basic instruction code.  */
527218822Sdim  unsigned int avalue : 28;
528130561Sobrien
529218822Sdim  /* Thumb-format instruction code.  */
530218822Sdim  unsigned int tvalue;
53189857Sobrien
532218822Sdim  /* Which architecture variant provides this instruction.  */
533218822Sdim  const arm_feature_set *avariant;
534218822Sdim  const arm_feature_set *tvariant;
53589857Sobrien
536218822Sdim  /* Function to call to encode instruction in ARM format.  */
537218822Sdim  void (* aencode) (void);
53889857Sobrien
539218822Sdim  /* Function to call to encode instruction in Thumb format.  */
540218822Sdim  void (* tencode) (void);
54189857Sobrien};
54289857Sobrien
543218822Sdim/* Defines for various bits that we will want to toggle.  */
544218822Sdim#define INST_IMMEDIATE	0x02000000
545218822Sdim#define OFFSET_REG	0x02000000
546218822Sdim#define HWOFFSET_IMM	0x00400000
547218822Sdim#define SHIFT_BY_REG	0x00000010
548218822Sdim#define PRE_INDEX	0x01000000
549218822Sdim#define INDEX_UP	0x00800000
550218822Sdim#define WRITE_BACK	0x00200000
551218822Sdim#define LDM_TYPE_2_OR_3	0x00400000
552218822Sdim#define CPSI_MMOD	0x00020000
55389857Sobrien
554218822Sdim#define LITERAL_MASK	0xf000f000
555218822Sdim#define OPCODE_MASK	0xfe1fffff
556218822Sdim#define V4_STR_BIT	0x00000020
55789857Sobrien
558218822Sdim#define T2_SUBS_PC_LR	0xf3de8f00
55989857Sobrien
560218822Sdim#define DATA_OP_SHIFT	21
56189857Sobrien
562218822Sdim#define T2_OPCODE_MASK	0xfe1fffff
563218822Sdim#define T2_DATA_OP_SHIFT 21
56489857Sobrien
565218822Sdim/* Codes to distinguish the arithmetic instructions.  */
566218822Sdim#define OPCODE_AND	0
567218822Sdim#define OPCODE_EOR	1
568218822Sdim#define OPCODE_SUB	2
569218822Sdim#define OPCODE_RSB	3
570218822Sdim#define OPCODE_ADD	4
571218822Sdim#define OPCODE_ADC	5
572218822Sdim#define OPCODE_SBC	6
573218822Sdim#define OPCODE_RSC	7
574218822Sdim#define OPCODE_TST	8
575218822Sdim#define OPCODE_TEQ	9
576218822Sdim#define OPCODE_CMP	10
577218822Sdim#define OPCODE_CMN	11
578218822Sdim#define OPCODE_ORR	12
579218822Sdim#define OPCODE_MOV	13
580218822Sdim#define OPCODE_BIC	14
581218822Sdim#define OPCODE_MVN	15
58289857Sobrien
583218822Sdim#define T2_OPCODE_AND	0
584218822Sdim#define T2_OPCODE_BIC	1
585218822Sdim#define T2_OPCODE_ORR	2
586218822Sdim#define T2_OPCODE_ORN	3
587218822Sdim#define T2_OPCODE_EOR	4
588218822Sdim#define T2_OPCODE_ADD	8
589218822Sdim#define T2_OPCODE_ADC	10
590218822Sdim#define T2_OPCODE_SBC	11
591218822Sdim#define T2_OPCODE_SUB	13
592218822Sdim#define T2_OPCODE_RSB	14
59389857Sobrien
594218822Sdim#define T_OPCODE_MUL 0x4340
595218822Sdim#define T_OPCODE_TST 0x4200
596218822Sdim#define T_OPCODE_CMN 0x42c0
597218822Sdim#define T_OPCODE_NEG 0x4240
598218822Sdim#define T_OPCODE_MVN 0x43c0
59989857Sobrien
600218822Sdim#define T_OPCODE_ADD_R3	0x1800
601218822Sdim#define T_OPCODE_SUB_R3 0x1a00
602218822Sdim#define T_OPCODE_ADD_HI 0x4400
603218822Sdim#define T_OPCODE_ADD_ST 0xb000
604218822Sdim#define T_OPCODE_SUB_ST 0xb080
605218822Sdim#define T_OPCODE_ADD_SP 0xa800
606218822Sdim#define T_OPCODE_ADD_PC 0xa000
607218822Sdim#define T_OPCODE_ADD_I8 0x3000
608218822Sdim#define T_OPCODE_SUB_I8 0x3800
609218822Sdim#define T_OPCODE_ADD_I3 0x1c00
610218822Sdim#define T_OPCODE_SUB_I3 0x1e00
61189857Sobrien
612218822Sdim#define T_OPCODE_ASR_R	0x4100
613218822Sdim#define T_OPCODE_LSL_R	0x4080
614218822Sdim#define T_OPCODE_LSR_R	0x40c0
615218822Sdim#define T_OPCODE_ROR_R	0x41c0
616218822Sdim#define T_OPCODE_ASR_I	0x1000
617218822Sdim#define T_OPCODE_LSL_I	0x0000
618218822Sdim#define T_OPCODE_LSR_I	0x0800
61989857Sobrien
620218822Sdim#define T_OPCODE_MOV_I8	0x2000
621218822Sdim#define T_OPCODE_CMP_I8 0x2800
622218822Sdim#define T_OPCODE_CMP_LR 0x4280
623218822Sdim#define T_OPCODE_MOV_HR 0x4600
624218822Sdim#define T_OPCODE_CMP_HR 0x4500
62589857Sobrien
626218822Sdim#define T_OPCODE_LDR_PC 0x4800
627218822Sdim#define T_OPCODE_LDR_SP 0x9800
628218822Sdim#define T_OPCODE_STR_SP 0x9000
629218822Sdim#define T_OPCODE_LDR_IW 0x6800
630218822Sdim#define T_OPCODE_STR_IW 0x6000
631218822Sdim#define T_OPCODE_LDR_IH 0x8800
632218822Sdim#define T_OPCODE_STR_IH 0x8000
633218822Sdim#define T_OPCODE_LDR_IB 0x7800
634218822Sdim#define T_OPCODE_STR_IB 0x7000
635218822Sdim#define T_OPCODE_LDR_RW 0x5800
636218822Sdim#define T_OPCODE_STR_RW 0x5000
637218822Sdim#define T_OPCODE_LDR_RH 0x5a00
638218822Sdim#define T_OPCODE_STR_RH 0x5200
639218822Sdim#define T_OPCODE_LDR_RB 0x5c00
640218822Sdim#define T_OPCODE_STR_RB 0x5400
64189857Sobrien
642218822Sdim#define T_OPCODE_PUSH	0xb400
643218822Sdim#define T_OPCODE_POP	0xbc00
64460484Sobrien
645218822Sdim#define T_OPCODE_BRANCH 0xe000
64677298Sobrien
647218822Sdim#define THUMB_SIZE	2	/* Size of thumb instruction.  */
648218822Sdim#define THUMB_PP_PC_LR 0x0100
649218822Sdim#define THUMB_LOAD_BIT 0x0800
650218822Sdim#define THUMB2_LOAD_BIT 0x00100000
65177298Sobrien
652218822Sdim#define BAD_ARGS	_("bad arguments to instruction")
653218822Sdim#define BAD_PC		_("r15 not allowed here")
654248460Sandrew#define BAD_SP		_("r13 not allowed here")
655218822Sdim#define BAD_COND	_("instruction cannot be conditional")
656218822Sdim#define BAD_OVERLAP	_("registers may not be the same")
657218822Sdim#define BAD_HIREG	_("lo register required")
658218822Sdim#define BAD_THUMB32	_("instruction not supported in Thumb16 mode")
659218822Sdim#define BAD_ADDR_MODE   _("instruction does not accept this addressing mode");
660218822Sdim#define BAD_BRANCH	_("branch must be last instruction in IT block")
661218822Sdim#define BAD_NOT_IT	_("instruction not allowed in IT block")
662218822Sdim#define BAD_FPU		_("selected FPU does not support instruction")
663248460Sandrew#define BAD_VMRS	_("APSR_nzcv may only be used with fpscr")
66477298Sobrien
665218822Sdimstatic struct hash_control *arm_ops_hsh;
666218822Sdimstatic struct hash_control *arm_cond_hsh;
667218822Sdimstatic struct hash_control *arm_shift_hsh;
668218822Sdimstatic struct hash_control *arm_psr_hsh;
669218822Sdimstatic struct hash_control *arm_v7m_psr_hsh;
670218822Sdimstatic struct hash_control *arm_reg_hsh;
671218822Sdimstatic struct hash_control *arm_reloc_hsh;
672218822Sdimstatic struct hash_control *arm_barrier_opt_hsh;
67377298Sobrien
674218822Sdim/* Stuff needed to resolve the label ambiguity
675218822Sdim   As:
676218822Sdim     ...
677218822Sdim     label:   <insn>
678218822Sdim   may differ from:
679218822Sdim     ...
680218822Sdim     label:
681218822Sdim	      <insn>
682218822Sdim*/
68389857Sobrien
684218822SdimsymbolS *  last_label_seen;
685218822Sdimstatic int label_is_thumb_function_name = FALSE;
686218822Sdim
687218822Sdim/* Literal pool structure.  Held on a per-section
688218822Sdim   and per-sub-section basis.  */
68989857Sobrien
690218822Sdim#define MAX_LITERAL_POOL_SIZE 1024
691218822Sdimtypedef struct literal_pool
692218822Sdim{
693218822Sdim  expressionS	 literals [MAX_LITERAL_POOL_SIZE];
694218822Sdim  unsigned int	 next_free_entry;
695218822Sdim  unsigned int	 id;
696218822Sdim  symbolS *	 symbol;
697218822Sdim  segT		 section;
698218822Sdim  subsegT	 sub_section;
699218822Sdim  struct literal_pool * next;
700218822Sdim} literal_pool;
70189857Sobrien
702218822Sdim/* Pointer to a linked list of literal pools.  */
703218822Sdimliteral_pool * list_of_pools = NULL;
70489857Sobrien
705218822Sdim/* State variables for IT block handling.  */
706218822Sdimstatic bfd_boolean current_it_mask = 0;
707218822Sdimstatic int current_cc;
70889857Sobrien
709218822Sdim
710218822Sdim/* Pure syntax.	 */
71189857Sobrien
712218822Sdim/* This array holds the chars that always start a comment.  If the
713218822Sdim   pre-processor is disabled, these aren't very useful.	 */
714218822Sdimconst char comment_chars[] = "@";
715130561Sobrien
716218822Sdim/* This array holds the chars that only start a comment at the beginning of
717218822Sdim   a line.  If the line seems to have the form '# 123 filename'
718218822Sdim   .line and .file directives will appear in the pre-processed output.	*/
719218822Sdim/* Note that input_file.c hand checks for '#' at the beginning of the
720218822Sdim   first line of the input file.  This is because the compiler outputs
721218822Sdim   #NO_APP at the beginning of its output.  */
722218822Sdim/* Also note that comments like this one will always work.  */
723218822Sdimconst char line_comment_chars[] = "#";
724130561Sobrien
725218822Sdimconst char line_separator_chars[] = ";";
72660484Sobrien
727218822Sdim/* Chars that can be used to separate mant
728218822Sdim   from exp in floating point numbers.	*/
729218822Sdimconst char EXP_CHARS[] = "eE";
73089857Sobrien
731218822Sdim/* Chars that mean this number is a floating point constant.  */
732218822Sdim/* As in 0f12.456  */
733218822Sdim/* or	 0d1.2345e12  */
73489857Sobrien
735218822Sdimconst char FLT_CHARS[] = "rRsSfFdDxXeEpP";
73689857Sobrien
737218822Sdim/* Prefix characters that indicate the start of an immediate
738218822Sdim   value.  */
739218822Sdim#define is_immediate_prefix(C) ((C) == '#' || (C) == '$')
74089857Sobrien
741218822Sdim/* Separator character handling.  */
74289857Sobrien
743218822Sdim#define skip_whitespace(str)  do { if (*(str) == ' ') ++(str); } while (0)
74460484Sobrien
745218822Sdimstatic inline int
746218822Sdimskip_past_char (char ** str, char c)
747218822Sdim{
748218822Sdim  if (**str == c)
749218822Sdim    {
750218822Sdim      (*str)++;
751218822Sdim      return SUCCESS;
752218822Sdim    }
753218822Sdim  else
754218822Sdim    return FAIL;
755218822Sdim}
756218822Sdim#define skip_past_comma(str) skip_past_char (str, ',')
757130561Sobrien
758218822Sdim/* Arithmetic expressions (possibly involving symbols).	 */
75960484Sobrien
760218822Sdim/* Return TRUE if anything in the expression is a bignum.  */
76160484Sobrien
762218822Sdimstatic int
763218822Sdimwalk_no_bignums (symbolS * sp)
764218822Sdim{
765218822Sdim  if (symbol_get_value_expression (sp)->X_op == O_big)
766218822Sdim    return 1;
76789857Sobrien
768218822Sdim  if (symbol_get_value_expression (sp)->X_add_symbol)
769218822Sdim    {
770218822Sdim      return (walk_no_bignums (symbol_get_value_expression (sp)->X_add_symbol)
771218822Sdim	      || (symbol_get_value_expression (sp)->X_op_symbol
772218822Sdim		  && walk_no_bignums (symbol_get_value_expression (sp)->X_op_symbol)));
773218822Sdim    }
77489857Sobrien
775218822Sdim  return 0;
776218822Sdim}
77789857Sobrien
778218822Sdimstatic int in_my_get_expression = 0;
77989857Sobrien
780218822Sdim/* Third argument to my_get_expression.	 */
781218822Sdim#define GE_NO_PREFIX 0
782218822Sdim#define GE_IMM_PREFIX 1
783218822Sdim#define GE_OPT_PREFIX 2
784218822Sdim/* This is a bit of a hack. Use an optional prefix, and also allow big (64-bit)
785218822Sdim   immediates, as can be used in Neon VMVN and VMOV immediate instructions.  */
786218822Sdim#define GE_OPT_PREFIX_BIG 3
78789857Sobrien
788218822Sdimstatic int
789218822Sdimmy_get_expression (expressionS * ep, char ** str, int prefix_mode)
79077298Sobrien{
791218822Sdim  char * save_in;
792218822Sdim  segT	 seg;
79360484Sobrien
794218822Sdim  /* In unified syntax, all prefixes are optional.  */
795218822Sdim  if (unified_syntax)
796218822Sdim    prefix_mode = (prefix_mode == GE_OPT_PREFIX_BIG) ? prefix_mode
797218822Sdim                  : GE_OPT_PREFIX;
79860484Sobrien
799218822Sdim  switch (prefix_mode)
800218822Sdim    {
801218822Sdim    case GE_NO_PREFIX: break;
802218822Sdim    case GE_IMM_PREFIX:
803218822Sdim      if (!is_immediate_prefix (**str))
804218822Sdim	{
805218822Sdim	  inst.error = _("immediate expression requires a # prefix");
806218822Sdim	  return FAIL;
807218822Sdim	}
808218822Sdim      (*str)++;
809218822Sdim      break;
810218822Sdim    case GE_OPT_PREFIX:
811218822Sdim    case GE_OPT_PREFIX_BIG:
812218822Sdim      if (is_immediate_prefix (**str))
813218822Sdim	(*str)++;
814218822Sdim      break;
815218822Sdim    default: abort ();
816218822Sdim    }
81760484Sobrien
818218822Sdim  memset (ep, 0, sizeof (expressionS));
81960484Sobrien
820218822Sdim  save_in = input_line_pointer;
821218822Sdim  input_line_pointer = *str;
822218822Sdim  in_my_get_expression = 1;
823218822Sdim  seg = expression (ep);
824218822Sdim  in_my_get_expression = 0;
82560484Sobrien
826218822Sdim  if (ep->X_op == O_illegal)
827218822Sdim    {
828218822Sdim      /* We found a bad expression in md_operand().  */
829218822Sdim      *str = input_line_pointer;
830218822Sdim      input_line_pointer = save_in;
831218822Sdim      if (inst.error == NULL)
832218822Sdim	inst.error = _("bad expression");
833218822Sdim      return 1;
834218822Sdim    }
835218822Sdim
836218822Sdim#ifdef OBJ_AOUT
837218822Sdim  if (seg != absolute_section
838218822Sdim      && seg != text_section
839218822Sdim      && seg != data_section
840218822Sdim      && seg != bss_section
841218822Sdim      && seg != undefined_section)
842218822Sdim    {
843218822Sdim      inst.error = _("bad segment");
844218822Sdim      *str = input_line_pointer;
845218822Sdim      input_line_pointer = save_in;
846218822Sdim      return 1;
847218822Sdim    }
848218822Sdim#endif
849218822Sdim
850218822Sdim  /* Get rid of any bignums now, so that we don't generate an error for which
851218822Sdim     we can't establish a line number later on.	 Big numbers are never valid
852218822Sdim     in instructions, which is where this routine is always called.  */
853218822Sdim  if (prefix_mode != GE_OPT_PREFIX_BIG
854218822Sdim      && (ep->X_op == O_big
855218822Sdim          || (ep->X_add_symbol
856218822Sdim	      && (walk_no_bignums (ep->X_add_symbol)
857218822Sdim	          || (ep->X_op_symbol
858218822Sdim		      && walk_no_bignums (ep->X_op_symbol))))))
859218822Sdim    {
860218822Sdim      inst.error = _("invalid constant");
861218822Sdim      *str = input_line_pointer;
862218822Sdim      input_line_pointer = save_in;
863218822Sdim      return 1;
864218822Sdim    }
865218822Sdim
866218822Sdim  *str = input_line_pointer;
867218822Sdim  input_line_pointer = save_in;
868218822Sdim  return 0;
869218822Sdim}
870218822Sdim
871218822Sdim/* Turn a string in input_line_pointer into a floating point constant
872218822Sdim   of type TYPE, and store the appropriate bytes in *LITP.  The number
873218822Sdim   of LITTLENUMS emitted is stored in *SIZEP.  An error message is
874218822Sdim   returned, or NULL on OK.
875218822Sdim
876218822Sdim   Note that fp constants aren't represent in the normal way on the ARM.
877218822Sdim   In big endian mode, things are as expected.	However, in little endian
878218822Sdim   mode fp constants are big-endian word-wise, and little-endian byte-wise
879218822Sdim   within the words.  For example, (double) 1.1 in big endian mode is
880218822Sdim   the byte sequence 3f f1 99 99 99 99 99 9a, and in little endian mode is
881218822Sdim   the byte sequence 99 99 f1 3f 9a 99 99 99.
882218822Sdim
883218822Sdim   ??? The format of 12 byte floats is uncertain according to gcc's arm.h.  */
884218822Sdim
885218822Sdimchar *
886218822Sdimmd_atof (int type, char * litP, int * sizeP)
88760484Sobrien{
888218822Sdim  int prec;
889218822Sdim  LITTLENUM_TYPE words[MAX_LITTLENUMS];
890218822Sdim  char *t;
891218822Sdim  int i;
89277298Sobrien
893218822Sdim  switch (type)
894218822Sdim    {
895218822Sdim    case 'f':
896218822Sdim    case 'F':
897218822Sdim    case 's':
898218822Sdim    case 'S':
899218822Sdim      prec = 2;
900218822Sdim      break;
90189857Sobrien
902218822Sdim    case 'd':
903218822Sdim    case 'D':
904218822Sdim    case 'r':
905218822Sdim    case 'R':
906218822Sdim      prec = 4;
907218822Sdim      break;
90889857Sobrien
909218822Sdim    case 'x':
910218822Sdim    case 'X':
911218822Sdim      prec = 6;
912218822Sdim      break;
91389857Sobrien
914218822Sdim    case 'p':
915218822Sdim    case 'P':
916218822Sdim      prec = 6;
917218822Sdim      break;
91889857Sobrien
919218822Sdim    default:
920218822Sdim      *sizeP = 0;
921218822Sdim      return _("bad call to MD_ATOF()");
922218822Sdim    }
92389857Sobrien
924218822Sdim  t = atof_ieee (input_line_pointer, type, words);
925218822Sdim  if (t)
926218822Sdim    input_line_pointer = t;
927218822Sdim  *sizeP = prec * 2;
92877298Sobrien
929218822Sdim  if (target_big_endian)
930218822Sdim    {
931218822Sdim      for (i = 0; i < prec; i++)
932218822Sdim	{
933218822Sdim	  md_number_to_chars (litP, (valueT) words[i], 2);
934218822Sdim	  litP += 2;
935218822Sdim	}
936218822Sdim    }
937218822Sdim  else
938218822Sdim    {
939218822Sdim      if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_endian_pure))
940218822Sdim	for (i = prec - 1; i >= 0; i--)
941218822Sdim	  {
942218822Sdim	    md_number_to_chars (litP, (valueT) words[i], 2);
943218822Sdim	    litP += 2;
944218822Sdim	  }
945218822Sdim      else
946218822Sdim	/* For a 4 byte float the order of elements in `words' is 1 0.
947218822Sdim	   For an 8 byte float the order is 1 0 3 2.  */
948218822Sdim	for (i = 0; i < prec; i += 2)
949218822Sdim	  {
950218822Sdim	    md_number_to_chars (litP, (valueT) words[i + 1], 2);
951218822Sdim	    md_number_to_chars (litP + 2, (valueT) words[i], 2);
952218822Sdim	    litP += 4;
953218822Sdim	  }
954218822Sdim    }
95560484Sobrien
956218822Sdim  return 0;
957218822Sdim}
95860484Sobrien
959218822Sdim/* We handle all bad expressions here, so that we can report the faulty
960218822Sdim   instruction in the error message.  */
961218822Sdimvoid
962218822Sdimmd_operand (expressionS * expr)
963218822Sdim{
964218822Sdim  if (in_my_get_expression)
965218822Sdim    expr->X_op = O_illegal;
966218822Sdim}
96760484Sobrien
968218822Sdim/* Immediate values.  */
96960484Sobrien
970218822Sdim/* Generic immediate-value read function for use in directives.
971218822Sdim   Accepts anything that 'expression' can fold to a constant.
972218822Sdim   *val receives the number.  */
973218822Sdim#ifdef OBJ_ELF
974218822Sdimstatic int
975218822Sdimimmediate_for_directive (int *val)
976218822Sdim{
977218822Sdim  expressionS exp;
978218822Sdim  exp.X_op = O_illegal;
97960484Sobrien
980218822Sdim  if (is_immediate_prefix (*input_line_pointer))
981218822Sdim    {
982218822Sdim      input_line_pointer++;
983218822Sdim      expression (&exp);
984218822Sdim    }
98560484Sobrien
986218822Sdim  if (exp.X_op != O_constant)
987218822Sdim    {
988218822Sdim      as_bad (_("expected #constant"));
989218822Sdim      ignore_rest_of_line ();
990218822Sdim      return FAIL;
991218822Sdim    }
992218822Sdim  *val = exp.X_add_number;
993218822Sdim  return SUCCESS;
994218822Sdim}
995218822Sdim#endif
99660484Sobrien
997218822Sdim/* Register parsing.  */
99877298Sobrien
999218822Sdim/* Generic register parser.  CCP points to what should be the
1000218822Sdim   beginning of a register name.  If it is indeed a valid register
1001218822Sdim   name, advance CCP over it and return the reg_entry structure;
1002218822Sdim   otherwise return NULL.  Does not issue diagnostics.	*/
100377298Sobrien
1004218822Sdimstatic struct reg_entry *
1005218822Sdimarm_reg_parse_multi (char **ccp)
1006218822Sdim{
1007218822Sdim  char *start = *ccp;
1008218822Sdim  char *p;
1009218822Sdim  struct reg_entry *reg;
101077298Sobrien
1011218822Sdim#ifdef REGISTER_PREFIX
1012218822Sdim  if (*start != REGISTER_PREFIX)
1013218822Sdim    return NULL;
1014218822Sdim  start++;
1015218822Sdim#endif
1016218822Sdim#ifdef OPTIONAL_REGISTER_PREFIX
1017218822Sdim  if (*start == OPTIONAL_REGISTER_PREFIX)
1018218822Sdim    start++;
1019218822Sdim#endif
102077298Sobrien
1021218822Sdim  p = start;
1022218822Sdim  if (!ISALPHA (*p) || !is_name_beginner (*p))
1023218822Sdim    return NULL;
102477298Sobrien
1025218822Sdim  do
1026218822Sdim    p++;
1027218822Sdim  while (ISALPHA (*p) || ISDIGIT (*p) || *p == '_');
102877298Sobrien
1029218822Sdim  reg = (struct reg_entry *) hash_find_n (arm_reg_hsh, start, p - start);
103077298Sobrien
1031218822Sdim  if (!reg)
1032218822Sdim    return NULL;
103377298Sobrien
1034218822Sdim  *ccp = p;
1035218822Sdim  return reg;
1036218822Sdim}
103789857Sobrien
1038218822Sdimstatic int
1039218822Sdimarm_reg_alt_syntax (char **ccp, char *start, struct reg_entry *reg,
1040218822Sdim                    enum arm_reg_type type)
1041218822Sdim{
1042218822Sdim  /* Alternative syntaxes are accepted for a few register classes.  */
1043218822Sdim  switch (type)
1044218822Sdim    {
1045218822Sdim    case REG_TYPE_MVF:
1046218822Sdim    case REG_TYPE_MVD:
1047218822Sdim    case REG_TYPE_MVFX:
1048218822Sdim    case REG_TYPE_MVDX:
1049218822Sdim      /* Generic coprocessor register names are allowed for these.  */
1050218822Sdim      if (reg && reg->type == REG_TYPE_CN)
1051218822Sdim	return reg->number;
1052218822Sdim      break;
105389857Sobrien
1054218822Sdim    case REG_TYPE_CP:
1055218822Sdim      /* For backward compatibility, a bare number is valid here.  */
1056218822Sdim      {
1057218822Sdim	unsigned long processor = strtoul (start, ccp, 10);
1058218822Sdim	if (*ccp != start && processor <= 15)
1059218822Sdim	  return processor;
1060218822Sdim      }
106189857Sobrien
1062218822Sdim    case REG_TYPE_MMXWC:
1063218822Sdim      /* WC includes WCG.  ??? I'm not sure this is true for all
1064218822Sdim	 instructions that take WC registers.  */
1065218822Sdim      if (reg && reg->type == REG_TYPE_MMXWCG)
1066218822Sdim	return reg->number;
1067218822Sdim      break;
1068130561Sobrien
1069218822Sdim    default:
1070218822Sdim      break;
1071218822Sdim    }
107289857Sobrien
1073218822Sdim  return FAIL;
1074218822Sdim}
107589857Sobrien
1076218822Sdim/* As arm_reg_parse_multi, but the register must be of type TYPE, and the
1077218822Sdim   return value is the register number or FAIL.  */
107889857Sobrien
1079218822Sdimstatic int
1080218822Sdimarm_reg_parse (char **ccp, enum arm_reg_type type)
1081218822Sdim{
1082218822Sdim  char *start = *ccp;
1083218822Sdim  struct reg_entry *reg = arm_reg_parse_multi (ccp);
1084218822Sdim  int ret;
108589857Sobrien
1086218822Sdim  /* Do not allow a scalar (reg+index) to parse as a register.  */
1087218822Sdim  if (reg && reg->neon && (reg->neon->defined & NTA_HASINDEX))
1088218822Sdim    return FAIL;
108989857Sobrien
1090218822Sdim  if (reg && reg->type == type)
1091218822Sdim    return reg->number;
109289857Sobrien
1093218822Sdim  if ((ret = arm_reg_alt_syntax (ccp, start, reg, type)) != FAIL)
1094218822Sdim    return ret;
109589857Sobrien
1096218822Sdim  *ccp = start;
1097218822Sdim  return FAIL;
1098218822Sdim}
109989857Sobrien
1100218822Sdim/* Parse a Neon type specifier. *STR should point at the leading '.'
1101218822Sdim   character. Does no verification at this stage that the type fits the opcode
1102218822Sdim   properly. E.g.,
110389857Sobrien
1104218822Sdim     .i32.i32.s16
1105218822Sdim     .s32.f32
1106218822Sdim     .u16
110789857Sobrien
1108218822Sdim   Can all be legally parsed by this function.
110989857Sobrien
1110218822Sdim   Fills in neon_type struct pointer with parsed information, and updates STR
1111218822Sdim   to point after the parsed type specifier. Returns SUCCESS if this was a legal
1112218822Sdim   type, FAIL if not.  */
111389857Sobrien
1114218822Sdimstatic int
1115218822Sdimparse_neon_type (struct neon_type *type, char **str)
1116218822Sdim{
1117218822Sdim  char *ptr = *str;
111889857Sobrien
1119218822Sdim  if (type)
1120218822Sdim    type->elems = 0;
112189857Sobrien
1122218822Sdim  while (type->elems < NEON_MAX_TYPE_ELS)
1123218822Sdim    {
1124218822Sdim      enum neon_el_type thistype = NT_untyped;
1125218822Sdim      unsigned thissize = -1u;
112689857Sobrien
1127218822Sdim      if (*ptr != '.')
1128218822Sdim	break;
112989857Sobrien
1130218822Sdim      ptr++;
113189857Sobrien
1132218822Sdim      /* Just a size without an explicit type.  */
1133218822Sdim      if (ISDIGIT (*ptr))
1134218822Sdim	goto parsesize;
113589857Sobrien
1136218822Sdim      switch (TOLOWER (*ptr))
1137218822Sdim	{
1138218822Sdim	case 'i': thistype = NT_integer; break;
1139218822Sdim	case 'f': thistype = NT_float; break;
1140218822Sdim	case 'p': thistype = NT_poly; break;
1141218822Sdim	case 's': thistype = NT_signed; break;
1142218822Sdim	case 'u': thistype = NT_unsigned; break;
1143218822Sdim        case 'd':
1144218822Sdim          thistype = NT_float;
1145218822Sdim          thissize = 64;
1146218822Sdim          ptr++;
1147218822Sdim          goto done;
1148218822Sdim	default:
1149218822Sdim	  as_bad (_("unexpected character `%c' in type specifier"), *ptr);
1150218822Sdim	  return FAIL;
1151218822Sdim	}
115289857Sobrien
1153218822Sdim      ptr++;
115489857Sobrien
1155218822Sdim      /* .f is an abbreviation for .f32.  */
1156218822Sdim      if (thistype == NT_float && !ISDIGIT (*ptr))
1157218822Sdim	thissize = 32;
1158218822Sdim      else
1159218822Sdim	{
1160218822Sdim	parsesize:
1161218822Sdim	  thissize = strtoul (ptr, &ptr, 10);
116289857Sobrien
1163218822Sdim	  if (thissize != 8 && thissize != 16 && thissize != 32
1164218822Sdim              && thissize != 64)
1165218822Sdim            {
1166218822Sdim              as_bad (_("bad size %d in type specifier"), thissize);
1167218822Sdim	      return FAIL;
1168218822Sdim	    }
1169218822Sdim	}
117089857Sobrien
1171218822Sdim      done:
1172218822Sdim      if (type)
1173218822Sdim        {
1174218822Sdim          type->el[type->elems].type = thistype;
1175218822Sdim	  type->el[type->elems].size = thissize;
1176218822Sdim	  type->elems++;
1177218822Sdim	}
1178218822Sdim    }
117989857Sobrien
1180218822Sdim  /* Empty/missing type is not a successful parse.  */
1181218822Sdim  if (type->elems == 0)
1182218822Sdim    return FAIL;
118389857Sobrien
1184218822Sdim  *str = ptr;
118589857Sobrien
1186218822Sdim  return SUCCESS;
1187218822Sdim}
118889857Sobrien
1189218822Sdim/* Errors may be set multiple times during parsing or bit encoding
1190218822Sdim   (particularly in the Neon bits), but usually the earliest error which is set
1191218822Sdim   will be the most meaningful. Avoid overwriting it with later (cascading)
1192218822Sdim   errors by calling this function.  */
119389857Sobrien
1194218822Sdimstatic void
1195218822Sdimfirst_error (const char *err)
1196218822Sdim{
1197218822Sdim  if (!inst.error)
1198218822Sdim    inst.error = err;
1199218822Sdim}
120089857Sobrien
1201218822Sdim/* Parse a single type, e.g. ".s32", leading period included.  */
1202218822Sdimstatic int
1203218822Sdimparse_neon_operand_type (struct neon_type_el *vectype, char **ccp)
1204218822Sdim{
1205218822Sdim  char *str = *ccp;
1206218822Sdim  struct neon_type optype;
120789857Sobrien
1208218822Sdim  if (*str == '.')
1209218822Sdim    {
1210218822Sdim      if (parse_neon_type (&optype, &str) == SUCCESS)
1211218822Sdim        {
1212218822Sdim          if (optype.elems == 1)
1213218822Sdim            *vectype = optype.el[0];
1214218822Sdim          else
1215218822Sdim            {
1216218822Sdim              first_error (_("only one type should be specified for operand"));
1217218822Sdim              return FAIL;
1218218822Sdim            }
1219218822Sdim        }
1220218822Sdim      else
1221218822Sdim        {
1222218822Sdim          first_error (_("vector type expected"));
1223218822Sdim          return FAIL;
1224218822Sdim        }
1225218822Sdim    }
1226218822Sdim  else
1227218822Sdim    return FAIL;
1228218822Sdim
1229218822Sdim  *ccp = str;
1230218822Sdim
1231218822Sdim  return SUCCESS;
1232218822Sdim}
123389857Sobrien
1234218822Sdim/* Special meanings for indices (which have a range of 0-7), which will fit into
1235218822Sdim   a 4-bit integer.  */
123689857Sobrien
1237218822Sdim#define NEON_ALL_LANES		15
1238218822Sdim#define NEON_INTERLEAVE_LANES	14
123989857Sobrien
1240218822Sdim/* Parse either a register or a scalar, with an optional type. Return the
1241218822Sdim   register number, and optionally fill in the actual type of the register
1242218822Sdim   when multiple alternatives were given (NEON_TYPE_NDQ) in *RTYPE, and
1243218822Sdim   type/index information in *TYPEINFO.  */
124489857Sobrien
1245218822Sdimstatic int
1246218822Sdimparse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type,
1247218822Sdim                           enum arm_reg_type *rtype,
1248218822Sdim                           struct neon_typed_alias *typeinfo)
1249218822Sdim{
1250218822Sdim  char *str = *ccp;
1251218822Sdim  struct reg_entry *reg = arm_reg_parse_multi (&str);
1252218822Sdim  struct neon_typed_alias atype;
1253218822Sdim  struct neon_type_el parsetype;
125489857Sobrien
1255218822Sdim  atype.defined = 0;
1256218822Sdim  atype.index = -1;
1257218822Sdim  atype.eltype.type = NT_invtype;
1258218822Sdim  atype.eltype.size = -1;
125989857Sobrien
1260218822Sdim  /* Try alternate syntax for some types of register. Note these are mutually
1261218822Sdim     exclusive with the Neon syntax extensions.  */
1262218822Sdim  if (reg == NULL)
1263218822Sdim    {
1264218822Sdim      int altreg = arm_reg_alt_syntax (&str, *ccp, reg, type);
1265218822Sdim      if (altreg != FAIL)
1266218822Sdim        *ccp = str;
1267218822Sdim      if (typeinfo)
1268218822Sdim        *typeinfo = atype;
1269218822Sdim      return altreg;
1270218822Sdim    }
127189857Sobrien
1272218822Sdim  /* Undo polymorphism when a set of register types may be accepted.  */
1273218822Sdim  if ((type == REG_TYPE_NDQ
1274218822Sdim       && (reg->type == REG_TYPE_NQ || reg->type == REG_TYPE_VFD))
1275218822Sdim      || (type == REG_TYPE_VFSD
1276218822Sdim          && (reg->type == REG_TYPE_VFS || reg->type == REG_TYPE_VFD))
1277218822Sdim      || (type == REG_TYPE_NSDQ
1278218822Sdim          && (reg->type == REG_TYPE_VFS || reg->type == REG_TYPE_VFD
1279218822Sdim              || reg->type == REG_TYPE_NQ))
1280218822Sdim      || (type == REG_TYPE_MMXWC
1281218822Sdim	  && (reg->type == REG_TYPE_MMXWCG)))
1282218822Sdim    type = reg->type;
128389857Sobrien
1284218822Sdim  if (type != reg->type)
1285218822Sdim    return FAIL;
128689857Sobrien
1287218822Sdim  if (reg->neon)
1288218822Sdim    atype = *reg->neon;
1289218822Sdim
1290218822Sdim  if (parse_neon_operand_type (&parsetype, &str) == SUCCESS)
1291218822Sdim    {
1292218822Sdim      if ((atype.defined & NTA_HASTYPE) != 0)
1293218822Sdim        {
1294218822Sdim          first_error (_("can't redefine type for operand"));
1295218822Sdim          return FAIL;
1296218822Sdim        }
1297218822Sdim      atype.defined |= NTA_HASTYPE;
1298218822Sdim      atype.eltype = parsetype;
1299218822Sdim    }
1300218822Sdim
1301218822Sdim  if (skip_past_char (&str, '[') == SUCCESS)
1302218822Sdim    {
1303218822Sdim      if (type != REG_TYPE_VFD)
1304218822Sdim        {
1305218822Sdim          first_error (_("only D registers may be indexed"));
1306218822Sdim          return FAIL;
1307218822Sdim        }
1308218822Sdim
1309218822Sdim      if ((atype.defined & NTA_HASINDEX) != 0)
1310218822Sdim        {
1311218822Sdim          first_error (_("can't change index for operand"));
1312218822Sdim          return FAIL;
1313218822Sdim        }
131489857Sobrien
1315218822Sdim      atype.defined |= NTA_HASINDEX;
131689857Sobrien
1317218822Sdim      if (skip_past_char (&str, ']') == SUCCESS)
1318218822Sdim        atype.index = NEON_ALL_LANES;
1319218822Sdim      else
1320218822Sdim        {
1321218822Sdim          expressionS exp;
132289857Sobrien
1323218822Sdim          my_get_expression (&exp, &str, GE_NO_PREFIX);
132489857Sobrien
1325218822Sdim          if (exp.X_op != O_constant)
1326218822Sdim            {
1327218822Sdim              first_error (_("constant expression required"));
1328218822Sdim              return FAIL;
1329218822Sdim            }
133089857Sobrien
1331218822Sdim          if (skip_past_char (&str, ']') == FAIL)
1332218822Sdim            return FAIL;
133389857Sobrien
1334218822Sdim          atype.index = exp.X_add_number;
1335218822Sdim        }
1336218822Sdim    }
1337218822Sdim
1338218822Sdim  if (typeinfo)
1339218822Sdim    *typeinfo = atype;
1340218822Sdim
1341218822Sdim  if (rtype)
1342218822Sdim    *rtype = type;
1343218822Sdim
1344218822Sdim  *ccp = str;
1345218822Sdim
1346218822Sdim  return reg->number;
1347218822Sdim}
134889857Sobrien
1349218822Sdim/* Like arm_reg_parse, but allow allow the following extra features:
1350218822Sdim    - If RTYPE is non-zero, return the (possibly restricted) type of the
1351218822Sdim      register (e.g. Neon double or quad reg when either has been requested).
1352218822Sdim    - If this is a Neon vector type with additional type information, fill
1353218822Sdim      in the struct pointed to by VECTYPE (if non-NULL).
1354218822Sdim   This function will fault on encountering a scalar.
1355218822Sdim*/
135689857Sobrien
1357218822Sdimstatic int
1358218822Sdimarm_typed_reg_parse (char **ccp, enum arm_reg_type type,
1359218822Sdim                     enum arm_reg_type *rtype, struct neon_type_el *vectype)
1360218822Sdim{
1361218822Sdim  struct neon_typed_alias atype;
1362218822Sdim  char *str = *ccp;
1363218822Sdim  int reg = parse_typed_reg_or_scalar (&str, type, rtype, &atype);
136489857Sobrien
1365218822Sdim  if (reg == FAIL)
1366218822Sdim    return FAIL;
136789857Sobrien
1368218822Sdim  /* Do not allow a scalar (reg+index) to parse as a register.  */
1369218822Sdim  if ((atype.defined & NTA_HASINDEX) != 0)
1370218822Sdim    {
1371218822Sdim      first_error (_("register operand expected, but got scalar"));
1372218822Sdim      return FAIL;
1373218822Sdim    }
1374130561Sobrien
1375218822Sdim  if (vectype)
1376218822Sdim    *vectype = atype.eltype;
137760484Sobrien
1378218822Sdim  *ccp = str;
137960484Sobrien
1380218822Sdim  return reg;
1381218822Sdim}
138289857Sobrien
1383218822Sdim#define NEON_SCALAR_REG(X)	((X) >> 4)
1384218822Sdim#define NEON_SCALAR_INDEX(X)	((X) & 15)
138560484Sobrien
1386218822Sdim/* Parse a Neon scalar. Most of the time when we're parsing a scalar, we don't
1387218822Sdim   have enough information to be able to do a good job bounds-checking. So, we
1388218822Sdim   just do easy checks here, and do further checks later.  */
138960484Sobrien
1390218822Sdimstatic int
1391218822Sdimparse_scalar (char **ccp, int elsize, struct neon_type_el *type)
1392218822Sdim{
1393218822Sdim  int reg;
1394218822Sdim  char *str = *ccp;
1395218822Sdim  struct neon_typed_alias atype;
1396218822Sdim
1397218822Sdim  reg = parse_typed_reg_or_scalar (&str, REG_TYPE_VFD, NULL, &atype);
1398218822Sdim
1399218822Sdim  if (reg == FAIL || (atype.defined & NTA_HASINDEX) == 0)
1400218822Sdim    return FAIL;
1401218822Sdim
1402218822Sdim  if (atype.index == NEON_ALL_LANES)
1403218822Sdim    {
1404218822Sdim      first_error (_("scalar must have an index"));
1405218822Sdim      return FAIL;
1406218822Sdim    }
1407218822Sdim  else if (atype.index >= 64 / elsize)
1408218822Sdim    {
1409218822Sdim      first_error (_("scalar index out of range"));
1410218822Sdim      return FAIL;
1411218822Sdim    }
1412218822Sdim
1413218822Sdim  if (type)
1414218822Sdim    *type = atype.eltype;
1415218822Sdim
1416218822Sdim  *ccp = str;
1417218822Sdim
1418218822Sdim  return reg * 16 + atype.index;
1419218822Sdim}
142060484Sobrien
1421218822Sdim/* Parse an ARM register list.  Returns the bitmask, or FAIL.  */
1422218822Sdimstatic long
1423218822Sdimparse_reg_list (char ** strp)
1424218822Sdim{
1425218822Sdim  char * str = * strp;
1426218822Sdim  long	 range = 0;
1427218822Sdim  int	 another_range;
142889857Sobrien
1429218822Sdim  /* We come back here if we get ranges concatenated by '+' or '|'.  */
1430218822Sdim  do
1431218822Sdim    {
1432218822Sdim      another_range = 0;
1433130561Sobrien
1434218822Sdim      if (*str == '{')
1435218822Sdim	{
1436218822Sdim	  int in_range = 0;
1437218822Sdim	  int cur_reg = -1;
143860484Sobrien
1439218822Sdim	  str++;
1440218822Sdim	  do
1441218822Sdim	    {
1442218822Sdim	      int reg;
144360484Sobrien
1444218822Sdim	      if ((reg = arm_reg_parse (&str, REG_TYPE_RN)) == FAIL)
1445218822Sdim		{
1446218822Sdim		  first_error (_(reg_expected_msgs[REG_TYPE_RN]));
1447218822Sdim		  return FAIL;
1448218822Sdim		}
144960484Sobrien
1450218822Sdim	      if (in_range)
1451218822Sdim		{
1452218822Sdim		  int i;
145360484Sobrien
1454218822Sdim		  if (reg <= cur_reg)
1455218822Sdim		    {
1456218822Sdim		      first_error (_("bad range in register list"));
1457218822Sdim		      return FAIL;
1458218822Sdim		    }
145960484Sobrien
1460218822Sdim		  for (i = cur_reg + 1; i < reg; i++)
1461218822Sdim		    {
1462218822Sdim		      if (range & (1 << i))
1463218822Sdim			as_tsktsk
1464218822Sdim			  (_("Warning: duplicated register (r%d) in register list"),
1465218822Sdim			   i);
1466218822Sdim		      else
1467218822Sdim			range |= 1 << i;
1468218822Sdim		    }
1469218822Sdim		  in_range = 0;
1470218822Sdim		}
147160484Sobrien
1472218822Sdim	      if (range & (1 << reg))
1473218822Sdim		as_tsktsk (_("Warning: duplicated register (r%d) in register list"),
1474218822Sdim			   reg);
1475218822Sdim	      else if (reg <= cur_reg)
1476218822Sdim		as_tsktsk (_("Warning: register range not in ascending order"));
147760484Sobrien
1478218822Sdim	      range |= 1 << reg;
1479218822Sdim	      cur_reg = reg;
1480218822Sdim	    }
1481218822Sdim	  while (skip_past_comma (&str) != FAIL
1482218822Sdim		 || (in_range = 1, *str++ == '-'));
1483218822Sdim	  str--;
148460484Sobrien
1485218822Sdim	  if (*str++ != '}')
1486218822Sdim	    {
1487218822Sdim	      first_error (_("missing `}'"));
1488218822Sdim	      return FAIL;
1489218822Sdim	    }
1490218822Sdim	}
1491218822Sdim      else
1492218822Sdim	{
1493218822Sdim	  expressionS expr;
149460484Sobrien
1495218822Sdim	  if (my_get_expression (&expr, &str, GE_NO_PREFIX))
1496218822Sdim	    return FAIL;
149760484Sobrien
1498218822Sdim	  if (expr.X_op == O_constant)
1499218822Sdim	    {
1500218822Sdim	      if (expr.X_add_number
1501218822Sdim		  != (expr.X_add_number & 0x0000ffff))
1502218822Sdim		{
1503218822Sdim		  inst.error = _("invalid register mask");
1504218822Sdim		  return FAIL;
1505218822Sdim		}
150660484Sobrien
1507218822Sdim	      if ((range & expr.X_add_number) != 0)
1508218822Sdim		{
1509218822Sdim		  int regno = range & expr.X_add_number;
151060484Sobrien
1511218822Sdim		  regno &= -regno;
1512218822Sdim		  regno = (1 << regno) - 1;
1513218822Sdim		  as_tsktsk
1514218822Sdim		    (_("Warning: duplicated register (r%d) in register list"),
1515218822Sdim		     regno);
1516218822Sdim		}
151760484Sobrien
1518218822Sdim	      range |= expr.X_add_number;
1519218822Sdim	    }
1520218822Sdim	  else
1521218822Sdim	    {
1522218822Sdim	      if (inst.reloc.type != 0)
1523218822Sdim		{
1524218822Sdim		  inst.error = _("expression too complex");
1525218822Sdim		  return FAIL;
1526218822Sdim		}
152760484Sobrien
1528218822Sdim	      memcpy (&inst.reloc.exp, &expr, sizeof (expressionS));
1529218822Sdim	      inst.reloc.type = BFD_RELOC_ARM_MULTI;
1530218822Sdim	      inst.reloc.pc_rel = 0;
1531218822Sdim	    }
1532218822Sdim	}
153360484Sobrien
1534218822Sdim      if (*str == '|' || *str == '+')
1535218822Sdim	{
1536218822Sdim	  str++;
1537218822Sdim	  another_range = 1;
1538218822Sdim	}
1539218822Sdim    }
1540218822Sdim  while (another_range);
154177298Sobrien
1542218822Sdim  *strp = str;
1543218822Sdim  return range;
1544218822Sdim}
154577298Sobrien
1546218822Sdim/* Types of registers in a list.  */
154777298Sobrien
1548218822Sdimenum reg_list_els
1549218822Sdim{
1550218822Sdim  REGLIST_VFP_S,
1551218822Sdim  REGLIST_VFP_D,
1552218822Sdim  REGLIST_NEON_D
155360484Sobrien};
155460484Sobrien
1555218822Sdim/* Parse a VFP register list.  If the string is invalid return FAIL.
1556218822Sdim   Otherwise return the number of registers, and set PBASE to the first
1557218822Sdim   register.  Parses registers of type ETYPE.
1558218822Sdim   If REGLIST_NEON_D is used, several syntax enhancements are enabled:
1559218822Sdim     - Q registers can be used to specify pairs of D registers
1560218822Sdim     - { } can be omitted from around a singleton register list
1561218822Sdim         FIXME: This is not implemented, as it would require backtracking in
1562218822Sdim         some cases, e.g.:
1563218822Sdim           vtbl.8 d3,d4,d5
1564218822Sdim         This could be done (the meaning isn't really ambiguous), but doesn't
1565218822Sdim         fit in well with the current parsing framework.
1566218822Sdim     - 32 D registers may be used (also true for VFPv3).
1567218822Sdim   FIXME: Types are ignored in these register lists, which is probably a
1568218822Sdim   bug.  */
1569218822Sdim
1570218822Sdimstatic int
1571218822Sdimparse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
157260484Sobrien{
1573218822Sdim  char *str = *ccp;
1574218822Sdim  int base_reg;
1575218822Sdim  int new_base;
1576218822Sdim  enum arm_reg_type regtype = 0;
1577218822Sdim  int max_regs = 0;
1578218822Sdim  int count = 0;
1579218822Sdim  int warned = 0;
1580218822Sdim  unsigned long mask = 0;
1581218822Sdim  int i;
1582130561Sobrien
1583218822Sdim  if (*str != '{')
1584218822Sdim    {
1585218822Sdim      inst.error = _("expecting {");
1586218822Sdim      return FAIL;
1587218822Sdim    }
158860484Sobrien
1589218822Sdim  str++;
159060484Sobrien
1591218822Sdim  switch (etype)
1592218822Sdim    {
1593218822Sdim    case REGLIST_VFP_S:
1594218822Sdim      regtype = REG_TYPE_VFS;
1595218822Sdim      max_regs = 32;
1596218822Sdim      break;
1597218822Sdim
1598218822Sdim    case REGLIST_VFP_D:
1599218822Sdim      regtype = REG_TYPE_VFD;
1600218822Sdim      break;
1601218822Sdim
1602218822Sdim    case REGLIST_NEON_D:
1603218822Sdim      regtype = REG_TYPE_NDQ;
1604218822Sdim      break;
1605218822Sdim    }
160660484Sobrien
1607218822Sdim  if (etype != REGLIST_VFP_S)
1608218822Sdim    {
1609218822Sdim      /* VFPv3 allows 32 D registers.  */
1610218822Sdim      if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v3))
1611218822Sdim        {
1612218822Sdim          max_regs = 32;
1613218822Sdim          if (thumb_mode)
1614218822Sdim            ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
1615218822Sdim                                    fpu_vfp_ext_v3);
1616218822Sdim          else
1617218822Sdim            ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used,
1618218822Sdim                                    fpu_vfp_ext_v3);
1619218822Sdim        }
1620218822Sdim      else
1621218822Sdim        max_regs = 16;
1622218822Sdim    }
162360484Sobrien
1624218822Sdim  base_reg = max_regs;
162560484Sobrien
1626218822Sdim  do
1627218822Sdim    {
1628218822Sdim      int setmask = 1, addregs = 1;
162960484Sobrien
1630218822Sdim      new_base = arm_typed_reg_parse (&str, regtype, &regtype, NULL);
163160484Sobrien
1632218822Sdim      if (new_base == FAIL)
1633218822Sdim	{
1634218822Sdim	  first_error (_(reg_expected_msgs[regtype]));
1635218822Sdim	  return FAIL;
1636218822Sdim	}
1637218822Sdim
1638218822Sdim      if (new_base >= max_regs)
1639218822Sdim        {
1640218822Sdim          first_error (_("register out of range in list"));
1641218822Sdim          return FAIL;
1642218822Sdim        }
1643218822Sdim
1644218822Sdim      /* Note: a value of 2 * n is returned for the register Q<n>.  */
1645218822Sdim      if (regtype == REG_TYPE_NQ)
1646218822Sdim        {
1647218822Sdim          setmask = 3;
1648218822Sdim          addregs = 2;
1649218822Sdim        }
165089857Sobrien
1651218822Sdim      if (new_base < base_reg)
1652218822Sdim	base_reg = new_base;
165360484Sobrien
1654218822Sdim      if (mask & (setmask << new_base))
1655218822Sdim	{
1656218822Sdim	  first_error (_("invalid register list"));
1657218822Sdim	  return FAIL;
1658218822Sdim	}
165960484Sobrien
1660218822Sdim      if ((mask >> new_base) != 0 && ! warned)
1661218822Sdim	{
1662218822Sdim	  as_tsktsk (_("register list not in ascending order"));
1663218822Sdim	  warned = 1;
1664218822Sdim	}
166560484Sobrien
1666218822Sdim      mask |= setmask << new_base;
1667218822Sdim      count += addregs;
166860484Sobrien
1669218822Sdim      if (*str == '-') /* We have the start of a range expression */
1670218822Sdim	{
1671218822Sdim	  int high_range;
167260484Sobrien
1673218822Sdim	  str++;
167477298Sobrien
1675218822Sdim	  if ((high_range = arm_typed_reg_parse (&str, regtype, NULL, NULL))
1676218822Sdim              == FAIL)
1677218822Sdim	    {
1678218822Sdim	      inst.error = gettext (reg_expected_msgs[regtype]);
1679218822Sdim	      return FAIL;
1680218822Sdim	    }
168177298Sobrien
1682218822Sdim          if (high_range >= max_regs)
1683218822Sdim            {
1684218822Sdim              first_error (_("register out of range in list"));
1685218822Sdim              return FAIL;
1686218822Sdim            }
168777298Sobrien
1688218822Sdim          if (regtype == REG_TYPE_NQ)
1689218822Sdim            high_range = high_range + 1;
1690218822Sdim
1691218822Sdim	  if (high_range <= new_base)
1692218822Sdim	    {
1693218822Sdim	      inst.error = _("register range not in ascending order");
1694218822Sdim	      return FAIL;
1695218822Sdim	    }
1696218822Sdim
1697218822Sdim	  for (new_base += addregs; new_base <= high_range; new_base += addregs)
1698218822Sdim	    {
1699218822Sdim	      if (mask & (setmask << new_base))
1700218822Sdim		{
1701218822Sdim		  inst.error = _("invalid register list");
1702218822Sdim		  return FAIL;
1703218822Sdim		}
1704218822Sdim
1705218822Sdim	      mask |= setmask << new_base;
1706218822Sdim	      count += addregs;
1707218822Sdim	    }
1708218822Sdim	}
1709218822Sdim    }
1710218822Sdim  while (skip_past_comma (&str) != FAIL);
1711218822Sdim
1712218822Sdim  str++;
1713218822Sdim
1714218822Sdim  /* Sanity check -- should have raised a parse error above.  */
1715218822Sdim  if (count == 0 || count > max_regs)
1716218822Sdim    abort ();
1717218822Sdim
1718218822Sdim  *pbase = base_reg;
1719218822Sdim
1720218822Sdim  /* Final test -- the registers must be consecutive.  */
1721218822Sdim  mask >>= base_reg;
1722218822Sdim  for (i = 0; i < count; i++)
1723130561Sobrien    {
1724218822Sdim      if ((mask & (1u << i)) == 0)
1725218822Sdim	{
1726218822Sdim	  inst.error = _("non-contiguous register range");
1727218822Sdim	  return FAIL;
1728218822Sdim	}
1729130561Sobrien    }
173060484Sobrien
1731218822Sdim  *ccp = str;
1732218822Sdim
1733218822Sdim  return count;
1734130561Sobrien}
1735130561Sobrien
1736218822Sdim/* True if two alias types are the same.  */
1737218822Sdim
1738218822Sdimstatic int
1739218822Sdimneon_alias_types_same (struct neon_typed_alias *a, struct neon_typed_alias *b)
1740130561Sobrien{
1741218822Sdim  if (!a && !b)
1742218822Sdim    return 1;
1743218822Sdim
1744218822Sdim  if (!a || !b)
1745218822Sdim    return 0;
1746130561Sobrien
1747218822Sdim  if (a->defined != b->defined)
1748218822Sdim    return 0;
1749218822Sdim
1750218822Sdim  if ((a->defined & NTA_HASTYPE) != 0
1751218822Sdim      && (a->eltype.type != b->eltype.type
1752218822Sdim          || a->eltype.size != b->eltype.size))
1753218822Sdim    return 0;
1754130561Sobrien
1755218822Sdim  if ((a->defined & NTA_HASINDEX) != 0
1756218822Sdim      && (a->index != b->index))
1757218822Sdim    return 0;
1758218822Sdim
1759218822Sdim  return 1;
1760218822Sdim}
1761218822Sdim
1762218822Sdim/* Parse element/structure lists for Neon VLD<n> and VST<n> instructions.
1763218822Sdim   The base register is put in *PBASE.
1764218822Sdim   The lane (or one of the NEON_*_LANES constants) is placed in bits [3:0] of
1765218822Sdim   the return value.
1766218822Sdim   The register stride (minus one) is put in bit 4 of the return value.
1767218822Sdim   Bits [6:5] encode the list length (minus one).
1768218822Sdim   The type of the list elements is put in *ELTYPE, if non-NULL.  */
1769218822Sdim
1770218822Sdim#define NEON_LANE(X)		((X) & 0xf)
1771218822Sdim#define NEON_REG_STRIDE(X)	((((X) >> 4) & 1) + 1)
1772218822Sdim#define NEON_REGLIST_LENGTH(X)	((((X) >> 5) & 3) + 1)
1773218822Sdim
1774218822Sdimstatic int
1775218822Sdimparse_neon_el_struct_list (char **str, unsigned *pbase,
1776218822Sdim                           struct neon_type_el *eltype)
1777218822Sdim{
1778218822Sdim  char *ptr = *str;
1779218822Sdim  int base_reg = -1;
1780218822Sdim  int reg_incr = -1;
1781218822Sdim  int count = 0;
1782218822Sdim  int lane = -1;
1783218822Sdim  int leading_brace = 0;
1784218822Sdim  enum arm_reg_type rtype = REG_TYPE_NDQ;
1785218822Sdim  int addregs = 1;
1786218822Sdim  const char *const incr_error = "register stride must be 1 or 2";
1787218822Sdim  const char *const type_error = "mismatched element/structure types in list";
1788218822Sdim  struct neon_typed_alias firsttype;
1789218822Sdim
1790218822Sdim  if (skip_past_char (&ptr, '{') == SUCCESS)
1791218822Sdim    leading_brace = 1;
1792218822Sdim
1793218822Sdim  do
1794130561Sobrien    {
1795218822Sdim      struct neon_typed_alias atype;
1796218822Sdim      int getreg = parse_typed_reg_or_scalar (&ptr, rtype, &rtype, &atype);
1797130561Sobrien
1798218822Sdim      if (getreg == FAIL)
1799218822Sdim        {
1800218822Sdim          first_error (_(reg_expected_msgs[rtype]));
1801218822Sdim          return FAIL;
1802218822Sdim        }
1803218822Sdim
1804218822Sdim      if (base_reg == -1)
1805218822Sdim        {
1806218822Sdim          base_reg = getreg;
1807218822Sdim          if (rtype == REG_TYPE_NQ)
1808218822Sdim            {
1809218822Sdim              reg_incr = 1;
1810218822Sdim              addregs = 2;
1811218822Sdim            }
1812218822Sdim          firsttype = atype;
1813218822Sdim        }
1814218822Sdim      else if (reg_incr == -1)
1815218822Sdim        {
1816218822Sdim          reg_incr = getreg - base_reg;
1817218822Sdim          if (reg_incr < 1 || reg_incr > 2)
1818218822Sdim            {
1819218822Sdim              first_error (_(incr_error));
1820218822Sdim              return FAIL;
1821218822Sdim            }
1822218822Sdim        }
1823218822Sdim      else if (getreg != base_reg + reg_incr * count)
1824218822Sdim        {
1825218822Sdim          first_error (_(incr_error));
1826218822Sdim          return FAIL;
1827218822Sdim        }
1828130561Sobrien
1829218822Sdim      if (!neon_alias_types_same (&atype, &firsttype))
1830218822Sdim        {
1831218822Sdim          first_error (_(type_error));
1832218822Sdim          return FAIL;
1833218822Sdim        }
1834218822Sdim
1835218822Sdim      /* Handle Dn-Dm or Qn-Qm syntax. Can only be used with non-indexed list
1836218822Sdim         modes.  */
1837218822Sdim      if (ptr[0] == '-')
1838218822Sdim        {
1839218822Sdim          struct neon_typed_alias htype;
1840218822Sdim          int hireg, dregs = (rtype == REG_TYPE_NQ) ? 2 : 1;
1841218822Sdim          if (lane == -1)
1842218822Sdim            lane = NEON_INTERLEAVE_LANES;
1843218822Sdim          else if (lane != NEON_INTERLEAVE_LANES)
1844218822Sdim            {
1845218822Sdim              first_error (_(type_error));
1846218822Sdim              return FAIL;
1847218822Sdim            }
1848218822Sdim          if (reg_incr == -1)
1849218822Sdim            reg_incr = 1;
1850218822Sdim          else if (reg_incr != 1)
1851218822Sdim            {
1852218822Sdim              first_error (_("don't use Rn-Rm syntax with non-unit stride"));
1853218822Sdim              return FAIL;
1854218822Sdim            }
1855218822Sdim          ptr++;
1856218822Sdim          hireg = parse_typed_reg_or_scalar (&ptr, rtype, NULL, &htype);
1857218822Sdim          if (hireg == FAIL)
1858218822Sdim            {
1859218822Sdim              first_error (_(reg_expected_msgs[rtype]));
1860218822Sdim              return FAIL;
1861218822Sdim            }
1862218822Sdim          if (!neon_alias_types_same (&htype, &firsttype))
1863218822Sdim            {
1864218822Sdim              first_error (_(type_error));
1865218822Sdim              return FAIL;
1866218822Sdim            }
1867218822Sdim          count += hireg + dregs - getreg;
1868218822Sdim          continue;
1869218822Sdim        }
1870218822Sdim
1871218822Sdim      /* If we're using Q registers, we can't use [] or [n] syntax.  */
1872218822Sdim      if (rtype == REG_TYPE_NQ)
1873218822Sdim        {
1874218822Sdim          count += 2;
1875218822Sdim          continue;
1876218822Sdim        }
1877218822Sdim
1878218822Sdim      if ((atype.defined & NTA_HASINDEX) != 0)
1879218822Sdim        {
1880218822Sdim          if (lane == -1)
1881218822Sdim            lane = atype.index;
1882218822Sdim          else if (lane != atype.index)
1883218822Sdim            {
1884218822Sdim              first_error (_(type_error));
1885218822Sdim              return FAIL;
1886218822Sdim            }
1887218822Sdim        }
1888218822Sdim      else if (lane == -1)
1889218822Sdim        lane = NEON_INTERLEAVE_LANES;
1890218822Sdim      else if (lane != NEON_INTERLEAVE_LANES)
1891218822Sdim        {
1892218822Sdim          first_error (_(type_error));
1893218822Sdim          return FAIL;
1894218822Sdim        }
1895218822Sdim      count++;
1896130561Sobrien    }
1897218822Sdim  while ((count != 1 || leading_brace) && skip_past_comma (&ptr) != FAIL);
1898218822Sdim
1899218822Sdim  /* No lane set by [x]. We must be interleaving structures.  */
1900218822Sdim  if (lane == -1)
1901218822Sdim    lane = NEON_INTERLEAVE_LANES;
1902218822Sdim
1903218822Sdim  /* Sanity check.  */
1904218822Sdim  if (lane == -1 || base_reg == -1 || count < 1 || count > 4
1905218822Sdim      || (count > 1 && reg_incr == -1))
1906218822Sdim    {
1907218822Sdim      first_error (_("error parsing element/structure list"));
1908218822Sdim      return FAIL;
1909218822Sdim    }
1910130561Sobrien
1911218822Sdim  if ((count > 1 || leading_brace) && skip_past_char (&ptr, '}') == FAIL)
1912130561Sobrien    {
1913218822Sdim      first_error (_("expected }"));
1914218822Sdim      return FAIL;
1915130561Sobrien    }
1916218822Sdim
1917218822Sdim  if (reg_incr == -1)
1918218822Sdim    reg_incr = 1;
1919130561Sobrien
1920218822Sdim  if (eltype)
1921218822Sdim    *eltype = firsttype.eltype;
1922218822Sdim
1923218822Sdim  *pbase = base_reg;
1924218822Sdim  *str = ptr;
1925218822Sdim
1926218822Sdim  return lane | ((reg_incr - 1) << 4) | ((count - 1) << 5);
1927130561Sobrien}
1928130561Sobrien
1929218822Sdim/* Parse an explicit relocation suffix on an expression.  This is
1930218822Sdim   either nothing, or a word in parentheses.  Note that if !OBJ_ELF,
1931218822Sdim   arm_reloc_hsh contains no entries, so this function can only
1932218822Sdim   succeed if there is no () after the word.  Returns -1 on error,
1933218822Sdim   BFD_RELOC_UNUSED if there wasn't any suffix.	 */
193460484Sobrienstatic int
1935218822Sdimparse_reloc (char **str)
193660484Sobrien{
1937218822Sdim  struct reloc_entry *r;
1938218822Sdim  char *p, *q;
193960484Sobrien
1940218822Sdim  if (**str != '(')
1941218822Sdim    return BFD_RELOC_UNUSED;
194260484Sobrien
1943218822Sdim  p = *str + 1;
1944218822Sdim  q = p;
194578828Sobrien
1946218822Sdim  while (*q && *q != ')' && *q != ',')
1947218822Sdim    q++;
1948218822Sdim  if (*q != ')')
1949218822Sdim    return -1;
195060484Sobrien
1951218822Sdim  if ((r = hash_find_n (arm_reloc_hsh, p, q - p)) == NULL)
1952218822Sdim    return -1;
1953218822Sdim
1954218822Sdim  *str = q + 1;
1955218822Sdim  return r->reloc;
1956218822Sdim}
1957218822Sdim
1958218822Sdim/* Directives: register aliases.  */
1959218822Sdim
1960218822Sdimstatic struct reg_entry *
1961218822Sdiminsert_reg_alias (char *str, int number, int type)
1962218822Sdim{
1963218822Sdim  struct reg_entry *new;
1964218822Sdim  const char *name;
1965218822Sdim
1966218822Sdim  if ((new = hash_find (arm_reg_hsh, str)) != 0)
196760484Sobrien    {
1968218822Sdim      if (new->builtin)
1969218822Sdim	as_warn (_("ignoring attempt to redefine built-in register '%s'"), str);
197060484Sobrien
1971218822Sdim      /* Only warn about a redefinition if it's not defined as the
1972218822Sdim	 same register.	 */
1973218822Sdim      else if (new->number != number || new->type != type)
1974218822Sdim	as_warn (_("ignoring redefinition of register alias '%s'"), str);
1975218822Sdim
1976218822Sdim      return 0;
197760484Sobrien    }
197860484Sobrien
1979218822Sdim  name = xstrdup (str);
1980218822Sdim  new = xmalloc (sizeof (struct reg_entry));
198160484Sobrien
1982218822Sdim  new->name = name;
1983218822Sdim  new->number = number;
1984218822Sdim  new->type = type;
1985218822Sdim  new->builtin = FALSE;
1986218822Sdim  new->neon = NULL;
1987218822Sdim
1988218822Sdim  if (hash_insert (arm_reg_hsh, name, (PTR) new))
1989218822Sdim    abort ();
1990218822Sdim
1991218822Sdim  return new;
199260484Sobrien}
199377298Sobrien
199460484Sobrienstatic void
1995218822Sdiminsert_neon_reg_alias (char *str, int number, int type,
1996218822Sdim                       struct neon_typed_alias *atype)
199760484Sobrien{
1998218822Sdim  struct reg_entry *reg = insert_reg_alias (str, number, type);
1999218822Sdim
2000218822Sdim  if (!reg)
2001218822Sdim    {
2002218822Sdim      first_error (_("attempt to redefine typed alias"));
2003218822Sdim      return;
2004218822Sdim    }
2005218822Sdim
2006218822Sdim  if (atype)
2007218822Sdim    {
2008218822Sdim      reg->neon = xmalloc (sizeof (struct neon_typed_alias));
2009218822Sdim      *reg->neon = *atype;
2010218822Sdim    }
2011218822Sdim}
201260484Sobrien
2013218822Sdim/* Look for the .req directive.	 This is of the form:
201460484Sobrien
2015218822Sdim	new_register_name .req existing_register_name
201660484Sobrien
2017218822Sdim   If we find one, or if it looks sufficiently like one that we want to
2018218822Sdim   handle any error here, return non-zero.  Otherwise return zero.  */
201960484Sobrien
2020218822Sdimstatic int
2021218822Sdimcreate_register_alias (char * newname, char *p)
2022218822Sdim{
2023218822Sdim  struct reg_entry *old;
2024218822Sdim  char *oldname, *nbuf;
2025218822Sdim  size_t nlen;
202660484Sobrien
2027218822Sdim  /* The input scrubber ensures that whitespace after the mnemonic is
2028218822Sdim     collapsed to single spaces.  */
2029218822Sdim  oldname = p;
2030218822Sdim  if (strncmp (oldname, " .req ", 6) != 0)
2031218822Sdim    return 0;
203260484Sobrien
2033218822Sdim  oldname += 6;
2034218822Sdim  if (*oldname == '\0')
2035218822Sdim    return 0;
203660484Sobrien
2037218822Sdim  old = hash_find (arm_reg_hsh, oldname);
2038218822Sdim  if (!old)
2039218822Sdim    {
2040218822Sdim      as_warn (_("unknown register '%s' -- .req ignored"), oldname);
2041218822Sdim      return 1;
2042218822Sdim    }
204360484Sobrien
2044218822Sdim  /* If TC_CASE_SENSITIVE is defined, then newname already points to
2045218822Sdim     the desired alias name, and p points to its end.  If not, then
2046218822Sdim     the desired alias name is in the global original_case_string.  */
2047218822Sdim#ifdef TC_CASE_SENSITIVE
2048218822Sdim  nlen = p - newname;
2049218822Sdim#else
2050218822Sdim  newname = original_case_string;
2051218822Sdim  nlen = strlen (newname);
205260484Sobrien#endif
205377298Sobrien
2054218822Sdim  nbuf = alloca (nlen + 1);
2055218822Sdim  memcpy (nbuf, newname, nlen);
2056218822Sdim  nbuf[nlen] = '\0';
205760484Sobrien
2058218822Sdim  /* Create aliases under the new name as stated; an all-lowercase
2059218822Sdim     version of the new name; and an all-uppercase version of the new
2060218822Sdim     name.  */
2061218822Sdim  insert_reg_alias (nbuf, old->number, old->type);
206277298Sobrien
2063218822Sdim  for (p = nbuf; *p; p++)
2064218822Sdim    *p = TOUPPER (*p);
206577298Sobrien
2066218822Sdim  if (strncmp (nbuf, newname, nlen))
2067218822Sdim    insert_reg_alias (nbuf, old->number, old->type);
206877298Sobrien
2069218822Sdim  for (p = nbuf; *p; p++)
2070218822Sdim    *p = TOLOWER (*p);
207177298Sobrien
2072218822Sdim  if (strncmp (nbuf, newname, nlen))
2073218822Sdim    insert_reg_alias (nbuf, old->number, old->type);
2074218822Sdim
2075218822Sdim  return 1;
207660484Sobrien}
207760484Sobrien
2078218822Sdim/* Create a Neon typed/indexed register alias using directives, e.g.:
2079218822Sdim     X .dn d5.s32[1]
2080218822Sdim     Y .qn 6.s16
2081218822Sdim     Z .dn d7
2082218822Sdim     T .dn Z[0]
2083218822Sdim   These typed registers can be used instead of the types specified after the
2084218822Sdim   Neon mnemonic, so long as all operands given have types. Types can also be
2085218822Sdim   specified directly, e.g.:
2086218822Sdim     vadd d0.s32, d1.s32, d2.s32
2087218822Sdim*/
208877298Sobrien
2089218822Sdimstatic int
2090218822Sdimcreate_neon_reg_alias (char *newname, char *p)
209160484Sobrien{
2092218822Sdim  enum arm_reg_type basetype;
2093218822Sdim  struct reg_entry *basereg;
2094218822Sdim  struct reg_entry mybasereg;
2095218822Sdim  struct neon_type ntype;
2096218822Sdim  struct neon_typed_alias typeinfo;
2097218822Sdim  char *namebuf, *nameend;
2098218822Sdim  int namelen;
2099218822Sdim
2100218822Sdim  typeinfo.defined = 0;
2101218822Sdim  typeinfo.eltype.type = NT_invtype;
2102218822Sdim  typeinfo.eltype.size = -1;
2103218822Sdim  typeinfo.index = -1;
2104218822Sdim
2105218822Sdim  nameend = p;
2106218822Sdim
2107218822Sdim  if (strncmp (p, " .dn ", 5) == 0)
2108218822Sdim    basetype = REG_TYPE_VFD;
2109218822Sdim  else if (strncmp (p, " .qn ", 5) == 0)
2110218822Sdim    basetype = REG_TYPE_NQ;
2111218822Sdim  else
2112218822Sdim    return 0;
2113218822Sdim
2114218822Sdim  p += 5;
2115218822Sdim
2116218822Sdim  if (*p == '\0')
2117218822Sdim    return 0;
2118218822Sdim
2119218822Sdim  basereg = arm_reg_parse_multi (&p);
212077298Sobrien
2121218822Sdim  if (basereg && basereg->type != basetype)
2122218822Sdim    {
2123218822Sdim      as_bad (_("bad type for register"));
2124218822Sdim      return 0;
2125218822Sdim    }
212660484Sobrien
2127218822Sdim  if (basereg == NULL)
2128218822Sdim    {
2129218822Sdim      expressionS exp;
2130218822Sdim      /* Try parsing as an integer.  */
2131218822Sdim      my_get_expression (&exp, &p, GE_NO_PREFIX);
2132218822Sdim      if (exp.X_op != O_constant)
2133218822Sdim        {
2134218822Sdim          as_bad (_("expression must be constant"));
2135218822Sdim          return 0;
2136218822Sdim        }
2137218822Sdim      basereg = &mybasereg;
2138218822Sdim      basereg->number = (basetype == REG_TYPE_NQ) ? exp.X_add_number * 2
2139218822Sdim                                                  : exp.X_add_number;
2140218822Sdim      basereg->neon = 0;
2141218822Sdim    }
214277298Sobrien
2143218822Sdim  if (basereg->neon)
2144218822Sdim    typeinfo = *basereg->neon;
2145218822Sdim
2146218822Sdim  if (parse_neon_type (&ntype, &p) == SUCCESS)
2147218822Sdim    {
2148218822Sdim      /* We got a type.  */
2149218822Sdim      if (typeinfo.defined & NTA_HASTYPE)
2150218822Sdim        {
2151218822Sdim          as_bad (_("can't redefine the type of a register alias"));
2152218822Sdim          return 0;
2153218822Sdim        }
2154218822Sdim
2155218822Sdim      typeinfo.defined |= NTA_HASTYPE;
2156218822Sdim      if (ntype.elems != 1)
2157218822Sdim        {
2158218822Sdim          as_bad (_("you must specify a single type only"));
2159218822Sdim          return 0;
2160218822Sdim        }
2161218822Sdim      typeinfo.eltype = ntype.el[0];
2162218822Sdim    }
2163218822Sdim
2164218822Sdim  if (skip_past_char (&p, '[') == SUCCESS)
2165218822Sdim    {
2166218822Sdim      expressionS exp;
2167218822Sdim      /* We got a scalar index.  */
2168218822Sdim
2169218822Sdim      if (typeinfo.defined & NTA_HASINDEX)
2170218822Sdim        {
2171218822Sdim          as_bad (_("can't redefine the index of a scalar alias"));
2172218822Sdim          return 0;
2173218822Sdim        }
2174218822Sdim
2175218822Sdim      my_get_expression (&exp, &p, GE_NO_PREFIX);
2176218822Sdim
2177218822Sdim      if (exp.X_op != O_constant)
2178218822Sdim        {
2179218822Sdim          as_bad (_("scalar index must be constant"));
2180218822Sdim          return 0;
2181218822Sdim        }
2182218822Sdim
2183218822Sdim      typeinfo.defined |= NTA_HASINDEX;
2184218822Sdim      typeinfo.index = exp.X_add_number;
2185218822Sdim
2186218822Sdim      if (skip_past_char (&p, ']') == FAIL)
2187218822Sdim        {
2188218822Sdim          as_bad (_("expecting ]"));
2189218822Sdim          return 0;
2190218822Sdim        }
2191218822Sdim    }
2192218822Sdim
2193218822Sdim  namelen = nameend - newname;
2194218822Sdim  namebuf = alloca (namelen + 1);
2195218822Sdim  strncpy (namebuf, newname, namelen);
2196218822Sdim  namebuf[namelen] = '\0';
2197218822Sdim
2198218822Sdim  insert_neon_reg_alias (namebuf, basereg->number, basetype,
2199218822Sdim                         typeinfo.defined != 0 ? &typeinfo : NULL);
2200218822Sdim
2201218822Sdim  /* Insert name in all uppercase.  */
2202218822Sdim  for (p = namebuf; *p; p++)
2203218822Sdim    *p = TOUPPER (*p);
2204218822Sdim
2205218822Sdim  if (strncmp (namebuf, newname, namelen))
2206218822Sdim    insert_neon_reg_alias (namebuf, basereg->number, basetype,
2207218822Sdim                           typeinfo.defined != 0 ? &typeinfo : NULL);
2208218822Sdim
2209218822Sdim  /* Insert name in all lowercase.  */
2210218822Sdim  for (p = namebuf; *p; p++)
2211218822Sdim    *p = TOLOWER (*p);
2212218822Sdim
2213218822Sdim  if (strncmp (namebuf, newname, namelen))
2214218822Sdim    insert_neon_reg_alias (namebuf, basereg->number, basetype,
2215218822Sdim                           typeinfo.defined != 0 ? &typeinfo : NULL);
2216218822Sdim
2217218822Sdim  return 1;
221860484Sobrien}
221960484Sobrien
2220218822Sdim/* Should never be called, as .req goes between the alias and the
2221218822Sdim   register name, not at the beginning of the line.  */
2222218822Sdimstatic void
2223218822Sdims_req (int a ATTRIBUTE_UNUSED)
222460484Sobrien{
2225218822Sdim  as_bad (_("invalid syntax for .req directive"));
222660484Sobrien}
222760484Sobrien
2228218822Sdimstatic void
2229218822Sdims_dn (int a ATTRIBUTE_UNUSED)
2230218822Sdim{
2231218822Sdim  as_bad (_("invalid syntax for .dn directive"));
2232218822Sdim}
2233130561Sobrien
2234218822Sdimstatic void
2235218822Sdims_qn (int a ATTRIBUTE_UNUSED)
2236218822Sdim{
2237218822Sdim  as_bad (_("invalid syntax for .qn directive"));
2238218822Sdim}
2239130561Sobrien
2240218822Sdim/* The .unreq directive deletes an alias which was previously defined
2241218822Sdim   by .req.  For example:
2242130561Sobrien
2243218822Sdim       my_alias .req r11
2244218822Sdim       .unreq my_alias	  */
2245130561Sobrien
2246218822Sdimstatic void
2247218822Sdims_unreq (int a ATTRIBUTE_UNUSED)
2248218822Sdim{
2249218822Sdim  char * name;
2250218822Sdim  char saved_char;
2251130561Sobrien
2252218822Sdim  name = input_line_pointer;
2253130561Sobrien
2254218822Sdim  while (*input_line_pointer != 0
2255218822Sdim	 && *input_line_pointer != ' '
2256218822Sdim	 && *input_line_pointer != '\n')
2257218822Sdim    ++input_line_pointer;
2258130561Sobrien
2259218822Sdim  saved_char = *input_line_pointer;
2260218822Sdim  *input_line_pointer = 0;
2261130561Sobrien
2262218822Sdim  if (!*name)
2263218822Sdim    as_bad (_("invalid syntax for .unreq directive"));
2264218822Sdim  else
2265218822Sdim    {
2266218822Sdim      struct reg_entry *reg = hash_find (arm_reg_hsh, name);
2267130561Sobrien
2268218822Sdim      if (!reg)
2269218822Sdim	as_bad (_("unknown register alias '%s'"), name);
2270218822Sdim      else if (reg->builtin)
2271218822Sdim	as_warn (_("ignoring attempt to undefine built-in register '%s'"),
2272218822Sdim		 name);
2273218822Sdim      else
2274218822Sdim	{
2275218822Sdim	  hash_delete (arm_reg_hsh, name);
2276218822Sdim	  free ((char *) reg->name);
2277218822Sdim          if (reg->neon)
2278218822Sdim            free (reg->neon);
2279218822Sdim	  free (reg);
2280218822Sdim	}
2281218822Sdim    }
2282130561Sobrien
2283218822Sdim  *input_line_pointer = saved_char;
2284218822Sdim  demand_empty_rest_of_line ();
2285218822Sdim}
2286130561Sobrien
2287218822Sdim/* Directives: Instruction set selection.  */
2288130561Sobrien
2289218822Sdim#ifdef OBJ_ELF
2290218822Sdim/* This code is to handle mapping symbols as defined in the ARM ELF spec.
2291218822Sdim   (See "Mapping symbols", section 4.5.5, ARM AAELF version 1.0).
2292218822Sdim   Note that previously, $a and $t has type STT_FUNC (BSF_OBJECT flag),
2293218822Sdim   and $d has type STT_OBJECT (BSF_OBJECT flag). Now all three are untyped.  */
2294130561Sobrien
2295130561Sobrienstatic enum mstate mapstate = MAP_UNDEFINED;
2296130561Sobrien
2297218822Sdimvoid
2298130561Sobrienmapping_state (enum mstate state)
2299130561Sobrien{
2300130561Sobrien  symbolS * symbolP;
2301130561Sobrien  const char * symname;
2302130561Sobrien  int type;
2303130561Sobrien
2304130561Sobrien  if (mapstate == state)
2305130561Sobrien    /* The mapping symbol has already been emitted.
2306130561Sobrien       There is nothing else to do.  */
2307130561Sobrien    return;
2308130561Sobrien
2309130561Sobrien  mapstate = state;
2310130561Sobrien
2311130561Sobrien  switch (state)
2312130561Sobrien    {
2313130561Sobrien    case MAP_DATA:
2314130561Sobrien      symname = "$d";
2315218822Sdim      type = BSF_NO_FLAGS;
2316130561Sobrien      break;
2317130561Sobrien    case MAP_ARM:
2318130561Sobrien      symname = "$a";
2319218822Sdim      type = BSF_NO_FLAGS;
2320130561Sobrien      break;
2321130561Sobrien    case MAP_THUMB:
2322130561Sobrien      symname = "$t";
2323218822Sdim      type = BSF_NO_FLAGS;
2324130561Sobrien      break;
2325130561Sobrien    case MAP_UNDEFINED:
2326218822Sdim      return;
2327130561Sobrien    default:
2328130561Sobrien      abort ();
2329130561Sobrien    }
2330130561Sobrien
2331218822Sdim  seg_info (now_seg)->tc_segment_info_data.mapstate = state;
2332130561Sobrien
2333130561Sobrien  symbolP = symbol_new (symname, now_seg, (valueT) frag_now_fix (), frag_now);
2334130561Sobrien  symbol_table_insert (symbolP);
2335130561Sobrien  symbol_get_bfdsym (symbolP)->flags |= type | BSF_LOCAL;
2336218822Sdim
2337130561Sobrien  switch (state)
2338130561Sobrien    {
2339130561Sobrien    case MAP_ARM:
2340130561Sobrien      THUMB_SET_FUNC (symbolP, 0);
2341130561Sobrien      ARM_SET_THUMB (symbolP, 0);
2342130561Sobrien      ARM_SET_INTERWORK (symbolP, support_interwork);
2343130561Sobrien      break;
2344218822Sdim
2345130561Sobrien    case MAP_THUMB:
2346130561Sobrien      THUMB_SET_FUNC (symbolP, 1);
2347130561Sobrien      ARM_SET_THUMB (symbolP, 1);
2348130561Sobrien      ARM_SET_INTERWORK (symbolP, support_interwork);
2349130561Sobrien      break;
2350218822Sdim
2351130561Sobrien    case MAP_DATA:
2352130561Sobrien    default:
2353130561Sobrien      return;
2354130561Sobrien    }
2355130561Sobrien}
2356218822Sdim#else
2357218822Sdim#define mapping_state(x) /* nothing */
2358218822Sdim#endif
2359130561Sobrien
2360218822Sdim/* Find the real, Thumb encoded start of a Thumb function.  */
2361130561Sobrien
2362218822Sdimstatic symbolS *
2363218822Sdimfind_real_start (symbolS * symbolP)
2364130561Sobrien{
2365218822Sdim  char *       real_start;
2366218822Sdim  const char * name = S_GET_NAME (symbolP);
2367218822Sdim  symbolS *    new_target;
2368130561Sobrien
2369218822Sdim  /* This definition must agree with the one in gcc/config/arm/thumb.c.	 */
2370218822Sdim#define STUB_NAME ".real_start_of"
2371130561Sobrien
2372218822Sdim  if (name == NULL)
2373218822Sdim    abort ();
2374130561Sobrien
2375218822Sdim  /* The compiler may generate BL instructions to local labels because
2376218822Sdim     it needs to perform a branch to a far away location. These labels
2377218822Sdim     do not have a corresponding ".real_start_of" label.  We check
2378218822Sdim     both for S_IS_LOCAL and for a leading dot, to give a way to bypass
2379218822Sdim     the ".real_start_of" convention for nonlocal branches.  */
2380218822Sdim  if (S_IS_LOCAL (symbolP) || name[0] == '.')
2381218822Sdim    return symbolP;
2382130561Sobrien
2383218822Sdim  real_start = ACONCAT ((STUB_NAME, name, NULL));
2384218822Sdim  new_target = symbol_find (real_start);
2385130561Sobrien
2386218822Sdim  if (new_target == NULL)
2387218822Sdim    {
2388218822Sdim      as_warn ("Failed to find real start of function: %s\n", name);
2389218822Sdim      new_target = symbolP;
2390218822Sdim    }
2391218822Sdim
2392218822Sdim  return new_target;
239360484Sobrien}
239460484Sobrien
239560484Sobrienstatic void
2396218822Sdimopcode_select (int width)
2397130561Sobrien{
2398218822Sdim  switch (width)
2399218822Sdim    {
2400218822Sdim    case 16:
2401218822Sdim      if (! thumb_mode)
2402218822Sdim	{
2403218822Sdim	  if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v4t))
2404218822Sdim	    as_bad (_("selected processor does not support THUMB opcodes"));
2405130561Sobrien
2406218822Sdim	  thumb_mode = 1;
2407218822Sdim	  /* No need to force the alignment, since we will have been
2408218822Sdim	     coming from ARM mode, which is word-aligned.  */
2409218822Sdim	  record_alignment (now_seg, 1);
2410218822Sdim	}
2411218822Sdim      mapping_state (MAP_THUMB);
2412218822Sdim      break;
2413130561Sobrien
2414218822Sdim    case 32:
2415218822Sdim      if (thumb_mode)
2416130561Sobrien	{
2417218822Sdim	  if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1))
2418218822Sdim	    as_bad (_("selected processor does not support ARM opcodes"));
2419130561Sobrien
2420218822Sdim	  thumb_mode = 0;
2421130561Sobrien
2422218822Sdim	  if (!need_pass_2)
2423218822Sdim	    frag_align (2, 0, 0);
2424130561Sobrien
2425218822Sdim	  record_alignment (now_seg, 1);
2426130561Sobrien	}
2427218822Sdim      mapping_state (MAP_ARM);
2428218822Sdim      break;
2429218822Sdim
2430218822Sdim    default:
2431218822Sdim      as_bad (_("invalid instruction size selected (%d)"), width);
2432130561Sobrien    }
2433130561Sobrien}
2434130561Sobrien
2435130561Sobrienstatic void
2436218822Sdims_arm (int ignore ATTRIBUTE_UNUSED)
243760484Sobrien{
2438218822Sdim  opcode_select (32);
243960484Sobrien  demand_empty_rest_of_line ();
244060484Sobrien}
244160484Sobrien
244260484Sobrienstatic void
2443218822Sdims_thumb (int ignore ATTRIBUTE_UNUSED)
244460484Sobrien{
2445218822Sdim  opcode_select (16);
244660484Sobrien  demand_empty_rest_of_line ();
244760484Sobrien}
244860484Sobrien
244960484Sobrienstatic void
2450218822Sdims_code (int unused ATTRIBUTE_UNUSED)
245160484Sobrien{
2452218822Sdim  int temp;
245360484Sobrien
245460484Sobrien  temp = get_absolute_expression ();
2455218822Sdim  switch (temp)
245660484Sobrien    {
2457218822Sdim    case 16:
2458218822Sdim    case 32:
2459218822Sdim      opcode_select (temp);
2460218822Sdim      break;
246160484Sobrien
2462218822Sdim    default:
2463218822Sdim      as_bad (_("invalid operand to .code directive (%d) (expecting 16 or 32)"), temp);
246460484Sobrien    }
246560484Sobrien}
246660484Sobrien
246760484Sobrienstatic void
2468218822Sdims_force_thumb (int ignore ATTRIBUTE_UNUSED)
246960484Sobrien{
247060484Sobrien  /* If we are not already in thumb mode go into it, EVEN if
247160484Sobrien     the target processor does not support thumb instructions.
247260484Sobrien     This is used by gcc/config/arm/lib1funcs.asm for example
247360484Sobrien     to compile interworking support functions even if the
2474218822Sdim     target processor should not support interworking.	*/
247560484Sobrien  if (! thumb_mode)
247660484Sobrien    {
247760484Sobrien      thumb_mode = 2;
247860484Sobrien      record_alignment (now_seg, 1);
247960484Sobrien    }
248077298Sobrien
248160484Sobrien  demand_empty_rest_of_line ();
248260484Sobrien}
248360484Sobrien
248460484Sobrienstatic void
2485218822Sdims_thumb_func (int ignore ATTRIBUTE_UNUSED)
248660484Sobrien{
2487218822Sdim  s_thumb (0);
248877298Sobrien
248960484Sobrien  /* The following label is the name/address of the start of a Thumb function.
2490218822Sdim     We need to know this for the interworking support.	 */
2491130561Sobrien  label_is_thumb_function_name = TRUE;
249260484Sobrien}
249360484Sobrien
249460484Sobrien/* Perform a .set directive, but also mark the alias as
249560484Sobrien   being a thumb function.  */
249660484Sobrien
249760484Sobrienstatic void
2498218822Sdims_thumb_set (int equiv)
249960484Sobrien{
250060484Sobrien  /* XXX the following is a duplicate of the code for s_set() in read.c
250160484Sobrien     We cannot just call that code as we need to get at the symbol that
250260484Sobrien     is created.  */
2503218822Sdim  char *    name;
2504218822Sdim  char	    delim;
2505218822Sdim  char *    end_name;
2506218822Sdim  symbolS * symbolP;
250760484Sobrien
250877298Sobrien  /* Especial apologies for the random logic:
250977298Sobrien     This just grew, and could be parsed much more simply!
251077298Sobrien     Dean - in haste.  */
2511218822Sdim  name	    = input_line_pointer;
2512218822Sdim  delim	    = get_symbol_end ();
251360484Sobrien  end_name  = input_line_pointer;
251460484Sobrien  *end_name = delim;
251577298Sobrien
251660484Sobrien  if (*input_line_pointer != ',')
251760484Sobrien    {
251860484Sobrien      *end_name = 0;
251989857Sobrien      as_bad (_("expected comma after name \"%s\""), name);
252060484Sobrien      *end_name = delim;
252160484Sobrien      ignore_rest_of_line ();
252260484Sobrien      return;
252360484Sobrien    }
252460484Sobrien
252560484Sobrien  input_line_pointer++;
252660484Sobrien  *end_name = 0;
252760484Sobrien
252860484Sobrien  if (name[0] == '.' && name[1] == '\0')
252960484Sobrien    {
253077298Sobrien      /* XXX - this should not happen to .thumb_set.  */
253160484Sobrien      abort ();
253260484Sobrien    }
253360484Sobrien
253460484Sobrien  if ((symbolP = symbol_find (name)) == NULL
253560484Sobrien      && (symbolP = md_undefined_symbol (name)) == NULL)
253660484Sobrien    {
253760484Sobrien#ifndef NO_LISTING
253860484Sobrien      /* When doing symbol listings, play games with dummy fragments living
253960484Sobrien	 outside the normal fragment chain to record the file and line info
2540218822Sdim	 for this symbol.  */
254160484Sobrien      if (listing & LISTING_SYMBOLS)
254260484Sobrien	{
254360484Sobrien	  extern struct list_info_struct * listing_tail;
2544218822Sdim	  fragS * dummy_frag = xmalloc (sizeof (fragS));
254577298Sobrien
254677298Sobrien	  memset (dummy_frag, 0, sizeof (fragS));
254760484Sobrien	  dummy_frag->fr_type = rs_fill;
254860484Sobrien	  dummy_frag->line = listing_tail;
254960484Sobrien	  symbolP = symbol_new (name, undefined_section, 0, dummy_frag);
255060484Sobrien	  dummy_frag->fr_symbol = symbolP;
255160484Sobrien	}
255260484Sobrien      else
255360484Sobrien#endif
255477298Sobrien	symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag);
255577298Sobrien
255660484Sobrien#ifdef OBJ_COFF
255777298Sobrien      /* "set" symbols are local unless otherwise specified.  */
255860484Sobrien      SF_SET_LOCAL (symbolP);
255977298Sobrien#endif /* OBJ_COFF  */
256077298Sobrien    }				/* Make a new symbol.  */
256160484Sobrien
256260484Sobrien  symbol_table_insert (symbolP);
256360484Sobrien
256460484Sobrien  * end_name = delim;
256560484Sobrien
256660484Sobrien  if (equiv
256760484Sobrien      && S_IS_DEFINED (symbolP)
256860484Sobrien      && S_GET_SEGMENT (symbolP) != reg_section)
256960484Sobrien    as_bad (_("symbol `%s' already defined"), S_GET_NAME (symbolP));
257060484Sobrien
257160484Sobrien  pseudo_set (symbolP);
257277298Sobrien
257360484Sobrien  demand_empty_rest_of_line ();
257460484Sobrien
2575218822Sdim  /* XXX Now we come to the Thumb specific bit of code.	 */
257677298Sobrien
257760484Sobrien  THUMB_SET_FUNC (symbolP, 1);
257860484Sobrien  ARM_SET_THUMB (symbolP, 1);
257960484Sobrien#if defined OBJ_ELF || defined OBJ_COFF
258060484Sobrien  ARM_SET_INTERWORK (symbolP, support_interwork);
258160484Sobrien#endif
258260484Sobrien}
258360484Sobrien
2584218822Sdim/* Directives: Mode selection.  */
2585218822Sdim
2586218822Sdim/* .syntax [unified|divided] - choose the new unified syntax
2587218822Sdim   (same for Arm and Thumb encoding, modulo slight differences in what
2588218822Sdim   can be represented) or the old divergent syntax for each mode.  */
258960484Sobrienstatic void
2590218822Sdims_syntax (int unused ATTRIBUTE_UNUSED)
259160484Sobrien{
2592218822Sdim  char *name, delim;
259377298Sobrien
2594218822Sdim  name = input_line_pointer;
2595218822Sdim  delim = get_symbol_end ();
259660484Sobrien
2597218822Sdim  if (!strcasecmp (name, "unified"))
2598218822Sdim    unified_syntax = TRUE;
2599218822Sdim  else if (!strcasecmp (name, "divided"))
2600218822Sdim    unified_syntax = FALSE;
2601218822Sdim  else
2602218822Sdim    {
2603218822Sdim      as_bad (_("unrecognized syntax mode \"%s\""), name);
2604218822Sdim      return;
260560484Sobrien    }
2606218822Sdim  *input_line_pointer = delim;
260760484Sobrien  demand_empty_rest_of_line ();
260860484Sobrien}
260960484Sobrien
2610218822Sdim/* Directives: sectioning and alignment.  */
261160484Sobrien
2612218822Sdim/* Same as s_align_ptwo but align 0 => align 2.	 */
2613218822Sdim
261460484Sobrienstatic void
2615218822Sdims_align (int unused ATTRIBUTE_UNUSED)
261660484Sobrien{
2617218822Sdim  int temp;
2618218822Sdim  bfd_boolean fill_p;
2619218822Sdim  long temp_fill;
2620218822Sdim  long max_alignment = 15;
262160484Sobrien
262260484Sobrien  temp = get_absolute_expression ();
2623218822Sdim  if (temp > max_alignment)
2624218822Sdim    as_bad (_("alignment too large: %d assumed"), temp = max_alignment);
2625218822Sdim  else if (temp < 0)
262660484Sobrien    {
2627218822Sdim      as_bad (_("alignment negative. 0 assumed."));
2628218822Sdim      temp = 0;
2629218822Sdim    }
263060484Sobrien
2631218822Sdim  if (*input_line_pointer == ',')
2632218822Sdim    {
2633218822Sdim      input_line_pointer++;
2634218822Sdim      temp_fill = get_absolute_expression ();
2635218822Sdim      fill_p = TRUE;
263660484Sobrien    }
2637218822Sdim  else
2638218822Sdim    {
2639218822Sdim      fill_p = FALSE;
2640218822Sdim      temp_fill = 0;
2641218822Sdim    }
264260484Sobrien
2643218822Sdim  if (!temp)
2644218822Sdim    temp = 2;
264560484Sobrien
2646218822Sdim  /* Only make a frag if we HAVE to.  */
2647218822Sdim  if (temp && !need_pass_2)
264860484Sobrien    {
2649218822Sdim      if (!fill_p && subseg_text_p (now_seg))
2650218822Sdim	frag_align_code (temp, 0);
2651218822Sdim      else
2652218822Sdim	frag_align (temp, (int) temp_fill, 0);
265360484Sobrien    }
2654218822Sdim  demand_empty_rest_of_line ();
265560484Sobrien
2656218822Sdim  record_alignment (now_seg, temp);
2657218822Sdim}
265860484Sobrien
2659218822Sdimstatic void
2660218822Sdims_bss (int ignore ATTRIBUTE_UNUSED)
2661218822Sdim{
2662218822Sdim  /* We don't support putting frags in the BSS segment, we fake it by
2663218822Sdim     marking in_bss, then looking at s_skip for clues.	*/
2664218822Sdim  subseg_set (bss_section, 0);
2665218822Sdim  demand_empty_rest_of_line ();
2666218822Sdim  mapping_state (MAP_DATA);
266760484Sobrien}
266860484Sobrien
2669218822Sdimstatic void
2670218822Sdims_even (int ignore ATTRIBUTE_UNUSED)
267160484Sobrien{
2672218822Sdim  /* Never make frag if expect extra pass.  */
2673218822Sdim  if (!need_pass_2)
2674218822Sdim    frag_align (1, 0, 0);
267560484Sobrien
2676218822Sdim  record_alignment (now_seg, 1);
267760484Sobrien
2678218822Sdim  demand_empty_rest_of_line ();
267960484Sobrien}
268060484Sobrien
2681218822Sdim/* Directives: Literal pools.  */
2682130561Sobrien
2683218822Sdimstatic literal_pool *
2684218822Sdimfind_literal_pool (void)
2685130561Sobrien{
2686218822Sdim  literal_pool * pool;
2687130561Sobrien
2688218822Sdim  for (pool = list_of_pools; pool != NULL; pool = pool->next)
2689130561Sobrien    {
2690218822Sdim      if (pool->section == now_seg
2691218822Sdim	  && pool->sub_section == now_subseg)
2692218822Sdim	break;
2693130561Sobrien    }
2694130561Sobrien
2695218822Sdim  return pool;
2696130561Sobrien}
2697130561Sobrien
2698218822Sdimstatic literal_pool *
2699218822Sdimfind_or_make_literal_pool (void)
270061843Sobrien{
2701218822Sdim  /* Next literal pool ID number.  */
2702218822Sdim  static unsigned int latest_pool_num = 1;
2703218822Sdim  literal_pool *      pool;
270461843Sobrien
2705218822Sdim  pool = find_literal_pool ();
270661843Sobrien
2707218822Sdim  if (pool == NULL)
270861843Sobrien    {
2709218822Sdim      /* Create a new pool.  */
2710218822Sdim      pool = xmalloc (sizeof (* pool));
2711218822Sdim      if (! pool)
2712218822Sdim	return NULL;
271361843Sobrien
2714218822Sdim      pool->next_free_entry = 0;
2715218822Sdim      pool->section	    = now_seg;
2716218822Sdim      pool->sub_section	    = now_subseg;
2717218822Sdim      pool->next	    = list_of_pools;
2718218822Sdim      pool->symbol	    = NULL;
271961843Sobrien
2720218822Sdim      /* Add it to the list.  */
2721218822Sdim      list_of_pools = pool;
2722218822Sdim    }
272377298Sobrien
2724218822Sdim  /* New pools, and emptied pools, will have a NULL symbol.  */
2725218822Sdim  if (pool->symbol == NULL)
2726218822Sdim    {
2727218822Sdim      pool->symbol = symbol_create (FAKE_LABEL_NAME, undefined_section,
2728218822Sdim				    (valueT) 0, &zero_address_frag);
2729218822Sdim      pool->id = latest_pool_num ++;
2730218822Sdim    }
273161843Sobrien
2732218822Sdim  /* Done.  */
2733218822Sdim  return pool;
273461843Sobrien}
273561843Sobrien
2736218822Sdim/* Add the literal in the global 'inst'
2737218822Sdim   structure to the relevent literal pool.  */
273877298Sobrien
273960484Sobrienstatic int
2740218822Sdimadd_to_lit_pool (void)
274160484Sobrien{
2742218822Sdim  literal_pool * pool;
2743218822Sdim  unsigned int entry;
274477298Sobrien
2745218822Sdim  pool = find_or_make_literal_pool ();
274661843Sobrien
2747218822Sdim  /* Check if this literal value is already in the pool.  */
2748218822Sdim  for (entry = 0; entry < pool->next_free_entry; entry ++)
274960484Sobrien    {
2750218822Sdim      if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
2751218822Sdim	  && (inst.reloc.exp.X_op == O_constant)
2752218822Sdim	  && (pool->literals[entry].X_add_number
2753218822Sdim	      == inst.reloc.exp.X_add_number)
2754218822Sdim	  && (pool->literals[entry].X_unsigned
2755218822Sdim	      == inst.reloc.exp.X_unsigned))
2756218822Sdim	break;
275761843Sobrien
2758218822Sdim      if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
2759218822Sdim	  && (inst.reloc.exp.X_op == O_symbol)
2760218822Sdim	  && (pool->literals[entry].X_add_number
2761218822Sdim	      == inst.reloc.exp.X_add_number)
2762218822Sdim	  && (pool->literals[entry].X_add_symbol
2763218822Sdim	      == inst.reloc.exp.X_add_symbol)
2764218822Sdim	  && (pool->literals[entry].X_op_symbol
2765218822Sdim	      == inst.reloc.exp.X_op_symbol))
2766218822Sdim	break;
276760484Sobrien    }
276860484Sobrien
2769218822Sdim  /* Do we need to create a new entry?	*/
2770218822Sdim  if (entry == pool->next_free_entry)
277189857Sobrien    {
2772218822Sdim      if (entry >= MAX_LITERAL_POOL_SIZE)
277360484Sobrien	{
2774218822Sdim	  inst.error = _("literal pool overflow");
277589857Sobrien	  return FAIL;
277689857Sobrien	}
2777218822Sdim
2778218822Sdim      pool->literals[entry] = inst.reloc.exp;
2779218822Sdim      pool->next_free_entry += 1;
278060484Sobrien    }
278160484Sobrien
2782218822Sdim  inst.reloc.exp.X_op	      = O_symbol;
2783218822Sdim  inst.reloc.exp.X_add_number = ((int) entry) * 4;
2784218822Sdim  inst.reloc.exp.X_add_symbol = pool->symbol;
2785218822Sdim
278660484Sobrien  return SUCCESS;
278760484Sobrien}
278860484Sobrien
2789218822Sdim/* Can't use symbol_new here, so have to create a symbol and then at
2790218822Sdim   a later date assign it a value. Thats what these functions do.  */
2791218822Sdim
2792218822Sdimstatic void
2793218822Sdimsymbol_locate (symbolS *    symbolP,
2794218822Sdim	       const char * name,	/* It is copied, the caller can modify.	 */
2795218822Sdim	       segT	    segment,	/* Segment identifier (SEG_<something>).  */
2796218822Sdim	       valueT	    valu,	/* Symbol value.  */
2797218822Sdim	       fragS *	    frag)	/* Associated fragment.	 */
279860484Sobrien{
2799218822Sdim  unsigned int name_length;
2800218822Sdim  char * preserved_copy_of_name;
280160484Sobrien
2802218822Sdim  name_length = strlen (name) + 1;   /* +1 for \0.  */
2803218822Sdim  obstack_grow (&notes, name, name_length);
2804218822Sdim  preserved_copy_of_name = obstack_finish (&notes);
280560484Sobrien
2806218822Sdim#ifdef tc_canonicalize_symbol_name
2807218822Sdim  preserved_copy_of_name =
2808218822Sdim    tc_canonicalize_symbol_name (preserved_copy_of_name);
2809218822Sdim#endif
281060484Sobrien
2811218822Sdim  S_SET_NAME (symbolP, preserved_copy_of_name);
281260484Sobrien
2813218822Sdim  S_SET_SEGMENT (symbolP, segment);
2814218822Sdim  S_SET_VALUE (symbolP, valu);
2815218822Sdim  symbol_clear_list_pointers (symbolP);
281660484Sobrien
2817218822Sdim  symbol_set_frag (symbolP, frag);
281860484Sobrien
2819218822Sdim  /* Link to end of symbol chain.  */
2820218822Sdim  {
2821218822Sdim    extern int symbol_table_frozen;
282260484Sobrien
2823218822Sdim    if (symbol_table_frozen)
2824218822Sdim      abort ();
2825218822Sdim  }
282660484Sobrien
2827218822Sdim  symbol_append (symbolP, symbol_lastP, & symbol_rootP, & symbol_lastP);
282860484Sobrien
2829218822Sdim  obj_symbol_new_hook (symbolP);
283060484Sobrien
2831218822Sdim#ifdef tc_symbol_new_hook
2832218822Sdim  tc_symbol_new_hook (symbolP);
2833218822Sdim#endif
283460484Sobrien
2835218822Sdim#ifdef DEBUG_SYMS
2836218822Sdim  verify_symbol_chain (symbol_rootP, symbol_lastP);
2837218822Sdim#endif /* DEBUG_SYMS  */
2838218822Sdim}
283960484Sobrien
284060484Sobrien
2841218822Sdimstatic void
2842218822Sdims_ltorg (int ignored ATTRIBUTE_UNUSED)
284360484Sobrien{
2844218822Sdim  unsigned int entry;
2845218822Sdim  literal_pool * pool;
2846218822Sdim  char sym_name[20];
284760484Sobrien
2848218822Sdim  pool = find_literal_pool ();
2849218822Sdim  if (pool == NULL
2850218822Sdim      || pool->symbol == NULL
2851218822Sdim      || pool->next_free_entry == 0)
2852218822Sdim    return;
285360484Sobrien
2854218822Sdim  mapping_state (MAP_DATA);
285560484Sobrien
2856218822Sdim  /* Align pool as you have word accesses.
2857218822Sdim     Only make a frag if we have to.  */
2858218822Sdim  if (!need_pass_2)
2859218822Sdim    frag_align (2, 0, 0);
286077298Sobrien
2861218822Sdim  record_alignment (now_seg, 2);
286277298Sobrien
2863218822Sdim  sprintf (sym_name, "$$lit_\002%x", pool->id);
286477298Sobrien
2865218822Sdim  symbol_locate (pool->symbol, sym_name, now_seg,
2866218822Sdim		 (valueT) frag_now_fix (), frag_now);
2867218822Sdim  symbol_table_insert (pool->symbol);
286860484Sobrien
2869218822Sdim  ARM_SET_THUMB (pool->symbol, thumb_mode);
287060484Sobrien
2871218822Sdim#if defined OBJ_COFF || defined OBJ_ELF
2872218822Sdim  ARM_SET_INTERWORK (pool->symbol, support_interwork);
2873218822Sdim#endif
287460484Sobrien
2875218822Sdim  for (entry = 0; entry < pool->next_free_entry; entry ++)
2876218822Sdim    /* First output the expression in the instruction to the pool.  */
2877218822Sdim    emit_expr (&(pool->literals[entry]), 4); /* .word  */
287860484Sobrien
2879218822Sdim  /* Mark the pool as empty.  */
2880218822Sdim  pool->next_free_entry = 0;
2881218822Sdim  pool->symbol = NULL;
288260484Sobrien}
288360484Sobrien
2884218822Sdim#ifdef OBJ_ELF
2885218822Sdim/* Forward declarations for functions below, in the MD interface
2886218822Sdim   section.  */
2887218822Sdimstatic void fix_new_arm (fragS *, int, short, expressionS *, int, int);
2888218822Sdimstatic valueT create_unwind_entry (int);
2889218822Sdimstatic void start_unwind_section (const segT, int);
2890218822Sdimstatic void add_unwind_opcode (valueT, int);
2891218822Sdimstatic void flush_pending_unwind (void);
2892218822Sdim
2893218822Sdim/* Directives: Data.  */
2894218822Sdim
2895218822Sdimstatic void
2896218822Sdims_arm_elf_cons (int nbytes)
289760484Sobrien{
2898218822Sdim  expressionS exp;
289960484Sobrien
2900218822Sdim#ifdef md_flush_pending_output
2901218822Sdim  md_flush_pending_output ();
2902218822Sdim#endif
2903218822Sdim
2904218822Sdim  if (is_it_end_of_statement ())
290560484Sobrien    {
2906218822Sdim      demand_empty_rest_of_line ();
2907218822Sdim      return;
2908218822Sdim    }
290960484Sobrien
2910218822Sdim#ifdef md_cons_align
2911218822Sdim  md_cons_align (nbytes);
2912218822Sdim#endif
291360484Sobrien
2914218822Sdim  mapping_state (MAP_DATA);
2915218822Sdim  do
2916218822Sdim    {
2917218822Sdim      int reloc;
2918218822Sdim      char *base = input_line_pointer;
291960484Sobrien
2920218822Sdim      expression (& exp);
292160484Sobrien
2922218822Sdim      if (exp.X_op != O_symbol)
2923218822Sdim	emit_expr (&exp, (unsigned int) nbytes);
2924218822Sdim      else
292560484Sobrien	{
2926218822Sdim	  char *before_reloc = input_line_pointer;
2927218822Sdim	  reloc = parse_reloc (&input_line_pointer);
2928218822Sdim	  if (reloc == -1)
292960484Sobrien	    {
2930218822Sdim	      as_bad (_("unrecognized relocation suffix"));
2931218822Sdim	      ignore_rest_of_line ();
2932218822Sdim	      return;
2933130561Sobrien	    }
2934218822Sdim	  else if (reloc == BFD_RELOC_UNUSED)
2935218822Sdim	    emit_expr (&exp, (unsigned int) nbytes);
2936218822Sdim	  else
2937130561Sobrien	    {
2938218822Sdim	      reloc_howto_type *howto = bfd_reloc_type_lookup (stdoutput, reloc);
2939218822Sdim	      int size = bfd_get_reloc_size (howto);
2940130561Sobrien
2941218822Sdim	      if (reloc == BFD_RELOC_ARM_PLT32)
294260484Sobrien		{
2943218822Sdim		  as_bad (_("(plt) is only valid on branch targets"));
2944218822Sdim		  reloc = BFD_RELOC_UNUSED;
2945218822Sdim		  size = 0;
2946218822Sdim		}
2947130561Sobrien
2948218822Sdim	      if (size > nbytes)
2949218822Sdim		as_bad (_("%s relocations do not fit in %d bytes"),
2950218822Sdim			howto->name, nbytes);
2951130561Sobrien	      else
2952130561Sobrien		{
2953218822Sdim		  /* We've parsed an expression stopping at O_symbol.
2954218822Sdim		     But there may be more expression left now that we
2955218822Sdim		     have parsed the relocation marker.  Parse it again.
2956218822Sdim		     XXX Surely there is a cleaner way to do this.  */
2957218822Sdim		  char *p = input_line_pointer;
2958218822Sdim		  int offset;
2959218822Sdim		  char *save_buf = alloca (input_line_pointer - base);
2960218822Sdim		  memcpy (save_buf, base, input_line_pointer - base);
2961218822Sdim		  memmove (base + (input_line_pointer - before_reloc),
2962218822Sdim			   base, before_reloc - base);
2963130561Sobrien
2964218822Sdim		  input_line_pointer = base + (input_line_pointer-before_reloc);
2965218822Sdim		  expression (&exp);
2966218822Sdim		  memcpy (base, save_buf, p - base);
2967130561Sobrien
2968218822Sdim		  offset = nbytes - size;
2969218822Sdim		  p = frag_more ((int) nbytes);
2970218822Sdim		  fix_new_exp (frag_now, p - frag_now->fr_literal + offset,
2971218822Sdim			       size, &exp, 0, reloc);
2972130561Sobrien		}
297360484Sobrien	    }
297460484Sobrien	}
2975218822Sdim    }
2976218822Sdim  while (*input_line_pointer++ == ',');
297760484Sobrien
2978218822Sdim  /* Put terminator back into stream.  */
2979218822Sdim  input_line_pointer --;
2980218822Sdim  demand_empty_rest_of_line ();
2981218822Sdim}
298260484Sobrien
298377298Sobrien
2984218822Sdim/* Parse a .rel31 directive.  */
298560484Sobrien
2986218822Sdimstatic void
2987218822Sdims_arm_rel31 (int ignored ATTRIBUTE_UNUSED)
2988218822Sdim{
2989218822Sdim  expressionS exp;
2990218822Sdim  char *p;
2991218822Sdim  valueT highbit;
299260484Sobrien
2993218822Sdim  highbit = 0;
2994218822Sdim  if (*input_line_pointer == '1')
2995218822Sdim    highbit = 0x80000000;
2996218822Sdim  else if (*input_line_pointer != '0')
2997218822Sdim    as_bad (_("expected 0 or 1"));
299860484Sobrien
2999218822Sdim  input_line_pointer++;
3000218822Sdim  if (*input_line_pointer != ',')
3001218822Sdim    as_bad (_("missing comma"));
3002218822Sdim  input_line_pointer++;
300360484Sobrien
3004218822Sdim#ifdef md_flush_pending_output
3005218822Sdim  md_flush_pending_output ();
3006218822Sdim#endif
300760484Sobrien
3008218822Sdim#ifdef md_cons_align
3009218822Sdim  md_cons_align (4);
3010218822Sdim#endif
301160484Sobrien
3012218822Sdim  mapping_state (MAP_DATA);
301360484Sobrien
3014218822Sdim  expression (&exp);
301560484Sobrien
3016218822Sdim  p = frag_more (4);
3017218822Sdim  md_number_to_chars (p, highbit, 4);
3018218822Sdim  fix_new_arm (frag_now, p - frag_now->fr_literal, 4, &exp, 1,
3019218822Sdim	       BFD_RELOC_ARM_PREL31);
3020130561Sobrien
3021218822Sdim  demand_empty_rest_of_line ();
3022218822Sdim}
3023130561Sobrien
3024218822Sdim/* Directives: AEABI stack-unwind tables.  */
3025130561Sobrien
3026218822Sdim/* Parse an unwind_fnstart directive.  Simply records the current location.  */
3027130561Sobrien
3028218822Sdimstatic void
3029218822Sdims_arm_unwind_fnstart (int ignored ATTRIBUTE_UNUSED)
3030218822Sdim{
3031218822Sdim  demand_empty_rest_of_line ();
3032218822Sdim  /* Mark the start of the function.  */
3033218822Sdim  unwind.proc_start = expr_build_dot ();
3034130561Sobrien
3035218822Sdim  /* Reset the rest of the unwind info.	 */
3036218822Sdim  unwind.opcode_count = 0;
3037218822Sdim  unwind.table_entry = NULL;
3038218822Sdim  unwind.personality_routine = NULL;
3039218822Sdim  unwind.personality_index = -1;
3040218822Sdim  unwind.frame_size = 0;
3041218822Sdim  unwind.fp_offset = 0;
3042218822Sdim  unwind.fp_reg = 13;
3043218822Sdim  unwind.fp_used = 0;
3044218822Sdim  unwind.sp_restored = 0;
3045130561Sobrien}
3046130561Sobrien
3047130561Sobrien
3048218822Sdim/* Parse a handlerdata directive.  Creates the exception handling table entry
3049218822Sdim   for the function.  */
3050130561Sobrien
3051218822Sdimstatic void
3052218822Sdims_arm_unwind_handlerdata (int ignored ATTRIBUTE_UNUSED)
3053218822Sdim{
3054218822Sdim  demand_empty_rest_of_line ();
3055218822Sdim  if (unwind.table_entry)
3056218822Sdim    as_bad (_("dupicate .handlerdata directive"));
3057130561Sobrien
3058218822Sdim  create_unwind_entry (1);
3059218822Sdim}
3060130561Sobrien
3061218822Sdim/* Parse an unwind_fnend directive.  Generates the index table entry.  */
3062130561Sobrien
3063218822Sdimstatic void
3064218822Sdims_arm_unwind_fnend (int ignored ATTRIBUTE_UNUSED)
3065218822Sdim{
3066218822Sdim  long where;
3067218822Sdim  char *ptr;
3068218822Sdim  valueT val;
3069130561Sobrien
3070218822Sdim  demand_empty_rest_of_line ();
3071130561Sobrien
3072218822Sdim  /* Add eh table entry.  */
3073218822Sdim  if (unwind.table_entry == NULL)
3074218822Sdim    val = create_unwind_entry (0);
3075218822Sdim  else
3076218822Sdim    val = 0;
3077130561Sobrien
3078218822Sdim  /* Add index table entry.  This is two words.	 */
3079218822Sdim  start_unwind_section (unwind.saved_seg, 1);
3080218822Sdim  frag_align (2, 0, 0);
3081218822Sdim  record_alignment (now_seg, 2);
3082130561Sobrien
3083218822Sdim  ptr = frag_more (8);
3084247386Sandrew  memset(ptr, 0, 8);
3085218822Sdim  where = frag_now_fix () - 8;
3086130561Sobrien
3087218822Sdim  /* Self relative offset of the function start.  */
3088218822Sdim  fix_new (frag_now, where, 4, unwind.proc_start, 0, 1,
3089218822Sdim	   BFD_RELOC_ARM_PREL31);
3090130561Sobrien
3091218822Sdim  /* Indicate dependency on EHABI-defined personality routines to the
3092218822Sdim     linker, if it hasn't been done already.  */
3093218822Sdim  if (unwind.personality_index >= 0 && unwind.personality_index < 3
3094218822Sdim      && !(marked_pr_dependency & (1 << unwind.personality_index)))
3095218822Sdim    {
3096218822Sdim      static const char *const name[] = {
3097218822Sdim	"__aeabi_unwind_cpp_pr0",
3098218822Sdim	"__aeabi_unwind_cpp_pr1",
3099218822Sdim	"__aeabi_unwind_cpp_pr2"
3100218822Sdim      };
3101218822Sdim      symbolS *pr = symbol_find_or_make (name[unwind.personality_index]);
3102218822Sdim      fix_new (frag_now, where, 0, pr, 0, 1, BFD_RELOC_NONE);
3103218822Sdim      marked_pr_dependency |= 1 << unwind.personality_index;
3104218822Sdim      seg_info (now_seg)->tc_segment_info_data.marked_pr_dependency
3105218822Sdim	= marked_pr_dependency;
3106218822Sdim    }
3107130561Sobrien
3108218822Sdim  if (val)
3109218822Sdim    /* Inline exception table entry.  */
3110218822Sdim    md_number_to_chars (ptr + 4, val, 4);
3111130561Sobrien  else
3112218822Sdim    /* Self relative offset of the table entry.	 */
3113218822Sdim    fix_new (frag_now, where + 4, 4, unwind.table_entry, 0, 1,
3114218822Sdim	     BFD_RELOC_ARM_PREL31);
3115130561Sobrien
3116218822Sdim  /* Restore the original section.  */
3117218822Sdim  subseg_set (unwind.saved_seg, unwind.saved_subseg);
3118130561Sobrien}
3119130561Sobrien
3120218822Sdim
3121218822Sdim/* Parse an unwind_cantunwind directive.  */
3122218822Sdim
312360484Sobrienstatic void
3124218822Sdims_arm_unwind_cantunwind (int ignored ATTRIBUTE_UNUSED)
312560484Sobrien{
3126218822Sdim  demand_empty_rest_of_line ();
3127218822Sdim  if (unwind.personality_routine || unwind.personality_index != -1)
3128218822Sdim    as_bad (_("personality routine specified for cantunwind frame"));
3129218822Sdim
3130218822Sdim  unwind.personality_index = -2;
313160484Sobrien}
313260484Sobrien
3133218822Sdim
3134218822Sdim/* Parse a personalityindex directive.	*/
3135218822Sdim
313660484Sobrienstatic void
3137218822Sdims_arm_unwind_personalityindex (int ignored ATTRIBUTE_UNUSED)
313860484Sobrien{
3139218822Sdim  expressionS exp;
314077298Sobrien
3141218822Sdim  if (unwind.personality_routine || unwind.personality_index != -1)
3142218822Sdim    as_bad (_("duplicate .personalityindex directive"));
314360484Sobrien
3144218822Sdim  expression (&exp);
314560484Sobrien
3146218822Sdim  if (exp.X_op != O_constant
3147218822Sdim      || exp.X_add_number < 0 || exp.X_add_number > 15)
314860484Sobrien    {
3149218822Sdim      as_bad (_("bad personality routine number"));
3150218822Sdim      ignore_rest_of_line ();
315160484Sobrien      return;
315260484Sobrien    }
315360484Sobrien
3154218822Sdim  unwind.personality_index = exp.X_add_number;
315561843Sobrien
3156218822Sdim  demand_empty_rest_of_line ();
3157218822Sdim}
315877298Sobrien
315961843Sobrien
3160218822Sdim/* Parse a personality directive.  */
316177298Sobrien
3162218822Sdimstatic void
3163218822Sdims_arm_unwind_personality (int ignored ATTRIBUTE_UNUSED)
3164218822Sdim{
3165218822Sdim  char *name, *p, c;
3166218822Sdim
3167218822Sdim  if (unwind.personality_routine || unwind.personality_index != -1)
3168218822Sdim    as_bad (_("duplicate .personality directive"));
3169218822Sdim
3170218822Sdim  name = input_line_pointer;
3171218822Sdim  c = get_symbol_end ();
3172218822Sdim  p = input_line_pointer;
3173218822Sdim  unwind.personality_routine = symbol_find_or_make (name);
3174218822Sdim  *p = c;
3175218822Sdim  demand_empty_rest_of_line ();
317660484Sobrien}
317760484Sobrien
317877298Sobrien
3179218822Sdim/* Parse a directive saving core registers.  */
3180218822Sdim
318160484Sobrienstatic void
3182218822Sdims_arm_unwind_save_core (void)
318360484Sobrien{
3184218822Sdim  valueT op;
3185218822Sdim  long range;
3186218822Sdim  int n;
318760484Sobrien
3188218822Sdim  range = parse_reg_list (&input_line_pointer);
3189218822Sdim  if (range == FAIL)
319061843Sobrien    {
3191218822Sdim      as_bad (_("expected register list"));
3192218822Sdim      ignore_rest_of_line ();
319361843Sobrien      return;
319461843Sobrien    }
319561843Sobrien
3196218822Sdim  demand_empty_rest_of_line ();
319760484Sobrien
3198218822Sdim  /* Turn .unwind_movsp ip followed by .unwind_save {..., ip, ...}
3199218822Sdim     into .unwind_save {..., sp...}.  We aren't bothered about the value of
3200218822Sdim     ip because it is clobbered by calls.  */
3201218822Sdim  if (unwind.sp_restored && unwind.fp_reg == 12
3202218822Sdim      && (range & 0x3000) == 0x1000)
320360484Sobrien    {
3204218822Sdim      unwind.opcode_count--;
3205218822Sdim      unwind.sp_restored = 0;
3206218822Sdim      range = (range | 0x2000) & ~0x1000;
3207218822Sdim      unwind.pending_offset = 0;
320861843Sobrien    }
320960484Sobrien
3210218822Sdim  /* Pop r4-r15.  */
3211218822Sdim  if (range & 0xfff0)
321261843Sobrien    {
3213218822Sdim      /* See if we can use the short opcodes.  These pop a block of up to 8
3214218822Sdim	 registers starting with r4, plus maybe r14.  */
3215218822Sdim      for (n = 0; n < 8; n++)
3216218822Sdim	{
3217218822Sdim	  /* Break at the first non-saved register.	 */
3218218822Sdim	  if ((range & (1 << (n + 4))) == 0)
3219218822Sdim	    break;
3220218822Sdim	}
3221218822Sdim      /* See if there are any other bits set.  */
3222218822Sdim      if (n == 0 || (range & (0xfff0 << n) & 0xbff0) != 0)
3223218822Sdim	{
3224218822Sdim	  /* Use the long form.  */
3225218822Sdim	  op = 0x8000 | ((range >> 4) & 0xfff);
3226218822Sdim	  add_unwind_opcode (op, 2);
3227218822Sdim	}
3228218822Sdim      else
3229218822Sdim	{
3230218822Sdim	  /* Use the short form.  */
3231218822Sdim	  if (range & 0x4000)
3232218822Sdim	    op = 0xa8; /* Pop r14.	*/
3233218822Sdim	  else
3234218822Sdim	    op = 0xa0; /* Do not pop r14.  */
3235218822Sdim	  op |= (n - 1);
3236218822Sdim	  add_unwind_opcode (op, 1);
3237218822Sdim	}
323860484Sobrien    }
323961843Sobrien
3240218822Sdim  /* Pop r0-r3.	 */
3241218822Sdim  if (range & 0xf)
324261843Sobrien    {
3243218822Sdim      op = 0xb100 | (range & 0xf);
3244218822Sdim      add_unwind_opcode (op, 2);
324561843Sobrien    }
324677298Sobrien
3247218822Sdim  /* Record the number of bytes pushed.	 */
3248218822Sdim  for (n = 0; n < 16; n++)
324961843Sobrien    {
3250218822Sdim      if (range & (1 << n))
3251218822Sdim	unwind.frame_size += 4;
325261843Sobrien    }
3253218822Sdim}
325477298Sobrien
325577298Sobrien
3256218822Sdim/* Parse a directive saving FPA registers.  */
325777298Sobrien
325860484Sobrienstatic void
3259218822Sdims_arm_unwind_save_fpa (int reg)
326060484Sobrien{
3261218822Sdim  expressionS exp;
3262218822Sdim  int num_regs;
3263218822Sdim  valueT op;
326460484Sobrien
3265218822Sdim  /* Get Number of registers to transfer.  */
3266218822Sdim  if (skip_past_comma (&input_line_pointer) != FAIL)
3267218822Sdim    expression (&exp);
3268218822Sdim  else
3269218822Sdim    exp.X_op = O_illegal;
327060484Sobrien
3271218822Sdim  if (exp.X_op != O_constant)
327260484Sobrien    {
3273218822Sdim      as_bad (_("expected , <constant>"));
3274218822Sdim      ignore_rest_of_line ();
327560484Sobrien      return;
327660484Sobrien    }
327760484Sobrien
3278218822Sdim  num_regs = exp.X_add_number;
327960484Sobrien
3280218822Sdim  if (num_regs < 1 || num_regs > 4)
328160484Sobrien    {
3282218822Sdim      as_bad (_("number of registers must be in the range [1:4]"));
3283218822Sdim      ignore_rest_of_line ();
328460484Sobrien      return;
328560484Sobrien    }
328660484Sobrien
3287218822Sdim  demand_empty_rest_of_line ();
328860484Sobrien
3289218822Sdim  if (reg == 4)
329060484Sobrien    {
3291218822Sdim      /* Short form.  */
3292218822Sdim      op = 0xb4 | (num_regs - 1);
3293218822Sdim      add_unwind_opcode (op, 1);
329460484Sobrien    }
3295218822Sdim  else
329660484Sobrien    {
3297218822Sdim      /* Long form.  */
3298218822Sdim      op = 0xc800 | (reg << 4) | (num_regs - 1);
3299218822Sdim      add_unwind_opcode (op, 2);
330060484Sobrien    }
3301218822Sdim  unwind.frame_size += num_regs * 12;
330260484Sobrien}
330360484Sobrien
3304218822Sdim
3305218822Sdim/* Parse a directive saving VFP registers for ARMv6 and above.  */
3306218822Sdim
330760484Sobrienstatic void
3308218822Sdims_arm_unwind_save_vfp_armv6 (void)
330960484Sobrien{
3310218822Sdim  int count;
3311218822Sdim  unsigned int start;
3312218822Sdim  valueT op;
3313218822Sdim  int num_vfpv3_regs = 0;
3314218822Sdim  int num_regs_below_16;
331577298Sobrien
3316218822Sdim  count = parse_vfp_reg_list (&input_line_pointer, &start, REGLIST_VFP_D);
3317218822Sdim  if (count == FAIL)
331860484Sobrien    {
3319218822Sdim      as_bad (_("expected register list"));
3320218822Sdim      ignore_rest_of_line ();
332160484Sobrien      return;
332260484Sobrien    }
332360484Sobrien
3324218822Sdim  demand_empty_rest_of_line ();
332560484Sobrien
3326218822Sdim  /* We always generate FSTMD/FLDMD-style unwinding opcodes (rather
3327218822Sdim     than FSTMX/FLDMX-style ones).  */
332860484Sobrien
3329218822Sdim  /* Generate opcode for (VFPv3) registers numbered in the range 16 .. 31.  */
3330218822Sdim  if (start >= 16)
3331218822Sdim    num_vfpv3_regs = count;
3332218822Sdim  else if (start + count > 16)
3333218822Sdim    num_vfpv3_regs = start + count - 16;
333460484Sobrien
3335218822Sdim  if (num_vfpv3_regs > 0)
333660484Sobrien    {
3337218822Sdim      int start_offset = start > 16 ? start - 16 : 0;
3338218822Sdim      op = 0xc800 | (start_offset << 4) | (num_vfpv3_regs - 1);
3339218822Sdim      add_unwind_opcode (op, 2);
334060484Sobrien    }
334160484Sobrien
3342218822Sdim  /* Generate opcode for registers numbered in the range 0 .. 15.  */
3343218822Sdim  num_regs_below_16 = num_vfpv3_regs > 0 ? 16 - (int) start : count;
3344218822Sdim  assert (num_regs_below_16 + num_vfpv3_regs == count);
3345218822Sdim  if (num_regs_below_16 > 0)
334660484Sobrien    {
3347218822Sdim      op = 0xc900 | (start << 4) | (num_regs_below_16 - 1);
3348218822Sdim      add_unwind_opcode (op, 2);
334960484Sobrien    }
335060484Sobrien
3351218822Sdim  unwind.frame_size += count * 8;
335260484Sobrien}
335360484Sobrien
3354218822Sdim
3355218822Sdim/* Parse a directive saving VFP registers for pre-ARMv6.  */
3356218822Sdim
335760484Sobrienstatic void
3358218822Sdims_arm_unwind_save_vfp (void)
335960484Sobrien{
3360218822Sdim  int count;
3361218822Sdim  unsigned int reg;
3362218822Sdim  valueT op;
336360484Sobrien
3364218822Sdim  count = parse_vfp_reg_list (&input_line_pointer, &reg, REGLIST_VFP_D);
3365218822Sdim  if (count == FAIL)
336660484Sobrien    {
3367218822Sdim      as_bad (_("expected register list"));
3368218822Sdim      ignore_rest_of_line ();
336960484Sobrien      return;
337060484Sobrien    }
337160484Sobrien
3372218822Sdim  demand_empty_rest_of_line ();
337360484Sobrien
3374218822Sdim  if (reg == 8)
337560484Sobrien    {
3376218822Sdim      /* Short form.  */
3377218822Sdim      op = 0xb8 | (count - 1);
3378218822Sdim      add_unwind_opcode (op, 1);
337960484Sobrien    }
3380218822Sdim  else
338160484Sobrien    {
3382218822Sdim      /* Long form.  */
3383218822Sdim      op = 0xb300 | (reg << 4) | (count - 1);
3384218822Sdim      add_unwind_opcode (op, 2);
338560484Sobrien    }
3386218822Sdim  unwind.frame_size += count * 8 + 4;
338760484Sobrien}
338860484Sobrien
338977298Sobrien
3390218822Sdim/* Parse a directive saving iWMMXt data registers.  */
339177298Sobrien
3392218822Sdimstatic void
3393218822Sdims_arm_unwind_save_mmxwr (void)
339477298Sobrien{
3395218822Sdim  int reg;
3396218822Sdim  int hi_reg;
3397218822Sdim  int i;
3398218822Sdim  unsigned mask = 0;
3399218822Sdim  valueT op;
340077298Sobrien
3401218822Sdim  if (*input_line_pointer == '{')
3402218822Sdim    input_line_pointer++;
340377298Sobrien
3404218822Sdim  do
3405218822Sdim    {
3406218822Sdim      reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWR);
340777298Sobrien
3408218822Sdim      if (reg == FAIL)
3409218822Sdim	{
3410218822Sdim	  as_bad (_(reg_expected_msgs[REG_TYPE_MMXWR]));
3411218822Sdim	  goto error;
3412218822Sdim	}
341377298Sobrien
3414218822Sdim      if (mask >> reg)
3415218822Sdim	as_tsktsk (_("register list not in ascending order"));
3416218822Sdim      mask |= 1 << reg;
3417218822Sdim
3418218822Sdim      if (*input_line_pointer == '-')
3419218822Sdim	{
3420218822Sdim	  input_line_pointer++;
3421218822Sdim	  hi_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWR);
3422218822Sdim	  if (hi_reg == FAIL)
3423218822Sdim	    {
3424218822Sdim	      as_bad (_(reg_expected_msgs[REG_TYPE_MMXWR]));
3425218822Sdim	      goto error;
3426218822Sdim	    }
3427218822Sdim	  else if (reg >= hi_reg)
3428218822Sdim	    {
3429218822Sdim	      as_bad (_("bad register range"));
3430218822Sdim	      goto error;
3431218822Sdim	    }
3432218822Sdim	  for (; reg < hi_reg; reg++)
3433218822Sdim	    mask |= 1 << reg;
3434218822Sdim	}
343577298Sobrien    }
3436218822Sdim  while (skip_past_comma (&input_line_pointer) != FAIL);
343777298Sobrien
3438218822Sdim  if (*input_line_pointer == '}')
3439218822Sdim    input_line_pointer++;
344077298Sobrien
3441218822Sdim  demand_empty_rest_of_line ();
344277298Sobrien
3443218822Sdim  /* Generate any deferred opcodes because we're going to be looking at
3444218822Sdim     the list.	*/
3445218822Sdim  flush_pending_unwind ();
344677298Sobrien
3447218822Sdim  for (i = 0; i < 16; i++)
3448218822Sdim    {
3449218822Sdim      if (mask & (1 << i))
3450218822Sdim	unwind.frame_size += 8;
3451218822Sdim    }
345277298Sobrien
3453218822Sdim  /* Attempt to combine with a previous opcode.	 We do this because gcc
3454218822Sdim     likes to output separate unwind directives for a single block of
3455218822Sdim     registers.	 */
3456218822Sdim  if (unwind.opcode_count > 0)
345777298Sobrien    {
3458218822Sdim      i = unwind.opcodes[unwind.opcode_count - 1];
3459218822Sdim      if ((i & 0xf8) == 0xc0)
346077298Sobrien	{
3461218822Sdim	  i &= 7;
3462218822Sdim	  /* Only merge if the blocks are contiguous.  */
3463218822Sdim	  if (i < 6)
346477298Sobrien	    {
3465218822Sdim	      if ((mask & 0xfe00) == (1 << 9))
3466218822Sdim		{
3467218822Sdim		  mask |= ((1 << (i + 11)) - 1) & 0xfc00;
3468218822Sdim		  unwind.opcode_count--;
3469218822Sdim		}
347077298Sobrien	    }
3471218822Sdim	  else if (i == 6 && unwind.opcode_count >= 2)
347277298Sobrien	    {
3473218822Sdim	      i = unwind.opcodes[unwind.opcode_count - 2];
3474218822Sdim	      reg = i >> 4;
3475218822Sdim	      i &= 0xf;
347677298Sobrien
3477218822Sdim	      op = 0xffff << (reg - 1);
3478218822Sdim	      if (reg > 0
3479218822Sdim		  && ((mask & op) == (1u << (reg - 1))))
3480104834Sobrien		{
3481218822Sdim		  op = (1 << (reg + i + 1)) - 1;
3482218822Sdim		  op &= ~((1 << reg) - 1);
3483218822Sdim		  mask |= op;
3484218822Sdim		  unwind.opcode_count -= 2;
3485104834Sobrien		}
348677298Sobrien	    }
348777298Sobrien	}
3488218822Sdim    }
3489218822Sdim
3490218822Sdim  hi_reg = 15;
3491218822Sdim  /* We want to generate opcodes in the order the registers have been
3492218822Sdim     saved, ie. descending order.  */
3493218822Sdim  for (reg = 15; reg >= -1; reg--)
3494218822Sdim    {
3495218822Sdim      /* Save registers in blocks.  */
3496218822Sdim      if (reg < 0
3497218822Sdim	  || !(mask & (1 << reg)))
349877298Sobrien	{
3499218822Sdim	  /* We found an unsaved reg.  Generate opcodes to save the
3500218822Sdim	     preceeding block.	*/
3501218822Sdim	  if (reg != hi_reg)
350277298Sobrien	    {
3503218822Sdim	      if (reg == 9)
3504218822Sdim		{
3505218822Sdim		  /* Short form.  */
3506218822Sdim		  op = 0xc0 | (hi_reg - 10);
3507218822Sdim		  add_unwind_opcode (op, 1);
3508218822Sdim		}
3509218822Sdim	      else
3510218822Sdim		{
3511218822Sdim		  /* Long form.	 */
3512218822Sdim		  op = 0xc600 | ((reg + 1) << 4) | ((hi_reg - reg) - 1);
3513218822Sdim		  add_unwind_opcode (op, 2);
3514218822Sdim		}
351577298Sobrien	    }
3516218822Sdim	  hi_reg = reg - 1;
3517218822Sdim	}
3518218822Sdim    }
351977298Sobrien
3520218822Sdim  return;
3521218822Sdimerror:
3522218822Sdim  ignore_rest_of_line ();
3523218822Sdim}
352477298Sobrien
3525218822Sdimstatic void
3526218822Sdims_arm_unwind_save_mmxwcg (void)
3527218822Sdim{
3528218822Sdim  int reg;
3529218822Sdim  int hi_reg;
3530218822Sdim  unsigned mask = 0;
3531218822Sdim  valueT op;
353277298Sobrien
3533218822Sdim  if (*input_line_pointer == '{')
3534218822Sdim    input_line_pointer++;
353577298Sobrien
3536218822Sdim  do
3537218822Sdim    {
3538218822Sdim      reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWCG);
353977298Sobrien
3540218822Sdim      if (reg == FAIL)
3541218822Sdim	{
3542218822Sdim	  as_bad (_(reg_expected_msgs[REG_TYPE_MMXWCG]));
3543218822Sdim	  goto error;
3544218822Sdim	}
354577298Sobrien
3546218822Sdim      reg -= 8;
3547218822Sdim      if (mask >> reg)
3548218822Sdim	as_tsktsk (_("register list not in ascending order"));
3549218822Sdim      mask |= 1 << reg;
3550218822Sdim
3551218822Sdim      if (*input_line_pointer == '-')
3552218822Sdim	{
3553218822Sdim	  input_line_pointer++;
3554218822Sdim	  hi_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWCG);
3555218822Sdim	  if (hi_reg == FAIL)
355677298Sobrien	    {
3557218822Sdim	      as_bad (_(reg_expected_msgs[REG_TYPE_MMXWCG]));
3558218822Sdim	      goto error;
355977298Sobrien	    }
3560218822Sdim	  else if (reg >= hi_reg)
3561218822Sdim	    {
3562218822Sdim	      as_bad (_("bad register range"));
3563218822Sdim	      goto error;
3564218822Sdim	    }
3565218822Sdim	  for (; reg < hi_reg; reg++)
3566218822Sdim	    mask |= 1 << reg;
356777298Sobrien	}
356877298Sobrien    }
3569218822Sdim  while (skip_past_comma (&input_line_pointer) != FAIL);
357077298Sobrien
3571218822Sdim  if (*input_line_pointer == '}')
3572218822Sdim    input_line_pointer++;
357377298Sobrien
3574218822Sdim  demand_empty_rest_of_line ();
357577298Sobrien
3576218822Sdim  /* Generate any deferred opcodes because we're going to be looking at
3577218822Sdim     the list.	*/
3578218822Sdim  flush_pending_unwind ();
357977298Sobrien
3580218822Sdim  for (reg = 0; reg < 16; reg++)
3581218822Sdim    {
3582218822Sdim      if (mask & (1 << reg))
3583218822Sdim	unwind.frame_size += 4;
3584218822Sdim    }
3585218822Sdim  op = 0xc700 | mask;
3586218822Sdim  add_unwind_opcode (op, 2);
3587218822Sdim  return;
3588218822Sdimerror:
3589218822Sdim  ignore_rest_of_line ();
359077298Sobrien}
359177298Sobrien
359277298Sobrien
3593218822Sdim/* Parse an unwind_save directive.
3594218822Sdim   If the argument is non-zero, this is a .vsave directive.  */
3595218822Sdim
359677298Sobrienstatic void
3597218822Sdims_arm_unwind_save (int arch_v6)
359877298Sobrien{
3599218822Sdim  char *peek;
3600218822Sdim  struct reg_entry *reg;
3601218822Sdim  bfd_boolean had_brace = FALSE;
360277298Sobrien
3603218822Sdim  /* Figure out what sort of save we have.  */
3604218822Sdim  peek = input_line_pointer;
360577298Sobrien
3606218822Sdim  if (*peek == '{')
3607218822Sdim    {
3608218822Sdim      had_brace = TRUE;
3609218822Sdim      peek++;
3610218822Sdim    }
361177298Sobrien
3612218822Sdim  reg = arm_reg_parse_multi (&peek);
361377298Sobrien
3614218822Sdim  if (!reg)
3615218822Sdim    {
3616218822Sdim      as_bad (_("register expected"));
3617218822Sdim      ignore_rest_of_line ();
3618218822Sdim      return;
3619218822Sdim    }
3620218822Sdim
3621218822Sdim  switch (reg->type)
3622218822Sdim    {
3623218822Sdim    case REG_TYPE_FN:
3624218822Sdim      if (had_brace)
3625218822Sdim	{
3626218822Sdim	  as_bad (_("FPA .unwind_save does not take a register list"));
3627218822Sdim	  ignore_rest_of_line ();
3628218822Sdim	  return;
3629218822Sdim	}
3630218822Sdim      s_arm_unwind_save_fpa (reg->number);
3631218822Sdim      return;
3632218822Sdim
3633218822Sdim    case REG_TYPE_RN:	  s_arm_unwind_save_core ();   return;
3634218822Sdim    case REG_TYPE_VFD:
3635218822Sdim      if (arch_v6)
3636218822Sdim        s_arm_unwind_save_vfp_armv6 ();
3637218822Sdim      else
3638218822Sdim        s_arm_unwind_save_vfp ();
3639218822Sdim      return;
3640218822Sdim    case REG_TYPE_MMXWR:  s_arm_unwind_save_mmxwr ();  return;
3641218822Sdim    case REG_TYPE_MMXWCG: s_arm_unwind_save_mmxwcg (); return;
3642218822Sdim
3643218822Sdim    default:
3644218822Sdim      as_bad (_(".unwind_save does not support this kind of register"));
3645218822Sdim      ignore_rest_of_line ();
3646218822Sdim    }
364777298Sobrien}
364877298Sobrien
364977298Sobrien
3650218822Sdim/* Parse an unwind_movsp directive.  */
3651218822Sdim
365277298Sobrienstatic void
3653218822Sdims_arm_unwind_movsp (int ignored ATTRIBUTE_UNUSED)
365477298Sobrien{
3655218822Sdim  int reg;
3656218822Sdim  valueT op;
3657218822Sdim  int offset;
365877298Sobrien
3659218822Sdim  reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN);
3660218822Sdim  if (reg == FAIL)
366177298Sobrien    {
3662218822Sdim      as_bad (_(reg_expected_msgs[REG_TYPE_RN]));
3663218822Sdim      ignore_rest_of_line ();
366477298Sobrien      return;
366577298Sobrien    }
366677298Sobrien
3667218822Sdim  /* Optional constant.	 */
3668218822Sdim  if (skip_past_comma (&input_line_pointer) != FAIL)
366977298Sobrien    {
3670218822Sdim      if (immediate_for_directive (&offset) == FAIL)
3671218822Sdim	return;
3672218822Sdim    }
3673218822Sdim  else
3674218822Sdim    offset = 0;
3675218822Sdim
3676218822Sdim  demand_empty_rest_of_line ();
3677218822Sdim
3678218822Sdim  if (reg == REG_SP || reg == REG_PC)
3679218822Sdim    {
3680218822Sdim      as_bad (_("SP and PC not permitted in .unwind_movsp directive"));
368177298Sobrien      return;
368277298Sobrien    }
368377298Sobrien
3684218822Sdim  if (unwind.fp_reg != REG_SP)
3685218822Sdim    as_bad (_("unexpected .unwind_movsp directive"));
368677298Sobrien
3687218822Sdim  /* Generate opcode to restore the value.  */
3688218822Sdim  op = 0x90 | reg;
3689218822Sdim  add_unwind_opcode (op, 1);
3690218822Sdim
3691218822Sdim  /* Record the information for later.	*/
3692218822Sdim  unwind.fp_reg = reg;
3693218822Sdim  unwind.fp_offset = unwind.frame_size - offset;
3694218822Sdim  unwind.sp_restored = 1;
369577298Sobrien}
369677298Sobrien
3697218822Sdim/* Parse an unwind_pad directive.  */
369877298Sobrien
369977298Sobrienstatic void
3700218822Sdims_arm_unwind_pad (int ignored ATTRIBUTE_UNUSED)
370177298Sobrien{
3702218822Sdim  int offset;
370377298Sobrien
3704218822Sdim  if (immediate_for_directive (&offset) == FAIL)
3705218822Sdim    return;
370677298Sobrien
3707218822Sdim  if (offset & 3)
3708218822Sdim    {
3709218822Sdim      as_bad (_("stack increment must be multiple of 4"));
3710218822Sdim      ignore_rest_of_line ();
3711218822Sdim      return;
3712218822Sdim    }
371377298Sobrien
3714218822Sdim  /* Don't generate any opcodes, just record the details for later.  */
3715218822Sdim  unwind.frame_size += offset;
3716218822Sdim  unwind.pending_offset += offset;
371777298Sobrien
3718218822Sdim  demand_empty_rest_of_line ();
371977298Sobrien}
372077298Sobrien
3721218822Sdim/* Parse an unwind_setfp directive.  */
372277298Sobrien
372377298Sobrienstatic void
3724218822Sdims_arm_unwind_setfp (int ignored ATTRIBUTE_UNUSED)
372577298Sobrien{
3726218822Sdim  int sp_reg;
3727218822Sdim  int fp_reg;
3728218822Sdim  int offset;
372977298Sobrien
3730218822Sdim  fp_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN);
3731218822Sdim  if (skip_past_comma (&input_line_pointer) == FAIL)
3732218822Sdim    sp_reg = FAIL;
3733218822Sdim  else
3734218822Sdim    sp_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN);
373577298Sobrien
3736218822Sdim  if (fp_reg == FAIL || sp_reg == FAIL)
3737218822Sdim    {
3738218822Sdim      as_bad (_("expected <reg>, <reg>"));
3739218822Sdim      ignore_rest_of_line ();
3740218822Sdim      return;
3741218822Sdim    }
374277298Sobrien
3743218822Sdim  /* Optional constant.	 */
3744218822Sdim  if (skip_past_comma (&input_line_pointer) != FAIL)
3745218822Sdim    {
3746218822Sdim      if (immediate_for_directive (&offset) == FAIL)
3747218822Sdim	return;
3748218822Sdim    }
3749218822Sdim  else
3750218822Sdim    offset = 0;
375177298Sobrien
3752218822Sdim  demand_empty_rest_of_line ();
3753218822Sdim
3754218822Sdim  if (sp_reg != 13 && sp_reg != unwind.fp_reg)
3755218822Sdim    {
3756218822Sdim      as_bad (_("register must be either sp or set by a previous"
3757218822Sdim		"unwind_movsp directive"));
3758218822Sdim      return;
3759218822Sdim    }
3760218822Sdim
3761218822Sdim  /* Don't generate any opcodes, just record the information for later.	 */
3762218822Sdim  unwind.fp_reg = fp_reg;
3763218822Sdim  unwind.fp_used = 1;
3764218822Sdim  if (sp_reg == 13)
3765218822Sdim    unwind.fp_offset = unwind.frame_size - offset;
376677298Sobrien  else
3767218822Sdim    unwind.fp_offset -= offset;
376877298Sobrien}
376977298Sobrien
3770218822Sdim/* Parse an unwind_raw directive.  */
377177298Sobrien
377277298Sobrienstatic void
3773218822Sdims_arm_unwind_raw (int ignored ATTRIBUTE_UNUSED)
377477298Sobrien{
3775218822Sdim  expressionS exp;
3776218822Sdim  /* This is an arbitrary limit.	 */
3777218822Sdim  unsigned char op[16];
3778218822Sdim  int count;
377977298Sobrien
3780218822Sdim  expression (&exp);
3781218822Sdim  if (exp.X_op == O_constant
3782218822Sdim      && skip_past_comma (&input_line_pointer) != FAIL)
378377298Sobrien    {
3784218822Sdim      unwind.frame_size += exp.X_add_number;
3785218822Sdim      expression (&exp);
378677298Sobrien    }
3787218822Sdim  else
3788218822Sdim    exp.X_op = O_illegal;
378977298Sobrien
3790218822Sdim  if (exp.X_op != O_constant)
379177298Sobrien    {
3792218822Sdim      as_bad (_("expected <offset>, <opcode>"));
3793218822Sdim      ignore_rest_of_line ();
379477298Sobrien      return;
379577298Sobrien    }
379677298Sobrien
3797218822Sdim  count = 0;
379877298Sobrien
3799218822Sdim  /* Parse the opcode.	*/
3800218822Sdim  for (;;)
380177298Sobrien    {
3802218822Sdim      if (count >= 16)
3803218822Sdim	{
3804218822Sdim	  as_bad (_("unwind opcode too long"));
3805218822Sdim	  ignore_rest_of_line ();
3806218822Sdim	}
3807218822Sdim      if (exp.X_op != O_constant || exp.X_add_number & ~0xff)
3808218822Sdim	{
3809218822Sdim	  as_bad (_("invalid unwind opcode"));
3810218822Sdim	  ignore_rest_of_line ();
3811218822Sdim	  return;
3812218822Sdim	}
3813218822Sdim      op[count++] = exp.X_add_number;
381477298Sobrien
3815218822Sdim      /* Parse the next byte.  */
3816218822Sdim      if (skip_past_comma (&input_line_pointer) == FAIL)
3817218822Sdim	break;
381877298Sobrien
3819218822Sdim      expression (&exp);
382077298Sobrien    }
382177298Sobrien
3822218822Sdim  /* Add the opcode bytes in reverse order.  */
3823218822Sdim  while (count--)
3824218822Sdim    add_unwind_opcode (op[count], 1);
3825218822Sdim
3826218822Sdim  demand_empty_rest_of_line ();
382777298Sobrien}
382877298Sobrien
382977298Sobrien
3830218822Sdim/* Parse a .eabi_attribute directive.  */
3831218822Sdim
383277298Sobrienstatic void
3833218822Sdims_arm_eabi_attribute (int ignored ATTRIBUTE_UNUSED)
383477298Sobrien{
3835218822Sdim  s_vendor_attribute (OBJ_ATTR_PROC);
3836218822Sdim}
3837218822Sdim#endif /* OBJ_ELF */
383877298Sobrien
3839218822Sdimstatic void s_arm_arch (int);
3840269797Sianstatic void s_arm_arch_extension (int);
3841218822Sdimstatic void s_arm_object_arch (int);
3842218822Sdimstatic void s_arm_cpu (int);
3843218822Sdimstatic void s_arm_fpu (int);
384477298Sobrien
3845218822Sdim#ifdef TE_PE
384677298Sobrien
3847218822Sdimstatic void
3848218822Sdimpe_directive_secrel (int dummy ATTRIBUTE_UNUSED)
3849218822Sdim{
3850218822Sdim  expressionS exp;
385177298Sobrien
3852218822Sdim  do
3853218822Sdim    {
3854218822Sdim      expression (&exp);
3855218822Sdim      if (exp.X_op == O_symbol)
3856218822Sdim	exp.X_op = O_secrel;
3857218822Sdim
3858218822Sdim      emit_expr (&exp, 4);
3859218822Sdim    }
3860218822Sdim  while (*input_line_pointer++ == ',');
3861218822Sdim
3862218822Sdim  input_line_pointer--;
3863218822Sdim  demand_empty_rest_of_line ();
386477298Sobrien}
3865218822Sdim#endif /* TE_PE */
386677298Sobrien
3867218822Sdim/* This table describes all the machine specific pseudo-ops the assembler
3868218822Sdim   has to support.  The fields are:
3869218822Sdim     pseudo-op name without dot
3870218822Sdim     function to call to execute this pseudo-op
3871218822Sdim     Integer arg to pass to the function.  */
387277298Sobrien
3873218822Sdimconst pseudo_typeS md_pseudo_table[] =
387477298Sobrien{
3875218822Sdim  /* Never called because '.req' does not start a line.	 */
3876218822Sdim  { "req",	   s_req,	  0 },
3877218822Sdim  /* Following two are likewise never called.  */
3878218822Sdim  { "dn",	   s_dn,          0 },
3879218822Sdim  { "qn",          s_qn,          0 },
3880218822Sdim  { "unreq",	   s_unreq,	  0 },
3881218822Sdim  { "bss",	   s_bss,	  0 },
3882218822Sdim  { "align",	   s_align,	  0 },
3883218822Sdim  { "arm",	   s_arm,	  0 },
3884218822Sdim  { "thumb",	   s_thumb,	  0 },
3885218822Sdim  { "code",	   s_code,	  0 },
3886218822Sdim  { "force_thumb", s_force_thumb, 0 },
3887218822Sdim  { "thumb_func",  s_thumb_func,  0 },
3888218822Sdim  { "thumb_set",   s_thumb_set,	  0 },
3889218822Sdim  { "even",	   s_even,	  0 },
3890218822Sdim  { "ltorg",	   s_ltorg,	  0 },
3891218822Sdim  { "pool",	   s_ltorg,	  0 },
3892218822Sdim  { "syntax",	   s_syntax,	  0 },
3893218822Sdim  { "cpu",	   s_arm_cpu,	  0 },
3894218822Sdim  { "arch",	   s_arm_arch,	  0 },
3895269797Sian  { "arch_extension",	   s_arm_arch_extension,	  0 },
3896218822Sdim  { "object_arch", s_arm_object_arch,	0 },
3897218822Sdim  { "fpu",	   s_arm_fpu,	  0 },
3898218822Sdim#ifdef OBJ_ELF
3899218822Sdim  { "word",	   s_arm_elf_cons, 4 },
3900218822Sdim  { "long",	   s_arm_elf_cons, 4 },
3901218822Sdim  { "rel31",	   s_arm_rel31,	  0 },
3902218822Sdim  { "fnstart",		s_arm_unwind_fnstart,	0 },
3903218822Sdim  { "fnend",		s_arm_unwind_fnend,	0 },
3904218822Sdim  { "cantunwind",	s_arm_unwind_cantunwind, 0 },
3905218822Sdim  { "personality",	s_arm_unwind_personality, 0 },
3906218822Sdim  { "personalityindex",	s_arm_unwind_personalityindex, 0 },
3907218822Sdim  { "handlerdata",	s_arm_unwind_handlerdata, 0 },
3908218822Sdim  { "save",		s_arm_unwind_save,	0 },
3909218822Sdim  { "vsave",		s_arm_unwind_save,	1 },
3910218822Sdim  { "movsp",		s_arm_unwind_movsp,	0 },
3911218822Sdim  { "pad",		s_arm_unwind_pad,	0 },
3912218822Sdim  { "setfp",		s_arm_unwind_setfp,	0 },
3913218822Sdim  { "unwind_raw",	s_arm_unwind_raw,	0 },
3914218822Sdim  { "eabi_attribute",	s_arm_eabi_attribute,	0 },
3915218822Sdim#else
3916218822Sdim  { "word",	   cons, 4},
391777298Sobrien
3918218822Sdim  /* These are used for dwarf.  */
3919218822Sdim  {"2byte", cons, 2},
3920218822Sdim  {"4byte", cons, 4},
3921218822Sdim  {"8byte", cons, 8},
3922218822Sdim  /* These are used for dwarf2.  */
3923218822Sdim  { "file", (void (*) (int)) dwarf2_directive_file, 0 },
3924218822Sdim  { "loc",  dwarf2_directive_loc,  0 },
3925218822Sdim  { "loc_mark_labels", dwarf2_directive_loc_mark_labels, 0 },
3926218822Sdim#endif
3927218822Sdim  { "extend",	   float_cons, 'x' },
3928218822Sdim  { "ldouble",	   float_cons, 'x' },
3929218822Sdim  { "packed",	   float_cons, 'p' },
3930218822Sdim#ifdef TE_PE
3931218822Sdim  {"secrel32", pe_directive_secrel, 0},
3932218822Sdim#endif
3933218822Sdim  { 0, 0, 0 }
3934218822Sdim};
3935218822Sdim
3936218822Sdim/* Parser functions used exclusively in instruction operands.  */
3937218822Sdim
3938218822Sdim/* Generic immediate-value read function for use in insn parsing.
3939218822Sdim   STR points to the beginning of the immediate (the leading #);
3940218822Sdim   VAL receives the value; if the value is outside [MIN, MAX]
3941218822Sdim   issue an error.  PREFIX_OPT is true if the immediate prefix is
3942218822Sdim   optional.  */
3943218822Sdim
3944218822Sdimstatic int
3945218822Sdimparse_immediate (char **str, int *val, int min, int max,
3946218822Sdim		 bfd_boolean prefix_opt)
3947218822Sdim{
3948218822Sdim  expressionS exp;
3949218822Sdim  my_get_expression (&exp, str, prefix_opt ? GE_OPT_PREFIX : GE_IMM_PREFIX);
3950218822Sdim  if (exp.X_op != O_constant)
395177298Sobrien    {
3952218822Sdim      inst.error = _("constant expression required");
3953218822Sdim      return FAIL;
395477298Sobrien    }
3955218822Sdim
3956218822Sdim  if (exp.X_add_number < min || exp.X_add_number > max)
395777298Sobrien    {
3958218822Sdim      inst.error = _("immediate value out of range");
3959218822Sdim      return FAIL;
396077298Sobrien    }
3961218822Sdim
3962218822Sdim  *val = exp.X_add_number;
3963218822Sdim  return SUCCESS;
3964218822Sdim}
3965218822Sdim
3966218822Sdim/* Less-generic immediate-value read function with the possibility of loading a
3967218822Sdim   big (64-bit) immediate, as required by Neon VMOV, VMVN and logic immediate
3968218822Sdim   instructions. Puts the result directly in inst.operands[i].  */
3969218822Sdim
3970218822Sdimstatic int
3971218822Sdimparse_big_immediate (char **str, int i)
3972218822Sdim{
3973218822Sdim  expressionS exp;
3974218822Sdim  char *ptr = *str;
3975218822Sdim
3976218822Sdim  my_get_expression (&exp, &ptr, GE_OPT_PREFIX_BIG);
3977218822Sdim
3978218822Sdim  if (exp.X_op == O_constant)
397977298Sobrien    {
3980218822Sdim      inst.operands[i].imm = exp.X_add_number & 0xffffffff;
3981218822Sdim      /* If we're on a 64-bit host, then a 64-bit number can be returned using
3982218822Sdim	 O_constant.  We have to be careful not to break compilation for
3983218822Sdim	 32-bit X_add_number, though.  */
3984218822Sdim      if ((exp.X_add_number & ~0xffffffffl) != 0)
3985218822Sdim	{
3986218822Sdim          /* X >> 32 is illegal if sizeof (exp.X_add_number) == 4.  */
3987218822Sdim	  inst.operands[i].reg = ((exp.X_add_number >> 16) >> 16) & 0xffffffff;
3988218822Sdim	  inst.operands[i].regisimm = 1;
3989218822Sdim	}
399077298Sobrien    }
3991218822Sdim  else if (exp.X_op == O_big
3992218822Sdim           && LITTLENUM_NUMBER_OF_BITS * exp.X_add_number > 32
3993218822Sdim           && LITTLENUM_NUMBER_OF_BITS * exp.X_add_number <= 64)
3994218822Sdim    {
3995218822Sdim      unsigned parts = 32 / LITTLENUM_NUMBER_OF_BITS, j, idx = 0;
3996218822Sdim      /* Bignums have their least significant bits in
3997218822Sdim         generic_bignum[0]. Make sure we put 32 bits in imm and
3998218822Sdim         32 bits in reg,  in a (hopefully) portable way.  */
3999218822Sdim      assert (parts != 0);
4000218822Sdim      inst.operands[i].imm = 0;
4001218822Sdim      for (j = 0; j < parts; j++, idx++)
4002218822Sdim        inst.operands[i].imm |= generic_bignum[idx]
4003218822Sdim                                << (LITTLENUM_NUMBER_OF_BITS * j);
4004218822Sdim      inst.operands[i].reg = 0;
4005218822Sdim      for (j = 0; j < parts; j++, idx++)
4006218822Sdim        inst.operands[i].reg |= generic_bignum[idx]
4007218822Sdim                                << (LITTLENUM_NUMBER_OF_BITS * j);
4008218822Sdim      inst.operands[i].regisimm = 1;
4009218822Sdim    }
401077298Sobrien  else
4011218822Sdim    return FAIL;
4012218822Sdim
4013218822Sdim  *str = ptr;
4014218822Sdim
4015218822Sdim  return SUCCESS;
401677298Sobrien}
401777298Sobrien
4018218822Sdim/* Returns the pseudo-register number of an FPA immediate constant,
4019218822Sdim   or FAIL if there isn't a valid constant here.  */
402077298Sobrien
4021218822Sdimstatic int
4022218822Sdimparse_fpa_immediate (char ** str)
402377298Sobrien{
4024218822Sdim  LITTLENUM_TYPE words[MAX_LITTLENUMS];
4025218822Sdim  char *	 save_in;
4026218822Sdim  expressionS	 exp;
4027218822Sdim  int		 i;
4028218822Sdim  int		 j;
402977298Sobrien
4030218822Sdim  /* First try and match exact strings, this is to guarantee
4031218822Sdim     that some formats will work even for cross assembly.  */
403277298Sobrien
4033218822Sdim  for (i = 0; fp_const[i]; i++)
403477298Sobrien    {
4035218822Sdim      if (strncmp (*str, fp_const[i], strlen (fp_const[i])) == 0)
4036218822Sdim	{
4037218822Sdim	  char *start = *str;
403877298Sobrien
4039218822Sdim	  *str += strlen (fp_const[i]);
4040218822Sdim	  if (is_end_of_line[(unsigned char) **str])
4041218822Sdim	    return i + 8;
4042218822Sdim	  *str = start;
4043218822Sdim	}
404477298Sobrien    }
404577298Sobrien
4046218822Sdim  /* Just because we didn't get a match doesn't mean that the constant
4047218822Sdim     isn't valid, just that it is in a format that we don't
4048218822Sdim     automatically recognize.  Try parsing it with the standard
4049218822Sdim     expression routines.  */
4050218822Sdim
4051218822Sdim  memset (words, 0, MAX_LITTLENUMS * sizeof (LITTLENUM_TYPE));
4052218822Sdim
4053218822Sdim  /* Look for a raw floating point number.  */
4054218822Sdim  if ((save_in = atof_ieee (*str, 'x', words)) != NULL
4055218822Sdim      && is_end_of_line[(unsigned char) *save_in])
405677298Sobrien    {
4057218822Sdim      for (i = 0; i < NUM_FLOAT_VALS; i++)
4058218822Sdim	{
4059218822Sdim	  for (j = 0; j < MAX_LITTLENUMS; j++)
4060218822Sdim	    {
4061218822Sdim	      if (words[j] != fp_values[i][j])
4062218822Sdim		break;
4063218822Sdim	    }
406477298Sobrien
4065218822Sdim	  if (j == MAX_LITTLENUMS)
4066218822Sdim	    {
4067218822Sdim	      *str = save_in;
4068218822Sdim	      return i + 8;
4069218822Sdim	    }
4070218822Sdim	}
407177298Sobrien    }
407277298Sobrien
4073218822Sdim  /* Try and parse a more complex expression, this will probably fail
4074218822Sdim     unless the code uses a floating point prefix (eg "0f").  */
4075218822Sdim  save_in = input_line_pointer;
4076218822Sdim  input_line_pointer = *str;
4077218822Sdim  if (expression (&exp) == absolute_section
4078218822Sdim      && exp.X_op == O_big
4079218822Sdim      && exp.X_add_number < 0)
408077298Sobrien    {
4081218822Sdim      /* FIXME: 5 = X_PRECISION, should be #define'd where we can use it.
4082218822Sdim	 Ditto for 15.	*/
4083218822Sdim      if (gen_to_words (words, 5, (long) 15) == 0)
408477298Sobrien	{
4085218822Sdim	  for (i = 0; i < NUM_FLOAT_VALS; i++)
4086218822Sdim	    {
4087218822Sdim	      for (j = 0; j < MAX_LITTLENUMS; j++)
4088218822Sdim		{
4089218822Sdim		  if (words[j] != fp_values[i][j])
4090218822Sdim		    break;
4091218822Sdim		}
4092218822Sdim
4093218822Sdim	      if (j == MAX_LITTLENUMS)
4094218822Sdim		{
4095218822Sdim		  *str = input_line_pointer;
4096218822Sdim		  input_line_pointer = save_in;
4097218822Sdim		  return i + 8;
4098218822Sdim		}
4099218822Sdim	    }
410077298Sobrien	}
410177298Sobrien    }
410277298Sobrien
4103218822Sdim  *str = input_line_pointer;
4104218822Sdim  input_line_pointer = save_in;
4105218822Sdim  inst.error = _("invalid FPA immediate expression");
4106218822Sdim  return FAIL;
410777298Sobrien}
410877298Sobrien
4109218822Sdim/* Returns 1 if a number has "quarter-precision" float format
4110218822Sdim   0baBbbbbbc defgh000 00000000 00000000.  */
411177298Sobrien
4112218822Sdimstatic int
4113218822Sdimis_quarter_float (unsigned imm)
411477298Sobrien{
4115218822Sdim  int bs = (imm & 0x20000000) ? 0x3e000000 : 0x40000000;
4116218822Sdim  return (imm & 0x7ffff) == 0 && ((imm & 0x7e000000) ^ bs) == 0;
4117218822Sdim}
411877298Sobrien
4119218822Sdim/* Parse an 8-bit "quarter-precision" floating point number of the form:
4120218822Sdim   0baBbbbbbc defgh000 00000000 00000000.
4121218822Sdim   The zero and minus-zero cases need special handling, since they can't be
4122218822Sdim   encoded in the "quarter-precision" float format, but can nonetheless be
4123218822Sdim   loaded as integer constants.  */
4124218822Sdim
4125218822Sdimstatic unsigned
4126218822Sdimparse_qfloat_immediate (char **ccp, int *immed)
4127218822Sdim{
4128218822Sdim  char *str = *ccp;
4129218822Sdim  char *fpnum;
4130218822Sdim  LITTLENUM_TYPE words[MAX_LITTLENUMS];
4131218822Sdim  int found_fpchar = 0;
4132218822Sdim
4133218822Sdim  skip_past_char (&str, '#');
4134218822Sdim
4135218822Sdim  /* We must not accidentally parse an integer as a floating-point number. Make
4136218822Sdim     sure that the value we parse is not an integer by checking for special
4137218822Sdim     characters '.' or 'e'.
4138218822Sdim     FIXME: This is a horrible hack, but doing better is tricky because type
4139218822Sdim     information isn't in a very usable state at parse time.  */
4140218822Sdim  fpnum = str;
4141218822Sdim  skip_whitespace (fpnum);
4142218822Sdim
4143218822Sdim  if (strncmp (fpnum, "0x", 2) == 0)
4144218822Sdim    return FAIL;
4145218822Sdim  else
414677298Sobrien    {
4147218822Sdim      for (; *fpnum != '\0' && *fpnum != ' ' && *fpnum != '\n'; fpnum++)
4148218822Sdim        if (*fpnum == '.' || *fpnum == 'e' || *fpnum == 'E')
4149218822Sdim          {
4150218822Sdim            found_fpchar = 1;
4151218822Sdim            break;
4152218822Sdim          }
4153218822Sdim
4154218822Sdim      if (!found_fpchar)
4155218822Sdim        return FAIL;
415677298Sobrien    }
4157218822Sdim
4158218822Sdim  if ((str = atof_ieee (str, 's', words)) != NULL)
4159218822Sdim    {
4160218822Sdim      unsigned fpword = 0;
4161218822Sdim      int i;
4162218822Sdim
4163218822Sdim      /* Our FP word must be 32 bits (single-precision FP).  */
4164218822Sdim      for (i = 0; i < 32 / LITTLENUM_NUMBER_OF_BITS; i++)
4165218822Sdim        {
4166218822Sdim          fpword <<= LITTLENUM_NUMBER_OF_BITS;
4167218822Sdim          fpword |= words[i];
4168218822Sdim        }
4169218822Sdim
4170218822Sdim      if (is_quarter_float (fpword) || (fpword & 0x7fffffff) == 0)
4171218822Sdim        *immed = fpword;
4172218822Sdim      else
4173218822Sdim        return FAIL;
417477298Sobrien
4175218822Sdim      *ccp = str;
4176218822Sdim
4177218822Sdim      return SUCCESS;
417877298Sobrien    }
4179218822Sdim
4180218822Sdim  return FAIL;
4181218822Sdim}
418277298Sobrien
4183218822Sdim/* Shift operands.  */
4184218822Sdimenum shift_kind
4185218822Sdim{
4186218822Sdim  SHIFT_LSL, SHIFT_LSR, SHIFT_ASR, SHIFT_ROR, SHIFT_RRX
4187218822Sdim};
4188218822Sdim
4189218822Sdimstruct asm_shift_name
4190218822Sdim{
4191218822Sdim  const char	  *name;
4192218822Sdim  enum shift_kind  kind;
4193218822Sdim};
4194218822Sdim
4195218822Sdim/* Third argument to parse_shift.  */
4196218822Sdimenum parse_shift_mode
4197218822Sdim{
4198218822Sdim  NO_SHIFT_RESTRICT,		/* Any kind of shift is accepted.  */
4199218822Sdim  SHIFT_IMMEDIATE,		/* Shift operand must be an immediate.	*/
4200218822Sdim  SHIFT_LSL_OR_ASR_IMMEDIATE,	/* Shift must be LSL or ASR immediate.	*/
4201218822Sdim  SHIFT_ASR_IMMEDIATE,		/* Shift must be ASR immediate.	 */
4202218822Sdim  SHIFT_LSL_IMMEDIATE,		/* Shift must be LSL immediate.	 */
4203218822Sdim};
4204218822Sdim
4205218822Sdim/* Parse a <shift> specifier on an ARM data processing instruction.
4206218822Sdim   This has three forms:
4207218822Sdim
4208218822Sdim     (LSL|LSR|ASL|ASR|ROR) Rs
4209218822Sdim     (LSL|LSR|ASL|ASR|ROR) #imm
4210218822Sdim     RRX
4211218822Sdim
4212218822Sdim   Note that ASL is assimilated to LSL in the instruction encoding, and
4213218822Sdim   RRX to ROR #0 (which cannot be written as such).  */
4214218822Sdim
4215218822Sdimstatic int
4216218822Sdimparse_shift (char **str, int i, enum parse_shift_mode mode)
4217218822Sdim{
4218218822Sdim  const struct asm_shift_name *shift_name;
4219218822Sdim  enum shift_kind shift;
4220218822Sdim  char *s = *str;
4221218822Sdim  char *p = s;
4222218822Sdim  int reg;
4223218822Sdim
4224218822Sdim  for (p = *str; ISALPHA (*p); p++)
4225218822Sdim    ;
4226218822Sdim
4227218822Sdim  if (p == *str)
422877298Sobrien    {
4229218822Sdim      inst.error = _("shift expression expected");
4230218822Sdim      return FAIL;
423177298Sobrien    }
423277298Sobrien
4233218822Sdim  shift_name = hash_find_n (arm_shift_hsh, *str, p - *str);
4234218822Sdim
4235218822Sdim  if (shift_name == NULL)
423677298Sobrien    {
4237218822Sdim      inst.error = _("shift expression expected");
4238218822Sdim      return FAIL;
423977298Sobrien    }
424077298Sobrien
4241218822Sdim  shift = shift_name->kind;
4242218822Sdim
4243218822Sdim  switch (mode)
424477298Sobrien    {
4245218822Sdim    case NO_SHIFT_RESTRICT:
4246218822Sdim    case SHIFT_IMMEDIATE:   break;
4247218822Sdim
4248218822Sdim    case SHIFT_LSL_OR_ASR_IMMEDIATE:
4249218822Sdim      if (shift != SHIFT_LSL && shift != SHIFT_ASR)
4250218822Sdim	{
4251218822Sdim	  inst.error = _("'LSL' or 'ASR' required");
4252218822Sdim	  return FAIL;
4253218822Sdim	}
4254218822Sdim      break;
4255218822Sdim
4256218822Sdim    case SHIFT_LSL_IMMEDIATE:
4257218822Sdim      if (shift != SHIFT_LSL)
4258218822Sdim	{
4259218822Sdim	  inst.error = _("'LSL' required");
4260218822Sdim	  return FAIL;
4261218822Sdim	}
4262218822Sdim      break;
4263218822Sdim
4264218822Sdim    case SHIFT_ASR_IMMEDIATE:
4265218822Sdim      if (shift != SHIFT_ASR)
4266218822Sdim	{
4267218822Sdim	  inst.error = _("'ASR' required");
4268218822Sdim	  return FAIL;
4269218822Sdim	}
4270218822Sdim      break;
4271218822Sdim
4272218822Sdim    default: abort ();
427377298Sobrien    }
427477298Sobrien
4275218822Sdim  if (shift != SHIFT_RRX)
427677298Sobrien    {
4277218822Sdim      /* Whitespace can appear here if the next thing is a bare digit.	*/
4278218822Sdim      skip_whitespace (p);
4279218822Sdim
4280218822Sdim      if (mode == NO_SHIFT_RESTRICT
4281218822Sdim	  && (reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL)
428277298Sobrien	{
4283218822Sdim	  inst.operands[i].imm = reg;
4284218822Sdim	  inst.operands[i].immisreg = 1;
428577298Sobrien	}
4286218822Sdim      else if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
4287218822Sdim	return FAIL;
428877298Sobrien    }
4289218822Sdim  inst.operands[i].shift_kind = shift;
4290218822Sdim  inst.operands[i].shifted = 1;
4291218822Sdim  *str = p;
4292218822Sdim  return SUCCESS;
429389857Sobrien}
429477298Sobrien
4295218822Sdim/* Parse a <shifter_operand> for an ARM data processing instruction:
4296218822Sdim
4297218822Sdim      #<immediate>
4298218822Sdim      #<immediate>, <rotate>
4299218822Sdim      <Rm>
4300218822Sdim      <Rm>, <shift>
4301218822Sdim
4302218822Sdim   where <shift> is defined by parse_shift above, and <rotate> is a
4303218822Sdim   multiple of 2 between 0 and 30.  Validation of immediate operands
4304218822Sdim   is deferred to md_apply_fix.  */
4305218822Sdim
4306218822Sdimstatic int
4307218822Sdimparse_shifter_operand (char **str, int i)
430889857Sobrien{
4309218822Sdim  int value;
4310218822Sdim  expressionS expr;
431189857Sobrien
4312218822Sdim  if ((value = arm_reg_parse (str, REG_TYPE_RN)) != FAIL)
4313218822Sdim    {
4314218822Sdim      inst.operands[i].reg = value;
4315218822Sdim      inst.operands[i].isreg = 1;
431689857Sobrien
4317218822Sdim      /* parse_shift will override this if appropriate */
4318218822Sdim      inst.reloc.exp.X_op = O_constant;
4319218822Sdim      inst.reloc.exp.X_add_number = 0;
4320218822Sdim
4321218822Sdim      if (skip_past_comma (str) == FAIL)
4322218822Sdim	return SUCCESS;
4323218822Sdim
4324218822Sdim      /* Shift operation on register.  */
4325218822Sdim      return parse_shift (str, i, NO_SHIFT_RESTRICT);
4326218822Sdim    }
4327218822Sdim
4328218822Sdim  if (my_get_expression (&inst.reloc.exp, str, GE_IMM_PREFIX))
4329218822Sdim    return FAIL;
4330218822Sdim
4331218822Sdim  if (skip_past_comma (str) == SUCCESS)
433289857Sobrien    {
4333218822Sdim      /* #x, y -- ie explicit rotation by Y.  */
4334218822Sdim      if (my_get_expression (&expr, str, GE_NO_PREFIX))
4335218822Sdim	return FAIL;
4336218822Sdim
4337218822Sdim      if (expr.X_op != O_constant || inst.reloc.exp.X_op != O_constant)
4338218822Sdim	{
4339218822Sdim	  inst.error = _("constant expression expected");
4340218822Sdim	  return FAIL;
4341218822Sdim	}
4342218822Sdim
4343218822Sdim      value = expr.X_add_number;
4344218822Sdim      if (value < 0 || value > 30 || value % 2 != 0)
4345218822Sdim	{
4346218822Sdim	  inst.error = _("invalid rotation");
4347218822Sdim	  return FAIL;
4348218822Sdim	}
4349218822Sdim      if (inst.reloc.exp.X_add_number < 0 || inst.reloc.exp.X_add_number > 255)
4350218822Sdim	{
4351218822Sdim	  inst.error = _("invalid constant");
4352218822Sdim	  return FAIL;
4353218822Sdim	}
4354218822Sdim
4355218822Sdim      /* Convert to decoded value.  md_apply_fix will put it back.  */
4356218822Sdim      inst.reloc.exp.X_add_number
4357218822Sdim	= (((inst.reloc.exp.X_add_number << (32 - value))
4358218822Sdim	    | (inst.reloc.exp.X_add_number >> value)) & 0xffffffff);
435989857Sobrien    }
436089857Sobrien
4361218822Sdim  inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
4362218822Sdim  inst.reloc.pc_rel = 0;
4363218822Sdim  return SUCCESS;
436477298Sobrien}
436577298Sobrien
4366218822Sdim/* Group relocation information.  Each entry in the table contains the
4367218822Sdim   textual name of the relocation as may appear in assembler source
4368218822Sdim   and must end with a colon.
4369218822Sdim   Along with this textual name are the relocation codes to be used if
4370218822Sdim   the corresponding instruction is an ALU instruction (ADD or SUB only),
4371218822Sdim   an LDR, an LDRS, or an LDC.  */
4372130561Sobrien
4373218822Sdimstruct group_reloc_table_entry
4374130561Sobrien{
4375218822Sdim  const char *name;
4376218822Sdim  int alu_code;
4377218822Sdim  int ldr_code;
4378218822Sdim  int ldrs_code;
4379218822Sdim  int ldc_code;
4380218822Sdim};
4381130561Sobrien
4382218822Sdimtypedef enum
4383218822Sdim{
4384218822Sdim  /* Varieties of non-ALU group relocation.  */
4385130561Sobrien
4386218822Sdim  GROUP_LDR,
4387218822Sdim  GROUP_LDRS,
4388218822Sdim  GROUP_LDC
4389218822Sdim} group_reloc_type;
4390218822Sdim
4391218822Sdimstatic struct group_reloc_table_entry group_reloc_table[] =
4392218822Sdim  { /* Program counter relative: */
4393218822Sdim    { "pc_g0_nc",
4394218822Sdim      BFD_RELOC_ARM_ALU_PC_G0_NC,	/* ALU */
4395218822Sdim      0,				/* LDR */
4396218822Sdim      0,				/* LDRS */
4397218822Sdim      0 },				/* LDC */
4398218822Sdim    { "pc_g0",
4399218822Sdim      BFD_RELOC_ARM_ALU_PC_G0,		/* ALU */
4400218822Sdim      BFD_RELOC_ARM_LDR_PC_G0,		/* LDR */
4401218822Sdim      BFD_RELOC_ARM_LDRS_PC_G0,		/* LDRS */
4402218822Sdim      BFD_RELOC_ARM_LDC_PC_G0 },	/* LDC */
4403218822Sdim    { "pc_g1_nc",
4404218822Sdim      BFD_RELOC_ARM_ALU_PC_G1_NC,	/* ALU */
4405218822Sdim      0,				/* LDR */
4406218822Sdim      0,				/* LDRS */
4407218822Sdim      0 },				/* LDC */
4408218822Sdim    { "pc_g1",
4409218822Sdim      BFD_RELOC_ARM_ALU_PC_G1,		/* ALU */
4410218822Sdim      BFD_RELOC_ARM_LDR_PC_G1, 		/* LDR */
4411218822Sdim      BFD_RELOC_ARM_LDRS_PC_G1,		/* LDRS */
4412218822Sdim      BFD_RELOC_ARM_LDC_PC_G1 },	/* LDC */
4413218822Sdim    { "pc_g2",
4414218822Sdim      BFD_RELOC_ARM_ALU_PC_G2,		/* ALU */
4415218822Sdim      BFD_RELOC_ARM_LDR_PC_G2,		/* LDR */
4416218822Sdim      BFD_RELOC_ARM_LDRS_PC_G2,		/* LDRS */
4417218822Sdim      BFD_RELOC_ARM_LDC_PC_G2 },	/* LDC */
4418218822Sdim    /* Section base relative */
4419218822Sdim    { "sb_g0_nc",
4420218822Sdim      BFD_RELOC_ARM_ALU_SB_G0_NC,	/* ALU */
4421218822Sdim      0,				/* LDR */
4422218822Sdim      0,				/* LDRS */
4423218822Sdim      0 },				/* LDC */
4424218822Sdim    { "sb_g0",
4425218822Sdim      BFD_RELOC_ARM_ALU_SB_G0,		/* ALU */
4426218822Sdim      BFD_RELOC_ARM_LDR_SB_G0,		/* LDR */
4427218822Sdim      BFD_RELOC_ARM_LDRS_SB_G0,		/* LDRS */
4428218822Sdim      BFD_RELOC_ARM_LDC_SB_G0 },	/* LDC */
4429218822Sdim    { "sb_g1_nc",
4430218822Sdim      BFD_RELOC_ARM_ALU_SB_G1_NC,	/* ALU */
4431218822Sdim      0,				/* LDR */
4432218822Sdim      0,				/* LDRS */
4433218822Sdim      0 },				/* LDC */
4434218822Sdim    { "sb_g1",
4435218822Sdim      BFD_RELOC_ARM_ALU_SB_G1,		/* ALU */
4436218822Sdim      BFD_RELOC_ARM_LDR_SB_G1, 		/* LDR */
4437218822Sdim      BFD_RELOC_ARM_LDRS_SB_G1,		/* LDRS */
4438218822Sdim      BFD_RELOC_ARM_LDC_SB_G1 },	/* LDC */
4439218822Sdim    { "sb_g2",
4440218822Sdim      BFD_RELOC_ARM_ALU_SB_G2,		/* ALU */
4441218822Sdim      BFD_RELOC_ARM_LDR_SB_G2,		/* LDR */
4442218822Sdim      BFD_RELOC_ARM_LDRS_SB_G2,		/* LDRS */
4443218822Sdim      BFD_RELOC_ARM_LDC_SB_G2 }	};	/* LDC */
4444218822Sdim
4445218822Sdim/* Given the address of a pointer pointing to the textual name of a group
4446218822Sdim   relocation as may appear in assembler source, attempt to find its details
4447218822Sdim   in group_reloc_table.  The pointer will be updated to the character after
4448218822Sdim   the trailing colon.  On failure, FAIL will be returned; SUCCESS
4449218822Sdim   otherwise.  On success, *entry will be updated to point at the relevant
4450218822Sdim   group_reloc_table entry. */
4451218822Sdim
4452218822Sdimstatic int
4453218822Sdimfind_group_reloc_table_entry (char **str, struct group_reloc_table_entry **out)
4454218822Sdim{
4455218822Sdim  unsigned int i;
4456218822Sdim  for (i = 0; i < ARRAY_SIZE (group_reloc_table); i++)
4457130561Sobrien    {
4458218822Sdim      int length = strlen (group_reloc_table[i].name);
4459130561Sobrien
4460218822Sdim      if (strncasecmp (group_reloc_table[i].name, *str, length) == 0 &&
4461218822Sdim          (*str)[length] == ':')
4462218822Sdim        {
4463218822Sdim          *out = &group_reloc_table[i];
4464218822Sdim          *str += (length + 1);
4465218822Sdim          return SUCCESS;
4466218822Sdim        }
4467130561Sobrien    }
4468130561Sobrien
4469218822Sdim  return FAIL;
4470130561Sobrien}
4471130561Sobrien
4472218822Sdim/* Parse a <shifter_operand> for an ARM data processing instruction
4473218822Sdim   (as for parse_shifter_operand) where group relocations are allowed:
4474130561Sobrien
4475218822Sdim      #<immediate>
4476218822Sdim      #<immediate>, <rotate>
4477218822Sdim      #:<group_reloc>:<expression>
4478218822Sdim      <Rm>
4479218822Sdim      <Rm>, <shift>
4480218822Sdim
4481218822Sdim   where <group_reloc> is one of the strings defined in group_reloc_table.
4482218822Sdim   The hashes are optional.
4483218822Sdim
4484218822Sdim   Everything else is as for parse_shifter_operand.  */
4485218822Sdim
4486218822Sdimstatic parse_operand_result
4487218822Sdimparse_shifter_operand_group_reloc (char **str, int i)
4488130561Sobrien{
4489218822Sdim  /* Determine if we have the sequence of characters #: or just :
4490218822Sdim     coming next.  If we do, then we check for a group relocation.
4491218822Sdim     If we don't, punt the whole lot to parse_shifter_operand.  */
4492130561Sobrien
4493218822Sdim  if (((*str)[0] == '#' && (*str)[1] == ':')
4494218822Sdim      || (*str)[0] == ':')
4495130561Sobrien    {
4496218822Sdim      struct group_reloc_table_entry *entry;
4497130561Sobrien
4498218822Sdim      if ((*str)[0] == '#')
4499218822Sdim        (*str) += 2;
4500218822Sdim      else
4501218822Sdim        (*str)++;
4502130561Sobrien
4503218822Sdim      /* Try to parse a group relocation.  Anything else is an error.  */
4504218822Sdim      if (find_group_reloc_table_entry (str, &entry) == FAIL)
4505218822Sdim        {
4506218822Sdim          inst.error = _("unknown group relocation");
4507218822Sdim          return PARSE_OPERAND_FAIL_NO_BACKTRACK;
4508218822Sdim        }
4509218822Sdim
4510218822Sdim      /* We now have the group relocation table entry corresponding to
4511218822Sdim         the name in the assembler source.  Next, we parse the expression.  */
4512218822Sdim      if (my_get_expression (&inst.reloc.exp, str, GE_NO_PREFIX))
4513218822Sdim        return PARSE_OPERAND_FAIL_NO_BACKTRACK;
4514218822Sdim
4515218822Sdim      /* Record the relocation type (always the ALU variant here).  */
4516218822Sdim      inst.reloc.type = entry->alu_code;
4517218822Sdim      assert (inst.reloc.type != 0);
4518218822Sdim
4519218822Sdim      return PARSE_OPERAND_SUCCESS;
4520130561Sobrien    }
4521218822Sdim  else
4522218822Sdim    return parse_shifter_operand (str, i) == SUCCESS
4523218822Sdim           ? PARSE_OPERAND_SUCCESS : PARSE_OPERAND_FAIL;
4524130561Sobrien
4525218822Sdim  /* Never reached.  */
4526130561Sobrien}
4527130561Sobrien
4528218822Sdim/* Parse all forms of an ARM address expression.  Information is written
4529218822Sdim   to inst.operands[i] and/or inst.reloc.
4530130561Sobrien
4531218822Sdim   Preindexed addressing (.preind=1):
4532130561Sobrien
4533218822Sdim   [Rn, #offset]       .reg=Rn .reloc.exp=offset
4534218822Sdim   [Rn, +/-Rm]	       .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
4535218822Sdim   [Rn, +/-Rm, shift]  .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
4536218822Sdim		       .shift_kind=shift .reloc.exp=shift_imm
4537130561Sobrien
4538218822Sdim   These three may have a trailing ! which causes .writeback to be set also.
4539130561Sobrien
4540218822Sdim   Postindexed addressing (.postind=1, .writeback=1):
4541218822Sdim
4542218822Sdim   [Rn], #offset       .reg=Rn .reloc.exp=offset
4543218822Sdim   [Rn], +/-Rm	       .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
4544218822Sdim   [Rn], +/-Rm, shift  .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
4545218822Sdim		       .shift_kind=shift .reloc.exp=shift_imm
4546218822Sdim
4547218822Sdim   Unindexed addressing (.preind=0, .postind=0):
4548218822Sdim
4549218822Sdim   [Rn], {option}      .reg=Rn .imm=option .immisreg=0
4550218822Sdim
4551218822Sdim   Other:
4552218822Sdim
4553218822Sdim   [Rn]{!}	       shorthand for [Rn,#0]{!}
4554218822Sdim   =immediate	       .isreg=0 .reloc.exp=immediate
4555218822Sdim   label	       .reg=PC .reloc.pc_rel=1 .reloc.exp=label
4556218822Sdim
4557218822Sdim  It is the caller's responsibility to check for addressing modes not
4558218822Sdim  supported by the instruction, and to set inst.reloc.type.  */
4559218822Sdim
4560218822Sdimstatic parse_operand_result
4561218822Sdimparse_address_main (char **str, int i, int group_relocations,
4562218822Sdim                    group_reloc_type group_type)
4563130561Sobrien{
4564218822Sdim  char *p = *str;
4565218822Sdim  int reg;
4566130561Sobrien
4567218822Sdim  if (skip_past_char (&p, '[') == FAIL)
4568130561Sobrien    {
4569218822Sdim      if (skip_past_char (&p, '=') == FAIL)
4570218822Sdim	{
4571218822Sdim	  /* bare address - translate to PC-relative offset */
4572218822Sdim	  inst.reloc.pc_rel = 1;
4573218822Sdim	  inst.operands[i].reg = REG_PC;
4574218822Sdim	  inst.operands[i].isreg = 1;
4575218822Sdim	  inst.operands[i].preind = 1;
4576218822Sdim	}
4577218822Sdim      /* else a load-constant pseudo op, no special treatment needed here */
4578218822Sdim
4579218822Sdim      if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX))
4580218822Sdim	return PARSE_OPERAND_FAIL;
4581218822Sdim
4582218822Sdim      *str = p;
4583218822Sdim      return PARSE_OPERAND_SUCCESS;
4584130561Sobrien    }
4585218822Sdim
4586218822Sdim  if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
4587130561Sobrien    {
4588218822Sdim      inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
4589218822Sdim      return PARSE_OPERAND_FAIL;
4590130561Sobrien    }
4591218822Sdim  inst.operands[i].reg = reg;
4592218822Sdim  inst.operands[i].isreg = 1;
4593130561Sobrien
4594218822Sdim  if (skip_past_comma (&p) == SUCCESS)
4595130561Sobrien    {
4596218822Sdim      inst.operands[i].preind = 1;
4597218822Sdim
4598218822Sdim      if (*p == '+') p++;
4599218822Sdim      else if (*p == '-') p++, inst.operands[i].negative = 1;
4600218822Sdim
4601218822Sdim      if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL)
4602218822Sdim	{
4603218822Sdim	  inst.operands[i].imm = reg;
4604218822Sdim	  inst.operands[i].immisreg = 1;
4605218822Sdim
4606218822Sdim	  if (skip_past_comma (&p) == SUCCESS)
4607218822Sdim	    if (parse_shift (&p, i, SHIFT_IMMEDIATE) == FAIL)
4608218822Sdim	      return PARSE_OPERAND_FAIL;
4609218822Sdim	}
4610218822Sdim      else if (skip_past_char (&p, ':') == SUCCESS)
4611218822Sdim        {
4612218822Sdim          /* FIXME: '@' should be used here, but it's filtered out by generic
4613218822Sdim             code before we get to see it here. This may be subject to
4614218822Sdim             change.  */
4615218822Sdim          expressionS exp;
4616218822Sdim          my_get_expression (&exp, &p, GE_NO_PREFIX);
4617218822Sdim          if (exp.X_op != O_constant)
4618218822Sdim            {
4619218822Sdim              inst.error = _("alignment must be constant");
4620218822Sdim              return PARSE_OPERAND_FAIL;
4621218822Sdim            }
4622218822Sdim          inst.operands[i].imm = exp.X_add_number << 8;
4623218822Sdim          inst.operands[i].immisalign = 1;
4624218822Sdim          /* Alignments are not pre-indexes.  */
4625218822Sdim          inst.operands[i].preind = 0;
4626218822Sdim        }
4627218822Sdim      else
4628218822Sdim	{
4629218822Sdim	  if (inst.operands[i].negative)
4630218822Sdim	    {
4631218822Sdim	      inst.operands[i].negative = 0;
4632218822Sdim	      p--;
4633218822Sdim	    }
4634218822Sdim
4635218822Sdim	  if (group_relocations &&
4636218822Sdim              ((*p == '#' && *(p + 1) == ':') || *p == ':'))
4637218822Sdim
4638218822Sdim	    {
4639218822Sdim	      struct group_reloc_table_entry *entry;
4640218822Sdim
4641218822Sdim              /* Skip over the #: or : sequence.  */
4642218822Sdim              if (*p == '#')
4643218822Sdim                p += 2;
4644218822Sdim              else
4645218822Sdim                p++;
4646218822Sdim
4647218822Sdim	      /* Try to parse a group relocation.  Anything else is an
4648218822Sdim                 error.  */
4649218822Sdim	      if (find_group_reloc_table_entry (&p, &entry) == FAIL)
4650218822Sdim		{
4651218822Sdim		  inst.error = _("unknown group relocation");
4652218822Sdim		  return PARSE_OPERAND_FAIL_NO_BACKTRACK;
4653218822Sdim		}
4654218822Sdim
4655218822Sdim	      /* We now have the group relocation table entry corresponding to
4656218822Sdim		 the name in the assembler source.  Next, we parse the
4657218822Sdim                 expression.  */
4658218822Sdim	      if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX))
4659218822Sdim		return PARSE_OPERAND_FAIL_NO_BACKTRACK;
4660218822Sdim
4661218822Sdim	      /* Record the relocation type.  */
4662218822Sdim              switch (group_type)
4663218822Sdim                {
4664218822Sdim                  case GROUP_LDR:
4665218822Sdim	            inst.reloc.type = entry->ldr_code;
4666218822Sdim                    break;
4667218822Sdim
4668218822Sdim                  case GROUP_LDRS:
4669218822Sdim	            inst.reloc.type = entry->ldrs_code;
4670218822Sdim                    break;
4671218822Sdim
4672218822Sdim                  case GROUP_LDC:
4673218822Sdim	            inst.reloc.type = entry->ldc_code;
4674218822Sdim                    break;
4675218822Sdim
4676218822Sdim                  default:
4677218822Sdim                    assert (0);
4678218822Sdim                }
4679218822Sdim
4680218822Sdim              if (inst.reloc.type == 0)
4681218822Sdim		{
4682218822Sdim		  inst.error = _("this group relocation is not allowed on this instruction");
4683218822Sdim		  return PARSE_OPERAND_FAIL_NO_BACKTRACK;
4684218822Sdim		}
4685218822Sdim            }
4686218822Sdim          else
4687218822Sdim	    if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
4688218822Sdim	      return PARSE_OPERAND_FAIL;
4689218822Sdim	}
4690130561Sobrien    }
4691218822Sdim
4692218822Sdim  if (skip_past_char (&p, ']') == FAIL)
4693130561Sobrien    {
4694218822Sdim      inst.error = _("']' expected");
4695218822Sdim      return PARSE_OPERAND_FAIL;
4696130561Sobrien    }
4697218822Sdim
4698218822Sdim  if (skip_past_char (&p, '!') == SUCCESS)
4699218822Sdim    inst.operands[i].writeback = 1;
4700218822Sdim
4701218822Sdim  else if (skip_past_comma (&p) == SUCCESS)
4702130561Sobrien    {
4703218822Sdim      if (skip_past_char (&p, '{') == SUCCESS)
4704218822Sdim	{
4705218822Sdim	  /* [Rn], {expr} - unindexed, with option */
4706218822Sdim	  if (parse_immediate (&p, &inst.operands[i].imm,
4707218822Sdim			       0, 255, TRUE) == FAIL)
4708218822Sdim	    return PARSE_OPERAND_FAIL;
4709218822Sdim
4710218822Sdim	  if (skip_past_char (&p, '}') == FAIL)
4711218822Sdim	    {
4712218822Sdim	      inst.error = _("'}' expected at end of 'option' field");
4713218822Sdim	      return PARSE_OPERAND_FAIL;
4714218822Sdim	    }
4715218822Sdim	  if (inst.operands[i].preind)
4716218822Sdim	    {
4717218822Sdim	      inst.error = _("cannot combine index with option");
4718218822Sdim	      return PARSE_OPERAND_FAIL;
4719218822Sdim	    }
4720218822Sdim	  *str = p;
4721218822Sdim	  return PARSE_OPERAND_SUCCESS;
4722218822Sdim	}
4723218822Sdim      else
4724218822Sdim	{
4725218822Sdim	  inst.operands[i].postind = 1;
4726218822Sdim	  inst.operands[i].writeback = 1;
4727218822Sdim
4728218822Sdim	  if (inst.operands[i].preind)
4729218822Sdim	    {
4730218822Sdim	      inst.error = _("cannot combine pre- and post-indexing");
4731218822Sdim	      return PARSE_OPERAND_FAIL;
4732218822Sdim	    }
4733218822Sdim
4734218822Sdim	  if (*p == '+') p++;
4735218822Sdim	  else if (*p == '-') p++, inst.operands[i].negative = 1;
4736218822Sdim
4737218822Sdim	  if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL)
4738218822Sdim	    {
4739218822Sdim              /* We might be using the immediate for alignment already. If we
4740218822Sdim                 are, OR the register number into the low-order bits.  */
4741218822Sdim              if (inst.operands[i].immisalign)
4742218822Sdim	        inst.operands[i].imm |= reg;
4743218822Sdim              else
4744218822Sdim                inst.operands[i].imm = reg;
4745218822Sdim	      inst.operands[i].immisreg = 1;
4746218822Sdim
4747218822Sdim	      if (skip_past_comma (&p) == SUCCESS)
4748218822Sdim		if (parse_shift (&p, i, SHIFT_IMMEDIATE) == FAIL)
4749218822Sdim		  return PARSE_OPERAND_FAIL;
4750218822Sdim	    }
4751218822Sdim	  else
4752218822Sdim	    {
4753218822Sdim	      if (inst.operands[i].negative)
4754218822Sdim		{
4755218822Sdim		  inst.operands[i].negative = 0;
4756218822Sdim		  p--;
4757218822Sdim		}
4758218822Sdim	      if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
4759218822Sdim		return PARSE_OPERAND_FAIL;
4760218822Sdim	    }
4761218822Sdim	}
4762130561Sobrien    }
4763130561Sobrien
4764218822Sdim  /* If at this point neither .preind nor .postind is set, we have a
4765218822Sdim     bare [Rn]{!}, which is shorthand for [Rn,#0]{!}.  */
4766218822Sdim  if (inst.operands[i].preind == 0 && inst.operands[i].postind == 0)
4767130561Sobrien    {
4768218822Sdim      inst.operands[i].preind = 1;
4769218822Sdim      inst.reloc.exp.X_op = O_constant;
4770218822Sdim      inst.reloc.exp.X_add_number = 0;
4771130561Sobrien    }
4772218822Sdim  *str = p;
4773218822Sdim  return PARSE_OPERAND_SUCCESS;
4774130561Sobrien}
4775130561Sobrien
4776218822Sdimstatic int
4777218822Sdimparse_address (char **str, int i)
4778130561Sobrien{
4779218822Sdim  return parse_address_main (str, i, 0, 0) == PARSE_OPERAND_SUCCESS
4780218822Sdim         ? SUCCESS : FAIL;
4781130561Sobrien}
4782130561Sobrien
4783218822Sdimstatic parse_operand_result
4784218822Sdimparse_address_group_reloc (char **str, int i, group_reloc_type type)
4785130561Sobrien{
4786218822Sdim  return parse_address_main (str, i, 1, type);
4787130561Sobrien}
4788130561Sobrien
4789218822Sdim/* Parse an operand for a MOVW or MOVT instruction.  */
4790218822Sdimstatic int
4791218822Sdimparse_half (char **str)
4792130561Sobrien{
4793218822Sdim  char * p;
4794218822Sdim
4795218822Sdim  p = *str;
4796218822Sdim  skip_past_char (&p, '#');
4797218822Sdim  if (strncasecmp (p, ":lower16:", 9) == 0)
4798218822Sdim    inst.reloc.type = BFD_RELOC_ARM_MOVW;
4799218822Sdim  else if (strncasecmp (p, ":upper16:", 9) == 0)
4800218822Sdim    inst.reloc.type = BFD_RELOC_ARM_MOVT;
4801130561Sobrien
4802218822Sdim  if (inst.reloc.type != BFD_RELOC_UNUSED)
4803130561Sobrien    {
4804218822Sdim      p += 9;
4805218822Sdim      skip_whitespace(p);
4806130561Sobrien    }
4807218822Sdim
4808218822Sdim  if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX))
4809218822Sdim    return FAIL;
4810218822Sdim
4811218822Sdim  if (inst.reloc.type == BFD_RELOC_UNUSED)
4812130561Sobrien    {
4813218822Sdim      if (inst.reloc.exp.X_op != O_constant)
4814218822Sdim	{
4815218822Sdim	  inst.error = _("constant expression expected");
4816218822Sdim	  return FAIL;
4817218822Sdim	}
4818218822Sdim      if (inst.reloc.exp.X_add_number < 0
4819218822Sdim	  || inst.reloc.exp.X_add_number > 0xffff)
4820218822Sdim	{
4821218822Sdim	  inst.error = _("immediate value out of range");
4822218822Sdim	  return FAIL;
4823218822Sdim	}
4824130561Sobrien    }
4825218822Sdim  *str = p;
4826218822Sdim  return SUCCESS;
4827218822Sdim}
4828130561Sobrien
4829218822Sdim/* Miscellaneous. */
4830218822Sdim
4831218822Sdim/* Parse a PSR flag operand.  The value returned is FAIL on syntax error,
4832218822Sdim   or a bitmask suitable to be or-ed into the ARM msr instruction.  */
4833218822Sdimstatic int
4834218822Sdimparse_psr (char **str)
4835218822Sdim{
4836218822Sdim  char *p;
4837218822Sdim  unsigned long psr_field;
4838218822Sdim  const struct asm_psr *psr;
4839218822Sdim  char *start;
4840218822Sdim
4841218822Sdim  /* CPSR's and SPSR's can now be lowercase.  This is just a convenience
4842218822Sdim     feature for ease of use and backwards compatibility.  */
4843218822Sdim  p = *str;
4844218822Sdim  if (strncasecmp (p, "SPSR", 4) == 0)
4845218822Sdim    psr_field = SPSR_BIT;
4846218822Sdim  else if (strncasecmp (p, "CPSR", 4) == 0)
4847218822Sdim    psr_field = 0;
4848130561Sobrien  else
4849130561Sobrien    {
4850218822Sdim      start = p;
4851218822Sdim      do
4852218822Sdim	p++;
4853218822Sdim      while (ISALNUM (*p) || *p == '_');
4854218822Sdim
4855218822Sdim      psr = hash_find_n (arm_v7m_psr_hsh, start, p - start);
4856218822Sdim      if (!psr)
4857218822Sdim	return FAIL;
4858218822Sdim
4859218822Sdim      *str = p;
4860218822Sdim      return psr->field;
4861130561Sobrien    }
4862218822Sdim
4863218822Sdim  p += 4;
4864218822Sdim  if (*p == '_')
4865130561Sobrien    {
4866218822Sdim      /* A suffix follows.  */
4867218822Sdim      p++;
4868218822Sdim      start = p;
4869218822Sdim
4870218822Sdim      do
4871218822Sdim	p++;
4872218822Sdim      while (ISALNUM (*p) || *p == '_');
4873218822Sdim
4874218822Sdim      psr = hash_find_n (arm_psr_hsh, start, p - start);
4875218822Sdim      if (!psr)
4876218822Sdim	goto error;
4877218822Sdim
4878218822Sdim      psr_field |= psr->field;
4879130561Sobrien    }
4880218822Sdim  else
4881130561Sobrien    {
4882218822Sdim      if (ISALNUM (*p))
4883218822Sdim	goto error;    /* Garbage after "[CS]PSR".  */
4884218822Sdim
4885218822Sdim      psr_field |= (PSR_c | PSR_f);
4886130561Sobrien    }
4887218822Sdim  *str = p;
4888218822Sdim  return psr_field;
4889130561Sobrien
4890218822Sdim error:
4891218822Sdim  inst.error = _("flag for {c}psr instruction expected");
4892218822Sdim  return FAIL;
4893130561Sobrien}
4894130561Sobrien
4895218822Sdim/* Parse the flags argument to CPSI[ED].  Returns FAIL on error, or a
4896218822Sdim   value suitable for splatting into the AIF field of the instruction.	*/
4897130561Sobrien
4898218822Sdimstatic int
4899218822Sdimparse_cps_flags (char **str)
4900130561Sobrien{
4901218822Sdim  int val = 0;
4902218822Sdim  int saw_a_flag = 0;
4903218822Sdim  char *s = *str;
4904130561Sobrien
4905218822Sdim  for (;;)
4906218822Sdim    switch (*s++)
4907218822Sdim      {
4908218822Sdim      case '\0': case ',':
4909218822Sdim	goto done;
4910130561Sobrien
4911218822Sdim      case 'a': case 'A': saw_a_flag = 1; val |= 0x4; break;
4912218822Sdim      case 'i': case 'I': saw_a_flag = 1; val |= 0x2; break;
4913218822Sdim      case 'f': case 'F': saw_a_flag = 1; val |= 0x1; break;
4914130561Sobrien
4915218822Sdim      default:
4916218822Sdim	inst.error = _("unrecognized CPS flag");
4917218822Sdim	return FAIL;
4918218822Sdim      }
4919218822Sdim
4920218822Sdim done:
4921218822Sdim  if (saw_a_flag == 0)
4922130561Sobrien    {
4923218822Sdim      inst.error = _("missing CPS flags");
4924218822Sdim      return FAIL;
4925130561Sobrien    }
4926130561Sobrien
4927218822Sdim  *str = s - 1;
4928218822Sdim  return val;
4929130561Sobrien}
4930130561Sobrien
4931218822Sdim/* Parse an endian specifier ("BE" or "LE", case insensitive);
4932218822Sdim   returns 0 for big-endian, 1 for little-endian, FAIL for an error.  */
4933130561Sobrien
4934218822Sdimstatic int
4935218822Sdimparse_endian_specifier (char **str)
4936130561Sobrien{
4937218822Sdim  int little_endian;
4938218822Sdim  char *s = *str;
4939218822Sdim
4940218822Sdim  if (strncasecmp (s, "BE", 2))
4941218822Sdim    little_endian = 0;
4942218822Sdim  else if (strncasecmp (s, "LE", 2))
4943218822Sdim    little_endian = 1;
4944218822Sdim  else
4945130561Sobrien    {
4946218822Sdim      inst.error = _("valid endian specifiers are be or le");
4947218822Sdim      return FAIL;
4948130561Sobrien    }
4949130561Sobrien
4950218822Sdim  if (ISALNUM (s[2]) || s[2] == '_')
4951130561Sobrien    {
4952218822Sdim      inst.error = _("valid endian specifiers are be or le");
4953218822Sdim      return FAIL;
4954130561Sobrien    }
4955130561Sobrien
4956218822Sdim  *str = s + 2;
4957218822Sdim  return little_endian;
4958130561Sobrien}
4959130561Sobrien
4960218822Sdim/* Parse a rotation specifier: ROR #0, #8, #16, #24.  *val receives a
4961218822Sdim   value suitable for poking into the rotate field of an sxt or sxta
4962218822Sdim   instruction, or FAIL on error.  */
4963130561Sobrien
4964218822Sdimstatic int
4965218822Sdimparse_ror (char **str)
4966130561Sobrien{
4967218822Sdim  int rot;
4968218822Sdim  char *s = *str;
4969218822Sdim
4970218822Sdim  if (strncasecmp (s, "ROR", 3) == 0)
4971218822Sdim    s += 3;
4972218822Sdim  else
4973130561Sobrien    {
4974218822Sdim      inst.error = _("missing rotation field after comma");
4975218822Sdim      return FAIL;
4976130561Sobrien    }
4977218822Sdim
4978218822Sdim  if (parse_immediate (&s, &rot, 0, 24, FALSE) == FAIL)
4979218822Sdim    return FAIL;
4980218822Sdim
4981218822Sdim  switch (rot)
4982130561Sobrien    {
4983218822Sdim    case  0: *str = s; return 0x0;
4984218822Sdim    case  8: *str = s; return 0x1;
4985218822Sdim    case 16: *str = s; return 0x2;
4986218822Sdim    case 24: *str = s; return 0x3;
4987218822Sdim
4988218822Sdim    default:
4989218822Sdim      inst.error = _("rotation can only be 0, 8, 16, or 24");
4990218822Sdim      return FAIL;
4991130561Sobrien    }
4992218822Sdim}
4993130561Sobrien
4994218822Sdim/* Parse a conditional code (from conds[] below).  The value returned is in the
4995218822Sdim   range 0 .. 14, or FAIL.  */
4996218822Sdimstatic int
4997218822Sdimparse_cond (char **str)
4998218822Sdim{
4999218822Sdim  char *p, *q;
5000218822Sdim  const struct asm_cond *c;
5001130561Sobrien
5002218822Sdim  p = q = *str;
5003218822Sdim  while (ISALPHA (*q))
5004218822Sdim    q++;
5005130561Sobrien
5006218822Sdim  c = hash_find_n (arm_cond_hsh, p, q - p);
5007218822Sdim  if (!c)
5008218822Sdim    {
5009218822Sdim      inst.error = _("condition required");
5010218822Sdim      return FAIL;
5011218822Sdim    }
5012130561Sobrien
5013218822Sdim  *str = q;
5014218822Sdim  return c->value;
5015130561Sobrien}
5016130561Sobrien
5017218822Sdim/* Parse an option for a barrier instruction.  Returns the encoding for the
5018218822Sdim   option, or FAIL.  */
5019130561Sobrienstatic int
5020218822Sdimparse_barrier (char **str)
5021130561Sobrien{
5022218822Sdim  char *p, *q;
5023218822Sdim  const struct asm_barrier_opt *o;
5024130561Sobrien
5025218822Sdim  p = q = *str;
5026218822Sdim  while (ISALPHA (*q))
5027218822Sdim    q++;
5028130561Sobrien
5029218822Sdim  o = hash_find_n (arm_barrier_opt_hsh, p, q - p);
5030218822Sdim  if (!o)
5031218822Sdim    return FAIL;
5032130561Sobrien
5033218822Sdim  *str = q;
5034218822Sdim  return o->value;
5035130561Sobrien}
5036130561Sobrien
5037218822Sdim/* Parse the operands of a table branch instruction.  Similar to a memory
5038218822Sdim   operand.  */
5039218822Sdimstatic int
5040218822Sdimparse_tb (char **str)
5041218822Sdim{
5042218822Sdim  char * p = *str;
5043218822Sdim  int reg;
5044130561Sobrien
5045218822Sdim  if (skip_past_char (&p, '[') == FAIL)
5046130561Sobrien    {
5047218822Sdim      inst.error = _("'[' expected");
5048218822Sdim      return FAIL;
5049130561Sobrien    }
5050130561Sobrien
5051218822Sdim  if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
5052130561Sobrien    {
5053218822Sdim      inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
5054218822Sdim      return FAIL;
5055130561Sobrien    }
5056218822Sdim  inst.operands[0].reg = reg;
5057218822Sdim
5058218822Sdim  if (skip_past_comma (&p) == FAIL)
5059130561Sobrien    {
5060218822Sdim      inst.error = _("',' expected");
5061218822Sdim      return FAIL;
5062130561Sobrien    }
5063130561Sobrien
5064218822Sdim  if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
5065130561Sobrien    {
5066218822Sdim      inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
5067218822Sdim      return FAIL;
5068130561Sobrien    }
5069218822Sdim  inst.operands[0].imm = reg;
5070218822Sdim
5071218822Sdim  if (skip_past_comma (&p) == SUCCESS)
5072130561Sobrien    {
5073218822Sdim      if (parse_shift (&p, 0, SHIFT_LSL_IMMEDIATE) == FAIL)
5074218822Sdim	return FAIL;
5075218822Sdim      if (inst.reloc.exp.X_add_number != 1)
5076218822Sdim	{
5077218822Sdim	  inst.error = _("invalid shift");
5078218822Sdim	  return FAIL;
5079218822Sdim	}
5080218822Sdim      inst.operands[0].shifted = 1;
5081130561Sobrien    }
5082218822Sdim
5083218822Sdim  if (skip_past_char (&p, ']') == FAIL)
5084130561Sobrien    {
5085218822Sdim      inst.error = _("']' expected");
5086218822Sdim      return FAIL;
5087130561Sobrien    }
5088218822Sdim  *str = p;
5089218822Sdim  return SUCCESS;
5090218822Sdim}
5091130561Sobrien
5092218822Sdim/* Parse the operands of a Neon VMOV instruction. See do_neon_mov for more
5093218822Sdim   information on the types the operands can take and how they are encoded.
5094218822Sdim   Up to four operands may be read; this function handles setting the
5095218822Sdim   ".present" field for each read operand itself.
5096218822Sdim   Updates STR and WHICH_OPERAND if parsing is successful and returns SUCCESS,
5097218822Sdim   else returns FAIL.  */
5098218822Sdim
5099218822Sdimstatic int
5100218822Sdimparse_neon_mov (char **str, int *which_operand)
5101218822Sdim{
5102218822Sdim  int i = *which_operand, val;
5103218822Sdim  enum arm_reg_type rtype;
5104218822Sdim  char *ptr = *str;
5105218822Sdim  struct neon_type_el optype;
5106130561Sobrien
5107218822Sdim  if ((val = parse_scalar (&ptr, 8, &optype)) != FAIL)
5108130561Sobrien    {
5109218822Sdim      /* Case 4: VMOV<c><q>.<size> <Dn[x]>, <Rd>.  */
5110218822Sdim      inst.operands[i].reg = val;
5111218822Sdim      inst.operands[i].isscalar = 1;
5112218822Sdim      inst.operands[i].vectype = optype;
5113218822Sdim      inst.operands[i++].present = 1;
5114130561Sobrien
5115218822Sdim      if (skip_past_comma (&ptr) == FAIL)
5116218822Sdim        goto wanted_comma;
5117130561Sobrien
5118218822Sdim      if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) == FAIL)
5119218822Sdim        goto wanted_arm;
5120218822Sdim
5121218822Sdim      inst.operands[i].reg = val;
5122218822Sdim      inst.operands[i].isreg = 1;
5123218822Sdim      inst.operands[i].present = 1;
5124130561Sobrien    }
5125218822Sdim  else if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_NSDQ, &rtype, &optype))
5126218822Sdim           != FAIL)
5127218822Sdim    {
5128218822Sdim      /* Cases 0, 1, 2, 3, 5 (D only).  */
5129218822Sdim      if (skip_past_comma (&ptr) == FAIL)
5130218822Sdim        goto wanted_comma;
5131218822Sdim
5132218822Sdim      inst.operands[i].reg = val;
5133218822Sdim      inst.operands[i].isreg = 1;
5134218822Sdim      inst.operands[i].isquad = (rtype == REG_TYPE_NQ);
5135218822Sdim      inst.operands[i].issingle = (rtype == REG_TYPE_VFS);
5136218822Sdim      inst.operands[i].isvec = 1;
5137218822Sdim      inst.operands[i].vectype = optype;
5138218822Sdim      inst.operands[i++].present = 1;
5139130561Sobrien
5140218822Sdim      if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) != FAIL)
5141218822Sdim        {
5142218822Sdim          /* Case 5: VMOV<c><q> <Dm>, <Rd>, <Rn>.
5143218822Sdim             Case 13: VMOV <Sd>, <Rm>  */
5144218822Sdim          inst.operands[i].reg = val;
5145218822Sdim          inst.operands[i].isreg = 1;
5146218822Sdim          inst.operands[i].present = 1;
5147130561Sobrien
5148218822Sdim          if (rtype == REG_TYPE_NQ)
5149218822Sdim            {
5150218822Sdim              first_error (_("can't use Neon quad register here"));
5151218822Sdim              return FAIL;
5152218822Sdim            }
5153218822Sdim          else if (rtype != REG_TYPE_VFS)
5154218822Sdim            {
5155218822Sdim              i++;
5156218822Sdim              if (skip_past_comma (&ptr) == FAIL)
5157218822Sdim                goto wanted_comma;
5158218822Sdim              if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) == FAIL)
5159218822Sdim                goto wanted_arm;
5160218822Sdim              inst.operands[i].reg = val;
5161218822Sdim              inst.operands[i].isreg = 1;
5162218822Sdim              inst.operands[i].present = 1;
5163218822Sdim            }
5164218822Sdim        }
5165218822Sdim      else if (parse_qfloat_immediate (&ptr, &inst.operands[i].imm) == SUCCESS)
5166218822Sdim          /* Case 2: VMOV<c><q>.<dt> <Qd>, #<float-imm>
5167218822Sdim             Case 3: VMOV<c><q>.<dt> <Dd>, #<float-imm>
5168218822Sdim             Case 10: VMOV.F32 <Sd>, #<imm>
5169218822Sdim             Case 11: VMOV.F64 <Dd>, #<imm>  */
5170218822Sdim        inst.operands[i].immisfloat = 1;
5171218822Sdim      else if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_NSDQ, &rtype,
5172218822Sdim                                           &optype)) != FAIL)
5173218822Sdim        {
5174218822Sdim          /* Case 0: VMOV<c><q> <Qd>, <Qm>
5175218822Sdim             Case 1: VMOV<c><q> <Dd>, <Dm>
5176218822Sdim             Case 8: VMOV.F32 <Sd>, <Sm>
5177218822Sdim             Case 15: VMOV <Sd>, <Se>, <Rn>, <Rm>  */
5178130561Sobrien
5179218822Sdim          inst.operands[i].reg = val;
5180218822Sdim          inst.operands[i].isreg = 1;
5181218822Sdim          inst.operands[i].isquad = (rtype == REG_TYPE_NQ);
5182218822Sdim          inst.operands[i].issingle = (rtype == REG_TYPE_VFS);
5183218822Sdim          inst.operands[i].isvec = 1;
5184218822Sdim          inst.operands[i].vectype = optype;
5185218822Sdim          inst.operands[i].present = 1;
5186218822Sdim
5187218822Sdim          if (skip_past_comma (&ptr) == SUCCESS)
5188218822Sdim            {
5189218822Sdim              /* Case 15.  */
5190218822Sdim              i++;
5191130561Sobrien
5192218822Sdim              if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) == FAIL)
5193218822Sdim                goto wanted_arm;
5194218822Sdim
5195218822Sdim              inst.operands[i].reg = val;
5196218822Sdim              inst.operands[i].isreg = 1;
5197218822Sdim              inst.operands[i++].present = 1;
5198218822Sdim
5199218822Sdim              if (skip_past_comma (&ptr) == FAIL)
5200218822Sdim                goto wanted_comma;
5201218822Sdim
5202218822Sdim              if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) == FAIL)
5203218822Sdim                goto wanted_arm;
5204218822Sdim
5205218822Sdim              inst.operands[i].reg = val;
5206218822Sdim              inst.operands[i].isreg = 1;
5207218822Sdim              inst.operands[i++].present = 1;
5208218822Sdim            }
5209218822Sdim        }
5210248459Sandrew      else if (parse_big_immediate (&ptr, i) == SUCCESS)
5211248459Sandrew          /* Case 2: VMOV<c><q>.<dt> <Qd>, #<imm>
5212248459Sandrew             Case 3: VMOV<c><q>.<dt> <Dd>, #<imm>  */
5213248459Sandrew        ;
5214218822Sdim      else
5215218822Sdim        {
5216218822Sdim          first_error (_("expected <Rm> or <Dm> or <Qm> operand"));
5217218822Sdim          return FAIL;
5218218822Sdim        }
5219130561Sobrien    }
5220218822Sdim  else if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) != FAIL)
5221130561Sobrien    {
5222218822Sdim      /* Cases 6, 7.  */
5223218822Sdim      inst.operands[i].reg = val;
5224218822Sdim      inst.operands[i].isreg = 1;
5225218822Sdim      inst.operands[i++].present = 1;
5226218822Sdim
5227218822Sdim      if (skip_past_comma (&ptr) == FAIL)
5228218822Sdim        goto wanted_comma;
5229218822Sdim
5230218822Sdim      if ((val = parse_scalar (&ptr, 8, &optype)) != FAIL)
5231218822Sdim        {
5232218822Sdim          /* Case 6: VMOV<c><q>.<dt> <Rd>, <Dn[x]>  */
5233218822Sdim          inst.operands[i].reg = val;
5234218822Sdim          inst.operands[i].isscalar = 1;
5235218822Sdim          inst.operands[i].present = 1;
5236218822Sdim          inst.operands[i].vectype = optype;
5237218822Sdim        }
5238218822Sdim      else if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) != FAIL)
5239218822Sdim        {
5240218822Sdim          /* Case 7: VMOV<c><q> <Rd>, <Rn>, <Dm>  */
5241218822Sdim          inst.operands[i].reg = val;
5242218822Sdim          inst.operands[i].isreg = 1;
5243218822Sdim          inst.operands[i++].present = 1;
5244218822Sdim
5245218822Sdim          if (skip_past_comma (&ptr) == FAIL)
5246218822Sdim            goto wanted_comma;
5247218822Sdim
5248218822Sdim          if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_VFSD, &rtype, &optype))
5249218822Sdim              == FAIL)
5250218822Sdim            {
5251218822Sdim              first_error (_(reg_expected_msgs[REG_TYPE_VFSD]));
5252218822Sdim              return FAIL;
5253218822Sdim            }
5254218822Sdim
5255218822Sdim          inst.operands[i].reg = val;
5256218822Sdim          inst.operands[i].isreg = 1;
5257218822Sdim          inst.operands[i].isvec = 1;
5258218822Sdim          inst.operands[i].issingle = (rtype == REG_TYPE_VFS);
5259218822Sdim          inst.operands[i].vectype = optype;
5260218822Sdim          inst.operands[i].present = 1;
5261218822Sdim
5262218822Sdim          if (rtype == REG_TYPE_VFS)
5263218822Sdim            {
5264218822Sdim              /* Case 14.  */
5265218822Sdim              i++;
5266218822Sdim              if (skip_past_comma (&ptr) == FAIL)
5267218822Sdim                goto wanted_comma;
5268218822Sdim              if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_VFS, NULL,
5269218822Sdim                                              &optype)) == FAIL)
5270218822Sdim                {
5271218822Sdim                  first_error (_(reg_expected_msgs[REG_TYPE_VFS]));
5272218822Sdim                  return FAIL;
5273218822Sdim                }
5274218822Sdim              inst.operands[i].reg = val;
5275218822Sdim              inst.operands[i].isreg = 1;
5276218822Sdim              inst.operands[i].isvec = 1;
5277218822Sdim              inst.operands[i].issingle = 1;
5278218822Sdim              inst.operands[i].vectype = optype;
5279218822Sdim              inst.operands[i].present = 1;
5280218822Sdim            }
5281218822Sdim        }
5282218822Sdim      else if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_VFS, NULL, &optype))
5283218822Sdim               != FAIL)
5284218822Sdim        {
5285218822Sdim          /* Case 13.  */
5286218822Sdim          inst.operands[i].reg = val;
5287218822Sdim          inst.operands[i].isreg = 1;
5288218822Sdim          inst.operands[i].isvec = 1;
5289218822Sdim          inst.operands[i].issingle = 1;
5290218822Sdim          inst.operands[i].vectype = optype;
5291218822Sdim          inst.operands[i++].present = 1;
5292218822Sdim        }
5293130561Sobrien    }
5294130561Sobrien  else
5295130561Sobrien    {
5296218822Sdim      first_error (_("parse error"));
5297218822Sdim      return FAIL;
5298130561Sobrien    }
5299130561Sobrien
5300218822Sdim  /* Successfully parsed the operands. Update args.  */
5301218822Sdim  *which_operand = i;
5302218822Sdim  *str = ptr;
5303218822Sdim  return SUCCESS;
5304130561Sobrien
5305218822Sdim  wanted_comma:
5306218822Sdim  first_error (_("expected comma"));
5307218822Sdim  return FAIL;
5308130561Sobrien
5309218822Sdim  wanted_arm:
5310218822Sdim  first_error (_(reg_expected_msgs[REG_TYPE_RN]));
5311218822Sdim  return FAIL;
5312130561Sobrien}
5313130561Sobrien
5314218822Sdim/* Matcher codes for parse_operands.  */
5315218822Sdimenum operand_parse_code
5316130561Sobrien{
5317218822Sdim  OP_stop,	/* end of line */
5318130561Sobrien
5319218822Sdim  OP_RR,	/* ARM register */
5320218822Sdim  OP_RRnpc,	/* ARM register, not r15 */
5321218822Sdim  OP_RRnpcb,	/* ARM register, not r15, in square brackets */
5322218822Sdim  OP_RRw,	/* ARM register, not r15, optional trailing ! */
5323218822Sdim  OP_RCP,	/* Coprocessor number */
5324218822Sdim  OP_RCN,	/* Coprocessor register */
5325218822Sdim  OP_RF,	/* FPA register */
5326218822Sdim  OP_RVS,	/* VFP single precision register */
5327218822Sdim  OP_RVD,	/* VFP double precision register (0..15) */
5328218822Sdim  OP_RND,       /* Neon double precision register (0..31) */
5329218822Sdim  OP_RNQ,	/* Neon quad precision register */
5330218822Sdim  OP_RVSD,	/* VFP single or double precision register */
5331218822Sdim  OP_RNDQ,      /* Neon double or quad precision register */
5332218822Sdim  OP_RNSDQ,	/* Neon single, double or quad precision register */
5333218822Sdim  OP_RNSC,      /* Neon scalar D[X] */
5334218822Sdim  OP_RVC,	/* VFP control register */
5335218822Sdim  OP_RMF,	/* Maverick F register */
5336218822Sdim  OP_RMD,	/* Maverick D register */
5337218822Sdim  OP_RMFX,	/* Maverick FX register */
5338218822Sdim  OP_RMDX,	/* Maverick DX register */
5339218822Sdim  OP_RMAX,	/* Maverick AX register */
5340218822Sdim  OP_RMDS,	/* Maverick DSPSC register */
5341218822Sdim  OP_RIWR,	/* iWMMXt wR register */
5342218822Sdim  OP_RIWC,	/* iWMMXt wC register */
5343218822Sdim  OP_RIWG,	/* iWMMXt wCG register */
5344218822Sdim  OP_RXA,	/* XScale accumulator register */
5345130561Sobrien
5346218822Sdim  OP_REGLST,	/* ARM register list */
5347218822Sdim  OP_VRSLST,	/* VFP single-precision register list */
5348218822Sdim  OP_VRDLST,	/* VFP double-precision register list */
5349218822Sdim  OP_VRSDLST,   /* VFP single or double-precision register list (& quad) */
5350218822Sdim  OP_NRDLST,    /* Neon double-precision register list (d0-d31, qN aliases) */
5351218822Sdim  OP_NSTRLST,   /* Neon element/structure list */
5352130561Sobrien
5353218822Sdim  OP_NILO,      /* Neon immediate/logic operands 2 or 2+3. (VBIC, VORR...)  */
5354218822Sdim  OP_RNDQ_I0,   /* Neon D or Q reg, or immediate zero.  */
5355218822Sdim  OP_RVSD_I0,	/* VFP S or D reg, or immediate zero.  */
5356218822Sdim  OP_RR_RNSC,   /* ARM reg or Neon scalar.  */
5357218822Sdim  OP_RNSDQ_RNSC, /* Vector S, D or Q reg, or Neon scalar.  */
5358218822Sdim  OP_RNDQ_RNSC, /* Neon D or Q reg, or Neon scalar.  */
5359218822Sdim  OP_RND_RNSC,  /* Neon D reg, or Neon scalar.  */
5360218822Sdim  OP_VMOV,      /* Neon VMOV operands.  */
5361218822Sdim  OP_RNDQ_IMVNb,/* Neon D or Q reg, or immediate good for VMVN.  */
5362218822Sdim  OP_RNDQ_I63b, /* Neon D or Q reg, or immediate for shift.  */
5363218822Sdim  OP_RIWR_I32z, /* iWMMXt wR register, or immediate 0 .. 32 for iWMMXt2.  */
5364130561Sobrien
5365218822Sdim  OP_I0,        /* immediate zero */
5366218822Sdim  OP_I7,	/* immediate value 0 .. 7 */
5367218822Sdim  OP_I15,	/*		   0 .. 15 */
5368218822Sdim  OP_I16,	/*		   1 .. 16 */
5369218822Sdim  OP_I16z,      /*                 0 .. 16 */
5370218822Sdim  OP_I31,	/*		   0 .. 31 */
5371218822Sdim  OP_I31w,	/*		   0 .. 31, optional trailing ! */
5372218822Sdim  OP_I32,	/*		   1 .. 32 */
5373218822Sdim  OP_I32z,	/*		   0 .. 32 */
5374218822Sdim  OP_I63,	/*		   0 .. 63 */
5375218822Sdim  OP_I63s,	/*		 -64 .. 63 */
5376218822Sdim  OP_I64,	/*		   1 .. 64 */
5377218822Sdim  OP_I64z,	/*		   0 .. 64 */
5378218822Sdim  OP_I255,	/*		   0 .. 255 */
5379130561Sobrien
5380218822Sdim  OP_I4b,	/* immediate, prefix optional, 1 .. 4 */
5381218822Sdim  OP_I7b,	/*			       0 .. 7 */
5382218822Sdim  OP_I15b,	/*			       0 .. 15 */
5383218822Sdim  OP_I31b,	/*			       0 .. 31 */
5384130561Sobrien
5385218822Sdim  OP_SH,	/* shifter operand */
5386218822Sdim  OP_SHG,	/* shifter operand with possible group relocation */
5387218822Sdim  OP_ADDR,	/* Memory address expression (any mode) */
5388218822Sdim  OP_ADDRGLDR,	/* Mem addr expr (any mode) with possible LDR group reloc */
5389218822Sdim  OP_ADDRGLDRS, /* Mem addr expr (any mode) with possible LDRS group reloc */
5390218822Sdim  OP_ADDRGLDC,  /* Mem addr expr (any mode) with possible LDC group reloc */
5391218822Sdim  OP_EXP,	/* arbitrary expression */
5392218822Sdim  OP_EXPi,	/* same, with optional immediate prefix */
5393218822Sdim  OP_EXPr,	/* same, with optional relocation suffix */
5394218822Sdim  OP_HALF,	/* 0 .. 65535 or low/high reloc.  */
5395130561Sobrien
5396218822Sdim  OP_CPSF,	/* CPS flags */
5397218822Sdim  OP_ENDI,	/* Endianness specifier */
5398218822Sdim  OP_PSR,	/* CPSR/SPSR mask for msr */
5399218822Sdim  OP_COND,	/* conditional code */
5400218822Sdim  OP_TB,	/* Table branch.  */
5401130561Sobrien
5402218822Sdim  OP_RVC_PSR,	/* CPSR/SPSR mask for msr, or VFP control register.  */
5403218822Sdim  OP_APSR_RR,   /* ARM register or "APSR_nzcv".  */
5404130561Sobrien
5405218822Sdim  OP_RRnpc_I0,	/* ARM register or literal 0 */
5406218822Sdim  OP_RR_EXr,	/* ARM register or expression with opt. reloc suff. */
5407218822Sdim  OP_RR_EXi,	/* ARM register or expression with imm prefix */
5408218822Sdim  OP_RF_IF,	/* FPA register or immediate */
5409218822Sdim  OP_RIWR_RIWC, /* iWMMXt R or C reg */
5410218822Sdim  OP_RIWC_RIWG, /* iWMMXt wC or wCG reg */
5411130561Sobrien
5412218822Sdim  /* Optional operands.	 */
5413218822Sdim  OP_oI7b,	 /* immediate, prefix optional, 0 .. 7 */
5414218822Sdim  OP_oI31b,	 /*				0 .. 31 */
5415218822Sdim  OP_oI32b,      /*                             1 .. 32 */
5416218822Sdim  OP_oIffffb,	 /*				0 .. 65535 */
5417218822Sdim  OP_oI255c,	 /*	  curly-brace enclosed, 0 .. 255 */
5418130561Sobrien
5419218822Sdim  OP_oRR,	 /* ARM register */
5420218822Sdim  OP_oRRnpc,	 /* ARM register, not the PC */
5421218822Sdim  OP_oRRw,	 /* ARM register, not r15, optional trailing ! */
5422218822Sdim  OP_oRND,       /* Optional Neon double precision register */
5423218822Sdim  OP_oRNQ,       /* Optional Neon quad precision register */
5424218822Sdim  OP_oRNDQ,      /* Optional Neon double or quad precision register */
5425218822Sdim  OP_oRNSDQ,	 /* Optional single, double or quad precision vector register */
5426218822Sdim  OP_oSHll,	 /* LSL immediate */
5427218822Sdim  OP_oSHar,	 /* ASR immediate */
5428218822Sdim  OP_oSHllar,	 /* LSL or ASR immediate */
5429218822Sdim  OP_oROR,	 /* ROR 0/8/16/24 */
5430218822Sdim  OP_oBARRIER,	 /* Option argument for a barrier instruction.  */
5431130561Sobrien
5432218822Sdim  OP_FIRST_OPTIONAL = OP_oI7b
5433218822Sdim};
5434130561Sobrien
5435218822Sdim/* Generic instruction operand parser.	This does no encoding and no
5436218822Sdim   semantic validation; it merely squirrels values away in the inst
5437218822Sdim   structure.  Returns SUCCESS or FAIL depending on whether the
5438218822Sdim   specified grammar matched.  */
5439218822Sdimstatic int
5440218822Sdimparse_operands (char *str, const unsigned char *pattern)
5441218822Sdim{
5442218822Sdim  unsigned const char *upat = pattern;
5443218822Sdim  char *backtrack_pos = 0;
5444218822Sdim  const char *backtrack_error = 0;
5445218822Sdim  int i, val, backtrack_index = 0;
5446218822Sdim  enum arm_reg_type rtype;
5447218822Sdim  parse_operand_result result;
5448130561Sobrien
5449218822Sdim#define po_char_or_fail(chr) do {		\
5450218822Sdim  if (skip_past_char (&str, chr) == FAIL)	\
5451218822Sdim    goto bad_args;				\
5452218822Sdim} while (0)
5453130561Sobrien
5454218822Sdim#define po_reg_or_fail(regtype) do {				\
5455218822Sdim  val = arm_typed_reg_parse (&str, regtype, &rtype,		\
5456218822Sdim  			     &inst.operands[i].vectype);	\
5457218822Sdim  if (val == FAIL)						\
5458218822Sdim    {								\
5459218822Sdim      first_error (_(reg_expected_msgs[regtype]));		\
5460218822Sdim      goto failure;						\
5461218822Sdim    }								\
5462218822Sdim  inst.operands[i].reg = val;					\
5463218822Sdim  inst.operands[i].isreg = 1;					\
5464218822Sdim  inst.operands[i].isquad = (rtype == REG_TYPE_NQ);		\
5465218822Sdim  inst.operands[i].issingle = (rtype == REG_TYPE_VFS);		\
5466218822Sdim  inst.operands[i].isvec = (rtype == REG_TYPE_VFS		\
5467218822Sdim                            || rtype == REG_TYPE_VFD		\
5468218822Sdim                            || rtype == REG_TYPE_NQ);		\
5469218822Sdim} while (0)
5470130561Sobrien
5471218822Sdim#define po_reg_or_goto(regtype, label) do {			\
5472218822Sdim  val = arm_typed_reg_parse (&str, regtype, &rtype,		\
5473218822Sdim                             &inst.operands[i].vectype);	\
5474218822Sdim  if (val == FAIL)						\
5475218822Sdim    goto label;							\
5476218822Sdim								\
5477218822Sdim  inst.operands[i].reg = val;					\
5478218822Sdim  inst.operands[i].isreg = 1;					\
5479218822Sdim  inst.operands[i].isquad = (rtype == REG_TYPE_NQ);		\
5480218822Sdim  inst.operands[i].issingle = (rtype == REG_TYPE_VFS);		\
5481218822Sdim  inst.operands[i].isvec = (rtype == REG_TYPE_VFS		\
5482218822Sdim                            || rtype == REG_TYPE_VFD		\
5483218822Sdim                            || rtype == REG_TYPE_NQ);		\
5484218822Sdim} while (0)
5485130561Sobrien
5486218822Sdim#define po_imm_or_fail(min, max, popt) do {			\
5487218822Sdim  if (parse_immediate (&str, &val, min, max, popt) == FAIL)	\
5488218822Sdim    goto failure;						\
5489218822Sdim  inst.operands[i].imm = val;					\
5490218822Sdim} while (0)
5491130561Sobrien
5492218822Sdim#define po_scalar_or_goto(elsz, label) do {			\
5493218822Sdim  val = parse_scalar (&str, elsz, &inst.operands[i].vectype);	\
5494218822Sdim  if (val == FAIL)						\
5495218822Sdim    goto label;							\
5496218822Sdim  inst.operands[i].reg = val;					\
5497218822Sdim  inst.operands[i].isscalar = 1;				\
5498218822Sdim} while (0)
5499130561Sobrien
5500218822Sdim#define po_misc_or_fail(expr) do {		\
5501218822Sdim  if (expr)					\
5502218822Sdim    goto failure;				\
5503218822Sdim} while (0)
5504130561Sobrien
5505218822Sdim#define po_misc_or_fail_no_backtrack(expr) do {	\
5506218822Sdim  result = expr;				\
5507218822Sdim  if (result == PARSE_OPERAND_FAIL_NO_BACKTRACK)\
5508218822Sdim    backtrack_pos = 0;				\
5509218822Sdim  if (result != PARSE_OPERAND_SUCCESS)		\
5510218822Sdim    goto failure;				\
5511218822Sdim} while (0)
5512130561Sobrien
5513130561Sobrien  skip_whitespace (str);
5514130561Sobrien
5515218822Sdim  for (i = 0; upat[i] != OP_stop; i++)
5516130561Sobrien    {
5517218822Sdim      if (upat[i] >= OP_FIRST_OPTIONAL)
5518130561Sobrien	{
5519218822Sdim	  /* Remember where we are in case we need to backtrack.  */
5520218822Sdim	  assert (!backtrack_pos);
5521218822Sdim	  backtrack_pos = str;
5522218822Sdim	  backtrack_error = inst.error;
5523218822Sdim	  backtrack_index = i;
5524130561Sobrien	}
5525130561Sobrien
5526218822Sdim      if (i > 0 && (i > 1 || inst.operands[0].present))
5527218822Sdim	po_char_or_fail (',');
5528130561Sobrien
5529218822Sdim      switch (upat[i])
5530218822Sdim	{
5531218822Sdim	  /* Registers */
5532218822Sdim	case OP_oRRnpc:
5533218822Sdim	case OP_RRnpc:
5534218822Sdim	case OP_oRR:
5535218822Sdim	case OP_RR:    po_reg_or_fail (REG_TYPE_RN);	  break;
5536218822Sdim	case OP_RCP:   po_reg_or_fail (REG_TYPE_CP);	  break;
5537218822Sdim	case OP_RCN:   po_reg_or_fail (REG_TYPE_CN);	  break;
5538218822Sdim	case OP_RF:    po_reg_or_fail (REG_TYPE_FN);	  break;
5539218822Sdim	case OP_RVS:   po_reg_or_fail (REG_TYPE_VFS);	  break;
5540218822Sdim	case OP_RVD:   po_reg_or_fail (REG_TYPE_VFD);	  break;
5541218822Sdim        case OP_oRND:
5542218822Sdim	case OP_RND:   po_reg_or_fail (REG_TYPE_VFD);	  break;
5543218822Sdim	case OP_RVC:
5544218822Sdim	  po_reg_or_goto (REG_TYPE_VFC, coproc_reg);
5545218822Sdim	  break;
5546218822Sdim	  /* Also accept generic coprocessor regs for unknown registers.  */
5547218822Sdim	  coproc_reg:
5548218822Sdim	  po_reg_or_fail (REG_TYPE_CN);
5549218822Sdim	  break;
5550218822Sdim	case OP_RMF:   po_reg_or_fail (REG_TYPE_MVF);	  break;
5551218822Sdim	case OP_RMD:   po_reg_or_fail (REG_TYPE_MVD);	  break;
5552218822Sdim	case OP_RMFX:  po_reg_or_fail (REG_TYPE_MVFX);	  break;
5553218822Sdim	case OP_RMDX:  po_reg_or_fail (REG_TYPE_MVDX);	  break;
5554218822Sdim	case OP_RMAX:  po_reg_or_fail (REG_TYPE_MVAX);	  break;
5555218822Sdim	case OP_RMDS:  po_reg_or_fail (REG_TYPE_DSPSC);	  break;
5556218822Sdim	case OP_RIWR:  po_reg_or_fail (REG_TYPE_MMXWR);	  break;
5557218822Sdim	case OP_RIWC:  po_reg_or_fail (REG_TYPE_MMXWC);	  break;
5558218822Sdim	case OP_RIWG:  po_reg_or_fail (REG_TYPE_MMXWCG);  break;
5559218822Sdim	case OP_RXA:   po_reg_or_fail (REG_TYPE_XSCALE);  break;
5560218822Sdim        case OP_oRNQ:
5561218822Sdim	case OP_RNQ:   po_reg_or_fail (REG_TYPE_NQ);      break;
5562218822Sdim        case OP_oRNDQ:
5563218822Sdim	case OP_RNDQ:  po_reg_or_fail (REG_TYPE_NDQ);     break;
5564218822Sdim        case OP_RVSD:  po_reg_or_fail (REG_TYPE_VFSD);    break;
5565218822Sdim        case OP_oRNSDQ:
5566218822Sdim        case OP_RNSDQ: po_reg_or_fail (REG_TYPE_NSDQ);    break;
5567130561Sobrien
5568218822Sdim        /* Neon scalar. Using an element size of 8 means that some invalid
5569218822Sdim           scalars are accepted here, so deal with those in later code.  */
5570218822Sdim        case OP_RNSC:  po_scalar_or_goto (8, failure);    break;
5571130561Sobrien
5572218822Sdim        /* WARNING: We can expand to two operands here. This has the potential
5573218822Sdim           to totally confuse the backtracking mechanism! It will be OK at
5574218822Sdim           least as long as we don't try to use optional args as well,
5575218822Sdim           though.  */
5576218822Sdim        case OP_NILO:
5577218822Sdim          {
5578218822Sdim            po_reg_or_goto (REG_TYPE_NDQ, try_imm);
5579218822Sdim	    inst.operands[i].present = 1;
5580218822Sdim            i++;
5581218822Sdim            skip_past_comma (&str);
5582218822Sdim            po_reg_or_goto (REG_TYPE_NDQ, one_reg_only);
5583218822Sdim            break;
5584218822Sdim            one_reg_only:
5585218822Sdim            /* Optional register operand was omitted. Unfortunately, it's in
5586218822Sdim               operands[i-1] and we need it to be in inst.operands[i]. Fix that
5587218822Sdim               here (this is a bit grotty).  */
5588218822Sdim            inst.operands[i] = inst.operands[i-1];
5589218822Sdim            inst.operands[i-1].present = 0;
5590218822Sdim            break;
5591218822Sdim            try_imm:
5592218822Sdim	    /* There's a possibility of getting a 64-bit immediate here, so
5593218822Sdim	       we need special handling.  */
5594218822Sdim	    if (parse_big_immediate (&str, i) == FAIL)
5595218822Sdim	      {
5596218822Sdim		inst.error = _("immediate value is out of range");
5597218822Sdim		goto failure;
5598218822Sdim	      }
5599218822Sdim          }
5600218822Sdim          break;
5601130561Sobrien
5602218822Sdim        case OP_RNDQ_I0:
5603218822Sdim          {
5604218822Sdim            po_reg_or_goto (REG_TYPE_NDQ, try_imm0);
5605218822Sdim            break;
5606218822Sdim            try_imm0:
5607218822Sdim            po_imm_or_fail (0, 0, TRUE);
5608218822Sdim          }
5609218822Sdim          break;
5610130561Sobrien
5611218822Sdim        case OP_RVSD_I0:
5612218822Sdim          po_reg_or_goto (REG_TYPE_VFSD, try_imm0);
5613218822Sdim          break;
5614130561Sobrien
5615218822Sdim        case OP_RR_RNSC:
5616218822Sdim          {
5617218822Sdim            po_scalar_or_goto (8, try_rr);
5618218822Sdim            break;
5619218822Sdim            try_rr:
5620218822Sdim            po_reg_or_fail (REG_TYPE_RN);
5621218822Sdim          }
5622218822Sdim          break;
5623130561Sobrien
5624218822Sdim        case OP_RNSDQ_RNSC:
5625218822Sdim          {
5626218822Sdim            po_scalar_or_goto (8, try_nsdq);
5627218822Sdim            break;
5628218822Sdim            try_nsdq:
5629218822Sdim            po_reg_or_fail (REG_TYPE_NSDQ);
5630218822Sdim          }
5631218822Sdim          break;
5632130561Sobrien
5633218822Sdim        case OP_RNDQ_RNSC:
5634218822Sdim          {
5635218822Sdim            po_scalar_or_goto (8, try_ndq);
5636218822Sdim            break;
5637218822Sdim            try_ndq:
5638218822Sdim            po_reg_or_fail (REG_TYPE_NDQ);
5639218822Sdim          }
5640218822Sdim          break;
5641130561Sobrien
5642218822Sdim        case OP_RND_RNSC:
5643218822Sdim          {
5644218822Sdim            po_scalar_or_goto (8, try_vfd);
5645218822Sdim            break;
5646218822Sdim            try_vfd:
5647218822Sdim            po_reg_or_fail (REG_TYPE_VFD);
5648218822Sdim          }
5649218822Sdim          break;
5650130561Sobrien
5651218822Sdim        case OP_VMOV:
5652218822Sdim          /* WARNING: parse_neon_mov can move the operand counter, i. If we're
5653218822Sdim             not careful then bad things might happen.  */
5654218822Sdim          po_misc_or_fail (parse_neon_mov (&str, &i) == FAIL);
5655218822Sdim          break;
5656130561Sobrien
5657218822Sdim        case OP_RNDQ_IMVNb:
5658218822Sdim          {
5659218822Sdim            po_reg_or_goto (REG_TYPE_NDQ, try_mvnimm);
5660218822Sdim            break;
5661218822Sdim            try_mvnimm:
5662218822Sdim            /* There's a possibility of getting a 64-bit immediate here, so
5663218822Sdim               we need special handling.  */
5664218822Sdim            if (parse_big_immediate (&str, i) == FAIL)
5665218822Sdim              {
5666218822Sdim                inst.error = _("immediate value is out of range");
5667218822Sdim                goto failure;
5668218822Sdim              }
5669218822Sdim          }
5670218822Sdim          break;
5671130561Sobrien
5672218822Sdim        case OP_RNDQ_I63b:
5673218822Sdim          {
5674218822Sdim            po_reg_or_goto (REG_TYPE_NDQ, try_shimm);
5675218822Sdim            break;
5676218822Sdim            try_shimm:
5677218822Sdim            po_imm_or_fail (0, 63, TRUE);
5678218822Sdim          }
5679218822Sdim          break;
5680130561Sobrien
5681218822Sdim	case OP_RRnpcb:
5682218822Sdim	  po_char_or_fail ('[');
5683218822Sdim	  po_reg_or_fail  (REG_TYPE_RN);
5684218822Sdim	  po_char_or_fail (']');
5685218822Sdim	  break;
5686130561Sobrien
5687218822Sdim	case OP_RRw:
5688218822Sdim	case OP_oRRw:
5689218822Sdim	  po_reg_or_fail (REG_TYPE_RN);
5690218822Sdim	  if (skip_past_char (&str, '!') == SUCCESS)
5691218822Sdim	    inst.operands[i].writeback = 1;
5692218822Sdim	  break;
5693130561Sobrien
5694218822Sdim	  /* Immediates */
5695218822Sdim	case OP_I7:	 po_imm_or_fail (  0,	   7, FALSE);	break;
5696218822Sdim	case OP_I15:	 po_imm_or_fail (  0,	  15, FALSE);	break;
5697218822Sdim	case OP_I16:	 po_imm_or_fail (  1,	  16, FALSE);	break;
5698218822Sdim        case OP_I16z:	 po_imm_or_fail (  0,     16, FALSE);   break;
5699218822Sdim	case OP_I31:	 po_imm_or_fail (  0,	  31, FALSE);	break;
5700218822Sdim	case OP_I32:	 po_imm_or_fail (  1,	  32, FALSE);	break;
5701218822Sdim        case OP_I32z:	 po_imm_or_fail (  0,     32, FALSE);   break;
5702218822Sdim	case OP_I63s:	 po_imm_or_fail (-64,	  63, FALSE);	break;
5703218822Sdim        case OP_I63:	 po_imm_or_fail (  0,     63, FALSE);   break;
5704218822Sdim        case OP_I64:	 po_imm_or_fail (  1,     64, FALSE);   break;
5705218822Sdim        case OP_I64z:	 po_imm_or_fail (  0,     64, FALSE);   break;
5706218822Sdim	case OP_I255:	 po_imm_or_fail (  0,	 255, FALSE);	break;
5707130561Sobrien
5708218822Sdim	case OP_I4b:	 po_imm_or_fail (  1,	   4, TRUE);	break;
5709218822Sdim	case OP_oI7b:
5710218822Sdim	case OP_I7b:	 po_imm_or_fail (  0,	   7, TRUE);	break;
5711218822Sdim	case OP_I15b:	 po_imm_or_fail (  0,	  15, TRUE);	break;
5712218822Sdim	case OP_oI31b:
5713218822Sdim	case OP_I31b:	 po_imm_or_fail (  0,	  31, TRUE);	break;
5714218822Sdim        case OP_oI32b:   po_imm_or_fail (  1,     32, TRUE);    break;
5715218822Sdim	case OP_oIffffb: po_imm_or_fail (  0, 0xffff, TRUE);	break;
5716130561Sobrien
5717218822Sdim	  /* Immediate variants */
5718218822Sdim	case OP_oI255c:
5719218822Sdim	  po_char_or_fail ('{');
5720218822Sdim	  po_imm_or_fail (0, 255, TRUE);
5721218822Sdim	  po_char_or_fail ('}');
5722218822Sdim	  break;
5723130561Sobrien
5724218822Sdim	case OP_I31w:
5725218822Sdim	  /* The expression parser chokes on a trailing !, so we have
5726218822Sdim	     to find it first and zap it.  */
5727218822Sdim	  {
5728218822Sdim	    char *s = str;
5729218822Sdim	    while (*s && *s != ',')
5730218822Sdim	      s++;
5731218822Sdim	    if (s[-1] == '!')
5732218822Sdim	      {
5733218822Sdim		s[-1] = '\0';
5734218822Sdim		inst.operands[i].writeback = 1;
5735218822Sdim	      }
5736218822Sdim	    po_imm_or_fail (0, 31, TRUE);
5737218822Sdim	    if (str == s - 1)
5738218822Sdim	      str = s;
5739218822Sdim	  }
5740218822Sdim	  break;
5741130561Sobrien
5742218822Sdim	  /* Expressions */
5743218822Sdim	case OP_EXPi:	EXPi:
5744218822Sdim	  po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str,
5745218822Sdim					      GE_OPT_PREFIX));
5746218822Sdim	  break;
5747130561Sobrien
5748218822Sdim	case OP_EXP:
5749218822Sdim	  po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str,
5750218822Sdim					      GE_NO_PREFIX));
5751218822Sdim	  break;
5752130561Sobrien
5753218822Sdim	case OP_EXPr:	EXPr:
5754218822Sdim	  po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str,
5755218822Sdim					      GE_NO_PREFIX));
5756218822Sdim	  if (inst.reloc.exp.X_op == O_symbol)
5757218822Sdim	    {
5758218822Sdim	      val = parse_reloc (&str);
5759218822Sdim	      if (val == -1)
5760218822Sdim		{
5761218822Sdim		  inst.error = _("unrecognized relocation suffix");
5762218822Sdim		  goto failure;
5763218822Sdim		}
5764218822Sdim	      else if (val != BFD_RELOC_UNUSED)
5765218822Sdim		{
5766218822Sdim		  inst.operands[i].imm = val;
5767218822Sdim		  inst.operands[i].hasreloc = 1;
5768218822Sdim		}
5769218822Sdim	    }
5770218822Sdim	  break;
5771218822Sdim
5772218822Sdim	  /* Operand for MOVW or MOVT.  */
5773218822Sdim	case OP_HALF:
5774218822Sdim	  po_misc_or_fail (parse_half (&str));
5775218822Sdim	  break;
5776218822Sdim
5777218822Sdim	  /* Register or expression */
5778218822Sdim	case OP_RR_EXr:	  po_reg_or_goto (REG_TYPE_RN, EXPr); break;
5779218822Sdim	case OP_RR_EXi:	  po_reg_or_goto (REG_TYPE_RN, EXPi); break;
5780218822Sdim
5781218822Sdim	  /* Register or immediate */
5782218822Sdim	case OP_RRnpc_I0: po_reg_or_goto (REG_TYPE_RN, I0);   break;
5783218822Sdim	I0:		  po_imm_or_fail (0, 0, FALSE);	      break;
5784218822Sdim
5785218822Sdim	case OP_RF_IF:    po_reg_or_goto (REG_TYPE_FN, IF);   break;
5786218822Sdim	IF:
5787218822Sdim	  if (!is_immediate_prefix (*str))
5788218822Sdim	    goto bad_args;
5789218822Sdim	  str++;
5790218822Sdim	  val = parse_fpa_immediate (&str);
5791218822Sdim	  if (val == FAIL)
5792218822Sdim	    goto failure;
5793218822Sdim	  /* FPA immediates are encoded as registers 8-15.
5794218822Sdim	     parse_fpa_immediate has already applied the offset.  */
5795218822Sdim	  inst.operands[i].reg = val;
5796218822Sdim	  inst.operands[i].isreg = 1;
5797218822Sdim	  break;
5798218822Sdim
5799218822Sdim	case OP_RIWR_I32z: po_reg_or_goto (REG_TYPE_MMXWR, I32z); break;
5800218822Sdim	I32z:		  po_imm_or_fail (0, 32, FALSE);	  break;
5801218822Sdim
5802218822Sdim	  /* Two kinds of register */
5803218822Sdim	case OP_RIWR_RIWC:
5804130561Sobrien	  {
5805218822Sdim	    struct reg_entry *rege = arm_reg_parse_multi (&str);
5806218822Sdim	    if (!rege
5807218822Sdim		|| (rege->type != REG_TYPE_MMXWR
5808218822Sdim		    && rege->type != REG_TYPE_MMXWC
5809218822Sdim		    && rege->type != REG_TYPE_MMXWCG))
5810218822Sdim	      {
5811218822Sdim		inst.error = _("iWMMXt data or control register expected");
5812218822Sdim		goto failure;
5813218822Sdim	      }
5814218822Sdim	    inst.operands[i].reg = rege->number;
5815218822Sdim	    inst.operands[i].isreg = (rege->type == REG_TYPE_MMXWR);
5816130561Sobrien	  }
5817218822Sdim	  break;
5818130561Sobrien
5819218822Sdim	case OP_RIWC_RIWG:
5820218822Sdim	  {
5821218822Sdim	    struct reg_entry *rege = arm_reg_parse_multi (&str);
5822218822Sdim	    if (!rege
5823218822Sdim		|| (rege->type != REG_TYPE_MMXWC
5824218822Sdim		    && rege->type != REG_TYPE_MMXWCG))
5825218822Sdim	      {
5826218822Sdim		inst.error = _("iWMMXt control register expected");
5827218822Sdim		goto failure;
5828218822Sdim	      }
5829218822Sdim	    inst.operands[i].reg = rege->number;
5830218822Sdim	    inst.operands[i].isreg = 1;
5831218822Sdim	  }
5832218822Sdim	  break;
583377298Sobrien
5834218822Sdim	  /* Misc */
5835218822Sdim	case OP_CPSF:	 val = parse_cps_flags (&str);		break;
5836218822Sdim	case OP_ENDI:	 val = parse_endian_specifier (&str);	break;
5837218822Sdim	case OP_oROR:	 val = parse_ror (&str);		break;
5838218822Sdim	case OP_PSR:	 val = parse_psr (&str);		break;
5839218822Sdim	case OP_COND:	 val = parse_cond (&str);		break;
5840218822Sdim	case OP_oBARRIER:val = parse_barrier (&str);		break;
584177298Sobrien
5842218822Sdim        case OP_RVC_PSR:
5843218822Sdim          po_reg_or_goto (REG_TYPE_VFC, try_psr);
5844218822Sdim          inst.operands[i].isvec = 1;  /* Mark VFP control reg as vector.  */
5845218822Sdim          break;
5846218822Sdim          try_psr:
5847218822Sdim          val = parse_psr (&str);
5848218822Sdim          break;
584977298Sobrien
5850218822Sdim        case OP_APSR_RR:
5851218822Sdim          po_reg_or_goto (REG_TYPE_RN, try_apsr);
5852218822Sdim          break;
5853218822Sdim          try_apsr:
5854218822Sdim          /* Parse "APSR_nvzc" operand (for FMSTAT-equivalent MRS
5855218822Sdim             instruction).  */
5856218822Sdim          if (strncasecmp (str, "APSR_", 5) == 0)
5857218822Sdim            {
5858218822Sdim              unsigned found = 0;
5859218822Sdim              str += 5;
5860218822Sdim              while (found < 15)
5861218822Sdim                switch (*str++)
5862218822Sdim                  {
5863218822Sdim                  case 'c': found = (found & 1) ? 16 : found | 1; break;
5864218822Sdim                  case 'n': found = (found & 2) ? 16 : found | 2; break;
5865218822Sdim                  case 'z': found = (found & 4) ? 16 : found | 4; break;
5866218822Sdim                  case 'v': found = (found & 8) ? 16 : found | 8; break;
5867218822Sdim                  default: found = 16;
5868218822Sdim                  }
5869218822Sdim              if (found != 15)
5870218822Sdim                goto failure;
5871218822Sdim              inst.operands[i].isvec = 1;
5872218822Sdim            }
5873218822Sdim          else
5874218822Sdim            goto failure;
5875218822Sdim          break;
587677298Sobrien
5877218822Sdim	case OP_TB:
5878218822Sdim	  po_misc_or_fail (parse_tb (&str));
5879218822Sdim	  break;
588077298Sobrien
5881218822Sdim	  /* Register lists */
5882218822Sdim	case OP_REGLST:
5883218822Sdim	  val = parse_reg_list (&str);
5884218822Sdim	  if (*str == '^')
5885218822Sdim	    {
5886218822Sdim	      inst.operands[1].writeback = 1;
5887218822Sdim	      str++;
5888218822Sdim	    }
5889218822Sdim	  break;
589077298Sobrien
5891218822Sdim	case OP_VRSLST:
5892218822Sdim	  val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_S);
5893218822Sdim	  break;
589477298Sobrien
5895218822Sdim	case OP_VRDLST:
5896218822Sdim	  val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_D);
5897218822Sdim	  break;
589877298Sobrien
5899218822Sdim        case OP_VRSDLST:
5900218822Sdim          /* Allow Q registers too.  */
5901218822Sdim          val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
5902218822Sdim                                    REGLIST_NEON_D);
5903218822Sdim          if (val == FAIL)
5904218822Sdim            {
5905218822Sdim              inst.error = NULL;
5906218822Sdim              val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
5907218822Sdim                                        REGLIST_VFP_S);
5908218822Sdim              inst.operands[i].issingle = 1;
5909218822Sdim            }
5910218822Sdim          break;
591177298Sobrien
5912218822Sdim        case OP_NRDLST:
5913218822Sdim          val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
5914218822Sdim                                    REGLIST_NEON_D);
5915218822Sdim          break;
591677298Sobrien
5917218822Sdim	case OP_NSTRLST:
5918218822Sdim          val = parse_neon_el_struct_list (&str, &inst.operands[i].reg,
5919218822Sdim                                           &inst.operands[i].vectype);
5920218822Sdim          break;
592177298Sobrien
5922218822Sdim	  /* Addressing modes */
5923218822Sdim	case OP_ADDR:
5924218822Sdim	  po_misc_or_fail (parse_address (&str, i));
5925218822Sdim	  break;
592677298Sobrien
5927218822Sdim	case OP_ADDRGLDR:
5928218822Sdim	  po_misc_or_fail_no_backtrack (
5929218822Sdim            parse_address_group_reloc (&str, i, GROUP_LDR));
5930218822Sdim	  break;
593177298Sobrien
5932218822Sdim	case OP_ADDRGLDRS:
5933218822Sdim	  po_misc_or_fail_no_backtrack (
5934218822Sdim            parse_address_group_reloc (&str, i, GROUP_LDRS));
5935218822Sdim	  break;
593677298Sobrien
5937218822Sdim	case OP_ADDRGLDC:
5938218822Sdim	  po_misc_or_fail_no_backtrack (
5939218822Sdim            parse_address_group_reloc (&str, i, GROUP_LDC));
5940218822Sdim	  break;
594177298Sobrien
5942218822Sdim	case OP_SH:
5943218822Sdim	  po_misc_or_fail (parse_shifter_operand (&str, i));
5944218822Sdim	  break;
594577298Sobrien
5946218822Sdim	case OP_SHG:
5947218822Sdim	  po_misc_or_fail_no_backtrack (
5948218822Sdim            parse_shifter_operand_group_reloc (&str, i));
5949218822Sdim	  break;
595077298Sobrien
5951218822Sdim	case OP_oSHll:
5952218822Sdim	  po_misc_or_fail (parse_shift (&str, i, SHIFT_LSL_IMMEDIATE));
5953218822Sdim	  break;
595477298Sobrien
5955218822Sdim	case OP_oSHar:
5956218822Sdim	  po_misc_or_fail (parse_shift (&str, i, SHIFT_ASR_IMMEDIATE));
5957218822Sdim	  break;
595877298Sobrien
5959218822Sdim	case OP_oSHllar:
5960218822Sdim	  po_misc_or_fail (parse_shift (&str, i, SHIFT_LSL_OR_ASR_IMMEDIATE));
5961218822Sdim	  break;
596277298Sobrien
5963218822Sdim	default:
5964218822Sdim	  as_fatal ("unhandled operand code %d", upat[i]);
5965218822Sdim	}
596677298Sobrien
5967218822Sdim      /* Various value-based sanity checks and shared operations.  We
5968218822Sdim	 do not signal immediate failures for the register constraints;
5969218822Sdim	 this allows a syntax error to take precedence.	 */
5970218822Sdim      switch (upat[i])
5971104834Sobrien	{
5972218822Sdim	case OP_oRRnpc:
5973218822Sdim	case OP_RRnpc:
5974218822Sdim	case OP_RRnpcb:
5975218822Sdim	case OP_RRw:
5976218822Sdim	case OP_oRRw:
5977218822Sdim	case OP_RRnpc_I0:
5978218822Sdim	  if (inst.operands[i].isreg && inst.operands[i].reg == REG_PC)
5979218822Sdim	    inst.error = BAD_PC;
5980218822Sdim	  break;
598177298Sobrien
5982218822Sdim	case OP_CPSF:
5983218822Sdim	case OP_ENDI:
5984218822Sdim	case OP_oROR:
5985218822Sdim	case OP_PSR:
5986218822Sdim        case OP_RVC_PSR:
5987218822Sdim	case OP_COND:
5988218822Sdim	case OP_oBARRIER:
5989218822Sdim	case OP_REGLST:
5990218822Sdim	case OP_VRSLST:
5991218822Sdim	case OP_VRDLST:
5992218822Sdim        case OP_VRSDLST:
5993218822Sdim        case OP_NRDLST:
5994218822Sdim        case OP_NSTRLST:
5995218822Sdim	  if (val == FAIL)
5996218822Sdim	    goto failure;
5997218822Sdim	  inst.operands[i].imm = val;
5998218822Sdim	  break;
599977298Sobrien
6000218822Sdim	default:
6001218822Sdim	  break;
6002218822Sdim	}
600377298Sobrien
6004218822Sdim      /* If we get here, this operand was successfully parsed.	*/
6005218822Sdim      inst.operands[i].present = 1;
6006218822Sdim      continue;
600777298Sobrien
6008218822Sdim    bad_args:
6009218822Sdim      inst.error = BAD_ARGS;
601077298Sobrien
6011218822Sdim    failure:
6012218822Sdim      if (!backtrack_pos)
6013218822Sdim	{
6014218822Sdim	  /* The parse routine should already have set inst.error, but set a
6015218822Sdim	     defaut here just in case.  */
6016218822Sdim	  if (!inst.error)
6017218822Sdim	    inst.error = _("syntax error");
6018218822Sdim	  return FAIL;
6019218822Sdim	}
602077298Sobrien
6021218822Sdim      /* Do not backtrack over a trailing optional argument that
6022218822Sdim	 absorbed some text.  We will only fail again, with the
6023218822Sdim	 'garbage following instruction' error message, which is
6024218822Sdim	 probably less helpful than the current one.  */
6025218822Sdim      if (backtrack_index == i && backtrack_pos != str
6026218822Sdim	  && upat[i+1] == OP_stop)
6027218822Sdim	{
6028218822Sdim	  if (!inst.error)
6029218822Sdim	    inst.error = _("syntax error");
6030218822Sdim	  return FAIL;
6031218822Sdim	}
603277298Sobrien
6033218822Sdim      /* Try again, skipping the optional argument at backtrack_pos.  */
6034218822Sdim      str = backtrack_pos;
6035218822Sdim      inst.error = backtrack_error;
6036218822Sdim      inst.operands[backtrack_index].present = 0;
6037218822Sdim      i = backtrack_index;
6038218822Sdim      backtrack_pos = 0;
603977298Sobrien    }
604077298Sobrien
6041218822Sdim  /* Check that we have parsed all the arguments.  */
6042218822Sdim  if (*str != '\0' && !inst.error)
6043218822Sdim    inst.error = _("garbage following instruction");
604477298Sobrien
6045218822Sdim  return inst.error ? FAIL : SUCCESS;
604677298Sobrien}
604777298Sobrien
6048218822Sdim#undef po_char_or_fail
6049218822Sdim#undef po_reg_or_fail
6050218822Sdim#undef po_reg_or_goto
6051218822Sdim#undef po_imm_or_fail
6052218822Sdim#undef po_scalar_or_fail
6053218822Sdim
6054218822Sdim/* Shorthand macro for instruction encoding functions issuing errors.  */
6055218822Sdim#define constraint(expr, err) do {		\
6056218822Sdim  if (expr)					\
6057218822Sdim    {						\
6058218822Sdim      inst.error = err;				\
6059218822Sdim      return;					\
6060218822Sdim    }						\
6061218822Sdim} while (0)
606277298Sobrien
6063218822Sdim/* Functions for operand encoding.  ARM, then Thumb.  */
6064218822Sdim
6065218822Sdim#define rotate_left(v, n) (v << n | v >> (32 - n))
6066218822Sdim
6067218822Sdim/* If VAL can be encoded in the immediate field of an ARM instruction,
6068218822Sdim   return the encoded form.  Otherwise, return FAIL.  */
6069218822Sdim
6070218822Sdimstatic unsigned int
6071218822Sdimencode_arm_immediate (unsigned int val)
607277298Sobrien{
6073218822Sdim  unsigned int a, i;
607477298Sobrien
6075218822Sdim  for (i = 0; i < 32; i += 2)
6076218822Sdim    if ((a = rotate_left (val, i)) <= 0xff)
6077218822Sdim      return a | (i << 7); /* 12-bit pack: [shift-cnt,const].  */
607877298Sobrien
6079218822Sdim  return FAIL;
6080218822Sdim}
608177298Sobrien
6082218822Sdim/* If VAL can be encoded in the immediate field of a Thumb32 instruction,
6083218822Sdim   return the encoded form.  Otherwise, return FAIL.  */
6084218822Sdimstatic unsigned int
6085218822Sdimencode_thumb32_immediate (unsigned int val)
6086218822Sdim{
6087218822Sdim  unsigned int a, i;
608877298Sobrien
6089218822Sdim  if (val <= 0xff)
6090218822Sdim    return val;
6091218822Sdim
6092218822Sdim  for (i = 1; i <= 24; i++)
609377298Sobrien    {
6094218822Sdim      a = val >> i;
6095218822Sdim      if ((val & ~(0xff << i)) == 0)
6096218822Sdim	return ((val >> i) & 0x7f) | ((32 - i) << 7);
609777298Sobrien    }
609877298Sobrien
6099218822Sdim  a = val & 0xff;
6100218822Sdim  if (val == ((a << 16) | a))
6101218822Sdim    return 0x100 | a;
6102218822Sdim  if (val == ((a << 24) | (a << 16) | (a << 8) | a))
6103218822Sdim    return 0x300 | a;
610477298Sobrien
6105218822Sdim  a = val & 0xff00;
6106218822Sdim  if (val == ((a << 16) | a))
6107218822Sdim    return 0x200 | (a >> 8);
6108218822Sdim
6109218822Sdim  return FAIL;
6110218822Sdim}
6111218822Sdim/* Encode a VFP SP or DP register number into inst.instruction.  */
6112218822Sdim
6113218822Sdimstatic void
6114218822Sdimencode_arm_vfp_reg (int reg, enum vfp_reg_pos pos)
6115218822Sdim{
6116218822Sdim  if ((pos == VFP_REG_Dd || pos == VFP_REG_Dn || pos == VFP_REG_Dm)
6117218822Sdim      && reg > 15)
611877298Sobrien    {
6119218822Sdim      if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v3))
6120218822Sdim        {
6121218822Sdim          if (thumb_mode)
6122218822Sdim            ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
6123218822Sdim                                    fpu_vfp_ext_v3);
6124218822Sdim          else
6125218822Sdim            ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used,
6126218822Sdim                                    fpu_vfp_ext_v3);
6127218822Sdim        }
6128218822Sdim      else
6129218822Sdim        {
6130218822Sdim          first_error (_("D register out of range for selected VFP version"));
6131218822Sdim          return;
6132218822Sdim        }
613377298Sobrien    }
613477298Sobrien
6135218822Sdim  switch (pos)
6136218822Sdim    {
6137218822Sdim    case VFP_REG_Sd:
6138218822Sdim      inst.instruction |= ((reg >> 1) << 12) | ((reg & 1) << 22);
6139218822Sdim      break;
614077298Sobrien
6141218822Sdim    case VFP_REG_Sn:
6142218822Sdim      inst.instruction |= ((reg >> 1) << 16) | ((reg & 1) << 7);
6143218822Sdim      break;
614477298Sobrien
6145218822Sdim    case VFP_REG_Sm:
6146218822Sdim      inst.instruction |= ((reg >> 1) << 0) | ((reg & 1) << 5);
6147218822Sdim      break;
6148218822Sdim
6149218822Sdim    case VFP_REG_Dd:
6150218822Sdim      inst.instruction |= ((reg & 15) << 12) | ((reg >> 4) << 22);
6151218822Sdim      break;
6152218822Sdim
6153218822Sdim    case VFP_REG_Dn:
6154218822Sdim      inst.instruction |= ((reg & 15) << 16) | ((reg >> 4) << 7);
6155218822Sdim      break;
6156218822Sdim
6157218822Sdim    case VFP_REG_Dm:
6158218822Sdim      inst.instruction |= (reg & 15) | ((reg >> 4) << 5);
6159218822Sdim      break;
6160218822Sdim
6161218822Sdim    default:
6162218822Sdim      abort ();
6163218822Sdim    }
616477298Sobrien}
616577298Sobrien
6166218822Sdim/* Encode a <shift> in an ARM-format instruction.  The immediate,
6167218822Sdim   if any, is handled by md_apply_fix.	 */
6168130561Sobrienstatic void
6169218822Sdimencode_arm_shift (int i)
6170130561Sobrien{
6171218822Sdim  if (inst.operands[i].shift_kind == SHIFT_RRX)
6172218822Sdim    inst.instruction |= SHIFT_ROR << 5;
6173218822Sdim  else
6174218822Sdim    {
6175218822Sdim      inst.instruction |= inst.operands[i].shift_kind << 5;
6176218822Sdim      if (inst.operands[i].immisreg)
6177218822Sdim	{
6178218822Sdim	  inst.instruction |= SHIFT_BY_REG;
6179218822Sdim	  inst.instruction |= inst.operands[i].imm << 8;
6180218822Sdim	}
6181218822Sdim      else
6182218822Sdim	inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
6183218822Sdim    }
6184130561Sobrien}
6185130561Sobrien
6186130561Sobrienstatic void
6187218822Sdimencode_arm_shifter_operand (int i)
6188130561Sobrien{
6189218822Sdim  if (inst.operands[i].isreg)
6190218822Sdim    {
6191218822Sdim      inst.instruction |= inst.operands[i].reg;
6192218822Sdim      encode_arm_shift (i);
6193218822Sdim    }
6194218822Sdim  else
6195218822Sdim    inst.instruction |= INST_IMMEDIATE;
6196130561Sobrien}
6197130561Sobrien
6198218822Sdim/* Subroutine of encode_arm_addr_mode_2 and encode_arm_addr_mode_3.  */
6199130561Sobrienstatic void
6200218822Sdimencode_arm_addr_mode_common (int i, bfd_boolean is_t)
6201130561Sobrien{
6202218822Sdim  assert (inst.operands[i].isreg);
6203218822Sdim  inst.instruction |= inst.operands[i].reg << 16;
6204130561Sobrien
6205218822Sdim  if (inst.operands[i].preind)
6206218822Sdim    {
6207218822Sdim      if (is_t)
6208218822Sdim	{
6209218822Sdim	  inst.error = _("instruction does not accept preindexed addressing");
6210218822Sdim	  return;
6211218822Sdim	}
6212218822Sdim      inst.instruction |= PRE_INDEX;
6213218822Sdim      if (inst.operands[i].writeback)
6214218822Sdim	inst.instruction |= WRITE_BACK;
6215130561Sobrien
6216218822Sdim    }
6217218822Sdim  else if (inst.operands[i].postind)
6218218822Sdim    {
6219218822Sdim      assert (inst.operands[i].writeback);
6220218822Sdim      if (is_t)
6221218822Sdim	inst.instruction |= WRITE_BACK;
6222218822Sdim    }
6223218822Sdim  else /* unindexed - only for coprocessor */
6224218822Sdim    {
6225218822Sdim      inst.error = _("instruction does not accept unindexed addressing");
6226218822Sdim      return;
6227218822Sdim    }
6228130561Sobrien
6229218822Sdim  if (((inst.instruction & WRITE_BACK) || !(inst.instruction & PRE_INDEX))
6230218822Sdim      && (((inst.instruction & 0x000f0000) >> 16)
6231218822Sdim	  == ((inst.instruction & 0x0000f000) >> 12)))
6232218822Sdim    as_warn ((inst.instruction & LOAD_BIT)
6233218822Sdim	     ? _("destination register same as write-back base")
6234218822Sdim	     : _("source register same as write-back base"));
6235218822Sdim}
6236218822Sdim
6237218822Sdim/* inst.operands[i] was set up by parse_address.  Encode it into an
6238218822Sdim   ARM-format mode 2 load or store instruction.	 If is_t is true,
6239218822Sdim   reject forms that cannot be used with a T instruction (i.e. not
6240218822Sdim   post-indexed).  */
6241218822Sdimstatic void
6242218822Sdimencode_arm_addr_mode_2 (int i, bfd_boolean is_t)
6243130561Sobrien{
6244218822Sdim  encode_arm_addr_mode_common (i, is_t);
6245130561Sobrien
6246218822Sdim  if (inst.operands[i].immisreg)
6247130561Sobrien    {
6248218822Sdim      inst.instruction |= INST_IMMEDIATE;  /* yes, this is backwards */
6249218822Sdim      inst.instruction |= inst.operands[i].imm;
6250218822Sdim      if (!inst.operands[i].negative)
6251218822Sdim	inst.instruction |= INDEX_UP;
6252218822Sdim      if (inst.operands[i].shifted)
6253218822Sdim	{
6254218822Sdim	  if (inst.operands[i].shift_kind == SHIFT_RRX)
6255218822Sdim	    inst.instruction |= SHIFT_ROR << 5;
6256218822Sdim	  else
6257218822Sdim	    {
6258218822Sdim	      inst.instruction |= inst.operands[i].shift_kind << 5;
6259218822Sdim	      inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
6260218822Sdim	    }
6261218822Sdim	}
6262130561Sobrien    }
6263218822Sdim  else /* immediate offset in inst.reloc */
6264130561Sobrien    {
6265218822Sdim      if (inst.reloc.type == BFD_RELOC_UNUSED)
6266218822Sdim	inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
6267130561Sobrien    }
6268218822Sdim}
6269218822Sdim
6270218822Sdim/* inst.operands[i] was set up by parse_address.  Encode it into an
6271218822Sdim   ARM-format mode 3 load or store instruction.	 Reject forms that
6272218822Sdim   cannot be used with such instructions.  If is_t is true, reject
6273218822Sdim   forms that cannot be used with a T instruction (i.e. not
6274218822Sdim   post-indexed).  */
6275218822Sdimstatic void
6276218822Sdimencode_arm_addr_mode_3 (int i, bfd_boolean is_t)
6277218822Sdim{
6278218822Sdim  if (inst.operands[i].immisreg && inst.operands[i].shifted)
6279130561Sobrien    {
6280218822Sdim      inst.error = _("instruction does not accept scaled register index");
6281218822Sdim      return;
6282218822Sdim    }
6283130561Sobrien
6284218822Sdim  encode_arm_addr_mode_common (i, is_t);
6285218822Sdim
6286218822Sdim  if (inst.operands[i].immisreg)
6287218822Sdim    {
6288218822Sdim      inst.instruction |= inst.operands[i].imm;
6289218822Sdim      if (!inst.operands[i].negative)
6290218822Sdim	inst.instruction |= INDEX_UP;
6291130561Sobrien    }
6292218822Sdim  else /* immediate offset in inst.reloc */
6293218822Sdim    {
6294218822Sdim      inst.instruction |= HWOFFSET_IMM;
6295218822Sdim      if (inst.reloc.type == BFD_RELOC_UNUSED)
6296218822Sdim	inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
6297218822Sdim    }
6298130561Sobrien}
6299130561Sobrien
6300218822Sdim/* inst.operands[i] was set up by parse_address.  Encode it into an
6301218822Sdim   ARM-format instruction.  Reject all forms which cannot be encoded
6302218822Sdim   into a coprocessor load/store instruction.  If wb_ok is false,
6303218822Sdim   reject use of writeback; if unind_ok is false, reject use of
6304218822Sdim   unindexed addressing.  If reloc_override is not 0, use it instead
6305218822Sdim   of BFD_ARM_CP_OFF_IMM, unless the initial relocation is a group one
6306218822Sdim   (in which case it is preserved).  */
6307218822Sdim
6308218822Sdimstatic int
6309218822Sdimencode_arm_cp_address (int i, int wb_ok, int unind_ok, int reloc_override)
6310130561Sobrien{
6311218822Sdim  inst.instruction |= inst.operands[i].reg << 16;
6312130561Sobrien
6313218822Sdim  assert (!(inst.operands[i].preind && inst.operands[i].postind));
6314130561Sobrien
6315218822Sdim  if (!inst.operands[i].preind && !inst.operands[i].postind) /* unindexed */
6316218822Sdim    {
6317218822Sdim      assert (!inst.operands[i].writeback);
6318218822Sdim      if (!unind_ok)
6319218822Sdim	{
6320218822Sdim	  inst.error = _("instruction does not support unindexed addressing");
6321218822Sdim	  return FAIL;
6322218822Sdim	}
6323218822Sdim      inst.instruction |= inst.operands[i].imm;
6324218822Sdim      inst.instruction |= INDEX_UP;
6325218822Sdim      return SUCCESS;
6326218822Sdim    }
6327130561Sobrien
6328218822Sdim  if (inst.operands[i].preind)
6329218822Sdim    inst.instruction |= PRE_INDEX;
6330218822Sdim
6331218822Sdim  if (inst.operands[i].writeback)
6332130561Sobrien    {
6333218822Sdim      if (inst.operands[i].reg == REG_PC)
6334218822Sdim	{
6335218822Sdim	  inst.error = _("pc may not be used with write-back");
6336218822Sdim	  return FAIL;
6337218822Sdim	}
6338218822Sdim      if (!wb_ok)
6339218822Sdim	{
6340218822Sdim	  inst.error = _("instruction does not support writeback");
6341218822Sdim	  return FAIL;
6342218822Sdim	}
6343218822Sdim      inst.instruction |= WRITE_BACK;
6344130561Sobrien    }
6345130561Sobrien
6346218822Sdim  if (reloc_override)
6347218822Sdim    inst.reloc.type = reloc_override;
6348218822Sdim  else if ((inst.reloc.type < BFD_RELOC_ARM_ALU_PC_G0_NC
6349218822Sdim            || inst.reloc.type > BFD_RELOC_ARM_LDC_SB_G2)
6350218822Sdim           && inst.reloc.type != BFD_RELOC_ARM_LDR_PC_G0)
6351130561Sobrien    {
6352218822Sdim      if (thumb_mode)
6353218822Sdim        inst.reloc.type = BFD_RELOC_ARM_T32_CP_OFF_IMM;
6354218822Sdim      else
6355218822Sdim        inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
6356130561Sobrien    }
6357218822Sdim
6358218822Sdim  return SUCCESS;
6359130561Sobrien}
6360130561Sobrien
6361218822Sdim/* inst.reloc.exp describes an "=expr" load pseudo-operation.
6362218822Sdim   Determine whether it can be performed with a move instruction; if
6363218822Sdim   it can, convert inst.instruction to that move instruction and
6364218822Sdim   return 1; if it can't, convert inst.instruction to a literal-pool
6365218822Sdim   load and return 0.  If this is not a valid thing to do in the
6366218822Sdim   current context, set inst.error and return 1.
6367218822Sdim
6368218822Sdim   inst.operands[i] describes the destination register.	 */
6369218822Sdim
6370218822Sdimstatic int
6371218822Sdimmove_or_literal_pool (int i, bfd_boolean thumb_p, bfd_boolean mode_3)
6372130561Sobrien{
6373218822Sdim  unsigned long tbit;
6374130561Sobrien
6375218822Sdim  if (thumb_p)
6376218822Sdim    tbit = (inst.instruction > 0xffff) ? THUMB2_LOAD_BIT : THUMB_LOAD_BIT;
6377218822Sdim  else
6378218822Sdim    tbit = LOAD_BIT;
6379130561Sobrien
6380218822Sdim  if ((inst.instruction & tbit) == 0)
6381218822Sdim    {
6382218822Sdim      inst.error = _("invalid pseudo operation");
6383218822Sdim      return 1;
6384218822Sdim    }
6385218822Sdim  if (inst.reloc.exp.X_op != O_constant && inst.reloc.exp.X_op != O_symbol)
6386218822Sdim    {
6387218822Sdim      inst.error = _("constant expression expected");
6388218822Sdim      return 1;
6389218822Sdim    }
6390218822Sdim  if (inst.reloc.exp.X_op == O_constant)
6391218822Sdim    {
6392218822Sdim      if (thumb_p)
6393218822Sdim	{
6394218822Sdim	  if (!unified_syntax && (inst.reloc.exp.X_add_number & ~0xFF) == 0)
6395218822Sdim	    {
6396218822Sdim	      /* This can be done with a mov(1) instruction.  */
6397218822Sdim	      inst.instruction	= T_OPCODE_MOV_I8 | (inst.operands[i].reg << 8);
6398218822Sdim	      inst.instruction |= inst.reloc.exp.X_add_number;
6399218822Sdim	      return 1;
6400218822Sdim	    }
6401218822Sdim	}
6402218822Sdim      else
6403218822Sdim	{
6404218822Sdim	  int value = encode_arm_immediate (inst.reloc.exp.X_add_number);
6405218822Sdim	  if (value != FAIL)
6406218822Sdim	    {
6407218822Sdim	      /* This can be done with a mov instruction.  */
6408218822Sdim	      inst.instruction &= LITERAL_MASK;
6409218822Sdim	      inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT);
6410218822Sdim	      inst.instruction |= value & 0xfff;
6411218822Sdim	      return 1;
6412218822Sdim	    }
6413218822Sdim
6414218822Sdim	  value = encode_arm_immediate (~inst.reloc.exp.X_add_number);
6415218822Sdim	  if (value != FAIL)
6416218822Sdim	    {
6417218822Sdim	      /* This can be done with a mvn instruction.  */
6418218822Sdim	      inst.instruction &= LITERAL_MASK;
6419218822Sdim	      inst.instruction |= INST_IMMEDIATE | (OPCODE_MVN << DATA_OP_SHIFT);
6420218822Sdim	      inst.instruction |= value & 0xfff;
6421218822Sdim	      return 1;
6422218822Sdim	    }
6423218822Sdim	}
6424218822Sdim    }
6425218822Sdim
6426218822Sdim  if (add_to_lit_pool () == FAIL)
6427218822Sdim    {
6428218822Sdim      inst.error = _("literal pool insertion failed");
6429218822Sdim      return 1;
6430218822Sdim    }
6431218822Sdim  inst.operands[1].reg = REG_PC;
6432218822Sdim  inst.operands[1].isreg = 1;
6433218822Sdim  inst.operands[1].preind = 1;
6434218822Sdim  inst.reloc.pc_rel = 1;
6435218822Sdim  inst.reloc.type = (thumb_p
6436218822Sdim		     ? BFD_RELOC_ARM_THUMB_OFFSET
6437218822Sdim		     : (mode_3
6438218822Sdim			? BFD_RELOC_ARM_HWLITERAL
6439218822Sdim			: BFD_RELOC_ARM_LITERAL));
6440218822Sdim  return 0;
6441130561Sobrien}
6442130561Sobrien
6443218822Sdim/* Functions for instruction encoding, sorted by subarchitecture.
6444218822Sdim   First some generics; their names are taken from the conventional
6445218822Sdim   bit positions for register arguments in ARM format instructions.  */
6446218822Sdim
6447130561Sobrienstatic void
6448218822Sdimdo_noargs (void)
6449130561Sobrien{
6450130561Sobrien}
6451130561Sobrien
6452130561Sobrienstatic void
6453218822Sdimdo_rd (void)
6454130561Sobrien{
6455218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6456130561Sobrien}
6457130561Sobrien
6458130561Sobrienstatic void
6459218822Sdimdo_rd_rm (void)
6460130561Sobrien{
6461218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6462218822Sdim  inst.instruction |= inst.operands[1].reg;
6463130561Sobrien}
6464130561Sobrien
6465130561Sobrienstatic void
6466218822Sdimdo_rd_rn (void)
6467130561Sobrien{
6468218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6469218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
6470130561Sobrien}
6471130561Sobrien
6472130561Sobrienstatic void
6473218822Sdimdo_rn_rd (void)
6474130561Sobrien{
6475218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
6476218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
6477130561Sobrien}
6478130561Sobrien
6479130561Sobrienstatic void
6480218822Sdimdo_rd_rm_rn (void)
6481130561Sobrien{
6482218822Sdim  unsigned Rn = inst.operands[2].reg;
6483218822Sdim  /* Enforce restrictions on SWP instruction.  */
6484218822Sdim  if ((inst.instruction & 0x0fbfffff) == 0x01000090)
6485218822Sdim    constraint (Rn == inst.operands[0].reg || Rn == inst.operands[1].reg,
6486218822Sdim		_("Rn must not overlap other operands"));
6487218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6488218822Sdim  inst.instruction |= inst.operands[1].reg;
6489218822Sdim  inst.instruction |= Rn << 16;
6490130561Sobrien}
6491130561Sobrien
6492130561Sobrienstatic void
6493218822Sdimdo_rd_rn_rm (void)
6494130561Sobrien{
6495218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6496218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
6497218822Sdim  inst.instruction |= inst.operands[2].reg;
6498130561Sobrien}
6499130561Sobrien
6500130561Sobrienstatic void
6501218822Sdimdo_rm_rd_rn (void)
6502130561Sobrien{
6503218822Sdim  inst.instruction |= inst.operands[0].reg;
6504218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
6505218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
6506130561Sobrien}
6507130561Sobrien
6508130561Sobrienstatic void
6509218822Sdimdo_imm0 (void)
6510130561Sobrien{
6511218822Sdim  inst.instruction |= inst.operands[0].imm;
6512130561Sobrien}
6513130561Sobrien
6514130561Sobrienstatic void
6515218822Sdimdo_rd_cpaddr (void)
6516130561Sobrien{
6517218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6518218822Sdim  encode_arm_cp_address (1, TRUE, TRUE, 0);
6519130561Sobrien}
6520130561Sobrien
6521218822Sdim/* ARM instructions, in alphabetical order by function name (except
6522218822Sdim   that wrapper functions appear immediately after the function they
6523218822Sdim   wrap).  */
6524218822Sdim
6525218822Sdim/* This is a pseudo-op of the form "adr rd, label" to be converted
6526218822Sdim   into a relative address of the form "add rd, pc, #label-.-8".  */
6527218822Sdim
6528130561Sobrienstatic void
6529218822Sdimdo_adr (void)
6530130561Sobrien{
6531218822Sdim  inst.instruction |= (inst.operands[0].reg << 12);  /* Rd */
6532218822Sdim
6533218822Sdim  /* Frag hacking will turn this into a sub instruction if the offset turns
6534218822Sdim     out to be negative.  */
6535218822Sdim  inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
6536218822Sdim  inst.reloc.pc_rel = 1;
6537218822Sdim  inst.reloc.exp.X_add_number -= 8;
6538130561Sobrien}
6539130561Sobrien
6540218822Sdim/* This is a pseudo-op of the form "adrl rd, label" to be converted
6541218822Sdim   into a relative address of the form:
6542218822Sdim   add rd, pc, #low(label-.-8)"
6543218822Sdim   add rd, rd, #high(label-.-8)"  */
6544218822Sdim
6545130561Sobrienstatic void
6546218822Sdimdo_adrl (void)
6547130561Sobrien{
6548218822Sdim  inst.instruction |= (inst.operands[0].reg << 12);  /* Rd */
6549130561Sobrien
6550218822Sdim  /* Frag hacking will turn this into a sub instruction if the offset turns
6551218822Sdim     out to be negative.  */
6552218822Sdim  inst.reloc.type	       = BFD_RELOC_ARM_ADRL_IMMEDIATE;
6553218822Sdim  inst.reloc.pc_rel	       = 1;
6554218822Sdim  inst.size		       = INSN_SIZE * 2;
6555218822Sdim  inst.reloc.exp.X_add_number -= 8;
6556130561Sobrien}
6557130561Sobrien
6558130561Sobrienstatic void
6559218822Sdimdo_arit (void)
6560130561Sobrien{
6561218822Sdim  if (!inst.operands[1].present)
6562218822Sdim    inst.operands[1].reg = inst.operands[0].reg;
6563218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6564218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
6565218822Sdim  encode_arm_shifter_operand (2);
6566130561Sobrien}
6567130561Sobrien
6568130561Sobrienstatic void
6569218822Sdimdo_barrier (void)
6570130561Sobrien{
6571218822Sdim  if (inst.operands[0].present)
6572130561Sobrien    {
6573218822Sdim      constraint ((inst.instruction & 0xf0) != 0x40
6574218822Sdim		  && inst.operands[0].imm != 0xf,
6575218822Sdim		  "bad barrier type");
6576218822Sdim      inst.instruction |= inst.operands[0].imm;
6577130561Sobrien    }
6578130561Sobrien  else
6579218822Sdim    inst.instruction |= 0xf;
6580130561Sobrien}
6581130561Sobrien
6582130561Sobrienstatic void
6583218822Sdimdo_bfc (void)
6584130561Sobrien{
6585218822Sdim  unsigned int msb = inst.operands[1].imm + inst.operands[2].imm;
6586218822Sdim  constraint (msb > 32, _("bit-field extends past end of register"));
6587218822Sdim  /* The instruction encoding stores the LSB and MSB,
6588218822Sdim     not the LSB and width.  */
6589218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6590218822Sdim  inst.instruction |= inst.operands[1].imm << 7;
6591218822Sdim  inst.instruction |= (msb - 1) << 16;
6592130561Sobrien}
6593130561Sobrien
6594130561Sobrienstatic void
6595218822Sdimdo_bfi (void)
6596130561Sobrien{
6597218822Sdim  unsigned int msb;
6598218822Sdim
6599218822Sdim  /* #0 in second position is alternative syntax for bfc, which is
6600218822Sdim     the same instruction but with REG_PC in the Rm field.  */
6601218822Sdim  if (!inst.operands[1].isreg)
6602218822Sdim    inst.operands[1].reg = REG_PC;
6603218822Sdim
6604218822Sdim  msb = inst.operands[2].imm + inst.operands[3].imm;
6605218822Sdim  constraint (msb > 32, _("bit-field extends past end of register"));
6606218822Sdim  /* The instruction encoding stores the LSB and MSB,
6607218822Sdim     not the LSB and width.  */
6608218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6609218822Sdim  inst.instruction |= inst.operands[1].reg;
6610218822Sdim  inst.instruction |= inst.operands[2].imm << 7;
6611218822Sdim  inst.instruction |= (msb - 1) << 16;
6612130561Sobrien}
6613130561Sobrien
6614130561Sobrienstatic void
6615218822Sdimdo_bfx (void)
6616130561Sobrien{
6617218822Sdim  constraint (inst.operands[2].imm + inst.operands[3].imm > 32,
6618218822Sdim	      _("bit-field extends past end of register"));
6619218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6620218822Sdim  inst.instruction |= inst.operands[1].reg;
6621218822Sdim  inst.instruction |= inst.operands[2].imm << 7;
6622218822Sdim  inst.instruction |= (inst.operands[3].imm - 1) << 16;
6623130561Sobrien}
6624130561Sobrien
6625218822Sdim/* ARM V5 breakpoint instruction (argument parse)
6626218822Sdim     BKPT <16 bit unsigned immediate>
6627218822Sdim     Instruction is not conditional.
6628218822Sdim	The bit pattern given in insns[] has the COND_ALWAYS condition,
6629218822Sdim	and it is an error if the caller tried to override that.  */
6630218822Sdim
6631130561Sobrienstatic void
6632218822Sdimdo_bkpt (void)
6633130561Sobrien{
6634218822Sdim  /* Top 12 of 16 bits to bits 19:8.  */
6635218822Sdim  inst.instruction |= (inst.operands[0].imm & 0xfff0) << 4;
6636130561Sobrien
6637218822Sdim  /* Bottom 4 of 16 bits to bits 3:0.  */
6638218822Sdim  inst.instruction |= inst.operands[0].imm & 0xf;
6639218822Sdim}
6640130561Sobrien
6641218822Sdimstatic void
6642218822Sdimencode_branch (int default_reloc)
6643218822Sdim{
6644218822Sdim  if (inst.operands[0].hasreloc)
6645218822Sdim    {
6646218822Sdim      constraint (inst.operands[0].imm != BFD_RELOC_ARM_PLT32,
6647218822Sdim		  _("the only suffix valid here is '(plt)'"));
6648218822Sdim      inst.reloc.type	= BFD_RELOC_ARM_PLT32;
6649218822Sdim    }
6650218822Sdim  else
6651218822Sdim    {
6652218822Sdim      inst.reloc.type = default_reloc;
6653218822Sdim    }
6654218822Sdim  inst.reloc.pc_rel = 1;
6655130561Sobrien}
6656130561Sobrien
6657130561Sobrienstatic void
6658218822Sdimdo_branch (void)
6659130561Sobrien{
6660218822Sdim#ifdef OBJ_ELF
6661218822Sdim  if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4)
6662218822Sdim    encode_branch (BFD_RELOC_ARM_PCREL_JUMP);
6663218822Sdim  else
6664218822Sdim#endif
6665218822Sdim    encode_branch (BFD_RELOC_ARM_PCREL_BRANCH);
6666218822Sdim}
6667130561Sobrien
6668218822Sdimstatic void
6669218822Sdimdo_bl (void)
6670218822Sdim{
6671218822Sdim#ifdef OBJ_ELF
6672218822Sdim  if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4)
6673218822Sdim    {
6674218822Sdim      if (inst.cond == COND_ALWAYS)
6675218822Sdim	encode_branch (BFD_RELOC_ARM_PCREL_CALL);
6676218822Sdim      else
6677218822Sdim	encode_branch (BFD_RELOC_ARM_PCREL_JUMP);
6678218822Sdim    }
6679218822Sdim  else
6680218822Sdim#endif
6681218822Sdim    encode_branch (BFD_RELOC_ARM_PCREL_BRANCH);
6682130561Sobrien}
6683130561Sobrien
6684218822Sdim/* ARM V5 branch-link-exchange instruction (argument parse)
6685218822Sdim     BLX <target_addr>		ie BLX(1)
6686218822Sdim     BLX{<condition>} <Rm>	ie BLX(2)
6687218822Sdim   Unfortunately, there are two different opcodes for this mnemonic.
6688218822Sdim   So, the insns[].value is not used, and the code here zaps values
6689218822Sdim	into inst.instruction.
6690218822Sdim   Also, the <target_addr> can be 25 bits, hence has its own reloc.  */
669177298Sobrien
669277298Sobrienstatic void
6693218822Sdimdo_blx (void)
669477298Sobrien{
6695218822Sdim  if (inst.operands[0].isreg)
6696218822Sdim    {
6697218822Sdim      /* Arg is a register; the opcode provided by insns[] is correct.
6698218822Sdim	 It is not illegal to do "blx pc", just useless.  */
6699218822Sdim      if (inst.operands[0].reg == REG_PC)
6700218822Sdim	as_tsktsk (_("use of r15 in blx in ARM mode is not really useful"));
670177298Sobrien
6702218822Sdim      inst.instruction |= inst.operands[0].reg;
6703218822Sdim    }
6704218822Sdim  else
6705218822Sdim    {
6706218822Sdim      /* Arg is an address; this instruction cannot be executed
6707218822Sdim	 conditionally, and the opcode must be adjusted.  */
6708218822Sdim      constraint (inst.cond != COND_ALWAYS, BAD_COND);
6709218822Sdim      inst.instruction = 0xfa000000;
6710218822Sdim#ifdef OBJ_ELF
6711218822Sdim      if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4)
6712218822Sdim	encode_branch (BFD_RELOC_ARM_PCREL_CALL);
6713218822Sdim      else
6714218822Sdim#endif
6715218822Sdim	encode_branch (BFD_RELOC_ARM_PCREL_BLX);
6716218822Sdim    }
6717218822Sdim}
671877298Sobrien
6719218822Sdimstatic void
6720218822Sdimdo_bx (void)
6721218822Sdim{
6722218822Sdim  if (inst.operands[0].reg == REG_PC)
6723218822Sdim    as_tsktsk (_("use of r15 in bx in ARM mode is not really useful"));
672477298Sobrien
6725218822Sdim  inst.instruction |= inst.operands[0].reg;
672677298Sobrien}
672777298Sobrien
672877298Sobrien
6729218822Sdim/* ARM v5TEJ.  Jump to Jazelle code.  */
673077298Sobrien
673177298Sobrienstatic void
6732218822Sdimdo_bxj (void)
673377298Sobrien{
6734218822Sdim  if (inst.operands[0].reg == REG_PC)
6735218822Sdim    as_tsktsk (_("use of r15 in bxj is not really useful"));
673677298Sobrien
6737218822Sdim  inst.instruction |= inst.operands[0].reg;
6738218822Sdim}
673977298Sobrien
6740218822Sdim/* Co-processor data operation:
6741218822Sdim      CDP{cond} <coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>{, <opcode_2>}
6742218822Sdim      CDP2	<coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>{, <opcode_2>}	 */
6743218822Sdimstatic void
6744218822Sdimdo_cdp (void)
6745218822Sdim{
6746218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
6747218822Sdim  inst.instruction |= inst.operands[1].imm << 20;
6748218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
6749218822Sdim  inst.instruction |= inst.operands[3].reg << 16;
6750218822Sdim  inst.instruction |= inst.operands[4].reg;
6751218822Sdim  inst.instruction |= inst.operands[5].imm << 5;
6752218822Sdim}
675377298Sobrien
6754218822Sdimstatic void
6755218822Sdimdo_cmp (void)
6756218822Sdim{
6757218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
6758218822Sdim  encode_arm_shifter_operand (1);
675977298Sobrien}
676077298Sobrien
6761218822Sdim/* Transfer between coprocessor and ARM registers.
6762218822Sdim   MRC{cond} <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>{, <opcode_2>}
6763218822Sdim   MRC2
6764218822Sdim   MCR{cond}
6765218822Sdim   MCR2
676677298Sobrien
6767218822Sdim   No special properties.  */
676877298Sobrien
676977298Sobrienstatic void
6770218822Sdimdo_co_reg (void)
677177298Sobrien{
6772218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
6773218822Sdim  inst.instruction |= inst.operands[1].imm << 21;
6774218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
6775218822Sdim  inst.instruction |= inst.operands[3].reg << 16;
6776218822Sdim  inst.instruction |= inst.operands[4].reg;
6777218822Sdim  inst.instruction |= inst.operands[5].imm << 5;
6778218822Sdim}
677977298Sobrien
6780218822Sdim/* Transfer between coprocessor register and pair of ARM registers.
6781218822Sdim   MCRR{cond} <coproc>, <opcode>, <Rd>, <Rn>, <CRm>.
6782218822Sdim   MCRR2
6783218822Sdim   MRRC{cond}
6784218822Sdim   MRRC2
678577298Sobrien
6786218822Sdim   Two XScale instructions are special cases of these:
678777298Sobrien
6788218822Sdim     MAR{cond} acc0, <RdLo>, <RdHi> == MCRR{cond} p0, #0, <RdLo>, <RdHi>, c0
6789218822Sdim     MRA{cond} acc0, <RdLo>, <RdHi> == MRRC{cond} p0, #0, <RdLo>, <RdHi>, c0
679077298Sobrien
6791218822Sdim   Result unpredicatable if Rd or Rn is R15.  */
679277298Sobrien
6793218822Sdimstatic void
6794218822Sdimdo_co_reg2c (void)
6795218822Sdim{
6796218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
6797218822Sdim  inst.instruction |= inst.operands[1].imm << 4;
6798218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
6799218822Sdim  inst.instruction |= inst.operands[3].reg << 16;
6800218822Sdim  inst.instruction |= inst.operands[4].reg;
6801218822Sdim}
680277298Sobrien
6803218822Sdimstatic void
6804218822Sdimdo_cpsi (void)
6805218822Sdim{
6806218822Sdim  inst.instruction |= inst.operands[0].imm << 6;
6807218822Sdim  if (inst.operands[1].present)
6808218822Sdim    {
6809218822Sdim      inst.instruction |= CPSI_MMOD;
6810218822Sdim      inst.instruction |= inst.operands[1].imm;
6811218822Sdim    }
681277298Sobrien}
681377298Sobrien
6814218822Sdimstatic void
6815218822Sdimdo_dbg (void)
6816218822Sdim{
6817218822Sdim  inst.instruction |= inst.operands[0].imm;
6818218822Sdim}
681977298Sobrien
6820218822Sdimstatic void
6821218822Sdimdo_it (void)
6822218822Sdim{
6823218822Sdim  /* There is no IT instruction in ARM mode.  We
6824218822Sdim     process it but do not generate code for it.  */
6825218822Sdim  inst.size = 0;
6826218822Sdim}
682777298Sobrien
682877298Sobrienstatic void
6829218822Sdimdo_ldmstm (void)
683077298Sobrien{
6831218822Sdim  int base_reg = inst.operands[0].reg;
6832218822Sdim  int range = inst.operands[1].imm;
683377298Sobrien
6834218822Sdim  inst.instruction |= base_reg << 16;
6835218822Sdim  inst.instruction |= range;
683677298Sobrien
6837218822Sdim  if (inst.operands[1].writeback)
6838218822Sdim    inst.instruction |= LDM_TYPE_2_OR_3;
683977298Sobrien
6840218822Sdim  if (inst.operands[0].writeback)
684177298Sobrien    {
6842218822Sdim      inst.instruction |= WRITE_BACK;
6843218822Sdim      /* Check for unpredictable uses of writeback.  */
6844218822Sdim      if (inst.instruction & LOAD_BIT)
684577298Sobrien	{
6846218822Sdim	  /* Not allowed in LDM type 2.	 */
6847218822Sdim	  if ((inst.instruction & LDM_TYPE_2_OR_3)
6848218822Sdim	      && ((range & (1 << REG_PC)) == 0))
6849218822Sdim	    as_warn (_("writeback of base register is UNPREDICTABLE"));
6850218822Sdim	  /* Only allowed if base reg not in list for other types.  */
6851218822Sdim	  else if (range & (1 << base_reg))
6852218822Sdim	    as_warn (_("writeback of base register when in register list is UNPREDICTABLE"));
685377298Sobrien	}
6854218822Sdim      else /* STM.  */
685577298Sobrien	{
6856218822Sdim	  /* Not allowed for type 2.  */
6857218822Sdim	  if (inst.instruction & LDM_TYPE_2_OR_3)
6858218822Sdim	    as_warn (_("writeback of base register is UNPREDICTABLE"));
6859218822Sdim	  /* Only allowed if base reg not in list, or first in list.  */
6860218822Sdim	  else if ((range & (1 << base_reg))
6861218822Sdim		   && (range & ((1 << base_reg) - 1)))
6862218822Sdim	    as_warn (_("if writeback register is in list, it must be the lowest reg in the list"));
686377298Sobrien	}
686477298Sobrien    }
6865218822Sdim}
686677298Sobrien
6867218822Sdim/* ARMv5TE load-consecutive (argument parse)
6868218822Sdim   Mode is like LDRH.
686977298Sobrien
6870218822Sdim     LDRccD R, mode
6871218822Sdim     STRccD R, mode.  */
687277298Sobrien
6873218822Sdimstatic void
6874218822Sdimdo_ldrd (void)
6875218822Sdim{
6876218822Sdim  constraint (inst.operands[0].reg % 2 != 0,
6877218822Sdim	      _("first destination register must be even"));
6878218822Sdim  constraint (inst.operands[1].present
6879218822Sdim	      && inst.operands[1].reg != inst.operands[0].reg + 1,
6880218822Sdim	      _("can only load two consecutive registers"));
6881218822Sdim  constraint (inst.operands[0].reg == REG_LR, _("r14 not allowed here"));
6882218822Sdim  constraint (!inst.operands[2].isreg, _("'[' expected"));
688377298Sobrien
6884218822Sdim  if (!inst.operands[1].present)
6885218822Sdim    inst.operands[1].reg = inst.operands[0].reg + 1;
6886218822Sdim
6887218822Sdim  if (inst.instruction & LOAD_BIT)
6888218822Sdim    {
6889218822Sdim      /* encode_arm_addr_mode_3 will diagnose overlap between the base
6890218822Sdim	 register and the first register written; we have to diagnose
6891218822Sdim	 overlap between the base and the second register written here.	 */
689277298Sobrien
6893218822Sdim      if (inst.operands[2].reg == inst.operands[1].reg
6894218822Sdim	  && (inst.operands[2].writeback || inst.operands[2].postind))
6895218822Sdim	as_warn (_("base register written back, and overlaps "
6896218822Sdim		   "second destination register"));
689777298Sobrien
6898218822Sdim      /* For an index-register load, the index register must not overlap the
6899218822Sdim	 destination (even if not write-back).	*/
6900218822Sdim      else if (inst.operands[2].immisreg
6901218822Sdim	       && ((unsigned) inst.operands[2].imm == inst.operands[0].reg
6902218822Sdim		   || (unsigned) inst.operands[2].imm == inst.operands[1].reg))
6903218822Sdim	as_warn (_("index register overlaps destination register"));
690477298Sobrien    }
690577298Sobrien
6906218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6907218822Sdim  encode_arm_addr_mode_3 (2, /*is_t=*/FALSE);
690877298Sobrien}
690977298Sobrien
6910218822Sdimstatic void
6911218822Sdimdo_ldrex (void)
6912218822Sdim{
6913218822Sdim  constraint (!inst.operands[1].isreg || !inst.operands[1].preind
6914218822Sdim	      || inst.operands[1].postind || inst.operands[1].writeback
6915218822Sdim	      || inst.operands[1].immisreg || inst.operands[1].shifted
6916218822Sdim	      || inst.operands[1].negative
6917218822Sdim	      /* This can arise if the programmer has written
6918218822Sdim		   strex rN, rM, foo
6919218822Sdim		 or if they have mistakenly used a register name as the last
6920218822Sdim		 operand,  eg:
6921218822Sdim		   strex rN, rM, rX
6922218822Sdim		 It is very difficult to distinguish between these two cases
6923218822Sdim		 because "rX" might actually be a label. ie the register
6924218822Sdim		 name has been occluded by a symbol of the same name. So we
6925218822Sdim		 just generate a general 'bad addressing mode' type error
6926218822Sdim		 message and leave it up to the programmer to discover the
6927218822Sdim		 true cause and fix their mistake.  */
6928218822Sdim	      || (inst.operands[1].reg == REG_PC),
6929218822Sdim	      BAD_ADDR_MODE);
693077298Sobrien
6931218822Sdim  constraint (inst.reloc.exp.X_op != O_constant
6932218822Sdim	      || inst.reloc.exp.X_add_number != 0,
6933218822Sdim	      _("offset must be zero in ARM encoding"));
693477298Sobrien
6935218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6936218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
6937218822Sdim  inst.reloc.type = BFD_RELOC_UNUSED;
6938218822Sdim}
6939218822Sdim
694077298Sobrienstatic void
6941218822Sdimdo_ldrexd (void)
694277298Sobrien{
6943218822Sdim  constraint (inst.operands[0].reg % 2 != 0,
6944218822Sdim	      _("even register required"));
6945218822Sdim  constraint (inst.operands[1].present
6946218822Sdim	      && inst.operands[1].reg != inst.operands[0].reg + 1,
6947218822Sdim	      _("can only load two consecutive registers"));
6948218822Sdim  /* If op 1 were present and equal to PC, this function wouldn't
6949218822Sdim     have been called in the first place.  */
6950218822Sdim  constraint (inst.operands[0].reg == REG_LR, _("r14 not allowed here"));
695177298Sobrien
6952218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6953218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
6954218822Sdim}
695577298Sobrien
6956218822Sdimstatic void
6957218822Sdimdo_ldst (void)
6958218822Sdim{
6959218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6960218822Sdim  if (!inst.operands[1].isreg)
6961218822Sdim    if (move_or_literal_pool (0, /*thumb_p=*/FALSE, /*mode_3=*/FALSE))
696277298Sobrien      return;
6963218822Sdim  encode_arm_addr_mode_2 (1, /*is_t=*/FALSE);
6964218822Sdim}
696577298Sobrien
6966218822Sdimstatic void
6967218822Sdimdo_ldstt (void)
6968218822Sdim{
6969218822Sdim  /* ldrt/strt always use post-indexed addressing.  Turn [Rn] into [Rn]! and
6970218822Sdim     reject [Rn,...].  */
6971218822Sdim  if (inst.operands[1].preind)
697277298Sobrien    {
6973218822Sdim      constraint (inst.reloc.exp.X_op != O_constant ||
6974218822Sdim		  inst.reloc.exp.X_add_number != 0,
6975218822Sdim		  _("this instruction requires a post-indexed address"));
697677298Sobrien
6977218822Sdim      inst.operands[1].preind = 0;
6978218822Sdim      inst.operands[1].postind = 1;
6979218822Sdim      inst.operands[1].writeback = 1;
698077298Sobrien    }
6981218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6982218822Sdim  encode_arm_addr_mode_2 (1, /*is_t=*/TRUE);
6983218822Sdim}
698477298Sobrien
6985218822Sdim/* Halfword and signed-byte load/store operations.  */
6986218822Sdim
6987218822Sdimstatic void
6988218822Sdimdo_ldstv4 (void)
6989218822Sdim{
6990218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6991218822Sdim  if (!inst.operands[1].isreg)
6992218822Sdim    if (move_or_literal_pool (0, /*thumb_p=*/FALSE, /*mode_3=*/TRUE))
699377298Sobrien      return;
6994218822Sdim  encode_arm_addr_mode_3 (1, /*is_t=*/FALSE);
6995218822Sdim}
699677298Sobrien
6997218822Sdimstatic void
6998218822Sdimdo_ldsttv4 (void)
6999218822Sdim{
7000218822Sdim  /* ldrt/strt always use post-indexed addressing.  Turn [Rn] into [Rn]! and
7001218822Sdim     reject [Rn,...].  */
7002218822Sdim  if (inst.operands[1].preind)
700389857Sobrien    {
7004218822Sdim      constraint (inst.reloc.exp.X_op != O_constant ||
7005218822Sdim		  inst.reloc.exp.X_add_number != 0,
7006218822Sdim		  _("this instruction requires a post-indexed address"));
700789857Sobrien
7008218822Sdim      inst.operands[1].preind = 0;
7009218822Sdim      inst.operands[1].postind = 1;
7010218822Sdim      inst.operands[1].writeback = 1;
701189857Sobrien    }
7012218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7013218822Sdim  encode_arm_addr_mode_3 (1, /*is_t=*/TRUE);
7014218822Sdim}
701589857Sobrien
7016218822Sdim/* Co-processor register load/store.
7017218822Sdim   Format: <LDC|STC>{cond}[L] CP#,CRd,<address>	 */
7018218822Sdimstatic void
7019218822Sdimdo_lstc (void)
7020218822Sdim{
7021218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
7022218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
7023218822Sdim  encode_arm_cp_address (2, TRUE, TRUE, 0);
702477298Sobrien}
702577298Sobrien
7026218822Sdimstatic void
7027218822Sdimdo_mlas (void)
702860484Sobrien{
7029218822Sdim  /* This restriction does not apply to mls (nor to mla in v6 or later).  */
7030218822Sdim  if (inst.operands[0].reg == inst.operands[1].reg
7031218822Sdim      && !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6)
7032218822Sdim      && !(inst.instruction & 0x00400000))
7033218822Sdim    as_tsktsk (_("Rd and Rm should be different in mla"));
703460484Sobrien
7035218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7036218822Sdim  inst.instruction |= inst.operands[1].reg;
7037218822Sdim  inst.instruction |= inst.operands[2].reg << 8;
7038218822Sdim  inst.instruction |= inst.operands[3].reg << 12;
7039218822Sdim}
704077298Sobrien
7041218822Sdimstatic void
7042218822Sdimdo_mov (void)
7043218822Sdim{
7044218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7045218822Sdim  encode_arm_shifter_operand (1);
7046218822Sdim}
704760484Sobrien
7048218822Sdim/* ARM V6T2 16-bit immediate register load: MOV[WT]{cond} Rd, #<imm16>.	 */
7049218822Sdimstatic void
7050218822Sdimdo_mov16 (void)
7051218822Sdim{
7052218822Sdim  bfd_vma imm;
7053218822Sdim  bfd_boolean top;
705460484Sobrien
7055218822Sdim  top = (inst.instruction & 0x00400000) != 0;
7056218822Sdim  constraint (top && inst.reloc.type == BFD_RELOC_ARM_MOVW,
7057218822Sdim	      _(":lower16: not allowed this instruction"));
7058218822Sdim  constraint (!top && inst.reloc.type == BFD_RELOC_ARM_MOVT,
7059218822Sdim	      _(":upper16: not allowed instruction"));
7060218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7061218822Sdim  if (inst.reloc.type == BFD_RELOC_UNUSED)
706260484Sobrien    {
7063218822Sdim      imm = inst.reloc.exp.X_add_number;
7064218822Sdim      /* The value is in two pieces: 0:11, 16:19.  */
7065218822Sdim      inst.instruction |= (imm & 0x00000fff);
7066218822Sdim      inst.instruction |= (imm & 0x0000f000) << 4;
706760484Sobrien    }
706860484Sobrien}
706960484Sobrien
7070218822Sdimstatic void do_vfp_nsyn_opcode (const char *);
707177298Sobrien
707260484Sobrienstatic int
7073218822Sdimdo_vfp_nsyn_mrs (void)
707460484Sobrien{
7075218822Sdim  if (inst.operands[0].isvec)
707660484Sobrien    {
7077218822Sdim      if (inst.operands[1].reg != 1)
7078218822Sdim        first_error (_("operand 1 must be FPSCR"));
7079218822Sdim      memset (&inst.operands[0], '\0', sizeof (inst.operands[0]));
7080218822Sdim      memset (&inst.operands[1], '\0', sizeof (inst.operands[1]));
7081218822Sdim      do_vfp_nsyn_opcode ("fmstat");
708260484Sobrien    }
7083218822Sdim  else if (inst.operands[1].isvec)
7084218822Sdim    do_vfp_nsyn_opcode ("fmrx");
7085218822Sdim  else
7086218822Sdim    return FAIL;
7087218822Sdim
7088218822Sdim  return SUCCESS;
708960484Sobrien}
709060484Sobrien
709160484Sobrienstatic int
7092218822Sdimdo_vfp_nsyn_msr (void)
709360484Sobrien{
7094218822Sdim  if (inst.operands[0].isvec)
7095218822Sdim    do_vfp_nsyn_opcode ("fmxr");
7096218822Sdim  else
7097218822Sdim    return FAIL;
709877298Sobrien
7099218822Sdim  return SUCCESS;
7100218822Sdim}
710160484Sobrien
7102248466Sandrewstatic void
7103248460Sandrewdo_vfp_vmrs (void)
7104248460Sandrew{
7105248460Sandrew  int rt;
7106248460Sandrew
7107248460Sandrew  /* The destination register can be r0-r14 or APSR_nzcv */
7108248460Sandrew  if (inst.operands[0].reg > 14)
7109248460Sandrew    {
7110248460Sandrew      inst.error = BAD_PC;
7111248466Sandrew      return;
7112248460Sandrew    }
7113248460Sandrew
7114248460Sandrew  /* If the destination is r13 and not in ARM mode then unprefictable */
7115248460Sandrew  if (thumb_mode && inst.operands[0].reg == REG_SP)
7116248460Sandrew    {
7117248460Sandrew      inst.error = BAD_SP;
7118248466Sandrew      return;
7119248460Sandrew    }
7120248460Sandrew
7121248460Sandrew  /* If the destination is APSR_nzcv */
7122248460Sandrew  if (inst.operands[0].isvec && inst.operands[1].reg != 1)
7123248460Sandrew    {
7124248460Sandrew      inst.error = BAD_VMRS;
7125248466Sandrew      return;
7126248460Sandrew    }
7127248460Sandrew
7128248460Sandrew  if (inst.operands[0].isvec)
7129248460Sandrew    rt = 15;
7130248460Sandrew  else
7131248460Sandrew    rt = inst.operands[0].reg;
7132248460Sandrew
7133248460Sandrew  /* Or in the registers to use */
7134248460Sandrew  inst.instruction |= rt << 12;
7135248460Sandrew  inst.instruction |= inst.operands[1].reg << 16;
7136248460Sandrew}
7137248460Sandrew
7138248466Sandrewstatic void
7139248460Sandrewdo_vfp_vmsr (void)
7140248460Sandrew{
7141248460Sandrew  /* The destination register can be r0-r14 or APSR_nzcv */
7142248460Sandrew  if (inst.operands[1].reg > 14)
7143248460Sandrew    {
7144248460Sandrew      inst.error = BAD_PC;
7145248466Sandrew      return;
7146248460Sandrew    }
7147248460Sandrew
7148248460Sandrew  /* If the destination is r13 and not in ARM mode then unprefictable */
7149248460Sandrew  if (thumb_mode && inst.operands[0].reg == REG_SP)
7150248460Sandrew    {
7151248460Sandrew      inst.error = BAD_SP;
7152248466Sandrew      return;
7153248460Sandrew    }
7154248460Sandrew
7155248460Sandrew  /* Or in the registers to use */
7156248460Sandrew  inst.instruction |= inst.operands[1].reg << 12;
7157248460Sandrew  inst.instruction |= inst.operands[0].reg << 16;
7158248460Sandrew}
7159248460Sandrew
7160218822Sdimstatic void
7161218822Sdimdo_mrs (void)
7162218822Sdim{
7163218822Sdim  if (do_vfp_nsyn_mrs () == SUCCESS)
7164218822Sdim    return;
716589857Sobrien
7166218822Sdim  /* mrs only accepts CPSR/SPSR/CPSR_all/SPSR_all.  */
7167218822Sdim  constraint ((inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f))
7168218822Sdim	      != (PSR_c|PSR_f),
7169218822Sdim	      _("'CPSR' or 'SPSR' expected"));
7170218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7171218822Sdim  inst.instruction |= (inst.operands[1].imm & SPSR_BIT);
7172218822Sdim}
717360484Sobrien
7174218822Sdim/* Two possible forms:
7175218822Sdim      "{C|S}PSR_<field>, Rm",
7176218822Sdim      "{C|S}PSR_f, #expression".  */
7177218822Sdim
7178218822Sdimstatic void
7179218822Sdimdo_msr (void)
7180218822Sdim{
7181218822Sdim  if (do_vfp_nsyn_msr () == SUCCESS)
7182218822Sdim    return;
7183218822Sdim
7184218822Sdim  inst.instruction |= inst.operands[0].imm;
7185218822Sdim  if (inst.operands[1].isreg)
7186218822Sdim    inst.instruction |= inst.operands[1].reg;
7187218822Sdim  else
718860484Sobrien    {
7189218822Sdim      inst.instruction |= INST_IMMEDIATE;
7190218822Sdim      inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
7191218822Sdim      inst.reloc.pc_rel = 0;
719260484Sobrien    }
719360484Sobrien}
719460484Sobrien
7195218822Sdimstatic void
7196218822Sdimdo_mul (void)
719789857Sobrien{
7198218822Sdim  if (!inst.operands[2].present)
7199218822Sdim    inst.operands[2].reg = inst.operands[0].reg;
7200218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7201218822Sdim  inst.instruction |= inst.operands[1].reg;
7202218822Sdim  inst.instruction |= inst.operands[2].reg << 8;
7203218822Sdim
7204218822Sdim  if (inst.operands[0].reg == inst.operands[1].reg
7205218822Sdim      && !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6))
7206218822Sdim    as_tsktsk (_("Rd and Rm should be different in mul"));
720789857Sobrien}
720889857Sobrien
7209218822Sdim/* Long Multiply Parser
7210218822Sdim   UMULL RdLo, RdHi, Rm, Rs
7211218822Sdim   SMULL RdLo, RdHi, Rm, Rs
7212218822Sdim   UMLAL RdLo, RdHi, Rm, Rs
7213218822Sdim   SMLAL RdLo, RdHi, Rm, Rs.  */
721460484Sobrien
7215218822Sdimstatic void
7216218822Sdimdo_mull (void)
721760484Sobrien{
7218218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7219218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7220218822Sdim  inst.instruction |= inst.operands[2].reg;
7221218822Sdim  inst.instruction |= inst.operands[3].reg << 8;
722277298Sobrien
7223254449Sandrew  /* rdhi, rdlo and rm must all be different prior to ARMv6.  */
7224218822Sdim  if (inst.operands[0].reg == inst.operands[1].reg
7225254449Sandrew      || ((inst.operands[0].reg == inst.operands[2].reg
7226218822Sdim      || inst.operands[1].reg == inst.operands[2].reg)
7227254449Sandrew      && !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6)))
7228218822Sdim    as_tsktsk (_("rdhi, rdlo and rm must all be different"));
7229218822Sdim}
723077298Sobrien
7231218822Sdimstatic void
7232218822Sdimdo_nop (void)
7233218822Sdim{
7234218822Sdim  if (inst.operands[0].present)
723560484Sobrien    {
7236218822Sdim      /* Architectural NOP hints are CPSR sets with no bits selected.  */
7237218822Sdim      inst.instruction &= 0xf0000000;
7238218822Sdim      inst.instruction |= 0x0320f000 + inst.operands[0].imm;
723960484Sobrien    }
7240218822Sdim}
724160484Sobrien
7242218822Sdim/* ARM V6 Pack Halfword Bottom Top instruction (argument parse).
7243218822Sdim   PKHBT {<cond>} <Rd>, <Rn>, <Rm> {, LSL #<shift_imm>}
7244218822Sdim   Condition defaults to COND_ALWAYS.
7245218822Sdim   Error if Rd, Rn or Rm are R15.  */
724677298Sobrien
7247218822Sdimstatic void
7248218822Sdimdo_pkhbt (void)
7249218822Sdim{
7250218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7251218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7252218822Sdim  inst.instruction |= inst.operands[2].reg;
7253218822Sdim  if (inst.operands[3].present)
7254218822Sdim    encode_arm_shift (3);
7255218822Sdim}
725660484Sobrien
7257218822Sdim/* ARM V6 PKHTB (Argument Parse).  */
725860484Sobrien
7259218822Sdimstatic void
7260218822Sdimdo_pkhtb (void)
7261218822Sdim{
7262218822Sdim  if (!inst.operands[3].present)
7263130561Sobrien    {
7264218822Sdim      /* If the shift specifier is omitted, turn the instruction
7265218822Sdim	 into pkhbt rd, rm, rn. */
7266218822Sdim      inst.instruction &= 0xfff00010;
7267218822Sdim      inst.instruction |= inst.operands[0].reg << 12;
7268218822Sdim      inst.instruction |= inst.operands[1].reg;
7269218822Sdim      inst.instruction |= inst.operands[2].reg << 16;
7270130561Sobrien    }
7271218822Sdim  else
7272130561Sobrien    {
7273218822Sdim      inst.instruction |= inst.operands[0].reg << 12;
7274218822Sdim      inst.instruction |= inst.operands[1].reg << 16;
7275218822Sdim      inst.instruction |= inst.operands[2].reg;
7276218822Sdim      encode_arm_shift (3);
7277130561Sobrien    }
7278218822Sdim}
727960484Sobrien
7280218822Sdim/* ARMv5TE: Preload-Cache
728160484Sobrien
7282218822Sdim    PLD <addr_mode>
728360484Sobrien
7284218822Sdim  Syntactically, like LDR with B=1, W=0, L=1.  */
728560484Sobrien
7286218822Sdimstatic void
7287218822Sdimdo_pld (void)
7288218822Sdim{
7289218822Sdim  constraint (!inst.operands[0].isreg,
7290218822Sdim	      _("'[' expected after PLD mnemonic"));
7291218822Sdim  constraint (inst.operands[0].postind,
7292218822Sdim	      _("post-indexed expression used in preload instruction"));
7293218822Sdim  constraint (inst.operands[0].writeback,
7294218822Sdim	      _("writeback used in preload instruction"));
7295218822Sdim  constraint (!inst.operands[0].preind,
7296218822Sdim	      _("unindexed addressing used in preload instruction"));
7297218822Sdim  encode_arm_addr_mode_2 (0, /*is_t=*/FALSE);
7298218822Sdim}
729960484Sobrien
7300218822Sdim/* ARMv7: PLI <addr_mode>  */
7301218822Sdimstatic void
7302218822Sdimdo_pli (void)
7303218822Sdim{
7304218822Sdim  constraint (!inst.operands[0].isreg,
7305218822Sdim	      _("'[' expected after PLI mnemonic"));
7306218822Sdim  constraint (inst.operands[0].postind,
7307218822Sdim	      _("post-indexed expression used in preload instruction"));
7308218822Sdim  constraint (inst.operands[0].writeback,
7309218822Sdim	      _("writeback used in preload instruction"));
7310218822Sdim  constraint (!inst.operands[0].preind,
7311218822Sdim	      _("unindexed addressing used in preload instruction"));
7312218822Sdim  encode_arm_addr_mode_2 (0, /*is_t=*/FALSE);
7313218822Sdim  inst.instruction &= ~PRE_INDEX;
7314218822Sdim}
731577298Sobrien
7316218822Sdimstatic void
7317218822Sdimdo_push_pop (void)
7318218822Sdim{
7319218822Sdim  inst.operands[1] = inst.operands[0];
7320218822Sdim  memset (&inst.operands[0], 0, sizeof inst.operands[0]);
7321218822Sdim  inst.operands[0].isreg = 1;
7322218822Sdim  inst.operands[0].writeback = 1;
7323218822Sdim  inst.operands[0].reg = REG_SP;
7324218822Sdim  do_ldmstm ();
7325218822Sdim}
732677298Sobrien
7327218822Sdim/* ARM V6 RFE (Return from Exception) loads the PC and CPSR from the
7328218822Sdim   word at the specified address and the following word
7329218822Sdim   respectively.
7330218822Sdim   Unconditionally executed.
7331218822Sdim   Error if Rn is R15.	*/
733277298Sobrien
7333218822Sdimstatic void
7334218822Sdimdo_rfe (void)
7335218822Sdim{
7336218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7337218822Sdim  if (inst.operands[0].writeback)
7338218822Sdim    inst.instruction |= WRITE_BACK;
733960484Sobrien}
734060484Sobrien
7341218822Sdim/* ARM V6 ssat (argument parse).  */
734277298Sobrien
7343218822Sdimstatic void
7344218822Sdimdo_ssat (void)
734560484Sobrien{
7346218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7347218822Sdim  inst.instruction |= (inst.operands[1].imm - 1) << 16;
7348218822Sdim  inst.instruction |= inst.operands[2].reg;
734960484Sobrien
7350218822Sdim  if (inst.operands[3].present)
7351218822Sdim    encode_arm_shift (3);
7352218822Sdim}
735360484Sobrien
7354218822Sdim/* ARM V6 usat (argument parse).  */
735560484Sobrien
7356218822Sdimstatic void
7357218822Sdimdo_usat (void)
7358218822Sdim{
7359218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7360218822Sdim  inst.instruction |= inst.operands[1].imm << 16;
7361218822Sdim  inst.instruction |= inst.operands[2].reg;
736260484Sobrien
7363218822Sdim  if (inst.operands[3].present)
7364218822Sdim    encode_arm_shift (3);
7365218822Sdim}
736660484Sobrien
7367218822Sdim/* ARM V6 ssat16 (argument parse).  */
736860484Sobrien
7369218822Sdimstatic void
7370218822Sdimdo_ssat16 (void)
7371218822Sdim{
7372218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7373218822Sdim  inst.instruction |= ((inst.operands[1].imm - 1) << 16);
7374218822Sdim  inst.instruction |= inst.operands[2].reg;
7375218822Sdim}
737660484Sobrien
7377218822Sdimstatic void
7378218822Sdimdo_usat16 (void)
7379218822Sdim{
7380218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7381218822Sdim  inst.instruction |= inst.operands[1].imm << 16;
7382218822Sdim  inst.instruction |= inst.operands[2].reg;
7383218822Sdim}
738460484Sobrien
7385218822Sdim/* ARM V6 SETEND (argument parse).  Sets the E bit in the CPSR while
7386218822Sdim   preserving the other bits.
738760484Sobrien
7388218822Sdim   setend <endian_specifier>, where <endian_specifier> is either
7389218822Sdim   BE or LE.  */
739060484Sobrien
7391218822Sdimstatic void
7392218822Sdimdo_setend (void)
7393218822Sdim{
7394218822Sdim  if (inst.operands[0].imm)
7395218822Sdim    inst.instruction |= 0x200;
7396218822Sdim}
739760484Sobrien
7398218822Sdimstatic void
7399218822Sdimdo_shift (void)
7400218822Sdim{
7401218822Sdim  unsigned int Rm = (inst.operands[1].present
7402218822Sdim		     ? inst.operands[1].reg
7403218822Sdim		     : inst.operands[0].reg);
740460484Sobrien
7405218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7406218822Sdim  inst.instruction |= Rm;
7407218822Sdim  if (inst.operands[2].isreg)  /* Rd, {Rm,} Rs */
7408218822Sdim    {
7409218822Sdim      inst.instruction |= inst.operands[2].reg << 8;
7410218822Sdim      inst.instruction |= SHIFT_BY_REG;
741160484Sobrien    }
7412218822Sdim  else
7413218822Sdim    inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
7414218822Sdim}
741560484Sobrien
7416218822Sdimstatic void
7417218822Sdimdo_smc (void)
7418218822Sdim{
7419218822Sdim  inst.reloc.type = BFD_RELOC_ARM_SMC;
7420218822Sdim  inst.reloc.pc_rel = 0;
7421218822Sdim}
742260484Sobrien
7423218822Sdimstatic void
7424218822Sdimdo_swi (void)
7425218822Sdim{
7426218822Sdim  inst.reloc.type = BFD_RELOC_ARM_SWI;
7427218822Sdim  inst.reloc.pc_rel = 0;
742860484Sobrien}
742960484Sobrien
7430218822Sdim/* ARM V5E (El Segundo) signed-multiply-accumulate (argument parse)
7431218822Sdim   SMLAxy{cond} Rd,Rm,Rs,Rn
7432218822Sdim   SMLAWy{cond} Rd,Rm,Rs,Rn
7433218822Sdim   Error if any register is R15.  */
7434218822Sdim
7435218822Sdimstatic void
7436218822Sdimdo_smla (void)
743760484Sobrien{
7438218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7439218822Sdim  inst.instruction |= inst.operands[1].reg;
7440218822Sdim  inst.instruction |= inst.operands[2].reg << 8;
7441218822Sdim  inst.instruction |= inst.operands[3].reg << 12;
7442218822Sdim}
744360484Sobrien
7444218822Sdim/* ARM V5E (El Segundo) signed-multiply-accumulate-long (argument parse)
7445218822Sdim   SMLALxy{cond} Rdlo,Rdhi,Rm,Rs
7446218822Sdim   Error if any register is R15.
7447218822Sdim   Warning if Rdlo == Rdhi.  */
744877298Sobrien
7449218822Sdimstatic void
7450218822Sdimdo_smlal (void)
7451218822Sdim{
7452218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7453218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7454218822Sdim  inst.instruction |= inst.operands[2].reg;
7455218822Sdim  inst.instruction |= inst.operands[3].reg << 8;
7456218822Sdim
7457218822Sdim  if (inst.operands[0].reg == inst.operands[1].reg)
7458218822Sdim    as_tsktsk (_("rdhi and rdlo must be different"));
7459218822Sdim}
7460218822Sdim
7461218822Sdim/* ARM V5E (El Segundo) signed-multiply (argument parse)
7462218822Sdim   SMULxy{cond} Rd,Rm,Rs
7463218822Sdim   Error if any register is R15.  */
7464218822Sdim
7465218822Sdimstatic void
7466218822Sdimdo_smul (void)
7467218822Sdim{
7468218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7469218822Sdim  inst.instruction |= inst.operands[1].reg;
7470218822Sdim  inst.instruction |= inst.operands[2].reg << 8;
7471218822Sdim}
7472218822Sdim
7473218822Sdim/* ARM V6 srs (argument parse).  The variable fields in the encoding are
7474218822Sdim   the same for both ARM and Thumb-2.  */
7475218822Sdim
7476218822Sdimstatic void
7477218822Sdimdo_srs (void)
7478218822Sdim{
7479218822Sdim  int reg;
7480218822Sdim
7481218822Sdim  if (inst.operands[0].present)
748260484Sobrien    {
7483218822Sdim      reg = inst.operands[0].reg;
7484218822Sdim      constraint (reg != 13, _("SRS base register must be r13"));
748560484Sobrien    }
748660484Sobrien  else
7487218822Sdim    reg = 13;
748877298Sobrien
7489218822Sdim  inst.instruction |= reg << 16;
7490218822Sdim  inst.instruction |= inst.operands[1].imm;
7491218822Sdim  if (inst.operands[0].writeback || inst.operands[1].writeback)
7492218822Sdim    inst.instruction |= WRITE_BACK;
7493218822Sdim}
749460484Sobrien
7495218822Sdim/* ARM V6 strex (argument parse).  */
749660484Sobrien
7497218822Sdimstatic void
7498218822Sdimdo_strex (void)
7499218822Sdim{
7500218822Sdim  constraint (!inst.operands[2].isreg || !inst.operands[2].preind
7501218822Sdim	      || inst.operands[2].postind || inst.operands[2].writeback
7502218822Sdim	      || inst.operands[2].immisreg || inst.operands[2].shifted
7503218822Sdim	      || inst.operands[2].negative
7504218822Sdim	      /* See comment in do_ldrex().  */
7505218822Sdim	      || (inst.operands[2].reg == REG_PC),
7506218822Sdim	      BAD_ADDR_MODE);
750777298Sobrien
7508218822Sdim  constraint (inst.operands[0].reg == inst.operands[1].reg
7509218822Sdim	      || inst.operands[0].reg == inst.operands[2].reg, BAD_OVERLAP);
751060484Sobrien
7511218822Sdim  constraint (inst.reloc.exp.X_op != O_constant
7512218822Sdim	      || inst.reloc.exp.X_add_number != 0,
7513218822Sdim	      _("offset must be zero in ARM encoding"));
751460484Sobrien
7515218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7516218822Sdim  inst.instruction |= inst.operands[1].reg;
7517218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
7518218822Sdim  inst.reloc.type = BFD_RELOC_UNUSED;
7519218822Sdim}
752060484Sobrien
7521218822Sdimstatic void
7522218822Sdimdo_strexd (void)
7523218822Sdim{
7524218822Sdim  constraint (inst.operands[1].reg % 2 != 0,
7525218822Sdim	      _("even register required"));
7526218822Sdim  constraint (inst.operands[2].present
7527218822Sdim	      && inst.operands[2].reg != inst.operands[1].reg + 1,
7528218822Sdim	      _("can only store two consecutive registers"));
7529218822Sdim  /* If op 2 were present and equal to PC, this function wouldn't
7530218822Sdim     have been called in the first place.  */
7531218822Sdim  constraint (inst.operands[1].reg == REG_LR, _("r14 not allowed here"));
753260484Sobrien
7533218822Sdim  constraint (inst.operands[0].reg == inst.operands[1].reg
7534218822Sdim	      || inst.operands[0].reg == inst.operands[1].reg + 1
7535218822Sdim	      || inst.operands[0].reg == inst.operands[3].reg,
7536218822Sdim	      BAD_OVERLAP);
753760484Sobrien
7538218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7539218822Sdim  inst.instruction |= inst.operands[1].reg;
7540218822Sdim  inst.instruction |= inst.operands[3].reg << 16;
754160484Sobrien}
754260484Sobrien
7543218822Sdim/* ARM V6 SXTAH extracts a 16-bit value from a register, sign
7544218822Sdim   extends it to 32-bits, and adds the result to a value in another
7545218822Sdim   register.  You can specify a rotation by 0, 8, 16, or 24 bits
7546218822Sdim   before extracting the 16-bit value.
7547218822Sdim   SXTAH{<cond>} <Rd>, <Rn>, <Rm>{, <rotation>}
7548218822Sdim   Condition defaults to COND_ALWAYS.
7549218822Sdim   Error if any register uses R15.  */
7550218822Sdim
7551218822Sdimstatic void
7552218822Sdimdo_sxtah (void)
755360484Sobrien{
7554218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7555218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7556218822Sdim  inst.instruction |= inst.operands[2].reg;
7557218822Sdim  inst.instruction |= inst.operands[3].imm << 10;
7558218822Sdim}
755960484Sobrien
7560218822Sdim/* ARM V6 SXTH.
756160484Sobrien
7562218822Sdim   SXTH {<cond>} <Rd>, <Rm>{, <rotation>}
7563218822Sdim   Condition defaults to COND_ALWAYS.
7564218822Sdim   Error if any register uses R15.  */
756560484Sobrien
7566218822Sdimstatic void
7567218822Sdimdo_sxth (void)
7568218822Sdim{
7569218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7570218822Sdim  inst.instruction |= inst.operands[1].reg;
7571218822Sdim  inst.instruction |= inst.operands[2].imm << 10;
7572218822Sdim}
7573218822Sdim
7574218822Sdim/* VFP instructions.  In a logical order: SP variant first, monad
7575218822Sdim   before dyad, arithmetic then move then load/store.  */
757660484Sobrien
7577218822Sdimstatic void
7578218822Sdimdo_vfp_sp_monadic (void)
7579218822Sdim{
7580218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7581218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sm);
7582218822Sdim}
758360484Sobrien
7584218822Sdimstatic void
7585218822Sdimdo_vfp_sp_dyadic (void)
7586218822Sdim{
7587218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7588218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sn);
7589218822Sdim  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Sm);
7590218822Sdim}
759160484Sobrien
7592218822Sdimstatic void
7593218822Sdimdo_vfp_sp_compare_z (void)
7594218822Sdim{
7595218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7596218822Sdim}
759760484Sobrien
7598218822Sdimstatic void
7599218822Sdimdo_vfp_dp_sp_cvt (void)
7600218822Sdim{
7601218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7602218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sm);
7603218822Sdim}
760460484Sobrien
7605218822Sdimstatic void
7606218822Sdimdo_vfp_sp_dp_cvt (void)
7607218822Sdim{
7608218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7609218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dm);
761060484Sobrien}
761160484Sobrien
761260484Sobrienstatic void
7613218822Sdimdo_vfp_reg_from_sp (void)
761460484Sobrien{
7615218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7616218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sn);
7617218822Sdim}
761860484Sobrien
7619218822Sdimstatic void
7620218822Sdimdo_vfp_reg2_from_sp2 (void)
7621218822Sdim{
7622218822Sdim  constraint (inst.operands[2].imm != 2,
7623218822Sdim	      _("only two consecutive VFP SP registers allowed here"));
7624218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7625218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7626218822Sdim  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Sm);
7627218822Sdim}
762860484Sobrien
7629218822Sdimstatic void
7630218822Sdimdo_vfp_sp_from_reg (void)
7631218822Sdim{
7632218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sn);
7633218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
763460484Sobrien}
763560484Sobrien
763660484Sobrienstatic void
7637218822Sdimdo_vfp_sp2_from_reg2 (void)
763860484Sobrien{
7639218822Sdim  constraint (inst.operands[0].imm != 2,
7640218822Sdim	      _("only two consecutive VFP SP registers allowed here"));
7641218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sm);
7642218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
7643218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
7644218822Sdim}
764560484Sobrien
7646218822Sdimstatic void
7647218822Sdimdo_vfp_sp_ldst (void)
7648218822Sdim{
7649218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7650218822Sdim  encode_arm_cp_address (1, FALSE, TRUE, 0);
7651218822Sdim}
765277298Sobrien
7653218822Sdimstatic void
7654218822Sdimdo_vfp_dp_ldst (void)
7655218822Sdim{
7656218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7657218822Sdim  encode_arm_cp_address (1, FALSE, TRUE, 0);
7658218822Sdim}
765977298Sobrien
7660218822Sdim
7661218822Sdimstatic void
7662218822Sdimvfp_sp_ldstm (enum vfp_ldstm_type ldstm_type)
7663218822Sdim{
7664218822Sdim  if (inst.operands[0].writeback)
7665218822Sdim    inst.instruction |= WRITE_BACK;
7666218822Sdim  else
7667218822Sdim    constraint (ldstm_type != VFP_LDSTMIA,
7668218822Sdim		_("this addressing mode requires base-register writeback"));
7669218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7670218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sd);
7671218822Sdim  inst.instruction |= inst.operands[1].imm;
767260484Sobrien}
767360484Sobrien
767460484Sobrienstatic void
7675218822Sdimvfp_dp_ldstm (enum vfp_ldstm_type ldstm_type)
767660484Sobrien{
7677218822Sdim  int count;
767860484Sobrien
7679218822Sdim  if (inst.operands[0].writeback)
7680218822Sdim    inst.instruction |= WRITE_BACK;
7681218822Sdim  else
7682218822Sdim    constraint (ldstm_type != VFP_LDSTMIA && ldstm_type != VFP_LDSTMIAX,
7683218822Sdim		_("this addressing mode requires base-register writeback"));
768460484Sobrien
7685218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7686218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dd);
768789857Sobrien
7688218822Sdim  count = inst.operands[1].imm << 1;
7689218822Sdim  if (ldstm_type == VFP_LDSTMIAX || ldstm_type == VFP_LDSTMDBX)
7690218822Sdim    count += 1;
769177298Sobrien
7692218822Sdim  inst.instruction |= count;
769360484Sobrien}
769460484Sobrien
769560484Sobrienstatic void
7696218822Sdimdo_vfp_sp_ldstmia (void)
769760484Sobrien{
7698218822Sdim  vfp_sp_ldstm (VFP_LDSTMIA);
7699218822Sdim}
770060484Sobrien
7701218822Sdimstatic void
7702218822Sdimdo_vfp_sp_ldstmdb (void)
7703218822Sdim{
7704218822Sdim  vfp_sp_ldstm (VFP_LDSTMDB);
7705218822Sdim}
770660484Sobrien
7707218822Sdimstatic void
7708218822Sdimdo_vfp_dp_ldstmia (void)
7709218822Sdim{
7710218822Sdim  vfp_dp_ldstm (VFP_LDSTMIA);
7711218822Sdim}
771260484Sobrien
7713218822Sdimstatic void
7714218822Sdimdo_vfp_dp_ldstmdb (void)
7715218822Sdim{
7716218822Sdim  vfp_dp_ldstm (VFP_LDSTMDB);
771760484Sobrien}
771860484Sobrien
771960484Sobrienstatic void
7720218822Sdimdo_vfp_xp_ldstmia (void)
772160484Sobrien{
7722218822Sdim  vfp_dp_ldstm (VFP_LDSTMIAX);
7723218822Sdim}
772460484Sobrien
7725218822Sdimstatic void
7726218822Sdimdo_vfp_xp_ldstmdb (void)
7727218822Sdim{
7728218822Sdim  vfp_dp_ldstm (VFP_LDSTMDBX);
7729218822Sdim}
773060484Sobrien
7731218822Sdimstatic void
7732218822Sdimdo_vfp_dp_rd_rm (void)
7733218822Sdim{
7734218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7735218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dm);
7736218822Sdim}
773760484Sobrien
7738218822Sdimstatic void
7739218822Sdimdo_vfp_dp_rn_rd (void)
7740218822Sdim{
7741218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dn);
7742218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dd);
774360484Sobrien}
774460484Sobrien
7745218822Sdimstatic void
7746218822Sdimdo_vfp_dp_rd_rn (void)
774760484Sobrien{
7748218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7749218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dn);
7750218822Sdim}
775160484Sobrien
7752218822Sdimstatic void
7753218822Sdimdo_vfp_dp_rd_rn_rm (void)
7754218822Sdim{
7755218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7756218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dn);
7757218822Sdim  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Dm);
7758218822Sdim}
775960484Sobrien
7760218822Sdimstatic void
7761218822Sdimdo_vfp_dp_rd (void)
7762218822Sdim{
7763218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7764218822Sdim}
776560484Sobrien
7766218822Sdimstatic void
7767218822Sdimdo_vfp_dp_rm_rd_rn (void)
7768218822Sdim{
7769218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dm);
7770218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dd);
7771218822Sdim  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Dn);
7772218822Sdim}
777360484Sobrien
7774218822Sdim/* VFPv3 instructions.  */
7775218822Sdimstatic void
7776218822Sdimdo_vfp_sp_const (void)
7777218822Sdim{
7778218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7779218822Sdim  inst.instruction |= (inst.operands[1].imm & 0xf0) << 12;
7780218822Sdim  inst.instruction |= (inst.operands[1].imm & 0x0f);
7781218822Sdim}
778260484Sobrien
7783218822Sdimstatic void
7784218822Sdimdo_vfp_dp_const (void)
7785218822Sdim{
7786218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7787218822Sdim  inst.instruction |= (inst.operands[1].imm & 0xf0) << 12;
7788218822Sdim  inst.instruction |= (inst.operands[1].imm & 0x0f);
7789218822Sdim}
779060484Sobrien
7791218822Sdimstatic void
7792218822Sdimvfp_conv (int srcsize)
7793218822Sdim{
7794218822Sdim  unsigned immbits = srcsize - inst.operands[1].imm;
7795218822Sdim  inst.instruction |= (immbits & 1) << 5;
7796218822Sdim  inst.instruction |= (immbits >> 1);
7797218822Sdim}
779877298Sobrien
7799218822Sdimstatic void
7800218822Sdimdo_vfp_sp_conv_16 (void)
7801218822Sdim{
7802218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7803218822Sdim  vfp_conv (16);
7804218822Sdim}
780577298Sobrien
7806218822Sdimstatic void
7807218822Sdimdo_vfp_dp_conv_16 (void)
7808218822Sdim{
7809218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7810218822Sdim  vfp_conv (16);
7811218822Sdim}
781260484Sobrien
7813218822Sdimstatic void
7814218822Sdimdo_vfp_sp_conv_32 (void)
7815218822Sdim{
7816218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7817218822Sdim  vfp_conv (32);
781860484Sobrien}
781960484Sobrien
782060484Sobrienstatic void
7821218822Sdimdo_vfp_dp_conv_32 (void)
782260484Sobrien{
7823218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7824218822Sdim  vfp_conv (32);
7825218822Sdim}
782660484Sobrien
7827218822Sdim
7828218822Sdim/* FPA instructions.  Also in a logical order.	*/
782989857Sobrien
7830218822Sdimstatic void
7831218822Sdimdo_fpa_cmp (void)
7832218822Sdim{
7833218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7834218822Sdim  inst.instruction |= inst.operands[1].reg;
7835218822Sdim}
783689857Sobrien
7837218822Sdimstatic void
7838218822Sdimdo_fpa_ldmstm (void)
7839218822Sdim{
7840218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7841218822Sdim  switch (inst.operands[1].imm)
784289857Sobrien    {
7843218822Sdim    case 1: inst.instruction |= CP_T_X;		 break;
7844218822Sdim    case 2: inst.instruction |= CP_T_Y;		 break;
7845218822Sdim    case 3: inst.instruction |= CP_T_Y | CP_T_X; break;
7846218822Sdim    case 4:					 break;
7847218822Sdim    default: abort ();
784889857Sobrien    }
784989857Sobrien
7850218822Sdim  if (inst.instruction & (PRE_INDEX | INDEX_UP))
785189857Sobrien    {
7852218822Sdim      /* The instruction specified "ea" or "fd", so we can only accept
7853218822Sdim	 [Rn]{!}.  The instruction does not really support stacking or
7854218822Sdim	 unstacking, so we have to emulate these by setting appropriate
7855218822Sdim	 bits and offsets.  */
7856218822Sdim      constraint (inst.reloc.exp.X_op != O_constant
7857218822Sdim		  || inst.reloc.exp.X_add_number != 0,
7858218822Sdim		  _("this instruction does not support indexing"));
785989857Sobrien
7860218822Sdim      if ((inst.instruction & PRE_INDEX) || inst.operands[2].writeback)
7861218822Sdim	inst.reloc.exp.X_add_number = 12 * inst.operands[1].imm;
786289857Sobrien
7863218822Sdim      if (!(inst.instruction & INDEX_UP))
7864218822Sdim	inst.reloc.exp.X_add_number = -inst.reloc.exp.X_add_number;
786589857Sobrien
7866218822Sdim      if (!(inst.instruction & PRE_INDEX) && inst.operands[2].writeback)
7867218822Sdim	{
7868218822Sdim	  inst.operands[2].preind = 0;
7869218822Sdim	  inst.operands[2].postind = 1;
7870218822Sdim	}
7871218822Sdim    }
787289857Sobrien
7873218822Sdim  encode_arm_cp_address (2, TRUE, TRUE, 0);
7874218822Sdim}
787589857Sobrien
7876218822Sdim
7877218822Sdim/* iWMMXt instructions: strictly in alphabetical order.	 */
787889857Sobrien
7879218822Sdimstatic void
7880218822Sdimdo_iwmmxt_tandorc (void)
7881218822Sdim{
7882218822Sdim  constraint (inst.operands[0].reg != REG_PC, _("only r15 allowed here"));
7883218822Sdim}
788489857Sobrien
7885218822Sdimstatic void
7886218822Sdimdo_iwmmxt_textrc (void)
7887218822Sdim{
7888218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7889218822Sdim  inst.instruction |= inst.operands[1].imm;
7890218822Sdim}
789189857Sobrien
7892218822Sdimstatic void
7893218822Sdimdo_iwmmxt_textrm (void)
7894218822Sdim{
7895218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7896218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7897218822Sdim  inst.instruction |= inst.operands[2].imm;
7898218822Sdim}
789989857Sobrien
7900218822Sdimstatic void
7901218822Sdimdo_iwmmxt_tinsr (void)
7902218822Sdim{
7903218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7904218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
7905218822Sdim  inst.instruction |= inst.operands[2].imm;
7906218822Sdim}
790789857Sobrien
7908218822Sdimstatic void
7909218822Sdimdo_iwmmxt_tmia (void)
7910218822Sdim{
7911218822Sdim  inst.instruction |= inst.operands[0].reg << 5;
7912218822Sdim  inst.instruction |= inst.operands[1].reg;
7913218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
7914218822Sdim}
791589857Sobrien
7916218822Sdimstatic void
7917218822Sdimdo_iwmmxt_waligni (void)
7918218822Sdim{
7919218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7920218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7921218822Sdim  inst.instruction |= inst.operands[2].reg;
7922218822Sdim  inst.instruction |= inst.operands[3].imm << 20;
7923218822Sdim}
792489857Sobrien
7925218822Sdimstatic void
7926218822Sdimdo_iwmmxt_wmerge (void)
7927218822Sdim{
7928218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7929218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7930218822Sdim  inst.instruction |= inst.operands[2].reg;
7931218822Sdim  inst.instruction |= inst.operands[3].imm << 21;
7932218822Sdim}
793389857Sobrien
7934218822Sdimstatic void
7935218822Sdimdo_iwmmxt_wmov (void)
7936218822Sdim{
7937218822Sdim  /* WMOV rD, rN is an alias for WOR rD, rN, rN.  */
7938218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7939218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7940218822Sdim  inst.instruction |= inst.operands[1].reg;
7941218822Sdim}
794289857Sobrien
7943218822Sdimstatic void
7944218822Sdimdo_iwmmxt_wldstbh (void)
7945218822Sdim{
7946218822Sdim  int reloc;
7947218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7948218822Sdim  if (thumb_mode)
7949218822Sdim    reloc = BFD_RELOC_ARM_T32_CP_OFF_IMM_S2;
7950218822Sdim  else
7951218822Sdim    reloc = BFD_RELOC_ARM_CP_OFF_IMM_S2;
7952218822Sdim  encode_arm_cp_address (1, TRUE, FALSE, reloc);
7953218822Sdim}
7954218822Sdim
7955218822Sdimstatic void
7956218822Sdimdo_iwmmxt_wldstw (void)
7957218822Sdim{
7958218822Sdim  /* RIWR_RIWC clears .isreg for a control register.  */
7959218822Sdim  if (!inst.operands[0].isreg)
7960218822Sdim    {
7961218822Sdim      constraint (inst.cond != COND_ALWAYS, BAD_COND);
7962218822Sdim      inst.instruction |= 0xf0000000;
796389857Sobrien    }
796460484Sobrien
7965218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7966218822Sdim  encode_arm_cp_address (1, TRUE, TRUE, 0);
7967218822Sdim}
796860484Sobrien
7969218822Sdimstatic void
7970218822Sdimdo_iwmmxt_wldstd (void)
7971218822Sdim{
7972218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7973218822Sdim  if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2)
7974218822Sdim      && inst.operands[1].immisreg)
7975218822Sdim    {
7976218822Sdim      inst.instruction &= ~0x1a000ff;
7977218822Sdim      inst.instruction |= (0xf << 28);
7978218822Sdim      if (inst.operands[1].preind)
7979218822Sdim	inst.instruction |= PRE_INDEX;
7980218822Sdim      if (!inst.operands[1].negative)
7981218822Sdim	inst.instruction |= INDEX_UP;
7982218822Sdim      if (inst.operands[1].writeback)
7983218822Sdim	inst.instruction |= WRITE_BACK;
7984218822Sdim      inst.instruction |= inst.operands[1].reg << 16;
7985218822Sdim      inst.instruction |= inst.reloc.exp.X_add_number << 4;
7986218822Sdim      inst.instruction |= inst.operands[1].imm;
7987218822Sdim    }
7988218822Sdim  else
7989218822Sdim    encode_arm_cp_address (1, TRUE, FALSE, 0);
7990218822Sdim}
799189857Sobrien
7992218822Sdimstatic void
7993218822Sdimdo_iwmmxt_wshufh (void)
7994218822Sdim{
7995218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7996218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7997218822Sdim  inst.instruction |= ((inst.operands[2].imm & 0xf0) << 16);
7998218822Sdim  inst.instruction |= (inst.operands[2].imm & 0x0f);
7999218822Sdim}
800089857Sobrien
8001218822Sdimstatic void
8002218822Sdimdo_iwmmxt_wzero (void)
8003218822Sdim{
8004218822Sdim  /* WZERO reg is an alias for WANDN reg, reg, reg.  */
8005218822Sdim  inst.instruction |= inst.operands[0].reg;
8006218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
8007218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
8008218822Sdim}
800989857Sobrien
8010218822Sdimstatic void
8011218822Sdimdo_iwmmxt_wrwrwr_or_imm5 (void)
8012218822Sdim{
8013218822Sdim  if (inst.operands[2].isreg)
8014218822Sdim    do_rd_rn_rm ();
8015218822Sdim  else {
8016218822Sdim    constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2),
8017218822Sdim		_("immediate operand requires iWMMXt2"));
8018218822Sdim    do_rd_rn ();
8019218822Sdim    if (inst.operands[2].imm == 0)
8020218822Sdim      {
8021218822Sdim	switch ((inst.instruction >> 20) & 0xf)
8022218822Sdim	  {
8023218822Sdim	  case 4:
8024218822Sdim	  case 5:
8025218822Sdim	  case 6:
8026218822Sdim	  case 7:
8027218822Sdim	    /* w...h wrd, wrn, #0 -> wrorh wrd, wrn, #16.  */
8028218822Sdim	    inst.operands[2].imm = 16;
8029218822Sdim	    inst.instruction = (inst.instruction & 0xff0fffff) | (0x7 << 20);
8030218822Sdim	    break;
8031218822Sdim	  case 8:
8032218822Sdim	  case 9:
8033218822Sdim	  case 10:
8034218822Sdim	  case 11:
8035218822Sdim	    /* w...w wrd, wrn, #0 -> wrorw wrd, wrn, #32.  */
8036218822Sdim	    inst.operands[2].imm = 32;
8037218822Sdim	    inst.instruction = (inst.instruction & 0xff0fffff) | (0xb << 20);
8038218822Sdim	    break;
8039218822Sdim	  case 12:
8040218822Sdim	  case 13:
8041218822Sdim	  case 14:
8042218822Sdim	  case 15:
804389857Sobrien	    {
8044218822Sdim	      /* w...d wrd, wrn, #0 -> wor wrd, wrn, wrn.  */
8045218822Sdim	      unsigned long wrn;
8046218822Sdim	      wrn = (inst.instruction >> 16) & 0xf;
8047218822Sdim	      inst.instruction &= 0xff0fff0f;
8048218822Sdim	      inst.instruction |= wrn;
8049218822Sdim	      /* Bail out here; the instruction is now assembled.  */
805089857Sobrien	      return;
805189857Sobrien	    }
8052218822Sdim	  }
8053218822Sdim      }
8054218822Sdim    /* Map 32 -> 0, etc.  */
8055218822Sdim    inst.operands[2].imm &= 0x1f;
8056218822Sdim    inst.instruction |= (0xf << 28) | ((inst.operands[2].imm & 0x10) << 4) | (inst.operands[2].imm & 0xf);
8057218822Sdim  }
8058218822Sdim}
8059218822Sdim
8060218822Sdim/* Cirrus Maverick instructions.  Simple 2-, 3-, and 4-register
8061218822Sdim   operations first, then control, shift, and load/store.  */
806289857Sobrien
8063218822Sdim/* Insns like "foo X,Y,Z".  */
806489857Sobrien
8065218822Sdimstatic void
8066218822Sdimdo_mav_triple (void)
8067218822Sdim{
8068218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
8069218822Sdim  inst.instruction |= inst.operands[1].reg;
8070218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
8071218822Sdim}
807289857Sobrien
8073218822Sdim/* Insns like "foo W,X,Y,Z".
8074218822Sdim    where W=MVAX[0:3] and X,Y,Z=MVFX[0:15].  */
807589857Sobrien
8076218822Sdimstatic void
8077218822Sdimdo_mav_quad (void)
8078218822Sdim{
8079218822Sdim  inst.instruction |= inst.operands[0].reg << 5;
8080218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
8081218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
8082218822Sdim  inst.instruction |= inst.operands[3].reg;
8083218822Sdim}
808460484Sobrien
8085218822Sdim/* cfmvsc32<cond> DSPSC,MVDX[15:0].  */
8086218822Sdimstatic void
8087218822Sdimdo_mav_dspsc (void)
8088218822Sdim{
8089218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
809089857Sobrien}
809189857Sobrien
8092218822Sdim/* Maverick shift immediate instructions.
8093218822Sdim   cfsh32<cond> MVFX[15:0],MVFX[15:0],Shift[6:0].
8094218822Sdim   cfsh64<cond> MVDX[15:0],MVDX[15:0],Shift[6:0].  */
8095218822Sdim
809689857Sobrienstatic void
8097218822Sdimdo_mav_shift (void)
809889857Sobrien{
8099218822Sdim  int imm = inst.operands[2].imm;
810089857Sobrien
8101218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
8102218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
810377298Sobrien
8104218822Sdim  /* Bits 0-3 of the insn should have bits 0-3 of the immediate.
8105218822Sdim     Bits 5-7 of the insn should have bits 4-6 of the immediate.
8106218822Sdim     Bit 4 should be 0.	 */
8107218822Sdim  imm = (imm & 0xf) | ((imm & 0x70) << 1);
810860484Sobrien
8109218822Sdim  inst.instruction |= imm;
8110218822Sdim}
8111218822Sdim
8112218822Sdim/* XScale instructions.	 Also sorted arithmetic before move.  */
811360484Sobrien
8114218822Sdim/* Xscale multiply-accumulate (argument parse)
8115218822Sdim     MIAcc   acc0,Rm,Rs
8116218822Sdim     MIAPHcc acc0,Rm,Rs
8117218822Sdim     MIAxycc acc0,Rm,Rs.  */
811860484Sobrien
8119218822Sdimstatic void
8120218822Sdimdo_xsc_mia (void)
8121218822Sdim{
8122218822Sdim  inst.instruction |= inst.operands[1].reg;
8123218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
8124218822Sdim}
812560484Sobrien
8126218822Sdim/* Xscale move-accumulator-register (argument parse)
812760484Sobrien
8128218822Sdim     MARcc   acc0,RdLo,RdHi.  */
812960484Sobrien
8130218822Sdimstatic void
8131218822Sdimdo_xsc_mar (void)
8132218822Sdim{
8133218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
8134218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
8135218822Sdim}
813689857Sobrien
8137218822Sdim/* Xscale move-register-accumulator (argument parse)
813889857Sobrien
8139218822Sdim     MRAcc   RdLo,RdHi,acc0.  */
814089857Sobrien
8141218822Sdimstatic void
8142218822Sdimdo_xsc_mra (void)
8143218822Sdim{
8144218822Sdim  constraint (inst.operands[0].reg == inst.operands[1].reg, BAD_OVERLAP);
8145218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
8146218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
8147218822Sdim}
8148218822Sdim
8149218822Sdim/* Encoding functions relevant only to Thumb.  */
815089857Sobrien
8151218822Sdim/* inst.operands[i] is a shifted-register operand; encode
8152218822Sdim   it into inst.instruction in the format used by Thumb32.  */
815389857Sobrien
8154218822Sdimstatic void
8155218822Sdimencode_thumb32_shifted_operand (int i)
8156218822Sdim{
8157218822Sdim  unsigned int value = inst.reloc.exp.X_add_number;
8158218822Sdim  unsigned int shift = inst.operands[i].shift_kind;
8159218822Sdim
8160218822Sdim  constraint (inst.operands[i].immisreg,
8161218822Sdim	      _("shift by register not allowed in thumb mode"));
8162218822Sdim  inst.instruction |= inst.operands[i].reg;
8163218822Sdim  if (shift == SHIFT_RRX)
8164218822Sdim    inst.instruction |= SHIFT_ROR << 4;
816589857Sobrien  else
816689857Sobrien    {
8167218822Sdim      constraint (inst.reloc.exp.X_op != O_constant,
8168218822Sdim		  _("expression too complex"));
8169218822Sdim
8170218822Sdim      constraint (value > 32
8171218822Sdim		  || (value == 32 && (shift == SHIFT_LSL
8172218822Sdim				      || shift == SHIFT_ROR)),
8173218822Sdim		  _("shift expression is too large"));
8174218822Sdim
8175218822Sdim      if (value == 0)
8176218822Sdim	shift = SHIFT_LSL;
8177218822Sdim      else if (value == 32)
8178218822Sdim	value = 0;
8179218822Sdim
8180218822Sdim      inst.instruction |= shift << 4;
8181218822Sdim      inst.instruction |= (value & 0x1c) << 10;
8182218822Sdim      inst.instruction |= (value & 0x03) << 6;
818389857Sobrien    }
818489857Sobrien}
818589857Sobrien
8186218822Sdim
8187218822Sdim/* inst.operands[i] was set up by parse_address.  Encode it into a
8188218822Sdim   Thumb32 format load or store instruction.  Reject forms that cannot
8189218822Sdim   be used with such instructions.  If is_t is true, reject forms that
8190218822Sdim   cannot be used with a T instruction; if is_d is true, reject forms
8191218822Sdim   that cannot be used with a D instruction.  */
8192218822Sdim
8193218822Sdimstatic void
8194218822Sdimencode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
819589857Sobrien{
8196218822Sdim  bfd_boolean is_pc = (inst.operands[i].reg == REG_PC);
819789857Sobrien
8198218822Sdim  constraint (!inst.operands[i].isreg,
8199218822Sdim	      _("Instruction does not support =N addresses"));
8200218822Sdim
8201218822Sdim  inst.instruction |= inst.operands[i].reg << 16;
8202218822Sdim  if (inst.operands[i].immisreg)
820389857Sobrien    {
8204218822Sdim      constraint (is_pc, _("cannot use register index with PC-relative addressing"));
8205218822Sdim      constraint (is_t || is_d, _("cannot use register index with this instruction"));
8206218822Sdim      constraint (inst.operands[i].negative,
8207218822Sdim		  _("Thumb does not support negative register indexing"));
8208218822Sdim      constraint (inst.operands[i].postind,
8209218822Sdim		  _("Thumb does not support register post-indexing"));
8210218822Sdim      constraint (inst.operands[i].writeback,
8211218822Sdim		  _("Thumb does not support register indexing with writeback"));
8212218822Sdim      constraint (inst.operands[i].shifted && inst.operands[i].shift_kind != SHIFT_LSL,
8213218822Sdim		  _("Thumb supports only LSL in shifted register indexing"));
821489857Sobrien
8215218822Sdim      inst.instruction |= inst.operands[i].imm;
8216218822Sdim      if (inst.operands[i].shifted)
821789857Sobrien	{
8218218822Sdim	  constraint (inst.reloc.exp.X_op != O_constant,
8219218822Sdim		      _("expression too complex"));
8220218822Sdim	  constraint (inst.reloc.exp.X_add_number < 0
8221218822Sdim		      || inst.reloc.exp.X_add_number > 3,
8222218822Sdim		      _("shift out of range"));
8223218822Sdim	  inst.instruction |= inst.reloc.exp.X_add_number << 4;
8224218822Sdim	}
8225218822Sdim      inst.reloc.type = BFD_RELOC_UNUSED;
8226218822Sdim    }
8227218822Sdim  else if (inst.operands[i].preind)
8228218822Sdim    {
8229218822Sdim      constraint (is_pc && inst.operands[i].writeback,
8230218822Sdim		  _("cannot use writeback with PC-relative addressing"));
8231218822Sdim      constraint (is_t && inst.operands[i].writeback,
8232218822Sdim		  _("cannot use writeback with this instruction"));
823389857Sobrien
8234218822Sdim      if (is_d)
8235218822Sdim	{
8236218822Sdim	  inst.instruction |= 0x01000000;
8237218822Sdim	  if (inst.operands[i].writeback)
8238218822Sdim	    inst.instruction |= 0x00200000;
823989857Sobrien	}
824089857Sobrien      else
824189857Sobrien	{
8242218822Sdim	  inst.instruction |= 0x00000c00;
8243218822Sdim	  if (inst.operands[i].writeback)
8244218822Sdim	    inst.instruction |= 0x00000100;
824589857Sobrien	}
8246218822Sdim      inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_IMM;
8247218822Sdim    }
8248218822Sdim  else if (inst.operands[i].postind)
8249218822Sdim    {
8250218822Sdim      assert (inst.operands[i].writeback);
8251218822Sdim      constraint (is_pc, _("cannot use post-indexing with PC-relative addressing"));
8252218822Sdim      constraint (is_t, _("cannot use post-indexing with this instruction"));
825389857Sobrien
8254218822Sdim      if (is_d)
8255218822Sdim	inst.instruction |= 0x00200000;
8256218822Sdim      else
8257218822Sdim	inst.instruction |= 0x00000900;
8258218822Sdim      inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_IMM;
8259218822Sdim    }
8260218822Sdim  else /* unindexed - only for coprocessor */
8261218822Sdim    inst.error = _("instruction does not accept unindexed addressing");
8262218822Sdim}
826389857Sobrien
8264218822Sdim/* Table of Thumb instructions which exist in both 16- and 32-bit
8265218822Sdim   encodings (the latter only in post-V6T2 cores).  The index is the
8266218822Sdim   value used in the insns table below.  When there is more than one
8267218822Sdim   possible 16-bit encoding for the instruction, this table always
8268218822Sdim   holds variant (1).
8269218822Sdim   Also contains several pseudo-instructions used during relaxation.  */
8270218822Sdim#define T16_32_TAB				\
8271218822Sdim  X(adc,   4140, eb400000),			\
8272218822Sdim  X(adcs,  4140, eb500000),			\
8273218822Sdim  X(add,   1c00, eb000000),			\
8274218822Sdim  X(adds,  1c00, eb100000),			\
8275218822Sdim  X(addi,  0000, f1000000),			\
8276218822Sdim  X(addis, 0000, f1100000),			\
8277218822Sdim  X(add_pc,000f, f20f0000),			\
8278218822Sdim  X(add_sp,000d, f10d0000),			\
8279218822Sdim  X(adr,   000f, f20f0000),			\
8280218822Sdim  X(and,   4000, ea000000),			\
8281218822Sdim  X(ands,  4000, ea100000),			\
8282218822Sdim  X(asr,   1000, fa40f000),			\
8283218822Sdim  X(asrs,  1000, fa50f000),			\
8284218822Sdim  X(b,     e000, f000b000),			\
8285218822Sdim  X(bcond, d000, f0008000),			\
8286218822Sdim  X(bic,   4380, ea200000),			\
8287218822Sdim  X(bics,  4380, ea300000),			\
8288218822Sdim  X(cmn,   42c0, eb100f00),			\
8289218822Sdim  X(cmp,   2800, ebb00f00),			\
8290218822Sdim  X(cpsie, b660, f3af8400),			\
8291218822Sdim  X(cpsid, b670, f3af8600),			\
8292218822Sdim  X(cpy,   4600, ea4f0000),			\
8293218822Sdim  X(dec_sp,80dd, f1ad0d00),			\
8294218822Sdim  X(eor,   4040, ea800000),			\
8295218822Sdim  X(eors,  4040, ea900000),			\
8296218822Sdim  X(inc_sp,00dd, f10d0d00),			\
8297218822Sdim  X(ldmia, c800, e8900000),			\
8298218822Sdim  X(ldr,   6800, f8500000),			\
8299218822Sdim  X(ldrb,  7800, f8100000),			\
8300218822Sdim  X(ldrh,  8800, f8300000),			\
8301218822Sdim  X(ldrsb, 5600, f9100000),			\
8302218822Sdim  X(ldrsh, 5e00, f9300000),			\
8303218822Sdim  X(ldr_pc,4800, f85f0000),			\
8304218822Sdim  X(ldr_pc2,4800, f85f0000),			\
8305218822Sdim  X(ldr_sp,9800, f85d0000),			\
8306218822Sdim  X(lsl,   0000, fa00f000),			\
8307218822Sdim  X(lsls,  0000, fa10f000),			\
8308218822Sdim  X(lsr,   0800, fa20f000),			\
8309218822Sdim  X(lsrs,  0800, fa30f000),			\
8310218822Sdim  X(mov,   2000, ea4f0000),			\
8311218822Sdim  X(movs,  2000, ea5f0000),			\
8312218822Sdim  X(mul,   4340, fb00f000),                     \
8313218822Sdim  X(muls,  4340, ffffffff), /* no 32b muls */	\
8314218822Sdim  X(mvn,   43c0, ea6f0000),			\
8315218822Sdim  X(mvns,  43c0, ea7f0000),			\
8316218822Sdim  X(neg,   4240, f1c00000), /* rsb #0 */	\
8317218822Sdim  X(negs,  4240, f1d00000), /* rsbs #0 */	\
8318218822Sdim  X(orr,   4300, ea400000),			\
8319218822Sdim  X(orrs,  4300, ea500000),			\
8320218822Sdim  X(pop,   bc00, e8bd0000), /* ldmia sp!,... */	\
8321218822Sdim  X(push,  b400, e92d0000), /* stmdb sp!,... */	\
8322218822Sdim  X(rev,   ba00, fa90f080),			\
8323218822Sdim  X(rev16, ba40, fa90f090),			\
8324218822Sdim  X(revsh, bac0, fa90f0b0),			\
8325218822Sdim  X(ror,   41c0, fa60f000),			\
8326218822Sdim  X(rors,  41c0, fa70f000),			\
8327218822Sdim  X(sbc,   4180, eb600000),			\
8328218822Sdim  X(sbcs,  4180, eb700000),			\
8329218822Sdim  X(stmia, c000, e8800000),			\
8330218822Sdim  X(str,   6000, f8400000),			\
8331218822Sdim  X(strb,  7000, f8000000),			\
8332218822Sdim  X(strh,  8000, f8200000),			\
8333218822Sdim  X(str_sp,9000, f84d0000),			\
8334218822Sdim  X(sub,   1e00, eba00000),			\
8335218822Sdim  X(subs,  1e00, ebb00000),			\
8336218822Sdim  X(subi,  8000, f1a00000),			\
8337218822Sdim  X(subis, 8000, f1b00000),			\
8338218822Sdim  X(sxtb,  b240, fa4ff080),			\
8339218822Sdim  X(sxth,  b200, fa0ff080),			\
8340218822Sdim  X(tst,   4200, ea100f00),			\
8341218822Sdim  X(uxtb,  b2c0, fa5ff080),			\
8342218822Sdim  X(uxth,  b280, fa1ff080),			\
8343218822Sdim  X(nop,   bf00, f3af8000),			\
8344218822Sdim  X(yield, bf10, f3af8001),			\
8345218822Sdim  X(wfe,   bf20, f3af8002),			\
8346218822Sdim  X(wfi,   bf30, f3af8003),			\
8347218822Sdim  X(sev,   bf40, f3af9004), /* typo, 8004? */
834889857Sobrien
8349218822Sdim/* To catch errors in encoding functions, the codes are all offset by
8350218822Sdim   0xF800, putting them in one of the 32-bit prefix ranges, ergo undefined
8351218822Sdim   as 16-bit instructions.  */
8352218822Sdim#define X(a,b,c) T_MNEM_##a
8353218822Sdimenum t16_32_codes { T16_32_OFFSET = 0xF7FF, T16_32_TAB };
8354218822Sdim#undef X
835589857Sobrien
8356218822Sdim#define X(a,b,c) 0x##b
8357218822Sdimstatic const unsigned short thumb_op16[] = { T16_32_TAB };
8358218822Sdim#define THUMB_OP16(n) (thumb_op16[(n) - (T16_32_OFFSET + 1)])
8359218822Sdim#undef X
836089857Sobrien
8361218822Sdim#define X(a,b,c) 0x##c
8362218822Sdimstatic const unsigned int thumb_op32[] = { T16_32_TAB };
8363218822Sdim#define THUMB_OP32(n) (thumb_op32[(n) - (T16_32_OFFSET + 1)])
8364218822Sdim#define THUMB_SETS_FLAGS(n) (THUMB_OP32 (n) & 0x00100000)
8365218822Sdim#undef X
8366218822Sdim#undef T16_32_TAB
8367218822Sdim
8368218822Sdim/* Thumb instruction encoders, in alphabetical order.  */
8369218822Sdim
8370218822Sdim/* ADDW or SUBW.  */
837189857Sobrienstatic void
8372218822Sdimdo_t_add_sub_w (void)
837389857Sobrien{
8374218822Sdim  int Rd, Rn;
837589857Sobrien
8376218822Sdim  Rd = inst.operands[0].reg;
8377218822Sdim  Rn = inst.operands[1].reg;
837889857Sobrien
8379218822Sdim  constraint (Rd == 15, _("PC not allowed as destination"));
8380218822Sdim  inst.instruction |= (Rn << 16) | (Rd << 8);
8381218822Sdim  inst.reloc.type = BFD_RELOC_ARM_T32_IMM12;
8382218822Sdim}
838389857Sobrien
8384218822Sdim/* Parse an add or subtract instruction.  We get here with inst.instruction
8385218822Sdim   equalling any of THUMB_OPCODE_add, adds, sub, or subs.  */
838689857Sobrien
8387218822Sdimstatic void
8388218822Sdimdo_t_add_sub (void)
8389218822Sdim{
8390218822Sdim  int Rd, Rs, Rn;
839189857Sobrien
8392218822Sdim  Rd = inst.operands[0].reg;
8393218822Sdim  Rs = (inst.operands[1].present
8394218822Sdim	? inst.operands[1].reg    /* Rd, Rs, foo */
8395218822Sdim	: inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
839689857Sobrien
8397218822Sdim  if (unified_syntax)
8398218822Sdim    {
8399218822Sdim      bfd_boolean flags;
8400218822Sdim      bfd_boolean narrow;
8401218822Sdim      int opcode;
840289857Sobrien
8403218822Sdim      flags = (inst.instruction == T_MNEM_adds
8404218822Sdim	       || inst.instruction == T_MNEM_subs);
8405218822Sdim      if (flags)
8406218822Sdim	narrow = (current_it_mask == 0);
8407218822Sdim      else
8408218822Sdim	narrow = (current_it_mask != 0);
8409218822Sdim      if (!inst.operands[2].isreg)
841060484Sobrien	{
8411218822Sdim	  int add;
841277298Sobrien
8413218822Sdim	  add = (inst.instruction == T_MNEM_add
8414218822Sdim		 || inst.instruction == T_MNEM_adds);
8415218822Sdim	  opcode = 0;
8416218822Sdim	  if (inst.size_req != 4)
841760484Sobrien	    {
8418218822Sdim	      /* Attempt to use a narrow opcode, with relaxation if
8419218822Sdim	         appropriate.  */
8420218822Sdim	      if (Rd == REG_SP && Rs == REG_SP && !flags)
8421218822Sdim		opcode = add ? T_MNEM_inc_sp : T_MNEM_dec_sp;
8422218822Sdim	      else if (Rd <= 7 && Rs == REG_SP && add && !flags)
8423218822Sdim		opcode = T_MNEM_add_sp;
8424218822Sdim	      else if (Rd <= 7 && Rs == REG_PC && add && !flags)
8425218822Sdim		opcode = T_MNEM_add_pc;
8426218822Sdim	      else if (Rd <= 7 && Rs <= 7 && narrow)
8427218822Sdim		{
8428218822Sdim		  if (flags)
8429218822Sdim		    opcode = add ? T_MNEM_addis : T_MNEM_subis;
8430218822Sdim		  else
8431218822Sdim		    opcode = add ? T_MNEM_addi : T_MNEM_subi;
8432218822Sdim		}
8433218822Sdim	      if (opcode)
8434218822Sdim		{
8435218822Sdim		  inst.instruction = THUMB_OP16(opcode);
8436218822Sdim		  inst.instruction |= (Rd << 4) | Rs;
8437218822Sdim		  inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
8438218822Sdim		  if (inst.size_req != 2)
8439218822Sdim		    inst.relax = opcode;
8440218822Sdim		}
8441218822Sdim	      else
8442218822Sdim		constraint (inst.size_req == 2, BAD_HIREG);
844360484Sobrien	    }
8444218822Sdim	  if (inst.size_req == 4
8445218822Sdim	      || (inst.size_req != 2 && !opcode))
844660484Sobrien	    {
8447218822Sdim	      if (Rd == REG_PC)
844877298Sobrien		{
8449218822Sdim		  constraint (Rs != REG_LR || inst.instruction != T_MNEM_subs,
8450218822Sdim			     _("only SUBS PC, LR, #const allowed"));
8451218822Sdim		  constraint (inst.reloc.exp.X_op != O_constant,
8452218822Sdim			      _("expression too complex"));
8453218822Sdim		  constraint (inst.reloc.exp.X_add_number < 0
8454218822Sdim			      || inst.reloc.exp.X_add_number > 0xff,
8455218822Sdim			     _("immediate value out of range"));
8456218822Sdim		  inst.instruction = T2_SUBS_PC_LR
8457218822Sdim				     | inst.reloc.exp.X_add_number;
8458218822Sdim		  inst.reloc.type = BFD_RELOC_UNUSED;
8459218822Sdim		  return;
846077298Sobrien		}
8461218822Sdim	      else if (Rs == REG_PC)
8462218822Sdim		{
8463218822Sdim		  /* Always use addw/subw.  */
8464218822Sdim		  inst.instruction = add ? 0xf20f0000 : 0xf2af0000;
8465218822Sdim		  inst.reloc.type = BFD_RELOC_ARM_T32_IMM12;
8466218822Sdim		}
8467218822Sdim	      else
8468218822Sdim		{
8469218822Sdim		  inst.instruction = THUMB_OP32 (inst.instruction);
8470218822Sdim		  inst.instruction = (inst.instruction & 0xe1ffffff)
8471218822Sdim				     | 0x10000000;
8472218822Sdim		  if (flags)
8473218822Sdim		    inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
8474218822Sdim		  else
8475218822Sdim		    inst.reloc.type = BFD_RELOC_ARM_T32_ADD_IMM;
8476218822Sdim		}
8477218822Sdim	      inst.instruction |= Rd << 8;
8478218822Sdim	      inst.instruction |= Rs << 16;
847960484Sobrien	    }
848060484Sobrien	}
848160484Sobrien      else
848260484Sobrien	{
8483218822Sdim	  Rn = inst.operands[2].reg;
8484218822Sdim	  /* See if we can do this with a 16-bit instruction.  */
8485218822Sdim	  if (!inst.operands[2].shifted && inst.size_req != 4)
848660484Sobrien	    {
8487218822Sdim	      if (Rd > 7 || Rs > 7 || Rn > 7)
8488218822Sdim		narrow = FALSE;
848960484Sobrien
8490218822Sdim	      if (narrow)
8491218822Sdim		{
8492218822Sdim		  inst.instruction = ((inst.instruction == T_MNEM_adds
8493218822Sdim				       || inst.instruction == T_MNEM_add)
8494218822Sdim				      ? T_OPCODE_ADD_R3
8495218822Sdim				      : T_OPCODE_SUB_R3);
8496218822Sdim		  inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
8497218822Sdim		  return;
8498218822Sdim		}
849960484Sobrien
8500218822Sdim	      if (inst.instruction == T_MNEM_add)
8501218822Sdim		{
8502218822Sdim		  if (Rd == Rs)
8503218822Sdim		    {
8504218822Sdim		      inst.instruction = T_OPCODE_ADD_HI;
8505218822Sdim		      inst.instruction |= (Rd & 8) << 4;
8506218822Sdim		      inst.instruction |= (Rd & 7);
8507218822Sdim		      inst.instruction |= Rn << 3;
8508218822Sdim		      return;
8509218822Sdim		    }
8510218822Sdim		  /* ... because addition is commutative! */
8511218822Sdim		  else if (Rd == Rn)
8512218822Sdim		    {
8513218822Sdim		      inst.instruction = T_OPCODE_ADD_HI;
8514218822Sdim		      inst.instruction |= (Rd & 8) << 4;
8515218822Sdim		      inst.instruction |= (Rd & 7);
8516218822Sdim		      inst.instruction |= Rs << 3;
8517218822Sdim		      return;
8518218822Sdim		    }
8519218822Sdim		}
852060484Sobrien	    }
8521218822Sdim	  /* If we get here, it can't be done in 16 bits.  */
8522218822Sdim	  constraint (inst.operands[2].shifted && inst.operands[2].immisreg,
8523218822Sdim		      _("shift must be constant"));
8524218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
8525218822Sdim	  inst.instruction |= Rd << 8;
8526218822Sdim	  inst.instruction |= Rs << 16;
8527218822Sdim	  encode_thumb32_shifted_operand (2);
852860484Sobrien	}
852960484Sobrien    }
8530218822Sdim  else
853160484Sobrien    {
8532218822Sdim      constraint (inst.instruction == T_MNEM_adds
8533218822Sdim		  || inst.instruction == T_MNEM_subs,
8534218822Sdim		  BAD_THUMB32);
8535218822Sdim
8536218822Sdim      if (!inst.operands[2].isreg) /* Rd, Rs, #imm */
853789857Sobrien	{
8538218822Sdim	  constraint ((Rd > 7 && (Rd != REG_SP || Rs != REG_SP))
8539218822Sdim		      || (Rs > 7 && Rs != REG_SP && Rs != REG_PC),
8540218822Sdim		      BAD_HIREG);
8541218822Sdim
8542218822Sdim	  inst.instruction = (inst.instruction == T_MNEM_add
8543218822Sdim			      ? 0x0000 : 0x8000);
8544218822Sdim	  inst.instruction |= (Rd << 4) | Rs;
8545218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
854689857Sobrien	  return;
854789857Sobrien	}
854889857Sobrien
8549218822Sdim      Rn = inst.operands[2].reg;
8550218822Sdim      constraint (inst.operands[2].shifted, _("unshifted register required"));
855160484Sobrien
8552218822Sdim      /* We now have Rd, Rs, and Rn set to registers.  */
8553218822Sdim      if (Rd > 7 || Rs > 7 || Rn > 7)
855460484Sobrien	{
8555218822Sdim	  /* Can't do this for SUB.	 */
8556218822Sdim	  constraint (inst.instruction == T_MNEM_sub, BAD_HIREG);
8557218822Sdim	  inst.instruction = T_OPCODE_ADD_HI;
8558218822Sdim	  inst.instruction |= (Rd & 8) << 4;
8559218822Sdim	  inst.instruction |= (Rd & 7);
8560218822Sdim	  if (Rs == Rd)
8561218822Sdim	    inst.instruction |= Rn << 3;
8562218822Sdim	  else if (Rn == Rd)
8563218822Sdim	    inst.instruction |= Rs << 3;
8564218822Sdim	  else
8565218822Sdim	    constraint (1, _("dest must overlap one source register"));
856660484Sobrien	}
8567218822Sdim      else
856860484Sobrien	{
8569218822Sdim	  inst.instruction = (inst.instruction == T_MNEM_add
8570218822Sdim			      ? T_OPCODE_ADD_R3 : T_OPCODE_SUB_R3);
8571218822Sdim	  inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
857260484Sobrien	}
8573218822Sdim    }
8574218822Sdim}
857580016Sobrien
8576218822Sdimstatic void
8577218822Sdimdo_t_adr (void)
8578218822Sdim{
8579218822Sdim  if (unified_syntax && inst.size_req == 0 && inst.operands[0].reg <= 7)
8580218822Sdim    {
8581218822Sdim      /* Defer to section relaxation.  */
8582218822Sdim      inst.relax = inst.instruction;
8583218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
8584218822Sdim      inst.instruction |= inst.operands[0].reg << 4;
8585218822Sdim    }
8586218822Sdim  else if (unified_syntax && inst.size_req != 2)
8587218822Sdim    {
8588218822Sdim      /* Generate a 32-bit opcode.  */
8589218822Sdim      inst.instruction = THUMB_OP32 (inst.instruction);
8590218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
8591218822Sdim      inst.reloc.type = BFD_RELOC_ARM_T32_ADD_PC12;
859280016Sobrien      inst.reloc.pc_rel = 1;
859360484Sobrien    }
859460484Sobrien  else
859560484Sobrien    {
8596218822Sdim      /* Generate a 16-bit opcode.  */
8597218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
8598218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
8599218822Sdim      inst.reloc.exp.X_add_number -= 4; /* PC relative adjust.  */
8600218822Sdim      inst.reloc.pc_rel = 1;
860160484Sobrien
8602218822Sdim      inst.instruction |= inst.operands[0].reg << 4;
860360484Sobrien    }
860460484Sobrien}
860560484Sobrien
8606218822Sdim/* Arithmetic instructions for which there is just one 16-bit
8607218822Sdim   instruction encoding, and it allows only two low registers.
8608218822Sdim   For maximal compatibility with ARM syntax, we allow three register
8609218822Sdim   operands even when Thumb-32 instructions are not available, as long
8610218822Sdim   as the first two are identical.  For instance, both "sbc r0,r1" and
8611218822Sdim   "sbc r0,r0,r1" are allowed.  */
8612218822Sdimstatic void
8613218822Sdimdo_t_arit3 (void)
861460484Sobrien{
8615218822Sdim  int Rd, Rs, Rn;
861660484Sobrien
8617218822Sdim  Rd = inst.operands[0].reg;
8618218822Sdim  Rs = (inst.operands[1].present
8619218822Sdim	? inst.operands[1].reg    /* Rd, Rs, foo */
8620218822Sdim	: inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
8621218822Sdim  Rn = inst.operands[2].reg;
8622218822Sdim
8623218822Sdim  if (unified_syntax)
862460484Sobrien    {
8625218822Sdim      if (!inst.operands[2].isreg)
862660484Sobrien	{
8627218822Sdim	  /* For an immediate, we always generate a 32-bit opcode;
8628218822Sdim	     section relaxation will shrink it later if possible.  */
8629218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
8630218822Sdim	  inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
8631218822Sdim	  inst.instruction |= Rd << 8;
8632218822Sdim	  inst.instruction |= Rs << 16;
8633218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
8634218822Sdim	}
8635218822Sdim      else
8636218822Sdim	{
8637218822Sdim	  bfd_boolean narrow;
863877298Sobrien
8639218822Sdim	  /* See if we can do this with a 16-bit instruction.  */
8640218822Sdim	  if (THUMB_SETS_FLAGS (inst.instruction))
8641218822Sdim	    narrow = current_it_mask == 0;
8642218822Sdim	  else
8643218822Sdim	    narrow = current_it_mask != 0;
864477298Sobrien
8645218822Sdim	  if (Rd > 7 || Rn > 7 || Rs > 7)
8646218822Sdim	    narrow = FALSE;
8647218822Sdim	  if (inst.operands[2].shifted)
8648218822Sdim	    narrow = FALSE;
8649218822Sdim	  if (inst.size_req == 4)
8650218822Sdim	    narrow = FALSE;
865160484Sobrien
8652218822Sdim	  if (narrow
8653218822Sdim	      && Rd == Rs)
8654218822Sdim	    {
8655218822Sdim	      inst.instruction = THUMB_OP16 (inst.instruction);
8656218822Sdim	      inst.instruction |= Rd;
8657218822Sdim	      inst.instruction |= Rn << 3;
8658218822Sdim	      return;
8659218822Sdim	    }
866077298Sobrien
8661218822Sdim	  /* If we get here, it can't be done in 16 bits.  */
8662218822Sdim	  constraint (inst.operands[2].shifted
8663218822Sdim		      && inst.operands[2].immisreg,
8664218822Sdim		      _("shift must be constant"));
8665218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
8666218822Sdim	  inst.instruction |= Rd << 8;
8667218822Sdim	  inst.instruction |= Rs << 16;
8668218822Sdim	  encode_thumb32_shifted_operand (2);
8669218822Sdim	}
8670218822Sdim    }
8671218822Sdim  else
8672218822Sdim    {
8673218822Sdim      /* On its face this is a lie - the instruction does set the
8674218822Sdim	 flags.  However, the only supported mnemonic in this mode
8675218822Sdim	 says it doesn't.  */
8676218822Sdim      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
867777298Sobrien
8678218822Sdim      constraint (!inst.operands[2].isreg || inst.operands[2].shifted,
8679218822Sdim		  _("unshifted register required"));
8680218822Sdim      constraint (Rd > 7 || Rs > 7 || Rn > 7, BAD_HIREG);
8681218822Sdim      constraint (Rd != Rs,
8682218822Sdim		  _("dest and source1 must be the same register"));
868360484Sobrien
8684218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
8685218822Sdim      inst.instruction |= Rd;
8686218822Sdim      inst.instruction |= Rn << 3;
8687218822Sdim    }
8688218822Sdim}
868960484Sobrien
8690218822Sdim/* Similarly, but for instructions where the arithmetic operation is
8691218822Sdim   commutative, so we can allow either of them to be different from
8692218822Sdim   the destination operand in a 16-bit instruction.  For instance, all
8693218822Sdim   three of "adc r0,r1", "adc r0,r0,r1", and "adc r0,r1,r0" are
8694218822Sdim   accepted.  */
8695218822Sdimstatic void
8696218822Sdimdo_t_arit3c (void)
8697218822Sdim{
8698218822Sdim  int Rd, Rs, Rn;
869960484Sobrien
8700218822Sdim  Rd = inst.operands[0].reg;
8701218822Sdim  Rs = (inst.operands[1].present
8702218822Sdim	? inst.operands[1].reg    /* Rd, Rs, foo */
8703218822Sdim	: inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
8704218822Sdim  Rn = inst.operands[2].reg;
870560484Sobrien
8706218822Sdim  if (unified_syntax)
8707218822Sdim    {
8708218822Sdim      if (!inst.operands[2].isreg)
8709218822Sdim	{
8710218822Sdim	  /* For an immediate, we always generate a 32-bit opcode;
8711218822Sdim	     section relaxation will shrink it later if possible.  */
8712218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
8713218822Sdim	  inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
8714218822Sdim	  inst.instruction |= Rd << 8;
8715218822Sdim	  inst.instruction |= Rs << 16;
8716218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
871760484Sobrien	}
871860484Sobrien      else
871960484Sobrien	{
8720218822Sdim	  bfd_boolean narrow;
872160484Sobrien
8722218822Sdim	  /* See if we can do this with a 16-bit instruction.  */
8723218822Sdim	  if (THUMB_SETS_FLAGS (inst.instruction))
8724218822Sdim	    narrow = current_it_mask == 0;
8725218822Sdim	  else
8726218822Sdim	    narrow = current_it_mask != 0;
872760484Sobrien
8728218822Sdim	  if (Rd > 7 || Rn > 7 || Rs > 7)
8729218822Sdim	    narrow = FALSE;
8730218822Sdim	  if (inst.operands[2].shifted)
8731218822Sdim	    narrow = FALSE;
8732218822Sdim	  if (inst.size_req == 4)
8733218822Sdim	    narrow = FALSE;
8734218822Sdim
8735218822Sdim	  if (narrow)
873660484Sobrien	    {
8737218822Sdim	      if (Rd == Rs)
873860484Sobrien		{
8739218822Sdim		  inst.instruction = THUMB_OP16 (inst.instruction);
8740218822Sdim		  inst.instruction |= Rd;
8741218822Sdim		  inst.instruction |= Rn << 3;
8742218822Sdim		  return;
874360484Sobrien		}
8744218822Sdim	      if (Rd == Rn)
874560484Sobrien		{
8746218822Sdim		  inst.instruction = THUMB_OP16 (inst.instruction);
8747218822Sdim		  inst.instruction |= Rd;
8748218822Sdim		  inst.instruction |= Rs << 3;
8749218822Sdim		  return;
875060484Sobrien		}
875160484Sobrien	    }
875260484Sobrien
8753218822Sdim	  /* If we get here, it can't be done in 16 bits.  */
8754218822Sdim	  constraint (inst.operands[2].shifted
8755218822Sdim		      && inst.operands[2].immisreg,
8756218822Sdim		      _("shift must be constant"));
8757218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
8758218822Sdim	  inst.instruction |= Rd << 8;
8759218822Sdim	  inst.instruction |= Rs << 16;
8760218822Sdim	  encode_thumb32_shifted_operand (2);
876160484Sobrien	}
8762218822Sdim    }
8763218822Sdim  else
8764218822Sdim    {
8765218822Sdim      /* On its face this is a lie - the instruction does set the
8766218822Sdim	 flags.  However, the only supported mnemonic in this mode
8767218822Sdim	 says it doesn't.  */
8768218822Sdim      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
876960484Sobrien
8770218822Sdim      constraint (!inst.operands[2].isreg || inst.operands[2].shifted,
8771218822Sdim		  _("unshifted register required"));
8772218822Sdim      constraint (Rd > 7 || Rs > 7 || Rn > 7, BAD_HIREG);
877360484Sobrien
8774218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
8775218822Sdim      inst.instruction |= Rd;
8776218822Sdim
8777218822Sdim      if (Rd == Rs)
8778218822Sdim	inst.instruction |= Rn << 3;
8779218822Sdim      else if (Rd == Rn)
8780218822Sdim	inst.instruction |= Rs << 3;
8781218822Sdim      else
8782218822Sdim	constraint (1, _("dest must overlap one source register"));
878377298Sobrien    }
8784218822Sdim}
878560484Sobrien
8786218822Sdimstatic void
8787218822Sdimdo_t_barrier (void)
8788218822Sdim{
8789218822Sdim  if (inst.operands[0].present)
8790218822Sdim    {
8791218822Sdim      constraint ((inst.instruction & 0xf0) != 0x40
8792218822Sdim		  && inst.operands[0].imm != 0xf,
8793218822Sdim		  "bad barrier type");
8794218822Sdim      inst.instruction |= inst.operands[0].imm;
8795218822Sdim    }
8796218822Sdim  else
8797218822Sdim    inst.instruction |= 0xf;
879860484Sobrien}
879960484Sobrien
880060484Sobrienstatic void
8801218822Sdimdo_t_bfc (void)
880260484Sobrien{
8803218822Sdim  unsigned int msb = inst.operands[1].imm + inst.operands[2].imm;
8804218822Sdim  constraint (msb > 32, _("bit-field extends past end of register"));
8805218822Sdim  /* The instruction encoding stores the LSB and MSB,
8806218822Sdim     not the LSB and width.  */
8807218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
8808218822Sdim  inst.instruction |= (inst.operands[1].imm & 0x1c) << 10;
8809218822Sdim  inst.instruction |= (inst.operands[1].imm & 0x03) << 6;
8810218822Sdim  inst.instruction |= msb - 1;
8811218822Sdim}
881260484Sobrien
8813218822Sdimstatic void
8814218822Sdimdo_t_bfi (void)
8815218822Sdim{
8816218822Sdim  unsigned int msb;
881760484Sobrien
8818218822Sdim  /* #0 in second position is alternative syntax for bfc, which is
8819218822Sdim     the same instruction but with REG_PC in the Rm field.  */
8820218822Sdim  if (!inst.operands[1].isreg)
8821218822Sdim    inst.operands[1].reg = REG_PC;
882260484Sobrien
8823218822Sdim  msb = inst.operands[2].imm + inst.operands[3].imm;
8824218822Sdim  constraint (msb > 32, _("bit-field extends past end of register"));
8825218822Sdim  /* The instruction encoding stores the LSB and MSB,
8826218822Sdim     not the LSB and width.  */
8827218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
8828218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
8829218822Sdim  inst.instruction |= (inst.operands[2].imm & 0x1c) << 10;
8830218822Sdim  inst.instruction |= (inst.operands[2].imm & 0x03) << 6;
8831218822Sdim  inst.instruction |= msb - 1;
8832218822Sdim}
883360484Sobrien
8834218822Sdimstatic void
8835218822Sdimdo_t_bfx (void)
8836218822Sdim{
8837218822Sdim  constraint (inst.operands[2].imm + inst.operands[3].imm > 32,
8838218822Sdim	      _("bit-field extends past end of register"));
8839218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
8840218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
8841218822Sdim  inst.instruction |= (inst.operands[2].imm & 0x1c) << 10;
8842218822Sdim  inst.instruction |= (inst.operands[2].imm & 0x03) << 6;
8843218822Sdim  inst.instruction |= inst.operands[3].imm - 1;
8844218822Sdim}
884560484Sobrien
8846218822Sdim/* ARM V5 Thumb BLX (argument parse)
8847218822Sdim	BLX <target_addr>	which is BLX(1)
8848218822Sdim	BLX <Rm>		which is BLX(2)
8849218822Sdim   Unfortunately, there are two different opcodes for this mnemonic.
8850218822Sdim   So, the insns[].value is not used, and the code here zaps values
8851218822Sdim	into inst.instruction.
885260484Sobrien
8853218822Sdim   ??? How to take advantage of the additional two bits of displacement
8854218822Sdim   available in Thumb32 mode?  Need new relocation?  */
8855218822Sdim
8856218822Sdimstatic void
8857218822Sdimdo_t_blx (void)
8858218822Sdim{
8859218822Sdim  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
8860218822Sdim  if (inst.operands[0].isreg)
8861218822Sdim    /* We have a register, so this is BLX(2).  */
8862218822Sdim    inst.instruction |= inst.operands[0].reg << 3;
8863218822Sdim  else
886460484Sobrien    {
8865218822Sdim      /* No register.  This must be BLX(1).  */
8866218822Sdim      inst.instruction = 0xf000e800;
8867218822Sdim#ifdef OBJ_ELF
8868218822Sdim      if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4)
8869218822Sdim	inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH23;
8870218822Sdim      else
8871218822Sdim#endif
8872218822Sdim	inst.reloc.type = BFD_RELOC_THUMB_PCREL_BLX;
8873218822Sdim      inst.reloc.pc_rel = 1;
887460484Sobrien    }
8875218822Sdim}
887660484Sobrien
8877218822Sdimstatic void
8878218822Sdimdo_t_branch (void)
8879218822Sdim{
8880218822Sdim  int opcode;
8881218822Sdim  int cond;
8882218822Sdim
8883218822Sdim  if (current_it_mask)
888460484Sobrien    {
8885218822Sdim      /* Conditional branches inside IT blocks are encoded as unconditional
8886218822Sdim         branches.  */
8887218822Sdim      cond = COND_ALWAYS;
8888218822Sdim      /* A branch must be the last instruction in an IT block.  */
8889218822Sdim      constraint (current_it_mask != 0x10, BAD_BRANCH);
889060484Sobrien    }
8891218822Sdim  else
8892218822Sdim    cond = inst.cond;
889360484Sobrien
8894218822Sdim  if (cond != COND_ALWAYS)
8895218822Sdim    opcode = T_MNEM_bcond;
8896218822Sdim  else
8897218822Sdim    opcode = inst.instruction;
8898218822Sdim
8899218822Sdim  if (unified_syntax && inst.size_req == 4)
8900130561Sobrien    {
8901218822Sdim      inst.instruction = THUMB_OP32(opcode);
8902218822Sdim      if (cond == COND_ALWAYS)
8903218822Sdim	inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH25;
8904218822Sdim      else
8905130561Sobrien	{
8906218822Sdim	  assert (cond != 0xF);
8907218822Sdim	  inst.instruction |= cond << 22;
8908218822Sdim	  inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH20;
8909130561Sobrien	}
8910218822Sdim    }
8911218822Sdim  else
8912218822Sdim    {
8913218822Sdim      inst.instruction = THUMB_OP16(opcode);
8914218822Sdim      if (cond == COND_ALWAYS)
8915218822Sdim	inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH12;
8916218822Sdim      else
8917130561Sobrien	{
8918218822Sdim	  inst.instruction |= cond << 8;
8919218822Sdim	  inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH9;
8920130561Sobrien	}
8921218822Sdim      /* Allow section relaxation.  */
8922218822Sdim      if (unified_syntax && inst.size_req != 2)
8923218822Sdim	inst.relax = opcode;
8924130561Sobrien    }
8925130561Sobrien
8926218822Sdim  inst.reloc.pc_rel = 1;
892760484Sobrien}
892860484Sobrien
892960484Sobrienstatic void
8930218822Sdimdo_t_bkpt (void)
893160484Sobrien{
8932218822Sdim  constraint (inst.cond != COND_ALWAYS,
8933218822Sdim	      _("instruction is always unconditional"));
8934218822Sdim  if (inst.operands[0].present)
8935218822Sdim    {
8936218822Sdim      constraint (inst.operands[0].imm > 255,
8937218822Sdim		  _("immediate value out of range"));
8938218822Sdim      inst.instruction |= inst.operands[0].imm;
8939218822Sdim    }
8940218822Sdim}
894177298Sobrien
8942218822Sdimstatic void
8943218822Sdimdo_t_branch23 (void)
8944218822Sdim{
8945218822Sdim  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
8946218822Sdim  inst.reloc.type   = BFD_RELOC_THUMB_PCREL_BRANCH23;
8947218822Sdim  inst.reloc.pc_rel = 1;
894860484Sobrien
8949218822Sdim  /* If the destination of the branch is a defined symbol which does not have
8950218822Sdim     the THUMB_FUNC attribute, then we must be calling a function which has
8951218822Sdim     the (interfacearm) attribute.  We look for the Thumb entry point to that
8952218822Sdim     function and change the branch to refer to that function instead.	*/
8953218822Sdim  if (	 inst.reloc.exp.X_op == O_symbol
8954218822Sdim      && inst.reloc.exp.X_add_symbol != NULL
8955218822Sdim      && S_IS_DEFINED (inst.reloc.exp.X_add_symbol)
8956218822Sdim      && ! THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol))
8957218822Sdim    inst.reloc.exp.X_add_symbol =
8958218822Sdim      find_real_start (inst.reloc.exp.X_add_symbol);
8959218822Sdim}
896060484Sobrien
8961218822Sdimstatic void
8962218822Sdimdo_t_bx (void)
8963218822Sdim{
8964218822Sdim  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
8965218822Sdim  inst.instruction |= inst.operands[0].reg << 3;
8966218822Sdim  /* ??? FIXME: Should add a hacky reloc here if reg is REG_PC.	 The reloc
8967218822Sdim     should cause the alignment to be checked once it is known.	 This is
8968218822Sdim     because BX PC only works if the instruction is word aligned.  */
896960484Sobrien}
897060484Sobrien
897160484Sobrienstatic void
8972218822Sdimdo_t_bxj (void)
897360484Sobrien{
8974218822Sdim  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
8975218822Sdim  if (inst.operands[0].reg == REG_PC)
8976218822Sdim    as_tsktsk (_("use of r15 in bxj is not really useful"));
897777298Sobrien
8978218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
8979218822Sdim}
898060484Sobrien
8981218822Sdimstatic void
8982218822Sdimdo_t_clz (void)
8983218822Sdim{
8984218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
8985218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
8986218822Sdim  inst.instruction |= inst.operands[1].reg;
8987218822Sdim}
898860484Sobrien
8989218822Sdimstatic void
8990218822Sdimdo_t_cps (void)
8991218822Sdim{
8992218822Sdim  constraint (current_it_mask, BAD_NOT_IT);
8993218822Sdim  inst.instruction |= inst.operands[0].imm;
8994218822Sdim}
899560484Sobrien
8996218822Sdimstatic void
8997218822Sdimdo_t_cpsi (void)
8998218822Sdim{
8999218822Sdim  constraint (current_it_mask, BAD_NOT_IT);
9000218822Sdim  if (unified_syntax
9001218822Sdim      && (inst.operands[1].present || inst.size_req == 4)
9002218822Sdim      && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6_notm))
900360484Sobrien    {
9004218822Sdim      unsigned int imod = (inst.instruction & 0x0030) >> 4;
9005218822Sdim      inst.instruction = 0xf3af8000;
9006218822Sdim      inst.instruction |= imod << 9;
9007218822Sdim      inst.instruction |= inst.operands[0].imm << 5;
9008218822Sdim      if (inst.operands[1].present)
9009218822Sdim	inst.instruction |= 0x100 | inst.operands[1].imm;
901060484Sobrien    }
9011218822Sdim  else
901260484Sobrien    {
9013218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1)
9014218822Sdim		  && (inst.operands[0].imm & 4),
9015218822Sdim		  _("selected processor does not support 'A' form "
9016218822Sdim		    "of this instruction"));
9017218822Sdim      constraint (inst.operands[1].present || inst.size_req == 4,
9018218822Sdim		  _("Thumb does not support the 2-argument "
9019218822Sdim		    "form of this instruction"));
9020218822Sdim      inst.instruction |= inst.operands[0].imm;
902160484Sobrien    }
9022218822Sdim}
902360484Sobrien
9024218822Sdim/* THUMB CPY instruction (argument parse).  */
902560484Sobrien
9026218822Sdimstatic void
9027218822Sdimdo_t_cpy (void)
9028218822Sdim{
9029218822Sdim  if (inst.size_req == 4)
903060484Sobrien    {
9031218822Sdim      inst.instruction = THUMB_OP32 (T_MNEM_mov);
9032218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
9033218822Sdim      inst.instruction |= inst.operands[1].reg;
903460484Sobrien    }
9035218822Sdim  else
903660484Sobrien    {
9037218822Sdim      inst.instruction |= (inst.operands[0].reg & 0x8) << 4;
9038218822Sdim      inst.instruction |= (inst.operands[0].reg & 0x7);
9039218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
904060484Sobrien    }
9041218822Sdim}
904260484Sobrien
9043218822Sdimstatic void
9044218822Sdimdo_t_cbz (void)
9045218822Sdim{
9046218822Sdim  constraint (current_it_mask, BAD_NOT_IT);
9047218822Sdim  constraint (inst.operands[0].reg > 7, BAD_HIREG);
9048218822Sdim  inst.instruction |= inst.operands[0].reg;
9049218822Sdim  inst.reloc.pc_rel = 1;
9050218822Sdim  inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH7;
905160484Sobrien}
905260484Sobrien
905360484Sobrienstatic void
9054218822Sdimdo_t_dbg (void)
905560484Sobrien{
9056218822Sdim  inst.instruction |= inst.operands[0].imm;
9057218822Sdim}
905877298Sobrien
9059218822Sdimstatic void
9060218822Sdimdo_t_div (void)
9061218822Sdim{
9062218822Sdim  if (!inst.operands[1].present)
9063218822Sdim    inst.operands[1].reg = inst.operands[0].reg;
9064218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
9065218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
9066218822Sdim  inst.instruction |= inst.operands[2].reg;
9067218822Sdim}
906877298Sobrien
9069218822Sdimstatic void
9070218822Sdimdo_t_hint (void)
9071218822Sdim{
9072218822Sdim  if (unified_syntax && inst.size_req == 4)
9073218822Sdim    inst.instruction = THUMB_OP32 (inst.instruction);
9074218822Sdim  else
9075218822Sdim    inst.instruction = THUMB_OP16 (inst.instruction);
907660484Sobrien}
907760484Sobrien
907860484Sobrienstatic void
9079218822Sdimdo_t_it (void)
908060484Sobrien{
9081218822Sdim  unsigned int cond = inst.operands[0].imm;
908260484Sobrien
9083218822Sdim  constraint (current_it_mask, BAD_NOT_IT);
9084218822Sdim  current_it_mask = (inst.instruction & 0xf) | 0x10;
9085218822Sdim  current_cc = cond;
908660484Sobrien
9087218822Sdim  /* If the condition is a negative condition, invert the mask.  */
9088218822Sdim  if ((cond & 0x1) == 0x0)
908960484Sobrien    {
9090218822Sdim      unsigned int mask = inst.instruction & 0x000f;
9091218822Sdim
9092218822Sdim      if ((mask & 0x7) == 0)
9093218822Sdim	/* no conversion needed */;
9094218822Sdim      else if ((mask & 0x3) == 0)
9095218822Sdim	mask ^= 0x8;
9096218822Sdim      else if ((mask & 0x1) == 0)
9097218822Sdim	mask ^= 0xC;
9098218822Sdim      else
9099218822Sdim	mask ^= 0xE;
9100218822Sdim
9101218822Sdim      inst.instruction &= 0xfff0;
9102218822Sdim      inst.instruction |= mask;
910360484Sobrien    }
910460484Sobrien
9105218822Sdim  inst.instruction |= cond << 4;
910660484Sobrien}
910760484Sobrien
9108218822Sdim/* Helper function used for both push/pop and ldm/stm.  */
910960484Sobrienstatic void
9110218822Sdimencode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback)
911160484Sobrien{
9112218822Sdim  bfd_boolean load;
911360484Sobrien
9114218822Sdim  load = (inst.instruction & (1 << 20)) != 0;
911560484Sobrien
9116218822Sdim  if (mask & (1 << 13))
9117218822Sdim    inst.error =  _("SP not allowed in register list");
9118218822Sdim  if (load)
911960484Sobrien    {
9120218822Sdim      if (mask & (1 << 14)
9121218822Sdim	  && mask & (1 << 15))
9122218822Sdim	inst.error = _("LR and PC should not both be in register list");
912360484Sobrien
9124218822Sdim      if ((mask & (1 << base)) != 0
9125218822Sdim	  && writeback)
9126218822Sdim	as_warn (_("base register should not be in register list "
9127218822Sdim		   "when written back"));
912860484Sobrien    }
9129218822Sdim  else
913060484Sobrien    {
9131218822Sdim      if (mask & (1 << 15))
9132218822Sdim	inst.error = _("PC not allowed in register list");
913360484Sobrien
9134218822Sdim      if (mask & (1 << base))
9135218822Sdim	as_warn (_("value stored for r%d is UNPREDICTABLE"), base);
913660484Sobrien    }
913760484Sobrien
9138218822Sdim  if ((mask & (mask - 1)) == 0)
913960484Sobrien    {
9140218822Sdim      /* Single register transfers implemented as str/ldr.  */
9141218822Sdim      if (writeback)
914260484Sobrien	{
9143218822Sdim	  if (inst.instruction & (1 << 23))
9144218822Sdim	    inst.instruction = 0x00000b04; /* ia! -> [base], #4 */
9145218822Sdim	  else
9146218822Sdim	    inst.instruction = 0x00000d04; /* db! -> [base, #-4]! */
914760484Sobrien	}
9148218822Sdim      else
9149218822Sdim	{
9150218822Sdim	  if (inst.instruction & (1 << 23))
9151218822Sdim	    inst.instruction = 0x00800000; /* ia -> [base] */
9152218822Sdim	  else
9153218822Sdim	    inst.instruction = 0x00000c04; /* db -> [base, #-4] */
9154218822Sdim	}
915560484Sobrien
9156218822Sdim      inst.instruction |= 0xf8400000;
9157218822Sdim      if (load)
9158218822Sdim	inst.instruction |= 0x00100000;
915960484Sobrien
9160218822Sdim      mask = ffs(mask) - 1;
9161218822Sdim      mask <<= 12;
916260484Sobrien    }
9163218822Sdim  else if (writeback)
9164218822Sdim    inst.instruction |= WRITE_BACK;
916560484Sobrien
9166218822Sdim  inst.instruction |= mask;
9167218822Sdim  inst.instruction |= base << 16;
916860484Sobrien}
916960484Sobrien
917060484Sobrienstatic void
9171218822Sdimdo_t_ldmstm (void)
917260484Sobrien{
9173218822Sdim  /* This really doesn't seem worth it.  */
9174218822Sdim  constraint (inst.reloc.type != BFD_RELOC_UNUSED,
9175218822Sdim	      _("expression too complex"));
9176218822Sdim  constraint (inst.operands[1].writeback,
9177218822Sdim	      _("Thumb load/store multiple does not support {reglist}^"));
917860484Sobrien
9179218822Sdim  if (unified_syntax)
918060484Sobrien    {
9181218822Sdim      bfd_boolean narrow;
9182218822Sdim      unsigned mask;
918360484Sobrien
9184218822Sdim      narrow = FALSE;
9185218822Sdim      /* See if we can use a 16-bit instruction.  */
9186218822Sdim      if (inst.instruction < 0xffff /* not ldmdb/stmdb */
9187218822Sdim	  && inst.size_req != 4
9188218822Sdim	  && !(inst.operands[1].imm & ~0xff))
9189218822Sdim	{
9190218822Sdim	  mask = 1 << inst.operands[0].reg;
919160484Sobrien
9192218822Sdim	  if (inst.operands[0].reg <= 7
9193218822Sdim	      && (inst.instruction == T_MNEM_stmia
9194218822Sdim		  ? inst.operands[0].writeback
9195218822Sdim		  : (inst.operands[0].writeback
9196218822Sdim		     == !(inst.operands[1].imm & mask))))
9197218822Sdim	    {
9198218822Sdim	      if (inst.instruction == T_MNEM_stmia
9199218822Sdim		  && (inst.operands[1].imm & mask)
9200218822Sdim		  && (inst.operands[1].imm & (mask - 1)))
9201218822Sdim		as_warn (_("value stored for r%d is UNPREDICTABLE"),
9202218822Sdim			 inst.operands[0].reg);
920360484Sobrien
9204218822Sdim	      inst.instruction = THUMB_OP16 (inst.instruction);
9205218822Sdim	      inst.instruction |= inst.operands[0].reg << 8;
9206218822Sdim	      inst.instruction |= inst.operands[1].imm;
9207218822Sdim	      narrow = TRUE;
9208218822Sdim	    }
9209218822Sdim	  else if (inst.operands[0] .reg == REG_SP
9210218822Sdim		   && inst.operands[0].writeback)
9211218822Sdim	    {
9212218822Sdim	      inst.instruction = THUMB_OP16 (inst.instruction == T_MNEM_stmia
9213218822Sdim					     ? T_MNEM_push : T_MNEM_pop);
9214218822Sdim	      inst.instruction |= inst.operands[1].imm;
9215218822Sdim	      narrow = TRUE;
9216218822Sdim	    }
9217218822Sdim	}
921860484Sobrien
9219218822Sdim      if (!narrow)
9220218822Sdim	{
9221218822Sdim	  if (inst.instruction < 0xffff)
9222218822Sdim	    inst.instruction = THUMB_OP32 (inst.instruction);
9223218822Sdim
9224218822Sdim	  encode_thumb2_ldmstm(inst.operands[0].reg, inst.operands[1].imm,
9225218822Sdim			       inst.operands[0].writeback);
9226218822Sdim	}
922760484Sobrien    }
9228218822Sdim  else
922960484Sobrien    {
9230218822Sdim      constraint (inst.operands[0].reg > 7
9231218822Sdim		  || (inst.operands[1].imm & ~0xff), BAD_HIREG);
9232218822Sdim      constraint (inst.instruction != T_MNEM_ldmia
9233218822Sdim		  && inst.instruction != T_MNEM_stmia,
9234218822Sdim		  _("Thumb-2 instruction only valid in unified syntax"));
9235218822Sdim      if (inst.instruction == T_MNEM_stmia)
923660484Sobrien	{
9237218822Sdim	  if (!inst.operands[0].writeback)
9238218822Sdim	    as_warn (_("this instruction will write back the base register"));
9239218822Sdim	  if ((inst.operands[1].imm & (1 << inst.operands[0].reg))
9240218822Sdim	      && (inst.operands[1].imm & ((1 << inst.operands[0].reg) - 1)))
9241218822Sdim	    as_warn (_("value stored for r%d is UNPREDICTABLE"),
9242218822Sdim		     inst.operands[0].reg);
924360484Sobrien	}
9244218822Sdim      else
9245218822Sdim	{
9246218822Sdim	  if (!inst.operands[0].writeback
9247218822Sdim	      && !(inst.operands[1].imm & (1 << inst.operands[0].reg)))
9248218822Sdim	    as_warn (_("this instruction will write back the base register"));
9249218822Sdim	  else if (inst.operands[0].writeback
9250218822Sdim		   && (inst.operands[1].imm & (1 << inst.operands[0].reg)))
9251218822Sdim	    as_warn (_("this instruction will not write back the base register"));
9252218822Sdim	}
9253218822Sdim
9254218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
9255218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
9256218822Sdim      inst.instruction |= inst.operands[1].imm;
925760484Sobrien    }
925860484Sobrien}
925960484Sobrien
926060484Sobrienstatic void
9261218822Sdimdo_t_ldrex (void)
926260484Sobrien{
9263218822Sdim  constraint (!inst.operands[1].isreg || !inst.operands[1].preind
9264218822Sdim	      || inst.operands[1].postind || inst.operands[1].writeback
9265218822Sdim	      || inst.operands[1].immisreg || inst.operands[1].shifted
9266218822Sdim	      || inst.operands[1].negative,
9267218822Sdim	      BAD_ADDR_MODE);
926860484Sobrien
9269218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9270218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
9271218822Sdim  inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_U8;
9272218822Sdim}
927360484Sobrien
9274218822Sdimstatic void
9275218822Sdimdo_t_ldrexd (void)
9276218822Sdim{
9277218822Sdim  if (!inst.operands[1].present)
927860484Sobrien    {
9279218822Sdim      constraint (inst.operands[0].reg == REG_LR,
9280218822Sdim		  _("r14 not allowed as first register "
9281218822Sdim		    "when second register is omitted"));
9282218822Sdim      inst.operands[1].reg = inst.operands[0].reg + 1;
928360484Sobrien    }
9284218822Sdim  constraint (inst.operands[0].reg == inst.operands[1].reg,
9285218822Sdim	      BAD_OVERLAP);
928660484Sobrien
9287218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9288218822Sdim  inst.instruction |= inst.operands[1].reg << 8;
9289218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
929060484Sobrien}
929160484Sobrien
929260484Sobrienstatic void
9293218822Sdimdo_t_ldst (void)
929460484Sobrien{
9295218822Sdim  unsigned long opcode;
9296218822Sdim  int Rn;
929760484Sobrien
9298218822Sdim  opcode = inst.instruction;
9299218822Sdim  if (unified_syntax)
930060484Sobrien    {
9301218822Sdim      if (!inst.operands[1].isreg)
9302218822Sdim	{
9303218822Sdim	  if (opcode <= 0xffff)
9304218822Sdim	    inst.instruction = THUMB_OP32 (opcode);
9305218822Sdim	  if (move_or_literal_pool (0, /*thumb_p=*/TRUE, /*mode_3=*/FALSE))
9306218822Sdim	    return;
9307218822Sdim	}
9308218822Sdim      if (inst.operands[1].isreg
9309218822Sdim	  && !inst.operands[1].writeback
9310218822Sdim	  && !inst.operands[1].shifted && !inst.operands[1].postind
9311218822Sdim	  && !inst.operands[1].negative && inst.operands[0].reg <= 7
9312218822Sdim	  && opcode <= 0xffff
9313218822Sdim	  && inst.size_req != 4)
9314218822Sdim	{
9315218822Sdim	  /* Insn may have a 16-bit form.  */
9316218822Sdim	  Rn = inst.operands[1].reg;
9317218822Sdim	  if (inst.operands[1].immisreg)
9318218822Sdim	    {
9319218822Sdim	      inst.instruction = THUMB_OP16 (opcode);
9320218822Sdim	      /* [Rn, Ri] */
9321218822Sdim	      if (Rn <= 7 && inst.operands[1].imm <= 7)
9322218822Sdim		goto op16;
9323218822Sdim	    }
9324218822Sdim	  else if ((Rn <= 7 && opcode != T_MNEM_ldrsh
9325218822Sdim		    && opcode != T_MNEM_ldrsb)
9326218822Sdim		   || ((Rn == REG_PC || Rn == REG_SP) && opcode == T_MNEM_ldr)
9327218822Sdim		   || (Rn == REG_SP && opcode == T_MNEM_str))
9328218822Sdim	    {
9329218822Sdim	      /* [Rn, #const] */
9330218822Sdim	      if (Rn > 7)
9331218822Sdim		{
9332218822Sdim		  if (Rn == REG_PC)
9333218822Sdim		    {
9334218822Sdim		      if (inst.reloc.pc_rel)
9335218822Sdim			opcode = T_MNEM_ldr_pc2;
9336218822Sdim		      else
9337218822Sdim			opcode = T_MNEM_ldr_pc;
9338218822Sdim		    }
9339218822Sdim		  else
9340218822Sdim		    {
9341218822Sdim		      if (opcode == T_MNEM_ldr)
9342218822Sdim			opcode = T_MNEM_ldr_sp;
9343218822Sdim		      else
9344218822Sdim			opcode = T_MNEM_str_sp;
9345218822Sdim		    }
9346218822Sdim		  inst.instruction = inst.operands[0].reg << 8;
9347218822Sdim		}
9348218822Sdim	      else
9349218822Sdim		{
9350218822Sdim		  inst.instruction = inst.operands[0].reg;
9351218822Sdim		  inst.instruction |= inst.operands[1].reg << 3;
9352218822Sdim		}
9353218822Sdim	      inst.instruction |= THUMB_OP16 (opcode);
9354218822Sdim	      if (inst.size_req == 2)
9355218822Sdim		inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
9356218822Sdim	      else
9357218822Sdim		inst.relax = opcode;
9358218822Sdim	      return;
9359218822Sdim	    }
9360218822Sdim	}
9361218822Sdim      /* Definitely a 32-bit variant.  */
9362218822Sdim      inst.instruction = THUMB_OP32 (opcode);
9363218822Sdim      inst.instruction |= inst.operands[0].reg << 12;
9364218822Sdim      encode_thumb32_addr_mode (1, /*is_t=*/FALSE, /*is_d=*/FALSE);
936560484Sobrien      return;
936660484Sobrien    }
936760484Sobrien
9368218822Sdim  constraint (inst.operands[0].reg > 7, BAD_HIREG);
9369218822Sdim
9370218822Sdim  if (inst.instruction == T_MNEM_ldrsh || inst.instruction == T_MNEM_ldrsb)
937160484Sobrien    {
9372218822Sdim      /* Only [Rn,Rm] is acceptable.  */
9373218822Sdim      constraint (inst.operands[1].reg > 7 || inst.operands[1].imm > 7, BAD_HIREG);
9374218822Sdim      constraint (!inst.operands[1].isreg || !inst.operands[1].immisreg
9375218822Sdim		  || inst.operands[1].postind || inst.operands[1].shifted
9376218822Sdim		  || inst.operands[1].negative,
9377218822Sdim		  _("Thumb does not support this addressing mode"));
9378218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
9379218822Sdim      goto op16;
9380218822Sdim    }
9381218822Sdim
9382218822Sdim  inst.instruction = THUMB_OP16 (inst.instruction);
9383218822Sdim  if (!inst.operands[1].isreg)
9384218822Sdim    if (move_or_literal_pool (0, /*thumb_p=*/TRUE, /*mode_3=*/FALSE))
938560484Sobrien      return;
938660484Sobrien
9387218822Sdim  constraint (!inst.operands[1].preind
9388218822Sdim	      || inst.operands[1].shifted
9389218822Sdim	      || inst.operands[1].writeback,
9390218822Sdim	      _("Thumb does not support this addressing mode"));
9391218822Sdim  if (inst.operands[1].reg == REG_PC || inst.operands[1].reg == REG_SP)
9392218822Sdim    {
9393218822Sdim      constraint (inst.instruction & 0x0600,
9394218822Sdim		  _("byte or halfword not valid for base register"));
9395218822Sdim      constraint (inst.operands[1].reg == REG_PC
9396218822Sdim		  && !(inst.instruction & THUMB_LOAD_BIT),
9397218822Sdim		  _("r15 based store not allowed"));
9398218822Sdim      constraint (inst.operands[1].immisreg,
9399218822Sdim		  _("invalid base register for register offset"));
940060484Sobrien
9401218822Sdim      if (inst.operands[1].reg == REG_PC)
9402218822Sdim	inst.instruction = T_OPCODE_LDR_PC;
9403218822Sdim      else if (inst.instruction & THUMB_LOAD_BIT)
9404218822Sdim	inst.instruction = T_OPCODE_LDR_SP;
9405218822Sdim      else
9406218822Sdim	inst.instruction = T_OPCODE_STR_SP;
940760484Sobrien
9408218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
9409218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
941060484Sobrien      return;
941160484Sobrien    }
941260484Sobrien
9413218822Sdim  constraint (inst.operands[1].reg > 7, BAD_HIREG);
9414218822Sdim  if (!inst.operands[1].immisreg)
941560484Sobrien    {
9416218822Sdim      /* Immediate offset.  */
9417218822Sdim      inst.instruction |= inst.operands[0].reg;
9418218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
9419218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
942060484Sobrien      return;
942160484Sobrien    }
942260484Sobrien
9423218822Sdim  /* Register offset.  */
9424218822Sdim  constraint (inst.operands[1].imm > 7, BAD_HIREG);
9425218822Sdim  constraint (inst.operands[1].negative,
9426218822Sdim	      _("Thumb does not support this addressing mode"));
9427218822Sdim
9428218822Sdim op16:
9429218822Sdim  switch (inst.instruction)
943060484Sobrien    {
9431218822Sdim    case T_OPCODE_STR_IW: inst.instruction = T_OPCODE_STR_RW; break;
9432218822Sdim    case T_OPCODE_STR_IH: inst.instruction = T_OPCODE_STR_RH; break;
9433218822Sdim    case T_OPCODE_STR_IB: inst.instruction = T_OPCODE_STR_RB; break;
9434218822Sdim    case T_OPCODE_LDR_IW: inst.instruction = T_OPCODE_LDR_RW; break;
9435218822Sdim    case T_OPCODE_LDR_IH: inst.instruction = T_OPCODE_LDR_RH; break;
9436218822Sdim    case T_OPCODE_LDR_IB: inst.instruction = T_OPCODE_LDR_RB; break;
9437218822Sdim    case 0x5600 /* ldrsb */:
9438218822Sdim    case 0x5e00 /* ldrsh */: break;
9439218822Sdim    default: abort ();
944060484Sobrien    }
944160484Sobrien
9442218822Sdim  inst.instruction |= inst.operands[0].reg;
9443218822Sdim  inst.instruction |= inst.operands[1].reg << 3;
9444218822Sdim  inst.instruction |= inst.operands[1].imm << 6;
9445218822Sdim}
944660484Sobrien
9447218822Sdimstatic void
9448218822Sdimdo_t_ldstd (void)
9449218822Sdim{
9450218822Sdim  if (!inst.operands[1].present)
945160484Sobrien    {
9452218822Sdim      inst.operands[1].reg = inst.operands[0].reg + 1;
9453218822Sdim      constraint (inst.operands[0].reg == REG_LR,
9454218822Sdim		  _("r14 not allowed here"));
945560484Sobrien    }
9456218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9457218822Sdim  inst.instruction |= inst.operands[1].reg << 8;
9458218822Sdim  encode_thumb32_addr_mode (2, /*is_t=*/FALSE, /*is_d=*/TRUE);
9459218822Sdim
9460218822Sdim}
946160484Sobrien
9462218822Sdimstatic void
9463218822Sdimdo_t_ldstt (void)
9464218822Sdim{
9465218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9466218822Sdim  encode_thumb32_addr_mode (1, /*is_t=*/TRUE, /*is_d=*/FALSE);
9467218822Sdim}
946860484Sobrien
9469218822Sdimstatic void
9470218822Sdimdo_t_mla (void)
9471218822Sdim{
9472218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
9473218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
9474218822Sdim  inst.instruction |= inst.operands[2].reg;
9475218822Sdim  inst.instruction |= inst.operands[3].reg << 12;
9476218822Sdim}
947760484Sobrien
9478218822Sdimstatic void
9479218822Sdimdo_t_mlal (void)
9480218822Sdim{
9481218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9482218822Sdim  inst.instruction |= inst.operands[1].reg << 8;
9483218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
9484218822Sdim  inst.instruction |= inst.operands[3].reg;
9485218822Sdim}
948660484Sobrien
9487218822Sdimstatic void
9488218822Sdimdo_t_mov_cmp (void)
9489218822Sdim{
9490218822Sdim  if (unified_syntax)
9491218822Sdim    {
9492218822Sdim      int r0off = (inst.instruction == T_MNEM_mov
9493218822Sdim		   || inst.instruction == T_MNEM_movs) ? 8 : 16;
9494218822Sdim      unsigned long opcode;
9495218822Sdim      bfd_boolean narrow;
9496218822Sdim      bfd_boolean low_regs;
949760484Sobrien
9498218822Sdim      low_regs = (inst.operands[0].reg <= 7 && inst.operands[1].reg <= 7);
9499218822Sdim      opcode = inst.instruction;
9500218822Sdim      if (current_it_mask)
9501218822Sdim	narrow = opcode != T_MNEM_movs;
9502218822Sdim      else
9503218822Sdim	narrow = opcode != T_MNEM_movs || low_regs;
9504218822Sdim      if (inst.size_req == 4
9505218822Sdim	  || inst.operands[1].shifted)
9506218822Sdim	narrow = FALSE;
950760484Sobrien
9508218822Sdim      /* MOVS PC, LR is encoded as SUBS PC, LR, #0.  */
9509218822Sdim      if (opcode == T_MNEM_movs && inst.operands[1].isreg
9510218822Sdim	  && !inst.operands[1].shifted
9511218822Sdim	  && inst.operands[0].reg == REG_PC
9512218822Sdim	  && inst.operands[1].reg == REG_LR)
951360484Sobrien	{
9514218822Sdim	  inst.instruction = T2_SUBS_PC_LR;
951560484Sobrien	  return;
951660484Sobrien	}
951760484Sobrien
9518218822Sdim      if (!inst.operands[1].isreg)
951960484Sobrien	{
9520218822Sdim	  /* Immediate operand.  */
9521218822Sdim	  if (current_it_mask == 0 && opcode == T_MNEM_mov)
9522218822Sdim	    narrow = 0;
9523218822Sdim	  if (low_regs && narrow)
952460484Sobrien	    {
9525218822Sdim	      inst.instruction = THUMB_OP16 (opcode);
9526218822Sdim	      inst.instruction |= inst.operands[0].reg << 8;
9527218822Sdim	      if (inst.size_req == 2)
9528218822Sdim		inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
9529218822Sdim	      else
9530218822Sdim		inst.relax = opcode;
953160484Sobrien	    }
9532218822Sdim	  else
9533218822Sdim	    {
9534218822Sdim	      inst.instruction = THUMB_OP32 (inst.instruction);
9535218822Sdim	      inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
9536218822Sdim	      inst.instruction |= inst.operands[0].reg << r0off;
9537218822Sdim	      inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
9538218822Sdim	    }
953960484Sobrien	}
9540218822Sdim      else if (inst.operands[1].shifted && inst.operands[1].immisreg
9541218822Sdim	       && (inst.instruction == T_MNEM_mov
9542218822Sdim		   || inst.instruction == T_MNEM_movs))
9543218822Sdim	{
9544218822Sdim	  /* Register shifts are encoded as separate shift instructions.  */
9545218822Sdim	  bfd_boolean flags = (inst.instruction == T_MNEM_movs);
954660484Sobrien
9547218822Sdim	  if (current_it_mask)
9548218822Sdim	    narrow = !flags;
9549218822Sdim	  else
9550218822Sdim	    narrow = flags;
9551218822Sdim
9552218822Sdim	  if (inst.size_req == 4)
9553218822Sdim	    narrow = FALSE;
9554218822Sdim
9555218822Sdim	  if (!low_regs || inst.operands[1].imm > 7)
9556218822Sdim	    narrow = FALSE;
9557218822Sdim
9558218822Sdim	  if (inst.operands[0].reg != inst.operands[1].reg)
9559218822Sdim	    narrow = FALSE;
9560218822Sdim
9561218822Sdim	  switch (inst.operands[1].shift_kind)
9562218822Sdim	    {
9563218822Sdim	    case SHIFT_LSL:
9564218822Sdim	      opcode = narrow ? T_OPCODE_LSL_R : THUMB_OP32 (T_MNEM_lsl);
9565218822Sdim	      break;
9566218822Sdim	    case SHIFT_ASR:
9567218822Sdim	      opcode = narrow ? T_OPCODE_ASR_R : THUMB_OP32 (T_MNEM_asr);
9568218822Sdim	      break;
9569218822Sdim	    case SHIFT_LSR:
9570218822Sdim	      opcode = narrow ? T_OPCODE_LSR_R : THUMB_OP32 (T_MNEM_lsr);
9571218822Sdim	      break;
9572218822Sdim	    case SHIFT_ROR:
9573218822Sdim	      opcode = narrow ? T_OPCODE_ROR_R : THUMB_OP32 (T_MNEM_ror);
9574218822Sdim	      break;
9575218822Sdim	    default:
9576218822Sdim	      abort();
9577218822Sdim	    }
9578218822Sdim
9579218822Sdim	  inst.instruction = opcode;
9580218822Sdim	  if (narrow)
9581218822Sdim	    {
9582218822Sdim	      inst.instruction |= inst.operands[0].reg;
9583218822Sdim	      inst.instruction |= inst.operands[1].imm << 3;
9584218822Sdim	    }
9585218822Sdim	  else
9586218822Sdim	    {
9587218822Sdim	      if (flags)
9588218822Sdim		inst.instruction |= CONDS_BIT;
9589218822Sdim
9590218822Sdim	      inst.instruction |= inst.operands[0].reg << 8;
9591218822Sdim	      inst.instruction |= inst.operands[1].reg << 16;
9592218822Sdim	      inst.instruction |= inst.operands[1].imm;
9593218822Sdim	    }
959460484Sobrien	}
9595218822Sdim      else if (!narrow)
959660484Sobrien	{
9597218822Sdim	  /* Some mov with immediate shift have narrow variants.
9598218822Sdim	     Register shifts are handled above.  */
9599218822Sdim	  if (low_regs && inst.operands[1].shifted
9600218822Sdim	      && (inst.instruction == T_MNEM_mov
9601218822Sdim		  || inst.instruction == T_MNEM_movs))
960260484Sobrien	    {
9603218822Sdim	      if (current_it_mask)
9604218822Sdim		narrow = (inst.instruction == T_MNEM_mov);
9605218822Sdim	      else
9606218822Sdim		narrow = (inst.instruction == T_MNEM_movs);
960760484Sobrien	    }
9608218822Sdim
9609218822Sdim	  if (narrow)
9610218822Sdim	    {
9611218822Sdim	      switch (inst.operands[1].shift_kind)
9612218822Sdim		{
9613218822Sdim		case SHIFT_LSL: inst.instruction = T_OPCODE_LSL_I; break;
9614218822Sdim		case SHIFT_LSR: inst.instruction = T_OPCODE_LSR_I; break;
9615218822Sdim		case SHIFT_ASR: inst.instruction = T_OPCODE_ASR_I; break;
9616218822Sdim		default: narrow = FALSE; break;
9617218822Sdim		}
9618218822Sdim	    }
9619218822Sdim
9620218822Sdim	  if (narrow)
9621218822Sdim	    {
9622218822Sdim	      inst.instruction |= inst.operands[0].reg;
9623218822Sdim	      inst.instruction |= inst.operands[1].reg << 3;
9624218822Sdim	      inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
9625218822Sdim	    }
962660484Sobrien	  else
962760484Sobrien	    {
9628218822Sdim	      inst.instruction = THUMB_OP32 (inst.instruction);
9629218822Sdim	      inst.instruction |= inst.operands[0].reg << r0off;
9630218822Sdim	      encode_thumb32_shifted_operand (1);
963160484Sobrien	    }
963260484Sobrien	}
9633218822Sdim      else
9634218822Sdim	switch (inst.instruction)
9635218822Sdim	  {
9636218822Sdim	  case T_MNEM_mov:
9637218822Sdim	    inst.instruction = T_OPCODE_MOV_HR;
9638218822Sdim	    inst.instruction |= (inst.operands[0].reg & 0x8) << 4;
9639218822Sdim	    inst.instruction |= (inst.operands[0].reg & 0x7);
9640218822Sdim	    inst.instruction |= inst.operands[1].reg << 3;
9641218822Sdim	    break;
964260484Sobrien
9643218822Sdim	  case T_MNEM_movs:
9644218822Sdim	    /* We know we have low registers at this point.
9645218822Sdim	       Generate ADD Rd, Rs, #0.  */
9646218822Sdim	    inst.instruction = T_OPCODE_ADD_I3;
9647218822Sdim	    inst.instruction |= inst.operands[0].reg;
9648218822Sdim	    inst.instruction |= inst.operands[1].reg << 3;
9649218822Sdim	    break;
9650218822Sdim
9651218822Sdim	  case T_MNEM_cmp:
9652218822Sdim	    if (low_regs)
9653218822Sdim	      {
9654218822Sdim		inst.instruction = T_OPCODE_CMP_LR;
9655218822Sdim		inst.instruction |= inst.operands[0].reg;
9656218822Sdim		inst.instruction |= inst.operands[1].reg << 3;
9657218822Sdim	      }
9658218822Sdim	    else
9659218822Sdim	      {
9660218822Sdim		inst.instruction = T_OPCODE_CMP_HR;
9661218822Sdim		inst.instruction |= (inst.operands[0].reg & 0x8) << 4;
9662218822Sdim		inst.instruction |= (inst.operands[0].reg & 0x7);
9663218822Sdim		inst.instruction |= inst.operands[1].reg << 3;
9664218822Sdim	      }
9665218822Sdim	    break;
9666218822Sdim	  }
9667218822Sdim      return;
966860484Sobrien    }
9669218822Sdim
9670218822Sdim  inst.instruction = THUMB_OP16 (inst.instruction);
9671218822Sdim  if (inst.operands[1].isreg)
967260484Sobrien    {
9673218822Sdim      if (inst.operands[0].reg < 8 && inst.operands[1].reg < 8)
9674218822Sdim	{
9675218822Sdim	  /* A move of two lowregs is encoded as ADD Rd, Rs, #0
9676218822Sdim	     since a MOV instruction produces unpredictable results.  */
9677218822Sdim	  if (inst.instruction == T_OPCODE_MOV_I8)
9678218822Sdim	    inst.instruction = T_OPCODE_ADD_I3;
9679218822Sdim	  else
9680218822Sdim	    inst.instruction = T_OPCODE_CMP_LR;
9681218822Sdim
9682218822Sdim	  inst.instruction |= inst.operands[0].reg;
9683218822Sdim	  inst.instruction |= inst.operands[1].reg << 3;
9684218822Sdim	}
9685218822Sdim      else
9686218822Sdim	{
9687218822Sdim	  if (inst.instruction == T_OPCODE_MOV_I8)
9688218822Sdim	    inst.instruction = T_OPCODE_MOV_HR;
9689218822Sdim	  else
9690218822Sdim	    inst.instruction = T_OPCODE_CMP_HR;
9691218822Sdim	  do_t_cpy ();
9692218822Sdim	}
969360484Sobrien    }
9694218822Sdim  else
9695218822Sdim    {
9696218822Sdim      constraint (inst.operands[0].reg > 7,
9697218822Sdim		  _("only lo regs allowed with immediate"));
9698218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
9699218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
9700218822Sdim    }
970160484Sobrien}
970260484Sobrien
970360484Sobrienstatic void
9704218822Sdimdo_t_mov16 (void)
970560484Sobrien{
9706218822Sdim  bfd_vma imm;
9707218822Sdim  bfd_boolean top;
970860484Sobrien
9709218822Sdim  top = (inst.instruction & 0x00800000) != 0;
9710218822Sdim  if (inst.reloc.type == BFD_RELOC_ARM_MOVW)
971160484Sobrien    {
9712218822Sdim      constraint (top, _(":lower16: not allowed this instruction"));
9713218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVW;
971460484Sobrien    }
9715218822Sdim  else if (inst.reloc.type == BFD_RELOC_ARM_MOVT)
971660484Sobrien    {
9717218822Sdim      constraint (!top, _(":upper16: not allowed this instruction"));
9718218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVT;
971960484Sobrien    }
972060484Sobrien
9721218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
9722218822Sdim  if (inst.reloc.type == BFD_RELOC_UNUSED)
972360484Sobrien    {
9724218822Sdim      imm = inst.reloc.exp.X_add_number;
9725218822Sdim      inst.instruction |= (imm & 0xf000) << 4;
9726218822Sdim      inst.instruction |= (imm & 0x0800) << 15;
9727218822Sdim      inst.instruction |= (imm & 0x0700) << 4;
9728218822Sdim      inst.instruction |= (imm & 0x00ff);
972960484Sobrien    }
973060484Sobrien}
973160484Sobrien
973260484Sobrienstatic void
9733218822Sdimdo_t_mvn_tst (void)
973460484Sobrien{
9735218822Sdim  if (unified_syntax)
9736218822Sdim    {
9737218822Sdim      int r0off = (inst.instruction == T_MNEM_mvn
9738218822Sdim		   || inst.instruction == T_MNEM_mvns) ? 8 : 16;
9739218822Sdim      bfd_boolean narrow;
974060484Sobrien
9741218822Sdim      if (inst.size_req == 4
9742218822Sdim	  || inst.instruction > 0xffff
9743218822Sdim	  || inst.operands[1].shifted
9744218822Sdim	  || inst.operands[0].reg > 7 || inst.operands[1].reg > 7)
9745218822Sdim	narrow = FALSE;
9746218822Sdim      else if (inst.instruction == T_MNEM_cmn)
9747218822Sdim	narrow = TRUE;
9748218822Sdim      else if (THUMB_SETS_FLAGS (inst.instruction))
9749218822Sdim	narrow = (current_it_mask == 0);
9750218822Sdim      else
9751218822Sdim	narrow = (current_it_mask != 0);
9752218822Sdim
9753218822Sdim      if (!inst.operands[1].isreg)
9754218822Sdim	{
9755218822Sdim	  /* For an immediate, we always generate a 32-bit opcode;
9756218822Sdim	     section relaxation will shrink it later if possible.  */
9757218822Sdim	  if (inst.instruction < 0xffff)
9758218822Sdim	    inst.instruction = THUMB_OP32 (inst.instruction);
9759218822Sdim	  inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
9760218822Sdim	  inst.instruction |= inst.operands[0].reg << r0off;
9761218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
9762218822Sdim	}
9763218822Sdim      else
9764218822Sdim	{
9765218822Sdim	  /* See if we can do this with a 16-bit instruction.  */
9766218822Sdim	  if (narrow)
9767218822Sdim	    {
9768218822Sdim	      inst.instruction = THUMB_OP16 (inst.instruction);
9769218822Sdim	      inst.instruction |= inst.operands[0].reg;
9770218822Sdim	      inst.instruction |= inst.operands[1].reg << 3;
9771218822Sdim	    }
9772218822Sdim	  else
9773218822Sdim	    {
9774218822Sdim	      constraint (inst.operands[1].shifted
9775218822Sdim			  && inst.operands[1].immisreg,
9776218822Sdim			  _("shift must be constant"));
9777218822Sdim	      if (inst.instruction < 0xffff)
9778218822Sdim		inst.instruction = THUMB_OP32 (inst.instruction);
9779218822Sdim	      inst.instruction |= inst.operands[0].reg << r0off;
9780218822Sdim	      encode_thumb32_shifted_operand (1);
9781218822Sdim	    }
9782218822Sdim	}
9783218822Sdim    }
9784218822Sdim  else
978560484Sobrien    {
9786218822Sdim      constraint (inst.instruction > 0xffff
9787218822Sdim		  || inst.instruction == T_MNEM_mvns, BAD_THUMB32);
9788218822Sdim      constraint (!inst.operands[1].isreg || inst.operands[1].shifted,
9789218822Sdim		  _("unshifted register required"));
9790218822Sdim      constraint (inst.operands[0].reg > 7 || inst.operands[1].reg > 7,
9791218822Sdim		  BAD_HIREG);
979260484Sobrien
9793218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
9794218822Sdim      inst.instruction |= inst.operands[0].reg;
9795218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
979660484Sobrien    }
979789857Sobrien}
979889857Sobrien
979989857Sobrienstatic void
9800218822Sdimdo_t_mrs (void)
980189857Sobrien{
9802218822Sdim  int flags;
980389857Sobrien
9804218822Sdim  if (do_vfp_nsyn_mrs () == SUCCESS)
9805218822Sdim    return;
9806218822Sdim
9807218822Sdim  flags = inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f|SPSR_BIT);
9808218822Sdim  if (flags == 0)
980989857Sobrien    {
9810218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7m),
9811218822Sdim		  _("selected processor does not support "
9812218822Sdim		    "requested special purpose register"));
981389857Sobrien    }
9814218822Sdim  else
981560484Sobrien    {
9816218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1),
9817218822Sdim		  _("selected processor does not support "
9818218822Sdim		    "requested special purpose register %x"));
9819218822Sdim      /* mrs only accepts CPSR/SPSR/CPSR_all/SPSR_all.  */
9820218822Sdim      constraint ((flags & ~SPSR_BIT) != (PSR_c|PSR_f),
9821218822Sdim		  _("'CPSR' or 'SPSR' expected"));
982260484Sobrien    }
9823218822Sdim
9824218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
9825218822Sdim  inst.instruction |= (flags & SPSR_BIT) >> 2;
9826218822Sdim  inst.instruction |= inst.operands[1].imm & 0xff;
982760484Sobrien}
982860484Sobrien
982960484Sobrienstatic void
9830218822Sdimdo_t_msr (void)
983160484Sobrien{
9832218822Sdim  int flags;
983360484Sobrien
9834218822Sdim  if (do_vfp_nsyn_msr () == SUCCESS)
9835218822Sdim    return;
9836218822Sdim
9837218822Sdim  constraint (!inst.operands[1].isreg,
9838218822Sdim	      _("Thumb encoding does not support an immediate here"));
9839218822Sdim  flags = inst.operands[0].imm;
9840218822Sdim  if (flags & ~0xff)
984160484Sobrien    {
9842218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1),
9843218822Sdim		  _("selected processor does not support "
9844218822Sdim		    "requested special purpose register"));
984560484Sobrien    }
9846218822Sdim  else
984760484Sobrien    {
9848218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7m),
9849218822Sdim		  _("selected processor does not support "
9850218822Sdim		    "requested special purpose register"));
9851218822Sdim      flags |= PSR_f;
985260484Sobrien    }
9853218822Sdim  inst.instruction |= (flags & SPSR_BIT) >> 2;
9854218822Sdim  inst.instruction |= (flags & ~SPSR_BIT) >> 8;
9855218822Sdim  inst.instruction |= (flags & 0xff);
9856218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
985760484Sobrien}
985860484Sobrien
985960484Sobrienstatic void
9860218822Sdimdo_t_mul (void)
986160484Sobrien{
9862218822Sdim  if (!inst.operands[2].present)
9863218822Sdim    inst.operands[2].reg = inst.operands[0].reg;
986460484Sobrien
9865218822Sdim  /* There is no 32-bit MULS and no 16-bit MUL. */
9866218822Sdim  if (unified_syntax && inst.instruction == T_MNEM_mul)
986760484Sobrien    {
9868218822Sdim      inst.instruction = THUMB_OP32 (inst.instruction);
9869218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
9870218822Sdim      inst.instruction |= inst.operands[1].reg << 16;
9871218822Sdim      inst.instruction |= inst.operands[2].reg << 0;
987260484Sobrien    }
9873218822Sdim  else
9874218822Sdim    {
9875218822Sdim      constraint (!unified_syntax
9876218822Sdim		  && inst.instruction == T_MNEM_muls, BAD_THUMB32);
9877218822Sdim      constraint (inst.operands[0].reg > 7 || inst.operands[1].reg > 7,
9878218822Sdim		  BAD_HIREG);
987960484Sobrien
9880218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
9881218822Sdim      inst.instruction |= inst.operands[0].reg;
9882218822Sdim
9883218822Sdim      if (inst.operands[0].reg == inst.operands[1].reg)
9884218822Sdim	inst.instruction |= inst.operands[2].reg << 3;
9885218822Sdim      else if (inst.operands[0].reg == inst.operands[2].reg)
9886218822Sdim	inst.instruction |= inst.operands[1].reg << 3;
9887218822Sdim      else
9888218822Sdim	constraint (1, _("dest must overlap one source register"));
9889218822Sdim    }
989089857Sobrien}
989189857Sobrien
9892218822Sdimstatic void
9893218822Sdimdo_t_mull (void)
989489857Sobrien{
9895218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9896218822Sdim  inst.instruction |= inst.operands[1].reg << 8;
9897218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
9898218822Sdim  inst.instruction |= inst.operands[3].reg;
989989857Sobrien
9900218822Sdim  if (inst.operands[0].reg == inst.operands[1].reg)
9901218822Sdim    as_tsktsk (_("rdhi and rdlo must be different"));
9902218822Sdim}
9903218822Sdim
9904218822Sdimstatic void
9905218822Sdimdo_t_nop (void)
9906218822Sdim{
9907218822Sdim  if (unified_syntax)
990860484Sobrien    {
9909218822Sdim      if (inst.size_req == 4 || inst.operands[0].imm > 15)
991089857Sobrien	{
9911218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
9912218822Sdim	  inst.instruction |= inst.operands[0].imm;
991389857Sobrien	}
9914218822Sdim      else
9915218822Sdim	{
9916218822Sdim	  inst.instruction = THUMB_OP16 (inst.instruction);
9917218822Sdim	  inst.instruction |= inst.operands[0].imm << 4;
9918218822Sdim	}
991989857Sobrien    }
9920218822Sdim  else
9921218822Sdim    {
9922218822Sdim      constraint (inst.operands[0].present,
9923218822Sdim		  _("Thumb does not support NOP with hints"));
9924218822Sdim      inst.instruction = 0x46c0;
9925218822Sdim    }
992689857Sobrien}
992789857Sobrien
9928218822Sdimstatic void
9929218822Sdimdo_t_neg (void)
993089857Sobrien{
9931218822Sdim  if (unified_syntax)
993289857Sobrien    {
9933218822Sdim      bfd_boolean narrow;
993489857Sobrien
9935218822Sdim      if (THUMB_SETS_FLAGS (inst.instruction))
9936218822Sdim	narrow = (current_it_mask == 0);
9937218822Sdim      else
9938218822Sdim	narrow = (current_it_mask != 0);
9939218822Sdim      if (inst.operands[0].reg > 7 || inst.operands[1].reg > 7)
9940218822Sdim	narrow = FALSE;
9941218822Sdim      if (inst.size_req == 4)
9942218822Sdim	narrow = FALSE;
994389857Sobrien
9944218822Sdim      if (!narrow)
9945218822Sdim	{
9946218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
9947218822Sdim	  inst.instruction |= inst.operands[0].reg << 8;
9948218822Sdim	  inst.instruction |= inst.operands[1].reg << 16;
994989857Sobrien	}
9950218822Sdim      else
9951218822Sdim	{
9952218822Sdim	  inst.instruction = THUMB_OP16 (inst.instruction);
9953218822Sdim	  inst.instruction |= inst.operands[0].reg;
9954218822Sdim	  inst.instruction |= inst.operands[1].reg << 3;
9955218822Sdim	}
995689857Sobrien    }
9957218822Sdim  else
9958218822Sdim    {
9959218822Sdim      constraint (inst.operands[0].reg > 7 || inst.operands[1].reg > 7,
9960218822Sdim		  BAD_HIREG);
9961218822Sdim      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
996289857Sobrien
9963218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
9964218822Sdim      inst.instruction |= inst.operands[0].reg;
9965218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
9966218822Sdim    }
996789857Sobrien}
996889857Sobrien
996989857Sobrienstatic void
9970218822Sdimdo_t_pkhbt (void)
997189857Sobrien{
9972218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
9973218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
9974218822Sdim  inst.instruction |= inst.operands[2].reg;
9975218822Sdim  if (inst.operands[3].present)
997689857Sobrien    {
9977218822Sdim      unsigned int val = inst.reloc.exp.X_add_number;
9978218822Sdim      constraint (inst.reloc.exp.X_op != O_constant,
9979218822Sdim		  _("expression too complex"));
9980218822Sdim      inst.instruction |= (val & 0x1c) << 10;
9981218822Sdim      inst.instruction |= (val & 0x03) << 6;
998260484Sobrien    }
9983218822Sdim}
998460484Sobrien
9985218822Sdimstatic void
9986218822Sdimdo_t_pkhtb (void)
9987218822Sdim{
9988218822Sdim  if (!inst.operands[3].present)
9989218822Sdim    inst.instruction &= ~0x00000020;
9990218822Sdim  do_t_pkhbt ();
999189857Sobrien}
999289857Sobrien
999389857Sobrienstatic void
9994218822Sdimdo_t_pld (void)
999589857Sobrien{
9996218822Sdim  encode_thumb32_addr_mode (0, /*is_t=*/FALSE, /*is_d=*/FALSE);
9997218822Sdim}
999889857Sobrien
9999218822Sdimstatic void
10000218822Sdimdo_t_push_pop (void)
10001218822Sdim{
10002218822Sdim  unsigned mask;
10003218822Sdim
10004218822Sdim  constraint (inst.operands[0].writeback,
10005218822Sdim	      _("push/pop do not support {reglist}^"));
10006218822Sdim  constraint (inst.reloc.type != BFD_RELOC_UNUSED,
10007218822Sdim	      _("expression too complex"));
1000889857Sobrien
10009218822Sdim  mask = inst.operands[0].imm;
10010218822Sdim  if ((mask & ~0xff) == 0)
10011218822Sdim    inst.instruction = THUMB_OP16 (inst.instruction) | mask;
10012218822Sdim  else if ((inst.instruction == T_MNEM_push
10013218822Sdim	    && (mask & ~0xff) == 1 << REG_LR)
10014218822Sdim	   || (inst.instruction == T_MNEM_pop
10015218822Sdim	       && (mask & ~0xff) == 1 << REG_PC))
1001689857Sobrien    {
10017218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
10018218822Sdim      inst.instruction |= THUMB_PP_PC_LR;
10019218822Sdim      inst.instruction |= mask & 0xff;
10020218822Sdim    }
10021218822Sdim  else if (unified_syntax)
10022218822Sdim    {
10023218822Sdim      inst.instruction = THUMB_OP32 (inst.instruction);
10024218822Sdim      encode_thumb2_ldmstm(13, mask, TRUE);
10025218822Sdim    }
10026218822Sdim  else
10027218822Sdim    {
10028218822Sdim      inst.error = _("invalid register list to push/pop instruction");
1002989857Sobrien      return;
1003089857Sobrien    }
10031218822Sdim}
1003289857Sobrien
10033218822Sdimstatic void
10034218822Sdimdo_t_rbit (void)
10035218822Sdim{
10036218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10037218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
1003889857Sobrien}
1003989857Sobrien
1004089857Sobrienstatic void
10041223484Sdimdo_t_rd_rm (void)
10042223484Sdim{
10043223484Sdim  inst.instruction |= inst.operands[0].reg << 8;
10044223484Sdim  inst.instruction |= inst.operands[1].reg;
10045223484Sdim}
10046223484Sdim
10047223484Sdimstatic void
10048218822Sdimdo_t_rev (void)
1004989857Sobrien{
10050218822Sdim  if (inst.operands[0].reg <= 7 && inst.operands[1].reg <= 7
10051218822Sdim      && inst.size_req != 4)
1005289857Sobrien    {
10053218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
10054218822Sdim      inst.instruction |= inst.operands[0].reg;
10055218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
1005689857Sobrien    }
10057218822Sdim  else if (unified_syntax)
10058218822Sdim    {
10059218822Sdim      inst.instruction = THUMB_OP32 (inst.instruction);
10060218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
10061218822Sdim      inst.instruction |= inst.operands[1].reg << 16;
10062218822Sdim      inst.instruction |= inst.operands[1].reg;
10063218822Sdim    }
10064218822Sdim  else
10065218822Sdim    inst.error = BAD_HIREG;
1006689857Sobrien}
1006789857Sobrien
1006889857Sobrienstatic void
10069218822Sdimdo_t_rsb (void)
1007089857Sobrien{
10071218822Sdim  int Rd, Rs;
1007289857Sobrien
10073218822Sdim  Rd = inst.operands[0].reg;
10074218822Sdim  Rs = (inst.operands[1].present
10075218822Sdim	? inst.operands[1].reg    /* Rd, Rs, foo */
10076218822Sdim	: inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
1007789857Sobrien
10078218822Sdim  inst.instruction |= Rd << 8;
10079218822Sdim  inst.instruction |= Rs << 16;
10080218822Sdim  if (!inst.operands[2].isreg)
1008189857Sobrien    {
10082218822Sdim      bfd_boolean narrow;
1008389857Sobrien
10084218822Sdim      if ((inst.instruction & 0x00100000) != 0)
10085218822Sdim	narrow = (current_it_mask == 0);
10086218822Sdim      else
10087218822Sdim	narrow = (current_it_mask != 0);
1008889857Sobrien
10089218822Sdim      if (Rd > 7 || Rs > 7)
10090218822Sdim	narrow = FALSE;
1009189857Sobrien
10092218822Sdim      if (inst.size_req == 4 || !unified_syntax)
10093218822Sdim	narrow = FALSE;
1009489857Sobrien
10095218822Sdim      if (inst.reloc.exp.X_op != O_constant
10096218822Sdim	  || inst.reloc.exp.X_add_number != 0)
10097218822Sdim	narrow = FALSE;
10098218822Sdim
10099218822Sdim      /* Turn rsb #0 into 16-bit neg.  We should probably do this via
10100218822Sdim         relaxation, but it doesn't seem worth the hassle.  */
10101218822Sdim      if (narrow)
10102218822Sdim	{
10103218822Sdim	  inst.reloc.type = BFD_RELOC_UNUSED;
10104218822Sdim	  inst.instruction = THUMB_OP16 (T_MNEM_negs);
10105218822Sdim	  inst.instruction |= Rs << 3;
10106218822Sdim	  inst.instruction |= Rd;
10107218822Sdim	}
10108218822Sdim      else
10109218822Sdim	{
10110218822Sdim	  inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
10111218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
10112218822Sdim	}
1011389857Sobrien    }
10114218822Sdim  else
10115218822Sdim    encode_thumb32_shifted_operand (2);
10116218822Sdim}
1011789857Sobrien
10118218822Sdimstatic void
10119218822Sdimdo_t_setend (void)
10120218822Sdim{
10121218822Sdim  constraint (current_it_mask, BAD_NOT_IT);
10122218822Sdim  if (inst.operands[0].imm)
10123218822Sdim    inst.instruction |= 0x8;
1012489857Sobrien}
1012589857Sobrien
1012689857Sobrienstatic void
10127218822Sdimdo_t_shift (void)
1012889857Sobrien{
10129218822Sdim  if (!inst.operands[1].present)
10130218822Sdim    inst.operands[1].reg = inst.operands[0].reg;
1013189857Sobrien
10132218822Sdim  if (unified_syntax)
1013389857Sobrien    {
10134218822Sdim      bfd_boolean narrow;
10135218822Sdim      int shift_kind;
10136218822Sdim
10137218822Sdim      switch (inst.instruction)
10138218822Sdim	{
10139218822Sdim	case T_MNEM_asr:
10140218822Sdim	case T_MNEM_asrs: shift_kind = SHIFT_ASR; break;
10141218822Sdim	case T_MNEM_lsl:
10142218822Sdim	case T_MNEM_lsls: shift_kind = SHIFT_LSL; break;
10143218822Sdim	case T_MNEM_lsr:
10144218822Sdim	case T_MNEM_lsrs: shift_kind = SHIFT_LSR; break;
10145218822Sdim	case T_MNEM_ror:
10146218822Sdim	case T_MNEM_rors: shift_kind = SHIFT_ROR; break;
10147218822Sdim	default: abort ();
10148218822Sdim	}
10149218822Sdim
10150218822Sdim      if (THUMB_SETS_FLAGS (inst.instruction))
10151218822Sdim	narrow = (current_it_mask == 0);
10152218822Sdim      else
10153218822Sdim	narrow = (current_it_mask != 0);
10154218822Sdim      if (inst.operands[0].reg > 7 || inst.operands[1].reg > 7)
10155218822Sdim	narrow = FALSE;
10156218822Sdim      if (!inst.operands[2].isreg && shift_kind == SHIFT_ROR)
10157218822Sdim	narrow = FALSE;
10158218822Sdim      if (inst.operands[2].isreg
10159218822Sdim	  && (inst.operands[1].reg != inst.operands[0].reg
10160218822Sdim	      || inst.operands[2].reg > 7))
10161218822Sdim	narrow = FALSE;
10162218822Sdim      if (inst.size_req == 4)
10163218822Sdim	narrow = FALSE;
10164218822Sdim
10165218822Sdim      if (!narrow)
10166218822Sdim	{
10167218822Sdim	  if (inst.operands[2].isreg)
10168218822Sdim	    {
10169218822Sdim	      inst.instruction = THUMB_OP32 (inst.instruction);
10170218822Sdim	      inst.instruction |= inst.operands[0].reg << 8;
10171218822Sdim	      inst.instruction |= inst.operands[1].reg << 16;
10172218822Sdim	      inst.instruction |= inst.operands[2].reg;
10173218822Sdim	    }
10174218822Sdim	  else
10175218822Sdim	    {
10176218822Sdim	      inst.operands[1].shifted = 1;
10177218822Sdim	      inst.operands[1].shift_kind = shift_kind;
10178218822Sdim	      inst.instruction = THUMB_OP32 (THUMB_SETS_FLAGS (inst.instruction)
10179218822Sdim					     ? T_MNEM_movs : T_MNEM_mov);
10180218822Sdim	      inst.instruction |= inst.operands[0].reg << 8;
10181218822Sdim	      encode_thumb32_shifted_operand (1);
10182218822Sdim	      /* Prevent the incorrect generation of an ARM_IMMEDIATE fixup.  */
10183218822Sdim	      inst.reloc.type = BFD_RELOC_UNUSED;
10184218822Sdim	    }
10185218822Sdim	}
10186218822Sdim      else
10187218822Sdim	{
10188218822Sdim	  if (inst.operands[2].isreg)
10189218822Sdim	    {
10190218822Sdim	      switch (shift_kind)
10191218822Sdim		{
10192218822Sdim		case SHIFT_ASR: inst.instruction = T_OPCODE_ASR_R; break;
10193218822Sdim		case SHIFT_LSL: inst.instruction = T_OPCODE_LSL_R; break;
10194218822Sdim		case SHIFT_LSR: inst.instruction = T_OPCODE_LSR_R; break;
10195218822Sdim		case SHIFT_ROR: inst.instruction = T_OPCODE_ROR_R; break;
10196218822Sdim		default: abort ();
10197218822Sdim		}
10198218822Sdim
10199218822Sdim	      inst.instruction |= inst.operands[0].reg;
10200218822Sdim	      inst.instruction |= inst.operands[2].reg << 3;
10201218822Sdim	    }
10202218822Sdim	  else
10203218822Sdim	    {
10204218822Sdim	      switch (shift_kind)
10205218822Sdim		{
10206218822Sdim		case SHIFT_ASR: inst.instruction = T_OPCODE_ASR_I; break;
10207218822Sdim		case SHIFT_LSL: inst.instruction = T_OPCODE_LSL_I; break;
10208218822Sdim		case SHIFT_LSR: inst.instruction = T_OPCODE_LSR_I; break;
10209218822Sdim		default: abort ();
10210218822Sdim		}
10211218822Sdim	      inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
10212218822Sdim	      inst.instruction |= inst.operands[0].reg;
10213218822Sdim	      inst.instruction |= inst.operands[1].reg << 3;
10214218822Sdim	    }
10215218822Sdim	}
1021689857Sobrien    }
10217218822Sdim  else
10218218822Sdim    {
10219218822Sdim      constraint (inst.operands[0].reg > 7
10220218822Sdim		  || inst.operands[1].reg > 7, BAD_HIREG);
10221218822Sdim      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
1022289857Sobrien
10223218822Sdim      if (inst.operands[2].isreg)  /* Rd, {Rs,} Rn */
10224218822Sdim	{
10225218822Sdim	  constraint (inst.operands[2].reg > 7, BAD_HIREG);
10226218822Sdim	  constraint (inst.operands[0].reg != inst.operands[1].reg,
10227218822Sdim		      _("source1 and dest must be same register"));
10228218822Sdim
10229218822Sdim	  switch (inst.instruction)
10230218822Sdim	    {
10231218822Sdim	    case T_MNEM_asr: inst.instruction = T_OPCODE_ASR_R; break;
10232218822Sdim	    case T_MNEM_lsl: inst.instruction = T_OPCODE_LSL_R; break;
10233218822Sdim	    case T_MNEM_lsr: inst.instruction = T_OPCODE_LSR_R; break;
10234218822Sdim	    case T_MNEM_ror: inst.instruction = T_OPCODE_ROR_R; break;
10235218822Sdim	    default: abort ();
10236218822Sdim	    }
10237218822Sdim
10238218822Sdim	  inst.instruction |= inst.operands[0].reg;
10239218822Sdim	  inst.instruction |= inst.operands[2].reg << 3;
10240218822Sdim	}
10241218822Sdim      else
10242218822Sdim	{
10243218822Sdim	  switch (inst.instruction)
10244218822Sdim	    {
10245218822Sdim	    case T_MNEM_asr: inst.instruction = T_OPCODE_ASR_I; break;
10246218822Sdim	    case T_MNEM_lsl: inst.instruction = T_OPCODE_LSL_I; break;
10247218822Sdim	    case T_MNEM_lsr: inst.instruction = T_OPCODE_LSR_I; break;
10248218822Sdim	    case T_MNEM_ror: inst.error = _("ror #imm not supported"); return;
10249218822Sdim	    default: abort ();
10250218822Sdim	    }
10251218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
10252218822Sdim	  inst.instruction |= inst.operands[0].reg;
10253218822Sdim	  inst.instruction |= inst.operands[1].reg << 3;
10254218822Sdim	}
1025589857Sobrien    }
10256218822Sdim}
1025789857Sobrien
10258218822Sdimstatic void
10259218822Sdimdo_t_simd (void)
10260218822Sdim{
10261218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10262218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
10263218822Sdim  inst.instruction |= inst.operands[2].reg;
1026489857Sobrien}
1026589857Sobrien
1026689857Sobrienstatic void
10267218822Sdimdo_t_smc (void)
1026889857Sobrien{
10269218822Sdim  unsigned int value = inst.reloc.exp.X_add_number;
10270218822Sdim  constraint (inst.reloc.exp.X_op != O_constant,
10271218822Sdim	      _("expression too complex"));
10272218822Sdim  inst.reloc.type = BFD_RELOC_UNUSED;
10273218822Sdim  inst.instruction |= (value & 0xf000) >> 12;
10274218822Sdim  inst.instruction |= (value & 0x0ff0);
10275218822Sdim  inst.instruction |= (value & 0x000f) << 16;
1027660484Sobrien}
1027760484Sobrien
1027860484Sobrienstatic void
10279218822Sdimdo_t_ssat (void)
10280130561Sobrien{
10281218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10282218822Sdim  inst.instruction |= inst.operands[1].imm - 1;
10283218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
10284130561Sobrien
10285218822Sdim  if (inst.operands[3].present)
10286130561Sobrien    {
10287218822Sdim      constraint (inst.reloc.exp.X_op != O_constant,
10288218822Sdim		  _("expression too complex"));
10289130561Sobrien
10290218822Sdim      if (inst.reloc.exp.X_add_number != 0)
10291218822Sdim	{
10292218822Sdim	  if (inst.operands[3].shift_kind == SHIFT_ASR)
10293218822Sdim	    inst.instruction |= 0x00200000;  /* sh bit */
10294218822Sdim	  inst.instruction |= (inst.reloc.exp.X_add_number & 0x1c) << 10;
10295218822Sdim	  inst.instruction |= (inst.reloc.exp.X_add_number & 0x03) << 6;
10296218822Sdim	}
10297218822Sdim      inst.reloc.type = BFD_RELOC_UNUSED;
10298130561Sobrien    }
10299218822Sdim}
10300130561Sobrien
10301218822Sdimstatic void
10302218822Sdimdo_t_ssat16 (void)
10303218822Sdim{
10304218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10305218822Sdim  inst.instruction |= inst.operands[1].imm - 1;
10306218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
10307130561Sobrien}
10308130561Sobrien
10309130561Sobrienstatic void
10310218822Sdimdo_t_strex (void)
1031160484Sobrien{
10312218822Sdim  constraint (!inst.operands[2].isreg || !inst.operands[2].preind
10313218822Sdim	      || inst.operands[2].postind || inst.operands[2].writeback
10314218822Sdim	      || inst.operands[2].immisreg || inst.operands[2].shifted
10315218822Sdim	      || inst.operands[2].negative,
10316218822Sdim	      BAD_ADDR_MODE);
1031760484Sobrien
10318218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10319218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
10320218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
10321218822Sdim  inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_U8;
1032260484Sobrien}
1032360484Sobrien
1032489857Sobrienstatic void
10325218822Sdimdo_t_strexd (void)
1032689857Sobrien{
10327218822Sdim  if (!inst.operands[2].present)
10328218822Sdim    inst.operands[2].reg = inst.operands[1].reg + 1;
1032989857Sobrien
10330218822Sdim  constraint (inst.operands[0].reg == inst.operands[1].reg
10331218822Sdim	      || inst.operands[0].reg == inst.operands[2].reg
10332218822Sdim	      || inst.operands[0].reg == inst.operands[3].reg
10333218822Sdim	      || inst.operands[1].reg == inst.operands[2].reg,
10334218822Sdim	      BAD_OVERLAP);
1033589857Sobrien
10336218822Sdim  inst.instruction |= inst.operands[0].reg;
10337218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
10338218822Sdim  inst.instruction |= inst.operands[2].reg << 8;
10339218822Sdim  inst.instruction |= inst.operands[3].reg << 16;
10340218822Sdim}
1034189857Sobrien
10342218822Sdimstatic void
10343218822Sdimdo_t_sxtah (void)
10344218822Sdim{
10345218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10346218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
10347218822Sdim  inst.instruction |= inst.operands[2].reg;
10348218822Sdim  inst.instruction |= inst.operands[3].imm << 4;
1034989857Sobrien}
1035089857Sobrien
1035189857Sobrienstatic void
10352218822Sdimdo_t_sxth (void)
1035389857Sobrien{
10354218822Sdim  if (inst.instruction <= 0xffff && inst.size_req != 4
10355218822Sdim      && inst.operands[0].reg <= 7 && inst.operands[1].reg <= 7
10356218822Sdim      && (!inst.operands[2].present || inst.operands[2].imm == 0))
1035789857Sobrien    {
10358218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
10359218822Sdim      inst.instruction |= inst.operands[0].reg;
10360218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
1036189857Sobrien    }
10362218822Sdim  else if (unified_syntax)
10363218822Sdim    {
10364218822Sdim      if (inst.instruction <= 0xffff)
10365218822Sdim	inst.instruction = THUMB_OP32 (inst.instruction);
10366218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
10367218822Sdim      inst.instruction |= inst.operands[1].reg;
10368218822Sdim      inst.instruction |= inst.operands[2].imm << 4;
10369218822Sdim    }
10370218822Sdim  else
10371218822Sdim    {
10372218822Sdim      constraint (inst.operands[2].present && inst.operands[2].imm != 0,
10373218822Sdim		  _("Thumb encoding does not support rotation"));
10374218822Sdim      constraint (1, BAD_HIREG);
10375218822Sdim    }
10376218822Sdim}
1037789857Sobrien
10378218822Sdimstatic void
10379218822Sdimdo_t_swi (void)
10380218822Sdim{
10381218822Sdim  inst.reloc.type = BFD_RELOC_ARM_SWI;
1038289857Sobrien}
1038389857Sobrien
1038489857Sobrienstatic void
10385218822Sdimdo_t_tb (void)
1038689857Sobrien{
10387218822Sdim  int half;
1038889857Sobrien
10389218822Sdim  half = (inst.instruction & 0x10) != 0;
10390218822Sdim  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
10391218822Sdim  constraint (inst.operands[0].immisreg,
10392218822Sdim	      _("instruction requires register index"));
10393218822Sdim  constraint (inst.operands[0].imm == 15,
10394218822Sdim	      _("PC is not a valid index register"));
10395218822Sdim  constraint (!half && inst.operands[0].shifted,
10396218822Sdim	      _("instruction does not allow shifted index"));
10397218822Sdim  inst.instruction |= (inst.operands[0].reg << 16) | inst.operands[0].imm;
1039889857Sobrien}
1039989857Sobrien
10400218822Sdimstatic void
10401218822Sdimdo_t_usat (void)
1040289857Sobrien{
10403218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10404218822Sdim  inst.instruction |= inst.operands[1].imm;
10405218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
1040689857Sobrien
10407218822Sdim  if (inst.operands[3].present)
1040889857Sobrien    {
10409218822Sdim      constraint (inst.reloc.exp.X_op != O_constant,
10410218822Sdim		  _("expression too complex"));
10411218822Sdim      if (inst.reloc.exp.X_add_number != 0)
10412218822Sdim	{
10413218822Sdim	  if (inst.operands[3].shift_kind == SHIFT_ASR)
10414218822Sdim	    inst.instruction |= 0x00200000;  /* sh bit */
1041589857Sobrien
10416218822Sdim	  inst.instruction |= (inst.reloc.exp.X_add_number & 0x1c) << 10;
10417218822Sdim	  inst.instruction |= (inst.reloc.exp.X_add_number & 0x03) << 6;
1041889857Sobrien	}
10419218822Sdim      inst.reloc.type = BFD_RELOC_UNUSED;
1042089857Sobrien    }
1042189857Sobrien}
1042289857Sobrien
10423218822Sdimstatic void
10424218822Sdimdo_t_usat16 (void)
1042589857Sobrien{
10426218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10427218822Sdim  inst.instruction |= inst.operands[1].imm;
10428218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
10429218822Sdim}
1043089857Sobrien
10431218822Sdim/* Neon instruction encoder helpers.  */
10432218822Sdim
10433218822Sdim/* Encodings for the different types for various Neon opcodes.  */
1043489857Sobrien
10435218822Sdim/* An "invalid" code for the following tables.  */
10436218822Sdim#define N_INV -1u
1043789857Sobrien
10438218822Sdimstruct neon_tab_entry
10439218822Sdim{
10440218822Sdim  unsigned integer;
10441218822Sdim  unsigned float_or_poly;
10442218822Sdim  unsigned scalar_or_imm;
10443218822Sdim};
10444218822Sdim
10445218822Sdim/* Map overloaded Neon opcodes to their respective encodings.  */
10446218822Sdim#define NEON_ENC_TAB					\
10447218822Sdim  X(vabd,	0x0000700, 0x1200d00, N_INV),		\
10448218822Sdim  X(vmax,	0x0000600, 0x0000f00, N_INV),		\
10449218822Sdim  X(vmin,	0x0000610, 0x0200f00, N_INV),		\
10450218822Sdim  X(vpadd,	0x0000b10, 0x1000d00, N_INV),		\
10451218822Sdim  X(vpmax,	0x0000a00, 0x1000f00, N_INV),		\
10452218822Sdim  X(vpmin,	0x0000a10, 0x1200f00, N_INV),		\
10453218822Sdim  X(vadd,	0x0000800, 0x0000d00, N_INV),		\
10454218822Sdim  X(vsub,	0x1000800, 0x0200d00, N_INV),		\
10455218822Sdim  X(vceq,	0x1000810, 0x0000e00, 0x1b10100),	\
10456218822Sdim  X(vcge,	0x0000310, 0x1000e00, 0x1b10080),	\
10457218822Sdim  X(vcgt,	0x0000300, 0x1200e00, 0x1b10000),	\
10458218822Sdim  /* Register variants of the following two instructions are encoded as
10459218822Sdim     vcge / vcgt with the operands reversed. */  	\
10460218822Sdim  X(vclt,	0x0000300, 0x1200e00, 0x1b10200),	\
10461218822Sdim  X(vcle,	0x0000310, 0x1000e00, 0x1b10180),	\
10462218822Sdim  X(vmla,	0x0000900, 0x0000d10, 0x0800040),	\
10463218822Sdim  X(vmls,	0x1000900, 0x0200d10, 0x0800440),	\
10464218822Sdim  X(vmul,	0x0000910, 0x1000d10, 0x0800840),	\
10465218822Sdim  X(vmull,	0x0800c00, 0x0800e00, 0x0800a40), /* polynomial not float.  */ \
10466218822Sdim  X(vmlal,	0x0800800, N_INV,     0x0800240),	\
10467218822Sdim  X(vmlsl,	0x0800a00, N_INV,     0x0800640),	\
10468218822Sdim  X(vqdmlal,	0x0800900, N_INV,     0x0800340),	\
10469218822Sdim  X(vqdmlsl,	0x0800b00, N_INV,     0x0800740),	\
10470218822Sdim  X(vqdmull,	0x0800d00, N_INV,     0x0800b40),	\
10471218822Sdim  X(vqdmulh,    0x0000b00, N_INV,     0x0800c40),	\
10472218822Sdim  X(vqrdmulh,   0x1000b00, N_INV,     0x0800d40),	\
10473218822Sdim  X(vshl,	0x0000400, N_INV,     0x0800510),	\
10474218822Sdim  X(vqshl,	0x0000410, N_INV,     0x0800710),	\
10475218822Sdim  X(vand,	0x0000110, N_INV,     0x0800030),	\
10476218822Sdim  X(vbic,	0x0100110, N_INV,     0x0800030),	\
10477218822Sdim  X(veor,	0x1000110, N_INV,     N_INV),		\
10478218822Sdim  X(vorn,	0x0300110, N_INV,     0x0800010),	\
10479218822Sdim  X(vorr,	0x0200110, N_INV,     0x0800010),	\
10480218822Sdim  X(vmvn,	0x1b00580, N_INV,     0x0800030),	\
10481218822Sdim  X(vshll,	0x1b20300, N_INV,     0x0800a10), /* max shift, immediate.  */ \
10482218822Sdim  X(vcvt,       0x1b30600, N_INV,     0x0800e10), /* integer, fixed-point.  */ \
10483218822Sdim  X(vdup,       0xe800b10, N_INV,     0x1b00c00), /* arm, scalar.  */ \
10484218822Sdim  X(vld1,       0x0200000, 0x0a00000, 0x0a00c00), /* interlv, lane, dup.  */ \
10485218822Sdim  X(vst1,	0x0000000, 0x0800000, N_INV),		\
10486218822Sdim  X(vld2,	0x0200100, 0x0a00100, 0x0a00d00),	\
10487218822Sdim  X(vst2,	0x0000100, 0x0800100, N_INV),		\
10488218822Sdim  X(vld3,	0x0200200, 0x0a00200, 0x0a00e00),	\
10489218822Sdim  X(vst3,	0x0000200, 0x0800200, N_INV),		\
10490218822Sdim  X(vld4,	0x0200300, 0x0a00300, 0x0a00f00),	\
10491218822Sdim  X(vst4,	0x0000300, 0x0800300, N_INV),		\
10492218822Sdim  X(vmovn,	0x1b20200, N_INV,     N_INV),		\
10493218822Sdim  X(vtrn,	0x1b20080, N_INV,     N_INV),		\
10494218822Sdim  X(vqmovn,	0x1b20200, N_INV,     N_INV),		\
10495218822Sdim  X(vqmovun,	0x1b20240, N_INV,     N_INV),		\
10496218822Sdim  X(vnmul,      0xe200a40, 0xe200b40, N_INV),		\
10497218822Sdim  X(vnmla,      0xe000a40, 0xe000b40, N_INV),		\
10498218822Sdim  X(vnmls,      0xe100a40, 0xe100b40, N_INV),		\
10499218822Sdim  X(vcmp,	0xeb40a40, 0xeb40b40, N_INV),		\
10500218822Sdim  X(vcmpz,	0xeb50a40, 0xeb50b40, N_INV),		\
10501218822Sdim  X(vcmpe,	0xeb40ac0, 0xeb40bc0, N_INV),		\
10502218822Sdim  X(vcmpez,     0xeb50ac0, 0xeb50bc0, N_INV)
1050389857Sobrien
10504218822Sdimenum neon_opc
10505218822Sdim{
10506218822Sdim#define X(OPC,I,F,S) N_MNEM_##OPC
10507218822SdimNEON_ENC_TAB
10508218822Sdim#undef X
10509218822Sdim};
1051089857Sobrien
10511218822Sdimstatic const struct neon_tab_entry neon_enc_tab[] =
1051289857Sobrien{
10513218822Sdim#define X(OPC,I,F,S) { (I), (F), (S) }
10514218822SdimNEON_ENC_TAB
10515218822Sdim#undef X
10516218822Sdim};
1051789857Sobrien
10518218822Sdim#define NEON_ENC_INTEGER(X) (neon_enc_tab[(X) & 0x0fffffff].integer)
10519218822Sdim#define NEON_ENC_ARMREG(X)  (neon_enc_tab[(X) & 0x0fffffff].integer)
10520218822Sdim#define NEON_ENC_POLY(X)    (neon_enc_tab[(X) & 0x0fffffff].float_or_poly)
10521218822Sdim#define NEON_ENC_FLOAT(X)   (neon_enc_tab[(X) & 0x0fffffff].float_or_poly)
10522218822Sdim#define NEON_ENC_SCALAR(X)  (neon_enc_tab[(X) & 0x0fffffff].scalar_or_imm)
10523218822Sdim#define NEON_ENC_IMMED(X)   (neon_enc_tab[(X) & 0x0fffffff].scalar_or_imm)
10524218822Sdim#define NEON_ENC_INTERLV(X) (neon_enc_tab[(X) & 0x0fffffff].integer)
10525218822Sdim#define NEON_ENC_LANE(X)    (neon_enc_tab[(X) & 0x0fffffff].float_or_poly)
10526218822Sdim#define NEON_ENC_DUP(X)     (neon_enc_tab[(X) & 0x0fffffff].scalar_or_imm)
10527218822Sdim#define NEON_ENC_SINGLE(X) \
10528218822Sdim  ((neon_enc_tab[(X) & 0x0fffffff].integer) | ((X) & 0xf0000000))
10529218822Sdim#define NEON_ENC_DOUBLE(X) \
10530218822Sdim  ((neon_enc_tab[(X) & 0x0fffffff].float_or_poly) | ((X) & 0xf0000000))
1053189857Sobrien
10532218822Sdim/* Define shapes for instruction operands. The following mnemonic characters
10533218822Sdim   are used in this table:
1053489857Sobrien
10535218822Sdim     F - VFP S<n> register
10536218822Sdim     D - Neon D<n> register
10537218822Sdim     Q - Neon Q<n> register
10538218822Sdim     I - Immediate
10539218822Sdim     S - Scalar
10540218822Sdim     R - ARM register
10541218822Sdim     L - D<n> register list
10542218822Sdim
10543218822Sdim   This table is used to generate various data:
10544218822Sdim     - enumerations of the form NS_DDR to be used as arguments to
10545218822Sdim       neon_select_shape.
10546218822Sdim     - a table classifying shapes into single, double, quad, mixed.
10547218822Sdim     - a table used to drive neon_select_shape.
10548218822Sdim*/
1054989857Sobrien
10550218822Sdim#define NEON_SHAPE_DEF			\
10551218822Sdim  X(3, (D, D, D), DOUBLE),		\
10552218822Sdim  X(3, (Q, Q, Q), QUAD),		\
10553218822Sdim  X(3, (D, D, I), DOUBLE),		\
10554218822Sdim  X(3, (Q, Q, I), QUAD),		\
10555218822Sdim  X(3, (D, D, S), DOUBLE),		\
10556218822Sdim  X(3, (Q, Q, S), QUAD),		\
10557218822Sdim  X(2, (D, D), DOUBLE),			\
10558218822Sdim  X(2, (Q, Q), QUAD),			\
10559218822Sdim  X(2, (D, S), DOUBLE),			\
10560218822Sdim  X(2, (Q, S), QUAD),			\
10561218822Sdim  X(2, (D, R), DOUBLE),			\
10562218822Sdim  X(2, (Q, R), QUAD),			\
10563218822Sdim  X(2, (D, I), DOUBLE),			\
10564218822Sdim  X(2, (Q, I), QUAD),			\
10565218822Sdim  X(3, (D, L, D), DOUBLE),		\
10566218822Sdim  X(2, (D, Q), MIXED),			\
10567218822Sdim  X(2, (Q, D), MIXED),			\
10568218822Sdim  X(3, (D, Q, I), MIXED),		\
10569218822Sdim  X(3, (Q, D, I), MIXED),		\
10570218822Sdim  X(3, (Q, D, D), MIXED),		\
10571218822Sdim  X(3, (D, Q, Q), MIXED),		\
10572218822Sdim  X(3, (Q, Q, D), MIXED),		\
10573218822Sdim  X(3, (Q, D, S), MIXED),		\
10574218822Sdim  X(3, (D, Q, S), MIXED),		\
10575218822Sdim  X(4, (D, D, D, I), DOUBLE),		\
10576218822Sdim  X(4, (Q, Q, Q, I), QUAD),		\
10577218822Sdim  X(2, (F, F), SINGLE),			\
10578218822Sdim  X(3, (F, F, F), SINGLE),		\
10579218822Sdim  X(2, (F, I), SINGLE),			\
10580218822Sdim  X(2, (F, D), MIXED),			\
10581218822Sdim  X(2, (D, F), MIXED),			\
10582218822Sdim  X(3, (F, F, I), MIXED),		\
10583218822Sdim  X(4, (R, R, F, F), SINGLE),		\
10584218822Sdim  X(4, (F, F, R, R), SINGLE),		\
10585218822Sdim  X(3, (D, R, R), DOUBLE),		\
10586218822Sdim  X(3, (R, R, D), DOUBLE),		\
10587218822Sdim  X(2, (S, R), SINGLE),			\
10588218822Sdim  X(2, (R, S), SINGLE),			\
10589218822Sdim  X(2, (F, R), SINGLE),			\
10590218822Sdim  X(2, (R, F), SINGLE)
10591218822Sdim
10592218822Sdim#define S2(A,B)		NS_##A##B
10593218822Sdim#define S3(A,B,C)	NS_##A##B##C
10594218822Sdim#define S4(A,B,C,D)	NS_##A##B##C##D
10595218822Sdim
10596218822Sdim#define X(N, L, C) S##N L
10597218822Sdim
10598218822Sdimenum neon_shape
1059989857Sobrien{
10600218822Sdim  NEON_SHAPE_DEF,
10601218822Sdim  NS_NULL
10602218822Sdim};
1060389857Sobrien
10604218822Sdim#undef X
10605218822Sdim#undef S2
10606218822Sdim#undef S3
10607218822Sdim#undef S4
1060889857Sobrien
10609218822Sdimenum neon_shape_class
10610218822Sdim{
10611218822Sdim  SC_SINGLE,
10612218822Sdim  SC_DOUBLE,
10613218822Sdim  SC_QUAD,
10614218822Sdim  SC_MIXED
10615218822Sdim};
1061689857Sobrien
10617218822Sdim#define X(N, L, C) SC_##C
1061889857Sobrien
10619218822Sdimstatic enum neon_shape_class neon_shape_class[] =
1062089857Sobrien{
10621218822Sdim  NEON_SHAPE_DEF
10622218822Sdim};
1062389857Sobrien
10624218822Sdim#undef X
1062589857Sobrien
10626218822Sdimenum neon_shape_el
10627218822Sdim{
10628218822Sdim  SE_F,
10629218822Sdim  SE_D,
10630218822Sdim  SE_Q,
10631218822Sdim  SE_I,
10632218822Sdim  SE_S,
10633218822Sdim  SE_R,
10634218822Sdim  SE_L
10635218822Sdim};
1063689857Sobrien
10637218822Sdim/* Register widths of above.  */
10638218822Sdimstatic unsigned neon_shape_el_size[] =
10639218822Sdim{
10640218822Sdim  32,
10641218822Sdim  64,
10642218822Sdim  128,
10643218822Sdim  0,
10644218822Sdim  32,
10645218822Sdim  32,
10646218822Sdim  0
10647218822Sdim};
1064889857Sobrien
10649218822Sdimstruct neon_shape_info
1065089857Sobrien{
10651218822Sdim  unsigned els;
10652218822Sdim  enum neon_shape_el el[NEON_MAX_TYPE_ELS];
10653218822Sdim};
1065489857Sobrien
10655218822Sdim#define S2(A,B)		{ SE_##A, SE_##B }
10656218822Sdim#define S3(A,B,C)	{ SE_##A, SE_##B, SE_##C }
10657218822Sdim#define S4(A,B,C,D)	{ SE_##A, SE_##B, SE_##C, SE_##D }
1065889857Sobrien
10659218822Sdim#define X(N, L, C) { N, S##N L }
1066089857Sobrien
10661218822Sdimstatic struct neon_shape_info neon_shape_tab[] =
1066289857Sobrien{
10663218822Sdim  NEON_SHAPE_DEF
10664218822Sdim};
1066589857Sobrien
10666218822Sdim#undef X
10667218822Sdim#undef S2
10668218822Sdim#undef S3
10669218822Sdim#undef S4
1067089857Sobrien
10671218822Sdim/* Bit masks used in type checking given instructions.
10672218822Sdim  'N_EQK' means the type must be the same as (or based on in some way) the key
10673218822Sdim   type, which itself is marked with the 'N_KEY' bit. If the 'N_EQK' bit is
10674218822Sdim   set, various other bits can be set as well in order to modify the meaning of
10675218822Sdim   the type constraint.  */
1067689857Sobrien
10677218822Sdimenum neon_type_mask
10678218822Sdim{
10679218822Sdim  N_S8   = 0x000001,
10680218822Sdim  N_S16  = 0x000002,
10681218822Sdim  N_S32  = 0x000004,
10682218822Sdim  N_S64  = 0x000008,
10683218822Sdim  N_U8   = 0x000010,
10684218822Sdim  N_U16  = 0x000020,
10685218822Sdim  N_U32  = 0x000040,
10686218822Sdim  N_U64  = 0x000080,
10687218822Sdim  N_I8   = 0x000100,
10688218822Sdim  N_I16  = 0x000200,
10689218822Sdim  N_I32  = 0x000400,
10690218822Sdim  N_I64  = 0x000800,
10691218822Sdim  N_8    = 0x001000,
10692218822Sdim  N_16   = 0x002000,
10693218822Sdim  N_32   = 0x004000,
10694218822Sdim  N_64   = 0x008000,
10695218822Sdim  N_P8   = 0x010000,
10696218822Sdim  N_P16  = 0x020000,
10697218822Sdim  N_F32  = 0x040000,
10698218822Sdim  N_F64  = 0x080000,
10699218822Sdim  N_KEY  = 0x100000, /* key element (main type specifier).  */
10700218822Sdim  N_EQK  = 0x200000, /* given operand has the same type & size as the key.  */
10701218822Sdim  N_VFP  = 0x400000, /* VFP mode: operand size must match register width.  */
10702218822Sdim  N_DBL  = 0x000001, /* if N_EQK, this operand is twice the size.  */
10703218822Sdim  N_HLF  = 0x000002, /* if N_EQK, this operand is half the size.  */
10704218822Sdim  N_SGN  = 0x000004, /* if N_EQK, this operand is forced to be signed.  */
10705218822Sdim  N_UNS  = 0x000008, /* if N_EQK, this operand is forced to be unsigned.  */
10706218822Sdim  N_INT  = 0x000010, /* if N_EQK, this operand is forced to be integer.  */
10707218822Sdim  N_FLT  = 0x000020, /* if N_EQK, this operand is forced to be float.  */
10708218822Sdim  N_SIZ  = 0x000040, /* if N_EQK, this operand is forced to be size-only.  */
10709218822Sdim  N_UTYP = 0,
10710218822Sdim  N_MAX_NONSPECIAL = N_F64
10711218822Sdim};
1071289857Sobrien
10713218822Sdim#define N_ALLMODS  (N_DBL | N_HLF | N_SGN | N_UNS | N_INT | N_FLT | N_SIZ)
1071489857Sobrien
10715218822Sdim#define N_SU_ALL   (N_S8 | N_S16 | N_S32 | N_S64 | N_U8 | N_U16 | N_U32 | N_U64)
10716218822Sdim#define N_SU_32    (N_S8 | N_S16 | N_S32 | N_U8 | N_U16 | N_U32)
10717218822Sdim#define N_SU_16_64 (N_S16 | N_S32 | N_S64 | N_U16 | N_U32 | N_U64)
10718218822Sdim#define N_SUF_32   (N_SU_32 | N_F32)
10719218822Sdim#define N_I_ALL    (N_I8 | N_I16 | N_I32 | N_I64)
10720218822Sdim#define N_IF_32    (N_I8 | N_I16 | N_I32 | N_F32)
1072189857Sobrien
10722218822Sdim/* Pass this as the first type argument to neon_check_type to ignore types
10723218822Sdim   altogether.  */
10724218822Sdim#define N_IGNORE_TYPE (N_KEY | N_EQK)
1072589857Sobrien
10726218822Sdim/* Select a "shape" for the current instruction (describing register types or
10727218822Sdim   sizes) from a list of alternatives. Return NS_NULL if the current instruction
10728218822Sdim   doesn't fit. For non-polymorphic shapes, checking is usually done as a
10729218822Sdim   function of operand parsing, so this function doesn't need to be called.
10730218822Sdim   Shapes should be listed in order of decreasing length.  */
1073189857Sobrien
10732218822Sdimstatic enum neon_shape
10733218822Sdimneon_select_shape (enum neon_shape shape, ...)
10734218822Sdim{
10735218822Sdim  va_list ap;
10736218822Sdim  enum neon_shape first_shape = shape;
1073789857Sobrien
10738218822Sdim  /* Fix missing optional operands. FIXME: we don't know at this point how
10739218822Sdim     many arguments we should have, so this makes the assumption that we have
10740218822Sdim     > 1. This is true of all current Neon opcodes, I think, but may not be
10741218822Sdim     true in the future.  */
10742218822Sdim  if (!inst.operands[1].present)
10743218822Sdim    inst.operands[1] = inst.operands[0];
1074489857Sobrien
10745218822Sdim  va_start (ap, shape);
10746218822Sdim
10747218822Sdim  for (; shape != NS_NULL; shape = va_arg (ap, int))
10748218822Sdim    {
10749218822Sdim      unsigned j;
10750218822Sdim      int matches = 1;
1075189857Sobrien
10752218822Sdim      for (j = 0; j < neon_shape_tab[shape].els; j++)
10753218822Sdim        {
10754218822Sdim          if (!inst.operands[j].present)
10755218822Sdim            {
10756218822Sdim              matches = 0;
10757218822Sdim              break;
10758218822Sdim            }
1075989857Sobrien
10760218822Sdim          switch (neon_shape_tab[shape].el[j])
10761218822Sdim            {
10762218822Sdim            case SE_F:
10763218822Sdim              if (!(inst.operands[j].isreg
10764218822Sdim                    && inst.operands[j].isvec
10765218822Sdim                    && inst.operands[j].issingle
10766218822Sdim                    && !inst.operands[j].isquad))
10767218822Sdim                matches = 0;
10768218822Sdim              break;
1076989857Sobrien
10770218822Sdim            case SE_D:
10771218822Sdim              if (!(inst.operands[j].isreg
10772218822Sdim                    && inst.operands[j].isvec
10773218822Sdim                    && !inst.operands[j].isquad
10774218822Sdim                    && !inst.operands[j].issingle))
10775218822Sdim                matches = 0;
10776218822Sdim              break;
1077789857Sobrien
10778218822Sdim            case SE_R:
10779218822Sdim              if (!(inst.operands[j].isreg
10780218822Sdim                    && !inst.operands[j].isvec))
10781218822Sdim                matches = 0;
10782218822Sdim              break;
1078389857Sobrien
10784218822Sdim            case SE_Q:
10785218822Sdim              if (!(inst.operands[j].isreg
10786218822Sdim                    && inst.operands[j].isvec
10787218822Sdim                    && inst.operands[j].isquad
10788218822Sdim                    && !inst.operands[j].issingle))
10789218822Sdim                matches = 0;
10790218822Sdim              break;
1079189857Sobrien
10792218822Sdim            case SE_I:
10793218822Sdim              if (!(!inst.operands[j].isreg
10794218822Sdim                    && !inst.operands[j].isscalar))
10795218822Sdim                matches = 0;
10796218822Sdim              break;
1079789857Sobrien
10798218822Sdim            case SE_S:
10799218822Sdim              if (!(!inst.operands[j].isreg
10800218822Sdim                    && inst.operands[j].isscalar))
10801218822Sdim                matches = 0;
10802218822Sdim              break;
10803218822Sdim
10804218822Sdim            case SE_L:
10805218822Sdim              break;
10806218822Sdim            }
10807218822Sdim        }
10808218822Sdim      if (matches)
10809218822Sdim        break;
1081089857Sobrien    }
10811218822Sdim
10812218822Sdim  va_end (ap);
1081389857Sobrien
10814218822Sdim  if (shape == NS_NULL && first_shape != NS_NULL)
10815218822Sdim    first_error (_("invalid instruction shape"));
1081689857Sobrien
10817218822Sdim  return shape;
10818218822Sdim}
1081989857Sobrien
10820218822Sdim/* True if SHAPE is predominantly a quadword operation (most of the time, this
10821218822Sdim   means the Q bit should be set).  */
1082289857Sobrien
10823218822Sdimstatic int
10824218822Sdimneon_quad (enum neon_shape shape)
10825218822Sdim{
10826218822Sdim  return neon_shape_class[shape] == SC_QUAD;
10827218822Sdim}
10828218822Sdim
10829218822Sdimstatic void
10830218822Sdimneon_modify_type_size (unsigned typebits, enum neon_el_type *g_type,
10831218822Sdim                       unsigned *g_size)
10832218822Sdim{
10833218822Sdim  /* Allow modification to be made to types which are constrained to be
10834218822Sdim     based on the key element, based on bits set alongside N_EQK.  */
10835218822Sdim  if ((typebits & N_EQK) != 0)
1083689857Sobrien    {
10837218822Sdim      if ((typebits & N_HLF) != 0)
10838218822Sdim	*g_size /= 2;
10839218822Sdim      else if ((typebits & N_DBL) != 0)
10840218822Sdim	*g_size *= 2;
10841218822Sdim      if ((typebits & N_SGN) != 0)
10842218822Sdim	*g_type = NT_signed;
10843218822Sdim      else if ((typebits & N_UNS) != 0)
10844218822Sdim        *g_type = NT_unsigned;
10845218822Sdim      else if ((typebits & N_INT) != 0)
10846218822Sdim        *g_type = NT_integer;
10847218822Sdim      else if ((typebits & N_FLT) != 0)
10848218822Sdim        *g_type = NT_float;
10849218822Sdim      else if ((typebits & N_SIZ) != 0)
10850218822Sdim        *g_type = NT_untyped;
1085189857Sobrien    }
10852218822Sdim}
10853218822Sdim
10854218822Sdim/* Return operand OPNO promoted by bits set in THISARG. KEY should be the "key"
10855218822Sdim   operand type, i.e. the single type specified in a Neon instruction when it
10856218822Sdim   is the only one given.  */
1085789857Sobrien
10858218822Sdimstatic struct neon_type_el
10859218822Sdimneon_type_promote (struct neon_type_el *key, unsigned thisarg)
10860218822Sdim{
10861218822Sdim  struct neon_type_el dest = *key;
10862218822Sdim
10863218822Sdim  assert ((thisarg & N_EQK) != 0);
10864218822Sdim
10865218822Sdim  neon_modify_type_size (thisarg, &dest.type, &dest.size);
10866218822Sdim
10867218822Sdim  return dest;
1086889857Sobrien}
1086989857Sobrien
10870218822Sdim/* Convert Neon type and size into compact bitmask representation.  */
10871218822Sdim
10872218822Sdimstatic enum neon_type_mask
10873218822Sdimtype_chk_of_el_type (enum neon_el_type type, unsigned size)
1087489857Sobrien{
10875218822Sdim  switch (type)
10876218822Sdim    {
10877218822Sdim    case NT_untyped:
10878218822Sdim      switch (size)
10879218822Sdim        {
10880218822Sdim        case 8:  return N_8;
10881218822Sdim        case 16: return N_16;
10882218822Sdim        case 32: return N_32;
10883218822Sdim        case 64: return N_64;
10884218822Sdim        default: ;
10885218822Sdim        }
10886218822Sdim      break;
1088789857Sobrien
10888218822Sdim    case NT_integer:
10889218822Sdim      switch (size)
10890218822Sdim        {
10891218822Sdim        case 8:  return N_I8;
10892218822Sdim        case 16: return N_I16;
10893218822Sdim        case 32: return N_I32;
10894218822Sdim        case 64: return N_I64;
10895218822Sdim        default: ;
10896218822Sdim        }
10897218822Sdim      break;
1089889857Sobrien
10899218822Sdim    case NT_float:
10900218822Sdim      switch (size)
10901218822Sdim        {
10902218822Sdim        case 32: return N_F32;
10903218822Sdim        case 64: return N_F64;
10904218822Sdim        default: ;
10905218822Sdim        }
10906218822Sdim      break;
1090789857Sobrien
10908218822Sdim    case NT_poly:
10909218822Sdim      switch (size)
10910218822Sdim        {
10911218822Sdim        case 8:  return N_P8;
10912218822Sdim        case 16: return N_P16;
10913218822Sdim        default: ;
10914218822Sdim        }
10915218822Sdim      break;
1091689857Sobrien
10917218822Sdim    case NT_signed:
10918218822Sdim      switch (size)
10919218822Sdim        {
10920218822Sdim        case 8:  return N_S8;
10921218822Sdim        case 16: return N_S16;
10922218822Sdim        case 32: return N_S32;
10923218822Sdim        case 64: return N_S64;
10924218822Sdim        default: ;
10925218822Sdim        }
10926218822Sdim      break;
1092789857Sobrien
10928218822Sdim    case NT_unsigned:
10929218822Sdim      switch (size)
10930218822Sdim        {
10931218822Sdim        case 8:  return N_U8;
10932218822Sdim        case 16: return N_U16;
10933218822Sdim        case 32: return N_U32;
10934218822Sdim        case 64: return N_U64;
10935218822Sdim        default: ;
10936218822Sdim        }
10937218822Sdim      break;
1093889857Sobrien
10939218822Sdim    default: ;
10940218822Sdim    }
10941218822Sdim
10942218822Sdim  return N_UTYP;
10943218822Sdim}
1094489857Sobrien
10945218822Sdim/* Convert compact Neon bitmask type representation to a type and size. Only
10946218822Sdim   handles the case where a single bit is set in the mask.  */
1094789857Sobrien
10948218822Sdimstatic int
10949218822Sdimel_type_of_type_chk (enum neon_el_type *type, unsigned *size,
10950218822Sdim                     enum neon_type_mask mask)
10951218822Sdim{
10952218822Sdim  if ((mask & N_EQK) != 0)
10953218822Sdim    return FAIL;
1095489857Sobrien
10955218822Sdim  if ((mask & (N_S8 | N_U8 | N_I8 | N_8 | N_P8)) != 0)
10956218822Sdim    *size = 8;
10957218822Sdim  else if ((mask & (N_S16 | N_U16 | N_I16 | N_16 | N_P16)) != 0)
10958218822Sdim    *size = 16;
10959218822Sdim  else if ((mask & (N_S32 | N_U32 | N_I32 | N_32 | N_F32)) != 0)
10960218822Sdim    *size = 32;
10961218822Sdim  else if ((mask & (N_S64 | N_U64 | N_I64 | N_64 | N_F64)) != 0)
10962218822Sdim    *size = 64;
10963218822Sdim  else
10964218822Sdim    return FAIL;
1096589857Sobrien
10966218822Sdim  if ((mask & (N_S8 | N_S16 | N_S32 | N_S64)) != 0)
10967218822Sdim    *type = NT_signed;
10968218822Sdim  else if ((mask & (N_U8 | N_U16 | N_U32 | N_U64)) != 0)
10969218822Sdim    *type = NT_unsigned;
10970218822Sdim  else if ((mask & (N_I8 | N_I16 | N_I32 | N_I64)) != 0)
10971218822Sdim    *type = NT_integer;
10972218822Sdim  else if ((mask & (N_8 | N_16 | N_32 | N_64)) != 0)
10973218822Sdim    *type = NT_untyped;
10974218822Sdim  else if ((mask & (N_P8 | N_P16)) != 0)
10975218822Sdim    *type = NT_poly;
10976218822Sdim  else if ((mask & (N_F32 | N_F64)) != 0)
10977218822Sdim    *type = NT_float;
10978218822Sdim  else
10979218822Sdim    return FAIL;
10980218822Sdim
10981218822Sdim  return SUCCESS;
10982218822Sdim}
1098389857Sobrien
10984218822Sdim/* Modify a bitmask of allowed types. This is only needed for type
10985218822Sdim   relaxation.  */
1098689857Sobrien
10987218822Sdimstatic unsigned
10988218822Sdimmodify_types_allowed (unsigned allowed, unsigned mods)
10989218822Sdim{
10990218822Sdim  unsigned size;
10991218822Sdim  enum neon_el_type type;
10992218822Sdim  unsigned destmask;
10993218822Sdim  int i;
10994218822Sdim
10995218822Sdim  destmask = 0;
10996218822Sdim
10997218822Sdim  for (i = 1; i <= N_MAX_NONSPECIAL; i <<= 1)
10998218822Sdim    {
10999218822Sdim      if (el_type_of_type_chk (&type, &size, allowed & i) == SUCCESS)
11000218822Sdim        {
11001218822Sdim          neon_modify_type_size (mods, &type, &size);
11002218822Sdim          destmask |= type_chk_of_el_type (type, size);
11003218822Sdim        }
11004218822Sdim    }
11005218822Sdim
11006218822Sdim  return destmask;
11007218822Sdim}
1100889857Sobrien
11009218822Sdim/* Check type and return type classification.
11010218822Sdim   The manual states (paraphrase): If one datatype is given, it indicates the
11011218822Sdim   type given in:
11012218822Sdim    - the second operand, if there is one
11013218822Sdim    - the operand, if there is no second operand
11014218822Sdim    - the result, if there are no operands.
11015218822Sdim   This isn't quite good enough though, so we use a concept of a "key" datatype
11016218822Sdim   which is set on a per-instruction basis, which is the one which matters when
11017218822Sdim   only one data type is written.
11018218822Sdim   Note: this function has side-effects (e.g. filling in missing operands). All
11019218822Sdim   Neon instructions should call it before performing bit encoding.  */
1102089857Sobrien
11021218822Sdimstatic struct neon_type_el
11022218822Sdimneon_check_type (unsigned els, enum neon_shape ns, ...)
11023218822Sdim{
11024218822Sdim  va_list ap;
11025218822Sdim  unsigned i, pass, key_el = 0;
11026218822Sdim  unsigned types[NEON_MAX_TYPE_ELS];
11027218822Sdim  enum neon_el_type k_type = NT_invtype;
11028218822Sdim  unsigned k_size = -1u;
11029218822Sdim  struct neon_type_el badtype = {NT_invtype, -1};
11030218822Sdim  unsigned key_allowed = 0;
1103189857Sobrien
11032218822Sdim  /* Optional registers in Neon instructions are always (not) in operand 1.
11033218822Sdim     Fill in the missing operand here, if it was omitted.  */
11034218822Sdim  if (els > 1 && !inst.operands[1].present)
11035218822Sdim    inst.operands[1] = inst.operands[0];
1103689857Sobrien
11037218822Sdim  /* Suck up all the varargs.  */
11038218822Sdim  va_start (ap, ns);
11039218822Sdim  for (i = 0; i < els; i++)
11040218822Sdim    {
11041218822Sdim      unsigned thisarg = va_arg (ap, unsigned);
11042218822Sdim      if (thisarg == N_IGNORE_TYPE)
11043218822Sdim        {
11044218822Sdim          va_end (ap);
11045218822Sdim          return badtype;
11046218822Sdim        }
11047218822Sdim      types[i] = thisarg;
11048218822Sdim      if ((thisarg & N_KEY) != 0)
11049218822Sdim        key_el = i;
1105089857Sobrien    }
11051218822Sdim  va_end (ap);
1105289857Sobrien
11053218822Sdim  if (inst.vectype.elems > 0)
11054218822Sdim    for (i = 0; i < els; i++)
11055218822Sdim      if (inst.operands[i].vectype.type != NT_invtype)
11056218822Sdim        {
11057218822Sdim          first_error (_("types specified in both the mnemonic and operands"));
11058218822Sdim          return badtype;
11059218822Sdim        }
11060218822Sdim
11061218822Sdim  /* Duplicate inst.vectype elements here as necessary.
11062218822Sdim     FIXME: No idea if this is exactly the same as the ARM assembler,
11063218822Sdim     particularly when an insn takes one register and one non-register
11064218822Sdim     operand. */
11065218822Sdim  if (inst.vectype.elems == 1 && els > 1)
1106689857Sobrien    {
11067218822Sdim      unsigned j;
11068218822Sdim      inst.vectype.elems = els;
11069218822Sdim      inst.vectype.el[key_el] = inst.vectype.el[0];
11070218822Sdim      for (j = 0; j < els; j++)
11071218822Sdim        if (j != key_el)
11072218822Sdim          inst.vectype.el[j] = neon_type_promote (&inst.vectype.el[key_el],
11073218822Sdim                                                  types[j]);
1107489857Sobrien    }
11075218822Sdim  else if (inst.vectype.elems == 0 && els > 0)
11076218822Sdim    {
11077218822Sdim      unsigned j;
11078218822Sdim      /* No types were given after the mnemonic, so look for types specified
11079218822Sdim         after each operand. We allow some flexibility here; as long as the
11080218822Sdim         "key" operand has a type, we can infer the others.  */
11081218822Sdim      for (j = 0; j < els; j++)
11082218822Sdim        if (inst.operands[j].vectype.type != NT_invtype)
11083218822Sdim          inst.vectype.el[j] = inst.operands[j].vectype;
1108489857Sobrien
11085218822Sdim      if (inst.operands[key_el].vectype.type != NT_invtype)
11086218822Sdim        {
11087218822Sdim          for (j = 0; j < els; j++)
11088218822Sdim            if (inst.operands[j].vectype.type == NT_invtype)
11089218822Sdim              inst.vectype.el[j] = neon_type_promote (&inst.vectype.el[key_el],
11090218822Sdim                                                      types[j]);
11091218822Sdim        }
11092218822Sdim      else
11093218822Sdim        {
11094218822Sdim          first_error (_("operand types can't be inferred"));
11095218822Sdim          return badtype;
11096218822Sdim        }
11097218822Sdim    }
11098218822Sdim  else if (inst.vectype.elems != els)
11099218822Sdim    {
11100218822Sdim      first_error (_("type specifier has the wrong number of parts"));
11101218822Sdim      return badtype;
11102218822Sdim    }
1110389857Sobrien
11104218822Sdim  for (pass = 0; pass < 2; pass++)
11105218822Sdim    {
11106218822Sdim      for (i = 0; i < els; i++)
11107218822Sdim        {
11108218822Sdim          unsigned thisarg = types[i];
11109218822Sdim          unsigned types_allowed = ((thisarg & N_EQK) != 0 && pass != 0)
11110218822Sdim            ? modify_types_allowed (key_allowed, thisarg) : thisarg;
11111218822Sdim          enum neon_el_type g_type = inst.vectype.el[i].type;
11112218822Sdim          unsigned g_size = inst.vectype.el[i].size;
1111389857Sobrien
11114218822Sdim          /* Decay more-specific signed & unsigned types to sign-insensitive
11115218822Sdim	     integer types if sign-specific variants are unavailable.  */
11116218822Sdim          if ((g_type == NT_signed || g_type == NT_unsigned)
11117218822Sdim	      && (types_allowed & N_SU_ALL) == 0)
11118218822Sdim	    g_type = NT_integer;
1111989857Sobrien
11120218822Sdim          /* If only untyped args are allowed, decay any more specific types to
11121218822Sdim	     them. Some instructions only care about signs for some element
11122218822Sdim	     sizes, so handle that properly.  */
11123218822Sdim          if ((g_size == 8 && (types_allowed & N_8) != 0)
11124218822Sdim	      || (g_size == 16 && (types_allowed & N_16) != 0)
11125218822Sdim	      || (g_size == 32 && (types_allowed & N_32) != 0)
11126218822Sdim	      || (g_size == 64 && (types_allowed & N_64) != 0))
11127218822Sdim	    g_type = NT_untyped;
11128218822Sdim
11129218822Sdim          if (pass == 0)
11130218822Sdim            {
11131218822Sdim              if ((thisarg & N_KEY) != 0)
11132218822Sdim                {
11133218822Sdim                  k_type = g_type;
11134218822Sdim                  k_size = g_size;
11135218822Sdim                  key_allowed = thisarg & ~N_KEY;
11136218822Sdim                }
11137218822Sdim            }
11138218822Sdim          else
11139218822Sdim            {
11140218822Sdim              if ((thisarg & N_VFP) != 0)
11141218822Sdim                {
11142218822Sdim                  enum neon_shape_el regshape = neon_shape_tab[ns].el[i];
11143218822Sdim                  unsigned regwidth = neon_shape_el_size[regshape], match;
11144218822Sdim
11145218822Sdim                  /* In VFP mode, operands must match register widths. If we
11146218822Sdim                     have a key operand, use its width, else use the width of
11147218822Sdim                     the current operand.  */
11148218822Sdim                  if (k_size != -1u)
11149218822Sdim                    match = k_size;
11150218822Sdim                  else
11151218822Sdim                    match = g_size;
11152218822Sdim
11153218822Sdim                  if (regwidth != match)
11154218822Sdim                    {
11155218822Sdim                      first_error (_("operand size must match register width"));
11156218822Sdim                      return badtype;
11157218822Sdim                    }
11158218822Sdim                }
11159218822Sdim
11160218822Sdim              if ((thisarg & N_EQK) == 0)
11161218822Sdim                {
11162218822Sdim                  unsigned given_type = type_chk_of_el_type (g_type, g_size);
11163218822Sdim
11164218822Sdim                  if ((given_type & types_allowed) == 0)
11165218822Sdim                    {
11166218822Sdim	              first_error (_("bad type in Neon instruction"));
11167218822Sdim	              return badtype;
11168218822Sdim                    }
11169218822Sdim                }
11170218822Sdim              else
11171218822Sdim                {
11172218822Sdim                  enum neon_el_type mod_k_type = k_type;
11173218822Sdim                  unsigned mod_k_size = k_size;
11174218822Sdim                  neon_modify_type_size (thisarg, &mod_k_type, &mod_k_size);
11175218822Sdim                  if (g_type != mod_k_type || g_size != mod_k_size)
11176218822Sdim                    {
11177218822Sdim                      first_error (_("inconsistent types in Neon instruction"));
11178218822Sdim                      return badtype;
11179218822Sdim                    }
11180218822Sdim                }
11181218822Sdim            }
11182218822Sdim        }
1118389857Sobrien    }
1118489857Sobrien
11185218822Sdim  return inst.vectype.el[key_el];
1118689857Sobrien}
1118789857Sobrien
11188218822Sdim/* Neon-style VFP instruction forwarding.  */
11189218822Sdim
11190218822Sdim/* Thumb VFP instructions have 0xE in the condition field.  */
11191218822Sdim
1119289857Sobrienstatic void
11193218822Sdimdo_vfp_cond_or_thumb (void)
1119489857Sobrien{
11195218822Sdim  if (thumb_mode)
11196218822Sdim    inst.instruction |= 0xe0000000;
11197218822Sdim  else
11198218822Sdim    inst.instruction |= inst.cond << 28;
11199218822Sdim}
1120089857Sobrien
11201218822Sdim/* Look up and encode a simple mnemonic, for use as a helper function for the
11202218822Sdim   Neon-style VFP syntax.  This avoids duplication of bits of the insns table,
11203218822Sdim   etc.  It is assumed that operand parsing has already been done, and that the
11204218822Sdim   operands are in the form expected by the given opcode (this isn't necessarily
11205218822Sdim   the same as the form in which they were parsed, hence some massaging must
11206218822Sdim   take place before this function is called).
11207218822Sdim   Checks current arch version against that in the looked-up opcode.  */
1120889857Sobrien
11209218822Sdimstatic void
11210218822Sdimdo_vfp_nsyn_opcode (const char *opname)
11211218822Sdim{
11212218822Sdim  const struct asm_opcode *opcode;
11213218822Sdim
11214218822Sdim  opcode = hash_find (arm_ops_hsh, opname);
1121589857Sobrien
11216218822Sdim  if (!opcode)
11217218822Sdim    abort ();
1121889857Sobrien
11219218822Sdim  constraint (!ARM_CPU_HAS_FEATURE (cpu_variant,
11220218822Sdim                thumb_mode ? *opcode->tvariant : *opcode->avariant),
11221218822Sdim              _(BAD_FPU));
11222218822Sdim
11223218822Sdim  if (thumb_mode)
1122489857Sobrien    {
11225218822Sdim      inst.instruction = opcode->tvalue;
11226218822Sdim      opcode->tencode ();
1122789857Sobrien    }
11228218822Sdim  else
1122989857Sobrien    {
11230218822Sdim      inst.instruction = (inst.cond << 28) | opcode->avalue;
11231218822Sdim      opcode->aencode ();
1123289857Sobrien    }
1123389857Sobrien}
1123489857Sobrien
1123589857Sobrienstatic void
11236218822Sdimdo_vfp_nsyn_add_sub (enum neon_shape rs)
1123789857Sobrien{
11238218822Sdim  int is_add = (inst.instruction & 0x0fffffff) == N_MNEM_vadd;
1123989857Sobrien
11240218822Sdim  if (rs == NS_FFF)
11241218822Sdim    {
11242218822Sdim      if (is_add)
11243218822Sdim        do_vfp_nsyn_opcode ("fadds");
11244218822Sdim      else
11245218822Sdim        do_vfp_nsyn_opcode ("fsubs");
11246218822Sdim    }
11247218822Sdim  else
11248218822Sdim    {
11249218822Sdim      if (is_add)
11250218822Sdim        do_vfp_nsyn_opcode ("faddd");
11251218822Sdim      else
11252218822Sdim        do_vfp_nsyn_opcode ("fsubd");
11253218822Sdim    }
11254218822Sdim}
1125589857Sobrien
11256218822Sdim/* Check operand types to see if this is a VFP instruction, and if so call
11257218822Sdim   PFN ().  */
1125889857Sobrien
11259218822Sdimstatic int
11260218822Sdimtry_vfp_nsyn (int args, void (*pfn) (enum neon_shape))
11261218822Sdim{
11262218822Sdim  enum neon_shape rs;
11263218822Sdim  struct neon_type_el et;
1126489857Sobrien
11265218822Sdim  switch (args)
1126689857Sobrien    {
11267218822Sdim    case 2:
11268218822Sdim      rs = neon_select_shape (NS_FF, NS_DD, NS_NULL);
11269218822Sdim      et = neon_check_type (2, rs,
11270218822Sdim        N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
11271218822Sdim      break;
11272218822Sdim
11273218822Sdim    case 3:
11274218822Sdim      rs = neon_select_shape (NS_FFF, NS_DDD, NS_NULL);
11275218822Sdim      et = neon_check_type (3, rs,
11276218822Sdim        N_EQK | N_VFP, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
11277218822Sdim      break;
11278218822Sdim
11279218822Sdim    default:
11280218822Sdim      abort ();
1128189857Sobrien    }
1128289857Sobrien
11283218822Sdim  if (et.type != NT_invtype)
1128489857Sobrien    {
11285218822Sdim      pfn (rs);
11286218822Sdim      return SUCCESS;
1128789857Sobrien    }
11288218822Sdim  else
11289218822Sdim    inst.error = NULL;
1129089857Sobrien
11291218822Sdim  return FAIL;
1129289857Sobrien}
1129389857Sobrien
1129489857Sobrienstatic void
11295218822Sdimdo_vfp_nsyn_mla_mls (enum neon_shape rs)
1129689857Sobrien{
11297218822Sdim  int is_mla = (inst.instruction & 0x0fffffff) == N_MNEM_vmla;
11298218822Sdim
11299218822Sdim  if (rs == NS_FFF)
11300218822Sdim    {
11301218822Sdim      if (is_mla)
11302218822Sdim        do_vfp_nsyn_opcode ("fmacs");
11303218822Sdim      else
11304218822Sdim        do_vfp_nsyn_opcode ("fmscs");
11305218822Sdim    }
11306218822Sdim  else
11307218822Sdim    {
11308218822Sdim      if (is_mla)
11309218822Sdim        do_vfp_nsyn_opcode ("fmacd");
11310218822Sdim      else
11311218822Sdim        do_vfp_nsyn_opcode ("fmscd");
11312218822Sdim    }
1131389857Sobrien}
1131489857Sobrien
1131589857Sobrienstatic void
11316218822Sdimdo_vfp_nsyn_mul (enum neon_shape rs)
1131789857Sobrien{
11318218822Sdim  if (rs == NS_FFF)
11319218822Sdim    do_vfp_nsyn_opcode ("fmuls");
11320218822Sdim  else
11321218822Sdim    do_vfp_nsyn_opcode ("fmuld");
1132289857Sobrien}
1132389857Sobrien
1132489857Sobrienstatic void
11325218822Sdimdo_vfp_nsyn_abs_neg (enum neon_shape rs)
1132689857Sobrien{
11327218822Sdim  int is_neg = (inst.instruction & 0x80) != 0;
11328218822Sdim  neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_VFP | N_KEY);
11329218822Sdim
11330218822Sdim  if (rs == NS_FF)
11331218822Sdim    {
11332218822Sdim      if (is_neg)
11333218822Sdim        do_vfp_nsyn_opcode ("fnegs");
11334218822Sdim      else
11335218822Sdim        do_vfp_nsyn_opcode ("fabss");
11336218822Sdim    }
11337218822Sdim  else
11338218822Sdim    {
11339218822Sdim      if (is_neg)
11340218822Sdim        do_vfp_nsyn_opcode ("fnegd");
11341218822Sdim      else
11342218822Sdim        do_vfp_nsyn_opcode ("fabsd");
11343218822Sdim    }
1134489857Sobrien}
1134589857Sobrien
11346218822Sdim/* Encode single-precision (only!) VFP fldm/fstm instructions. Double precision
11347218822Sdim   insns belong to Neon, and are handled elsewhere.  */
11348218822Sdim
1134989857Sobrienstatic void
11350218822Sdimdo_vfp_nsyn_ldm_stm (int is_dbmode)
1135189857Sobrien{
11352218822Sdim  int is_ldm = (inst.instruction & (1 << 20)) != 0;
11353218822Sdim  if (is_ldm)
11354218822Sdim    {
11355218822Sdim      if (is_dbmode)
11356218822Sdim        do_vfp_nsyn_opcode ("fldmdbs");
11357218822Sdim      else
11358218822Sdim        do_vfp_nsyn_opcode ("fldmias");
11359218822Sdim    }
11360218822Sdim  else
11361218822Sdim    {
11362218822Sdim      if (is_dbmode)
11363218822Sdim        do_vfp_nsyn_opcode ("fstmdbs");
11364218822Sdim      else
11365218822Sdim        do_vfp_nsyn_opcode ("fstmias");
11366218822Sdim    }
1136789857Sobrien}
1136889857Sobrien
1136989857Sobrienstatic void
11370218822Sdimdo_vfp_nsyn_sqrt (void)
1137189857Sobrien{
11372218822Sdim  enum neon_shape rs = neon_select_shape (NS_FF, NS_DD, NS_NULL);
11373218822Sdim  neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
11374218822Sdim
11375218822Sdim  if (rs == NS_FF)
11376218822Sdim    do_vfp_nsyn_opcode ("fsqrts");
11377218822Sdim  else
11378218822Sdim    do_vfp_nsyn_opcode ("fsqrtd");
1137989857Sobrien}
1138089857Sobrien
1138189857Sobrienstatic void
11382218822Sdimdo_vfp_nsyn_div (void)
1138389857Sobrien{
11384218822Sdim  enum neon_shape rs = neon_select_shape (NS_FFF, NS_DDD, NS_NULL);
11385218822Sdim  neon_check_type (3, rs, N_EQK | N_VFP, N_EQK | N_VFP,
11386218822Sdim    N_F32 | N_F64 | N_KEY | N_VFP);
11387218822Sdim
11388218822Sdim  if (rs == NS_FFF)
11389218822Sdim    do_vfp_nsyn_opcode ("fdivs");
11390218822Sdim  else
11391218822Sdim    do_vfp_nsyn_opcode ("fdivd");
1139289857Sobrien}
1139389857Sobrien
1139489857Sobrienstatic void
11395218822Sdimdo_vfp_nsyn_nmul (void)
1139689857Sobrien{
11397218822Sdim  enum neon_shape rs = neon_select_shape (NS_FFF, NS_DDD, NS_NULL);
11398218822Sdim  neon_check_type (3, rs, N_EQK | N_VFP, N_EQK | N_VFP,
11399218822Sdim    N_F32 | N_F64 | N_KEY | N_VFP);
11400218822Sdim
11401218822Sdim  if (rs == NS_FFF)
1140289857Sobrien    {
11403218822Sdim      inst.instruction = NEON_ENC_SINGLE (inst.instruction);
11404218822Sdim      do_vfp_sp_dyadic ();
1140589857Sobrien    }
11406218822Sdim  else
11407218822Sdim    {
11408218822Sdim      inst.instruction = NEON_ENC_DOUBLE (inst.instruction);
11409218822Sdim      do_vfp_dp_rd_rn_rm ();
11410218822Sdim    }
11411218822Sdim  do_vfp_cond_or_thumb ();
1141289857Sobrien}
1141389857Sobrien
1141489857Sobrienstatic void
11415218822Sdimdo_vfp_nsyn_cmp (void)
1141689857Sobrien{
11417218822Sdim  if (inst.operands[1].isreg)
1141889857Sobrien    {
11419218822Sdim      enum neon_shape rs = neon_select_shape (NS_FF, NS_DD, NS_NULL);
11420218822Sdim      neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
11421218822Sdim
11422218822Sdim      if (rs == NS_FF)
11423218822Sdim        {
11424218822Sdim          inst.instruction = NEON_ENC_SINGLE (inst.instruction);
11425218822Sdim          do_vfp_sp_monadic ();
11426218822Sdim        }
11427218822Sdim      else
11428218822Sdim        {
11429218822Sdim          inst.instruction = NEON_ENC_DOUBLE (inst.instruction);
11430218822Sdim          do_vfp_dp_rd_rm ();
11431218822Sdim        }
1143289857Sobrien    }
11433218822Sdim  else
11434218822Sdim    {
11435218822Sdim      enum neon_shape rs = neon_select_shape (NS_FI, NS_DI, NS_NULL);
11436218822Sdim      neon_check_type (2, rs, N_F32 | N_F64 | N_KEY | N_VFP, N_EQK);
1143789857Sobrien
11438218822Sdim      switch (inst.instruction & 0x0fffffff)
11439218822Sdim        {
11440218822Sdim        case N_MNEM_vcmp:
11441218822Sdim          inst.instruction += N_MNEM_vcmpz - N_MNEM_vcmp;
11442218822Sdim          break;
11443218822Sdim        case N_MNEM_vcmpe:
11444218822Sdim          inst.instruction += N_MNEM_vcmpez - N_MNEM_vcmpe;
11445218822Sdim          break;
11446218822Sdim        default:
11447218822Sdim          abort ();
11448218822Sdim        }
11449218822Sdim
11450218822Sdim      if (rs == NS_FI)
11451218822Sdim        {
11452218822Sdim          inst.instruction = NEON_ENC_SINGLE (inst.instruction);
11453218822Sdim          do_vfp_sp_compare_z ();
11454218822Sdim        }
11455218822Sdim      else
11456218822Sdim        {
11457218822Sdim          inst.instruction = NEON_ENC_DOUBLE (inst.instruction);
11458218822Sdim          do_vfp_dp_rd ();
11459218822Sdim        }
11460218822Sdim    }
11461218822Sdim  do_vfp_cond_or_thumb ();
1146289857Sobrien}
1146389857Sobrien
1146489857Sobrienstatic void
11465218822Sdimnsyn_insert_sp (void)
1146689857Sobrien{
11467218822Sdim  inst.operands[1] = inst.operands[0];
11468218822Sdim  memset (&inst.operands[0], '\0', sizeof (inst.operands[0]));
11469218822Sdim  inst.operands[0].reg = 13;
11470218822Sdim  inst.operands[0].isreg = 1;
11471218822Sdim  inst.operands[0].writeback = 1;
11472218822Sdim  inst.operands[0].present = 1;
11473218822Sdim}
1147489857Sobrien
11475218822Sdimstatic void
11476218822Sdimdo_vfp_nsyn_push (void)
11477218822Sdim{
11478218822Sdim  nsyn_insert_sp ();
11479218822Sdim  if (inst.operands[1].issingle)
11480218822Sdim    do_vfp_nsyn_opcode ("fstmdbs");
11481218822Sdim  else
11482218822Sdim    do_vfp_nsyn_opcode ("fstmdbd");
1148389857Sobrien}
1148489857Sobrien
1148589857Sobrienstatic void
11486218822Sdimdo_vfp_nsyn_pop (void)
1148789857Sobrien{
11488218822Sdim  nsyn_insert_sp ();
11489218822Sdim  if (inst.operands[1].issingle)
11490218822Sdim    do_vfp_nsyn_opcode ("fldmias");
11491218822Sdim  else
11492218822Sdim    do_vfp_nsyn_opcode ("fldmiad");
11493218822Sdim}
1149489857Sobrien
11495218822Sdim/* Fix up Neon data-processing instructions, ORing in the correct bits for
11496218822Sdim   ARM mode or Thumb mode and moving the encoded bit 24 to bit 28.  */
1149789857Sobrien
11498218822Sdimstatic unsigned
11499218822Sdimneon_dp_fixup (unsigned i)
11500218822Sdim{
11501218822Sdim  if (thumb_mode)
1150289857Sobrien    {
11503218822Sdim      /* The U bit is at bit 24 by default. Move to bit 28 in Thumb mode.  */
11504218822Sdim      if (i & (1 << 24))
11505218822Sdim        i |= 1 << 28;
11506218822Sdim
11507218822Sdim      i &= ~(1 << 24);
11508218822Sdim
11509218822Sdim      i |= 0xef000000;
1151089857Sobrien    }
11511218822Sdim  else
11512218822Sdim    i |= 0xf2000000;
11513218822Sdim
11514218822Sdim  return i;
11515218822Sdim}
1151689857Sobrien
11517218822Sdim/* Turn a size (8, 16, 32, 64) into the respective bit number minus 3
11518218822Sdim   (0, 1, 2, 3).  */
11519218822Sdim
11520218822Sdimstatic unsigned
11521218822Sdimneon_logbits (unsigned x)
11522218822Sdim{
11523218822Sdim  return ffs (x) - 4;
1152489857Sobrien}
1152589857Sobrien
11526218822Sdim#define LOW4(R) ((R) & 0xf)
11527218822Sdim#define HI1(R) (((R) >> 4) & 1)
1152860484Sobrien
11529218822Sdim/* Encode insns with bit pattern:
1153077298Sobrien
11531218822Sdim  |28/24|23|22 |21 20|19 16|15 12|11    8|7|6|5|4|3  0|
11532218822Sdim  |  U  |x |D  |size | Rn  | Rd  |x x x x|N|Q|M|x| Rm |
11533218822Sdim
11534218822Sdim  SIZE is passed in bits. -1 means size field isn't changed, in case it has a
11535218822Sdim  different meaning for some instruction.  */
11536218822Sdim
11537218822Sdimstatic void
11538218822Sdimneon_three_same (int isquad, int ubit, int size)
1153960484Sobrien{
11540218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
11541218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
11542218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
11543218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
11544218822Sdim  inst.instruction |= LOW4 (inst.operands[2].reg);
11545218822Sdim  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
11546218822Sdim  inst.instruction |= (isquad != 0) << 6;
11547218822Sdim  inst.instruction |= (ubit != 0) << 24;
11548218822Sdim  if (size != -1)
11549218822Sdim    inst.instruction |= neon_logbits (size) << 20;
11550218822Sdim
11551218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
11552218822Sdim}
1155360484Sobrien
11554218822Sdim/* Encode instructions of the form:
1155560484Sobrien
11556218822Sdim  |28/24|23|22|21 20|19 18|17 16|15 12|11      7|6|5|4|3  0|
11557218822Sdim  |  U  |x |D |x  x |size |x  x | Rd  |x x x x x|Q|M|x| Rm |
1155860484Sobrien
11559218822Sdim  Don't write size if SIZE == -1.  */
1156060484Sobrien
11561218822Sdimstatic void
11562218822Sdimneon_two_same (int qbit, int ubit, int size)
11563218822Sdim{
11564218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
11565218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
11566218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg);
11567218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 5;
11568218822Sdim  inst.instruction |= (qbit != 0) << 6;
11569218822Sdim  inst.instruction |= (ubit != 0) << 24;
1157060484Sobrien
11571218822Sdim  if (size != -1)
11572218822Sdim    inst.instruction |= neon_logbits (size) << 18;
11573218822Sdim
11574218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1157560484Sobrien}
1157660484Sobrien
11577218822Sdim/* Neon instruction encoders, in approximate order of appearance.  */
1157877298Sobrien
1157960484Sobrienstatic void
11580218822Sdimdo_neon_dyadic_i_su (void)
1158160484Sobrien{
11582218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11583218822Sdim  struct neon_type_el et = neon_check_type (3, rs,
11584218822Sdim    N_EQK, N_EQK, N_SU_32 | N_KEY);
11585218822Sdim  neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
11586218822Sdim}
1158760484Sobrien
11588218822Sdimstatic void
11589218822Sdimdo_neon_dyadic_i64_su (void)
11590218822Sdim{
11591218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11592218822Sdim  struct neon_type_el et = neon_check_type (3, rs,
11593218822Sdim    N_EQK, N_EQK, N_SU_ALL | N_KEY);
11594218822Sdim  neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
11595218822Sdim}
1159660484Sobrien
11597218822Sdimstatic void
11598218822Sdimneon_imm_shift (int write_ubit, int uval, int isquad, struct neon_type_el et,
11599218822Sdim                unsigned immbits)
11600218822Sdim{
11601218822Sdim  unsigned size = et.size >> 3;
11602218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
11603218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
11604218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg);
11605218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 5;
11606218822Sdim  inst.instruction |= (isquad != 0) << 6;
11607218822Sdim  inst.instruction |= immbits << 16;
11608218822Sdim  inst.instruction |= (size >> 3) << 7;
11609218822Sdim  inst.instruction |= (size & 0x7) << 19;
11610218822Sdim  if (write_ubit)
11611218822Sdim    inst.instruction |= (uval != 0) << 24;
11612218822Sdim
11613218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
11614218822Sdim}
11615218822Sdim
11616218822Sdimstatic void
11617218822Sdimdo_neon_shl_imm (void)
11618218822Sdim{
11619218822Sdim  if (!inst.operands[2].isreg)
1162060484Sobrien    {
11621218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
11622218822Sdim      struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_KEY | N_I_ALL);
11623218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
11624218822Sdim      neon_imm_shift (FALSE, 0, neon_quad (rs), et, inst.operands[2].imm);
1162560484Sobrien    }
11626218822Sdim  else
11627218822Sdim    {
11628218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11629218822Sdim      struct neon_type_el et = neon_check_type (3, rs,
11630218822Sdim        N_EQK, N_SU_ALL | N_KEY, N_EQK | N_SGN);
11631218822Sdim      unsigned int tmp;
1163260484Sobrien
11633218822Sdim      /* VSHL/VQSHL 3-register variants have syntax such as:
11634218822Sdim           vshl.xx Dd, Dm, Dn
11635218822Sdim         whereas other 3-register operations encoded by neon_three_same have
11636218822Sdim         syntax like:
11637218822Sdim           vadd.xx Dd, Dn, Dm
11638218822Sdim         (i.e. with Dn & Dm reversed). Swap operands[1].reg and operands[2].reg
11639218822Sdim         here.  */
11640218822Sdim      tmp = inst.operands[2].reg;
11641218822Sdim      inst.operands[2].reg = inst.operands[1].reg;
11642218822Sdim      inst.operands[1].reg = tmp;
11643218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
11644218822Sdim      neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
11645218822Sdim    }
11646218822Sdim}
11647218822Sdim
11648218822Sdimstatic void
11649218822Sdimdo_neon_qshl_imm (void)
11650218822Sdim{
11651218822Sdim  if (!inst.operands[2].isreg)
1165260484Sobrien    {
11653218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
11654218822Sdim      struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_SU_ALL | N_KEY);
11655218822Sdim
11656218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
11657218822Sdim      neon_imm_shift (TRUE, et.type == NT_unsigned, neon_quad (rs), et,
11658218822Sdim                      inst.operands[2].imm);
1165960484Sobrien    }
1166060484Sobrien  else
1166160484Sobrien    {
11662218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11663218822Sdim      struct neon_type_el et = neon_check_type (3, rs,
11664218822Sdim        N_EQK, N_SU_ALL | N_KEY, N_EQK | N_SGN);
11665218822Sdim      unsigned int tmp;
1166660484Sobrien
11667218822Sdim      /* See note in do_neon_shl_imm.  */
11668218822Sdim      tmp = inst.operands[2].reg;
11669218822Sdim      inst.operands[2].reg = inst.operands[1].reg;
11670218822Sdim      inst.operands[1].reg = tmp;
11671218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
11672218822Sdim      neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
11673218822Sdim    }
11674218822Sdim}
11675218822Sdim
11676218822Sdimstatic void
11677218822Sdimdo_neon_rshl (void)
11678218822Sdim{
11679218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11680218822Sdim  struct neon_type_el et = neon_check_type (3, rs,
11681218822Sdim    N_EQK, N_EQK, N_SU_ALL | N_KEY);
11682218822Sdim  unsigned int tmp;
11683218822Sdim
11684218822Sdim  tmp = inst.operands[2].reg;
11685218822Sdim  inst.operands[2].reg = inst.operands[1].reg;
11686218822Sdim  inst.operands[1].reg = tmp;
11687218822Sdim  neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
11688218822Sdim}
11689218822Sdim
11690218822Sdimstatic int
11691218822Sdimneon_cmode_for_logic_imm (unsigned immediate, unsigned *immbits, int size)
11692218822Sdim{
11693218822Sdim  /* Handle .I8 pseudo-instructions.  */
11694218822Sdim  if (size == 8)
11695218822Sdim    {
11696218822Sdim      /* Unfortunately, this will make everything apart from zero out-of-range.
11697218822Sdim         FIXME is this the intended semantics? There doesn't seem much point in
11698218822Sdim         accepting .I8 if so.  */
11699218822Sdim      immediate |= immediate << 8;
11700218822Sdim      size = 16;
11701218822Sdim    }
11702218822Sdim
11703218822Sdim  if (size >= 32)
11704218822Sdim    {
11705218822Sdim      if (immediate == (immediate & 0x000000ff))
1170660484Sobrien	{
11707218822Sdim	  *immbits = immediate;
11708218822Sdim	  return 0x1;
1170960484Sobrien	}
11710218822Sdim      else if (immediate == (immediate & 0x0000ff00))
1171160484Sobrien	{
11712218822Sdim	  *immbits = immediate >> 8;
11713218822Sdim	  return 0x3;
1171460484Sobrien	}
11715218822Sdim      else if (immediate == (immediate & 0x00ff0000))
1171660484Sobrien	{
11717218822Sdim	  *immbits = immediate >> 16;
11718218822Sdim	  return 0x5;
1171960484Sobrien	}
11720218822Sdim      else if (immediate == (immediate & 0xff000000))
1172160484Sobrien	{
11722218822Sdim	  *immbits = immediate >> 24;
11723218822Sdim	  return 0x7;
1172460484Sobrien	}
11725218822Sdim      if ((immediate & 0xffff) != (immediate >> 16))
11726218822Sdim	goto bad_immediate;
11727218822Sdim      immediate &= 0xffff;
1172860484Sobrien    }
11729218822Sdim
11730218822Sdim  if (immediate == (immediate & 0x000000ff))
1173160484Sobrien    {
11732218822Sdim      *immbits = immediate;
11733218822Sdim      return 0x9;
11734218822Sdim    }
11735218822Sdim  else if (immediate == (immediate & 0x0000ff00))
11736218822Sdim    {
11737218822Sdim      *immbits = immediate >> 8;
11738218822Sdim      return 0xb;
11739218822Sdim    }
1174060484Sobrien
11741218822Sdim  bad_immediate:
11742218822Sdim  first_error (_("immediate value out of range"));
11743218822Sdim  return FAIL;
11744218822Sdim}
1174560484Sobrien
11746218822Sdim/* True if IMM has form 0bAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD for bits
11747218822Sdim   A, B, C, D.  */
1174860484Sobrien
11749218822Sdimstatic int
11750218822Sdimneon_bits_same_in_bytes (unsigned imm)
11751218822Sdim{
11752218822Sdim  return ((imm & 0x000000ff) == 0 || (imm & 0x000000ff) == 0x000000ff)
11753218822Sdim         && ((imm & 0x0000ff00) == 0 || (imm & 0x0000ff00) == 0x0000ff00)
11754218822Sdim         && ((imm & 0x00ff0000) == 0 || (imm & 0x00ff0000) == 0x00ff0000)
11755218822Sdim         && ((imm & 0xff000000) == 0 || (imm & 0xff000000) == 0xff000000);
11756218822Sdim}
1175760484Sobrien
11758218822Sdim/* For immediate of above form, return 0bABCD.  */
1175960484Sobrien
11760218822Sdimstatic unsigned
11761218822Sdimneon_squash_bits (unsigned imm)
11762218822Sdim{
11763218822Sdim  return (imm & 0x01) | ((imm & 0x0100) >> 7) | ((imm & 0x010000) >> 14)
11764218822Sdim         | ((imm & 0x01000000) >> 21);
11765218822Sdim}
1176660484Sobrien
11767218822Sdim/* Compress quarter-float representation to 0b...000 abcdefgh.  */
1176877298Sobrien
11769218822Sdimstatic unsigned
11770218822Sdimneon_qfloat_bits (unsigned imm)
11771218822Sdim{
11772218822Sdim  return ((imm >> 19) & 0x7f) | ((imm >> 24) & 0x80);
1177360484Sobrien}
1177460484Sobrien
11775218822Sdim/* Returns CMODE. IMMBITS [7:0] is set to bits suitable for inserting into
11776218822Sdim   the instruction. *OP is passed as the initial value of the op field, and
11777218822Sdim   may be set to a different value depending on the constant (i.e.
11778218822Sdim   "MOV I64, 0bAAAAAAAABBBB..." which uses OP = 1 despite being MOV not
11779218822Sdim   MVN).  If the immediate looks like a repeated parttern then also
11780218822Sdim   try smaller element sizes.  */
11781218822Sdim
11782218822Sdimstatic int
11783218822Sdimneon_cmode_for_move_imm (unsigned immlo, unsigned immhi, int float_p,
11784218822Sdim			 unsigned *immbits, int *op, int size,
11785218822Sdim			 enum neon_el_type type)
1178660484Sobrien{
11787218822Sdim  /* Only permit float immediates (including 0.0/-0.0) if the operand type is
11788218822Sdim     float.  */
11789218822Sdim  if (type == NT_float && !float_p)
11790218822Sdim    return FAIL;
1179160484Sobrien
11792218822Sdim  if (type == NT_float && is_quarter_float (immlo) && immhi == 0)
1179360484Sobrien    {
11794218822Sdim      if (size != 32 || *op == 1)
11795218822Sdim        return FAIL;
11796218822Sdim      *immbits = neon_qfloat_bits (immlo);
11797218822Sdim      return 0xf;
1179860484Sobrien    }
1179960484Sobrien
11800218822Sdim  if (size == 64)
1180160484Sobrien    {
11802218822Sdim      if (neon_bits_same_in_bytes (immhi)
11803218822Sdim	  && neon_bits_same_in_bytes (immlo))
11804218822Sdim	{
11805218822Sdim	  if (*op == 1)
11806218822Sdim	    return FAIL;
11807218822Sdim	  *immbits = (neon_squash_bits (immhi) << 4)
11808218822Sdim		     | neon_squash_bits (immlo);
11809218822Sdim	  *op = 1;
11810218822Sdim	  return 0xe;
11811218822Sdim	}
11812218822Sdim
11813218822Sdim      if (immhi != immlo)
11814218822Sdim	return FAIL;
1181560484Sobrien    }
11816218822Sdim
11817218822Sdim  if (size >= 32)
1181860484Sobrien    {
11819218822Sdim      if (immlo == (immlo & 0x000000ff))
1182060484Sobrien	{
11821218822Sdim	  *immbits = immlo;
11822218822Sdim	  return 0x0;
1182360484Sobrien	}
11824218822Sdim      else if (immlo == (immlo & 0x0000ff00))
1182560484Sobrien	{
11826218822Sdim	  *immbits = immlo >> 8;
11827218822Sdim	  return 0x2;
1182860484Sobrien	}
11829218822Sdim      else if (immlo == (immlo & 0x00ff0000))
1183060484Sobrien	{
11831218822Sdim	  *immbits = immlo >> 16;
11832218822Sdim	  return 0x4;
1183360484Sobrien	}
11834218822Sdim      else if (immlo == (immlo & 0xff000000))
1183560484Sobrien	{
11836218822Sdim	  *immbits = immlo >> 24;
11837218822Sdim	  return 0x6;
1183860484Sobrien	}
11839218822Sdim      else if (immlo == ((immlo & 0x0000ff00) | 0x000000ff))
11840218822Sdim	{
11841218822Sdim	  *immbits = (immlo >> 8) & 0xff;
11842218822Sdim	  return 0xc;
11843218822Sdim	}
11844218822Sdim      else if (immlo == ((immlo & 0x00ff0000) | 0x0000ffff))
11845218822Sdim	{
11846218822Sdim	  *immbits = (immlo >> 16) & 0xff;
11847218822Sdim	  return 0xd;
11848218822Sdim	}
1184960484Sobrien
11850218822Sdim      if ((immlo & 0xffff) != (immlo >> 16))
11851218822Sdim	return FAIL;
11852218822Sdim      immlo &= 0xffff;
1185360484Sobrien    }
11854218822Sdim
11855218822Sdim  if (size >= 16)
1185660484Sobrien    {
11857218822Sdim      if (immlo == (immlo & 0x000000ff))
1185860484Sobrien	{
11859218822Sdim	  *immbits = immlo;
11860218822Sdim	  return 0x8;
1186160484Sobrien	}
11862218822Sdim      else if (immlo == (immlo & 0x0000ff00))
1186360484Sobrien	{
11864218822Sdim	  *immbits = immlo >> 8;
11865218822Sdim	  return 0xa;
1186660484Sobrien	}
1186760484Sobrien
11868218822Sdim      if ((immlo & 0xff) != (immlo >> 8))
11869218822Sdim	return FAIL;
11870218822Sdim      immlo &= 0xff;
11871218822Sdim    }
1187260484Sobrien
11873218822Sdim  if (immlo == (immlo & 0x000000ff))
11874218822Sdim    {
11875218822Sdim      /* Don't allow MVN with 8-bit immediate.  */
11876218822Sdim      if (*op == 1)
11877218822Sdim	return FAIL;
11878218822Sdim      *immbits = immlo;
11879218822Sdim      return 0xe;
11880218822Sdim    }
1188160484Sobrien
11882218822Sdim  return FAIL;
11883218822Sdim}
1188460484Sobrien
11885218822Sdim/* Write immediate bits [7:0] to the following locations:
1188660484Sobrien
11887218822Sdim  |28/24|23     19|18 16|15                    4|3     0|
11888218822Sdim  |  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|
1188977298Sobrien
11890218822Sdim  This function is used by VMOV/VMVN/VORR/VBIC.  */
1189160484Sobrien
1189260484Sobrienstatic void
11893218822Sdimneon_write_immbits (unsigned immbits)
1189460484Sobrien{
11895218822Sdim  inst.instruction |= immbits & 0xf;
11896218822Sdim  inst.instruction |= ((immbits >> 4) & 0x7) << 16;
11897218822Sdim  inst.instruction |= ((immbits >> 7) & 0x1) << 24;
11898218822Sdim}
1189960484Sobrien
11900218822Sdim/* Invert low-order SIZE bits of XHI:XLO.  */
1190160484Sobrien
11902218822Sdimstatic void
11903218822Sdimneon_invert_size (unsigned *xlo, unsigned *xhi, int size)
11904218822Sdim{
11905218822Sdim  unsigned immlo = xlo ? *xlo : 0;
11906218822Sdim  unsigned immhi = xhi ? *xhi : 0;
1190760484Sobrien
11908218822Sdim  switch (size)
1190960484Sobrien    {
11910218822Sdim    case 8:
11911218822Sdim      immlo = (~immlo) & 0xff;
11912218822Sdim      break;
1191360484Sobrien
11914218822Sdim    case 16:
11915218822Sdim      immlo = (~immlo) & 0xffff;
11916218822Sdim      break;
1191760484Sobrien
11918218822Sdim    case 64:
11919218822Sdim      immhi = (~immhi) & 0xffffffff;
11920218822Sdim      /* fall through.  */
1192160484Sobrien
11922218822Sdim    case 32:
11923218822Sdim      immlo = (~immlo) & 0xffffffff;
11924218822Sdim      break;
1192560484Sobrien
11926218822Sdim    default:
11927218822Sdim      abort ();
1192860484Sobrien    }
11929218822Sdim
11930218822Sdim  if (xlo)
11931218822Sdim    *xlo = immlo;
11932218822Sdim
11933218822Sdim  if (xhi)
11934218822Sdim    *xhi = immhi;
11935218822Sdim}
11936218822Sdim
11937218822Sdimstatic void
11938218822Sdimdo_neon_logic (void)
11939218822Sdim{
11940218822Sdim  if (inst.operands[2].present && inst.operands[2].isreg)
11941218822Sdim    {
11942218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11943218822Sdim      neon_check_type (3, rs, N_IGNORE_TYPE);
11944218822Sdim      /* U bit and size field were set as part of the bitmask.  */
11945218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
11946218822Sdim      neon_three_same (neon_quad (rs), 0, -1);
11947218822Sdim    }
1194860484Sobrien  else
1194960484Sobrien    {
11950218822Sdim      enum neon_shape rs = neon_select_shape (NS_DI, NS_QI, NS_NULL);
11951218822Sdim      struct neon_type_el et = neon_check_type (2, rs,
11952218822Sdim        N_I8 | N_I16 | N_I32 | N_I64 | N_F32 | N_KEY, N_EQK);
11953218822Sdim      enum neon_opc opcode = inst.instruction & 0x0fffffff;
11954218822Sdim      unsigned immbits;
11955218822Sdim      int cmode;
11956218822Sdim
11957218822Sdim      if (et.type == NT_invtype)
11958218822Sdim        return;
11959218822Sdim
11960218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
11961218822Sdim
11962218822Sdim      immbits = inst.operands[1].imm;
11963218822Sdim      if (et.size == 64)
1196460484Sobrien	{
11965218822Sdim	  /* .i64 is a pseudo-op, so the immediate must be a repeating
11966218822Sdim	     pattern.  */
11967218822Sdim	  if (immbits != (inst.operands[1].regisimm ?
11968218822Sdim			  inst.operands[1].reg : 0))
11969218822Sdim	    {
11970218822Sdim	      /* Set immbits to an invalid constant.  */
11971218822Sdim	      immbits = 0xdeadbeef;
11972218822Sdim	    }
1197360484Sobrien	}
1197460484Sobrien
11975218822Sdim      switch (opcode)
11976218822Sdim        {
11977218822Sdim        case N_MNEM_vbic:
11978218822Sdim          cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
11979218822Sdim          break;
11980218822Sdim
11981218822Sdim        case N_MNEM_vorr:
11982218822Sdim          cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
11983218822Sdim          break;
11984218822Sdim
11985218822Sdim        case N_MNEM_vand:
11986218822Sdim          /* Pseudo-instruction for VBIC.  */
11987218822Sdim          neon_invert_size (&immbits, 0, et.size);
11988218822Sdim          cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
11989218822Sdim          break;
11990218822Sdim
11991218822Sdim        case N_MNEM_vorn:
11992218822Sdim          /* Pseudo-instruction for VORR.  */
11993218822Sdim          neon_invert_size (&immbits, 0, et.size);
11994218822Sdim          cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
11995218822Sdim          break;
11996218822Sdim
11997218822Sdim        default:
11998218822Sdim          abort ();
11999218822Sdim        }
1200060484Sobrien
12001218822Sdim      if (cmode == FAIL)
12002218822Sdim        return;
1200360484Sobrien
12004218822Sdim      inst.instruction |= neon_quad (rs) << 6;
12005218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12006218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12007218822Sdim      inst.instruction |= cmode << 8;
12008218822Sdim      neon_write_immbits (immbits);
12009218822Sdim
12010218822Sdim      inst.instruction = neon_dp_fixup (inst.instruction);
1201160484Sobrien    }
12012218822Sdim}
1201360484Sobrien
12014218822Sdimstatic void
12015218822Sdimdo_neon_bitfield (void)
12016218822Sdim{
12017218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
12018218822Sdim  neon_check_type (3, rs, N_IGNORE_TYPE);
12019218822Sdim  neon_three_same (neon_quad (rs), 0, -1);
1202060484Sobrien}
1202160484Sobrien
1202260484Sobrienstatic void
12023218822Sdimneon_dyadic_misc (enum neon_el_type ubit_meaning, unsigned types,
12024218822Sdim                  unsigned destbits)
1202560484Sobrien{
12026218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
12027218822Sdim  struct neon_type_el et = neon_check_type (3, rs, N_EQK | destbits, N_EQK,
12028218822Sdim                                            types | N_KEY);
12029218822Sdim  if (et.type == NT_float)
1203060484Sobrien    {
12031218822Sdim      inst.instruction = NEON_ENC_FLOAT (inst.instruction);
12032218822Sdim      neon_three_same (neon_quad (rs), 0, -1);
1203360484Sobrien    }
12034218822Sdim  else
1203560484Sobrien    {
12036218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12037218822Sdim      neon_three_same (neon_quad (rs), et.type == ubit_meaning, et.size);
1203860484Sobrien    }
12039218822Sdim}
1204089857Sobrien
12041218822Sdimstatic void
12042218822Sdimdo_neon_dyadic_if_su (void)
12043218822Sdim{
12044218822Sdim  neon_dyadic_misc (NT_unsigned, N_SUF_32, 0);
12045218822Sdim}
1204660484Sobrien
12047218822Sdimstatic void
12048218822Sdimdo_neon_dyadic_if_su_d (void)
12049218822Sdim{
12050218822Sdim  /* This version only allow D registers, but that constraint is enforced during
12051218822Sdim     operand parsing so we don't need to do anything extra here.  */
12052218822Sdim  neon_dyadic_misc (NT_unsigned, N_SUF_32, 0);
12053218822Sdim}
1205460484Sobrien
12055218822Sdimstatic void
12056218822Sdimdo_neon_dyadic_if_i_d (void)
12057218822Sdim{
12058218822Sdim  /* The "untyped" case can't happen. Do this to stop the "U" bit being
12059218822Sdim     affected if we specify unsigned args.  */
12060218822Sdim  neon_dyadic_misc (NT_untyped, N_IF_32, 0);
12061218822Sdim}
1206260484Sobrien
12063218822Sdimenum vfp_or_neon_is_neon_bits
12064218822Sdim{
12065218822Sdim  NEON_CHECK_CC = 1,
12066218822Sdim  NEON_CHECK_ARCH = 2
12067218822Sdim};
1206877298Sobrien
12069218822Sdim/* Call this function if an instruction which may have belonged to the VFP or
12070218822Sdim   Neon instruction sets, but turned out to be a Neon instruction (due to the
12071218822Sdim   operand types involved, etc.). We have to check and/or fix-up a couple of
12072218822Sdim   things:
1207360484Sobrien
12074218822Sdim     - Make sure the user hasn't attempted to make a Neon instruction
12075218822Sdim       conditional.
12076218822Sdim     - Alter the value in the condition code field if necessary.
12077218822Sdim     - Make sure that the arch supports Neon instructions.
1207860484Sobrien
12079218822Sdim   Which of these operations take place depends on bits from enum
12080218822Sdim   vfp_or_neon_is_neon_bits.
1208160484Sobrien
12082218822Sdim   WARNING: This function has side effects! If NEON_CHECK_CC is used and the
12083218822Sdim   current instruction's condition is COND_ALWAYS, the condition field is
12084218822Sdim   changed to inst.uncond_value. This is necessary because instructions shared
12085218822Sdim   between VFP and Neon may be conditional for the VFP variants only, and the
12086218822Sdim   unconditional Neon version must have, e.g., 0xF in the condition field.  */
1208760484Sobrien
12088218822Sdimstatic int
12089218822Sdimvfp_or_neon_is_neon (unsigned check)
12090218822Sdim{
12091218822Sdim  /* Conditions are always legal in Thumb mode (IT blocks).  */
12092218822Sdim  if (!thumb_mode && (check & NEON_CHECK_CC))
12093218822Sdim    {
12094218822Sdim      if (inst.cond != COND_ALWAYS)
12095218822Sdim        {
12096218822Sdim          first_error (_(BAD_COND));
12097218822Sdim          return FAIL;
12098218822Sdim        }
12099218822Sdim      if (inst.uncond_value != -1)
12100218822Sdim        inst.instruction |= inst.uncond_value << 28;
1210160484Sobrien    }
12102218822Sdim
12103218822Sdim  if ((check & NEON_CHECK_ARCH)
12104218822Sdim      && !ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1))
1210560484Sobrien    {
12106218822Sdim      first_error (_(BAD_FPU));
12107218822Sdim      return FAIL;
1210860484Sobrien    }
12109218822Sdim
12110218822Sdim  return SUCCESS;
12111218822Sdim}
1211260484Sobrien
12113218822Sdimstatic void
12114218822Sdimdo_neon_addsub_if_i (void)
12115218822Sdim{
12116218822Sdim  if (try_vfp_nsyn (3, do_vfp_nsyn_add_sub) == SUCCESS)
12117218822Sdim    return;
1211860484Sobrien
12119218822Sdim  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12120218822Sdim    return;
1212160484Sobrien
12122218822Sdim  /* The "untyped" case can't happen. Do this to stop the "U" bit being
12123218822Sdim     affected if we specify unsigned args.  */
12124218822Sdim  neon_dyadic_misc (NT_untyped, N_IF_32 | N_I64, 0);
12125218822Sdim}
1212660484Sobrien
12127218822Sdim/* Swaps operands 1 and 2. If operand 1 (optional arg) was omitted, we want the
12128218822Sdim   result to be:
12129218822Sdim     V<op> A,B     (A is operand 0, B is operand 2)
12130218822Sdim   to mean:
12131218822Sdim     V<op> A,B,A
12132218822Sdim   not:
12133218822Sdim     V<op> A,B,B
12134218822Sdim   so handle that case specially.  */
1213560484Sobrien
12136218822Sdimstatic void
12137218822Sdimneon_exchange_operands (void)
12138218822Sdim{
12139218822Sdim  void *scratch = alloca (sizeof (inst.operands[0]));
12140218822Sdim  if (inst.operands[1].present)
12141218822Sdim    {
12142218822Sdim      /* Swap operands[1] and operands[2].  */
12143218822Sdim      memcpy (scratch, &inst.operands[1], sizeof (inst.operands[0]));
12144218822Sdim      inst.operands[1] = inst.operands[2];
12145218822Sdim      memcpy (&inst.operands[2], scratch, sizeof (inst.operands[0]));
1214660484Sobrien    }
12147218822Sdim  else
1214860484Sobrien    {
12149218822Sdim      inst.operands[1] = inst.operands[2];
12150218822Sdim      inst.operands[2] = inst.operands[0];
1215160484Sobrien    }
12152218822Sdim}
12153218822Sdim
12154218822Sdimstatic void
12155218822Sdimneon_compare (unsigned regtypes, unsigned immtypes, int invert)
12156218822Sdim{
12157218822Sdim  if (inst.operands[2].isreg)
1215860484Sobrien    {
12159218822Sdim      if (invert)
12160218822Sdim        neon_exchange_operands ();
12161218822Sdim      neon_dyadic_misc (NT_unsigned, regtypes, N_SIZ);
1216260484Sobrien    }
1216360484Sobrien  else
1216460484Sobrien    {
12165218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
12166218822Sdim      struct neon_type_el et = neon_check_type (2, rs,
12167218822Sdim        N_EQK | N_SIZ, immtypes | N_KEY);
1216860484Sobrien
12169218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
12170218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12171218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12172218822Sdim      inst.instruction |= LOW4 (inst.operands[1].reg);
12173218822Sdim      inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12174218822Sdim      inst.instruction |= neon_quad (rs) << 6;
12175218822Sdim      inst.instruction |= (et.type == NT_float) << 10;
12176218822Sdim      inst.instruction |= neon_logbits (et.size) << 18;
12177218822Sdim
12178218822Sdim      inst.instruction = neon_dp_fixup (inst.instruction);
1217960484Sobrien    }
12180218822Sdim}
1218160484Sobrien
12182218822Sdimstatic void
12183218822Sdimdo_neon_cmp (void)
12184218822Sdim{
12185218822Sdim  neon_compare (N_SUF_32, N_S8 | N_S16 | N_S32 | N_F32, FALSE);
1218660484Sobrien}
1218760484Sobrien
12188218822Sdimstatic void
12189218822Sdimdo_neon_cmp_inv (void)
12190218822Sdim{
12191218822Sdim  neon_compare (N_SUF_32, N_S8 | N_S16 | N_S32 | N_F32, TRUE);
12192218822Sdim}
1219389857Sobrien
12194218822Sdimstatic void
12195218822Sdimdo_neon_ceq (void)
12196218822Sdim{
12197218822Sdim  neon_compare (N_IF_32, N_IF_32, FALSE);
12198218822Sdim}
1219989857Sobrien
12200218822Sdim/* For multiply instructions, we have the possibility of 16-bit or 32-bit
12201218822Sdim   scalars, which are encoded in 5 bits, M : Rm.
12202218822Sdim   For 16-bit scalars, the register is encoded in Rm[2:0] and the index in
12203218822Sdim   M:Rm[3], and for 32-bit scalars, the register is encoded in Rm[3:0] and the
12204218822Sdim   index in M.  */
1220589857Sobrien
12206218822Sdimstatic unsigned
12207218822Sdimneon_scalar_for_mul (unsigned scalar, unsigned elsize)
1220889857Sobrien{
12209218822Sdim  unsigned regno = NEON_SCALAR_REG (scalar);
12210218822Sdim  unsigned elno = NEON_SCALAR_INDEX (scalar);
1221189857Sobrien
12212218822Sdim  switch (elsize)
1221389857Sobrien    {
12214218822Sdim    case 16:
12215218822Sdim      if (regno > 7 || elno > 3)
12216218822Sdim        goto bad_scalar;
12217218822Sdim      return regno | (elno << 3);
12218218822Sdim
12219218822Sdim    case 32:
12220218822Sdim      if (regno > 15 || elno > 1)
12221218822Sdim        goto bad_scalar;
12222218822Sdim      return regno | (elno << 4);
1222389857Sobrien
12224218822Sdim    default:
12225218822Sdim    bad_scalar:
12226218822Sdim      first_error (_("scalar out of range for multiply instruction"));
1222789857Sobrien    }
1222889857Sobrien
12229218822Sdim  return 0;
12230218822Sdim}
1223199461Sobrien
12232218822Sdim/* Encode multiply / multiply-accumulate scalar instructions.  */
12233104834Sobrien
12234218822Sdimstatic void
12235218822Sdimneon_mul_mac (struct neon_type_el et, int ubit)
12236218822Sdim{
12237218822Sdim  unsigned scalar;
12238218822Sdim
12239218822Sdim  /* Give a more helpful error message if we have an invalid type.  */
12240218822Sdim  if (et.type == NT_invtype)
12241218822Sdim    return;
12242218822Sdim
12243218822Sdim  scalar = neon_scalar_for_mul (inst.operands[2].reg, et.size);
12244218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12245218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12246218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
12247218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
12248218822Sdim  inst.instruction |= LOW4 (scalar);
12249218822Sdim  inst.instruction |= HI1 (scalar) << 5;
12250218822Sdim  inst.instruction |= (et.type == NT_float) << 8;
12251218822Sdim  inst.instruction |= neon_logbits (et.size) << 20;
12252218822Sdim  inst.instruction |= (ubit != 0) << 24;
12253218822Sdim
12254218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1225589857Sobrien}
1225689857Sobrien
12257218822Sdimstatic void
12258218822Sdimdo_neon_mac_maybe_scalar (void)
12259218822Sdim{
12260218822Sdim  if (try_vfp_nsyn (3, do_vfp_nsyn_mla_mls) == SUCCESS)
12261218822Sdim    return;
1226289857Sobrien
12263218822Sdim  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12264218822Sdim    return;
1226589857Sobrien
12266218822Sdim  if (inst.operands[2].isscalar)
12267218822Sdim    {
12268218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDS, NS_QQS, NS_NULL);
12269218822Sdim      struct neon_type_el et = neon_check_type (3, rs,
12270218822Sdim        N_EQK, N_EQK, N_I16 | N_I32 | N_F32 | N_KEY);
12271218822Sdim      inst.instruction = NEON_ENC_SCALAR (inst.instruction);
12272218822Sdim      neon_mul_mac (et, neon_quad (rs));
12273218822Sdim    }
12274218822Sdim  else
12275218822Sdim    {
12276218822Sdim      /* The "untyped" case can't happen.  Do this to stop the "U" bit being
12277218822Sdim	 affected if we specify unsigned args.  */
12278218822Sdim      neon_dyadic_misc (NT_untyped, N_IF_32, 0);
12279218822Sdim    }
12280218822Sdim}
12281218822Sdim
1228260484Sobrienstatic void
12283218822Sdimdo_neon_tst (void)
1228489857Sobrien{
12285218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
12286218822Sdim  struct neon_type_el et = neon_check_type (3, rs,
12287218822Sdim    N_EQK, N_EQK, N_8 | N_16 | N_32 | N_KEY);
12288218822Sdim  neon_three_same (neon_quad (rs), 0, et.size);
1228989857Sobrien}
1229089857Sobrien
12291218822Sdim/* VMUL with 3 registers allows the P8 type. The scalar version supports the
12292218822Sdim   same types as the MAC equivalents. The polynomial type for this instruction
12293218822Sdim   is encoded the same as the integer type.  */
12294218822Sdim
1229589857Sobrienstatic void
12296218822Sdimdo_neon_mul (void)
1229789857Sobrien{
12298218822Sdim  if (try_vfp_nsyn (3, do_vfp_nsyn_mul) == SUCCESS)
12299218822Sdim    return;
12300218822Sdim
12301218822Sdim  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12302218822Sdim    return;
12303218822Sdim
12304218822Sdim  if (inst.operands[2].isscalar)
12305218822Sdim    do_neon_mac_maybe_scalar ();
12306218822Sdim  else
12307218822Sdim    neon_dyadic_misc (NT_poly, N_I8 | N_I16 | N_I32 | N_F32 | N_P8, 0);
1230889857Sobrien}
1230989857Sobrien
1231089857Sobrienstatic void
12311218822Sdimdo_neon_qdmulh (void)
1231289857Sobrien{
12313218822Sdim  if (inst.operands[2].isscalar)
12314218822Sdim    {
12315218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDS, NS_QQS, NS_NULL);
12316218822Sdim      struct neon_type_el et = neon_check_type (3, rs,
12317218822Sdim        N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
12318218822Sdim      inst.instruction = NEON_ENC_SCALAR (inst.instruction);
12319218822Sdim      neon_mul_mac (et, neon_quad (rs));
12320218822Sdim    }
12321218822Sdim  else
12322218822Sdim    {
12323218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
12324218822Sdim      struct neon_type_el et = neon_check_type (3, rs,
12325218822Sdim        N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
12326218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12327218822Sdim      /* The U bit (rounding) comes from bit mask.  */
12328218822Sdim      neon_three_same (neon_quad (rs), 0, et.size);
12329218822Sdim    }
1233089857Sobrien}
1233189857Sobrien
1233289857Sobrienstatic void
12333218822Sdimdo_neon_fcmp_absolute (void)
1233489857Sobrien{
12335218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
12336218822Sdim  neon_check_type (3, rs, N_EQK, N_EQK, N_F32 | N_KEY);
12337218822Sdim  /* Size field comes from bit mask.  */
12338218822Sdim  neon_three_same (neon_quad (rs), 1, -1);
1233989857Sobrien}
1234089857Sobrien
1234189857Sobrienstatic void
12342218822Sdimdo_neon_fcmp_absolute_inv (void)
1234389857Sobrien{
12344218822Sdim  neon_exchange_operands ();
12345218822Sdim  do_neon_fcmp_absolute ();
1234689857Sobrien}
1234789857Sobrien
1234889857Sobrienstatic void
12349218822Sdimdo_neon_step (void)
1235089857Sobrien{
12351218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
12352218822Sdim  neon_check_type (3, rs, N_EQK, N_EQK, N_F32 | N_KEY);
12353218822Sdim  neon_three_same (neon_quad (rs), 0, -1);
1235489857Sobrien}
1235589857Sobrien
1235689857Sobrienstatic void
12357218822Sdimdo_neon_abs_neg (void)
1235889857Sobrien{
12359218822Sdim  enum neon_shape rs;
12360218822Sdim  struct neon_type_el et;
12361218822Sdim
12362218822Sdim  if (try_vfp_nsyn (2, do_vfp_nsyn_abs_neg) == SUCCESS)
12363218822Sdim    return;
12364218822Sdim
12365218822Sdim  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12366218822Sdim    return;
12367218822Sdim
12368218822Sdim  rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
12369218822Sdim  et = neon_check_type (2, rs, N_EQK, N_S8 | N_S16 | N_S32 | N_F32 | N_KEY);
12370218822Sdim
12371218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12372218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12373218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg);
12374218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12375218822Sdim  inst.instruction |= neon_quad (rs) << 6;
12376218822Sdim  inst.instruction |= (et.type == NT_float) << 10;
12377218822Sdim  inst.instruction |= neon_logbits (et.size) << 18;
12378218822Sdim
12379218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1238089857Sobrien}
1238189857Sobrien
1238289857Sobrienstatic void
12383218822Sdimdo_neon_sli (void)
1238489857Sobrien{
12385218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
12386218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
12387218822Sdim    N_EQK, N_8 | N_16 | N_32 | N_64 | N_KEY);
12388218822Sdim  int imm = inst.operands[2].imm;
12389218822Sdim  constraint (imm < 0 || (unsigned)imm >= et.size,
12390218822Sdim              _("immediate out of range for insert"));
12391218822Sdim  neon_imm_shift (FALSE, 0, neon_quad (rs), et, imm);
1239289857Sobrien}
1239389857Sobrien
1239489857Sobrienstatic void
12395218822Sdimdo_neon_sri (void)
1239689857Sobrien{
12397218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
12398218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
12399218822Sdim    N_EQK, N_8 | N_16 | N_32 | N_64 | N_KEY);
12400218822Sdim  int imm = inst.operands[2].imm;
12401218822Sdim  constraint (imm < 1 || (unsigned)imm > et.size,
12402218822Sdim              _("immediate out of range for insert"));
12403218822Sdim  neon_imm_shift (FALSE, 0, neon_quad (rs), et, et.size - imm);
1240489857Sobrien}
1240589857Sobrien
1240689857Sobrienstatic void
12407218822Sdimdo_neon_qshlu_imm (void)
1240889857Sobrien{
12409218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
12410218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
12411218822Sdim    N_EQK | N_UNS, N_S8 | N_S16 | N_S32 | N_S64 | N_KEY);
12412218822Sdim  int imm = inst.operands[2].imm;
12413218822Sdim  constraint (imm < 0 || (unsigned)imm >= et.size,
12414218822Sdim              _("immediate out of range for shift"));
12415218822Sdim  /* Only encodes the 'U present' variant of the instruction.
12416218822Sdim     In this case, signed types have OP (bit 8) set to 0.
12417218822Sdim     Unsigned types have OP set to 1.  */
12418218822Sdim  inst.instruction |= (et.type == NT_unsigned) << 8;
12419218822Sdim  /* The rest of the bits are the same as other immediate shifts.  */
12420218822Sdim  neon_imm_shift (FALSE, 0, neon_quad (rs), et, imm);
1242189857Sobrien}
1242289857Sobrien
1242389857Sobrienstatic void
12424218822Sdimdo_neon_qmovn (void)
1242589857Sobrien{
12426218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQ,
12427218822Sdim    N_EQK | N_HLF, N_SU_16_64 | N_KEY);
12428218822Sdim  /* Saturating move where operands can be signed or unsigned, and the
12429218822Sdim     destination has the same signedness.  */
12430218822Sdim  inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12431218822Sdim  if (et.type == NT_unsigned)
12432218822Sdim    inst.instruction |= 0xc0;
12433218822Sdim  else
12434218822Sdim    inst.instruction |= 0x80;
12435218822Sdim  neon_two_same (0, 1, et.size / 2);
1243689857Sobrien}
1243789857Sobrien
1243889857Sobrienstatic void
12439218822Sdimdo_neon_qmovun (void)
1244089857Sobrien{
12441218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQ,
12442218822Sdim    N_EQK | N_HLF | N_UNS, N_S16 | N_S32 | N_S64 | N_KEY);
12443218822Sdim  /* Saturating move with unsigned results. Operands must be signed.  */
12444218822Sdim  inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12445218822Sdim  neon_two_same (0, 1, et.size / 2);
1244689857Sobrien}
1244789857Sobrien
1244889857Sobrienstatic void
12449218822Sdimdo_neon_rshift_sat_narrow (void)
1245089857Sobrien{
12451218822Sdim  /* FIXME: Types for narrowing. If operands are signed, results can be signed
12452218822Sdim     or unsigned. If operands are unsigned, results must also be unsigned.  */
12453218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQI,
12454218822Sdim    N_EQK | N_HLF, N_SU_16_64 | N_KEY);
12455218822Sdim  int imm = inst.operands[2].imm;
12456218822Sdim  /* This gets the bounds check, size encoding and immediate bits calculation
12457218822Sdim     right.  */
12458218822Sdim  et.size /= 2;
12459218822Sdim
12460218822Sdim  /* VQ{R}SHRN.I<size> <Dd>, <Qm>, #0 is a synonym for
12461218822Sdim     VQMOVN.I<size> <Dd>, <Qm>.  */
12462218822Sdim  if (imm == 0)
12463218822Sdim    {
12464218822Sdim      inst.operands[2].present = 0;
12465218822Sdim      inst.instruction = N_MNEM_vqmovn;
12466218822Sdim      do_neon_qmovn ();
12467218822Sdim      return;
12468218822Sdim    }
12469218822Sdim
12470218822Sdim  constraint (imm < 1 || (unsigned)imm > et.size,
12471218822Sdim              _("immediate out of range"));
12472218822Sdim  neon_imm_shift (TRUE, et.type == NT_unsigned, 0, et, et.size - imm);
1247389857Sobrien}
1247489857Sobrien
1247589857Sobrienstatic void
12476218822Sdimdo_neon_rshift_sat_narrow_u (void)
1247789857Sobrien{
12478218822Sdim  /* FIXME: Types for narrowing. If operands are signed, results can be signed
12479218822Sdim     or unsigned. If operands are unsigned, results must also be unsigned.  */
12480218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQI,
12481218822Sdim    N_EQK | N_HLF | N_UNS, N_S16 | N_S32 | N_S64 | N_KEY);
12482218822Sdim  int imm = inst.operands[2].imm;
12483218822Sdim  /* This gets the bounds check, size encoding and immediate bits calculation
12484218822Sdim     right.  */
12485218822Sdim  et.size /= 2;
12486218822Sdim
12487218822Sdim  /* VQSHRUN.I<size> <Dd>, <Qm>, #0 is a synonym for
12488218822Sdim     VQMOVUN.I<size> <Dd>, <Qm>.  */
12489218822Sdim  if (imm == 0)
12490218822Sdim    {
12491218822Sdim      inst.operands[2].present = 0;
12492218822Sdim      inst.instruction = N_MNEM_vqmovun;
12493218822Sdim      do_neon_qmovun ();
12494218822Sdim      return;
12495218822Sdim    }
12496218822Sdim
12497218822Sdim  constraint (imm < 1 || (unsigned)imm > et.size,
12498218822Sdim              _("immediate out of range"));
12499218822Sdim  /* FIXME: The manual is kind of unclear about what value U should have in
12500218822Sdim     VQ{R}SHRUN instructions, but U=0, op=0 definitely encodes VRSHR, so it
12501218822Sdim     must be 1.  */
12502218822Sdim  neon_imm_shift (TRUE, 1, 0, et, et.size - imm);
1250389857Sobrien}
1250489857Sobrien
1250589857Sobrienstatic void
12506218822Sdimdo_neon_movn (void)
1250789857Sobrien{
12508218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQ,
12509218822Sdim    N_EQK | N_HLF, N_I16 | N_I32 | N_I64 | N_KEY);
12510218822Sdim  inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12511218822Sdim  neon_two_same (0, 1, et.size / 2);
1251289857Sobrien}
1251389857Sobrien
1251489857Sobrienstatic void
12515218822Sdimdo_neon_rshift_narrow (void)
1251689857Sobrien{
12517218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQI,
12518218822Sdim    N_EQK | N_HLF, N_I16 | N_I32 | N_I64 | N_KEY);
12519218822Sdim  int imm = inst.operands[2].imm;
12520218822Sdim  /* This gets the bounds check, size encoding and immediate bits calculation
12521218822Sdim     right.  */
12522218822Sdim  et.size /= 2;
12523218822Sdim
12524218822Sdim  /* If immediate is zero then we are a pseudo-instruction for
12525218822Sdim     VMOVN.I<size> <Dd>, <Qm>  */
12526218822Sdim  if (imm == 0)
12527218822Sdim    {
12528218822Sdim      inst.operands[2].present = 0;
12529218822Sdim      inst.instruction = N_MNEM_vmovn;
12530218822Sdim      do_neon_movn ();
12531218822Sdim      return;
12532218822Sdim    }
12533218822Sdim
12534218822Sdim  constraint (imm < 1 || (unsigned)imm > et.size,
12535218822Sdim              _("immediate out of range for narrowing operation"));
12536218822Sdim  neon_imm_shift (FALSE, 0, 0, et, et.size - imm);
1253789857Sobrien}
1253889857Sobrien
1253989857Sobrienstatic void
12540218822Sdimdo_neon_shll (void)
1254189857Sobrien{
12542218822Sdim  /* FIXME: Type checking when lengthening.  */
12543218822Sdim  struct neon_type_el et = neon_check_type (2, NS_QDI,
12544218822Sdim    N_EQK | N_DBL, N_I8 | N_I16 | N_I32 | N_KEY);
12545218822Sdim  unsigned imm = inst.operands[2].imm;
12546218822Sdim
12547218822Sdim  if (imm == et.size)
12548218822Sdim    {
12549218822Sdim      /* Maximum shift variant.  */
12550218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12551218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12552218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12553218822Sdim      inst.instruction |= LOW4 (inst.operands[1].reg);
12554218822Sdim      inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12555218822Sdim      inst.instruction |= neon_logbits (et.size) << 18;
12556218822Sdim
12557218822Sdim      inst.instruction = neon_dp_fixup (inst.instruction);
12558218822Sdim    }
12559218822Sdim  else
12560218822Sdim    {
12561218822Sdim      /* A more-specific type check for non-max versions.  */
12562218822Sdim      et = neon_check_type (2, NS_QDI,
12563218822Sdim        N_EQK | N_DBL, N_SU_32 | N_KEY);
12564218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
12565218822Sdim      neon_imm_shift (TRUE, et.type == NT_unsigned, 0, et, imm);
12566218822Sdim    }
1256789857Sobrien}
1256889857Sobrien
12569218822Sdim/* Check the various types for the VCVT instruction, and return which version
12570218822Sdim   the current instruction is.  */
12571218822Sdim
12572218822Sdimstatic int
12573218822Sdimneon_cvt_flavour (enum neon_shape rs)
12574218822Sdim{
12575218822Sdim#define CVT_VAR(C,X,Y)							\
12576218822Sdim  et = neon_check_type (2, rs, whole_reg | (X), whole_reg | (Y));	\
12577218822Sdim  if (et.type != NT_invtype)						\
12578218822Sdim    {									\
12579218822Sdim      inst.error = NULL;						\
12580218822Sdim      return (C);							\
12581218822Sdim    }
12582218822Sdim  struct neon_type_el et;
12583218822Sdim  unsigned whole_reg = (rs == NS_FFI || rs == NS_FD || rs == NS_DF
12584218822Sdim                        || rs == NS_FF) ? N_VFP : 0;
12585218822Sdim  /* The instruction versions which take an immediate take one register
12586218822Sdim     argument, which is extended to the width of the full register. Thus the
12587218822Sdim     "source" and "destination" registers must have the same width.  Hack that
12588218822Sdim     here by making the size equal to the key (wider, in this case) operand.  */
12589218822Sdim  unsigned key = (rs == NS_QQI || rs == NS_DDI || rs == NS_FFI) ? N_KEY : 0;
12590218822Sdim
12591218822Sdim  CVT_VAR (0, N_S32, N_F32);
12592218822Sdim  CVT_VAR (1, N_U32, N_F32);
12593218822Sdim  CVT_VAR (2, N_F32, N_S32);
12594218822Sdim  CVT_VAR (3, N_F32, N_U32);
12595218822Sdim
12596218822Sdim  whole_reg = N_VFP;
12597218822Sdim
12598218822Sdim  /* VFP instructions.  */
12599218822Sdim  CVT_VAR (4, N_F32, N_F64);
12600218822Sdim  CVT_VAR (5, N_F64, N_F32);
12601218822Sdim  CVT_VAR (6, N_S32, N_F64 | key);
12602218822Sdim  CVT_VAR (7, N_U32, N_F64 | key);
12603218822Sdim  CVT_VAR (8, N_F64 | key, N_S32);
12604218822Sdim  CVT_VAR (9, N_F64 | key, N_U32);
12605218822Sdim  /* VFP instructions with bitshift.  */
12606218822Sdim  CVT_VAR (10, N_F32 | key, N_S16);
12607218822Sdim  CVT_VAR (11, N_F32 | key, N_U16);
12608218822Sdim  CVT_VAR (12, N_F64 | key, N_S16);
12609218822Sdim  CVT_VAR (13, N_F64 | key, N_U16);
12610218822Sdim  CVT_VAR (14, N_S16, N_F32 | key);
12611218822Sdim  CVT_VAR (15, N_U16, N_F32 | key);
12612218822Sdim  CVT_VAR (16, N_S16, N_F64 | key);
12613218822Sdim  CVT_VAR (17, N_U16, N_F64 | key);
12614218822Sdim
12615218822Sdim  return -1;
12616218822Sdim#undef CVT_VAR
12617218822Sdim}
12618218822Sdim
12619218822Sdim/* Neon-syntax VFP conversions.  */
12620218822Sdim
1262189857Sobrienstatic void
12622218822Sdimdo_vfp_nsyn_cvt (enum neon_shape rs, int flavour)
1262389857Sobrien{
12624218822Sdim  const char *opname = 0;
12625218822Sdim
12626218822Sdim  if (rs == NS_DDI || rs == NS_QQI || rs == NS_FFI)
12627218822Sdim    {
12628218822Sdim      /* Conversions with immediate bitshift.  */
12629218822Sdim      const char *enc[] =
12630218822Sdim        {
12631218822Sdim          "ftosls",
12632218822Sdim          "ftouls",
12633218822Sdim          "fsltos",
12634218822Sdim          "fultos",
12635218822Sdim          NULL,
12636218822Sdim          NULL,
12637218822Sdim          "ftosld",
12638218822Sdim          "ftould",
12639218822Sdim          "fsltod",
12640218822Sdim          "fultod",
12641218822Sdim          "fshtos",
12642218822Sdim          "fuhtos",
12643218822Sdim          "fshtod",
12644218822Sdim          "fuhtod",
12645218822Sdim          "ftoshs",
12646218822Sdim          "ftouhs",
12647218822Sdim          "ftoshd",
12648218822Sdim          "ftouhd"
12649218822Sdim        };
12650218822Sdim
12651218822Sdim      if (flavour >= 0 && flavour < (int) ARRAY_SIZE (enc))
12652218822Sdim        {
12653218822Sdim          opname = enc[flavour];
12654218822Sdim          constraint (inst.operands[0].reg != inst.operands[1].reg,
12655218822Sdim                      _("operands 0 and 1 must be the same register"));
12656218822Sdim          inst.operands[1] = inst.operands[2];
12657218822Sdim          memset (&inst.operands[2], '\0', sizeof (inst.operands[2]));
12658218822Sdim        }
12659218822Sdim    }
12660218822Sdim  else
12661218822Sdim    {
12662218822Sdim      /* Conversions without bitshift.  */
12663218822Sdim      const char *enc[] =
12664218822Sdim        {
12665266414Sian          "ftosizs",
12666266414Sian          "ftouizs",
12667218822Sdim          "fsitos",
12668218822Sdim          "fuitos",
12669218822Sdim          "fcvtsd",
12670218822Sdim          "fcvtds",
12671266414Sian          "ftosizd",
12672266414Sian          "ftouizd",
12673218822Sdim          "fsitod",
12674218822Sdim          "fuitod"
12675218822Sdim        };
12676218822Sdim
12677218822Sdim      if (flavour >= 0 && flavour < (int) ARRAY_SIZE (enc))
12678218822Sdim        opname = enc[flavour];
12679218822Sdim    }
12680218822Sdim
12681218822Sdim  if (opname)
12682218822Sdim    do_vfp_nsyn_opcode (opname);
1268389857Sobrien}
1268489857Sobrien
1268589857Sobrienstatic void
12686218822Sdimdo_vfp_nsyn_cvtz (void)
1268789857Sobrien{
12688218822Sdim  enum neon_shape rs = neon_select_shape (NS_FF, NS_FD, NS_NULL);
12689218822Sdim  int flavour = neon_cvt_flavour (rs);
12690218822Sdim  const char *enc[] =
12691218822Sdim    {
12692218822Sdim      "ftosizs",
12693218822Sdim      "ftouizs",
12694218822Sdim      NULL,
12695218822Sdim      NULL,
12696218822Sdim      NULL,
12697218822Sdim      NULL,
12698218822Sdim      "ftosizd",
12699218822Sdim      "ftouizd"
12700218822Sdim    };
12701218822Sdim
12702218822Sdim  if (flavour >= 0 && flavour < (int) ARRAY_SIZE (enc) && enc[flavour])
12703218822Sdim    do_vfp_nsyn_opcode (enc[flavour]);
1270489857Sobrien}
1270589857Sobrien
1270689857Sobrienstatic void
12707218822Sdimdo_neon_cvt (void)
1270889857Sobrien{
12709218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_FFI, NS_DD, NS_QQ,
12710218822Sdim    NS_FD, NS_DF, NS_FF, NS_NULL);
12711218822Sdim  int flavour = neon_cvt_flavour (rs);
12712218822Sdim
12713218822Sdim  /* VFP rather than Neon conversions.  */
12714218822Sdim  if (flavour >= 4)
12715218822Sdim    {
12716218822Sdim      do_vfp_nsyn_cvt (rs, flavour);
12717218822Sdim      return;
12718218822Sdim    }
12719218822Sdim
12720218822Sdim  switch (rs)
12721218822Sdim    {
12722218822Sdim    case NS_DDI:
12723218822Sdim    case NS_QQI:
12724218822Sdim      {
12725218822Sdim        if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12726218822Sdim          return;
12727218822Sdim
12728218822Sdim        /* Fixed-point conversion with #0 immediate is encoded as an
12729218822Sdim           integer conversion.  */
12730218822Sdim        if (inst.operands[2].present && inst.operands[2].imm == 0)
12731218822Sdim          goto int_encode;
12732218822Sdim        unsigned immbits = 32 - inst.operands[2].imm;
12733218822Sdim        unsigned enctab[] = { 0x0000100, 0x1000100, 0x0, 0x1000000 };
12734218822Sdim        inst.instruction = NEON_ENC_IMMED (inst.instruction);
12735218822Sdim        if (flavour != -1)
12736218822Sdim          inst.instruction |= enctab[flavour];
12737218822Sdim        inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12738218822Sdim        inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12739218822Sdim        inst.instruction |= LOW4 (inst.operands[1].reg);
12740218822Sdim        inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12741218822Sdim        inst.instruction |= neon_quad (rs) << 6;
12742218822Sdim        inst.instruction |= 1 << 21;
12743218822Sdim        inst.instruction |= immbits << 16;
12744218822Sdim
12745218822Sdim        inst.instruction = neon_dp_fixup (inst.instruction);
12746218822Sdim      }
12747218822Sdim      break;
12748218822Sdim
12749218822Sdim    case NS_DD:
12750218822Sdim    case NS_QQ:
12751218822Sdim    int_encode:
12752218822Sdim      {
12753218822Sdim        unsigned enctab[] = { 0x100, 0x180, 0x0, 0x080 };
12754218822Sdim
12755218822Sdim        inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12756218822Sdim
12757218822Sdim        if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12758218822Sdim          return;
12759218822Sdim
12760218822Sdim        if (flavour != -1)
12761218822Sdim          inst.instruction |= enctab[flavour];
12762218822Sdim
12763218822Sdim        inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12764218822Sdim        inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12765218822Sdim        inst.instruction |= LOW4 (inst.operands[1].reg);
12766218822Sdim        inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12767218822Sdim        inst.instruction |= neon_quad (rs) << 6;
12768218822Sdim        inst.instruction |= 2 << 18;
12769218822Sdim
12770218822Sdim        inst.instruction = neon_dp_fixup (inst.instruction);
12771218822Sdim      }
12772218822Sdim    break;
12773218822Sdim
12774218822Sdim    default:
12775218822Sdim      /* Some VFP conversions go here (s32 <-> f32, u32 <-> f32).  */
12776218822Sdim      do_vfp_nsyn_cvt (rs, flavour);
12777218822Sdim    }
1277889857Sobrien}
1277989857Sobrien
1278089857Sobrienstatic void
12781218822Sdimneon_move_immediate (void)
1278289857Sobrien{
12783218822Sdim  enum neon_shape rs = neon_select_shape (NS_DI, NS_QI, NS_NULL);
12784218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
12785218822Sdim    N_I8 | N_I16 | N_I32 | N_I64 | N_F32 | N_KEY, N_EQK);
12786218822Sdim  unsigned immlo, immhi = 0, immbits;
12787218822Sdim  int op, cmode, float_p;
12788218822Sdim
12789218822Sdim  constraint (et.type == NT_invtype,
12790218822Sdim              _("operand size must be specified for immediate VMOV"));
12791218822Sdim
12792218822Sdim  /* We start out as an MVN instruction if OP = 1, MOV otherwise.  */
12793218822Sdim  op = (inst.instruction & (1 << 5)) != 0;
12794218822Sdim
12795218822Sdim  immlo = inst.operands[1].imm;
12796218822Sdim  if (inst.operands[1].regisimm)
12797218822Sdim    immhi = inst.operands[1].reg;
12798218822Sdim
12799218822Sdim  constraint (et.size < 32 && (immlo & ~((1 << et.size) - 1)) != 0,
12800218822Sdim              _("immediate has bits set outside the operand size"));
12801218822Sdim
12802218822Sdim  float_p = inst.operands[1].immisfloat;
12803218822Sdim
12804218822Sdim  if ((cmode = neon_cmode_for_move_imm (immlo, immhi, float_p, &immbits, &op,
12805218822Sdim                                        et.size, et.type)) == FAIL)
12806218822Sdim    {
12807218822Sdim      /* Invert relevant bits only.  */
12808218822Sdim      neon_invert_size (&immlo, &immhi, et.size);
12809218822Sdim      /* Flip from VMOV/VMVN to VMVN/VMOV. Some immediate types are unavailable
12810218822Sdim         with one or the other; those cases are caught by
12811218822Sdim         neon_cmode_for_move_imm.  */
12812218822Sdim      op = !op;
12813218822Sdim      if ((cmode = neon_cmode_for_move_imm (immlo, immhi, float_p, &immbits,
12814218822Sdim					    &op, et.size, et.type)) == FAIL)
12815218822Sdim        {
12816218822Sdim          first_error (_("immediate out of range"));
12817218822Sdim          return;
12818218822Sdim        }
12819218822Sdim    }
12820218822Sdim
12821218822Sdim  inst.instruction &= ~(1 << 5);
12822218822Sdim  inst.instruction |= op << 5;
12823218822Sdim
12824218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12825218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12826218822Sdim  inst.instruction |= neon_quad (rs) << 6;
12827218822Sdim  inst.instruction |= cmode << 8;
12828218822Sdim
12829218822Sdim  neon_write_immbits (immbits);
1283089857Sobrien}
1283189857Sobrien
1283289857Sobrienstatic void
12833218822Sdimdo_neon_mvn (void)
1283489857Sobrien{
12835218822Sdim  if (inst.operands[1].isreg)
12836218822Sdim    {
12837218822Sdim      enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
12838218822Sdim
12839218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12840218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12841218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12842218822Sdim      inst.instruction |= LOW4 (inst.operands[1].reg);
12843218822Sdim      inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12844218822Sdim      inst.instruction |= neon_quad (rs) << 6;
12845218822Sdim    }
12846218822Sdim  else
12847218822Sdim    {
12848218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
12849218822Sdim      neon_move_immediate ();
12850218822Sdim    }
12851218822Sdim
12852218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1285389857Sobrien}
1285489857Sobrien
12855218822Sdim/* Encode instructions of form:
12856218822Sdim
12857218822Sdim  |28/24|23|22|21 20|19 16|15 12|11    8|7|6|5|4|3  0|
12858218822Sdim  |  U  |x |D |size | Rn  | Rd  |x x x x|N|x|M|x| Rm |
12859218822Sdim
12860218822Sdim*/
12861218822Sdim
1286289857Sobrienstatic void
12863218822Sdimneon_mixed_length (struct neon_type_el et, unsigned size)
1286489857Sobrien{
12865218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12866218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12867218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
12868218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
12869218822Sdim  inst.instruction |= LOW4 (inst.operands[2].reg);
12870218822Sdim  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
12871218822Sdim  inst.instruction |= (et.type == NT_unsigned) << 24;
12872218822Sdim  inst.instruction |= neon_logbits (size) << 20;
12873218822Sdim
12874218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1287589857Sobrien}
1287689857Sobrien
1287789857Sobrienstatic void
12878218822Sdimdo_neon_dyadic_long (void)
1287989857Sobrien{
12880218822Sdim  /* FIXME: Type checking for lengthening op.  */
12881218822Sdim  struct neon_type_el et = neon_check_type (3, NS_QDD,
12882218822Sdim    N_EQK | N_DBL, N_EQK, N_SU_32 | N_KEY);
12883218822Sdim  neon_mixed_length (et, et.size);
1288489857Sobrien}
1288589857Sobrien
1288689857Sobrienstatic void
12887218822Sdimdo_neon_abal (void)
1288889857Sobrien{
12889218822Sdim  struct neon_type_el et = neon_check_type (3, NS_QDD,
12890218822Sdim    N_EQK | N_INT | N_DBL, N_EQK, N_SU_32 | N_KEY);
12891218822Sdim  neon_mixed_length (et, et.size);
1289289857Sobrien}
1289389857Sobrien
1289489857Sobrienstatic void
12895218822Sdimneon_mac_reg_scalar_long (unsigned regtypes, unsigned scalartypes)
1289689857Sobrien{
12897218822Sdim  if (inst.operands[2].isscalar)
12898218822Sdim    {
12899218822Sdim      struct neon_type_el et = neon_check_type (3, NS_QDS,
12900218822Sdim        N_EQK | N_DBL, N_EQK, regtypes | N_KEY);
12901218822Sdim      inst.instruction = NEON_ENC_SCALAR (inst.instruction);
12902218822Sdim      neon_mul_mac (et, et.type == NT_unsigned);
12903218822Sdim    }
12904218822Sdim  else
12905218822Sdim    {
12906218822Sdim      struct neon_type_el et = neon_check_type (3, NS_QDD,
12907218822Sdim        N_EQK | N_DBL, N_EQK, scalartypes | N_KEY);
12908218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12909218822Sdim      neon_mixed_length (et, et.size);
12910218822Sdim    }
1291189857Sobrien}
1291289857Sobrien
1291389857Sobrienstatic void
12914218822Sdimdo_neon_mac_maybe_scalar_long (void)
1291589857Sobrien{
12916218822Sdim  neon_mac_reg_scalar_long (N_S16 | N_S32 | N_U16 | N_U32, N_SU_32);
1291789857Sobrien}
1291889857Sobrien
1291989857Sobrienstatic void
12920218822Sdimdo_neon_dyadic_wide (void)
1292189857Sobrien{
12922218822Sdim  struct neon_type_el et = neon_check_type (3, NS_QQD,
12923218822Sdim    N_EQK | N_DBL, N_EQK | N_DBL, N_SU_32 | N_KEY);
12924218822Sdim  neon_mixed_length (et, et.size);
1292589857Sobrien}
1292689857Sobrien
1292789857Sobrienstatic void
12928218822Sdimdo_neon_dyadic_narrow (void)
1292989857Sobrien{
12930218822Sdim  struct neon_type_el et = neon_check_type (3, NS_QDD,
12931218822Sdim    N_EQK | N_DBL, N_EQK, N_I16 | N_I32 | N_I64 | N_KEY);
12932218822Sdim  /* Operand sign is unimportant, and the U bit is part of the opcode,
12933218822Sdim     so force the operand type to integer.  */
12934218822Sdim  et.type = NT_integer;
12935218822Sdim  neon_mixed_length (et, et.size / 2);
1293689857Sobrien}
1293789857Sobrien
1293889857Sobrienstatic void
12939218822Sdimdo_neon_mul_sat_scalar_long (void)
1294089857Sobrien{
12941218822Sdim  neon_mac_reg_scalar_long (N_S16 | N_S32, N_S16 | N_S32);
1294289857Sobrien}
1294389857Sobrien
1294489857Sobrienstatic void
12945218822Sdimdo_neon_vmull (void)
1294689857Sobrien{
12947218822Sdim  if (inst.operands[2].isscalar)
12948218822Sdim    do_neon_mac_maybe_scalar_long ();
12949218822Sdim  else
12950218822Sdim    {
12951218822Sdim      struct neon_type_el et = neon_check_type (3, NS_QDD,
12952218822Sdim        N_EQK | N_DBL, N_EQK, N_SU_32 | N_P8 | N_KEY);
12953218822Sdim      if (et.type == NT_poly)
12954218822Sdim        inst.instruction = NEON_ENC_POLY (inst.instruction);
12955218822Sdim      else
12956218822Sdim        inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12957218822Sdim      /* For polynomial encoding, size field must be 0b00 and the U bit must be
12958218822Sdim         zero. Should be OK as-is.  */
12959218822Sdim      neon_mixed_length (et, et.size);
12960218822Sdim    }
1296189857Sobrien}
1296289857Sobrien
1296389857Sobrienstatic void
12964218822Sdimdo_neon_ext (void)
1296589857Sobrien{
12966218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDDI, NS_QQQI, NS_NULL);
12967218822Sdim  struct neon_type_el et = neon_check_type (3, rs,
12968218822Sdim    N_EQK, N_EQK, N_8 | N_16 | N_32 | N_64 | N_KEY);
12969218822Sdim  unsigned imm = (inst.operands[3].imm * et.size) / 8;
12970218822Sdim  constraint (imm >= (neon_quad (rs) ? 16 : 8), _("shift out of range"));
12971218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12972218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12973218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
12974218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
12975218822Sdim  inst.instruction |= LOW4 (inst.operands[2].reg);
12976218822Sdim  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
12977218822Sdim  inst.instruction |= neon_quad (rs) << 6;
12978218822Sdim  inst.instruction |= imm << 8;
12979218822Sdim
12980218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1298189857Sobrien}
1298289857Sobrien
1298389857Sobrienstatic void
12984218822Sdimdo_neon_rev (void)
1298589857Sobrien{
12986218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
12987218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
12988218822Sdim    N_EQK, N_8 | N_16 | N_32 | N_KEY);
12989218822Sdim  unsigned op = (inst.instruction >> 7) & 3;
12990218822Sdim  /* N (width of reversed regions) is encoded as part of the bitmask. We
12991218822Sdim     extract it here to check the elements to be reversed are smaller.
12992218822Sdim     Otherwise we'd get a reserved instruction.  */
12993218822Sdim  unsigned elsize = (op == 2) ? 16 : (op == 1) ? 32 : (op == 0) ? 64 : 0;
12994218822Sdim  assert (elsize != 0);
12995218822Sdim  constraint (et.size >= elsize,
12996218822Sdim              _("elements must be smaller than reversal region"));
12997218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1299889857Sobrien}
1299989857Sobrien
1300089857Sobrienstatic void
13001218822Sdimdo_neon_dup (void)
1300289857Sobrien{
13003218822Sdim  if (inst.operands[1].isscalar)
13004218822Sdim    {
13005218822Sdim      enum neon_shape rs = neon_select_shape (NS_DS, NS_QS, NS_NULL);
13006218822Sdim      struct neon_type_el et = neon_check_type (2, rs,
13007218822Sdim        N_EQK, N_8 | N_16 | N_32 | N_KEY);
13008218822Sdim      unsigned sizebits = et.size >> 3;
13009218822Sdim      unsigned dm = NEON_SCALAR_REG (inst.operands[1].reg);
13010218822Sdim      int logsize = neon_logbits (et.size);
13011218822Sdim      unsigned x = NEON_SCALAR_INDEX (inst.operands[1].reg) << logsize;
13012218822Sdim
13013218822Sdim      if (vfp_or_neon_is_neon (NEON_CHECK_CC) == FAIL)
13014218822Sdim        return;
13015218822Sdim
13016218822Sdim      inst.instruction = NEON_ENC_SCALAR (inst.instruction);
13017218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
13018218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
13019218822Sdim      inst.instruction |= LOW4 (dm);
13020218822Sdim      inst.instruction |= HI1 (dm) << 5;
13021218822Sdim      inst.instruction |= neon_quad (rs) << 6;
13022218822Sdim      inst.instruction |= x << 17;
13023218822Sdim      inst.instruction |= sizebits << 16;
13024218822Sdim
13025218822Sdim      inst.instruction = neon_dp_fixup (inst.instruction);
13026218822Sdim    }
13027218822Sdim  else
13028218822Sdim    {
13029218822Sdim      enum neon_shape rs = neon_select_shape (NS_DR, NS_QR, NS_NULL);
13030218822Sdim      struct neon_type_el et = neon_check_type (2, rs,
13031218822Sdim        N_8 | N_16 | N_32 | N_KEY, N_EQK);
13032218822Sdim      /* Duplicate ARM register to lanes of vector.  */
13033218822Sdim      inst.instruction = NEON_ENC_ARMREG (inst.instruction);
13034218822Sdim      switch (et.size)
13035218822Sdim        {
13036218822Sdim        case 8:  inst.instruction |= 0x400000; break;
13037218822Sdim        case 16: inst.instruction |= 0x000020; break;
13038218822Sdim        case 32: inst.instruction |= 0x000000; break;
13039218822Sdim        default: break;
13040218822Sdim        }
13041218822Sdim      inst.instruction |= LOW4 (inst.operands[1].reg) << 12;
13042218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 16;
13043218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 7;
13044218822Sdim      inst.instruction |= neon_quad (rs) << 21;
13045218822Sdim      /* The encoding for this instruction is identical for the ARM and Thumb
13046218822Sdim         variants, except for the condition field.  */
13047218822Sdim      do_vfp_cond_or_thumb ();
13048218822Sdim    }
1304989857Sobrien}
1305089857Sobrien
13051218822Sdim/* VMOV has particularly many variations. It can be one of:
13052218822Sdim     0. VMOV<c><q> <Qd>, <Qm>
13053218822Sdim     1. VMOV<c><q> <Dd>, <Dm>
13054218822Sdim   (Register operations, which are VORR with Rm = Rn.)
13055218822Sdim     2. VMOV<c><q>.<dt> <Qd>, #<imm>
13056218822Sdim     3. VMOV<c><q>.<dt> <Dd>, #<imm>
13057218822Sdim   (Immediate loads.)
13058218822Sdim     4. VMOV<c><q>.<size> <Dn[x]>, <Rd>
13059218822Sdim   (ARM register to scalar.)
13060218822Sdim     5. VMOV<c><q> <Dm>, <Rd>, <Rn>
13061218822Sdim   (Two ARM registers to vector.)
13062218822Sdim     6. VMOV<c><q>.<dt> <Rd>, <Dn[x]>
13063218822Sdim   (Scalar to ARM register.)
13064218822Sdim     7. VMOV<c><q> <Rd>, <Rn>, <Dm>
13065218822Sdim   (Vector to two ARM registers.)
13066218822Sdim     8. VMOV.F32 <Sd>, <Sm>
13067218822Sdim     9. VMOV.F64 <Dd>, <Dm>
13068218822Sdim   (VFP register moves.)
13069218822Sdim    10. VMOV.F32 <Sd>, #imm
13070218822Sdim    11. VMOV.F64 <Dd>, #imm
13071218822Sdim   (VFP float immediate load.)
13072218822Sdim    12. VMOV <Rd>, <Sm>
13073218822Sdim   (VFP single to ARM reg.)
13074218822Sdim    13. VMOV <Sd>, <Rm>
13075218822Sdim   (ARM reg to VFP single.)
13076218822Sdim    14. VMOV <Rd>, <Re>, <Sn>, <Sm>
13077218822Sdim   (Two ARM regs to two VFP singles.)
13078218822Sdim    15. VMOV <Sd>, <Se>, <Rn>, <Rm>
13079218822Sdim   (Two VFP singles to two ARM regs.)
13080218822Sdim
13081218822Sdim   These cases can be disambiguated using neon_select_shape, except cases 1/9
13082218822Sdim   and 3/11 which depend on the operand type too.
13083218822Sdim
13084218822Sdim   All the encoded bits are hardcoded by this function.
13085218822Sdim
13086218822Sdim   Cases 4, 6 may be used with VFPv1 and above (only 32-bit transfers!).
13087218822Sdim   Cases 5, 7 may be used with VFPv2 and above.
13088218822Sdim
13089218822Sdim   FIXME: Some of the checking may be a bit sloppy (in a couple of cases you
13090218822Sdim   can specify a type where it doesn't make sense to, and is ignored).
13091218822Sdim*/
13092218822Sdim
1309389857Sobrienstatic void
13094218822Sdimdo_neon_mov (void)
1309589857Sobrien{
13096218822Sdim  enum neon_shape rs = neon_select_shape (NS_RRFF, NS_FFRR, NS_DRR, NS_RRD,
13097218822Sdim    NS_QQ, NS_DD, NS_QI, NS_DI, NS_SR, NS_RS, NS_FF, NS_FI, NS_RF, NS_FR,
13098218822Sdim    NS_NULL);
13099218822Sdim  struct neon_type_el et;
13100218822Sdim  const char *ldconst = 0;
1310189857Sobrien
13102218822Sdim  switch (rs)
1310389857Sobrien    {
13104218822Sdim    case NS_DD:  /* case 1/9.  */
13105218822Sdim      et = neon_check_type (2, rs, N_EQK, N_F64 | N_KEY);
13106218822Sdim      /* It is not an error here if no type is given.  */
13107218822Sdim      inst.error = NULL;
13108218822Sdim      if (et.type == NT_float && et.size == 64)
13109218822Sdim        {
13110218822Sdim          do_vfp_nsyn_opcode ("fcpyd");
13111218822Sdim          break;
13112218822Sdim        }
13113218822Sdim      /* fall through.  */
1311489857Sobrien
13115218822Sdim    case NS_QQ:  /* case 0/1.  */
13116218822Sdim      {
13117218822Sdim        if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
13118218822Sdim          return;
13119218822Sdim        /* The architecture manual I have doesn't explicitly state which
13120218822Sdim           value the U bit should have for register->register moves, but
13121218822Sdim           the equivalent VORR instruction has U = 0, so do that.  */
13122218822Sdim        inst.instruction = 0x0200110;
13123218822Sdim        inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
13124218822Sdim        inst.instruction |= HI1 (inst.operands[0].reg) << 22;
13125218822Sdim        inst.instruction |= LOW4 (inst.operands[1].reg);
13126218822Sdim        inst.instruction |= HI1 (inst.operands[1].reg) << 5;
13127218822Sdim        inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
13128218822Sdim        inst.instruction |= HI1 (inst.operands[1].reg) << 7;
13129218822Sdim        inst.instruction |= neon_quad (rs) << 6;
13130218822Sdim
13131218822Sdim        inst.instruction = neon_dp_fixup (inst.instruction);
13132218822Sdim      }
13133218822Sdim      break;
13134218822Sdim
13135218822Sdim    case NS_DI:  /* case 3/11.  */
13136218822Sdim      et = neon_check_type (2, rs, N_EQK, N_F64 | N_KEY);
13137218822Sdim      inst.error = NULL;
13138218822Sdim      if (et.type == NT_float && et.size == 64)
13139218822Sdim        {
13140218822Sdim          /* case 11 (fconstd).  */
13141218822Sdim          ldconst = "fconstd";
13142218822Sdim          goto encode_fconstd;
13143218822Sdim        }
13144218822Sdim      /* fall through.  */
13145218822Sdim
13146218822Sdim    case NS_QI:  /* case 2/3.  */
13147218822Sdim      if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
13148218822Sdim        return;
13149218822Sdim      inst.instruction = 0x0800010;
13150218822Sdim      neon_move_immediate ();
13151218822Sdim      inst.instruction = neon_dp_fixup (inst.instruction);
13152218822Sdim      break;
13153218822Sdim
13154218822Sdim    case NS_SR:  /* case 4.  */
13155218822Sdim      {
13156218822Sdim        unsigned bcdebits = 0;
13157218822Sdim        struct neon_type_el et = neon_check_type (2, NS_NULL,
13158218822Sdim          N_8 | N_16 | N_32 | N_KEY, N_EQK);
13159218822Sdim        int logsize = neon_logbits (et.size);
13160218822Sdim        unsigned dn = NEON_SCALAR_REG (inst.operands[0].reg);
13161218822Sdim        unsigned x = NEON_SCALAR_INDEX (inst.operands[0].reg);
13162218822Sdim
13163218822Sdim        constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v1),
13164218822Sdim                    _(BAD_FPU));
13165218822Sdim        constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1)
13166218822Sdim                    && et.size != 32, _(BAD_FPU));
13167218822Sdim        constraint (et.type == NT_invtype, _("bad type for scalar"));
13168218822Sdim        constraint (x >= 64 / et.size, _("scalar index out of range"));
13169218822Sdim
13170218822Sdim        switch (et.size)
13171218822Sdim          {
13172218822Sdim          case 8:  bcdebits = 0x8; break;
13173218822Sdim          case 16: bcdebits = 0x1; break;
13174218822Sdim          case 32: bcdebits = 0x0; break;
13175218822Sdim          default: ;
13176218822Sdim          }
13177218822Sdim
13178218822Sdim        bcdebits |= x << logsize;
13179218822Sdim
13180218822Sdim        inst.instruction = 0xe000b10;
13181218822Sdim        do_vfp_cond_or_thumb ();
13182218822Sdim        inst.instruction |= LOW4 (dn) << 16;
13183218822Sdim        inst.instruction |= HI1 (dn) << 7;
13184218822Sdim        inst.instruction |= inst.operands[1].reg << 12;
13185218822Sdim        inst.instruction |= (bcdebits & 3) << 5;
13186218822Sdim        inst.instruction |= (bcdebits >> 2) << 21;
13187218822Sdim      }
13188218822Sdim      break;
13189218822Sdim
13190218822Sdim    case NS_DRR:  /* case 5 (fmdrr).  */
13191218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v2),
13192218822Sdim                  _(BAD_FPU));
13193218822Sdim
13194218822Sdim      inst.instruction = 0xc400b10;
13195218822Sdim      do_vfp_cond_or_thumb ();
13196218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg);
13197218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 5;
13198218822Sdim      inst.instruction |= inst.operands[1].reg << 12;
13199218822Sdim      inst.instruction |= inst.operands[2].reg << 16;
13200218822Sdim      break;
13201218822Sdim
13202218822Sdim    case NS_RS:  /* case 6.  */
13203218822Sdim      {
13204218822Sdim        struct neon_type_el et = neon_check_type (2, NS_NULL,
13205218822Sdim          N_EQK, N_S8 | N_S16 | N_U8 | N_U16 | N_32 | N_KEY);
13206218822Sdim        unsigned logsize = neon_logbits (et.size);
13207218822Sdim        unsigned dn = NEON_SCALAR_REG (inst.operands[1].reg);
13208218822Sdim        unsigned x = NEON_SCALAR_INDEX (inst.operands[1].reg);
13209218822Sdim        unsigned abcdebits = 0;
13210218822Sdim
13211218822Sdim        constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v1),
13212218822Sdim                    _(BAD_FPU));
13213218822Sdim        constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1)
13214218822Sdim                    && et.size != 32, _(BAD_FPU));
13215218822Sdim        constraint (et.type == NT_invtype, _("bad type for scalar"));
13216218822Sdim        constraint (x >= 64 / et.size, _("scalar index out of range"));
13217218822Sdim
13218218822Sdim        switch (et.size)
13219218822Sdim          {
13220218822Sdim          case 8:  abcdebits = (et.type == NT_signed) ? 0x08 : 0x18; break;
13221218822Sdim          case 16: abcdebits = (et.type == NT_signed) ? 0x01 : 0x11; break;
13222218822Sdim          case 32: abcdebits = 0x00; break;
13223218822Sdim          default: ;
13224218822Sdim          }
13225218822Sdim
13226218822Sdim        abcdebits |= x << logsize;
13227218822Sdim        inst.instruction = 0xe100b10;
13228218822Sdim        do_vfp_cond_or_thumb ();
13229218822Sdim        inst.instruction |= LOW4 (dn) << 16;
13230218822Sdim        inst.instruction |= HI1 (dn) << 7;
13231218822Sdim        inst.instruction |= inst.operands[0].reg << 12;
13232218822Sdim        inst.instruction |= (abcdebits & 3) << 5;
13233218822Sdim        inst.instruction |= (abcdebits >> 2) << 21;
13234218822Sdim      }
13235218822Sdim      break;
13236218822Sdim
13237218822Sdim    case NS_RRD:  /* case 7 (fmrrd).  */
13238218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v2),
13239218822Sdim                  _(BAD_FPU));
13240218822Sdim
13241218822Sdim      inst.instruction = 0xc500b10;
13242218822Sdim      do_vfp_cond_or_thumb ();
13243218822Sdim      inst.instruction |= inst.operands[0].reg << 12;
13244218822Sdim      inst.instruction |= inst.operands[1].reg << 16;
13245218822Sdim      inst.instruction |= LOW4 (inst.operands[2].reg);
13246218822Sdim      inst.instruction |= HI1 (inst.operands[2].reg) << 5;
13247218822Sdim      break;
13248218822Sdim
13249218822Sdim    case NS_FF:  /* case 8 (fcpys).  */
13250218822Sdim      do_vfp_nsyn_opcode ("fcpys");
13251218822Sdim      break;
13252218822Sdim
13253218822Sdim    case NS_FI:  /* case 10 (fconsts).  */
13254218822Sdim      ldconst = "fconsts";
13255218822Sdim      encode_fconstd:
13256218822Sdim      if (is_quarter_float (inst.operands[1].imm))
13257218822Sdim        {
13258218822Sdim          inst.operands[1].imm = neon_qfloat_bits (inst.operands[1].imm);
13259218822Sdim          do_vfp_nsyn_opcode (ldconst);
13260218822Sdim        }
13261218822Sdim      else
13262218822Sdim        first_error (_("immediate out of range"));
13263218822Sdim      break;
13264218822Sdim
13265218822Sdim    case NS_RF:  /* case 12 (fmrs).  */
13266218822Sdim      do_vfp_nsyn_opcode ("fmrs");
13267218822Sdim      break;
13268218822Sdim
13269218822Sdim    case NS_FR:  /* case 13 (fmsr).  */
13270218822Sdim      do_vfp_nsyn_opcode ("fmsr");
13271218822Sdim      break;
13272218822Sdim
13273218822Sdim    /* The encoders for the fmrrs and fmsrr instructions expect three operands
13274218822Sdim       (one of which is a list), but we have parsed four.  Do some fiddling to
13275218822Sdim       make the operands what do_vfp_reg2_from_sp2 and do_vfp_sp2_from_reg2
13276218822Sdim       expect.  */
13277218822Sdim    case NS_RRFF:  /* case 14 (fmrrs).  */
13278218822Sdim      constraint (inst.operands[3].reg != inst.operands[2].reg + 1,
13279218822Sdim                  _("VFP registers must be adjacent"));
13280218822Sdim      inst.operands[2].imm = 2;
13281218822Sdim      memset (&inst.operands[3], '\0', sizeof (inst.operands[3]));
13282218822Sdim      do_vfp_nsyn_opcode ("fmrrs");
13283218822Sdim      break;
13284218822Sdim
13285218822Sdim    case NS_FFRR:  /* case 15 (fmsrr).  */
13286218822Sdim      constraint (inst.operands[1].reg != inst.operands[0].reg + 1,
13287218822Sdim                  _("VFP registers must be adjacent"));
13288218822Sdim      inst.operands[1] = inst.operands[2];
13289218822Sdim      inst.operands[2] = inst.operands[3];
13290218822Sdim      inst.operands[0].imm = 2;
13291218822Sdim      memset (&inst.operands[3], '\0', sizeof (inst.operands[3]));
13292218822Sdim      do_vfp_nsyn_opcode ("fmsrr");
13293218822Sdim      break;
13294218822Sdim
13295218822Sdim    default:
13296218822Sdim      abort ();
13297218822Sdim    }
13298218822Sdim}
13299218822Sdim
13300218822Sdimstatic void
13301218822Sdimdo_neon_rshift_round_imm (void)
13302218822Sdim{
13303218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
13304218822Sdim  struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_SU_ALL | N_KEY);
13305218822Sdim  int imm = inst.operands[2].imm;
13306218822Sdim
13307218822Sdim  /* imm == 0 case is encoded as VMOV for V{R}SHR.  */
13308218822Sdim  if (imm == 0)
13309218822Sdim    {
13310218822Sdim      inst.operands[2].present = 0;
13311218822Sdim      do_neon_mov ();
1331289857Sobrien      return;
1331389857Sobrien    }
1331489857Sobrien
13315218822Sdim  constraint (imm < 1 || (unsigned)imm > et.size,
13316218822Sdim              _("immediate out of range for shift"));
13317218822Sdim  neon_imm_shift (TRUE, et.type == NT_unsigned, neon_quad (rs), et,
13318218822Sdim                  et.size - imm);
1331989857Sobrien}
1332089857Sobrien
1332189857Sobrienstatic void
13322218822Sdimdo_neon_movl (void)
1332389857Sobrien{
13324218822Sdim  struct neon_type_el et = neon_check_type (2, NS_QD,
13325218822Sdim    N_EQK | N_DBL, N_SU_32 | N_KEY);
13326218822Sdim  unsigned sizebits = et.size >> 3;
13327218822Sdim  inst.instruction |= sizebits << 19;
13328218822Sdim  neon_two_same (0, et.type == NT_unsigned, -1);
13329218822Sdim}
1333089857Sobrien
13331218822Sdimstatic void
13332218822Sdimdo_neon_trn (void)
13333218822Sdim{
13334218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13335218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13336218822Sdim    N_EQK, N_8 | N_16 | N_32 | N_KEY);
13337218822Sdim  inst.instruction = NEON_ENC_INTEGER (inst.instruction);
13338218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
13339218822Sdim}
13340218822Sdim
13341218822Sdimstatic void
13342218822Sdimdo_neon_zip_uzp (void)
13343218822Sdim{
13344218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13345218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13346218822Sdim    N_EQK, N_8 | N_16 | N_32 | N_KEY);
13347218822Sdim  if (rs == NS_DD && et.size == 32)
1334889857Sobrien    {
13349218822Sdim      /* Special case: encode as VTRN.32 <Dd>, <Dm>.  */
13350218822Sdim      inst.instruction = N_MNEM_vtrn;
13351218822Sdim      do_neon_trn ();
1335289857Sobrien      return;
1335389857Sobrien    }
13354218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
13355218822Sdim}
1335689857Sobrien
13357218822Sdimstatic void
13358218822Sdimdo_neon_sat_abs_neg (void)
13359218822Sdim{
13360218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13361218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13362218822Sdim    N_EQK, N_S8 | N_S16 | N_S32 | N_KEY);
13363218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1336489857Sobrien}
1336589857Sobrien
1336689857Sobrienstatic void
13367218822Sdimdo_neon_pair_long (void)
1336889857Sobrien{
13369218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13370218822Sdim  struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_SU_32 | N_KEY);
13371218822Sdim  /* Unsigned is encoded in OP field (bit 7) for these instruction.  */
13372218822Sdim  inst.instruction |= (et.type == NT_unsigned) << 7;
13373218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1337489857Sobrien}
1337589857Sobrien
1337689857Sobrienstatic void
13377218822Sdimdo_neon_recip_est (void)
1337889857Sobrien{
13379218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13380218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13381218822Sdim    N_EQK | N_FLT, N_F32 | N_U32 | N_KEY);
13382218822Sdim  inst.instruction |= (et.type == NT_float) << 8;
13383218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1338489857Sobrien}
1338589857Sobrien
1338689857Sobrienstatic void
13387218822Sdimdo_neon_cls (void)
1338889857Sobrien{
13389218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13390218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13391218822Sdim    N_EQK, N_S8 | N_S16 | N_S32 | N_KEY);
13392218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1339389857Sobrien}
1339489857Sobrien
1339589857Sobrienstatic void
13396218822Sdimdo_neon_clz (void)
1339789857Sobrien{
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_I8 | N_I16 | N_I32 | N_KEY);
13401218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1340289857Sobrien}
1340389857Sobrien
1340489857Sobrienstatic void
13405218822Sdimdo_neon_cnt (void)
1340689857Sobrien{
13407218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13408218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13409218822Sdim    N_EQK | N_INT, N_8 | N_KEY);
13410218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1341189857Sobrien}
1341289857Sobrien
1341389857Sobrienstatic void
13414218822Sdimdo_neon_swp (void)
1341589857Sobrien{
13416218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13417218822Sdim  neon_two_same (neon_quad (rs), 1, -1);
1341889857Sobrien}
1341989857Sobrien
13420218822Sdimstatic void
13421218822Sdimdo_neon_tbl_tbx (void)
13422218822Sdim{
13423218822Sdim  unsigned listlenbits;
13424218822Sdim  neon_check_type (3, NS_DLD, N_EQK, N_EQK, N_8 | N_KEY);
13425218822Sdim
13426218822Sdim  if (inst.operands[1].imm < 1 || inst.operands[1].imm > 4)
13427218822Sdim    {
13428218822Sdim      first_error (_("bad list length for table lookup"));
13429218822Sdim      return;
13430218822Sdim    }
13431218822Sdim
13432218822Sdim  listlenbits = inst.operands[1].imm - 1;
13433218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
13434218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
13435218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
13436218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
13437218822Sdim  inst.instruction |= LOW4 (inst.operands[2].reg);
13438218822Sdim  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
13439218822Sdim  inst.instruction |= listlenbits << 8;
13440218822Sdim
13441218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
13442218822Sdim}
1344389857Sobrien
1344489857Sobrienstatic void
13445218822Sdimdo_neon_ldm_stm (void)
1344689857Sobrien{
13447218822Sdim  /* P, U and L bits are part of bitmask.  */
13448218822Sdim  int is_dbmode = (inst.instruction & (1 << 24)) != 0;
13449218822Sdim  unsigned offsetbits = inst.operands[1].imm * 2;
1345089857Sobrien
13451218822Sdim  if (inst.operands[1].issingle)
13452218822Sdim    {
13453218822Sdim      do_vfp_nsyn_ldm_stm (is_dbmode);
13454218822Sdim      return;
13455218822Sdim    }
1345689857Sobrien
13457218822Sdim  constraint (is_dbmode && !inst.operands[0].writeback,
13458218822Sdim              _("writeback (!) must be used for VLDMDB and VSTMDB"));
1345989857Sobrien
13460218822Sdim  constraint (inst.operands[1].imm < 1 || inst.operands[1].imm > 16,
13461218822Sdim              _("register list must contain at least 1 and at most 16 "
13462218822Sdim                "registers"));
13463218822Sdim
13464218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
13465218822Sdim  inst.instruction |= inst.operands[0].writeback << 21;
13466218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 12;
13467218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 22;
13468218822Sdim
13469218822Sdim  inst.instruction |= offsetbits;
13470218822Sdim
13471218822Sdim  do_vfp_cond_or_thumb ();
13472218822Sdim}
13473218822Sdim
13474218822Sdimstatic void
13475218822Sdimdo_neon_ldr_str (void)
13476218822Sdim{
13477218822Sdim  int is_ldr = (inst.instruction & (1 << 20)) != 0;
13478218822Sdim
13479218822Sdim  if (inst.operands[0].issingle)
1348089857Sobrien    {
13481218822Sdim      if (is_ldr)
13482218822Sdim        do_vfp_nsyn_opcode ("flds");
13483218822Sdim      else
13484218822Sdim        do_vfp_nsyn_opcode ("fsts");
1348589857Sobrien    }
1348689857Sobrien  else
13487218822Sdim    {
13488218822Sdim      if (is_ldr)
13489218822Sdim        do_vfp_nsyn_opcode ("fldd");
13490218822Sdim      else
13491218822Sdim        do_vfp_nsyn_opcode ("fstd");
13492218822Sdim    }
1349389857Sobrien}
1349489857Sobrien
13495218822Sdim/* "interleave" version also handles non-interleaving register VLD1/VST1
13496218822Sdim   instructions.  */
1349789857Sobrien
1349889857Sobrienstatic void
13499218822Sdimdo_neon_ld_st_interleave (void)
1350089857Sobrien{
13501218822Sdim  struct neon_type_el et = neon_check_type (1, NS_NULL,
13502218822Sdim                                            N_8 | N_16 | N_32 | N_64);
13503218822Sdim  unsigned alignbits = 0;
13504218822Sdim  unsigned idx;
13505218822Sdim  /* The bits in this table go:
13506218822Sdim     0: register stride of one (0) or two (1)
13507218822Sdim     1,2: register list length, minus one (1, 2, 3, 4).
13508218822Sdim     3,4: <n> in instruction type, minus one (VLD<n> / VST<n>).
13509218822Sdim     We use -1 for invalid entries.  */
13510218822Sdim  const int typetable[] =
13511218822Sdim    {
13512218822Sdim      0x7,  -1, 0xa,  -1, 0x6,  -1, 0x2,  -1, /* VLD1 / VST1.  */
13513218822Sdim       -1,  -1, 0x8, 0x9,  -1,  -1, 0x3,  -1, /* VLD2 / VST2.  */
13514218822Sdim       -1,  -1,  -1,  -1, 0x4, 0x5,  -1,  -1, /* VLD3 / VST3.  */
13515218822Sdim       -1,  -1,  -1,  -1,  -1,  -1, 0x0, 0x1  /* VLD4 / VST4.  */
13516218822Sdim    };
13517218822Sdim  int typebits;
1351889857Sobrien
13519218822Sdim  if (et.type == NT_invtype)
13520218822Sdim    return;
1352189857Sobrien
13522218822Sdim  if (inst.operands[1].immisalign)
13523218822Sdim    switch (inst.operands[1].imm >> 8)
13524218822Sdim      {
13525218822Sdim      case 64: alignbits = 1; break;
13526218822Sdim      case 128:
13527218822Sdim        if (NEON_REGLIST_LENGTH (inst.operands[0].imm) == 3)
13528218822Sdim          goto bad_alignment;
13529218822Sdim        alignbits = 2;
13530218822Sdim        break;
13531218822Sdim      case 256:
13532218822Sdim        if (NEON_REGLIST_LENGTH (inst.operands[0].imm) == 3)
13533218822Sdim          goto bad_alignment;
13534218822Sdim        alignbits = 3;
13535218822Sdim        break;
13536218822Sdim      default:
13537218822Sdim      bad_alignment:
13538218822Sdim        first_error (_("bad alignment"));
13539218822Sdim        return;
13540218822Sdim      }
1354189857Sobrien
13542218822Sdim  inst.instruction |= alignbits << 4;
13543218822Sdim  inst.instruction |= neon_logbits (et.size) << 6;
13544218822Sdim
13545218822Sdim  /* Bits [4:6] of the immediate in a list specifier encode register stride
13546218822Sdim     (minus 1) in bit 4, and list length in bits [5:6]. We put the <n> of
13547218822Sdim     VLD<n>/VST<n> in bits [9:8] of the initial bitmask. Suck it out here, look
13548218822Sdim     up the right value for "type" in a table based on this value and the given
13549218822Sdim     list style, then stick it back.  */
13550218822Sdim  idx = ((inst.operands[0].imm >> 4) & 7)
13551218822Sdim        | (((inst.instruction >> 8) & 3) << 3);
13552218822Sdim
13553218822Sdim  typebits = typetable[idx];
13554218822Sdim
13555218822Sdim  constraint (typebits == -1, _("bad list type for instruction"));
13556218822Sdim
13557218822Sdim  inst.instruction &= ~0xf00;
13558218822Sdim  inst.instruction |= typebits << 8;
13559218822Sdim}
13560218822Sdim
13561218822Sdim/* Check alignment is valid for do_neon_ld_st_lane and do_neon_ld_dup.
13562218822Sdim   *DO_ALIGN is set to 1 if the relevant alignment bit should be set, 0
13563218822Sdim   otherwise. The variable arguments are a list of pairs of legal (size, align)
13564218822Sdim   values, terminated with -1.  */
13565218822Sdim
13566218822Sdimstatic int
13567218822Sdimneon_alignment_bit (int size, int align, int *do_align, ...)
13568218822Sdim{
13569218822Sdim  va_list ap;
13570218822Sdim  int result = FAIL, thissize, thisalign;
13571218822Sdim
13572218822Sdim  if (!inst.operands[1].immisalign)
1357389857Sobrien    {
13574218822Sdim      *do_align = 0;
13575218822Sdim      return SUCCESS;
1357689857Sobrien    }
13577218822Sdim
13578218822Sdim  va_start (ap, do_align);
13579218822Sdim
13580218822Sdim  do
13581218822Sdim    {
13582218822Sdim      thissize = va_arg (ap, int);
13583218822Sdim      if (thissize == -1)
13584218822Sdim        break;
13585218822Sdim      thisalign = va_arg (ap, int);
13586218822Sdim
13587218822Sdim      if (size == thissize && align == thisalign)
13588218822Sdim        result = SUCCESS;
13589218822Sdim    }
13590218822Sdim  while (result != SUCCESS);
13591218822Sdim
13592218822Sdim  va_end (ap);
13593218822Sdim
13594218822Sdim  if (result == SUCCESS)
13595218822Sdim    *do_align = 1;
1359689857Sobrien  else
13597218822Sdim    first_error (_("unsupported alignment for instruction"));
13598218822Sdim
13599218822Sdim  return result;
1360089857Sobrien}
1360189857Sobrien
1360289857Sobrienstatic void
13603218822Sdimdo_neon_ld_st_lane (void)
1360489857Sobrien{
13605218822Sdim  struct neon_type_el et = neon_check_type (1, NS_NULL, N_8 | N_16 | N_32);
13606218822Sdim  int align_good, do_align = 0;
13607218822Sdim  int logsize = neon_logbits (et.size);
13608218822Sdim  int align = inst.operands[1].imm >> 8;
13609218822Sdim  int n = (inst.instruction >> 8) & 3;
13610218822Sdim  int max_el = 64 / et.size;
13611218822Sdim
13612218822Sdim  if (et.type == NT_invtype)
13613218822Sdim    return;
13614218822Sdim
13615218822Sdim  constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != n + 1,
13616218822Sdim              _("bad list length"));
13617218822Sdim  constraint (NEON_LANE (inst.operands[0].imm) >= max_el,
13618218822Sdim              _("scalar index out of range"));
13619218822Sdim  constraint (n != 0 && NEON_REG_STRIDE (inst.operands[0].imm) == 2
13620218822Sdim              && et.size == 8,
13621218822Sdim              _("stride of 2 unavailable when element size is 8"));
13622218822Sdim
13623218822Sdim  switch (n)
13624218822Sdim    {
13625218822Sdim    case 0:  /* VLD1 / VST1.  */
13626218822Sdim      align_good = neon_alignment_bit (et.size, align, &do_align, 16, 16,
13627218822Sdim                                       32, 32, -1);
13628218822Sdim      if (align_good == FAIL)
13629218822Sdim        return;
13630218822Sdim      if (do_align)
13631218822Sdim        {
13632218822Sdim          unsigned alignbits = 0;
13633218822Sdim          switch (et.size)
13634218822Sdim            {
13635218822Sdim            case 16: alignbits = 0x1; break;
13636218822Sdim            case 32: alignbits = 0x3; break;
13637218822Sdim            default: ;
13638218822Sdim            }
13639218822Sdim          inst.instruction |= alignbits << 4;
13640218822Sdim        }
13641218822Sdim      break;
1364289857Sobrien
13643218822Sdim    case 1:  /* VLD2 / VST2.  */
13644218822Sdim      align_good = neon_alignment_bit (et.size, align, &do_align, 8, 16, 16, 32,
13645218822Sdim                                       32, 64, -1);
13646218822Sdim      if (align_good == FAIL)
13647218822Sdim        return;
13648218822Sdim      if (do_align)
13649218822Sdim        inst.instruction |= 1 << 4;
13650218822Sdim      break;
1365189857Sobrien
13652218822Sdim    case 2:  /* VLD3 / VST3.  */
13653218822Sdim      constraint (inst.operands[1].immisalign,
13654218822Sdim                  _("can't use alignment with this instruction"));
13655218822Sdim      break;
1365689857Sobrien
13657218822Sdim    case 3:  /* VLD4 / VST4.  */
13658218822Sdim      align_good = neon_alignment_bit (et.size, align, &do_align, 8, 32,
13659218822Sdim                                       16, 64, 32, 64, 32, 128, -1);
13660218822Sdim      if (align_good == FAIL)
13661218822Sdim        return;
13662218822Sdim      if (do_align)
13663218822Sdim        {
13664218822Sdim          unsigned alignbits = 0;
13665218822Sdim          switch (et.size)
13666218822Sdim            {
13667218822Sdim            case 8:  alignbits = 0x1; break;
13668218822Sdim            case 16: alignbits = 0x1; break;
13669218822Sdim            case 32: alignbits = (align == 64) ? 0x1 : 0x2; break;
13670218822Sdim            default: ;
13671218822Sdim            }
13672218822Sdim          inst.instruction |= alignbits << 4;
13673218822Sdim        }
13674218822Sdim      break;
13675218822Sdim
13676218822Sdim    default: ;
1367789857Sobrien    }
13678218822Sdim
13679218822Sdim  /* Reg stride of 2 is encoded in bit 5 when size==16, bit 6 when size==32.  */
13680218822Sdim  if (n != 0 && NEON_REG_STRIDE (inst.operands[0].imm) == 2)
13681218822Sdim    inst.instruction |= 1 << (4 + logsize);
13682218822Sdim
13683218822Sdim  inst.instruction |= NEON_LANE (inst.operands[0].imm) << (logsize + 5);
13684218822Sdim  inst.instruction |= logsize << 10;
1368589857Sobrien}
1368689857Sobrien
13687218822Sdim/* Encode single n-element structure to all lanes VLD<n> instructions.  */
1368889857Sobrien
1368989857Sobrienstatic void
13690218822Sdimdo_neon_ld_dup (void)
1369189857Sobrien{
13692218822Sdim  struct neon_type_el et = neon_check_type (1, NS_NULL, N_8 | N_16 | N_32);
13693218822Sdim  int align_good, do_align = 0;
1369489857Sobrien
13695218822Sdim  if (et.type == NT_invtype)
13696218822Sdim    return;
1369789857Sobrien
13698218822Sdim  switch ((inst.instruction >> 8) & 3)
13699218822Sdim    {
13700218822Sdim    case 0:  /* VLD1.  */
13701218822Sdim      assert (NEON_REG_STRIDE (inst.operands[0].imm) != 2);
13702218822Sdim      align_good = neon_alignment_bit (et.size, inst.operands[1].imm >> 8,
13703218822Sdim                                       &do_align, 16, 16, 32, 32, -1);
13704218822Sdim      if (align_good == FAIL)
13705218822Sdim        return;
13706218822Sdim      switch (NEON_REGLIST_LENGTH (inst.operands[0].imm))
13707218822Sdim        {
13708218822Sdim        case 1: break;
13709218822Sdim        case 2: inst.instruction |= 1 << 5; break;
13710218822Sdim        default: first_error (_("bad list length")); return;
13711218822Sdim        }
13712218822Sdim      inst.instruction |= neon_logbits (et.size) << 6;
13713218822Sdim      break;
1371489857Sobrien
13715218822Sdim    case 1:  /* VLD2.  */
13716218822Sdim      align_good = neon_alignment_bit (et.size, inst.operands[1].imm >> 8,
13717218822Sdim                                       &do_align, 8, 16, 16, 32, 32, 64, -1);
13718218822Sdim      if (align_good == FAIL)
13719218822Sdim        return;
13720218822Sdim      constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 2,
13721218822Sdim                  _("bad list length"));
13722218822Sdim      if (NEON_REG_STRIDE (inst.operands[0].imm) == 2)
13723218822Sdim        inst.instruction |= 1 << 5;
13724218822Sdim      inst.instruction |= neon_logbits (et.size) << 6;
13725218822Sdim      break;
13726218822Sdim
13727218822Sdim    case 2:  /* VLD3.  */
13728218822Sdim      constraint (inst.operands[1].immisalign,
13729218822Sdim                  _("can't use alignment with this instruction"));
13730218822Sdim      constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 3,
13731218822Sdim                  _("bad list length"));
13732218822Sdim      if (NEON_REG_STRIDE (inst.operands[0].imm) == 2)
13733218822Sdim        inst.instruction |= 1 << 5;
13734218822Sdim      inst.instruction |= neon_logbits (et.size) << 6;
13735218822Sdim      break;
13736218822Sdim
13737218822Sdim    case 3:  /* VLD4.  */
13738218822Sdim      {
13739218822Sdim        int align = inst.operands[1].imm >> 8;
13740218822Sdim        align_good = neon_alignment_bit (et.size, align, &do_align, 8, 32,
13741218822Sdim                                         16, 64, 32, 64, 32, 128, -1);
13742218822Sdim        if (align_good == FAIL)
13743218822Sdim          return;
13744218822Sdim        constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 4,
13745218822Sdim                    _("bad list length"));
13746218822Sdim        if (NEON_REG_STRIDE (inst.operands[0].imm) == 2)
13747218822Sdim          inst.instruction |= 1 << 5;
13748218822Sdim        if (et.size == 32 && align == 128)
13749218822Sdim          inst.instruction |= 0x3 << 6;
13750218822Sdim        else
13751218822Sdim          inst.instruction |= neon_logbits (et.size) << 6;
13752218822Sdim      }
13753218822Sdim      break;
13754218822Sdim
13755218822Sdim    default: ;
1375689857Sobrien    }
1375789857Sobrien
13758218822Sdim  inst.instruction |= do_align << 4;
13759218822Sdim}
1376089857Sobrien
13761218822Sdim/* Disambiguate VLD<n> and VST<n> instructions, and fill in common bits (those
13762218822Sdim   apart from bits [11:4].  */
1376389857Sobrien
13764218822Sdimstatic void
13765218822Sdimdo_neon_ldx_stx (void)
13766218822Sdim{
13767218822Sdim  switch (NEON_LANE (inst.operands[0].imm))
1376889857Sobrien    {
13769218822Sdim    case NEON_INTERLEAVE_LANES:
13770218822Sdim      inst.instruction = NEON_ENC_INTERLV (inst.instruction);
13771218822Sdim      do_neon_ld_st_interleave ();
13772218822Sdim      break;
13773218822Sdim
13774218822Sdim    case NEON_ALL_LANES:
13775218822Sdim      inst.instruction = NEON_ENC_DUP (inst.instruction);
13776218822Sdim      do_neon_ld_dup ();
13777218822Sdim      break;
13778218822Sdim
13779218822Sdim    default:
13780218822Sdim      inst.instruction = NEON_ENC_LANE (inst.instruction);
13781218822Sdim      do_neon_ld_st_lane ();
1378289857Sobrien    }
1378389857Sobrien
13784218822Sdim  /* L bit comes from bit mask.  */
13785218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
13786218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
13787218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
13788218822Sdim
13789218822Sdim  if (inst.operands[1].postind)
1379089857Sobrien    {
13791218822Sdim      int postreg = inst.operands[1].imm & 0xf;
13792218822Sdim      constraint (!inst.operands[1].immisreg,
13793218822Sdim                  _("post-index must be a register"));
13794218822Sdim      constraint (postreg == 0xd || postreg == 0xf,
13795218822Sdim                  _("bad register for post-index"));
13796218822Sdim      inst.instruction |= postreg;
1379789857Sobrien    }
13798218822Sdim  else if (inst.operands[1].writeback)
13799218822Sdim    {
13800218822Sdim      inst.instruction |= 0xd;
13801218822Sdim    }
13802218822Sdim  else
13803218822Sdim    inst.instruction |= 0xf;
13804218822Sdim
13805218822Sdim  if (thumb_mode)
13806218822Sdim    inst.instruction |= 0xf9000000;
13807218822Sdim  else
13808218822Sdim    inst.instruction |= 0xf4000000;
13809218822Sdim}
1381089857Sobrien
13811218822Sdim
13812218822Sdim/* Overall per-instruction processing.	*/
1381389857Sobrien
13814218822Sdim/* We need to be able to fix up arbitrary expressions in some statements.
13815218822Sdim   This is so that we can handle symbols that are an arbitrary distance from
13816218822Sdim   the pc.  The most common cases are of the form ((+/-sym -/+ . - 8) & mask),
13817218822Sdim   which returns part of an address in a form which will be valid for
13818218822Sdim   a data instruction.	We do this by pushing the expression into a symbol
13819218822Sdim   in the expr_section, and creating a fix for that.  */
13820218822Sdim
13821218822Sdimstatic void
13822218822Sdimfix_new_arm (fragS *	   frag,
13823218822Sdim	     int	   where,
13824218822Sdim	     short int	   size,
13825218822Sdim	     expressionS * exp,
13826218822Sdim	     int	   pc_rel,
13827218822Sdim	     int	   reloc)
13828218822Sdim{
13829218822Sdim  fixS *	   new_fix;
13830218822Sdim
13831218822Sdim  switch (exp->X_op)
1383289857Sobrien    {
13833218822Sdim    case O_constant:
13834218822Sdim    case O_symbol:
13835218822Sdim    case O_add:
13836218822Sdim    case O_subtract:
13837218822Sdim      new_fix = fix_new_exp (frag, where, size, exp, pc_rel, reloc);
13838218822Sdim      break;
1383989857Sobrien
13840218822Sdim    default:
13841218822Sdim      new_fix = fix_new (frag, where, size, make_expr_symbol (exp), 0,
13842218822Sdim			 pc_rel, reloc);
13843218822Sdim      break;
1384489857Sobrien    }
1384589857Sobrien
13846218822Sdim  /* Mark whether the fix is to a THUMB instruction, or an ARM
13847218822Sdim     instruction.  */
13848218822Sdim  new_fix->tc_fix_data = thumb_mode;
1384989857Sobrien}
1385089857Sobrien
13851218822Sdim/* Create a frg for an instruction requiring relaxation.  */
13852218822Sdimstatic void
13853218822Sdimoutput_relax_insn (void)
1385489857Sobrien{
13855218822Sdim  char * to;
13856218822Sdim  symbolS *sym;
1385789857Sobrien  int offset;
1385889857Sobrien
13859218822Sdim  /* The size of the instruction is unknown, so tie the debug info to the
13860218822Sdim     start of the instruction.  */
13861218822Sdim  dwarf2_emit_insn (0);
1386289857Sobrien
13863218822Sdim  switch (inst.reloc.exp.X_op)
13864218822Sdim    {
13865218822Sdim    case O_symbol:
13866218822Sdim      sym = inst.reloc.exp.X_add_symbol;
13867218822Sdim      offset = inst.reloc.exp.X_add_number;
13868218822Sdim      break;
13869218822Sdim    case O_constant:
13870218822Sdim      sym = NULL;
13871218822Sdim      offset = inst.reloc.exp.X_add_number;
13872218822Sdim      break;
13873218822Sdim    default:
13874218822Sdim      sym = make_expr_symbol (&inst.reloc.exp);
13875218822Sdim      offset = 0;
13876218822Sdim      break;
13877218822Sdim  }
13878218822Sdim  to = frag_var (rs_machine_dependent, INSN_SIZE, THUMB_SIZE,
13879218822Sdim		 inst.relax, sym, offset, NULL/*offset, opcode*/);
13880218822Sdim  md_number_to_chars (to, inst.instruction, THUMB_SIZE);
13881218822Sdim}
1388289857Sobrien
13883218822Sdim/* Write a 32-bit thumb instruction to buf.  */
13884218822Sdimstatic void
13885218822Sdimput_thumb32_insn (char * buf, unsigned long insn)
13886218822Sdim{
13887218822Sdim  md_number_to_chars (buf, insn >> 16, THUMB_SIZE);
13888218822Sdim  md_number_to_chars (buf + THUMB_SIZE, insn, THUMB_SIZE);
13889218822Sdim}
1389089857Sobrien
13891218822Sdimstatic void
13892218822Sdimoutput_inst (const char * str)
13893218822Sdim{
13894218822Sdim  char * to = NULL;
1389589857Sobrien
13896218822Sdim  if (inst.error)
1389789857Sobrien    {
13898218822Sdim      as_bad ("%s -- `%s'", inst.error, str);
13899218822Sdim      return;
1390089857Sobrien    }
13901218822Sdim  if (inst.relax) {
13902218822Sdim      output_relax_insn();
13903218822Sdim      return;
13904218822Sdim  }
13905218822Sdim  if (inst.size == 0)
13906218822Sdim    return;
1390789857Sobrien
13908218822Sdim  to = frag_more (inst.size);
1390989857Sobrien
13910218822Sdim  if (thumb_mode && (inst.size > THUMB_SIZE))
1391189857Sobrien    {
13912218822Sdim      assert (inst.size == (2 * THUMB_SIZE));
13913218822Sdim      put_thumb32_insn (to, inst.instruction);
1391489857Sobrien    }
13915218822Sdim  else if (inst.size > INSN_SIZE)
13916218822Sdim    {
13917218822Sdim      assert (inst.size == (2 * INSN_SIZE));
13918218822Sdim      md_number_to_chars (to, inst.instruction, INSN_SIZE);
13919218822Sdim      md_number_to_chars (to + INSN_SIZE, inst.instruction, INSN_SIZE);
13920218822Sdim    }
13921218822Sdim  else
13922218822Sdim    md_number_to_chars (to, inst.instruction, inst.size);
1392389857Sobrien
13924218822Sdim  if (inst.reloc.type != BFD_RELOC_UNUSED)
13925218822Sdim    fix_new_arm (frag_now, to - frag_now->fr_literal,
13926218822Sdim		 inst.size, & inst.reloc.exp, inst.reloc.pc_rel,
13927218822Sdim		 inst.reloc.type);
1392889857Sobrien
13929218822Sdim  dwarf2_emit_insn (inst.size);
1393089857Sobrien}
1393189857Sobrien
13932218822Sdim/* Tag values used in struct asm_opcode's tag field.  */
13933218822Sdimenum opcode_tag
13934218822Sdim{
13935218822Sdim  OT_unconditional,	/* Instruction cannot be conditionalized.
13936218822Sdim			   The ARM condition field is still 0xE.  */
13937218822Sdim  OT_unconditionalF,	/* Instruction cannot be conditionalized
13938218822Sdim			   and carries 0xF in its ARM condition field.  */
13939218822Sdim  OT_csuffix,		/* Instruction takes a conditional suffix.  */
13940218822Sdim  OT_csuffixF,		/* Some forms of the instruction take a conditional
13941218822Sdim                           suffix, others place 0xF where the condition field
13942218822Sdim                           would be.  */
13943218822Sdim  OT_cinfix3,		/* Instruction takes a conditional infix,
13944218822Sdim			   beginning at character index 3.  (In
13945218822Sdim			   unified mode, it becomes a suffix.)  */
13946218822Sdim  OT_cinfix3_deprecated, /* The same as OT_cinfix3.  This is used for
13947218822Sdim			    tsts, cmps, cmns, and teqs. */
13948218822Sdim  OT_cinfix3_legacy,	/* Legacy instruction takes a conditional infix at
13949218822Sdim			   character index 3, even in unified mode.  Used for
13950218822Sdim			   legacy instructions where suffix and infix forms
13951218822Sdim			   may be ambiguous.  */
13952218822Sdim  OT_csuf_or_in3,	/* Instruction takes either a conditional
13953218822Sdim			   suffix or an infix at character index 3.  */
13954218822Sdim  OT_odd_infix_unc,	/* This is the unconditional variant of an
13955218822Sdim			   instruction that takes a conditional infix
13956218822Sdim			   at an unusual position.  In unified mode,
13957218822Sdim			   this variant will accept a suffix.  */
13958218822Sdim  OT_odd_infix_0	/* Values greater than or equal to OT_odd_infix_0
13959218822Sdim			   are the conditional variants of instructions that
13960218822Sdim			   take conditional infixes in unusual positions.
13961218822Sdim			   The infix appears at character index
13962218822Sdim			   (tag - OT_odd_infix_0).  These are not accepted
13963218822Sdim			   in unified mode.  */
13964218822Sdim};
1396589857Sobrien
13966218822Sdim/* Subroutine of md_assemble, responsible for looking up the primary
13967218822Sdim   opcode from the mnemonic the user wrote.  STR points to the
13968218822Sdim   beginning of the mnemonic.
13969218822Sdim
13970218822Sdim   This is not simply a hash table lookup, because of conditional
13971218822Sdim   variants.  Most instructions have conditional variants, which are
13972218822Sdim   expressed with a _conditional affix_ to the mnemonic.  If we were
13973218822Sdim   to encode each conditional variant as a literal string in the opcode
13974218822Sdim   table, it would have approximately 20,000 entries.
13975218822Sdim
13976218822Sdim   Most mnemonics take this affix as a suffix, and in unified syntax,
13977218822Sdim   'most' is upgraded to 'all'.  However, in the divided syntax, some
13978218822Sdim   instructions take the affix as an infix, notably the s-variants of
13979218822Sdim   the arithmetic instructions.  Of those instructions, all but six
13980218822Sdim   have the infix appear after the third character of the mnemonic.
13981218822Sdim
13982218822Sdim   Accordingly, the algorithm for looking up primary opcodes given
13983218822Sdim   an identifier is:
13984218822Sdim
13985218822Sdim   1. Look up the identifier in the opcode table.
13986218822Sdim      If we find a match, go to step U.
13987218822Sdim
13988218822Sdim   2. Look up the last two characters of the identifier in the
13989218822Sdim      conditions table.  If we find a match, look up the first N-2
13990218822Sdim      characters of the identifier in the opcode table.  If we
13991218822Sdim      find a match, go to step CE.
13992218822Sdim
13993218822Sdim   3. Look up the fourth and fifth characters of the identifier in
13994218822Sdim      the conditions table.  If we find a match, extract those
13995218822Sdim      characters from the identifier, and look up the remaining
13996218822Sdim      characters in the opcode table.  If we find a match, go
13997218822Sdim      to step CM.
13998218822Sdim
13999218822Sdim   4. Fail.
14000218822Sdim
14001218822Sdim   U. Examine the tag field of the opcode structure, in case this is
14002218822Sdim      one of the six instructions with its conditional infix in an
14003218822Sdim      unusual place.  If it is, the tag tells us where to find the
14004218822Sdim      infix; look it up in the conditions table and set inst.cond
14005218822Sdim      accordingly.  Otherwise, this is an unconditional instruction.
14006218822Sdim      Again set inst.cond accordingly.  Return the opcode structure.
14007218822Sdim
14008218822Sdim  CE. Examine the tag field to make sure this is an instruction that
14009218822Sdim      should receive a conditional suffix.  If it is not, fail.
14010218822Sdim      Otherwise, set inst.cond from the suffix we already looked up,
14011218822Sdim      and return the opcode structure.
14012218822Sdim
14013218822Sdim  CM. Examine the tag field to make sure this is an instruction that
14014218822Sdim      should receive a conditional infix after the third character.
14015218822Sdim      If it is not, fail.  Otherwise, undo the edits to the current
14016218822Sdim      line of input and proceed as for case CE.  */
14017218822Sdim
14018218822Sdimstatic const struct asm_opcode *
14019218822Sdimopcode_lookup (char **str)
1402089857Sobrien{
14021218822Sdim  char *end, *base;
14022218822Sdim  char *affix;
14023218822Sdim  const struct asm_opcode *opcode;
14024218822Sdim  const struct asm_cond *cond;
14025218822Sdim  char save[2];
14026218822Sdim  bfd_boolean neon_supported;
14027218822Sdim
14028218822Sdim  neon_supported = ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1);
1402989857Sobrien
14030218822Sdim  /* Scan up to the end of the mnemonic, which must end in white space,
14031218822Sdim     '.' (in unified mode, or for Neon instructions), or end of string.  */
14032218822Sdim  for (base = end = *str; *end != '\0'; end++)
14033218822Sdim    if (*end == ' ' || ((unified_syntax || neon_supported) && *end == '.'))
14034218822Sdim      break;
1403589857Sobrien
14036218822Sdim  if (end == base)
14037218822Sdim    return 0;
1403889857Sobrien
14039218822Sdim  /* Handle a possible width suffix and/or Neon type suffix.  */
14040218822Sdim  if (end[0] == '.')
1404189857Sobrien    {
14042218822Sdim      int offset = 2;
14043218822Sdim
14044218822Sdim      /* The .w and .n suffixes are only valid if the unified syntax is in
14045218822Sdim         use.  */
14046218822Sdim      if (unified_syntax && end[1] == 'w')
14047218822Sdim	inst.size_req = 4;
14048218822Sdim      else if (unified_syntax && end[1] == 'n')
14049218822Sdim	inst.size_req = 2;
14050218822Sdim      else
14051218822Sdim        offset = 0;
1405289857Sobrien
14053218822Sdim      inst.vectype.elems = 0;
1405489857Sobrien
14055218822Sdim      *str = end + offset;
1405689857Sobrien
14057218822Sdim      if (end[offset] == '.')
1405889857Sobrien	{
14059218822Sdim	  /* See if we have a Neon type suffix (possible in either unified or
14060218822Sdim             non-unified ARM syntax mode).  */
14061218822Sdim          if (parse_neon_type (&inst.vectype, str) == FAIL)
14062218822Sdim	    return 0;
14063218822Sdim        }
14064218822Sdim      else if (end[offset] != '\0' && end[offset] != ' ')
14065218822Sdim        return 0;
14066218822Sdim    }
14067218822Sdim  else
14068218822Sdim    *str = end;
1406989857Sobrien
14070218822Sdim  /* Look for unaffixed or special-case affixed mnemonic.  */
14071218822Sdim  opcode = hash_find_n (arm_ops_hsh, base, end - base);
14072218822Sdim  if (opcode)
14073218822Sdim    {
14074218822Sdim      /* step U */
14075218822Sdim      if (opcode->tag < OT_odd_infix_0)
1407689857Sobrien	{
14077218822Sdim	  inst.cond = COND_ALWAYS;
14078218822Sdim	  return opcode;
1407989857Sobrien	}
14080218822Sdim
14081218822Sdim      if (unified_syntax)
14082218822Sdim	as_warn (_("conditional infixes are deprecated in unified syntax"));
14083218822Sdim      affix = base + (opcode->tag - OT_odd_infix_0);
14084218822Sdim      cond = hash_find_n (arm_cond_hsh, affix, 2);
14085218822Sdim      assert (cond);
14086218822Sdim
14087218822Sdim      inst.cond = cond->value;
14088218822Sdim      return opcode;
1408989857Sobrien    }
14090218822Sdim
14091218822Sdim  /* Cannot have a conditional suffix on a mnemonic of less than two
14092218822Sdim     characters.  */
14093218822Sdim  if (end - base < 3)
14094218822Sdim    return 0;
14095218822Sdim
14096218822Sdim  /* Look for suffixed mnemonic.  */
14097218822Sdim  affix = end - 2;
14098218822Sdim  cond = hash_find_n (arm_cond_hsh, affix, 2);
14099218822Sdim  opcode = hash_find_n (arm_ops_hsh, base, affix - base);
14100218822Sdim  if (opcode && cond)
1410189857Sobrien    {
14102218822Sdim      /* step CE */
14103218822Sdim      switch (opcode->tag)
1410489857Sobrien	{
14105218822Sdim	case OT_cinfix3_legacy:
14106218822Sdim	  /* Ignore conditional suffixes matched on infix only mnemonics.  */
14107218822Sdim	  break;
1410889857Sobrien
14109218822Sdim	case OT_cinfix3:
14110218822Sdim	case OT_cinfix3_deprecated:
14111218822Sdim	case OT_odd_infix_unc:
14112218822Sdim	  if (!unified_syntax)
14113218822Sdim	    return 0;
14114218822Sdim	  /* else fall through */
1411589857Sobrien
14116218822Sdim	case OT_csuffix:
14117218822Sdim        case OT_csuffixF:
14118218822Sdim	case OT_csuf_or_in3:
14119218822Sdim	  inst.cond = cond->value;
14120218822Sdim	  return opcode;
14121218822Sdim
14122218822Sdim	case OT_unconditional:
14123218822Sdim	case OT_unconditionalF:
14124218822Sdim	  if (thumb_mode)
14125218822Sdim	    {
14126218822Sdim	      inst.cond = cond->value;
14127218822Sdim	    }
14128218822Sdim	  else
14129218822Sdim	    {
14130218822Sdim	      /* delayed diagnostic */
14131218822Sdim	      inst.error = BAD_COND;
14132218822Sdim	      inst.cond = COND_ALWAYS;
14133218822Sdim	    }
14134218822Sdim	  return opcode;
14135218822Sdim
14136218822Sdim	default:
14137218822Sdim	  return 0;
14138218822Sdim	}
1413989857Sobrien    }
1414089857Sobrien
14141218822Sdim  /* Cannot have a usual-position infix on a mnemonic of less than
14142218822Sdim     six characters (five would be a suffix).  */
14143218822Sdim  if (end - base < 6)
14144218822Sdim    return 0;
1414589857Sobrien
14146218822Sdim  /* Look for infixed mnemonic in the usual position.  */
14147218822Sdim  affix = base + 3;
14148218822Sdim  cond = hash_find_n (arm_cond_hsh, affix, 2);
14149218822Sdim  if (!cond)
14150218822Sdim    return 0;
1415189857Sobrien
14152218822Sdim  memcpy (save, affix, 2);
14153218822Sdim  memmove (affix, affix + 2, (end - affix) - 2);
14154218822Sdim  opcode = hash_find_n (arm_ops_hsh, base, (end - base) - 2);
14155218822Sdim  memmove (affix + 2, affix, (end - affix) - 2);
14156218822Sdim  memcpy (affix, save, 2);
14157218822Sdim
14158218822Sdim  if (opcode
14159218822Sdim      && (opcode->tag == OT_cinfix3
14160218822Sdim	  || opcode->tag == OT_cinfix3_deprecated
14161218822Sdim	  || opcode->tag == OT_csuf_or_in3
14162218822Sdim	  || opcode->tag == OT_cinfix3_legacy))
14163218822Sdim    {
14164218822Sdim      /* step CM */
14165218822Sdim      if (unified_syntax
14166218822Sdim	  && (opcode->tag == OT_cinfix3
14167218822Sdim	      || opcode->tag == OT_cinfix3_deprecated))
14168218822Sdim	as_warn (_("conditional infixes are deprecated in unified syntax"));
14169218822Sdim
14170218822Sdim      inst.cond = cond->value;
14171218822Sdim      return opcode;
14172218822Sdim    }
14173218822Sdim
14174218822Sdim  return 0;
1417589857Sobrien}
1417689857Sobrien
14177218822Sdimvoid
14178218822Sdimmd_assemble (char *str)
1417960484Sobrien{
14180218822Sdim  char *p = str;
14181218822Sdim  const struct asm_opcode * opcode;
1418260484Sobrien
14183218822Sdim  /* Align the previous label if needed.  */
14184218822Sdim  if (last_label_seen != NULL)
14185218822Sdim    {
14186218822Sdim      symbol_set_frag (last_label_seen, frag_now);
14187218822Sdim      S_SET_VALUE (last_label_seen, (valueT) frag_now_fix ());
14188218822Sdim      S_SET_SEGMENT (last_label_seen, now_seg);
14189218822Sdim    }
1419077298Sobrien
14191218822Sdim  memset (&inst, '\0', sizeof (inst));
14192218822Sdim  inst.reloc.type = BFD_RELOC_UNUSED;
1419360484Sobrien
14194218822Sdim  opcode = opcode_lookup (&p);
14195218822Sdim  if (!opcode)
14196218822Sdim    {
14197218822Sdim      /* It wasn't an instruction, but it might be a register alias of
14198218822Sdim	 the form alias .req reg, or a Neon .dn/.qn directive.  */
14199218822Sdim      if (!create_register_alias (str, p)
14200218822Sdim          && !create_neon_reg_alias (str, p))
14201218822Sdim	as_bad (_("bad instruction `%s'"), str);
1420260484Sobrien
1420377298Sobrien      return;
1420460484Sobrien    }
1420560484Sobrien
14206218822Sdim  if (opcode->tag == OT_cinfix3_deprecated)
14207218822Sdim    as_warn (_("s suffix on comparison instruction is deprecated"));
14208218822Sdim
14209218822Sdim  /* The value which unconditional instructions should have in place of the
14210218822Sdim     condition field.  */
14211218822Sdim  inst.uncond_value = (opcode->tag == OT_csuffixF) ? 0xf : -1;
14212218822Sdim
14213218822Sdim  if (thumb_mode)
1421460484Sobrien    {
14215218822Sdim      arm_feature_set variant;
14216218822Sdim
14217218822Sdim      variant = cpu_variant;
14218218822Sdim      /* Only allow coprocessor instructions on Thumb-2 capable devices.  */
14219218822Sdim      if (!ARM_CPU_HAS_FEATURE (variant, arm_arch_t2))
14220218822Sdim	ARM_CLEAR_FEATURE (variant, variant, fpu_any_hard);
14221218822Sdim      /* Check that this instruction is supported for this CPU.  */
14222218822Sdim      if (!opcode->tvariant
14223218822Sdim	  || (thumb_mode == 1
14224218822Sdim	      && !ARM_CPU_HAS_FEATURE (variant, *opcode->tvariant)))
1422560484Sobrien	{
14226218822Sdim	  as_bad (_("selected processor does not support `%s'"), str);
1422760484Sobrien	  return;
1422860484Sobrien	}
14229218822Sdim      if (inst.cond != COND_ALWAYS && !unified_syntax
14230218822Sdim	  && opcode->tencode != do_t_branch)
14231218822Sdim	{
14232218822Sdim	  as_bad (_("Thumb does not support conditional execution"));
14233218822Sdim	  return;
14234218822Sdim	}
1423560484Sobrien
14236218822Sdim      if (!ARM_CPU_HAS_FEATURE (variant, arm_ext_v6t2) && !inst.size_req)
14237218822Sdim	{
14238218822Sdim	  /* Implicit require narrow instructions on Thumb-1.  This avoids
14239218822Sdim	     relaxation accidentally introducing Thumb-2 instructions.  */
14240218822Sdim	  if (opcode->tencode != do_t_blx && opcode->tencode != do_t_branch23)
14241218822Sdim	    inst.size_req = 2;
14242218822Sdim	}
1424360484Sobrien
14244218822Sdim      /* Check conditional suffixes.  */
14245218822Sdim      if (current_it_mask)
1424660484Sobrien	{
14247218822Sdim	  int cond;
14248218822Sdim	  cond = current_cc ^ ((current_it_mask >> 4) & 1) ^ 1;
14249218822Sdim	  current_it_mask <<= 1;
14250218822Sdim	  current_it_mask &= 0x1f;
14251218822Sdim	  /* The BKPT instruction is unconditional even in an IT block.  */
14252218822Sdim	  if (!inst.error
14253218822Sdim	      && cond != inst.cond && opcode->tencode != do_t_bkpt)
14254218822Sdim	    {
14255218822Sdim	      as_bad (_("incorrect condition in IT block"));
14256218822Sdim	      return;
14257218822Sdim	    }
14258218822Sdim	}
14259218822Sdim      else if (inst.cond != COND_ALWAYS && opcode->tencode != do_t_branch)
14260218822Sdim	{
14261218822Sdim	  as_bad (_("thumb conditional instrunction not in IT block"));
1426260484Sobrien	  return;
1426360484Sobrien	}
1426460484Sobrien
14265218822Sdim      mapping_state (MAP_THUMB);
14266218822Sdim      inst.instruction = opcode->tvalue;
1426760484Sobrien
14268218822Sdim      if (!parse_operands (p, opcode->operands))
14269218822Sdim	opcode->tencode ();
1427060484Sobrien
14271218822Sdim      /* Clear current_it_mask at the end of an IT block.  */
14272218822Sdim      if (current_it_mask == 0x10)
14273218822Sdim	current_it_mask = 0;
1427460484Sobrien
14275218822Sdim      if (!(inst.error || inst.relax))
14276218822Sdim	{
14277218822Sdim	  assert (inst.instruction < 0xe800 || inst.instruction > 0xffff);
14278218822Sdim	  inst.size = (inst.instruction > 0xffff ? 4 : 2);
14279218822Sdim	  if (inst.size_req && inst.size_req != inst.size)
14280218822Sdim	    {
14281218822Sdim	      as_bad (_("cannot honor width suffix -- `%s'"), str);
14282218822Sdim	      return;
14283218822Sdim	    }
14284218822Sdim	}
14285218822Sdim
14286218822Sdim      /* Something has gone badly wrong if we try to relax a fixed size
14287218822Sdim         instruction.  */
14288218822Sdim      assert (inst.size_req == 0 || !inst.relax);
14289218822Sdim
14290218822Sdim      ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
14291218822Sdim			      *opcode->tvariant);
14292218822Sdim      /* Many Thumb-2 instructions also have Thumb-1 variants, so explicitly
14293218822Sdim	 set those bits when Thumb-2 32-bit instructions are seen.  ie.
14294218822Sdim	 anything other than bl/blx.
14295218822Sdim	 This is overly pessimistic for relaxable instructions.  */
14296218822Sdim      if ((inst.size == 4 && (inst.instruction & 0xf800e800) != 0xf000e800)
14297218822Sdim	  || inst.relax)
14298218822Sdim	ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
14299218822Sdim				arm_ext_v6t2);
14300218822Sdim    }
14301218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1))
14302218822Sdim    {
14303218822Sdim      /* Check that this instruction is supported for this CPU.  */
14304218822Sdim      if (!opcode->avariant ||
14305218822Sdim	  !ARM_CPU_HAS_FEATURE (cpu_variant, *opcode->avariant))
14306218822Sdim	{
14307218822Sdim	  as_bad (_("selected processor does not support `%s'"), str);
14308218822Sdim	  return;
14309218822Sdim	}
14310218822Sdim      if (inst.size_req)
14311218822Sdim	{
14312218822Sdim	  as_bad (_("width suffixes are invalid in ARM mode -- `%s'"), str);
14313218822Sdim	  return;
14314218822Sdim	}
14315218822Sdim
14316218822Sdim      mapping_state (MAP_ARM);
14317218822Sdim      inst.instruction = opcode->avalue;
14318218822Sdim      if (opcode->tag == OT_unconditionalF)
14319218822Sdim	inst.instruction |= 0xF << 28;
14320218822Sdim      else
14321218822Sdim	inst.instruction |= inst.cond << 28;
14322218822Sdim      inst.size = INSN_SIZE;
14323218822Sdim      if (!parse_operands (p, opcode->operands))
14324218822Sdim	opcode->aencode ();
14325218822Sdim      /* Arm mode bx is marked as both v4T and v5 because it's still required
14326218822Sdim         on a hypothetical non-thumb v5 core.  */
14327218822Sdim      if (ARM_CPU_HAS_FEATURE (*opcode->avariant, arm_ext_v4t)
14328218822Sdim	  || ARM_CPU_HAS_FEATURE (*opcode->avariant, arm_ext_v5))
14329218822Sdim	ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used, arm_ext_v4t);
14330218822Sdim      else
14331218822Sdim	ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used,
14332218822Sdim				*opcode->avariant);
14333218822Sdim    }
14334218822Sdim  else
14335218822Sdim    {
14336218822Sdim      as_bad (_("attempt to use an ARM instruction on a Thumb-only processor "
14337218822Sdim		"-- `%s'"), str);
14338218822Sdim      return;
14339218822Sdim    }
14340218822Sdim  output_inst (str);
1434160484Sobrien}
1434260484Sobrien
14343218822Sdim/* Various frobbings of labels and their addresses.  */
14344218822Sdim
14345218822Sdimvoid
14346218822Sdimarm_start_line_hook (void)
1434760484Sobrien{
14348218822Sdim  last_label_seen = NULL;
1434960484Sobrien}
1435060484Sobrien
14351218822Sdimvoid
14352218822Sdimarm_frob_label (symbolS * sym)
1435360484Sobrien{
14354218822Sdim  last_label_seen = sym;
1435560484Sobrien
14356218822Sdim  ARM_SET_THUMB (sym, thumb_mode);
1435760484Sobrien
14358218822Sdim#if defined OBJ_COFF || defined OBJ_ELF
14359218822Sdim  ARM_SET_INTERWORK (sym, support_interwork);
14360218822Sdim#endif
1436160484Sobrien
14362218822Sdim  /* Note - do not allow local symbols (.Lxxx) to be labeled
14363218822Sdim     as Thumb functions.  This is because these labels, whilst
14364218822Sdim     they exist inside Thumb code, are not the entry points for
14365218822Sdim     possible ARM->Thumb calls.	 Also, these labels can be used
14366218822Sdim     as part of a computed goto or switch statement.  eg gcc
14367218822Sdim     can generate code that looks like this:
1436860484Sobrien
14369218822Sdim		ldr  r2, [pc, .Laaa]
14370218822Sdim		lsl  r3, r3, #2
14371218822Sdim		ldr  r2, [r3, r2]
14372218822Sdim		mov  pc, r2
1437360484Sobrien
14374218822Sdim       .Lbbb:  .word .Lxxx
14375218822Sdim       .Lccc:  .word .Lyyy
14376218822Sdim       ..etc...
14377218822Sdim       .Laaa:	.word Lbbb
1437877298Sobrien
14379218822Sdim     The first instruction loads the address of the jump table.
14380218822Sdim     The second instruction converts a table index into a byte offset.
14381218822Sdim     The third instruction gets the jump address out of the table.
14382218822Sdim     The fourth instruction performs the jump.
1438360484Sobrien
14384218822Sdim     If the address stored at .Laaa is that of a symbol which has the
14385218822Sdim     Thumb_Func bit set, then the linker will arrange for this address
14386218822Sdim     to have the bottom bit set, which in turn would mean that the
14387218822Sdim     address computation performed by the third instruction would end
14388218822Sdim     up with the bottom bit set.  Since the ARM is capable of unaligned
14389218822Sdim     word loads, the instruction would then load the incorrect address
14390218822Sdim     out of the jump table, and chaos would ensue.  */
14391218822Sdim  if (label_is_thumb_function_name
14392218822Sdim      && (S_GET_NAME (sym)[0] != '.' || S_GET_NAME (sym)[1] != 'L')
14393218822Sdim      && (bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0)
14394218822Sdim    {
14395218822Sdim      /* When the address of a Thumb function is taken the bottom
14396218822Sdim	 bit of that address should be set.  This will allow
14397218822Sdim	 interworking between Arm and Thumb functions to work
14398218822Sdim	 correctly.  */
1439977298Sobrien
14400218822Sdim      THUMB_SET_FUNC (sym, 1);
14401218822Sdim
14402218822Sdim      label_is_thumb_function_name = FALSE;
14403218822Sdim    }
14404218822Sdim
14405218822Sdim  dwarf2_emit_label (sym);
14406218822Sdim}
14407218822Sdim
14408218822Sdimint
14409218822Sdimarm_data_in_code (void)
14410218822Sdim{
14411218822Sdim  if (thumb_mode && ! strncmp (input_line_pointer + 1, "data:", 5))
1441260484Sobrien    {
14413218822Sdim      *input_line_pointer = '/';
14414218822Sdim      input_line_pointer += 5;
14415218822Sdim      *input_line_pointer = 0;
14416218822Sdim      return 1;
1441760484Sobrien    }
1441860484Sobrien
14419218822Sdim  return 0;
1442060484Sobrien}
1442160484Sobrien
14422218822Sdimchar *
14423218822Sdimarm_canonicalize_symbol_name (char * name)
1442460484Sobrien{
14425218822Sdim  int len;
1442677298Sobrien
14427218822Sdim  if (thumb_mode && (len = strlen (name)) > 5
14428218822Sdim      && streq (name + len - 5, "/data"))
14429218822Sdim    *(name + len - 5) = 0;
1443060484Sobrien
14431218822Sdim  return name;
1443260484Sobrien}
14433218822Sdim
14434218822Sdim/* Table of all register names defined by default.  The user can
14435218822Sdim   define additional names with .req.  Note that all register names
14436218822Sdim   should appear in both upper and lowercase variants.	Some registers
14437218822Sdim   also have mixed-case names.	*/
1443860484Sobrien
14439218822Sdim#define REGDEF(s,n,t) { #s, n, REG_TYPE_##t, TRUE, 0 }
14440218822Sdim#define REGNUM(p,n,t) REGDEF(p##n, n, t)
14441218822Sdim#define REGNUM2(p,n,t) REGDEF(p##n, 2 * n, t)
14442218822Sdim#define REGSET(p,t) \
14443218822Sdim  REGNUM(p, 0,t), REGNUM(p, 1,t), REGNUM(p, 2,t), REGNUM(p, 3,t), \
14444218822Sdim  REGNUM(p, 4,t), REGNUM(p, 5,t), REGNUM(p, 6,t), REGNUM(p, 7,t), \
14445218822Sdim  REGNUM(p, 8,t), REGNUM(p, 9,t), REGNUM(p,10,t), REGNUM(p,11,t), \
14446218822Sdim  REGNUM(p,12,t), REGNUM(p,13,t), REGNUM(p,14,t), REGNUM(p,15,t)
14447218822Sdim#define REGSETH(p,t) \
14448218822Sdim  REGNUM(p,16,t), REGNUM(p,17,t), REGNUM(p,18,t), REGNUM(p,19,t), \
14449218822Sdim  REGNUM(p,20,t), REGNUM(p,21,t), REGNUM(p,22,t), REGNUM(p,23,t), \
14450218822Sdim  REGNUM(p,24,t), REGNUM(p,25,t), REGNUM(p,26,t), REGNUM(p,27,t), \
14451218822Sdim  REGNUM(p,28,t), REGNUM(p,29,t), REGNUM(p,30,t), REGNUM(p,31,t)
14452218822Sdim#define REGSET2(p,t) \
14453218822Sdim  REGNUM2(p, 0,t), REGNUM2(p, 1,t), REGNUM2(p, 2,t), REGNUM2(p, 3,t), \
14454218822Sdim  REGNUM2(p, 4,t), REGNUM2(p, 5,t), REGNUM2(p, 6,t), REGNUM2(p, 7,t), \
14455218822Sdim  REGNUM2(p, 8,t), REGNUM2(p, 9,t), REGNUM2(p,10,t), REGNUM2(p,11,t), \
14456218822Sdim  REGNUM2(p,12,t), REGNUM2(p,13,t), REGNUM2(p,14,t), REGNUM2(p,15,t)
14457218822Sdim
14458218822Sdimstatic const struct reg_entry reg_names[] =
1445960484Sobrien{
14460218822Sdim  /* ARM integer registers.  */
14461218822Sdim  REGSET(r, RN), REGSET(R, RN),
1446260484Sobrien
14463218822Sdim  /* ATPCS synonyms.  */
14464218822Sdim  REGDEF(a1,0,RN), REGDEF(a2,1,RN), REGDEF(a3, 2,RN), REGDEF(a4, 3,RN),
14465218822Sdim  REGDEF(v1,4,RN), REGDEF(v2,5,RN), REGDEF(v3, 6,RN), REGDEF(v4, 7,RN),
14466218822Sdim  REGDEF(v5,8,RN), REGDEF(v6,9,RN), REGDEF(v7,10,RN), REGDEF(v8,11,RN),
1446760484Sobrien
14468218822Sdim  REGDEF(A1,0,RN), REGDEF(A2,1,RN), REGDEF(A3, 2,RN), REGDEF(A4, 3,RN),
14469218822Sdim  REGDEF(V1,4,RN), REGDEF(V2,5,RN), REGDEF(V3, 6,RN), REGDEF(V4, 7,RN),
14470218822Sdim  REGDEF(V5,8,RN), REGDEF(V6,9,RN), REGDEF(V7,10,RN), REGDEF(V8,11,RN),
1447160484Sobrien
14472218822Sdim  /* Well-known aliases.  */
14473218822Sdim  REGDEF(wr, 7,RN), REGDEF(sb, 9,RN), REGDEF(sl,10,RN), REGDEF(fp,11,RN),
14474218822Sdim  REGDEF(ip,12,RN), REGDEF(sp,13,RN), REGDEF(lr,14,RN), REGDEF(pc,15,RN),
1447560484Sobrien
14476218822Sdim  REGDEF(WR, 7,RN), REGDEF(SB, 9,RN), REGDEF(SL,10,RN), REGDEF(FP,11,RN),
14477218822Sdim  REGDEF(IP,12,RN), REGDEF(SP,13,RN), REGDEF(LR,14,RN), REGDEF(PC,15,RN),
1447860484Sobrien
14479218822Sdim  /* Coprocessor numbers.  */
14480218822Sdim  REGSET(p, CP), REGSET(P, CP),
1448160484Sobrien
14482218822Sdim  /* Coprocessor register numbers.  The "cr" variants are for backward
14483218822Sdim     compatibility.  */
14484218822Sdim  REGSET(c,  CN), REGSET(C, CN),
14485218822Sdim  REGSET(cr, CN), REGSET(CR, CN),
1448660484Sobrien
14487218822Sdim  /* FPA registers.  */
14488218822Sdim  REGNUM(f,0,FN), REGNUM(f,1,FN), REGNUM(f,2,FN), REGNUM(f,3,FN),
14489218822Sdim  REGNUM(f,4,FN), REGNUM(f,5,FN), REGNUM(f,6,FN), REGNUM(f,7, FN),
1449060484Sobrien
14491218822Sdim  REGNUM(F,0,FN), REGNUM(F,1,FN), REGNUM(F,2,FN), REGNUM(F,3,FN),
14492218822Sdim  REGNUM(F,4,FN), REGNUM(F,5,FN), REGNUM(F,6,FN), REGNUM(F,7, FN),
1449360484Sobrien
14494218822Sdim  /* VFP SP registers.	*/
14495218822Sdim  REGSET(s,VFS),  REGSET(S,VFS),
14496218822Sdim  REGSETH(s,VFS), REGSETH(S,VFS),
1449760484Sobrien
14498218822Sdim  /* VFP DP Registers.	*/
14499218822Sdim  REGSET(d,VFD),  REGSET(D,VFD),
14500218822Sdim  /* Extra Neon DP registers.  */
14501218822Sdim  REGSETH(d,VFD), REGSETH(D,VFD),
1450260484Sobrien
14503218822Sdim  /* Neon QP registers.  */
14504218822Sdim  REGSET2(q,NQ),  REGSET2(Q,NQ),
1450560484Sobrien
14506218822Sdim  /* VFP control registers.  */
14507218822Sdim  REGDEF(fpsid,0,VFC), REGDEF(fpscr,1,VFC), REGDEF(fpexc,8,VFC),
14508218822Sdim  REGDEF(FPSID,0,VFC), REGDEF(FPSCR,1,VFC), REGDEF(FPEXC,8,VFC),
14509218822Sdim  REGDEF(fpinst,9,VFC), REGDEF(fpinst2,10,VFC),
14510218822Sdim  REGDEF(FPINST,9,VFC), REGDEF(FPINST2,10,VFC),
14511218822Sdim  REGDEF(mvfr0,7,VFC), REGDEF(mvfr1,6,VFC),
14512218822Sdim  REGDEF(MVFR0,7,VFC), REGDEF(MVFR1,6,VFC),
1451360484Sobrien
14514218822Sdim  /* Maverick DSP coprocessor registers.  */
14515218822Sdim  REGSET(mvf,MVF),  REGSET(mvd,MVD),  REGSET(mvfx,MVFX),  REGSET(mvdx,MVDX),
14516218822Sdim  REGSET(MVF,MVF),  REGSET(MVD,MVD),  REGSET(MVFX,MVFX),  REGSET(MVDX,MVDX),
1451760484Sobrien
14518218822Sdim  REGNUM(mvax,0,MVAX), REGNUM(mvax,1,MVAX),
14519218822Sdim  REGNUM(mvax,2,MVAX), REGNUM(mvax,3,MVAX),
14520218822Sdim  REGDEF(dspsc,0,DSPSC),
1452160484Sobrien
14522218822Sdim  REGNUM(MVAX,0,MVAX), REGNUM(MVAX,1,MVAX),
14523218822Sdim  REGNUM(MVAX,2,MVAX), REGNUM(MVAX,3,MVAX),
14524218822Sdim  REGDEF(DSPSC,0,DSPSC),
1452560484Sobrien
14526218822Sdim  /* iWMMXt data registers - p0, c0-15.	 */
14527218822Sdim  REGSET(wr,MMXWR), REGSET(wR,MMXWR), REGSET(WR, MMXWR),
1452860484Sobrien
14529218822Sdim  /* iWMMXt control registers - p1, c0-3.  */
14530218822Sdim  REGDEF(wcid,	0,MMXWC),  REGDEF(wCID,	 0,MMXWC),  REGDEF(WCID,  0,MMXWC),
14531218822Sdim  REGDEF(wcon,	1,MMXWC),  REGDEF(wCon,	 1,MMXWC),  REGDEF(WCON,  1,MMXWC),
14532218822Sdim  REGDEF(wcssf, 2,MMXWC),  REGDEF(wCSSF, 2,MMXWC),  REGDEF(WCSSF, 2,MMXWC),
14533218822Sdim  REGDEF(wcasf, 3,MMXWC),  REGDEF(wCASF, 3,MMXWC),  REGDEF(WCASF, 3,MMXWC),
1453460484Sobrien
14535218822Sdim  /* iWMMXt scalar (constant/offset) registers - p1, c8-11.  */
14536218822Sdim  REGDEF(wcgr0, 8,MMXWCG),  REGDEF(wCGR0, 8,MMXWCG),  REGDEF(WCGR0, 8,MMXWCG),
14537218822Sdim  REGDEF(wcgr1, 9,MMXWCG),  REGDEF(wCGR1, 9,MMXWCG),  REGDEF(WCGR1, 9,MMXWCG),
14538218822Sdim  REGDEF(wcgr2,10,MMXWCG),  REGDEF(wCGR2,10,MMXWCG),  REGDEF(WCGR2,10,MMXWCG),
14539218822Sdim  REGDEF(wcgr3,11,MMXWCG),  REGDEF(wCGR3,11,MMXWCG),  REGDEF(WCGR3,11,MMXWCG),
1454060484Sobrien
14541218822Sdim  /* XScale accumulator registers.  */
14542218822Sdim  REGNUM(acc,0,XSCALE), REGNUM(ACC,0,XSCALE),
14543218822Sdim};
14544218822Sdim#undef REGDEF
14545218822Sdim#undef REGNUM
14546218822Sdim#undef REGSET
1454760484Sobrien
14548218822Sdim/* Table of all PSR suffixes.  Bare "CPSR" and "SPSR" are handled
14549218822Sdim   within psr_required_here.  */
14550218822Sdimstatic const struct asm_psr psrs[] =
14551218822Sdim{
14552218822Sdim  /* Backward compatibility notation.  Note that "all" is no longer
14553218822Sdim     truly all possible PSR bits.  */
14554218822Sdim  {"all",  PSR_c | PSR_f},
14555218822Sdim  {"flg",  PSR_f},
14556218822Sdim  {"ctl",  PSR_c},
1455760484Sobrien
14558218822Sdim  /* Individual flags.	*/
14559218822Sdim  {"f",	   PSR_f},
14560218822Sdim  {"c",	   PSR_c},
14561218822Sdim  {"x",	   PSR_x},
14562218822Sdim  {"s",	   PSR_s},
14563218822Sdim  /* Combinations of flags.  */
14564218822Sdim  {"fs",   PSR_f | PSR_s},
14565218822Sdim  {"fx",   PSR_f | PSR_x},
14566218822Sdim  {"fc",   PSR_f | PSR_c},
14567218822Sdim  {"sf",   PSR_s | PSR_f},
14568218822Sdim  {"sx",   PSR_s | PSR_x},
14569218822Sdim  {"sc",   PSR_s | PSR_c},
14570218822Sdim  {"xf",   PSR_x | PSR_f},
14571218822Sdim  {"xs",   PSR_x | PSR_s},
14572218822Sdim  {"xc",   PSR_x | PSR_c},
14573218822Sdim  {"cf",   PSR_c | PSR_f},
14574218822Sdim  {"cs",   PSR_c | PSR_s},
14575218822Sdim  {"cx",   PSR_c | PSR_x},
14576218822Sdim  {"fsx",  PSR_f | PSR_s | PSR_x},
14577218822Sdim  {"fsc",  PSR_f | PSR_s | PSR_c},
14578218822Sdim  {"fxs",  PSR_f | PSR_x | PSR_s},
14579218822Sdim  {"fxc",  PSR_f | PSR_x | PSR_c},
14580218822Sdim  {"fcs",  PSR_f | PSR_c | PSR_s},
14581218822Sdim  {"fcx",  PSR_f | PSR_c | PSR_x},
14582218822Sdim  {"sfx",  PSR_s | PSR_f | PSR_x},
14583218822Sdim  {"sfc",  PSR_s | PSR_f | PSR_c},
14584218822Sdim  {"sxf",  PSR_s | PSR_x | PSR_f},
14585218822Sdim  {"sxc",  PSR_s | PSR_x | PSR_c},
14586218822Sdim  {"scf",  PSR_s | PSR_c | PSR_f},
14587218822Sdim  {"scx",  PSR_s | PSR_c | PSR_x},
14588218822Sdim  {"xfs",  PSR_x | PSR_f | PSR_s},
14589218822Sdim  {"xfc",  PSR_x | PSR_f | PSR_c},
14590218822Sdim  {"xsf",  PSR_x | PSR_s | PSR_f},
14591218822Sdim  {"xsc",  PSR_x | PSR_s | PSR_c},
14592218822Sdim  {"xcf",  PSR_x | PSR_c | PSR_f},
14593218822Sdim  {"xcs",  PSR_x | PSR_c | PSR_s},
14594218822Sdim  {"cfs",  PSR_c | PSR_f | PSR_s},
14595218822Sdim  {"cfx",  PSR_c | PSR_f | PSR_x},
14596218822Sdim  {"csf",  PSR_c | PSR_s | PSR_f},
14597218822Sdim  {"csx",  PSR_c | PSR_s | PSR_x},
14598218822Sdim  {"cxf",  PSR_c | PSR_x | PSR_f},
14599218822Sdim  {"cxs",  PSR_c | PSR_x | PSR_s},
14600218822Sdim  {"fsxc", PSR_f | PSR_s | PSR_x | PSR_c},
14601218822Sdim  {"fscx", PSR_f | PSR_s | PSR_c | PSR_x},
14602218822Sdim  {"fxsc", PSR_f | PSR_x | PSR_s | PSR_c},
14603218822Sdim  {"fxcs", PSR_f | PSR_x | PSR_c | PSR_s},
14604218822Sdim  {"fcsx", PSR_f | PSR_c | PSR_s | PSR_x},
14605218822Sdim  {"fcxs", PSR_f | PSR_c | PSR_x | PSR_s},
14606218822Sdim  {"sfxc", PSR_s | PSR_f | PSR_x | PSR_c},
14607218822Sdim  {"sfcx", PSR_s | PSR_f | PSR_c | PSR_x},
14608218822Sdim  {"sxfc", PSR_s | PSR_x | PSR_f | PSR_c},
14609218822Sdim  {"sxcf", PSR_s | PSR_x | PSR_c | PSR_f},
14610218822Sdim  {"scfx", PSR_s | PSR_c | PSR_f | PSR_x},
14611218822Sdim  {"scxf", PSR_s | PSR_c | PSR_x | PSR_f},
14612218822Sdim  {"xfsc", PSR_x | PSR_f | PSR_s | PSR_c},
14613218822Sdim  {"xfcs", PSR_x | PSR_f | PSR_c | PSR_s},
14614218822Sdim  {"xsfc", PSR_x | PSR_s | PSR_f | PSR_c},
14615218822Sdim  {"xscf", PSR_x | PSR_s | PSR_c | PSR_f},
14616218822Sdim  {"xcfs", PSR_x | PSR_c | PSR_f | PSR_s},
14617218822Sdim  {"xcsf", PSR_x | PSR_c | PSR_s | PSR_f},
14618218822Sdim  {"cfsx", PSR_c | PSR_f | PSR_s | PSR_x},
14619218822Sdim  {"cfxs", PSR_c | PSR_f | PSR_x | PSR_s},
14620218822Sdim  {"csfx", PSR_c | PSR_s | PSR_f | PSR_x},
14621218822Sdim  {"csxf", PSR_c | PSR_s | PSR_x | PSR_f},
14622218822Sdim  {"cxfs", PSR_c | PSR_x | PSR_f | PSR_s},
14623218822Sdim  {"cxsf", PSR_c | PSR_x | PSR_s | PSR_f},
14624218822Sdim};
1462560484Sobrien
14626218822Sdim/* Table of V7M psr names.  */
14627218822Sdimstatic const struct asm_psr v7m_psrs[] =
1462860484Sobrien{
14629218822Sdim  {"apsr",	  0 }, {"APSR",		0 },
14630218822Sdim  {"iapsr",	  1 }, {"IAPSR",	1 },
14631218822Sdim  {"eapsr",	  2 }, {"EAPSR",	2 },
14632218822Sdim  {"psr",	  3 }, {"PSR",		3 },
14633218822Sdim  {"xpsr",	  3 }, {"XPSR",		3 }, {"xPSR",	  3 },
14634218822Sdim  {"ipsr",	  5 }, {"IPSR",		5 },
14635218822Sdim  {"epsr",	  6 }, {"EPSR",		6 },
14636218822Sdim  {"iepsr",	  7 }, {"IEPSR",	7 },
14637218822Sdim  {"msp",	  8 }, {"MSP",		8 },
14638218822Sdim  {"psp",	  9 }, {"PSP",		9 },
14639218822Sdim  {"primask",	  16}, {"PRIMASK",	16},
14640218822Sdim  {"basepri",	  17}, {"BASEPRI",	17},
14641218822Sdim  {"basepri_max", 18}, {"BASEPRI_MAX",	18},
14642218822Sdim  {"faultmask",	  19}, {"FAULTMASK",	19},
14643218822Sdim  {"control",	  20}, {"CONTROL",	20}
14644218822Sdim};
1464560484Sobrien
14646218822Sdim/* Table of all shift-in-operand names.	 */
14647218822Sdimstatic const struct asm_shift_name shift_names [] =
1464860484Sobrien{
14649218822Sdim  { "asl", SHIFT_LSL },	 { "ASL", SHIFT_LSL },
14650218822Sdim  { "lsl", SHIFT_LSL },	 { "LSL", SHIFT_LSL },
14651218822Sdim  { "lsr", SHIFT_LSR },	 { "LSR", SHIFT_LSR },
14652218822Sdim  { "asr", SHIFT_ASR },	 { "ASR", SHIFT_ASR },
14653218822Sdim  { "ror", SHIFT_ROR },	 { "ROR", SHIFT_ROR },
14654218822Sdim  { "rrx", SHIFT_RRX },	 { "RRX", SHIFT_RRX }
14655218822Sdim};
1465660484Sobrien
14657218822Sdim/* Table of all explicit relocation names.  */
14658218822Sdim#ifdef OBJ_ELF
14659218822Sdimstatic struct reloc_entry reloc_names[] =
1466060484Sobrien{
14661218822Sdim  { "got",     BFD_RELOC_ARM_GOT32   },	 { "GOT",     BFD_RELOC_ARM_GOT32   },
14662218822Sdim  { "gotoff",  BFD_RELOC_ARM_GOTOFF  },	 { "GOTOFF",  BFD_RELOC_ARM_GOTOFF  },
14663218822Sdim  { "plt",     BFD_RELOC_ARM_PLT32   },	 { "PLT",     BFD_RELOC_ARM_PLT32   },
14664218822Sdim  { "target1", BFD_RELOC_ARM_TARGET1 },	 { "TARGET1", BFD_RELOC_ARM_TARGET1 },
14665218822Sdim  { "target2", BFD_RELOC_ARM_TARGET2 },	 { "TARGET2", BFD_RELOC_ARM_TARGET2 },
14666218822Sdim  { "sbrel",   BFD_RELOC_ARM_SBREL32 },	 { "SBREL",   BFD_RELOC_ARM_SBREL32 },
14667218822Sdim  { "tlsgd",   BFD_RELOC_ARM_TLS_GD32},  { "TLSGD",   BFD_RELOC_ARM_TLS_GD32},
14668218822Sdim  { "tlsldm",  BFD_RELOC_ARM_TLS_LDM32}, { "TLSLDM",  BFD_RELOC_ARM_TLS_LDM32},
14669218822Sdim  { "tlsldo",  BFD_RELOC_ARM_TLS_LDO32}, { "TLSLDO",  BFD_RELOC_ARM_TLS_LDO32},
14670218822Sdim  { "gottpoff",BFD_RELOC_ARM_TLS_IE32},  { "GOTTPOFF",BFD_RELOC_ARM_TLS_IE32},
14671218822Sdim  { "tpoff",   BFD_RELOC_ARM_TLS_LE32},  { "TPOFF",   BFD_RELOC_ARM_TLS_LE32}
14672218822Sdim};
14673218822Sdim#endif
1467460484Sobrien
14675218822Sdim/* Table of all conditional affixes.  0xF is not defined as a condition code.  */
14676218822Sdimstatic const struct asm_cond conds[] =
1467760484Sobrien{
14678218822Sdim  {"eq", 0x0},
14679218822Sdim  {"ne", 0x1},
14680218822Sdim  {"cs", 0x2}, {"hs", 0x2},
14681218822Sdim  {"cc", 0x3}, {"ul", 0x3}, {"lo", 0x3},
14682218822Sdim  {"mi", 0x4},
14683218822Sdim  {"pl", 0x5},
14684218822Sdim  {"vs", 0x6},
14685218822Sdim  {"vc", 0x7},
14686218822Sdim  {"hi", 0x8},
14687218822Sdim  {"ls", 0x9},
14688218822Sdim  {"ge", 0xa},
14689218822Sdim  {"lt", 0xb},
14690218822Sdim  {"gt", 0xc},
14691218822Sdim  {"le", 0xd},
14692218822Sdim  {"al", 0xe}
14693218822Sdim};
1469460484Sobrien
14695218822Sdimstatic struct asm_barrier_opt barrier_opt_names[] =
14696218822Sdim{
14697218822Sdim  { "sy",   0xf },
14698218822Sdim  { "un",   0x7 },
14699218822Sdim  { "st",   0xe },
14700218822Sdim  { "unst", 0x6 }
14701218822Sdim};
1470260484Sobrien
14703218822Sdim/* Table of ARM-format instructions.	*/
1470460484Sobrien
14705218822Sdim/* Macros for gluing together operand strings.  N.B. In all cases
14706218822Sdim   other than OPS0, the trailing OP_stop comes from default
14707218822Sdim   zero-initialization of the unspecified elements of the array.  */
14708218822Sdim#define OPS0()		  { OP_stop, }
14709218822Sdim#define OPS1(a)		  { OP_##a, }
14710218822Sdim#define OPS2(a,b)	  { OP_##a,OP_##b, }
14711218822Sdim#define OPS3(a,b,c)	  { OP_##a,OP_##b,OP_##c, }
14712218822Sdim#define OPS4(a,b,c,d)	  { OP_##a,OP_##b,OP_##c,OP_##d, }
14713218822Sdim#define OPS5(a,b,c,d,e)	  { OP_##a,OP_##b,OP_##c,OP_##d,OP_##e, }
14714218822Sdim#define OPS6(a,b,c,d,e,f) { OP_##a,OP_##b,OP_##c,OP_##d,OP_##e,OP_##f, }
1471560484Sobrien
14716218822Sdim/* These macros abstract out the exact format of the mnemonic table and
14717218822Sdim   save some repeated characters.  */
1471860484Sobrien
14719218822Sdim/* The normal sort of mnemonic; has a Thumb variant; takes a conditional suffix.  */
14720218822Sdim#define TxCE(mnem, op, top, nops, ops, ae, te) \
14721218822Sdim  { #mnem, OPS##nops ops, OT_csuffix, 0x##op, top, ARM_VARIANT, \
14722218822Sdim    THUMB_VARIANT, do_##ae, do_##te }
1472360484Sobrien
14724218822Sdim/* Two variants of the above - TCE for a numeric Thumb opcode, tCE for
14725218822Sdim   a T_MNEM_xyz enumerator.  */
14726218822Sdim#define TCE(mnem, aop, top, nops, ops, ae, te) \
14727218822Sdim       TxCE(mnem, aop, 0x##top, nops, ops, ae, te)
14728218822Sdim#define tCE(mnem, aop, top, nops, ops, ae, te) \
14729218822Sdim       TxCE(mnem, aop, T_MNEM_##top, nops, ops, ae, te)
1473060484Sobrien
14731218822Sdim/* Second most common sort of mnemonic: has a Thumb variant, takes a conditional
14732218822Sdim   infix after the third character.  */
14733218822Sdim#define TxC3(mnem, op, top, nops, ops, ae, te) \
14734218822Sdim  { #mnem, OPS##nops ops, OT_cinfix3, 0x##op, top, ARM_VARIANT, \
14735218822Sdim    THUMB_VARIANT, do_##ae, do_##te }
14736218822Sdim#define TxC3w(mnem, op, top, nops, ops, ae, te) \
14737218822Sdim  { #mnem, OPS##nops ops, OT_cinfix3_deprecated, 0x##op, top, ARM_VARIANT, \
14738218822Sdim    THUMB_VARIANT, do_##ae, do_##te }
14739218822Sdim#define TC3(mnem, aop, top, nops, ops, ae, te) \
14740218822Sdim       TxC3(mnem, aop, 0x##top, nops, ops, ae, te)
14741218822Sdim#define TC3w(mnem, aop, top, nops, ops, ae, te) \
14742218822Sdim       TxC3w(mnem, aop, 0x##top, nops, ops, ae, te)
14743218822Sdim#define tC3(mnem, aop, top, nops, ops, ae, te) \
14744218822Sdim       TxC3(mnem, aop, T_MNEM_##top, nops, ops, ae, te)
14745218822Sdim#define tC3w(mnem, aop, top, nops, ops, ae, te) \
14746218822Sdim       TxC3w(mnem, aop, T_MNEM_##top, nops, ops, ae, te)
1474760484Sobrien
14748218822Sdim/* Mnemonic with a conditional infix in an unusual place.  Each and every variant has to
14749218822Sdim   appear in the condition table.  */
14750218822Sdim#define TxCM_(m1, m2, m3, op, top, nops, ops, ae, te)	\
14751218822Sdim  { #m1 #m2 #m3, OPS##nops ops, sizeof(#m2) == 1 ? OT_odd_infix_unc : OT_odd_infix_0 + sizeof(#m1) - 1, \
14752218822Sdim    0x##op, top, ARM_VARIANT, THUMB_VARIANT, do_##ae, do_##te }
1475360484Sobrien
14754218822Sdim#define TxCM(m1, m2, op, top, nops, ops, ae, te)	\
14755218822Sdim  TxCM_(m1,   , m2, op, top, nops, ops, ae, te),	\
14756218822Sdim  TxCM_(m1, eq, m2, op, top, nops, ops, ae, te),	\
14757218822Sdim  TxCM_(m1, ne, m2, op, top, nops, ops, ae, te),	\
14758218822Sdim  TxCM_(m1, cs, m2, op, top, nops, ops, ae, te),	\
14759218822Sdim  TxCM_(m1, hs, m2, op, top, nops, ops, ae, te),	\
14760218822Sdim  TxCM_(m1, cc, m2, op, top, nops, ops, ae, te),	\
14761218822Sdim  TxCM_(m1, ul, m2, op, top, nops, ops, ae, te),	\
14762218822Sdim  TxCM_(m1, lo, m2, op, top, nops, ops, ae, te),	\
14763218822Sdim  TxCM_(m1, mi, m2, op, top, nops, ops, ae, te),	\
14764218822Sdim  TxCM_(m1, pl, m2, op, top, nops, ops, ae, te),	\
14765218822Sdim  TxCM_(m1, vs, m2, op, top, nops, ops, ae, te),	\
14766218822Sdim  TxCM_(m1, vc, m2, op, top, nops, ops, ae, te),	\
14767218822Sdim  TxCM_(m1, hi, m2, op, top, nops, ops, ae, te),	\
14768218822Sdim  TxCM_(m1, ls, m2, op, top, nops, ops, ae, te),	\
14769218822Sdim  TxCM_(m1, ge, m2, op, top, nops, ops, ae, te),	\
14770218822Sdim  TxCM_(m1, lt, m2, op, top, nops, ops, ae, te),	\
14771218822Sdim  TxCM_(m1, gt, m2, op, top, nops, ops, ae, te),	\
14772218822Sdim  TxCM_(m1, le, m2, op, top, nops, ops, ae, te),	\
14773218822Sdim  TxCM_(m1, al, m2, op, top, nops, ops, ae, te)
1477460484Sobrien
14775218822Sdim#define TCM(m1,m2, aop, top, nops, ops, ae, te)		\
14776218822Sdim       TxCM(m1,m2, aop, 0x##top, nops, ops, ae, te)
14777218822Sdim#define tCM(m1,m2, aop, top, nops, ops, ae, te)			\
14778218822Sdim       TxCM(m1,m2, aop, T_MNEM_##top, nops, ops, ae, te)
1477960484Sobrien
14780218822Sdim/* Mnemonic that cannot be conditionalized.  The ARM condition-code
14781218822Sdim   field is still 0xE.  Many of the Thumb variants can be executed
14782218822Sdim   conditionally, so this is checked separately.  */
14783218822Sdim#define TUE(mnem, op, top, nops, ops, ae, te)				\
14784218822Sdim  { #mnem, OPS##nops ops, OT_unconditional, 0x##op, 0x##top, ARM_VARIANT, \
14785218822Sdim    THUMB_VARIANT, do_##ae, do_##te }
1478660484Sobrien
14787218822Sdim/* Mnemonic that cannot be conditionalized, and bears 0xF in its ARM
14788218822Sdim   condition code field.  */
14789218822Sdim#define TUF(mnem, op, top, nops, ops, ae, te)				\
14790218822Sdim  { #mnem, OPS##nops ops, OT_unconditionalF, 0x##op, 0x##top, ARM_VARIANT, \
14791218822Sdim    THUMB_VARIANT, do_##ae, do_##te }
1479260484Sobrien
14793218822Sdim/* ARM-only variants of all the above.  */
14794218822Sdim#define CE(mnem,  op, nops, ops, ae)	\
14795218822Sdim  { #mnem, OPS##nops ops, OT_csuffix, 0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
1479660484Sobrien
14797218822Sdim#define C3(mnem, op, nops, ops, ae)	\
14798218822Sdim  { #mnem, OPS##nops ops, OT_cinfix3, 0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
1479960484Sobrien
14800218822Sdim/* Legacy mnemonics that always have conditional infix after the third
14801218822Sdim   character.  */
14802218822Sdim#define CL(mnem, op, nops, ops, ae)	\
14803218822Sdim  { #mnem, OPS##nops ops, OT_cinfix3_legacy, \
14804218822Sdim    0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
1480560484Sobrien
14806218822Sdim/* Coprocessor instructions.  Isomorphic between Arm and Thumb-2.  */
14807218822Sdim#define cCE(mnem,  op, nops, ops, ae)	\
14808218822Sdim  { #mnem, OPS##nops ops, OT_csuffix, 0x##op, 0xe##op, ARM_VARIANT, ARM_VARIANT, do_##ae, do_##ae }
1480977298Sobrien
14810218822Sdim/* Legacy coprocessor instructions where conditional infix and conditional
14811218822Sdim   suffix are ambiguous.  For consistency this includes all FPA instructions,
14812218822Sdim   not just the potentially ambiguous ones.  */
14813218822Sdim#define cCL(mnem, op, nops, ops, ae)	\
14814218822Sdim  { #mnem, OPS##nops ops, OT_cinfix3_legacy, \
14815218822Sdim    0x##op, 0xe##op, ARM_VARIANT, ARM_VARIANT, do_##ae, do_##ae }
1481660484Sobrien
14817218822Sdim/* Coprocessor, takes either a suffix or a position-3 infix
14818218822Sdim   (for an FPA corner case). */
14819218822Sdim#define C3E(mnem, op, nops, ops, ae) \
14820218822Sdim  { #mnem, OPS##nops ops, OT_csuf_or_in3, \
14821218822Sdim    0x##op, 0xe##op, ARM_VARIANT, ARM_VARIANT, do_##ae, do_##ae }
1482260484Sobrien
14823218822Sdim#define xCM_(m1, m2, m3, op, nops, ops, ae)	\
14824218822Sdim  { #m1 #m2 #m3, OPS##nops ops, \
14825218822Sdim    sizeof(#m2) == 1 ? OT_odd_infix_unc : OT_odd_infix_0 + sizeof(#m1) - 1, \
14826218822Sdim    0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
1482760484Sobrien
14828218822Sdim#define CM(m1, m2, op, nops, ops, ae)	\
14829218822Sdim  xCM_(m1,   , m2, op, nops, ops, ae),	\
14830218822Sdim  xCM_(m1, eq, m2, op, nops, ops, ae),	\
14831218822Sdim  xCM_(m1, ne, m2, op, nops, ops, ae),	\
14832218822Sdim  xCM_(m1, cs, m2, op, nops, ops, ae),	\
14833218822Sdim  xCM_(m1, hs, m2, op, nops, ops, ae),	\
14834218822Sdim  xCM_(m1, cc, m2, op, nops, ops, ae),	\
14835218822Sdim  xCM_(m1, ul, m2, op, nops, ops, ae),	\
14836218822Sdim  xCM_(m1, lo, m2, op, nops, ops, ae),	\
14837218822Sdim  xCM_(m1, mi, m2, op, nops, ops, ae),	\
14838218822Sdim  xCM_(m1, pl, m2, op, nops, ops, ae),	\
14839218822Sdim  xCM_(m1, vs, m2, op, nops, ops, ae),	\
14840218822Sdim  xCM_(m1, vc, m2, op, nops, ops, ae),	\
14841218822Sdim  xCM_(m1, hi, m2, op, nops, ops, ae),	\
14842218822Sdim  xCM_(m1, ls, m2, op, nops, ops, ae),	\
14843218822Sdim  xCM_(m1, ge, m2, op, nops, ops, ae),	\
14844218822Sdim  xCM_(m1, lt, m2, op, nops, ops, ae),	\
14845218822Sdim  xCM_(m1, gt, m2, op, nops, ops, ae),	\
14846218822Sdim  xCM_(m1, le, m2, op, nops, ops, ae),	\
14847218822Sdim  xCM_(m1, al, m2, op, nops, ops, ae)
1484860484Sobrien
14849218822Sdim#define UE(mnem, op, nops, ops, ae)	\
14850218822Sdim  { #mnem, OPS##nops ops, OT_unconditional, 0x##op, 0, ARM_VARIANT, 0, do_##ae, NULL }
1485160484Sobrien
14852218822Sdim#define UF(mnem, op, nops, ops, ae)	\
14853218822Sdim  { #mnem, OPS##nops ops, OT_unconditionalF, 0x##op, 0, ARM_VARIANT, 0, do_##ae, NULL }
1485460484Sobrien
14855218822Sdim/* Neon data-processing. ARM versions are unconditional with cond=0xf.
14856218822Sdim   The Thumb and ARM variants are mostly the same (bits 0-23 and 24/28), so we
14857218822Sdim   use the same encoding function for each.  */
14858218822Sdim#define NUF(mnem, op, nops, ops, enc)					\
14859218822Sdim  { #mnem, OPS##nops ops, OT_unconditionalF, 0x##op, 0x##op,		\
14860218822Sdim    ARM_VARIANT, THUMB_VARIANT, do_##enc, do_##enc }
1486160484Sobrien
14862218822Sdim/* Neon data processing, version which indirects through neon_enc_tab for
14863218822Sdim   the various overloaded versions of opcodes.  */
14864218822Sdim#define nUF(mnem, op, nops, ops, enc)					\
14865218822Sdim  { #mnem, OPS##nops ops, OT_unconditionalF, N_MNEM_##op, N_MNEM_##op,	\
14866218822Sdim    ARM_VARIANT, THUMB_VARIANT, do_##enc, do_##enc }
14867218822Sdim
14868218822Sdim/* Neon insn with conditional suffix for the ARM version, non-overloaded
14869218822Sdim   version.  */
14870218822Sdim#define NCE_tag(mnem, op, nops, ops, enc, tag)				\
14871218822Sdim  { #mnem, OPS##nops ops, tag, 0x##op, 0x##op, ARM_VARIANT,		\
14872218822Sdim    THUMB_VARIANT, do_##enc, do_##enc }
14873218822Sdim
14874218822Sdim#define NCE(mnem, op, nops, ops, enc)					\
14875218822Sdim  NCE_tag(mnem, op, nops, ops, enc, OT_csuffix)
14876218822Sdim
14877218822Sdim#define NCEF(mnem, op, nops, ops, enc)					\
14878218822Sdim  NCE_tag(mnem, op, nops, ops, enc, OT_csuffixF)
14879218822Sdim
14880218822Sdim/* Neon insn with conditional suffix for the ARM version, overloaded types.  */
14881218822Sdim#define nCE_tag(mnem, op, nops, ops, enc, tag)				\
14882218822Sdim  { #mnem, OPS##nops ops, tag, N_MNEM_##op, N_MNEM_##op,		\
14883218822Sdim    ARM_VARIANT, THUMB_VARIANT, do_##enc, do_##enc }
14884218822Sdim
14885218822Sdim#define nCE(mnem, op, nops, ops, enc)					\
14886218822Sdim  nCE_tag(mnem, op, nops, ops, enc, OT_csuffix)
14887218822Sdim
14888218822Sdim#define nCEF(mnem, op, nops, ops, enc)					\
14889218822Sdim  nCE_tag(mnem, op, nops, ops, enc, OT_csuffixF)
14890218822Sdim
14891218822Sdim#define do_0 0
14892218822Sdim
14893218822Sdim/* Thumb-only, unconditional.  */
14894218822Sdim#define UT(mnem,  op, nops, ops, te) TUE(mnem,  0, op, nops, ops, 0, te)
14895218822Sdim
14896218822Sdimstatic const struct asm_opcode insns[] =
1489789857Sobrien{
14898218822Sdim#define ARM_VARIANT &arm_ext_v1 /* Core ARM Instructions.  */
14899218822Sdim#define THUMB_VARIANT &arm_ext_v4t
14900218822Sdim tCE(and,	0000000, and,      3, (RR, oRR, SH), arit, t_arit3c),
14901218822Sdim tC3(ands,	0100000, ands,	   3, (RR, oRR, SH), arit, t_arit3c),
14902218822Sdim tCE(eor,	0200000, eor,	   3, (RR, oRR, SH), arit, t_arit3c),
14903218822Sdim tC3(eors,	0300000, eors,	   3, (RR, oRR, SH), arit, t_arit3c),
14904218822Sdim tCE(sub,	0400000, sub,	   3, (RR, oRR, SH), arit, t_add_sub),
14905218822Sdim tC3(subs,	0500000, subs,	   3, (RR, oRR, SH), arit, t_add_sub),
14906218822Sdim tCE(add,	0800000, add,	   3, (RR, oRR, SHG), arit, t_add_sub),
14907218822Sdim tC3(adds,	0900000, adds,	   3, (RR, oRR, SHG), arit, t_add_sub),
14908218822Sdim tCE(adc,	0a00000, adc,	   3, (RR, oRR, SH), arit, t_arit3c),
14909218822Sdim tC3(adcs,	0b00000, adcs,	   3, (RR, oRR, SH), arit, t_arit3c),
14910218822Sdim tCE(sbc,	0c00000, sbc,	   3, (RR, oRR, SH), arit, t_arit3),
14911218822Sdim tC3(sbcs,	0d00000, sbcs,	   3, (RR, oRR, SH), arit, t_arit3),
14912218822Sdim tCE(orr,	1800000, orr,	   3, (RR, oRR, SH), arit, t_arit3c),
14913218822Sdim tC3(orrs,	1900000, orrs,	   3, (RR, oRR, SH), arit, t_arit3c),
14914218822Sdim tCE(bic,	1c00000, bic,	   3, (RR, oRR, SH), arit, t_arit3),
14915218822Sdim tC3(bics,	1d00000, bics,	   3, (RR, oRR, SH), arit, t_arit3),
1491689857Sobrien
14917218822Sdim /* The p-variants of tst/cmp/cmn/teq (below) are the pre-V6 mechanism
14918218822Sdim    for setting PSR flag bits.  They are obsolete in V6 and do not
14919218822Sdim    have Thumb equivalents. */
14920218822Sdim tCE(tst,	1100000, tst,	   2, (RR, SH),      cmp,  t_mvn_tst),
14921218822Sdim tC3w(tsts,	1100000, tst,	   2, (RR, SH),      cmp,  t_mvn_tst),
14922218822Sdim  CL(tstp,	110f000,     	   2, (RR, SH),      cmp),
14923218822Sdim tCE(cmp,	1500000, cmp,	   2, (RR, SH),      cmp,  t_mov_cmp),
14924218822Sdim tC3w(cmps,	1500000, cmp,	   2, (RR, SH),      cmp,  t_mov_cmp),
14925218822Sdim  CL(cmpp,	150f000,     	   2, (RR, SH),      cmp),
14926218822Sdim tCE(cmn,	1700000, cmn,	   2, (RR, SH),      cmp,  t_mvn_tst),
14927218822Sdim tC3w(cmns,	1700000, cmn,	   2, (RR, SH),      cmp,  t_mvn_tst),
14928218822Sdim  CL(cmnp,	170f000,     	   2, (RR, SH),      cmp),
1492989857Sobrien
14930218822Sdim tCE(mov,	1a00000, mov,	   2, (RR, SH),      mov,  t_mov_cmp),
14931218822Sdim tC3(movs,	1b00000, movs,	   2, (RR, SH),      mov,  t_mov_cmp),
14932218822Sdim tCE(mvn,	1e00000, mvn,	   2, (RR, SH),      mov,  t_mvn_tst),
14933218822Sdim tC3(mvns,	1f00000, mvns,	   2, (RR, SH),      mov,  t_mvn_tst),
14934218822Sdim
14935218822Sdim tCE(ldr,	4100000, ldr,	   2, (RR, ADDRGLDR),ldst, t_ldst),
14936218822Sdim tC3(ldrb,	4500000, ldrb,	   2, (RR, ADDRGLDR),ldst, t_ldst),
14937218822Sdim tCE(str,	4000000, str,	   2, (RR, ADDRGLDR),ldst, t_ldst),
14938218822Sdim tC3(strb,	4400000, strb,	   2, (RR, ADDRGLDR),ldst, t_ldst),
14939218822Sdim
14940218822Sdim tCE(stm,	8800000, stmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
14941218822Sdim tC3(stmia,	8800000, stmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
14942218822Sdim tC3(stmea,	8800000, stmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
14943218822Sdim tCE(ldm,	8900000, ldmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
14944218822Sdim tC3(ldmia,	8900000, ldmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
14945218822Sdim tC3(ldmfd,	8900000, ldmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
14946218822Sdim
14947218822Sdim TCE(swi,	f000000, df00,     1, (EXPi),        swi, t_swi),
14948218822Sdim TCE(svc,	f000000, df00,     1, (EXPi),        swi, t_swi),
14949218822Sdim tCE(b,		a000000, b,	   1, (EXPr),	     branch, t_branch),
14950218822Sdim TCE(bl,	b000000, f000f800, 1, (EXPr),	     bl, t_branch23),
14951218822Sdim
14952218822Sdim  /* Pseudo ops.  */
14953218822Sdim tCE(adr,	28f0000, adr,	   2, (RR, EXP),     adr,  t_adr),
14954218822Sdim  C3(adrl,	28f0000,           2, (RR, EXP),     adrl),
14955218822Sdim tCE(nop,	1a00000, nop,	   1, (oI255c),	     nop,  t_nop),
14956218822Sdim
14957218822Sdim  /* Thumb-compatibility pseudo ops.  */
14958218822Sdim tCE(lsl,	1a00000, lsl,	   3, (RR, oRR, SH), shift, t_shift),
14959218822Sdim tC3(lsls,	1b00000, lsls,	   3, (RR, oRR, SH), shift, t_shift),
14960218822Sdim tCE(lsr,	1a00020, lsr,	   3, (RR, oRR, SH), shift, t_shift),
14961218822Sdim tC3(lsrs,	1b00020, lsrs,	   3, (RR, oRR, SH), shift, t_shift),
14962218822Sdim tCE(asr,	1a00040, asr,	   3, (RR, oRR, SH), shift, t_shift),
14963218822Sdim tC3(asrs,      1b00040, asrs,     3, (RR, oRR, SH), shift, t_shift),
14964218822Sdim tCE(ror,	1a00060, ror,	   3, (RR, oRR, SH), shift, t_shift),
14965218822Sdim tC3(rors,	1b00060, rors,	   3, (RR, oRR, SH), shift, t_shift),
14966218822Sdim tCE(neg,	2600000, neg,	   2, (RR, RR),      rd_rn, t_neg),
14967218822Sdim tC3(negs,	2700000, negs,	   2, (RR, RR),      rd_rn, t_neg),
14968218822Sdim tCE(push,	92d0000, push,     1, (REGLST),	     push_pop, t_push_pop),
14969218822Sdim tCE(pop,	8bd0000, pop,	   1, (REGLST),	     push_pop, t_push_pop),
14970218822Sdim
14971218822Sdim /* These may simplify to neg.  */
14972218822Sdim TCE(rsb,	0600000, ebc00000, 3, (RR, oRR, SH), arit, t_rsb),
14973218822Sdim TC3(rsbs,	0700000, ebd00000, 3, (RR, oRR, SH), arit, t_rsb),
14974218822Sdim
14975223484Sdim TCE(rrx,      1a00060, ea4f0030, 2, (RR, RR),      rd_rm, t_rd_rm),
14976223484Sdim TCE(rrxs,     1b00060, ea5f0030, 2, (RR, RR),      rd_rm, t_rd_rm),
14977223484Sdim
14978218822Sdim#undef THUMB_VARIANT
14979218822Sdim#define THUMB_VARIANT &arm_ext_v6
14980218822Sdim TCE(cpy,       1a00000, 4600,     2, (RR, RR),      rd_rm, t_cpy),
14981218822Sdim
14982218822Sdim /* V1 instructions with no Thumb analogue prior to V6T2.  */
14983218822Sdim#undef THUMB_VARIANT
14984218822Sdim#define THUMB_VARIANT &arm_ext_v6t2
14985218822Sdim TCE(teq,	1300000, ea900f00, 2, (RR, SH),      cmp,  t_mvn_tst),
14986218822Sdim TC3w(teqs,	1300000, ea900f00, 2, (RR, SH),      cmp,  t_mvn_tst),
14987218822Sdim  CL(teqp,	130f000,           2, (RR, SH),      cmp),
14988218822Sdim
14989218822Sdim TC3(ldrt,	4300000, f8500e00, 2, (RR, ADDR),    ldstt, t_ldstt),
14990218822Sdim TC3(ldrbt,	4700000, f8100e00, 2, (RR, ADDR),    ldstt, t_ldstt),
14991218822Sdim TC3(strt,	4200000, f8400e00, 2, (RR, ADDR),    ldstt, t_ldstt),
14992218822Sdim TC3(strbt,	4600000, f8000e00, 2, (RR, ADDR),    ldstt, t_ldstt),
14993218822Sdim
14994218822Sdim TC3(stmdb,	9000000, e9000000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
14995218822Sdim TC3(stmfd,     9000000, e9000000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
14996218822Sdim
14997218822Sdim TC3(ldmdb,	9100000, e9100000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
14998218822Sdim TC3(ldmea,	9100000, e9100000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
14999218822Sdim
15000218822Sdim /* V1 instructions with no Thumb analogue at all.  */
15001218822Sdim  CE(rsc,	0e00000,	   3, (RR, oRR, SH), arit),
15002218822Sdim  C3(rscs,	0f00000,	   3, (RR, oRR, SH), arit),
15003218822Sdim
15004218822Sdim  C3(stmib,	9800000,	   2, (RRw, REGLST), ldmstm),
15005218822Sdim  C3(stmfa,	9800000,	   2, (RRw, REGLST), ldmstm),
15006218822Sdim  C3(stmda,	8000000,	   2, (RRw, REGLST), ldmstm),
15007218822Sdim  C3(stmed,	8000000,	   2, (RRw, REGLST), ldmstm),
15008218822Sdim  C3(ldmib,	9900000,	   2, (RRw, REGLST), ldmstm),
15009218822Sdim  C3(ldmed,	9900000,	   2, (RRw, REGLST), ldmstm),
15010218822Sdim  C3(ldmda,	8100000,	   2, (RRw, REGLST), ldmstm),
15011218822Sdim  C3(ldmfa,	8100000,	   2, (RRw, REGLST), ldmstm),
15012218822Sdim
15013218822Sdim#undef ARM_VARIANT
15014218822Sdim#define ARM_VARIANT &arm_ext_v2	/* ARM 2 - multiplies.	*/
15015218822Sdim#undef THUMB_VARIANT
15016218822Sdim#define THUMB_VARIANT &arm_ext_v4t
15017218822Sdim tCE(mul,	0000090, mul,	   3, (RRnpc, RRnpc, oRR), mul, t_mul),
15018218822Sdim tC3(muls,	0100090, muls,	   3, (RRnpc, RRnpc, oRR), mul, t_mul),
15019218822Sdim
15020218822Sdim#undef THUMB_VARIANT
15021218822Sdim#define THUMB_VARIANT &arm_ext_v6t2
15022218822Sdim TCE(mla,	0200090, fb000000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mlas, t_mla),
15023218822Sdim  C3(mlas,	0300090,           4, (RRnpc, RRnpc, RRnpc, RRnpc), mlas),
15024218822Sdim
15025218822Sdim  /* Generic coprocessor instructions.	*/
15026218822Sdim TCE(cdp,	e000000, ee000000, 6, (RCP, I15b, RCN, RCN, RCN, oI7b), cdp,    cdp),
15027218822Sdim TCE(ldc,	c100000, ec100000, 3, (RCP, RCN, ADDRGLDC),	        lstc,   lstc),
15028218822Sdim TC3(ldcl,	c500000, ec500000, 3, (RCP, RCN, ADDRGLDC),	        lstc,   lstc),
15029218822Sdim TCE(stc,	c000000, ec000000, 3, (RCP, RCN, ADDRGLDC),	        lstc,   lstc),
15030218822Sdim TC3(stcl,	c400000, ec400000, 3, (RCP, RCN, ADDRGLDC),	        lstc,   lstc),
15031218822Sdim TCE(mcr,	e000010, ee000010, 6, (RCP, I7b, RR, RCN, RCN, oI7b),   co_reg, co_reg),
15032218822Sdim TCE(mrc,	e100010, ee100010, 6, (RCP, I7b, RR, RCN, RCN, oI7b),   co_reg, co_reg),
15033218822Sdim
15034218822Sdim#undef ARM_VARIANT
15035218822Sdim#define ARM_VARIANT &arm_ext_v2s /* ARM 3 - swp instructions.  */
15036218822Sdim  CE(swp,	1000090,           3, (RRnpc, RRnpc, RRnpcb), rd_rm_rn),
15037218822Sdim  C3(swpb,	1400090,           3, (RRnpc, RRnpc, RRnpcb), rd_rm_rn),
15038218822Sdim
15039218822Sdim#undef ARM_VARIANT
15040218822Sdim#define ARM_VARIANT &arm_ext_v3	/* ARM 6 Status register instructions.	*/
15041218822Sdim TCE(mrs,	10f0000, f3ef8000, 2, (APSR_RR, RVC_PSR), mrs, t_mrs),
15042218822Sdim TCE(msr,	120f000, f3808000, 2, (RVC_PSR, RR_EXi), msr, t_msr),
15043218822Sdim
15044218822Sdim#undef ARM_VARIANT
15045218822Sdim#define ARM_VARIANT &arm_ext_v3m	 /* ARM 7M long multiplies.  */
15046218822Sdim TCE(smull,	0c00090, fb800000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull, t_mull),
15047218822Sdim  CM(smull,s,	0d00090,           4, (RRnpc, RRnpc, RRnpc, RRnpc), mull),
15048218822Sdim TCE(umull,	0800090, fba00000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull, t_mull),
15049218822Sdim  CM(umull,s,	0900090,           4, (RRnpc, RRnpc, RRnpc, RRnpc), mull),
15050218822Sdim TCE(smlal,	0e00090, fbc00000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull, t_mull),
15051218822Sdim  CM(smlal,s,	0f00090,           4, (RRnpc, RRnpc, RRnpc, RRnpc), mull),
15052218822Sdim TCE(umlal,	0a00090, fbe00000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull, t_mull),
15053218822Sdim  CM(umlal,s,	0b00090,           4, (RRnpc, RRnpc, RRnpc, RRnpc), mull),
15054218822Sdim
15055218822Sdim#undef ARM_VARIANT
15056218822Sdim#define ARM_VARIANT &arm_ext_v4	/* ARM Architecture 4.	*/
15057218822Sdim#undef THUMB_VARIANT
15058218822Sdim#define THUMB_VARIANT &arm_ext_v4t
15059218822Sdim tC3(ldrh,	01000b0, ldrh,     2, (RR, ADDRGLDRS), ldstv4, t_ldst),
15060218822Sdim tC3(strh,	00000b0, strh,     2, (RR, ADDRGLDRS), ldstv4, t_ldst),
15061218822Sdim tC3(ldrsh,	01000f0, ldrsh,    2, (RR, ADDRGLDRS), ldstv4, t_ldst),
15062218822Sdim tC3(ldrsb,	01000d0, ldrsb,    2, (RR, ADDRGLDRS), ldstv4, t_ldst),
15063218822Sdim tCM(ld,sh,	01000f0, ldrsh,    2, (RR, ADDRGLDRS), ldstv4, t_ldst),
15064218822Sdim tCM(ld,sb,	01000d0, ldrsb,    2, (RR, ADDRGLDRS), ldstv4, t_ldst),
15065218822Sdim
15066218822Sdim#undef ARM_VARIANT
15067218822Sdim#define ARM_VARIANT &arm_ext_v4t_5
15068218822Sdim  /* ARM Architecture 4T.  */
15069218822Sdim  /* Note: bx (and blx) are required on V5, even if the processor does
15070218822Sdim     not support Thumb.	 */
15071218822Sdim TCE(bx,	12fff10, 4700, 1, (RR),	bx, t_bx),
15072218822Sdim
15073218822Sdim#undef ARM_VARIANT
15074218822Sdim#define ARM_VARIANT &arm_ext_v5 /*  ARM Architecture 5T.	 */
15075218822Sdim#undef THUMB_VARIANT
15076218822Sdim#define THUMB_VARIANT &arm_ext_v5t
15077218822Sdim  /* Note: blx has 2 variants; the .value coded here is for
15078218822Sdim     BLX(2).  Only this variant has conditional execution.  */
15079218822Sdim TCE(blx,	12fff30, 4780, 1, (RR_EXr),			    blx,  t_blx),
15080218822Sdim TUE(bkpt,	1200070, be00, 1, (oIffffb),			    bkpt, t_bkpt),
15081218822Sdim
15082218822Sdim#undef THUMB_VARIANT
15083218822Sdim#define THUMB_VARIANT &arm_ext_v6t2
15084218822Sdim TCE(clz,	16f0f10, fab0f080, 2, (RRnpc, RRnpc),		        rd_rm,  t_clz),
15085218822Sdim TUF(ldc2,	c100000, fc100000, 3, (RCP, RCN, ADDRGLDC),	        lstc,	lstc),
15086218822Sdim TUF(ldc2l,	c500000, fc500000, 3, (RCP, RCN, ADDRGLDC),		        lstc,	lstc),
15087218822Sdim TUF(stc2,	c000000, fc000000, 3, (RCP, RCN, ADDRGLDC),	        lstc,	lstc),
15088218822Sdim TUF(stc2l,	c400000, fc400000, 3, (RCP, RCN, ADDRGLDC),		        lstc,	lstc),
15089218822Sdim TUF(cdp2,	e000000, fe000000, 6, (RCP, I15b, RCN, RCN, RCN, oI7b), cdp,    cdp),
15090218822Sdim TUF(mcr2,	e000010, fe000010, 6, (RCP, I7b, RR, RCN, RCN, oI7b),   co_reg, co_reg),
15091218822Sdim TUF(mrc2,	e100010, fe100010, 6, (RCP, I7b, RR, RCN, RCN, oI7b),   co_reg, co_reg),
15092218822Sdim
15093218822Sdim#undef ARM_VARIANT
15094218822Sdim#define ARM_VARIANT &arm_ext_v5exp /*  ARM Architecture 5TExP.  */
15095218822Sdim TCE(smlabb,	1000080, fb100000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15096218822Sdim TCE(smlatb,	10000a0, fb100020, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15097218822Sdim TCE(smlabt,	10000c0, fb100010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15098218822Sdim TCE(smlatt,	10000e0, fb100030, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15099218822Sdim
15100218822Sdim TCE(smlawb,	1200080, fb300000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15101218822Sdim TCE(smlawt,	12000c0, fb300010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15102218822Sdim
15103218822Sdim TCE(smlalbb,	1400080, fbc00080, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smlal, t_mlal),
15104218822Sdim TCE(smlaltb,	14000a0, fbc000a0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smlal, t_mlal),
15105218822Sdim TCE(smlalbt,	14000c0, fbc00090, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smlal, t_mlal),
15106218822Sdim TCE(smlaltt,	14000e0, fbc000b0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smlal, t_mlal),
15107218822Sdim
15108218822Sdim TCE(smulbb,	1600080, fb10f000, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15109218822Sdim TCE(smultb,	16000a0, fb10f020, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15110218822Sdim TCE(smulbt,	16000c0, fb10f010, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15111218822Sdim TCE(smultt,	16000e0, fb10f030, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15112218822Sdim
15113218822Sdim TCE(smulwb,	12000a0, fb30f000, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15114218822Sdim TCE(smulwt,	12000e0, fb30f010, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15115218822Sdim
15116218822Sdim TCE(qadd,	1000050, fa80f080, 3, (RRnpc, RRnpc, RRnpc),	    rd_rm_rn, rd_rm_rn),
15117218822Sdim TCE(qdadd,	1400050, fa80f090, 3, (RRnpc, RRnpc, RRnpc),	    rd_rm_rn, rd_rm_rn),
15118218822Sdim TCE(qsub,	1200050, fa80f0a0, 3, (RRnpc, RRnpc, RRnpc),	    rd_rm_rn, rd_rm_rn),
15119218822Sdim TCE(qdsub,	1600050, fa80f0b0, 3, (RRnpc, RRnpc, RRnpc),	    rd_rm_rn, rd_rm_rn),
15120218822Sdim
15121218822Sdim#undef ARM_VARIANT
15122218822Sdim#define ARM_VARIANT &arm_ext_v5e /*  ARM Architecture 5TE.  */
15123218822Sdim TUF(pld,	450f000, f810f000, 1, (ADDR),		     pld,  t_pld),
15124218822Sdim TC3(ldrd,	00000d0, e8500000, 3, (RRnpc, oRRnpc, ADDRGLDRS), ldrd, t_ldstd),
15125218822Sdim TC3(strd,	00000f0, e8400000, 3, (RRnpc, oRRnpc, ADDRGLDRS), ldrd, t_ldstd),
15126218822Sdim
15127218822Sdim TCE(mcrr,	c400000, ec400000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
15128218822Sdim TCE(mrrc,	c500000, ec500000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
15129218822Sdim
15130218822Sdim#undef ARM_VARIANT
15131218822Sdim#define ARM_VARIANT &arm_ext_v5j /*  ARM Architecture 5TEJ.  */
15132218822Sdim TCE(bxj,	12fff20, f3c08f00, 1, (RR),			  bxj, t_bxj),
15133218822Sdim
15134218822Sdim#undef ARM_VARIANT
15135218822Sdim#define ARM_VARIANT &arm_ext_v6 /*  ARM V6.  */
15136218822Sdim#undef THUMB_VARIANT
15137218822Sdim#define THUMB_VARIANT &arm_ext_v6
15138218822Sdim TUF(cpsie,     1080000, b660,     2, (CPSF, oI31b),              cpsi,   t_cpsi),
15139218822Sdim TUF(cpsid,     10c0000, b670,     2, (CPSF, oI31b),              cpsi,   t_cpsi),
15140218822Sdim tCE(rev,       6bf0f30, rev,      2, (RRnpc, RRnpc),             rd_rm,  t_rev),
15141218822Sdim tCE(rev16,     6bf0fb0, rev16,    2, (RRnpc, RRnpc),             rd_rm,  t_rev),
15142218822Sdim tCE(revsh,     6ff0fb0, revsh,    2, (RRnpc, RRnpc),             rd_rm,  t_rev),
15143218822Sdim tCE(sxth,      6bf0070, sxth,     3, (RRnpc, RRnpc, oROR),       sxth,   t_sxth),
15144218822Sdim tCE(uxth,      6ff0070, uxth,     3, (RRnpc, RRnpc, oROR),       sxth,   t_sxth),
15145218822Sdim tCE(sxtb,      6af0070, sxtb,     3, (RRnpc, RRnpc, oROR),       sxth,   t_sxth),
15146218822Sdim tCE(uxtb,      6ef0070, uxtb,     3, (RRnpc, RRnpc, oROR),       sxth,   t_sxth),
15147218822Sdim TUF(setend,    1010000, b650,     1, (ENDI),                     setend, t_setend),
15148218822Sdim
15149218822Sdim#undef THUMB_VARIANT
15150218822Sdim#define THUMB_VARIANT &arm_ext_v6t2
15151218822Sdim TCE(ldrex,	1900f9f, e8500f00, 2, (RRnpc, ADDR),		  ldrex, t_ldrex),
15152218822Sdim TCE(strex,	1800f90, e8400000, 3, (RRnpc, RRnpc, ADDR),	   strex,  t_strex),
15153218822Sdim TUF(mcrr2,	c400000, fc400000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
15154218822Sdim TUF(mrrc2,	c500000, fc500000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
15155218822Sdim
15156218822Sdim TCE(ssat,	6a00010, f3000000, 4, (RRnpc, I32, RRnpc, oSHllar),ssat,   t_ssat),
15157218822Sdim TCE(usat,	6e00010, f3800000, 4, (RRnpc, I31, RRnpc, oSHllar),usat,   t_usat),
15158218822Sdim
15159218822Sdim/*  ARM V6 not included in V7M (eg. integer SIMD).  */
15160218822Sdim#undef THUMB_VARIANT
15161218822Sdim#define THUMB_VARIANT &arm_ext_v6_notm
15162218822Sdim TUF(cps,	1020000, f3af8100, 1, (I31b),			  imm0, t_cps),
15163218822Sdim TCE(pkhbt,	6800010, eac00000, 4, (RRnpc, RRnpc, RRnpc, oSHll),   pkhbt, t_pkhbt),
15164218822Sdim TCE(pkhtb,	6800050, eac00020, 4, (RRnpc, RRnpc, RRnpc, oSHar),   pkhtb, t_pkhtb),
15165218822Sdim TCE(qadd16,	6200f10, fa90f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15166218822Sdim TCE(qadd8,	6200f90, fa80f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15167218822Sdim TCE(qaddsubx,	6200f30, faa0f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15168218822Sdim TCE(qsub16,	6200f70, fad0f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15169218822Sdim TCE(qsub8,	6200ff0, fac0f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15170218822Sdim TCE(qsubaddx,	6200f50, fae0f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15171218822Sdim TCE(sadd16,	6100f10, fa90f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15172218822Sdim TCE(sadd8,	6100f90, fa80f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15173218822Sdim TCE(saddsubx,	6100f30, faa0f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15174218822Sdim TCE(shadd16,	6300f10, fa90f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15175218822Sdim TCE(shadd8,	6300f90, fa80f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15176218822Sdim TCE(shaddsubx, 6300f30, faa0f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15177218822Sdim TCE(shsub16,	6300f70, fad0f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15178218822Sdim TCE(shsub8,	6300ff0, fac0f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15179218822Sdim TCE(shsubaddx, 6300f50, fae0f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15180218822Sdim TCE(ssub16,	6100f70, fad0f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15181218822Sdim TCE(ssub8,	6100ff0, fac0f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15182218822Sdim TCE(ssubaddx,	6100f50, fae0f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15183218822Sdim TCE(uadd16,	6500f10, fa90f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15184218822Sdim TCE(uadd8,	6500f90, fa80f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15185218822Sdim TCE(uaddsubx,	6500f30, faa0f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15186218822Sdim TCE(uhadd16,	6700f10, fa90f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15187218822Sdim TCE(uhadd8,	6700f90, fa80f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15188218822Sdim TCE(uhaddsubx, 6700f30, faa0f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15189218822Sdim TCE(uhsub16,	6700f70, fad0f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15190218822Sdim TCE(uhsub8,	6700ff0, fac0f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15191218822Sdim TCE(uhsubaddx, 6700f50, fae0f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15192218822Sdim TCE(uqadd16,	6600f10, fa90f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15193218822Sdim TCE(uqadd8,	6600f90, fa80f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15194218822Sdim TCE(uqaddsubx, 6600f30, faa0f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15195218822Sdim TCE(uqsub16,	6600f70, fad0f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15196218822Sdim TCE(uqsub8,	6600ff0, fac0f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15197218822Sdim TCE(uqsubaddx, 6600f50, fae0f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15198218822Sdim TCE(usub16,	6500f70, fad0f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15199218822Sdim TCE(usub8,	6500ff0, fac0f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15200218822Sdim TCE(usubaddx,	6500f50, fae0f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15201218822Sdim TUF(rfeia,	8900a00, e990c000, 1, (RRw),			   rfe, rfe),
15202218822Sdim  UF(rfeib,	9900a00,           1, (RRw),			   rfe),
15203218822Sdim  UF(rfeda,	8100a00,           1, (RRw),			   rfe),
15204218822Sdim TUF(rfedb,	9100a00, e810c000, 1, (RRw),			   rfe, rfe),
15205218822Sdim TUF(rfefd,	8900a00, e990c000, 1, (RRw),			   rfe, rfe),
15206218822Sdim  UF(rfefa,	9900a00,           1, (RRw),			   rfe),
15207218822Sdim  UF(rfeea,	8100a00,           1, (RRw),			   rfe),
15208218822Sdim TUF(rfeed,	9100a00, e810c000, 1, (RRw),			   rfe, rfe),
15209218822Sdim TCE(sxtah,	6b00070, fa00f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15210218822Sdim TCE(sxtab16,	6800070, fa20f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15211218822Sdim TCE(sxtab,	6a00070, fa40f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15212218822Sdim TCE(sxtb16,	68f0070, fa2ff080, 3, (RRnpc, RRnpc, oROR),	   sxth,  t_sxth),
15213218822Sdim TCE(uxtah,	6f00070, fa10f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15214218822Sdim TCE(uxtab16,	6c00070, fa30f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15215218822Sdim TCE(uxtab,	6e00070, fa50f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15216218822Sdim TCE(uxtb16,	6cf0070, fa3ff080, 3, (RRnpc, RRnpc, oROR),	   sxth,  t_sxth),
15217218822Sdim TCE(sel,	6800fb0, faa0f080, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15218218822Sdim TCE(smlad,	7000010, fb200000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15219218822Sdim TCE(smladx,	7000030, fb200010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15220218822Sdim TCE(smlald,	7400010, fbc000c0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,t_mlal),
15221218822Sdim TCE(smlaldx,	7400030, fbc000d0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,t_mlal),
15222218822Sdim TCE(smlsd,	7000050, fb400000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15223218822Sdim TCE(smlsdx,	7000070, fb400010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15224218822Sdim TCE(smlsld,	7400050, fbd000c0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,t_mlal),
15225218822Sdim TCE(smlsldx,	7400070, fbd000d0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,t_mlal),
15226218822Sdim TCE(smmla,	7500010, fb500000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15227218822Sdim TCE(smmlar,	7500030, fb500010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15228218822Sdim TCE(smmls,	75000d0, fb600000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15229218822Sdim TCE(smmlsr,	75000f0, fb600010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15230218822Sdim TCE(smmul,	750f010, fb50f000, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15231218822Sdim TCE(smmulr,	750f030, fb50f010, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15232218822Sdim TCE(smuad,	700f010, fb20f000, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15233218822Sdim TCE(smuadx,	700f030, fb20f010, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15234218822Sdim TCE(smusd,	700f050, fb40f000, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15235218822Sdim TCE(smusdx,	700f070, fb40f010, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15236218822Sdim TUF(srsia,	8c00500, e980c000, 2, (oRRw, I31w),		   srs,  srs),
15237218822Sdim  UF(srsib,	9c00500,           2, (oRRw, I31w),		   srs),
15238218822Sdim  UF(srsda,	8400500,	   2, (oRRw, I31w),		   srs),
15239218822Sdim TUF(srsdb,	9400500, e800c000, 2, (oRRw, I31w),		   srs,  srs),
15240218822Sdim TCE(ssat16,	6a00f30, f3200000, 3, (RRnpc, I16, RRnpc),	   ssat16, t_ssat16),
15241218822Sdim TCE(umaal,	0400090, fbe00060, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,  t_mlal),
15242218822Sdim TCE(usad8,	780f010, fb70f000, 3, (RRnpc, RRnpc, RRnpc),	   smul,   t_simd),
15243218822Sdim TCE(usada8,	7800010, fb700000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla,   t_mla),
15244218822Sdim TCE(usat16,	6e00f30, f3a00000, 3, (RRnpc, I15, RRnpc),	   usat16, t_usat16),
15245218822Sdim
15246218822Sdim#undef ARM_VARIANT
15247218822Sdim#define ARM_VARIANT &arm_ext_v6k
15248218822Sdim#undef THUMB_VARIANT
15249218822Sdim#define THUMB_VARIANT &arm_ext_v6k
15250218822Sdim tCE(yield,	320f001, yield,    0, (), noargs, t_hint),
15251218822Sdim tCE(wfe,	320f002, wfe,      0, (), noargs, t_hint),
15252218822Sdim tCE(wfi,	320f003, wfi,      0, (), noargs, t_hint),
15253218822Sdim tCE(sev,	320f004, sev,      0, (), noargs, t_hint),
15254218822Sdim
15255218822Sdim#undef THUMB_VARIANT
15256218822Sdim#define THUMB_VARIANT &arm_ext_v6_notm
15257218822Sdim TCE(ldrexd,	1b00f9f, e8d0007f, 3, (RRnpc, oRRnpc, RRnpcb),        ldrexd, t_ldrexd),
15258218822Sdim TCE(strexd,	1a00f90, e8c00070, 4, (RRnpc, RRnpc, oRRnpc, RRnpcb), strexd, t_strexd),
15259218822Sdim
15260218822Sdim#undef THUMB_VARIANT
15261218822Sdim#define THUMB_VARIANT &arm_ext_v6t2
15262218822Sdim TCE(ldrexb,	1d00f9f, e8d00f4f, 2, (RRnpc, RRnpcb),	              rd_rn,  rd_rn),
15263218822Sdim TCE(ldrexh,	1f00f9f, e8d00f5f, 2, (RRnpc, RRnpcb),	              rd_rn,  rd_rn),
15264218822Sdim TCE(strexb,	1c00f90, e8c00f40, 3, (RRnpc, RRnpc, ADDR),           strex,  rm_rd_rn),
15265218822Sdim TCE(strexh,	1e00f90, e8c00f50, 3, (RRnpc, RRnpc, ADDR),           strex,  rm_rd_rn),
15266218822Sdim TUF(clrex,	57ff01f, f3bf8f2f, 0, (),			      noargs, noargs),
15267218822Sdim
15268218822Sdim#undef ARM_VARIANT
15269218822Sdim#define ARM_VARIANT &arm_ext_v6z
15270218822Sdim TCE(smc,	1600070, f7f08000, 1, (EXPi), smc, t_smc),
15271218822Sdim
15272218822Sdim#undef ARM_VARIANT
15273218822Sdim#define ARM_VARIANT &arm_ext_v6t2
15274218822Sdim TCE(bfc,	7c0001f, f36f0000, 3, (RRnpc, I31, I32),	   bfc, t_bfc),
15275218822Sdim TCE(bfi,	7c00010, f3600000, 4, (RRnpc, RRnpc_I0, I31, I32), bfi, t_bfi),
15276218822Sdim TCE(sbfx,	7a00050, f3400000, 4, (RR, RR, I31, I32),	   bfx, t_bfx),
15277218822Sdim TCE(ubfx,	7e00050, f3c00000, 4, (RR, RR, I31, I32),	   bfx, t_bfx),
15278218822Sdim
15279218822Sdim TCE(mls,	0600090, fb000010, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mlas, t_mla),
15280218822Sdim TCE(movw,	3000000, f2400000, 2, (RRnpc, HALF),		    mov16, t_mov16),
15281218822Sdim TCE(movt,	3400000, f2c00000, 2, (RRnpc, HALF),		    mov16, t_mov16),
15282218822Sdim TCE(rbit,	6ff0f30, fa90f0a0, 2, (RR, RR),			    rd_rm, t_rbit),
15283218822Sdim
15284218822Sdim TC3(ldrht,	03000b0, f8300e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
15285218822Sdim TC3(ldrsht,	03000f0, f9300e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
15286218822Sdim TC3(ldrsbt,	03000d0, f9100e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
15287218822Sdim TC3(strht,	02000b0, f8200e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
15288218822Sdim
15289218822Sdim  UT(cbnz,      b900,    2, (RR, EXP), t_cbz),
15290218822Sdim  UT(cbz,       b100,    2, (RR, EXP), t_cbz),
15291218822Sdim /* ARM does not really have an IT instruction, so always allow it.  */
15292218822Sdim#undef ARM_VARIANT
15293218822Sdim#define ARM_VARIANT &arm_ext_v1
15294218822Sdim TUE(it,        0, bf08, 1, (COND),    it, t_it),
15295218822Sdim TUE(itt,       0, bf0c, 1, (COND),    it, t_it),
15296218822Sdim TUE(ite,       0, bf04, 1, (COND),    it, t_it),
15297218822Sdim TUE(ittt,      0, bf0e, 1, (COND),    it, t_it),
15298218822Sdim TUE(itet,      0, bf06, 1, (COND),    it, t_it),
15299218822Sdim TUE(itte,      0, bf0a, 1, (COND),    it, t_it),
15300218822Sdim TUE(itee,      0, bf02, 1, (COND),    it, t_it),
15301218822Sdim TUE(itttt,     0, bf0f, 1, (COND),    it, t_it),
15302218822Sdim TUE(itett,     0, bf07, 1, (COND),    it, t_it),
15303218822Sdim TUE(ittet,     0, bf0b, 1, (COND),    it, t_it),
15304218822Sdim TUE(iteet,     0, bf03, 1, (COND),    it, t_it),
15305218822Sdim TUE(ittte,     0, bf0d, 1, (COND),    it, t_it),
15306218822Sdim TUE(itete,     0, bf05, 1, (COND),    it, t_it),
15307218822Sdim TUE(ittee,     0, bf09, 1, (COND),    it, t_it),
15308218822Sdim TUE(iteee,     0, bf01, 1, (COND),    it, t_it),
15309218822Sdim
15310218822Sdim /* Thumb2 only instructions.  */
15311218822Sdim#undef ARM_VARIANT
15312218822Sdim#define ARM_VARIANT NULL
15313218822Sdim
15314218822Sdim TCE(addw,	0, f2000000, 3, (RR, RR, EXPi), 0, t_add_sub_w),
15315218822Sdim TCE(subw,	0, f2a00000, 3, (RR, RR, EXPi), 0, t_add_sub_w),
15316218822Sdim TCE(tbb,       0, e8d0f000, 1, (TB), 0, t_tb),
15317218822Sdim TCE(tbh,       0, e8d0f010, 1, (TB), 0, t_tb),
15318218822Sdim
15319218822Sdim /* Thumb-2 hardware division instructions (R and M profiles only).  */
15320218822Sdim#undef THUMB_VARIANT
15321218822Sdim#define THUMB_VARIANT &arm_ext_div
15322218822Sdim TCE(sdiv,	0, fb90f0f0, 3, (RR, oRR, RR), 0, t_div),
15323218822Sdim TCE(udiv,	0, fbb0f0f0, 3, (RR, oRR, RR), 0, t_div),
15324218822Sdim
15325218822Sdim /* ARM V7 instructions.  */
15326218822Sdim#undef ARM_VARIANT
15327218822Sdim#define ARM_VARIANT &arm_ext_v7
15328218822Sdim#undef THUMB_VARIANT
15329218822Sdim#define THUMB_VARIANT &arm_ext_v7
15330218822Sdim TUF(pli,	450f000, f910f000, 1, (ADDR),	  pli,	    t_pld),
15331218822Sdim TCE(dbg,	320f0f0, f3af80f0, 1, (I15),	  dbg,	    t_dbg),
15332218822Sdim TUF(dmb,	57ff050, f3bf8f50, 1, (oBARRIER), barrier,  t_barrier),
15333218822Sdim TUF(dsb,	57ff040, f3bf8f40, 1, (oBARRIER), barrier,  t_barrier),
15334218822Sdim TUF(isb,	57ff060, f3bf8f60, 1, (oBARRIER), barrier,  t_barrier),
15335218822Sdim
15336218822Sdim#undef ARM_VARIANT
15337218822Sdim#define ARM_VARIANT &fpu_fpa_ext_v1  /* Core FPA instruction set (V1).  */
15338218822Sdim cCE(wfs,	e200110, 1, (RR),	     rd),
15339218822Sdim cCE(rfs,	e300110, 1, (RR),	     rd),
15340218822Sdim cCE(wfc,	e400110, 1, (RR),	     rd),
15341218822Sdim cCE(rfc,	e500110, 1, (RR),	     rd),
15342218822Sdim
15343218822Sdim cCL(ldfs,	c100100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15344218822Sdim cCL(ldfd,	c108100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15345218822Sdim cCL(ldfe,	c500100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15346218822Sdim cCL(ldfp,	c508100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15347218822Sdim
15348218822Sdim cCL(stfs,	c000100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15349218822Sdim cCL(stfd,	c008100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15350218822Sdim cCL(stfe,	c400100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15351218822Sdim cCL(stfp,	c408100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15352218822Sdim
15353218822Sdim cCL(mvfs,	e008100, 2, (RF, RF_IF),     rd_rm),
15354218822Sdim cCL(mvfsp,	e008120, 2, (RF, RF_IF),     rd_rm),
15355218822Sdim cCL(mvfsm,	e008140, 2, (RF, RF_IF),     rd_rm),
15356218822Sdim cCL(mvfsz,	e008160, 2, (RF, RF_IF),     rd_rm),
15357218822Sdim cCL(mvfd,	e008180, 2, (RF, RF_IF),     rd_rm),
15358218822Sdim cCL(mvfdp,	e0081a0, 2, (RF, RF_IF),     rd_rm),
15359218822Sdim cCL(mvfdm,	e0081c0, 2, (RF, RF_IF),     rd_rm),
15360218822Sdim cCL(mvfdz,	e0081e0, 2, (RF, RF_IF),     rd_rm),
15361218822Sdim cCL(mvfe,	e088100, 2, (RF, RF_IF),     rd_rm),
15362218822Sdim cCL(mvfep,	e088120, 2, (RF, RF_IF),     rd_rm),
15363218822Sdim cCL(mvfem,	e088140, 2, (RF, RF_IF),     rd_rm),
15364218822Sdim cCL(mvfez,	e088160, 2, (RF, RF_IF),     rd_rm),
15365218822Sdim
15366218822Sdim cCL(mnfs,	e108100, 2, (RF, RF_IF),     rd_rm),
15367218822Sdim cCL(mnfsp,	e108120, 2, (RF, RF_IF),     rd_rm),
15368218822Sdim cCL(mnfsm,	e108140, 2, (RF, RF_IF),     rd_rm),
15369218822Sdim cCL(mnfsz,	e108160, 2, (RF, RF_IF),     rd_rm),
15370218822Sdim cCL(mnfd,	e108180, 2, (RF, RF_IF),     rd_rm),
15371218822Sdim cCL(mnfdp,	e1081a0, 2, (RF, RF_IF),     rd_rm),
15372218822Sdim cCL(mnfdm,	e1081c0, 2, (RF, RF_IF),     rd_rm),
15373218822Sdim cCL(mnfdz,	e1081e0, 2, (RF, RF_IF),     rd_rm),
15374218822Sdim cCL(mnfe,	e188100, 2, (RF, RF_IF),     rd_rm),
15375218822Sdim cCL(mnfep,	e188120, 2, (RF, RF_IF),     rd_rm),
15376218822Sdim cCL(mnfem,	e188140, 2, (RF, RF_IF),     rd_rm),
15377218822Sdim cCL(mnfez,	e188160, 2, (RF, RF_IF),     rd_rm),
15378218822Sdim
15379218822Sdim cCL(abss,	e208100, 2, (RF, RF_IF),     rd_rm),
15380218822Sdim cCL(abssp,	e208120, 2, (RF, RF_IF),     rd_rm),
15381218822Sdim cCL(abssm,	e208140, 2, (RF, RF_IF),     rd_rm),
15382218822Sdim cCL(abssz,	e208160, 2, (RF, RF_IF),     rd_rm),
15383218822Sdim cCL(absd,	e208180, 2, (RF, RF_IF),     rd_rm),
15384218822Sdim cCL(absdp,	e2081a0, 2, (RF, RF_IF),     rd_rm),
15385218822Sdim cCL(absdm,	e2081c0, 2, (RF, RF_IF),     rd_rm),
15386218822Sdim cCL(absdz,	e2081e0, 2, (RF, RF_IF),     rd_rm),
15387218822Sdim cCL(abse,	e288100, 2, (RF, RF_IF),     rd_rm),
15388218822Sdim cCL(absep,	e288120, 2, (RF, RF_IF),     rd_rm),
15389218822Sdim cCL(absem,	e288140, 2, (RF, RF_IF),     rd_rm),
15390218822Sdim cCL(absez,	e288160, 2, (RF, RF_IF),     rd_rm),
15391218822Sdim
15392218822Sdim cCL(rnds,	e308100, 2, (RF, RF_IF),     rd_rm),
15393218822Sdim cCL(rndsp,	e308120, 2, (RF, RF_IF),     rd_rm),
15394218822Sdim cCL(rndsm,	e308140, 2, (RF, RF_IF),     rd_rm),
15395218822Sdim cCL(rndsz,	e308160, 2, (RF, RF_IF),     rd_rm),
15396218822Sdim cCL(rndd,	e308180, 2, (RF, RF_IF),     rd_rm),
15397218822Sdim cCL(rnddp,	e3081a0, 2, (RF, RF_IF),     rd_rm),
15398218822Sdim cCL(rnddm,	e3081c0, 2, (RF, RF_IF),     rd_rm),
15399218822Sdim cCL(rnddz,	e3081e0, 2, (RF, RF_IF),     rd_rm),
15400218822Sdim cCL(rnde,	e388100, 2, (RF, RF_IF),     rd_rm),
15401218822Sdim cCL(rndep,	e388120, 2, (RF, RF_IF),     rd_rm),
15402218822Sdim cCL(rndem,	e388140, 2, (RF, RF_IF),     rd_rm),
15403218822Sdim cCL(rndez,	e388160, 2, (RF, RF_IF),     rd_rm),
15404218822Sdim
15405218822Sdim cCL(sqts,	e408100, 2, (RF, RF_IF),     rd_rm),
15406218822Sdim cCL(sqtsp,	e408120, 2, (RF, RF_IF),     rd_rm),
15407218822Sdim cCL(sqtsm,	e408140, 2, (RF, RF_IF),     rd_rm),
15408218822Sdim cCL(sqtsz,	e408160, 2, (RF, RF_IF),     rd_rm),
15409218822Sdim cCL(sqtd,	e408180, 2, (RF, RF_IF),     rd_rm),
15410218822Sdim cCL(sqtdp,	e4081a0, 2, (RF, RF_IF),     rd_rm),
15411218822Sdim cCL(sqtdm,	e4081c0, 2, (RF, RF_IF),     rd_rm),
15412218822Sdim cCL(sqtdz,	e4081e0, 2, (RF, RF_IF),     rd_rm),
15413218822Sdim cCL(sqte,	e488100, 2, (RF, RF_IF),     rd_rm),
15414218822Sdim cCL(sqtep,	e488120, 2, (RF, RF_IF),     rd_rm),
15415218822Sdim cCL(sqtem,	e488140, 2, (RF, RF_IF),     rd_rm),
15416218822Sdim cCL(sqtez,	e488160, 2, (RF, RF_IF),     rd_rm),
15417218822Sdim
15418218822Sdim cCL(logs,	e508100, 2, (RF, RF_IF),     rd_rm),
15419218822Sdim cCL(logsp,	e508120, 2, (RF, RF_IF),     rd_rm),
15420218822Sdim cCL(logsm,	e508140, 2, (RF, RF_IF),     rd_rm),
15421218822Sdim cCL(logsz,	e508160, 2, (RF, RF_IF),     rd_rm),
15422218822Sdim cCL(logd,	e508180, 2, (RF, RF_IF),     rd_rm),
15423218822Sdim cCL(logdp,	e5081a0, 2, (RF, RF_IF),     rd_rm),
15424218822Sdim cCL(logdm,	e5081c0, 2, (RF, RF_IF),     rd_rm),
15425218822Sdim cCL(logdz,	e5081e0, 2, (RF, RF_IF),     rd_rm),
15426218822Sdim cCL(loge,	e588100, 2, (RF, RF_IF),     rd_rm),
15427218822Sdim cCL(logep,	e588120, 2, (RF, RF_IF),     rd_rm),
15428218822Sdim cCL(logem,	e588140, 2, (RF, RF_IF),     rd_rm),
15429218822Sdim cCL(logez,	e588160, 2, (RF, RF_IF),     rd_rm),
15430218822Sdim
15431218822Sdim cCL(lgns,	e608100, 2, (RF, RF_IF),     rd_rm),
15432218822Sdim cCL(lgnsp,	e608120, 2, (RF, RF_IF),     rd_rm),
15433218822Sdim cCL(lgnsm,	e608140, 2, (RF, RF_IF),     rd_rm),
15434218822Sdim cCL(lgnsz,	e608160, 2, (RF, RF_IF),     rd_rm),
15435218822Sdim cCL(lgnd,	e608180, 2, (RF, RF_IF),     rd_rm),
15436218822Sdim cCL(lgndp,	e6081a0, 2, (RF, RF_IF),     rd_rm),
15437218822Sdim cCL(lgndm,	e6081c0, 2, (RF, RF_IF),     rd_rm),
15438218822Sdim cCL(lgndz,	e6081e0, 2, (RF, RF_IF),     rd_rm),
15439218822Sdim cCL(lgne,	e688100, 2, (RF, RF_IF),     rd_rm),
15440218822Sdim cCL(lgnep,	e688120, 2, (RF, RF_IF),     rd_rm),
15441218822Sdim cCL(lgnem,	e688140, 2, (RF, RF_IF),     rd_rm),
15442218822Sdim cCL(lgnez,	e688160, 2, (RF, RF_IF),     rd_rm),
15443218822Sdim
15444218822Sdim cCL(exps,	e708100, 2, (RF, RF_IF),     rd_rm),
15445218822Sdim cCL(expsp,	e708120, 2, (RF, RF_IF),     rd_rm),
15446218822Sdim cCL(expsm,	e708140, 2, (RF, RF_IF),     rd_rm),
15447218822Sdim cCL(expsz,	e708160, 2, (RF, RF_IF),     rd_rm),
15448218822Sdim cCL(expd,	e708180, 2, (RF, RF_IF),     rd_rm),
15449218822Sdim cCL(expdp,	e7081a0, 2, (RF, RF_IF),     rd_rm),
15450218822Sdim cCL(expdm,	e7081c0, 2, (RF, RF_IF),     rd_rm),
15451218822Sdim cCL(expdz,	e7081e0, 2, (RF, RF_IF),     rd_rm),
15452218822Sdim cCL(expe,	e788100, 2, (RF, RF_IF),     rd_rm),
15453218822Sdim cCL(expep,	e788120, 2, (RF, RF_IF),     rd_rm),
15454218822Sdim cCL(expem,	e788140, 2, (RF, RF_IF),     rd_rm),
15455218822Sdim cCL(expdz,	e788160, 2, (RF, RF_IF),     rd_rm),
15456218822Sdim
15457218822Sdim cCL(sins,	e808100, 2, (RF, RF_IF),     rd_rm),
15458218822Sdim cCL(sinsp,	e808120, 2, (RF, RF_IF),     rd_rm),
15459218822Sdim cCL(sinsm,	e808140, 2, (RF, RF_IF),     rd_rm),
15460218822Sdim cCL(sinsz,	e808160, 2, (RF, RF_IF),     rd_rm),
15461218822Sdim cCL(sind,	e808180, 2, (RF, RF_IF),     rd_rm),
15462218822Sdim cCL(sindp,	e8081a0, 2, (RF, RF_IF),     rd_rm),
15463218822Sdim cCL(sindm,	e8081c0, 2, (RF, RF_IF),     rd_rm),
15464218822Sdim cCL(sindz,	e8081e0, 2, (RF, RF_IF),     rd_rm),
15465218822Sdim cCL(sine,	e888100, 2, (RF, RF_IF),     rd_rm),
15466218822Sdim cCL(sinep,	e888120, 2, (RF, RF_IF),     rd_rm),
15467218822Sdim cCL(sinem,	e888140, 2, (RF, RF_IF),     rd_rm),
15468218822Sdim cCL(sinez,	e888160, 2, (RF, RF_IF),     rd_rm),
15469218822Sdim
15470218822Sdim cCL(coss,	e908100, 2, (RF, RF_IF),     rd_rm),
15471218822Sdim cCL(cossp,	e908120, 2, (RF, RF_IF),     rd_rm),
15472218822Sdim cCL(cossm,	e908140, 2, (RF, RF_IF),     rd_rm),
15473218822Sdim cCL(cossz,	e908160, 2, (RF, RF_IF),     rd_rm),
15474218822Sdim cCL(cosd,	e908180, 2, (RF, RF_IF),     rd_rm),
15475218822Sdim cCL(cosdp,	e9081a0, 2, (RF, RF_IF),     rd_rm),
15476218822Sdim cCL(cosdm,	e9081c0, 2, (RF, RF_IF),     rd_rm),
15477218822Sdim cCL(cosdz,	e9081e0, 2, (RF, RF_IF),     rd_rm),
15478218822Sdim cCL(cose,	e988100, 2, (RF, RF_IF),     rd_rm),
15479218822Sdim cCL(cosep,	e988120, 2, (RF, RF_IF),     rd_rm),
15480218822Sdim cCL(cosem,	e988140, 2, (RF, RF_IF),     rd_rm),
15481218822Sdim cCL(cosez,	e988160, 2, (RF, RF_IF),     rd_rm),
15482218822Sdim
15483218822Sdim cCL(tans,	ea08100, 2, (RF, RF_IF),     rd_rm),
15484218822Sdim cCL(tansp,	ea08120, 2, (RF, RF_IF),     rd_rm),
15485218822Sdim cCL(tansm,	ea08140, 2, (RF, RF_IF),     rd_rm),
15486218822Sdim cCL(tansz,	ea08160, 2, (RF, RF_IF),     rd_rm),
15487218822Sdim cCL(tand,	ea08180, 2, (RF, RF_IF),     rd_rm),
15488218822Sdim cCL(tandp,	ea081a0, 2, (RF, RF_IF),     rd_rm),
15489218822Sdim cCL(tandm,	ea081c0, 2, (RF, RF_IF),     rd_rm),
15490218822Sdim cCL(tandz,	ea081e0, 2, (RF, RF_IF),     rd_rm),
15491218822Sdim cCL(tane,	ea88100, 2, (RF, RF_IF),     rd_rm),
15492218822Sdim cCL(tanep,	ea88120, 2, (RF, RF_IF),     rd_rm),
15493218822Sdim cCL(tanem,	ea88140, 2, (RF, RF_IF),     rd_rm),
15494218822Sdim cCL(tanez,	ea88160, 2, (RF, RF_IF),     rd_rm),
15495218822Sdim
15496218822Sdim cCL(asns,	eb08100, 2, (RF, RF_IF),     rd_rm),
15497218822Sdim cCL(asnsp,	eb08120, 2, (RF, RF_IF),     rd_rm),
15498218822Sdim cCL(asnsm,	eb08140, 2, (RF, RF_IF),     rd_rm),
15499218822Sdim cCL(asnsz,	eb08160, 2, (RF, RF_IF),     rd_rm),
15500218822Sdim cCL(asnd,	eb08180, 2, (RF, RF_IF),     rd_rm),
15501218822Sdim cCL(asndp,	eb081a0, 2, (RF, RF_IF),     rd_rm),
15502218822Sdim cCL(asndm,	eb081c0, 2, (RF, RF_IF),     rd_rm),
15503218822Sdim cCL(asndz,	eb081e0, 2, (RF, RF_IF),     rd_rm),
15504218822Sdim cCL(asne,	eb88100, 2, (RF, RF_IF),     rd_rm),
15505218822Sdim cCL(asnep,	eb88120, 2, (RF, RF_IF),     rd_rm),
15506218822Sdim cCL(asnem,	eb88140, 2, (RF, RF_IF),     rd_rm),
15507218822Sdim cCL(asnez,	eb88160, 2, (RF, RF_IF),     rd_rm),
15508218822Sdim
15509218822Sdim cCL(acss,	ec08100, 2, (RF, RF_IF),     rd_rm),
15510218822Sdim cCL(acssp,	ec08120, 2, (RF, RF_IF),     rd_rm),
15511218822Sdim cCL(acssm,	ec08140, 2, (RF, RF_IF),     rd_rm),
15512218822Sdim cCL(acssz,	ec08160, 2, (RF, RF_IF),     rd_rm),
15513218822Sdim cCL(acsd,	ec08180, 2, (RF, RF_IF),     rd_rm),
15514218822Sdim cCL(acsdp,	ec081a0, 2, (RF, RF_IF),     rd_rm),
15515218822Sdim cCL(acsdm,	ec081c0, 2, (RF, RF_IF),     rd_rm),
15516218822Sdim cCL(acsdz,	ec081e0, 2, (RF, RF_IF),     rd_rm),
15517218822Sdim cCL(acse,	ec88100, 2, (RF, RF_IF),     rd_rm),
15518218822Sdim cCL(acsep,	ec88120, 2, (RF, RF_IF),     rd_rm),
15519218822Sdim cCL(acsem,	ec88140, 2, (RF, RF_IF),     rd_rm),
15520218822Sdim cCL(acsez,	ec88160, 2, (RF, RF_IF),     rd_rm),
15521218822Sdim
15522218822Sdim cCL(atns,	ed08100, 2, (RF, RF_IF),     rd_rm),
15523218822Sdim cCL(atnsp,	ed08120, 2, (RF, RF_IF),     rd_rm),
15524218822Sdim cCL(atnsm,	ed08140, 2, (RF, RF_IF),     rd_rm),
15525218822Sdim cCL(atnsz,	ed08160, 2, (RF, RF_IF),     rd_rm),
15526218822Sdim cCL(atnd,	ed08180, 2, (RF, RF_IF),     rd_rm),
15527218822Sdim cCL(atndp,	ed081a0, 2, (RF, RF_IF),     rd_rm),
15528218822Sdim cCL(atndm,	ed081c0, 2, (RF, RF_IF),     rd_rm),
15529218822Sdim cCL(atndz,	ed081e0, 2, (RF, RF_IF),     rd_rm),
15530218822Sdim cCL(atne,	ed88100, 2, (RF, RF_IF),     rd_rm),
15531218822Sdim cCL(atnep,	ed88120, 2, (RF, RF_IF),     rd_rm),
15532218822Sdim cCL(atnem,	ed88140, 2, (RF, RF_IF),     rd_rm),
15533218822Sdim cCL(atnez,	ed88160, 2, (RF, RF_IF),     rd_rm),
15534218822Sdim
15535218822Sdim cCL(urds,	ee08100, 2, (RF, RF_IF),     rd_rm),
15536218822Sdim cCL(urdsp,	ee08120, 2, (RF, RF_IF),     rd_rm),
15537218822Sdim cCL(urdsm,	ee08140, 2, (RF, RF_IF),     rd_rm),
15538218822Sdim cCL(urdsz,	ee08160, 2, (RF, RF_IF),     rd_rm),
15539218822Sdim cCL(urdd,	ee08180, 2, (RF, RF_IF),     rd_rm),
15540218822Sdim cCL(urddp,	ee081a0, 2, (RF, RF_IF),     rd_rm),
15541218822Sdim cCL(urddm,	ee081c0, 2, (RF, RF_IF),     rd_rm),
15542218822Sdim cCL(urddz,	ee081e0, 2, (RF, RF_IF),     rd_rm),
15543218822Sdim cCL(urde,	ee88100, 2, (RF, RF_IF),     rd_rm),
15544218822Sdim cCL(urdep,	ee88120, 2, (RF, RF_IF),     rd_rm),
15545218822Sdim cCL(urdem,	ee88140, 2, (RF, RF_IF),     rd_rm),
15546218822Sdim cCL(urdez,	ee88160, 2, (RF, RF_IF),     rd_rm),
15547218822Sdim
15548218822Sdim cCL(nrms,	ef08100, 2, (RF, RF_IF),     rd_rm),
15549218822Sdim cCL(nrmsp,	ef08120, 2, (RF, RF_IF),     rd_rm),
15550218822Sdim cCL(nrmsm,	ef08140, 2, (RF, RF_IF),     rd_rm),
15551218822Sdim cCL(nrmsz,	ef08160, 2, (RF, RF_IF),     rd_rm),
15552218822Sdim cCL(nrmd,	ef08180, 2, (RF, RF_IF),     rd_rm),
15553218822Sdim cCL(nrmdp,	ef081a0, 2, (RF, RF_IF),     rd_rm),
15554218822Sdim cCL(nrmdm,	ef081c0, 2, (RF, RF_IF),     rd_rm),
15555218822Sdim cCL(nrmdz,	ef081e0, 2, (RF, RF_IF),     rd_rm),
15556218822Sdim cCL(nrme,	ef88100, 2, (RF, RF_IF),     rd_rm),
15557218822Sdim cCL(nrmep,	ef88120, 2, (RF, RF_IF),     rd_rm),
15558218822Sdim cCL(nrmem,	ef88140, 2, (RF, RF_IF),     rd_rm),
15559218822Sdim cCL(nrmez,	ef88160, 2, (RF, RF_IF),     rd_rm),
15560218822Sdim
15561218822Sdim cCL(adfs,	e000100, 3, (RF, RF, RF_IF), rd_rn_rm),
15562218822Sdim cCL(adfsp,	e000120, 3, (RF, RF, RF_IF), rd_rn_rm),
15563218822Sdim cCL(adfsm,	e000140, 3, (RF, RF, RF_IF), rd_rn_rm),
15564218822Sdim cCL(adfsz,	e000160, 3, (RF, RF, RF_IF), rd_rn_rm),
15565218822Sdim cCL(adfd,	e000180, 3, (RF, RF, RF_IF), rd_rn_rm),
15566218822Sdim cCL(adfdp,	e0001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15567218822Sdim cCL(adfdm,	e0001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15568218822Sdim cCL(adfdz,	e0001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15569218822Sdim cCL(adfe,	e080100, 3, (RF, RF, RF_IF), rd_rn_rm),
15570218822Sdim cCL(adfep,	e080120, 3, (RF, RF, RF_IF), rd_rn_rm),
15571218822Sdim cCL(adfem,	e080140, 3, (RF, RF, RF_IF), rd_rn_rm),
15572218822Sdim cCL(adfez,	e080160, 3, (RF, RF, RF_IF), rd_rn_rm),
15573218822Sdim
15574218822Sdim cCL(sufs,	e200100, 3, (RF, RF, RF_IF), rd_rn_rm),
15575218822Sdim cCL(sufsp,	e200120, 3, (RF, RF, RF_IF), rd_rn_rm),
15576218822Sdim cCL(sufsm,	e200140, 3, (RF, RF, RF_IF), rd_rn_rm),
15577218822Sdim cCL(sufsz,	e200160, 3, (RF, RF, RF_IF), rd_rn_rm),
15578218822Sdim cCL(sufd,	e200180, 3, (RF, RF, RF_IF), rd_rn_rm),
15579218822Sdim cCL(sufdp,	e2001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15580218822Sdim cCL(sufdm,	e2001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15581218822Sdim cCL(sufdz,	e2001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15582218822Sdim cCL(sufe,	e280100, 3, (RF, RF, RF_IF), rd_rn_rm),
15583218822Sdim cCL(sufep,	e280120, 3, (RF, RF, RF_IF), rd_rn_rm),
15584218822Sdim cCL(sufem,	e280140, 3, (RF, RF, RF_IF), rd_rn_rm),
15585218822Sdim cCL(sufez,	e280160, 3, (RF, RF, RF_IF), rd_rn_rm),
15586218822Sdim
15587218822Sdim cCL(rsfs,	e300100, 3, (RF, RF, RF_IF), rd_rn_rm),
15588218822Sdim cCL(rsfsp,	e300120, 3, (RF, RF, RF_IF), rd_rn_rm),
15589218822Sdim cCL(rsfsm,	e300140, 3, (RF, RF, RF_IF), rd_rn_rm),
15590218822Sdim cCL(rsfsz,	e300160, 3, (RF, RF, RF_IF), rd_rn_rm),
15591218822Sdim cCL(rsfd,	e300180, 3, (RF, RF, RF_IF), rd_rn_rm),
15592218822Sdim cCL(rsfdp,	e3001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15593218822Sdim cCL(rsfdm,	e3001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15594218822Sdim cCL(rsfdz,	e3001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15595218822Sdim cCL(rsfe,	e380100, 3, (RF, RF, RF_IF), rd_rn_rm),
15596218822Sdim cCL(rsfep,	e380120, 3, (RF, RF, RF_IF), rd_rn_rm),
15597218822Sdim cCL(rsfem,	e380140, 3, (RF, RF, RF_IF), rd_rn_rm),
15598218822Sdim cCL(rsfez,	e380160, 3, (RF, RF, RF_IF), rd_rn_rm),
15599218822Sdim
15600218822Sdim cCL(mufs,	e100100, 3, (RF, RF, RF_IF), rd_rn_rm),
15601218822Sdim cCL(mufsp,	e100120, 3, (RF, RF, RF_IF), rd_rn_rm),
15602218822Sdim cCL(mufsm,	e100140, 3, (RF, RF, RF_IF), rd_rn_rm),
15603218822Sdim cCL(mufsz,	e100160, 3, (RF, RF, RF_IF), rd_rn_rm),
15604218822Sdim cCL(mufd,	e100180, 3, (RF, RF, RF_IF), rd_rn_rm),
15605218822Sdim cCL(mufdp,	e1001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15606218822Sdim cCL(mufdm,	e1001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15607218822Sdim cCL(mufdz,	e1001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15608218822Sdim cCL(mufe,	e180100, 3, (RF, RF, RF_IF), rd_rn_rm),
15609218822Sdim cCL(mufep,	e180120, 3, (RF, RF, RF_IF), rd_rn_rm),
15610218822Sdim cCL(mufem,	e180140, 3, (RF, RF, RF_IF), rd_rn_rm),
15611218822Sdim cCL(mufez,	e180160, 3, (RF, RF, RF_IF), rd_rn_rm),
15612218822Sdim
15613218822Sdim cCL(dvfs,	e400100, 3, (RF, RF, RF_IF), rd_rn_rm),
15614218822Sdim cCL(dvfsp,	e400120, 3, (RF, RF, RF_IF), rd_rn_rm),
15615218822Sdim cCL(dvfsm,	e400140, 3, (RF, RF, RF_IF), rd_rn_rm),
15616218822Sdim cCL(dvfsz,	e400160, 3, (RF, RF, RF_IF), rd_rn_rm),
15617218822Sdim cCL(dvfd,	e400180, 3, (RF, RF, RF_IF), rd_rn_rm),
15618218822Sdim cCL(dvfdp,	e4001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15619218822Sdim cCL(dvfdm,	e4001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15620218822Sdim cCL(dvfdz,	e4001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15621218822Sdim cCL(dvfe,	e480100, 3, (RF, RF, RF_IF), rd_rn_rm),
15622218822Sdim cCL(dvfep,	e480120, 3, (RF, RF, RF_IF), rd_rn_rm),
15623218822Sdim cCL(dvfem,	e480140, 3, (RF, RF, RF_IF), rd_rn_rm),
15624218822Sdim cCL(dvfez,	e480160, 3, (RF, RF, RF_IF), rd_rn_rm),
15625218822Sdim
15626218822Sdim cCL(rdfs,	e500100, 3, (RF, RF, RF_IF), rd_rn_rm),
15627218822Sdim cCL(rdfsp,	e500120, 3, (RF, RF, RF_IF), rd_rn_rm),
15628218822Sdim cCL(rdfsm,	e500140, 3, (RF, RF, RF_IF), rd_rn_rm),
15629218822Sdim cCL(rdfsz,	e500160, 3, (RF, RF, RF_IF), rd_rn_rm),
15630218822Sdim cCL(rdfd,	e500180, 3, (RF, RF, RF_IF), rd_rn_rm),
15631218822Sdim cCL(rdfdp,	e5001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15632218822Sdim cCL(rdfdm,	e5001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15633218822Sdim cCL(rdfdz,	e5001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15634218822Sdim cCL(rdfe,	e580100, 3, (RF, RF, RF_IF), rd_rn_rm),
15635218822Sdim cCL(rdfep,	e580120, 3, (RF, RF, RF_IF), rd_rn_rm),
15636218822Sdim cCL(rdfem,	e580140, 3, (RF, RF, RF_IF), rd_rn_rm),
15637218822Sdim cCL(rdfez,	e580160, 3, (RF, RF, RF_IF), rd_rn_rm),
15638218822Sdim
15639218822Sdim cCL(pows,	e600100, 3, (RF, RF, RF_IF), rd_rn_rm),
15640218822Sdim cCL(powsp,	e600120, 3, (RF, RF, RF_IF), rd_rn_rm),
15641218822Sdim cCL(powsm,	e600140, 3, (RF, RF, RF_IF), rd_rn_rm),
15642218822Sdim cCL(powsz,	e600160, 3, (RF, RF, RF_IF), rd_rn_rm),
15643218822Sdim cCL(powd,	e600180, 3, (RF, RF, RF_IF), rd_rn_rm),
15644218822Sdim cCL(powdp,	e6001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15645218822Sdim cCL(powdm,	e6001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15646218822Sdim cCL(powdz,	e6001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15647218822Sdim cCL(powe,	e680100, 3, (RF, RF, RF_IF), rd_rn_rm),
15648218822Sdim cCL(powep,	e680120, 3, (RF, RF, RF_IF), rd_rn_rm),
15649218822Sdim cCL(powem,	e680140, 3, (RF, RF, RF_IF), rd_rn_rm),
15650218822Sdim cCL(powez,	e680160, 3, (RF, RF, RF_IF), rd_rn_rm),
15651218822Sdim
15652218822Sdim cCL(rpws,	e700100, 3, (RF, RF, RF_IF), rd_rn_rm),
15653218822Sdim cCL(rpwsp,	e700120, 3, (RF, RF, RF_IF), rd_rn_rm),
15654218822Sdim cCL(rpwsm,	e700140, 3, (RF, RF, RF_IF), rd_rn_rm),
15655218822Sdim cCL(rpwsz,	e700160, 3, (RF, RF, RF_IF), rd_rn_rm),
15656218822Sdim cCL(rpwd,	e700180, 3, (RF, RF, RF_IF), rd_rn_rm),
15657218822Sdim cCL(rpwdp,	e7001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15658218822Sdim cCL(rpwdm,	e7001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15659218822Sdim cCL(rpwdz,	e7001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15660218822Sdim cCL(rpwe,	e780100, 3, (RF, RF, RF_IF), rd_rn_rm),
15661218822Sdim cCL(rpwep,	e780120, 3, (RF, RF, RF_IF), rd_rn_rm),
15662218822Sdim cCL(rpwem,	e780140, 3, (RF, RF, RF_IF), rd_rn_rm),
15663218822Sdim cCL(rpwez,	e780160, 3, (RF, RF, RF_IF), rd_rn_rm),
15664218822Sdim
15665218822Sdim cCL(rmfs,	e800100, 3, (RF, RF, RF_IF), rd_rn_rm),
15666218822Sdim cCL(rmfsp,	e800120, 3, (RF, RF, RF_IF), rd_rn_rm),
15667218822Sdim cCL(rmfsm,	e800140, 3, (RF, RF, RF_IF), rd_rn_rm),
15668218822Sdim cCL(rmfsz,	e800160, 3, (RF, RF, RF_IF), rd_rn_rm),
15669218822Sdim cCL(rmfd,	e800180, 3, (RF, RF, RF_IF), rd_rn_rm),
15670218822Sdim cCL(rmfdp,	e8001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15671218822Sdim cCL(rmfdm,	e8001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15672218822Sdim cCL(rmfdz,	e8001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15673218822Sdim cCL(rmfe,	e880100, 3, (RF, RF, RF_IF), rd_rn_rm),
15674218822Sdim cCL(rmfep,	e880120, 3, (RF, RF, RF_IF), rd_rn_rm),
15675218822Sdim cCL(rmfem,	e880140, 3, (RF, RF, RF_IF), rd_rn_rm),
15676218822Sdim cCL(rmfez,	e880160, 3, (RF, RF, RF_IF), rd_rn_rm),
15677218822Sdim
15678218822Sdim cCL(fmls,	e900100, 3, (RF, RF, RF_IF), rd_rn_rm),
15679218822Sdim cCL(fmlsp,	e900120, 3, (RF, RF, RF_IF), rd_rn_rm),
15680218822Sdim cCL(fmlsm,	e900140, 3, (RF, RF, RF_IF), rd_rn_rm),
15681218822Sdim cCL(fmlsz,	e900160, 3, (RF, RF, RF_IF), rd_rn_rm),
15682218822Sdim cCL(fmld,	e900180, 3, (RF, RF, RF_IF), rd_rn_rm),
15683218822Sdim cCL(fmldp,	e9001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15684218822Sdim cCL(fmldm,	e9001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15685218822Sdim cCL(fmldz,	e9001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15686218822Sdim cCL(fmle,	e980100, 3, (RF, RF, RF_IF), rd_rn_rm),
15687218822Sdim cCL(fmlep,	e980120, 3, (RF, RF, RF_IF), rd_rn_rm),
15688218822Sdim cCL(fmlem,	e980140, 3, (RF, RF, RF_IF), rd_rn_rm),
15689218822Sdim cCL(fmlez,	e980160, 3, (RF, RF, RF_IF), rd_rn_rm),
15690218822Sdim
15691218822Sdim cCL(fdvs,	ea00100, 3, (RF, RF, RF_IF), rd_rn_rm),
15692218822Sdim cCL(fdvsp,	ea00120, 3, (RF, RF, RF_IF), rd_rn_rm),
15693218822Sdim cCL(fdvsm,	ea00140, 3, (RF, RF, RF_IF), rd_rn_rm),
15694218822Sdim cCL(fdvsz,	ea00160, 3, (RF, RF, RF_IF), rd_rn_rm),
15695218822Sdim cCL(fdvd,	ea00180, 3, (RF, RF, RF_IF), rd_rn_rm),
15696218822Sdim cCL(fdvdp,	ea001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15697218822Sdim cCL(fdvdm,	ea001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15698218822Sdim cCL(fdvdz,	ea001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15699218822Sdim cCL(fdve,	ea80100, 3, (RF, RF, RF_IF), rd_rn_rm),
15700218822Sdim cCL(fdvep,	ea80120, 3, (RF, RF, RF_IF), rd_rn_rm),
15701218822Sdim cCL(fdvem,	ea80140, 3, (RF, RF, RF_IF), rd_rn_rm),
15702218822Sdim cCL(fdvez,	ea80160, 3, (RF, RF, RF_IF), rd_rn_rm),
15703218822Sdim
15704218822Sdim cCL(frds,	eb00100, 3, (RF, RF, RF_IF), rd_rn_rm),
15705218822Sdim cCL(frdsp,	eb00120, 3, (RF, RF, RF_IF), rd_rn_rm),
15706218822Sdim cCL(frdsm,	eb00140, 3, (RF, RF, RF_IF), rd_rn_rm),
15707218822Sdim cCL(frdsz,	eb00160, 3, (RF, RF, RF_IF), rd_rn_rm),
15708218822Sdim cCL(frdd,	eb00180, 3, (RF, RF, RF_IF), rd_rn_rm),
15709218822Sdim cCL(frddp,	eb001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15710218822Sdim cCL(frddm,	eb001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15711218822Sdim cCL(frddz,	eb001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15712218822Sdim cCL(frde,	eb80100, 3, (RF, RF, RF_IF), rd_rn_rm),
15713218822Sdim cCL(frdep,	eb80120, 3, (RF, RF, RF_IF), rd_rn_rm),
15714218822Sdim cCL(frdem,	eb80140, 3, (RF, RF, RF_IF), rd_rn_rm),
15715218822Sdim cCL(frdez,	eb80160, 3, (RF, RF, RF_IF), rd_rn_rm),
15716218822Sdim
15717218822Sdim cCL(pols,	ec00100, 3, (RF, RF, RF_IF), rd_rn_rm),
15718218822Sdim cCL(polsp,	ec00120, 3, (RF, RF, RF_IF), rd_rn_rm),
15719218822Sdim cCL(polsm,	ec00140, 3, (RF, RF, RF_IF), rd_rn_rm),
15720218822Sdim cCL(polsz,	ec00160, 3, (RF, RF, RF_IF), rd_rn_rm),
15721218822Sdim cCL(pold,	ec00180, 3, (RF, RF, RF_IF), rd_rn_rm),
15722218822Sdim cCL(poldp,	ec001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15723218822Sdim cCL(poldm,	ec001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15724218822Sdim cCL(poldz,	ec001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15725218822Sdim cCL(pole,	ec80100, 3, (RF, RF, RF_IF), rd_rn_rm),
15726218822Sdim cCL(polep,	ec80120, 3, (RF, RF, RF_IF), rd_rn_rm),
15727218822Sdim cCL(polem,	ec80140, 3, (RF, RF, RF_IF), rd_rn_rm),
15728218822Sdim cCL(polez,	ec80160, 3, (RF, RF, RF_IF), rd_rn_rm),
15729218822Sdim
15730218822Sdim cCE(cmf,	e90f110, 2, (RF, RF_IF),     fpa_cmp),
15731218822Sdim C3E(cmfe,	ed0f110, 2, (RF, RF_IF),     fpa_cmp),
15732218822Sdim cCE(cnf,	eb0f110, 2, (RF, RF_IF),     fpa_cmp),
15733218822Sdim C3E(cnfe,	ef0f110, 2, (RF, RF_IF),     fpa_cmp),
15734218822Sdim
15735218822Sdim cCL(flts,	e000110, 2, (RF, RR),	     rn_rd),
15736218822Sdim cCL(fltsp,	e000130, 2, (RF, RR),	     rn_rd),
15737218822Sdim cCL(fltsm,	e000150, 2, (RF, RR),	     rn_rd),
15738218822Sdim cCL(fltsz,	e000170, 2, (RF, RR),	     rn_rd),
15739218822Sdim cCL(fltd,	e000190, 2, (RF, RR),	     rn_rd),
15740218822Sdim cCL(fltdp,	e0001b0, 2, (RF, RR),	     rn_rd),
15741218822Sdim cCL(fltdm,	e0001d0, 2, (RF, RR),	     rn_rd),
15742218822Sdim cCL(fltdz,	e0001f0, 2, (RF, RR),	     rn_rd),
15743218822Sdim cCL(flte,	e080110, 2, (RF, RR),	     rn_rd),
15744218822Sdim cCL(fltep,	e080130, 2, (RF, RR),	     rn_rd),
15745218822Sdim cCL(fltem,	e080150, 2, (RF, RR),	     rn_rd),
15746218822Sdim cCL(fltez,	e080170, 2, (RF, RR),	     rn_rd),
15747218822Sdim
15748218822Sdim  /* The implementation of the FIX instruction is broken on some
15749218822Sdim     assemblers, in that it accepts a precision specifier as well as a
15750218822Sdim     rounding specifier, despite the fact that this is meaningless.
15751218822Sdim     To be more compatible, we accept it as well, though of course it
15752218822Sdim     does not set any bits.  */
15753218822Sdim cCE(fix,	e100110, 2, (RR, RF),	     rd_rm),
15754218822Sdim cCL(fixp,	e100130, 2, (RR, RF),	     rd_rm),
15755218822Sdim cCL(fixm,	e100150, 2, (RR, RF),	     rd_rm),
15756218822Sdim cCL(fixz,	e100170, 2, (RR, RF),	     rd_rm),
15757218822Sdim cCL(fixsp,	e100130, 2, (RR, RF),	     rd_rm),
15758218822Sdim cCL(fixsm,	e100150, 2, (RR, RF),	     rd_rm),
15759218822Sdim cCL(fixsz,	e100170, 2, (RR, RF),	     rd_rm),
15760218822Sdim cCL(fixdp,	e100130, 2, (RR, RF),	     rd_rm),
15761218822Sdim cCL(fixdm,	e100150, 2, (RR, RF),	     rd_rm),
15762218822Sdim cCL(fixdz,	e100170, 2, (RR, RF),	     rd_rm),
15763218822Sdim cCL(fixep,	e100130, 2, (RR, RF),	     rd_rm),
15764218822Sdim cCL(fixem,	e100150, 2, (RR, RF),	     rd_rm),
15765218822Sdim cCL(fixez,	e100170, 2, (RR, RF),	     rd_rm),
15766218822Sdim
15767218822Sdim  /* Instructions that were new with the real FPA, call them V2.  */
15768218822Sdim#undef ARM_VARIANT
15769218822Sdim#define ARM_VARIANT &fpu_fpa_ext_v2
15770218822Sdim cCE(lfm,	c100200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15771218822Sdim cCL(lfmfd,	c900200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15772218822Sdim cCL(lfmea,	d100200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15773218822Sdim cCE(sfm,	c000200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15774218822Sdim cCL(sfmfd,	d000200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15775218822Sdim cCL(sfmea,	c800200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15776218822Sdim
15777218822Sdim#undef ARM_VARIANT
15778218822Sdim#define ARM_VARIANT &fpu_vfp_ext_v1xd  /* VFP V1xD (single precision).  */
15779218822Sdim  /* Moves and type conversions.  */
15780218822Sdim cCE(fcpys,	eb00a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15781218822Sdim cCE(fmrs,	e100a10, 2, (RR, RVS),	      vfp_reg_from_sp),
15782218822Sdim cCE(fmsr,	e000a10, 2, (RVS, RR),	      vfp_sp_from_reg),
15783218822Sdim cCE(fmstat,	ef1fa10, 0, (),		      noargs),
15784218822Sdim cCE(fsitos,	eb80ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15785218822Sdim cCE(fuitos,	eb80a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15786218822Sdim cCE(ftosis,	ebd0a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15787218822Sdim cCE(ftosizs,	ebd0ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15788218822Sdim cCE(ftouis,	ebc0a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15789218822Sdim cCE(ftouizs,	ebc0ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15790218822Sdim cCE(fmrx,	ef00a10, 2, (RR, RVC),	      rd_rn),
15791218822Sdim cCE(fmxr,	ee00a10, 2, (RVC, RR),	      rn_rd),
15792248460Sandrew cCE(vmrs,	ef00a10, 2, (APSR_RR, RVC),   vfp_vmrs),
15793248460Sandrew cCE(vmsr,	ee00a10, 2, (RVC, RR),        vfp_vmsr),
15794218822Sdim
15795218822Sdim  /* Memory operations.	 */
15796218822Sdim cCE(flds,	d100a00, 2, (RVS, ADDRGLDC),  vfp_sp_ldst),
15797218822Sdim cCE(fsts,	d000a00, 2, (RVS, ADDRGLDC),  vfp_sp_ldst),
15798218822Sdim cCE(fldmias,	c900a00, 2, (RRw, VRSLST),    vfp_sp_ldstmia),
15799218822Sdim cCE(fldmfds,	c900a00, 2, (RRw, VRSLST),    vfp_sp_ldstmia),
15800218822Sdim cCE(fldmdbs,	d300a00, 2, (RRw, VRSLST),    vfp_sp_ldstmdb),
15801218822Sdim cCE(fldmeas,	d300a00, 2, (RRw, VRSLST),    vfp_sp_ldstmdb),
15802218822Sdim cCE(fldmiax,	c900b00, 2, (RRw, VRDLST),    vfp_xp_ldstmia),
15803218822Sdim cCE(fldmfdx,	c900b00, 2, (RRw, VRDLST),    vfp_xp_ldstmia),
15804218822Sdim cCE(fldmdbx,	d300b00, 2, (RRw, VRDLST),    vfp_xp_ldstmdb),
15805218822Sdim cCE(fldmeax,	d300b00, 2, (RRw, VRDLST),    vfp_xp_ldstmdb),
15806218822Sdim cCE(fstmias,	c800a00, 2, (RRw, VRSLST),    vfp_sp_ldstmia),
15807218822Sdim cCE(fstmeas,	c800a00, 2, (RRw, VRSLST),    vfp_sp_ldstmia),
15808218822Sdim cCE(fstmdbs,	d200a00, 2, (RRw, VRSLST),    vfp_sp_ldstmdb),
15809218822Sdim cCE(fstmfds,	d200a00, 2, (RRw, VRSLST),    vfp_sp_ldstmdb),
15810218822Sdim cCE(fstmiax,	c800b00, 2, (RRw, VRDLST),    vfp_xp_ldstmia),
15811218822Sdim cCE(fstmeax,	c800b00, 2, (RRw, VRDLST),    vfp_xp_ldstmia),
15812218822Sdim cCE(fstmdbx,	d200b00, 2, (RRw, VRDLST),    vfp_xp_ldstmdb),
15813218822Sdim cCE(fstmfdx,	d200b00, 2, (RRw, VRDLST),    vfp_xp_ldstmdb),
15814218822Sdim
15815218822Sdim  /* Monadic operations.  */
15816218822Sdim cCE(fabss,	eb00ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15817218822Sdim cCE(fnegs,	eb10a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15818218822Sdim cCE(fsqrts,	eb10ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15819218822Sdim
15820218822Sdim  /* Dyadic operations.	 */
15821218822Sdim cCE(fadds,	e300a00, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15822218822Sdim cCE(fsubs,	e300a40, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15823218822Sdim cCE(fmuls,	e200a00, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15824218822Sdim cCE(fdivs,	e800a00, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15825218822Sdim cCE(fmacs,	e000a00, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15826218822Sdim cCE(fmscs,	e100a00, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15827218822Sdim cCE(fnmuls,	e200a40, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15828218822Sdim cCE(fnmacs,	e000a40, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15829218822Sdim cCE(fnmscs,	e100a40, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15830218822Sdim
15831218822Sdim  /* Comparisons.  */
15832218822Sdim cCE(fcmps,	eb40a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15833218822Sdim cCE(fcmpzs,	eb50a40, 1, (RVS),	      vfp_sp_compare_z),
15834218822Sdim cCE(fcmpes,	eb40ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15835218822Sdim cCE(fcmpezs,	eb50ac0, 1, (RVS),	      vfp_sp_compare_z),
15836218822Sdim
15837218822Sdim#undef ARM_VARIANT
15838218822Sdim#define ARM_VARIANT &fpu_vfp_ext_v1 /* VFP V1 (Double precision).  */
15839218822Sdim  /* Moves and type conversions.  */
15840218822Sdim cCE(fcpyd,	eb00b40, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15841218822Sdim cCE(fcvtds,	eb70ac0, 2, (RVD, RVS),	      vfp_dp_sp_cvt),
15842218822Sdim cCE(fcvtsd,	eb70bc0, 2, (RVS, RVD),	      vfp_sp_dp_cvt),
15843218822Sdim cCE(fmdhr,	e200b10, 2, (RVD, RR),	      vfp_dp_rn_rd),
15844218822Sdim cCE(fmdlr,	e000b10, 2, (RVD, RR),	      vfp_dp_rn_rd),
15845218822Sdim cCE(fmrdh,	e300b10, 2, (RR, RVD),	      vfp_dp_rd_rn),
15846218822Sdim cCE(fmrdl,	e100b10, 2, (RR, RVD),	      vfp_dp_rd_rn),
15847218822Sdim cCE(fsitod,	eb80bc0, 2, (RVD, RVS),	      vfp_dp_sp_cvt),
15848218822Sdim cCE(fuitod,	eb80b40, 2, (RVD, RVS),	      vfp_dp_sp_cvt),
15849218822Sdim cCE(ftosid,	ebd0b40, 2, (RVS, RVD),	      vfp_sp_dp_cvt),
15850218822Sdim cCE(ftosizd,	ebd0bc0, 2, (RVS, RVD),	      vfp_sp_dp_cvt),
15851218822Sdim cCE(ftouid,	ebc0b40, 2, (RVS, RVD),	      vfp_sp_dp_cvt),
15852218822Sdim cCE(ftouizd,	ebc0bc0, 2, (RVS, RVD),	      vfp_sp_dp_cvt),
15853218822Sdim
15854218822Sdim  /* Memory operations.	 */
15855218822Sdim cCE(fldd,	d100b00, 2, (RVD, ADDRGLDC),  vfp_dp_ldst),
15856218822Sdim cCE(fstd,	d000b00, 2, (RVD, ADDRGLDC),  vfp_dp_ldst),
15857218822Sdim cCE(fldmiad,	c900b00, 2, (RRw, VRDLST),    vfp_dp_ldstmia),
15858218822Sdim cCE(fldmfdd,	c900b00, 2, (RRw, VRDLST),    vfp_dp_ldstmia),
15859218822Sdim cCE(fldmdbd,	d300b00, 2, (RRw, VRDLST),    vfp_dp_ldstmdb),
15860218822Sdim cCE(fldmead,	d300b00, 2, (RRw, VRDLST),    vfp_dp_ldstmdb),
15861218822Sdim cCE(fstmiad,	c800b00, 2, (RRw, VRDLST),    vfp_dp_ldstmia),
15862218822Sdim cCE(fstmead,	c800b00, 2, (RRw, VRDLST),    vfp_dp_ldstmia),
15863218822Sdim cCE(fstmdbd,	d200b00, 2, (RRw, VRDLST),    vfp_dp_ldstmdb),
15864218822Sdim cCE(fstmfdd,	d200b00, 2, (RRw, VRDLST),    vfp_dp_ldstmdb),
15865218822Sdim
15866218822Sdim  /* Monadic operations.  */
15867218822Sdim cCE(fabsd,	eb00bc0, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15868218822Sdim cCE(fnegd,	eb10b40, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15869218822Sdim cCE(fsqrtd,	eb10bc0, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15870218822Sdim
15871218822Sdim  /* Dyadic operations.	 */
15872218822Sdim cCE(faddd,	e300b00, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15873218822Sdim cCE(fsubd,	e300b40, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15874218822Sdim cCE(fmuld,	e200b00, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15875218822Sdim cCE(fdivd,	e800b00, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15876218822Sdim cCE(fmacd,	e000b00, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15877218822Sdim cCE(fmscd,	e100b00, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15878218822Sdim cCE(fnmuld,	e200b40, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15879218822Sdim cCE(fnmacd,	e000b40, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15880218822Sdim cCE(fnmscd,	e100b40, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15881218822Sdim
15882218822Sdim  /* Comparisons.  */
15883218822Sdim cCE(fcmpd,	eb40b40, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15884218822Sdim cCE(fcmpzd,	eb50b40, 1, (RVD),	      vfp_dp_rd),
15885218822Sdim cCE(fcmped,	eb40bc0, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15886218822Sdim cCE(fcmpezd,	eb50bc0, 1, (RVD),	      vfp_dp_rd),
15887218822Sdim
15888218822Sdim#undef ARM_VARIANT
15889218822Sdim#define ARM_VARIANT &fpu_vfp_ext_v2
15890218822Sdim cCE(fmsrr,	c400a10, 3, (VRSLST, RR, RR), vfp_sp2_from_reg2),
15891218822Sdim cCE(fmrrs,	c500a10, 3, (RR, RR, VRSLST), vfp_reg2_from_sp2),
15892218822Sdim cCE(fmdrr,	c400b10, 3, (RVD, RR, RR),    vfp_dp_rm_rd_rn),
15893218822Sdim cCE(fmrrd,	c500b10, 3, (RR, RR, RVD),    vfp_dp_rd_rn_rm),
15894218822Sdim
15895218822Sdim/* Instructions which may belong to either the Neon or VFP instruction sets.
15896218822Sdim   Individual encoder functions perform additional architecture checks.  */
15897218822Sdim#undef ARM_VARIANT
15898218822Sdim#define ARM_VARIANT &fpu_vfp_ext_v1xd
15899218822Sdim#undef THUMB_VARIANT
15900218822Sdim#define THUMB_VARIANT &fpu_vfp_ext_v1xd
15901218822Sdim  /* These mnemonics are unique to VFP.  */
15902218822Sdim NCE(vsqrt,     0,       2, (RVSD, RVSD),       vfp_nsyn_sqrt),
15903218822Sdim NCE(vdiv,      0,       3, (RVSD, RVSD, RVSD), vfp_nsyn_div),
15904218822Sdim nCE(vnmul,     vnmul,   3, (RVSD, RVSD, RVSD), vfp_nsyn_nmul),
15905218822Sdim nCE(vnmla,     vnmla,   3, (RVSD, RVSD, RVSD), vfp_nsyn_nmul),
15906218822Sdim nCE(vnmls,     vnmls,   3, (RVSD, RVSD, RVSD), vfp_nsyn_nmul),
15907218822Sdim nCE(vcmp,      vcmp,    2, (RVSD, RVSD_I0),    vfp_nsyn_cmp),
15908218822Sdim nCE(vcmpe,     vcmpe,   2, (RVSD, RVSD_I0),    vfp_nsyn_cmp),
15909218822Sdim NCE(vpush,     0,       1, (VRSDLST),          vfp_nsyn_push),
15910218822Sdim NCE(vpop,      0,       1, (VRSDLST),          vfp_nsyn_pop),
15911218822Sdim NCE(vcvtz,     0,       2, (RVSD, RVSD),       vfp_nsyn_cvtz),
15912218822Sdim
15913218822Sdim  /* Mnemonics shared by Neon and VFP.  */
15914218822Sdim nCEF(vmul,     vmul,    3, (RNSDQ, oRNSDQ, RNSDQ_RNSC), neon_mul),
15915218822Sdim nCEF(vmla,     vmla,    3, (RNSDQ, oRNSDQ, RNSDQ_RNSC), neon_mac_maybe_scalar),
15916218822Sdim nCEF(vmls,     vmls,    3, (RNSDQ, oRNSDQ, RNSDQ_RNSC), neon_mac_maybe_scalar),
15917218822Sdim
15918218822Sdim nCEF(vadd,     vadd,    3, (RNSDQ, oRNSDQ, RNSDQ), neon_addsub_if_i),
15919218822Sdim nCEF(vsub,     vsub,    3, (RNSDQ, oRNSDQ, RNSDQ), neon_addsub_if_i),
15920218822Sdim
15921218822Sdim NCEF(vabs,     1b10300, 2, (RNSDQ, RNSDQ), neon_abs_neg),
15922218822Sdim NCEF(vneg,     1b10380, 2, (RNSDQ, RNSDQ), neon_abs_neg),
15923218822Sdim
15924218822Sdim NCE(vldm,      c900b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15925218822Sdim NCE(vldmia,    c900b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15926218822Sdim NCE(vldmdb,    d100b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15927218822Sdim NCE(vstm,      c800b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15928218822Sdim NCE(vstmia,    c800b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15929218822Sdim NCE(vstmdb,    d000b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15930218822Sdim NCE(vldr,      d100b00, 2, (RVSD, ADDRGLDC), neon_ldr_str),
15931218822Sdim NCE(vstr,      d000b00, 2, (RVSD, ADDRGLDC), neon_ldr_str),
15932218822Sdim
15933218822Sdim nCEF(vcvt,     vcvt,    3, (RNSDQ, RNSDQ, oI32b), neon_cvt),
15934218822Sdim
15935218822Sdim  /* NOTE: All VMOV encoding is special-cased!  */
15936218822Sdim NCE(vmov,      0,       1, (VMOV), neon_mov),
15937218822Sdim NCE(vmovq,     0,       1, (VMOV), neon_mov),
15938218822Sdim
15939218822Sdim#undef THUMB_VARIANT
15940218822Sdim#define THUMB_VARIANT &fpu_neon_ext_v1
15941218822Sdim#undef ARM_VARIANT
15942218822Sdim#define ARM_VARIANT &fpu_neon_ext_v1
15943218822Sdim  /* Data processing with three registers of the same length.  */
15944218822Sdim  /* integer ops, valid types S8 S16 S32 U8 U16 U32.  */
15945218822Sdim NUF(vaba,      0000710, 3, (RNDQ, RNDQ,  RNDQ), neon_dyadic_i_su),
15946218822Sdim NUF(vabaq,     0000710, 3, (RNQ,  RNQ,   RNQ),  neon_dyadic_i_su),
15947218822Sdim NUF(vhadd,     0000000, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i_su),
15948218822Sdim NUF(vhaddq,    0000000, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i_su),
15949218822Sdim NUF(vrhadd,    0000100, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i_su),
15950218822Sdim NUF(vrhaddq,   0000100, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i_su),
15951218822Sdim NUF(vhsub,     0000200, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i_su),
15952218822Sdim NUF(vhsubq,    0000200, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i_su),
15953218822Sdim  /* integer ops, valid types S8 S16 S32 S64 U8 U16 U32 U64.  */
15954218822Sdim NUF(vqadd,     0000010, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i64_su),
15955218822Sdim NUF(vqaddq,    0000010, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i64_su),
15956218822Sdim NUF(vqsub,     0000210, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i64_su),
15957218822Sdim NUF(vqsubq,    0000210, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i64_su),
15958218822Sdim NUF(vrshl,     0000500, 3, (RNDQ, oRNDQ, RNDQ), neon_rshl),
15959218822Sdim NUF(vrshlq,    0000500, 3, (RNQ,  oRNQ,  RNQ),  neon_rshl),
15960218822Sdim NUF(vqrshl,    0000510, 3, (RNDQ, oRNDQ, RNDQ), neon_rshl),
15961218822Sdim NUF(vqrshlq,   0000510, 3, (RNQ,  oRNQ,  RNQ),  neon_rshl),
15962218822Sdim  /* If not immediate, fall back to neon_dyadic_i64_su.
15963218822Sdim     shl_imm should accept I8 I16 I32 I64,
15964218822Sdim     qshl_imm should accept S8 S16 S32 S64 U8 U16 U32 U64.  */
15965218822Sdim nUF(vshl,      vshl,    3, (RNDQ, oRNDQ, RNDQ_I63b), neon_shl_imm),
15966218822Sdim nUF(vshlq,     vshl,    3, (RNQ,  oRNQ,  RNDQ_I63b), neon_shl_imm),
15967218822Sdim nUF(vqshl,     vqshl,   3, (RNDQ, oRNDQ, RNDQ_I63b), neon_qshl_imm),
15968218822Sdim nUF(vqshlq,    vqshl,   3, (RNQ,  oRNQ,  RNDQ_I63b), neon_qshl_imm),
15969218822Sdim  /* Logic ops, types optional & ignored.  */
15970218822Sdim nUF(vand,      vand,    2, (RNDQ, NILO),        neon_logic),
15971218822Sdim nUF(vandq,     vand,    2, (RNQ,  NILO),        neon_logic),
15972218822Sdim nUF(vbic,      vbic,    2, (RNDQ, NILO),        neon_logic),
15973218822Sdim nUF(vbicq,     vbic,    2, (RNQ,  NILO),        neon_logic),
15974218822Sdim nUF(vorr,      vorr,    2, (RNDQ, NILO),        neon_logic),
15975218822Sdim nUF(vorrq,     vorr,    2, (RNQ,  NILO),        neon_logic),
15976218822Sdim nUF(vorn,      vorn,    2, (RNDQ, NILO),        neon_logic),
15977218822Sdim nUF(vornq,     vorn,    2, (RNQ,  NILO),        neon_logic),
15978218822Sdim nUF(veor,      veor,    3, (RNDQ, oRNDQ, RNDQ), neon_logic),
15979218822Sdim nUF(veorq,     veor,    3, (RNQ,  oRNQ,  RNQ),  neon_logic),
15980218822Sdim  /* Bitfield ops, untyped.  */
15981218822Sdim NUF(vbsl,      1100110, 3, (RNDQ, RNDQ, RNDQ), neon_bitfield),
15982218822Sdim NUF(vbslq,     1100110, 3, (RNQ,  RNQ,  RNQ),  neon_bitfield),
15983218822Sdim NUF(vbit,      1200110, 3, (RNDQ, RNDQ, RNDQ), neon_bitfield),
15984218822Sdim NUF(vbitq,     1200110, 3, (RNQ,  RNQ,  RNQ),  neon_bitfield),
15985218822Sdim NUF(vbif,      1300110, 3, (RNDQ, RNDQ, RNDQ), neon_bitfield),
15986218822Sdim NUF(vbifq,     1300110, 3, (RNQ,  RNQ,  RNQ),  neon_bitfield),
15987218822Sdim  /* Int and float variants, types S8 S16 S32 U8 U16 U32 F32.  */
15988218822Sdim nUF(vabd,      vabd,    3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_if_su),
15989218822Sdim nUF(vabdq,     vabd,    3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_if_su),
15990218822Sdim nUF(vmax,      vmax,    3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_if_su),
15991218822Sdim nUF(vmaxq,     vmax,    3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_if_su),
15992218822Sdim nUF(vmin,      vmin,    3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_if_su),
15993218822Sdim nUF(vminq,     vmin,    3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_if_su),
15994218822Sdim  /* Comparisons. Types S8 S16 S32 U8 U16 U32 F32. Non-immediate versions fall
15995218822Sdim     back to neon_dyadic_if_su.  */
15996218822Sdim nUF(vcge,      vcge,    3, (RNDQ, oRNDQ, RNDQ_I0), neon_cmp),
15997218822Sdim nUF(vcgeq,     vcge,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_cmp),
15998218822Sdim nUF(vcgt,      vcgt,    3, (RNDQ, oRNDQ, RNDQ_I0), neon_cmp),
15999218822Sdim nUF(vcgtq,     vcgt,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_cmp),
16000218822Sdim nUF(vclt,      vclt,    3, (RNDQ, oRNDQ, RNDQ_I0), neon_cmp_inv),
16001218822Sdim nUF(vcltq,     vclt,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_cmp_inv),
16002218822Sdim nUF(vcle,      vcle,    3, (RNDQ, oRNDQ, RNDQ_I0), neon_cmp_inv),
16003218822Sdim nUF(vcleq,     vcle,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_cmp_inv),
16004218822Sdim  /* Comparison. Type I8 I16 I32 F32.  */
16005218822Sdim nUF(vceq,      vceq,    3, (RNDQ, oRNDQ, RNDQ_I0), neon_ceq),
16006218822Sdim nUF(vceqq,     vceq,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_ceq),
16007218822Sdim  /* As above, D registers only.  */
16008218822Sdim nUF(vpmax,     vpmax,   3, (RND, oRND, RND), neon_dyadic_if_su_d),
16009218822Sdim nUF(vpmin,     vpmin,   3, (RND, oRND, RND), neon_dyadic_if_su_d),
16010218822Sdim  /* Int and float variants, signedness unimportant.  */
16011218822Sdim nUF(vmlaq,     vmla,    3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_mac_maybe_scalar),
16012218822Sdim nUF(vmlsq,     vmls,    3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_mac_maybe_scalar),
16013218822Sdim nUF(vpadd,     vpadd,   3, (RND,  oRND,  RND),       neon_dyadic_if_i_d),
16014218822Sdim  /* Add/sub take types I8 I16 I32 I64 F32.  */
16015218822Sdim nUF(vaddq,     vadd,    3, (RNQ,  oRNQ,  RNQ),  neon_addsub_if_i),
16016218822Sdim nUF(vsubq,     vsub,    3, (RNQ,  oRNQ,  RNQ),  neon_addsub_if_i),
16017218822Sdim  /* vtst takes sizes 8, 16, 32.  */
16018218822Sdim NUF(vtst,      0000810, 3, (RNDQ, oRNDQ, RNDQ), neon_tst),
16019218822Sdim NUF(vtstq,     0000810, 3, (RNQ,  oRNQ,  RNQ),  neon_tst),
16020218822Sdim  /* VMUL takes I8 I16 I32 F32 P8.  */
16021218822Sdim nUF(vmulq,     vmul,     3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_mul),
16022218822Sdim  /* VQD{R}MULH takes S16 S32.  */
16023218822Sdim nUF(vqdmulh,   vqdmulh,  3, (RNDQ, oRNDQ, RNDQ_RNSC), neon_qdmulh),
16024218822Sdim nUF(vqdmulhq,  vqdmulh,  3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_qdmulh),
16025218822Sdim nUF(vqrdmulh,  vqrdmulh, 3, (RNDQ, oRNDQ, RNDQ_RNSC), neon_qdmulh),
16026218822Sdim nUF(vqrdmulhq, vqrdmulh, 3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_qdmulh),
16027218822Sdim NUF(vacge,     0000e10,  3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute),
16028218822Sdim NUF(vacgeq,    0000e10,  3, (RNQ,  oRNQ,  RNQ),  neon_fcmp_absolute),
16029218822Sdim NUF(vacgt,     0200e10,  3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute),
16030218822Sdim NUF(vacgtq,    0200e10,  3, (RNQ,  oRNQ,  RNQ),  neon_fcmp_absolute),
16031218822Sdim NUF(vaclt,     0200e10,  3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute_inv),
16032218822Sdim NUF(vacltq,    0200e10,  3, (RNQ,  oRNQ,  RNQ),  neon_fcmp_absolute_inv),
16033218822Sdim NUF(vacle,     0000e10,  3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute_inv),
16034218822Sdim NUF(vacleq,    0000e10,  3, (RNQ,  oRNQ,  RNQ),  neon_fcmp_absolute_inv),
16035218822Sdim NUF(vrecps,    0000f10,  3, (RNDQ, oRNDQ, RNDQ), neon_step),
16036218822Sdim NUF(vrecpsq,   0000f10,  3, (RNQ,  oRNQ,  RNQ),  neon_step),
16037218822Sdim NUF(vrsqrts,   0200f10,  3, (RNDQ, oRNDQ, RNDQ), neon_step),
16038218822Sdim NUF(vrsqrtsq,  0200f10,  3, (RNQ,  oRNQ,  RNQ),  neon_step),
16039218822Sdim
16040218822Sdim  /* Two address, int/float. Types S8 S16 S32 F32.  */
16041218822Sdim NUF(vabsq,     1b10300, 2, (RNQ,  RNQ),      neon_abs_neg),
16042218822Sdim NUF(vnegq,     1b10380, 2, (RNQ,  RNQ),      neon_abs_neg),
16043218822Sdim
16044218822Sdim  /* Data processing with two registers and a shift amount.  */
16045218822Sdim  /* Right shifts, and variants with rounding.
16046218822Sdim     Types accepted S8 S16 S32 S64 U8 U16 U32 U64.  */
16047218822Sdim NUF(vshr,      0800010, 3, (RNDQ, oRNDQ, I64z), neon_rshift_round_imm),
16048218822Sdim NUF(vshrq,     0800010, 3, (RNQ,  oRNQ,  I64z), neon_rshift_round_imm),
16049218822Sdim NUF(vrshr,     0800210, 3, (RNDQ, oRNDQ, I64z), neon_rshift_round_imm),
16050218822Sdim NUF(vrshrq,    0800210, 3, (RNQ,  oRNQ,  I64z), neon_rshift_round_imm),
16051218822Sdim NUF(vsra,      0800110, 3, (RNDQ, oRNDQ, I64),  neon_rshift_round_imm),
16052218822Sdim NUF(vsraq,     0800110, 3, (RNQ,  oRNQ,  I64),  neon_rshift_round_imm),
16053218822Sdim NUF(vrsra,     0800310, 3, (RNDQ, oRNDQ, I64),  neon_rshift_round_imm),
16054218822Sdim NUF(vrsraq,    0800310, 3, (RNQ,  oRNQ,  I64),  neon_rshift_round_imm),
16055218822Sdim  /* Shift and insert. Sizes accepted 8 16 32 64.  */
16056218822Sdim NUF(vsli,      1800510, 3, (RNDQ, oRNDQ, I63), neon_sli),
16057218822Sdim NUF(vsliq,     1800510, 3, (RNQ,  oRNQ,  I63), neon_sli),
16058218822Sdim NUF(vsri,      1800410, 3, (RNDQ, oRNDQ, I64), neon_sri),
16059218822Sdim NUF(vsriq,     1800410, 3, (RNQ,  oRNQ,  I64), neon_sri),
16060218822Sdim  /* QSHL{U} immediate accepts S8 S16 S32 S64 U8 U16 U32 U64.  */
16061218822Sdim NUF(vqshlu,    1800610, 3, (RNDQ, oRNDQ, I63), neon_qshlu_imm),
16062218822Sdim NUF(vqshluq,   1800610, 3, (RNQ,  oRNQ,  I63), neon_qshlu_imm),
16063218822Sdim  /* Right shift immediate, saturating & narrowing, with rounding variants.
16064218822Sdim     Types accepted S16 S32 S64 U16 U32 U64.  */
16065218822Sdim NUF(vqshrn,    0800910, 3, (RND, RNQ, I32z), neon_rshift_sat_narrow),
16066218822Sdim NUF(vqrshrn,   0800950, 3, (RND, RNQ, I32z), neon_rshift_sat_narrow),
16067218822Sdim  /* As above, unsigned. Types accepted S16 S32 S64.  */
16068218822Sdim NUF(vqshrun,   0800810, 3, (RND, RNQ, I32z), neon_rshift_sat_narrow_u),
16069218822Sdim NUF(vqrshrun,  0800850, 3, (RND, RNQ, I32z), neon_rshift_sat_narrow_u),
16070218822Sdim  /* Right shift narrowing. Types accepted I16 I32 I64.  */
16071218822Sdim NUF(vshrn,     0800810, 3, (RND, RNQ, I32z), neon_rshift_narrow),
16072218822Sdim NUF(vrshrn,    0800850, 3, (RND, RNQ, I32z), neon_rshift_narrow),
16073218822Sdim  /* Special case. Types S8 S16 S32 U8 U16 U32. Handles max shift variant.  */
16074218822Sdim nUF(vshll,     vshll,   3, (RNQ, RND, I32),  neon_shll),
16075218822Sdim  /* CVT with optional immediate for fixed-point variant.  */
16076218822Sdim nUF(vcvtq,     vcvt,    3, (RNQ, RNQ, oI32b), neon_cvt),
16077218822Sdim
16078218822Sdim nUF(vmvn,      vmvn,    2, (RNDQ, RNDQ_IMVNb), neon_mvn),
16079218822Sdim nUF(vmvnq,     vmvn,    2, (RNQ,  RNDQ_IMVNb), neon_mvn),
16080218822Sdim
16081218822Sdim  /* Data processing, three registers of different lengths.  */
16082218822Sdim  /* Dyadic, long insns. Types S8 S16 S32 U8 U16 U32.  */
16083218822Sdim NUF(vabal,     0800500, 3, (RNQ, RND, RND),  neon_abal),
16084218822Sdim NUF(vabdl,     0800700, 3, (RNQ, RND, RND),  neon_dyadic_long),
16085218822Sdim NUF(vaddl,     0800000, 3, (RNQ, RND, RND),  neon_dyadic_long),
16086218822Sdim NUF(vsubl,     0800200, 3, (RNQ, RND, RND),  neon_dyadic_long),
16087218822Sdim  /* If not scalar, fall back to neon_dyadic_long.
16088218822Sdim     Vector types as above, scalar types S16 S32 U16 U32.  */
16089218822Sdim nUF(vmlal,     vmlal,   3, (RNQ, RND, RND_RNSC), neon_mac_maybe_scalar_long),
16090218822Sdim nUF(vmlsl,     vmlsl,   3, (RNQ, RND, RND_RNSC), neon_mac_maybe_scalar_long),
16091218822Sdim  /* Dyadic, widening insns. Types S8 S16 S32 U8 U16 U32.  */
16092218822Sdim NUF(vaddw,     0800100, 3, (RNQ, oRNQ, RND), neon_dyadic_wide),
16093218822Sdim NUF(vsubw,     0800300, 3, (RNQ, oRNQ, RND), neon_dyadic_wide),
16094218822Sdim  /* Dyadic, narrowing insns. Types I16 I32 I64.  */
16095218822Sdim NUF(vaddhn,    0800400, 3, (RND, RNQ, RNQ),  neon_dyadic_narrow),
16096218822Sdim NUF(vraddhn,   1800400, 3, (RND, RNQ, RNQ),  neon_dyadic_narrow),
16097218822Sdim NUF(vsubhn,    0800600, 3, (RND, RNQ, RNQ),  neon_dyadic_narrow),
16098218822Sdim NUF(vrsubhn,   1800600, 3, (RND, RNQ, RNQ),  neon_dyadic_narrow),
16099218822Sdim  /* Saturating doubling multiplies. Types S16 S32.  */
16100218822Sdim nUF(vqdmlal,   vqdmlal, 3, (RNQ, RND, RND_RNSC), neon_mul_sat_scalar_long),
16101218822Sdim nUF(vqdmlsl,   vqdmlsl, 3, (RNQ, RND, RND_RNSC), neon_mul_sat_scalar_long),
16102218822Sdim nUF(vqdmull,   vqdmull, 3, (RNQ, RND, RND_RNSC), neon_mul_sat_scalar_long),
16103218822Sdim  /* VMULL. Vector types S8 S16 S32 U8 U16 U32 P8, scalar types
16104218822Sdim     S16 S32 U16 U32.  */
16105218822Sdim nUF(vmull,     vmull,   3, (RNQ, RND, RND_RNSC), neon_vmull),
16106218822Sdim
16107218822Sdim  /* Extract. Size 8.  */
16108218822Sdim NUF(vext,      0b00000, 4, (RNDQ, oRNDQ, RNDQ, I15), neon_ext),
16109218822Sdim NUF(vextq,     0b00000, 4, (RNQ,  oRNQ,  RNQ,  I15), neon_ext),
16110218822Sdim
16111218822Sdim  /* Two registers, miscellaneous.  */
16112218822Sdim  /* Reverse. Sizes 8 16 32 (must be < size in opcode).  */
16113218822Sdim NUF(vrev64,    1b00000, 2, (RNDQ, RNDQ),     neon_rev),
16114218822Sdim NUF(vrev64q,   1b00000, 2, (RNQ,  RNQ),      neon_rev),
16115218822Sdim NUF(vrev32,    1b00080, 2, (RNDQ, RNDQ),     neon_rev),
16116218822Sdim NUF(vrev32q,   1b00080, 2, (RNQ,  RNQ),      neon_rev),
16117218822Sdim NUF(vrev16,    1b00100, 2, (RNDQ, RNDQ),     neon_rev),
16118218822Sdim NUF(vrev16q,   1b00100, 2, (RNQ,  RNQ),      neon_rev),
16119218822Sdim  /* Vector replicate. Sizes 8 16 32.  */
16120218822Sdim nCE(vdup,      vdup,    2, (RNDQ, RR_RNSC),  neon_dup),
16121218822Sdim nCE(vdupq,     vdup,    2, (RNQ,  RR_RNSC),  neon_dup),
16122218822Sdim  /* VMOVL. Types S8 S16 S32 U8 U16 U32.  */
16123218822Sdim NUF(vmovl,     0800a10, 2, (RNQ, RND),       neon_movl),
16124218822Sdim  /* VMOVN. Types I16 I32 I64.  */
16125218822Sdim nUF(vmovn,     vmovn,   2, (RND, RNQ),       neon_movn),
16126218822Sdim  /* VQMOVN. Types S16 S32 S64 U16 U32 U64.  */
16127218822Sdim nUF(vqmovn,    vqmovn,  2, (RND, RNQ),       neon_qmovn),
16128218822Sdim  /* VQMOVUN. Types S16 S32 S64.  */
16129218822Sdim nUF(vqmovun,   vqmovun, 2, (RND, RNQ),       neon_qmovun),
16130218822Sdim  /* VZIP / VUZP. Sizes 8 16 32.  */
16131218822Sdim NUF(vzip,      1b20180, 2, (RNDQ, RNDQ),     neon_zip_uzp),
16132218822Sdim NUF(vzipq,     1b20180, 2, (RNQ,  RNQ),      neon_zip_uzp),
16133218822Sdim NUF(vuzp,      1b20100, 2, (RNDQ, RNDQ),     neon_zip_uzp),
16134218822Sdim NUF(vuzpq,     1b20100, 2, (RNQ,  RNQ),      neon_zip_uzp),
16135218822Sdim  /* VQABS / VQNEG. Types S8 S16 S32.  */
16136218822Sdim NUF(vqabs,     1b00700, 2, (RNDQ, RNDQ),     neon_sat_abs_neg),
16137218822Sdim NUF(vqabsq,    1b00700, 2, (RNQ,  RNQ),      neon_sat_abs_neg),
16138218822Sdim NUF(vqneg,     1b00780, 2, (RNDQ, RNDQ),     neon_sat_abs_neg),
16139218822Sdim NUF(vqnegq,    1b00780, 2, (RNQ,  RNQ),      neon_sat_abs_neg),
16140218822Sdim  /* Pairwise, lengthening. Types S8 S16 S32 U8 U16 U32.  */
16141218822Sdim NUF(vpadal,    1b00600, 2, (RNDQ, RNDQ),     neon_pair_long),
16142218822Sdim NUF(vpadalq,   1b00600, 2, (RNQ,  RNQ),      neon_pair_long),
16143218822Sdim NUF(vpaddl,    1b00200, 2, (RNDQ, RNDQ),     neon_pair_long),
16144218822Sdim NUF(vpaddlq,   1b00200, 2, (RNQ,  RNQ),      neon_pair_long),
16145218822Sdim  /* Reciprocal estimates. Types U32 F32.  */
16146218822Sdim NUF(vrecpe,    1b30400, 2, (RNDQ, RNDQ),     neon_recip_est),
16147218822Sdim NUF(vrecpeq,   1b30400, 2, (RNQ,  RNQ),      neon_recip_est),
16148218822Sdim NUF(vrsqrte,   1b30480, 2, (RNDQ, RNDQ),     neon_recip_est),
16149218822Sdim NUF(vrsqrteq,  1b30480, 2, (RNQ,  RNQ),      neon_recip_est),
16150218822Sdim  /* VCLS. Types S8 S16 S32.  */
16151218822Sdim NUF(vcls,      1b00400, 2, (RNDQ, RNDQ),     neon_cls),
16152218822Sdim NUF(vclsq,     1b00400, 2, (RNQ,  RNQ),      neon_cls),
16153218822Sdim  /* VCLZ. Types I8 I16 I32.  */
16154218822Sdim NUF(vclz,      1b00480, 2, (RNDQ, RNDQ),     neon_clz),
16155218822Sdim NUF(vclzq,     1b00480, 2, (RNQ,  RNQ),      neon_clz),
16156218822Sdim  /* VCNT. Size 8.  */
16157218822Sdim NUF(vcnt,      1b00500, 2, (RNDQ, RNDQ),     neon_cnt),
16158218822Sdim NUF(vcntq,     1b00500, 2, (RNQ,  RNQ),      neon_cnt),
16159218822Sdim  /* Two address, untyped.  */
16160218822Sdim NUF(vswp,      1b20000, 2, (RNDQ, RNDQ),     neon_swp),
16161218822Sdim NUF(vswpq,     1b20000, 2, (RNQ,  RNQ),      neon_swp),
16162218822Sdim  /* VTRN. Sizes 8 16 32.  */
16163218822Sdim nUF(vtrn,      vtrn,    2, (RNDQ, RNDQ),     neon_trn),
16164218822Sdim nUF(vtrnq,     vtrn,    2, (RNQ,  RNQ),      neon_trn),
16165218822Sdim
16166218822Sdim  /* Table lookup. Size 8.  */
16167218822Sdim NUF(vtbl,      1b00800, 3, (RND, NRDLST, RND), neon_tbl_tbx),
16168218822Sdim NUF(vtbx,      1b00840, 3, (RND, NRDLST, RND), neon_tbl_tbx),
16169218822Sdim
16170218822Sdim#undef THUMB_VARIANT
16171218822Sdim#define THUMB_VARIANT &fpu_vfp_v3_or_neon_ext
16172218822Sdim#undef ARM_VARIANT
16173218822Sdim#define ARM_VARIANT &fpu_vfp_v3_or_neon_ext
16174218822Sdim  /* Neon element/structure load/store.  */
16175218822Sdim nUF(vld1,      vld1,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16176218822Sdim nUF(vst1,      vst1,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16177218822Sdim nUF(vld2,      vld2,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16178218822Sdim nUF(vst2,      vst2,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16179218822Sdim nUF(vld3,      vld3,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16180218822Sdim nUF(vst3,      vst3,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16181218822Sdim nUF(vld4,      vld4,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16182218822Sdim nUF(vst4,      vst4,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16183218822Sdim
16184218822Sdim#undef THUMB_VARIANT
16185218822Sdim#define THUMB_VARIANT &fpu_vfp_ext_v3
16186218822Sdim#undef ARM_VARIANT
16187218822Sdim#define ARM_VARIANT &fpu_vfp_ext_v3
16188218822Sdim cCE(fconsts,   eb00a00, 2, (RVS, I255),      vfp_sp_const),
16189218822Sdim cCE(fconstd,   eb00b00, 2, (RVD, I255),      vfp_dp_const),
16190218822Sdim cCE(fshtos,    eba0a40, 2, (RVS, I16z),      vfp_sp_conv_16),
16191218822Sdim cCE(fshtod,    eba0b40, 2, (RVD, I16z),      vfp_dp_conv_16),
16192218822Sdim cCE(fsltos,    eba0ac0, 2, (RVS, I32),       vfp_sp_conv_32),
16193218822Sdim cCE(fsltod,    eba0bc0, 2, (RVD, I32),       vfp_dp_conv_32),
16194218822Sdim cCE(fuhtos,    ebb0a40, 2, (RVS, I16z),      vfp_sp_conv_16),
16195218822Sdim cCE(fuhtod,    ebb0b40, 2, (RVD, I16z),      vfp_dp_conv_16),
16196218822Sdim cCE(fultos,    ebb0ac0, 2, (RVS, I32),       vfp_sp_conv_32),
16197218822Sdim cCE(fultod,    ebb0bc0, 2, (RVD, I32),       vfp_dp_conv_32),
16198218822Sdim cCE(ftoshs,    ebe0a40, 2, (RVS, I16z),      vfp_sp_conv_16),
16199218822Sdim cCE(ftoshd,    ebe0b40, 2, (RVD, I16z),      vfp_dp_conv_16),
16200218822Sdim cCE(ftosls,    ebe0ac0, 2, (RVS, I32),       vfp_sp_conv_32),
16201218822Sdim cCE(ftosld,    ebe0bc0, 2, (RVD, I32),       vfp_dp_conv_32),
16202218822Sdim cCE(ftouhs,    ebf0a40, 2, (RVS, I16z),      vfp_sp_conv_16),
16203218822Sdim cCE(ftouhd,    ebf0b40, 2, (RVD, I16z),      vfp_dp_conv_16),
16204218822Sdim cCE(ftouls,    ebf0ac0, 2, (RVS, I32),       vfp_sp_conv_32),
16205218822Sdim cCE(ftould,    ebf0bc0, 2, (RVD, I32),       vfp_dp_conv_32),
16206218822Sdim
16207218822Sdim#undef THUMB_VARIANT
16208218822Sdim#undef ARM_VARIANT
16209218822Sdim#define ARM_VARIANT &arm_cext_xscale /* Intel XScale extensions.	 */
16210218822Sdim cCE(mia,	e200010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16211218822Sdim cCE(miaph,	e280010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16212218822Sdim cCE(miabb,	e2c0010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16213218822Sdim cCE(miabt,	e2d0010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16214218822Sdim cCE(miatb,	e2e0010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16215218822Sdim cCE(miatt,	e2f0010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16216218822Sdim cCE(mar,	c400000, 3, (RXA, RRnpc, RRnpc), xsc_mar),
16217218822Sdim cCE(mra,	c500000, 3, (RRnpc, RRnpc, RXA), xsc_mra),
16218218822Sdim
16219218822Sdim#undef ARM_VARIANT
16220218822Sdim#define ARM_VARIANT &arm_cext_iwmmxt /* Intel Wireless MMX technology.  */
16221218822Sdim cCE(tandcb,	e13f130, 1, (RR),		    iwmmxt_tandorc),
16222218822Sdim cCE(tandch,	e53f130, 1, (RR),		    iwmmxt_tandorc),
16223218822Sdim cCE(tandcw,	e93f130, 1, (RR),		    iwmmxt_tandorc),
16224218822Sdim cCE(tbcstb,	e400010, 2, (RIWR, RR),		    rn_rd),
16225218822Sdim cCE(tbcsth,	e400050, 2, (RIWR, RR),		    rn_rd),
16226218822Sdim cCE(tbcstw,	e400090, 2, (RIWR, RR),		    rn_rd),
16227218822Sdim cCE(textrcb,	e130170, 2, (RR, I7),		    iwmmxt_textrc),
16228218822Sdim cCE(textrch,	e530170, 2, (RR, I7),		    iwmmxt_textrc),
16229218822Sdim cCE(textrcw,	e930170, 2, (RR, I7),		    iwmmxt_textrc),
16230218822Sdim cCE(textrmub,	e100070, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16231218822Sdim cCE(textrmuh,	e500070, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16232218822Sdim cCE(textrmuw,	e900070, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16233218822Sdim cCE(textrmsb,	e100078, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16234218822Sdim cCE(textrmsh,	e500078, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16235218822Sdim cCE(textrmsw,	e900078, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16236218822Sdim cCE(tinsrb,	e600010, 3, (RIWR, RR, I7),	    iwmmxt_tinsr),
16237218822Sdim cCE(tinsrh,	e600050, 3, (RIWR, RR, I7),	    iwmmxt_tinsr),
16238218822Sdim cCE(tinsrw,	e600090, 3, (RIWR, RR, I7),	    iwmmxt_tinsr),
16239218822Sdim cCE(tmcr,	e000110, 2, (RIWC_RIWG, RR),	    rn_rd),
16240218822Sdim cCE(tmcrr,	c400000, 3, (RIWR, RR, RR),	    rm_rd_rn),
16241218822Sdim cCE(tmia,	e200010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16242218822Sdim cCE(tmiaph,	e280010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16243218822Sdim cCE(tmiabb,	e2c0010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16244218822Sdim cCE(tmiabt,	e2d0010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16245218822Sdim cCE(tmiatb,	e2e0010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16246218822Sdim cCE(tmiatt,	e2f0010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16247218822Sdim cCE(tmovmskb,	e100030, 2, (RR, RIWR),		    rd_rn),
16248218822Sdim cCE(tmovmskh,	e500030, 2, (RR, RIWR),		    rd_rn),
16249218822Sdim cCE(tmovmskw,	e900030, 2, (RR, RIWR),		    rd_rn),
16250218822Sdim cCE(tmrc,	e100110, 2, (RR, RIWC_RIWG),	    rd_rn),
16251218822Sdim cCE(tmrrc,	c500000, 3, (RR, RR, RIWR),	    rd_rn_rm),
16252218822Sdim cCE(torcb,	e13f150, 1, (RR),		    iwmmxt_tandorc),
16253218822Sdim cCE(torch,	e53f150, 1, (RR),		    iwmmxt_tandorc),
16254218822Sdim cCE(torcw,	e93f150, 1, (RR),		    iwmmxt_tandorc),
16255218822Sdim cCE(waccb,	e0001c0, 2, (RIWR, RIWR),	    rd_rn),
16256218822Sdim cCE(wacch,	e4001c0, 2, (RIWR, RIWR),	    rd_rn),
16257218822Sdim cCE(waccw,	e8001c0, 2, (RIWR, RIWR),	    rd_rn),
16258218822Sdim cCE(waddbss,	e300180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16259218822Sdim cCE(waddb,	e000180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16260218822Sdim cCE(waddbus,	e100180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16261218822Sdim cCE(waddhss,	e700180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16262218822Sdim cCE(waddh,	e400180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16263218822Sdim cCE(waddhus,	e500180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16264218822Sdim cCE(waddwss,	eb00180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16265218822Sdim cCE(waddw,	e800180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16266218822Sdim cCE(waddwus,	e900180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16267218822Sdim cCE(waligni,	e000020, 4, (RIWR, RIWR, RIWR, I7), iwmmxt_waligni),
16268218822Sdim cCE(walignr0,	e800020, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16269218822Sdim cCE(walignr1,	e900020, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16270218822Sdim cCE(walignr2,	ea00020, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16271218822Sdim cCE(walignr3,	eb00020, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16272218822Sdim cCE(wand,	e200000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16273218822Sdim cCE(wandn,	e300000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16274218822Sdim cCE(wavg2b,	e800000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16275218822Sdim cCE(wavg2br,	e900000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16276218822Sdim cCE(wavg2h,	ec00000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16277218822Sdim cCE(wavg2hr,	ed00000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16278218822Sdim cCE(wcmpeqb,	e000060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16279218822Sdim cCE(wcmpeqh,	e400060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16280218822Sdim cCE(wcmpeqw,	e800060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16281218822Sdim cCE(wcmpgtub,	e100060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16282218822Sdim cCE(wcmpgtuh,	e500060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16283218822Sdim cCE(wcmpgtuw,	e900060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16284218822Sdim cCE(wcmpgtsb,	e300060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16285218822Sdim cCE(wcmpgtsh,	e700060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16286218822Sdim cCE(wcmpgtsw,	eb00060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16287218822Sdim cCE(wldrb,	c100000, 2, (RIWR, ADDR),	    iwmmxt_wldstbh),
16288218822Sdim cCE(wldrh,	c500000, 2, (RIWR, ADDR),	    iwmmxt_wldstbh),
16289218822Sdim cCE(wldrw,	c100100, 2, (RIWR_RIWC, ADDR),	    iwmmxt_wldstw),
16290218822Sdim cCE(wldrd,	c500100, 2, (RIWR, ADDR),	    iwmmxt_wldstd),
16291218822Sdim cCE(wmacs,	e600100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16292218822Sdim cCE(wmacsz,	e700100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16293218822Sdim cCE(wmacu,	e400100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16294218822Sdim cCE(wmacuz,	e500100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16295218822Sdim cCE(wmadds,	ea00100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16296218822Sdim cCE(wmaddu,	e800100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16297218822Sdim cCE(wmaxsb,	e200160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16298218822Sdim cCE(wmaxsh,	e600160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16299218822Sdim cCE(wmaxsw,	ea00160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16300218822Sdim cCE(wmaxub,	e000160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16301218822Sdim cCE(wmaxuh,	e400160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16302218822Sdim cCE(wmaxuw,	e800160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16303218822Sdim cCE(wminsb,	e300160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16304218822Sdim cCE(wminsh,	e700160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16305218822Sdim cCE(wminsw,	eb00160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16306218822Sdim cCE(wminub,	e100160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16307218822Sdim cCE(wminuh,	e500160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16308218822Sdim cCE(wminuw,	e900160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16309218822Sdim cCE(wmov,	e000000, 2, (RIWR, RIWR),	    iwmmxt_wmov),
16310218822Sdim cCE(wmulsm,	e300100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16311218822Sdim cCE(wmulsl,	e200100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16312218822Sdim cCE(wmulum,	e100100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16313218822Sdim cCE(wmulul,	e000100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16314218822Sdim cCE(wor,	e000000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16315218822Sdim cCE(wpackhss,	e700080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16316218822Sdim cCE(wpackhus,	e500080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16317218822Sdim cCE(wpackwss,	eb00080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16318218822Sdim cCE(wpackwus,	e900080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16319218822Sdim cCE(wpackdss,	ef00080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16320218822Sdim cCE(wpackdus,	ed00080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16321218822Sdim cCE(wrorh,	e700040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16322218822Sdim cCE(wrorhg,	e700148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16323218822Sdim cCE(wrorw,	eb00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16324218822Sdim cCE(wrorwg,	eb00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16325218822Sdim cCE(wrord,	ef00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16326218822Sdim cCE(wrordg,	ef00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16327218822Sdim cCE(wsadb,	e000120, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16328218822Sdim cCE(wsadbz,	e100120, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16329218822Sdim cCE(wsadh,	e400120, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16330218822Sdim cCE(wsadhz,	e500120, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16331218822Sdim cCE(wshufh,	e0001e0, 3, (RIWR, RIWR, I255),	    iwmmxt_wshufh),
16332218822Sdim cCE(wsllh,	e500040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16333218822Sdim cCE(wsllhg,	e500148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16334218822Sdim cCE(wsllw,	e900040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16335218822Sdim cCE(wsllwg,	e900148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16336218822Sdim cCE(wslld,	ed00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16337218822Sdim cCE(wslldg,	ed00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16338218822Sdim cCE(wsrah,	e400040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16339218822Sdim cCE(wsrahg,	e400148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16340218822Sdim cCE(wsraw,	e800040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16341218822Sdim cCE(wsrawg,	e800148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16342218822Sdim cCE(wsrad,	ec00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16343218822Sdim cCE(wsradg,	ec00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16344218822Sdim cCE(wsrlh,	e600040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16345218822Sdim cCE(wsrlhg,	e600148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16346218822Sdim cCE(wsrlw,	ea00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16347218822Sdim cCE(wsrlwg,	ea00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16348218822Sdim cCE(wsrld,	ee00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16349218822Sdim cCE(wsrldg,	ee00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16350218822Sdim cCE(wstrb,	c000000, 2, (RIWR, ADDR),	    iwmmxt_wldstbh),
16351218822Sdim cCE(wstrh,	c400000, 2, (RIWR, ADDR),	    iwmmxt_wldstbh),
16352218822Sdim cCE(wstrw,	c000100, 2, (RIWR_RIWC, ADDR),	    iwmmxt_wldstw),
16353218822Sdim cCE(wstrd,	c400100, 2, (RIWR, ADDR),	    iwmmxt_wldstd),
16354218822Sdim cCE(wsubbss,	e3001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16355218822Sdim cCE(wsubb,	e0001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16356218822Sdim cCE(wsubbus,	e1001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16357218822Sdim cCE(wsubhss,	e7001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16358218822Sdim cCE(wsubh,	e4001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16359218822Sdim cCE(wsubhus,	e5001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16360218822Sdim cCE(wsubwss,	eb001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16361218822Sdim cCE(wsubw,	e8001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16362218822Sdim cCE(wsubwus,	e9001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16363218822Sdim cCE(wunpckehub,e0000c0, 2, (RIWR, RIWR),	    rd_rn),
16364218822Sdim cCE(wunpckehuh,e4000c0, 2, (RIWR, RIWR),	    rd_rn),
16365218822Sdim cCE(wunpckehuw,e8000c0, 2, (RIWR, RIWR),	    rd_rn),
16366218822Sdim cCE(wunpckehsb,e2000c0, 2, (RIWR, RIWR),	    rd_rn),
16367218822Sdim cCE(wunpckehsh,e6000c0, 2, (RIWR, RIWR),	    rd_rn),
16368218822Sdim cCE(wunpckehsw,ea000c0, 2, (RIWR, RIWR),	    rd_rn),
16369218822Sdim cCE(wunpckihb, e1000c0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16370218822Sdim cCE(wunpckihh, e5000c0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16371218822Sdim cCE(wunpckihw, e9000c0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16372218822Sdim cCE(wunpckelub,e0000e0, 2, (RIWR, RIWR),	    rd_rn),
16373218822Sdim cCE(wunpckeluh,e4000e0, 2, (RIWR, RIWR),	    rd_rn),
16374218822Sdim cCE(wunpckeluw,e8000e0, 2, (RIWR, RIWR),	    rd_rn),
16375218822Sdim cCE(wunpckelsb,e2000e0, 2, (RIWR, RIWR),	    rd_rn),
16376218822Sdim cCE(wunpckelsh,e6000e0, 2, (RIWR, RIWR),	    rd_rn),
16377218822Sdim cCE(wunpckelsw,ea000e0, 2, (RIWR, RIWR),	    rd_rn),
16378218822Sdim cCE(wunpckilb, e1000e0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16379218822Sdim cCE(wunpckilh, e5000e0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16380218822Sdim cCE(wunpckilw, e9000e0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16381218822Sdim cCE(wxor,	e100000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16382218822Sdim cCE(wzero,	e300000, 1, (RIWR),		    iwmmxt_wzero),
16383218822Sdim
16384218822Sdim#undef ARM_VARIANT
16385218822Sdim#define ARM_VARIANT &arm_cext_iwmmxt2 /* Intel Wireless MMX technology, version 2.  */
16386218822Sdim cCE(torvscb,   e13f190, 1, (RR),		    iwmmxt_tandorc),
16387218822Sdim cCE(torvsch,   e53f190, 1, (RR),		    iwmmxt_tandorc),
16388218822Sdim cCE(torvscw,   e93f190, 1, (RR),		    iwmmxt_tandorc),
16389218822Sdim cCE(wabsb,     e2001c0, 2, (RIWR, RIWR),           rd_rn),
16390218822Sdim cCE(wabsh,     e6001c0, 2, (RIWR, RIWR),           rd_rn),
16391218822Sdim cCE(wabsw,     ea001c0, 2, (RIWR, RIWR),           rd_rn),
16392218822Sdim cCE(wabsdiffb, e1001c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16393218822Sdim cCE(wabsdiffh, e5001c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16394218822Sdim cCE(wabsdiffw, e9001c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16395218822Sdim cCE(waddbhusl, e2001a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16396218822Sdim cCE(waddbhusm, e6001a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16397218822Sdim cCE(waddhc,    e600180, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16398218822Sdim cCE(waddwc,    ea00180, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16399218822Sdim cCE(waddsubhx, ea001a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16400218822Sdim cCE(wavg4,	e400000, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16401218822Sdim cCE(wavg4r,    e500000, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16402218822Sdim cCE(wmaddsn,   ee00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16403218822Sdim cCE(wmaddsx,   eb00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16404218822Sdim cCE(wmaddun,   ec00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16405218822Sdim cCE(wmaddux,   e900100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16406218822Sdim cCE(wmerge,    e000080, 4, (RIWR, RIWR, RIWR, I7), iwmmxt_wmerge),
16407218822Sdim cCE(wmiabb,    e0000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16408218822Sdim cCE(wmiabt,    e1000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16409218822Sdim cCE(wmiatb,    e2000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16410218822Sdim cCE(wmiatt,    e3000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16411218822Sdim cCE(wmiabbn,   e4000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16412218822Sdim cCE(wmiabtn,   e5000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16413218822Sdim cCE(wmiatbn,   e6000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16414218822Sdim cCE(wmiattn,   e7000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16415218822Sdim cCE(wmiawbb,   e800120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16416218822Sdim cCE(wmiawbt,   e900120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16417218822Sdim cCE(wmiawtb,   ea00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16418218822Sdim cCE(wmiawtt,   eb00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16419218822Sdim cCE(wmiawbbn,  ec00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16420218822Sdim cCE(wmiawbtn,  ed00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16421218822Sdim cCE(wmiawtbn,  ee00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16422218822Sdim cCE(wmiawttn,  ef00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16423218822Sdim cCE(wmulsmr,   ef00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16424218822Sdim cCE(wmulumr,   ed00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16425218822Sdim cCE(wmulwumr,  ec000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16426218822Sdim cCE(wmulwsmr,  ee000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16427218822Sdim cCE(wmulwum,   ed000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16428218822Sdim cCE(wmulwsm,   ef000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16429218822Sdim cCE(wmulwl,    eb000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16430218822Sdim cCE(wqmiabb,   e8000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16431218822Sdim cCE(wqmiabt,   e9000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16432218822Sdim cCE(wqmiatb,   ea000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16433218822Sdim cCE(wqmiatt,   eb000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16434218822Sdim cCE(wqmiabbn,  ec000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16435218822Sdim cCE(wqmiabtn,  ed000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16436218822Sdim cCE(wqmiatbn,  ee000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16437218822Sdim cCE(wqmiattn,  ef000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16438218822Sdim cCE(wqmulm,    e100080, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16439218822Sdim cCE(wqmulmr,   e300080, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16440218822Sdim cCE(wqmulwm,   ec000e0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16441218822Sdim cCE(wqmulwmr,  ee000e0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16442218822Sdim cCE(wsubaddhx, ed001c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16443218822Sdim
16444218822Sdim#undef ARM_VARIANT
16445218822Sdim#define ARM_VARIANT &arm_cext_maverick /* Cirrus Maverick instructions.	*/
16446218822Sdim cCE(cfldrs,	c100400, 2, (RMF, ADDRGLDC),	      rd_cpaddr),
16447218822Sdim cCE(cfldrd,	c500400, 2, (RMD, ADDRGLDC),	      rd_cpaddr),
16448218822Sdim cCE(cfldr32,	c100500, 2, (RMFX, ADDRGLDC),	      rd_cpaddr),
16449218822Sdim cCE(cfldr64,	c500500, 2, (RMDX, ADDRGLDC),	      rd_cpaddr),
16450218822Sdim cCE(cfstrs,	c000400, 2, (RMF, ADDRGLDC),	      rd_cpaddr),
16451218822Sdim cCE(cfstrd,	c400400, 2, (RMD, ADDRGLDC),	      rd_cpaddr),
16452218822Sdim cCE(cfstr32,	c000500, 2, (RMFX, ADDRGLDC),	      rd_cpaddr),
16453218822Sdim cCE(cfstr64,	c400500, 2, (RMDX, ADDRGLDC),	      rd_cpaddr),
16454218822Sdim cCE(cfmvsr,	e000450, 2, (RMF, RR),		      rn_rd),
16455218822Sdim cCE(cfmvrs,	e100450, 2, (RR, RMF),		      rd_rn),
16456218822Sdim cCE(cfmvdlr,	e000410, 2, (RMD, RR),		      rn_rd),
16457218822Sdim cCE(cfmvrdl,	e100410, 2, (RR, RMD),		      rd_rn),
16458218822Sdim cCE(cfmvdhr,	e000430, 2, (RMD, RR),		      rn_rd),
16459218822Sdim cCE(cfmvrdh,	e100430, 2, (RR, RMD),		      rd_rn),
16460218822Sdim cCE(cfmv64lr,	e000510, 2, (RMDX, RR),		      rn_rd),
16461218822Sdim cCE(cfmvr64l,	e100510, 2, (RR, RMDX),		      rd_rn),
16462218822Sdim cCE(cfmv64hr,	e000530, 2, (RMDX, RR),		      rn_rd),
16463218822Sdim cCE(cfmvr64h,	e100530, 2, (RR, RMDX),		      rd_rn),
16464218822Sdim cCE(cfmval32,	e200440, 2, (RMAX, RMFX),	      rd_rn),
16465218822Sdim cCE(cfmv32al,	e100440, 2, (RMFX, RMAX),	      rd_rn),
16466218822Sdim cCE(cfmvam32,	e200460, 2, (RMAX, RMFX),	      rd_rn),
16467218822Sdim cCE(cfmv32am,	e100460, 2, (RMFX, RMAX),	      rd_rn),
16468218822Sdim cCE(cfmvah32,	e200480, 2, (RMAX, RMFX),	      rd_rn),
16469218822Sdim cCE(cfmv32ah,	e100480, 2, (RMFX, RMAX),	      rd_rn),
16470218822Sdim cCE(cfmva32,	e2004a0, 2, (RMAX, RMFX),	      rd_rn),
16471218822Sdim cCE(cfmv32a,	e1004a0, 2, (RMFX, RMAX),	      rd_rn),
16472218822Sdim cCE(cfmva64,	e2004c0, 2, (RMAX, RMDX),	      rd_rn),
16473218822Sdim cCE(cfmv64a,	e1004c0, 2, (RMDX, RMAX),	      rd_rn),
16474218822Sdim cCE(cfmvsc32,	e2004e0, 2, (RMDS, RMDX),	      mav_dspsc),
16475218822Sdim cCE(cfmv32sc,	e1004e0, 2, (RMDX, RMDS),	      rd),
16476218822Sdim cCE(cfcpys,	e000400, 2, (RMF, RMF),		      rd_rn),
16477218822Sdim cCE(cfcpyd,	e000420, 2, (RMD, RMD),		      rd_rn),
16478218822Sdim cCE(cfcvtsd,	e000460, 2, (RMD, RMF),		      rd_rn),
16479218822Sdim cCE(cfcvtds,	e000440, 2, (RMF, RMD),		      rd_rn),
16480218822Sdim cCE(cfcvt32s,	e000480, 2, (RMF, RMFX),	      rd_rn),
16481218822Sdim cCE(cfcvt32d,	e0004a0, 2, (RMD, RMFX),	      rd_rn),
16482218822Sdim cCE(cfcvt64s,	e0004c0, 2, (RMF, RMDX),	      rd_rn),
16483218822Sdim cCE(cfcvt64d,	e0004e0, 2, (RMD, RMDX),	      rd_rn),
16484218822Sdim cCE(cfcvts32,	e100580, 2, (RMFX, RMF),	      rd_rn),
16485218822Sdim cCE(cfcvtd32,	e1005a0, 2, (RMFX, RMD),	      rd_rn),
16486218822Sdim cCE(cftruncs32,e1005c0, 2, (RMFX, RMF),	      rd_rn),
16487218822Sdim cCE(cftruncd32,e1005e0, 2, (RMFX, RMD),	      rd_rn),
16488218822Sdim cCE(cfrshl32,	e000550, 3, (RMFX, RMFX, RR),	      mav_triple),
16489218822Sdim cCE(cfrshl64,	e000570, 3, (RMDX, RMDX, RR),	      mav_triple),
16490218822Sdim cCE(cfsh32,	e000500, 3, (RMFX, RMFX, I63s),	      mav_shift),
16491218822Sdim cCE(cfsh64,	e200500, 3, (RMDX, RMDX, I63s),	      mav_shift),
16492218822Sdim cCE(cfcmps,	e100490, 3, (RR, RMF, RMF),	      rd_rn_rm),
16493218822Sdim cCE(cfcmpd,	e1004b0, 3, (RR, RMD, RMD),	      rd_rn_rm),
16494218822Sdim cCE(cfcmp32,	e100590, 3, (RR, RMFX, RMFX),	      rd_rn_rm),
16495218822Sdim cCE(cfcmp64,	e1005b0, 3, (RR, RMDX, RMDX),	      rd_rn_rm),
16496218822Sdim cCE(cfabss,	e300400, 2, (RMF, RMF),		      rd_rn),
16497218822Sdim cCE(cfabsd,	e300420, 2, (RMD, RMD),		      rd_rn),
16498218822Sdim cCE(cfnegs,	e300440, 2, (RMF, RMF),		      rd_rn),
16499218822Sdim cCE(cfnegd,	e300460, 2, (RMD, RMD),		      rd_rn),
16500218822Sdim cCE(cfadds,	e300480, 3, (RMF, RMF, RMF),	      rd_rn_rm),
16501218822Sdim cCE(cfaddd,	e3004a0, 3, (RMD, RMD, RMD),	      rd_rn_rm),
16502218822Sdim cCE(cfsubs,	e3004c0, 3, (RMF, RMF, RMF),	      rd_rn_rm),
16503218822Sdim cCE(cfsubd,	e3004e0, 3, (RMD, RMD, RMD),	      rd_rn_rm),
16504218822Sdim cCE(cfmuls,	e100400, 3, (RMF, RMF, RMF),	      rd_rn_rm),
16505218822Sdim cCE(cfmuld,	e100420, 3, (RMD, RMD, RMD),	      rd_rn_rm),
16506218822Sdim cCE(cfabs32,	e300500, 2, (RMFX, RMFX),	      rd_rn),
16507218822Sdim cCE(cfabs64,	e300520, 2, (RMDX, RMDX),	      rd_rn),
16508218822Sdim cCE(cfneg32,	e300540, 2, (RMFX, RMFX),	      rd_rn),
16509218822Sdim cCE(cfneg64,	e300560, 2, (RMDX, RMDX),	      rd_rn),
16510218822Sdim cCE(cfadd32,	e300580, 3, (RMFX, RMFX, RMFX),	      rd_rn_rm),
16511218822Sdim cCE(cfadd64,	e3005a0, 3, (RMDX, RMDX, RMDX),	      rd_rn_rm),
16512218822Sdim cCE(cfsub32,	e3005c0, 3, (RMFX, RMFX, RMFX),	      rd_rn_rm),
16513218822Sdim cCE(cfsub64,	e3005e0, 3, (RMDX, RMDX, RMDX),	      rd_rn_rm),
16514218822Sdim cCE(cfmul32,	e100500, 3, (RMFX, RMFX, RMFX),	      rd_rn_rm),
16515218822Sdim cCE(cfmul64,	e100520, 3, (RMDX, RMDX, RMDX),	      rd_rn_rm),
16516218822Sdim cCE(cfmac32,	e100540, 3, (RMFX, RMFX, RMFX),	      rd_rn_rm),
16517218822Sdim cCE(cfmsc32,	e100560, 3, (RMFX, RMFX, RMFX),	      rd_rn_rm),
16518218822Sdim cCE(cfmadd32,	e000600, 4, (RMAX, RMFX, RMFX, RMFX), mav_quad),
16519218822Sdim cCE(cfmsub32,	e100600, 4, (RMAX, RMFX, RMFX, RMFX), mav_quad),
16520218822Sdim cCE(cfmadda32, e200600, 4, (RMAX, RMAX, RMFX, RMFX), mav_quad),
16521218822Sdim cCE(cfmsuba32, e300600, 4, (RMAX, RMAX, RMFX, RMFX), mav_quad),
16522218822Sdim};
16523218822Sdim#undef ARM_VARIANT
16524218822Sdim#undef THUMB_VARIANT
16525218822Sdim#undef TCE
16526218822Sdim#undef TCM
16527218822Sdim#undef TUE
16528218822Sdim#undef TUF
16529218822Sdim#undef TCC
16530218822Sdim#undef cCE
16531218822Sdim#undef cCL
16532218822Sdim#undef C3E
16533218822Sdim#undef CE
16534218822Sdim#undef CM
16535218822Sdim#undef UE
16536218822Sdim#undef UF
16537218822Sdim#undef UT
16538218822Sdim#undef NUF
16539218822Sdim#undef nUF
16540218822Sdim#undef NCE
16541218822Sdim#undef nCE
16542218822Sdim#undef OPS0
16543218822Sdim#undef OPS1
16544218822Sdim#undef OPS2
16545218822Sdim#undef OPS3
16546218822Sdim#undef OPS4
16547218822Sdim#undef OPS5
16548218822Sdim#undef OPS6
16549218822Sdim#undef do_0
16550218822Sdim
16551218822Sdim/* MD interface: bits in the object file.  */
16552218822Sdim
16553218822Sdim/* Turn an integer of n bytes (in val) into a stream of bytes appropriate
16554218822Sdim   for use in the a.out file, and stores them in the array pointed to by buf.
16555218822Sdim   This knows about the endian-ness of the target machine and does
16556218822Sdim   THE RIGHT THING, whatever it is.  Possible values for n are 1 (byte)
16557218822Sdim   2 (short) and 4 (long)  Floating numbers are put out as a series of
16558218822Sdim   LITTLENUMS (shorts, here at least).	*/
16559218822Sdim
16560218822Sdimvoid
16561218822Sdimmd_number_to_chars (char * buf, valueT val, int n)
16562218822Sdim{
16563218822Sdim  if (target_big_endian)
16564218822Sdim    number_to_chars_bigendian (buf, val, n);
16565218822Sdim  else
16566218822Sdim    number_to_chars_littleendian (buf, val, n);
1656789857Sobrien}
1656889857Sobrien
16569218822Sdimstatic valueT
16570218822Sdimmd_chars_to_number (char * buf, int n)
1657160484Sobrien{
16572218822Sdim  valueT result = 0;
16573218822Sdim  unsigned char * where = (unsigned char *) buf;
1657460484Sobrien
16575218822Sdim  if (target_big_endian)
16576130561Sobrien    {
16577218822Sdim      while (n--)
16578218822Sdim	{
16579218822Sdim	  result <<= 8;
16580218822Sdim	  result |= (*where++ & 255);
16581218822Sdim	}
16582130561Sobrien    }
16583218822Sdim  else
16584218822Sdim    {
16585218822Sdim      while (n--)
16586218822Sdim	{
16587218822Sdim	  result <<= 8;
16588218822Sdim	  result |= (where[n] & 255);
16589218822Sdim	}
16590218822Sdim    }
16591218822Sdim
16592218822Sdim  return result;
1659360484Sobrien}
1659460484Sobrien
16595218822Sdim/* MD interface: Sections.  */
1659689857Sobrien
16597218822Sdim/* Estimate the size of a frag before relaxing.  Assume everything fits in
16598218822Sdim   2 bytes.  */
1659989857Sobrien
16600218822Sdimint
16601218822Sdimmd_estimate_size_before_relax (fragS * fragp,
16602218822Sdim			       segT    segtype ATTRIBUTE_UNUSED)
1660389857Sobrien{
16604218822Sdim  fragp->fr_var = 2;
16605218822Sdim  return 2;
16606218822Sdim}
1660789857Sobrien
16608218822Sdim/* Convert a machine dependent frag.  */
1660989857Sobrien
16610218822Sdimvoid
16611218822Sdimmd_convert_frag (bfd *abfd, segT asec ATTRIBUTE_UNUSED, fragS *fragp)
16612218822Sdim{
16613218822Sdim  unsigned long insn;
16614218822Sdim  unsigned long old_op;
16615218822Sdim  char *buf;
16616218822Sdim  expressionS exp;
16617218822Sdim  fixS *fixp;
16618218822Sdim  int reloc_type;
16619218822Sdim  int pc_rel;
16620218822Sdim  int opcode;
1662189857Sobrien
16622218822Sdim  buf = fragp->fr_literal + fragp->fr_fix;
16623218822Sdim
16624218822Sdim  old_op = bfd_get_16(abfd, buf);
16625218822Sdim  if (fragp->fr_symbol) {
16626218822Sdim      exp.X_op = O_symbol;
16627218822Sdim      exp.X_add_symbol = fragp->fr_symbol;
16628218822Sdim  } else {
16629218822Sdim      exp.X_op = O_constant;
16630218822Sdim  }
16631218822Sdim  exp.X_add_number = fragp->fr_offset;
16632218822Sdim  opcode = fragp->fr_subtype;
16633218822Sdim  switch (opcode)
1663489857Sobrien    {
16635218822Sdim    case T_MNEM_ldr_pc:
16636218822Sdim    case T_MNEM_ldr_pc2:
16637218822Sdim    case T_MNEM_ldr_sp:
16638218822Sdim    case T_MNEM_str_sp:
16639218822Sdim    case T_MNEM_ldr:
16640218822Sdim    case T_MNEM_ldrb:
16641218822Sdim    case T_MNEM_ldrh:
16642218822Sdim    case T_MNEM_str:
16643218822Sdim    case T_MNEM_strb:
16644218822Sdim    case T_MNEM_strh:
16645218822Sdim      if (fragp->fr_var == 4)
1664689857Sobrien	{
16647218822Sdim	  insn = THUMB_OP32(opcode);
16648218822Sdim	  if ((old_op >> 12) == 4 || (old_op >> 12) == 9)
1664989857Sobrien	    {
16650218822Sdim	      insn |= (old_op & 0x700) << 4;
1665189857Sobrien	    }
16652218822Sdim	  else
1665389857Sobrien	    {
16654218822Sdim	      insn |= (old_op & 7) << 12;
16655218822Sdim	      insn |= (old_op & 0x38) << 13;
1665689857Sobrien	    }
16657218822Sdim	  insn |= 0x00000c00;
16658218822Sdim	  put_thumb32_insn (buf, insn);
16659218822Sdim	  reloc_type = BFD_RELOC_ARM_T32_OFFSET_IMM;
16660218822Sdim	}
16661218822Sdim      else
16662218822Sdim	{
16663218822Sdim	  reloc_type = BFD_RELOC_ARM_THUMB_OFFSET;
16664218822Sdim	}
16665218822Sdim      pc_rel = (opcode == T_MNEM_ldr_pc2);
16666218822Sdim      break;
16667218822Sdim    case T_MNEM_adr:
16668218822Sdim      if (fragp->fr_var == 4)
16669218822Sdim	{
16670218822Sdim	  insn = THUMB_OP32 (opcode);
16671218822Sdim	  insn |= (old_op & 0xf0) << 4;
16672218822Sdim	  put_thumb32_insn (buf, insn);
16673218822Sdim	  reloc_type = BFD_RELOC_ARM_T32_ADD_PC12;
16674218822Sdim	}
16675218822Sdim      else
16676218822Sdim	{
16677218822Sdim	  reloc_type = BFD_RELOC_ARM_THUMB_ADD;
16678218822Sdim	  exp.X_add_number -= 4;
16679218822Sdim	}
16680218822Sdim      pc_rel = 1;
16681218822Sdim      break;
16682218822Sdim    case T_MNEM_mov:
16683218822Sdim    case T_MNEM_movs:
16684218822Sdim    case T_MNEM_cmp:
16685218822Sdim    case T_MNEM_cmn:
16686218822Sdim      if (fragp->fr_var == 4)
16687218822Sdim	{
16688218822Sdim	  int r0off = (opcode == T_MNEM_mov
16689218822Sdim		       || opcode == T_MNEM_movs) ? 0 : 8;
16690218822Sdim	  insn = THUMB_OP32 (opcode);
16691218822Sdim	  insn = (insn & 0xe1ffffff) | 0x10000000;
16692218822Sdim	  insn |= (old_op & 0x700) << r0off;
16693218822Sdim	  put_thumb32_insn (buf, insn);
16694218822Sdim	  reloc_type = BFD_RELOC_ARM_T32_IMMEDIATE;
16695218822Sdim	}
16696218822Sdim      else
16697218822Sdim	{
16698218822Sdim	  reloc_type = BFD_RELOC_ARM_THUMB_IMM;
16699218822Sdim	}
16700218822Sdim      pc_rel = 0;
16701218822Sdim      break;
16702218822Sdim    case T_MNEM_b:
16703218822Sdim      if (fragp->fr_var == 4)
16704218822Sdim	{
16705218822Sdim	  insn = THUMB_OP32(opcode);
16706218822Sdim	  put_thumb32_insn (buf, insn);
16707218822Sdim	  reloc_type = BFD_RELOC_THUMB_PCREL_BRANCH25;
16708218822Sdim	}
16709218822Sdim      else
16710218822Sdim	reloc_type = BFD_RELOC_THUMB_PCREL_BRANCH12;
16711218822Sdim      pc_rel = 1;
16712218822Sdim      break;
16713218822Sdim    case T_MNEM_bcond:
16714218822Sdim      if (fragp->fr_var == 4)
16715218822Sdim	{
16716218822Sdim	  insn = THUMB_OP32(opcode);
16717218822Sdim	  insn |= (old_op & 0xf00) << 14;
16718218822Sdim	  put_thumb32_insn (buf, insn);
16719218822Sdim	  reloc_type = BFD_RELOC_THUMB_PCREL_BRANCH20;
16720218822Sdim	}
16721218822Sdim      else
16722218822Sdim	reloc_type = BFD_RELOC_THUMB_PCREL_BRANCH9;
16723218822Sdim      pc_rel = 1;
16724218822Sdim      break;
16725218822Sdim    case T_MNEM_add_sp:
16726218822Sdim    case T_MNEM_add_pc:
16727218822Sdim    case T_MNEM_inc_sp:
16728218822Sdim    case T_MNEM_dec_sp:
16729218822Sdim      if (fragp->fr_var == 4)
16730218822Sdim	{
16731218822Sdim	  /* ??? Choose between add and addw.  */
16732218822Sdim	  insn = THUMB_OP32 (opcode);
16733218822Sdim	  insn |= (old_op & 0xf0) << 4;
16734218822Sdim	  put_thumb32_insn (buf, insn);
16735218822Sdim	  if (opcode == T_MNEM_add_pc)
16736218822Sdim	    reloc_type = BFD_RELOC_ARM_T32_IMM12;
1673789857Sobrien	  else
16738218822Sdim	    reloc_type = BFD_RELOC_ARM_T32_ADD_IMM;
16739218822Sdim	}
16740218822Sdim      else
16741218822Sdim	reloc_type = BFD_RELOC_ARM_THUMB_ADD;
16742218822Sdim      pc_rel = 0;
16743218822Sdim      break;
1674489857Sobrien
16745218822Sdim    case T_MNEM_addi:
16746218822Sdim    case T_MNEM_addis:
16747218822Sdim    case T_MNEM_subi:
16748218822Sdim    case T_MNEM_subis:
16749218822Sdim      if (fragp->fr_var == 4)
16750218822Sdim	{
16751218822Sdim	  insn = THUMB_OP32 (opcode);
16752218822Sdim	  insn |= (old_op & 0xf0) << 4;
16753218822Sdim	  insn |= (old_op & 0xf) << 16;
16754218822Sdim	  put_thumb32_insn (buf, insn);
16755218822Sdim	  if (insn & (1 << 20))
16756218822Sdim	    reloc_type = BFD_RELOC_ARM_T32_ADD_IMM;
16757218822Sdim	  else
16758218822Sdim	    reloc_type = BFD_RELOC_ARM_T32_IMMEDIATE;
1675989857Sobrien	}
1676089857Sobrien      else
16761218822Sdim	reloc_type = BFD_RELOC_ARM_THUMB_ADD;
16762218822Sdim      pc_rel = 0;
16763218822Sdim      break;
16764218822Sdim    default:
16765218822Sdim      abort();
1676689857Sobrien    }
16767218822Sdim  fixp = fix_new_exp (fragp, fragp->fr_fix, fragp->fr_var, &exp, pc_rel,
16768218822Sdim		      reloc_type);
16769218822Sdim  fixp->fx_file = fragp->fr_file;
16770218822Sdim  fixp->fx_line = fragp->fr_line;
16771218822Sdim  fragp->fr_fix += fragp->fr_var;
1677289857Sobrien}
16773104834Sobrien
16774218822Sdim/* Return the size of a relaxable immediate operand instruction.
16775218822Sdim   SHIFT and SIZE specify the form of the allowable immediate.  */
16776218822Sdimstatic int
16777218822Sdimrelax_immediate (fragS *fragp, int size, int shift)
1677860484Sobrien{
16779218822Sdim  offsetT offset;
16780218822Sdim  offsetT mask;
16781218822Sdim  offsetT low;
1678260484Sobrien
16783218822Sdim  /* ??? Should be able to do better than this.  */
16784218822Sdim  if (fragp->fr_symbol)
16785218822Sdim    return 4;
16786218822Sdim
16787218822Sdim  low = (1 << shift) - 1;
16788218822Sdim  mask = (1 << (shift + size)) - (1 << shift);
16789218822Sdim  offset = fragp->fr_offset;
16790218822Sdim  /* Force misaligned offsets to 32-bit variant.  */
16791218822Sdim  if (offset & low)
16792218822Sdim    return 4;
16793218822Sdim  if (offset & ~mask)
16794218822Sdim    return 4;
16795218822Sdim  return 2;
1679660484Sobrien}
1679760484Sobrien
16798218822Sdim/* Get the address of a symbol during relaxation.  */
16799218822Sdimstatic addressT
16800218822Sdimrelaxed_symbol_addr(fragS *fragp, long stretch)
1680189857Sobrien{
16802218822Sdim  fragS *sym_frag;
16803218822Sdim  addressT addr;
16804218822Sdim  symbolS *sym;
1680589857Sobrien
16806218822Sdim  sym = fragp->fr_symbol;
16807218822Sdim  sym_frag = symbol_get_frag (sym);
16808218822Sdim  know (S_GET_SEGMENT (sym) != absolute_section
16809218822Sdim	|| sym_frag == &zero_address_frag);
16810218822Sdim  addr = S_GET_VALUE (sym) + fragp->fr_offset;
1681189857Sobrien
16812218822Sdim  /* If frag has yet to be reached on this pass, assume it will
16813218822Sdim     move by STRETCH just as we did.  If this is not so, it will
16814218822Sdim     be because some frag between grows, and that will force
16815218822Sdim     another pass.  */
1681689857Sobrien
16817218822Sdim  if (stretch != 0
16818218822Sdim      && sym_frag->relax_marker != fragp->relax_marker)
16819218822Sdim    addr += stretch;
1682089857Sobrien
16821218822Sdim  return addr;
16822218822Sdim}
1682389857Sobrien
16824218822Sdim/* Return the size of a relaxable adr pseudo-instruction or PC-relative
16825218822Sdim   load.  */
16826218822Sdimstatic int
16827218822Sdimrelax_adr (fragS *fragp, asection *sec, long stretch)
16828218822Sdim{
16829218822Sdim  addressT addr;
16830218822Sdim  offsetT val;
1683189857Sobrien
16832218822Sdim  /* Assume worst case for symbols not known to be in the same section.  */
16833218822Sdim  if (!S_IS_DEFINED(fragp->fr_symbol)
16834218822Sdim      || sec != S_GET_SEGMENT (fragp->fr_symbol))
16835218822Sdim    return 4;
16836218822Sdim
16837218822Sdim  val = relaxed_symbol_addr(fragp, stretch);
16838218822Sdim  addr = fragp->fr_address + fragp->fr_fix;
16839218822Sdim  addr = (addr + 4) & ~3;
16840218822Sdim  /* Force misaligned targets to 32-bit variant.  */
16841218822Sdim  if (val & 3)
16842218822Sdim    return 4;
16843218822Sdim  val -= addr;
16844218822Sdim  if (val < 0 || val > 1020)
16845218822Sdim    return 4;
16846218822Sdim  return 2;
1684789857Sobrien}
1684889857Sobrien
16849218822Sdim/* Return the size of a relaxable add/sub immediate instruction.  */
16850218822Sdimstatic int
16851218822Sdimrelax_addsub (fragS *fragp, asection *sec)
16852130561Sobrien{
16853218822Sdim  char *buf;
16854218822Sdim  int op;
16855130561Sobrien
16856218822Sdim  buf = fragp->fr_literal + fragp->fr_fix;
16857218822Sdim  op = bfd_get_16(sec->owner, buf);
16858218822Sdim  if ((op & 0xf) == ((op >> 4) & 0xf))
16859218822Sdim    return relax_immediate (fragp, 8, 0);
16860218822Sdim  else
16861218822Sdim    return relax_immediate (fragp, 3, 0);
16862218822Sdim}
16863130561Sobrien
16864130561Sobrien
16865218822Sdim/* Return the size of a relaxable branch instruction.  BITS is the
16866218822Sdim   size of the offset field in the narrow instruction.  */
16867130561Sobrien
16868218822Sdimstatic int
16869218822Sdimrelax_branch (fragS *fragp, asection *sec, int bits, long stretch)
16870218822Sdim{
16871218822Sdim  addressT addr;
16872218822Sdim  offsetT val;
16873218822Sdim  offsetT limit;
16874130561Sobrien
16875218822Sdim  /* Assume worst case for symbols not known to be in the same section.  */
16876218822Sdim  if (!S_IS_DEFINED(fragp->fr_symbol)
16877218822Sdim      || sec != S_GET_SEGMENT (fragp->fr_symbol))
16878218822Sdim    return 4;
16879130561Sobrien
16880218822Sdim  val = relaxed_symbol_addr(fragp, stretch);
16881218822Sdim  addr = fragp->fr_address + fragp->fr_fix + 4;
16882218822Sdim  val -= addr;
16883130561Sobrien
16884218822Sdim  /* Offset is a signed value *2 */
16885218822Sdim  limit = 1 << bits;
16886218822Sdim  if (val >= limit || val < -limit)
16887218822Sdim    return 4;
16888218822Sdim  return 2;
16889130561Sobrien}
16890130561Sobrien
16891218822Sdim
16892218822Sdim/* Relax a machine dependent frag.  This returns the amount by which
16893218822Sdim   the current size of the frag should change.  */
16894218822Sdim
16895218822Sdimint
16896218822Sdimarm_relax_frag (asection *sec, fragS *fragp, long stretch)
1689760484Sobrien{
16898218822Sdim  int oldsize;
16899218822Sdim  int newsize;
1690077298Sobrien
16901218822Sdim  oldsize = fragp->fr_var;
16902218822Sdim  switch (fragp->fr_subtype)
16903218822Sdim    {
16904218822Sdim    case T_MNEM_ldr_pc2:
16905218822Sdim      newsize = relax_adr(fragp, sec, stretch);
16906218822Sdim      break;
16907218822Sdim    case T_MNEM_ldr_pc:
16908218822Sdim    case T_MNEM_ldr_sp:
16909218822Sdim    case T_MNEM_str_sp:
16910218822Sdim      newsize = relax_immediate(fragp, 8, 2);
16911218822Sdim      break;
16912218822Sdim    case T_MNEM_ldr:
16913218822Sdim    case T_MNEM_str:
16914218822Sdim      newsize = relax_immediate(fragp, 5, 2);
16915218822Sdim      break;
16916218822Sdim    case T_MNEM_ldrh:
16917218822Sdim    case T_MNEM_strh:
16918218822Sdim      newsize = relax_immediate(fragp, 5, 1);
16919218822Sdim      break;
16920218822Sdim    case T_MNEM_ldrb:
16921218822Sdim    case T_MNEM_strb:
16922218822Sdim      newsize = relax_immediate(fragp, 5, 0);
16923218822Sdim      break;
16924218822Sdim    case T_MNEM_adr:
16925218822Sdim      newsize = relax_adr(fragp, sec, stretch);
16926218822Sdim      break;
16927218822Sdim    case T_MNEM_mov:
16928218822Sdim    case T_MNEM_movs:
16929218822Sdim    case T_MNEM_cmp:
16930218822Sdim    case T_MNEM_cmn:
16931218822Sdim      newsize = relax_immediate(fragp, 8, 0);
16932218822Sdim      break;
16933218822Sdim    case T_MNEM_b:
16934218822Sdim      newsize = relax_branch(fragp, sec, 11, stretch);
16935218822Sdim      break;
16936218822Sdim    case T_MNEM_bcond:
16937218822Sdim      newsize = relax_branch(fragp, sec, 8, stretch);
16938218822Sdim      break;
16939218822Sdim    case T_MNEM_add_sp:
16940218822Sdim    case T_MNEM_add_pc:
16941218822Sdim      newsize = relax_immediate (fragp, 8, 2);
16942218822Sdim      break;
16943218822Sdim    case T_MNEM_inc_sp:
16944218822Sdim    case T_MNEM_dec_sp:
16945218822Sdim      newsize = relax_immediate (fragp, 7, 2);
16946218822Sdim      break;
16947218822Sdim    case T_MNEM_addi:
16948218822Sdim    case T_MNEM_addis:
16949218822Sdim    case T_MNEM_subi:
16950218822Sdim    case T_MNEM_subis:
16951218822Sdim      newsize = relax_addsub (fragp, sec);
16952218822Sdim      break;
16953218822Sdim    default:
16954218822Sdim      abort();
16955218822Sdim    }
1695677298Sobrien
16957218822Sdim  fragp->fr_var = newsize;
16958218822Sdim  /* Freeze wide instructions that are at or before the same location as
16959218822Sdim     in the previous pass.  This avoids infinite loops.
16960218822Sdim     Don't freeze them unconditionally because targets may be artificialy
16961218822Sdim     misaligned by the expansion of preceeding frags.  */
16962218822Sdim  if (stretch <= 0 && newsize > 2)
16963218822Sdim    {
16964218822Sdim      md_convert_frag (sec->owner, sec, fragp);
16965218822Sdim      frag_wane(fragp);
16966218822Sdim    }
1696760484Sobrien
16968218822Sdim  return newsize - oldsize;
16969218822Sdim}
1697060484Sobrien
16971218822Sdim/* Round up a section size to the appropriate boundary.	 */
1697260484Sobrien
16973218822SdimvalueT
16974218822Sdimmd_section_align (segT	 segment ATTRIBUTE_UNUSED,
16975218822Sdim		  valueT size)
16976218822Sdim{
16977218822Sdim#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
16978218822Sdim  if (OUTPUT_FLAVOR == bfd_target_aout_flavour)
1697989857Sobrien    {
16980218822Sdim      /* For a.out, force the section size to be aligned.  If we don't do
16981218822Sdim	 this, BFD will align it for us, but it will not write out the
16982218822Sdim	 final bytes of the section.  This may be a bug in BFD, but it is
16983218822Sdim	 easier to fix it here since that is how the other a.out targets
16984218822Sdim	 work.  */
16985218822Sdim      int align;
1698689857Sobrien
16987218822Sdim      align = bfd_get_section_alignment (stdoutput, segment);
16988218822Sdim      size = ((size + (1 << align) - 1) & ((valueT) -1 << align));
1698989857Sobrien    }
16990218822Sdim#endif
1699189857Sobrien
16992218822Sdim  return size;
16993218822Sdim}
16994218822Sdim
16995218822Sdim/* This is called from HANDLE_ALIGN in write.c.	 Fill in the contents
16996218822Sdim   of an rs_align_code fragment.  */
16997218822Sdim
16998218822Sdimvoid
16999218822Sdimarm_handle_align (fragS * fragP)
17000218822Sdim{
17001218822Sdim  static char const arm_noop[4] = { 0x00, 0x00, 0xa0, 0xe1 };
17002218822Sdim  static char const thumb_noop[2] = { 0xc0, 0x46 };
17003218822Sdim  static char const arm_bigend_noop[4] = { 0xe1, 0xa0, 0x00, 0x00 };
17004218822Sdim  static char const thumb_bigend_noop[2] = { 0x46, 0xc0 };
17005218822Sdim
17006218822Sdim  int bytes, fix, noop_size;
17007218822Sdim  char * p;
17008218822Sdim  const char * noop;
17009218822Sdim
17010218822Sdim  if (fragP->fr_type != rs_align_code)
17011218822Sdim    return;
17012218822Sdim
17013218822Sdim  bytes = fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix;
17014218822Sdim  p = fragP->fr_literal + fragP->fr_fix;
17015218822Sdim  fix = 0;
17016218822Sdim
17017218822Sdim  if (bytes > MAX_MEM_FOR_RS_ALIGN_CODE)
17018218822Sdim    bytes &= MAX_MEM_FOR_RS_ALIGN_CODE;
17019218822Sdim
17020218822Sdim  if (fragP->tc_frag_data)
1702189857Sobrien    {
17022218822Sdim      if (target_big_endian)
17023218822Sdim	noop = thumb_bigend_noop;
17024218822Sdim      else
17025218822Sdim	noop = thumb_noop;
17026218822Sdim      noop_size = sizeof (thumb_noop);
1702789857Sobrien    }
17028218822Sdim  else
1702989857Sobrien    {
17030218822Sdim      if (target_big_endian)
17031218822Sdim	noop = arm_bigend_noop;
1703289857Sobrien      else
17033218822Sdim	noop = arm_noop;
17034218822Sdim      noop_size = sizeof (arm_noop);
1703589857Sobrien    }
1703689857Sobrien
17037218822Sdim  if (bytes & (noop_size - 1))
1703889857Sobrien    {
17039218822Sdim      fix = bytes & (noop_size - 1);
17040218822Sdim      memset (p, 0, fix);
17041218822Sdim      p += fix;
17042218822Sdim      bytes -= fix;
1704389857Sobrien    }
1704489857Sobrien
17045218822Sdim  while (bytes >= noop_size)
17046218822Sdim    {
17047218822Sdim      memcpy (p, noop, noop_size);
17048218822Sdim      p += noop_size;
17049218822Sdim      bytes -= noop_size;
17050218822Sdim      fix += noop_size;
17051218822Sdim    }
1705289857Sobrien
17053218822Sdim  fragP->fr_fix += fix;
17054218822Sdim  fragP->fr_var = noop_size;
17055218822Sdim}
1705689857Sobrien
17057218822Sdim/* Called from md_do_align.  Used to create an alignment
17058218822Sdim   frag in a code section.  */
1705977298Sobrien
17060218822Sdimvoid
17061218822Sdimarm_frag_align_code (int n, int max)
17062218822Sdim{
17063218822Sdim  char * p;
17064130561Sobrien
17065218822Sdim  /* We assume that there will never be a requirement
17066218822Sdim     to support alignments greater than 32 bytes.  */
17067218822Sdim  if (max > MAX_MEM_FOR_RS_ALIGN_CODE)
17068218822Sdim    as_fatal (_("alignments greater than 32 bytes not supported in .text sections."));
1706960484Sobrien
17070218822Sdim  p = frag_var (rs_align_code,
17071218822Sdim		MAX_MEM_FOR_RS_ALIGN_CODE,
17072218822Sdim		1,
17073218822Sdim		(relax_substateT) max,
17074218822Sdim		(symbolS *) NULL,
17075218822Sdim		(offsetT) n,
17076218822Sdim		(char *) NULL);
17077218822Sdim  *p = 0;
17078218822Sdim}
1707989857Sobrien
17080218822Sdim/* Perform target specific initialisation of a frag.  */
1708177298Sobrien
17082218822Sdimvoid
17083218822Sdimarm_init_frag (fragS * fragP)
17084218822Sdim{
17085218822Sdim  /* Record whether this frag is in an ARM or a THUMB area.  */
17086218822Sdim  fragP->tc_frag_data = thumb_mode;
17087218822Sdim}
1708877298Sobrien
17089218822Sdim#ifdef OBJ_ELF
17090218822Sdim/* When we change sections we need to issue a new mapping symbol.  */
1709177298Sobrien
17092218822Sdimvoid
17093218822Sdimarm_elf_change_section (void)
17094218822Sdim{
17095218822Sdim  flagword flags;
17096218822Sdim  segment_info_type *seginfo;
1709777298Sobrien
17098218822Sdim  /* Link an unlinked unwind index table section to the .text section.	*/
17099218822Sdim  if (elf_section_type (now_seg) == SHT_ARM_EXIDX
17100218822Sdim      && elf_linked_to_section (now_seg) == NULL)
17101218822Sdim    elf_linked_to_section (now_seg) = text_section;
1710277298Sobrien
17103218822Sdim  if (!SEG_NORMAL (now_seg))
17104218822Sdim    return;
1710577298Sobrien
17106218822Sdim  flags = bfd_get_section_flags (stdoutput, now_seg);
1710789857Sobrien
17108218822Sdim  /* We can ignore sections that only contain debug info.  */
17109218822Sdim  if ((flags & SEC_ALLOC) == 0)
17110218822Sdim    return;
1711177298Sobrien
17112218822Sdim  seginfo = seg_info (now_seg);
17113218822Sdim  mapstate = seginfo->tc_segment_info_data.mapstate;
17114218822Sdim  marked_pr_dependency = seginfo->tc_segment_info_data.marked_pr_dependency;
17115218822Sdim}
17116218822Sdim
17117218822Sdimint
17118218822Sdimarm_elf_section_type (const char * str, size_t len)
17119218822Sdim{
17120218822Sdim  if (len == 5 && strncmp (str, "exidx", 5) == 0)
17121218822Sdim    return SHT_ARM_EXIDX;
17122218822Sdim
17123218822Sdim  return -1;
17124218822Sdim}
17125218822Sdim
17126218822Sdim/* Code to deal with unwinding tables.	*/
17127218822Sdim
17128218822Sdimstatic void add_unwind_adjustsp (offsetT);
17129218822Sdim
17130218822Sdim/* Cenerate and deferred unwind frame offset.  */
17131218822Sdim
17132218822Sdimstatic void
17133218822Sdimflush_pending_unwind (void)
17134218822Sdim{
17135218822Sdim  offsetT offset;
17136218822Sdim
17137218822Sdim  offset = unwind.pending_offset;
17138218822Sdim  unwind.pending_offset = 0;
17139218822Sdim  if (offset != 0)
17140218822Sdim    add_unwind_adjustsp (offset);
17141218822Sdim}
17142218822Sdim
17143218822Sdim/* Add an opcode to this list for this function.  Two-byte opcodes should
17144218822Sdim   be passed as op[0] << 8 | op[1].  The list of opcodes is built in reverse
17145218822Sdim   order.  */
17146218822Sdim
17147218822Sdimstatic void
17148218822Sdimadd_unwind_opcode (valueT op, int length)
17149218822Sdim{
17150218822Sdim  /* Add any deferred stack adjustment.	 */
17151218822Sdim  if (unwind.pending_offset)
17152218822Sdim    flush_pending_unwind ();
17153218822Sdim
17154218822Sdim  unwind.sp_restored = 0;
17155218822Sdim
17156218822Sdim  if (unwind.opcode_count + length > unwind.opcode_alloc)
1715760484Sobrien    {
17158218822Sdim      unwind.opcode_alloc += ARM_OPCODE_CHUNK_SIZE;
17159218822Sdim      if (unwind.opcodes)
17160218822Sdim	unwind.opcodes = xrealloc (unwind.opcodes,
17161218822Sdim				   unwind.opcode_alloc);
1716278828Sobrien      else
17163218822Sdim	unwind.opcodes = xmalloc (unwind.opcode_alloc);
1716460484Sobrien    }
17165218822Sdim  while (length > 0)
1716678828Sobrien    {
17167218822Sdim      length--;
17168218822Sdim      unwind.opcodes[unwind.opcode_count] = op & 0xff;
17169218822Sdim      op >>= 8;
17170218822Sdim      unwind.opcode_count++;
1717178828Sobrien    }
17172218822Sdim}
1717377298Sobrien
17174218822Sdim/* Add unwind opcodes to adjust the stack pointer.  */
17175130561Sobrien
17176218822Sdimstatic void
17177218822Sdimadd_unwind_adjustsp (offsetT offset)
17178218822Sdim{
17179218822Sdim  valueT op;
17180130561Sobrien
17181218822Sdim  if (offset > 0x200)
17182218822Sdim    {
17183218822Sdim      /* We need at most 5 bytes to hold a 32-bit value in a uleb128.  */
17184218822Sdim      char bytes[5];
17185218822Sdim      int n;
17186218822Sdim      valueT o;
17187130561Sobrien
17188218822Sdim      /* Long form: 0xb2, uleb128.  */
17189218822Sdim      /* This might not fit in a word so add the individual bytes,
17190218822Sdim	 remembering the list is built in reverse order.  */
17191218822Sdim      o = (valueT) ((offset - 0x204) >> 2);
17192218822Sdim      if (o == 0)
17193218822Sdim	add_unwind_opcode (0, 1);
17194130561Sobrien
17195218822Sdim      /* Calculate the uleb128 encoding of the offset.	*/
17196218822Sdim      n = 0;
17197218822Sdim      while (o)
17198218822Sdim	{
17199218822Sdim	  bytes[n] = o & 0x7f;
17200218822Sdim	  o >>= 7;
17201218822Sdim	  if (o)
17202218822Sdim	    bytes[n] |= 0x80;
17203218822Sdim	  n++;
17204218822Sdim	}
17205218822Sdim      /* Add the insn.	*/
17206218822Sdim      for (; n; n--)
17207218822Sdim	add_unwind_opcode (bytes[n - 1], 1);
17208218822Sdim      add_unwind_opcode (0xb2, 1);
17209218822Sdim    }
17210218822Sdim  else if (offset > 0x100)
17211218822Sdim    {
17212218822Sdim      /* Two short opcodes.  */
17213218822Sdim      add_unwind_opcode (0x3f, 1);
17214218822Sdim      op = (offset - 0x104) >> 2;
17215218822Sdim      add_unwind_opcode (op, 1);
17216218822Sdim    }
17217218822Sdim  else if (offset > 0)
17218218822Sdim    {
17219218822Sdim      /* Short opcode.	*/
17220218822Sdim      op = (offset - 4) >> 2;
17221218822Sdim      add_unwind_opcode (op, 1);
17222218822Sdim    }
17223218822Sdim  else if (offset < 0)
17224218822Sdim    {
17225218822Sdim      offset = -offset;
17226218822Sdim      while (offset > 0x100)
17227218822Sdim	{
17228218822Sdim	  add_unwind_opcode (0x7f, 1);
17229218822Sdim	  offset -= 0x100;
17230218822Sdim	}
17231218822Sdim      op = ((offset - 4) >> 2) | 0x40;
17232218822Sdim      add_unwind_opcode (op, 1);
17233218822Sdim    }
17234218822Sdim}
17235130561Sobrien
17236218822Sdim/* Finish the list of unwind opcodes for this function.	 */
17237218822Sdimstatic void
17238218822Sdimfinish_unwind_opcodes (void)
17239218822Sdim{
17240218822Sdim  valueT op;
17241130561Sobrien
17242218822Sdim  if (unwind.fp_used)
17243218822Sdim    {
17244218822Sdim      /* Adjust sp as necessary.  */
17245218822Sdim      unwind.pending_offset += unwind.fp_offset - unwind.frame_size;
17246218822Sdim      flush_pending_unwind ();
17247130561Sobrien
17248218822Sdim      /* After restoring sp from the frame pointer.  */
17249218822Sdim      op = 0x90 | unwind.fp_reg;
17250218822Sdim      add_unwind_opcode (op, 1);
17251218822Sdim    }
17252218822Sdim  else
17253218822Sdim    flush_pending_unwind ();
1725460484Sobrien}
1725560484Sobrien
1725677298Sobrien
17257218822Sdim/* Start an exception table entry.  If idx is nonzero this is an index table
17258218822Sdim   entry.  */
17259218822Sdim
17260218822Sdimstatic void
17261218822Sdimstart_unwind_section (const segT text_seg, int idx)
1726260484Sobrien{
17263218822Sdim  const char * text_name;
17264218822Sdim  const char * prefix;
17265218822Sdim  const char * prefix_once;
17266218822Sdim  const char * group_name;
17267218822Sdim  size_t prefix_len;
17268218822Sdim  size_t text_len;
17269218822Sdim  char * sec_name;
17270218822Sdim  size_t sec_name_len;
17271218822Sdim  int type;
17272218822Sdim  int flags;
17273218822Sdim  int linkonce;
17274218822Sdim
17275218822Sdim  if (idx)
17276218822Sdim    {
17277218822Sdim      prefix = ELF_STRING_ARM_unwind;
17278218822Sdim      prefix_once = ELF_STRING_ARM_unwind_once;
17279218822Sdim      type = SHT_ARM_EXIDX;
17280218822Sdim    }
1728160484Sobrien  else
17282218822Sdim    {
17283218822Sdim      prefix = ELF_STRING_ARM_unwind_info;
17284218822Sdim      prefix_once = ELF_STRING_ARM_unwind_info_once;
17285218822Sdim      type = SHT_PROGBITS;
17286218822Sdim    }
17287218822Sdim
17288218822Sdim  text_name = segment_name (text_seg);
17289218822Sdim  if (streq (text_name, ".text"))
17290218822Sdim    text_name = "";
17291218822Sdim
17292218822Sdim  if (strncmp (text_name, ".gnu.linkonce.t.",
17293218822Sdim	       strlen (".gnu.linkonce.t.")) == 0)
17294218822Sdim    {
17295218822Sdim      prefix = prefix_once;
17296218822Sdim      text_name += strlen (".gnu.linkonce.t.");
17297218822Sdim    }
17298218822Sdim
17299218822Sdim  prefix_len = strlen (prefix);
17300218822Sdim  text_len = strlen (text_name);
17301218822Sdim  sec_name_len = prefix_len + text_len;
17302218822Sdim  sec_name = xmalloc (sec_name_len + 1);
17303218822Sdim  memcpy (sec_name, prefix, prefix_len);
17304218822Sdim  memcpy (sec_name + prefix_len, text_name, text_len);
17305218822Sdim  sec_name[prefix_len + text_len] = '\0';
17306218822Sdim
17307218822Sdim  flags = SHF_ALLOC;
17308218822Sdim  linkonce = 0;
17309218822Sdim  group_name = 0;
17310218822Sdim
17311218822Sdim  /* Handle COMDAT group.  */
17312218822Sdim  if (prefix != prefix_once && (text_seg->flags & SEC_LINK_ONCE) != 0)
17313218822Sdim    {
17314218822Sdim      group_name = elf_group_name (text_seg);
17315218822Sdim      if (group_name == NULL)
17316218822Sdim	{
17317218822Sdim	  as_bad ("Group section `%s' has no group signature",
17318218822Sdim		  segment_name (text_seg));
17319218822Sdim	  ignore_rest_of_line ();
17320218822Sdim	  return;
17321218822Sdim	}
17322218822Sdim      flags |= SHF_GROUP;
17323218822Sdim      linkonce = 1;
17324218822Sdim    }
17325218822Sdim
17326218822Sdim  obj_elf_change_section (sec_name, type, flags, 0, group_name, linkonce, 0);
17327218822Sdim
17328218822Sdim  /* Set the setion link for index tables.  */
17329218822Sdim  if (idx)
17330218822Sdim    elf_linked_to_section (now_seg) = text_seg;
1733160484Sobrien}
1733260484Sobrien
17333218822Sdim
17334218822Sdim/* Start an unwind table entry.	 HAVE_DATA is nonzero if we have additional
17335218822Sdim   personality routine data.  Returns zero, or the index table value for
17336218822Sdim   and inline entry.  */
17337218822Sdim
1733877298Sobrienstatic valueT
17339218822Sdimcreate_unwind_entry (int have_data)
1734060484Sobrien{
17341218822Sdim  int size;
17342218822Sdim  addressT where;
17343218822Sdim  char *ptr;
17344218822Sdim  /* The current word of data.	*/
17345218822Sdim  valueT data;
17346218822Sdim  /* The number of bytes left in this word.  */
17347218822Sdim  int n;
1734860484Sobrien
17349218822Sdim  finish_unwind_opcodes ();
17350218822Sdim
17351218822Sdim  /* Remember the current text section.	 */
17352218822Sdim  unwind.saved_seg = now_seg;
17353218822Sdim  unwind.saved_subseg = now_subseg;
17354218822Sdim
17355218822Sdim  start_unwind_section (now_seg, 0);
17356218822Sdim
17357218822Sdim  if (unwind.personality_routine == NULL)
1735860484Sobrien    {
17359218822Sdim      if (unwind.personality_index == -2)
1736060484Sobrien	{
17361218822Sdim	  if (have_data)
17362218822Sdim	    as_bad (_("handerdata in cantunwind frame"));
17363218822Sdim	  return 1; /* EXIDX_CANTUNWIND.  */
1736460484Sobrien	}
17365218822Sdim
17366218822Sdim      /* Use a default personality routine if none is specified.  */
17367218822Sdim      if (unwind.personality_index == -1)
1736860484Sobrien	{
17369218822Sdim	  if (unwind.opcode_count > 3)
17370218822Sdim	    unwind.personality_index = 1;
17371218822Sdim	  else
17372218822Sdim	    unwind.personality_index = 0;
1737360484Sobrien	}
1737460484Sobrien
17375218822Sdim      /* Space for the personality routine entry.  */
17376218822Sdim      if (unwind.personality_index == 0)
17377218822Sdim	{
17378218822Sdim	  if (unwind.opcode_count > 3)
17379218822Sdim	    as_bad (_("too many unwind opcodes for personality routine 0"));
1738060484Sobrien
17381218822Sdim	  if (!have_data)
17382218822Sdim	    {
17383218822Sdim	      /* All the data is inline in the index table.  */
17384218822Sdim	      data = 0x80;
17385218822Sdim	      n = 3;
17386218822Sdim	      while (unwind.opcode_count > 0)
17387218822Sdim		{
17388218822Sdim		  unwind.opcode_count--;
17389218822Sdim		  data = (data << 8) | unwind.opcodes[unwind.opcode_count];
17390218822Sdim		  n--;
17391218822Sdim		}
1739260484Sobrien
17393218822Sdim	      /* Pad with "finish" opcodes.  */
17394218822Sdim	      while (n--)
17395218822Sdim		data = (data << 8) | 0xb0;
1739660484Sobrien
17397218822Sdim	      return data;
17398218822Sdim	    }
17399218822Sdim	  size = 0;
17400218822Sdim	}
17401218822Sdim      else
17402218822Sdim	/* We get two opcodes "free" in the first word.	 */
17403218822Sdim	size = unwind.opcode_count - 2;
17404218822Sdim    }
17405218822Sdim  else
17406218822Sdim    /* An extra byte is required for the opcode count.	*/
17407218822Sdim    size = unwind.opcode_count + 1;
1740860484Sobrien
17409218822Sdim  size = (size + 3) >> 2;
17410218822Sdim  if (size > 0xff)
17411218822Sdim    as_bad (_("too many unwind opcodes"));
1741260484Sobrien
17413218822Sdim  frag_align (2, 0, 0);
17414218822Sdim  record_alignment (now_seg, 2);
17415218822Sdim  unwind.table_entry = expr_build_dot ();
17416218822Sdim
17417218822Sdim  /* Allocate the table entry.	*/
17418218822Sdim  ptr = frag_more ((size << 2) + 4);
17419247386Sandrew  memset(ptr, 0, (size << 2) + 4);
17420218822Sdim  where = frag_now_fix () - ((size << 2) + 4);
17421218822Sdim
17422218822Sdim  switch (unwind.personality_index)
1742360484Sobrien    {
17424218822Sdim    case -1:
17425218822Sdim      /* ??? Should this be a PLT generating relocation?  */
17426218822Sdim      /* Custom personality routine.  */
17427218822Sdim      fix_new (frag_now, where, 4, unwind.personality_routine, 0, 1,
17428218822Sdim	       BFD_RELOC_ARM_PREL31);
1742960484Sobrien
17430218822Sdim      where += 4;
17431218822Sdim      ptr += 4;
17432218822Sdim
17433218822Sdim      /* Set the first byte to the number of additional words.	*/
17434218822Sdim      data = size - 1;
17435218822Sdim      n = 3;
1743660484Sobrien      break;
1743760484Sobrien
17438218822Sdim    /* ABI defined personality routines.  */
17439218822Sdim    case 0:
17440218822Sdim      /* Three opcodes bytes are packed into the first word.  */
17441218822Sdim      data = 0x80;
17442218822Sdim      n = 3;
1744360484Sobrien      break;
1744460484Sobrien
17445218822Sdim    case 1:
17446218822Sdim    case 2:
17447218822Sdim      /* The size and first two opcode bytes go in the first word.  */
17448218822Sdim      data = ((0x80 + unwind.personality_index) << 8) | size;
17449218822Sdim      n = 2;
1745060484Sobrien      break;
1745160484Sobrien
1745260484Sobrien    default:
17453218822Sdim      /* Should never happen.  */
17454218822Sdim      abort ();
1745560484Sobrien    }
1745660484Sobrien
17457218822Sdim  /* Pack the opcodes into words (MSB first), reversing the list at the same
17458218822Sdim     time.  */
17459218822Sdim  while (unwind.opcode_count > 0)
1746060484Sobrien    {
17461218822Sdim      if (n == 0)
1746260484Sobrien	{
17463218822Sdim	  md_number_to_chars (ptr, data, 4);
17464218822Sdim	  ptr += 4;
17465218822Sdim	  n = 4;
17466218822Sdim	  data = 0;
1746760484Sobrien	}
17468218822Sdim      unwind.opcode_count--;
17469218822Sdim      n--;
17470218822Sdim      data = (data << 8) | unwind.opcodes[unwind.opcode_count];
1747160484Sobrien    }
17472218822Sdim
17473218822Sdim  /* Finish off the last word.	*/
17474218822Sdim  if (n < 4)
1747560484Sobrien    {
17476218822Sdim      /* Pad with "finish" opcodes.  */
17477218822Sdim      while (n--)
17478218822Sdim	data = (data << 8) | 0xb0;
17479218822Sdim
17480218822Sdim      md_number_to_chars (ptr, data, 4);
1748160484Sobrien    }
1748260484Sobrien
17483218822Sdim  if (!have_data)
17484218822Sdim    {
17485218822Sdim      /* Add an empty descriptor if there is no user-specified data.   */
17486218822Sdim      ptr = frag_more (4);
17487218822Sdim      md_number_to_chars (ptr, 0, 4);
17488218822Sdim    }
17489218822Sdim
1749060484Sobrien  return 0;
1749160484Sobrien}
1749260484Sobrien
1749377298Sobrien
17494218822Sdim/* Initialize the DWARF-2 unwind information for this procedure.  */
17495218822Sdim
17496218822Sdimvoid
17497218822Sdimtc_arm_frame_initial_instructions (void)
17498218822Sdim{
17499218822Sdim  cfi_add_CFA_def_cfa (REG_SP, 0);
17500218822Sdim}
17501218822Sdim#endif /* OBJ_ELF */
17502218822Sdim
17503218822Sdim/* Convert REGNAME to a DWARF-2 register number.  */
17504218822Sdim
17505218822Sdimint
17506218822Sdimtc_arm_regname_to_dw2regnum (char *regname)
17507218822Sdim{
17508218822Sdim  int reg = arm_reg_parse (&regname, REG_TYPE_RN);
17509218822Sdim
17510218822Sdim  if (reg == FAIL)
17511218822Sdim    return -1;
17512218822Sdim
17513218822Sdim  return reg;
17514218822Sdim}
17515218822Sdim
17516218822Sdim#ifdef TE_PE
17517218822Sdimvoid
17518218822Sdimtc_pe_dwarf2_emit_offset (symbolS *symbol, unsigned int size)
17519218822Sdim{
17520218822Sdim  expressionS expr;
17521218822Sdim
17522218822Sdim  expr.X_op = O_secrel;
17523218822Sdim  expr.X_add_symbol = symbol;
17524218822Sdim  expr.X_add_number = 0;
17525218822Sdim  emit_expr (&expr, size);
17526218822Sdim}
17527218822Sdim#endif
17528218822Sdim
17529218822Sdim/* MD interface: Symbol and relocation handling.  */
17530218822Sdim
17531218822Sdim/* Return the address within the segment that a PC-relative fixup is
17532218822Sdim   relative to.  For ARM, PC-relative fixups applied to instructions
17533218822Sdim   are generally relative to the location of the fixup plus 8 bytes.
17534218822Sdim   Thumb branches are offset by 4, and Thumb loads relative to PC
17535218822Sdim   require special handling.  */
17536218822Sdim
1753760484Sobrienlong
17538218822Sdimmd_pcrel_from_section (fixS * fixP, segT seg)
1753960484Sobrien{
17540218822Sdim  offsetT base = fixP->fx_where + fixP->fx_frag->fr_address;
1754177298Sobrien
17542218822Sdim  /* If this is pc-relative and we are going to emit a relocation
17543218822Sdim     then we just want to put out any pipeline compensation that the linker
17544218822Sdim     will need.  Otherwise we want to use the calculated base.
17545218822Sdim     For WinCE we skip the bias for externals as well, since this
17546218822Sdim     is how the MS ARM-CE assembler behaves and we want to be compatible.  */
17547218822Sdim  if (fixP->fx_pcrel
17548218822Sdim      && ((fixP->fx_addsy && S_GET_SEGMENT (fixP->fx_addsy) != seg)
17549218822Sdim	  || (arm_force_relocation (fixP)
17550218822Sdim#ifdef TE_WINCE
17551218822Sdim	      && !S_IS_EXTERNAL (fixP->fx_addsy)
17552218822Sdim#endif
17553218822Sdim	      )))
17554218822Sdim    base = 0;
17555218822Sdim
17556218822Sdim  switch (fixP->fx_r_type)
1755760484Sobrien    {
17558218822Sdim      /* PC relative addressing on the Thumb is slightly odd as the
17559218822Sdim	 bottom two bits of the PC are forced to zero for the
17560218822Sdim	 calculation.  This happens *after* application of the
17561218822Sdim	 pipeline offset.  However, Thumb adrl already adjusts for
17562218822Sdim	 this, so we need not do it again.  */
17563218822Sdim    case BFD_RELOC_ARM_THUMB_ADD:
17564218822Sdim      return base & ~3;
1756560484Sobrien
17566218822Sdim    case BFD_RELOC_ARM_THUMB_OFFSET:
17567218822Sdim    case BFD_RELOC_ARM_T32_OFFSET_IMM:
17568218822Sdim    case BFD_RELOC_ARM_T32_ADD_PC12:
17569218822Sdim    case BFD_RELOC_ARM_T32_CP_OFF_IMM:
17570218822Sdim      return (base + 4) & ~3;
17571218822Sdim
17572218822Sdim      /* Thumb branches are simply offset by +4.  */
17573218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH7:
17574218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH9:
17575218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH12:
17576218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH20:
17577218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH23:
17578218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH25:
17579218822Sdim    case BFD_RELOC_THUMB_PCREL_BLX:
17580218822Sdim      return base + 4;
17581218822Sdim
17582218822Sdim      /* ARM mode branches are offset by +8.  However, the Windows CE
17583218822Sdim	 loader expects the relocation not to take this into account.  */
17584218822Sdim    case BFD_RELOC_ARM_PCREL_BRANCH:
17585218822Sdim    case BFD_RELOC_ARM_PCREL_CALL:
17586218822Sdim    case BFD_RELOC_ARM_PCREL_JUMP:
17587218822Sdim    case BFD_RELOC_ARM_PCREL_BLX:
17588218822Sdim    case BFD_RELOC_ARM_PLT32:
1758960484Sobrien#ifdef TE_WINCE
17590218822Sdim      /* When handling fixups immediately, because we have already
17591218822Sdim         discovered the value of a symbol, or the address of the frag involved
17592218822Sdim	 we must account for the offset by +8, as the OS loader will never see the reloc.
17593218822Sdim         see fixup_segment() in write.c
17594218822Sdim         The S_IS_EXTERNAL test handles the case of global symbols.
17595218822Sdim         Those need the calculated base, not just the pipe compensation the linker will need.  */
17596218822Sdim      if (fixP->fx_pcrel
17597218822Sdim	  && fixP->fx_addsy != NULL
17598218822Sdim	  && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
17599218822Sdim	  && (S_IS_EXTERNAL (fixP->fx_addsy) || !arm_force_relocation (fixP)))
17600218822Sdim	return base + 8;
17601218822Sdim      return base;
1760260484Sobrien#else
17603218822Sdim      return base + 8;
1760460484Sobrien#endif
1760560484Sobrien
17606218822Sdim      /* ARM mode loads relative to PC are also offset by +8.  Unlike
17607218822Sdim	 branches, the Windows CE loader *does* expect the relocation
17608218822Sdim	 to take this into account.  */
17609218822Sdim    case BFD_RELOC_ARM_OFFSET_IMM:
17610218822Sdim    case BFD_RELOC_ARM_OFFSET_IMM8:
17611218822Sdim    case BFD_RELOC_ARM_HWLITERAL:
17612218822Sdim    case BFD_RELOC_ARM_LITERAL:
17613218822Sdim    case BFD_RELOC_ARM_CP_OFF_IMM:
17614218822Sdim      return base + 8;
1761577298Sobrien
17616218822Sdim
17617218822Sdim      /* Other PC-relative relocations are un-offset.  */
17618218822Sdim    default:
17619218822Sdim      return base;
17620218822Sdim    }
1762160484Sobrien}
1762260484Sobrien
1762377298Sobrien/* Under ELF we need to default _GLOBAL_OFFSET_TABLE.
1762477298Sobrien   Otherwise we have no need to default values of symbols.  */
1762560484Sobrien
1762660484SobriensymbolS *
17627218822Sdimmd_undefined_symbol (char * name ATTRIBUTE_UNUSED)
1762860484Sobrien{
1762960484Sobrien#ifdef OBJ_ELF
1763060484Sobrien  if (name[0] == '_' && name[1] == 'G'
1763160484Sobrien      && streq (name, GLOBAL_OFFSET_TABLE_NAME))
1763260484Sobrien    {
1763360484Sobrien      if (!GOT_symbol)
1763460484Sobrien	{
1763560484Sobrien	  if (symbol_find (name))
1763660484Sobrien	    as_bad ("GOT already in the symbol table");
1763777298Sobrien
1763860484Sobrien	  GOT_symbol = symbol_new (name, undefined_section,
1763977298Sobrien				   (valueT) 0, & zero_address_frag);
1764060484Sobrien	}
1764177298Sobrien
1764260484Sobrien      return GOT_symbol;
1764360484Sobrien    }
1764460484Sobrien#endif
1764577298Sobrien
1764660484Sobrien  return 0;
1764760484Sobrien}
1764860484Sobrien
17649218822Sdim/* Subroutine of md_apply_fix.	 Check to see if an immediate can be
17650218822Sdim   computed as two separate immediate values, added together.  We
17651218822Sdim   already know that this value cannot be computed by just one ARM
17652218822Sdim   instruction.	 */
1765360484Sobrien
17654218822Sdimstatic unsigned int
17655218822Sdimvalidate_immediate_twopart (unsigned int   val,
17656218822Sdim			    unsigned int * highpart)
17657218822Sdim{
17658218822Sdim  unsigned int a;
17659218822Sdim  unsigned int i;
17660218822Sdim
17661218822Sdim  for (i = 0; i < 32; i += 2)
17662218822Sdim    if (((a = rotate_left (val, i)) & 0xff) != 0)
17663218822Sdim      {
17664218822Sdim	if (a & 0xff00)
17665218822Sdim	  {
17666218822Sdim	    if (a & ~ 0xffff)
17667218822Sdim	      continue;
17668218822Sdim	    * highpart = (a  >> 8) | ((i + 24) << 7);
17669218822Sdim	  }
17670218822Sdim	else if (a & 0xff0000)
17671218822Sdim	  {
17672218822Sdim	    if (a & 0xff000000)
17673218822Sdim	      continue;
17674218822Sdim	    * highpart = (a >> 16) | ((i + 16) << 7);
17675218822Sdim	  }
17676218822Sdim	else
17677218822Sdim	  {
17678218822Sdim	    assert (a & 0xff000000);
17679218822Sdim	    * highpart = (a >> 24) | ((i + 8) << 7);
17680218822Sdim	  }
17681218822Sdim
17682218822Sdim	return (a & 0xff) | (i << 7);
17683218822Sdim      }
17684218822Sdim
17685218822Sdim  return FAIL;
17686218822Sdim}
17687218822Sdim
1768860484Sobrienstatic int
17689218822Sdimvalidate_offset_imm (unsigned int val, int hwse)
1769060484Sobrien{
17691218822Sdim  if ((hwse && val > 255) || val > 4095)
17692218822Sdim    return FAIL;
17693218822Sdim  return val;
17694218822Sdim}
1769560484Sobrien
17696218822Sdim/* Subroutine of md_apply_fix.	 Do those data_ops which can take a
17697218822Sdim   negative immediate constant by altering the instruction.  A bit of
17698218822Sdim   a hack really.
17699218822Sdim	MOV <-> MVN
17700218822Sdim	AND <-> BIC
17701218822Sdim	ADC <-> SBC
17702218822Sdim	by inverting the second operand, and
17703218822Sdim	ADD <-> SUB
17704218822Sdim	CMP <-> CMN
17705218822Sdim	by negating the second operand.	 */
17706218822Sdim
17707218822Sdimstatic int
17708218822Sdimnegate_data_op (unsigned long * instruction,
17709218822Sdim		unsigned long	value)
17710218822Sdim{
17711218822Sdim  int op, new_inst;
17712218822Sdim  unsigned long negated, inverted;
17713218822Sdim
17714218822Sdim  negated = encode_arm_immediate (-value);
17715218822Sdim  inverted = encode_arm_immediate (~value);
17716218822Sdim
17717218822Sdim  op = (*instruction >> DATA_OP_SHIFT) & 0xf;
17718218822Sdim  switch (op)
17719218822Sdim    {
17720218822Sdim      /* First negates.	 */
17721218822Sdim    case OPCODE_SUB:		 /* ADD <-> SUB	 */
17722218822Sdim      new_inst = OPCODE_ADD;
17723218822Sdim      value = negated;
17724218822Sdim      break;
17725218822Sdim
17726218822Sdim    case OPCODE_ADD:
17727218822Sdim      new_inst = OPCODE_SUB;
17728218822Sdim      value = negated;
17729218822Sdim      break;
17730218822Sdim
17731218822Sdim    case OPCODE_CMP:		 /* CMP <-> CMN	 */
17732218822Sdim      new_inst = OPCODE_CMN;
17733218822Sdim      value = negated;
17734218822Sdim      break;
17735218822Sdim
17736218822Sdim    case OPCODE_CMN:
17737218822Sdim      new_inst = OPCODE_CMP;
17738218822Sdim      value = negated;
17739218822Sdim      break;
17740218822Sdim
17741218822Sdim      /* Now Inverted ops.  */
17742218822Sdim    case OPCODE_MOV:		 /* MOV <-> MVN	 */
17743218822Sdim      new_inst = OPCODE_MVN;
17744218822Sdim      value = inverted;
17745218822Sdim      break;
17746218822Sdim
17747218822Sdim    case OPCODE_MVN:
17748218822Sdim      new_inst = OPCODE_MOV;
17749218822Sdim      value = inverted;
17750218822Sdim      break;
17751218822Sdim
17752218822Sdim    case OPCODE_AND:		 /* AND <-> BIC	 */
17753218822Sdim      new_inst = OPCODE_BIC;
17754218822Sdim      value = inverted;
17755218822Sdim      break;
17756218822Sdim
17757218822Sdim    case OPCODE_BIC:
17758218822Sdim      new_inst = OPCODE_AND;
17759218822Sdim      value = inverted;
17760218822Sdim      break;
17761218822Sdim
17762218822Sdim    case OPCODE_ADC:		  /* ADC <-> SBC  */
17763218822Sdim      new_inst = OPCODE_SBC;
17764218822Sdim      value = inverted;
17765218822Sdim      break;
17766218822Sdim
17767218822Sdim    case OPCODE_SBC:
17768218822Sdim      new_inst = OPCODE_ADC;
17769218822Sdim      value = inverted;
17770218822Sdim      break;
17771218822Sdim
17772218822Sdim      /* We cannot do anything.	 */
17773218822Sdim    default:
17774218822Sdim      return FAIL;
17775218822Sdim    }
17776218822Sdim
17777218822Sdim  if (value == (unsigned) FAIL)
1777860484Sobrien    return FAIL;
1777960484Sobrien
17780218822Sdim  *instruction &= OPCODE_MASK;
17781218822Sdim  *instruction |= new_inst << DATA_OP_SHIFT;
17782218822Sdim  return value;
17783218822Sdim}
1778460484Sobrien
17785218822Sdim/* Like negate_data_op, but for Thumb-2.   */
1778677298Sobrien
17787218822Sdimstatic unsigned int
17788218822Sdimthumb32_negate_data_op (offsetT *instruction, unsigned int value)
17789218822Sdim{
17790218822Sdim  int op, new_inst;
17791218822Sdim  int rd;
17792218822Sdim  unsigned int negated, inverted;
17793218822Sdim
17794218822Sdim  negated = encode_thumb32_immediate (-value);
17795218822Sdim  inverted = encode_thumb32_immediate (~value);
17796218822Sdim
17797218822Sdim  rd = (*instruction >> 8) & 0xf;
17798218822Sdim  op = (*instruction >> T2_DATA_OP_SHIFT) & 0xf;
17799218822Sdim  switch (op)
1780060484Sobrien    {
17801218822Sdim      /* ADD <-> SUB.  Includes CMP <-> CMN.  */
17802218822Sdim    case T2_OPCODE_SUB:
17803218822Sdim      new_inst = T2_OPCODE_ADD;
17804218822Sdim      value = negated;
17805218822Sdim      break;
17806218822Sdim
17807218822Sdim    case T2_OPCODE_ADD:
17808218822Sdim      new_inst = T2_OPCODE_SUB;
17809218822Sdim      value = negated;
17810218822Sdim      break;
17811218822Sdim
17812218822Sdim      /* ORR <-> ORN.  Includes MOV <-> MVN.  */
17813218822Sdim    case T2_OPCODE_ORR:
17814218822Sdim      new_inst = T2_OPCODE_ORN;
17815218822Sdim      value = inverted;
17816218822Sdim      break;
17817218822Sdim
17818218822Sdim    case T2_OPCODE_ORN:
17819218822Sdim      new_inst = T2_OPCODE_ORR;
17820218822Sdim      value = inverted;
17821218822Sdim      break;
17822218822Sdim
17823218822Sdim      /* AND <-> BIC.  TST has no inverted equivalent.  */
17824218822Sdim    case T2_OPCODE_AND:
17825218822Sdim      new_inst = T2_OPCODE_BIC;
17826218822Sdim      if (rd == 15)
17827218822Sdim	value = FAIL;
17828218822Sdim      else
17829218822Sdim	value = inverted;
17830218822Sdim      break;
17831218822Sdim
17832218822Sdim    case T2_OPCODE_BIC:
17833218822Sdim      new_inst = T2_OPCODE_AND;
17834218822Sdim      value = inverted;
17835218822Sdim      break;
17836218822Sdim
17837218822Sdim      /* ADC <-> SBC  */
17838218822Sdim    case T2_OPCODE_ADC:
17839218822Sdim      new_inst = T2_OPCODE_SBC;
17840218822Sdim      value = inverted;
17841218822Sdim      break;
17842218822Sdim
17843218822Sdim    case T2_OPCODE_SBC:
17844218822Sdim      new_inst = T2_OPCODE_ADC;
17845218822Sdim      value = inverted;
17846218822Sdim      break;
17847218822Sdim
17848218822Sdim      /* We cannot do anything.	 */
17849218822Sdim    default:
17850218822Sdim      return FAIL;
1785160484Sobrien    }
1785260484Sobrien
17853218822Sdim  if (value == (unsigned int)FAIL)
17854218822Sdim    return FAIL;
17855218822Sdim
17856218822Sdim  *instruction &= T2_OPCODE_MASK;
17857218822Sdim  *instruction |= new_inst << T2_DATA_OP_SHIFT;
17858218822Sdim  return value;
1785960484Sobrien}
1786060484Sobrien
17861218822Sdim/* Read a 32-bit thumb instruction from buf.  */
17862218822Sdimstatic unsigned long
17863218822Sdimget_thumb32_insn (char * buf)
1786489857Sobrien{
17865218822Sdim  unsigned long insn;
17866218822Sdim  insn = md_chars_to_number (buf, THUMB_SIZE) << 16;
17867218822Sdim  insn |= md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
1786889857Sobrien
17869218822Sdim  return insn;
17870218822Sdim}
1787189857Sobrien
17872218822Sdim
17873218822Sdim/* We usually want to set the low bit on the address of thumb function
17874218822Sdim   symbols.  In particular .word foo - . should have the low bit set.
17875218822Sdim   Generic code tries to fold the difference of two symbols to
17876218822Sdim   a constant.  Prevent this and force a relocation when the first symbols
17877218822Sdim   is a thumb function.  */
17878218822Sdimint
17879218822Sdimarm_optimize_expr (expressionS *l, operatorT op, expressionS *r)
17880218822Sdim{
17881218822Sdim  if (op == O_subtract
17882218822Sdim      && l->X_op == O_symbol
17883218822Sdim      && r->X_op == O_symbol
17884218822Sdim      && THUMB_IS_FUNC (l->X_add_symbol))
17885218822Sdim    {
17886218822Sdim      l->X_op = O_subtract;
17887218822Sdim      l->X_op_symbol = r->X_add_symbol;
17888218822Sdim      l->X_add_number -= r->X_add_number;
17889218822Sdim      return 1;
17890218822Sdim    }
17891218822Sdim  /* Process as normal.  */
17892218822Sdim  return 0;
1789389857Sobrien}
1789489857Sobrien
1789589857Sobrienvoid
17896218822Sdimmd_apply_fix (fixS *	fixP,
17897218822Sdim	       valueT * valP,
17898218822Sdim	       segT	seg)
1789960484Sobrien{
17900218822Sdim  offsetT	 value = * valP;
17901218822Sdim  offsetT	 newval;
17902218822Sdim  unsigned int	 newimm;
17903218822Sdim  unsigned long	 temp;
17904218822Sdim  int		 sign;
17905218822Sdim  char *	 buf = fixP->fx_where + fixP->fx_frag->fr_literal;
1790660484Sobrien
17907218822Sdim  assert (fixP->fx_r_type <= BFD_RELOC_UNUSED);
1790860484Sobrien
1790960484Sobrien  /* Note whether this will delete the relocation.  */
17910218822Sdim
1791160484Sobrien  if (fixP->fx_addsy == 0 && !fixP->fx_pcrel)
1791260484Sobrien    fixP->fx_done = 1;
1791360484Sobrien
17914218822Sdim  /* On a 64-bit host, silently truncate 'value' to 32 bits for
17915218822Sdim     consistency with the behavior on 32-bit hosts.  Remember value
17916218822Sdim     for emit_reloc.  */
17917218822Sdim  value &= 0xffffffff;
17918218822Sdim  value ^= 0x80000000;
17919218822Sdim  value -= 0x80000000;
1792060484Sobrien
17921218822Sdim  *valP = value;
1792277298Sobrien  fixP->fx_addnumber = value;
1792360484Sobrien
17924218822Sdim  /* Same treatment for fixP->fx_offset.  */
17925218822Sdim  fixP->fx_offset &= 0xffffffff;
17926218822Sdim  fixP->fx_offset ^= 0x80000000;
17927218822Sdim  fixP->fx_offset -= 0x80000000;
17928218822Sdim
1792960484Sobrien  switch (fixP->fx_r_type)
1793060484Sobrien    {
17931218822Sdim    case BFD_RELOC_NONE:
17932218822Sdim      /* This will need to go in the object file.  */
17933218822Sdim      fixP->fx_done = 0;
17934218822Sdim      break;
17935218822Sdim
1793660484Sobrien    case BFD_RELOC_ARM_IMMEDIATE:
17937218822Sdim      /* We claim that this fixup has been processed here,
17938218822Sdim	 even if in fact we generate an error because we do
17939218822Sdim	 not have a reloc for it, so tc_gen_reloc will reject it.  */
17940218822Sdim      fixP->fx_done = 1;
17941218822Sdim
17942218822Sdim      if (fixP->fx_addsy
17943218822Sdim	  && ! S_IS_DEFINED (fixP->fx_addsy))
17944218822Sdim	{
17945218822Sdim	  as_bad_where (fixP->fx_file, fixP->fx_line,
17946218822Sdim			_("undefined symbol %s used as an immediate value"),
17947218822Sdim			S_GET_NAME (fixP->fx_addsy));
17948218822Sdim	  break;
17949218822Sdim	}
17950218822Sdim
17951218822Sdim      newimm = encode_arm_immediate (value);
1795260484Sobrien      temp = md_chars_to_number (buf, INSN_SIZE);
1795360484Sobrien
1795460484Sobrien      /* If the instruction will fail, see if we can fix things up by
1795560484Sobrien	 changing the opcode.  */
1795660484Sobrien      if (newimm == (unsigned int) FAIL
1795760484Sobrien	  && (newimm = negate_data_op (&temp, value)) == (unsigned int) FAIL)
1795860484Sobrien	{
1795960484Sobrien	  as_bad_where (fixP->fx_file, fixP->fx_line,
1796060484Sobrien			_("invalid constant (%lx) after fixup"),
1796160484Sobrien			(unsigned long) value);
1796260484Sobrien	  break;
1796360484Sobrien	}
1796460484Sobrien
1796560484Sobrien      newimm |= (temp & 0xfffff000);
1796660484Sobrien      md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
1796760484Sobrien      break;
1796860484Sobrien
1796960484Sobrien    case BFD_RELOC_ARM_ADRL_IMMEDIATE:
1797060484Sobrien      {
1797160484Sobrien	unsigned int highpart = 0;
1797277298Sobrien	unsigned int newinsn  = 0xe1a00000; /* nop.  */
17973130561Sobrien
17974218822Sdim	newimm = encode_arm_immediate (value);
1797560484Sobrien	temp = md_chars_to_number (buf, INSN_SIZE);
1797660484Sobrien
1797760484Sobrien	/* If the instruction will fail, see if we can fix things up by
17978218822Sdim	   changing the opcode.	 */
1797960484Sobrien	if (newimm == (unsigned int) FAIL
1798060484Sobrien	    && (newimm = negate_data_op (& temp, value)) == (unsigned int) FAIL)
1798160484Sobrien	  {
1798277298Sobrien	    /* No ?  OK - try using two ADD instructions to generate
17983218822Sdim	       the value.  */
1798460484Sobrien	    newimm = validate_immediate_twopart (value, & highpart);
1798560484Sobrien
1798677298Sobrien	    /* Yes - then make sure that the second instruction is
17987218822Sdim	       also an add.  */
1798860484Sobrien	    if (newimm != (unsigned int) FAIL)
1798960484Sobrien	      newinsn = temp;
1799060484Sobrien	    /* Still No ?  Try using a negated value.  */
1799168765Sobrien	    else if ((newimm = validate_immediate_twopart (- value, & highpart)) != (unsigned int) FAIL)
1799277298Sobrien	      temp = newinsn = (temp & OPCODE_MASK) | OPCODE_SUB << DATA_OP_SHIFT;
1799360484Sobrien	    /* Otherwise - give up.  */
1799460484Sobrien	    else
1799560484Sobrien	      {
1799660484Sobrien		as_bad_where (fixP->fx_file, fixP->fx_line,
1799789857Sobrien			      _("unable to compute ADRL instructions for PC offset of 0x%lx"),
17998130561Sobrien			      (long) value);
1799960484Sobrien		break;
1800060484Sobrien	      }
1800160484Sobrien
1800277298Sobrien	    /* Replace the first operand in the 2nd instruction (which
1800377298Sobrien	       is the PC) with the destination register.  We have
1800477298Sobrien	       already added in the PC in the first instruction and we
1800577298Sobrien	       do not want to do it again.  */
1800660484Sobrien	    newinsn &= ~ 0xf0000;
1800760484Sobrien	    newinsn |= ((newinsn & 0x0f000) << 4);
1800860484Sobrien	  }
1800960484Sobrien
1801060484Sobrien	newimm |= (temp & 0xfffff000);
1801160484Sobrien	md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
1801260484Sobrien
1801360484Sobrien	highpart |= (newinsn & 0xfffff000);
1801460484Sobrien	md_number_to_chars (buf + INSN_SIZE, (valueT) highpart, INSN_SIZE);
1801560484Sobrien      }
1801660484Sobrien      break;
1801760484Sobrien
1801860484Sobrien    case BFD_RELOC_ARM_OFFSET_IMM:
18019218822Sdim      if (!fixP->fx_done && seg->use_rela_p)
18020218822Sdim	value = 0;
18021218822Sdim
18022218822Sdim    case BFD_RELOC_ARM_LITERAL:
1802360484Sobrien      sign = value >= 0;
1802477298Sobrien
1802560484Sobrien      if (value < 0)
1802660484Sobrien	value = - value;
1802777298Sobrien
1802860484Sobrien      if (validate_offset_imm (value, 0) == FAIL)
1802977298Sobrien	{
18030218822Sdim	  if (fixP->fx_r_type == BFD_RELOC_ARM_LITERAL)
18031218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
18032218822Sdim			  _("invalid literal constant: pool needs to be closer"));
18033218822Sdim	  else
18034218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
18035218822Sdim			  _("bad immediate value for offset (%ld)"),
18036218822Sdim			  (long) value);
1803777298Sobrien	  break;
1803877298Sobrien	}
1803960484Sobrien
1804060484Sobrien      newval = md_chars_to_number (buf, INSN_SIZE);
1804160484Sobrien      newval &= 0xff7ff000;
1804260484Sobrien      newval |= value | (sign ? INDEX_UP : 0);
1804360484Sobrien      md_number_to_chars (buf, newval, INSN_SIZE);
1804460484Sobrien      break;
1804560484Sobrien
1804677298Sobrien    case BFD_RELOC_ARM_OFFSET_IMM8:
1804777298Sobrien    case BFD_RELOC_ARM_HWLITERAL:
1804860484Sobrien      sign = value >= 0;
1804977298Sobrien
1805060484Sobrien      if (value < 0)
1805160484Sobrien	value = - value;
1805260484Sobrien
1805360484Sobrien      if (validate_offset_imm (value, 1) == FAIL)
1805477298Sobrien	{
1805577298Sobrien	  if (fixP->fx_r_type == BFD_RELOC_ARM_HWLITERAL)
1805677298Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
1805777298Sobrien			  _("invalid literal constant: pool needs to be closer"));
1805877298Sobrien	  else
18059218822Sdim	    as_bad (_("bad immediate value for 8-bit offset (%ld)"),
1806060484Sobrien		    (long) value);
1806177298Sobrien	  break;
1806277298Sobrien	}
1806360484Sobrien
1806460484Sobrien      newval = md_chars_to_number (buf, INSN_SIZE);
1806560484Sobrien      newval &= 0xff7ff0f0;
1806660484Sobrien      newval |= ((value >> 4) << 8) | (value & 0xf) | (sign ? INDEX_UP : 0);
1806760484Sobrien      md_number_to_chars (buf, newval, INSN_SIZE);
1806860484Sobrien      break;
1806960484Sobrien
18070218822Sdim    case BFD_RELOC_ARM_T32_OFFSET_U8:
18071218822Sdim      if (value < 0 || value > 1020 || value % 4 != 0)
18072218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18073218822Sdim		      _("bad immediate value for offset (%ld)"), (long) value);
18074218822Sdim      value /= 4;
1807577298Sobrien
18076218822Sdim      newval = md_chars_to_number (buf+2, THUMB_SIZE);
18077218822Sdim      newval |= value;
18078218822Sdim      md_number_to_chars (buf+2, newval, THUMB_SIZE);
18079218822Sdim      break;
1808060484Sobrien
18081218822Sdim    case BFD_RELOC_ARM_T32_OFFSET_IMM:
18082218822Sdim      /* This is a complicated relocation used for all varieties of Thumb32
18083218822Sdim	 load/store instruction with immediate offset:
18084218822Sdim
18085218822Sdim	 1110 100P u1WL NNNN XXXX YYYY iiii iiii - +/-(U) pre/post(P) 8-bit,
18086218822Sdim	                                           *4, optional writeback(W)
18087218822Sdim						   (doubleword load/store)
18088218822Sdim
18089218822Sdim	 1111 100S uTTL 1111 XXXX iiii iiii iiii - +/-(U) 12-bit PC-rel
18090218822Sdim	 1111 100S 0TTL NNNN XXXX 1Pu1 iiii iiii - +/-(U) pre/post(P) 8-bit
18091218822Sdim	 1111 100S 0TTL NNNN XXXX 1110 iiii iiii - positive 8-bit (T instruction)
18092218822Sdim	 1111 100S 1TTL NNNN XXXX iiii iiii iiii - positive 12-bit
18093218822Sdim	 1111 100S 0TTL NNNN XXXX 1100 iiii iiii - negative 8-bit
18094218822Sdim
18095218822Sdim	 Uppercase letters indicate bits that are already encoded at
18096218822Sdim	 this point.  Lowercase letters are our problem.  For the
18097218822Sdim	 second block of instructions, the secondary opcode nybble
18098218822Sdim	 (bits 8..11) is present, and bit 23 is zero, even if this is
18099218822Sdim	 a PC-relative operation.  */
18100218822Sdim      newval = md_chars_to_number (buf, THUMB_SIZE);
18101218822Sdim      newval <<= 16;
18102218822Sdim      newval |= md_chars_to_number (buf+THUMB_SIZE, THUMB_SIZE);
18103218822Sdim
18104218822Sdim      if ((newval & 0xf0000000) == 0xe0000000)
1810560484Sobrien	{
18106218822Sdim	  /* Doubleword load/store: 8-bit offset, scaled by 4.  */
18107218822Sdim	  if (value >= 0)
18108218822Sdim	    newval |= (1 << 23);
18109218822Sdim	  else
18110218822Sdim	    value = -value;
18111218822Sdim	  if (value % 4 != 0)
18112218822Sdim	    {
18113218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18114218822Sdim			    _("offset not a multiple of 4"));
18115218822Sdim	      break;
18116218822Sdim	    }
18117218822Sdim	  value /= 4;
18118218822Sdim	  if (value > 0xff)
18119218822Sdim	    {
18120218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18121218822Sdim			    _("offset out of range"));
18122218822Sdim	      break;
18123218822Sdim	    }
18124218822Sdim	  newval &= ~0xff;
1812560484Sobrien	}
18126218822Sdim      else if ((newval & 0x000f0000) == 0x000f0000)
18127218822Sdim	{
18128218822Sdim	  /* PC-relative, 12-bit offset.  */
18129218822Sdim	  if (value >= 0)
18130218822Sdim	    newval |= (1 << 23);
18131218822Sdim	  else
18132218822Sdim	    value = -value;
18133218822Sdim	  if (value > 0xfff)
18134218822Sdim	    {
18135218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18136218822Sdim			    _("offset out of range"));
18137218822Sdim	      break;
18138218822Sdim	    }
18139218822Sdim	  newval &= ~0xfff;
18140218822Sdim	}
18141218822Sdim      else if ((newval & 0x00000100) == 0x00000100)
18142218822Sdim	{
18143218822Sdim	  /* Writeback: 8-bit, +/- offset.  */
18144218822Sdim	  if (value >= 0)
18145218822Sdim	    newval |= (1 << 9);
18146218822Sdim	  else
18147218822Sdim	    value = -value;
18148218822Sdim	  if (value > 0xff)
18149218822Sdim	    {
18150218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18151218822Sdim			    _("offset out of range"));
18152218822Sdim	      break;
18153218822Sdim	    }
18154218822Sdim	  newval &= ~0xff;
18155218822Sdim	}
18156218822Sdim      else if ((newval & 0x00000f00) == 0x00000e00)
18157218822Sdim	{
18158218822Sdim	  /* T-instruction: positive 8-bit offset.  */
18159218822Sdim	  if (value < 0 || value > 0xff)
18160218822Sdim	    {
18161218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18162218822Sdim			    _("offset out of range"));
18163218822Sdim	      break;
18164218822Sdim	    }
18165218822Sdim	  newval &= ~0xff;
18166218822Sdim	  newval |= value;
18167218822Sdim	}
18168218822Sdim      else
18169218822Sdim	{
18170218822Sdim	  /* Positive 12-bit or negative 8-bit offset.  */
18171218822Sdim	  int limit;
18172218822Sdim	  if (value >= 0)
18173218822Sdim	    {
18174218822Sdim	      newval |= (1 << 23);
18175218822Sdim	      limit = 0xfff;
18176218822Sdim	    }
18177218822Sdim	  else
18178218822Sdim	    {
18179218822Sdim	      value = -value;
18180218822Sdim	      limit = 0xff;
18181218822Sdim	    }
18182218822Sdim	  if (value > limit)
18183218822Sdim	    {
18184218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18185218822Sdim			    _("offset out of range"));
18186218822Sdim	      break;
18187218822Sdim	    }
18188218822Sdim	  newval &= ~limit;
18189218822Sdim	}
1819060484Sobrien
18191218822Sdim      newval |= value;
18192218822Sdim      md_number_to_chars (buf, (newval >> 16) & 0xffff, THUMB_SIZE);
18193218822Sdim      md_number_to_chars (buf + THUMB_SIZE, newval & 0xffff, THUMB_SIZE);
1819460484Sobrien      break;
1819560484Sobrien
1819660484Sobrien    case BFD_RELOC_ARM_SHIFT_IMM:
1819760484Sobrien      newval = md_chars_to_number (buf, INSN_SIZE);
1819860484Sobrien      if (((unsigned long) value) > 32
1819977298Sobrien	  || (value == 32
1820060484Sobrien	      && (((newval & 0x60) == 0) || (newval & 0x60) == 0x60)))
1820160484Sobrien	{
1820260484Sobrien	  as_bad_where (fixP->fx_file, fixP->fx_line,
1820360484Sobrien			_("shift expression is too large"));
1820460484Sobrien	  break;
1820560484Sobrien	}
1820660484Sobrien
1820760484Sobrien      if (value == 0)
18208218822Sdim	/* Shifts of zero must be done as lsl.	*/
1820977298Sobrien	newval &= ~0x60;
1821060484Sobrien      else if (value == 32)
1821160484Sobrien	value = 0;
1821260484Sobrien      newval &= 0xfffff07f;
1821360484Sobrien      newval |= (value & 0x1f) << 7;
1821477298Sobrien      md_number_to_chars (buf, newval, INSN_SIZE);
1821560484Sobrien      break;
1821660484Sobrien
18217218822Sdim    case BFD_RELOC_ARM_T32_IMMEDIATE:
18218218822Sdim    case BFD_RELOC_ARM_T32_ADD_IMM:
18219218822Sdim    case BFD_RELOC_ARM_T32_IMM12:
18220218822Sdim    case BFD_RELOC_ARM_T32_ADD_PC12:
18221218822Sdim      /* We claim that this fixup has been processed here,
18222218822Sdim	 even if in fact we generate an error because we do
18223218822Sdim	 not have a reloc for it, so tc_gen_reloc will reject it.  */
18224218822Sdim      fixP->fx_done = 1;
18225218822Sdim
18226218822Sdim      if (fixP->fx_addsy
18227218822Sdim	  && ! S_IS_DEFINED (fixP->fx_addsy))
18228218822Sdim	{
18229218822Sdim	  as_bad_where (fixP->fx_file, fixP->fx_line,
18230218822Sdim			_("undefined symbol %s used as an immediate value"),
18231218822Sdim			S_GET_NAME (fixP->fx_addsy));
18232218822Sdim	  break;
18233218822Sdim	}
18234218822Sdim
18235218822Sdim      newval = md_chars_to_number (buf, THUMB_SIZE);
18236218822Sdim      newval <<= 16;
18237218822Sdim      newval |= md_chars_to_number (buf+2, THUMB_SIZE);
18238218822Sdim
18239218822Sdim      newimm = FAIL;
18240218822Sdim      if (fixP->fx_r_type == BFD_RELOC_ARM_T32_IMMEDIATE
18241218822Sdim	  || fixP->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM)
18242218822Sdim	{
18243218822Sdim	  newimm = encode_thumb32_immediate (value);
18244218822Sdim	  if (newimm == (unsigned int) FAIL)
18245218822Sdim	    newimm = thumb32_negate_data_op (&newval, value);
18246218822Sdim	}
18247218822Sdim      if (fixP->fx_r_type != BFD_RELOC_ARM_T32_IMMEDIATE
18248218822Sdim	  && newimm == (unsigned int) FAIL)
18249218822Sdim	{
18250218822Sdim	  /* Turn add/sum into addw/subw.  */
18251218822Sdim	  if (fixP->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM)
18252218822Sdim	    newval = (newval & 0xfeffffff) | 0x02000000;
18253218822Sdim
18254218822Sdim	  /* 12 bit immediate for addw/subw.  */
18255218822Sdim	  if (value < 0)
18256218822Sdim	    {
18257218822Sdim	      value = -value;
18258218822Sdim	      newval ^= 0x00a00000;
18259218822Sdim	    }
18260218822Sdim	  if (value > 0xfff)
18261218822Sdim	    newimm = (unsigned int) FAIL;
18262218822Sdim	  else
18263218822Sdim	    newimm = value;
18264218822Sdim	}
18265218822Sdim
18266218822Sdim      if (newimm == (unsigned int)FAIL)
18267218822Sdim	{
18268218822Sdim	  as_bad_where (fixP->fx_file, fixP->fx_line,
18269218822Sdim			_("invalid constant (%lx) after fixup"),
18270218822Sdim			(unsigned long) value);
18271218822Sdim	  break;
18272218822Sdim	}
18273218822Sdim
18274218822Sdim      newval |= (newimm & 0x800) << 15;
18275218822Sdim      newval |= (newimm & 0x700) << 4;
18276218822Sdim      newval |= (newimm & 0x0ff);
18277218822Sdim
18278218822Sdim      md_number_to_chars (buf,   (valueT) ((newval >> 16) & 0xffff), THUMB_SIZE);
18279218822Sdim      md_number_to_chars (buf+2, (valueT) (newval & 0xffff), THUMB_SIZE);
18280218822Sdim      break;
18281218822Sdim
18282218822Sdim    case BFD_RELOC_ARM_SMC:
18283218822Sdim      if (((unsigned long) value) > 0xffff)
18284218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18285218822Sdim		      _("invalid smc expression"));
18286218822Sdim      newval = md_chars_to_number (buf, INSN_SIZE);
18287218822Sdim      newval |= (value & 0xf) | ((value & 0xfff0) << 4);
18288218822Sdim      md_number_to_chars (buf, newval, INSN_SIZE);
18289218822Sdim      break;
18290218822Sdim
1829160484Sobrien    case BFD_RELOC_ARM_SWI:
18292218822Sdim      if (fixP->tc_fix_data != 0)
1829360484Sobrien	{
1829460484Sobrien	  if (((unsigned long) value) > 0xff)
1829560484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
1829689857Sobrien			  _("invalid swi expression"));
18297218822Sdim	  newval = md_chars_to_number (buf, THUMB_SIZE);
1829860484Sobrien	  newval |= value;
1829960484Sobrien	  md_number_to_chars (buf, newval, THUMB_SIZE);
1830060484Sobrien	}
1830160484Sobrien      else
1830260484Sobrien	{
1830360484Sobrien	  if (((unsigned long) value) > 0x00ffffff)
1830477298Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
1830589857Sobrien			  _("invalid swi expression"));
18306218822Sdim	  newval = md_chars_to_number (buf, INSN_SIZE);
1830760484Sobrien	  newval |= value;
1830877298Sobrien	  md_number_to_chars (buf, newval, INSN_SIZE);
1830960484Sobrien	}
1831060484Sobrien      break;
1831160484Sobrien
1831260484Sobrien    case BFD_RELOC_ARM_MULTI:
1831360484Sobrien      if (((unsigned long) value) > 0xffff)
1831460484Sobrien	as_bad_where (fixP->fx_file, fixP->fx_line,
1831589857Sobrien		      _("invalid expression in load/store multiple"));
1831660484Sobrien      newval = value | md_chars_to_number (buf, INSN_SIZE);
1831760484Sobrien      md_number_to_chars (buf, newval, INSN_SIZE);
1831860484Sobrien      break;
1831960484Sobrien
18320218822Sdim#ifdef OBJ_ELF
18321218822Sdim    case BFD_RELOC_ARM_PCREL_CALL:
1832260484Sobrien      newval = md_chars_to_number (buf, INSN_SIZE);
18323218822Sdim      if ((newval & 0xf0000000) == 0xf0000000)
18324218822Sdim	temp = 1;
18325218822Sdim      else
18326218822Sdim	temp = 3;
18327218822Sdim      goto arm_branch_common;
1832860484Sobrien
18329218822Sdim    case BFD_RELOC_ARM_PCREL_JUMP:
18330218822Sdim    case BFD_RELOC_ARM_PLT32:
1833160484Sobrien#endif
18332218822Sdim    case BFD_RELOC_ARM_PCREL_BRANCH:
18333218822Sdim      temp = 3;
18334218822Sdim      goto arm_branch_common;
1833560484Sobrien
18336218822Sdim    case BFD_RELOC_ARM_PCREL_BLX:
18337218822Sdim      temp = 1;
18338218822Sdim    arm_branch_common:
1833960484Sobrien      /* We are going to store value (shifted right by two) in the
18340218822Sdim	 instruction, in a 24 bit, signed field.  Bits 26 through 32 either
18341218822Sdim	 all clear or all set and bit 0 must be clear.  For B/BL bit 1 must
18342218822Sdim	 also be be clear.  */
18343218822Sdim      if (value & temp)
18344218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18345218822Sdim		      _("misaligned branch destination"));
18346218822Sdim      if ((value & (offsetT)0xfe000000) != (offsetT)0
18347218822Sdim	  && (value & (offsetT)0xfe000000) != (offsetT)0xfe000000)
18348218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18349218822Sdim		      _("branch out of range"));
18350218822Sdim
18351218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
1835260484Sobrien	{
18353218822Sdim	  newval = md_chars_to_number (buf, INSN_SIZE);
18354218822Sdim	  newval |= (value >> 2) & 0x00ffffff;
18355218822Sdim	  /* Set the H bit on BLX instructions.  */
18356218822Sdim	  if (temp == 1)
1835760484Sobrien	    {
18358218822Sdim	      if (value & 2)
18359218822Sdim		newval |= 0x01000000;
18360218822Sdim	      else
18361218822Sdim		newval &= ~0x01000000;
1836260484Sobrien	    }
18363218822Sdim	  md_number_to_chars (buf, newval, INSN_SIZE);
18364218822Sdim	}
18365218822Sdim      break;
1836677298Sobrien
18367218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH7: /* CBZ */
18368218822Sdim      /* CBZ can only branch forward.  */
18369218822Sdim
18370218822Sdim      /* Attempts to use CBZ to branch to the next instruction
18371218822Sdim         (which, strictly speaking, are prohibited) will be turned into
18372218822Sdim         no-ops.
18373218822Sdim
18374218822Sdim	 FIXME: It may be better to remove the instruction completely and
18375218822Sdim	 perform relaxation.  */
18376218822Sdim      if (value == -2)
18377218822Sdim	{
18378218822Sdim	  newval = md_chars_to_number (buf, THUMB_SIZE);
18379218822Sdim	  newval = 0xbf00; /* NOP encoding T1 */
18380218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18381218822Sdim	}
18382218822Sdim      else
18383218822Sdim	{
18384218822Sdim	  if (value & ~0x7e)
1838560484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18386218822Sdim		          _("branch out of range"));
18387218822Sdim
18388218822Sdim          if (fixP->fx_done || !seg->use_rela_p)
18389218822Sdim	    {
18390218822Sdim	      newval = md_chars_to_number (buf, THUMB_SIZE);
18391218822Sdim	      newval |= ((value & 0x3e) << 2) | ((value & 0x40) << 3);
18392218822Sdim	      md_number_to_chars (buf, newval, THUMB_SIZE);
18393218822Sdim	    }
1839460484Sobrien	}
18395218822Sdim      break;
1839660484Sobrien
18397218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH9: /* Conditional branch.	*/
18398218822Sdim      if ((value & ~0xff) && ((value & ~0xff) != ~0xff))
1839960484Sobrien	as_bad_where (fixP->fx_file, fixP->fx_line,
18400218822Sdim		      _("branch out of range"));
1840177298Sobrien
18402218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18403218822Sdim	{
18404218822Sdim	  newval = md_chars_to_number (buf, THUMB_SIZE);
18405218822Sdim	  newval |= (value & 0x1ff) >> 1;
18406218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18407218822Sdim	}
1840860484Sobrien      break;
1840960484Sobrien
18410218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH12: /* Unconditional branch.  */
18411218822Sdim      if ((value & ~0x7ff) && ((value & ~0x7ff) != ~0x7ff))
18412218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18413218822Sdim		      _("branch out of range"));
1841460484Sobrien
18415218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18416218822Sdim	{
18417218822Sdim	  newval = md_chars_to_number (buf, THUMB_SIZE);
18418218822Sdim	  newval |= (value & 0xfff) >> 1;
18419218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18420218822Sdim	}
1842177298Sobrien      break;
1842277298Sobrien
18423218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH20:
18424218822Sdim      if ((value & ~0x1fffff) && ((value & ~0x1fffff) != ~0x1fffff))
18425218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18426218822Sdim		      _("conditional branch out of range"));
1842760484Sobrien
18428218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18429218822Sdim	{
18430218822Sdim	  offsetT newval2;
18431218822Sdim	  addressT S, J1, J2, lo, hi;
1843260484Sobrien
18433218822Sdim	  S  = (value & 0x00100000) >> 20;
18434218822Sdim	  J2 = (value & 0x00080000) >> 19;
18435218822Sdim	  J1 = (value & 0x00040000) >> 18;
18436218822Sdim	  hi = (value & 0x0003f000) >> 12;
18437218822Sdim	  lo = (value & 0x00000ffe) >> 1;
1843860484Sobrien
18439218822Sdim	  newval   = md_chars_to_number (buf, THUMB_SIZE);
18440218822Sdim	  newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
18441218822Sdim	  newval  |= (S << 10) | hi;
18442218822Sdim	  newval2 |= (J1 << 13) | (J2 << 11) | lo;
18443218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18444218822Sdim	  md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
18445218822Sdim	}
1844660484Sobrien      break;
1844760484Sobrien
1844877298Sobrien    case BFD_RELOC_THUMB_PCREL_BLX:
1844960484Sobrien    case BFD_RELOC_THUMB_PCREL_BRANCH23:
18450218822Sdim      if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff))
18451218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18452218822Sdim		      _("branch out of range"));
1845360484Sobrien
18454218822Sdim      if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
18455218822Sdim	/* For a BLX instruction, make sure that the relocation is rounded up
18456218822Sdim	   to a word boundary.  This follows the semantics of the instruction
18457218822Sdim	   which specifies that bit 1 of the target address will come from bit
18458218822Sdim	   1 of the base address.  */
18459218822Sdim	value = (value + 1) & ~ 1;
18460104834Sobrien
18461218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18462218822Sdim	{
18463218822Sdim	  offsetT newval2;
1846460484Sobrien
18465218822Sdim	  newval   = md_chars_to_number (buf, THUMB_SIZE);
18466218822Sdim	  newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
18467218822Sdim	  newval  |= (value & 0x7fffff) >> 12;
18468218822Sdim	  newval2 |= (value & 0xfff) >> 1;
18469218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18470218822Sdim	  md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
18471218822Sdim	}
1847260484Sobrien      break;
1847360484Sobrien
18474218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH25:
18475218822Sdim      if ((value & ~0x1ffffff) && ((value & ~0x1ffffff) != ~0x1ffffff))
18476218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18477218822Sdim		      _("branch out of range"));
18478218822Sdim
18479218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
1848077298Sobrien	{
18481218822Sdim	  offsetT newval2;
18482218822Sdim	  addressT S, I1, I2, lo, hi;
18483218822Sdim
18484218822Sdim	  S  = (value & 0x01000000) >> 24;
18485218822Sdim	  I1 = (value & 0x00800000) >> 23;
18486218822Sdim	  I2 = (value & 0x00400000) >> 22;
18487218822Sdim	  hi = (value & 0x003ff000) >> 12;
18488218822Sdim	  lo = (value & 0x00000ffe) >> 1;
18489218822Sdim
18490218822Sdim	  I1 = !(I1 ^ S);
18491218822Sdim	  I2 = !(I2 ^ S);
18492218822Sdim
18493218822Sdim	  newval   = md_chars_to_number (buf, THUMB_SIZE);
18494218822Sdim	  newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
18495218822Sdim	  newval  |= (S << 10) | hi;
18496218822Sdim	  newval2 |= (I1 << 13) | (I2 << 11) | lo;
18497218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18498218822Sdim	  md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
1849977298Sobrien	}
1850060484Sobrien      break;
1850160484Sobrien
18502218822Sdim    case BFD_RELOC_8:
18503218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18504218822Sdim	md_number_to_chars (buf, value, 1);
18505218822Sdim      break;
18506218822Sdim
1850760484Sobrien    case BFD_RELOC_16:
18508218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
1850960484Sobrien	md_number_to_chars (buf, value, 2);
1851060484Sobrien      break;
1851160484Sobrien
1851260484Sobrien#ifdef OBJ_ELF
18513218822Sdim    case BFD_RELOC_ARM_TLS_GD32:
18514218822Sdim    case BFD_RELOC_ARM_TLS_LE32:
18515218822Sdim    case BFD_RELOC_ARM_TLS_IE32:
18516218822Sdim    case BFD_RELOC_ARM_TLS_LDM32:
18517218822Sdim    case BFD_RELOC_ARM_TLS_LDO32:
18518218822Sdim      S_SET_THREAD_LOCAL (fixP->fx_addsy);
18519218822Sdim      /* fall through */
18520218822Sdim
1852160484Sobrien    case BFD_RELOC_ARM_GOT32:
1852260484Sobrien    case BFD_RELOC_ARM_GOTOFF:
18523218822Sdim    case BFD_RELOC_ARM_TARGET2:
18524218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18525218822Sdim	md_number_to_chars (buf, 0, 4);
1852677298Sobrien      break;
1852760484Sobrien#endif
1852860484Sobrien
1852960484Sobrien    case BFD_RELOC_RVA:
1853060484Sobrien    case BFD_RELOC_32:
18531218822Sdim    case BFD_RELOC_ARM_TARGET1:
18532218822Sdim    case BFD_RELOC_ARM_ROSEGREL32:
18533218822Sdim    case BFD_RELOC_ARM_SBREL32:
18534218822Sdim    case BFD_RELOC_32_PCREL:
18535218822Sdim#ifdef TE_PE
18536218822Sdim    case BFD_RELOC_32_SECREL:
18537218822Sdim#endif
18538218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18539218822Sdim#ifdef TE_WINCE
18540218822Sdim	/* For WinCE we only do this for pcrel fixups.  */
18541218822Sdim	if (fixP->fx_done || fixP->fx_pcrel)
18542218822Sdim#endif
1854377298Sobrien	  md_number_to_chars (buf, value, 4);
1854460484Sobrien      break;
1854560484Sobrien
1854660484Sobrien#ifdef OBJ_ELF
18547218822Sdim    case BFD_RELOC_ARM_PREL31:
18548218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18549218822Sdim	{
18550218822Sdim	  newval = md_chars_to_number (buf, 4) & 0x80000000;
18551218822Sdim	  if ((value ^ (value >> 1)) & 0x40000000)
18552218822Sdim	    {
18553218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18554218822Sdim			    _("rel31 relocation overflow"));
18555218822Sdim	    }
18556218822Sdim	  newval |= value & 0x7fffffff;
18557218822Sdim	  md_number_to_chars (buf, newval, 4);
18558218822Sdim	}
1855960484Sobrien      break;
1856060484Sobrien#endif
1856160484Sobrien
1856260484Sobrien    case BFD_RELOC_ARM_CP_OFF_IMM:
18563218822Sdim    case BFD_RELOC_ARM_T32_CP_OFF_IMM:
1856460484Sobrien      if (value < -1023 || value > 1023 || (value & 3))
1856560484Sobrien	as_bad_where (fixP->fx_file, fixP->fx_line,
18566218822Sdim		      _("co-processor offset out of range"));
18567218822Sdim    cp_off_common:
18568218822Sdim      sign = value >= 0;
1856960484Sobrien      if (value < 0)
1857060484Sobrien	value = -value;
18571218822Sdim      if (fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM
18572218822Sdim	  || fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM_S2)
18573218822Sdim	newval = md_chars_to_number (buf, INSN_SIZE);
18574218822Sdim      else
18575218822Sdim	newval = get_thumb32_insn (buf);
18576218822Sdim      newval &= 0xff7fff00;
1857777298Sobrien      newval |= (value >> 2) | (sign ? INDEX_UP : 0);
18578218822Sdim      if (fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM
18579218822Sdim	  || fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM_S2)
18580218822Sdim	md_number_to_chars (buf, newval, INSN_SIZE);
18581218822Sdim      else
18582218822Sdim	put_thumb32_insn (buf, newval);
1858360484Sobrien      break;
1858460484Sobrien
18585130561Sobrien    case BFD_RELOC_ARM_CP_OFF_IMM_S2:
18586218822Sdim    case BFD_RELOC_ARM_T32_CP_OFF_IMM_S2:
18587130561Sobrien      if (value < -255 || value > 255)
18588218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18589218822Sdim		      _("co-processor offset out of range"));
18590218822Sdim      value *= 4;
18591218822Sdim      goto cp_off_common;
18592130561Sobrien
1859360484Sobrien    case BFD_RELOC_ARM_THUMB_OFFSET:
1859460484Sobrien      newval = md_chars_to_number (buf, THUMB_SIZE);
1859577298Sobrien      /* Exactly what ranges, and where the offset is inserted depends
1859677298Sobrien	 on the type of instruction, we can establish this from the
1859777298Sobrien	 top 4 bits.  */
1859860484Sobrien      switch (newval >> 12)
1859960484Sobrien	{
1860077298Sobrien	case 4: /* PC load.  */
1860160484Sobrien	  /* Thumb PC loads are somewhat odd, bit 1 of the PC is
18602218822Sdim	     forced to zero for these loads; md_pcrel_from has already
18603218822Sdim	     compensated for this.  */
18604218822Sdim	  if (value & 3)
1860560484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18606218822Sdim			  _("invalid offset, target not word aligned (0x%08lX)"),
18607218822Sdim			  (((unsigned long) fixP->fx_frag->fr_address
18608218822Sdim			    + (unsigned long) fixP->fx_where) & ~3)
18609218822Sdim			  + (unsigned long) value);
1861060484Sobrien
18611218822Sdim	  if (value & ~0x3fc)
1861260484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18613130561Sobrien			  _("invalid offset, value too big (0x%08lX)"),
18614130561Sobrien			  (long) value);
1861560484Sobrien
18616218822Sdim	  newval |= value >> 2;
1861760484Sobrien	  break;
1861860484Sobrien
1861977298Sobrien	case 9: /* SP load/store.  */
1862060484Sobrien	  if (value & ~0x3fc)
1862160484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18622130561Sobrien			  _("invalid offset, value too big (0x%08lX)"),
18623130561Sobrien			  (long) value);
1862460484Sobrien	  newval |= value >> 2;
1862560484Sobrien	  break;
1862660484Sobrien
1862777298Sobrien	case 6: /* Word load/store.  */
1862860484Sobrien	  if (value & ~0x7c)
1862960484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18630130561Sobrien			  _("invalid offset, value too big (0x%08lX)"),
18631130561Sobrien			  (long) value);
1863277298Sobrien	  newval |= value << 4; /* 6 - 2.  */
1863360484Sobrien	  break;
1863460484Sobrien
1863577298Sobrien	case 7: /* Byte load/store.  */
1863660484Sobrien	  if (value & ~0x1f)
1863760484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18638130561Sobrien			  _("invalid offset, value too big (0x%08lX)"),
18639130561Sobrien			  (long) value);
1864060484Sobrien	  newval |= value << 6;
1864160484Sobrien	  break;
1864260484Sobrien
18643218822Sdim	case 8: /* Halfword load/store.	 */
1864460484Sobrien	  if (value & ~0x3e)
1864560484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18646130561Sobrien			  _("invalid offset, value too big (0x%08lX)"),
18647130561Sobrien			  (long) value);
1864877298Sobrien	  newval |= value << 5; /* 6 - 1.  */
1864960484Sobrien	  break;
1865060484Sobrien
1865160484Sobrien	default:
1865260484Sobrien	  as_bad_where (fixP->fx_file, fixP->fx_line,
1865360484Sobrien			"Unable to process relocation for thumb opcode: %lx",
1865460484Sobrien			(unsigned long) newval);
1865560484Sobrien	  break;
1865660484Sobrien	}
1865760484Sobrien      md_number_to_chars (buf, newval, THUMB_SIZE);
1865860484Sobrien      break;
1865960484Sobrien
1866060484Sobrien    case BFD_RELOC_ARM_THUMB_ADD:
1866160484Sobrien      /* This is a complicated relocation, since we use it for all of
18662218822Sdim	 the following immediate relocations:
1866360484Sobrien
1866477298Sobrien	    3bit ADD/SUB
1866577298Sobrien	    8bit ADD/SUB
1866677298Sobrien	    9bit ADD/SUB SP word-aligned
1866777298Sobrien	   10bit ADD PC/SP word-aligned
1866877298Sobrien
18669218822Sdim	 The type of instruction being processed is encoded in the
18670218822Sdim	 instruction field:
1867177298Sobrien
1867277298Sobrien	   0x8000  SUB
1867377298Sobrien	   0x00F0  Rd
1867477298Sobrien	   0x000F  Rs
1867560484Sobrien      */
1867660484Sobrien      newval = md_chars_to_number (buf, THUMB_SIZE);
1867760484Sobrien      {
1867877298Sobrien	int rd = (newval >> 4) & 0xf;
1867977298Sobrien	int rs = newval & 0xf;
18680218822Sdim	int subtract = !!(newval & 0x8000);
1868160484Sobrien
18682218822Sdim	/* Check for HI regs, only very restricted cases allowed:
18683218822Sdim	   Adjusting SP, and using PC or SP to get an address.	*/
18684218822Sdim	if ((rd > 7 && (rd != REG_SP || rs != REG_SP))
18685218822Sdim	    || (rs > 7 && rs != REG_SP && rs != REG_PC))
18686218822Sdim	  as_bad_where (fixP->fx_file, fixP->fx_line,
18687218822Sdim			_("invalid Hi register with immediate"));
18688218822Sdim
18689218822Sdim	/* If value is negative, choose the opposite instruction.  */
18690218822Sdim	if (value < 0)
18691218822Sdim	  {
18692218822Sdim	    value = -value;
18693218822Sdim	    subtract = !subtract;
18694218822Sdim	    if (value < 0)
18695218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18696218822Sdim			    _("immediate value out of range"));
18697218822Sdim	  }
18698218822Sdim
1869977298Sobrien	if (rd == REG_SP)
1870077298Sobrien	  {
1870177298Sobrien	    if (value & ~0x1fc)
1870277298Sobrien	      as_bad_where (fixP->fx_file, fixP->fx_line,
1870389857Sobrien			    _("invalid immediate for stack address calculation"));
1870477298Sobrien	    newval = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
1870577298Sobrien	    newval |= value >> 2;
1870677298Sobrien	  }
1870777298Sobrien	else if (rs == REG_PC || rs == REG_SP)
1870877298Sobrien	  {
18709218822Sdim	    if (subtract || value & ~0x3fc)
1871077298Sobrien	      as_bad_where (fixP->fx_file, fixP->fx_line,
1871189857Sobrien			    _("invalid immediate for address calculation (value = 0x%08lX)"),
1871260484Sobrien			    (unsigned long) value);
1871377298Sobrien	    newval = (rs == REG_PC ? T_OPCODE_ADD_PC : T_OPCODE_ADD_SP);
1871477298Sobrien	    newval |= rd << 8;
1871577298Sobrien	    newval |= value >> 2;
1871677298Sobrien	  }
1871777298Sobrien	else if (rs == rd)
1871877298Sobrien	  {
1871977298Sobrien	    if (value & ~0xff)
1872077298Sobrien	      as_bad_where (fixP->fx_file, fixP->fx_line,
18721218822Sdim			    _("immediate value out of range"));
1872277298Sobrien	    newval = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8;
1872377298Sobrien	    newval |= (rd << 8) | value;
1872477298Sobrien	  }
1872577298Sobrien	else
1872677298Sobrien	  {
1872777298Sobrien	    if (value & ~0x7)
1872877298Sobrien	      as_bad_where (fixP->fx_file, fixP->fx_line,
18729218822Sdim			    _("immediate value out of range"));
1873077298Sobrien	    newval = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
1873177298Sobrien	    newval |= rd | (rs << 3) | (value << 6);
1873277298Sobrien	  }
1873360484Sobrien      }
1873477298Sobrien      md_number_to_chars (buf, newval, THUMB_SIZE);
1873560484Sobrien      break;
1873660484Sobrien
1873760484Sobrien    case BFD_RELOC_ARM_THUMB_IMM:
1873860484Sobrien      newval = md_chars_to_number (buf, THUMB_SIZE);
18739218822Sdim      if (value < 0 || value > 255)
18740218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18741218822Sdim		      _("invalid immediate: %ld is too large"),
18742218822Sdim		      (long) value);
18743218822Sdim      newval |= value;
1874477298Sobrien      md_number_to_chars (buf, newval, THUMB_SIZE);
1874560484Sobrien      break;
1874660484Sobrien
1874760484Sobrien    case BFD_RELOC_ARM_THUMB_SHIFT:
18748218822Sdim      /* 5bit shift value (0..32).  LSL cannot take 32.	 */
18749218822Sdim      newval = md_chars_to_number (buf, THUMB_SIZE) & 0xf83f;
18750218822Sdim      temp = newval & 0xf800;
18751218822Sdim      if (value < 0 || value > 32 || (value == 32 && temp == T_OPCODE_LSL_I))
1875260484Sobrien	as_bad_where (fixP->fx_file, fixP->fx_line,
18753218822Sdim		      _("invalid shift value: %ld"), (long) value);
18754218822Sdim      /* Shifts of zero must be encoded as LSL.	 */
18755218822Sdim      if (value == 0)
18756218822Sdim	newval = (newval & 0x003f) | T_OPCODE_LSL_I;
18757218822Sdim      /* Shifts of 32 are encoded as zero.  */
18758218822Sdim      else if (value == 32)
18759218822Sdim	value = 0;
1876060484Sobrien      newval |= value << 6;
1876177298Sobrien      md_number_to_chars (buf, newval, THUMB_SIZE);
1876260484Sobrien      break;
1876360484Sobrien
1876460484Sobrien    case BFD_RELOC_VTABLE_INHERIT:
1876560484Sobrien    case BFD_RELOC_VTABLE_ENTRY:
1876660484Sobrien      fixP->fx_done = 0;
1876789857Sobrien      return;
1876860484Sobrien
18769218822Sdim    case BFD_RELOC_ARM_MOVW:
18770218822Sdim    case BFD_RELOC_ARM_MOVT:
18771218822Sdim    case BFD_RELOC_ARM_THUMB_MOVW:
18772218822Sdim    case BFD_RELOC_ARM_THUMB_MOVT:
18773218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18774218822Sdim	{
18775218822Sdim	  /* REL format relocations are limited to a 16-bit addend.  */
18776218822Sdim	  if (!fixP->fx_done)
18777218822Sdim	    {
18778218822Sdim	      if (value < -0x1000 || value > 0xffff)
18779218822Sdim		  as_bad_where (fixP->fx_file, fixP->fx_line,
18780218822Sdim				_("offset too big"));
18781218822Sdim	    }
18782218822Sdim	  else if (fixP->fx_r_type == BFD_RELOC_ARM_MOVT
18783218822Sdim		   || fixP->fx_r_type == BFD_RELOC_ARM_THUMB_MOVT)
18784218822Sdim	    {
18785218822Sdim	      value >>= 16;
18786218822Sdim	    }
18787218822Sdim
18788218822Sdim	  if (fixP->fx_r_type == BFD_RELOC_ARM_THUMB_MOVW
18789218822Sdim	      || fixP->fx_r_type == BFD_RELOC_ARM_THUMB_MOVT)
18790218822Sdim	    {
18791218822Sdim	      newval = get_thumb32_insn (buf);
18792218822Sdim	      newval &= 0xfbf08f00;
18793218822Sdim	      newval |= (value & 0xf000) << 4;
18794218822Sdim	      newval |= (value & 0x0800) << 15;
18795218822Sdim	      newval |= (value & 0x0700) << 4;
18796218822Sdim	      newval |= (value & 0x00ff);
18797218822Sdim	      put_thumb32_insn (buf, newval);
18798218822Sdim	    }
18799218822Sdim	  else
18800218822Sdim	    {
18801218822Sdim	      newval = md_chars_to_number (buf, 4);
18802218822Sdim	      newval &= 0xfff0f000;
18803218822Sdim	      newval |= value & 0x0fff;
18804218822Sdim	      newval |= (value & 0xf000) << 4;
18805218822Sdim	      md_number_to_chars (buf, newval, 4);
18806218822Sdim	    }
18807218822Sdim	}
18808218822Sdim      return;
18809218822Sdim
18810218822Sdim   case BFD_RELOC_ARM_ALU_PC_G0_NC:
18811218822Sdim   case BFD_RELOC_ARM_ALU_PC_G0:
18812218822Sdim   case BFD_RELOC_ARM_ALU_PC_G1_NC:
18813218822Sdim   case BFD_RELOC_ARM_ALU_PC_G1:
18814218822Sdim   case BFD_RELOC_ARM_ALU_PC_G2:
18815218822Sdim   case BFD_RELOC_ARM_ALU_SB_G0_NC:
18816218822Sdim   case BFD_RELOC_ARM_ALU_SB_G0:
18817218822Sdim   case BFD_RELOC_ARM_ALU_SB_G1_NC:
18818218822Sdim   case BFD_RELOC_ARM_ALU_SB_G1:
18819218822Sdim   case BFD_RELOC_ARM_ALU_SB_G2:
18820218822Sdim     assert (!fixP->fx_done);
18821218822Sdim     if (!seg->use_rela_p)
18822218822Sdim       {
18823218822Sdim         bfd_vma insn;
18824218822Sdim         bfd_vma encoded_addend;
18825218822Sdim         bfd_vma addend_abs = abs (value);
18826218822Sdim
18827218822Sdim         /* Check that the absolute value of the addend can be
18828218822Sdim            expressed as an 8-bit constant plus a rotation.  */
18829218822Sdim         encoded_addend = encode_arm_immediate (addend_abs);
18830218822Sdim         if (encoded_addend == (unsigned int) FAIL)
18831218822Sdim	   as_bad_where (fixP->fx_file, fixP->fx_line,
18832218822Sdim	                 _("the offset 0x%08lX is not representable"),
18833218822Sdim                         (unsigned long) addend_abs);
18834218822Sdim
18835218822Sdim         /* Extract the instruction.  */
18836218822Sdim         insn = md_chars_to_number (buf, INSN_SIZE);
18837218822Sdim
18838218822Sdim         /* If the addend is positive, use an ADD instruction.
18839218822Sdim            Otherwise use a SUB.  Take care not to destroy the S bit.  */
18840218822Sdim         insn &= 0xff1fffff;
18841218822Sdim         if (value < 0)
18842218822Sdim           insn |= 1 << 22;
18843218822Sdim         else
18844218822Sdim           insn |= 1 << 23;
18845218822Sdim
18846218822Sdim         /* Place the encoded addend into the first 12 bits of the
18847218822Sdim            instruction.  */
18848218822Sdim         insn &= 0xfffff000;
18849218822Sdim         insn |= encoded_addend;
18850218822Sdim
18851218822Sdim         /* Update the instruction.  */
18852218822Sdim         md_number_to_chars (buf, insn, INSN_SIZE);
18853218822Sdim       }
18854218822Sdim     break;
18855218822Sdim
18856218822Sdim    case BFD_RELOC_ARM_LDR_PC_G0:
18857218822Sdim    case BFD_RELOC_ARM_LDR_PC_G1:
18858218822Sdim    case BFD_RELOC_ARM_LDR_PC_G2:
18859218822Sdim    case BFD_RELOC_ARM_LDR_SB_G0:
18860218822Sdim    case BFD_RELOC_ARM_LDR_SB_G1:
18861218822Sdim    case BFD_RELOC_ARM_LDR_SB_G2:
18862218822Sdim      assert (!fixP->fx_done);
18863218822Sdim      if (!seg->use_rela_p)
18864218822Sdim        {
18865218822Sdim          bfd_vma insn;
18866218822Sdim          bfd_vma addend_abs = abs (value);
18867218822Sdim
18868218822Sdim          /* Check that the absolute value of the addend can be
18869218822Sdim             encoded in 12 bits.  */
18870218822Sdim          if (addend_abs >= 0x1000)
18871218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
18872218822Sdim	  	          _("bad offset 0x%08lX (only 12 bits available for the magnitude)"),
18873218822Sdim                          (unsigned long) addend_abs);
18874218822Sdim
18875218822Sdim          /* Extract the instruction.  */
18876218822Sdim          insn = md_chars_to_number (buf, INSN_SIZE);
18877218822Sdim
18878218822Sdim          /* If the addend is negative, clear bit 23 of the instruction.
18879218822Sdim             Otherwise set it.  */
18880218822Sdim          if (value < 0)
18881218822Sdim            insn &= ~(1 << 23);
18882218822Sdim          else
18883218822Sdim            insn |= 1 << 23;
18884218822Sdim
18885218822Sdim          /* Place the absolute value of the addend into the first 12 bits
18886218822Sdim             of the instruction.  */
18887218822Sdim          insn &= 0xfffff000;
18888218822Sdim          insn |= addend_abs;
18889218822Sdim
18890218822Sdim          /* Update the instruction.  */
18891218822Sdim          md_number_to_chars (buf, insn, INSN_SIZE);
18892218822Sdim        }
18893218822Sdim      break;
18894218822Sdim
18895218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G0:
18896218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G1:
18897218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G2:
18898218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G0:
18899218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G1:
18900218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G2:
18901218822Sdim      assert (!fixP->fx_done);
18902218822Sdim      if (!seg->use_rela_p)
18903218822Sdim        {
18904218822Sdim          bfd_vma insn;
18905218822Sdim          bfd_vma addend_abs = abs (value);
18906218822Sdim
18907218822Sdim          /* Check that the absolute value of the addend can be
18908218822Sdim             encoded in 8 bits.  */
18909218822Sdim          if (addend_abs >= 0x100)
18910218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
18911218822Sdim	  	          _("bad offset 0x%08lX (only 8 bits available for the magnitude)"),
18912218822Sdim                          (unsigned long) addend_abs);
18913218822Sdim
18914218822Sdim          /* Extract the instruction.  */
18915218822Sdim          insn = md_chars_to_number (buf, INSN_SIZE);
18916218822Sdim
18917218822Sdim          /* If the addend is negative, clear bit 23 of the instruction.
18918218822Sdim             Otherwise set it.  */
18919218822Sdim          if (value < 0)
18920218822Sdim            insn &= ~(1 << 23);
18921218822Sdim          else
18922218822Sdim            insn |= 1 << 23;
18923218822Sdim
18924218822Sdim          /* Place the first four bits of the absolute value of the addend
18925218822Sdim             into the first 4 bits of the instruction, and the remaining
18926218822Sdim             four into bits 8 .. 11.  */
18927218822Sdim          insn &= 0xfffff0f0;
18928218822Sdim          insn |= (addend_abs & 0xf) | ((addend_abs & 0xf0) << 4);
18929218822Sdim
18930218822Sdim          /* Update the instruction.  */
18931218822Sdim          md_number_to_chars (buf, insn, INSN_SIZE);
18932218822Sdim        }
18933218822Sdim      break;
18934218822Sdim
18935218822Sdim    case BFD_RELOC_ARM_LDC_PC_G0:
18936218822Sdim    case BFD_RELOC_ARM_LDC_PC_G1:
18937218822Sdim    case BFD_RELOC_ARM_LDC_PC_G2:
18938218822Sdim    case BFD_RELOC_ARM_LDC_SB_G0:
18939218822Sdim    case BFD_RELOC_ARM_LDC_SB_G1:
18940218822Sdim    case BFD_RELOC_ARM_LDC_SB_G2:
18941218822Sdim      assert (!fixP->fx_done);
18942218822Sdim      if (!seg->use_rela_p)
18943218822Sdim        {
18944218822Sdim          bfd_vma insn;
18945218822Sdim          bfd_vma addend_abs = abs (value);
18946218822Sdim
18947218822Sdim          /* Check that the absolute value of the addend is a multiple of
18948218822Sdim             four and, when divided by four, fits in 8 bits.  */
18949218822Sdim          if (addend_abs & 0x3)
18950218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
18951218822Sdim	  	          _("bad offset 0x%08lX (must be word-aligned)"),
18952218822Sdim                          (unsigned long) addend_abs);
18953218822Sdim
18954218822Sdim          if ((addend_abs >> 2) > 0xff)
18955218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
18956218822Sdim	  	          _("bad offset 0x%08lX (must be an 8-bit number of words)"),
18957218822Sdim                          (unsigned long) addend_abs);
18958218822Sdim
18959218822Sdim          /* Extract the instruction.  */
18960218822Sdim          insn = md_chars_to_number (buf, INSN_SIZE);
18961218822Sdim
18962218822Sdim          /* If the addend is negative, clear bit 23 of the instruction.
18963218822Sdim             Otherwise set it.  */
18964218822Sdim          if (value < 0)
18965218822Sdim            insn &= ~(1 << 23);
18966218822Sdim          else
18967218822Sdim            insn |= 1 << 23;
18968218822Sdim
18969218822Sdim          /* Place the addend (divided by four) into the first eight
18970218822Sdim             bits of the instruction.  */
18971218822Sdim          insn &= 0xfffffff0;
18972218822Sdim          insn |= addend_abs >> 2;
18973218822Sdim
18974218822Sdim          /* Update the instruction.  */
18975218822Sdim          md_number_to_chars (buf, insn, INSN_SIZE);
18976218822Sdim        }
18977218822Sdim      break;
18978218822Sdim
18979218822Sdim    case BFD_RELOC_UNUSED:
1898060484Sobrien    default:
1898160484Sobrien      as_bad_where (fixP->fx_file, fixP->fx_line,
1898289857Sobrien		    _("bad relocation fixup type (%d)"), fixP->fx_r_type);
1898360484Sobrien    }
1898460484Sobrien}
1898560484Sobrien
1898660484Sobrien/* Translate internal representation of relocation info to BFD target
1898760484Sobrien   format.  */
1898877298Sobrien
1898960484Sobrienarelent *
18990218822Sdimtc_gen_reloc (asection *section, fixS *fixp)
1899160484Sobrien{
1899260484Sobrien  arelent * reloc;
1899360484Sobrien  bfd_reloc_code_real_type code;
1899460484Sobrien
18995218822Sdim  reloc = xmalloc (sizeof (arelent));
1899660484Sobrien
18997218822Sdim  reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
1899860484Sobrien  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
1899960484Sobrien  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
1900060484Sobrien
19001218822Sdim  if (fixp->fx_pcrel)
19002218822Sdim    {
19003218822Sdim      if (section->use_rela_p)
19004218822Sdim	fixp->fx_offset -= md_pcrel_from_section (fixp, section);
19005218822Sdim      else
19006218822Sdim	fixp->fx_offset = reloc->address;
19007218822Sdim    }
1900860484Sobrien  reloc->addend = fixp->fx_offset;
1900960484Sobrien
1901060484Sobrien  switch (fixp->fx_r_type)
1901160484Sobrien    {
1901260484Sobrien    case BFD_RELOC_8:
1901360484Sobrien      if (fixp->fx_pcrel)
1901460484Sobrien	{
1901560484Sobrien	  code = BFD_RELOC_8_PCREL;
1901660484Sobrien	  break;
1901760484Sobrien	}
1901860484Sobrien
1901960484Sobrien    case BFD_RELOC_16:
1902060484Sobrien      if (fixp->fx_pcrel)
1902160484Sobrien	{
1902260484Sobrien	  code = BFD_RELOC_16_PCREL;
1902360484Sobrien	  break;
1902460484Sobrien	}
1902560484Sobrien
1902660484Sobrien    case BFD_RELOC_32:
1902760484Sobrien      if (fixp->fx_pcrel)
1902860484Sobrien	{
1902960484Sobrien	  code = BFD_RELOC_32_PCREL;
1903060484Sobrien	  break;
1903160484Sobrien	}
1903260484Sobrien
19033218822Sdim    case BFD_RELOC_ARM_MOVW:
19034218822Sdim      if (fixp->fx_pcrel)
19035218822Sdim	{
19036218822Sdim	  code = BFD_RELOC_ARM_MOVW_PCREL;
19037218822Sdim	  break;
19038218822Sdim	}
19039218822Sdim
19040218822Sdim    case BFD_RELOC_ARM_MOVT:
19041218822Sdim      if (fixp->fx_pcrel)
19042218822Sdim	{
19043218822Sdim	  code = BFD_RELOC_ARM_MOVT_PCREL;
19044218822Sdim	  break;
19045218822Sdim	}
19046218822Sdim
19047218822Sdim    case BFD_RELOC_ARM_THUMB_MOVW:
19048218822Sdim      if (fixp->fx_pcrel)
19049218822Sdim	{
19050218822Sdim	  code = BFD_RELOC_ARM_THUMB_MOVW_PCREL;
19051218822Sdim	  break;
19052218822Sdim	}
19053218822Sdim
19054218822Sdim    case BFD_RELOC_ARM_THUMB_MOVT:
19055218822Sdim      if (fixp->fx_pcrel)
19056218822Sdim	{
19057218822Sdim	  code = BFD_RELOC_ARM_THUMB_MOVT_PCREL;
19058218822Sdim	  break;
19059218822Sdim	}
19060218822Sdim
19061218822Sdim    case BFD_RELOC_NONE:
1906260484Sobrien    case BFD_RELOC_ARM_PCREL_BRANCH:
1906377298Sobrien    case BFD_RELOC_ARM_PCREL_BLX:
1906477298Sobrien    case BFD_RELOC_RVA:
19065218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH7:
1906660484Sobrien    case BFD_RELOC_THUMB_PCREL_BRANCH9:
1906760484Sobrien    case BFD_RELOC_THUMB_PCREL_BRANCH12:
19068218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH20:
1906960484Sobrien    case BFD_RELOC_THUMB_PCREL_BRANCH23:
19070218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH25:
1907177298Sobrien    case BFD_RELOC_THUMB_PCREL_BLX:
1907260484Sobrien    case BFD_RELOC_VTABLE_ENTRY:
1907360484Sobrien    case BFD_RELOC_VTABLE_INHERIT:
19074218822Sdim#ifdef TE_PE
19075218822Sdim    case BFD_RELOC_32_SECREL:
19076218822Sdim#endif
1907760484Sobrien      code = fixp->fx_r_type;
1907860484Sobrien      break;
1907960484Sobrien
1908060484Sobrien    case BFD_RELOC_ARM_LITERAL:
1908160484Sobrien    case BFD_RELOC_ARM_HWLITERAL:
19082130561Sobrien      /* If this is called then the a literal has
19083130561Sobrien	 been referenced across a section boundary.  */
1908460484Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
19085130561Sobrien		    _("literal referenced across section boundary"));
1908660484Sobrien      return NULL;
1908760484Sobrien
1908860484Sobrien#ifdef OBJ_ELF
1908960484Sobrien    case BFD_RELOC_ARM_GOT32:
1909060484Sobrien    case BFD_RELOC_ARM_GOTOFF:
1909160484Sobrien    case BFD_RELOC_ARM_PLT32:
19092218822Sdim    case BFD_RELOC_ARM_TARGET1:
19093218822Sdim    case BFD_RELOC_ARM_ROSEGREL32:
19094218822Sdim    case BFD_RELOC_ARM_SBREL32:
19095218822Sdim    case BFD_RELOC_ARM_PREL31:
19096218822Sdim    case BFD_RELOC_ARM_TARGET2:
19097218822Sdim    case BFD_RELOC_ARM_TLS_LE32:
19098218822Sdim    case BFD_RELOC_ARM_TLS_LDO32:
19099218822Sdim    case BFD_RELOC_ARM_PCREL_CALL:
19100218822Sdim    case BFD_RELOC_ARM_PCREL_JUMP:
19101218822Sdim    case BFD_RELOC_ARM_ALU_PC_G0_NC:
19102218822Sdim    case BFD_RELOC_ARM_ALU_PC_G0:
19103218822Sdim    case BFD_RELOC_ARM_ALU_PC_G1_NC:
19104218822Sdim    case BFD_RELOC_ARM_ALU_PC_G1:
19105218822Sdim    case BFD_RELOC_ARM_ALU_PC_G2:
19106218822Sdim    case BFD_RELOC_ARM_LDR_PC_G0:
19107218822Sdim    case BFD_RELOC_ARM_LDR_PC_G1:
19108218822Sdim    case BFD_RELOC_ARM_LDR_PC_G2:
19109218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G0:
19110218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G1:
19111218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G2:
19112218822Sdim    case BFD_RELOC_ARM_LDC_PC_G0:
19113218822Sdim    case BFD_RELOC_ARM_LDC_PC_G1:
19114218822Sdim    case BFD_RELOC_ARM_LDC_PC_G2:
19115218822Sdim    case BFD_RELOC_ARM_ALU_SB_G0_NC:
19116218822Sdim    case BFD_RELOC_ARM_ALU_SB_G0:
19117218822Sdim    case BFD_RELOC_ARM_ALU_SB_G1_NC:
19118218822Sdim    case BFD_RELOC_ARM_ALU_SB_G1:
19119218822Sdim    case BFD_RELOC_ARM_ALU_SB_G2:
19120218822Sdim    case BFD_RELOC_ARM_LDR_SB_G0:
19121218822Sdim    case BFD_RELOC_ARM_LDR_SB_G1:
19122218822Sdim    case BFD_RELOC_ARM_LDR_SB_G2:
19123218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G0:
19124218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G1:
19125218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G2:
19126218822Sdim    case BFD_RELOC_ARM_LDC_SB_G0:
19127218822Sdim    case BFD_RELOC_ARM_LDC_SB_G1:
19128218822Sdim    case BFD_RELOC_ARM_LDC_SB_G2:
1912977298Sobrien      code = fixp->fx_r_type;
1913077298Sobrien      break;
19131218822Sdim
19132218822Sdim    case BFD_RELOC_ARM_TLS_GD32:
19133218822Sdim    case BFD_RELOC_ARM_TLS_IE32:
19134218822Sdim    case BFD_RELOC_ARM_TLS_LDM32:
19135218822Sdim      /* BFD will include the symbol's address in the addend.
19136218822Sdim	 But we don't want that, so subtract it out again here.  */
19137218822Sdim      if (!S_IS_COMMON (fixp->fx_addsy))
19138218822Sdim	reloc->addend -= (*reloc->sym_ptr_ptr)->value;
19139218822Sdim      code = fixp->fx_r_type;
19140218822Sdim      break;
1914160484Sobrien#endif
1914260484Sobrien
1914360484Sobrien    case BFD_RELOC_ARM_IMMEDIATE:
1914460484Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
19145130561Sobrien		    _("internal relocation (type: IMMEDIATE) not fixed up"));
1914660484Sobrien      return NULL;
1914760484Sobrien
1914860484Sobrien    case BFD_RELOC_ARM_ADRL_IMMEDIATE:
1914960484Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
1915077298Sobrien		    _("ADRL used for a symbol not defined in the same file"));
1915160484Sobrien      return NULL;
1915260484Sobrien
1915360484Sobrien    case BFD_RELOC_ARM_OFFSET_IMM:
19154218822Sdim      if (section->use_rela_p)
19155218822Sdim	{
19156218822Sdim	  code = fixp->fx_r_type;
19157218822Sdim	  break;
19158218822Sdim	}
19159218822Sdim
19160130561Sobrien      if (fixp->fx_addsy != NULL
19161130561Sobrien	  && !S_IS_DEFINED (fixp->fx_addsy)
19162130561Sobrien	  && S_IS_LOCAL (fixp->fx_addsy))
19163130561Sobrien	{
19164130561Sobrien	  as_bad_where (fixp->fx_file, fixp->fx_line,
19165130561Sobrien			_("undefined local label `%s'"),
19166130561Sobrien			S_GET_NAME (fixp->fx_addsy));
19167130561Sobrien	  return NULL;
19168130561Sobrien	}
19169130561Sobrien
1917060484Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
19171130561Sobrien		    _("internal_relocation (type: OFFSET_IMM) not fixed up"));
1917260484Sobrien      return NULL;
1917360484Sobrien
1917460484Sobrien    default:
1917560484Sobrien      {
1917660484Sobrien	char * type;
1917777298Sobrien
1917860484Sobrien	switch (fixp->fx_r_type)
1917960484Sobrien	  {
19180218822Sdim	  case BFD_RELOC_NONE:		   type = "NONE";	  break;
1918160484Sobrien	  case BFD_RELOC_ARM_OFFSET_IMM8:  type = "OFFSET_IMM8";  break;
19182218822Sdim	  case BFD_RELOC_ARM_SHIFT_IMM:	   type = "SHIFT_IMM";	  break;
19183218822Sdim	  case BFD_RELOC_ARM_SMC:	   type = "SMC";	  break;
19184218822Sdim	  case BFD_RELOC_ARM_SWI:	   type = "SWI";	  break;
19185218822Sdim	  case BFD_RELOC_ARM_MULTI:	   type = "MULTI";	  break;
19186218822Sdim	  case BFD_RELOC_ARM_CP_OFF_IMM:   type = "CP_OFF_IMM";	  break;
19187218822Sdim	  case BFD_RELOC_ARM_T32_CP_OFF_IMM: type = "T32_CP_OFF_IMM"; break;
19188218822Sdim	  case BFD_RELOC_ARM_THUMB_ADD:	   type = "THUMB_ADD";	  break;
1918960484Sobrien	  case BFD_RELOC_ARM_THUMB_SHIFT:  type = "THUMB_SHIFT";  break;
19190218822Sdim	  case BFD_RELOC_ARM_THUMB_IMM:	   type = "THUMB_IMM";	  break;
1919160484Sobrien	  case BFD_RELOC_ARM_THUMB_OFFSET: type = "THUMB_OFFSET"; break;
19192218822Sdim	  default:			   type = _("<unknown>"); break;
1919360484Sobrien	  }
1919460484Sobrien	as_bad_where (fixp->fx_file, fixp->fx_line,
1919589857Sobrien		      _("cannot represent %s relocation in this object file format"),
1919677298Sobrien		      type);
1919760484Sobrien	return NULL;
1919860484Sobrien      }
1919960484Sobrien    }
1920060484Sobrien
1920160484Sobrien#ifdef OBJ_ELF
19202130561Sobrien  if ((code == BFD_RELOC_32_PCREL || code == BFD_RELOC_32)
1920377298Sobrien      && GOT_symbol
1920477298Sobrien      && fixp->fx_addsy == GOT_symbol)
1920577298Sobrien    {
1920677298Sobrien      code = BFD_RELOC_ARM_GOTPC;
1920777298Sobrien      reloc->addend = fixp->fx_offset = reloc->address;
1920877298Sobrien    }
1920960484Sobrien#endif
1921077298Sobrien
1921160484Sobrien  reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
1921260484Sobrien
1921360484Sobrien  if (reloc->howto == NULL)
1921460484Sobrien    {
1921560484Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
1921689857Sobrien		    _("cannot represent %s relocation in this object file format"),
1921760484Sobrien		    bfd_get_reloc_code_name (code));
1921860484Sobrien      return NULL;
1921960484Sobrien    }
1922060484Sobrien
1922177298Sobrien  /* HACK: Since arm ELF uses Rel instead of Rela, encode the
1922277298Sobrien     vtable entry to be used in the relocation's section offset.  */
1922377298Sobrien  if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
1922477298Sobrien    reloc->address = fixp->fx_offset;
1922560484Sobrien
1922660484Sobrien  return reloc;
1922760484Sobrien}
1922860484Sobrien
19229218822Sdim/* This fix_new is called by cons via TC_CONS_FIX_NEW.	*/
1923060484Sobrien
19231218822Sdimvoid
19232218822Sdimcons_fix_new_arm (fragS *	frag,
19233218822Sdim		  int		where,
19234218822Sdim		  int		size,
19235218822Sdim		  expressionS * exp)
1923660484Sobrien{
19237218822Sdim  bfd_reloc_code_real_type type;
19238218822Sdim  int pcrel = 0;
1923977298Sobrien
19240218822Sdim  /* Pick a reloc.
19241218822Sdim     FIXME: @@ Should look at CPU word size.  */
19242218822Sdim  switch (size)
1924360484Sobrien    {
19244218822Sdim    case 1:
19245218822Sdim      type = BFD_RELOC_8;
19246218822Sdim      break;
19247218822Sdim    case 2:
19248218822Sdim      type = BFD_RELOC_16;
19249218822Sdim      break;
19250218822Sdim    case 4:
19251218822Sdim    default:
19252218822Sdim      type = BFD_RELOC_32;
19253218822Sdim      break;
19254218822Sdim    case 8:
19255218822Sdim      type = BFD_RELOC_64;
19256218822Sdim      break;
1925760484Sobrien    }
1925860484Sobrien
19259218822Sdim#ifdef TE_PE
19260218822Sdim  if (exp->X_op == O_secrel)
19261218822Sdim  {
19262218822Sdim    exp->X_op = O_symbol;
19263218822Sdim    type = BFD_RELOC_32_SECREL;
19264218822Sdim  }
19265218822Sdim#endif
1926677298Sobrien
19267218822Sdim  fix_new_exp (frag, where, (int) size, exp, pcrel, type);
19268218822Sdim}
19269218822Sdim
19270218822Sdim#if defined OBJ_COFF || defined OBJ_ELF
19271218822Sdimvoid
19272218822Sdimarm_validate_fix (fixS * fixP)
19273218822Sdim{
19274218822Sdim  /* If the destination of the branch is a defined symbol which does not have
19275218822Sdim     the THUMB_FUNC attribute, then we must be calling a function which has
19276218822Sdim     the (interfacearm) attribute.  We look for the Thumb entry point to that
19277218822Sdim     function and change the branch to refer to that function instead.	*/
19278218822Sdim  if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23
19279218822Sdim      && fixP->fx_addsy != NULL
19280218822Sdim      && S_IS_DEFINED (fixP->fx_addsy)
19281218822Sdim      && ! THUMB_IS_FUNC (fixP->fx_addsy))
1928260484Sobrien    {
19283218822Sdim      fixP->fx_addsy = find_real_start (fixP->fx_addsy);
1928460484Sobrien    }
19285218822Sdim}
19286218822Sdim#endif
1928760484Sobrien
19288218822Sdimint
19289218822Sdimarm_force_relocation (struct fix * fixp)
19290218822Sdim{
19291218822Sdim#if defined (OBJ_COFF) && defined (TE_PE)
19292218822Sdim  if (fixp->fx_r_type == BFD_RELOC_RVA)
19293218822Sdim    return 1;
19294218822Sdim#endif
1929560484Sobrien
19296218822Sdim  /* Resolve these relocations even if the symbol is extern or weak.  */
19297218822Sdim  if (fixp->fx_r_type == BFD_RELOC_ARM_IMMEDIATE
19298218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_OFFSET_IMM
19299218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE
19300218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM
19301218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_T32_IMMEDIATE
19302218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_T32_IMM12
19303218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_T32_ADD_PC12)
19304218822Sdim    return 0;
19305218822Sdim
19306218822Sdim  /* Always leave these relocations for the linker.  */
19307218822Sdim  if ((fixp->fx_r_type >= BFD_RELOC_ARM_ALU_PC_G0_NC
19308218822Sdim       && fixp->fx_r_type <= BFD_RELOC_ARM_LDC_SB_G2)
19309218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_LDR_PC_G0)
19310218822Sdim    return 1;
19311218822Sdim
19312218822Sdim  /* Always generate relocations against function symbols.  */
19313218822Sdim  if (fixp->fx_r_type == BFD_RELOC_32
19314218822Sdim      && fixp->fx_addsy
19315218822Sdim      && (symbol_get_bfdsym (fixp->fx_addsy)->flags & BSF_FUNCTION))
19316218822Sdim    return 1;
19317218822Sdim
19318218822Sdim  return generic_force_reloc (fixp);
19319218822Sdim}
19320218822Sdim
19321218822Sdim#if defined (OBJ_ELF) || defined (OBJ_COFF)
19322218822Sdim/* Relocations against function names must be left unadjusted,
19323218822Sdim   so that the linker can use this information to generate interworking
19324218822Sdim   stubs.  The MIPS version of this function
19325218822Sdim   also prevents relocations that are mips-16 specific, but I do not
19326218822Sdim   know why it does this.
19327218822Sdim
19328218822Sdim   FIXME:
19329218822Sdim   There is one other problem that ought to be addressed here, but
19330218822Sdim   which currently is not:  Taking the address of a label (rather
19331218822Sdim   than a function) and then later jumping to that address.  Such
19332218822Sdim   addresses also ought to have their bottom bit set (assuming that
19333218822Sdim   they reside in Thumb code), but at the moment they will not.	 */
19334218822Sdim
19335218822Sdimbfd_boolean
19336218822Sdimarm_fix_adjustable (fixS * fixP)
19337218822Sdim{
19338218822Sdim  if (fixP->fx_addsy == NULL)
19339218822Sdim    return 1;
19340218822Sdim
19341218822Sdim  /* Preserve relocations against symbols with function type.  */
19342218822Sdim  if (symbol_get_bfdsym (fixP->fx_addsy)->flags & BSF_FUNCTION)
19343218822Sdim    return 0;
19344218822Sdim
19345218822Sdim  if (THUMB_IS_FUNC (fixP->fx_addsy)
19346218822Sdim      && fixP->fx_subsy == NULL)
19347218822Sdim    return 0;
19348218822Sdim
19349218822Sdim  /* We need the symbol name for the VTABLE entries.  */
19350218822Sdim  if (	 fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
19351218822Sdim      || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
19352218822Sdim    return 0;
19353218822Sdim
19354218822Sdim  /* Don't allow symbols to be discarded on GOT related relocs.	 */
19355218822Sdim  if (fixP->fx_r_type == BFD_RELOC_ARM_PLT32
19356218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_GOT32
19357218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_GOTOFF
19358218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_GD32
19359218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LE32
19360218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_IE32
19361218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDM32
19362218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDO32
19363218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TARGET2)
19364218822Sdim    return 0;
19365218822Sdim
19366218822Sdim  /* Similarly for group relocations.  */
19367218822Sdim  if ((fixP->fx_r_type >= BFD_RELOC_ARM_ALU_PC_G0_NC
19368218822Sdim       && fixP->fx_r_type <= BFD_RELOC_ARM_LDC_SB_G2)
19369218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_LDR_PC_G0)
19370218822Sdim    return 0;
19371218822Sdim
19372218822Sdim  return 1;
19373218822Sdim}
19374218822Sdim#endif /* defined (OBJ_ELF) || defined (OBJ_COFF) */
19375218822Sdim
1937677298Sobrien#ifdef OBJ_ELF
19377218822Sdim
19378218822Sdimconst char *
19379218822Sdimelf32_arm_target_format (void)
19380218822Sdim{
19381218822Sdim#ifdef TE_SYMBIAN
19382218822Sdim  return (target_big_endian
19383218822Sdim	  ? "elf32-bigarm-symbian"
19384218822Sdim	  : "elf32-littlearm-symbian");
19385218822Sdim#elif defined (TE_VXWORKS)
19386218822Sdim  return (target_big_endian
19387218822Sdim	  ? "elf32-bigarm-vxworks"
19388218822Sdim	  : "elf32-littlearm-vxworks");
19389218822Sdim#else
19390218822Sdim  if (target_big_endian)
19391218822Sdim    return "elf32-bigarm";
19392218822Sdim  else
19393218822Sdim    return "elf32-littlearm";
1939477298Sobrien#endif
1939560484Sobrien}
1939660484Sobrien
1939760484Sobrienvoid
19398218822Sdimarmelf_frob_symbol (symbolS * symp,
19399218822Sdim		    int *     puntp)
1940060484Sobrien{
19401218822Sdim  elf_frob_symbol (symp, puntp);
19402218822Sdim}
1940377298Sobrien#endif
1940460484Sobrien
19405218822Sdim/* MD interface: Finalization.	*/
1940660484Sobrien
19407218822Sdim/* A good place to do this, although this was probably not intended
19408218822Sdim   for this kind of use.  We need to dump the literal pool before
19409218822Sdim   references are made to a null symbol pointer.  */
1941060484Sobrien
19411218822Sdimvoid
19412218822Sdimarm_cleanup (void)
19413218822Sdim{
19414218822Sdim  literal_pool * pool;
1941577298Sobrien
19416218822Sdim  for (pool = list_of_pools; pool; pool = pool->next)
1941760484Sobrien    {
19418218822Sdim      /* Put it at the end of the relevent section.  */
19419218822Sdim      subseg_set (pool->section, pool->sub_section);
19420218822Sdim#ifdef OBJ_ELF
19421218822Sdim      arm_elf_change_section ();
19422218822Sdim#endif
19423218822Sdim      s_ltorg (0);
1942460484Sobrien    }
19425218822Sdim}
1942660484Sobrien
19427218822Sdim/* Adjust the symbol table.  This marks Thumb symbols as distinct from
19428218822Sdim   ARM ones.  */
1942960484Sobrien
19430218822Sdimvoid
19431218822Sdimarm_adjust_symtab (void)
19432218822Sdim{
19433218822Sdim#ifdef OBJ_COFF
19434218822Sdim  symbolS * sym;
1943577298Sobrien
19436218822Sdim  for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
19437218822Sdim    {
19438218822Sdim      if (ARM_IS_THUMB (sym))
1943960484Sobrien	{
19440218822Sdim	  if (THUMB_IS_FUNC (sym))
1944177298Sobrien	    {
19442218822Sdim	      /* Mark the symbol as a Thumb function.  */
19443218822Sdim	      if (   S_GET_STORAGE_CLASS (sym) == C_STAT
19444218822Sdim		  || S_GET_STORAGE_CLASS (sym) == C_LABEL)  /* This can happen!	 */
19445218822Sdim		S_SET_STORAGE_CLASS (sym, C_THUMBSTATFUNC);
19446218822Sdim
19447218822Sdim	      else if (S_GET_STORAGE_CLASS (sym) == C_EXT)
19448218822Sdim		S_SET_STORAGE_CLASS (sym, C_THUMBEXTFUNC);
19449218822Sdim	      else
19450218822Sdim		as_bad (_("%s: unexpected function type: %d"),
19451218822Sdim			S_GET_NAME (sym), S_GET_STORAGE_CLASS (sym));
1945277298Sobrien	    }
19453218822Sdim	  else switch (S_GET_STORAGE_CLASS (sym))
19454218822Sdim	    {
19455218822Sdim	    case C_EXT:
19456218822Sdim	      S_SET_STORAGE_CLASS (sym, C_THUMBEXT);
19457218822Sdim	      break;
19458218822Sdim	    case C_STAT:
19459218822Sdim	      S_SET_STORAGE_CLASS (sym, C_THUMBSTAT);
19460218822Sdim	      break;
19461218822Sdim	    case C_LABEL:
19462218822Sdim	      S_SET_STORAGE_CLASS (sym, C_THUMBLABEL);
19463218822Sdim	      break;
19464218822Sdim	    default:
19465218822Sdim	      /* Do nothing.  */
19466218822Sdim	      break;
19467218822Sdim	    }
19468218822Sdim	}
1946960484Sobrien
19470218822Sdim      if (ARM_IS_INTERWORK (sym))
19471218822Sdim	coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_flags = 0xFF;
1947260484Sobrien    }
19473218822Sdim#endif
19474218822Sdim#ifdef OBJ_ELF
19475218822Sdim  symbolS * sym;
19476218822Sdim  char	    bind;
19477218822Sdim
19478218822Sdim  for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
1947960484Sobrien    {
19480218822Sdim      if (ARM_IS_THUMB (sym))
19481218822Sdim	{
19482218822Sdim	  elf_symbol_type * elf_sym;
1948360484Sobrien
19484218822Sdim	  elf_sym = elf_symbol (symbol_get_bfdsym (sym));
19485218822Sdim	  bind = ELF_ST_BIND (elf_sym->internal_elf_sym.st_info);
1948677298Sobrien
19487218822Sdim	  if (! bfd_is_arm_special_symbol_name (elf_sym->symbol.name,
19488218822Sdim		BFD_ARM_SPECIAL_SYM_TYPE_ANY))
1948960484Sobrien	    {
19490218822Sdim	      /* If it's a .thumb_func, declare it as so,
19491218822Sdim		 otherwise tag label as .code 16.  */
19492218822Sdim	      if (THUMB_IS_FUNC (sym))
19493218822Sdim		elf_sym->internal_elf_sym.st_info =
19494218822Sdim		  ELF_ST_INFO (bind, STT_ARM_TFUNC);
19495218822Sdim	      else if (EF_ARM_EABI_VERSION (meabi_flags) < EF_ARM_EABI_VER4)
19496218822Sdim		elf_sym->internal_elf_sym.st_info =
19497218822Sdim		  ELF_ST_INFO (bind, STT_ARM_16BIT);
1949860484Sobrien	    }
1949960484Sobrien	}
1950060484Sobrien    }
19501218822Sdim#endif
19502218822Sdim}
1950360484Sobrien
19504218822Sdim/* MD interface: Initialization.  */
1950560484Sobrien
19506218822Sdimstatic void
19507218822Sdimset_constant_flonums (void)
19508218822Sdim{
19509218822Sdim  int i;
19510218822Sdim
19511218822Sdim  for (i = 0; i < NUM_FLOAT_VALS; i++)
19512218822Sdim    if (atof_ieee ((char *) fp_const[i], 'x', fp_values[i]) == NULL)
19513218822Sdim      abort ();
1951489857Sobrien}
1951577298Sobrien
19516218822Sdim/* Auto-select Thumb mode if it's the only available instruction set for the
19517218822Sdim   given architecture.  */
19518218822Sdim
19519218822Sdimstatic void
19520218822Sdimautoselect_thumb_from_cpu_variant (void)
19521218822Sdim{
19522218822Sdim  if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1))
19523218822Sdim    opcode_select (16);
19524218822Sdim}
19525218822Sdim
19526218822Sdimvoid
19527218822Sdimmd_begin (void)
19528218822Sdim{
19529218822Sdim  unsigned mach;
19530218822Sdim  unsigned int i;
19531218822Sdim
19532218822Sdim  if (	 (arm_ops_hsh = hash_new ()) == NULL
19533218822Sdim      || (arm_cond_hsh = hash_new ()) == NULL
19534218822Sdim      || (arm_shift_hsh = hash_new ()) == NULL
19535218822Sdim      || (arm_psr_hsh = hash_new ()) == NULL
19536218822Sdim      || (arm_v7m_psr_hsh = hash_new ()) == NULL
19537218822Sdim      || (arm_reg_hsh = hash_new ()) == NULL
19538218822Sdim      || (arm_reloc_hsh = hash_new ()) == NULL
19539218822Sdim      || (arm_barrier_opt_hsh = hash_new ()) == NULL)
19540218822Sdim    as_fatal (_("virtual memory exhausted"));
19541218822Sdim
19542218822Sdim  for (i = 0; i < sizeof (insns) / sizeof (struct asm_opcode); i++)
19543218822Sdim    hash_insert (arm_ops_hsh, insns[i].template, (PTR) (insns + i));
19544218822Sdim  for (i = 0; i < sizeof (conds) / sizeof (struct asm_cond); i++)
19545218822Sdim    hash_insert (arm_cond_hsh, conds[i].template, (PTR) (conds + i));
19546218822Sdim  for (i = 0; i < sizeof (shift_names) / sizeof (struct asm_shift_name); i++)
19547218822Sdim    hash_insert (arm_shift_hsh, shift_names[i].name, (PTR) (shift_names + i));
19548218822Sdim  for (i = 0; i < sizeof (psrs) / sizeof (struct asm_psr); i++)
19549218822Sdim    hash_insert (arm_psr_hsh, psrs[i].template, (PTR) (psrs + i));
19550218822Sdim  for (i = 0; i < sizeof (v7m_psrs) / sizeof (struct asm_psr); i++)
19551218822Sdim    hash_insert (arm_v7m_psr_hsh, v7m_psrs[i].template, (PTR) (v7m_psrs + i));
19552218822Sdim  for (i = 0; i < sizeof (reg_names) / sizeof (struct reg_entry); i++)
19553218822Sdim    hash_insert (arm_reg_hsh, reg_names[i].name, (PTR) (reg_names + i));
19554218822Sdim  for (i = 0;
19555218822Sdim       i < sizeof (barrier_opt_names) / sizeof (struct asm_barrier_opt);
19556218822Sdim       i++)
19557218822Sdim    hash_insert (arm_barrier_opt_hsh, barrier_opt_names[i].template,
19558218822Sdim		 (PTR) (barrier_opt_names + i));
19559218822Sdim#ifdef OBJ_ELF
19560218822Sdim  for (i = 0; i < sizeof (reloc_names) / sizeof (struct reloc_entry); i++)
19561218822Sdim    hash_insert (arm_reloc_hsh, reloc_names[i].name, (PTR) (reloc_names + i));
19562218822Sdim#endif
19563218822Sdim
19564218822Sdim  set_constant_flonums ();
19565218822Sdim
19566218822Sdim  /* Set the cpu variant based on the command-line options.  We prefer
19567218822Sdim     -mcpu= over -march= if both are set (as for GCC); and we prefer
19568218822Sdim     -mfpu= over any other way of setting the floating point unit.
19569218822Sdim     Use of legacy options with new options are faulted.  */
19570218822Sdim  if (legacy_cpu)
19571218822Sdim    {
19572218822Sdim      if (mcpu_cpu_opt || march_cpu_opt)
19573218822Sdim	as_bad (_("use of old and new-style options to set CPU type"));
19574218822Sdim
19575218822Sdim      mcpu_cpu_opt = legacy_cpu;
19576218822Sdim    }
19577218822Sdim  else if (!mcpu_cpu_opt)
19578218822Sdim    mcpu_cpu_opt = march_cpu_opt;
19579218822Sdim
19580218822Sdim  if (legacy_fpu)
19581218822Sdim    {
19582218822Sdim      if (mfpu_opt)
19583218822Sdim	as_bad (_("use of old and new-style options to set FPU type"));
19584218822Sdim
19585218822Sdim      mfpu_opt = legacy_fpu;
19586218822Sdim    }
19587218822Sdim  else if (!mfpu_opt)
19588218822Sdim    {
19589218822Sdim#if !(defined (TE_LINUX) || defined (TE_NetBSD) || defined (TE_VXWORKS))
19590218822Sdim      /* Some environments specify a default FPU.  If they don't, infer it
19591218822Sdim	 from the processor.  */
19592218822Sdim      if (mcpu_fpu_opt)
19593218822Sdim	mfpu_opt = mcpu_fpu_opt;
19594218822Sdim      else
19595218822Sdim	mfpu_opt = march_fpu_opt;
19596218822Sdim#else
19597218822Sdim      mfpu_opt = &fpu_default;
19598218822Sdim#endif
19599218822Sdim    }
19600218822Sdim
19601218822Sdim  if (!mfpu_opt)
19602218822Sdim    {
19603218822Sdim      if (mcpu_cpu_opt != NULL)
19604218822Sdim	mfpu_opt = &fpu_default;
19605218822Sdim      else if (mcpu_fpu_opt != NULL && ARM_CPU_HAS_FEATURE (*mcpu_fpu_opt, arm_ext_v5))
19606218822Sdim	mfpu_opt = &fpu_arch_vfp_v2;
19607218822Sdim      else
19608218822Sdim	mfpu_opt = &fpu_arch_fpa;
19609218822Sdim    }
19610218822Sdim
19611218822Sdim#ifdef CPU_DEFAULT
19612218822Sdim  if (!mcpu_cpu_opt)
19613218822Sdim    {
19614218822Sdim      mcpu_cpu_opt = &cpu_default;
19615218822Sdim      selected_cpu = cpu_default;
19616218822Sdim    }
19617218822Sdim#else
19618218822Sdim  if (mcpu_cpu_opt)
19619218822Sdim    selected_cpu = *mcpu_cpu_opt;
19620218822Sdim  else
19621218822Sdim    mcpu_cpu_opt = &arm_arch_any;
19622218822Sdim#endif
19623218822Sdim
19624218822Sdim  ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
19625218822Sdim
19626218822Sdim  autoselect_thumb_from_cpu_variant ();
19627218822Sdim
19628218822Sdim  arm_arch_used = thumb_arch_used = arm_arch_none;
19629218822Sdim
19630218822Sdim#if defined OBJ_COFF || defined OBJ_ELF
19631218822Sdim  {
19632218822Sdim    unsigned int flags = 0;
19633218822Sdim
19634218822Sdim#if defined OBJ_ELF
19635218822Sdim    flags = meabi_flags;
19636218822Sdim
19637218822Sdim    switch (meabi_flags)
19638218822Sdim      {
19639218822Sdim      case EF_ARM_EABI_UNKNOWN:
19640218822Sdim#endif
19641218822Sdim	/* Set the flags in the private structure.  */
19642218822Sdim	if (uses_apcs_26)      flags |= F_APCS26;
19643218822Sdim	if (support_interwork) flags |= F_INTERWORK;
19644218822Sdim	if (uses_apcs_float)   flags |= F_APCS_FLOAT;
19645218822Sdim	if (pic_code)	       flags |= F_PIC;
19646218822Sdim	if (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_any_hard))
19647218822Sdim	  flags |= F_SOFT_FLOAT;
19648218822Sdim
19649218822Sdim	switch (mfloat_abi_opt)
19650218822Sdim	  {
19651218822Sdim	  case ARM_FLOAT_ABI_SOFT:
19652218822Sdim	  case ARM_FLOAT_ABI_SOFTFP:
19653218822Sdim	    flags |= F_SOFT_FLOAT;
19654218822Sdim	    break;
19655218822Sdim
19656218822Sdim	  case ARM_FLOAT_ABI_HARD:
19657218822Sdim	    if (flags & F_SOFT_FLOAT)
19658218822Sdim	      as_bad (_("hard-float conflicts with specified fpu"));
19659218822Sdim	    break;
19660218822Sdim	  }
19661218822Sdim
19662218822Sdim	/* Using pure-endian doubles (even if soft-float).	*/
19663218822Sdim	if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_endian_pure))
19664218822Sdim	  flags |= F_VFP_FLOAT;
19665218822Sdim
19666218822Sdim#if defined OBJ_ELF
19667218822Sdim	if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_arch_maverick))
19668218822Sdim	    flags |= EF_ARM_MAVERICK_FLOAT;
19669218822Sdim	break;
19670218822Sdim
19671218822Sdim      case EF_ARM_EABI_VER4:
19672218822Sdim      case EF_ARM_EABI_VER5:
19673218822Sdim	/* No additional flags to set.	*/
19674218822Sdim	break;
19675218822Sdim
19676218822Sdim      default:
19677218822Sdim	abort ();
19678218822Sdim      }
19679218822Sdim#endif
19680218822Sdim    bfd_set_private_flags (stdoutput, flags);
19681218822Sdim
19682218822Sdim    /* We have run out flags in the COFF header to encode the
19683218822Sdim       status of ATPCS support, so instead we create a dummy,
19684218822Sdim       empty, debug section called .arm.atpcs.	*/
19685218822Sdim    if (atpcs)
19686218822Sdim      {
19687218822Sdim	asection * sec;
19688218822Sdim
19689218822Sdim	sec = bfd_make_section (stdoutput, ".arm.atpcs");
19690218822Sdim
19691218822Sdim	if (sec != NULL)
19692218822Sdim	  {
19693218822Sdim	    bfd_set_section_flags
19694218822Sdim	      (stdoutput, sec, SEC_READONLY | SEC_DEBUGGING /* | SEC_HAS_CONTENTS */);
19695218822Sdim	    bfd_set_section_size (stdoutput, sec, 0);
19696218822Sdim	    bfd_set_section_contents (stdoutput, sec, NULL, 0, 0);
19697218822Sdim	  }
19698218822Sdim      }
19699218822Sdim  }
19700218822Sdim#endif
19701218822Sdim
19702218822Sdim  /* Record the CPU type as well.  */
19703218822Sdim  if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2))
19704218822Sdim    mach = bfd_mach_arm_iWMMXt2;
19705218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt))
19706218822Sdim    mach = bfd_mach_arm_iWMMXt;
19707218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_xscale))
19708218822Sdim    mach = bfd_mach_arm_XScale;
19709218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_maverick))
19710218822Sdim    mach = bfd_mach_arm_ep9312;
19711218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v5e))
19712218822Sdim    mach = bfd_mach_arm_5TE;
19713218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v5))
19714218822Sdim    {
19715218822Sdim      if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v4t))
19716218822Sdim	mach = bfd_mach_arm_5T;
19717218822Sdim      else
19718218822Sdim	mach = bfd_mach_arm_5;
19719218822Sdim    }
19720218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v4))
19721218822Sdim    {
19722218822Sdim      if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v4t))
19723218822Sdim	mach = bfd_mach_arm_4T;
19724218822Sdim      else
19725218822Sdim	mach = bfd_mach_arm_4;
19726218822Sdim    }
19727218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v3m))
19728218822Sdim    mach = bfd_mach_arm_3M;
19729218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v3))
19730218822Sdim    mach = bfd_mach_arm_3;
19731218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v2s))
19732218822Sdim    mach = bfd_mach_arm_2a;
19733218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v2))
19734218822Sdim    mach = bfd_mach_arm_2;
19735218822Sdim  else
19736218822Sdim    mach = bfd_mach_arm_unknown;
19737218822Sdim
19738218822Sdim  bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
19739218822Sdim}
19740218822Sdim
19741218822Sdim/* Command line processing.  */
19742218822Sdim
1974389857Sobrien/* md_parse_option
1974489857Sobrien      Invocation line includes a switch not recognized by the base assembler.
19745104834Sobrien      See if it's a processor-specific option.
1974677298Sobrien
1974789857Sobrien      This routine is somewhat complicated by the need for backwards
1974889857Sobrien      compatibility (since older releases of gcc can't be changed).
1974989857Sobrien      The new options try to make the interface as compatible as
1975089857Sobrien      possible with GCC.
1975177298Sobrien
1975289857Sobrien      New options (supported) are:
1975360484Sobrien
1975489857Sobrien	      -mcpu=<cpu name>		 Assemble for selected processor
1975589857Sobrien	      -march=<architecture name> Assemble for selected architecture
1975689857Sobrien	      -mfpu=<fpu architecture>	 Assemble for selected FPU.
1975789857Sobrien	      -EB/-mbig-endian		 Big-endian
1975889857Sobrien	      -EL/-mlittle-endian	 Little-endian
1975989857Sobrien	      -k			 Generate PIC code
1976089857Sobrien	      -mthumb			 Start in Thumb mode
1976189857Sobrien	      -mthumb-interwork		 Code supports ARM/Thumb interworking
1976277298Sobrien
19763130561Sobrien      For now we will also provide support for:
1976460484Sobrien
1976589857Sobrien	      -mapcs-32			 32-bit Program counter
1976689857Sobrien	      -mapcs-26			 26-bit Program counter
1976789857Sobrien	      -macps-float		 Floats passed in FP registers
1976889857Sobrien	      -mapcs-reentrant		 Reentrant code
1976989857Sobrien	      -matpcs
1977089857Sobrien      (sometime these will probably be replaced with -mapcs=<list of options>
1977189857Sobrien      and -matpcs=<list of options>)
1977260484Sobrien
1977389857Sobrien      The remaining options are only supported for back-wards compatibility.
1977477298Sobrien      Cpu variants, the arm part is optional:
19775218822Sdim	      -m[arm]1		      Currently not supported.
19776218822Sdim	      -m[arm]2, -m[arm]250    Arm 2 and Arm 250 processor
19777218822Sdim	      -m[arm]3		      Arm 3 processor
19778218822Sdim	      -m[arm]6[xx],	      Arm 6 processors
19779218822Sdim	      -m[arm]7[xx][t][[d]m]   Arm 7 processors
19780218822Sdim	      -m[arm]8[10]	      Arm 8 processors
19781218822Sdim	      -m[arm]9[20][tdmi]      Arm 9 processors
19782218822Sdim	      -mstrongarm[110[0]]     StrongARM processors
19783218822Sdim	      -mxscale		      XScale processors
19784218822Sdim	      -m[arm]v[2345[t[e]]]    Arm architectures
19785218822Sdim	      -mall		      All (except the ARM1)
1978677298Sobrien      FP variants:
19787218822Sdim	      -mfpa10, -mfpa11	      FPA10 and 11 co-processor instructions
19788218822Sdim	      -mfpe-old		      (No float load/store multiples)
1978989857Sobrien	      -mvfpxd		      VFP Single precision
1979089857Sobrien	      -mvfp		      All VFP
19791218822Sdim	      -mno-fpu		      Disable all floating point instructions
1979260484Sobrien
1979389857Sobrien      The following CPU names are recognized:
1979489857Sobrien	      arm1, arm2, arm250, arm3, arm6, arm600, arm610, arm620,
1979589857Sobrien	      arm7, arm7m, arm7d, arm7dm, arm7di, arm7dmi, arm70, arm700,
1979689857Sobrien	      arm700i, arm710 arm710t, arm720, arm720t, arm740t, arm710c,
1979789857Sobrien	      arm7100, arm7500, arm7500fe, arm7tdmi, arm8, arm810, arm9,
1979889857Sobrien	      arm920, arm920t, arm940t, arm946, arm966, arm9tdmi, arm9e,
1979989857Sobrien	      arm10t arm10e, arm1020t, arm1020e, arm10200e,
1980089857Sobrien	      strongarm, strongarm110, strongarm1100, strongarm1110, xscale.
1980189857Sobrien
1980289857Sobrien      */
1980389857Sobrien
19804104834Sobrienconst char * md_shortopts = "m:k";
1980577298Sobrien
1980689857Sobrien#ifdef ARM_BI_ENDIAN
1980789857Sobrien#define OPTION_EB (OPTION_MD_BASE + 0)
1980889857Sobrien#define OPTION_EL (OPTION_MD_BASE + 1)
1980989857Sobrien#else
1981089857Sobrien#if TARGET_BYTES_BIG_ENDIAN
1981189857Sobrien#define OPTION_EB (OPTION_MD_BASE + 0)
1981289857Sobrien#else
1981389857Sobrien#define OPTION_EL (OPTION_MD_BASE + 1)
1981489857Sobrien#endif
1981589857Sobrien#endif
1981689857Sobrien
1981760484Sobrienstruct option md_longopts[] =
1981860484Sobrien{
1981989857Sobrien#ifdef OPTION_EB
1982060484Sobrien  {"EB", no_argument, NULL, OPTION_EB},
1982189857Sobrien#endif
1982289857Sobrien#ifdef OPTION_EL
1982360484Sobrien  {"EL", no_argument, NULL, OPTION_EL},
1982460484Sobrien#endif
1982560484Sobrien  {NULL, no_argument, NULL, 0}
1982660484Sobrien};
1982777298Sobrien
1982860484Sobriensize_t md_longopts_size = sizeof (md_longopts);
1982960484Sobrien
1983089857Sobrienstruct arm_option_table
1983160484Sobrien{
1983289857Sobrien  char *option;		/* Option name to match.  */
1983389857Sobrien  char *help;		/* Help information.  */
19834218822Sdim  int  *var;		/* Variable to change.	*/
19835218822Sdim  int	value;		/* What to change it to.  */
1983689857Sobrien  char *deprecated;	/* If non-null, print this message.  */
1983789857Sobrien};
1983860484Sobrien
19839104834Sobrienstruct arm_option_table arm_opts[] =
1984089857Sobrien{
19841218822Sdim  {"k",	     N_("generate PIC code"),	   &pic_code,	 1, NULL},
19842218822Sdim  {"mthumb", N_("assemble Thumb code"),	   &thumb_mode,	 1, NULL},
1984389857Sobrien  {"mthumb-interwork", N_("support ARM/Thumb interworking"),
1984489857Sobrien   &support_interwork, 1, NULL},
1984589857Sobrien  {"mapcs-32", N_("code uses 32-bit program counter"), &uses_apcs_26, 0, NULL},
1984689857Sobrien  {"mapcs-26", N_("code uses 26-bit program counter"), &uses_apcs_26, 1, NULL},
1984789857Sobrien  {"mapcs-float", N_("floating point args are in fp regs"), &uses_apcs_float,
1984889857Sobrien   1, NULL},
1984989857Sobrien  {"mapcs-reentrant", N_("re-entrant code"), &pic_code, 1, NULL},
1985089857Sobrien  {"matpcs", N_("code is ATPCS conformant"), &atpcs, 1, NULL},
1985189857Sobrien  {"mbig-endian", N_("assemble for big-endian"), &target_big_endian, 1, NULL},
19852218822Sdim  {"mlittle-endian", N_("assemble for little-endian"), &target_big_endian, 0,
1985389857Sobrien   NULL},
1985489857Sobrien
19855218822Sdim  /* These are recognized by the assembler, but have no affect on code.	 */
1985689857Sobrien  {"mapcs-frame", N_("use frame pointer"), NULL, 0, NULL},
1985789857Sobrien  {"mapcs-stack-check", N_("use stack size checking"), NULL, 0, NULL},
19858218822Sdim  {NULL, NULL, NULL, 0, NULL}
19859218822Sdim};
1986089857Sobrien
19861218822Sdimstruct arm_legacy_option_table
19862218822Sdim{
19863218822Sdim  char *option;				/* Option name to match.  */
19864218822Sdim  const arm_feature_set	**var;		/* Variable to change.	*/
19865218822Sdim  const arm_feature_set	value;		/* What to change it to.  */
19866218822Sdim  char *deprecated;			/* If non-null, print this message.  */
19867218822Sdim};
19868218822Sdim
19869218822Sdimconst struct arm_legacy_option_table arm_legacy_opts[] =
19870218822Sdim{
1987189857Sobrien  /* DON'T add any new processors to this list -- we want the whole list
1987289857Sobrien     to go away...  Add them to the processors table instead.  */
19873218822Sdim  {"marm1",	 &legacy_cpu, ARM_ARCH_V1,  N_("use -mcpu=arm1")},
19874218822Sdim  {"m1",	 &legacy_cpu, ARM_ARCH_V1,  N_("use -mcpu=arm1")},
19875218822Sdim  {"marm2",	 &legacy_cpu, ARM_ARCH_V2,  N_("use -mcpu=arm2")},
19876218822Sdim  {"m2",	 &legacy_cpu, ARM_ARCH_V2,  N_("use -mcpu=arm2")},
19877218822Sdim  {"marm250",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm250")},
19878218822Sdim  {"m250",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm250")},
19879218822Sdim  {"marm3",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm3")},
19880218822Sdim  {"m3",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm3")},
19881218822Sdim  {"marm6",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm6")},
19882218822Sdim  {"m6",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm6")},
19883218822Sdim  {"marm600",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm600")},
19884218822Sdim  {"m600",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm600")},
19885218822Sdim  {"marm610",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm610")},
19886218822Sdim  {"m610",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm610")},
19887218822Sdim  {"marm620",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm620")},
19888218822Sdim  {"m620",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm620")},
19889218822Sdim  {"marm7",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7")},
19890218822Sdim  {"m7",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7")},
19891218822Sdim  {"marm70",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm70")},
19892218822Sdim  {"m70",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm70")},
19893218822Sdim  {"marm700",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm700")},
19894218822Sdim  {"m700",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm700")},
19895218822Sdim  {"marm700i",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm700i")},
19896218822Sdim  {"m700i",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm700i")},
19897218822Sdim  {"marm710",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm710")},
19898218822Sdim  {"m710",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm710")},
19899218822Sdim  {"marm710c",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm710c")},
19900218822Sdim  {"m710c",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm710c")},
19901218822Sdim  {"marm720",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm720")},
19902218822Sdim  {"m720",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm720")},
19903218822Sdim  {"marm7d",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7d")},
19904218822Sdim  {"m7d",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7d")},
19905218822Sdim  {"marm7di",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7di")},
19906218822Sdim  {"m7di",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7di")},
19907218822Sdim  {"marm7m",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7m")},
19908218822Sdim  {"m7m",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7m")},
19909218822Sdim  {"marm7dm",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dm")},
19910218822Sdim  {"m7dm",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dm")},
19911218822Sdim  {"marm7dmi",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dmi")},
19912218822Sdim  {"m7dmi",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dmi")},
19913218822Sdim  {"marm7100",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7100")},
19914218822Sdim  {"m7100",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7100")},
19915218822Sdim  {"marm7500",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7500")},
19916218822Sdim  {"m7500",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7500")},
19917218822Sdim  {"marm7500fe", &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7500fe")},
19918218822Sdim  {"m7500fe",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7500fe")},
19919218822Sdim  {"marm7t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
19920218822Sdim  {"m7t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
19921218822Sdim  {"marm7tdmi",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
19922218822Sdim  {"m7tdmi",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
19923218822Sdim  {"marm710t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm710t")},
19924218822Sdim  {"m710t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm710t")},
19925218822Sdim  {"marm720t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm720t")},
19926218822Sdim  {"m720t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm720t")},
19927218822Sdim  {"marm740t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm740t")},
19928218822Sdim  {"m740t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm740t")},
19929218822Sdim  {"marm8",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -mcpu=arm8")},
19930218822Sdim  {"m8",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -mcpu=arm8")},
19931218822Sdim  {"marm810",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -mcpu=arm810")},
19932218822Sdim  {"m810",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -mcpu=arm810")},
19933218822Sdim  {"marm9",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9")},
19934218822Sdim  {"m9",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9")},
19935218822Sdim  {"marm9tdmi",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9tdmi")},
19936218822Sdim  {"m9tdmi",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9tdmi")},
19937218822Sdim  {"marm920",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm920")},
19938218822Sdim  {"m920",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm920")},
19939218822Sdim  {"marm940",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm940")},
19940218822Sdim  {"m940",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm940")},
19941218822Sdim  {"mstrongarm", &legacy_cpu, ARM_ARCH_V4,  N_("use -mcpu=strongarm")},
19942218822Sdim  {"mstrongarm110", &legacy_cpu, ARM_ARCH_V4,
1994389857Sobrien   N_("use -mcpu=strongarm110")},
19944218822Sdim  {"mstrongarm1100", &legacy_cpu, ARM_ARCH_V4,
1994589857Sobrien   N_("use -mcpu=strongarm1100")},
19946218822Sdim  {"mstrongarm1110", &legacy_cpu, ARM_ARCH_V4,
1994789857Sobrien   N_("use -mcpu=strongarm1110")},
19948218822Sdim  {"mxscale",	 &legacy_cpu, ARM_ARCH_XSCALE, N_("use -mcpu=xscale")},
19949218822Sdim  {"miwmmxt",	 &legacy_cpu, ARM_ARCH_IWMMXT, N_("use -mcpu=iwmmxt")},
19950218822Sdim  {"mall",	 &legacy_cpu, ARM_ANY,	       N_("use -mcpu=all")},
1995189857Sobrien
1995289857Sobrien  /* Architecture variants -- don't add any more to this list either.  */
19953218822Sdim  {"mv2",	 &legacy_cpu, ARM_ARCH_V2,  N_("use -march=armv2")},
19954218822Sdim  {"marmv2",	 &legacy_cpu, ARM_ARCH_V2,  N_("use -march=armv2")},
19955218822Sdim  {"mv2a",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -march=armv2a")},
19956218822Sdim  {"marmv2a",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -march=armv2a")},
19957218822Sdim  {"mv3",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -march=armv3")},
19958218822Sdim  {"marmv3",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -march=armv3")},
19959218822Sdim  {"mv3m",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -march=armv3m")},
19960218822Sdim  {"marmv3m",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -march=armv3m")},
19961218822Sdim  {"mv4",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -march=armv4")},
19962218822Sdim  {"marmv4",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -march=armv4")},
19963218822Sdim  {"mv4t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -march=armv4t")},
19964218822Sdim  {"marmv4t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -march=armv4t")},
19965218822Sdim  {"mv5",	 &legacy_cpu, ARM_ARCH_V5,  N_("use -march=armv5")},
19966218822Sdim  {"marmv5",	 &legacy_cpu, ARM_ARCH_V5,  N_("use -march=armv5")},
19967218822Sdim  {"mv5t",	 &legacy_cpu, ARM_ARCH_V5T, N_("use -march=armv5t")},
19968218822Sdim  {"marmv5t",	 &legacy_cpu, ARM_ARCH_V5T, N_("use -march=armv5t")},
19969218822Sdim  {"mv5e",	 &legacy_cpu, ARM_ARCH_V5TE, N_("use -march=armv5te")},
19970218822Sdim  {"marmv5e",	 &legacy_cpu, ARM_ARCH_V5TE, N_("use -march=armv5te")},
1997189857Sobrien
19972218822Sdim  /* Floating point variants -- don't add any more to this list either.	 */
19973218822Sdim  {"mfpe-old", &legacy_fpu, FPU_ARCH_FPE, N_("use -mfpu=fpe")},
19974218822Sdim  {"mfpa10",   &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa10")},
19975218822Sdim  {"mfpa11",   &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa11")},
19976218822Sdim  {"mno-fpu",  &legacy_fpu, ARM_ARCH_NONE,
1997789857Sobrien   N_("use either -mfpu=softfpa or -mfpu=softvfp")},
1997889857Sobrien
19979218822Sdim  {NULL, NULL, ARM_ARCH_NONE, NULL}
1998089857Sobrien};
1998189857Sobrien
1998289857Sobrienstruct arm_cpu_option_table
1998389857Sobrien{
1998489857Sobrien  char *name;
19985218822Sdim  const arm_feature_set	value;
1998689857Sobrien  /* For some CPUs we assume an FPU unless the user explicitly sets
19987218822Sdim     -mfpu=...	*/
19988218822Sdim  const arm_feature_set	default_fpu;
19989218822Sdim  /* The canonical name of the CPU, or NULL to use NAME converted to upper
19990218822Sdim     case.  */
19991218822Sdim  const char *canonical_name;
1999289857Sobrien};
1999389857Sobrien
1999489857Sobrien/* This list should, at a minimum, contain all the cpu names
1999589857Sobrien   recognized by GCC.  */
19996218822Sdimstatic const struct arm_cpu_option_table arm_cpus[] =
1999789857Sobrien{
19998218822Sdim  {"all",		ARM_ANY,	 FPU_ARCH_FPA,    NULL},
19999218822Sdim  {"arm1",		ARM_ARCH_V1,	 FPU_ARCH_FPA,    NULL},
20000218822Sdim  {"arm2",		ARM_ARCH_V2,	 FPU_ARCH_FPA,    NULL},
20001218822Sdim  {"arm250",		ARM_ARCH_V2S,	 FPU_ARCH_FPA,    NULL},
20002218822Sdim  {"arm3",		ARM_ARCH_V2S,	 FPU_ARCH_FPA,    NULL},
20003218822Sdim  {"arm6",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20004218822Sdim  {"arm60",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20005218822Sdim  {"arm600",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20006218822Sdim  {"arm610",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20007218822Sdim  {"arm620",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20008218822Sdim  {"arm7",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20009218822Sdim  {"arm7m",		ARM_ARCH_V3M,	 FPU_ARCH_FPA,    NULL},
20010218822Sdim  {"arm7d",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20011218822Sdim  {"arm7dm",		ARM_ARCH_V3M,	 FPU_ARCH_FPA,    NULL},
20012218822Sdim  {"arm7di",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20013218822Sdim  {"arm7dmi",		ARM_ARCH_V3M,	 FPU_ARCH_FPA,    NULL},
20014218822Sdim  {"arm70",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20015218822Sdim  {"arm700",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20016218822Sdim  {"arm700i",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20017218822Sdim  {"arm710",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20018218822Sdim  {"arm710t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20019218822Sdim  {"arm720",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20020218822Sdim  {"arm720t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20021218822Sdim  {"arm740t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20022218822Sdim  {"arm710c",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20023218822Sdim  {"arm7100",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20024218822Sdim  {"arm7500",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20025218822Sdim  {"arm7500fe",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
20026218822Sdim  {"arm7t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20027218822Sdim  {"arm7tdmi",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20028218822Sdim  {"arm7tdmi-s",	ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20029218822Sdim  {"arm8",		ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
20030218822Sdim  {"arm810",		ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
20031218822Sdim  {"strongarm",		ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
20032218822Sdim  {"strongarm1",	ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
20033218822Sdim  {"strongarm110",	ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
20034218822Sdim  {"strongarm1100",	ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
20035218822Sdim  {"strongarm1110",	ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
20036218822Sdim  {"arm9",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20037218822Sdim  {"arm920",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    "ARM920T"},
20038218822Sdim  {"arm920t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20039218822Sdim  {"arm922t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20040218822Sdim  {"arm940t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
20041218822Sdim  {"arm9tdmi",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,	  NULL},
2004289857Sobrien  /* For V5 or later processors we default to using VFP; but the user
20043218822Sdim     should really set the FPU type explicitly.	 */
20044218822Sdim  {"arm9e-r0",		ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL},
20045218822Sdim  {"arm9e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
20046218822Sdim  {"arm926ej",		ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP_V2, "ARM926EJ-S"},
20047218822Sdim  {"arm926ejs",		ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP_V2, "ARM926EJ-S"},
20048218822Sdim  {"arm926ej-s",	ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP_V2, NULL},
20049218822Sdim  {"arm946e-r0",	ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL},
20050218822Sdim  {"arm946e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, "ARM946E-S"},
20051218822Sdim  {"arm946e-s",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
20052218822Sdim  {"arm966e-r0",	ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL},
20053218822Sdim  {"arm966e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, "ARM966E-S"},
20054218822Sdim  {"arm966e-s",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
20055218822Sdim  {"arm968e-s",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
20056218822Sdim  {"arm10t",		ARM_ARCH_V5T,	 FPU_ARCH_VFP_V1, NULL},
20057218822Sdim  {"arm10tdmi",		ARM_ARCH_V5T,	 FPU_ARCH_VFP_V1, NULL},
20058218822Sdim  {"arm10e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
20059218822Sdim  {"arm1020",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, "ARM1020E"},
20060218822Sdim  {"arm1020t",		ARM_ARCH_V5T,	 FPU_ARCH_VFP_V1, NULL},
20061218822Sdim  {"arm1020e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
20062218822Sdim  {"arm1022e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
20063218822Sdim  {"arm1026ejs",	ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP_V2, "ARM1026EJ-S"},
20064218822Sdim  {"arm1026ej-s",	ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP_V2, NULL},
20065218822Sdim  {"arm1136js",		ARM_ARCH_V6,	 FPU_NONE,	  "ARM1136J-S"},
20066218822Sdim  {"arm1136j-s",	ARM_ARCH_V6,	 FPU_NONE,	  NULL},
20067218822Sdim  {"arm1136jfs",	ARM_ARCH_V6,	 FPU_ARCH_VFP_V2, "ARM1136JF-S"},
20068218822Sdim  {"arm1136jf-s",	ARM_ARCH_V6,	 FPU_ARCH_VFP_V2, NULL},
20069218822Sdim  {"mpcore",		ARM_ARCH_V6K,	 FPU_ARCH_VFP_V2, NULL},
20070218822Sdim  {"mpcorenovfp",	ARM_ARCH_V6K,	 FPU_NONE,	  NULL},
20071218822Sdim  {"arm1156t2-s",	ARM_ARCH_V6T2,	 FPU_NONE,	  NULL},
20072218822Sdim  {"arm1156t2f-s",	ARM_ARCH_V6T2,	 FPU_ARCH_VFP_V2, NULL},
20073218822Sdim  {"arm1176jz-s",	ARM_ARCH_V6ZK,	 FPU_NONE,	  NULL},
20074218822Sdim  {"arm1176jzf-s",	ARM_ARCH_V6ZK,	 FPU_ARCH_VFP_V2, NULL},
20075218822Sdim  {"cortex-a8",		ARM_ARCH_V7A,	 ARM_FEATURE(0, FPU_VFP_V3
20076218822Sdim                                                        | FPU_NEON_EXT_V1),
20077218822Sdim                                                          NULL},
20078239272Sgonzo  {"cortex-a9",		ARM_ARCH_V7A,	 ARM_FEATURE(0, FPU_VFP_V3
20079239272Sgonzo                                                        | FPU_NEON_EXT_V1),
20080239272Sgonzo                                                          NULL},
20081218822Sdim  {"cortex-r4",		ARM_ARCH_V7R,	 FPU_NONE,	  NULL},
20082218822Sdim  {"cortex-m3",		ARM_ARCH_V7M,	 FPU_NONE,	  NULL},
2008389857Sobrien  /* ??? XSCALE is really an architecture.  */
20084218822Sdim  {"xscale",		ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL},
20085130561Sobrien  /* ??? iwmmxt is not a processor.  */
20086218822Sdim  {"iwmmxt",		ARM_ARCH_IWMMXT, FPU_ARCH_VFP_V2, NULL},
20087218822Sdim  {"iwmmxt2",		ARM_ARCH_IWMMXT2,FPU_ARCH_VFP_V2, NULL},
20088218822Sdim  {"i80200",		ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL},
2008989857Sobrien  /* Maverick */
20090218822Sdim  {"ep9312",	ARM_FEATURE(ARM_AEXT_V4T, ARM_CEXT_MAVERICK), FPU_ARCH_MAVERICK, "ARM920T"},
20091218822Sdim  {NULL,		ARM_ARCH_NONE,	 ARM_ARCH_NONE, NULL}
2009289857Sobrien};
20093104834Sobrien
2009489857Sobrienstruct arm_arch_option_table
2009589857Sobrien{
2009689857Sobrien  char *name;
20097218822Sdim  const arm_feature_set	value;
20098218822Sdim  const arm_feature_set	default_fpu;
2009989857Sobrien};
2010089857Sobrien
2010189857Sobrien/* This list should, at a minimum, contain all the architecture names
2010289857Sobrien   recognized by GCC.  */
20103218822Sdimstatic const struct arm_arch_option_table arm_archs[] =
2010489857Sobrien{
2010589857Sobrien  {"all",		ARM_ANY,	 FPU_ARCH_FPA},
2010689857Sobrien  {"armv1",		ARM_ARCH_V1,	 FPU_ARCH_FPA},
2010789857Sobrien  {"armv2",		ARM_ARCH_V2,	 FPU_ARCH_FPA},
2010889857Sobrien  {"armv2a",		ARM_ARCH_V2S,	 FPU_ARCH_FPA},
2010989857Sobrien  {"armv2s",		ARM_ARCH_V2S,	 FPU_ARCH_FPA},
2011089857Sobrien  {"armv3",		ARM_ARCH_V3,	 FPU_ARCH_FPA},
2011189857Sobrien  {"armv3m",		ARM_ARCH_V3M,	 FPU_ARCH_FPA},
2011289857Sobrien  {"armv4",		ARM_ARCH_V4,	 FPU_ARCH_FPA},
2011389857Sobrien  {"armv4xm",		ARM_ARCH_V4xM,	 FPU_ARCH_FPA},
2011489857Sobrien  {"armv4t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA},
2011589857Sobrien  {"armv4txm",		ARM_ARCH_V4TxM,	 FPU_ARCH_FPA},
2011689857Sobrien  {"armv5",		ARM_ARCH_V5,	 FPU_ARCH_VFP},
2011789857Sobrien  {"armv5t",		ARM_ARCH_V5T,	 FPU_ARCH_VFP},
2011889857Sobrien  {"armv5txm",		ARM_ARCH_V5TxM,	 FPU_ARCH_VFP},
2011989857Sobrien  {"armv5te",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP},
2012089857Sobrien  {"armv5texp",		ARM_ARCH_V5TExP, FPU_ARCH_VFP},
20121218822Sdim  {"armv5tej",		ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP},
20122218822Sdim  {"armv6",		ARM_ARCH_V6,	 FPU_ARCH_VFP},
20123218822Sdim  {"armv6j",		ARM_ARCH_V6,	 FPU_ARCH_VFP},
20124218822Sdim  {"armv6k",		ARM_ARCH_V6K,	 FPU_ARCH_VFP},
20125218822Sdim  {"armv6z",		ARM_ARCH_V6Z,	 FPU_ARCH_VFP},
20126218822Sdim  {"armv6zk",		ARM_ARCH_V6ZK,	 FPU_ARCH_VFP},
20127218822Sdim  {"armv6t2",		ARM_ARCH_V6T2,	 FPU_ARCH_VFP},
20128218822Sdim  {"armv6kt2",		ARM_ARCH_V6KT2,	 FPU_ARCH_VFP},
20129218822Sdim  {"armv6zt2",		ARM_ARCH_V6ZT2,	 FPU_ARCH_VFP},
20130218822Sdim  {"armv6zkt2",		ARM_ARCH_V6ZKT2, FPU_ARCH_VFP},
20131218822Sdim  {"armv7",		ARM_ARCH_V7,	 FPU_ARCH_VFP},
20132218822Sdim  /* The official spelling of the ARMv7 profile variants is the dashed form.
20133218822Sdim     Accept the non-dashed form for compatibility with old toolchains.  */
20134218822Sdim  {"armv7a",		ARM_ARCH_V7A,	 FPU_ARCH_VFP},
20135218822Sdim  {"armv7r",		ARM_ARCH_V7R,	 FPU_ARCH_VFP},
20136218822Sdim  {"armv7m",		ARM_ARCH_V7M,	 FPU_ARCH_VFP},
20137218822Sdim  {"armv7-a",		ARM_ARCH_V7A,	 FPU_ARCH_VFP},
20138218822Sdim  {"armv7-r",		ARM_ARCH_V7R,	 FPU_ARCH_VFP},
20139218822Sdim  {"armv7-m",		ARM_ARCH_V7M,	 FPU_ARCH_VFP},
2014089857Sobrien  {"xscale",		ARM_ARCH_XSCALE, FPU_ARCH_VFP},
20141130561Sobrien  {"iwmmxt",		ARM_ARCH_IWMMXT, FPU_ARCH_VFP},
20142218822Sdim  {"iwmmxt2",		ARM_ARCH_IWMMXT2,FPU_ARCH_VFP},
20143218822Sdim  {NULL,		ARM_ARCH_NONE,	 ARM_ARCH_NONE}
2014489857Sobrien};
2014589857Sobrien
2014689857Sobrien/* ISA extensions in the co-processor space.  */
20147218822Sdimstruct arm_option_cpu_value_table
2014889857Sobrien{
2014989857Sobrien  char *name;
20150218822Sdim  const arm_feature_set value;
2015189857Sobrien};
2015289857Sobrien
20153218822Sdimstatic const struct arm_option_cpu_value_table arm_extensions[] =
2015489857Sobrien{
20155218822Sdim  {"maverick",		ARM_FEATURE (0, ARM_CEXT_MAVERICK)},
20156218822Sdim  {"xscale",		ARM_FEATURE (0, ARM_CEXT_XSCALE)},
20157218822Sdim  {"iwmmxt",		ARM_FEATURE (0, ARM_CEXT_IWMMXT)},
20158218822Sdim  {"iwmmxt2",		ARM_FEATURE (0, ARM_CEXT_IWMMXT2)},
20159269797Sian  {"sec",		ARM_FEATURE (ARM_EXT_V6Z, 0)},
20160218822Sdim  {NULL,		ARM_ARCH_NONE}
2016189857Sobrien};
2016289857Sobrien
2016389857Sobrien/* This list should, at a minimum, contain all the fpu names
2016489857Sobrien   recognized by GCC.  */
20165218822Sdimstatic const struct arm_option_cpu_value_table arm_fpus[] =
2016689857Sobrien{
2016789857Sobrien  {"softfpa",		FPU_NONE},
2016889857Sobrien  {"fpe",		FPU_ARCH_FPE},
2016989857Sobrien  {"fpe2",		FPU_ARCH_FPE},
2017089857Sobrien  {"fpe3",		FPU_ARCH_FPA},	/* Third release supports LFM/SFM.  */
2017189857Sobrien  {"fpa",		FPU_ARCH_FPA},
2017289857Sobrien  {"fpa10",		FPU_ARCH_FPA},
2017389857Sobrien  {"fpa11",		FPU_ARCH_FPA},
2017489857Sobrien  {"arm7500fe",		FPU_ARCH_FPA},
2017589857Sobrien  {"softvfp",		FPU_ARCH_VFP},
2017689857Sobrien  {"softvfp+vfp",	FPU_ARCH_VFP_V2},
2017789857Sobrien  {"vfp",		FPU_ARCH_VFP_V2},
20178244274Sandrew  {"vfpv2",		FPU_ARCH_VFP_V2},
2017989857Sobrien  {"vfp9",		FPU_ARCH_VFP_V2},
20180218822Sdim  {"vfp3",              FPU_ARCH_VFP_V3},
20181239272Sgonzo  {"vfpv3",             FPU_ARCH_VFP_V3},
2018289857Sobrien  {"vfp10",		FPU_ARCH_VFP_V2},
2018389857Sobrien  {"vfp10-r0",		FPU_ARCH_VFP_V1},
2018489857Sobrien  {"vfpxd",		FPU_ARCH_VFP_V1xD},
2018589857Sobrien  {"arm1020t",		FPU_ARCH_VFP_V1},
2018689857Sobrien  {"arm1020e",		FPU_ARCH_VFP_V2},
20187130561Sobrien  {"arm1136jfs",	FPU_ARCH_VFP_V2},
20188218822Sdim  {"arm1136jf-s",	FPU_ARCH_VFP_V2},
20189130561Sobrien  {"maverick",		FPU_ARCH_MAVERICK},
20190218822Sdim  {"neon",              FPU_ARCH_VFP_V3_PLUS_NEON_V1},
20191218822Sdim  {NULL,		ARM_ARCH_NONE}
2019289857Sobrien};
2019389857Sobrien
20194218822Sdimstruct arm_option_value_table
20195130561Sobrien{
20196130561Sobrien  char *name;
20197218822Sdim  long value;
20198130561Sobrien};
20199130561Sobrien
20200218822Sdimstatic const struct arm_option_value_table arm_float_abis[] =
20201130561Sobrien{
20202130561Sobrien  {"hard",	ARM_FLOAT_ABI_HARD},
20203130561Sobrien  {"softfp",	ARM_FLOAT_ABI_SOFTFP},
20204130561Sobrien  {"soft",	ARM_FLOAT_ABI_SOFT},
20205218822Sdim  {NULL,	0}
20206130561Sobrien};
20207130561Sobrien
20208218822Sdim#ifdef OBJ_ELF
20209218822Sdim/* We only know how to output GNU and ver 4/5 (AAELF) formats.  */
20210218822Sdimstatic const struct arm_option_value_table arm_eabis[] =
20211218822Sdim{
20212218822Sdim  {"gnu",	EF_ARM_EABI_UNKNOWN},
20213218822Sdim  {"4",		EF_ARM_EABI_VER4},
20214218822Sdim  {"5",		EF_ARM_EABI_VER5},
20215218822Sdim  {NULL,	0}
20216218822Sdim};
20217218822Sdim#endif
20218218822Sdim
2021989857Sobrienstruct arm_long_option_table
2022089857Sobrien{
20221218822Sdim  char * option;		/* Substring to match.	*/
20222218822Sdim  char * help;			/* Help information.  */
20223218822Sdim  int (* func) (char * subopt);	/* Function to decode sub-option.  */
20224218822Sdim  char * deprecated;		/* If non-null, print this message.  */
2022589857Sobrien};
2022689857Sobrien
2022789857Sobrienstatic int
20228218822Sdimarm_parse_extension (char * str, const arm_feature_set **opt_p)
2022989857Sobrien{
20230218822Sdim  arm_feature_set *ext_set = xmalloc (sizeof (arm_feature_set));
20231218822Sdim
20232218822Sdim  /* Copy the feature set, so that we can modify it.  */
20233218822Sdim  *ext_set = **opt_p;
20234218822Sdim  *opt_p = ext_set;
20235218822Sdim
2023689857Sobrien  while (str != NULL && *str != 0)
2023760484Sobrien    {
20238218822Sdim      const struct arm_option_cpu_value_table * opt;
20239218822Sdim      char * ext;
2024089857Sobrien      int optlen;
2024160484Sobrien
2024289857Sobrien      if (*str != '+')
2024360484Sobrien	{
2024489857Sobrien	  as_bad (_("invalid architectural extension"));
2024589857Sobrien	  return 0;
2024689857Sobrien	}
2024760484Sobrien
2024889857Sobrien      str++;
2024989857Sobrien      ext = strchr (str, '+');
2025060484Sobrien
2025189857Sobrien      if (ext != NULL)
2025289857Sobrien	optlen = ext - str;
2025389857Sobrien      else
2025489857Sobrien	optlen = strlen (str);
2025577298Sobrien
2025689857Sobrien      if (optlen == 0)
2025789857Sobrien	{
2025889857Sobrien	  as_bad (_("missing architectural extension"));
2025989857Sobrien	  return 0;
2026089857Sobrien	}
2026160484Sobrien
2026289857Sobrien      for (opt = arm_extensions; opt->name != NULL; opt++)
2026389857Sobrien	if (strncmp (opt->name, str, optlen) == 0)
2026489857Sobrien	  {
20265218822Sdim	    ARM_MERGE_FEATURE_SETS (*ext_set, *ext_set, opt->value);
2026689857Sobrien	    break;
2026789857Sobrien	  }
2026860484Sobrien
2026989857Sobrien      if (opt->name == NULL)
2027089857Sobrien	{
2027189857Sobrien	  as_bad (_("unknown architectural extnsion `%s'"), str);
2027289857Sobrien	  return 0;
2027389857Sobrien	}
2027477298Sobrien
2027589857Sobrien      str = ext;
2027689857Sobrien    };
2027760484Sobrien
2027889857Sobrien  return 1;
2027989857Sobrien}
2028060484Sobrien
2028189857Sobrienstatic int
20282218822Sdimarm_parse_cpu (char * str)
2028389857Sobrien{
20284218822Sdim  const struct arm_cpu_option_table * opt;
20285218822Sdim  char * ext = strchr (str, '+');
2028689857Sobrien  int optlen;
2028777298Sobrien
2028889857Sobrien  if (ext != NULL)
2028989857Sobrien    optlen = ext - str;
2029089857Sobrien  else
2029189857Sobrien    optlen = strlen (str);
2029277298Sobrien
2029389857Sobrien  if (optlen == 0)
2029489857Sobrien    {
2029589857Sobrien      as_bad (_("missing cpu name `%s'"), str);
2029689857Sobrien      return 0;
2029789857Sobrien    }
2029860484Sobrien
2029989857Sobrien  for (opt = arm_cpus; opt->name != NULL; opt++)
2030089857Sobrien    if (strncmp (opt->name, str, optlen) == 0)
2030189857Sobrien      {
20302218822Sdim	mcpu_cpu_opt = &opt->value;
20303218822Sdim	mcpu_fpu_opt = &opt->default_fpu;
20304218822Sdim	if (opt->canonical_name)
20305218822Sdim	  strcpy(selected_cpu_name, opt->canonical_name);
20306218822Sdim	else
20307218822Sdim	  {
20308218822Sdim	    int i;
20309218822Sdim	    for (i = 0; i < optlen; i++)
20310218822Sdim	      selected_cpu_name[i] = TOUPPER (opt->name[i]);
20311218822Sdim	    selected_cpu_name[i] = 0;
20312218822Sdim	  }
2031360484Sobrien
2031489857Sobrien	if (ext != NULL)
2031589857Sobrien	  return arm_parse_extension (ext, &mcpu_cpu_opt);
2031660484Sobrien
2031789857Sobrien	return 1;
2031889857Sobrien      }
2031960484Sobrien
2032089857Sobrien  as_bad (_("unknown cpu `%s'"), str);
2032189857Sobrien  return 0;
2032289857Sobrien}
2032360484Sobrien
2032489857Sobrienstatic int
20325218822Sdimarm_parse_arch (char * str)
2032689857Sobrien{
20327218822Sdim  const struct arm_arch_option_table *opt;
2032889857Sobrien  char *ext = strchr (str, '+');
2032989857Sobrien  int optlen;
2033060484Sobrien
2033189857Sobrien  if (ext != NULL)
2033289857Sobrien    optlen = ext - str;
2033389857Sobrien  else
2033489857Sobrien    optlen = strlen (str);
2033560484Sobrien
2033689857Sobrien  if (optlen == 0)
2033789857Sobrien    {
2033889857Sobrien      as_bad (_("missing architecture name `%s'"), str);
2033989857Sobrien      return 0;
2034089857Sobrien    }
2034177298Sobrien
2034289857Sobrien  for (opt = arm_archs; opt->name != NULL; opt++)
20343269797Sian    if (strncmp (opt->name, str, optlen) == 0)
2034489857Sobrien      {
20345218822Sdim	march_cpu_opt = &opt->value;
20346218822Sdim	march_fpu_opt = &opt->default_fpu;
20347218822Sdim	strcpy(selected_cpu_name, opt->name);
2034860484Sobrien
2034989857Sobrien	if (ext != NULL)
2035089857Sobrien	  return arm_parse_extension (ext, &march_cpu_opt);
2035177298Sobrien
2035289857Sobrien	return 1;
2035389857Sobrien      }
2035460484Sobrien
2035589857Sobrien  as_bad (_("unknown architecture `%s'\n"), str);
2035689857Sobrien  return 0;
2035789857Sobrien}
2035877298Sobrien
2035989857Sobrienstatic int
20360218822Sdimarm_parse_fpu (char * str)
2036189857Sobrien{
20362218822Sdim  const struct arm_option_cpu_value_table * opt;
2036377298Sobrien
2036489857Sobrien  for (opt = arm_fpus; opt->name != NULL; opt++)
20365218822Sdim    if (streq (opt->name, str))
2036689857Sobrien      {
20367218822Sdim	mfpu_opt = &opt->value;
2036889857Sobrien	return 1;
2036989857Sobrien      }
2037077298Sobrien
2037189857Sobrien  as_bad (_("unknown floating point format `%s'\n"), str);
2037289857Sobrien  return 0;
2037389857Sobrien}
2037477298Sobrien
20375130561Sobrienstatic int
20376218822Sdimarm_parse_float_abi (char * str)
20377130561Sobrien{
20378218822Sdim  const struct arm_option_value_table * opt;
20379130561Sobrien
20380130561Sobrien  for (opt = arm_float_abis; opt->name != NULL; opt++)
20381218822Sdim    if (streq (opt->name, str))
20382130561Sobrien      {
20383130561Sobrien	mfloat_abi_opt = opt->value;
20384130561Sobrien	return 1;
20385130561Sobrien      }
20386130561Sobrien
20387130561Sobrien  as_bad (_("unknown floating point abi `%s'\n"), str);
20388130561Sobrien  return 0;
20389130561Sobrien}
20390130561Sobrien
20391218822Sdim#ifdef OBJ_ELF
20392218822Sdimstatic int
20393218822Sdimarm_parse_eabi (char * str)
20394218822Sdim{
20395218822Sdim  const struct arm_option_value_table *opt;
20396218822Sdim
20397218822Sdim  for (opt = arm_eabis; opt->name != NULL; opt++)
20398218822Sdim    if (streq (opt->name, str))
20399218822Sdim      {
20400218822Sdim	meabi_flags = opt->value;
20401218822Sdim	return 1;
20402218822Sdim      }
20403218822Sdim  as_bad (_("unknown EABI `%s'\n"), str);
20404218822Sdim  return 0;
20405218822Sdim}
20406218822Sdim#endif
20407218822Sdim
2040889857Sobrienstruct arm_long_option_table arm_long_opts[] =
2040989857Sobrien{
2041089857Sobrien  {"mcpu=", N_("<cpu name>\t  assemble for CPU <cpu name>"),
2041189857Sobrien   arm_parse_cpu, NULL},
2041289857Sobrien  {"march=", N_("<arch name>\t  assemble for architecture <arch name>"),
2041389857Sobrien   arm_parse_arch, NULL},
2041489857Sobrien  {"mfpu=", N_("<fpu name>\t  assemble for FPU architecture <fpu name>"),
2041589857Sobrien   arm_parse_fpu, NULL},
20416130561Sobrien  {"mfloat-abi=", N_("<abi>\t  assemble for floating point ABI <abi>"),
20417130561Sobrien   arm_parse_float_abi, NULL},
20418218822Sdim#ifdef OBJ_ELF
20419218822Sdim  {"meabi=", N_("<ver>\t  assemble for eabi version <ver>"),
20420218822Sdim   arm_parse_eabi, NULL},
20421218822Sdim#endif
2042289857Sobrien  {NULL, NULL, 0, NULL}
2042389857Sobrien};
2042477298Sobrien
2042589857Sobrienint
20426218822Sdimmd_parse_option (int c, char * arg)
2042789857Sobrien{
2042889857Sobrien  struct arm_option_table *opt;
20429218822Sdim  const struct arm_legacy_option_table *fopt;
2043089857Sobrien  struct arm_long_option_table *lopt;
2043177298Sobrien
2043289857Sobrien  switch (c)
2043389857Sobrien    {
2043489857Sobrien#ifdef OPTION_EB
2043589857Sobrien    case OPTION_EB:
2043689857Sobrien      target_big_endian = 1;
2043789857Sobrien      break;
2043889857Sobrien#endif
2043960484Sobrien
2044089857Sobrien#ifdef OPTION_EL
2044189857Sobrien    case OPTION_EL:
2044289857Sobrien      target_big_endian = 0;
2044389857Sobrien      break;
2044489857Sobrien#endif
2044577298Sobrien
2044689857Sobrien    case 'a':
20447104834Sobrien      /* Listing option.  Just ignore these, we don't support additional
20448218822Sdim	 ones.	*/
2044989857Sobrien      return 0;
2045077298Sobrien
2045189857Sobrien    default:
2045289857Sobrien      for (opt = arm_opts; opt->option != NULL; opt++)
2045389857Sobrien	{
2045489857Sobrien	  if (c == opt->option[0]
2045589857Sobrien	      && ((arg == NULL && opt->option[1] == 0)
20456218822Sdim		  || streq (arg, opt->option + 1)))
2045789857Sobrien	    {
2045889857Sobrien#if WARN_DEPRECATED
2045989857Sobrien	      /* If the option is deprecated, tell the user.  */
2046089857Sobrien	      if (opt->deprecated != NULL)
2046189857Sobrien		as_tsktsk (_("option `-%c%s' is deprecated: %s"), c,
2046289857Sobrien			   arg ? arg : "", _(opt->deprecated));
2046389857Sobrien#endif
2046489857Sobrien
2046589857Sobrien	      if (opt->var != NULL)
2046689857Sobrien		*opt->var = opt->value;
2046789857Sobrien
2046889857Sobrien	      return 1;
2046960484Sobrien	    }
2047060484Sobrien	}
2047160484Sobrien
20472218822Sdim      for (fopt = arm_legacy_opts; fopt->option != NULL; fopt++)
20473218822Sdim	{
20474218822Sdim	  if (c == fopt->option[0]
20475218822Sdim	      && ((arg == NULL && fopt->option[1] == 0)
20476218822Sdim		  || streq (arg, fopt->option + 1)))
20477218822Sdim	    {
20478218822Sdim#if WARN_DEPRECATED
20479218822Sdim	      /* If the option is deprecated, tell the user.  */
20480218822Sdim	      if (fopt->deprecated != NULL)
20481218822Sdim		as_tsktsk (_("option `-%c%s' is deprecated: %s"), c,
20482218822Sdim			   arg ? arg : "", _(fopt->deprecated));
20483218822Sdim#endif
20484218822Sdim
20485218822Sdim	      if (fopt->var != NULL)
20486218822Sdim		*fopt->var = &fopt->value;
20487218822Sdim
20488218822Sdim	      return 1;
20489218822Sdim	    }
20490218822Sdim	}
20491218822Sdim
2049289857Sobrien      for (lopt = arm_long_opts; lopt->option != NULL; lopt++)
2049389857Sobrien	{
20494104834Sobrien	  /* These options are expected to have an argument.  */
2049589857Sobrien	  if (c == lopt->option[0]
2049689857Sobrien	      && arg != NULL
20497104834Sobrien	      && strncmp (arg, lopt->option + 1,
2049889857Sobrien			  strlen (lopt->option + 1)) == 0)
2049989857Sobrien	    {
2050089857Sobrien#if WARN_DEPRECATED
2050189857Sobrien	      /* If the option is deprecated, tell the user.  */
2050289857Sobrien	      if (lopt->deprecated != NULL)
2050389857Sobrien		as_tsktsk (_("option `-%c%s' is deprecated: %s"), c, arg,
2050489857Sobrien			   _(lopt->deprecated));
2050560484Sobrien#endif
2050677298Sobrien
2050789857Sobrien	      /* Call the sup-option parser.  */
20508218822Sdim	      return lopt->func (arg + strlen (lopt->option) - 1);
2050989857Sobrien	    }
2051089857Sobrien	}
2051189857Sobrien
2051260484Sobrien      return 0;
2051360484Sobrien    }
2051460484Sobrien
2051577298Sobrien  return 1;
2051660484Sobrien}
2051760484Sobrien
2051860484Sobrienvoid
20519218822Sdimmd_show_usage (FILE * fp)
2052060484Sobrien{
2052189857Sobrien  struct arm_option_table *opt;
2052289857Sobrien  struct arm_long_option_table *lopt;
2052389857Sobrien
2052489857Sobrien  fprintf (fp, _(" ARM-specific assembler options:\n"));
2052589857Sobrien
2052689857Sobrien  for (opt = arm_opts; opt->option != NULL; opt++)
2052789857Sobrien    if (opt->help != NULL)
2052889857Sobrien      fprintf (fp, "  -%-23s%s\n", opt->option, _(opt->help));
2052989857Sobrien
2053089857Sobrien  for (lopt = arm_long_opts; lopt->option != NULL; lopt++)
2053189857Sobrien    if (lopt->help != NULL)
2053289857Sobrien      fprintf (fp, "  -%s%s\n", lopt->option, _(lopt->help));
2053389857Sobrien
2053489857Sobrien#ifdef OPTION_EB
2053560484Sobrien  fprintf (fp, _("\
2053689857Sobrien  -EB                     assemble code for a big-endian cpu\n"));
2053777298Sobrien#endif
2053889857Sobrien
2053989857Sobrien#ifdef OPTION_EL
2054060484Sobrien  fprintf (fp, _("\
2054189857Sobrien  -EL                     assemble code for a little-endian cpu\n"));
2054260484Sobrien#endif
2054360484Sobrien}
2054460484Sobrien
2054560484Sobrien
20546218822Sdim#ifdef OBJ_ELF
20547218822Sdimtypedef struct
2054860484Sobrien{
20549218822Sdim  int val;
20550218822Sdim  arm_feature_set flags;
20551218822Sdim} cpu_arch_ver_table;
2055260484Sobrien
20553218822Sdim/* Mapping from CPU features to EABI CPU arch values.  Table must be sorted
20554218822Sdim   least features first.  */
20555218822Sdimstatic const cpu_arch_ver_table cpu_arch_ver[] =
2055660484Sobrien{
20557218822Sdim    {1, ARM_ARCH_V4},
20558218822Sdim    {2, ARM_ARCH_V4T},
20559218822Sdim    {3, ARM_ARCH_V5},
20560218822Sdim    {4, ARM_ARCH_V5TE},
20561218822Sdim    {5, ARM_ARCH_V5TEJ},
20562218822Sdim    {6, ARM_ARCH_V6},
20563218822Sdim    {7, ARM_ARCH_V6Z},
20564218822Sdim    {8, ARM_ARCH_V6K},
20565218822Sdim    {9, ARM_ARCH_V6T2},
20566218822Sdim    {10, ARM_ARCH_V7A},
20567218822Sdim    {10, ARM_ARCH_V7R},
20568218822Sdim    {10, ARM_ARCH_V7M},
20569218822Sdim    {0, ARM_ARCH_NONE}
20570218822Sdim};
2057177298Sobrien
20572218822Sdim/* Set the public EABI object attributes.  */
20573218822Sdimstatic void
20574218822Sdimaeabi_set_public_attributes (void)
2057560484Sobrien{
20576218822Sdim  int arch;
20577218822Sdim  arm_feature_set flags;
20578218822Sdim  arm_feature_set tmp;
20579218822Sdim  const cpu_arch_ver_table *p;
2058077298Sobrien
20581218822Sdim  /* Choose the architecture based on the capabilities of the requested cpu
20582218822Sdim     (if any) and/or the instructions actually used.  */
20583218822Sdim  ARM_MERGE_FEATURE_SETS (flags, arm_arch_used, thumb_arch_used);
20584218822Sdim  ARM_MERGE_FEATURE_SETS (flags, flags, *mfpu_opt);
20585218822Sdim  ARM_MERGE_FEATURE_SETS (flags, flags, selected_cpu);
20586218822Sdim  /*Allow the user to override the reported architecture.  */
20587218822Sdim  if (object_arch)
20588130561Sobrien    {
20589218822Sdim      ARM_CLEAR_FEATURE (flags, flags, arm_arch_any);
20590218822Sdim      ARM_MERGE_FEATURE_SETS (flags, flags, *object_arch);
20591130561Sobrien    }
2059260484Sobrien
20593218822Sdim  tmp = flags;
20594218822Sdim  arch = 0;
20595218822Sdim  for (p = cpu_arch_ver; p->val; p++)
2059660484Sobrien    {
20597218822Sdim      if (ARM_CPU_HAS_FEATURE (tmp, p->flags))
2059877298Sobrien	{
20599218822Sdim	  arch = p->val;
20600218822Sdim	  ARM_CLEAR_FEATURE (tmp, tmp, p->flags);
2060177298Sobrien	}
2060260484Sobrien    }
2060360484Sobrien
20604218822Sdim  /* Tag_CPU_name.  */
20605218822Sdim  if (selected_cpu_name[0])
2060660484Sobrien    {
20607218822Sdim      char *p;
20608218822Sdim
20609218822Sdim      p = selected_cpu_name;
20610218822Sdim      if (strncmp(p, "armv", 4) == 0)
2061177298Sobrien	{
20612218822Sdim	  int i;
20613218822Sdim
20614218822Sdim	  p += 4;
20615218822Sdim	  for (i = 0; p[i]; i++)
20616218822Sdim	    p[i] = TOUPPER (p[i]);
2061777298Sobrien	}
20618218822Sdim      bfd_elf_add_proc_attr_string (stdoutput, 5, p);
2061977298Sobrien    }
20620218822Sdim  /* Tag_CPU_arch.  */
20621218822Sdim  bfd_elf_add_proc_attr_int (stdoutput, 6, arch);
20622218822Sdim  /* Tag_CPU_arch_profile.  */
20623218822Sdim  if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7a))
20624218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 7, 'A');
20625218822Sdim  else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7r))
20626218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 7, 'R');
20627218822Sdim  else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7m))
20628218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 7, 'M');
20629218822Sdim  /* Tag_ARM_ISA_use.  */
20630218822Sdim  if (ARM_CPU_HAS_FEATURE (arm_arch_used, arm_arch_full))
20631218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 8, 1);
20632218822Sdim  /* Tag_THUMB_ISA_use.  */
20633218822Sdim  if (ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_full))
20634218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 9,
20635218822Sdim	ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_t2) ? 2 : 1);
20636218822Sdim  /* Tag_VFP_arch.  */
20637218822Sdim  if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v3)
20638218822Sdim      || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v3))
20639218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 10, 3);
20640218822Sdim  else if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v2)
20641218822Sdim           || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v2))
20642218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 10, 2);
20643218822Sdim  else if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v1)
20644218822Sdim           || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v1)
20645218822Sdim           || ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v1xd)
20646218822Sdim           || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v1xd))
20647218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 10, 1);
20648218822Sdim  /* Tag_WMMX_arch.  */
20649218822Sdim  if (ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_cext_iwmmxt)
20650218822Sdim      || ARM_CPU_HAS_FEATURE (arm_arch_used, arm_cext_iwmmxt))
20651218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 11, 1);
20652218822Sdim  /* Tag_NEON_arch.  */
20653218822Sdim  if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_neon_ext_v1)
20654218822Sdim      || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_neon_ext_v1))
20655218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 12, 1);
2065660484Sobrien}
2065760484Sobrien
20658218822Sdim/* Add the default contents for the .ARM.attributes section.  */
20659218822Sdimvoid
20660218822Sdimarm_md_end (void)
2066160484Sobrien{
20662218822Sdim  if (EF_ARM_EABI_VERSION (meabi_flags) < EF_ARM_EABI_VER4)
20663218822Sdim    return;
2066477298Sobrien
20665218822Sdim  aeabi_set_public_attributes ();
2066660484Sobrien}
20667218822Sdim#endif /* OBJ_ELF */
2066860484Sobrien
2066960484Sobrien
20670218822Sdim/* Parse a .cpu directive.  */
2067160484Sobrien
20672218822Sdimstatic void
20673218822Sdims_arm_cpu (int ignored ATTRIBUTE_UNUSED)
2067460484Sobrien{
20675218822Sdim  const struct arm_cpu_option_table *opt;
20676218822Sdim  char *name;
20677218822Sdim  char saved_char;
2067860484Sobrien
20679218822Sdim  name = input_line_pointer;
20680218822Sdim  while (*input_line_pointer && !ISSPACE(*input_line_pointer))
20681218822Sdim    input_line_pointer++;
20682218822Sdim  saved_char = *input_line_pointer;
20683218822Sdim  *input_line_pointer = 0;
20684130561Sobrien
20685218822Sdim  /* Skip the first "all" entry.  */
20686218822Sdim  for (opt = arm_cpus + 1; opt->name != NULL; opt++)
20687218822Sdim    if (streq (opt->name, name))
20688218822Sdim      {
20689218822Sdim	mcpu_cpu_opt = &opt->value;
20690218822Sdim	selected_cpu = opt->value;
20691218822Sdim	if (opt->canonical_name)
20692218822Sdim	  strcpy(selected_cpu_name, opt->canonical_name);
20693218822Sdim	else
20694218822Sdim	  {
20695218822Sdim	    int i;
20696218822Sdim	    for (i = 0; opt->name[i]; i++)
20697218822Sdim	      selected_cpu_name[i] = TOUPPER (opt->name[i]);
20698218822Sdim	    selected_cpu_name[i] = 0;
20699218822Sdim	  }
20700218822Sdim	ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
20701218822Sdim	*input_line_pointer = saved_char;
20702218822Sdim	demand_empty_rest_of_line ();
20703218822Sdim	return;
20704218822Sdim      }
20705218822Sdim  as_bad (_("unknown cpu `%s'"), name);
20706218822Sdim  *input_line_pointer = saved_char;
20707218822Sdim  ignore_rest_of_line ();
2070860484Sobrien}
2070960484Sobrien
2071077298Sobrien
20711218822Sdim/* Parse a .arch directive.  */
20712130561Sobrien
20713218822Sdimstatic void
20714218822Sdims_arm_arch (int ignored ATTRIBUTE_UNUSED)
2071560484Sobrien{
20716218822Sdim  const struct arm_arch_option_table *opt;
20717218822Sdim  char saved_char;
20718218822Sdim  char *name;
2071977298Sobrien
20720218822Sdim  name = input_line_pointer;
20721218822Sdim  while (*input_line_pointer && !ISSPACE(*input_line_pointer))
20722218822Sdim    input_line_pointer++;
20723218822Sdim  saved_char = *input_line_pointer;
20724218822Sdim  *input_line_pointer = 0;
2072577298Sobrien
20726218822Sdim  /* Skip the first "all" entry.  */
20727218822Sdim  for (opt = arm_archs + 1; opt->name != NULL; opt++)
20728218822Sdim    if (streq (opt->name, name))
20729218822Sdim      {
20730218822Sdim	mcpu_cpu_opt = &opt->value;
20731218822Sdim	selected_cpu = opt->value;
20732218822Sdim	strcpy(selected_cpu_name, opt->name);
20733218822Sdim	ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
20734218822Sdim	*input_line_pointer = saved_char;
20735218822Sdim	demand_empty_rest_of_line ();
20736218822Sdim	return;
20737218822Sdim      }
2073860484Sobrien
20739218822Sdim  as_bad (_("unknown architecture `%s'\n"), name);
20740218822Sdim  *input_line_pointer = saved_char;
20741218822Sdim  ignore_rest_of_line ();
2074260484Sobrien}
2074360484Sobrien
20744269797Sian/* Parse a .arch_extension directive.  */
2074560484Sobrien
20746269797Sianstatic void
20747269797Sians_arm_arch_extension (int ignored ATTRIBUTE_UNUSED)
20748269797Sian{
20749269797Sian  const struct arm_option_cpu_value_table *opt;
20750269797Sian  char saved_char;
20751269797Sian  char *name;
20752269797Sian
20753269797Sian  name = input_line_pointer;
20754269797Sian  while (*input_line_pointer && !ISSPACE(*input_line_pointer))
20755269797Sian    input_line_pointer++;
20756269797Sian  saved_char = *input_line_pointer;
20757269797Sian  *input_line_pointer = 0;
20758269797Sian
20759269797Sian  for (opt = arm_extensions; opt->name != NULL; opt++)
20760269797Sian    if (streq (opt->name, name))
20761269797Sian      {
20762269797Sian	ARM_MERGE_FEATURE_SETS (cpu_variant, cpu_variant, opt->value);
20763269797Sian	*input_line_pointer = saved_char;
20764269797Sian	demand_empty_rest_of_line ();
20765269797Sian	return;
20766269797Sian      }
20767269797Sian
20768269797Sian  as_bad (_("unknown architecture `%s'\n"), name);
20769269797Sian  *input_line_pointer = saved_char;
20770269797Sian  ignore_rest_of_line ();
20771269797Sian}
20772269797Sian
20773218822Sdim/* Parse a .object_arch directive.  */
2077460484Sobrien
2077560484Sobrienstatic void
20776218822Sdims_arm_object_arch (int ignored ATTRIBUTE_UNUSED)
2077760484Sobrien{
20778218822Sdim  const struct arm_arch_option_table *opt;
20779218822Sdim  char saved_char;
20780218822Sdim  char *name;
2078160484Sobrien
20782218822Sdim  name = input_line_pointer;
20783218822Sdim  while (*input_line_pointer && !ISSPACE(*input_line_pointer))
20784218822Sdim    input_line_pointer++;
20785218822Sdim  saved_char = *input_line_pointer;
20786218822Sdim  *input_line_pointer = 0;
2078760484Sobrien
20788218822Sdim  /* Skip the first "all" entry.  */
20789218822Sdim  for (opt = arm_archs + 1; opt->name != NULL; opt++)
20790218822Sdim    if (streq (opt->name, name))
20791218822Sdim      {
20792218822Sdim	object_arch = &opt->value;
20793218822Sdim	*input_line_pointer = saved_char;
20794218822Sdim	demand_empty_rest_of_line ();
20795218822Sdim	return;
20796218822Sdim      }
2079760484Sobrien
20798218822Sdim  as_bad (_("unknown architecture `%s'\n"), name);
20799218822Sdim  *input_line_pointer = saved_char;
20800218822Sdim  ignore_rest_of_line ();
2080160484Sobrien}
2080260484Sobrien
2080378828Sobrien
20804218822Sdim/* Parse a .fpu directive.  */
2080578828Sobrien
20806218822Sdimstatic void
20807218822Sdims_arm_fpu (int ignored ATTRIBUTE_UNUSED)
2080878828Sobrien{
20809218822Sdim  const struct arm_option_cpu_value_table *opt;
20810218822Sdim  char saved_char;
20811218822Sdim  char *name;
2081278828Sobrien
20813218822Sdim  name = input_line_pointer;
20814218822Sdim  while (*input_line_pointer && !ISSPACE(*input_line_pointer))
20815218822Sdim    input_line_pointer++;
20816218822Sdim  saved_char = *input_line_pointer;
20817218822Sdim  *input_line_pointer = 0;
20818218822Sdim
20819218822Sdim  for (opt = arm_fpus; opt->name != NULL; opt++)
20820218822Sdim    if (streq (opt->name, name))
20821218822Sdim      {
20822218822Sdim	mfpu_opt = &opt->value;
20823218822Sdim	ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
20824218822Sdim	*input_line_pointer = saved_char;
20825218822Sdim	demand_empty_rest_of_line ();
20826218822Sdim	return;
20827218822Sdim      }
20828104834Sobrien
20829218822Sdim  as_bad (_("unknown floating point format `%s'\n"), name);
20830218822Sdim  *input_line_pointer = saved_char;
20831218822Sdim  ignore_rest_of_line ();
2083278828Sobrien}
2083378828Sobrien
20834218822Sdim/* Copy symbol information.  */
2083578828Sobrienvoid
20836218822Sdimarm_copy_symbol_attributes (symbolS *dest, symbolS *src)
2083778828Sobrien{
20838218822Sdim  ARM_GET_FLAG (dest) = ARM_GET_FLAG (src);
2083978828Sobrien}
20840