bfd/
[deliverable/binutils-gdb.git] / gas / expr.c
index c601b0af6986e89312ffcc6c2e018f2b328003ef..285b4381da24445242c9c5fbe4542c2172fb65c6 100644 (file)
@@ -1,13 +1,13 @@
 /* expr.c -operands, expressions-
    Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
 /* expr.c -operands, expressions-
    Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
    any later version.
 
    GAS is distributed in the hope that it will be useful,
@@ -25,7 +25,6 @@
    (It also gives smaller files to re-compile.)
    Here, "operand"s are of expressions, not instructions.  */
 
    (It also gives smaller files to re-compile.)
    Here, "operand"s are of expressions, not instructions.  */
 
-#include <string.h>
 #define min(a, b)       ((a) < (b) ? (a) : (b))
 
 #include "as.h"
 #define min(a, b)       ((a) < (b) ? (a) : (b))
 
 #include "as.h"
@@ -96,7 +95,9 @@ make_expr_symbol (expressionS *expressionP)
   symbolP = symbol_create (FAKE_LABEL_NAME,
                           (expressionP->X_op == O_constant
                            ? absolute_section
   symbolP = symbol_create (FAKE_LABEL_NAME,
                           (expressionP->X_op == O_constant
                            ? absolute_section
-                           : expr_section),
+                           : expressionP->X_op == O_register
+                             ? reg_section
+                             : expr_section),
                           0, &zero_address_frag);
   symbol_set_value_expression (symbolP, expressionP);
 
                           0, &zero_address_frag);
   symbol_set_value_expression (symbolP, expressionP);
 
@@ -1003,11 +1004,6 @@ operand (expressionS *expressionP, enum expr_mode mode)
     case '-':
     case '+':
       {
     case '-':
     case '+':
       {
-       /* Do not accept ++e or --e as +(+e) or -(-e)
-          Disabled, since the preprocessor removes whitespace.  */
-       if (0 && (c == '-' || c == '+') && *input_line_pointer == c)
-         goto target_op;
-       
        operand (expressionP, mode);
        if (expressionP->X_op == O_constant)
          {
        operand (expressionP, mode);
        if (expressionP->X_op == O_constant)
          {
@@ -1291,7 +1287,6 @@ operand (expressionS *expressionP, enum expr_mode mode)
        }
       else
        {
        }
       else
        {
-       target_op:
          /* Let the target try to parse it.  Success is indicated by changing
             the X_op field to something other than O_absent and pointing
             input_line_pointer past the expression.  If it can't parse the
          /* Let the target try to parse it.  Success is indicated by changing
             the X_op field to something other than O_absent and pointing
             input_line_pointer past the expression.  If it can't parse the
@@ -1552,11 +1547,7 @@ operator (int *num_chars)
 
     case '+':
     case '-':
 
     case '+':
     case '-':
-      /* Do not allow a++b and a--b to be a + (+b) and a - (-b)
-        Disabled, since the preprocessor removes whitespace.  */
-      if (1 || input_line_pointer[1] != c)
-       return op_encoding[c];
-      return O_illegal;
+      return op_encoding[c];
 
     case '<':
       switch (input_line_pointer[1])
 
     case '<':
       switch (input_line_pointer[1])
@@ -1647,7 +1638,7 @@ expr (int rankarg,                /* Larger # is higher rank.  */
   operatorT op_right;
   int op_chars;
 
   operatorT op_right;
   int op_chars;
 
-  know (rank >= 0);
+  know (rankarg >= 0);
 
   /* Save the value of dot for the fixup code.  */
   if (rank == 0)
 
   /* Save the value of dot for the fixup code.  */
   if (rank == 0)
@@ -1662,6 +1653,7 @@ expr (int rankarg,                /* Larger # is higher rank.  */
   while (op_left != O_illegal && op_rank[(int) op_left] > rank)
     {
       segT rightseg;
   while (op_left != O_illegal && op_rank[(int) op_left] > rank)
     {
       segT rightseg;
+      bfd_vma frag_off;
 
       input_line_pointer += op_chars;  /* -> after operator.  */
 
 
       input_line_pointer += op_chars;  /* -> after operator.  */
 
@@ -1732,7 +1724,11 @@ expr (int rankarg,               /* Larger # is higher rank.  */
        }
       else
 #endif
        }
       else
 #endif
-      if (op_left == O_add && right.X_op == O_constant)
+#ifndef md_register_arithmetic
+# define md_register_arithmetic 1
+#endif
+      if (op_left == O_add && right.X_op == O_constant
+         && (md_register_arithmetic || resultP->X_op != O_register))
        {
          /* X + constant.  */
          resultP->X_add_number += right.X_add_number;
        {
          /* X + constant.  */
          resultP->X_add_number += right.X_add_number;
@@ -1741,23 +1737,31 @@ expr (int rankarg,              /* Larger # is higher rank.  */
       else if (op_left == O_subtract
               && right.X_op == O_symbol
               && resultP->X_op == O_symbol
       else if (op_left == O_subtract
               && right.X_op == O_symbol
               && resultP->X_op == O_symbol
-              && (symbol_get_frag (right.X_add_symbol)
-                  == symbol_get_frag (resultP->X_add_symbol))
+              && retval == rightseg
+#ifdef md_allow_local_subtract
+              && md_allow_local_subtract (resultP, & right, rightseg)
+#endif
               && (SEG_NORMAL (rightseg)
               && (SEG_NORMAL (rightseg)
-                  || right.X_add_symbol == resultP->X_add_symbol))
+                  || right.X_add_symbol == resultP->X_add_symbol)
+              && frag_offset_fixed_p (symbol_get_frag (resultP->X_add_symbol),
+                                      symbol_get_frag (right.X_add_symbol),
+                                      &frag_off))
        {
          resultP->X_add_number -= right.X_add_number;
        {
          resultP->X_add_number -= right.X_add_number;
+         resultP->X_add_number -= frag_off / OCTETS_PER_BYTE;
          resultP->X_add_number += (S_GET_VALUE (resultP->X_add_symbol)
                                    - S_GET_VALUE (right.X_add_symbol));
          resultP->X_op = O_constant;
          resultP->X_add_symbol = 0;
        }
          resultP->X_add_number += (S_GET_VALUE (resultP->X_add_symbol)
                                    - S_GET_VALUE (right.X_add_symbol));
          resultP->X_op = O_constant;
          resultP->X_add_symbol = 0;
        }
-      else if (op_left == O_subtract && right.X_op == O_constant)
+      else if (op_left == O_subtract && right.X_op == O_constant
+              && (md_register_arithmetic || resultP->X_op != O_register))
        {
          /* X - constant.  */
          resultP->X_add_number -= right.X_add_number;
        }
        {
          /* X - constant.  */
          resultP->X_add_number -= right.X_add_number;
        }
-      else if (op_left == O_add && resultP->X_op == O_constant)
+      else if (op_left == O_add && resultP->X_op == O_constant
+              && (md_register_arithmetic || right.X_op != O_register))
        {
          /* Constant + X.  */
          resultP->X_op = right.X_op;
        {
          /* Constant + X.  */
          resultP->X_op = right.X_op;
@@ -1792,7 +1796,9 @@ expr (int rankarg,                /* Larger # is higher rank.  */
            case O_bit_or_not:          resultP->X_add_number |= ~v; break;
            case O_bit_exclusive_or:    resultP->X_add_number ^= v; break;
            case O_bit_and:             resultP->X_add_number &= v; break;
            case O_bit_or_not:          resultP->X_add_number |= ~v; break;
            case O_bit_exclusive_or:    resultP->X_add_number ^= v; break;
            case O_bit_and:             resultP->X_add_number &= v; break;
-           case O_add:                 resultP->X_add_number += v; break;
+             /* Constant + constant (O_add) is handled by the
+                previous if statement for constant + X, so is omitted
+                here.  */
            case O_subtract:            resultP->X_add_number -= v; break;
            case O_eq:
              resultP->X_add_number =
            case O_subtract:            resultP->X_add_number -= v; break;
            case O_eq:
              resultP->X_add_number =
@@ -1900,6 +1906,7 @@ resolve_expression (expressionS *expressionP)
   valueT left, right;
   segT seg_left, seg_right;
   fragS *frag_left, *frag_right;
   valueT left, right;
   segT seg_left, seg_right;
   fragS *frag_left, *frag_right;
+  bfd_vma frag_off;
 
   switch (op)
     {
 
   switch (op)
     {
@@ -1913,7 +1920,7 @@ resolve_expression (expressionS *expressionP)
 
     case O_symbol:
     case O_symbol_rva:
 
     case O_symbol:
     case O_symbol_rva:
-      if (!snapshot_symbol (add_symbol, &left, &seg_left, &frag_left))
+      if (!snapshot_symbol (&add_symbol, &left, &seg_left, &frag_left))
        return 0;
 
       break;
        return 0;
 
       break;
@@ -1921,7 +1928,7 @@ resolve_expression (expressionS *expressionP)
     case O_uminus:
     case O_bit_not:
     case O_logical_not:
     case O_uminus:
     case O_bit_not:
     case O_logical_not:
-      if (!snapshot_symbol (add_symbol, &left, &seg_left, &frag_left))
+      if (!snapshot_symbol (&add_symbol, &left, &seg_left, &frag_left))
        return 0;
 
       if (seg_left != absolute_section)
        return 0;
 
       if (seg_left != absolute_section)
@@ -1955,8 +1962,8 @@ resolve_expression (expressionS *expressionP)
     case O_gt:
     case O_logical_and:
     case O_logical_or:
     case O_gt:
     case O_logical_and:
     case O_logical_or:
-      if (!snapshot_symbol (add_symbol, &left, &seg_left, &frag_left)
-         || !snapshot_symbol (op_symbol, &right, &seg_right, &frag_right))
+      if (!snapshot_symbol (&add_symbol, &left, &seg_left, &frag_left)
+         || !snapshot_symbol (&op_symbol, &right, &seg_right, &frag_right))
        return 0;
 
       /* Simplify addition or subtraction of a constant by folding the
        return 0;
 
       /* Simplify addition or subtraction of a constant by folding the
@@ -1974,7 +1981,7 @@ resolve_expression (expressionS *expressionP)
              final_val += left;
              left = right;
              seg_left = seg_right;
              final_val += left;
              left = right;
              seg_left = seg_right;
-             expressionP->X_add_symbol = expressionP->X_op_symbol;
+             add_symbol = op_symbol;
              op = O_symbol;
              break;
            }
              op = O_symbol;
              break;
            }
@@ -1991,21 +1998,86 @@ resolve_expression (expressionS *expressionP)
 
       /* Equality and non-equality tests are permitted on anything.
         Subtraction, and other comparison operators are permitted if
 
       /* Equality and non-equality tests are permitted on anything.
         Subtraction, and other comparison operators are permitted if
-        both operands are in the same section.  Otherwise, both
-        operands must be absolute.  We already handled the case of
-        addition or subtraction of a constant above.  */
+        both operands are in the same section.
+        Shifts by constant zero are permitted on anything.
+        Multiplies, bit-ors, and bit-ands with constant zero are
+        permitted on anything.
+        Multiplies and divides by constant one are permitted on
+        anything.
+        Binary operations with both operands being the same register
+        or undefined symbol are permitted if the result doesn't depend
+        on the input value.
+        Otherwise, both operands must be absolute.  We already handled
+        the case of addition or subtraction of a constant above.  */
+      frag_off = 0;
       if (!(seg_left == absolute_section
               && seg_right == absolute_section)
          && !(op == O_eq || op == O_ne)
          && !((op == O_subtract
                || op == O_lt || op == O_le || op == O_ge || op == O_gt)
               && seg_left == seg_right
       if (!(seg_left == absolute_section
               && seg_right == absolute_section)
          && !(op == O_eq || op == O_ne)
          && !((op == O_subtract
                || op == O_lt || op == O_le || op == O_ge || op == O_gt)
               && seg_left == seg_right
-              && (finalize_syms || frag_left == frag_right)
-              && ((seg_left != undefined_section
-                   && seg_left != reg_section)
-                  || add_symbol == op_symbol)))
-       return 0;
+              && (finalize_syms
+                  || frag_offset_fixed_p (frag_left, frag_right, &frag_off))
+              && (seg_left != reg_section || left == right)
+              && (seg_left != undefined_section || add_symbol == op_symbol)))
+       {
+         if ((seg_left == absolute_section && left == 0)
+             || (seg_right == absolute_section && right == 0))
+           {
+             if (op == O_bit_exclusive_or || op == O_bit_inclusive_or)
+               {
+                 if (seg_right != absolute_section || right != 0)
+                   {
+                     seg_left = seg_right;
+                     left = right;
+                     add_symbol = op_symbol;
+                   }
+                 op = O_symbol;
+                 break;
+               }
+             else if (op == O_left_shift || op == O_right_shift)
+               {
+                 if (seg_left != absolute_section || left != 0)
+                   {
+                     op = O_symbol;
+                     break;
+                   }
+               }
+             else if (op != O_multiply
+                      && op != O_bit_or_not && op != O_bit_and)
+               return 0;
+           }
+         else if (op == O_multiply
+                  && seg_left == absolute_section && left == 1)
+           {
+             seg_left = seg_right;
+             left = right;
+             add_symbol = op_symbol;
+             op = O_symbol;
+             break;
+           }
+         else if ((op == O_multiply || op == O_divide)
+                  && seg_right == absolute_section && right == 1)
+           {
+             op = O_symbol;
+             break;
+           }
+         else if (left != right
+                  || ((seg_left != reg_section || seg_right != reg_section)
+                      && (seg_left != undefined_section
+                          || seg_right != undefined_section
+                          || add_symbol != op_symbol)))
+           return 0;
+         else if (op == O_bit_and || op == O_bit_inclusive_or)
+           {
+             op = O_symbol;
+             break;
+           }
+         else if (op != O_bit_exclusive_or && op != O_bit_or_not)
+           return 0;
+       }
 
 
+      right += frag_off / OCTETS_PER_BYTE;
       switch (op)
        {
        case O_add:                     left += right; break;
       switch (op)
        {
        case O_add:                     left += right; break;
@@ -2032,8 +2104,7 @@ resolve_expression (expressionS *expressionP)
          left = (left == right
                  && seg_left == seg_right
                  && (finalize_syms || frag_left == frag_right)
          left = (left == right
                  && seg_left == seg_right
                  && (finalize_syms || frag_left == frag_right)
-                 && ((seg_left != undefined_section
-                      && seg_left != reg_section)
+                 && (seg_left != undefined_section
                      || add_symbol == op_symbol)
                  ? ~ (valueT) 0 : 0);
          if (op == O_ne)
                      || add_symbol == op_symbol)
                  ? ~ (valueT) 0 : 0);
          if (op == O_ne)
@@ -2066,6 +2137,9 @@ resolve_expression (expressionS *expressionP)
        op = O_constant;
       else if (seg_left == reg_section && final_val == 0)
        op = O_register;
        op = O_constant;
       else if (seg_left == reg_section && final_val == 0)
        op = O_register;
+      else if (add_symbol != expressionP->X_add_symbol)
+       final_val += left;
+      expressionP->X_add_symbol = add_symbol;
     }
   expressionP->X_op = op;
 
     }
   expressionP->X_op = op;
 
This page took 0.027419 seconds and 4 git commands to generate.