public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Fix more of C/fortran canonical type issues
@ 2015-06-08  1:23 Jan Hubicka
  2015-06-08  5:45 ` Jan Hubicka
  0 siblings, 1 reply; 35+ messages in thread
From: Jan Hubicka @ 2015-06-08  1:23 UTC (permalink / raw)
  To: gcc-patches, rguenther, burnus

Hi,
this patchs makes fortran's C_SIGNED_CHAR and C_SIZE_T interoperable with 
signed char and size_t as standard require.  There are two issues here.

First Fortran integers are always signed, but the standard insist on the
signed integer to match C size_t that is unsigned (if it was ptrdiff_t, we would
be better of) and similarly the standard seems to explicitly state that
C_SIGNED_CHAR is interoperable with both signed char and unsigned char.
I thus globbed all integer types of precision compatible either with char
or size_t to be the same regardless the signedness.

These types are special and apparently magic.  I wonder if C FE can be adjusted
to make these unsigned instead, but I have no idea if that could possibly work.

I also had to update useless_type_conversion_p here and move INTEGER_CST
handling ahead so it does not ignore sign.  The patch got handled in ugly way
by diff, it only moves the whole block on INTEGER_CST up.

The second problem is that Fortran FE does not set STRING_FLAG for
C_SIGNED_CHAR while C frontend do. I suppose we can teach Fortran to set the
flag, but again I do not know what consequences that would have.

I thus dropped STRING_FLAG from the canonical type computation.  It is already
ignored by gimple_canonical_types_compatible_p.  My understanding is that
STRING_FLAG on integer types is only kind of support to define the array types
anyway. The wrong code can be reproduced by uncommenging the char part of
bind_c-4 testcase.

Finally I added testcases for all types of 15.3.2 of the fortran 2008 draft.
I found that C_CHAR is not really compatible with char because it is
declared as array of chars. Lets handle that incrementally.

Bootstrapped/regtested ppc64le-linux, seems sane?

	* gimple-expr.c (useless_type_conversion_p): Move
	INTEGER_TYPE handling ahead.
	* tree.c (gimple_canonical_types_compatible_p): Do not compare
	TYPE_UNSIGNED for size_t and char compatible types; do not hash
	STRING_FLAG on integer types.

	* lto.c (hash_canonical_type): Do not hash TYPE_UNSIGNED for size_t
	and char compatible types; do not hash STRING_FLAG on integer types.

	* gfortran.dg/lto/bind_c-2_0.f90: New testcase.
	* gfortran.dg/lto/bind_c-2_1.c: New testcase.
	* gfortran.dg/lto/bind_c-3_0.f90: New testcase.
	* gfortran.dg/lto/bind_c-3_1.c: New testcase.
	* gfortran.dg/lto/bind_c-4_0.f90: New testcase.
	* gfortran.dg/lto/bind_c-4_1.c: New testcase.
Index: gimple-expr.c
===================================================================
--- gimple-expr.c	(revision 224201)
+++ gimple-expr.c	(working copy)
@@ -91,30 +91,14 @@
 	       || TREE_CODE (TREE_TYPE (inner_type)) == METHOD_TYPE))
 	return false;
     }
-
-  /* From now on qualifiers on value types do not matter.  */
-  inner_type = TYPE_MAIN_VARIANT (inner_type);
-  outer_type = TYPE_MAIN_VARIANT (outer_type);
-
-  if (inner_type == outer_type)
-    return true;
-
-  /* If we know the canonical types, compare them.  */
-  if (TYPE_CANONICAL (inner_type)
-      && TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type))
-    return true;
-
-  /* Changes in machine mode are never useless conversions unless we
-     deal with aggregate types in which case we defer to later checks.  */
-  if (TYPE_MODE (inner_type) != TYPE_MODE (outer_type)
-      && !AGGREGATE_TYPE_P (inner_type))
-    return false;
-
   /* If both the inner and outer types are integral types, then the
      conversion is not necessary if they have the same mode and
-     signedness and precision, and both or neither are boolean.  */
-  if (INTEGRAL_TYPE_P (inner_type)
-      && INTEGRAL_TYPE_P (outer_type))
+     signedness and precision, and both or neither are boolean.
+
+     Do not rely on TYPE_CANONICAL here because LTO puts same canonical
+     type for signed char and unsigned char.  */
+  else if (INTEGRAL_TYPE_P (inner_type)
+           && INTEGRAL_TYPE_P (outer_type))
     {
       /* Preserve changes in signedness or precision.  */
       if (TYPE_UNSIGNED (inner_type) != TYPE_UNSIGNED (outer_type)
@@ -134,6 +118,25 @@
       return true;
     }
 
+
+  /* From now on qualifiers on value types do not matter.  */
+  inner_type = TYPE_MAIN_VARIANT (inner_type);
+  outer_type = TYPE_MAIN_VARIANT (outer_type);
+
+  if (inner_type == outer_type)
+    return true;
+
+  /* If we know the canonical types, compare them.  */
+  if (TYPE_CANONICAL (inner_type)
+      && TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type))
+    return true;
+
+  /* Changes in machine mode are never useless conversions unless we
+     deal with aggregate types in which case we defer to later checks.  */
+  if (TYPE_MODE (inner_type) != TYPE_MODE (outer_type)
+      && !AGGREGATE_TYPE_P (inner_type))
+    return false;
+
   /* Scalar floating point types with the same mode are compatible.  */
   else if (SCALAR_FLOAT_TYPE_P (inner_type)
 	   && SCALAR_FLOAT_TYPE_P (outer_type))
Index: lto/lto.c
===================================================================
--- lto/lto.c	(revision 224201)
+++ lto/lto.c	(working copy)
@@ -303,6 +303,7 @@
 hash_canonical_type (tree type)
 {
   inchash::hash hstate;
+  enum tree_code code;
 
   /* We compute alias sets only for types that needs them.
      Be sure we do not recurse to something else as we can not hash incomplete
@@ -314,7 +315,8 @@
      smaller sets; when searching for existing matching types to merge,
      only existing types having the same features as the new type will be
      checked.  */
-  hstate.add_int (tree_code_for_canonical_type_merging (TREE_CODE (type)));
+  code = tree_code_for_canonical_type_merging (TREE_CODE (type));
+  hstate.add_int (code);
   hstate.add_int (TYPE_MODE (type));
 
   /* Incorporate common features of numerical types.  */
@@ -324,8 +326,15 @@
       || TREE_CODE (type) == OFFSET_TYPE
       || POINTER_TYPE_P (type))
     {
-      hstate.add_int (TYPE_UNSIGNED (type));
       hstate.add_int (TYPE_PRECISION (type));
+      /* Ignore sign for char and size_t.  This is needed for fortran
+	 C_SIGNED_CHAR to be interoperable with both signed char and
+	 unsigned char (as stadnard requires).  Similarly fortran FE builds
+	 C_SIZE_T is signed type, while C defines it unsigned.  */
+      if (code != INTEGER_TYPE
+	  || (TYPE_PRECISION (type) != BITS_PER_UNIT
+	      && TYPE_PRECISION (type) != POINTER_SIZE))
+        hstate.add_int (TYPE_UNSIGNED (type));
     }
 
   if (VECTOR_TYPE_P (type))
@@ -345,9 +354,9 @@
       hstate.add_int (TYPE_ADDR_SPACE (TREE_TYPE (type)));
     }
 
-  /* For integer types hash only the string flag.  */
-  if (TREE_CODE (type) == INTEGER_TYPE)
-    hstate.add_int (TYPE_STRING_FLAG (type));
+  /* Fortran FE does not set string flag for C_SIGNED_CHAR while C
+     sets it for signed char.  To use STRING_FLAG to define canonical types,
+     the frontends would need to agree.  */
 
   /* For array types hash the domain bounds and the string flag.  */
   if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
Index: testsuite/gfortran.dg/lto/bind_c-2_0.f90
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-2_0.f90	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-2_0.f90	(working copy)
@@ -0,0 +1,21 @@
+! { dg-lto-do run }
+! { dg-lto-options {{ -O3 -flto }} }
+! This testcase will abort if C_PTR is not interoperable with both int *
+! and float *
+module lto_type_merge_test
+  use, intrinsic :: iso_c_binding
+  implicit none
+
+  type, bind(c) :: MYFTYPE_1
+     integer(c_signed_char) :: chr
+     integer(c_signed_char) :: chrb
+  end type MYFTYPE_1
+
+  type(myftype_1), bind(c, name="myVar") :: myVar
+
+contains
+  subroutine types_test() bind(c)
+    myVar%chr = myVar%chrb
+  end subroutine types_test
+end module lto_type_merge_test
+
Index: testsuite/gfortran.dg/lto/bind_c-2_1.c
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-2_1.c	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-2_1.c	(working copy)
@@ -0,0 +1,36 @@
+#include <stdlib.h>
+/* interopse with myftype_1 */
+typedef struct {
+   unsigned char chr;
+   signed char chr2;
+} myctype_t;
+
+
+extern void abort(void);
+void types_test(void);
+/* declared in the fortran module */
+extern myctype_t myVar;
+
+int main(int argc, char **argv)
+{
+   myctype_t *cchr;
+   asm("":"=r"(cchr):"0"(&myVar));
+   cchr->chr = 1;
+   cchr->chr2 = 2;
+
+   types_test();
+
+   if(cchr->chr != 2)
+      abort();
+   if(cchr->chr2 != 2)
+      abort();
+   myVar.chr2 = 3;
+   types_test();
+
+   if(myVar.chr != 3)
+      abort();
+   if(myVar.chr2 != 3)
+      abort();
+   return 0;
+}
+
Index: testsuite/gfortran.dg/lto/bind_c-3_0.f90
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-3_0.f90	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-3_0.f90	(working copy)
@@ -0,0 +1,91 @@
+! { dg-lto-do run }
+! { dg-lto-options {{ -O3 -flto }} }
+! This testcase will abort if integer types are not interoperable.
+module lto_type_merge_test
+  use, intrinsic :: iso_c_binding
+  implicit none
+
+  type, bind(c) :: MYFTYPE_1
+    integer(c_int) :: val_int
+    integer(c_short) :: val_short
+    integer(c_long) :: val_long
+    integer(c_long_long) :: val_long_long
+    integer(c_size_t) :: val_size_t
+    integer(c_int8_t) :: val_int8_t
+    integer(c_int16_t) :: val_int16_t
+    integer(c_int32_t) :: val_int32_t
+    integer(c_int64_t) :: val_int64_t
+    integer(c_int_least8_t) :: val_intleast_8_t
+    integer(c_int_least16_t) :: val_intleast_16_t
+    integer(c_int_least32_t) :: val_intleast_32_t
+    integer(c_int_least64_t) :: val_intleast_64_t
+    integer(c_int_fast8_t) :: val_intfast_8_t
+    integer(c_int_fast16_t) :: val_intfast_16_t
+    integer(c_int_fast32_t) :: val_intfast_32_t
+    integer(c_int_fast64_t) :: val_intfast_64_t
+    integer(c_intmax_t) :: val_intmax_t
+    integer(c_intptr_t) :: val_intptr_t
+  end type MYFTYPE_1
+
+  type(myftype_1), bind(c, name="myVar") :: myVar
+
+contains
+  subroutine types_test1() bind(c)
+    myVar%val_int = 2
+  end subroutine types_test1
+  subroutine types_test2() bind(c)
+    myVar%val_short = 2
+  end subroutine types_test2
+  subroutine types_test3() bind(c)
+    myVar%val_long = 2
+  end subroutine types_test3
+  subroutine types_test4() bind(c)
+    myVar%val_long_long = 2
+  end subroutine types_test4
+  subroutine types_test5() bind(c)
+    myVar%val_size_t = 2
+  end subroutine types_test5
+  subroutine types_test6() bind(c)
+    myVar%val_int8_t = 2
+  end subroutine types_test6
+  subroutine types_test7() bind(c)
+    myVar%val_int16_t = 2
+  end subroutine types_test7
+  subroutine types_test8() bind(c)
+    myVar%val_int32_t = 2
+  end subroutine types_test8
+  subroutine types_test9() bind(c)
+    myVar%val_int64_t = 2
+  end subroutine types_test9
+  subroutine types_test10() bind(c)
+    myVar%val_intleast_8_t = 2
+  end subroutine types_test10
+  subroutine types_test11() bind(c)
+    myVar%val_intleast_16_t = 2
+  end subroutine types_test11
+  subroutine types_test12() bind(c)
+    myVar%val_intleast_32_t = 2
+  end subroutine types_test12
+  subroutine types_test13() bind(c)
+    myVar%val_intleast_64_t = 2
+  end subroutine types_test13
+  subroutine types_test14() bind(c)
+    myVar%val_intfast_8_t = 2
+  end subroutine types_test14
+  subroutine types_test15() bind(c)
+    myVar%val_intfast_16_t = 2
+  end subroutine types_test15
+  subroutine types_test16() bind(c)
+    myVar%val_intfast_32_t = 2
+  end subroutine types_test16
+  subroutine types_test17() bind(c)
+    myVar%val_intfast_64_t = 2
+  end subroutine types_test17
+  subroutine types_test18() bind(c)
+    myVar%val_intmax_t = 2
+  end subroutine types_test18
+  subroutine types_test19() bind(c)
+    myVar%val_intptr_t = 2
+  end subroutine types_test19
+end module lto_type_merge_test
+
Index: testsuite/gfortran.dg/lto/bind_c-3_1.c
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-3_1.c	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-3_1.c	(working copy)
@@ -0,0 +1,78 @@
+#include <stdlib.h>
+#include <stdint.h>
+/* interopse with myftype_1 */
+typedef struct {
+  int val1;
+  short int val2;
+  long int val3;
+  long long int val4;
+  size_t val5;
+  int8_t val6;
+  int16_t val7;
+  int32_t val8;
+  int64_t val9;
+  int_least8_t val10;
+  int_least16_t val11;
+  int_least32_t val12;
+  int_least64_t val13;
+  int_fast8_t val14;
+  int_fast16_t val15;
+  int_fast32_t val16;
+  int_fast64_t val17;
+  intmax_t val18;
+  intptr_t val19;
+} myctype_t;
+
+
+extern void abort(void);
+void types_test1(void);
+void types_test2(void);
+void types_test3(void);
+void types_test4(void);
+void types_test5(void);
+void types_test6(void);
+void types_test7(void);
+void types_test8(void);
+void types_test9(void);
+void types_test10(void);
+void types_test11(void);
+void types_test12(void);
+void types_test13(void);
+void types_test14(void);
+void types_test15(void);
+void types_test16(void);
+void types_test17(void);
+void types_test18(void);
+void types_test19(void);
+/* declared in the fortran module */
+extern myctype_t myVar;
+
+#define test(n)\
+  cchr->val##n = 1; types_test##n (); if (cchr->val##n != 2) abort ();
+
+int main(int argc, char **argv)
+{
+   myctype_t *cchr;
+   asm("":"=r"(cchr):"0"(&myVar));
+   test(1);
+   test(2);
+   test(3);
+   test(4);
+   test(5);
+   test(6);
+   test(7);
+   test(8);
+   test(9);
+   test(10);
+   test(11);
+   test(12);
+   test(13);
+   test(14);
+   test(15);
+   test(16);
+   test(17);
+   test(18);
+   test(19);
+   return 0;
+}
+
Index: testsuite/gfortran.dg/lto/bind_c-4_0.f90
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-4_0.f90	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-4_0.f90	(working copy)
@@ -0,0 +1,48 @@
+! { dg-lto-do run }
+! { dg-lto-options {{ -O3 -flto }} }
+! This testcase will abort if real/complex/boolean/character types are not interoperable
+module lto_type_merge_test
+  use, intrinsic :: iso_c_binding
+  implicit none
+
+  type, bind(c) :: MYFTYPE_1
+    real(c_float) :: val_1
+    real(c_double) :: val_2
+    real(c_long_double) :: val_3
+    complex(c_float_complex) :: val_4
+    complex(c_double_complex) :: val_5
+    complex(c_long_double_complex) :: val_6
+    logical(c_bool) :: val_7
+    !FIXME: Fortran define c_char as array of size 1.
+    !character(c_char) :: val_8
+  end type MYFTYPE_1
+
+  type(myftype_1), bind(c, name="myVar") :: myVar
+
+contains
+  subroutine types_test1() bind(c)
+    myVar%val_1 = 2
+  end subroutine types_test1
+  subroutine types_test2() bind(c)
+    myVar%val_2 = 2
+  end subroutine types_test2
+  subroutine types_test3() bind(c)
+    myVar%val_3 = 2
+  end subroutine types_test3
+  subroutine types_test4() bind(c)
+    myVar%val_4 = 2
+  end subroutine types_test4
+  subroutine types_test5() bind(c)
+    myVar%val_5 = 2
+  end subroutine types_test5
+  subroutine types_test6() bind(c)
+    myVar%val_6 = 2
+  end subroutine types_test6
+  subroutine types_test7() bind(c)
+    myVar%val_7 = myVar%val_7 .or. .not. myVar%val_7
+  end subroutine types_test7
+  !subroutine types_test8() bind(c)
+    !myVar%val_8 = "a"
+  !end subroutine types_test8
+end module lto_type_merge_test
+
Index: testsuite/gfortran.dg/lto/bind_c-4_1.c
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-4_1.c	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-4_1.c	(working copy)
@@ -0,0 +1,46 @@
+#include <stdlib.h>
+#include <stdint.h>
+/* interopse with myftype_1 */
+typedef struct {
+  float val1;
+  double val2;
+  long double val3;
+  float _Complex val4;
+  double _Complex val5;
+  long double _Complex val6;
+  _Bool val7;
+  /* FIXME: Fortran define c_char as array of size 1.
+     char val8;  */
+} myctype_t;
+
+
+extern void abort(void);
+void types_test1(void);
+void types_test2(void);
+void types_test3(void);
+void types_test4(void);
+void types_test5(void);
+void types_test6(void);
+void types_test7(void);
+void types_test8(void);
+/* declared in the fortran module */
+extern myctype_t myVar;
+
+#define test(n)\
+  cchr->val##n = 1; types_test##n (); if (cchr->val##n != 2) abort ();
+
+int main(int argc, char **argv)
+{
+   myctype_t *cchr;
+   asm("":"=r"(cchr):"0"(&myVar));
+   test(1);
+   test(2);
+   test(3);
+   test(4);
+   test(5);
+   test(6);
+   cchr->val7 = 0; types_test7 (); if (cchr->val7 != 1) abort ();
+   /*cchr->val8 = 0; types_test8 (); if (cchr->val8 != 'a') abort ();*/
+   return 0;
+}
+
Index: tree.c
===================================================================
--- tree.c	(revision 224201)
+++ tree.c	(working copy)
@@ -12925,8 +12925,8 @@
     return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
 
   /* Can't be the same type if the types don't have the same code.  */
-  if (tree_code_for_canonical_type_merging (TREE_CODE (t1))
-      != tree_code_for_canonical_type_merging (TREE_CODE (t2)))
+  enum tree_code code = tree_code_for_canonical_type_merging (TREE_CODE (t1));
+  if (code != tree_code_for_canonical_type_merging (TREE_CODE (t2)))
     return false;
 
   /* Qualifiers do not matter for canonical type comparison purposes.  */
@@ -12949,15 +12949,23 @@
       || TREE_CODE (t1) == OFFSET_TYPE
       || POINTER_TYPE_P (t1))
     {
-      /* Can't be the same type if they have different sign or precision.  */
-      if (TYPE_PRECISION (t1) != TYPE_PRECISION (t2)
-	  || TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2))
+      /* Can't be the same type if they have different recision.  */
+      if (TYPE_PRECISION (t1) != TYPE_PRECISION (t2))
 	return false;
-
-      if (TREE_CODE (t1) == INTEGER_TYPE
-	  && TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2))
+      /* Ignore sign for char and size_t.  This is needed for fortran
+	 C_SIGNED_CHAR to be interoperable with both signed char and
+	 unsigned char (as stadnard requires).  Similarly fortran FE builds
+	 C_SIZE_T is signed type, while C defines it unsigned.  */
+      if (TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2)
+	  && ((TYPE_PRECISION (t1) != BITS_PER_UNIT
+	       && TYPE_PRECISION (t1) != POINTER_SIZE)
+	      || code != INTEGER_TYPE))
 	return false;
 
+      /* Fortran FE does not set STRING_FLAG for C_SIGNED_CHAR while C
+	 sets it for signed char.  To use string flag to define canonical
+	 types, the frontends would need to agree.  */
+
       /* Fortran standard define C_PTR type that is compatible with every
  	 C pointer.  For this reason we need to glob all pointers into one.
 	 Still pointers in different address spaces are not compatible.  */

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-08  1:23 Fix more of C/fortran canonical type issues Jan Hubicka
@ 2015-06-08  5:45 ` Jan Hubicka
  2015-06-08  7:25   ` Jan Hubicka
  2015-06-08 13:37   ` Richard Biener
  0 siblings, 2 replies; 35+ messages in thread
From: Jan Hubicka @ 2015-06-08  5:45 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches, rguenther, burnus

> Hi,
> this patchs makes fortran's C_SIGNED_CHAR and C_SIZE_T interoperable with 
> signed char and size_t as standard require.  There are two issues here.
> 
> First Fortran integers are always signed, but the standard insist on the
> signed integer to match C size_t that is unsigned (if it was ptrdiff_t, we would
> be better of) and similarly the standard seems to explicitly state that
> C_SIGNED_CHAR is interoperable with both signed char and unsigned char.
> I thus globbed all integer types of precision compatible either with char
> or size_t to be the same regardless the signedness.
Hmm, actually there is a note:
  NOTE 15.8
  ISO/IEC 9899:1999 specifies that the representations for nonnegative signed
  integers are the same as the corresponding values of unsigned integers.
  Because Fortran does not provide direct support for unsigned kinds of integers,
  the ISO C BINDING module does not make accessible named constant s for their
  kind type parameter values.  A user can use the signed kinds of integers to
  interoperate with the unsigned types and  all  their  qualified  versions  as
  well.   This  has  the  potentially  surprising  side  ect  that  the  C  type
  unsigned char is interoperable with the type integer with a kind type parameter
  of C SIGNED CHAR

This seems to imply that other integer types also should be interoperable regardless
of the signedness.  It is true that representation is same for C, but alias sets are
not.  Perhaps all of the C BINDING types shall just be dropped to alias set 0? That
would also solve the inter-operability of char versus char[1].

I would say that the note is non-normative, so perhaps it can just be ignored, too :)

Honza

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-08  5:45 ` Jan Hubicka
@ 2015-06-08  7:25   ` Jan Hubicka
  2015-06-08 13:43     ` Richard Biener
  2015-10-08  3:47     ` Jan Hubicka
  2015-06-08 13:37   ` Richard Biener
  1 sibling, 2 replies; 35+ messages in thread
From: Jan Hubicka @ 2015-06-08  7:25 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches, rguenther, burnus

Hi,
this is a variant of patch that globs also the rest of integer types.
Note that we will still get false warnings out of lto-symtab when the
values are not wrapped up in structures.  This is because lto-symtab
uses types_compatible_p that in turn uses useless_type_conversion and
that one needs to honor signedness.

I suppose we need a way to test representation compatibility and TBAA
compatiblity. I will give it a more tought how to reorganize the code.
Basically we need
  - way to decide if two types have compatible memory representation 
    (to test in lto-symtab and for some cases in ipa-icf (contructors/pure
     moves))
    operands_equal_p/compare_constant/ipa-icf::sem_variable all implements
    bit of this. copmare_constant seems to be most complete.
  - way to decide if two types match by TBAA oracle
    (to test in lto-symtab merging and for ipa-icf memory operations)
  - way to decide if one type is semantically compatible to other
    (useless_type_conversion_p)
  - way to decide if two types are same for canonical type computation
    (gimple_type_compatible_p).  This may be sensitive to the set of languages
    we are merging and enable/disable various globbing as required.

It may make sense to refactor the type walkers and get this more organized.
But before playing with this I think we want to get something conservatively
correct according to language standards and get a reasonable body of testcases.

This is a variant of patch that removes TYPE_UNSIGNED testing completely.
I am fine with both variants.

Bootstrapped/regtested ppc64le-linux.

Honza

	* gimple-expr.c (useless_type_conversion_p): Move
	INTEGER_TYPE handling ahead.
	* tree.c (gimple_canonical_types_compatible_p): Do not compare
	TYPE_UNSIGNED for size_t and char compatible types; do not hash
	STRING_FLAG on integer types.

	* lto.c (hash_canonical_type): Do not hash TYPE_UNSIGNED for size_t
	and char compatible types; do not hash STRING_FLAG on integer types.

	* gfortran.dg/lto/bind_c-2_0.f90: New testcase.
	* gfortran.dg/lto/bind_c-2_1.c: New testcase.
	* gfortran.dg/lto/bind_c-3_0.f90: New testcase.
	* gfortran.dg/lto/bind_c-3_1.c: New testcase.
	* gfortran.dg/lto/bind_c-4_0.f90: New testcase.
	* gfortran.dg/lto/bind_c-4_1.c: New testcase.
Index: gimple-expr.c
===================================================================
--- gimple-expr.c	(revision 224201)
+++ gimple-expr.c	(working copy)
@@ -91,30 +91,14 @@
 	       || TREE_CODE (TREE_TYPE (inner_type)) == METHOD_TYPE))
 	return false;
     }
-
-  /* From now on qualifiers on value types do not matter.  */
-  inner_type = TYPE_MAIN_VARIANT (inner_type);
-  outer_type = TYPE_MAIN_VARIANT (outer_type);
-
-  if (inner_type == outer_type)
-    return true;
-
-  /* If we know the canonical types, compare them.  */
-  if (TYPE_CANONICAL (inner_type)
-      && TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type))
-    return true;
-
-  /* Changes in machine mode are never useless conversions unless we
-     deal with aggregate types in which case we defer to later checks.  */
-  if (TYPE_MODE (inner_type) != TYPE_MODE (outer_type)
-      && !AGGREGATE_TYPE_P (inner_type))
-    return false;
-
   /* If both the inner and outer types are integral types, then the
      conversion is not necessary if they have the same mode and
-     signedness and precision, and both or neither are boolean.  */
-  if (INTEGRAL_TYPE_P (inner_type)
-      && INTEGRAL_TYPE_P (outer_type))
+     signedness and precision, and both or neither are boolean.
+
+     Do not rely on TYPE_CANONICAL here because LTO puts same canonical
+     type for signed char and unsigned char.  */
+  else if (INTEGRAL_TYPE_P (inner_type)
+           && INTEGRAL_TYPE_P (outer_type))
     {
       /* Preserve changes in signedness or precision.  */
       if (TYPE_UNSIGNED (inner_type) != TYPE_UNSIGNED (outer_type)
@@ -134,6 +118,25 @@
       return true;
     }
 
+
+  /* From now on qualifiers on value types do not matter.  */
+  inner_type = TYPE_MAIN_VARIANT (inner_type);
+  outer_type = TYPE_MAIN_VARIANT (outer_type);
+
+  if (inner_type == outer_type)
+    return true;
+
+  /* If we know the canonical types, compare them.  */
+  if (TYPE_CANONICAL (inner_type)
+      && TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type))
+    return true;
+
+  /* Changes in machine mode are never useless conversions unless we
+     deal with aggregate types in which case we defer to later checks.  */
+  if (TYPE_MODE (inner_type) != TYPE_MODE (outer_type)
+      && !AGGREGATE_TYPE_P (inner_type))
+    return false;
+
   /* Scalar floating point types with the same mode are compatible.  */
   else if (SCALAR_FLOAT_TYPE_P (inner_type)
 	   && SCALAR_FLOAT_TYPE_P (outer_type))
Index: lto/lto.c
===================================================================
--- lto/lto.c	(revision 224201)
+++ lto/lto.c	(working copy)
@@ -303,6 +303,7 @@
 hash_canonical_type (tree type)
 {
   inchash::hash hstate;
+  enum tree_code code;
 
   /* We compute alias sets only for types that needs them.
      Be sure we do not recurse to something else as we can not hash incomplete
@@ -314,7 +315,8 @@
      smaller sets; when searching for existing matching types to merge,
      only existing types having the same features as the new type will be
      checked.  */
-  hstate.add_int (tree_code_for_canonical_type_merging (TREE_CODE (type)));
+  code = tree_code_for_canonical_type_merging (TREE_CODE (type));
+  hstate.add_int (code);
   hstate.add_int (TYPE_MODE (type));
 
   /* Incorporate common features of numerical types.  */
@@ -324,8 +326,13 @@
       || TREE_CODE (type) == OFFSET_TYPE
       || POINTER_TYPE_P (type))
     {
-      hstate.add_int (TYPE_UNSIGNED (type));
       hstate.add_int (TYPE_PRECISION (type));
+      /* Ignore TYPE_SIGNED. This is needed for Fortran
+	 C_SIGNED_CHAR to be interoperable with both signed char and
+	 unsigned char (as stadnard requires).  Similarly Fortran FE builds
+	 C_SIZE_T is signed type, while C defines it unsigned.
+	 NOTE 15.8 of Fortran 2008 seems to imply that even other types ought
+	 to be inter-operable. */
     }
 
   if (VECTOR_TYPE_P (type))
@@ -345,9 +352,9 @@
       hstate.add_int (TYPE_ADDR_SPACE (TREE_TYPE (type)));
     }
 
-  /* For integer types hash only the string flag.  */
-  if (TREE_CODE (type) == INTEGER_TYPE)
-    hstate.add_int (TYPE_STRING_FLAG (type));
+  /* Fortran FE does not set string flag for C_SIGNED_CHAR while C
+     sets it for signed char.  To use STRING_FLAG to define canonical types,
+     the frontends would need to agree.  */
 
   /* For array types hash the domain bounds and the string flag.  */
   if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
Index: testsuite/gfortran.dg/lto/bind_c-2_0.f90
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-2_0.f90	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-2_0.f90	(working copy)
@@ -0,0 +1,21 @@
+! { dg-lto-do run }
+! { dg-lto-options {{ -O3 -flto }} }
+! This testcase will abort if C_PTR is not interoperable with both int *
+! and float *
+module lto_type_merge_test
+  use, intrinsic :: iso_c_binding
+  implicit none
+
+  type, bind(c) :: MYFTYPE_1
+     integer(c_signed_char) :: chr
+     integer(c_signed_char) :: chrb
+  end type MYFTYPE_1
+
+  type(myftype_1), bind(c, name="myVar") :: myVar
+
+contains
+  subroutine types_test() bind(c)
+    myVar%chr = myVar%chrb
+  end subroutine types_test
+end module lto_type_merge_test
+
Index: testsuite/gfortran.dg/lto/bind_c-2_1.c
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-2_1.c	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-2_1.c	(working copy)
@@ -0,0 +1,36 @@
+#include <stdlib.h>
+/* interopse with myftype_1 */
+typedef struct {
+   unsigned char chr;
+   signed char chr2;
+} myctype_t;
+
+
+extern void abort(void);
+void types_test(void);
+/* declared in the fortran module */
+extern myctype_t myVar;
+
+int main(int argc, char **argv)
+{
+   myctype_t *cchr;
+   asm("":"=r"(cchr):"0"(&myVar));
+   cchr->chr = 1;
+   cchr->chr2 = 2;
+
+   types_test();
+
+   if(cchr->chr != 2)
+      abort();
+   if(cchr->chr2 != 2)
+      abort();
+   myVar.chr2 = 3;
+   types_test();
+
+   if(myVar.chr != 3)
+      abort();
+   if(myVar.chr2 != 3)
+      abort();
+   return 0;
+}
+
Index: testsuite/gfortran.dg/lto/bind_c-3_0.f90
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-3_0.f90	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-3_0.f90	(working copy)
@@ -0,0 +1,91 @@
+! { dg-lto-do run }
+! { dg-lto-options {{ -O3 -flto }} }
+! This testcase will abort if integer types are not interoperable.
+module lto_type_merge_test
+  use, intrinsic :: iso_c_binding
+  implicit none
+
+  type, bind(c) :: MYFTYPE_1
+    integer(c_int) :: val_int
+    integer(c_short) :: val_short
+    integer(c_long) :: val_long
+    integer(c_long_long) :: val_long_long
+    integer(c_size_t) :: val_size_t
+    integer(c_int8_t) :: val_int8_t
+    integer(c_int16_t) :: val_int16_t
+    integer(c_int32_t) :: val_int32_t
+    integer(c_int64_t) :: val_int64_t
+    integer(c_int_least8_t) :: val_intleast_8_t
+    integer(c_int_least16_t) :: val_intleast_16_t
+    integer(c_int_least32_t) :: val_intleast_32_t
+    integer(c_int_least64_t) :: val_intleast_64_t
+    integer(c_int_fast8_t) :: val_intfast_8_t
+    integer(c_int_fast16_t) :: val_intfast_16_t
+    integer(c_int_fast32_t) :: val_intfast_32_t
+    integer(c_int_fast64_t) :: val_intfast_64_t
+    integer(c_intmax_t) :: val_intmax_t
+    integer(c_intptr_t) :: val_intptr_t
+  end type MYFTYPE_1
+
+  type(myftype_1), bind(c, name="myVar") :: myVar
+
+contains
+  subroutine types_test1() bind(c)
+    myVar%val_int = 2
+  end subroutine types_test1
+  subroutine types_test2() bind(c)
+    myVar%val_short = 2
+  end subroutine types_test2
+  subroutine types_test3() bind(c)
+    myVar%val_long = 2
+  end subroutine types_test3
+  subroutine types_test4() bind(c)
+    myVar%val_long_long = 2
+  end subroutine types_test4
+  subroutine types_test5() bind(c)
+    myVar%val_size_t = 2
+  end subroutine types_test5
+  subroutine types_test6() bind(c)
+    myVar%val_int8_t = 2
+  end subroutine types_test6
+  subroutine types_test7() bind(c)
+    myVar%val_int16_t = 2
+  end subroutine types_test7
+  subroutine types_test8() bind(c)
+    myVar%val_int32_t = 2
+  end subroutine types_test8
+  subroutine types_test9() bind(c)
+    myVar%val_int64_t = 2
+  end subroutine types_test9
+  subroutine types_test10() bind(c)
+    myVar%val_intleast_8_t = 2
+  end subroutine types_test10
+  subroutine types_test11() bind(c)
+    myVar%val_intleast_16_t = 2
+  end subroutine types_test11
+  subroutine types_test12() bind(c)
+    myVar%val_intleast_32_t = 2
+  end subroutine types_test12
+  subroutine types_test13() bind(c)
+    myVar%val_intleast_64_t = 2
+  end subroutine types_test13
+  subroutine types_test14() bind(c)
+    myVar%val_intfast_8_t = 2
+  end subroutine types_test14
+  subroutine types_test15() bind(c)
+    myVar%val_intfast_16_t = 2
+  end subroutine types_test15
+  subroutine types_test16() bind(c)
+    myVar%val_intfast_32_t = 2
+  end subroutine types_test16
+  subroutine types_test17() bind(c)
+    myVar%val_intfast_64_t = 2
+  end subroutine types_test17
+  subroutine types_test18() bind(c)
+    myVar%val_intmax_t = 2
+  end subroutine types_test18
+  subroutine types_test19() bind(c)
+    myVar%val_intptr_t = 2
+  end subroutine types_test19
+end module lto_type_merge_test
+
Index: testsuite/gfortran.dg/lto/bind_c-3_1.c
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-3_1.c	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-3_1.c	(working copy)
@@ -0,0 +1,78 @@
+#include <stdlib.h>
+#include <stdint.h>
+/* interopse with myftype_1 */
+typedef struct {
+  int val1;
+  short int val2;
+  long int val3;
+  long long int val4;
+  size_t val5;
+  int8_t val6;
+  int16_t val7;
+  int32_t val8;
+  int64_t val9;
+  int_least8_t val10;
+  int_least16_t val11;
+  int_least32_t val12;
+  int_least64_t val13;
+  int_fast8_t val14;
+  int_fast16_t val15;
+  int_fast32_t val16;
+  int_fast64_t val17;
+  intmax_t val18;
+  intptr_t val19;
+} myctype_t;
+
+
+extern void abort(void);
+void types_test1(void);
+void types_test2(void);
+void types_test3(void);
+void types_test4(void);
+void types_test5(void);
+void types_test6(void);
+void types_test7(void);
+void types_test8(void);
+void types_test9(void);
+void types_test10(void);
+void types_test11(void);
+void types_test12(void);
+void types_test13(void);
+void types_test14(void);
+void types_test15(void);
+void types_test16(void);
+void types_test17(void);
+void types_test18(void);
+void types_test19(void);
+/* declared in the fortran module */
+extern myctype_t myVar;
+
+#define test(n)\
+  cchr->val##n = 1; types_test##n (); if (cchr->val##n != 2) abort ();
+
+int main(int argc, char **argv)
+{
+   myctype_t *cchr;
+   asm("":"=r"(cchr):"0"(&myVar));
+   test(1);
+   test(2);
+   test(3);
+   test(4);
+   test(5);
+   test(6);
+   test(7);
+   test(8);
+   test(9);
+   test(10);
+   test(11);
+   test(12);
+   test(13);
+   test(14);
+   test(15);
+   test(16);
+   test(17);
+   test(18);
+   test(19);
+   return 0;
+}
+
Index: testsuite/gfortran.dg/lto/bind_c-4_0.f90
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-4_0.f90	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-4_0.f90	(working copy)
@@ -0,0 +1,48 @@
+! { dg-lto-do run }
+! { dg-lto-options {{ -O3 -flto }} }
+! This testcase will abort if real/complex/boolean/character types are not interoperable
+module lto_type_merge_test
+  use, intrinsic :: iso_c_binding
+  implicit none
+
+  type, bind(c) :: MYFTYPE_1
+    real(c_float) :: val_1
+    real(c_double) :: val_2
+    real(c_long_double) :: val_3
+    complex(c_float_complex) :: val_4
+    complex(c_double_complex) :: val_5
+    complex(c_long_double_complex) :: val_6
+    logical(c_bool) :: val_7
+    !FIXME: Fortran define c_char as array of size 1.
+    !character(c_char) :: val_8
+  end type MYFTYPE_1
+
+  type(myftype_1), bind(c, name="myVar") :: myVar
+
+contains
+  subroutine types_test1() bind(c)
+    myVar%val_1 = 2
+  end subroutine types_test1
+  subroutine types_test2() bind(c)
+    myVar%val_2 = 2
+  end subroutine types_test2
+  subroutine types_test3() bind(c)
+    myVar%val_3 = 2
+  end subroutine types_test3
+  subroutine types_test4() bind(c)
+    myVar%val_4 = 2
+  end subroutine types_test4
+  subroutine types_test5() bind(c)
+    myVar%val_5 = 2
+  end subroutine types_test5
+  subroutine types_test6() bind(c)
+    myVar%val_6 = 2
+  end subroutine types_test6
+  subroutine types_test7() bind(c)
+    myVar%val_7 = myVar%val_7 .or. .not. myVar%val_7
+  end subroutine types_test7
+  !subroutine types_test8() bind(c)
+    !myVar%val_8 = "a"
+  !end subroutine types_test8
+end module lto_type_merge_test
+
Index: testsuite/gfortran.dg/lto/bind_c-4_1.c
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-4_1.c	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-4_1.c	(working copy)
@@ -0,0 +1,46 @@
+#include <stdlib.h>
+#include <stdint.h>
+/* interopse with myftype_1 */
+typedef struct {
+  float val1;
+  double val2;
+  long double val3;
+  float _Complex val4;
+  double _Complex val5;
+  long double _Complex val6;
+  _Bool val7;
+  /* FIXME: Fortran define c_char as array of size 1.
+     char val8;  */
+} myctype_t;
+
+
+extern void abort(void);
+void types_test1(void);
+void types_test2(void);
+void types_test3(void);
+void types_test4(void);
+void types_test5(void);
+void types_test6(void);
+void types_test7(void);
+void types_test8(void);
+/* declared in the fortran module */
+extern myctype_t myVar;
+
+#define test(n)\
+  cchr->val##n = 1; types_test##n (); if (cchr->val##n != 2) abort ();
+
+int main(int argc, char **argv)
+{
+   myctype_t *cchr;
+   asm("":"=r"(cchr):"0"(&myVar));
+   test(1);
+   test(2);
+   test(3);
+   test(4);
+   test(5);
+   test(6);
+   cchr->val7 = 0; types_test7 (); if (cchr->val7 != 1) abort ();
+   /*cchr->val8 = 0; types_test8 (); if (cchr->val8 != 'a') abort ();*/
+   return 0;
+}
+
Index: tree.c
===================================================================
--- tree.c	(revision 224201)
+++ tree.c	(working copy)
@@ -12925,8 +12925,8 @@
     return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
 
   /* Can't be the same type if the types don't have the same code.  */
-  if (tree_code_for_canonical_type_merging (TREE_CODE (t1))
-      != tree_code_for_canonical_type_merging (TREE_CODE (t2)))
+  enum tree_code code = tree_code_for_canonical_type_merging (TREE_CODE (t1));
+  if (code != tree_code_for_canonical_type_merging (TREE_CODE (t2)))
     return false;
 
   /* Qualifiers do not matter for canonical type comparison purposes.  */
@@ -12949,14 +12949,19 @@
       || TREE_CODE (t1) == OFFSET_TYPE
       || POINTER_TYPE_P (t1))
     {
-      /* Can't be the same type if they have different sign or precision.  */
-      if (TYPE_PRECISION (t1) != TYPE_PRECISION (t2)
-	  || TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2))
+      /* Can't be the same type if they have different recision.  */
+      if (TYPE_PRECISION (t1) != TYPE_PRECISION (t2))
 	return false;
+      /* Ignore TYPE_SIGNED.  This is needed for Fortran
+	 C_SIGNED_CHAR to be interoperable with both signed char and
+	 unsigned char (as stadnard requires).  Similarly Fortran FE builds
+	 C_SIZE_T is signed type, while C defines it unsigned.
+	 NOTE 15.8 of Fortran 2008 seems to imply that even other types ought
+	 to be inter-operable. */
 
-      if (TREE_CODE (t1) == INTEGER_TYPE
-	  && TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2))
-	return false;
+      /* Fortran FE does not set STRING_FLAG for C_SIGNED_CHAR while C
+	 sets it for signed char.  To use string flag to define canonical
+	 types, the frontends would need to agree.  */
 
       /* Fortran standard define C_PTR type that is compatible with every
  	 C pointer.  For this reason we need to glob all pointers into one.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-08  5:45 ` Jan Hubicka
  2015-06-08  7:25   ` Jan Hubicka
@ 2015-06-08 13:37   ` Richard Biener
  1 sibling, 0 replies; 35+ messages in thread
From: Richard Biener @ 2015-06-08 13:37 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches, burnus

On Mon, 8 Jun 2015, Jan Hubicka wrote:

> > Hi,
> > this patchs makes fortran's C_SIGNED_CHAR and C_SIZE_T interoperable with 
> > signed char and size_t as standard require.  There are two issues here.
> > 
> > First Fortran integers are always signed, but the standard insist on the
> > signed integer to match C size_t that is unsigned (if it was ptrdiff_t, we would
> > be better of) and similarly the standard seems to explicitly state that
> > C_SIGNED_CHAR is interoperable with both signed char and unsigned char.
> > I thus globbed all integer types of precision compatible either with char
> > or size_t to be the same regardless the signedness.
> Hmm, actually there is a note:
>   NOTE 15.8
>   ISO/IEC 9899:1999 specifies that the representations for nonnegative signed
>   integers are the same as the corresponding values of unsigned integers.
>   Because Fortran does not provide direct support for unsigned kinds of integers,
>   the ISO C BINDING module does not make accessible named constant s for their
>   kind type parameter values.  A user can use the signed kinds of integers to
>   interoperate with the unsigned types and  all  their  qualified  versions  as
>   well.   This  has  the  potentially  surprising  side  ect  that  the  C  type
>   unsigned char is interoperable with the type integer with a kind type parameter
>   of C SIGNED CHAR
> 
> This seems to imply that other integer types also should be 
> interoperable regardless of the signedness.  It is true that 
> representation is same for C, but alias sets are not.  Perhaps all of 
> the C BINDING types shall just be dropped to alias set 0? That would 
> also solve the inter-operability of char versus char[1].

Alias-sets of signed and unsigned variants of integer types are the same:

alias_set_type
c_common_get_alias_set (tree t)
{
...
  /* The C standard specifically allows aliasing between signed and
     unsigned variants of the same type.  We treat the signed
     variant as canonical.  */
  if (TREE_CODE (t) == INTEGER_TYPE && TYPE_UNSIGNED (t))
    {
      tree t1 = c_common_signed_type (t);

      /* t1 == t can happen for boolean nodes which are always unsigned.  
*/
      if (t1 != t)
        return get_alias_set (t1);

yes, this should be moved to alias.c ...

Richard.

> I would say that the note is non-normative, so perhaps it can just be 
> ignored, too :)
> 
> Honza
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-08  7:25   ` Jan Hubicka
@ 2015-06-08 13:43     ` Richard Biener
  2015-06-08 14:07       ` Joseph Myers
                         ` (2 more replies)
  2015-10-08  3:47     ` Jan Hubicka
  1 sibling, 3 replies; 35+ messages in thread
From: Richard Biener @ 2015-06-08 13:43 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches, burnus, Joseph S. Myers

On Mon, 8 Jun 2015, Jan Hubicka wrote:

> Hi,
> this is a variant of patch that globs also the rest of integer types.
> Note that we will still get false warnings out of lto-symtab when the
> values are not wrapped up in structures.  This is because lto-symtab
> uses types_compatible_p that in turn uses useless_type_conversion and
> that one needs to honor signedness.
> 
> I suppose we need a way to test representation compatibility and TBAA
> compatiblity. I will give it a more tought how to reorganize the code.
> Basically we need

representation compatibility is TYPE_CANONICAL equivalence, TBAA
compatibility is get_alias_set equivalence.

So you have to be careful when mangling TYPE_CANONICAL according to
get_alias_set and make sure to only apply this (signedness for example)
for aggregate type components.

Can you please split out the string-flag change?  It is approved.

I'm not sure the C standard mandates compatibility between

struct { int i; } and struct { unsigned i; } for purposes of TBAA.
Joseph?

Thanks,
Richard.

>   - way to decide if two types have compatible memory representation 
>     (to test in lto-symtab and for some cases in ipa-icf (contructors/pure
>      moves))
>     operands_equal_p/compare_constant/ipa-icf::sem_variable all implements
>     bit of this. copmare_constant seems to be most complete.
>   - way to decide if two types match by TBAA oracle
>     (to test in lto-symtab merging and for ipa-icf memory operations)
>   - way to decide if one type is semantically compatible to other
>     (useless_type_conversion_p)
>   - way to decide if two types are same for canonical type computation
>     (gimple_type_compatible_p).  This may be sensitive to the set of languages
>     we are merging and enable/disable various globbing as required.
> 
> It may make sense to refactor the type walkers and get this more organized.
> But before playing with this I think we want to get something conservatively
> correct according to language standards and get a reasonable body of testcases.
> 
> This is a variant of patch that removes TYPE_UNSIGNED testing completely.
> I am fine with both variants.
> 
> Bootstrapped/regtested ppc64le-linux.
> 
> Honza
> 
> 	* gimple-expr.c (useless_type_conversion_p): Move
> 	INTEGER_TYPE handling ahead.
> 	* tree.c (gimple_canonical_types_compatible_p): Do not compare
> 	TYPE_UNSIGNED for size_t and char compatible types; do not hash
> 	STRING_FLAG on integer types.
> 
> 	* lto.c (hash_canonical_type): Do not hash TYPE_UNSIGNED for size_t
> 	and char compatible types; do not hash STRING_FLAG on integer types.
> 
> 	* gfortran.dg/lto/bind_c-2_0.f90: New testcase.
> 	* gfortran.dg/lto/bind_c-2_1.c: New testcase.
> 	* gfortran.dg/lto/bind_c-3_0.f90: New testcase.
> 	* gfortran.dg/lto/bind_c-3_1.c: New testcase.
> 	* gfortran.dg/lto/bind_c-4_0.f90: New testcase.
> 	* gfortran.dg/lto/bind_c-4_1.c: New testcase.
> Index: gimple-expr.c
> ===================================================================
> --- gimple-expr.c	(revision 224201)
> +++ gimple-expr.c	(working copy)
> @@ -91,30 +91,14 @@
>  	       || TREE_CODE (TREE_TYPE (inner_type)) == METHOD_TYPE))
>  	return false;
>      }
> -
> -  /* From now on qualifiers on value types do not matter.  */
> -  inner_type = TYPE_MAIN_VARIANT (inner_type);
> -  outer_type = TYPE_MAIN_VARIANT (outer_type);
> -
> -  if (inner_type == outer_type)
> -    return true;
> -
> -  /* If we know the canonical types, compare them.  */
> -  if (TYPE_CANONICAL (inner_type)
> -      && TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type))
> -    return true;
> -
> -  /* Changes in machine mode are never useless conversions unless we
> -     deal with aggregate types in which case we defer to later checks.  */
> -  if (TYPE_MODE (inner_type) != TYPE_MODE (outer_type)
> -      && !AGGREGATE_TYPE_P (inner_type))
> -    return false;
> -
>    /* If both the inner and outer types are integral types, then the
>       conversion is not necessary if they have the same mode and
> -     signedness and precision, and both or neither are boolean.  */
> -  if (INTEGRAL_TYPE_P (inner_type)
> -      && INTEGRAL_TYPE_P (outer_type))
> +     signedness and precision, and both or neither are boolean.
> +
> +     Do not rely on TYPE_CANONICAL here because LTO puts same canonical
> +     type for signed char and unsigned char.  */
> +  else if (INTEGRAL_TYPE_P (inner_type)
> +           && INTEGRAL_TYPE_P (outer_type))
>      {
>        /* Preserve changes in signedness or precision.  */
>        if (TYPE_UNSIGNED (inner_type) != TYPE_UNSIGNED (outer_type)
> @@ -134,6 +118,25 @@
>        return true;
>      }
>  
> +
> +  /* From now on qualifiers on value types do not matter.  */
> +  inner_type = TYPE_MAIN_VARIANT (inner_type);
> +  outer_type = TYPE_MAIN_VARIANT (outer_type);
> +
> +  if (inner_type == outer_type)
> +    return true;
> +
> +  /* If we know the canonical types, compare them.  */
> +  if (TYPE_CANONICAL (inner_type)
> +      && TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type))
> +    return true;
> +
> +  /* Changes in machine mode are never useless conversions unless we
> +     deal with aggregate types in which case we defer to later checks.  */
> +  if (TYPE_MODE (inner_type) != TYPE_MODE (outer_type)
> +      && !AGGREGATE_TYPE_P (inner_type))
> +    return false;
> +
>    /* Scalar floating point types with the same mode are compatible.  */
>    else if (SCALAR_FLOAT_TYPE_P (inner_type)
>  	   && SCALAR_FLOAT_TYPE_P (outer_type))
> Index: lto/lto.c
> ===================================================================
> --- lto/lto.c	(revision 224201)
> +++ lto/lto.c	(working copy)
> @@ -303,6 +303,7 @@
>  hash_canonical_type (tree type)
>  {
>    inchash::hash hstate;
> +  enum tree_code code;
>  
>    /* We compute alias sets only for types that needs them.
>       Be sure we do not recurse to something else as we can not hash incomplete
> @@ -314,7 +315,8 @@
>       smaller sets; when searching for existing matching types to merge,
>       only existing types having the same features as the new type will be
>       checked.  */
> -  hstate.add_int (tree_code_for_canonical_type_merging (TREE_CODE (type)));
> +  code = tree_code_for_canonical_type_merging (TREE_CODE (type));
> +  hstate.add_int (code);
>    hstate.add_int (TYPE_MODE (type));
>  
>    /* Incorporate common features of numerical types.  */
> @@ -324,8 +326,13 @@
>        || TREE_CODE (type) == OFFSET_TYPE
>        || POINTER_TYPE_P (type))
>      {
> -      hstate.add_int (TYPE_UNSIGNED (type));
>        hstate.add_int (TYPE_PRECISION (type));
> +      /* Ignore TYPE_SIGNED. This is needed for Fortran
> +	 C_SIGNED_CHAR to be interoperable with both signed char and
> +	 unsigned char (as stadnard requires).  Similarly Fortran FE builds
> +	 C_SIZE_T is signed type, while C defines it unsigned.
> +	 NOTE 15.8 of Fortran 2008 seems to imply that even other types ought
> +	 to be inter-operable. */
>      }
>  
>    if (VECTOR_TYPE_P (type))
> @@ -345,9 +352,9 @@
>        hstate.add_int (TYPE_ADDR_SPACE (TREE_TYPE (type)));
>      }
>  
> -  /* For integer types hash only the string flag.  */
> -  if (TREE_CODE (type) == INTEGER_TYPE)
> -    hstate.add_int (TYPE_STRING_FLAG (type));
> +  /* Fortran FE does not set string flag for C_SIGNED_CHAR while C
> +     sets it for signed char.  To use STRING_FLAG to define canonical types,
> +     the frontends would need to agree.  */
>  
>    /* For array types hash the domain bounds and the string flag.  */
>    if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
> Index: testsuite/gfortran.dg/lto/bind_c-2_0.f90
> ===================================================================
> --- testsuite/gfortran.dg/lto/bind_c-2_0.f90	(revision 0)
> +++ testsuite/gfortran.dg/lto/bind_c-2_0.f90	(working copy)
> @@ -0,0 +1,21 @@
> +! { dg-lto-do run }
> +! { dg-lto-options {{ -O3 -flto }} }
> +! This testcase will abort if C_PTR is not interoperable with both int *
> +! and float *
> +module lto_type_merge_test
> +  use, intrinsic :: iso_c_binding
> +  implicit none
> +
> +  type, bind(c) :: MYFTYPE_1
> +     integer(c_signed_char) :: chr
> +     integer(c_signed_char) :: chrb
> +  end type MYFTYPE_1
> +
> +  type(myftype_1), bind(c, name="myVar") :: myVar
> +
> +contains
> +  subroutine types_test() bind(c)
> +    myVar%chr = myVar%chrb
> +  end subroutine types_test
> +end module lto_type_merge_test
> +
> Index: testsuite/gfortran.dg/lto/bind_c-2_1.c
> ===================================================================
> --- testsuite/gfortran.dg/lto/bind_c-2_1.c	(revision 0)
> +++ testsuite/gfortran.dg/lto/bind_c-2_1.c	(working copy)
> @@ -0,0 +1,36 @@
> +#include <stdlib.h>
> +/* interopse with myftype_1 */
> +typedef struct {
> +   unsigned char chr;
> +   signed char chr2;
> +} myctype_t;
> +
> +
> +extern void abort(void);
> +void types_test(void);
> +/* declared in the fortran module */
> +extern myctype_t myVar;
> +
> +int main(int argc, char **argv)
> +{
> +   myctype_t *cchr;
> +   asm("":"=r"(cchr):"0"(&myVar));
> +   cchr->chr = 1;
> +   cchr->chr2 = 2;
> +
> +   types_test();
> +
> +   if(cchr->chr != 2)
> +      abort();
> +   if(cchr->chr2 != 2)
> +      abort();
> +   myVar.chr2 = 3;
> +   types_test();
> +
> +   if(myVar.chr != 3)
> +      abort();
> +   if(myVar.chr2 != 3)
> +      abort();
> +   return 0;
> +}
> +
> Index: testsuite/gfortran.dg/lto/bind_c-3_0.f90
> ===================================================================
> --- testsuite/gfortran.dg/lto/bind_c-3_0.f90	(revision 0)
> +++ testsuite/gfortran.dg/lto/bind_c-3_0.f90	(working copy)
> @@ -0,0 +1,91 @@
> +! { dg-lto-do run }
> +! { dg-lto-options {{ -O3 -flto }} }
> +! This testcase will abort if integer types are not interoperable.
> +module lto_type_merge_test
> +  use, intrinsic :: iso_c_binding
> +  implicit none
> +
> +  type, bind(c) :: MYFTYPE_1
> +    integer(c_int) :: val_int
> +    integer(c_short) :: val_short
> +    integer(c_long) :: val_long
> +    integer(c_long_long) :: val_long_long
> +    integer(c_size_t) :: val_size_t
> +    integer(c_int8_t) :: val_int8_t
> +    integer(c_int16_t) :: val_int16_t
> +    integer(c_int32_t) :: val_int32_t
> +    integer(c_int64_t) :: val_int64_t
> +    integer(c_int_least8_t) :: val_intleast_8_t
> +    integer(c_int_least16_t) :: val_intleast_16_t
> +    integer(c_int_least32_t) :: val_intleast_32_t
> +    integer(c_int_least64_t) :: val_intleast_64_t
> +    integer(c_int_fast8_t) :: val_intfast_8_t
> +    integer(c_int_fast16_t) :: val_intfast_16_t
> +    integer(c_int_fast32_t) :: val_intfast_32_t
> +    integer(c_int_fast64_t) :: val_intfast_64_t
> +    integer(c_intmax_t) :: val_intmax_t
> +    integer(c_intptr_t) :: val_intptr_t
> +  end type MYFTYPE_1
> +
> +  type(myftype_1), bind(c, name="myVar") :: myVar
> +
> +contains
> +  subroutine types_test1() bind(c)
> +    myVar%val_int = 2
> +  end subroutine types_test1
> +  subroutine types_test2() bind(c)
> +    myVar%val_short = 2
> +  end subroutine types_test2
> +  subroutine types_test3() bind(c)
> +    myVar%val_long = 2
> +  end subroutine types_test3
> +  subroutine types_test4() bind(c)
> +    myVar%val_long_long = 2
> +  end subroutine types_test4
> +  subroutine types_test5() bind(c)
> +    myVar%val_size_t = 2
> +  end subroutine types_test5
> +  subroutine types_test6() bind(c)
> +    myVar%val_int8_t = 2
> +  end subroutine types_test6
> +  subroutine types_test7() bind(c)
> +    myVar%val_int16_t = 2
> +  end subroutine types_test7
> +  subroutine types_test8() bind(c)
> +    myVar%val_int32_t = 2
> +  end subroutine types_test8
> +  subroutine types_test9() bind(c)
> +    myVar%val_int64_t = 2
> +  end subroutine types_test9
> +  subroutine types_test10() bind(c)
> +    myVar%val_intleast_8_t = 2
> +  end subroutine types_test10
> +  subroutine types_test11() bind(c)
> +    myVar%val_intleast_16_t = 2
> +  end subroutine types_test11
> +  subroutine types_test12() bind(c)
> +    myVar%val_intleast_32_t = 2
> +  end subroutine types_test12
> +  subroutine types_test13() bind(c)
> +    myVar%val_intleast_64_t = 2
> +  end subroutine types_test13
> +  subroutine types_test14() bind(c)
> +    myVar%val_intfast_8_t = 2
> +  end subroutine types_test14
> +  subroutine types_test15() bind(c)
> +    myVar%val_intfast_16_t = 2
> +  end subroutine types_test15
> +  subroutine types_test16() bind(c)
> +    myVar%val_intfast_32_t = 2
> +  end subroutine types_test16
> +  subroutine types_test17() bind(c)
> +    myVar%val_intfast_64_t = 2
> +  end subroutine types_test17
> +  subroutine types_test18() bind(c)
> +    myVar%val_intmax_t = 2
> +  end subroutine types_test18
> +  subroutine types_test19() bind(c)
> +    myVar%val_intptr_t = 2
> +  end subroutine types_test19
> +end module lto_type_merge_test
> +
> Index: testsuite/gfortran.dg/lto/bind_c-3_1.c
> ===================================================================
> --- testsuite/gfortran.dg/lto/bind_c-3_1.c	(revision 0)
> +++ testsuite/gfortran.dg/lto/bind_c-3_1.c	(working copy)
> @@ -0,0 +1,78 @@
> +#include <stdlib.h>
> +#include <stdint.h>
> +/* interopse with myftype_1 */
> +typedef struct {
> +  int val1;
> +  short int val2;
> +  long int val3;
> +  long long int val4;
> +  size_t val5;
> +  int8_t val6;
> +  int16_t val7;
> +  int32_t val8;
> +  int64_t val9;
> +  int_least8_t val10;
> +  int_least16_t val11;
> +  int_least32_t val12;
> +  int_least64_t val13;
> +  int_fast8_t val14;
> +  int_fast16_t val15;
> +  int_fast32_t val16;
> +  int_fast64_t val17;
> +  intmax_t val18;
> +  intptr_t val19;
> +} myctype_t;
> +
> +
> +extern void abort(void);
> +void types_test1(void);
> +void types_test2(void);
> +void types_test3(void);
> +void types_test4(void);
> +void types_test5(void);
> +void types_test6(void);
> +void types_test7(void);
> +void types_test8(void);
> +void types_test9(void);
> +void types_test10(void);
> +void types_test11(void);
> +void types_test12(void);
> +void types_test13(void);
> +void types_test14(void);
> +void types_test15(void);
> +void types_test16(void);
> +void types_test17(void);
> +void types_test18(void);
> +void types_test19(void);
> +/* declared in the fortran module */
> +extern myctype_t myVar;
> +
> +#define test(n)\
> +  cchr->val##n = 1; types_test##n (); if (cchr->val##n != 2) abort ();
> +
> +int main(int argc, char **argv)
> +{
> +   myctype_t *cchr;
> +   asm("":"=r"(cchr):"0"(&myVar));
> +   test(1);
> +   test(2);
> +   test(3);
> +   test(4);
> +   test(5);
> +   test(6);
> +   test(7);
> +   test(8);
> +   test(9);
> +   test(10);
> +   test(11);
> +   test(12);
> +   test(13);
> +   test(14);
> +   test(15);
> +   test(16);
> +   test(17);
> +   test(18);
> +   test(19);
> +   return 0;
> +}
> +
> Index: testsuite/gfortran.dg/lto/bind_c-4_0.f90
> ===================================================================
> --- testsuite/gfortran.dg/lto/bind_c-4_0.f90	(revision 0)
> +++ testsuite/gfortran.dg/lto/bind_c-4_0.f90	(working copy)
> @@ -0,0 +1,48 @@
> +! { dg-lto-do run }
> +! { dg-lto-options {{ -O3 -flto }} }
> +! This testcase will abort if real/complex/boolean/character types are not interoperable
> +module lto_type_merge_test
> +  use, intrinsic :: iso_c_binding
> +  implicit none
> +
> +  type, bind(c) :: MYFTYPE_1
> +    real(c_float) :: val_1
> +    real(c_double) :: val_2
> +    real(c_long_double) :: val_3
> +    complex(c_float_complex) :: val_4
> +    complex(c_double_complex) :: val_5
> +    complex(c_long_double_complex) :: val_6
> +    logical(c_bool) :: val_7
> +    !FIXME: Fortran define c_char as array of size 1.
> +    !character(c_char) :: val_8
> +  end type MYFTYPE_1
> +
> +  type(myftype_1), bind(c, name="myVar") :: myVar
> +
> +contains
> +  subroutine types_test1() bind(c)
> +    myVar%val_1 = 2
> +  end subroutine types_test1
> +  subroutine types_test2() bind(c)
> +    myVar%val_2 = 2
> +  end subroutine types_test2
> +  subroutine types_test3() bind(c)
> +    myVar%val_3 = 2
> +  end subroutine types_test3
> +  subroutine types_test4() bind(c)
> +    myVar%val_4 = 2
> +  end subroutine types_test4
> +  subroutine types_test5() bind(c)
> +    myVar%val_5 = 2
> +  end subroutine types_test5
> +  subroutine types_test6() bind(c)
> +    myVar%val_6 = 2
> +  end subroutine types_test6
> +  subroutine types_test7() bind(c)
> +    myVar%val_7 = myVar%val_7 .or. .not. myVar%val_7
> +  end subroutine types_test7
> +  !subroutine types_test8() bind(c)
> +    !myVar%val_8 = "a"
> +  !end subroutine types_test8
> +end module lto_type_merge_test
> +
> Index: testsuite/gfortran.dg/lto/bind_c-4_1.c
> ===================================================================
> --- testsuite/gfortran.dg/lto/bind_c-4_1.c	(revision 0)
> +++ testsuite/gfortran.dg/lto/bind_c-4_1.c	(working copy)
> @@ -0,0 +1,46 @@
> +#include <stdlib.h>
> +#include <stdint.h>
> +/* interopse with myftype_1 */
> +typedef struct {
> +  float val1;
> +  double val2;
> +  long double val3;
> +  float _Complex val4;
> +  double _Complex val5;
> +  long double _Complex val6;
> +  _Bool val7;
> +  /* FIXME: Fortran define c_char as array of size 1.
> +     char val8;  */
> +} myctype_t;
> +
> +
> +extern void abort(void);
> +void types_test1(void);
> +void types_test2(void);
> +void types_test3(void);
> +void types_test4(void);
> +void types_test5(void);
> +void types_test6(void);
> +void types_test7(void);
> +void types_test8(void);
> +/* declared in the fortran module */
> +extern myctype_t myVar;
> +
> +#define test(n)\
> +  cchr->val##n = 1; types_test##n (); if (cchr->val##n != 2) abort ();
> +
> +int main(int argc, char **argv)
> +{
> +   myctype_t *cchr;
> +   asm("":"=r"(cchr):"0"(&myVar));
> +   test(1);
> +   test(2);
> +   test(3);
> +   test(4);
> +   test(5);
> +   test(6);
> +   cchr->val7 = 0; types_test7 (); if (cchr->val7 != 1) abort ();
> +   /*cchr->val8 = 0; types_test8 (); if (cchr->val8 != 'a') abort ();*/
> +   return 0;
> +}
> +
> Index: tree.c
> ===================================================================
> --- tree.c	(revision 224201)
> +++ tree.c	(working copy)
> @@ -12925,8 +12925,8 @@
>      return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
>  
>    /* Can't be the same type if the types don't have the same code.  */
> -  if (tree_code_for_canonical_type_merging (TREE_CODE (t1))
> -      != tree_code_for_canonical_type_merging (TREE_CODE (t2)))
> +  enum tree_code code = tree_code_for_canonical_type_merging (TREE_CODE (t1));
> +  if (code != tree_code_for_canonical_type_merging (TREE_CODE (t2)))
>      return false;
>  
>    /* Qualifiers do not matter for canonical type comparison purposes.  */
> @@ -12949,14 +12949,19 @@
>        || TREE_CODE (t1) == OFFSET_TYPE
>        || POINTER_TYPE_P (t1))
>      {
> -      /* Can't be the same type if they have different sign or precision.  */
> -      if (TYPE_PRECISION (t1) != TYPE_PRECISION (t2)
> -	  || TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2))
> +      /* Can't be the same type if they have different recision.  */
> +      if (TYPE_PRECISION (t1) != TYPE_PRECISION (t2))
>  	return false;
> +      /* Ignore TYPE_SIGNED.  This is needed for Fortran
> +	 C_SIGNED_CHAR to be interoperable with both signed char and
> +	 unsigned char (as stadnard requires).  Similarly Fortran FE builds
> +	 C_SIZE_T is signed type, while C defines it unsigned.
> +	 NOTE 15.8 of Fortran 2008 seems to imply that even other types ought
> +	 to be inter-operable. */
>  
> -      if (TREE_CODE (t1) == INTEGER_TYPE
> -	  && TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2))
> -	return false;
> +      /* Fortran FE does not set STRING_FLAG for C_SIGNED_CHAR while C
> +	 sets it for signed char.  To use string flag to define canonical
> +	 types, the frontends would need to agree.  */
>  
>        /* Fortran standard define C_PTR type that is compatible with every
>   	 C pointer.  For this reason we need to glob all pointers into one.
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-08 13:43     ` Richard Biener
@ 2015-06-08 14:07       ` Joseph Myers
  2015-06-08 14:32         ` Richard Biener
  2015-06-08 15:08       ` Jan Hubicka
  2015-06-08 23:01       ` Jan Hubicka
  2 siblings, 1 reply; 35+ messages in thread
From: Joseph Myers @ 2015-06-08 14:07 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jan Hubicka, gcc-patches, burnus

On Mon, 8 Jun 2015, Richard Biener wrote:

> I'm not sure the C standard mandates compatibility between
> 
> struct { int i; } and struct { unsigned i; } for purposes of TBAA.
> Joseph?

I don't think they are necessarily compatible for TBAA.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-08 14:07       ` Joseph Myers
@ 2015-06-08 14:32         ` Richard Biener
  2015-06-08 14:44           ` Joseph Myers
  0 siblings, 1 reply; 35+ messages in thread
From: Richard Biener @ 2015-06-08 14:32 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Jan Hubicka, gcc-patches, burnus

On Mon, 8 Jun 2015, Joseph Myers wrote:

> On Mon, 8 Jun 2015, Richard Biener wrote:
> 
> > I'm not sure the C standard mandates compatibility between
> > 
> > struct { int i; } and struct { unsigned i; } for purposes of TBAA.
> > Joseph?
> 
> I don't think they are necessarily compatible for TBAA.

Ok, but as int and unsigned are reading either structs element
via a pointer to int or a pointer to unsigned must be supported?
(The C FE ensures this via alias-subsets and the get_alias_set
langhook returning the same alias sets for int and unsigned)

Richard.

-- 
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-08 14:32         ` Richard Biener
@ 2015-06-08 14:44           ` Joseph Myers
  2015-06-08 14:52             ` Jan Hubicka
  0 siblings, 1 reply; 35+ messages in thread
From: Joseph Myers @ 2015-06-08 14:44 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jan Hubicka, gcc-patches, burnus

On Mon, 8 Jun 2015, Richard Biener wrote:

> On Mon, 8 Jun 2015, Joseph Myers wrote:
> 
> > On Mon, 8 Jun 2015, Richard Biener wrote:
> > 
> > > I'm not sure the C standard mandates compatibility between
> > > 
> > > struct { int i; } and struct { unsigned i; } for purposes of TBAA.
> > > Joseph?
> > 
> > I don't think they are necessarily compatible for TBAA.
> 
> Ok, but as int and unsigned are reading either structs element
> via a pointer to int or a pointer to unsigned must be supported?

Yes.  The questionable case would be taking an object of one of those 
structure types, casting a pointer to it to point to the other structure 
type and then dereferencing.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-08 14:44           ` Joseph Myers
@ 2015-06-08 14:52             ` Jan Hubicka
  2015-06-08 14:54               ` Richard Biener
  0 siblings, 1 reply; 35+ messages in thread
From: Jan Hubicka @ 2015-06-08 14:52 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Richard Biener, Jan Hubicka, gcc-patches, burnus

> On Mon, 8 Jun 2015, Richard Biener wrote:
> 
> > On Mon, 8 Jun 2015, Joseph Myers wrote:
> > 
> > > On Mon, 8 Jun 2015, Richard Biener wrote:
> > > 
> > > > I'm not sure the C standard mandates compatibility between
> > > > 
> > > > struct { int i; } and struct { unsigned i; } for purposes of TBAA.
> > > > Joseph?
> > > 
> > > I don't think they are necessarily compatible for TBAA.
> > 
> > Ok, but as int and unsigned are reading either structs element
> > via a pointer to int or a pointer to unsigned must be supported?
> 
> Yes.  The questionable case would be taking an object of one of those 
> structure types, casting a pointer to it to point to the other structure 
> type and then dereferencing.

Are "struct { int i; }" and "struct { unsigned i; }" compatible when one is defined
in one unit and other in another?
In any cae, I suppose if int and unsigned int pointers can be used interchangeably,
we want to ignore TYPE_UNSGINED for purposes of canonical type calculation for LTO.
So is the second variant of patch OK with a comment update that this is also required
by C?

Honza
> 
> -- 
> Joseph S. Myers
> joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-08 14:52             ` Jan Hubicka
@ 2015-06-08 14:54               ` Richard Biener
  2015-06-08 15:11                 ` Jan Hubicka
  0 siblings, 1 reply; 35+ messages in thread
From: Richard Biener @ 2015-06-08 14:54 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Joseph Myers, gcc-patches, burnus

On Mon, 8 Jun 2015, Jan Hubicka wrote:

> > On Mon, 8 Jun 2015, Richard Biener wrote:
> > 
> > > On Mon, 8 Jun 2015, Joseph Myers wrote:
> > > 
> > > > On Mon, 8 Jun 2015, Richard Biener wrote:
> > > > 
> > > > > I'm not sure the C standard mandates compatibility between
> > > > > 
> > > > > struct { int i; } and struct { unsigned i; } for purposes of TBAA.
> > > > > Joseph?
> > > > 
> > > > I don't think they are necessarily compatible for TBAA.
> > > 
> > > Ok, but as int and unsigned are reading either structs element
> > > via a pointer to int or a pointer to unsigned must be supported?
> > 
> > Yes.  The questionable case would be taking an object of one of those 
> > structure types, casting a pointer to it to point to the other structure 
> > type and then dereferencing.
> 
> Are "struct { int i; }" and "struct { unsigned i; }" compatible when one is defined
> in one unit and other in another?
> In any cae, I suppose if int and unsigned int pointers can be used interchangeably,
> we want to ignore TYPE_UNSGINED for purposes of canonical type calculation for LTO.
> So is the second variant of patch OK with a comment update that this is also required
> by C?

I think we should instead work towards eliminating the get_alias_set
langhook first.  The LTO langhook variant contains the same handling, btw,
so just inline that into get_alias_set and see what remains?

Richard.

> Honza
> > 
> > -- 
> > Joseph S. Myers
> > joseph@codesourcery.com
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-08 13:43     ` Richard Biener
  2015-06-08 14:07       ` Joseph Myers
@ 2015-06-08 15:08       ` Jan Hubicka
  2015-06-08 16:54         ` Joseph Myers
  2015-06-08 23:01       ` Jan Hubicka
  2 siblings, 1 reply; 35+ messages in thread
From: Jan Hubicka @ 2015-06-08 15:08 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jan Hubicka, gcc-patches, burnus, Joseph S. Myers

> On Mon, 8 Jun 2015, Jan Hubicka wrote:
> 
> > Hi,
> > this is a variant of patch that globs also the rest of integer types.
> > Note that we will still get false warnings out of lto-symtab when the
> > values are not wrapped up in structures.  This is because lto-symtab
> > uses types_compatible_p that in turn uses useless_type_conversion and
> > that one needs to honor signedness.
> > 
> > I suppose we need a way to test representation compatibility and TBAA
> > compatiblity. I will give it a more tought how to reorganize the code.
> > Basically we need
> 
> representation compatibility is TYPE_CANONICAL equivalence, TBAA
> compatibility is get_alias_set equivalence.
> 
> So you have to be careful when mangling TYPE_CANONICAL according to
> get_alias_set and make sure to only apply this (signedness for example)
> for aggregate type components.

Hmm, OK, so you think that 

TYPE_CANONICAL (int) != TYPE_CANONICAL (unsigned int)
get_alias_set (TYPE_CANONICAL (int)) == get_alias_set (TYPE_CANONICAL (unsigned int))
TYPE_CANOINCAL (struct {int}) == TYPE_CANONICAL (struct {unsgined int})

I suppose that makes sense because the actual fields of structure are not
really used for semantics (it depends on what FIELD_DECL we pull out).  

I will build testcase and send a patch that will glob alias set of signed and
usigned types in LTO's own get_lias_set hook.  I do not think we need to punish
aliasing of non-C languages (without LTO) by putting it all the way to alias.c.

As for structures, I have the following plan.

I plan to add computation of canonical types of pointers that will use
the canonical type of pointed-to type same was as non-LTO path does.
This however can not be propagated up to structure fields, since
pointer to complete structure must be compatile to pointer to incomplete
type.  I suppose signed and unsgined values can be handled the same way.
We thus need to track in hash_canonical_type and gimple_types_compatible_p
if we are in a subtype of aggregate/array and if so, we don't want to use
TYPE_CANONICAL of the nested type and instead just recurse with more coarsce
equivalence defined.


Joseph, I may be wrong, but I believe that the cross-compilation-unit
representation compatibility (in C standard sense) is however not an
equivalence class, so it can't be fully represented by TYPE_CANOINICAL
equivalence.

We may want to warn about types not being compatible when compiling:

a.c:
struct b {int c;};
struct a {struct b *ptr;} var;

b.c:
struct b {long c;};
struct a {struct b *ptr;} var;

pointers are not required to be compatible with each other.

Or in more ugly way
int a[5]; as a structure field may be compatible with int a[b];
int a[b] is compatible with int a[10];
But in a[5] is not compatible with int a[10];

I am not sure if TYPE_CANONICAL of a structure with fixed size array
should match TYPE_CANONICAL of similarly looking structure with VLA.
> 
> Can you please split out the string-flag change?  It is approved.

OK, I will split it and commit it with the corresponding parts of the testcase
commented out.  Thanks!

Honza

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-08 14:54               ` Richard Biener
@ 2015-06-08 15:11                 ` Jan Hubicka
  2015-06-08 15:32                   ` Fortran's C_CHAR type Jan Hubicka
  2015-06-09  9:50                   ` Fix more of C/fortran canonical type issues Richard Biener
  0 siblings, 2 replies; 35+ messages in thread
From: Jan Hubicka @ 2015-06-08 15:11 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jan Hubicka, Joseph Myers, gcc-patches, burnus

> 
> I think we should instead work towards eliminating the get_alias_set
> langhook first.  The LTO langhook variant contains the same handling, btw,
> so just inline that into get_alias_set and see what remains?

I see, i completely missed existence of gimple_get_alias_set. It makes more
sense now.

Is moving everyting to alias.c realy a desirable thing? If non-C languages do
not have this rule, why we want to reduce the code quality when compiling
those?

Honza
> 
> Richard.
> 
> > Honza
> > > 
> > > -- 
> > > Joseph S. Myers
> > > joseph@codesourcery.com
> > 
> > 
> 
> -- 
> Richard Biener <rguenther@suse.de>
> SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Fortran's C_CHAR type
  2015-06-08 15:11                 ` Jan Hubicka
@ 2015-06-08 15:32                   ` Jan Hubicka
  2015-06-10 11:50                     ` Mikael Morin
  2015-06-09  9:50                   ` Fix more of C/fortran canonical type issues Richard Biener
  1 sibling, 1 reply; 35+ messages in thread
From: Jan Hubicka @ 2015-06-08 15:32 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Richard Biener, Joseph Myers, gcc-patches, burnus

Hi,
to furhter add to the topics to discuss, I noticed that Fortran FE seems to be quite
ambivalent about C_CHAR type:
[jh@gcc2-power8 gcc]$ cat ../b.f90
! This testcase will abort if C_CHAR types are not interoperable
module lto_type_merge_test
  use, intrinsic :: iso_c_binding
  implicit none

contains
  function types_test1(V) bind(c)
    USE, INTRINSIC :: ISO_C_BINDING
    CHARACTER(C_CHAR) :: types_test1
    CHARACTER(C_CHAR), VALUE :: V
    types_test1 = V
  end function types_test1
end module lto_type_merge_test

[jh@gcc2-power8 gcc]$ cat ../a.c
extern unsigned char types_test1 (char v);
void
main ()
{ 
  if (types_test1 ('a') != 'a')
    __builtin_abort ();
  return 0;
}

As my fortran-fu goes, i think this testcase is correct. Fortran FE however
builds types_test1 as a function return char but taking the array of size of 1
as a parameter.  I think it is just kind of coincidence that those are passed the
same way for x86-64 and may not be quite the case for other targets.

If the testcase seems valid, I would like to commit it to the non-LTO testsuite
so we get this tested.

With LTO we get bogus types mismatch warning and types_test1 won't be inlined
for this reason.

Honza

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-08 15:08       ` Jan Hubicka
@ 2015-06-08 16:54         ` Joseph Myers
  2015-06-08 16:57           ` Jan Hubicka
  0 siblings, 1 reply; 35+ messages in thread
From: Joseph Myers @ 2015-06-08 16:54 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Richard Biener, gcc-patches, burnus

On Mon, 8 Jun 2015, Jan Hubicka wrote:

> Joseph, I may be wrong, but I believe that the cross-compilation-unit
> representation compatibility (in C standard sense) is however not an
> equivalence class, so it can't be fully represented by TYPE_CANOINICAL

Indeed, type compatibility is not transitive, but the expressed intention 
of WG14 in response to DR#314 is that in a valid program it should be 
possible to merge the translation units, unifying structure and union 
types across translation units (with renaming as needed).

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-08 16:54         ` Joseph Myers
@ 2015-06-08 16:57           ` Jan Hubicka
  2015-06-08 17:03             ` Joseph Myers
  0 siblings, 1 reply; 35+ messages in thread
From: Jan Hubicka @ 2015-06-08 16:57 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Jan Hubicka, Richard Biener, gcc-patches, burnus

> On Mon, 8 Jun 2015, Jan Hubicka wrote:
> 
> > Joseph, I may be wrong, but I believe that the cross-compilation-unit
> > representation compatibility (in C standard sense) is however not an
> > equivalence class, so it can't be fully represented by TYPE_CANOINICAL
> 
> Indeed, type compatibility is not transitive, but the expressed intention 
> of WG14 in response to DR#314 is that in a valid program it should be 
> possible to merge the translation units, unifying structure and union 
> types across translation units (with renaming as needed).

Thank you. It is interesting that the DR exists. We do have comments about
possibly completing the types by equiality established by the symbol table
but I tought it is strictly invalid.  Not sure how much that buy us though.
 As for specific examples.  Shall we warn for

a.c:
int a;

b.c:
unsigned int a;

(this seems perfectly valid by C/Fortran rules)

or

a.c
int *a;

b.c:
unsigned int *a;

or

a.c
struct a {int a;} a;

b.c:
struct a {unsigned int a} a;

so I assume the following is no longer valid

a.c:
struct a {int a;} *a;

b.c:
struct a *a;
struct a *b;

c.c:
struct b {float a;} *a;

as we may figure out that struct a in b.c does not have unique completetion.
> 
> -- 
> Joseph S. Myers
> joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-08 16:57           ` Jan Hubicka
@ 2015-06-08 17:03             ` Joseph Myers
  2015-06-08 22:06               ` Jan Hubicka
  0 siblings, 1 reply; 35+ messages in thread
From: Joseph Myers @ 2015-06-08 17:03 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Richard Biener, gcc-patches, burnus

On Mon, 8 Jun 2015, Jan Hubicka wrote:

> Thank you. It is interesting that the DR exists. We do have comments about
> possibly completing the types by equiality established by the symbol table
> but I tought it is strictly invalid.  Not sure how much that buy us though.
>  As for specific examples.  Shall we warn for
> 
> a.c:
> int a;
> 
> b.c:
> unsigned int a;
> 
> (this seems perfectly valid by C/Fortran rules)

That's clearly invalid (declarations of the same object with incompatible 
types).  int and unsigned int can alias, but declarations still need to be 
consistent.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-08 17:03             ` Joseph Myers
@ 2015-06-08 22:06               ` Jan Hubicka
  0 siblings, 0 replies; 35+ messages in thread
From: Jan Hubicka @ 2015-06-08 22:06 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Jan Hubicka, Richard Biener, gcc-patches, burnus

> On Mon, 8 Jun 2015, Jan Hubicka wrote:
> 
> > Thank you. It is interesting that the DR exists. We do have comments about
> > possibly completing the types by equiality established by the symbol table
> > but I tought it is strictly invalid.  Not sure how much that buy us though.
> >  As for specific examples.  Shall we warn for
> > 
> > a.c:
> > int a;
> > 
> > b.c:
> > unsigned int a;
> > 
> > (this seems perfectly valid by C/Fortran rules)
> 
> That's clearly invalid (declarations of the same object with incompatible 
> types).  int and unsigned int can alias, but declarations still need to be 
> consistent.

OK, so following the wording of the standard we have

2      All declarations that refer to the same object or function shall have compatible type;
       otherwise, the behavior is undefined.

in 6.2.7. The int and unsigned int is not considered compatible.

However the memory accesses are further discussed in 6.5

 7  An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
   1 a type compatible with the effective type of the object,
   2 a qualified version of a type compatible with the effective type of the object,
   3 a type that is the signed or unsigned type corresponding to the effective type of the object,
   4 a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
   5 an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
   6 a character type

So this is where the basic c_get_alias rules come from. i.e. 1-4 basically
boils down to ignoring qualifiers and signedness and 6 is about dropping char
into alias set 0, so this gives us some extra rules for TBAA compatibility that
however does not propagate up when building canonical types during LTO.

So we don't really need to ignore signedness for C/C++ only programs while
building canonical types (that correspond to the symmetric and transitive
closure of the notion of compatible types).

In C/Fortran mixed units however C_SIZE_T (that is signed type) is
interoperable with size_t (that is unsigned type) and this propagates up by:

  A  Fortran  derived  type  is interoperable with  a  C  struct  type  if  and
  only  if  the  Fortran  type  has  the BIND attribute (4.5.2), the Fortran
  derived type and the C struct type have the same number of components, and the
  components of the Fortran derived type would interoperate with corresponding
  components of the C struct type as described in 15.3.5 and 15.3.6 if the
  components were variables.  A component of a Fortran derived type and a
  component of a C struct type correspond if they are declared in the same
  relative position in their respective type de\fnitions.

So clearly Fortran's structure containing C_SIZE_T sould interoperate with
struct {size_t val;}.  So we do need to ignore TYPE_UNSIGNED when processing
fields of structures in C/fortran mixed programs and we should not warn
on a variable being declared both as size_t and C_SIZE_T.

Honza

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-08 13:43     ` Richard Biener
  2015-06-08 14:07       ` Joseph Myers
  2015-06-08 15:08       ` Jan Hubicka
@ 2015-06-08 23:01       ` Jan Hubicka
  2 siblings, 0 replies; 35+ messages in thread
From: Jan Hubicka @ 2015-06-08 23:01 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jan Hubicka, gcc-patches, burnus, Joseph S. Myers

> On Mon, 8 Jun 2015, Jan Hubicka wrote:
> 
> > Hi,
> > this is a variant of patch that globs also the rest of integer types.
> > Note that we will still get false warnings out of lto-symtab when the
> > values are not wrapped up in structures.  This is because lto-symtab
> > uses types_compatible_p that in turn uses useless_type_conversion and
> > that one needs to honor signedness.
> > 
> > I suppose we need a way to test representation compatibility and TBAA
> > compatiblity. I will give it a more tought how to reorganize the code.
> > Basically we need
> 
> representation compatibility is TYPE_CANONICAL equivalence, TBAA
> compatibility is get_alias_set equivalence.

Hmm, I still wonder what to use in lto-symtab's warn_type_compatibility_p.

Currently we use types_compatible_p which goes to useless conversion and
honnors TYPE_UNSIGNED, so it will give false positives for Fortran.
Comparing TYPE_CANONICAL for equivalence will be conservatively correct
for now (I will submit patch for that and prepare a testcases), but as
soon as we start computing finer TYPE_CANONICAL for pointers
we really want to avoid warning on C_PTR declaration in Fortran and
say float * in C.  This will have different canonical types (C_PTR is void *)
that are TBAA compatible.

Comparing get_alias_set will block warnings about representation incompatibility
in some cases, like when one of units is compiled with -fno-strict-aliasing.
Even then IMO we ought to warn when fortran declares variable as "C_DOUBLE"
and C declares it as "int *".

So I think we want to factor out the representation compatibility logic better
and make it separate from canonical type machinery.

> 
> So you have to be careful when mangling TYPE_CANONICAL according to
> get_alias_set and make sure to only apply this (signedness for example)
> for aggregate type components.
> 
> Can you please split out the string-flag change?  It is approved.

This is what I commited.

After the discussion I still think the second variant of patch (completely
dropping signed/unsigned) makes sense for C+fortran units though it is
unnecesarily coarse for C/C++ only units.  Given that the current plan is
to get things conservatively correct first, I would stick to it.

Bootstrapped/regtested ppc64le-linux, comitted.

Honza

	* lto.c (hash_canonical_type): Drop hashing of TYPE_STRING_FLAG.
	* tree.c (gimple_canonical_types_compatible_p): Drop comparsion of
	TYPE_STRING_FLAG.

	* gfortran.dg/lto/bind_c-2b_0.f90: New testcase
	* gfortran.dg/lto/bind_c-2b_1.c: New testcase
Index: lto/lto.c
===================================================================
--- lto/lto.c	(revision 224250)
+++ lto/lto.c	(working copy)
@@ -332,18 +332,16 @@
   if (TREE_CODE (type) == COMPLEX_TYPE)
     hstate.add_int (TYPE_UNSIGNED (type));
 
+  /* Fortran's C_SIGNED_CHAR is !TYPE_STRING_FLAG but needs to be
+     interoperable with "signed char".  Unless all frontends are revisited to
+     agree on these types, we must ignore the flag completely.  */
+
   /* Fortran standard define C_PTR type that is compatible with every
      C pointer.  For this reason we need to glob all pointers into one.
      Still pointers in different address spaces are not compatible.  */
   if (POINTER_TYPE_P (type))
-    {
-      hstate.add_int (TYPE_ADDR_SPACE (TREE_TYPE (type)));
-    }
+    hstate.add_int (TYPE_ADDR_SPACE (TREE_TYPE (type)));
 
-  /* For integer types hash only the string flag.  */
-  if (TREE_CODE (type) == INTEGER_TYPE)
-    hstate.add_int (TYPE_STRING_FLAG (type));
-
   /* For array types hash the domain bounds and the string flag.  */
   if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
     {
Index: testsuite/gfortran.dg/lto/bind_c-2b_0.f90
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-2b_0.f90	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-2b_0.f90	(working copy)
@@ -0,0 +1,21 @@
+! { dg-lto-do run }
+! { dg-lto-options {{ -O3 -flto }} }
+! This testcase will abort if C_SIGNED_CHAR is not interoperable with signed
+! char
+module lto_type_merge_test
+  use, intrinsic :: iso_c_binding
+  implicit none
+
+  type, bind(c) :: MYFTYPE_1
+     integer(c_signed_char) :: chr
+     integer(c_signed_char) :: chrb
+  end type MYFTYPE_1
+
+  type(myftype_1), bind(c, name="myVar") :: myVar
+
+contains
+  subroutine types_test() bind(c)
+    myVar%chr = myVar%chrb
+  end subroutine types_test
+end module lto_type_merge_test
+
Index: testsuite/gfortran.dg/lto/bind_c-2b_1.c
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-2b_1.c	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-2b_1.c	(working copy)
@@ -0,0 +1,36 @@
+#include <stdlib.h>
+/* interopse with myftype_1 */
+typedef struct {
+   signed char chr;
+   signed char chr2;
+} myctype_t;
+
+
+extern void abort(void);
+void types_test(void);
+/* declared in the fortran module */
+extern myctype_t myVar;
+
+int main(int argc, char **argv)
+{
+   myctype_t *cchr;
+   asm("":"=r"(cchr):"0"(&myVar));
+   cchr->chr = 1;
+   cchr->chr2 = 2;
+
+   types_test();
+
+   if(cchr->chr != 2)
+      abort();
+   if(cchr->chr2 != 2)
+      abort();
+   myVar.chr2 = 3;
+   types_test();
+
+   if(myVar.chr != 3)
+      abort();
+   if(myVar.chr2 != 3)
+      abort();
+   return 0;
+}
+
Index: tree.c
===================================================================
--- tree.c	(revision 224250)
+++ tree.c	(working copy)
@@ -12948,9 +12948,9 @@
 	  || TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2))
 	return false;
 
-      if (TREE_CODE (t1) == INTEGER_TYPE
-	  && TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2))
-	return false;
+      /* Fortran's C_SIGNED_CHAR is !TYPE_STRING_FLAG but needs to be
+	 interoperable with "signed char".  Unless all frontends are revisited
+	 to agree on these types, we must ignore the flag completely.  */
 
       /* Fortran standard define C_PTR type that is compatible with every
  	 C pointer.  For this reason we need to glob all pointers into one.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-08 15:11                 ` Jan Hubicka
  2015-06-08 15:32                   ` Fortran's C_CHAR type Jan Hubicka
@ 2015-06-09  9:50                   ` Richard Biener
  2015-06-09 17:24                     ` Jan Hubicka
  1 sibling, 1 reply; 35+ messages in thread
From: Richard Biener @ 2015-06-09  9:50 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Joseph Myers, gcc-patches, burnus

On Mon, 8 Jun 2015, Jan Hubicka wrote:

> > 
> > I think we should instead work towards eliminating the get_alias_set
> > langhook first.  The LTO langhook variant contains the same handling, btw,
> > so just inline that into get_alias_set and see what remains?
> 
> I see, i completely missed existence of gimple_get_alias_set. It makes more
> sense now.
> 
> Is moving everyting to alias.c realy a desirable thing? If non-C languages do
> not have this rule, why we want to reduce the code quality when compiling
> those?

Well, for consistency and for getting rid of one langhook ;)

Richard.

> Honza
> > 
> > Richard.
> > 
> > > Honza
> > > > 
> > > > -- 
> > > > Joseph S. Myers
> > > > joseph@codesourcery.com
> > > 
> > > 
> > 
> > -- 
> > Richard Biener <rguenther@suse.de>
> > SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nuernberg)
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Dilip Upmanyu, Graham Norton, HRB 21284 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-09  9:50                   ` Fix more of C/fortran canonical type issues Richard Biener
@ 2015-06-09 17:24                     ` Jan Hubicka
  2015-06-11 17:58                       ` Jan Hubicka
  2015-06-22  7:25                       ` Jan Hubicka
  0 siblings, 2 replies; 35+ messages in thread
From: Jan Hubicka @ 2015-06-09 17:24 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jan Hubicka, Joseph Myers, gcc-patches, burnus

> On Mon, 8 Jun 2015, Jan Hubicka wrote:
> 
> > > 
> > > I think we should instead work towards eliminating the get_alias_set
> > > langhook first.  The LTO langhook variant contains the same handling, btw,
> > > so just inline that into get_alias_set and see what remains?
> > 
> > I see, i completely missed existence of gimple_get_alias_set. It makes more
> > sense now.
> > 
> > Is moving everyting to alias.c realy a desirable thing? If non-C languages do
> > not have this rule, why we want to reduce the code quality when compiling
> > those?
> 
> Well, for consistency and for getting rid of one langhook ;)
:)
In a way this particular langhook makes sense to me - TBAA rules are language specific.
We also may with explicit streaming of the TBAA dag, like LLVM does.

Anyway, this is the updated patch fixing the Fortran's interoperability with
size_t and signed char.  I will send separate patch for the extra lto-symtab
warnings shortly.

I will be happy looking into the TYPE_CANONICAL (int) to be different from
TYPE_CANONICAL (unsigned int) if that seems desirable. There are two things that
needs to be solved - hash_canonical_type/gimple_canonical_types_compatible_p can't
use TYPE_CNAONICAL of subtypes in all cases (that is easy) and we will need some
way to recognize the conflict in lto-symtab other thanjust comparing TYPE_CANONICAL
to not warn when a variable is declared signed in Fortran unit and unsigned in C.

Bootstrapped/regtested ppc64le-linux.

	* lto/lto.c (hash_canonical_type): Do not hash TYPE_UNSIGNED
	of INTEGER_TYPE.
	* tree.c (gimple_canonical_types_compatible_p): Do not compare TYPE_UNSIGNED
	of INTEGER_TYPE.
	* gimple-expr.c (useless_type_conversion_p): Move INTEGER type handling
	ahead the canonical type lookup.

	* gfortran.dg/lto/bind_c-2_0.f90: New testcase
	* gfortran.dg/lto/bind_c-2_1.c: New testcase
	* gfortran.dg/lto/bind_c-3_0.f90: New testcase
	* gfortran.dg/lto/bind_c-3_1.c: New testcase
	* gfortran.dg/lto/bind_c-4_0.f90: New testcase
	* gfortran.dg/lto/bind_c-4_1.c: New testcase
Index: lto/lto.c
===================================================================
--- lto/lto.c	(revision 224252)
+++ lto/lto.c	(working copy)
@@ -298,6 +298,7 @@
 hash_canonical_type (tree type)
 {
   inchash::hash hstate;
+  enum tree_code code;
 
   /* We compute alias sets only for types that needs them.
      Be sure we do not recurse to something else as we can not hash incomplete
@@ -309,7 +310,8 @@
      smaller sets; when searching for existing matching types to merge,
      only existing types having the same features as the new type will be
      checked.  */
-  hstate.add_int (tree_code_for_canonical_type_merging (TREE_CODE (type)));
+  code = tree_code_for_canonical_type_merging (TREE_CODE (type));
+  hstate.add_int (code);
   hstate.add_int (TYPE_MODE (type));
 
   /* Incorporate common features of numerical types.  */
@@ -319,7 +321,14 @@
       || TREE_CODE (type) == OFFSET_TYPE
       || POINTER_TYPE_P (type))
     {
-      hstate.add_int (TYPE_UNSIGNED (type));
+      /* Some Fortran integer types are interoperable with C types regardless
+	 their signedness.  We need to ignore sign on these to make it
+	 possible for structure containing unsigned type to interoperate
+	 with structure containing signed type which is also required by
+	 the standard.  It is thus not enough to keep alias set of signed
+	 type same with alias set of unsigned type.  */
+      if (code != INTEGER_TYPE)
+        hstate.add_int (TYPE_UNSIGNED (type));
       hstate.add_int (TYPE_PRECISION (type));
     }
 
Index: tree.c
===================================================================
--- tree.c	(revision 224252)
+++ tree.c	(working copy)
@@ -12879,6 +12879,7 @@
 gimple_canonical_types_compatible_p (const_tree t1, const_tree t2,
 				     bool trust_type_canonical)
 {
+  enum tree_code code;
   /* Type variants should be same as the main variant.  When not doing sanity
      checking to verify this fact, go to main variants and save some work.  */
   if (trust_type_canonical)
@@ -12918,9 +12919,9 @@
       && trust_type_canonical)
     return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
 
+  code = tree_code_for_canonical_type_merging (TREE_CODE (t1));
   /* Can't be the same type if the types don't have the same code.  */
-  if (tree_code_for_canonical_type_merging (TREE_CODE (t1))
-      != tree_code_for_canonical_type_merging (TREE_CODE (t2)))
+  if (code != tree_code_for_canonical_type_merging (TREE_CODE (t2)))
     return false;
 
   /* Qualifiers do not matter for canonical type comparison purposes.  */
@@ -12945,7 +12946,14 @@
     {
       /* Can't be the same type if they have different sign or precision.  */
       if (TYPE_PRECISION (t1) != TYPE_PRECISION (t2)
-	  || TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2))
+	  /* Some Fortran integer types are interoperable with C types
+	     regardless their signedness.  We need to ignore sign on these to
+	     make it possible for structure containing unsigned type to
+	     interoperate with structure containing signed type which is also
+	     required by the standard.  It is thus not enough to keep alias set
+	     of signed type same with alias set of unsigned type.  */
+	  || (code != INTEGER_TYPE
+	      && TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2)))
 	return false;
 
       /* Fortran's C_SIGNED_CHAR is !TYPE_STRING_FLAG but needs to be
Index: testsuite/gfortran.dg/lto/bind_c-2_0.f90
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-2_0.f90	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-2_0.f90	(working copy)
@@ -0,0 +1,21 @@
+! { dg-lto-do run }
+! { dg-lto-options {{ -O3 -flto }} }
+! This testcase will abort if C_PTR is not interoperable with both int *
+! and float *
+module lto_type_merge_test
+  use, intrinsic :: iso_c_binding
+  implicit none
+
+  type, bind(c) :: MYFTYPE_1
+     integer(c_signed_char) :: chr
+     integer(c_signed_char) :: chrb
+  end type MYFTYPE_1
+
+  type(myftype_1), bind(c, name="myVar") :: myVar
+
+contains
+  subroutine types_test() bind(c)
+    myVar%chr = myVar%chrb
+  end subroutine types_test
+end module lto_type_merge_test
+
Index: testsuite/gfortran.dg/lto/bind_c-2_1.c
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-2_1.c	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-2_1.c	(working copy)
@@ -0,0 +1,36 @@
+#include <stdlib.h>
+/* interopse with myftype_1 */
+typedef struct {
+   unsigned char chr;
+   signed char chr2;
+} myctype_t;
+
+
+extern void abort(void);
+void types_test(void);
+/* declared in the fortran module */
+extern myctype_t myVar;
+
+int main(int argc, char **argv)
+{
+   myctype_t *cchr;
+   asm("":"=r"(cchr):"0"(&myVar));
+   cchr->chr = 1;
+   cchr->chr2 = 2;
+
+   types_test();
+
+   if(cchr->chr != 2)
+      abort();
+   if(cchr->chr2 != 2)
+      abort();
+   myVar.chr2 = 3;
+   types_test();
+
+   if(myVar.chr != 3)
+      abort();
+   if(myVar.chr2 != 3)
+      abort();
+   return 0;
+}
+
Index: testsuite/gfortran.dg/lto/bind_c-3_0.f90
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-3_0.f90	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-3_0.f90	(working copy)
@@ -0,0 +1,91 @@
+! { dg-lto-do run }
+! { dg-lto-options {{ -O3 -flto }} }
+! This testcase will abort if integer types are not interoperable.
+module lto_type_merge_test
+  use, intrinsic :: iso_c_binding
+  implicit none
+
+  type, bind(c) :: MYFTYPE_1
+    integer(c_int) :: val_int
+    integer(c_short) :: val_short
+    integer(c_long) :: val_long
+    integer(c_long_long) :: val_long_long
+    integer(c_size_t) :: val_size_t
+    integer(c_int8_t) :: val_int8_t
+    integer(c_int16_t) :: val_int16_t
+    integer(c_int32_t) :: val_int32_t
+    integer(c_int64_t) :: val_int64_t
+    integer(c_int_least8_t) :: val_intleast_8_t
+    integer(c_int_least16_t) :: val_intleast_16_t
+    integer(c_int_least32_t) :: val_intleast_32_t
+    integer(c_int_least64_t) :: val_intleast_64_t
+    integer(c_int_fast8_t) :: val_intfast_8_t
+    integer(c_int_fast16_t) :: val_intfast_16_t
+    integer(c_int_fast32_t) :: val_intfast_32_t
+    integer(c_int_fast64_t) :: val_intfast_64_t
+    integer(c_intmax_t) :: val_intmax_t
+    integer(c_intptr_t) :: val_intptr_t
+  end type MYFTYPE_1
+
+  type(myftype_1), bind(c, name="myVar") :: myVar
+
+contains
+  subroutine types_test1() bind(c)
+    myVar%val_int = 2
+  end subroutine types_test1
+  subroutine types_test2() bind(c)
+    myVar%val_short = 2
+  end subroutine types_test2
+  subroutine types_test3() bind(c)
+    myVar%val_long = 2
+  end subroutine types_test3
+  subroutine types_test4() bind(c)
+    myVar%val_long_long = 2
+  end subroutine types_test4
+  subroutine types_test5() bind(c)
+    myVar%val_size_t = 2
+  end subroutine types_test5
+  subroutine types_test6() bind(c)
+    myVar%val_int8_t = 2
+  end subroutine types_test6
+  subroutine types_test7() bind(c)
+    myVar%val_int16_t = 2
+  end subroutine types_test7
+  subroutine types_test8() bind(c)
+    myVar%val_int32_t = 2
+  end subroutine types_test8
+  subroutine types_test9() bind(c)
+    myVar%val_int64_t = 2
+  end subroutine types_test9
+  subroutine types_test10() bind(c)
+    myVar%val_intleast_8_t = 2
+  end subroutine types_test10
+  subroutine types_test11() bind(c)
+    myVar%val_intleast_16_t = 2
+  end subroutine types_test11
+  subroutine types_test12() bind(c)
+    myVar%val_intleast_32_t = 2
+  end subroutine types_test12
+  subroutine types_test13() bind(c)
+    myVar%val_intleast_64_t = 2
+  end subroutine types_test13
+  subroutine types_test14() bind(c)
+    myVar%val_intfast_8_t = 2
+  end subroutine types_test14
+  subroutine types_test15() bind(c)
+    myVar%val_intfast_16_t = 2
+  end subroutine types_test15
+  subroutine types_test16() bind(c)
+    myVar%val_intfast_32_t = 2
+  end subroutine types_test16
+  subroutine types_test17() bind(c)
+    myVar%val_intfast_64_t = 2
+  end subroutine types_test17
+  subroutine types_test18() bind(c)
+    myVar%val_intmax_t = 2
+  end subroutine types_test18
+  subroutine types_test19() bind(c)
+    myVar%val_intptr_t = 2
+  end subroutine types_test19
+end module lto_type_merge_test
+
Index: testsuite/gfortran.dg/lto/bind_c-3_1.c
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-3_1.c	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-3_1.c	(working copy)
@@ -0,0 +1,78 @@
+#include <stdlib.h>
+#include <stdint.h>
+/* interopse with myftype_1 */
+typedef struct {
+  int val1;
+  short int val2;
+  long int val3;
+  long long int val4;
+  size_t val5;
+  int8_t val6;
+  int16_t val7;
+  int32_t val8;
+  int64_t val9;
+  int_least8_t val10;
+  int_least16_t val11;
+  int_least32_t val12;
+  int_least64_t val13;
+  int_fast8_t val14;
+  int_fast16_t val15;
+  int_fast32_t val16;
+  int_fast64_t val17;
+  intmax_t val18;
+  intptr_t val19;
+} myctype_t;
+
+
+extern void abort(void);
+void types_test1(void);
+void types_test2(void);
+void types_test3(void);
+void types_test4(void);
+void types_test5(void);
+void types_test6(void);
+void types_test7(void);
+void types_test8(void);
+void types_test9(void);
+void types_test10(void);
+void types_test11(void);
+void types_test12(void);
+void types_test13(void);
+void types_test14(void);
+void types_test15(void);
+void types_test16(void);
+void types_test17(void);
+void types_test18(void);
+void types_test19(void);
+/* declared in the fortran module */
+extern myctype_t myVar;
+
+#define test(n)\
+  cchr->val##n = 1; types_test##n (); if (cchr->val##n != 2) abort ();
+
+int main(int argc, char **argv)
+{
+   myctype_t *cchr;
+   asm("":"=r"(cchr):"0"(&myVar));
+   test(1);
+   test(2);
+   test(3);
+   test(4);
+   test(5);
+   test(6);
+   test(7);
+   test(8);
+   test(9);
+   test(10);
+   test(11);
+   test(12);
+   test(13);
+   test(14);
+   test(15);
+   test(16);
+   test(17);
+   test(18);
+   test(19);
+   return 0;
+}
+
Index: testsuite/gfortran.dg/lto/bind_c-4_0.f90
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-4_0.f90	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-4_0.f90	(working copy)
@@ -0,0 +1,48 @@
+! { dg-lto-do run }
+! { dg-lto-options {{ -O3 -flto }} }
+! This testcase will abort if real/complex/boolean/character types are not interoperable
+module lto_type_merge_test
+  use, intrinsic :: iso_c_binding
+  implicit none
+
+  type, bind(c) :: MYFTYPE_1
+    real(c_float) :: val_1
+    real(c_double) :: val_2
+    real(c_long_double) :: val_3
+    complex(c_float_complex) :: val_4
+    complex(c_double_complex) :: val_5
+    complex(c_long_double_complex) :: val_6
+    logical(c_bool) :: val_7
+    !FIXME: Fortran define c_char as array of size 1.
+    !character(c_char) :: val_8
+  end type MYFTYPE_1
+
+  type(myftype_1), bind(c, name="myVar") :: myVar
+
+contains
+  subroutine types_test1() bind(c)
+    myVar%val_1 = 2
+  end subroutine types_test1
+  subroutine types_test2() bind(c)
+    myVar%val_2 = 2
+  end subroutine types_test2
+  subroutine types_test3() bind(c)
+    myVar%val_3 = 2
+  end subroutine types_test3
+  subroutine types_test4() bind(c)
+    myVar%val_4 = 2
+  end subroutine types_test4
+  subroutine types_test5() bind(c)
+    myVar%val_5 = 2
+  end subroutine types_test5
+  subroutine types_test6() bind(c)
+    myVar%val_6 = 2
+  end subroutine types_test6
+  subroutine types_test7() bind(c)
+    myVar%val_7 = myVar%val_7 .or. .not. myVar%val_7
+  end subroutine types_test7
+  !subroutine types_test8() bind(c)
+    !myVar%val_8 = "a"
+  !end subroutine types_test8
+end module lto_type_merge_test
+
Index: testsuite/gfortran.dg/lto/bind_c-4_1.c
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-4_1.c	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-4_1.c	(working copy)
@@ -0,0 +1,46 @@
+#include <stdlib.h>
+#include <stdint.h>
+/* interopse with myftype_1 */
+typedef struct {
+  float val1;
+  double val2;
+  long double val3;
+  float _Complex val4;
+  double _Complex val5;
+  long double _Complex val6;
+  _Bool val7;
+  /* FIXME: Fortran define c_char as array of size 1.
+     char val8;  */
+} myctype_t;
+
+
+extern void abort(void);
+void types_test1(void);
+void types_test2(void);
+void types_test3(void);
+void types_test4(void);
+void types_test5(void);
+void types_test6(void);
+void types_test7(void);
+void types_test8(void);
+/* declared in the fortran module */
+extern myctype_t myVar;
+
+#define test(n)\
+  cchr->val##n = 1; types_test##n (); if (cchr->val##n != 2) abort ();
+
+int main(int argc, char **argv)
+{
+   myctype_t *cchr;
+   asm("":"=r"(cchr):"0"(&myVar));
+   test(1);
+   test(2);
+   test(3);
+   test(4);
+   test(5);
+   test(6);
+   cchr->val7 = 0; types_test7 (); if (cchr->val7 != 1) abort ();
+   /*cchr->val8 = 0; types_test8 (); if (cchr->val8 != 'a') abort ();*/
+   return 0;
+}
+
Index: gimple-expr.c
===================================================================
--- gimple-expr.c	(revision 224250)
+++ gimple-expr.c	(working copy)
@@ -89,18 +89,6 @@
 	return false;
     }
 
-  /* From now on qualifiers on value types do not matter.  */
-  inner_type = TYPE_MAIN_VARIANT (inner_type);
-  outer_type = TYPE_MAIN_VARIANT (outer_type);
-
-  if (inner_type == outer_type)
-    return true;
-
-  /* If we know the canonical types, compare them.  */
-  if (TYPE_CANONICAL (inner_type)
-      && TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type))
-    return true;
-
   /* Changes in machine mode are never useless conversions unless we
      deal with aggregate types in which case we defer to later checks.  */
   if (TYPE_MODE (inner_type) != TYPE_MODE (outer_type)
@@ -131,6 +119,18 @@
       return true;
     }
 
+  /* From now on qualifiers on value types do not matter.  */
+  inner_type = TYPE_MAIN_VARIANT (inner_type);
+  outer_type = TYPE_MAIN_VARIANT (outer_type);
+
+  if (inner_type == outer_type)
+    return true;
+
+  /* If we know the canonical types, compare them.  */
+  if (TYPE_CANONICAL (inner_type)
+      && TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type))
+    return true;
+
   /* Scalar floating point types with the same mode are compatible.  */
   else if (SCALAR_FLOAT_TYPE_P (inner_type)
 	   && SCALAR_FLOAT_TYPE_P (outer_type))

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fortran's C_CHAR type
  2015-06-08 15:32                   ` Fortran's C_CHAR type Jan Hubicka
@ 2015-06-10 11:50                     ` Mikael Morin
  2015-06-10 14:55                       ` Jan Hubicka
  0 siblings, 1 reply; 35+ messages in thread
From: Mikael Morin @ 2015-06-10 11:50 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Richard Biener, Joseph Myers, gcc-patches, burnus

Le 08/06/2015 17:31, Jan Hubicka a écrit :
> Hi,
> to furhter add to the topics to discuss, I noticed that Fortran FE seems to be quite
> ambivalent about C_CHAR type:
> [jh@gcc2-power8 gcc]$ cat ../b.f90
> ! This testcase will abort if C_CHAR types are not interoperable
> module lto_type_merge_test
>   use, intrinsic :: iso_c_binding
>   implicit none
> 
> contains
>   function types_test1(V) bind(c)
>     USE, INTRINSIC :: ISO_C_BINDING
>     CHARACTER(C_CHAR) :: types_test1
>     CHARACTER(C_CHAR), VALUE :: V
>     types_test1 = V
>   end function types_test1
> end module lto_type_merge_test
> 
> [jh@gcc2-power8 gcc]$ cat ../a.c
> extern unsigned char types_test1 (char v);
> void
> main ()
> { 
>   if (types_test1 ('a') != 'a')
>     __builtin_abort ();
>   return 0;
> }
> 
> As my fortran-fu goes, i think this testcase is correct. Fortran FE however
> builds types_test1 as a function return char but taking the array of size of 1
> as a parameter.
C_CHAR is a named constant of value 1 (the number of bytes of a char),
and character(foo) declares a string of length foo and default kind
(which is 1 for character types).
So it is expected that the argument is an array.
If you want to declare a single character, you have to use an integer of
kind 1.
types_test1's result and v should have type integer(c_char), I think.

Mikael

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fortran's C_CHAR type
  2015-06-10 11:50                     ` Mikael Morin
@ 2015-06-10 14:55                       ` Jan Hubicka
  2015-06-10 16:37                         ` Mikael Morin
  0 siblings, 1 reply; 35+ messages in thread
From: Jan Hubicka @ 2015-06-10 14:55 UTC (permalink / raw)
  To: Mikael Morin
  Cc: Jan Hubicka, Richard Biener, Joseph Myers, gcc-patches, burnus

> > [jh@gcc2-power8 gcc]$ cat ../b.f90
> > ! This testcase will abort if C_CHAR types are not interoperable
> > module lto_type_merge_test
> >   use, intrinsic :: iso_c_binding
> >   implicit none
> > 
> > contains
> >   function types_test1(V) bind(c)
> >     USE, INTRINSIC :: ISO_C_BINDING
> >     CHARACTER(C_CHAR) :: types_test1
> >     CHARACTER(C_CHAR), VALUE :: V
> >     types_test1 = V
> >   end function types_test1
> > end module lto_type_merge_test
> > 
> > [jh@gcc2-power8 gcc]$ cat ../a.c
> > extern unsigned char types_test1 (char v);
> > void
> > main ()
> > { 
> >   if (types_test1 ('a') != 'a')
> >     __builtin_abort ();
> >   return 0;
> > }
> > 
> > As my fortran-fu goes, i think this testcase is correct. Fortran FE however
> > builds types_test1 as a function return char but taking the array of size of 1
> > as a parameter.
> C_CHAR is a named constant of value 1 (the number of bytes of a char),
> and character(foo) declares a string of length foo and default kind
> (which is 1 for character types).
> So it is expected that the argument is an array.

I see, what is the reason for assymetry for return value to not be array in this case?

> If you want to declare a single character, you have to use an integer of
> kind 1.
> types_test1's result and v should have type integer(c_char), I think.

I will fix the testcase accordingly.  I basicallly copied what is in table
15.2 of the Fortran 2008 draft that explicitely lists Fortran type CHARACTER
if kind C_CHAR compatible with "char". On the other hand there are no examples
in the standard that would suggest that this should work this way.
It only shows stuff like
 CHARACTER(KIND=C_CHAR), DIMENSION(*) :: IN, OUT
which corresponds to char []

Is my testcase supposed to work if I simply add KIND= before "C_CHAR"

If you can look at the other c-bind testcases I produced, I would really appreachiate that.
Honza
> 
> Mikael

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fortran's C_CHAR type
  2015-06-10 14:55                       ` Jan Hubicka
@ 2015-06-10 16:37                         ` Mikael Morin
  2015-06-11 18:19                           ` Jan Hubicka
  0 siblings, 1 reply; 35+ messages in thread
From: Mikael Morin @ 2015-06-10 16:37 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Richard Biener, Joseph Myers, gcc-patches, burnus

Le 10/06/2015 16:38, Jan Hubicka a écrit :
>>> [jh@gcc2-power8 gcc]$ cat ../b.f90
>>> ! This testcase will abort if C_CHAR types are not interoperable
>>> module lto_type_merge_test
>>>   use, intrinsic :: iso_c_binding
>>>   implicit none
>>>
>>> contains
>>>   function types_test1(V) bind(c)
>>>     USE, INTRINSIC :: ISO_C_BINDING
>>>     CHARACTER(C_CHAR) :: types_test1
>>>     CHARACTER(C_CHAR), VALUE :: V
>>>     types_test1 = V
>>>   end function types_test1
>>> end module lto_type_merge_test
>>>
>>> [jh@gcc2-power8 gcc]$ cat ../a.c
>>> extern unsigned char types_test1 (char v);
>>> void
>>> main ()
>>> { 
>>>   if (types_test1 ('a') != 'a')
>>>     __builtin_abort ();
>>>   return 0;
>>> }
>>>
>>> As my fortran-fu goes, i think this testcase is correct. Fortran FE however
>>> builds types_test1 as a function return char but taking the array of size of 1
>>> as a parameter.
>> C_CHAR is a named constant of value 1 (the number of bytes of a char),
>> and character(foo) declares a string of length foo and default kind
>> (which is 1 for character types).
>> So it is expected that the argument is an array.
> 
> I see, what is the reason for assymetry for return value to not be array in this case?

There is this in gfc_sym_type:

  if (sym->ts.type == BT_CHARACTER
      && ((sym->attr.function && sym->attr.is_bind_c)
	  || (sym->attr.result
	      && sym->ns->proc_name
	      && sym->ns->proc_name->attr.is_bind_c)
	  || (sym->ts.deferred && (!sym->ts.u.cl
				   || !sym->ts.u.cl->backend_decl))))
    type = gfc_character1_type_node;
  else
    type = gfc_typenode_for_spec (&sym->ts);


And gfc_character1_type_node is defined as a plain char, it seems.
I don't know about the reason for either.

> 
>> If you want to declare a single character, you have to use an integer of
>> kind 1.
>> types_test1's result and v should have type integer(c_char), I think.
> 
> I will fix the testcase accordingly.  I basicallly copied what is in table
> 15.2 of the Fortran 2008 draft that explicitely lists Fortran type CHARACTER
> if kind C_CHAR compatible with "char". On the other hand there are no examples
> in the standard that would suggest that this should work this way.
> It only shows stuff like
>  CHARACTER(KIND=C_CHAR), DIMENSION(*) :: IN, OUT
> which corresponds to char []
> 
> Is my testcase supposed to work if I simply add KIND= before "C_CHAR"
> 
I have had a look at the table and the text around, and first I should
correct myself.
C_CHAR is 1, C_SIGNED_CHAR is 1, and the default values for len= and
kind= are 1 as well.
So, even if CHARACTER(KIND=C_CHAR) is what should be used as it's not
dependent on the implementation's default kind choice, it boils down to
the same as CHARACTER(C_CHAR), namely CHARACTER(len=1, kind=1) actually.


And about the line saying CHARACTER(KIND=C_CHAR) interoperable with char
in table 15.2:
You're right, while I would myself prefer to use an
INTEGER(KIND=C_SIGNED_CHAR) type, CHARACTER(KIND=C_CHAR) should be
supported as well.
That means that char should be compatible with char[1], I think.
You said there is no guarantee they are passed the same way?


> If you can look at the other c-bind testcases I produced, I would really appreachiate that.
I have looked at:
https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00693.html
https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00713.html
I saw nothing wrong with the tests.
Avoiding character interoperability avoids most of the pain. ;-)

Mikael

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-09 17:24                     ` Jan Hubicka
@ 2015-06-11 17:58                       ` Jan Hubicka
  2015-06-22  7:25                       ` Jan Hubicka
  1 sibling, 0 replies; 35+ messages in thread
From: Jan Hubicka @ 2015-06-11 17:58 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Richard Biener, Joseph Myers, gcc-patches, burnus

> > On Mon, 8 Jun 2015, Jan Hubicka wrote:
> > 
> > > > 
> > > > I think we should instead work towards eliminating the get_alias_set
> > > > langhook first.  The LTO langhook variant contains the same handling, btw,
> > > > so just inline that into get_alias_set and see what remains?
> > > 
> > > I see, i completely missed existence of gimple_get_alias_set. It makes more
> > > sense now.
> > > 
> > > Is moving everyting to alias.c realy a desirable thing? If non-C languages do
> > > not have this rule, why we want to reduce the code quality when compiling
> > > those?
> > 
> > Well, for consistency and for getting rid of one langhook ;)
> :)
> In a way this particular langhook makes sense to me - TBAA rules are language specific.
> We also may with explicit streaming of the TBAA dag, like LLVM does.
> 
> Anyway, this is the updated patch fixing the Fortran's interoperability with
> size_t and signed char.  I will send separate patch for the extra lto-symtab
> warnings shortly.
> 
> I will be happy looking into the TYPE_CANONICAL (int) to be different from
> TYPE_CANONICAL (unsigned int) if that seems desirable. There are two things that
> needs to be solved - hash_canonical_type/gimple_canonical_types_compatible_p can't
> use TYPE_CNAONICAL of subtypes in all cases (that is easy) and we will need some
> way to recognize the conflict in lto-symtab other thanjust comparing TYPE_CANONICAL
> to not warn when a variable is declared signed in Fortran unit and unsigned in C.
> 
> Bootstrapped/regtested ppc64le-linux.
> 
> 	* lto/lto.c (hash_canonical_type): Do not hash TYPE_UNSIGNED
> 	of INTEGER_TYPE.
> 	* tree.c (gimple_canonical_types_compatible_p): Do not compare TYPE_UNSIGNED
> 	of INTEGER_TYPE.
> 	* gimple-expr.c (useless_type_conversion_p): Move INTEGER type handling
> 	ahead the canonical type lookup.
> 
> 	* gfortran.dg/lto/bind_c-2_0.f90: New testcase
> 	* gfortran.dg/lto/bind_c-2_1.c: New testcase
> 	* gfortran.dg/lto/bind_c-3_0.f90: New testcase
> 	* gfortran.dg/lto/bind_c-3_1.c: New testcase
> 	* gfortran.dg/lto/bind_c-4_0.f90: New testcase
> 	* gfortran.dg/lto/bind_c-4_1.c: New testcase

Hello,
I would like to ping this.  I am almost done with reviewing the Fortran's interoperability
issues.  I think the only two remaining problems is the CHARACTER(C_CHAR) and the fact
that Fortran explicitly sates that arrays are interoperable regardless their bounds
(just sizes):

NOTE 15.17
  For example, a Fortran array declared as
    INTEGER(C_INT) :: A(18, 3:7, *)
  is interoperable with a C array declared as
    int b[][5][18];

Honza

> Index: lto/lto.c
> ===================================================================
> --- lto/lto.c	(revision 224252)
> +++ lto/lto.c	(working copy)
> @@ -298,6 +298,7 @@
>  hash_canonical_type (tree type)
>  {
>    inchash::hash hstate;
> +  enum tree_code code;
>  
>    /* We compute alias sets only for types that needs them.
>       Be sure we do not recurse to something else as we can not hash incomplete
> @@ -309,7 +310,8 @@
>       smaller sets; when searching for existing matching types to merge,
>       only existing types having the same features as the new type will be
>       checked.  */
> -  hstate.add_int (tree_code_for_canonical_type_merging (TREE_CODE (type)));
> +  code = tree_code_for_canonical_type_merging (TREE_CODE (type));
> +  hstate.add_int (code);
>    hstate.add_int (TYPE_MODE (type));
>  
>    /* Incorporate common features of numerical types.  */
> @@ -319,7 +321,14 @@
>        || TREE_CODE (type) == OFFSET_TYPE
>        || POINTER_TYPE_P (type))
>      {
> -      hstate.add_int (TYPE_UNSIGNED (type));
> +      /* Some Fortran integer types are interoperable with C types regardless
> +	 their signedness.  We need to ignore sign on these to make it
> +	 possible for structure containing unsigned type to interoperate
> +	 with structure containing signed type which is also required by
> +	 the standard.  It is thus not enough to keep alias set of signed
> +	 type same with alias set of unsigned type.  */
> +      if (code != INTEGER_TYPE)
> +        hstate.add_int (TYPE_UNSIGNED (type));
>        hstate.add_int (TYPE_PRECISION (type));
>      }
>  
> Index: tree.c
> ===================================================================
> --- tree.c	(revision 224252)
> +++ tree.c	(working copy)
> @@ -12879,6 +12879,7 @@
>  gimple_canonical_types_compatible_p (const_tree t1, const_tree t2,
>  				     bool trust_type_canonical)
>  {
> +  enum tree_code code;
>    /* Type variants should be same as the main variant.  When not doing sanity
>       checking to verify this fact, go to main variants and save some work.  */
>    if (trust_type_canonical)
> @@ -12918,9 +12919,9 @@
>        && trust_type_canonical)
>      return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
>  
> +  code = tree_code_for_canonical_type_merging (TREE_CODE (t1));
>    /* Can't be the same type if the types don't have the same code.  */
> -  if (tree_code_for_canonical_type_merging (TREE_CODE (t1))
> -      != tree_code_for_canonical_type_merging (TREE_CODE (t2)))
> +  if (code != tree_code_for_canonical_type_merging (TREE_CODE (t2)))
>      return false;
>  
>    /* Qualifiers do not matter for canonical type comparison purposes.  */
> @@ -12945,7 +12946,14 @@
>      {
>        /* Can't be the same type if they have different sign or precision.  */
>        if (TYPE_PRECISION (t1) != TYPE_PRECISION (t2)
> -	  || TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2))
> +	  /* Some Fortran integer types are interoperable with C types
> +	     regardless their signedness.  We need to ignore sign on these to
> +	     make it possible for structure containing unsigned type to
> +	     interoperate with structure containing signed type which is also
> +	     required by the standard.  It is thus not enough to keep alias set
> +	     of signed type same with alias set of unsigned type.  */
> +	  || (code != INTEGER_TYPE
> +	      && TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2)))
>  	return false;
>  
>        /* Fortran's C_SIGNED_CHAR is !TYPE_STRING_FLAG but needs to be
> Index: testsuite/gfortran.dg/lto/bind_c-2_0.f90
> ===================================================================
> --- testsuite/gfortran.dg/lto/bind_c-2_0.f90	(revision 0)
> +++ testsuite/gfortran.dg/lto/bind_c-2_0.f90	(working copy)
> @@ -0,0 +1,21 @@
> +! { dg-lto-do run }
> +! { dg-lto-options {{ -O3 -flto }} }
> +! This testcase will abort if C_PTR is not interoperable with both int *
> +! and float *
> +module lto_type_merge_test
> +  use, intrinsic :: iso_c_binding
> +  implicit none
> +
> +  type, bind(c) :: MYFTYPE_1
> +     integer(c_signed_char) :: chr
> +     integer(c_signed_char) :: chrb
> +  end type MYFTYPE_1
> +
> +  type(myftype_1), bind(c, name="myVar") :: myVar
> +
> +contains
> +  subroutine types_test() bind(c)
> +    myVar%chr = myVar%chrb
> +  end subroutine types_test
> +end module lto_type_merge_test
> +
> Index: testsuite/gfortran.dg/lto/bind_c-2_1.c
> ===================================================================
> --- testsuite/gfortran.dg/lto/bind_c-2_1.c	(revision 0)
> +++ testsuite/gfortran.dg/lto/bind_c-2_1.c	(working copy)
> @@ -0,0 +1,36 @@
> +#include <stdlib.h>
> +/* interopse with myftype_1 */
> +typedef struct {
> +   unsigned char chr;
> +   signed char chr2;
> +} myctype_t;
> +
> +
> +extern void abort(void);
> +void types_test(void);
> +/* declared in the fortran module */
> +extern myctype_t myVar;
> +
> +int main(int argc, char **argv)
> +{
> +   myctype_t *cchr;
> +   asm("":"=r"(cchr):"0"(&myVar));
> +   cchr->chr = 1;
> +   cchr->chr2 = 2;
> +
> +   types_test();
> +
> +   if(cchr->chr != 2)
> +      abort();
> +   if(cchr->chr2 != 2)
> +      abort();
> +   myVar.chr2 = 3;
> +   types_test();
> +
> +   if(myVar.chr != 3)
> +      abort();
> +   if(myVar.chr2 != 3)
> +      abort();
> +   return 0;
> +}
> +
> Index: testsuite/gfortran.dg/lto/bind_c-3_0.f90
> ===================================================================
> --- testsuite/gfortran.dg/lto/bind_c-3_0.f90	(revision 0)
> +++ testsuite/gfortran.dg/lto/bind_c-3_0.f90	(working copy)
> @@ -0,0 +1,91 @@
> +! { dg-lto-do run }
> +! { dg-lto-options {{ -O3 -flto }} }
> +! This testcase will abort if integer types are not interoperable.
> +module lto_type_merge_test
> +  use, intrinsic :: iso_c_binding
> +  implicit none
> +
> +  type, bind(c) :: MYFTYPE_1
> +    integer(c_int) :: val_int
> +    integer(c_short) :: val_short
> +    integer(c_long) :: val_long
> +    integer(c_long_long) :: val_long_long
> +    integer(c_size_t) :: val_size_t
> +    integer(c_int8_t) :: val_int8_t
> +    integer(c_int16_t) :: val_int16_t
> +    integer(c_int32_t) :: val_int32_t
> +    integer(c_int64_t) :: val_int64_t
> +    integer(c_int_least8_t) :: val_intleast_8_t
> +    integer(c_int_least16_t) :: val_intleast_16_t
> +    integer(c_int_least32_t) :: val_intleast_32_t
> +    integer(c_int_least64_t) :: val_intleast_64_t
> +    integer(c_int_fast8_t) :: val_intfast_8_t
> +    integer(c_int_fast16_t) :: val_intfast_16_t
> +    integer(c_int_fast32_t) :: val_intfast_32_t
> +    integer(c_int_fast64_t) :: val_intfast_64_t
> +    integer(c_intmax_t) :: val_intmax_t
> +    integer(c_intptr_t) :: val_intptr_t
> +  end type MYFTYPE_1
> +
> +  type(myftype_1), bind(c, name="myVar") :: myVar
> +
> +contains
> +  subroutine types_test1() bind(c)
> +    myVar%val_int = 2
> +  end subroutine types_test1
> +  subroutine types_test2() bind(c)
> +    myVar%val_short = 2
> +  end subroutine types_test2
> +  subroutine types_test3() bind(c)
> +    myVar%val_long = 2
> +  end subroutine types_test3
> +  subroutine types_test4() bind(c)
> +    myVar%val_long_long = 2
> +  end subroutine types_test4
> +  subroutine types_test5() bind(c)
> +    myVar%val_size_t = 2
> +  end subroutine types_test5
> +  subroutine types_test6() bind(c)
> +    myVar%val_int8_t = 2
> +  end subroutine types_test6
> +  subroutine types_test7() bind(c)
> +    myVar%val_int16_t = 2
> +  end subroutine types_test7
> +  subroutine types_test8() bind(c)
> +    myVar%val_int32_t = 2
> +  end subroutine types_test8
> +  subroutine types_test9() bind(c)
> +    myVar%val_int64_t = 2
> +  end subroutine types_test9
> +  subroutine types_test10() bind(c)
> +    myVar%val_intleast_8_t = 2
> +  end subroutine types_test10
> +  subroutine types_test11() bind(c)
> +    myVar%val_intleast_16_t = 2
> +  end subroutine types_test11
> +  subroutine types_test12() bind(c)
> +    myVar%val_intleast_32_t = 2
> +  end subroutine types_test12
> +  subroutine types_test13() bind(c)
> +    myVar%val_intleast_64_t = 2
> +  end subroutine types_test13
> +  subroutine types_test14() bind(c)
> +    myVar%val_intfast_8_t = 2
> +  end subroutine types_test14
> +  subroutine types_test15() bind(c)
> +    myVar%val_intfast_16_t = 2
> +  end subroutine types_test15
> +  subroutine types_test16() bind(c)
> +    myVar%val_intfast_32_t = 2
> +  end subroutine types_test16
> +  subroutine types_test17() bind(c)
> +    myVar%val_intfast_64_t = 2
> +  end subroutine types_test17
> +  subroutine types_test18() bind(c)
> +    myVar%val_intmax_t = 2
> +  end subroutine types_test18
> +  subroutine types_test19() bind(c)
> +    myVar%val_intptr_t = 2
> +  end subroutine types_test19
> +end module lto_type_merge_test
> +
> Index: testsuite/gfortran.dg/lto/bind_c-3_1.c
> ===================================================================
> --- testsuite/gfortran.dg/lto/bind_c-3_1.c	(revision 0)
> +++ testsuite/gfortran.dg/lto/bind_c-3_1.c	(working copy)
> @@ -0,0 +1,78 @@
> +#include <stdlib.h>
> +#include <stdint.h>
> +/* interopse with myftype_1 */
> +typedef struct {
> +  int val1;
> +  short int val2;
> +  long int val3;
> +  long long int val4;
> +  size_t val5;
> +  int8_t val6;
> +  int16_t val7;
> +  int32_t val8;
> +  int64_t val9;
> +  int_least8_t val10;
> +  int_least16_t val11;
> +  int_least32_t val12;
> +  int_least64_t val13;
> +  int_fast8_t val14;
> +  int_fast16_t val15;
> +  int_fast32_t val16;
> +  int_fast64_t val17;
> +  intmax_t val18;
> +  intptr_t val19;
> +} myctype_t;
> +
> +
> +extern void abort(void);
> +void types_test1(void);
> +void types_test2(void);
> +void types_test3(void);
> +void types_test4(void);
> +void types_test5(void);
> +void types_test6(void);
> +void types_test7(void);
> +void types_test8(void);
> +void types_test9(void);
> +void types_test10(void);
> +void types_test11(void);
> +void types_test12(void);
> +void types_test13(void);
> +void types_test14(void);
> +void types_test15(void);
> +void types_test16(void);
> +void types_test17(void);
> +void types_test18(void);
> +void types_test19(void);
> +/* declared in the fortran module */
> +extern myctype_t myVar;
> +
> +#define test(n)\
> +  cchr->val##n = 1; types_test##n (); if (cchr->val##n != 2) abort ();
> +
> +int main(int argc, char **argv)
> +{
> +   myctype_t *cchr;
> +   asm("":"=r"(cchr):"0"(&myVar));
> +   test(1);
> +   test(2);
> +   test(3);
> +   test(4);
> +   test(5);
> +   test(6);
> +   test(7);
> +   test(8);
> +   test(9);
> +   test(10);
> +   test(11);
> +   test(12);
> +   test(13);
> +   test(14);
> +   test(15);
> +   test(16);
> +   test(17);
> +   test(18);
> +   test(19);
> +   return 0;
> +}
> +
> Index: testsuite/gfortran.dg/lto/bind_c-4_0.f90
> ===================================================================
> --- testsuite/gfortran.dg/lto/bind_c-4_0.f90	(revision 0)
> +++ testsuite/gfortran.dg/lto/bind_c-4_0.f90	(working copy)
> @@ -0,0 +1,48 @@
> +! { dg-lto-do run }
> +! { dg-lto-options {{ -O3 -flto }} }
> +! This testcase will abort if real/complex/boolean/character types are not interoperable
> +module lto_type_merge_test
> +  use, intrinsic :: iso_c_binding
> +  implicit none
> +
> +  type, bind(c) :: MYFTYPE_1
> +    real(c_float) :: val_1
> +    real(c_double) :: val_2
> +    real(c_long_double) :: val_3
> +    complex(c_float_complex) :: val_4
> +    complex(c_double_complex) :: val_5
> +    complex(c_long_double_complex) :: val_6
> +    logical(c_bool) :: val_7
> +    !FIXME: Fortran define c_char as array of size 1.
> +    !character(c_char) :: val_8
> +  end type MYFTYPE_1
> +
> +  type(myftype_1), bind(c, name="myVar") :: myVar
> +
> +contains
> +  subroutine types_test1() bind(c)
> +    myVar%val_1 = 2
> +  end subroutine types_test1
> +  subroutine types_test2() bind(c)
> +    myVar%val_2 = 2
> +  end subroutine types_test2
> +  subroutine types_test3() bind(c)
> +    myVar%val_3 = 2
> +  end subroutine types_test3
> +  subroutine types_test4() bind(c)
> +    myVar%val_4 = 2
> +  end subroutine types_test4
> +  subroutine types_test5() bind(c)
> +    myVar%val_5 = 2
> +  end subroutine types_test5
> +  subroutine types_test6() bind(c)
> +    myVar%val_6 = 2
> +  end subroutine types_test6
> +  subroutine types_test7() bind(c)
> +    myVar%val_7 = myVar%val_7 .or. .not. myVar%val_7
> +  end subroutine types_test7
> +  !subroutine types_test8() bind(c)
> +    !myVar%val_8 = "a"
> +  !end subroutine types_test8
> +end module lto_type_merge_test
> +
> Index: testsuite/gfortran.dg/lto/bind_c-4_1.c
> ===================================================================
> --- testsuite/gfortran.dg/lto/bind_c-4_1.c	(revision 0)
> +++ testsuite/gfortran.dg/lto/bind_c-4_1.c	(working copy)
> @@ -0,0 +1,46 @@
> +#include <stdlib.h>
> +#include <stdint.h>
> +/* interopse with myftype_1 */
> +typedef struct {
> +  float val1;
> +  double val2;
> +  long double val3;
> +  float _Complex val4;
> +  double _Complex val5;
> +  long double _Complex val6;
> +  _Bool val7;
> +  /* FIXME: Fortran define c_char as array of size 1.
> +     char val8;  */
> +} myctype_t;
> +
> +
> +extern void abort(void);
> +void types_test1(void);
> +void types_test2(void);
> +void types_test3(void);
> +void types_test4(void);
> +void types_test5(void);
> +void types_test6(void);
> +void types_test7(void);
> +void types_test8(void);
> +/* declared in the fortran module */
> +extern myctype_t myVar;
> +
> +#define test(n)\
> +  cchr->val##n = 1; types_test##n (); if (cchr->val##n != 2) abort ();
> +
> +int main(int argc, char **argv)
> +{
> +   myctype_t *cchr;
> +   asm("":"=r"(cchr):"0"(&myVar));
> +   test(1);
> +   test(2);
> +   test(3);
> +   test(4);
> +   test(5);
> +   test(6);
> +   cchr->val7 = 0; types_test7 (); if (cchr->val7 != 1) abort ();
> +   /*cchr->val8 = 0; types_test8 (); if (cchr->val8 != 'a') abort ();*/
> +   return 0;
> +}
> +
> Index: gimple-expr.c
> ===================================================================
> --- gimple-expr.c	(revision 224250)
> +++ gimple-expr.c	(working copy)
> @@ -89,18 +89,6 @@
>  	return false;
>      }
>  
> -  /* From now on qualifiers on value types do not matter.  */
> -  inner_type = TYPE_MAIN_VARIANT (inner_type);
> -  outer_type = TYPE_MAIN_VARIANT (outer_type);
> -
> -  if (inner_type == outer_type)
> -    return true;
> -
> -  /* If we know the canonical types, compare them.  */
> -  if (TYPE_CANONICAL (inner_type)
> -      && TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type))
> -    return true;
> -
>    /* Changes in machine mode are never useless conversions unless we
>       deal with aggregate types in which case we defer to later checks.  */
>    if (TYPE_MODE (inner_type) != TYPE_MODE (outer_type)
> @@ -131,6 +119,18 @@
>        return true;
>      }
>  
> +  /* From now on qualifiers on value types do not matter.  */
> +  inner_type = TYPE_MAIN_VARIANT (inner_type);
> +  outer_type = TYPE_MAIN_VARIANT (outer_type);
> +
> +  if (inner_type == outer_type)
> +    return true;
> +
> +  /* If we know the canonical types, compare them.  */
> +  if (TYPE_CANONICAL (inner_type)
> +      && TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type))
> +    return true;
> +
>    /* Scalar floating point types with the same mode are compatible.  */
>    else if (SCALAR_FLOAT_TYPE_P (inner_type)
>  	   && SCALAR_FLOAT_TYPE_P (outer_type))

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fortran's C_CHAR type
  2015-06-10 16:37                         ` Mikael Morin
@ 2015-06-11 18:19                           ` Jan Hubicka
  0 siblings, 0 replies; 35+ messages in thread
From: Jan Hubicka @ 2015-06-11 18:19 UTC (permalink / raw)
  To: Mikael Morin
  Cc: Jan Hubicka, Richard Biener, Joseph Myers, gcc-patches, burnus

> I have had a look at the table and the text around, and first I should
> correct myself.
> C_CHAR is 1, C_SIGNED_CHAR is 1, and the default values for len= and
> kind= are 1 as well.
> So, even if CHARACTER(KIND=C_CHAR) is what should be used as it's not
> dependent on the implementation's default kind choice, it boils down to
> the same as CHARACTER(C_CHAR), namely CHARACTER(len=1, kind=1) actually.

Thanks for explanation - as I said I hardly wrote any Fortran code except
for these few testcases :))
> 
> 
> And about the line saying CHARACTER(KIND=C_CHAR) interoperable with char
> in table 15.2:
> You're right, while I would myself prefer to use an
> INTEGER(KIND=C_SIGNED_CHAR) type, CHARACTER(KIND=C_CHAR) should be
> supported as well.
> That means that char should be compatible with char[1], I think.
> You said there is no guarantee they are passed the same way?

With LTO we definitely don't consider the types compatible, so we produce bogus
warning.  Things may work on TBAA side because it basically ignores arrays, but
I am not 100% sure - will double check.

For passing conventions, it is definitely not a requirement of C ABI to pass arrays
of size 1 and scalars same way. I think there are ABIs passing scalars in registers
and everything else in memory (PPC SYSV ABI?).

If we consider my testcase defined, I would suggest simply adding it to testsuite
and lets see if something breaks.
> 
> 
> > If you can look at the other c-bind testcases I produced, I would really appreachiate that.
> I have looked at:
> https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00693.html
> https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00713.html
> I saw nothing wrong with the tests.
> Avoiding character interoperability avoids most of the pain. ;-)

Hehe, quite on the contrary, I would say that both Richard and me had quite some pain from
the rest of interoperability rules, too ;))

Honza
> 
> Mikael

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-09 17:24                     ` Jan Hubicka
  2015-06-11 17:58                       ` Jan Hubicka
@ 2015-06-22  7:25                       ` Jan Hubicka
  2015-06-22 15:09                         ` Richard Biener
  1 sibling, 1 reply; 35+ messages in thread
From: Jan Hubicka @ 2015-06-22  7:25 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Richard Biener, Joseph Myers, gcc-patches, burnus

> > On Mon, 8 Jun 2015, Jan Hubicka wrote:
> > 
> > > > 
> > > > I think we should instead work towards eliminating the get_alias_set
> > > > langhook first.  The LTO langhook variant contains the same handling, btw,
> > > > so just inline that into get_alias_set and see what remains?
> > > 
> > > I see, i completely missed existence of gimple_get_alias_set. It makes more
> > > sense now.
> > > 
> > > Is moving everyting to alias.c realy a desirable thing? If non-C languages do
> > > not have this rule, why we want to reduce the code quality when compiling
> > > those?
> > 
> > Well, for consistency and for getting rid of one langhook ;)
> :)
> In a way this particular langhook makes sense to me - TBAA rules are language specific.
> We also may with explicit streaming of the TBAA dag, like LLVM does.
> 
> Anyway, this is the updated patch fixing the Fortran's interoperability with
> size_t and signed char.  I will send separate patch for the extra lto-symtab
> warnings shortly.
> 
> I will be happy looking into the TYPE_CANONICAL (int) to be different from
> TYPE_CANONICAL (unsigned int) if that seems desirable. There are two things that
> needs to be solved - hash_canonical_type/gimple_canonical_types_compatible_p can't
> use TYPE_CNAONICAL of subtypes in all cases (that is easy) and we will need some
> way to recognize the conflict in lto-symtab other thanjust comparing TYPE_CANONICAL
> to not warn when a variable is declared signed in Fortran unit and unsigned in C.
> 
> Bootstrapped/regtested ppc64le-linux.
> 
> 	* lto/lto.c (hash_canonical_type): Do not hash TYPE_UNSIGNED
> 	of INTEGER_TYPE.
> 	* tree.c (gimple_canonical_types_compatible_p): Do not compare TYPE_UNSIGNED
> 	of INTEGER_TYPE.
> 	* gimple-expr.c (useless_type_conversion_p): Move INTEGER type handling
> 	ahead the canonical type lookup.
> 
> 	* gfortran.dg/lto/bind_c-2_0.f90: New testcase
> 	* gfortran.dg/lto/bind_c-2_1.c: New testcase
> 	* gfortran.dg/lto/bind_c-3_0.f90: New testcase
> 	* gfortran.dg/lto/bind_c-3_1.c: New testcase
> 	* gfortran.dg/lto/bind_c-4_0.f90: New testcase
> 	* gfortran.dg/lto/bind_c-4_1.c: New testcase

Hi,
I would like to ping this.  There are still few things to fix to make our
merging compliant at least for C/C++/Fortran rules (the array bounds for
Fortran and union ordering for C I believe) and I would like to progress
on this.

Honza

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-22  7:25                       ` Jan Hubicka
@ 2015-06-22 15:09                         ` Richard Biener
  2015-06-22 16:17                           ` Jan Hubicka
  0 siblings, 1 reply; 35+ messages in thread
From: Richard Biener @ 2015-06-22 15:09 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Joseph Myers, gcc-patches, burnus

On Mon, 22 Jun 2015, Jan Hubicka wrote:

> > > On Mon, 8 Jun 2015, Jan Hubicka wrote:
> > > 
> > > > > 
> > > > > I think we should instead work towards eliminating the get_alias_set
> > > > > langhook first.  The LTO langhook variant contains the same handling, btw,
> > > > > so just inline that into get_alias_set and see what remains?
> > > > 
> > > > I see, i completely missed existence of gimple_get_alias_set. It makes more
> > > > sense now.
> > > > 
> > > > Is moving everyting to alias.c realy a desirable thing? If non-C languages do
> > > > not have this rule, why we want to reduce the code quality when compiling
> > > > those?
> > > 
> > > Well, for consistency and for getting rid of one langhook ;)
> > :)
> > In a way this particular langhook makes sense to me - TBAA rules are language specific.
> > We also may with explicit streaming of the TBAA dag, like LLVM does.
> > 
> > Anyway, this is the updated patch fixing the Fortran's interoperability with
> > size_t and signed char.  I will send separate patch for the extra lto-symtab
> > warnings shortly.
> > 
> > I will be happy looking into the TYPE_CANONICAL (int) to be different from
> > TYPE_CANONICAL (unsigned int) if that seems desirable. There are two things that
> > needs to be solved - hash_canonical_type/gimple_canonical_types_compatible_p can't
> > use TYPE_CNAONICAL of subtypes in all cases (that is easy) and we will need some
> > way to recognize the conflict in lto-symtab other thanjust comparing TYPE_CANONICAL
> > to not warn when a variable is declared signed in Fortran unit and unsigned in C.
> > 
> > Bootstrapped/regtested ppc64le-linux.
> > 
> > 	* lto/lto.c (hash_canonical_type): Do not hash TYPE_UNSIGNED
> > 	of INTEGER_TYPE.
> > 	* tree.c (gimple_canonical_types_compatible_p): Do not compare TYPE_UNSIGNED
> > 	of INTEGER_TYPE.
> > 	* gimple-expr.c (useless_type_conversion_p): Move INTEGER type handling
> > 	ahead the canonical type lookup.
> > 
> > 	* gfortran.dg/lto/bind_c-2_0.f90: New testcase
> > 	* gfortran.dg/lto/bind_c-2_1.c: New testcase
> > 	* gfortran.dg/lto/bind_c-3_0.f90: New testcase
> > 	* gfortran.dg/lto/bind_c-3_1.c: New testcase
> > 	* gfortran.dg/lto/bind_c-4_0.f90: New testcase
> > 	* gfortran.dg/lto/bind_c-4_1.c: New testcase
> 
> Hi,
> I would like to ping this.  There are still few things to fix to make our
> merging compliant at least for C/C++/Fortran rules (the array bounds for
> Fortran and union ordering for C I believe) and I would like to progress
> on this.

I don't like the changes to useless_type_conversion_p much.  Why
do you preserve qualifiers for the integer kind compares?

All the testcases have the integral types in aggregates as members.
I already said that I'm happy globbing them together in aggregates.

I'm still not convinced that we need a 1:1 correspondence between
canonical types and alias sets.  In particular canonical types are
used for type compatibility in lhs = rhs assignments
(useless_type_conversion_p) which is a transitive relation.
Mixing both too much will cause serious confusion.  We have
alias-sets for a reason.

Richard.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-22 15:09                         ` Richard Biener
@ 2015-06-22 16:17                           ` Jan Hubicka
  0 siblings, 0 replies; 35+ messages in thread
From: Jan Hubicka @ 2015-06-22 16:17 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jan Hubicka, Joseph Myers, gcc-patches, burnus

> > Hi,
> > I would like to ping this.  There are still few things to fix to make our
> > merging compliant at least for C/C++/Fortran rules (the array bounds for
> > Fortran and union ordering for C I believe) and I would like to progress
> > on this.
> 
> I don't like the changes to useless_type_conversion_p much.  Why
> do you preserve qualifiers for the integer kind compares?
> 
> All the testcases have the integral types in aggregates as members.
> I already said that I'm happy globbing them together in aggregates.

I originally made the testcase this way because I wanted to test the way
aggregates are built and because it needs less of fortran code to realize it.
It is possible to consutrct same testcase with scalar variables.  See the other
patch fixing the surprious warning.  You need also variant "size_t a" to be
compatible with fortran equivalent of "signed size_t a", so it is not only
about variables.

> 
> I'm still not convinced that we need a 1:1 correspondence between
> canonical types and alias sets.  In particular canonical types are
> used for type compatibility in lhs = rhs assignments
> (useless_type_conversion_p) which is a transitive relation.
> Mixing both too much will cause serious confusion.  We have
> alias-sets for a reason.

OK, I am not sure if canonical types needs to actually mean the type
compatibility in the middle-end sense.  It is a language specific thing:

   The "canonical" type for this type node, which is used by frontends to
   compare the type for equality with another type.  If two types are
   equal (based on the semantics of the language), then they will have
   equivalent TYPE_CANONICAL entries.

In a way TYPE_CANONICAL seems bit schizofrenic about if it means language level
compatibility, representation compatibility or middle end semantic
compatibility.  It seems bit odd to define something like
useless_type_conversion_p by language specific manner despite the fact its
definition is now sound in language independent way as we now have all semantics
represented in IL (and flags, well)

but I would be happy to update the patch to assign different canonical types to
signed/unsigned integers and avoid recursion on those for aggregates/arrays and
all other derived types. (After all I plan to do that for pointers
incrementally)

Here we are "lucky" that alias.c already contains the globbing for
signed/unsigned.  Do we want to do the same scheme in other cases? For example
next on my list is the fact that array with bounds 3...5 is interoperable with
array[3] in C.  Here again we can not consider these useless_type_conversion_p
because index operation is different, but they are representation compatible.
This will need a special case in get_alias_set. I would not like to make
get_alias_set, or (with less loss of code quality on non-C languages) in lto's
get_alias_set langhook.

Honza
> 
> Richard.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-06-08  7:25   ` Jan Hubicka
  2015-06-08 13:43     ` Richard Biener
@ 2015-10-08  3:47     ` Jan Hubicka
  2015-10-08  7:44       ` Richard Biener
  1 sibling, 1 reply; 35+ messages in thread
From: Jan Hubicka @ 2015-10-08  3:47 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches, rguenther, burnus

Hello,
here is updated version of the patch, this time without need to modify
useless_type_conversion.  Just to recall the issue, Fortran C interoperability
requires size_t to interoperate with signed version produced by Fortran FE.
Unlike the existing logic in aliasing that makes signed and unsigned share
alias sets this propagate up to the structures.  I.e. structure containing size_t
is interoperable with structure containing ptrdiff_t.

Bootstrapped/regtested ppc64le-linux, OK?

Honza


	* tree.c (gimple_canonical_types_compatible_p): Do not compare
	TYPE_UNSIGNED for size_t and char compatible types.

	* lto.c (hash_canonical_type): Do not hash TYPE_UNSIGNED for size_t
	and char compatible types.

	* gfortran.dg/lto/bind_c-2_0.f90: New testcase.
	* gfortran.dg/lto/bind_c-2_1.c: New testcase.
	* gfortran.dg/lto/bind_c-3_0.f90: New testcase.
	* gfortran.dg/lto/bind_c-3_1.c: New testcase.
	* gfortran.dg/lto/bind_c-4_0.f90: New testcase.
	* gfortran.dg/lto/bind_c-4_1.c: New testcase.
	* gfortran.dg/lto/bind_c-5_0.f90: New testcase.
	* gfortran.dg/lto/bind_c-5_1.c: New testcase.
Index: lto/lto.c
===================================================================
--- lto/lto.c	(revision 228586)
+++ lto/lto.c	(working copy)
@@ -288,6 +288,7 @@
 hash_canonical_type (tree type)
 {
   inchash::hash hstate;
+  enum tree_code code;
 
   /* We compute alias sets only for types that needs them.
      Be sure we do not recurse to something else as we can not hash incomplete
@@ -299,7 +300,8 @@
      smaller sets; when searching for existing matching types to merge,
      only existing types having the same features as the new type will be
      checked.  */
-  hstate.add_int (tree_code_for_canonical_type_merging (TREE_CODE (type)));
+  code = tree_code_for_canonical_type_merging (TREE_CODE (type));
+  hstate.add_int (code);
   hstate.add_int (TYPE_MODE (type));
 
   /* Incorporate common features of numerical types.  */
@@ -309,8 +311,15 @@
       || TREE_CODE (type) == OFFSET_TYPE
       || POINTER_TYPE_P (type))
     {
-      hstate.add_int (TYPE_UNSIGNED (type));
       hstate.add_int (TYPE_PRECISION (type));
+      /* Ignore sign for char and size_t.  This is needed for fortran
+	 C_SIGNED_CHAR to be interoperable with both signed char and
+	 unsigned char (as stadnard requires).  Similarly fortran FE builds
+	 C_SIZE_T is signed type, while C defines it unsigned.  */
+      if (code != INTEGER_TYPE
+	  || (TYPE_PRECISION (type) != BITS_PER_UNIT
+	      && TYPE_PRECISION (type) != POINTER_SIZE))
+        hstate.add_int (TYPE_UNSIGNED (type));
     }
 
   if (VECTOR_TYPE_P (type))
Index: testsuite/gfortran.dg/lto/bind_c-2_0.f90
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-2_0.f90	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-2_0.f90	(working copy)
@@ -0,0 +1,21 @@
+! { dg-lto-do run }
+! { dg-lto-options {{ -O3 -flto }} }
+! This testcase will abort if C_PTR is not interoperable with both int *
+! and float *
+module lto_type_merge_test
+  use, intrinsic :: iso_c_binding
+  implicit none
+
+  type, bind(c) :: MYFTYPE_1
+     integer(c_signed_char) :: chr
+     integer(c_signed_char) :: chrb
+  end type MYFTYPE_1
+
+  type(myftype_1), bind(c, name="myVar") :: myVar
+
+contains
+  subroutine types_test() bind(c)
+    myVar%chr = myVar%chrb
+  end subroutine types_test
+end module lto_type_merge_test
+
Index: testsuite/gfortran.dg/lto/bind_c-2_1.c
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-2_1.c	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-2_1.c	(working copy)
@@ -0,0 +1,36 @@
+#include <stdlib.h>
+/* interopse with myftype_1 */
+typedef struct {
+   unsigned char chr;
+   signed char chr2;
+} myctype_t;
+
+
+extern void abort(void);
+void types_test(void);
+/* declared in the fortran module */
+extern myctype_t myVar;
+
+int main(int argc, char **argv)
+{
+   myctype_t *cchr;
+   asm("":"=r"(cchr):"0"(&myVar));
+   cchr->chr = 1;
+   cchr->chr2 = 2;
+
+   types_test();
+
+   if(cchr->chr != 2)
+      abort();
+   if(cchr->chr2 != 2)
+      abort();
+   myVar.chr2 = 3;
+   types_test();
+
+   if(myVar.chr != 3)
+      abort();
+   if(myVar.chr2 != 3)
+      abort();
+   return 0;
+}
+
Index: testsuite/gfortran.dg/lto/bind_c-3_0.f90
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-3_0.f90	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-3_0.f90	(working copy)
@@ -0,0 +1,91 @@
+! { dg-lto-do run }
+! { dg-lto-options {{ -O3 -flto }} }
+! This testcase will abort if integer types are not interoperable.
+module lto_type_merge_test
+  use, intrinsic :: iso_c_binding
+  implicit none
+
+  type, bind(c) :: MYFTYPE_1
+    integer(c_int) :: val_int
+    integer(c_short) :: val_short
+    integer(c_long) :: val_long
+    integer(c_long_long) :: val_long_long
+    integer(c_size_t) :: val_size_t
+    integer(c_int8_t) :: val_int8_t
+    integer(c_int16_t) :: val_int16_t
+    integer(c_int32_t) :: val_int32_t
+    integer(c_int64_t) :: val_int64_t
+    integer(c_int_least8_t) :: val_intleast_8_t
+    integer(c_int_least16_t) :: val_intleast_16_t
+    integer(c_int_least32_t) :: val_intleast_32_t
+    integer(c_int_least64_t) :: val_intleast_64_t
+    integer(c_int_fast8_t) :: val_intfast_8_t
+    integer(c_int_fast16_t) :: val_intfast_16_t
+    integer(c_int_fast32_t) :: val_intfast_32_t
+    integer(c_int_fast64_t) :: val_intfast_64_t
+    integer(c_intmax_t) :: val_intmax_t
+    integer(c_intptr_t) :: val_intptr_t
+  end type MYFTYPE_1
+
+  type(myftype_1), bind(c, name="myVar") :: myVar
+
+contains
+  subroutine types_test1() bind(c)
+    myVar%val_int = 2
+  end subroutine types_test1
+  subroutine types_test2() bind(c)
+    myVar%val_short = 2
+  end subroutine types_test2
+  subroutine types_test3() bind(c)
+    myVar%val_long = 2
+  end subroutine types_test3
+  subroutine types_test4() bind(c)
+    myVar%val_long_long = 2
+  end subroutine types_test4
+  subroutine types_test5() bind(c)
+    myVar%val_size_t = 2
+  end subroutine types_test5
+  subroutine types_test6() bind(c)
+    myVar%val_int8_t = 2
+  end subroutine types_test6
+  subroutine types_test7() bind(c)
+    myVar%val_int16_t = 2
+  end subroutine types_test7
+  subroutine types_test8() bind(c)
+    myVar%val_int32_t = 2
+  end subroutine types_test8
+  subroutine types_test9() bind(c)
+    myVar%val_int64_t = 2
+  end subroutine types_test9
+  subroutine types_test10() bind(c)
+    myVar%val_intleast_8_t = 2
+  end subroutine types_test10
+  subroutine types_test11() bind(c)
+    myVar%val_intleast_16_t = 2
+  end subroutine types_test11
+  subroutine types_test12() bind(c)
+    myVar%val_intleast_32_t = 2
+  end subroutine types_test12
+  subroutine types_test13() bind(c)
+    myVar%val_intleast_64_t = 2
+  end subroutine types_test13
+  subroutine types_test14() bind(c)
+    myVar%val_intfast_8_t = 2
+  end subroutine types_test14
+  subroutine types_test15() bind(c)
+    myVar%val_intfast_16_t = 2
+  end subroutine types_test15
+  subroutine types_test16() bind(c)
+    myVar%val_intfast_32_t = 2
+  end subroutine types_test16
+  subroutine types_test17() bind(c)
+    myVar%val_intfast_64_t = 2
+  end subroutine types_test17
+  subroutine types_test18() bind(c)
+    myVar%val_intmax_t = 2
+  end subroutine types_test18
+  subroutine types_test19() bind(c)
+    myVar%val_intptr_t = 2
+  end subroutine types_test19
+end module lto_type_merge_test
+
Index: testsuite/gfortran.dg/lto/bind_c-3_1.c
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-3_1.c	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-3_1.c	(working copy)
@@ -0,0 +1,78 @@
+#include <stdlib.h>
+#include <stdint.h>
+/* interopse with myftype_1 */
+typedef struct {
+  int val1;
+  short int val2;
+  long int val3;
+  long long int val4;
+  size_t val5;
+  int8_t val6;
+  int16_t val7;
+  int32_t val8;
+  int64_t val9;
+  int_least8_t val10;
+  int_least16_t val11;
+  int_least32_t val12;
+  int_least64_t val13;
+  int_fast8_t val14;
+  int_fast16_t val15;
+  int_fast32_t val16;
+  int_fast64_t val17;
+  intmax_t val18;
+  intptr_t val19;
+} myctype_t;
+
+
+extern void abort(void);
+void types_test1(void);
+void types_test2(void);
+void types_test3(void);
+void types_test4(void);
+void types_test5(void);
+void types_test6(void);
+void types_test7(void);
+void types_test8(void);
+void types_test9(void);
+void types_test10(void);
+void types_test11(void);
+void types_test12(void);
+void types_test13(void);
+void types_test14(void);
+void types_test15(void);
+void types_test16(void);
+void types_test17(void);
+void types_test18(void);
+void types_test19(void);
+/* declared in the fortran module */
+extern myctype_t myVar;
+
+#define test(n)\
+  cchr->val##n = 1; types_test##n (); if (cchr->val##n != 2) abort ();
+
+int main(int argc, char **argv)
+{
+   myctype_t *cchr;
+   asm("":"=r"(cchr):"0"(&myVar));
+   test(1);
+   test(2);
+   test(3);
+   test(4);
+   test(5);
+   test(6);
+   test(7);
+   test(8);
+   test(9);
+   test(10);
+   test(11);
+   test(12);
+   test(13);
+   test(14);
+   test(15);
+   test(16);
+   test(17);
+   test(18);
+   test(19);
+   return 0;
+}
+
Index: testsuite/gfortran.dg/lto/bind_c-4_0.f90
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-4_0.f90	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-4_0.f90	(working copy)
@@ -0,0 +1,48 @@
+! { dg-lto-do run }
+! { dg-lto-options {{ -O3 -flto }} }
+! This testcase will abort if real/complex/boolean/character types are not interoperable
+module lto_type_merge_test
+  use, intrinsic :: iso_c_binding
+  implicit none
+
+  type, bind(c) :: MYFTYPE_1
+    real(c_float) :: val_1
+    real(c_double) :: val_2
+    real(c_long_double) :: val_3
+    complex(c_float_complex) :: val_4
+    complex(c_double_complex) :: val_5
+    complex(c_long_double_complex) :: val_6
+    logical(c_bool) :: val_7
+    !FIXME: Fortran define c_char as array of size 1.
+    !character(c_char) :: val_8
+  end type MYFTYPE_1
+
+  type(myftype_1), bind(c, name="myVar") :: myVar
+
+contains
+  subroutine types_test1() bind(c)
+    myVar%val_1 = 2
+  end subroutine types_test1
+  subroutine types_test2() bind(c)
+    myVar%val_2 = 2
+  end subroutine types_test2
+  subroutine types_test3() bind(c)
+    myVar%val_3 = 2
+  end subroutine types_test3
+  subroutine types_test4() bind(c)
+    myVar%val_4 = 2
+  end subroutine types_test4
+  subroutine types_test5() bind(c)
+    myVar%val_5 = 2
+  end subroutine types_test5
+  subroutine types_test6() bind(c)
+    myVar%val_6 = 2
+  end subroutine types_test6
+  subroutine types_test7() bind(c)
+    myVar%val_7 = myVar%val_7 .or. .not. myVar%val_7
+  end subroutine types_test7
+  !subroutine types_test8() bind(c)
+    !myVar%val_8 = "a"
+  !end subroutine types_test8
+end module lto_type_merge_test
+
Index: testsuite/gfortran.dg/lto/bind_c-4_1.c
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-4_1.c	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-4_1.c	(working copy)
@@ -0,0 +1,46 @@
+#include <stdlib.h>
+#include <stdint.h>
+/* interopse with myftype_1 */
+typedef struct {
+  float val1;
+  double val2;
+  long double val3;
+  float _Complex val4;
+  double _Complex val5;
+  long double _Complex val6;
+  _Bool val7;
+  /* FIXME: Fortran define c_char as array of size 1.
+     char val8;  */
+} myctype_t;
+
+
+extern void abort(void);
+void types_test1(void);
+void types_test2(void);
+void types_test3(void);
+void types_test4(void);
+void types_test5(void);
+void types_test6(void);
+void types_test7(void);
+void types_test8(void);
+/* declared in the fortran module */
+extern myctype_t myVar;
+
+#define test(n)\
+  cchr->val##n = 1; types_test##n (); if (cchr->val##n != 2) abort ();
+
+int main(int argc, char **argv)
+{
+   myctype_t *cchr;
+   asm("":"=r"(cchr):"0"(&myVar));
+   test(1);
+   test(2);
+   test(3);
+   test(4);
+   test(5);
+   test(6);
+   cchr->val7 = 0; types_test7 (); if (cchr->val7 != 1) abort ();
+   /*cchr->val8 = 0; types_test8 (); if (cchr->val8 != 'a') abort ();*/
+   return 0;
+}
+
Index: testsuite/gfortran.dg/lto/bind_c-5_0.f90
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-5_0.f90	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-5_0.f90	(working copy)
@@ -0,0 +1,17 @@
+! { dg-lto-do run }
+! { dg-lto-options {{ -O3 -flto }} }
+! This testcase will abort if C_FUNPTR is not interoperable with both int *
+! and float *
+module lto_type_merge_test
+  use, intrinsic :: iso_c_binding
+  implicit none
+
+  type(c_funptr), bind(c, name="myVar") :: myVar
+  type(c_funptr), bind(c, name="myVar2") :: myVar2
+
+contains
+  subroutine types_test() bind(c)
+    myVar = myVar2
+  end subroutine types_test
+end module lto_type_merge_test
+
Index: testsuite/gfortran.dg/lto/bind_c-5_1.c
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-5_1.c	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-5_1.c	(working copy)
@@ -0,0 +1,31 @@
+#include <stdlib.h>
+/* declared in the fortran module */
+extern int (*myVar) (int);
+extern float (*myVar2) (float);
+void types_test(void);
+
+
+extern void abort(void);
+
+int main(int argc, char **argv)
+{
+   int (**myptr) (int);
+   float (**myptr2) (float);
+   asm("":"=r"(myptr):"0"(&myVar));
+   asm("":"=r"(myptr2):"0"(&myVar2));
+   *myptr = (int (*) (int)) (size_t) (void *)1;
+   *myptr2 = (float (*) (float)) (size_t) (void *)2;
+   types_test();
+   if (*myptr != (int (*) (int)) (size_t) (void *)2)
+	abort ();
+   if (*myptr2 != (float (*) (float)) (size_t) (void *)2)
+	abort ();
+   *myptr2 = (float (*) (float)) (size_t) (void *)3;
+   types_test();
+   if (*myptr != (int (*) (int)) (size_t) (void *)3)
+	abort ();
+   if (*myptr2 != (float (*) (float)) (size_t) (void *)3)
+	abort ();
+   return 0;
+}
+
Index: tree.c
===================================================================
--- tree.c	(revision 228586)
+++ tree.c	(working copy)
@@ -13062,8 +13062,8 @@
     return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
 
   /* Can't be the same type if the types don't have the same code.  */
-  if (tree_code_for_canonical_type_merging (TREE_CODE (t1))
-      != tree_code_for_canonical_type_merging (TREE_CODE (t2)))
+  enum tree_code code = tree_code_for_canonical_type_merging (TREE_CODE (t1));
+  if (code != tree_code_for_canonical_type_merging (TREE_CODE (t2)))
     return false;
 
   /* Qualifiers do not matter for canonical type comparison purposes.  */
@@ -13086,11 +13086,19 @@
       || TREE_CODE (t1) == OFFSET_TYPE
       || POINTER_TYPE_P (t1))
     {
-      /* Can't be the same type if they have different sign or precision.  */
-      if (TYPE_PRECISION (t1) != TYPE_PRECISION (t2)
-	  || TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2))
+      /* Can't be the same type if they have different recision.  */
+      if (TYPE_PRECISION (t1) != TYPE_PRECISION (t2))
 	return false;
 
+      /* Ignore sign for char and size_t.  This is needed for fortran
+	 C_SIGNED_CHAR to be interoperable with both signed char and
+	 unsigned char (as stadnard requires).  Similarly fortran FE builds
+	 C_SIZE_T is signed type, while C defines it unsigned.  */
+      if (TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2)
+	  && ((TYPE_PRECISION (t1) != BITS_PER_UNIT
+	       && TYPE_PRECISION (t1) != POINTER_SIZE)
+	      || code != INTEGER_TYPE))
+
       /* Fortran's C_SIGNED_CHAR is !TYPE_STRING_FLAG but needs to be
 	 interoperable with "signed char".  Unless all frontends are revisited
 	 to agree on these types, we must ignore the flag completely.  */

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-10-08  3:47     ` Jan Hubicka
@ 2015-10-08  7:44       ` Richard Biener
  2015-10-08 16:17         ` Jan Hubicka
  2015-10-10 19:45         ` Jan Hubicka
  0 siblings, 2 replies; 35+ messages in thread
From: Richard Biener @ 2015-10-08  7:44 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches, burnus

On Thu, 8 Oct 2015, Jan Hubicka wrote:

> Hello,
> here is updated version of the patch, this time without need to modify
> useless_type_conversion.  Just to recall the issue, Fortran C interoperability
> requires size_t to interoperate with signed version produced by Fortran FE.
> Unlike the existing logic in aliasing that makes signed and unsigned share
> alias sets this propagate up to the structures.  I.e. structure containing size_t
> is interoperable with structure containing ptrdiff_t.

Hmm, note that size_t and ptrdiff_t do not have to have the same
precision.  C11 just says size_t is the result of sizeof () and
ptrdiff_t is the result of subtracting two pointers.  So instead
of using BITS_PER_UNIT and POINTER_SIZE please look at the
global C ABI types (size_type_node for size_t interoperability
and char_type_node for char interoperability).

Please skim over the testcases to see whether you falsely test
interoperability of ptrdiff_t (I see at least intptr_t which
would need an extra handling of TYPE_PRECISION equal to that
of ptrdiff_type_node).

As you duplicate the code in two places it would be nice to
split this out into a function maybe?  
integer_precisions_with_interoperable_signedness () (uh... ;))

Ok with that change(s).

Thanks,
Richard.

> Bootstrapped/regtested ppc64le-linux, OK?
> 
> Honza
> 
> 
> 	* tree.c (gimple_canonical_types_compatible_p): Do not compare
> 	TYPE_UNSIGNED for size_t and char compatible types.
> 
> 	* lto.c (hash_canonical_type): Do not hash TYPE_UNSIGNED for size_t
> 	and char compatible types.
> 
> 	* gfortran.dg/lto/bind_c-2_0.f90: New testcase.
> 	* gfortran.dg/lto/bind_c-2_1.c: New testcase.
> 	* gfortran.dg/lto/bind_c-3_0.f90: New testcase.
> 	* gfortran.dg/lto/bind_c-3_1.c: New testcase.
> 	* gfortran.dg/lto/bind_c-4_0.f90: New testcase.
> 	* gfortran.dg/lto/bind_c-4_1.c: New testcase.
> 	* gfortran.dg/lto/bind_c-5_0.f90: New testcase.
> 	* gfortran.dg/lto/bind_c-5_1.c: New testcase.
> Index: lto/lto.c
> ===================================================================
> --- lto/lto.c	(revision 228586)
> +++ lto/lto.c	(working copy)
> @@ -288,6 +288,7 @@
>  hash_canonical_type (tree type)
>  {
>    inchash::hash hstate;
> +  enum tree_code code;
>  
>    /* We compute alias sets only for types that needs them.
>       Be sure we do not recurse to something else as we can not hash incomplete
> @@ -299,7 +300,8 @@
>       smaller sets; when searching for existing matching types to merge,
>       only existing types having the same features as the new type will be
>       checked.  */
> -  hstate.add_int (tree_code_for_canonical_type_merging (TREE_CODE (type)));
> +  code = tree_code_for_canonical_type_merging (TREE_CODE (type));
> +  hstate.add_int (code);
>    hstate.add_int (TYPE_MODE (type));
>  
>    /* Incorporate common features of numerical types.  */
> @@ -309,8 +311,15 @@
>        || TREE_CODE (type) == OFFSET_TYPE
>        || POINTER_TYPE_P (type))
>      {
> -      hstate.add_int (TYPE_UNSIGNED (type));
>        hstate.add_int (TYPE_PRECISION (type));
> +      /* Ignore sign for char and size_t.  This is needed for fortran
> +	 C_SIGNED_CHAR to be interoperable with both signed char and
> +	 unsigned char (as stadnard requires).  Similarly fortran FE builds
> +	 C_SIZE_T is signed type, while C defines it unsigned.  */
> +      if (code != INTEGER_TYPE
> +	  || (TYPE_PRECISION (type) != BITS_PER_UNIT
> +	      && TYPE_PRECISION (type) != POINTER_SIZE))
> +        hstate.add_int (TYPE_UNSIGNED (type));
>      }
>  
>    if (VECTOR_TYPE_P (type))
> Index: testsuite/gfortran.dg/lto/bind_c-2_0.f90
> ===================================================================
> --- testsuite/gfortran.dg/lto/bind_c-2_0.f90	(revision 0)
> +++ testsuite/gfortran.dg/lto/bind_c-2_0.f90	(working copy)
> @@ -0,0 +1,21 @@
> +! { dg-lto-do run }
> +! { dg-lto-options {{ -O3 -flto }} }
> +! This testcase will abort if C_PTR is not interoperable with both int *
> +! and float *
> +module lto_type_merge_test
> +  use, intrinsic :: iso_c_binding
> +  implicit none
> +
> +  type, bind(c) :: MYFTYPE_1
> +     integer(c_signed_char) :: chr
> +     integer(c_signed_char) :: chrb
> +  end type MYFTYPE_1
> +
> +  type(myftype_1), bind(c, name="myVar") :: myVar
> +
> +contains
> +  subroutine types_test() bind(c)
> +    myVar%chr = myVar%chrb
> +  end subroutine types_test
> +end module lto_type_merge_test
> +
> Index: testsuite/gfortran.dg/lto/bind_c-2_1.c
> ===================================================================
> --- testsuite/gfortran.dg/lto/bind_c-2_1.c	(revision 0)
> +++ testsuite/gfortran.dg/lto/bind_c-2_1.c	(working copy)
> @@ -0,0 +1,36 @@
> +#include <stdlib.h>
> +/* interopse with myftype_1 */
> +typedef struct {
> +   unsigned char chr;
> +   signed char chr2;
> +} myctype_t;
> +
> +
> +extern void abort(void);
> +void types_test(void);
> +/* declared in the fortran module */
> +extern myctype_t myVar;
> +
> +int main(int argc, char **argv)
> +{
> +   myctype_t *cchr;
> +   asm("":"=r"(cchr):"0"(&myVar));
> +   cchr->chr = 1;
> +   cchr->chr2 = 2;
> +
> +   types_test();
> +
> +   if(cchr->chr != 2)
> +      abort();
> +   if(cchr->chr2 != 2)
> +      abort();
> +   myVar.chr2 = 3;
> +   types_test();
> +
> +   if(myVar.chr != 3)
> +      abort();
> +   if(myVar.chr2 != 3)
> +      abort();
> +   return 0;
> +}
> +
> Index: testsuite/gfortran.dg/lto/bind_c-3_0.f90
> ===================================================================
> --- testsuite/gfortran.dg/lto/bind_c-3_0.f90	(revision 0)
> +++ testsuite/gfortran.dg/lto/bind_c-3_0.f90	(working copy)
> @@ -0,0 +1,91 @@
> +! { dg-lto-do run }
> +! { dg-lto-options {{ -O3 -flto }} }
> +! This testcase will abort if integer types are not interoperable.
> +module lto_type_merge_test
> +  use, intrinsic :: iso_c_binding
> +  implicit none
> +
> +  type, bind(c) :: MYFTYPE_1
> +    integer(c_int) :: val_int
> +    integer(c_short) :: val_short
> +    integer(c_long) :: val_long
> +    integer(c_long_long) :: val_long_long
> +    integer(c_size_t) :: val_size_t
> +    integer(c_int8_t) :: val_int8_t
> +    integer(c_int16_t) :: val_int16_t
> +    integer(c_int32_t) :: val_int32_t
> +    integer(c_int64_t) :: val_int64_t
> +    integer(c_int_least8_t) :: val_intleast_8_t
> +    integer(c_int_least16_t) :: val_intleast_16_t
> +    integer(c_int_least32_t) :: val_intleast_32_t
> +    integer(c_int_least64_t) :: val_intleast_64_t
> +    integer(c_int_fast8_t) :: val_intfast_8_t
> +    integer(c_int_fast16_t) :: val_intfast_16_t
> +    integer(c_int_fast32_t) :: val_intfast_32_t
> +    integer(c_int_fast64_t) :: val_intfast_64_t
> +    integer(c_intmax_t) :: val_intmax_t
> +    integer(c_intptr_t) :: val_intptr_t
> +  end type MYFTYPE_1
> +
> +  type(myftype_1), bind(c, name="myVar") :: myVar
> +
> +contains
> +  subroutine types_test1() bind(c)
> +    myVar%val_int = 2
> +  end subroutine types_test1
> +  subroutine types_test2() bind(c)
> +    myVar%val_short = 2
> +  end subroutine types_test2
> +  subroutine types_test3() bind(c)
> +    myVar%val_long = 2
> +  end subroutine types_test3
> +  subroutine types_test4() bind(c)
> +    myVar%val_long_long = 2
> +  end subroutine types_test4
> +  subroutine types_test5() bind(c)
> +    myVar%val_size_t = 2
> +  end subroutine types_test5
> +  subroutine types_test6() bind(c)
> +    myVar%val_int8_t = 2
> +  end subroutine types_test6
> +  subroutine types_test7() bind(c)
> +    myVar%val_int16_t = 2
> +  end subroutine types_test7
> +  subroutine types_test8() bind(c)
> +    myVar%val_int32_t = 2
> +  end subroutine types_test8
> +  subroutine types_test9() bind(c)
> +    myVar%val_int64_t = 2
> +  end subroutine types_test9
> +  subroutine types_test10() bind(c)
> +    myVar%val_intleast_8_t = 2
> +  end subroutine types_test10
> +  subroutine types_test11() bind(c)
> +    myVar%val_intleast_16_t = 2
> +  end subroutine types_test11
> +  subroutine types_test12() bind(c)
> +    myVar%val_intleast_32_t = 2
> +  end subroutine types_test12
> +  subroutine types_test13() bind(c)
> +    myVar%val_intleast_64_t = 2
> +  end subroutine types_test13
> +  subroutine types_test14() bind(c)
> +    myVar%val_intfast_8_t = 2
> +  end subroutine types_test14
> +  subroutine types_test15() bind(c)
> +    myVar%val_intfast_16_t = 2
> +  end subroutine types_test15
> +  subroutine types_test16() bind(c)
> +    myVar%val_intfast_32_t = 2
> +  end subroutine types_test16
> +  subroutine types_test17() bind(c)
> +    myVar%val_intfast_64_t = 2
> +  end subroutine types_test17
> +  subroutine types_test18() bind(c)
> +    myVar%val_intmax_t = 2
> +  end subroutine types_test18
> +  subroutine types_test19() bind(c)
> +    myVar%val_intptr_t = 2
> +  end subroutine types_test19
> +end module lto_type_merge_test
> +
> Index: testsuite/gfortran.dg/lto/bind_c-3_1.c
> ===================================================================
> --- testsuite/gfortran.dg/lto/bind_c-3_1.c	(revision 0)
> +++ testsuite/gfortran.dg/lto/bind_c-3_1.c	(working copy)
> @@ -0,0 +1,78 @@
> +#include <stdlib.h>
> +#include <stdint.h>
> +/* interopse with myftype_1 */
> +typedef struct {
> +  int val1;
> +  short int val2;
> +  long int val3;
> +  long long int val4;
> +  size_t val5;
> +  int8_t val6;
> +  int16_t val7;
> +  int32_t val8;
> +  int64_t val9;
> +  int_least8_t val10;
> +  int_least16_t val11;
> +  int_least32_t val12;
> +  int_least64_t val13;
> +  int_fast8_t val14;
> +  int_fast16_t val15;
> +  int_fast32_t val16;
> +  int_fast64_t val17;
> +  intmax_t val18;
> +  intptr_t val19;
> +} myctype_t;
> +
> +
> +extern void abort(void);
> +void types_test1(void);
> +void types_test2(void);
> +void types_test3(void);
> +void types_test4(void);
> +void types_test5(void);
> +void types_test6(void);
> +void types_test7(void);
> +void types_test8(void);
> +void types_test9(void);
> +void types_test10(void);
> +void types_test11(void);
> +void types_test12(void);
> +void types_test13(void);
> +void types_test14(void);
> +void types_test15(void);
> +void types_test16(void);
> +void types_test17(void);
> +void types_test18(void);
> +void types_test19(void);
> +/* declared in the fortran module */
> +extern myctype_t myVar;
> +
> +#define test(n)\
> +  cchr->val##n = 1; types_test##n (); if (cchr->val##n != 2) abort ();
> +
> +int main(int argc, char **argv)
> +{
> +   myctype_t *cchr;
> +   asm("":"=r"(cchr):"0"(&myVar));
> +   test(1);
> +   test(2);
> +   test(3);
> +   test(4);
> +   test(5);
> +   test(6);
> +   test(7);
> +   test(8);
> +   test(9);
> +   test(10);
> +   test(11);
> +   test(12);
> +   test(13);
> +   test(14);
> +   test(15);
> +   test(16);
> +   test(17);
> +   test(18);
> +   test(19);
> +   return 0;
> +}
> +
> Index: testsuite/gfortran.dg/lto/bind_c-4_0.f90
> ===================================================================
> --- testsuite/gfortran.dg/lto/bind_c-4_0.f90	(revision 0)
> +++ testsuite/gfortran.dg/lto/bind_c-4_0.f90	(working copy)
> @@ -0,0 +1,48 @@
> +! { dg-lto-do run }
> +! { dg-lto-options {{ -O3 -flto }} }
> +! This testcase will abort if real/complex/boolean/character types are not interoperable
> +module lto_type_merge_test
> +  use, intrinsic :: iso_c_binding
> +  implicit none
> +
> +  type, bind(c) :: MYFTYPE_1
> +    real(c_float) :: val_1
> +    real(c_double) :: val_2
> +    real(c_long_double) :: val_3
> +    complex(c_float_complex) :: val_4
> +    complex(c_double_complex) :: val_5
> +    complex(c_long_double_complex) :: val_6
> +    logical(c_bool) :: val_7
> +    !FIXME: Fortran define c_char as array of size 1.
> +    !character(c_char) :: val_8
> +  end type MYFTYPE_1
> +
> +  type(myftype_1), bind(c, name="myVar") :: myVar
> +
> +contains
> +  subroutine types_test1() bind(c)
> +    myVar%val_1 = 2
> +  end subroutine types_test1
> +  subroutine types_test2() bind(c)
> +    myVar%val_2 = 2
> +  end subroutine types_test2
> +  subroutine types_test3() bind(c)
> +    myVar%val_3 = 2
> +  end subroutine types_test3
> +  subroutine types_test4() bind(c)
> +    myVar%val_4 = 2
> +  end subroutine types_test4
> +  subroutine types_test5() bind(c)
> +    myVar%val_5 = 2
> +  end subroutine types_test5
> +  subroutine types_test6() bind(c)
> +    myVar%val_6 = 2
> +  end subroutine types_test6
> +  subroutine types_test7() bind(c)
> +    myVar%val_7 = myVar%val_7 .or. .not. myVar%val_7
> +  end subroutine types_test7
> +  !subroutine types_test8() bind(c)
> +    !myVar%val_8 = "a"
> +  !end subroutine types_test8
> +end module lto_type_merge_test
> +
> Index: testsuite/gfortran.dg/lto/bind_c-4_1.c
> ===================================================================
> --- testsuite/gfortran.dg/lto/bind_c-4_1.c	(revision 0)
> +++ testsuite/gfortran.dg/lto/bind_c-4_1.c	(working copy)
> @@ -0,0 +1,46 @@
> +#include <stdlib.h>
> +#include <stdint.h>
> +/* interopse with myftype_1 */
> +typedef struct {
> +  float val1;
> +  double val2;
> +  long double val3;
> +  float _Complex val4;
> +  double _Complex val5;
> +  long double _Complex val6;
> +  _Bool val7;
> +  /* FIXME: Fortran define c_char as array of size 1.
> +     char val8;  */
> +} myctype_t;
> +
> +
> +extern void abort(void);
> +void types_test1(void);
> +void types_test2(void);
> +void types_test3(void);
> +void types_test4(void);
> +void types_test5(void);
> +void types_test6(void);
> +void types_test7(void);
> +void types_test8(void);
> +/* declared in the fortran module */
> +extern myctype_t myVar;
> +
> +#define test(n)\
> +  cchr->val##n = 1; types_test##n (); if (cchr->val##n != 2) abort ();
> +
> +int main(int argc, char **argv)
> +{
> +   myctype_t *cchr;
> +   asm("":"=r"(cchr):"0"(&myVar));
> +   test(1);
> +   test(2);
> +   test(3);
> +   test(4);
> +   test(5);
> +   test(6);
> +   cchr->val7 = 0; types_test7 (); if (cchr->val7 != 1) abort ();
> +   /*cchr->val8 = 0; types_test8 (); if (cchr->val8 != 'a') abort ();*/
> +   return 0;
> +}
> +
> Index: testsuite/gfortran.dg/lto/bind_c-5_0.f90
> ===================================================================
> --- testsuite/gfortran.dg/lto/bind_c-5_0.f90	(revision 0)
> +++ testsuite/gfortran.dg/lto/bind_c-5_0.f90	(working copy)
> @@ -0,0 +1,17 @@
> +! { dg-lto-do run }
> +! { dg-lto-options {{ -O3 -flto }} }
> +! This testcase will abort if C_FUNPTR is not interoperable with both int *
> +! and float *
> +module lto_type_merge_test
> +  use, intrinsic :: iso_c_binding
> +  implicit none
> +
> +  type(c_funptr), bind(c, name="myVar") :: myVar
> +  type(c_funptr), bind(c, name="myVar2") :: myVar2
> +
> +contains
> +  subroutine types_test() bind(c)
> +    myVar = myVar2
> +  end subroutine types_test
> +end module lto_type_merge_test
> +
> Index: testsuite/gfortran.dg/lto/bind_c-5_1.c
> ===================================================================
> --- testsuite/gfortran.dg/lto/bind_c-5_1.c	(revision 0)
> +++ testsuite/gfortran.dg/lto/bind_c-5_1.c	(working copy)
> @@ -0,0 +1,31 @@
> +#include <stdlib.h>
> +/* declared in the fortran module */
> +extern int (*myVar) (int);
> +extern float (*myVar2) (float);
> +void types_test(void);
> +
> +
> +extern void abort(void);
> +
> +int main(int argc, char **argv)
> +{
> +   int (**myptr) (int);
> +   float (**myptr2) (float);
> +   asm("":"=r"(myptr):"0"(&myVar));
> +   asm("":"=r"(myptr2):"0"(&myVar2));
> +   *myptr = (int (*) (int)) (size_t) (void *)1;
> +   *myptr2 = (float (*) (float)) (size_t) (void *)2;
> +   types_test();
> +   if (*myptr != (int (*) (int)) (size_t) (void *)2)
> +	abort ();
> +   if (*myptr2 != (float (*) (float)) (size_t) (void *)2)
> +	abort ();
> +   *myptr2 = (float (*) (float)) (size_t) (void *)3;
> +   types_test();
> +   if (*myptr != (int (*) (int)) (size_t) (void *)3)
> +	abort ();
> +   if (*myptr2 != (float (*) (float)) (size_t) (void *)3)
> +	abort ();
> +   return 0;
> +}
> +
> Index: tree.c
> ===================================================================
> --- tree.c	(revision 228586)
> +++ tree.c	(working copy)
> @@ -13062,8 +13062,8 @@
>      return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
>  
>    /* Can't be the same type if the types don't have the same code.  */
> -  if (tree_code_for_canonical_type_merging (TREE_CODE (t1))
> -      != tree_code_for_canonical_type_merging (TREE_CODE (t2)))
> +  enum tree_code code = tree_code_for_canonical_type_merging (TREE_CODE (t1));
> +  if (code != tree_code_for_canonical_type_merging (TREE_CODE (t2)))
>      return false;
>  
>    /* Qualifiers do not matter for canonical type comparison purposes.  */
> @@ -13086,11 +13086,19 @@
>        || TREE_CODE (t1) == OFFSET_TYPE
>        || POINTER_TYPE_P (t1))
>      {
> -      /* Can't be the same type if they have different sign or precision.  */
> -      if (TYPE_PRECISION (t1) != TYPE_PRECISION (t2)
> -	  || TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2))
> +      /* Can't be the same type if they have different recision.  */
> +      if (TYPE_PRECISION (t1) != TYPE_PRECISION (t2))
>  	return false;
>  
> +      /* Ignore sign for char and size_t.  This is needed for fortran
> +	 C_SIGNED_CHAR to be interoperable with both signed char and
> +	 unsigned char (as stadnard requires).  Similarly fortran FE builds
> +	 C_SIZE_T is signed type, while C defines it unsigned.  */
> +      if (TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2)
> +	  && ((TYPE_PRECISION (t1) != BITS_PER_UNIT
> +	       && TYPE_PRECISION (t1) != POINTER_SIZE)
> +	      || code != INTEGER_TYPE))
> +
>        /* Fortran's C_SIGNED_CHAR is !TYPE_STRING_FLAG but needs to be
>  	 interoperable with "signed char".  Unless all frontends are revisited
>  	 to agree on these types, we must ignore the flag completely.  */
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-10-08  7:44       ` Richard Biener
@ 2015-10-08 16:17         ` Jan Hubicka
  2015-10-10 19:45         ` Jan Hubicka
  1 sibling, 0 replies; 35+ messages in thread
From: Jan Hubicka @ 2015-10-08 16:17 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jan Hubicka, gcc-patches, burnus

> On Thu, 8 Oct 2015, Jan Hubicka wrote:
> 
> > Hello,
> > here is updated version of the patch, this time without need to modify
> > useless_type_conversion.  Just to recall the issue, Fortran C interoperability
> > requires size_t to interoperate with signed version produced by Fortran FE.
> > Unlike the existing logic in aliasing that makes signed and unsigned share
> > alias sets this propagate up to the structures.  I.e. structure containing size_t
> > is interoperable with structure containing ptrdiff_t.
> 
> Hmm, note that size_t and ptrdiff_t do not have to have the same
> precision.  C11 just says size_t is the result of sizeof () and
> ptrdiff_t is the result of subtracting two pointers.  So instead
> of using BITS_PER_UNIT and POINTER_SIZE please look at the
> global C ABI types (size_type_node for size_t interoperability
> and char_type_node for char interoperability).

OK, I wll compare with TYPE_PRECISION of these.

> 
> Please skim over the testcases to see whether you falsely test
> interoperability of ptrdiff_t (I see at least intptr_t which
> would need an extra handling of TYPE_PRECISION equal to that
> of ptrdiff_type_node).

No, I only test size_t. I used ptrdiff_t only in the explanation letter ;)
The other types are just listing all integer types explicitely claimed
by the standard to be inter-operable.
> 
> As you duplicate the code in two places it would be nice to
> split this out into a function maybe?  
> integer_precisions_with_interoperable_signedness () (uh... ;))

Uhm, yep, that is a good idea. I will prepare updated patch after
fixing that Ada issue.

Honza
> 
> Ok with that change(s).
> 
> Thanks,
> Richard.
> 
> > Bootstrapped/regtested ppc64le-linux, OK?
> > 
> > Honza
> > 
> > 
> > 	* tree.c (gimple_canonical_types_compatible_p): Do not compare
> > 	TYPE_UNSIGNED for size_t and char compatible types.
> > 
> > 	* lto.c (hash_canonical_type): Do not hash TYPE_UNSIGNED for size_t
> > 	and char compatible types.
> > 
> > 	* gfortran.dg/lto/bind_c-2_0.f90: New testcase.
> > 	* gfortran.dg/lto/bind_c-2_1.c: New testcase.
> > 	* gfortran.dg/lto/bind_c-3_0.f90: New testcase.
> > 	* gfortran.dg/lto/bind_c-3_1.c: New testcase.
> > 	* gfortran.dg/lto/bind_c-4_0.f90: New testcase.
> > 	* gfortran.dg/lto/bind_c-4_1.c: New testcase.
> > 	* gfortran.dg/lto/bind_c-5_0.f90: New testcase.
> > 	* gfortran.dg/lto/bind_c-5_1.c: New testcase.
> > Index: lto/lto.c
> > ===================================================================
> > --- lto/lto.c	(revision 228586)
> > +++ lto/lto.c	(working copy)
> > @@ -288,6 +288,7 @@
> >  hash_canonical_type (tree type)
> >  {
> >    inchash::hash hstate;
> > +  enum tree_code code;
> >  
> >    /* We compute alias sets only for types that needs them.
> >       Be sure we do not recurse to something else as we can not hash incomplete
> > @@ -299,7 +300,8 @@
> >       smaller sets; when searching for existing matching types to merge,
> >       only existing types having the same features as the new type will be
> >       checked.  */
> > -  hstate.add_int (tree_code_for_canonical_type_merging (TREE_CODE (type)));
> > +  code = tree_code_for_canonical_type_merging (TREE_CODE (type));
> > +  hstate.add_int (code);
> >    hstate.add_int (TYPE_MODE (type));
> >  
> >    /* Incorporate common features of numerical types.  */
> > @@ -309,8 +311,15 @@
> >        || TREE_CODE (type) == OFFSET_TYPE
> >        || POINTER_TYPE_P (type))
> >      {
> > -      hstate.add_int (TYPE_UNSIGNED (type));
> >        hstate.add_int (TYPE_PRECISION (type));
> > +      /* Ignore sign for char and size_t.  This is needed for fortran
> > +	 C_SIGNED_CHAR to be interoperable with both signed char and
> > +	 unsigned char (as stadnard requires).  Similarly fortran FE builds
> > +	 C_SIZE_T is signed type, while C defines it unsigned.  */
> > +      if (code != INTEGER_TYPE
> > +	  || (TYPE_PRECISION (type) != BITS_PER_UNIT
> > +	      && TYPE_PRECISION (type) != POINTER_SIZE))
> > +        hstate.add_int (TYPE_UNSIGNED (type));
> >      }
> >  
> >    if (VECTOR_TYPE_P (type))
> > Index: testsuite/gfortran.dg/lto/bind_c-2_0.f90
> > ===================================================================
> > --- testsuite/gfortran.dg/lto/bind_c-2_0.f90	(revision 0)
> > +++ testsuite/gfortran.dg/lto/bind_c-2_0.f90	(working copy)
> > @@ -0,0 +1,21 @@
> > +! { dg-lto-do run }
> > +! { dg-lto-options {{ -O3 -flto }} }
> > +! This testcase will abort if C_PTR is not interoperable with both int *
> > +! and float *
> > +module lto_type_merge_test
> > +  use, intrinsic :: iso_c_binding
> > +  implicit none
> > +
> > +  type, bind(c) :: MYFTYPE_1
> > +     integer(c_signed_char) :: chr
> > +     integer(c_signed_char) :: chrb
> > +  end type MYFTYPE_1
> > +
> > +  type(myftype_1), bind(c, name="myVar") :: myVar
> > +
> > +contains
> > +  subroutine types_test() bind(c)
> > +    myVar%chr = myVar%chrb
> > +  end subroutine types_test
> > +end module lto_type_merge_test
> > +
> > Index: testsuite/gfortran.dg/lto/bind_c-2_1.c
> > ===================================================================
> > --- testsuite/gfortran.dg/lto/bind_c-2_1.c	(revision 0)
> > +++ testsuite/gfortran.dg/lto/bind_c-2_1.c	(working copy)
> > @@ -0,0 +1,36 @@
> > +#include <stdlib.h>
> > +/* interopse with myftype_1 */
> > +typedef struct {
> > +   unsigned char chr;
> > +   signed char chr2;
> > +} myctype_t;
> > +
> > +
> > +extern void abort(void);
> > +void types_test(void);
> > +/* declared in the fortran module */
> > +extern myctype_t myVar;
> > +
> > +int main(int argc, char **argv)
> > +{
> > +   myctype_t *cchr;
> > +   asm("":"=r"(cchr):"0"(&myVar));
> > +   cchr->chr = 1;
> > +   cchr->chr2 = 2;
> > +
> > +   types_test();
> > +
> > +   if(cchr->chr != 2)
> > +      abort();
> > +   if(cchr->chr2 != 2)
> > +      abort();
> > +   myVar.chr2 = 3;
> > +   types_test();
> > +
> > +   if(myVar.chr != 3)
> > +      abort();
> > +   if(myVar.chr2 != 3)
> > +      abort();
> > +   return 0;
> > +}
> > +
> > Index: testsuite/gfortran.dg/lto/bind_c-3_0.f90
> > ===================================================================
> > --- testsuite/gfortran.dg/lto/bind_c-3_0.f90	(revision 0)
> > +++ testsuite/gfortran.dg/lto/bind_c-3_0.f90	(working copy)
> > @@ -0,0 +1,91 @@
> > +! { dg-lto-do run }
> > +! { dg-lto-options {{ -O3 -flto }} }
> > +! This testcase will abort if integer types are not interoperable.
> > +module lto_type_merge_test
> > +  use, intrinsic :: iso_c_binding
> > +  implicit none
> > +
> > +  type, bind(c) :: MYFTYPE_1
> > +    integer(c_int) :: val_int
> > +    integer(c_short) :: val_short
> > +    integer(c_long) :: val_long
> > +    integer(c_long_long) :: val_long_long
> > +    integer(c_size_t) :: val_size_t
> > +    integer(c_int8_t) :: val_int8_t
> > +    integer(c_int16_t) :: val_int16_t
> > +    integer(c_int32_t) :: val_int32_t
> > +    integer(c_int64_t) :: val_int64_t
> > +    integer(c_int_least8_t) :: val_intleast_8_t
> > +    integer(c_int_least16_t) :: val_intleast_16_t
> > +    integer(c_int_least32_t) :: val_intleast_32_t
> > +    integer(c_int_least64_t) :: val_intleast_64_t
> > +    integer(c_int_fast8_t) :: val_intfast_8_t
> > +    integer(c_int_fast16_t) :: val_intfast_16_t
> > +    integer(c_int_fast32_t) :: val_intfast_32_t
> > +    integer(c_int_fast64_t) :: val_intfast_64_t
> > +    integer(c_intmax_t) :: val_intmax_t
> > +    integer(c_intptr_t) :: val_intptr_t
> > +  end type MYFTYPE_1
> > +
> > +  type(myftype_1), bind(c, name="myVar") :: myVar
> > +
> > +contains
> > +  subroutine types_test1() bind(c)
> > +    myVar%val_int = 2
> > +  end subroutine types_test1
> > +  subroutine types_test2() bind(c)
> > +    myVar%val_short = 2
> > +  end subroutine types_test2
> > +  subroutine types_test3() bind(c)
> > +    myVar%val_long = 2
> > +  end subroutine types_test3
> > +  subroutine types_test4() bind(c)
> > +    myVar%val_long_long = 2
> > +  end subroutine types_test4
> > +  subroutine types_test5() bind(c)
> > +    myVar%val_size_t = 2
> > +  end subroutine types_test5
> > +  subroutine types_test6() bind(c)
> > +    myVar%val_int8_t = 2
> > +  end subroutine types_test6
> > +  subroutine types_test7() bind(c)
> > +    myVar%val_int16_t = 2
> > +  end subroutine types_test7
> > +  subroutine types_test8() bind(c)
> > +    myVar%val_int32_t = 2
> > +  end subroutine types_test8
> > +  subroutine types_test9() bind(c)
> > +    myVar%val_int64_t = 2
> > +  end subroutine types_test9
> > +  subroutine types_test10() bind(c)
> > +    myVar%val_intleast_8_t = 2
> > +  end subroutine types_test10
> > +  subroutine types_test11() bind(c)
> > +    myVar%val_intleast_16_t = 2
> > +  end subroutine types_test11
> > +  subroutine types_test12() bind(c)
> > +    myVar%val_intleast_32_t = 2
> > +  end subroutine types_test12
> > +  subroutine types_test13() bind(c)
> > +    myVar%val_intleast_64_t = 2
> > +  end subroutine types_test13
> > +  subroutine types_test14() bind(c)
> > +    myVar%val_intfast_8_t = 2
> > +  end subroutine types_test14
> > +  subroutine types_test15() bind(c)
> > +    myVar%val_intfast_16_t = 2
> > +  end subroutine types_test15
> > +  subroutine types_test16() bind(c)
> > +    myVar%val_intfast_32_t = 2
> > +  end subroutine types_test16
> > +  subroutine types_test17() bind(c)
> > +    myVar%val_intfast_64_t = 2
> > +  end subroutine types_test17
> > +  subroutine types_test18() bind(c)
> > +    myVar%val_intmax_t = 2
> > +  end subroutine types_test18
> > +  subroutine types_test19() bind(c)
> > +    myVar%val_intptr_t = 2
> > +  end subroutine types_test19
> > +end module lto_type_merge_test
> > +
> > Index: testsuite/gfortran.dg/lto/bind_c-3_1.c
> > ===================================================================
> > --- testsuite/gfortran.dg/lto/bind_c-3_1.c	(revision 0)
> > +++ testsuite/gfortran.dg/lto/bind_c-3_1.c	(working copy)
> > @@ -0,0 +1,78 @@
> > +#include <stdlib.h>
> > +#include <stdint.h>
> > +/* interopse with myftype_1 */
> > +typedef struct {
> > +  int val1;
> > +  short int val2;
> > +  long int val3;
> > +  long long int val4;
> > +  size_t val5;
> > +  int8_t val6;
> > +  int16_t val7;
> > +  int32_t val8;
> > +  int64_t val9;
> > +  int_least8_t val10;
> > +  int_least16_t val11;
> > +  int_least32_t val12;
> > +  int_least64_t val13;
> > +  int_fast8_t val14;
> > +  int_fast16_t val15;
> > +  int_fast32_t val16;
> > +  int_fast64_t val17;
> > +  intmax_t val18;
> > +  intptr_t val19;
> > +} myctype_t;
> > +
> > +
> > +extern void abort(void);
> > +void types_test1(void);
> > +void types_test2(void);
> > +void types_test3(void);
> > +void types_test4(void);
> > +void types_test5(void);
> > +void types_test6(void);
> > +void types_test7(void);
> > +void types_test8(void);
> > +void types_test9(void);
> > +void types_test10(void);
> > +void types_test11(void);
> > +void types_test12(void);
> > +void types_test13(void);
> > +void types_test14(void);
> > +void types_test15(void);
> > +void types_test16(void);
> > +void types_test17(void);
> > +void types_test18(void);
> > +void types_test19(void);
> > +/* declared in the fortran module */
> > +extern myctype_t myVar;
> > +
> > +#define test(n)\
> > +  cchr->val##n = 1; types_test##n (); if (cchr->val##n != 2) abort ();
> > +
> > +int main(int argc, char **argv)
> > +{
> > +   myctype_t *cchr;
> > +   asm("":"=r"(cchr):"0"(&myVar));
> > +   test(1);
> > +   test(2);
> > +   test(3);
> > +   test(4);
> > +   test(5);
> > +   test(6);
> > +   test(7);
> > +   test(8);
> > +   test(9);
> > +   test(10);
> > +   test(11);
> > +   test(12);
> > +   test(13);
> > +   test(14);
> > +   test(15);
> > +   test(16);
> > +   test(17);
> > +   test(18);
> > +   test(19);
> > +   return 0;
> > +}
> > +
> > Index: testsuite/gfortran.dg/lto/bind_c-4_0.f90
> > ===================================================================
> > --- testsuite/gfortran.dg/lto/bind_c-4_0.f90	(revision 0)
> > +++ testsuite/gfortran.dg/lto/bind_c-4_0.f90	(working copy)
> > @@ -0,0 +1,48 @@
> > +! { dg-lto-do run }
> > +! { dg-lto-options {{ -O3 -flto }} }
> > +! This testcase will abort if real/complex/boolean/character types are not interoperable
> > +module lto_type_merge_test
> > +  use, intrinsic :: iso_c_binding
> > +  implicit none
> > +
> > +  type, bind(c) :: MYFTYPE_1
> > +    real(c_float) :: val_1
> > +    real(c_double) :: val_2
> > +    real(c_long_double) :: val_3
> > +    complex(c_float_complex) :: val_4
> > +    complex(c_double_complex) :: val_5
> > +    complex(c_long_double_complex) :: val_6
> > +    logical(c_bool) :: val_7
> > +    !FIXME: Fortran define c_char as array of size 1.
> > +    !character(c_char) :: val_8
> > +  end type MYFTYPE_1
> > +
> > +  type(myftype_1), bind(c, name="myVar") :: myVar
> > +
> > +contains
> > +  subroutine types_test1() bind(c)
> > +    myVar%val_1 = 2
> > +  end subroutine types_test1
> > +  subroutine types_test2() bind(c)
> > +    myVar%val_2 = 2
> > +  end subroutine types_test2
> > +  subroutine types_test3() bind(c)
> > +    myVar%val_3 = 2
> > +  end subroutine types_test3
> > +  subroutine types_test4() bind(c)
> > +    myVar%val_4 = 2
> > +  end subroutine types_test4
> > +  subroutine types_test5() bind(c)
> > +    myVar%val_5 = 2
> > +  end subroutine types_test5
> > +  subroutine types_test6() bind(c)
> > +    myVar%val_6 = 2
> > +  end subroutine types_test6
> > +  subroutine types_test7() bind(c)
> > +    myVar%val_7 = myVar%val_7 .or. .not. myVar%val_7
> > +  end subroutine types_test7
> > +  !subroutine types_test8() bind(c)
> > +    !myVar%val_8 = "a"
> > +  !end subroutine types_test8
> > +end module lto_type_merge_test
> > +
> > Index: testsuite/gfortran.dg/lto/bind_c-4_1.c
> > ===================================================================
> > --- testsuite/gfortran.dg/lto/bind_c-4_1.c	(revision 0)
> > +++ testsuite/gfortran.dg/lto/bind_c-4_1.c	(working copy)
> > @@ -0,0 +1,46 @@
> > +#include <stdlib.h>
> > +#include <stdint.h>
> > +/* interopse with myftype_1 */
> > +typedef struct {
> > +  float val1;
> > +  double val2;
> > +  long double val3;
> > +  float _Complex val4;
> > +  double _Complex val5;
> > +  long double _Complex val6;
> > +  _Bool val7;
> > +  /* FIXME: Fortran define c_char as array of size 1.
> > +     char val8;  */
> > +} myctype_t;
> > +
> > +
> > +extern void abort(void);
> > +void types_test1(void);
> > +void types_test2(void);
> > +void types_test3(void);
> > +void types_test4(void);
> > +void types_test5(void);
> > +void types_test6(void);
> > +void types_test7(void);
> > +void types_test8(void);
> > +/* declared in the fortran module */
> > +extern myctype_t myVar;
> > +
> > +#define test(n)\
> > +  cchr->val##n = 1; types_test##n (); if (cchr->val##n != 2) abort ();
> > +
> > +int main(int argc, char **argv)
> > +{
> > +   myctype_t *cchr;
> > +   asm("":"=r"(cchr):"0"(&myVar));
> > +   test(1);
> > +   test(2);
> > +   test(3);
> > +   test(4);
> > +   test(5);
> > +   test(6);
> > +   cchr->val7 = 0; types_test7 (); if (cchr->val7 != 1) abort ();
> > +   /*cchr->val8 = 0; types_test8 (); if (cchr->val8 != 'a') abort ();*/
> > +   return 0;
> > +}
> > +
> > Index: testsuite/gfortran.dg/lto/bind_c-5_0.f90
> > ===================================================================
> > --- testsuite/gfortran.dg/lto/bind_c-5_0.f90	(revision 0)
> > +++ testsuite/gfortran.dg/lto/bind_c-5_0.f90	(working copy)
> > @@ -0,0 +1,17 @@
> > +! { dg-lto-do run }
> > +! { dg-lto-options {{ -O3 -flto }} }
> > +! This testcase will abort if C_FUNPTR is not interoperable with both int *
> > +! and float *
> > +module lto_type_merge_test
> > +  use, intrinsic :: iso_c_binding
> > +  implicit none
> > +
> > +  type(c_funptr), bind(c, name="myVar") :: myVar
> > +  type(c_funptr), bind(c, name="myVar2") :: myVar2
> > +
> > +contains
> > +  subroutine types_test() bind(c)
> > +    myVar = myVar2
> > +  end subroutine types_test
> > +end module lto_type_merge_test
> > +
> > Index: testsuite/gfortran.dg/lto/bind_c-5_1.c
> > ===================================================================
> > --- testsuite/gfortran.dg/lto/bind_c-5_1.c	(revision 0)
> > +++ testsuite/gfortran.dg/lto/bind_c-5_1.c	(working copy)
> > @@ -0,0 +1,31 @@
> > +#include <stdlib.h>
> > +/* declared in the fortran module */
> > +extern int (*myVar) (int);
> > +extern float (*myVar2) (float);
> > +void types_test(void);
> > +
> > +
> > +extern void abort(void);
> > +
> > +int main(int argc, char **argv)
> > +{
> > +   int (**myptr) (int);
> > +   float (**myptr2) (float);
> > +   asm("":"=r"(myptr):"0"(&myVar));
> > +   asm("":"=r"(myptr2):"0"(&myVar2));
> > +   *myptr = (int (*) (int)) (size_t) (void *)1;
> > +   *myptr2 = (float (*) (float)) (size_t) (void *)2;
> > +   types_test();
> > +   if (*myptr != (int (*) (int)) (size_t) (void *)2)
> > +	abort ();
> > +   if (*myptr2 != (float (*) (float)) (size_t) (void *)2)
> > +	abort ();
> > +   *myptr2 = (float (*) (float)) (size_t) (void *)3;
> > +   types_test();
> > +   if (*myptr != (int (*) (int)) (size_t) (void *)3)
> > +	abort ();
> > +   if (*myptr2 != (float (*) (float)) (size_t) (void *)3)
> > +	abort ();
> > +   return 0;
> > +}
> > +
> > Index: tree.c
> > ===================================================================
> > --- tree.c	(revision 228586)
> > +++ tree.c	(working copy)
> > @@ -13062,8 +13062,8 @@
> >      return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
> >  
> >    /* Can't be the same type if the types don't have the same code.  */
> > -  if (tree_code_for_canonical_type_merging (TREE_CODE (t1))
> > -      != tree_code_for_canonical_type_merging (TREE_CODE (t2)))
> > +  enum tree_code code = tree_code_for_canonical_type_merging (TREE_CODE (t1));
> > +  if (code != tree_code_for_canonical_type_merging (TREE_CODE (t2)))
> >      return false;
> >  
> >    /* Qualifiers do not matter for canonical type comparison purposes.  */
> > @@ -13086,11 +13086,19 @@
> >        || TREE_CODE (t1) == OFFSET_TYPE
> >        || POINTER_TYPE_P (t1))
> >      {
> > -      /* Can't be the same type if they have different sign or precision.  */
> > -      if (TYPE_PRECISION (t1) != TYPE_PRECISION (t2)
> > -	  || TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2))
> > +      /* Can't be the same type if they have different recision.  */
> > +      if (TYPE_PRECISION (t1) != TYPE_PRECISION (t2))
> >  	return false;
> >  
> > +      /* Ignore sign for char and size_t.  This is needed for fortran
> > +	 C_SIGNED_CHAR to be interoperable with both signed char and
> > +	 unsigned char (as stadnard requires).  Similarly fortran FE builds
> > +	 C_SIZE_T is signed type, while C defines it unsigned.  */
> > +      if (TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2)
> > +	  && ((TYPE_PRECISION (t1) != BITS_PER_UNIT
> > +	       && TYPE_PRECISION (t1) != POINTER_SIZE)
> > +	      || code != INTEGER_TYPE))
> > +
> >        /* Fortran's C_SIGNED_CHAR is !TYPE_STRING_FLAG but needs to be
> >  	 interoperable with "signed char".  Unless all frontends are revisited
> >  	 to agree on these types, we must ignore the flag completely.  */
> > 
> > 
> 
> -- 
> Richard Biener <rguenther@suse.de>
> SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-10-08  7:44       ` Richard Biener
  2015-10-08 16:17         ` Jan Hubicka
@ 2015-10-10 19:45         ` Jan Hubicka
  1 sibling, 0 replies; 35+ messages in thread
From: Jan Hubicka @ 2015-10-10 19:45 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jan Hubicka, gcc-patches, burnus

Hi,
this is a variant of patch I commited (adding the suggested predicate)

Honza

	* tree.c (type_with_interoperable_signedness): New.
	(gimple_canonical_types_compatible_p): Use it.
	* tree.h (type_with_interoperable_signedness): Declare

	* lto.c (hash_canonical_type): Honor
	type_with_interoperable_signedness.

	* gfortran.dg/lto/bind_c-2_0.f90: New testcase.
	* gfortran.dg/lto/bind_c-2_1.c: New testcase.
	* gfortran.dg/lto/bind_c-3_0.f90: New testcase.
	* gfortran.dg/lto/bind_c-3_1.c: New testcase.
	* gfortran.dg/lto/bind_c-4_0.f90: New testcase.
	* gfortran.dg/lto/bind_c-4_1.c: New testcase.
	* gfortran.dg/lto/bind_c-5_0.f90: New testcase.
	* gfortran.dg/lto/bind_c-5_1.c: New testcase.
Index: testsuite/gfortran.dg/lto/bind_c-2_1.c
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-2_1.c	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-2_1.c	(revision 0)
@@ -0,0 +1,36 @@
+#include <stdlib.h>
+/* interopse with myftype_1 */
+typedef struct {
+   unsigned char chr;
+   signed char chr2;
+} myctype_t;
+
+
+extern void abort(void);
+void types_test(void);
+/* declared in the fortran module */
+extern myctype_t myVar;
+
+int main(int argc, char **argv)
+{
+   myctype_t *cchr;
+   asm("":"=r"(cchr):"0"(&myVar));
+   cchr->chr = 1;
+   cchr->chr2 = 2;
+
+   types_test();
+
+   if(cchr->chr != 2)
+      abort();
+   if(cchr->chr2 != 2)
+      abort();
+   myVar.chr2 = 3;
+   types_test();
+
+   if(myVar.chr != 3)
+      abort();
+   if(myVar.chr2 != 3)
+      abort();
+   return 0;
+}
+
Index: testsuite/gfortran.dg/lto/bind_c-3_1.c
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-3_1.c	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-3_1.c	(revision 0)
@@ -0,0 +1,78 @@
+#include <stdlib.h>
+#include <stdint.h>
+/* interopse with myftype_1 */
+typedef struct {
+  int val1;
+  short int val2;
+  long int val3;
+  long long int val4;
+  size_t val5;
+  int8_t val6;
+  int16_t val7;
+  int32_t val8;
+  int64_t val9;
+  int_least8_t val10;
+  int_least16_t val11;
+  int_least32_t val12;
+  int_least64_t val13;
+  int_fast8_t val14;
+  int_fast16_t val15;
+  int_fast32_t val16;
+  int_fast64_t val17;
+  intmax_t val18;
+  intptr_t val19;
+} myctype_t;
+
+
+extern void abort(void);
+void types_test1(void);
+void types_test2(void);
+void types_test3(void);
+void types_test4(void);
+void types_test5(void);
+void types_test6(void);
+void types_test7(void);
+void types_test8(void);
+void types_test9(void);
+void types_test10(void);
+void types_test11(void);
+void types_test12(void);
+void types_test13(void);
+void types_test14(void);
+void types_test15(void);
+void types_test16(void);
+void types_test17(void);
+void types_test18(void);
+void types_test19(void);
+/* declared in the fortran module */
+extern myctype_t myVar;
+
+#define test(n)\
+  cchr->val##n = 1; types_test##n (); if (cchr->val##n != 2) abort ();
+
+int main(int argc, char **argv)
+{
+   myctype_t *cchr;
+   asm("":"=r"(cchr):"0"(&myVar));
+   test(1);
+   test(2);
+   test(3);
+   test(4);
+   test(5);
+   test(6);
+   test(7);
+   test(8);
+   test(9);
+   test(10);
+   test(11);
+   test(12);
+   test(13);
+   test(14);
+   test(15);
+   test(16);
+   test(17);
+   test(18);
+   test(19);
+   return 0;
+}
+
Index: testsuite/gfortran.dg/lto/bind_c-4_1.c
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-4_1.c	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-4_1.c	(revision 0)
@@ -0,0 +1,46 @@
+#include <stdlib.h>
+#include <stdint.h>
+/* interopse with myftype_1 */
+typedef struct {
+  float val1;
+  double val2;
+  long double val3;
+  float _Complex val4;
+  double _Complex val5;
+  long double _Complex val6;
+  _Bool val7;
+  /* FIXME: Fortran define c_char as array of size 1.
+     char val8;  */
+} myctype_t;
+
+
+extern void abort(void);
+void types_test1(void);
+void types_test2(void);
+void types_test3(void);
+void types_test4(void);
+void types_test5(void);
+void types_test6(void);
+void types_test7(void);
+void types_test8(void);
+/* declared in the fortran module */
+extern myctype_t myVar;
+
+#define test(n)\
+  cchr->val##n = 1; types_test##n (); if (cchr->val##n != 2) abort ();
+
+int main(int argc, char **argv)
+{
+   myctype_t *cchr;
+   asm("":"=r"(cchr):"0"(&myVar));
+   test(1);
+   test(2);
+   test(3);
+   test(4);
+   test(5);
+   test(6);
+   cchr->val7 = 0; types_test7 (); if (cchr->val7 != 1) abort ();
+   /*cchr->val8 = 0; types_test8 (); if (cchr->val8 != 'a') abort ();*/
+   return 0;
+}
+
Index: testsuite/gfortran.dg/lto/bind_c-5_1.c
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-5_1.c	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-5_1.c	(revision 0)
@@ -0,0 +1,31 @@
+#include <stdlib.h>
+/* declared in the fortran module */
+extern int (*myVar) (int);
+extern float (*myVar2) (float);
+void types_test(void);
+
+
+extern void abort(void);
+
+int main(int argc, char **argv)
+{
+   int (**myptr) (int);
+   float (**myptr2) (float);
+   asm("":"=r"(myptr):"0"(&myVar));
+   asm("":"=r"(myptr2):"0"(&myVar2));
+   *myptr = (int (*) (int)) (size_t) (void *)1;
+   *myptr2 = (float (*) (float)) (size_t) (void *)2;
+   types_test();
+   if (*myptr != (int (*) (int)) (size_t) (void *)2)
+	abort ();
+   if (*myptr2 != (float (*) (float)) (size_t) (void *)2)
+	abort ();
+   *myptr2 = (float (*) (float)) (size_t) (void *)3;
+   types_test();
+   if (*myptr != (int (*) (int)) (size_t) (void *)3)
+	abort ();
+   if (*myptr2 != (float (*) (float)) (size_t) (void *)3)
+	abort ();
+   return 0;
+}
+
Index: testsuite/gfortran.dg/lto/bind_c-2_0.f90
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-2_0.f90	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-2_0.f90	(revision 0)
@@ -0,0 +1,21 @@
+! { dg-lto-do run }
+! { dg-lto-options {{ -O3 -flto }} }
+! This testcase will abort if C_PTR is not interoperable with both int *
+! and float *
+module lto_type_merge_test
+  use, intrinsic :: iso_c_binding
+  implicit none
+
+  type, bind(c) :: MYFTYPE_1
+     integer(c_signed_char) :: chr
+     integer(c_signed_char) :: chrb
+  end type MYFTYPE_1
+
+  type(myftype_1), bind(c, name="myVar") :: myVar
+
+contains
+  subroutine types_test() bind(c)
+    myVar%chr = myVar%chrb
+  end subroutine types_test
+end module lto_type_merge_test
+
Index: testsuite/gfortran.dg/lto/bind_c-3_0.f90
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-3_0.f90	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-3_0.f90	(revision 0)
@@ -0,0 +1,91 @@
+! { dg-lto-do run }
+! { dg-lto-options {{ -O3 -flto }} }
+! This testcase will abort if integer types are not interoperable.
+module lto_type_merge_test
+  use, intrinsic :: iso_c_binding
+  implicit none
+
+  type, bind(c) :: MYFTYPE_1
+    integer(c_int) :: val_int
+    integer(c_short) :: val_short
+    integer(c_long) :: val_long
+    integer(c_long_long) :: val_long_long
+    integer(c_size_t) :: val_size_t
+    integer(c_int8_t) :: val_int8_t
+    integer(c_int16_t) :: val_int16_t
+    integer(c_int32_t) :: val_int32_t
+    integer(c_int64_t) :: val_int64_t
+    integer(c_int_least8_t) :: val_intleast_8_t
+    integer(c_int_least16_t) :: val_intleast_16_t
+    integer(c_int_least32_t) :: val_intleast_32_t
+    integer(c_int_least64_t) :: val_intleast_64_t
+    integer(c_int_fast8_t) :: val_intfast_8_t
+    integer(c_int_fast16_t) :: val_intfast_16_t
+    integer(c_int_fast32_t) :: val_intfast_32_t
+    integer(c_int_fast64_t) :: val_intfast_64_t
+    integer(c_intmax_t) :: val_intmax_t
+    integer(c_intptr_t) :: val_intptr_t
+  end type MYFTYPE_1
+
+  type(myftype_1), bind(c, name="myVar") :: myVar
+
+contains
+  subroutine types_test1() bind(c)
+    myVar%val_int = 2
+  end subroutine types_test1
+  subroutine types_test2() bind(c)
+    myVar%val_short = 2
+  end subroutine types_test2
+  subroutine types_test3() bind(c)
+    myVar%val_long = 2
+  end subroutine types_test3
+  subroutine types_test4() bind(c)
+    myVar%val_long_long = 2
+  end subroutine types_test4
+  subroutine types_test5() bind(c)
+    myVar%val_size_t = 2
+  end subroutine types_test5
+  subroutine types_test6() bind(c)
+    myVar%val_int8_t = 2
+  end subroutine types_test6
+  subroutine types_test7() bind(c)
+    myVar%val_int16_t = 2
+  end subroutine types_test7
+  subroutine types_test8() bind(c)
+    myVar%val_int32_t = 2
+  end subroutine types_test8
+  subroutine types_test9() bind(c)
+    myVar%val_int64_t = 2
+  end subroutine types_test9
+  subroutine types_test10() bind(c)
+    myVar%val_intleast_8_t = 2
+  end subroutine types_test10
+  subroutine types_test11() bind(c)
+    myVar%val_intleast_16_t = 2
+  end subroutine types_test11
+  subroutine types_test12() bind(c)
+    myVar%val_intleast_32_t = 2
+  end subroutine types_test12
+  subroutine types_test13() bind(c)
+    myVar%val_intleast_64_t = 2
+  end subroutine types_test13
+  subroutine types_test14() bind(c)
+    myVar%val_intfast_8_t = 2
+  end subroutine types_test14
+  subroutine types_test15() bind(c)
+    myVar%val_intfast_16_t = 2
+  end subroutine types_test15
+  subroutine types_test16() bind(c)
+    myVar%val_intfast_32_t = 2
+  end subroutine types_test16
+  subroutine types_test17() bind(c)
+    myVar%val_intfast_64_t = 2
+  end subroutine types_test17
+  subroutine types_test18() bind(c)
+    myVar%val_intmax_t = 2
+  end subroutine types_test18
+  subroutine types_test19() bind(c)
+    myVar%val_intptr_t = 2
+  end subroutine types_test19
+end module lto_type_merge_test
+
Index: testsuite/gfortran.dg/lto/bind_c-4_0.f90
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-4_0.f90	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-4_0.f90	(revision 0)
@@ -0,0 +1,48 @@
+! { dg-lto-do run }
+! { dg-lto-options {{ -O3 -flto }} }
+! This testcase will abort if real/complex/boolean/character types are not interoperable
+module lto_type_merge_test
+  use, intrinsic :: iso_c_binding
+  implicit none
+
+  type, bind(c) :: MYFTYPE_1
+    real(c_float) :: val_1
+    real(c_double) :: val_2
+    real(c_long_double) :: val_3
+    complex(c_float_complex) :: val_4
+    complex(c_double_complex) :: val_5
+    complex(c_long_double_complex) :: val_6
+    logical(c_bool) :: val_7
+    !FIXME: Fortran define c_char as array of size 1.
+    !character(c_char) :: val_8
+  end type MYFTYPE_1
+
+  type(myftype_1), bind(c, name="myVar") :: myVar
+
+contains
+  subroutine types_test1() bind(c)
+    myVar%val_1 = 2
+  end subroutine types_test1
+  subroutine types_test2() bind(c)
+    myVar%val_2 = 2
+  end subroutine types_test2
+  subroutine types_test3() bind(c)
+    myVar%val_3 = 2
+  end subroutine types_test3
+  subroutine types_test4() bind(c)
+    myVar%val_4 = 2
+  end subroutine types_test4
+  subroutine types_test5() bind(c)
+    myVar%val_5 = 2
+  end subroutine types_test5
+  subroutine types_test6() bind(c)
+    myVar%val_6 = 2
+  end subroutine types_test6
+  subroutine types_test7() bind(c)
+    myVar%val_7 = myVar%val_7 .or. .not. myVar%val_7
+  end subroutine types_test7
+  !subroutine types_test8() bind(c)
+    !myVar%val_8 = "a"
+  !end subroutine types_test8
+end module lto_type_merge_test
+
Index: testsuite/gfortran.dg/lto/bind_c-5_0.f90
===================================================================
--- testsuite/gfortran.dg/lto/bind_c-5_0.f90	(revision 0)
+++ testsuite/gfortran.dg/lto/bind_c-5_0.f90	(revision 0)
@@ -0,0 +1,17 @@
+! { dg-lto-do run }
+! { dg-lto-options {{ -O3 -flto }} }
+! This testcase will abort if C_FUNPTR is not interoperable with both int *
+! and float *
+module lto_type_merge_test
+  use, intrinsic :: iso_c_binding
+  implicit none
+
+  type(c_funptr), bind(c, name="myVar") :: myVar
+  type(c_funptr), bind(c, name="myVar2") :: myVar2
+
+contains
+  subroutine types_test() bind(c)
+    myVar = myVar2
+  end subroutine types_test
+end module lto_type_merge_test
+
Index: lto/lto.c
===================================================================
--- lto/lto.c	(revision 228625)
+++ lto/lto.c	(working copy)
@@ -288,6 +288,7 @@ static hashval_t
 hash_canonical_type (tree type)
 {
   inchash::hash hstate;
+  enum tree_code code;
 
   /* We compute alias sets only for types that needs them.
      Be sure we do not recurse to something else as we can not hash incomplete
@@ -299,7 +300,8 @@ hash_canonical_type (tree type)
      smaller sets; when searching for existing matching types to merge,
      only existing types having the same features as the new type will be
      checked.  */
-  hstate.add_int (tree_code_for_canonical_type_merging (TREE_CODE (type)));
+  code = tree_code_for_canonical_type_merging (TREE_CODE (type));
+  hstate.add_int (code);
   hstate.add_int (TYPE_MODE (type));
 
   /* Incorporate common features of numerical types.  */
@@ -309,8 +311,9 @@ hash_canonical_type (tree type)
       || TREE_CODE (type) == OFFSET_TYPE
       || POINTER_TYPE_P (type))
     {
-      hstate.add_int (TYPE_UNSIGNED (type));
       hstate.add_int (TYPE_PRECISION (type));
+      if (!type_with_interoperable_signedness (type))
+        hstate.add_int (TYPE_UNSIGNED (type));
     }
 
   if (VECTOR_TYPE_P (type))
Index: tree.c
===================================================================
--- tree.c	(revision 228625)
+++ tree.c	(working copy)
@@ -13012,6 +13012,23 @@ verify_type_variant (const_tree t, tree
    back to pointer-comparison of TYPE_CANONICAL for aggregates
    for example.  */
 
+/* Return true if TYPE_UNSIGNED of TYPE should be ignored for canonical
+   type calculation because we need to allow inter-operability between signed
+   and unsigned variants.  */
+
+bool
+type_with_interoperable_signedness (const_tree type)
+{
+  /* Fortran standard require C_SIGNED_CHAR to be interoperable with both
+     signed char and unsigned char.  Similarly fortran FE builds
+     C_SIZE_T as signed type, while C defines it unsigned.  */
+
+  return tree_code_for_canonical_type_merging (TREE_CODE (type))
+	   == INTEGER_TYPE
+         && (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node)
+	     || TYPE_PRECISION (type) == TYPE_PRECISION (size_type_node));
+}
+
 /* Return true iff T1 and T2 are structurally identical for what
    TBAA is concerned.  
    This function is used both by lto.c canonical type merging and by the
@@ -13062,8 +13079,8 @@ gimple_canonical_types_compatible_p (con
     return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
 
   /* Can't be the same type if the types don't have the same code.  */
-  if (tree_code_for_canonical_type_merging (TREE_CODE (t1))
-      != tree_code_for_canonical_type_merging (TREE_CODE (t2)))
+  enum tree_code code = tree_code_for_canonical_type_merging (TREE_CODE (t1));
+  if (code != tree_code_for_canonical_type_merging (TREE_CODE (t2)))
     return false;
 
   /* Qualifiers do not matter for canonical type comparison purposes.  */
@@ -13086,9 +13103,14 @@ gimple_canonical_types_compatible_p (con
       || TREE_CODE (t1) == OFFSET_TYPE
       || POINTER_TYPE_P (t1))
     {
-      /* Can't be the same type if they have different sign or precision.  */
-      if (TYPE_PRECISION (t1) != TYPE_PRECISION (t2)
-	  || TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2))
+      /* Can't be the same type if they have different recision.  */
+      if (TYPE_PRECISION (t1) != TYPE_PRECISION (t2))
+	return false;
+
+      /* In some cases the signed and unsigned types are required to be
+	 inter-operable.  */
+      if (TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2)
+	  && !type_with_interoperable_signedness (t1))
 	return false;
 
       /* Fortran's C_SIGNED_CHAR is !TYPE_STRING_FLAG but needs to be
Index: tree.h
===================================================================
--- tree.h	(revision 228625)
+++ tree.h	(working copy)
@@ -4609,6 +4609,7 @@ extern int tree_map_base_marked_p (const
 extern void DEBUG_FUNCTION verify_type (const_tree t);
 extern bool gimple_canonical_types_compatible_p (const_tree, const_tree,
 						 bool trust_type_canonical = true);
+extern bool type_with_interoperable_signedness (const_tree);
 /* Return simplified tree code of type that is used for canonical type merging.  */
 inline enum tree_code
 tree_code_for_canonical_type_merging (enum tree_code code)

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-10-12  7:10 ` Jan Hubicka
@ 2015-10-12  7:41   ` Richard Biener
  0 siblings, 0 replies; 35+ messages in thread
From: Richard Biener @ 2015-10-12  7:41 UTC (permalink / raw)
  To: Jan Hubicka
  Cc: Dominique d'Humières, Paul Richard Thomas, GCC Patches

On Mon, 12 Oct 2015, Jan Hubicka wrote:

> > Honza,
> > > this is a variant of patch I commited (adding the suggested predicate)
> > 
> > This caused https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67923
> 
> Hmm, strange, I do not seem to be able to reproduce this locally. Is it x86?

Can't reproduce it either.

Richard.

> /opt/gcc/_clean/gcc/testsuite/gfortran.dg/pr56015.f90:12:0: error: type mismatch in pointer plus expression
>    subroutine foo (p)
> ^
> complex double[10] *
> 
> complex double[10] * restrict
> 
> long int
> 
> _85 = p_5(D) + 32;
> 
> I suppose the complaint is about "long int".  Did you possibly revert the change
> to skip TYPE_CANONICAL testing in useless_type_conversion? That would declare
> "long int" to be the same as "unsigned long int"
> 
> Honza

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
  2015-10-11  8:09 Dominique d'Humières
@ 2015-10-12  7:10 ` Jan Hubicka
  2015-10-12  7:41   ` Richard Biener
  0 siblings, 1 reply; 35+ messages in thread
From: Jan Hubicka @ 2015-10-12  7:10 UTC (permalink / raw)
  To: Dominique d'Humières
  Cc: hubicka, rguenther, Paul Richard Thomas, GCC Patches

> Honza,
> > this is a variant of patch I commited (adding the suggested predicate)
> 
> This caused https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67923

Hmm, strange, I do not seem to be able to reproduce this locally. Is it x86?

/opt/gcc/_clean/gcc/testsuite/gfortran.dg/pr56015.f90:12:0: error: type mismatch in pointer plus expression
   subroutine foo (p)
^
complex double[10] *

complex double[10] * restrict

long int

_85 = p_5(D) + 32;

I suppose the complaint is about "long int".  Did you possibly revert the change
to skip TYPE_CANONICAL testing in useless_type_conversion? That would declare
"long int" to be the same as "unsigned long int"

Honza

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Fix more of C/fortran canonical type issues
@ 2015-10-11  8:09 Dominique d'Humières
  2015-10-12  7:10 ` Jan Hubicka
  0 siblings, 1 reply; 35+ messages in thread
From: Dominique d'Humières @ 2015-10-11  8:09 UTC (permalink / raw)
  To: hubicka; +Cc: rguenther, Paul Richard Thomas, GCC Patches

Honza,
> this is a variant of patch I commited (adding the suggested predicate)

This caused https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67923

Probably related pr66238 and pr66762.

TIA

Dominique

^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2015-10-12  7:41 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-08  1:23 Fix more of C/fortran canonical type issues Jan Hubicka
2015-06-08  5:45 ` Jan Hubicka
2015-06-08  7:25   ` Jan Hubicka
2015-06-08 13:43     ` Richard Biener
2015-06-08 14:07       ` Joseph Myers
2015-06-08 14:32         ` Richard Biener
2015-06-08 14:44           ` Joseph Myers
2015-06-08 14:52             ` Jan Hubicka
2015-06-08 14:54               ` Richard Biener
2015-06-08 15:11                 ` Jan Hubicka
2015-06-08 15:32                   ` Fortran's C_CHAR type Jan Hubicka
2015-06-10 11:50                     ` Mikael Morin
2015-06-10 14:55                       ` Jan Hubicka
2015-06-10 16:37                         ` Mikael Morin
2015-06-11 18:19                           ` Jan Hubicka
2015-06-09  9:50                   ` Fix more of C/fortran canonical type issues Richard Biener
2015-06-09 17:24                     ` Jan Hubicka
2015-06-11 17:58                       ` Jan Hubicka
2015-06-22  7:25                       ` Jan Hubicka
2015-06-22 15:09                         ` Richard Biener
2015-06-22 16:17                           ` Jan Hubicka
2015-06-08 15:08       ` Jan Hubicka
2015-06-08 16:54         ` Joseph Myers
2015-06-08 16:57           ` Jan Hubicka
2015-06-08 17:03             ` Joseph Myers
2015-06-08 22:06               ` Jan Hubicka
2015-06-08 23:01       ` Jan Hubicka
2015-10-08  3:47     ` Jan Hubicka
2015-10-08  7:44       ` Richard Biener
2015-10-08 16:17         ` Jan Hubicka
2015-10-10 19:45         ` Jan Hubicka
2015-06-08 13:37   ` Richard Biener
2015-10-11  8:09 Dominique d'Humières
2015-10-12  7:10 ` Jan Hubicka
2015-10-12  7:41   ` Richard Biener

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).