/* aarch64-dis.c -- AArch64 disassembler.
- Copyright (C) 2009-2016 Free Software Foundation, Inc.
+ Copyright (C) 2009-2017 Free Software Foundation, Inc.
Contributed by ARM Ltd.
This file is part of the GNU opcodes library.
default:
return 0;
}
+
+ if (inst->opcode->op == OP_FCMLA_ELEM)
+ {
+ /* Complex operand takes two elements. */
+ if (info->reglane.index & 1)
+ return 0;
+ info->reglane.index /= 2;
+ }
}
return 1;
return 1;
}
+/* Decode rotate immediate for FCMLA <Vd>.<T>, <Vn>.<T>, <Vm>.<T>, #rotate. */
+int
+aarch64_ext_imm_rotate (const aarch64_operand *self, aarch64_opnd_info *info,
+ const aarch64_insn code,
+ const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+ uint64_t rot = extract_field (self->fields[0], code, 0);
+
+ switch (info->type)
+ {
+ case AARCH64_OPND_IMM_ROT1:
+ case AARCH64_OPND_IMM_ROT2:
+ /* rot value
+ 0 0
+ 1 90
+ 2 180
+ 3 270 */
+ assert (rot < 4U);
+ break;
+ case AARCH64_OPND_IMM_ROT3:
+ /* rot value
+ 0 90
+ 1 270 */
+ assert (rot < 2U);
+ rot = 2 * rot + 1;
+ break;
+ default:
+ assert (0);
+ return 0;
+ }
+ info->imm.value = rot * 90;
+ return 1;
+}
+
/* Decode scale for e.g. SCVTF <Dd>, <Wn>, #<fbits>. */
int
aarch64_ext_fbits (const aarch64_operand *self ATTRIBUTE_UNUSED,
switch (simd_size)
{
case 2: imm = (imm << 2) | imm;
+ /* Fall through. */
case 4: imm = (imm << 4) | imm;
+ /* Fall through. */
case 8: imm = (imm << 8) | imm;
+ /* Fall through. */
case 16: imm = (imm << 16) | imm;
+ /* Fall through. */
case 32: imm = (imm << 32) | imm;
+ /* Fall through. */
case 64: break;
default: assert (0); return 0;
}
return 1;
}
+/* Decode the address operand for e.g. LDRAA <Xt>, [<Xn|SP>{, #<simm>}]. */
+int
+aarch64_ext_addr_simm10 (const aarch64_operand *self, aarch64_opnd_info *info,
+ aarch64_insn code,
+ const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+ aarch64_insn imm;
+
+ info->qualifier = get_expected_qualifier (inst, info->idx);
+ /* Rn */
+ info->addr.base_regno = extract_field (self->fields[0], code, 0);
+ /* simm10 */
+ imm = extract_fields (code, 0, 2, self->fields[1], self->fields[2]);
+ info->addr.offset.imm = sign_extend (imm, 9) << 3;
+ if (extract_field (self->fields[3], code, 0) == 1) {
+ info->addr.writeback = 1;
+ info->addr.preind = 1;
+ }
+ return 1;
+}
+
/* Decode the address operand for e.g.
LD1 {<Vt>.<T>, <Vt2>.<T>, <Vt3>.<T>}, [<Xn|SP>], <Xm|#<amount>>. */
int
aarch64_opnd_info *info, aarch64_insn code,
const aarch64_inst *inst ATTRIBUTE_UNUSED)
{
- int index;
+ int index_regno;
- index = extract_field (self->fields[1], code, 0);
- if (index == 31 && (self->flags & OPD_F_NO_ZR) != 0)
+ index_regno = extract_field (self->fields[1], code, 0);
+ if (index_regno == 31 && (self->flags & OPD_F_NO_ZR) != 0)
return 0;
info->addr.base_regno = extract_field (self->fields[0], code, 0);
- info->addr.offset.regno = index;
+ info->addr.offset.regno = index_regno;
info->addr.offset.is_reg = TRUE;
info->addr.writeback = FALSE;
info->addr.preind = TRUE;
}
}
+/* Set NAME to a copy of INST's mnemonic with the "." suffix removed. */
+
+static void
+remove_dot_suffix (char *name, const aarch64_inst *inst)
+{
+ char *ptr;
+ size_t len;
+
+ ptr = strchr (inst->opcode->name, '.');
+ assert (ptr && inst->cond);
+ len = ptr - inst->opcode->name;
+ assert (len < 8);
+ strncpy (name, inst->opcode->name, len);
+ name[len] = '\0';
+}
+
/* Print the instruction mnemonic name. */
static void
/* For instructions that are truly conditionally executed, e.g. b.cond,
prepare the full mnemonic name with the corresponding condition
suffix. */
- char name[8], *ptr;
- size_t len;
-
- ptr = strchr (inst->opcode->name, '.');
- assert (ptr && inst->cond);
- len = ptr - inst->opcode->name;
- assert (len < 8);
- strncpy (name, inst->opcode->name, len);
- name [len] = '\0';
+ char name[8];
+
+ remove_dot_suffix (name, inst);
(*info->fprintf_func) (info->stream, "%s.%s", name, inst->cond->names[0]);
}
else
(*info->fprintf_func) (info->stream, "%s", inst->opcode->name);
}
+/* Decide whether we need to print a comment after the operands of
+ instruction INST. */
+
+static void
+print_comment (const aarch64_inst *inst, struct disassemble_info *info)
+{
+ if (inst->opcode->flags & F_COND)
+ {
+ char name[8];
+ unsigned int i, num_conds;
+
+ remove_dot_suffix (name, inst);
+ num_conds = ARRAY_SIZE (inst->cond->names);
+ for (i = 1; i < num_conds && inst->cond->names[i]; ++i)
+ (*info->fprintf_func) (info->stream, "%s %s.%s",
+ i == 1 ? " //" : ",",
+ name, inst->cond->names[i]);
+ }
+}
+
/* Print the instruction according to *INST. */
static void
{
print_mnemonic_name (inst, info);
print_operands (pc, inst->opcode, inst->operands, info);
+ print_comment (inst, info);
}
/* Entry-point of the instruction disassembler and printer. */