1 /* aarch64-opc.h -- Header file for aarch64-opc.c and aarch64-opc-2.c. 2 Copyright (C) 2012-2014 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. */ 29 enum 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_lse_sz, 88 FLD_H, 89 FLD_L, 90 FLD_M, 91 FLD_b5, 92 FLD_b40, 93 FLD_scale, 94 }; 95 96 /* Field description. */ 97 struct aarch64_field 98 { 99 int lsb; 100 int width; 101 }; 102 103 typedef struct aarch64_field aarch64_field; 104 105 extern const aarch64_field fields[]; 106 107 /* Operand description. */ 109 110 struct aarch64_operand 111 { 112 enum aarch64_operand_class op_class; 113 114 /* Name of the operand code; used mainly for the purpose of internal 115 debugging. */ 116 const char *name; 117 118 unsigned int flags; 119 120 /* The associated instruction bit-fields; no operand has more than 4 121 bit-fields */ 122 enum aarch64_field_kind fields[4]; 123 124 /* Brief description */ 125 const char *desc; 126 }; 127 128 typedef struct aarch64_operand aarch64_operand; 129 130 extern const aarch64_operand aarch64_operands[]; 131 132 /* Operand flags. */ 133 134 #define OPD_F_HAS_INSERTER 0x00000001 135 #define OPD_F_HAS_EXTRACTOR 0x00000002 136 #define OPD_F_SEXT 0x00000004 /* Require sign-extension. */ 137 #define OPD_F_SHIFT_BY_2 0x00000008 /* Need to left shift the field 138 value by 2 to get the value 139 of an immediate operand. */ 140 #define OPD_F_MAYBE_SP 0x00000010 /* May potentially be SP. */ 141 142 static inline bfd_boolean 143 operand_has_inserter (const aarch64_operand *operand) 144 { 145 return (operand->flags & OPD_F_HAS_INSERTER) ? TRUE : FALSE; 146 } 147 148 static inline bfd_boolean 149 operand_has_extractor (const aarch64_operand *operand) 150 { 151 return (operand->flags & OPD_F_HAS_EXTRACTOR) ? TRUE : FALSE; 152 } 153 154 static inline bfd_boolean 155 operand_need_sign_extension (const aarch64_operand *operand) 156 { 157 return (operand->flags & OPD_F_SEXT) ? TRUE : FALSE; 158 } 159 160 static inline bfd_boolean 161 operand_need_shift_by_two (const aarch64_operand *operand) 162 { 163 return (operand->flags & OPD_F_SHIFT_BY_2) ? TRUE : FALSE; 164 } 165 166 static inline bfd_boolean 167 operand_maybe_stack_pointer (const aarch64_operand *operand) 168 { 169 return (operand->flags & OPD_F_MAYBE_SP) ? TRUE : FALSE; 170 } 171 172 /* Return the total width of the operand *OPERAND. */ 173 static inline unsigned 174 get_operand_fields_width (const aarch64_operand *operand) 175 { 176 int i = 0; 177 unsigned width = 0; 178 while (operand->fields[i] != FLD_NIL) 179 width += fields[operand->fields[i++]].width; 180 assert (width > 0 && width < 32); 181 return width; 182 } 183 184 static inline const aarch64_operand * 185 get_operand_from_code (enum aarch64_opnd code) 186 { 187 return aarch64_operands + code; 188 } 189 190 /* Operand qualifier and operand constraint checking. */ 192 193 int aarch64_match_operands_constraint (aarch64_inst *, 194 aarch64_operand_error *); 195 196 /* Operand qualifier related functions. */ 197 const char* aarch64_get_qualifier_name (aarch64_opnd_qualifier_t); 198 unsigned char aarch64_get_qualifier_nelem (aarch64_opnd_qualifier_t); 199 aarch64_insn aarch64_get_qualifier_standard_value (aarch64_opnd_qualifier_t); 200 int aarch64_find_best_match (const aarch64_inst *, 201 const aarch64_opnd_qualifier_seq_t *, 202 int, aarch64_opnd_qualifier_t *); 203 204 static inline void 205 reset_operand_qualifier (aarch64_inst *inst, int idx) 206 { 207 assert (idx >=0 && idx < aarch64_num_of_operands (inst->opcode)); 208 inst->operands[idx].qualifier = AARCH64_OPND_QLF_NIL; 209 } 210 211 /* Inline functions operating on instruction bit-field(s). */ 213 214 /* Generate a mask that has WIDTH number of consecutive 1s. */ 215 216 static inline aarch64_insn 217 gen_mask (int width) 218 { 219 return ((aarch64_insn) 1 << width) - 1; 220 } 221 222 /* LSB_REL is the relative location of the lsb in the sub field, starting from 0. */ 223 static inline int 224 gen_sub_field (enum aarch64_field_kind kind, int lsb_rel, int width, aarch64_field *ret) 225 { 226 const aarch64_field *field = &fields[kind]; 227 if (lsb_rel < 0 || width <= 0 || lsb_rel + width > field->width) 228 return 0; 229 ret->lsb = field->lsb + lsb_rel; 230 ret->width = width; 231 return 1; 232 } 233 234 /* Insert VALUE into FIELD of CODE. MASK can be zero or the base mask 235 of the opcode. */ 236 237 static inline void 238 insert_field_2 (const aarch64_field *field, aarch64_insn *code, 239 aarch64_insn value, aarch64_insn mask) 240 { 241 assert (field->width < 32 && field->width >= 1 && field->lsb >= 0 242 && field->lsb + field->width <= 32); 243 value &= gen_mask (field->width); 244 value <<= field->lsb; 245 /* In some opcodes, field can be part of the base opcode, e.g. the size 246 field in FADD. The following helps avoid corrupt the base opcode. */ 247 value &= ~mask; 248 *code |= value; 249 } 250 251 /* Extract FIELD of CODE and return the value. MASK can be zero or the base 252 mask of the opcode. */ 253 254 static inline aarch64_insn 255 extract_field_2 (const aarch64_field *field, aarch64_insn code, 256 aarch64_insn mask) 257 { 258 aarch64_insn value; 259 /* Clear any bit that is a part of the base opcode. */ 260 code &= ~mask; 261 value = (code >> field->lsb) & gen_mask (field->width); 262 return value; 263 } 264 265 /* Insert VALUE into field KIND of CODE. MASK can be zero or the base mask 266 of the opcode. */ 267 268 static inline void 269 insert_field (enum aarch64_field_kind kind, aarch64_insn *code, 270 aarch64_insn value, aarch64_insn mask) 271 { 272 insert_field_2 (&fields[kind], code, value, mask); 273 } 274 275 /* Extract field KIND of CODE and return the value. MASK can be zero or the 276 base mask of the opcode. */ 277 278 static inline aarch64_insn 279 extract_field (enum aarch64_field_kind kind, aarch64_insn code, 280 aarch64_insn mask) 281 { 282 return extract_field_2 (&fields[kind], code, mask); 283 } 284 285 /* Inline functions selecting operand to do the encoding/decoding for a 287 certain instruction bit-field. */ 288 289 /* Select the operand to do the encoding/decoding of the 'sf' field. 290 The heuristic-based rule is that the result operand is respected more. */ 291 292 static inline int 293 select_operand_for_sf_field_coding (const aarch64_opcode *opcode) 294 { 295 int idx = -1; 296 if (aarch64_get_operand_class (opcode->operands[0]) 297 == AARCH64_OPND_CLASS_INT_REG) 298 /* normal case. */ 299 idx = 0; 300 else if (aarch64_get_operand_class (opcode->operands[1]) 301 == AARCH64_OPND_CLASS_INT_REG) 302 /* e.g. float2fix. */ 303 idx = 1; 304 else 305 { assert (0); abort (); } 306 return idx; 307 } 308 309 /* Select the operand to do the encoding/decoding of the 'type' field in 310 the floating-point instructions. 311 The heuristic-based rule is that the source operand is respected more. */ 312 313 static inline int 314 select_operand_for_fptype_field_coding (const aarch64_opcode *opcode) 315 { 316 int idx; 317 if (aarch64_get_operand_class (opcode->operands[1]) 318 == AARCH64_OPND_CLASS_FP_REG) 319 /* normal case. */ 320 idx = 1; 321 else if (aarch64_get_operand_class (opcode->operands[0]) 322 == AARCH64_OPND_CLASS_FP_REG) 323 /* e.g. float2fix. */ 324 idx = 0; 325 else 326 { assert (0); abort (); } 327 return idx; 328 } 329 330 /* Select the operand to do the encoding/decoding of the 'size' field in 331 the AdvSIMD scalar instructions. 332 The heuristic-based rule is that the destination operand is respected 333 more. */ 334 335 static inline int 336 select_operand_for_scalar_size_field_coding (const aarch64_opcode *opcode) 337 { 338 int src_size = 0, dst_size = 0; 339 if (aarch64_get_operand_class (opcode->operands[0]) 340 == AARCH64_OPND_CLASS_SISD_REG) 341 dst_size = aarch64_get_qualifier_esize (opcode->qualifiers_list[0][0]); 342 if (aarch64_get_operand_class (opcode->operands[1]) 343 == AARCH64_OPND_CLASS_SISD_REG) 344 src_size = aarch64_get_qualifier_esize (opcode->qualifiers_list[0][1]); 345 if (src_size == dst_size && src_size == 0) 346 { assert (0); abort (); } 347 /* When the result is not a sisd register or it is a long operantion. */ 348 if (dst_size == 0 || dst_size == src_size << 1) 349 return 1; 350 else 351 return 0; 352 } 353 354 /* Select the operand to do the encoding/decoding of the 'size:Q' fields in 355 the AdvSIMD instructions. */ 356 357 int aarch64_select_operand_for_sizeq_field_coding (const aarch64_opcode *); 358 359 /* Miscellaneous. */ 361 362 aarch64_insn aarch64_get_operand_modifier_value (enum aarch64_modifier_kind); 363 enum aarch64_modifier_kind 364 aarch64_get_operand_modifier_from_value (aarch64_insn, bfd_boolean); 365 366 367 bfd_boolean aarch64_wide_constant_p (int64_t, int, unsigned int *); 368 bfd_boolean aarch64_logical_immediate_p (uint64_t, int, aarch64_insn *); 369 int aarch64_shrink_expanded_imm8 (uint64_t); 370 371 /* Copy the content of INST->OPERANDS[SRC] to INST->OPERANDS[DST]. */ 372 static inline void 373 copy_operand_info (aarch64_inst *inst, int dst, int src) 374 { 375 assert (dst >= 0 && src >= 0 && dst < AARCH64_MAX_OPND_NUM 376 && src < AARCH64_MAX_OPND_NUM); 377 memcpy (&inst->operands[dst], &inst->operands[src], 378 sizeof (aarch64_opnd_info)); 379 inst->operands[dst].idx = dst; 380 } 381 382 /* A primitive log caculator. */ 383 384 static inline unsigned int 385 get_logsz (unsigned int size) 386 { 387 const unsigned char ls[16] = 388 {0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4}; 389 if (size > 16) 390 { 391 assert (0); 392 return -1; 393 } 394 assert (ls[size - 1] != (unsigned char)-1); 395 return ls[size - 1]; 396 } 397 398 #endif /* OPCODES_AARCH64_OPC_H */ 399