Bug 33330 - [4.3 Regression] Wrong alias for accessing scalar through array
Summary: [4.3 Regression] Wrong alias for accessing scalar through array
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 4.3.0
: P3 normal
Target Milestone: 4.3.0
Assignee: Richard Biener
URL:
Keywords: alias, wrong-code
Depends on:
Blocks:
 
Reported: 2007-09-07 06:36 UTC by Dominique d'Humieres
Modified: 2007-09-07 12:47 UTC (History)
4 users (show)

See Also:
Host: powerpc-apple-darwin8
Target: powerpc-apple-darwin8
Build: powerpc-apple-darwin8
Known to work:
Known to fail:
Last reconfirmed: 2007-09-07 11:45:21


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Dominique d'Humieres 2007-09-07 06:36:43 UTC
copy of http://gcc.gnu.org/ml/fortran/2007-09/msg00121.html:

I have done some investigation about the recent failure of gfortran.dg/c_char_tests.f03. First the failure disappears with -fno-inline or -fno-inline-functions:

[karma] f90/bug% gfc c_char_tests_db.f03 -O3 -fno-inline c_char_driver_db.c
[karma] f90/bug% a.out
[karma] f90/bug% gfc c_char_tests_db.f03 -O3 -fno-inline-functions c_char_driver_db.c
[karma] f90/bug% a.out

Second, if I remove the line"   sub0();" in c_char_driver.c, the test succeeds, so the C driver can be reduced to:

[karma] f90/bug% cat c_char_driver_red.c
void sub0(void);

int main(int argc, char **argv)
{
  char my_char = 'y';
  
  sub0();
  
  return 0;
}

with the same behavior. Now the stange part: if I try the following reduced code:

! { dg-do run }
! { dg-additional-sources c_char_driver.c }
! Verify that character dummy arguments for bind(c) procedures can work both 
! by-value and by-reference when called by either C or Fortran.
! PR fortran/32732
module c_char_tests
  use, intrinsic :: iso_c_binding, only: c_char
  implicit none
contains
  subroutine param_test(my_char) bind(c)
    character(c_char), value :: my_char
    
    call sub1(my_char)
  end subroutine param_test

  subroutine sub0() bind(c)
    call param_test('y')
  end subroutine sub0

  subroutine sub1(my_char_ref) bind(c)
    character(c_char) :: my_char_ref
    if(my_char_ref /= c_char_'y') call abort()
  end subroutine sub1
end module c_char_tests

! { dg-final { cleanup-modules "c_char_tests" } }

I get:

[karma] f90/bug% gfc c_char_tests_red.f03 -O3 -fno-inline-functions c_char_driver_red.c
[karma] f90/bug% a.out
Abort
[karma] f90/bug% gfc c_char_tests_red.f03 -O3 -fno-inline-functions -fno-inline c_char_driver_red.c
[karma] f90/bug% a.out

Wierd, isn't it?

So if one wants an immediate clean test suite, add -fno-inline-functions. Now clearly the new version of GCC inlines more than the previous one, with two failing cases. The first one (do_3) is a very borderline one, testing folding after integer overflows and I think the addition of -fno-strict-overflow is enough. In my opinion, the second case requires further investigation, but I don't think it would be a good idea to try to prevent the new inlining (unless we discover that it open another Pandora box).
Comment 1 Richard Biener 2007-09-07 10:06:12 UTC
The problem is that DCE2 deletes the my_char = 121; store because aliasing
thinks the array reference doesn't alias the scalar:

;; Function sub0 (sub0)

sub0 ()
{
  char[1:1] & my_char_ref;
  char D.874;
  char my_char;

<bb 2>:
  # my_char_4 = VDEF <my_char_3(D)>
  my_char = 121;
  my_char_ref_1 = (char[1:1] &) &my_char;
  # VUSE <NMT.30_5(D)>
  D.874_2 = (*my_char_ref_1)[1]{lb: 1 sz: 1};
  if (D.874_2 != 121)
    goto <bb 3>;
  else
    goto <bb 4>;

<bb 3>:
  _gfortran_abort ();

<bb 4>:
  return;

}

aliasing has similar problems where references are not combined completely
in some places like

  my_char_ref_1 = (char[1:1] &) &my_char;
  # VUSE <NMT.30_5(D)>
  D.874_2 = (*my_char_ref_1)[1]{lb: 1 sz: 1};

we might be able to work around this by properly doing the propagation.

Finally a nice small testcase though ;)
Comment 2 Richard Biener 2007-09-07 10:10:19 UTC
We have

Pointed-to sets for pointers in sub0

my_char_ref_1, name memory tag: NMT.30, is dereferenced, points-to vars: { my_char }

and

Aliased symbols

my_char, UID D.871, char, is addressable, direct reads: 0, direct writes: 1, indirect reads: 1, indirect writes: 0, read frequency: 10000, write frequency: 10000
SMT.29, UID D.904, char[1:1], is addressable, direct reads: 0, direct writes: 0, indirect reads: 0, indirect writes: 0, read frequency: 0, write frequency: 0, may aliases: { my_char }
NMT.30, UID D.905, char[1:1], is addressable, direct reads: 1, direct writes: 0, indirect reads: 0, indirect writes: 0, read frequency: 0, write frequency: 0, may aliases: { my_char }

so somehow we prune the aliases.
Comment 3 Richard Biener 2007-09-07 10:24:35 UTC
Through this:

  else if (ref
           && flag_strict_aliasing
           && TREE_CODE (ref) != INDIRECT_REF
           && !MTAG_P (alias)
           && base
           && (TREE_CODE (base) != INDIRECT_REF
               || TREE_CODE (TREE_TYPE (base)) != UNION_TYPE)
           && !AGGREGATE_TYPE_P (TREE_TYPE (alias))
           && TREE_CODE (TREE_TYPE (alias)) != COMPLEX_TYPE
           && !var_ann (alias)->is_heapvar
           /* When the struct has may_alias attached to it, we need not to
              return true.  */
           && get_alias_set (base))
    {
#ifdef ACCESS_DEBUGGING
      fprintf (stderr, "Access to ");
      print_generic_expr (stderr, ref, 0);
      fprintf (stderr, " may not touch ");
      print_generic_expr (stderr, alias, 0);
      fprintf (stderr, " in function %s\n", get_name (current_function_decl));
#endif
      return false;
    }

(gdb) call debug_generic_expr (ref)
(*my_char_ref_1)[1]{lb: 1 sz: 1}
(gdb) call debug_generic_expr (alias)
my_char
(gdb) call debug_generic_expr (base)
*my_char_ref_1

we miss the case accessing a variable through an array type of size one.
Something like

Index: tree-ssa-operands.c
===================================================================
--- tree-ssa-operands.c (revision 128188)
+++ tree-ssa-operands.c (working copy)
@@ -1300,6 +1300,13 @@ access_can_touch_variable (tree ref, tre
           && base
           && (TREE_CODE (base) != INDIRECT_REF
               || TREE_CODE (TREE_TYPE (base)) != UNION_TYPE)
+          && (TREE_CODE (base) != INDIRECT_REF
+              || TREE_CODE (ref) != ARRAY_REF
+              || offset != 0
+              || (DECL_SIZE (alias)
+                  && TREE_CODE (DECL_SIZE (alias)) == INTEGER_CST
+                  && size != -1
+                  && size != TREE_INT_CST_LOW (DECL_SIZE (alias))))
           && !AGGREGATE_TYPE_P (TREE_TYPE (alias))
           && TREE_CODE (TREE_TYPE (alias)) != COMPLEX_TYPE
           && !var_ann (alias)->is_heapvar

fixes it.
Comment 4 Richard Biener 2007-09-07 11:45:21 UTC
Mine.
Comment 5 Richard Biener 2007-09-07 11:58:08 UTC
Subject: Bug 33330

Author: rguenth
Date: Fri Sep  7 11:57:57 2007
New Revision: 128240

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=128240
Log:
2007-09-07  Richard Guenther  <rguenther@suse.de>

	PR middle-end/33330
	* tree-ssa-operands.c (access_can_touch_variable): An access
	of the form (*p)[0] can touch a variable of same size.

Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/tree-ssa-operands.c

Comment 6 Richard Biener 2007-09-07 12:00:08 UTC
Fixed.
Comment 7 Richard Biener 2007-09-07 12:13:53 UTC
Btw, is it mandated by the fortran standard to pass a scalar as array reference?
Comment 8 Francois-Xavier Coudert 2007-09-07 12:47:45 UTC
(In reply to comment #7)
> Btw, is it mandated by the fortran standard to pass a scalar as array
> reference?

As far as I understand, in this case, it actually is the right thing to do.