OLD | NEW |
(Empty) | |
| 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. */ |
| 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_H, |
| 88 FLD_L, |
| 89 FLD_M, |
| 90 FLD_b5, |
| 91 FLD_b40, |
| 92 FLD_scale, |
| 93 }; |
| 94 |
| 95 /* Field description. */ |
| 96 struct aarch64_field |
| 97 { |
| 98 int lsb; |
| 99 int width; |
| 100 }; |
| 101 |
| 102 typedef struct aarch64_field aarch64_field; |
| 103 |
| 104 extern const aarch64_field fields[]; |
| 105 |
| 106 /* Operand description. */ |
| 107 |
| 108 struct 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 |
| 126 typedef struct aarch64_operand aarch64_operand; |
| 127 |
| 128 extern 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 |
| 140 static inline bfd_boolean |
| 141 operand_has_inserter (const aarch64_operand *operand) |
| 142 { |
| 143 return (operand->flags & OPD_F_HAS_INSERTER) ? TRUE : FALSE; |
| 144 } |
| 145 |
| 146 static inline bfd_boolean |
| 147 operand_has_extractor (const aarch64_operand *operand) |
| 148 { |
| 149 return (operand->flags & OPD_F_HAS_EXTRACTOR) ? TRUE : FALSE; |
| 150 } |
| 151 |
| 152 static inline bfd_boolean |
| 153 operand_need_sign_extension (const aarch64_operand *operand) |
| 154 { |
| 155 return (operand->flags & OPD_F_SEXT) ? TRUE : FALSE; |
| 156 } |
| 157 |
| 158 static inline bfd_boolean |
| 159 operand_need_shift_by_two (const aarch64_operand *operand) |
| 160 { |
| 161 return (operand->flags & OPD_F_SHIFT_BY_2) ? TRUE : FALSE; |
| 162 } |
| 163 |
| 164 static inline bfd_boolean |
| 165 operand_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. */ |
| 171 static inline unsigned |
| 172 get_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 |
| 182 static inline const aarch64_operand * |
| 183 get_operand_from_code (enum aarch64_opnd code) |
| 184 { |
| 185 return aarch64_operands + code; |
| 186 } |
| 187 |
| 188 /* Operand qualifier and operand constraint checking. */ |
| 189 |
| 190 int aarch64_match_operands_constraint (aarch64_inst *, |
| 191 aarch64_operand_error *); |
| 192 |
| 193 /* Operand qualifier related functions. */ |
| 194 const char* aarch64_get_qualifier_name (aarch64_opnd_qualifier_t); |
| 195 unsigned char aarch64_get_qualifier_nelem (aarch64_opnd_qualifier_t); |
| 196 aarch64_insn aarch64_get_qualifier_standard_value (aarch64_opnd_qualifier_t); |
| 197 int aarch64_find_best_match (const aarch64_inst *, |
| 198 const aarch64_opnd_qualifier_seq_t *, |
| 199 int, aarch64_opnd_qualifier_t *); |
| 200 |
| 201 static inline void |
| 202 reset_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 |
| 212 static inline aarch64_insn |
| 213 gen_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
. */ |
| 219 static inline int |
| 220 gen_sub_field (enum aarch64_field_kind kind, int lsb_rel, int width, aarch64_fie
ld *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 |
| 233 static inline void |
| 234 insert_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 |
| 250 static inline aarch64_insn |
| 251 extract_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 |
| 264 static inline void |
| 265 insert_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 |
| 274 static inline aarch64_insn |
| 275 extract_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 |
| 287 static inline int |
| 288 select_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 |
| 308 static inline int |
| 309 select_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 |
| 330 static inline int |
| 331 select_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 |
| 352 int aarch64_select_operand_for_sizeq_field_coding (const aarch64_opcode *); |
| 353 |
| 354 /* Miscellaneous. */ |
| 355 |
| 356 aarch64_insn aarch64_get_operand_modifier_value (enum aarch64_modifier_kind); |
| 357 enum aarch64_modifier_kind |
| 358 aarch64_get_operand_modifier_from_value (aarch64_insn, bfd_boolean); |
| 359 |
| 360 |
| 361 bfd_boolean aarch64_wide_constant_p (int64_t, int, unsigned int *); |
| 362 bfd_boolean aarch64_logical_immediate_p (uint64_t, int, aarch64_insn *); |
| 363 int aarch64_shrink_expanded_imm8 (uint64_t); |
| 364 |
| 365 /* Copy the content of INST->OPERANDS[SRC] to INST->OPERANDS[DST]. */ |
| 366 static inline void |
| 367 copy_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 |
| 378 static inline unsigned int |
| 379 get_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 */ |
OLD | NEW |