/* aarch64-asm.c -- AArch64 assembler support.
- Copyright 2012, 2013 Free Software Foundation, Inc.
+ Copyright (C) 2012-2016 Free Software Foundation, Inc.
Contributed by ARM Ltd.
This file is part of the GNU opcodes library.
#include "sysdep.h"
#include <stdarg.h>
+#include "libiberty.h"
#include "aarch64-asm.h"
/* Utilities. */
N.B. the fields are required to be in such an order than the least signficant
field for VALUE comes the first, e.g. the <index> in
SQDMLAL <Va><d>, <Vb><n>, <Vm>.<Ts>[<index>]
- is encoded in H:L:M in some cases, the the fields H:L:M should be passed in
+ is encoded in H:L:M in some cases, the fields H:L:M should be passed in
the order of M, L, H. */
static inline void
va_end (va);
}
+/* Insert a raw field value VALUE into all fields in SELF->fields.
+ The least significant bit goes in the final field. */
+
+static void
+insert_all_fields (const aarch64_operand *self, aarch64_insn *code,
+ aarch64_insn value)
+{
+ unsigned int i;
+ enum aarch64_field_kind kind;
+
+ for (i = ARRAY_SIZE (self->fields); i-- > 0; )
+ if (self->fields[i] != FLD_NIL)
+ {
+ kind = self->fields[i];
+ insert_field (kind, code, value, 0);
+ value >>= fields[kind].width;
+ }
+}
+
/* Operand inserters. */
/* Insert register number. */
const aarch64_inst *inst ATTRIBUTE_UNUSED)
{
int64_t imm;
- /* Maximum of two fields to insert. */
- assert (self->fields[2] == FLD_NIL);
imm = info->imm.value;
if (operand_need_shift_by_two (self))
imm >>= 2;
- if (self->fields[1] == FLD_NIL)
- insert_field (self->fields[0], code, imm, 0);
- else
- /* e.g. TBZ b5:b40. */
- insert_fields (code, imm, 0, 2, self->fields[1], self->fields[0]);
+ insert_all_fields (self, code, imm);
return NULL;
}
{
aarch64_insn value;
uint64_t imm = info->imm.value;
- int is32 = aarch64_get_qualifier_esize (inst->operands[0].qualifier) == 4;
+ int esize = aarch64_get_qualifier_esize (inst->operands[0].qualifier);
if (inst->opcode->op == OP_BIC)
imm = ~imm;
- if (aarch64_logical_immediate_p (imm, is32, &value) == FALSE)
+ if (aarch64_logical_immediate_p (imm, esize, &value) == FALSE)
/* The constraint check should have guaranteed this wouldn't happen. */
assert (0);
return NULL;
}
+/* Encode the hint number for instructions that alias HINT but take an
+ operand. */
+
+const char *
+aarch64_ins_hint (const aarch64_operand *self ATTRIBUTE_UNUSED,
+ const aarch64_opnd_info *info, aarch64_insn *code,
+ const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+ /* CRm:op2. */
+ insert_fields (code, info->hint_option->value, 0, 2, FLD_op2, FLD_CRm);
+ return NULL;
+}
+
/* Encode the extended register operand for e.g.
STR <Qt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]. */
const char *
if (inst->opcode->flags & F_N)
insert_field (FLD_N, &inst->value, value, inst->opcode->mask);
}
+ if (inst->opcode->flags & F_LSE_SZ)
+ {
+ idx = select_operand_for_sf_field_coding (inst->opcode);
+ value = (inst->operands[idx].qualifier == AARCH64_OPND_QLF_X
+ || inst->operands[idx].qualifier == AARCH64_OPND_QLF_SP)
+ ? 1 : 0;
+ insert_field (FLD_lse_sz, &inst->value, value, 0);
+ }
if (inst->opcode->flags & F_SIZEQ)
encode_sizeq (inst);
if (inst->opcode->flags & F_FPTYPE)
}
}
+/* The instruction written:
+ BFC <Xd>, #<lsb>, #<width>
+ is equivalent to:
+ BFM <Xd>, XZR, #((64-<lsb>)&0x3f), #(<width>-1). */
+
+static void
+convert_bfc_to_bfm (aarch64_inst *inst)
+{
+ int64_t lsb, width;
+
+ /* Insert XZR. */
+ copy_operand_info (inst, 3, 2);
+ copy_operand_info (inst, 2, 1);
+ copy_operand_info (inst, 2, 0);
+ inst->operands[1].reg.regno = 0x1f;
+
+ /* Convert the immedate operand. */
+ lsb = inst->operands[2].imm.value;
+ width = inst->operands[3].imm.value;
+ if (inst->operands[2].qualifier == AARCH64_OPND_QLF_imm_0_31)
+ {
+ inst->operands[2].imm.value = (32 - lsb) & 0x1f;
+ inst->operands[3].imm.value = width - 1;
+ }
+ else
+ {
+ inst->operands[2].imm.value = (64 - lsb) & 0x3f;
+ inst->operands[3].imm.value = width - 1;
+ }
+}
+
/* The instruction written:
LSL <Xd>, <Xn>, #<shift>
is equivalent to:
case OP_UBFIZ:
convert_bfi_to_bfm (inst);
break;
+ case OP_BFC:
+ convert_bfc_to_bfm (inst);
+ break;
case OP_MOV_V:
convert_mov_to_orr (inst);
break;