I am attaching my current (incomplete) patch to gcc for your reference.

From a71eb73bee5857440c4ff67c4c82be115e0675cb Mon Sep 17 00:00:00 2001
From: qing zhao <qinz...@gcc.gnu.org>
Date: Sat, 12 Dec 2020 00:02:28 +0100
Subject: [PATCH] First version of -ftrivial-auto-var-init

---
 gcc/common.opt            | 35 ++++++++++++++++++
 gcc/flag-types.h          | 14 ++++++++
 gcc/gimple-pretty-print.c |  2 +-
 gcc/gimplify.c            | 90 +++++++++++++++++++++++++++++++++++++++++++++++
 gcc/internal-fn.c         | 20 +++++++++++
 gcc/internal-fn.def       |  5 +++
 gcc/tree-cfg.c            |  3 ++
 gcc/tree-ssa-uninit.c     |  3 ++
 gcc/tree-ssa.c            |  5 +++
 9 files changed, 176 insertions(+), 1 deletion(-)

diff --git a/gcc/common.opt b/gcc/common.opt
index 6645539f5e5..c4c4fc28ef7 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -3053,6 +3053,41 @@ ftree-scev-cprop
 Common Report Var(flag_tree_scev_cprop) Init(1) Optimization
 Enable copy propagation of scalar-evolution information.
 
+ftrivial-auto-var-init=
+Common Joined RejectNegative Enum(auto_init_type) 
Var(flag_trivial_auto_var_init) Init(AUTO_INIT_UNINITIALIZED)
+-ftrivial-auto-var-init=[uninitialized|pattern|zero]   Add initializations to 
automatic variables.     
+
+Enum
+Name(auto_init_type) Type(enum auto_init_type) UnknownError(unrecognized 
automatic variable initialization type %qs)
+
+EnumValue
+Enum(auto_init_type) String(uninitialized) Value(AUTO_INIT_UNINITIALIZED)
+
+EnumValue
+Enum(auto_init_type) String(pattern) Value(AUTO_INIT_PATTERN)
+
+EnumValue
+Enum(auto_init_type) String(zero) Value(AUTO_INIT_ZERO)
+
+fauto-var-init-approach=
+Common Joined RejectNegative Enum(auto_init_approach) 
Var(flag_auto_init_approach) Init(AUTO_INIT_A))
+-fauto-var-init-approach=[A|B|C|D]     Choose the approach to initialize 
automatic variables.  
+
+Enum
+Name(auto_init_approach) Type(enum auto_init_approach) 
UnknownError(unrecognized automatic variable initialization approach %qs)
+
+EnumValue
+Enum(auto_init_approach) String(A) Value(AUTO_INIT_A)
+
+EnumValue
+Enum(auto_init_approach) String(B) Value(AUTO_INIT_B)
+
+EnumValue
+Enum(auto_init_approach) String(C) Value(AUTO_INIT_C)
+
+EnumValue
+Enum(auto_init_approach) String(D) Value(AUTO_INIT_D)
+
 ; -fverbose-asm causes extra commentary information to be produced in
 ; the generated assembly code (to make it more readable).  This option
 ; is generally only of use to those who actually need to read the
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index 9342bd87be3..bfd0692b82c 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -242,6 +242,20 @@ enum vect_cost_model {
   VECT_COST_MODEL_DEFAULT = 1
 };
 
+/* Automatic variable initialization type.  */
+enum auto_init_type {
+  AUTO_INIT_UNINITIALIZED = 0,
+  AUTO_INIT_PATTERN = 1,
+  AUTO_INIT_ZERO = 2
+};
+
+enum auto_init_approach {
+  AUTO_INIT_A = 0,
+  AUTO_INIT_B = 1,
+  AUTO_INIT_C = 2,
+  AUTO_INIT_D = 3
+};
+
 /* Different instrumentation modes.  */
 enum sanitize_code {
   /* AddressSanitizer.  */
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 075d6e5208a..1044d54e8d3 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -81,7 +81,7 @@ newline_and_indent (pretty_printer *buffer, int spc)
 DEBUG_FUNCTION void
 debug_gimple_stmt (gimple *gs)
 {
-  print_gimple_stmt (stderr, gs, 0, TDF_VOPS|TDF_MEMSYMS);
+  print_gimple_stmt (stderr, gs, 0, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO|TDF_ALIAS);
 }
 
 
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 54cb66bd1dd..1eb0747ea2f 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1674,6 +1674,16 @@ gimplify_return_expr (tree stmt, gimple_seq *pre_p)
   return GS_ALL_DONE;
 }
 
+/* Return the value that is used to initialize the vla DECL based 
+   on INIT_TYPE.  */
+tree memset_init_node (enum auto_init_type init_type)
+{
+  if (init_type == AUTO_INIT_ZERO)
+    return integer_zero_node;
+  else
+    gcc_assert (0);
+}
+
 /* Gimplify a variable-length array DECL.  */
 
 static void
@@ -1712,6 +1722,19 @@ gimplify_vla_decl (tree decl, gimple_seq *seq_p)
 
   gimplify_and_add (t, seq_p);
 
+  /* Add a call to memset to initialize this vla when the user requested.  */
+  if (flag_trivial_auto_var_init > AUTO_INIT_UNINITIALIZED
+      && !DECL_ARTIFICIAL (decl)
+      && VAR_P (decl) 
+      && !DECL_EXTERNAL (decl) 
+      && !TREE_STATIC (decl))
+  {
+    t = builtin_decl_implicit (BUILT_IN_MEMSET);
+    tree init_node = memset_init_node (flag_trivial_auto_var_init);
+    t = build_call_expr (t, 3, addr, init_node, DECL_SIZE_UNIT (decl)); 
+    gimplify_and_add (t, seq_p);
+  }
+
   /* Record the dynamic allocation associated with DECL if requested.  */
   if (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC)
     record_dynamic_alloc (decl);
@@ -1734,6 +1757,63 @@ force_labels_r (tree *tp, int *walk_subtrees, void *data 
ATTRIBUTE_UNUSED)
   return NULL_TREE;
 }
 
+
+/* Build a call to internal const function DEFERRED_INIT,
+   1st argument: DECL;
+   2nd argument: INIT_TYPE;
+
+   as DEFERRED_INIT (DECL, INIT_TYPE)
+
+   DEFERRED_INIT is defined as:
+   DEF_INTERNAL_FN (DEFERRED_INIT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL).  
*/
+
+static gimple * 
+build_deferred_init (tree decl,
+                    enum auto_init_type init_type)
+{
+   tree init_type_node =
+     build_int_cst (integer_type_node, (int) init_type);
+   return gimple_build_call_internal (IFN_DEFERRED_INIT, 2, decl, 
init_type_node);
+}
+
+
+/* Generate initialization to automatic variable DECL based on INIT_TYPE.  */
+static void
+gimple_add_init_for_auto_var (tree decl,
+                             enum auto_init_type init_type,
+                             enum auto_init_approach init_approach,
+                             gimple_seq *seq_p)
+{
+  gcc_assert (VAR_P (decl) && !DECL_EXTERNAL (decl) && !TREE_STATIC (decl));
+  switch (init_type)
+  {
+  case AUTO_INIT_UNINITIALIZED:
+  case AUTO_INIT_PATTERN:
+    gcc_assert (0);
+    break;
+  case AUTO_INIT_ZERO:
+    if (init_approach == AUTO_INIT_A)
+    {
+      tree init = build_zero_cst (TREE_TYPE (decl));
+      init = build2 (INIT_EXPR, void_type_node, decl, init);
+      gimplify_and_add (init, seq_p);
+      ggc_free (init);
+    }
+    else if (init_approach == AUTO_INIT_D)
+    {
+      gimple *call = build_deferred_init (decl, AUTO_INIT_ZERO);
+      gimple_call_set_lhs (call, decl);
+      gimplify_seq_add_stmt (seq_p, call);
+    }
+    else 
+      gcc_assert (0);
+    break;
+  default:
+    gcc_unreachable ();
+  }
+}
+
+
 /* Gimplify a DECL_EXPR node *STMT_P by making any necessary allocation
    and initialization explicit.  */
 
@@ -1821,6 +1901,16 @@ gimplify_decl_expr (tree *stmt_p, gimple_seq *seq_p)
               as they may contain a label address.  */
            walk_tree (&init, force_labels_r, NULL, NULL);
        }
+      /* When there is no explicit initializer, if the user requested,
+        We should insert an artifical initializer for this automatic
+        variable for non vla variables.  */
+      else if (flag_trivial_auto_var_init > AUTO_INIT_UNINITIALIZED
+              && !TREE_STATIC (decl)
+              && !is_vla)
+       gimple_add_init_for_auto_var (decl, 
+                                     flag_trivial_auto_var_init, 
+                                     flag_auto_init_approach,
+                                     seq_p);
     }
 
   return GS_ALL_DONE;
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 41223ff7d82..6eef6ddb259 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -2971,6 +2971,26 @@ expand_UNIQUE (internal_fn, gcall *stmt)
     emit_insn (pattern);
 }
 
+/* Expand the IFN_DEFERRED_INIT function according to its second argument.  */
+static void
+expand_DEFERRED_INIT (internal_fn, gcall *stmt)
+{
+  tree var = gimple_call_lhs (stmt);
+  enum auto_init_type init_type
+    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
+
+  switch (init_type)
+    {
+    default:
+      gcc_unreachable ();
+    case AUTO_INIT_PATTERN:
+      gcc_assert (0);
+    case AUTO_INIT_ZERO:
+      tree init = build_zero_cst (TREE_TYPE (var));
+      expand_assignment (var, init, false);
+    }
+}
+
 /* The size of an OpenACC compute dimension.  */
 
 static void
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index 91a7bfea3ee..fd077d8b55c 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -347,6 +347,11 @@ DEF_INTERNAL_FN (VEC_CONVERT, ECF_CONST | ECF_LEAF | 
ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (UNIQUE, ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (PHI, 0, NULL)
 
+/* A function to represent an artifical initialization to an uninitialized
+   automatic variable. The first argument is the variable itself, the
+   second argument is the initialization type.  */
+DEF_INTERNAL_FN (DEFERRED_INIT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
+
 /* DIM_SIZE and DIM_POS return the size of a particular compute
    dimension and the executing thread's position within that
    dimension.  DIM_POS is pure (and not const) so that it isn't
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index f59a0c05200..3717c6d26a5 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -3433,6 +3433,9 @@ verify_gimple_call (gcall *stmt)
        }
     }
 
+  if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
+    return false;
+
   /* ???  The C frontend passes unpromoted arguments in case it
      didn't see a function declaration before the call.  So for now
      leave the call arguments mostly unverified.  Once we gimplify
diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c
index 516a7bd2c99..6c0946b0bc5 100644
--- a/gcc/tree-ssa-uninit.c
+++ b/gcc/tree-ssa-uninit.c
@@ -611,6 +611,9 @@ warn_uninitialized_vars (bool wmaybe_uninit)
          ssa_op_iter op_iter;
          tree use;
 
+         if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
+           continue;
+
          if (is_gimple_debug (stmt))
            continue;
 
diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
index a575979aa13..319e4150dc4 100644
--- a/gcc/tree-ssa.c
+++ b/gcc/tree-ssa.c
@@ -1325,6 +1325,11 @@ ssa_undefined_value_p (tree t, bool partial)
   if (gimple_nop_p (def_stmt))
     return true;
 
+  /* The value is undefined iff the definition statement is a call
+     to .DEFERRED_INIT function.  */
+  if (gimple_call_internal_p (def_stmt, IFN_DEFERRED_INIT))
+    return true;
+
   /* Check if the complex was not only partially defined.  */
   if (partial && is_gimple_assign (def_stmt)
       && gimple_assign_rhs_code (def_stmt) == COMPLEX_EXPR)
-- 
2.11.0

> On Jan 5, 2021, at 1:05 PM, Qing Zhao via Gcc-patches 
> <gcc-patches@gcc.gnu.org> wrote:
> 
> Hi,
> 
> This is an update for our previous discussion. 
> 
> 1. I implemented the following two different implementations in the latest 
> upstream gcc:
> 
> A. Adding real initialization during gimplification, not maintain the 
> uninitialized warnings.
> 
> D. Adding  calls to .DEFFERED_INIT during gimplification, expand the 
> .DEFFERED_INIT during expand to
> real initialization. Adjusting uninitialized pass with the new refs with 
> “.DEFFERED_INIT”.
> 
> Note, in this initial implementation,
>       ** I ONLY implement -ftrivial-auto-var-init=zero, the implementation of 
> -ftrivial-auto-var-init=pattern 
>          is not done yet.  Therefore, the performance data is only about 
> -ftrivial-auto-var-init=zero. 
> 
>       ** I added an temporary  option -fauto-var-init-approach=A|B|C|D  to 
> choose implementation A or D for 
>          runtime performance study.
>       ** I didn’t finish the uninitialized warnings maintenance work for D. 
> (That might take more time than I expected). 
> 
> 2. I collected runtime data for CPU2017 on a x86 machine with this new gcc 
> for the following 3 cases:
> 
> no: default. (-g -O2 -march=native )
> A:  default +  -ftrivial-auto-var-init=zero -fauto-var-init-approach=A 
> D:  default +  -ftrivial-auto-var-init=zero -fauto-var-init-approach=D 
> 
> And then compute the slowdown data for both A and D as following:
> 
> benchmarks            A / no  D /no
> 
> 500.perlbench_r       1.25%   1.25%
> 502.gcc_r             0.68%   1.80%
> 505.mcf_r             0.68%   0.14%
> 520.omnetpp_r 4.83%   4.68%
> 523.xalancbmk_r       0.18%   1.96%
> 525.x264_r            1.55%   2.07%
> 531.deepsjeng_        11.57%  11.85%
> 541.leela_r           0.64%   0.80%
> 557.xz_                        -0.41% -0.41%
> 
> 507.cactuBSSN_r       0.44%   0.44%
> 508.namd_r            0.34%   0.34%
> 510.parest_r          0.17%   0.25%
> 511.povray_r          56.57%  57.27%
> 519.lbm_r             0.00%   0.00%
> 521.wrf_r                      -0.28% -0.37%
> 526.blender_r         16.96%  17.71%
> 527.cam4_r            0.70%   0.53%
> 538.imagick_r         2.40%   2.40%
> 544.nab_r             0.00%   -0.65%
> 
> avg                           5.17%   5.37%
> 
> From the above data, we can see that in general, the runtime performance 
> slowdown for 
> implementation A and D are similar for individual benchmarks.
> 
> There are several benchmarks that have significant slowdown with the new 
> added initialization for both
> A and D, for example, 511.povray_r, 526.blender_, and 531.deepsjeng_r, I will 
> try to study a little bit
> more on what kind of new initializations introduced such slowdown. 
> 
> From the current study so far, I think that approach D should be good enough 
> for our final implementation. 
> So, I will try to finish approach D with the following remaining work
> 
>      ** complete the implementation of -ftrivial-auto-var-init=pattern;
>      ** complete the implementation of uninitialized warnings maintenance 
> work for D. 
> 
> 
> Let me know if you have any comments and suggestions on my current and future 
> work.
> 
> Thanks a lot for your help.
> 
> Qing
> 
>> On Dec 9, 2020, at 10:18 AM, Qing Zhao via Gcc-patches 
>> <gcc-patches@gcc.gnu.org> wrote:
>> 
>> The following are the approaches I will implement and compare:
>> 
>> Our final goal is to keep the uninitialized warning and minimize the 
>> run-time performance cost.
>> 
>> A. Adding real initialization during gimplification, not maintain the 
>> uninitialized warnings.
>> B. Adding real initialization during gimplification, marking them with 
>> “artificial_init”. 
>>    Adjusting uninitialized pass, maintaining the annotation, making sure the 
>> real init not
>>    Deleted from the fake init. 
>> C.  Marking the DECL for an uninitialized auto variable as 
>> “no_explicit_init” during gimplification,
>>     maintain this “no_explicit_init” bit till after 
>> pass_late_warn_uninitialized, or till pass_expand, 
>>     add real initialization for all DECLs that are marked with 
>> “no_explicit_init”.
>> D. Adding .DEFFERED_INIT during gimplification, expand the .DEFFERED_INIT 
>> during expand to
>>    real initialization. Adjusting uninitialized pass with the new refs with 
>> “.DEFFERED_INIT”.
>> 
>> 
>> In the above, approach A will be the one that have the minimum run-time 
>> cost, will be the base for the performance
>> comparison. 
>> 
>> I will implement approach D then, this one is expected to have the most 
>> run-time overhead among the above list, but
>> Implementation should be the cleanest among B, C, D. Let’s see how much more 
>> performance overhead this approach
>> will be. If the data is good, maybe we can avoid the effort to implement B, 
>> and C. 
>> 
>> If the performance of D is not good, I will implement B or C at that time.
>> 
>> Let me know if you have any comment or suggestions.
>> 
>> Thanks.
>> 
>> Qing
> 

Reply via email to