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