x86: Initialize broadcast_op.bytes to 0
[external/binutils.git] / gas / config / tc-i386.c
index 8768d68..9e9c676 100644 (file)
@@ -230,6 +230,9 @@ struct Broadcast_Operation
 
   /* Index of broadcasted operand.  */
   int operand;
+
+  /* Number of bytes to broadcast.  */
+  int bytes;
 };
 
 static struct Broadcast_Operation broadcast_op;
@@ -3362,12 +3365,12 @@ build_vex_prefix (const insn_template *t)
     vector_length = 1;
   else
     {
-      int op;
+      unsigned int op;
 
       /* Determine vector length from the last multi-length vector
         operand.  */
       vector_length = 0;
-      for (op = t->operands - 1; op >= 0; op--)
+      for (op = t->operands; op--;)
        if (t->operand_types[op].bitfield.xmmword
            && t->operand_types[op].bitfield.ymmword
            && i.types[op].bitfield.ymmword)
@@ -3612,12 +3615,12 @@ build_evex_prefix (void)
       if (!i.tm.opcode_modifier.evex
          || i.tm.opcode_modifier.evex == EVEXDYN)
        {
-         int op;
+         unsigned int op;
 
          /* Determine vector length from the last multi-length vector
             operand.  */
          vec_length = 0;
-         for (op = i.operands - 1; op >= 0; op--)
+         for (op = i.operands; op--;)
            if (i.tm.operand_types[op].bitfield.xmmword
                + i.tm.operand_types[op].bitfield.ymmword
                + i.tm.operand_types[op].bitfield.zmmword > 1)
@@ -3639,8 +3642,7 @@ build_evex_prefix (void)
                  }
                else if (i.broadcast && (int) op == i.broadcast->operand)
                  {
-                   switch ((i.tm.operand_types[op].bitfield.dword ? 4 : 8)
-                           * i.broadcast->type)
+                   switch (i.broadcast->bytes)
                      {
                        case 64:
                          i.tm.opcode_modifier.evex = EVEX512;
@@ -3658,7 +3660,7 @@ build_evex_prefix (void)
                  }
              }
 
-         if (op < 0)
+         if (op >= MAX_OPERANDS)
            abort ();
        }
 
@@ -5008,6 +5010,22 @@ optimize_disp (void)
       }
 }
 
+/* Return 1 if there is a match in broadcast bytes between operand
+   GIVEN and instruction template T.   */
+
+static INLINE int
+match_broadcast_size (const insn_template *t, unsigned int given)
+{
+  return ((t->opcode_modifier.broadcast == BYTE_BROADCAST
+          && i.types[given].bitfield.byte)
+         || (t->opcode_modifier.broadcast == WORD_BROADCAST
+             && i.types[given].bitfield.word)
+         || (t->opcode_modifier.broadcast == DWORD_BROADCAST
+             && i.types[given].bitfield.dword)
+         || (t->opcode_modifier.broadcast == QWORD_BROADCAST
+             && i.types[given].bitfield.qword));
+}
+
 /* Check if operands are valid for the instruction.  */
 
 static int
@@ -5126,23 +5144,29 @@ check_VecOperands (const insn_template *t)
       i386_operand_type type, overlap;
 
       /* Check if specified broadcast is supported in this instruction,
-        and it's applied to memory operand of DWORD or QWORD type.  */
+        and its broadcast bytes match the memory operand.  */
       op = i.broadcast->operand;
       if (!t->opcode_modifier.broadcast
          || !i.types[op].bitfield.mem
          || (!i.types[op].bitfield.unspecified
-             && (t->operand_types[op].bitfield.dword
-                 ? !i.types[op].bitfield.dword
-                 : !i.types[op].bitfield.qword)))
+             && !match_broadcast_size (t, op)))
        {
        bad_broadcast:
          i.error = unsupported_broadcast;
          return 1;
        }
 
+      i.broadcast->bytes = ((1 << (t->opcode_modifier.broadcast - 1))
+                           * i.broadcast->type);
       operand_type_set (&type, 0);
-      switch ((t->operand_types[op].bitfield.dword ? 4 : 8) * i.broadcast->type)
+      switch (i.broadcast->bytes)
        {
+       case 2:
+         type.bitfield.word = 1;
+         break;
+       case 4:
+         type.bitfield.dword = 1;
+         break;
        case 8:
          type.bitfield.qword = 1;
          break;
@@ -5189,9 +5213,7 @@ check_VecOperands (const insn_template *t)
          break;
       gas_assert (op < i.operands);
       /* Check size of the memory operand.  */
-      if (t->operand_types[op].bitfield.dword
-         ? i.types[op].bitfield.dword
-         : i.types[op].bitfield.qword)
+      if (match_broadcast_size (t, op))
        {
          i.error = broadcast_needed;
          return 1;
@@ -5245,7 +5267,7 @@ check_VecOperands (const insn_template *t)
       && i.disp_encoding != disp_encoding_32bit)
     {
       if (i.broadcast)
-       i.memshift = t->operand_types[op].bitfield.dword ? 2 : 3;
+       i.memshift = t->opcode_modifier.broadcast - 1;
       else if (t->opcode_modifier.disp8memshift != DISP8_SHIFT_VL)
        i.memshift = t->opcode_modifier.disp8memshift;
       else
@@ -5256,14 +5278,17 @@ check_VecOperands (const insn_template *t)
          for (op = 0; op < i.operands; op++)
            if (operand_type_check (i.types[op], anymem))
              {
-               if (t->operand_types[op].bitfield.xmmword
-                   + t->operand_types[op].bitfield.ymmword
-                   + t->operand_types[op].bitfield.zmmword <= 1)
+               if (t->opcode_modifier.evex == EVEXLIG)
+                 i.memshift = 2 + (i.suffix == QWORD_MNEM_SUFFIX);
+               else if (t->operand_types[op].bitfield.xmmword
+                        + t->operand_types[op].bitfield.ymmword
+                        + t->operand_types[op].bitfield.zmmword <= 1)
                  type = &t->operand_types[op];
                else if (!i.types[op].bitfield.unspecified)
                  type = &i.types[op];
              }
-           else if (i.types[op].bitfield.regsimd)
+           else if (i.types[op].bitfield.regsimd
+                    && t->opcode_modifier.evex != EVEXLIG)
              {
                if (i.types[op].bitfield.zmmword)
                  i.memshift = 6;
@@ -8609,6 +8634,7 @@ check_VecOperations (char *op_string, char *op_end)
 
              broadcast_op.type = bcst_type;
              broadcast_op.operand = this_operand;
+             broadcast_op.bytes = 0;
              i.broadcast = &broadcast_op;
            }
          /* Check masking operation.  */