[AArch64][SVE 15/32] Add {insert,extract}_all_fields helpers
[deliverable/binutils-gdb.git] / opcodes / aarch64-asm.c
index 96396e87d48080ee9741508508d968a48fde1f9c..3b0a38373fcb8416a5ca942fffa82ea5e52702cb 100644 (file)
@@ -1,5 +1,5 @@
 /* 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.
@@ -20,6 +20,7 @@
 
 #include "sysdep.h"
 #include <stdarg.h>
+#include "libiberty.h"
 #include "aarch64-asm.h"
 
 /* Utilities.  */
@@ -31,7 +32,7 @@
    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
@@ -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 <Qt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}].  */
 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 <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:
@@ -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;
This page took 0.033203 seconds and 4 git commands to generate.