This reduces the compile-time for the testcase from PR12392 from
~50s to ~35s, dropping the alias-stmt walking time from 40% to around 8%.

Currently (even when -fno-devirtualize-speculatively - heh) when
looking for a must-def that specifies the dynamic type of an object
we invoke a virtual call on we skip may-defs speculatively until
we run into the function start which of course may be quite some
work to do and which is of course not acceptable.

The following limits the number of may-defs we skip.

It does not limit the number of stmts we skip as non-aliasing, thus we can
still run into large overhead cases but that would require to assign an
overall budget to the current function which isn't that trivial
because this is a helper which is called from multiple places in GCC.
Ideally the devirt machinery would record interesting must-defs in
a body walk and thus when looking for it it could find candidates
with a hashtable lookup and would only need to check whether there
is no intermediate may-def.  But as said, with the "tool" nature
of the devirt thing this is hard (but maybe speculative devirt
is really only done at IPA time and not from PRE?).

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

Honza, is this ok?  Can you check effects on devirt numbers for
the testcases you have monitored that?

Thanks,
Richard.

2016-03-23  Michael Matz  <m...@suse.de>
        Richard Biener  <rguent...@suse.de>

        PR ipa/12392
        * ipa-polymorphic-call.c (struct type_change_info): Change
        speculative to an unsigned allowing to limit the work we do.
        (MAXSPEC): New define.
        (check_stmt_for_type_change): Limit the number of may-defs
        skipped for speculative devirtualization to
        max-speculative-devirt-maydefs.
        * params.def (max-speculative-devirt-maydefs): New param.
        * doc/invoke.texi (--param max-speculative-devirt-maydefs): Document.

Index: gcc/params.def
===================================================================
*** gcc/params.def      (revision 234415)
--- gcc/params.def      (working copy)
*************** DEFPARAM (PARAM_HSA_GEN_DEBUG_STORES,
*** 1203,1208 ****
--- 1203,1214 ----
          "hsa-gen-debug-stores",
          "Level of hsa debug stores verbosity",
          0, 0, 1)
+ 
+ DEFPARAM (PARAM_MAX_SPECULATIVE_DEVIRT_MAYDEFS,
+         "max-speculative-devirt-maydefs",
+         "Maximum number of may-defs visited when devirtualizing "
+         "speculatively", 50, 0, 0)
+ 
  /*
  
  Local variables:
Index: gcc/ipa-polymorphic-call.c
===================================================================
*** gcc/ipa-polymorphic-call.c  (revision 234415)
--- gcc/ipa-polymorphic-call.c  (working copy)
*************** along with GCC; see the file COPYING3.
*** 38,43 ****
--- 38,44 ----
  #include "tree-dfa.h"
  #include "gimple-pretty-print.h"
  #include "tree-into-ssa.h"
+ #include "params.h"
  
  /* Return true when TYPE contains an polymorphic type and thus is interesting
     for devirtualization machinery.  */
*************** struct type_change_info
*** 1094,1107 ****
    tree known_current_type;
    HOST_WIDE_INT known_current_offset;
  
    /* Set to true if dynamic type change has been detected.  */
    bool type_maybe_changed;
    /* Set to true if multiple types have been encountered.  known_current_type
       must be disregarded in that case.  */
    bool multiple_types_encountered;
-   /* Set to true if we possibly missed some dynamic type changes and we should
-      consider the set to be speculative.  */
-   bool speculative;
    bool seen_unanalyzed_store;
  };
  
--- 1095,1109 ----
    tree known_current_type;
    HOST_WIDE_INT known_current_offset;
  
+   /* Set to nonzero if we possibly missed some dynamic type changes and we
+      should consider the set to be speculative.  */
+   unsigned speculative;
+ 
    /* Set to true if dynamic type change has been detected.  */
    bool type_maybe_changed;
    /* Set to true if multiple types have been encountered.  known_current_type
       must be disregarded in that case.  */
    bool multiple_types_encountered;
    bool seen_unanalyzed_store;
  };
  
*************** record_known_type (struct type_change_in
*** 1338,1343 ****
--- 1340,1353 ----
    tci->type_maybe_changed = true;
  }
  
+ 
+ /* The maximum number of may-defs we visit when looking for a must-def
+    that changes the dynamic type in check_stmt_for_type_change.  Tuned
+    after the PR12392 testcase which unlimited spends 40% time within
+    these alias walks and 8% with the following limit.  */
+ 
+ #define MAXSPEC (PARAM_VALUE (PARAM_MAX_SPECULATIVE_DEVIRT_MAYDEFS))
+ 
  /* Callback of walk_aliased_vdefs and a helper function for
     detect_type_change to check whether a particular statement may modify
     the virtual table pointer, and if possible also determine the new type of
*************** check_stmt_for_type_change (ao_ref *ao A
*** 1384,1398 ****
                                          &size, &max_size, &reverse);
            if (size != max_size || max_size == -1)
              {
!                 tci->speculative = true;
!               return false;
              }
            if (op && TREE_CODE (op) == MEM_REF)
              {
                if (!tree_fits_shwi_p (TREE_OPERAND (op, 1)))
                  {
!                     tci->speculative = true;
!                   return false;
                  }
                offset += tree_to_shwi (TREE_OPERAND (op, 1))
                          * BITS_PER_UNIT;
--- 1394,1408 ----
                                          &size, &max_size, &reverse);
            if (size != max_size || max_size == -1)
              {
!                 tci->speculative++;
!               return tci->speculative > MAXSPEC ? true : false;
              }
            if (op && TREE_CODE (op) == MEM_REF)
              {
                if (!tree_fits_shwi_p (TREE_OPERAND (op, 1)))
                  {
!                     tci->speculative++;
!                   return tci->speculative > MAXSPEC ? true : false;
                  }
                offset += tree_to_shwi (TREE_OPERAND (op, 1))
                          * BITS_PER_UNIT;
*************** check_stmt_for_type_change (ao_ref *ao A
*** 1402,1409 ****
              ;
            else
              {
!                 tci->speculative = true;
!               return false;
              }
            op = walk_ssa_copies (op);
          }
--- 1412,1419 ----
              ;
            else
              {
!                 tci->speculative++;
!               return tci->speculative > MAXSPEC ? true : false;
              }
            op = walk_ssa_copies (op);
          }
*************** check_stmt_for_type_change (ao_ref *ao A
*** 1438,1445 ****
            fprintf (dump_file, "  Function call may change dynamic type:");
          print_gimple_stmt (dump_file, stmt, 0, 0);
        }
!      tci->speculative = true;
!      return false;
     }
    /* Check for inlined virtual table store.  */
    else if (noncall_stmt_may_be_vtbl_ptr_store (stmt))
--- 1448,1455 ----
            fprintf (dump_file, "  Function call may change dynamic type:");
          print_gimple_stmt (dump_file, stmt, 0, 0);
        }
!      tci->speculative++;
!      return tci->speculative > MAXSPEC ? true : false;
     }
    /* Check for inlined virtual table store.  */
    else if (noncall_stmt_may_be_vtbl_ptr_store (stmt))
*************** check_stmt_for_type_change (ao_ref *ao A
*** 1461,1467 ****
          if (dump_file)
            fprintf (dump_file, "  Unanalyzed store may change type.\n");
          tci->seen_unanalyzed_store = true;
!         tci->speculative = true;
        }
        else
          record_known_type (tci, type, offset);
--- 1471,1477 ----
          if (dump_file)
            fprintf (dump_file, "  Unanalyzed store may change type.\n");
          tci->seen_unanalyzed_store = true;
!         tci->speculative++;
        }
        else
          record_known_type (tci, type, offset);
*************** check_stmt_for_type_change (ao_ref *ao A
*** 1471,1476 ****
--- 1481,1489 ----
      return false;
  }
  
+ #undef MAXSPEC
+ 
+ 
  /* THIS is polymorphic call context obtained from get_polymorphic_context.
     OTR_OBJECT is pointer to the instance returned by OBJ_TYPE_REF_OBJECT.
     INSTANCE is pointer to the outer instance as returned by
*************** ipa_polymorphic_call_context::get_dynami
*** 1646,1652 ****
    tci.otr_type = otr_type;
    tci.type_maybe_changed = false;
    tci.multiple_types_encountered = false;
!   tci.speculative = false;
    tci.seen_unanalyzed_store = false;
  
    walk_aliased_vdefs (&ao, gimple_vuse (stmt), check_stmt_for_type_change,
--- 1659,1665 ----
    tci.otr_type = otr_type;
    tci.type_maybe_changed = false;
    tci.multiple_types_encountered = false;
!   tci.speculative = 0;
    tci.seen_unanalyzed_store = false;
  
    walk_aliased_vdefs (&ao, gimple_vuse (stmt), check_stmt_for_type_change,
Index: gcc/doc/invoke.texi
===================================================================
*** gcc/doc/invoke.texi (revision 234415)
--- gcc/doc/invoke.texi (working copy)
*************** Enable emission of special debug stores
*** 9593,9598 ****
--- 9593,9603 ----
  then read and reported by libgomp plugin.  Generation of these stores
  is disabled by default, use @option{--param hsa-gen-debug-stores=1} to
  enable it.
+ 
+ @item max-speculative-devirt-maydefs
+ The maximum number of may-defs we analyze when looking for a must-def
+ specifying the dynamic type of an object that invokes a virtual call
+ we may be able to devirtualize speculatively.
  @end table
  @end table
  

Reply via email to