The following attempts to provide a fix for PR59990 - the fact
that we shouldn't use FP modes to implement memcpy in the middle-end.
It consolidates the ubsan case for BOOLEAN and ENUMERAL types which
are desirable to avoid anyway.

Bootstrapped and tested on x86_64-unknown-linux-gnu.

Does this look reasonable?

Thanks,
Richard.

2014-01-30  Richard Biener  <rguent...@suse.de>

        PR middle-end/59990
        * builtins.c (fold_builtin_memory_op): Make sure to not
        use a floating-point mode or a boolean or enumeral type for
        the copy operation.

        * gcc.dg/torture/pr59990.c: New testcase.

Index: gcc/builtins.c
===================================================================
*** gcc/builtins.c      (revision 207306)
--- gcc/builtins.c      (working copy)
*************** fold_builtin_memory_op (location_t loc,
*** 8851,8856 ****
--- 8851,8862 ----
        if (!POINTER_TYPE_P (TREE_TYPE (src))
          || !POINTER_TYPE_P (TREE_TYPE (dest)))
        return NULL_TREE;
+       /* In the following try to find a type that is most natural to be
+        used for the memcpy source and destination and that allows
+        the most optimization when memcpy is turned into a plain assignment
+        using that type.  In theory we could always use a char[len] type
+        but that only gains us that the destination and source possibly
+        no longer will have their address taken.  */
        /* As we fold (void *)(p + CST) to (void *)p + CST undo this here.  */
        if (TREE_CODE (src) == POINTER_PLUS_EXPR)
        {
*************** fold_builtin_memory_op (location_t loc,
*** 8886,8891 ****
--- 8892,8932 ----
          || TREE_ADDRESSABLE (desttype))
        return NULL_TREE;
  
+       /* Make sure we are not copying using a floating-point mode or
+          a type whose size possibly does not match its precision.  */
+       if (FLOAT_MODE_P (TYPE_MODE (desttype))
+         || TREE_CODE (desttype) == BOOLEAN_TYPE
+         || TREE_CODE (desttype) == ENUMERAL_TYPE)
+       {
+         /* A more suitable int_mode_for_mode would return a vector
+            integer mode for a vector float mode or a integer complex
+            mode for a float complex mode if there isn't a regular
+            integer mode covering the mode of desttype.  */
+         enum machine_mode mode = int_mode_for_mode (TYPE_MODE (desttype));
+         if (mode == BLKmode)
+           desttype = NULL_TREE;
+         else
+           desttype = build_nonstandard_integer_type (GET_MODE_BITSIZE (mode),
+                                                      1);
+       }
+       if (FLOAT_MODE_P (TYPE_MODE (srctype))
+         || TREE_CODE (srctype) == BOOLEAN_TYPE
+         || TREE_CODE (srctype) == ENUMERAL_TYPE)
+       {
+         enum machine_mode mode = int_mode_for_mode (TYPE_MODE (srctype));
+         if (mode == BLKmode)
+           srctype = NULL_TREE;
+         else
+           srctype = build_nonstandard_integer_type (GET_MODE_BITSIZE (mode),
+                                                     1);
+       }
+       if (!srctype)
+       srctype = desttype;
+       if (!desttype)
+       desttype = srctype;
+       if (!srctype)
+       return NULL_TREE;
+ 
        src_align = get_pointer_alignment (src);
        dest_align = get_pointer_alignment (dest);
        if (dest_align < TYPE_ALIGN (desttype)
*************** fold_builtin_memory_op (location_t loc,
*** 8899,8927 ****
        off0 = build_int_cst (build_pointer_type_for_mode (char_type_node,
                                                         ptr_mode, true), 0);
  
-       /* For -fsanitize={bool,enum} make sure the load isn't performed in
-        the bool or enum type.  */
-       if (((flag_sanitize & SANITIZE_BOOL)
-          && TREE_CODE (desttype) == BOOLEAN_TYPE)
-         || ((flag_sanitize & SANITIZE_ENUM)
-             && TREE_CODE (desttype) == ENUMERAL_TYPE))
-       {
-         tree destitype
-           = lang_hooks.types.type_for_mode (TYPE_MODE (desttype),
-                                             TYPE_UNSIGNED (desttype));
-         desttype = build_aligned_type (destitype, TYPE_ALIGN (desttype));
-       }
-       if (((flag_sanitize & SANITIZE_BOOL)
-          && TREE_CODE (srctype) == BOOLEAN_TYPE)
-         || ((flag_sanitize & SANITIZE_ENUM)
-             && TREE_CODE (srctype) == ENUMERAL_TYPE))
-       {
-         tree srcitype
-           = lang_hooks.types.type_for_mode (TYPE_MODE (srctype),
-                                             TYPE_UNSIGNED (srctype));
-         srctype = build_aligned_type (srcitype, TYPE_ALIGN (srctype));
-       }
- 
        destvar = dest;
        STRIP_NOPS (destvar);
        if (TREE_CODE (destvar) == ADDR_EXPR
--- 8940,8945 ----
Index: gcc/testsuite/gcc.dg/torture/pr59990.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr59990.c      (revision 0)
--- gcc/testsuite/gcc.dg/torture/pr59990.c      (working copy)
***************
*** 0 ****
--- 1,18 ----
+ /* { dg-do run } */
+ 
+ extern void abort (void);
+ 
+ unsigned char value[4] = { 66, 9, 160, 255 };
+ 
+ int main (void)
+ {
+   volatile float f;
+   unsigned char a[4];
+ 
+   __builtin_memcpy ((void *)&f, value, 4);
+   __builtin_memcpy (a, (void *)&f, 4);
+   if (a[2] != 160)
+     abort ();
+ 
+   return 0;
+ }

Reply via email to