From d0442491d506497f9c7e8bfa6f0e9edb16d21306 Mon Sep 17 00:00:00 2001 From: Harald Anlauf Date: Fri, 14 Jun 2019 18:41:20 +0000 Subject: [PATCH] re PR fortran/90577 (FAIL: gfortran.dg/lrshift_1.f90 with -O(2|3) and -flto) 2019-06-14 Harald Anlauf PR fortran/90577 PR fortran/90578 * trans-intrinsic.c (gfc_conv_intrinsic_shift): Properly distinguish logical/arithmetic shifts. * intrinsic.texi: Update documentation for SHIFTR/SHIFTL/SHIFTA (Fortran 2008) and LSHIFT/RSHIFT (GNU extensions). PR fortran/90577 PR fortran/90578 * gfortran.dg/lrshift_1.f90: Adjust testcase. * gfortran.dg/shiftalr_3.f90: New testcase. From-SVN: r272309 --- gcc/fortran/ChangeLog | 9 +++++++ gcc/fortran/intrinsic.texi | 46 +++++++++++++++++--------------- gcc/fortran/trans-intrinsic.c | 15 ++++++++++- gcc/testsuite/ChangeLog | 7 +++++ gcc/testsuite/gfortran.dg/lrshift_1.f90 | 2 +- gcc/testsuite/gfortran.dg/shiftalr_3.f90 | 42 +++++++++++++++++++++++++++++ 6 files changed, 97 insertions(+), 24 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/shiftalr_3.f90 diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 9a82b9b..def1810 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,12 @@ +2019-06-14 Harald Anlauf + + PR fortran/90577 + PR fortran/90578 + * trans-intrinsic.c (gfc_conv_intrinsic_shift): Properly + distinguish logical/arithmetic shifts. + * intrinsic.texi: Update documentation for SHIFTR/SHIFTL/SHIFTA + (Fortran 2008) and LSHIFT/RSHIFT (GNU extensions). + 2019-06-14 Steven G. Kargl PR fortran/89646 diff --git a/gcc/fortran/intrinsic.texi b/gcc/fortran/intrinsic.texi index f3f4c00..f390761 100644 --- a/gcc/fortran/intrinsic.texi +++ b/gcc/fortran/intrinsic.texi @@ -9689,10 +9689,10 @@ The return value is a @code{INTEGER(4)} variable. @table @asis @item @emph{Description}: @code{LSHIFT} returns a value corresponding to @var{I} with all of the -bits shifted left by @var{SHIFT} places. If the absolute value of -@var{SHIFT} is greater than @code{BIT_SIZE(I)}, the value is undefined. -Bits shifted out from the left end are lost; zeros are shifted in from -the opposite end. +bits shifted left by @var{SHIFT} places. @var{SHIFT} shall be +nonnegative and less than or equal to @code{BIT_SIZE(I)}, otherwise +the result value is undefined. Bits shifted out from the left end are +lost; zeros are shifted in from the opposite end. This function has been superseded by the @code{ISHFT} intrinsic, which is standard in Fortran 95 and later, and the @code{SHIFTL} intrinsic, @@ -12244,11 +12244,12 @@ The value returned is equal to @table @asis @item @emph{Description}: @code{RSHIFT} returns a value corresponding to @var{I} with all of the -bits shifted right by @var{SHIFT} places. If the absolute value of -@var{SHIFT} is greater than @code{BIT_SIZE(I)}, the value is undefined. -Bits shifted out from the right end are lost. The fill is arithmetic: the -bits shifted in from the left end are equal to the leftmost bit, which in -two's complement representation is the sign bit. +bits shifted right by @var{SHIFT} places. @var{SHIFT} shall be +nonnegative and less than or equal to @code{BIT_SIZE(I)}, otherwise +the result value is undefined. Bits shifted out from the right end +are lost. The fill is arithmetic: the bits shifted in from the left +end are equal to the leftmost bit, which in two's complement +representation is the sign bit. This function has been superseded by the @code{SHIFTA} intrinsic, which is standard in Fortran 2008 and later. @@ -12783,11 +12784,12 @@ END PROGRAM @table @asis @item @emph{Description}: @code{SHIFTA} returns a value corresponding to @var{I} with all of the -bits shifted right by @var{SHIFT} places. If the absolute value of -@var{SHIFT} is greater than @code{BIT_SIZE(I)}, the value is undefined. -Bits shifted out from the right end are lost. The fill is arithmetic: the -bits shifted in from the left end are equal to the leftmost bit, which in -two's complement representation is the sign bit. +bits shifted right by @var{SHIFT} places. @var{SHIFT} that be +nonnegative and less than or equal to @code{BIT_SIZE(I)}, otherwise +the result value is undefined. Bits shifted out from the right end +are lost. The fill is arithmetic: the bits shifted in from the left +end are equal to the leftmost bit, which in two's complement +representation is the sign bit. @item @emph{Standard}: Fortran 2008 and later @@ -12823,10 +12825,10 @@ The return value is of type @code{INTEGER} and of the same kind as @table @asis @item @emph{Description}: @code{SHIFTL} returns a value corresponding to @var{I} with all of the -bits shifted left by @var{SHIFT} places. If the absolute value of -@var{SHIFT} is greater than @code{BIT_SIZE(I)}, the value is undefined. -Bits shifted out from the left end are lost, and bits shifted in from -the right end are set to 0. +bits shifted left by @var{SHIFT} places. @var{SHIFT} shall be +nonnegative and less than or equal to @code{BIT_SIZE(I)}, otherwise +the result value is undefined. Bits shifted out from the left end are +lost, and bits shifted in from the right end are set to 0. @item @emph{Standard}: Fortran 2008 and later @@ -12862,10 +12864,10 @@ The return value is of type @code{INTEGER} and of the same kind as @table @asis @item @emph{Description}: @code{SHIFTR} returns a value corresponding to @var{I} with all of the -bits shifted right by @var{SHIFT} places. If the absolute value of -@var{SHIFT} is greater than @code{BIT_SIZE(I)}, the value is undefined. -Bits shifted out from the right end are lost, and bits shifted in from -the left end are set to 0. +bits shifted right by @var{SHIFT} places. @var{SHIFT} shall be +nonnegative and less than or equal to @code{BIT_SIZE(I)}, otherwise +the result value is undefined. Bits shifted out from the right end +are lost, and bits shifted in from the left end are set to 0. @item @emph{Standard}: Fortran 2008 and later diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c index f6edd68..cc041f9 100644 --- a/gcc/fortran/trans-intrinsic.c +++ b/gcc/fortran/trans-intrinsic.c @@ -6346,6 +6346,7 @@ gfc_conv_intrinsic_shift (gfc_se * se, gfc_expr * expr, bool right_shift, bool arithmetic) { tree args[2], type, num_bits, cond; + tree bigshift; gfc_conv_intrinsic_function_args (se, expr, args, 2); @@ -6365,6 +6366,18 @@ gfc_conv_intrinsic_shift (gfc_se * se, gfc_expr * expr, bool right_shift, if (!arithmetic) se->expr = fold_convert (type, se->expr); + if (!arithmetic) + bigshift = build_int_cst (type, 0); + else + { + tree nonneg = fold_build2_loc (input_location, GE_EXPR, + logical_type_node, args[0], + build_int_cst (TREE_TYPE (args[0]), 0)); + bigshift = fold_build3_loc (input_location, COND_EXPR, type, nonneg, + build_int_cst (type, 0), + build_int_cst (type, -1)); + } + /* The Fortran standard allows shift widths <= BIT_SIZE(I), whereas gcc requires a shift width < BIT_SIZE(I), so we have to catch this special case. */ @@ -6373,7 +6386,7 @@ gfc_conv_intrinsic_shift (gfc_se * se, gfc_expr * expr, bool right_shift, args[1], num_bits); se->expr = fold_build3_loc (input_location, COND_EXPR, type, cond, - build_int_cst (type, 0), se->expr); + bigshift, se->expr); } /* ISHFT (I, SHIFT) = (abs (shift) >= BIT_SIZE (i)) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8ab6cb4..7332d53 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2019-06-14 Harald Anlauf + + PR fortran/90577 + PR fortran/90578 + * gfortran.dg/lrshift_1.f90: Adjust testcase. + * gfortran.dg/shiftalr_3.f90: New testcase. + 2019-06-14 Steven G. Kargl PR fortran/89646 diff --git a/gcc/testsuite/gfortran.dg/lrshift_1.f90 b/gcc/testsuite/gfortran.dg/lrshift_1.f90 index b0e5379..d262921 100644 --- a/gcc/testsuite/gfortran.dg/lrshift_1.f90 +++ b/gcc/testsuite/gfortran.dg/lrshift_1.f90 @@ -10,7 +10,7 @@ program test_rshift_lshift 1, 2, 127, 128, 129, huge(i)/2, huge(i) /) do n = 1, size(i) - do j = -30, 30 + do j = 0, 31 if (lshift(i(n),j) /= c_lshift(i(n),j)) STOP 1 if (rshift(i(n),j) /= c_rshift(i(n),j)) STOP 2 end do diff --git a/gcc/testsuite/gfortran.dg/shiftalr_3.f90 b/gcc/testsuite/gfortran.dg/shiftalr_3.f90 new file mode 100644 index 0000000..4eb0ba7 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/shiftalr_3.f90 @@ -0,0 +1,42 @@ +! { dg-do run } +! +! Test shift intrinsics when the SHIFT argument equals BIT_SIZE(arg1). + +program test + implicit none + ! Test compile-time simplifications + if (ishft (-1, 32) /= 0) stop 1 ! 0 -> simplify_shift OK + if (ishft (-1,-32) /= 0) stop 2 ! 0 -> simplify_shift OK + if (shiftl (-1, 32) /= 0) stop 3 ! 0 -> simplify_shift OK + if (shiftr (-1, 32) /= 0) stop 4 ! 0 -> simplify_shift OK + if (shifta (-1, 32) /= -1) stop 5 ! -1 -> simplify_shift OK + if (rshift (-1, 32) /= -1) stop 6 ! -1 -> simplify_shift OK + if (lshift (-1, 32) /= 0) stop 7 ! 0 -> simplify_shift OK + ! Test run-time + call foo (-1) +contains + subroutine foo (n) + integer(4) :: i, j, k, n + integer, parameter :: bb = bit_size (n) + ! Test code generated by gfc_conv_intrinsic_ishft + i = ishft (n, bb) ! Logical (left) shift (Fortran 2008) + j = ishft (n,-bb) ! Logical (right) shift (Fortran 2008) + if (i /= 0) stop 11 + if (j /= 0) stop 12 + ! Test code generated by gfc_conv_intrinsic_shift: + i = shiftl (n, bb) ! Logical left shift (Fortran 2008) + j = shiftr (n, bb) ! Logical right shift (Fortran 2008) + k = shifta (n, bb) ! Arithmetic right shift (Fortran 2008) + if (i /= 0) stop 13 + if (j /= 0) stop 14 + if (k /= -1) stop 15 + i = lshift (n, bb) ! Logical left shift (GNU extension) + j = rshift (n, bb) ! Arithmetic right shift (GNU extension) + if (i /= 0) stop 16 + if (j /= -1) stop 17 + do i = bb-1,bb + if (shifta (n, i) /= -1) stop 18 + if (rshift (n, i) /= -1) stop 19 + end do + end subroutine foo +end program test -- 2.7.4