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")
654218822Sdim#define BAD_COND	_("instruction cannot be conditional")
655218822Sdim#define BAD_OVERLAP	_("registers may not be the same")
656218822Sdim#define BAD_HIREG	_("lo register required")
657218822Sdim#define BAD_THUMB32	_("instruction not supported in Thumb16 mode")
658218822Sdim#define BAD_ADDR_MODE   _("instruction does not accept this addressing mode");
659218822Sdim#define BAD_BRANCH	_("branch must be last instruction in IT block")
660218822Sdim#define BAD_NOT_IT	_("instruction not allowed in IT block")
661218822Sdim#define BAD_FPU		_("selected FPU does not support instruction")
66277298Sobrien
663218822Sdimstatic struct hash_control *arm_ops_hsh;
664218822Sdimstatic struct hash_control *arm_cond_hsh;
665218822Sdimstatic struct hash_control *arm_shift_hsh;
666218822Sdimstatic struct hash_control *arm_psr_hsh;
667218822Sdimstatic struct hash_control *arm_v7m_psr_hsh;
668218822Sdimstatic struct hash_control *arm_reg_hsh;
669218822Sdimstatic struct hash_control *arm_reloc_hsh;
670218822Sdimstatic struct hash_control *arm_barrier_opt_hsh;
67177298Sobrien
672218822Sdim/* Stuff needed to resolve the label ambiguity
673218822Sdim   As:
674218822Sdim     ...
675218822Sdim     label:   <insn>
676218822Sdim   may differ from:
677218822Sdim     ...
678218822Sdim     label:
679218822Sdim	      <insn>
680218822Sdim*/
68189857Sobrien
682218822SdimsymbolS *  last_label_seen;
683218822Sdimstatic int label_is_thumb_function_name = FALSE;
684218822Sdim
685218822Sdim/* Literal pool structure.  Held on a per-section
686218822Sdim   and per-sub-section basis.  */
68789857Sobrien
688218822Sdim#define MAX_LITERAL_POOL_SIZE 1024
689218822Sdimtypedef struct literal_pool
690218822Sdim{
691218822Sdim  expressionS	 literals [MAX_LITERAL_POOL_SIZE];
692218822Sdim  unsigned int	 next_free_entry;
693218822Sdim  unsigned int	 id;
694218822Sdim  symbolS *	 symbol;
695218822Sdim  segT		 section;
696218822Sdim  subsegT	 sub_section;
697218822Sdim  struct literal_pool * next;
698218822Sdim} literal_pool;
69989857Sobrien
700218822Sdim/* Pointer to a linked list of literal pools.  */
701218822Sdimliteral_pool * list_of_pools = NULL;
70289857Sobrien
703218822Sdim/* State variables for IT block handling.  */
704218822Sdimstatic bfd_boolean current_it_mask = 0;
705218822Sdimstatic int current_cc;
70689857Sobrien
707218822Sdim
708218822Sdim/* Pure syntax.	 */
70989857Sobrien
710218822Sdim/* This array holds the chars that always start a comment.  If the
711218822Sdim   pre-processor is disabled, these aren't very useful.	 */
712218822Sdimconst char comment_chars[] = "@";
713130561Sobrien
714218822Sdim/* This array holds the chars that only start a comment at the beginning of
715218822Sdim   a line.  If the line seems to have the form '# 123 filename'
716218822Sdim   .line and .file directives will appear in the pre-processed output.	*/
717218822Sdim/* Note that input_file.c hand checks for '#' at the beginning of the
718218822Sdim   first line of the input file.  This is because the compiler outputs
719218822Sdim   #NO_APP at the beginning of its output.  */
720218822Sdim/* Also note that comments like this one will always work.  */
721218822Sdimconst char line_comment_chars[] = "#";
722130561Sobrien
723218822Sdimconst char line_separator_chars[] = ";";
72460484Sobrien
725218822Sdim/* Chars that can be used to separate mant
726218822Sdim   from exp in floating point numbers.	*/
727218822Sdimconst char EXP_CHARS[] = "eE";
72889857Sobrien
729218822Sdim/* Chars that mean this number is a floating point constant.  */
730218822Sdim/* As in 0f12.456  */
731218822Sdim/* or	 0d1.2345e12  */
73289857Sobrien
733218822Sdimconst char FLT_CHARS[] = "rRsSfFdDxXeEpP";
73489857Sobrien
735218822Sdim/* Prefix characters that indicate the start of an immediate
736218822Sdim   value.  */
737218822Sdim#define is_immediate_prefix(C) ((C) == '#' || (C) == '$')
73889857Sobrien
739218822Sdim/* Separator character handling.  */
74089857Sobrien
741218822Sdim#define skip_whitespace(str)  do { if (*(str) == ' ') ++(str); } while (0)
74260484Sobrien
743218822Sdimstatic inline int
744218822Sdimskip_past_char (char ** str, char c)
745218822Sdim{
746218822Sdim  if (**str == c)
747218822Sdim    {
748218822Sdim      (*str)++;
749218822Sdim      return SUCCESS;
750218822Sdim    }
751218822Sdim  else
752218822Sdim    return FAIL;
753218822Sdim}
754218822Sdim#define skip_past_comma(str) skip_past_char (str, ',')
755130561Sobrien
756218822Sdim/* Arithmetic expressions (possibly involving symbols).	 */
75760484Sobrien
758218822Sdim/* Return TRUE if anything in the expression is a bignum.  */
75960484Sobrien
760218822Sdimstatic int
761218822Sdimwalk_no_bignums (symbolS * sp)
762218822Sdim{
763218822Sdim  if (symbol_get_value_expression (sp)->X_op == O_big)
764218822Sdim    return 1;
76589857Sobrien
766218822Sdim  if (symbol_get_value_expression (sp)->X_add_symbol)
767218822Sdim    {
768218822Sdim      return (walk_no_bignums (symbol_get_value_expression (sp)->X_add_symbol)
769218822Sdim	      || (symbol_get_value_expression (sp)->X_op_symbol
770218822Sdim		  && walk_no_bignums (symbol_get_value_expression (sp)->X_op_symbol)));
771218822Sdim    }
77289857Sobrien
773218822Sdim  return 0;
774218822Sdim}
77589857Sobrien
776218822Sdimstatic int in_my_get_expression = 0;
77789857Sobrien
778218822Sdim/* Third argument to my_get_expression.	 */
779218822Sdim#define GE_NO_PREFIX 0
780218822Sdim#define GE_IMM_PREFIX 1
781218822Sdim#define GE_OPT_PREFIX 2
782218822Sdim/* This is a bit of a hack. Use an optional prefix, and also allow big (64-bit)
783218822Sdim   immediates, as can be used in Neon VMVN and VMOV immediate instructions.  */
784218822Sdim#define GE_OPT_PREFIX_BIG 3
78589857Sobrien
786218822Sdimstatic int
787218822Sdimmy_get_expression (expressionS * ep, char ** str, int prefix_mode)
78877298Sobrien{
789218822Sdim  char * save_in;
790218822Sdim  segT	 seg;
79160484Sobrien
792218822Sdim  /* In unified syntax, all prefixes are optional.  */
793218822Sdim  if (unified_syntax)
794218822Sdim    prefix_mode = (prefix_mode == GE_OPT_PREFIX_BIG) ? prefix_mode
795218822Sdim                  : GE_OPT_PREFIX;
79660484Sobrien
797218822Sdim  switch (prefix_mode)
798218822Sdim    {
799218822Sdim    case GE_NO_PREFIX: break;
800218822Sdim    case GE_IMM_PREFIX:
801218822Sdim      if (!is_immediate_prefix (**str))
802218822Sdim	{
803218822Sdim	  inst.error = _("immediate expression requires a # prefix");
804218822Sdim	  return FAIL;
805218822Sdim	}
806218822Sdim      (*str)++;
807218822Sdim      break;
808218822Sdim    case GE_OPT_PREFIX:
809218822Sdim    case GE_OPT_PREFIX_BIG:
810218822Sdim      if (is_immediate_prefix (**str))
811218822Sdim	(*str)++;
812218822Sdim      break;
813218822Sdim    default: abort ();
814218822Sdim    }
81560484Sobrien
816218822Sdim  memset (ep, 0, sizeof (expressionS));
81760484Sobrien
818218822Sdim  save_in = input_line_pointer;
819218822Sdim  input_line_pointer = *str;
820218822Sdim  in_my_get_expression = 1;
821218822Sdim  seg = expression (ep);
822218822Sdim  in_my_get_expression = 0;
82360484Sobrien
824218822Sdim  if (ep->X_op == O_illegal)
825218822Sdim    {
826218822Sdim      /* We found a bad expression in md_operand().  */
827218822Sdim      *str = input_line_pointer;
828218822Sdim      input_line_pointer = save_in;
829218822Sdim      if (inst.error == NULL)
830218822Sdim	inst.error = _("bad expression");
831218822Sdim      return 1;
832218822Sdim    }
833218822Sdim
834218822Sdim#ifdef OBJ_AOUT
835218822Sdim  if (seg != absolute_section
836218822Sdim      && seg != text_section
837218822Sdim      && seg != data_section
838218822Sdim      && seg != bss_section
839218822Sdim      && seg != undefined_section)
840218822Sdim    {
841218822Sdim      inst.error = _("bad segment");
842218822Sdim      *str = input_line_pointer;
843218822Sdim      input_line_pointer = save_in;
844218822Sdim      return 1;
845218822Sdim    }
846218822Sdim#endif
847218822Sdim
848218822Sdim  /* Get rid of any bignums now, so that we don't generate an error for which
849218822Sdim     we can't establish a line number later on.	 Big numbers are never valid
850218822Sdim     in instructions, which is where this routine is always called.  */
851218822Sdim  if (prefix_mode != GE_OPT_PREFIX_BIG
852218822Sdim      && (ep->X_op == O_big
853218822Sdim          || (ep->X_add_symbol
854218822Sdim	      && (walk_no_bignums (ep->X_add_symbol)
855218822Sdim	          || (ep->X_op_symbol
856218822Sdim		      && walk_no_bignums (ep->X_op_symbol))))))
857218822Sdim    {
858218822Sdim      inst.error = _("invalid constant");
859218822Sdim      *str = input_line_pointer;
860218822Sdim      input_line_pointer = save_in;
861218822Sdim      return 1;
862218822Sdim    }
863218822Sdim
864218822Sdim  *str = input_line_pointer;
865218822Sdim  input_line_pointer = save_in;
866218822Sdim  return 0;
867218822Sdim}
868218822Sdim
869218822Sdim/* Turn a string in input_line_pointer into a floating point constant
870218822Sdim   of type TYPE, and store the appropriate bytes in *LITP.  The number
871218822Sdim   of LITTLENUMS emitted is stored in *SIZEP.  An error message is
872218822Sdim   returned, or NULL on OK.
873218822Sdim
874218822Sdim   Note that fp constants aren't represent in the normal way on the ARM.
875218822Sdim   In big endian mode, things are as expected.	However, in little endian
876218822Sdim   mode fp constants are big-endian word-wise, and little-endian byte-wise
877218822Sdim   within the words.  For example, (double) 1.1 in big endian mode is
878218822Sdim   the byte sequence 3f f1 99 99 99 99 99 9a, and in little endian mode is
879218822Sdim   the byte sequence 99 99 f1 3f 9a 99 99 99.
880218822Sdim
881218822Sdim   ??? The format of 12 byte floats is uncertain according to gcc's arm.h.  */
882218822Sdim
883218822Sdimchar *
884218822Sdimmd_atof (int type, char * litP, int * sizeP)
88560484Sobrien{
886218822Sdim  int prec;
887218822Sdim  LITTLENUM_TYPE words[MAX_LITTLENUMS];
888218822Sdim  char *t;
889218822Sdim  int i;
89077298Sobrien
891218822Sdim  switch (type)
892218822Sdim    {
893218822Sdim    case 'f':
894218822Sdim    case 'F':
895218822Sdim    case 's':
896218822Sdim    case 'S':
897218822Sdim      prec = 2;
898218822Sdim      break;
89989857Sobrien
900218822Sdim    case 'd':
901218822Sdim    case 'D':
902218822Sdim    case 'r':
903218822Sdim    case 'R':
904218822Sdim      prec = 4;
905218822Sdim      break;
90689857Sobrien
907218822Sdim    case 'x':
908218822Sdim    case 'X':
909218822Sdim      prec = 6;
910218822Sdim      break;
91189857Sobrien
912218822Sdim    case 'p':
913218822Sdim    case 'P':
914218822Sdim      prec = 6;
915218822Sdim      break;
91689857Sobrien
917218822Sdim    default:
918218822Sdim      *sizeP = 0;
919218822Sdim      return _("bad call to MD_ATOF()");
920218822Sdim    }
92189857Sobrien
922218822Sdim  t = atof_ieee (input_line_pointer, type, words);
923218822Sdim  if (t)
924218822Sdim    input_line_pointer = t;
925218822Sdim  *sizeP = prec * 2;
92677298Sobrien
927218822Sdim  if (target_big_endian)
928218822Sdim    {
929218822Sdim      for (i = 0; i < prec; i++)
930218822Sdim	{
931218822Sdim	  md_number_to_chars (litP, (valueT) words[i], 2);
932218822Sdim	  litP += 2;
933218822Sdim	}
934218822Sdim    }
935218822Sdim  else
936218822Sdim    {
937218822Sdim      if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_endian_pure))
938218822Sdim	for (i = prec - 1; i >= 0; i--)
939218822Sdim	  {
940218822Sdim	    md_number_to_chars (litP, (valueT) words[i], 2);
941218822Sdim	    litP += 2;
942218822Sdim	  }
943218822Sdim      else
944218822Sdim	/* For a 4 byte float the order of elements in `words' is 1 0.
945218822Sdim	   For an 8 byte float the order is 1 0 3 2.  */
946218822Sdim	for (i = 0; i < prec; i += 2)
947218822Sdim	  {
948218822Sdim	    md_number_to_chars (litP, (valueT) words[i + 1], 2);
949218822Sdim	    md_number_to_chars (litP + 2, (valueT) words[i], 2);
950218822Sdim	    litP += 4;
951218822Sdim	  }
952218822Sdim    }
95360484Sobrien
954218822Sdim  return 0;
955218822Sdim}
95660484Sobrien
957218822Sdim/* We handle all bad expressions here, so that we can report the faulty
958218822Sdim   instruction in the error message.  */
959218822Sdimvoid
960218822Sdimmd_operand (expressionS * expr)
961218822Sdim{
962218822Sdim  if (in_my_get_expression)
963218822Sdim    expr->X_op = O_illegal;
964218822Sdim}
96560484Sobrien
966218822Sdim/* Immediate values.  */
96760484Sobrien
968218822Sdim/* Generic immediate-value read function for use in directives.
969218822Sdim   Accepts anything that 'expression' can fold to a constant.
970218822Sdim   *val receives the number.  */
971218822Sdim#ifdef OBJ_ELF
972218822Sdimstatic int
973218822Sdimimmediate_for_directive (int *val)
974218822Sdim{
975218822Sdim  expressionS exp;
976218822Sdim  exp.X_op = O_illegal;
97760484Sobrien
978218822Sdim  if (is_immediate_prefix (*input_line_pointer))
979218822Sdim    {
980218822Sdim      input_line_pointer++;
981218822Sdim      expression (&exp);
982218822Sdim    }
98360484Sobrien
984218822Sdim  if (exp.X_op != O_constant)
985218822Sdim    {
986218822Sdim      as_bad (_("expected #constant"));
987218822Sdim      ignore_rest_of_line ();
988218822Sdim      return FAIL;
989218822Sdim    }
990218822Sdim  *val = exp.X_add_number;
991218822Sdim  return SUCCESS;
992218822Sdim}
993218822Sdim#endif
99460484Sobrien
995218822Sdim/* Register parsing.  */
99677298Sobrien
997218822Sdim/* Generic register parser.  CCP points to what should be the
998218822Sdim   beginning of a register name.  If it is indeed a valid register
999218822Sdim   name, advance CCP over it and return the reg_entry structure;
1000218822Sdim   otherwise return NULL.  Does not issue diagnostics.	*/
100177298Sobrien
1002218822Sdimstatic struct reg_entry *
1003218822Sdimarm_reg_parse_multi (char **ccp)
1004218822Sdim{
1005218822Sdim  char *start = *ccp;
1006218822Sdim  char *p;
1007218822Sdim  struct reg_entry *reg;
100877298Sobrien
1009218822Sdim#ifdef REGISTER_PREFIX
1010218822Sdim  if (*start != REGISTER_PREFIX)
1011218822Sdim    return NULL;
1012218822Sdim  start++;
1013218822Sdim#endif
1014218822Sdim#ifdef OPTIONAL_REGISTER_PREFIX
1015218822Sdim  if (*start == OPTIONAL_REGISTER_PREFIX)
1016218822Sdim    start++;
1017218822Sdim#endif
101877298Sobrien
1019218822Sdim  p = start;
1020218822Sdim  if (!ISALPHA (*p) || !is_name_beginner (*p))
1021218822Sdim    return NULL;
102277298Sobrien
1023218822Sdim  do
1024218822Sdim    p++;
1025218822Sdim  while (ISALPHA (*p) || ISDIGIT (*p) || *p == '_');
102677298Sobrien
1027218822Sdim  reg = (struct reg_entry *) hash_find_n (arm_reg_hsh, start, p - start);
102877298Sobrien
1029218822Sdim  if (!reg)
1030218822Sdim    return NULL;
103177298Sobrien
1032218822Sdim  *ccp = p;
1033218822Sdim  return reg;
1034218822Sdim}
103589857Sobrien
1036218822Sdimstatic int
1037218822Sdimarm_reg_alt_syntax (char **ccp, char *start, struct reg_entry *reg,
1038218822Sdim                    enum arm_reg_type type)
1039218822Sdim{
1040218822Sdim  /* Alternative syntaxes are accepted for a few register classes.  */
1041218822Sdim  switch (type)
1042218822Sdim    {
1043218822Sdim    case REG_TYPE_MVF:
1044218822Sdim    case REG_TYPE_MVD:
1045218822Sdim    case REG_TYPE_MVFX:
1046218822Sdim    case REG_TYPE_MVDX:
1047218822Sdim      /* Generic coprocessor register names are allowed for these.  */
1048218822Sdim      if (reg && reg->type == REG_TYPE_CN)
1049218822Sdim	return reg->number;
1050218822Sdim      break;
105189857Sobrien
1052218822Sdim    case REG_TYPE_CP:
1053218822Sdim      /* For backward compatibility, a bare number is valid here.  */
1054218822Sdim      {
1055218822Sdim	unsigned long processor = strtoul (start, ccp, 10);
1056218822Sdim	if (*ccp != start && processor <= 15)
1057218822Sdim	  return processor;
1058218822Sdim      }
105989857Sobrien
1060218822Sdim    case REG_TYPE_MMXWC:
1061218822Sdim      /* WC includes WCG.  ??? I'm not sure this is true for all
1062218822Sdim	 instructions that take WC registers.  */
1063218822Sdim      if (reg && reg->type == REG_TYPE_MMXWCG)
1064218822Sdim	return reg->number;
1065218822Sdim      break;
1066130561Sobrien
1067218822Sdim    default:
1068218822Sdim      break;
1069218822Sdim    }
107089857Sobrien
1071218822Sdim  return FAIL;
1072218822Sdim}
107389857Sobrien
1074218822Sdim/* As arm_reg_parse_multi, but the register must be of type TYPE, and the
1075218822Sdim   return value is the register number or FAIL.  */
107689857Sobrien
1077218822Sdimstatic int
1078218822Sdimarm_reg_parse (char **ccp, enum arm_reg_type type)
1079218822Sdim{
1080218822Sdim  char *start = *ccp;
1081218822Sdim  struct reg_entry *reg = arm_reg_parse_multi (ccp);
1082218822Sdim  int ret;
108389857Sobrien
1084218822Sdim  /* Do not allow a scalar (reg+index) to parse as a register.  */
1085218822Sdim  if (reg && reg->neon && (reg->neon->defined & NTA_HASINDEX))
1086218822Sdim    return FAIL;
108789857Sobrien
1088218822Sdim  if (reg && reg->type == type)
1089218822Sdim    return reg->number;
109089857Sobrien
1091218822Sdim  if ((ret = arm_reg_alt_syntax (ccp, start, reg, type)) != FAIL)
1092218822Sdim    return ret;
109389857Sobrien
1094218822Sdim  *ccp = start;
1095218822Sdim  return FAIL;
1096218822Sdim}
109789857Sobrien
1098218822Sdim/* Parse a Neon type specifier. *STR should point at the leading '.'
1099218822Sdim   character. Does no verification at this stage that the type fits the opcode
1100218822Sdim   properly. E.g.,
110189857Sobrien
1102218822Sdim     .i32.i32.s16
1103218822Sdim     .s32.f32
1104218822Sdim     .u16
110589857Sobrien
1106218822Sdim   Can all be legally parsed by this function.
110789857Sobrien
1108218822Sdim   Fills in neon_type struct pointer with parsed information, and updates STR
1109218822Sdim   to point after the parsed type specifier. Returns SUCCESS if this was a legal
1110218822Sdim   type, FAIL if not.  */
111189857Sobrien
1112218822Sdimstatic int
1113218822Sdimparse_neon_type (struct neon_type *type, char **str)
1114218822Sdim{
1115218822Sdim  char *ptr = *str;
111689857Sobrien
1117218822Sdim  if (type)
1118218822Sdim    type->elems = 0;
111989857Sobrien
1120218822Sdim  while (type->elems < NEON_MAX_TYPE_ELS)
1121218822Sdim    {
1122218822Sdim      enum neon_el_type thistype = NT_untyped;
1123218822Sdim      unsigned thissize = -1u;
112489857Sobrien
1125218822Sdim      if (*ptr != '.')
1126218822Sdim	break;
112789857Sobrien
1128218822Sdim      ptr++;
112989857Sobrien
1130218822Sdim      /* Just a size without an explicit type.  */
1131218822Sdim      if (ISDIGIT (*ptr))
1132218822Sdim	goto parsesize;
113389857Sobrien
1134218822Sdim      switch (TOLOWER (*ptr))
1135218822Sdim	{
1136218822Sdim	case 'i': thistype = NT_integer; break;
1137218822Sdim	case 'f': thistype = NT_float; break;
1138218822Sdim	case 'p': thistype = NT_poly; break;
1139218822Sdim	case 's': thistype = NT_signed; break;
1140218822Sdim	case 'u': thistype = NT_unsigned; break;
1141218822Sdim        case 'd':
1142218822Sdim          thistype = NT_float;
1143218822Sdim          thissize = 64;
1144218822Sdim          ptr++;
1145218822Sdim          goto done;
1146218822Sdim	default:
1147218822Sdim	  as_bad (_("unexpected character `%c' in type specifier"), *ptr);
1148218822Sdim	  return FAIL;
1149218822Sdim	}
115089857Sobrien
1151218822Sdim      ptr++;
115289857Sobrien
1153218822Sdim      /* .f is an abbreviation for .f32.  */
1154218822Sdim      if (thistype == NT_float && !ISDIGIT (*ptr))
1155218822Sdim	thissize = 32;
1156218822Sdim      else
1157218822Sdim	{
1158218822Sdim	parsesize:
1159218822Sdim	  thissize = strtoul (ptr, &ptr, 10);
116089857Sobrien
1161218822Sdim	  if (thissize != 8 && thissize != 16 && thissize != 32
1162218822Sdim              && thissize != 64)
1163218822Sdim            {
1164218822Sdim              as_bad (_("bad size %d in type specifier"), thissize);
1165218822Sdim	      return FAIL;
1166218822Sdim	    }
1167218822Sdim	}
116889857Sobrien
1169218822Sdim      done:
1170218822Sdim      if (type)
1171218822Sdim        {
1172218822Sdim          type->el[type->elems].type = thistype;
1173218822Sdim	  type->el[type->elems].size = thissize;
1174218822Sdim	  type->elems++;
1175218822Sdim	}
1176218822Sdim    }
117789857Sobrien
1178218822Sdim  /* Empty/missing type is not a successful parse.  */
1179218822Sdim  if (type->elems == 0)
1180218822Sdim    return FAIL;
118189857Sobrien
1182218822Sdim  *str = ptr;
118389857Sobrien
1184218822Sdim  return SUCCESS;
1185218822Sdim}
118689857Sobrien
1187218822Sdim/* Errors may be set multiple times during parsing or bit encoding
1188218822Sdim   (particularly in the Neon bits), but usually the earliest error which is set
1189218822Sdim   will be the most meaningful. Avoid overwriting it with later (cascading)
1190218822Sdim   errors by calling this function.  */
119189857Sobrien
1192218822Sdimstatic void
1193218822Sdimfirst_error (const char *err)
1194218822Sdim{
1195218822Sdim  if (!inst.error)
1196218822Sdim    inst.error = err;
1197218822Sdim}
119889857Sobrien
1199218822Sdim/* Parse a single type, e.g. ".s32", leading period included.  */
1200218822Sdimstatic int
1201218822Sdimparse_neon_operand_type (struct neon_type_el *vectype, char **ccp)
1202218822Sdim{
1203218822Sdim  char *str = *ccp;
1204218822Sdim  struct neon_type optype;
120589857Sobrien
1206218822Sdim  if (*str == '.')
1207218822Sdim    {
1208218822Sdim      if (parse_neon_type (&optype, &str) == SUCCESS)
1209218822Sdim        {
1210218822Sdim          if (optype.elems == 1)
1211218822Sdim            *vectype = optype.el[0];
1212218822Sdim          else
1213218822Sdim            {
1214218822Sdim              first_error (_("only one type should be specified for operand"));
1215218822Sdim              return FAIL;
1216218822Sdim            }
1217218822Sdim        }
1218218822Sdim      else
1219218822Sdim        {
1220218822Sdim          first_error (_("vector type expected"));
1221218822Sdim          return FAIL;
1222218822Sdim        }
1223218822Sdim    }
1224218822Sdim  else
1225218822Sdim    return FAIL;
1226218822Sdim
1227218822Sdim  *ccp = str;
1228218822Sdim
1229218822Sdim  return SUCCESS;
1230218822Sdim}
123189857Sobrien
1232218822Sdim/* Special meanings for indices (which have a range of 0-7), which will fit into
1233218822Sdim   a 4-bit integer.  */
123489857Sobrien
1235218822Sdim#define NEON_ALL_LANES		15
1236218822Sdim#define NEON_INTERLEAVE_LANES	14
123789857Sobrien
1238218822Sdim/* Parse either a register or a scalar, with an optional type. Return the
1239218822Sdim   register number, and optionally fill in the actual type of the register
1240218822Sdim   when multiple alternatives were given (NEON_TYPE_NDQ) in *RTYPE, and
1241218822Sdim   type/index information in *TYPEINFO.  */
124289857Sobrien
1243218822Sdimstatic int
1244218822Sdimparse_typed_reg_or_scalar (char **ccp, enum arm_reg_type type,
1245218822Sdim                           enum arm_reg_type *rtype,
1246218822Sdim                           struct neon_typed_alias *typeinfo)
1247218822Sdim{
1248218822Sdim  char *str = *ccp;
1249218822Sdim  struct reg_entry *reg = arm_reg_parse_multi (&str);
1250218822Sdim  struct neon_typed_alias atype;
1251218822Sdim  struct neon_type_el parsetype;
125289857Sobrien
1253218822Sdim  atype.defined = 0;
1254218822Sdim  atype.index = -1;
1255218822Sdim  atype.eltype.type = NT_invtype;
1256218822Sdim  atype.eltype.size = -1;
125789857Sobrien
1258218822Sdim  /* Try alternate syntax for some types of register. Note these are mutually
1259218822Sdim     exclusive with the Neon syntax extensions.  */
1260218822Sdim  if (reg == NULL)
1261218822Sdim    {
1262218822Sdim      int altreg = arm_reg_alt_syntax (&str, *ccp, reg, type);
1263218822Sdim      if (altreg != FAIL)
1264218822Sdim        *ccp = str;
1265218822Sdim      if (typeinfo)
1266218822Sdim        *typeinfo = atype;
1267218822Sdim      return altreg;
1268218822Sdim    }
126989857Sobrien
1270218822Sdim  /* Undo polymorphism when a set of register types may be accepted.  */
1271218822Sdim  if ((type == REG_TYPE_NDQ
1272218822Sdim       && (reg->type == REG_TYPE_NQ || reg->type == REG_TYPE_VFD))
1273218822Sdim      || (type == REG_TYPE_VFSD
1274218822Sdim          && (reg->type == REG_TYPE_VFS || reg->type == REG_TYPE_VFD))
1275218822Sdim      || (type == REG_TYPE_NSDQ
1276218822Sdim          && (reg->type == REG_TYPE_VFS || reg->type == REG_TYPE_VFD
1277218822Sdim              || reg->type == REG_TYPE_NQ))
1278218822Sdim      || (type == REG_TYPE_MMXWC
1279218822Sdim	  && (reg->type == REG_TYPE_MMXWCG)))
1280218822Sdim    type = reg->type;
128189857Sobrien
1282218822Sdim  if (type != reg->type)
1283218822Sdim    return FAIL;
128489857Sobrien
1285218822Sdim  if (reg->neon)
1286218822Sdim    atype = *reg->neon;
1287218822Sdim
1288218822Sdim  if (parse_neon_operand_type (&parsetype, &str) == SUCCESS)
1289218822Sdim    {
1290218822Sdim      if ((atype.defined & NTA_HASTYPE) != 0)
1291218822Sdim        {
1292218822Sdim          first_error (_("can't redefine type for operand"));
1293218822Sdim          return FAIL;
1294218822Sdim        }
1295218822Sdim      atype.defined |= NTA_HASTYPE;
1296218822Sdim      atype.eltype = parsetype;
1297218822Sdim    }
1298218822Sdim
1299218822Sdim  if (skip_past_char (&str, '[') == SUCCESS)
1300218822Sdim    {
1301218822Sdim      if (type != REG_TYPE_VFD)
1302218822Sdim        {
1303218822Sdim          first_error (_("only D registers may be indexed"));
1304218822Sdim          return FAIL;
1305218822Sdim        }
1306218822Sdim
1307218822Sdim      if ((atype.defined & NTA_HASINDEX) != 0)
1308218822Sdim        {
1309218822Sdim          first_error (_("can't change index for operand"));
1310218822Sdim          return FAIL;
1311218822Sdim        }
131289857Sobrien
1313218822Sdim      atype.defined |= NTA_HASINDEX;
131489857Sobrien
1315218822Sdim      if (skip_past_char (&str, ']') == SUCCESS)
1316218822Sdim        atype.index = NEON_ALL_LANES;
1317218822Sdim      else
1318218822Sdim        {
1319218822Sdim          expressionS exp;
132089857Sobrien
1321218822Sdim          my_get_expression (&exp, &str, GE_NO_PREFIX);
132289857Sobrien
1323218822Sdim          if (exp.X_op != O_constant)
1324218822Sdim            {
1325218822Sdim              first_error (_("constant expression required"));
1326218822Sdim              return FAIL;
1327218822Sdim            }
132889857Sobrien
1329218822Sdim          if (skip_past_char (&str, ']') == FAIL)
1330218822Sdim            return FAIL;
133189857Sobrien
1332218822Sdim          atype.index = exp.X_add_number;
1333218822Sdim        }
1334218822Sdim    }
1335218822Sdim
1336218822Sdim  if (typeinfo)
1337218822Sdim    *typeinfo = atype;
1338218822Sdim
1339218822Sdim  if (rtype)
1340218822Sdim    *rtype = type;
1341218822Sdim
1342218822Sdim  *ccp = str;
1343218822Sdim
1344218822Sdim  return reg->number;
1345218822Sdim}
134689857Sobrien
1347218822Sdim/* Like arm_reg_parse, but allow allow the following extra features:
1348218822Sdim    - If RTYPE is non-zero, return the (possibly restricted) type of the
1349218822Sdim      register (e.g. Neon double or quad reg when either has been requested).
1350218822Sdim    - If this is a Neon vector type with additional type information, fill
1351218822Sdim      in the struct pointed to by VECTYPE (if non-NULL).
1352218822Sdim   This function will fault on encountering a scalar.
1353218822Sdim*/
135489857Sobrien
1355218822Sdimstatic int
1356218822Sdimarm_typed_reg_parse (char **ccp, enum arm_reg_type type,
1357218822Sdim                     enum arm_reg_type *rtype, struct neon_type_el *vectype)
1358218822Sdim{
1359218822Sdim  struct neon_typed_alias atype;
1360218822Sdim  char *str = *ccp;
1361218822Sdim  int reg = parse_typed_reg_or_scalar (&str, type, rtype, &atype);
136289857Sobrien
1363218822Sdim  if (reg == FAIL)
1364218822Sdim    return FAIL;
136589857Sobrien
1366218822Sdim  /* Do not allow a scalar (reg+index) to parse as a register.  */
1367218822Sdim  if ((atype.defined & NTA_HASINDEX) != 0)
1368218822Sdim    {
1369218822Sdim      first_error (_("register operand expected, but got scalar"));
1370218822Sdim      return FAIL;
1371218822Sdim    }
1372130561Sobrien
1373218822Sdim  if (vectype)
1374218822Sdim    *vectype = atype.eltype;
137560484Sobrien
1376218822Sdim  *ccp = str;
137760484Sobrien
1378218822Sdim  return reg;
1379218822Sdim}
138089857Sobrien
1381218822Sdim#define NEON_SCALAR_REG(X)	((X) >> 4)
1382218822Sdim#define NEON_SCALAR_INDEX(X)	((X) & 15)
138360484Sobrien
1384218822Sdim/* Parse a Neon scalar. Most of the time when we're parsing a scalar, we don't
1385218822Sdim   have enough information to be able to do a good job bounds-checking. So, we
1386218822Sdim   just do easy checks here, and do further checks later.  */
138760484Sobrien
1388218822Sdimstatic int
1389218822Sdimparse_scalar (char **ccp, int elsize, struct neon_type_el *type)
1390218822Sdim{
1391218822Sdim  int reg;
1392218822Sdim  char *str = *ccp;
1393218822Sdim  struct neon_typed_alias atype;
1394218822Sdim
1395218822Sdim  reg = parse_typed_reg_or_scalar (&str, REG_TYPE_VFD, NULL, &atype);
1396218822Sdim
1397218822Sdim  if (reg == FAIL || (atype.defined & NTA_HASINDEX) == 0)
1398218822Sdim    return FAIL;
1399218822Sdim
1400218822Sdim  if (atype.index == NEON_ALL_LANES)
1401218822Sdim    {
1402218822Sdim      first_error (_("scalar must have an index"));
1403218822Sdim      return FAIL;
1404218822Sdim    }
1405218822Sdim  else if (atype.index >= 64 / elsize)
1406218822Sdim    {
1407218822Sdim      first_error (_("scalar index out of range"));
1408218822Sdim      return FAIL;
1409218822Sdim    }
1410218822Sdim
1411218822Sdim  if (type)
1412218822Sdim    *type = atype.eltype;
1413218822Sdim
1414218822Sdim  *ccp = str;
1415218822Sdim
1416218822Sdim  return reg * 16 + atype.index;
1417218822Sdim}
141860484Sobrien
1419218822Sdim/* Parse an ARM register list.  Returns the bitmask, or FAIL.  */
1420218822Sdimstatic long
1421218822Sdimparse_reg_list (char ** strp)
1422218822Sdim{
1423218822Sdim  char * str = * strp;
1424218822Sdim  long	 range = 0;
1425218822Sdim  int	 another_range;
142689857Sobrien
1427218822Sdim  /* We come back here if we get ranges concatenated by '+' or '|'.  */
1428218822Sdim  do
1429218822Sdim    {
1430218822Sdim      another_range = 0;
1431130561Sobrien
1432218822Sdim      if (*str == '{')
1433218822Sdim	{
1434218822Sdim	  int in_range = 0;
1435218822Sdim	  int cur_reg = -1;
143660484Sobrien
1437218822Sdim	  str++;
1438218822Sdim	  do
1439218822Sdim	    {
1440218822Sdim	      int reg;
144160484Sobrien
1442218822Sdim	      if ((reg = arm_reg_parse (&str, REG_TYPE_RN)) == FAIL)
1443218822Sdim		{
1444218822Sdim		  first_error (_(reg_expected_msgs[REG_TYPE_RN]));
1445218822Sdim		  return FAIL;
1446218822Sdim		}
144760484Sobrien
1448218822Sdim	      if (in_range)
1449218822Sdim		{
1450218822Sdim		  int i;
145160484Sobrien
1452218822Sdim		  if (reg <= cur_reg)
1453218822Sdim		    {
1454218822Sdim		      first_error (_("bad range in register list"));
1455218822Sdim		      return FAIL;
1456218822Sdim		    }
145760484Sobrien
1458218822Sdim		  for (i = cur_reg + 1; i < reg; i++)
1459218822Sdim		    {
1460218822Sdim		      if (range & (1 << i))
1461218822Sdim			as_tsktsk
1462218822Sdim			  (_("Warning: duplicated register (r%d) in register list"),
1463218822Sdim			   i);
1464218822Sdim		      else
1465218822Sdim			range |= 1 << i;
1466218822Sdim		    }
1467218822Sdim		  in_range = 0;
1468218822Sdim		}
146960484Sobrien
1470218822Sdim	      if (range & (1 << reg))
1471218822Sdim		as_tsktsk (_("Warning: duplicated register (r%d) in register list"),
1472218822Sdim			   reg);
1473218822Sdim	      else if (reg <= cur_reg)
1474218822Sdim		as_tsktsk (_("Warning: register range not in ascending order"));
147560484Sobrien
1476218822Sdim	      range |= 1 << reg;
1477218822Sdim	      cur_reg = reg;
1478218822Sdim	    }
1479218822Sdim	  while (skip_past_comma (&str) != FAIL
1480218822Sdim		 || (in_range = 1, *str++ == '-'));
1481218822Sdim	  str--;
148260484Sobrien
1483218822Sdim	  if (*str++ != '}')
1484218822Sdim	    {
1485218822Sdim	      first_error (_("missing `}'"));
1486218822Sdim	      return FAIL;
1487218822Sdim	    }
1488218822Sdim	}
1489218822Sdim      else
1490218822Sdim	{
1491218822Sdim	  expressionS expr;
149260484Sobrien
1493218822Sdim	  if (my_get_expression (&expr, &str, GE_NO_PREFIX))
1494218822Sdim	    return FAIL;
149560484Sobrien
1496218822Sdim	  if (expr.X_op == O_constant)
1497218822Sdim	    {
1498218822Sdim	      if (expr.X_add_number
1499218822Sdim		  != (expr.X_add_number & 0x0000ffff))
1500218822Sdim		{
1501218822Sdim		  inst.error = _("invalid register mask");
1502218822Sdim		  return FAIL;
1503218822Sdim		}
150460484Sobrien
1505218822Sdim	      if ((range & expr.X_add_number) != 0)
1506218822Sdim		{
1507218822Sdim		  int regno = range & expr.X_add_number;
150860484Sobrien
1509218822Sdim		  regno &= -regno;
1510218822Sdim		  regno = (1 << regno) - 1;
1511218822Sdim		  as_tsktsk
1512218822Sdim		    (_("Warning: duplicated register (r%d) in register list"),
1513218822Sdim		     regno);
1514218822Sdim		}
151560484Sobrien
1516218822Sdim	      range |= expr.X_add_number;
1517218822Sdim	    }
1518218822Sdim	  else
1519218822Sdim	    {
1520218822Sdim	      if (inst.reloc.type != 0)
1521218822Sdim		{
1522218822Sdim		  inst.error = _("expression too complex");
1523218822Sdim		  return FAIL;
1524218822Sdim		}
152560484Sobrien
1526218822Sdim	      memcpy (&inst.reloc.exp, &expr, sizeof (expressionS));
1527218822Sdim	      inst.reloc.type = BFD_RELOC_ARM_MULTI;
1528218822Sdim	      inst.reloc.pc_rel = 0;
1529218822Sdim	    }
1530218822Sdim	}
153160484Sobrien
1532218822Sdim      if (*str == '|' || *str == '+')
1533218822Sdim	{
1534218822Sdim	  str++;
1535218822Sdim	  another_range = 1;
1536218822Sdim	}
1537218822Sdim    }
1538218822Sdim  while (another_range);
153977298Sobrien
1540218822Sdim  *strp = str;
1541218822Sdim  return range;
1542218822Sdim}
154377298Sobrien
1544218822Sdim/* Types of registers in a list.  */
154577298Sobrien
1546218822Sdimenum reg_list_els
1547218822Sdim{
1548218822Sdim  REGLIST_VFP_S,
1549218822Sdim  REGLIST_VFP_D,
1550218822Sdim  REGLIST_NEON_D
155160484Sobrien};
155260484Sobrien
1553218822Sdim/* Parse a VFP register list.  If the string is invalid return FAIL.
1554218822Sdim   Otherwise return the number of registers, and set PBASE to the first
1555218822Sdim   register.  Parses registers of type ETYPE.
1556218822Sdim   If REGLIST_NEON_D is used, several syntax enhancements are enabled:
1557218822Sdim     - Q registers can be used to specify pairs of D registers
1558218822Sdim     - { } can be omitted from around a singleton register list
1559218822Sdim         FIXME: This is not implemented, as it would require backtracking in
1560218822Sdim         some cases, e.g.:
1561218822Sdim           vtbl.8 d3,d4,d5
1562218822Sdim         This could be done (the meaning isn't really ambiguous), but doesn't
1563218822Sdim         fit in well with the current parsing framework.
1564218822Sdim     - 32 D registers may be used (also true for VFPv3).
1565218822Sdim   FIXME: Types are ignored in these register lists, which is probably a
1566218822Sdim   bug.  */
1567218822Sdim
1568218822Sdimstatic int
1569218822Sdimparse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
157060484Sobrien{
1571218822Sdim  char *str = *ccp;
1572218822Sdim  int base_reg;
1573218822Sdim  int new_base;
1574218822Sdim  enum arm_reg_type regtype = 0;
1575218822Sdim  int max_regs = 0;
1576218822Sdim  int count = 0;
1577218822Sdim  int warned = 0;
1578218822Sdim  unsigned long mask = 0;
1579218822Sdim  int i;
1580130561Sobrien
1581218822Sdim  if (*str != '{')
1582218822Sdim    {
1583218822Sdim      inst.error = _("expecting {");
1584218822Sdim      return FAIL;
1585218822Sdim    }
158660484Sobrien
1587218822Sdim  str++;
158860484Sobrien
1589218822Sdim  switch (etype)
1590218822Sdim    {
1591218822Sdim    case REGLIST_VFP_S:
1592218822Sdim      regtype = REG_TYPE_VFS;
1593218822Sdim      max_regs = 32;
1594218822Sdim      break;
1595218822Sdim
1596218822Sdim    case REGLIST_VFP_D:
1597218822Sdim      regtype = REG_TYPE_VFD;
1598218822Sdim      break;
1599218822Sdim
1600218822Sdim    case REGLIST_NEON_D:
1601218822Sdim      regtype = REG_TYPE_NDQ;
1602218822Sdim      break;
1603218822Sdim    }
160460484Sobrien
1605218822Sdim  if (etype != REGLIST_VFP_S)
1606218822Sdim    {
1607218822Sdim      /* VFPv3 allows 32 D registers.  */
1608218822Sdim      if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v3))
1609218822Sdim        {
1610218822Sdim          max_regs = 32;
1611218822Sdim          if (thumb_mode)
1612218822Sdim            ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
1613218822Sdim                                    fpu_vfp_ext_v3);
1614218822Sdim          else
1615218822Sdim            ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used,
1616218822Sdim                                    fpu_vfp_ext_v3);
1617218822Sdim        }
1618218822Sdim      else
1619218822Sdim        max_regs = 16;
1620218822Sdim    }
162160484Sobrien
1622218822Sdim  base_reg = max_regs;
162360484Sobrien
1624218822Sdim  do
1625218822Sdim    {
1626218822Sdim      int setmask = 1, addregs = 1;
162760484Sobrien
1628218822Sdim      new_base = arm_typed_reg_parse (&str, regtype, &regtype, NULL);
162960484Sobrien
1630218822Sdim      if (new_base == FAIL)
1631218822Sdim	{
1632218822Sdim	  first_error (_(reg_expected_msgs[regtype]));
1633218822Sdim	  return FAIL;
1634218822Sdim	}
1635218822Sdim
1636218822Sdim      if (new_base >= max_regs)
1637218822Sdim        {
1638218822Sdim          first_error (_("register out of range in list"));
1639218822Sdim          return FAIL;
1640218822Sdim        }
1641218822Sdim
1642218822Sdim      /* Note: a value of 2 * n is returned for the register Q<n>.  */
1643218822Sdim      if (regtype == REG_TYPE_NQ)
1644218822Sdim        {
1645218822Sdim          setmask = 3;
1646218822Sdim          addregs = 2;
1647218822Sdim        }
164889857Sobrien
1649218822Sdim      if (new_base < base_reg)
1650218822Sdim	base_reg = new_base;
165160484Sobrien
1652218822Sdim      if (mask & (setmask << new_base))
1653218822Sdim	{
1654218822Sdim	  first_error (_("invalid register list"));
1655218822Sdim	  return FAIL;
1656218822Sdim	}
165760484Sobrien
1658218822Sdim      if ((mask >> new_base) != 0 && ! warned)
1659218822Sdim	{
1660218822Sdim	  as_tsktsk (_("register list not in ascending order"));
1661218822Sdim	  warned = 1;
1662218822Sdim	}
166360484Sobrien
1664218822Sdim      mask |= setmask << new_base;
1665218822Sdim      count += addregs;
166660484Sobrien
1667218822Sdim      if (*str == '-') /* We have the start of a range expression */
1668218822Sdim	{
1669218822Sdim	  int high_range;
167060484Sobrien
1671218822Sdim	  str++;
167277298Sobrien
1673218822Sdim	  if ((high_range = arm_typed_reg_parse (&str, regtype, NULL, NULL))
1674218822Sdim              == FAIL)
1675218822Sdim	    {
1676218822Sdim	      inst.error = gettext (reg_expected_msgs[regtype]);
1677218822Sdim	      return FAIL;
1678218822Sdim	    }
167977298Sobrien
1680218822Sdim          if (high_range >= max_regs)
1681218822Sdim            {
1682218822Sdim              first_error (_("register out of range in list"));
1683218822Sdim              return FAIL;
1684218822Sdim            }
168577298Sobrien
1686218822Sdim          if (regtype == REG_TYPE_NQ)
1687218822Sdim            high_range = high_range + 1;
1688218822Sdim
1689218822Sdim	  if (high_range <= new_base)
1690218822Sdim	    {
1691218822Sdim	      inst.error = _("register range not in ascending order");
1692218822Sdim	      return FAIL;
1693218822Sdim	    }
1694218822Sdim
1695218822Sdim	  for (new_base += addregs; new_base <= high_range; new_base += addregs)
1696218822Sdim	    {
1697218822Sdim	      if (mask & (setmask << new_base))
1698218822Sdim		{
1699218822Sdim		  inst.error = _("invalid register list");
1700218822Sdim		  return FAIL;
1701218822Sdim		}
1702218822Sdim
1703218822Sdim	      mask |= setmask << new_base;
1704218822Sdim	      count += addregs;
1705218822Sdim	    }
1706218822Sdim	}
1707218822Sdim    }
1708218822Sdim  while (skip_past_comma (&str) != FAIL);
1709218822Sdim
1710218822Sdim  str++;
1711218822Sdim
1712218822Sdim  /* Sanity check -- should have raised a parse error above.  */
1713218822Sdim  if (count == 0 || count > max_regs)
1714218822Sdim    abort ();
1715218822Sdim
1716218822Sdim  *pbase = base_reg;
1717218822Sdim
1718218822Sdim  /* Final test -- the registers must be consecutive.  */
1719218822Sdim  mask >>= base_reg;
1720218822Sdim  for (i = 0; i < count; i++)
1721130561Sobrien    {
1722218822Sdim      if ((mask & (1u << i)) == 0)
1723218822Sdim	{
1724218822Sdim	  inst.error = _("non-contiguous register range");
1725218822Sdim	  return FAIL;
1726218822Sdim	}
1727130561Sobrien    }
172860484Sobrien
1729218822Sdim  *ccp = str;
1730218822Sdim
1731218822Sdim  return count;
1732130561Sobrien}
1733130561Sobrien
1734218822Sdim/* True if two alias types are the same.  */
1735218822Sdim
1736218822Sdimstatic int
1737218822Sdimneon_alias_types_same (struct neon_typed_alias *a, struct neon_typed_alias *b)
1738130561Sobrien{
1739218822Sdim  if (!a && !b)
1740218822Sdim    return 1;
1741218822Sdim
1742218822Sdim  if (!a || !b)
1743218822Sdim    return 0;
1744130561Sobrien
1745218822Sdim  if (a->defined != b->defined)
1746218822Sdim    return 0;
1747218822Sdim
1748218822Sdim  if ((a->defined & NTA_HASTYPE) != 0
1749218822Sdim      && (a->eltype.type != b->eltype.type
1750218822Sdim          || a->eltype.size != b->eltype.size))
1751218822Sdim    return 0;
1752130561Sobrien
1753218822Sdim  if ((a->defined & NTA_HASINDEX) != 0
1754218822Sdim      && (a->index != b->index))
1755218822Sdim    return 0;
1756218822Sdim
1757218822Sdim  return 1;
1758218822Sdim}
1759218822Sdim
1760218822Sdim/* Parse element/structure lists for Neon VLD<n> and VST<n> instructions.
1761218822Sdim   The base register is put in *PBASE.
1762218822Sdim   The lane (or one of the NEON_*_LANES constants) is placed in bits [3:0] of
1763218822Sdim   the return value.
1764218822Sdim   The register stride (minus one) is put in bit 4 of the return value.
1765218822Sdim   Bits [6:5] encode the list length (minus one).
1766218822Sdim   The type of the list elements is put in *ELTYPE, if non-NULL.  */
1767218822Sdim
1768218822Sdim#define NEON_LANE(X)		((X) & 0xf)
1769218822Sdim#define NEON_REG_STRIDE(X)	((((X) >> 4) & 1) + 1)
1770218822Sdim#define NEON_REGLIST_LENGTH(X)	((((X) >> 5) & 3) + 1)
1771218822Sdim
1772218822Sdimstatic int
1773218822Sdimparse_neon_el_struct_list (char **str, unsigned *pbase,
1774218822Sdim                           struct neon_type_el *eltype)
1775218822Sdim{
1776218822Sdim  char *ptr = *str;
1777218822Sdim  int base_reg = -1;
1778218822Sdim  int reg_incr = -1;
1779218822Sdim  int count = 0;
1780218822Sdim  int lane = -1;
1781218822Sdim  int leading_brace = 0;
1782218822Sdim  enum arm_reg_type rtype = REG_TYPE_NDQ;
1783218822Sdim  int addregs = 1;
1784218822Sdim  const char *const incr_error = "register stride must be 1 or 2";
1785218822Sdim  const char *const type_error = "mismatched element/structure types in list";
1786218822Sdim  struct neon_typed_alias firsttype;
1787218822Sdim
1788218822Sdim  if (skip_past_char (&ptr, '{') == SUCCESS)
1789218822Sdim    leading_brace = 1;
1790218822Sdim
1791218822Sdim  do
1792130561Sobrien    {
1793218822Sdim      struct neon_typed_alias atype;
1794218822Sdim      int getreg = parse_typed_reg_or_scalar (&ptr, rtype, &rtype, &atype);
1795130561Sobrien
1796218822Sdim      if (getreg == FAIL)
1797218822Sdim        {
1798218822Sdim          first_error (_(reg_expected_msgs[rtype]));
1799218822Sdim          return FAIL;
1800218822Sdim        }
1801218822Sdim
1802218822Sdim      if (base_reg == -1)
1803218822Sdim        {
1804218822Sdim          base_reg = getreg;
1805218822Sdim          if (rtype == REG_TYPE_NQ)
1806218822Sdim            {
1807218822Sdim              reg_incr = 1;
1808218822Sdim              addregs = 2;
1809218822Sdim            }
1810218822Sdim          firsttype = atype;
1811218822Sdim        }
1812218822Sdim      else if (reg_incr == -1)
1813218822Sdim        {
1814218822Sdim          reg_incr = getreg - base_reg;
1815218822Sdim          if (reg_incr < 1 || reg_incr > 2)
1816218822Sdim            {
1817218822Sdim              first_error (_(incr_error));
1818218822Sdim              return FAIL;
1819218822Sdim            }
1820218822Sdim        }
1821218822Sdim      else if (getreg != base_reg + reg_incr * count)
1822218822Sdim        {
1823218822Sdim          first_error (_(incr_error));
1824218822Sdim          return FAIL;
1825218822Sdim        }
1826130561Sobrien
1827218822Sdim      if (!neon_alias_types_same (&atype, &firsttype))
1828218822Sdim        {
1829218822Sdim          first_error (_(type_error));
1830218822Sdim          return FAIL;
1831218822Sdim        }
1832218822Sdim
1833218822Sdim      /* Handle Dn-Dm or Qn-Qm syntax. Can only be used with non-indexed list
1834218822Sdim         modes.  */
1835218822Sdim      if (ptr[0] == '-')
1836218822Sdim        {
1837218822Sdim          struct neon_typed_alias htype;
1838218822Sdim          int hireg, dregs = (rtype == REG_TYPE_NQ) ? 2 : 1;
1839218822Sdim          if (lane == -1)
1840218822Sdim            lane = NEON_INTERLEAVE_LANES;
1841218822Sdim          else if (lane != NEON_INTERLEAVE_LANES)
1842218822Sdim            {
1843218822Sdim              first_error (_(type_error));
1844218822Sdim              return FAIL;
1845218822Sdim            }
1846218822Sdim          if (reg_incr == -1)
1847218822Sdim            reg_incr = 1;
1848218822Sdim          else if (reg_incr != 1)
1849218822Sdim            {
1850218822Sdim              first_error (_("don't use Rn-Rm syntax with non-unit stride"));
1851218822Sdim              return FAIL;
1852218822Sdim            }
1853218822Sdim          ptr++;
1854218822Sdim          hireg = parse_typed_reg_or_scalar (&ptr, rtype, NULL, &htype);
1855218822Sdim          if (hireg == FAIL)
1856218822Sdim            {
1857218822Sdim              first_error (_(reg_expected_msgs[rtype]));
1858218822Sdim              return FAIL;
1859218822Sdim            }
1860218822Sdim          if (!neon_alias_types_same (&htype, &firsttype))
1861218822Sdim            {
1862218822Sdim              first_error (_(type_error));
1863218822Sdim              return FAIL;
1864218822Sdim            }
1865218822Sdim          count += hireg + dregs - getreg;
1866218822Sdim          continue;
1867218822Sdim        }
1868218822Sdim
1869218822Sdim      /* If we're using Q registers, we can't use [] or [n] syntax.  */
1870218822Sdim      if (rtype == REG_TYPE_NQ)
1871218822Sdim        {
1872218822Sdim          count += 2;
1873218822Sdim          continue;
1874218822Sdim        }
1875218822Sdim
1876218822Sdim      if ((atype.defined & NTA_HASINDEX) != 0)
1877218822Sdim        {
1878218822Sdim          if (lane == -1)
1879218822Sdim            lane = atype.index;
1880218822Sdim          else if (lane != atype.index)
1881218822Sdim            {
1882218822Sdim              first_error (_(type_error));
1883218822Sdim              return FAIL;
1884218822Sdim            }
1885218822Sdim        }
1886218822Sdim      else if (lane == -1)
1887218822Sdim        lane = NEON_INTERLEAVE_LANES;
1888218822Sdim      else if (lane != NEON_INTERLEAVE_LANES)
1889218822Sdim        {
1890218822Sdim          first_error (_(type_error));
1891218822Sdim          return FAIL;
1892218822Sdim        }
1893218822Sdim      count++;
1894130561Sobrien    }
1895218822Sdim  while ((count != 1 || leading_brace) && skip_past_comma (&ptr) != FAIL);
1896218822Sdim
1897218822Sdim  /* No lane set by [x]. We must be interleaving structures.  */
1898218822Sdim  if (lane == -1)
1899218822Sdim    lane = NEON_INTERLEAVE_LANES;
1900218822Sdim
1901218822Sdim  /* Sanity check.  */
1902218822Sdim  if (lane == -1 || base_reg == -1 || count < 1 || count > 4
1903218822Sdim      || (count > 1 && reg_incr == -1))
1904218822Sdim    {
1905218822Sdim      first_error (_("error parsing element/structure list"));
1906218822Sdim      return FAIL;
1907218822Sdim    }
1908130561Sobrien
1909218822Sdim  if ((count > 1 || leading_brace) && skip_past_char (&ptr, '}') == FAIL)
1910130561Sobrien    {
1911218822Sdim      first_error (_("expected }"));
1912218822Sdim      return FAIL;
1913130561Sobrien    }
1914218822Sdim
1915218822Sdim  if (reg_incr == -1)
1916218822Sdim    reg_incr = 1;
1917130561Sobrien
1918218822Sdim  if (eltype)
1919218822Sdim    *eltype = firsttype.eltype;
1920218822Sdim
1921218822Sdim  *pbase = base_reg;
1922218822Sdim  *str = ptr;
1923218822Sdim
1924218822Sdim  return lane | ((reg_incr - 1) << 4) | ((count - 1) << 5);
1925130561Sobrien}
1926130561Sobrien
1927218822Sdim/* Parse an explicit relocation suffix on an expression.  This is
1928218822Sdim   either nothing, or a word in parentheses.  Note that if !OBJ_ELF,
1929218822Sdim   arm_reloc_hsh contains no entries, so this function can only
1930218822Sdim   succeed if there is no () after the word.  Returns -1 on error,
1931218822Sdim   BFD_RELOC_UNUSED if there wasn't any suffix.	 */
193260484Sobrienstatic int
1933218822Sdimparse_reloc (char **str)
193460484Sobrien{
1935218822Sdim  struct reloc_entry *r;
1936218822Sdim  char *p, *q;
193760484Sobrien
1938218822Sdim  if (**str != '(')
1939218822Sdim    return BFD_RELOC_UNUSED;
194060484Sobrien
1941218822Sdim  p = *str + 1;
1942218822Sdim  q = p;
194378828Sobrien
1944218822Sdim  while (*q && *q != ')' && *q != ',')
1945218822Sdim    q++;
1946218822Sdim  if (*q != ')')
1947218822Sdim    return -1;
194860484Sobrien
1949218822Sdim  if ((r = hash_find_n (arm_reloc_hsh, p, q - p)) == NULL)
1950218822Sdim    return -1;
1951218822Sdim
1952218822Sdim  *str = q + 1;
1953218822Sdim  return r->reloc;
1954218822Sdim}
1955218822Sdim
1956218822Sdim/* Directives: register aliases.  */
1957218822Sdim
1958218822Sdimstatic struct reg_entry *
1959218822Sdiminsert_reg_alias (char *str, int number, int type)
1960218822Sdim{
1961218822Sdim  struct reg_entry *new;
1962218822Sdim  const char *name;
1963218822Sdim
1964218822Sdim  if ((new = hash_find (arm_reg_hsh, str)) != 0)
196560484Sobrien    {
1966218822Sdim      if (new->builtin)
1967218822Sdim	as_warn (_("ignoring attempt to redefine built-in register '%s'"), str);
196860484Sobrien
1969218822Sdim      /* Only warn about a redefinition if it's not defined as the
1970218822Sdim	 same register.	 */
1971218822Sdim      else if (new->number != number || new->type != type)
1972218822Sdim	as_warn (_("ignoring redefinition of register alias '%s'"), str);
1973218822Sdim
1974218822Sdim      return 0;
197560484Sobrien    }
197660484Sobrien
1977218822Sdim  name = xstrdup (str);
1978218822Sdim  new = xmalloc (sizeof (struct reg_entry));
197960484Sobrien
1980218822Sdim  new->name = name;
1981218822Sdim  new->number = number;
1982218822Sdim  new->type = type;
1983218822Sdim  new->builtin = FALSE;
1984218822Sdim  new->neon = NULL;
1985218822Sdim
1986218822Sdim  if (hash_insert (arm_reg_hsh, name, (PTR) new))
1987218822Sdim    abort ();
1988218822Sdim
1989218822Sdim  return new;
199060484Sobrien}
199177298Sobrien
199260484Sobrienstatic void
1993218822Sdiminsert_neon_reg_alias (char *str, int number, int type,
1994218822Sdim                       struct neon_typed_alias *atype)
199560484Sobrien{
1996218822Sdim  struct reg_entry *reg = insert_reg_alias (str, number, type);
1997218822Sdim
1998218822Sdim  if (!reg)
1999218822Sdim    {
2000218822Sdim      first_error (_("attempt to redefine typed alias"));
2001218822Sdim      return;
2002218822Sdim    }
2003218822Sdim
2004218822Sdim  if (atype)
2005218822Sdim    {
2006218822Sdim      reg->neon = xmalloc (sizeof (struct neon_typed_alias));
2007218822Sdim      *reg->neon = *atype;
2008218822Sdim    }
2009218822Sdim}
201060484Sobrien
2011218822Sdim/* Look for the .req directive.	 This is of the form:
201260484Sobrien
2013218822Sdim	new_register_name .req existing_register_name
201460484Sobrien
2015218822Sdim   If we find one, or if it looks sufficiently like one that we want to
2016218822Sdim   handle any error here, return non-zero.  Otherwise return zero.  */
201760484Sobrien
2018218822Sdimstatic int
2019218822Sdimcreate_register_alias (char * newname, char *p)
2020218822Sdim{
2021218822Sdim  struct reg_entry *old;
2022218822Sdim  char *oldname, *nbuf;
2023218822Sdim  size_t nlen;
202460484Sobrien
2025218822Sdim  /* The input scrubber ensures that whitespace after the mnemonic is
2026218822Sdim     collapsed to single spaces.  */
2027218822Sdim  oldname = p;
2028218822Sdim  if (strncmp (oldname, " .req ", 6) != 0)
2029218822Sdim    return 0;
203060484Sobrien
2031218822Sdim  oldname += 6;
2032218822Sdim  if (*oldname == '\0')
2033218822Sdim    return 0;
203460484Sobrien
2035218822Sdim  old = hash_find (arm_reg_hsh, oldname);
2036218822Sdim  if (!old)
2037218822Sdim    {
2038218822Sdim      as_warn (_("unknown register '%s' -- .req ignored"), oldname);
2039218822Sdim      return 1;
2040218822Sdim    }
204160484Sobrien
2042218822Sdim  /* If TC_CASE_SENSITIVE is defined, then newname already points to
2043218822Sdim     the desired alias name, and p points to its end.  If not, then
2044218822Sdim     the desired alias name is in the global original_case_string.  */
2045218822Sdim#ifdef TC_CASE_SENSITIVE
2046218822Sdim  nlen = p - newname;
2047218822Sdim#else
2048218822Sdim  newname = original_case_string;
2049218822Sdim  nlen = strlen (newname);
205060484Sobrien#endif
205177298Sobrien
2052218822Sdim  nbuf = alloca (nlen + 1);
2053218822Sdim  memcpy (nbuf, newname, nlen);
2054218822Sdim  nbuf[nlen] = '\0';
205560484Sobrien
2056218822Sdim  /* Create aliases under the new name as stated; an all-lowercase
2057218822Sdim     version of the new name; and an all-uppercase version of the new
2058218822Sdim     name.  */
2059218822Sdim  insert_reg_alias (nbuf, old->number, old->type);
206077298Sobrien
2061218822Sdim  for (p = nbuf; *p; p++)
2062218822Sdim    *p = TOUPPER (*p);
206377298Sobrien
2064218822Sdim  if (strncmp (nbuf, newname, nlen))
2065218822Sdim    insert_reg_alias (nbuf, old->number, old->type);
206677298Sobrien
2067218822Sdim  for (p = nbuf; *p; p++)
2068218822Sdim    *p = TOLOWER (*p);
206977298Sobrien
2070218822Sdim  if (strncmp (nbuf, newname, nlen))
2071218822Sdim    insert_reg_alias (nbuf, old->number, old->type);
2072218822Sdim
2073218822Sdim  return 1;
207460484Sobrien}
207560484Sobrien
2076218822Sdim/* Create a Neon typed/indexed register alias using directives, e.g.:
2077218822Sdim     X .dn d5.s32[1]
2078218822Sdim     Y .qn 6.s16
2079218822Sdim     Z .dn d7
2080218822Sdim     T .dn Z[0]
2081218822Sdim   These typed registers can be used instead of the types specified after the
2082218822Sdim   Neon mnemonic, so long as all operands given have types. Types can also be
2083218822Sdim   specified directly, e.g.:
2084218822Sdim     vadd d0.s32, d1.s32, d2.s32
2085218822Sdim*/
208677298Sobrien
2087218822Sdimstatic int
2088218822Sdimcreate_neon_reg_alias (char *newname, char *p)
208960484Sobrien{
2090218822Sdim  enum arm_reg_type basetype;
2091218822Sdim  struct reg_entry *basereg;
2092218822Sdim  struct reg_entry mybasereg;
2093218822Sdim  struct neon_type ntype;
2094218822Sdim  struct neon_typed_alias typeinfo;
2095218822Sdim  char *namebuf, *nameend;
2096218822Sdim  int namelen;
2097218822Sdim
2098218822Sdim  typeinfo.defined = 0;
2099218822Sdim  typeinfo.eltype.type = NT_invtype;
2100218822Sdim  typeinfo.eltype.size = -1;
2101218822Sdim  typeinfo.index = -1;
2102218822Sdim
2103218822Sdim  nameend = p;
2104218822Sdim
2105218822Sdim  if (strncmp (p, " .dn ", 5) == 0)
2106218822Sdim    basetype = REG_TYPE_VFD;
2107218822Sdim  else if (strncmp (p, " .qn ", 5) == 0)
2108218822Sdim    basetype = REG_TYPE_NQ;
2109218822Sdim  else
2110218822Sdim    return 0;
2111218822Sdim
2112218822Sdim  p += 5;
2113218822Sdim
2114218822Sdim  if (*p == '\0')
2115218822Sdim    return 0;
2116218822Sdim
2117218822Sdim  basereg = arm_reg_parse_multi (&p);
211877298Sobrien
2119218822Sdim  if (basereg && basereg->type != basetype)
2120218822Sdim    {
2121218822Sdim      as_bad (_("bad type for register"));
2122218822Sdim      return 0;
2123218822Sdim    }
212460484Sobrien
2125218822Sdim  if (basereg == NULL)
2126218822Sdim    {
2127218822Sdim      expressionS exp;
2128218822Sdim      /* Try parsing as an integer.  */
2129218822Sdim      my_get_expression (&exp, &p, GE_NO_PREFIX);
2130218822Sdim      if (exp.X_op != O_constant)
2131218822Sdim        {
2132218822Sdim          as_bad (_("expression must be constant"));
2133218822Sdim          return 0;
2134218822Sdim        }
2135218822Sdim      basereg = &mybasereg;
2136218822Sdim      basereg->number = (basetype == REG_TYPE_NQ) ? exp.X_add_number * 2
2137218822Sdim                                                  : exp.X_add_number;
2138218822Sdim      basereg->neon = 0;
2139218822Sdim    }
214077298Sobrien
2141218822Sdim  if (basereg->neon)
2142218822Sdim    typeinfo = *basereg->neon;
2143218822Sdim
2144218822Sdim  if (parse_neon_type (&ntype, &p) == SUCCESS)
2145218822Sdim    {
2146218822Sdim      /* We got a type.  */
2147218822Sdim      if (typeinfo.defined & NTA_HASTYPE)
2148218822Sdim        {
2149218822Sdim          as_bad (_("can't redefine the type of a register alias"));
2150218822Sdim          return 0;
2151218822Sdim        }
2152218822Sdim
2153218822Sdim      typeinfo.defined |= NTA_HASTYPE;
2154218822Sdim      if (ntype.elems != 1)
2155218822Sdim        {
2156218822Sdim          as_bad (_("you must specify a single type only"));
2157218822Sdim          return 0;
2158218822Sdim        }
2159218822Sdim      typeinfo.eltype = ntype.el[0];
2160218822Sdim    }
2161218822Sdim
2162218822Sdim  if (skip_past_char (&p, '[') == SUCCESS)
2163218822Sdim    {
2164218822Sdim      expressionS exp;
2165218822Sdim      /* We got a scalar index.  */
2166218822Sdim
2167218822Sdim      if (typeinfo.defined & NTA_HASINDEX)
2168218822Sdim        {
2169218822Sdim          as_bad (_("can't redefine the index of a scalar alias"));
2170218822Sdim          return 0;
2171218822Sdim        }
2172218822Sdim
2173218822Sdim      my_get_expression (&exp, &p, GE_NO_PREFIX);
2174218822Sdim
2175218822Sdim      if (exp.X_op != O_constant)
2176218822Sdim        {
2177218822Sdim          as_bad (_("scalar index must be constant"));
2178218822Sdim          return 0;
2179218822Sdim        }
2180218822Sdim
2181218822Sdim      typeinfo.defined |= NTA_HASINDEX;
2182218822Sdim      typeinfo.index = exp.X_add_number;
2183218822Sdim
2184218822Sdim      if (skip_past_char (&p, ']') == FAIL)
2185218822Sdim        {
2186218822Sdim          as_bad (_("expecting ]"));
2187218822Sdim          return 0;
2188218822Sdim        }
2189218822Sdim    }
2190218822Sdim
2191218822Sdim  namelen = nameend - newname;
2192218822Sdim  namebuf = alloca (namelen + 1);
2193218822Sdim  strncpy (namebuf, newname, namelen);
2194218822Sdim  namebuf[namelen] = '\0';
2195218822Sdim
2196218822Sdim  insert_neon_reg_alias (namebuf, basereg->number, basetype,
2197218822Sdim                         typeinfo.defined != 0 ? &typeinfo : NULL);
2198218822Sdim
2199218822Sdim  /* Insert name in all uppercase.  */
2200218822Sdim  for (p = namebuf; *p; p++)
2201218822Sdim    *p = TOUPPER (*p);
2202218822Sdim
2203218822Sdim  if (strncmp (namebuf, newname, namelen))
2204218822Sdim    insert_neon_reg_alias (namebuf, basereg->number, basetype,
2205218822Sdim                           typeinfo.defined != 0 ? &typeinfo : NULL);
2206218822Sdim
2207218822Sdim  /* Insert name in all lowercase.  */
2208218822Sdim  for (p = namebuf; *p; p++)
2209218822Sdim    *p = TOLOWER (*p);
2210218822Sdim
2211218822Sdim  if (strncmp (namebuf, newname, namelen))
2212218822Sdim    insert_neon_reg_alias (namebuf, basereg->number, basetype,
2213218822Sdim                           typeinfo.defined != 0 ? &typeinfo : NULL);
2214218822Sdim
2215218822Sdim  return 1;
221660484Sobrien}
221760484Sobrien
2218218822Sdim/* Should never be called, as .req goes between the alias and the
2219218822Sdim   register name, not at the beginning of the line.  */
2220218822Sdimstatic void
2221218822Sdims_req (int a ATTRIBUTE_UNUSED)
222260484Sobrien{
2223218822Sdim  as_bad (_("invalid syntax for .req directive"));
222460484Sobrien}
222560484Sobrien
2226218822Sdimstatic void
2227218822Sdims_dn (int a ATTRIBUTE_UNUSED)
2228218822Sdim{
2229218822Sdim  as_bad (_("invalid syntax for .dn directive"));
2230218822Sdim}
2231130561Sobrien
2232218822Sdimstatic void
2233218822Sdims_qn (int a ATTRIBUTE_UNUSED)
2234218822Sdim{
2235218822Sdim  as_bad (_("invalid syntax for .qn directive"));
2236218822Sdim}
2237130561Sobrien
2238218822Sdim/* The .unreq directive deletes an alias which was previously defined
2239218822Sdim   by .req.  For example:
2240130561Sobrien
2241218822Sdim       my_alias .req r11
2242218822Sdim       .unreq my_alias	  */
2243130561Sobrien
2244218822Sdimstatic void
2245218822Sdims_unreq (int a ATTRIBUTE_UNUSED)
2246218822Sdim{
2247218822Sdim  char * name;
2248218822Sdim  char saved_char;
2249130561Sobrien
2250218822Sdim  name = input_line_pointer;
2251130561Sobrien
2252218822Sdim  while (*input_line_pointer != 0
2253218822Sdim	 && *input_line_pointer != ' '
2254218822Sdim	 && *input_line_pointer != '\n')
2255218822Sdim    ++input_line_pointer;
2256130561Sobrien
2257218822Sdim  saved_char = *input_line_pointer;
2258218822Sdim  *input_line_pointer = 0;
2259130561Sobrien
2260218822Sdim  if (!*name)
2261218822Sdim    as_bad (_("invalid syntax for .unreq directive"));
2262218822Sdim  else
2263218822Sdim    {
2264218822Sdim      struct reg_entry *reg = hash_find (arm_reg_hsh, name);
2265130561Sobrien
2266218822Sdim      if (!reg)
2267218822Sdim	as_bad (_("unknown register alias '%s'"), name);
2268218822Sdim      else if (reg->builtin)
2269218822Sdim	as_warn (_("ignoring attempt to undefine built-in register '%s'"),
2270218822Sdim		 name);
2271218822Sdim      else
2272218822Sdim	{
2273218822Sdim	  hash_delete (arm_reg_hsh, name);
2274218822Sdim	  free ((char *) reg->name);
2275218822Sdim          if (reg->neon)
2276218822Sdim            free (reg->neon);
2277218822Sdim	  free (reg);
2278218822Sdim	}
2279218822Sdim    }
2280130561Sobrien
2281218822Sdim  *input_line_pointer = saved_char;
2282218822Sdim  demand_empty_rest_of_line ();
2283218822Sdim}
2284130561Sobrien
2285218822Sdim/* Directives: Instruction set selection.  */
2286130561Sobrien
2287218822Sdim#ifdef OBJ_ELF
2288218822Sdim/* This code is to handle mapping symbols as defined in the ARM ELF spec.
2289218822Sdim   (See "Mapping symbols", section 4.5.5, ARM AAELF version 1.0).
2290218822Sdim   Note that previously, $a and $t has type STT_FUNC (BSF_OBJECT flag),
2291218822Sdim   and $d has type STT_OBJECT (BSF_OBJECT flag). Now all three are untyped.  */
2292130561Sobrien
2293130561Sobrienstatic enum mstate mapstate = MAP_UNDEFINED;
2294130561Sobrien
2295218822Sdimvoid
2296130561Sobrienmapping_state (enum mstate state)
2297130561Sobrien{
2298130561Sobrien  symbolS * symbolP;
2299130561Sobrien  const char * symname;
2300130561Sobrien  int type;
2301130561Sobrien
2302130561Sobrien  if (mapstate == state)
2303130561Sobrien    /* The mapping symbol has already been emitted.
2304130561Sobrien       There is nothing else to do.  */
2305130561Sobrien    return;
2306130561Sobrien
2307130561Sobrien  mapstate = state;
2308130561Sobrien
2309130561Sobrien  switch (state)
2310130561Sobrien    {
2311130561Sobrien    case MAP_DATA:
2312130561Sobrien      symname = "$d";
2313218822Sdim      type = BSF_NO_FLAGS;
2314130561Sobrien      break;
2315130561Sobrien    case MAP_ARM:
2316130561Sobrien      symname = "$a";
2317218822Sdim      type = BSF_NO_FLAGS;
2318130561Sobrien      break;
2319130561Sobrien    case MAP_THUMB:
2320130561Sobrien      symname = "$t";
2321218822Sdim      type = BSF_NO_FLAGS;
2322130561Sobrien      break;
2323130561Sobrien    case MAP_UNDEFINED:
2324218822Sdim      return;
2325130561Sobrien    default:
2326130561Sobrien      abort ();
2327130561Sobrien    }
2328130561Sobrien
2329218822Sdim  seg_info (now_seg)->tc_segment_info_data.mapstate = state;
2330130561Sobrien
2331130561Sobrien  symbolP = symbol_new (symname, now_seg, (valueT) frag_now_fix (), frag_now);
2332130561Sobrien  symbol_table_insert (symbolP);
2333130561Sobrien  symbol_get_bfdsym (symbolP)->flags |= type | BSF_LOCAL;
2334218822Sdim
2335130561Sobrien  switch (state)
2336130561Sobrien    {
2337130561Sobrien    case MAP_ARM:
2338130561Sobrien      THUMB_SET_FUNC (symbolP, 0);
2339130561Sobrien      ARM_SET_THUMB (symbolP, 0);
2340130561Sobrien      ARM_SET_INTERWORK (symbolP, support_interwork);
2341130561Sobrien      break;
2342218822Sdim
2343130561Sobrien    case MAP_THUMB:
2344130561Sobrien      THUMB_SET_FUNC (symbolP, 1);
2345130561Sobrien      ARM_SET_THUMB (symbolP, 1);
2346130561Sobrien      ARM_SET_INTERWORK (symbolP, support_interwork);
2347130561Sobrien      break;
2348218822Sdim
2349130561Sobrien    case MAP_DATA:
2350130561Sobrien    default:
2351130561Sobrien      return;
2352130561Sobrien    }
2353130561Sobrien}
2354218822Sdim#else
2355218822Sdim#define mapping_state(x) /* nothing */
2356218822Sdim#endif
2357130561Sobrien
2358218822Sdim/* Find the real, Thumb encoded start of a Thumb function.  */
2359130561Sobrien
2360218822Sdimstatic symbolS *
2361218822Sdimfind_real_start (symbolS * symbolP)
2362130561Sobrien{
2363218822Sdim  char *       real_start;
2364218822Sdim  const char * name = S_GET_NAME (symbolP);
2365218822Sdim  symbolS *    new_target;
2366130561Sobrien
2367218822Sdim  /* This definition must agree with the one in gcc/config/arm/thumb.c.	 */
2368218822Sdim#define STUB_NAME ".real_start_of"
2369130561Sobrien
2370218822Sdim  if (name == NULL)
2371218822Sdim    abort ();
2372130561Sobrien
2373218822Sdim  /* The compiler may generate BL instructions to local labels because
2374218822Sdim     it needs to perform a branch to a far away location. These labels
2375218822Sdim     do not have a corresponding ".real_start_of" label.  We check
2376218822Sdim     both for S_IS_LOCAL and for a leading dot, to give a way to bypass
2377218822Sdim     the ".real_start_of" convention for nonlocal branches.  */
2378218822Sdim  if (S_IS_LOCAL (symbolP) || name[0] == '.')
2379218822Sdim    return symbolP;
2380130561Sobrien
2381218822Sdim  real_start = ACONCAT ((STUB_NAME, name, NULL));
2382218822Sdim  new_target = symbol_find (real_start);
2383130561Sobrien
2384218822Sdim  if (new_target == NULL)
2385218822Sdim    {
2386218822Sdim      as_warn ("Failed to find real start of function: %s\n", name);
2387218822Sdim      new_target = symbolP;
2388218822Sdim    }
2389218822Sdim
2390218822Sdim  return new_target;
239160484Sobrien}
239260484Sobrien
239360484Sobrienstatic void
2394218822Sdimopcode_select (int width)
2395130561Sobrien{
2396218822Sdim  switch (width)
2397218822Sdim    {
2398218822Sdim    case 16:
2399218822Sdim      if (! thumb_mode)
2400218822Sdim	{
2401218822Sdim	  if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v4t))
2402218822Sdim	    as_bad (_("selected processor does not support THUMB opcodes"));
2403130561Sobrien
2404218822Sdim	  thumb_mode = 1;
2405218822Sdim	  /* No need to force the alignment, since we will have been
2406218822Sdim	     coming from ARM mode, which is word-aligned.  */
2407218822Sdim	  record_alignment (now_seg, 1);
2408218822Sdim	}
2409218822Sdim      mapping_state (MAP_THUMB);
2410218822Sdim      break;
2411130561Sobrien
2412218822Sdim    case 32:
2413218822Sdim      if (thumb_mode)
2414130561Sobrien	{
2415218822Sdim	  if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1))
2416218822Sdim	    as_bad (_("selected processor does not support ARM opcodes"));
2417130561Sobrien
2418218822Sdim	  thumb_mode = 0;
2419130561Sobrien
2420218822Sdim	  if (!need_pass_2)
2421218822Sdim	    frag_align (2, 0, 0);
2422130561Sobrien
2423218822Sdim	  record_alignment (now_seg, 1);
2424130561Sobrien	}
2425218822Sdim      mapping_state (MAP_ARM);
2426218822Sdim      break;
2427218822Sdim
2428218822Sdim    default:
2429218822Sdim      as_bad (_("invalid instruction size selected (%d)"), width);
2430130561Sobrien    }
2431130561Sobrien}
2432130561Sobrien
2433130561Sobrienstatic void
2434218822Sdims_arm (int ignore ATTRIBUTE_UNUSED)
243560484Sobrien{
2436218822Sdim  opcode_select (32);
243760484Sobrien  demand_empty_rest_of_line ();
243860484Sobrien}
243960484Sobrien
244060484Sobrienstatic void
2441218822Sdims_thumb (int ignore ATTRIBUTE_UNUSED)
244260484Sobrien{
2443218822Sdim  opcode_select (16);
244460484Sobrien  demand_empty_rest_of_line ();
244560484Sobrien}
244660484Sobrien
244760484Sobrienstatic void
2448218822Sdims_code (int unused ATTRIBUTE_UNUSED)
244960484Sobrien{
2450218822Sdim  int temp;
245160484Sobrien
245260484Sobrien  temp = get_absolute_expression ();
2453218822Sdim  switch (temp)
245460484Sobrien    {
2455218822Sdim    case 16:
2456218822Sdim    case 32:
2457218822Sdim      opcode_select (temp);
2458218822Sdim      break;
245960484Sobrien
2460218822Sdim    default:
2461218822Sdim      as_bad (_("invalid operand to .code directive (%d) (expecting 16 or 32)"), temp);
246260484Sobrien    }
246360484Sobrien}
246460484Sobrien
246560484Sobrienstatic void
2466218822Sdims_force_thumb (int ignore ATTRIBUTE_UNUSED)
246760484Sobrien{
246860484Sobrien  /* If we are not already in thumb mode go into it, EVEN if
246960484Sobrien     the target processor does not support thumb instructions.
247060484Sobrien     This is used by gcc/config/arm/lib1funcs.asm for example
247160484Sobrien     to compile interworking support functions even if the
2472218822Sdim     target processor should not support interworking.	*/
247360484Sobrien  if (! thumb_mode)
247460484Sobrien    {
247560484Sobrien      thumb_mode = 2;
247660484Sobrien      record_alignment (now_seg, 1);
247760484Sobrien    }
247877298Sobrien
247960484Sobrien  demand_empty_rest_of_line ();
248060484Sobrien}
248160484Sobrien
248260484Sobrienstatic void
2483218822Sdims_thumb_func (int ignore ATTRIBUTE_UNUSED)
248460484Sobrien{
2485218822Sdim  s_thumb (0);
248677298Sobrien
248760484Sobrien  /* The following label is the name/address of the start of a Thumb function.
2488218822Sdim     We need to know this for the interworking support.	 */
2489130561Sobrien  label_is_thumb_function_name = TRUE;
249060484Sobrien}
249160484Sobrien
249260484Sobrien/* Perform a .set directive, but also mark the alias as
249360484Sobrien   being a thumb function.  */
249460484Sobrien
249560484Sobrienstatic void
2496218822Sdims_thumb_set (int equiv)
249760484Sobrien{
249860484Sobrien  /* XXX the following is a duplicate of the code for s_set() in read.c
249960484Sobrien     We cannot just call that code as we need to get at the symbol that
250060484Sobrien     is created.  */
2501218822Sdim  char *    name;
2502218822Sdim  char	    delim;
2503218822Sdim  char *    end_name;
2504218822Sdim  symbolS * symbolP;
250560484Sobrien
250677298Sobrien  /* Especial apologies for the random logic:
250777298Sobrien     This just grew, and could be parsed much more simply!
250877298Sobrien     Dean - in haste.  */
2509218822Sdim  name	    = input_line_pointer;
2510218822Sdim  delim	    = get_symbol_end ();
251160484Sobrien  end_name  = input_line_pointer;
251260484Sobrien  *end_name = delim;
251377298Sobrien
251460484Sobrien  if (*input_line_pointer != ',')
251560484Sobrien    {
251660484Sobrien      *end_name = 0;
251789857Sobrien      as_bad (_("expected comma after name \"%s\""), name);
251860484Sobrien      *end_name = delim;
251960484Sobrien      ignore_rest_of_line ();
252060484Sobrien      return;
252160484Sobrien    }
252260484Sobrien
252360484Sobrien  input_line_pointer++;
252460484Sobrien  *end_name = 0;
252560484Sobrien
252660484Sobrien  if (name[0] == '.' && name[1] == '\0')
252760484Sobrien    {
252877298Sobrien      /* XXX - this should not happen to .thumb_set.  */
252960484Sobrien      abort ();
253060484Sobrien    }
253160484Sobrien
253260484Sobrien  if ((symbolP = symbol_find (name)) == NULL
253360484Sobrien      && (symbolP = md_undefined_symbol (name)) == NULL)
253460484Sobrien    {
253560484Sobrien#ifndef NO_LISTING
253660484Sobrien      /* When doing symbol listings, play games with dummy fragments living
253760484Sobrien	 outside the normal fragment chain to record the file and line info
2538218822Sdim	 for this symbol.  */
253960484Sobrien      if (listing & LISTING_SYMBOLS)
254060484Sobrien	{
254160484Sobrien	  extern struct list_info_struct * listing_tail;
2542218822Sdim	  fragS * dummy_frag = xmalloc (sizeof (fragS));
254377298Sobrien
254477298Sobrien	  memset (dummy_frag, 0, sizeof (fragS));
254560484Sobrien	  dummy_frag->fr_type = rs_fill;
254660484Sobrien	  dummy_frag->line = listing_tail;
254760484Sobrien	  symbolP = symbol_new (name, undefined_section, 0, dummy_frag);
254860484Sobrien	  dummy_frag->fr_symbol = symbolP;
254960484Sobrien	}
255060484Sobrien      else
255160484Sobrien#endif
255277298Sobrien	symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag);
255377298Sobrien
255460484Sobrien#ifdef OBJ_COFF
255577298Sobrien      /* "set" symbols are local unless otherwise specified.  */
255660484Sobrien      SF_SET_LOCAL (symbolP);
255777298Sobrien#endif /* OBJ_COFF  */
255877298Sobrien    }				/* Make a new symbol.  */
255960484Sobrien
256060484Sobrien  symbol_table_insert (symbolP);
256160484Sobrien
256260484Sobrien  * end_name = delim;
256360484Sobrien
256460484Sobrien  if (equiv
256560484Sobrien      && S_IS_DEFINED (symbolP)
256660484Sobrien      && S_GET_SEGMENT (symbolP) != reg_section)
256760484Sobrien    as_bad (_("symbol `%s' already defined"), S_GET_NAME (symbolP));
256860484Sobrien
256960484Sobrien  pseudo_set (symbolP);
257077298Sobrien
257160484Sobrien  demand_empty_rest_of_line ();
257260484Sobrien
2573218822Sdim  /* XXX Now we come to the Thumb specific bit of code.	 */
257477298Sobrien
257560484Sobrien  THUMB_SET_FUNC (symbolP, 1);
257660484Sobrien  ARM_SET_THUMB (symbolP, 1);
257760484Sobrien#if defined OBJ_ELF || defined OBJ_COFF
257860484Sobrien  ARM_SET_INTERWORK (symbolP, support_interwork);
257960484Sobrien#endif
258060484Sobrien}
258160484Sobrien
2582218822Sdim/* Directives: Mode selection.  */
2583218822Sdim
2584218822Sdim/* .syntax [unified|divided] - choose the new unified syntax
2585218822Sdim   (same for Arm and Thumb encoding, modulo slight differences in what
2586218822Sdim   can be represented) or the old divergent syntax for each mode.  */
258760484Sobrienstatic void
2588218822Sdims_syntax (int unused ATTRIBUTE_UNUSED)
258960484Sobrien{
2590218822Sdim  char *name, delim;
259177298Sobrien
2592218822Sdim  name = input_line_pointer;
2593218822Sdim  delim = get_symbol_end ();
259460484Sobrien
2595218822Sdim  if (!strcasecmp (name, "unified"))
2596218822Sdim    unified_syntax = TRUE;
2597218822Sdim  else if (!strcasecmp (name, "divided"))
2598218822Sdim    unified_syntax = FALSE;
2599218822Sdim  else
2600218822Sdim    {
2601218822Sdim      as_bad (_("unrecognized syntax mode \"%s\""), name);
2602218822Sdim      return;
260360484Sobrien    }
2604218822Sdim  *input_line_pointer = delim;
260560484Sobrien  demand_empty_rest_of_line ();
260660484Sobrien}
260760484Sobrien
2608218822Sdim/* Directives: sectioning and alignment.  */
260960484Sobrien
2610218822Sdim/* Same as s_align_ptwo but align 0 => align 2.	 */
2611218822Sdim
261260484Sobrienstatic void
2613218822Sdims_align (int unused ATTRIBUTE_UNUSED)
261460484Sobrien{
2615218822Sdim  int temp;
2616218822Sdim  bfd_boolean fill_p;
2617218822Sdim  long temp_fill;
2618218822Sdim  long max_alignment = 15;
261960484Sobrien
262060484Sobrien  temp = get_absolute_expression ();
2621218822Sdim  if (temp > max_alignment)
2622218822Sdim    as_bad (_("alignment too large: %d assumed"), temp = max_alignment);
2623218822Sdim  else if (temp < 0)
262460484Sobrien    {
2625218822Sdim      as_bad (_("alignment negative. 0 assumed."));
2626218822Sdim      temp = 0;
2627218822Sdim    }
262860484Sobrien
2629218822Sdim  if (*input_line_pointer == ',')
2630218822Sdim    {
2631218822Sdim      input_line_pointer++;
2632218822Sdim      temp_fill = get_absolute_expression ();
2633218822Sdim      fill_p = TRUE;
263460484Sobrien    }
2635218822Sdim  else
2636218822Sdim    {
2637218822Sdim      fill_p = FALSE;
2638218822Sdim      temp_fill = 0;
2639218822Sdim    }
264060484Sobrien
2641218822Sdim  if (!temp)
2642218822Sdim    temp = 2;
264360484Sobrien
2644218822Sdim  /* Only make a frag if we HAVE to.  */
2645218822Sdim  if (temp && !need_pass_2)
264660484Sobrien    {
2647218822Sdim      if (!fill_p && subseg_text_p (now_seg))
2648218822Sdim	frag_align_code (temp, 0);
2649218822Sdim      else
2650218822Sdim	frag_align (temp, (int) temp_fill, 0);
265160484Sobrien    }
2652218822Sdim  demand_empty_rest_of_line ();
265360484Sobrien
2654218822Sdim  record_alignment (now_seg, temp);
2655218822Sdim}
265660484Sobrien
2657218822Sdimstatic void
2658218822Sdims_bss (int ignore ATTRIBUTE_UNUSED)
2659218822Sdim{
2660218822Sdim  /* We don't support putting frags in the BSS segment, we fake it by
2661218822Sdim     marking in_bss, then looking at s_skip for clues.	*/
2662218822Sdim  subseg_set (bss_section, 0);
2663218822Sdim  demand_empty_rest_of_line ();
2664218822Sdim  mapping_state (MAP_DATA);
266560484Sobrien}
266660484Sobrien
2667218822Sdimstatic void
2668218822Sdims_even (int ignore ATTRIBUTE_UNUSED)
266960484Sobrien{
2670218822Sdim  /* Never make frag if expect extra pass.  */
2671218822Sdim  if (!need_pass_2)
2672218822Sdim    frag_align (1, 0, 0);
267360484Sobrien
2674218822Sdim  record_alignment (now_seg, 1);
267560484Sobrien
2676218822Sdim  demand_empty_rest_of_line ();
267760484Sobrien}
267860484Sobrien
2679218822Sdim/* Directives: Literal pools.  */
2680130561Sobrien
2681218822Sdimstatic literal_pool *
2682218822Sdimfind_literal_pool (void)
2683130561Sobrien{
2684218822Sdim  literal_pool * pool;
2685130561Sobrien
2686218822Sdim  for (pool = list_of_pools; pool != NULL; pool = pool->next)
2687130561Sobrien    {
2688218822Sdim      if (pool->section == now_seg
2689218822Sdim	  && pool->sub_section == now_subseg)
2690218822Sdim	break;
2691130561Sobrien    }
2692130561Sobrien
2693218822Sdim  return pool;
2694130561Sobrien}
2695130561Sobrien
2696218822Sdimstatic literal_pool *
2697218822Sdimfind_or_make_literal_pool (void)
269861843Sobrien{
2699218822Sdim  /* Next literal pool ID number.  */
2700218822Sdim  static unsigned int latest_pool_num = 1;
2701218822Sdim  literal_pool *      pool;
270261843Sobrien
2703218822Sdim  pool = find_literal_pool ();
270461843Sobrien
2705218822Sdim  if (pool == NULL)
270661843Sobrien    {
2707218822Sdim      /* Create a new pool.  */
2708218822Sdim      pool = xmalloc (sizeof (* pool));
2709218822Sdim      if (! pool)
2710218822Sdim	return NULL;
271161843Sobrien
2712218822Sdim      pool->next_free_entry = 0;
2713218822Sdim      pool->section	    = now_seg;
2714218822Sdim      pool->sub_section	    = now_subseg;
2715218822Sdim      pool->next	    = list_of_pools;
2716218822Sdim      pool->symbol	    = NULL;
271761843Sobrien
2718218822Sdim      /* Add it to the list.  */
2719218822Sdim      list_of_pools = pool;
2720218822Sdim    }
272177298Sobrien
2722218822Sdim  /* New pools, and emptied pools, will have a NULL symbol.  */
2723218822Sdim  if (pool->symbol == NULL)
2724218822Sdim    {
2725218822Sdim      pool->symbol = symbol_create (FAKE_LABEL_NAME, undefined_section,
2726218822Sdim				    (valueT) 0, &zero_address_frag);
2727218822Sdim      pool->id = latest_pool_num ++;
2728218822Sdim    }
272961843Sobrien
2730218822Sdim  /* Done.  */
2731218822Sdim  return pool;
273261843Sobrien}
273361843Sobrien
2734218822Sdim/* Add the literal in the global 'inst'
2735218822Sdim   structure to the relevent literal pool.  */
273677298Sobrien
273760484Sobrienstatic int
2738218822Sdimadd_to_lit_pool (void)
273960484Sobrien{
2740218822Sdim  literal_pool * pool;
2741218822Sdim  unsigned int entry;
274277298Sobrien
2743218822Sdim  pool = find_or_make_literal_pool ();
274461843Sobrien
2745218822Sdim  /* Check if this literal value is already in the pool.  */
2746218822Sdim  for (entry = 0; entry < pool->next_free_entry; entry ++)
274760484Sobrien    {
2748218822Sdim      if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
2749218822Sdim	  && (inst.reloc.exp.X_op == O_constant)
2750218822Sdim	  && (pool->literals[entry].X_add_number
2751218822Sdim	      == inst.reloc.exp.X_add_number)
2752218822Sdim	  && (pool->literals[entry].X_unsigned
2753218822Sdim	      == inst.reloc.exp.X_unsigned))
2754218822Sdim	break;
275561843Sobrien
2756218822Sdim      if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
2757218822Sdim	  && (inst.reloc.exp.X_op == O_symbol)
2758218822Sdim	  && (pool->literals[entry].X_add_number
2759218822Sdim	      == inst.reloc.exp.X_add_number)
2760218822Sdim	  && (pool->literals[entry].X_add_symbol
2761218822Sdim	      == inst.reloc.exp.X_add_symbol)
2762218822Sdim	  && (pool->literals[entry].X_op_symbol
2763218822Sdim	      == inst.reloc.exp.X_op_symbol))
2764218822Sdim	break;
276560484Sobrien    }
276660484Sobrien
2767218822Sdim  /* Do we need to create a new entry?	*/
2768218822Sdim  if (entry == pool->next_free_entry)
276989857Sobrien    {
2770218822Sdim      if (entry >= MAX_LITERAL_POOL_SIZE)
277160484Sobrien	{
2772218822Sdim	  inst.error = _("literal pool overflow");
277389857Sobrien	  return FAIL;
277489857Sobrien	}
2775218822Sdim
2776218822Sdim      pool->literals[entry] = inst.reloc.exp;
2777218822Sdim      pool->next_free_entry += 1;
277860484Sobrien    }
277960484Sobrien
2780218822Sdim  inst.reloc.exp.X_op	      = O_symbol;
2781218822Sdim  inst.reloc.exp.X_add_number = ((int) entry) * 4;
2782218822Sdim  inst.reloc.exp.X_add_symbol = pool->symbol;
2783218822Sdim
278460484Sobrien  return SUCCESS;
278560484Sobrien}
278660484Sobrien
2787218822Sdim/* Can't use symbol_new here, so have to create a symbol and then at
2788218822Sdim   a later date assign it a value. Thats what these functions do.  */
2789218822Sdim
2790218822Sdimstatic void
2791218822Sdimsymbol_locate (symbolS *    symbolP,
2792218822Sdim	       const char * name,	/* It is copied, the caller can modify.	 */
2793218822Sdim	       segT	    segment,	/* Segment identifier (SEG_<something>).  */
2794218822Sdim	       valueT	    valu,	/* Symbol value.  */
2795218822Sdim	       fragS *	    frag)	/* Associated fragment.	 */
279660484Sobrien{
2797218822Sdim  unsigned int name_length;
2798218822Sdim  char * preserved_copy_of_name;
279960484Sobrien
2800218822Sdim  name_length = strlen (name) + 1;   /* +1 for \0.  */
2801218822Sdim  obstack_grow (&notes, name, name_length);
2802218822Sdim  preserved_copy_of_name = obstack_finish (&notes);
280360484Sobrien
2804218822Sdim#ifdef tc_canonicalize_symbol_name
2805218822Sdim  preserved_copy_of_name =
2806218822Sdim    tc_canonicalize_symbol_name (preserved_copy_of_name);
2807218822Sdim#endif
280860484Sobrien
2809218822Sdim  S_SET_NAME (symbolP, preserved_copy_of_name);
281060484Sobrien
2811218822Sdim  S_SET_SEGMENT (symbolP, segment);
2812218822Sdim  S_SET_VALUE (symbolP, valu);
2813218822Sdim  symbol_clear_list_pointers (symbolP);
281460484Sobrien
2815218822Sdim  symbol_set_frag (symbolP, frag);
281660484Sobrien
2817218822Sdim  /* Link to end of symbol chain.  */
2818218822Sdim  {
2819218822Sdim    extern int symbol_table_frozen;
282060484Sobrien
2821218822Sdim    if (symbol_table_frozen)
2822218822Sdim      abort ();
2823218822Sdim  }
282460484Sobrien
2825218822Sdim  symbol_append (symbolP, symbol_lastP, & symbol_rootP, & symbol_lastP);
282660484Sobrien
2827218822Sdim  obj_symbol_new_hook (symbolP);
282860484Sobrien
2829218822Sdim#ifdef tc_symbol_new_hook
2830218822Sdim  tc_symbol_new_hook (symbolP);
2831218822Sdim#endif
283260484Sobrien
2833218822Sdim#ifdef DEBUG_SYMS
2834218822Sdim  verify_symbol_chain (symbol_rootP, symbol_lastP);
2835218822Sdim#endif /* DEBUG_SYMS  */
2836218822Sdim}
283760484Sobrien
283860484Sobrien
2839218822Sdimstatic void
2840218822Sdims_ltorg (int ignored ATTRIBUTE_UNUSED)
284160484Sobrien{
2842218822Sdim  unsigned int entry;
2843218822Sdim  literal_pool * pool;
2844218822Sdim  char sym_name[20];
284560484Sobrien
2846218822Sdim  pool = find_literal_pool ();
2847218822Sdim  if (pool == NULL
2848218822Sdim      || pool->symbol == NULL
2849218822Sdim      || pool->next_free_entry == 0)
2850218822Sdim    return;
285160484Sobrien
2852218822Sdim  mapping_state (MAP_DATA);
285360484Sobrien
2854218822Sdim  /* Align pool as you have word accesses.
2855218822Sdim     Only make a frag if we have to.  */
2856218822Sdim  if (!need_pass_2)
2857218822Sdim    frag_align (2, 0, 0);
285877298Sobrien
2859218822Sdim  record_alignment (now_seg, 2);
286077298Sobrien
2861218822Sdim  sprintf (sym_name, "$$lit_\002%x", pool->id);
286277298Sobrien
2863218822Sdim  symbol_locate (pool->symbol, sym_name, now_seg,
2864218822Sdim		 (valueT) frag_now_fix (), frag_now);
2865218822Sdim  symbol_table_insert (pool->symbol);
286660484Sobrien
2867218822Sdim  ARM_SET_THUMB (pool->symbol, thumb_mode);
286860484Sobrien
2869218822Sdim#if defined OBJ_COFF || defined OBJ_ELF
2870218822Sdim  ARM_SET_INTERWORK (pool->symbol, support_interwork);
2871218822Sdim#endif
287260484Sobrien
2873218822Sdim  for (entry = 0; entry < pool->next_free_entry; entry ++)
2874218822Sdim    /* First output the expression in the instruction to the pool.  */
2875218822Sdim    emit_expr (&(pool->literals[entry]), 4); /* .word  */
287660484Sobrien
2877218822Sdim  /* Mark the pool as empty.  */
2878218822Sdim  pool->next_free_entry = 0;
2879218822Sdim  pool->symbol = NULL;
288060484Sobrien}
288160484Sobrien
2882218822Sdim#ifdef OBJ_ELF
2883218822Sdim/* Forward declarations for functions below, in the MD interface
2884218822Sdim   section.  */
2885218822Sdimstatic void fix_new_arm (fragS *, int, short, expressionS *, int, int);
2886218822Sdimstatic valueT create_unwind_entry (int);
2887218822Sdimstatic void start_unwind_section (const segT, int);
2888218822Sdimstatic void add_unwind_opcode (valueT, int);
2889218822Sdimstatic void flush_pending_unwind (void);
2890218822Sdim
2891218822Sdim/* Directives: Data.  */
2892218822Sdim
2893218822Sdimstatic void
2894218822Sdims_arm_elf_cons (int nbytes)
289560484Sobrien{
2896218822Sdim  expressionS exp;
289760484Sobrien
2898218822Sdim#ifdef md_flush_pending_output
2899218822Sdim  md_flush_pending_output ();
2900218822Sdim#endif
2901218822Sdim
2902218822Sdim  if (is_it_end_of_statement ())
290360484Sobrien    {
2904218822Sdim      demand_empty_rest_of_line ();
2905218822Sdim      return;
2906218822Sdim    }
290760484Sobrien
2908218822Sdim#ifdef md_cons_align
2909218822Sdim  md_cons_align (nbytes);
2910218822Sdim#endif
291160484Sobrien
2912218822Sdim  mapping_state (MAP_DATA);
2913218822Sdim  do
2914218822Sdim    {
2915218822Sdim      int reloc;
2916218822Sdim      char *base = input_line_pointer;
291760484Sobrien
2918218822Sdim      expression (& exp);
291960484Sobrien
2920218822Sdim      if (exp.X_op != O_symbol)
2921218822Sdim	emit_expr (&exp, (unsigned int) nbytes);
2922218822Sdim      else
292360484Sobrien	{
2924218822Sdim	  char *before_reloc = input_line_pointer;
2925218822Sdim	  reloc = parse_reloc (&input_line_pointer);
2926218822Sdim	  if (reloc == -1)
292760484Sobrien	    {
2928218822Sdim	      as_bad (_("unrecognized relocation suffix"));
2929218822Sdim	      ignore_rest_of_line ();
2930218822Sdim	      return;
2931130561Sobrien	    }
2932218822Sdim	  else if (reloc == BFD_RELOC_UNUSED)
2933218822Sdim	    emit_expr (&exp, (unsigned int) nbytes);
2934218822Sdim	  else
2935130561Sobrien	    {
2936218822Sdim	      reloc_howto_type *howto = bfd_reloc_type_lookup (stdoutput, reloc);
2937218822Sdim	      int size = bfd_get_reloc_size (howto);
2938130561Sobrien
2939218822Sdim	      if (reloc == BFD_RELOC_ARM_PLT32)
294060484Sobrien		{
2941218822Sdim		  as_bad (_("(plt) is only valid on branch targets"));
2942218822Sdim		  reloc = BFD_RELOC_UNUSED;
2943218822Sdim		  size = 0;
2944218822Sdim		}
2945130561Sobrien
2946218822Sdim	      if (size > nbytes)
2947218822Sdim		as_bad (_("%s relocations do not fit in %d bytes"),
2948218822Sdim			howto->name, nbytes);
2949130561Sobrien	      else
2950130561Sobrien		{
2951218822Sdim		  /* We've parsed an expression stopping at O_symbol.
2952218822Sdim		     But there may be more expression left now that we
2953218822Sdim		     have parsed the relocation marker.  Parse it again.
2954218822Sdim		     XXX Surely there is a cleaner way to do this.  */
2955218822Sdim		  char *p = input_line_pointer;
2956218822Sdim		  int offset;
2957218822Sdim		  char *save_buf = alloca (input_line_pointer - base);
2958218822Sdim		  memcpy (save_buf, base, input_line_pointer - base);
2959218822Sdim		  memmove (base + (input_line_pointer - before_reloc),
2960218822Sdim			   base, before_reloc - base);
2961130561Sobrien
2962218822Sdim		  input_line_pointer = base + (input_line_pointer-before_reloc);
2963218822Sdim		  expression (&exp);
2964218822Sdim		  memcpy (base, save_buf, p - base);
2965130561Sobrien
2966218822Sdim		  offset = nbytes - size;
2967218822Sdim		  p = frag_more ((int) nbytes);
2968218822Sdim		  fix_new_exp (frag_now, p - frag_now->fr_literal + offset,
2969218822Sdim			       size, &exp, 0, reloc);
2970130561Sobrien		}
297160484Sobrien	    }
297260484Sobrien	}
2973218822Sdim    }
2974218822Sdim  while (*input_line_pointer++ == ',');
297560484Sobrien
2976218822Sdim  /* Put terminator back into stream.  */
2977218822Sdim  input_line_pointer --;
2978218822Sdim  demand_empty_rest_of_line ();
2979218822Sdim}
298060484Sobrien
298177298Sobrien
2982218822Sdim/* Parse a .rel31 directive.  */
298360484Sobrien
2984218822Sdimstatic void
2985218822Sdims_arm_rel31 (int ignored ATTRIBUTE_UNUSED)
2986218822Sdim{
2987218822Sdim  expressionS exp;
2988218822Sdim  char *p;
2989218822Sdim  valueT highbit;
299060484Sobrien
2991218822Sdim  highbit = 0;
2992218822Sdim  if (*input_line_pointer == '1')
2993218822Sdim    highbit = 0x80000000;
2994218822Sdim  else if (*input_line_pointer != '0')
2995218822Sdim    as_bad (_("expected 0 or 1"));
299660484Sobrien
2997218822Sdim  input_line_pointer++;
2998218822Sdim  if (*input_line_pointer != ',')
2999218822Sdim    as_bad (_("missing comma"));
3000218822Sdim  input_line_pointer++;
300160484Sobrien
3002218822Sdim#ifdef md_flush_pending_output
3003218822Sdim  md_flush_pending_output ();
3004218822Sdim#endif
300560484Sobrien
3006218822Sdim#ifdef md_cons_align
3007218822Sdim  md_cons_align (4);
3008218822Sdim#endif
300960484Sobrien
3010218822Sdim  mapping_state (MAP_DATA);
301160484Sobrien
3012218822Sdim  expression (&exp);
301360484Sobrien
3014218822Sdim  p = frag_more (4);
3015218822Sdim  md_number_to_chars (p, highbit, 4);
3016218822Sdim  fix_new_arm (frag_now, p - frag_now->fr_literal, 4, &exp, 1,
3017218822Sdim	       BFD_RELOC_ARM_PREL31);
3018130561Sobrien
3019218822Sdim  demand_empty_rest_of_line ();
3020218822Sdim}
3021130561Sobrien
3022218822Sdim/* Directives: AEABI stack-unwind tables.  */
3023130561Sobrien
3024218822Sdim/* Parse an unwind_fnstart directive.  Simply records the current location.  */
3025130561Sobrien
3026218822Sdimstatic void
3027218822Sdims_arm_unwind_fnstart (int ignored ATTRIBUTE_UNUSED)
3028218822Sdim{
3029218822Sdim  demand_empty_rest_of_line ();
3030218822Sdim  /* Mark the start of the function.  */
3031218822Sdim  unwind.proc_start = expr_build_dot ();
3032130561Sobrien
3033218822Sdim  /* Reset the rest of the unwind info.	 */
3034218822Sdim  unwind.opcode_count = 0;
3035218822Sdim  unwind.table_entry = NULL;
3036218822Sdim  unwind.personality_routine = NULL;
3037218822Sdim  unwind.personality_index = -1;
3038218822Sdim  unwind.frame_size = 0;
3039218822Sdim  unwind.fp_offset = 0;
3040218822Sdim  unwind.fp_reg = 13;
3041218822Sdim  unwind.fp_used = 0;
3042218822Sdim  unwind.sp_restored = 0;
3043130561Sobrien}
3044130561Sobrien
3045130561Sobrien
3046218822Sdim/* Parse a handlerdata directive.  Creates the exception handling table entry
3047218822Sdim   for the function.  */
3048130561Sobrien
3049218822Sdimstatic void
3050218822Sdims_arm_unwind_handlerdata (int ignored ATTRIBUTE_UNUSED)
3051218822Sdim{
3052218822Sdim  demand_empty_rest_of_line ();
3053218822Sdim  if (unwind.table_entry)
3054218822Sdim    as_bad (_("dupicate .handlerdata directive"));
3055130561Sobrien
3056218822Sdim  create_unwind_entry (1);
3057218822Sdim}
3058130561Sobrien
3059218822Sdim/* Parse an unwind_fnend directive.  Generates the index table entry.  */
3060130561Sobrien
3061218822Sdimstatic void
3062218822Sdims_arm_unwind_fnend (int ignored ATTRIBUTE_UNUSED)
3063218822Sdim{
3064218822Sdim  long where;
3065218822Sdim  char *ptr;
3066218822Sdim  valueT val;
3067130561Sobrien
3068218822Sdim  demand_empty_rest_of_line ();
3069130561Sobrien
3070218822Sdim  /* Add eh table entry.  */
3071218822Sdim  if (unwind.table_entry == NULL)
3072218822Sdim    val = create_unwind_entry (0);
3073218822Sdim  else
3074218822Sdim    val = 0;
3075130561Sobrien
3076218822Sdim  /* Add index table entry.  This is two words.	 */
3077218822Sdim  start_unwind_section (unwind.saved_seg, 1);
3078218822Sdim  frag_align (2, 0, 0);
3079218822Sdim  record_alignment (now_seg, 2);
3080130561Sobrien
3081218822Sdim  ptr = frag_more (8);
3082218822Sdim  where = frag_now_fix () - 8;
3083130561Sobrien
3084218822Sdim  /* Self relative offset of the function start.  */
3085218822Sdim  fix_new (frag_now, where, 4, unwind.proc_start, 0, 1,
3086218822Sdim	   BFD_RELOC_ARM_PREL31);
3087130561Sobrien
3088218822Sdim  /* Indicate dependency on EHABI-defined personality routines to the
3089218822Sdim     linker, if it hasn't been done already.  */
3090218822Sdim  if (unwind.personality_index >= 0 && unwind.personality_index < 3
3091218822Sdim      && !(marked_pr_dependency & (1 << unwind.personality_index)))
3092218822Sdim    {
3093218822Sdim      static const char *const name[] = {
3094218822Sdim	"__aeabi_unwind_cpp_pr0",
3095218822Sdim	"__aeabi_unwind_cpp_pr1",
3096218822Sdim	"__aeabi_unwind_cpp_pr2"
3097218822Sdim      };
3098218822Sdim      symbolS *pr = symbol_find_or_make (name[unwind.personality_index]);
3099218822Sdim      fix_new (frag_now, where, 0, pr, 0, 1, BFD_RELOC_NONE);
3100218822Sdim      marked_pr_dependency |= 1 << unwind.personality_index;
3101218822Sdim      seg_info (now_seg)->tc_segment_info_data.marked_pr_dependency
3102218822Sdim	= marked_pr_dependency;
3103218822Sdim    }
3104130561Sobrien
3105218822Sdim  if (val)
3106218822Sdim    /* Inline exception table entry.  */
3107218822Sdim    md_number_to_chars (ptr + 4, val, 4);
3108130561Sobrien  else
3109218822Sdim    /* Self relative offset of the table entry.	 */
3110218822Sdim    fix_new (frag_now, where + 4, 4, unwind.table_entry, 0, 1,
3111218822Sdim	     BFD_RELOC_ARM_PREL31);
3112130561Sobrien
3113218822Sdim  /* Restore the original section.  */
3114218822Sdim  subseg_set (unwind.saved_seg, unwind.saved_subseg);
3115130561Sobrien}
3116130561Sobrien
3117218822Sdim
3118218822Sdim/* Parse an unwind_cantunwind directive.  */
3119218822Sdim
312060484Sobrienstatic void
3121218822Sdims_arm_unwind_cantunwind (int ignored ATTRIBUTE_UNUSED)
312260484Sobrien{
3123218822Sdim  demand_empty_rest_of_line ();
3124218822Sdim  if (unwind.personality_routine || unwind.personality_index != -1)
3125218822Sdim    as_bad (_("personality routine specified for cantunwind frame"));
3126218822Sdim
3127218822Sdim  unwind.personality_index = -2;
312860484Sobrien}
312960484Sobrien
3130218822Sdim
3131218822Sdim/* Parse a personalityindex directive.	*/
3132218822Sdim
313360484Sobrienstatic void
3134218822Sdims_arm_unwind_personalityindex (int ignored ATTRIBUTE_UNUSED)
313560484Sobrien{
3136218822Sdim  expressionS exp;
313777298Sobrien
3138218822Sdim  if (unwind.personality_routine || unwind.personality_index != -1)
3139218822Sdim    as_bad (_("duplicate .personalityindex directive"));
314060484Sobrien
3141218822Sdim  expression (&exp);
314260484Sobrien
3143218822Sdim  if (exp.X_op != O_constant
3144218822Sdim      || exp.X_add_number < 0 || exp.X_add_number > 15)
314560484Sobrien    {
3146218822Sdim      as_bad (_("bad personality routine number"));
3147218822Sdim      ignore_rest_of_line ();
314860484Sobrien      return;
314960484Sobrien    }
315060484Sobrien
3151218822Sdim  unwind.personality_index = exp.X_add_number;
315261843Sobrien
3153218822Sdim  demand_empty_rest_of_line ();
3154218822Sdim}
315577298Sobrien
315661843Sobrien
3157218822Sdim/* Parse a personality directive.  */
315877298Sobrien
3159218822Sdimstatic void
3160218822Sdims_arm_unwind_personality (int ignored ATTRIBUTE_UNUSED)
3161218822Sdim{
3162218822Sdim  char *name, *p, c;
3163218822Sdim
3164218822Sdim  if (unwind.personality_routine || unwind.personality_index != -1)
3165218822Sdim    as_bad (_("duplicate .personality directive"));
3166218822Sdim
3167218822Sdim  name = input_line_pointer;
3168218822Sdim  c = get_symbol_end ();
3169218822Sdim  p = input_line_pointer;
3170218822Sdim  unwind.personality_routine = symbol_find_or_make (name);
3171218822Sdim  *p = c;
3172218822Sdim  demand_empty_rest_of_line ();
317360484Sobrien}
317460484Sobrien
317577298Sobrien
3176218822Sdim/* Parse a directive saving core registers.  */
3177218822Sdim
317860484Sobrienstatic void
3179218822Sdims_arm_unwind_save_core (void)
318060484Sobrien{
3181218822Sdim  valueT op;
3182218822Sdim  long range;
3183218822Sdim  int n;
318460484Sobrien
3185218822Sdim  range = parse_reg_list (&input_line_pointer);
3186218822Sdim  if (range == FAIL)
318761843Sobrien    {
3188218822Sdim      as_bad (_("expected register list"));
3189218822Sdim      ignore_rest_of_line ();
319061843Sobrien      return;
319161843Sobrien    }
319261843Sobrien
3193218822Sdim  demand_empty_rest_of_line ();
319460484Sobrien
3195218822Sdim  /* Turn .unwind_movsp ip followed by .unwind_save {..., ip, ...}
3196218822Sdim     into .unwind_save {..., sp...}.  We aren't bothered about the value of
3197218822Sdim     ip because it is clobbered by calls.  */
3198218822Sdim  if (unwind.sp_restored && unwind.fp_reg == 12
3199218822Sdim      && (range & 0x3000) == 0x1000)
320060484Sobrien    {
3201218822Sdim      unwind.opcode_count--;
3202218822Sdim      unwind.sp_restored = 0;
3203218822Sdim      range = (range | 0x2000) & ~0x1000;
3204218822Sdim      unwind.pending_offset = 0;
320561843Sobrien    }
320660484Sobrien
3207218822Sdim  /* Pop r4-r15.  */
3208218822Sdim  if (range & 0xfff0)
320961843Sobrien    {
3210218822Sdim      /* See if we can use the short opcodes.  These pop a block of up to 8
3211218822Sdim	 registers starting with r4, plus maybe r14.  */
3212218822Sdim      for (n = 0; n < 8; n++)
3213218822Sdim	{
3214218822Sdim	  /* Break at the first non-saved register.	 */
3215218822Sdim	  if ((range & (1 << (n + 4))) == 0)
3216218822Sdim	    break;
3217218822Sdim	}
3218218822Sdim      /* See if there are any other bits set.  */
3219218822Sdim      if (n == 0 || (range & (0xfff0 << n) & 0xbff0) != 0)
3220218822Sdim	{
3221218822Sdim	  /* Use the long form.  */
3222218822Sdim	  op = 0x8000 | ((range >> 4) & 0xfff);
3223218822Sdim	  add_unwind_opcode (op, 2);
3224218822Sdim	}
3225218822Sdim      else
3226218822Sdim	{
3227218822Sdim	  /* Use the short form.  */
3228218822Sdim	  if (range & 0x4000)
3229218822Sdim	    op = 0xa8; /* Pop r14.	*/
3230218822Sdim	  else
3231218822Sdim	    op = 0xa0; /* Do not pop r14.  */
3232218822Sdim	  op |= (n - 1);
3233218822Sdim	  add_unwind_opcode (op, 1);
3234218822Sdim	}
323560484Sobrien    }
323661843Sobrien
3237218822Sdim  /* Pop r0-r3.	 */
3238218822Sdim  if (range & 0xf)
323961843Sobrien    {
3240218822Sdim      op = 0xb100 | (range & 0xf);
3241218822Sdim      add_unwind_opcode (op, 2);
324261843Sobrien    }
324377298Sobrien
3244218822Sdim  /* Record the number of bytes pushed.	 */
3245218822Sdim  for (n = 0; n < 16; n++)
324661843Sobrien    {
3247218822Sdim      if (range & (1 << n))
3248218822Sdim	unwind.frame_size += 4;
324961843Sobrien    }
3250218822Sdim}
325177298Sobrien
325277298Sobrien
3253218822Sdim/* Parse a directive saving FPA registers.  */
325477298Sobrien
325560484Sobrienstatic void
3256218822Sdims_arm_unwind_save_fpa (int reg)
325760484Sobrien{
3258218822Sdim  expressionS exp;
3259218822Sdim  int num_regs;
3260218822Sdim  valueT op;
326160484Sobrien
3262218822Sdim  /* Get Number of registers to transfer.  */
3263218822Sdim  if (skip_past_comma (&input_line_pointer) != FAIL)
3264218822Sdim    expression (&exp);
3265218822Sdim  else
3266218822Sdim    exp.X_op = O_illegal;
326760484Sobrien
3268218822Sdim  if (exp.X_op != O_constant)
326960484Sobrien    {
3270218822Sdim      as_bad (_("expected , <constant>"));
3271218822Sdim      ignore_rest_of_line ();
327260484Sobrien      return;
327360484Sobrien    }
327460484Sobrien
3275218822Sdim  num_regs = exp.X_add_number;
327660484Sobrien
3277218822Sdim  if (num_regs < 1 || num_regs > 4)
327860484Sobrien    {
3279218822Sdim      as_bad (_("number of registers must be in the range [1:4]"));
3280218822Sdim      ignore_rest_of_line ();
328160484Sobrien      return;
328260484Sobrien    }
328360484Sobrien
3284218822Sdim  demand_empty_rest_of_line ();
328560484Sobrien
3286218822Sdim  if (reg == 4)
328760484Sobrien    {
3288218822Sdim      /* Short form.  */
3289218822Sdim      op = 0xb4 | (num_regs - 1);
3290218822Sdim      add_unwind_opcode (op, 1);
329160484Sobrien    }
3292218822Sdim  else
329360484Sobrien    {
3294218822Sdim      /* Long form.  */
3295218822Sdim      op = 0xc800 | (reg << 4) | (num_regs - 1);
3296218822Sdim      add_unwind_opcode (op, 2);
329760484Sobrien    }
3298218822Sdim  unwind.frame_size += num_regs * 12;
329960484Sobrien}
330060484Sobrien
3301218822Sdim
3302218822Sdim/* Parse a directive saving VFP registers for ARMv6 and above.  */
3303218822Sdim
330460484Sobrienstatic void
3305218822Sdims_arm_unwind_save_vfp_armv6 (void)
330660484Sobrien{
3307218822Sdim  int count;
3308218822Sdim  unsigned int start;
3309218822Sdim  valueT op;
3310218822Sdim  int num_vfpv3_regs = 0;
3311218822Sdim  int num_regs_below_16;
331277298Sobrien
3313218822Sdim  count = parse_vfp_reg_list (&input_line_pointer, &start, REGLIST_VFP_D);
3314218822Sdim  if (count == FAIL)
331560484Sobrien    {
3316218822Sdim      as_bad (_("expected register list"));
3317218822Sdim      ignore_rest_of_line ();
331860484Sobrien      return;
331960484Sobrien    }
332060484Sobrien
3321218822Sdim  demand_empty_rest_of_line ();
332260484Sobrien
3323218822Sdim  /* We always generate FSTMD/FLDMD-style unwinding opcodes (rather
3324218822Sdim     than FSTMX/FLDMX-style ones).  */
332560484Sobrien
3326218822Sdim  /* Generate opcode for (VFPv3) registers numbered in the range 16 .. 31.  */
3327218822Sdim  if (start >= 16)
3328218822Sdim    num_vfpv3_regs = count;
3329218822Sdim  else if (start + count > 16)
3330218822Sdim    num_vfpv3_regs = start + count - 16;
333160484Sobrien
3332218822Sdim  if (num_vfpv3_regs > 0)
333360484Sobrien    {
3334218822Sdim      int start_offset = start > 16 ? start - 16 : 0;
3335218822Sdim      op = 0xc800 | (start_offset << 4) | (num_vfpv3_regs - 1);
3336218822Sdim      add_unwind_opcode (op, 2);
333760484Sobrien    }
333860484Sobrien
3339218822Sdim  /* Generate opcode for registers numbered in the range 0 .. 15.  */
3340218822Sdim  num_regs_below_16 = num_vfpv3_regs > 0 ? 16 - (int) start : count;
3341218822Sdim  assert (num_regs_below_16 + num_vfpv3_regs == count);
3342218822Sdim  if (num_regs_below_16 > 0)
334360484Sobrien    {
3344218822Sdim      op = 0xc900 | (start << 4) | (num_regs_below_16 - 1);
3345218822Sdim      add_unwind_opcode (op, 2);
334660484Sobrien    }
334760484Sobrien
3348218822Sdim  unwind.frame_size += count * 8;
334960484Sobrien}
335060484Sobrien
3351218822Sdim
3352218822Sdim/* Parse a directive saving VFP registers for pre-ARMv6.  */
3353218822Sdim
335460484Sobrienstatic void
3355218822Sdims_arm_unwind_save_vfp (void)
335660484Sobrien{
3357218822Sdim  int count;
3358218822Sdim  unsigned int reg;
3359218822Sdim  valueT op;
336060484Sobrien
3361218822Sdim  count = parse_vfp_reg_list (&input_line_pointer, &reg, REGLIST_VFP_D);
3362218822Sdim  if (count == FAIL)
336360484Sobrien    {
3364218822Sdim      as_bad (_("expected register list"));
3365218822Sdim      ignore_rest_of_line ();
336660484Sobrien      return;
336760484Sobrien    }
336860484Sobrien
3369218822Sdim  demand_empty_rest_of_line ();
337060484Sobrien
3371218822Sdim  if (reg == 8)
337260484Sobrien    {
3373218822Sdim      /* Short form.  */
3374218822Sdim      op = 0xb8 | (count - 1);
3375218822Sdim      add_unwind_opcode (op, 1);
337660484Sobrien    }
3377218822Sdim  else
337860484Sobrien    {
3379218822Sdim      /* Long form.  */
3380218822Sdim      op = 0xb300 | (reg << 4) | (count - 1);
3381218822Sdim      add_unwind_opcode (op, 2);
338260484Sobrien    }
3383218822Sdim  unwind.frame_size += count * 8 + 4;
338460484Sobrien}
338560484Sobrien
338677298Sobrien
3387218822Sdim/* Parse a directive saving iWMMXt data registers.  */
338877298Sobrien
3389218822Sdimstatic void
3390218822Sdims_arm_unwind_save_mmxwr (void)
339177298Sobrien{
3392218822Sdim  int reg;
3393218822Sdim  int hi_reg;
3394218822Sdim  int i;
3395218822Sdim  unsigned mask = 0;
3396218822Sdim  valueT op;
339777298Sobrien
3398218822Sdim  if (*input_line_pointer == '{')
3399218822Sdim    input_line_pointer++;
340077298Sobrien
3401218822Sdim  do
3402218822Sdim    {
3403218822Sdim      reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWR);
340477298Sobrien
3405218822Sdim      if (reg == FAIL)
3406218822Sdim	{
3407218822Sdim	  as_bad (_(reg_expected_msgs[REG_TYPE_MMXWR]));
3408218822Sdim	  goto error;
3409218822Sdim	}
341077298Sobrien
3411218822Sdim      if (mask >> reg)
3412218822Sdim	as_tsktsk (_("register list not in ascending order"));
3413218822Sdim      mask |= 1 << reg;
3414218822Sdim
3415218822Sdim      if (*input_line_pointer == '-')
3416218822Sdim	{
3417218822Sdim	  input_line_pointer++;
3418218822Sdim	  hi_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWR);
3419218822Sdim	  if (hi_reg == FAIL)
3420218822Sdim	    {
3421218822Sdim	      as_bad (_(reg_expected_msgs[REG_TYPE_MMXWR]));
3422218822Sdim	      goto error;
3423218822Sdim	    }
3424218822Sdim	  else if (reg >= hi_reg)
3425218822Sdim	    {
3426218822Sdim	      as_bad (_("bad register range"));
3427218822Sdim	      goto error;
3428218822Sdim	    }
3429218822Sdim	  for (; reg < hi_reg; reg++)
3430218822Sdim	    mask |= 1 << reg;
3431218822Sdim	}
343277298Sobrien    }
3433218822Sdim  while (skip_past_comma (&input_line_pointer) != FAIL);
343477298Sobrien
3435218822Sdim  if (*input_line_pointer == '}')
3436218822Sdim    input_line_pointer++;
343777298Sobrien
3438218822Sdim  demand_empty_rest_of_line ();
343977298Sobrien
3440218822Sdim  /* Generate any deferred opcodes because we're going to be looking at
3441218822Sdim     the list.	*/
3442218822Sdim  flush_pending_unwind ();
344377298Sobrien
3444218822Sdim  for (i = 0; i < 16; i++)
3445218822Sdim    {
3446218822Sdim      if (mask & (1 << i))
3447218822Sdim	unwind.frame_size += 8;
3448218822Sdim    }
344977298Sobrien
3450218822Sdim  /* Attempt to combine with a previous opcode.	 We do this because gcc
3451218822Sdim     likes to output separate unwind directives for a single block of
3452218822Sdim     registers.	 */
3453218822Sdim  if (unwind.opcode_count > 0)
345477298Sobrien    {
3455218822Sdim      i = unwind.opcodes[unwind.opcode_count - 1];
3456218822Sdim      if ((i & 0xf8) == 0xc0)
345777298Sobrien	{
3458218822Sdim	  i &= 7;
3459218822Sdim	  /* Only merge if the blocks are contiguous.  */
3460218822Sdim	  if (i < 6)
346177298Sobrien	    {
3462218822Sdim	      if ((mask & 0xfe00) == (1 << 9))
3463218822Sdim		{
3464218822Sdim		  mask |= ((1 << (i + 11)) - 1) & 0xfc00;
3465218822Sdim		  unwind.opcode_count--;
3466218822Sdim		}
346777298Sobrien	    }
3468218822Sdim	  else if (i == 6 && unwind.opcode_count >= 2)
346977298Sobrien	    {
3470218822Sdim	      i = unwind.opcodes[unwind.opcode_count - 2];
3471218822Sdim	      reg = i >> 4;
3472218822Sdim	      i &= 0xf;
347377298Sobrien
3474218822Sdim	      op = 0xffff << (reg - 1);
3475218822Sdim	      if (reg > 0
3476218822Sdim		  && ((mask & op) == (1u << (reg - 1))))
3477104834Sobrien		{
3478218822Sdim		  op = (1 << (reg + i + 1)) - 1;
3479218822Sdim		  op &= ~((1 << reg) - 1);
3480218822Sdim		  mask |= op;
3481218822Sdim		  unwind.opcode_count -= 2;
3482104834Sobrien		}
348377298Sobrien	    }
348477298Sobrien	}
3485218822Sdim    }
3486218822Sdim
3487218822Sdim  hi_reg = 15;
3488218822Sdim  /* We want to generate opcodes in the order the registers have been
3489218822Sdim     saved, ie. descending order.  */
3490218822Sdim  for (reg = 15; reg >= -1; reg--)
3491218822Sdim    {
3492218822Sdim      /* Save registers in blocks.  */
3493218822Sdim      if (reg < 0
3494218822Sdim	  || !(mask & (1 << reg)))
349577298Sobrien	{
3496218822Sdim	  /* We found an unsaved reg.  Generate opcodes to save the
3497218822Sdim	     preceeding block.	*/
3498218822Sdim	  if (reg != hi_reg)
349977298Sobrien	    {
3500218822Sdim	      if (reg == 9)
3501218822Sdim		{
3502218822Sdim		  /* Short form.  */
3503218822Sdim		  op = 0xc0 | (hi_reg - 10);
3504218822Sdim		  add_unwind_opcode (op, 1);
3505218822Sdim		}
3506218822Sdim	      else
3507218822Sdim		{
3508218822Sdim		  /* Long form.	 */
3509218822Sdim		  op = 0xc600 | ((reg + 1) << 4) | ((hi_reg - reg) - 1);
3510218822Sdim		  add_unwind_opcode (op, 2);
3511218822Sdim		}
351277298Sobrien	    }
3513218822Sdim	  hi_reg = reg - 1;
3514218822Sdim	}
3515218822Sdim    }
351677298Sobrien
3517218822Sdim  return;
3518218822Sdimerror:
3519218822Sdim  ignore_rest_of_line ();
3520218822Sdim}
352177298Sobrien
3522218822Sdimstatic void
3523218822Sdims_arm_unwind_save_mmxwcg (void)
3524218822Sdim{
3525218822Sdim  int reg;
3526218822Sdim  int hi_reg;
3527218822Sdim  unsigned mask = 0;
3528218822Sdim  valueT op;
352977298Sobrien
3530218822Sdim  if (*input_line_pointer == '{')
3531218822Sdim    input_line_pointer++;
353277298Sobrien
3533218822Sdim  do
3534218822Sdim    {
3535218822Sdim      reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWCG);
353677298Sobrien
3537218822Sdim      if (reg == FAIL)
3538218822Sdim	{
3539218822Sdim	  as_bad (_(reg_expected_msgs[REG_TYPE_MMXWCG]));
3540218822Sdim	  goto error;
3541218822Sdim	}
354277298Sobrien
3543218822Sdim      reg -= 8;
3544218822Sdim      if (mask >> reg)
3545218822Sdim	as_tsktsk (_("register list not in ascending order"));
3546218822Sdim      mask |= 1 << reg;
3547218822Sdim
3548218822Sdim      if (*input_line_pointer == '-')
3549218822Sdim	{
3550218822Sdim	  input_line_pointer++;
3551218822Sdim	  hi_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_MMXWCG);
3552218822Sdim	  if (hi_reg == FAIL)
355377298Sobrien	    {
3554218822Sdim	      as_bad (_(reg_expected_msgs[REG_TYPE_MMXWCG]));
3555218822Sdim	      goto error;
355677298Sobrien	    }
3557218822Sdim	  else if (reg >= hi_reg)
3558218822Sdim	    {
3559218822Sdim	      as_bad (_("bad register range"));
3560218822Sdim	      goto error;
3561218822Sdim	    }
3562218822Sdim	  for (; reg < hi_reg; reg++)
3563218822Sdim	    mask |= 1 << reg;
356477298Sobrien	}
356577298Sobrien    }
3566218822Sdim  while (skip_past_comma (&input_line_pointer) != FAIL);
356777298Sobrien
3568218822Sdim  if (*input_line_pointer == '}')
3569218822Sdim    input_line_pointer++;
357077298Sobrien
3571218822Sdim  demand_empty_rest_of_line ();
357277298Sobrien
3573218822Sdim  /* Generate any deferred opcodes because we're going to be looking at
3574218822Sdim     the list.	*/
3575218822Sdim  flush_pending_unwind ();
357677298Sobrien
3577218822Sdim  for (reg = 0; reg < 16; reg++)
3578218822Sdim    {
3579218822Sdim      if (mask & (1 << reg))
3580218822Sdim	unwind.frame_size += 4;
3581218822Sdim    }
3582218822Sdim  op = 0xc700 | mask;
3583218822Sdim  add_unwind_opcode (op, 2);
3584218822Sdim  return;
3585218822Sdimerror:
3586218822Sdim  ignore_rest_of_line ();
358777298Sobrien}
358877298Sobrien
358977298Sobrien
3590218822Sdim/* Parse an unwind_save directive.
3591218822Sdim   If the argument is non-zero, this is a .vsave directive.  */
3592218822Sdim
359377298Sobrienstatic void
3594218822Sdims_arm_unwind_save (int arch_v6)
359577298Sobrien{
3596218822Sdim  char *peek;
3597218822Sdim  struct reg_entry *reg;
3598218822Sdim  bfd_boolean had_brace = FALSE;
359977298Sobrien
3600218822Sdim  /* Figure out what sort of save we have.  */
3601218822Sdim  peek = input_line_pointer;
360277298Sobrien
3603218822Sdim  if (*peek == '{')
3604218822Sdim    {
3605218822Sdim      had_brace = TRUE;
3606218822Sdim      peek++;
3607218822Sdim    }
360877298Sobrien
3609218822Sdim  reg = arm_reg_parse_multi (&peek);
361077298Sobrien
3611218822Sdim  if (!reg)
3612218822Sdim    {
3613218822Sdim      as_bad (_("register expected"));
3614218822Sdim      ignore_rest_of_line ();
3615218822Sdim      return;
3616218822Sdim    }
3617218822Sdim
3618218822Sdim  switch (reg->type)
3619218822Sdim    {
3620218822Sdim    case REG_TYPE_FN:
3621218822Sdim      if (had_brace)
3622218822Sdim	{
3623218822Sdim	  as_bad (_("FPA .unwind_save does not take a register list"));
3624218822Sdim	  ignore_rest_of_line ();
3625218822Sdim	  return;
3626218822Sdim	}
3627218822Sdim      s_arm_unwind_save_fpa (reg->number);
3628218822Sdim      return;
3629218822Sdim
3630218822Sdim    case REG_TYPE_RN:	  s_arm_unwind_save_core ();   return;
3631218822Sdim    case REG_TYPE_VFD:
3632218822Sdim      if (arch_v6)
3633218822Sdim        s_arm_unwind_save_vfp_armv6 ();
3634218822Sdim      else
3635218822Sdim        s_arm_unwind_save_vfp ();
3636218822Sdim      return;
3637218822Sdim    case REG_TYPE_MMXWR:  s_arm_unwind_save_mmxwr ();  return;
3638218822Sdim    case REG_TYPE_MMXWCG: s_arm_unwind_save_mmxwcg (); return;
3639218822Sdim
3640218822Sdim    default:
3641218822Sdim      as_bad (_(".unwind_save does not support this kind of register"));
3642218822Sdim      ignore_rest_of_line ();
3643218822Sdim    }
364477298Sobrien}
364577298Sobrien
364677298Sobrien
3647218822Sdim/* Parse an unwind_movsp directive.  */
3648218822Sdim
364977298Sobrienstatic void
3650218822Sdims_arm_unwind_movsp (int ignored ATTRIBUTE_UNUSED)
365177298Sobrien{
3652218822Sdim  int reg;
3653218822Sdim  valueT op;
3654218822Sdim  int offset;
365577298Sobrien
3656218822Sdim  reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN);
3657218822Sdim  if (reg == FAIL)
365877298Sobrien    {
3659218822Sdim      as_bad (_(reg_expected_msgs[REG_TYPE_RN]));
3660218822Sdim      ignore_rest_of_line ();
366177298Sobrien      return;
366277298Sobrien    }
366377298Sobrien
3664218822Sdim  /* Optional constant.	 */
3665218822Sdim  if (skip_past_comma (&input_line_pointer) != FAIL)
366677298Sobrien    {
3667218822Sdim      if (immediate_for_directive (&offset) == FAIL)
3668218822Sdim	return;
3669218822Sdim    }
3670218822Sdim  else
3671218822Sdim    offset = 0;
3672218822Sdim
3673218822Sdim  demand_empty_rest_of_line ();
3674218822Sdim
3675218822Sdim  if (reg == REG_SP || reg == REG_PC)
3676218822Sdim    {
3677218822Sdim      as_bad (_("SP and PC not permitted in .unwind_movsp directive"));
367877298Sobrien      return;
367977298Sobrien    }
368077298Sobrien
3681218822Sdim  if (unwind.fp_reg != REG_SP)
3682218822Sdim    as_bad (_("unexpected .unwind_movsp directive"));
368377298Sobrien
3684218822Sdim  /* Generate opcode to restore the value.  */
3685218822Sdim  op = 0x90 | reg;
3686218822Sdim  add_unwind_opcode (op, 1);
3687218822Sdim
3688218822Sdim  /* Record the information for later.	*/
3689218822Sdim  unwind.fp_reg = reg;
3690218822Sdim  unwind.fp_offset = unwind.frame_size - offset;
3691218822Sdim  unwind.sp_restored = 1;
369277298Sobrien}
369377298Sobrien
3694218822Sdim/* Parse an unwind_pad directive.  */
369577298Sobrien
369677298Sobrienstatic void
3697218822Sdims_arm_unwind_pad (int ignored ATTRIBUTE_UNUSED)
369877298Sobrien{
3699218822Sdim  int offset;
370077298Sobrien
3701218822Sdim  if (immediate_for_directive (&offset) == FAIL)
3702218822Sdim    return;
370377298Sobrien
3704218822Sdim  if (offset & 3)
3705218822Sdim    {
3706218822Sdim      as_bad (_("stack increment must be multiple of 4"));
3707218822Sdim      ignore_rest_of_line ();
3708218822Sdim      return;
3709218822Sdim    }
371077298Sobrien
3711218822Sdim  /* Don't generate any opcodes, just record the details for later.  */
3712218822Sdim  unwind.frame_size += offset;
3713218822Sdim  unwind.pending_offset += offset;
371477298Sobrien
3715218822Sdim  demand_empty_rest_of_line ();
371677298Sobrien}
371777298Sobrien
3718218822Sdim/* Parse an unwind_setfp directive.  */
371977298Sobrien
372077298Sobrienstatic void
3721218822Sdims_arm_unwind_setfp (int ignored ATTRIBUTE_UNUSED)
372277298Sobrien{
3723218822Sdim  int sp_reg;
3724218822Sdim  int fp_reg;
3725218822Sdim  int offset;
372677298Sobrien
3727218822Sdim  fp_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN);
3728218822Sdim  if (skip_past_comma (&input_line_pointer) == FAIL)
3729218822Sdim    sp_reg = FAIL;
3730218822Sdim  else
3731218822Sdim    sp_reg = arm_reg_parse (&input_line_pointer, REG_TYPE_RN);
373277298Sobrien
3733218822Sdim  if (fp_reg == FAIL || sp_reg == FAIL)
3734218822Sdim    {
3735218822Sdim      as_bad (_("expected <reg>, <reg>"));
3736218822Sdim      ignore_rest_of_line ();
3737218822Sdim      return;
3738218822Sdim    }
373977298Sobrien
3740218822Sdim  /* Optional constant.	 */
3741218822Sdim  if (skip_past_comma (&input_line_pointer) != FAIL)
3742218822Sdim    {
3743218822Sdim      if (immediate_for_directive (&offset) == FAIL)
3744218822Sdim	return;
3745218822Sdim    }
3746218822Sdim  else
3747218822Sdim    offset = 0;
374877298Sobrien
3749218822Sdim  demand_empty_rest_of_line ();
3750218822Sdim
3751218822Sdim  if (sp_reg != 13 && sp_reg != unwind.fp_reg)
3752218822Sdim    {
3753218822Sdim      as_bad (_("register must be either sp or set by a previous"
3754218822Sdim		"unwind_movsp directive"));
3755218822Sdim      return;
3756218822Sdim    }
3757218822Sdim
3758218822Sdim  /* Don't generate any opcodes, just record the information for later.	 */
3759218822Sdim  unwind.fp_reg = fp_reg;
3760218822Sdim  unwind.fp_used = 1;
3761218822Sdim  if (sp_reg == 13)
3762218822Sdim    unwind.fp_offset = unwind.frame_size - offset;
376377298Sobrien  else
3764218822Sdim    unwind.fp_offset -= offset;
376577298Sobrien}
376677298Sobrien
3767218822Sdim/* Parse an unwind_raw directive.  */
376877298Sobrien
376977298Sobrienstatic void
3770218822Sdims_arm_unwind_raw (int ignored ATTRIBUTE_UNUSED)
377177298Sobrien{
3772218822Sdim  expressionS exp;
3773218822Sdim  /* This is an arbitrary limit.	 */
3774218822Sdim  unsigned char op[16];
3775218822Sdim  int count;
377677298Sobrien
3777218822Sdim  expression (&exp);
3778218822Sdim  if (exp.X_op == O_constant
3779218822Sdim      && skip_past_comma (&input_line_pointer) != FAIL)
378077298Sobrien    {
3781218822Sdim      unwind.frame_size += exp.X_add_number;
3782218822Sdim      expression (&exp);
378377298Sobrien    }
3784218822Sdim  else
3785218822Sdim    exp.X_op = O_illegal;
378677298Sobrien
3787218822Sdim  if (exp.X_op != O_constant)
378877298Sobrien    {
3789218822Sdim      as_bad (_("expected <offset>, <opcode>"));
3790218822Sdim      ignore_rest_of_line ();
379177298Sobrien      return;
379277298Sobrien    }
379377298Sobrien
3794218822Sdim  count = 0;
379577298Sobrien
3796218822Sdim  /* Parse the opcode.	*/
3797218822Sdim  for (;;)
379877298Sobrien    {
3799218822Sdim      if (count >= 16)
3800218822Sdim	{
3801218822Sdim	  as_bad (_("unwind opcode too long"));
3802218822Sdim	  ignore_rest_of_line ();
3803218822Sdim	}
3804218822Sdim      if (exp.X_op != O_constant || exp.X_add_number & ~0xff)
3805218822Sdim	{
3806218822Sdim	  as_bad (_("invalid unwind opcode"));
3807218822Sdim	  ignore_rest_of_line ();
3808218822Sdim	  return;
3809218822Sdim	}
3810218822Sdim      op[count++] = exp.X_add_number;
381177298Sobrien
3812218822Sdim      /* Parse the next byte.  */
3813218822Sdim      if (skip_past_comma (&input_line_pointer) == FAIL)
3814218822Sdim	break;
381577298Sobrien
3816218822Sdim      expression (&exp);
381777298Sobrien    }
381877298Sobrien
3819218822Sdim  /* Add the opcode bytes in reverse order.  */
3820218822Sdim  while (count--)
3821218822Sdim    add_unwind_opcode (op[count], 1);
3822218822Sdim
3823218822Sdim  demand_empty_rest_of_line ();
382477298Sobrien}
382577298Sobrien
382677298Sobrien
3827218822Sdim/* Parse a .eabi_attribute directive.  */
3828218822Sdim
382977298Sobrienstatic void
3830218822Sdims_arm_eabi_attribute (int ignored ATTRIBUTE_UNUSED)
383177298Sobrien{
3832218822Sdim  s_vendor_attribute (OBJ_ATTR_PROC);
3833218822Sdim}
3834218822Sdim#endif /* OBJ_ELF */
383577298Sobrien
3836218822Sdimstatic void s_arm_arch (int);
3837218822Sdimstatic void s_arm_object_arch (int);
3838218822Sdimstatic void s_arm_cpu (int);
3839218822Sdimstatic void s_arm_fpu (int);
384077298Sobrien
3841218822Sdim#ifdef TE_PE
384277298Sobrien
3843218822Sdimstatic void
3844218822Sdimpe_directive_secrel (int dummy ATTRIBUTE_UNUSED)
3845218822Sdim{
3846218822Sdim  expressionS exp;
384777298Sobrien
3848218822Sdim  do
3849218822Sdim    {
3850218822Sdim      expression (&exp);
3851218822Sdim      if (exp.X_op == O_symbol)
3852218822Sdim	exp.X_op = O_secrel;
3853218822Sdim
3854218822Sdim      emit_expr (&exp, 4);
3855218822Sdim    }
3856218822Sdim  while (*input_line_pointer++ == ',');
3857218822Sdim
3858218822Sdim  input_line_pointer--;
3859218822Sdim  demand_empty_rest_of_line ();
386077298Sobrien}
3861218822Sdim#endif /* TE_PE */
386277298Sobrien
3863218822Sdim/* This table describes all the machine specific pseudo-ops the assembler
3864218822Sdim   has to support.  The fields are:
3865218822Sdim     pseudo-op name without dot
3866218822Sdim     function to call to execute this pseudo-op
3867218822Sdim     Integer arg to pass to the function.  */
386877298Sobrien
3869218822Sdimconst pseudo_typeS md_pseudo_table[] =
387077298Sobrien{
3871218822Sdim  /* Never called because '.req' does not start a line.	 */
3872218822Sdim  { "req",	   s_req,	  0 },
3873218822Sdim  /* Following two are likewise never called.  */
3874218822Sdim  { "dn",	   s_dn,          0 },
3875218822Sdim  { "qn",          s_qn,          0 },
3876218822Sdim  { "unreq",	   s_unreq,	  0 },
3877218822Sdim  { "bss",	   s_bss,	  0 },
3878218822Sdim  { "align",	   s_align,	  0 },
3879218822Sdim  { "arm",	   s_arm,	  0 },
3880218822Sdim  { "thumb",	   s_thumb,	  0 },
3881218822Sdim  { "code",	   s_code,	  0 },
3882218822Sdim  { "force_thumb", s_force_thumb, 0 },
3883218822Sdim  { "thumb_func",  s_thumb_func,  0 },
3884218822Sdim  { "thumb_set",   s_thumb_set,	  0 },
3885218822Sdim  { "even",	   s_even,	  0 },
3886218822Sdim  { "ltorg",	   s_ltorg,	  0 },
3887218822Sdim  { "pool",	   s_ltorg,	  0 },
3888218822Sdim  { "syntax",	   s_syntax,	  0 },
3889218822Sdim  { "cpu",	   s_arm_cpu,	  0 },
3890218822Sdim  { "arch",	   s_arm_arch,	  0 },
3891218822Sdim  { "object_arch", s_arm_object_arch,	0 },
3892218822Sdim  { "fpu",	   s_arm_fpu,	  0 },
3893218822Sdim#ifdef OBJ_ELF
3894218822Sdim  { "word",	   s_arm_elf_cons, 4 },
3895218822Sdim  { "long",	   s_arm_elf_cons, 4 },
3896218822Sdim  { "rel31",	   s_arm_rel31,	  0 },
3897218822Sdim  { "fnstart",		s_arm_unwind_fnstart,	0 },
3898218822Sdim  { "fnend",		s_arm_unwind_fnend,	0 },
3899218822Sdim  { "cantunwind",	s_arm_unwind_cantunwind, 0 },
3900218822Sdim  { "personality",	s_arm_unwind_personality, 0 },
3901218822Sdim  { "personalityindex",	s_arm_unwind_personalityindex, 0 },
3902218822Sdim  { "handlerdata",	s_arm_unwind_handlerdata, 0 },
3903218822Sdim  { "save",		s_arm_unwind_save,	0 },
3904218822Sdim  { "vsave",		s_arm_unwind_save,	1 },
3905218822Sdim  { "movsp",		s_arm_unwind_movsp,	0 },
3906218822Sdim  { "pad",		s_arm_unwind_pad,	0 },
3907218822Sdim  { "setfp",		s_arm_unwind_setfp,	0 },
3908218822Sdim  { "unwind_raw",	s_arm_unwind_raw,	0 },
3909218822Sdim  { "eabi_attribute",	s_arm_eabi_attribute,	0 },
3910218822Sdim#else
3911218822Sdim  { "word",	   cons, 4},
391277298Sobrien
3913218822Sdim  /* These are used for dwarf.  */
3914218822Sdim  {"2byte", cons, 2},
3915218822Sdim  {"4byte", cons, 4},
3916218822Sdim  {"8byte", cons, 8},
3917218822Sdim  /* These are used for dwarf2.  */
3918218822Sdim  { "file", (void (*) (int)) dwarf2_directive_file, 0 },
3919218822Sdim  { "loc",  dwarf2_directive_loc,  0 },
3920218822Sdim  { "loc_mark_labels", dwarf2_directive_loc_mark_labels, 0 },
3921218822Sdim#endif
3922218822Sdim  { "extend",	   float_cons, 'x' },
3923218822Sdim  { "ldouble",	   float_cons, 'x' },
3924218822Sdim  { "packed",	   float_cons, 'p' },
3925218822Sdim#ifdef TE_PE
3926218822Sdim  {"secrel32", pe_directive_secrel, 0},
3927218822Sdim#endif
3928218822Sdim  { 0, 0, 0 }
3929218822Sdim};
3930218822Sdim
3931218822Sdim/* Parser functions used exclusively in instruction operands.  */
3932218822Sdim
3933218822Sdim/* Generic immediate-value read function for use in insn parsing.
3934218822Sdim   STR points to the beginning of the immediate (the leading #);
3935218822Sdim   VAL receives the value; if the value is outside [MIN, MAX]
3936218822Sdim   issue an error.  PREFIX_OPT is true if the immediate prefix is
3937218822Sdim   optional.  */
3938218822Sdim
3939218822Sdimstatic int
3940218822Sdimparse_immediate (char **str, int *val, int min, int max,
3941218822Sdim		 bfd_boolean prefix_opt)
3942218822Sdim{
3943218822Sdim  expressionS exp;
3944218822Sdim  my_get_expression (&exp, str, prefix_opt ? GE_OPT_PREFIX : GE_IMM_PREFIX);
3945218822Sdim  if (exp.X_op != O_constant)
394677298Sobrien    {
3947218822Sdim      inst.error = _("constant expression required");
3948218822Sdim      return FAIL;
394977298Sobrien    }
3950218822Sdim
3951218822Sdim  if (exp.X_add_number < min || exp.X_add_number > max)
395277298Sobrien    {
3953218822Sdim      inst.error = _("immediate value out of range");
3954218822Sdim      return FAIL;
395577298Sobrien    }
3956218822Sdim
3957218822Sdim  *val = exp.X_add_number;
3958218822Sdim  return SUCCESS;
3959218822Sdim}
3960218822Sdim
3961218822Sdim/* Less-generic immediate-value read function with the possibility of loading a
3962218822Sdim   big (64-bit) immediate, as required by Neon VMOV, VMVN and logic immediate
3963218822Sdim   instructions. Puts the result directly in inst.operands[i].  */
3964218822Sdim
3965218822Sdimstatic int
3966218822Sdimparse_big_immediate (char **str, int i)
3967218822Sdim{
3968218822Sdim  expressionS exp;
3969218822Sdim  char *ptr = *str;
3970218822Sdim
3971218822Sdim  my_get_expression (&exp, &ptr, GE_OPT_PREFIX_BIG);
3972218822Sdim
3973218822Sdim  if (exp.X_op == O_constant)
397477298Sobrien    {
3975218822Sdim      inst.operands[i].imm = exp.X_add_number & 0xffffffff;
3976218822Sdim      /* If we're on a 64-bit host, then a 64-bit number can be returned using
3977218822Sdim	 O_constant.  We have to be careful not to break compilation for
3978218822Sdim	 32-bit X_add_number, though.  */
3979218822Sdim      if ((exp.X_add_number & ~0xffffffffl) != 0)
3980218822Sdim	{
3981218822Sdim          /* X >> 32 is illegal if sizeof (exp.X_add_number) == 4.  */
3982218822Sdim	  inst.operands[i].reg = ((exp.X_add_number >> 16) >> 16) & 0xffffffff;
3983218822Sdim	  inst.operands[i].regisimm = 1;
3984218822Sdim	}
398577298Sobrien    }
3986218822Sdim  else if (exp.X_op == O_big
3987218822Sdim           && LITTLENUM_NUMBER_OF_BITS * exp.X_add_number > 32
3988218822Sdim           && LITTLENUM_NUMBER_OF_BITS * exp.X_add_number <= 64)
3989218822Sdim    {
3990218822Sdim      unsigned parts = 32 / LITTLENUM_NUMBER_OF_BITS, j, idx = 0;
3991218822Sdim      /* Bignums have their least significant bits in
3992218822Sdim         generic_bignum[0]. Make sure we put 32 bits in imm and
3993218822Sdim         32 bits in reg,  in a (hopefully) portable way.  */
3994218822Sdim      assert (parts != 0);
3995218822Sdim      inst.operands[i].imm = 0;
3996218822Sdim      for (j = 0; j < parts; j++, idx++)
3997218822Sdim        inst.operands[i].imm |= generic_bignum[idx]
3998218822Sdim                                << (LITTLENUM_NUMBER_OF_BITS * j);
3999218822Sdim      inst.operands[i].reg = 0;
4000218822Sdim      for (j = 0; j < parts; j++, idx++)
4001218822Sdim        inst.operands[i].reg |= generic_bignum[idx]
4002218822Sdim                                << (LITTLENUM_NUMBER_OF_BITS * j);
4003218822Sdim      inst.operands[i].regisimm = 1;
4004218822Sdim    }
400577298Sobrien  else
4006218822Sdim    return FAIL;
4007218822Sdim
4008218822Sdim  *str = ptr;
4009218822Sdim
4010218822Sdim  return SUCCESS;
401177298Sobrien}
401277298Sobrien
4013218822Sdim/* Returns the pseudo-register number of an FPA immediate constant,
4014218822Sdim   or FAIL if there isn't a valid constant here.  */
401577298Sobrien
4016218822Sdimstatic int
4017218822Sdimparse_fpa_immediate (char ** str)
401877298Sobrien{
4019218822Sdim  LITTLENUM_TYPE words[MAX_LITTLENUMS];
4020218822Sdim  char *	 save_in;
4021218822Sdim  expressionS	 exp;
4022218822Sdim  int		 i;
4023218822Sdim  int		 j;
402477298Sobrien
4025218822Sdim  /* First try and match exact strings, this is to guarantee
4026218822Sdim     that some formats will work even for cross assembly.  */
402777298Sobrien
4028218822Sdim  for (i = 0; fp_const[i]; i++)
402977298Sobrien    {
4030218822Sdim      if (strncmp (*str, fp_const[i], strlen (fp_const[i])) == 0)
4031218822Sdim	{
4032218822Sdim	  char *start = *str;
403377298Sobrien
4034218822Sdim	  *str += strlen (fp_const[i]);
4035218822Sdim	  if (is_end_of_line[(unsigned char) **str])
4036218822Sdim	    return i + 8;
4037218822Sdim	  *str = start;
4038218822Sdim	}
403977298Sobrien    }
404077298Sobrien
4041218822Sdim  /* Just because we didn't get a match doesn't mean that the constant
4042218822Sdim     isn't valid, just that it is in a format that we don't
4043218822Sdim     automatically recognize.  Try parsing it with the standard
4044218822Sdim     expression routines.  */
4045218822Sdim
4046218822Sdim  memset (words, 0, MAX_LITTLENUMS * sizeof (LITTLENUM_TYPE));
4047218822Sdim
4048218822Sdim  /* Look for a raw floating point number.  */
4049218822Sdim  if ((save_in = atof_ieee (*str, 'x', words)) != NULL
4050218822Sdim      && is_end_of_line[(unsigned char) *save_in])
405177298Sobrien    {
4052218822Sdim      for (i = 0; i < NUM_FLOAT_VALS; i++)
4053218822Sdim	{
4054218822Sdim	  for (j = 0; j < MAX_LITTLENUMS; j++)
4055218822Sdim	    {
4056218822Sdim	      if (words[j] != fp_values[i][j])
4057218822Sdim		break;
4058218822Sdim	    }
405977298Sobrien
4060218822Sdim	  if (j == MAX_LITTLENUMS)
4061218822Sdim	    {
4062218822Sdim	      *str = save_in;
4063218822Sdim	      return i + 8;
4064218822Sdim	    }
4065218822Sdim	}
406677298Sobrien    }
406777298Sobrien
4068218822Sdim  /* Try and parse a more complex expression, this will probably fail
4069218822Sdim     unless the code uses a floating point prefix (eg "0f").  */
4070218822Sdim  save_in = input_line_pointer;
4071218822Sdim  input_line_pointer = *str;
4072218822Sdim  if (expression (&exp) == absolute_section
4073218822Sdim      && exp.X_op == O_big
4074218822Sdim      && exp.X_add_number < 0)
407577298Sobrien    {
4076218822Sdim      /* FIXME: 5 = X_PRECISION, should be #define'd where we can use it.
4077218822Sdim	 Ditto for 15.	*/
4078218822Sdim      if (gen_to_words (words, 5, (long) 15) == 0)
407977298Sobrien	{
4080218822Sdim	  for (i = 0; i < NUM_FLOAT_VALS; i++)
4081218822Sdim	    {
4082218822Sdim	      for (j = 0; j < MAX_LITTLENUMS; j++)
4083218822Sdim		{
4084218822Sdim		  if (words[j] != fp_values[i][j])
4085218822Sdim		    break;
4086218822Sdim		}
4087218822Sdim
4088218822Sdim	      if (j == MAX_LITTLENUMS)
4089218822Sdim		{
4090218822Sdim		  *str = input_line_pointer;
4091218822Sdim		  input_line_pointer = save_in;
4092218822Sdim		  return i + 8;
4093218822Sdim		}
4094218822Sdim	    }
409577298Sobrien	}
409677298Sobrien    }
409777298Sobrien
4098218822Sdim  *str = input_line_pointer;
4099218822Sdim  input_line_pointer = save_in;
4100218822Sdim  inst.error = _("invalid FPA immediate expression");
4101218822Sdim  return FAIL;
410277298Sobrien}
410377298Sobrien
4104218822Sdim/* Returns 1 if a number has "quarter-precision" float format
4105218822Sdim   0baBbbbbbc defgh000 00000000 00000000.  */
410677298Sobrien
4107218822Sdimstatic int
4108218822Sdimis_quarter_float (unsigned imm)
410977298Sobrien{
4110218822Sdim  int bs = (imm & 0x20000000) ? 0x3e000000 : 0x40000000;
4111218822Sdim  return (imm & 0x7ffff) == 0 && ((imm & 0x7e000000) ^ bs) == 0;
4112218822Sdim}
411377298Sobrien
4114218822Sdim/* Parse an 8-bit "quarter-precision" floating point number of the form:
4115218822Sdim   0baBbbbbbc defgh000 00000000 00000000.
4116218822Sdim   The zero and minus-zero cases need special handling, since they can't be
4117218822Sdim   encoded in the "quarter-precision" float format, but can nonetheless be
4118218822Sdim   loaded as integer constants.  */
4119218822Sdim
4120218822Sdimstatic unsigned
4121218822Sdimparse_qfloat_immediate (char **ccp, int *immed)
4122218822Sdim{
4123218822Sdim  char *str = *ccp;
4124218822Sdim  char *fpnum;
4125218822Sdim  LITTLENUM_TYPE words[MAX_LITTLENUMS];
4126218822Sdim  int found_fpchar = 0;
4127218822Sdim
4128218822Sdim  skip_past_char (&str, '#');
4129218822Sdim
4130218822Sdim  /* We must not accidentally parse an integer as a floating-point number. Make
4131218822Sdim     sure that the value we parse is not an integer by checking for special
4132218822Sdim     characters '.' or 'e'.
4133218822Sdim     FIXME: This is a horrible hack, but doing better is tricky because type
4134218822Sdim     information isn't in a very usable state at parse time.  */
4135218822Sdim  fpnum = str;
4136218822Sdim  skip_whitespace (fpnum);
4137218822Sdim
4138218822Sdim  if (strncmp (fpnum, "0x", 2) == 0)
4139218822Sdim    return FAIL;
4140218822Sdim  else
414177298Sobrien    {
4142218822Sdim      for (; *fpnum != '\0' && *fpnum != ' ' && *fpnum != '\n'; fpnum++)
4143218822Sdim        if (*fpnum == '.' || *fpnum == 'e' || *fpnum == 'E')
4144218822Sdim          {
4145218822Sdim            found_fpchar = 1;
4146218822Sdim            break;
4147218822Sdim          }
4148218822Sdim
4149218822Sdim      if (!found_fpchar)
4150218822Sdim        return FAIL;
415177298Sobrien    }
4152218822Sdim
4153218822Sdim  if ((str = atof_ieee (str, 's', words)) != NULL)
4154218822Sdim    {
4155218822Sdim      unsigned fpword = 0;
4156218822Sdim      int i;
4157218822Sdim
4158218822Sdim      /* Our FP word must be 32 bits (single-precision FP).  */
4159218822Sdim      for (i = 0; i < 32 / LITTLENUM_NUMBER_OF_BITS; i++)
4160218822Sdim        {
4161218822Sdim          fpword <<= LITTLENUM_NUMBER_OF_BITS;
4162218822Sdim          fpword |= words[i];
4163218822Sdim        }
4164218822Sdim
4165218822Sdim      if (is_quarter_float (fpword) || (fpword & 0x7fffffff) == 0)
4166218822Sdim        *immed = fpword;
4167218822Sdim      else
4168218822Sdim        return FAIL;
416977298Sobrien
4170218822Sdim      *ccp = str;
4171218822Sdim
4172218822Sdim      return SUCCESS;
417377298Sobrien    }
4174218822Sdim
4175218822Sdim  return FAIL;
4176218822Sdim}
417777298Sobrien
4178218822Sdim/* Shift operands.  */
4179218822Sdimenum shift_kind
4180218822Sdim{
4181218822Sdim  SHIFT_LSL, SHIFT_LSR, SHIFT_ASR, SHIFT_ROR, SHIFT_RRX
4182218822Sdim};
4183218822Sdim
4184218822Sdimstruct asm_shift_name
4185218822Sdim{
4186218822Sdim  const char	  *name;
4187218822Sdim  enum shift_kind  kind;
4188218822Sdim};
4189218822Sdim
4190218822Sdim/* Third argument to parse_shift.  */
4191218822Sdimenum parse_shift_mode
4192218822Sdim{
4193218822Sdim  NO_SHIFT_RESTRICT,		/* Any kind of shift is accepted.  */
4194218822Sdim  SHIFT_IMMEDIATE,		/* Shift operand must be an immediate.	*/
4195218822Sdim  SHIFT_LSL_OR_ASR_IMMEDIATE,	/* Shift must be LSL or ASR immediate.	*/
4196218822Sdim  SHIFT_ASR_IMMEDIATE,		/* Shift must be ASR immediate.	 */
4197218822Sdim  SHIFT_LSL_IMMEDIATE,		/* Shift must be LSL immediate.	 */
4198218822Sdim};
4199218822Sdim
4200218822Sdim/* Parse a <shift> specifier on an ARM data processing instruction.
4201218822Sdim   This has three forms:
4202218822Sdim
4203218822Sdim     (LSL|LSR|ASL|ASR|ROR) Rs
4204218822Sdim     (LSL|LSR|ASL|ASR|ROR) #imm
4205218822Sdim     RRX
4206218822Sdim
4207218822Sdim   Note that ASL is assimilated to LSL in the instruction encoding, and
4208218822Sdim   RRX to ROR #0 (which cannot be written as such).  */
4209218822Sdim
4210218822Sdimstatic int
4211218822Sdimparse_shift (char **str, int i, enum parse_shift_mode mode)
4212218822Sdim{
4213218822Sdim  const struct asm_shift_name *shift_name;
4214218822Sdim  enum shift_kind shift;
4215218822Sdim  char *s = *str;
4216218822Sdim  char *p = s;
4217218822Sdim  int reg;
4218218822Sdim
4219218822Sdim  for (p = *str; ISALPHA (*p); p++)
4220218822Sdim    ;
4221218822Sdim
4222218822Sdim  if (p == *str)
422377298Sobrien    {
4224218822Sdim      inst.error = _("shift expression expected");
4225218822Sdim      return FAIL;
422677298Sobrien    }
422777298Sobrien
4228218822Sdim  shift_name = hash_find_n (arm_shift_hsh, *str, p - *str);
4229218822Sdim
4230218822Sdim  if (shift_name == NULL)
423177298Sobrien    {
4232218822Sdim      inst.error = _("shift expression expected");
4233218822Sdim      return FAIL;
423477298Sobrien    }
423577298Sobrien
4236218822Sdim  shift = shift_name->kind;
4237218822Sdim
4238218822Sdim  switch (mode)
423977298Sobrien    {
4240218822Sdim    case NO_SHIFT_RESTRICT:
4241218822Sdim    case SHIFT_IMMEDIATE:   break;
4242218822Sdim
4243218822Sdim    case SHIFT_LSL_OR_ASR_IMMEDIATE:
4244218822Sdim      if (shift != SHIFT_LSL && shift != SHIFT_ASR)
4245218822Sdim	{
4246218822Sdim	  inst.error = _("'LSL' or 'ASR' required");
4247218822Sdim	  return FAIL;
4248218822Sdim	}
4249218822Sdim      break;
4250218822Sdim
4251218822Sdim    case SHIFT_LSL_IMMEDIATE:
4252218822Sdim      if (shift != SHIFT_LSL)
4253218822Sdim	{
4254218822Sdim	  inst.error = _("'LSL' required");
4255218822Sdim	  return FAIL;
4256218822Sdim	}
4257218822Sdim      break;
4258218822Sdim
4259218822Sdim    case SHIFT_ASR_IMMEDIATE:
4260218822Sdim      if (shift != SHIFT_ASR)
4261218822Sdim	{
4262218822Sdim	  inst.error = _("'ASR' required");
4263218822Sdim	  return FAIL;
4264218822Sdim	}
4265218822Sdim      break;
4266218822Sdim
4267218822Sdim    default: abort ();
426877298Sobrien    }
426977298Sobrien
4270218822Sdim  if (shift != SHIFT_RRX)
427177298Sobrien    {
4272218822Sdim      /* Whitespace can appear here if the next thing is a bare digit.	*/
4273218822Sdim      skip_whitespace (p);
4274218822Sdim
4275218822Sdim      if (mode == NO_SHIFT_RESTRICT
4276218822Sdim	  && (reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL)
427777298Sobrien	{
4278218822Sdim	  inst.operands[i].imm = reg;
4279218822Sdim	  inst.operands[i].immisreg = 1;
428077298Sobrien	}
4281218822Sdim      else if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
4282218822Sdim	return FAIL;
428377298Sobrien    }
4284218822Sdim  inst.operands[i].shift_kind = shift;
4285218822Sdim  inst.operands[i].shifted = 1;
4286218822Sdim  *str = p;
4287218822Sdim  return SUCCESS;
428889857Sobrien}
428977298Sobrien
4290218822Sdim/* Parse a <shifter_operand> for an ARM data processing instruction:
4291218822Sdim
4292218822Sdim      #<immediate>
4293218822Sdim      #<immediate>, <rotate>
4294218822Sdim      <Rm>
4295218822Sdim      <Rm>, <shift>
4296218822Sdim
4297218822Sdim   where <shift> is defined by parse_shift above, and <rotate> is a
4298218822Sdim   multiple of 2 between 0 and 30.  Validation of immediate operands
4299218822Sdim   is deferred to md_apply_fix.  */
4300218822Sdim
4301218822Sdimstatic int
4302218822Sdimparse_shifter_operand (char **str, int i)
430389857Sobrien{
4304218822Sdim  int value;
4305218822Sdim  expressionS expr;
430689857Sobrien
4307218822Sdim  if ((value = arm_reg_parse (str, REG_TYPE_RN)) != FAIL)
4308218822Sdim    {
4309218822Sdim      inst.operands[i].reg = value;
4310218822Sdim      inst.operands[i].isreg = 1;
431189857Sobrien
4312218822Sdim      /* parse_shift will override this if appropriate */
4313218822Sdim      inst.reloc.exp.X_op = O_constant;
4314218822Sdim      inst.reloc.exp.X_add_number = 0;
4315218822Sdim
4316218822Sdim      if (skip_past_comma (str) == FAIL)
4317218822Sdim	return SUCCESS;
4318218822Sdim
4319218822Sdim      /* Shift operation on register.  */
4320218822Sdim      return parse_shift (str, i, NO_SHIFT_RESTRICT);
4321218822Sdim    }
4322218822Sdim
4323218822Sdim  if (my_get_expression (&inst.reloc.exp, str, GE_IMM_PREFIX))
4324218822Sdim    return FAIL;
4325218822Sdim
4326218822Sdim  if (skip_past_comma (str) == SUCCESS)
432789857Sobrien    {
4328218822Sdim      /* #x, y -- ie explicit rotation by Y.  */
4329218822Sdim      if (my_get_expression (&expr, str, GE_NO_PREFIX))
4330218822Sdim	return FAIL;
4331218822Sdim
4332218822Sdim      if (expr.X_op != O_constant || inst.reloc.exp.X_op != O_constant)
4333218822Sdim	{
4334218822Sdim	  inst.error = _("constant expression expected");
4335218822Sdim	  return FAIL;
4336218822Sdim	}
4337218822Sdim
4338218822Sdim      value = expr.X_add_number;
4339218822Sdim      if (value < 0 || value > 30 || value % 2 != 0)
4340218822Sdim	{
4341218822Sdim	  inst.error = _("invalid rotation");
4342218822Sdim	  return FAIL;
4343218822Sdim	}
4344218822Sdim      if (inst.reloc.exp.X_add_number < 0 || inst.reloc.exp.X_add_number > 255)
4345218822Sdim	{
4346218822Sdim	  inst.error = _("invalid constant");
4347218822Sdim	  return FAIL;
4348218822Sdim	}
4349218822Sdim
4350218822Sdim      /* Convert to decoded value.  md_apply_fix will put it back.  */
4351218822Sdim      inst.reloc.exp.X_add_number
4352218822Sdim	= (((inst.reloc.exp.X_add_number << (32 - value))
4353218822Sdim	    | (inst.reloc.exp.X_add_number >> value)) & 0xffffffff);
435489857Sobrien    }
435589857Sobrien
4356218822Sdim  inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
4357218822Sdim  inst.reloc.pc_rel = 0;
4358218822Sdim  return SUCCESS;
435977298Sobrien}
436077298Sobrien
4361218822Sdim/* Group relocation information.  Each entry in the table contains the
4362218822Sdim   textual name of the relocation as may appear in assembler source
4363218822Sdim   and must end with a colon.
4364218822Sdim   Along with this textual name are the relocation codes to be used if
4365218822Sdim   the corresponding instruction is an ALU instruction (ADD or SUB only),
4366218822Sdim   an LDR, an LDRS, or an LDC.  */
4367130561Sobrien
4368218822Sdimstruct group_reloc_table_entry
4369130561Sobrien{
4370218822Sdim  const char *name;
4371218822Sdim  int alu_code;
4372218822Sdim  int ldr_code;
4373218822Sdim  int ldrs_code;
4374218822Sdim  int ldc_code;
4375218822Sdim};
4376130561Sobrien
4377218822Sdimtypedef enum
4378218822Sdim{
4379218822Sdim  /* Varieties of non-ALU group relocation.  */
4380130561Sobrien
4381218822Sdim  GROUP_LDR,
4382218822Sdim  GROUP_LDRS,
4383218822Sdim  GROUP_LDC
4384218822Sdim} group_reloc_type;
4385218822Sdim
4386218822Sdimstatic struct group_reloc_table_entry group_reloc_table[] =
4387218822Sdim  { /* Program counter relative: */
4388218822Sdim    { "pc_g0_nc",
4389218822Sdim      BFD_RELOC_ARM_ALU_PC_G0_NC,	/* ALU */
4390218822Sdim      0,				/* LDR */
4391218822Sdim      0,				/* LDRS */
4392218822Sdim      0 },				/* LDC */
4393218822Sdim    { "pc_g0",
4394218822Sdim      BFD_RELOC_ARM_ALU_PC_G0,		/* ALU */
4395218822Sdim      BFD_RELOC_ARM_LDR_PC_G0,		/* LDR */
4396218822Sdim      BFD_RELOC_ARM_LDRS_PC_G0,		/* LDRS */
4397218822Sdim      BFD_RELOC_ARM_LDC_PC_G0 },	/* LDC */
4398218822Sdim    { "pc_g1_nc",
4399218822Sdim      BFD_RELOC_ARM_ALU_PC_G1_NC,	/* ALU */
4400218822Sdim      0,				/* LDR */
4401218822Sdim      0,				/* LDRS */
4402218822Sdim      0 },				/* LDC */
4403218822Sdim    { "pc_g1",
4404218822Sdim      BFD_RELOC_ARM_ALU_PC_G1,		/* ALU */
4405218822Sdim      BFD_RELOC_ARM_LDR_PC_G1, 		/* LDR */
4406218822Sdim      BFD_RELOC_ARM_LDRS_PC_G1,		/* LDRS */
4407218822Sdim      BFD_RELOC_ARM_LDC_PC_G1 },	/* LDC */
4408218822Sdim    { "pc_g2",
4409218822Sdim      BFD_RELOC_ARM_ALU_PC_G2,		/* ALU */
4410218822Sdim      BFD_RELOC_ARM_LDR_PC_G2,		/* LDR */
4411218822Sdim      BFD_RELOC_ARM_LDRS_PC_G2,		/* LDRS */
4412218822Sdim      BFD_RELOC_ARM_LDC_PC_G2 },	/* LDC */
4413218822Sdim    /* Section base relative */
4414218822Sdim    { "sb_g0_nc",
4415218822Sdim      BFD_RELOC_ARM_ALU_SB_G0_NC,	/* ALU */
4416218822Sdim      0,				/* LDR */
4417218822Sdim      0,				/* LDRS */
4418218822Sdim      0 },				/* LDC */
4419218822Sdim    { "sb_g0",
4420218822Sdim      BFD_RELOC_ARM_ALU_SB_G0,		/* ALU */
4421218822Sdim      BFD_RELOC_ARM_LDR_SB_G0,		/* LDR */
4422218822Sdim      BFD_RELOC_ARM_LDRS_SB_G0,		/* LDRS */
4423218822Sdim      BFD_RELOC_ARM_LDC_SB_G0 },	/* LDC */
4424218822Sdim    { "sb_g1_nc",
4425218822Sdim      BFD_RELOC_ARM_ALU_SB_G1_NC,	/* ALU */
4426218822Sdim      0,				/* LDR */
4427218822Sdim      0,				/* LDRS */
4428218822Sdim      0 },				/* LDC */
4429218822Sdim    { "sb_g1",
4430218822Sdim      BFD_RELOC_ARM_ALU_SB_G1,		/* ALU */
4431218822Sdim      BFD_RELOC_ARM_LDR_SB_G1, 		/* LDR */
4432218822Sdim      BFD_RELOC_ARM_LDRS_SB_G1,		/* LDRS */
4433218822Sdim      BFD_RELOC_ARM_LDC_SB_G1 },	/* LDC */
4434218822Sdim    { "sb_g2",
4435218822Sdim      BFD_RELOC_ARM_ALU_SB_G2,		/* ALU */
4436218822Sdim      BFD_RELOC_ARM_LDR_SB_G2,		/* LDR */
4437218822Sdim      BFD_RELOC_ARM_LDRS_SB_G2,		/* LDRS */
4438218822Sdim      BFD_RELOC_ARM_LDC_SB_G2 }	};	/* LDC */
4439218822Sdim
4440218822Sdim/* Given the address of a pointer pointing to the textual name of a group
4441218822Sdim   relocation as may appear in assembler source, attempt to find its details
4442218822Sdim   in group_reloc_table.  The pointer will be updated to the character after
4443218822Sdim   the trailing colon.  On failure, FAIL will be returned; SUCCESS
4444218822Sdim   otherwise.  On success, *entry will be updated to point at the relevant
4445218822Sdim   group_reloc_table entry. */
4446218822Sdim
4447218822Sdimstatic int
4448218822Sdimfind_group_reloc_table_entry (char **str, struct group_reloc_table_entry **out)
4449218822Sdim{
4450218822Sdim  unsigned int i;
4451218822Sdim  for (i = 0; i < ARRAY_SIZE (group_reloc_table); i++)
4452130561Sobrien    {
4453218822Sdim      int length = strlen (group_reloc_table[i].name);
4454130561Sobrien
4455218822Sdim      if (strncasecmp (group_reloc_table[i].name, *str, length) == 0 &&
4456218822Sdim          (*str)[length] == ':')
4457218822Sdim        {
4458218822Sdim          *out = &group_reloc_table[i];
4459218822Sdim          *str += (length + 1);
4460218822Sdim          return SUCCESS;
4461218822Sdim        }
4462130561Sobrien    }
4463130561Sobrien
4464218822Sdim  return FAIL;
4465130561Sobrien}
4466130561Sobrien
4467218822Sdim/* Parse a <shifter_operand> for an ARM data processing instruction
4468218822Sdim   (as for parse_shifter_operand) where group relocations are allowed:
4469130561Sobrien
4470218822Sdim      #<immediate>
4471218822Sdim      #<immediate>, <rotate>
4472218822Sdim      #:<group_reloc>:<expression>
4473218822Sdim      <Rm>
4474218822Sdim      <Rm>, <shift>
4475218822Sdim
4476218822Sdim   where <group_reloc> is one of the strings defined in group_reloc_table.
4477218822Sdim   The hashes are optional.
4478218822Sdim
4479218822Sdim   Everything else is as for parse_shifter_operand.  */
4480218822Sdim
4481218822Sdimstatic parse_operand_result
4482218822Sdimparse_shifter_operand_group_reloc (char **str, int i)
4483130561Sobrien{
4484218822Sdim  /* Determine if we have the sequence of characters #: or just :
4485218822Sdim     coming next.  If we do, then we check for a group relocation.
4486218822Sdim     If we don't, punt the whole lot to parse_shifter_operand.  */
4487130561Sobrien
4488218822Sdim  if (((*str)[0] == '#' && (*str)[1] == ':')
4489218822Sdim      || (*str)[0] == ':')
4490130561Sobrien    {
4491218822Sdim      struct group_reloc_table_entry *entry;
4492130561Sobrien
4493218822Sdim      if ((*str)[0] == '#')
4494218822Sdim        (*str) += 2;
4495218822Sdim      else
4496218822Sdim        (*str)++;
4497130561Sobrien
4498218822Sdim      /* Try to parse a group relocation.  Anything else is an error.  */
4499218822Sdim      if (find_group_reloc_table_entry (str, &entry) == FAIL)
4500218822Sdim        {
4501218822Sdim          inst.error = _("unknown group relocation");
4502218822Sdim          return PARSE_OPERAND_FAIL_NO_BACKTRACK;
4503218822Sdim        }
4504218822Sdim
4505218822Sdim      /* We now have the group relocation table entry corresponding to
4506218822Sdim         the name in the assembler source.  Next, we parse the expression.  */
4507218822Sdim      if (my_get_expression (&inst.reloc.exp, str, GE_NO_PREFIX))
4508218822Sdim        return PARSE_OPERAND_FAIL_NO_BACKTRACK;
4509218822Sdim
4510218822Sdim      /* Record the relocation type (always the ALU variant here).  */
4511218822Sdim      inst.reloc.type = entry->alu_code;
4512218822Sdim      assert (inst.reloc.type != 0);
4513218822Sdim
4514218822Sdim      return PARSE_OPERAND_SUCCESS;
4515130561Sobrien    }
4516218822Sdim  else
4517218822Sdim    return parse_shifter_operand (str, i) == SUCCESS
4518218822Sdim           ? PARSE_OPERAND_SUCCESS : PARSE_OPERAND_FAIL;
4519130561Sobrien
4520218822Sdim  /* Never reached.  */
4521130561Sobrien}
4522130561Sobrien
4523218822Sdim/* Parse all forms of an ARM address expression.  Information is written
4524218822Sdim   to inst.operands[i] and/or inst.reloc.
4525130561Sobrien
4526218822Sdim   Preindexed addressing (.preind=1):
4527130561Sobrien
4528218822Sdim   [Rn, #offset]       .reg=Rn .reloc.exp=offset
4529218822Sdim   [Rn, +/-Rm]	       .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
4530218822Sdim   [Rn, +/-Rm, shift]  .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
4531218822Sdim		       .shift_kind=shift .reloc.exp=shift_imm
4532130561Sobrien
4533218822Sdim   These three may have a trailing ! which causes .writeback to be set also.
4534130561Sobrien
4535218822Sdim   Postindexed addressing (.postind=1, .writeback=1):
4536218822Sdim
4537218822Sdim   [Rn], #offset       .reg=Rn .reloc.exp=offset
4538218822Sdim   [Rn], +/-Rm	       .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
4539218822Sdim   [Rn], +/-Rm, shift  .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
4540218822Sdim		       .shift_kind=shift .reloc.exp=shift_imm
4541218822Sdim
4542218822Sdim   Unindexed addressing (.preind=0, .postind=0):
4543218822Sdim
4544218822Sdim   [Rn], {option}      .reg=Rn .imm=option .immisreg=0
4545218822Sdim
4546218822Sdim   Other:
4547218822Sdim
4548218822Sdim   [Rn]{!}	       shorthand for [Rn,#0]{!}
4549218822Sdim   =immediate	       .isreg=0 .reloc.exp=immediate
4550218822Sdim   label	       .reg=PC .reloc.pc_rel=1 .reloc.exp=label
4551218822Sdim
4552218822Sdim  It is the caller's responsibility to check for addressing modes not
4553218822Sdim  supported by the instruction, and to set inst.reloc.type.  */
4554218822Sdim
4555218822Sdimstatic parse_operand_result
4556218822Sdimparse_address_main (char **str, int i, int group_relocations,
4557218822Sdim                    group_reloc_type group_type)
4558130561Sobrien{
4559218822Sdim  char *p = *str;
4560218822Sdim  int reg;
4561130561Sobrien
4562218822Sdim  if (skip_past_char (&p, '[') == FAIL)
4563130561Sobrien    {
4564218822Sdim      if (skip_past_char (&p, '=') == FAIL)
4565218822Sdim	{
4566218822Sdim	  /* bare address - translate to PC-relative offset */
4567218822Sdim	  inst.reloc.pc_rel = 1;
4568218822Sdim	  inst.operands[i].reg = REG_PC;
4569218822Sdim	  inst.operands[i].isreg = 1;
4570218822Sdim	  inst.operands[i].preind = 1;
4571218822Sdim	}
4572218822Sdim      /* else a load-constant pseudo op, no special treatment needed here */
4573218822Sdim
4574218822Sdim      if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX))
4575218822Sdim	return PARSE_OPERAND_FAIL;
4576218822Sdim
4577218822Sdim      *str = p;
4578218822Sdim      return PARSE_OPERAND_SUCCESS;
4579130561Sobrien    }
4580218822Sdim
4581218822Sdim  if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
4582130561Sobrien    {
4583218822Sdim      inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
4584218822Sdim      return PARSE_OPERAND_FAIL;
4585130561Sobrien    }
4586218822Sdim  inst.operands[i].reg = reg;
4587218822Sdim  inst.operands[i].isreg = 1;
4588130561Sobrien
4589218822Sdim  if (skip_past_comma (&p) == SUCCESS)
4590130561Sobrien    {
4591218822Sdim      inst.operands[i].preind = 1;
4592218822Sdim
4593218822Sdim      if (*p == '+') p++;
4594218822Sdim      else if (*p == '-') p++, inst.operands[i].negative = 1;
4595218822Sdim
4596218822Sdim      if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL)
4597218822Sdim	{
4598218822Sdim	  inst.operands[i].imm = reg;
4599218822Sdim	  inst.operands[i].immisreg = 1;
4600218822Sdim
4601218822Sdim	  if (skip_past_comma (&p) == SUCCESS)
4602218822Sdim	    if (parse_shift (&p, i, SHIFT_IMMEDIATE) == FAIL)
4603218822Sdim	      return PARSE_OPERAND_FAIL;
4604218822Sdim	}
4605218822Sdim      else if (skip_past_char (&p, ':') == SUCCESS)
4606218822Sdim        {
4607218822Sdim          /* FIXME: '@' should be used here, but it's filtered out by generic
4608218822Sdim             code before we get to see it here. This may be subject to
4609218822Sdim             change.  */
4610218822Sdim          expressionS exp;
4611218822Sdim          my_get_expression (&exp, &p, GE_NO_PREFIX);
4612218822Sdim          if (exp.X_op != O_constant)
4613218822Sdim            {
4614218822Sdim              inst.error = _("alignment must be constant");
4615218822Sdim              return PARSE_OPERAND_FAIL;
4616218822Sdim            }
4617218822Sdim          inst.operands[i].imm = exp.X_add_number << 8;
4618218822Sdim          inst.operands[i].immisalign = 1;
4619218822Sdim          /* Alignments are not pre-indexes.  */
4620218822Sdim          inst.operands[i].preind = 0;
4621218822Sdim        }
4622218822Sdim      else
4623218822Sdim	{
4624218822Sdim	  if (inst.operands[i].negative)
4625218822Sdim	    {
4626218822Sdim	      inst.operands[i].negative = 0;
4627218822Sdim	      p--;
4628218822Sdim	    }
4629218822Sdim
4630218822Sdim	  if (group_relocations &&
4631218822Sdim              ((*p == '#' && *(p + 1) == ':') || *p == ':'))
4632218822Sdim
4633218822Sdim	    {
4634218822Sdim	      struct group_reloc_table_entry *entry;
4635218822Sdim
4636218822Sdim              /* Skip over the #: or : sequence.  */
4637218822Sdim              if (*p == '#')
4638218822Sdim                p += 2;
4639218822Sdim              else
4640218822Sdim                p++;
4641218822Sdim
4642218822Sdim	      /* Try to parse a group relocation.  Anything else is an
4643218822Sdim                 error.  */
4644218822Sdim	      if (find_group_reloc_table_entry (&p, &entry) == FAIL)
4645218822Sdim		{
4646218822Sdim		  inst.error = _("unknown group relocation");
4647218822Sdim		  return PARSE_OPERAND_FAIL_NO_BACKTRACK;
4648218822Sdim		}
4649218822Sdim
4650218822Sdim	      /* We now have the group relocation table entry corresponding to
4651218822Sdim		 the name in the assembler source.  Next, we parse the
4652218822Sdim                 expression.  */
4653218822Sdim	      if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX))
4654218822Sdim		return PARSE_OPERAND_FAIL_NO_BACKTRACK;
4655218822Sdim
4656218822Sdim	      /* Record the relocation type.  */
4657218822Sdim              switch (group_type)
4658218822Sdim                {
4659218822Sdim                  case GROUP_LDR:
4660218822Sdim	            inst.reloc.type = entry->ldr_code;
4661218822Sdim                    break;
4662218822Sdim
4663218822Sdim                  case GROUP_LDRS:
4664218822Sdim	            inst.reloc.type = entry->ldrs_code;
4665218822Sdim                    break;
4666218822Sdim
4667218822Sdim                  case GROUP_LDC:
4668218822Sdim	            inst.reloc.type = entry->ldc_code;
4669218822Sdim                    break;
4670218822Sdim
4671218822Sdim                  default:
4672218822Sdim                    assert (0);
4673218822Sdim                }
4674218822Sdim
4675218822Sdim              if (inst.reloc.type == 0)
4676218822Sdim		{
4677218822Sdim		  inst.error = _("this group relocation is not allowed on this instruction");
4678218822Sdim		  return PARSE_OPERAND_FAIL_NO_BACKTRACK;
4679218822Sdim		}
4680218822Sdim            }
4681218822Sdim          else
4682218822Sdim	    if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
4683218822Sdim	      return PARSE_OPERAND_FAIL;
4684218822Sdim	}
4685130561Sobrien    }
4686218822Sdim
4687218822Sdim  if (skip_past_char (&p, ']') == FAIL)
4688130561Sobrien    {
4689218822Sdim      inst.error = _("']' expected");
4690218822Sdim      return PARSE_OPERAND_FAIL;
4691130561Sobrien    }
4692218822Sdim
4693218822Sdim  if (skip_past_char (&p, '!') == SUCCESS)
4694218822Sdim    inst.operands[i].writeback = 1;
4695218822Sdim
4696218822Sdim  else if (skip_past_comma (&p) == SUCCESS)
4697130561Sobrien    {
4698218822Sdim      if (skip_past_char (&p, '{') == SUCCESS)
4699218822Sdim	{
4700218822Sdim	  /* [Rn], {expr} - unindexed, with option */
4701218822Sdim	  if (parse_immediate (&p, &inst.operands[i].imm,
4702218822Sdim			       0, 255, TRUE) == FAIL)
4703218822Sdim	    return PARSE_OPERAND_FAIL;
4704218822Sdim
4705218822Sdim	  if (skip_past_char (&p, '}') == FAIL)
4706218822Sdim	    {
4707218822Sdim	      inst.error = _("'}' expected at end of 'option' field");
4708218822Sdim	      return PARSE_OPERAND_FAIL;
4709218822Sdim	    }
4710218822Sdim	  if (inst.operands[i].preind)
4711218822Sdim	    {
4712218822Sdim	      inst.error = _("cannot combine index with option");
4713218822Sdim	      return PARSE_OPERAND_FAIL;
4714218822Sdim	    }
4715218822Sdim	  *str = p;
4716218822Sdim	  return PARSE_OPERAND_SUCCESS;
4717218822Sdim	}
4718218822Sdim      else
4719218822Sdim	{
4720218822Sdim	  inst.operands[i].postind = 1;
4721218822Sdim	  inst.operands[i].writeback = 1;
4722218822Sdim
4723218822Sdim	  if (inst.operands[i].preind)
4724218822Sdim	    {
4725218822Sdim	      inst.error = _("cannot combine pre- and post-indexing");
4726218822Sdim	      return PARSE_OPERAND_FAIL;
4727218822Sdim	    }
4728218822Sdim
4729218822Sdim	  if (*p == '+') p++;
4730218822Sdim	  else if (*p == '-') p++, inst.operands[i].negative = 1;
4731218822Sdim
4732218822Sdim	  if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL)
4733218822Sdim	    {
4734218822Sdim              /* We might be using the immediate for alignment already. If we
4735218822Sdim                 are, OR the register number into the low-order bits.  */
4736218822Sdim              if (inst.operands[i].immisalign)
4737218822Sdim	        inst.operands[i].imm |= reg;
4738218822Sdim              else
4739218822Sdim                inst.operands[i].imm = reg;
4740218822Sdim	      inst.operands[i].immisreg = 1;
4741218822Sdim
4742218822Sdim	      if (skip_past_comma (&p) == SUCCESS)
4743218822Sdim		if (parse_shift (&p, i, SHIFT_IMMEDIATE) == FAIL)
4744218822Sdim		  return PARSE_OPERAND_FAIL;
4745218822Sdim	    }
4746218822Sdim	  else
4747218822Sdim	    {
4748218822Sdim	      if (inst.operands[i].negative)
4749218822Sdim		{
4750218822Sdim		  inst.operands[i].negative = 0;
4751218822Sdim		  p--;
4752218822Sdim		}
4753218822Sdim	      if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
4754218822Sdim		return PARSE_OPERAND_FAIL;
4755218822Sdim	    }
4756218822Sdim	}
4757130561Sobrien    }
4758130561Sobrien
4759218822Sdim  /* If at this point neither .preind nor .postind is set, we have a
4760218822Sdim     bare [Rn]{!}, which is shorthand for [Rn,#0]{!}.  */
4761218822Sdim  if (inst.operands[i].preind == 0 && inst.operands[i].postind == 0)
4762130561Sobrien    {
4763218822Sdim      inst.operands[i].preind = 1;
4764218822Sdim      inst.reloc.exp.X_op = O_constant;
4765218822Sdim      inst.reloc.exp.X_add_number = 0;
4766130561Sobrien    }
4767218822Sdim  *str = p;
4768218822Sdim  return PARSE_OPERAND_SUCCESS;
4769130561Sobrien}
4770130561Sobrien
4771218822Sdimstatic int
4772218822Sdimparse_address (char **str, int i)
4773130561Sobrien{
4774218822Sdim  return parse_address_main (str, i, 0, 0) == PARSE_OPERAND_SUCCESS
4775218822Sdim         ? SUCCESS : FAIL;
4776130561Sobrien}
4777130561Sobrien
4778218822Sdimstatic parse_operand_result
4779218822Sdimparse_address_group_reloc (char **str, int i, group_reloc_type type)
4780130561Sobrien{
4781218822Sdim  return parse_address_main (str, i, 1, type);
4782130561Sobrien}
4783130561Sobrien
4784218822Sdim/* Parse an operand for a MOVW or MOVT instruction.  */
4785218822Sdimstatic int
4786218822Sdimparse_half (char **str)
4787130561Sobrien{
4788218822Sdim  char * p;
4789218822Sdim
4790218822Sdim  p = *str;
4791218822Sdim  skip_past_char (&p, '#');
4792218822Sdim  if (strncasecmp (p, ":lower16:", 9) == 0)
4793218822Sdim    inst.reloc.type = BFD_RELOC_ARM_MOVW;
4794218822Sdim  else if (strncasecmp (p, ":upper16:", 9) == 0)
4795218822Sdim    inst.reloc.type = BFD_RELOC_ARM_MOVT;
4796130561Sobrien
4797218822Sdim  if (inst.reloc.type != BFD_RELOC_UNUSED)
4798130561Sobrien    {
4799218822Sdim      p += 9;
4800218822Sdim      skip_whitespace(p);
4801130561Sobrien    }
4802218822Sdim
4803218822Sdim  if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX))
4804218822Sdim    return FAIL;
4805218822Sdim
4806218822Sdim  if (inst.reloc.type == BFD_RELOC_UNUSED)
4807130561Sobrien    {
4808218822Sdim      if (inst.reloc.exp.X_op != O_constant)
4809218822Sdim	{
4810218822Sdim	  inst.error = _("constant expression expected");
4811218822Sdim	  return FAIL;
4812218822Sdim	}
4813218822Sdim      if (inst.reloc.exp.X_add_number < 0
4814218822Sdim	  || inst.reloc.exp.X_add_number > 0xffff)
4815218822Sdim	{
4816218822Sdim	  inst.error = _("immediate value out of range");
4817218822Sdim	  return FAIL;
4818218822Sdim	}
4819130561Sobrien    }
4820218822Sdim  *str = p;
4821218822Sdim  return SUCCESS;
4822218822Sdim}
4823130561Sobrien
4824218822Sdim/* Miscellaneous. */
4825218822Sdim
4826218822Sdim/* Parse a PSR flag operand.  The value returned is FAIL on syntax error,
4827218822Sdim   or a bitmask suitable to be or-ed into the ARM msr instruction.  */
4828218822Sdimstatic int
4829218822Sdimparse_psr (char **str)
4830218822Sdim{
4831218822Sdim  char *p;
4832218822Sdim  unsigned long psr_field;
4833218822Sdim  const struct asm_psr *psr;
4834218822Sdim  char *start;
4835218822Sdim
4836218822Sdim  /* CPSR's and SPSR's can now be lowercase.  This is just a convenience
4837218822Sdim     feature for ease of use and backwards compatibility.  */
4838218822Sdim  p = *str;
4839218822Sdim  if (strncasecmp (p, "SPSR", 4) == 0)
4840218822Sdim    psr_field = SPSR_BIT;
4841218822Sdim  else if (strncasecmp (p, "CPSR", 4) == 0)
4842218822Sdim    psr_field = 0;
4843130561Sobrien  else
4844130561Sobrien    {
4845218822Sdim      start = p;
4846218822Sdim      do
4847218822Sdim	p++;
4848218822Sdim      while (ISALNUM (*p) || *p == '_');
4849218822Sdim
4850218822Sdim      psr = hash_find_n (arm_v7m_psr_hsh, start, p - start);
4851218822Sdim      if (!psr)
4852218822Sdim	return FAIL;
4853218822Sdim
4854218822Sdim      *str = p;
4855218822Sdim      return psr->field;
4856130561Sobrien    }
4857218822Sdim
4858218822Sdim  p += 4;
4859218822Sdim  if (*p == '_')
4860130561Sobrien    {
4861218822Sdim      /* A suffix follows.  */
4862218822Sdim      p++;
4863218822Sdim      start = p;
4864218822Sdim
4865218822Sdim      do
4866218822Sdim	p++;
4867218822Sdim      while (ISALNUM (*p) || *p == '_');
4868218822Sdim
4869218822Sdim      psr = hash_find_n (arm_psr_hsh, start, p - start);
4870218822Sdim      if (!psr)
4871218822Sdim	goto error;
4872218822Sdim
4873218822Sdim      psr_field |= psr->field;
4874130561Sobrien    }
4875218822Sdim  else
4876130561Sobrien    {
4877218822Sdim      if (ISALNUM (*p))
4878218822Sdim	goto error;    /* Garbage after "[CS]PSR".  */
4879218822Sdim
4880218822Sdim      psr_field |= (PSR_c | PSR_f);
4881130561Sobrien    }
4882218822Sdim  *str = p;
4883218822Sdim  return psr_field;
4884130561Sobrien
4885218822Sdim error:
4886218822Sdim  inst.error = _("flag for {c}psr instruction expected");
4887218822Sdim  return FAIL;
4888130561Sobrien}
4889130561Sobrien
4890218822Sdim/* Parse the flags argument to CPSI[ED].  Returns FAIL on error, or a
4891218822Sdim   value suitable for splatting into the AIF field of the instruction.	*/
4892130561Sobrien
4893218822Sdimstatic int
4894218822Sdimparse_cps_flags (char **str)
4895130561Sobrien{
4896218822Sdim  int val = 0;
4897218822Sdim  int saw_a_flag = 0;
4898218822Sdim  char *s = *str;
4899130561Sobrien
4900218822Sdim  for (;;)
4901218822Sdim    switch (*s++)
4902218822Sdim      {
4903218822Sdim      case '\0': case ',':
4904218822Sdim	goto done;
4905130561Sobrien
4906218822Sdim      case 'a': case 'A': saw_a_flag = 1; val |= 0x4; break;
4907218822Sdim      case 'i': case 'I': saw_a_flag = 1; val |= 0x2; break;
4908218822Sdim      case 'f': case 'F': saw_a_flag = 1; val |= 0x1; break;
4909130561Sobrien
4910218822Sdim      default:
4911218822Sdim	inst.error = _("unrecognized CPS flag");
4912218822Sdim	return FAIL;
4913218822Sdim      }
4914218822Sdim
4915218822Sdim done:
4916218822Sdim  if (saw_a_flag == 0)
4917130561Sobrien    {
4918218822Sdim      inst.error = _("missing CPS flags");
4919218822Sdim      return FAIL;
4920130561Sobrien    }
4921130561Sobrien
4922218822Sdim  *str = s - 1;
4923218822Sdim  return val;
4924130561Sobrien}
4925130561Sobrien
4926218822Sdim/* Parse an endian specifier ("BE" or "LE", case insensitive);
4927218822Sdim   returns 0 for big-endian, 1 for little-endian, FAIL for an error.  */
4928130561Sobrien
4929218822Sdimstatic int
4930218822Sdimparse_endian_specifier (char **str)
4931130561Sobrien{
4932218822Sdim  int little_endian;
4933218822Sdim  char *s = *str;
4934218822Sdim
4935218822Sdim  if (strncasecmp (s, "BE", 2))
4936218822Sdim    little_endian = 0;
4937218822Sdim  else if (strncasecmp (s, "LE", 2))
4938218822Sdim    little_endian = 1;
4939218822Sdim  else
4940130561Sobrien    {
4941218822Sdim      inst.error = _("valid endian specifiers are be or le");
4942218822Sdim      return FAIL;
4943130561Sobrien    }
4944130561Sobrien
4945218822Sdim  if (ISALNUM (s[2]) || s[2] == '_')
4946130561Sobrien    {
4947218822Sdim      inst.error = _("valid endian specifiers are be or le");
4948218822Sdim      return FAIL;
4949130561Sobrien    }
4950130561Sobrien
4951218822Sdim  *str = s + 2;
4952218822Sdim  return little_endian;
4953130561Sobrien}
4954130561Sobrien
4955218822Sdim/* Parse a rotation specifier: ROR #0, #8, #16, #24.  *val receives a
4956218822Sdim   value suitable for poking into the rotate field of an sxt or sxta
4957218822Sdim   instruction, or FAIL on error.  */
4958130561Sobrien
4959218822Sdimstatic int
4960218822Sdimparse_ror (char **str)
4961130561Sobrien{
4962218822Sdim  int rot;
4963218822Sdim  char *s = *str;
4964218822Sdim
4965218822Sdim  if (strncasecmp (s, "ROR", 3) == 0)
4966218822Sdim    s += 3;
4967218822Sdim  else
4968130561Sobrien    {
4969218822Sdim      inst.error = _("missing rotation field after comma");
4970218822Sdim      return FAIL;
4971130561Sobrien    }
4972218822Sdim
4973218822Sdim  if (parse_immediate (&s, &rot, 0, 24, FALSE) == FAIL)
4974218822Sdim    return FAIL;
4975218822Sdim
4976218822Sdim  switch (rot)
4977130561Sobrien    {
4978218822Sdim    case  0: *str = s; return 0x0;
4979218822Sdim    case  8: *str = s; return 0x1;
4980218822Sdim    case 16: *str = s; return 0x2;
4981218822Sdim    case 24: *str = s; return 0x3;
4982218822Sdim
4983218822Sdim    default:
4984218822Sdim      inst.error = _("rotation can only be 0, 8, 16, or 24");
4985218822Sdim      return FAIL;
4986130561Sobrien    }
4987218822Sdim}
4988130561Sobrien
4989218822Sdim/* Parse a conditional code (from conds[] below).  The value returned is in the
4990218822Sdim   range 0 .. 14, or FAIL.  */
4991218822Sdimstatic int
4992218822Sdimparse_cond (char **str)
4993218822Sdim{
4994218822Sdim  char *p, *q;
4995218822Sdim  const struct asm_cond *c;
4996130561Sobrien
4997218822Sdim  p = q = *str;
4998218822Sdim  while (ISALPHA (*q))
4999218822Sdim    q++;
5000130561Sobrien
5001218822Sdim  c = hash_find_n (arm_cond_hsh, p, q - p);
5002218822Sdim  if (!c)
5003218822Sdim    {
5004218822Sdim      inst.error = _("condition required");
5005218822Sdim      return FAIL;
5006218822Sdim    }
5007130561Sobrien
5008218822Sdim  *str = q;
5009218822Sdim  return c->value;
5010130561Sobrien}
5011130561Sobrien
5012218822Sdim/* Parse an option for a barrier instruction.  Returns the encoding for the
5013218822Sdim   option, or FAIL.  */
5014130561Sobrienstatic int
5015218822Sdimparse_barrier (char **str)
5016130561Sobrien{
5017218822Sdim  char *p, *q;
5018218822Sdim  const struct asm_barrier_opt *o;
5019130561Sobrien
5020218822Sdim  p = q = *str;
5021218822Sdim  while (ISALPHA (*q))
5022218822Sdim    q++;
5023130561Sobrien
5024218822Sdim  o = hash_find_n (arm_barrier_opt_hsh, p, q - p);
5025218822Sdim  if (!o)
5026218822Sdim    return FAIL;
5027130561Sobrien
5028218822Sdim  *str = q;
5029218822Sdim  return o->value;
5030130561Sobrien}
5031130561Sobrien
5032218822Sdim/* Parse the operands of a table branch instruction.  Similar to a memory
5033218822Sdim   operand.  */
5034218822Sdimstatic int
5035218822Sdimparse_tb (char **str)
5036218822Sdim{
5037218822Sdim  char * p = *str;
5038218822Sdim  int reg;
5039130561Sobrien
5040218822Sdim  if (skip_past_char (&p, '[') == FAIL)
5041130561Sobrien    {
5042218822Sdim      inst.error = _("'[' expected");
5043218822Sdim      return FAIL;
5044130561Sobrien    }
5045130561Sobrien
5046218822Sdim  if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
5047130561Sobrien    {
5048218822Sdim      inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
5049218822Sdim      return FAIL;
5050130561Sobrien    }
5051218822Sdim  inst.operands[0].reg = reg;
5052218822Sdim
5053218822Sdim  if (skip_past_comma (&p) == FAIL)
5054130561Sobrien    {
5055218822Sdim      inst.error = _("',' expected");
5056218822Sdim      return FAIL;
5057130561Sobrien    }
5058130561Sobrien
5059218822Sdim  if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
5060130561Sobrien    {
5061218822Sdim      inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
5062218822Sdim      return FAIL;
5063130561Sobrien    }
5064218822Sdim  inst.operands[0].imm = reg;
5065218822Sdim
5066218822Sdim  if (skip_past_comma (&p) == SUCCESS)
5067130561Sobrien    {
5068218822Sdim      if (parse_shift (&p, 0, SHIFT_LSL_IMMEDIATE) == FAIL)
5069218822Sdim	return FAIL;
5070218822Sdim      if (inst.reloc.exp.X_add_number != 1)
5071218822Sdim	{
5072218822Sdim	  inst.error = _("invalid shift");
5073218822Sdim	  return FAIL;
5074218822Sdim	}
5075218822Sdim      inst.operands[0].shifted = 1;
5076130561Sobrien    }
5077218822Sdim
5078218822Sdim  if (skip_past_char (&p, ']') == FAIL)
5079130561Sobrien    {
5080218822Sdim      inst.error = _("']' expected");
5081218822Sdim      return FAIL;
5082130561Sobrien    }
5083218822Sdim  *str = p;
5084218822Sdim  return SUCCESS;
5085218822Sdim}
5086130561Sobrien
5087218822Sdim/* Parse the operands of a Neon VMOV instruction. See do_neon_mov for more
5088218822Sdim   information on the types the operands can take and how they are encoded.
5089218822Sdim   Up to four operands may be read; this function handles setting the
5090218822Sdim   ".present" field for each read operand itself.
5091218822Sdim   Updates STR and WHICH_OPERAND if parsing is successful and returns SUCCESS,
5092218822Sdim   else returns FAIL.  */
5093218822Sdim
5094218822Sdimstatic int
5095218822Sdimparse_neon_mov (char **str, int *which_operand)
5096218822Sdim{
5097218822Sdim  int i = *which_operand, val;
5098218822Sdim  enum arm_reg_type rtype;
5099218822Sdim  char *ptr = *str;
5100218822Sdim  struct neon_type_el optype;
5101130561Sobrien
5102218822Sdim  if ((val = parse_scalar (&ptr, 8, &optype)) != FAIL)
5103130561Sobrien    {
5104218822Sdim      /* Case 4: VMOV<c><q>.<size> <Dn[x]>, <Rd>.  */
5105218822Sdim      inst.operands[i].reg = val;
5106218822Sdim      inst.operands[i].isscalar = 1;
5107218822Sdim      inst.operands[i].vectype = optype;
5108218822Sdim      inst.operands[i++].present = 1;
5109130561Sobrien
5110218822Sdim      if (skip_past_comma (&ptr) == FAIL)
5111218822Sdim        goto wanted_comma;
5112130561Sobrien
5113218822Sdim      if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) == FAIL)
5114218822Sdim        goto wanted_arm;
5115218822Sdim
5116218822Sdim      inst.operands[i].reg = val;
5117218822Sdim      inst.operands[i].isreg = 1;
5118218822Sdim      inst.operands[i].present = 1;
5119130561Sobrien    }
5120218822Sdim  else if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_NSDQ, &rtype, &optype))
5121218822Sdim           != FAIL)
5122218822Sdim    {
5123218822Sdim      /* Cases 0, 1, 2, 3, 5 (D only).  */
5124218822Sdim      if (skip_past_comma (&ptr) == FAIL)
5125218822Sdim        goto wanted_comma;
5126218822Sdim
5127218822Sdim      inst.operands[i].reg = val;
5128218822Sdim      inst.operands[i].isreg = 1;
5129218822Sdim      inst.operands[i].isquad = (rtype == REG_TYPE_NQ);
5130218822Sdim      inst.operands[i].issingle = (rtype == REG_TYPE_VFS);
5131218822Sdim      inst.operands[i].isvec = 1;
5132218822Sdim      inst.operands[i].vectype = optype;
5133218822Sdim      inst.operands[i++].present = 1;
5134130561Sobrien
5135218822Sdim      if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) != FAIL)
5136218822Sdim        {
5137218822Sdim          /* Case 5: VMOV<c><q> <Dm>, <Rd>, <Rn>.
5138218822Sdim             Case 13: VMOV <Sd>, <Rm>  */
5139218822Sdim          inst.operands[i].reg = val;
5140218822Sdim          inst.operands[i].isreg = 1;
5141218822Sdim          inst.operands[i].present = 1;
5142130561Sobrien
5143218822Sdim          if (rtype == REG_TYPE_NQ)
5144218822Sdim            {
5145218822Sdim              first_error (_("can't use Neon quad register here"));
5146218822Sdim              return FAIL;
5147218822Sdim            }
5148218822Sdim          else if (rtype != REG_TYPE_VFS)
5149218822Sdim            {
5150218822Sdim              i++;
5151218822Sdim              if (skip_past_comma (&ptr) == FAIL)
5152218822Sdim                goto wanted_comma;
5153218822Sdim              if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) == FAIL)
5154218822Sdim                goto wanted_arm;
5155218822Sdim              inst.operands[i].reg = val;
5156218822Sdim              inst.operands[i].isreg = 1;
5157218822Sdim              inst.operands[i].present = 1;
5158218822Sdim            }
5159218822Sdim        }
5160218822Sdim      else if (parse_qfloat_immediate (&ptr, &inst.operands[i].imm) == SUCCESS)
5161218822Sdim          /* Case 2: VMOV<c><q>.<dt> <Qd>, #<float-imm>
5162218822Sdim             Case 3: VMOV<c><q>.<dt> <Dd>, #<float-imm>
5163218822Sdim             Case 10: VMOV.F32 <Sd>, #<imm>
5164218822Sdim             Case 11: VMOV.F64 <Dd>, #<imm>  */
5165218822Sdim        inst.operands[i].immisfloat = 1;
5166218822Sdim      else if (parse_big_immediate (&ptr, i) == SUCCESS)
5167218822Sdim          /* Case 2: VMOV<c><q>.<dt> <Qd>, #<imm>
5168218822Sdim             Case 3: VMOV<c><q>.<dt> <Dd>, #<imm>  */
5169218822Sdim        ;
5170218822Sdim      else if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_NSDQ, &rtype,
5171218822Sdim                                           &optype)) != FAIL)
5172218822Sdim        {
5173218822Sdim          /* Case 0: VMOV<c><q> <Qd>, <Qm>
5174218822Sdim             Case 1: VMOV<c><q> <Dd>, <Dm>
5175218822Sdim             Case 8: VMOV.F32 <Sd>, <Sm>
5176218822Sdim             Case 15: VMOV <Sd>, <Se>, <Rn>, <Rm>  */
5177130561Sobrien
5178218822Sdim          inst.operands[i].reg = val;
5179218822Sdim          inst.operands[i].isreg = 1;
5180218822Sdim          inst.operands[i].isquad = (rtype == REG_TYPE_NQ);
5181218822Sdim          inst.operands[i].issingle = (rtype == REG_TYPE_VFS);
5182218822Sdim          inst.operands[i].isvec = 1;
5183218822Sdim          inst.operands[i].vectype = optype;
5184218822Sdim          inst.operands[i].present = 1;
5185218822Sdim
5186218822Sdim          if (skip_past_comma (&ptr) == SUCCESS)
5187218822Sdim            {
5188218822Sdim              /* Case 15.  */
5189218822Sdim              i++;
5190130561Sobrien
5191218822Sdim              if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) == FAIL)
5192218822Sdim                goto wanted_arm;
5193218822Sdim
5194218822Sdim              inst.operands[i].reg = val;
5195218822Sdim              inst.operands[i].isreg = 1;
5196218822Sdim              inst.operands[i++].present = 1;
5197218822Sdim
5198218822Sdim              if (skip_past_comma (&ptr) == FAIL)
5199218822Sdim                goto wanted_comma;
5200218822Sdim
5201218822Sdim              if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) == FAIL)
5202218822Sdim                goto wanted_arm;
5203218822Sdim
5204218822Sdim              inst.operands[i].reg = val;
5205218822Sdim              inst.operands[i].isreg = 1;
5206218822Sdim              inst.operands[i++].present = 1;
5207218822Sdim            }
5208218822Sdim        }
5209218822Sdim      else
5210218822Sdim        {
5211218822Sdim          first_error (_("expected <Rm> or <Dm> or <Qm> operand"));
5212218822Sdim          return FAIL;
5213218822Sdim        }
5214130561Sobrien    }
5215218822Sdim  else if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) != FAIL)
5216130561Sobrien    {
5217218822Sdim      /* Cases 6, 7.  */
5218218822Sdim      inst.operands[i].reg = val;
5219218822Sdim      inst.operands[i].isreg = 1;
5220218822Sdim      inst.operands[i++].present = 1;
5221218822Sdim
5222218822Sdim      if (skip_past_comma (&ptr) == FAIL)
5223218822Sdim        goto wanted_comma;
5224218822Sdim
5225218822Sdim      if ((val = parse_scalar (&ptr, 8, &optype)) != FAIL)
5226218822Sdim        {
5227218822Sdim          /* Case 6: VMOV<c><q>.<dt> <Rd>, <Dn[x]>  */
5228218822Sdim          inst.operands[i].reg = val;
5229218822Sdim          inst.operands[i].isscalar = 1;
5230218822Sdim          inst.operands[i].present = 1;
5231218822Sdim          inst.operands[i].vectype = optype;
5232218822Sdim        }
5233218822Sdim      else if ((val = arm_reg_parse (&ptr, REG_TYPE_RN)) != FAIL)
5234218822Sdim        {
5235218822Sdim          /* Case 7: VMOV<c><q> <Rd>, <Rn>, <Dm>  */
5236218822Sdim          inst.operands[i].reg = val;
5237218822Sdim          inst.operands[i].isreg = 1;
5238218822Sdim          inst.operands[i++].present = 1;
5239218822Sdim
5240218822Sdim          if (skip_past_comma (&ptr) == FAIL)
5241218822Sdim            goto wanted_comma;
5242218822Sdim
5243218822Sdim          if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_VFSD, &rtype, &optype))
5244218822Sdim              == FAIL)
5245218822Sdim            {
5246218822Sdim              first_error (_(reg_expected_msgs[REG_TYPE_VFSD]));
5247218822Sdim              return FAIL;
5248218822Sdim            }
5249218822Sdim
5250218822Sdim          inst.operands[i].reg = val;
5251218822Sdim          inst.operands[i].isreg = 1;
5252218822Sdim          inst.operands[i].isvec = 1;
5253218822Sdim          inst.operands[i].issingle = (rtype == REG_TYPE_VFS);
5254218822Sdim          inst.operands[i].vectype = optype;
5255218822Sdim          inst.operands[i].present = 1;
5256218822Sdim
5257218822Sdim          if (rtype == REG_TYPE_VFS)
5258218822Sdim            {
5259218822Sdim              /* Case 14.  */
5260218822Sdim              i++;
5261218822Sdim              if (skip_past_comma (&ptr) == FAIL)
5262218822Sdim                goto wanted_comma;
5263218822Sdim              if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_VFS, NULL,
5264218822Sdim                                              &optype)) == FAIL)
5265218822Sdim                {
5266218822Sdim                  first_error (_(reg_expected_msgs[REG_TYPE_VFS]));
5267218822Sdim                  return FAIL;
5268218822Sdim                }
5269218822Sdim              inst.operands[i].reg = val;
5270218822Sdim              inst.operands[i].isreg = 1;
5271218822Sdim              inst.operands[i].isvec = 1;
5272218822Sdim              inst.operands[i].issingle = 1;
5273218822Sdim              inst.operands[i].vectype = optype;
5274218822Sdim              inst.operands[i].present = 1;
5275218822Sdim            }
5276218822Sdim        }
5277218822Sdim      else if ((val = arm_typed_reg_parse (&ptr, REG_TYPE_VFS, NULL, &optype))
5278218822Sdim               != FAIL)
5279218822Sdim        {
5280218822Sdim          /* Case 13.  */
5281218822Sdim          inst.operands[i].reg = val;
5282218822Sdim          inst.operands[i].isreg = 1;
5283218822Sdim          inst.operands[i].isvec = 1;
5284218822Sdim          inst.operands[i].issingle = 1;
5285218822Sdim          inst.operands[i].vectype = optype;
5286218822Sdim          inst.operands[i++].present = 1;
5287218822Sdim        }
5288130561Sobrien    }
5289130561Sobrien  else
5290130561Sobrien    {
5291218822Sdim      first_error (_("parse error"));
5292218822Sdim      return FAIL;
5293130561Sobrien    }
5294130561Sobrien
5295218822Sdim  /* Successfully parsed the operands. Update args.  */
5296218822Sdim  *which_operand = i;
5297218822Sdim  *str = ptr;
5298218822Sdim  return SUCCESS;
5299130561Sobrien
5300218822Sdim  wanted_comma:
5301218822Sdim  first_error (_("expected comma"));
5302218822Sdim  return FAIL;
5303130561Sobrien
5304218822Sdim  wanted_arm:
5305218822Sdim  first_error (_(reg_expected_msgs[REG_TYPE_RN]));
5306218822Sdim  return FAIL;
5307130561Sobrien}
5308130561Sobrien
5309218822Sdim/* Matcher codes for parse_operands.  */
5310218822Sdimenum operand_parse_code
5311130561Sobrien{
5312218822Sdim  OP_stop,	/* end of line */
5313130561Sobrien
5314218822Sdim  OP_RR,	/* ARM register */
5315218822Sdim  OP_RRnpc,	/* ARM register, not r15 */
5316218822Sdim  OP_RRnpcb,	/* ARM register, not r15, in square brackets */
5317218822Sdim  OP_RRw,	/* ARM register, not r15, optional trailing ! */
5318218822Sdim  OP_RCP,	/* Coprocessor number */
5319218822Sdim  OP_RCN,	/* Coprocessor register */
5320218822Sdim  OP_RF,	/* FPA register */
5321218822Sdim  OP_RVS,	/* VFP single precision register */
5322218822Sdim  OP_RVD,	/* VFP double precision register (0..15) */
5323218822Sdim  OP_RND,       /* Neon double precision register (0..31) */
5324218822Sdim  OP_RNQ,	/* Neon quad precision register */
5325218822Sdim  OP_RVSD,	/* VFP single or double precision register */
5326218822Sdim  OP_RNDQ,      /* Neon double or quad precision register */
5327218822Sdim  OP_RNSDQ,	/* Neon single, double or quad precision register */
5328218822Sdim  OP_RNSC,      /* Neon scalar D[X] */
5329218822Sdim  OP_RVC,	/* VFP control register */
5330218822Sdim  OP_RMF,	/* Maverick F register */
5331218822Sdim  OP_RMD,	/* Maverick D register */
5332218822Sdim  OP_RMFX,	/* Maverick FX register */
5333218822Sdim  OP_RMDX,	/* Maverick DX register */
5334218822Sdim  OP_RMAX,	/* Maverick AX register */
5335218822Sdim  OP_RMDS,	/* Maverick DSPSC register */
5336218822Sdim  OP_RIWR,	/* iWMMXt wR register */
5337218822Sdim  OP_RIWC,	/* iWMMXt wC register */
5338218822Sdim  OP_RIWG,	/* iWMMXt wCG register */
5339218822Sdim  OP_RXA,	/* XScale accumulator register */
5340130561Sobrien
5341218822Sdim  OP_REGLST,	/* ARM register list */
5342218822Sdim  OP_VRSLST,	/* VFP single-precision register list */
5343218822Sdim  OP_VRDLST,	/* VFP double-precision register list */
5344218822Sdim  OP_VRSDLST,   /* VFP single or double-precision register list (& quad) */
5345218822Sdim  OP_NRDLST,    /* Neon double-precision register list (d0-d31, qN aliases) */
5346218822Sdim  OP_NSTRLST,   /* Neon element/structure list */
5347130561Sobrien
5348218822Sdim  OP_NILO,      /* Neon immediate/logic operands 2 or 2+3. (VBIC, VORR...)  */
5349218822Sdim  OP_RNDQ_I0,   /* Neon D or Q reg, or immediate zero.  */
5350218822Sdim  OP_RVSD_I0,	/* VFP S or D reg, or immediate zero.  */
5351218822Sdim  OP_RR_RNSC,   /* ARM reg or Neon scalar.  */
5352218822Sdim  OP_RNSDQ_RNSC, /* Vector S, D or Q reg, or Neon scalar.  */
5353218822Sdim  OP_RNDQ_RNSC, /* Neon D or Q reg, or Neon scalar.  */
5354218822Sdim  OP_RND_RNSC,  /* Neon D reg, or Neon scalar.  */
5355218822Sdim  OP_VMOV,      /* Neon VMOV operands.  */
5356218822Sdim  OP_RNDQ_IMVNb,/* Neon D or Q reg, or immediate good for VMVN.  */
5357218822Sdim  OP_RNDQ_I63b, /* Neon D or Q reg, or immediate for shift.  */
5358218822Sdim  OP_RIWR_I32z, /* iWMMXt wR register, or immediate 0 .. 32 for iWMMXt2.  */
5359130561Sobrien
5360218822Sdim  OP_I0,        /* immediate zero */
5361218822Sdim  OP_I7,	/* immediate value 0 .. 7 */
5362218822Sdim  OP_I15,	/*		   0 .. 15 */
5363218822Sdim  OP_I16,	/*		   1 .. 16 */
5364218822Sdim  OP_I16z,      /*                 0 .. 16 */
5365218822Sdim  OP_I31,	/*		   0 .. 31 */
5366218822Sdim  OP_I31w,	/*		   0 .. 31, optional trailing ! */
5367218822Sdim  OP_I32,	/*		   1 .. 32 */
5368218822Sdim  OP_I32z,	/*		   0 .. 32 */
5369218822Sdim  OP_I63,	/*		   0 .. 63 */
5370218822Sdim  OP_I63s,	/*		 -64 .. 63 */
5371218822Sdim  OP_I64,	/*		   1 .. 64 */
5372218822Sdim  OP_I64z,	/*		   0 .. 64 */
5373218822Sdim  OP_I255,	/*		   0 .. 255 */
5374130561Sobrien
5375218822Sdim  OP_I4b,	/* immediate, prefix optional, 1 .. 4 */
5376218822Sdim  OP_I7b,	/*			       0 .. 7 */
5377218822Sdim  OP_I15b,	/*			       0 .. 15 */
5378218822Sdim  OP_I31b,	/*			       0 .. 31 */
5379130561Sobrien
5380218822Sdim  OP_SH,	/* shifter operand */
5381218822Sdim  OP_SHG,	/* shifter operand with possible group relocation */
5382218822Sdim  OP_ADDR,	/* Memory address expression (any mode) */
5383218822Sdim  OP_ADDRGLDR,	/* Mem addr expr (any mode) with possible LDR group reloc */
5384218822Sdim  OP_ADDRGLDRS, /* Mem addr expr (any mode) with possible LDRS group reloc */
5385218822Sdim  OP_ADDRGLDC,  /* Mem addr expr (any mode) with possible LDC group reloc */
5386218822Sdim  OP_EXP,	/* arbitrary expression */
5387218822Sdim  OP_EXPi,	/* same, with optional immediate prefix */
5388218822Sdim  OP_EXPr,	/* same, with optional relocation suffix */
5389218822Sdim  OP_HALF,	/* 0 .. 65535 or low/high reloc.  */
5390130561Sobrien
5391218822Sdim  OP_CPSF,	/* CPS flags */
5392218822Sdim  OP_ENDI,	/* Endianness specifier */
5393218822Sdim  OP_PSR,	/* CPSR/SPSR mask for msr */
5394218822Sdim  OP_COND,	/* conditional code */
5395218822Sdim  OP_TB,	/* Table branch.  */
5396130561Sobrien
5397218822Sdim  OP_RVC_PSR,	/* CPSR/SPSR mask for msr, or VFP control register.  */
5398218822Sdim  OP_APSR_RR,   /* ARM register or "APSR_nzcv".  */
5399130561Sobrien
5400218822Sdim  OP_RRnpc_I0,	/* ARM register or literal 0 */
5401218822Sdim  OP_RR_EXr,	/* ARM register or expression with opt. reloc suff. */
5402218822Sdim  OP_RR_EXi,	/* ARM register or expression with imm prefix */
5403218822Sdim  OP_RF_IF,	/* FPA register or immediate */
5404218822Sdim  OP_RIWR_RIWC, /* iWMMXt R or C reg */
5405218822Sdim  OP_RIWC_RIWG, /* iWMMXt wC or wCG reg */
5406130561Sobrien
5407218822Sdim  /* Optional operands.	 */
5408218822Sdim  OP_oI7b,	 /* immediate, prefix optional, 0 .. 7 */
5409218822Sdim  OP_oI31b,	 /*				0 .. 31 */
5410218822Sdim  OP_oI32b,      /*                             1 .. 32 */
5411218822Sdim  OP_oIffffb,	 /*				0 .. 65535 */
5412218822Sdim  OP_oI255c,	 /*	  curly-brace enclosed, 0 .. 255 */
5413130561Sobrien
5414218822Sdim  OP_oRR,	 /* ARM register */
5415218822Sdim  OP_oRRnpc,	 /* ARM register, not the PC */
5416218822Sdim  OP_oRRw,	 /* ARM register, not r15, optional trailing ! */
5417218822Sdim  OP_oRND,       /* Optional Neon double precision register */
5418218822Sdim  OP_oRNQ,       /* Optional Neon quad precision register */
5419218822Sdim  OP_oRNDQ,      /* Optional Neon double or quad precision register */
5420218822Sdim  OP_oRNSDQ,	 /* Optional single, double or quad precision vector register */
5421218822Sdim  OP_oSHll,	 /* LSL immediate */
5422218822Sdim  OP_oSHar,	 /* ASR immediate */
5423218822Sdim  OP_oSHllar,	 /* LSL or ASR immediate */
5424218822Sdim  OP_oROR,	 /* ROR 0/8/16/24 */
5425218822Sdim  OP_oBARRIER,	 /* Option argument for a barrier instruction.  */
5426130561Sobrien
5427218822Sdim  OP_FIRST_OPTIONAL = OP_oI7b
5428218822Sdim};
5429130561Sobrien
5430218822Sdim/* Generic instruction operand parser.	This does no encoding and no
5431218822Sdim   semantic validation; it merely squirrels values away in the inst
5432218822Sdim   structure.  Returns SUCCESS or FAIL depending on whether the
5433218822Sdim   specified grammar matched.  */
5434218822Sdimstatic int
5435218822Sdimparse_operands (char *str, const unsigned char *pattern)
5436218822Sdim{
5437218822Sdim  unsigned const char *upat = pattern;
5438218822Sdim  char *backtrack_pos = 0;
5439218822Sdim  const char *backtrack_error = 0;
5440218822Sdim  int i, val, backtrack_index = 0;
5441218822Sdim  enum arm_reg_type rtype;
5442218822Sdim  parse_operand_result result;
5443130561Sobrien
5444218822Sdim#define po_char_or_fail(chr) do {		\
5445218822Sdim  if (skip_past_char (&str, chr) == FAIL)	\
5446218822Sdim    goto bad_args;				\
5447218822Sdim} while (0)
5448130561Sobrien
5449218822Sdim#define po_reg_or_fail(regtype) do {				\
5450218822Sdim  val = arm_typed_reg_parse (&str, regtype, &rtype,		\
5451218822Sdim  			     &inst.operands[i].vectype);	\
5452218822Sdim  if (val == FAIL)						\
5453218822Sdim    {								\
5454218822Sdim      first_error (_(reg_expected_msgs[regtype]));		\
5455218822Sdim      goto failure;						\
5456218822Sdim    }								\
5457218822Sdim  inst.operands[i].reg = val;					\
5458218822Sdim  inst.operands[i].isreg = 1;					\
5459218822Sdim  inst.operands[i].isquad = (rtype == REG_TYPE_NQ);		\
5460218822Sdim  inst.operands[i].issingle = (rtype == REG_TYPE_VFS);		\
5461218822Sdim  inst.operands[i].isvec = (rtype == REG_TYPE_VFS		\
5462218822Sdim                            || rtype == REG_TYPE_VFD		\
5463218822Sdim                            || rtype == REG_TYPE_NQ);		\
5464218822Sdim} while (0)
5465130561Sobrien
5466218822Sdim#define po_reg_or_goto(regtype, label) do {			\
5467218822Sdim  val = arm_typed_reg_parse (&str, regtype, &rtype,		\
5468218822Sdim                             &inst.operands[i].vectype);	\
5469218822Sdim  if (val == FAIL)						\
5470218822Sdim    goto label;							\
5471218822Sdim								\
5472218822Sdim  inst.operands[i].reg = val;					\
5473218822Sdim  inst.operands[i].isreg = 1;					\
5474218822Sdim  inst.operands[i].isquad = (rtype == REG_TYPE_NQ);		\
5475218822Sdim  inst.operands[i].issingle = (rtype == REG_TYPE_VFS);		\
5476218822Sdim  inst.operands[i].isvec = (rtype == REG_TYPE_VFS		\
5477218822Sdim                            || rtype == REG_TYPE_VFD		\
5478218822Sdim                            || rtype == REG_TYPE_NQ);		\
5479218822Sdim} while (0)
5480130561Sobrien
5481218822Sdim#define po_imm_or_fail(min, max, popt) do {			\
5482218822Sdim  if (parse_immediate (&str, &val, min, max, popt) == FAIL)	\
5483218822Sdim    goto failure;						\
5484218822Sdim  inst.operands[i].imm = val;					\
5485218822Sdim} while (0)
5486130561Sobrien
5487218822Sdim#define po_scalar_or_goto(elsz, label) do {			\
5488218822Sdim  val = parse_scalar (&str, elsz, &inst.operands[i].vectype);	\
5489218822Sdim  if (val == FAIL)						\
5490218822Sdim    goto label;							\
5491218822Sdim  inst.operands[i].reg = val;					\
5492218822Sdim  inst.operands[i].isscalar = 1;				\
5493218822Sdim} while (0)
5494130561Sobrien
5495218822Sdim#define po_misc_or_fail(expr) do {		\
5496218822Sdim  if (expr)					\
5497218822Sdim    goto failure;				\
5498218822Sdim} while (0)
5499130561Sobrien
5500218822Sdim#define po_misc_or_fail_no_backtrack(expr) do {	\
5501218822Sdim  result = expr;				\
5502218822Sdim  if (result == PARSE_OPERAND_FAIL_NO_BACKTRACK)\
5503218822Sdim    backtrack_pos = 0;				\
5504218822Sdim  if (result != PARSE_OPERAND_SUCCESS)		\
5505218822Sdim    goto failure;				\
5506218822Sdim} while (0)
5507130561Sobrien
5508130561Sobrien  skip_whitespace (str);
5509130561Sobrien
5510218822Sdim  for (i = 0; upat[i] != OP_stop; i++)
5511130561Sobrien    {
5512218822Sdim      if (upat[i] >= OP_FIRST_OPTIONAL)
5513130561Sobrien	{
5514218822Sdim	  /* Remember where we are in case we need to backtrack.  */
5515218822Sdim	  assert (!backtrack_pos);
5516218822Sdim	  backtrack_pos = str;
5517218822Sdim	  backtrack_error = inst.error;
5518218822Sdim	  backtrack_index = i;
5519130561Sobrien	}
5520130561Sobrien
5521218822Sdim      if (i > 0 && (i > 1 || inst.operands[0].present))
5522218822Sdim	po_char_or_fail (',');
5523130561Sobrien
5524218822Sdim      switch (upat[i])
5525218822Sdim	{
5526218822Sdim	  /* Registers */
5527218822Sdim	case OP_oRRnpc:
5528218822Sdim	case OP_RRnpc:
5529218822Sdim	case OP_oRR:
5530218822Sdim	case OP_RR:    po_reg_or_fail (REG_TYPE_RN);	  break;
5531218822Sdim	case OP_RCP:   po_reg_or_fail (REG_TYPE_CP);	  break;
5532218822Sdim	case OP_RCN:   po_reg_or_fail (REG_TYPE_CN);	  break;
5533218822Sdim	case OP_RF:    po_reg_or_fail (REG_TYPE_FN);	  break;
5534218822Sdim	case OP_RVS:   po_reg_or_fail (REG_TYPE_VFS);	  break;
5535218822Sdim	case OP_RVD:   po_reg_or_fail (REG_TYPE_VFD);	  break;
5536218822Sdim        case OP_oRND:
5537218822Sdim	case OP_RND:   po_reg_or_fail (REG_TYPE_VFD);	  break;
5538218822Sdim	case OP_RVC:
5539218822Sdim	  po_reg_or_goto (REG_TYPE_VFC, coproc_reg);
5540218822Sdim	  break;
5541218822Sdim	  /* Also accept generic coprocessor regs for unknown registers.  */
5542218822Sdim	  coproc_reg:
5543218822Sdim	  po_reg_or_fail (REG_TYPE_CN);
5544218822Sdim	  break;
5545218822Sdim	case OP_RMF:   po_reg_or_fail (REG_TYPE_MVF);	  break;
5546218822Sdim	case OP_RMD:   po_reg_or_fail (REG_TYPE_MVD);	  break;
5547218822Sdim	case OP_RMFX:  po_reg_or_fail (REG_TYPE_MVFX);	  break;
5548218822Sdim	case OP_RMDX:  po_reg_or_fail (REG_TYPE_MVDX);	  break;
5549218822Sdim	case OP_RMAX:  po_reg_or_fail (REG_TYPE_MVAX);	  break;
5550218822Sdim	case OP_RMDS:  po_reg_or_fail (REG_TYPE_DSPSC);	  break;
5551218822Sdim	case OP_RIWR:  po_reg_or_fail (REG_TYPE_MMXWR);	  break;
5552218822Sdim	case OP_RIWC:  po_reg_or_fail (REG_TYPE_MMXWC);	  break;
5553218822Sdim	case OP_RIWG:  po_reg_or_fail (REG_TYPE_MMXWCG);  break;
5554218822Sdim	case OP_RXA:   po_reg_or_fail (REG_TYPE_XSCALE);  break;
5555218822Sdim        case OP_oRNQ:
5556218822Sdim	case OP_RNQ:   po_reg_or_fail (REG_TYPE_NQ);      break;
5557218822Sdim        case OP_oRNDQ:
5558218822Sdim	case OP_RNDQ:  po_reg_or_fail (REG_TYPE_NDQ);     break;
5559218822Sdim        case OP_RVSD:  po_reg_or_fail (REG_TYPE_VFSD);    break;
5560218822Sdim        case OP_oRNSDQ:
5561218822Sdim        case OP_RNSDQ: po_reg_or_fail (REG_TYPE_NSDQ);    break;
5562130561Sobrien
5563218822Sdim        /* Neon scalar. Using an element size of 8 means that some invalid
5564218822Sdim           scalars are accepted here, so deal with those in later code.  */
5565218822Sdim        case OP_RNSC:  po_scalar_or_goto (8, failure);    break;
5566130561Sobrien
5567218822Sdim        /* WARNING: We can expand to two operands here. This has the potential
5568218822Sdim           to totally confuse the backtracking mechanism! It will be OK at
5569218822Sdim           least as long as we don't try to use optional args as well,
5570218822Sdim           though.  */
5571218822Sdim        case OP_NILO:
5572218822Sdim          {
5573218822Sdim            po_reg_or_goto (REG_TYPE_NDQ, try_imm);
5574218822Sdim	    inst.operands[i].present = 1;
5575218822Sdim            i++;
5576218822Sdim            skip_past_comma (&str);
5577218822Sdim            po_reg_or_goto (REG_TYPE_NDQ, one_reg_only);
5578218822Sdim            break;
5579218822Sdim            one_reg_only:
5580218822Sdim            /* Optional register operand was omitted. Unfortunately, it's in
5581218822Sdim               operands[i-1] and we need it to be in inst.operands[i]. Fix that
5582218822Sdim               here (this is a bit grotty).  */
5583218822Sdim            inst.operands[i] = inst.operands[i-1];
5584218822Sdim            inst.operands[i-1].present = 0;
5585218822Sdim            break;
5586218822Sdim            try_imm:
5587218822Sdim	    /* There's a possibility of getting a 64-bit immediate here, so
5588218822Sdim	       we need special handling.  */
5589218822Sdim	    if (parse_big_immediate (&str, i) == FAIL)
5590218822Sdim	      {
5591218822Sdim		inst.error = _("immediate value is out of range");
5592218822Sdim		goto failure;
5593218822Sdim	      }
5594218822Sdim          }
5595218822Sdim          break;
5596130561Sobrien
5597218822Sdim        case OP_RNDQ_I0:
5598218822Sdim          {
5599218822Sdim            po_reg_or_goto (REG_TYPE_NDQ, try_imm0);
5600218822Sdim            break;
5601218822Sdim            try_imm0:
5602218822Sdim            po_imm_or_fail (0, 0, TRUE);
5603218822Sdim          }
5604218822Sdim          break;
5605130561Sobrien
5606218822Sdim        case OP_RVSD_I0:
5607218822Sdim          po_reg_or_goto (REG_TYPE_VFSD, try_imm0);
5608218822Sdim          break;
5609130561Sobrien
5610218822Sdim        case OP_RR_RNSC:
5611218822Sdim          {
5612218822Sdim            po_scalar_or_goto (8, try_rr);
5613218822Sdim            break;
5614218822Sdim            try_rr:
5615218822Sdim            po_reg_or_fail (REG_TYPE_RN);
5616218822Sdim          }
5617218822Sdim          break;
5618130561Sobrien
5619218822Sdim        case OP_RNSDQ_RNSC:
5620218822Sdim          {
5621218822Sdim            po_scalar_or_goto (8, try_nsdq);
5622218822Sdim            break;
5623218822Sdim            try_nsdq:
5624218822Sdim            po_reg_or_fail (REG_TYPE_NSDQ);
5625218822Sdim          }
5626218822Sdim          break;
5627130561Sobrien
5628218822Sdim        case OP_RNDQ_RNSC:
5629218822Sdim          {
5630218822Sdim            po_scalar_or_goto (8, try_ndq);
5631218822Sdim            break;
5632218822Sdim            try_ndq:
5633218822Sdim            po_reg_or_fail (REG_TYPE_NDQ);
5634218822Sdim          }
5635218822Sdim          break;
5636130561Sobrien
5637218822Sdim        case OP_RND_RNSC:
5638218822Sdim          {
5639218822Sdim            po_scalar_or_goto (8, try_vfd);
5640218822Sdim            break;
5641218822Sdim            try_vfd:
5642218822Sdim            po_reg_or_fail (REG_TYPE_VFD);
5643218822Sdim          }
5644218822Sdim          break;
5645130561Sobrien
5646218822Sdim        case OP_VMOV:
5647218822Sdim          /* WARNING: parse_neon_mov can move the operand counter, i. If we're
5648218822Sdim             not careful then bad things might happen.  */
5649218822Sdim          po_misc_or_fail (parse_neon_mov (&str, &i) == FAIL);
5650218822Sdim          break;
5651130561Sobrien
5652218822Sdim        case OP_RNDQ_IMVNb:
5653218822Sdim          {
5654218822Sdim            po_reg_or_goto (REG_TYPE_NDQ, try_mvnimm);
5655218822Sdim            break;
5656218822Sdim            try_mvnimm:
5657218822Sdim            /* There's a possibility of getting a 64-bit immediate here, so
5658218822Sdim               we need special handling.  */
5659218822Sdim            if (parse_big_immediate (&str, i) == FAIL)
5660218822Sdim              {
5661218822Sdim                inst.error = _("immediate value is out of range");
5662218822Sdim                goto failure;
5663218822Sdim              }
5664218822Sdim          }
5665218822Sdim          break;
5666130561Sobrien
5667218822Sdim        case OP_RNDQ_I63b:
5668218822Sdim          {
5669218822Sdim            po_reg_or_goto (REG_TYPE_NDQ, try_shimm);
5670218822Sdim            break;
5671218822Sdim            try_shimm:
5672218822Sdim            po_imm_or_fail (0, 63, TRUE);
5673218822Sdim          }
5674218822Sdim          break;
5675130561Sobrien
5676218822Sdim	case OP_RRnpcb:
5677218822Sdim	  po_char_or_fail ('[');
5678218822Sdim	  po_reg_or_fail  (REG_TYPE_RN);
5679218822Sdim	  po_char_or_fail (']');
5680218822Sdim	  break;
5681130561Sobrien
5682218822Sdim	case OP_RRw:
5683218822Sdim	case OP_oRRw:
5684218822Sdim	  po_reg_or_fail (REG_TYPE_RN);
5685218822Sdim	  if (skip_past_char (&str, '!') == SUCCESS)
5686218822Sdim	    inst.operands[i].writeback = 1;
5687218822Sdim	  break;
5688130561Sobrien
5689218822Sdim	  /* Immediates */
5690218822Sdim	case OP_I7:	 po_imm_or_fail (  0,	   7, FALSE);	break;
5691218822Sdim	case OP_I15:	 po_imm_or_fail (  0,	  15, FALSE);	break;
5692218822Sdim	case OP_I16:	 po_imm_or_fail (  1,	  16, FALSE);	break;
5693218822Sdim        case OP_I16z:	 po_imm_or_fail (  0,     16, FALSE);   break;
5694218822Sdim	case OP_I31:	 po_imm_or_fail (  0,	  31, FALSE);	break;
5695218822Sdim	case OP_I32:	 po_imm_or_fail (  1,	  32, FALSE);	break;
5696218822Sdim        case OP_I32z:	 po_imm_or_fail (  0,     32, FALSE);   break;
5697218822Sdim	case OP_I63s:	 po_imm_or_fail (-64,	  63, FALSE);	break;
5698218822Sdim        case OP_I63:	 po_imm_or_fail (  0,     63, FALSE);   break;
5699218822Sdim        case OP_I64:	 po_imm_or_fail (  1,     64, FALSE);   break;
5700218822Sdim        case OP_I64z:	 po_imm_or_fail (  0,     64, FALSE);   break;
5701218822Sdim	case OP_I255:	 po_imm_or_fail (  0,	 255, FALSE);	break;
5702130561Sobrien
5703218822Sdim	case OP_I4b:	 po_imm_or_fail (  1,	   4, TRUE);	break;
5704218822Sdim	case OP_oI7b:
5705218822Sdim	case OP_I7b:	 po_imm_or_fail (  0,	   7, TRUE);	break;
5706218822Sdim	case OP_I15b:	 po_imm_or_fail (  0,	  15, TRUE);	break;
5707218822Sdim	case OP_oI31b:
5708218822Sdim	case OP_I31b:	 po_imm_or_fail (  0,	  31, TRUE);	break;
5709218822Sdim        case OP_oI32b:   po_imm_or_fail (  1,     32, TRUE);    break;
5710218822Sdim	case OP_oIffffb: po_imm_or_fail (  0, 0xffff, TRUE);	break;
5711130561Sobrien
5712218822Sdim	  /* Immediate variants */
5713218822Sdim	case OP_oI255c:
5714218822Sdim	  po_char_or_fail ('{');
5715218822Sdim	  po_imm_or_fail (0, 255, TRUE);
5716218822Sdim	  po_char_or_fail ('}');
5717218822Sdim	  break;
5718130561Sobrien
5719218822Sdim	case OP_I31w:
5720218822Sdim	  /* The expression parser chokes on a trailing !, so we have
5721218822Sdim	     to find it first and zap it.  */
5722218822Sdim	  {
5723218822Sdim	    char *s = str;
5724218822Sdim	    while (*s && *s != ',')
5725218822Sdim	      s++;
5726218822Sdim	    if (s[-1] == '!')
5727218822Sdim	      {
5728218822Sdim		s[-1] = '\0';
5729218822Sdim		inst.operands[i].writeback = 1;
5730218822Sdim	      }
5731218822Sdim	    po_imm_or_fail (0, 31, TRUE);
5732218822Sdim	    if (str == s - 1)
5733218822Sdim	      str = s;
5734218822Sdim	  }
5735218822Sdim	  break;
5736130561Sobrien
5737218822Sdim	  /* Expressions */
5738218822Sdim	case OP_EXPi:	EXPi:
5739218822Sdim	  po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str,
5740218822Sdim					      GE_OPT_PREFIX));
5741218822Sdim	  break;
5742130561Sobrien
5743218822Sdim	case OP_EXP:
5744218822Sdim	  po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str,
5745218822Sdim					      GE_NO_PREFIX));
5746218822Sdim	  break;
5747130561Sobrien
5748218822Sdim	case OP_EXPr:	EXPr:
5749218822Sdim	  po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str,
5750218822Sdim					      GE_NO_PREFIX));
5751218822Sdim	  if (inst.reloc.exp.X_op == O_symbol)
5752218822Sdim	    {
5753218822Sdim	      val = parse_reloc (&str);
5754218822Sdim	      if (val == -1)
5755218822Sdim		{
5756218822Sdim		  inst.error = _("unrecognized relocation suffix");
5757218822Sdim		  goto failure;
5758218822Sdim		}
5759218822Sdim	      else if (val != BFD_RELOC_UNUSED)
5760218822Sdim		{
5761218822Sdim		  inst.operands[i].imm = val;
5762218822Sdim		  inst.operands[i].hasreloc = 1;
5763218822Sdim		}
5764218822Sdim	    }
5765218822Sdim	  break;
5766218822Sdim
5767218822Sdim	  /* Operand for MOVW or MOVT.  */
5768218822Sdim	case OP_HALF:
5769218822Sdim	  po_misc_or_fail (parse_half (&str));
5770218822Sdim	  break;
5771218822Sdim
5772218822Sdim	  /* Register or expression */
5773218822Sdim	case OP_RR_EXr:	  po_reg_or_goto (REG_TYPE_RN, EXPr); break;
5774218822Sdim	case OP_RR_EXi:	  po_reg_or_goto (REG_TYPE_RN, EXPi); break;
5775218822Sdim
5776218822Sdim	  /* Register or immediate */
5777218822Sdim	case OP_RRnpc_I0: po_reg_or_goto (REG_TYPE_RN, I0);   break;
5778218822Sdim	I0:		  po_imm_or_fail (0, 0, FALSE);	      break;
5779218822Sdim
5780218822Sdim	case OP_RF_IF:    po_reg_or_goto (REG_TYPE_FN, IF);   break;
5781218822Sdim	IF:
5782218822Sdim	  if (!is_immediate_prefix (*str))
5783218822Sdim	    goto bad_args;
5784218822Sdim	  str++;
5785218822Sdim	  val = parse_fpa_immediate (&str);
5786218822Sdim	  if (val == FAIL)
5787218822Sdim	    goto failure;
5788218822Sdim	  /* FPA immediates are encoded as registers 8-15.
5789218822Sdim	     parse_fpa_immediate has already applied the offset.  */
5790218822Sdim	  inst.operands[i].reg = val;
5791218822Sdim	  inst.operands[i].isreg = 1;
5792218822Sdim	  break;
5793218822Sdim
5794218822Sdim	case OP_RIWR_I32z: po_reg_or_goto (REG_TYPE_MMXWR, I32z); break;
5795218822Sdim	I32z:		  po_imm_or_fail (0, 32, FALSE);	  break;
5796218822Sdim
5797218822Sdim	  /* Two kinds of register */
5798218822Sdim	case OP_RIWR_RIWC:
5799130561Sobrien	  {
5800218822Sdim	    struct reg_entry *rege = arm_reg_parse_multi (&str);
5801218822Sdim	    if (!rege
5802218822Sdim		|| (rege->type != REG_TYPE_MMXWR
5803218822Sdim		    && rege->type != REG_TYPE_MMXWC
5804218822Sdim		    && rege->type != REG_TYPE_MMXWCG))
5805218822Sdim	      {
5806218822Sdim		inst.error = _("iWMMXt data or control register expected");
5807218822Sdim		goto failure;
5808218822Sdim	      }
5809218822Sdim	    inst.operands[i].reg = rege->number;
5810218822Sdim	    inst.operands[i].isreg = (rege->type == REG_TYPE_MMXWR);
5811130561Sobrien	  }
5812218822Sdim	  break;
5813130561Sobrien
5814218822Sdim	case OP_RIWC_RIWG:
5815218822Sdim	  {
5816218822Sdim	    struct reg_entry *rege = arm_reg_parse_multi (&str);
5817218822Sdim	    if (!rege
5818218822Sdim		|| (rege->type != REG_TYPE_MMXWC
5819218822Sdim		    && rege->type != REG_TYPE_MMXWCG))
5820218822Sdim	      {
5821218822Sdim		inst.error = _("iWMMXt control register expected");
5822218822Sdim		goto failure;
5823218822Sdim	      }
5824218822Sdim	    inst.operands[i].reg = rege->number;
5825218822Sdim	    inst.operands[i].isreg = 1;
5826218822Sdim	  }
5827218822Sdim	  break;
582877298Sobrien
5829218822Sdim	  /* Misc */
5830218822Sdim	case OP_CPSF:	 val = parse_cps_flags (&str);		break;
5831218822Sdim	case OP_ENDI:	 val = parse_endian_specifier (&str);	break;
5832218822Sdim	case OP_oROR:	 val = parse_ror (&str);		break;
5833218822Sdim	case OP_PSR:	 val = parse_psr (&str);		break;
5834218822Sdim	case OP_COND:	 val = parse_cond (&str);		break;
5835218822Sdim	case OP_oBARRIER:val = parse_barrier (&str);		break;
583677298Sobrien
5837218822Sdim        case OP_RVC_PSR:
5838218822Sdim          po_reg_or_goto (REG_TYPE_VFC, try_psr);
5839218822Sdim          inst.operands[i].isvec = 1;  /* Mark VFP control reg as vector.  */
5840218822Sdim          break;
5841218822Sdim          try_psr:
5842218822Sdim          val = parse_psr (&str);
5843218822Sdim          break;
584477298Sobrien
5845218822Sdim        case OP_APSR_RR:
5846218822Sdim          po_reg_or_goto (REG_TYPE_RN, try_apsr);
5847218822Sdim          break;
5848218822Sdim          try_apsr:
5849218822Sdim          /* Parse "APSR_nvzc" operand (for FMSTAT-equivalent MRS
5850218822Sdim             instruction).  */
5851218822Sdim          if (strncasecmp (str, "APSR_", 5) == 0)
5852218822Sdim            {
5853218822Sdim              unsigned found = 0;
5854218822Sdim              str += 5;
5855218822Sdim              while (found < 15)
5856218822Sdim                switch (*str++)
5857218822Sdim                  {
5858218822Sdim                  case 'c': found = (found & 1) ? 16 : found | 1; break;
5859218822Sdim                  case 'n': found = (found & 2) ? 16 : found | 2; break;
5860218822Sdim                  case 'z': found = (found & 4) ? 16 : found | 4; break;
5861218822Sdim                  case 'v': found = (found & 8) ? 16 : found | 8; break;
5862218822Sdim                  default: found = 16;
5863218822Sdim                  }
5864218822Sdim              if (found != 15)
5865218822Sdim                goto failure;
5866218822Sdim              inst.operands[i].isvec = 1;
5867218822Sdim            }
5868218822Sdim          else
5869218822Sdim            goto failure;
5870218822Sdim          break;
587177298Sobrien
5872218822Sdim	case OP_TB:
5873218822Sdim	  po_misc_or_fail (parse_tb (&str));
5874218822Sdim	  break;
587577298Sobrien
5876218822Sdim	  /* Register lists */
5877218822Sdim	case OP_REGLST:
5878218822Sdim	  val = parse_reg_list (&str);
5879218822Sdim	  if (*str == '^')
5880218822Sdim	    {
5881218822Sdim	      inst.operands[1].writeback = 1;
5882218822Sdim	      str++;
5883218822Sdim	    }
5884218822Sdim	  break;
588577298Sobrien
5886218822Sdim	case OP_VRSLST:
5887218822Sdim	  val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_S);
5888218822Sdim	  break;
588977298Sobrien
5890218822Sdim	case OP_VRDLST:
5891218822Sdim	  val = parse_vfp_reg_list (&str, &inst.operands[i].reg, REGLIST_VFP_D);
5892218822Sdim	  break;
589377298Sobrien
5894218822Sdim        case OP_VRSDLST:
5895218822Sdim          /* Allow Q registers too.  */
5896218822Sdim          val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
5897218822Sdim                                    REGLIST_NEON_D);
5898218822Sdim          if (val == FAIL)
5899218822Sdim            {
5900218822Sdim              inst.error = NULL;
5901218822Sdim              val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
5902218822Sdim                                        REGLIST_VFP_S);
5903218822Sdim              inst.operands[i].issingle = 1;
5904218822Sdim            }
5905218822Sdim          break;
590677298Sobrien
5907218822Sdim        case OP_NRDLST:
5908218822Sdim          val = parse_vfp_reg_list (&str, &inst.operands[i].reg,
5909218822Sdim                                    REGLIST_NEON_D);
5910218822Sdim          break;
591177298Sobrien
5912218822Sdim	case OP_NSTRLST:
5913218822Sdim          val = parse_neon_el_struct_list (&str, &inst.operands[i].reg,
5914218822Sdim                                           &inst.operands[i].vectype);
5915218822Sdim          break;
591677298Sobrien
5917218822Sdim	  /* Addressing modes */
5918218822Sdim	case OP_ADDR:
5919218822Sdim	  po_misc_or_fail (parse_address (&str, i));
5920218822Sdim	  break;
592177298Sobrien
5922218822Sdim	case OP_ADDRGLDR:
5923218822Sdim	  po_misc_or_fail_no_backtrack (
5924218822Sdim            parse_address_group_reloc (&str, i, GROUP_LDR));
5925218822Sdim	  break;
592677298Sobrien
5927218822Sdim	case OP_ADDRGLDRS:
5928218822Sdim	  po_misc_or_fail_no_backtrack (
5929218822Sdim            parse_address_group_reloc (&str, i, GROUP_LDRS));
5930218822Sdim	  break;
593177298Sobrien
5932218822Sdim	case OP_ADDRGLDC:
5933218822Sdim	  po_misc_or_fail_no_backtrack (
5934218822Sdim            parse_address_group_reloc (&str, i, GROUP_LDC));
5935218822Sdim	  break;
593677298Sobrien
5937218822Sdim	case OP_SH:
5938218822Sdim	  po_misc_or_fail (parse_shifter_operand (&str, i));
5939218822Sdim	  break;
594077298Sobrien
5941218822Sdim	case OP_SHG:
5942218822Sdim	  po_misc_or_fail_no_backtrack (
5943218822Sdim            parse_shifter_operand_group_reloc (&str, i));
5944218822Sdim	  break;
594577298Sobrien
5946218822Sdim	case OP_oSHll:
5947218822Sdim	  po_misc_or_fail (parse_shift (&str, i, SHIFT_LSL_IMMEDIATE));
5948218822Sdim	  break;
594977298Sobrien
5950218822Sdim	case OP_oSHar:
5951218822Sdim	  po_misc_or_fail (parse_shift (&str, i, SHIFT_ASR_IMMEDIATE));
5952218822Sdim	  break;
595377298Sobrien
5954218822Sdim	case OP_oSHllar:
5955218822Sdim	  po_misc_or_fail (parse_shift (&str, i, SHIFT_LSL_OR_ASR_IMMEDIATE));
5956218822Sdim	  break;
595777298Sobrien
5958218822Sdim	default:
5959218822Sdim	  as_fatal ("unhandled operand code %d", upat[i]);
5960218822Sdim	}
596177298Sobrien
5962218822Sdim      /* Various value-based sanity checks and shared operations.  We
5963218822Sdim	 do not signal immediate failures for the register constraints;
5964218822Sdim	 this allows a syntax error to take precedence.	 */
5965218822Sdim      switch (upat[i])
5966104834Sobrien	{
5967218822Sdim	case OP_oRRnpc:
5968218822Sdim	case OP_RRnpc:
5969218822Sdim	case OP_RRnpcb:
5970218822Sdim	case OP_RRw:
5971218822Sdim	case OP_oRRw:
5972218822Sdim	case OP_RRnpc_I0:
5973218822Sdim	  if (inst.operands[i].isreg && inst.operands[i].reg == REG_PC)
5974218822Sdim	    inst.error = BAD_PC;
5975218822Sdim	  break;
597677298Sobrien
5977218822Sdim	case OP_CPSF:
5978218822Sdim	case OP_ENDI:
5979218822Sdim	case OP_oROR:
5980218822Sdim	case OP_PSR:
5981218822Sdim        case OP_RVC_PSR:
5982218822Sdim	case OP_COND:
5983218822Sdim	case OP_oBARRIER:
5984218822Sdim	case OP_REGLST:
5985218822Sdim	case OP_VRSLST:
5986218822Sdim	case OP_VRDLST:
5987218822Sdim        case OP_VRSDLST:
5988218822Sdim        case OP_NRDLST:
5989218822Sdim        case OP_NSTRLST:
5990218822Sdim	  if (val == FAIL)
5991218822Sdim	    goto failure;
5992218822Sdim	  inst.operands[i].imm = val;
5993218822Sdim	  break;
599477298Sobrien
5995218822Sdim	default:
5996218822Sdim	  break;
5997218822Sdim	}
599877298Sobrien
5999218822Sdim      /* If we get here, this operand was successfully parsed.	*/
6000218822Sdim      inst.operands[i].present = 1;
6001218822Sdim      continue;
600277298Sobrien
6003218822Sdim    bad_args:
6004218822Sdim      inst.error = BAD_ARGS;
600577298Sobrien
6006218822Sdim    failure:
6007218822Sdim      if (!backtrack_pos)
6008218822Sdim	{
6009218822Sdim	  /* The parse routine should already have set inst.error, but set a
6010218822Sdim	     defaut here just in case.  */
6011218822Sdim	  if (!inst.error)
6012218822Sdim	    inst.error = _("syntax error");
6013218822Sdim	  return FAIL;
6014218822Sdim	}
601577298Sobrien
6016218822Sdim      /* Do not backtrack over a trailing optional argument that
6017218822Sdim	 absorbed some text.  We will only fail again, with the
6018218822Sdim	 'garbage following instruction' error message, which is
6019218822Sdim	 probably less helpful than the current one.  */
6020218822Sdim      if (backtrack_index == i && backtrack_pos != str
6021218822Sdim	  && upat[i+1] == OP_stop)
6022218822Sdim	{
6023218822Sdim	  if (!inst.error)
6024218822Sdim	    inst.error = _("syntax error");
6025218822Sdim	  return FAIL;
6026218822Sdim	}
602777298Sobrien
6028218822Sdim      /* Try again, skipping the optional argument at backtrack_pos.  */
6029218822Sdim      str = backtrack_pos;
6030218822Sdim      inst.error = backtrack_error;
6031218822Sdim      inst.operands[backtrack_index].present = 0;
6032218822Sdim      i = backtrack_index;
6033218822Sdim      backtrack_pos = 0;
603477298Sobrien    }
603577298Sobrien
6036218822Sdim  /* Check that we have parsed all the arguments.  */
6037218822Sdim  if (*str != '\0' && !inst.error)
6038218822Sdim    inst.error = _("garbage following instruction");
603977298Sobrien
6040218822Sdim  return inst.error ? FAIL : SUCCESS;
604177298Sobrien}
604277298Sobrien
6043218822Sdim#undef po_char_or_fail
6044218822Sdim#undef po_reg_or_fail
6045218822Sdim#undef po_reg_or_goto
6046218822Sdim#undef po_imm_or_fail
6047218822Sdim#undef po_scalar_or_fail
6048218822Sdim
6049218822Sdim/* Shorthand macro for instruction encoding functions issuing errors.  */
6050218822Sdim#define constraint(expr, err) do {		\
6051218822Sdim  if (expr)					\
6052218822Sdim    {						\
6053218822Sdim      inst.error = err;				\
6054218822Sdim      return;					\
6055218822Sdim    }						\
6056218822Sdim} while (0)
605777298Sobrien
6058218822Sdim/* Functions for operand encoding.  ARM, then Thumb.  */
6059218822Sdim
6060218822Sdim#define rotate_left(v, n) (v << n | v >> (32 - n))
6061218822Sdim
6062218822Sdim/* If VAL can be encoded in the immediate field of an ARM instruction,
6063218822Sdim   return the encoded form.  Otherwise, return FAIL.  */
6064218822Sdim
6065218822Sdimstatic unsigned int
6066218822Sdimencode_arm_immediate (unsigned int val)
606777298Sobrien{
6068218822Sdim  unsigned int a, i;
606977298Sobrien
6070218822Sdim  for (i = 0; i < 32; i += 2)
6071218822Sdim    if ((a = rotate_left (val, i)) <= 0xff)
6072218822Sdim      return a | (i << 7); /* 12-bit pack: [shift-cnt,const].  */
607377298Sobrien
6074218822Sdim  return FAIL;
6075218822Sdim}
607677298Sobrien
6077218822Sdim/* If VAL can be encoded in the immediate field of a Thumb32 instruction,
6078218822Sdim   return the encoded form.  Otherwise, return FAIL.  */
6079218822Sdimstatic unsigned int
6080218822Sdimencode_thumb32_immediate (unsigned int val)
6081218822Sdim{
6082218822Sdim  unsigned int a, i;
608377298Sobrien
6084218822Sdim  if (val <= 0xff)
6085218822Sdim    return val;
6086218822Sdim
6087218822Sdim  for (i = 1; i <= 24; i++)
608877298Sobrien    {
6089218822Sdim      a = val >> i;
6090218822Sdim      if ((val & ~(0xff << i)) == 0)
6091218822Sdim	return ((val >> i) & 0x7f) | ((32 - i) << 7);
609277298Sobrien    }
609377298Sobrien
6094218822Sdim  a = val & 0xff;
6095218822Sdim  if (val == ((a << 16) | a))
6096218822Sdim    return 0x100 | a;
6097218822Sdim  if (val == ((a << 24) | (a << 16) | (a << 8) | a))
6098218822Sdim    return 0x300 | a;
609977298Sobrien
6100218822Sdim  a = val & 0xff00;
6101218822Sdim  if (val == ((a << 16) | a))
6102218822Sdim    return 0x200 | (a >> 8);
6103218822Sdim
6104218822Sdim  return FAIL;
6105218822Sdim}
6106218822Sdim/* Encode a VFP SP or DP register number into inst.instruction.  */
6107218822Sdim
6108218822Sdimstatic void
6109218822Sdimencode_arm_vfp_reg (int reg, enum vfp_reg_pos pos)
6110218822Sdim{
6111218822Sdim  if ((pos == VFP_REG_Dd || pos == VFP_REG_Dn || pos == VFP_REG_Dm)
6112218822Sdim      && reg > 15)
611377298Sobrien    {
6114218822Sdim      if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v3))
6115218822Sdim        {
6116218822Sdim          if (thumb_mode)
6117218822Sdim            ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
6118218822Sdim                                    fpu_vfp_ext_v3);
6119218822Sdim          else
6120218822Sdim            ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used,
6121218822Sdim                                    fpu_vfp_ext_v3);
6122218822Sdim        }
6123218822Sdim      else
6124218822Sdim        {
6125218822Sdim          first_error (_("D register out of range for selected VFP version"));
6126218822Sdim          return;
6127218822Sdim        }
612877298Sobrien    }
612977298Sobrien
6130218822Sdim  switch (pos)
6131218822Sdim    {
6132218822Sdim    case VFP_REG_Sd:
6133218822Sdim      inst.instruction |= ((reg >> 1) << 12) | ((reg & 1) << 22);
6134218822Sdim      break;
613577298Sobrien
6136218822Sdim    case VFP_REG_Sn:
6137218822Sdim      inst.instruction |= ((reg >> 1) << 16) | ((reg & 1) << 7);
6138218822Sdim      break;
613977298Sobrien
6140218822Sdim    case VFP_REG_Sm:
6141218822Sdim      inst.instruction |= ((reg >> 1) << 0) | ((reg & 1) << 5);
6142218822Sdim      break;
6143218822Sdim
6144218822Sdim    case VFP_REG_Dd:
6145218822Sdim      inst.instruction |= ((reg & 15) << 12) | ((reg >> 4) << 22);
6146218822Sdim      break;
6147218822Sdim
6148218822Sdim    case VFP_REG_Dn:
6149218822Sdim      inst.instruction |= ((reg & 15) << 16) | ((reg >> 4) << 7);
6150218822Sdim      break;
6151218822Sdim
6152218822Sdim    case VFP_REG_Dm:
6153218822Sdim      inst.instruction |= (reg & 15) | ((reg >> 4) << 5);
6154218822Sdim      break;
6155218822Sdim
6156218822Sdim    default:
6157218822Sdim      abort ();
6158218822Sdim    }
615977298Sobrien}
616077298Sobrien
6161218822Sdim/* Encode a <shift> in an ARM-format instruction.  The immediate,
6162218822Sdim   if any, is handled by md_apply_fix.	 */
6163130561Sobrienstatic void
6164218822Sdimencode_arm_shift (int i)
6165130561Sobrien{
6166218822Sdim  if (inst.operands[i].shift_kind == SHIFT_RRX)
6167218822Sdim    inst.instruction |= SHIFT_ROR << 5;
6168218822Sdim  else
6169218822Sdim    {
6170218822Sdim      inst.instruction |= inst.operands[i].shift_kind << 5;
6171218822Sdim      if (inst.operands[i].immisreg)
6172218822Sdim	{
6173218822Sdim	  inst.instruction |= SHIFT_BY_REG;
6174218822Sdim	  inst.instruction |= inst.operands[i].imm << 8;
6175218822Sdim	}
6176218822Sdim      else
6177218822Sdim	inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
6178218822Sdim    }
6179130561Sobrien}
6180130561Sobrien
6181130561Sobrienstatic void
6182218822Sdimencode_arm_shifter_operand (int i)
6183130561Sobrien{
6184218822Sdim  if (inst.operands[i].isreg)
6185218822Sdim    {
6186218822Sdim      inst.instruction |= inst.operands[i].reg;
6187218822Sdim      encode_arm_shift (i);
6188218822Sdim    }
6189218822Sdim  else
6190218822Sdim    inst.instruction |= INST_IMMEDIATE;
6191130561Sobrien}
6192130561Sobrien
6193218822Sdim/* Subroutine of encode_arm_addr_mode_2 and encode_arm_addr_mode_3.  */
6194130561Sobrienstatic void
6195218822Sdimencode_arm_addr_mode_common (int i, bfd_boolean is_t)
6196130561Sobrien{
6197218822Sdim  assert (inst.operands[i].isreg);
6198218822Sdim  inst.instruction |= inst.operands[i].reg << 16;
6199130561Sobrien
6200218822Sdim  if (inst.operands[i].preind)
6201218822Sdim    {
6202218822Sdim      if (is_t)
6203218822Sdim	{
6204218822Sdim	  inst.error = _("instruction does not accept preindexed addressing");
6205218822Sdim	  return;
6206218822Sdim	}
6207218822Sdim      inst.instruction |= PRE_INDEX;
6208218822Sdim      if (inst.operands[i].writeback)
6209218822Sdim	inst.instruction |= WRITE_BACK;
6210130561Sobrien
6211218822Sdim    }
6212218822Sdim  else if (inst.operands[i].postind)
6213218822Sdim    {
6214218822Sdim      assert (inst.operands[i].writeback);
6215218822Sdim      if (is_t)
6216218822Sdim	inst.instruction |= WRITE_BACK;
6217218822Sdim    }
6218218822Sdim  else /* unindexed - only for coprocessor */
6219218822Sdim    {
6220218822Sdim      inst.error = _("instruction does not accept unindexed addressing");
6221218822Sdim      return;
6222218822Sdim    }
6223130561Sobrien
6224218822Sdim  if (((inst.instruction & WRITE_BACK) || !(inst.instruction & PRE_INDEX))
6225218822Sdim      && (((inst.instruction & 0x000f0000) >> 16)
6226218822Sdim	  == ((inst.instruction & 0x0000f000) >> 12)))
6227218822Sdim    as_warn ((inst.instruction & LOAD_BIT)
6228218822Sdim	     ? _("destination register same as write-back base")
6229218822Sdim	     : _("source register same as write-back base"));
6230218822Sdim}
6231218822Sdim
6232218822Sdim/* inst.operands[i] was set up by parse_address.  Encode it into an
6233218822Sdim   ARM-format mode 2 load or store instruction.	 If is_t is true,
6234218822Sdim   reject forms that cannot be used with a T instruction (i.e. not
6235218822Sdim   post-indexed).  */
6236218822Sdimstatic void
6237218822Sdimencode_arm_addr_mode_2 (int i, bfd_boolean is_t)
6238130561Sobrien{
6239218822Sdim  encode_arm_addr_mode_common (i, is_t);
6240130561Sobrien
6241218822Sdim  if (inst.operands[i].immisreg)
6242130561Sobrien    {
6243218822Sdim      inst.instruction |= INST_IMMEDIATE;  /* yes, this is backwards */
6244218822Sdim      inst.instruction |= inst.operands[i].imm;
6245218822Sdim      if (!inst.operands[i].negative)
6246218822Sdim	inst.instruction |= INDEX_UP;
6247218822Sdim      if (inst.operands[i].shifted)
6248218822Sdim	{
6249218822Sdim	  if (inst.operands[i].shift_kind == SHIFT_RRX)
6250218822Sdim	    inst.instruction |= SHIFT_ROR << 5;
6251218822Sdim	  else
6252218822Sdim	    {
6253218822Sdim	      inst.instruction |= inst.operands[i].shift_kind << 5;
6254218822Sdim	      inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
6255218822Sdim	    }
6256218822Sdim	}
6257130561Sobrien    }
6258218822Sdim  else /* immediate offset in inst.reloc */
6259130561Sobrien    {
6260218822Sdim      if (inst.reloc.type == BFD_RELOC_UNUSED)
6261218822Sdim	inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
6262130561Sobrien    }
6263218822Sdim}
6264218822Sdim
6265218822Sdim/* inst.operands[i] was set up by parse_address.  Encode it into an
6266218822Sdim   ARM-format mode 3 load or store instruction.	 Reject forms that
6267218822Sdim   cannot be used with such instructions.  If is_t is true, reject
6268218822Sdim   forms that cannot be used with a T instruction (i.e. not
6269218822Sdim   post-indexed).  */
6270218822Sdimstatic void
6271218822Sdimencode_arm_addr_mode_3 (int i, bfd_boolean is_t)
6272218822Sdim{
6273218822Sdim  if (inst.operands[i].immisreg && inst.operands[i].shifted)
6274130561Sobrien    {
6275218822Sdim      inst.error = _("instruction does not accept scaled register index");
6276218822Sdim      return;
6277218822Sdim    }
6278130561Sobrien
6279218822Sdim  encode_arm_addr_mode_common (i, is_t);
6280218822Sdim
6281218822Sdim  if (inst.operands[i].immisreg)
6282218822Sdim    {
6283218822Sdim      inst.instruction |= inst.operands[i].imm;
6284218822Sdim      if (!inst.operands[i].negative)
6285218822Sdim	inst.instruction |= INDEX_UP;
6286130561Sobrien    }
6287218822Sdim  else /* immediate offset in inst.reloc */
6288218822Sdim    {
6289218822Sdim      inst.instruction |= HWOFFSET_IMM;
6290218822Sdim      if (inst.reloc.type == BFD_RELOC_UNUSED)
6291218822Sdim	inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
6292218822Sdim    }
6293130561Sobrien}
6294130561Sobrien
6295218822Sdim/* inst.operands[i] was set up by parse_address.  Encode it into an
6296218822Sdim   ARM-format instruction.  Reject all forms which cannot be encoded
6297218822Sdim   into a coprocessor load/store instruction.  If wb_ok is false,
6298218822Sdim   reject use of writeback; if unind_ok is false, reject use of
6299218822Sdim   unindexed addressing.  If reloc_override is not 0, use it instead
6300218822Sdim   of BFD_ARM_CP_OFF_IMM, unless the initial relocation is a group one
6301218822Sdim   (in which case it is preserved).  */
6302218822Sdim
6303218822Sdimstatic int
6304218822Sdimencode_arm_cp_address (int i, int wb_ok, int unind_ok, int reloc_override)
6305130561Sobrien{
6306218822Sdim  inst.instruction |= inst.operands[i].reg << 16;
6307130561Sobrien
6308218822Sdim  assert (!(inst.operands[i].preind && inst.operands[i].postind));
6309130561Sobrien
6310218822Sdim  if (!inst.operands[i].preind && !inst.operands[i].postind) /* unindexed */
6311218822Sdim    {
6312218822Sdim      assert (!inst.operands[i].writeback);
6313218822Sdim      if (!unind_ok)
6314218822Sdim	{
6315218822Sdim	  inst.error = _("instruction does not support unindexed addressing");
6316218822Sdim	  return FAIL;
6317218822Sdim	}
6318218822Sdim      inst.instruction |= inst.operands[i].imm;
6319218822Sdim      inst.instruction |= INDEX_UP;
6320218822Sdim      return SUCCESS;
6321218822Sdim    }
6322130561Sobrien
6323218822Sdim  if (inst.operands[i].preind)
6324218822Sdim    inst.instruction |= PRE_INDEX;
6325218822Sdim
6326218822Sdim  if (inst.operands[i].writeback)
6327130561Sobrien    {
6328218822Sdim      if (inst.operands[i].reg == REG_PC)
6329218822Sdim	{
6330218822Sdim	  inst.error = _("pc may not be used with write-back");
6331218822Sdim	  return FAIL;
6332218822Sdim	}
6333218822Sdim      if (!wb_ok)
6334218822Sdim	{
6335218822Sdim	  inst.error = _("instruction does not support writeback");
6336218822Sdim	  return FAIL;
6337218822Sdim	}
6338218822Sdim      inst.instruction |= WRITE_BACK;
6339130561Sobrien    }
6340130561Sobrien
6341218822Sdim  if (reloc_override)
6342218822Sdim    inst.reloc.type = reloc_override;
6343218822Sdim  else if ((inst.reloc.type < BFD_RELOC_ARM_ALU_PC_G0_NC
6344218822Sdim            || inst.reloc.type > BFD_RELOC_ARM_LDC_SB_G2)
6345218822Sdim           && inst.reloc.type != BFD_RELOC_ARM_LDR_PC_G0)
6346130561Sobrien    {
6347218822Sdim      if (thumb_mode)
6348218822Sdim        inst.reloc.type = BFD_RELOC_ARM_T32_CP_OFF_IMM;
6349218822Sdim      else
6350218822Sdim        inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
6351130561Sobrien    }
6352218822Sdim
6353218822Sdim  return SUCCESS;
6354130561Sobrien}
6355130561Sobrien
6356218822Sdim/* inst.reloc.exp describes an "=expr" load pseudo-operation.
6357218822Sdim   Determine whether it can be performed with a move instruction; if
6358218822Sdim   it can, convert inst.instruction to that move instruction and
6359218822Sdim   return 1; if it can't, convert inst.instruction to a literal-pool
6360218822Sdim   load and return 0.  If this is not a valid thing to do in the
6361218822Sdim   current context, set inst.error and return 1.
6362218822Sdim
6363218822Sdim   inst.operands[i] describes the destination register.	 */
6364218822Sdim
6365218822Sdimstatic int
6366218822Sdimmove_or_literal_pool (int i, bfd_boolean thumb_p, bfd_boolean mode_3)
6367130561Sobrien{
6368218822Sdim  unsigned long tbit;
6369130561Sobrien
6370218822Sdim  if (thumb_p)
6371218822Sdim    tbit = (inst.instruction > 0xffff) ? THUMB2_LOAD_BIT : THUMB_LOAD_BIT;
6372218822Sdim  else
6373218822Sdim    tbit = LOAD_BIT;
6374130561Sobrien
6375218822Sdim  if ((inst.instruction & tbit) == 0)
6376218822Sdim    {
6377218822Sdim      inst.error = _("invalid pseudo operation");
6378218822Sdim      return 1;
6379218822Sdim    }
6380218822Sdim  if (inst.reloc.exp.X_op != O_constant && inst.reloc.exp.X_op != O_symbol)
6381218822Sdim    {
6382218822Sdim      inst.error = _("constant expression expected");
6383218822Sdim      return 1;
6384218822Sdim    }
6385218822Sdim  if (inst.reloc.exp.X_op == O_constant)
6386218822Sdim    {
6387218822Sdim      if (thumb_p)
6388218822Sdim	{
6389218822Sdim	  if (!unified_syntax && (inst.reloc.exp.X_add_number & ~0xFF) == 0)
6390218822Sdim	    {
6391218822Sdim	      /* This can be done with a mov(1) instruction.  */
6392218822Sdim	      inst.instruction	= T_OPCODE_MOV_I8 | (inst.operands[i].reg << 8);
6393218822Sdim	      inst.instruction |= inst.reloc.exp.X_add_number;
6394218822Sdim	      return 1;
6395218822Sdim	    }
6396218822Sdim	}
6397218822Sdim      else
6398218822Sdim	{
6399218822Sdim	  int value = encode_arm_immediate (inst.reloc.exp.X_add_number);
6400218822Sdim	  if (value != FAIL)
6401218822Sdim	    {
6402218822Sdim	      /* This can be done with a mov instruction.  */
6403218822Sdim	      inst.instruction &= LITERAL_MASK;
6404218822Sdim	      inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT);
6405218822Sdim	      inst.instruction |= value & 0xfff;
6406218822Sdim	      return 1;
6407218822Sdim	    }
6408218822Sdim
6409218822Sdim	  value = encode_arm_immediate (~inst.reloc.exp.X_add_number);
6410218822Sdim	  if (value != FAIL)
6411218822Sdim	    {
6412218822Sdim	      /* This can be done with a mvn instruction.  */
6413218822Sdim	      inst.instruction &= LITERAL_MASK;
6414218822Sdim	      inst.instruction |= INST_IMMEDIATE | (OPCODE_MVN << DATA_OP_SHIFT);
6415218822Sdim	      inst.instruction |= value & 0xfff;
6416218822Sdim	      return 1;
6417218822Sdim	    }
6418218822Sdim	}
6419218822Sdim    }
6420218822Sdim
6421218822Sdim  if (add_to_lit_pool () == FAIL)
6422218822Sdim    {
6423218822Sdim      inst.error = _("literal pool insertion failed");
6424218822Sdim      return 1;
6425218822Sdim    }
6426218822Sdim  inst.operands[1].reg = REG_PC;
6427218822Sdim  inst.operands[1].isreg = 1;
6428218822Sdim  inst.operands[1].preind = 1;
6429218822Sdim  inst.reloc.pc_rel = 1;
6430218822Sdim  inst.reloc.type = (thumb_p
6431218822Sdim		     ? BFD_RELOC_ARM_THUMB_OFFSET
6432218822Sdim		     : (mode_3
6433218822Sdim			? BFD_RELOC_ARM_HWLITERAL
6434218822Sdim			: BFD_RELOC_ARM_LITERAL));
6435218822Sdim  return 0;
6436130561Sobrien}
6437130561Sobrien
6438218822Sdim/* Functions for instruction encoding, sorted by subarchitecture.
6439218822Sdim   First some generics; their names are taken from the conventional
6440218822Sdim   bit positions for register arguments in ARM format instructions.  */
6441218822Sdim
6442130561Sobrienstatic void
6443218822Sdimdo_noargs (void)
6444130561Sobrien{
6445130561Sobrien}
6446130561Sobrien
6447130561Sobrienstatic void
6448218822Sdimdo_rd (void)
6449130561Sobrien{
6450218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6451130561Sobrien}
6452130561Sobrien
6453130561Sobrienstatic void
6454218822Sdimdo_rd_rm (void)
6455130561Sobrien{
6456218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6457218822Sdim  inst.instruction |= inst.operands[1].reg;
6458130561Sobrien}
6459130561Sobrien
6460130561Sobrienstatic void
6461218822Sdimdo_rd_rn (void)
6462130561Sobrien{
6463218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6464218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
6465130561Sobrien}
6466130561Sobrien
6467130561Sobrienstatic void
6468218822Sdimdo_rn_rd (void)
6469130561Sobrien{
6470218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
6471218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
6472130561Sobrien}
6473130561Sobrien
6474130561Sobrienstatic void
6475218822Sdimdo_rd_rm_rn (void)
6476130561Sobrien{
6477218822Sdim  unsigned Rn = inst.operands[2].reg;
6478218822Sdim  /* Enforce restrictions on SWP instruction.  */
6479218822Sdim  if ((inst.instruction & 0x0fbfffff) == 0x01000090)
6480218822Sdim    constraint (Rn == inst.operands[0].reg || Rn == inst.operands[1].reg,
6481218822Sdim		_("Rn must not overlap other operands"));
6482218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6483218822Sdim  inst.instruction |= inst.operands[1].reg;
6484218822Sdim  inst.instruction |= Rn << 16;
6485130561Sobrien}
6486130561Sobrien
6487130561Sobrienstatic void
6488218822Sdimdo_rd_rn_rm (void)
6489130561Sobrien{
6490218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6491218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
6492218822Sdim  inst.instruction |= inst.operands[2].reg;
6493130561Sobrien}
6494130561Sobrien
6495130561Sobrienstatic void
6496218822Sdimdo_rm_rd_rn (void)
6497130561Sobrien{
6498218822Sdim  inst.instruction |= inst.operands[0].reg;
6499218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
6500218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
6501130561Sobrien}
6502130561Sobrien
6503130561Sobrienstatic void
6504218822Sdimdo_imm0 (void)
6505130561Sobrien{
6506218822Sdim  inst.instruction |= inst.operands[0].imm;
6507130561Sobrien}
6508130561Sobrien
6509130561Sobrienstatic void
6510218822Sdimdo_rd_cpaddr (void)
6511130561Sobrien{
6512218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6513218822Sdim  encode_arm_cp_address (1, TRUE, TRUE, 0);
6514130561Sobrien}
6515130561Sobrien
6516218822Sdim/* ARM instructions, in alphabetical order by function name (except
6517218822Sdim   that wrapper functions appear immediately after the function they
6518218822Sdim   wrap).  */
6519218822Sdim
6520218822Sdim/* This is a pseudo-op of the form "adr rd, label" to be converted
6521218822Sdim   into a relative address of the form "add rd, pc, #label-.-8".  */
6522218822Sdim
6523130561Sobrienstatic void
6524218822Sdimdo_adr (void)
6525130561Sobrien{
6526218822Sdim  inst.instruction |= (inst.operands[0].reg << 12);  /* Rd */
6527218822Sdim
6528218822Sdim  /* Frag hacking will turn this into a sub instruction if the offset turns
6529218822Sdim     out to be negative.  */
6530218822Sdim  inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
6531218822Sdim  inst.reloc.pc_rel = 1;
6532218822Sdim  inst.reloc.exp.X_add_number -= 8;
6533130561Sobrien}
6534130561Sobrien
6535218822Sdim/* This is a pseudo-op of the form "adrl rd, label" to be converted
6536218822Sdim   into a relative address of the form:
6537218822Sdim   add rd, pc, #low(label-.-8)"
6538218822Sdim   add rd, rd, #high(label-.-8)"  */
6539218822Sdim
6540130561Sobrienstatic void
6541218822Sdimdo_adrl (void)
6542130561Sobrien{
6543218822Sdim  inst.instruction |= (inst.operands[0].reg << 12);  /* Rd */
6544130561Sobrien
6545218822Sdim  /* Frag hacking will turn this into a sub instruction if the offset turns
6546218822Sdim     out to be negative.  */
6547218822Sdim  inst.reloc.type	       = BFD_RELOC_ARM_ADRL_IMMEDIATE;
6548218822Sdim  inst.reloc.pc_rel	       = 1;
6549218822Sdim  inst.size		       = INSN_SIZE * 2;
6550218822Sdim  inst.reloc.exp.X_add_number -= 8;
6551130561Sobrien}
6552130561Sobrien
6553130561Sobrienstatic void
6554218822Sdimdo_arit (void)
6555130561Sobrien{
6556218822Sdim  if (!inst.operands[1].present)
6557218822Sdim    inst.operands[1].reg = inst.operands[0].reg;
6558218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6559218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
6560218822Sdim  encode_arm_shifter_operand (2);
6561130561Sobrien}
6562130561Sobrien
6563130561Sobrienstatic void
6564218822Sdimdo_barrier (void)
6565130561Sobrien{
6566218822Sdim  if (inst.operands[0].present)
6567130561Sobrien    {
6568218822Sdim      constraint ((inst.instruction & 0xf0) != 0x40
6569218822Sdim		  && inst.operands[0].imm != 0xf,
6570218822Sdim		  "bad barrier type");
6571218822Sdim      inst.instruction |= inst.operands[0].imm;
6572130561Sobrien    }
6573130561Sobrien  else
6574218822Sdim    inst.instruction |= 0xf;
6575130561Sobrien}
6576130561Sobrien
6577130561Sobrienstatic void
6578218822Sdimdo_bfc (void)
6579130561Sobrien{
6580218822Sdim  unsigned int msb = inst.operands[1].imm + inst.operands[2].imm;
6581218822Sdim  constraint (msb > 32, _("bit-field extends past end of register"));
6582218822Sdim  /* The instruction encoding stores the LSB and MSB,
6583218822Sdim     not the LSB and width.  */
6584218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6585218822Sdim  inst.instruction |= inst.operands[1].imm << 7;
6586218822Sdim  inst.instruction |= (msb - 1) << 16;
6587130561Sobrien}
6588130561Sobrien
6589130561Sobrienstatic void
6590218822Sdimdo_bfi (void)
6591130561Sobrien{
6592218822Sdim  unsigned int msb;
6593218822Sdim
6594218822Sdim  /* #0 in second position is alternative syntax for bfc, which is
6595218822Sdim     the same instruction but with REG_PC in the Rm field.  */
6596218822Sdim  if (!inst.operands[1].isreg)
6597218822Sdim    inst.operands[1].reg = REG_PC;
6598218822Sdim
6599218822Sdim  msb = inst.operands[2].imm + inst.operands[3].imm;
6600218822Sdim  constraint (msb > 32, _("bit-field extends past end of register"));
6601218822Sdim  /* The instruction encoding stores the LSB and MSB,
6602218822Sdim     not the LSB and width.  */
6603218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6604218822Sdim  inst.instruction |= inst.operands[1].reg;
6605218822Sdim  inst.instruction |= inst.operands[2].imm << 7;
6606218822Sdim  inst.instruction |= (msb - 1) << 16;
6607130561Sobrien}
6608130561Sobrien
6609130561Sobrienstatic void
6610218822Sdimdo_bfx (void)
6611130561Sobrien{
6612218822Sdim  constraint (inst.operands[2].imm + inst.operands[3].imm > 32,
6613218822Sdim	      _("bit-field extends past end of register"));
6614218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6615218822Sdim  inst.instruction |= inst.operands[1].reg;
6616218822Sdim  inst.instruction |= inst.operands[2].imm << 7;
6617218822Sdim  inst.instruction |= (inst.operands[3].imm - 1) << 16;
6618130561Sobrien}
6619130561Sobrien
6620218822Sdim/* ARM V5 breakpoint instruction (argument parse)
6621218822Sdim     BKPT <16 bit unsigned immediate>
6622218822Sdim     Instruction is not conditional.
6623218822Sdim	The bit pattern given in insns[] has the COND_ALWAYS condition,
6624218822Sdim	and it is an error if the caller tried to override that.  */
6625218822Sdim
6626130561Sobrienstatic void
6627218822Sdimdo_bkpt (void)
6628130561Sobrien{
6629218822Sdim  /* Top 12 of 16 bits to bits 19:8.  */
6630218822Sdim  inst.instruction |= (inst.operands[0].imm & 0xfff0) << 4;
6631130561Sobrien
6632218822Sdim  /* Bottom 4 of 16 bits to bits 3:0.  */
6633218822Sdim  inst.instruction |= inst.operands[0].imm & 0xf;
6634218822Sdim}
6635130561Sobrien
6636218822Sdimstatic void
6637218822Sdimencode_branch (int default_reloc)
6638218822Sdim{
6639218822Sdim  if (inst.operands[0].hasreloc)
6640218822Sdim    {
6641218822Sdim      constraint (inst.operands[0].imm != BFD_RELOC_ARM_PLT32,
6642218822Sdim		  _("the only suffix valid here is '(plt)'"));
6643218822Sdim      inst.reloc.type	= BFD_RELOC_ARM_PLT32;
6644218822Sdim    }
6645218822Sdim  else
6646218822Sdim    {
6647218822Sdim      inst.reloc.type = default_reloc;
6648218822Sdim    }
6649218822Sdim  inst.reloc.pc_rel = 1;
6650130561Sobrien}
6651130561Sobrien
6652130561Sobrienstatic void
6653218822Sdimdo_branch (void)
6654130561Sobrien{
6655218822Sdim#ifdef OBJ_ELF
6656218822Sdim  if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4)
6657218822Sdim    encode_branch (BFD_RELOC_ARM_PCREL_JUMP);
6658218822Sdim  else
6659218822Sdim#endif
6660218822Sdim    encode_branch (BFD_RELOC_ARM_PCREL_BRANCH);
6661218822Sdim}
6662130561Sobrien
6663218822Sdimstatic void
6664218822Sdimdo_bl (void)
6665218822Sdim{
6666218822Sdim#ifdef OBJ_ELF
6667218822Sdim  if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4)
6668218822Sdim    {
6669218822Sdim      if (inst.cond == COND_ALWAYS)
6670218822Sdim	encode_branch (BFD_RELOC_ARM_PCREL_CALL);
6671218822Sdim      else
6672218822Sdim	encode_branch (BFD_RELOC_ARM_PCREL_JUMP);
6673218822Sdim    }
6674218822Sdim  else
6675218822Sdim#endif
6676218822Sdim    encode_branch (BFD_RELOC_ARM_PCREL_BRANCH);
6677130561Sobrien}
6678130561Sobrien
6679218822Sdim/* ARM V5 branch-link-exchange instruction (argument parse)
6680218822Sdim     BLX <target_addr>		ie BLX(1)
6681218822Sdim     BLX{<condition>} <Rm>	ie BLX(2)
6682218822Sdim   Unfortunately, there are two different opcodes for this mnemonic.
6683218822Sdim   So, the insns[].value is not used, and the code here zaps values
6684218822Sdim	into inst.instruction.
6685218822Sdim   Also, the <target_addr> can be 25 bits, hence has its own reloc.  */
668677298Sobrien
668777298Sobrienstatic void
6688218822Sdimdo_blx (void)
668977298Sobrien{
6690218822Sdim  if (inst.operands[0].isreg)
6691218822Sdim    {
6692218822Sdim      /* Arg is a register; the opcode provided by insns[] is correct.
6693218822Sdim	 It is not illegal to do "blx pc", just useless.  */
6694218822Sdim      if (inst.operands[0].reg == REG_PC)
6695218822Sdim	as_tsktsk (_("use of r15 in blx in ARM mode is not really useful"));
669677298Sobrien
6697218822Sdim      inst.instruction |= inst.operands[0].reg;
6698218822Sdim    }
6699218822Sdim  else
6700218822Sdim    {
6701218822Sdim      /* Arg is an address; this instruction cannot be executed
6702218822Sdim	 conditionally, and the opcode must be adjusted.  */
6703218822Sdim      constraint (inst.cond != COND_ALWAYS, BAD_COND);
6704218822Sdim      inst.instruction = 0xfa000000;
6705218822Sdim#ifdef OBJ_ELF
6706218822Sdim      if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4)
6707218822Sdim	encode_branch (BFD_RELOC_ARM_PCREL_CALL);
6708218822Sdim      else
6709218822Sdim#endif
6710218822Sdim	encode_branch (BFD_RELOC_ARM_PCREL_BLX);
6711218822Sdim    }
6712218822Sdim}
671377298Sobrien
6714218822Sdimstatic void
6715218822Sdimdo_bx (void)
6716218822Sdim{
6717218822Sdim  if (inst.operands[0].reg == REG_PC)
6718218822Sdim    as_tsktsk (_("use of r15 in bx in ARM mode is not really useful"));
671977298Sobrien
6720218822Sdim  inst.instruction |= inst.operands[0].reg;
672177298Sobrien}
672277298Sobrien
672377298Sobrien
6724218822Sdim/* ARM v5TEJ.  Jump to Jazelle code.  */
672577298Sobrien
672677298Sobrienstatic void
6727218822Sdimdo_bxj (void)
672877298Sobrien{
6729218822Sdim  if (inst.operands[0].reg == REG_PC)
6730218822Sdim    as_tsktsk (_("use of r15 in bxj is not really useful"));
673177298Sobrien
6732218822Sdim  inst.instruction |= inst.operands[0].reg;
6733218822Sdim}
673477298Sobrien
6735218822Sdim/* Co-processor data operation:
6736218822Sdim      CDP{cond} <coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>{, <opcode_2>}
6737218822Sdim      CDP2	<coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>{, <opcode_2>}	 */
6738218822Sdimstatic void
6739218822Sdimdo_cdp (void)
6740218822Sdim{
6741218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
6742218822Sdim  inst.instruction |= inst.operands[1].imm << 20;
6743218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
6744218822Sdim  inst.instruction |= inst.operands[3].reg << 16;
6745218822Sdim  inst.instruction |= inst.operands[4].reg;
6746218822Sdim  inst.instruction |= inst.operands[5].imm << 5;
6747218822Sdim}
674877298Sobrien
6749218822Sdimstatic void
6750218822Sdimdo_cmp (void)
6751218822Sdim{
6752218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
6753218822Sdim  encode_arm_shifter_operand (1);
675477298Sobrien}
675577298Sobrien
6756218822Sdim/* Transfer between coprocessor and ARM registers.
6757218822Sdim   MRC{cond} <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>{, <opcode_2>}
6758218822Sdim   MRC2
6759218822Sdim   MCR{cond}
6760218822Sdim   MCR2
676177298Sobrien
6762218822Sdim   No special properties.  */
676377298Sobrien
676477298Sobrienstatic void
6765218822Sdimdo_co_reg (void)
676677298Sobrien{
6767218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
6768218822Sdim  inst.instruction |= inst.operands[1].imm << 21;
6769218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
6770218822Sdim  inst.instruction |= inst.operands[3].reg << 16;
6771218822Sdim  inst.instruction |= inst.operands[4].reg;
6772218822Sdim  inst.instruction |= inst.operands[5].imm << 5;
6773218822Sdim}
677477298Sobrien
6775218822Sdim/* Transfer between coprocessor register and pair of ARM registers.
6776218822Sdim   MCRR{cond} <coproc>, <opcode>, <Rd>, <Rn>, <CRm>.
6777218822Sdim   MCRR2
6778218822Sdim   MRRC{cond}
6779218822Sdim   MRRC2
678077298Sobrien
6781218822Sdim   Two XScale instructions are special cases of these:
678277298Sobrien
6783218822Sdim     MAR{cond} acc0, <RdLo>, <RdHi> == MCRR{cond} p0, #0, <RdLo>, <RdHi>, c0
6784218822Sdim     MRA{cond} acc0, <RdLo>, <RdHi> == MRRC{cond} p0, #0, <RdLo>, <RdHi>, c0
678577298Sobrien
6786218822Sdim   Result unpredicatable if Rd or Rn is R15.  */
678777298Sobrien
6788218822Sdimstatic void
6789218822Sdimdo_co_reg2c (void)
6790218822Sdim{
6791218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
6792218822Sdim  inst.instruction |= inst.operands[1].imm << 4;
6793218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
6794218822Sdim  inst.instruction |= inst.operands[3].reg << 16;
6795218822Sdim  inst.instruction |= inst.operands[4].reg;
6796218822Sdim}
679777298Sobrien
6798218822Sdimstatic void
6799218822Sdimdo_cpsi (void)
6800218822Sdim{
6801218822Sdim  inst.instruction |= inst.operands[0].imm << 6;
6802218822Sdim  if (inst.operands[1].present)
6803218822Sdim    {
6804218822Sdim      inst.instruction |= CPSI_MMOD;
6805218822Sdim      inst.instruction |= inst.operands[1].imm;
6806218822Sdim    }
680777298Sobrien}
680877298Sobrien
6809218822Sdimstatic void
6810218822Sdimdo_dbg (void)
6811218822Sdim{
6812218822Sdim  inst.instruction |= inst.operands[0].imm;
6813218822Sdim}
681477298Sobrien
6815218822Sdimstatic void
6816218822Sdimdo_it (void)
6817218822Sdim{
6818218822Sdim  /* There is no IT instruction in ARM mode.  We
6819218822Sdim     process it but do not generate code for it.  */
6820218822Sdim  inst.size = 0;
6821218822Sdim}
682277298Sobrien
682377298Sobrienstatic void
6824218822Sdimdo_ldmstm (void)
682577298Sobrien{
6826218822Sdim  int base_reg = inst.operands[0].reg;
6827218822Sdim  int range = inst.operands[1].imm;
682877298Sobrien
6829218822Sdim  inst.instruction |= base_reg << 16;
6830218822Sdim  inst.instruction |= range;
683177298Sobrien
6832218822Sdim  if (inst.operands[1].writeback)
6833218822Sdim    inst.instruction |= LDM_TYPE_2_OR_3;
683477298Sobrien
6835218822Sdim  if (inst.operands[0].writeback)
683677298Sobrien    {
6837218822Sdim      inst.instruction |= WRITE_BACK;
6838218822Sdim      /* Check for unpredictable uses of writeback.  */
6839218822Sdim      if (inst.instruction & LOAD_BIT)
684077298Sobrien	{
6841218822Sdim	  /* Not allowed in LDM type 2.	 */
6842218822Sdim	  if ((inst.instruction & LDM_TYPE_2_OR_3)
6843218822Sdim	      && ((range & (1 << REG_PC)) == 0))
6844218822Sdim	    as_warn (_("writeback of base register is UNPREDICTABLE"));
6845218822Sdim	  /* Only allowed if base reg not in list for other types.  */
6846218822Sdim	  else if (range & (1 << base_reg))
6847218822Sdim	    as_warn (_("writeback of base register when in register list is UNPREDICTABLE"));
684877298Sobrien	}
6849218822Sdim      else /* STM.  */
685077298Sobrien	{
6851218822Sdim	  /* Not allowed for type 2.  */
6852218822Sdim	  if (inst.instruction & LDM_TYPE_2_OR_3)
6853218822Sdim	    as_warn (_("writeback of base register is UNPREDICTABLE"));
6854218822Sdim	  /* Only allowed if base reg not in list, or first in list.  */
6855218822Sdim	  else if ((range & (1 << base_reg))
6856218822Sdim		   && (range & ((1 << base_reg) - 1)))
6857218822Sdim	    as_warn (_("if writeback register is in list, it must be the lowest reg in the list"));
685877298Sobrien	}
685977298Sobrien    }
6860218822Sdim}
686177298Sobrien
6862218822Sdim/* ARMv5TE load-consecutive (argument parse)
6863218822Sdim   Mode is like LDRH.
686477298Sobrien
6865218822Sdim     LDRccD R, mode
6866218822Sdim     STRccD R, mode.  */
686777298Sobrien
6868218822Sdimstatic void
6869218822Sdimdo_ldrd (void)
6870218822Sdim{
6871218822Sdim  constraint (inst.operands[0].reg % 2 != 0,
6872218822Sdim	      _("first destination register must be even"));
6873218822Sdim  constraint (inst.operands[1].present
6874218822Sdim	      && inst.operands[1].reg != inst.operands[0].reg + 1,
6875218822Sdim	      _("can only load two consecutive registers"));
6876218822Sdim  constraint (inst.operands[0].reg == REG_LR, _("r14 not allowed here"));
6877218822Sdim  constraint (!inst.operands[2].isreg, _("'[' expected"));
687877298Sobrien
6879218822Sdim  if (!inst.operands[1].present)
6880218822Sdim    inst.operands[1].reg = inst.operands[0].reg + 1;
6881218822Sdim
6882218822Sdim  if (inst.instruction & LOAD_BIT)
6883218822Sdim    {
6884218822Sdim      /* encode_arm_addr_mode_3 will diagnose overlap between the base
6885218822Sdim	 register and the first register written; we have to diagnose
6886218822Sdim	 overlap between the base and the second register written here.	 */
688777298Sobrien
6888218822Sdim      if (inst.operands[2].reg == inst.operands[1].reg
6889218822Sdim	  && (inst.operands[2].writeback || inst.operands[2].postind))
6890218822Sdim	as_warn (_("base register written back, and overlaps "
6891218822Sdim		   "second destination register"));
689277298Sobrien
6893218822Sdim      /* For an index-register load, the index register must not overlap the
6894218822Sdim	 destination (even if not write-back).	*/
6895218822Sdim      else if (inst.operands[2].immisreg
6896218822Sdim	       && ((unsigned) inst.operands[2].imm == inst.operands[0].reg
6897218822Sdim		   || (unsigned) inst.operands[2].imm == inst.operands[1].reg))
6898218822Sdim	as_warn (_("index register overlaps destination register"));
689977298Sobrien    }
690077298Sobrien
6901218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6902218822Sdim  encode_arm_addr_mode_3 (2, /*is_t=*/FALSE);
690377298Sobrien}
690477298Sobrien
6905218822Sdimstatic void
6906218822Sdimdo_ldrex (void)
6907218822Sdim{
6908218822Sdim  constraint (!inst.operands[1].isreg || !inst.operands[1].preind
6909218822Sdim	      || inst.operands[1].postind || inst.operands[1].writeback
6910218822Sdim	      || inst.operands[1].immisreg || inst.operands[1].shifted
6911218822Sdim	      || inst.operands[1].negative
6912218822Sdim	      /* This can arise if the programmer has written
6913218822Sdim		   strex rN, rM, foo
6914218822Sdim		 or if they have mistakenly used a register name as the last
6915218822Sdim		 operand,  eg:
6916218822Sdim		   strex rN, rM, rX
6917218822Sdim		 It is very difficult to distinguish between these two cases
6918218822Sdim		 because "rX" might actually be a label. ie the register
6919218822Sdim		 name has been occluded by a symbol of the same name. So we
6920218822Sdim		 just generate a general 'bad addressing mode' type error
6921218822Sdim		 message and leave it up to the programmer to discover the
6922218822Sdim		 true cause and fix their mistake.  */
6923218822Sdim	      || (inst.operands[1].reg == REG_PC),
6924218822Sdim	      BAD_ADDR_MODE);
692577298Sobrien
6926218822Sdim  constraint (inst.reloc.exp.X_op != O_constant
6927218822Sdim	      || inst.reloc.exp.X_add_number != 0,
6928218822Sdim	      _("offset must be zero in ARM encoding"));
692977298Sobrien
6930218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6931218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
6932218822Sdim  inst.reloc.type = BFD_RELOC_UNUSED;
6933218822Sdim}
6934218822Sdim
693577298Sobrienstatic void
6936218822Sdimdo_ldrexd (void)
693777298Sobrien{
6938218822Sdim  constraint (inst.operands[0].reg % 2 != 0,
6939218822Sdim	      _("even register required"));
6940218822Sdim  constraint (inst.operands[1].present
6941218822Sdim	      && inst.operands[1].reg != inst.operands[0].reg + 1,
6942218822Sdim	      _("can only load two consecutive registers"));
6943218822Sdim  /* If op 1 were present and equal to PC, this function wouldn't
6944218822Sdim     have been called in the first place.  */
6945218822Sdim  constraint (inst.operands[0].reg == REG_LR, _("r14 not allowed here"));
694677298Sobrien
6947218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6948218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
6949218822Sdim}
695077298Sobrien
6951218822Sdimstatic void
6952218822Sdimdo_ldst (void)
6953218822Sdim{
6954218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6955218822Sdim  if (!inst.operands[1].isreg)
6956218822Sdim    if (move_or_literal_pool (0, /*thumb_p=*/FALSE, /*mode_3=*/FALSE))
695777298Sobrien      return;
6958218822Sdim  encode_arm_addr_mode_2 (1, /*is_t=*/FALSE);
6959218822Sdim}
696077298Sobrien
6961218822Sdimstatic void
6962218822Sdimdo_ldstt (void)
6963218822Sdim{
6964218822Sdim  /* ldrt/strt always use post-indexed addressing.  Turn [Rn] into [Rn]! and
6965218822Sdim     reject [Rn,...].  */
6966218822Sdim  if (inst.operands[1].preind)
696777298Sobrien    {
6968218822Sdim      constraint (inst.reloc.exp.X_op != O_constant ||
6969218822Sdim		  inst.reloc.exp.X_add_number != 0,
6970218822Sdim		  _("this instruction requires a post-indexed address"));
697177298Sobrien
6972218822Sdim      inst.operands[1].preind = 0;
6973218822Sdim      inst.operands[1].postind = 1;
6974218822Sdim      inst.operands[1].writeback = 1;
697577298Sobrien    }
6976218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6977218822Sdim  encode_arm_addr_mode_2 (1, /*is_t=*/TRUE);
6978218822Sdim}
697977298Sobrien
6980218822Sdim/* Halfword and signed-byte load/store operations.  */
6981218822Sdim
6982218822Sdimstatic void
6983218822Sdimdo_ldstv4 (void)
6984218822Sdim{
6985218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
6986218822Sdim  if (!inst.operands[1].isreg)
6987218822Sdim    if (move_or_literal_pool (0, /*thumb_p=*/FALSE, /*mode_3=*/TRUE))
698877298Sobrien      return;
6989218822Sdim  encode_arm_addr_mode_3 (1, /*is_t=*/FALSE);
6990218822Sdim}
699177298Sobrien
6992218822Sdimstatic void
6993218822Sdimdo_ldsttv4 (void)
6994218822Sdim{
6995218822Sdim  /* ldrt/strt always use post-indexed addressing.  Turn [Rn] into [Rn]! and
6996218822Sdim     reject [Rn,...].  */
6997218822Sdim  if (inst.operands[1].preind)
699889857Sobrien    {
6999218822Sdim      constraint (inst.reloc.exp.X_op != O_constant ||
7000218822Sdim		  inst.reloc.exp.X_add_number != 0,
7001218822Sdim		  _("this instruction requires a post-indexed address"));
700289857Sobrien
7003218822Sdim      inst.operands[1].preind = 0;
7004218822Sdim      inst.operands[1].postind = 1;
7005218822Sdim      inst.operands[1].writeback = 1;
700689857Sobrien    }
7007218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7008218822Sdim  encode_arm_addr_mode_3 (1, /*is_t=*/TRUE);
7009218822Sdim}
701089857Sobrien
7011218822Sdim/* Co-processor register load/store.
7012218822Sdim   Format: <LDC|STC>{cond}[L] CP#,CRd,<address>	 */
7013218822Sdimstatic void
7014218822Sdimdo_lstc (void)
7015218822Sdim{
7016218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
7017218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
7018218822Sdim  encode_arm_cp_address (2, TRUE, TRUE, 0);
701977298Sobrien}
702077298Sobrien
7021218822Sdimstatic void
7022218822Sdimdo_mlas (void)
702360484Sobrien{
7024218822Sdim  /* This restriction does not apply to mls (nor to mla in v6 or later).  */
7025218822Sdim  if (inst.operands[0].reg == inst.operands[1].reg
7026218822Sdim      && !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6)
7027218822Sdim      && !(inst.instruction & 0x00400000))
7028218822Sdim    as_tsktsk (_("Rd and Rm should be different in mla"));
702960484Sobrien
7030218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7031218822Sdim  inst.instruction |= inst.operands[1].reg;
7032218822Sdim  inst.instruction |= inst.operands[2].reg << 8;
7033218822Sdim  inst.instruction |= inst.operands[3].reg << 12;
7034218822Sdim}
703577298Sobrien
7036218822Sdimstatic void
7037218822Sdimdo_mov (void)
7038218822Sdim{
7039218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7040218822Sdim  encode_arm_shifter_operand (1);
7041218822Sdim}
704260484Sobrien
7043218822Sdim/* ARM V6T2 16-bit immediate register load: MOV[WT]{cond} Rd, #<imm16>.	 */
7044218822Sdimstatic void
7045218822Sdimdo_mov16 (void)
7046218822Sdim{
7047218822Sdim  bfd_vma imm;
7048218822Sdim  bfd_boolean top;
704960484Sobrien
7050218822Sdim  top = (inst.instruction & 0x00400000) != 0;
7051218822Sdim  constraint (top && inst.reloc.type == BFD_RELOC_ARM_MOVW,
7052218822Sdim	      _(":lower16: not allowed this instruction"));
7053218822Sdim  constraint (!top && inst.reloc.type == BFD_RELOC_ARM_MOVT,
7054218822Sdim	      _(":upper16: not allowed instruction"));
7055218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7056218822Sdim  if (inst.reloc.type == BFD_RELOC_UNUSED)
705760484Sobrien    {
7058218822Sdim      imm = inst.reloc.exp.X_add_number;
7059218822Sdim      /* The value is in two pieces: 0:11, 16:19.  */
7060218822Sdim      inst.instruction |= (imm & 0x00000fff);
7061218822Sdim      inst.instruction |= (imm & 0x0000f000) << 4;
706260484Sobrien    }
706360484Sobrien}
706460484Sobrien
7065218822Sdimstatic void do_vfp_nsyn_opcode (const char *);
706677298Sobrien
706760484Sobrienstatic int
7068218822Sdimdo_vfp_nsyn_mrs (void)
706960484Sobrien{
7070218822Sdim  if (inst.operands[0].isvec)
707160484Sobrien    {
7072218822Sdim      if (inst.operands[1].reg != 1)
7073218822Sdim        first_error (_("operand 1 must be FPSCR"));
7074218822Sdim      memset (&inst.operands[0], '\0', sizeof (inst.operands[0]));
7075218822Sdim      memset (&inst.operands[1], '\0', sizeof (inst.operands[1]));
7076218822Sdim      do_vfp_nsyn_opcode ("fmstat");
707760484Sobrien    }
7078218822Sdim  else if (inst.operands[1].isvec)
7079218822Sdim    do_vfp_nsyn_opcode ("fmrx");
7080218822Sdim  else
7081218822Sdim    return FAIL;
7082218822Sdim
7083218822Sdim  return SUCCESS;
708460484Sobrien}
708560484Sobrien
708660484Sobrienstatic int
7087218822Sdimdo_vfp_nsyn_msr (void)
708860484Sobrien{
7089218822Sdim  if (inst.operands[0].isvec)
7090218822Sdim    do_vfp_nsyn_opcode ("fmxr");
7091218822Sdim  else
7092218822Sdim    return FAIL;
709377298Sobrien
7094218822Sdim  return SUCCESS;
7095218822Sdim}
709660484Sobrien
7097218822Sdimstatic void
7098218822Sdimdo_mrs (void)
7099218822Sdim{
7100218822Sdim  if (do_vfp_nsyn_mrs () == SUCCESS)
7101218822Sdim    return;
710289857Sobrien
7103218822Sdim  /* mrs only accepts CPSR/SPSR/CPSR_all/SPSR_all.  */
7104218822Sdim  constraint ((inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f))
7105218822Sdim	      != (PSR_c|PSR_f),
7106218822Sdim	      _("'CPSR' or 'SPSR' expected"));
7107218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7108218822Sdim  inst.instruction |= (inst.operands[1].imm & SPSR_BIT);
7109218822Sdim}
711060484Sobrien
7111218822Sdim/* Two possible forms:
7112218822Sdim      "{C|S}PSR_<field>, Rm",
7113218822Sdim      "{C|S}PSR_f, #expression".  */
7114218822Sdim
7115218822Sdimstatic void
7116218822Sdimdo_msr (void)
7117218822Sdim{
7118218822Sdim  if (do_vfp_nsyn_msr () == SUCCESS)
7119218822Sdim    return;
7120218822Sdim
7121218822Sdim  inst.instruction |= inst.operands[0].imm;
7122218822Sdim  if (inst.operands[1].isreg)
7123218822Sdim    inst.instruction |= inst.operands[1].reg;
7124218822Sdim  else
712560484Sobrien    {
7126218822Sdim      inst.instruction |= INST_IMMEDIATE;
7127218822Sdim      inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
7128218822Sdim      inst.reloc.pc_rel = 0;
712960484Sobrien    }
713060484Sobrien}
713160484Sobrien
7132218822Sdimstatic void
7133218822Sdimdo_mul (void)
713489857Sobrien{
7135218822Sdim  if (!inst.operands[2].present)
7136218822Sdim    inst.operands[2].reg = inst.operands[0].reg;
7137218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7138218822Sdim  inst.instruction |= inst.operands[1].reg;
7139218822Sdim  inst.instruction |= inst.operands[2].reg << 8;
7140218822Sdim
7141218822Sdim  if (inst.operands[0].reg == inst.operands[1].reg
7142218822Sdim      && !ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v6))
7143218822Sdim    as_tsktsk (_("Rd and Rm should be different in mul"));
714489857Sobrien}
714589857Sobrien
7146218822Sdim/* Long Multiply Parser
7147218822Sdim   UMULL RdLo, RdHi, Rm, Rs
7148218822Sdim   SMULL RdLo, RdHi, Rm, Rs
7149218822Sdim   UMLAL RdLo, RdHi, Rm, Rs
7150218822Sdim   SMLAL RdLo, RdHi, Rm, Rs.  */
715160484Sobrien
7152218822Sdimstatic void
7153218822Sdimdo_mull (void)
715460484Sobrien{
7155218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7156218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7157218822Sdim  inst.instruction |= inst.operands[2].reg;
7158218822Sdim  inst.instruction |= inst.operands[3].reg << 8;
715977298Sobrien
7160218822Sdim  /* rdhi, rdlo and rm must all be different.  */
7161218822Sdim  if (inst.operands[0].reg == inst.operands[1].reg
7162218822Sdim      || inst.operands[0].reg == inst.operands[2].reg
7163218822Sdim      || inst.operands[1].reg == inst.operands[2].reg)
7164218822Sdim    as_tsktsk (_("rdhi, rdlo and rm must all be different"));
7165218822Sdim}
716677298Sobrien
7167218822Sdimstatic void
7168218822Sdimdo_nop (void)
7169218822Sdim{
7170218822Sdim  if (inst.operands[0].present)
717160484Sobrien    {
7172218822Sdim      /* Architectural NOP hints are CPSR sets with no bits selected.  */
7173218822Sdim      inst.instruction &= 0xf0000000;
7174218822Sdim      inst.instruction |= 0x0320f000 + inst.operands[0].imm;
717560484Sobrien    }
7176218822Sdim}
717760484Sobrien
7178218822Sdim/* ARM V6 Pack Halfword Bottom Top instruction (argument parse).
7179218822Sdim   PKHBT {<cond>} <Rd>, <Rn>, <Rm> {, LSL #<shift_imm>}
7180218822Sdim   Condition defaults to COND_ALWAYS.
7181218822Sdim   Error if Rd, Rn or Rm are R15.  */
718277298Sobrien
7183218822Sdimstatic void
7184218822Sdimdo_pkhbt (void)
7185218822Sdim{
7186218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7187218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7188218822Sdim  inst.instruction |= inst.operands[2].reg;
7189218822Sdim  if (inst.operands[3].present)
7190218822Sdim    encode_arm_shift (3);
7191218822Sdim}
719260484Sobrien
7193218822Sdim/* ARM V6 PKHTB (Argument Parse).  */
719460484Sobrien
7195218822Sdimstatic void
7196218822Sdimdo_pkhtb (void)
7197218822Sdim{
7198218822Sdim  if (!inst.operands[3].present)
7199130561Sobrien    {
7200218822Sdim      /* If the shift specifier is omitted, turn the instruction
7201218822Sdim	 into pkhbt rd, rm, rn. */
7202218822Sdim      inst.instruction &= 0xfff00010;
7203218822Sdim      inst.instruction |= inst.operands[0].reg << 12;
7204218822Sdim      inst.instruction |= inst.operands[1].reg;
7205218822Sdim      inst.instruction |= inst.operands[2].reg << 16;
7206130561Sobrien    }
7207218822Sdim  else
7208130561Sobrien    {
7209218822Sdim      inst.instruction |= inst.operands[0].reg << 12;
7210218822Sdim      inst.instruction |= inst.operands[1].reg << 16;
7211218822Sdim      inst.instruction |= inst.operands[2].reg;
7212218822Sdim      encode_arm_shift (3);
7213130561Sobrien    }
7214218822Sdim}
721560484Sobrien
7216218822Sdim/* ARMv5TE: Preload-Cache
721760484Sobrien
7218218822Sdim    PLD <addr_mode>
721960484Sobrien
7220218822Sdim  Syntactically, like LDR with B=1, W=0, L=1.  */
722160484Sobrien
7222218822Sdimstatic void
7223218822Sdimdo_pld (void)
7224218822Sdim{
7225218822Sdim  constraint (!inst.operands[0].isreg,
7226218822Sdim	      _("'[' expected after PLD mnemonic"));
7227218822Sdim  constraint (inst.operands[0].postind,
7228218822Sdim	      _("post-indexed expression used in preload instruction"));
7229218822Sdim  constraint (inst.operands[0].writeback,
7230218822Sdim	      _("writeback used in preload instruction"));
7231218822Sdim  constraint (!inst.operands[0].preind,
7232218822Sdim	      _("unindexed addressing used in preload instruction"));
7233218822Sdim  encode_arm_addr_mode_2 (0, /*is_t=*/FALSE);
7234218822Sdim}
723560484Sobrien
7236218822Sdim/* ARMv7: PLI <addr_mode>  */
7237218822Sdimstatic void
7238218822Sdimdo_pli (void)
7239218822Sdim{
7240218822Sdim  constraint (!inst.operands[0].isreg,
7241218822Sdim	      _("'[' expected after PLI mnemonic"));
7242218822Sdim  constraint (inst.operands[0].postind,
7243218822Sdim	      _("post-indexed expression used in preload instruction"));
7244218822Sdim  constraint (inst.operands[0].writeback,
7245218822Sdim	      _("writeback used in preload instruction"));
7246218822Sdim  constraint (!inst.operands[0].preind,
7247218822Sdim	      _("unindexed addressing used in preload instruction"));
7248218822Sdim  encode_arm_addr_mode_2 (0, /*is_t=*/FALSE);
7249218822Sdim  inst.instruction &= ~PRE_INDEX;
7250218822Sdim}
725177298Sobrien
7252218822Sdimstatic void
7253218822Sdimdo_push_pop (void)
7254218822Sdim{
7255218822Sdim  inst.operands[1] = inst.operands[0];
7256218822Sdim  memset (&inst.operands[0], 0, sizeof inst.operands[0]);
7257218822Sdim  inst.operands[0].isreg = 1;
7258218822Sdim  inst.operands[0].writeback = 1;
7259218822Sdim  inst.operands[0].reg = REG_SP;
7260218822Sdim  do_ldmstm ();
7261218822Sdim}
726277298Sobrien
7263218822Sdim/* ARM V6 RFE (Return from Exception) loads the PC and CPSR from the
7264218822Sdim   word at the specified address and the following word
7265218822Sdim   respectively.
7266218822Sdim   Unconditionally executed.
7267218822Sdim   Error if Rn is R15.	*/
726877298Sobrien
7269218822Sdimstatic void
7270218822Sdimdo_rfe (void)
7271218822Sdim{
7272218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7273218822Sdim  if (inst.operands[0].writeback)
7274218822Sdim    inst.instruction |= WRITE_BACK;
727560484Sobrien}
727660484Sobrien
7277218822Sdim/* ARM V6 ssat (argument parse).  */
727877298Sobrien
7279218822Sdimstatic void
7280218822Sdimdo_ssat (void)
728160484Sobrien{
7282218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7283218822Sdim  inst.instruction |= (inst.operands[1].imm - 1) << 16;
7284218822Sdim  inst.instruction |= inst.operands[2].reg;
728560484Sobrien
7286218822Sdim  if (inst.operands[3].present)
7287218822Sdim    encode_arm_shift (3);
7288218822Sdim}
728960484Sobrien
7290218822Sdim/* ARM V6 usat (argument parse).  */
729160484Sobrien
7292218822Sdimstatic void
7293218822Sdimdo_usat (void)
7294218822Sdim{
7295218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7296218822Sdim  inst.instruction |= inst.operands[1].imm << 16;
7297218822Sdim  inst.instruction |= inst.operands[2].reg;
729860484Sobrien
7299218822Sdim  if (inst.operands[3].present)
7300218822Sdim    encode_arm_shift (3);
7301218822Sdim}
730260484Sobrien
7303218822Sdim/* ARM V6 ssat16 (argument parse).  */
730460484Sobrien
7305218822Sdimstatic void
7306218822Sdimdo_ssat16 (void)
7307218822Sdim{
7308218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7309218822Sdim  inst.instruction |= ((inst.operands[1].imm - 1) << 16);
7310218822Sdim  inst.instruction |= inst.operands[2].reg;
7311218822Sdim}
731260484Sobrien
7313218822Sdimstatic void
7314218822Sdimdo_usat16 (void)
7315218822Sdim{
7316218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7317218822Sdim  inst.instruction |= inst.operands[1].imm << 16;
7318218822Sdim  inst.instruction |= inst.operands[2].reg;
7319218822Sdim}
732060484Sobrien
7321218822Sdim/* ARM V6 SETEND (argument parse).  Sets the E bit in the CPSR while
7322218822Sdim   preserving the other bits.
732360484Sobrien
7324218822Sdim   setend <endian_specifier>, where <endian_specifier> is either
7325218822Sdim   BE or LE.  */
732660484Sobrien
7327218822Sdimstatic void
7328218822Sdimdo_setend (void)
7329218822Sdim{
7330218822Sdim  if (inst.operands[0].imm)
7331218822Sdim    inst.instruction |= 0x200;
7332218822Sdim}
733360484Sobrien
7334218822Sdimstatic void
7335218822Sdimdo_shift (void)
7336218822Sdim{
7337218822Sdim  unsigned int Rm = (inst.operands[1].present
7338218822Sdim		     ? inst.operands[1].reg
7339218822Sdim		     : inst.operands[0].reg);
734060484Sobrien
7341218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7342218822Sdim  inst.instruction |= Rm;
7343218822Sdim  if (inst.operands[2].isreg)  /* Rd, {Rm,} Rs */
7344218822Sdim    {
7345218822Sdim      inst.instruction |= inst.operands[2].reg << 8;
7346218822Sdim      inst.instruction |= SHIFT_BY_REG;
734760484Sobrien    }
7348218822Sdim  else
7349218822Sdim    inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
7350218822Sdim}
735160484Sobrien
7352218822Sdimstatic void
7353218822Sdimdo_smc (void)
7354218822Sdim{
7355218822Sdim  inst.reloc.type = BFD_RELOC_ARM_SMC;
7356218822Sdim  inst.reloc.pc_rel = 0;
7357218822Sdim}
735860484Sobrien
7359218822Sdimstatic void
7360218822Sdimdo_swi (void)
7361218822Sdim{
7362218822Sdim  inst.reloc.type = BFD_RELOC_ARM_SWI;
7363218822Sdim  inst.reloc.pc_rel = 0;
736460484Sobrien}
736560484Sobrien
7366218822Sdim/* ARM V5E (El Segundo) signed-multiply-accumulate (argument parse)
7367218822Sdim   SMLAxy{cond} Rd,Rm,Rs,Rn
7368218822Sdim   SMLAWy{cond} Rd,Rm,Rs,Rn
7369218822Sdim   Error if any register is R15.  */
7370218822Sdim
7371218822Sdimstatic void
7372218822Sdimdo_smla (void)
737360484Sobrien{
7374218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7375218822Sdim  inst.instruction |= inst.operands[1].reg;
7376218822Sdim  inst.instruction |= inst.operands[2].reg << 8;
7377218822Sdim  inst.instruction |= inst.operands[3].reg << 12;
7378218822Sdim}
737960484Sobrien
7380218822Sdim/* ARM V5E (El Segundo) signed-multiply-accumulate-long (argument parse)
7381218822Sdim   SMLALxy{cond} Rdlo,Rdhi,Rm,Rs
7382218822Sdim   Error if any register is R15.
7383218822Sdim   Warning if Rdlo == Rdhi.  */
738477298Sobrien
7385218822Sdimstatic void
7386218822Sdimdo_smlal (void)
7387218822Sdim{
7388218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7389218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7390218822Sdim  inst.instruction |= inst.operands[2].reg;
7391218822Sdim  inst.instruction |= inst.operands[3].reg << 8;
7392218822Sdim
7393218822Sdim  if (inst.operands[0].reg == inst.operands[1].reg)
7394218822Sdim    as_tsktsk (_("rdhi and rdlo must be different"));
7395218822Sdim}
7396218822Sdim
7397218822Sdim/* ARM V5E (El Segundo) signed-multiply (argument parse)
7398218822Sdim   SMULxy{cond} Rd,Rm,Rs
7399218822Sdim   Error if any register is R15.  */
7400218822Sdim
7401218822Sdimstatic void
7402218822Sdimdo_smul (void)
7403218822Sdim{
7404218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7405218822Sdim  inst.instruction |= inst.operands[1].reg;
7406218822Sdim  inst.instruction |= inst.operands[2].reg << 8;
7407218822Sdim}
7408218822Sdim
7409218822Sdim/* ARM V6 srs (argument parse).  The variable fields in the encoding are
7410218822Sdim   the same for both ARM and Thumb-2.  */
7411218822Sdim
7412218822Sdimstatic void
7413218822Sdimdo_srs (void)
7414218822Sdim{
7415218822Sdim  int reg;
7416218822Sdim
7417218822Sdim  if (inst.operands[0].present)
741860484Sobrien    {
7419218822Sdim      reg = inst.operands[0].reg;
7420218822Sdim      constraint (reg != 13, _("SRS base register must be r13"));
742160484Sobrien    }
742260484Sobrien  else
7423218822Sdim    reg = 13;
742477298Sobrien
7425218822Sdim  inst.instruction |= reg << 16;
7426218822Sdim  inst.instruction |= inst.operands[1].imm;
7427218822Sdim  if (inst.operands[0].writeback || inst.operands[1].writeback)
7428218822Sdim    inst.instruction |= WRITE_BACK;
7429218822Sdim}
743060484Sobrien
7431218822Sdim/* ARM V6 strex (argument parse).  */
743260484Sobrien
7433218822Sdimstatic void
7434218822Sdimdo_strex (void)
7435218822Sdim{
7436218822Sdim  constraint (!inst.operands[2].isreg || !inst.operands[2].preind
7437218822Sdim	      || inst.operands[2].postind || inst.operands[2].writeback
7438218822Sdim	      || inst.operands[2].immisreg || inst.operands[2].shifted
7439218822Sdim	      || inst.operands[2].negative
7440218822Sdim	      /* See comment in do_ldrex().  */
7441218822Sdim	      || (inst.operands[2].reg == REG_PC),
7442218822Sdim	      BAD_ADDR_MODE);
744377298Sobrien
7444218822Sdim  constraint (inst.operands[0].reg == inst.operands[1].reg
7445218822Sdim	      || inst.operands[0].reg == inst.operands[2].reg, BAD_OVERLAP);
744660484Sobrien
7447218822Sdim  constraint (inst.reloc.exp.X_op != O_constant
7448218822Sdim	      || inst.reloc.exp.X_add_number != 0,
7449218822Sdim	      _("offset must be zero in ARM encoding"));
745060484Sobrien
7451218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7452218822Sdim  inst.instruction |= inst.operands[1].reg;
7453218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
7454218822Sdim  inst.reloc.type = BFD_RELOC_UNUSED;
7455218822Sdim}
745660484Sobrien
7457218822Sdimstatic void
7458218822Sdimdo_strexd (void)
7459218822Sdim{
7460218822Sdim  constraint (inst.operands[1].reg % 2 != 0,
7461218822Sdim	      _("even register required"));
7462218822Sdim  constraint (inst.operands[2].present
7463218822Sdim	      && inst.operands[2].reg != inst.operands[1].reg + 1,
7464218822Sdim	      _("can only store two consecutive registers"));
7465218822Sdim  /* If op 2 were present and equal to PC, this function wouldn't
7466218822Sdim     have been called in the first place.  */
7467218822Sdim  constraint (inst.operands[1].reg == REG_LR, _("r14 not allowed here"));
746860484Sobrien
7469218822Sdim  constraint (inst.operands[0].reg == inst.operands[1].reg
7470218822Sdim	      || inst.operands[0].reg == inst.operands[1].reg + 1
7471218822Sdim	      || inst.operands[0].reg == inst.operands[3].reg,
7472218822Sdim	      BAD_OVERLAP);
747360484Sobrien
7474218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7475218822Sdim  inst.instruction |= inst.operands[1].reg;
7476218822Sdim  inst.instruction |= inst.operands[3].reg << 16;
747760484Sobrien}
747860484Sobrien
7479218822Sdim/* ARM V6 SXTAH extracts a 16-bit value from a register, sign
7480218822Sdim   extends it to 32-bits, and adds the result to a value in another
7481218822Sdim   register.  You can specify a rotation by 0, 8, 16, or 24 bits
7482218822Sdim   before extracting the 16-bit value.
7483218822Sdim   SXTAH{<cond>} <Rd>, <Rn>, <Rm>{, <rotation>}
7484218822Sdim   Condition defaults to COND_ALWAYS.
7485218822Sdim   Error if any register uses R15.  */
7486218822Sdim
7487218822Sdimstatic void
7488218822Sdimdo_sxtah (void)
748960484Sobrien{
7490218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7491218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7492218822Sdim  inst.instruction |= inst.operands[2].reg;
7493218822Sdim  inst.instruction |= inst.operands[3].imm << 10;
7494218822Sdim}
749560484Sobrien
7496218822Sdim/* ARM V6 SXTH.
749760484Sobrien
7498218822Sdim   SXTH {<cond>} <Rd>, <Rm>{, <rotation>}
7499218822Sdim   Condition defaults to COND_ALWAYS.
7500218822Sdim   Error if any register uses R15.  */
750160484Sobrien
7502218822Sdimstatic void
7503218822Sdimdo_sxth (void)
7504218822Sdim{
7505218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7506218822Sdim  inst.instruction |= inst.operands[1].reg;
7507218822Sdim  inst.instruction |= inst.operands[2].imm << 10;
7508218822Sdim}
7509218822Sdim
7510218822Sdim/* VFP instructions.  In a logical order: SP variant first, monad
7511218822Sdim   before dyad, arithmetic then move then load/store.  */
751260484Sobrien
7513218822Sdimstatic void
7514218822Sdimdo_vfp_sp_monadic (void)
7515218822Sdim{
7516218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7517218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sm);
7518218822Sdim}
751960484Sobrien
7520218822Sdimstatic void
7521218822Sdimdo_vfp_sp_dyadic (void)
7522218822Sdim{
7523218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7524218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sn);
7525218822Sdim  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Sm);
7526218822Sdim}
752760484Sobrien
7528218822Sdimstatic void
7529218822Sdimdo_vfp_sp_compare_z (void)
7530218822Sdim{
7531218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7532218822Sdim}
753360484Sobrien
7534218822Sdimstatic void
7535218822Sdimdo_vfp_dp_sp_cvt (void)
7536218822Sdim{
7537218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7538218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sm);
7539218822Sdim}
754060484Sobrien
7541218822Sdimstatic void
7542218822Sdimdo_vfp_sp_dp_cvt (void)
7543218822Sdim{
7544218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7545218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dm);
754660484Sobrien}
754760484Sobrien
754860484Sobrienstatic void
7549218822Sdimdo_vfp_reg_from_sp (void)
755060484Sobrien{
7551218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7552218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sn);
7553218822Sdim}
755460484Sobrien
7555218822Sdimstatic void
7556218822Sdimdo_vfp_reg2_from_sp2 (void)
7557218822Sdim{
7558218822Sdim  constraint (inst.operands[2].imm != 2,
7559218822Sdim	      _("only two consecutive VFP SP registers allowed here"));
7560218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7561218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7562218822Sdim  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Sm);
7563218822Sdim}
756460484Sobrien
7565218822Sdimstatic void
7566218822Sdimdo_vfp_sp_from_reg (void)
7567218822Sdim{
7568218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sn);
7569218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
757060484Sobrien}
757160484Sobrien
757260484Sobrienstatic void
7573218822Sdimdo_vfp_sp2_from_reg2 (void)
757460484Sobrien{
7575218822Sdim  constraint (inst.operands[0].imm != 2,
7576218822Sdim	      _("only two consecutive VFP SP registers allowed here"));
7577218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sm);
7578218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
7579218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
7580218822Sdim}
758160484Sobrien
7582218822Sdimstatic void
7583218822Sdimdo_vfp_sp_ldst (void)
7584218822Sdim{
7585218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7586218822Sdim  encode_arm_cp_address (1, FALSE, TRUE, 0);
7587218822Sdim}
758877298Sobrien
7589218822Sdimstatic void
7590218822Sdimdo_vfp_dp_ldst (void)
7591218822Sdim{
7592218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7593218822Sdim  encode_arm_cp_address (1, FALSE, TRUE, 0);
7594218822Sdim}
759577298Sobrien
7596218822Sdim
7597218822Sdimstatic void
7598218822Sdimvfp_sp_ldstm (enum vfp_ldstm_type ldstm_type)
7599218822Sdim{
7600218822Sdim  if (inst.operands[0].writeback)
7601218822Sdim    inst.instruction |= WRITE_BACK;
7602218822Sdim  else
7603218822Sdim    constraint (ldstm_type != VFP_LDSTMIA,
7604218822Sdim		_("this addressing mode requires base-register writeback"));
7605218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7606218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Sd);
7607218822Sdim  inst.instruction |= inst.operands[1].imm;
760860484Sobrien}
760960484Sobrien
761060484Sobrienstatic void
7611218822Sdimvfp_dp_ldstm (enum vfp_ldstm_type ldstm_type)
761260484Sobrien{
7613218822Sdim  int count;
761460484Sobrien
7615218822Sdim  if (inst.operands[0].writeback)
7616218822Sdim    inst.instruction |= WRITE_BACK;
7617218822Sdim  else
7618218822Sdim    constraint (ldstm_type != VFP_LDSTMIA && ldstm_type != VFP_LDSTMIAX,
7619218822Sdim		_("this addressing mode requires base-register writeback"));
762060484Sobrien
7621218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7622218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dd);
762389857Sobrien
7624218822Sdim  count = inst.operands[1].imm << 1;
7625218822Sdim  if (ldstm_type == VFP_LDSTMIAX || ldstm_type == VFP_LDSTMDBX)
7626218822Sdim    count += 1;
762777298Sobrien
7628218822Sdim  inst.instruction |= count;
762960484Sobrien}
763060484Sobrien
763160484Sobrienstatic void
7632218822Sdimdo_vfp_sp_ldstmia (void)
763360484Sobrien{
7634218822Sdim  vfp_sp_ldstm (VFP_LDSTMIA);
7635218822Sdim}
763660484Sobrien
7637218822Sdimstatic void
7638218822Sdimdo_vfp_sp_ldstmdb (void)
7639218822Sdim{
7640218822Sdim  vfp_sp_ldstm (VFP_LDSTMDB);
7641218822Sdim}
764260484Sobrien
7643218822Sdimstatic void
7644218822Sdimdo_vfp_dp_ldstmia (void)
7645218822Sdim{
7646218822Sdim  vfp_dp_ldstm (VFP_LDSTMIA);
7647218822Sdim}
764860484Sobrien
7649218822Sdimstatic void
7650218822Sdimdo_vfp_dp_ldstmdb (void)
7651218822Sdim{
7652218822Sdim  vfp_dp_ldstm (VFP_LDSTMDB);
765360484Sobrien}
765460484Sobrien
765560484Sobrienstatic void
7656218822Sdimdo_vfp_xp_ldstmia (void)
765760484Sobrien{
7658218822Sdim  vfp_dp_ldstm (VFP_LDSTMIAX);
7659218822Sdim}
766060484Sobrien
7661218822Sdimstatic void
7662218822Sdimdo_vfp_xp_ldstmdb (void)
7663218822Sdim{
7664218822Sdim  vfp_dp_ldstm (VFP_LDSTMDBX);
7665218822Sdim}
766660484Sobrien
7667218822Sdimstatic void
7668218822Sdimdo_vfp_dp_rd_rm (void)
7669218822Sdim{
7670218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7671218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dm);
7672218822Sdim}
767360484Sobrien
7674218822Sdimstatic void
7675218822Sdimdo_vfp_dp_rn_rd (void)
7676218822Sdim{
7677218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dn);
7678218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dd);
767960484Sobrien}
768060484Sobrien
7681218822Sdimstatic void
7682218822Sdimdo_vfp_dp_rd_rn (void)
768360484Sobrien{
7684218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7685218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dn);
7686218822Sdim}
768760484Sobrien
7688218822Sdimstatic void
7689218822Sdimdo_vfp_dp_rd_rn_rm (void)
7690218822Sdim{
7691218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7692218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dn);
7693218822Sdim  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Dm);
7694218822Sdim}
769560484Sobrien
7696218822Sdimstatic void
7697218822Sdimdo_vfp_dp_rd (void)
7698218822Sdim{
7699218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7700218822Sdim}
770160484Sobrien
7702218822Sdimstatic void
7703218822Sdimdo_vfp_dp_rm_rd_rn (void)
7704218822Sdim{
7705218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dm);
7706218822Sdim  encode_arm_vfp_reg (inst.operands[1].reg, VFP_REG_Dd);
7707218822Sdim  encode_arm_vfp_reg (inst.operands[2].reg, VFP_REG_Dn);
7708218822Sdim}
770960484Sobrien
7710218822Sdim/* VFPv3 instructions.  */
7711218822Sdimstatic void
7712218822Sdimdo_vfp_sp_const (void)
7713218822Sdim{
7714218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7715218822Sdim  inst.instruction |= (inst.operands[1].imm & 0xf0) << 12;
7716218822Sdim  inst.instruction |= (inst.operands[1].imm & 0x0f);
7717218822Sdim}
771860484Sobrien
7719218822Sdimstatic void
7720218822Sdimdo_vfp_dp_const (void)
7721218822Sdim{
7722218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7723218822Sdim  inst.instruction |= (inst.operands[1].imm & 0xf0) << 12;
7724218822Sdim  inst.instruction |= (inst.operands[1].imm & 0x0f);
7725218822Sdim}
772660484Sobrien
7727218822Sdimstatic void
7728218822Sdimvfp_conv (int srcsize)
7729218822Sdim{
7730218822Sdim  unsigned immbits = srcsize - inst.operands[1].imm;
7731218822Sdim  inst.instruction |= (immbits & 1) << 5;
7732218822Sdim  inst.instruction |= (immbits >> 1);
7733218822Sdim}
773477298Sobrien
7735218822Sdimstatic void
7736218822Sdimdo_vfp_sp_conv_16 (void)
7737218822Sdim{
7738218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7739218822Sdim  vfp_conv (16);
7740218822Sdim}
774177298Sobrien
7742218822Sdimstatic void
7743218822Sdimdo_vfp_dp_conv_16 (void)
7744218822Sdim{
7745218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7746218822Sdim  vfp_conv (16);
7747218822Sdim}
774860484Sobrien
7749218822Sdimstatic void
7750218822Sdimdo_vfp_sp_conv_32 (void)
7751218822Sdim{
7752218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Sd);
7753218822Sdim  vfp_conv (32);
775460484Sobrien}
775560484Sobrien
775660484Sobrienstatic void
7757218822Sdimdo_vfp_dp_conv_32 (void)
775860484Sobrien{
7759218822Sdim  encode_arm_vfp_reg (inst.operands[0].reg, VFP_REG_Dd);
7760218822Sdim  vfp_conv (32);
7761218822Sdim}
776260484Sobrien
7763218822Sdim
7764218822Sdim/* FPA instructions.  Also in a logical order.	*/
776589857Sobrien
7766218822Sdimstatic void
7767218822Sdimdo_fpa_cmp (void)
7768218822Sdim{
7769218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7770218822Sdim  inst.instruction |= inst.operands[1].reg;
7771218822Sdim}
777289857Sobrien
7773218822Sdimstatic void
7774218822Sdimdo_fpa_ldmstm (void)
7775218822Sdim{
7776218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7777218822Sdim  switch (inst.operands[1].imm)
777889857Sobrien    {
7779218822Sdim    case 1: inst.instruction |= CP_T_X;		 break;
7780218822Sdim    case 2: inst.instruction |= CP_T_Y;		 break;
7781218822Sdim    case 3: inst.instruction |= CP_T_Y | CP_T_X; break;
7782218822Sdim    case 4:					 break;
7783218822Sdim    default: abort ();
778489857Sobrien    }
778589857Sobrien
7786218822Sdim  if (inst.instruction & (PRE_INDEX | INDEX_UP))
778789857Sobrien    {
7788218822Sdim      /* The instruction specified "ea" or "fd", so we can only accept
7789218822Sdim	 [Rn]{!}.  The instruction does not really support stacking or
7790218822Sdim	 unstacking, so we have to emulate these by setting appropriate
7791218822Sdim	 bits and offsets.  */
7792218822Sdim      constraint (inst.reloc.exp.X_op != O_constant
7793218822Sdim		  || inst.reloc.exp.X_add_number != 0,
7794218822Sdim		  _("this instruction does not support indexing"));
779589857Sobrien
7796218822Sdim      if ((inst.instruction & PRE_INDEX) || inst.operands[2].writeback)
7797218822Sdim	inst.reloc.exp.X_add_number = 12 * inst.operands[1].imm;
779889857Sobrien
7799218822Sdim      if (!(inst.instruction & INDEX_UP))
7800218822Sdim	inst.reloc.exp.X_add_number = -inst.reloc.exp.X_add_number;
780189857Sobrien
7802218822Sdim      if (!(inst.instruction & PRE_INDEX) && inst.operands[2].writeback)
7803218822Sdim	{
7804218822Sdim	  inst.operands[2].preind = 0;
7805218822Sdim	  inst.operands[2].postind = 1;
7806218822Sdim	}
7807218822Sdim    }
780889857Sobrien
7809218822Sdim  encode_arm_cp_address (2, TRUE, TRUE, 0);
7810218822Sdim}
781189857Sobrien
7812218822Sdim
7813218822Sdim/* iWMMXt instructions: strictly in alphabetical order.	 */
781489857Sobrien
7815218822Sdimstatic void
7816218822Sdimdo_iwmmxt_tandorc (void)
7817218822Sdim{
7818218822Sdim  constraint (inst.operands[0].reg != REG_PC, _("only r15 allowed here"));
7819218822Sdim}
782089857Sobrien
7821218822Sdimstatic void
7822218822Sdimdo_iwmmxt_textrc (void)
7823218822Sdim{
7824218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7825218822Sdim  inst.instruction |= inst.operands[1].imm;
7826218822Sdim}
782789857Sobrien
7828218822Sdimstatic void
7829218822Sdimdo_iwmmxt_textrm (void)
7830218822Sdim{
7831218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7832218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7833218822Sdim  inst.instruction |= inst.operands[2].imm;
7834218822Sdim}
783589857Sobrien
7836218822Sdimstatic void
7837218822Sdimdo_iwmmxt_tinsr (void)
7838218822Sdim{
7839218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7840218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
7841218822Sdim  inst.instruction |= inst.operands[2].imm;
7842218822Sdim}
784389857Sobrien
7844218822Sdimstatic void
7845218822Sdimdo_iwmmxt_tmia (void)
7846218822Sdim{
7847218822Sdim  inst.instruction |= inst.operands[0].reg << 5;
7848218822Sdim  inst.instruction |= inst.operands[1].reg;
7849218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
7850218822Sdim}
785189857Sobrien
7852218822Sdimstatic void
7853218822Sdimdo_iwmmxt_waligni (void)
7854218822Sdim{
7855218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7856218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7857218822Sdim  inst.instruction |= inst.operands[2].reg;
7858218822Sdim  inst.instruction |= inst.operands[3].imm << 20;
7859218822Sdim}
786089857Sobrien
7861218822Sdimstatic void
7862218822Sdimdo_iwmmxt_wmerge (void)
7863218822Sdim{
7864218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7865218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7866218822Sdim  inst.instruction |= inst.operands[2].reg;
7867218822Sdim  inst.instruction |= inst.operands[3].imm << 21;
7868218822Sdim}
786989857Sobrien
7870218822Sdimstatic void
7871218822Sdimdo_iwmmxt_wmov (void)
7872218822Sdim{
7873218822Sdim  /* WMOV rD, rN is an alias for WOR rD, rN, rN.  */
7874218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7875218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7876218822Sdim  inst.instruction |= inst.operands[1].reg;
7877218822Sdim}
787889857Sobrien
7879218822Sdimstatic void
7880218822Sdimdo_iwmmxt_wldstbh (void)
7881218822Sdim{
7882218822Sdim  int reloc;
7883218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7884218822Sdim  if (thumb_mode)
7885218822Sdim    reloc = BFD_RELOC_ARM_T32_CP_OFF_IMM_S2;
7886218822Sdim  else
7887218822Sdim    reloc = BFD_RELOC_ARM_CP_OFF_IMM_S2;
7888218822Sdim  encode_arm_cp_address (1, TRUE, FALSE, reloc);
7889218822Sdim}
7890218822Sdim
7891218822Sdimstatic void
7892218822Sdimdo_iwmmxt_wldstw (void)
7893218822Sdim{
7894218822Sdim  /* RIWR_RIWC clears .isreg for a control register.  */
7895218822Sdim  if (!inst.operands[0].isreg)
7896218822Sdim    {
7897218822Sdim      constraint (inst.cond != COND_ALWAYS, BAD_COND);
7898218822Sdim      inst.instruction |= 0xf0000000;
789989857Sobrien    }
790060484Sobrien
7901218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7902218822Sdim  encode_arm_cp_address (1, TRUE, TRUE, 0);
7903218822Sdim}
790460484Sobrien
7905218822Sdimstatic void
7906218822Sdimdo_iwmmxt_wldstd (void)
7907218822Sdim{
7908218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7909218822Sdim  if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2)
7910218822Sdim      && inst.operands[1].immisreg)
7911218822Sdim    {
7912218822Sdim      inst.instruction &= ~0x1a000ff;
7913218822Sdim      inst.instruction |= (0xf << 28);
7914218822Sdim      if (inst.operands[1].preind)
7915218822Sdim	inst.instruction |= PRE_INDEX;
7916218822Sdim      if (!inst.operands[1].negative)
7917218822Sdim	inst.instruction |= INDEX_UP;
7918218822Sdim      if (inst.operands[1].writeback)
7919218822Sdim	inst.instruction |= WRITE_BACK;
7920218822Sdim      inst.instruction |= inst.operands[1].reg << 16;
7921218822Sdim      inst.instruction |= inst.reloc.exp.X_add_number << 4;
7922218822Sdim      inst.instruction |= inst.operands[1].imm;
7923218822Sdim    }
7924218822Sdim  else
7925218822Sdim    encode_arm_cp_address (1, TRUE, FALSE, 0);
7926218822Sdim}
792789857Sobrien
7928218822Sdimstatic void
7929218822Sdimdo_iwmmxt_wshufh (void)
7930218822Sdim{
7931218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7932218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
7933218822Sdim  inst.instruction |= ((inst.operands[2].imm & 0xf0) << 16);
7934218822Sdim  inst.instruction |= (inst.operands[2].imm & 0x0f);
7935218822Sdim}
793689857Sobrien
7937218822Sdimstatic void
7938218822Sdimdo_iwmmxt_wzero (void)
7939218822Sdim{
7940218822Sdim  /* WZERO reg is an alias for WANDN reg, reg, reg.  */
7941218822Sdim  inst.instruction |= inst.operands[0].reg;
7942218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
7943218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
7944218822Sdim}
794589857Sobrien
7946218822Sdimstatic void
7947218822Sdimdo_iwmmxt_wrwrwr_or_imm5 (void)
7948218822Sdim{
7949218822Sdim  if (inst.operands[2].isreg)
7950218822Sdim    do_rd_rn_rm ();
7951218822Sdim  else {
7952218822Sdim    constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2),
7953218822Sdim		_("immediate operand requires iWMMXt2"));
7954218822Sdim    do_rd_rn ();
7955218822Sdim    if (inst.operands[2].imm == 0)
7956218822Sdim      {
7957218822Sdim	switch ((inst.instruction >> 20) & 0xf)
7958218822Sdim	  {
7959218822Sdim	  case 4:
7960218822Sdim	  case 5:
7961218822Sdim	  case 6:
7962218822Sdim	  case 7:
7963218822Sdim	    /* w...h wrd, wrn, #0 -> wrorh wrd, wrn, #16.  */
7964218822Sdim	    inst.operands[2].imm = 16;
7965218822Sdim	    inst.instruction = (inst.instruction & 0xff0fffff) | (0x7 << 20);
7966218822Sdim	    break;
7967218822Sdim	  case 8:
7968218822Sdim	  case 9:
7969218822Sdim	  case 10:
7970218822Sdim	  case 11:
7971218822Sdim	    /* w...w wrd, wrn, #0 -> wrorw wrd, wrn, #32.  */
7972218822Sdim	    inst.operands[2].imm = 32;
7973218822Sdim	    inst.instruction = (inst.instruction & 0xff0fffff) | (0xb << 20);
7974218822Sdim	    break;
7975218822Sdim	  case 12:
7976218822Sdim	  case 13:
7977218822Sdim	  case 14:
7978218822Sdim	  case 15:
797989857Sobrien	    {
7980218822Sdim	      /* w...d wrd, wrn, #0 -> wor wrd, wrn, wrn.  */
7981218822Sdim	      unsigned long wrn;
7982218822Sdim	      wrn = (inst.instruction >> 16) & 0xf;
7983218822Sdim	      inst.instruction &= 0xff0fff0f;
7984218822Sdim	      inst.instruction |= wrn;
7985218822Sdim	      /* Bail out here; the instruction is now assembled.  */
798689857Sobrien	      return;
798789857Sobrien	    }
7988218822Sdim	  }
7989218822Sdim      }
7990218822Sdim    /* Map 32 -> 0, etc.  */
7991218822Sdim    inst.operands[2].imm &= 0x1f;
7992218822Sdim    inst.instruction |= (0xf << 28) | ((inst.operands[2].imm & 0x10) << 4) | (inst.operands[2].imm & 0xf);
7993218822Sdim  }
7994218822Sdim}
7995218822Sdim
7996218822Sdim/* Cirrus Maverick instructions.  Simple 2-, 3-, and 4-register
7997218822Sdim   operations first, then control, shift, and load/store.  */
799889857Sobrien
7999218822Sdim/* Insns like "foo X,Y,Z".  */
800089857Sobrien
8001218822Sdimstatic void
8002218822Sdimdo_mav_triple (void)
8003218822Sdim{
8004218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
8005218822Sdim  inst.instruction |= inst.operands[1].reg;
8006218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
8007218822Sdim}
800889857Sobrien
8009218822Sdim/* Insns like "foo W,X,Y,Z".
8010218822Sdim    where W=MVAX[0:3] and X,Y,Z=MVFX[0:15].  */
801189857Sobrien
8012218822Sdimstatic void
8013218822Sdimdo_mav_quad (void)
8014218822Sdim{
8015218822Sdim  inst.instruction |= inst.operands[0].reg << 5;
8016218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
8017218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
8018218822Sdim  inst.instruction |= inst.operands[3].reg;
8019218822Sdim}
802060484Sobrien
8021218822Sdim/* cfmvsc32<cond> DSPSC,MVDX[15:0].  */
8022218822Sdimstatic void
8023218822Sdimdo_mav_dspsc (void)
8024218822Sdim{
8025218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
802689857Sobrien}
802789857Sobrien
8028218822Sdim/* Maverick shift immediate instructions.
8029218822Sdim   cfsh32<cond> MVFX[15:0],MVFX[15:0],Shift[6:0].
8030218822Sdim   cfsh64<cond> MVDX[15:0],MVDX[15:0],Shift[6:0].  */
8031218822Sdim
803289857Sobrienstatic void
8033218822Sdimdo_mav_shift (void)
803489857Sobrien{
8035218822Sdim  int imm = inst.operands[2].imm;
803689857Sobrien
8037218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
8038218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
803977298Sobrien
8040218822Sdim  /* Bits 0-3 of the insn should have bits 0-3 of the immediate.
8041218822Sdim     Bits 5-7 of the insn should have bits 4-6 of the immediate.
8042218822Sdim     Bit 4 should be 0.	 */
8043218822Sdim  imm = (imm & 0xf) | ((imm & 0x70) << 1);
804460484Sobrien
8045218822Sdim  inst.instruction |= imm;
8046218822Sdim}
8047218822Sdim
8048218822Sdim/* XScale instructions.	 Also sorted arithmetic before move.  */
804960484Sobrien
8050218822Sdim/* Xscale multiply-accumulate (argument parse)
8051218822Sdim     MIAcc   acc0,Rm,Rs
8052218822Sdim     MIAPHcc acc0,Rm,Rs
8053218822Sdim     MIAxycc acc0,Rm,Rs.  */
805460484Sobrien
8055218822Sdimstatic void
8056218822Sdimdo_xsc_mia (void)
8057218822Sdim{
8058218822Sdim  inst.instruction |= inst.operands[1].reg;
8059218822Sdim  inst.instruction |= inst.operands[2].reg << 12;
8060218822Sdim}
806160484Sobrien
8062218822Sdim/* Xscale move-accumulator-register (argument parse)
806360484Sobrien
8064218822Sdim     MARcc   acc0,RdLo,RdHi.  */
806560484Sobrien
8066218822Sdimstatic void
8067218822Sdimdo_xsc_mar (void)
8068218822Sdim{
8069218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
8070218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
8071218822Sdim}
807289857Sobrien
8073218822Sdim/* Xscale move-register-accumulator (argument parse)
807489857Sobrien
8075218822Sdim     MRAcc   RdLo,RdHi,acc0.  */
807689857Sobrien
8077218822Sdimstatic void
8078218822Sdimdo_xsc_mra (void)
8079218822Sdim{
8080218822Sdim  constraint (inst.operands[0].reg == inst.operands[1].reg, BAD_OVERLAP);
8081218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
8082218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
8083218822Sdim}
8084218822Sdim
8085218822Sdim/* Encoding functions relevant only to Thumb.  */
808689857Sobrien
8087218822Sdim/* inst.operands[i] is a shifted-register operand; encode
8088218822Sdim   it into inst.instruction in the format used by Thumb32.  */
808989857Sobrien
8090218822Sdimstatic void
8091218822Sdimencode_thumb32_shifted_operand (int i)
8092218822Sdim{
8093218822Sdim  unsigned int value = inst.reloc.exp.X_add_number;
8094218822Sdim  unsigned int shift = inst.operands[i].shift_kind;
8095218822Sdim
8096218822Sdim  constraint (inst.operands[i].immisreg,
8097218822Sdim	      _("shift by register not allowed in thumb mode"));
8098218822Sdim  inst.instruction |= inst.operands[i].reg;
8099218822Sdim  if (shift == SHIFT_RRX)
8100218822Sdim    inst.instruction |= SHIFT_ROR << 4;
810189857Sobrien  else
810289857Sobrien    {
8103218822Sdim      constraint (inst.reloc.exp.X_op != O_constant,
8104218822Sdim		  _("expression too complex"));
8105218822Sdim
8106218822Sdim      constraint (value > 32
8107218822Sdim		  || (value == 32 && (shift == SHIFT_LSL
8108218822Sdim				      || shift == SHIFT_ROR)),
8109218822Sdim		  _("shift expression is too large"));
8110218822Sdim
8111218822Sdim      if (value == 0)
8112218822Sdim	shift = SHIFT_LSL;
8113218822Sdim      else if (value == 32)
8114218822Sdim	value = 0;
8115218822Sdim
8116218822Sdim      inst.instruction |= shift << 4;
8117218822Sdim      inst.instruction |= (value & 0x1c) << 10;
8118218822Sdim      inst.instruction |= (value & 0x03) << 6;
811989857Sobrien    }
812089857Sobrien}
812189857Sobrien
8122218822Sdim
8123218822Sdim/* inst.operands[i] was set up by parse_address.  Encode it into a
8124218822Sdim   Thumb32 format load or store instruction.  Reject forms that cannot
8125218822Sdim   be used with such instructions.  If is_t is true, reject forms that
8126218822Sdim   cannot be used with a T instruction; if is_d is true, reject forms
8127218822Sdim   that cannot be used with a D instruction.  */
8128218822Sdim
8129218822Sdimstatic void
8130218822Sdimencode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
813189857Sobrien{
8132218822Sdim  bfd_boolean is_pc = (inst.operands[i].reg == REG_PC);
813389857Sobrien
8134218822Sdim  constraint (!inst.operands[i].isreg,
8135218822Sdim	      _("Instruction does not support =N addresses"));
8136218822Sdim
8137218822Sdim  inst.instruction |= inst.operands[i].reg << 16;
8138218822Sdim  if (inst.operands[i].immisreg)
813989857Sobrien    {
8140218822Sdim      constraint (is_pc, _("cannot use register index with PC-relative addressing"));
8141218822Sdim      constraint (is_t || is_d, _("cannot use register index with this instruction"));
8142218822Sdim      constraint (inst.operands[i].negative,
8143218822Sdim		  _("Thumb does not support negative register indexing"));
8144218822Sdim      constraint (inst.operands[i].postind,
8145218822Sdim		  _("Thumb does not support register post-indexing"));
8146218822Sdim      constraint (inst.operands[i].writeback,
8147218822Sdim		  _("Thumb does not support register indexing with writeback"));
8148218822Sdim      constraint (inst.operands[i].shifted && inst.operands[i].shift_kind != SHIFT_LSL,
8149218822Sdim		  _("Thumb supports only LSL in shifted register indexing"));
815089857Sobrien
8151218822Sdim      inst.instruction |= inst.operands[i].imm;
8152218822Sdim      if (inst.operands[i].shifted)
815389857Sobrien	{
8154218822Sdim	  constraint (inst.reloc.exp.X_op != O_constant,
8155218822Sdim		      _("expression too complex"));
8156218822Sdim	  constraint (inst.reloc.exp.X_add_number < 0
8157218822Sdim		      || inst.reloc.exp.X_add_number > 3,
8158218822Sdim		      _("shift out of range"));
8159218822Sdim	  inst.instruction |= inst.reloc.exp.X_add_number << 4;
8160218822Sdim	}
8161218822Sdim      inst.reloc.type = BFD_RELOC_UNUSED;
8162218822Sdim    }
8163218822Sdim  else if (inst.operands[i].preind)
8164218822Sdim    {
8165218822Sdim      constraint (is_pc && inst.operands[i].writeback,
8166218822Sdim		  _("cannot use writeback with PC-relative addressing"));
8167218822Sdim      constraint (is_t && inst.operands[i].writeback,
8168218822Sdim		  _("cannot use writeback with this instruction"));
816989857Sobrien
8170218822Sdim      if (is_d)
8171218822Sdim	{
8172218822Sdim	  inst.instruction |= 0x01000000;
8173218822Sdim	  if (inst.operands[i].writeback)
8174218822Sdim	    inst.instruction |= 0x00200000;
817589857Sobrien	}
817689857Sobrien      else
817789857Sobrien	{
8178218822Sdim	  inst.instruction |= 0x00000c00;
8179218822Sdim	  if (inst.operands[i].writeback)
8180218822Sdim	    inst.instruction |= 0x00000100;
818189857Sobrien	}
8182218822Sdim      inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_IMM;
8183218822Sdim    }
8184218822Sdim  else if (inst.operands[i].postind)
8185218822Sdim    {
8186218822Sdim      assert (inst.operands[i].writeback);
8187218822Sdim      constraint (is_pc, _("cannot use post-indexing with PC-relative addressing"));
8188218822Sdim      constraint (is_t, _("cannot use post-indexing with this instruction"));
818989857Sobrien
8190218822Sdim      if (is_d)
8191218822Sdim	inst.instruction |= 0x00200000;
8192218822Sdim      else
8193218822Sdim	inst.instruction |= 0x00000900;
8194218822Sdim      inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_IMM;
8195218822Sdim    }
8196218822Sdim  else /* unindexed - only for coprocessor */
8197218822Sdim    inst.error = _("instruction does not accept unindexed addressing");
8198218822Sdim}
819989857Sobrien
8200218822Sdim/* Table of Thumb instructions which exist in both 16- and 32-bit
8201218822Sdim   encodings (the latter only in post-V6T2 cores).  The index is the
8202218822Sdim   value used in the insns table below.  When there is more than one
8203218822Sdim   possible 16-bit encoding for the instruction, this table always
8204218822Sdim   holds variant (1).
8205218822Sdim   Also contains several pseudo-instructions used during relaxation.  */
8206218822Sdim#define T16_32_TAB				\
8207218822Sdim  X(adc,   4140, eb400000),			\
8208218822Sdim  X(adcs,  4140, eb500000),			\
8209218822Sdim  X(add,   1c00, eb000000),			\
8210218822Sdim  X(adds,  1c00, eb100000),			\
8211218822Sdim  X(addi,  0000, f1000000),			\
8212218822Sdim  X(addis, 0000, f1100000),			\
8213218822Sdim  X(add_pc,000f, f20f0000),			\
8214218822Sdim  X(add_sp,000d, f10d0000),			\
8215218822Sdim  X(adr,   000f, f20f0000),			\
8216218822Sdim  X(and,   4000, ea000000),			\
8217218822Sdim  X(ands,  4000, ea100000),			\
8218218822Sdim  X(asr,   1000, fa40f000),			\
8219218822Sdim  X(asrs,  1000, fa50f000),			\
8220218822Sdim  X(b,     e000, f000b000),			\
8221218822Sdim  X(bcond, d000, f0008000),			\
8222218822Sdim  X(bic,   4380, ea200000),			\
8223218822Sdim  X(bics,  4380, ea300000),			\
8224218822Sdim  X(cmn,   42c0, eb100f00),			\
8225218822Sdim  X(cmp,   2800, ebb00f00),			\
8226218822Sdim  X(cpsie, b660, f3af8400),			\
8227218822Sdim  X(cpsid, b670, f3af8600),			\
8228218822Sdim  X(cpy,   4600, ea4f0000),			\
8229218822Sdim  X(dec_sp,80dd, f1ad0d00),			\
8230218822Sdim  X(eor,   4040, ea800000),			\
8231218822Sdim  X(eors,  4040, ea900000),			\
8232218822Sdim  X(inc_sp,00dd, f10d0d00),			\
8233218822Sdim  X(ldmia, c800, e8900000),			\
8234218822Sdim  X(ldr,   6800, f8500000),			\
8235218822Sdim  X(ldrb,  7800, f8100000),			\
8236218822Sdim  X(ldrh,  8800, f8300000),			\
8237218822Sdim  X(ldrsb, 5600, f9100000),			\
8238218822Sdim  X(ldrsh, 5e00, f9300000),			\
8239218822Sdim  X(ldr_pc,4800, f85f0000),			\
8240218822Sdim  X(ldr_pc2,4800, f85f0000),			\
8241218822Sdim  X(ldr_sp,9800, f85d0000),			\
8242218822Sdim  X(lsl,   0000, fa00f000),			\
8243218822Sdim  X(lsls,  0000, fa10f000),			\
8244218822Sdim  X(lsr,   0800, fa20f000),			\
8245218822Sdim  X(lsrs,  0800, fa30f000),			\
8246218822Sdim  X(mov,   2000, ea4f0000),			\
8247218822Sdim  X(movs,  2000, ea5f0000),			\
8248218822Sdim  X(mul,   4340, fb00f000),                     \
8249218822Sdim  X(muls,  4340, ffffffff), /* no 32b muls */	\
8250218822Sdim  X(mvn,   43c0, ea6f0000),			\
8251218822Sdim  X(mvns,  43c0, ea7f0000),			\
8252218822Sdim  X(neg,   4240, f1c00000), /* rsb #0 */	\
8253218822Sdim  X(negs,  4240, f1d00000), /* rsbs #0 */	\
8254218822Sdim  X(orr,   4300, ea400000),			\
8255218822Sdim  X(orrs,  4300, ea500000),			\
8256218822Sdim  X(pop,   bc00, e8bd0000), /* ldmia sp!,... */	\
8257218822Sdim  X(push,  b400, e92d0000), /* stmdb sp!,... */	\
8258218822Sdim  X(rev,   ba00, fa90f080),			\
8259218822Sdim  X(rev16, ba40, fa90f090),			\
8260218822Sdim  X(revsh, bac0, fa90f0b0),			\
8261218822Sdim  X(ror,   41c0, fa60f000),			\
8262218822Sdim  X(rors,  41c0, fa70f000),			\
8263218822Sdim  X(sbc,   4180, eb600000),			\
8264218822Sdim  X(sbcs,  4180, eb700000),			\
8265218822Sdim  X(stmia, c000, e8800000),			\
8266218822Sdim  X(str,   6000, f8400000),			\
8267218822Sdim  X(strb,  7000, f8000000),			\
8268218822Sdim  X(strh,  8000, f8200000),			\
8269218822Sdim  X(str_sp,9000, f84d0000),			\
8270218822Sdim  X(sub,   1e00, eba00000),			\
8271218822Sdim  X(subs,  1e00, ebb00000),			\
8272218822Sdim  X(subi,  8000, f1a00000),			\
8273218822Sdim  X(subis, 8000, f1b00000),			\
8274218822Sdim  X(sxtb,  b240, fa4ff080),			\
8275218822Sdim  X(sxth,  b200, fa0ff080),			\
8276218822Sdim  X(tst,   4200, ea100f00),			\
8277218822Sdim  X(uxtb,  b2c0, fa5ff080),			\
8278218822Sdim  X(uxth,  b280, fa1ff080),			\
8279218822Sdim  X(nop,   bf00, f3af8000),			\
8280218822Sdim  X(yield, bf10, f3af8001),			\
8281218822Sdim  X(wfe,   bf20, f3af8002),			\
8282218822Sdim  X(wfi,   bf30, f3af8003),			\
8283218822Sdim  X(sev,   bf40, f3af9004), /* typo, 8004? */
828489857Sobrien
8285218822Sdim/* To catch errors in encoding functions, the codes are all offset by
8286218822Sdim   0xF800, putting them in one of the 32-bit prefix ranges, ergo undefined
8287218822Sdim   as 16-bit instructions.  */
8288218822Sdim#define X(a,b,c) T_MNEM_##a
8289218822Sdimenum t16_32_codes { T16_32_OFFSET = 0xF7FF, T16_32_TAB };
8290218822Sdim#undef X
829189857Sobrien
8292218822Sdim#define X(a,b,c) 0x##b
8293218822Sdimstatic const unsigned short thumb_op16[] = { T16_32_TAB };
8294218822Sdim#define THUMB_OP16(n) (thumb_op16[(n) - (T16_32_OFFSET + 1)])
8295218822Sdim#undef X
829689857Sobrien
8297218822Sdim#define X(a,b,c) 0x##c
8298218822Sdimstatic const unsigned int thumb_op32[] = { T16_32_TAB };
8299218822Sdim#define THUMB_OP32(n) (thumb_op32[(n) - (T16_32_OFFSET + 1)])
8300218822Sdim#define THUMB_SETS_FLAGS(n) (THUMB_OP32 (n) & 0x00100000)
8301218822Sdim#undef X
8302218822Sdim#undef T16_32_TAB
8303218822Sdim
8304218822Sdim/* Thumb instruction encoders, in alphabetical order.  */
8305218822Sdim
8306218822Sdim/* ADDW or SUBW.  */
830789857Sobrienstatic void
8308218822Sdimdo_t_add_sub_w (void)
830989857Sobrien{
8310218822Sdim  int Rd, Rn;
831189857Sobrien
8312218822Sdim  Rd = inst.operands[0].reg;
8313218822Sdim  Rn = inst.operands[1].reg;
831489857Sobrien
8315218822Sdim  constraint (Rd == 15, _("PC not allowed as destination"));
8316218822Sdim  inst.instruction |= (Rn << 16) | (Rd << 8);
8317218822Sdim  inst.reloc.type = BFD_RELOC_ARM_T32_IMM12;
8318218822Sdim}
831989857Sobrien
8320218822Sdim/* Parse an add or subtract instruction.  We get here with inst.instruction
8321218822Sdim   equalling any of THUMB_OPCODE_add, adds, sub, or subs.  */
832289857Sobrien
8323218822Sdimstatic void
8324218822Sdimdo_t_add_sub (void)
8325218822Sdim{
8326218822Sdim  int Rd, Rs, Rn;
832789857Sobrien
8328218822Sdim  Rd = inst.operands[0].reg;
8329218822Sdim  Rs = (inst.operands[1].present
8330218822Sdim	? inst.operands[1].reg    /* Rd, Rs, foo */
8331218822Sdim	: inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
833289857Sobrien
8333218822Sdim  if (unified_syntax)
8334218822Sdim    {
8335218822Sdim      bfd_boolean flags;
8336218822Sdim      bfd_boolean narrow;
8337218822Sdim      int opcode;
833889857Sobrien
8339218822Sdim      flags = (inst.instruction == T_MNEM_adds
8340218822Sdim	       || inst.instruction == T_MNEM_subs);
8341218822Sdim      if (flags)
8342218822Sdim	narrow = (current_it_mask == 0);
8343218822Sdim      else
8344218822Sdim	narrow = (current_it_mask != 0);
8345218822Sdim      if (!inst.operands[2].isreg)
834660484Sobrien	{
8347218822Sdim	  int add;
834877298Sobrien
8349218822Sdim	  add = (inst.instruction == T_MNEM_add
8350218822Sdim		 || inst.instruction == T_MNEM_adds);
8351218822Sdim	  opcode = 0;
8352218822Sdim	  if (inst.size_req != 4)
835360484Sobrien	    {
8354218822Sdim	      /* Attempt to use a narrow opcode, with relaxation if
8355218822Sdim	         appropriate.  */
8356218822Sdim	      if (Rd == REG_SP && Rs == REG_SP && !flags)
8357218822Sdim		opcode = add ? T_MNEM_inc_sp : T_MNEM_dec_sp;
8358218822Sdim	      else if (Rd <= 7 && Rs == REG_SP && add && !flags)
8359218822Sdim		opcode = T_MNEM_add_sp;
8360218822Sdim	      else if (Rd <= 7 && Rs == REG_PC && add && !flags)
8361218822Sdim		opcode = T_MNEM_add_pc;
8362218822Sdim	      else if (Rd <= 7 && Rs <= 7 && narrow)
8363218822Sdim		{
8364218822Sdim		  if (flags)
8365218822Sdim		    opcode = add ? T_MNEM_addis : T_MNEM_subis;
8366218822Sdim		  else
8367218822Sdim		    opcode = add ? T_MNEM_addi : T_MNEM_subi;
8368218822Sdim		}
8369218822Sdim	      if (opcode)
8370218822Sdim		{
8371218822Sdim		  inst.instruction = THUMB_OP16(opcode);
8372218822Sdim		  inst.instruction |= (Rd << 4) | Rs;
8373218822Sdim		  inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
8374218822Sdim		  if (inst.size_req != 2)
8375218822Sdim		    inst.relax = opcode;
8376218822Sdim		}
8377218822Sdim	      else
8378218822Sdim		constraint (inst.size_req == 2, BAD_HIREG);
837960484Sobrien	    }
8380218822Sdim	  if (inst.size_req == 4
8381218822Sdim	      || (inst.size_req != 2 && !opcode))
838260484Sobrien	    {
8383218822Sdim	      if (Rd == REG_PC)
838477298Sobrien		{
8385218822Sdim		  constraint (Rs != REG_LR || inst.instruction != T_MNEM_subs,
8386218822Sdim			     _("only SUBS PC, LR, #const allowed"));
8387218822Sdim		  constraint (inst.reloc.exp.X_op != O_constant,
8388218822Sdim			      _("expression too complex"));
8389218822Sdim		  constraint (inst.reloc.exp.X_add_number < 0
8390218822Sdim			      || inst.reloc.exp.X_add_number > 0xff,
8391218822Sdim			     _("immediate value out of range"));
8392218822Sdim		  inst.instruction = T2_SUBS_PC_LR
8393218822Sdim				     | inst.reloc.exp.X_add_number;
8394218822Sdim		  inst.reloc.type = BFD_RELOC_UNUSED;
8395218822Sdim		  return;
839677298Sobrien		}
8397218822Sdim	      else if (Rs == REG_PC)
8398218822Sdim		{
8399218822Sdim		  /* Always use addw/subw.  */
8400218822Sdim		  inst.instruction = add ? 0xf20f0000 : 0xf2af0000;
8401218822Sdim		  inst.reloc.type = BFD_RELOC_ARM_T32_IMM12;
8402218822Sdim		}
8403218822Sdim	      else
8404218822Sdim		{
8405218822Sdim		  inst.instruction = THUMB_OP32 (inst.instruction);
8406218822Sdim		  inst.instruction = (inst.instruction & 0xe1ffffff)
8407218822Sdim				     | 0x10000000;
8408218822Sdim		  if (flags)
8409218822Sdim		    inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
8410218822Sdim		  else
8411218822Sdim		    inst.reloc.type = BFD_RELOC_ARM_T32_ADD_IMM;
8412218822Sdim		}
8413218822Sdim	      inst.instruction |= Rd << 8;
8414218822Sdim	      inst.instruction |= Rs << 16;
841560484Sobrien	    }
841660484Sobrien	}
841760484Sobrien      else
841860484Sobrien	{
8419218822Sdim	  Rn = inst.operands[2].reg;
8420218822Sdim	  /* See if we can do this with a 16-bit instruction.  */
8421218822Sdim	  if (!inst.operands[2].shifted && inst.size_req != 4)
842260484Sobrien	    {
8423218822Sdim	      if (Rd > 7 || Rs > 7 || Rn > 7)
8424218822Sdim		narrow = FALSE;
842560484Sobrien
8426218822Sdim	      if (narrow)
8427218822Sdim		{
8428218822Sdim		  inst.instruction = ((inst.instruction == T_MNEM_adds
8429218822Sdim				       || inst.instruction == T_MNEM_add)
8430218822Sdim				      ? T_OPCODE_ADD_R3
8431218822Sdim				      : T_OPCODE_SUB_R3);
8432218822Sdim		  inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
8433218822Sdim		  return;
8434218822Sdim		}
843560484Sobrien
8436218822Sdim	      if (inst.instruction == T_MNEM_add)
8437218822Sdim		{
8438218822Sdim		  if (Rd == Rs)
8439218822Sdim		    {
8440218822Sdim		      inst.instruction = T_OPCODE_ADD_HI;
8441218822Sdim		      inst.instruction |= (Rd & 8) << 4;
8442218822Sdim		      inst.instruction |= (Rd & 7);
8443218822Sdim		      inst.instruction |= Rn << 3;
8444218822Sdim		      return;
8445218822Sdim		    }
8446218822Sdim		  /* ... because addition is commutative! */
8447218822Sdim		  else if (Rd == Rn)
8448218822Sdim		    {
8449218822Sdim		      inst.instruction = T_OPCODE_ADD_HI;
8450218822Sdim		      inst.instruction |= (Rd & 8) << 4;
8451218822Sdim		      inst.instruction |= (Rd & 7);
8452218822Sdim		      inst.instruction |= Rs << 3;
8453218822Sdim		      return;
8454218822Sdim		    }
8455218822Sdim		}
845660484Sobrien	    }
8457218822Sdim	  /* If we get here, it can't be done in 16 bits.  */
8458218822Sdim	  constraint (inst.operands[2].shifted && inst.operands[2].immisreg,
8459218822Sdim		      _("shift must be constant"));
8460218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
8461218822Sdim	  inst.instruction |= Rd << 8;
8462218822Sdim	  inst.instruction |= Rs << 16;
8463218822Sdim	  encode_thumb32_shifted_operand (2);
846460484Sobrien	}
846560484Sobrien    }
8466218822Sdim  else
846760484Sobrien    {
8468218822Sdim      constraint (inst.instruction == T_MNEM_adds
8469218822Sdim		  || inst.instruction == T_MNEM_subs,
8470218822Sdim		  BAD_THUMB32);
8471218822Sdim
8472218822Sdim      if (!inst.operands[2].isreg) /* Rd, Rs, #imm */
847389857Sobrien	{
8474218822Sdim	  constraint ((Rd > 7 && (Rd != REG_SP || Rs != REG_SP))
8475218822Sdim		      || (Rs > 7 && Rs != REG_SP && Rs != REG_PC),
8476218822Sdim		      BAD_HIREG);
8477218822Sdim
8478218822Sdim	  inst.instruction = (inst.instruction == T_MNEM_add
8479218822Sdim			      ? 0x0000 : 0x8000);
8480218822Sdim	  inst.instruction |= (Rd << 4) | Rs;
8481218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
848289857Sobrien	  return;
848389857Sobrien	}
848489857Sobrien
8485218822Sdim      Rn = inst.operands[2].reg;
8486218822Sdim      constraint (inst.operands[2].shifted, _("unshifted register required"));
848760484Sobrien
8488218822Sdim      /* We now have Rd, Rs, and Rn set to registers.  */
8489218822Sdim      if (Rd > 7 || Rs > 7 || Rn > 7)
849060484Sobrien	{
8491218822Sdim	  /* Can't do this for SUB.	 */
8492218822Sdim	  constraint (inst.instruction == T_MNEM_sub, BAD_HIREG);
8493218822Sdim	  inst.instruction = T_OPCODE_ADD_HI;
8494218822Sdim	  inst.instruction |= (Rd & 8) << 4;
8495218822Sdim	  inst.instruction |= (Rd & 7);
8496218822Sdim	  if (Rs == Rd)
8497218822Sdim	    inst.instruction |= Rn << 3;
8498218822Sdim	  else if (Rn == Rd)
8499218822Sdim	    inst.instruction |= Rs << 3;
8500218822Sdim	  else
8501218822Sdim	    constraint (1, _("dest must overlap one source register"));
850260484Sobrien	}
8503218822Sdim      else
850460484Sobrien	{
8505218822Sdim	  inst.instruction = (inst.instruction == T_MNEM_add
8506218822Sdim			      ? T_OPCODE_ADD_R3 : T_OPCODE_SUB_R3);
8507218822Sdim	  inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
850860484Sobrien	}
8509218822Sdim    }
8510218822Sdim}
851180016Sobrien
8512218822Sdimstatic void
8513218822Sdimdo_t_adr (void)
8514218822Sdim{
8515218822Sdim  if (unified_syntax && inst.size_req == 0 && inst.operands[0].reg <= 7)
8516218822Sdim    {
8517218822Sdim      /* Defer to section relaxation.  */
8518218822Sdim      inst.relax = inst.instruction;
8519218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
8520218822Sdim      inst.instruction |= inst.operands[0].reg << 4;
8521218822Sdim    }
8522218822Sdim  else if (unified_syntax && inst.size_req != 2)
8523218822Sdim    {
8524218822Sdim      /* Generate a 32-bit opcode.  */
8525218822Sdim      inst.instruction = THUMB_OP32 (inst.instruction);
8526218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
8527218822Sdim      inst.reloc.type = BFD_RELOC_ARM_T32_ADD_PC12;
852880016Sobrien      inst.reloc.pc_rel = 1;
852960484Sobrien    }
853060484Sobrien  else
853160484Sobrien    {
8532218822Sdim      /* Generate a 16-bit opcode.  */
8533218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
8534218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
8535218822Sdim      inst.reloc.exp.X_add_number -= 4; /* PC relative adjust.  */
8536218822Sdim      inst.reloc.pc_rel = 1;
853760484Sobrien
8538218822Sdim      inst.instruction |= inst.operands[0].reg << 4;
853960484Sobrien    }
854060484Sobrien}
854160484Sobrien
8542218822Sdim/* Arithmetic instructions for which there is just one 16-bit
8543218822Sdim   instruction encoding, and it allows only two low registers.
8544218822Sdim   For maximal compatibility with ARM syntax, we allow three register
8545218822Sdim   operands even when Thumb-32 instructions are not available, as long
8546218822Sdim   as the first two are identical.  For instance, both "sbc r0,r1" and
8547218822Sdim   "sbc r0,r0,r1" are allowed.  */
8548218822Sdimstatic void
8549218822Sdimdo_t_arit3 (void)
855060484Sobrien{
8551218822Sdim  int Rd, Rs, Rn;
855260484Sobrien
8553218822Sdim  Rd = inst.operands[0].reg;
8554218822Sdim  Rs = (inst.operands[1].present
8555218822Sdim	? inst.operands[1].reg    /* Rd, Rs, foo */
8556218822Sdim	: inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
8557218822Sdim  Rn = inst.operands[2].reg;
8558218822Sdim
8559218822Sdim  if (unified_syntax)
856060484Sobrien    {
8561218822Sdim      if (!inst.operands[2].isreg)
856260484Sobrien	{
8563218822Sdim	  /* For an immediate, we always generate a 32-bit opcode;
8564218822Sdim	     section relaxation will shrink it later if possible.  */
8565218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
8566218822Sdim	  inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
8567218822Sdim	  inst.instruction |= Rd << 8;
8568218822Sdim	  inst.instruction |= Rs << 16;
8569218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
8570218822Sdim	}
8571218822Sdim      else
8572218822Sdim	{
8573218822Sdim	  bfd_boolean narrow;
857477298Sobrien
8575218822Sdim	  /* See if we can do this with a 16-bit instruction.  */
8576218822Sdim	  if (THUMB_SETS_FLAGS (inst.instruction))
8577218822Sdim	    narrow = current_it_mask == 0;
8578218822Sdim	  else
8579218822Sdim	    narrow = current_it_mask != 0;
858077298Sobrien
8581218822Sdim	  if (Rd > 7 || Rn > 7 || Rs > 7)
8582218822Sdim	    narrow = FALSE;
8583218822Sdim	  if (inst.operands[2].shifted)
8584218822Sdim	    narrow = FALSE;
8585218822Sdim	  if (inst.size_req == 4)
8586218822Sdim	    narrow = FALSE;
858760484Sobrien
8588218822Sdim	  if (narrow
8589218822Sdim	      && Rd == Rs)
8590218822Sdim	    {
8591218822Sdim	      inst.instruction = THUMB_OP16 (inst.instruction);
8592218822Sdim	      inst.instruction |= Rd;
8593218822Sdim	      inst.instruction |= Rn << 3;
8594218822Sdim	      return;
8595218822Sdim	    }
859677298Sobrien
8597218822Sdim	  /* If we get here, it can't be done in 16 bits.  */
8598218822Sdim	  constraint (inst.operands[2].shifted
8599218822Sdim		      && inst.operands[2].immisreg,
8600218822Sdim		      _("shift must be constant"));
8601218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
8602218822Sdim	  inst.instruction |= Rd << 8;
8603218822Sdim	  inst.instruction |= Rs << 16;
8604218822Sdim	  encode_thumb32_shifted_operand (2);
8605218822Sdim	}
8606218822Sdim    }
8607218822Sdim  else
8608218822Sdim    {
8609218822Sdim      /* On its face this is a lie - the instruction does set the
8610218822Sdim	 flags.  However, the only supported mnemonic in this mode
8611218822Sdim	 says it doesn't.  */
8612218822Sdim      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
861377298Sobrien
8614218822Sdim      constraint (!inst.operands[2].isreg || inst.operands[2].shifted,
8615218822Sdim		  _("unshifted register required"));
8616218822Sdim      constraint (Rd > 7 || Rs > 7 || Rn > 7, BAD_HIREG);
8617218822Sdim      constraint (Rd != Rs,
8618218822Sdim		  _("dest and source1 must be the same register"));
861960484Sobrien
8620218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
8621218822Sdim      inst.instruction |= Rd;
8622218822Sdim      inst.instruction |= Rn << 3;
8623218822Sdim    }
8624218822Sdim}
862560484Sobrien
8626218822Sdim/* Similarly, but for instructions where the arithmetic operation is
8627218822Sdim   commutative, so we can allow either of them to be different from
8628218822Sdim   the destination operand in a 16-bit instruction.  For instance, all
8629218822Sdim   three of "adc r0,r1", "adc r0,r0,r1", and "adc r0,r1,r0" are
8630218822Sdim   accepted.  */
8631218822Sdimstatic void
8632218822Sdimdo_t_arit3c (void)
8633218822Sdim{
8634218822Sdim  int Rd, Rs, Rn;
863560484Sobrien
8636218822Sdim  Rd = inst.operands[0].reg;
8637218822Sdim  Rs = (inst.operands[1].present
8638218822Sdim	? inst.operands[1].reg    /* Rd, Rs, foo */
8639218822Sdim	: inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
8640218822Sdim  Rn = inst.operands[2].reg;
864160484Sobrien
8642218822Sdim  if (unified_syntax)
8643218822Sdim    {
8644218822Sdim      if (!inst.operands[2].isreg)
8645218822Sdim	{
8646218822Sdim	  /* For an immediate, we always generate a 32-bit opcode;
8647218822Sdim	     section relaxation will shrink it later if possible.  */
8648218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
8649218822Sdim	  inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
8650218822Sdim	  inst.instruction |= Rd << 8;
8651218822Sdim	  inst.instruction |= Rs << 16;
8652218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
865360484Sobrien	}
865460484Sobrien      else
865560484Sobrien	{
8656218822Sdim	  bfd_boolean narrow;
865760484Sobrien
8658218822Sdim	  /* See if we can do this with a 16-bit instruction.  */
8659218822Sdim	  if (THUMB_SETS_FLAGS (inst.instruction))
8660218822Sdim	    narrow = current_it_mask == 0;
8661218822Sdim	  else
8662218822Sdim	    narrow = current_it_mask != 0;
866360484Sobrien
8664218822Sdim	  if (Rd > 7 || Rn > 7 || Rs > 7)
8665218822Sdim	    narrow = FALSE;
8666218822Sdim	  if (inst.operands[2].shifted)
8667218822Sdim	    narrow = FALSE;
8668218822Sdim	  if (inst.size_req == 4)
8669218822Sdim	    narrow = FALSE;
8670218822Sdim
8671218822Sdim	  if (narrow)
867260484Sobrien	    {
8673218822Sdim	      if (Rd == Rs)
867460484Sobrien		{
8675218822Sdim		  inst.instruction = THUMB_OP16 (inst.instruction);
8676218822Sdim		  inst.instruction |= Rd;
8677218822Sdim		  inst.instruction |= Rn << 3;
8678218822Sdim		  return;
867960484Sobrien		}
8680218822Sdim	      if (Rd == Rn)
868160484Sobrien		{
8682218822Sdim		  inst.instruction = THUMB_OP16 (inst.instruction);
8683218822Sdim		  inst.instruction |= Rd;
8684218822Sdim		  inst.instruction |= Rs << 3;
8685218822Sdim		  return;
868660484Sobrien		}
868760484Sobrien	    }
868860484Sobrien
8689218822Sdim	  /* If we get here, it can't be done in 16 bits.  */
8690218822Sdim	  constraint (inst.operands[2].shifted
8691218822Sdim		      && inst.operands[2].immisreg,
8692218822Sdim		      _("shift must be constant"));
8693218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
8694218822Sdim	  inst.instruction |= Rd << 8;
8695218822Sdim	  inst.instruction |= Rs << 16;
8696218822Sdim	  encode_thumb32_shifted_operand (2);
869760484Sobrien	}
8698218822Sdim    }
8699218822Sdim  else
8700218822Sdim    {
8701218822Sdim      /* On its face this is a lie - the instruction does set the
8702218822Sdim	 flags.  However, the only supported mnemonic in this mode
8703218822Sdim	 says it doesn't.  */
8704218822Sdim      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
870560484Sobrien
8706218822Sdim      constraint (!inst.operands[2].isreg || inst.operands[2].shifted,
8707218822Sdim		  _("unshifted register required"));
8708218822Sdim      constraint (Rd > 7 || Rs > 7 || Rn > 7, BAD_HIREG);
870960484Sobrien
8710218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
8711218822Sdim      inst.instruction |= Rd;
8712218822Sdim
8713218822Sdim      if (Rd == Rs)
8714218822Sdim	inst.instruction |= Rn << 3;
8715218822Sdim      else if (Rd == Rn)
8716218822Sdim	inst.instruction |= Rs << 3;
8717218822Sdim      else
8718218822Sdim	constraint (1, _("dest must overlap one source register"));
871977298Sobrien    }
8720218822Sdim}
872160484Sobrien
8722218822Sdimstatic void
8723218822Sdimdo_t_barrier (void)
8724218822Sdim{
8725218822Sdim  if (inst.operands[0].present)
8726218822Sdim    {
8727218822Sdim      constraint ((inst.instruction & 0xf0) != 0x40
8728218822Sdim		  && inst.operands[0].imm != 0xf,
8729218822Sdim		  "bad barrier type");
8730218822Sdim      inst.instruction |= inst.operands[0].imm;
8731218822Sdim    }
8732218822Sdim  else
8733218822Sdim    inst.instruction |= 0xf;
873460484Sobrien}
873560484Sobrien
873660484Sobrienstatic void
8737218822Sdimdo_t_bfc (void)
873860484Sobrien{
8739218822Sdim  unsigned int msb = inst.operands[1].imm + inst.operands[2].imm;
8740218822Sdim  constraint (msb > 32, _("bit-field extends past end of register"));
8741218822Sdim  /* The instruction encoding stores the LSB and MSB,
8742218822Sdim     not the LSB and width.  */
8743218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
8744218822Sdim  inst.instruction |= (inst.operands[1].imm & 0x1c) << 10;
8745218822Sdim  inst.instruction |= (inst.operands[1].imm & 0x03) << 6;
8746218822Sdim  inst.instruction |= msb - 1;
8747218822Sdim}
874860484Sobrien
8749218822Sdimstatic void
8750218822Sdimdo_t_bfi (void)
8751218822Sdim{
8752218822Sdim  unsigned int msb;
875360484Sobrien
8754218822Sdim  /* #0 in second position is alternative syntax for bfc, which is
8755218822Sdim     the same instruction but with REG_PC in the Rm field.  */
8756218822Sdim  if (!inst.operands[1].isreg)
8757218822Sdim    inst.operands[1].reg = REG_PC;
875860484Sobrien
8759218822Sdim  msb = inst.operands[2].imm + inst.operands[3].imm;
8760218822Sdim  constraint (msb > 32, _("bit-field extends past end of register"));
8761218822Sdim  /* The instruction encoding stores the LSB and MSB,
8762218822Sdim     not the LSB and width.  */
8763218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
8764218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
8765218822Sdim  inst.instruction |= (inst.operands[2].imm & 0x1c) << 10;
8766218822Sdim  inst.instruction |= (inst.operands[2].imm & 0x03) << 6;
8767218822Sdim  inst.instruction |= msb - 1;
8768218822Sdim}
876960484Sobrien
8770218822Sdimstatic void
8771218822Sdimdo_t_bfx (void)
8772218822Sdim{
8773218822Sdim  constraint (inst.operands[2].imm + inst.operands[3].imm > 32,
8774218822Sdim	      _("bit-field extends past end of register"));
8775218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
8776218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
8777218822Sdim  inst.instruction |= (inst.operands[2].imm & 0x1c) << 10;
8778218822Sdim  inst.instruction |= (inst.operands[2].imm & 0x03) << 6;
8779218822Sdim  inst.instruction |= inst.operands[3].imm - 1;
8780218822Sdim}
878160484Sobrien
8782218822Sdim/* ARM V5 Thumb BLX (argument parse)
8783218822Sdim	BLX <target_addr>	which is BLX(1)
8784218822Sdim	BLX <Rm>		which is BLX(2)
8785218822Sdim   Unfortunately, there are two different opcodes for this mnemonic.
8786218822Sdim   So, the insns[].value is not used, and the code here zaps values
8787218822Sdim	into inst.instruction.
878860484Sobrien
8789218822Sdim   ??? How to take advantage of the additional two bits of displacement
8790218822Sdim   available in Thumb32 mode?  Need new relocation?  */
8791218822Sdim
8792218822Sdimstatic void
8793218822Sdimdo_t_blx (void)
8794218822Sdim{
8795218822Sdim  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
8796218822Sdim  if (inst.operands[0].isreg)
8797218822Sdim    /* We have a register, so this is BLX(2).  */
8798218822Sdim    inst.instruction |= inst.operands[0].reg << 3;
8799218822Sdim  else
880060484Sobrien    {
8801218822Sdim      /* No register.  This must be BLX(1).  */
8802218822Sdim      inst.instruction = 0xf000e800;
8803218822Sdim#ifdef OBJ_ELF
8804218822Sdim      if (EF_ARM_EABI_VERSION (meabi_flags) >= EF_ARM_EABI_VER4)
8805218822Sdim	inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH23;
8806218822Sdim      else
8807218822Sdim#endif
8808218822Sdim	inst.reloc.type = BFD_RELOC_THUMB_PCREL_BLX;
8809218822Sdim      inst.reloc.pc_rel = 1;
881060484Sobrien    }
8811218822Sdim}
881260484Sobrien
8813218822Sdimstatic void
8814218822Sdimdo_t_branch (void)
8815218822Sdim{
8816218822Sdim  int opcode;
8817218822Sdim  int cond;
8818218822Sdim
8819218822Sdim  if (current_it_mask)
882060484Sobrien    {
8821218822Sdim      /* Conditional branches inside IT blocks are encoded as unconditional
8822218822Sdim         branches.  */
8823218822Sdim      cond = COND_ALWAYS;
8824218822Sdim      /* A branch must be the last instruction in an IT block.  */
8825218822Sdim      constraint (current_it_mask != 0x10, BAD_BRANCH);
882660484Sobrien    }
8827218822Sdim  else
8828218822Sdim    cond = inst.cond;
882960484Sobrien
8830218822Sdim  if (cond != COND_ALWAYS)
8831218822Sdim    opcode = T_MNEM_bcond;
8832218822Sdim  else
8833218822Sdim    opcode = inst.instruction;
8834218822Sdim
8835218822Sdim  if (unified_syntax && inst.size_req == 4)
8836130561Sobrien    {
8837218822Sdim      inst.instruction = THUMB_OP32(opcode);
8838218822Sdim      if (cond == COND_ALWAYS)
8839218822Sdim	inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH25;
8840218822Sdim      else
8841130561Sobrien	{
8842218822Sdim	  assert (cond != 0xF);
8843218822Sdim	  inst.instruction |= cond << 22;
8844218822Sdim	  inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH20;
8845130561Sobrien	}
8846218822Sdim    }
8847218822Sdim  else
8848218822Sdim    {
8849218822Sdim      inst.instruction = THUMB_OP16(opcode);
8850218822Sdim      if (cond == COND_ALWAYS)
8851218822Sdim	inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH12;
8852218822Sdim      else
8853130561Sobrien	{
8854218822Sdim	  inst.instruction |= cond << 8;
8855218822Sdim	  inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH9;
8856130561Sobrien	}
8857218822Sdim      /* Allow section relaxation.  */
8858218822Sdim      if (unified_syntax && inst.size_req != 2)
8859218822Sdim	inst.relax = opcode;
8860130561Sobrien    }
8861130561Sobrien
8862218822Sdim  inst.reloc.pc_rel = 1;
886360484Sobrien}
886460484Sobrien
886560484Sobrienstatic void
8866218822Sdimdo_t_bkpt (void)
886760484Sobrien{
8868218822Sdim  constraint (inst.cond != COND_ALWAYS,
8869218822Sdim	      _("instruction is always unconditional"));
8870218822Sdim  if (inst.operands[0].present)
8871218822Sdim    {
8872218822Sdim      constraint (inst.operands[0].imm > 255,
8873218822Sdim		  _("immediate value out of range"));
8874218822Sdim      inst.instruction |= inst.operands[0].imm;
8875218822Sdim    }
8876218822Sdim}
887777298Sobrien
8878218822Sdimstatic void
8879218822Sdimdo_t_branch23 (void)
8880218822Sdim{
8881218822Sdim  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
8882218822Sdim  inst.reloc.type   = BFD_RELOC_THUMB_PCREL_BRANCH23;
8883218822Sdim  inst.reloc.pc_rel = 1;
888460484Sobrien
8885218822Sdim  /* If the destination of the branch is a defined symbol which does not have
8886218822Sdim     the THUMB_FUNC attribute, then we must be calling a function which has
8887218822Sdim     the (interfacearm) attribute.  We look for the Thumb entry point to that
8888218822Sdim     function and change the branch to refer to that function instead.	*/
8889218822Sdim  if (	 inst.reloc.exp.X_op == O_symbol
8890218822Sdim      && inst.reloc.exp.X_add_symbol != NULL
8891218822Sdim      && S_IS_DEFINED (inst.reloc.exp.X_add_symbol)
8892218822Sdim      && ! THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol))
8893218822Sdim    inst.reloc.exp.X_add_symbol =
8894218822Sdim      find_real_start (inst.reloc.exp.X_add_symbol);
8895218822Sdim}
889660484Sobrien
8897218822Sdimstatic void
8898218822Sdimdo_t_bx (void)
8899218822Sdim{
8900218822Sdim  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
8901218822Sdim  inst.instruction |= inst.operands[0].reg << 3;
8902218822Sdim  /* ??? FIXME: Should add a hacky reloc here if reg is REG_PC.	 The reloc
8903218822Sdim     should cause the alignment to be checked once it is known.	 This is
8904218822Sdim     because BX PC only works if the instruction is word aligned.  */
890560484Sobrien}
890660484Sobrien
890760484Sobrienstatic void
8908218822Sdimdo_t_bxj (void)
890960484Sobrien{
8910218822Sdim  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
8911218822Sdim  if (inst.operands[0].reg == REG_PC)
8912218822Sdim    as_tsktsk (_("use of r15 in bxj is not really useful"));
891377298Sobrien
8914218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
8915218822Sdim}
891660484Sobrien
8917218822Sdimstatic void
8918218822Sdimdo_t_clz (void)
8919218822Sdim{
8920218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
8921218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
8922218822Sdim  inst.instruction |= inst.operands[1].reg;
8923218822Sdim}
892460484Sobrien
8925218822Sdimstatic void
8926218822Sdimdo_t_cps (void)
8927218822Sdim{
8928218822Sdim  constraint (current_it_mask, BAD_NOT_IT);
8929218822Sdim  inst.instruction |= inst.operands[0].imm;
8930218822Sdim}
893160484Sobrien
8932218822Sdimstatic void
8933218822Sdimdo_t_cpsi (void)
8934218822Sdim{
8935218822Sdim  constraint (current_it_mask, BAD_NOT_IT);
8936218822Sdim  if (unified_syntax
8937218822Sdim      && (inst.operands[1].present || inst.size_req == 4)
8938218822Sdim      && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6_notm))
893960484Sobrien    {
8940218822Sdim      unsigned int imod = (inst.instruction & 0x0030) >> 4;
8941218822Sdim      inst.instruction = 0xf3af8000;
8942218822Sdim      inst.instruction |= imod << 9;
8943218822Sdim      inst.instruction |= inst.operands[0].imm << 5;
8944218822Sdim      if (inst.operands[1].present)
8945218822Sdim	inst.instruction |= 0x100 | inst.operands[1].imm;
894660484Sobrien    }
8947218822Sdim  else
894860484Sobrien    {
8949218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1)
8950218822Sdim		  && (inst.operands[0].imm & 4),
8951218822Sdim		  _("selected processor does not support 'A' form "
8952218822Sdim		    "of this instruction"));
8953218822Sdim      constraint (inst.operands[1].present || inst.size_req == 4,
8954218822Sdim		  _("Thumb does not support the 2-argument "
8955218822Sdim		    "form of this instruction"));
8956218822Sdim      inst.instruction |= inst.operands[0].imm;
895760484Sobrien    }
8958218822Sdim}
895960484Sobrien
8960218822Sdim/* THUMB CPY instruction (argument parse).  */
896160484Sobrien
8962218822Sdimstatic void
8963218822Sdimdo_t_cpy (void)
8964218822Sdim{
8965218822Sdim  if (inst.size_req == 4)
896660484Sobrien    {
8967218822Sdim      inst.instruction = THUMB_OP32 (T_MNEM_mov);
8968218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
8969218822Sdim      inst.instruction |= inst.operands[1].reg;
897060484Sobrien    }
8971218822Sdim  else
897260484Sobrien    {
8973218822Sdim      inst.instruction |= (inst.operands[0].reg & 0x8) << 4;
8974218822Sdim      inst.instruction |= (inst.operands[0].reg & 0x7);
8975218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
897660484Sobrien    }
8977218822Sdim}
897860484Sobrien
8979218822Sdimstatic void
8980218822Sdimdo_t_cbz (void)
8981218822Sdim{
8982218822Sdim  constraint (current_it_mask, BAD_NOT_IT);
8983218822Sdim  constraint (inst.operands[0].reg > 7, BAD_HIREG);
8984218822Sdim  inst.instruction |= inst.operands[0].reg;
8985218822Sdim  inst.reloc.pc_rel = 1;
8986218822Sdim  inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH7;
898760484Sobrien}
898860484Sobrien
898960484Sobrienstatic void
8990218822Sdimdo_t_dbg (void)
899160484Sobrien{
8992218822Sdim  inst.instruction |= inst.operands[0].imm;
8993218822Sdim}
899477298Sobrien
8995218822Sdimstatic void
8996218822Sdimdo_t_div (void)
8997218822Sdim{
8998218822Sdim  if (!inst.operands[1].present)
8999218822Sdim    inst.operands[1].reg = inst.operands[0].reg;
9000218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
9001218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
9002218822Sdim  inst.instruction |= inst.operands[2].reg;
9003218822Sdim}
900477298Sobrien
9005218822Sdimstatic void
9006218822Sdimdo_t_hint (void)
9007218822Sdim{
9008218822Sdim  if (unified_syntax && inst.size_req == 4)
9009218822Sdim    inst.instruction = THUMB_OP32 (inst.instruction);
9010218822Sdim  else
9011218822Sdim    inst.instruction = THUMB_OP16 (inst.instruction);
901260484Sobrien}
901360484Sobrien
901460484Sobrienstatic void
9015218822Sdimdo_t_it (void)
901660484Sobrien{
9017218822Sdim  unsigned int cond = inst.operands[0].imm;
901860484Sobrien
9019218822Sdim  constraint (current_it_mask, BAD_NOT_IT);
9020218822Sdim  current_it_mask = (inst.instruction & 0xf) | 0x10;
9021218822Sdim  current_cc = cond;
902260484Sobrien
9023218822Sdim  /* If the condition is a negative condition, invert the mask.  */
9024218822Sdim  if ((cond & 0x1) == 0x0)
902560484Sobrien    {
9026218822Sdim      unsigned int mask = inst.instruction & 0x000f;
9027218822Sdim
9028218822Sdim      if ((mask & 0x7) == 0)
9029218822Sdim	/* no conversion needed */;
9030218822Sdim      else if ((mask & 0x3) == 0)
9031218822Sdim	mask ^= 0x8;
9032218822Sdim      else if ((mask & 0x1) == 0)
9033218822Sdim	mask ^= 0xC;
9034218822Sdim      else
9035218822Sdim	mask ^= 0xE;
9036218822Sdim
9037218822Sdim      inst.instruction &= 0xfff0;
9038218822Sdim      inst.instruction |= mask;
903960484Sobrien    }
904060484Sobrien
9041218822Sdim  inst.instruction |= cond << 4;
904260484Sobrien}
904360484Sobrien
9044218822Sdim/* Helper function used for both push/pop and ldm/stm.  */
904560484Sobrienstatic void
9046218822Sdimencode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback)
904760484Sobrien{
9048218822Sdim  bfd_boolean load;
904960484Sobrien
9050218822Sdim  load = (inst.instruction & (1 << 20)) != 0;
905160484Sobrien
9052218822Sdim  if (mask & (1 << 13))
9053218822Sdim    inst.error =  _("SP not allowed in register list");
9054218822Sdim  if (load)
905560484Sobrien    {
9056218822Sdim      if (mask & (1 << 14)
9057218822Sdim	  && mask & (1 << 15))
9058218822Sdim	inst.error = _("LR and PC should not both be in register list");
905960484Sobrien
9060218822Sdim      if ((mask & (1 << base)) != 0
9061218822Sdim	  && writeback)
9062218822Sdim	as_warn (_("base register should not be in register list "
9063218822Sdim		   "when written back"));
906460484Sobrien    }
9065218822Sdim  else
906660484Sobrien    {
9067218822Sdim      if (mask & (1 << 15))
9068218822Sdim	inst.error = _("PC not allowed in register list");
906960484Sobrien
9070218822Sdim      if (mask & (1 << base))
9071218822Sdim	as_warn (_("value stored for r%d is UNPREDICTABLE"), base);
907260484Sobrien    }
907360484Sobrien
9074218822Sdim  if ((mask & (mask - 1)) == 0)
907560484Sobrien    {
9076218822Sdim      /* Single register transfers implemented as str/ldr.  */
9077218822Sdim      if (writeback)
907860484Sobrien	{
9079218822Sdim	  if (inst.instruction & (1 << 23))
9080218822Sdim	    inst.instruction = 0x00000b04; /* ia! -> [base], #4 */
9081218822Sdim	  else
9082218822Sdim	    inst.instruction = 0x00000d04; /* db! -> [base, #-4]! */
908360484Sobrien	}
9084218822Sdim      else
9085218822Sdim	{
9086218822Sdim	  if (inst.instruction & (1 << 23))
9087218822Sdim	    inst.instruction = 0x00800000; /* ia -> [base] */
9088218822Sdim	  else
9089218822Sdim	    inst.instruction = 0x00000c04; /* db -> [base, #-4] */
9090218822Sdim	}
909160484Sobrien
9092218822Sdim      inst.instruction |= 0xf8400000;
9093218822Sdim      if (load)
9094218822Sdim	inst.instruction |= 0x00100000;
909560484Sobrien
9096218822Sdim      mask = ffs(mask) - 1;
9097218822Sdim      mask <<= 12;
909860484Sobrien    }
9099218822Sdim  else if (writeback)
9100218822Sdim    inst.instruction |= WRITE_BACK;
910160484Sobrien
9102218822Sdim  inst.instruction |= mask;
9103218822Sdim  inst.instruction |= base << 16;
910460484Sobrien}
910560484Sobrien
910660484Sobrienstatic void
9107218822Sdimdo_t_ldmstm (void)
910860484Sobrien{
9109218822Sdim  /* This really doesn't seem worth it.  */
9110218822Sdim  constraint (inst.reloc.type != BFD_RELOC_UNUSED,
9111218822Sdim	      _("expression too complex"));
9112218822Sdim  constraint (inst.operands[1].writeback,
9113218822Sdim	      _("Thumb load/store multiple does not support {reglist}^"));
911460484Sobrien
9115218822Sdim  if (unified_syntax)
911660484Sobrien    {
9117218822Sdim      bfd_boolean narrow;
9118218822Sdim      unsigned mask;
911960484Sobrien
9120218822Sdim      narrow = FALSE;
9121218822Sdim      /* See if we can use a 16-bit instruction.  */
9122218822Sdim      if (inst.instruction < 0xffff /* not ldmdb/stmdb */
9123218822Sdim	  && inst.size_req != 4
9124218822Sdim	  && !(inst.operands[1].imm & ~0xff))
9125218822Sdim	{
9126218822Sdim	  mask = 1 << inst.operands[0].reg;
912760484Sobrien
9128218822Sdim	  if (inst.operands[0].reg <= 7
9129218822Sdim	      && (inst.instruction == T_MNEM_stmia
9130218822Sdim		  ? inst.operands[0].writeback
9131218822Sdim		  : (inst.operands[0].writeback
9132218822Sdim		     == !(inst.operands[1].imm & mask))))
9133218822Sdim	    {
9134218822Sdim	      if (inst.instruction == T_MNEM_stmia
9135218822Sdim		  && (inst.operands[1].imm & mask)
9136218822Sdim		  && (inst.operands[1].imm & (mask - 1)))
9137218822Sdim		as_warn (_("value stored for r%d is UNPREDICTABLE"),
9138218822Sdim			 inst.operands[0].reg);
913960484Sobrien
9140218822Sdim	      inst.instruction = THUMB_OP16 (inst.instruction);
9141218822Sdim	      inst.instruction |= inst.operands[0].reg << 8;
9142218822Sdim	      inst.instruction |= inst.operands[1].imm;
9143218822Sdim	      narrow = TRUE;
9144218822Sdim	    }
9145218822Sdim	  else if (inst.operands[0] .reg == REG_SP
9146218822Sdim		   && inst.operands[0].writeback)
9147218822Sdim	    {
9148218822Sdim	      inst.instruction = THUMB_OP16 (inst.instruction == T_MNEM_stmia
9149218822Sdim					     ? T_MNEM_push : T_MNEM_pop);
9150218822Sdim	      inst.instruction |= inst.operands[1].imm;
9151218822Sdim	      narrow = TRUE;
9152218822Sdim	    }
9153218822Sdim	}
915460484Sobrien
9155218822Sdim      if (!narrow)
9156218822Sdim	{
9157218822Sdim	  if (inst.instruction < 0xffff)
9158218822Sdim	    inst.instruction = THUMB_OP32 (inst.instruction);
9159218822Sdim
9160218822Sdim	  encode_thumb2_ldmstm(inst.operands[0].reg, inst.operands[1].imm,
9161218822Sdim			       inst.operands[0].writeback);
9162218822Sdim	}
916360484Sobrien    }
9164218822Sdim  else
916560484Sobrien    {
9166218822Sdim      constraint (inst.operands[0].reg > 7
9167218822Sdim		  || (inst.operands[1].imm & ~0xff), BAD_HIREG);
9168218822Sdim      constraint (inst.instruction != T_MNEM_ldmia
9169218822Sdim		  && inst.instruction != T_MNEM_stmia,
9170218822Sdim		  _("Thumb-2 instruction only valid in unified syntax"));
9171218822Sdim      if (inst.instruction == T_MNEM_stmia)
917260484Sobrien	{
9173218822Sdim	  if (!inst.operands[0].writeback)
9174218822Sdim	    as_warn (_("this instruction will write back the base register"));
9175218822Sdim	  if ((inst.operands[1].imm & (1 << inst.operands[0].reg))
9176218822Sdim	      && (inst.operands[1].imm & ((1 << inst.operands[0].reg) - 1)))
9177218822Sdim	    as_warn (_("value stored for r%d is UNPREDICTABLE"),
9178218822Sdim		     inst.operands[0].reg);
917960484Sobrien	}
9180218822Sdim      else
9181218822Sdim	{
9182218822Sdim	  if (!inst.operands[0].writeback
9183218822Sdim	      && !(inst.operands[1].imm & (1 << inst.operands[0].reg)))
9184218822Sdim	    as_warn (_("this instruction will write back the base register"));
9185218822Sdim	  else if (inst.operands[0].writeback
9186218822Sdim		   && (inst.operands[1].imm & (1 << inst.operands[0].reg)))
9187218822Sdim	    as_warn (_("this instruction will not write back the base register"));
9188218822Sdim	}
9189218822Sdim
9190218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
9191218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
9192218822Sdim      inst.instruction |= inst.operands[1].imm;
919360484Sobrien    }
919460484Sobrien}
919560484Sobrien
919660484Sobrienstatic void
9197218822Sdimdo_t_ldrex (void)
919860484Sobrien{
9199218822Sdim  constraint (!inst.operands[1].isreg || !inst.operands[1].preind
9200218822Sdim	      || inst.operands[1].postind || inst.operands[1].writeback
9201218822Sdim	      || inst.operands[1].immisreg || inst.operands[1].shifted
9202218822Sdim	      || inst.operands[1].negative,
9203218822Sdim	      BAD_ADDR_MODE);
920460484Sobrien
9205218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9206218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
9207218822Sdim  inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_U8;
9208218822Sdim}
920960484Sobrien
9210218822Sdimstatic void
9211218822Sdimdo_t_ldrexd (void)
9212218822Sdim{
9213218822Sdim  if (!inst.operands[1].present)
921460484Sobrien    {
9215218822Sdim      constraint (inst.operands[0].reg == REG_LR,
9216218822Sdim		  _("r14 not allowed as first register "
9217218822Sdim		    "when second register is omitted"));
9218218822Sdim      inst.operands[1].reg = inst.operands[0].reg + 1;
921960484Sobrien    }
9220218822Sdim  constraint (inst.operands[0].reg == inst.operands[1].reg,
9221218822Sdim	      BAD_OVERLAP);
922260484Sobrien
9223218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9224218822Sdim  inst.instruction |= inst.operands[1].reg << 8;
9225218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
922660484Sobrien}
922760484Sobrien
922860484Sobrienstatic void
9229218822Sdimdo_t_ldst (void)
923060484Sobrien{
9231218822Sdim  unsigned long opcode;
9232218822Sdim  int Rn;
923360484Sobrien
9234218822Sdim  opcode = inst.instruction;
9235218822Sdim  if (unified_syntax)
923660484Sobrien    {
9237218822Sdim      if (!inst.operands[1].isreg)
9238218822Sdim	{
9239218822Sdim	  if (opcode <= 0xffff)
9240218822Sdim	    inst.instruction = THUMB_OP32 (opcode);
9241218822Sdim	  if (move_or_literal_pool (0, /*thumb_p=*/TRUE, /*mode_3=*/FALSE))
9242218822Sdim	    return;
9243218822Sdim	}
9244218822Sdim      if (inst.operands[1].isreg
9245218822Sdim	  && !inst.operands[1].writeback
9246218822Sdim	  && !inst.operands[1].shifted && !inst.operands[1].postind
9247218822Sdim	  && !inst.operands[1].negative && inst.operands[0].reg <= 7
9248218822Sdim	  && opcode <= 0xffff
9249218822Sdim	  && inst.size_req != 4)
9250218822Sdim	{
9251218822Sdim	  /* Insn may have a 16-bit form.  */
9252218822Sdim	  Rn = inst.operands[1].reg;
9253218822Sdim	  if (inst.operands[1].immisreg)
9254218822Sdim	    {
9255218822Sdim	      inst.instruction = THUMB_OP16 (opcode);
9256218822Sdim	      /* [Rn, Ri] */
9257218822Sdim	      if (Rn <= 7 && inst.operands[1].imm <= 7)
9258218822Sdim		goto op16;
9259218822Sdim	    }
9260218822Sdim	  else if ((Rn <= 7 && opcode != T_MNEM_ldrsh
9261218822Sdim		    && opcode != T_MNEM_ldrsb)
9262218822Sdim		   || ((Rn == REG_PC || Rn == REG_SP) && opcode == T_MNEM_ldr)
9263218822Sdim		   || (Rn == REG_SP && opcode == T_MNEM_str))
9264218822Sdim	    {
9265218822Sdim	      /* [Rn, #const] */
9266218822Sdim	      if (Rn > 7)
9267218822Sdim		{
9268218822Sdim		  if (Rn == REG_PC)
9269218822Sdim		    {
9270218822Sdim		      if (inst.reloc.pc_rel)
9271218822Sdim			opcode = T_MNEM_ldr_pc2;
9272218822Sdim		      else
9273218822Sdim			opcode = T_MNEM_ldr_pc;
9274218822Sdim		    }
9275218822Sdim		  else
9276218822Sdim		    {
9277218822Sdim		      if (opcode == T_MNEM_ldr)
9278218822Sdim			opcode = T_MNEM_ldr_sp;
9279218822Sdim		      else
9280218822Sdim			opcode = T_MNEM_str_sp;
9281218822Sdim		    }
9282218822Sdim		  inst.instruction = inst.operands[0].reg << 8;
9283218822Sdim		}
9284218822Sdim	      else
9285218822Sdim		{
9286218822Sdim		  inst.instruction = inst.operands[0].reg;
9287218822Sdim		  inst.instruction |= inst.operands[1].reg << 3;
9288218822Sdim		}
9289218822Sdim	      inst.instruction |= THUMB_OP16 (opcode);
9290218822Sdim	      if (inst.size_req == 2)
9291218822Sdim		inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
9292218822Sdim	      else
9293218822Sdim		inst.relax = opcode;
9294218822Sdim	      return;
9295218822Sdim	    }
9296218822Sdim	}
9297218822Sdim      /* Definitely a 32-bit variant.  */
9298218822Sdim      inst.instruction = THUMB_OP32 (opcode);
9299218822Sdim      inst.instruction |= inst.operands[0].reg << 12;
9300218822Sdim      encode_thumb32_addr_mode (1, /*is_t=*/FALSE, /*is_d=*/FALSE);
930160484Sobrien      return;
930260484Sobrien    }
930360484Sobrien
9304218822Sdim  constraint (inst.operands[0].reg > 7, BAD_HIREG);
9305218822Sdim
9306218822Sdim  if (inst.instruction == T_MNEM_ldrsh || inst.instruction == T_MNEM_ldrsb)
930760484Sobrien    {
9308218822Sdim      /* Only [Rn,Rm] is acceptable.  */
9309218822Sdim      constraint (inst.operands[1].reg > 7 || inst.operands[1].imm > 7, BAD_HIREG);
9310218822Sdim      constraint (!inst.operands[1].isreg || !inst.operands[1].immisreg
9311218822Sdim		  || inst.operands[1].postind || inst.operands[1].shifted
9312218822Sdim		  || inst.operands[1].negative,
9313218822Sdim		  _("Thumb does not support this addressing mode"));
9314218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
9315218822Sdim      goto op16;
9316218822Sdim    }
9317218822Sdim
9318218822Sdim  inst.instruction = THUMB_OP16 (inst.instruction);
9319218822Sdim  if (!inst.operands[1].isreg)
9320218822Sdim    if (move_or_literal_pool (0, /*thumb_p=*/TRUE, /*mode_3=*/FALSE))
932160484Sobrien      return;
932260484Sobrien
9323218822Sdim  constraint (!inst.operands[1].preind
9324218822Sdim	      || inst.operands[1].shifted
9325218822Sdim	      || inst.operands[1].writeback,
9326218822Sdim	      _("Thumb does not support this addressing mode"));
9327218822Sdim  if (inst.operands[1].reg == REG_PC || inst.operands[1].reg == REG_SP)
9328218822Sdim    {
9329218822Sdim      constraint (inst.instruction & 0x0600,
9330218822Sdim		  _("byte or halfword not valid for base register"));
9331218822Sdim      constraint (inst.operands[1].reg == REG_PC
9332218822Sdim		  && !(inst.instruction & THUMB_LOAD_BIT),
9333218822Sdim		  _("r15 based store not allowed"));
9334218822Sdim      constraint (inst.operands[1].immisreg,
9335218822Sdim		  _("invalid base register for register offset"));
933660484Sobrien
9337218822Sdim      if (inst.operands[1].reg == REG_PC)
9338218822Sdim	inst.instruction = T_OPCODE_LDR_PC;
9339218822Sdim      else if (inst.instruction & THUMB_LOAD_BIT)
9340218822Sdim	inst.instruction = T_OPCODE_LDR_SP;
9341218822Sdim      else
9342218822Sdim	inst.instruction = T_OPCODE_STR_SP;
934360484Sobrien
9344218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
9345218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
934660484Sobrien      return;
934760484Sobrien    }
934860484Sobrien
9349218822Sdim  constraint (inst.operands[1].reg > 7, BAD_HIREG);
9350218822Sdim  if (!inst.operands[1].immisreg)
935160484Sobrien    {
9352218822Sdim      /* Immediate offset.  */
9353218822Sdim      inst.instruction |= inst.operands[0].reg;
9354218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
9355218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
935660484Sobrien      return;
935760484Sobrien    }
935860484Sobrien
9359218822Sdim  /* Register offset.  */
9360218822Sdim  constraint (inst.operands[1].imm > 7, BAD_HIREG);
9361218822Sdim  constraint (inst.operands[1].negative,
9362218822Sdim	      _("Thumb does not support this addressing mode"));
9363218822Sdim
9364218822Sdim op16:
9365218822Sdim  switch (inst.instruction)
936660484Sobrien    {
9367218822Sdim    case T_OPCODE_STR_IW: inst.instruction = T_OPCODE_STR_RW; break;
9368218822Sdim    case T_OPCODE_STR_IH: inst.instruction = T_OPCODE_STR_RH; break;
9369218822Sdim    case T_OPCODE_STR_IB: inst.instruction = T_OPCODE_STR_RB; break;
9370218822Sdim    case T_OPCODE_LDR_IW: inst.instruction = T_OPCODE_LDR_RW; break;
9371218822Sdim    case T_OPCODE_LDR_IH: inst.instruction = T_OPCODE_LDR_RH; break;
9372218822Sdim    case T_OPCODE_LDR_IB: inst.instruction = T_OPCODE_LDR_RB; break;
9373218822Sdim    case 0x5600 /* ldrsb */:
9374218822Sdim    case 0x5e00 /* ldrsh */: break;
9375218822Sdim    default: abort ();
937660484Sobrien    }
937760484Sobrien
9378218822Sdim  inst.instruction |= inst.operands[0].reg;
9379218822Sdim  inst.instruction |= inst.operands[1].reg << 3;
9380218822Sdim  inst.instruction |= inst.operands[1].imm << 6;
9381218822Sdim}
938260484Sobrien
9383218822Sdimstatic void
9384218822Sdimdo_t_ldstd (void)
9385218822Sdim{
9386218822Sdim  if (!inst.operands[1].present)
938760484Sobrien    {
9388218822Sdim      inst.operands[1].reg = inst.operands[0].reg + 1;
9389218822Sdim      constraint (inst.operands[0].reg == REG_LR,
9390218822Sdim		  _("r14 not allowed here"));
939160484Sobrien    }
9392218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9393218822Sdim  inst.instruction |= inst.operands[1].reg << 8;
9394218822Sdim  encode_thumb32_addr_mode (2, /*is_t=*/FALSE, /*is_d=*/TRUE);
9395218822Sdim
9396218822Sdim}
939760484Sobrien
9398218822Sdimstatic void
9399218822Sdimdo_t_ldstt (void)
9400218822Sdim{
9401218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9402218822Sdim  encode_thumb32_addr_mode (1, /*is_t=*/TRUE, /*is_d=*/FALSE);
9403218822Sdim}
940460484Sobrien
9405218822Sdimstatic void
9406218822Sdimdo_t_mla (void)
9407218822Sdim{
9408218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
9409218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
9410218822Sdim  inst.instruction |= inst.operands[2].reg;
9411218822Sdim  inst.instruction |= inst.operands[3].reg << 12;
9412218822Sdim}
941360484Sobrien
9414218822Sdimstatic void
9415218822Sdimdo_t_mlal (void)
9416218822Sdim{
9417218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9418218822Sdim  inst.instruction |= inst.operands[1].reg << 8;
9419218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
9420218822Sdim  inst.instruction |= inst.operands[3].reg;
9421218822Sdim}
942260484Sobrien
9423218822Sdimstatic void
9424218822Sdimdo_t_mov_cmp (void)
9425218822Sdim{
9426218822Sdim  if (unified_syntax)
9427218822Sdim    {
9428218822Sdim      int r0off = (inst.instruction == T_MNEM_mov
9429218822Sdim		   || inst.instruction == T_MNEM_movs) ? 8 : 16;
9430218822Sdim      unsigned long opcode;
9431218822Sdim      bfd_boolean narrow;
9432218822Sdim      bfd_boolean low_regs;
943360484Sobrien
9434218822Sdim      low_regs = (inst.operands[0].reg <= 7 && inst.operands[1].reg <= 7);
9435218822Sdim      opcode = inst.instruction;
9436218822Sdim      if (current_it_mask)
9437218822Sdim	narrow = opcode != T_MNEM_movs;
9438218822Sdim      else
9439218822Sdim	narrow = opcode != T_MNEM_movs || low_regs;
9440218822Sdim      if (inst.size_req == 4
9441218822Sdim	  || inst.operands[1].shifted)
9442218822Sdim	narrow = FALSE;
944360484Sobrien
9444218822Sdim      /* MOVS PC, LR is encoded as SUBS PC, LR, #0.  */
9445218822Sdim      if (opcode == T_MNEM_movs && inst.operands[1].isreg
9446218822Sdim	  && !inst.operands[1].shifted
9447218822Sdim	  && inst.operands[0].reg == REG_PC
9448218822Sdim	  && inst.operands[1].reg == REG_LR)
944960484Sobrien	{
9450218822Sdim	  inst.instruction = T2_SUBS_PC_LR;
945160484Sobrien	  return;
945260484Sobrien	}
945360484Sobrien
9454218822Sdim      if (!inst.operands[1].isreg)
945560484Sobrien	{
9456218822Sdim	  /* Immediate operand.  */
9457218822Sdim	  if (current_it_mask == 0 && opcode == T_MNEM_mov)
9458218822Sdim	    narrow = 0;
9459218822Sdim	  if (low_regs && narrow)
946060484Sobrien	    {
9461218822Sdim	      inst.instruction = THUMB_OP16 (opcode);
9462218822Sdim	      inst.instruction |= inst.operands[0].reg << 8;
9463218822Sdim	      if (inst.size_req == 2)
9464218822Sdim		inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
9465218822Sdim	      else
9466218822Sdim		inst.relax = opcode;
946760484Sobrien	    }
9468218822Sdim	  else
9469218822Sdim	    {
9470218822Sdim	      inst.instruction = THUMB_OP32 (inst.instruction);
9471218822Sdim	      inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
9472218822Sdim	      inst.instruction |= inst.operands[0].reg << r0off;
9473218822Sdim	      inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
9474218822Sdim	    }
947560484Sobrien	}
9476218822Sdim      else if (inst.operands[1].shifted && inst.operands[1].immisreg
9477218822Sdim	       && (inst.instruction == T_MNEM_mov
9478218822Sdim		   || inst.instruction == T_MNEM_movs))
9479218822Sdim	{
9480218822Sdim	  /* Register shifts are encoded as separate shift instructions.  */
9481218822Sdim	  bfd_boolean flags = (inst.instruction == T_MNEM_movs);
948260484Sobrien
9483218822Sdim	  if (current_it_mask)
9484218822Sdim	    narrow = !flags;
9485218822Sdim	  else
9486218822Sdim	    narrow = flags;
9487218822Sdim
9488218822Sdim	  if (inst.size_req == 4)
9489218822Sdim	    narrow = FALSE;
9490218822Sdim
9491218822Sdim	  if (!low_regs || inst.operands[1].imm > 7)
9492218822Sdim	    narrow = FALSE;
9493218822Sdim
9494218822Sdim	  if (inst.operands[0].reg != inst.operands[1].reg)
9495218822Sdim	    narrow = FALSE;
9496218822Sdim
9497218822Sdim	  switch (inst.operands[1].shift_kind)
9498218822Sdim	    {
9499218822Sdim	    case SHIFT_LSL:
9500218822Sdim	      opcode = narrow ? T_OPCODE_LSL_R : THUMB_OP32 (T_MNEM_lsl);
9501218822Sdim	      break;
9502218822Sdim	    case SHIFT_ASR:
9503218822Sdim	      opcode = narrow ? T_OPCODE_ASR_R : THUMB_OP32 (T_MNEM_asr);
9504218822Sdim	      break;
9505218822Sdim	    case SHIFT_LSR:
9506218822Sdim	      opcode = narrow ? T_OPCODE_LSR_R : THUMB_OP32 (T_MNEM_lsr);
9507218822Sdim	      break;
9508218822Sdim	    case SHIFT_ROR:
9509218822Sdim	      opcode = narrow ? T_OPCODE_ROR_R : THUMB_OP32 (T_MNEM_ror);
9510218822Sdim	      break;
9511218822Sdim	    default:
9512218822Sdim	      abort();
9513218822Sdim	    }
9514218822Sdim
9515218822Sdim	  inst.instruction = opcode;
9516218822Sdim	  if (narrow)
9517218822Sdim	    {
9518218822Sdim	      inst.instruction |= inst.operands[0].reg;
9519218822Sdim	      inst.instruction |= inst.operands[1].imm << 3;
9520218822Sdim	    }
9521218822Sdim	  else
9522218822Sdim	    {
9523218822Sdim	      if (flags)
9524218822Sdim		inst.instruction |= CONDS_BIT;
9525218822Sdim
9526218822Sdim	      inst.instruction |= inst.operands[0].reg << 8;
9527218822Sdim	      inst.instruction |= inst.operands[1].reg << 16;
9528218822Sdim	      inst.instruction |= inst.operands[1].imm;
9529218822Sdim	    }
953060484Sobrien	}
9531218822Sdim      else if (!narrow)
953260484Sobrien	{
9533218822Sdim	  /* Some mov with immediate shift have narrow variants.
9534218822Sdim	     Register shifts are handled above.  */
9535218822Sdim	  if (low_regs && inst.operands[1].shifted
9536218822Sdim	      && (inst.instruction == T_MNEM_mov
9537218822Sdim		  || inst.instruction == T_MNEM_movs))
953860484Sobrien	    {
9539218822Sdim	      if (current_it_mask)
9540218822Sdim		narrow = (inst.instruction == T_MNEM_mov);
9541218822Sdim	      else
9542218822Sdim		narrow = (inst.instruction == T_MNEM_movs);
954360484Sobrien	    }
9544218822Sdim
9545218822Sdim	  if (narrow)
9546218822Sdim	    {
9547218822Sdim	      switch (inst.operands[1].shift_kind)
9548218822Sdim		{
9549218822Sdim		case SHIFT_LSL: inst.instruction = T_OPCODE_LSL_I; break;
9550218822Sdim		case SHIFT_LSR: inst.instruction = T_OPCODE_LSR_I; break;
9551218822Sdim		case SHIFT_ASR: inst.instruction = T_OPCODE_ASR_I; break;
9552218822Sdim		default: narrow = FALSE; break;
9553218822Sdim		}
9554218822Sdim	    }
9555218822Sdim
9556218822Sdim	  if (narrow)
9557218822Sdim	    {
9558218822Sdim	      inst.instruction |= inst.operands[0].reg;
9559218822Sdim	      inst.instruction |= inst.operands[1].reg << 3;
9560218822Sdim	      inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
9561218822Sdim	    }
956260484Sobrien	  else
956360484Sobrien	    {
9564218822Sdim	      inst.instruction = THUMB_OP32 (inst.instruction);
9565218822Sdim	      inst.instruction |= inst.operands[0].reg << r0off;
9566218822Sdim	      encode_thumb32_shifted_operand (1);
956760484Sobrien	    }
956860484Sobrien	}
9569218822Sdim      else
9570218822Sdim	switch (inst.instruction)
9571218822Sdim	  {
9572218822Sdim	  case T_MNEM_mov:
9573218822Sdim	    inst.instruction = T_OPCODE_MOV_HR;
9574218822Sdim	    inst.instruction |= (inst.operands[0].reg & 0x8) << 4;
9575218822Sdim	    inst.instruction |= (inst.operands[0].reg & 0x7);
9576218822Sdim	    inst.instruction |= inst.operands[1].reg << 3;
9577218822Sdim	    break;
957860484Sobrien
9579218822Sdim	  case T_MNEM_movs:
9580218822Sdim	    /* We know we have low registers at this point.
9581218822Sdim	       Generate ADD Rd, Rs, #0.  */
9582218822Sdim	    inst.instruction = T_OPCODE_ADD_I3;
9583218822Sdim	    inst.instruction |= inst.operands[0].reg;
9584218822Sdim	    inst.instruction |= inst.operands[1].reg << 3;
9585218822Sdim	    break;
9586218822Sdim
9587218822Sdim	  case T_MNEM_cmp:
9588218822Sdim	    if (low_regs)
9589218822Sdim	      {
9590218822Sdim		inst.instruction = T_OPCODE_CMP_LR;
9591218822Sdim		inst.instruction |= inst.operands[0].reg;
9592218822Sdim		inst.instruction |= inst.operands[1].reg << 3;
9593218822Sdim	      }
9594218822Sdim	    else
9595218822Sdim	      {
9596218822Sdim		inst.instruction = T_OPCODE_CMP_HR;
9597218822Sdim		inst.instruction |= (inst.operands[0].reg & 0x8) << 4;
9598218822Sdim		inst.instruction |= (inst.operands[0].reg & 0x7);
9599218822Sdim		inst.instruction |= inst.operands[1].reg << 3;
9600218822Sdim	      }
9601218822Sdim	    break;
9602218822Sdim	  }
9603218822Sdim      return;
960460484Sobrien    }
9605218822Sdim
9606218822Sdim  inst.instruction = THUMB_OP16 (inst.instruction);
9607218822Sdim  if (inst.operands[1].isreg)
960860484Sobrien    {
9609218822Sdim      if (inst.operands[0].reg < 8 && inst.operands[1].reg < 8)
9610218822Sdim	{
9611218822Sdim	  /* A move of two lowregs is encoded as ADD Rd, Rs, #0
9612218822Sdim	     since a MOV instruction produces unpredictable results.  */
9613218822Sdim	  if (inst.instruction == T_OPCODE_MOV_I8)
9614218822Sdim	    inst.instruction = T_OPCODE_ADD_I3;
9615218822Sdim	  else
9616218822Sdim	    inst.instruction = T_OPCODE_CMP_LR;
9617218822Sdim
9618218822Sdim	  inst.instruction |= inst.operands[0].reg;
9619218822Sdim	  inst.instruction |= inst.operands[1].reg << 3;
9620218822Sdim	}
9621218822Sdim      else
9622218822Sdim	{
9623218822Sdim	  if (inst.instruction == T_OPCODE_MOV_I8)
9624218822Sdim	    inst.instruction = T_OPCODE_MOV_HR;
9625218822Sdim	  else
9626218822Sdim	    inst.instruction = T_OPCODE_CMP_HR;
9627218822Sdim	  do_t_cpy ();
9628218822Sdim	}
962960484Sobrien    }
9630218822Sdim  else
9631218822Sdim    {
9632218822Sdim      constraint (inst.operands[0].reg > 7,
9633218822Sdim		  _("only lo regs allowed with immediate"));
9634218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
9635218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
9636218822Sdim    }
963760484Sobrien}
963860484Sobrien
963960484Sobrienstatic void
9640218822Sdimdo_t_mov16 (void)
964160484Sobrien{
9642218822Sdim  bfd_vma imm;
9643218822Sdim  bfd_boolean top;
964460484Sobrien
9645218822Sdim  top = (inst.instruction & 0x00800000) != 0;
9646218822Sdim  if (inst.reloc.type == BFD_RELOC_ARM_MOVW)
964760484Sobrien    {
9648218822Sdim      constraint (top, _(":lower16: not allowed this instruction"));
9649218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVW;
965060484Sobrien    }
9651218822Sdim  else if (inst.reloc.type == BFD_RELOC_ARM_MOVT)
965260484Sobrien    {
9653218822Sdim      constraint (!top, _(":upper16: not allowed this instruction"));
9654218822Sdim      inst.reloc.type = BFD_RELOC_ARM_THUMB_MOVT;
965560484Sobrien    }
965660484Sobrien
9657218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
9658218822Sdim  if (inst.reloc.type == BFD_RELOC_UNUSED)
965960484Sobrien    {
9660218822Sdim      imm = inst.reloc.exp.X_add_number;
9661218822Sdim      inst.instruction |= (imm & 0xf000) << 4;
9662218822Sdim      inst.instruction |= (imm & 0x0800) << 15;
9663218822Sdim      inst.instruction |= (imm & 0x0700) << 4;
9664218822Sdim      inst.instruction |= (imm & 0x00ff);
966560484Sobrien    }
966660484Sobrien}
966760484Sobrien
966860484Sobrienstatic void
9669218822Sdimdo_t_mvn_tst (void)
967060484Sobrien{
9671218822Sdim  if (unified_syntax)
9672218822Sdim    {
9673218822Sdim      int r0off = (inst.instruction == T_MNEM_mvn
9674218822Sdim		   || inst.instruction == T_MNEM_mvns) ? 8 : 16;
9675218822Sdim      bfd_boolean narrow;
967660484Sobrien
9677218822Sdim      if (inst.size_req == 4
9678218822Sdim	  || inst.instruction > 0xffff
9679218822Sdim	  || inst.operands[1].shifted
9680218822Sdim	  || inst.operands[0].reg > 7 || inst.operands[1].reg > 7)
9681218822Sdim	narrow = FALSE;
9682218822Sdim      else if (inst.instruction == T_MNEM_cmn)
9683218822Sdim	narrow = TRUE;
9684218822Sdim      else if (THUMB_SETS_FLAGS (inst.instruction))
9685218822Sdim	narrow = (current_it_mask == 0);
9686218822Sdim      else
9687218822Sdim	narrow = (current_it_mask != 0);
9688218822Sdim
9689218822Sdim      if (!inst.operands[1].isreg)
9690218822Sdim	{
9691218822Sdim	  /* For an immediate, we always generate a 32-bit opcode;
9692218822Sdim	     section relaxation will shrink it later if possible.  */
9693218822Sdim	  if (inst.instruction < 0xffff)
9694218822Sdim	    inst.instruction = THUMB_OP32 (inst.instruction);
9695218822Sdim	  inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
9696218822Sdim	  inst.instruction |= inst.operands[0].reg << r0off;
9697218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
9698218822Sdim	}
9699218822Sdim      else
9700218822Sdim	{
9701218822Sdim	  /* See if we can do this with a 16-bit instruction.  */
9702218822Sdim	  if (narrow)
9703218822Sdim	    {
9704218822Sdim	      inst.instruction = THUMB_OP16 (inst.instruction);
9705218822Sdim	      inst.instruction |= inst.operands[0].reg;
9706218822Sdim	      inst.instruction |= inst.operands[1].reg << 3;
9707218822Sdim	    }
9708218822Sdim	  else
9709218822Sdim	    {
9710218822Sdim	      constraint (inst.operands[1].shifted
9711218822Sdim			  && inst.operands[1].immisreg,
9712218822Sdim			  _("shift must be constant"));
9713218822Sdim	      if (inst.instruction < 0xffff)
9714218822Sdim		inst.instruction = THUMB_OP32 (inst.instruction);
9715218822Sdim	      inst.instruction |= inst.operands[0].reg << r0off;
9716218822Sdim	      encode_thumb32_shifted_operand (1);
9717218822Sdim	    }
9718218822Sdim	}
9719218822Sdim    }
9720218822Sdim  else
972160484Sobrien    {
9722218822Sdim      constraint (inst.instruction > 0xffff
9723218822Sdim		  || inst.instruction == T_MNEM_mvns, BAD_THUMB32);
9724218822Sdim      constraint (!inst.operands[1].isreg || inst.operands[1].shifted,
9725218822Sdim		  _("unshifted register required"));
9726218822Sdim      constraint (inst.operands[0].reg > 7 || inst.operands[1].reg > 7,
9727218822Sdim		  BAD_HIREG);
972860484Sobrien
9729218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
9730218822Sdim      inst.instruction |= inst.operands[0].reg;
9731218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
973260484Sobrien    }
973389857Sobrien}
973489857Sobrien
973589857Sobrienstatic void
9736218822Sdimdo_t_mrs (void)
973789857Sobrien{
9738218822Sdim  int flags;
973989857Sobrien
9740218822Sdim  if (do_vfp_nsyn_mrs () == SUCCESS)
9741218822Sdim    return;
9742218822Sdim
9743218822Sdim  flags = inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f|SPSR_BIT);
9744218822Sdim  if (flags == 0)
974589857Sobrien    {
9746218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7m),
9747218822Sdim		  _("selected processor does not support "
9748218822Sdim		    "requested special purpose register"));
974989857Sobrien    }
9750218822Sdim  else
975160484Sobrien    {
9752218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1),
9753218822Sdim		  _("selected processor does not support "
9754218822Sdim		    "requested special purpose register %x"));
9755218822Sdim      /* mrs only accepts CPSR/SPSR/CPSR_all/SPSR_all.  */
9756218822Sdim      constraint ((flags & ~SPSR_BIT) != (PSR_c|PSR_f),
9757218822Sdim		  _("'CPSR' or 'SPSR' expected"));
975860484Sobrien    }
9759218822Sdim
9760218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
9761218822Sdim  inst.instruction |= (flags & SPSR_BIT) >> 2;
9762218822Sdim  inst.instruction |= inst.operands[1].imm & 0xff;
976360484Sobrien}
976460484Sobrien
976560484Sobrienstatic void
9766218822Sdimdo_t_msr (void)
976760484Sobrien{
9768218822Sdim  int flags;
976960484Sobrien
9770218822Sdim  if (do_vfp_nsyn_msr () == SUCCESS)
9771218822Sdim    return;
9772218822Sdim
9773218822Sdim  constraint (!inst.operands[1].isreg,
9774218822Sdim	      _("Thumb encoding does not support an immediate here"));
9775218822Sdim  flags = inst.operands[0].imm;
9776218822Sdim  if (flags & ~0xff)
977760484Sobrien    {
9778218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1),
9779218822Sdim		  _("selected processor does not support "
9780218822Sdim		    "requested special purpose register"));
978160484Sobrien    }
9782218822Sdim  else
978360484Sobrien    {
9784218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v7m),
9785218822Sdim		  _("selected processor does not support "
9786218822Sdim		    "requested special purpose register"));
9787218822Sdim      flags |= PSR_f;
978860484Sobrien    }
9789218822Sdim  inst.instruction |= (flags & SPSR_BIT) >> 2;
9790218822Sdim  inst.instruction |= (flags & ~SPSR_BIT) >> 8;
9791218822Sdim  inst.instruction |= (flags & 0xff);
9792218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
979360484Sobrien}
979460484Sobrien
979560484Sobrienstatic void
9796218822Sdimdo_t_mul (void)
979760484Sobrien{
9798218822Sdim  if (!inst.operands[2].present)
9799218822Sdim    inst.operands[2].reg = inst.operands[0].reg;
980060484Sobrien
9801218822Sdim  /* There is no 32-bit MULS and no 16-bit MUL. */
9802218822Sdim  if (unified_syntax && inst.instruction == T_MNEM_mul)
980360484Sobrien    {
9804218822Sdim      inst.instruction = THUMB_OP32 (inst.instruction);
9805218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
9806218822Sdim      inst.instruction |= inst.operands[1].reg << 16;
9807218822Sdim      inst.instruction |= inst.operands[2].reg << 0;
980860484Sobrien    }
9809218822Sdim  else
9810218822Sdim    {
9811218822Sdim      constraint (!unified_syntax
9812218822Sdim		  && inst.instruction == T_MNEM_muls, BAD_THUMB32);
9813218822Sdim      constraint (inst.operands[0].reg > 7 || inst.operands[1].reg > 7,
9814218822Sdim		  BAD_HIREG);
981560484Sobrien
9816218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
9817218822Sdim      inst.instruction |= inst.operands[0].reg;
9818218822Sdim
9819218822Sdim      if (inst.operands[0].reg == inst.operands[1].reg)
9820218822Sdim	inst.instruction |= inst.operands[2].reg << 3;
9821218822Sdim      else if (inst.operands[0].reg == inst.operands[2].reg)
9822218822Sdim	inst.instruction |= inst.operands[1].reg << 3;
9823218822Sdim      else
9824218822Sdim	constraint (1, _("dest must overlap one source register"));
9825218822Sdim    }
982689857Sobrien}
982789857Sobrien
9828218822Sdimstatic void
9829218822Sdimdo_t_mull (void)
983089857Sobrien{
9831218822Sdim  inst.instruction |= inst.operands[0].reg << 12;
9832218822Sdim  inst.instruction |= inst.operands[1].reg << 8;
9833218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
9834218822Sdim  inst.instruction |= inst.operands[3].reg;
983589857Sobrien
9836218822Sdim  if (inst.operands[0].reg == inst.operands[1].reg)
9837218822Sdim    as_tsktsk (_("rdhi and rdlo must be different"));
9838218822Sdim}
9839218822Sdim
9840218822Sdimstatic void
9841218822Sdimdo_t_nop (void)
9842218822Sdim{
9843218822Sdim  if (unified_syntax)
984460484Sobrien    {
9845218822Sdim      if (inst.size_req == 4 || inst.operands[0].imm > 15)
984689857Sobrien	{
9847218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
9848218822Sdim	  inst.instruction |= inst.operands[0].imm;
984989857Sobrien	}
9850218822Sdim      else
9851218822Sdim	{
9852218822Sdim	  inst.instruction = THUMB_OP16 (inst.instruction);
9853218822Sdim	  inst.instruction |= inst.operands[0].imm << 4;
9854218822Sdim	}
985589857Sobrien    }
9856218822Sdim  else
9857218822Sdim    {
9858218822Sdim      constraint (inst.operands[0].present,
9859218822Sdim		  _("Thumb does not support NOP with hints"));
9860218822Sdim      inst.instruction = 0x46c0;
9861218822Sdim    }
986289857Sobrien}
986389857Sobrien
9864218822Sdimstatic void
9865218822Sdimdo_t_neg (void)
986689857Sobrien{
9867218822Sdim  if (unified_syntax)
986889857Sobrien    {
9869218822Sdim      bfd_boolean narrow;
987089857Sobrien
9871218822Sdim      if (THUMB_SETS_FLAGS (inst.instruction))
9872218822Sdim	narrow = (current_it_mask == 0);
9873218822Sdim      else
9874218822Sdim	narrow = (current_it_mask != 0);
9875218822Sdim      if (inst.operands[0].reg > 7 || inst.operands[1].reg > 7)
9876218822Sdim	narrow = FALSE;
9877218822Sdim      if (inst.size_req == 4)
9878218822Sdim	narrow = FALSE;
987989857Sobrien
9880218822Sdim      if (!narrow)
9881218822Sdim	{
9882218822Sdim	  inst.instruction = THUMB_OP32 (inst.instruction);
9883218822Sdim	  inst.instruction |= inst.operands[0].reg << 8;
9884218822Sdim	  inst.instruction |= inst.operands[1].reg << 16;
988589857Sobrien	}
9886218822Sdim      else
9887218822Sdim	{
9888218822Sdim	  inst.instruction = THUMB_OP16 (inst.instruction);
9889218822Sdim	  inst.instruction |= inst.operands[0].reg;
9890218822Sdim	  inst.instruction |= inst.operands[1].reg << 3;
9891218822Sdim	}
989289857Sobrien    }
9893218822Sdim  else
9894218822Sdim    {
9895218822Sdim      constraint (inst.operands[0].reg > 7 || inst.operands[1].reg > 7,
9896218822Sdim		  BAD_HIREG);
9897218822Sdim      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
989889857Sobrien
9899218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
9900218822Sdim      inst.instruction |= inst.operands[0].reg;
9901218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
9902218822Sdim    }
990389857Sobrien}
990489857Sobrien
990589857Sobrienstatic void
9906218822Sdimdo_t_pkhbt (void)
990789857Sobrien{
9908218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
9909218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
9910218822Sdim  inst.instruction |= inst.operands[2].reg;
9911218822Sdim  if (inst.operands[3].present)
991289857Sobrien    {
9913218822Sdim      unsigned int val = inst.reloc.exp.X_add_number;
9914218822Sdim      constraint (inst.reloc.exp.X_op != O_constant,
9915218822Sdim		  _("expression too complex"));
9916218822Sdim      inst.instruction |= (val & 0x1c) << 10;
9917218822Sdim      inst.instruction |= (val & 0x03) << 6;
991860484Sobrien    }
9919218822Sdim}
992060484Sobrien
9921218822Sdimstatic void
9922218822Sdimdo_t_pkhtb (void)
9923218822Sdim{
9924218822Sdim  if (!inst.operands[3].present)
9925218822Sdim    inst.instruction &= ~0x00000020;
9926218822Sdim  do_t_pkhbt ();
992789857Sobrien}
992889857Sobrien
992989857Sobrienstatic void
9930218822Sdimdo_t_pld (void)
993189857Sobrien{
9932218822Sdim  encode_thumb32_addr_mode (0, /*is_t=*/FALSE, /*is_d=*/FALSE);
9933218822Sdim}
993489857Sobrien
9935218822Sdimstatic void
9936218822Sdimdo_t_push_pop (void)
9937218822Sdim{
9938218822Sdim  unsigned mask;
9939218822Sdim
9940218822Sdim  constraint (inst.operands[0].writeback,
9941218822Sdim	      _("push/pop do not support {reglist}^"));
9942218822Sdim  constraint (inst.reloc.type != BFD_RELOC_UNUSED,
9943218822Sdim	      _("expression too complex"));
994489857Sobrien
9945218822Sdim  mask = inst.operands[0].imm;
9946218822Sdim  if ((mask & ~0xff) == 0)
9947218822Sdim    inst.instruction = THUMB_OP16 (inst.instruction) | mask;
9948218822Sdim  else if ((inst.instruction == T_MNEM_push
9949218822Sdim	    && (mask & ~0xff) == 1 << REG_LR)
9950218822Sdim	   || (inst.instruction == T_MNEM_pop
9951218822Sdim	       && (mask & ~0xff) == 1 << REG_PC))
995289857Sobrien    {
9953218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
9954218822Sdim      inst.instruction |= THUMB_PP_PC_LR;
9955218822Sdim      inst.instruction |= mask & 0xff;
9956218822Sdim    }
9957218822Sdim  else if (unified_syntax)
9958218822Sdim    {
9959218822Sdim      inst.instruction = THUMB_OP32 (inst.instruction);
9960218822Sdim      encode_thumb2_ldmstm(13, mask, TRUE);
9961218822Sdim    }
9962218822Sdim  else
9963218822Sdim    {
9964218822Sdim      inst.error = _("invalid register list to push/pop instruction");
996589857Sobrien      return;
996689857Sobrien    }
9967218822Sdim}
996889857Sobrien
9969218822Sdimstatic void
9970218822Sdimdo_t_rbit (void)
9971218822Sdim{
9972218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
9973218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
997489857Sobrien}
997589857Sobrien
997689857Sobrienstatic void
9977223484Sdimdo_t_rd_rm (void)
9978223484Sdim{
9979223484Sdim  inst.instruction |= inst.operands[0].reg << 8;
9980223484Sdim  inst.instruction |= inst.operands[1].reg;
9981223484Sdim}
9982223484Sdim
9983223484Sdimstatic void
9984218822Sdimdo_t_rev (void)
998589857Sobrien{
9986218822Sdim  if (inst.operands[0].reg <= 7 && inst.operands[1].reg <= 7
9987218822Sdim      && inst.size_req != 4)
998889857Sobrien    {
9989218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
9990218822Sdim      inst.instruction |= inst.operands[0].reg;
9991218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
999289857Sobrien    }
9993218822Sdim  else if (unified_syntax)
9994218822Sdim    {
9995218822Sdim      inst.instruction = THUMB_OP32 (inst.instruction);
9996218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
9997218822Sdim      inst.instruction |= inst.operands[1].reg << 16;
9998218822Sdim      inst.instruction |= inst.operands[1].reg;
9999218822Sdim    }
10000218822Sdim  else
10001218822Sdim    inst.error = BAD_HIREG;
1000289857Sobrien}
1000389857Sobrien
1000489857Sobrienstatic void
10005218822Sdimdo_t_rsb (void)
1000689857Sobrien{
10007218822Sdim  int Rd, Rs;
1000889857Sobrien
10009218822Sdim  Rd = inst.operands[0].reg;
10010218822Sdim  Rs = (inst.operands[1].present
10011218822Sdim	? inst.operands[1].reg    /* Rd, Rs, foo */
10012218822Sdim	: inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
1001389857Sobrien
10014218822Sdim  inst.instruction |= Rd << 8;
10015218822Sdim  inst.instruction |= Rs << 16;
10016218822Sdim  if (!inst.operands[2].isreg)
1001789857Sobrien    {
10018218822Sdim      bfd_boolean narrow;
1001989857Sobrien
10020218822Sdim      if ((inst.instruction & 0x00100000) != 0)
10021218822Sdim	narrow = (current_it_mask == 0);
10022218822Sdim      else
10023218822Sdim	narrow = (current_it_mask != 0);
1002489857Sobrien
10025218822Sdim      if (Rd > 7 || Rs > 7)
10026218822Sdim	narrow = FALSE;
1002789857Sobrien
10028218822Sdim      if (inst.size_req == 4 || !unified_syntax)
10029218822Sdim	narrow = FALSE;
1003089857Sobrien
10031218822Sdim      if (inst.reloc.exp.X_op != O_constant
10032218822Sdim	  || inst.reloc.exp.X_add_number != 0)
10033218822Sdim	narrow = FALSE;
10034218822Sdim
10035218822Sdim      /* Turn rsb #0 into 16-bit neg.  We should probably do this via
10036218822Sdim         relaxation, but it doesn't seem worth the hassle.  */
10037218822Sdim      if (narrow)
10038218822Sdim	{
10039218822Sdim	  inst.reloc.type = BFD_RELOC_UNUSED;
10040218822Sdim	  inst.instruction = THUMB_OP16 (T_MNEM_negs);
10041218822Sdim	  inst.instruction |= Rs << 3;
10042218822Sdim	  inst.instruction |= Rd;
10043218822Sdim	}
10044218822Sdim      else
10045218822Sdim	{
10046218822Sdim	  inst.instruction = (inst.instruction & 0xe1ffffff) | 0x10000000;
10047218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_T32_IMMEDIATE;
10048218822Sdim	}
1004989857Sobrien    }
10050218822Sdim  else
10051218822Sdim    encode_thumb32_shifted_operand (2);
10052218822Sdim}
1005389857Sobrien
10054218822Sdimstatic void
10055218822Sdimdo_t_setend (void)
10056218822Sdim{
10057218822Sdim  constraint (current_it_mask, BAD_NOT_IT);
10058218822Sdim  if (inst.operands[0].imm)
10059218822Sdim    inst.instruction |= 0x8;
1006089857Sobrien}
1006189857Sobrien
1006289857Sobrienstatic void
10063218822Sdimdo_t_shift (void)
1006489857Sobrien{
10065218822Sdim  if (!inst.operands[1].present)
10066218822Sdim    inst.operands[1].reg = inst.operands[0].reg;
1006789857Sobrien
10068218822Sdim  if (unified_syntax)
1006989857Sobrien    {
10070218822Sdim      bfd_boolean narrow;
10071218822Sdim      int shift_kind;
10072218822Sdim
10073218822Sdim      switch (inst.instruction)
10074218822Sdim	{
10075218822Sdim	case T_MNEM_asr:
10076218822Sdim	case T_MNEM_asrs: shift_kind = SHIFT_ASR; break;
10077218822Sdim	case T_MNEM_lsl:
10078218822Sdim	case T_MNEM_lsls: shift_kind = SHIFT_LSL; break;
10079218822Sdim	case T_MNEM_lsr:
10080218822Sdim	case T_MNEM_lsrs: shift_kind = SHIFT_LSR; break;
10081218822Sdim	case T_MNEM_ror:
10082218822Sdim	case T_MNEM_rors: shift_kind = SHIFT_ROR; break;
10083218822Sdim	default: abort ();
10084218822Sdim	}
10085218822Sdim
10086218822Sdim      if (THUMB_SETS_FLAGS (inst.instruction))
10087218822Sdim	narrow = (current_it_mask == 0);
10088218822Sdim      else
10089218822Sdim	narrow = (current_it_mask != 0);
10090218822Sdim      if (inst.operands[0].reg > 7 || inst.operands[1].reg > 7)
10091218822Sdim	narrow = FALSE;
10092218822Sdim      if (!inst.operands[2].isreg && shift_kind == SHIFT_ROR)
10093218822Sdim	narrow = FALSE;
10094218822Sdim      if (inst.operands[2].isreg
10095218822Sdim	  && (inst.operands[1].reg != inst.operands[0].reg
10096218822Sdim	      || inst.operands[2].reg > 7))
10097218822Sdim	narrow = FALSE;
10098218822Sdim      if (inst.size_req == 4)
10099218822Sdim	narrow = FALSE;
10100218822Sdim
10101218822Sdim      if (!narrow)
10102218822Sdim	{
10103218822Sdim	  if (inst.operands[2].isreg)
10104218822Sdim	    {
10105218822Sdim	      inst.instruction = THUMB_OP32 (inst.instruction);
10106218822Sdim	      inst.instruction |= inst.operands[0].reg << 8;
10107218822Sdim	      inst.instruction |= inst.operands[1].reg << 16;
10108218822Sdim	      inst.instruction |= inst.operands[2].reg;
10109218822Sdim	    }
10110218822Sdim	  else
10111218822Sdim	    {
10112218822Sdim	      inst.operands[1].shifted = 1;
10113218822Sdim	      inst.operands[1].shift_kind = shift_kind;
10114218822Sdim	      inst.instruction = THUMB_OP32 (THUMB_SETS_FLAGS (inst.instruction)
10115218822Sdim					     ? T_MNEM_movs : T_MNEM_mov);
10116218822Sdim	      inst.instruction |= inst.operands[0].reg << 8;
10117218822Sdim	      encode_thumb32_shifted_operand (1);
10118218822Sdim	      /* Prevent the incorrect generation of an ARM_IMMEDIATE fixup.  */
10119218822Sdim	      inst.reloc.type = BFD_RELOC_UNUSED;
10120218822Sdim	    }
10121218822Sdim	}
10122218822Sdim      else
10123218822Sdim	{
10124218822Sdim	  if (inst.operands[2].isreg)
10125218822Sdim	    {
10126218822Sdim	      switch (shift_kind)
10127218822Sdim		{
10128218822Sdim		case SHIFT_ASR: inst.instruction = T_OPCODE_ASR_R; break;
10129218822Sdim		case SHIFT_LSL: inst.instruction = T_OPCODE_LSL_R; break;
10130218822Sdim		case SHIFT_LSR: inst.instruction = T_OPCODE_LSR_R; break;
10131218822Sdim		case SHIFT_ROR: inst.instruction = T_OPCODE_ROR_R; break;
10132218822Sdim		default: abort ();
10133218822Sdim		}
10134218822Sdim
10135218822Sdim	      inst.instruction |= inst.operands[0].reg;
10136218822Sdim	      inst.instruction |= inst.operands[2].reg << 3;
10137218822Sdim	    }
10138218822Sdim	  else
10139218822Sdim	    {
10140218822Sdim	      switch (shift_kind)
10141218822Sdim		{
10142218822Sdim		case SHIFT_ASR: inst.instruction = T_OPCODE_ASR_I; break;
10143218822Sdim		case SHIFT_LSL: inst.instruction = T_OPCODE_LSL_I; break;
10144218822Sdim		case SHIFT_LSR: inst.instruction = T_OPCODE_LSR_I; break;
10145218822Sdim		default: abort ();
10146218822Sdim		}
10147218822Sdim	      inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
10148218822Sdim	      inst.instruction |= inst.operands[0].reg;
10149218822Sdim	      inst.instruction |= inst.operands[1].reg << 3;
10150218822Sdim	    }
10151218822Sdim	}
1015289857Sobrien    }
10153218822Sdim  else
10154218822Sdim    {
10155218822Sdim      constraint (inst.operands[0].reg > 7
10156218822Sdim		  || inst.operands[1].reg > 7, BAD_HIREG);
10157218822Sdim      constraint (THUMB_SETS_FLAGS (inst.instruction), BAD_THUMB32);
1015889857Sobrien
10159218822Sdim      if (inst.operands[2].isreg)  /* Rd, {Rs,} Rn */
10160218822Sdim	{
10161218822Sdim	  constraint (inst.operands[2].reg > 7, BAD_HIREG);
10162218822Sdim	  constraint (inst.operands[0].reg != inst.operands[1].reg,
10163218822Sdim		      _("source1 and dest must be same register"));
10164218822Sdim
10165218822Sdim	  switch (inst.instruction)
10166218822Sdim	    {
10167218822Sdim	    case T_MNEM_asr: inst.instruction = T_OPCODE_ASR_R; break;
10168218822Sdim	    case T_MNEM_lsl: inst.instruction = T_OPCODE_LSL_R; break;
10169218822Sdim	    case T_MNEM_lsr: inst.instruction = T_OPCODE_LSR_R; break;
10170218822Sdim	    case T_MNEM_ror: inst.instruction = T_OPCODE_ROR_R; break;
10171218822Sdim	    default: abort ();
10172218822Sdim	    }
10173218822Sdim
10174218822Sdim	  inst.instruction |= inst.operands[0].reg;
10175218822Sdim	  inst.instruction |= inst.operands[2].reg << 3;
10176218822Sdim	}
10177218822Sdim      else
10178218822Sdim	{
10179218822Sdim	  switch (inst.instruction)
10180218822Sdim	    {
10181218822Sdim	    case T_MNEM_asr: inst.instruction = T_OPCODE_ASR_I; break;
10182218822Sdim	    case T_MNEM_lsl: inst.instruction = T_OPCODE_LSL_I; break;
10183218822Sdim	    case T_MNEM_lsr: inst.instruction = T_OPCODE_LSR_I; break;
10184218822Sdim	    case T_MNEM_ror: inst.error = _("ror #imm not supported"); return;
10185218822Sdim	    default: abort ();
10186218822Sdim	    }
10187218822Sdim	  inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
10188218822Sdim	  inst.instruction |= inst.operands[0].reg;
10189218822Sdim	  inst.instruction |= inst.operands[1].reg << 3;
10190218822Sdim	}
1019189857Sobrien    }
10192218822Sdim}
1019389857Sobrien
10194218822Sdimstatic void
10195218822Sdimdo_t_simd (void)
10196218822Sdim{
10197218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10198218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
10199218822Sdim  inst.instruction |= inst.operands[2].reg;
1020089857Sobrien}
1020189857Sobrien
1020289857Sobrienstatic void
10203218822Sdimdo_t_smc (void)
1020489857Sobrien{
10205218822Sdim  unsigned int value = inst.reloc.exp.X_add_number;
10206218822Sdim  constraint (inst.reloc.exp.X_op != O_constant,
10207218822Sdim	      _("expression too complex"));
10208218822Sdim  inst.reloc.type = BFD_RELOC_UNUSED;
10209218822Sdim  inst.instruction |= (value & 0xf000) >> 12;
10210218822Sdim  inst.instruction |= (value & 0x0ff0);
10211218822Sdim  inst.instruction |= (value & 0x000f) << 16;
1021260484Sobrien}
1021360484Sobrien
1021460484Sobrienstatic void
10215218822Sdimdo_t_ssat (void)
10216130561Sobrien{
10217218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10218218822Sdim  inst.instruction |= inst.operands[1].imm - 1;
10219218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
10220130561Sobrien
10221218822Sdim  if (inst.operands[3].present)
10222130561Sobrien    {
10223218822Sdim      constraint (inst.reloc.exp.X_op != O_constant,
10224218822Sdim		  _("expression too complex"));
10225130561Sobrien
10226218822Sdim      if (inst.reloc.exp.X_add_number != 0)
10227218822Sdim	{
10228218822Sdim	  if (inst.operands[3].shift_kind == SHIFT_ASR)
10229218822Sdim	    inst.instruction |= 0x00200000;  /* sh bit */
10230218822Sdim	  inst.instruction |= (inst.reloc.exp.X_add_number & 0x1c) << 10;
10231218822Sdim	  inst.instruction |= (inst.reloc.exp.X_add_number & 0x03) << 6;
10232218822Sdim	}
10233218822Sdim      inst.reloc.type = BFD_RELOC_UNUSED;
10234130561Sobrien    }
10235218822Sdim}
10236130561Sobrien
10237218822Sdimstatic void
10238218822Sdimdo_t_ssat16 (void)
10239218822Sdim{
10240218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10241218822Sdim  inst.instruction |= inst.operands[1].imm - 1;
10242218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
10243130561Sobrien}
10244130561Sobrien
10245130561Sobrienstatic void
10246218822Sdimdo_t_strex (void)
1024760484Sobrien{
10248218822Sdim  constraint (!inst.operands[2].isreg || !inst.operands[2].preind
10249218822Sdim	      || inst.operands[2].postind || inst.operands[2].writeback
10250218822Sdim	      || inst.operands[2].immisreg || inst.operands[2].shifted
10251218822Sdim	      || inst.operands[2].negative,
10252218822Sdim	      BAD_ADDR_MODE);
1025360484Sobrien
10254218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10255218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
10256218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
10257218822Sdim  inst.reloc.type = BFD_RELOC_ARM_T32_OFFSET_U8;
1025860484Sobrien}
1025960484Sobrien
1026089857Sobrienstatic void
10261218822Sdimdo_t_strexd (void)
1026289857Sobrien{
10263218822Sdim  if (!inst.operands[2].present)
10264218822Sdim    inst.operands[2].reg = inst.operands[1].reg + 1;
1026589857Sobrien
10266218822Sdim  constraint (inst.operands[0].reg == inst.operands[1].reg
10267218822Sdim	      || inst.operands[0].reg == inst.operands[2].reg
10268218822Sdim	      || inst.operands[0].reg == inst.operands[3].reg
10269218822Sdim	      || inst.operands[1].reg == inst.operands[2].reg,
10270218822Sdim	      BAD_OVERLAP);
1027189857Sobrien
10272218822Sdim  inst.instruction |= inst.operands[0].reg;
10273218822Sdim  inst.instruction |= inst.operands[1].reg << 12;
10274218822Sdim  inst.instruction |= inst.operands[2].reg << 8;
10275218822Sdim  inst.instruction |= inst.operands[3].reg << 16;
10276218822Sdim}
1027789857Sobrien
10278218822Sdimstatic void
10279218822Sdimdo_t_sxtah (void)
10280218822Sdim{
10281218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10282218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
10283218822Sdim  inst.instruction |= inst.operands[2].reg;
10284218822Sdim  inst.instruction |= inst.operands[3].imm << 4;
1028589857Sobrien}
1028689857Sobrien
1028789857Sobrienstatic void
10288218822Sdimdo_t_sxth (void)
1028989857Sobrien{
10290218822Sdim  if (inst.instruction <= 0xffff && inst.size_req != 4
10291218822Sdim      && inst.operands[0].reg <= 7 && inst.operands[1].reg <= 7
10292218822Sdim      && (!inst.operands[2].present || inst.operands[2].imm == 0))
1029389857Sobrien    {
10294218822Sdim      inst.instruction = THUMB_OP16 (inst.instruction);
10295218822Sdim      inst.instruction |= inst.operands[0].reg;
10296218822Sdim      inst.instruction |= inst.operands[1].reg << 3;
1029789857Sobrien    }
10298218822Sdim  else if (unified_syntax)
10299218822Sdim    {
10300218822Sdim      if (inst.instruction <= 0xffff)
10301218822Sdim	inst.instruction = THUMB_OP32 (inst.instruction);
10302218822Sdim      inst.instruction |= inst.operands[0].reg << 8;
10303218822Sdim      inst.instruction |= inst.operands[1].reg;
10304218822Sdim      inst.instruction |= inst.operands[2].imm << 4;
10305218822Sdim    }
10306218822Sdim  else
10307218822Sdim    {
10308218822Sdim      constraint (inst.operands[2].present && inst.operands[2].imm != 0,
10309218822Sdim		  _("Thumb encoding does not support rotation"));
10310218822Sdim      constraint (1, BAD_HIREG);
10311218822Sdim    }
10312218822Sdim}
1031389857Sobrien
10314218822Sdimstatic void
10315218822Sdimdo_t_swi (void)
10316218822Sdim{
10317218822Sdim  inst.reloc.type = BFD_RELOC_ARM_SWI;
1031889857Sobrien}
1031989857Sobrien
1032089857Sobrienstatic void
10321218822Sdimdo_t_tb (void)
1032289857Sobrien{
10323218822Sdim  int half;
1032489857Sobrien
10325218822Sdim  half = (inst.instruction & 0x10) != 0;
10326218822Sdim  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
10327218822Sdim  constraint (inst.operands[0].immisreg,
10328218822Sdim	      _("instruction requires register index"));
10329218822Sdim  constraint (inst.operands[0].imm == 15,
10330218822Sdim	      _("PC is not a valid index register"));
10331218822Sdim  constraint (!half && inst.operands[0].shifted,
10332218822Sdim	      _("instruction does not allow shifted index"));
10333218822Sdim  inst.instruction |= (inst.operands[0].reg << 16) | inst.operands[0].imm;
1033489857Sobrien}
1033589857Sobrien
10336218822Sdimstatic void
10337218822Sdimdo_t_usat (void)
1033889857Sobrien{
10339218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10340218822Sdim  inst.instruction |= inst.operands[1].imm;
10341218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
1034289857Sobrien
10343218822Sdim  if (inst.operands[3].present)
1034489857Sobrien    {
10345218822Sdim      constraint (inst.reloc.exp.X_op != O_constant,
10346218822Sdim		  _("expression too complex"));
10347218822Sdim      if (inst.reloc.exp.X_add_number != 0)
10348218822Sdim	{
10349218822Sdim	  if (inst.operands[3].shift_kind == SHIFT_ASR)
10350218822Sdim	    inst.instruction |= 0x00200000;  /* sh bit */
1035189857Sobrien
10352218822Sdim	  inst.instruction |= (inst.reloc.exp.X_add_number & 0x1c) << 10;
10353218822Sdim	  inst.instruction |= (inst.reloc.exp.X_add_number & 0x03) << 6;
1035489857Sobrien	}
10355218822Sdim      inst.reloc.type = BFD_RELOC_UNUSED;
1035689857Sobrien    }
1035789857Sobrien}
1035889857Sobrien
10359218822Sdimstatic void
10360218822Sdimdo_t_usat16 (void)
1036189857Sobrien{
10362218822Sdim  inst.instruction |= inst.operands[0].reg << 8;
10363218822Sdim  inst.instruction |= inst.operands[1].imm;
10364218822Sdim  inst.instruction |= inst.operands[2].reg << 16;
10365218822Sdim}
1036689857Sobrien
10367218822Sdim/* Neon instruction encoder helpers.  */
10368218822Sdim
10369218822Sdim/* Encodings for the different types for various Neon opcodes.  */
1037089857Sobrien
10371218822Sdim/* An "invalid" code for the following tables.  */
10372218822Sdim#define N_INV -1u
1037389857Sobrien
10374218822Sdimstruct neon_tab_entry
10375218822Sdim{
10376218822Sdim  unsigned integer;
10377218822Sdim  unsigned float_or_poly;
10378218822Sdim  unsigned scalar_or_imm;
10379218822Sdim};
10380218822Sdim
10381218822Sdim/* Map overloaded Neon opcodes to their respective encodings.  */
10382218822Sdim#define NEON_ENC_TAB					\
10383218822Sdim  X(vabd,	0x0000700, 0x1200d00, N_INV),		\
10384218822Sdim  X(vmax,	0x0000600, 0x0000f00, N_INV),		\
10385218822Sdim  X(vmin,	0x0000610, 0x0200f00, N_INV),		\
10386218822Sdim  X(vpadd,	0x0000b10, 0x1000d00, N_INV),		\
10387218822Sdim  X(vpmax,	0x0000a00, 0x1000f00, N_INV),		\
10388218822Sdim  X(vpmin,	0x0000a10, 0x1200f00, N_INV),		\
10389218822Sdim  X(vadd,	0x0000800, 0x0000d00, N_INV),		\
10390218822Sdim  X(vsub,	0x1000800, 0x0200d00, N_INV),		\
10391218822Sdim  X(vceq,	0x1000810, 0x0000e00, 0x1b10100),	\
10392218822Sdim  X(vcge,	0x0000310, 0x1000e00, 0x1b10080),	\
10393218822Sdim  X(vcgt,	0x0000300, 0x1200e00, 0x1b10000),	\
10394218822Sdim  /* Register variants of the following two instructions are encoded as
10395218822Sdim     vcge / vcgt with the operands reversed. */  	\
10396218822Sdim  X(vclt,	0x0000300, 0x1200e00, 0x1b10200),	\
10397218822Sdim  X(vcle,	0x0000310, 0x1000e00, 0x1b10180),	\
10398218822Sdim  X(vmla,	0x0000900, 0x0000d10, 0x0800040),	\
10399218822Sdim  X(vmls,	0x1000900, 0x0200d10, 0x0800440),	\
10400218822Sdim  X(vmul,	0x0000910, 0x1000d10, 0x0800840),	\
10401218822Sdim  X(vmull,	0x0800c00, 0x0800e00, 0x0800a40), /* polynomial not float.  */ \
10402218822Sdim  X(vmlal,	0x0800800, N_INV,     0x0800240),	\
10403218822Sdim  X(vmlsl,	0x0800a00, N_INV,     0x0800640),	\
10404218822Sdim  X(vqdmlal,	0x0800900, N_INV,     0x0800340),	\
10405218822Sdim  X(vqdmlsl,	0x0800b00, N_INV,     0x0800740),	\
10406218822Sdim  X(vqdmull,	0x0800d00, N_INV,     0x0800b40),	\
10407218822Sdim  X(vqdmulh,    0x0000b00, N_INV,     0x0800c40),	\
10408218822Sdim  X(vqrdmulh,   0x1000b00, N_INV,     0x0800d40),	\
10409218822Sdim  X(vshl,	0x0000400, N_INV,     0x0800510),	\
10410218822Sdim  X(vqshl,	0x0000410, N_INV,     0x0800710),	\
10411218822Sdim  X(vand,	0x0000110, N_INV,     0x0800030),	\
10412218822Sdim  X(vbic,	0x0100110, N_INV,     0x0800030),	\
10413218822Sdim  X(veor,	0x1000110, N_INV,     N_INV),		\
10414218822Sdim  X(vorn,	0x0300110, N_INV,     0x0800010),	\
10415218822Sdim  X(vorr,	0x0200110, N_INV,     0x0800010),	\
10416218822Sdim  X(vmvn,	0x1b00580, N_INV,     0x0800030),	\
10417218822Sdim  X(vshll,	0x1b20300, N_INV,     0x0800a10), /* max shift, immediate.  */ \
10418218822Sdim  X(vcvt,       0x1b30600, N_INV,     0x0800e10), /* integer, fixed-point.  */ \
10419218822Sdim  X(vdup,       0xe800b10, N_INV,     0x1b00c00), /* arm, scalar.  */ \
10420218822Sdim  X(vld1,       0x0200000, 0x0a00000, 0x0a00c00), /* interlv, lane, dup.  */ \
10421218822Sdim  X(vst1,	0x0000000, 0x0800000, N_INV),		\
10422218822Sdim  X(vld2,	0x0200100, 0x0a00100, 0x0a00d00),	\
10423218822Sdim  X(vst2,	0x0000100, 0x0800100, N_INV),		\
10424218822Sdim  X(vld3,	0x0200200, 0x0a00200, 0x0a00e00),	\
10425218822Sdim  X(vst3,	0x0000200, 0x0800200, N_INV),		\
10426218822Sdim  X(vld4,	0x0200300, 0x0a00300, 0x0a00f00),	\
10427218822Sdim  X(vst4,	0x0000300, 0x0800300, N_INV),		\
10428218822Sdim  X(vmovn,	0x1b20200, N_INV,     N_INV),		\
10429218822Sdim  X(vtrn,	0x1b20080, N_INV,     N_INV),		\
10430218822Sdim  X(vqmovn,	0x1b20200, N_INV,     N_INV),		\
10431218822Sdim  X(vqmovun,	0x1b20240, N_INV,     N_INV),		\
10432218822Sdim  X(vnmul,      0xe200a40, 0xe200b40, N_INV),		\
10433218822Sdim  X(vnmla,      0xe000a40, 0xe000b40, N_INV),		\
10434218822Sdim  X(vnmls,      0xe100a40, 0xe100b40, N_INV),		\
10435218822Sdim  X(vcmp,	0xeb40a40, 0xeb40b40, N_INV),		\
10436218822Sdim  X(vcmpz,	0xeb50a40, 0xeb50b40, N_INV),		\
10437218822Sdim  X(vcmpe,	0xeb40ac0, 0xeb40bc0, N_INV),		\
10438218822Sdim  X(vcmpez,     0xeb50ac0, 0xeb50bc0, N_INV)
1043989857Sobrien
10440218822Sdimenum neon_opc
10441218822Sdim{
10442218822Sdim#define X(OPC,I,F,S) N_MNEM_##OPC
10443218822SdimNEON_ENC_TAB
10444218822Sdim#undef X
10445218822Sdim};
1044689857Sobrien
10447218822Sdimstatic const struct neon_tab_entry neon_enc_tab[] =
1044889857Sobrien{
10449218822Sdim#define X(OPC,I,F,S) { (I), (F), (S) }
10450218822SdimNEON_ENC_TAB
10451218822Sdim#undef X
10452218822Sdim};
1045389857Sobrien
10454218822Sdim#define NEON_ENC_INTEGER(X) (neon_enc_tab[(X) & 0x0fffffff].integer)
10455218822Sdim#define NEON_ENC_ARMREG(X)  (neon_enc_tab[(X) & 0x0fffffff].integer)
10456218822Sdim#define NEON_ENC_POLY(X)    (neon_enc_tab[(X) & 0x0fffffff].float_or_poly)
10457218822Sdim#define NEON_ENC_FLOAT(X)   (neon_enc_tab[(X) & 0x0fffffff].float_or_poly)
10458218822Sdim#define NEON_ENC_SCALAR(X)  (neon_enc_tab[(X) & 0x0fffffff].scalar_or_imm)
10459218822Sdim#define NEON_ENC_IMMED(X)   (neon_enc_tab[(X) & 0x0fffffff].scalar_or_imm)
10460218822Sdim#define NEON_ENC_INTERLV(X) (neon_enc_tab[(X) & 0x0fffffff].integer)
10461218822Sdim#define NEON_ENC_LANE(X)    (neon_enc_tab[(X) & 0x0fffffff].float_or_poly)
10462218822Sdim#define NEON_ENC_DUP(X)     (neon_enc_tab[(X) & 0x0fffffff].scalar_or_imm)
10463218822Sdim#define NEON_ENC_SINGLE(X) \
10464218822Sdim  ((neon_enc_tab[(X) & 0x0fffffff].integer) | ((X) & 0xf0000000))
10465218822Sdim#define NEON_ENC_DOUBLE(X) \
10466218822Sdim  ((neon_enc_tab[(X) & 0x0fffffff].float_or_poly) | ((X) & 0xf0000000))
1046789857Sobrien
10468218822Sdim/* Define shapes for instruction operands. The following mnemonic characters
10469218822Sdim   are used in this table:
1047089857Sobrien
10471218822Sdim     F - VFP S<n> register
10472218822Sdim     D - Neon D<n> register
10473218822Sdim     Q - Neon Q<n> register
10474218822Sdim     I - Immediate
10475218822Sdim     S - Scalar
10476218822Sdim     R - ARM register
10477218822Sdim     L - D<n> register list
10478218822Sdim
10479218822Sdim   This table is used to generate various data:
10480218822Sdim     - enumerations of the form NS_DDR to be used as arguments to
10481218822Sdim       neon_select_shape.
10482218822Sdim     - a table classifying shapes into single, double, quad, mixed.
10483218822Sdim     - a table used to drive neon_select_shape.
10484218822Sdim*/
1048589857Sobrien
10486218822Sdim#define NEON_SHAPE_DEF			\
10487218822Sdim  X(3, (D, D, D), DOUBLE),		\
10488218822Sdim  X(3, (Q, Q, Q), QUAD),		\
10489218822Sdim  X(3, (D, D, I), DOUBLE),		\
10490218822Sdim  X(3, (Q, Q, I), QUAD),		\
10491218822Sdim  X(3, (D, D, S), DOUBLE),		\
10492218822Sdim  X(3, (Q, Q, S), QUAD),		\
10493218822Sdim  X(2, (D, D), DOUBLE),			\
10494218822Sdim  X(2, (Q, Q), QUAD),			\
10495218822Sdim  X(2, (D, S), DOUBLE),			\
10496218822Sdim  X(2, (Q, S), QUAD),			\
10497218822Sdim  X(2, (D, R), DOUBLE),			\
10498218822Sdim  X(2, (Q, R), QUAD),			\
10499218822Sdim  X(2, (D, I), DOUBLE),			\
10500218822Sdim  X(2, (Q, I), QUAD),			\
10501218822Sdim  X(3, (D, L, D), DOUBLE),		\
10502218822Sdim  X(2, (D, Q), MIXED),			\
10503218822Sdim  X(2, (Q, D), MIXED),			\
10504218822Sdim  X(3, (D, Q, I), MIXED),		\
10505218822Sdim  X(3, (Q, D, I), MIXED),		\
10506218822Sdim  X(3, (Q, D, D), MIXED),		\
10507218822Sdim  X(3, (D, Q, Q), MIXED),		\
10508218822Sdim  X(3, (Q, Q, D), MIXED),		\
10509218822Sdim  X(3, (Q, D, S), MIXED),		\
10510218822Sdim  X(3, (D, Q, S), MIXED),		\
10511218822Sdim  X(4, (D, D, D, I), DOUBLE),		\
10512218822Sdim  X(4, (Q, Q, Q, I), QUAD),		\
10513218822Sdim  X(2, (F, F), SINGLE),			\
10514218822Sdim  X(3, (F, F, F), SINGLE),		\
10515218822Sdim  X(2, (F, I), SINGLE),			\
10516218822Sdim  X(2, (F, D), MIXED),			\
10517218822Sdim  X(2, (D, F), MIXED),			\
10518218822Sdim  X(3, (F, F, I), MIXED),		\
10519218822Sdim  X(4, (R, R, F, F), SINGLE),		\
10520218822Sdim  X(4, (F, F, R, R), SINGLE),		\
10521218822Sdim  X(3, (D, R, R), DOUBLE),		\
10522218822Sdim  X(3, (R, R, D), DOUBLE),		\
10523218822Sdim  X(2, (S, R), SINGLE),			\
10524218822Sdim  X(2, (R, S), SINGLE),			\
10525218822Sdim  X(2, (F, R), SINGLE),			\
10526218822Sdim  X(2, (R, F), SINGLE)
10527218822Sdim
10528218822Sdim#define S2(A,B)		NS_##A##B
10529218822Sdim#define S3(A,B,C)	NS_##A##B##C
10530218822Sdim#define S4(A,B,C,D)	NS_##A##B##C##D
10531218822Sdim
10532218822Sdim#define X(N, L, C) S##N L
10533218822Sdim
10534218822Sdimenum neon_shape
1053589857Sobrien{
10536218822Sdim  NEON_SHAPE_DEF,
10537218822Sdim  NS_NULL
10538218822Sdim};
1053989857Sobrien
10540218822Sdim#undef X
10541218822Sdim#undef S2
10542218822Sdim#undef S3
10543218822Sdim#undef S4
1054489857Sobrien
10545218822Sdimenum neon_shape_class
10546218822Sdim{
10547218822Sdim  SC_SINGLE,
10548218822Sdim  SC_DOUBLE,
10549218822Sdim  SC_QUAD,
10550218822Sdim  SC_MIXED
10551218822Sdim};
1055289857Sobrien
10553218822Sdim#define X(N, L, C) SC_##C
1055489857Sobrien
10555218822Sdimstatic enum neon_shape_class neon_shape_class[] =
1055689857Sobrien{
10557218822Sdim  NEON_SHAPE_DEF
10558218822Sdim};
1055989857Sobrien
10560218822Sdim#undef X
1056189857Sobrien
10562218822Sdimenum neon_shape_el
10563218822Sdim{
10564218822Sdim  SE_F,
10565218822Sdim  SE_D,
10566218822Sdim  SE_Q,
10567218822Sdim  SE_I,
10568218822Sdim  SE_S,
10569218822Sdim  SE_R,
10570218822Sdim  SE_L
10571218822Sdim};
1057289857Sobrien
10573218822Sdim/* Register widths of above.  */
10574218822Sdimstatic unsigned neon_shape_el_size[] =
10575218822Sdim{
10576218822Sdim  32,
10577218822Sdim  64,
10578218822Sdim  128,
10579218822Sdim  0,
10580218822Sdim  32,
10581218822Sdim  32,
10582218822Sdim  0
10583218822Sdim};
1058489857Sobrien
10585218822Sdimstruct neon_shape_info
1058689857Sobrien{
10587218822Sdim  unsigned els;
10588218822Sdim  enum neon_shape_el el[NEON_MAX_TYPE_ELS];
10589218822Sdim};
1059089857Sobrien
10591218822Sdim#define S2(A,B)		{ SE_##A, SE_##B }
10592218822Sdim#define S3(A,B,C)	{ SE_##A, SE_##B, SE_##C }
10593218822Sdim#define S4(A,B,C,D)	{ SE_##A, SE_##B, SE_##C, SE_##D }
1059489857Sobrien
10595218822Sdim#define X(N, L, C) { N, S##N L }
1059689857Sobrien
10597218822Sdimstatic struct neon_shape_info neon_shape_tab[] =
1059889857Sobrien{
10599218822Sdim  NEON_SHAPE_DEF
10600218822Sdim};
1060189857Sobrien
10602218822Sdim#undef X
10603218822Sdim#undef S2
10604218822Sdim#undef S3
10605218822Sdim#undef S4
1060689857Sobrien
10607218822Sdim/* Bit masks used in type checking given instructions.
10608218822Sdim  'N_EQK' means the type must be the same as (or based on in some way) the key
10609218822Sdim   type, which itself is marked with the 'N_KEY' bit. If the 'N_EQK' bit is
10610218822Sdim   set, various other bits can be set as well in order to modify the meaning of
10611218822Sdim   the type constraint.  */
1061289857Sobrien
10613218822Sdimenum neon_type_mask
10614218822Sdim{
10615218822Sdim  N_S8   = 0x000001,
10616218822Sdim  N_S16  = 0x000002,
10617218822Sdim  N_S32  = 0x000004,
10618218822Sdim  N_S64  = 0x000008,
10619218822Sdim  N_U8   = 0x000010,
10620218822Sdim  N_U16  = 0x000020,
10621218822Sdim  N_U32  = 0x000040,
10622218822Sdim  N_U64  = 0x000080,
10623218822Sdim  N_I8   = 0x000100,
10624218822Sdim  N_I16  = 0x000200,
10625218822Sdim  N_I32  = 0x000400,
10626218822Sdim  N_I64  = 0x000800,
10627218822Sdim  N_8    = 0x001000,
10628218822Sdim  N_16   = 0x002000,
10629218822Sdim  N_32   = 0x004000,
10630218822Sdim  N_64   = 0x008000,
10631218822Sdim  N_P8   = 0x010000,
10632218822Sdim  N_P16  = 0x020000,
10633218822Sdim  N_F32  = 0x040000,
10634218822Sdim  N_F64  = 0x080000,
10635218822Sdim  N_KEY  = 0x100000, /* key element (main type specifier).  */
10636218822Sdim  N_EQK  = 0x200000, /* given operand has the same type & size as the key.  */
10637218822Sdim  N_VFP  = 0x400000, /* VFP mode: operand size must match register width.  */
10638218822Sdim  N_DBL  = 0x000001, /* if N_EQK, this operand is twice the size.  */
10639218822Sdim  N_HLF  = 0x000002, /* if N_EQK, this operand is half the size.  */
10640218822Sdim  N_SGN  = 0x000004, /* if N_EQK, this operand is forced to be signed.  */
10641218822Sdim  N_UNS  = 0x000008, /* if N_EQK, this operand is forced to be unsigned.  */
10642218822Sdim  N_INT  = 0x000010, /* if N_EQK, this operand is forced to be integer.  */
10643218822Sdim  N_FLT  = 0x000020, /* if N_EQK, this operand is forced to be float.  */
10644218822Sdim  N_SIZ  = 0x000040, /* if N_EQK, this operand is forced to be size-only.  */
10645218822Sdim  N_UTYP = 0,
10646218822Sdim  N_MAX_NONSPECIAL = N_F64
10647218822Sdim};
1064889857Sobrien
10649218822Sdim#define N_ALLMODS  (N_DBL | N_HLF | N_SGN | N_UNS | N_INT | N_FLT | N_SIZ)
1065089857Sobrien
10651218822Sdim#define N_SU_ALL   (N_S8 | N_S16 | N_S32 | N_S64 | N_U8 | N_U16 | N_U32 | N_U64)
10652218822Sdim#define N_SU_32    (N_S8 | N_S16 | N_S32 | N_U8 | N_U16 | N_U32)
10653218822Sdim#define N_SU_16_64 (N_S16 | N_S32 | N_S64 | N_U16 | N_U32 | N_U64)
10654218822Sdim#define N_SUF_32   (N_SU_32 | N_F32)
10655218822Sdim#define N_I_ALL    (N_I8 | N_I16 | N_I32 | N_I64)
10656218822Sdim#define N_IF_32    (N_I8 | N_I16 | N_I32 | N_F32)
1065789857Sobrien
10658218822Sdim/* Pass this as the first type argument to neon_check_type to ignore types
10659218822Sdim   altogether.  */
10660218822Sdim#define N_IGNORE_TYPE (N_KEY | N_EQK)
1066189857Sobrien
10662218822Sdim/* Select a "shape" for the current instruction (describing register types or
10663218822Sdim   sizes) from a list of alternatives. Return NS_NULL if the current instruction
10664218822Sdim   doesn't fit. For non-polymorphic shapes, checking is usually done as a
10665218822Sdim   function of operand parsing, so this function doesn't need to be called.
10666218822Sdim   Shapes should be listed in order of decreasing length.  */
1066789857Sobrien
10668218822Sdimstatic enum neon_shape
10669218822Sdimneon_select_shape (enum neon_shape shape, ...)
10670218822Sdim{
10671218822Sdim  va_list ap;
10672218822Sdim  enum neon_shape first_shape = shape;
1067389857Sobrien
10674218822Sdim  /* Fix missing optional operands. FIXME: we don't know at this point how
10675218822Sdim     many arguments we should have, so this makes the assumption that we have
10676218822Sdim     > 1. This is true of all current Neon opcodes, I think, but may not be
10677218822Sdim     true in the future.  */
10678218822Sdim  if (!inst.operands[1].present)
10679218822Sdim    inst.operands[1] = inst.operands[0];
1068089857Sobrien
10681218822Sdim  va_start (ap, shape);
10682218822Sdim
10683218822Sdim  for (; shape != NS_NULL; shape = va_arg (ap, int))
10684218822Sdim    {
10685218822Sdim      unsigned j;
10686218822Sdim      int matches = 1;
1068789857Sobrien
10688218822Sdim      for (j = 0; j < neon_shape_tab[shape].els; j++)
10689218822Sdim        {
10690218822Sdim          if (!inst.operands[j].present)
10691218822Sdim            {
10692218822Sdim              matches = 0;
10693218822Sdim              break;
10694218822Sdim            }
1069589857Sobrien
10696218822Sdim          switch (neon_shape_tab[shape].el[j])
10697218822Sdim            {
10698218822Sdim            case SE_F:
10699218822Sdim              if (!(inst.operands[j].isreg
10700218822Sdim                    && inst.operands[j].isvec
10701218822Sdim                    && inst.operands[j].issingle
10702218822Sdim                    && !inst.operands[j].isquad))
10703218822Sdim                matches = 0;
10704218822Sdim              break;
1070589857Sobrien
10706218822Sdim            case SE_D:
10707218822Sdim              if (!(inst.operands[j].isreg
10708218822Sdim                    && inst.operands[j].isvec
10709218822Sdim                    && !inst.operands[j].isquad
10710218822Sdim                    && !inst.operands[j].issingle))
10711218822Sdim                matches = 0;
10712218822Sdim              break;
1071389857Sobrien
10714218822Sdim            case SE_R:
10715218822Sdim              if (!(inst.operands[j].isreg
10716218822Sdim                    && !inst.operands[j].isvec))
10717218822Sdim                matches = 0;
10718218822Sdim              break;
1071989857Sobrien
10720218822Sdim            case SE_Q:
10721218822Sdim              if (!(inst.operands[j].isreg
10722218822Sdim                    && inst.operands[j].isvec
10723218822Sdim                    && inst.operands[j].isquad
10724218822Sdim                    && !inst.operands[j].issingle))
10725218822Sdim                matches = 0;
10726218822Sdim              break;
1072789857Sobrien
10728218822Sdim            case SE_I:
10729218822Sdim              if (!(!inst.operands[j].isreg
10730218822Sdim                    && !inst.operands[j].isscalar))
10731218822Sdim                matches = 0;
10732218822Sdim              break;
1073389857Sobrien
10734218822Sdim            case SE_S:
10735218822Sdim              if (!(!inst.operands[j].isreg
10736218822Sdim                    && inst.operands[j].isscalar))
10737218822Sdim                matches = 0;
10738218822Sdim              break;
10739218822Sdim
10740218822Sdim            case SE_L:
10741218822Sdim              break;
10742218822Sdim            }
10743218822Sdim        }
10744218822Sdim      if (matches)
10745218822Sdim        break;
1074689857Sobrien    }
10747218822Sdim
10748218822Sdim  va_end (ap);
1074989857Sobrien
10750218822Sdim  if (shape == NS_NULL && first_shape != NS_NULL)
10751218822Sdim    first_error (_("invalid instruction shape"));
1075289857Sobrien
10753218822Sdim  return shape;
10754218822Sdim}
1075589857Sobrien
10756218822Sdim/* True if SHAPE is predominantly a quadword operation (most of the time, this
10757218822Sdim   means the Q bit should be set).  */
1075889857Sobrien
10759218822Sdimstatic int
10760218822Sdimneon_quad (enum neon_shape shape)
10761218822Sdim{
10762218822Sdim  return neon_shape_class[shape] == SC_QUAD;
10763218822Sdim}
10764218822Sdim
10765218822Sdimstatic void
10766218822Sdimneon_modify_type_size (unsigned typebits, enum neon_el_type *g_type,
10767218822Sdim                       unsigned *g_size)
10768218822Sdim{
10769218822Sdim  /* Allow modification to be made to types which are constrained to be
10770218822Sdim     based on the key element, based on bits set alongside N_EQK.  */
10771218822Sdim  if ((typebits & N_EQK) != 0)
1077289857Sobrien    {
10773218822Sdim      if ((typebits & N_HLF) != 0)
10774218822Sdim	*g_size /= 2;
10775218822Sdim      else if ((typebits & N_DBL) != 0)
10776218822Sdim	*g_size *= 2;
10777218822Sdim      if ((typebits & N_SGN) != 0)
10778218822Sdim	*g_type = NT_signed;
10779218822Sdim      else if ((typebits & N_UNS) != 0)
10780218822Sdim        *g_type = NT_unsigned;
10781218822Sdim      else if ((typebits & N_INT) != 0)
10782218822Sdim        *g_type = NT_integer;
10783218822Sdim      else if ((typebits & N_FLT) != 0)
10784218822Sdim        *g_type = NT_float;
10785218822Sdim      else if ((typebits & N_SIZ) != 0)
10786218822Sdim        *g_type = NT_untyped;
1078789857Sobrien    }
10788218822Sdim}
10789218822Sdim
10790218822Sdim/* Return operand OPNO promoted by bits set in THISARG. KEY should be the "key"
10791218822Sdim   operand type, i.e. the single type specified in a Neon instruction when it
10792218822Sdim   is the only one given.  */
1079389857Sobrien
10794218822Sdimstatic struct neon_type_el
10795218822Sdimneon_type_promote (struct neon_type_el *key, unsigned thisarg)
10796218822Sdim{
10797218822Sdim  struct neon_type_el dest = *key;
10798218822Sdim
10799218822Sdim  assert ((thisarg & N_EQK) != 0);
10800218822Sdim
10801218822Sdim  neon_modify_type_size (thisarg, &dest.type, &dest.size);
10802218822Sdim
10803218822Sdim  return dest;
1080489857Sobrien}
1080589857Sobrien
10806218822Sdim/* Convert Neon type and size into compact bitmask representation.  */
10807218822Sdim
10808218822Sdimstatic enum neon_type_mask
10809218822Sdimtype_chk_of_el_type (enum neon_el_type type, unsigned size)
1081089857Sobrien{
10811218822Sdim  switch (type)
10812218822Sdim    {
10813218822Sdim    case NT_untyped:
10814218822Sdim      switch (size)
10815218822Sdim        {
10816218822Sdim        case 8:  return N_8;
10817218822Sdim        case 16: return N_16;
10818218822Sdim        case 32: return N_32;
10819218822Sdim        case 64: return N_64;
10820218822Sdim        default: ;
10821218822Sdim        }
10822218822Sdim      break;
1082389857Sobrien
10824218822Sdim    case NT_integer:
10825218822Sdim      switch (size)
10826218822Sdim        {
10827218822Sdim        case 8:  return N_I8;
10828218822Sdim        case 16: return N_I16;
10829218822Sdim        case 32: return N_I32;
10830218822Sdim        case 64: return N_I64;
10831218822Sdim        default: ;
10832218822Sdim        }
10833218822Sdim      break;
1083489857Sobrien
10835218822Sdim    case NT_float:
10836218822Sdim      switch (size)
10837218822Sdim        {
10838218822Sdim        case 32: return N_F32;
10839218822Sdim        case 64: return N_F64;
10840218822Sdim        default: ;
10841218822Sdim        }
10842218822Sdim      break;
1084389857Sobrien
10844218822Sdim    case NT_poly:
10845218822Sdim      switch (size)
10846218822Sdim        {
10847218822Sdim        case 8:  return N_P8;
10848218822Sdim        case 16: return N_P16;
10849218822Sdim        default: ;
10850218822Sdim        }
10851218822Sdim      break;
1085289857Sobrien
10853218822Sdim    case NT_signed:
10854218822Sdim      switch (size)
10855218822Sdim        {
10856218822Sdim        case 8:  return N_S8;
10857218822Sdim        case 16: return N_S16;
10858218822Sdim        case 32: return N_S32;
10859218822Sdim        case 64: return N_S64;
10860218822Sdim        default: ;
10861218822Sdim        }
10862218822Sdim      break;
1086389857Sobrien
10864218822Sdim    case NT_unsigned:
10865218822Sdim      switch (size)
10866218822Sdim        {
10867218822Sdim        case 8:  return N_U8;
10868218822Sdim        case 16: return N_U16;
10869218822Sdim        case 32: return N_U32;
10870218822Sdim        case 64: return N_U64;
10871218822Sdim        default: ;
10872218822Sdim        }
10873218822Sdim      break;
1087489857Sobrien
10875218822Sdim    default: ;
10876218822Sdim    }
10877218822Sdim
10878218822Sdim  return N_UTYP;
10879218822Sdim}
1088089857Sobrien
10881218822Sdim/* Convert compact Neon bitmask type representation to a type and size. Only
10882218822Sdim   handles the case where a single bit is set in the mask.  */
1088389857Sobrien
10884218822Sdimstatic int
10885218822Sdimel_type_of_type_chk (enum neon_el_type *type, unsigned *size,
10886218822Sdim                     enum neon_type_mask mask)
10887218822Sdim{
10888218822Sdim  if ((mask & N_EQK) != 0)
10889218822Sdim    return FAIL;
1089089857Sobrien
10891218822Sdim  if ((mask & (N_S8 | N_U8 | N_I8 | N_8 | N_P8)) != 0)
10892218822Sdim    *size = 8;
10893218822Sdim  else if ((mask & (N_S16 | N_U16 | N_I16 | N_16 | N_P16)) != 0)
10894218822Sdim    *size = 16;
10895218822Sdim  else if ((mask & (N_S32 | N_U32 | N_I32 | N_32 | N_F32)) != 0)
10896218822Sdim    *size = 32;
10897218822Sdim  else if ((mask & (N_S64 | N_U64 | N_I64 | N_64 | N_F64)) != 0)
10898218822Sdim    *size = 64;
10899218822Sdim  else
10900218822Sdim    return FAIL;
1090189857Sobrien
10902218822Sdim  if ((mask & (N_S8 | N_S16 | N_S32 | N_S64)) != 0)
10903218822Sdim    *type = NT_signed;
10904218822Sdim  else if ((mask & (N_U8 | N_U16 | N_U32 | N_U64)) != 0)
10905218822Sdim    *type = NT_unsigned;
10906218822Sdim  else if ((mask & (N_I8 | N_I16 | N_I32 | N_I64)) != 0)
10907218822Sdim    *type = NT_integer;
10908218822Sdim  else if ((mask & (N_8 | N_16 | N_32 | N_64)) != 0)
10909218822Sdim    *type = NT_untyped;
10910218822Sdim  else if ((mask & (N_P8 | N_P16)) != 0)
10911218822Sdim    *type = NT_poly;
10912218822Sdim  else if ((mask & (N_F32 | N_F64)) != 0)
10913218822Sdim    *type = NT_float;
10914218822Sdim  else
10915218822Sdim    return FAIL;
10916218822Sdim
10917218822Sdim  return SUCCESS;
10918218822Sdim}
1091989857Sobrien
10920218822Sdim/* Modify a bitmask of allowed types. This is only needed for type
10921218822Sdim   relaxation.  */
1092289857Sobrien
10923218822Sdimstatic unsigned
10924218822Sdimmodify_types_allowed (unsigned allowed, unsigned mods)
10925218822Sdim{
10926218822Sdim  unsigned size;
10927218822Sdim  enum neon_el_type type;
10928218822Sdim  unsigned destmask;
10929218822Sdim  int i;
10930218822Sdim
10931218822Sdim  destmask = 0;
10932218822Sdim
10933218822Sdim  for (i = 1; i <= N_MAX_NONSPECIAL; i <<= 1)
10934218822Sdim    {
10935218822Sdim      if (el_type_of_type_chk (&type, &size, allowed & i) == SUCCESS)
10936218822Sdim        {
10937218822Sdim          neon_modify_type_size (mods, &type, &size);
10938218822Sdim          destmask |= type_chk_of_el_type (type, size);
10939218822Sdim        }
10940218822Sdim    }
10941218822Sdim
10942218822Sdim  return destmask;
10943218822Sdim}
1094489857Sobrien
10945218822Sdim/* Check type and return type classification.
10946218822Sdim   The manual states (paraphrase): If one datatype is given, it indicates the
10947218822Sdim   type given in:
10948218822Sdim    - the second operand, if there is one
10949218822Sdim    - the operand, if there is no second operand
10950218822Sdim    - the result, if there are no operands.
10951218822Sdim   This isn't quite good enough though, so we use a concept of a "key" datatype
10952218822Sdim   which is set on a per-instruction basis, which is the one which matters when
10953218822Sdim   only one data type is written.
10954218822Sdim   Note: this function has side-effects (e.g. filling in missing operands). All
10955218822Sdim   Neon instructions should call it before performing bit encoding.  */
1095689857Sobrien
10957218822Sdimstatic struct neon_type_el
10958218822Sdimneon_check_type (unsigned els, enum neon_shape ns, ...)
10959218822Sdim{
10960218822Sdim  va_list ap;
10961218822Sdim  unsigned i, pass, key_el = 0;
10962218822Sdim  unsigned types[NEON_MAX_TYPE_ELS];
10963218822Sdim  enum neon_el_type k_type = NT_invtype;
10964218822Sdim  unsigned k_size = -1u;
10965218822Sdim  struct neon_type_el badtype = {NT_invtype, -1};
10966218822Sdim  unsigned key_allowed = 0;
1096789857Sobrien
10968218822Sdim  /* Optional registers in Neon instructions are always (not) in operand 1.
10969218822Sdim     Fill in the missing operand here, if it was omitted.  */
10970218822Sdim  if (els > 1 && !inst.operands[1].present)
10971218822Sdim    inst.operands[1] = inst.operands[0];
1097289857Sobrien
10973218822Sdim  /* Suck up all the varargs.  */
10974218822Sdim  va_start (ap, ns);
10975218822Sdim  for (i = 0; i < els; i++)
10976218822Sdim    {
10977218822Sdim      unsigned thisarg = va_arg (ap, unsigned);
10978218822Sdim      if (thisarg == N_IGNORE_TYPE)
10979218822Sdim        {
10980218822Sdim          va_end (ap);
10981218822Sdim          return badtype;
10982218822Sdim        }
10983218822Sdim      types[i] = thisarg;
10984218822Sdim      if ((thisarg & N_KEY) != 0)
10985218822Sdim        key_el = i;
1098689857Sobrien    }
10987218822Sdim  va_end (ap);
1098889857Sobrien
10989218822Sdim  if (inst.vectype.elems > 0)
10990218822Sdim    for (i = 0; i < els; i++)
10991218822Sdim      if (inst.operands[i].vectype.type != NT_invtype)
10992218822Sdim        {
10993218822Sdim          first_error (_("types specified in both the mnemonic and operands"));
10994218822Sdim          return badtype;
10995218822Sdim        }
10996218822Sdim
10997218822Sdim  /* Duplicate inst.vectype elements here as necessary.
10998218822Sdim     FIXME: No idea if this is exactly the same as the ARM assembler,
10999218822Sdim     particularly when an insn takes one register and one non-register
11000218822Sdim     operand. */
11001218822Sdim  if (inst.vectype.elems == 1 && els > 1)
1100289857Sobrien    {
11003218822Sdim      unsigned j;
11004218822Sdim      inst.vectype.elems = els;
11005218822Sdim      inst.vectype.el[key_el] = inst.vectype.el[0];
11006218822Sdim      for (j = 0; j < els; j++)
11007218822Sdim        if (j != key_el)
11008218822Sdim          inst.vectype.el[j] = neon_type_promote (&inst.vectype.el[key_el],
11009218822Sdim                                                  types[j]);
1101089857Sobrien    }
11011218822Sdim  else if (inst.vectype.elems == 0 && els > 0)
11012218822Sdim    {
11013218822Sdim      unsigned j;
11014218822Sdim      /* No types were given after the mnemonic, so look for types specified
11015218822Sdim         after each operand. We allow some flexibility here; as long as the
11016218822Sdim         "key" operand has a type, we can infer the others.  */
11017218822Sdim      for (j = 0; j < els; j++)
11018218822Sdim        if (inst.operands[j].vectype.type != NT_invtype)
11019218822Sdim          inst.vectype.el[j] = inst.operands[j].vectype;
1102089857Sobrien
11021218822Sdim      if (inst.operands[key_el].vectype.type != NT_invtype)
11022218822Sdim        {
11023218822Sdim          for (j = 0; j < els; j++)
11024218822Sdim            if (inst.operands[j].vectype.type == NT_invtype)
11025218822Sdim              inst.vectype.el[j] = neon_type_promote (&inst.vectype.el[key_el],
11026218822Sdim                                                      types[j]);
11027218822Sdim        }
11028218822Sdim      else
11029218822Sdim        {
11030218822Sdim          first_error (_("operand types can't be inferred"));
11031218822Sdim          return badtype;
11032218822Sdim        }
11033218822Sdim    }
11034218822Sdim  else if (inst.vectype.elems != els)
11035218822Sdim    {
11036218822Sdim      first_error (_("type specifier has the wrong number of parts"));
11037218822Sdim      return badtype;
11038218822Sdim    }
1103989857Sobrien
11040218822Sdim  for (pass = 0; pass < 2; pass++)
11041218822Sdim    {
11042218822Sdim      for (i = 0; i < els; i++)
11043218822Sdim        {
11044218822Sdim          unsigned thisarg = types[i];
11045218822Sdim          unsigned types_allowed = ((thisarg & N_EQK) != 0 && pass != 0)
11046218822Sdim            ? modify_types_allowed (key_allowed, thisarg) : thisarg;
11047218822Sdim          enum neon_el_type g_type = inst.vectype.el[i].type;
11048218822Sdim          unsigned g_size = inst.vectype.el[i].size;
1104989857Sobrien
11050218822Sdim          /* Decay more-specific signed & unsigned types to sign-insensitive
11051218822Sdim	     integer types if sign-specific variants are unavailable.  */
11052218822Sdim          if ((g_type == NT_signed || g_type == NT_unsigned)
11053218822Sdim	      && (types_allowed & N_SU_ALL) == 0)
11054218822Sdim	    g_type = NT_integer;
1105589857Sobrien
11056218822Sdim          /* If only untyped args are allowed, decay any more specific types to
11057218822Sdim	     them. Some instructions only care about signs for some element
11058218822Sdim	     sizes, so handle that properly.  */
11059218822Sdim          if ((g_size == 8 && (types_allowed & N_8) != 0)
11060218822Sdim	      || (g_size == 16 && (types_allowed & N_16) != 0)
11061218822Sdim	      || (g_size == 32 && (types_allowed & N_32) != 0)
11062218822Sdim	      || (g_size == 64 && (types_allowed & N_64) != 0))
11063218822Sdim	    g_type = NT_untyped;
11064218822Sdim
11065218822Sdim          if (pass == 0)
11066218822Sdim            {
11067218822Sdim              if ((thisarg & N_KEY) != 0)
11068218822Sdim                {
11069218822Sdim                  k_type = g_type;
11070218822Sdim                  k_size = g_size;
11071218822Sdim                  key_allowed = thisarg & ~N_KEY;
11072218822Sdim                }
11073218822Sdim            }
11074218822Sdim          else
11075218822Sdim            {
11076218822Sdim              if ((thisarg & N_VFP) != 0)
11077218822Sdim                {
11078218822Sdim                  enum neon_shape_el regshape = neon_shape_tab[ns].el[i];
11079218822Sdim                  unsigned regwidth = neon_shape_el_size[regshape], match;
11080218822Sdim
11081218822Sdim                  /* In VFP mode, operands must match register widths. If we
11082218822Sdim                     have a key operand, use its width, else use the width of
11083218822Sdim                     the current operand.  */
11084218822Sdim                  if (k_size != -1u)
11085218822Sdim                    match = k_size;
11086218822Sdim                  else
11087218822Sdim                    match = g_size;
11088218822Sdim
11089218822Sdim                  if (regwidth != match)
11090218822Sdim                    {
11091218822Sdim                      first_error (_("operand size must match register width"));
11092218822Sdim                      return badtype;
11093218822Sdim                    }
11094218822Sdim                }
11095218822Sdim
11096218822Sdim              if ((thisarg & N_EQK) == 0)
11097218822Sdim                {
11098218822Sdim                  unsigned given_type = type_chk_of_el_type (g_type, g_size);
11099218822Sdim
11100218822Sdim                  if ((given_type & types_allowed) == 0)
11101218822Sdim                    {
11102218822Sdim	              first_error (_("bad type in Neon instruction"));
11103218822Sdim	              return badtype;
11104218822Sdim                    }
11105218822Sdim                }
11106218822Sdim              else
11107218822Sdim                {
11108218822Sdim                  enum neon_el_type mod_k_type = k_type;
11109218822Sdim                  unsigned mod_k_size = k_size;
11110218822Sdim                  neon_modify_type_size (thisarg, &mod_k_type, &mod_k_size);
11111218822Sdim                  if (g_type != mod_k_type || g_size != mod_k_size)
11112218822Sdim                    {
11113218822Sdim                      first_error (_("inconsistent types in Neon instruction"));
11114218822Sdim                      return badtype;
11115218822Sdim                    }
11116218822Sdim                }
11117218822Sdim            }
11118218822Sdim        }
1111989857Sobrien    }
1112089857Sobrien
11121218822Sdim  return inst.vectype.el[key_el];
1112289857Sobrien}
1112389857Sobrien
11124218822Sdim/* Neon-style VFP instruction forwarding.  */
11125218822Sdim
11126218822Sdim/* Thumb VFP instructions have 0xE in the condition field.  */
11127218822Sdim
1112889857Sobrienstatic void
11129218822Sdimdo_vfp_cond_or_thumb (void)
1113089857Sobrien{
11131218822Sdim  if (thumb_mode)
11132218822Sdim    inst.instruction |= 0xe0000000;
11133218822Sdim  else
11134218822Sdim    inst.instruction |= inst.cond << 28;
11135218822Sdim}
1113689857Sobrien
11137218822Sdim/* Look up and encode a simple mnemonic, for use as a helper function for the
11138218822Sdim   Neon-style VFP syntax.  This avoids duplication of bits of the insns table,
11139218822Sdim   etc.  It is assumed that operand parsing has already been done, and that the
11140218822Sdim   operands are in the form expected by the given opcode (this isn't necessarily
11141218822Sdim   the same as the form in which they were parsed, hence some massaging must
11142218822Sdim   take place before this function is called).
11143218822Sdim   Checks current arch version against that in the looked-up opcode.  */
1114489857Sobrien
11145218822Sdimstatic void
11146218822Sdimdo_vfp_nsyn_opcode (const char *opname)
11147218822Sdim{
11148218822Sdim  const struct asm_opcode *opcode;
11149218822Sdim
11150218822Sdim  opcode = hash_find (arm_ops_hsh, opname);
1115189857Sobrien
11152218822Sdim  if (!opcode)
11153218822Sdim    abort ();
1115489857Sobrien
11155218822Sdim  constraint (!ARM_CPU_HAS_FEATURE (cpu_variant,
11156218822Sdim                thumb_mode ? *opcode->tvariant : *opcode->avariant),
11157218822Sdim              _(BAD_FPU));
11158218822Sdim
11159218822Sdim  if (thumb_mode)
1116089857Sobrien    {
11161218822Sdim      inst.instruction = opcode->tvalue;
11162218822Sdim      opcode->tencode ();
1116389857Sobrien    }
11164218822Sdim  else
1116589857Sobrien    {
11166218822Sdim      inst.instruction = (inst.cond << 28) | opcode->avalue;
11167218822Sdim      opcode->aencode ();
1116889857Sobrien    }
1116989857Sobrien}
1117089857Sobrien
1117189857Sobrienstatic void
11172218822Sdimdo_vfp_nsyn_add_sub (enum neon_shape rs)
1117389857Sobrien{
11174218822Sdim  int is_add = (inst.instruction & 0x0fffffff) == N_MNEM_vadd;
1117589857Sobrien
11176218822Sdim  if (rs == NS_FFF)
11177218822Sdim    {
11178218822Sdim      if (is_add)
11179218822Sdim        do_vfp_nsyn_opcode ("fadds");
11180218822Sdim      else
11181218822Sdim        do_vfp_nsyn_opcode ("fsubs");
11182218822Sdim    }
11183218822Sdim  else
11184218822Sdim    {
11185218822Sdim      if (is_add)
11186218822Sdim        do_vfp_nsyn_opcode ("faddd");
11187218822Sdim      else
11188218822Sdim        do_vfp_nsyn_opcode ("fsubd");
11189218822Sdim    }
11190218822Sdim}
1119189857Sobrien
11192218822Sdim/* Check operand types to see if this is a VFP instruction, and if so call
11193218822Sdim   PFN ().  */
1119489857Sobrien
11195218822Sdimstatic int
11196218822Sdimtry_vfp_nsyn (int args, void (*pfn) (enum neon_shape))
11197218822Sdim{
11198218822Sdim  enum neon_shape rs;
11199218822Sdim  struct neon_type_el et;
1120089857Sobrien
11201218822Sdim  switch (args)
1120289857Sobrien    {
11203218822Sdim    case 2:
11204218822Sdim      rs = neon_select_shape (NS_FF, NS_DD, NS_NULL);
11205218822Sdim      et = neon_check_type (2, rs,
11206218822Sdim        N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
11207218822Sdim      break;
11208218822Sdim
11209218822Sdim    case 3:
11210218822Sdim      rs = neon_select_shape (NS_FFF, NS_DDD, NS_NULL);
11211218822Sdim      et = neon_check_type (3, rs,
11212218822Sdim        N_EQK | N_VFP, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
11213218822Sdim      break;
11214218822Sdim
11215218822Sdim    default:
11216218822Sdim      abort ();
1121789857Sobrien    }
1121889857Sobrien
11219218822Sdim  if (et.type != NT_invtype)
1122089857Sobrien    {
11221218822Sdim      pfn (rs);
11222218822Sdim      return SUCCESS;
1122389857Sobrien    }
11224218822Sdim  else
11225218822Sdim    inst.error = NULL;
1122689857Sobrien
11227218822Sdim  return FAIL;
1122889857Sobrien}
1122989857Sobrien
1123089857Sobrienstatic void
11231218822Sdimdo_vfp_nsyn_mla_mls (enum neon_shape rs)
1123289857Sobrien{
11233218822Sdim  int is_mla = (inst.instruction & 0x0fffffff) == N_MNEM_vmla;
11234218822Sdim
11235218822Sdim  if (rs == NS_FFF)
11236218822Sdim    {
11237218822Sdim      if (is_mla)
11238218822Sdim        do_vfp_nsyn_opcode ("fmacs");
11239218822Sdim      else
11240218822Sdim        do_vfp_nsyn_opcode ("fmscs");
11241218822Sdim    }
11242218822Sdim  else
11243218822Sdim    {
11244218822Sdim      if (is_mla)
11245218822Sdim        do_vfp_nsyn_opcode ("fmacd");
11246218822Sdim      else
11247218822Sdim        do_vfp_nsyn_opcode ("fmscd");
11248218822Sdim    }
1124989857Sobrien}
1125089857Sobrien
1125189857Sobrienstatic void
11252218822Sdimdo_vfp_nsyn_mul (enum neon_shape rs)
1125389857Sobrien{
11254218822Sdim  if (rs == NS_FFF)
11255218822Sdim    do_vfp_nsyn_opcode ("fmuls");
11256218822Sdim  else
11257218822Sdim    do_vfp_nsyn_opcode ("fmuld");
1125889857Sobrien}
1125989857Sobrien
1126089857Sobrienstatic void
11261218822Sdimdo_vfp_nsyn_abs_neg (enum neon_shape rs)
1126289857Sobrien{
11263218822Sdim  int is_neg = (inst.instruction & 0x80) != 0;
11264218822Sdim  neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_VFP | N_KEY);
11265218822Sdim
11266218822Sdim  if (rs == NS_FF)
11267218822Sdim    {
11268218822Sdim      if (is_neg)
11269218822Sdim        do_vfp_nsyn_opcode ("fnegs");
11270218822Sdim      else
11271218822Sdim        do_vfp_nsyn_opcode ("fabss");
11272218822Sdim    }
11273218822Sdim  else
11274218822Sdim    {
11275218822Sdim      if (is_neg)
11276218822Sdim        do_vfp_nsyn_opcode ("fnegd");
11277218822Sdim      else
11278218822Sdim        do_vfp_nsyn_opcode ("fabsd");
11279218822Sdim    }
1128089857Sobrien}
1128189857Sobrien
11282218822Sdim/* Encode single-precision (only!) VFP fldm/fstm instructions. Double precision
11283218822Sdim   insns belong to Neon, and are handled elsewhere.  */
11284218822Sdim
1128589857Sobrienstatic void
11286218822Sdimdo_vfp_nsyn_ldm_stm (int is_dbmode)
1128789857Sobrien{
11288218822Sdim  int is_ldm = (inst.instruction & (1 << 20)) != 0;
11289218822Sdim  if (is_ldm)
11290218822Sdim    {
11291218822Sdim      if (is_dbmode)
11292218822Sdim        do_vfp_nsyn_opcode ("fldmdbs");
11293218822Sdim      else
11294218822Sdim        do_vfp_nsyn_opcode ("fldmias");
11295218822Sdim    }
11296218822Sdim  else
11297218822Sdim    {
11298218822Sdim      if (is_dbmode)
11299218822Sdim        do_vfp_nsyn_opcode ("fstmdbs");
11300218822Sdim      else
11301218822Sdim        do_vfp_nsyn_opcode ("fstmias");
11302218822Sdim    }
1130389857Sobrien}
1130489857Sobrien
1130589857Sobrienstatic void
11306218822Sdimdo_vfp_nsyn_sqrt (void)
1130789857Sobrien{
11308218822Sdim  enum neon_shape rs = neon_select_shape (NS_FF, NS_DD, NS_NULL);
11309218822Sdim  neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
11310218822Sdim
11311218822Sdim  if (rs == NS_FF)
11312218822Sdim    do_vfp_nsyn_opcode ("fsqrts");
11313218822Sdim  else
11314218822Sdim    do_vfp_nsyn_opcode ("fsqrtd");
1131589857Sobrien}
1131689857Sobrien
1131789857Sobrienstatic void
11318218822Sdimdo_vfp_nsyn_div (void)
1131989857Sobrien{
11320218822Sdim  enum neon_shape rs = neon_select_shape (NS_FFF, NS_DDD, NS_NULL);
11321218822Sdim  neon_check_type (3, rs, N_EQK | N_VFP, N_EQK | N_VFP,
11322218822Sdim    N_F32 | N_F64 | N_KEY | N_VFP);
11323218822Sdim
11324218822Sdim  if (rs == NS_FFF)
11325218822Sdim    do_vfp_nsyn_opcode ("fdivs");
11326218822Sdim  else
11327218822Sdim    do_vfp_nsyn_opcode ("fdivd");
1132889857Sobrien}
1132989857Sobrien
1133089857Sobrienstatic void
11331218822Sdimdo_vfp_nsyn_nmul (void)
1133289857Sobrien{
11333218822Sdim  enum neon_shape rs = neon_select_shape (NS_FFF, NS_DDD, NS_NULL);
11334218822Sdim  neon_check_type (3, rs, N_EQK | N_VFP, N_EQK | N_VFP,
11335218822Sdim    N_F32 | N_F64 | N_KEY | N_VFP);
11336218822Sdim
11337218822Sdim  if (rs == NS_FFF)
1133889857Sobrien    {
11339218822Sdim      inst.instruction = NEON_ENC_SINGLE (inst.instruction);
11340218822Sdim      do_vfp_sp_dyadic ();
1134189857Sobrien    }
11342218822Sdim  else
11343218822Sdim    {
11344218822Sdim      inst.instruction = NEON_ENC_DOUBLE (inst.instruction);
11345218822Sdim      do_vfp_dp_rd_rn_rm ();
11346218822Sdim    }
11347218822Sdim  do_vfp_cond_or_thumb ();
1134889857Sobrien}
1134989857Sobrien
1135089857Sobrienstatic void
11351218822Sdimdo_vfp_nsyn_cmp (void)
1135289857Sobrien{
11353218822Sdim  if (inst.operands[1].isreg)
1135489857Sobrien    {
11355218822Sdim      enum neon_shape rs = neon_select_shape (NS_FF, NS_DD, NS_NULL);
11356218822Sdim      neon_check_type (2, rs, N_EQK | N_VFP, N_F32 | N_F64 | N_KEY | N_VFP);
11357218822Sdim
11358218822Sdim      if (rs == NS_FF)
11359218822Sdim        {
11360218822Sdim          inst.instruction = NEON_ENC_SINGLE (inst.instruction);
11361218822Sdim          do_vfp_sp_monadic ();
11362218822Sdim        }
11363218822Sdim      else
11364218822Sdim        {
11365218822Sdim          inst.instruction = NEON_ENC_DOUBLE (inst.instruction);
11366218822Sdim          do_vfp_dp_rd_rm ();
11367218822Sdim        }
1136889857Sobrien    }
11369218822Sdim  else
11370218822Sdim    {
11371218822Sdim      enum neon_shape rs = neon_select_shape (NS_FI, NS_DI, NS_NULL);
11372218822Sdim      neon_check_type (2, rs, N_F32 | N_F64 | N_KEY | N_VFP, N_EQK);
1137389857Sobrien
11374218822Sdim      switch (inst.instruction & 0x0fffffff)
11375218822Sdim        {
11376218822Sdim        case N_MNEM_vcmp:
11377218822Sdim          inst.instruction += N_MNEM_vcmpz - N_MNEM_vcmp;
11378218822Sdim          break;
11379218822Sdim        case N_MNEM_vcmpe:
11380218822Sdim          inst.instruction += N_MNEM_vcmpez - N_MNEM_vcmpe;
11381218822Sdim          break;
11382218822Sdim        default:
11383218822Sdim          abort ();
11384218822Sdim        }
11385218822Sdim
11386218822Sdim      if (rs == NS_FI)
11387218822Sdim        {
11388218822Sdim          inst.instruction = NEON_ENC_SINGLE (inst.instruction);
11389218822Sdim          do_vfp_sp_compare_z ();
11390218822Sdim        }
11391218822Sdim      else
11392218822Sdim        {
11393218822Sdim          inst.instruction = NEON_ENC_DOUBLE (inst.instruction);
11394218822Sdim          do_vfp_dp_rd ();
11395218822Sdim        }
11396218822Sdim    }
11397218822Sdim  do_vfp_cond_or_thumb ();
1139889857Sobrien}
1139989857Sobrien
1140089857Sobrienstatic void
11401218822Sdimnsyn_insert_sp (void)
1140289857Sobrien{
11403218822Sdim  inst.operands[1] = inst.operands[0];
11404218822Sdim  memset (&inst.operands[0], '\0', sizeof (inst.operands[0]));
11405218822Sdim  inst.operands[0].reg = 13;
11406218822Sdim  inst.operands[0].isreg = 1;
11407218822Sdim  inst.operands[0].writeback = 1;
11408218822Sdim  inst.operands[0].present = 1;
11409218822Sdim}
1141089857Sobrien
11411218822Sdimstatic void
11412218822Sdimdo_vfp_nsyn_push (void)
11413218822Sdim{
11414218822Sdim  nsyn_insert_sp ();
11415218822Sdim  if (inst.operands[1].issingle)
11416218822Sdim    do_vfp_nsyn_opcode ("fstmdbs");
11417218822Sdim  else
11418218822Sdim    do_vfp_nsyn_opcode ("fstmdbd");
1141989857Sobrien}
1142089857Sobrien
1142189857Sobrienstatic void
11422218822Sdimdo_vfp_nsyn_pop (void)
1142389857Sobrien{
11424218822Sdim  nsyn_insert_sp ();
11425218822Sdim  if (inst.operands[1].issingle)
11426218822Sdim    do_vfp_nsyn_opcode ("fldmias");
11427218822Sdim  else
11428218822Sdim    do_vfp_nsyn_opcode ("fldmiad");
11429218822Sdim}
1143089857Sobrien
11431218822Sdim/* Fix up Neon data-processing instructions, ORing in the correct bits for
11432218822Sdim   ARM mode or Thumb mode and moving the encoded bit 24 to bit 28.  */
1143389857Sobrien
11434218822Sdimstatic unsigned
11435218822Sdimneon_dp_fixup (unsigned i)
11436218822Sdim{
11437218822Sdim  if (thumb_mode)
1143889857Sobrien    {
11439218822Sdim      /* The U bit is at bit 24 by default. Move to bit 28 in Thumb mode.  */
11440218822Sdim      if (i & (1 << 24))
11441218822Sdim        i |= 1 << 28;
11442218822Sdim
11443218822Sdim      i &= ~(1 << 24);
11444218822Sdim
11445218822Sdim      i |= 0xef000000;
1144689857Sobrien    }
11447218822Sdim  else
11448218822Sdim    i |= 0xf2000000;
11449218822Sdim
11450218822Sdim  return i;
11451218822Sdim}
1145289857Sobrien
11453218822Sdim/* Turn a size (8, 16, 32, 64) into the respective bit number minus 3
11454218822Sdim   (0, 1, 2, 3).  */
11455218822Sdim
11456218822Sdimstatic unsigned
11457218822Sdimneon_logbits (unsigned x)
11458218822Sdim{
11459218822Sdim  return ffs (x) - 4;
1146089857Sobrien}
1146189857Sobrien
11462218822Sdim#define LOW4(R) ((R) & 0xf)
11463218822Sdim#define HI1(R) (((R) >> 4) & 1)
1146460484Sobrien
11465218822Sdim/* Encode insns with bit pattern:
1146677298Sobrien
11467218822Sdim  |28/24|23|22 |21 20|19 16|15 12|11    8|7|6|5|4|3  0|
11468218822Sdim  |  U  |x |D  |size | Rn  | Rd  |x x x x|N|Q|M|x| Rm |
11469218822Sdim
11470218822Sdim  SIZE is passed in bits. -1 means size field isn't changed, in case it has a
11471218822Sdim  different meaning for some instruction.  */
11472218822Sdim
11473218822Sdimstatic void
11474218822Sdimneon_three_same (int isquad, int ubit, int size)
1147560484Sobrien{
11476218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
11477218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
11478218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
11479218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
11480218822Sdim  inst.instruction |= LOW4 (inst.operands[2].reg);
11481218822Sdim  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
11482218822Sdim  inst.instruction |= (isquad != 0) << 6;
11483218822Sdim  inst.instruction |= (ubit != 0) << 24;
11484218822Sdim  if (size != -1)
11485218822Sdim    inst.instruction |= neon_logbits (size) << 20;
11486218822Sdim
11487218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
11488218822Sdim}
1148960484Sobrien
11490218822Sdim/* Encode instructions of the form:
1149160484Sobrien
11492218822Sdim  |28/24|23|22|21 20|19 18|17 16|15 12|11      7|6|5|4|3  0|
11493218822Sdim  |  U  |x |D |x  x |size |x  x | Rd  |x x x x x|Q|M|x| Rm |
1149460484Sobrien
11495218822Sdim  Don't write size if SIZE == -1.  */
1149660484Sobrien
11497218822Sdimstatic void
11498218822Sdimneon_two_same (int qbit, int ubit, int size)
11499218822Sdim{
11500218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
11501218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
11502218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg);
11503218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 5;
11504218822Sdim  inst.instruction |= (qbit != 0) << 6;
11505218822Sdim  inst.instruction |= (ubit != 0) << 24;
1150660484Sobrien
11507218822Sdim  if (size != -1)
11508218822Sdim    inst.instruction |= neon_logbits (size) << 18;
11509218822Sdim
11510218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1151160484Sobrien}
1151260484Sobrien
11513218822Sdim/* Neon instruction encoders, in approximate order of appearance.  */
1151477298Sobrien
1151560484Sobrienstatic void
11516218822Sdimdo_neon_dyadic_i_su (void)
1151760484Sobrien{
11518218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11519218822Sdim  struct neon_type_el et = neon_check_type (3, rs,
11520218822Sdim    N_EQK, N_EQK, N_SU_32 | N_KEY);
11521218822Sdim  neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
11522218822Sdim}
1152360484Sobrien
11524218822Sdimstatic void
11525218822Sdimdo_neon_dyadic_i64_su (void)
11526218822Sdim{
11527218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11528218822Sdim  struct neon_type_el et = neon_check_type (3, rs,
11529218822Sdim    N_EQK, N_EQK, N_SU_ALL | N_KEY);
11530218822Sdim  neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
11531218822Sdim}
1153260484Sobrien
11533218822Sdimstatic void
11534218822Sdimneon_imm_shift (int write_ubit, int uval, int isquad, struct neon_type_el et,
11535218822Sdim                unsigned immbits)
11536218822Sdim{
11537218822Sdim  unsigned size = et.size >> 3;
11538218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
11539218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
11540218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg);
11541218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 5;
11542218822Sdim  inst.instruction |= (isquad != 0) << 6;
11543218822Sdim  inst.instruction |= immbits << 16;
11544218822Sdim  inst.instruction |= (size >> 3) << 7;
11545218822Sdim  inst.instruction |= (size & 0x7) << 19;
11546218822Sdim  if (write_ubit)
11547218822Sdim    inst.instruction |= (uval != 0) << 24;
11548218822Sdim
11549218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
11550218822Sdim}
11551218822Sdim
11552218822Sdimstatic void
11553218822Sdimdo_neon_shl_imm (void)
11554218822Sdim{
11555218822Sdim  if (!inst.operands[2].isreg)
1155660484Sobrien    {
11557218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
11558218822Sdim      struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_KEY | N_I_ALL);
11559218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
11560218822Sdim      neon_imm_shift (FALSE, 0, neon_quad (rs), et, inst.operands[2].imm);
1156160484Sobrien    }
11562218822Sdim  else
11563218822Sdim    {
11564218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11565218822Sdim      struct neon_type_el et = neon_check_type (3, rs,
11566218822Sdim        N_EQK, N_SU_ALL | N_KEY, N_EQK | N_SGN);
11567218822Sdim      unsigned int tmp;
1156860484Sobrien
11569218822Sdim      /* VSHL/VQSHL 3-register variants have syntax such as:
11570218822Sdim           vshl.xx Dd, Dm, Dn
11571218822Sdim         whereas other 3-register operations encoded by neon_three_same have
11572218822Sdim         syntax like:
11573218822Sdim           vadd.xx Dd, Dn, Dm
11574218822Sdim         (i.e. with Dn & Dm reversed). Swap operands[1].reg and operands[2].reg
11575218822Sdim         here.  */
11576218822Sdim      tmp = inst.operands[2].reg;
11577218822Sdim      inst.operands[2].reg = inst.operands[1].reg;
11578218822Sdim      inst.operands[1].reg = tmp;
11579218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
11580218822Sdim      neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
11581218822Sdim    }
11582218822Sdim}
11583218822Sdim
11584218822Sdimstatic void
11585218822Sdimdo_neon_qshl_imm (void)
11586218822Sdim{
11587218822Sdim  if (!inst.operands[2].isreg)
1158860484Sobrien    {
11589218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
11590218822Sdim      struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_SU_ALL | N_KEY);
11591218822Sdim
11592218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
11593218822Sdim      neon_imm_shift (TRUE, et.type == NT_unsigned, neon_quad (rs), et,
11594218822Sdim                      inst.operands[2].imm);
1159560484Sobrien    }
1159660484Sobrien  else
1159760484Sobrien    {
11598218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11599218822Sdim      struct neon_type_el et = neon_check_type (3, rs,
11600218822Sdim        N_EQK, N_SU_ALL | N_KEY, N_EQK | N_SGN);
11601218822Sdim      unsigned int tmp;
1160260484Sobrien
11603218822Sdim      /* See note in do_neon_shl_imm.  */
11604218822Sdim      tmp = inst.operands[2].reg;
11605218822Sdim      inst.operands[2].reg = inst.operands[1].reg;
11606218822Sdim      inst.operands[1].reg = tmp;
11607218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
11608218822Sdim      neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
11609218822Sdim    }
11610218822Sdim}
11611218822Sdim
11612218822Sdimstatic void
11613218822Sdimdo_neon_rshl (void)
11614218822Sdim{
11615218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11616218822Sdim  struct neon_type_el et = neon_check_type (3, rs,
11617218822Sdim    N_EQK, N_EQK, N_SU_ALL | N_KEY);
11618218822Sdim  unsigned int tmp;
11619218822Sdim
11620218822Sdim  tmp = inst.operands[2].reg;
11621218822Sdim  inst.operands[2].reg = inst.operands[1].reg;
11622218822Sdim  inst.operands[1].reg = tmp;
11623218822Sdim  neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
11624218822Sdim}
11625218822Sdim
11626218822Sdimstatic int
11627218822Sdimneon_cmode_for_logic_imm (unsigned immediate, unsigned *immbits, int size)
11628218822Sdim{
11629218822Sdim  /* Handle .I8 pseudo-instructions.  */
11630218822Sdim  if (size == 8)
11631218822Sdim    {
11632218822Sdim      /* Unfortunately, this will make everything apart from zero out-of-range.
11633218822Sdim         FIXME is this the intended semantics? There doesn't seem much point in
11634218822Sdim         accepting .I8 if so.  */
11635218822Sdim      immediate |= immediate << 8;
11636218822Sdim      size = 16;
11637218822Sdim    }
11638218822Sdim
11639218822Sdim  if (size >= 32)
11640218822Sdim    {
11641218822Sdim      if (immediate == (immediate & 0x000000ff))
1164260484Sobrien	{
11643218822Sdim	  *immbits = immediate;
11644218822Sdim	  return 0x1;
1164560484Sobrien	}
11646218822Sdim      else if (immediate == (immediate & 0x0000ff00))
1164760484Sobrien	{
11648218822Sdim	  *immbits = immediate >> 8;
11649218822Sdim	  return 0x3;
1165060484Sobrien	}
11651218822Sdim      else if (immediate == (immediate & 0x00ff0000))
1165260484Sobrien	{
11653218822Sdim	  *immbits = immediate >> 16;
11654218822Sdim	  return 0x5;
1165560484Sobrien	}
11656218822Sdim      else if (immediate == (immediate & 0xff000000))
1165760484Sobrien	{
11658218822Sdim	  *immbits = immediate >> 24;
11659218822Sdim	  return 0x7;
1166060484Sobrien	}
11661218822Sdim      if ((immediate & 0xffff) != (immediate >> 16))
11662218822Sdim	goto bad_immediate;
11663218822Sdim      immediate &= 0xffff;
1166460484Sobrien    }
11665218822Sdim
11666218822Sdim  if (immediate == (immediate & 0x000000ff))
1166760484Sobrien    {
11668218822Sdim      *immbits = immediate;
11669218822Sdim      return 0x9;
11670218822Sdim    }
11671218822Sdim  else if (immediate == (immediate & 0x0000ff00))
11672218822Sdim    {
11673218822Sdim      *immbits = immediate >> 8;
11674218822Sdim      return 0xb;
11675218822Sdim    }
1167660484Sobrien
11677218822Sdim  bad_immediate:
11678218822Sdim  first_error (_("immediate value out of range"));
11679218822Sdim  return FAIL;
11680218822Sdim}
1168160484Sobrien
11682218822Sdim/* True if IMM has form 0bAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD for bits
11683218822Sdim   A, B, C, D.  */
1168460484Sobrien
11685218822Sdimstatic int
11686218822Sdimneon_bits_same_in_bytes (unsigned imm)
11687218822Sdim{
11688218822Sdim  return ((imm & 0x000000ff) == 0 || (imm & 0x000000ff) == 0x000000ff)
11689218822Sdim         && ((imm & 0x0000ff00) == 0 || (imm & 0x0000ff00) == 0x0000ff00)
11690218822Sdim         && ((imm & 0x00ff0000) == 0 || (imm & 0x00ff0000) == 0x00ff0000)
11691218822Sdim         && ((imm & 0xff000000) == 0 || (imm & 0xff000000) == 0xff000000);
11692218822Sdim}
1169360484Sobrien
11694218822Sdim/* For immediate of above form, return 0bABCD.  */
1169560484Sobrien
11696218822Sdimstatic unsigned
11697218822Sdimneon_squash_bits (unsigned imm)
11698218822Sdim{
11699218822Sdim  return (imm & 0x01) | ((imm & 0x0100) >> 7) | ((imm & 0x010000) >> 14)
11700218822Sdim         | ((imm & 0x01000000) >> 21);
11701218822Sdim}
1170260484Sobrien
11703218822Sdim/* Compress quarter-float representation to 0b...000 abcdefgh.  */
1170477298Sobrien
11705218822Sdimstatic unsigned
11706218822Sdimneon_qfloat_bits (unsigned imm)
11707218822Sdim{
11708218822Sdim  return ((imm >> 19) & 0x7f) | ((imm >> 24) & 0x80);
1170960484Sobrien}
1171060484Sobrien
11711218822Sdim/* Returns CMODE. IMMBITS [7:0] is set to bits suitable for inserting into
11712218822Sdim   the instruction. *OP is passed as the initial value of the op field, and
11713218822Sdim   may be set to a different value depending on the constant (i.e.
11714218822Sdim   "MOV I64, 0bAAAAAAAABBBB..." which uses OP = 1 despite being MOV not
11715218822Sdim   MVN).  If the immediate looks like a repeated parttern then also
11716218822Sdim   try smaller element sizes.  */
11717218822Sdim
11718218822Sdimstatic int
11719218822Sdimneon_cmode_for_move_imm (unsigned immlo, unsigned immhi, int float_p,
11720218822Sdim			 unsigned *immbits, int *op, int size,
11721218822Sdim			 enum neon_el_type type)
1172260484Sobrien{
11723218822Sdim  /* Only permit float immediates (including 0.0/-0.0) if the operand type is
11724218822Sdim     float.  */
11725218822Sdim  if (type == NT_float && !float_p)
11726218822Sdim    return FAIL;
1172760484Sobrien
11728218822Sdim  if (type == NT_float && is_quarter_float (immlo) && immhi == 0)
1172960484Sobrien    {
11730218822Sdim      if (size != 32 || *op == 1)
11731218822Sdim        return FAIL;
11732218822Sdim      *immbits = neon_qfloat_bits (immlo);
11733218822Sdim      return 0xf;
1173460484Sobrien    }
1173560484Sobrien
11736218822Sdim  if (size == 64)
1173760484Sobrien    {
11738218822Sdim      if (neon_bits_same_in_bytes (immhi)
11739218822Sdim	  && neon_bits_same_in_bytes (immlo))
11740218822Sdim	{
11741218822Sdim	  if (*op == 1)
11742218822Sdim	    return FAIL;
11743218822Sdim	  *immbits = (neon_squash_bits (immhi) << 4)
11744218822Sdim		     | neon_squash_bits (immlo);
11745218822Sdim	  *op = 1;
11746218822Sdim	  return 0xe;
11747218822Sdim	}
11748218822Sdim
11749218822Sdim      if (immhi != immlo)
11750218822Sdim	return FAIL;
1175160484Sobrien    }
11752218822Sdim
11753218822Sdim  if (size >= 32)
1175460484Sobrien    {
11755218822Sdim      if (immlo == (immlo & 0x000000ff))
1175660484Sobrien	{
11757218822Sdim	  *immbits = immlo;
11758218822Sdim	  return 0x0;
1175960484Sobrien	}
11760218822Sdim      else if (immlo == (immlo & 0x0000ff00))
1176160484Sobrien	{
11762218822Sdim	  *immbits = immlo >> 8;
11763218822Sdim	  return 0x2;
1176460484Sobrien	}
11765218822Sdim      else if (immlo == (immlo & 0x00ff0000))
1176660484Sobrien	{
11767218822Sdim	  *immbits = immlo >> 16;
11768218822Sdim	  return 0x4;
1176960484Sobrien	}
11770218822Sdim      else if (immlo == (immlo & 0xff000000))
1177160484Sobrien	{
11772218822Sdim	  *immbits = immlo >> 24;
11773218822Sdim	  return 0x6;
1177460484Sobrien	}
11775218822Sdim      else if (immlo == ((immlo & 0x0000ff00) | 0x000000ff))
11776218822Sdim	{
11777218822Sdim	  *immbits = (immlo >> 8) & 0xff;
11778218822Sdim	  return 0xc;
11779218822Sdim	}
11780218822Sdim      else if (immlo == ((immlo & 0x00ff0000) | 0x0000ffff))
11781218822Sdim	{
11782218822Sdim	  *immbits = (immlo >> 16) & 0xff;
11783218822Sdim	  return 0xd;
11784218822Sdim	}
1178560484Sobrien
11786218822Sdim      if ((immlo & 0xffff) != (immlo >> 16))
11787218822Sdim	return FAIL;
11788218822Sdim      immlo &= 0xffff;
1178960484Sobrien    }
11790218822Sdim
11791218822Sdim  if (size >= 16)
1179260484Sobrien    {
11793218822Sdim      if (immlo == (immlo & 0x000000ff))
1179460484Sobrien	{
11795218822Sdim	  *immbits = immlo;
11796218822Sdim	  return 0x8;
1179760484Sobrien	}
11798218822Sdim      else if (immlo == (immlo & 0x0000ff00))
1179960484Sobrien	{
11800218822Sdim	  *immbits = immlo >> 8;
11801218822Sdim	  return 0xa;
1180260484Sobrien	}
1180360484Sobrien
11804218822Sdim      if ((immlo & 0xff) != (immlo >> 8))
11805218822Sdim	return FAIL;
11806218822Sdim      immlo &= 0xff;
11807218822Sdim    }
1180860484Sobrien
11809218822Sdim  if (immlo == (immlo & 0x000000ff))
11810218822Sdim    {
11811218822Sdim      /* Don't allow MVN with 8-bit immediate.  */
11812218822Sdim      if (*op == 1)
11813218822Sdim	return FAIL;
11814218822Sdim      *immbits = immlo;
11815218822Sdim      return 0xe;
11816218822Sdim    }
1181760484Sobrien
11818218822Sdim  return FAIL;
11819218822Sdim}
1182060484Sobrien
11821218822Sdim/* Write immediate bits [7:0] to the following locations:
1182260484Sobrien
11823218822Sdim  |28/24|23     19|18 16|15                    4|3     0|
11824218822Sdim  |  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|
1182577298Sobrien
11826218822Sdim  This function is used by VMOV/VMVN/VORR/VBIC.  */
1182760484Sobrien
1182860484Sobrienstatic void
11829218822Sdimneon_write_immbits (unsigned immbits)
1183060484Sobrien{
11831218822Sdim  inst.instruction |= immbits & 0xf;
11832218822Sdim  inst.instruction |= ((immbits >> 4) & 0x7) << 16;
11833218822Sdim  inst.instruction |= ((immbits >> 7) & 0x1) << 24;
11834218822Sdim}
1183560484Sobrien
11836218822Sdim/* Invert low-order SIZE bits of XHI:XLO.  */
1183760484Sobrien
11838218822Sdimstatic void
11839218822Sdimneon_invert_size (unsigned *xlo, unsigned *xhi, int size)
11840218822Sdim{
11841218822Sdim  unsigned immlo = xlo ? *xlo : 0;
11842218822Sdim  unsigned immhi = xhi ? *xhi : 0;
1184360484Sobrien
11844218822Sdim  switch (size)
1184560484Sobrien    {
11846218822Sdim    case 8:
11847218822Sdim      immlo = (~immlo) & 0xff;
11848218822Sdim      break;
1184960484Sobrien
11850218822Sdim    case 16:
11851218822Sdim      immlo = (~immlo) & 0xffff;
11852218822Sdim      break;
1185360484Sobrien
11854218822Sdim    case 64:
11855218822Sdim      immhi = (~immhi) & 0xffffffff;
11856218822Sdim      /* fall through.  */
1185760484Sobrien
11858218822Sdim    case 32:
11859218822Sdim      immlo = (~immlo) & 0xffffffff;
11860218822Sdim      break;
1186160484Sobrien
11862218822Sdim    default:
11863218822Sdim      abort ();
1186460484Sobrien    }
11865218822Sdim
11866218822Sdim  if (xlo)
11867218822Sdim    *xlo = immlo;
11868218822Sdim
11869218822Sdim  if (xhi)
11870218822Sdim    *xhi = immhi;
11871218822Sdim}
11872218822Sdim
11873218822Sdimstatic void
11874218822Sdimdo_neon_logic (void)
11875218822Sdim{
11876218822Sdim  if (inst.operands[2].present && inst.operands[2].isreg)
11877218822Sdim    {
11878218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11879218822Sdim      neon_check_type (3, rs, N_IGNORE_TYPE);
11880218822Sdim      /* U bit and size field were set as part of the bitmask.  */
11881218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
11882218822Sdim      neon_three_same (neon_quad (rs), 0, -1);
11883218822Sdim    }
1188460484Sobrien  else
1188560484Sobrien    {
11886218822Sdim      enum neon_shape rs = neon_select_shape (NS_DI, NS_QI, NS_NULL);
11887218822Sdim      struct neon_type_el et = neon_check_type (2, rs,
11888218822Sdim        N_I8 | N_I16 | N_I32 | N_I64 | N_F32 | N_KEY, N_EQK);
11889218822Sdim      enum neon_opc opcode = inst.instruction & 0x0fffffff;
11890218822Sdim      unsigned immbits;
11891218822Sdim      int cmode;
11892218822Sdim
11893218822Sdim      if (et.type == NT_invtype)
11894218822Sdim        return;
11895218822Sdim
11896218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
11897218822Sdim
11898218822Sdim      immbits = inst.operands[1].imm;
11899218822Sdim      if (et.size == 64)
1190060484Sobrien	{
11901218822Sdim	  /* .i64 is a pseudo-op, so the immediate must be a repeating
11902218822Sdim	     pattern.  */
11903218822Sdim	  if (immbits != (inst.operands[1].regisimm ?
11904218822Sdim			  inst.operands[1].reg : 0))
11905218822Sdim	    {
11906218822Sdim	      /* Set immbits to an invalid constant.  */
11907218822Sdim	      immbits = 0xdeadbeef;
11908218822Sdim	    }
1190960484Sobrien	}
1191060484Sobrien
11911218822Sdim      switch (opcode)
11912218822Sdim        {
11913218822Sdim        case N_MNEM_vbic:
11914218822Sdim          cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
11915218822Sdim          break;
11916218822Sdim
11917218822Sdim        case N_MNEM_vorr:
11918218822Sdim          cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
11919218822Sdim          break;
11920218822Sdim
11921218822Sdim        case N_MNEM_vand:
11922218822Sdim          /* Pseudo-instruction for VBIC.  */
11923218822Sdim          neon_invert_size (&immbits, 0, et.size);
11924218822Sdim          cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
11925218822Sdim          break;
11926218822Sdim
11927218822Sdim        case N_MNEM_vorn:
11928218822Sdim          /* Pseudo-instruction for VORR.  */
11929218822Sdim          neon_invert_size (&immbits, 0, et.size);
11930218822Sdim          cmode = neon_cmode_for_logic_imm (immbits, &immbits, et.size);
11931218822Sdim          break;
11932218822Sdim
11933218822Sdim        default:
11934218822Sdim          abort ();
11935218822Sdim        }
1193660484Sobrien
11937218822Sdim      if (cmode == FAIL)
11938218822Sdim        return;
1193960484Sobrien
11940218822Sdim      inst.instruction |= neon_quad (rs) << 6;
11941218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
11942218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
11943218822Sdim      inst.instruction |= cmode << 8;
11944218822Sdim      neon_write_immbits (immbits);
11945218822Sdim
11946218822Sdim      inst.instruction = neon_dp_fixup (inst.instruction);
1194760484Sobrien    }
11948218822Sdim}
1194960484Sobrien
11950218822Sdimstatic void
11951218822Sdimdo_neon_bitfield (void)
11952218822Sdim{
11953218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11954218822Sdim  neon_check_type (3, rs, N_IGNORE_TYPE);
11955218822Sdim  neon_three_same (neon_quad (rs), 0, -1);
1195660484Sobrien}
1195760484Sobrien
1195860484Sobrienstatic void
11959218822Sdimneon_dyadic_misc (enum neon_el_type ubit_meaning, unsigned types,
11960218822Sdim                  unsigned destbits)
1196160484Sobrien{
11962218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
11963218822Sdim  struct neon_type_el et = neon_check_type (3, rs, N_EQK | destbits, N_EQK,
11964218822Sdim                                            types | N_KEY);
11965218822Sdim  if (et.type == NT_float)
1196660484Sobrien    {
11967218822Sdim      inst.instruction = NEON_ENC_FLOAT (inst.instruction);
11968218822Sdim      neon_three_same (neon_quad (rs), 0, -1);
1196960484Sobrien    }
11970218822Sdim  else
1197160484Sobrien    {
11972218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
11973218822Sdim      neon_three_same (neon_quad (rs), et.type == ubit_meaning, et.size);
1197460484Sobrien    }
11975218822Sdim}
1197689857Sobrien
11977218822Sdimstatic void
11978218822Sdimdo_neon_dyadic_if_su (void)
11979218822Sdim{
11980218822Sdim  neon_dyadic_misc (NT_unsigned, N_SUF_32, 0);
11981218822Sdim}
1198260484Sobrien
11983218822Sdimstatic void
11984218822Sdimdo_neon_dyadic_if_su_d (void)
11985218822Sdim{
11986218822Sdim  /* This version only allow D registers, but that constraint is enforced during
11987218822Sdim     operand parsing so we don't need to do anything extra here.  */
11988218822Sdim  neon_dyadic_misc (NT_unsigned, N_SUF_32, 0);
11989218822Sdim}
1199060484Sobrien
11991218822Sdimstatic void
11992218822Sdimdo_neon_dyadic_if_i_d (void)
11993218822Sdim{
11994218822Sdim  /* The "untyped" case can't happen. Do this to stop the "U" bit being
11995218822Sdim     affected if we specify unsigned args.  */
11996218822Sdim  neon_dyadic_misc (NT_untyped, N_IF_32, 0);
11997218822Sdim}
1199860484Sobrien
11999218822Sdimenum vfp_or_neon_is_neon_bits
12000218822Sdim{
12001218822Sdim  NEON_CHECK_CC = 1,
12002218822Sdim  NEON_CHECK_ARCH = 2
12003218822Sdim};
1200477298Sobrien
12005218822Sdim/* Call this function if an instruction which may have belonged to the VFP or
12006218822Sdim   Neon instruction sets, but turned out to be a Neon instruction (due to the
12007218822Sdim   operand types involved, etc.). We have to check and/or fix-up a couple of
12008218822Sdim   things:
1200960484Sobrien
12010218822Sdim     - Make sure the user hasn't attempted to make a Neon instruction
12011218822Sdim       conditional.
12012218822Sdim     - Alter the value in the condition code field if necessary.
12013218822Sdim     - Make sure that the arch supports Neon instructions.
1201460484Sobrien
12015218822Sdim   Which of these operations take place depends on bits from enum
12016218822Sdim   vfp_or_neon_is_neon_bits.
1201760484Sobrien
12018218822Sdim   WARNING: This function has side effects! If NEON_CHECK_CC is used and the
12019218822Sdim   current instruction's condition is COND_ALWAYS, the condition field is
12020218822Sdim   changed to inst.uncond_value. This is necessary because instructions shared
12021218822Sdim   between VFP and Neon may be conditional for the VFP variants only, and the
12022218822Sdim   unconditional Neon version must have, e.g., 0xF in the condition field.  */
1202360484Sobrien
12024218822Sdimstatic int
12025218822Sdimvfp_or_neon_is_neon (unsigned check)
12026218822Sdim{
12027218822Sdim  /* Conditions are always legal in Thumb mode (IT blocks).  */
12028218822Sdim  if (!thumb_mode && (check & NEON_CHECK_CC))
12029218822Sdim    {
12030218822Sdim      if (inst.cond != COND_ALWAYS)
12031218822Sdim        {
12032218822Sdim          first_error (_(BAD_COND));
12033218822Sdim          return FAIL;
12034218822Sdim        }
12035218822Sdim      if (inst.uncond_value != -1)
12036218822Sdim        inst.instruction |= inst.uncond_value << 28;
1203760484Sobrien    }
12038218822Sdim
12039218822Sdim  if ((check & NEON_CHECK_ARCH)
12040218822Sdim      && !ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1))
1204160484Sobrien    {
12042218822Sdim      first_error (_(BAD_FPU));
12043218822Sdim      return FAIL;
1204460484Sobrien    }
12045218822Sdim
12046218822Sdim  return SUCCESS;
12047218822Sdim}
1204860484Sobrien
12049218822Sdimstatic void
12050218822Sdimdo_neon_addsub_if_i (void)
12051218822Sdim{
12052218822Sdim  if (try_vfp_nsyn (3, do_vfp_nsyn_add_sub) == SUCCESS)
12053218822Sdim    return;
1205460484Sobrien
12055218822Sdim  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12056218822Sdim    return;
1205760484Sobrien
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 | N_I64, 0);
12061218822Sdim}
1206260484Sobrien
12063218822Sdim/* Swaps operands 1 and 2. If operand 1 (optional arg) was omitted, we want the
12064218822Sdim   result to be:
12065218822Sdim     V<op> A,B     (A is operand 0, B is operand 2)
12066218822Sdim   to mean:
12067218822Sdim     V<op> A,B,A
12068218822Sdim   not:
12069218822Sdim     V<op> A,B,B
12070218822Sdim   so handle that case specially.  */
1207160484Sobrien
12072218822Sdimstatic void
12073218822Sdimneon_exchange_operands (void)
12074218822Sdim{
12075218822Sdim  void *scratch = alloca (sizeof (inst.operands[0]));
12076218822Sdim  if (inst.operands[1].present)
12077218822Sdim    {
12078218822Sdim      /* Swap operands[1] and operands[2].  */
12079218822Sdim      memcpy (scratch, &inst.operands[1], sizeof (inst.operands[0]));
12080218822Sdim      inst.operands[1] = inst.operands[2];
12081218822Sdim      memcpy (&inst.operands[2], scratch, sizeof (inst.operands[0]));
1208260484Sobrien    }
12083218822Sdim  else
1208460484Sobrien    {
12085218822Sdim      inst.operands[1] = inst.operands[2];
12086218822Sdim      inst.operands[2] = inst.operands[0];
1208760484Sobrien    }
12088218822Sdim}
12089218822Sdim
12090218822Sdimstatic void
12091218822Sdimneon_compare (unsigned regtypes, unsigned immtypes, int invert)
12092218822Sdim{
12093218822Sdim  if (inst.operands[2].isreg)
1209460484Sobrien    {
12095218822Sdim      if (invert)
12096218822Sdim        neon_exchange_operands ();
12097218822Sdim      neon_dyadic_misc (NT_unsigned, regtypes, N_SIZ);
1209860484Sobrien    }
1209960484Sobrien  else
1210060484Sobrien    {
12101218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
12102218822Sdim      struct neon_type_el et = neon_check_type (2, rs,
12103218822Sdim        N_EQK | N_SIZ, immtypes | N_KEY);
1210460484Sobrien
12105218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
12106218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12107218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12108218822Sdim      inst.instruction |= LOW4 (inst.operands[1].reg);
12109218822Sdim      inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12110218822Sdim      inst.instruction |= neon_quad (rs) << 6;
12111218822Sdim      inst.instruction |= (et.type == NT_float) << 10;
12112218822Sdim      inst.instruction |= neon_logbits (et.size) << 18;
12113218822Sdim
12114218822Sdim      inst.instruction = neon_dp_fixup (inst.instruction);
1211560484Sobrien    }
12116218822Sdim}
1211760484Sobrien
12118218822Sdimstatic void
12119218822Sdimdo_neon_cmp (void)
12120218822Sdim{
12121218822Sdim  neon_compare (N_SUF_32, N_S8 | N_S16 | N_S32 | N_F32, FALSE);
1212260484Sobrien}
1212360484Sobrien
12124218822Sdimstatic void
12125218822Sdimdo_neon_cmp_inv (void)
12126218822Sdim{
12127218822Sdim  neon_compare (N_SUF_32, N_S8 | N_S16 | N_S32 | N_F32, TRUE);
12128218822Sdim}
1212989857Sobrien
12130218822Sdimstatic void
12131218822Sdimdo_neon_ceq (void)
12132218822Sdim{
12133218822Sdim  neon_compare (N_IF_32, N_IF_32, FALSE);
12134218822Sdim}
1213589857Sobrien
12136218822Sdim/* For multiply instructions, we have the possibility of 16-bit or 32-bit
12137218822Sdim   scalars, which are encoded in 5 bits, M : Rm.
12138218822Sdim   For 16-bit scalars, the register is encoded in Rm[2:0] and the index in
12139218822Sdim   M:Rm[3], and for 32-bit scalars, the register is encoded in Rm[3:0] and the
12140218822Sdim   index in M.  */
1214189857Sobrien
12142218822Sdimstatic unsigned
12143218822Sdimneon_scalar_for_mul (unsigned scalar, unsigned elsize)
1214489857Sobrien{
12145218822Sdim  unsigned regno = NEON_SCALAR_REG (scalar);
12146218822Sdim  unsigned elno = NEON_SCALAR_INDEX (scalar);
1214789857Sobrien
12148218822Sdim  switch (elsize)
1214989857Sobrien    {
12150218822Sdim    case 16:
12151218822Sdim      if (regno > 7 || elno > 3)
12152218822Sdim        goto bad_scalar;
12153218822Sdim      return regno | (elno << 3);
12154218822Sdim
12155218822Sdim    case 32:
12156218822Sdim      if (regno > 15 || elno > 1)
12157218822Sdim        goto bad_scalar;
12158218822Sdim      return regno | (elno << 4);
1215989857Sobrien
12160218822Sdim    default:
12161218822Sdim    bad_scalar:
12162218822Sdim      first_error (_("scalar out of range for multiply instruction"));
1216389857Sobrien    }
1216489857Sobrien
12165218822Sdim  return 0;
12166218822Sdim}
1216799461Sobrien
12168218822Sdim/* Encode multiply / multiply-accumulate scalar instructions.  */
12169104834Sobrien
12170218822Sdimstatic void
12171218822Sdimneon_mul_mac (struct neon_type_el et, int ubit)
12172218822Sdim{
12173218822Sdim  unsigned scalar;
12174218822Sdim
12175218822Sdim  /* Give a more helpful error message if we have an invalid type.  */
12176218822Sdim  if (et.type == NT_invtype)
12177218822Sdim    return;
12178218822Sdim
12179218822Sdim  scalar = neon_scalar_for_mul (inst.operands[2].reg, et.size);
12180218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12181218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12182218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
12183218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
12184218822Sdim  inst.instruction |= LOW4 (scalar);
12185218822Sdim  inst.instruction |= HI1 (scalar) << 5;
12186218822Sdim  inst.instruction |= (et.type == NT_float) << 8;
12187218822Sdim  inst.instruction |= neon_logbits (et.size) << 20;
12188218822Sdim  inst.instruction |= (ubit != 0) << 24;
12189218822Sdim
12190218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1219189857Sobrien}
1219289857Sobrien
12193218822Sdimstatic void
12194218822Sdimdo_neon_mac_maybe_scalar (void)
12195218822Sdim{
12196218822Sdim  if (try_vfp_nsyn (3, do_vfp_nsyn_mla_mls) == SUCCESS)
12197218822Sdim    return;
1219889857Sobrien
12199218822Sdim  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12200218822Sdim    return;
1220189857Sobrien
12202218822Sdim  if (inst.operands[2].isscalar)
12203218822Sdim    {
12204218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDS, NS_QQS, NS_NULL);
12205218822Sdim      struct neon_type_el et = neon_check_type (3, rs,
12206218822Sdim        N_EQK, N_EQK, N_I16 | N_I32 | N_F32 | N_KEY);
12207218822Sdim      inst.instruction = NEON_ENC_SCALAR (inst.instruction);
12208218822Sdim      neon_mul_mac (et, neon_quad (rs));
12209218822Sdim    }
12210218822Sdim  else
12211218822Sdim    {
12212218822Sdim      /* The "untyped" case can't happen.  Do this to stop the "U" bit being
12213218822Sdim	 affected if we specify unsigned args.  */
12214218822Sdim      neon_dyadic_misc (NT_untyped, N_IF_32, 0);
12215218822Sdim    }
12216218822Sdim}
12217218822Sdim
1221860484Sobrienstatic void
12219218822Sdimdo_neon_tst (void)
1222089857Sobrien{
12221218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
12222218822Sdim  struct neon_type_el et = neon_check_type (3, rs,
12223218822Sdim    N_EQK, N_EQK, N_8 | N_16 | N_32 | N_KEY);
12224218822Sdim  neon_three_same (neon_quad (rs), 0, et.size);
1222589857Sobrien}
1222689857Sobrien
12227218822Sdim/* VMUL with 3 registers allows the P8 type. The scalar version supports the
12228218822Sdim   same types as the MAC equivalents. The polynomial type for this instruction
12229218822Sdim   is encoded the same as the integer type.  */
12230218822Sdim
1223189857Sobrienstatic void
12232218822Sdimdo_neon_mul (void)
1223389857Sobrien{
12234218822Sdim  if (try_vfp_nsyn (3, do_vfp_nsyn_mul) == SUCCESS)
12235218822Sdim    return;
12236218822Sdim
12237218822Sdim  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12238218822Sdim    return;
12239218822Sdim
12240218822Sdim  if (inst.operands[2].isscalar)
12241218822Sdim    do_neon_mac_maybe_scalar ();
12242218822Sdim  else
12243218822Sdim    neon_dyadic_misc (NT_poly, N_I8 | N_I16 | N_I32 | N_F32 | N_P8, 0);
1224489857Sobrien}
1224589857Sobrien
1224689857Sobrienstatic void
12247218822Sdimdo_neon_qdmulh (void)
1224889857Sobrien{
12249218822Sdim  if (inst.operands[2].isscalar)
12250218822Sdim    {
12251218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDS, NS_QQS, NS_NULL);
12252218822Sdim      struct neon_type_el et = neon_check_type (3, rs,
12253218822Sdim        N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
12254218822Sdim      inst.instruction = NEON_ENC_SCALAR (inst.instruction);
12255218822Sdim      neon_mul_mac (et, neon_quad (rs));
12256218822Sdim    }
12257218822Sdim  else
12258218822Sdim    {
12259218822Sdim      enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
12260218822Sdim      struct neon_type_el et = neon_check_type (3, rs,
12261218822Sdim        N_EQK, N_EQK, N_S16 | N_S32 | N_KEY);
12262218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12263218822Sdim      /* The U bit (rounding) comes from bit mask.  */
12264218822Sdim      neon_three_same (neon_quad (rs), 0, et.size);
12265218822Sdim    }
1226689857Sobrien}
1226789857Sobrien
1226889857Sobrienstatic void
12269218822Sdimdo_neon_fcmp_absolute (void)
1227089857Sobrien{
12271218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
12272218822Sdim  neon_check_type (3, rs, N_EQK, N_EQK, N_F32 | N_KEY);
12273218822Sdim  /* Size field comes from bit mask.  */
12274218822Sdim  neon_three_same (neon_quad (rs), 1, -1);
1227589857Sobrien}
1227689857Sobrien
1227789857Sobrienstatic void
12278218822Sdimdo_neon_fcmp_absolute_inv (void)
1227989857Sobrien{
12280218822Sdim  neon_exchange_operands ();
12281218822Sdim  do_neon_fcmp_absolute ();
1228289857Sobrien}
1228389857Sobrien
1228489857Sobrienstatic void
12285218822Sdimdo_neon_step (void)
1228689857Sobrien{
12287218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
12288218822Sdim  neon_check_type (3, rs, N_EQK, N_EQK, N_F32 | N_KEY);
12289218822Sdim  neon_three_same (neon_quad (rs), 0, -1);
1229089857Sobrien}
1229189857Sobrien
1229289857Sobrienstatic void
12293218822Sdimdo_neon_abs_neg (void)
1229489857Sobrien{
12295218822Sdim  enum neon_shape rs;
12296218822Sdim  struct neon_type_el et;
12297218822Sdim
12298218822Sdim  if (try_vfp_nsyn (2, do_vfp_nsyn_abs_neg) == SUCCESS)
12299218822Sdim    return;
12300218822Sdim
12301218822Sdim  if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12302218822Sdim    return;
12303218822Sdim
12304218822Sdim  rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
12305218822Sdim  et = neon_check_type (2, rs, N_EQK, N_S8 | N_S16 | N_S32 | N_F32 | N_KEY);
12306218822Sdim
12307218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12308218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12309218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg);
12310218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12311218822Sdim  inst.instruction |= neon_quad (rs) << 6;
12312218822Sdim  inst.instruction |= (et.type == NT_float) << 10;
12313218822Sdim  inst.instruction |= neon_logbits (et.size) << 18;
12314218822Sdim
12315218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1231689857Sobrien}
1231789857Sobrien
1231889857Sobrienstatic void
12319218822Sdimdo_neon_sli (void)
1232089857Sobrien{
12321218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
12322218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
12323218822Sdim    N_EQK, N_8 | N_16 | N_32 | N_64 | N_KEY);
12324218822Sdim  int imm = inst.operands[2].imm;
12325218822Sdim  constraint (imm < 0 || (unsigned)imm >= et.size,
12326218822Sdim              _("immediate out of range for insert"));
12327218822Sdim  neon_imm_shift (FALSE, 0, neon_quad (rs), et, imm);
1232889857Sobrien}
1232989857Sobrien
1233089857Sobrienstatic void
12331218822Sdimdo_neon_sri (void)
1233289857Sobrien{
12333218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
12334218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
12335218822Sdim    N_EQK, N_8 | N_16 | N_32 | N_64 | N_KEY);
12336218822Sdim  int imm = inst.operands[2].imm;
12337218822Sdim  constraint (imm < 1 || (unsigned)imm > et.size,
12338218822Sdim              _("immediate out of range for insert"));
12339218822Sdim  neon_imm_shift (FALSE, 0, neon_quad (rs), et, et.size - imm);
1234089857Sobrien}
1234189857Sobrien
1234289857Sobrienstatic void
12343218822Sdimdo_neon_qshlu_imm (void)
1234489857Sobrien{
12345218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
12346218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
12347218822Sdim    N_EQK | N_UNS, N_S8 | N_S16 | N_S32 | N_S64 | N_KEY);
12348218822Sdim  int imm = inst.operands[2].imm;
12349218822Sdim  constraint (imm < 0 || (unsigned)imm >= et.size,
12350218822Sdim              _("immediate out of range for shift"));
12351218822Sdim  /* Only encodes the 'U present' variant of the instruction.
12352218822Sdim     In this case, signed types have OP (bit 8) set to 0.
12353218822Sdim     Unsigned types have OP set to 1.  */
12354218822Sdim  inst.instruction |= (et.type == NT_unsigned) << 8;
12355218822Sdim  /* The rest of the bits are the same as other immediate shifts.  */
12356218822Sdim  neon_imm_shift (FALSE, 0, neon_quad (rs), et, imm);
1235789857Sobrien}
1235889857Sobrien
1235989857Sobrienstatic void
12360218822Sdimdo_neon_qmovn (void)
1236189857Sobrien{
12362218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQ,
12363218822Sdim    N_EQK | N_HLF, N_SU_16_64 | N_KEY);
12364218822Sdim  /* Saturating move where operands can be signed or unsigned, and the
12365218822Sdim     destination has the same signedness.  */
12366218822Sdim  inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12367218822Sdim  if (et.type == NT_unsigned)
12368218822Sdim    inst.instruction |= 0xc0;
12369218822Sdim  else
12370218822Sdim    inst.instruction |= 0x80;
12371218822Sdim  neon_two_same (0, 1, et.size / 2);
1237289857Sobrien}
1237389857Sobrien
1237489857Sobrienstatic void
12375218822Sdimdo_neon_qmovun (void)
1237689857Sobrien{
12377218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQ,
12378218822Sdim    N_EQK | N_HLF | N_UNS, N_S16 | N_S32 | N_S64 | N_KEY);
12379218822Sdim  /* Saturating move with unsigned results. Operands must be signed.  */
12380218822Sdim  inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12381218822Sdim  neon_two_same (0, 1, et.size / 2);
1238289857Sobrien}
1238389857Sobrien
1238489857Sobrienstatic void
12385218822Sdimdo_neon_rshift_sat_narrow (void)
1238689857Sobrien{
12387218822Sdim  /* FIXME: Types for narrowing. If operands are signed, results can be signed
12388218822Sdim     or unsigned. If operands are unsigned, results must also be unsigned.  */
12389218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQI,
12390218822Sdim    N_EQK | N_HLF, N_SU_16_64 | N_KEY);
12391218822Sdim  int imm = inst.operands[2].imm;
12392218822Sdim  /* This gets the bounds check, size encoding and immediate bits calculation
12393218822Sdim     right.  */
12394218822Sdim  et.size /= 2;
12395218822Sdim
12396218822Sdim  /* VQ{R}SHRN.I<size> <Dd>, <Qm>, #0 is a synonym for
12397218822Sdim     VQMOVN.I<size> <Dd>, <Qm>.  */
12398218822Sdim  if (imm == 0)
12399218822Sdim    {
12400218822Sdim      inst.operands[2].present = 0;
12401218822Sdim      inst.instruction = N_MNEM_vqmovn;
12402218822Sdim      do_neon_qmovn ();
12403218822Sdim      return;
12404218822Sdim    }
12405218822Sdim
12406218822Sdim  constraint (imm < 1 || (unsigned)imm > et.size,
12407218822Sdim              _("immediate out of range"));
12408218822Sdim  neon_imm_shift (TRUE, et.type == NT_unsigned, 0, et, et.size - imm);
1240989857Sobrien}
1241089857Sobrien
1241189857Sobrienstatic void
12412218822Sdimdo_neon_rshift_sat_narrow_u (void)
1241389857Sobrien{
12414218822Sdim  /* FIXME: Types for narrowing. If operands are signed, results can be signed
12415218822Sdim     or unsigned. If operands are unsigned, results must also be unsigned.  */
12416218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQI,
12417218822Sdim    N_EQK | N_HLF | N_UNS, N_S16 | N_S32 | N_S64 | N_KEY);
12418218822Sdim  int imm = inst.operands[2].imm;
12419218822Sdim  /* This gets the bounds check, size encoding and immediate bits calculation
12420218822Sdim     right.  */
12421218822Sdim  et.size /= 2;
12422218822Sdim
12423218822Sdim  /* VQSHRUN.I<size> <Dd>, <Qm>, #0 is a synonym for
12424218822Sdim     VQMOVUN.I<size> <Dd>, <Qm>.  */
12425218822Sdim  if (imm == 0)
12426218822Sdim    {
12427218822Sdim      inst.operands[2].present = 0;
12428218822Sdim      inst.instruction = N_MNEM_vqmovun;
12429218822Sdim      do_neon_qmovun ();
12430218822Sdim      return;
12431218822Sdim    }
12432218822Sdim
12433218822Sdim  constraint (imm < 1 || (unsigned)imm > et.size,
12434218822Sdim              _("immediate out of range"));
12435218822Sdim  /* FIXME: The manual is kind of unclear about what value U should have in
12436218822Sdim     VQ{R}SHRUN instructions, but U=0, op=0 definitely encodes VRSHR, so it
12437218822Sdim     must be 1.  */
12438218822Sdim  neon_imm_shift (TRUE, 1, 0, et, et.size - imm);
1243989857Sobrien}
1244089857Sobrien
1244189857Sobrienstatic void
12442218822Sdimdo_neon_movn (void)
1244389857Sobrien{
12444218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQ,
12445218822Sdim    N_EQK | N_HLF, N_I16 | N_I32 | N_I64 | N_KEY);
12446218822Sdim  inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12447218822Sdim  neon_two_same (0, 1, et.size / 2);
1244889857Sobrien}
1244989857Sobrien
1245089857Sobrienstatic void
12451218822Sdimdo_neon_rshift_narrow (void)
1245289857Sobrien{
12453218822Sdim  struct neon_type_el et = neon_check_type (2, NS_DQI,
12454218822Sdim    N_EQK | N_HLF, N_I16 | N_I32 | N_I64 | 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  /* If immediate is zero then we are a pseudo-instruction for
12461218822Sdim     VMOVN.I<size> <Dd>, <Qm>  */
12462218822Sdim  if (imm == 0)
12463218822Sdim    {
12464218822Sdim      inst.operands[2].present = 0;
12465218822Sdim      inst.instruction = N_MNEM_vmovn;
12466218822Sdim      do_neon_movn ();
12467218822Sdim      return;
12468218822Sdim    }
12469218822Sdim
12470218822Sdim  constraint (imm < 1 || (unsigned)imm > et.size,
12471218822Sdim              _("immediate out of range for narrowing operation"));
12472218822Sdim  neon_imm_shift (FALSE, 0, 0, et, et.size - imm);
1247389857Sobrien}
1247489857Sobrien
1247589857Sobrienstatic void
12476218822Sdimdo_neon_shll (void)
1247789857Sobrien{
12478218822Sdim  /* FIXME: Type checking when lengthening.  */
12479218822Sdim  struct neon_type_el et = neon_check_type (2, NS_QDI,
12480218822Sdim    N_EQK | N_DBL, N_I8 | N_I16 | N_I32 | N_KEY);
12481218822Sdim  unsigned imm = inst.operands[2].imm;
12482218822Sdim
12483218822Sdim  if (imm == et.size)
12484218822Sdim    {
12485218822Sdim      /* Maximum shift variant.  */
12486218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12487218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12488218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12489218822Sdim      inst.instruction |= LOW4 (inst.operands[1].reg);
12490218822Sdim      inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12491218822Sdim      inst.instruction |= neon_logbits (et.size) << 18;
12492218822Sdim
12493218822Sdim      inst.instruction = neon_dp_fixup (inst.instruction);
12494218822Sdim    }
12495218822Sdim  else
12496218822Sdim    {
12497218822Sdim      /* A more-specific type check for non-max versions.  */
12498218822Sdim      et = neon_check_type (2, NS_QDI,
12499218822Sdim        N_EQK | N_DBL, N_SU_32 | N_KEY);
12500218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
12501218822Sdim      neon_imm_shift (TRUE, et.type == NT_unsigned, 0, et, imm);
12502218822Sdim    }
1250389857Sobrien}
1250489857Sobrien
12505218822Sdim/* Check the various types for the VCVT instruction, and return which version
12506218822Sdim   the current instruction is.  */
12507218822Sdim
12508218822Sdimstatic int
12509218822Sdimneon_cvt_flavour (enum neon_shape rs)
12510218822Sdim{
12511218822Sdim#define CVT_VAR(C,X,Y)							\
12512218822Sdim  et = neon_check_type (2, rs, whole_reg | (X), whole_reg | (Y));	\
12513218822Sdim  if (et.type != NT_invtype)						\
12514218822Sdim    {									\
12515218822Sdim      inst.error = NULL;						\
12516218822Sdim      return (C);							\
12517218822Sdim    }
12518218822Sdim  struct neon_type_el et;
12519218822Sdim  unsigned whole_reg = (rs == NS_FFI || rs == NS_FD || rs == NS_DF
12520218822Sdim                        || rs == NS_FF) ? N_VFP : 0;
12521218822Sdim  /* The instruction versions which take an immediate take one register
12522218822Sdim     argument, which is extended to the width of the full register. Thus the
12523218822Sdim     "source" and "destination" registers must have the same width.  Hack that
12524218822Sdim     here by making the size equal to the key (wider, in this case) operand.  */
12525218822Sdim  unsigned key = (rs == NS_QQI || rs == NS_DDI || rs == NS_FFI) ? N_KEY : 0;
12526218822Sdim
12527218822Sdim  CVT_VAR (0, N_S32, N_F32);
12528218822Sdim  CVT_VAR (1, N_U32, N_F32);
12529218822Sdim  CVT_VAR (2, N_F32, N_S32);
12530218822Sdim  CVT_VAR (3, N_F32, N_U32);
12531218822Sdim
12532218822Sdim  whole_reg = N_VFP;
12533218822Sdim
12534218822Sdim  /* VFP instructions.  */
12535218822Sdim  CVT_VAR (4, N_F32, N_F64);
12536218822Sdim  CVT_VAR (5, N_F64, N_F32);
12537218822Sdim  CVT_VAR (6, N_S32, N_F64 | key);
12538218822Sdim  CVT_VAR (7, N_U32, N_F64 | key);
12539218822Sdim  CVT_VAR (8, N_F64 | key, N_S32);
12540218822Sdim  CVT_VAR (9, N_F64 | key, N_U32);
12541218822Sdim  /* VFP instructions with bitshift.  */
12542218822Sdim  CVT_VAR (10, N_F32 | key, N_S16);
12543218822Sdim  CVT_VAR (11, N_F32 | key, N_U16);
12544218822Sdim  CVT_VAR (12, N_F64 | key, N_S16);
12545218822Sdim  CVT_VAR (13, N_F64 | key, N_U16);
12546218822Sdim  CVT_VAR (14, N_S16, N_F32 | key);
12547218822Sdim  CVT_VAR (15, N_U16, N_F32 | key);
12548218822Sdim  CVT_VAR (16, N_S16, N_F64 | key);
12549218822Sdim  CVT_VAR (17, N_U16, N_F64 | key);
12550218822Sdim
12551218822Sdim  return -1;
12552218822Sdim#undef CVT_VAR
12553218822Sdim}
12554218822Sdim
12555218822Sdim/* Neon-syntax VFP conversions.  */
12556218822Sdim
1255789857Sobrienstatic void
12558218822Sdimdo_vfp_nsyn_cvt (enum neon_shape rs, int flavour)
1255989857Sobrien{
12560218822Sdim  const char *opname = 0;
12561218822Sdim
12562218822Sdim  if (rs == NS_DDI || rs == NS_QQI || rs == NS_FFI)
12563218822Sdim    {
12564218822Sdim      /* Conversions with immediate bitshift.  */
12565218822Sdim      const char *enc[] =
12566218822Sdim        {
12567218822Sdim          "ftosls",
12568218822Sdim          "ftouls",
12569218822Sdim          "fsltos",
12570218822Sdim          "fultos",
12571218822Sdim          NULL,
12572218822Sdim          NULL,
12573218822Sdim          "ftosld",
12574218822Sdim          "ftould",
12575218822Sdim          "fsltod",
12576218822Sdim          "fultod",
12577218822Sdim          "fshtos",
12578218822Sdim          "fuhtos",
12579218822Sdim          "fshtod",
12580218822Sdim          "fuhtod",
12581218822Sdim          "ftoshs",
12582218822Sdim          "ftouhs",
12583218822Sdim          "ftoshd",
12584218822Sdim          "ftouhd"
12585218822Sdim        };
12586218822Sdim
12587218822Sdim      if (flavour >= 0 && flavour < (int) ARRAY_SIZE (enc))
12588218822Sdim        {
12589218822Sdim          opname = enc[flavour];
12590218822Sdim          constraint (inst.operands[0].reg != inst.operands[1].reg,
12591218822Sdim                      _("operands 0 and 1 must be the same register"));
12592218822Sdim          inst.operands[1] = inst.operands[2];
12593218822Sdim          memset (&inst.operands[2], '\0', sizeof (inst.operands[2]));
12594218822Sdim        }
12595218822Sdim    }
12596218822Sdim  else
12597218822Sdim    {
12598218822Sdim      /* Conversions without bitshift.  */
12599218822Sdim      const char *enc[] =
12600218822Sdim        {
12601218822Sdim          "ftosis",
12602218822Sdim          "ftouis",
12603218822Sdim          "fsitos",
12604218822Sdim          "fuitos",
12605218822Sdim          "fcvtsd",
12606218822Sdim          "fcvtds",
12607218822Sdim          "ftosid",
12608218822Sdim          "ftouid",
12609218822Sdim          "fsitod",
12610218822Sdim          "fuitod"
12611218822Sdim        };
12612218822Sdim
12613218822Sdim      if (flavour >= 0 && flavour < (int) ARRAY_SIZE (enc))
12614218822Sdim        opname = enc[flavour];
12615218822Sdim    }
12616218822Sdim
12617218822Sdim  if (opname)
12618218822Sdim    do_vfp_nsyn_opcode (opname);
1261989857Sobrien}
1262089857Sobrien
1262189857Sobrienstatic void
12622218822Sdimdo_vfp_nsyn_cvtz (void)
1262389857Sobrien{
12624218822Sdim  enum neon_shape rs = neon_select_shape (NS_FF, NS_FD, NS_NULL);
12625218822Sdim  int flavour = neon_cvt_flavour (rs);
12626218822Sdim  const char *enc[] =
12627218822Sdim    {
12628218822Sdim      "ftosizs",
12629218822Sdim      "ftouizs",
12630218822Sdim      NULL,
12631218822Sdim      NULL,
12632218822Sdim      NULL,
12633218822Sdim      NULL,
12634218822Sdim      "ftosizd",
12635218822Sdim      "ftouizd"
12636218822Sdim    };
12637218822Sdim
12638218822Sdim  if (flavour >= 0 && flavour < (int) ARRAY_SIZE (enc) && enc[flavour])
12639218822Sdim    do_vfp_nsyn_opcode (enc[flavour]);
1264089857Sobrien}
1264189857Sobrien
1264289857Sobrienstatic void
12643218822Sdimdo_neon_cvt (void)
1264489857Sobrien{
12645218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_FFI, NS_DD, NS_QQ,
12646218822Sdim    NS_FD, NS_DF, NS_FF, NS_NULL);
12647218822Sdim  int flavour = neon_cvt_flavour (rs);
12648218822Sdim
12649218822Sdim  /* VFP rather than Neon conversions.  */
12650218822Sdim  if (flavour >= 4)
12651218822Sdim    {
12652218822Sdim      do_vfp_nsyn_cvt (rs, flavour);
12653218822Sdim      return;
12654218822Sdim    }
12655218822Sdim
12656218822Sdim  switch (rs)
12657218822Sdim    {
12658218822Sdim    case NS_DDI:
12659218822Sdim    case NS_QQI:
12660218822Sdim      {
12661218822Sdim        if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12662218822Sdim          return;
12663218822Sdim
12664218822Sdim        /* Fixed-point conversion with #0 immediate is encoded as an
12665218822Sdim           integer conversion.  */
12666218822Sdim        if (inst.operands[2].present && inst.operands[2].imm == 0)
12667218822Sdim          goto int_encode;
12668218822Sdim        unsigned immbits = 32 - inst.operands[2].imm;
12669218822Sdim        unsigned enctab[] = { 0x0000100, 0x1000100, 0x0, 0x1000000 };
12670218822Sdim        inst.instruction = NEON_ENC_IMMED (inst.instruction);
12671218822Sdim        if (flavour != -1)
12672218822Sdim          inst.instruction |= enctab[flavour];
12673218822Sdim        inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12674218822Sdim        inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12675218822Sdim        inst.instruction |= LOW4 (inst.operands[1].reg);
12676218822Sdim        inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12677218822Sdim        inst.instruction |= neon_quad (rs) << 6;
12678218822Sdim        inst.instruction |= 1 << 21;
12679218822Sdim        inst.instruction |= immbits << 16;
12680218822Sdim
12681218822Sdim        inst.instruction = neon_dp_fixup (inst.instruction);
12682218822Sdim      }
12683218822Sdim      break;
12684218822Sdim
12685218822Sdim    case NS_DD:
12686218822Sdim    case NS_QQ:
12687218822Sdim    int_encode:
12688218822Sdim      {
12689218822Sdim        unsigned enctab[] = { 0x100, 0x180, 0x0, 0x080 };
12690218822Sdim
12691218822Sdim        inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12692218822Sdim
12693218822Sdim        if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
12694218822Sdim          return;
12695218822Sdim
12696218822Sdim        if (flavour != -1)
12697218822Sdim          inst.instruction |= enctab[flavour];
12698218822Sdim
12699218822Sdim        inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12700218822Sdim        inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12701218822Sdim        inst.instruction |= LOW4 (inst.operands[1].reg);
12702218822Sdim        inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12703218822Sdim        inst.instruction |= neon_quad (rs) << 6;
12704218822Sdim        inst.instruction |= 2 << 18;
12705218822Sdim
12706218822Sdim        inst.instruction = neon_dp_fixup (inst.instruction);
12707218822Sdim      }
12708218822Sdim    break;
12709218822Sdim
12710218822Sdim    default:
12711218822Sdim      /* Some VFP conversions go here (s32 <-> f32, u32 <-> f32).  */
12712218822Sdim      do_vfp_nsyn_cvt (rs, flavour);
12713218822Sdim    }
1271489857Sobrien}
1271589857Sobrien
1271689857Sobrienstatic void
12717218822Sdimneon_move_immediate (void)
1271889857Sobrien{
12719218822Sdim  enum neon_shape rs = neon_select_shape (NS_DI, NS_QI, NS_NULL);
12720218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
12721218822Sdim    N_I8 | N_I16 | N_I32 | N_I64 | N_F32 | N_KEY, N_EQK);
12722218822Sdim  unsigned immlo, immhi = 0, immbits;
12723218822Sdim  int op, cmode, float_p;
12724218822Sdim
12725218822Sdim  constraint (et.type == NT_invtype,
12726218822Sdim              _("operand size must be specified for immediate VMOV"));
12727218822Sdim
12728218822Sdim  /* We start out as an MVN instruction if OP = 1, MOV otherwise.  */
12729218822Sdim  op = (inst.instruction & (1 << 5)) != 0;
12730218822Sdim
12731218822Sdim  immlo = inst.operands[1].imm;
12732218822Sdim  if (inst.operands[1].regisimm)
12733218822Sdim    immhi = inst.operands[1].reg;
12734218822Sdim
12735218822Sdim  constraint (et.size < 32 && (immlo & ~((1 << et.size) - 1)) != 0,
12736218822Sdim              _("immediate has bits set outside the operand size"));
12737218822Sdim
12738218822Sdim  float_p = inst.operands[1].immisfloat;
12739218822Sdim
12740218822Sdim  if ((cmode = neon_cmode_for_move_imm (immlo, immhi, float_p, &immbits, &op,
12741218822Sdim                                        et.size, et.type)) == FAIL)
12742218822Sdim    {
12743218822Sdim      /* Invert relevant bits only.  */
12744218822Sdim      neon_invert_size (&immlo, &immhi, et.size);
12745218822Sdim      /* Flip from VMOV/VMVN to VMVN/VMOV. Some immediate types are unavailable
12746218822Sdim         with one or the other; those cases are caught by
12747218822Sdim         neon_cmode_for_move_imm.  */
12748218822Sdim      op = !op;
12749218822Sdim      if ((cmode = neon_cmode_for_move_imm (immlo, immhi, float_p, &immbits,
12750218822Sdim					    &op, et.size, et.type)) == FAIL)
12751218822Sdim        {
12752218822Sdim          first_error (_("immediate out of range"));
12753218822Sdim          return;
12754218822Sdim        }
12755218822Sdim    }
12756218822Sdim
12757218822Sdim  inst.instruction &= ~(1 << 5);
12758218822Sdim  inst.instruction |= op << 5;
12759218822Sdim
12760218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12761218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12762218822Sdim  inst.instruction |= neon_quad (rs) << 6;
12763218822Sdim  inst.instruction |= cmode << 8;
12764218822Sdim
12765218822Sdim  neon_write_immbits (immbits);
1276689857Sobrien}
1276789857Sobrien
1276889857Sobrienstatic void
12769218822Sdimdo_neon_mvn (void)
1277089857Sobrien{
12771218822Sdim  if (inst.operands[1].isreg)
12772218822Sdim    {
12773218822Sdim      enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
12774218822Sdim
12775218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12776218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12777218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12778218822Sdim      inst.instruction |= LOW4 (inst.operands[1].reg);
12779218822Sdim      inst.instruction |= HI1 (inst.operands[1].reg) << 5;
12780218822Sdim      inst.instruction |= neon_quad (rs) << 6;
12781218822Sdim    }
12782218822Sdim  else
12783218822Sdim    {
12784218822Sdim      inst.instruction = NEON_ENC_IMMED (inst.instruction);
12785218822Sdim      neon_move_immediate ();
12786218822Sdim    }
12787218822Sdim
12788218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1278989857Sobrien}
1279089857Sobrien
12791218822Sdim/* Encode instructions of form:
12792218822Sdim
12793218822Sdim  |28/24|23|22|21 20|19 16|15 12|11    8|7|6|5|4|3  0|
12794218822Sdim  |  U  |x |D |size | Rn  | Rd  |x x x x|N|x|M|x| Rm |
12795218822Sdim
12796218822Sdim*/
12797218822Sdim
1279889857Sobrienstatic void
12799218822Sdimneon_mixed_length (struct neon_type_el et, unsigned size)
1280089857Sobrien{
12801218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12802218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12803218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
12804218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
12805218822Sdim  inst.instruction |= LOW4 (inst.operands[2].reg);
12806218822Sdim  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
12807218822Sdim  inst.instruction |= (et.type == NT_unsigned) << 24;
12808218822Sdim  inst.instruction |= neon_logbits (size) << 20;
12809218822Sdim
12810218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1281189857Sobrien}
1281289857Sobrien
1281389857Sobrienstatic void
12814218822Sdimdo_neon_dyadic_long (void)
1281589857Sobrien{
12816218822Sdim  /* FIXME: Type checking for lengthening op.  */
12817218822Sdim  struct neon_type_el et = neon_check_type (3, NS_QDD,
12818218822Sdim    N_EQK | N_DBL, N_EQK, N_SU_32 | N_KEY);
12819218822Sdim  neon_mixed_length (et, et.size);
1282089857Sobrien}
1282189857Sobrien
1282289857Sobrienstatic void
12823218822Sdimdo_neon_abal (void)
1282489857Sobrien{
12825218822Sdim  struct neon_type_el et = neon_check_type (3, NS_QDD,
12826218822Sdim    N_EQK | N_INT | N_DBL, N_EQK, N_SU_32 | N_KEY);
12827218822Sdim  neon_mixed_length (et, et.size);
1282889857Sobrien}
1282989857Sobrien
1283089857Sobrienstatic void
12831218822Sdimneon_mac_reg_scalar_long (unsigned regtypes, unsigned scalartypes)
1283289857Sobrien{
12833218822Sdim  if (inst.operands[2].isscalar)
12834218822Sdim    {
12835218822Sdim      struct neon_type_el et = neon_check_type (3, NS_QDS,
12836218822Sdim        N_EQK | N_DBL, N_EQK, regtypes | N_KEY);
12837218822Sdim      inst.instruction = NEON_ENC_SCALAR (inst.instruction);
12838218822Sdim      neon_mul_mac (et, et.type == NT_unsigned);
12839218822Sdim    }
12840218822Sdim  else
12841218822Sdim    {
12842218822Sdim      struct neon_type_el et = neon_check_type (3, NS_QDD,
12843218822Sdim        N_EQK | N_DBL, N_EQK, scalartypes | N_KEY);
12844218822Sdim      inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12845218822Sdim      neon_mixed_length (et, et.size);
12846218822Sdim    }
1284789857Sobrien}
1284889857Sobrien
1284989857Sobrienstatic void
12850218822Sdimdo_neon_mac_maybe_scalar_long (void)
1285189857Sobrien{
12852218822Sdim  neon_mac_reg_scalar_long (N_S16 | N_S32 | N_U16 | N_U32, N_SU_32);
1285389857Sobrien}
1285489857Sobrien
1285589857Sobrienstatic void
12856218822Sdimdo_neon_dyadic_wide (void)
1285789857Sobrien{
12858218822Sdim  struct neon_type_el et = neon_check_type (3, NS_QQD,
12859218822Sdim    N_EQK | N_DBL, N_EQK | N_DBL, N_SU_32 | N_KEY);
12860218822Sdim  neon_mixed_length (et, et.size);
1286189857Sobrien}
1286289857Sobrien
1286389857Sobrienstatic void
12864218822Sdimdo_neon_dyadic_narrow (void)
1286589857Sobrien{
12866218822Sdim  struct neon_type_el et = neon_check_type (3, NS_QDD,
12867218822Sdim    N_EQK | N_DBL, N_EQK, N_I16 | N_I32 | N_I64 | N_KEY);
12868218822Sdim  /* Operand sign is unimportant, and the U bit is part of the opcode,
12869218822Sdim     so force the operand type to integer.  */
12870218822Sdim  et.type = NT_integer;
12871218822Sdim  neon_mixed_length (et, et.size / 2);
1287289857Sobrien}
1287389857Sobrien
1287489857Sobrienstatic void
12875218822Sdimdo_neon_mul_sat_scalar_long (void)
1287689857Sobrien{
12877218822Sdim  neon_mac_reg_scalar_long (N_S16 | N_S32, N_S16 | N_S32);
1287889857Sobrien}
1287989857Sobrien
1288089857Sobrienstatic void
12881218822Sdimdo_neon_vmull (void)
1288289857Sobrien{
12883218822Sdim  if (inst.operands[2].isscalar)
12884218822Sdim    do_neon_mac_maybe_scalar_long ();
12885218822Sdim  else
12886218822Sdim    {
12887218822Sdim      struct neon_type_el et = neon_check_type (3, NS_QDD,
12888218822Sdim        N_EQK | N_DBL, N_EQK, N_SU_32 | N_P8 | N_KEY);
12889218822Sdim      if (et.type == NT_poly)
12890218822Sdim        inst.instruction = NEON_ENC_POLY (inst.instruction);
12891218822Sdim      else
12892218822Sdim        inst.instruction = NEON_ENC_INTEGER (inst.instruction);
12893218822Sdim      /* For polynomial encoding, size field must be 0b00 and the U bit must be
12894218822Sdim         zero. Should be OK as-is.  */
12895218822Sdim      neon_mixed_length (et, et.size);
12896218822Sdim    }
1289789857Sobrien}
1289889857Sobrien
1289989857Sobrienstatic void
12900218822Sdimdo_neon_ext (void)
1290189857Sobrien{
12902218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDDI, NS_QQQI, NS_NULL);
12903218822Sdim  struct neon_type_el et = neon_check_type (3, rs,
12904218822Sdim    N_EQK, N_EQK, N_8 | N_16 | N_32 | N_64 | N_KEY);
12905218822Sdim  unsigned imm = (inst.operands[3].imm * et.size) / 8;
12906218822Sdim  constraint (imm >= (neon_quad (rs) ? 16 : 8), _("shift out of range"));
12907218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12908218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12909218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
12910218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
12911218822Sdim  inst.instruction |= LOW4 (inst.operands[2].reg);
12912218822Sdim  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
12913218822Sdim  inst.instruction |= neon_quad (rs) << 6;
12914218822Sdim  inst.instruction |= imm << 8;
12915218822Sdim
12916218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
1291789857Sobrien}
1291889857Sobrien
1291989857Sobrienstatic void
12920218822Sdimdo_neon_rev (void)
1292189857Sobrien{
12922218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
12923218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
12924218822Sdim    N_EQK, N_8 | N_16 | N_32 | N_KEY);
12925218822Sdim  unsigned op = (inst.instruction >> 7) & 3;
12926218822Sdim  /* N (width of reversed regions) is encoded as part of the bitmask. We
12927218822Sdim     extract it here to check the elements to be reversed are smaller.
12928218822Sdim     Otherwise we'd get a reserved instruction.  */
12929218822Sdim  unsigned elsize = (op == 2) ? 16 : (op == 1) ? 32 : (op == 0) ? 64 : 0;
12930218822Sdim  assert (elsize != 0);
12931218822Sdim  constraint (et.size >= elsize,
12932218822Sdim              _("elements must be smaller than reversal region"));
12933218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1293489857Sobrien}
1293589857Sobrien
1293689857Sobrienstatic void
12937218822Sdimdo_neon_dup (void)
1293889857Sobrien{
12939218822Sdim  if (inst.operands[1].isscalar)
12940218822Sdim    {
12941218822Sdim      enum neon_shape rs = neon_select_shape (NS_DS, NS_QS, NS_NULL);
12942218822Sdim      struct neon_type_el et = neon_check_type (2, rs,
12943218822Sdim        N_EQK, N_8 | N_16 | N_32 | N_KEY);
12944218822Sdim      unsigned sizebits = et.size >> 3;
12945218822Sdim      unsigned dm = NEON_SCALAR_REG (inst.operands[1].reg);
12946218822Sdim      int logsize = neon_logbits (et.size);
12947218822Sdim      unsigned x = NEON_SCALAR_INDEX (inst.operands[1].reg) << logsize;
12948218822Sdim
12949218822Sdim      if (vfp_or_neon_is_neon (NEON_CHECK_CC) == FAIL)
12950218822Sdim        return;
12951218822Sdim
12952218822Sdim      inst.instruction = NEON_ENC_SCALAR (inst.instruction);
12953218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
12954218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 22;
12955218822Sdim      inst.instruction |= LOW4 (dm);
12956218822Sdim      inst.instruction |= HI1 (dm) << 5;
12957218822Sdim      inst.instruction |= neon_quad (rs) << 6;
12958218822Sdim      inst.instruction |= x << 17;
12959218822Sdim      inst.instruction |= sizebits << 16;
12960218822Sdim
12961218822Sdim      inst.instruction = neon_dp_fixup (inst.instruction);
12962218822Sdim    }
12963218822Sdim  else
12964218822Sdim    {
12965218822Sdim      enum neon_shape rs = neon_select_shape (NS_DR, NS_QR, NS_NULL);
12966218822Sdim      struct neon_type_el et = neon_check_type (2, rs,
12967218822Sdim        N_8 | N_16 | N_32 | N_KEY, N_EQK);
12968218822Sdim      /* Duplicate ARM register to lanes of vector.  */
12969218822Sdim      inst.instruction = NEON_ENC_ARMREG (inst.instruction);
12970218822Sdim      switch (et.size)
12971218822Sdim        {
12972218822Sdim        case 8:  inst.instruction |= 0x400000; break;
12973218822Sdim        case 16: inst.instruction |= 0x000020; break;
12974218822Sdim        case 32: inst.instruction |= 0x000000; break;
12975218822Sdim        default: break;
12976218822Sdim        }
12977218822Sdim      inst.instruction |= LOW4 (inst.operands[1].reg) << 12;
12978218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg) << 16;
12979218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 7;
12980218822Sdim      inst.instruction |= neon_quad (rs) << 21;
12981218822Sdim      /* The encoding for this instruction is identical for the ARM and Thumb
12982218822Sdim         variants, except for the condition field.  */
12983218822Sdim      do_vfp_cond_or_thumb ();
12984218822Sdim    }
1298589857Sobrien}
1298689857Sobrien
12987218822Sdim/* VMOV has particularly many variations. It can be one of:
12988218822Sdim     0. VMOV<c><q> <Qd>, <Qm>
12989218822Sdim     1. VMOV<c><q> <Dd>, <Dm>
12990218822Sdim   (Register operations, which are VORR with Rm = Rn.)
12991218822Sdim     2. VMOV<c><q>.<dt> <Qd>, #<imm>
12992218822Sdim     3. VMOV<c><q>.<dt> <Dd>, #<imm>
12993218822Sdim   (Immediate loads.)
12994218822Sdim     4. VMOV<c><q>.<size> <Dn[x]>, <Rd>
12995218822Sdim   (ARM register to scalar.)
12996218822Sdim     5. VMOV<c><q> <Dm>, <Rd>, <Rn>
12997218822Sdim   (Two ARM registers to vector.)
12998218822Sdim     6. VMOV<c><q>.<dt> <Rd>, <Dn[x]>
12999218822Sdim   (Scalar to ARM register.)
13000218822Sdim     7. VMOV<c><q> <Rd>, <Rn>, <Dm>
13001218822Sdim   (Vector to two ARM registers.)
13002218822Sdim     8. VMOV.F32 <Sd>, <Sm>
13003218822Sdim     9. VMOV.F64 <Dd>, <Dm>
13004218822Sdim   (VFP register moves.)
13005218822Sdim    10. VMOV.F32 <Sd>, #imm
13006218822Sdim    11. VMOV.F64 <Dd>, #imm
13007218822Sdim   (VFP float immediate load.)
13008218822Sdim    12. VMOV <Rd>, <Sm>
13009218822Sdim   (VFP single to ARM reg.)
13010218822Sdim    13. VMOV <Sd>, <Rm>
13011218822Sdim   (ARM reg to VFP single.)
13012218822Sdim    14. VMOV <Rd>, <Re>, <Sn>, <Sm>
13013218822Sdim   (Two ARM regs to two VFP singles.)
13014218822Sdim    15. VMOV <Sd>, <Se>, <Rn>, <Rm>
13015218822Sdim   (Two VFP singles to two ARM regs.)
13016218822Sdim
13017218822Sdim   These cases can be disambiguated using neon_select_shape, except cases 1/9
13018218822Sdim   and 3/11 which depend on the operand type too.
13019218822Sdim
13020218822Sdim   All the encoded bits are hardcoded by this function.
13021218822Sdim
13022218822Sdim   Cases 4, 6 may be used with VFPv1 and above (only 32-bit transfers!).
13023218822Sdim   Cases 5, 7 may be used with VFPv2 and above.
13024218822Sdim
13025218822Sdim   FIXME: Some of the checking may be a bit sloppy (in a couple of cases you
13026218822Sdim   can specify a type where it doesn't make sense to, and is ignored).
13027218822Sdim*/
13028218822Sdim
1302989857Sobrienstatic void
13030218822Sdimdo_neon_mov (void)
1303189857Sobrien{
13032218822Sdim  enum neon_shape rs = neon_select_shape (NS_RRFF, NS_FFRR, NS_DRR, NS_RRD,
13033218822Sdim    NS_QQ, NS_DD, NS_QI, NS_DI, NS_SR, NS_RS, NS_FF, NS_FI, NS_RF, NS_FR,
13034218822Sdim    NS_NULL);
13035218822Sdim  struct neon_type_el et;
13036218822Sdim  const char *ldconst = 0;
1303789857Sobrien
13038218822Sdim  switch (rs)
1303989857Sobrien    {
13040218822Sdim    case NS_DD:  /* case 1/9.  */
13041218822Sdim      et = neon_check_type (2, rs, N_EQK, N_F64 | N_KEY);
13042218822Sdim      /* It is not an error here if no type is given.  */
13043218822Sdim      inst.error = NULL;
13044218822Sdim      if (et.type == NT_float && et.size == 64)
13045218822Sdim        {
13046218822Sdim          do_vfp_nsyn_opcode ("fcpyd");
13047218822Sdim          break;
13048218822Sdim        }
13049218822Sdim      /* fall through.  */
1305089857Sobrien
13051218822Sdim    case NS_QQ:  /* case 0/1.  */
13052218822Sdim      {
13053218822Sdim        if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
13054218822Sdim          return;
13055218822Sdim        /* The architecture manual I have doesn't explicitly state which
13056218822Sdim           value the U bit should have for register->register moves, but
13057218822Sdim           the equivalent VORR instruction has U = 0, so do that.  */
13058218822Sdim        inst.instruction = 0x0200110;
13059218822Sdim        inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
13060218822Sdim        inst.instruction |= HI1 (inst.operands[0].reg) << 22;
13061218822Sdim        inst.instruction |= LOW4 (inst.operands[1].reg);
13062218822Sdim        inst.instruction |= HI1 (inst.operands[1].reg) << 5;
13063218822Sdim        inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
13064218822Sdim        inst.instruction |= HI1 (inst.operands[1].reg) << 7;
13065218822Sdim        inst.instruction |= neon_quad (rs) << 6;
13066218822Sdim
13067218822Sdim        inst.instruction = neon_dp_fixup (inst.instruction);
13068218822Sdim      }
13069218822Sdim      break;
13070218822Sdim
13071218822Sdim    case NS_DI:  /* case 3/11.  */
13072218822Sdim      et = neon_check_type (2, rs, N_EQK, N_F64 | N_KEY);
13073218822Sdim      inst.error = NULL;
13074218822Sdim      if (et.type == NT_float && et.size == 64)
13075218822Sdim        {
13076218822Sdim          /* case 11 (fconstd).  */
13077218822Sdim          ldconst = "fconstd";
13078218822Sdim          goto encode_fconstd;
13079218822Sdim        }
13080218822Sdim      /* fall through.  */
13081218822Sdim
13082218822Sdim    case NS_QI:  /* case 2/3.  */
13083218822Sdim      if (vfp_or_neon_is_neon (NEON_CHECK_CC | NEON_CHECK_ARCH) == FAIL)
13084218822Sdim        return;
13085218822Sdim      inst.instruction = 0x0800010;
13086218822Sdim      neon_move_immediate ();
13087218822Sdim      inst.instruction = neon_dp_fixup (inst.instruction);
13088218822Sdim      break;
13089218822Sdim
13090218822Sdim    case NS_SR:  /* case 4.  */
13091218822Sdim      {
13092218822Sdim        unsigned bcdebits = 0;
13093218822Sdim        struct neon_type_el et = neon_check_type (2, NS_NULL,
13094218822Sdim          N_8 | N_16 | N_32 | N_KEY, N_EQK);
13095218822Sdim        int logsize = neon_logbits (et.size);
13096218822Sdim        unsigned dn = NEON_SCALAR_REG (inst.operands[0].reg);
13097218822Sdim        unsigned x = NEON_SCALAR_INDEX (inst.operands[0].reg);
13098218822Sdim
13099218822Sdim        constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v1),
13100218822Sdim                    _(BAD_FPU));
13101218822Sdim        constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1)
13102218822Sdim                    && et.size != 32, _(BAD_FPU));
13103218822Sdim        constraint (et.type == NT_invtype, _("bad type for scalar"));
13104218822Sdim        constraint (x >= 64 / et.size, _("scalar index out of range"));
13105218822Sdim
13106218822Sdim        switch (et.size)
13107218822Sdim          {
13108218822Sdim          case 8:  bcdebits = 0x8; break;
13109218822Sdim          case 16: bcdebits = 0x1; break;
13110218822Sdim          case 32: bcdebits = 0x0; break;
13111218822Sdim          default: ;
13112218822Sdim          }
13113218822Sdim
13114218822Sdim        bcdebits |= x << logsize;
13115218822Sdim
13116218822Sdim        inst.instruction = 0xe000b10;
13117218822Sdim        do_vfp_cond_or_thumb ();
13118218822Sdim        inst.instruction |= LOW4 (dn) << 16;
13119218822Sdim        inst.instruction |= HI1 (dn) << 7;
13120218822Sdim        inst.instruction |= inst.operands[1].reg << 12;
13121218822Sdim        inst.instruction |= (bcdebits & 3) << 5;
13122218822Sdim        inst.instruction |= (bcdebits >> 2) << 21;
13123218822Sdim      }
13124218822Sdim      break;
13125218822Sdim
13126218822Sdim    case NS_DRR:  /* case 5 (fmdrr).  */
13127218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v2),
13128218822Sdim                  _(BAD_FPU));
13129218822Sdim
13130218822Sdim      inst.instruction = 0xc400b10;
13131218822Sdim      do_vfp_cond_or_thumb ();
13132218822Sdim      inst.instruction |= LOW4 (inst.operands[0].reg);
13133218822Sdim      inst.instruction |= HI1 (inst.operands[0].reg) << 5;
13134218822Sdim      inst.instruction |= inst.operands[1].reg << 12;
13135218822Sdim      inst.instruction |= inst.operands[2].reg << 16;
13136218822Sdim      break;
13137218822Sdim
13138218822Sdim    case NS_RS:  /* case 6.  */
13139218822Sdim      {
13140218822Sdim        struct neon_type_el et = neon_check_type (2, NS_NULL,
13141218822Sdim          N_EQK, N_S8 | N_S16 | N_U8 | N_U16 | N_32 | N_KEY);
13142218822Sdim        unsigned logsize = neon_logbits (et.size);
13143218822Sdim        unsigned dn = NEON_SCALAR_REG (inst.operands[1].reg);
13144218822Sdim        unsigned x = NEON_SCALAR_INDEX (inst.operands[1].reg);
13145218822Sdim        unsigned abcdebits = 0;
13146218822Sdim
13147218822Sdim        constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v1),
13148218822Sdim                    _(BAD_FPU));
13149218822Sdim        constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1)
13150218822Sdim                    && et.size != 32, _(BAD_FPU));
13151218822Sdim        constraint (et.type == NT_invtype, _("bad type for scalar"));
13152218822Sdim        constraint (x >= 64 / et.size, _("scalar index out of range"));
13153218822Sdim
13154218822Sdim        switch (et.size)
13155218822Sdim          {
13156218822Sdim          case 8:  abcdebits = (et.type == NT_signed) ? 0x08 : 0x18; break;
13157218822Sdim          case 16: abcdebits = (et.type == NT_signed) ? 0x01 : 0x11; break;
13158218822Sdim          case 32: abcdebits = 0x00; break;
13159218822Sdim          default: ;
13160218822Sdim          }
13161218822Sdim
13162218822Sdim        abcdebits |= x << logsize;
13163218822Sdim        inst.instruction = 0xe100b10;
13164218822Sdim        do_vfp_cond_or_thumb ();
13165218822Sdim        inst.instruction |= LOW4 (dn) << 16;
13166218822Sdim        inst.instruction |= HI1 (dn) << 7;
13167218822Sdim        inst.instruction |= inst.operands[0].reg << 12;
13168218822Sdim        inst.instruction |= (abcdebits & 3) << 5;
13169218822Sdim        inst.instruction |= (abcdebits >> 2) << 21;
13170218822Sdim      }
13171218822Sdim      break;
13172218822Sdim
13173218822Sdim    case NS_RRD:  /* case 7 (fmrrd).  */
13174218822Sdim      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v2),
13175218822Sdim                  _(BAD_FPU));
13176218822Sdim
13177218822Sdim      inst.instruction = 0xc500b10;
13178218822Sdim      do_vfp_cond_or_thumb ();
13179218822Sdim      inst.instruction |= inst.operands[0].reg << 12;
13180218822Sdim      inst.instruction |= inst.operands[1].reg << 16;
13181218822Sdim      inst.instruction |= LOW4 (inst.operands[2].reg);
13182218822Sdim      inst.instruction |= HI1 (inst.operands[2].reg) << 5;
13183218822Sdim      break;
13184218822Sdim
13185218822Sdim    case NS_FF:  /* case 8 (fcpys).  */
13186218822Sdim      do_vfp_nsyn_opcode ("fcpys");
13187218822Sdim      break;
13188218822Sdim
13189218822Sdim    case NS_FI:  /* case 10 (fconsts).  */
13190218822Sdim      ldconst = "fconsts";
13191218822Sdim      encode_fconstd:
13192218822Sdim      if (is_quarter_float (inst.operands[1].imm))
13193218822Sdim        {
13194218822Sdim          inst.operands[1].imm = neon_qfloat_bits (inst.operands[1].imm);
13195218822Sdim          do_vfp_nsyn_opcode (ldconst);
13196218822Sdim        }
13197218822Sdim      else
13198218822Sdim        first_error (_("immediate out of range"));
13199218822Sdim      break;
13200218822Sdim
13201218822Sdim    case NS_RF:  /* case 12 (fmrs).  */
13202218822Sdim      do_vfp_nsyn_opcode ("fmrs");
13203218822Sdim      break;
13204218822Sdim
13205218822Sdim    case NS_FR:  /* case 13 (fmsr).  */
13206218822Sdim      do_vfp_nsyn_opcode ("fmsr");
13207218822Sdim      break;
13208218822Sdim
13209218822Sdim    /* The encoders for the fmrrs and fmsrr instructions expect three operands
13210218822Sdim       (one of which is a list), but we have parsed four.  Do some fiddling to
13211218822Sdim       make the operands what do_vfp_reg2_from_sp2 and do_vfp_sp2_from_reg2
13212218822Sdim       expect.  */
13213218822Sdim    case NS_RRFF:  /* case 14 (fmrrs).  */
13214218822Sdim      constraint (inst.operands[3].reg != inst.operands[2].reg + 1,
13215218822Sdim                  _("VFP registers must be adjacent"));
13216218822Sdim      inst.operands[2].imm = 2;
13217218822Sdim      memset (&inst.operands[3], '\0', sizeof (inst.operands[3]));
13218218822Sdim      do_vfp_nsyn_opcode ("fmrrs");
13219218822Sdim      break;
13220218822Sdim
13221218822Sdim    case NS_FFRR:  /* case 15 (fmsrr).  */
13222218822Sdim      constraint (inst.operands[1].reg != inst.operands[0].reg + 1,
13223218822Sdim                  _("VFP registers must be adjacent"));
13224218822Sdim      inst.operands[1] = inst.operands[2];
13225218822Sdim      inst.operands[2] = inst.operands[3];
13226218822Sdim      inst.operands[0].imm = 2;
13227218822Sdim      memset (&inst.operands[3], '\0', sizeof (inst.operands[3]));
13228218822Sdim      do_vfp_nsyn_opcode ("fmsrr");
13229218822Sdim      break;
13230218822Sdim
13231218822Sdim    default:
13232218822Sdim      abort ();
13233218822Sdim    }
13234218822Sdim}
13235218822Sdim
13236218822Sdimstatic void
13237218822Sdimdo_neon_rshift_round_imm (void)
13238218822Sdim{
13239218822Sdim  enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
13240218822Sdim  struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_SU_ALL | N_KEY);
13241218822Sdim  int imm = inst.operands[2].imm;
13242218822Sdim
13243218822Sdim  /* imm == 0 case is encoded as VMOV for V{R}SHR.  */
13244218822Sdim  if (imm == 0)
13245218822Sdim    {
13246218822Sdim      inst.operands[2].present = 0;
13247218822Sdim      do_neon_mov ();
1324889857Sobrien      return;
1324989857Sobrien    }
1325089857Sobrien
13251218822Sdim  constraint (imm < 1 || (unsigned)imm > et.size,
13252218822Sdim              _("immediate out of range for shift"));
13253218822Sdim  neon_imm_shift (TRUE, et.type == NT_unsigned, neon_quad (rs), et,
13254218822Sdim                  et.size - imm);
1325589857Sobrien}
1325689857Sobrien
1325789857Sobrienstatic void
13258218822Sdimdo_neon_movl (void)
1325989857Sobrien{
13260218822Sdim  struct neon_type_el et = neon_check_type (2, NS_QD,
13261218822Sdim    N_EQK | N_DBL, N_SU_32 | N_KEY);
13262218822Sdim  unsigned sizebits = et.size >> 3;
13263218822Sdim  inst.instruction |= sizebits << 19;
13264218822Sdim  neon_two_same (0, et.type == NT_unsigned, -1);
13265218822Sdim}
1326689857Sobrien
13267218822Sdimstatic void
13268218822Sdimdo_neon_trn (void)
13269218822Sdim{
13270218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13271218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13272218822Sdim    N_EQK, N_8 | N_16 | N_32 | N_KEY);
13273218822Sdim  inst.instruction = NEON_ENC_INTEGER (inst.instruction);
13274218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
13275218822Sdim}
13276218822Sdim
13277218822Sdimstatic void
13278218822Sdimdo_neon_zip_uzp (void)
13279218822Sdim{
13280218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13281218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13282218822Sdim    N_EQK, N_8 | N_16 | N_32 | N_KEY);
13283218822Sdim  if (rs == NS_DD && et.size == 32)
1328489857Sobrien    {
13285218822Sdim      /* Special case: encode as VTRN.32 <Dd>, <Dm>.  */
13286218822Sdim      inst.instruction = N_MNEM_vtrn;
13287218822Sdim      do_neon_trn ();
1328889857Sobrien      return;
1328989857Sobrien    }
13290218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
13291218822Sdim}
1329289857Sobrien
13293218822Sdimstatic void
13294218822Sdimdo_neon_sat_abs_neg (void)
13295218822Sdim{
13296218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13297218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13298218822Sdim    N_EQK, N_S8 | N_S16 | N_S32 | N_KEY);
13299218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1330089857Sobrien}
1330189857Sobrien
1330289857Sobrienstatic void
13303218822Sdimdo_neon_pair_long (void)
1330489857Sobrien{
13305218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13306218822Sdim  struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_SU_32 | N_KEY);
13307218822Sdim  /* Unsigned is encoded in OP field (bit 7) for these instruction.  */
13308218822Sdim  inst.instruction |= (et.type == NT_unsigned) << 7;
13309218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1331089857Sobrien}
1331189857Sobrien
1331289857Sobrienstatic void
13313218822Sdimdo_neon_recip_est (void)
1331489857Sobrien{
13315218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13316218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13317218822Sdim    N_EQK | N_FLT, N_F32 | N_U32 | N_KEY);
13318218822Sdim  inst.instruction |= (et.type == NT_float) << 8;
13319218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1332089857Sobrien}
1332189857Sobrien
1332289857Sobrienstatic void
13323218822Sdimdo_neon_cls (void)
1332489857Sobrien{
13325218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13326218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13327218822Sdim    N_EQK, N_S8 | N_S16 | N_S32 | N_KEY);
13328218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1332989857Sobrien}
1333089857Sobrien
1333189857Sobrienstatic void
13332218822Sdimdo_neon_clz (void)
1333389857Sobrien{
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_I8 | N_I16 | N_I32 | N_KEY);
13337218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1333889857Sobrien}
1333989857Sobrien
1334089857Sobrienstatic void
13341218822Sdimdo_neon_cnt (void)
1334289857Sobrien{
13343218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13344218822Sdim  struct neon_type_el et = neon_check_type (2, rs,
13345218822Sdim    N_EQK | N_INT, N_8 | N_KEY);
13346218822Sdim  neon_two_same (neon_quad (rs), 1, et.size);
1334789857Sobrien}
1334889857Sobrien
1334989857Sobrienstatic void
13350218822Sdimdo_neon_swp (void)
1335189857Sobrien{
13352218822Sdim  enum neon_shape rs = neon_select_shape (NS_DD, NS_QQ, NS_NULL);
13353218822Sdim  neon_two_same (neon_quad (rs), 1, -1);
1335489857Sobrien}
1335589857Sobrien
13356218822Sdimstatic void
13357218822Sdimdo_neon_tbl_tbx (void)
13358218822Sdim{
13359218822Sdim  unsigned listlenbits;
13360218822Sdim  neon_check_type (3, NS_DLD, N_EQK, N_EQK, N_8 | N_KEY);
13361218822Sdim
13362218822Sdim  if (inst.operands[1].imm < 1 || inst.operands[1].imm > 4)
13363218822Sdim    {
13364218822Sdim      first_error (_("bad list length for table lookup"));
13365218822Sdim      return;
13366218822Sdim    }
13367218822Sdim
13368218822Sdim  listlenbits = inst.operands[1].imm - 1;
13369218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
13370218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
13371218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 16;
13372218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 7;
13373218822Sdim  inst.instruction |= LOW4 (inst.operands[2].reg);
13374218822Sdim  inst.instruction |= HI1 (inst.operands[2].reg) << 5;
13375218822Sdim  inst.instruction |= listlenbits << 8;
13376218822Sdim
13377218822Sdim  inst.instruction = neon_dp_fixup (inst.instruction);
13378218822Sdim}
1337989857Sobrien
1338089857Sobrienstatic void
13381218822Sdimdo_neon_ldm_stm (void)
1338289857Sobrien{
13383218822Sdim  /* P, U and L bits are part of bitmask.  */
13384218822Sdim  int is_dbmode = (inst.instruction & (1 << 24)) != 0;
13385218822Sdim  unsigned offsetbits = inst.operands[1].imm * 2;
1338689857Sobrien
13387218822Sdim  if (inst.operands[1].issingle)
13388218822Sdim    {
13389218822Sdim      do_vfp_nsyn_ldm_stm (is_dbmode);
13390218822Sdim      return;
13391218822Sdim    }
1339289857Sobrien
13393218822Sdim  constraint (is_dbmode && !inst.operands[0].writeback,
13394218822Sdim              _("writeback (!) must be used for VLDMDB and VSTMDB"));
1339589857Sobrien
13396218822Sdim  constraint (inst.operands[1].imm < 1 || inst.operands[1].imm > 16,
13397218822Sdim              _("register list must contain at least 1 and at most 16 "
13398218822Sdim                "registers"));
13399218822Sdim
13400218822Sdim  inst.instruction |= inst.operands[0].reg << 16;
13401218822Sdim  inst.instruction |= inst.operands[0].writeback << 21;
13402218822Sdim  inst.instruction |= LOW4 (inst.operands[1].reg) << 12;
13403218822Sdim  inst.instruction |= HI1 (inst.operands[1].reg) << 22;
13404218822Sdim
13405218822Sdim  inst.instruction |= offsetbits;
13406218822Sdim
13407218822Sdim  do_vfp_cond_or_thumb ();
13408218822Sdim}
13409218822Sdim
13410218822Sdimstatic void
13411218822Sdimdo_neon_ldr_str (void)
13412218822Sdim{
13413218822Sdim  int is_ldr = (inst.instruction & (1 << 20)) != 0;
13414218822Sdim
13415218822Sdim  if (inst.operands[0].issingle)
1341689857Sobrien    {
13417218822Sdim      if (is_ldr)
13418218822Sdim        do_vfp_nsyn_opcode ("flds");
13419218822Sdim      else
13420218822Sdim        do_vfp_nsyn_opcode ("fsts");
1342189857Sobrien    }
1342289857Sobrien  else
13423218822Sdim    {
13424218822Sdim      if (is_ldr)
13425218822Sdim        do_vfp_nsyn_opcode ("fldd");
13426218822Sdim      else
13427218822Sdim        do_vfp_nsyn_opcode ("fstd");
13428218822Sdim    }
1342989857Sobrien}
1343089857Sobrien
13431218822Sdim/* "interleave" version also handles non-interleaving register VLD1/VST1
13432218822Sdim   instructions.  */
1343389857Sobrien
1343489857Sobrienstatic void
13435218822Sdimdo_neon_ld_st_interleave (void)
1343689857Sobrien{
13437218822Sdim  struct neon_type_el et = neon_check_type (1, NS_NULL,
13438218822Sdim                                            N_8 | N_16 | N_32 | N_64);
13439218822Sdim  unsigned alignbits = 0;
13440218822Sdim  unsigned idx;
13441218822Sdim  /* The bits in this table go:
13442218822Sdim     0: register stride of one (0) or two (1)
13443218822Sdim     1,2: register list length, minus one (1, 2, 3, 4).
13444218822Sdim     3,4: <n> in instruction type, minus one (VLD<n> / VST<n>).
13445218822Sdim     We use -1 for invalid entries.  */
13446218822Sdim  const int typetable[] =
13447218822Sdim    {
13448218822Sdim      0x7,  -1, 0xa,  -1, 0x6,  -1, 0x2,  -1, /* VLD1 / VST1.  */
13449218822Sdim       -1,  -1, 0x8, 0x9,  -1,  -1, 0x3,  -1, /* VLD2 / VST2.  */
13450218822Sdim       -1,  -1,  -1,  -1, 0x4, 0x5,  -1,  -1, /* VLD3 / VST3.  */
13451218822Sdim       -1,  -1,  -1,  -1,  -1,  -1, 0x0, 0x1  /* VLD4 / VST4.  */
13452218822Sdim    };
13453218822Sdim  int typebits;
1345489857Sobrien
13455218822Sdim  if (et.type == NT_invtype)
13456218822Sdim    return;
1345789857Sobrien
13458218822Sdim  if (inst.operands[1].immisalign)
13459218822Sdim    switch (inst.operands[1].imm >> 8)
13460218822Sdim      {
13461218822Sdim      case 64: alignbits = 1; break;
13462218822Sdim      case 128:
13463218822Sdim        if (NEON_REGLIST_LENGTH (inst.operands[0].imm) == 3)
13464218822Sdim          goto bad_alignment;
13465218822Sdim        alignbits = 2;
13466218822Sdim        break;
13467218822Sdim      case 256:
13468218822Sdim        if (NEON_REGLIST_LENGTH (inst.operands[0].imm) == 3)
13469218822Sdim          goto bad_alignment;
13470218822Sdim        alignbits = 3;
13471218822Sdim        break;
13472218822Sdim      default:
13473218822Sdim      bad_alignment:
13474218822Sdim        first_error (_("bad alignment"));
13475218822Sdim        return;
13476218822Sdim      }
1347789857Sobrien
13478218822Sdim  inst.instruction |= alignbits << 4;
13479218822Sdim  inst.instruction |= neon_logbits (et.size) << 6;
13480218822Sdim
13481218822Sdim  /* Bits [4:6] of the immediate in a list specifier encode register stride
13482218822Sdim     (minus 1) in bit 4, and list length in bits [5:6]. We put the <n> of
13483218822Sdim     VLD<n>/VST<n> in bits [9:8] of the initial bitmask. Suck it out here, look
13484218822Sdim     up the right value for "type" in a table based on this value and the given
13485218822Sdim     list style, then stick it back.  */
13486218822Sdim  idx = ((inst.operands[0].imm >> 4) & 7)
13487218822Sdim        | (((inst.instruction >> 8) & 3) << 3);
13488218822Sdim
13489218822Sdim  typebits = typetable[idx];
13490218822Sdim
13491218822Sdim  constraint (typebits == -1, _("bad list type for instruction"));
13492218822Sdim
13493218822Sdim  inst.instruction &= ~0xf00;
13494218822Sdim  inst.instruction |= typebits << 8;
13495218822Sdim}
13496218822Sdim
13497218822Sdim/* Check alignment is valid for do_neon_ld_st_lane and do_neon_ld_dup.
13498218822Sdim   *DO_ALIGN is set to 1 if the relevant alignment bit should be set, 0
13499218822Sdim   otherwise. The variable arguments are a list of pairs of legal (size, align)
13500218822Sdim   values, terminated with -1.  */
13501218822Sdim
13502218822Sdimstatic int
13503218822Sdimneon_alignment_bit (int size, int align, int *do_align, ...)
13504218822Sdim{
13505218822Sdim  va_list ap;
13506218822Sdim  int result = FAIL, thissize, thisalign;
13507218822Sdim
13508218822Sdim  if (!inst.operands[1].immisalign)
1350989857Sobrien    {
13510218822Sdim      *do_align = 0;
13511218822Sdim      return SUCCESS;
1351289857Sobrien    }
13513218822Sdim
13514218822Sdim  va_start (ap, do_align);
13515218822Sdim
13516218822Sdim  do
13517218822Sdim    {
13518218822Sdim      thissize = va_arg (ap, int);
13519218822Sdim      if (thissize == -1)
13520218822Sdim        break;
13521218822Sdim      thisalign = va_arg (ap, int);
13522218822Sdim
13523218822Sdim      if (size == thissize && align == thisalign)
13524218822Sdim        result = SUCCESS;
13525218822Sdim    }
13526218822Sdim  while (result != SUCCESS);
13527218822Sdim
13528218822Sdim  va_end (ap);
13529218822Sdim
13530218822Sdim  if (result == SUCCESS)
13531218822Sdim    *do_align = 1;
1353289857Sobrien  else
13533218822Sdim    first_error (_("unsupported alignment for instruction"));
13534218822Sdim
13535218822Sdim  return result;
1353689857Sobrien}
1353789857Sobrien
1353889857Sobrienstatic void
13539218822Sdimdo_neon_ld_st_lane (void)
1354089857Sobrien{
13541218822Sdim  struct neon_type_el et = neon_check_type (1, NS_NULL, N_8 | N_16 | N_32);
13542218822Sdim  int align_good, do_align = 0;
13543218822Sdim  int logsize = neon_logbits (et.size);
13544218822Sdim  int align = inst.operands[1].imm >> 8;
13545218822Sdim  int n = (inst.instruction >> 8) & 3;
13546218822Sdim  int max_el = 64 / et.size;
13547218822Sdim
13548218822Sdim  if (et.type == NT_invtype)
13549218822Sdim    return;
13550218822Sdim
13551218822Sdim  constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != n + 1,
13552218822Sdim              _("bad list length"));
13553218822Sdim  constraint (NEON_LANE (inst.operands[0].imm) >= max_el,
13554218822Sdim              _("scalar index out of range"));
13555218822Sdim  constraint (n != 0 && NEON_REG_STRIDE (inst.operands[0].imm) == 2
13556218822Sdim              && et.size == 8,
13557218822Sdim              _("stride of 2 unavailable when element size is 8"));
13558218822Sdim
13559218822Sdim  switch (n)
13560218822Sdim    {
13561218822Sdim    case 0:  /* VLD1 / VST1.  */
13562218822Sdim      align_good = neon_alignment_bit (et.size, align, &do_align, 16, 16,
13563218822Sdim                                       32, 32, -1);
13564218822Sdim      if (align_good == FAIL)
13565218822Sdim        return;
13566218822Sdim      if (do_align)
13567218822Sdim        {
13568218822Sdim          unsigned alignbits = 0;
13569218822Sdim          switch (et.size)
13570218822Sdim            {
13571218822Sdim            case 16: alignbits = 0x1; break;
13572218822Sdim            case 32: alignbits = 0x3; break;
13573218822Sdim            default: ;
13574218822Sdim            }
13575218822Sdim          inst.instruction |= alignbits << 4;
13576218822Sdim        }
13577218822Sdim      break;
1357889857Sobrien
13579218822Sdim    case 1:  /* VLD2 / VST2.  */
13580218822Sdim      align_good = neon_alignment_bit (et.size, align, &do_align, 8, 16, 16, 32,
13581218822Sdim                                       32, 64, -1);
13582218822Sdim      if (align_good == FAIL)
13583218822Sdim        return;
13584218822Sdim      if (do_align)
13585218822Sdim        inst.instruction |= 1 << 4;
13586218822Sdim      break;
1358789857Sobrien
13588218822Sdim    case 2:  /* VLD3 / VST3.  */
13589218822Sdim      constraint (inst.operands[1].immisalign,
13590218822Sdim                  _("can't use alignment with this instruction"));
13591218822Sdim      break;
1359289857Sobrien
13593218822Sdim    case 3:  /* VLD4 / VST4.  */
13594218822Sdim      align_good = neon_alignment_bit (et.size, align, &do_align, 8, 32,
13595218822Sdim                                       16, 64, 32, 64, 32, 128, -1);
13596218822Sdim      if (align_good == FAIL)
13597218822Sdim        return;
13598218822Sdim      if (do_align)
13599218822Sdim        {
13600218822Sdim          unsigned alignbits = 0;
13601218822Sdim          switch (et.size)
13602218822Sdim            {
13603218822Sdim            case 8:  alignbits = 0x1; break;
13604218822Sdim            case 16: alignbits = 0x1; break;
13605218822Sdim            case 32: alignbits = (align == 64) ? 0x1 : 0x2; break;
13606218822Sdim            default: ;
13607218822Sdim            }
13608218822Sdim          inst.instruction |= alignbits << 4;
13609218822Sdim        }
13610218822Sdim      break;
13611218822Sdim
13612218822Sdim    default: ;
1361389857Sobrien    }
13614218822Sdim
13615218822Sdim  /* Reg stride of 2 is encoded in bit 5 when size==16, bit 6 when size==32.  */
13616218822Sdim  if (n != 0 && NEON_REG_STRIDE (inst.operands[0].imm) == 2)
13617218822Sdim    inst.instruction |= 1 << (4 + logsize);
13618218822Sdim
13619218822Sdim  inst.instruction |= NEON_LANE (inst.operands[0].imm) << (logsize + 5);
13620218822Sdim  inst.instruction |= logsize << 10;
1362189857Sobrien}
1362289857Sobrien
13623218822Sdim/* Encode single n-element structure to all lanes VLD<n> instructions.  */
1362489857Sobrien
1362589857Sobrienstatic void
13626218822Sdimdo_neon_ld_dup (void)
1362789857Sobrien{
13628218822Sdim  struct neon_type_el et = neon_check_type (1, NS_NULL, N_8 | N_16 | N_32);
13629218822Sdim  int align_good, do_align = 0;
1363089857Sobrien
13631218822Sdim  if (et.type == NT_invtype)
13632218822Sdim    return;
1363389857Sobrien
13634218822Sdim  switch ((inst.instruction >> 8) & 3)
13635218822Sdim    {
13636218822Sdim    case 0:  /* VLD1.  */
13637218822Sdim      assert (NEON_REG_STRIDE (inst.operands[0].imm) != 2);
13638218822Sdim      align_good = neon_alignment_bit (et.size, inst.operands[1].imm >> 8,
13639218822Sdim                                       &do_align, 16, 16, 32, 32, -1);
13640218822Sdim      if (align_good == FAIL)
13641218822Sdim        return;
13642218822Sdim      switch (NEON_REGLIST_LENGTH (inst.operands[0].imm))
13643218822Sdim        {
13644218822Sdim        case 1: break;
13645218822Sdim        case 2: inst.instruction |= 1 << 5; break;
13646218822Sdim        default: first_error (_("bad list length")); return;
13647218822Sdim        }
13648218822Sdim      inst.instruction |= neon_logbits (et.size) << 6;
13649218822Sdim      break;
1365089857Sobrien
13651218822Sdim    case 1:  /* VLD2.  */
13652218822Sdim      align_good = neon_alignment_bit (et.size, inst.operands[1].imm >> 8,
13653218822Sdim                                       &do_align, 8, 16, 16, 32, 32, 64, -1);
13654218822Sdim      if (align_good == FAIL)
13655218822Sdim        return;
13656218822Sdim      constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 2,
13657218822Sdim                  _("bad list length"));
13658218822Sdim      if (NEON_REG_STRIDE (inst.operands[0].imm) == 2)
13659218822Sdim        inst.instruction |= 1 << 5;
13660218822Sdim      inst.instruction |= neon_logbits (et.size) << 6;
13661218822Sdim      break;
13662218822Sdim
13663218822Sdim    case 2:  /* VLD3.  */
13664218822Sdim      constraint (inst.operands[1].immisalign,
13665218822Sdim                  _("can't use alignment with this instruction"));
13666218822Sdim      constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 3,
13667218822Sdim                  _("bad list length"));
13668218822Sdim      if (NEON_REG_STRIDE (inst.operands[0].imm) == 2)
13669218822Sdim        inst.instruction |= 1 << 5;
13670218822Sdim      inst.instruction |= neon_logbits (et.size) << 6;
13671218822Sdim      break;
13672218822Sdim
13673218822Sdim    case 3:  /* VLD4.  */
13674218822Sdim      {
13675218822Sdim        int align = inst.operands[1].imm >> 8;
13676218822Sdim        align_good = neon_alignment_bit (et.size, align, &do_align, 8, 32,
13677218822Sdim                                         16, 64, 32, 64, 32, 128, -1);
13678218822Sdim        if (align_good == FAIL)
13679218822Sdim          return;
13680218822Sdim        constraint (NEON_REGLIST_LENGTH (inst.operands[0].imm) != 4,
13681218822Sdim                    _("bad list length"));
13682218822Sdim        if (NEON_REG_STRIDE (inst.operands[0].imm) == 2)
13683218822Sdim          inst.instruction |= 1 << 5;
13684218822Sdim        if (et.size == 32 && align == 128)
13685218822Sdim          inst.instruction |= 0x3 << 6;
13686218822Sdim        else
13687218822Sdim          inst.instruction |= neon_logbits (et.size) << 6;
13688218822Sdim      }
13689218822Sdim      break;
13690218822Sdim
13691218822Sdim    default: ;
1369289857Sobrien    }
1369389857Sobrien
13694218822Sdim  inst.instruction |= do_align << 4;
13695218822Sdim}
1369689857Sobrien
13697218822Sdim/* Disambiguate VLD<n> and VST<n> instructions, and fill in common bits (those
13698218822Sdim   apart from bits [11:4].  */
1369989857Sobrien
13700218822Sdimstatic void
13701218822Sdimdo_neon_ldx_stx (void)
13702218822Sdim{
13703218822Sdim  switch (NEON_LANE (inst.operands[0].imm))
1370489857Sobrien    {
13705218822Sdim    case NEON_INTERLEAVE_LANES:
13706218822Sdim      inst.instruction = NEON_ENC_INTERLV (inst.instruction);
13707218822Sdim      do_neon_ld_st_interleave ();
13708218822Sdim      break;
13709218822Sdim
13710218822Sdim    case NEON_ALL_LANES:
13711218822Sdim      inst.instruction = NEON_ENC_DUP (inst.instruction);
13712218822Sdim      do_neon_ld_dup ();
13713218822Sdim      break;
13714218822Sdim
13715218822Sdim    default:
13716218822Sdim      inst.instruction = NEON_ENC_LANE (inst.instruction);
13717218822Sdim      do_neon_ld_st_lane ();
1371889857Sobrien    }
1371989857Sobrien
13720218822Sdim  /* L bit comes from bit mask.  */
13721218822Sdim  inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
13722218822Sdim  inst.instruction |= HI1 (inst.operands[0].reg) << 22;
13723218822Sdim  inst.instruction |= inst.operands[1].reg << 16;
13724218822Sdim
13725218822Sdim  if (inst.operands[1].postind)
1372689857Sobrien    {
13727218822Sdim      int postreg = inst.operands[1].imm & 0xf;
13728218822Sdim      constraint (!inst.operands[1].immisreg,
13729218822Sdim                  _("post-index must be a register"));
13730218822Sdim      constraint (postreg == 0xd || postreg == 0xf,
13731218822Sdim                  _("bad register for post-index"));
13732218822Sdim      inst.instruction |= postreg;
1373389857Sobrien    }
13734218822Sdim  else if (inst.operands[1].writeback)
13735218822Sdim    {
13736218822Sdim      inst.instruction |= 0xd;
13737218822Sdim    }
13738218822Sdim  else
13739218822Sdim    inst.instruction |= 0xf;
13740218822Sdim
13741218822Sdim  if (thumb_mode)
13742218822Sdim    inst.instruction |= 0xf9000000;
13743218822Sdim  else
13744218822Sdim    inst.instruction |= 0xf4000000;
13745218822Sdim}
1374689857Sobrien
13747218822Sdim
13748218822Sdim/* Overall per-instruction processing.	*/
1374989857Sobrien
13750218822Sdim/* We need to be able to fix up arbitrary expressions in some statements.
13751218822Sdim   This is so that we can handle symbols that are an arbitrary distance from
13752218822Sdim   the pc.  The most common cases are of the form ((+/-sym -/+ . - 8) & mask),
13753218822Sdim   which returns part of an address in a form which will be valid for
13754218822Sdim   a data instruction.	We do this by pushing the expression into a symbol
13755218822Sdim   in the expr_section, and creating a fix for that.  */
13756218822Sdim
13757218822Sdimstatic void
13758218822Sdimfix_new_arm (fragS *	   frag,
13759218822Sdim	     int	   where,
13760218822Sdim	     short int	   size,
13761218822Sdim	     expressionS * exp,
13762218822Sdim	     int	   pc_rel,
13763218822Sdim	     int	   reloc)
13764218822Sdim{
13765218822Sdim  fixS *	   new_fix;
13766218822Sdim
13767218822Sdim  switch (exp->X_op)
1376889857Sobrien    {
13769218822Sdim    case O_constant:
13770218822Sdim    case O_symbol:
13771218822Sdim    case O_add:
13772218822Sdim    case O_subtract:
13773218822Sdim      new_fix = fix_new_exp (frag, where, size, exp, pc_rel, reloc);
13774218822Sdim      break;
1377589857Sobrien
13776218822Sdim    default:
13777218822Sdim      new_fix = fix_new (frag, where, size, make_expr_symbol (exp), 0,
13778218822Sdim			 pc_rel, reloc);
13779218822Sdim      break;
1378089857Sobrien    }
1378189857Sobrien
13782218822Sdim  /* Mark whether the fix is to a THUMB instruction, or an ARM
13783218822Sdim     instruction.  */
13784218822Sdim  new_fix->tc_fix_data = thumb_mode;
1378589857Sobrien}
1378689857Sobrien
13787218822Sdim/* Create a frg for an instruction requiring relaxation.  */
13788218822Sdimstatic void
13789218822Sdimoutput_relax_insn (void)
1379089857Sobrien{
13791218822Sdim  char * to;
13792218822Sdim  symbolS *sym;
1379389857Sobrien  int offset;
1379489857Sobrien
13795218822Sdim  /* The size of the instruction is unknown, so tie the debug info to the
13796218822Sdim     start of the instruction.  */
13797218822Sdim  dwarf2_emit_insn (0);
1379889857Sobrien
13799218822Sdim  switch (inst.reloc.exp.X_op)
13800218822Sdim    {
13801218822Sdim    case O_symbol:
13802218822Sdim      sym = inst.reloc.exp.X_add_symbol;
13803218822Sdim      offset = inst.reloc.exp.X_add_number;
13804218822Sdim      break;
13805218822Sdim    case O_constant:
13806218822Sdim      sym = NULL;
13807218822Sdim      offset = inst.reloc.exp.X_add_number;
13808218822Sdim      break;
13809218822Sdim    default:
13810218822Sdim      sym = make_expr_symbol (&inst.reloc.exp);
13811218822Sdim      offset = 0;
13812218822Sdim      break;
13813218822Sdim  }
13814218822Sdim  to = frag_var (rs_machine_dependent, INSN_SIZE, THUMB_SIZE,
13815218822Sdim		 inst.relax, sym, offset, NULL/*offset, opcode*/);
13816218822Sdim  md_number_to_chars (to, inst.instruction, THUMB_SIZE);
13817218822Sdim}
1381889857Sobrien
13819218822Sdim/* Write a 32-bit thumb instruction to buf.  */
13820218822Sdimstatic void
13821218822Sdimput_thumb32_insn (char * buf, unsigned long insn)
13822218822Sdim{
13823218822Sdim  md_number_to_chars (buf, insn >> 16, THUMB_SIZE);
13824218822Sdim  md_number_to_chars (buf + THUMB_SIZE, insn, THUMB_SIZE);
13825218822Sdim}
1382689857Sobrien
13827218822Sdimstatic void
13828218822Sdimoutput_inst (const char * str)
13829218822Sdim{
13830218822Sdim  char * to = NULL;
1383189857Sobrien
13832218822Sdim  if (inst.error)
1383389857Sobrien    {
13834218822Sdim      as_bad ("%s -- `%s'", inst.error, str);
13835218822Sdim      return;
1383689857Sobrien    }
13837218822Sdim  if (inst.relax) {
13838218822Sdim      output_relax_insn();
13839218822Sdim      return;
13840218822Sdim  }
13841218822Sdim  if (inst.size == 0)
13842218822Sdim    return;
1384389857Sobrien
13844218822Sdim  to = frag_more (inst.size);
1384589857Sobrien
13846218822Sdim  if (thumb_mode && (inst.size > THUMB_SIZE))
1384789857Sobrien    {
13848218822Sdim      assert (inst.size == (2 * THUMB_SIZE));
13849218822Sdim      put_thumb32_insn (to, inst.instruction);
1385089857Sobrien    }
13851218822Sdim  else if (inst.size > INSN_SIZE)
13852218822Sdim    {
13853218822Sdim      assert (inst.size == (2 * INSN_SIZE));
13854218822Sdim      md_number_to_chars (to, inst.instruction, INSN_SIZE);
13855218822Sdim      md_number_to_chars (to + INSN_SIZE, inst.instruction, INSN_SIZE);
13856218822Sdim    }
13857218822Sdim  else
13858218822Sdim    md_number_to_chars (to, inst.instruction, inst.size);
1385989857Sobrien
13860218822Sdim  if (inst.reloc.type != BFD_RELOC_UNUSED)
13861218822Sdim    fix_new_arm (frag_now, to - frag_now->fr_literal,
13862218822Sdim		 inst.size, & inst.reloc.exp, inst.reloc.pc_rel,
13863218822Sdim		 inst.reloc.type);
1386489857Sobrien
13865218822Sdim  dwarf2_emit_insn (inst.size);
1386689857Sobrien}
1386789857Sobrien
13868218822Sdim/* Tag values used in struct asm_opcode's tag field.  */
13869218822Sdimenum opcode_tag
13870218822Sdim{
13871218822Sdim  OT_unconditional,	/* Instruction cannot be conditionalized.
13872218822Sdim			   The ARM condition field is still 0xE.  */
13873218822Sdim  OT_unconditionalF,	/* Instruction cannot be conditionalized
13874218822Sdim			   and carries 0xF in its ARM condition field.  */
13875218822Sdim  OT_csuffix,		/* Instruction takes a conditional suffix.  */
13876218822Sdim  OT_csuffixF,		/* Some forms of the instruction take a conditional
13877218822Sdim                           suffix, others place 0xF where the condition field
13878218822Sdim                           would be.  */
13879218822Sdim  OT_cinfix3,		/* Instruction takes a conditional infix,
13880218822Sdim			   beginning at character index 3.  (In
13881218822Sdim			   unified mode, it becomes a suffix.)  */
13882218822Sdim  OT_cinfix3_deprecated, /* The same as OT_cinfix3.  This is used for
13883218822Sdim			    tsts, cmps, cmns, and teqs. */
13884218822Sdim  OT_cinfix3_legacy,	/* Legacy instruction takes a conditional infix at
13885218822Sdim			   character index 3, even in unified mode.  Used for
13886218822Sdim			   legacy instructions where suffix and infix forms
13887218822Sdim			   may be ambiguous.  */
13888218822Sdim  OT_csuf_or_in3,	/* Instruction takes either a conditional
13889218822Sdim			   suffix or an infix at character index 3.  */
13890218822Sdim  OT_odd_infix_unc,	/* This is the unconditional variant of an
13891218822Sdim			   instruction that takes a conditional infix
13892218822Sdim			   at an unusual position.  In unified mode,
13893218822Sdim			   this variant will accept a suffix.  */
13894218822Sdim  OT_odd_infix_0	/* Values greater than or equal to OT_odd_infix_0
13895218822Sdim			   are the conditional variants of instructions that
13896218822Sdim			   take conditional infixes in unusual positions.
13897218822Sdim			   The infix appears at character index
13898218822Sdim			   (tag - OT_odd_infix_0).  These are not accepted
13899218822Sdim			   in unified mode.  */
13900218822Sdim};
1390189857Sobrien
13902218822Sdim/* Subroutine of md_assemble, responsible for looking up the primary
13903218822Sdim   opcode from the mnemonic the user wrote.  STR points to the
13904218822Sdim   beginning of the mnemonic.
13905218822Sdim
13906218822Sdim   This is not simply a hash table lookup, because of conditional
13907218822Sdim   variants.  Most instructions have conditional variants, which are
13908218822Sdim   expressed with a _conditional affix_ to the mnemonic.  If we were
13909218822Sdim   to encode each conditional variant as a literal string in the opcode
13910218822Sdim   table, it would have approximately 20,000 entries.
13911218822Sdim
13912218822Sdim   Most mnemonics take this affix as a suffix, and in unified syntax,
13913218822Sdim   'most' is upgraded to 'all'.  However, in the divided syntax, some
13914218822Sdim   instructions take the affix as an infix, notably the s-variants of
13915218822Sdim   the arithmetic instructions.  Of those instructions, all but six
13916218822Sdim   have the infix appear after the third character of the mnemonic.
13917218822Sdim
13918218822Sdim   Accordingly, the algorithm for looking up primary opcodes given
13919218822Sdim   an identifier is:
13920218822Sdim
13921218822Sdim   1. Look up the identifier in the opcode table.
13922218822Sdim      If we find a match, go to step U.
13923218822Sdim
13924218822Sdim   2. Look up the last two characters of the identifier in the
13925218822Sdim      conditions table.  If we find a match, look up the first N-2
13926218822Sdim      characters of the identifier in the opcode table.  If we
13927218822Sdim      find a match, go to step CE.
13928218822Sdim
13929218822Sdim   3. Look up the fourth and fifth characters of the identifier in
13930218822Sdim      the conditions table.  If we find a match, extract those
13931218822Sdim      characters from the identifier, and look up the remaining
13932218822Sdim      characters in the opcode table.  If we find a match, go
13933218822Sdim      to step CM.
13934218822Sdim
13935218822Sdim   4. Fail.
13936218822Sdim
13937218822Sdim   U. Examine the tag field of the opcode structure, in case this is
13938218822Sdim      one of the six instructions with its conditional infix in an
13939218822Sdim      unusual place.  If it is, the tag tells us where to find the
13940218822Sdim      infix; look it up in the conditions table and set inst.cond
13941218822Sdim      accordingly.  Otherwise, this is an unconditional instruction.
13942218822Sdim      Again set inst.cond accordingly.  Return the opcode structure.
13943218822Sdim
13944218822Sdim  CE. Examine the tag field to make sure this is an instruction that
13945218822Sdim      should receive a conditional suffix.  If it is not, fail.
13946218822Sdim      Otherwise, set inst.cond from the suffix we already looked up,
13947218822Sdim      and return the opcode structure.
13948218822Sdim
13949218822Sdim  CM. Examine the tag field to make sure this is an instruction that
13950218822Sdim      should receive a conditional infix after the third character.
13951218822Sdim      If it is not, fail.  Otherwise, undo the edits to the current
13952218822Sdim      line of input and proceed as for case CE.  */
13953218822Sdim
13954218822Sdimstatic const struct asm_opcode *
13955218822Sdimopcode_lookup (char **str)
1395689857Sobrien{
13957218822Sdim  char *end, *base;
13958218822Sdim  char *affix;
13959218822Sdim  const struct asm_opcode *opcode;
13960218822Sdim  const struct asm_cond *cond;
13961218822Sdim  char save[2];
13962218822Sdim  bfd_boolean neon_supported;
13963218822Sdim
13964218822Sdim  neon_supported = ARM_CPU_HAS_FEATURE (cpu_variant, fpu_neon_ext_v1);
1396589857Sobrien
13966218822Sdim  /* Scan up to the end of the mnemonic, which must end in white space,
13967218822Sdim     '.' (in unified mode, or for Neon instructions), or end of string.  */
13968218822Sdim  for (base = end = *str; *end != '\0'; end++)
13969218822Sdim    if (*end == ' ' || ((unified_syntax || neon_supported) && *end == '.'))
13970218822Sdim      break;
1397189857Sobrien
13972218822Sdim  if (end == base)
13973218822Sdim    return 0;
1397489857Sobrien
13975218822Sdim  /* Handle a possible width suffix and/or Neon type suffix.  */
13976218822Sdim  if (end[0] == '.')
1397789857Sobrien    {
13978218822Sdim      int offset = 2;
13979218822Sdim
13980218822Sdim      /* The .w and .n suffixes are only valid if the unified syntax is in
13981218822Sdim         use.  */
13982218822Sdim      if (unified_syntax && end[1] == 'w')
13983218822Sdim	inst.size_req = 4;
13984218822Sdim      else if (unified_syntax && end[1] == 'n')
13985218822Sdim	inst.size_req = 2;
13986218822Sdim      else
13987218822Sdim        offset = 0;
1398889857Sobrien
13989218822Sdim      inst.vectype.elems = 0;
1399089857Sobrien
13991218822Sdim      *str = end + offset;
1399289857Sobrien
13993218822Sdim      if (end[offset] == '.')
1399489857Sobrien	{
13995218822Sdim	  /* See if we have a Neon type suffix (possible in either unified or
13996218822Sdim             non-unified ARM syntax mode).  */
13997218822Sdim          if (parse_neon_type (&inst.vectype, str) == FAIL)
13998218822Sdim	    return 0;
13999218822Sdim        }
14000218822Sdim      else if (end[offset] != '\0' && end[offset] != ' ')
14001218822Sdim        return 0;
14002218822Sdim    }
14003218822Sdim  else
14004218822Sdim    *str = end;
1400589857Sobrien
14006218822Sdim  /* Look for unaffixed or special-case affixed mnemonic.  */
14007218822Sdim  opcode = hash_find_n (arm_ops_hsh, base, end - base);
14008218822Sdim  if (opcode)
14009218822Sdim    {
14010218822Sdim      /* step U */
14011218822Sdim      if (opcode->tag < OT_odd_infix_0)
1401289857Sobrien	{
14013218822Sdim	  inst.cond = COND_ALWAYS;
14014218822Sdim	  return opcode;
1401589857Sobrien	}
14016218822Sdim
14017218822Sdim      if (unified_syntax)
14018218822Sdim	as_warn (_("conditional infixes are deprecated in unified syntax"));
14019218822Sdim      affix = base + (opcode->tag - OT_odd_infix_0);
14020218822Sdim      cond = hash_find_n (arm_cond_hsh, affix, 2);
14021218822Sdim      assert (cond);
14022218822Sdim
14023218822Sdim      inst.cond = cond->value;
14024218822Sdim      return opcode;
1402589857Sobrien    }
14026218822Sdim
14027218822Sdim  /* Cannot have a conditional suffix on a mnemonic of less than two
14028218822Sdim     characters.  */
14029218822Sdim  if (end - base < 3)
14030218822Sdim    return 0;
14031218822Sdim
14032218822Sdim  /* Look for suffixed mnemonic.  */
14033218822Sdim  affix = end - 2;
14034218822Sdim  cond = hash_find_n (arm_cond_hsh, affix, 2);
14035218822Sdim  opcode = hash_find_n (arm_ops_hsh, base, affix - base);
14036218822Sdim  if (opcode && cond)
1403789857Sobrien    {
14038218822Sdim      /* step CE */
14039218822Sdim      switch (opcode->tag)
1404089857Sobrien	{
14041218822Sdim	case OT_cinfix3_legacy:
14042218822Sdim	  /* Ignore conditional suffixes matched on infix only mnemonics.  */
14043218822Sdim	  break;
1404489857Sobrien
14045218822Sdim	case OT_cinfix3:
14046218822Sdim	case OT_cinfix3_deprecated:
14047218822Sdim	case OT_odd_infix_unc:
14048218822Sdim	  if (!unified_syntax)
14049218822Sdim	    return 0;
14050218822Sdim	  /* else fall through */
1405189857Sobrien
14052218822Sdim	case OT_csuffix:
14053218822Sdim        case OT_csuffixF:
14054218822Sdim	case OT_csuf_or_in3:
14055218822Sdim	  inst.cond = cond->value;
14056218822Sdim	  return opcode;
14057218822Sdim
14058218822Sdim	case OT_unconditional:
14059218822Sdim	case OT_unconditionalF:
14060218822Sdim	  if (thumb_mode)
14061218822Sdim	    {
14062218822Sdim	      inst.cond = cond->value;
14063218822Sdim	    }
14064218822Sdim	  else
14065218822Sdim	    {
14066218822Sdim	      /* delayed diagnostic */
14067218822Sdim	      inst.error = BAD_COND;
14068218822Sdim	      inst.cond = COND_ALWAYS;
14069218822Sdim	    }
14070218822Sdim	  return opcode;
14071218822Sdim
14072218822Sdim	default:
14073218822Sdim	  return 0;
14074218822Sdim	}
1407589857Sobrien    }
1407689857Sobrien
14077218822Sdim  /* Cannot have a usual-position infix on a mnemonic of less than
14078218822Sdim     six characters (five would be a suffix).  */
14079218822Sdim  if (end - base < 6)
14080218822Sdim    return 0;
1408189857Sobrien
14082218822Sdim  /* Look for infixed mnemonic in the usual position.  */
14083218822Sdim  affix = base + 3;
14084218822Sdim  cond = hash_find_n (arm_cond_hsh, affix, 2);
14085218822Sdim  if (!cond)
14086218822Sdim    return 0;
1408789857Sobrien
14088218822Sdim  memcpy (save, affix, 2);
14089218822Sdim  memmove (affix, affix + 2, (end - affix) - 2);
14090218822Sdim  opcode = hash_find_n (arm_ops_hsh, base, (end - base) - 2);
14091218822Sdim  memmove (affix + 2, affix, (end - affix) - 2);
14092218822Sdim  memcpy (affix, save, 2);
14093218822Sdim
14094218822Sdim  if (opcode
14095218822Sdim      && (opcode->tag == OT_cinfix3
14096218822Sdim	  || opcode->tag == OT_cinfix3_deprecated
14097218822Sdim	  || opcode->tag == OT_csuf_or_in3
14098218822Sdim	  || opcode->tag == OT_cinfix3_legacy))
14099218822Sdim    {
14100218822Sdim      /* step CM */
14101218822Sdim      if (unified_syntax
14102218822Sdim	  && (opcode->tag == OT_cinfix3
14103218822Sdim	      || opcode->tag == OT_cinfix3_deprecated))
14104218822Sdim	as_warn (_("conditional infixes are deprecated in unified syntax"));
14105218822Sdim
14106218822Sdim      inst.cond = cond->value;
14107218822Sdim      return opcode;
14108218822Sdim    }
14109218822Sdim
14110218822Sdim  return 0;
1411189857Sobrien}
1411289857Sobrien
14113218822Sdimvoid
14114218822Sdimmd_assemble (char *str)
1411560484Sobrien{
14116218822Sdim  char *p = str;
14117218822Sdim  const struct asm_opcode * opcode;
1411860484Sobrien
14119218822Sdim  /* Align the previous label if needed.  */
14120218822Sdim  if (last_label_seen != NULL)
14121218822Sdim    {
14122218822Sdim      symbol_set_frag (last_label_seen, frag_now);
14123218822Sdim      S_SET_VALUE (last_label_seen, (valueT) frag_now_fix ());
14124218822Sdim      S_SET_SEGMENT (last_label_seen, now_seg);
14125218822Sdim    }
1412677298Sobrien
14127218822Sdim  memset (&inst, '\0', sizeof (inst));
14128218822Sdim  inst.reloc.type = BFD_RELOC_UNUSED;
1412960484Sobrien
14130218822Sdim  opcode = opcode_lookup (&p);
14131218822Sdim  if (!opcode)
14132218822Sdim    {
14133218822Sdim      /* It wasn't an instruction, but it might be a register alias of
14134218822Sdim	 the form alias .req reg, or a Neon .dn/.qn directive.  */
14135218822Sdim      if (!create_register_alias (str, p)
14136218822Sdim          && !create_neon_reg_alias (str, p))
14137218822Sdim	as_bad (_("bad instruction `%s'"), str);
1413860484Sobrien
1413977298Sobrien      return;
1414060484Sobrien    }
1414160484Sobrien
14142218822Sdim  if (opcode->tag == OT_cinfix3_deprecated)
14143218822Sdim    as_warn (_("s suffix on comparison instruction is deprecated"));
14144218822Sdim
14145218822Sdim  /* The value which unconditional instructions should have in place of the
14146218822Sdim     condition field.  */
14147218822Sdim  inst.uncond_value = (opcode->tag == OT_csuffixF) ? 0xf : -1;
14148218822Sdim
14149218822Sdim  if (thumb_mode)
1415060484Sobrien    {
14151218822Sdim      arm_feature_set variant;
14152218822Sdim
14153218822Sdim      variant = cpu_variant;
14154218822Sdim      /* Only allow coprocessor instructions on Thumb-2 capable devices.  */
14155218822Sdim      if (!ARM_CPU_HAS_FEATURE (variant, arm_arch_t2))
14156218822Sdim	ARM_CLEAR_FEATURE (variant, variant, fpu_any_hard);
14157218822Sdim      /* Check that this instruction is supported for this CPU.  */
14158218822Sdim      if (!opcode->tvariant
14159218822Sdim	  || (thumb_mode == 1
14160218822Sdim	      && !ARM_CPU_HAS_FEATURE (variant, *opcode->tvariant)))
1416160484Sobrien	{
14162218822Sdim	  as_bad (_("selected processor does not support `%s'"), str);
1416360484Sobrien	  return;
1416460484Sobrien	}
14165218822Sdim      if (inst.cond != COND_ALWAYS && !unified_syntax
14166218822Sdim	  && opcode->tencode != do_t_branch)
14167218822Sdim	{
14168218822Sdim	  as_bad (_("Thumb does not support conditional execution"));
14169218822Sdim	  return;
14170218822Sdim	}
1417160484Sobrien
14172218822Sdim      if (!ARM_CPU_HAS_FEATURE (variant, arm_ext_v6t2) && !inst.size_req)
14173218822Sdim	{
14174218822Sdim	  /* Implicit require narrow instructions on Thumb-1.  This avoids
14175218822Sdim	     relaxation accidentally introducing Thumb-2 instructions.  */
14176218822Sdim	  if (opcode->tencode != do_t_blx && opcode->tencode != do_t_branch23)
14177218822Sdim	    inst.size_req = 2;
14178218822Sdim	}
1417960484Sobrien
14180218822Sdim      /* Check conditional suffixes.  */
14181218822Sdim      if (current_it_mask)
1418260484Sobrien	{
14183218822Sdim	  int cond;
14184218822Sdim	  cond = current_cc ^ ((current_it_mask >> 4) & 1) ^ 1;
14185218822Sdim	  current_it_mask <<= 1;
14186218822Sdim	  current_it_mask &= 0x1f;
14187218822Sdim	  /* The BKPT instruction is unconditional even in an IT block.  */
14188218822Sdim	  if (!inst.error
14189218822Sdim	      && cond != inst.cond && opcode->tencode != do_t_bkpt)
14190218822Sdim	    {
14191218822Sdim	      as_bad (_("incorrect condition in IT block"));
14192218822Sdim	      return;
14193218822Sdim	    }
14194218822Sdim	}
14195218822Sdim      else if (inst.cond != COND_ALWAYS && opcode->tencode != do_t_branch)
14196218822Sdim	{
14197218822Sdim	  as_bad (_("thumb conditional instrunction not in IT block"));
1419860484Sobrien	  return;
1419960484Sobrien	}
1420060484Sobrien
14201218822Sdim      mapping_state (MAP_THUMB);
14202218822Sdim      inst.instruction = opcode->tvalue;
1420360484Sobrien
14204218822Sdim      if (!parse_operands (p, opcode->operands))
14205218822Sdim	opcode->tencode ();
1420660484Sobrien
14207218822Sdim      /* Clear current_it_mask at the end of an IT block.  */
14208218822Sdim      if (current_it_mask == 0x10)
14209218822Sdim	current_it_mask = 0;
1421060484Sobrien
14211218822Sdim      if (!(inst.error || inst.relax))
14212218822Sdim	{
14213218822Sdim	  assert (inst.instruction < 0xe800 || inst.instruction > 0xffff);
14214218822Sdim	  inst.size = (inst.instruction > 0xffff ? 4 : 2);
14215218822Sdim	  if (inst.size_req && inst.size_req != inst.size)
14216218822Sdim	    {
14217218822Sdim	      as_bad (_("cannot honor width suffix -- `%s'"), str);
14218218822Sdim	      return;
14219218822Sdim	    }
14220218822Sdim	}
14221218822Sdim
14222218822Sdim      /* Something has gone badly wrong if we try to relax a fixed size
14223218822Sdim         instruction.  */
14224218822Sdim      assert (inst.size_req == 0 || !inst.relax);
14225218822Sdim
14226218822Sdim      ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
14227218822Sdim			      *opcode->tvariant);
14228218822Sdim      /* Many Thumb-2 instructions also have Thumb-1 variants, so explicitly
14229218822Sdim	 set those bits when Thumb-2 32-bit instructions are seen.  ie.
14230218822Sdim	 anything other than bl/blx.
14231218822Sdim	 This is overly pessimistic for relaxable instructions.  */
14232218822Sdim      if ((inst.size == 4 && (inst.instruction & 0xf800e800) != 0xf000e800)
14233218822Sdim	  || inst.relax)
14234218822Sdim	ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
14235218822Sdim				arm_ext_v6t2);
14236218822Sdim    }
14237218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1))
14238218822Sdim    {
14239218822Sdim      /* Check that this instruction is supported for this CPU.  */
14240218822Sdim      if (!opcode->avariant ||
14241218822Sdim	  !ARM_CPU_HAS_FEATURE (cpu_variant, *opcode->avariant))
14242218822Sdim	{
14243218822Sdim	  as_bad (_("selected processor does not support `%s'"), str);
14244218822Sdim	  return;
14245218822Sdim	}
14246218822Sdim      if (inst.size_req)
14247218822Sdim	{
14248218822Sdim	  as_bad (_("width suffixes are invalid in ARM mode -- `%s'"), str);
14249218822Sdim	  return;
14250218822Sdim	}
14251218822Sdim
14252218822Sdim      mapping_state (MAP_ARM);
14253218822Sdim      inst.instruction = opcode->avalue;
14254218822Sdim      if (opcode->tag == OT_unconditionalF)
14255218822Sdim	inst.instruction |= 0xF << 28;
14256218822Sdim      else
14257218822Sdim	inst.instruction |= inst.cond << 28;
14258218822Sdim      inst.size = INSN_SIZE;
14259218822Sdim      if (!parse_operands (p, opcode->operands))
14260218822Sdim	opcode->aencode ();
14261218822Sdim      /* Arm mode bx is marked as both v4T and v5 because it's still required
14262218822Sdim         on a hypothetical non-thumb v5 core.  */
14263218822Sdim      if (ARM_CPU_HAS_FEATURE (*opcode->avariant, arm_ext_v4t)
14264218822Sdim	  || ARM_CPU_HAS_FEATURE (*opcode->avariant, arm_ext_v5))
14265218822Sdim	ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used, arm_ext_v4t);
14266218822Sdim      else
14267218822Sdim	ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used,
14268218822Sdim				*opcode->avariant);
14269218822Sdim    }
14270218822Sdim  else
14271218822Sdim    {
14272218822Sdim      as_bad (_("attempt to use an ARM instruction on a Thumb-only processor "
14273218822Sdim		"-- `%s'"), str);
14274218822Sdim      return;
14275218822Sdim    }
14276218822Sdim  output_inst (str);
1427760484Sobrien}
1427860484Sobrien
14279218822Sdim/* Various frobbings of labels and their addresses.  */
14280218822Sdim
14281218822Sdimvoid
14282218822Sdimarm_start_line_hook (void)
1428360484Sobrien{
14284218822Sdim  last_label_seen = NULL;
1428560484Sobrien}
1428660484Sobrien
14287218822Sdimvoid
14288218822Sdimarm_frob_label (symbolS * sym)
1428960484Sobrien{
14290218822Sdim  last_label_seen = sym;
1429160484Sobrien
14292218822Sdim  ARM_SET_THUMB (sym, thumb_mode);
1429360484Sobrien
14294218822Sdim#if defined OBJ_COFF || defined OBJ_ELF
14295218822Sdim  ARM_SET_INTERWORK (sym, support_interwork);
14296218822Sdim#endif
1429760484Sobrien
14298218822Sdim  /* Note - do not allow local symbols (.Lxxx) to be labeled
14299218822Sdim     as Thumb functions.  This is because these labels, whilst
14300218822Sdim     they exist inside Thumb code, are not the entry points for
14301218822Sdim     possible ARM->Thumb calls.	 Also, these labels can be used
14302218822Sdim     as part of a computed goto or switch statement.  eg gcc
14303218822Sdim     can generate code that looks like this:
1430460484Sobrien
14305218822Sdim		ldr  r2, [pc, .Laaa]
14306218822Sdim		lsl  r3, r3, #2
14307218822Sdim		ldr  r2, [r3, r2]
14308218822Sdim		mov  pc, r2
1430960484Sobrien
14310218822Sdim       .Lbbb:  .word .Lxxx
14311218822Sdim       .Lccc:  .word .Lyyy
14312218822Sdim       ..etc...
14313218822Sdim       .Laaa:	.word Lbbb
1431477298Sobrien
14315218822Sdim     The first instruction loads the address of the jump table.
14316218822Sdim     The second instruction converts a table index into a byte offset.
14317218822Sdim     The third instruction gets the jump address out of the table.
14318218822Sdim     The fourth instruction performs the jump.
1431960484Sobrien
14320218822Sdim     If the address stored at .Laaa is that of a symbol which has the
14321218822Sdim     Thumb_Func bit set, then the linker will arrange for this address
14322218822Sdim     to have the bottom bit set, which in turn would mean that the
14323218822Sdim     address computation performed by the third instruction would end
14324218822Sdim     up with the bottom bit set.  Since the ARM is capable of unaligned
14325218822Sdim     word loads, the instruction would then load the incorrect address
14326218822Sdim     out of the jump table, and chaos would ensue.  */
14327218822Sdim  if (label_is_thumb_function_name
14328218822Sdim      && (S_GET_NAME (sym)[0] != '.' || S_GET_NAME (sym)[1] != 'L')
14329218822Sdim      && (bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0)
14330218822Sdim    {
14331218822Sdim      /* When the address of a Thumb function is taken the bottom
14332218822Sdim	 bit of that address should be set.  This will allow
14333218822Sdim	 interworking between Arm and Thumb functions to work
14334218822Sdim	 correctly.  */
1433577298Sobrien
14336218822Sdim      THUMB_SET_FUNC (sym, 1);
14337218822Sdim
14338218822Sdim      label_is_thumb_function_name = FALSE;
14339218822Sdim    }
14340218822Sdim
14341218822Sdim  dwarf2_emit_label (sym);
14342218822Sdim}
14343218822Sdim
14344218822Sdimint
14345218822Sdimarm_data_in_code (void)
14346218822Sdim{
14347218822Sdim  if (thumb_mode && ! strncmp (input_line_pointer + 1, "data:", 5))
1434860484Sobrien    {
14349218822Sdim      *input_line_pointer = '/';
14350218822Sdim      input_line_pointer += 5;
14351218822Sdim      *input_line_pointer = 0;
14352218822Sdim      return 1;
1435360484Sobrien    }
1435460484Sobrien
14355218822Sdim  return 0;
1435660484Sobrien}
1435760484Sobrien
14358218822Sdimchar *
14359218822Sdimarm_canonicalize_symbol_name (char * name)
1436060484Sobrien{
14361218822Sdim  int len;
1436277298Sobrien
14363218822Sdim  if (thumb_mode && (len = strlen (name)) > 5
14364218822Sdim      && streq (name + len - 5, "/data"))
14365218822Sdim    *(name + len - 5) = 0;
1436660484Sobrien
14367218822Sdim  return name;
1436860484Sobrien}
14369218822Sdim
14370218822Sdim/* Table of all register names defined by default.  The user can
14371218822Sdim   define additional names with .req.  Note that all register names
14372218822Sdim   should appear in both upper and lowercase variants.	Some registers
14373218822Sdim   also have mixed-case names.	*/
1437460484Sobrien
14375218822Sdim#define REGDEF(s,n,t) { #s, n, REG_TYPE_##t, TRUE, 0 }
14376218822Sdim#define REGNUM(p,n,t) REGDEF(p##n, n, t)
14377218822Sdim#define REGNUM2(p,n,t) REGDEF(p##n, 2 * n, t)
14378218822Sdim#define REGSET(p,t) \
14379218822Sdim  REGNUM(p, 0,t), REGNUM(p, 1,t), REGNUM(p, 2,t), REGNUM(p, 3,t), \
14380218822Sdim  REGNUM(p, 4,t), REGNUM(p, 5,t), REGNUM(p, 6,t), REGNUM(p, 7,t), \
14381218822Sdim  REGNUM(p, 8,t), REGNUM(p, 9,t), REGNUM(p,10,t), REGNUM(p,11,t), \
14382218822Sdim  REGNUM(p,12,t), REGNUM(p,13,t), REGNUM(p,14,t), REGNUM(p,15,t)
14383218822Sdim#define REGSETH(p,t) \
14384218822Sdim  REGNUM(p,16,t), REGNUM(p,17,t), REGNUM(p,18,t), REGNUM(p,19,t), \
14385218822Sdim  REGNUM(p,20,t), REGNUM(p,21,t), REGNUM(p,22,t), REGNUM(p,23,t), \
14386218822Sdim  REGNUM(p,24,t), REGNUM(p,25,t), REGNUM(p,26,t), REGNUM(p,27,t), \
14387218822Sdim  REGNUM(p,28,t), REGNUM(p,29,t), REGNUM(p,30,t), REGNUM(p,31,t)
14388218822Sdim#define REGSET2(p,t) \
14389218822Sdim  REGNUM2(p, 0,t), REGNUM2(p, 1,t), REGNUM2(p, 2,t), REGNUM2(p, 3,t), \
14390218822Sdim  REGNUM2(p, 4,t), REGNUM2(p, 5,t), REGNUM2(p, 6,t), REGNUM2(p, 7,t), \
14391218822Sdim  REGNUM2(p, 8,t), REGNUM2(p, 9,t), REGNUM2(p,10,t), REGNUM2(p,11,t), \
14392218822Sdim  REGNUM2(p,12,t), REGNUM2(p,13,t), REGNUM2(p,14,t), REGNUM2(p,15,t)
14393218822Sdim
14394218822Sdimstatic const struct reg_entry reg_names[] =
1439560484Sobrien{
14396218822Sdim  /* ARM integer registers.  */
14397218822Sdim  REGSET(r, RN), REGSET(R, RN),
1439860484Sobrien
14399218822Sdim  /* ATPCS synonyms.  */
14400218822Sdim  REGDEF(a1,0,RN), REGDEF(a2,1,RN), REGDEF(a3, 2,RN), REGDEF(a4, 3,RN),
14401218822Sdim  REGDEF(v1,4,RN), REGDEF(v2,5,RN), REGDEF(v3, 6,RN), REGDEF(v4, 7,RN),
14402218822Sdim  REGDEF(v5,8,RN), REGDEF(v6,9,RN), REGDEF(v7,10,RN), REGDEF(v8,11,RN),
1440360484Sobrien
14404218822Sdim  REGDEF(A1,0,RN), REGDEF(A2,1,RN), REGDEF(A3, 2,RN), REGDEF(A4, 3,RN),
14405218822Sdim  REGDEF(V1,4,RN), REGDEF(V2,5,RN), REGDEF(V3, 6,RN), REGDEF(V4, 7,RN),
14406218822Sdim  REGDEF(V5,8,RN), REGDEF(V6,9,RN), REGDEF(V7,10,RN), REGDEF(V8,11,RN),
1440760484Sobrien
14408218822Sdim  /* Well-known aliases.  */
14409218822Sdim  REGDEF(wr, 7,RN), REGDEF(sb, 9,RN), REGDEF(sl,10,RN), REGDEF(fp,11,RN),
14410218822Sdim  REGDEF(ip,12,RN), REGDEF(sp,13,RN), REGDEF(lr,14,RN), REGDEF(pc,15,RN),
1441160484Sobrien
14412218822Sdim  REGDEF(WR, 7,RN), REGDEF(SB, 9,RN), REGDEF(SL,10,RN), REGDEF(FP,11,RN),
14413218822Sdim  REGDEF(IP,12,RN), REGDEF(SP,13,RN), REGDEF(LR,14,RN), REGDEF(PC,15,RN),
1441460484Sobrien
14415218822Sdim  /* Coprocessor numbers.  */
14416218822Sdim  REGSET(p, CP), REGSET(P, CP),
1441760484Sobrien
14418218822Sdim  /* Coprocessor register numbers.  The "cr" variants are for backward
14419218822Sdim     compatibility.  */
14420218822Sdim  REGSET(c,  CN), REGSET(C, CN),
14421218822Sdim  REGSET(cr, CN), REGSET(CR, CN),
1442260484Sobrien
14423218822Sdim  /* FPA registers.  */
14424218822Sdim  REGNUM(f,0,FN), REGNUM(f,1,FN), REGNUM(f,2,FN), REGNUM(f,3,FN),
14425218822Sdim  REGNUM(f,4,FN), REGNUM(f,5,FN), REGNUM(f,6,FN), REGNUM(f,7, FN),
1442660484Sobrien
14427218822Sdim  REGNUM(F,0,FN), REGNUM(F,1,FN), REGNUM(F,2,FN), REGNUM(F,3,FN),
14428218822Sdim  REGNUM(F,4,FN), REGNUM(F,5,FN), REGNUM(F,6,FN), REGNUM(F,7, FN),
1442960484Sobrien
14430218822Sdim  /* VFP SP registers.	*/
14431218822Sdim  REGSET(s,VFS),  REGSET(S,VFS),
14432218822Sdim  REGSETH(s,VFS), REGSETH(S,VFS),
1443360484Sobrien
14434218822Sdim  /* VFP DP Registers.	*/
14435218822Sdim  REGSET(d,VFD),  REGSET(D,VFD),
14436218822Sdim  /* Extra Neon DP registers.  */
14437218822Sdim  REGSETH(d,VFD), REGSETH(D,VFD),
1443860484Sobrien
14439218822Sdim  /* Neon QP registers.  */
14440218822Sdim  REGSET2(q,NQ),  REGSET2(Q,NQ),
1444160484Sobrien
14442218822Sdim  /* VFP control registers.  */
14443218822Sdim  REGDEF(fpsid,0,VFC), REGDEF(fpscr,1,VFC), REGDEF(fpexc,8,VFC),
14444218822Sdim  REGDEF(FPSID,0,VFC), REGDEF(FPSCR,1,VFC), REGDEF(FPEXC,8,VFC),
14445218822Sdim  REGDEF(fpinst,9,VFC), REGDEF(fpinst2,10,VFC),
14446218822Sdim  REGDEF(FPINST,9,VFC), REGDEF(FPINST2,10,VFC),
14447218822Sdim  REGDEF(mvfr0,7,VFC), REGDEF(mvfr1,6,VFC),
14448218822Sdim  REGDEF(MVFR0,7,VFC), REGDEF(MVFR1,6,VFC),
1444960484Sobrien
14450218822Sdim  /* Maverick DSP coprocessor registers.  */
14451218822Sdim  REGSET(mvf,MVF),  REGSET(mvd,MVD),  REGSET(mvfx,MVFX),  REGSET(mvdx,MVDX),
14452218822Sdim  REGSET(MVF,MVF),  REGSET(MVD,MVD),  REGSET(MVFX,MVFX),  REGSET(MVDX,MVDX),
1445360484Sobrien
14454218822Sdim  REGNUM(mvax,0,MVAX), REGNUM(mvax,1,MVAX),
14455218822Sdim  REGNUM(mvax,2,MVAX), REGNUM(mvax,3,MVAX),
14456218822Sdim  REGDEF(dspsc,0,DSPSC),
1445760484Sobrien
14458218822Sdim  REGNUM(MVAX,0,MVAX), REGNUM(MVAX,1,MVAX),
14459218822Sdim  REGNUM(MVAX,2,MVAX), REGNUM(MVAX,3,MVAX),
14460218822Sdim  REGDEF(DSPSC,0,DSPSC),
1446160484Sobrien
14462218822Sdim  /* iWMMXt data registers - p0, c0-15.	 */
14463218822Sdim  REGSET(wr,MMXWR), REGSET(wR,MMXWR), REGSET(WR, MMXWR),
1446460484Sobrien
14465218822Sdim  /* iWMMXt control registers - p1, c0-3.  */
14466218822Sdim  REGDEF(wcid,	0,MMXWC),  REGDEF(wCID,	 0,MMXWC),  REGDEF(WCID,  0,MMXWC),
14467218822Sdim  REGDEF(wcon,	1,MMXWC),  REGDEF(wCon,	 1,MMXWC),  REGDEF(WCON,  1,MMXWC),
14468218822Sdim  REGDEF(wcssf, 2,MMXWC),  REGDEF(wCSSF, 2,MMXWC),  REGDEF(WCSSF, 2,MMXWC),
14469218822Sdim  REGDEF(wcasf, 3,MMXWC),  REGDEF(wCASF, 3,MMXWC),  REGDEF(WCASF, 3,MMXWC),
1447060484Sobrien
14471218822Sdim  /* iWMMXt scalar (constant/offset) registers - p1, c8-11.  */
14472218822Sdim  REGDEF(wcgr0, 8,MMXWCG),  REGDEF(wCGR0, 8,MMXWCG),  REGDEF(WCGR0, 8,MMXWCG),
14473218822Sdim  REGDEF(wcgr1, 9,MMXWCG),  REGDEF(wCGR1, 9,MMXWCG),  REGDEF(WCGR1, 9,MMXWCG),
14474218822Sdim  REGDEF(wcgr2,10,MMXWCG),  REGDEF(wCGR2,10,MMXWCG),  REGDEF(WCGR2,10,MMXWCG),
14475218822Sdim  REGDEF(wcgr3,11,MMXWCG),  REGDEF(wCGR3,11,MMXWCG),  REGDEF(WCGR3,11,MMXWCG),
1447660484Sobrien
14477218822Sdim  /* XScale accumulator registers.  */
14478218822Sdim  REGNUM(acc,0,XSCALE), REGNUM(ACC,0,XSCALE),
14479218822Sdim};
14480218822Sdim#undef REGDEF
14481218822Sdim#undef REGNUM
14482218822Sdim#undef REGSET
1448360484Sobrien
14484218822Sdim/* Table of all PSR suffixes.  Bare "CPSR" and "SPSR" are handled
14485218822Sdim   within psr_required_here.  */
14486218822Sdimstatic const struct asm_psr psrs[] =
14487218822Sdim{
14488218822Sdim  /* Backward compatibility notation.  Note that "all" is no longer
14489218822Sdim     truly all possible PSR bits.  */
14490218822Sdim  {"all",  PSR_c | PSR_f},
14491218822Sdim  {"flg",  PSR_f},
14492218822Sdim  {"ctl",  PSR_c},
1449360484Sobrien
14494218822Sdim  /* Individual flags.	*/
14495218822Sdim  {"f",	   PSR_f},
14496218822Sdim  {"c",	   PSR_c},
14497218822Sdim  {"x",	   PSR_x},
14498218822Sdim  {"s",	   PSR_s},
14499218822Sdim  /* Combinations of flags.  */
14500218822Sdim  {"fs",   PSR_f | PSR_s},
14501218822Sdim  {"fx",   PSR_f | PSR_x},
14502218822Sdim  {"fc",   PSR_f | PSR_c},
14503218822Sdim  {"sf",   PSR_s | PSR_f},
14504218822Sdim  {"sx",   PSR_s | PSR_x},
14505218822Sdim  {"sc",   PSR_s | PSR_c},
14506218822Sdim  {"xf",   PSR_x | PSR_f},
14507218822Sdim  {"xs",   PSR_x | PSR_s},
14508218822Sdim  {"xc",   PSR_x | PSR_c},
14509218822Sdim  {"cf",   PSR_c | PSR_f},
14510218822Sdim  {"cs",   PSR_c | PSR_s},
14511218822Sdim  {"cx",   PSR_c | PSR_x},
14512218822Sdim  {"fsx",  PSR_f | PSR_s | PSR_x},
14513218822Sdim  {"fsc",  PSR_f | PSR_s | PSR_c},
14514218822Sdim  {"fxs",  PSR_f | PSR_x | PSR_s},
14515218822Sdim  {"fxc",  PSR_f | PSR_x | PSR_c},
14516218822Sdim  {"fcs",  PSR_f | PSR_c | PSR_s},
14517218822Sdim  {"fcx",  PSR_f | PSR_c | PSR_x},
14518218822Sdim  {"sfx",  PSR_s | PSR_f | PSR_x},
14519218822Sdim  {"sfc",  PSR_s | PSR_f | PSR_c},
14520218822Sdim  {"sxf",  PSR_s | PSR_x | PSR_f},
14521218822Sdim  {"sxc",  PSR_s | PSR_x | PSR_c},
14522218822Sdim  {"scf",  PSR_s | PSR_c | PSR_f},
14523218822Sdim  {"scx",  PSR_s | PSR_c | PSR_x},
14524218822Sdim  {"xfs",  PSR_x | PSR_f | PSR_s},
14525218822Sdim  {"xfc",  PSR_x | PSR_f | PSR_c},
14526218822Sdim  {"xsf",  PSR_x | PSR_s | PSR_f},
14527218822Sdim  {"xsc",  PSR_x | PSR_s | PSR_c},
14528218822Sdim  {"xcf",  PSR_x | PSR_c | PSR_f},
14529218822Sdim  {"xcs",  PSR_x | PSR_c | PSR_s},
14530218822Sdim  {"cfs",  PSR_c | PSR_f | PSR_s},
14531218822Sdim  {"cfx",  PSR_c | PSR_f | PSR_x},
14532218822Sdim  {"csf",  PSR_c | PSR_s | PSR_f},
14533218822Sdim  {"csx",  PSR_c | PSR_s | PSR_x},
14534218822Sdim  {"cxf",  PSR_c | PSR_x | PSR_f},
14535218822Sdim  {"cxs",  PSR_c | PSR_x | PSR_s},
14536218822Sdim  {"fsxc", PSR_f | PSR_s | PSR_x | PSR_c},
14537218822Sdim  {"fscx", PSR_f | PSR_s | PSR_c | PSR_x},
14538218822Sdim  {"fxsc", PSR_f | PSR_x | PSR_s | PSR_c},
14539218822Sdim  {"fxcs", PSR_f | PSR_x | PSR_c | PSR_s},
14540218822Sdim  {"fcsx", PSR_f | PSR_c | PSR_s | PSR_x},
14541218822Sdim  {"fcxs", PSR_f | PSR_c | PSR_x | PSR_s},
14542218822Sdim  {"sfxc", PSR_s | PSR_f | PSR_x | PSR_c},
14543218822Sdim  {"sfcx", PSR_s | PSR_f | PSR_c | PSR_x},
14544218822Sdim  {"sxfc", PSR_s | PSR_x | PSR_f | PSR_c},
14545218822Sdim  {"sxcf", PSR_s | PSR_x | PSR_c | PSR_f},
14546218822Sdim  {"scfx", PSR_s | PSR_c | PSR_f | PSR_x},
14547218822Sdim  {"scxf", PSR_s | PSR_c | PSR_x | PSR_f},
14548218822Sdim  {"xfsc", PSR_x | PSR_f | PSR_s | PSR_c},
14549218822Sdim  {"xfcs", PSR_x | PSR_f | PSR_c | PSR_s},
14550218822Sdim  {"xsfc", PSR_x | PSR_s | PSR_f | PSR_c},
14551218822Sdim  {"xscf", PSR_x | PSR_s | PSR_c | PSR_f},
14552218822Sdim  {"xcfs", PSR_x | PSR_c | PSR_f | PSR_s},
14553218822Sdim  {"xcsf", PSR_x | PSR_c | PSR_s | PSR_f},
14554218822Sdim  {"cfsx", PSR_c | PSR_f | PSR_s | PSR_x},
14555218822Sdim  {"cfxs", PSR_c | PSR_f | PSR_x | PSR_s},
14556218822Sdim  {"csfx", PSR_c | PSR_s | PSR_f | PSR_x},
14557218822Sdim  {"csxf", PSR_c | PSR_s | PSR_x | PSR_f},
14558218822Sdim  {"cxfs", PSR_c | PSR_x | PSR_f | PSR_s},
14559218822Sdim  {"cxsf", PSR_c | PSR_x | PSR_s | PSR_f},
14560218822Sdim};
1456160484Sobrien
14562218822Sdim/* Table of V7M psr names.  */
14563218822Sdimstatic const struct asm_psr v7m_psrs[] =
1456460484Sobrien{
14565218822Sdim  {"apsr",	  0 }, {"APSR",		0 },
14566218822Sdim  {"iapsr",	  1 }, {"IAPSR",	1 },
14567218822Sdim  {"eapsr",	  2 }, {"EAPSR",	2 },
14568218822Sdim  {"psr",	  3 }, {"PSR",		3 },
14569218822Sdim  {"xpsr",	  3 }, {"XPSR",		3 }, {"xPSR",	  3 },
14570218822Sdim  {"ipsr",	  5 }, {"IPSR",		5 },
14571218822Sdim  {"epsr",	  6 }, {"EPSR",		6 },
14572218822Sdim  {"iepsr",	  7 }, {"IEPSR",	7 },
14573218822Sdim  {"msp",	  8 }, {"MSP",		8 },
14574218822Sdim  {"psp",	  9 }, {"PSP",		9 },
14575218822Sdim  {"primask",	  16}, {"PRIMASK",	16},
14576218822Sdim  {"basepri",	  17}, {"BASEPRI",	17},
14577218822Sdim  {"basepri_max", 18}, {"BASEPRI_MAX",	18},
14578218822Sdim  {"faultmask",	  19}, {"FAULTMASK",	19},
14579218822Sdim  {"control",	  20}, {"CONTROL",	20}
14580218822Sdim};
1458160484Sobrien
14582218822Sdim/* Table of all shift-in-operand names.	 */
14583218822Sdimstatic const struct asm_shift_name shift_names [] =
1458460484Sobrien{
14585218822Sdim  { "asl", SHIFT_LSL },	 { "ASL", SHIFT_LSL },
14586218822Sdim  { "lsl", SHIFT_LSL },	 { "LSL", SHIFT_LSL },
14587218822Sdim  { "lsr", SHIFT_LSR },	 { "LSR", SHIFT_LSR },
14588218822Sdim  { "asr", SHIFT_ASR },	 { "ASR", SHIFT_ASR },
14589218822Sdim  { "ror", SHIFT_ROR },	 { "ROR", SHIFT_ROR },
14590218822Sdim  { "rrx", SHIFT_RRX },	 { "RRX", SHIFT_RRX }
14591218822Sdim};
1459260484Sobrien
14593218822Sdim/* Table of all explicit relocation names.  */
14594218822Sdim#ifdef OBJ_ELF
14595218822Sdimstatic struct reloc_entry reloc_names[] =
1459660484Sobrien{
14597218822Sdim  { "got",     BFD_RELOC_ARM_GOT32   },	 { "GOT",     BFD_RELOC_ARM_GOT32   },
14598218822Sdim  { "gotoff",  BFD_RELOC_ARM_GOTOFF  },	 { "GOTOFF",  BFD_RELOC_ARM_GOTOFF  },
14599218822Sdim  { "plt",     BFD_RELOC_ARM_PLT32   },	 { "PLT",     BFD_RELOC_ARM_PLT32   },
14600218822Sdim  { "target1", BFD_RELOC_ARM_TARGET1 },	 { "TARGET1", BFD_RELOC_ARM_TARGET1 },
14601218822Sdim  { "target2", BFD_RELOC_ARM_TARGET2 },	 { "TARGET2", BFD_RELOC_ARM_TARGET2 },
14602218822Sdim  { "sbrel",   BFD_RELOC_ARM_SBREL32 },	 { "SBREL",   BFD_RELOC_ARM_SBREL32 },
14603218822Sdim  { "tlsgd",   BFD_RELOC_ARM_TLS_GD32},  { "TLSGD",   BFD_RELOC_ARM_TLS_GD32},
14604218822Sdim  { "tlsldm",  BFD_RELOC_ARM_TLS_LDM32}, { "TLSLDM",  BFD_RELOC_ARM_TLS_LDM32},
14605218822Sdim  { "tlsldo",  BFD_RELOC_ARM_TLS_LDO32}, { "TLSLDO",  BFD_RELOC_ARM_TLS_LDO32},
14606218822Sdim  { "gottpoff",BFD_RELOC_ARM_TLS_IE32},  { "GOTTPOFF",BFD_RELOC_ARM_TLS_IE32},
14607218822Sdim  { "tpoff",   BFD_RELOC_ARM_TLS_LE32},  { "TPOFF",   BFD_RELOC_ARM_TLS_LE32}
14608218822Sdim};
14609218822Sdim#endif
1461060484Sobrien
14611218822Sdim/* Table of all conditional affixes.  0xF is not defined as a condition code.  */
14612218822Sdimstatic const struct asm_cond conds[] =
1461360484Sobrien{
14614218822Sdim  {"eq", 0x0},
14615218822Sdim  {"ne", 0x1},
14616218822Sdim  {"cs", 0x2}, {"hs", 0x2},
14617218822Sdim  {"cc", 0x3}, {"ul", 0x3}, {"lo", 0x3},
14618218822Sdim  {"mi", 0x4},
14619218822Sdim  {"pl", 0x5},
14620218822Sdim  {"vs", 0x6},
14621218822Sdim  {"vc", 0x7},
14622218822Sdim  {"hi", 0x8},
14623218822Sdim  {"ls", 0x9},
14624218822Sdim  {"ge", 0xa},
14625218822Sdim  {"lt", 0xb},
14626218822Sdim  {"gt", 0xc},
14627218822Sdim  {"le", 0xd},
14628218822Sdim  {"al", 0xe}
14629218822Sdim};
1463060484Sobrien
14631218822Sdimstatic struct asm_barrier_opt barrier_opt_names[] =
14632218822Sdim{
14633218822Sdim  { "sy",   0xf },
14634218822Sdim  { "un",   0x7 },
14635218822Sdim  { "st",   0xe },
14636218822Sdim  { "unst", 0x6 }
14637218822Sdim};
1463860484Sobrien
14639218822Sdim/* Table of ARM-format instructions.	*/
1464060484Sobrien
14641218822Sdim/* Macros for gluing together operand strings.  N.B. In all cases
14642218822Sdim   other than OPS0, the trailing OP_stop comes from default
14643218822Sdim   zero-initialization of the unspecified elements of the array.  */
14644218822Sdim#define OPS0()		  { OP_stop, }
14645218822Sdim#define OPS1(a)		  { OP_##a, }
14646218822Sdim#define OPS2(a,b)	  { OP_##a,OP_##b, }
14647218822Sdim#define OPS3(a,b,c)	  { OP_##a,OP_##b,OP_##c, }
14648218822Sdim#define OPS4(a,b,c,d)	  { OP_##a,OP_##b,OP_##c,OP_##d, }
14649218822Sdim#define OPS5(a,b,c,d,e)	  { OP_##a,OP_##b,OP_##c,OP_##d,OP_##e, }
14650218822Sdim#define OPS6(a,b,c,d,e,f) { OP_##a,OP_##b,OP_##c,OP_##d,OP_##e,OP_##f, }
1465160484Sobrien
14652218822Sdim/* These macros abstract out the exact format of the mnemonic table and
14653218822Sdim   save some repeated characters.  */
1465460484Sobrien
14655218822Sdim/* The normal sort of mnemonic; has a Thumb variant; takes a conditional suffix.  */
14656218822Sdim#define TxCE(mnem, op, top, nops, ops, ae, te) \
14657218822Sdim  { #mnem, OPS##nops ops, OT_csuffix, 0x##op, top, ARM_VARIANT, \
14658218822Sdim    THUMB_VARIANT, do_##ae, do_##te }
1465960484Sobrien
14660218822Sdim/* Two variants of the above - TCE for a numeric Thumb opcode, tCE for
14661218822Sdim   a T_MNEM_xyz enumerator.  */
14662218822Sdim#define TCE(mnem, aop, top, nops, ops, ae, te) \
14663218822Sdim       TxCE(mnem, aop, 0x##top, nops, ops, ae, te)
14664218822Sdim#define tCE(mnem, aop, top, nops, ops, ae, te) \
14665218822Sdim       TxCE(mnem, aop, T_MNEM_##top, nops, ops, ae, te)
1466660484Sobrien
14667218822Sdim/* Second most common sort of mnemonic: has a Thumb variant, takes a conditional
14668218822Sdim   infix after the third character.  */
14669218822Sdim#define TxC3(mnem, op, top, nops, ops, ae, te) \
14670218822Sdim  { #mnem, OPS##nops ops, OT_cinfix3, 0x##op, top, ARM_VARIANT, \
14671218822Sdim    THUMB_VARIANT, do_##ae, do_##te }
14672218822Sdim#define TxC3w(mnem, op, top, nops, ops, ae, te) \
14673218822Sdim  { #mnem, OPS##nops ops, OT_cinfix3_deprecated, 0x##op, top, ARM_VARIANT, \
14674218822Sdim    THUMB_VARIANT, do_##ae, do_##te }
14675218822Sdim#define TC3(mnem, aop, top, nops, ops, ae, te) \
14676218822Sdim       TxC3(mnem, aop, 0x##top, nops, ops, ae, te)
14677218822Sdim#define TC3w(mnem, aop, top, nops, ops, ae, te) \
14678218822Sdim       TxC3w(mnem, aop, 0x##top, nops, ops, ae, te)
14679218822Sdim#define tC3(mnem, aop, top, nops, ops, ae, te) \
14680218822Sdim       TxC3(mnem, aop, T_MNEM_##top, nops, ops, ae, te)
14681218822Sdim#define tC3w(mnem, aop, top, nops, ops, ae, te) \
14682218822Sdim       TxC3w(mnem, aop, T_MNEM_##top, nops, ops, ae, te)
1468360484Sobrien
14684218822Sdim/* Mnemonic with a conditional infix in an unusual place.  Each and every variant has to
14685218822Sdim   appear in the condition table.  */
14686218822Sdim#define TxCM_(m1, m2, m3, op, top, nops, ops, ae, te)	\
14687218822Sdim  { #m1 #m2 #m3, OPS##nops ops, sizeof(#m2) == 1 ? OT_odd_infix_unc : OT_odd_infix_0 + sizeof(#m1) - 1, \
14688218822Sdim    0x##op, top, ARM_VARIANT, THUMB_VARIANT, do_##ae, do_##te }
1468960484Sobrien
14690218822Sdim#define TxCM(m1, m2, op, top, nops, ops, ae, te)	\
14691218822Sdim  TxCM_(m1,   , m2, op, top, nops, ops, ae, te),	\
14692218822Sdim  TxCM_(m1, eq, m2, op, top, nops, ops, ae, te),	\
14693218822Sdim  TxCM_(m1, ne, m2, op, top, nops, ops, ae, te),	\
14694218822Sdim  TxCM_(m1, cs, m2, op, top, nops, ops, ae, te),	\
14695218822Sdim  TxCM_(m1, hs, m2, op, top, nops, ops, ae, te),	\
14696218822Sdim  TxCM_(m1, cc, m2, op, top, nops, ops, ae, te),	\
14697218822Sdim  TxCM_(m1, ul, m2, op, top, nops, ops, ae, te),	\
14698218822Sdim  TxCM_(m1, lo, m2, op, top, nops, ops, ae, te),	\
14699218822Sdim  TxCM_(m1, mi, m2, op, top, nops, ops, ae, te),	\
14700218822Sdim  TxCM_(m1, pl, m2, op, top, nops, ops, ae, te),	\
14701218822Sdim  TxCM_(m1, vs, m2, op, top, nops, ops, ae, te),	\
14702218822Sdim  TxCM_(m1, vc, m2, op, top, nops, ops, ae, te),	\
14703218822Sdim  TxCM_(m1, hi, m2, op, top, nops, ops, ae, te),	\
14704218822Sdim  TxCM_(m1, ls, m2, op, top, nops, ops, ae, te),	\
14705218822Sdim  TxCM_(m1, ge, m2, op, top, nops, ops, ae, te),	\
14706218822Sdim  TxCM_(m1, lt, m2, op, top, nops, ops, ae, te),	\
14707218822Sdim  TxCM_(m1, gt, m2, op, top, nops, ops, ae, te),	\
14708218822Sdim  TxCM_(m1, le, m2, op, top, nops, ops, ae, te),	\
14709218822Sdim  TxCM_(m1, al, m2, op, top, nops, ops, ae, te)
1471060484Sobrien
14711218822Sdim#define TCM(m1,m2, aop, top, nops, ops, ae, te)		\
14712218822Sdim       TxCM(m1,m2, aop, 0x##top, nops, ops, ae, te)
14713218822Sdim#define tCM(m1,m2, aop, top, nops, ops, ae, te)			\
14714218822Sdim       TxCM(m1,m2, aop, T_MNEM_##top, nops, ops, ae, te)
1471560484Sobrien
14716218822Sdim/* Mnemonic that cannot be conditionalized.  The ARM condition-code
14717218822Sdim   field is still 0xE.  Many of the Thumb variants can be executed
14718218822Sdim   conditionally, so this is checked separately.  */
14719218822Sdim#define TUE(mnem, op, top, nops, ops, ae, te)				\
14720218822Sdim  { #mnem, OPS##nops ops, OT_unconditional, 0x##op, 0x##top, ARM_VARIANT, \
14721218822Sdim    THUMB_VARIANT, do_##ae, do_##te }
1472260484Sobrien
14723218822Sdim/* Mnemonic that cannot be conditionalized, and bears 0xF in its ARM
14724218822Sdim   condition code field.  */
14725218822Sdim#define TUF(mnem, op, top, nops, ops, ae, te)				\
14726218822Sdim  { #mnem, OPS##nops ops, OT_unconditionalF, 0x##op, 0x##top, ARM_VARIANT, \
14727218822Sdim    THUMB_VARIANT, do_##ae, do_##te }
1472860484Sobrien
14729218822Sdim/* ARM-only variants of all the above.  */
14730218822Sdim#define CE(mnem,  op, nops, ops, ae)	\
14731218822Sdim  { #mnem, OPS##nops ops, OT_csuffix, 0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
1473260484Sobrien
14733218822Sdim#define C3(mnem, op, nops, ops, ae)	\
14734218822Sdim  { #mnem, OPS##nops ops, OT_cinfix3, 0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
1473560484Sobrien
14736218822Sdim/* Legacy mnemonics that always have conditional infix after the third
14737218822Sdim   character.  */
14738218822Sdim#define CL(mnem, op, nops, ops, ae)	\
14739218822Sdim  { #mnem, OPS##nops ops, OT_cinfix3_legacy, \
14740218822Sdim    0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
1474160484Sobrien
14742218822Sdim/* Coprocessor instructions.  Isomorphic between Arm and Thumb-2.  */
14743218822Sdim#define cCE(mnem,  op, nops, ops, ae)	\
14744218822Sdim  { #mnem, OPS##nops ops, OT_csuffix, 0x##op, 0xe##op, ARM_VARIANT, ARM_VARIANT, do_##ae, do_##ae }
1474577298Sobrien
14746218822Sdim/* Legacy coprocessor instructions where conditional infix and conditional
14747218822Sdim   suffix are ambiguous.  For consistency this includes all FPA instructions,
14748218822Sdim   not just the potentially ambiguous ones.  */
14749218822Sdim#define cCL(mnem, op, nops, ops, ae)	\
14750218822Sdim  { #mnem, OPS##nops ops, OT_cinfix3_legacy, \
14751218822Sdim    0x##op, 0xe##op, ARM_VARIANT, ARM_VARIANT, do_##ae, do_##ae }
1475260484Sobrien
14753218822Sdim/* Coprocessor, takes either a suffix or a position-3 infix
14754218822Sdim   (for an FPA corner case). */
14755218822Sdim#define C3E(mnem, op, nops, ops, ae) \
14756218822Sdim  { #mnem, OPS##nops ops, OT_csuf_or_in3, \
14757218822Sdim    0x##op, 0xe##op, ARM_VARIANT, ARM_VARIANT, do_##ae, do_##ae }
1475860484Sobrien
14759218822Sdim#define xCM_(m1, m2, m3, op, nops, ops, ae)	\
14760218822Sdim  { #m1 #m2 #m3, OPS##nops ops, \
14761218822Sdim    sizeof(#m2) == 1 ? OT_odd_infix_unc : OT_odd_infix_0 + sizeof(#m1) - 1, \
14762218822Sdim    0x##op, 0x0, ARM_VARIANT, 0, do_##ae, NULL }
1476360484Sobrien
14764218822Sdim#define CM(m1, m2, op, nops, ops, ae)	\
14765218822Sdim  xCM_(m1,   , m2, op, nops, ops, ae),	\
14766218822Sdim  xCM_(m1, eq, m2, op, nops, ops, ae),	\
14767218822Sdim  xCM_(m1, ne, m2, op, nops, ops, ae),	\
14768218822Sdim  xCM_(m1, cs, m2, op, nops, ops, ae),	\
14769218822Sdim  xCM_(m1, hs, m2, op, nops, ops, ae),	\
14770218822Sdim  xCM_(m1, cc, m2, op, nops, ops, ae),	\
14771218822Sdim  xCM_(m1, ul, m2, op, nops, ops, ae),	\
14772218822Sdim  xCM_(m1, lo, m2, op, nops, ops, ae),	\
14773218822Sdim  xCM_(m1, mi, m2, op, nops, ops, ae),	\
14774218822Sdim  xCM_(m1, pl, m2, op, nops, ops, ae),	\
14775218822Sdim  xCM_(m1, vs, m2, op, nops, ops, ae),	\
14776218822Sdim  xCM_(m1, vc, m2, op, nops, ops, ae),	\
14777218822Sdim  xCM_(m1, hi, m2, op, nops, ops, ae),	\
14778218822Sdim  xCM_(m1, ls, m2, op, nops, ops, ae),	\
14779218822Sdim  xCM_(m1, ge, m2, op, nops, ops, ae),	\
14780218822Sdim  xCM_(m1, lt, m2, op, nops, ops, ae),	\
14781218822Sdim  xCM_(m1, gt, m2, op, nops, ops, ae),	\
14782218822Sdim  xCM_(m1, le, m2, op, nops, ops, ae),	\
14783218822Sdim  xCM_(m1, al, m2, op, nops, ops, ae)
1478460484Sobrien
14785218822Sdim#define UE(mnem, op, nops, ops, ae)	\
14786218822Sdim  { #mnem, OPS##nops ops, OT_unconditional, 0x##op, 0, ARM_VARIANT, 0, do_##ae, NULL }
1478760484Sobrien
14788218822Sdim#define UF(mnem, op, nops, ops, ae)	\
14789218822Sdim  { #mnem, OPS##nops ops, OT_unconditionalF, 0x##op, 0, ARM_VARIANT, 0, do_##ae, NULL }
1479060484Sobrien
14791218822Sdim/* Neon data-processing. ARM versions are unconditional with cond=0xf.
14792218822Sdim   The Thumb and ARM variants are mostly the same (bits 0-23 and 24/28), so we
14793218822Sdim   use the same encoding function for each.  */
14794218822Sdim#define NUF(mnem, op, nops, ops, enc)					\
14795218822Sdim  { #mnem, OPS##nops ops, OT_unconditionalF, 0x##op, 0x##op,		\
14796218822Sdim    ARM_VARIANT, THUMB_VARIANT, do_##enc, do_##enc }
1479760484Sobrien
14798218822Sdim/* Neon data processing, version which indirects through neon_enc_tab for
14799218822Sdim   the various overloaded versions of opcodes.  */
14800218822Sdim#define nUF(mnem, op, nops, ops, enc)					\
14801218822Sdim  { #mnem, OPS##nops ops, OT_unconditionalF, N_MNEM_##op, N_MNEM_##op,	\
14802218822Sdim    ARM_VARIANT, THUMB_VARIANT, do_##enc, do_##enc }
14803218822Sdim
14804218822Sdim/* Neon insn with conditional suffix for the ARM version, non-overloaded
14805218822Sdim   version.  */
14806218822Sdim#define NCE_tag(mnem, op, nops, ops, enc, tag)				\
14807218822Sdim  { #mnem, OPS##nops ops, tag, 0x##op, 0x##op, ARM_VARIANT,		\
14808218822Sdim    THUMB_VARIANT, do_##enc, do_##enc }
14809218822Sdim
14810218822Sdim#define NCE(mnem, op, nops, ops, enc)					\
14811218822Sdim  NCE_tag(mnem, op, nops, ops, enc, OT_csuffix)
14812218822Sdim
14813218822Sdim#define NCEF(mnem, op, nops, ops, enc)					\
14814218822Sdim  NCE_tag(mnem, op, nops, ops, enc, OT_csuffixF)
14815218822Sdim
14816218822Sdim/* Neon insn with conditional suffix for the ARM version, overloaded types.  */
14817218822Sdim#define nCE_tag(mnem, op, nops, ops, enc, tag)				\
14818218822Sdim  { #mnem, OPS##nops ops, tag, N_MNEM_##op, N_MNEM_##op,		\
14819218822Sdim    ARM_VARIANT, THUMB_VARIANT, do_##enc, do_##enc }
14820218822Sdim
14821218822Sdim#define nCE(mnem, op, nops, ops, enc)					\
14822218822Sdim  nCE_tag(mnem, op, nops, ops, enc, OT_csuffix)
14823218822Sdim
14824218822Sdim#define nCEF(mnem, op, nops, ops, enc)					\
14825218822Sdim  nCE_tag(mnem, op, nops, ops, enc, OT_csuffixF)
14826218822Sdim
14827218822Sdim#define do_0 0
14828218822Sdim
14829218822Sdim/* Thumb-only, unconditional.  */
14830218822Sdim#define UT(mnem,  op, nops, ops, te) TUE(mnem,  0, op, nops, ops, 0, te)
14831218822Sdim
14832218822Sdimstatic const struct asm_opcode insns[] =
1483389857Sobrien{
14834218822Sdim#define ARM_VARIANT &arm_ext_v1 /* Core ARM Instructions.  */
14835218822Sdim#define THUMB_VARIANT &arm_ext_v4t
14836218822Sdim tCE(and,	0000000, and,      3, (RR, oRR, SH), arit, t_arit3c),
14837218822Sdim tC3(ands,	0100000, ands,	   3, (RR, oRR, SH), arit, t_arit3c),
14838218822Sdim tCE(eor,	0200000, eor,	   3, (RR, oRR, SH), arit, t_arit3c),
14839218822Sdim tC3(eors,	0300000, eors,	   3, (RR, oRR, SH), arit, t_arit3c),
14840218822Sdim tCE(sub,	0400000, sub,	   3, (RR, oRR, SH), arit, t_add_sub),
14841218822Sdim tC3(subs,	0500000, subs,	   3, (RR, oRR, SH), arit, t_add_sub),
14842218822Sdim tCE(add,	0800000, add,	   3, (RR, oRR, SHG), arit, t_add_sub),
14843218822Sdim tC3(adds,	0900000, adds,	   3, (RR, oRR, SHG), arit, t_add_sub),
14844218822Sdim tCE(adc,	0a00000, adc,	   3, (RR, oRR, SH), arit, t_arit3c),
14845218822Sdim tC3(adcs,	0b00000, adcs,	   3, (RR, oRR, SH), arit, t_arit3c),
14846218822Sdim tCE(sbc,	0c00000, sbc,	   3, (RR, oRR, SH), arit, t_arit3),
14847218822Sdim tC3(sbcs,	0d00000, sbcs,	   3, (RR, oRR, SH), arit, t_arit3),
14848218822Sdim tCE(orr,	1800000, orr,	   3, (RR, oRR, SH), arit, t_arit3c),
14849218822Sdim tC3(orrs,	1900000, orrs,	   3, (RR, oRR, SH), arit, t_arit3c),
14850218822Sdim tCE(bic,	1c00000, bic,	   3, (RR, oRR, SH), arit, t_arit3),
14851218822Sdim tC3(bics,	1d00000, bics,	   3, (RR, oRR, SH), arit, t_arit3),
1485289857Sobrien
14853218822Sdim /* The p-variants of tst/cmp/cmn/teq (below) are the pre-V6 mechanism
14854218822Sdim    for setting PSR flag bits.  They are obsolete in V6 and do not
14855218822Sdim    have Thumb equivalents. */
14856218822Sdim tCE(tst,	1100000, tst,	   2, (RR, SH),      cmp,  t_mvn_tst),
14857218822Sdim tC3w(tsts,	1100000, tst,	   2, (RR, SH),      cmp,  t_mvn_tst),
14858218822Sdim  CL(tstp,	110f000,     	   2, (RR, SH),      cmp),
14859218822Sdim tCE(cmp,	1500000, cmp,	   2, (RR, SH),      cmp,  t_mov_cmp),
14860218822Sdim tC3w(cmps,	1500000, cmp,	   2, (RR, SH),      cmp,  t_mov_cmp),
14861218822Sdim  CL(cmpp,	150f000,     	   2, (RR, SH),      cmp),
14862218822Sdim tCE(cmn,	1700000, cmn,	   2, (RR, SH),      cmp,  t_mvn_tst),
14863218822Sdim tC3w(cmns,	1700000, cmn,	   2, (RR, SH),      cmp,  t_mvn_tst),
14864218822Sdim  CL(cmnp,	170f000,     	   2, (RR, SH),      cmp),
1486589857Sobrien
14866218822Sdim tCE(mov,	1a00000, mov,	   2, (RR, SH),      mov,  t_mov_cmp),
14867218822Sdim tC3(movs,	1b00000, movs,	   2, (RR, SH),      mov,  t_mov_cmp),
14868218822Sdim tCE(mvn,	1e00000, mvn,	   2, (RR, SH),      mov,  t_mvn_tst),
14869218822Sdim tC3(mvns,	1f00000, mvns,	   2, (RR, SH),      mov,  t_mvn_tst),
14870218822Sdim
14871218822Sdim tCE(ldr,	4100000, ldr,	   2, (RR, ADDRGLDR),ldst, t_ldst),
14872218822Sdim tC3(ldrb,	4500000, ldrb,	   2, (RR, ADDRGLDR),ldst, t_ldst),
14873218822Sdim tCE(str,	4000000, str,	   2, (RR, ADDRGLDR),ldst, t_ldst),
14874218822Sdim tC3(strb,	4400000, strb,	   2, (RR, ADDRGLDR),ldst, t_ldst),
14875218822Sdim
14876218822Sdim tCE(stm,	8800000, stmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
14877218822Sdim tC3(stmia,	8800000, stmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
14878218822Sdim tC3(stmea,	8800000, stmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
14879218822Sdim tCE(ldm,	8900000, ldmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
14880218822Sdim tC3(ldmia,	8900000, ldmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
14881218822Sdim tC3(ldmfd,	8900000, ldmia,    2, (RRw, REGLST), ldmstm, t_ldmstm),
14882218822Sdim
14883218822Sdim TCE(swi,	f000000, df00,     1, (EXPi),        swi, t_swi),
14884218822Sdim TCE(svc,	f000000, df00,     1, (EXPi),        swi, t_swi),
14885218822Sdim tCE(b,		a000000, b,	   1, (EXPr),	     branch, t_branch),
14886218822Sdim TCE(bl,	b000000, f000f800, 1, (EXPr),	     bl, t_branch23),
14887218822Sdim
14888218822Sdim  /* Pseudo ops.  */
14889218822Sdim tCE(adr,	28f0000, adr,	   2, (RR, EXP),     adr,  t_adr),
14890218822Sdim  C3(adrl,	28f0000,           2, (RR, EXP),     adrl),
14891218822Sdim tCE(nop,	1a00000, nop,	   1, (oI255c),	     nop,  t_nop),
14892218822Sdim
14893218822Sdim  /* Thumb-compatibility pseudo ops.  */
14894218822Sdim tCE(lsl,	1a00000, lsl,	   3, (RR, oRR, SH), shift, t_shift),
14895218822Sdim tC3(lsls,	1b00000, lsls,	   3, (RR, oRR, SH), shift, t_shift),
14896218822Sdim tCE(lsr,	1a00020, lsr,	   3, (RR, oRR, SH), shift, t_shift),
14897218822Sdim tC3(lsrs,	1b00020, lsrs,	   3, (RR, oRR, SH), shift, t_shift),
14898218822Sdim tCE(asr,	1a00040, asr,	   3, (RR, oRR, SH), shift, t_shift),
14899218822Sdim tC3(asrs,      1b00040, asrs,     3, (RR, oRR, SH), shift, t_shift),
14900218822Sdim tCE(ror,	1a00060, ror,	   3, (RR, oRR, SH), shift, t_shift),
14901218822Sdim tC3(rors,	1b00060, rors,	   3, (RR, oRR, SH), shift, t_shift),
14902218822Sdim tCE(neg,	2600000, neg,	   2, (RR, RR),      rd_rn, t_neg),
14903218822Sdim tC3(negs,	2700000, negs,	   2, (RR, RR),      rd_rn, t_neg),
14904218822Sdim tCE(push,	92d0000, push,     1, (REGLST),	     push_pop, t_push_pop),
14905218822Sdim tCE(pop,	8bd0000, pop,	   1, (REGLST),	     push_pop, t_push_pop),
14906218822Sdim
14907218822Sdim /* These may simplify to neg.  */
14908218822Sdim TCE(rsb,	0600000, ebc00000, 3, (RR, oRR, SH), arit, t_rsb),
14909218822Sdim TC3(rsbs,	0700000, ebd00000, 3, (RR, oRR, SH), arit, t_rsb),
14910218822Sdim
14911223484Sdim TCE(rrx,      1a00060, ea4f0030, 2, (RR, RR),      rd_rm, t_rd_rm),
14912223484Sdim TCE(rrxs,     1b00060, ea5f0030, 2, (RR, RR),      rd_rm, t_rd_rm),
14913223484Sdim
14914218822Sdim#undef THUMB_VARIANT
14915218822Sdim#define THUMB_VARIANT &arm_ext_v6
14916218822Sdim TCE(cpy,       1a00000, 4600,     2, (RR, RR),      rd_rm, t_cpy),
14917218822Sdim
14918218822Sdim /* V1 instructions with no Thumb analogue prior to V6T2.  */
14919218822Sdim#undef THUMB_VARIANT
14920218822Sdim#define THUMB_VARIANT &arm_ext_v6t2
14921218822Sdim TCE(teq,	1300000, ea900f00, 2, (RR, SH),      cmp,  t_mvn_tst),
14922218822Sdim TC3w(teqs,	1300000, ea900f00, 2, (RR, SH),      cmp,  t_mvn_tst),
14923218822Sdim  CL(teqp,	130f000,           2, (RR, SH),      cmp),
14924218822Sdim
14925218822Sdim TC3(ldrt,	4300000, f8500e00, 2, (RR, ADDR),    ldstt, t_ldstt),
14926218822Sdim TC3(ldrbt,	4700000, f8100e00, 2, (RR, ADDR),    ldstt, t_ldstt),
14927218822Sdim TC3(strt,	4200000, f8400e00, 2, (RR, ADDR),    ldstt, t_ldstt),
14928218822Sdim TC3(strbt,	4600000, f8000e00, 2, (RR, ADDR),    ldstt, t_ldstt),
14929218822Sdim
14930218822Sdim TC3(stmdb,	9000000, e9000000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
14931218822Sdim TC3(stmfd,     9000000, e9000000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
14932218822Sdim
14933218822Sdim TC3(ldmdb,	9100000, e9100000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
14934218822Sdim TC3(ldmea,	9100000, e9100000, 2, (RRw, REGLST), ldmstm, t_ldmstm),
14935218822Sdim
14936218822Sdim /* V1 instructions with no Thumb analogue at all.  */
14937218822Sdim  CE(rsc,	0e00000,	   3, (RR, oRR, SH), arit),
14938218822Sdim  C3(rscs,	0f00000,	   3, (RR, oRR, SH), arit),
14939218822Sdim
14940218822Sdim  C3(stmib,	9800000,	   2, (RRw, REGLST), ldmstm),
14941218822Sdim  C3(stmfa,	9800000,	   2, (RRw, REGLST), ldmstm),
14942218822Sdim  C3(stmda,	8000000,	   2, (RRw, REGLST), ldmstm),
14943218822Sdim  C3(stmed,	8000000,	   2, (RRw, REGLST), ldmstm),
14944218822Sdim  C3(ldmib,	9900000,	   2, (RRw, REGLST), ldmstm),
14945218822Sdim  C3(ldmed,	9900000,	   2, (RRw, REGLST), ldmstm),
14946218822Sdim  C3(ldmda,	8100000,	   2, (RRw, REGLST), ldmstm),
14947218822Sdim  C3(ldmfa,	8100000,	   2, (RRw, REGLST), ldmstm),
14948218822Sdim
14949218822Sdim#undef ARM_VARIANT
14950218822Sdim#define ARM_VARIANT &arm_ext_v2	/* ARM 2 - multiplies.	*/
14951218822Sdim#undef THUMB_VARIANT
14952218822Sdim#define THUMB_VARIANT &arm_ext_v4t
14953218822Sdim tCE(mul,	0000090, mul,	   3, (RRnpc, RRnpc, oRR), mul, t_mul),
14954218822Sdim tC3(muls,	0100090, muls,	   3, (RRnpc, RRnpc, oRR), mul, t_mul),
14955218822Sdim
14956218822Sdim#undef THUMB_VARIANT
14957218822Sdim#define THUMB_VARIANT &arm_ext_v6t2
14958218822Sdim TCE(mla,	0200090, fb000000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mlas, t_mla),
14959218822Sdim  C3(mlas,	0300090,           4, (RRnpc, RRnpc, RRnpc, RRnpc), mlas),
14960218822Sdim
14961218822Sdim  /* Generic coprocessor instructions.	*/
14962218822Sdim TCE(cdp,	e000000, ee000000, 6, (RCP, I15b, RCN, RCN, RCN, oI7b), cdp,    cdp),
14963218822Sdim TCE(ldc,	c100000, ec100000, 3, (RCP, RCN, ADDRGLDC),	        lstc,   lstc),
14964218822Sdim TC3(ldcl,	c500000, ec500000, 3, (RCP, RCN, ADDRGLDC),	        lstc,   lstc),
14965218822Sdim TCE(stc,	c000000, ec000000, 3, (RCP, RCN, ADDRGLDC),	        lstc,   lstc),
14966218822Sdim TC3(stcl,	c400000, ec400000, 3, (RCP, RCN, ADDRGLDC),	        lstc,   lstc),
14967218822Sdim TCE(mcr,	e000010, ee000010, 6, (RCP, I7b, RR, RCN, RCN, oI7b),   co_reg, co_reg),
14968218822Sdim TCE(mrc,	e100010, ee100010, 6, (RCP, I7b, RR, RCN, RCN, oI7b),   co_reg, co_reg),
14969218822Sdim
14970218822Sdim#undef ARM_VARIANT
14971218822Sdim#define ARM_VARIANT &arm_ext_v2s /* ARM 3 - swp instructions.  */
14972218822Sdim  CE(swp,	1000090,           3, (RRnpc, RRnpc, RRnpcb), rd_rm_rn),
14973218822Sdim  C3(swpb,	1400090,           3, (RRnpc, RRnpc, RRnpcb), rd_rm_rn),
14974218822Sdim
14975218822Sdim#undef ARM_VARIANT
14976218822Sdim#define ARM_VARIANT &arm_ext_v3	/* ARM 6 Status register instructions.	*/
14977218822Sdim TCE(mrs,	10f0000, f3ef8000, 2, (APSR_RR, RVC_PSR), mrs, t_mrs),
14978218822Sdim TCE(msr,	120f000, f3808000, 2, (RVC_PSR, RR_EXi), msr, t_msr),
14979218822Sdim
14980218822Sdim#undef ARM_VARIANT
14981218822Sdim#define ARM_VARIANT &arm_ext_v3m	 /* ARM 7M long multiplies.  */
14982218822Sdim TCE(smull,	0c00090, fb800000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull, t_mull),
14983218822Sdim  CM(smull,s,	0d00090,           4, (RRnpc, RRnpc, RRnpc, RRnpc), mull),
14984218822Sdim TCE(umull,	0800090, fba00000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull, t_mull),
14985218822Sdim  CM(umull,s,	0900090,           4, (RRnpc, RRnpc, RRnpc, RRnpc), mull),
14986218822Sdim TCE(smlal,	0e00090, fbc00000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull, t_mull),
14987218822Sdim  CM(smlal,s,	0f00090,           4, (RRnpc, RRnpc, RRnpc, RRnpc), mull),
14988218822Sdim TCE(umlal,	0a00090, fbe00000, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mull, t_mull),
14989218822Sdim  CM(umlal,s,	0b00090,           4, (RRnpc, RRnpc, RRnpc, RRnpc), mull),
14990218822Sdim
14991218822Sdim#undef ARM_VARIANT
14992218822Sdim#define ARM_VARIANT &arm_ext_v4	/* ARM Architecture 4.	*/
14993218822Sdim#undef THUMB_VARIANT
14994218822Sdim#define THUMB_VARIANT &arm_ext_v4t
14995218822Sdim tC3(ldrh,	01000b0, ldrh,     2, (RR, ADDRGLDRS), ldstv4, t_ldst),
14996218822Sdim tC3(strh,	00000b0, strh,     2, (RR, ADDRGLDRS), ldstv4, t_ldst),
14997218822Sdim tC3(ldrsh,	01000f0, ldrsh,    2, (RR, ADDRGLDRS), ldstv4, t_ldst),
14998218822Sdim tC3(ldrsb,	01000d0, ldrsb,    2, (RR, ADDRGLDRS), ldstv4, t_ldst),
14999218822Sdim tCM(ld,sh,	01000f0, ldrsh,    2, (RR, ADDRGLDRS), ldstv4, t_ldst),
15000218822Sdim tCM(ld,sb,	01000d0, ldrsb,    2, (RR, ADDRGLDRS), ldstv4, t_ldst),
15001218822Sdim
15002218822Sdim#undef ARM_VARIANT
15003218822Sdim#define ARM_VARIANT &arm_ext_v4t_5
15004218822Sdim  /* ARM Architecture 4T.  */
15005218822Sdim  /* Note: bx (and blx) are required on V5, even if the processor does
15006218822Sdim     not support Thumb.	 */
15007218822Sdim TCE(bx,	12fff10, 4700, 1, (RR),	bx, t_bx),
15008218822Sdim
15009218822Sdim#undef ARM_VARIANT
15010218822Sdim#define ARM_VARIANT &arm_ext_v5 /*  ARM Architecture 5T.	 */
15011218822Sdim#undef THUMB_VARIANT
15012218822Sdim#define THUMB_VARIANT &arm_ext_v5t
15013218822Sdim  /* Note: blx has 2 variants; the .value coded here is for
15014218822Sdim     BLX(2).  Only this variant has conditional execution.  */
15015218822Sdim TCE(blx,	12fff30, 4780, 1, (RR_EXr),			    blx,  t_blx),
15016218822Sdim TUE(bkpt,	1200070, be00, 1, (oIffffb),			    bkpt, t_bkpt),
15017218822Sdim
15018218822Sdim#undef THUMB_VARIANT
15019218822Sdim#define THUMB_VARIANT &arm_ext_v6t2
15020218822Sdim TCE(clz,	16f0f10, fab0f080, 2, (RRnpc, RRnpc),		        rd_rm,  t_clz),
15021218822Sdim TUF(ldc2,	c100000, fc100000, 3, (RCP, RCN, ADDRGLDC),	        lstc,	lstc),
15022218822Sdim TUF(ldc2l,	c500000, fc500000, 3, (RCP, RCN, ADDRGLDC),		        lstc,	lstc),
15023218822Sdim TUF(stc2,	c000000, fc000000, 3, (RCP, RCN, ADDRGLDC),	        lstc,	lstc),
15024218822Sdim TUF(stc2l,	c400000, fc400000, 3, (RCP, RCN, ADDRGLDC),		        lstc,	lstc),
15025218822Sdim TUF(cdp2,	e000000, fe000000, 6, (RCP, I15b, RCN, RCN, RCN, oI7b), cdp,    cdp),
15026218822Sdim TUF(mcr2,	e000010, fe000010, 6, (RCP, I7b, RR, RCN, RCN, oI7b),   co_reg, co_reg),
15027218822Sdim TUF(mrc2,	e100010, fe100010, 6, (RCP, I7b, RR, RCN, RCN, oI7b),   co_reg, co_reg),
15028218822Sdim
15029218822Sdim#undef ARM_VARIANT
15030218822Sdim#define ARM_VARIANT &arm_ext_v5exp /*  ARM Architecture 5TExP.  */
15031218822Sdim TCE(smlabb,	1000080, fb100000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15032218822Sdim TCE(smlatb,	10000a0, fb100020, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15033218822Sdim TCE(smlabt,	10000c0, fb100010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15034218822Sdim TCE(smlatt,	10000e0, fb100030, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15035218822Sdim
15036218822Sdim TCE(smlawb,	1200080, fb300000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15037218822Sdim TCE(smlawt,	12000c0, fb300010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smla, t_mla),
15038218822Sdim
15039218822Sdim TCE(smlalbb,	1400080, fbc00080, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smlal, t_mlal),
15040218822Sdim TCE(smlaltb,	14000a0, fbc000a0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smlal, t_mlal),
15041218822Sdim TCE(smlalbt,	14000c0, fbc00090, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smlal, t_mlal),
15042218822Sdim TCE(smlaltt,	14000e0, fbc000b0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),   smlal, t_mlal),
15043218822Sdim
15044218822Sdim TCE(smulbb,	1600080, fb10f000, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15045218822Sdim TCE(smultb,	16000a0, fb10f020, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15046218822Sdim TCE(smulbt,	16000c0, fb10f010, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15047218822Sdim TCE(smultt,	16000e0, fb10f030, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15048218822Sdim
15049218822Sdim TCE(smulwb,	12000a0, fb30f000, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15050218822Sdim TCE(smulwt,	12000e0, fb30f010, 3, (RRnpc, RRnpc, RRnpc),	    smul, t_simd),
15051218822Sdim
15052218822Sdim TCE(qadd,	1000050, fa80f080, 3, (RRnpc, RRnpc, RRnpc),	    rd_rm_rn, rd_rm_rn),
15053218822Sdim TCE(qdadd,	1400050, fa80f090, 3, (RRnpc, RRnpc, RRnpc),	    rd_rm_rn, rd_rm_rn),
15054218822Sdim TCE(qsub,	1200050, fa80f0a0, 3, (RRnpc, RRnpc, RRnpc),	    rd_rm_rn, rd_rm_rn),
15055218822Sdim TCE(qdsub,	1600050, fa80f0b0, 3, (RRnpc, RRnpc, RRnpc),	    rd_rm_rn, rd_rm_rn),
15056218822Sdim
15057218822Sdim#undef ARM_VARIANT
15058218822Sdim#define ARM_VARIANT &arm_ext_v5e /*  ARM Architecture 5TE.  */
15059218822Sdim TUF(pld,	450f000, f810f000, 1, (ADDR),		     pld,  t_pld),
15060218822Sdim TC3(ldrd,	00000d0, e8500000, 3, (RRnpc, oRRnpc, ADDRGLDRS), ldrd, t_ldstd),
15061218822Sdim TC3(strd,	00000f0, e8400000, 3, (RRnpc, oRRnpc, ADDRGLDRS), ldrd, t_ldstd),
15062218822Sdim
15063218822Sdim TCE(mcrr,	c400000, ec400000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
15064218822Sdim TCE(mrrc,	c500000, ec500000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
15065218822Sdim
15066218822Sdim#undef ARM_VARIANT
15067218822Sdim#define ARM_VARIANT &arm_ext_v5j /*  ARM Architecture 5TEJ.  */
15068218822Sdim TCE(bxj,	12fff20, f3c08f00, 1, (RR),			  bxj, t_bxj),
15069218822Sdim
15070218822Sdim#undef ARM_VARIANT
15071218822Sdim#define ARM_VARIANT &arm_ext_v6 /*  ARM V6.  */
15072218822Sdim#undef THUMB_VARIANT
15073218822Sdim#define THUMB_VARIANT &arm_ext_v6
15074218822Sdim TUF(cpsie,     1080000, b660,     2, (CPSF, oI31b),              cpsi,   t_cpsi),
15075218822Sdim TUF(cpsid,     10c0000, b670,     2, (CPSF, oI31b),              cpsi,   t_cpsi),
15076218822Sdim tCE(rev,       6bf0f30, rev,      2, (RRnpc, RRnpc),             rd_rm,  t_rev),
15077218822Sdim tCE(rev16,     6bf0fb0, rev16,    2, (RRnpc, RRnpc),             rd_rm,  t_rev),
15078218822Sdim tCE(revsh,     6ff0fb0, revsh,    2, (RRnpc, RRnpc),             rd_rm,  t_rev),
15079218822Sdim tCE(sxth,      6bf0070, sxth,     3, (RRnpc, RRnpc, oROR),       sxth,   t_sxth),
15080218822Sdim tCE(uxth,      6ff0070, uxth,     3, (RRnpc, RRnpc, oROR),       sxth,   t_sxth),
15081218822Sdim tCE(sxtb,      6af0070, sxtb,     3, (RRnpc, RRnpc, oROR),       sxth,   t_sxth),
15082218822Sdim tCE(uxtb,      6ef0070, uxtb,     3, (RRnpc, RRnpc, oROR),       sxth,   t_sxth),
15083218822Sdim TUF(setend,    1010000, b650,     1, (ENDI),                     setend, t_setend),
15084218822Sdim
15085218822Sdim#undef THUMB_VARIANT
15086218822Sdim#define THUMB_VARIANT &arm_ext_v6t2
15087218822Sdim TCE(ldrex,	1900f9f, e8500f00, 2, (RRnpc, ADDR),		  ldrex, t_ldrex),
15088218822Sdim TCE(strex,	1800f90, e8400000, 3, (RRnpc, RRnpc, ADDR),	   strex,  t_strex),
15089218822Sdim TUF(mcrr2,	c400000, fc400000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
15090218822Sdim TUF(mrrc2,	c500000, fc500000, 5, (RCP, I15b, RRnpc, RRnpc, RCN), co_reg2c, co_reg2c),
15091218822Sdim
15092218822Sdim TCE(ssat,	6a00010, f3000000, 4, (RRnpc, I32, RRnpc, oSHllar),ssat,   t_ssat),
15093218822Sdim TCE(usat,	6e00010, f3800000, 4, (RRnpc, I31, RRnpc, oSHllar),usat,   t_usat),
15094218822Sdim
15095218822Sdim/*  ARM V6 not included in V7M (eg. integer SIMD).  */
15096218822Sdim#undef THUMB_VARIANT
15097218822Sdim#define THUMB_VARIANT &arm_ext_v6_notm
15098218822Sdim TUF(cps,	1020000, f3af8100, 1, (I31b),			  imm0, t_cps),
15099218822Sdim TCE(pkhbt,	6800010, eac00000, 4, (RRnpc, RRnpc, RRnpc, oSHll),   pkhbt, t_pkhbt),
15100218822Sdim TCE(pkhtb,	6800050, eac00020, 4, (RRnpc, RRnpc, RRnpc, oSHar),   pkhtb, t_pkhtb),
15101218822Sdim TCE(qadd16,	6200f10, fa90f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15102218822Sdim TCE(qadd8,	6200f90, fa80f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15103218822Sdim TCE(qaddsubx,	6200f30, faa0f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15104218822Sdim TCE(qsub16,	6200f70, fad0f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15105218822Sdim TCE(qsub8,	6200ff0, fac0f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15106218822Sdim TCE(qsubaddx,	6200f50, fae0f010, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15107218822Sdim TCE(sadd16,	6100f10, fa90f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15108218822Sdim TCE(sadd8,	6100f90, fa80f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15109218822Sdim TCE(saddsubx,	6100f30, faa0f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15110218822Sdim TCE(shadd16,	6300f10, fa90f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15111218822Sdim TCE(shadd8,	6300f90, fa80f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15112218822Sdim TCE(shaddsubx, 6300f30, faa0f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15113218822Sdim TCE(shsub16,	6300f70, fad0f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15114218822Sdim TCE(shsub8,	6300ff0, fac0f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15115218822Sdim TCE(shsubaddx, 6300f50, fae0f020, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15116218822Sdim TCE(ssub16,	6100f70, fad0f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15117218822Sdim TCE(ssub8,	6100ff0, fac0f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15118218822Sdim TCE(ssubaddx,	6100f50, fae0f000, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15119218822Sdim TCE(uadd16,	6500f10, fa90f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15120218822Sdim TCE(uadd8,	6500f90, fa80f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15121218822Sdim TCE(uaddsubx,	6500f30, faa0f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15122218822Sdim TCE(uhadd16,	6700f10, fa90f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15123218822Sdim TCE(uhadd8,	6700f90, fa80f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15124218822Sdim TCE(uhaddsubx, 6700f30, faa0f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15125218822Sdim TCE(uhsub16,	6700f70, fad0f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15126218822Sdim TCE(uhsub8,	6700ff0, fac0f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15127218822Sdim TCE(uhsubaddx, 6700f50, fae0f060, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15128218822Sdim TCE(uqadd16,	6600f10, fa90f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15129218822Sdim TCE(uqadd8,	6600f90, fa80f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15130218822Sdim TCE(uqaddsubx, 6600f30, faa0f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15131218822Sdim TCE(uqsub16,	6600f70, fad0f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15132218822Sdim TCE(uqsub8,	6600ff0, fac0f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15133218822Sdim TCE(uqsubaddx, 6600f50, fae0f050, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15134218822Sdim TCE(usub16,	6500f70, fad0f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15135218822Sdim TCE(usub8,	6500ff0, fac0f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15136218822Sdim TCE(usubaddx,	6500f50, fae0f040, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15137218822Sdim TUF(rfeia,	8900a00, e990c000, 1, (RRw),			   rfe, rfe),
15138218822Sdim  UF(rfeib,	9900a00,           1, (RRw),			   rfe),
15139218822Sdim  UF(rfeda,	8100a00,           1, (RRw),			   rfe),
15140218822Sdim TUF(rfedb,	9100a00, e810c000, 1, (RRw),			   rfe, rfe),
15141218822Sdim TUF(rfefd,	8900a00, e990c000, 1, (RRw),			   rfe, rfe),
15142218822Sdim  UF(rfefa,	9900a00,           1, (RRw),			   rfe),
15143218822Sdim  UF(rfeea,	8100a00,           1, (RRw),			   rfe),
15144218822Sdim TUF(rfeed,	9100a00, e810c000, 1, (RRw),			   rfe, rfe),
15145218822Sdim TCE(sxtah,	6b00070, fa00f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15146218822Sdim TCE(sxtab16,	6800070, fa20f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15147218822Sdim TCE(sxtab,	6a00070, fa40f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15148218822Sdim TCE(sxtb16,	68f0070, fa2ff080, 3, (RRnpc, RRnpc, oROR),	   sxth,  t_sxth),
15149218822Sdim TCE(uxtah,	6f00070, fa10f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15150218822Sdim TCE(uxtab16,	6c00070, fa30f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15151218822Sdim TCE(uxtab,	6e00070, fa50f080, 4, (RRnpc, RRnpc, RRnpc, oROR), sxtah, t_sxtah),
15152218822Sdim TCE(uxtb16,	6cf0070, fa3ff080, 3, (RRnpc, RRnpc, oROR),	   sxth,  t_sxth),
15153218822Sdim TCE(sel,	6800fb0, faa0f080, 3, (RRnpc, RRnpc, RRnpc),	   rd_rn_rm, t_simd),
15154218822Sdim TCE(smlad,	7000010, fb200000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15155218822Sdim TCE(smladx,	7000030, fb200010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15156218822Sdim TCE(smlald,	7400010, fbc000c0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,t_mlal),
15157218822Sdim TCE(smlaldx,	7400030, fbc000d0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,t_mlal),
15158218822Sdim TCE(smlsd,	7000050, fb400000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15159218822Sdim TCE(smlsdx,	7000070, fb400010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15160218822Sdim TCE(smlsld,	7400050, fbd000c0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,t_mlal),
15161218822Sdim TCE(smlsldx,	7400070, fbd000d0, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,t_mlal),
15162218822Sdim TCE(smmla,	7500010, fb500000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15163218822Sdim TCE(smmlar,	7500030, fb500010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15164218822Sdim TCE(smmls,	75000d0, fb600000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15165218822Sdim TCE(smmlsr,	75000f0, fb600010, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla, t_mla),
15166218822Sdim TCE(smmul,	750f010, fb50f000, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15167218822Sdim TCE(smmulr,	750f030, fb50f010, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15168218822Sdim TCE(smuad,	700f010, fb20f000, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15169218822Sdim TCE(smuadx,	700f030, fb20f010, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15170218822Sdim TCE(smusd,	700f050, fb40f000, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15171218822Sdim TCE(smusdx,	700f070, fb40f010, 3, (RRnpc, RRnpc, RRnpc),	   smul, t_simd),
15172218822Sdim TUF(srsia,	8c00500, e980c000, 2, (oRRw, I31w),		   srs,  srs),
15173218822Sdim  UF(srsib,	9c00500,           2, (oRRw, I31w),		   srs),
15174218822Sdim  UF(srsda,	8400500,	   2, (oRRw, I31w),		   srs),
15175218822Sdim TUF(srsdb,	9400500, e800c000, 2, (oRRw, I31w),		   srs,  srs),
15176218822Sdim TCE(ssat16,	6a00f30, f3200000, 3, (RRnpc, I16, RRnpc),	   ssat16, t_ssat16),
15177218822Sdim TCE(umaal,	0400090, fbe00060, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smlal,  t_mlal),
15178218822Sdim TCE(usad8,	780f010, fb70f000, 3, (RRnpc, RRnpc, RRnpc),	   smul,   t_simd),
15179218822Sdim TCE(usada8,	7800010, fb700000, 4, (RRnpc, RRnpc, RRnpc, RRnpc),smla,   t_mla),
15180218822Sdim TCE(usat16,	6e00f30, f3a00000, 3, (RRnpc, I15, RRnpc),	   usat16, t_usat16),
15181218822Sdim
15182218822Sdim#undef ARM_VARIANT
15183218822Sdim#define ARM_VARIANT &arm_ext_v6k
15184218822Sdim#undef THUMB_VARIANT
15185218822Sdim#define THUMB_VARIANT &arm_ext_v6k
15186218822Sdim tCE(yield,	320f001, yield,    0, (), noargs, t_hint),
15187218822Sdim tCE(wfe,	320f002, wfe,      0, (), noargs, t_hint),
15188218822Sdim tCE(wfi,	320f003, wfi,      0, (), noargs, t_hint),
15189218822Sdim tCE(sev,	320f004, sev,      0, (), noargs, t_hint),
15190218822Sdim
15191218822Sdim#undef THUMB_VARIANT
15192218822Sdim#define THUMB_VARIANT &arm_ext_v6_notm
15193218822Sdim TCE(ldrexd,	1b00f9f, e8d0007f, 3, (RRnpc, oRRnpc, RRnpcb),        ldrexd, t_ldrexd),
15194218822Sdim TCE(strexd,	1a00f90, e8c00070, 4, (RRnpc, RRnpc, oRRnpc, RRnpcb), strexd, t_strexd),
15195218822Sdim
15196218822Sdim#undef THUMB_VARIANT
15197218822Sdim#define THUMB_VARIANT &arm_ext_v6t2
15198218822Sdim TCE(ldrexb,	1d00f9f, e8d00f4f, 2, (RRnpc, RRnpcb),	              rd_rn,  rd_rn),
15199218822Sdim TCE(ldrexh,	1f00f9f, e8d00f5f, 2, (RRnpc, RRnpcb),	              rd_rn,  rd_rn),
15200218822Sdim TCE(strexb,	1c00f90, e8c00f40, 3, (RRnpc, RRnpc, ADDR),           strex,  rm_rd_rn),
15201218822Sdim TCE(strexh,	1e00f90, e8c00f50, 3, (RRnpc, RRnpc, ADDR),           strex,  rm_rd_rn),
15202218822Sdim TUF(clrex,	57ff01f, f3bf8f2f, 0, (),			      noargs, noargs),
15203218822Sdim
15204218822Sdim#undef ARM_VARIANT
15205218822Sdim#define ARM_VARIANT &arm_ext_v6z
15206218822Sdim TCE(smc,	1600070, f7f08000, 1, (EXPi), smc, t_smc),
15207218822Sdim
15208218822Sdim#undef ARM_VARIANT
15209218822Sdim#define ARM_VARIANT &arm_ext_v6t2
15210218822Sdim TCE(bfc,	7c0001f, f36f0000, 3, (RRnpc, I31, I32),	   bfc, t_bfc),
15211218822Sdim TCE(bfi,	7c00010, f3600000, 4, (RRnpc, RRnpc_I0, I31, I32), bfi, t_bfi),
15212218822Sdim TCE(sbfx,	7a00050, f3400000, 4, (RR, RR, I31, I32),	   bfx, t_bfx),
15213218822Sdim TCE(ubfx,	7e00050, f3c00000, 4, (RR, RR, I31, I32),	   bfx, t_bfx),
15214218822Sdim
15215218822Sdim TCE(mls,	0600090, fb000010, 4, (RRnpc, RRnpc, RRnpc, RRnpc), mlas, t_mla),
15216218822Sdim TCE(movw,	3000000, f2400000, 2, (RRnpc, HALF),		    mov16, t_mov16),
15217218822Sdim TCE(movt,	3400000, f2c00000, 2, (RRnpc, HALF),		    mov16, t_mov16),
15218218822Sdim TCE(rbit,	6ff0f30, fa90f0a0, 2, (RR, RR),			    rd_rm, t_rbit),
15219218822Sdim
15220218822Sdim TC3(ldrht,	03000b0, f8300e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
15221218822Sdim TC3(ldrsht,	03000f0, f9300e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
15222218822Sdim TC3(ldrsbt,	03000d0, f9100e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
15223218822Sdim TC3(strht,	02000b0, f8200e00, 2, (RR, ADDR), ldsttv4, t_ldstt),
15224218822Sdim
15225218822Sdim  UT(cbnz,      b900,    2, (RR, EXP), t_cbz),
15226218822Sdim  UT(cbz,       b100,    2, (RR, EXP), t_cbz),
15227218822Sdim /* ARM does not really have an IT instruction, so always allow it.  */
15228218822Sdim#undef ARM_VARIANT
15229218822Sdim#define ARM_VARIANT &arm_ext_v1
15230218822Sdim TUE(it,        0, bf08, 1, (COND),    it, t_it),
15231218822Sdim TUE(itt,       0, bf0c, 1, (COND),    it, t_it),
15232218822Sdim TUE(ite,       0, bf04, 1, (COND),    it, t_it),
15233218822Sdim TUE(ittt,      0, bf0e, 1, (COND),    it, t_it),
15234218822Sdim TUE(itet,      0, bf06, 1, (COND),    it, t_it),
15235218822Sdim TUE(itte,      0, bf0a, 1, (COND),    it, t_it),
15236218822Sdim TUE(itee,      0, bf02, 1, (COND),    it, t_it),
15237218822Sdim TUE(itttt,     0, bf0f, 1, (COND),    it, t_it),
15238218822Sdim TUE(itett,     0, bf07, 1, (COND),    it, t_it),
15239218822Sdim TUE(ittet,     0, bf0b, 1, (COND),    it, t_it),
15240218822Sdim TUE(iteet,     0, bf03, 1, (COND),    it, t_it),
15241218822Sdim TUE(ittte,     0, bf0d, 1, (COND),    it, t_it),
15242218822Sdim TUE(itete,     0, bf05, 1, (COND),    it, t_it),
15243218822Sdim TUE(ittee,     0, bf09, 1, (COND),    it, t_it),
15244218822Sdim TUE(iteee,     0, bf01, 1, (COND),    it, t_it),
15245218822Sdim
15246218822Sdim /* Thumb2 only instructions.  */
15247218822Sdim#undef ARM_VARIANT
15248218822Sdim#define ARM_VARIANT NULL
15249218822Sdim
15250218822Sdim TCE(addw,	0, f2000000, 3, (RR, RR, EXPi), 0, t_add_sub_w),
15251218822Sdim TCE(subw,	0, f2a00000, 3, (RR, RR, EXPi), 0, t_add_sub_w),
15252218822Sdim TCE(tbb,       0, e8d0f000, 1, (TB), 0, t_tb),
15253218822Sdim TCE(tbh,       0, e8d0f010, 1, (TB), 0, t_tb),
15254218822Sdim
15255218822Sdim /* Thumb-2 hardware division instructions (R and M profiles only).  */
15256218822Sdim#undef THUMB_VARIANT
15257218822Sdim#define THUMB_VARIANT &arm_ext_div
15258218822Sdim TCE(sdiv,	0, fb90f0f0, 3, (RR, oRR, RR), 0, t_div),
15259218822Sdim TCE(udiv,	0, fbb0f0f0, 3, (RR, oRR, RR), 0, t_div),
15260218822Sdim
15261218822Sdim /* ARM V7 instructions.  */
15262218822Sdim#undef ARM_VARIANT
15263218822Sdim#define ARM_VARIANT &arm_ext_v7
15264218822Sdim#undef THUMB_VARIANT
15265218822Sdim#define THUMB_VARIANT &arm_ext_v7
15266218822Sdim TUF(pli,	450f000, f910f000, 1, (ADDR),	  pli,	    t_pld),
15267218822Sdim TCE(dbg,	320f0f0, f3af80f0, 1, (I15),	  dbg,	    t_dbg),
15268218822Sdim TUF(dmb,	57ff050, f3bf8f50, 1, (oBARRIER), barrier,  t_barrier),
15269218822Sdim TUF(dsb,	57ff040, f3bf8f40, 1, (oBARRIER), barrier,  t_barrier),
15270218822Sdim TUF(isb,	57ff060, f3bf8f60, 1, (oBARRIER), barrier,  t_barrier),
15271218822Sdim
15272218822Sdim#undef ARM_VARIANT
15273218822Sdim#define ARM_VARIANT &fpu_fpa_ext_v1  /* Core FPA instruction set (V1).  */
15274218822Sdim cCE(wfs,	e200110, 1, (RR),	     rd),
15275218822Sdim cCE(rfs,	e300110, 1, (RR),	     rd),
15276218822Sdim cCE(wfc,	e400110, 1, (RR),	     rd),
15277218822Sdim cCE(rfc,	e500110, 1, (RR),	     rd),
15278218822Sdim
15279218822Sdim cCL(ldfs,	c100100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15280218822Sdim cCL(ldfd,	c108100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15281218822Sdim cCL(ldfe,	c500100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15282218822Sdim cCL(ldfp,	c508100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15283218822Sdim
15284218822Sdim cCL(stfs,	c000100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15285218822Sdim cCL(stfd,	c008100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15286218822Sdim cCL(stfe,	c400100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15287218822Sdim cCL(stfp,	c408100, 2, (RF, ADDRGLDC),  rd_cpaddr),
15288218822Sdim
15289218822Sdim cCL(mvfs,	e008100, 2, (RF, RF_IF),     rd_rm),
15290218822Sdim cCL(mvfsp,	e008120, 2, (RF, RF_IF),     rd_rm),
15291218822Sdim cCL(mvfsm,	e008140, 2, (RF, RF_IF),     rd_rm),
15292218822Sdim cCL(mvfsz,	e008160, 2, (RF, RF_IF),     rd_rm),
15293218822Sdim cCL(mvfd,	e008180, 2, (RF, RF_IF),     rd_rm),
15294218822Sdim cCL(mvfdp,	e0081a0, 2, (RF, RF_IF),     rd_rm),
15295218822Sdim cCL(mvfdm,	e0081c0, 2, (RF, RF_IF),     rd_rm),
15296218822Sdim cCL(mvfdz,	e0081e0, 2, (RF, RF_IF),     rd_rm),
15297218822Sdim cCL(mvfe,	e088100, 2, (RF, RF_IF),     rd_rm),
15298218822Sdim cCL(mvfep,	e088120, 2, (RF, RF_IF),     rd_rm),
15299218822Sdim cCL(mvfem,	e088140, 2, (RF, RF_IF),     rd_rm),
15300218822Sdim cCL(mvfez,	e088160, 2, (RF, RF_IF),     rd_rm),
15301218822Sdim
15302218822Sdim cCL(mnfs,	e108100, 2, (RF, RF_IF),     rd_rm),
15303218822Sdim cCL(mnfsp,	e108120, 2, (RF, RF_IF),     rd_rm),
15304218822Sdim cCL(mnfsm,	e108140, 2, (RF, RF_IF),     rd_rm),
15305218822Sdim cCL(mnfsz,	e108160, 2, (RF, RF_IF),     rd_rm),
15306218822Sdim cCL(mnfd,	e108180, 2, (RF, RF_IF),     rd_rm),
15307218822Sdim cCL(mnfdp,	e1081a0, 2, (RF, RF_IF),     rd_rm),
15308218822Sdim cCL(mnfdm,	e1081c0, 2, (RF, RF_IF),     rd_rm),
15309218822Sdim cCL(mnfdz,	e1081e0, 2, (RF, RF_IF),     rd_rm),
15310218822Sdim cCL(mnfe,	e188100, 2, (RF, RF_IF),     rd_rm),
15311218822Sdim cCL(mnfep,	e188120, 2, (RF, RF_IF),     rd_rm),
15312218822Sdim cCL(mnfem,	e188140, 2, (RF, RF_IF),     rd_rm),
15313218822Sdim cCL(mnfez,	e188160, 2, (RF, RF_IF),     rd_rm),
15314218822Sdim
15315218822Sdim cCL(abss,	e208100, 2, (RF, RF_IF),     rd_rm),
15316218822Sdim cCL(abssp,	e208120, 2, (RF, RF_IF),     rd_rm),
15317218822Sdim cCL(abssm,	e208140, 2, (RF, RF_IF),     rd_rm),
15318218822Sdim cCL(abssz,	e208160, 2, (RF, RF_IF),     rd_rm),
15319218822Sdim cCL(absd,	e208180, 2, (RF, RF_IF),     rd_rm),
15320218822Sdim cCL(absdp,	e2081a0, 2, (RF, RF_IF),     rd_rm),
15321218822Sdim cCL(absdm,	e2081c0, 2, (RF, RF_IF),     rd_rm),
15322218822Sdim cCL(absdz,	e2081e0, 2, (RF, RF_IF),     rd_rm),
15323218822Sdim cCL(abse,	e288100, 2, (RF, RF_IF),     rd_rm),
15324218822Sdim cCL(absep,	e288120, 2, (RF, RF_IF),     rd_rm),
15325218822Sdim cCL(absem,	e288140, 2, (RF, RF_IF),     rd_rm),
15326218822Sdim cCL(absez,	e288160, 2, (RF, RF_IF),     rd_rm),
15327218822Sdim
15328218822Sdim cCL(rnds,	e308100, 2, (RF, RF_IF),     rd_rm),
15329218822Sdim cCL(rndsp,	e308120, 2, (RF, RF_IF),     rd_rm),
15330218822Sdim cCL(rndsm,	e308140, 2, (RF, RF_IF),     rd_rm),
15331218822Sdim cCL(rndsz,	e308160, 2, (RF, RF_IF),     rd_rm),
15332218822Sdim cCL(rndd,	e308180, 2, (RF, RF_IF),     rd_rm),
15333218822Sdim cCL(rnddp,	e3081a0, 2, (RF, RF_IF),     rd_rm),
15334218822Sdim cCL(rnddm,	e3081c0, 2, (RF, RF_IF),     rd_rm),
15335218822Sdim cCL(rnddz,	e3081e0, 2, (RF, RF_IF),     rd_rm),
15336218822Sdim cCL(rnde,	e388100, 2, (RF, RF_IF),     rd_rm),
15337218822Sdim cCL(rndep,	e388120, 2, (RF, RF_IF),     rd_rm),
15338218822Sdim cCL(rndem,	e388140, 2, (RF, RF_IF),     rd_rm),
15339218822Sdim cCL(rndez,	e388160, 2, (RF, RF_IF),     rd_rm),
15340218822Sdim
15341218822Sdim cCL(sqts,	e408100, 2, (RF, RF_IF),     rd_rm),
15342218822Sdim cCL(sqtsp,	e408120, 2, (RF, RF_IF),     rd_rm),
15343218822Sdim cCL(sqtsm,	e408140, 2, (RF, RF_IF),     rd_rm),
15344218822Sdim cCL(sqtsz,	e408160, 2, (RF, RF_IF),     rd_rm),
15345218822Sdim cCL(sqtd,	e408180, 2, (RF, RF_IF),     rd_rm),
15346218822Sdim cCL(sqtdp,	e4081a0, 2, (RF, RF_IF),     rd_rm),
15347218822Sdim cCL(sqtdm,	e4081c0, 2, (RF, RF_IF),     rd_rm),
15348218822Sdim cCL(sqtdz,	e4081e0, 2, (RF, RF_IF),     rd_rm),
15349218822Sdim cCL(sqte,	e488100, 2, (RF, RF_IF),     rd_rm),
15350218822Sdim cCL(sqtep,	e488120, 2, (RF, RF_IF),     rd_rm),
15351218822Sdim cCL(sqtem,	e488140, 2, (RF, RF_IF),     rd_rm),
15352218822Sdim cCL(sqtez,	e488160, 2, (RF, RF_IF),     rd_rm),
15353218822Sdim
15354218822Sdim cCL(logs,	e508100, 2, (RF, RF_IF),     rd_rm),
15355218822Sdim cCL(logsp,	e508120, 2, (RF, RF_IF),     rd_rm),
15356218822Sdim cCL(logsm,	e508140, 2, (RF, RF_IF),     rd_rm),
15357218822Sdim cCL(logsz,	e508160, 2, (RF, RF_IF),     rd_rm),
15358218822Sdim cCL(logd,	e508180, 2, (RF, RF_IF),     rd_rm),
15359218822Sdim cCL(logdp,	e5081a0, 2, (RF, RF_IF),     rd_rm),
15360218822Sdim cCL(logdm,	e5081c0, 2, (RF, RF_IF),     rd_rm),
15361218822Sdim cCL(logdz,	e5081e0, 2, (RF, RF_IF),     rd_rm),
15362218822Sdim cCL(loge,	e588100, 2, (RF, RF_IF),     rd_rm),
15363218822Sdim cCL(logep,	e588120, 2, (RF, RF_IF),     rd_rm),
15364218822Sdim cCL(logem,	e588140, 2, (RF, RF_IF),     rd_rm),
15365218822Sdim cCL(logez,	e588160, 2, (RF, RF_IF),     rd_rm),
15366218822Sdim
15367218822Sdim cCL(lgns,	e608100, 2, (RF, RF_IF),     rd_rm),
15368218822Sdim cCL(lgnsp,	e608120, 2, (RF, RF_IF),     rd_rm),
15369218822Sdim cCL(lgnsm,	e608140, 2, (RF, RF_IF),     rd_rm),
15370218822Sdim cCL(lgnsz,	e608160, 2, (RF, RF_IF),     rd_rm),
15371218822Sdim cCL(lgnd,	e608180, 2, (RF, RF_IF),     rd_rm),
15372218822Sdim cCL(lgndp,	e6081a0, 2, (RF, RF_IF),     rd_rm),
15373218822Sdim cCL(lgndm,	e6081c0, 2, (RF, RF_IF),     rd_rm),
15374218822Sdim cCL(lgndz,	e6081e0, 2, (RF, RF_IF),     rd_rm),
15375218822Sdim cCL(lgne,	e688100, 2, (RF, RF_IF),     rd_rm),
15376218822Sdim cCL(lgnep,	e688120, 2, (RF, RF_IF),     rd_rm),
15377218822Sdim cCL(lgnem,	e688140, 2, (RF, RF_IF),     rd_rm),
15378218822Sdim cCL(lgnez,	e688160, 2, (RF, RF_IF),     rd_rm),
15379218822Sdim
15380218822Sdim cCL(exps,	e708100, 2, (RF, RF_IF),     rd_rm),
15381218822Sdim cCL(expsp,	e708120, 2, (RF, RF_IF),     rd_rm),
15382218822Sdim cCL(expsm,	e708140, 2, (RF, RF_IF),     rd_rm),
15383218822Sdim cCL(expsz,	e708160, 2, (RF, RF_IF),     rd_rm),
15384218822Sdim cCL(expd,	e708180, 2, (RF, RF_IF),     rd_rm),
15385218822Sdim cCL(expdp,	e7081a0, 2, (RF, RF_IF),     rd_rm),
15386218822Sdim cCL(expdm,	e7081c0, 2, (RF, RF_IF),     rd_rm),
15387218822Sdim cCL(expdz,	e7081e0, 2, (RF, RF_IF),     rd_rm),
15388218822Sdim cCL(expe,	e788100, 2, (RF, RF_IF),     rd_rm),
15389218822Sdim cCL(expep,	e788120, 2, (RF, RF_IF),     rd_rm),
15390218822Sdim cCL(expem,	e788140, 2, (RF, RF_IF),     rd_rm),
15391218822Sdim cCL(expdz,	e788160, 2, (RF, RF_IF),     rd_rm),
15392218822Sdim
15393218822Sdim cCL(sins,	e808100, 2, (RF, RF_IF),     rd_rm),
15394218822Sdim cCL(sinsp,	e808120, 2, (RF, RF_IF),     rd_rm),
15395218822Sdim cCL(sinsm,	e808140, 2, (RF, RF_IF),     rd_rm),
15396218822Sdim cCL(sinsz,	e808160, 2, (RF, RF_IF),     rd_rm),
15397218822Sdim cCL(sind,	e808180, 2, (RF, RF_IF),     rd_rm),
15398218822Sdim cCL(sindp,	e8081a0, 2, (RF, RF_IF),     rd_rm),
15399218822Sdim cCL(sindm,	e8081c0, 2, (RF, RF_IF),     rd_rm),
15400218822Sdim cCL(sindz,	e8081e0, 2, (RF, RF_IF),     rd_rm),
15401218822Sdim cCL(sine,	e888100, 2, (RF, RF_IF),     rd_rm),
15402218822Sdim cCL(sinep,	e888120, 2, (RF, RF_IF),     rd_rm),
15403218822Sdim cCL(sinem,	e888140, 2, (RF, RF_IF),     rd_rm),
15404218822Sdim cCL(sinez,	e888160, 2, (RF, RF_IF),     rd_rm),
15405218822Sdim
15406218822Sdim cCL(coss,	e908100, 2, (RF, RF_IF),     rd_rm),
15407218822Sdim cCL(cossp,	e908120, 2, (RF, RF_IF),     rd_rm),
15408218822Sdim cCL(cossm,	e908140, 2, (RF, RF_IF),     rd_rm),
15409218822Sdim cCL(cossz,	e908160, 2, (RF, RF_IF),     rd_rm),
15410218822Sdim cCL(cosd,	e908180, 2, (RF, RF_IF),     rd_rm),
15411218822Sdim cCL(cosdp,	e9081a0, 2, (RF, RF_IF),     rd_rm),
15412218822Sdim cCL(cosdm,	e9081c0, 2, (RF, RF_IF),     rd_rm),
15413218822Sdim cCL(cosdz,	e9081e0, 2, (RF, RF_IF),     rd_rm),
15414218822Sdim cCL(cose,	e988100, 2, (RF, RF_IF),     rd_rm),
15415218822Sdim cCL(cosep,	e988120, 2, (RF, RF_IF),     rd_rm),
15416218822Sdim cCL(cosem,	e988140, 2, (RF, RF_IF),     rd_rm),
15417218822Sdim cCL(cosez,	e988160, 2, (RF, RF_IF),     rd_rm),
15418218822Sdim
15419218822Sdim cCL(tans,	ea08100, 2, (RF, RF_IF),     rd_rm),
15420218822Sdim cCL(tansp,	ea08120, 2, (RF, RF_IF),     rd_rm),
15421218822Sdim cCL(tansm,	ea08140, 2, (RF, RF_IF),     rd_rm),
15422218822Sdim cCL(tansz,	ea08160, 2, (RF, RF_IF),     rd_rm),
15423218822Sdim cCL(tand,	ea08180, 2, (RF, RF_IF),     rd_rm),
15424218822Sdim cCL(tandp,	ea081a0, 2, (RF, RF_IF),     rd_rm),
15425218822Sdim cCL(tandm,	ea081c0, 2, (RF, RF_IF),     rd_rm),
15426218822Sdim cCL(tandz,	ea081e0, 2, (RF, RF_IF),     rd_rm),
15427218822Sdim cCL(tane,	ea88100, 2, (RF, RF_IF),     rd_rm),
15428218822Sdim cCL(tanep,	ea88120, 2, (RF, RF_IF),     rd_rm),
15429218822Sdim cCL(tanem,	ea88140, 2, (RF, RF_IF),     rd_rm),
15430218822Sdim cCL(tanez,	ea88160, 2, (RF, RF_IF),     rd_rm),
15431218822Sdim
15432218822Sdim cCL(asns,	eb08100, 2, (RF, RF_IF),     rd_rm),
15433218822Sdim cCL(asnsp,	eb08120, 2, (RF, RF_IF),     rd_rm),
15434218822Sdim cCL(asnsm,	eb08140, 2, (RF, RF_IF),     rd_rm),
15435218822Sdim cCL(asnsz,	eb08160, 2, (RF, RF_IF),     rd_rm),
15436218822Sdim cCL(asnd,	eb08180, 2, (RF, RF_IF),     rd_rm),
15437218822Sdim cCL(asndp,	eb081a0, 2, (RF, RF_IF),     rd_rm),
15438218822Sdim cCL(asndm,	eb081c0, 2, (RF, RF_IF),     rd_rm),
15439218822Sdim cCL(asndz,	eb081e0, 2, (RF, RF_IF),     rd_rm),
15440218822Sdim cCL(asne,	eb88100, 2, (RF, RF_IF),     rd_rm),
15441218822Sdim cCL(asnep,	eb88120, 2, (RF, RF_IF),     rd_rm),
15442218822Sdim cCL(asnem,	eb88140, 2, (RF, RF_IF),     rd_rm),
15443218822Sdim cCL(asnez,	eb88160, 2, (RF, RF_IF),     rd_rm),
15444218822Sdim
15445218822Sdim cCL(acss,	ec08100, 2, (RF, RF_IF),     rd_rm),
15446218822Sdim cCL(acssp,	ec08120, 2, (RF, RF_IF),     rd_rm),
15447218822Sdim cCL(acssm,	ec08140, 2, (RF, RF_IF),     rd_rm),
15448218822Sdim cCL(acssz,	ec08160, 2, (RF, RF_IF),     rd_rm),
15449218822Sdim cCL(acsd,	ec08180, 2, (RF, RF_IF),     rd_rm),
15450218822Sdim cCL(acsdp,	ec081a0, 2, (RF, RF_IF),     rd_rm),
15451218822Sdim cCL(acsdm,	ec081c0, 2, (RF, RF_IF),     rd_rm),
15452218822Sdim cCL(acsdz,	ec081e0, 2, (RF, RF_IF),     rd_rm),
15453218822Sdim cCL(acse,	ec88100, 2, (RF, RF_IF),     rd_rm),
15454218822Sdim cCL(acsep,	ec88120, 2, (RF, RF_IF),     rd_rm),
15455218822Sdim cCL(acsem,	ec88140, 2, (RF, RF_IF),     rd_rm),
15456218822Sdim cCL(acsez,	ec88160, 2, (RF, RF_IF),     rd_rm),
15457218822Sdim
15458218822Sdim cCL(atns,	ed08100, 2, (RF, RF_IF),     rd_rm),
15459218822Sdim cCL(atnsp,	ed08120, 2, (RF, RF_IF),     rd_rm),
15460218822Sdim cCL(atnsm,	ed08140, 2, (RF, RF_IF),     rd_rm),
15461218822Sdim cCL(atnsz,	ed08160, 2, (RF, RF_IF),     rd_rm),
15462218822Sdim cCL(atnd,	ed08180, 2, (RF, RF_IF),     rd_rm),
15463218822Sdim cCL(atndp,	ed081a0, 2, (RF, RF_IF),     rd_rm),
15464218822Sdim cCL(atndm,	ed081c0, 2, (RF, RF_IF),     rd_rm),
15465218822Sdim cCL(atndz,	ed081e0, 2, (RF, RF_IF),     rd_rm),
15466218822Sdim cCL(atne,	ed88100, 2, (RF, RF_IF),     rd_rm),
15467218822Sdim cCL(atnep,	ed88120, 2, (RF, RF_IF),     rd_rm),
15468218822Sdim cCL(atnem,	ed88140, 2, (RF, RF_IF),     rd_rm),
15469218822Sdim cCL(atnez,	ed88160, 2, (RF, RF_IF),     rd_rm),
15470218822Sdim
15471218822Sdim cCL(urds,	ee08100, 2, (RF, RF_IF),     rd_rm),
15472218822Sdim cCL(urdsp,	ee08120, 2, (RF, RF_IF),     rd_rm),
15473218822Sdim cCL(urdsm,	ee08140, 2, (RF, RF_IF),     rd_rm),
15474218822Sdim cCL(urdsz,	ee08160, 2, (RF, RF_IF),     rd_rm),
15475218822Sdim cCL(urdd,	ee08180, 2, (RF, RF_IF),     rd_rm),
15476218822Sdim cCL(urddp,	ee081a0, 2, (RF, RF_IF),     rd_rm),
15477218822Sdim cCL(urddm,	ee081c0, 2, (RF, RF_IF),     rd_rm),
15478218822Sdim cCL(urddz,	ee081e0, 2, (RF, RF_IF),     rd_rm),
15479218822Sdim cCL(urde,	ee88100, 2, (RF, RF_IF),     rd_rm),
15480218822Sdim cCL(urdep,	ee88120, 2, (RF, RF_IF),     rd_rm),
15481218822Sdim cCL(urdem,	ee88140, 2, (RF, RF_IF),     rd_rm),
15482218822Sdim cCL(urdez,	ee88160, 2, (RF, RF_IF),     rd_rm),
15483218822Sdim
15484218822Sdim cCL(nrms,	ef08100, 2, (RF, RF_IF),     rd_rm),
15485218822Sdim cCL(nrmsp,	ef08120, 2, (RF, RF_IF),     rd_rm),
15486218822Sdim cCL(nrmsm,	ef08140, 2, (RF, RF_IF),     rd_rm),
15487218822Sdim cCL(nrmsz,	ef08160, 2, (RF, RF_IF),     rd_rm),
15488218822Sdim cCL(nrmd,	ef08180, 2, (RF, RF_IF),     rd_rm),
15489218822Sdim cCL(nrmdp,	ef081a0, 2, (RF, RF_IF),     rd_rm),
15490218822Sdim cCL(nrmdm,	ef081c0, 2, (RF, RF_IF),     rd_rm),
15491218822Sdim cCL(nrmdz,	ef081e0, 2, (RF, RF_IF),     rd_rm),
15492218822Sdim cCL(nrme,	ef88100, 2, (RF, RF_IF),     rd_rm),
15493218822Sdim cCL(nrmep,	ef88120, 2, (RF, RF_IF),     rd_rm),
15494218822Sdim cCL(nrmem,	ef88140, 2, (RF, RF_IF),     rd_rm),
15495218822Sdim cCL(nrmez,	ef88160, 2, (RF, RF_IF),     rd_rm),
15496218822Sdim
15497218822Sdim cCL(adfs,	e000100, 3, (RF, RF, RF_IF), rd_rn_rm),
15498218822Sdim cCL(adfsp,	e000120, 3, (RF, RF, RF_IF), rd_rn_rm),
15499218822Sdim cCL(adfsm,	e000140, 3, (RF, RF, RF_IF), rd_rn_rm),
15500218822Sdim cCL(adfsz,	e000160, 3, (RF, RF, RF_IF), rd_rn_rm),
15501218822Sdim cCL(adfd,	e000180, 3, (RF, RF, RF_IF), rd_rn_rm),
15502218822Sdim cCL(adfdp,	e0001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15503218822Sdim cCL(adfdm,	e0001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15504218822Sdim cCL(adfdz,	e0001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15505218822Sdim cCL(adfe,	e080100, 3, (RF, RF, RF_IF), rd_rn_rm),
15506218822Sdim cCL(adfep,	e080120, 3, (RF, RF, RF_IF), rd_rn_rm),
15507218822Sdim cCL(adfem,	e080140, 3, (RF, RF, RF_IF), rd_rn_rm),
15508218822Sdim cCL(adfez,	e080160, 3, (RF, RF, RF_IF), rd_rn_rm),
15509218822Sdim
15510218822Sdim cCL(sufs,	e200100, 3, (RF, RF, RF_IF), rd_rn_rm),
15511218822Sdim cCL(sufsp,	e200120, 3, (RF, RF, RF_IF), rd_rn_rm),
15512218822Sdim cCL(sufsm,	e200140, 3, (RF, RF, RF_IF), rd_rn_rm),
15513218822Sdim cCL(sufsz,	e200160, 3, (RF, RF, RF_IF), rd_rn_rm),
15514218822Sdim cCL(sufd,	e200180, 3, (RF, RF, RF_IF), rd_rn_rm),
15515218822Sdim cCL(sufdp,	e2001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15516218822Sdim cCL(sufdm,	e2001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15517218822Sdim cCL(sufdz,	e2001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15518218822Sdim cCL(sufe,	e280100, 3, (RF, RF, RF_IF), rd_rn_rm),
15519218822Sdim cCL(sufep,	e280120, 3, (RF, RF, RF_IF), rd_rn_rm),
15520218822Sdim cCL(sufem,	e280140, 3, (RF, RF, RF_IF), rd_rn_rm),
15521218822Sdim cCL(sufez,	e280160, 3, (RF, RF, RF_IF), rd_rn_rm),
15522218822Sdim
15523218822Sdim cCL(rsfs,	e300100, 3, (RF, RF, RF_IF), rd_rn_rm),
15524218822Sdim cCL(rsfsp,	e300120, 3, (RF, RF, RF_IF), rd_rn_rm),
15525218822Sdim cCL(rsfsm,	e300140, 3, (RF, RF, RF_IF), rd_rn_rm),
15526218822Sdim cCL(rsfsz,	e300160, 3, (RF, RF, RF_IF), rd_rn_rm),
15527218822Sdim cCL(rsfd,	e300180, 3, (RF, RF, RF_IF), rd_rn_rm),
15528218822Sdim cCL(rsfdp,	e3001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15529218822Sdim cCL(rsfdm,	e3001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15530218822Sdim cCL(rsfdz,	e3001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15531218822Sdim cCL(rsfe,	e380100, 3, (RF, RF, RF_IF), rd_rn_rm),
15532218822Sdim cCL(rsfep,	e380120, 3, (RF, RF, RF_IF), rd_rn_rm),
15533218822Sdim cCL(rsfem,	e380140, 3, (RF, RF, RF_IF), rd_rn_rm),
15534218822Sdim cCL(rsfez,	e380160, 3, (RF, RF, RF_IF), rd_rn_rm),
15535218822Sdim
15536218822Sdim cCL(mufs,	e100100, 3, (RF, RF, RF_IF), rd_rn_rm),
15537218822Sdim cCL(mufsp,	e100120, 3, (RF, RF, RF_IF), rd_rn_rm),
15538218822Sdim cCL(mufsm,	e100140, 3, (RF, RF, RF_IF), rd_rn_rm),
15539218822Sdim cCL(mufsz,	e100160, 3, (RF, RF, RF_IF), rd_rn_rm),
15540218822Sdim cCL(mufd,	e100180, 3, (RF, RF, RF_IF), rd_rn_rm),
15541218822Sdim cCL(mufdp,	e1001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15542218822Sdim cCL(mufdm,	e1001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15543218822Sdim cCL(mufdz,	e1001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15544218822Sdim cCL(mufe,	e180100, 3, (RF, RF, RF_IF), rd_rn_rm),
15545218822Sdim cCL(mufep,	e180120, 3, (RF, RF, RF_IF), rd_rn_rm),
15546218822Sdim cCL(mufem,	e180140, 3, (RF, RF, RF_IF), rd_rn_rm),
15547218822Sdim cCL(mufez,	e180160, 3, (RF, RF, RF_IF), rd_rn_rm),
15548218822Sdim
15549218822Sdim cCL(dvfs,	e400100, 3, (RF, RF, RF_IF), rd_rn_rm),
15550218822Sdim cCL(dvfsp,	e400120, 3, (RF, RF, RF_IF), rd_rn_rm),
15551218822Sdim cCL(dvfsm,	e400140, 3, (RF, RF, RF_IF), rd_rn_rm),
15552218822Sdim cCL(dvfsz,	e400160, 3, (RF, RF, RF_IF), rd_rn_rm),
15553218822Sdim cCL(dvfd,	e400180, 3, (RF, RF, RF_IF), rd_rn_rm),
15554218822Sdim cCL(dvfdp,	e4001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15555218822Sdim cCL(dvfdm,	e4001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15556218822Sdim cCL(dvfdz,	e4001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15557218822Sdim cCL(dvfe,	e480100, 3, (RF, RF, RF_IF), rd_rn_rm),
15558218822Sdim cCL(dvfep,	e480120, 3, (RF, RF, RF_IF), rd_rn_rm),
15559218822Sdim cCL(dvfem,	e480140, 3, (RF, RF, RF_IF), rd_rn_rm),
15560218822Sdim cCL(dvfez,	e480160, 3, (RF, RF, RF_IF), rd_rn_rm),
15561218822Sdim
15562218822Sdim cCL(rdfs,	e500100, 3, (RF, RF, RF_IF), rd_rn_rm),
15563218822Sdim cCL(rdfsp,	e500120, 3, (RF, RF, RF_IF), rd_rn_rm),
15564218822Sdim cCL(rdfsm,	e500140, 3, (RF, RF, RF_IF), rd_rn_rm),
15565218822Sdim cCL(rdfsz,	e500160, 3, (RF, RF, RF_IF), rd_rn_rm),
15566218822Sdim cCL(rdfd,	e500180, 3, (RF, RF, RF_IF), rd_rn_rm),
15567218822Sdim cCL(rdfdp,	e5001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15568218822Sdim cCL(rdfdm,	e5001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15569218822Sdim cCL(rdfdz,	e5001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15570218822Sdim cCL(rdfe,	e580100, 3, (RF, RF, RF_IF), rd_rn_rm),
15571218822Sdim cCL(rdfep,	e580120, 3, (RF, RF, RF_IF), rd_rn_rm),
15572218822Sdim cCL(rdfem,	e580140, 3, (RF, RF, RF_IF), rd_rn_rm),
15573218822Sdim cCL(rdfez,	e580160, 3, (RF, RF, RF_IF), rd_rn_rm),
15574218822Sdim
15575218822Sdim cCL(pows,	e600100, 3, (RF, RF, RF_IF), rd_rn_rm),
15576218822Sdim cCL(powsp,	e600120, 3, (RF, RF, RF_IF), rd_rn_rm),
15577218822Sdim cCL(powsm,	e600140, 3, (RF, RF, RF_IF), rd_rn_rm),
15578218822Sdim cCL(powsz,	e600160, 3, (RF, RF, RF_IF), rd_rn_rm),
15579218822Sdim cCL(powd,	e600180, 3, (RF, RF, RF_IF), rd_rn_rm),
15580218822Sdim cCL(powdp,	e6001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15581218822Sdim cCL(powdm,	e6001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15582218822Sdim cCL(powdz,	e6001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15583218822Sdim cCL(powe,	e680100, 3, (RF, RF, RF_IF), rd_rn_rm),
15584218822Sdim cCL(powep,	e680120, 3, (RF, RF, RF_IF), rd_rn_rm),
15585218822Sdim cCL(powem,	e680140, 3, (RF, RF, RF_IF), rd_rn_rm),
15586218822Sdim cCL(powez,	e680160, 3, (RF, RF, RF_IF), rd_rn_rm),
15587218822Sdim
15588218822Sdim cCL(rpws,	e700100, 3, (RF, RF, RF_IF), rd_rn_rm),
15589218822Sdim cCL(rpwsp,	e700120, 3, (RF, RF, RF_IF), rd_rn_rm),
15590218822Sdim cCL(rpwsm,	e700140, 3, (RF, RF, RF_IF), rd_rn_rm),
15591218822Sdim cCL(rpwsz,	e700160, 3, (RF, RF, RF_IF), rd_rn_rm),
15592218822Sdim cCL(rpwd,	e700180, 3, (RF, RF, RF_IF), rd_rn_rm),
15593218822Sdim cCL(rpwdp,	e7001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15594218822Sdim cCL(rpwdm,	e7001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15595218822Sdim cCL(rpwdz,	e7001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15596218822Sdim cCL(rpwe,	e780100, 3, (RF, RF, RF_IF), rd_rn_rm),
15597218822Sdim cCL(rpwep,	e780120, 3, (RF, RF, RF_IF), rd_rn_rm),
15598218822Sdim cCL(rpwem,	e780140, 3, (RF, RF, RF_IF), rd_rn_rm),
15599218822Sdim cCL(rpwez,	e780160, 3, (RF, RF, RF_IF), rd_rn_rm),
15600218822Sdim
15601218822Sdim cCL(rmfs,	e800100, 3, (RF, RF, RF_IF), rd_rn_rm),
15602218822Sdim cCL(rmfsp,	e800120, 3, (RF, RF, RF_IF), rd_rn_rm),
15603218822Sdim cCL(rmfsm,	e800140, 3, (RF, RF, RF_IF), rd_rn_rm),
15604218822Sdim cCL(rmfsz,	e800160, 3, (RF, RF, RF_IF), rd_rn_rm),
15605218822Sdim cCL(rmfd,	e800180, 3, (RF, RF, RF_IF), rd_rn_rm),
15606218822Sdim cCL(rmfdp,	e8001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15607218822Sdim cCL(rmfdm,	e8001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15608218822Sdim cCL(rmfdz,	e8001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15609218822Sdim cCL(rmfe,	e880100, 3, (RF, RF, RF_IF), rd_rn_rm),
15610218822Sdim cCL(rmfep,	e880120, 3, (RF, RF, RF_IF), rd_rn_rm),
15611218822Sdim cCL(rmfem,	e880140, 3, (RF, RF, RF_IF), rd_rn_rm),
15612218822Sdim cCL(rmfez,	e880160, 3, (RF, RF, RF_IF), rd_rn_rm),
15613218822Sdim
15614218822Sdim cCL(fmls,	e900100, 3, (RF, RF, RF_IF), rd_rn_rm),
15615218822Sdim cCL(fmlsp,	e900120, 3, (RF, RF, RF_IF), rd_rn_rm),
15616218822Sdim cCL(fmlsm,	e900140, 3, (RF, RF, RF_IF), rd_rn_rm),
15617218822Sdim cCL(fmlsz,	e900160, 3, (RF, RF, RF_IF), rd_rn_rm),
15618218822Sdim cCL(fmld,	e900180, 3, (RF, RF, RF_IF), rd_rn_rm),
15619218822Sdim cCL(fmldp,	e9001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15620218822Sdim cCL(fmldm,	e9001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15621218822Sdim cCL(fmldz,	e9001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15622218822Sdim cCL(fmle,	e980100, 3, (RF, RF, RF_IF), rd_rn_rm),
15623218822Sdim cCL(fmlep,	e980120, 3, (RF, RF, RF_IF), rd_rn_rm),
15624218822Sdim cCL(fmlem,	e980140, 3, (RF, RF, RF_IF), rd_rn_rm),
15625218822Sdim cCL(fmlez,	e980160, 3, (RF, RF, RF_IF), rd_rn_rm),
15626218822Sdim
15627218822Sdim cCL(fdvs,	ea00100, 3, (RF, RF, RF_IF), rd_rn_rm),
15628218822Sdim cCL(fdvsp,	ea00120, 3, (RF, RF, RF_IF), rd_rn_rm),
15629218822Sdim cCL(fdvsm,	ea00140, 3, (RF, RF, RF_IF), rd_rn_rm),
15630218822Sdim cCL(fdvsz,	ea00160, 3, (RF, RF, RF_IF), rd_rn_rm),
15631218822Sdim cCL(fdvd,	ea00180, 3, (RF, RF, RF_IF), rd_rn_rm),
15632218822Sdim cCL(fdvdp,	ea001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15633218822Sdim cCL(fdvdm,	ea001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15634218822Sdim cCL(fdvdz,	ea001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15635218822Sdim cCL(fdve,	ea80100, 3, (RF, RF, RF_IF), rd_rn_rm),
15636218822Sdim cCL(fdvep,	ea80120, 3, (RF, RF, RF_IF), rd_rn_rm),
15637218822Sdim cCL(fdvem,	ea80140, 3, (RF, RF, RF_IF), rd_rn_rm),
15638218822Sdim cCL(fdvez,	ea80160, 3, (RF, RF, RF_IF), rd_rn_rm),
15639218822Sdim
15640218822Sdim cCL(frds,	eb00100, 3, (RF, RF, RF_IF), rd_rn_rm),
15641218822Sdim cCL(frdsp,	eb00120, 3, (RF, RF, RF_IF), rd_rn_rm),
15642218822Sdim cCL(frdsm,	eb00140, 3, (RF, RF, RF_IF), rd_rn_rm),
15643218822Sdim cCL(frdsz,	eb00160, 3, (RF, RF, RF_IF), rd_rn_rm),
15644218822Sdim cCL(frdd,	eb00180, 3, (RF, RF, RF_IF), rd_rn_rm),
15645218822Sdim cCL(frddp,	eb001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15646218822Sdim cCL(frddm,	eb001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15647218822Sdim cCL(frddz,	eb001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15648218822Sdim cCL(frde,	eb80100, 3, (RF, RF, RF_IF), rd_rn_rm),
15649218822Sdim cCL(frdep,	eb80120, 3, (RF, RF, RF_IF), rd_rn_rm),
15650218822Sdim cCL(frdem,	eb80140, 3, (RF, RF, RF_IF), rd_rn_rm),
15651218822Sdim cCL(frdez,	eb80160, 3, (RF, RF, RF_IF), rd_rn_rm),
15652218822Sdim
15653218822Sdim cCL(pols,	ec00100, 3, (RF, RF, RF_IF), rd_rn_rm),
15654218822Sdim cCL(polsp,	ec00120, 3, (RF, RF, RF_IF), rd_rn_rm),
15655218822Sdim cCL(polsm,	ec00140, 3, (RF, RF, RF_IF), rd_rn_rm),
15656218822Sdim cCL(polsz,	ec00160, 3, (RF, RF, RF_IF), rd_rn_rm),
15657218822Sdim cCL(pold,	ec00180, 3, (RF, RF, RF_IF), rd_rn_rm),
15658218822Sdim cCL(poldp,	ec001a0, 3, (RF, RF, RF_IF), rd_rn_rm),
15659218822Sdim cCL(poldm,	ec001c0, 3, (RF, RF, RF_IF), rd_rn_rm),
15660218822Sdim cCL(poldz,	ec001e0, 3, (RF, RF, RF_IF), rd_rn_rm),
15661218822Sdim cCL(pole,	ec80100, 3, (RF, RF, RF_IF), rd_rn_rm),
15662218822Sdim cCL(polep,	ec80120, 3, (RF, RF, RF_IF), rd_rn_rm),
15663218822Sdim cCL(polem,	ec80140, 3, (RF, RF, RF_IF), rd_rn_rm),
15664218822Sdim cCL(polez,	ec80160, 3, (RF, RF, RF_IF), rd_rn_rm),
15665218822Sdim
15666218822Sdim cCE(cmf,	e90f110, 2, (RF, RF_IF),     fpa_cmp),
15667218822Sdim C3E(cmfe,	ed0f110, 2, (RF, RF_IF),     fpa_cmp),
15668218822Sdim cCE(cnf,	eb0f110, 2, (RF, RF_IF),     fpa_cmp),
15669218822Sdim C3E(cnfe,	ef0f110, 2, (RF, RF_IF),     fpa_cmp),
15670218822Sdim
15671218822Sdim cCL(flts,	e000110, 2, (RF, RR),	     rn_rd),
15672218822Sdim cCL(fltsp,	e000130, 2, (RF, RR),	     rn_rd),
15673218822Sdim cCL(fltsm,	e000150, 2, (RF, RR),	     rn_rd),
15674218822Sdim cCL(fltsz,	e000170, 2, (RF, RR),	     rn_rd),
15675218822Sdim cCL(fltd,	e000190, 2, (RF, RR),	     rn_rd),
15676218822Sdim cCL(fltdp,	e0001b0, 2, (RF, RR),	     rn_rd),
15677218822Sdim cCL(fltdm,	e0001d0, 2, (RF, RR),	     rn_rd),
15678218822Sdim cCL(fltdz,	e0001f0, 2, (RF, RR),	     rn_rd),
15679218822Sdim cCL(flte,	e080110, 2, (RF, RR),	     rn_rd),
15680218822Sdim cCL(fltep,	e080130, 2, (RF, RR),	     rn_rd),
15681218822Sdim cCL(fltem,	e080150, 2, (RF, RR),	     rn_rd),
15682218822Sdim cCL(fltez,	e080170, 2, (RF, RR),	     rn_rd),
15683218822Sdim
15684218822Sdim  /* The implementation of the FIX instruction is broken on some
15685218822Sdim     assemblers, in that it accepts a precision specifier as well as a
15686218822Sdim     rounding specifier, despite the fact that this is meaningless.
15687218822Sdim     To be more compatible, we accept it as well, though of course it
15688218822Sdim     does not set any bits.  */
15689218822Sdim cCE(fix,	e100110, 2, (RR, RF),	     rd_rm),
15690218822Sdim cCL(fixp,	e100130, 2, (RR, RF),	     rd_rm),
15691218822Sdim cCL(fixm,	e100150, 2, (RR, RF),	     rd_rm),
15692218822Sdim cCL(fixz,	e100170, 2, (RR, RF),	     rd_rm),
15693218822Sdim cCL(fixsp,	e100130, 2, (RR, RF),	     rd_rm),
15694218822Sdim cCL(fixsm,	e100150, 2, (RR, RF),	     rd_rm),
15695218822Sdim cCL(fixsz,	e100170, 2, (RR, RF),	     rd_rm),
15696218822Sdim cCL(fixdp,	e100130, 2, (RR, RF),	     rd_rm),
15697218822Sdim cCL(fixdm,	e100150, 2, (RR, RF),	     rd_rm),
15698218822Sdim cCL(fixdz,	e100170, 2, (RR, RF),	     rd_rm),
15699218822Sdim cCL(fixep,	e100130, 2, (RR, RF),	     rd_rm),
15700218822Sdim cCL(fixem,	e100150, 2, (RR, RF),	     rd_rm),
15701218822Sdim cCL(fixez,	e100170, 2, (RR, RF),	     rd_rm),
15702218822Sdim
15703218822Sdim  /* Instructions that were new with the real FPA, call them V2.  */
15704218822Sdim#undef ARM_VARIANT
15705218822Sdim#define ARM_VARIANT &fpu_fpa_ext_v2
15706218822Sdim cCE(lfm,	c100200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15707218822Sdim cCL(lfmfd,	c900200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15708218822Sdim cCL(lfmea,	d100200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15709218822Sdim cCE(sfm,	c000200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15710218822Sdim cCL(sfmfd,	d000200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15711218822Sdim cCL(sfmea,	c800200, 3, (RF, I4b, ADDR), fpa_ldmstm),
15712218822Sdim
15713218822Sdim#undef ARM_VARIANT
15714218822Sdim#define ARM_VARIANT &fpu_vfp_ext_v1xd  /* VFP V1xD (single precision).  */
15715218822Sdim  /* Moves and type conversions.  */
15716218822Sdim cCE(fcpys,	eb00a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15717218822Sdim cCE(fmrs,	e100a10, 2, (RR, RVS),	      vfp_reg_from_sp),
15718218822Sdim cCE(fmsr,	e000a10, 2, (RVS, RR),	      vfp_sp_from_reg),
15719218822Sdim cCE(fmstat,	ef1fa10, 0, (),		      noargs),
15720218822Sdim cCE(fsitos,	eb80ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15721218822Sdim cCE(fuitos,	eb80a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15722218822Sdim cCE(ftosis,	ebd0a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15723218822Sdim cCE(ftosizs,	ebd0ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15724218822Sdim cCE(ftouis,	ebc0a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15725218822Sdim cCE(ftouizs,	ebc0ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15726218822Sdim cCE(fmrx,	ef00a10, 2, (RR, RVC),	      rd_rn),
15727218822Sdim cCE(fmxr,	ee00a10, 2, (RVC, RR),	      rn_rd),
15728218822Sdim
15729218822Sdim  /* Memory operations.	 */
15730218822Sdim cCE(flds,	d100a00, 2, (RVS, ADDRGLDC),  vfp_sp_ldst),
15731218822Sdim cCE(fsts,	d000a00, 2, (RVS, ADDRGLDC),  vfp_sp_ldst),
15732218822Sdim cCE(fldmias,	c900a00, 2, (RRw, VRSLST),    vfp_sp_ldstmia),
15733218822Sdim cCE(fldmfds,	c900a00, 2, (RRw, VRSLST),    vfp_sp_ldstmia),
15734218822Sdim cCE(fldmdbs,	d300a00, 2, (RRw, VRSLST),    vfp_sp_ldstmdb),
15735218822Sdim cCE(fldmeas,	d300a00, 2, (RRw, VRSLST),    vfp_sp_ldstmdb),
15736218822Sdim cCE(fldmiax,	c900b00, 2, (RRw, VRDLST),    vfp_xp_ldstmia),
15737218822Sdim cCE(fldmfdx,	c900b00, 2, (RRw, VRDLST),    vfp_xp_ldstmia),
15738218822Sdim cCE(fldmdbx,	d300b00, 2, (RRw, VRDLST),    vfp_xp_ldstmdb),
15739218822Sdim cCE(fldmeax,	d300b00, 2, (RRw, VRDLST),    vfp_xp_ldstmdb),
15740218822Sdim cCE(fstmias,	c800a00, 2, (RRw, VRSLST),    vfp_sp_ldstmia),
15741218822Sdim cCE(fstmeas,	c800a00, 2, (RRw, VRSLST),    vfp_sp_ldstmia),
15742218822Sdim cCE(fstmdbs,	d200a00, 2, (RRw, VRSLST),    vfp_sp_ldstmdb),
15743218822Sdim cCE(fstmfds,	d200a00, 2, (RRw, VRSLST),    vfp_sp_ldstmdb),
15744218822Sdim cCE(fstmiax,	c800b00, 2, (RRw, VRDLST),    vfp_xp_ldstmia),
15745218822Sdim cCE(fstmeax,	c800b00, 2, (RRw, VRDLST),    vfp_xp_ldstmia),
15746218822Sdim cCE(fstmdbx,	d200b00, 2, (RRw, VRDLST),    vfp_xp_ldstmdb),
15747218822Sdim cCE(fstmfdx,	d200b00, 2, (RRw, VRDLST),    vfp_xp_ldstmdb),
15748218822Sdim
15749218822Sdim  /* Monadic operations.  */
15750218822Sdim cCE(fabss,	eb00ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15751218822Sdim cCE(fnegs,	eb10a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15752218822Sdim cCE(fsqrts,	eb10ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15753218822Sdim
15754218822Sdim  /* Dyadic operations.	 */
15755218822Sdim cCE(fadds,	e300a00, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15756218822Sdim cCE(fsubs,	e300a40, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15757218822Sdim cCE(fmuls,	e200a00, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15758218822Sdim cCE(fdivs,	e800a00, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15759218822Sdim cCE(fmacs,	e000a00, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15760218822Sdim cCE(fmscs,	e100a00, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15761218822Sdim cCE(fnmuls,	e200a40, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15762218822Sdim cCE(fnmacs,	e000a40, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15763218822Sdim cCE(fnmscs,	e100a40, 3, (RVS, RVS, RVS),  vfp_sp_dyadic),
15764218822Sdim
15765218822Sdim  /* Comparisons.  */
15766218822Sdim cCE(fcmps,	eb40a40, 2, (RVS, RVS),	      vfp_sp_monadic),
15767218822Sdim cCE(fcmpzs,	eb50a40, 1, (RVS),	      vfp_sp_compare_z),
15768218822Sdim cCE(fcmpes,	eb40ac0, 2, (RVS, RVS),	      vfp_sp_monadic),
15769218822Sdim cCE(fcmpezs,	eb50ac0, 1, (RVS),	      vfp_sp_compare_z),
15770218822Sdim
15771218822Sdim#undef ARM_VARIANT
15772218822Sdim#define ARM_VARIANT &fpu_vfp_ext_v1 /* VFP V1 (Double precision).  */
15773218822Sdim  /* Moves and type conversions.  */
15774218822Sdim cCE(fcpyd,	eb00b40, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15775218822Sdim cCE(fcvtds,	eb70ac0, 2, (RVD, RVS),	      vfp_dp_sp_cvt),
15776218822Sdim cCE(fcvtsd,	eb70bc0, 2, (RVS, RVD),	      vfp_sp_dp_cvt),
15777218822Sdim cCE(fmdhr,	e200b10, 2, (RVD, RR),	      vfp_dp_rn_rd),
15778218822Sdim cCE(fmdlr,	e000b10, 2, (RVD, RR),	      vfp_dp_rn_rd),
15779218822Sdim cCE(fmrdh,	e300b10, 2, (RR, RVD),	      vfp_dp_rd_rn),
15780218822Sdim cCE(fmrdl,	e100b10, 2, (RR, RVD),	      vfp_dp_rd_rn),
15781218822Sdim cCE(fsitod,	eb80bc0, 2, (RVD, RVS),	      vfp_dp_sp_cvt),
15782218822Sdim cCE(fuitod,	eb80b40, 2, (RVD, RVS),	      vfp_dp_sp_cvt),
15783218822Sdim cCE(ftosid,	ebd0b40, 2, (RVS, RVD),	      vfp_sp_dp_cvt),
15784218822Sdim cCE(ftosizd,	ebd0bc0, 2, (RVS, RVD),	      vfp_sp_dp_cvt),
15785218822Sdim cCE(ftouid,	ebc0b40, 2, (RVS, RVD),	      vfp_sp_dp_cvt),
15786218822Sdim cCE(ftouizd,	ebc0bc0, 2, (RVS, RVD),	      vfp_sp_dp_cvt),
15787218822Sdim
15788218822Sdim  /* Memory operations.	 */
15789218822Sdim cCE(fldd,	d100b00, 2, (RVD, ADDRGLDC),  vfp_dp_ldst),
15790218822Sdim cCE(fstd,	d000b00, 2, (RVD, ADDRGLDC),  vfp_dp_ldst),
15791218822Sdim cCE(fldmiad,	c900b00, 2, (RRw, VRDLST),    vfp_dp_ldstmia),
15792218822Sdim cCE(fldmfdd,	c900b00, 2, (RRw, VRDLST),    vfp_dp_ldstmia),
15793218822Sdim cCE(fldmdbd,	d300b00, 2, (RRw, VRDLST),    vfp_dp_ldstmdb),
15794218822Sdim cCE(fldmead,	d300b00, 2, (RRw, VRDLST),    vfp_dp_ldstmdb),
15795218822Sdim cCE(fstmiad,	c800b00, 2, (RRw, VRDLST),    vfp_dp_ldstmia),
15796218822Sdim cCE(fstmead,	c800b00, 2, (RRw, VRDLST),    vfp_dp_ldstmia),
15797218822Sdim cCE(fstmdbd,	d200b00, 2, (RRw, VRDLST),    vfp_dp_ldstmdb),
15798218822Sdim cCE(fstmfdd,	d200b00, 2, (RRw, VRDLST),    vfp_dp_ldstmdb),
15799218822Sdim
15800218822Sdim  /* Monadic operations.  */
15801218822Sdim cCE(fabsd,	eb00bc0, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15802218822Sdim cCE(fnegd,	eb10b40, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15803218822Sdim cCE(fsqrtd,	eb10bc0, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15804218822Sdim
15805218822Sdim  /* Dyadic operations.	 */
15806218822Sdim cCE(faddd,	e300b00, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15807218822Sdim cCE(fsubd,	e300b40, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15808218822Sdim cCE(fmuld,	e200b00, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15809218822Sdim cCE(fdivd,	e800b00, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15810218822Sdim cCE(fmacd,	e000b00, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15811218822Sdim cCE(fmscd,	e100b00, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15812218822Sdim cCE(fnmuld,	e200b40, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15813218822Sdim cCE(fnmacd,	e000b40, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15814218822Sdim cCE(fnmscd,	e100b40, 3, (RVD, RVD, RVD),  vfp_dp_rd_rn_rm),
15815218822Sdim
15816218822Sdim  /* Comparisons.  */
15817218822Sdim cCE(fcmpd,	eb40b40, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15818218822Sdim cCE(fcmpzd,	eb50b40, 1, (RVD),	      vfp_dp_rd),
15819218822Sdim cCE(fcmped,	eb40bc0, 2, (RVD, RVD),	      vfp_dp_rd_rm),
15820218822Sdim cCE(fcmpezd,	eb50bc0, 1, (RVD),	      vfp_dp_rd),
15821218822Sdim
15822218822Sdim#undef ARM_VARIANT
15823218822Sdim#define ARM_VARIANT &fpu_vfp_ext_v2
15824218822Sdim cCE(fmsrr,	c400a10, 3, (VRSLST, RR, RR), vfp_sp2_from_reg2),
15825218822Sdim cCE(fmrrs,	c500a10, 3, (RR, RR, VRSLST), vfp_reg2_from_sp2),
15826218822Sdim cCE(fmdrr,	c400b10, 3, (RVD, RR, RR),    vfp_dp_rm_rd_rn),
15827218822Sdim cCE(fmrrd,	c500b10, 3, (RR, RR, RVD),    vfp_dp_rd_rn_rm),
15828218822Sdim
15829218822Sdim/* Instructions which may belong to either the Neon or VFP instruction sets.
15830218822Sdim   Individual encoder functions perform additional architecture checks.  */
15831218822Sdim#undef ARM_VARIANT
15832218822Sdim#define ARM_VARIANT &fpu_vfp_ext_v1xd
15833218822Sdim#undef THUMB_VARIANT
15834218822Sdim#define THUMB_VARIANT &fpu_vfp_ext_v1xd
15835218822Sdim  /* These mnemonics are unique to VFP.  */
15836218822Sdim NCE(vsqrt,     0,       2, (RVSD, RVSD),       vfp_nsyn_sqrt),
15837218822Sdim NCE(vdiv,      0,       3, (RVSD, RVSD, RVSD), vfp_nsyn_div),
15838218822Sdim nCE(vnmul,     vnmul,   3, (RVSD, RVSD, RVSD), vfp_nsyn_nmul),
15839218822Sdim nCE(vnmla,     vnmla,   3, (RVSD, RVSD, RVSD), vfp_nsyn_nmul),
15840218822Sdim nCE(vnmls,     vnmls,   3, (RVSD, RVSD, RVSD), vfp_nsyn_nmul),
15841218822Sdim nCE(vcmp,      vcmp,    2, (RVSD, RVSD_I0),    vfp_nsyn_cmp),
15842218822Sdim nCE(vcmpe,     vcmpe,   2, (RVSD, RVSD_I0),    vfp_nsyn_cmp),
15843218822Sdim NCE(vpush,     0,       1, (VRSDLST),          vfp_nsyn_push),
15844218822Sdim NCE(vpop,      0,       1, (VRSDLST),          vfp_nsyn_pop),
15845218822Sdim NCE(vcvtz,     0,       2, (RVSD, RVSD),       vfp_nsyn_cvtz),
15846218822Sdim
15847218822Sdim  /* Mnemonics shared by Neon and VFP.  */
15848218822Sdim nCEF(vmul,     vmul,    3, (RNSDQ, oRNSDQ, RNSDQ_RNSC), neon_mul),
15849218822Sdim nCEF(vmla,     vmla,    3, (RNSDQ, oRNSDQ, RNSDQ_RNSC), neon_mac_maybe_scalar),
15850218822Sdim nCEF(vmls,     vmls,    3, (RNSDQ, oRNSDQ, RNSDQ_RNSC), neon_mac_maybe_scalar),
15851218822Sdim
15852218822Sdim nCEF(vadd,     vadd,    3, (RNSDQ, oRNSDQ, RNSDQ), neon_addsub_if_i),
15853218822Sdim nCEF(vsub,     vsub,    3, (RNSDQ, oRNSDQ, RNSDQ), neon_addsub_if_i),
15854218822Sdim
15855218822Sdim NCEF(vabs,     1b10300, 2, (RNSDQ, RNSDQ), neon_abs_neg),
15856218822Sdim NCEF(vneg,     1b10380, 2, (RNSDQ, RNSDQ), neon_abs_neg),
15857218822Sdim
15858218822Sdim NCE(vldm,      c900b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15859218822Sdim NCE(vldmia,    c900b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15860218822Sdim NCE(vldmdb,    d100b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15861218822Sdim NCE(vstm,      c800b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15862218822Sdim NCE(vstmia,    c800b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15863218822Sdim NCE(vstmdb,    d000b00, 2, (RRw, VRSDLST), neon_ldm_stm),
15864218822Sdim NCE(vldr,      d100b00, 2, (RVSD, ADDRGLDC), neon_ldr_str),
15865218822Sdim NCE(vstr,      d000b00, 2, (RVSD, ADDRGLDC), neon_ldr_str),
15866218822Sdim
15867218822Sdim nCEF(vcvt,     vcvt,    3, (RNSDQ, RNSDQ, oI32b), neon_cvt),
15868218822Sdim
15869218822Sdim  /* NOTE: All VMOV encoding is special-cased!  */
15870218822Sdim NCE(vmov,      0,       1, (VMOV), neon_mov),
15871218822Sdim NCE(vmovq,     0,       1, (VMOV), neon_mov),
15872218822Sdim
15873218822Sdim#undef THUMB_VARIANT
15874218822Sdim#define THUMB_VARIANT &fpu_neon_ext_v1
15875218822Sdim#undef ARM_VARIANT
15876218822Sdim#define ARM_VARIANT &fpu_neon_ext_v1
15877218822Sdim  /* Data processing with three registers of the same length.  */
15878218822Sdim  /* integer ops, valid types S8 S16 S32 U8 U16 U32.  */
15879218822Sdim NUF(vaba,      0000710, 3, (RNDQ, RNDQ,  RNDQ), neon_dyadic_i_su),
15880218822Sdim NUF(vabaq,     0000710, 3, (RNQ,  RNQ,   RNQ),  neon_dyadic_i_su),
15881218822Sdim NUF(vhadd,     0000000, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i_su),
15882218822Sdim NUF(vhaddq,    0000000, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i_su),
15883218822Sdim NUF(vrhadd,    0000100, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i_su),
15884218822Sdim NUF(vrhaddq,   0000100, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i_su),
15885218822Sdim NUF(vhsub,     0000200, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i_su),
15886218822Sdim NUF(vhsubq,    0000200, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i_su),
15887218822Sdim  /* integer ops, valid types S8 S16 S32 S64 U8 U16 U32 U64.  */
15888218822Sdim NUF(vqadd,     0000010, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i64_su),
15889218822Sdim NUF(vqaddq,    0000010, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i64_su),
15890218822Sdim NUF(vqsub,     0000210, 3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_i64_su),
15891218822Sdim NUF(vqsubq,    0000210, 3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_i64_su),
15892218822Sdim NUF(vrshl,     0000500, 3, (RNDQ, oRNDQ, RNDQ), neon_rshl),
15893218822Sdim NUF(vrshlq,    0000500, 3, (RNQ,  oRNQ,  RNQ),  neon_rshl),
15894218822Sdim NUF(vqrshl,    0000510, 3, (RNDQ, oRNDQ, RNDQ), neon_rshl),
15895218822Sdim NUF(vqrshlq,   0000510, 3, (RNQ,  oRNQ,  RNQ),  neon_rshl),
15896218822Sdim  /* If not immediate, fall back to neon_dyadic_i64_su.
15897218822Sdim     shl_imm should accept I8 I16 I32 I64,
15898218822Sdim     qshl_imm should accept S8 S16 S32 S64 U8 U16 U32 U64.  */
15899218822Sdim nUF(vshl,      vshl,    3, (RNDQ, oRNDQ, RNDQ_I63b), neon_shl_imm),
15900218822Sdim nUF(vshlq,     vshl,    3, (RNQ,  oRNQ,  RNDQ_I63b), neon_shl_imm),
15901218822Sdim nUF(vqshl,     vqshl,   3, (RNDQ, oRNDQ, RNDQ_I63b), neon_qshl_imm),
15902218822Sdim nUF(vqshlq,    vqshl,   3, (RNQ,  oRNQ,  RNDQ_I63b), neon_qshl_imm),
15903218822Sdim  /* Logic ops, types optional & ignored.  */
15904218822Sdim nUF(vand,      vand,    2, (RNDQ, NILO),        neon_logic),
15905218822Sdim nUF(vandq,     vand,    2, (RNQ,  NILO),        neon_logic),
15906218822Sdim nUF(vbic,      vbic,    2, (RNDQ, NILO),        neon_logic),
15907218822Sdim nUF(vbicq,     vbic,    2, (RNQ,  NILO),        neon_logic),
15908218822Sdim nUF(vorr,      vorr,    2, (RNDQ, NILO),        neon_logic),
15909218822Sdim nUF(vorrq,     vorr,    2, (RNQ,  NILO),        neon_logic),
15910218822Sdim nUF(vorn,      vorn,    2, (RNDQ, NILO),        neon_logic),
15911218822Sdim nUF(vornq,     vorn,    2, (RNQ,  NILO),        neon_logic),
15912218822Sdim nUF(veor,      veor,    3, (RNDQ, oRNDQ, RNDQ), neon_logic),
15913218822Sdim nUF(veorq,     veor,    3, (RNQ,  oRNQ,  RNQ),  neon_logic),
15914218822Sdim  /* Bitfield ops, untyped.  */
15915218822Sdim NUF(vbsl,      1100110, 3, (RNDQ, RNDQ, RNDQ), neon_bitfield),
15916218822Sdim NUF(vbslq,     1100110, 3, (RNQ,  RNQ,  RNQ),  neon_bitfield),
15917218822Sdim NUF(vbit,      1200110, 3, (RNDQ, RNDQ, RNDQ), neon_bitfield),
15918218822Sdim NUF(vbitq,     1200110, 3, (RNQ,  RNQ,  RNQ),  neon_bitfield),
15919218822Sdim NUF(vbif,      1300110, 3, (RNDQ, RNDQ, RNDQ), neon_bitfield),
15920218822Sdim NUF(vbifq,     1300110, 3, (RNQ,  RNQ,  RNQ),  neon_bitfield),
15921218822Sdim  /* Int and float variants, types S8 S16 S32 U8 U16 U32 F32.  */
15922218822Sdim nUF(vabd,      vabd,    3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_if_su),
15923218822Sdim nUF(vabdq,     vabd,    3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_if_su),
15924218822Sdim nUF(vmax,      vmax,    3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_if_su),
15925218822Sdim nUF(vmaxq,     vmax,    3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_if_su),
15926218822Sdim nUF(vmin,      vmin,    3, (RNDQ, oRNDQ, RNDQ), neon_dyadic_if_su),
15927218822Sdim nUF(vminq,     vmin,    3, (RNQ,  oRNQ,  RNQ),  neon_dyadic_if_su),
15928218822Sdim  /* Comparisons. Types S8 S16 S32 U8 U16 U32 F32. Non-immediate versions fall
15929218822Sdim     back to neon_dyadic_if_su.  */
15930218822Sdim nUF(vcge,      vcge,    3, (RNDQ, oRNDQ, RNDQ_I0), neon_cmp),
15931218822Sdim nUF(vcgeq,     vcge,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_cmp),
15932218822Sdim nUF(vcgt,      vcgt,    3, (RNDQ, oRNDQ, RNDQ_I0), neon_cmp),
15933218822Sdim nUF(vcgtq,     vcgt,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_cmp),
15934218822Sdim nUF(vclt,      vclt,    3, (RNDQ, oRNDQ, RNDQ_I0), neon_cmp_inv),
15935218822Sdim nUF(vcltq,     vclt,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_cmp_inv),
15936218822Sdim nUF(vcle,      vcle,    3, (RNDQ, oRNDQ, RNDQ_I0), neon_cmp_inv),
15937218822Sdim nUF(vcleq,     vcle,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_cmp_inv),
15938218822Sdim  /* Comparison. Type I8 I16 I32 F32.  */
15939218822Sdim nUF(vceq,      vceq,    3, (RNDQ, oRNDQ, RNDQ_I0), neon_ceq),
15940218822Sdim nUF(vceqq,     vceq,    3, (RNQ,  oRNQ,  RNDQ_I0), neon_ceq),
15941218822Sdim  /* As above, D registers only.  */
15942218822Sdim nUF(vpmax,     vpmax,   3, (RND, oRND, RND), neon_dyadic_if_su_d),
15943218822Sdim nUF(vpmin,     vpmin,   3, (RND, oRND, RND), neon_dyadic_if_su_d),
15944218822Sdim  /* Int and float variants, signedness unimportant.  */
15945218822Sdim nUF(vmlaq,     vmla,    3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_mac_maybe_scalar),
15946218822Sdim nUF(vmlsq,     vmls,    3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_mac_maybe_scalar),
15947218822Sdim nUF(vpadd,     vpadd,   3, (RND,  oRND,  RND),       neon_dyadic_if_i_d),
15948218822Sdim  /* Add/sub take types I8 I16 I32 I64 F32.  */
15949218822Sdim nUF(vaddq,     vadd,    3, (RNQ,  oRNQ,  RNQ),  neon_addsub_if_i),
15950218822Sdim nUF(vsubq,     vsub,    3, (RNQ,  oRNQ,  RNQ),  neon_addsub_if_i),
15951218822Sdim  /* vtst takes sizes 8, 16, 32.  */
15952218822Sdim NUF(vtst,      0000810, 3, (RNDQ, oRNDQ, RNDQ), neon_tst),
15953218822Sdim NUF(vtstq,     0000810, 3, (RNQ,  oRNQ,  RNQ),  neon_tst),
15954218822Sdim  /* VMUL takes I8 I16 I32 F32 P8.  */
15955218822Sdim nUF(vmulq,     vmul,     3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_mul),
15956218822Sdim  /* VQD{R}MULH takes S16 S32.  */
15957218822Sdim nUF(vqdmulh,   vqdmulh,  3, (RNDQ, oRNDQ, RNDQ_RNSC), neon_qdmulh),
15958218822Sdim nUF(vqdmulhq,  vqdmulh,  3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_qdmulh),
15959218822Sdim nUF(vqrdmulh,  vqrdmulh, 3, (RNDQ, oRNDQ, RNDQ_RNSC), neon_qdmulh),
15960218822Sdim nUF(vqrdmulhq, vqrdmulh, 3, (RNQ,  oRNQ,  RNDQ_RNSC), neon_qdmulh),
15961218822Sdim NUF(vacge,     0000e10,  3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute),
15962218822Sdim NUF(vacgeq,    0000e10,  3, (RNQ,  oRNQ,  RNQ),  neon_fcmp_absolute),
15963218822Sdim NUF(vacgt,     0200e10,  3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute),
15964218822Sdim NUF(vacgtq,    0200e10,  3, (RNQ,  oRNQ,  RNQ),  neon_fcmp_absolute),
15965218822Sdim NUF(vaclt,     0200e10,  3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute_inv),
15966218822Sdim NUF(vacltq,    0200e10,  3, (RNQ,  oRNQ,  RNQ),  neon_fcmp_absolute_inv),
15967218822Sdim NUF(vacle,     0000e10,  3, (RNDQ, oRNDQ, RNDQ), neon_fcmp_absolute_inv),
15968218822Sdim NUF(vacleq,    0000e10,  3, (RNQ,  oRNQ,  RNQ),  neon_fcmp_absolute_inv),
15969218822Sdim NUF(vrecps,    0000f10,  3, (RNDQ, oRNDQ, RNDQ), neon_step),
15970218822Sdim NUF(vrecpsq,   0000f10,  3, (RNQ,  oRNQ,  RNQ),  neon_step),
15971218822Sdim NUF(vrsqrts,   0200f10,  3, (RNDQ, oRNDQ, RNDQ), neon_step),
15972218822Sdim NUF(vrsqrtsq,  0200f10,  3, (RNQ,  oRNQ,  RNQ),  neon_step),
15973218822Sdim
15974218822Sdim  /* Two address, int/float. Types S8 S16 S32 F32.  */
15975218822Sdim NUF(vabsq,     1b10300, 2, (RNQ,  RNQ),      neon_abs_neg),
15976218822Sdim NUF(vnegq,     1b10380, 2, (RNQ,  RNQ),      neon_abs_neg),
15977218822Sdim
15978218822Sdim  /* Data processing with two registers and a shift amount.  */
15979218822Sdim  /* Right shifts, and variants with rounding.
15980218822Sdim     Types accepted S8 S16 S32 S64 U8 U16 U32 U64.  */
15981218822Sdim NUF(vshr,      0800010, 3, (RNDQ, oRNDQ, I64z), neon_rshift_round_imm),
15982218822Sdim NUF(vshrq,     0800010, 3, (RNQ,  oRNQ,  I64z), neon_rshift_round_imm),
15983218822Sdim NUF(vrshr,     0800210, 3, (RNDQ, oRNDQ, I64z), neon_rshift_round_imm),
15984218822Sdim NUF(vrshrq,    0800210, 3, (RNQ,  oRNQ,  I64z), neon_rshift_round_imm),
15985218822Sdim NUF(vsra,      0800110, 3, (RNDQ, oRNDQ, I64),  neon_rshift_round_imm),
15986218822Sdim NUF(vsraq,     0800110, 3, (RNQ,  oRNQ,  I64),  neon_rshift_round_imm),
15987218822Sdim NUF(vrsra,     0800310, 3, (RNDQ, oRNDQ, I64),  neon_rshift_round_imm),
15988218822Sdim NUF(vrsraq,    0800310, 3, (RNQ,  oRNQ,  I64),  neon_rshift_round_imm),
15989218822Sdim  /* Shift and insert. Sizes accepted 8 16 32 64.  */
15990218822Sdim NUF(vsli,      1800510, 3, (RNDQ, oRNDQ, I63), neon_sli),
15991218822Sdim NUF(vsliq,     1800510, 3, (RNQ,  oRNQ,  I63), neon_sli),
15992218822Sdim NUF(vsri,      1800410, 3, (RNDQ, oRNDQ, I64), neon_sri),
15993218822Sdim NUF(vsriq,     1800410, 3, (RNQ,  oRNQ,  I64), neon_sri),
15994218822Sdim  /* QSHL{U} immediate accepts S8 S16 S32 S64 U8 U16 U32 U64.  */
15995218822Sdim NUF(vqshlu,    1800610, 3, (RNDQ, oRNDQ, I63), neon_qshlu_imm),
15996218822Sdim NUF(vqshluq,   1800610, 3, (RNQ,  oRNQ,  I63), neon_qshlu_imm),
15997218822Sdim  /* Right shift immediate, saturating & narrowing, with rounding variants.
15998218822Sdim     Types accepted S16 S32 S64 U16 U32 U64.  */
15999218822Sdim NUF(vqshrn,    0800910, 3, (RND, RNQ, I32z), neon_rshift_sat_narrow),
16000218822Sdim NUF(vqrshrn,   0800950, 3, (RND, RNQ, I32z), neon_rshift_sat_narrow),
16001218822Sdim  /* As above, unsigned. Types accepted S16 S32 S64.  */
16002218822Sdim NUF(vqshrun,   0800810, 3, (RND, RNQ, I32z), neon_rshift_sat_narrow_u),
16003218822Sdim NUF(vqrshrun,  0800850, 3, (RND, RNQ, I32z), neon_rshift_sat_narrow_u),
16004218822Sdim  /* Right shift narrowing. Types accepted I16 I32 I64.  */
16005218822Sdim NUF(vshrn,     0800810, 3, (RND, RNQ, I32z), neon_rshift_narrow),
16006218822Sdim NUF(vrshrn,    0800850, 3, (RND, RNQ, I32z), neon_rshift_narrow),
16007218822Sdim  /* Special case. Types S8 S16 S32 U8 U16 U32. Handles max shift variant.  */
16008218822Sdim nUF(vshll,     vshll,   3, (RNQ, RND, I32),  neon_shll),
16009218822Sdim  /* CVT with optional immediate for fixed-point variant.  */
16010218822Sdim nUF(vcvtq,     vcvt,    3, (RNQ, RNQ, oI32b), neon_cvt),
16011218822Sdim
16012218822Sdim nUF(vmvn,      vmvn,    2, (RNDQ, RNDQ_IMVNb), neon_mvn),
16013218822Sdim nUF(vmvnq,     vmvn,    2, (RNQ,  RNDQ_IMVNb), neon_mvn),
16014218822Sdim
16015218822Sdim  /* Data processing, three registers of different lengths.  */
16016218822Sdim  /* Dyadic, long insns. Types S8 S16 S32 U8 U16 U32.  */
16017218822Sdim NUF(vabal,     0800500, 3, (RNQ, RND, RND),  neon_abal),
16018218822Sdim NUF(vabdl,     0800700, 3, (RNQ, RND, RND),  neon_dyadic_long),
16019218822Sdim NUF(vaddl,     0800000, 3, (RNQ, RND, RND),  neon_dyadic_long),
16020218822Sdim NUF(vsubl,     0800200, 3, (RNQ, RND, RND),  neon_dyadic_long),
16021218822Sdim  /* If not scalar, fall back to neon_dyadic_long.
16022218822Sdim     Vector types as above, scalar types S16 S32 U16 U32.  */
16023218822Sdim nUF(vmlal,     vmlal,   3, (RNQ, RND, RND_RNSC), neon_mac_maybe_scalar_long),
16024218822Sdim nUF(vmlsl,     vmlsl,   3, (RNQ, RND, RND_RNSC), neon_mac_maybe_scalar_long),
16025218822Sdim  /* Dyadic, widening insns. Types S8 S16 S32 U8 U16 U32.  */
16026218822Sdim NUF(vaddw,     0800100, 3, (RNQ, oRNQ, RND), neon_dyadic_wide),
16027218822Sdim NUF(vsubw,     0800300, 3, (RNQ, oRNQ, RND), neon_dyadic_wide),
16028218822Sdim  /* Dyadic, narrowing insns. Types I16 I32 I64.  */
16029218822Sdim NUF(vaddhn,    0800400, 3, (RND, RNQ, RNQ),  neon_dyadic_narrow),
16030218822Sdim NUF(vraddhn,   1800400, 3, (RND, RNQ, RNQ),  neon_dyadic_narrow),
16031218822Sdim NUF(vsubhn,    0800600, 3, (RND, RNQ, RNQ),  neon_dyadic_narrow),
16032218822Sdim NUF(vrsubhn,   1800600, 3, (RND, RNQ, RNQ),  neon_dyadic_narrow),
16033218822Sdim  /* Saturating doubling multiplies. Types S16 S32.  */
16034218822Sdim nUF(vqdmlal,   vqdmlal, 3, (RNQ, RND, RND_RNSC), neon_mul_sat_scalar_long),
16035218822Sdim nUF(vqdmlsl,   vqdmlsl, 3, (RNQ, RND, RND_RNSC), neon_mul_sat_scalar_long),
16036218822Sdim nUF(vqdmull,   vqdmull, 3, (RNQ, RND, RND_RNSC), neon_mul_sat_scalar_long),
16037218822Sdim  /* VMULL. Vector types S8 S16 S32 U8 U16 U32 P8, scalar types
16038218822Sdim     S16 S32 U16 U32.  */
16039218822Sdim nUF(vmull,     vmull,   3, (RNQ, RND, RND_RNSC), neon_vmull),
16040218822Sdim
16041218822Sdim  /* Extract. Size 8.  */
16042218822Sdim NUF(vext,      0b00000, 4, (RNDQ, oRNDQ, RNDQ, I15), neon_ext),
16043218822Sdim NUF(vextq,     0b00000, 4, (RNQ,  oRNQ,  RNQ,  I15), neon_ext),
16044218822Sdim
16045218822Sdim  /* Two registers, miscellaneous.  */
16046218822Sdim  /* Reverse. Sizes 8 16 32 (must be < size in opcode).  */
16047218822Sdim NUF(vrev64,    1b00000, 2, (RNDQ, RNDQ),     neon_rev),
16048218822Sdim NUF(vrev64q,   1b00000, 2, (RNQ,  RNQ),      neon_rev),
16049218822Sdim NUF(vrev32,    1b00080, 2, (RNDQ, RNDQ),     neon_rev),
16050218822Sdim NUF(vrev32q,   1b00080, 2, (RNQ,  RNQ),      neon_rev),
16051218822Sdim NUF(vrev16,    1b00100, 2, (RNDQ, RNDQ),     neon_rev),
16052218822Sdim NUF(vrev16q,   1b00100, 2, (RNQ,  RNQ),      neon_rev),
16053218822Sdim  /* Vector replicate. Sizes 8 16 32.  */
16054218822Sdim nCE(vdup,      vdup,    2, (RNDQ, RR_RNSC),  neon_dup),
16055218822Sdim nCE(vdupq,     vdup,    2, (RNQ,  RR_RNSC),  neon_dup),
16056218822Sdim  /* VMOVL. Types S8 S16 S32 U8 U16 U32.  */
16057218822Sdim NUF(vmovl,     0800a10, 2, (RNQ, RND),       neon_movl),
16058218822Sdim  /* VMOVN. Types I16 I32 I64.  */
16059218822Sdim nUF(vmovn,     vmovn,   2, (RND, RNQ),       neon_movn),
16060218822Sdim  /* VQMOVN. Types S16 S32 S64 U16 U32 U64.  */
16061218822Sdim nUF(vqmovn,    vqmovn,  2, (RND, RNQ),       neon_qmovn),
16062218822Sdim  /* VQMOVUN. Types S16 S32 S64.  */
16063218822Sdim nUF(vqmovun,   vqmovun, 2, (RND, RNQ),       neon_qmovun),
16064218822Sdim  /* VZIP / VUZP. Sizes 8 16 32.  */
16065218822Sdim NUF(vzip,      1b20180, 2, (RNDQ, RNDQ),     neon_zip_uzp),
16066218822Sdim NUF(vzipq,     1b20180, 2, (RNQ,  RNQ),      neon_zip_uzp),
16067218822Sdim NUF(vuzp,      1b20100, 2, (RNDQ, RNDQ),     neon_zip_uzp),
16068218822Sdim NUF(vuzpq,     1b20100, 2, (RNQ,  RNQ),      neon_zip_uzp),
16069218822Sdim  /* VQABS / VQNEG. Types S8 S16 S32.  */
16070218822Sdim NUF(vqabs,     1b00700, 2, (RNDQ, RNDQ),     neon_sat_abs_neg),
16071218822Sdim NUF(vqabsq,    1b00700, 2, (RNQ,  RNQ),      neon_sat_abs_neg),
16072218822Sdim NUF(vqneg,     1b00780, 2, (RNDQ, RNDQ),     neon_sat_abs_neg),
16073218822Sdim NUF(vqnegq,    1b00780, 2, (RNQ,  RNQ),      neon_sat_abs_neg),
16074218822Sdim  /* Pairwise, lengthening. Types S8 S16 S32 U8 U16 U32.  */
16075218822Sdim NUF(vpadal,    1b00600, 2, (RNDQ, RNDQ),     neon_pair_long),
16076218822Sdim NUF(vpadalq,   1b00600, 2, (RNQ,  RNQ),      neon_pair_long),
16077218822Sdim NUF(vpaddl,    1b00200, 2, (RNDQ, RNDQ),     neon_pair_long),
16078218822Sdim NUF(vpaddlq,   1b00200, 2, (RNQ,  RNQ),      neon_pair_long),
16079218822Sdim  /* Reciprocal estimates. Types U32 F32.  */
16080218822Sdim NUF(vrecpe,    1b30400, 2, (RNDQ, RNDQ),     neon_recip_est),
16081218822Sdim NUF(vrecpeq,   1b30400, 2, (RNQ,  RNQ),      neon_recip_est),
16082218822Sdim NUF(vrsqrte,   1b30480, 2, (RNDQ, RNDQ),     neon_recip_est),
16083218822Sdim NUF(vrsqrteq,  1b30480, 2, (RNQ,  RNQ),      neon_recip_est),
16084218822Sdim  /* VCLS. Types S8 S16 S32.  */
16085218822Sdim NUF(vcls,      1b00400, 2, (RNDQ, RNDQ),     neon_cls),
16086218822Sdim NUF(vclsq,     1b00400, 2, (RNQ,  RNQ),      neon_cls),
16087218822Sdim  /* VCLZ. Types I8 I16 I32.  */
16088218822Sdim NUF(vclz,      1b00480, 2, (RNDQ, RNDQ),     neon_clz),
16089218822Sdim NUF(vclzq,     1b00480, 2, (RNQ,  RNQ),      neon_clz),
16090218822Sdim  /* VCNT. Size 8.  */
16091218822Sdim NUF(vcnt,      1b00500, 2, (RNDQ, RNDQ),     neon_cnt),
16092218822Sdim NUF(vcntq,     1b00500, 2, (RNQ,  RNQ),      neon_cnt),
16093218822Sdim  /* Two address, untyped.  */
16094218822Sdim NUF(vswp,      1b20000, 2, (RNDQ, RNDQ),     neon_swp),
16095218822Sdim NUF(vswpq,     1b20000, 2, (RNQ,  RNQ),      neon_swp),
16096218822Sdim  /* VTRN. Sizes 8 16 32.  */
16097218822Sdim nUF(vtrn,      vtrn,    2, (RNDQ, RNDQ),     neon_trn),
16098218822Sdim nUF(vtrnq,     vtrn,    2, (RNQ,  RNQ),      neon_trn),
16099218822Sdim
16100218822Sdim  /* Table lookup. Size 8.  */
16101218822Sdim NUF(vtbl,      1b00800, 3, (RND, NRDLST, RND), neon_tbl_tbx),
16102218822Sdim NUF(vtbx,      1b00840, 3, (RND, NRDLST, RND), neon_tbl_tbx),
16103218822Sdim
16104218822Sdim#undef THUMB_VARIANT
16105218822Sdim#define THUMB_VARIANT &fpu_vfp_v3_or_neon_ext
16106218822Sdim#undef ARM_VARIANT
16107218822Sdim#define ARM_VARIANT &fpu_vfp_v3_or_neon_ext
16108218822Sdim  /* Neon element/structure load/store.  */
16109218822Sdim nUF(vld1,      vld1,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16110218822Sdim nUF(vst1,      vst1,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16111218822Sdim nUF(vld2,      vld2,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16112218822Sdim nUF(vst2,      vst2,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16113218822Sdim nUF(vld3,      vld3,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16114218822Sdim nUF(vst3,      vst3,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16115218822Sdim nUF(vld4,      vld4,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16116218822Sdim nUF(vst4,      vst4,    2, (NSTRLST, ADDR),  neon_ldx_stx),
16117218822Sdim
16118218822Sdim#undef THUMB_VARIANT
16119218822Sdim#define THUMB_VARIANT &fpu_vfp_ext_v3
16120218822Sdim#undef ARM_VARIANT
16121218822Sdim#define ARM_VARIANT &fpu_vfp_ext_v3
16122218822Sdim cCE(fconsts,   eb00a00, 2, (RVS, I255),      vfp_sp_const),
16123218822Sdim cCE(fconstd,   eb00b00, 2, (RVD, I255),      vfp_dp_const),
16124218822Sdim cCE(fshtos,    eba0a40, 2, (RVS, I16z),      vfp_sp_conv_16),
16125218822Sdim cCE(fshtod,    eba0b40, 2, (RVD, I16z),      vfp_dp_conv_16),
16126218822Sdim cCE(fsltos,    eba0ac0, 2, (RVS, I32),       vfp_sp_conv_32),
16127218822Sdim cCE(fsltod,    eba0bc0, 2, (RVD, I32),       vfp_dp_conv_32),
16128218822Sdim cCE(fuhtos,    ebb0a40, 2, (RVS, I16z),      vfp_sp_conv_16),
16129218822Sdim cCE(fuhtod,    ebb0b40, 2, (RVD, I16z),      vfp_dp_conv_16),
16130218822Sdim cCE(fultos,    ebb0ac0, 2, (RVS, I32),       vfp_sp_conv_32),
16131218822Sdim cCE(fultod,    ebb0bc0, 2, (RVD, I32),       vfp_dp_conv_32),
16132218822Sdim cCE(ftoshs,    ebe0a40, 2, (RVS, I16z),      vfp_sp_conv_16),
16133218822Sdim cCE(ftoshd,    ebe0b40, 2, (RVD, I16z),      vfp_dp_conv_16),
16134218822Sdim cCE(ftosls,    ebe0ac0, 2, (RVS, I32),       vfp_sp_conv_32),
16135218822Sdim cCE(ftosld,    ebe0bc0, 2, (RVD, I32),       vfp_dp_conv_32),
16136218822Sdim cCE(ftouhs,    ebf0a40, 2, (RVS, I16z),      vfp_sp_conv_16),
16137218822Sdim cCE(ftouhd,    ebf0b40, 2, (RVD, I16z),      vfp_dp_conv_16),
16138218822Sdim cCE(ftouls,    ebf0ac0, 2, (RVS, I32),       vfp_sp_conv_32),
16139218822Sdim cCE(ftould,    ebf0bc0, 2, (RVD, I32),       vfp_dp_conv_32),
16140218822Sdim
16141218822Sdim#undef THUMB_VARIANT
16142218822Sdim#undef ARM_VARIANT
16143218822Sdim#define ARM_VARIANT &arm_cext_xscale /* Intel XScale extensions.	 */
16144218822Sdim cCE(mia,	e200010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16145218822Sdim cCE(miaph,	e280010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16146218822Sdim cCE(miabb,	e2c0010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16147218822Sdim cCE(miabt,	e2d0010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16148218822Sdim cCE(miatb,	e2e0010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16149218822Sdim cCE(miatt,	e2f0010, 3, (RXA, RRnpc, RRnpc), xsc_mia),
16150218822Sdim cCE(mar,	c400000, 3, (RXA, RRnpc, RRnpc), xsc_mar),
16151218822Sdim cCE(mra,	c500000, 3, (RRnpc, RRnpc, RXA), xsc_mra),
16152218822Sdim
16153218822Sdim#undef ARM_VARIANT
16154218822Sdim#define ARM_VARIANT &arm_cext_iwmmxt /* Intel Wireless MMX technology.  */
16155218822Sdim cCE(tandcb,	e13f130, 1, (RR),		    iwmmxt_tandorc),
16156218822Sdim cCE(tandch,	e53f130, 1, (RR),		    iwmmxt_tandorc),
16157218822Sdim cCE(tandcw,	e93f130, 1, (RR),		    iwmmxt_tandorc),
16158218822Sdim cCE(tbcstb,	e400010, 2, (RIWR, RR),		    rn_rd),
16159218822Sdim cCE(tbcsth,	e400050, 2, (RIWR, RR),		    rn_rd),
16160218822Sdim cCE(tbcstw,	e400090, 2, (RIWR, RR),		    rn_rd),
16161218822Sdim cCE(textrcb,	e130170, 2, (RR, I7),		    iwmmxt_textrc),
16162218822Sdim cCE(textrch,	e530170, 2, (RR, I7),		    iwmmxt_textrc),
16163218822Sdim cCE(textrcw,	e930170, 2, (RR, I7),		    iwmmxt_textrc),
16164218822Sdim cCE(textrmub,	e100070, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16165218822Sdim cCE(textrmuh,	e500070, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16166218822Sdim cCE(textrmuw,	e900070, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16167218822Sdim cCE(textrmsb,	e100078, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16168218822Sdim cCE(textrmsh,	e500078, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16169218822Sdim cCE(textrmsw,	e900078, 3, (RR, RIWR, I7),	    iwmmxt_textrm),
16170218822Sdim cCE(tinsrb,	e600010, 3, (RIWR, RR, I7),	    iwmmxt_tinsr),
16171218822Sdim cCE(tinsrh,	e600050, 3, (RIWR, RR, I7),	    iwmmxt_tinsr),
16172218822Sdim cCE(tinsrw,	e600090, 3, (RIWR, RR, I7),	    iwmmxt_tinsr),
16173218822Sdim cCE(tmcr,	e000110, 2, (RIWC_RIWG, RR),	    rn_rd),
16174218822Sdim cCE(tmcrr,	c400000, 3, (RIWR, RR, RR),	    rm_rd_rn),
16175218822Sdim cCE(tmia,	e200010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16176218822Sdim cCE(tmiaph,	e280010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16177218822Sdim cCE(tmiabb,	e2c0010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16178218822Sdim cCE(tmiabt,	e2d0010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16179218822Sdim cCE(tmiatb,	e2e0010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16180218822Sdim cCE(tmiatt,	e2f0010, 3, (RIWR, RR, RR),	    iwmmxt_tmia),
16181218822Sdim cCE(tmovmskb,	e100030, 2, (RR, RIWR),		    rd_rn),
16182218822Sdim cCE(tmovmskh,	e500030, 2, (RR, RIWR),		    rd_rn),
16183218822Sdim cCE(tmovmskw,	e900030, 2, (RR, RIWR),		    rd_rn),
16184218822Sdim cCE(tmrc,	e100110, 2, (RR, RIWC_RIWG),	    rd_rn),
16185218822Sdim cCE(tmrrc,	c500000, 3, (RR, RR, RIWR),	    rd_rn_rm),
16186218822Sdim cCE(torcb,	e13f150, 1, (RR),		    iwmmxt_tandorc),
16187218822Sdim cCE(torch,	e53f150, 1, (RR),		    iwmmxt_tandorc),
16188218822Sdim cCE(torcw,	e93f150, 1, (RR),		    iwmmxt_tandorc),
16189218822Sdim cCE(waccb,	e0001c0, 2, (RIWR, RIWR),	    rd_rn),
16190218822Sdim cCE(wacch,	e4001c0, 2, (RIWR, RIWR),	    rd_rn),
16191218822Sdim cCE(waccw,	e8001c0, 2, (RIWR, RIWR),	    rd_rn),
16192218822Sdim cCE(waddbss,	e300180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16193218822Sdim cCE(waddb,	e000180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16194218822Sdim cCE(waddbus,	e100180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16195218822Sdim cCE(waddhss,	e700180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16196218822Sdim cCE(waddh,	e400180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16197218822Sdim cCE(waddhus,	e500180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16198218822Sdim cCE(waddwss,	eb00180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16199218822Sdim cCE(waddw,	e800180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16200218822Sdim cCE(waddwus,	e900180, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16201218822Sdim cCE(waligni,	e000020, 4, (RIWR, RIWR, RIWR, I7), iwmmxt_waligni),
16202218822Sdim cCE(walignr0,	e800020, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16203218822Sdim cCE(walignr1,	e900020, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16204218822Sdim cCE(walignr2,	ea00020, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16205218822Sdim cCE(walignr3,	eb00020, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16206218822Sdim cCE(wand,	e200000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16207218822Sdim cCE(wandn,	e300000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16208218822Sdim cCE(wavg2b,	e800000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16209218822Sdim cCE(wavg2br,	e900000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16210218822Sdim cCE(wavg2h,	ec00000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16211218822Sdim cCE(wavg2hr,	ed00000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16212218822Sdim cCE(wcmpeqb,	e000060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16213218822Sdim cCE(wcmpeqh,	e400060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16214218822Sdim cCE(wcmpeqw,	e800060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16215218822Sdim cCE(wcmpgtub,	e100060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16216218822Sdim cCE(wcmpgtuh,	e500060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16217218822Sdim cCE(wcmpgtuw,	e900060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16218218822Sdim cCE(wcmpgtsb,	e300060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16219218822Sdim cCE(wcmpgtsh,	e700060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16220218822Sdim cCE(wcmpgtsw,	eb00060, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16221218822Sdim cCE(wldrb,	c100000, 2, (RIWR, ADDR),	    iwmmxt_wldstbh),
16222218822Sdim cCE(wldrh,	c500000, 2, (RIWR, ADDR),	    iwmmxt_wldstbh),
16223218822Sdim cCE(wldrw,	c100100, 2, (RIWR_RIWC, ADDR),	    iwmmxt_wldstw),
16224218822Sdim cCE(wldrd,	c500100, 2, (RIWR, ADDR),	    iwmmxt_wldstd),
16225218822Sdim cCE(wmacs,	e600100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16226218822Sdim cCE(wmacsz,	e700100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16227218822Sdim cCE(wmacu,	e400100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16228218822Sdim cCE(wmacuz,	e500100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16229218822Sdim cCE(wmadds,	ea00100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16230218822Sdim cCE(wmaddu,	e800100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16231218822Sdim cCE(wmaxsb,	e200160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16232218822Sdim cCE(wmaxsh,	e600160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16233218822Sdim cCE(wmaxsw,	ea00160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16234218822Sdim cCE(wmaxub,	e000160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16235218822Sdim cCE(wmaxuh,	e400160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16236218822Sdim cCE(wmaxuw,	e800160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16237218822Sdim cCE(wminsb,	e300160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16238218822Sdim cCE(wminsh,	e700160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16239218822Sdim cCE(wminsw,	eb00160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16240218822Sdim cCE(wminub,	e100160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16241218822Sdim cCE(wminuh,	e500160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16242218822Sdim cCE(wminuw,	e900160, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16243218822Sdim cCE(wmov,	e000000, 2, (RIWR, RIWR),	    iwmmxt_wmov),
16244218822Sdim cCE(wmulsm,	e300100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16245218822Sdim cCE(wmulsl,	e200100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16246218822Sdim cCE(wmulum,	e100100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16247218822Sdim cCE(wmulul,	e000100, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16248218822Sdim cCE(wor,	e000000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16249218822Sdim cCE(wpackhss,	e700080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16250218822Sdim cCE(wpackhus,	e500080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16251218822Sdim cCE(wpackwss,	eb00080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16252218822Sdim cCE(wpackwus,	e900080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16253218822Sdim cCE(wpackdss,	ef00080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16254218822Sdim cCE(wpackdus,	ed00080, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16255218822Sdim cCE(wrorh,	e700040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16256218822Sdim cCE(wrorhg,	e700148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16257218822Sdim cCE(wrorw,	eb00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16258218822Sdim cCE(wrorwg,	eb00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16259218822Sdim cCE(wrord,	ef00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16260218822Sdim cCE(wrordg,	ef00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16261218822Sdim cCE(wsadb,	e000120, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16262218822Sdim cCE(wsadbz,	e100120, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16263218822Sdim cCE(wsadh,	e400120, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16264218822Sdim cCE(wsadhz,	e500120, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16265218822Sdim cCE(wshufh,	e0001e0, 3, (RIWR, RIWR, I255),	    iwmmxt_wshufh),
16266218822Sdim cCE(wsllh,	e500040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16267218822Sdim cCE(wsllhg,	e500148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16268218822Sdim cCE(wsllw,	e900040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16269218822Sdim cCE(wsllwg,	e900148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16270218822Sdim cCE(wslld,	ed00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16271218822Sdim cCE(wslldg,	ed00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16272218822Sdim cCE(wsrah,	e400040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16273218822Sdim cCE(wsrahg,	e400148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16274218822Sdim cCE(wsraw,	e800040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16275218822Sdim cCE(wsrawg,	e800148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16276218822Sdim cCE(wsrad,	ec00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16277218822Sdim cCE(wsradg,	ec00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16278218822Sdim cCE(wsrlh,	e600040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16279218822Sdim cCE(wsrlhg,	e600148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16280218822Sdim cCE(wsrlw,	ea00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16281218822Sdim cCE(wsrlwg,	ea00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16282218822Sdim cCE(wsrld,	ee00040, 3, (RIWR, RIWR, RIWR_I32z),iwmmxt_wrwrwr_or_imm5),
16283218822Sdim cCE(wsrldg,	ee00148, 3, (RIWR, RIWR, RIWG),	    rd_rn_rm),
16284218822Sdim cCE(wstrb,	c000000, 2, (RIWR, ADDR),	    iwmmxt_wldstbh),
16285218822Sdim cCE(wstrh,	c400000, 2, (RIWR, ADDR),	    iwmmxt_wldstbh),
16286218822Sdim cCE(wstrw,	c000100, 2, (RIWR_RIWC, ADDR),	    iwmmxt_wldstw),
16287218822Sdim cCE(wstrd,	c400100, 2, (RIWR, ADDR),	    iwmmxt_wldstd),
16288218822Sdim cCE(wsubbss,	e3001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16289218822Sdim cCE(wsubb,	e0001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16290218822Sdim cCE(wsubbus,	e1001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16291218822Sdim cCE(wsubhss,	e7001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16292218822Sdim cCE(wsubh,	e4001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16293218822Sdim cCE(wsubhus,	e5001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16294218822Sdim cCE(wsubwss,	eb001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16295218822Sdim cCE(wsubw,	e8001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16296218822Sdim cCE(wsubwus,	e9001a0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16297218822Sdim cCE(wunpckehub,e0000c0, 2, (RIWR, RIWR),	    rd_rn),
16298218822Sdim cCE(wunpckehuh,e4000c0, 2, (RIWR, RIWR),	    rd_rn),
16299218822Sdim cCE(wunpckehuw,e8000c0, 2, (RIWR, RIWR),	    rd_rn),
16300218822Sdim cCE(wunpckehsb,e2000c0, 2, (RIWR, RIWR),	    rd_rn),
16301218822Sdim cCE(wunpckehsh,e6000c0, 2, (RIWR, RIWR),	    rd_rn),
16302218822Sdim cCE(wunpckehsw,ea000c0, 2, (RIWR, RIWR),	    rd_rn),
16303218822Sdim cCE(wunpckihb, e1000c0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16304218822Sdim cCE(wunpckihh, e5000c0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16305218822Sdim cCE(wunpckihw, e9000c0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16306218822Sdim cCE(wunpckelub,e0000e0, 2, (RIWR, RIWR),	    rd_rn),
16307218822Sdim cCE(wunpckeluh,e4000e0, 2, (RIWR, RIWR),	    rd_rn),
16308218822Sdim cCE(wunpckeluw,e8000e0, 2, (RIWR, RIWR),	    rd_rn),
16309218822Sdim cCE(wunpckelsb,e2000e0, 2, (RIWR, RIWR),	    rd_rn),
16310218822Sdim cCE(wunpckelsh,e6000e0, 2, (RIWR, RIWR),	    rd_rn),
16311218822Sdim cCE(wunpckelsw,ea000e0, 2, (RIWR, RIWR),	    rd_rn),
16312218822Sdim cCE(wunpckilb, e1000e0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16313218822Sdim cCE(wunpckilh, e5000e0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16314218822Sdim cCE(wunpckilw, e9000e0, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16315218822Sdim cCE(wxor,	e100000, 3, (RIWR, RIWR, RIWR),	    rd_rn_rm),
16316218822Sdim cCE(wzero,	e300000, 1, (RIWR),		    iwmmxt_wzero),
16317218822Sdim
16318218822Sdim#undef ARM_VARIANT
16319218822Sdim#define ARM_VARIANT &arm_cext_iwmmxt2 /* Intel Wireless MMX technology, version 2.  */
16320218822Sdim cCE(torvscb,   e13f190, 1, (RR),		    iwmmxt_tandorc),
16321218822Sdim cCE(torvsch,   e53f190, 1, (RR),		    iwmmxt_tandorc),
16322218822Sdim cCE(torvscw,   e93f190, 1, (RR),		    iwmmxt_tandorc),
16323218822Sdim cCE(wabsb,     e2001c0, 2, (RIWR, RIWR),           rd_rn),
16324218822Sdim cCE(wabsh,     e6001c0, 2, (RIWR, RIWR),           rd_rn),
16325218822Sdim cCE(wabsw,     ea001c0, 2, (RIWR, RIWR),           rd_rn),
16326218822Sdim cCE(wabsdiffb, e1001c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16327218822Sdim cCE(wabsdiffh, e5001c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16328218822Sdim cCE(wabsdiffw, e9001c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16329218822Sdim cCE(waddbhusl, e2001a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16330218822Sdim cCE(waddbhusm, e6001a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16331218822Sdim cCE(waddhc,    e600180, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16332218822Sdim cCE(waddwc,    ea00180, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16333218822Sdim cCE(waddsubhx, ea001a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16334218822Sdim cCE(wavg4,	e400000, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16335218822Sdim cCE(wavg4r,    e500000, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16336218822Sdim cCE(wmaddsn,   ee00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16337218822Sdim cCE(wmaddsx,   eb00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16338218822Sdim cCE(wmaddun,   ec00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16339218822Sdim cCE(wmaddux,   e900100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16340218822Sdim cCE(wmerge,    e000080, 4, (RIWR, RIWR, RIWR, I7), iwmmxt_wmerge),
16341218822Sdim cCE(wmiabb,    e0000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16342218822Sdim cCE(wmiabt,    e1000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16343218822Sdim cCE(wmiatb,    e2000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16344218822Sdim cCE(wmiatt,    e3000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16345218822Sdim cCE(wmiabbn,   e4000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16346218822Sdim cCE(wmiabtn,   e5000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16347218822Sdim cCE(wmiatbn,   e6000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16348218822Sdim cCE(wmiattn,   e7000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16349218822Sdim cCE(wmiawbb,   e800120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16350218822Sdim cCE(wmiawbt,   e900120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16351218822Sdim cCE(wmiawtb,   ea00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16352218822Sdim cCE(wmiawtt,   eb00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16353218822Sdim cCE(wmiawbbn,  ec00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16354218822Sdim cCE(wmiawbtn,  ed00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16355218822Sdim cCE(wmiawtbn,  ee00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16356218822Sdim cCE(wmiawttn,  ef00120, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16357218822Sdim cCE(wmulsmr,   ef00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16358218822Sdim cCE(wmulumr,   ed00100, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16359218822Sdim cCE(wmulwumr,  ec000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16360218822Sdim cCE(wmulwsmr,  ee000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16361218822Sdim cCE(wmulwum,   ed000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16362218822Sdim cCE(wmulwsm,   ef000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16363218822Sdim cCE(wmulwl,    eb000c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16364218822Sdim cCE(wqmiabb,   e8000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16365218822Sdim cCE(wqmiabt,   e9000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16366218822Sdim cCE(wqmiatb,   ea000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16367218822Sdim cCE(wqmiatt,   eb000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16368218822Sdim cCE(wqmiabbn,  ec000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16369218822Sdim cCE(wqmiabtn,  ed000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16370218822Sdim cCE(wqmiatbn,  ee000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16371218822Sdim cCE(wqmiattn,  ef000a0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16372218822Sdim cCE(wqmulm,    e100080, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16373218822Sdim cCE(wqmulmr,   e300080, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16374218822Sdim cCE(wqmulwm,   ec000e0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16375218822Sdim cCE(wqmulwmr,  ee000e0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16376218822Sdim cCE(wsubaddhx, ed001c0, 3, (RIWR, RIWR, RIWR),     rd_rn_rm),
16377218822Sdim
16378218822Sdim#undef ARM_VARIANT
16379218822Sdim#define ARM_VARIANT &arm_cext_maverick /* Cirrus Maverick instructions.	*/
16380218822Sdim cCE(cfldrs,	c100400, 2, (RMF, ADDRGLDC),	      rd_cpaddr),
16381218822Sdim cCE(cfldrd,	c500400, 2, (RMD, ADDRGLDC),	      rd_cpaddr),
16382218822Sdim cCE(cfldr32,	c100500, 2, (RMFX, ADDRGLDC),	      rd_cpaddr),
16383218822Sdim cCE(cfldr64,	c500500, 2, (RMDX, ADDRGLDC),	      rd_cpaddr),
16384218822Sdim cCE(cfstrs,	c000400, 2, (RMF, ADDRGLDC),	      rd_cpaddr),
16385218822Sdim cCE(cfstrd,	c400400, 2, (RMD, ADDRGLDC),	      rd_cpaddr),
16386218822Sdim cCE(cfstr32,	c000500, 2, (RMFX, ADDRGLDC),	      rd_cpaddr),
16387218822Sdim cCE(cfstr64,	c400500, 2, (RMDX, ADDRGLDC),	      rd_cpaddr),
16388218822Sdim cCE(cfmvsr,	e000450, 2, (RMF, RR),		      rn_rd),
16389218822Sdim cCE(cfmvrs,	e100450, 2, (RR, RMF),		      rd_rn),
16390218822Sdim cCE(cfmvdlr,	e000410, 2, (RMD, RR),		      rn_rd),
16391218822Sdim cCE(cfmvrdl,	e100410, 2, (RR, RMD),		      rd_rn),
16392218822Sdim cCE(cfmvdhr,	e000430, 2, (RMD, RR),		      rn_rd),
16393218822Sdim cCE(cfmvrdh,	e100430, 2, (RR, RMD),		      rd_rn),
16394218822Sdim cCE(cfmv64lr,	e000510, 2, (RMDX, RR),		      rn_rd),
16395218822Sdim cCE(cfmvr64l,	e100510, 2, (RR, RMDX),		      rd_rn),
16396218822Sdim cCE(cfmv64hr,	e000530, 2, (RMDX, RR),		      rn_rd),
16397218822Sdim cCE(cfmvr64h,	e100530, 2, (RR, RMDX),		      rd_rn),
16398218822Sdim cCE(cfmval32,	e200440, 2, (RMAX, RMFX),	      rd_rn),
16399218822Sdim cCE(cfmv32al,	e100440, 2, (RMFX, RMAX),	      rd_rn),
16400218822Sdim cCE(cfmvam32,	e200460, 2, (RMAX, RMFX),	      rd_rn),
16401218822Sdim cCE(cfmv32am,	e100460, 2, (RMFX, RMAX),	      rd_rn),
16402218822Sdim cCE(cfmvah32,	e200480, 2, (RMAX, RMFX),	      rd_rn),
16403218822Sdim cCE(cfmv32ah,	e100480, 2, (RMFX, RMAX),	      rd_rn),
16404218822Sdim cCE(cfmva32,	e2004a0, 2, (RMAX, RMFX),	      rd_rn),
16405218822Sdim cCE(cfmv32a,	e1004a0, 2, (RMFX, RMAX),	      rd_rn),
16406218822Sdim cCE(cfmva64,	e2004c0, 2, (RMAX, RMDX),	      rd_rn),
16407218822Sdim cCE(cfmv64a,	e1004c0, 2, (RMDX, RMAX),	      rd_rn),
16408218822Sdim cCE(cfmvsc32,	e2004e0, 2, (RMDS, RMDX),	      mav_dspsc),
16409218822Sdim cCE(cfmv32sc,	e1004e0, 2, (RMDX, RMDS),	      rd),
16410218822Sdim cCE(cfcpys,	e000400, 2, (RMF, RMF),		      rd_rn),
16411218822Sdim cCE(cfcpyd,	e000420, 2, (RMD, RMD),		      rd_rn),
16412218822Sdim cCE(cfcvtsd,	e000460, 2, (RMD, RMF),		      rd_rn),
16413218822Sdim cCE(cfcvtds,	e000440, 2, (RMF, RMD),		      rd_rn),
16414218822Sdim cCE(cfcvt32s,	e000480, 2, (RMF, RMFX),	      rd_rn),
16415218822Sdim cCE(cfcvt32d,	e0004a0, 2, (RMD, RMFX),	      rd_rn),
16416218822Sdim cCE(cfcvt64s,	e0004c0, 2, (RMF, RMDX),	      rd_rn),
16417218822Sdim cCE(cfcvt64d,	e0004e0, 2, (RMD, RMDX),	      rd_rn),
16418218822Sdim cCE(cfcvts32,	e100580, 2, (RMFX, RMF),	      rd_rn),
16419218822Sdim cCE(cfcvtd32,	e1005a0, 2, (RMFX, RMD),	      rd_rn),
16420218822Sdim cCE(cftruncs32,e1005c0, 2, (RMFX, RMF),	      rd_rn),
16421218822Sdim cCE(cftruncd32,e1005e0, 2, (RMFX, RMD),	      rd_rn),
16422218822Sdim cCE(cfrshl32,	e000550, 3, (RMFX, RMFX, RR),	      mav_triple),
16423218822Sdim cCE(cfrshl64,	e000570, 3, (RMDX, RMDX, RR),	      mav_triple),
16424218822Sdim cCE(cfsh32,	e000500, 3, (RMFX, RMFX, I63s),	      mav_shift),
16425218822Sdim cCE(cfsh64,	e200500, 3, (RMDX, RMDX, I63s),	      mav_shift),
16426218822Sdim cCE(cfcmps,	e100490, 3, (RR, RMF, RMF),	      rd_rn_rm),
16427218822Sdim cCE(cfcmpd,	e1004b0, 3, (RR, RMD, RMD),	      rd_rn_rm),
16428218822Sdim cCE(cfcmp32,	e100590, 3, (RR, RMFX, RMFX),	      rd_rn_rm),
16429218822Sdim cCE(cfcmp64,	e1005b0, 3, (RR, RMDX, RMDX),	      rd_rn_rm),
16430218822Sdim cCE(cfabss,	e300400, 2, (RMF, RMF),		      rd_rn),
16431218822Sdim cCE(cfabsd,	e300420, 2, (RMD, RMD),		      rd_rn),
16432218822Sdim cCE(cfnegs,	e300440, 2, (RMF, RMF),		      rd_rn),
16433218822Sdim cCE(cfnegd,	e300460, 2, (RMD, RMD),		      rd_rn),
16434218822Sdim cCE(cfadds,	e300480, 3, (RMF, RMF, RMF),	      rd_rn_rm),
16435218822Sdim cCE(cfaddd,	e3004a0, 3, (RMD, RMD, RMD),	      rd_rn_rm),
16436218822Sdim cCE(cfsubs,	e3004c0, 3, (RMF, RMF, RMF),	      rd_rn_rm),
16437218822Sdim cCE(cfsubd,	e3004e0, 3, (RMD, RMD, RMD),	      rd_rn_rm),
16438218822Sdim cCE(cfmuls,	e100400, 3, (RMF, RMF, RMF),	      rd_rn_rm),
16439218822Sdim cCE(cfmuld,	e100420, 3, (RMD, RMD, RMD),	      rd_rn_rm),
16440218822Sdim cCE(cfabs32,	e300500, 2, (RMFX, RMFX),	      rd_rn),
16441218822Sdim cCE(cfabs64,	e300520, 2, (RMDX, RMDX),	      rd_rn),
16442218822Sdim cCE(cfneg32,	e300540, 2, (RMFX, RMFX),	      rd_rn),
16443218822Sdim cCE(cfneg64,	e300560, 2, (RMDX, RMDX),	      rd_rn),
16444218822Sdim cCE(cfadd32,	e300580, 3, (RMFX, RMFX, RMFX),	      rd_rn_rm),
16445218822Sdim cCE(cfadd64,	e3005a0, 3, (RMDX, RMDX, RMDX),	      rd_rn_rm),
16446218822Sdim cCE(cfsub32,	e3005c0, 3, (RMFX, RMFX, RMFX),	      rd_rn_rm),
16447218822Sdim cCE(cfsub64,	e3005e0, 3, (RMDX, RMDX, RMDX),	      rd_rn_rm),
16448218822Sdim cCE(cfmul32,	e100500, 3, (RMFX, RMFX, RMFX),	      rd_rn_rm),
16449218822Sdim cCE(cfmul64,	e100520, 3, (RMDX, RMDX, RMDX),	      rd_rn_rm),
16450218822Sdim cCE(cfmac32,	e100540, 3, (RMFX, RMFX, RMFX),	      rd_rn_rm),
16451218822Sdim cCE(cfmsc32,	e100560, 3, (RMFX, RMFX, RMFX),	      rd_rn_rm),
16452218822Sdim cCE(cfmadd32,	e000600, 4, (RMAX, RMFX, RMFX, RMFX), mav_quad),
16453218822Sdim cCE(cfmsub32,	e100600, 4, (RMAX, RMFX, RMFX, RMFX), mav_quad),
16454218822Sdim cCE(cfmadda32, e200600, 4, (RMAX, RMAX, RMFX, RMFX), mav_quad),
16455218822Sdim cCE(cfmsuba32, e300600, 4, (RMAX, RMAX, RMFX, RMFX), mav_quad),
16456218822Sdim};
16457218822Sdim#undef ARM_VARIANT
16458218822Sdim#undef THUMB_VARIANT
16459218822Sdim#undef TCE
16460218822Sdim#undef TCM
16461218822Sdim#undef TUE
16462218822Sdim#undef TUF
16463218822Sdim#undef TCC
16464218822Sdim#undef cCE
16465218822Sdim#undef cCL
16466218822Sdim#undef C3E
16467218822Sdim#undef CE
16468218822Sdim#undef CM
16469218822Sdim#undef UE
16470218822Sdim#undef UF
16471218822Sdim#undef UT
16472218822Sdim#undef NUF
16473218822Sdim#undef nUF
16474218822Sdim#undef NCE
16475218822Sdim#undef nCE
16476218822Sdim#undef OPS0
16477218822Sdim#undef OPS1
16478218822Sdim#undef OPS2
16479218822Sdim#undef OPS3
16480218822Sdim#undef OPS4
16481218822Sdim#undef OPS5
16482218822Sdim#undef OPS6
16483218822Sdim#undef do_0
16484218822Sdim
16485218822Sdim/* MD interface: bits in the object file.  */
16486218822Sdim
16487218822Sdim/* Turn an integer of n bytes (in val) into a stream of bytes appropriate
16488218822Sdim   for use in the a.out file, and stores them in the array pointed to by buf.
16489218822Sdim   This knows about the endian-ness of the target machine and does
16490218822Sdim   THE RIGHT THING, whatever it is.  Possible values for n are 1 (byte)
16491218822Sdim   2 (short) and 4 (long)  Floating numbers are put out as a series of
16492218822Sdim   LITTLENUMS (shorts, here at least).	*/
16493218822Sdim
16494218822Sdimvoid
16495218822Sdimmd_number_to_chars (char * buf, valueT val, int n)
16496218822Sdim{
16497218822Sdim  if (target_big_endian)
16498218822Sdim    number_to_chars_bigendian (buf, val, n);
16499218822Sdim  else
16500218822Sdim    number_to_chars_littleendian (buf, val, n);
1650189857Sobrien}
1650289857Sobrien
16503218822Sdimstatic valueT
16504218822Sdimmd_chars_to_number (char * buf, int n)
1650560484Sobrien{
16506218822Sdim  valueT result = 0;
16507218822Sdim  unsigned char * where = (unsigned char *) buf;
1650860484Sobrien
16509218822Sdim  if (target_big_endian)
16510130561Sobrien    {
16511218822Sdim      while (n--)
16512218822Sdim	{
16513218822Sdim	  result <<= 8;
16514218822Sdim	  result |= (*where++ & 255);
16515218822Sdim	}
16516130561Sobrien    }
16517218822Sdim  else
16518218822Sdim    {
16519218822Sdim      while (n--)
16520218822Sdim	{
16521218822Sdim	  result <<= 8;
16522218822Sdim	  result |= (where[n] & 255);
16523218822Sdim	}
16524218822Sdim    }
16525218822Sdim
16526218822Sdim  return result;
1652760484Sobrien}
1652860484Sobrien
16529218822Sdim/* MD interface: Sections.  */
1653089857Sobrien
16531218822Sdim/* Estimate the size of a frag before relaxing.  Assume everything fits in
16532218822Sdim   2 bytes.  */
1653389857Sobrien
16534218822Sdimint
16535218822Sdimmd_estimate_size_before_relax (fragS * fragp,
16536218822Sdim			       segT    segtype ATTRIBUTE_UNUSED)
1653789857Sobrien{
16538218822Sdim  fragp->fr_var = 2;
16539218822Sdim  return 2;
16540218822Sdim}
1654189857Sobrien
16542218822Sdim/* Convert a machine dependent frag.  */
1654389857Sobrien
16544218822Sdimvoid
16545218822Sdimmd_convert_frag (bfd *abfd, segT asec ATTRIBUTE_UNUSED, fragS *fragp)
16546218822Sdim{
16547218822Sdim  unsigned long insn;
16548218822Sdim  unsigned long old_op;
16549218822Sdim  char *buf;
16550218822Sdim  expressionS exp;
16551218822Sdim  fixS *fixp;
16552218822Sdim  int reloc_type;
16553218822Sdim  int pc_rel;
16554218822Sdim  int opcode;
1655589857Sobrien
16556218822Sdim  buf = fragp->fr_literal + fragp->fr_fix;
16557218822Sdim
16558218822Sdim  old_op = bfd_get_16(abfd, buf);
16559218822Sdim  if (fragp->fr_symbol) {
16560218822Sdim      exp.X_op = O_symbol;
16561218822Sdim      exp.X_add_symbol = fragp->fr_symbol;
16562218822Sdim  } else {
16563218822Sdim      exp.X_op = O_constant;
16564218822Sdim  }
16565218822Sdim  exp.X_add_number = fragp->fr_offset;
16566218822Sdim  opcode = fragp->fr_subtype;
16567218822Sdim  switch (opcode)
1656889857Sobrien    {
16569218822Sdim    case T_MNEM_ldr_pc:
16570218822Sdim    case T_MNEM_ldr_pc2:
16571218822Sdim    case T_MNEM_ldr_sp:
16572218822Sdim    case T_MNEM_str_sp:
16573218822Sdim    case T_MNEM_ldr:
16574218822Sdim    case T_MNEM_ldrb:
16575218822Sdim    case T_MNEM_ldrh:
16576218822Sdim    case T_MNEM_str:
16577218822Sdim    case T_MNEM_strb:
16578218822Sdim    case T_MNEM_strh:
16579218822Sdim      if (fragp->fr_var == 4)
1658089857Sobrien	{
16581218822Sdim	  insn = THUMB_OP32(opcode);
16582218822Sdim	  if ((old_op >> 12) == 4 || (old_op >> 12) == 9)
1658389857Sobrien	    {
16584218822Sdim	      insn |= (old_op & 0x700) << 4;
1658589857Sobrien	    }
16586218822Sdim	  else
1658789857Sobrien	    {
16588218822Sdim	      insn |= (old_op & 7) << 12;
16589218822Sdim	      insn |= (old_op & 0x38) << 13;
1659089857Sobrien	    }
16591218822Sdim	  insn |= 0x00000c00;
16592218822Sdim	  put_thumb32_insn (buf, insn);
16593218822Sdim	  reloc_type = BFD_RELOC_ARM_T32_OFFSET_IMM;
16594218822Sdim	}
16595218822Sdim      else
16596218822Sdim	{
16597218822Sdim	  reloc_type = BFD_RELOC_ARM_THUMB_OFFSET;
16598218822Sdim	}
16599218822Sdim      pc_rel = (opcode == T_MNEM_ldr_pc2);
16600218822Sdim      break;
16601218822Sdim    case T_MNEM_adr:
16602218822Sdim      if (fragp->fr_var == 4)
16603218822Sdim	{
16604218822Sdim	  insn = THUMB_OP32 (opcode);
16605218822Sdim	  insn |= (old_op & 0xf0) << 4;
16606218822Sdim	  put_thumb32_insn (buf, insn);
16607218822Sdim	  reloc_type = BFD_RELOC_ARM_T32_ADD_PC12;
16608218822Sdim	}
16609218822Sdim      else
16610218822Sdim	{
16611218822Sdim	  reloc_type = BFD_RELOC_ARM_THUMB_ADD;
16612218822Sdim	  exp.X_add_number -= 4;
16613218822Sdim	}
16614218822Sdim      pc_rel = 1;
16615218822Sdim      break;
16616218822Sdim    case T_MNEM_mov:
16617218822Sdim    case T_MNEM_movs:
16618218822Sdim    case T_MNEM_cmp:
16619218822Sdim    case T_MNEM_cmn:
16620218822Sdim      if (fragp->fr_var == 4)
16621218822Sdim	{
16622218822Sdim	  int r0off = (opcode == T_MNEM_mov
16623218822Sdim		       || opcode == T_MNEM_movs) ? 0 : 8;
16624218822Sdim	  insn = THUMB_OP32 (opcode);
16625218822Sdim	  insn = (insn & 0xe1ffffff) | 0x10000000;
16626218822Sdim	  insn |= (old_op & 0x700) << r0off;
16627218822Sdim	  put_thumb32_insn (buf, insn);
16628218822Sdim	  reloc_type = BFD_RELOC_ARM_T32_IMMEDIATE;
16629218822Sdim	}
16630218822Sdim      else
16631218822Sdim	{
16632218822Sdim	  reloc_type = BFD_RELOC_ARM_THUMB_IMM;
16633218822Sdim	}
16634218822Sdim      pc_rel = 0;
16635218822Sdim      break;
16636218822Sdim    case T_MNEM_b:
16637218822Sdim      if (fragp->fr_var == 4)
16638218822Sdim	{
16639218822Sdim	  insn = THUMB_OP32(opcode);
16640218822Sdim	  put_thumb32_insn (buf, insn);
16641218822Sdim	  reloc_type = BFD_RELOC_THUMB_PCREL_BRANCH25;
16642218822Sdim	}
16643218822Sdim      else
16644218822Sdim	reloc_type = BFD_RELOC_THUMB_PCREL_BRANCH12;
16645218822Sdim      pc_rel = 1;
16646218822Sdim      break;
16647218822Sdim    case T_MNEM_bcond:
16648218822Sdim      if (fragp->fr_var == 4)
16649218822Sdim	{
16650218822Sdim	  insn = THUMB_OP32(opcode);
16651218822Sdim	  insn |= (old_op & 0xf00) << 14;
16652218822Sdim	  put_thumb32_insn (buf, insn);
16653218822Sdim	  reloc_type = BFD_RELOC_THUMB_PCREL_BRANCH20;
16654218822Sdim	}
16655218822Sdim      else
16656218822Sdim	reloc_type = BFD_RELOC_THUMB_PCREL_BRANCH9;
16657218822Sdim      pc_rel = 1;
16658218822Sdim      break;
16659218822Sdim    case T_MNEM_add_sp:
16660218822Sdim    case T_MNEM_add_pc:
16661218822Sdim    case T_MNEM_inc_sp:
16662218822Sdim    case T_MNEM_dec_sp:
16663218822Sdim      if (fragp->fr_var == 4)
16664218822Sdim	{
16665218822Sdim	  /* ??? Choose between add and addw.  */
16666218822Sdim	  insn = THUMB_OP32 (opcode);
16667218822Sdim	  insn |= (old_op & 0xf0) << 4;
16668218822Sdim	  put_thumb32_insn (buf, insn);
16669218822Sdim	  if (opcode == T_MNEM_add_pc)
16670218822Sdim	    reloc_type = BFD_RELOC_ARM_T32_IMM12;
1667189857Sobrien	  else
16672218822Sdim	    reloc_type = BFD_RELOC_ARM_T32_ADD_IMM;
16673218822Sdim	}
16674218822Sdim      else
16675218822Sdim	reloc_type = BFD_RELOC_ARM_THUMB_ADD;
16676218822Sdim      pc_rel = 0;
16677218822Sdim      break;
1667889857Sobrien
16679218822Sdim    case T_MNEM_addi:
16680218822Sdim    case T_MNEM_addis:
16681218822Sdim    case T_MNEM_subi:
16682218822Sdim    case T_MNEM_subis:
16683218822Sdim      if (fragp->fr_var == 4)
16684218822Sdim	{
16685218822Sdim	  insn = THUMB_OP32 (opcode);
16686218822Sdim	  insn |= (old_op & 0xf0) << 4;
16687218822Sdim	  insn |= (old_op & 0xf) << 16;
16688218822Sdim	  put_thumb32_insn (buf, insn);
16689218822Sdim	  if (insn & (1 << 20))
16690218822Sdim	    reloc_type = BFD_RELOC_ARM_T32_ADD_IMM;
16691218822Sdim	  else
16692218822Sdim	    reloc_type = BFD_RELOC_ARM_T32_IMMEDIATE;
1669389857Sobrien	}
1669489857Sobrien      else
16695218822Sdim	reloc_type = BFD_RELOC_ARM_THUMB_ADD;
16696218822Sdim      pc_rel = 0;
16697218822Sdim      break;
16698218822Sdim    default:
16699218822Sdim      abort();
1670089857Sobrien    }
16701218822Sdim  fixp = fix_new_exp (fragp, fragp->fr_fix, fragp->fr_var, &exp, pc_rel,
16702218822Sdim		      reloc_type);
16703218822Sdim  fixp->fx_file = fragp->fr_file;
16704218822Sdim  fixp->fx_line = fragp->fr_line;
16705218822Sdim  fragp->fr_fix += fragp->fr_var;
1670689857Sobrien}
16707104834Sobrien
16708218822Sdim/* Return the size of a relaxable immediate operand instruction.
16709218822Sdim   SHIFT and SIZE specify the form of the allowable immediate.  */
16710218822Sdimstatic int
16711218822Sdimrelax_immediate (fragS *fragp, int size, int shift)
1671260484Sobrien{
16713218822Sdim  offsetT offset;
16714218822Sdim  offsetT mask;
16715218822Sdim  offsetT low;
1671660484Sobrien
16717218822Sdim  /* ??? Should be able to do better than this.  */
16718218822Sdim  if (fragp->fr_symbol)
16719218822Sdim    return 4;
16720218822Sdim
16721218822Sdim  low = (1 << shift) - 1;
16722218822Sdim  mask = (1 << (shift + size)) - (1 << shift);
16723218822Sdim  offset = fragp->fr_offset;
16724218822Sdim  /* Force misaligned offsets to 32-bit variant.  */
16725218822Sdim  if (offset & low)
16726218822Sdim    return 4;
16727218822Sdim  if (offset & ~mask)
16728218822Sdim    return 4;
16729218822Sdim  return 2;
1673060484Sobrien}
1673160484Sobrien
16732218822Sdim/* Get the address of a symbol during relaxation.  */
16733218822Sdimstatic addressT
16734218822Sdimrelaxed_symbol_addr(fragS *fragp, long stretch)
1673589857Sobrien{
16736218822Sdim  fragS *sym_frag;
16737218822Sdim  addressT addr;
16738218822Sdim  symbolS *sym;
1673989857Sobrien
16740218822Sdim  sym = fragp->fr_symbol;
16741218822Sdim  sym_frag = symbol_get_frag (sym);
16742218822Sdim  know (S_GET_SEGMENT (sym) != absolute_section
16743218822Sdim	|| sym_frag == &zero_address_frag);
16744218822Sdim  addr = S_GET_VALUE (sym) + fragp->fr_offset;
1674589857Sobrien
16746218822Sdim  /* If frag has yet to be reached on this pass, assume it will
16747218822Sdim     move by STRETCH just as we did.  If this is not so, it will
16748218822Sdim     be because some frag between grows, and that will force
16749218822Sdim     another pass.  */
1675089857Sobrien
16751218822Sdim  if (stretch != 0
16752218822Sdim      && sym_frag->relax_marker != fragp->relax_marker)
16753218822Sdim    addr += stretch;
1675489857Sobrien
16755218822Sdim  return addr;
16756218822Sdim}
1675789857Sobrien
16758218822Sdim/* Return the size of a relaxable adr pseudo-instruction or PC-relative
16759218822Sdim   load.  */
16760218822Sdimstatic int
16761218822Sdimrelax_adr (fragS *fragp, asection *sec, long stretch)
16762218822Sdim{
16763218822Sdim  addressT addr;
16764218822Sdim  offsetT val;
1676589857Sobrien
16766218822Sdim  /* Assume worst case for symbols not known to be in the same section.  */
16767218822Sdim  if (!S_IS_DEFINED(fragp->fr_symbol)
16768218822Sdim      || sec != S_GET_SEGMENT (fragp->fr_symbol))
16769218822Sdim    return 4;
16770218822Sdim
16771218822Sdim  val = relaxed_symbol_addr(fragp, stretch);
16772218822Sdim  addr = fragp->fr_address + fragp->fr_fix;
16773218822Sdim  addr = (addr + 4) & ~3;
16774218822Sdim  /* Force misaligned targets to 32-bit variant.  */
16775218822Sdim  if (val & 3)
16776218822Sdim    return 4;
16777218822Sdim  val -= addr;
16778218822Sdim  if (val < 0 || val > 1020)
16779218822Sdim    return 4;
16780218822Sdim  return 2;
1678189857Sobrien}
1678289857Sobrien
16783218822Sdim/* Return the size of a relaxable add/sub immediate instruction.  */
16784218822Sdimstatic int
16785218822Sdimrelax_addsub (fragS *fragp, asection *sec)
16786130561Sobrien{
16787218822Sdim  char *buf;
16788218822Sdim  int op;
16789130561Sobrien
16790218822Sdim  buf = fragp->fr_literal + fragp->fr_fix;
16791218822Sdim  op = bfd_get_16(sec->owner, buf);
16792218822Sdim  if ((op & 0xf) == ((op >> 4) & 0xf))
16793218822Sdim    return relax_immediate (fragp, 8, 0);
16794218822Sdim  else
16795218822Sdim    return relax_immediate (fragp, 3, 0);
16796218822Sdim}
16797130561Sobrien
16798130561Sobrien
16799218822Sdim/* Return the size of a relaxable branch instruction.  BITS is the
16800218822Sdim   size of the offset field in the narrow instruction.  */
16801130561Sobrien
16802218822Sdimstatic int
16803218822Sdimrelax_branch (fragS *fragp, asection *sec, int bits, long stretch)
16804218822Sdim{
16805218822Sdim  addressT addr;
16806218822Sdim  offsetT val;
16807218822Sdim  offsetT limit;
16808130561Sobrien
16809218822Sdim  /* Assume worst case for symbols not known to be in the same section.  */
16810218822Sdim  if (!S_IS_DEFINED(fragp->fr_symbol)
16811218822Sdim      || sec != S_GET_SEGMENT (fragp->fr_symbol))
16812218822Sdim    return 4;
16813130561Sobrien
16814218822Sdim  val = relaxed_symbol_addr(fragp, stretch);
16815218822Sdim  addr = fragp->fr_address + fragp->fr_fix + 4;
16816218822Sdim  val -= addr;
16817130561Sobrien
16818218822Sdim  /* Offset is a signed value *2 */
16819218822Sdim  limit = 1 << bits;
16820218822Sdim  if (val >= limit || val < -limit)
16821218822Sdim    return 4;
16822218822Sdim  return 2;
16823130561Sobrien}
16824130561Sobrien
16825218822Sdim
16826218822Sdim/* Relax a machine dependent frag.  This returns the amount by which
16827218822Sdim   the current size of the frag should change.  */
16828218822Sdim
16829218822Sdimint
16830218822Sdimarm_relax_frag (asection *sec, fragS *fragp, long stretch)
1683160484Sobrien{
16832218822Sdim  int oldsize;
16833218822Sdim  int newsize;
1683477298Sobrien
16835218822Sdim  oldsize = fragp->fr_var;
16836218822Sdim  switch (fragp->fr_subtype)
16837218822Sdim    {
16838218822Sdim    case T_MNEM_ldr_pc2:
16839218822Sdim      newsize = relax_adr(fragp, sec, stretch);
16840218822Sdim      break;
16841218822Sdim    case T_MNEM_ldr_pc:
16842218822Sdim    case T_MNEM_ldr_sp:
16843218822Sdim    case T_MNEM_str_sp:
16844218822Sdim      newsize = relax_immediate(fragp, 8, 2);
16845218822Sdim      break;
16846218822Sdim    case T_MNEM_ldr:
16847218822Sdim    case T_MNEM_str:
16848218822Sdim      newsize = relax_immediate(fragp, 5, 2);
16849218822Sdim      break;
16850218822Sdim    case T_MNEM_ldrh:
16851218822Sdim    case T_MNEM_strh:
16852218822Sdim      newsize = relax_immediate(fragp, 5, 1);
16853218822Sdim      break;
16854218822Sdim    case T_MNEM_ldrb:
16855218822Sdim    case T_MNEM_strb:
16856218822Sdim      newsize = relax_immediate(fragp, 5, 0);
16857218822Sdim      break;
16858218822Sdim    case T_MNEM_adr:
16859218822Sdim      newsize = relax_adr(fragp, sec, stretch);
16860218822Sdim      break;
16861218822Sdim    case T_MNEM_mov:
16862218822Sdim    case T_MNEM_movs:
16863218822Sdim    case T_MNEM_cmp:
16864218822Sdim    case T_MNEM_cmn:
16865218822Sdim      newsize = relax_immediate(fragp, 8, 0);
16866218822Sdim      break;
16867218822Sdim    case T_MNEM_b:
16868218822Sdim      newsize = relax_branch(fragp, sec, 11, stretch);
16869218822Sdim      break;
16870218822Sdim    case T_MNEM_bcond:
16871218822Sdim      newsize = relax_branch(fragp, sec, 8, stretch);
16872218822Sdim      break;
16873218822Sdim    case T_MNEM_add_sp:
16874218822Sdim    case T_MNEM_add_pc:
16875218822Sdim      newsize = relax_immediate (fragp, 8, 2);
16876218822Sdim      break;
16877218822Sdim    case T_MNEM_inc_sp:
16878218822Sdim    case T_MNEM_dec_sp:
16879218822Sdim      newsize = relax_immediate (fragp, 7, 2);
16880218822Sdim      break;
16881218822Sdim    case T_MNEM_addi:
16882218822Sdim    case T_MNEM_addis:
16883218822Sdim    case T_MNEM_subi:
16884218822Sdim    case T_MNEM_subis:
16885218822Sdim      newsize = relax_addsub (fragp, sec);
16886218822Sdim      break;
16887218822Sdim    default:
16888218822Sdim      abort();
16889218822Sdim    }
1689077298Sobrien
16891218822Sdim  fragp->fr_var = newsize;
16892218822Sdim  /* Freeze wide instructions that are at or before the same location as
16893218822Sdim     in the previous pass.  This avoids infinite loops.
16894218822Sdim     Don't freeze them unconditionally because targets may be artificialy
16895218822Sdim     misaligned by the expansion of preceeding frags.  */
16896218822Sdim  if (stretch <= 0 && newsize > 2)
16897218822Sdim    {
16898218822Sdim      md_convert_frag (sec->owner, sec, fragp);
16899218822Sdim      frag_wane(fragp);
16900218822Sdim    }
1690160484Sobrien
16902218822Sdim  return newsize - oldsize;
16903218822Sdim}
1690460484Sobrien
16905218822Sdim/* Round up a section size to the appropriate boundary.	 */
1690660484Sobrien
16907218822SdimvalueT
16908218822Sdimmd_section_align (segT	 segment ATTRIBUTE_UNUSED,
16909218822Sdim		  valueT size)
16910218822Sdim{
16911218822Sdim#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
16912218822Sdim  if (OUTPUT_FLAVOR == bfd_target_aout_flavour)
1691389857Sobrien    {
16914218822Sdim      /* For a.out, force the section size to be aligned.  If we don't do
16915218822Sdim	 this, BFD will align it for us, but it will not write out the
16916218822Sdim	 final bytes of the section.  This may be a bug in BFD, but it is
16917218822Sdim	 easier to fix it here since that is how the other a.out targets
16918218822Sdim	 work.  */
16919218822Sdim      int align;
1692089857Sobrien
16921218822Sdim      align = bfd_get_section_alignment (stdoutput, segment);
16922218822Sdim      size = ((size + (1 << align) - 1) & ((valueT) -1 << align));
1692389857Sobrien    }
16924218822Sdim#endif
1692589857Sobrien
16926218822Sdim  return size;
16927218822Sdim}
16928218822Sdim
16929218822Sdim/* This is called from HANDLE_ALIGN in write.c.	 Fill in the contents
16930218822Sdim   of an rs_align_code fragment.  */
16931218822Sdim
16932218822Sdimvoid
16933218822Sdimarm_handle_align (fragS * fragP)
16934218822Sdim{
16935218822Sdim  static char const arm_noop[4] = { 0x00, 0x00, 0xa0, 0xe1 };
16936218822Sdim  static char const thumb_noop[2] = { 0xc0, 0x46 };
16937218822Sdim  static char const arm_bigend_noop[4] = { 0xe1, 0xa0, 0x00, 0x00 };
16938218822Sdim  static char const thumb_bigend_noop[2] = { 0x46, 0xc0 };
16939218822Sdim
16940218822Sdim  int bytes, fix, noop_size;
16941218822Sdim  char * p;
16942218822Sdim  const char * noop;
16943218822Sdim
16944218822Sdim  if (fragP->fr_type != rs_align_code)
16945218822Sdim    return;
16946218822Sdim
16947218822Sdim  bytes = fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix;
16948218822Sdim  p = fragP->fr_literal + fragP->fr_fix;
16949218822Sdim  fix = 0;
16950218822Sdim
16951218822Sdim  if (bytes > MAX_MEM_FOR_RS_ALIGN_CODE)
16952218822Sdim    bytes &= MAX_MEM_FOR_RS_ALIGN_CODE;
16953218822Sdim
16954218822Sdim  if (fragP->tc_frag_data)
1695589857Sobrien    {
16956218822Sdim      if (target_big_endian)
16957218822Sdim	noop = thumb_bigend_noop;
16958218822Sdim      else
16959218822Sdim	noop = thumb_noop;
16960218822Sdim      noop_size = sizeof (thumb_noop);
1696189857Sobrien    }
16962218822Sdim  else
1696389857Sobrien    {
16964218822Sdim      if (target_big_endian)
16965218822Sdim	noop = arm_bigend_noop;
1696689857Sobrien      else
16967218822Sdim	noop = arm_noop;
16968218822Sdim      noop_size = sizeof (arm_noop);
1696989857Sobrien    }
1697089857Sobrien
16971218822Sdim  if (bytes & (noop_size - 1))
1697289857Sobrien    {
16973218822Sdim      fix = bytes & (noop_size - 1);
16974218822Sdim      memset (p, 0, fix);
16975218822Sdim      p += fix;
16976218822Sdim      bytes -= fix;
1697789857Sobrien    }
1697889857Sobrien
16979218822Sdim  while (bytes >= noop_size)
16980218822Sdim    {
16981218822Sdim      memcpy (p, noop, noop_size);
16982218822Sdim      p += noop_size;
16983218822Sdim      bytes -= noop_size;
16984218822Sdim      fix += noop_size;
16985218822Sdim    }
1698689857Sobrien
16987218822Sdim  fragP->fr_fix += fix;
16988218822Sdim  fragP->fr_var = noop_size;
16989218822Sdim}
1699089857Sobrien
16991218822Sdim/* Called from md_do_align.  Used to create an alignment
16992218822Sdim   frag in a code section.  */
1699377298Sobrien
16994218822Sdimvoid
16995218822Sdimarm_frag_align_code (int n, int max)
16996218822Sdim{
16997218822Sdim  char * p;
16998130561Sobrien
16999218822Sdim  /* We assume that there will never be a requirement
17000218822Sdim     to support alignments greater than 32 bytes.  */
17001218822Sdim  if (max > MAX_MEM_FOR_RS_ALIGN_CODE)
17002218822Sdim    as_fatal (_("alignments greater than 32 bytes not supported in .text sections."));
1700360484Sobrien
17004218822Sdim  p = frag_var (rs_align_code,
17005218822Sdim		MAX_MEM_FOR_RS_ALIGN_CODE,
17006218822Sdim		1,
17007218822Sdim		(relax_substateT) max,
17008218822Sdim		(symbolS *) NULL,
17009218822Sdim		(offsetT) n,
17010218822Sdim		(char *) NULL);
17011218822Sdim  *p = 0;
17012218822Sdim}
1701389857Sobrien
17014218822Sdim/* Perform target specific initialisation of a frag.  */
1701577298Sobrien
17016218822Sdimvoid
17017218822Sdimarm_init_frag (fragS * fragP)
17018218822Sdim{
17019218822Sdim  /* Record whether this frag is in an ARM or a THUMB area.  */
17020218822Sdim  fragP->tc_frag_data = thumb_mode;
17021218822Sdim}
1702277298Sobrien
17023218822Sdim#ifdef OBJ_ELF
17024218822Sdim/* When we change sections we need to issue a new mapping symbol.  */
1702577298Sobrien
17026218822Sdimvoid
17027218822Sdimarm_elf_change_section (void)
17028218822Sdim{
17029218822Sdim  flagword flags;
17030218822Sdim  segment_info_type *seginfo;
1703177298Sobrien
17032218822Sdim  /* Link an unlinked unwind index table section to the .text section.	*/
17033218822Sdim  if (elf_section_type (now_seg) == SHT_ARM_EXIDX
17034218822Sdim      && elf_linked_to_section (now_seg) == NULL)
17035218822Sdim    elf_linked_to_section (now_seg) = text_section;
1703677298Sobrien
17037218822Sdim  if (!SEG_NORMAL (now_seg))
17038218822Sdim    return;
1703977298Sobrien
17040218822Sdim  flags = bfd_get_section_flags (stdoutput, now_seg);
1704189857Sobrien
17042218822Sdim  /* We can ignore sections that only contain debug info.  */
17043218822Sdim  if ((flags & SEC_ALLOC) == 0)
17044218822Sdim    return;
1704577298Sobrien
17046218822Sdim  seginfo = seg_info (now_seg);
17047218822Sdim  mapstate = seginfo->tc_segment_info_data.mapstate;
17048218822Sdim  marked_pr_dependency = seginfo->tc_segment_info_data.marked_pr_dependency;
17049218822Sdim}
17050218822Sdim
17051218822Sdimint
17052218822Sdimarm_elf_section_type (const char * str, size_t len)
17053218822Sdim{
17054218822Sdim  if (len == 5 && strncmp (str, "exidx", 5) == 0)
17055218822Sdim    return SHT_ARM_EXIDX;
17056218822Sdim
17057218822Sdim  return -1;
17058218822Sdim}
17059218822Sdim
17060218822Sdim/* Code to deal with unwinding tables.	*/
17061218822Sdim
17062218822Sdimstatic void add_unwind_adjustsp (offsetT);
17063218822Sdim
17064218822Sdim/* Cenerate and deferred unwind frame offset.  */
17065218822Sdim
17066218822Sdimstatic void
17067218822Sdimflush_pending_unwind (void)
17068218822Sdim{
17069218822Sdim  offsetT offset;
17070218822Sdim
17071218822Sdim  offset = unwind.pending_offset;
17072218822Sdim  unwind.pending_offset = 0;
17073218822Sdim  if (offset != 0)
17074218822Sdim    add_unwind_adjustsp (offset);
17075218822Sdim}
17076218822Sdim
17077218822Sdim/* Add an opcode to this list for this function.  Two-byte opcodes should
17078218822Sdim   be passed as op[0] << 8 | op[1].  The list of opcodes is built in reverse
17079218822Sdim   order.  */
17080218822Sdim
17081218822Sdimstatic void
17082218822Sdimadd_unwind_opcode (valueT op, int length)
17083218822Sdim{
17084218822Sdim  /* Add any deferred stack adjustment.	 */
17085218822Sdim  if (unwind.pending_offset)
17086218822Sdim    flush_pending_unwind ();
17087218822Sdim
17088218822Sdim  unwind.sp_restored = 0;
17089218822Sdim
17090218822Sdim  if (unwind.opcode_count + length > unwind.opcode_alloc)
1709160484Sobrien    {
17092218822Sdim      unwind.opcode_alloc += ARM_OPCODE_CHUNK_SIZE;
17093218822Sdim      if (unwind.opcodes)
17094218822Sdim	unwind.opcodes = xrealloc (unwind.opcodes,
17095218822Sdim				   unwind.opcode_alloc);
1709678828Sobrien      else
17097218822Sdim	unwind.opcodes = xmalloc (unwind.opcode_alloc);
1709860484Sobrien    }
17099218822Sdim  while (length > 0)
1710078828Sobrien    {
17101218822Sdim      length--;
17102218822Sdim      unwind.opcodes[unwind.opcode_count] = op & 0xff;
17103218822Sdim      op >>= 8;
17104218822Sdim      unwind.opcode_count++;
1710578828Sobrien    }
17106218822Sdim}
1710777298Sobrien
17108218822Sdim/* Add unwind opcodes to adjust the stack pointer.  */
17109130561Sobrien
17110218822Sdimstatic void
17111218822Sdimadd_unwind_adjustsp (offsetT offset)
17112218822Sdim{
17113218822Sdim  valueT op;
17114130561Sobrien
17115218822Sdim  if (offset > 0x200)
17116218822Sdim    {
17117218822Sdim      /* We need at most 5 bytes to hold a 32-bit value in a uleb128.  */
17118218822Sdim      char bytes[5];
17119218822Sdim      int n;
17120218822Sdim      valueT o;
17121130561Sobrien
17122218822Sdim      /* Long form: 0xb2, uleb128.  */
17123218822Sdim      /* This might not fit in a word so add the individual bytes,
17124218822Sdim	 remembering the list is built in reverse order.  */
17125218822Sdim      o = (valueT) ((offset - 0x204) >> 2);
17126218822Sdim      if (o == 0)
17127218822Sdim	add_unwind_opcode (0, 1);
17128130561Sobrien
17129218822Sdim      /* Calculate the uleb128 encoding of the offset.	*/
17130218822Sdim      n = 0;
17131218822Sdim      while (o)
17132218822Sdim	{
17133218822Sdim	  bytes[n] = o & 0x7f;
17134218822Sdim	  o >>= 7;
17135218822Sdim	  if (o)
17136218822Sdim	    bytes[n] |= 0x80;
17137218822Sdim	  n++;
17138218822Sdim	}
17139218822Sdim      /* Add the insn.	*/
17140218822Sdim      for (; n; n--)
17141218822Sdim	add_unwind_opcode (bytes[n - 1], 1);
17142218822Sdim      add_unwind_opcode (0xb2, 1);
17143218822Sdim    }
17144218822Sdim  else if (offset > 0x100)
17145218822Sdim    {
17146218822Sdim      /* Two short opcodes.  */
17147218822Sdim      add_unwind_opcode (0x3f, 1);
17148218822Sdim      op = (offset - 0x104) >> 2;
17149218822Sdim      add_unwind_opcode (op, 1);
17150218822Sdim    }
17151218822Sdim  else if (offset > 0)
17152218822Sdim    {
17153218822Sdim      /* Short opcode.	*/
17154218822Sdim      op = (offset - 4) >> 2;
17155218822Sdim      add_unwind_opcode (op, 1);
17156218822Sdim    }
17157218822Sdim  else if (offset < 0)
17158218822Sdim    {
17159218822Sdim      offset = -offset;
17160218822Sdim      while (offset > 0x100)
17161218822Sdim	{
17162218822Sdim	  add_unwind_opcode (0x7f, 1);
17163218822Sdim	  offset -= 0x100;
17164218822Sdim	}
17165218822Sdim      op = ((offset - 4) >> 2) | 0x40;
17166218822Sdim      add_unwind_opcode (op, 1);
17167218822Sdim    }
17168218822Sdim}
17169130561Sobrien
17170218822Sdim/* Finish the list of unwind opcodes for this function.	 */
17171218822Sdimstatic void
17172218822Sdimfinish_unwind_opcodes (void)
17173218822Sdim{
17174218822Sdim  valueT op;
17175130561Sobrien
17176218822Sdim  if (unwind.fp_used)
17177218822Sdim    {
17178218822Sdim      /* Adjust sp as necessary.  */
17179218822Sdim      unwind.pending_offset += unwind.fp_offset - unwind.frame_size;
17180218822Sdim      flush_pending_unwind ();
17181130561Sobrien
17182218822Sdim      /* After restoring sp from the frame pointer.  */
17183218822Sdim      op = 0x90 | unwind.fp_reg;
17184218822Sdim      add_unwind_opcode (op, 1);
17185218822Sdim    }
17186218822Sdim  else
17187218822Sdim    flush_pending_unwind ();
1718860484Sobrien}
1718960484Sobrien
1719077298Sobrien
17191218822Sdim/* Start an exception table entry.  If idx is nonzero this is an index table
17192218822Sdim   entry.  */
17193218822Sdim
17194218822Sdimstatic void
17195218822Sdimstart_unwind_section (const segT text_seg, int idx)
1719660484Sobrien{
17197218822Sdim  const char * text_name;
17198218822Sdim  const char * prefix;
17199218822Sdim  const char * prefix_once;
17200218822Sdim  const char * group_name;
17201218822Sdim  size_t prefix_len;
17202218822Sdim  size_t text_len;
17203218822Sdim  char * sec_name;
17204218822Sdim  size_t sec_name_len;
17205218822Sdim  int type;
17206218822Sdim  int flags;
17207218822Sdim  int linkonce;
17208218822Sdim
17209218822Sdim  if (idx)
17210218822Sdim    {
17211218822Sdim      prefix = ELF_STRING_ARM_unwind;
17212218822Sdim      prefix_once = ELF_STRING_ARM_unwind_once;
17213218822Sdim      type = SHT_ARM_EXIDX;
17214218822Sdim    }
1721560484Sobrien  else
17216218822Sdim    {
17217218822Sdim      prefix = ELF_STRING_ARM_unwind_info;
17218218822Sdim      prefix_once = ELF_STRING_ARM_unwind_info_once;
17219218822Sdim      type = SHT_PROGBITS;
17220218822Sdim    }
17221218822Sdim
17222218822Sdim  text_name = segment_name (text_seg);
17223218822Sdim  if (streq (text_name, ".text"))
17224218822Sdim    text_name = "";
17225218822Sdim
17226218822Sdim  if (strncmp (text_name, ".gnu.linkonce.t.",
17227218822Sdim	       strlen (".gnu.linkonce.t.")) == 0)
17228218822Sdim    {
17229218822Sdim      prefix = prefix_once;
17230218822Sdim      text_name += strlen (".gnu.linkonce.t.");
17231218822Sdim    }
17232218822Sdim
17233218822Sdim  prefix_len = strlen (prefix);
17234218822Sdim  text_len = strlen (text_name);
17235218822Sdim  sec_name_len = prefix_len + text_len;
17236218822Sdim  sec_name = xmalloc (sec_name_len + 1);
17237218822Sdim  memcpy (sec_name, prefix, prefix_len);
17238218822Sdim  memcpy (sec_name + prefix_len, text_name, text_len);
17239218822Sdim  sec_name[prefix_len + text_len] = '\0';
17240218822Sdim
17241218822Sdim  flags = SHF_ALLOC;
17242218822Sdim  linkonce = 0;
17243218822Sdim  group_name = 0;
17244218822Sdim
17245218822Sdim  /* Handle COMDAT group.  */
17246218822Sdim  if (prefix != prefix_once && (text_seg->flags & SEC_LINK_ONCE) != 0)
17247218822Sdim    {
17248218822Sdim      group_name = elf_group_name (text_seg);
17249218822Sdim      if (group_name == NULL)
17250218822Sdim	{
17251218822Sdim	  as_bad ("Group section `%s' has no group signature",
17252218822Sdim		  segment_name (text_seg));
17253218822Sdim	  ignore_rest_of_line ();
17254218822Sdim	  return;
17255218822Sdim	}
17256218822Sdim      flags |= SHF_GROUP;
17257218822Sdim      linkonce = 1;
17258218822Sdim    }
17259218822Sdim
17260218822Sdim  obj_elf_change_section (sec_name, type, flags, 0, group_name, linkonce, 0);
17261218822Sdim
17262218822Sdim  /* Set the setion link for index tables.  */
17263218822Sdim  if (idx)
17264218822Sdim    elf_linked_to_section (now_seg) = text_seg;
1726560484Sobrien}
1726660484Sobrien
17267218822Sdim
17268218822Sdim/* Start an unwind table entry.	 HAVE_DATA is nonzero if we have additional
17269218822Sdim   personality routine data.  Returns zero, or the index table value for
17270218822Sdim   and inline entry.  */
17271218822Sdim
1727277298Sobrienstatic valueT
17273218822Sdimcreate_unwind_entry (int have_data)
1727460484Sobrien{
17275218822Sdim  int size;
17276218822Sdim  addressT where;
17277218822Sdim  char *ptr;
17278218822Sdim  /* The current word of data.	*/
17279218822Sdim  valueT data;
17280218822Sdim  /* The number of bytes left in this word.  */
17281218822Sdim  int n;
1728260484Sobrien
17283218822Sdim  finish_unwind_opcodes ();
17284218822Sdim
17285218822Sdim  /* Remember the current text section.	 */
17286218822Sdim  unwind.saved_seg = now_seg;
17287218822Sdim  unwind.saved_subseg = now_subseg;
17288218822Sdim
17289218822Sdim  start_unwind_section (now_seg, 0);
17290218822Sdim
17291218822Sdim  if (unwind.personality_routine == NULL)
1729260484Sobrien    {
17293218822Sdim      if (unwind.personality_index == -2)
1729460484Sobrien	{
17295218822Sdim	  if (have_data)
17296218822Sdim	    as_bad (_("handerdata in cantunwind frame"));
17297218822Sdim	  return 1; /* EXIDX_CANTUNWIND.  */
1729860484Sobrien	}
17299218822Sdim
17300218822Sdim      /* Use a default personality routine if none is specified.  */
17301218822Sdim      if (unwind.personality_index == -1)
1730260484Sobrien	{
17303218822Sdim	  if (unwind.opcode_count > 3)
17304218822Sdim	    unwind.personality_index = 1;
17305218822Sdim	  else
17306218822Sdim	    unwind.personality_index = 0;
1730760484Sobrien	}
1730860484Sobrien
17309218822Sdim      /* Space for the personality routine entry.  */
17310218822Sdim      if (unwind.personality_index == 0)
17311218822Sdim	{
17312218822Sdim	  if (unwind.opcode_count > 3)
17313218822Sdim	    as_bad (_("too many unwind opcodes for personality routine 0"));
1731460484Sobrien
17315218822Sdim	  if (!have_data)
17316218822Sdim	    {
17317218822Sdim	      /* All the data is inline in the index table.  */
17318218822Sdim	      data = 0x80;
17319218822Sdim	      n = 3;
17320218822Sdim	      while (unwind.opcode_count > 0)
17321218822Sdim		{
17322218822Sdim		  unwind.opcode_count--;
17323218822Sdim		  data = (data << 8) | unwind.opcodes[unwind.opcode_count];
17324218822Sdim		  n--;
17325218822Sdim		}
1732660484Sobrien
17327218822Sdim	      /* Pad with "finish" opcodes.  */
17328218822Sdim	      while (n--)
17329218822Sdim		data = (data << 8) | 0xb0;
1733060484Sobrien
17331218822Sdim	      return data;
17332218822Sdim	    }
17333218822Sdim	  size = 0;
17334218822Sdim	}
17335218822Sdim      else
17336218822Sdim	/* We get two opcodes "free" in the first word.	 */
17337218822Sdim	size = unwind.opcode_count - 2;
17338218822Sdim    }
17339218822Sdim  else
17340218822Sdim    /* An extra byte is required for the opcode count.	*/
17341218822Sdim    size = unwind.opcode_count + 1;
1734260484Sobrien
17343218822Sdim  size = (size + 3) >> 2;
17344218822Sdim  if (size > 0xff)
17345218822Sdim    as_bad (_("too many unwind opcodes"));
1734660484Sobrien
17347218822Sdim  frag_align (2, 0, 0);
17348218822Sdim  record_alignment (now_seg, 2);
17349218822Sdim  unwind.table_entry = expr_build_dot ();
17350218822Sdim
17351218822Sdim  /* Allocate the table entry.	*/
17352218822Sdim  ptr = frag_more ((size << 2) + 4);
17353218822Sdim  where = frag_now_fix () - ((size << 2) + 4);
17354218822Sdim
17355218822Sdim  switch (unwind.personality_index)
1735660484Sobrien    {
17357218822Sdim    case -1:
17358218822Sdim      /* ??? Should this be a PLT generating relocation?  */
17359218822Sdim      /* Custom personality routine.  */
17360218822Sdim      fix_new (frag_now, where, 4, unwind.personality_routine, 0, 1,
17361218822Sdim	       BFD_RELOC_ARM_PREL31);
1736260484Sobrien
17363218822Sdim      where += 4;
17364218822Sdim      ptr += 4;
17365218822Sdim
17366218822Sdim      /* Set the first byte to the number of additional words.	*/
17367218822Sdim      data = size - 1;
17368218822Sdim      n = 3;
1736960484Sobrien      break;
1737060484Sobrien
17371218822Sdim    /* ABI defined personality routines.  */
17372218822Sdim    case 0:
17373218822Sdim      /* Three opcodes bytes are packed into the first word.  */
17374218822Sdim      data = 0x80;
17375218822Sdim      n = 3;
1737660484Sobrien      break;
1737760484Sobrien
17378218822Sdim    case 1:
17379218822Sdim    case 2:
17380218822Sdim      /* The size and first two opcode bytes go in the first word.  */
17381218822Sdim      data = ((0x80 + unwind.personality_index) << 8) | size;
17382218822Sdim      n = 2;
1738360484Sobrien      break;
1738460484Sobrien
1738560484Sobrien    default:
17386218822Sdim      /* Should never happen.  */
17387218822Sdim      abort ();
1738860484Sobrien    }
1738960484Sobrien
17390218822Sdim  /* Pack the opcodes into words (MSB first), reversing the list at the same
17391218822Sdim     time.  */
17392218822Sdim  while (unwind.opcode_count > 0)
1739360484Sobrien    {
17394218822Sdim      if (n == 0)
1739560484Sobrien	{
17396218822Sdim	  md_number_to_chars (ptr, data, 4);
17397218822Sdim	  ptr += 4;
17398218822Sdim	  n = 4;
17399218822Sdim	  data = 0;
1740060484Sobrien	}
17401218822Sdim      unwind.opcode_count--;
17402218822Sdim      n--;
17403218822Sdim      data = (data << 8) | unwind.opcodes[unwind.opcode_count];
1740460484Sobrien    }
17405218822Sdim
17406218822Sdim  /* Finish off the last word.	*/
17407218822Sdim  if (n < 4)
1740860484Sobrien    {
17409218822Sdim      /* Pad with "finish" opcodes.  */
17410218822Sdim      while (n--)
17411218822Sdim	data = (data << 8) | 0xb0;
17412218822Sdim
17413218822Sdim      md_number_to_chars (ptr, data, 4);
1741460484Sobrien    }
1741560484Sobrien
17416218822Sdim  if (!have_data)
17417218822Sdim    {
17418218822Sdim      /* Add an empty descriptor if there is no user-specified data.   */
17419218822Sdim      ptr = frag_more (4);
17420218822Sdim      md_number_to_chars (ptr, 0, 4);
17421218822Sdim    }
17422218822Sdim
1742360484Sobrien  return 0;
1742460484Sobrien}
1742560484Sobrien
1742677298Sobrien
17427218822Sdim/* Initialize the DWARF-2 unwind information for this procedure.  */
17428218822Sdim
17429218822Sdimvoid
17430218822Sdimtc_arm_frame_initial_instructions (void)
17431218822Sdim{
17432218822Sdim  cfi_add_CFA_def_cfa (REG_SP, 0);
17433218822Sdim}
17434218822Sdim#endif /* OBJ_ELF */
17435218822Sdim
17436218822Sdim/* Convert REGNAME to a DWARF-2 register number.  */
17437218822Sdim
17438218822Sdimint
17439218822Sdimtc_arm_regname_to_dw2regnum (char *regname)
17440218822Sdim{
17441218822Sdim  int reg = arm_reg_parse (&regname, REG_TYPE_RN);
17442218822Sdim
17443218822Sdim  if (reg == FAIL)
17444218822Sdim    return -1;
17445218822Sdim
17446218822Sdim  return reg;
17447218822Sdim}
17448218822Sdim
17449218822Sdim#ifdef TE_PE
17450218822Sdimvoid
17451218822Sdimtc_pe_dwarf2_emit_offset (symbolS *symbol, unsigned int size)
17452218822Sdim{
17453218822Sdim  expressionS expr;
17454218822Sdim
17455218822Sdim  expr.X_op = O_secrel;
17456218822Sdim  expr.X_add_symbol = symbol;
17457218822Sdim  expr.X_add_number = 0;
17458218822Sdim  emit_expr (&expr, size);
17459218822Sdim}
17460218822Sdim#endif
17461218822Sdim
17462218822Sdim/* MD interface: Symbol and relocation handling.  */
17463218822Sdim
17464218822Sdim/* Return the address within the segment that a PC-relative fixup is
17465218822Sdim   relative to.  For ARM, PC-relative fixups applied to instructions
17466218822Sdim   are generally relative to the location of the fixup plus 8 bytes.
17467218822Sdim   Thumb branches are offset by 4, and Thumb loads relative to PC
17468218822Sdim   require special handling.  */
17469218822Sdim
1747060484Sobrienlong
17471218822Sdimmd_pcrel_from_section (fixS * fixP, segT seg)
1747260484Sobrien{
17473218822Sdim  offsetT base = fixP->fx_where + fixP->fx_frag->fr_address;
1747477298Sobrien
17475218822Sdim  /* If this is pc-relative and we are going to emit a relocation
17476218822Sdim     then we just want to put out any pipeline compensation that the linker
17477218822Sdim     will need.  Otherwise we want to use the calculated base.
17478218822Sdim     For WinCE we skip the bias for externals as well, since this
17479218822Sdim     is how the MS ARM-CE assembler behaves and we want to be compatible.  */
17480218822Sdim  if (fixP->fx_pcrel
17481218822Sdim      && ((fixP->fx_addsy && S_GET_SEGMENT (fixP->fx_addsy) != seg)
17482218822Sdim	  || (arm_force_relocation (fixP)
17483218822Sdim#ifdef TE_WINCE
17484218822Sdim	      && !S_IS_EXTERNAL (fixP->fx_addsy)
17485218822Sdim#endif
17486218822Sdim	      )))
17487218822Sdim    base = 0;
17488218822Sdim
17489218822Sdim  switch (fixP->fx_r_type)
1749060484Sobrien    {
17491218822Sdim      /* PC relative addressing on the Thumb is slightly odd as the
17492218822Sdim	 bottom two bits of the PC are forced to zero for the
17493218822Sdim	 calculation.  This happens *after* application of the
17494218822Sdim	 pipeline offset.  However, Thumb adrl already adjusts for
17495218822Sdim	 this, so we need not do it again.  */
17496218822Sdim    case BFD_RELOC_ARM_THUMB_ADD:
17497218822Sdim      return base & ~3;
1749860484Sobrien
17499218822Sdim    case BFD_RELOC_ARM_THUMB_OFFSET:
17500218822Sdim    case BFD_RELOC_ARM_T32_OFFSET_IMM:
17501218822Sdim    case BFD_RELOC_ARM_T32_ADD_PC12:
17502218822Sdim    case BFD_RELOC_ARM_T32_CP_OFF_IMM:
17503218822Sdim      return (base + 4) & ~3;
17504218822Sdim
17505218822Sdim      /* Thumb branches are simply offset by +4.  */
17506218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH7:
17507218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH9:
17508218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH12:
17509218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH20:
17510218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH23:
17511218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH25:
17512218822Sdim    case BFD_RELOC_THUMB_PCREL_BLX:
17513218822Sdim      return base + 4;
17514218822Sdim
17515218822Sdim      /* ARM mode branches are offset by +8.  However, the Windows CE
17516218822Sdim	 loader expects the relocation not to take this into account.  */
17517218822Sdim    case BFD_RELOC_ARM_PCREL_BRANCH:
17518218822Sdim    case BFD_RELOC_ARM_PCREL_CALL:
17519218822Sdim    case BFD_RELOC_ARM_PCREL_JUMP:
17520218822Sdim    case BFD_RELOC_ARM_PCREL_BLX:
17521218822Sdim    case BFD_RELOC_ARM_PLT32:
1752260484Sobrien#ifdef TE_WINCE
17523218822Sdim      /* When handling fixups immediately, because we have already
17524218822Sdim         discovered the value of a symbol, or the address of the frag involved
17525218822Sdim	 we must account for the offset by +8, as the OS loader will never see the reloc.
17526218822Sdim         see fixup_segment() in write.c
17527218822Sdim         The S_IS_EXTERNAL test handles the case of global symbols.
17528218822Sdim         Those need the calculated base, not just the pipe compensation the linker will need.  */
17529218822Sdim      if (fixP->fx_pcrel
17530218822Sdim	  && fixP->fx_addsy != NULL
17531218822Sdim	  && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
17532218822Sdim	  && (S_IS_EXTERNAL (fixP->fx_addsy) || !arm_force_relocation (fixP)))
17533218822Sdim	return base + 8;
17534218822Sdim      return base;
1753560484Sobrien#else
17536218822Sdim      return base + 8;
1753760484Sobrien#endif
1753860484Sobrien
17539218822Sdim      /* ARM mode loads relative to PC are also offset by +8.  Unlike
17540218822Sdim	 branches, the Windows CE loader *does* expect the relocation
17541218822Sdim	 to take this into account.  */
17542218822Sdim    case BFD_RELOC_ARM_OFFSET_IMM:
17543218822Sdim    case BFD_RELOC_ARM_OFFSET_IMM8:
17544218822Sdim    case BFD_RELOC_ARM_HWLITERAL:
17545218822Sdim    case BFD_RELOC_ARM_LITERAL:
17546218822Sdim    case BFD_RELOC_ARM_CP_OFF_IMM:
17547218822Sdim      return base + 8;
1754877298Sobrien
17549218822Sdim
17550218822Sdim      /* Other PC-relative relocations are un-offset.  */
17551218822Sdim    default:
17552218822Sdim      return base;
17553218822Sdim    }
1755460484Sobrien}
1755560484Sobrien
1755677298Sobrien/* Under ELF we need to default _GLOBAL_OFFSET_TABLE.
1755777298Sobrien   Otherwise we have no need to default values of symbols.  */
1755860484Sobrien
1755960484SobriensymbolS *
17560218822Sdimmd_undefined_symbol (char * name ATTRIBUTE_UNUSED)
1756160484Sobrien{
1756260484Sobrien#ifdef OBJ_ELF
1756360484Sobrien  if (name[0] == '_' && name[1] == 'G'
1756460484Sobrien      && streq (name, GLOBAL_OFFSET_TABLE_NAME))
1756560484Sobrien    {
1756660484Sobrien      if (!GOT_symbol)
1756760484Sobrien	{
1756860484Sobrien	  if (symbol_find (name))
1756960484Sobrien	    as_bad ("GOT already in the symbol table");
1757077298Sobrien
1757160484Sobrien	  GOT_symbol = symbol_new (name, undefined_section,
1757277298Sobrien				   (valueT) 0, & zero_address_frag);
1757360484Sobrien	}
1757477298Sobrien
1757560484Sobrien      return GOT_symbol;
1757660484Sobrien    }
1757760484Sobrien#endif
1757877298Sobrien
1757960484Sobrien  return 0;
1758060484Sobrien}
1758160484Sobrien
17582218822Sdim/* Subroutine of md_apply_fix.	 Check to see if an immediate can be
17583218822Sdim   computed as two separate immediate values, added together.  We
17584218822Sdim   already know that this value cannot be computed by just one ARM
17585218822Sdim   instruction.	 */
1758660484Sobrien
17587218822Sdimstatic unsigned int
17588218822Sdimvalidate_immediate_twopart (unsigned int   val,
17589218822Sdim			    unsigned int * highpart)
17590218822Sdim{
17591218822Sdim  unsigned int a;
17592218822Sdim  unsigned int i;
17593218822Sdim
17594218822Sdim  for (i = 0; i < 32; i += 2)
17595218822Sdim    if (((a = rotate_left (val, i)) & 0xff) != 0)
17596218822Sdim      {
17597218822Sdim	if (a & 0xff00)
17598218822Sdim	  {
17599218822Sdim	    if (a & ~ 0xffff)
17600218822Sdim	      continue;
17601218822Sdim	    * highpart = (a  >> 8) | ((i + 24) << 7);
17602218822Sdim	  }
17603218822Sdim	else if (a & 0xff0000)
17604218822Sdim	  {
17605218822Sdim	    if (a & 0xff000000)
17606218822Sdim	      continue;
17607218822Sdim	    * highpart = (a >> 16) | ((i + 16) << 7);
17608218822Sdim	  }
17609218822Sdim	else
17610218822Sdim	  {
17611218822Sdim	    assert (a & 0xff000000);
17612218822Sdim	    * highpart = (a >> 24) | ((i + 8) << 7);
17613218822Sdim	  }
17614218822Sdim
17615218822Sdim	return (a & 0xff) | (i << 7);
17616218822Sdim      }
17617218822Sdim
17618218822Sdim  return FAIL;
17619218822Sdim}
17620218822Sdim
1762160484Sobrienstatic int
17622218822Sdimvalidate_offset_imm (unsigned int val, int hwse)
1762360484Sobrien{
17624218822Sdim  if ((hwse && val > 255) || val > 4095)
17625218822Sdim    return FAIL;
17626218822Sdim  return val;
17627218822Sdim}
1762860484Sobrien
17629218822Sdim/* Subroutine of md_apply_fix.	 Do those data_ops which can take a
17630218822Sdim   negative immediate constant by altering the instruction.  A bit of
17631218822Sdim   a hack really.
17632218822Sdim	MOV <-> MVN
17633218822Sdim	AND <-> BIC
17634218822Sdim	ADC <-> SBC
17635218822Sdim	by inverting the second operand, and
17636218822Sdim	ADD <-> SUB
17637218822Sdim	CMP <-> CMN
17638218822Sdim	by negating the second operand.	 */
17639218822Sdim
17640218822Sdimstatic int
17641218822Sdimnegate_data_op (unsigned long * instruction,
17642218822Sdim		unsigned long	value)
17643218822Sdim{
17644218822Sdim  int op, new_inst;
17645218822Sdim  unsigned long negated, inverted;
17646218822Sdim
17647218822Sdim  negated = encode_arm_immediate (-value);
17648218822Sdim  inverted = encode_arm_immediate (~value);
17649218822Sdim
17650218822Sdim  op = (*instruction >> DATA_OP_SHIFT) & 0xf;
17651218822Sdim  switch (op)
17652218822Sdim    {
17653218822Sdim      /* First negates.	 */
17654218822Sdim    case OPCODE_SUB:		 /* ADD <-> SUB	 */
17655218822Sdim      new_inst = OPCODE_ADD;
17656218822Sdim      value = negated;
17657218822Sdim      break;
17658218822Sdim
17659218822Sdim    case OPCODE_ADD:
17660218822Sdim      new_inst = OPCODE_SUB;
17661218822Sdim      value = negated;
17662218822Sdim      break;
17663218822Sdim
17664218822Sdim    case OPCODE_CMP:		 /* CMP <-> CMN	 */
17665218822Sdim      new_inst = OPCODE_CMN;
17666218822Sdim      value = negated;
17667218822Sdim      break;
17668218822Sdim
17669218822Sdim    case OPCODE_CMN:
17670218822Sdim      new_inst = OPCODE_CMP;
17671218822Sdim      value = negated;
17672218822Sdim      break;
17673218822Sdim
17674218822Sdim      /* Now Inverted ops.  */
17675218822Sdim    case OPCODE_MOV:		 /* MOV <-> MVN	 */
17676218822Sdim      new_inst = OPCODE_MVN;
17677218822Sdim      value = inverted;
17678218822Sdim      break;
17679218822Sdim
17680218822Sdim    case OPCODE_MVN:
17681218822Sdim      new_inst = OPCODE_MOV;
17682218822Sdim      value = inverted;
17683218822Sdim      break;
17684218822Sdim
17685218822Sdim    case OPCODE_AND:		 /* AND <-> BIC	 */
17686218822Sdim      new_inst = OPCODE_BIC;
17687218822Sdim      value = inverted;
17688218822Sdim      break;
17689218822Sdim
17690218822Sdim    case OPCODE_BIC:
17691218822Sdim      new_inst = OPCODE_AND;
17692218822Sdim      value = inverted;
17693218822Sdim      break;
17694218822Sdim
17695218822Sdim    case OPCODE_ADC:		  /* ADC <-> SBC  */
17696218822Sdim      new_inst = OPCODE_SBC;
17697218822Sdim      value = inverted;
17698218822Sdim      break;
17699218822Sdim
17700218822Sdim    case OPCODE_SBC:
17701218822Sdim      new_inst = OPCODE_ADC;
17702218822Sdim      value = inverted;
17703218822Sdim      break;
17704218822Sdim
17705218822Sdim      /* We cannot do anything.	 */
17706218822Sdim    default:
17707218822Sdim      return FAIL;
17708218822Sdim    }
17709218822Sdim
17710218822Sdim  if (value == (unsigned) FAIL)
1771160484Sobrien    return FAIL;
1771260484Sobrien
17713218822Sdim  *instruction &= OPCODE_MASK;
17714218822Sdim  *instruction |= new_inst << DATA_OP_SHIFT;
17715218822Sdim  return value;
17716218822Sdim}
1771760484Sobrien
17718218822Sdim/* Like negate_data_op, but for Thumb-2.   */
1771977298Sobrien
17720218822Sdimstatic unsigned int
17721218822Sdimthumb32_negate_data_op (offsetT *instruction, unsigned int value)
17722218822Sdim{
17723218822Sdim  int op, new_inst;
17724218822Sdim  int rd;
17725218822Sdim  unsigned int negated, inverted;
17726218822Sdim
17727218822Sdim  negated = encode_thumb32_immediate (-value);
17728218822Sdim  inverted = encode_thumb32_immediate (~value);
17729218822Sdim
17730218822Sdim  rd = (*instruction >> 8) & 0xf;
17731218822Sdim  op = (*instruction >> T2_DATA_OP_SHIFT) & 0xf;
17732218822Sdim  switch (op)
1773360484Sobrien    {
17734218822Sdim      /* ADD <-> SUB.  Includes CMP <-> CMN.  */
17735218822Sdim    case T2_OPCODE_SUB:
17736218822Sdim      new_inst = T2_OPCODE_ADD;
17737218822Sdim      value = negated;
17738218822Sdim      break;
17739218822Sdim
17740218822Sdim    case T2_OPCODE_ADD:
17741218822Sdim      new_inst = T2_OPCODE_SUB;
17742218822Sdim      value = negated;
17743218822Sdim      break;
17744218822Sdim
17745218822Sdim      /* ORR <-> ORN.  Includes MOV <-> MVN.  */
17746218822Sdim    case T2_OPCODE_ORR:
17747218822Sdim      new_inst = T2_OPCODE_ORN;
17748218822Sdim      value = inverted;
17749218822Sdim      break;
17750218822Sdim
17751218822Sdim    case T2_OPCODE_ORN:
17752218822Sdim      new_inst = T2_OPCODE_ORR;
17753218822Sdim      value = inverted;
17754218822Sdim      break;
17755218822Sdim
17756218822Sdim      /* AND <-> BIC.  TST has no inverted equivalent.  */
17757218822Sdim    case T2_OPCODE_AND:
17758218822Sdim      new_inst = T2_OPCODE_BIC;
17759218822Sdim      if (rd == 15)
17760218822Sdim	value = FAIL;
17761218822Sdim      else
17762218822Sdim	value = inverted;
17763218822Sdim      break;
17764218822Sdim
17765218822Sdim    case T2_OPCODE_BIC:
17766218822Sdim      new_inst = T2_OPCODE_AND;
17767218822Sdim      value = inverted;
17768218822Sdim      break;
17769218822Sdim
17770218822Sdim      /* ADC <-> SBC  */
17771218822Sdim    case T2_OPCODE_ADC:
17772218822Sdim      new_inst = T2_OPCODE_SBC;
17773218822Sdim      value = inverted;
17774218822Sdim      break;
17775218822Sdim
17776218822Sdim    case T2_OPCODE_SBC:
17777218822Sdim      new_inst = T2_OPCODE_ADC;
17778218822Sdim      value = inverted;
17779218822Sdim      break;
17780218822Sdim
17781218822Sdim      /* We cannot do anything.	 */
17782218822Sdim    default:
17783218822Sdim      return FAIL;
1778460484Sobrien    }
1778560484Sobrien
17786218822Sdim  if (value == (unsigned int)FAIL)
17787218822Sdim    return FAIL;
17788218822Sdim
17789218822Sdim  *instruction &= T2_OPCODE_MASK;
17790218822Sdim  *instruction |= new_inst << T2_DATA_OP_SHIFT;
17791218822Sdim  return value;
1779260484Sobrien}
1779360484Sobrien
17794218822Sdim/* Read a 32-bit thumb instruction from buf.  */
17795218822Sdimstatic unsigned long
17796218822Sdimget_thumb32_insn (char * buf)
1779789857Sobrien{
17798218822Sdim  unsigned long insn;
17799218822Sdim  insn = md_chars_to_number (buf, THUMB_SIZE) << 16;
17800218822Sdim  insn |= md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
1780189857Sobrien
17802218822Sdim  return insn;
17803218822Sdim}
1780489857Sobrien
17805218822Sdim
17806218822Sdim/* We usually want to set the low bit on the address of thumb function
17807218822Sdim   symbols.  In particular .word foo - . should have the low bit set.
17808218822Sdim   Generic code tries to fold the difference of two symbols to
17809218822Sdim   a constant.  Prevent this and force a relocation when the first symbols
17810218822Sdim   is a thumb function.  */
17811218822Sdimint
17812218822Sdimarm_optimize_expr (expressionS *l, operatorT op, expressionS *r)
17813218822Sdim{
17814218822Sdim  if (op == O_subtract
17815218822Sdim      && l->X_op == O_symbol
17816218822Sdim      && r->X_op == O_symbol
17817218822Sdim      && THUMB_IS_FUNC (l->X_add_symbol))
17818218822Sdim    {
17819218822Sdim      l->X_op = O_subtract;
17820218822Sdim      l->X_op_symbol = r->X_add_symbol;
17821218822Sdim      l->X_add_number -= r->X_add_number;
17822218822Sdim      return 1;
17823218822Sdim    }
17824218822Sdim  /* Process as normal.  */
17825218822Sdim  return 0;
1782689857Sobrien}
1782789857Sobrien
1782889857Sobrienvoid
17829218822Sdimmd_apply_fix (fixS *	fixP,
17830218822Sdim	       valueT * valP,
17831218822Sdim	       segT	seg)
1783260484Sobrien{
17833218822Sdim  offsetT	 value = * valP;
17834218822Sdim  offsetT	 newval;
17835218822Sdim  unsigned int	 newimm;
17836218822Sdim  unsigned long	 temp;
17837218822Sdim  int		 sign;
17838218822Sdim  char *	 buf = fixP->fx_where + fixP->fx_frag->fr_literal;
1783960484Sobrien
17840218822Sdim  assert (fixP->fx_r_type <= BFD_RELOC_UNUSED);
1784160484Sobrien
1784260484Sobrien  /* Note whether this will delete the relocation.  */
17843218822Sdim
1784460484Sobrien  if (fixP->fx_addsy == 0 && !fixP->fx_pcrel)
1784560484Sobrien    fixP->fx_done = 1;
1784660484Sobrien
17847218822Sdim  /* On a 64-bit host, silently truncate 'value' to 32 bits for
17848218822Sdim     consistency with the behavior on 32-bit hosts.  Remember value
17849218822Sdim     for emit_reloc.  */
17850218822Sdim  value &= 0xffffffff;
17851218822Sdim  value ^= 0x80000000;
17852218822Sdim  value -= 0x80000000;
1785360484Sobrien
17854218822Sdim  *valP = value;
1785577298Sobrien  fixP->fx_addnumber = value;
1785660484Sobrien
17857218822Sdim  /* Same treatment for fixP->fx_offset.  */
17858218822Sdim  fixP->fx_offset &= 0xffffffff;
17859218822Sdim  fixP->fx_offset ^= 0x80000000;
17860218822Sdim  fixP->fx_offset -= 0x80000000;
17861218822Sdim
1786260484Sobrien  switch (fixP->fx_r_type)
1786360484Sobrien    {
17864218822Sdim    case BFD_RELOC_NONE:
17865218822Sdim      /* This will need to go in the object file.  */
17866218822Sdim      fixP->fx_done = 0;
17867218822Sdim      break;
17868218822Sdim
1786960484Sobrien    case BFD_RELOC_ARM_IMMEDIATE:
17870218822Sdim      /* We claim that this fixup has been processed here,
17871218822Sdim	 even if in fact we generate an error because we do
17872218822Sdim	 not have a reloc for it, so tc_gen_reloc will reject it.  */
17873218822Sdim      fixP->fx_done = 1;
17874218822Sdim
17875218822Sdim      if (fixP->fx_addsy
17876218822Sdim	  && ! S_IS_DEFINED (fixP->fx_addsy))
17877218822Sdim	{
17878218822Sdim	  as_bad_where (fixP->fx_file, fixP->fx_line,
17879218822Sdim			_("undefined symbol %s used as an immediate value"),
17880218822Sdim			S_GET_NAME (fixP->fx_addsy));
17881218822Sdim	  break;
17882218822Sdim	}
17883218822Sdim
17884218822Sdim      newimm = encode_arm_immediate (value);
1788560484Sobrien      temp = md_chars_to_number (buf, INSN_SIZE);
1788660484Sobrien
1788760484Sobrien      /* If the instruction will fail, see if we can fix things up by
1788860484Sobrien	 changing the opcode.  */
1788960484Sobrien      if (newimm == (unsigned int) FAIL
1789060484Sobrien	  && (newimm = negate_data_op (&temp, value)) == (unsigned int) FAIL)
1789160484Sobrien	{
1789260484Sobrien	  as_bad_where (fixP->fx_file, fixP->fx_line,
1789360484Sobrien			_("invalid constant (%lx) after fixup"),
1789460484Sobrien			(unsigned long) value);
1789560484Sobrien	  break;
1789660484Sobrien	}
1789760484Sobrien
1789860484Sobrien      newimm |= (temp & 0xfffff000);
1789960484Sobrien      md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
1790060484Sobrien      break;
1790160484Sobrien
1790260484Sobrien    case BFD_RELOC_ARM_ADRL_IMMEDIATE:
1790360484Sobrien      {
1790460484Sobrien	unsigned int highpart = 0;
1790577298Sobrien	unsigned int newinsn  = 0xe1a00000; /* nop.  */
17906130561Sobrien
17907218822Sdim	newimm = encode_arm_immediate (value);
1790860484Sobrien	temp = md_chars_to_number (buf, INSN_SIZE);
1790960484Sobrien
1791060484Sobrien	/* If the instruction will fail, see if we can fix things up by
17911218822Sdim	   changing the opcode.	 */
1791260484Sobrien	if (newimm == (unsigned int) FAIL
1791360484Sobrien	    && (newimm = negate_data_op (& temp, value)) == (unsigned int) FAIL)
1791460484Sobrien	  {
1791577298Sobrien	    /* No ?  OK - try using two ADD instructions to generate
17916218822Sdim	       the value.  */
1791760484Sobrien	    newimm = validate_immediate_twopart (value, & highpart);
1791860484Sobrien
1791977298Sobrien	    /* Yes - then make sure that the second instruction is
17920218822Sdim	       also an add.  */
1792160484Sobrien	    if (newimm != (unsigned int) FAIL)
1792260484Sobrien	      newinsn = temp;
1792360484Sobrien	    /* Still No ?  Try using a negated value.  */
1792468765Sobrien	    else if ((newimm = validate_immediate_twopart (- value, & highpart)) != (unsigned int) FAIL)
1792577298Sobrien	      temp = newinsn = (temp & OPCODE_MASK) | OPCODE_SUB << DATA_OP_SHIFT;
1792660484Sobrien	    /* Otherwise - give up.  */
1792760484Sobrien	    else
1792860484Sobrien	      {
1792960484Sobrien		as_bad_where (fixP->fx_file, fixP->fx_line,
1793089857Sobrien			      _("unable to compute ADRL instructions for PC offset of 0x%lx"),
17931130561Sobrien			      (long) value);
1793260484Sobrien		break;
1793360484Sobrien	      }
1793460484Sobrien
1793577298Sobrien	    /* Replace the first operand in the 2nd instruction (which
1793677298Sobrien	       is the PC) with the destination register.  We have
1793777298Sobrien	       already added in the PC in the first instruction and we
1793877298Sobrien	       do not want to do it again.  */
1793960484Sobrien	    newinsn &= ~ 0xf0000;
1794060484Sobrien	    newinsn |= ((newinsn & 0x0f000) << 4);
1794160484Sobrien	  }
1794260484Sobrien
1794360484Sobrien	newimm |= (temp & 0xfffff000);
1794460484Sobrien	md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
1794560484Sobrien
1794660484Sobrien	highpart |= (newinsn & 0xfffff000);
1794760484Sobrien	md_number_to_chars (buf + INSN_SIZE, (valueT) highpart, INSN_SIZE);
1794860484Sobrien      }
1794960484Sobrien      break;
1795060484Sobrien
1795160484Sobrien    case BFD_RELOC_ARM_OFFSET_IMM:
17952218822Sdim      if (!fixP->fx_done && seg->use_rela_p)
17953218822Sdim	value = 0;
17954218822Sdim
17955218822Sdim    case BFD_RELOC_ARM_LITERAL:
1795660484Sobrien      sign = value >= 0;
1795777298Sobrien
1795860484Sobrien      if (value < 0)
1795960484Sobrien	value = - value;
1796077298Sobrien
1796160484Sobrien      if (validate_offset_imm (value, 0) == FAIL)
1796277298Sobrien	{
17963218822Sdim	  if (fixP->fx_r_type == BFD_RELOC_ARM_LITERAL)
17964218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
17965218822Sdim			  _("invalid literal constant: pool needs to be closer"));
17966218822Sdim	  else
17967218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
17968218822Sdim			  _("bad immediate value for offset (%ld)"),
17969218822Sdim			  (long) value);
1797077298Sobrien	  break;
1797177298Sobrien	}
1797260484Sobrien
1797360484Sobrien      newval = md_chars_to_number (buf, INSN_SIZE);
1797460484Sobrien      newval &= 0xff7ff000;
1797560484Sobrien      newval |= value | (sign ? INDEX_UP : 0);
1797660484Sobrien      md_number_to_chars (buf, newval, INSN_SIZE);
1797760484Sobrien      break;
1797860484Sobrien
1797977298Sobrien    case BFD_RELOC_ARM_OFFSET_IMM8:
1798077298Sobrien    case BFD_RELOC_ARM_HWLITERAL:
1798160484Sobrien      sign = value >= 0;
1798277298Sobrien
1798360484Sobrien      if (value < 0)
1798460484Sobrien	value = - value;
1798560484Sobrien
1798660484Sobrien      if (validate_offset_imm (value, 1) == FAIL)
1798777298Sobrien	{
1798877298Sobrien	  if (fixP->fx_r_type == BFD_RELOC_ARM_HWLITERAL)
1798977298Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
1799077298Sobrien			  _("invalid literal constant: pool needs to be closer"));
1799177298Sobrien	  else
17992218822Sdim	    as_bad (_("bad immediate value for 8-bit offset (%ld)"),
1799360484Sobrien		    (long) value);
1799477298Sobrien	  break;
1799577298Sobrien	}
1799660484Sobrien
1799760484Sobrien      newval = md_chars_to_number (buf, INSN_SIZE);
1799860484Sobrien      newval &= 0xff7ff0f0;
1799960484Sobrien      newval |= ((value >> 4) << 8) | (value & 0xf) | (sign ? INDEX_UP : 0);
1800060484Sobrien      md_number_to_chars (buf, newval, INSN_SIZE);
1800160484Sobrien      break;
1800260484Sobrien
18003218822Sdim    case BFD_RELOC_ARM_T32_OFFSET_U8:
18004218822Sdim      if (value < 0 || value > 1020 || value % 4 != 0)
18005218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18006218822Sdim		      _("bad immediate value for offset (%ld)"), (long) value);
18007218822Sdim      value /= 4;
1800877298Sobrien
18009218822Sdim      newval = md_chars_to_number (buf+2, THUMB_SIZE);
18010218822Sdim      newval |= value;
18011218822Sdim      md_number_to_chars (buf+2, newval, THUMB_SIZE);
18012218822Sdim      break;
1801360484Sobrien
18014218822Sdim    case BFD_RELOC_ARM_T32_OFFSET_IMM:
18015218822Sdim      /* This is a complicated relocation used for all varieties of Thumb32
18016218822Sdim	 load/store instruction with immediate offset:
18017218822Sdim
18018218822Sdim	 1110 100P u1WL NNNN XXXX YYYY iiii iiii - +/-(U) pre/post(P) 8-bit,
18019218822Sdim	                                           *4, optional writeback(W)
18020218822Sdim						   (doubleword load/store)
18021218822Sdim
18022218822Sdim	 1111 100S uTTL 1111 XXXX iiii iiii iiii - +/-(U) 12-bit PC-rel
18023218822Sdim	 1111 100S 0TTL NNNN XXXX 1Pu1 iiii iiii - +/-(U) pre/post(P) 8-bit
18024218822Sdim	 1111 100S 0TTL NNNN XXXX 1110 iiii iiii - positive 8-bit (T instruction)
18025218822Sdim	 1111 100S 1TTL NNNN XXXX iiii iiii iiii - positive 12-bit
18026218822Sdim	 1111 100S 0TTL NNNN XXXX 1100 iiii iiii - negative 8-bit
18027218822Sdim
18028218822Sdim	 Uppercase letters indicate bits that are already encoded at
18029218822Sdim	 this point.  Lowercase letters are our problem.  For the
18030218822Sdim	 second block of instructions, the secondary opcode nybble
18031218822Sdim	 (bits 8..11) is present, and bit 23 is zero, even if this is
18032218822Sdim	 a PC-relative operation.  */
18033218822Sdim      newval = md_chars_to_number (buf, THUMB_SIZE);
18034218822Sdim      newval <<= 16;
18035218822Sdim      newval |= md_chars_to_number (buf+THUMB_SIZE, THUMB_SIZE);
18036218822Sdim
18037218822Sdim      if ((newval & 0xf0000000) == 0xe0000000)
1803860484Sobrien	{
18039218822Sdim	  /* Doubleword load/store: 8-bit offset, scaled by 4.  */
18040218822Sdim	  if (value >= 0)
18041218822Sdim	    newval |= (1 << 23);
18042218822Sdim	  else
18043218822Sdim	    value = -value;
18044218822Sdim	  if (value % 4 != 0)
18045218822Sdim	    {
18046218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18047218822Sdim			    _("offset not a multiple of 4"));
18048218822Sdim	      break;
18049218822Sdim	    }
18050218822Sdim	  value /= 4;
18051218822Sdim	  if (value > 0xff)
18052218822Sdim	    {
18053218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18054218822Sdim			    _("offset out of range"));
18055218822Sdim	      break;
18056218822Sdim	    }
18057218822Sdim	  newval &= ~0xff;
1805860484Sobrien	}
18059218822Sdim      else if ((newval & 0x000f0000) == 0x000f0000)
18060218822Sdim	{
18061218822Sdim	  /* PC-relative, 12-bit offset.  */
18062218822Sdim	  if (value >= 0)
18063218822Sdim	    newval |= (1 << 23);
18064218822Sdim	  else
18065218822Sdim	    value = -value;
18066218822Sdim	  if (value > 0xfff)
18067218822Sdim	    {
18068218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18069218822Sdim			    _("offset out of range"));
18070218822Sdim	      break;
18071218822Sdim	    }
18072218822Sdim	  newval &= ~0xfff;
18073218822Sdim	}
18074218822Sdim      else if ((newval & 0x00000100) == 0x00000100)
18075218822Sdim	{
18076218822Sdim	  /* Writeback: 8-bit, +/- offset.  */
18077218822Sdim	  if (value >= 0)
18078218822Sdim	    newval |= (1 << 9);
18079218822Sdim	  else
18080218822Sdim	    value = -value;
18081218822Sdim	  if (value > 0xff)
18082218822Sdim	    {
18083218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18084218822Sdim			    _("offset out of range"));
18085218822Sdim	      break;
18086218822Sdim	    }
18087218822Sdim	  newval &= ~0xff;
18088218822Sdim	}
18089218822Sdim      else if ((newval & 0x00000f00) == 0x00000e00)
18090218822Sdim	{
18091218822Sdim	  /* T-instruction: positive 8-bit offset.  */
18092218822Sdim	  if (value < 0 || value > 0xff)
18093218822Sdim	    {
18094218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18095218822Sdim			    _("offset out of range"));
18096218822Sdim	      break;
18097218822Sdim	    }
18098218822Sdim	  newval &= ~0xff;
18099218822Sdim	  newval |= value;
18100218822Sdim	}
18101218822Sdim      else
18102218822Sdim	{
18103218822Sdim	  /* Positive 12-bit or negative 8-bit offset.  */
18104218822Sdim	  int limit;
18105218822Sdim	  if (value >= 0)
18106218822Sdim	    {
18107218822Sdim	      newval |= (1 << 23);
18108218822Sdim	      limit = 0xfff;
18109218822Sdim	    }
18110218822Sdim	  else
18111218822Sdim	    {
18112218822Sdim	      value = -value;
18113218822Sdim	      limit = 0xff;
18114218822Sdim	    }
18115218822Sdim	  if (value > limit)
18116218822Sdim	    {
18117218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18118218822Sdim			    _("offset out of range"));
18119218822Sdim	      break;
18120218822Sdim	    }
18121218822Sdim	  newval &= ~limit;
18122218822Sdim	}
1812360484Sobrien
18124218822Sdim      newval |= value;
18125218822Sdim      md_number_to_chars (buf, (newval >> 16) & 0xffff, THUMB_SIZE);
18126218822Sdim      md_number_to_chars (buf + THUMB_SIZE, newval & 0xffff, THUMB_SIZE);
1812760484Sobrien      break;
1812860484Sobrien
1812960484Sobrien    case BFD_RELOC_ARM_SHIFT_IMM:
1813060484Sobrien      newval = md_chars_to_number (buf, INSN_SIZE);
1813160484Sobrien      if (((unsigned long) value) > 32
1813277298Sobrien	  || (value == 32
1813360484Sobrien	      && (((newval & 0x60) == 0) || (newval & 0x60) == 0x60)))
1813460484Sobrien	{
1813560484Sobrien	  as_bad_where (fixP->fx_file, fixP->fx_line,
1813660484Sobrien			_("shift expression is too large"));
1813760484Sobrien	  break;
1813860484Sobrien	}
1813960484Sobrien
1814060484Sobrien      if (value == 0)
18141218822Sdim	/* Shifts of zero must be done as lsl.	*/
1814277298Sobrien	newval &= ~0x60;
1814360484Sobrien      else if (value == 32)
1814460484Sobrien	value = 0;
1814560484Sobrien      newval &= 0xfffff07f;
1814660484Sobrien      newval |= (value & 0x1f) << 7;
1814777298Sobrien      md_number_to_chars (buf, newval, INSN_SIZE);
1814860484Sobrien      break;
1814960484Sobrien
18150218822Sdim    case BFD_RELOC_ARM_T32_IMMEDIATE:
18151218822Sdim    case BFD_RELOC_ARM_T32_ADD_IMM:
18152218822Sdim    case BFD_RELOC_ARM_T32_IMM12:
18153218822Sdim    case BFD_RELOC_ARM_T32_ADD_PC12:
18154218822Sdim      /* We claim that this fixup has been processed here,
18155218822Sdim	 even if in fact we generate an error because we do
18156218822Sdim	 not have a reloc for it, so tc_gen_reloc will reject it.  */
18157218822Sdim      fixP->fx_done = 1;
18158218822Sdim
18159218822Sdim      if (fixP->fx_addsy
18160218822Sdim	  && ! S_IS_DEFINED (fixP->fx_addsy))
18161218822Sdim	{
18162218822Sdim	  as_bad_where (fixP->fx_file, fixP->fx_line,
18163218822Sdim			_("undefined symbol %s used as an immediate value"),
18164218822Sdim			S_GET_NAME (fixP->fx_addsy));
18165218822Sdim	  break;
18166218822Sdim	}
18167218822Sdim
18168218822Sdim      newval = md_chars_to_number (buf, THUMB_SIZE);
18169218822Sdim      newval <<= 16;
18170218822Sdim      newval |= md_chars_to_number (buf+2, THUMB_SIZE);
18171218822Sdim
18172218822Sdim      newimm = FAIL;
18173218822Sdim      if (fixP->fx_r_type == BFD_RELOC_ARM_T32_IMMEDIATE
18174218822Sdim	  || fixP->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM)
18175218822Sdim	{
18176218822Sdim	  newimm = encode_thumb32_immediate (value);
18177218822Sdim	  if (newimm == (unsigned int) FAIL)
18178218822Sdim	    newimm = thumb32_negate_data_op (&newval, value);
18179218822Sdim	}
18180218822Sdim      if (fixP->fx_r_type != BFD_RELOC_ARM_T32_IMMEDIATE
18181218822Sdim	  && newimm == (unsigned int) FAIL)
18182218822Sdim	{
18183218822Sdim	  /* Turn add/sum into addw/subw.  */
18184218822Sdim	  if (fixP->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM)
18185218822Sdim	    newval = (newval & 0xfeffffff) | 0x02000000;
18186218822Sdim
18187218822Sdim	  /* 12 bit immediate for addw/subw.  */
18188218822Sdim	  if (value < 0)
18189218822Sdim	    {
18190218822Sdim	      value = -value;
18191218822Sdim	      newval ^= 0x00a00000;
18192218822Sdim	    }
18193218822Sdim	  if (value > 0xfff)
18194218822Sdim	    newimm = (unsigned int) FAIL;
18195218822Sdim	  else
18196218822Sdim	    newimm = value;
18197218822Sdim	}
18198218822Sdim
18199218822Sdim      if (newimm == (unsigned int)FAIL)
18200218822Sdim	{
18201218822Sdim	  as_bad_where (fixP->fx_file, fixP->fx_line,
18202218822Sdim			_("invalid constant (%lx) after fixup"),
18203218822Sdim			(unsigned long) value);
18204218822Sdim	  break;
18205218822Sdim	}
18206218822Sdim
18207218822Sdim      newval |= (newimm & 0x800) << 15;
18208218822Sdim      newval |= (newimm & 0x700) << 4;
18209218822Sdim      newval |= (newimm & 0x0ff);
18210218822Sdim
18211218822Sdim      md_number_to_chars (buf,   (valueT) ((newval >> 16) & 0xffff), THUMB_SIZE);
18212218822Sdim      md_number_to_chars (buf+2, (valueT) (newval & 0xffff), THUMB_SIZE);
18213218822Sdim      break;
18214218822Sdim
18215218822Sdim    case BFD_RELOC_ARM_SMC:
18216218822Sdim      if (((unsigned long) value) > 0xffff)
18217218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18218218822Sdim		      _("invalid smc expression"));
18219218822Sdim      newval = md_chars_to_number (buf, INSN_SIZE);
18220218822Sdim      newval |= (value & 0xf) | ((value & 0xfff0) << 4);
18221218822Sdim      md_number_to_chars (buf, newval, INSN_SIZE);
18222218822Sdim      break;
18223218822Sdim
1822460484Sobrien    case BFD_RELOC_ARM_SWI:
18225218822Sdim      if (fixP->tc_fix_data != 0)
1822660484Sobrien	{
1822760484Sobrien	  if (((unsigned long) value) > 0xff)
1822860484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
1822989857Sobrien			  _("invalid swi expression"));
18230218822Sdim	  newval = md_chars_to_number (buf, THUMB_SIZE);
1823160484Sobrien	  newval |= value;
1823260484Sobrien	  md_number_to_chars (buf, newval, THUMB_SIZE);
1823360484Sobrien	}
1823460484Sobrien      else
1823560484Sobrien	{
1823660484Sobrien	  if (((unsigned long) value) > 0x00ffffff)
1823777298Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
1823889857Sobrien			  _("invalid swi expression"));
18239218822Sdim	  newval = md_chars_to_number (buf, INSN_SIZE);
1824060484Sobrien	  newval |= value;
1824177298Sobrien	  md_number_to_chars (buf, newval, INSN_SIZE);
1824260484Sobrien	}
1824360484Sobrien      break;
1824460484Sobrien
1824560484Sobrien    case BFD_RELOC_ARM_MULTI:
1824660484Sobrien      if (((unsigned long) value) > 0xffff)
1824760484Sobrien	as_bad_where (fixP->fx_file, fixP->fx_line,
1824889857Sobrien		      _("invalid expression in load/store multiple"));
1824960484Sobrien      newval = value | md_chars_to_number (buf, INSN_SIZE);
1825060484Sobrien      md_number_to_chars (buf, newval, INSN_SIZE);
1825160484Sobrien      break;
1825260484Sobrien
18253218822Sdim#ifdef OBJ_ELF
18254218822Sdim    case BFD_RELOC_ARM_PCREL_CALL:
1825560484Sobrien      newval = md_chars_to_number (buf, INSN_SIZE);
18256218822Sdim      if ((newval & 0xf0000000) == 0xf0000000)
18257218822Sdim	temp = 1;
18258218822Sdim      else
18259218822Sdim	temp = 3;
18260218822Sdim      goto arm_branch_common;
1826160484Sobrien
18262218822Sdim    case BFD_RELOC_ARM_PCREL_JUMP:
18263218822Sdim    case BFD_RELOC_ARM_PLT32:
1826460484Sobrien#endif
18265218822Sdim    case BFD_RELOC_ARM_PCREL_BRANCH:
18266218822Sdim      temp = 3;
18267218822Sdim      goto arm_branch_common;
1826860484Sobrien
18269218822Sdim    case BFD_RELOC_ARM_PCREL_BLX:
18270218822Sdim      temp = 1;
18271218822Sdim    arm_branch_common:
1827260484Sobrien      /* We are going to store value (shifted right by two) in the
18273218822Sdim	 instruction, in a 24 bit, signed field.  Bits 26 through 32 either
18274218822Sdim	 all clear or all set and bit 0 must be clear.  For B/BL bit 1 must
18275218822Sdim	 also be be clear.  */
18276218822Sdim      if (value & temp)
18277218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18278218822Sdim		      _("misaligned branch destination"));
18279218822Sdim      if ((value & (offsetT)0xfe000000) != (offsetT)0
18280218822Sdim	  && (value & (offsetT)0xfe000000) != (offsetT)0xfe000000)
18281218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18282218822Sdim		      _("branch out of range"));
18283218822Sdim
18284218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
1828560484Sobrien	{
18286218822Sdim	  newval = md_chars_to_number (buf, INSN_SIZE);
18287218822Sdim	  newval |= (value >> 2) & 0x00ffffff;
18288218822Sdim	  /* Set the H bit on BLX instructions.  */
18289218822Sdim	  if (temp == 1)
1829060484Sobrien	    {
18291218822Sdim	      if (value & 2)
18292218822Sdim		newval |= 0x01000000;
18293218822Sdim	      else
18294218822Sdim		newval &= ~0x01000000;
1829560484Sobrien	    }
18296218822Sdim	  md_number_to_chars (buf, newval, INSN_SIZE);
18297218822Sdim	}
18298218822Sdim      break;
1829977298Sobrien
18300218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH7: /* CBZ */
18301218822Sdim      /* CBZ can only branch forward.  */
18302218822Sdim
18303218822Sdim      /* Attempts to use CBZ to branch to the next instruction
18304218822Sdim         (which, strictly speaking, are prohibited) will be turned into
18305218822Sdim         no-ops.
18306218822Sdim
18307218822Sdim	 FIXME: It may be better to remove the instruction completely and
18308218822Sdim	 perform relaxation.  */
18309218822Sdim      if (value == -2)
18310218822Sdim	{
18311218822Sdim	  newval = md_chars_to_number (buf, THUMB_SIZE);
18312218822Sdim	  newval = 0xbf00; /* NOP encoding T1 */
18313218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18314218822Sdim	}
18315218822Sdim      else
18316218822Sdim	{
18317218822Sdim	  if (value & ~0x7e)
1831860484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18319218822Sdim		          _("branch out of range"));
18320218822Sdim
18321218822Sdim          if (fixP->fx_done || !seg->use_rela_p)
18322218822Sdim	    {
18323218822Sdim	      newval = md_chars_to_number (buf, THUMB_SIZE);
18324218822Sdim	      newval |= ((value & 0x3e) << 2) | ((value & 0x40) << 3);
18325218822Sdim	      md_number_to_chars (buf, newval, THUMB_SIZE);
18326218822Sdim	    }
1832760484Sobrien	}
18328218822Sdim      break;
1832960484Sobrien
18330218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH9: /* Conditional branch.	*/
18331218822Sdim      if ((value & ~0xff) && ((value & ~0xff) != ~0xff))
1833260484Sobrien	as_bad_where (fixP->fx_file, fixP->fx_line,
18333218822Sdim		      _("branch out of range"));
1833477298Sobrien
18335218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18336218822Sdim	{
18337218822Sdim	  newval = md_chars_to_number (buf, THUMB_SIZE);
18338218822Sdim	  newval |= (value & 0x1ff) >> 1;
18339218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18340218822Sdim	}
1834160484Sobrien      break;
1834260484Sobrien
18343218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH12: /* Unconditional branch.  */
18344218822Sdim      if ((value & ~0x7ff) && ((value & ~0x7ff) != ~0x7ff))
18345218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18346218822Sdim		      _("branch out of range"));
1834760484Sobrien
18348218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18349218822Sdim	{
18350218822Sdim	  newval = md_chars_to_number (buf, THUMB_SIZE);
18351218822Sdim	  newval |= (value & 0xfff) >> 1;
18352218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18353218822Sdim	}
1835477298Sobrien      break;
1835577298Sobrien
18356218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH20:
18357218822Sdim      if ((value & ~0x1fffff) && ((value & ~0x1fffff) != ~0x1fffff))
18358218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18359218822Sdim		      _("conditional branch out of range"));
1836060484Sobrien
18361218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18362218822Sdim	{
18363218822Sdim	  offsetT newval2;
18364218822Sdim	  addressT S, J1, J2, lo, hi;
1836560484Sobrien
18366218822Sdim	  S  = (value & 0x00100000) >> 20;
18367218822Sdim	  J2 = (value & 0x00080000) >> 19;
18368218822Sdim	  J1 = (value & 0x00040000) >> 18;
18369218822Sdim	  hi = (value & 0x0003f000) >> 12;
18370218822Sdim	  lo = (value & 0x00000ffe) >> 1;
1837160484Sobrien
18372218822Sdim	  newval   = md_chars_to_number (buf, THUMB_SIZE);
18373218822Sdim	  newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
18374218822Sdim	  newval  |= (S << 10) | hi;
18375218822Sdim	  newval2 |= (J1 << 13) | (J2 << 11) | lo;
18376218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18377218822Sdim	  md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
18378218822Sdim	}
1837960484Sobrien      break;
1838060484Sobrien
1838177298Sobrien    case BFD_RELOC_THUMB_PCREL_BLX:
1838260484Sobrien    case BFD_RELOC_THUMB_PCREL_BRANCH23:
18383218822Sdim      if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff))
18384218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18385218822Sdim		      _("branch out of range"));
1838660484Sobrien
18387218822Sdim      if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
18388218822Sdim	/* For a BLX instruction, make sure that the relocation is rounded up
18389218822Sdim	   to a word boundary.  This follows the semantics of the instruction
18390218822Sdim	   which specifies that bit 1 of the target address will come from bit
18391218822Sdim	   1 of the base address.  */
18392218822Sdim	value = (value + 1) & ~ 1;
18393104834Sobrien
18394218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18395218822Sdim	{
18396218822Sdim	  offsetT newval2;
1839760484Sobrien
18398218822Sdim	  newval   = md_chars_to_number (buf, THUMB_SIZE);
18399218822Sdim	  newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
18400218822Sdim	  newval  |= (value & 0x7fffff) >> 12;
18401218822Sdim	  newval2 |= (value & 0xfff) >> 1;
18402218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18403218822Sdim	  md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
18404218822Sdim	}
1840560484Sobrien      break;
1840660484Sobrien
18407218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH25:
18408218822Sdim      if ((value & ~0x1ffffff) && ((value & ~0x1ffffff) != ~0x1ffffff))
18409218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18410218822Sdim		      _("branch out of range"));
18411218822Sdim
18412218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
1841377298Sobrien	{
18414218822Sdim	  offsetT newval2;
18415218822Sdim	  addressT S, I1, I2, lo, hi;
18416218822Sdim
18417218822Sdim	  S  = (value & 0x01000000) >> 24;
18418218822Sdim	  I1 = (value & 0x00800000) >> 23;
18419218822Sdim	  I2 = (value & 0x00400000) >> 22;
18420218822Sdim	  hi = (value & 0x003ff000) >> 12;
18421218822Sdim	  lo = (value & 0x00000ffe) >> 1;
18422218822Sdim
18423218822Sdim	  I1 = !(I1 ^ S);
18424218822Sdim	  I2 = !(I2 ^ S);
18425218822Sdim
18426218822Sdim	  newval   = md_chars_to_number (buf, THUMB_SIZE);
18427218822Sdim	  newval2  = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
18428218822Sdim	  newval  |= (S << 10) | hi;
18429218822Sdim	  newval2 |= (I1 << 13) | (I2 << 11) | lo;
18430218822Sdim	  md_number_to_chars (buf, newval, THUMB_SIZE);
18431218822Sdim	  md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
1843277298Sobrien	}
1843360484Sobrien      break;
1843460484Sobrien
18435218822Sdim    case BFD_RELOC_8:
18436218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18437218822Sdim	md_number_to_chars (buf, value, 1);
18438218822Sdim      break;
18439218822Sdim
1844060484Sobrien    case BFD_RELOC_16:
18441218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
1844260484Sobrien	md_number_to_chars (buf, value, 2);
1844360484Sobrien      break;
1844460484Sobrien
1844560484Sobrien#ifdef OBJ_ELF
18446218822Sdim    case BFD_RELOC_ARM_TLS_GD32:
18447218822Sdim    case BFD_RELOC_ARM_TLS_LE32:
18448218822Sdim    case BFD_RELOC_ARM_TLS_IE32:
18449218822Sdim    case BFD_RELOC_ARM_TLS_LDM32:
18450218822Sdim    case BFD_RELOC_ARM_TLS_LDO32:
18451218822Sdim      S_SET_THREAD_LOCAL (fixP->fx_addsy);
18452218822Sdim      /* fall through */
18453218822Sdim
1845460484Sobrien    case BFD_RELOC_ARM_GOT32:
1845560484Sobrien    case BFD_RELOC_ARM_GOTOFF:
18456218822Sdim    case BFD_RELOC_ARM_TARGET2:
18457218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18458218822Sdim	md_number_to_chars (buf, 0, 4);
1845977298Sobrien      break;
1846060484Sobrien#endif
1846160484Sobrien
1846260484Sobrien    case BFD_RELOC_RVA:
1846360484Sobrien    case BFD_RELOC_32:
18464218822Sdim    case BFD_RELOC_ARM_TARGET1:
18465218822Sdim    case BFD_RELOC_ARM_ROSEGREL32:
18466218822Sdim    case BFD_RELOC_ARM_SBREL32:
18467218822Sdim    case BFD_RELOC_32_PCREL:
18468218822Sdim#ifdef TE_PE
18469218822Sdim    case BFD_RELOC_32_SECREL:
18470218822Sdim#endif
18471218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18472218822Sdim#ifdef TE_WINCE
18473218822Sdim	/* For WinCE we only do this for pcrel fixups.  */
18474218822Sdim	if (fixP->fx_done || fixP->fx_pcrel)
18475218822Sdim#endif
1847677298Sobrien	  md_number_to_chars (buf, value, 4);
1847760484Sobrien      break;
1847860484Sobrien
1847960484Sobrien#ifdef OBJ_ELF
18480218822Sdim    case BFD_RELOC_ARM_PREL31:
18481218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18482218822Sdim	{
18483218822Sdim	  newval = md_chars_to_number (buf, 4) & 0x80000000;
18484218822Sdim	  if ((value ^ (value >> 1)) & 0x40000000)
18485218822Sdim	    {
18486218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18487218822Sdim			    _("rel31 relocation overflow"));
18488218822Sdim	    }
18489218822Sdim	  newval |= value & 0x7fffffff;
18490218822Sdim	  md_number_to_chars (buf, newval, 4);
18491218822Sdim	}
1849260484Sobrien      break;
1849360484Sobrien#endif
1849460484Sobrien
1849560484Sobrien    case BFD_RELOC_ARM_CP_OFF_IMM:
18496218822Sdim    case BFD_RELOC_ARM_T32_CP_OFF_IMM:
1849760484Sobrien      if (value < -1023 || value > 1023 || (value & 3))
1849860484Sobrien	as_bad_where (fixP->fx_file, fixP->fx_line,
18499218822Sdim		      _("co-processor offset out of range"));
18500218822Sdim    cp_off_common:
18501218822Sdim      sign = value >= 0;
1850260484Sobrien      if (value < 0)
1850360484Sobrien	value = -value;
18504218822Sdim      if (fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM
18505218822Sdim	  || fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM_S2)
18506218822Sdim	newval = md_chars_to_number (buf, INSN_SIZE);
18507218822Sdim      else
18508218822Sdim	newval = get_thumb32_insn (buf);
18509218822Sdim      newval &= 0xff7fff00;
1851077298Sobrien      newval |= (value >> 2) | (sign ? INDEX_UP : 0);
18511218822Sdim      if (fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM
18512218822Sdim	  || fixP->fx_r_type == BFD_RELOC_ARM_CP_OFF_IMM_S2)
18513218822Sdim	md_number_to_chars (buf, newval, INSN_SIZE);
18514218822Sdim      else
18515218822Sdim	put_thumb32_insn (buf, newval);
1851660484Sobrien      break;
1851760484Sobrien
18518130561Sobrien    case BFD_RELOC_ARM_CP_OFF_IMM_S2:
18519218822Sdim    case BFD_RELOC_ARM_T32_CP_OFF_IMM_S2:
18520130561Sobrien      if (value < -255 || value > 255)
18521218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18522218822Sdim		      _("co-processor offset out of range"));
18523218822Sdim      value *= 4;
18524218822Sdim      goto cp_off_common;
18525130561Sobrien
1852660484Sobrien    case BFD_RELOC_ARM_THUMB_OFFSET:
1852760484Sobrien      newval = md_chars_to_number (buf, THUMB_SIZE);
1852877298Sobrien      /* Exactly what ranges, and where the offset is inserted depends
1852977298Sobrien	 on the type of instruction, we can establish this from the
1853077298Sobrien	 top 4 bits.  */
1853160484Sobrien      switch (newval >> 12)
1853260484Sobrien	{
1853377298Sobrien	case 4: /* PC load.  */
1853460484Sobrien	  /* Thumb PC loads are somewhat odd, bit 1 of the PC is
18535218822Sdim	     forced to zero for these loads; md_pcrel_from has already
18536218822Sdim	     compensated for this.  */
18537218822Sdim	  if (value & 3)
1853860484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18539218822Sdim			  _("invalid offset, target not word aligned (0x%08lX)"),
18540218822Sdim			  (((unsigned long) fixP->fx_frag->fr_address
18541218822Sdim			    + (unsigned long) fixP->fx_where) & ~3)
18542218822Sdim			  + (unsigned long) value);
1854360484Sobrien
18544218822Sdim	  if (value & ~0x3fc)
1854560484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18546130561Sobrien			  _("invalid offset, value too big (0x%08lX)"),
18547130561Sobrien			  (long) value);
1854860484Sobrien
18549218822Sdim	  newval |= value >> 2;
1855060484Sobrien	  break;
1855160484Sobrien
1855277298Sobrien	case 9: /* SP load/store.  */
1855360484Sobrien	  if (value & ~0x3fc)
1855460484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18555130561Sobrien			  _("invalid offset, value too big (0x%08lX)"),
18556130561Sobrien			  (long) value);
1855760484Sobrien	  newval |= value >> 2;
1855860484Sobrien	  break;
1855960484Sobrien
1856077298Sobrien	case 6: /* Word load/store.  */
1856160484Sobrien	  if (value & ~0x7c)
1856260484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18563130561Sobrien			  _("invalid offset, value too big (0x%08lX)"),
18564130561Sobrien			  (long) value);
1856577298Sobrien	  newval |= value << 4; /* 6 - 2.  */
1856660484Sobrien	  break;
1856760484Sobrien
1856877298Sobrien	case 7: /* Byte load/store.  */
1856960484Sobrien	  if (value & ~0x1f)
1857060484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18571130561Sobrien			  _("invalid offset, value too big (0x%08lX)"),
18572130561Sobrien			  (long) value);
1857360484Sobrien	  newval |= value << 6;
1857460484Sobrien	  break;
1857560484Sobrien
18576218822Sdim	case 8: /* Halfword load/store.	 */
1857760484Sobrien	  if (value & ~0x3e)
1857860484Sobrien	    as_bad_where (fixP->fx_file, fixP->fx_line,
18579130561Sobrien			  _("invalid offset, value too big (0x%08lX)"),
18580130561Sobrien			  (long) value);
1858177298Sobrien	  newval |= value << 5; /* 6 - 1.  */
1858260484Sobrien	  break;
1858360484Sobrien
1858460484Sobrien	default:
1858560484Sobrien	  as_bad_where (fixP->fx_file, fixP->fx_line,
1858660484Sobrien			"Unable to process relocation for thumb opcode: %lx",
1858760484Sobrien			(unsigned long) newval);
1858860484Sobrien	  break;
1858960484Sobrien	}
1859060484Sobrien      md_number_to_chars (buf, newval, THUMB_SIZE);
1859160484Sobrien      break;
1859260484Sobrien
1859360484Sobrien    case BFD_RELOC_ARM_THUMB_ADD:
1859460484Sobrien      /* This is a complicated relocation, since we use it for all of
18595218822Sdim	 the following immediate relocations:
1859660484Sobrien
1859777298Sobrien	    3bit ADD/SUB
1859877298Sobrien	    8bit ADD/SUB
1859977298Sobrien	    9bit ADD/SUB SP word-aligned
1860077298Sobrien	   10bit ADD PC/SP word-aligned
1860177298Sobrien
18602218822Sdim	 The type of instruction being processed is encoded in the
18603218822Sdim	 instruction field:
1860477298Sobrien
1860577298Sobrien	   0x8000  SUB
1860677298Sobrien	   0x00F0  Rd
1860777298Sobrien	   0x000F  Rs
1860860484Sobrien      */
1860960484Sobrien      newval = md_chars_to_number (buf, THUMB_SIZE);
1861060484Sobrien      {
1861177298Sobrien	int rd = (newval >> 4) & 0xf;
1861277298Sobrien	int rs = newval & 0xf;
18613218822Sdim	int subtract = !!(newval & 0x8000);
1861460484Sobrien
18615218822Sdim	/* Check for HI regs, only very restricted cases allowed:
18616218822Sdim	   Adjusting SP, and using PC or SP to get an address.	*/
18617218822Sdim	if ((rd > 7 && (rd != REG_SP || rs != REG_SP))
18618218822Sdim	    || (rs > 7 && rs != REG_SP && rs != REG_PC))
18619218822Sdim	  as_bad_where (fixP->fx_file, fixP->fx_line,
18620218822Sdim			_("invalid Hi register with immediate"));
18621218822Sdim
18622218822Sdim	/* If value is negative, choose the opposite instruction.  */
18623218822Sdim	if (value < 0)
18624218822Sdim	  {
18625218822Sdim	    value = -value;
18626218822Sdim	    subtract = !subtract;
18627218822Sdim	    if (value < 0)
18628218822Sdim	      as_bad_where (fixP->fx_file, fixP->fx_line,
18629218822Sdim			    _("immediate value out of range"));
18630218822Sdim	  }
18631218822Sdim
1863277298Sobrien	if (rd == REG_SP)
1863377298Sobrien	  {
1863477298Sobrien	    if (value & ~0x1fc)
1863577298Sobrien	      as_bad_where (fixP->fx_file, fixP->fx_line,
1863689857Sobrien			    _("invalid immediate for stack address calculation"));
1863777298Sobrien	    newval = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
1863877298Sobrien	    newval |= value >> 2;
1863977298Sobrien	  }
1864077298Sobrien	else if (rs == REG_PC || rs == REG_SP)
1864177298Sobrien	  {
18642218822Sdim	    if (subtract || value & ~0x3fc)
1864377298Sobrien	      as_bad_where (fixP->fx_file, fixP->fx_line,
1864489857Sobrien			    _("invalid immediate for address calculation (value = 0x%08lX)"),
1864560484Sobrien			    (unsigned long) value);
1864677298Sobrien	    newval = (rs == REG_PC ? T_OPCODE_ADD_PC : T_OPCODE_ADD_SP);
1864777298Sobrien	    newval |= rd << 8;
1864877298Sobrien	    newval |= value >> 2;
1864977298Sobrien	  }
1865077298Sobrien	else if (rs == rd)
1865177298Sobrien	  {
1865277298Sobrien	    if (value & ~0xff)
1865377298Sobrien	      as_bad_where (fixP->fx_file, fixP->fx_line,
18654218822Sdim			    _("immediate value out of range"));
1865577298Sobrien	    newval = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8;
1865677298Sobrien	    newval |= (rd << 8) | value;
1865777298Sobrien	  }
1865877298Sobrien	else
1865977298Sobrien	  {
1866077298Sobrien	    if (value & ~0x7)
1866177298Sobrien	      as_bad_where (fixP->fx_file, fixP->fx_line,
18662218822Sdim			    _("immediate value out of range"));
1866377298Sobrien	    newval = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
1866477298Sobrien	    newval |= rd | (rs << 3) | (value << 6);
1866577298Sobrien	  }
1866660484Sobrien      }
1866777298Sobrien      md_number_to_chars (buf, newval, THUMB_SIZE);
1866860484Sobrien      break;
1866960484Sobrien
1867060484Sobrien    case BFD_RELOC_ARM_THUMB_IMM:
1867160484Sobrien      newval = md_chars_to_number (buf, THUMB_SIZE);
18672218822Sdim      if (value < 0 || value > 255)
18673218822Sdim	as_bad_where (fixP->fx_file, fixP->fx_line,
18674218822Sdim		      _("invalid immediate: %ld is too large"),
18675218822Sdim		      (long) value);
18676218822Sdim      newval |= value;
1867777298Sobrien      md_number_to_chars (buf, newval, THUMB_SIZE);
1867860484Sobrien      break;
1867960484Sobrien
1868060484Sobrien    case BFD_RELOC_ARM_THUMB_SHIFT:
18681218822Sdim      /* 5bit shift value (0..32).  LSL cannot take 32.	 */
18682218822Sdim      newval = md_chars_to_number (buf, THUMB_SIZE) & 0xf83f;
18683218822Sdim      temp = newval & 0xf800;
18684218822Sdim      if (value < 0 || value > 32 || (value == 32 && temp == T_OPCODE_LSL_I))
1868560484Sobrien	as_bad_where (fixP->fx_file, fixP->fx_line,
18686218822Sdim		      _("invalid shift value: %ld"), (long) value);
18687218822Sdim      /* Shifts of zero must be encoded as LSL.	 */
18688218822Sdim      if (value == 0)
18689218822Sdim	newval = (newval & 0x003f) | T_OPCODE_LSL_I;
18690218822Sdim      /* Shifts of 32 are encoded as zero.  */
18691218822Sdim      else if (value == 32)
18692218822Sdim	value = 0;
1869360484Sobrien      newval |= value << 6;
1869477298Sobrien      md_number_to_chars (buf, newval, THUMB_SIZE);
1869560484Sobrien      break;
1869660484Sobrien
1869760484Sobrien    case BFD_RELOC_VTABLE_INHERIT:
1869860484Sobrien    case BFD_RELOC_VTABLE_ENTRY:
1869960484Sobrien      fixP->fx_done = 0;
1870089857Sobrien      return;
1870160484Sobrien
18702218822Sdim    case BFD_RELOC_ARM_MOVW:
18703218822Sdim    case BFD_RELOC_ARM_MOVT:
18704218822Sdim    case BFD_RELOC_ARM_THUMB_MOVW:
18705218822Sdim    case BFD_RELOC_ARM_THUMB_MOVT:
18706218822Sdim      if (fixP->fx_done || !seg->use_rela_p)
18707218822Sdim	{
18708218822Sdim	  /* REL format relocations are limited to a 16-bit addend.  */
18709218822Sdim	  if (!fixP->fx_done)
18710218822Sdim	    {
18711218822Sdim	      if (value < -0x1000 || value > 0xffff)
18712218822Sdim		  as_bad_where (fixP->fx_file, fixP->fx_line,
18713218822Sdim				_("offset too big"));
18714218822Sdim	    }
18715218822Sdim	  else if (fixP->fx_r_type == BFD_RELOC_ARM_MOVT
18716218822Sdim		   || fixP->fx_r_type == BFD_RELOC_ARM_THUMB_MOVT)
18717218822Sdim	    {
18718218822Sdim	      value >>= 16;
18719218822Sdim	    }
18720218822Sdim
18721218822Sdim	  if (fixP->fx_r_type == BFD_RELOC_ARM_THUMB_MOVW
18722218822Sdim	      || fixP->fx_r_type == BFD_RELOC_ARM_THUMB_MOVT)
18723218822Sdim	    {
18724218822Sdim	      newval = get_thumb32_insn (buf);
18725218822Sdim	      newval &= 0xfbf08f00;
18726218822Sdim	      newval |= (value & 0xf000) << 4;
18727218822Sdim	      newval |= (value & 0x0800) << 15;
18728218822Sdim	      newval |= (value & 0x0700) << 4;
18729218822Sdim	      newval |= (value & 0x00ff);
18730218822Sdim	      put_thumb32_insn (buf, newval);
18731218822Sdim	    }
18732218822Sdim	  else
18733218822Sdim	    {
18734218822Sdim	      newval = md_chars_to_number (buf, 4);
18735218822Sdim	      newval &= 0xfff0f000;
18736218822Sdim	      newval |= value & 0x0fff;
18737218822Sdim	      newval |= (value & 0xf000) << 4;
18738218822Sdim	      md_number_to_chars (buf, newval, 4);
18739218822Sdim	    }
18740218822Sdim	}
18741218822Sdim      return;
18742218822Sdim
18743218822Sdim   case BFD_RELOC_ARM_ALU_PC_G0_NC:
18744218822Sdim   case BFD_RELOC_ARM_ALU_PC_G0:
18745218822Sdim   case BFD_RELOC_ARM_ALU_PC_G1_NC:
18746218822Sdim   case BFD_RELOC_ARM_ALU_PC_G1:
18747218822Sdim   case BFD_RELOC_ARM_ALU_PC_G2:
18748218822Sdim   case BFD_RELOC_ARM_ALU_SB_G0_NC:
18749218822Sdim   case BFD_RELOC_ARM_ALU_SB_G0:
18750218822Sdim   case BFD_RELOC_ARM_ALU_SB_G1_NC:
18751218822Sdim   case BFD_RELOC_ARM_ALU_SB_G1:
18752218822Sdim   case BFD_RELOC_ARM_ALU_SB_G2:
18753218822Sdim     assert (!fixP->fx_done);
18754218822Sdim     if (!seg->use_rela_p)
18755218822Sdim       {
18756218822Sdim         bfd_vma insn;
18757218822Sdim         bfd_vma encoded_addend;
18758218822Sdim         bfd_vma addend_abs = abs (value);
18759218822Sdim
18760218822Sdim         /* Check that the absolute value of the addend can be
18761218822Sdim            expressed as an 8-bit constant plus a rotation.  */
18762218822Sdim         encoded_addend = encode_arm_immediate (addend_abs);
18763218822Sdim         if (encoded_addend == (unsigned int) FAIL)
18764218822Sdim	   as_bad_where (fixP->fx_file, fixP->fx_line,
18765218822Sdim	                 _("the offset 0x%08lX is not representable"),
18766218822Sdim                         (unsigned long) addend_abs);
18767218822Sdim
18768218822Sdim         /* Extract the instruction.  */
18769218822Sdim         insn = md_chars_to_number (buf, INSN_SIZE);
18770218822Sdim
18771218822Sdim         /* If the addend is positive, use an ADD instruction.
18772218822Sdim            Otherwise use a SUB.  Take care not to destroy the S bit.  */
18773218822Sdim         insn &= 0xff1fffff;
18774218822Sdim         if (value < 0)
18775218822Sdim           insn |= 1 << 22;
18776218822Sdim         else
18777218822Sdim           insn |= 1 << 23;
18778218822Sdim
18779218822Sdim         /* Place the encoded addend into the first 12 bits of the
18780218822Sdim            instruction.  */
18781218822Sdim         insn &= 0xfffff000;
18782218822Sdim         insn |= encoded_addend;
18783218822Sdim
18784218822Sdim         /* Update the instruction.  */
18785218822Sdim         md_number_to_chars (buf, insn, INSN_SIZE);
18786218822Sdim       }
18787218822Sdim     break;
18788218822Sdim
18789218822Sdim    case BFD_RELOC_ARM_LDR_PC_G0:
18790218822Sdim    case BFD_RELOC_ARM_LDR_PC_G1:
18791218822Sdim    case BFD_RELOC_ARM_LDR_PC_G2:
18792218822Sdim    case BFD_RELOC_ARM_LDR_SB_G0:
18793218822Sdim    case BFD_RELOC_ARM_LDR_SB_G1:
18794218822Sdim    case BFD_RELOC_ARM_LDR_SB_G2:
18795218822Sdim      assert (!fixP->fx_done);
18796218822Sdim      if (!seg->use_rela_p)
18797218822Sdim        {
18798218822Sdim          bfd_vma insn;
18799218822Sdim          bfd_vma addend_abs = abs (value);
18800218822Sdim
18801218822Sdim          /* Check that the absolute value of the addend can be
18802218822Sdim             encoded in 12 bits.  */
18803218822Sdim          if (addend_abs >= 0x1000)
18804218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
18805218822Sdim	  	          _("bad offset 0x%08lX (only 12 bits available for the magnitude)"),
18806218822Sdim                          (unsigned long) addend_abs);
18807218822Sdim
18808218822Sdim          /* Extract the instruction.  */
18809218822Sdim          insn = md_chars_to_number (buf, INSN_SIZE);
18810218822Sdim
18811218822Sdim          /* If the addend is negative, clear bit 23 of the instruction.
18812218822Sdim             Otherwise set it.  */
18813218822Sdim          if (value < 0)
18814218822Sdim            insn &= ~(1 << 23);
18815218822Sdim          else
18816218822Sdim            insn |= 1 << 23;
18817218822Sdim
18818218822Sdim          /* Place the absolute value of the addend into the first 12 bits
18819218822Sdim             of the instruction.  */
18820218822Sdim          insn &= 0xfffff000;
18821218822Sdim          insn |= addend_abs;
18822218822Sdim
18823218822Sdim          /* Update the instruction.  */
18824218822Sdim          md_number_to_chars (buf, insn, INSN_SIZE);
18825218822Sdim        }
18826218822Sdim      break;
18827218822Sdim
18828218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G0:
18829218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G1:
18830218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G2:
18831218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G0:
18832218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G1:
18833218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G2:
18834218822Sdim      assert (!fixP->fx_done);
18835218822Sdim      if (!seg->use_rela_p)
18836218822Sdim        {
18837218822Sdim          bfd_vma insn;
18838218822Sdim          bfd_vma addend_abs = abs (value);
18839218822Sdim
18840218822Sdim          /* Check that the absolute value of the addend can be
18841218822Sdim             encoded in 8 bits.  */
18842218822Sdim          if (addend_abs >= 0x100)
18843218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
18844218822Sdim	  	          _("bad offset 0x%08lX (only 8 bits available for the magnitude)"),
18845218822Sdim                          (unsigned long) addend_abs);
18846218822Sdim
18847218822Sdim          /* Extract the instruction.  */
18848218822Sdim          insn = md_chars_to_number (buf, INSN_SIZE);
18849218822Sdim
18850218822Sdim          /* If the addend is negative, clear bit 23 of the instruction.
18851218822Sdim             Otherwise set it.  */
18852218822Sdim          if (value < 0)
18853218822Sdim            insn &= ~(1 << 23);
18854218822Sdim          else
18855218822Sdim            insn |= 1 << 23;
18856218822Sdim
18857218822Sdim          /* Place the first four bits of the absolute value of the addend
18858218822Sdim             into the first 4 bits of the instruction, and the remaining
18859218822Sdim             four into bits 8 .. 11.  */
18860218822Sdim          insn &= 0xfffff0f0;
18861218822Sdim          insn |= (addend_abs & 0xf) | ((addend_abs & 0xf0) << 4);
18862218822Sdim
18863218822Sdim          /* Update the instruction.  */
18864218822Sdim          md_number_to_chars (buf, insn, INSN_SIZE);
18865218822Sdim        }
18866218822Sdim      break;
18867218822Sdim
18868218822Sdim    case BFD_RELOC_ARM_LDC_PC_G0:
18869218822Sdim    case BFD_RELOC_ARM_LDC_PC_G1:
18870218822Sdim    case BFD_RELOC_ARM_LDC_PC_G2:
18871218822Sdim    case BFD_RELOC_ARM_LDC_SB_G0:
18872218822Sdim    case BFD_RELOC_ARM_LDC_SB_G1:
18873218822Sdim    case BFD_RELOC_ARM_LDC_SB_G2:
18874218822Sdim      assert (!fixP->fx_done);
18875218822Sdim      if (!seg->use_rela_p)
18876218822Sdim        {
18877218822Sdim          bfd_vma insn;
18878218822Sdim          bfd_vma addend_abs = abs (value);
18879218822Sdim
18880218822Sdim          /* Check that the absolute value of the addend is a multiple of
18881218822Sdim             four and, when divided by four, fits in 8 bits.  */
18882218822Sdim          if (addend_abs & 0x3)
18883218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
18884218822Sdim	  	          _("bad offset 0x%08lX (must be word-aligned)"),
18885218822Sdim                          (unsigned long) addend_abs);
18886218822Sdim
18887218822Sdim          if ((addend_abs >> 2) > 0xff)
18888218822Sdim	    as_bad_where (fixP->fx_file, fixP->fx_line,
18889218822Sdim	  	          _("bad offset 0x%08lX (must be an 8-bit number of words)"),
18890218822Sdim                          (unsigned long) addend_abs);
18891218822Sdim
18892218822Sdim          /* Extract the instruction.  */
18893218822Sdim          insn = md_chars_to_number (buf, INSN_SIZE);
18894218822Sdim
18895218822Sdim          /* If the addend is negative, clear bit 23 of the instruction.
18896218822Sdim             Otherwise set it.  */
18897218822Sdim          if (value < 0)
18898218822Sdim            insn &= ~(1 << 23);
18899218822Sdim          else
18900218822Sdim            insn |= 1 << 23;
18901218822Sdim
18902218822Sdim          /* Place the addend (divided by four) into the first eight
18903218822Sdim             bits of the instruction.  */
18904218822Sdim          insn &= 0xfffffff0;
18905218822Sdim          insn |= addend_abs >> 2;
18906218822Sdim
18907218822Sdim          /* Update the instruction.  */
18908218822Sdim          md_number_to_chars (buf, insn, INSN_SIZE);
18909218822Sdim        }
18910218822Sdim      break;
18911218822Sdim
18912218822Sdim    case BFD_RELOC_UNUSED:
1891360484Sobrien    default:
1891460484Sobrien      as_bad_where (fixP->fx_file, fixP->fx_line,
1891589857Sobrien		    _("bad relocation fixup type (%d)"), fixP->fx_r_type);
1891660484Sobrien    }
1891760484Sobrien}
1891860484Sobrien
1891960484Sobrien/* Translate internal representation of relocation info to BFD target
1892060484Sobrien   format.  */
1892177298Sobrien
1892260484Sobrienarelent *
18923218822Sdimtc_gen_reloc (asection *section, fixS *fixp)
1892460484Sobrien{
1892560484Sobrien  arelent * reloc;
1892660484Sobrien  bfd_reloc_code_real_type code;
1892760484Sobrien
18928218822Sdim  reloc = xmalloc (sizeof (arelent));
1892960484Sobrien
18930218822Sdim  reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
1893160484Sobrien  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
1893260484Sobrien  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
1893360484Sobrien
18934218822Sdim  if (fixp->fx_pcrel)
18935218822Sdim    {
18936218822Sdim      if (section->use_rela_p)
18937218822Sdim	fixp->fx_offset -= md_pcrel_from_section (fixp, section);
18938218822Sdim      else
18939218822Sdim	fixp->fx_offset = reloc->address;
18940218822Sdim    }
1894160484Sobrien  reloc->addend = fixp->fx_offset;
1894260484Sobrien
1894360484Sobrien  switch (fixp->fx_r_type)
1894460484Sobrien    {
1894560484Sobrien    case BFD_RELOC_8:
1894660484Sobrien      if (fixp->fx_pcrel)
1894760484Sobrien	{
1894860484Sobrien	  code = BFD_RELOC_8_PCREL;
1894960484Sobrien	  break;
1895060484Sobrien	}
1895160484Sobrien
1895260484Sobrien    case BFD_RELOC_16:
1895360484Sobrien      if (fixp->fx_pcrel)
1895460484Sobrien	{
1895560484Sobrien	  code = BFD_RELOC_16_PCREL;
1895660484Sobrien	  break;
1895760484Sobrien	}
1895860484Sobrien
1895960484Sobrien    case BFD_RELOC_32:
1896060484Sobrien      if (fixp->fx_pcrel)
1896160484Sobrien	{
1896260484Sobrien	  code = BFD_RELOC_32_PCREL;
1896360484Sobrien	  break;
1896460484Sobrien	}
1896560484Sobrien
18966218822Sdim    case BFD_RELOC_ARM_MOVW:
18967218822Sdim      if (fixp->fx_pcrel)
18968218822Sdim	{
18969218822Sdim	  code = BFD_RELOC_ARM_MOVW_PCREL;
18970218822Sdim	  break;
18971218822Sdim	}
18972218822Sdim
18973218822Sdim    case BFD_RELOC_ARM_MOVT:
18974218822Sdim      if (fixp->fx_pcrel)
18975218822Sdim	{
18976218822Sdim	  code = BFD_RELOC_ARM_MOVT_PCREL;
18977218822Sdim	  break;
18978218822Sdim	}
18979218822Sdim
18980218822Sdim    case BFD_RELOC_ARM_THUMB_MOVW:
18981218822Sdim      if (fixp->fx_pcrel)
18982218822Sdim	{
18983218822Sdim	  code = BFD_RELOC_ARM_THUMB_MOVW_PCREL;
18984218822Sdim	  break;
18985218822Sdim	}
18986218822Sdim
18987218822Sdim    case BFD_RELOC_ARM_THUMB_MOVT:
18988218822Sdim      if (fixp->fx_pcrel)
18989218822Sdim	{
18990218822Sdim	  code = BFD_RELOC_ARM_THUMB_MOVT_PCREL;
18991218822Sdim	  break;
18992218822Sdim	}
18993218822Sdim
18994218822Sdim    case BFD_RELOC_NONE:
1899560484Sobrien    case BFD_RELOC_ARM_PCREL_BRANCH:
1899677298Sobrien    case BFD_RELOC_ARM_PCREL_BLX:
1899777298Sobrien    case BFD_RELOC_RVA:
18998218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH7:
1899960484Sobrien    case BFD_RELOC_THUMB_PCREL_BRANCH9:
1900060484Sobrien    case BFD_RELOC_THUMB_PCREL_BRANCH12:
19001218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH20:
1900260484Sobrien    case BFD_RELOC_THUMB_PCREL_BRANCH23:
19003218822Sdim    case BFD_RELOC_THUMB_PCREL_BRANCH25:
1900477298Sobrien    case BFD_RELOC_THUMB_PCREL_BLX:
1900560484Sobrien    case BFD_RELOC_VTABLE_ENTRY:
1900660484Sobrien    case BFD_RELOC_VTABLE_INHERIT:
19007218822Sdim#ifdef TE_PE
19008218822Sdim    case BFD_RELOC_32_SECREL:
19009218822Sdim#endif
1901060484Sobrien      code = fixp->fx_r_type;
1901160484Sobrien      break;
1901260484Sobrien
1901360484Sobrien    case BFD_RELOC_ARM_LITERAL:
1901460484Sobrien    case BFD_RELOC_ARM_HWLITERAL:
19015130561Sobrien      /* If this is called then the a literal has
19016130561Sobrien	 been referenced across a section boundary.  */
1901760484Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
19018130561Sobrien		    _("literal referenced across section boundary"));
1901960484Sobrien      return NULL;
1902060484Sobrien
1902160484Sobrien#ifdef OBJ_ELF
1902260484Sobrien    case BFD_RELOC_ARM_GOT32:
1902360484Sobrien    case BFD_RELOC_ARM_GOTOFF:
1902460484Sobrien    case BFD_RELOC_ARM_PLT32:
19025218822Sdim    case BFD_RELOC_ARM_TARGET1:
19026218822Sdim    case BFD_RELOC_ARM_ROSEGREL32:
19027218822Sdim    case BFD_RELOC_ARM_SBREL32:
19028218822Sdim    case BFD_RELOC_ARM_PREL31:
19029218822Sdim    case BFD_RELOC_ARM_TARGET2:
19030218822Sdim    case BFD_RELOC_ARM_TLS_LE32:
19031218822Sdim    case BFD_RELOC_ARM_TLS_LDO32:
19032218822Sdim    case BFD_RELOC_ARM_PCREL_CALL:
19033218822Sdim    case BFD_RELOC_ARM_PCREL_JUMP:
19034218822Sdim    case BFD_RELOC_ARM_ALU_PC_G0_NC:
19035218822Sdim    case BFD_RELOC_ARM_ALU_PC_G0:
19036218822Sdim    case BFD_RELOC_ARM_ALU_PC_G1_NC:
19037218822Sdim    case BFD_RELOC_ARM_ALU_PC_G1:
19038218822Sdim    case BFD_RELOC_ARM_ALU_PC_G2:
19039218822Sdim    case BFD_RELOC_ARM_LDR_PC_G0:
19040218822Sdim    case BFD_RELOC_ARM_LDR_PC_G1:
19041218822Sdim    case BFD_RELOC_ARM_LDR_PC_G2:
19042218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G0:
19043218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G1:
19044218822Sdim    case BFD_RELOC_ARM_LDRS_PC_G2:
19045218822Sdim    case BFD_RELOC_ARM_LDC_PC_G0:
19046218822Sdim    case BFD_RELOC_ARM_LDC_PC_G1:
19047218822Sdim    case BFD_RELOC_ARM_LDC_PC_G2:
19048218822Sdim    case BFD_RELOC_ARM_ALU_SB_G0_NC:
19049218822Sdim    case BFD_RELOC_ARM_ALU_SB_G0:
19050218822Sdim    case BFD_RELOC_ARM_ALU_SB_G1_NC:
19051218822Sdim    case BFD_RELOC_ARM_ALU_SB_G1:
19052218822Sdim    case BFD_RELOC_ARM_ALU_SB_G2:
19053218822Sdim    case BFD_RELOC_ARM_LDR_SB_G0:
19054218822Sdim    case BFD_RELOC_ARM_LDR_SB_G1:
19055218822Sdim    case BFD_RELOC_ARM_LDR_SB_G2:
19056218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G0:
19057218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G1:
19058218822Sdim    case BFD_RELOC_ARM_LDRS_SB_G2:
19059218822Sdim    case BFD_RELOC_ARM_LDC_SB_G0:
19060218822Sdim    case BFD_RELOC_ARM_LDC_SB_G1:
19061218822Sdim    case BFD_RELOC_ARM_LDC_SB_G2:
1906277298Sobrien      code = fixp->fx_r_type;
1906377298Sobrien      break;
19064218822Sdim
19065218822Sdim    case BFD_RELOC_ARM_TLS_GD32:
19066218822Sdim    case BFD_RELOC_ARM_TLS_IE32:
19067218822Sdim    case BFD_RELOC_ARM_TLS_LDM32:
19068218822Sdim      /* BFD will include the symbol's address in the addend.
19069218822Sdim	 But we don't want that, so subtract it out again here.  */
19070218822Sdim      if (!S_IS_COMMON (fixp->fx_addsy))
19071218822Sdim	reloc->addend -= (*reloc->sym_ptr_ptr)->value;
19072218822Sdim      code = fixp->fx_r_type;
19073218822Sdim      break;
1907460484Sobrien#endif
1907560484Sobrien
1907660484Sobrien    case BFD_RELOC_ARM_IMMEDIATE:
1907760484Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
19078130561Sobrien		    _("internal relocation (type: IMMEDIATE) not fixed up"));
1907960484Sobrien      return NULL;
1908060484Sobrien
1908160484Sobrien    case BFD_RELOC_ARM_ADRL_IMMEDIATE:
1908260484Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
1908377298Sobrien		    _("ADRL used for a symbol not defined in the same file"));
1908460484Sobrien      return NULL;
1908560484Sobrien
1908660484Sobrien    case BFD_RELOC_ARM_OFFSET_IMM:
19087218822Sdim      if (section->use_rela_p)
19088218822Sdim	{
19089218822Sdim	  code = fixp->fx_r_type;
19090218822Sdim	  break;
19091218822Sdim	}
19092218822Sdim
19093130561Sobrien      if (fixp->fx_addsy != NULL
19094130561Sobrien	  && !S_IS_DEFINED (fixp->fx_addsy)
19095130561Sobrien	  && S_IS_LOCAL (fixp->fx_addsy))
19096130561Sobrien	{
19097130561Sobrien	  as_bad_where (fixp->fx_file, fixp->fx_line,
19098130561Sobrien			_("undefined local label `%s'"),
19099130561Sobrien			S_GET_NAME (fixp->fx_addsy));
19100130561Sobrien	  return NULL;
19101130561Sobrien	}
19102130561Sobrien
1910360484Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
19104130561Sobrien		    _("internal_relocation (type: OFFSET_IMM) not fixed up"));
1910560484Sobrien      return NULL;
1910660484Sobrien
1910760484Sobrien    default:
1910860484Sobrien      {
1910960484Sobrien	char * type;
1911077298Sobrien
1911160484Sobrien	switch (fixp->fx_r_type)
1911260484Sobrien	  {
19113218822Sdim	  case BFD_RELOC_NONE:		   type = "NONE";	  break;
1911460484Sobrien	  case BFD_RELOC_ARM_OFFSET_IMM8:  type = "OFFSET_IMM8";  break;
19115218822Sdim	  case BFD_RELOC_ARM_SHIFT_IMM:	   type = "SHIFT_IMM";	  break;
19116218822Sdim	  case BFD_RELOC_ARM_SMC:	   type = "SMC";	  break;
19117218822Sdim	  case BFD_RELOC_ARM_SWI:	   type = "SWI";	  break;
19118218822Sdim	  case BFD_RELOC_ARM_MULTI:	   type = "MULTI";	  break;
19119218822Sdim	  case BFD_RELOC_ARM_CP_OFF_IMM:   type = "CP_OFF_IMM";	  break;
19120218822Sdim	  case BFD_RELOC_ARM_T32_CP_OFF_IMM: type = "T32_CP_OFF_IMM"; break;
19121218822Sdim	  case BFD_RELOC_ARM_THUMB_ADD:	   type = "THUMB_ADD";	  break;
1912260484Sobrien	  case BFD_RELOC_ARM_THUMB_SHIFT:  type = "THUMB_SHIFT";  break;
19123218822Sdim	  case BFD_RELOC_ARM_THUMB_IMM:	   type = "THUMB_IMM";	  break;
1912460484Sobrien	  case BFD_RELOC_ARM_THUMB_OFFSET: type = "THUMB_OFFSET"; break;
19125218822Sdim	  default:			   type = _("<unknown>"); break;
1912660484Sobrien	  }
1912760484Sobrien	as_bad_where (fixp->fx_file, fixp->fx_line,
1912889857Sobrien		      _("cannot represent %s relocation in this object file format"),
1912977298Sobrien		      type);
1913060484Sobrien	return NULL;
1913160484Sobrien      }
1913260484Sobrien    }
1913360484Sobrien
1913460484Sobrien#ifdef OBJ_ELF
19135130561Sobrien  if ((code == BFD_RELOC_32_PCREL || code == BFD_RELOC_32)
1913677298Sobrien      && GOT_symbol
1913777298Sobrien      && fixp->fx_addsy == GOT_symbol)
1913877298Sobrien    {
1913977298Sobrien      code = BFD_RELOC_ARM_GOTPC;
1914077298Sobrien      reloc->addend = fixp->fx_offset = reloc->address;
1914177298Sobrien    }
1914260484Sobrien#endif
1914377298Sobrien
1914460484Sobrien  reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
1914560484Sobrien
1914660484Sobrien  if (reloc->howto == NULL)
1914760484Sobrien    {
1914860484Sobrien      as_bad_where (fixp->fx_file, fixp->fx_line,
1914989857Sobrien		    _("cannot represent %s relocation in this object file format"),
1915060484Sobrien		    bfd_get_reloc_code_name (code));
1915160484Sobrien      return NULL;
1915260484Sobrien    }
1915360484Sobrien
1915477298Sobrien  /* HACK: Since arm ELF uses Rel instead of Rela, encode the
1915577298Sobrien     vtable entry to be used in the relocation's section offset.  */
1915677298Sobrien  if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
1915777298Sobrien    reloc->address = fixp->fx_offset;
1915860484Sobrien
1915960484Sobrien  return reloc;
1916060484Sobrien}
1916160484Sobrien
19162218822Sdim/* This fix_new is called by cons via TC_CONS_FIX_NEW.	*/
1916360484Sobrien
19164218822Sdimvoid
19165218822Sdimcons_fix_new_arm (fragS *	frag,
19166218822Sdim		  int		where,
19167218822Sdim		  int		size,
19168218822Sdim		  expressionS * exp)
1916960484Sobrien{
19170218822Sdim  bfd_reloc_code_real_type type;
19171218822Sdim  int pcrel = 0;
1917277298Sobrien
19173218822Sdim  /* Pick a reloc.
19174218822Sdim     FIXME: @@ Should look at CPU word size.  */
19175218822Sdim  switch (size)
1917660484Sobrien    {
19177218822Sdim    case 1:
19178218822Sdim      type = BFD_RELOC_8;
19179218822Sdim      break;
19180218822Sdim    case 2:
19181218822Sdim      type = BFD_RELOC_16;
19182218822Sdim      break;
19183218822Sdim    case 4:
19184218822Sdim    default:
19185218822Sdim      type = BFD_RELOC_32;
19186218822Sdim      break;
19187218822Sdim    case 8:
19188218822Sdim      type = BFD_RELOC_64;
19189218822Sdim      break;
1919060484Sobrien    }
1919160484Sobrien
19192218822Sdim#ifdef TE_PE
19193218822Sdim  if (exp->X_op == O_secrel)
19194218822Sdim  {
19195218822Sdim    exp->X_op = O_symbol;
19196218822Sdim    type = BFD_RELOC_32_SECREL;
19197218822Sdim  }
19198218822Sdim#endif
1919977298Sobrien
19200218822Sdim  fix_new_exp (frag, where, (int) size, exp, pcrel, type);
19201218822Sdim}
19202218822Sdim
19203218822Sdim#if defined OBJ_COFF || defined OBJ_ELF
19204218822Sdimvoid
19205218822Sdimarm_validate_fix (fixS * fixP)
19206218822Sdim{
19207218822Sdim  /* If the destination of the branch is a defined symbol which does not have
19208218822Sdim     the THUMB_FUNC attribute, then we must be calling a function which has
19209218822Sdim     the (interfacearm) attribute.  We look for the Thumb entry point to that
19210218822Sdim     function and change the branch to refer to that function instead.	*/
19211218822Sdim  if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23
19212218822Sdim      && fixP->fx_addsy != NULL
19213218822Sdim      && S_IS_DEFINED (fixP->fx_addsy)
19214218822Sdim      && ! THUMB_IS_FUNC (fixP->fx_addsy))
1921560484Sobrien    {
19216218822Sdim      fixP->fx_addsy = find_real_start (fixP->fx_addsy);
1921760484Sobrien    }
19218218822Sdim}
19219218822Sdim#endif
1922060484Sobrien
19221218822Sdimint
19222218822Sdimarm_force_relocation (struct fix * fixp)
19223218822Sdim{
19224218822Sdim#if defined (OBJ_COFF) && defined (TE_PE)
19225218822Sdim  if (fixp->fx_r_type == BFD_RELOC_RVA)
19226218822Sdim    return 1;
19227218822Sdim#endif
1922860484Sobrien
19229218822Sdim  /* Resolve these relocations even if the symbol is extern or weak.  */
19230218822Sdim  if (fixp->fx_r_type == BFD_RELOC_ARM_IMMEDIATE
19231218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_OFFSET_IMM
19232218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE
19233218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_T32_ADD_IMM
19234218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_T32_IMMEDIATE
19235218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_T32_IMM12
19236218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_T32_ADD_PC12)
19237218822Sdim    return 0;
19238218822Sdim
19239218822Sdim  /* Always leave these relocations for the linker.  */
19240218822Sdim  if ((fixp->fx_r_type >= BFD_RELOC_ARM_ALU_PC_G0_NC
19241218822Sdim       && fixp->fx_r_type <= BFD_RELOC_ARM_LDC_SB_G2)
19242218822Sdim      || fixp->fx_r_type == BFD_RELOC_ARM_LDR_PC_G0)
19243218822Sdim    return 1;
19244218822Sdim
19245218822Sdim  /* Always generate relocations against function symbols.  */
19246218822Sdim  if (fixp->fx_r_type == BFD_RELOC_32
19247218822Sdim      && fixp->fx_addsy
19248218822Sdim      && (symbol_get_bfdsym (fixp->fx_addsy)->flags & BSF_FUNCTION))
19249218822Sdim    return 1;
19250218822Sdim
19251218822Sdim  return generic_force_reloc (fixp);
19252218822Sdim}
19253218822Sdim
19254218822Sdim#if defined (OBJ_ELF) || defined (OBJ_COFF)
19255218822Sdim/* Relocations against function names must be left unadjusted,
19256218822Sdim   so that the linker can use this information to generate interworking
19257218822Sdim   stubs.  The MIPS version of this function
19258218822Sdim   also prevents relocations that are mips-16 specific, but I do not
19259218822Sdim   know why it does this.
19260218822Sdim
19261218822Sdim   FIXME:
19262218822Sdim   There is one other problem that ought to be addressed here, but
19263218822Sdim   which currently is not:  Taking the address of a label (rather
19264218822Sdim   than a function) and then later jumping to that address.  Such
19265218822Sdim   addresses also ought to have their bottom bit set (assuming that
19266218822Sdim   they reside in Thumb code), but at the moment they will not.	 */
19267218822Sdim
19268218822Sdimbfd_boolean
19269218822Sdimarm_fix_adjustable (fixS * fixP)
19270218822Sdim{
19271218822Sdim  if (fixP->fx_addsy == NULL)
19272218822Sdim    return 1;
19273218822Sdim
19274218822Sdim  /* Preserve relocations against symbols with function type.  */
19275218822Sdim  if (symbol_get_bfdsym (fixP->fx_addsy)->flags & BSF_FUNCTION)
19276218822Sdim    return 0;
19277218822Sdim
19278218822Sdim  if (THUMB_IS_FUNC (fixP->fx_addsy)
19279218822Sdim      && fixP->fx_subsy == NULL)
19280218822Sdim    return 0;
19281218822Sdim
19282218822Sdim  /* We need the symbol name for the VTABLE entries.  */
19283218822Sdim  if (	 fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
19284218822Sdim      || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
19285218822Sdim    return 0;
19286218822Sdim
19287218822Sdim  /* Don't allow symbols to be discarded on GOT related relocs.	 */
19288218822Sdim  if (fixP->fx_r_type == BFD_RELOC_ARM_PLT32
19289218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_GOT32
19290218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_GOTOFF
19291218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_GD32
19292218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LE32
19293218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_IE32
19294218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDM32
19295218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDO32
19296218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_TARGET2)
19297218822Sdim    return 0;
19298218822Sdim
19299218822Sdim  /* Similarly for group relocations.  */
19300218822Sdim  if ((fixP->fx_r_type >= BFD_RELOC_ARM_ALU_PC_G0_NC
19301218822Sdim       && fixP->fx_r_type <= BFD_RELOC_ARM_LDC_SB_G2)
19302218822Sdim      || fixP->fx_r_type == BFD_RELOC_ARM_LDR_PC_G0)
19303218822Sdim    return 0;
19304218822Sdim
19305218822Sdim  return 1;
19306218822Sdim}
19307218822Sdim#endif /* defined (OBJ_ELF) || defined (OBJ_COFF) */
19308218822Sdim
1930977298Sobrien#ifdef OBJ_ELF
19310218822Sdim
19311218822Sdimconst char *
19312218822Sdimelf32_arm_target_format (void)
19313218822Sdim{
19314218822Sdim#ifdef TE_SYMBIAN
19315218822Sdim  return (target_big_endian
19316218822Sdim	  ? "elf32-bigarm-symbian"
19317218822Sdim	  : "elf32-littlearm-symbian");
19318218822Sdim#elif defined (TE_VXWORKS)
19319218822Sdim  return (target_big_endian
19320218822Sdim	  ? "elf32-bigarm-vxworks"
19321218822Sdim	  : "elf32-littlearm-vxworks");
19322218822Sdim#else
19323218822Sdim  if (target_big_endian)
19324218822Sdim    return "elf32-bigarm";
19325218822Sdim  else
19326218822Sdim    return "elf32-littlearm";
1932777298Sobrien#endif
1932860484Sobrien}
1932960484Sobrien
1933060484Sobrienvoid
19331218822Sdimarmelf_frob_symbol (symbolS * symp,
19332218822Sdim		    int *     puntp)
1933360484Sobrien{
19334218822Sdim  elf_frob_symbol (symp, puntp);
19335218822Sdim}
1933677298Sobrien#endif
1933760484Sobrien
19338218822Sdim/* MD interface: Finalization.	*/
1933960484Sobrien
19340218822Sdim/* A good place to do this, although this was probably not intended
19341218822Sdim   for this kind of use.  We need to dump the literal pool before
19342218822Sdim   references are made to a null symbol pointer.  */
1934360484Sobrien
19344218822Sdimvoid
19345218822Sdimarm_cleanup (void)
19346218822Sdim{
19347218822Sdim  literal_pool * pool;
1934877298Sobrien
19349218822Sdim  for (pool = list_of_pools; pool; pool = pool->next)
1935060484Sobrien    {
19351218822Sdim      /* Put it at the end of the relevent section.  */
19352218822Sdim      subseg_set (pool->section, pool->sub_section);
19353218822Sdim#ifdef OBJ_ELF
19354218822Sdim      arm_elf_change_section ();
19355218822Sdim#endif
19356218822Sdim      s_ltorg (0);
1935760484Sobrien    }
19358218822Sdim}
1935960484Sobrien
19360218822Sdim/* Adjust the symbol table.  This marks Thumb symbols as distinct from
19361218822Sdim   ARM ones.  */
1936260484Sobrien
19363218822Sdimvoid
19364218822Sdimarm_adjust_symtab (void)
19365218822Sdim{
19366218822Sdim#ifdef OBJ_COFF
19367218822Sdim  symbolS * sym;
1936877298Sobrien
19369218822Sdim  for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
19370218822Sdim    {
19371218822Sdim      if (ARM_IS_THUMB (sym))
1937260484Sobrien	{
19373218822Sdim	  if (THUMB_IS_FUNC (sym))
1937477298Sobrien	    {
19375218822Sdim	      /* Mark the symbol as a Thumb function.  */
19376218822Sdim	      if (   S_GET_STORAGE_CLASS (sym) == C_STAT
19377218822Sdim		  || S_GET_STORAGE_CLASS (sym) == C_LABEL)  /* This can happen!	 */
19378218822Sdim		S_SET_STORAGE_CLASS (sym, C_THUMBSTATFUNC);
19379218822Sdim
19380218822Sdim	      else if (S_GET_STORAGE_CLASS (sym) == C_EXT)
19381218822Sdim		S_SET_STORAGE_CLASS (sym, C_THUMBEXTFUNC);
19382218822Sdim	      else
19383218822Sdim		as_bad (_("%s: unexpected function type: %d"),
19384218822Sdim			S_GET_NAME (sym), S_GET_STORAGE_CLASS (sym));
1938577298Sobrien	    }
19386218822Sdim	  else switch (S_GET_STORAGE_CLASS (sym))
19387218822Sdim	    {
19388218822Sdim	    case C_EXT:
19389218822Sdim	      S_SET_STORAGE_CLASS (sym, C_THUMBEXT);
19390218822Sdim	      break;
19391218822Sdim	    case C_STAT:
19392218822Sdim	      S_SET_STORAGE_CLASS (sym, C_THUMBSTAT);
19393218822Sdim	      break;
19394218822Sdim	    case C_LABEL:
19395218822Sdim	      S_SET_STORAGE_CLASS (sym, C_THUMBLABEL);
19396218822Sdim	      break;
19397218822Sdim	    default:
19398218822Sdim	      /* Do nothing.  */
19399218822Sdim	      break;
19400218822Sdim	    }
19401218822Sdim	}
1940260484Sobrien
19403218822Sdim      if (ARM_IS_INTERWORK (sym))
19404218822Sdim	coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_flags = 0xFF;
1940560484Sobrien    }
19406218822Sdim#endif
19407218822Sdim#ifdef OBJ_ELF
19408218822Sdim  symbolS * sym;
19409218822Sdim  char	    bind;
19410218822Sdim
19411218822Sdim  for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
1941260484Sobrien    {
19413218822Sdim      if (ARM_IS_THUMB (sym))
19414218822Sdim	{
19415218822Sdim	  elf_symbol_type * elf_sym;
1941660484Sobrien
19417218822Sdim	  elf_sym = elf_symbol (symbol_get_bfdsym (sym));
19418218822Sdim	  bind = ELF_ST_BIND (elf_sym->internal_elf_sym.st_info);
1941977298Sobrien
19420218822Sdim	  if (! bfd_is_arm_special_symbol_name (elf_sym->symbol.name,
19421218822Sdim		BFD_ARM_SPECIAL_SYM_TYPE_ANY))
1942260484Sobrien	    {
19423218822Sdim	      /* If it's a .thumb_func, declare it as so,
19424218822Sdim		 otherwise tag label as .code 16.  */
19425218822Sdim	      if (THUMB_IS_FUNC (sym))
19426218822Sdim		elf_sym->internal_elf_sym.st_info =
19427218822Sdim		  ELF_ST_INFO (bind, STT_ARM_TFUNC);
19428218822Sdim	      else if (EF_ARM_EABI_VERSION (meabi_flags) < EF_ARM_EABI_VER4)
19429218822Sdim		elf_sym->internal_elf_sym.st_info =
19430218822Sdim		  ELF_ST_INFO (bind, STT_ARM_16BIT);
1943160484Sobrien	    }
1943260484Sobrien	}
1943360484Sobrien    }
19434218822Sdim#endif
19435218822Sdim}
1943660484Sobrien
19437218822Sdim/* MD interface: Initialization.  */
1943860484Sobrien
19439218822Sdimstatic void
19440218822Sdimset_constant_flonums (void)
19441218822Sdim{
19442218822Sdim  int i;
19443218822Sdim
19444218822Sdim  for (i = 0; i < NUM_FLOAT_VALS; i++)
19445218822Sdim    if (atof_ieee ((char *) fp_const[i], 'x', fp_values[i]) == NULL)
19446218822Sdim      abort ();
1944789857Sobrien}
1944877298Sobrien
19449218822Sdim/* Auto-select Thumb mode if it's the only available instruction set for the
19450218822Sdim   given architecture.  */
19451218822Sdim
19452218822Sdimstatic void
19453218822Sdimautoselect_thumb_from_cpu_variant (void)
19454218822Sdim{
19455218822Sdim  if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1))
19456218822Sdim    opcode_select (16);
19457218822Sdim}
19458218822Sdim
19459218822Sdimvoid
19460218822Sdimmd_begin (void)
19461218822Sdim{
19462218822Sdim  unsigned mach;
19463218822Sdim  unsigned int i;
19464218822Sdim
19465218822Sdim  if (	 (arm_ops_hsh = hash_new ()) == NULL
19466218822Sdim      || (arm_cond_hsh = hash_new ()) == NULL
19467218822Sdim      || (arm_shift_hsh = hash_new ()) == NULL
19468218822Sdim      || (arm_psr_hsh = hash_new ()) == NULL
19469218822Sdim      || (arm_v7m_psr_hsh = hash_new ()) == NULL
19470218822Sdim      || (arm_reg_hsh = hash_new ()) == NULL
19471218822Sdim      || (arm_reloc_hsh = hash_new ()) == NULL
19472218822Sdim      || (arm_barrier_opt_hsh = hash_new ()) == NULL)
19473218822Sdim    as_fatal (_("virtual memory exhausted"));
19474218822Sdim
19475218822Sdim  for (i = 0; i < sizeof (insns) / sizeof (struct asm_opcode); i++)
19476218822Sdim    hash_insert (arm_ops_hsh, insns[i].template, (PTR) (insns + i));
19477218822Sdim  for (i = 0; i < sizeof (conds) / sizeof (struct asm_cond); i++)
19478218822Sdim    hash_insert (arm_cond_hsh, conds[i].template, (PTR) (conds + i));
19479218822Sdim  for (i = 0; i < sizeof (shift_names) / sizeof (struct asm_shift_name); i++)
19480218822Sdim    hash_insert (arm_shift_hsh, shift_names[i].name, (PTR) (shift_names + i));
19481218822Sdim  for (i = 0; i < sizeof (psrs) / sizeof (struct asm_psr); i++)
19482218822Sdim    hash_insert (arm_psr_hsh, psrs[i].template, (PTR) (psrs + i));
19483218822Sdim  for (i = 0; i < sizeof (v7m_psrs) / sizeof (struct asm_psr); i++)
19484218822Sdim    hash_insert (arm_v7m_psr_hsh, v7m_psrs[i].template, (PTR) (v7m_psrs + i));
19485218822Sdim  for (i = 0; i < sizeof (reg_names) / sizeof (struct reg_entry); i++)
19486218822Sdim    hash_insert (arm_reg_hsh, reg_names[i].name, (PTR) (reg_names + i));
19487218822Sdim  for (i = 0;
19488218822Sdim       i < sizeof (barrier_opt_names) / sizeof (struct asm_barrier_opt);
19489218822Sdim       i++)
19490218822Sdim    hash_insert (arm_barrier_opt_hsh, barrier_opt_names[i].template,
19491218822Sdim		 (PTR) (barrier_opt_names + i));
19492218822Sdim#ifdef OBJ_ELF
19493218822Sdim  for (i = 0; i < sizeof (reloc_names) / sizeof (struct reloc_entry); i++)
19494218822Sdim    hash_insert (arm_reloc_hsh, reloc_names[i].name, (PTR) (reloc_names + i));
19495218822Sdim#endif
19496218822Sdim
19497218822Sdim  set_constant_flonums ();
19498218822Sdim
19499218822Sdim  /* Set the cpu variant based on the command-line options.  We prefer
19500218822Sdim     -mcpu= over -march= if both are set (as for GCC); and we prefer
19501218822Sdim     -mfpu= over any other way of setting the floating point unit.
19502218822Sdim     Use of legacy options with new options are faulted.  */
19503218822Sdim  if (legacy_cpu)
19504218822Sdim    {
19505218822Sdim      if (mcpu_cpu_opt || march_cpu_opt)
19506218822Sdim	as_bad (_("use of old and new-style options to set CPU type"));
19507218822Sdim
19508218822Sdim      mcpu_cpu_opt = legacy_cpu;
19509218822Sdim    }
19510218822Sdim  else if (!mcpu_cpu_opt)
19511218822Sdim    mcpu_cpu_opt = march_cpu_opt;
19512218822Sdim
19513218822Sdim  if (legacy_fpu)
19514218822Sdim    {
19515218822Sdim      if (mfpu_opt)
19516218822Sdim	as_bad (_("use of old and new-style options to set FPU type"));
19517218822Sdim
19518218822Sdim      mfpu_opt = legacy_fpu;
19519218822Sdim    }
19520218822Sdim  else if (!mfpu_opt)
19521218822Sdim    {
19522218822Sdim#if !(defined (TE_LINUX) || defined (TE_NetBSD) || defined (TE_VXWORKS))
19523218822Sdim      /* Some environments specify a default FPU.  If they don't, infer it
19524218822Sdim	 from the processor.  */
19525218822Sdim      if (mcpu_fpu_opt)
19526218822Sdim	mfpu_opt = mcpu_fpu_opt;
19527218822Sdim      else
19528218822Sdim	mfpu_opt = march_fpu_opt;
19529218822Sdim#else
19530218822Sdim      mfpu_opt = &fpu_default;
19531218822Sdim#endif
19532218822Sdim    }
19533218822Sdim
19534218822Sdim  if (!mfpu_opt)
19535218822Sdim    {
19536218822Sdim      if (mcpu_cpu_opt != NULL)
19537218822Sdim	mfpu_opt = &fpu_default;
19538218822Sdim      else if (mcpu_fpu_opt != NULL && ARM_CPU_HAS_FEATURE (*mcpu_fpu_opt, arm_ext_v5))
19539218822Sdim	mfpu_opt = &fpu_arch_vfp_v2;
19540218822Sdim      else
19541218822Sdim	mfpu_opt = &fpu_arch_fpa;
19542218822Sdim    }
19543218822Sdim
19544218822Sdim#ifdef CPU_DEFAULT
19545218822Sdim  if (!mcpu_cpu_opt)
19546218822Sdim    {
19547218822Sdim      mcpu_cpu_opt = &cpu_default;
19548218822Sdim      selected_cpu = cpu_default;
19549218822Sdim    }
19550218822Sdim#else
19551218822Sdim  if (mcpu_cpu_opt)
19552218822Sdim    selected_cpu = *mcpu_cpu_opt;
19553218822Sdim  else
19554218822Sdim    mcpu_cpu_opt = &arm_arch_any;
19555218822Sdim#endif
19556218822Sdim
19557218822Sdim  ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
19558218822Sdim
19559218822Sdim  autoselect_thumb_from_cpu_variant ();
19560218822Sdim
19561218822Sdim  arm_arch_used = thumb_arch_used = arm_arch_none;
19562218822Sdim
19563218822Sdim#if defined OBJ_COFF || defined OBJ_ELF
19564218822Sdim  {
19565218822Sdim    unsigned int flags = 0;
19566218822Sdim
19567218822Sdim#if defined OBJ_ELF
19568218822Sdim    flags = meabi_flags;
19569218822Sdim
19570218822Sdim    switch (meabi_flags)
19571218822Sdim      {
19572218822Sdim      case EF_ARM_EABI_UNKNOWN:
19573218822Sdim#endif
19574218822Sdim	/* Set the flags in the private structure.  */
19575218822Sdim	if (uses_apcs_26)      flags |= F_APCS26;
19576218822Sdim	if (support_interwork) flags |= F_INTERWORK;
19577218822Sdim	if (uses_apcs_float)   flags |= F_APCS_FLOAT;
19578218822Sdim	if (pic_code)	       flags |= F_PIC;
19579218822Sdim	if (!ARM_CPU_HAS_FEATURE (cpu_variant, fpu_any_hard))
19580218822Sdim	  flags |= F_SOFT_FLOAT;
19581218822Sdim
19582218822Sdim	switch (mfloat_abi_opt)
19583218822Sdim	  {
19584218822Sdim	  case ARM_FLOAT_ABI_SOFT:
19585218822Sdim	  case ARM_FLOAT_ABI_SOFTFP:
19586218822Sdim	    flags |= F_SOFT_FLOAT;
19587218822Sdim	    break;
19588218822Sdim
19589218822Sdim	  case ARM_FLOAT_ABI_HARD:
19590218822Sdim	    if (flags & F_SOFT_FLOAT)
19591218822Sdim	      as_bad (_("hard-float conflicts with specified fpu"));
19592218822Sdim	    break;
19593218822Sdim	  }
19594218822Sdim
19595218822Sdim	/* Using pure-endian doubles (even if soft-float).	*/
19596218822Sdim	if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_endian_pure))
19597218822Sdim	  flags |= F_VFP_FLOAT;
19598218822Sdim
19599218822Sdim#if defined OBJ_ELF
19600218822Sdim	if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_arch_maverick))
19601218822Sdim	    flags |= EF_ARM_MAVERICK_FLOAT;
19602218822Sdim	break;
19603218822Sdim
19604218822Sdim      case EF_ARM_EABI_VER4:
19605218822Sdim      case EF_ARM_EABI_VER5:
19606218822Sdim	/* No additional flags to set.	*/
19607218822Sdim	break;
19608218822Sdim
19609218822Sdim      default:
19610218822Sdim	abort ();
19611218822Sdim      }
19612218822Sdim#endif
19613218822Sdim    bfd_set_private_flags (stdoutput, flags);
19614218822Sdim
19615218822Sdim    /* We have run out flags in the COFF header to encode the
19616218822Sdim       status of ATPCS support, so instead we create a dummy,
19617218822Sdim       empty, debug section called .arm.atpcs.	*/
19618218822Sdim    if (atpcs)
19619218822Sdim      {
19620218822Sdim	asection * sec;
19621218822Sdim
19622218822Sdim	sec = bfd_make_section (stdoutput, ".arm.atpcs");
19623218822Sdim
19624218822Sdim	if (sec != NULL)
19625218822Sdim	  {
19626218822Sdim	    bfd_set_section_flags
19627218822Sdim	      (stdoutput, sec, SEC_READONLY | SEC_DEBUGGING /* | SEC_HAS_CONTENTS */);
19628218822Sdim	    bfd_set_section_size (stdoutput, sec, 0);
19629218822Sdim	    bfd_set_section_contents (stdoutput, sec, NULL, 0, 0);
19630218822Sdim	  }
19631218822Sdim      }
19632218822Sdim  }
19633218822Sdim#endif
19634218822Sdim
19635218822Sdim  /* Record the CPU type as well.  */
19636218822Sdim  if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt2))
19637218822Sdim    mach = bfd_mach_arm_iWMMXt2;
19638218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_iwmmxt))
19639218822Sdim    mach = bfd_mach_arm_iWMMXt;
19640218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_xscale))
19641218822Sdim    mach = bfd_mach_arm_XScale;
19642218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_cext_maverick))
19643218822Sdim    mach = bfd_mach_arm_ep9312;
19644218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v5e))
19645218822Sdim    mach = bfd_mach_arm_5TE;
19646218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v5))
19647218822Sdim    {
19648218822Sdim      if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v4t))
19649218822Sdim	mach = bfd_mach_arm_5T;
19650218822Sdim      else
19651218822Sdim	mach = bfd_mach_arm_5;
19652218822Sdim    }
19653218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v4))
19654218822Sdim    {
19655218822Sdim      if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v4t))
19656218822Sdim	mach = bfd_mach_arm_4T;
19657218822Sdim      else
19658218822Sdim	mach = bfd_mach_arm_4;
19659218822Sdim    }
19660218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v3m))
19661218822Sdim    mach = bfd_mach_arm_3M;
19662218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v3))
19663218822Sdim    mach = bfd_mach_arm_3;
19664218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v2s))
19665218822Sdim    mach = bfd_mach_arm_2a;
19666218822Sdim  else if (ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v2))
19667218822Sdim    mach = bfd_mach_arm_2;
19668218822Sdim  else
19669218822Sdim    mach = bfd_mach_arm_unknown;
19670218822Sdim
19671218822Sdim  bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
19672218822Sdim}
19673218822Sdim
19674218822Sdim/* Command line processing.  */
19675218822Sdim
1967689857Sobrien/* md_parse_option
1967789857Sobrien      Invocation line includes a switch not recognized by the base assembler.
19678104834Sobrien      See if it's a processor-specific option.
1967977298Sobrien
1968089857Sobrien      This routine is somewhat complicated by the need for backwards
1968189857Sobrien      compatibility (since older releases of gcc can't be changed).
1968289857Sobrien      The new options try to make the interface as compatible as
1968389857Sobrien      possible with GCC.
1968477298Sobrien
1968589857Sobrien      New options (supported) are:
1968660484Sobrien
1968789857Sobrien	      -mcpu=<cpu name>		 Assemble for selected processor
1968889857Sobrien	      -march=<architecture name> Assemble for selected architecture
1968989857Sobrien	      -mfpu=<fpu architecture>	 Assemble for selected FPU.
1969089857Sobrien	      -EB/-mbig-endian		 Big-endian
1969189857Sobrien	      -EL/-mlittle-endian	 Little-endian
1969289857Sobrien	      -k			 Generate PIC code
1969389857Sobrien	      -mthumb			 Start in Thumb mode
1969489857Sobrien	      -mthumb-interwork		 Code supports ARM/Thumb interworking
1969577298Sobrien
19696130561Sobrien      For now we will also provide support for:
1969760484Sobrien
1969889857Sobrien	      -mapcs-32			 32-bit Program counter
1969989857Sobrien	      -mapcs-26			 26-bit Program counter
1970089857Sobrien	      -macps-float		 Floats passed in FP registers
1970189857Sobrien	      -mapcs-reentrant		 Reentrant code
1970289857Sobrien	      -matpcs
1970389857Sobrien      (sometime these will probably be replaced with -mapcs=<list of options>
1970489857Sobrien      and -matpcs=<list of options>)
1970560484Sobrien
1970689857Sobrien      The remaining options are only supported for back-wards compatibility.
1970777298Sobrien      Cpu variants, the arm part is optional:
19708218822Sdim	      -m[arm]1		      Currently not supported.
19709218822Sdim	      -m[arm]2, -m[arm]250    Arm 2 and Arm 250 processor
19710218822Sdim	      -m[arm]3		      Arm 3 processor
19711218822Sdim	      -m[arm]6[xx],	      Arm 6 processors
19712218822Sdim	      -m[arm]7[xx][t][[d]m]   Arm 7 processors
19713218822Sdim	      -m[arm]8[10]	      Arm 8 processors
19714218822Sdim	      -m[arm]9[20][tdmi]      Arm 9 processors
19715218822Sdim	      -mstrongarm[110[0]]     StrongARM processors
19716218822Sdim	      -mxscale		      XScale processors
19717218822Sdim	      -m[arm]v[2345[t[e]]]    Arm architectures
19718218822Sdim	      -mall		      All (except the ARM1)
1971977298Sobrien      FP variants:
19720218822Sdim	      -mfpa10, -mfpa11	      FPA10 and 11 co-processor instructions
19721218822Sdim	      -mfpe-old		      (No float load/store multiples)
1972289857Sobrien	      -mvfpxd		      VFP Single precision
1972389857Sobrien	      -mvfp		      All VFP
19724218822Sdim	      -mno-fpu		      Disable all floating point instructions
1972560484Sobrien
1972689857Sobrien      The following CPU names are recognized:
1972789857Sobrien	      arm1, arm2, arm250, arm3, arm6, arm600, arm610, arm620,
1972889857Sobrien	      arm7, arm7m, arm7d, arm7dm, arm7di, arm7dmi, arm70, arm700,
1972989857Sobrien	      arm700i, arm710 arm710t, arm720, arm720t, arm740t, arm710c,
1973089857Sobrien	      arm7100, arm7500, arm7500fe, arm7tdmi, arm8, arm810, arm9,
1973189857Sobrien	      arm920, arm920t, arm940t, arm946, arm966, arm9tdmi, arm9e,
1973289857Sobrien	      arm10t arm10e, arm1020t, arm1020e, arm10200e,
1973389857Sobrien	      strongarm, strongarm110, strongarm1100, strongarm1110, xscale.
1973489857Sobrien
1973589857Sobrien      */
1973689857Sobrien
19737104834Sobrienconst char * md_shortopts = "m:k";
1973877298Sobrien
1973989857Sobrien#ifdef ARM_BI_ENDIAN
1974089857Sobrien#define OPTION_EB (OPTION_MD_BASE + 0)
1974189857Sobrien#define OPTION_EL (OPTION_MD_BASE + 1)
1974289857Sobrien#else
1974389857Sobrien#if TARGET_BYTES_BIG_ENDIAN
1974489857Sobrien#define OPTION_EB (OPTION_MD_BASE + 0)
1974589857Sobrien#else
1974689857Sobrien#define OPTION_EL (OPTION_MD_BASE + 1)
1974789857Sobrien#endif
1974889857Sobrien#endif
1974989857Sobrien
1975060484Sobrienstruct option md_longopts[] =
1975160484Sobrien{
1975289857Sobrien#ifdef OPTION_EB
1975360484Sobrien  {"EB", no_argument, NULL, OPTION_EB},
1975489857Sobrien#endif
1975589857Sobrien#ifdef OPTION_EL
1975660484Sobrien  {"EL", no_argument, NULL, OPTION_EL},
1975760484Sobrien#endif
1975860484Sobrien  {NULL, no_argument, NULL, 0}
1975960484Sobrien};
1976077298Sobrien
1976160484Sobriensize_t md_longopts_size = sizeof (md_longopts);
1976260484Sobrien
1976389857Sobrienstruct arm_option_table
1976460484Sobrien{
1976589857Sobrien  char *option;		/* Option name to match.  */
1976689857Sobrien  char *help;		/* Help information.  */
19767218822Sdim  int  *var;		/* Variable to change.	*/
19768218822Sdim  int	value;		/* What to change it to.  */
1976989857Sobrien  char *deprecated;	/* If non-null, print this message.  */
1977089857Sobrien};
1977160484Sobrien
19772104834Sobrienstruct arm_option_table arm_opts[] =
1977389857Sobrien{
19774218822Sdim  {"k",	     N_("generate PIC code"),	   &pic_code,	 1, NULL},
19775218822Sdim  {"mthumb", N_("assemble Thumb code"),	   &thumb_mode,	 1, NULL},
1977689857Sobrien  {"mthumb-interwork", N_("support ARM/Thumb interworking"),
1977789857Sobrien   &support_interwork, 1, NULL},
1977889857Sobrien  {"mapcs-32", N_("code uses 32-bit program counter"), &uses_apcs_26, 0, NULL},
1977989857Sobrien  {"mapcs-26", N_("code uses 26-bit program counter"), &uses_apcs_26, 1, NULL},
1978089857Sobrien  {"mapcs-float", N_("floating point args are in fp regs"), &uses_apcs_float,
1978189857Sobrien   1, NULL},
1978289857Sobrien  {"mapcs-reentrant", N_("re-entrant code"), &pic_code, 1, NULL},
1978389857Sobrien  {"matpcs", N_("code is ATPCS conformant"), &atpcs, 1, NULL},
1978489857Sobrien  {"mbig-endian", N_("assemble for big-endian"), &target_big_endian, 1, NULL},
19785218822Sdim  {"mlittle-endian", N_("assemble for little-endian"), &target_big_endian, 0,
1978689857Sobrien   NULL},
1978789857Sobrien
19788218822Sdim  /* These are recognized by the assembler, but have no affect on code.	 */
1978989857Sobrien  {"mapcs-frame", N_("use frame pointer"), NULL, 0, NULL},
1979089857Sobrien  {"mapcs-stack-check", N_("use stack size checking"), NULL, 0, NULL},
19791218822Sdim  {NULL, NULL, NULL, 0, NULL}
19792218822Sdim};
1979389857Sobrien
19794218822Sdimstruct arm_legacy_option_table
19795218822Sdim{
19796218822Sdim  char *option;				/* Option name to match.  */
19797218822Sdim  const arm_feature_set	**var;		/* Variable to change.	*/
19798218822Sdim  const arm_feature_set	value;		/* What to change it to.  */
19799218822Sdim  char *deprecated;			/* If non-null, print this message.  */
19800218822Sdim};
19801218822Sdim
19802218822Sdimconst struct arm_legacy_option_table arm_legacy_opts[] =
19803218822Sdim{
1980489857Sobrien  /* DON'T add any new processors to this list -- we want the whole list
1980589857Sobrien     to go away...  Add them to the processors table instead.  */
19806218822Sdim  {"marm1",	 &legacy_cpu, ARM_ARCH_V1,  N_("use -mcpu=arm1")},
19807218822Sdim  {"m1",	 &legacy_cpu, ARM_ARCH_V1,  N_("use -mcpu=arm1")},
19808218822Sdim  {"marm2",	 &legacy_cpu, ARM_ARCH_V2,  N_("use -mcpu=arm2")},
19809218822Sdim  {"m2",	 &legacy_cpu, ARM_ARCH_V2,  N_("use -mcpu=arm2")},
19810218822Sdim  {"marm250",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm250")},
19811218822Sdim  {"m250",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm250")},
19812218822Sdim  {"marm3",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm3")},
19813218822Sdim  {"m3",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm3")},
19814218822Sdim  {"marm6",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm6")},
19815218822Sdim  {"m6",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm6")},
19816218822Sdim  {"marm600",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm600")},
19817218822Sdim  {"m600",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm600")},
19818218822Sdim  {"marm610",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm610")},
19819218822Sdim  {"m610",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm610")},
19820218822Sdim  {"marm620",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm620")},
19821218822Sdim  {"m620",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm620")},
19822218822Sdim  {"marm7",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7")},
19823218822Sdim  {"m7",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7")},
19824218822Sdim  {"marm70",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm70")},
19825218822Sdim  {"m70",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm70")},
19826218822Sdim  {"marm700",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm700")},
19827218822Sdim  {"m700",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm700")},
19828218822Sdim  {"marm700i",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm700i")},
19829218822Sdim  {"m700i",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm700i")},
19830218822Sdim  {"marm710",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm710")},
19831218822Sdim  {"m710",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm710")},
19832218822Sdim  {"marm710c",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm710c")},
19833218822Sdim  {"m710c",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm710c")},
19834218822Sdim  {"marm720",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm720")},
19835218822Sdim  {"m720",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm720")},
19836218822Sdim  {"marm7d",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7d")},
19837218822Sdim  {"m7d",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7d")},
19838218822Sdim  {"marm7di",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7di")},
19839218822Sdim  {"m7di",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7di")},
19840218822Sdim  {"marm7m",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7m")},
19841218822Sdim  {"m7m",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7m")},
19842218822Sdim  {"marm7dm",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dm")},
19843218822Sdim  {"m7dm",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dm")},
19844218822Sdim  {"marm7dmi",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dmi")},
19845218822Sdim  {"m7dmi",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dmi")},
19846218822Sdim  {"marm7100",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7100")},
19847218822Sdim  {"m7100",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7100")},
19848218822Sdim  {"marm7500",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7500")},
19849218822Sdim  {"m7500",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7500")},
19850218822Sdim  {"marm7500fe", &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7500fe")},
19851218822Sdim  {"m7500fe",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -mcpu=arm7500fe")},
19852218822Sdim  {"marm7t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
19853218822Sdim  {"m7t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
19854218822Sdim  {"marm7tdmi",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
19855218822Sdim  {"m7tdmi",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
19856218822Sdim  {"marm710t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm710t")},
19857218822Sdim  {"m710t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm710t")},
19858218822Sdim  {"marm720t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm720t")},
19859218822Sdim  {"m720t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm720t")},
19860218822Sdim  {"marm740t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm740t")},
19861218822Sdim  {"m740t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm740t")},
19862218822Sdim  {"marm8",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -mcpu=arm8")},
19863218822Sdim  {"m8",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -mcpu=arm8")},
19864218822Sdim  {"marm810",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -mcpu=arm810")},
19865218822Sdim  {"m810",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -mcpu=arm810")},
19866218822Sdim  {"marm9",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9")},
19867218822Sdim  {"m9",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9")},
19868218822Sdim  {"marm9tdmi",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9tdmi")},
19869218822Sdim  {"m9tdmi",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9tdmi")},
19870218822Sdim  {"marm920",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm920")},
19871218822Sdim  {"m920",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm920")},
19872218822Sdim  {"marm940",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm940")},
19873218822Sdim  {"m940",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm940")},
19874218822Sdim  {"mstrongarm", &legacy_cpu, ARM_ARCH_V4,  N_("use -mcpu=strongarm")},
19875218822Sdim  {"mstrongarm110", &legacy_cpu, ARM_ARCH_V4,
1987689857Sobrien   N_("use -mcpu=strongarm110")},
19877218822Sdim  {"mstrongarm1100", &legacy_cpu, ARM_ARCH_V4,
1987889857Sobrien   N_("use -mcpu=strongarm1100")},
19879218822Sdim  {"mstrongarm1110", &legacy_cpu, ARM_ARCH_V4,
1988089857Sobrien   N_("use -mcpu=strongarm1110")},
19881218822Sdim  {"mxscale",	 &legacy_cpu, ARM_ARCH_XSCALE, N_("use -mcpu=xscale")},
19882218822Sdim  {"miwmmxt",	 &legacy_cpu, ARM_ARCH_IWMMXT, N_("use -mcpu=iwmmxt")},
19883218822Sdim  {"mall",	 &legacy_cpu, ARM_ANY,	       N_("use -mcpu=all")},
1988489857Sobrien
1988589857Sobrien  /* Architecture variants -- don't add any more to this list either.  */
19886218822Sdim  {"mv2",	 &legacy_cpu, ARM_ARCH_V2,  N_("use -march=armv2")},
19887218822Sdim  {"marmv2",	 &legacy_cpu, ARM_ARCH_V2,  N_("use -march=armv2")},
19888218822Sdim  {"mv2a",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -march=armv2a")},
19889218822Sdim  {"marmv2a",	 &legacy_cpu, ARM_ARCH_V2S, N_("use -march=armv2a")},
19890218822Sdim  {"mv3",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -march=armv3")},
19891218822Sdim  {"marmv3",	 &legacy_cpu, ARM_ARCH_V3,  N_("use -march=armv3")},
19892218822Sdim  {"mv3m",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -march=armv3m")},
19893218822Sdim  {"marmv3m",	 &legacy_cpu, ARM_ARCH_V3M, N_("use -march=armv3m")},
19894218822Sdim  {"mv4",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -march=armv4")},
19895218822Sdim  {"marmv4",	 &legacy_cpu, ARM_ARCH_V4,  N_("use -march=armv4")},
19896218822Sdim  {"mv4t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -march=armv4t")},
19897218822Sdim  {"marmv4t",	 &legacy_cpu, ARM_ARCH_V4T, N_("use -march=armv4t")},
19898218822Sdim  {"mv5",	 &legacy_cpu, ARM_ARCH_V5,  N_("use -march=armv5")},
19899218822Sdim  {"marmv5",	 &legacy_cpu, ARM_ARCH_V5,  N_("use -march=armv5")},
19900218822Sdim  {"mv5t",	 &legacy_cpu, ARM_ARCH_V5T, N_("use -march=armv5t")},
19901218822Sdim  {"marmv5t",	 &legacy_cpu, ARM_ARCH_V5T, N_("use -march=armv5t")},
19902218822Sdim  {"mv5e",	 &legacy_cpu, ARM_ARCH_V5TE, N_("use -march=armv5te")},
19903218822Sdim  {"marmv5e",	 &legacy_cpu, ARM_ARCH_V5TE, N_("use -march=armv5te")},
1990489857Sobrien
19905218822Sdim  /* Floating point variants -- don't add any more to this list either.	 */
19906218822Sdim  {"mfpe-old", &legacy_fpu, FPU_ARCH_FPE, N_("use -mfpu=fpe")},
19907218822Sdim  {"mfpa10",   &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa10")},
19908218822Sdim  {"mfpa11",   &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa11")},
19909218822Sdim  {"mno-fpu",  &legacy_fpu, ARM_ARCH_NONE,
1991089857Sobrien   N_("use either -mfpu=softfpa or -mfpu=softvfp")},
1991189857Sobrien
19912218822Sdim  {NULL, NULL, ARM_ARCH_NONE, NULL}
1991389857Sobrien};
1991489857Sobrien
1991589857Sobrienstruct arm_cpu_option_table
1991689857Sobrien{
1991789857Sobrien  char *name;
19918218822Sdim  const arm_feature_set	value;
1991989857Sobrien  /* For some CPUs we assume an FPU unless the user explicitly sets
19920218822Sdim     -mfpu=...	*/
19921218822Sdim  const arm_feature_set	default_fpu;
19922218822Sdim  /* The canonical name of the CPU, or NULL to use NAME converted to upper
19923218822Sdim     case.  */
19924218822Sdim  const char *canonical_name;
1992589857Sobrien};
1992689857Sobrien
1992789857Sobrien/* This list should, at a minimum, contain all the cpu names
1992889857Sobrien   recognized by GCC.  */
19929218822Sdimstatic const struct arm_cpu_option_table arm_cpus[] =
1993089857Sobrien{
19931218822Sdim  {"all",		ARM_ANY,	 FPU_ARCH_FPA,    NULL},
19932218822Sdim  {"arm1",		ARM_ARCH_V1,	 FPU_ARCH_FPA,    NULL},
19933218822Sdim  {"arm2",		ARM_ARCH_V2,	 FPU_ARCH_FPA,    NULL},
19934218822Sdim  {"arm250",		ARM_ARCH_V2S,	 FPU_ARCH_FPA,    NULL},
19935218822Sdim  {"arm3",		ARM_ARCH_V2S,	 FPU_ARCH_FPA,    NULL},
19936218822Sdim  {"arm6",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
19937218822Sdim  {"arm60",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
19938218822Sdim  {"arm600",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
19939218822Sdim  {"arm610",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
19940218822Sdim  {"arm620",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
19941218822Sdim  {"arm7",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
19942218822Sdim  {"arm7m",		ARM_ARCH_V3M,	 FPU_ARCH_FPA,    NULL},
19943218822Sdim  {"arm7d",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
19944218822Sdim  {"arm7dm",		ARM_ARCH_V3M,	 FPU_ARCH_FPA,    NULL},
19945218822Sdim  {"arm7di",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
19946218822Sdim  {"arm7dmi",		ARM_ARCH_V3M,	 FPU_ARCH_FPA,    NULL},
19947218822Sdim  {"arm70",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
19948218822Sdim  {"arm700",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
19949218822Sdim  {"arm700i",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
19950218822Sdim  {"arm710",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
19951218822Sdim  {"arm710t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
19952218822Sdim  {"arm720",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
19953218822Sdim  {"arm720t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
19954218822Sdim  {"arm740t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
19955218822Sdim  {"arm710c",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
19956218822Sdim  {"arm7100",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
19957218822Sdim  {"arm7500",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
19958218822Sdim  {"arm7500fe",		ARM_ARCH_V3,	 FPU_ARCH_FPA,    NULL},
19959218822Sdim  {"arm7t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
19960218822Sdim  {"arm7tdmi",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
19961218822Sdim  {"arm7tdmi-s",	ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
19962218822Sdim  {"arm8",		ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
19963218822Sdim  {"arm810",		ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
19964218822Sdim  {"strongarm",		ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
19965218822Sdim  {"strongarm1",	ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
19966218822Sdim  {"strongarm110",	ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
19967218822Sdim  {"strongarm1100",	ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
19968218822Sdim  {"strongarm1110",	ARM_ARCH_V4,	 FPU_ARCH_FPA,    NULL},
19969218822Sdim  {"arm9",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
19970218822Sdim  {"arm920",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    "ARM920T"},
19971218822Sdim  {"arm920t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
19972218822Sdim  {"arm922t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
19973218822Sdim  {"arm940t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,    NULL},
19974218822Sdim  {"arm9tdmi",		ARM_ARCH_V4T,	 FPU_ARCH_FPA,	  NULL},
1997589857Sobrien  /* For V5 or later processors we default to using VFP; but the user
19976218822Sdim     should really set the FPU type explicitly.	 */
19977218822Sdim  {"arm9e-r0",		ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL},
19978218822Sdim  {"arm9e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
19979218822Sdim  {"arm926ej",		ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP_V2, "ARM926EJ-S"},
19980218822Sdim  {"arm926ejs",		ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP_V2, "ARM926EJ-S"},
19981218822Sdim  {"arm926ej-s",	ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP_V2, NULL},
19982218822Sdim  {"arm946e-r0",	ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL},
19983218822Sdim  {"arm946e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, "ARM946E-S"},
19984218822Sdim  {"arm946e-s",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
19985218822Sdim  {"arm966e-r0",	ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2, NULL},
19986218822Sdim  {"arm966e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, "ARM966E-S"},
19987218822Sdim  {"arm966e-s",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
19988218822Sdim  {"arm968e-s",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
19989218822Sdim  {"arm10t",		ARM_ARCH_V5T,	 FPU_ARCH_VFP_V1, NULL},
19990218822Sdim  {"arm10tdmi",		ARM_ARCH_V5T,	 FPU_ARCH_VFP_V1, NULL},
19991218822Sdim  {"arm10e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
19992218822Sdim  {"arm1020",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, "ARM1020E"},
19993218822Sdim  {"arm1020t",		ARM_ARCH_V5T,	 FPU_ARCH_VFP_V1, NULL},
19994218822Sdim  {"arm1020e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
19995218822Sdim  {"arm1022e",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP_V2, NULL},
19996218822Sdim  {"arm1026ejs",	ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP_V2, "ARM1026EJ-S"},
19997218822Sdim  {"arm1026ej-s",	ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP_V2, NULL},
19998218822Sdim  {"arm1136js",		ARM_ARCH_V6,	 FPU_NONE,	  "ARM1136J-S"},
19999218822Sdim  {"arm1136j-s",	ARM_ARCH_V6,	 FPU_NONE,	  NULL},
20000218822Sdim  {"arm1136jfs",	ARM_ARCH_V6,	 FPU_ARCH_VFP_V2, "ARM1136JF-S"},
20001218822Sdim  {"arm1136jf-s",	ARM_ARCH_V6,	 FPU_ARCH_VFP_V2, NULL},
20002218822Sdim  {"mpcore",		ARM_ARCH_V6K,	 FPU_ARCH_VFP_V2, NULL},
20003218822Sdim  {"mpcorenovfp",	ARM_ARCH_V6K,	 FPU_NONE,	  NULL},
20004218822Sdim  {"arm1156t2-s",	ARM_ARCH_V6T2,	 FPU_NONE,	  NULL},
20005218822Sdim  {"arm1156t2f-s",	ARM_ARCH_V6T2,	 FPU_ARCH_VFP_V2, NULL},
20006218822Sdim  {"arm1176jz-s",	ARM_ARCH_V6ZK,	 FPU_NONE,	  NULL},
20007218822Sdim  {"arm1176jzf-s",	ARM_ARCH_V6ZK,	 FPU_ARCH_VFP_V2, NULL},
20008218822Sdim  {"cortex-a8",		ARM_ARCH_V7A,	 ARM_FEATURE(0, FPU_VFP_V3
20009218822Sdim                                                        | FPU_NEON_EXT_V1),
20010218822Sdim                                                          NULL},
20011218822Sdim  {"cortex-r4",		ARM_ARCH_V7R,	 FPU_NONE,	  NULL},
20012218822Sdim  {"cortex-m3",		ARM_ARCH_V7M,	 FPU_NONE,	  NULL},
2001389857Sobrien  /* ??? XSCALE is really an architecture.  */
20014218822Sdim  {"xscale",		ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL},
20015130561Sobrien  /* ??? iwmmxt is not a processor.  */
20016218822Sdim  {"iwmmxt",		ARM_ARCH_IWMMXT, FPU_ARCH_VFP_V2, NULL},
20017218822Sdim  {"iwmmxt2",		ARM_ARCH_IWMMXT2,FPU_ARCH_VFP_V2, NULL},
20018218822Sdim  {"i80200",		ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2, NULL},
2001989857Sobrien  /* Maverick */
20020218822Sdim  {"ep9312",	ARM_FEATURE(ARM_AEXT_V4T, ARM_CEXT_MAVERICK), FPU_ARCH_MAVERICK, "ARM920T"},
20021218822Sdim  {NULL,		ARM_ARCH_NONE,	 ARM_ARCH_NONE, NULL}
2002289857Sobrien};
20023104834Sobrien
2002489857Sobrienstruct arm_arch_option_table
2002589857Sobrien{
2002689857Sobrien  char *name;
20027218822Sdim  const arm_feature_set	value;
20028218822Sdim  const arm_feature_set	default_fpu;
2002989857Sobrien};
2003089857Sobrien
2003189857Sobrien/* This list should, at a minimum, contain all the architecture names
2003289857Sobrien   recognized by GCC.  */
20033218822Sdimstatic const struct arm_arch_option_table arm_archs[] =
2003489857Sobrien{
2003589857Sobrien  {"all",		ARM_ANY,	 FPU_ARCH_FPA},
2003689857Sobrien  {"armv1",		ARM_ARCH_V1,	 FPU_ARCH_FPA},
2003789857Sobrien  {"armv2",		ARM_ARCH_V2,	 FPU_ARCH_FPA},
2003889857Sobrien  {"armv2a",		ARM_ARCH_V2S,	 FPU_ARCH_FPA},
2003989857Sobrien  {"armv2s",		ARM_ARCH_V2S,	 FPU_ARCH_FPA},
2004089857Sobrien  {"armv3",		ARM_ARCH_V3,	 FPU_ARCH_FPA},
2004189857Sobrien  {"armv3m",		ARM_ARCH_V3M,	 FPU_ARCH_FPA},
2004289857Sobrien  {"armv4",		ARM_ARCH_V4,	 FPU_ARCH_FPA},
2004389857Sobrien  {"armv4xm",		ARM_ARCH_V4xM,	 FPU_ARCH_FPA},
2004489857Sobrien  {"armv4t",		ARM_ARCH_V4T,	 FPU_ARCH_FPA},
2004589857Sobrien  {"armv4txm",		ARM_ARCH_V4TxM,	 FPU_ARCH_FPA},
2004689857Sobrien  {"armv5",		ARM_ARCH_V5,	 FPU_ARCH_VFP},
2004789857Sobrien  {"armv5t",		ARM_ARCH_V5T,	 FPU_ARCH_VFP},
2004889857Sobrien  {"armv5txm",		ARM_ARCH_V5TxM,	 FPU_ARCH_VFP},
2004989857Sobrien  {"armv5te",		ARM_ARCH_V5TE,	 FPU_ARCH_VFP},
2005089857Sobrien  {"armv5texp",		ARM_ARCH_V5TExP, FPU_ARCH_VFP},
20051218822Sdim  {"armv5tej",		ARM_ARCH_V5TEJ,	 FPU_ARCH_VFP},
20052218822Sdim  {"armv6",		ARM_ARCH_V6,	 FPU_ARCH_VFP},
20053218822Sdim  {"armv6j",		ARM_ARCH_V6,	 FPU_ARCH_VFP},
20054218822Sdim  {"armv6k",		ARM_ARCH_V6K,	 FPU_ARCH_VFP},
20055218822Sdim  {"armv6z",		ARM_ARCH_V6Z,	 FPU_ARCH_VFP},
20056218822Sdim  {"armv6zk",		ARM_ARCH_V6ZK,	 FPU_ARCH_VFP},
20057218822Sdim  {"armv6t2",		ARM_ARCH_V6T2,	 FPU_ARCH_VFP},
20058218822Sdim  {"armv6kt2",		ARM_ARCH_V6KT2,	 FPU_ARCH_VFP},
20059218822Sdim  {"armv6zt2",		ARM_ARCH_V6ZT2,	 FPU_ARCH_VFP},
20060218822Sdim  {"armv6zkt2",		ARM_ARCH_V6ZKT2, FPU_ARCH_VFP},
20061218822Sdim  {"armv7",		ARM_ARCH_V7,	 FPU_ARCH_VFP},
20062218822Sdim  /* The official spelling of the ARMv7 profile variants is the dashed form.
20063218822Sdim     Accept the non-dashed form for compatibility with old toolchains.  */
20064218822Sdim  {"armv7a",		ARM_ARCH_V7A,	 FPU_ARCH_VFP},
20065218822Sdim  {"armv7r",		ARM_ARCH_V7R,	 FPU_ARCH_VFP},
20066218822Sdim  {"armv7m",		ARM_ARCH_V7M,	 FPU_ARCH_VFP},
20067218822Sdim  {"armv7-a",		ARM_ARCH_V7A,	 FPU_ARCH_VFP},
20068218822Sdim  {"armv7-r",		ARM_ARCH_V7R,	 FPU_ARCH_VFP},
20069218822Sdim  {"armv7-m",		ARM_ARCH_V7M,	 FPU_ARCH_VFP},
2007089857Sobrien  {"xscale",		ARM_ARCH_XSCALE, FPU_ARCH_VFP},
20071130561Sobrien  {"iwmmxt",		ARM_ARCH_IWMMXT, FPU_ARCH_VFP},
20072218822Sdim  {"iwmmxt2",		ARM_ARCH_IWMMXT2,FPU_ARCH_VFP},
20073218822Sdim  {NULL,		ARM_ARCH_NONE,	 ARM_ARCH_NONE}
2007489857Sobrien};
2007589857Sobrien
2007689857Sobrien/* ISA extensions in the co-processor space.  */
20077218822Sdimstruct arm_option_cpu_value_table
2007889857Sobrien{
2007989857Sobrien  char *name;
20080218822Sdim  const arm_feature_set value;
2008189857Sobrien};
2008289857Sobrien
20083218822Sdimstatic const struct arm_option_cpu_value_table arm_extensions[] =
2008489857Sobrien{
20085218822Sdim  {"maverick",		ARM_FEATURE (0, ARM_CEXT_MAVERICK)},
20086218822Sdim  {"xscale",		ARM_FEATURE (0, ARM_CEXT_XSCALE)},
20087218822Sdim  {"iwmmxt",		ARM_FEATURE (0, ARM_CEXT_IWMMXT)},
20088218822Sdim  {"iwmmxt2",		ARM_FEATURE (0, ARM_CEXT_IWMMXT2)},
20089218822Sdim  {NULL,		ARM_ARCH_NONE}
2009089857Sobrien};
2009189857Sobrien
2009289857Sobrien/* This list should, at a minimum, contain all the fpu names
2009389857Sobrien   recognized by GCC.  */
20094218822Sdimstatic const struct arm_option_cpu_value_table arm_fpus[] =
2009589857Sobrien{
2009689857Sobrien  {"softfpa",		FPU_NONE},
2009789857Sobrien  {"fpe",		FPU_ARCH_FPE},
2009889857Sobrien  {"fpe2",		FPU_ARCH_FPE},
2009989857Sobrien  {"fpe3",		FPU_ARCH_FPA},	/* Third release supports LFM/SFM.  */
2010089857Sobrien  {"fpa",		FPU_ARCH_FPA},
2010189857Sobrien  {"fpa10",		FPU_ARCH_FPA},
2010289857Sobrien  {"fpa11",		FPU_ARCH_FPA},
2010389857Sobrien  {"arm7500fe",		FPU_ARCH_FPA},
2010489857Sobrien  {"softvfp",		FPU_ARCH_VFP},
2010589857Sobrien  {"softvfp+vfp",	FPU_ARCH_VFP_V2},
2010689857Sobrien  {"vfp",		FPU_ARCH_VFP_V2},
2010789857Sobrien  {"vfp9",		FPU_ARCH_VFP_V2},
20108218822Sdim  {"vfp3",              FPU_ARCH_VFP_V3},
2010989857Sobrien  {"vfp10",		FPU_ARCH_VFP_V2},
2011089857Sobrien  {"vfp10-r0",		FPU_ARCH_VFP_V1},
2011189857Sobrien  {"vfpxd",		FPU_ARCH_VFP_V1xD},
2011289857Sobrien  {"arm1020t",		FPU_ARCH_VFP_V1},
2011389857Sobrien  {"arm1020e",		FPU_ARCH_VFP_V2},
20114130561Sobrien  {"arm1136jfs",	FPU_ARCH_VFP_V2},
20115218822Sdim  {"arm1136jf-s",	FPU_ARCH_VFP_V2},
20116130561Sobrien  {"maverick",		FPU_ARCH_MAVERICK},
20117218822Sdim  {"neon",              FPU_ARCH_VFP_V3_PLUS_NEON_V1},
20118218822Sdim  {NULL,		ARM_ARCH_NONE}
2011989857Sobrien};
2012089857Sobrien
20121218822Sdimstruct arm_option_value_table
20122130561Sobrien{
20123130561Sobrien  char *name;
20124218822Sdim  long value;
20125130561Sobrien};
20126130561Sobrien
20127218822Sdimstatic const struct arm_option_value_table arm_float_abis[] =
20128130561Sobrien{
20129130561Sobrien  {"hard",	ARM_FLOAT_ABI_HARD},
20130130561Sobrien  {"softfp",	ARM_FLOAT_ABI_SOFTFP},
20131130561Sobrien  {"soft",	ARM_FLOAT_ABI_SOFT},
20132218822Sdim  {NULL,	0}
20133130561Sobrien};
20134130561Sobrien
20135218822Sdim#ifdef OBJ_ELF
20136218822Sdim/* We only know how to output GNU and ver 4/5 (AAELF) formats.  */
20137218822Sdimstatic const struct arm_option_value_table arm_eabis[] =
20138218822Sdim{
20139218822Sdim  {"gnu",	EF_ARM_EABI_UNKNOWN},
20140218822Sdim  {"4",		EF_ARM_EABI_VER4},
20141218822Sdim  {"5",		EF_ARM_EABI_VER5},
20142218822Sdim  {NULL,	0}
20143218822Sdim};
20144218822Sdim#endif
20145218822Sdim
2014689857Sobrienstruct arm_long_option_table
2014789857Sobrien{
20148218822Sdim  char * option;		/* Substring to match.	*/
20149218822Sdim  char * help;			/* Help information.  */
20150218822Sdim  int (* func) (char * subopt);	/* Function to decode sub-option.  */
20151218822Sdim  char * deprecated;		/* If non-null, print this message.  */
2015289857Sobrien};
2015389857Sobrien
2015489857Sobrienstatic int
20155218822Sdimarm_parse_extension (char * str, const arm_feature_set **opt_p)
2015689857Sobrien{
20157218822Sdim  arm_feature_set *ext_set = xmalloc (sizeof (arm_feature_set));
20158218822Sdim
20159218822Sdim  /* Copy the feature set, so that we can modify it.  */
20160218822Sdim  *ext_set = **opt_p;
20161218822Sdim  *opt_p = ext_set;
20162218822Sdim
2016389857Sobrien  while (str != NULL && *str != 0)
2016460484Sobrien    {
20165218822Sdim      const struct arm_option_cpu_value_table * opt;
20166218822Sdim      char * ext;
2016789857Sobrien      int optlen;
2016860484Sobrien
2016989857Sobrien      if (*str != '+')
2017060484Sobrien	{
2017189857Sobrien	  as_bad (_("invalid architectural extension"));
2017289857Sobrien	  return 0;
2017389857Sobrien	}
2017460484Sobrien
2017589857Sobrien      str++;
2017689857Sobrien      ext = strchr (str, '+');
2017760484Sobrien
2017889857Sobrien      if (ext != NULL)
2017989857Sobrien	optlen = ext - str;
2018089857Sobrien      else
2018189857Sobrien	optlen = strlen (str);
2018277298Sobrien
2018389857Sobrien      if (optlen == 0)
2018489857Sobrien	{
2018589857Sobrien	  as_bad (_("missing architectural extension"));
2018689857Sobrien	  return 0;
2018789857Sobrien	}
2018860484Sobrien
2018989857Sobrien      for (opt = arm_extensions; opt->name != NULL; opt++)
2019089857Sobrien	if (strncmp (opt->name, str, optlen) == 0)
2019189857Sobrien	  {
20192218822Sdim	    ARM_MERGE_FEATURE_SETS (*ext_set, *ext_set, opt->value);
2019389857Sobrien	    break;
2019489857Sobrien	  }
2019560484Sobrien
2019689857Sobrien      if (opt->name == NULL)
2019789857Sobrien	{
2019889857Sobrien	  as_bad (_("unknown architectural extnsion `%s'"), str);
2019989857Sobrien	  return 0;
2020089857Sobrien	}
2020177298Sobrien
2020289857Sobrien      str = ext;
2020389857Sobrien    };
2020460484Sobrien
2020589857Sobrien  return 1;
2020689857Sobrien}
2020760484Sobrien
2020889857Sobrienstatic int
20209218822Sdimarm_parse_cpu (char * str)
2021089857Sobrien{
20211218822Sdim  const struct arm_cpu_option_table * opt;
20212218822Sdim  char * ext = strchr (str, '+');
2021389857Sobrien  int optlen;
2021477298Sobrien
2021589857Sobrien  if (ext != NULL)
2021689857Sobrien    optlen = ext - str;
2021789857Sobrien  else
2021889857Sobrien    optlen = strlen (str);
2021977298Sobrien
2022089857Sobrien  if (optlen == 0)
2022189857Sobrien    {
2022289857Sobrien      as_bad (_("missing cpu name `%s'"), str);
2022389857Sobrien      return 0;
2022489857Sobrien    }
2022560484Sobrien
2022689857Sobrien  for (opt = arm_cpus; opt->name != NULL; opt++)
2022789857Sobrien    if (strncmp (opt->name, str, optlen) == 0)
2022889857Sobrien      {
20229218822Sdim	mcpu_cpu_opt = &opt->value;
20230218822Sdim	mcpu_fpu_opt = &opt->default_fpu;
20231218822Sdim	if (opt->canonical_name)
20232218822Sdim	  strcpy(selected_cpu_name, opt->canonical_name);
20233218822Sdim	else
20234218822Sdim	  {
20235218822Sdim	    int i;
20236218822Sdim	    for (i = 0; i < optlen; i++)
20237218822Sdim	      selected_cpu_name[i] = TOUPPER (opt->name[i]);
20238218822Sdim	    selected_cpu_name[i] = 0;
20239218822Sdim	  }
2024060484Sobrien
2024189857Sobrien	if (ext != NULL)
2024289857Sobrien	  return arm_parse_extension (ext, &mcpu_cpu_opt);
2024360484Sobrien
2024489857Sobrien	return 1;
2024589857Sobrien      }
2024660484Sobrien
2024789857Sobrien  as_bad (_("unknown cpu `%s'"), str);
2024889857Sobrien  return 0;
2024989857Sobrien}
2025060484Sobrien
2025189857Sobrienstatic int
20252218822Sdimarm_parse_arch (char * str)
2025389857Sobrien{
20254218822Sdim  const struct arm_arch_option_table *opt;
2025589857Sobrien  char *ext = strchr (str, '+');
2025689857Sobrien  int optlen;
2025760484Sobrien
2025889857Sobrien  if (ext != NULL)
2025989857Sobrien    optlen = ext - str;
2026089857Sobrien  else
2026189857Sobrien    optlen = strlen (str);
2026260484Sobrien
2026389857Sobrien  if (optlen == 0)
2026489857Sobrien    {
2026589857Sobrien      as_bad (_("missing architecture name `%s'"), str);
2026689857Sobrien      return 0;
2026789857Sobrien    }
2026877298Sobrien
2026989857Sobrien  for (opt = arm_archs; opt->name != NULL; opt++)
20270218822Sdim    if (streq (opt->name, str))
2027189857Sobrien      {
20272218822Sdim	march_cpu_opt = &opt->value;
20273218822Sdim	march_fpu_opt = &opt->default_fpu;
20274218822Sdim	strcpy(selected_cpu_name, opt->name);
2027560484Sobrien
2027689857Sobrien	if (ext != NULL)
2027789857Sobrien	  return arm_parse_extension (ext, &march_cpu_opt);
2027877298Sobrien
2027989857Sobrien	return 1;
2028089857Sobrien      }
2028160484Sobrien
2028289857Sobrien  as_bad (_("unknown architecture `%s'\n"), str);
2028389857Sobrien  return 0;
2028489857Sobrien}
2028577298Sobrien
2028689857Sobrienstatic int
20287218822Sdimarm_parse_fpu (char * str)
2028889857Sobrien{
20289218822Sdim  const struct arm_option_cpu_value_table * opt;
2029077298Sobrien
2029189857Sobrien  for (opt = arm_fpus; opt->name != NULL; opt++)
20292218822Sdim    if (streq (opt->name, str))
2029389857Sobrien      {
20294218822Sdim	mfpu_opt = &opt->value;
2029589857Sobrien	return 1;
2029689857Sobrien      }
2029777298Sobrien
2029889857Sobrien  as_bad (_("unknown floating point format `%s'\n"), str);
2029989857Sobrien  return 0;
2030089857Sobrien}
2030177298Sobrien
20302130561Sobrienstatic int
20303218822Sdimarm_parse_float_abi (char * str)
20304130561Sobrien{
20305218822Sdim  const struct arm_option_value_table * opt;
20306130561Sobrien
20307130561Sobrien  for (opt = arm_float_abis; opt->name != NULL; opt++)
20308218822Sdim    if (streq (opt->name, str))
20309130561Sobrien      {
20310130561Sobrien	mfloat_abi_opt = opt->value;
20311130561Sobrien	return 1;
20312130561Sobrien      }
20313130561Sobrien
20314130561Sobrien  as_bad (_("unknown floating point abi `%s'\n"), str);
20315130561Sobrien  return 0;
20316130561Sobrien}
20317130561Sobrien
20318218822Sdim#ifdef OBJ_ELF
20319218822Sdimstatic int
20320218822Sdimarm_parse_eabi (char * str)
20321218822Sdim{
20322218822Sdim  const struct arm_option_value_table *opt;
20323218822Sdim
20324218822Sdim  for (opt = arm_eabis; opt->name != NULL; opt++)
20325218822Sdim    if (streq (opt->name, str))
20326218822Sdim      {
20327218822Sdim	meabi_flags = opt->value;
20328218822Sdim	return 1;
20329218822Sdim      }
20330218822Sdim  as_bad (_("unknown EABI `%s'\n"), str);
20331218822Sdim  return 0;
20332218822Sdim}
20333218822Sdim#endif
20334218822Sdim
2033589857Sobrienstruct arm_long_option_table arm_long_opts[] =
2033689857Sobrien{
2033789857Sobrien  {"mcpu=", N_("<cpu name>\t  assemble for CPU <cpu name>"),
2033889857Sobrien   arm_parse_cpu, NULL},
2033989857Sobrien  {"march=", N_("<arch name>\t  assemble for architecture <arch name>"),
2034089857Sobrien   arm_parse_arch, NULL},
2034189857Sobrien  {"mfpu=", N_("<fpu name>\t  assemble for FPU architecture <fpu name>"),
2034289857Sobrien   arm_parse_fpu, NULL},
20343130561Sobrien  {"mfloat-abi=", N_("<abi>\t  assemble for floating point ABI <abi>"),
20344130561Sobrien   arm_parse_float_abi, NULL},
20345218822Sdim#ifdef OBJ_ELF
20346218822Sdim  {"meabi=", N_("<ver>\t  assemble for eabi version <ver>"),
20347218822Sdim   arm_parse_eabi, NULL},
20348218822Sdim#endif
2034989857Sobrien  {NULL, NULL, 0, NULL}
2035089857Sobrien};
2035177298Sobrien
2035289857Sobrienint
20353218822Sdimmd_parse_option (int c, char * arg)
2035489857Sobrien{
2035589857Sobrien  struct arm_option_table *opt;
20356218822Sdim  const struct arm_legacy_option_table *fopt;
2035789857Sobrien  struct arm_long_option_table *lopt;
2035877298Sobrien
2035989857Sobrien  switch (c)
2036089857Sobrien    {
2036189857Sobrien#ifdef OPTION_EB
2036289857Sobrien    case OPTION_EB:
2036389857Sobrien      target_big_endian = 1;
2036489857Sobrien      break;
2036589857Sobrien#endif
2036660484Sobrien
2036789857Sobrien#ifdef OPTION_EL
2036889857Sobrien    case OPTION_EL:
2036989857Sobrien      target_big_endian = 0;
2037089857Sobrien      break;
2037189857Sobrien#endif
2037277298Sobrien
2037389857Sobrien    case 'a':
20374104834Sobrien      /* Listing option.  Just ignore these, we don't support additional
20375218822Sdim	 ones.	*/
2037689857Sobrien      return 0;
2037777298Sobrien
2037889857Sobrien    default:
2037989857Sobrien      for (opt = arm_opts; opt->option != NULL; opt++)
2038089857Sobrien	{
2038189857Sobrien	  if (c == opt->option[0]
2038289857Sobrien	      && ((arg == NULL && opt->option[1] == 0)
20383218822Sdim		  || streq (arg, opt->option + 1)))
2038489857Sobrien	    {
2038589857Sobrien#if WARN_DEPRECATED
2038689857Sobrien	      /* If the option is deprecated, tell the user.  */
2038789857Sobrien	      if (opt->deprecated != NULL)
2038889857Sobrien		as_tsktsk (_("option `-%c%s' is deprecated: %s"), c,
2038989857Sobrien			   arg ? arg : "", _(opt->deprecated));
2039089857Sobrien#endif
2039189857Sobrien
2039289857Sobrien	      if (opt->var != NULL)
2039389857Sobrien		*opt->var = opt->value;
2039489857Sobrien
2039589857Sobrien	      return 1;
2039660484Sobrien	    }
2039760484Sobrien	}
2039860484Sobrien
20399218822Sdim      for (fopt = arm_legacy_opts; fopt->option != NULL; fopt++)
20400218822Sdim	{
20401218822Sdim	  if (c == fopt->option[0]
20402218822Sdim	      && ((arg == NULL && fopt->option[1] == 0)
20403218822Sdim		  || streq (arg, fopt->option + 1)))
20404218822Sdim	    {
20405218822Sdim#if WARN_DEPRECATED
20406218822Sdim	      /* If the option is deprecated, tell the user.  */
20407218822Sdim	      if (fopt->deprecated != NULL)
20408218822Sdim		as_tsktsk (_("option `-%c%s' is deprecated: %s"), c,
20409218822Sdim			   arg ? arg : "", _(fopt->deprecated));
20410218822Sdim#endif
20411218822Sdim
20412218822Sdim	      if (fopt->var != NULL)
20413218822Sdim		*fopt->var = &fopt->value;
20414218822Sdim
20415218822Sdim	      return 1;
20416218822Sdim	    }
20417218822Sdim	}
20418218822Sdim
2041989857Sobrien      for (lopt = arm_long_opts; lopt->option != NULL; lopt++)
2042089857Sobrien	{
20421104834Sobrien	  /* These options are expected to have an argument.  */
2042289857Sobrien	  if (c == lopt->option[0]
2042389857Sobrien	      && arg != NULL
20424104834Sobrien	      && strncmp (arg, lopt->option + 1,
2042589857Sobrien			  strlen (lopt->option + 1)) == 0)
2042689857Sobrien	    {
2042789857Sobrien#if WARN_DEPRECATED
2042889857Sobrien	      /* If the option is deprecated, tell the user.  */
2042989857Sobrien	      if (lopt->deprecated != NULL)
2043089857Sobrien		as_tsktsk (_("option `-%c%s' is deprecated: %s"), c, arg,
2043189857Sobrien			   _(lopt->deprecated));
2043260484Sobrien#endif
2043377298Sobrien
2043489857Sobrien	      /* Call the sup-option parser.  */
20435218822Sdim	      return lopt->func (arg + strlen (lopt->option) - 1);
2043689857Sobrien	    }
2043789857Sobrien	}
2043889857Sobrien
2043960484Sobrien      return 0;
2044060484Sobrien    }
2044160484Sobrien
2044277298Sobrien  return 1;
2044360484Sobrien}
2044460484Sobrien
2044560484Sobrienvoid
20446218822Sdimmd_show_usage (FILE * fp)
2044760484Sobrien{
2044889857Sobrien  struct arm_option_table *opt;
2044989857Sobrien  struct arm_long_option_table *lopt;
2045089857Sobrien
2045189857Sobrien  fprintf (fp, _(" ARM-specific assembler options:\n"));
2045289857Sobrien
2045389857Sobrien  for (opt = arm_opts; opt->option != NULL; opt++)
2045489857Sobrien    if (opt->help != NULL)
2045589857Sobrien      fprintf (fp, "  -%-23s%s\n", opt->option, _(opt->help));
2045689857Sobrien
2045789857Sobrien  for (lopt = arm_long_opts; lopt->option != NULL; lopt++)
2045889857Sobrien    if (lopt->help != NULL)
2045989857Sobrien      fprintf (fp, "  -%s%s\n", lopt->option, _(lopt->help));
2046089857Sobrien
2046189857Sobrien#ifdef OPTION_EB
2046260484Sobrien  fprintf (fp, _("\
2046389857Sobrien  -EB                     assemble code for a big-endian cpu\n"));
2046477298Sobrien#endif
2046589857Sobrien
2046689857Sobrien#ifdef OPTION_EL
2046760484Sobrien  fprintf (fp, _("\
2046889857Sobrien  -EL                     assemble code for a little-endian cpu\n"));
2046960484Sobrien#endif
2047060484Sobrien}
2047160484Sobrien
2047260484Sobrien
20473218822Sdim#ifdef OBJ_ELF
20474218822Sdimtypedef struct
2047560484Sobrien{
20476218822Sdim  int val;
20477218822Sdim  arm_feature_set flags;
20478218822Sdim} cpu_arch_ver_table;
2047960484Sobrien
20480218822Sdim/* Mapping from CPU features to EABI CPU arch values.  Table must be sorted
20481218822Sdim   least features first.  */
20482218822Sdimstatic const cpu_arch_ver_table cpu_arch_ver[] =
2048360484Sobrien{
20484218822Sdim    {1, ARM_ARCH_V4},
20485218822Sdim    {2, ARM_ARCH_V4T},
20486218822Sdim    {3, ARM_ARCH_V5},
20487218822Sdim    {4, ARM_ARCH_V5TE},
20488218822Sdim    {5, ARM_ARCH_V5TEJ},
20489218822Sdim    {6, ARM_ARCH_V6},
20490218822Sdim    {7, ARM_ARCH_V6Z},
20491218822Sdim    {8, ARM_ARCH_V6K},
20492218822Sdim    {9, ARM_ARCH_V6T2},
20493218822Sdim    {10, ARM_ARCH_V7A},
20494218822Sdim    {10, ARM_ARCH_V7R},
20495218822Sdim    {10, ARM_ARCH_V7M},
20496218822Sdim    {0, ARM_ARCH_NONE}
20497218822Sdim};
2049877298Sobrien
20499218822Sdim/* Set the public EABI object attributes.  */
20500218822Sdimstatic void
20501218822Sdimaeabi_set_public_attributes (void)
2050260484Sobrien{
20503218822Sdim  int arch;
20504218822Sdim  arm_feature_set flags;
20505218822Sdim  arm_feature_set tmp;
20506218822Sdim  const cpu_arch_ver_table *p;
2050777298Sobrien
20508218822Sdim  /* Choose the architecture based on the capabilities of the requested cpu
20509218822Sdim     (if any) and/or the instructions actually used.  */
20510218822Sdim  ARM_MERGE_FEATURE_SETS (flags, arm_arch_used, thumb_arch_used);
20511218822Sdim  ARM_MERGE_FEATURE_SETS (flags, flags, *mfpu_opt);
20512218822Sdim  ARM_MERGE_FEATURE_SETS (flags, flags, selected_cpu);
20513218822Sdim  /*Allow the user to override the reported architecture.  */
20514218822Sdim  if (object_arch)
20515130561Sobrien    {
20516218822Sdim      ARM_CLEAR_FEATURE (flags, flags, arm_arch_any);
20517218822Sdim      ARM_MERGE_FEATURE_SETS (flags, flags, *object_arch);
20518130561Sobrien    }
2051960484Sobrien
20520218822Sdim  tmp = flags;
20521218822Sdim  arch = 0;
20522218822Sdim  for (p = cpu_arch_ver; p->val; p++)
2052360484Sobrien    {
20524218822Sdim      if (ARM_CPU_HAS_FEATURE (tmp, p->flags))
2052577298Sobrien	{
20526218822Sdim	  arch = p->val;
20527218822Sdim	  ARM_CLEAR_FEATURE (tmp, tmp, p->flags);
2052877298Sobrien	}
2052960484Sobrien    }
2053060484Sobrien
20531218822Sdim  /* Tag_CPU_name.  */
20532218822Sdim  if (selected_cpu_name[0])
2053360484Sobrien    {
20534218822Sdim      char *p;
20535218822Sdim
20536218822Sdim      p = selected_cpu_name;
20537218822Sdim      if (strncmp(p, "armv", 4) == 0)
2053877298Sobrien	{
20539218822Sdim	  int i;
20540218822Sdim
20541218822Sdim	  p += 4;
20542218822Sdim	  for (i = 0; p[i]; i++)
20543218822Sdim	    p[i] = TOUPPER (p[i]);
2054477298Sobrien	}
20545218822Sdim      bfd_elf_add_proc_attr_string (stdoutput, 5, p);
2054677298Sobrien    }
20547218822Sdim  /* Tag_CPU_arch.  */
20548218822Sdim  bfd_elf_add_proc_attr_int (stdoutput, 6, arch);
20549218822Sdim  /* Tag_CPU_arch_profile.  */
20550218822Sdim  if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7a))
20551218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 7, 'A');
20552218822Sdim  else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7r))
20553218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 7, 'R');
20554218822Sdim  else if (ARM_CPU_HAS_FEATURE (flags, arm_ext_v7m))
20555218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 7, 'M');
20556218822Sdim  /* Tag_ARM_ISA_use.  */
20557218822Sdim  if (ARM_CPU_HAS_FEATURE (arm_arch_used, arm_arch_full))
20558218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 8, 1);
20559218822Sdim  /* Tag_THUMB_ISA_use.  */
20560218822Sdim  if (ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_full))
20561218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 9,
20562218822Sdim	ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_arch_t2) ? 2 : 1);
20563218822Sdim  /* Tag_VFP_arch.  */
20564218822Sdim  if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v3)
20565218822Sdim      || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v3))
20566218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 10, 3);
20567218822Sdim  else if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v2)
20568218822Sdim           || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v2))
20569218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 10, 2);
20570218822Sdim  else if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v1)
20571218822Sdim           || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v1)
20572218822Sdim           || ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_vfp_ext_v1xd)
20573218822Sdim           || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_vfp_ext_v1xd))
20574218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 10, 1);
20575218822Sdim  /* Tag_WMMX_arch.  */
20576218822Sdim  if (ARM_CPU_HAS_FEATURE (thumb_arch_used, arm_cext_iwmmxt)
20577218822Sdim      || ARM_CPU_HAS_FEATURE (arm_arch_used, arm_cext_iwmmxt))
20578218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 11, 1);
20579218822Sdim  /* Tag_NEON_arch.  */
20580218822Sdim  if (ARM_CPU_HAS_FEATURE (thumb_arch_used, fpu_neon_ext_v1)
20581218822Sdim      || ARM_CPU_HAS_FEATURE (arm_arch_used, fpu_neon_ext_v1))
20582218822Sdim    bfd_elf_add_proc_attr_int (stdoutput, 12, 1);
2058360484Sobrien}
2058460484Sobrien
20585218822Sdim/* Add the default contents for the .ARM.attributes section.  */
20586218822Sdimvoid
20587218822Sdimarm_md_end (void)
2058860484Sobrien{
20589218822Sdim  if (EF_ARM_EABI_VERSION (meabi_flags) < EF_ARM_EABI_VER4)
20590218822Sdim    return;
2059177298Sobrien
20592218822Sdim  aeabi_set_public_attributes ();
2059360484Sobrien}
20594218822Sdim#endif /* OBJ_ELF */
2059560484Sobrien
2059660484Sobrien
20597218822Sdim/* Parse a .cpu directive.  */
2059860484Sobrien
20599218822Sdimstatic void
20600218822Sdims_arm_cpu (int ignored ATTRIBUTE_UNUSED)
2060160484Sobrien{
20602218822Sdim  const struct arm_cpu_option_table *opt;
20603218822Sdim  char *name;
20604218822Sdim  char saved_char;
2060560484Sobrien
20606218822Sdim  name = input_line_pointer;
20607218822Sdim  while (*input_line_pointer && !ISSPACE(*input_line_pointer))
20608218822Sdim    input_line_pointer++;
20609218822Sdim  saved_char = *input_line_pointer;
20610218822Sdim  *input_line_pointer = 0;
20611130561Sobrien
20612218822Sdim  /* Skip the first "all" entry.  */
20613218822Sdim  for (opt = arm_cpus + 1; opt->name != NULL; opt++)
20614218822Sdim    if (streq (opt->name, name))
20615218822Sdim      {
20616218822Sdim	mcpu_cpu_opt = &opt->value;
20617218822Sdim	selected_cpu = opt->value;
20618218822Sdim	if (opt->canonical_name)
20619218822Sdim	  strcpy(selected_cpu_name, opt->canonical_name);
20620218822Sdim	else
20621218822Sdim	  {
20622218822Sdim	    int i;
20623218822Sdim	    for (i = 0; opt->name[i]; i++)
20624218822Sdim	      selected_cpu_name[i] = TOUPPER (opt->name[i]);
20625218822Sdim	    selected_cpu_name[i] = 0;
20626218822Sdim	  }
20627218822Sdim	ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
20628218822Sdim	*input_line_pointer = saved_char;
20629218822Sdim	demand_empty_rest_of_line ();
20630218822Sdim	return;
20631218822Sdim      }
20632218822Sdim  as_bad (_("unknown cpu `%s'"), name);
20633218822Sdim  *input_line_pointer = saved_char;
20634218822Sdim  ignore_rest_of_line ();
2063560484Sobrien}
2063660484Sobrien
2063777298Sobrien
20638218822Sdim/* Parse a .arch directive.  */
20639130561Sobrien
20640218822Sdimstatic void
20641218822Sdims_arm_arch (int ignored ATTRIBUTE_UNUSED)
2064260484Sobrien{
20643218822Sdim  const struct arm_arch_option_table *opt;
20644218822Sdim  char saved_char;
20645218822Sdim  char *name;
2064677298Sobrien
20647218822Sdim  name = input_line_pointer;
20648218822Sdim  while (*input_line_pointer && !ISSPACE(*input_line_pointer))
20649218822Sdim    input_line_pointer++;
20650218822Sdim  saved_char = *input_line_pointer;
20651218822Sdim  *input_line_pointer = 0;
2065277298Sobrien
20653218822Sdim  /* Skip the first "all" entry.  */
20654218822Sdim  for (opt = arm_archs + 1; opt->name != NULL; opt++)
20655218822Sdim    if (streq (opt->name, name))
20656218822Sdim      {
20657218822Sdim	mcpu_cpu_opt = &opt->value;
20658218822Sdim	selected_cpu = opt->value;
20659218822Sdim	strcpy(selected_cpu_name, opt->name);
20660218822Sdim	ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
20661218822Sdim	*input_line_pointer = saved_char;
20662218822Sdim	demand_empty_rest_of_line ();
20663218822Sdim	return;
20664218822Sdim      }
2066560484Sobrien
20666218822Sdim  as_bad (_("unknown architecture `%s'\n"), name);
20667218822Sdim  *input_line_pointer = saved_char;
20668218822Sdim  ignore_rest_of_line ();
2066960484Sobrien}
2067060484Sobrien
2067160484Sobrien
20672218822Sdim/* Parse a .object_arch directive.  */
2067360484Sobrien
2067460484Sobrienstatic void
20675218822Sdims_arm_object_arch (int ignored ATTRIBUTE_UNUSED)
2067660484Sobrien{
20677218822Sdim  const struct arm_arch_option_table *opt;
20678218822Sdim  char saved_char;
20679218822Sdim  char *name;
2068060484Sobrien
20681218822Sdim  name = input_line_pointer;
20682218822Sdim  while (*input_line_pointer && !ISSPACE(*input_line_pointer))
20683218822Sdim    input_line_pointer++;
20684218822Sdim  saved_char = *input_line_pointer;
20685218822Sdim  *input_line_pointer = 0;
2068660484Sobrien
20687218822Sdim  /* Skip the first "all" entry.  */
20688218822Sdim  for (opt = arm_archs + 1; opt->name != NULL; opt++)
20689218822Sdim    if (streq (opt->name, name))
20690218822Sdim      {
20691218822Sdim	object_arch = &opt->value;
20692218822Sdim	*input_line_pointer = saved_char;
20693218822Sdim	demand_empty_rest_of_line ();
20694218822Sdim	return;
20695218822Sdim      }
2069660484Sobrien
20697218822Sdim  as_bad (_("unknown architecture `%s'\n"), name);
20698218822Sdim  *input_line_pointer = saved_char;
20699218822Sdim  ignore_rest_of_line ();
2070060484Sobrien}
2070160484Sobrien
2070278828Sobrien
20703218822Sdim/* Parse a .fpu directive.  */
2070478828Sobrien
20705218822Sdimstatic void
20706218822Sdims_arm_fpu (int ignored ATTRIBUTE_UNUSED)
2070778828Sobrien{
20708218822Sdim  const struct arm_option_cpu_value_table *opt;
20709218822Sdim  char saved_char;
20710218822Sdim  char *name;
2071178828Sobrien
20712218822Sdim  name = input_line_pointer;
20713218822Sdim  while (*input_line_pointer && !ISSPACE(*input_line_pointer))
20714218822Sdim    input_line_pointer++;
20715218822Sdim  saved_char = *input_line_pointer;
20716218822Sdim  *input_line_pointer = 0;
20717218822Sdim
20718218822Sdim  for (opt = arm_fpus; opt->name != NULL; opt++)
20719218822Sdim    if (streq (opt->name, name))
20720218822Sdim      {
20721218822Sdim	mfpu_opt = &opt->value;
20722218822Sdim	ARM_MERGE_FEATURE_SETS (cpu_variant, *mcpu_cpu_opt, *mfpu_opt);
20723218822Sdim	*input_line_pointer = saved_char;
20724218822Sdim	demand_empty_rest_of_line ();
20725218822Sdim	return;
20726218822Sdim      }
20727104834Sobrien
20728218822Sdim  as_bad (_("unknown floating point format `%s'\n"), name);
20729218822Sdim  *input_line_pointer = saved_char;
20730218822Sdim  ignore_rest_of_line ();
2073178828Sobrien}
2073278828Sobrien
20733218822Sdim/* Copy symbol information.  */
2073478828Sobrienvoid
20735218822Sdimarm_copy_symbol_attributes (symbolS *dest, symbolS *src)
2073678828Sobrien{
20737218822Sdim  ARM_GET_FLAG (dest) = ARM_GET_FLAG (src);
2073878828Sobrien}
20739