Only now we get a testcase using __builtin_va_arg_pack() and friends
two levels deep which doesn't work since we (reliably) perform inlining
bottom-up.

The following fixes the bug by simply not replacing the builtins
with garbage in case the caller wasn't passing args but an argument
pack itself.

Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk.

Richard.

2017-03-21  Richard Biener  <rguent...@suse.de>

        PR tree-optimization/80122
        * tree-inline.c (copy_bb): Do not expans va-arg packs or
        va_arg_pack_len when the inlined call stmt requires pack
        expansion itself.
        * tree-inline.h (struct copy_body_data): Make call_stmt a gcall *.

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

Index: gcc/tree-inline.c
===================================================================
*** gcc/tree-inline.c   (revision 246277)
--- gcc/tree-inline.c   (working copy)
*************** copy_bb (copy_body_data *id, basic_block
*** 1860,1866 ****
          call_stmt = dyn_cast <gcall *> (stmt);
          if (call_stmt
              && gimple_call_va_arg_pack_p (call_stmt)
!             && id->call_stmt)
            {
              /* __builtin_va_arg_pack () should be replaced by
                 all arguments corresponding to ... in the caller.  */
--- 1860,1867 ----
          call_stmt = dyn_cast <gcall *> (stmt);
          if (call_stmt
              && gimple_call_va_arg_pack_p (call_stmt)
!             && id->call_stmt
!             && ! gimple_call_va_arg_pack_p (id->call_stmt))
            {
              /* __builtin_va_arg_pack () should be replaced by
                 all arguments corresponding to ... in the caller.  */
*************** copy_bb (copy_body_data *id, basic_block
*** 1940,1946 ****
                   && id->call_stmt
                   && (decl = gimple_call_fndecl (stmt))
                   && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
!                  && DECL_FUNCTION_CODE (decl) == BUILT_IN_VA_ARG_PACK_LEN)
            {
              /* __builtin_va_arg_pack_len () should be replaced by
                 the number of anonymous arguments.  */
--- 1941,1948 ----
                   && id->call_stmt
                   && (decl = gimple_call_fndecl (stmt))
                   && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
!                  && DECL_FUNCTION_CODE (decl) == BUILT_IN_VA_ARG_PACK_LEN
!                  && ! gimple_call_va_arg_pack_p (id->call_stmt))
            {
              /* __builtin_va_arg_pack_len () should be replaced by
                 the number of anonymous arguments.  */
*************** expand_call_inline (basic_block bb, gimp
*** 4584,4590 ****
    /* Record the function we are about to inline.  */
    id->src_fn = fn;
    id->src_cfun = DECL_STRUCT_FUNCTION (fn);
!   id->call_stmt = stmt;
  
    /* If the src function contains an IFN_VA_ARG, then so will the dst
       function after inlining.  Likewise for IFN_GOMP_USE_SIMT.  */
--- 4586,4592 ----
    /* Record the function we are about to inline.  */
    id->src_fn = fn;
    id->src_cfun = DECL_STRUCT_FUNCTION (fn);
!   id->call_stmt = call_stmt;
  
    /* If the src function contains an IFN_VA_ARG, then so will the dst
       function after inlining.  Likewise for IFN_GOMP_USE_SIMT.  */
Index: gcc/tree-inline.h
===================================================================
*** gcc/tree-inline.h   (revision 246277)
--- gcc/tree-inline.h   (working copy)
*************** struct copy_body_data
*** 81,87 ****
  
    /* GIMPLE_CALL if va arg parameter packs should be expanded or NULL
       is not.  */
!   gimple *call_stmt;
  
    /* Exception landing pad the inlined call lies in.  */
    int eh_lp_nr;
--- 81,87 ----
  
    /* GIMPLE_CALL if va arg parameter packs should be expanded or NULL
       is not.  */
!   gcall *call_stmt;
  
    /* Exception landing pad the inlined call lies in.  */
    int eh_lp_nr;
Index: gcc/testsuite/gcc.dg/torture/pr80122.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr80122.c      (nonexistent)
--- gcc/testsuite/gcc.dg/torture/pr80122.c      (working copy)
***************
*** 0 ****
--- 1,52 ----
+ /* { dg-do run } */
+ 
+ #define __GNU_ALWAYS_INLINE inline __attribute__(( __always_inline__))
+ 
+ #define DEVT_ALL    0
+ 
+ #define CMD_ABI_DEVICES 100
+ 
+ static __GNU_ALWAYS_INLINE int
+ send_msg_to_gm_w_dev_t(int msg_type, unsigned int dev_msg_type,
+                      int devt, ...)
+ {
+   char s[256];
+   int nArgs = __builtin_va_arg_pack_len();
+   if (nArgs != 2)
+     __builtin_abort ();
+   __builtin_sprintf (s, "%d", __builtin_va_arg_pack ());
+   if (__builtin_strcmp (s, "99") != 0)
+     __builtin_abort ();
+   /* do something with nArgs and ... */ 
+   return 0;
+ }
+ 
+ static __GNU_ALWAYS_INLINE int
+ send_msg_to_gm(int msg_type, unsigned int dev_msg_type,
+              ...)
+ {
+   int nArgs = __builtin_va_arg_pack_len();
+   if (nArgs != 2)
+     __builtin_abort ();
+   return send_msg_to_gm_w_dev_t(msg_type, dev_msg_type,
+                               DEVT_ALL, __builtin_va_arg_pack()); 
+ }
+ 
+ static __GNU_ALWAYS_INLINE int
+ send_enable(unsigned int dev_msg_type, ...)
+ {
+   int nArgs = __builtin_va_arg_pack_len();
+   if (nArgs != 2)
+     __builtin_abort ();
+   return send_msg_to_gm(CMD_ABI_DEVICES, dev_msg_type,  
__builtin_va_arg_pack());
+ }
+ 
+ int 
+ main(void)
+ {
+   int mode = 99;
+ 
+   send_enable(1, mode, sizeof(mode));
+ 
+   return 0;
+ }

Reply via email to