X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=opcodes%2Faarch64-asm.c;h=3b0a38373fcb8416a5ca942fffa82ea5e52702cb;hb=b5464a6825e40e6d8ab2dd86c7ff5d65bedd64d4;hp=5b5790f79878a2f9af09b8c607542e0f39ca86de;hpb=4b95cf5c0c75d6efc1b2f96af72317aecca079f1;p=binutils-gdb.git diff --git a/opcodes/aarch64-asm.c b/opcodes/aarch64-asm.c index 5b5790f7987..3b0a38373fc 100644 --- a/opcodes/aarch64-asm.c +++ b/opcodes/aarch64-asm.c @@ -1,5 +1,5 @@ /* aarch64-asm.c -- AArch64 assembler support. - Copyright (C) 2012-2014 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. @@ -20,6 +20,7 @@ #include "sysdep.h" #include +#include "libiberty.h" #include "aarch64-asm.h" /* Utilities. */ @@ -55,6 +56,25 @@ insert_fields (aarch64_insn *code, aarch64_insn value, aarch64_insn mask, ...) 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. */ @@ -318,17 +338,11 @@ aarch64_ins_imm (const aarch64_operand *self, const aarch64_opnd_info *info, 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; } @@ -436,11 +450,11 @@ aarch64_ins_limm (const aarch64_operand *self, const aarch64_opnd_info *info, { 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); @@ -667,6 +681,19 @@ aarch64_ins_prfop (const aarch64_operand *self ATTRIBUTE_UNUSED, 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 , [, {, {}}]. */ const char * @@ -856,6 +883,14 @@ do_special_encoding (struct aarch64_inst *inst) 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) @@ -1030,6 +1065,37 @@ convert_bfi_to_bfm (aarch64_inst *inst) } } +/* The instruction written: + BFC , #, # + is equivalent to: + BFM , XZR, #((64-)&0x3f), #(-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 , , # is equivalent to: @@ -1163,6 +1229,9 @@ convert_to_real (aarch64_inst *inst, const aarch64_opcode *real) 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;