}
 
   /* Accept the above plus <cr bit>, and <cr bit> plus the above.  */
-  if (right->X_op == O_register
+  if (op == O_add
       && left->X_op == O_register
-      && op == O_add
+      && right->X_op == O_register
       && ((right->X_md == PPC_OPERAND_CR_BIT
           && left->X_md == (PPC_OPERAND_CR_REG | PPC_OPERAND_CR_BIT))
          || (right->X_md == (PPC_OPERAND_CR_REG | PPC_OPERAND_CR_BIT)
     }
 
   /* Accept reg +/- constant.  */
-  if (left->X_op == O_register
+  if (left && left->X_op == O_register
       && !((op == O_add || op == O_subtract) && right->X_op == O_constant))
     as_warn (_("invalid register expression"));
 
 
 is called, @code{input_line_pointer} will point to the start of the
 expression.
 
+@item md_optimize_expr
+@cindex md_optimize_expr
+GAS will call this function before trying to carry out certain operations,
+like the adding of two constants.  The function is passed the left-hand
+operand, an @code{expressionS} pointer, the operator, an @code{operatorT}
+value, and the right-hand operand, again an @code{expressionS} pointer.  For
+unary expressions NULL is passed as first argument.
+
 @item md_register_arithmetic
 @cindex md_register_arithmetic
 If this macro is defined and evaluates to zero then GAS will not fold
 
   symbolS *symbolP;    /* Points to symbol.  */
   char *name;          /* Points to name of symbol.  */
   segT segment;
+  operatorT op = O_absent; /* For unary operators.  */
 
   /* All integers are regarded as unsigned unless they are negated.
      This is because the only thing which cares whether a number is
       /* '~' is permitted to start a label on the Delta.  */
       if (is_name_beginner (c))
        goto isname;
-      /* Fall through.  */
+      op = O_bit_not;
+      goto unary;
+
     case '!':
+      op = O_logical_not;
+      goto unary;
+
     case '-':
+      op = O_uminus;
+      /* Fall through.  */
     case '+':
       {
-#ifdef md_operator
       unary:
-#endif
        operand (expressionP, mode);
+
+#ifdef md_optimize_expr
+       if (md_optimize_expr (NULL, op, expressionP))
+       {
+         /* Skip.  */
+         ;
+       }
+       else
+#endif
        if (expressionP->X_op == O_constant)
          {
            /* input_line_pointer -> char after operand.  */
-           if (c == '-')
+           if (op == O_uminus)
              {
                expressionP->X_add_number
                  = - (addressT) expressionP->X_add_number;
                if (expressionP->X_add_number)
                  expressionP->X_extrabit ^= 1;
              }
-           else if (c == '~' || c == '"')
+           else if (op == O_bit_not)
              {
                expressionP->X_add_number = ~ expressionP->X_add_number;
                expressionP->X_extrabit ^= 1;
                expressionP->X_unsigned = 0;
              }
-           else if (c == '!')
+           else if (op == O_logical_not)
              {
                expressionP->X_add_number = ! expressionP->X_add_number;
                expressionP->X_unsigned = 1;
          }
        else if (expressionP->X_op == O_big
                 && expressionP->X_add_number <= 0
-                && c == '-'
+                && op == O_uminus
                 && (generic_floating_point_number.sign == '+'
                     || generic_floating_point_number.sign == 'P'))
          {
          {
            int i;
 
-           if (c == '~' || c == '-')
+           if (op == O_uminus || op == O_bit_not)
              {
                for (i = 0; i < expressionP->X_add_number; ++i)
                  generic_bignum[i] = ~generic_bignum[i];
                      generic_bignum[i] = ~(LITTLENUM_TYPE) 0;
                  }
 
-               if (c == '-')
+               if (op == O_uminus)
                  for (i = 0; i < expressionP->X_add_number; ++i)
                    {
                      generic_bignum[i] += 1;
                        break;
                    }
              }
-           else if (c == '!')
+           else if (op == O_logical_not)
              {
                for (i = 0; i < expressionP->X_add_number; ++i)
                  if (generic_bignum[i] != 0)
        else if (expressionP->X_op != O_illegal
                 && expressionP->X_op != O_absent)
          {
-           if (c != '+')
+           if (op != O_absent)
              {
                expressionP->X_add_symbol = make_expr_symbol (expressionP);
-               if (c == '-')
-                 expressionP->X_op = O_uminus;
-               else if (c == '~' || c == '"')
-                 expressionP->X_op = O_bit_not;
-               else
-                 expressionP->X_op = O_logical_not;
+               expressionP->X_op = op;
                expressionP->X_add_number = 0;
              }
            else if (!md_register_arithmetic && expressionP->X_op == O_register)
 
 #ifdef md_operator
          {
-           operatorT op = md_operator (name, 1, &c);
-
+           op = md_operator (name, 1, &c);
            switch (op)
              {
              case O_uminus: