i386: Add -mbranches-within-32B-boundaries
[deliverable/binutils-gdb.git] / opcodes / aarch64-asm.c
index 67c9b6e5d904b5c7adfa14276837fd2c4a5a09d7..3dcd84a5cb72af95f93223df129f7d9a5370c626 100644 (file)
@@ -1,5 +1,5 @@
 /* aarch64-asm.c -- AArch64 assembler support.
-   Copyright (C) 2012-2018 Free Software Foundation, Inc.
+   Copyright (C) 2012-2019 Free Software Foundation, Inc.
    Contributed by ARM Ltd.
 
    This file is part of the GNU opcodes library.
@@ -22,6 +22,7 @@
 #include <stdarg.h>
 #include "libiberty.h"
 #include "aarch64-asm.h"
+#include "opintl.h"
 
 /* Utilities.  */
 
@@ -129,6 +130,7 @@ aarch64_ins_reglane (const aarch64_operand *self, const aarch64_opnd_info *info,
       switch (info->qualifier)
        {
        case AARCH64_OPND_QLF_S_4B:
+       case AARCH64_OPND_QLF_S_2H:
          /* L:H */
          assert (reglane_index < 4);
          insert_fields (code, reglane_index, 0, 2, FLD_L, FLD_H);
@@ -380,6 +382,8 @@ aarch64_ins_imm (const aarch64_operand *self, const aarch64_opnd_info *info,
   imm = info->imm.value;
   if (operand_need_shift_by_two (self))
     imm >>= 2;
+  if (operand_need_shift_by_four (self))
+    imm >>= 4;
   insert_all_fields (self, code, imm);
   return TRUE;
 }
@@ -687,7 +691,8 @@ aarch64_ins_addr_simm (const aarch64_operand *self,
   insert_field (FLD_Rn, code, info->addr.base_regno, 0);
   /* simm (imm9 or imm7) */
   imm = info->addr.offset.imm;
-  if (self->fields[0] == FLD_imm7)
+  if (self->fields[0] == FLD_imm7
+     || info->qualifier == AARCH64_OPND_QLF_imm_tag)
     /* scaled immediate in ld/st pair instructions..  */
     imm >>= get_logsz (aarch64_get_qualifier_esize (info->qualifier));
   insert_field (self->fields[0], code, imm, 0);
@@ -785,6 +790,36 @@ aarch64_ins_sysreg (const aarch64_operand *self ATTRIBUTE_UNUSED,
                    const aarch64_inst *inst,
                    aarch64_operand_error *detail ATTRIBUTE_UNUSED)
 {
+   /* If a system instruction check if we have any restrictions on which
+      registers it can use.  */
+   if (inst->opcode->iclass == ic_system)
+     {
+        uint64_t opcode_flags
+         = inst->opcode->flags & (F_SYS_READ | F_SYS_WRITE);
+       uint32_t sysreg_flags
+         = info->sysreg.flags & (F_REG_READ | F_REG_WRITE);
+
+        /* Check to see if it's read-only, else check if it's write only.
+          if it's both or unspecified don't care.  */
+       if (opcode_flags == F_SYS_READ
+           && sysreg_flags
+           && sysreg_flags != F_REG_READ)
+         {
+               detail->kind = AARCH64_OPDE_SYNTAX_ERROR;
+               detail->error = _("specified register cannot be read from");
+               detail->index = info->idx;
+               detail->non_fatal = TRUE;
+         }
+       else if (opcode_flags == F_SYS_WRITE
+                && sysreg_flags
+                && sysreg_flags != F_REG_WRITE)
+         {
+               detail->kind = AARCH64_OPDE_SYNTAX_ERROR;
+               detail->error = _("specified register cannot be written to");
+               detail->index = info->idx;
+               detail->non_fatal = TRUE;
+         }
+     }
   /* op0:op1:CRn:CRm:op2 */
   insert_fields (code, info->sysreg.value, inst->opcode->mask, 5,
                 FLD_op2, FLD_CRm, FLD_CRn, FLD_op1, FLD_op0);
@@ -1207,8 +1242,9 @@ aarch64_ins_sve_shrimm (const aarch64_operand *self,
   const aarch64_opnd_info *prev_operand;
   unsigned int esize;
 
-  assert (info->idx > 0);
-  prev_operand = &inst->operands[info->idx - 1];
+  unsigned int opnd_backshift = get_operand_specific_data (self);
+  assert (info->idx >= (int)opnd_backshift);
+  prev_operand = &inst->operands[info->idx - opnd_backshift];
   esize = aarch64_get_qualifier_esize (prev_operand->qualifier);
   insert_all_fields (self, code, 16 * esize - info->imm.value);
   return TRUE;
@@ -1579,6 +1615,7 @@ do_special_encoding (struct aarch64_inst *inst)
 static void
 aarch64_encode_variant_using_iclass (struct aarch64_inst *inst)
 {
+  int variant = 0;
   switch (inst->opcode->iclass)
     {
     case sve_cpy:
@@ -1589,6 +1626,8 @@ aarch64_encode_variant_using_iclass (struct aarch64_inst *inst)
     case sve_index:
     case sve_shift_pred:
     case sve_shift_unpred:
+    case sve_shift_tsz_hsd:
+    case sve_shift_tsz_bhsd:
       /* For indices and shift amounts, the variant is encoded as
         part of the immediate.  */
       break;
@@ -1621,10 +1660,33 @@ aarch64_encode_variant_using_iclass (struct aarch64_inst *inst)
       insert_field (FLD_size, &inst->value, aarch64_get_variant (inst) + 1, 0);
       break;
 
+    case sve_size_bh:
     case sve_size_sd:
       insert_field (FLD_SVE_sz, &inst->value, aarch64_get_variant (inst), 0);
       break;
 
+    case sve_size_sd2:
+      insert_field (FLD_SVE_sz2, &inst->value, aarch64_get_variant (inst), 0);
+      break;
+
+    case sve_size_hsd2:
+      insert_field (FLD_SVE_size, &inst->value,
+                   aarch64_get_variant (inst) + 1, 0);
+      break;
+
+    case sve_size_tsz_bhs:
+      insert_fields (&inst->value,
+                    (1 << aarch64_get_variant (inst)),
+                    0, 2, FLD_SVE_tszl_19, FLD_SVE_sz);
+      break;
+
+    case sve_size_13:
+      variant = aarch64_get_variant (inst) + 1;
+      if (variant == 2)
+         variant = 3;
+      insert_field (FLD_size, &inst->value, variant, 0);
+      break;
+
     default:
       break;
     }
@@ -1917,7 +1979,8 @@ bfd_boolean
 aarch64_opcode_encode (const aarch64_opcode *opcode,
                       const aarch64_inst *inst_ori, aarch64_insn *code,
                       aarch64_opnd_qualifier_t *qlf_seq,
-                      aarch64_operand_error *mismatch_detail)
+                      aarch64_operand_error *mismatch_detail,
+                      aarch64_instr_sequence* insn_sequence)
 {
   int i;
   const aarch64_opcode *aliased;
@@ -2004,6 +2067,38 @@ aarch64_opcode_encode (const aarch64_opcode *opcode,
      variant.  */
   aarch64_encode_variant_using_iclass (inst);
 
+  /* Run a verifier if the instruction has one set.  */
+  if (opcode->verifier)
+    {
+      enum err_type result = opcode->verifier (inst, *code, 0, TRUE,
+                                              mismatch_detail, insn_sequence);
+      switch (result)
+       {
+       case ERR_UND:
+       case ERR_UNP:
+       case ERR_NYI:
+         return FALSE;
+       default:
+         break;
+       }
+    }
+
+  /* Always run constrain verifiers, this is needed because constrains need to
+     maintain a global state.  Regardless if the instruction has the flag set
+     or not.  */
+  enum err_type result = verify_constraints (inst, *code, 0, TRUE,
+                                            mismatch_detail, insn_sequence);
+  switch (result)
+    {
+    case ERR_UND:
+    case ERR_UNP:
+    case ERR_NYI:
+      return FALSE;
+    default:
+      break;
+    }
+
+
 encoding_exit:
   DEBUG_TRACE ("exit with %s", opcode->name);
 
This page took 0.057126 seconds and 4 git commands to generate.