https://gcc.gnu.org/g:05bb1a71fb052d9145c010e4431d8bc01fb44115

commit 05bb1a71fb052d9145c010e4431d8bc01fb44115
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
    
    Regression tested on x86_64-linux.  OK for master?
    
    -- 8< --
    
    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.
    
    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 (maybe_lvalue_p): New overload, split from the
            original function.
            (stripped_converted_equals_original): New predicate function.
            (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                          | 228 ++++++++++++++++++-----------
 gcc/testsuite/gfortran.dg/non_lvalue_2.f90 |  58 ++++++++
 gcc/testsuite/gfortran.dg/non_lvalue_3.f90 | 172 ++++++++++++++++++++++
 3 files changed, 375 insertions(+), 83 deletions(-)

diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
index 014f42187932..867ef7017b0d 100644
--- a/gcc/fold-const.cc
+++ b/gcc/fold-const.cc
@@ -2790,56 +2790,65 @@ fold_convert_loc (location_t loc, tree type, tree arg)
   return tem;
 }
 
-/* Return false if expr can be assumed not to be an lvalue, true
-   otherwise.  */
+/* Return false if a tree whose code is CODE can be assumed not to represent an
+   lvalue, true otherwise.  */
 
 static bool
-maybe_lvalue_p (const_tree x)
+maybe_lvalue_p (enum tree_code code)
 {
   /* We only need to wrap lvalue tree codes.  */
-  switch (TREE_CODE (x))
-  {
-  case VAR_DECL:
-  case PARM_DECL:
-  case RESULT_DECL:
-  case LABEL_DECL:
-  case FUNCTION_DECL:
-  case SSA_NAME:
-  case COMPOUND_LITERAL_EXPR:
-
-  case COMPONENT_REF:
-  case MEM_REF:
-  case INDIRECT_REF:
-  case ARRAY_REF:
-  case ARRAY_RANGE_REF:
-  case BIT_FIELD_REF:
-  case OBJ_TYPE_REF:
-
-  case REALPART_EXPR:
-  case IMAGPART_EXPR:
-  case PREINCREMENT_EXPR:
-  case PREDECREMENT_EXPR:
-  case SAVE_EXPR:
-  case TRY_CATCH_EXPR:
-  case WITH_CLEANUP_EXPR:
-  case COMPOUND_EXPR:
-  case MODIFY_EXPR:
-  case TARGET_EXPR:
-  case COND_EXPR:
-  case BIND_EXPR:
-  case VIEW_CONVERT_EXPR:
-    break;
+  switch (code)
+    {
+    case VAR_DECL:
+    case PARM_DECL:
+    case RESULT_DECL:
+    case LABEL_DECL:
+    case FUNCTION_DECL:
+    case SSA_NAME:
+    case COMPOUND_LITERAL_EXPR:
+
+    case COMPONENT_REF:
+    case MEM_REF:
+    case INDIRECT_REF:
+    case ARRAY_REF:
+    case ARRAY_RANGE_REF:
+    case BIT_FIELD_REF:
+    case OBJ_TYPE_REF:
 
-  default:
-    /* Assume the worst for front-end tree codes.  */
-    if ((int)TREE_CODE (x) >= NUM_TREE_CODES)
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+    case PREINCREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+    case SAVE_EXPR:
+    case TRY_CATCH_EXPR:
+    case WITH_CLEANUP_EXPR:
+    case COMPOUND_EXPR:
+    case MODIFY_EXPR:
+    case TARGET_EXPR:
+    case COND_EXPR:
+    case BIND_EXPR:
+    case VIEW_CONVERT_EXPR:
       break;
-    return false;
-  }
+
+    default:
+      /* Assume the worst for front-end tree codes.  */
+      if ((int)code >= NUM_TREE_CODES)
+       break;
+      return false;
+    }
 
   return true;
 }
 
+/* Return false if expr can be assumed not to be an lvalue, true
+   otherwise.  */
+
+static bool
+maybe_lvalue_p (const_tree x)
+{
+  return maybe_lvalue_p (TREE_CODE (x));
+}
+
 /* Return an expr equal to X but certainly not valid as an lvalue.  */
 
 tree
@@ -9181,6 +9190,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 +9323,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 +9461,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 +9471,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 +9520,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 +9533,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 +9553,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 +9572,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 +9581,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 +9595,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 +11179,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 +11199,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 +11484,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 +11568,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 +11627,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 +11673,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 +11702,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 +12010,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 +12021,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 +12059,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 +12116,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 +12134,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 +12143,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 +12165,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 +12229,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 +12291,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 +12317,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 +12600,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 +12737,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 +12763,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