This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[patch,libfortran] PR31964 ishftc fails with certain thrid argument
- From: Jerry DeLisle <jvdelisle at verizon dot net>
- To: Fortran List <fortran at gcc dot gnu dot org>
- Cc: gcc-patches <gcc-patches at gcc dot gnu dot org>
- Date: Thu, 17 May 2007 18:14:53 -0700
- Subject: [patch,libfortran] PR31964 ishftc fails with certain thrid argument
Hi,
Fortran defines bit shifting up to and including bit_size of a value.
It turns out that shifting is undefined for >= bit_size bits. In the test case
reported, we are trying to shift a 32 bit word, 32 times. The ishftc function
tried to do this, but no can do. (Thank you Andrew for pointing that out and I
confirmed it looking in K&R)
To fix this, the patch special cases the mask for this situation. I took the
liberty to do a few other minor tweaks so that the result looks logical to me.
In particular, not using the original incoming word as operand for the right
shift. I also arranged the shifting left to right in the result statement.
Updated test case is attached.
Regression tested on X86-64.
OK for trunk and I assume 4.2 when open, and 4.1 after that?
Regards,
Jerry
2007-05-17 Jerry DeLisle <jvdelisle@gcc.gnu.org>
PR libfortran/31964
* intrinsics/ishftc.c (ishftc4, ishftc8, ishftc16): Fix mask to handle
shift of bit-size number of bits.
Index: ishftc.c
===================================================================
*** ishftc.c (revision 124756)
--- ishftc.c (working copy)
*************** export_proto(ishftc4);
*** 36,43 ****
GFC_INTEGER_4
ishftc4 (GFC_INTEGER_4 i, GFC_INTEGER_4 shift, GFC_INTEGER_4 size)
{
! GFC_INTEGER_4 mask;
! GFC_UINTEGER_4 bits;
if (shift < 0)
shift = shift + size;
--- 36,42 ----
GFC_INTEGER_4
ishftc4 (GFC_INTEGER_4 i, GFC_INTEGER_4 shift, GFC_INTEGER_4 size)
{
! GFC_UINTEGER_4 mask, bits;
if (shift < 0)
shift = shift + size;
*************** ishftc4 (GFC_INTEGER_4 i, GFC_INTEGER_4
*** 45,53 ****
if (shift == 0 || shift == size)
return i;
! mask = (~(GFC_INTEGER_4)0) << size;
! bits = i & ~mask;
! return (i & mask) | (bits >> (size - shift)) | ((i << shift) & ~mask);
}
extern GFC_INTEGER_8 ishftc8 (GFC_INTEGER_8, GFC_INTEGER_4, GFC_INTEGER_4);
--- 44,57 ----
if (shift == 0 || shift == size)
return i;
! /* In C, the result of the shift operator is undefined if the right operand
! is greater than or equal to the number of bits in the left operand. So we
! have to special case it for fortran. */
! mask = ~((size == 32) ? 0 : (~0 << size));
!
! bits = i & mask;
!
! return (i & ~mask) | ((bits << shift) & mask) | (bits >> (size - shift));
}
extern GFC_INTEGER_8 ishftc8 (GFC_INTEGER_8, GFC_INTEGER_4, GFC_INTEGER_4);
*************** export_proto(ishftc8);
*** 56,63 ****
GFC_INTEGER_8
ishftc8 (GFC_INTEGER_8 i, GFC_INTEGER_4 shift, GFC_INTEGER_4 size)
{
! GFC_INTEGER_8 mask;
! GFC_UINTEGER_8 bits;
if (shift < 0)
shift = shift + size;
--- 60,66 ----
GFC_INTEGER_8
ishftc8 (GFC_INTEGER_8 i, GFC_INTEGER_4 shift, GFC_INTEGER_4 size)
{
! GFC_UINTEGER_8 mask, bits;
if (shift < 0)
shift = shift + size;
*************** ishftc8 (GFC_INTEGER_8 i, GFC_INTEGER_4
*** 65,73 ****
if (shift == 0 || shift == size)
return i;
! mask = (~(GFC_INTEGER_8)0) << size;
! bits = i & ~mask;
! return (i & mask) | (bits >> (size - shift)) | ((i << shift) & ~mask);
}
#ifdef HAVE_GFC_INTEGER_16
--- 68,81 ----
if (shift == 0 || shift == size)
return i;
! /* In C, the result of the shift operator is undefined if the right operand
! is greater than or equal to the number of bits in the left operand. So we
! have to special case it for fortran. */
! mask = ~((size == 64) ? 0 : (~0 << size));
!
! bits = i & mask;
!
! return (i & ~mask) | ((bits << shift) & mask) | (bits >> (size - shift));
}
#ifdef HAVE_GFC_INTEGER_16
*************** export_proto(ishftc16);
*** 77,84 ****
GFC_INTEGER_16
ishftc16 (GFC_INTEGER_16 i, GFC_INTEGER_4 shift, GFC_INTEGER_4 size)
{
! GFC_INTEGER_16 mask;
! GFC_UINTEGER_16 bits;
if (shift < 0)
shift = shift + size;
--- 85,91 ----
GFC_INTEGER_16
ishftc16 (GFC_INTEGER_16 i, GFC_INTEGER_4 shift, GFC_INTEGER_4 size)
{
! GFC_UINTEGER_16 mask, bits;
if (shift < 0)
shift = shift + size;
*************** ishftc16 (GFC_INTEGER_16 i, GFC_INTEGER_
*** 86,93 ****
if (shift == 0 || shift == size)
return i;
! mask = (~(GFC_INTEGER_16)0) << size;
! bits = i & ~mask;
! return (i & mask) | (bits >> (size - shift)) | ((i << shift) & ~mask);
}
#endif
--- 93,105 ----
if (shift == 0 || shift == size)
return i;
! /* In C, the result of the shift operator is undefined if the right operand
! is greater than or equal to the number of bits in the left operand. So we
! have to special case it for fortran. */
! mask = ~((size == 128) ? 0 : (~0 << size));
!
! bits = i & mask;
!
! return (i & ~mask) | ((bits << shift) & mask) | (bits >> (size - shift));
}
#endif
! Program to test intrinsic bitops
program intrinsic_bitops
implicit none
integer(kind=4) :: i, j, k, o, t
integer(kind=8) :: a, b, c
o = 0
i = 2
j = 3
k = 12
a = 5
if (.not. btest (i, o+1)) call abort
if (btest (i, o+2)) call abort
if (iand (i, j) .ne. 2) call abort
if (ibclr (j, o+1) .ne. 1) call abort
if (ibclr (j, o+2) .ne. 3) call abort
if (ibits (k, o+1, o+2) .ne. 2) call abort
if (ibset (j, o+1) .ne. 3) call abort
if (ibset (j, o+2) .ne. 7) call abort
if (ieor (i, j) .ne. 1) call abort
if (ior (i, j) .ne. 3) call abort
if (ishft (k, o+2) .ne. 48) call abort
if (ishft (k, o-3) .ne. 1) call abort
if (ishft (k, o) .ne. 12) call abort
if (ishftc (k, o+30) .ne. 3) call abort
if (ishftc (k, o-30) .ne. 48) call abort
if (ishftc (k, o+1, o+3) .ne. 9) call abort
if (not (i) .ne. -3) call abort
if (ishftc (a, 1, bit_size(a)) .ne. 10) call abort
if (ishftc (1, 1, 32) .ne. 2) call abort
end program