This fixes PR64313 - the match-and-simplify machinery has a hard
time re-doing the "magic" trick of re-using builtins in the matched IL
and thus fails to generate calls to builtins that are not marked
as builtin_decl_implicit_p.

The following patch fixes this by remembering whether the user
has declared a builtin in a new per-builtin flag and recognizing
explicit uses (in ADDR_EXPRs which catches calls and address-takens)
during gimplification.  For explicitely used builtins the compiler
can generate them implicitely (well, not 100% true - the semantics
do not have to agree unless the identifier is reserved, sth we can't
check easily).

This is an approach that follows that of the STPCPY case right next
to the place this patch patches the frontends, just a little bit less
aggressive in requiring an explicit use of the builtin.

No attempt is done to preserve (and merge) this through LTO - builtins
are streamed by simply streaming DECL_FUNCTION_CODE which makes doing
this a bit hard(er).  The gcc.dg/torture/builtin-explog-1.c testcase
was failing on bare-metal targets and is fixed with the patch below
already during early optimizations.

An alternative to fix the regression is to remove the very few
builtin simplification patterns from match.pd and/or restore
the folding code in builtins.c.  The issue would then need to
be revisited during the next stage1 (where I can look into how to
deal with this with LTO - but 'implicit_p' is also not transitioned
properly if you combine for example a C89 input and C99 input - lto1
defaults all of flag_isoc{94,99,11} to zero and uses the C family
builtins.def way of initialization, so the LTO issue is certainly
pre-existing).

Ok for trunk now?

Bootstrap and regtest is running on x86_64-unknown-linux-gnu.

Thanks,
Richard.

2015-01-19  Richard Biener  <rguent...@suse.de>

        PR middle-end/64313
        * tree-core.h (builtin_info, builtin_info_type): Turn from
        an object with two arrays into an array of an object with
        decl and two flags, implicit_p and declared_p.
        * tree.h (builtin_decl_explicit, builtin_decl_implicit,
        set_builtin_decl, set_builtin_decl_implicit_p,
        builtin_decl_explicit_p, builtin_decl_implicit_p): Adjust.
        (set_builtin_decl_declared_p, builtin_decl_declared_p): New functions.
        * builtins.c (builtin_info): Adjust.
        * gimplify.c (gimplify_addr_expr): References to builtins
        that have been declared by the user makes them eligible for
        use by the compiler.  Call set_builtin_decl_implicit_p on them.

        c/
        * c-decl.c (merge_decls): Call set_builtin_decl_declared_p
        for builtins the user declared correctly.

        cp/
        * decl.c (duplicate_decls): Call set_builtin_decl_declared_p
        for builtins the user declared correctly.

Index: gcc/tree.h
===================================================================
*** gcc/tree.h.orig     2015-01-19 14:51:26.175142267 +0100
--- gcc/tree.h  2015-01-19 15:11:48.602099942 +0100
*************** builtin_decl_explicit (enum built_in_fun
*** 4606,4612 ****
  {
    gcc_checking_assert (BUILTIN_VALID_P (fncode));
  
!   return builtin_info.decl[(size_t)fncode];
  }
  
  /* Return the tree node for an implicit builtin function or NULL.  */
--- 4606,4612 ----
  {
    gcc_checking_assert (BUILTIN_VALID_P (fncode));
  
!   return builtin_info[(size_t)fncode].decl;
  }
  
  /* Return the tree node for an implicit builtin function or NULL.  */
*************** builtin_decl_implicit (enum built_in_fun
*** 4616,4625 ****
    size_t uns_fncode = (size_t)fncode;
    gcc_checking_assert (BUILTIN_VALID_P (fncode));
  
!   if (!builtin_info.implicit_p[uns_fncode])
      return NULL_TREE;
  
!   return builtin_info.decl[uns_fncode];
  }
  
  /* Set explicit builtin function nodes and whether it is an implicit
--- 4616,4625 ----
    size_t uns_fncode = (size_t)fncode;
    gcc_checking_assert (BUILTIN_VALID_P (fncode));
  
!   if (!builtin_info[uns_fncode].implicit_p)
      return NULL_TREE;
  
!   return builtin_info[uns_fncode].decl;
  }
  
  /* Set explicit builtin function nodes and whether it is an implicit
*************** set_builtin_decl (enum built_in_function
*** 4633,4640 ****
    gcc_checking_assert (BUILTIN_VALID_P (fncode)
                       && (decl != NULL_TREE || !implicit_p));
  
!   builtin_info.decl[ufncode] = decl;
!   builtin_info.implicit_p[ufncode] = implicit_p;
  }
  
  /* Set the implicit flag for a builtin function.  */
--- 4633,4641 ----
    gcc_checking_assert (BUILTIN_VALID_P (fncode)
                       && (decl != NULL_TREE || !implicit_p));
  
!   builtin_info[ufncode].decl = decl;
!   builtin_info[ufncode].implicit_p = implicit_p;
!   builtin_info[ufncode].declared_p = false;
  }
  
  /* Set the implicit flag for a builtin function.  */
*************** set_builtin_decl_implicit_p (enum built_
*** 4645,4653 ****
    size_t uns_fncode = (size_t)fncode;
  
    gcc_checking_assert (BUILTIN_VALID_P (fncode)
!                      && builtin_info.decl[uns_fncode] != NULL_TREE);
  
!   builtin_info.implicit_p[uns_fncode] = implicit_p;
  }
  
  /* Return whether the standard builtin function can be used as an explicit
--- 4646,4667 ----
    size_t uns_fncode = (size_t)fncode;
  
    gcc_checking_assert (BUILTIN_VALID_P (fncode)
!                      && builtin_info[uns_fncode].decl != NULL_TREE);
  
!   builtin_info[uns_fncode].implicit_p = implicit_p;
! }
! 
! /* Set the declared flag for a builtin function.  */
! 
! static inline void
! set_builtin_decl_declared_p (enum built_in_function fncode, bool declared_p)
! {
!   size_t uns_fncode = (size_t)fncode;
! 
!   gcc_checking_assert (BUILTIN_VALID_P (fncode)
!                      && builtin_info[uns_fncode].decl != NULL_TREE);
! 
!   builtin_info[uns_fncode].declared_p = declared_p;
  }
  
  /* Return whether the standard builtin function can be used as an explicit
*************** static inline bool
*** 4657,4663 ****
  builtin_decl_explicit_p (enum built_in_function fncode)
  {
    gcc_checking_assert (BUILTIN_VALID_P (fncode));
!   return (builtin_info.decl[(size_t)fncode] != NULL_TREE);
  }
  
  /* Return whether the standard builtin function can be used implicitly.  */
--- 4671,4677 ----
  builtin_decl_explicit_p (enum built_in_function fncode)
  {
    gcc_checking_assert (BUILTIN_VALID_P (fncode));
!   return (builtin_info[(size_t)fncode].decl != NULL_TREE);
  }
  
  /* Return whether the standard builtin function can be used implicitly.  */
*************** builtin_decl_implicit_p (enum built_in_f
*** 4668,4675 ****
    size_t uns_fncode = (size_t)fncode;
  
    gcc_checking_assert (BUILTIN_VALID_P (fncode));
!   return (builtin_info.decl[uns_fncode] != NULL_TREE
!         && builtin_info.implicit_p[uns_fncode]);
  }
  
  /* Return true if T (assumed to be a DECL) is a global variable.
--- 4682,4701 ----
    size_t uns_fncode = (size_t)fncode;
  
    gcc_checking_assert (BUILTIN_VALID_P (fncode));
!   return (builtin_info[uns_fncode].decl != NULL_TREE
!         && builtin_info[uns_fncode].implicit_p);
! }
! 
! /* Return whether the standard builtin function was declared.  */
! 
! static inline bool
! builtin_decl_declared_p (enum built_in_function fncode)
! {
!   size_t uns_fncode = (size_t)fncode;
! 
!   gcc_checking_assert (BUILTIN_VALID_P (fncode));
!   return (builtin_info[uns_fncode].decl != NULL_TREE
!         && builtin_info[uns_fncode].declared_p);
  }
  
  /* Return true if T (assumed to be a DECL) is a global variable.
Index: gcc/tree-core.h
===================================================================
*** gcc/tree-core.h.orig        2015-01-19 14:51:26.175142267 +0100
--- gcc/tree-core.h     2015-01-19 15:10:01.111103664 +0100
*************** struct const_call_expr_arg_iterator {
*** 1853,1863 ****
  };
  
  /* The builtin_info structure holds the FUNCTION_DECL of the standard builtin
!    function, and a flag that says if the function is available implicitly, or
!    whether the user has to code explicit calls to __builtin_<xxx>.  */
  struct GTY(()) builtin_info_type {
!   tree decl[(int)END_BUILTINS];
!   bool implicit_p[(int)END_BUILTINS];
  };
  
  
--- 1853,1866 ----
  };
  
  /* The builtin_info structure holds the FUNCTION_DECL of the standard builtin
!    function, and flags.  */
  struct GTY(()) builtin_info_type {
!   tree decl;
!   /* Whether the user can use <xxx> instead of explicitely using calls
!      to __builtin_<xxx>.  */
!   unsigned implicit_p : 1;
!   /* Whether the user has provided a declaration of <xxx>.  */
!   unsigned declared_p : 1;
  };
  
  
*************** extern int tree_node_sizes[];
*** 1913,1919 ****
  extern bool in_gimple_form;
  
  /* Functional interface to the builtin functions.  */
! extern GTY(()) builtin_info_type builtin_info;
  
  /* If nonzero, an upper limit on alignment of structure fields, in bits,  */
  extern unsigned int maximum_field_alignment;
--- 1916,1922 ----
  extern bool in_gimple_form;
  
  /* Functional interface to the builtin functions.  */
! extern GTY(()) builtin_info_type builtin_info[(int)END_BUILTINS];
  
  /* If nonzero, an upper limit on alignment of structure fields, in bits,  */
  extern unsigned int maximum_field_alignment;
Index: gcc/c/c-decl.c
===================================================================
*** gcc/c/c-decl.c.orig 2015-01-19 14:51:40.378141775 +0100
--- gcc/c/c-decl.c      2015-01-19 14:51:46.891141549 +0100
*************** merge_decls (tree newdecl, tree olddecl,
*** 2582,2587 ****
--- 2582,2589 ----
                        set_builtin_decl_implicit_p (fncode, true);
                      break;
                    default:
+                     if (builtin_decl_explicit_p (fncode))
+                       set_builtin_decl_declared_p (fncode, true);
                      break;
                    }
                }
Index: gcc/cp/decl.c
===================================================================
*** gcc/cp/decl.c.orig  2015-01-16 09:40:55.145761684 +0100
--- gcc/cp/decl.c       2015-01-19 14:58:13.496128164 +0100
*************** duplicate_decls (tree newdecl, tree oldd
*** 2309,2314 ****
--- 2309,2316 ----
                    set_builtin_decl_implicit_p (fncode, true);
                  break;
                default:
+                 if (builtin_decl_explicit_p (fncode))
+                   set_builtin_decl_declared_p (fncode, true);
                  break;
                }
            }
Index: gcc/gimplify.c
===================================================================
*** gcc/gimplify.c.orig 2015-01-16 09:40:55.904761658 +0100
--- gcc/gimplify.c      2015-01-19 14:56:10.403132426 +0100
*************** gimplify_addr_expr (tree *expr_p, gimple
*** 4956,4961 ****
--- 4956,4969 ----
        break;
  
      default:
+       /* If we see a call to a declared builtin or see its address
+        being taken (we can unify those cases here) then we can mark
+        the builtin for implicit generation by GCC.  */
+       if (TREE_CODE (op0) == FUNCTION_DECL
+         && DECL_BUILT_IN_CLASS (op0) == BUILT_IN_NORMAL
+         && builtin_decl_declared_p (DECL_FUNCTION_CODE (op0)))
+       set_builtin_decl_implicit_p (DECL_FUNCTION_CODE (op0), true);
+ 
        /* We use fb_either here because the C frontend sometimes takes
         the address of a call that returns a struct; see
         gcc.dg/c99-array-lval-1.c.  The gimplifier will correctly make
Index: gcc/builtins.c
===================================================================
*** gcc/builtins.c.orig 2015-01-16 14:13:07.679196199 +0100
--- gcc/builtins.c      2015-01-19 15:12:39.633098175 +0100
*************** const char * built_in_names[(int) END_BU
*** 105,113 ****
  };
  #undef DEF_BUILTIN
  
! /* Setup an array of _DECL trees, make sure each element is
     initialized to NULL_TREE.  */
! builtin_info_type builtin_info;
  
  /* Non-zero if __builtin_constant_p should be folded right away.  */
  bool force_folding_builtin_constant_p;
--- 105,113 ----
  };
  #undef DEF_BUILTIN
  
! /* Setup an array of builtin_info_type, make sure each element decl is
     initialized to NULL_TREE.  */
! builtin_info_type builtin_info[(int)END_BUILTINS];
  
  /* Non-zero if __builtin_constant_p should be folded right away.  */
  bool force_folding_builtin_constant_p;

Reply via email to