Improve gas error messages for invalid instructions.
[deliverable/binutils-gdb.git] / gas / config / tc-ia64.c
index df566e2f81803066fed276f834e0eef5f7e1d154..517d96c37167015054699dede229b355e9c53972 100644 (file)
@@ -124,6 +124,13 @@ enum dynreg_type
     DYNREG_NUM_TYPES
   };
 
+enum operand_match_result
+  {
+    OPERAND_MATCH,
+    OPERAND_OUT_OF_RANGE,
+    OPERAND_MISMATCH
+  };
+
 /* On the ia64, we can't know the address of a text label until the
    instructions are packed into a bundle.  To handle this, we keep
    track of the list of labels that appear in front of each
@@ -624,6 +631,7 @@ static struct
   /* TRUE if processing unwind directives in a prologue region.  */
   int prologue;
   int prologue_mask;
+  unsigned int prologue_count; /* number of .prologues seen so far */
 } unwind;
 
 typedef void (*vbyte_func) PARAMS ((int, char *, char *));
@@ -689,8 +697,9 @@ static void add_unwind_entry PARAMS((unw_rec_list *ptr));
 static symbolS *declare_register PARAMS ((const char *name, int regnum));
 static void declare_register_set PARAMS ((const char *, int, int));
 static unsigned int operand_width PARAMS ((enum ia64_opnd));
-static int operand_match PARAMS ((const struct ia64_opcode *idesc,
-                                 int index, expressionS *e));
+static enum operand_match_result operand_match PARAMS ((const struct ia64_opcode *idesc,
+                                                       int index,
+                                                       expressionS *e));
 static int parse_operand PARAMS ((expressionS *e));
 static struct ia64_opcode * parse_operands PARAMS ((struct ia64_opcode *));
 static void build_insn PARAMS ((struct slot *, bfd_vma *));
@@ -3047,7 +3056,7 @@ dot_restore (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
   expressionS e1, e2;
-  unsigned long ecount = 0;
+  unsigned long ecount;        /* # of _additional_ regions to pop */
   int sep;
 
   sep = parse_operand (&e1);
@@ -3060,14 +3069,21 @@ dot_restore (dummy)
   if (sep == ',')
     {
       parse_operand (&e2);
-      if (e1.X_op != O_constant)
+      if (e2.X_op != O_constant || e2.X_add_number < 0)
        {
-         as_bad ("Second operand to .restore must be constant");
+         as_bad ("Second operand to .restore must be a constant >= 0");
          return;
        }
-      ecount = e1.X_op;
+      ecount = e2.X_add_number;
     }
+  else
+    ecount = unwind.prologue_count - 1;
   add_unwind_entry (output_epilogue (ecount));
+
+  if (ecount < unwind.prologue_count)
+    unwind.prologue_count -= ecount + 1;
+  else
+    unwind.prologue_count = 0;
 }
 
 static void
@@ -3710,6 +3726,7 @@ dot_proc (dummy)
   demand_empty_rest_of_line ();
   ia64_do_align (16);
 
+  unwind.prologue_count = 0;
   unwind.list = unwind.tail = unwind.current_entry = NULL;
   unwind.personality_routine = 0;
 }
@@ -3764,6 +3781,7 @@ dot_prologue (dummy)
 
   unwind.prologue = 1;
   unwind.prologue_mask = mask;
+  ++unwind.prologue_count;
 }
 
 static void
@@ -4730,7 +4748,7 @@ operand_width (opnd)
   return bits;
 }
 
-static int
+static enum operand_match_result
 operand_match (idesc, index, e)
      const struct ia64_opcode *idesc;
      int index;
@@ -4747,62 +4765,77 @@ operand_match (idesc, index, e)
 
     case IA64_OPND_AR_CCV:
       if (e->X_op == O_register && e->X_add_number == REG_AR + 32)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_AR_PFS:
       if (e->X_op == O_register && e->X_add_number == REG_AR + 64)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_GR0:
       if (e->X_op == O_register && e->X_add_number == REG_GR + 0)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_IP:
       if (e->X_op == O_register && e->X_add_number == REG_IP)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_PR:
       if (e->X_op == O_register && e->X_add_number == REG_PR)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_PR_ROT:
       if (e->X_op == O_register && e->X_add_number == REG_PR_ROT)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_PSR:
       if (e->X_op == O_register && e->X_add_number == REG_PSR)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_PSR_L:
       if (e->X_op == O_register && e->X_add_number == REG_PSR_L)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_PSR_UM:
       if (e->X_op == O_register && e->X_add_number == REG_PSR_UM)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_C1:
-      if (e->X_op == O_constant && e->X_add_number == 1)
-       return 1;
+      if (e->X_op == O_constant)
+       {
+         if (e->X_add_number == 1)
+           return OPERAND_MATCH;
+         else
+           return OPERAND_OUT_OF_RANGE;
+       }
       break;
 
     case IA64_OPND_C8:
-      if (e->X_op == O_constant && e->X_add_number == 8)
-       return 1;
+      if (e->X_op == O_constant)
+       {
+         if (e->X_add_number == 8)
+           return OPERAND_MATCH;
+         else
+           return OPERAND_OUT_OF_RANGE;
+       }
       break;
 
     case IA64_OPND_C16:
-      if (e->X_op == O_constant && e->X_add_number == 16)
-       return 1;
+      if (e->X_op == O_constant)
+       {
+         if (e->X_add_number == 16)
+           return OPERAND_MATCH;
+         else
+           return OPERAND_OUT_OF_RANGE;
+       }
       break;
 
       /* register operands:  */
@@ -4810,20 +4843,20 @@ operand_match (idesc, index, e)
     case IA64_OPND_AR3:
       if (e->X_op == O_register && e->X_add_number >= REG_AR
          && e->X_add_number < REG_AR + 128)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_B1:
     case IA64_OPND_B2:
       if (e->X_op == O_register && e->X_add_number >= REG_BR
          && e->X_add_number < REG_BR + 8)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_CR3:
       if (e->X_op == O_register && e->X_add_number >= REG_CR
          && e->X_add_number < REG_CR + 128)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_F1:
@@ -4832,14 +4865,14 @@ operand_match (idesc, index, e)
     case IA64_OPND_F4:
       if (e->X_op == O_register && e->X_add_number >= REG_FR
          && e->X_add_number < REG_FR + 128)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_P1:
     case IA64_OPND_P2:
       if (e->X_op == O_register && e->X_add_number >= REG_P
          && e->X_add_number < REG_P + 64)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_R1:
@@ -4847,13 +4880,17 @@ operand_match (idesc, index, e)
     case IA64_OPND_R3:
       if (e->X_op == O_register && e->X_add_number >= REG_GR
          && e->X_add_number < REG_GR + 128)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_R3_2:
-      if (e->X_op == O_register && e->X_add_number >= REG_GR
-         && e->X_add_number < REG_GR + 4)
-       return 1;
+      if (e->X_op == O_register && e->X_add_number >= REG_GR)
+       { 
+         if (e->X_add_number < REG_GR + 4)
+           return OPERAND_MATCH;
+         else if (e->X_add_number < REG_GR + 128)
+           return OPERAND_OUT_OF_RANGE;
+       }
       break;
 
       /* indirect operands:  */
@@ -4870,12 +4907,12 @@ operand_match (idesc, index, e)
       if (e->X_op == O_index && e->X_op_symbol
          && (S_GET_VALUE (e->X_op_symbol) - IND_CPUID
              == opnd - IA64_OPND_CPUID_R3))
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_MR3:
       if (e->X_op == O_index && !e->X_op_symbol)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
       /* immediate operands:  */
@@ -4883,40 +4920,58 @@ operand_match (idesc, index, e)
     case IA64_OPND_LEN4:
     case IA64_OPND_LEN6:
       bits = operand_width (idesc->operands[index]);
-      if (e->X_op == O_constant
-         && (bfd_vma) (e->X_add_number - 1) < ((bfd_vma) 1 << bits))
-       return 1;
+      if (e->X_op == O_constant)
+       {
+         if ((bfd_vma) (e->X_add_number - 1) < ((bfd_vma) 1 << bits))
+           return OPERAND_MATCH;
+         else
+           return OPERAND_OUT_OF_RANGE;
+       }
       break;
 
     case IA64_OPND_CNT2b:
-      if (e->X_op == O_constant
-         && (bfd_vma) (e->X_add_number - 1) < 3)
-       return 1;
+      if (e->X_op == O_constant)
+       {
+         if ((bfd_vma) (e->X_add_number - 1) < 3)
+           return OPERAND_MATCH;
+         else
+           return OPERAND_OUT_OF_RANGE;
+       }
       break;
 
     case IA64_OPND_CNT2c:
       val = e->X_add_number;
-      if (e->X_op == O_constant
-         && (val == 0 || val == 7 || val == 15 || val == 16))
-       return 1;
+      if (e->X_op == O_constant)
+       {
+         if ((val == 0 || val == 7 || val == 15 || val == 16))
+           return OPERAND_MATCH;
+         else
+           return OPERAND_OUT_OF_RANGE;
+       }
       break;
 
     case IA64_OPND_SOR:
       /* SOR must be an integer multiple of 8 */
-      if (e->X_add_number & 0x7)
-       break;
+      if (e->X_op == O_constant && e->X_add_number & 0x7)
+       return OPERAND_OUT_OF_RANGE;
     case IA64_OPND_SOF:
     case IA64_OPND_SOL:
-      if (e->X_op == O_constant &&
-         (bfd_vma) e->X_add_number <= 96)
-       return 1;
+      if (e->X_op == O_constant)
+       {
+         if ((bfd_vma) e->X_add_number <= 96)
+           return OPERAND_MATCH;
+         else
+           return OPERAND_OUT_OF_RANGE;
+       }
       break;
 
     case IA64_OPND_IMMU62:
       if (e->X_op == O_constant)
        {
          if ((bfd_vma) e->X_add_number < ((bfd_vma) 1 << 62))
-           return 1;
+           return OPERAND_MATCH;
+         else
+           return OPERAND_OUT_OF_RANGE;
        }
       else
        {
@@ -4942,10 +4997,10 @@ operand_match (idesc, index, e)
          fix->expr = *e;
          fix->is_pcrel = 0;
          ++CURR_SLOT.num_fixups;
-         return 1;
+         return OPERAND_MATCH;
        }
       else if (e->X_op == O_constant)
-       return 1;
+       return OPERAND_MATCH;
       break;
 
     case IA64_OPND_CCNT5:
@@ -4963,59 +5018,78 @@ operand_match (idesc, index, e)
     case IA64_OPND_MHTYPE8:
     case IA64_OPND_POS6:
       bits = operand_width (idesc->operands[index]);
-      if (e->X_op == O_constant
-         && (bfd_vma) e->X_add_number < ((bfd_vma) 1 << bits))
-       return 1;
+      if (e->X_op == O_constant)
+       {
+         if ((bfd_vma) e->X_add_number < ((bfd_vma) 1 << bits))
+           return OPERAND_MATCH;
+         else
+           return OPERAND_OUT_OF_RANGE;
+       }
       break;
 
     case IA64_OPND_IMMU9:
       bits = operand_width (idesc->operands[index]);
-      if (e->X_op == O_constant
-         && (bfd_vma) e->X_add_number < ((bfd_vma) 1 << bits))
+      if (e->X_op == O_constant)
        {
-         int lobits = e->X_add_number & 0x3;
-         if (((bfd_vma) e->X_add_number & 0x3C) != 0 && lobits == 0)
-           e->X_add_number |= (bfd_vma) 0x3;
-         return 1;
+         if ((bfd_vma) e->X_add_number < ((bfd_vma) 1 << bits))
+           {
+             int lobits = e->X_add_number & 0x3;
+             if (((bfd_vma) e->X_add_number & 0x3C) != 0 && lobits == 0)
+               e->X_add_number |= (bfd_vma) 0x3;
+             return OPERAND_MATCH;
+           }
+         else
+           return OPERAND_OUT_OF_RANGE;
        }
       break;
 
     case IA64_OPND_IMM44:
       /* least 16 bits must be zero */
       if ((e->X_add_number & 0xffff) != 0)
+       /* XXX technically, this is wrong: we should not be issuing warning
+          messages until we're sure this instruction pattern is going to
+          be used! */
        as_warn (_("lower 16 bits of mask ignored"));
 
-      if (e->X_op == O_constant
-         && ((e->X_add_number >= 0
-              && (bfd_vma) e->X_add_number < ((bfd_vma) 1 << 44))
-             || (e->X_add_number < 0
-                 && (bfd_vma) -e->X_add_number <= ((bfd_vma) 1 << 44))))
+      if (e->X_op == O_constant)
        {
-         /* sign-extend */
-         if (e->X_add_number >= 0
-             && (e->X_add_number & ((bfd_vma) 1 << 43)) != 0)
+         if (((e->X_add_number >= 0
+               && (bfd_vma) e->X_add_number < ((bfd_vma) 1 << 44))
+              || (e->X_add_number < 0
+                  && (bfd_vma) -e->X_add_number <= ((bfd_vma) 1 << 44))))
            {
-             e->X_add_number |= ~(((bfd_vma) 1 << 44) - 1);
+             /* sign-extend */
+             if (e->X_add_number >= 0
+                 && (e->X_add_number & ((bfd_vma) 1 << 43)) != 0)
+               {
+                 e->X_add_number |= ~(((bfd_vma) 1 << 44) - 1);
+               }
+             return OPERAND_MATCH;
            }
-         return 1;
+         else
+           return OPERAND_OUT_OF_RANGE;
        }
       break;
 
     case IA64_OPND_IMM17:
       /* bit 0 is a don't care (pr0 is hardwired to 1) */
-      if (e->X_op == O_constant
-         && ((e->X_add_number >= 0
-              && (bfd_vma) e->X_add_number < ((bfd_vma) 1 << 17))
-             || (e->X_add_number < 0
-                 && (bfd_vma) -e->X_add_number <= ((bfd_vma) 1 << 17))))
-       {
-         /* sign-extend */
-         if (e->X_add_number >= 0
-             && (e->X_add_number & ((bfd_vma) 1 << 16)) != 0)
+      if (e->X_op == O_constant)
+       {
+         if (((e->X_add_number >= 0
+               && (bfd_vma) e->X_add_number < ((bfd_vma) 1 << 17))
+              || (e->X_add_number < 0
+                  && (bfd_vma) -e->X_add_number <= ((bfd_vma) 1 << 17))))
            {
-             e->X_add_number |= ~(((bfd_vma) 1 << 17) - 1);
+             /* sign-extend */
+             if (e->X_add_number >= 0
+                 && (e->X_add_number & ((bfd_vma) 1 << 16)) != 0)
+               {
+                 e->X_add_number |= ~(((bfd_vma) 1 << 17) - 1);
+               }
+             return OPERAND_MATCH;
            }
-         return 1;
+         else
+           return OPERAND_OUT_OF_RANGE;
        }
       break;
 
@@ -5053,18 +5127,18 @@ operand_match (idesc, index, e)
          fix->expr = *e;
          fix->is_pcrel = 0;
          ++CURR_SLOT.num_fixups;
-         return 1;
+         return OPERAND_MATCH;
        }
       else if (e->X_op != O_constant
               && ! (e->X_op == O_big && opnd == IA64_OPND_IMM8M1U8))
-       return 0;
+       return OPERAND_MISMATCH;
 
       if (opnd == IA64_OPND_IMM8M1U4)
        {
          /* Zero is not valid for unsigned compares that take an adjusted
             constant immediate range.  */
          if (e->X_add_number == 0)
-           return 0;
+           return OPERAND_OUT_OF_RANGE;
 
          /* Sign-extend 32-bit unsigned numbers, so that the following range
             checks will work.  */
@@ -5076,7 +5150,7 @@ operand_match (idesc, index, e)
          /* Check for 0x100000000.  This is valid because
             0x100000000-1 is the same as ((uint32_t) -1).  */
          if (val == ((bfd_signed_vma) 1 << 32))
-           return 1;
+           return OPERAND_MATCH;
 
          val = val - 1;
        }
@@ -5085,7 +5159,7 @@ operand_match (idesc, index, e)
          /* Zero is not valid for unsigned compares that take an adjusted
             constant immediate range.  */
          if (e->X_add_number == 0)
-           return 0;
+           return OPERAND_OUT_OF_RANGE;
 
          /* Check for 0x10000000000000000.  */
          if (e->X_op == O_big)
@@ -5095,9 +5169,9 @@ operand_match (idesc, index, e)
                  && generic_bignum[2] == 0
                  && generic_bignum[3] == 0
                  && generic_bignum[4] == 1)
-               return 1;
+               return OPERAND_MATCH;
              else
-               return 0;
+               return OPERAND_OUT_OF_RANGE;
            }
          else
            val = e->X_add_number - 1;
@@ -5118,17 +5192,22 @@ operand_match (idesc, index, e)
 
       if ((val >= 0 && (bfd_vma) val < ((bfd_vma) 1 << (bits - 1)))
          || (val < 0 && (bfd_vma) -val <= ((bfd_vma) 1 << (bits - 1))))
-       return 1;
-      break;
+       return OPERAND_MATCH;
+      else
+       return OPERAND_OUT_OF_RANGE;
 
     case IA64_OPND_INC3:
       /* +/- 1, 4, 8, 16 */
       val = e->X_add_number;
       if (val < 0)
        val = -val;
-      if (e->X_op == O_constant
-         && (val == 1 || val == 4 || val == 8 || val == 16))
-       return 1;
+      if (e->X_op == O_constant)
+       {
+         if ((val == 1 || val == 4 || val == 8 || val == 16))
+           return OPERAND_MATCH;
+         else
+           return OPERAND_OUT_OF_RANGE;
+       }
       break;
 
     case IA64_OPND_TGT25:
@@ -5154,14 +5233,14 @@ operand_match (idesc, index, e)
          fix->expr = *e;
          fix->is_pcrel = 1;
          ++CURR_SLOT.num_fixups;
-         return 1;
+         return OPERAND_MATCH;
        }
     case IA64_OPND_TAG13:
     case IA64_OPND_TAG13b:
       switch (e->X_op)
        {
        case O_constant:
-         return 1;
+         return OPERAND_MATCH;
 
        case O_symbol:
          fix = CURR_SLOT.fixup + CURR_SLOT.num_fixups;
@@ -5173,7 +5252,7 @@ operand_match (idesc, index, e)
          fix->expr = *e;
          fix->is_pcrel = 1;
          ++CURR_SLOT.num_fixups;
-         return 1;
+         return OPERAND_MATCH;
 
        default:
          break;
@@ -5183,7 +5262,7 @@ operand_match (idesc, index, e)
     default:
       break;
     }
-  return 0;
+  return OPERAND_MISMATCH;
 }
 
 static int
@@ -5231,8 +5310,9 @@ parse_operands (idesc)
      struct ia64_opcode *idesc;
 {
   int i = 0, highest_unmatched_operand, num_operands = 0, num_outputs = 0;
-  int sep = 0;
+  int error_pos, out_of_range_pos, curr_out_of_range_pos, sep = 0;
   enum ia64_opnd expected_operand = IA64_OPND_NIL;
+  enum operand_match_result result;
   char mnemonic[129];
   char *first_arg = 0, *end, *saved_input_pointer;
   unsigned int sof;
@@ -5314,6 +5394,8 @@ parse_operands (idesc)
     }
 
   highest_unmatched_operand = 0;
+  curr_out_of_range_pos = -1;
+  error_pos = 0;
   expected_operand = idesc->operands[0];
   for (; idesc; idesc = get_next_opcode (idesc))
     {
@@ -5321,16 +5403,52 @@ parse_operands (idesc)
        continue;               /* mismatch in # of outputs */
 
       CURR_SLOT.num_fixups = 0;
+
+      /* Try to match all operands.  If we see an out-of-range operand,
+        then continue trying to match the rest of the operands, since if
+        the rest match, then this idesc will give the best error message.  */
+
+      out_of_range_pos = -1;
       for (i = 0; i < num_operands && idesc->operands[i]; ++i)
-       if (!operand_match (idesc, i, CURR_SLOT.opnd + i))
-         break;
+       {
+         result = operand_match (idesc, i, CURR_SLOT.opnd + i);
+         if (result != OPERAND_MATCH)
+           {
+             if (result != OPERAND_OUT_OF_RANGE)
+               break;
+             if (out_of_range_pos < 0)
+               /* remember position of the first out-of-range operand: */
+               out_of_range_pos = i;
+           }
+       }
+
+      /* If we did not match all operands, or if at least one operand was
+        out-of-range, then this idesc does not match.  Keep track of which
+        idesc matched the most operands before failing.  If we have two
+        idescs that failed at the same position, and one had an out-of-range
+        operand, then prefer the out-of-range operand.  Thus if we have
+        "add r0=0x1000000,r1" we get an error saying the constant is out
+        of range instead of an error saying that the constant should have been
+        a register.  */
 
-      if (i != num_operands)
+      if (i != num_operands || out_of_range_pos >= 0)
        {
-         if (i > highest_unmatched_operand)
+         if (i > highest_unmatched_operand
+             || (i == highest_unmatched_operand
+                 && out_of_range_pos > curr_out_of_range_pos))
            {
              highest_unmatched_operand = i;
-             expected_operand = idesc->operands[i];
+             if (out_of_range_pos >= 0)
+               {
+                 expected_operand = idesc->operands[out_of_range_pos];
+                 error_pos = out_of_range_pos;
+               }
+             else
+               {
+                 expected_operand = idesc->operands[i];
+                 error_pos = i;
+               }
+             curr_out_of_range_pos = out_of_range_pos;
            }
          continue;
        }
@@ -5345,7 +5463,7 @@ parse_operands (idesc)
     {
       if (expected_operand)
        as_bad ("Operand %u of `%s' should be %s",
-               highest_unmatched_operand + 1, mnemonic,
+               error_pos + 1, mnemonic,
                elf64_ia64_operands[expected_operand].desc);
       else
        as_bad ("Operand mismatch");
This page took 0.032553 seconds and 4 git commands to generate.