https://gcc.gnu.org/g:96a657775713c5f99ed5fbdfd240b66797dc0c6e

commit 96a657775713c5f99ed5fbdfd240b66797dc0c6e
Author: Mikael Morin <mik...@gcc.gnu.org>
Date:   Thu Jul 4 15:24:36 2024 +0200

    match: Unwrap non-lvalue as unary or binary operand
    
    This change makes the binary and unary folding functions return a tree
    whose operands have their non-lvalue wrapper stripped (if they had one).
    It only makes a difference if the function hasn't found any
    simplification and would return NULL_TREE.  It moves all early NULL_TREE
    return to the end of the function where a last resort common
    simplification attempt is made.  That attempt checks whether the
    implicit simplifications contained in the stripped operands are worth
    keeping, and returns a new tree based on the stripped operands in that
    case.  This requires the original tree code to remain unmodified until
    the end of the function, so the code variable is renamed to a new
    variable in an area where a modified value was used.
    
    The testcases are best effort; for some operators the fortran frontend
    generates a temporary variable, so the simplification doesn't happen.
    Those cases are not tested.
    
    gcc/ChangeLog:
    
            * fold-const.cc (stripped_converted_equals_original): New.
            (fold_binary_loc): Check whether the initial stripping of
            operands was a simplification worth keeping before returning
            NULL_TREE, and rebuild a new tree based on the stripped operands
            in that case.
            (fold_unary_loc): Likewise.
    
    gcc/testsuite/ChangeLog:
    
            * gfortran.dg/non_lvalue_2.f90: New test.
            * gfortran.dg/non_lvalue_3.f90: New test.

Diff:
---
 gcc/fold-const.cc                          | 139 +++++++++++++++--------
 gcc/testsuite/gfortran.dg/non_lvalue_2.f90 |  58 ++++++++++
 gcc/testsuite/gfortran.dg/non_lvalue_3.f90 | 172 +++++++++++++++++++++++++++++
 3 files changed, 326 insertions(+), 43 deletions(-)

diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
index 014f42187932..db0fc0ae3efe 100644
--- a/gcc/fold-const.cc
+++ b/gcc/fold-const.cc
@@ -9181,6 +9181,21 @@ build_fold_addr_expr_loc (location_t loc, tree t)
   return build_fold_addr_expr_with_type_loc (loc, t, ptrtype);
 }
 
+/* Tells whether tree ORIGINAL is equal to what would be produced if
+   converting its nop-stripped subtree STRIPPED to its type.  */
+
+static inline bool
+stripped_converted_equals_original (const_tree stripped, const_tree original)
+{
+  if (stripped == original)
+    return true;
+
+  if (TREE_TYPE (stripped) == TREE_TYPE (original))
+    return false;
+
+  return TREE_OPERAND (original, 0) == stripped;
+}
+
 /* Fold a unary expression of code CODE and type TYPE with operand
    OP0.  Return the folded expression if folding is successful.
    Otherwise, return NULL_TREE.  */
@@ -9299,7 +9314,7 @@ fold_unary_loc (location_t loc, enum tree_code code, tree 
type, tree op0)
     case NON_LVALUE_EXPR:
       if (!maybe_lvalue_p (op0))
        return fold_convert_loc (loc, type, op0);
-      return NULL_TREE;
+      break;
 
     CASE_CONVERT:
     case FLOAT_EXPR:
@@ -9437,7 +9452,7 @@ fold_unary_loc (location_t loc, enum tree_code code, tree 
type, tree op0)
              && sanitize_flags_p (SANITIZE_ALIGNMENT)
              && (min_align_of_type (TREE_TYPE (type))
                  > min_align_of_type (TREE_TYPE (TREE_TYPE (arg00)))))
-           return NULL_TREE;
+           break;
 
          /* Similarly, avoid this optimization in GENERIC for -fsanitize=null
             when type is a reference type and arg00's type is not,
@@ -9447,7 +9462,7 @@ fold_unary_loc (location_t loc, enum tree_code code, tree 
type, tree op0)
              && !in_gimple_form
              && sanitize_flags_p (SANITIZE_NULL)
              && TREE_CODE (TREE_TYPE (arg00)) != REFERENCE_TYPE)
-           return NULL_TREE;
+           break;
 
          arg00 = fold_convert_loc (loc, type, arg00);
          return fold_build_pointer_plus_loc (loc, arg00, arg01);
@@ -9496,7 +9511,7 @@ fold_unary_loc (location_t loc, enum tree_code code, tree 
type, tree op0)
            }
        }
 
-      return NULL_TREE;
+      break;
 
     case VIEW_CONVERT_EXPR:
       if (TREE_CODE (op0) == MEM_REF)
@@ -9509,13 +9524,13 @@ fold_unary_loc (location_t loc, enum tree_code code, 
tree type, tree op0)
          return tem;
        }
 
-      return NULL_TREE;
+      break;
 
     case NEGATE_EXPR:
       tem = fold_negate_expr (loc, arg0);
       if (tem)
        return fold_convert_loc (loc, type, tem);
-      return NULL_TREE;
+      break;
 
     case ABS_EXPR:
       /* Convert fabs((double)float) into (double)fabsf(float).  */
@@ -9529,7 +9544,7 @@ fold_unary_loc (location_t loc, enum tree_code code, tree 
type, tree op0)
                                                  TREE_TYPE (targ0),
                                                  targ0));
        }
-      return NULL_TREE;
+      break;
 
     case BIT_NOT_EXPR:
       /* Convert ~(X ^ Y) to ~X ^ Y or X ^ ~Y if ~X or ~Y simplify.  */
@@ -9548,7 +9563,7 @@ fold_unary_loc (location_t loc, enum tree_code code, tree 
type, tree op0)
                            fold_convert_loc (loc, type,
                                              TREE_OPERAND (arg0, 0)), tem);
 
-      return NULL_TREE;
+      break;
 
     case TRUTH_NOT_EXPR:
       /* Note that the operand of this must be an int
@@ -9557,7 +9572,7 @@ fold_unary_loc (location_t loc, enum tree_code code, tree 
type, tree op0)
         but we don't handle values other than 1 correctly yet.)  */
       tem = fold_truth_not_expr (loc, arg0);
       if (!tem)
-       return NULL_TREE;
+       break;
       return fold_convert_loc (loc, type, tem);
 
     case INDIRECT_REF:
@@ -9571,11 +9586,22 @@ fold_unary_loc (location_t loc, enum tree_code code, 
tree type, tree op0)
              && !TREE_READONLY (op00))
            return op00;
        }
-      return NULL_TREE;
+      break;
 
     default:
-      return NULL_TREE;
+      break;
     } /* switch (code) */
+
+  if (kind == tcc_unary
+      && !stripped_converted_equals_original (arg0, op0))
+    {
+      op0 = fold_convert_loc (EXPR_HAS_LOCATION (op0)
+                             ? EXPR_LOCATION (op0) : loc,
+                             TREE_TYPE (op0), arg0);
+      return fold_build1_loc (loc, code, type, op0);
+    }
+
+  return NULL_TREE;
 }
 
 
@@ -11144,14 +11170,14 @@ fold_binary_loc (location_t loc, enum tree_code code, 
tree type,
          base = get_addr_base_and_unit_offset (TREE_OPERAND (arg0, 0),
                                                &coffset);
          if (!base)
-           return NULL_TREE;
+           break;
          return fold_build2 (MEM_REF, type,
                              build1 (ADDR_EXPR, TREE_TYPE (arg0), base),
                              int_const_binop (PLUS_EXPR, arg1,
                                               size_int (coffset)));
        }
 
-      return NULL_TREE;
+      break;
 
     case POINTER_PLUS_EXPR:
       /* INT +p INT -> (PTR)(INT + INT).  Stripping types allows for this. */
@@ -11164,7 +11190,7 @@ fold_binary_loc (location_t loc, enum tree_code code, 
tree type,
                                              fold_convert_loc (loc, sizetype,
                                                                arg0)));
 
-      return NULL_TREE;
+      break;
 
     case PLUS_EXPR:
       if (INTEGRAL_TYPE_P (type) || VECTOR_INTEGER_TYPE_P (type))
@@ -11449,8 +11475,9 @@ fold_binary_loc (location_t loc, enum tree_code code, 
tree type,
                             &lit1, &minus_lit1, code == MINUS_EXPR);
 
          /* Recombine MINUS_EXPR operands by using PLUS_EXPR.  */
+         enum tree_code assoc_code = code;
          if (code == MINUS_EXPR)
-           code = PLUS_EXPR;
+           assoc_code = PLUS_EXPR;
 
          /* With undefined overflow prefer doing association in a type
             which wraps on overflow, if that is one of the operand types.  */
@@ -11532,15 +11559,15 @@ fold_binary_loc (location_t loc, enum tree_code code, 
tree type,
              int lit0_origin = (lit0 != 0) + 2 * (lit1 != 0);
              int minus_lit0_origin
                = (minus_lit0 != 0) + 2 * (minus_lit1 != 0);
-             var0 = associate_trees (loc, var0, var1, code, atype);
+             var0 = associate_trees (loc, var0, var1, assoc_code, atype);
              minus_var0 = associate_trees (loc, minus_var0, minus_var1,
-                                           code, atype);
-             con0 = associate_trees (loc, con0, con1, code, atype);
+                                           assoc_code, atype);
+             con0 = associate_trees (loc, con0, con1, assoc_code, atype);
              minus_con0 = associate_trees (loc, minus_con0, minus_con1,
-                                           code, atype);
-             lit0 = associate_trees (loc, lit0, lit1, code, atype);
+                                           assoc_code, atype);
+             lit0 = associate_trees (loc, lit0, lit1, assoc_code, atype);
              minus_lit0 = associate_trees (loc, minus_lit0, minus_lit1,
-                                           code, atype);
+                                           assoc_code, atype);
 
              if (minus_var0 && var0)
                {
@@ -11591,14 +11618,14 @@ fold_binary_loc (location_t loc, enum tree_code code, 
tree type,
              /* Don't introduce overflows through reassociation.  */
              if ((lit0 && TREE_OVERFLOW_P (lit0))
                  || (minus_lit0 && TREE_OVERFLOW_P (minus_lit0)))
-               return NULL_TREE;
+               break;
 
              /* Eliminate lit0 and minus_lit0 to con0 and minus_con0. */
              con0_origin |= lit0_origin;
-             con0 = associate_trees (loc, con0, lit0, code, atype);
+             con0 = associate_trees (loc, con0, lit0, assoc_code, atype);
              minus_con0_origin |= minus_lit0_origin;
              minus_con0 = associate_trees (loc, minus_con0, minus_lit0,
-                                           code, atype);
+                                           assoc_code, atype);
 
              /* Eliminate minus_con0.  */
              if (minus_con0)
@@ -11637,15 +11664,15 @@ fold_binary_loc (location_t loc, enum tree_code code, 
tree type,
                 least one of the operands, otherwise we risk infinite
                 recursion.  See PR114084.  */
              if (var0_origin != 3 && con0_origin != 3)
-               return NULL_TREE;
+               break;
 
              return
                fold_convert_loc (loc, type, associate_trees (loc, var0, con0,
-                                                             code, atype));
+                                                             assoc_code, 
atype));
            }
        }
 
-      return NULL_TREE;
+      break;
 
     case POINTER_DIFF_EXPR:
     case MINUS_EXPR:
@@ -11666,7 +11693,7 @@ fold_binary_loc (location_t loc, enum tree_code code, 
tree type,
 
       /* Further transformations are not for pointers.  */
       if (code == POINTER_DIFF_EXPR)
-       return NULL_TREE;
+       break;
 
       /* (-A) - B -> (-B) - A  where B is easily negated and we can swap.  */
       if (TREE_CODE (arg0) == NEGATE_EXPR
@@ -11974,7 +12001,7 @@ fold_binary_loc (location_t loc, enum tree_code code, 
tree type,
       if (TREE_CODE (arg1) == REAL_CST
          && !MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (arg1)))
          && real_zerop (arg1))
-       return NULL_TREE;
+       break;
 
       /* (-A) / (-B) -> A / B  */
       if (TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (arg1))
@@ -11985,7 +12012,7 @@ fold_binary_loc (location_t loc, enum tree_code code, 
tree type,
        return fold_build2_loc (loc, RDIV_EXPR, type,
                            negate_expr (arg0),
                            TREE_OPERAND (arg1, 0));
-      return NULL_TREE;
+      break;
 
     case TRUNC_DIV_EXPR:
       /* Fall through */
@@ -12023,7 +12050,7 @@ fold_binary_loc (location_t loc, enum tree_code code, 
tree type,
     case CEIL_DIV_EXPR:
     case EXACT_DIV_EXPR:
       if (integer_zerop (arg1))
-       return NULL_TREE;
+       break;
 
       /* Convert -A / -B to A / B when the type is signed and overflow is
         undefined.  */
@@ -12080,7 +12107,7 @@ fold_binary_loc (location_t loc, enum tree_code code, 
tree type,
          return fold_convert_loc (loc, type, tem);
        }
 
-      return NULL_TREE;
+      break;
 
     case CEIL_MOD_EXPR:
     case FLOOR_MOD_EXPR:
@@ -12098,7 +12125,7 @@ fold_binary_loc (location_t loc, enum tree_code code, 
tree type,
          return fold_convert_loc (loc, type, tem);
        }
 
-      return NULL_TREE;
+      break;
 
     case LROTATE_EXPR:
     case RROTATE_EXPR:
@@ -12107,7 +12134,7 @@ fold_binary_loc (location_t loc, enum tree_code code, 
tree type,
       /* Since negative shift count is not well-defined,
         don't try to compute it in the compiler.  */
       if (TREE_CODE (arg1) == INTEGER_CST && tree_int_cst_sgn (arg1) < 0)
-       return NULL_TREE;
+       break;
 
       prec = element_precision (type);
 
@@ -12129,7 +12156,7 @@ fold_binary_loc (location_t loc, enum tree_code code, 
tree type,
                                                   arg01, arg1));
        }
 
-      return NULL_TREE;
+      break;
 
     case MIN_EXPR:
     case MAX_EXPR:
@@ -12193,7 +12220,7 @@ fold_binary_loc (location_t loc, enum tree_code code, 
tree type,
           != NULL_TREE)
         return tem;
 
-      return NULL_TREE;
+      break;
 
     case TRUTH_ORIF_EXPR:
       /* Note that the operands of this must be ints
@@ -12255,7 +12282,7 @@ fold_binary_loc (location_t loc, enum tree_code code, 
tree type,
           != NULL_TREE)
         return tem;
 
-      return NULL_TREE;
+      break;
 
     case TRUTH_XOR_EXPR:
       /* If the second arg is constant zero, drop it.  */
@@ -12281,7 +12308,7 @@ fold_binary_loc (location_t loc, enum tree_code code, 
tree type,
          && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
        return omit_one_operand_loc (loc, type, integer_one_node, arg0);
 
-      return NULL_TREE;
+      break;
 
     case EQ_EXPR:
     case NE_EXPR:
@@ -12564,7 +12591,7 @@ fold_binary_loc (location_t loc, enum tree_code code, 
tree type,
            }
        }
 
-      return NULL_TREE;
+      break;
 
     case LT_EXPR:
     case GT_EXPR:
@@ -12701,7 +12728,7 @@ fold_binary_loc (location_t loc, enum tree_code code, 
tree type,
                             build_zero_cst (TREE_TYPE (arg0)));
        }
 
-      return NULL_TREE;
+      break;
 
     case UNORDERED_EXPR:
     case ORDERED_EXPR:
@@ -12727,21 +12754,47 @@ fold_binary_loc (location_t loc, enum tree_code code, 
tree type,
                              fold_convert_loc (loc, newtype, targ1));
       }
 
-      return NULL_TREE;
+      break;
 
     case COMPOUND_EXPR:
       /* When pedantic, a compound expression can be neither an lvalue
         nor an integer constant expression.  */
       if (TREE_SIDE_EFFECTS (arg0) || TREE_CONSTANT (arg1))
-       return NULL_TREE;
+       break;
       /* Don't let (0, 0) be null pointer constant.  */
       tem = integer_zerop (arg1) ? build1_loc (loc, NOP_EXPR, type, arg1)
                                 : fold_convert_loc (loc, type, arg1);
       return tem;
 
     default:
-      return NULL_TREE;
+      break;
     } /* switch (code) */
+
+  if (kind == tcc_comparison || kind == tcc_binary)
+    {
+      bool any_changed_op = false;
+      if (!stripped_converted_equals_original (arg0, op0))
+
+       {
+         op0 = fold_convert_loc (EXPR_HAS_LOCATION (op0)
+                                 ? EXPR_LOCATION (op0) : loc,
+                                 TREE_TYPE (op0), arg0);
+         any_changed_op = true;
+       }
+
+      if (!stripped_converted_equals_original (arg1, op1))
+       {
+         op1 = fold_convert_loc (EXPR_HAS_LOCATION (op1)
+                                 ? EXPR_LOCATION (op1) : loc,
+                                 TREE_TYPE (op1), arg1);
+         any_changed_op = true;
+       }
+
+      if (any_changed_op)
+       return fold_build2_loc (loc, code, type, op0, op1);
+    }
+
+  return NULL_TREE;
 }
 
 /* For constants M and N, if M == (1LL << cst) - 1 && (N & M) == M,
diff --git a/gcc/testsuite/gfortran.dg/non_lvalue_2.f90 
b/gcc/testsuite/gfortran.dg/non_lvalue_2.f90
new file mode 100644
index 000000000000..24eff12ea4d5
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/non_lvalue_2.f90
@@ -0,0 +1,58 @@
+! { dg-do compile }
+! { dg-additional-options "-funsigned -fdump-tree-original" }
+!
+! Check the unwrapping of the NON_LVALUE_EXPR that may com from an earlier
+! simplification, if it is used in a unary operator context.
+
+! The NON_LVALUE_EXPR is dropped if it's used as argument to an absolute value
+! operator.
+function f1 (f1_arg1)
+  integer, value :: f1_arg1
+  integer :: f1
+  f1 = abs(f1_arg1 + 0)
+end function
+! { dg-final { scan-tree-dump {__result_f1 = ABS_EXPR <f1_arg1>;} "original" } 
}
+
+! The NON_LVALUE_EXPR is dropped if it's used as argument to a complement
+! operator.
+function f2 (f2_arg1)
+  integer, value :: f2_arg1
+  integer :: f2
+  f2 = not(f2_arg1 + 0)
+end function
+! { dg-final { scan-tree-dump {__result_f2 = ~f2_arg1;} "original" } }
+
+! The NON_LVALUE_EXPR is dropped if it's used as argument to a conjugate
+! operator.
+function f3 (f3_arg1)
+  complex, value :: f3_arg1
+  complex :: f3
+  f3 = conjg(conjg(conjg(f3_arg1)))
+end function
+! { dg-final { scan-tree-dump {__result_f3 = CONJ_EXPR <f3_arg1>;} "original" 
} }
+
+! The NON_LVALUE_EXPR is dropped if it's used as argument to a type conversion
+! operator.
+function f4 (f4_arg1)
+  integer(kind=4), value :: f4_arg1
+  integer(kind=8) :: f4
+  f4 = f4_arg1 + 0
+end function
+! { dg-final { scan-tree-dump {__result_f4 = \(integer\(kind=8\)\) f4_arg1;} 
"original" } }
+
+! The NON_LVALUE_EXPR is dropped if it's used as argument to a float conversion
+! operator.
+function f5 (f5_arg1)
+  integer, value :: f5_arg1
+  real :: f5
+  f5 = f5_arg1 + 0
+end function
+! { dg-final { scan-tree-dump {__result_f5 = \(real\(kind=4\)\) f5_arg1;} 
"original" } }
+
+! The NON_LVALUE_EXPR is dropped if it's used as argument to a negate operator.
+function f6 (f6_arg1)
+  integer, value :: f6_arg1
+  integer :: f6
+  f6 = -not(not(f6_arg1))
+end function
+! { dg-final { scan-tree-dump {__result_f6 = -f6_arg1;} "original" } }
diff --git a/gcc/testsuite/gfortran.dg/non_lvalue_3.f90 
b/gcc/testsuite/gfortran.dg/non_lvalue_3.f90
new file mode 100644
index 000000000000..280859c133b8
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/non_lvalue_3.f90
@@ -0,0 +1,172 @@
+! { dg-do compile }
+! { dg-additional-options "-fdump-tree-original" }
+!
+! Check the unwrapping of the NON_LVALUE_EXPR that may come from an earlier
+! simplification, if it is used in a binary operator context.
+
+! The NON_LVALUE_EXPR is dropped if it's used as argument to a LT logical
+! operator
+subroutine f01 (f01_res1, f01_res2, f01_arg1, f01_arg2)
+  integer, value :: f01_arg1, f01_arg2
+  logical, intent(out) :: f01_res1, f01_res2
+  f01_res1 = f01_arg1 + 0 .lt. f01_arg2
+  f01_res2 = f01_arg1 .lt. f01_arg2 + 0
+end subroutine
+! { dg-final { scan-tree-dump {\*f01_res1 = f01_arg1 < f01_arg2;} "original" } 
}
+! { dg-final { scan-tree-dump {\*f01_res2 = f01_arg1 < f01_arg2;} "original" } 
}
+
+! The NON_LVALUE_EXPR is dropped if it's used as argument to a LE logical
+! operator
+subroutine f02 (f02_res1, f02_res2, f02_arg1, f02_arg2)
+  integer, value :: f02_arg1, f02_arg2
+  logical, intent(out) :: f02_res1, f02_res2
+  f02_res1 = f02_arg1 + 0 .le. f02_arg2
+  f02_res2 = f02_arg1 .le. f02_arg2 + 0
+end subroutine
+! { dg-final { scan-tree-dump {\*f02_res1 = f02_arg1 <= f02_arg2;} "original" 
} }
+! { dg-final { scan-tree-dump {\*f02_res2 = f02_arg1 <= f02_arg2;} "original" 
} }
+
+! The NON_LVALUE_EXPR is dropped if it's used as argument to a GT logical
+! operator
+subroutine f03 (f03_res1, f03_res2, f03_arg1, f03_arg2)
+  integer, value :: f03_arg1, f03_arg2
+  logical, intent(out) :: f03_res1, f03_res2
+  f03_res1 = f03_arg1 + 0 .gt. f03_arg2
+  f03_res2 = f03_arg1 .gt. f03_arg2 + 0
+end subroutine
+! { dg-final { scan-tree-dump {\*f03_res1 = f03_arg1 > f03_arg2;} "original" } 
}
+! { dg-final { scan-tree-dump {\*f03_res2 = f03_arg1 > f03_arg2;} "original" } 
}
+
+! The NON_LVALUE_EXPR is dropped if it's used as argument to a GE logical
+! operator
+subroutine f04 (f04_res1, f04_res2, f04_arg1, f04_arg2)
+  integer, value :: f04_arg1, f04_arg2
+  logical, intent(out) :: f04_res1, f04_res2
+  f04_res1 = f04_arg1 + 0 .ge. f04_arg2
+  f04_res2 = f04_arg1 .ge. f04_arg2 + 0
+end subroutine
+! { dg-final { scan-tree-dump {\*f04_res1 = f04_arg1 >= f04_arg2;} "original" 
} }
+! { dg-final { scan-tree-dump {\*f04_res2 = f04_arg1 >= f04_arg2;} "original" 
} }
+
+! The NON_LVALUE_EXPR is dropped if it's used as argument to a LTGT logical
+! operator
+subroutine f05 (f05_res1, f05_res2, f05_arg1, f05_arg2)
+  real, value :: f05_arg1, f05_arg2
+  logical, intent(out) :: f05_res1, f05_res2
+  f05_res1 = f05_arg1 * 1 .lt. f05_arg2 .or. f05_arg1 * 1 .gt. f05_arg2
+  f05_res2 = f05_arg1 .lt. f05_arg2 * 1 .or. f05_arg1 .gt. f05_arg2 * 1
+end subroutine
+! { dg-final { scan-tree-dump {\*f05_res1 = f05_arg1 <> f05_arg2;} "original" 
} }
+! { dg-final { scan-tree-dump {\*f05_res2 = f05_arg1 <> f05_arg2;} "original" 
} }
+
+! The NON_LVALUE_EXPR is dropped if it's used as argument to a EQ logical
+! operator
+subroutine f06 (f06_res1, f06_res2, f06_arg1, f06_arg2)
+  integer, value :: f06_arg1, f06_arg2
+  logical, intent(out) :: f06_res1, f06_res2
+  f06_res1 = f06_arg1 + 0 .eq. f06_arg2
+  f06_res2 = f06_arg1 .eq. f06_arg2 + 0
+end subroutine
+! { dg-final { scan-tree-dump {\*f06_res1 = f06_arg1 == f06_arg2;} "original" 
} }
+! { dg-final { scan-tree-dump {\*f06_res2 = f06_arg1 == f06_arg2;} "original" 
} }
+
+! The NON_LVALUE_EXPR is dropped if it's used as argument to a NE logical
+! operator
+subroutine f07 (f07_res1, f07_res2, f07_arg1, f07_arg2)
+  integer, value :: f07_arg1, f07_arg2
+  logical, intent(out) :: f07_res1, f07_res2
+  f07_res1 = f07_arg1 + 0 .ne. f07_arg2
+  f07_res2 = f07_arg1 .ne. f07_arg2 + 0
+end subroutine
+! { dg-final { scan-tree-dump {\*f07_res1 = f07_arg1 != f07_arg2;} "original" 
} }
+! { dg-final { scan-tree-dump {\*f07_res2 = f07_arg1 != f07_arg2;} "original" 
} }
+
+! The NON_LVALUE_EXPR is dropped if it's used as argument to a PLUS operator
+subroutine f08 (f08_res1, f08_res2, f08_arg1, f08_arg2)
+  integer, value :: f08_arg1, f08_arg2
+  integer, intent(out) :: f08_res1, f08_res2
+  f08_res1 = f08_arg1 * 1 + f08_arg2
+  f08_res2 = f08_arg1 + f08_arg2 * 1
+end subroutine
+! { dg-final { scan-tree-dump {\*f08_res1 = f08_arg1 \+ f08_arg2;} "original" 
} }
+! { dg-final { scan-tree-dump {\*f08_res2 = f08_arg1 \+ f08_arg2;} "original" 
} }
+
+! The NON_LVALUE_EXPR is dropped if it's used as argument to a MINUS operator
+subroutine f09 (f09_res1, f09_res2, f09_arg1, f09_arg2)
+  integer, value :: f09_arg1, f09_arg2
+  integer, intent(out) :: f09_res1, f09_res2
+  f09_res1 = f09_arg1 * 1 - f09_arg2
+  f09_res2 = f09_arg1 - f09_arg2 * 1
+end subroutine
+! { dg-final { scan-tree-dump {\*f09_res1 = f09_arg1 - f09_arg2;} "original" } 
}
+! { dg-final { scan-tree-dump {\*f09_res2 = f09_arg1 - f09_arg2;} "original" } 
}
+
+! The NON_LVALUE_EXPR is dropped if it's used as argument to a MULT operator
+subroutine f10 (f10_res1, f10_res2, f10_arg1, f10_arg2)
+  integer, value :: f10_arg1, f10_arg2
+  integer, intent(out) :: f10_res1, f10_res2
+  f10_res1 = not(not(f10_arg1)) * f10_arg2
+  f10_res2 = f10_arg1 * not(not(f10_arg2))
+end subroutine
+! { dg-final { scan-tree-dump {\*f10_res1 = f10_arg1 \* f10_arg2;} "original" 
} }
+! { dg-final { scan-tree-dump {\*f10_res2 = f10_arg1 \* f10_arg2;} "original" 
} }
+
+! The NON_LVALUE_EXPR is dropped if it's used as argument to a DIV operator
+subroutine f11 (f11_res1, f11_res2, f11_arg1, f11_arg2)
+  integer, value :: f11_arg1, f11_arg2
+  integer, intent(out) :: f11_res1, f11_res2
+  f11_res1 = not(not(f11_arg1)) / f11_arg2
+  f11_res2 = f11_arg1 / not(not(f11_arg2))
+end subroutine
+! { dg-final { scan-tree-dump {\*f11_res1 = f11_arg1 / f11_arg2;} "original" } 
}
+! { dg-final { scan-tree-dump {\*f11_res2 = f11_arg1 / f11_arg2;} "original" } 
}
+
+! The NON_LVALUE_EXPR is dropped if it's used as argument to a MOD operator
+subroutine f12 (f12_res1, f12_res2, f12_arg1, f12_arg2)
+  integer, value :: f12_arg1, f12_arg2
+  integer, intent(out) :: f12_res1, f12_res2
+  f12_res1 = mod(f12_arg1 + 0, f12_arg2)
+  f12_res2 = mod(f12_arg1, f12_arg2 + 0)
+end subroutine
+! { dg-final { scan-tree-dump {\*f12_res1 = f12_arg1 % f12_arg2;} "original" } 
}
+! { dg-final { scan-tree-dump {\*f12_res2 = f12_arg1 % f12_arg2;} "original" } 
}
+
+! The NON_LVALUE_EXPR is dropped if it's used as argument to an OR operator
+subroutine f13 (f13_res1, f13_res2, f13_arg1, f13_arg2)
+  integer, value :: f13_arg1, f13_arg2
+  integer, intent(out) :: f13_res1, f13_res2
+  f13_res1 = ior(f13_arg1 + 0, f13_arg2)
+  f13_res2 = ior(f13_arg1, f13_arg2 + 0)
+end subroutine
+! { dg-final { scan-tree-dump {\*f13_res1 = f13_arg1 \| f13_arg2;} "original" 
} }
+! { dg-final { scan-tree-dump {\*f13_res2 = f13_arg1 \| f13_arg2;} "original" 
} }
+
+! The NON_LVALUE_EXPR is dropped if it's used as argument to a XOR operator
+subroutine f14 (f14_res1, f14_res2, f14_arg1, f14_arg2)
+  integer, value :: f14_arg1, f14_arg2
+  integer, intent(out) :: f14_res1, f14_res2
+  f14_res1 = ieor(f14_arg1 + 0, f14_arg2)
+  f14_res2 = ieor(f14_arg1, f14_arg2 + 0)
+end subroutine
+! { dg-final { scan-tree-dump {\*f14_res1 = f14_arg1 \^ f14_arg2;} "original" 
} }
+! { dg-final { scan-tree-dump {\*f14_res2 = f14_arg1 \^ f14_arg2;} "original" 
} }
+
+! The NON_LVALUE_EXPR is dropped if it's used as argument to an AND operator
+subroutine f15 (f15_res1, f15_res2, f15_arg1, f15_arg2)
+  integer, value :: f15_arg1, f15_arg2
+  integer, intent(out) :: f15_res1, f15_res2
+  f15_res1 = iand(f15_arg1 + 0, f15_arg2)
+  f15_res2 = iand(f15_arg1, f15_arg2 + 0)
+end subroutine
+! { dg-final { scan-tree-dump {\*f15_res1 = f15_arg1 & f15_arg2;} "original" } 
}
+! { dg-final { scan-tree-dump {\*f15_res2 = f15_arg1 & f15_arg2;} "original" } 
}
+
+! The NON_LVALUE_EXPR is dropped if it's used as argument to a complex 
constructor
+subroutine f16 (f16_res1, f16_res2, f16_arg1, f16_arg2)
+  real, value :: f16_arg1, f16_arg2
+  complex, intent(out) :: f16_res1, f16_res2
+  f16_res1 = cmplx(f16_arg1 * 1, f16_arg2)
+  f16_res2 = cmplx(f16_arg1, f16_arg2 * 1)
+end subroutine
+! { dg-final { scan-tree-dump {\*f16_res1 = COMPLEX_EXPR <f16_arg1, 
f16_arg2>;} "original" } }
+! { dg-final { scan-tree-dump {\*f16_res2 = COMPLEX_EXPR <f16_arg1, 
f16_arg2>;} "original" } }

Reply via email to