+
/* Simplify x - x.
This is unsafe for certain floats even in non-IEEE formats.
In IEEE, it is unsafe because it does wrong for NaNs.
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 00000000000..24eff12ea4d
--- /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 00000000000..280859c133b
--- /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" } }
--
2.47.2