aarch64-opc.h revision 1.1.1.1
1/* aarch64-opc.h -- Header file for aarch64-opc.c and aarch64-opc-2.c.
2   Copyright 2012  Free Software Foundation, Inc.
3   Contributed by ARM Ltd.
4
5   This file is part of the GNU opcodes library.
6
7   This library is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3, or (at your option)
10   any later version.
11
12   It is distributed in the hope that it will be useful, but WITHOUT
13   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15   License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; see the file COPYING3. If not,
19   see <http://www.gnu.org/licenses/>.  */
20
21#ifndef OPCODES_AARCH64_OPC_H
22#define OPCODES_AARCH64_OPC_H
23
24#include <string.h>
25#include "opcode/aarch64.h"
26
27/* Instruction fields.
28   Keep synced with fields.  */
29enum aarch64_field_kind
30{
31  FLD_NIL,
32  FLD_cond2,
33  FLD_nzcv,
34  FLD_defgh,
35  FLD_abc,
36  FLD_imm19,
37  FLD_immhi,
38  FLD_immlo,
39  FLD_size,
40  FLD_vldst_size,
41  FLD_op,
42  FLD_Q,
43  FLD_Rt,
44  FLD_Rd,
45  FLD_Rn,
46  FLD_Rt2,
47  FLD_Ra,
48  FLD_op2,
49  FLD_CRm,
50  FLD_CRn,
51  FLD_op1,
52  FLD_op0,
53  FLD_imm3,
54  FLD_cond,
55  FLD_opcode,
56  FLD_cmode,
57  FLD_asisdlso_opcode,
58  FLD_len,
59  FLD_Rm,
60  FLD_Rs,
61  FLD_option,
62  FLD_S,
63  FLD_hw,
64  FLD_opc,
65  FLD_opc1,
66  FLD_shift,
67  FLD_type,
68  FLD_ldst_size,
69  FLD_imm6,
70  FLD_imm4,
71  FLD_imm5,
72  FLD_imm7,
73  FLD_imm8,
74  FLD_imm9,
75  FLD_imm12,
76  FLD_imm14,
77  FLD_imm16,
78  FLD_imm26,
79  FLD_imms,
80  FLD_immr,
81  FLD_immb,
82  FLD_immh,
83  FLD_N,
84  FLD_index,
85  FLD_index2,
86  FLD_sf,
87  FLD_H,
88  FLD_L,
89  FLD_M,
90  FLD_b5,
91  FLD_b40,
92  FLD_scale,
93};
94
95/* Field description.  */
96struct aarch64_field
97{
98  int lsb;
99  int width;
100};
101
102typedef struct aarch64_field aarch64_field;
103
104extern const aarch64_field fields[];
105
106/* Operand description.  */
107
108struct aarch64_operand
109{
110  enum aarch64_operand_class op_class;
111
112  /* Name of the operand code; used mainly for the purpose of internal
113     debugging.  */
114  const char *name;
115
116  unsigned int flags;
117
118  /* The associated instruction bit-fields; no operand has more than 4
119     bit-fields */
120  enum aarch64_field_kind fields[4];
121
122  /* Brief description */
123  const char *desc;
124};
125
126typedef struct aarch64_operand aarch64_operand;
127
128extern const aarch64_operand aarch64_operands[];
129
130/* Operand flags.  */
131
132#define OPD_F_HAS_INSERTER	0x00000001
133#define OPD_F_HAS_EXTRACTOR	0x00000002
134#define OPD_F_SEXT		0x00000004	/* Require sign-extension.  */
135#define OPD_F_SHIFT_BY_2	0x00000008	/* Need to left shift the field
136						   value by 2 to get the value
137						   of an immediate operand.  */
138#define OPD_F_MAYBE_SP		0x00000010	/* May potentially be SP.  */
139
140static inline bfd_boolean
141operand_has_inserter (const aarch64_operand *operand)
142{
143  return (operand->flags & OPD_F_HAS_INSERTER) ? TRUE : FALSE;
144}
145
146static inline bfd_boolean
147operand_has_extractor (const aarch64_operand *operand)
148{
149  return (operand->flags & OPD_F_HAS_EXTRACTOR) ? TRUE : FALSE;
150}
151
152static inline bfd_boolean
153operand_need_sign_extension (const aarch64_operand *operand)
154{
155  return (operand->flags & OPD_F_SEXT) ? TRUE : FALSE;
156}
157
158static inline bfd_boolean
159operand_need_shift_by_two (const aarch64_operand *operand)
160{
161  return (operand->flags & OPD_F_SHIFT_BY_2) ? TRUE : FALSE;
162}
163
164static inline bfd_boolean
165operand_maybe_stack_pointer (const aarch64_operand *operand)
166{
167  return (operand->flags & OPD_F_MAYBE_SP) ? TRUE : FALSE;
168}
169
170/* Return the total width of the operand *OPERAND.  */
171static inline unsigned
172get_operand_fields_width (const aarch64_operand *operand)
173{
174  int i = 0;
175  unsigned width = 0;
176  while (operand->fields[i] != FLD_NIL)
177    width += fields[operand->fields[i++]].width;
178  assert (width > 0 && width < 32);
179  return width;
180}
181
182static inline const aarch64_operand *
183get_operand_from_code (enum aarch64_opnd code)
184{
185  return aarch64_operands + code;
186}
187
188/* Operand qualifier and operand constraint checking.  */
189
190int aarch64_match_operands_constraint (aarch64_inst *,
191				       aarch64_operand_error *);
192
193/* Operand qualifier related functions.  */
194const char* aarch64_get_qualifier_name (aarch64_opnd_qualifier_t);
195unsigned char aarch64_get_qualifier_nelem (aarch64_opnd_qualifier_t);
196aarch64_insn aarch64_get_qualifier_standard_value (aarch64_opnd_qualifier_t);
197int aarch64_find_best_match (const aarch64_inst *,
198			     const aarch64_opnd_qualifier_seq_t *,
199			     int, aarch64_opnd_qualifier_t *);
200
201static inline void
202reset_operand_qualifier (aarch64_inst *inst, int idx)
203{
204  assert (idx >=0 && idx < aarch64_num_of_operands (inst->opcode));
205  inst->operands[idx].qualifier = AARCH64_OPND_QLF_NIL;
206}
207
208/* Inline functions operating on instruction bit-field(s).  */
209
210/* Generate a mask that has WIDTH number of consecutive 1s.  */
211
212static inline aarch64_insn
213gen_mask (int width)
214{
215  return ((aarch64_insn) 1 << width) - 1;
216}
217
218/* LSB_REL is the relative location of the lsb in the sub field, starting from 0.  */
219static inline int
220gen_sub_field (enum aarch64_field_kind kind, int lsb_rel, int width, aarch64_field *ret)
221{
222  const aarch64_field *field = &fields[kind];
223  if (lsb_rel < 0 || width <= 0 || lsb_rel + width > field->width)
224    return 0;
225  ret->lsb = field->lsb + lsb_rel;
226  ret->width = width;
227  return 1;
228}
229
230/* Insert VALUE into FIELD of CODE.  MASK can be zero or the base mask
231   of the opcode.  */
232
233static inline void
234insert_field_2 (const aarch64_field *field, aarch64_insn *code,
235		aarch64_insn value, aarch64_insn mask)
236{
237  assert (field->width < 32 && field->width >= 1 && field->lsb >= 0
238	  && field->lsb + field->width <= 32);
239  value &= gen_mask (field->width);
240  value <<= field->lsb;
241  /* In some opcodes, field can be part of the base opcode, e.g. the size
242     field in FADD.  The following helps avoid corrupt the base opcode.  */
243  value &= ~mask;
244  *code |= value;
245}
246
247/* Extract FIELD of CODE and return the value.  MASK can be zero or the base
248   mask of the opcode.  */
249
250static inline aarch64_insn
251extract_field_2 (const aarch64_field *field, aarch64_insn code,
252		 aarch64_insn mask)
253{
254  aarch64_insn value;
255  /* Clear any bit that is a part of the base opcode.  */
256  code &= ~mask;
257  value = (code >> field->lsb) & gen_mask (field->width);
258  return value;
259}
260
261/* Insert VALUE into field KIND of CODE.  MASK can be zero or the base mask
262   of the opcode.  */
263
264static inline void
265insert_field (enum aarch64_field_kind kind, aarch64_insn *code,
266	      aarch64_insn value, aarch64_insn mask)
267{
268  insert_field_2 (&fields[kind], code, value, mask);
269}
270
271/* Extract field KIND of CODE and return the value.  MASK can be zero or the
272   base mask of the opcode.  */
273
274static inline aarch64_insn
275extract_field (enum aarch64_field_kind kind, aarch64_insn code,
276	       aarch64_insn mask)
277{
278  return extract_field_2 (&fields[kind], code, mask);
279}
280
281/* Inline functions selecting operand to do the encoding/decoding for a
282   certain instruction bit-field.  */
283
284/* Select the operand to do the encoding/decoding of the 'sf' field.
285   The heuristic-based rule is that the result operand is respected more.  */
286
287static inline int
288select_operand_for_sf_field_coding (const aarch64_opcode *opcode)
289{
290  int idx = -1;
291  if (aarch64_get_operand_class (opcode->operands[0])
292      == AARCH64_OPND_CLASS_INT_REG)
293    /* normal case.  */
294    idx = 0;
295  else if (aarch64_get_operand_class (opcode->operands[1])
296	   == AARCH64_OPND_CLASS_INT_REG)
297    /* e.g. float2fix.  */
298    idx = 1;
299  else
300    { assert (0); abort (); }
301  return idx;
302}
303
304/* Select the operand to do the encoding/decoding of the 'type' field in
305   the floating-point instructions.
306   The heuristic-based rule is that the source operand is respected more.  */
307
308static inline int
309select_operand_for_fptype_field_coding (const aarch64_opcode *opcode)
310{
311  int idx;
312  if (aarch64_get_operand_class (opcode->operands[1])
313      == AARCH64_OPND_CLASS_FP_REG)
314    /* normal case.  */
315    idx = 1;
316  else if (aarch64_get_operand_class (opcode->operands[0])
317	   == AARCH64_OPND_CLASS_FP_REG)
318    /* e.g. float2fix.  */
319    idx = 0;
320  else
321    { assert (0); abort (); }
322  return idx;
323}
324
325/* Select the operand to do the encoding/decoding of the 'size' field in
326   the AdvSIMD scalar instructions.
327   The heuristic-based rule is that the destination operand is respected
328   more.  */
329
330static inline int
331select_operand_for_scalar_size_field_coding (const aarch64_opcode *opcode)
332{
333  int src_size = 0, dst_size = 0;
334  if (aarch64_get_operand_class (opcode->operands[0])
335      == AARCH64_OPND_CLASS_SISD_REG)
336    dst_size = aarch64_get_qualifier_esize (opcode->qualifiers_list[0][0]);
337  if (aarch64_get_operand_class (opcode->operands[1])
338      == AARCH64_OPND_CLASS_SISD_REG)
339    src_size = aarch64_get_qualifier_esize (opcode->qualifiers_list[0][1]);
340  if (src_size == dst_size && src_size == 0)
341    { assert (0); abort (); }
342  /* When the result is not a sisd register or it is a long operantion.  */
343  if (dst_size == 0 || dst_size == src_size << 1)
344    return 1;
345  else
346    return 0;
347}
348
349/* Select the operand to do the encoding/decoding of the 'size:Q' fields in
350   the AdvSIMD instructions.  */
351
352int aarch64_select_operand_for_sizeq_field_coding (const aarch64_opcode *);
353
354/* Miscellaneous.  */
355
356aarch64_insn aarch64_get_operand_modifier_value (enum aarch64_modifier_kind);
357enum aarch64_modifier_kind
358aarch64_get_operand_modifier_from_value (aarch64_insn, bfd_boolean);
359
360
361bfd_boolean aarch64_wide_constant_p (int64_t, int, unsigned int *);
362bfd_boolean aarch64_logical_immediate_p (uint64_t, int, aarch64_insn *);
363int aarch64_shrink_expanded_imm8 (uint64_t);
364
365/* Copy the content of INST->OPERANDS[SRC] to INST->OPERANDS[DST].  */
366static inline void
367copy_operand_info (aarch64_inst *inst, int dst, int src)
368{
369  assert (dst >= 0 && src >= 0 && dst < AARCH64_MAX_OPND_NUM
370	  && src < AARCH64_MAX_OPND_NUM);
371  memcpy (&inst->operands[dst], &inst->operands[src],
372	  sizeof (aarch64_opnd_info));
373  inst->operands[dst].idx = dst;
374}
375
376/* A primitive log caculator.  */
377
378static inline unsigned int
379get_logsz (unsigned int size)
380{
381  const unsigned char ls[16] =
382    {0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4};
383  if (size > 16)
384    {
385      assert (0);
386      return -1;
387    }
388  assert (ls[size - 1] != (unsigned char)-1);
389  return ls[size - 1];
390}
391
392#endif /* OPCODES_AARCH64_OPC_H */
393