public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [patch for gcc12 stage1][version 2] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
@ 2021-03-24 21:21 Qing Zhao
  2021-04-07 14:44 ` Qing Zhao
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Qing Zhao @ 2021-03-24 21:21 UTC (permalink / raw)
  To: richard Sandiford, Richard Biener, Kees Cook; +Cc: Gcc-patches Qing Zhao via

[-- Attachment #1: Type: text/plain, Size: 10521 bytes --]

Hi, 

This is the 2nd version of the patch for the new security feature for GCC.

Could you please take a look at it and let me know any comments and issues.

Thanks.

Qing

******compared to Version 1, this version added the following new features to address Kees’s comments:

1.  correctly handle VLA inside a structure for pattern initialization.
In tree.c (build_pattern_cst):

+           /* if the field is a variable length array, it should be the last
+              field of the record, and no need to initialize.  */
+           if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
+               && TYPE_SIZE (TREE_TYPE (field)) == NULL_TREE
+               && ((TYPE_DOMAIN (TREE_TYPE (field)) != NULL_TREE
+                   && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field)))
+                                      == NULL_TREE)
+                  || TYPE_DOMAIN (TREE_TYPE (field)) == NULL_TREE))
+             continue;

2.  initialize all paddings to zero when -ftrivial-auto-var-init is present.
In expr.c (store_constructor):

	Clear the whole structure when
        -ftrivial-auto-var-init and the structure has paddings.

In gimplify.c (gimplify_init_constructor):

	Clear the whole structure when
        -ftrivial-auto-var-init and the structure has paddings.

As agreed with Kees, treat the issue related to auto variables outside of the cases and inside the switch as a low priority one. 

3. Add  the following new testing cases for the above 1 and 2:

        * c-c++-common/auto-init-13.c: New test.
        * c-c++-common/auto-init-14.c: New test. 

	* gcc.target/aarch64/auto-init-9.c: New test.
	* gcc.target/aarch64/auto-init-10.c: New test.
        * gcc.target/aarch64/auto-init-11.c: New test.
        * gcc.target/aarch64/auto-init-12.c: New test.
        * gcc.target/aarch64/auto-init-13.c: New test.
        * gcc.target/aarch64/auto-init-14.c: New test.
        * gcc.target/aarch64/auto-init-15.c: New test.
        * gcc.target/aarch64/auto-init-16.c: New test.
        * gcc.target/aarch64/auto-init-17.c: New test.
        * gcc.target/aarch64/auto-init-18.c: New test.
        * gcc.target/aarch64/auto-init-19.c: New test.
        * gcc.target/aarch64/auto-init-20.c: New test.

        * gcc.target/i386/auto-init-9.c: New test.
        * gcc.target/i386/auto-init-10.c: New test.
        * gcc.target/i386/auto-init-11.c: New test.
        * gcc.target/i386/auto-init-12.c: New test.
        * gcc.target/i386/auto-init-13.c: New test.
        * gcc.target/i386/auto-init-14.c: New test.
        * gcc.target/i386/auto-init-15.c: New test.
        * gcc.target/i386/auto-init-16.c: New test.
        * gcc.target/i386/auto-init-17.c: New test.
        * gcc.target/i386/auto-init-18.c: New test.
        * gcc.target/i386/auto-init-19.c: New test.
        * gcc.target/i386/auto-init-20.c: New test.

4. Update the default approach as D,  then when specify -ftrivial-auto-var-init,  the default approach is the “.DEFERRED_INIT” 
Approach. No need to add -fauto-var-init-approach=D anymore.

If we need to compare approach A and D, we can add -fauto-var-init-approach=A to get that implementation. 

5.  Delete all -fauto-var-init-approach=D in the testing cases. 

****** others are the same as Version 1, please see the version 1 description at:

https://gcc.gnu.org/pipermail/gcc-patches/2021-February/565581.html


*******Changelog:

gcc/:

2021-03-24  qing zhao  <qing.zhao@oracle.com>

	* common.opt (ftrivial-auto-var-init=): New.
	(fauto-var-init-approach=): Likewise.
	* doc/extend.texi: Document the uninitialized attribute.
	* doc/invoke.texi: Document -ftrivial-auto-var-init.
	* expr.c (store_constructor): Clear the whole structure when
	-ftrivial-auto-var-init and the structure has paddings.
	* flag-types.h (enum auto_init_type): New enumerated type
	auto_init_type.
	(enum auto_init_approach): New enumerated type auto_init_approach.
	* gimple.h (enum gf_mask): Add GF_CALL_MEMSET_FOR_UNINIT case.
	(gimple_call_set_memset_for_uninit): New function.
	(gimple_call_memset_for_uninit_p): Likewise.
	* gimplify.c (gimplify_vla_decl): Add initialization to vla per users'
	requests. 
	(build_deferred_init): New function.
	(gimple_add_init_for_auto_var): Likewise.
	(gimplify_decl_expr): Add initialization to automatic variables per
	users' requests.
	(gimplify_init_constructor): Clear the whole structure when
	-ftrivial-auto-var-init and the structure has paddings.
	* internal-fn.c (expand_DEFERRED_INIT): New function.
	* internal-fn.def (DEFERRED_INIT): New internal function.
	* tree-cfg.c (verify_gimple_call): Skip calls to DEFERRED_INIT.
	* tree-core.h (tree_decl_with_vis): Add uninitialized field.
	* tree-sra.c (sra_stats): Add two new fields deferred_init and
	subtree_deferred_init.
	(generate_subtree_deferred_init): New function.
	(sra_modify_deferred_init): Likewise.
	(sra_modify_function_body): Handle calls to DEFERRED_INIT specially.
	* tree-ssa-structalias.c (find_func_aliases_for_deferred_init): New
	function.
	(find_func_aliases_for_call): Handle calls to DEFERRED_INIT specially.
	* tree-ssa-uninit.c (warn_uninit): Handle calls to DEFERRED_INIT
	specially.
	(check_defs): Handle calls to DEFERRED_INIT and MEMSET for uninitialized
	variable specially.
	(warn_uninitialized_vars): Handle calls to DEFERRED_INIT specially.
	* tree-ssa.c (ssa_undefined_value_p): Handle calls to DEFERRED_INIT
	specially.
	* tree.c (build_pattern_cst): New function.
	(type_has_padding): Likewise.
	* tree.h (DECL_UNINITIALIZED): New macro.
	(build_pattern_cst): New declaration.
	(type_has_padding): Likewise.

gcc/c-family/:

2021-03-24  qing zhao  <qing.zhao@oracle.com>

	* c-attribs.c (handle_uninitialized_attribute): New function.
	(c_common_attribute_table): Add "uninitialized" attribute.

gcc/testsuite/:

2021-03-24  qing zhao  <qing.zhao@oracle.com>

	* c-c++-common/auto-init-1.c: New test.
	* c-c++-common/auto-init-10.c: New test.
	* c-c++-common/auto-init-11.c: New test.
	* c-c++-common/auto-init-12.c: New test.
	* c-c++-common/auto-init-13.c: New test.
	* c-c++-common/auto-init-14.c: New test.
	* c-c++-common/auto-init-2.c: New test.
	* c-c++-common/auto-init-3.c: New test.
	* c-c++-common/auto-init-4.c: New test.
	* c-c++-common/auto-init-5.c: New test.
	* c-c++-common/auto-init-6.c: New test.
	* c-c++-common/auto-init-7.c: New test.
	* c-c++-common/auto-init-8.c: New test.
	* c-c++-common/auto-init-9.c: New test.
	* c-c++-common/auto-init-esra.c: New test.
	* g++.dg/auto-init-uninit-pred-1_a.C: New test.
	* g++.dg/auto-init-uninit-pred-1_b.C: New test.
	* g++.dg/auto-init-uninit-pred-2_a.C: New test.
	* g++.dg/auto-init-uninit-pred-2_b.C: New test.
	* g++.dg/auto-init-uninit-pred-3_a.C: New test.
	* g++.dg/auto-init-uninit-pred-3_b.C: New test.
	* g++.dg/auto-init-uninit-pred-4.C: New test.
	* g++.dg/auto-init-uninit-pred-loop-1_a.cc: New test.
	* g++.dg/auto-init-uninit-pred-loop-1_b.cc: New test.
	* g++.dg/auto-init-uninit-pred-loop-1_c.cc: New test.
	* g++.dg/auto-init-uninit-pred-loop_1.cc: New test.
	* gcc.dg/auto-init-uninit-1.c: New test.
	* gcc.dg/auto-init-uninit-11.c: New test.
	* gcc.dg/auto-init-uninit-12.c: New test.
	* gcc.dg/auto-init-uninit-13.c: New test.
	* gcc.dg/auto-init-uninit-14.c: New test.
	* gcc.dg/auto-init-uninit-15.c: New test.
	* gcc.dg/auto-init-uninit-16.c: New test.
	* gcc.dg/auto-init-uninit-17.c: New test.
	* gcc.dg/auto-init-uninit-18.c: New test.
	* gcc.dg/auto-init-uninit-19.c: New test.
	* gcc.dg/auto-init-uninit-2.c: New test.
	* gcc.dg/auto-init-uninit-20.c: New test.
	* gcc.dg/auto-init-uninit-21.c: New test.
	* gcc.dg/auto-init-uninit-22.c: New test.
	* gcc.dg/auto-init-uninit-23.c: New test.
	* gcc.dg/auto-init-uninit-24.c: New test.
	* gcc.dg/auto-init-uninit-25.c: New test.
	* gcc.dg/auto-init-uninit-26.c: New test.
	* gcc.dg/auto-init-uninit-3.c: New test.
	* gcc.dg/auto-init-uninit-34.c: New test.
	* gcc.dg/auto-init-uninit-36.c: New test.
	* gcc.dg/auto-init-uninit-37.c: New test.
	* gcc.dg/auto-init-uninit-4.c: New test.
	* gcc.dg/auto-init-uninit-5.c: New test.
	* gcc.dg/auto-init-uninit-6.c: New test.
	* gcc.dg/auto-init-uninit-8.c: New test.
	* gcc.dg/auto-init-uninit-9.c: New test.
	* gcc.dg/auto-init-uninit-A.c: New test.
	* gcc.dg/auto-init-uninit-B.c: New test.
	* gcc.dg/auto-init-uninit-C.c: New test.
	* gcc.dg/auto-init-uninit-H.c: New test.
	* gcc.dg/auto-init-uninit-I.c: New test.
	* gcc.target/aarch64/auto-init-1.c: New test.
	* gcc.target/aarch64/auto-init-10.c: New test.
	* gcc.target/aarch64/auto-init-11.c: New test.
	* gcc.target/aarch64/auto-init-12.c: New test.
	* gcc.target/aarch64/auto-init-13.c: New test.
	* gcc.target/aarch64/auto-init-14.c: New test.
	* gcc.target/aarch64/auto-init-15.c: New test.
	* gcc.target/aarch64/auto-init-16.c: New test.
	* gcc.target/aarch64/auto-init-17.c: New test.
	* gcc.target/aarch64/auto-init-18.c: New test.
	* gcc.target/aarch64/auto-init-19.c: New test.
	* gcc.target/aarch64/auto-init-2.c: New test.
	* gcc.target/aarch64/auto-init-20.c: New test.
	* gcc.target/aarch64/auto-init-3.c: New test.
	* gcc.target/aarch64/auto-init-4.c: New test.
	* gcc.target/aarch64/auto-init-5.c: New test.
	* gcc.target/aarch64/auto-init-6.c: New test.
	* gcc.target/aarch64/auto-init-7.c: New test.
	* gcc.target/aarch64/auto-init-8.c: New test.
	* gcc.target/aarch64/auto-init-9.c: New test.
	* gcc.target/i386/auto-init-1.c: New test.
	* gcc.target/i386/auto-init-10.c: New test.
	* gcc.target/i386/auto-init-11.c: New test.
	* gcc.target/i386/auto-init-12.c: New test.
	* gcc.target/i386/auto-init-13.c: New test.
	* gcc.target/i386/auto-init-14.c: New test.
	* gcc.target/i386/auto-init-15.c: New test.
	* gcc.target/i386/auto-init-16.c: New test.
	* gcc.target/i386/auto-init-17.c: New test.
	* gcc.target/i386/auto-init-18.c: New test.
	* gcc.target/i386/auto-init-19.c: New test.
	* gcc.target/i386/auto-init-2.c: New test.
	* gcc.target/i386/auto-init-20.c: New test.
	* gcc.target/i386/auto-init-3.c: New test.
	* gcc.target/i386/auto-init-4.c: New test.
	* gcc.target/i386/auto-init-5.c: New test.
	* gcc.target/i386/auto-init-6.c: New test.
	* gcc.target/i386/auto-init-7.c: New test.
	* gcc.target/i386/auto-init-8.c: New test.
	* gcc.target/i386/auto-init-9.c: New test.

******The complete patch is attached as following:


[-- Attachment #2: 0001-add-ftrivial-auto-var-init-and-variable-attribute-un.patch --]
[-- Type: application/octet-stream, Size: 162686 bytes --]

From 481c1b6b36ebd47fa95f87a2490132636b443c77 Mon Sep 17 00:00:00 2001
From: qing zhao <qing.zhao@oracle.com>
Date: Wed, 24 Mar 2021 14:54:43 +0000
Subject: [PATCH] add -ftrivial-auto-var-init and variable attribute 
 uninitialized to gcc.


gcc/:

2021-03-24  qing zhao  <qing.zhao@oracle.com>

	* common.opt (ftrivial-auto-var-init=): New.
	(fauto-var-init-approach=): Likewise.
	* doc/extend.texi: Document the uninitialized attribute.
	* doc/invoke.texi: Document -ftrivial-auto-var-init.
	* expr.c (store_constructor): Clear the whole structure when
	-ftrivial-auto-var-init and the structure has paddings.
	* flag-types.h (enum auto_init_type): New enumerated type
	auto_init_type.
	(enum auto_init_approach): New enumerated type auto_init_approach.
	* gimple.h (enum gf_mask): Add GF_CALL_MEMSET_FOR_UNINIT case.
	(gimple_call_set_memset_for_uninit): New function.
	(gimple_call_memset_for_uninit_p): Likewise.
	* gimplify.c (gimplify_vla_decl): Add initialization to vla per users'
	requests. 
	(build_deferred_init): New function.
	(gimple_add_init_for_auto_var): Likewise.
	(gimplify_decl_expr): Add initialization to automatic variables per
	users' requests.
	(gimplify_init_constructor): Clear the whole structure when
	-ftrivial-auto-var-init and the structure has paddings.
	* internal-fn.c (expand_DEFERRED_INIT): New function.
	* internal-fn.def (DEFERRED_INIT): New internal function.
	* tree-cfg.c (verify_gimple_call): Skip calls to DEFERRED_INIT.
	* tree-core.h (tree_decl_with_vis): Add uninitialized field.
	* tree-sra.c (sra_stats): Add two new fields deferred_init and
	subtree_deferred_init.
	(generate_subtree_deferred_init): New function.
	(sra_modify_deferred_init): Likewise.
	(sra_modify_function_body): Handle calls to DEFERRED_INIT specially.
	* tree-ssa-structalias.c (find_func_aliases_for_deferred_init): New
	function.
	(find_func_aliases_for_call): Handle calls to DEFERRED_INIT specially.
	* tree-ssa-uninit.c (warn_uninit): Handle calls to DEFERRED_INIT
	specially.
	(check_defs): Handle calls to DEFERRED_INIT and MEMSET for uninitialized
	variable specially.
	(warn_uninitialized_vars): Handle calls to DEFERRED_INIT specially.
	* tree-ssa.c (ssa_undefined_value_p): Handle calls to DEFERRED_INIT
	specially.
	* tree.c (build_pattern_cst): New function.
	(type_has_padding): Likewise.
	* tree.h (DECL_UNINITIALIZED): New macro.
	(build_pattern_cst): New declaration.
	(type_has_padding): Likewise.

gcc/c-family/:

2021-03-24  qing zhao  <qing.zhao@oracle.com>

	* c-attribs.c (handle_uninitialized_attribute): New function.
	(c_common_attribute_table): Add "uninitialized" attribute.

gcc/testsuite/:

2021-03-24  qing zhao  <qing.zhao@oracle.com>

	* c-c++-common/auto-init-1.c: New test.
	* c-c++-common/auto-init-10.c: New test.
	* c-c++-common/auto-init-11.c: New test.
	* c-c++-common/auto-init-12.c: New test.
	* c-c++-common/auto-init-13.c: New test.
	* c-c++-common/auto-init-14.c: New test.
	* c-c++-common/auto-init-2.c: New test.
	* c-c++-common/auto-init-3.c: New test.
	* c-c++-common/auto-init-4.c: New test.
	* c-c++-common/auto-init-5.c: New test.
	* c-c++-common/auto-init-6.c: New test.
	* c-c++-common/auto-init-7.c: New test.
	* c-c++-common/auto-init-8.c: New test.
	* c-c++-common/auto-init-9.c: New test.
	* c-c++-common/auto-init-esra.c: New test.
	* g++.dg/auto-init-uninit-pred-1_a.C: New test.
	* g++.dg/auto-init-uninit-pred-1_b.C: New test.
	* g++.dg/auto-init-uninit-pred-2_a.C: New test.
	* g++.dg/auto-init-uninit-pred-2_b.C: New test.
	* g++.dg/auto-init-uninit-pred-3_a.C: New test.
	* g++.dg/auto-init-uninit-pred-3_b.C: New test.
	* g++.dg/auto-init-uninit-pred-4.C: New test.
	* g++.dg/auto-init-uninit-pred-loop-1_a.cc: New test.
	* g++.dg/auto-init-uninit-pred-loop-1_b.cc: New test.
	* g++.dg/auto-init-uninit-pred-loop-1_c.cc: New test.
	* g++.dg/auto-init-uninit-pred-loop_1.cc: New test.
	* gcc.dg/auto-init-uninit-1.c: New test.
	* gcc.dg/auto-init-uninit-11.c: New test.
	* gcc.dg/auto-init-uninit-12.c: New test.
	* gcc.dg/auto-init-uninit-13.c: New test.
	* gcc.dg/auto-init-uninit-14.c: New test.
	* gcc.dg/auto-init-uninit-15.c: New test.
	* gcc.dg/auto-init-uninit-16.c: New test.
	* gcc.dg/auto-init-uninit-17.c: New test.
	* gcc.dg/auto-init-uninit-18.c: New test.
	* gcc.dg/auto-init-uninit-19.c: New test.
	* gcc.dg/auto-init-uninit-2.c: New test.
	* gcc.dg/auto-init-uninit-20.c: New test.
	* gcc.dg/auto-init-uninit-21.c: New test.
	* gcc.dg/auto-init-uninit-22.c: New test.
	* gcc.dg/auto-init-uninit-23.c: New test.
	* gcc.dg/auto-init-uninit-24.c: New test.
	* gcc.dg/auto-init-uninit-25.c: New test.
	* gcc.dg/auto-init-uninit-26.c: New test.
	* gcc.dg/auto-init-uninit-3.c: New test.
	* gcc.dg/auto-init-uninit-34.c: New test.
	* gcc.dg/auto-init-uninit-36.c: New test.
	* gcc.dg/auto-init-uninit-37.c: New test.
	* gcc.dg/auto-init-uninit-4.c: New test.
	* gcc.dg/auto-init-uninit-5.c: New test.
	* gcc.dg/auto-init-uninit-6.c: New test.
	* gcc.dg/auto-init-uninit-8.c: New test.
	* gcc.dg/auto-init-uninit-9.c: New test.
	* gcc.dg/auto-init-uninit-A.c: New test.
	* gcc.dg/auto-init-uninit-B.c: New test.
	* gcc.dg/auto-init-uninit-C.c: New test.
	* gcc.dg/auto-init-uninit-H.c: New test.
	* gcc.dg/auto-init-uninit-I.c: New test.
	* gcc.target/aarch64/auto-init-1.c: New test.
	* gcc.target/aarch64/auto-init-10.c: New test.
	* gcc.target/aarch64/auto-init-11.c: New test.
	* gcc.target/aarch64/auto-init-12.c: New test.
	* gcc.target/aarch64/auto-init-13.c: New test.
	* gcc.target/aarch64/auto-init-14.c: New test.
	* gcc.target/aarch64/auto-init-15.c: New test.
	* gcc.target/aarch64/auto-init-16.c: New test.
	* gcc.target/aarch64/auto-init-17.c: New test.
	* gcc.target/aarch64/auto-init-18.c: New test.
	* gcc.target/aarch64/auto-init-19.c: New test.
	* gcc.target/aarch64/auto-init-2.c: New test.
	* gcc.target/aarch64/auto-init-20.c: New test.
	* gcc.target/aarch64/auto-init-3.c: New test.
	* gcc.target/aarch64/auto-init-4.c: New test.
	* gcc.target/aarch64/auto-init-5.c: New test.
	* gcc.target/aarch64/auto-init-6.c: New test.
	* gcc.target/aarch64/auto-init-7.c: New test.
	* gcc.target/aarch64/auto-init-8.c: New test.
	* gcc.target/aarch64/auto-init-9.c: New test.
	* gcc.target/i386/auto-init-1.c: New test.
	* gcc.target/i386/auto-init-10.c: New test.
	* gcc.target/i386/auto-init-11.c: New test.
	* gcc.target/i386/auto-init-12.c: New test.
	* gcc.target/i386/auto-init-13.c: New test.
	* gcc.target/i386/auto-init-14.c: New test.
	* gcc.target/i386/auto-init-15.c: New test.
	* gcc.target/i386/auto-init-16.c: New test.
	* gcc.target/i386/auto-init-17.c: New test.
	* gcc.target/i386/auto-init-18.c: New test.
	* gcc.target/i386/auto-init-19.c: New test.
	* gcc.target/i386/auto-init-2.c: New test.
	* gcc.target/i386/auto-init-20.c: New test.
	* gcc.target/i386/auto-init-3.c: New test.
	* gcc.target/i386/auto-init-4.c: New test.
	* gcc.target/i386/auto-init-5.c: New test.
	* gcc.target/i386/auto-init-6.c: New test.
	* gcc.target/i386/auto-init-7.c: New test.
	* gcc.target/i386/auto-init-8.c: New test.
	* gcc.target/i386/auto-init-9.c: New test.

---
 gcc/c-family/c-attribs.c                           |  21 ++
 gcc/common.opt                                     |  29 +++
 gcc/doc/extend.texi                                |  16 ++
 gcc/doc/invoke.texi                                |  34 ++-
 gcc/expr.c                                         |  17 +-
 gcc/flag-types.h                                   |  12 ++
 gcc/gimple.h                                       |  24 +++
 gcc/gimplify.c                                     | 191 +++++++++++++++++
 gcc/internal-fn.c                                  |  24 +++
 gcc/internal-fn.def                                |   5 +
 gcc/testsuite/c-c++-common/auto-init-1.c           |  39 ++++
 gcc/testsuite/c-c++-common/auto-init-10.c          |  17 ++
 gcc/testsuite/c-c++-common/auto-init-11.c          |  14 ++
 gcc/testsuite/c-c++-common/auto-init-12.c          |  14 ++
 gcc/testsuite/c-c++-common/auto-init-13.c          |  23 ++
 gcc/testsuite/c-c++-common/auto-init-14.c          |  23 ++
 gcc/testsuite/c-c++-common/auto-init-2.c           |  39 ++++
 gcc/testsuite/c-c++-common/auto-init-3.c           |  19 ++
 gcc/testsuite/c-c++-common/auto-init-4.c           |  19 ++
 gcc/testsuite/c-c++-common/auto-init-5.c           |  21 ++
 gcc/testsuite/c-c++-common/auto-init-6.c           |  21 ++
 gcc/testsuite/c-c++-common/auto-init-7.c           |  35 +++
 gcc/testsuite/c-c++-common/auto-init-8.c           |  35 +++
 gcc/testsuite/c-c++-common/auto-init-9.c           |  17 ++
 gcc/testsuite/c-c++-common/auto-init-esra.c        |  35 +++
 gcc/testsuite/g++.dg/auto-init-uninit-pred-1_a.C   |  63 ++++++
 gcc/testsuite/g++.dg/auto-init-uninit-pred-1_b.C   |  63 ++++++
 gcc/testsuite/g++.dg/auto-init-uninit-pred-2_a.C   |  62 ++++++
 gcc/testsuite/g++.dg/auto-init-uninit-pred-2_b.C   |  62 ++++++
 gcc/testsuite/g++.dg/auto-init-uninit-pred-3_a.C   |  77 +++++++
 gcc/testsuite/g++.dg/auto-init-uninit-pred-3_b.C   |  87 ++++++++
 gcc/testsuite/g++.dg/auto-init-uninit-pred-4.C     |  16 ++
 .../g++.dg/auto-init-uninit-pred-loop-1_a.cc       |  21 ++
 .../g++.dg/auto-init-uninit-pred-loop-1_b.cc       |  21 ++
 .../g++.dg/auto-init-uninit-pred-loop-1_c.cc       |  23 ++
 .../g++.dg/auto-init-uninit-pred-loop_1.cc         |  21 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-1.c          |  30 +++
 gcc/testsuite/gcc.dg/auto-init-uninit-11.c         |  42 ++++
 gcc/testsuite/gcc.dg/auto-init-uninit-12.c         |  12 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-13.c         |  10 +
 gcc/testsuite/gcc.dg/auto-init-uninit-14.c         |  20 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-15.c         |  26 +++
 gcc/testsuite/gcc.dg/auto-init-uninit-16.c         |  23 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-17.c         |  15 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-18.c         |  24 +++
 gcc/testsuite/gcc.dg/auto-init-uninit-19.c         |  26 +++
 gcc/testsuite/gcc.dg/auto-init-uninit-2.c          |  52 +++++
 gcc/testsuite/gcc.dg/auto-init-uninit-20.c         |  18 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-21.c         |  33 +++
 gcc/testsuite/gcc.dg/auto-init-uninit-22.c         |  69 ++++++
 gcc/testsuite/gcc.dg/auto-init-uninit-23.c         |  27 +++
 gcc/testsuite/gcc.dg/auto-init-uninit-24.c         |  10 +
 gcc/testsuite/gcc.dg/auto-init-uninit-25.c         |  23 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-26.c         |  23 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-3.c          |  33 +++
 gcc/testsuite/gcc.dg/auto-init-uninit-34.c         |  58 +++++
 gcc/testsuite/gcc.dg/auto-init-uninit-36.c         | 238 +++++++++++++++++++++
 gcc/testsuite/gcc.dg/auto-init-uninit-37.c         | 154 +++++++++++++
 gcc/testsuite/gcc.dg/auto-init-uninit-4.c          |  52 +++++
 gcc/testsuite/gcc.dg/auto-init-uninit-5.c          |  39 ++++
 gcc/testsuite/gcc.dg/auto-init-uninit-6.c          |  47 ++++
 gcc/testsuite/gcc.dg/auto-init-uninit-8.c          |  32 +++
 gcc/testsuite/gcc.dg/auto-init-uninit-9.c          |  42 ++++
 gcc/testsuite/gcc.dg/auto-init-uninit-A.c          | 117 ++++++++++
 gcc/testsuite/gcc.dg/auto-init-uninit-B.c          |  15 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-C.c          |  21 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-H.c          |  33 +++
 gcc/testsuite/gcc.dg/auto-init-uninit-I.c          |   8 +
 gcc/testsuite/gcc.target/aarch64/auto-init-1.c     |  32 +++
 gcc/testsuite/gcc.target/aarch64/auto-init-10.c    |  18 ++
 gcc/testsuite/gcc.target/aarch64/auto-init-11.c    |  27 +++
 gcc/testsuite/gcc.target/aarch64/auto-init-12.c    |  27 +++
 gcc/testsuite/gcc.target/aarch64/auto-init-13.c    |  22 ++
 gcc/testsuite/gcc.target/aarch64/auto-init-14.c    |  20 ++
 gcc/testsuite/gcc.target/aarch64/auto-init-15.c    |  20 ++
 gcc/testsuite/gcc.target/aarch64/auto-init-16.c    |  22 ++
 gcc/testsuite/gcc.target/aarch64/auto-init-17.c    |  21 ++
 gcc/testsuite/gcc.target/aarch64/auto-init-18.c    |  21 ++
 gcc/testsuite/gcc.target/aarch64/auto-init-19.c    |  27 +++
 gcc/testsuite/gcc.target/aarch64/auto-init-2.c     |  37 ++++
 gcc/testsuite/gcc.target/aarch64/auto-init-20.c    |  27 +++
 gcc/testsuite/gcc.target/aarch64/auto-init-3.c     |  19 ++
 gcc/testsuite/gcc.target/aarch64/auto-init-4.c     |  19 ++
 gcc/testsuite/gcc.target/aarch64/auto-init-5.c     |  19 ++
 gcc/testsuite/gcc.target/aarch64/auto-init-6.c     |  21 ++
 gcc/testsuite/gcc.target/aarch64/auto-init-7.c     |  32 +++
 gcc/testsuite/gcc.target/aarch64/auto-init-8.c     |  33 +++
 gcc/testsuite/gcc.target/aarch64/auto-init-9.c     |  19 ++
 gcc/testsuite/gcc.target/i386/auto-init-1.c        |  32 +++
 gcc/testsuite/gcc.target/i386/auto-init-10.c       |  19 ++
 gcc/testsuite/gcc.target/i386/auto-init-11.c       |  30 +++
 gcc/testsuite/gcc.target/i386/auto-init-12.c       |  30 +++
 gcc/testsuite/gcc.target/i386/auto-init-13.c       |  22 ++
 gcc/testsuite/gcc.target/i386/auto-init-14.c       |  22 ++
 gcc/testsuite/gcc.target/i386/auto-init-15.c       |  22 ++
 gcc/testsuite/gcc.target/i386/auto-init-16.c       |  22 ++
 gcc/testsuite/gcc.target/i386/auto-init-17.c       |  23 ++
 gcc/testsuite/gcc.target/i386/auto-init-18.c       |  21 ++
 gcc/testsuite/gcc.target/i386/auto-init-19.c       |  26 +++
 gcc/testsuite/gcc.target/i386/auto-init-2.c        |  37 ++++
 gcc/testsuite/gcc.target/i386/auto-init-20.c       |  26 +++
 gcc/testsuite/gcc.target/i386/auto-init-3.c        |  20 ++
 gcc/testsuite/gcc.target/i386/auto-init-4.c        |  23 ++
 gcc/testsuite/gcc.target/i386/auto-init-5.c        |  19 ++
 gcc/testsuite/gcc.target/i386/auto-init-6.c        |  22 ++
 gcc/testsuite/gcc.target/i386/auto-init-7.c        |  32 +++
 gcc/testsuite/gcc.target/i386/auto-init-8.c        |  33 +++
 gcc/testsuite/gcc.target/i386/auto-init-9.c        |  19 ++
 gcc/tree-cfg.c                                     |   3 +
 gcc/tree-core.h                                    |   3 +-
 gcc/tree-sra.c                                     | 132 +++++++++++-
 gcc/tree-ssa-structalias.c                         |  29 +++
 gcc/tree-ssa-uninit.c                              |  30 +++
 gcc/tree-ssa.c                                     |  17 ++
 gcc/tree.c                                         | 204 ++++++++++++++++++
 gcc/tree.h                                         |   6 +
 116 files changed, 4021 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-1.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-10.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-11.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-12.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-13.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-14.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-2.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-3.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-4.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-5.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-6.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-7.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-8.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-9.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-esra.c
 create mode 100644 gcc/testsuite/g++.dg/auto-init-uninit-pred-1_a.C
 create mode 100644 gcc/testsuite/g++.dg/auto-init-uninit-pred-1_b.C
 create mode 100644 gcc/testsuite/g++.dg/auto-init-uninit-pred-2_a.C
 create mode 100644 gcc/testsuite/g++.dg/auto-init-uninit-pred-2_b.C
 create mode 100644 gcc/testsuite/g++.dg/auto-init-uninit-pred-3_a.C
 create mode 100644 gcc/testsuite/g++.dg/auto-init-uninit-pred-3_b.C
 create mode 100644 gcc/testsuite/g++.dg/auto-init-uninit-pred-4.C
 create mode 100644 gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_a.cc
 create mode 100644 gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_b.cc
 create mode 100644 gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_c.cc
 create mode 100644 gcc/testsuite/g++.dg/auto-init-uninit-pred-loop_1.cc
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-1.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-11.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-12.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-13.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-14.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-15.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-16.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-17.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-18.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-19.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-2.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-20.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-21.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-22.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-23.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-24.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-25.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-26.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-3.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-34.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-36.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-37.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-4.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-5.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-6.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-8.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-9.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-A.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-B.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-C.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-H.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-I.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-10.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-11.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-12.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-13.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-14.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-15.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-16.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-17.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-18.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-19.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-2.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-20.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-3.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-4.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-5.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-6.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-7.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-8.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-9.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-1.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-10.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-11.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-12.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-13.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-14.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-15.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-16.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-17.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-18.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-19.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-2.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-20.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-3.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-4.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-5.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-6.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-7.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-8.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-9.c

diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index c1f652d..2a69e07 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -81,6 +81,7 @@ static tree handle_artificial_attribute (tree *, tree, tree, int, bool *);
 static tree handle_flatten_attribute (tree *, tree, tree, int, bool *);
 static tree handle_error_attribute (tree *, tree, tree, int, bool *);
 static tree handle_used_attribute (tree *, tree, tree, int, bool *);
+static tree handle_uninitialized_attribute (tree *, tree, tree, int, bool *);
 static tree handle_externally_visible_attribute (tree *, tree, tree, int,
 						 bool *);
 static tree handle_no_reorder_attribute (tree *, tree, tree, int,
@@ -329,6 +330,8 @@ const struct attribute_spec c_common_attribute_table[] =
 			      handle_used_attribute, NULL },
   { "unused",                 0, 0, false, false, false, false,
 			      handle_unused_attribute, NULL },
+  { "uninitialized",	      0, 0, true, false, false, false,
+			      handle_uninitialized_attribute, NULL },
   { "retain",                 0, 0, true,  false, false, false,
 			      handle_retain_attribute, NULL },
   { "externally_visible",     0, 0, true,  false, false, false,
@@ -1589,6 +1592,24 @@ handle_retain_attribute (tree *pnode, tree name, tree ARG_UNUSED (args),
   return NULL_TREE;
 }
 
+/* Handle a "uninitialized" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_uninitialized_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+				int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  if (VAR_P (*node))
+    DECL_UNINITIALIZED (*node) = 1;
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
 /* Handle a "externally_visible" attribute; arguments as in
    struct attribute_spec.handler.  */
 
diff --git a/gcc/common.opt b/gcc/common.opt
index c75dd36..d0fc7bb 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -3049,6 +3049,35 @@ ftree-scev-cprop
 Common 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_D))
+-fauto-var-init-approach=[A|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(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/doc/extend.texi b/gcc/doc/extend.texi
index 0debf84..5c737d0 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -7519,6 +7519,22 @@ will be placed in new, unique sections.
 
 This additional functionality requires Binutils version 2.36 or later.
 
+@item uninitialized
+@cindex @code{uninitialized} variable attribute
+This attribute, attached to a variable with automatic storage, means that
+the variable should not be automatically initialized by the compiler when
+the option @code{-ftrivial-auto-var-init} presents.
+
+With the option @code{-ftrivial-auto-var-init}, all the automatic variables
+that do not have explicit initializers will be initialized by the compiler.
+These additional compiler initializations might incur run-time overhead,
+sometimes dramatically.  This attribute can be used to mark some variables
+to be excluded from such automatical initialization in order to reduce runtime
+overhead.
+
+This attribute has no effect when the option @code{-ftrivial-auto-var-init}
+does not present.
+
 @item vector_size (@var{bytes})
 @cindex @code{vector_size} variable attribute
 This attribute specifies the vector size for the type of the declared
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index ca204c7..0b80fcc 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -567,9 +567,9 @@ Objective-C and Objective-C++ Dialects}.
 -ftree-parallelize-loops=@var{n}  -ftree-pre  -ftree-partial-pre  -ftree-pta @gol
 -ftree-reassoc  -ftree-scev-cprop  -ftree-sink  -ftree-slsr  -ftree-sra @gol
 -ftree-switch-conversion  -ftree-tail-merge @gol
--ftree-ter  -ftree-vectorize  -ftree-vrp  -funconstrained-commons @gol
--funit-at-a-time  -funroll-all-loops  -funroll-loops @gol
--funsafe-math-optimizations  -funswitch-loops @gol
+-ftree-ter  -ftree-vectorize  -ftree-vrp  -ftrivial-auto-var-init @gol
+-funconstrained-commons -funit-at-a-time  -funroll-all-loops @gol
+-funroll-loops -funsafe-math-optimizations  -funswitch-loops @gol
 -fipa-ra  -fvariable-expansion-in-unroller  -fvect-cost-model  -fvpt @gol
 -fweb  -fwhole-program  -fwpa  -fuse-linker-plugin -fzero-call-used-regs @gol
 --param @var{name}=@var{value}
@@ -11689,6 +11689,34 @@ Perform basic block vectorization on trees. This flag is enabled by default at
 @option{-O3} and by @option{-ftree-vectorize}, @option{-fprofile-use},
 and @option{-fauto-profile}.
 
+@item -ftrivial-auto-var-init=@var{choice}
+@opindex ftrivial-auto-var-init
+Initialize automatic variables with either a pattern or with zeroes to increase
+program security by preventing uninitialized memory disclosure and use.
+
+The three values of @var{choice} are:
+
+@itemize @bullet
+@item
+@samp{uninitialized} doesn't initialize any automatic variables.
+This is C and C++'s default.
+
+@item
+@samp{pattern} Initialize automatic variables with values which will likely
+transform logic bugs into crashes down the line, are easily recognized in a
+crash dump and without being values that programmers can rely on for useful
+program semantics.
+The values used for pattern initialization might be changed in the future.
+
+@item
+@samp{zero} Initialize automatic variables with zeroes.
+@end itemize
+
+The default is @samp{uninitialized}.
+
+You can control this behavior for a specific variable by using the variable
+attribute @code{uninitialized} (@pxref{Variable Attributes}).
+
 @item -fvect-cost-model=@var{model}
 @opindex fvect-cost-model
 Alter the cost model used for vectorization.  The @var{model} argument
diff --git a/gcc/expr.c b/gcc/expr.c
index 92035c7..4a3516e 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -6566,14 +6566,19 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size,
 	    cleared = 1;
 	  }
 
-        /* If the constructor has fewer fields than the structure or
-	   if we are initializing the structure to mostly zeros, clear
-	   the whole structure first.  Don't do this if TARGET is a
-	   register whose mode size isn't equal to SIZE since
-	   clear_storage can't handle this case.  */
+	/* If the constructor has fewer fields than the structure,
+	   or if we are initializing the structure to mostly zeros,
+	   or if the user requests to initialize automatic variables with
+	   paddings inside the type,
+	   we should clear the whole structure first.
+	   Don't do this if TARGET is a register whose mode size isn't equal
+	   SIZE since clear_storage can't handle this case.  */
 	else if (known_size_p (size)
 		 && (((int) CONSTRUCTOR_NELTS (exp) != fields_length (type))
-		     || mostly_zeros_p (exp))
+		     || mostly_zeros_p (exp)
+		     || (flag_trivial_auto_var_init > AUTO_INIT_UNINITIALIZED
+			 && !TREE_STATIC (exp)
+			 && type_has_padding (type)))
 		 && (!REG_P (target)
 		     || known_eq (GET_MODE_SIZE (GET_MODE (target)), size)))
 	  {
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index a038c8f..28e3231 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -242,6 +242,18 @@ 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_D = 1
+};
+
 /* Different instrumentation modes.  */
 enum sanitize_code {
   /* AddressSanitizer.  */
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 3ec86f5..8e947bc 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -150,6 +150,7 @@ enum gf_mask {
     GF_CALL_BY_DESCRIPTOR	= 1 << 10,
     GF_CALL_NOCF_CHECK		= 1 << 11,
     GF_CALL_FROM_NEW_OR_DELETE	= 1 << 12,
+    GF_CALL_MEMSET_FOR_UNINIT	= 1 << 13,
     GF_OMP_PARALLEL_COMBINED	= 1 << 0,
     GF_OMP_TASK_TASKLOOP	= 1 << 0,
     GF_OMP_TASK_TASKWAIT	= 1 << 1,
@@ -3488,6 +3489,29 @@ gimple_call_alloca_for_var_p (gimple *s)
   return (gc->subcode & GF_CALL_ALLOCA_FOR_VAR) != 0;
 }
 
+/* If FOR_UNINIT is true, GIMPLE_CALL S is a call to builtin_memset that
+   is known to be emitted for unintialized VLA objects.  */
+
+static inline void
+gimple_call_set_memset_for_uninit (gcall *s, bool for_uninit)
+{
+  if (for_uninit)
+    s->subcode |= GF_CALL_MEMSET_FOR_UNINIT;
+  else
+    s->subcode &= ~GF_CALL_MEMSET_FOR_UNINIT;
+}
+
+/* Return true if S is a call to builtin_memset emitted for uninitialized
+   VLA objects.  */
+
+static inline bool
+gimple_call_memset_for_uninit_p (gimple *s)
+{
+  const gcall *gc = GIMPLE_CHECK2<gcall *> (s);
+  return (gc->subcode & GF_CALL_MEMSET_FOR_UNINIT) != 0;
+}
+
+
 /* If BY_DESCRIPTOR_P is true, GIMPLE_CALL S is an indirect call for which
    pointers to nested function are descriptors instead of trampolines.  */
 
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 6da6698..fafd2e9 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1716,6 +1716,116 @@ gimplify_vla_decl (tree decl, gimple_seq *seq_p)
 
   gimplify_and_add (t, seq_p);
 
+  /* Add a call to memset or calls to memcpy to initialize this vla
+     when the user requested.  */
+  if (!DECL_ARTIFICIAL (decl)
+      && VAR_P (decl)
+      && !DECL_EXTERNAL (decl)
+      && !TREE_STATIC (decl)
+      && !DECL_UNINITIALIZED (decl))
+    switch (flag_trivial_auto_var_init)
+      {
+      case AUTO_INIT_UNINITIALIZED:
+	break;
+      case AUTO_INIT_ZERO:
+	{
+	  /* Generate a call to memset to initialize this vla.  */
+	  gcall *gs;
+	  t = builtin_decl_implicit (BUILT_IN_MEMSET);
+	  gs = gimple_build_call (t, 3, addr, integer_zero_node,
+				  DECL_SIZE_UNIT (decl));
+	  gimple_call_set_memset_for_uninit (gs, true);
+	  gimplify_seq_add_stmt (seq_p, gs);
+	}
+	break;
+      case AUTO_INIT_PATTERN:
+	{
+	  /* Generate the following sequence to initialize this vla:
+	     if (DECL_SIZE_UNIT (decl) > 0) goto label_true;
+					    else goto label_cont;
+	     label_true:
+	      {
+		element_type = TREE_TYPE (TREE_TYPE (decl));
+		size_of_element = DECL_SIZE_UNIT (element_type);
+		init_node = build_pattern_cst (element_type);
+		cur = addr;
+		offset = DECL_SIZE_UNIT (decl) - size_of_element;
+		end = addr + offset;
+
+		label_loop:
+		  {
+		    memcpy (cur, &init_node, size_of_element);
+		    cur  += size_of_element;
+		    if (cur <= end) goto label_loop;
+				    else goto label_cont;
+		  }
+	      }
+	      label_cont:
+	  */
+
+	  tree size_of_element, element_type;
+	  tree cur, end, offset;
+	  tree init_node, addrof_init_node;
+	  tree t;
+
+	  tree label_true = create_artificial_label (UNKNOWN_LOCATION);
+	  tree label_cont = create_artificial_label (UNKNOWN_LOCATION);
+	  tree label_loop = create_artificial_label (UNKNOWN_LOCATION);
+
+	  element_type = TREE_TYPE (TREE_TYPE (decl));
+
+	  gcond *cond_stmt = gimple_build_cond (GT_EXPR, DECL_SIZE_UNIT (decl),
+						build_zero_cst (sizetype),
+						label_true,
+						label_cont);
+	  gimplify_seq_add_stmt (seq_p, cond_stmt);
+	  gimplify_seq_add_stmt (seq_p, gimple_build_label (label_true));
+
+	  size_of_element = create_tmp_var (sizetype,
+					    ".size_of_element");
+
+	  init_node = create_tmp_var (element_type, ".init_node");
+	  mark_addressable (init_node);
+	  addrof_init_node = build_fold_addr_expr_loc (UNKNOWN_LOCATION,
+						       init_node);
+
+	  gimplify_assign (size_of_element, TYPE_SIZE_UNIT (element_type),
+			   seq_p);
+	  gimplify_assign (init_node, build_pattern_cst (element_type), seq_p);
+
+	  cur = create_tmp_var (ptr_type, ".cur_addr");
+	  end = create_tmp_var (ptr_type, ".end_addr");
+	  offset = create_tmp_var (sizetype, ".offset");
+
+	  gimplify_assign (cur, addr, seq_p);
+	  gimplify_seq_add_stmt (seq_p,
+				 gimple_build_assign (offset, MINUS_EXPR,
+						      DECL_SIZE_UNIT (decl),
+						      size_of_element));
+	  gimplify_seq_add_stmt (seq_p,
+				 gimple_build_assign (end, POINTER_PLUS_EXPR,
+						      addr, offset));
+
+	  gimplify_seq_add_stmt (seq_p, gimple_build_label (label_loop));
+
+	  t = builtin_decl_implicit (BUILT_IN_MEMCPY);
+	  gimplify_seq_add_stmt (seq_p,
+				 gimple_build_call (t, 3, cur,
+						    addrof_init_node,
+						    size_of_element));
+	  gimplify_seq_add_stmt (seq_p,
+				 gimple_build_assign (cur, POINTER_PLUS_EXPR,
+						      cur, size_of_element));
+	  cond_stmt = gimple_build_cond (LE_EXPR, cur, end, label_loop,
+					 label_cont);
+	  gimplify_seq_add_stmt (seq_p, cond_stmt);
+	  gimplify_seq_add_stmt (seq_p, gimple_build_label (label_cont));
+	}
+	break;
+      default:
+	gcc_assert (0);
+      }
+
   /* Record the dynamic allocation associated with DECL if requested.  */
   if (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC)
     record_dynamic_alloc (decl);
@@ -1738,6 +1848,65 @@ 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:
+    gcc_assert (0);
+    break;
+  case AUTO_INIT_PATTERN:
+  case AUTO_INIT_ZERO:
+    if (init_approach == AUTO_INIT_A)
+    {
+      tree init = (init_type == AUTO_INIT_PATTERN)
+		   ? build_pattern_cst (TREE_TYPE (decl)) :
+		   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, init_type);
+      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.  */
 
@@ -1831,6 +2000,17 @@ 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
+	       && !DECL_UNINITIALIZED (decl)
+	       && !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;
@@ -5015,6 +5195,17 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 	  /* If a single access to the target must be ensured and all elements
 	     are zero, then it's optimal to clear whatever their number.  */
 	  cleared = true;
+	else if (flag_trivial_auto_var_init > AUTO_INIT_UNINITIALIZED
+		 && !TREE_STATIC (object)
+		 && type_has_padding (type))
+	  /* If the user requests to initialize automatic variables with
+	     paddings inside the type, we should initialize the paddings too.
+	     C guarantees that brace-init with fewer initializers than members
+	     aggregate will initialize the rest of the aggregate as-if it were
+	     static initialization.  In turn static initialization guarantees
+	     that pad is initialized to zero bits.
+	     So, it's better to clear the whole record under such situation.  */
+	  cleared = true;
 	else
 	  cleared = false;
 
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index dd71731..a2e2075 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -2963,6 +2963,30 @@ 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);
+  tree init = NULL_TREE;
+  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:
+      init = build_pattern_cst (TREE_TYPE (var));
+      expand_assignment (var, init, false);
+      break;
+    case AUTO_INIT_ZERO:
+      init = build_zero_cst (TREE_TYPE (var));
+      expand_assignment (var, init, false);
+      break;
+    }
+}
+
 /* The size of an OpenACC compute dimension.  */
 
 static void
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index daeace7..7249ce7 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -356,6 +356,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/testsuite/c-c++-common/auto-init-1.c b/gcc/testsuite/c-c++-common/auto-init-1.c
new file mode 100644
index 0000000..a29b18e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-1.c
@@ -0,0 +1,39 @@
+/* Verify zero initialization for integer and pointer type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-tree-gimple" } */
+
+#ifndef __cplusplus
+# define bool _Bool
+#endif
+
+enum E {
+  N1 = 0,
+  N2,
+  N3
+};
+
+extern void bar (char, short, int, enum E, long, long long, int *, bool);
+
+void foo()
+{
+  char temp1;
+  short temp2;
+  int temp3;
+  enum E temp4;
+  long temp5;
+  long long temp6;
+  int *temp7;
+  bool temp8;
+
+  bar (temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8);
+  return;
+}
+
+/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(temp1, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(temp2, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(temp3, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp4 = .DEFERRED_INIT \\(temp4, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp5 = .DEFERRED_INIT \\(temp5, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp6 = .DEFERRED_INIT \\(temp6, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp7 = .DEFERRED_INIT \\(temp7, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp8 = .DEFERRED_INIT \\(temp8, 2\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-10.c b/gcc/testsuite/c-c++-common/auto-init-10.c
new file mode 100644
index 0000000..0955889
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-10.c
@@ -0,0 +1,17 @@
+/* Verify the variable attribute "uninitialized".  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-tree-gimple" } */
+
+extern void bar (char, long long *) __attribute__ ((uninitialized)); /* { dg-warning "'uninitialized' attribute ignored" } */
+
+void foo()
+{
+  short temp1;
+  long long __attribute__ ((uninitialized)) temp2[10];
+
+  bar (temp1, temp2);
+  return;
+}
+
+/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(temp1, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump-not "temp2 = .DEFERRED_INIT \\(temp2, 1\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-11.c b/gcc/testsuite/c-c++-common/auto-init-11.c
new file mode 100644
index 0000000..12d9ed6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-11.c
@@ -0,0 +1,14 @@
+/* Verify zero initialization for VLA automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-tree-gimple" } */
+
+extern void bar (int);
+
+void foo(int n)
+{
+  int arr[n];
+  bar (arr[2]);
+  return;
+}
+
+/* { dg-final { scan-tree-dump "__builtin_memset" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-12.c b/gcc/testsuite/c-c++-common/auto-init-12.c
new file mode 100644
index 0000000..189f650
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-12.c
@@ -0,0 +1,14 @@
+/* Verify zero initialization for VLA automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-tree-gimple" } */
+
+extern void bar (int);
+
+void foo(int n)
+{
+  int arr[n];
+  bar (arr[2]);
+  return;
+}
+
+/* { dg-final { scan-tree-dump "__builtin_memcpy" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-13.c b/gcc/testsuite/c-c++-common/auto-init-13.c
new file mode 100644
index 0000000..177659c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-13.c
@@ -0,0 +1,23 @@
+/* Verify the auto initialization of structure or union with a flexible array
+   member.  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-tree-gimple" } */
+
+struct a {
+  int b;
+  int array[];
+};
+union tar {
+  struct a bar;
+  char buf;
+};
+
+int foo()
+{
+  struct a d;
+  union tar var;
+  return d.b + var.bar.b;
+}
+
+/* { dg-final { scan-tree-dump "d = .DEFERRED_INIT \\(d, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "var = .DEFERRED_INIT \\(var, 1\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-14.c b/gcc/testsuite/c-c++-common/auto-init-14.c
new file mode 100644
index 0000000..59d0503
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-14.c
@@ -0,0 +1,23 @@
+/* Verify the auto initialization of structure or union with a flexible array
+   member.  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-tree-gimple" } */
+
+struct a {
+  int b;
+  int array[];
+};
+union tar {
+  struct a bar;
+  char buf;
+};
+
+int foo()
+{
+  struct a d;
+  union tar var;
+  return d.b + var.bar.b;
+}
+
+/* { dg-final { scan-tree-dump "d = .DEFERRED_INIT \\(d, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "var = .DEFERRED_INIT \\(var, 2\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-2.c b/gcc/testsuite/c-c++-common/auto-init-2.c
new file mode 100644
index 0000000..07c2f38
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-2.c
@@ -0,0 +1,39 @@
+/* Verify pattern initialization for integer and pointer type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-tree-gimple" } */
+
+#ifndef __cplusplus
+# define bool _Bool
+#endif
+
+enum E {
+  N1 = 0,
+  N2,
+  N3
+};
+
+extern void bar (char, short, int, enum E, long, long long, int *, bool);
+
+void foo()
+{
+  char temp1;
+  short temp2;
+  int temp3;
+  enum E temp4;
+  long temp5;
+  long long temp6;
+  int *temp7;
+  bool temp8;
+
+  bar (temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8);
+  return;
+}
+
+/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(temp1, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(temp2, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(temp3, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp4 = .DEFERRED_INIT \\(temp4, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp5 = .DEFERRED_INIT \\(temp5, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp6 = .DEFERRED_INIT \\(temp6, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp7 = .DEFERRED_INIT \\(temp7, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp8 = .DEFERRED_INIT \\(temp8, 1\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-3.c b/gcc/testsuite/c-c++-common/auto-init-3.c
new file mode 100644
index 0000000..c6b301d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-3.c
@@ -0,0 +1,19 @@
+/* Verify zero initialization for floating point type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-tree-gimple" } */
+
+long double result;
+
+long double foo()
+{
+  float temp1;
+  double temp2;
+  long double temp3;
+  
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(temp1, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(temp2, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(temp3, 2\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-4.c b/gcc/testsuite/c-c++-common/auto-init-4.c
new file mode 100644
index 0000000..db23469
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-4.c
@@ -0,0 +1,19 @@
+/* Verify pattern initialization for floating point type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-tree-gimple" } */
+
+long double result;
+
+long double foo()
+{
+  float temp1;
+  double temp2;
+  long double temp3;
+  
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(temp1, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(temp2, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(temp3, 1\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-5.c b/gcc/testsuite/c-c++-common/auto-init-5.c
new file mode 100644
index 0000000..596b066
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-5.c
@@ -0,0 +1,21 @@
+/* Verify zero initialization for complex type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-tree-gimple" } */
+
+
+_Complex long double result;
+
+_Complex long double foo()
+{
+  _Complex float temp1;
+  _Complex double temp2;
+  _Complex long double temp3;
+
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(temp1, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(temp2, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(temp3, 2\\)" "gimple" } } */
+
diff --git a/gcc/testsuite/c-c++-common/auto-init-6.c b/gcc/testsuite/c-c++-common/auto-init-6.c
new file mode 100644
index 0000000..725d80a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-6.c
@@ -0,0 +1,21 @@
+/* Verify pattern initialization for complex type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-tree-gimple" } */
+
+
+_Complex long double result;
+
+_Complex long double foo()
+{
+  _Complex float temp1;
+  _Complex double temp2;
+  _Complex long double temp3;
+
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(temp1, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(temp2, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(temp3, 1\\)" "gimple" } } */
+
diff --git a/gcc/testsuite/c-c++-common/auto-init-7.c b/gcc/testsuite/c-c++-common/auto-init-7.c
new file mode 100644
index 0000000..9fd2edc
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-7.c
@@ -0,0 +1,35 @@
+/* Verify zero initialization for array, union, and structure type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-tree-gimple" } */
+
+struct S
+{
+  int f1;
+  float f2;
+  char f3[20];
+};
+
+union U
+{
+  char u1[5];
+  int u2;
+  float u3; 
+};
+
+double result;
+
+double foo()
+{
+  int temp1[3];
+  double temp2[3];
+  struct S temp3;
+  union U temp4;
+  
+  result = temp1[2] + temp2[1] + temp3.f2 + temp4.u3;
+  return result;
+}
+
+/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(temp1, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(temp2, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(temp3, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp4 = .DEFERRED_INIT \\(temp4, 2\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-8.c b/gcc/testsuite/c-c++-common/auto-init-8.c
new file mode 100644
index 0000000..06dfc97
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-8.c
@@ -0,0 +1,35 @@
+/* Verify pattern initialization for array, union, and structure type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-tree-gimple" } */
+
+struct S
+{
+  int f1;
+  float f2;
+  char f3[20];
+};
+
+union U
+{
+  char u1[5];
+  int u2;
+  float u3; 
+};
+
+double result;
+
+double foo()
+{
+  int temp1[3];
+  double temp2[3];
+  struct S temp3;
+  union U temp4;
+  
+  result = temp1[2] + temp2[1] + temp3.f2 + temp4.u3;
+  return result;
+}
+
+/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(temp1, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(temp2, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(temp3, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp4 = .DEFERRED_INIT \\(temp4, 1\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-9.c b/gcc/testsuite/c-c++-common/auto-init-9.c
new file mode 100644
index 0000000..32dd342
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-9.c
@@ -0,0 +1,17 @@
+/* Verify the variable attribute "uninitialized".  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-tree-gimple" } */
+
+extern void bar (char, long long *) __attribute__ ((uninitialized)); /* { dg-warning "'uninitialized' attribute ignored" } */
+
+void foo()
+{
+  short temp1;
+  long long __attribute__ ((uninitialized)) temp2[10];
+
+  bar (temp1, temp2);
+  return;
+}
+
+/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(temp1, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump-not "temp2 = .DEFERRED_INIT \\(temp2, 2\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-esra.c b/gcc/testsuite/c-c++-common/auto-init-esra.c
new file mode 100644
index 0000000..b204374
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-esra.c
@@ -0,0 +1,35 @@
+/* Verify the strength reduction adjustment for -ftrivial-auto-var-init.  */ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftrivial-auto-var-init=zero -fauto-var-init-approach=D -fdump-tree-gimple -fdump-tree-esra" } */
+
+
+typedef double VECTOR[3];
+
+enum
+{
+ X = 0,
+ Y = 1,
+ Z = 2,
+ T = 3
+};
+
+void Assign_Vector(VECTOR d, VECTOR s)
+{
+ d[X] = s[X];
+ d[Y] = s[Y];
+ d[Z] = s[Z];
+}
+
+void VCross(VECTOR a, const VECTOR b, const VECTOR c)
+{
+ VECTOR tmp;
+
+ tmp[X] = b[Y] * c[Z] - b[Z] * c[Y];
+ tmp[Y] = b[Z] * c[X] - b[X] * c[Z];
+ tmp[Z] = b[X] * c[Y] - b[Y] * c[X];
+
+ Assign_Vector(a, tmp);
+}
+
+/* { dg-final { scan-tree-dump-times "tmp = .DEFERRED_INIT \\(tmp, 2\\)" 1 "gimple" } } */
+/* { dg-final { scan-tree-dump-times ".DEFERRED_INIT \\(tmp" 3 "esra" } } */
diff --git a/gcc/testsuite/g++.dg/auto-init-uninit-pred-1_a.C b/gcc/testsuite/g++.dg/auto-init-uninit-pred-1_a.C
new file mode 100644
index 0000000..33c1744
--- /dev/null
+++ b/gcc/testsuite/g++.dg/auto-init-uninit-pred-1_a.C
@@ -0,0 +1,63 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized -O2 -ftrivial-auto-var-init=zero" } */
+
+typedef long long int64;
+void incr ();
+bool is_valid (int);
+int  get_time ();
+
+class A 
+{
+public:
+  A ();
+  ~A () {
+    if (I) delete I;
+  }
+
+private:
+  int* I;
+};
+
+bool get_url (A *);
+
+class M {
+
+ public:
+__attribute__ ((always_inline))  int GetC (int *c)  {
+
+    A details_str;
+    if (!get_url (&details_str))
+      {
+        incr ();
+        return 1;
+      }
+
+    *c = get_time ();
+    return -1;
+  }
+
+  void do_sth();
+  void do_sth2();
+   
+  void P (int64 t)
+    {
+      int cc; /* { dg-bogus "uninitialized" "uninitialized variable warning" }  */ 
+      if (GetC (&cc) >= 0 )
+        return;
+      
+      if (t && cc <= 0 )  /* { dg-bogus "uninitialized" "uninitialized variable warning" } */
+        {
+          this->do_sth();
+          return;
+        }
+
+    do_sth2();
+  }
+};
+
+M* m; 
+void foo(int x)
+{
+  m = new M;
+  m->P(x);
+}
diff --git a/gcc/testsuite/g++.dg/auto-init-uninit-pred-1_b.C b/gcc/testsuite/g++.dg/auto-init-uninit-pred-1_b.C
new file mode 100644
index 0000000..6b6bdae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/auto-init-uninit-pred-1_b.C
@@ -0,0 +1,63 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized -O2 -ftrivial-auto-var-init=zero" } */
+
+typedef long long int64;
+void incr ();
+bool is_valid (int);
+int  get_time ();
+
+class A 
+{
+public:
+  A ();
+  ~A () {
+    if (I) delete I;
+  }
+
+private:
+  int* I;
+};
+
+bool get_url (A *);
+
+class M {
+
+ public:
+__attribute__ ((always_inline))  int GetC (int *c)  {
+
+    A details_str;
+    if (!get_url (&details_str))
+      {
+        incr ();
+        return 1;
+      }
+
+    *c = get_time ();
+    return -1;
+  }
+
+  void do_sth();
+  void do_sth2();
+   
+  void P (int64 t)
+    {
+      int cc; /* { dg-message "note: 'cc' was declared here" } */
+      if (GetC (&cc) <= 0 ) /* return flag checked wrongly */
+        return;
+      
+      if (t && cc <= 0 )  /* { dg-warning "uninitialized" "uninitialized variable warning" } */
+        {
+          this->do_sth();
+          return;
+        }
+
+    do_sth2();
+  }
+};
+
+M* m; 
+void foo(int x)
+{
+  m = new M;
+  m->P(x);
+}
diff --git a/gcc/testsuite/g++.dg/auto-init-uninit-pred-2_a.C b/gcc/testsuite/g++.dg/auto-init-uninit-pred-2_a.C
new file mode 100644
index 0000000..fc18cb1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/auto-init-uninit-pred-2_a.C
@@ -0,0 +1,62 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized -O2 -ftrivial-auto-var-init=zero" } */
+
+typedef long long int64;
+void incr ();
+bool is_valid (int);
+int  get_time ();
+
+class A 
+{
+public:
+  A ();
+  ~A () {
+    if (I) delete I;
+  }
+
+private:
+  int* I;
+};
+
+bool get_url (A *);
+
+class M {
+
+ public:
+__attribute__ ((always_inline))  bool GetC (int *c)  {
+
+    A details_str;
+    if (get_url (&details_str))
+      {
+        *c = get_time ();
+        return true;
+      }
+
+    return false;
+  }
+
+  void do_sth();
+  void do_sth2();
+   
+  void P (int64 t)
+    {
+      int cc; 
+      if (!GetC (&cc)) /* return flag checked properly */
+        return;
+      
+      if (cc <= 0)  /* { dg-bogus "uninitialized" "uninitialized variable warning" } */
+        {
+          this->do_sth();
+          return;
+        }
+
+    do_sth2();
+  }
+};
+
+M* m; 
+void foo(int x)
+{
+  m = new M;
+  m->P(x);
+}
diff --git a/gcc/testsuite/g++.dg/auto-init-uninit-pred-2_b.C b/gcc/testsuite/g++.dg/auto-init-uninit-pred-2_b.C
new file mode 100644
index 0000000..e85a36f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/auto-init-uninit-pred-2_b.C
@@ -0,0 +1,62 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized -O2 -ftrivial-auto-var-init=zero" } */
+
+typedef long long int64;
+void incr ();
+bool is_valid (int);
+int  get_time ();
+
+class A 
+{
+public:
+  A ();
+  ~A () {
+    if (I) delete I;
+  }
+
+private:
+  int* I;
+};
+
+bool get_url (A *);
+
+class M {
+
+ public:
+__attribute__ ((always_inline))  bool GetC (int *c)  {
+
+    A details_str;
+    if (get_url (&details_str))
+      {
+        *c = get_time ();
+        return true;
+      }
+
+    return false;
+  }
+
+  void do_sth();
+  void do_sth2();
+   
+  void P (int64 t)
+    {
+      int cc; /* { dg-message "note: 'cc' was declared here" } */
+      if (GetC (&cc)) /* return flag checked wrongly */
+        return;
+      
+      if (cc <= 0)  /* { dg-warning "uninitialized" "uninitialized variable warning" } */
+        {
+          this->do_sth();
+          return;
+        }
+
+    do_sth2();
+  }
+};
+
+M* m; 
+void foo(int x)
+{
+  m = new M;
+  m->P(x);
+}
diff --git a/gcc/testsuite/g++.dg/auto-init-uninit-pred-3_a.C b/gcc/testsuite/g++.dg/auto-init-uninit-pred-3_a.C
new file mode 100644
index 0000000..09ed692
--- /dev/null
+++ b/gcc/testsuite/g++.dg/auto-init-uninit-pred-3_a.C
@@ -0,0 +1,77 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized -O2 -ftrivial-auto-var-init=zero" } */
+
+/* Multiple initialization paths.  */
+
+typedef long long int64;
+void incr ();
+bool is_valid (int);
+int  get_time ();
+
+class A
+{
+public:
+  A ();
+  ~A () {
+    if (I) delete I;
+  }
+
+private:
+  int* I;
+};
+
+bool get_url (A *);
+bool get_url2 (A *);
+
+class M {
+
+ public:
+ __attribute__ ((always_inline))
+ bool GetC (int *c)  {
+
+    A details_str;
+    /* Intialization path 1  */
+    if (get_url (&details_str))
+      {
+        *c = get_time ();
+        return true;
+      }
+
+    /* insert dtor calls (inlined) into following return paths  */
+    A tmp_str;
+
+    /* Intializtion path 2  */
+    if (get_url2 (&details_str))
+      {
+        *c = get_time ();
+        return true;
+      }
+
+    return false;
+  }
+
+  void do_sth();
+  void do_sth2();
+
+  void P (int64 t)
+    {
+      int cc;
+      if (!GetC (&cc)) /* return flag checked properly */
+        return;
+
+      if (cc <= 0)   /* { dg-bogus "uninitialized" "uninitialized variable warning" } */
+        {
+          this->do_sth();
+          return;
+        }
+
+    do_sth2();
+  }
+};
+
+M* m;
+void test(int x)
+{
+  m = new M;
+  m->P(x);
+}
diff --git a/gcc/testsuite/g++.dg/auto-init-uninit-pred-3_b.C b/gcc/testsuite/g++.dg/auto-init-uninit-pred-3_b.C
new file mode 100644
index 0000000..8e7b854
--- /dev/null
+++ b/gcc/testsuite/g++.dg/auto-init-uninit-pred-3_b.C
@@ -0,0 +1,87 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized -O2 -ftrivial-auto-var-init=zero" } */
+
+/* Multiple initialization paths.  */
+
+typedef long long int64;
+void incr ();
+bool is_valid (int);
+int  get_time ();
+
+class A
+{
+public:
+  A ();
+  ~A () {
+    if (I) delete I;
+  }
+
+private:
+  int* I;
+};
+
+bool get_url (A *);
+bool get_url2 (A *);
+bool get_url3 (A *);
+
+class M {
+
+ public:
+ __attribute__ ((always_inline))
+ bool GetC (int *c)  {
+
+    A details_str;
+
+    /* Initialization path 1  */
+    if (get_url (&details_str))
+      {
+        *c = get_time ();
+        return true;
+      }
+
+    /* Destructor call before return*/
+    A tmp_str;
+
+    /* Initialization path 2  */
+    if (get_url2 (&details_str))
+      {
+        *c = get_time ();
+        return true;
+      }
+
+    /* Fail to initialize in this path but
+       still returns true  */
+    if (get_url2 (&details_str))
+      {
+        /* Fail to initialize *c  */
+        return true;
+      }
+
+    return false;
+  }
+
+  void do_sth();
+  void do_sth2();
+
+  void P (int64 t)
+    {
+      int cc;
+      if (!GetC (&cc))
+        return;
+
+      if (cc <= 0)   /* { dg-warning "uninitialized" "uninitialized variable warning" } */
+        {
+          this->do_sth();
+          return;
+        }
+
+    do_sth2();
+  }
+};
+
+M* m;
+void test(int x)
+{
+  m = new M;
+  m->P(x);
+}
diff --git a/gcc/testsuite/g++.dg/auto-init-uninit-pred-4.C b/gcc/testsuite/g++.dg/auto-init-uninit-pred-4.C
new file mode 100644
index 0000000..c48770a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/auto-init-uninit-pred-4.C
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized -Og -ftrivial-auto-var-init=zero" } */
+
+int pop ();
+int pop_first_bucket;
+
+int my_pop ()
+{
+  int out;  // { dg-bogus "uninitialized" "uninitialized variable warning" }
+
+  while (pop_first_bucket)
+    if (pop_first_bucket && (out = pop()))
+      return out;
+
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_a.cc b/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_a.cc
new file mode 100644
index 0000000..629677a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_a.cc
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized -O2 -ftrivial-auto-var-init=zero" } */
+
+extern int bar();
+int foo(void)
+{
+ for (;;) {
+   int err = ({int _err; /*  { dg-bogus "uninitialized" "false warning" } */
+     for (int i = 0; i < 16; ++i) {
+       _err = 17;
+       _err = bar();
+     }
+     _err; /*  { dg-bogus "uninitialized" "false warning" } */
+   });
+
+   if (err == 0) return 17; 
+ }
+
+ return 18;
+}
+
diff --git a/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_b.cc b/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_b.cc
new file mode 100644
index 0000000..04ab364
--- /dev/null
+++ b/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_b.cc
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized -O2 -ftrivial-auto-var-init=zero" } */
+
+extern int bar();
+int foo(int n)
+{
+ for (;;) {
+   int err = ({int _err; 
+     for (int i = 0; i < n; ++i) {
+       _err = 17;
+       _err = bar();
+     }
+     _err; 
+   }); /* { dg-warning "uninitialized" "warn on _err" } */
+
+   if (err == 0) return 17; 
+ }
+
+ return 18;
+}
+
diff --git a/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_c.cc b/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_c.cc
new file mode 100644
index 0000000..82a1846
--- /dev/null
+++ b/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_c.cc
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized -O2 -ftrivial-auto-var-init=zero" } */
+
+extern int bar();
+int foo(int n, int m)
+{
+ for (;;) {
+   int err = ({int _err; 
+     for (int i = 0; i < 16; ++i) {
+       if (m+i > n)
+          break;
+       _err = 17;
+       _err = bar();
+     }
+     _err; 
+   }); 
+
+   if (err == 0) return 17; }); /* { dg-warning "uninitialized" "warn on _err" } */
+ }
+
+ return 18;
+}
+
diff --git a/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop_1.cc b/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop_1.cc
new file mode 100644
index 0000000..629677a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop_1.cc
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized -O2 -ftrivial-auto-var-init=zero" } */
+
+extern int bar();
+int foo(void)
+{
+ for (;;) {
+   int err = ({int _err; /*  { dg-bogus "uninitialized" "false warning" } */
+     for (int i = 0; i < 16; ++i) {
+       _err = 17;
+       _err = bar();
+     }
+     _err; /*  { dg-bogus "uninitialized" "false warning" } */
+   });
+
+   if (err == 0) return 17; 
+ }
+
+ return 18;
+}
+
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-1.c b/gcc/testsuite/gcc.dg/auto-init-uninit-1.c
new file mode 100644
index 0000000..cb0e7cc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-1.c
@@ -0,0 +1,30 @@
+/* Spurious uninitialized variable warnings, case 1.
+   Taken from cppfiles.c (merge_include_chains) */
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+struct list
+{
+  struct list *next;
+  int id;
+};
+
+extern void free (void *);
+
+void remove_dupes (struct list *el)
+{
+  struct list *p, *q, *r;  /* { dg-bogus "r" "uninitialized variable warning" } */
+
+  for (p = el; p; p = p->next)
+  {
+    for (q = el; q != p; q = q->next)
+      if (q->id == p->id)
+      {
+	r->next = p->next;
+	free (p);
+	p = r;
+	break;
+      }
+    r = p;
+  }
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-11.c b/gcc/testsuite/gcc.dg/auto-init-uninit-11.c
new file mode 100644
index 0000000..559e2d9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-11.c
@@ -0,0 +1,42 @@
+/* Positive test for uninitialized variables.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+int sink;
+
+void f1(int parm)	/* { dg-bogus "uninitialized" "parameter" } */
+{
+  sink = parm;		/* { dg-bogus "uninitialized" "parameter" } */
+}
+
+void f2(void)
+{
+  int x;
+  sink = x;		/* { dg-warning "is used" "unconditional" } */
+}
+
+void f3(int p)
+{
+  int x;		
+  if (p)
+    x = p;
+  sink = x;            /* { dg-warning "may be used" "conditional" } */
+}
+
+void f4(int p)
+{
+  int x;		/* { dg-bogus "uninitialized" "easy if" } */
+  if (p)
+    x = 1;
+  else
+    x = 2;
+  sink = x;
+}
+
+void f5(void)
+{
+  int x, i;		/* { dg-bogus "uninitialized" "easy loop" } */
+  for (i = 0; i < 10; ++i)
+    x = 1;
+  sink = x;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-12.c b/gcc/testsuite/gcc.dg/auto-init-uninit-12.c
new file mode 100644
index 0000000..acff725
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-12.c
@@ -0,0 +1,12 @@
+/* PR 23497 */
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+typedef _Complex float C;
+C foo()
+{
+  C f;
+  __real__ f = 0;
+  __imag__ f = 0;
+  return f;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-13.c b/gcc/testsuite/gcc.dg/auto-init-uninit-13.c
new file mode 100644
index 0000000..87dd8b5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-13.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+typedef _Complex float C;
+C foo()
+{
+  C f;
+  __imag__ f = 0;
+  return f;	/* { dg-warning "is used" "unconditional" } */
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-14.c b/gcc/testsuite/gcc.dg/auto-init-uninit-14.c
new file mode 100644
index 0000000..592052a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-14.c
@@ -0,0 +1,20 @@
+/* PR 24931 */
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+struct p {
+        short x, y;
+};
+
+struct s {
+        int i;
+        struct p p;
+};
+
+struct s f()
+{
+        struct s s;
+        s.p = (struct p){};
+        s.i = (s.p.x || s.p.y);
+        return s;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-15.c b/gcc/testsuite/gcc.dg/auto-init-uninit-15.c
new file mode 100644
index 0000000..121f0cf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-15.c
@@ -0,0 +1,26 @@
+/* PR tree-optimization/17506
+   We issue an uninitialized variable warning at a wrong location at
+   line 11, which is very confusing.  Make sure we print out a note to
+   make it less confusing.  (not xfailed alternative)
+   But it is of course ok if we warn in bar about uninitialized use
+   of j.  (not xfailed alternative)  */
+/* { dg-do compile } */
+/* { dg-options "-O1 -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+inline int
+foo (int i)
+{
+  if (i) /* { dg-warning "used uninitialized" } */
+    return 1;
+  return 0;
+}
+
+void baz (void);
+
+void
+bar (void)
+{
+  int j; /* { dg-message "note: 'j' was declared here" "" } */
+  for (; foo (j); ++j)  /* { dg-warning "'j' is used uninitialized" "" { xfail *-*-* } } */
+    baz ();
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-16.c b/gcc/testsuite/gcc.dg/auto-init-uninit-16.c
new file mode 100644
index 0000000..0e4f336
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-16.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+int foo, bar;
+
+static
+void decode_reloc(int reloc, int *is_alt)
+{
+  if (reloc >= 20)
+      *is_alt = 1;
+  else if (reloc >= 10)
+      *is_alt = 0;
+}
+
+void testfunc()
+{
+  int alt_reloc;
+
+  decode_reloc(foo, &alt_reloc);
+
+  if (alt_reloc) /* { dg-warning "may be used uninitialized" } */
+    bar = 42;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-17.c b/gcc/testsuite/gcc.dg/auto-init-uninit-17.c
new file mode 100644
index 0000000..9eec944
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-17.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+typedef _Complex float C;
+C foo(int cond)
+{
+  C f;
+  __imag__ f = 0;
+  if (cond)
+    {
+      __real__ f = 1;
+      return f;
+    }
+  return f;	/* { dg-warning "may be used" "unconditional" } */
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-18.c b/gcc/testsuite/gcc.dg/auto-init-uninit-18.c
new file mode 100644
index 0000000..4922848
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-18.c
@@ -0,0 +1,24 @@
+/* { dg-do compile }  */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+char *foo(int bar, char *baz)
+{
+  char *tmp;
+
+  if (bar & 3)
+    tmp = baz;
+
+  switch (bar) {
+  case 1:
+    tmp[5] = 7;    /* { dg-bogus "may be used uninitialized" } */
+    break;
+  case 2:
+    tmp[11] = 15;  /* { dg-bogus "may be used uninitialized" } */
+    break;
+  default:
+    tmp = 0;
+    break;
+  }
+
+  return tmp;      /* { dg-bogus "may be used uninitialized" } */
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-19.c b/gcc/testsuite/gcc.dg/auto-init-uninit-19.c
new file mode 100644
index 0000000..38d27e4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-19.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+/* { dg-additional-options "-finline-small-functions" { target avr-*-* } } */
+
+int a, l, m;
+float *b;
+float c, d, e, g, h;
+unsigned char i, k;
+void
+fn1 (int p1, float *f1, float *f2, float *f3, unsigned char *c1, float *f4,
+     unsigned char *c2, float *p10)
+{
+  if (p1 & 8)
+    b[3] = p10[a];
+  /* { dg-warning "may be used uninitialized" "" { target { { nonpic || pie_enabled } || { hppa*64*-*-* *-*-darwin* } } } .-1 } */
+}
+
+void
+fn2 ()
+{
+  float *n;
+  if (l & 6)
+    n = &c + m;
+  fn1 (l, &d, &e, &g, &i, &h, &k, n);
+  /* { dg-warning "may be used uninitialized" "" { target { ! { { nonpic || pie_enabled } || { hppa*64*-*-* *-*-darwin* } } } } .-1 } */
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-2.c b/gcc/testsuite/gcc.dg/auto-init-uninit-2.c
new file mode 100644
index 0000000..da03bf8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-2.c
@@ -0,0 +1,52 @@
+/* Spurious uninitialized variable warnings, case 2.
+   Taken from cpphash.c (macroexpand) */
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+struct definition
+{
+  int nargs;
+  int rest_args;
+};
+
+struct cpp_reader;
+
+enum cpp_token
+{
+  CPP_EOF, CPP_POP, CPP_COMMA, CPP_RPAREN
+};
+
+extern enum cpp_token macarg (struct cpp_reader *, int);
+
+void
+macroexpand (struct cpp_reader *pfile, struct definition *defn)
+{
+  int nargs = defn->nargs;
+
+  if (nargs >= 0)
+    {
+      enum cpp_token token;  /* { dg-bogus "token" "uninitialized variable warning" } */
+      int i, rest_args;
+      i = 0;
+      rest_args = 0;
+      do
+	{
+	  if (rest_args)
+	    continue;
+	  if (i < nargs || (nargs == 0 && i == 0))
+	    {
+	      /* if we are working on last arg which absorbs rest of args... */
+	      if (i == nargs - 1 && defn->rest_args)
+		rest_args = 1;
+	      token = macarg (pfile, rest_args);
+	    }
+	  else
+	    token = macarg (pfile, 0);
+	  if (token == CPP_EOF || token == CPP_POP)
+	    return;
+
+	  i++;
+	}
+      while (token == CPP_COMMA);
+    }
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-20.c b/gcc/testsuite/gcc.dg/auto-init-uninit-20.c
new file mode 100644
index 0000000..f533ce9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-20.c
@@ -0,0 +1,18 @@
+/* Spurious uninitialized variable warnings, from gdb */
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wuninitialized -ftrivial-auto-var-init=zero" } */
+struct os { struct o *o; };
+struct o { struct o *next; struct os *se; };
+void f(struct o *o){
+  struct os *s;
+  if(o) s = o->se;
+  while(o && s == o->se){
+    s++; // here `o' is non-zero and thus s is initialized
+    s == o->se  // `?' is essential, `if' does not trigger the warning
+      ? (o = o->next, o ? s = o->se : 0)
+      : 0;
+  }
+}
+
+
+
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-21.c b/gcc/testsuite/gcc.dg/auto-init-uninit-21.c
new file mode 100644
index 0000000..6044eab
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-21.c
@@ -0,0 +1,33 @@
+/* PR69537, spurious warning because of a missed optimization. */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-short-enums -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+enum clnt_stat {
+ RPC_SUCCESS=0,
+ RPC_CANTENCODEARGS=1,
+};
+ 
+int do_ypcall_tr ();
+ 
+static int
+yp_master (char **outname)
+{
+  // Replacing enum clnt_stat with int avoids the warning.
+  enum clnt_stat result;
+  result = do_ypcall_tr ();
+  if (result != 0)
+    return result;
+  *outname = __builtin_strdup ("foo");
+  return 0;
+}
+ 
+int
+yp_update (void)
+{
+  char *master;
+  int r;
+  if ((r = yp_master (&master)) != 0)
+    return r;
+  __builtin_free (master); /* { dg-bogus "uninitialized" } */
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-22.c b/gcc/testsuite/gcc.dg/auto-init-uninit-22.c
new file mode 100644
index 0000000..0200d73
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-22.c
@@ -0,0 +1,69 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -Wuninitialized --param vect-max-version-for-alias-checks=20 -ftrivial-auto-var-init=zero" } */
+
+#include <stdint.h>
+
+#define A1  2896 /* (1/sqrt(2))<<12 */
+#define A2  2217
+#define A3  3784
+#define A4 -5352
+
+#define IDCT_TRANSFORM(dest,s0,s1,s2,s3,s4,s5,s6,s7,d0,d1,d2,d3,d4,d5,d6,d7,munge,src) {\
+    const int a0 = (src)[s0] + (src)[s4]; \
+    const int a1 = (src)[s0] - (src)[s4]; \
+    const int a2 = (src)[s2] + (src)[s6]; \
+    const int a3 = (A1*((src)[s2] - (src)[s6])) >> 11; \
+    const int a4 = (src)[s5] + (src)[s3]; \
+    const int a5 = (src)[s5] - (src)[s3]; \
+    const int a6 = (src)[s1] + (src)[s7]; \
+    const int a7 = (src)[s1] - (src)[s7]; \
+    const int b0 = a4 + a6; \
+    const int b1 = (A3*(a5 + a7)) >> 11; \
+    const int b2 = ((A4*a5) >> 11) - b0 + b1; \
+    const int b3 = (A1*(a6 - a4) >> 11) - b2; \
+    const int b4 = ((A2*a7) >> 11) + b3 - b1; \
+    (dest)[d0] = munge(a0+a2   +b0); \
+    (dest)[d1] = munge(a1+a3-a2+b2); \
+    (dest)[d2] = munge(a1-a3+a2+b3); \
+    (dest)[d3] = munge(a0-a2   -b4); \
+    (dest)[d4] = munge(a0-a2   +b4); \
+    (dest)[d5] = munge(a1-a3+a2-b3); \
+    (dest)[d6] = munge(a1+a3-a2-b2); \
+    (dest)[d7] = munge(a0+a2   -b0); \
+}
+
+#define MUNGE_NONE(x) (x)
+#define IDCT_COL(dest,src) IDCT_TRANSFORM(dest,0,8,16,24,32,40,48,56,0,8,16,24,32,40,48,56,MUNGE_NONE,src)
+
+#define MUNGE_ROW(x) (((x) + 0x7F)>>8)
+#define IDCT_ROW(dest,src) IDCT_TRANSFORM(dest,0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,MUNGE_ROW,src)
+
+static inline void bink_idct_col(int *dest, const int32_t *src)
+{
+    if ((src[8]|src[16]|src[24]|src[32]|src[40]|src[48]|src[56])==0) {
+        dest[0]  =
+        dest[8]  =
+        dest[16] =
+        dest[24] =
+        dest[32] =
+        dest[40] =
+        dest[48] =
+        dest[56] = src[0];
+    } else {
+        IDCT_COL(dest, src);
+    }
+}
+
+int bink_idct_put_c(uint8_t *dest, int linesize, int32_t *block)
+{
+    int i;
+    int temp[64];
+    for (i = 0; i < 8; i++)
+        bink_idct_col(&temp[i], &block[i]);
+    for (i = 0; i < 8; i++) {
+        IDCT_ROW( (&dest[i*linesize]), (&temp[8*i]) );
+    }
+
+    return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-23.c b/gcc/testsuite/gcc.dg/auto-init-uninit-23.c
new file mode 100644
index 0000000..7dce8d0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-23.c
@@ -0,0 +1,27 @@
+/* PR tree-optimization/78455 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+int ij;
+
+void
+ql (void)
+{
+  int m5 = 0;
+
+  for (;;)
+  {
+    if (0)
+      for (;;)
+      {
+        int *go;
+        int *t4 = go; /* { dg-warning "is used uninitialized" } */
+
+ l1:
+        *t4 = (*t4 != 0) ? 0 : 2;
+      }
+
+    if (ij != 0)
+      goto l1;
+  }
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-24.c b/gcc/testsuite/gcc.dg/auto-init-uninit-24.c
new file mode 100644
index 0000000..1f6740c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-24.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O -Wmaybe-uninitialized -ftrivial-auto-var-init=zero" } */
+
+int foo (int x)
+{
+  int y;
+  if (x)
+    return *(&y + 1); /* { dg-bogus "may be used uninitialized" } */
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-25.c b/gcc/testsuite/gcc.dg/auto-init-uninit-25.c
new file mode 100644
index 0000000..f36d95f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-25.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-O -Wmaybe-uninitialized -ftrivial-auto-var-init=zero" } */
+
+extern unsigned bar (void);
+extern void quux (void);
+
+unsigned foo (unsigned v)
+{
+  unsigned u;
+  if (v != 1)
+    u = bar ();
+
+  // Prevent the "dom" pass from changing the CFG layout based on the inference
+  // 'if (v != 1) is false then (v != 2) is true'.  (Now it would have to
+  // duplicate the loop in order to do so, which is deemed expensive.)
+  for (int i = 0; i < 10; i++)
+    quux ();
+
+  if (v != 2)
+    return u;       /* { dg-warning "may be used uninitialized" } */
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-26.c b/gcc/testsuite/gcc.dg/auto-init-uninit-26.c
new file mode 100644
index 0000000..ae97ecf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-26.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-O -Wmaybe-uninitialized -ftrivial-auto-var-init=zero" } */
+
+extern unsigned bar (void);
+extern void quux (void);
+
+unsigned foo (unsigned v)
+{
+  unsigned u;
+  if (v != 100)
+    u = bar ();
+
+  // Prevent the "dom" pass from changing the CFG layout based on the inference
+  // 'if (v != 100) is false then (v < 105) is true'.  (Now it would have to
+  // duplicate the loop in order to do so, which is deemed expensive.)
+  for (int i = 0; i < 10; i++)
+    quux ();
+
+  if (v < 105) /* v == 100 falls into this range.  */
+    return u;       /* { dg-warning "may be used uninitialized" }  */
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-3.c b/gcc/testsuite/gcc.dg/auto-init-uninit-3.c
new file mode 100644
index 0000000..7ff2285
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-3.c
@@ -0,0 +1,33 @@
+/* Spurious uninit variable warnings, case 3.
+   Inspired by cppexp.c (parse_charconst) */
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+extern void error (char *);
+
+int
+parse_charconst (const char *start, const char *end)
+{
+  int c; /* { dg-bogus "c" "uninitialized variable warning" } */
+  int nchars, retval;
+
+  nchars = 0;
+  retval = 0;
+  while (start < end)
+    {
+      c = *start++;
+      if (c == '\'')
+	break;
+      nchars++;
+      retval += c;
+      retval <<= 8;
+    }
+
+  if (nchars == 0)
+    return 0;
+
+  if (c != '\'')
+    error ("malformed character constant");
+
+  return retval;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-34.c b/gcc/testsuite/gcc.dg/auto-init-uninit-34.c
new file mode 100644
index 0000000..98fc366
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-34.c
@@ -0,0 +1,58 @@
+/* PR middle-end/10138 - warn for uninitialized arrays passed as const*
+   arguments
+   Verify that passing pointers to uninitialized objects to arguments
+   to functions declared with attribute access is diagnosed where expected.
+   { dg-do compile }
+   { dg-options "-O -Wall -ftrivial-auto-var-init=zero" } */
+
+#define RW(...) __attribute__ ((access (read_write, __VA_ARGS__)))
+
+RW (1) RW (3) void
+f4pi (int*, int*, int*, int*);    // { dg-message "in a call to 'f4pi' declared with attribute 'access \\\(read_write, \[13\]\\\)'" }
+
+
+void nowarn_scalar (void)
+{
+  int i1 = 0, i2, i3 = 1, i4;
+  f4pi (&i1, &i2, &i3, &i4);
+}
+
+void warn_scalar_1 (void)
+{
+  int i1;                         // { dg-message "declared here" }
+  int i2, i3 = 1, i4;
+
+  f4pi (&i1, &i2, &i3, &i4);      // { dg-warning "'i1' may be used uninitialized" }
+}
+
+void warn_scalar_2 (void)
+{
+  int j1 = 0, j2, j4;
+  int j3;
+
+  f4pi (&j1, &j2, &j3, &j4);      // { dg-warning "'j3' may be used uninitialized" }
+}
+
+
+void nowarn_array_init (void)
+{
+  int a1[4] = { 0 }, a2[5], a3[6] = { 0 }, a4[7];
+
+  f4pi (a1, a2, a3, a4);
+}
+
+void warn_array_1 (void)
+{
+  int a1[4];                  // { dg-message "'a1' declared here" }
+  int a2[5], a3[6] = { 0 }, a4[7];
+
+  f4pi (a1, a2, a3, a4);      // { dg-warning "'a1' may be used uninitialized" }
+}
+
+void warn_array_2 (void)
+{
+  int a1[4] = { 0 }, a2[5], a4[7];
+  int a3[6];                  // { dg-message "'a3' declared here" }
+
+  f4pi (a1, a2, a3, a4);      // { dg-warning "'a3' may be used uninitialized" }
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-36.c b/gcc/testsuite/gcc.dg/auto-init-uninit-36.c
new file mode 100644
index 0000000..64377d3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-36.c
@@ -0,0 +1,238 @@
+/* PR middle-end/10138 - warn for uninitialized arrays passed as const*
+   arguments
+   Verify that passing pointers to uninitialized objects to const
+   arguments to built-ins is diagnosed where expected.
+   { dg-do compile }
+   { dg-options "-O -Wall -ftrivial-auto-var-init=zero" }
+   { dg-require-effective-target alloca } */
+
+typedef __SIZE_TYPE__ size_t;
+
+void* alloca (size_t);
+void* malloc (size_t);
+void* realloc (void*, size_t);
+
+void* memcpy (void*, const void*, size_t);
+char* strcpy (char*, const char*);
+size_t strlen (const char*);
+
+void sink (void*);
+
+void nowarn_array_memcpy (void *d, unsigned n)
+{
+  int a[2];
+  /* Diagnose this?  */
+  memcpy (d, a, n /* Non-constant to avoid folding into MEM_REF.  */);
+}
+
+void nowarn_array_plus_cst_memcpy (void *d, unsigned n)
+{
+  int a[3];
+  /* Diagnose this?  */
+  memcpy (d, a + 1, n);
+}
+
+void nowarn_array_plus_var_memcpy (void *d, unsigned n, int i)
+{
+  int a[4];
+  /* Diagnose this?  */
+  memcpy (d, a + i, n);
+}
+
+void nowarn_array_assign_memcpy (char *d, unsigned n)
+{
+  int a[3];
+  a[1] = 3;
+  memcpy (d, a, n);
+}
+
+void nowarn_array_init_memcpy (char *d, unsigned n)
+{
+  int a[4] = { 0 };
+  memcpy (d, a, n);
+}
+
+void nowarn_array_compound_memcpy (void *d, unsigned n)
+{
+  memcpy (d, (int[2]){ 0 }, n);
+}
+
+void nowarn_struct_assign_memcpy (void *d, unsigned n)
+{
+  struct S { int a, b, c, d; } s;
+  s.b = 1;
+  s.d = 2;
+  memcpy (d, &s, n);
+}
+
+
+void nowarn_array_init_strcpy (char *d[], unsigned n)
+{
+  char a[8] = "012";
+
+  strcpy (d[0], a);
+  strcpy (d[1], a + 1);
+  strcpy (d[1], a + 2);
+  strcpy (d[1], a + 3);
+  strcpy (d[1], a + 4);
+  strcpy (d[1], a + 5);
+  strcpy (d[1], a + 6);
+  strcpy (d[1], a + 7);
+}
+
+
+void nowarn_array_assign_strcpy (char *d[], unsigned n)
+{
+  char a[8];
+  a[0] = '0';
+  a[1] = '1';
+  a[2] = '2';
+  a[3] = '\0';
+
+  strcpy (d[0], a);
+  strcpy (d[1], a + 1);
+  strcpy (d[1], a + 2);
+  strcpy (d[1], a + 3);
+}
+
+void warn_array_plus_cst_strcpy (char *d, unsigned n)
+{
+  char a[8];
+  a[0] = '1';
+  a[1] = '2';
+  a[2] = '3';
+  a[3] = '\0';
+
+  strcpy (d, a + 4);          // { dg-warning "\\\[-Wuninitialized" }
+  strcpy (d, a + 5);          // { dg-warning "\\\[-Wuninitialized" }
+  strcpy (d, a + 6);          // { dg-warning "\\\[-Wuninitialized" }
+  strcpy (d, a + 7);          // { dg-warning "\\\[-Wuninitialized" }
+}
+
+void nowarn_array_plus_var_strcpy (char *d, int i)
+{
+  char a[8];
+  a[0] = '1';
+  a[1] = '2';
+  a[2] = '3';
+  a[3] = '\0';
+
+  strcpy (d, a + i);
+}
+
+
+size_t nowarn_array_assign_strlen (const char *s)
+{
+  char a[8];
+  a[0] = s[0];
+  a[1] = s[1];
+  a[2] = s[2];
+  a[3] = s[3];
+
+  size_t n = 0;
+
+  n += strlen (a);
+  n += strlen (a + 1);
+  n += strlen (a + 2);
+  n += strlen (a + 3);
+  return n;
+}
+
+size_t warn_array_plus_cst_strlen (const char *s)
+{
+  char a[8];
+  a[0] = s[0];
+  a[1] = s[1];
+  a[2] = s[2];
+  a[3] = s[3];
+
+  return strlen (a + 4);      // { dg-warning "\\\[-Wuninitialized" }
+}
+
+size_t nowarn_array_plus_var_strlen (const char *s, int i)
+{
+  char a[8];
+  a[0] = s[0];
+  a[1] = s[1];
+  a[2] = s[2];
+  a[3] = s[3];
+
+  return strlen (a + i);
+}
+
+
+size_t nowarn_alloca_assign_strlen (int i)
+{
+  char *p = (char*)alloca (8);
+  p[i] = '\0';
+  return strlen (p);
+}
+
+size_t nowarn_alloca_escape_strlen (int i)
+{
+  char *p = (char*)alloca (8);
+  sink (p);
+  return strlen (p);
+}
+
+size_t warn_alloca_strlen (void)
+{
+  char *p = (char*)alloca (8);
+  return strlen (p);          // { dg-warning "\\\[-Wuninitialized" }
+}
+
+
+size_t nowarn_malloc_assign_strlen (int i)
+{
+  char *p = (char*)malloc (8);
+  p[i] = '\0';
+  return strlen (p);
+}
+
+size_t nowarn_malloc_escape_strlen (int i)
+{
+  char *p = (char*)malloc (8);
+  sink (p);
+  return strlen (p);
+}
+
+size_t warn_malloc_strlen (void)
+{
+  char *p = (char*)malloc (8);
+  return strlen (p);          // { dg-warning "\\\[-Wuninitialized" }
+}
+
+
+size_t nowarn_realloc_strlen (void *p)
+{
+  char *q = (char*)realloc (p, 8);
+  return strlen (q);
+}
+
+
+size_t nowarn_vla_assign_strlen (int n, int i)
+{
+  char vla[n];
+  vla[i] = '\0';
+  return strlen (vla);
+}
+
+size_t nowarn_vla_strcpy_strlen (int n, const char *s, int i)
+{
+  char vla[n];
+  strcpy (vla, s);
+  return strlen (vla + i);
+}
+
+size_t nowarn_vla_escape_strlen (int n, int i)
+{
+  char vla[n];
+  sink (vla);
+  return strlen (vla);
+}
+
+size_t warn_vla_strlen (unsigned n)
+{
+  char vla[n];
+  return strlen (vla);        // { dg-warning "\\\[-Wuninitialized" }
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-37.c b/gcc/testsuite/gcc.dg/auto-init-uninit-37.c
new file mode 100644
index 0000000..da3c9db
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-37.c
@@ -0,0 +1,154 @@
+/* PR middle-end/10138 - warn for uninitialized arrays passed as const arguments
+   Verify that -Wuninitialized and -Wmaybe-uninitialized trigger (or don't)
+   when passing uninitialized variables by reference to functions declared
+   with or without attribute access and with (or without) const qualified
+   arguments of array, VLA, or pointer types.
+   { dg-do compile }
+   { dg-options "-O2 -Wall -ftrack-macro-expansion=0 -ftrivial-auto-var-init=zero" } */
+
+#define NONE    /* none */
+#define RO(...) __attribute__ ((access (read_only, __VA_ARGS__)))
+#define RW(...) __attribute__ ((access (read_write, __VA_ARGS__)))
+#define WO(...) __attribute__ ((access (write_only, __VA_ARGS__)))
+#define X(...)  __attribute__ ((access (none, __VA_ARGS__)))
+
+#define CONCAT(x, y) x ## y
+#define CAT(x, y)    CONCAT (x, y)
+#define UNIQ(pfx)    CAT (pfx, __LINE__)
+
+extern void sink (void*);
+
+
+#define T1(attr, name, type)			\
+  void UNIQ (CAT (test_, name))(void) {		\
+    extern attr void UNIQ (name)(type);		\
+    int x;					\
+    UNIQ (name)(&x);				\
+    sink (&x);					\
+  }
+
+#define T2(attr, name, types)			\
+  void UNIQ (CAT (test_, name))(void) {		\
+    extern attr void UNIQ (name)(types);	\
+    int x;					\
+    UNIQ (name)(1, &x);				\
+    sink (&x);					\
+  }
+
+
+typedef int IA_[];
+typedef const int CIA_[];
+
+T1 (NONE,   fia_,   IA_);
+T1 (NONE,   fcia_,  CIA_);    // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froia_, IA_);     // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwia_, IA_);     // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoia_, IA_);
+T1 (X (1),  fxia_,  IA_);
+
+
+typedef int IA1[1];
+typedef const int CIA1[1];
+
+T1 (NONE,   fia1,   IA1);
+T1 (NONE,   fcia1,  CIA1);    // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froia1, IA1);     // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwia1, IA1);     // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoia1, IA1);
+T1 (X (1),  fxia1,  IA1);
+
+
+#define IARS1  int[restrict static 1]
+#define CIARS1 const int[restrict static 1]
+
+T1 (NONE,   fiars1,   IARS1);
+T1 (NONE,   fciars1,  CIARS1);// { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froiars1, IARS1); // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwiars1, IARS1); // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoiars1, IARS1);
+T1 (X (1),  fxiars1,  IARS1);
+
+
+#define IAS1  int[static 1]
+#define CIAS1 const int[static 1]
+
+T1 (NONE,   fias1,   IAS1);
+T1 (NONE,   fcias1,  CIAS1);   // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froias1, IAS1);    // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwias1, IAS1);    // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoias1, IAS1);
+T1 (X (1),  fxias1,  IAS1);
+
+
+#define IAX  int[*]
+#define CIAX const int[*]
+
+T1 (NONE,   fiax,   IAX);
+T1 (NONE,   fciax,  CIAX);    // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froiax, IAX);     // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwiax, IAX);     // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoiax, IAX);
+T1 (X (1),  fxiax,  IAX);
+
+
+#define IAN  int n, int[n]
+#define CIAN int n, const int[n]
+
+T2 (NONE,      fian,   IAN);
+T2 (NONE,      fcian,  CIAN); // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T2 (RO (2, 1), froian, IAN);  // { dg-warning "\\\[-Wuninitialized" }
+T2 (RW (2, 1), frwian, IAN);  // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T2 (WO (2, 1), fwoian, IAN);
+T2 (X (2, 1),  fxian,  IAN);
+
+
+typedef int* IP;
+typedef const int* CIP;
+
+T1 (NONE,   fip,   IP);
+T1 (NONE,   fcip,  CIP);     // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froip, IP);      // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwip, IP);      // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoip, IP);
+T1 (X (1),  fxip,  IP);
+
+
+/* Verify that the notes printed after the warning mention attribute
+   access only when the attribute is explicitly used in the declaration
+   and not otherwise.  */
+
+void test_note_cst_restrict (void)
+{
+  extern void
+    fccar (const char[restrict]);   // { dg-message "by argument 1 of type 'const char\\\[restrict]' to 'fccar'" "note" }
+
+  char a[1];                  // { dg-message "'a' declared here" "note" }
+  fccar (a);                  // { dg-warning "'a' may be used uninitialized" }
+}
+
+void test_note_vla (int n)
+{
+  extern void
+    fccvla (const char[n]);   // { dg-message "by argument 1 of type 'const char\\\[n]' to 'fccvla'" "note" }
+
+  char a[2];                  // { dg-message "'a' declared here" "note" }
+  fccvla (a);                 // { dg-warning "'a' may be used uninitialized" }
+}
+
+void test_note_ro (void)
+{
+  extern RO (1) void
+    frocar (char[restrict]);  // { dg-message "in a call to 'frocar' declared with attribute 'access \\\(read_only, 1\\\)'" "note" }
+
+  char a[3];                  // { dg-message "'a' declared here" "note" }
+  frocar (a);                 // { dg-warning "'a' is used uninitialized" }
+}
+
+void test_note_rw (void)
+{
+  extern RW (1) void
+    frwcar (char[restrict]);  // { dg-message "in a call to 'frwcar' declared with attribute 'access \\\(read_write, 1\\\)'" "note" }
+
+  char a[4];                  // { dg-message "'a' declared here" "note" }
+  frwcar (a);                 // { dg-warning "'a' may be used uninitialized" }
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-4.c b/gcc/testsuite/gcc.dg/auto-init-uninit-4.c
new file mode 100644
index 0000000..482c837
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-4.c
@@ -0,0 +1,52 @@
+/* Spurious uninit variable warnings, case 4.
+   Simplified version of cppexp.c (cpp_parse_expr).
+
+   This one is really fragile, it gets it right if you take out case
+   1, or if the structure is replaced by an int, or if the structure
+   has fewer members (!) */
+
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+extern void abort (void);
+
+struct operation {
+    short op;
+    char rprio;
+    char flags;
+    char unsignedp;
+    long value;
+};
+
+extern struct operation cpp_lex (void);
+
+void
+cpp_parse_expr (void)
+{
+  int rprio; /* { dg-bogus "rprio" "uninitialized variable warning PR19833" } */
+  struct operation op;
+
+  for (;;)
+    {
+      op = cpp_lex ();
+
+      switch (op.op)
+	{
+	case 0:
+	  break;
+	case 1:
+	  return;
+	case 2:
+	  rprio = 1;
+	  break;
+	default:
+	  return;
+	}
+
+      if (op.op == 0)
+	return;
+
+      if (rprio != 1)
+	abort();
+    }
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-5.c b/gcc/testsuite/gcc.dg/auto-init-uninit-5.c
new file mode 100644
index 0000000..ada81c9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-5.c
@@ -0,0 +1,39 @@
+/* Spurious uninitialized-variable warnings.  */
+/* Disable jump threading, etc to test compiler analysis.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -fno-tree-dce -fno-tree-vrp -fno-tree-dominator-opts -ftrivial-auto-var-init=zero" } */
+
+extern void use(int);
+extern void foo(void);
+
+void
+func1(int cond)
+{
+    int x;  /* { dg-bogus "x" "uninitialized variable warning" } */
+
+    if(cond)
+	x = 1;
+
+    foo();
+
+    if(cond)
+	use(x);
+}
+
+void
+func2 (int cond)
+{
+    int x;  /* { dg-bogus "x" "uninitialized variable warning" } */
+    int flag = 0;
+
+    if(cond)
+    {
+	x = 1;
+	flag = 1;
+    }
+
+    foo();
+
+    if(flag)
+	use(x);
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-6.c b/gcc/testsuite/gcc.dg/auto-init-uninit-6.c
new file mode 100644
index 0000000..e6cba4e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-6.c
@@ -0,0 +1,47 @@
+/* Spurious uninitialized variable warnings.
+   This one inspired by java/class.c:build_utf8_ref.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+#include <stddef.h>
+
+struct tree
+{
+    struct tree *car;
+    struct tree *cdr;
+    int type, data;
+};
+
+extern void *malloc(size_t);
+
+#define INTEGER_T 1
+#define PTR_T	  2
+
+#define APPEND(TREE, LAST, TYPE, VALUE)				\
+do {								\
+     struct tree *tmp = malloc (sizeof (struct tree));		\
+     tmp->car = 0; tmp->cdr = 0; tmp->type = TYPE;		\
+     tmp->data = VALUE;						\
+     if (TREE->car)						\
+	 LAST->cdr = tmp;					\
+     else							\
+	 TREE->car = tmp;					\
+     LAST = tmp;						\
+} while(0)
+ 
+struct tree *
+make_something(int a, int b, int c)
+{
+    struct tree *rv;
+    struct tree *field;
+
+    rv = malloc (sizeof (struct tree));
+    rv->car = 0;
+
+    APPEND(rv, field, INTEGER_T, a);  /* { dg-bogus "field" "uninitialized variable warning" } */
+    APPEND(rv, field, PTR_T, b);
+    APPEND(rv, field, INTEGER_T, c);
+
+    return rv;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-8.c b/gcc/testsuite/gcc.dg/auto-init-uninit-8.c
new file mode 100644
index 0000000..6c29887
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-8.c
@@ -0,0 +1,32 @@
+/* Uninitialized variable warning tests...
+   Inspired by part of optabs.c:expand_binop.
+   May be the same as uninit-1.c.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+#include <limits.h>
+
+void
+add_bignums (int *out, int *x, int *y)
+{
+    int p, sum;
+    int carry; /* { dg-bogus "carry" "uninitialized variable warning" } */
+
+    p = 0;
+    for (; *x; x++, y++, out++, p++)
+    {
+	if (p)
+	    sum = *x + *y + carry;
+	else
+	    sum = *x + *y;
+
+	if (sum < 0)
+	{
+	    carry = 1;
+	    sum -= INT_MAX;
+	}
+	else
+	    carry = 0;
+    }
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-9.c b/gcc/testsuite/gcc.dg/auto-init-uninit-9.c
new file mode 100644
index 0000000..9d65493
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-9.c
@@ -0,0 +1,42 @@
+/* Spurious uninitialized variable warnings.  Slight variant on the
+   documented case, inspired by reg-stack.c:record_asm_reg_life.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+/* { dg-require-effective-target alloca } */
+
+struct foo
+{
+    int type;
+    struct foo *car;
+    struct foo *cdr;
+    char *data;
+    int data2;
+};
+
+extern void use(struct foo *);
+
+#define CLOBBER 6
+#define PARALLEL 3
+
+void
+func(struct foo *list, int count)
+{
+    int n_clobbers = 0;
+    int i;
+    struct foo **clob_list;   /* { dg-bogus "clob_list" "uninitialized variable warning" } */
+
+    if(list[0].type == PARALLEL)
+    {
+	clob_list = __builtin_alloca(count * sizeof(struct foo *));
+	
+	for(i = 1; i < count; i++)
+	{
+	    if(list[i].type == CLOBBER)
+		clob_list[n_clobbers++] = &list[i];
+	}
+    }
+
+    for(i = 0; i < n_clobbers; i++)
+	use(clob_list[i]);
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-A.c b/gcc/testsuite/gcc.dg/auto-init-uninit-A.c
new file mode 100644
index 0000000..01fcf59
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-A.c
@@ -0,0 +1,117 @@
+/* Inspired by part of java/parse.y.
+   May be a real bug in CSE. */
+
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wall -ftrivial-auto-var-init=zero" } */
+
+struct tree
+{
+    struct tree *car, *cdr, *wfl;
+    int code;
+    struct { unsigned int renp:1;
+      unsigned int rtnp:1;
+      unsigned int rpnp:1; } flags;
+};
+typedef struct tree *tree;
+#define NULL_TREE ((tree)0)
+
+/* Codes */
+enum
+{
+    CALL_EXPR, NEW_ARRAY_EXPR, NEW_CLASS_EXPR, CONVERT_EXPR,
+    ARRAY_REF, CONDITIONAL_EXPR, STRING_CST, EXPR_WITH_FILE_LOCATION
+};
+
+/* Flags */
+#define RESOLVE_EXPRESSION_NAME_P(t) ((t)->flags.renp)
+#define RESOLVE_TYPE_NAME_P(t) ((t)->flags.rtnp)
+#define RESOLVE_PACKAGE_NAME_P(t) ((t)->flags.rpnp)
+
+/* Macros */
+#define EXPR_WFL_QUALIFICATION(t) ((t)->wfl)
+#define QUAL_WFL(t) ((t)->wfl)
+#define EXPR_WFL_NODE(t) ((t)->wfl)
+#define TREE_CODE(t) ((t)->code)
+#define TREE_OPERAND(t,x) ((t)->car)
+#define CLASSTYPE_SUPER(t) ((t)->car)
+#define IDENTIFIER_LOCAL_VALUE(t) ((t)->car)
+#define TREE_CHAIN(t) ((t)->cdr)
+#define QUAL_RESOLUTION(t) ((t)->cdr)
+
+extern tree current_class, this_identifier_node;
+extern tree super_identifier_node, length_identifier_node;
+
+tree resolve_and_layout (tree, tree);
+tree lookup_field_wrapper (tree, tree);
+
+void
+qualify_ambiguous_name (id)
+     tree id;
+{
+  tree qual, qual_wfl, decl;
+  tree name;	 /* { dg-bogus "name" "uninitialized variable warning" } */
+  tree ptr_type; /* { dg-bogus "ptr_type" "uninitialized variable warning" } */
+  int again, new_array_found = 0;
+  int super_found = 0, this_found = 0;
+
+  qual = EXPR_WFL_QUALIFICATION (id);
+  do {
+    qual_wfl = QUAL_WFL (qual);
+    switch (TREE_CODE (qual_wfl))
+      {
+      case CALL_EXPR:
+	qual_wfl = TREE_OPERAND (qual_wfl, 0);
+	if (TREE_CODE (qual_wfl) != EXPR_WITH_FILE_LOCATION)
+	  {
+	    qual = EXPR_WFL_QUALIFICATION (qual_wfl);
+	    qual_wfl = QUAL_WFL (qual);
+	  }
+	break;
+      case NEW_ARRAY_EXPR:
+	qual = TREE_CHAIN (qual);
+	new_array_found = again = 1;
+	continue;
+      case NEW_CLASS_EXPR:
+      case CONVERT_EXPR:
+	qual_wfl = TREE_OPERAND (qual_wfl, 0);
+	break;
+      case ARRAY_REF:
+	while (TREE_CODE (qual_wfl) == ARRAY_REF)
+	  qual_wfl = TREE_OPERAND (qual_wfl, 0);
+	break;
+      default:
+	break;
+      }
+
+    name = EXPR_WFL_NODE (qual_wfl);
+    ptr_type = current_class;
+    again = 0;
+
+  } while (again);
+
+  /* If you put straightforward uses of name and ptr_type here
+     instead of the if-else sequence below, the warnings go away.
+     Therefore I suspect a real bug. */
+  
+  if (!this_found && !super_found && (decl = IDENTIFIER_LOCAL_VALUE (name)))
+    {
+      RESOLVE_EXPRESSION_NAME_P (qual_wfl) = 1;
+      QUAL_RESOLUTION (qual) = decl;
+    }
+  else if ((decl = lookup_field_wrapper (ptr_type, name))
+	   || (new_array_found && name == length_identifier_node))
+    {
+      RESOLVE_EXPRESSION_NAME_P (qual_wfl) = 1;
+      QUAL_RESOLUTION (qual) = (new_array_found ? NULL_TREE : decl);
+    }
+  else if ((decl = resolve_and_layout (name, NULL_TREE)))
+    {
+      RESOLVE_TYPE_NAME_P (qual_wfl) = 1;
+      QUAL_RESOLUTION (qual) = decl;
+    }
+  else if (TREE_CODE (QUAL_WFL (qual)) == CALL_EXPR
+	   || TREE_CODE (QUAL_WFL (qual)) == ARRAY_REF)
+    RESOLVE_EXPRESSION_NAME_P (qual_wfl) = 1;
+  else 
+    RESOLVE_PACKAGE_NAME_P (qual_wfl) = 1;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-B.c b/gcc/testsuite/gcc.dg/auto-init-uninit-B.c
new file mode 100644
index 0000000..0b28371
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-B.c
@@ -0,0 +1,15 @@
+/* Origin: PR c/179 from Gray Watson <gray@256.com>, adapted as a testcase
+   by Joseph Myers <jsm28@cam.ac.uk>.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wuninitialized -ftrivial-auto-var-init=zero" } */
+extern void foo (int *);
+extern void bar (int);
+
+void
+baz (void)
+{
+  int i;
+  if (i) /* { dg-warning "is used uninitialized" "uninit i warning" } */
+    bar (i);
+  foo (&i);
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-C.c b/gcc/testsuite/gcc.dg/auto-init-uninit-C.c
new file mode 100644
index 0000000..a4aa629
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-C.c
@@ -0,0 +1,21 @@
+/* Spurious uninitialized variable warning, inspired by libgcc2.c.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+/* Not all platforms support TImode integers.  */
+#if defined(__LP64__) && !defined(__hppa__)
+typedef int TItype __attribute__ ((mode (TI)));
+#else
+typedef long TItype;
+#endif
+
+
+TItype
+__subvdi3 (TItype a, TItype b)
+{
+  TItype w;
+  
+  w = a - b;
+  
+  return w;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-H.c b/gcc/testsuite/gcc.dg/auto-init-uninit-H.c
new file mode 100644
index 0000000..71e2e2d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-H.c
@@ -0,0 +1,33 @@
+/* PR 14204 */
+/* { dg-do compile } */
+/* { dg-options "-O -Wall -Werror -ftrivial-auto-var-init=zero" } */
+
+#if defined __alpha__
+# define ASM __asm__("$30")
+#elif defined __i386__
+# define ASM __asm__("esp")
+#elif defined (__powerpc__) || defined (__PPC__) || defined (__ppc__) || defined (_POWER)
+# define ASM __asm__("r1")
+#elif defined __s390__
+# define ASM __asm__("r15")
+#elif defined __mips
+# define ASM __asm__("$sp")
+#elif defined __sparc__
+# define ASM __asm__("sp")
+#elif defined __ia64__
+# define ASM __asm__("r12")
+#elif defined __hppa__
+# define ASM __asm__("%r30")
+#elif defined __xtensa__
+# define ASM __asm__("sp")
+#else
+/* The register name should be target-dependent so for other targets,
+   we just silence the test.  */
+# define ASM = 0
+#endif
+
+void *load_PCB (void)
+{
+  register void *sp ASM;
+  return sp;			/* { dg-bogus "uninitialized" } */
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-I.c b/gcc/testsuite/gcc.dg/auto-init-uninit-I.c
new file mode 100644
index 0000000..09680fe
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-I.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+int sys_msgctl (void)
+{
+  struct { int mode; } setbuf;
+  return setbuf.mode;  /* { dg-warning "'setbuf\.mode' is used" } */
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-1.c b/gcc/testsuite/gcc.target/aarch64/auto-init-1.c
new file mode 100644
index 0000000..0fa4708
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-1.c
@@ -0,0 +1,32 @@
+/* Verify zero initialization for integer and pointer type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand" } */
+
+#ifndef __cplusplus
+# define bool _Bool
+#endif
+
+enum E {
+  N1 = 0,
+  N2,
+  N3
+};
+
+extern void bar (char, short, int, enum E, long, long long, int *, bool);
+
+void foo()
+{
+  char temp1;
+  short temp2;
+  int temp3;
+  enum E temp4;
+  long temp5;
+  long long temp6;
+  int *temp7;
+  bool temp8;
+
+  bar (temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8);
+  return;
+}
+
+/* { dg-final { scan-rtl-dump-times "const_int 0" 11 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-10.c b/gcc/testsuite/gcc.target/aarch64/auto-init-10.c
new file mode 100644
index 0000000..aceceb8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-10.c
@@ -0,0 +1,18 @@
+/* Verify pattern initialization for structure type automatic variables with
+   padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_aligned {
+        int internal1;
+        long long internal2;
+} __attribute__ ((aligned(64)));
+
+int foo ()
+{
+  struct test_aligned var;
+  return var.internal1;
+}
+
+/* { dg-final { scan-assembler-times "stp\tq0, q0," 2 } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-11.c b/gcc/testsuite/gcc.target/aarch64/auto-init-11.c
new file mode 100644
index 0000000..085c386
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-11.c
@@ -0,0 +1,27 @@
+/* Verify zero initialization for nested structure type automatic variables with
+   padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_aligned {
+        unsigned internal1;
+        unsigned long long internal2;
+} __attribute__ ((aligned(64)));
+
+struct test_big_hole {
+        char one;
+        char two;
+        char three;
+        /* 61 byte padding hole here. */
+        struct test_aligned four;
+} __attribute__ ((aligned(64)));
+
+
+int foo ()
+{
+  struct test_big_hole var;
+  return var.four.internal1;
+}
+
+/* { dg-final { scan-assembler-times "stp\tq0, q0," 4 } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-12.c b/gcc/testsuite/gcc.target/aarch64/auto-init-12.c
new file mode 100644
index 0000000..5d1383b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-12.c
@@ -0,0 +1,27 @@
+/* Verify pattern initialization for nested structure type automatic variables with
+   padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_aligned {
+        unsigned internal1;
+        unsigned long long internal2;
+} __attribute__ ((aligned(64)));
+
+struct test_big_hole {
+        char one;
+        char two;
+        char three;
+        /* 61 byte padding hole here. */
+        struct test_aligned four;
+} __attribute__ ((aligned(64)));
+
+
+int foo ()
+{
+  struct test_big_hole var;
+  return var.four.internal1;
+}
+
+/* { dg-final { scan-assembler-times "stp\tq0, q0," 4 } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-13.c b/gcc/testsuite/gcc.target/aarch64/auto-init-13.c
new file mode 100644
index 0000000..3c45a6c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-13.c
@@ -0,0 +1,22 @@
+/* Verify zero initialization for structure type automatic variables with
+   tail padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_trailing_hole {
+        char *one;
+        char *two;
+        char *three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+int foo ()
+{
+  struct test_trailing_hole var;
+  return var.four;
+}
+
+/* { dg-final { scan-assembler-times "stp\txzr, xzr," 2 } } */
+
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-14.c b/gcc/testsuite/gcc.target/aarch64/auto-init-14.c
new file mode 100644
index 0000000..500020e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-14.c
@@ -0,0 +1,20 @@
+/* Verify pattern initialization for structure type automatic variables with
+   tail padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_trailing_hole {
+        char *one;
+        char *two;
+        char *three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+int foo ()
+{
+  struct test_trailing_hole var;
+  return var.four;
+}
+
+/* { dg-final { scan-assembler-times "stp\txzr, xzr," 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-15.c b/gcc/testsuite/gcc.target/aarch64/auto-init-15.c
new file mode 100644
index 0000000..cb96c3a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-15.c
@@ -0,0 +1,20 @@
+/* Verify zero initialization for structure type automatic variables with
+   padding and has explicit initialization.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+int foo ()
+{
+  struct test_trailing_hole var = {.one = 1,.two = 2, .four = 'c'};
+  return var.four;
+}
+
+/* { dg-final { scan-assembler "stp\txzr, xzr," } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-16.c b/gcc/testsuite/gcc.target/aarch64/auto-init-16.c
new file mode 100644
index 0000000..ce7c7cd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-16.c
@@ -0,0 +1,22 @@
+/* Verify pattern initialization for structure type automatic variables with
+   padding and has explicit initialization.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+int foo ()
+{
+  struct test_trailing_hole var = {.one = 1,.two = 2, .four = 'c'};
+  return var.four;
+}
+
+/* { dg-final { scan-assembler "stp\txzr, xzr," } } */
+
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-17.c b/gcc/testsuite/gcc.target/aarch64/auto-init-17.c
new file mode 100644
index 0000000..c81e5ff
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-17.c
@@ -0,0 +1,21 @@
+/* Verify zero initialization for array type with structure element with
+   padding.  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+
+int foo ()
+{
+  struct test_trailing_hole var[10]; 
+  return var[2].four;
+}
+
+/* { dg-final { scan-assembler-times "stp\tq0, q0," 5 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-18.c b/gcc/testsuite/gcc.target/aarch64/auto-init-18.c
new file mode 100644
index 0000000..0ec0ac4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-18.c
@@ -0,0 +1,21 @@
+/* Verify pattern initialization for array type with structure element with
+   padding.  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+
+int foo ()
+{
+  struct test_trailing_hole var[10]; 
+  return var[2].four;
+}
+
+/* { dg-final { scan-assembler-times "str\tw0, " 30 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-19.c b/gcc/testsuite/gcc.target/aarch64/auto-init-19.c
new file mode 100644
index 0000000..02f7edc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-19.c
@@ -0,0 +1,27 @@
+/* Verify zero initialization for union type with structure field with
+   padding.  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+union test_union_padding {
+  struct test_trailing_hole u1;
+  long long u2;
+};
+
+
+int foo ()
+{
+  union test_union_padding var;
+  return var.u1.four;
+}
+
+/* { dg-final { scan-assembler "stp\txzr, xzr," } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-2.c b/gcc/testsuite/gcc.target/aarch64/auto-init-2.c
new file mode 100644
index 0000000..2cbe34e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-2.c
@@ -0,0 +1,37 @@
+/* Verify pattern initialization for integer and pointer type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */
+
+#ifndef __cplusplus
+# define bool _Bool
+#endif
+
+enum E {
+  N1 = 0,
+  N2,
+  N3
+};
+
+extern void bar (char, short, int, enum E, long, long long, int *, bool);
+
+void foo()
+{
+  char temp1;
+  short temp2;
+  int temp3;
+  enum E temp4;
+  long temp5;
+  long long temp6;
+  int *temp7;
+  bool temp8;
+
+  bar (temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8);
+  return;
+}
+
+/* { dg-final { scan-rtl-dump-times "0xffffffffffffffaa" 1 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xffffffffffffaaaa" 1 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xffffffffaaaaaaaa" 2 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xaaaaaaaaaaaaaaaa" 3 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "const_int 0" 4 "expand" } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-20.c b/gcc/testsuite/gcc.target/aarch64/auto-init-20.c
new file mode 100644
index 0000000..0ef9acd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-20.c
@@ -0,0 +1,27 @@
+/* Verify pattern initialization for union type with structure field with
+   padding.  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+union test_union_padding {
+  struct test_trailing_hole u1;
+  long long u2;
+};
+
+
+int foo ()
+{
+  union test_union_padding var;
+  return var.u1.four;
+}
+
+/* { dg-final { scan-assembler "stp\txzr, xzr," } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-3.c b/gcc/testsuite/gcc.target/aarch64/auto-init-3.c
new file mode 100644
index 0000000..78291a1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-3.c
@@ -0,0 +1,19 @@
+/* Verify zero initialization for floating point type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand" } */
+
+long double result;
+
+long double foo()
+{
+  float temp1;
+  double temp2;
+  long double temp3;
+  
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-rtl-dump "const_double:SF 0.0" "expand" } } */
+/* { dg-final { scan-rtl-dump "const_double:DF 0.0" "expand" } } */
+/* { dg-final { scan-rtl-dump "const_double:TF 0.0" "expand" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-4.c b/gcc/testsuite/gcc.target/aarch64/auto-init-4.c
new file mode 100644
index 0000000..53b8203
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-4.c
@@ -0,0 +1,19 @@
+/* Verify pattern initialization for floating point type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */
+
+long double result;
+
+long double foo()
+{
+  float temp1;
+  double temp2;
+  long double temp3;
+  
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-rtl-dump "const_double:SF \\+QNaN" "expand" } } */
+/* { dg-final { scan-rtl-dump "const_double:DF \\+QNaN" "expand" } } */
+/* { dg-final { scan-rtl-dump "const_double:TF \\+QNaN" "expand" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-5.c b/gcc/testsuite/gcc.target/aarch64/auto-init-5.c
new file mode 100644
index 0000000..092f83e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-5.c
@@ -0,0 +1,19 @@
+/* Verify zero initialization for complex type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+
+_Complex long double result;
+
+_Complex long double foo()
+{
+  _Complex float temp1;
+  _Complex double temp2;
+  _Complex long double temp3;
+
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-assembler-times ".word\\t0" 14 } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-6.c b/gcc/testsuite/gcc.target/aarch64/auto-init-6.c
new file mode 100644
index 0000000..8cea598
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-6.c
@@ -0,0 +1,21 @@
+/* Verify pattern initialization for complex type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+
+_Complex long double result;
+
+_Complex long double foo()
+{
+  _Complex float temp1;
+  _Complex double temp2;
+  _Complex long double temp3;
+
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-assembler-times ".word\\t2143289344" 2 } } */
+/* { dg-final { scan-assembler-times ".word\\t2146959360" 2 } } */
+/* { dg-final { scan-assembler-times ".word\\t2147450880" 2 } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-7.c b/gcc/testsuite/gcc.target/aarch64/auto-init-7.c
new file mode 100644
index 0000000..ac27fbe
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-7.c
@@ -0,0 +1,32 @@
+/* Verify zero initialization for array, union, and structure type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand" } */
+
+struct S
+{
+  int f1;
+  float f2;
+  char f3[20];
+};
+
+union U
+{
+  char u1[5];
+  int u2;
+  float u3; 
+};
+
+double result;
+
+double foo()
+{
+  int temp1[3];
+  double temp2[3];
+  struct S temp3;
+  union U temp4;
+  
+  result = temp1[2] + temp2[1] + temp3.f2 + temp4.u3;
+  return result;
+}
+
+/* { dg-final { scan-rtl-dump-times "const_int 0" 8 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-8.c b/gcc/testsuite/gcc.target/aarch64/auto-init-8.c
new file mode 100644
index 0000000..2f1de12
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-8.c
@@ -0,0 +1,33 @@
+/* Verify pattern initialization for array, union, and structure type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */
+
+struct S
+{
+  int f1;
+  float f2;
+  char f3[20];
+};
+
+union U
+{
+  char u1[5];
+  int u2;
+  float u3; 
+};
+
+double result;
+
+double foo()
+{
+  int temp1[3];
+  double temp2[3];
+  struct S temp3;
+  union U temp4;
+  
+  result = temp1[2] + temp2[1] + temp3.f2 + temp4.u3;
+  return result;
+}
+
+/* { dg-final { scan-rtl-dump-times "0xffffffffaaaaaaaa" 4 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xffffffffffffffaa" 25 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-9.c b/gcc/testsuite/gcc.target/aarch64/auto-init-9.c
new file mode 100644
index 0000000..7294de5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-9.c
@@ -0,0 +1,19 @@
+/* Verify zero initialization for structure type automatic variables with
+   padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_aligned {
+        int internal1;
+        long long internal2;
+} __attribute__ ((aligned(64)));
+
+int foo ()
+{
+  struct test_aligned var;
+  return var.internal1;
+}
+
+/* { dg-final { scan-assembler-times "stp\tq0, q0," 2 } } */
+
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-1.c b/gcc/testsuite/gcc.target/i386/auto-init-1.c
new file mode 100644
index 0000000..b7690df
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-1.c
@@ -0,0 +1,32 @@
+/* Verify zero initialization for integer and pointer type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand" } */
+
+#ifndef __cplusplus
+# define bool _Bool
+#endif
+
+enum E {
+  N1 = 0,
+  N2,
+  N3
+};
+
+extern void bar (char, short, int, enum E, long, long long, int *, bool);
+
+void foo()
+{
+  char temp1;
+  short temp2;
+  int temp3;
+  enum E temp4;
+  long temp5;
+  long long temp6;
+  int *temp7;
+  bool temp8;
+
+  bar (temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8);
+  return;
+}
+
+/* { dg-final { scan-rtl-dump-times "const_int 0" 10 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-10.c b/gcc/testsuite/gcc.target/i386/auto-init-10.c
new file mode 100644
index 0000000..88f95b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-10.c
@@ -0,0 +1,19 @@
+/* Verify pattern initialization for structure type automatic variables with
+   padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_aligned {
+        int internal1;
+        long long internal2;
+} __attribute__ ((aligned(64)));
+
+int foo ()
+{
+  struct test_aligned var;
+  return var.internal1;
+}
+
+/* { dg-final { scan-assembler-times "movq\t\\\$0," 8 } } */
+
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-11.c b/gcc/testsuite/gcc.target/i386/auto-init-11.c
new file mode 100644
index 0000000..8a6d764
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-11.c
@@ -0,0 +1,30 @@
+/* Verify zero initialization for nested structure type automatic variables with
+   padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_aligned {
+        unsigned internal1;
+        unsigned long long internal2;
+} __attribute__ ((aligned(64)));
+
+struct test_big_hole {
+        char one;
+        char two;
+        char three;
+        /* 61 byte padding hole here. */
+        struct test_aligned four;
+} __attribute__ ((aligned(64)));
+
+
+int foo ()
+{
+  struct test_big_hole var;
+  return var.four.internal1;
+}
+
+/* { dg-final { scan-assembler "movl\t\\\$0," } } */
+/* { dg-final { scan-assembler "movl\t\\\$16," } } */
+/* { dg-final { scan-assembler "rep stosq" } } */
+
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-12.c b/gcc/testsuite/gcc.target/i386/auto-init-12.c
new file mode 100644
index 0000000..b5a7bd4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-12.c
@@ -0,0 +1,30 @@
+/* Verify pattern initialization for nested structure type automatic variables with
+   padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_aligned {
+        unsigned internal1;
+        unsigned long long internal2;
+} __attribute__ ((aligned(64)));
+
+struct test_big_hole {
+        char one;
+        char two;
+        char three;
+        /* 61 byte padding hole here. */
+        struct test_aligned four;
+} __attribute__ ((aligned(64)));
+
+
+int foo ()
+{
+  struct test_big_hole var;
+  return var.four.internal1;
+}
+
+/* { dg-final { scan-assembler "movl\t\\\$0," } } */
+/* { dg-final { scan-assembler "movl\t\\\$16," } } */
+/* { dg-final { scan-assembler "rep stosq" } } */
+
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-13.c b/gcc/testsuite/gcc.target/i386/auto-init-13.c
new file mode 100644
index 0000000..e18bc30
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-13.c
@@ -0,0 +1,22 @@
+/* Verify zero initialization for structure type automatic variables with
+   tail padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_trailing_hole {
+        char *one;
+        char *two;
+        char *three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+int foo ()
+{
+  struct test_trailing_hole var;
+  return var.four;
+}
+
+/* { dg-final { scan-assembler-times "movq\t\\\$0," 4 } } */
+
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-14.c b/gcc/testsuite/gcc.target/i386/auto-init-14.c
new file mode 100644
index 0000000..55a4c9d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-14.c
@@ -0,0 +1,22 @@
+/* Verify pattern initialization for structure type automatic variables with
+   tail padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_trailing_hole {
+        char *one;
+        char *two;
+        char *three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+int foo ()
+{
+  struct test_trailing_hole var;
+  return var.four;
+}
+
+/* { dg-final { scan-assembler-times "movq\t\\\$0," 4 } } */
+
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-15.c b/gcc/testsuite/gcc.target/i386/auto-init-15.c
new file mode 100644
index 0000000..b5abffb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-15.c
@@ -0,0 +1,22 @@
+/* Verify zero initialization for structure type automatic variables with
+   padding and has explicit initialization.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+int foo ()
+{
+  struct test_trailing_hole var = {.one = 1,.two = 2, .four = 'c'};
+  return var.four;
+}
+
+/* { dg-final { scan-assembler-times "movq\t\\\$0," 2 } } */
+
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-16.c b/gcc/testsuite/gcc.target/i386/auto-init-16.c
new file mode 100644
index 0000000..66591cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-16.c
@@ -0,0 +1,22 @@
+/* Verify pattern initialization for structure type automatic variables with
+   padding and has explicit initialization.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+int foo ()
+{
+  struct test_trailing_hole var = {.one = 1,.two = 2, .four = 'c'};
+  return var.four;
+}
+
+/* { dg-final { scan-assembler-times "movq\t\\\$0," 2 } } */
+
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-17.c b/gcc/testsuite/gcc.target/i386/auto-init-17.c
new file mode 100644
index 0000000..40fccad
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-17.c
@@ -0,0 +1,23 @@
+/* Verify zero initialization for array type with structure element with
+   padding.  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+
+int foo ()
+{
+  struct test_trailing_hole var[10]; 
+  return var[2].four;
+}
+
+/* { dg-final { scan-assembler "movl\t\\\$0," } } */
+/* { dg-final { scan-assembler "movl\t\\\$20," } } */
+/* { dg-final { scan-assembler "rep stosq" } } */
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-18.c b/gcc/testsuite/gcc.target/i386/auto-init-18.c
new file mode 100644
index 0000000..a422a8d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-18.c
@@ -0,0 +1,21 @@
+/* Verify pattern initialization for array type with structure element with
+   padding.  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+
+int foo ()
+{
+  struct test_trailing_hole var[10]; 
+  return var[2].four;
+}
+
+/* { dg-final { scan-assembler-times "movq\t\\\$0," 20 } } */
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-19.c b/gcc/testsuite/gcc.target/i386/auto-init-19.c
new file mode 100644
index 0000000..31a3ee1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-19.c
@@ -0,0 +1,26 @@
+/* Verify zero initialization for union type with structure field with
+   padding.  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+union test_union_padding {
+  struct test_trailing_hole u1;
+  long long u2;
+};
+
+
+int foo ()
+{
+  union test_union_padding var;
+  return var.u1.four;
+}
+
+/* { dg-final { scan-assembler-times "movq\t\\\$0," 2 } } */
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-2.c b/gcc/testsuite/gcc.target/i386/auto-init-2.c
new file mode 100644
index 0000000..c7e006e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-2.c
@@ -0,0 +1,37 @@
+/* Verify pattern initialization for integer and pointer type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */
+
+#ifndef __cplusplus
+# define bool _Bool
+#endif
+
+enum E {
+  N1 = 0,
+  N2,
+  N3
+};
+
+extern void bar (char, short, int, enum E, long, long long, int *, bool);
+
+void foo()
+{
+  char temp1;
+  short temp2;
+  int temp3;
+  enum E temp4;
+  long temp5;
+  long long temp6;
+  int *temp7;
+  bool temp8;
+
+  bar (temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8);
+  return;
+}
+
+/* { dg-final { scan-rtl-dump-times "0xffffffffffffffaa" 1 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xffffffffffffaaaa" 1 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xffffffffaaaaaaaa" 2 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xaaaaaaaaaaaaaaaa" 3 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "const_int 0" 3 "expand" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-20.c b/gcc/testsuite/gcc.target/i386/auto-init-20.c
new file mode 100644
index 0000000..e675e8f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-20.c
@@ -0,0 +1,26 @@
+/* Verify pattern initialization for union type with structure field with
+   padding.  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+union test_union_padding {
+  struct test_trailing_hole u1;
+  long long u2;
+};
+
+
+int foo ()
+{
+  union test_union_padding var;
+  return var.u1.four;
+}
+
+/* { dg-final { scan-assembler-times "movq\t\\\$0," 2 } } */
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-3.c b/gcc/testsuite/gcc.target/i386/auto-init-3.c
new file mode 100644
index 0000000..0771f4f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-3.c
@@ -0,0 +1,20 @@
+/* Verify zero initialization for floating point type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+long double result;
+
+long double foo()
+{
+  float temp1;
+  double temp2;
+  long double temp3;
+
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-assembler "pxor\[ \t\]+%xmm0, %xmm0" } } */
+/* { dg-final { scan-assembler "movss\[ \t\]+%xmm0" } } */
+/* { dg-final { scan-assembler "movsd\[ \t\]+%xmm0" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-4.c b/gcc/testsuite/gcc.target/i386/auto-init-4.c
new file mode 100644
index 0000000..4001e2c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-4.c
@@ -0,0 +1,23 @@
+/* Verify pattern initialization for floating point type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+long double result;
+
+long double foo()
+{
+  float temp1;
+  double temp2;
+  long double temp3;
+
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-assembler "movss\[ \t\]+.LC0\\(%rip\\), %xmm0" } } */
+/* { dg-final { scan-assembler "movss\[ \t\]+%xmm0" } } */
+/* { dg-final { scan-assembler "movsd\[ \t\]+.LC1\\(%rip\\), %xmm0" } } */
+/* { dg-final { scan-assembler "movsd\[ \t\]+%xmm0" } } */
+/* { dg-final { scan-assembler ".long\[ \t\]+2143289344" } } */
+/* { dg-final { scan-assembler ".long\[ \t\]+2146959360" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-5.c b/gcc/testsuite/gcc.target/i386/auto-init-5.c
new file mode 100644
index 0000000..c24a6fa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-5.c
@@ -0,0 +1,19 @@
+/* Verify zero initialization for complex type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-tree-gimple" } */
+
+
+_Complex long double result;
+
+_Complex long double foo()
+{
+  _Complex float temp1;
+  _Complex double temp2;
+  _Complex long double temp3;
+
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-assembler-times ".long\\t0" 14 } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-6.c b/gcc/testsuite/gcc.target/i386/auto-init-6.c
new file mode 100644
index 0000000..3f17113
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-6.c
@@ -0,0 +1,22 @@
+/* Verify pattern initialization for complex type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+
+_Complex long double result;
+
+_Complex long double foo()
+{
+  _Complex float temp1;
+  _Complex double temp2;
+  _Complex long double temp3;
+
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-assembler-times ".long\\t2143289344" 3 } } */
+/* { dg-final { scan-assembler-times ".long\\t2146959360" 2 } } */
+/* { dg-final { scan-assembler-times ".long\\t-1073741824" 2 } } */
+/* { dg-final { scan-assembler-times ".long\\t32767" 2 } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-7.c b/gcc/testsuite/gcc.target/i386/auto-init-7.c
new file mode 100644
index 0000000..ac27fbe
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-7.c
@@ -0,0 +1,32 @@
+/* Verify zero initialization for array, union, and structure type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand" } */
+
+struct S
+{
+  int f1;
+  float f2;
+  char f3[20];
+};
+
+union U
+{
+  char u1[5];
+  int u2;
+  float u3; 
+};
+
+double result;
+
+double foo()
+{
+  int temp1[3];
+  double temp2[3];
+  struct S temp3;
+  union U temp4;
+  
+  result = temp1[2] + temp2[1] + temp3.f2 + temp4.u3;
+  return result;
+}
+
+/* { dg-final { scan-rtl-dump-times "const_int 0" 8 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-8.c b/gcc/testsuite/gcc.target/i386/auto-init-8.c
new file mode 100644
index 0000000..ef5ab31
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-8.c
@@ -0,0 +1,33 @@
+/* Verify pattern initialization for array, union, and structure type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */
+
+struct S
+{
+  int f1;
+  float f2;
+  char f3[20];
+};
+
+union U
+{
+  char u1[5];
+  int u2;
+  float u3; 
+};
+
+double result;
+
+double foo()
+{
+  int temp1[3];
+  double temp2[3];
+  struct S temp3;
+  union U temp4;
+  
+  result = temp1[2] + temp2[1] + temp3.f2 + temp4.u3;
+  return result;
+}
+
+/* { dg-final { scan-rtl-dump-times "0xffffffffaaaaaaaa" 4 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xffffffffffffffaa" 26 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-9.c b/gcc/testsuite/gcc.target/i386/auto-init-9.c
new file mode 100644
index 0000000..b406979
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-9.c
@@ -0,0 +1,19 @@
+/* Verify zero initialization for structure type automatic variables with
+   padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_aligned {
+        int internal1;
+        long long internal2;
+} __attribute__ ((aligned(64)));
+
+int foo ()
+{
+  struct test_aligned var;
+  return var.internal1;
+}
+
+/* { dg-final { scan-assembler-times "movq\t\\\$0," 8 } } */
+
+
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 7e3aae5..da02be2 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -3471,6 +3471,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-core.h b/gcc/tree-core.h
index d2e6c89..fb42c41 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1815,6 +1815,7 @@ struct GTY(()) tree_decl_with_vis {
  unsigned in_text_section : 1;
  unsigned in_constant_pool : 1;
  unsigned dllimport_flag : 1;
+ unsigned uninitialized : 1;
  /* Don't belong to VAR_DECL exclusively.  */
  unsigned weak_flag : 1;
 
@@ -1836,7 +1837,7 @@ struct GTY(()) tree_decl_with_vis {
  unsigned final : 1;
  /* Belong to FUNCTION_DECL exclusively.  */
  unsigned regdecl_flag : 1;
- /* 14 unused bits. */
+ /* 13 unused bits.  */
  /* 32 more unused on 64 bit HW. */
 };
 
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index d177f1b..fe439f7 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -384,6 +384,13 @@ static struct
 
   /* Numbber of components created when splitting aggregate parameters.  */
   int param_reductions_created;
+
+  /* Number of deferred_init calls that are modified.  */
+  int deferred_init;
+
+  /* Number of deferred_init calls that are created by
+     generate_subtree_deferred_init.  */
+  int subtree_deferred_init;
 } sra_stats;
 
 static void
@@ -4070,6 +4077,105 @@ get_repl_default_def_ssa_name (struct access *racc, tree reg_type)
   return get_or_create_ssa_default_def (cfun, racc->replacement_decl);
 }
 
+
+/* Generate statements to call .DEFERRED_INIT to initialize scalar replacements
+   of accesses within a subtree ACCESS, all its children, siblings and their
+   children are to be processed.  TOP_OFFSET is the offset  of the processed
+   subtree which has to be subtracted from offsets of individual accesses to
+   get corresponding offsets for AGG.  GSI is a statement iterator used to place
+   the new statements.  */
+static void
+generate_subtree_deferred_init (struct access *access, tree agg,
+				enum auto_init_type init_type,
+				HOST_WIDE_INT top_offset,
+				gimple_stmt_iterator *gsi,
+				location_t loc)
+{
+  do
+    {
+      if (access->grp_to_be_replaced)
+	{
+	  tree repl = get_access_replacement (access);
+	  tree init_type_node
+	    = build_int_cst (integer_type_node, (int) init_type);
+	  gimple *call = gimple_build_call_internal (IFN_DEFERRED_INIT, 2,
+						     repl, init_type_node);
+	  gimple_call_set_lhs (call, repl);
+	  gsi_insert_before (gsi, call, GSI_SAME_STMT);
+	  update_stmt (call);
+	  gimple_set_location (call, loc);
+
+	  sra_stats.subtree_deferred_init++;
+	}
+      else if (access->grp_to_be_debug_replaced)
+	{
+	  /* FIXME, this part might have some issue.  */
+	  tree drhs = build_debug_ref_for_model (loc, agg,
+						 access->offset - top_offset,
+						 access);
+	  gdebug *ds = gimple_build_debug_bind (get_access_replacement (access),
+						drhs, gsi_stmt (*gsi));
+	  gsi_insert_before (gsi, ds, GSI_SAME_STMT);
+	}
+      if (access->first_child)
+	generate_subtree_deferred_init (access->first_child, agg, init_type,
+					top_offset, gsi, loc);
+
+      access = access ->next_sibling;
+    }
+  while (access);
+}
+
+/* For a call to .DEFERRED_INIT:
+   var = .DEFERRED_INIT (var, init_type);
+   examine the LHS variable VAR and replace it with a scalar replacement if
+   there is one, also replace the RHS call to a call to .DEFERRED_INIT of
+   the corresponding scalar relacement variable.  Examine the subtree and
+   do the scalar replacements in the subtree too.  STMT is the call, GSI is
+   the statment iterator to place newly created statements.  */
+
+static enum assignment_mod_result
+sra_modify_deferred_init (gimple *stmt, gimple_stmt_iterator *gsi)
+{
+  tree lhs = gimple_call_lhs (stmt);
+  enum auto_init_type init_type
+    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
+  struct access *access = get_access_for_expr (lhs);
+  if (!access)
+    return SRA_AM_NONE;
+  location_t loc = gimple_location (stmt);
+
+  if (access->grp_to_be_replaced)
+    {
+      tree repl = get_access_replacement (access);
+      gimple_call_set_lhs (stmt, repl);
+      gimple_call_set_arg (stmt, 0, repl);
+      sra_stats.deferred_init++;
+    }
+  else if (access->grp_to_be_debug_replaced)
+    {
+      /* FIXME, this part might have some issues.  */
+      tree drepl = get_access_replacement (access);
+      gdebug *ds = gimple_build_debug_bind (drepl, NULL_TREE,
+					    gsi_stmt (*gsi));
+      gsi_insert_before (gsi, ds, GSI_SAME_STMT);
+    }
+
+  if (access->first_child)
+    generate_subtree_deferred_init (access->first_child, lhs,
+				    init_type, access->offset,
+				    gsi, loc);
+  if (access->grp_covered)
+    {
+      unlink_stmt_vdef (stmt);
+      gsi_remove (gsi, true);
+      release_defs (stmt);
+      return SRA_AM_REMOVED;
+    }
+
+  return SRA_AM_MODIFIED;
+}
+
 /* Examine both sides of the assignment statement pointed to by STMT, replace
    them with a scalare replacement if there is one and generate copying of
    replacements if scalarized aggregates have been used in the assignment.  GSI
@@ -4434,17 +4540,27 @@ sra_modify_function_body (void)
 	      break;
 
 	    case GIMPLE_CALL:
-	      /* Operands must be processed before the lhs.  */
-	      for (i = 0; i < gimple_call_num_args (stmt); i++)
+	      /* Handle calls to .DEFERRED_INIT specially.  */
+	      if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
 		{
-		  t = gimple_call_arg_ptr (stmt, i);
-		  modified |= sra_modify_expr (t, &gsi, false);
+		  assign_result = sra_modify_deferred_init (stmt, &gsi);
+		  modified |= assign_result == SRA_AM_MODIFIED;
+		  deleted = assign_result == SRA_AM_REMOVED;
 		}
-
-	      if (gimple_call_lhs (stmt))
+	      else
 		{
-		  t = gimple_call_lhs_ptr (stmt);
-		  modified |= sra_modify_expr (t, &gsi, true);
+		  /* Operands must be processed before the lhs.  */
+		  for (i = 0; i < gimple_call_num_args (stmt); i++)
+		    {
+		      t = gimple_call_arg_ptr (stmt, i);
+		      modified |= sra_modify_expr (t, &gsi, false);
+		    }
+
+	      	  if (gimple_call_lhs (stmt))
+		    {
+		      t = gimple_call_lhs_ptr (stmt);
+		      modified |= sra_modify_expr (t, &gsi, true);
+		    }
 		}
 	      break;
 
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index 529ec3a..dc325aa 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -4863,6 +4863,29 @@ find_func_aliases_for_builtin_call (struct function *fn, gcall *t)
   return false;
 }
 
+static void
+find_func_aliases_for_deferred_init (gcall *t)
+{
+  tree lhsop = gimple_call_lhs (t);
+  enum auto_init_type init_type
+    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (t, 1));
+  auto_vec<ce_s, 2> lhsc;
+  auto_vec<ce_s, 4> rhsc;
+  struct constraint_expr temp;
+
+  get_constraint_for (lhsop, &lhsc);
+  if (init_type == AUTO_INIT_ZERO && flag_delete_null_pointer_checks)
+    temp.var = nothing_id;
+  else
+    temp.var = nonlocal_id;
+  temp.type = ADDRESSOF;
+  temp.offset = 0;
+  rhsc.safe_push (temp);
+
+  process_all_all_constraints (lhsc, rhsc);
+  return;
+}
+
 /* Create constraints for the call T.  */
 
 static void
@@ -4876,6 +4899,12 @@ find_func_aliases_for_call (struct function *fn, gcall *t)
       && find_func_aliases_for_builtin_call (fn, t))
     return;
 
+  if (gimple_call_internal_p (t, IFN_DEFERRED_INIT))
+    {
+      find_func_aliases_for_deferred_init (t);
+      return;
+    }
+
   fi = get_fi_for_callee (t);
   if (!in_ipa_mode
       || (fi->decl && fndecl && !fi->is_fn_info))
diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c
index 0800f59..0c61f60 100644
--- a/gcc/tree-ssa-uninit.c
+++ b/gcc/tree-ssa-uninit.c
@@ -135,6 +135,20 @@ warn_uninit (enum opt_code wc, tree t, tree expr, tree var,
   if (is_gimple_assign (context)
       && gimple_assign_rhs_code (context) == COMPLEX_EXPR)
     return;
+
+  /* Ignore REALPART_EXPR or IMAGPART_EXPR if its operand is
+     a call to .DEFERRED_INIT.  */
+  if (is_gimple_assign (context)
+      && (gimple_assign_rhs_code (context) == REALPART_EXPR
+	  || gimple_assign_rhs_code (context) == IMAGPART_EXPR))
+    {
+      tree v = gimple_assign_rhs1 (context);
+      if (TREE_CODE (TREE_OPERAND (v, 0)) == SSA_NAME
+	  && gimple_call_internal_p (SSA_NAME_DEF_STMT (TREE_OPERAND (v, 0)),
+				     IFN_DEFERRED_INIT))
+	return;
+    }
+
   if (!has_undefined_value_p (t))
     return;
 
@@ -209,6 +223,19 @@ check_defs (ao_ref *ref, tree vdef, void *data_)
 {
   check_defs_data *data = (check_defs_data *)data_;
   gimple *def_stmt = SSA_NAME_DEF_STMT (vdef);
+
+  /* Ignore the vdef iff the definition statement is a call
+     to .DEFERRED_INIT function.  */
+  if (gimple_call_internal_p (def_stmt, IFN_DEFERRED_INIT))
+    return false;
+
+  /* Ignore the vdef iff the definition statement is a call
+     to builtin_memset function that is added for uninitialized
+     auto variable initialization.  */
+  if (gimple_call_builtin_p (def_stmt, BUILT_IN_MEMSET)
+      && gimple_call_memset_for_uninit_p (def_stmt))
+    return false;
+
   /* If this is a clobber then if it is not a kill walk past it.  */
   if (gimple_clobber_p (def_stmt))
     {
@@ -611,6 +638,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 cf54c89..93d6124 100644
--- a/gcc/tree-ssa.c
+++ b/gcc/tree-ssa.c
@@ -1325,6 +1325,23 @@ 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;
+
+  if (partial && is_gimple_assign (def_stmt)
+      && (gimple_assign_rhs_code (def_stmt) == REALPART_EXPR
+	  || gimple_assign_rhs_code (def_stmt) == IMAGPART_EXPR))
+    {
+      tree real_imag_part = TREE_OPERAND (gimple_assign_rhs1 (def_stmt), 0);
+      if (TREE_CODE (real_imag_part) == SSA_NAME
+	 && gimple_call_internal_p (SSA_NAME_DEF_STMT (real_imag_part),
+				    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)
diff --git a/gcc/tree.c b/gcc/tree.c
index 7c44c22..2c9acad 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -2531,6 +2531,144 @@ build_zero_cst (tree type)
     }
 }
 
+/* Build pattern constant of type TYPE.  This is used for initializing
+   auto variables.  */
+
+tree
+build_pattern_cst (tree type)
+{
+  /* The following value is a guaranteed unmappable pointer value and has a
+     repeated byte-pattern which makes it easier to synthesize.  We use it for
+     pointers as well as integers so that aggregates are likely to be
+     initialized with this repeated value.  */
+  uint64_t largevalue = 0xAAAAAAAAAAAAAAAAull;
+  /* For 32-bit platforms it's a bit trickier because, across systems, only the
+     zero page can reasonably be expected to be unmapped, and even then we need
+     a very low address.  We use a smaller value, and that value sadly doesn't
+     have a repeated byte-pattern.  We don't use it for integers.  */
+  uint32_t smallvalue = 0x000000AA;
+
+  switch (TREE_CODE (type))
+    {
+    case INTEGER_TYPE:
+    case ENUMERAL_TYPE:
+    case BOOLEAN_TYPE:
+      /* This will initialize a boolean type variable to 0 instead of 1.
+ 	 We think that initializint a boolean variable to 0 other than 1
+	 is better even for pattern initialization.  */
+      return build_int_cstu (type, largevalue);
+    case POINTER_TYPE:
+    case OFFSET_TYPE:
+    case REFERENCE_TYPE:
+    case NULLPTR_TYPE:
+      {
+	poly_uint64 intvalue;
+
+	if (POINTER_SIZE == 64)
+	  intvalue = largevalue;
+	else if (POINTER_SIZE == 32)
+	  intvalue = smallvalue;
+	else
+	  gcc_assert (0);
+	return build_int_cstu (type, intvalue);
+      }
+    case REAL_TYPE:
+      {
+	REAL_VALUE_TYPE rnan;
+
+	/* create an quiet NAN for REAL TYPE.  */
+	if (real_nan (&rnan, "", 1, TYPE_MODE (type)))
+	  return build_real (type, rnan);
+	return NULL_TREE;
+      }
+
+    case FIXED_POINT_TYPE:
+      {
+	/* FIXME.  What should we put into a fixed point?  */
+	FIXED_VALUE_TYPE fixed;
+	fixed_from_string (&fixed, "0xFFFFFFFFFFFFFFFF",
+			   SCALAR_TYPE_MODE (type));
+	return build_fixed (type, fixed);
+      }
+    case VECTOR_TYPE:
+      {
+	tree scalar = build_pattern_cst (TREE_TYPE (type));
+	return build_vector_from_val (type, scalar);
+      }
+    case COMPLEX_TYPE:
+      {
+	tree element = build_pattern_cst (TREE_TYPE (type));
+	return build_complex (type, element, element);
+      }
+    case RECORD_TYPE:
+      {
+	tree field;
+	tree field_value;
+	vec<constructor_elt, va_gc> *v = NULL;
+	for (field= TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+	  {
+	    if (TREE_CODE (field) != FIELD_DECL)
+	      continue;
+	    /* if the field is a variable length array, it should be the last
+	       field of the record, and no need to initialize.  */
+	    if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
+		&& TYPE_SIZE (TREE_TYPE (field)) == NULL_TREE
+		&& ((TYPE_DOMAIN (TREE_TYPE (field)) != NULL_TREE
+		    && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field)))
+				       == NULL_TREE)
+		   || TYPE_DOMAIN (TREE_TYPE (field)) == NULL_TREE))
+	      continue;
+	    field_value = build_pattern_cst (TREE_TYPE (field));
+	    CONSTRUCTOR_APPEND_ELT (v, field, field_value);
+	  }
+	return build_constructor (type, v);
+      }
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+      {
+	tree field, max_field = NULL;
+	unsigned max_size = 0;
+	tree field_value;
+	vec<constructor_elt, va_gc> *v = NULL;
+	/* find the field with the largest size.  */
+	for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+	  {
+	    if (TREE_CODE (field) != FIELD_DECL)
+	      continue;
+	    if (tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field))) >= max_size)
+	      {
+		max_size = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field)));
+		max_field = field;
+	      }
+	  }
+	  field_value = build_pattern_cst (TREE_TYPE (max_field));
+	  CONSTRUCTOR_APPEND_ELT (v, max_field, field_value);
+	return build_constructor (type, v);
+      }
+    case ARRAY_TYPE:
+      {
+	vec<constructor_elt, va_gc> *elts = NULL;
+	tree element = build_pattern_cst (TREE_TYPE (type));
+	tree nelts = array_type_nelts (type);
+	if (nelts && tree_fits_uhwi_p (nelts))
+	  {
+	    unsigned HOST_WIDE_INT n = tree_to_uhwi (nelts) + 1;
+	    for (unsigned int i = 0; i < n; i++)
+	      CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, element);
+	    return build_constructor (type, elts);
+	  }
+	/* variable length array should not be here.  */
+	gcc_assert (0);
+      }
+    default:
+      if (!AGGREGATE_TYPE_P (type))
+	return fold_convert (type, build_pattern_cst (unsigned_type_node));
+      else
+	gcc_assert (0);
+
+    }
+}
+
 
 /* Build a BINFO with LEN language slots.  */
 
@@ -11950,6 +12088,72 @@ lower_bound_in_type (tree outer, tree inner)
     }
 }
 
+/* Returns true when the given TYPE has padding inside it.
+   return false otherwise.  */
+bool
+type_has_padding (tree type)
+{
+  switch (TREE_CODE (type))
+    {
+    case RECORD_TYPE:
+      {
+	unsigned HOST_WIDE_INT record_size
+	  = tree_to_uhwi (TYPE_SIZE_UNIT (type));
+	unsigned HOST_WIDE_INT size_sofar = 0;
+
+	for (tree field= TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+	  {
+	    if (TREE_CODE (field) != FIELD_DECL)
+	      continue;
+	    unsigned HOST_WIDE_INT cur_off = int_byte_position (field);
+	    if (size_sofar < cur_off)
+	      return true;
+	    size_sofar = cur_off
+			 + tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field)));
+    	  }
+	if (size_sofar < record_size)
+	  return true;
+	/* If any of the field has padding, return true.  */
+	for (tree field= TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+	  {
+	    if ((TREE_CODE (field) != FIELD_DECL))
+	      continue;
+	    if (AGGREGATE_TYPE_P (TREE_TYPE (field))
+		&& type_has_padding (TREE_TYPE (field)))
+	      return true;
+	  }
+  	return false;
+      }
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+      {
+	tree max_field = NULL;
+	unsigned max_size = 0;
+	for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+	  {
+	    if (TREE_CODE (field) != FIELD_DECL)
+	      continue;
+	    if (tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field))) >= max_size)
+	      {
+		max_size = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field)));
+		max_field = field;
+	      }
+	  }
+	if (AGGREGATE_TYPE_P (TREE_TYPE (max_field)))
+	  return type_has_padding (TREE_TYPE (max_field));
+	return false;
+      }
+    case ARRAY_TYPE:
+      {
+	if (AGGREGATE_TYPE_P (TREE_TYPE (type)))
+	  return type_has_padding (TREE_TYPE (type));
+ 	return false;
+      }
+    default:
+      return false;
+    }
+}
+
 /* Return nonzero if two operands that are suitable for PHI nodes are
    necessarily equal.  Specifically, both ARG0 and ARG1 must be either
    SSA_NAME or invariant.  Note that this is strictly an optimization.
diff --git a/gcc/tree.h b/gcc/tree.h
index f00ea2e..4d87002 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2892,6 +2892,10 @@ extern void decl_value_expr_insert (tree, tree);
 #define DECL_HARD_REGISTER(NODE)  \
   (VAR_DECL_CHECK (NODE)->decl_with_vis.hard_register)
 
+/* In a VAR_DECL, nonzero if the decl is intentionly not initialized.  */
+#define DECL_UNINITIALIZED(NODE)  \
+  (VAR_DECL_CHECK (NODE)->decl_with_vis.uninitialized)
+
   /* Used to indicate that this DECL has weak linkage.  */
 #define DECL_WEAK(NODE) (DECL_WITH_VIS_CHECK (NODE)->decl_with_vis.weak_flag)
 
@@ -4478,6 +4482,7 @@ extern tree build_one_cst (tree);
 extern tree build_minus_one_cst (tree);
 extern tree build_all_ones_cst (tree);
 extern tree build_zero_cst (tree);
+extern tree build_pattern_cst (tree);
 extern tree build_string (unsigned, const char * = NULL);
 extern tree build_poly_int_cst (tree, const poly_wide_int_ref &);
 extern tree build_tree_list (tree, tree CXX_MEM_STAT_INFO);
@@ -5145,6 +5150,7 @@ extern bool operation_can_overflow (enum tree_code);
 extern bool operation_no_trapping_overflow (tree, enum tree_code);
 extern tree upper_bound_in_type (tree, tree);
 extern tree lower_bound_in_type (tree, tree);
+extern bool type_has_padding (tree);
 extern int operand_equal_for_phi_arg_p (const_tree, const_tree);
 extern tree create_artificial_label (location_t);
 extern const char *get_name (tree);
-- 
1.8.3.1


[-- Attachment #3: Type: text/plain, Size: 2 bytes --]




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [patch for gcc12 stage1][version 2] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-03-24 21:21 [patch for gcc12 stage1][version 2] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc Qing Zhao
@ 2021-04-07 14:44 ` Qing Zhao
  2021-04-07 22:19 ` Kees Cook
  2021-04-23 19:05 ` Richard Sandiford
  2 siblings, 0 replies; 13+ messages in thread
From: Qing Zhao @ 2021-04-07 14:44 UTC (permalink / raw)
  To: richard Sandiford, Richard Biener; +Cc: Kees Cook, Gcc-patches Qing Zhao via

Ping

> On Mar 24, 2021, at 4:21 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> 
> Hi, 
> 
> This is the 2nd version of the patch for the new security feature for GCC.
> 
> Could you please take a look at it and let me know any comments and issues.
> 
> Thanks.
> 
> Qing
> 
> ******compared to Version 1, this version added the following new features to address Kees’s comments:
> 
> 1.  correctly handle VLA inside a structure for pattern initialization.
> In tree.c (build_pattern_cst):
> 
> +           /* if the field is a variable length array, it should be the last
> +              field of the record, and no need to initialize.  */
> +           if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
> +               && TYPE_SIZE (TREE_TYPE (field)) == NULL_TREE
> +               && ((TYPE_DOMAIN (TREE_TYPE (field)) != NULL_TREE
> +                   && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field)))
> +                                      == NULL_TREE)
> +                  || TYPE_DOMAIN (TREE_TYPE (field)) == NULL_TREE))
> +             continue;
> 
> 2.  initialize all paddings to zero when -ftrivial-auto-var-init is present.
> In expr.c (store_constructor):
> 
>         Clear the whole structure when
>         -ftrivial-auto-var-init and the structure has paddings.
> 
> In gimplify.c (gimplify_init_constructor):
> 
>         Clear the whole structure when
>         -ftrivial-auto-var-init and the structure has paddings.
> 
> As agreed with Kees, treat the issue related to auto variables outside of the cases and inside the switch as a low priority one. 
> 
> 3. Add  the following new testing cases for the above 1 and 2:
> 
>         * c-c++-common/auto-init-13.c: New test.
>         * c-c++-common/auto-init-14.c: New test. 
> 
>         * gcc.target/aarch64/auto-init-9.c: New test.
>         * gcc.target/aarch64/auto-init-10.c: New test.
>         * gcc.target/aarch64/auto-init-11.c: New test.
>         * gcc.target/aarch64/auto-init-12.c: New test.
>         * gcc.target/aarch64/auto-init-13.c: New test.
>         * gcc.target/aarch64/auto-init-14.c: New test.
>         * gcc.target/aarch64/auto-init-15.c: New test.
>         * gcc.target/aarch64/auto-init-16.c: New test.
>         * gcc.target/aarch64/auto-init-17.c: New test.
>         * gcc.target/aarch64/auto-init-18.c: New test.
>         * gcc.target/aarch64/auto-init-19.c: New test.
>         * gcc.target/aarch64/auto-init-20.c: New test.
> 
>         * gcc.target/i386/auto-init-9.c: New test.
>         * gcc.target/i386/auto-init-10.c: New test.
>         * gcc.target/i386/auto-init-11.c: New test.
>         * gcc.target/i386/auto-init-12.c: New test.
>         * gcc.target/i386/auto-init-13.c: New test.
>         * gcc.target/i386/auto-init-14.c: New test.
>         * gcc.target/i386/auto-init-15.c: New test.
>         * gcc.target/i386/auto-init-16.c: New test.
>         * gcc.target/i386/auto-init-17.c: New test.
>         * gcc.target/i386/auto-init-18.c: New test.
>         * gcc.target/i386/auto-init-19.c: New test.
>         * gcc.target/i386/auto-init-20.c: New test.
> 
> 4. Update the default approach as D,  then when specify -ftrivial-auto-var-init,  the default approach is the “.DEFERRED_INIT” 
> Approach. No need to add -fauto-var-init-approach=D anymore.
> 
> If we need to compare approach A and D, we can add -fauto-var-init-approach=A to get that implementation. 
> 
> 5.  Delete all -fauto-var-init-approach=D in the testing cases. 
> 
> ****** others are the same as Version 1, please see the version 1 description at:
> 
> https://gcc.gnu.org/pipermail/gcc-patches/2021-February/565581.html <https://gcc.gnu.org/pipermail/gcc-patches/2021-February/565581.html>
> 
> 
> *******Changelog:
> 
> gcc/:
> 
> 2021-03-24  qing zhao  <qing.zhao@oracle.com>
> 
>         * common.opt (ftrivial-auto-var-init=): New.
>         (fauto-var-init-approach=): Likewise.
>         * doc/extend.texi: Document the uninitialized attribute.
>         * doc/invoke.texi: Document -ftrivial-auto-var-init.
>         * expr.c (store_constructor): Clear the whole structure when
>         -ftrivial-auto-var-init and the structure has paddings.
>         * flag-types.h (enum auto_init_type): New enumerated type
>         auto_init_type.
>         (enum auto_init_approach): New enumerated type auto_init_approach.
>         * gimple.h (enum gf_mask): Add GF_CALL_MEMSET_FOR_UNINIT case.
>         (gimple_call_set_memset_for_uninit): New function.
>         (gimple_call_memset_for_uninit_p): Likewise.
>         * gimplify.c (gimplify_vla_decl): Add initialization to vla per users'
>         requests. 
>         (build_deferred_init): New function.
>         (gimple_add_init_for_auto_var): Likewise.
>         (gimplify_decl_expr): Add initialization to automatic variables per
>         users' requests.
>         (gimplify_init_constructor): Clear the whole structure when
>         -ftrivial-auto-var-init and the structure has paddings.
>         * internal-fn.c (expand_DEFERRED_INIT): New function.
>         * internal-fn.def (DEFERRED_INIT): New internal function.
>         * tree-cfg.c (verify_gimple_call): Skip calls to DEFERRED_INIT.
>         * tree-core.h (tree_decl_with_vis): Add uninitialized field.
>         * tree-sra.c (sra_stats): Add two new fields deferred_init and
>         subtree_deferred_init.
>         (generate_subtree_deferred_init): New function.
>         (sra_modify_deferred_init): Likewise.
>         (sra_modify_function_body): Handle calls to DEFERRED_INIT specially.
>         * tree-ssa-structalias.c (find_func_aliases_for_deferred_init): New
>         function.
>         (find_func_aliases_for_call): Handle calls to DEFERRED_INIT specially.
>         * tree-ssa-uninit.c (warn_uninit): Handle calls to DEFERRED_INIT
>         specially.
>         (check_defs): Handle calls to DEFERRED_INIT and MEMSET for uninitialized
>         variable specially.
>         (warn_uninitialized_vars): Handle calls to DEFERRED_INIT specially.
>         * tree-ssa.c (ssa_undefined_value_p): Handle calls to DEFERRED_INIT
>         specially.
>         * tree.c (build_pattern_cst): New function.
>         (type_has_padding): Likewise.
>         * tree.h (DECL_UNINITIALIZED): New macro.
>         (build_pattern_cst): New declaration.
>         (type_has_padding): Likewise.
> 
> gcc/c-family/:
> 
> 2021-03-24  qing zhao  <qing.zhao@oracle.com>
> 
>         * c-attribs.c (handle_uninitialized_attribute): New function.
>         (c_common_attribute_table): Add "uninitialized" attribute.
> 
> gcc/testsuite/:
> 
> 2021-03-24  qing zhao  <qing.zhao@oracle.com>
> 
>         * c-c++-common/auto-init-1.c: New test.
>         * c-c++-common/auto-init-10.c: New test.
>         * c-c++-common/auto-init-11.c: New test.
>         * c-c++-common/auto-init-12.c: New test.
>         * c-c++-common/auto-init-13.c: New test.
>         * c-c++-common/auto-init-14.c: New test.
>         * c-c++-common/auto-init-2.c: New test.
>         * c-c++-common/auto-init-3.c: New test.
>         * c-c++-common/auto-init-4.c: New test.
>         * c-c++-common/auto-init-5.c: New test.
>         * c-c++-common/auto-init-6.c: New test.
>         * c-c++-common/auto-init-7.c: New test.
>         * c-c++-common/auto-init-8.c: New test.
>         * c-c++-common/auto-init-9.c: New test.
>         * c-c++-common/auto-init-esra.c: New test.
>         * g++.dg/auto-init-uninit-pred-1_a.C: New test.
>         * g++.dg/auto-init-uninit-pred-1_b.C: New test.
>         * g++.dg/auto-init-uninit-pred-2_a.C: New test.
>         * g++.dg/auto-init-uninit-pred-2_b.C: New test.
>         * g++.dg/auto-init-uninit-pred-3_a.C: New test.
>         * g++.dg/auto-init-uninit-pred-3_b.C: New test.
>         * g++.dg/auto-init-uninit-pred-4.C: New test.
>         * g++.dg/auto-init-uninit-pred-loop-1_a.cc: New test.
>         * g++.dg/auto-init-uninit-pred-loop-1_b.cc: New test.
>         * g++.dg/auto-init-uninit-pred-loop-1_c.cc: New test.
>         * g++.dg/auto-init-uninit-pred-loop_1.cc: New test.
>         * gcc.dg/auto-init-uninit-1.c: New test.
>         * gcc.dg/auto-init-uninit-11.c: New test.
>         * gcc.dg/auto-init-uninit-12.c: New test.
>         * gcc.dg/auto-init-uninit-13.c: New test.
>         * gcc.dg/auto-init-uninit-14.c: New test.
>         * gcc.dg/auto-init-uninit-15.c: New test.
>         * gcc.dg/auto-init-uninit-16.c: New test.
>         * gcc.dg/auto-init-uninit-17.c: New test.
>         * gcc.dg/auto-init-uninit-18.c: New test.
>         * gcc.dg/auto-init-uninit-19.c: New test.
>         * gcc.dg/auto-init-uninit-2.c: New test.
>         * gcc.dg/auto-init-uninit-20.c: New test.
>         * gcc.dg/auto-init-uninit-21.c: New test.
>         * gcc.dg/auto-init-uninit-22.c: New test.
>         * gcc.dg/auto-init-uninit-23.c: New test.
>         * gcc.dg/auto-init-uninit-24.c: New test.
>         * gcc.dg/auto-init-uninit-25.c: New test.
>         * gcc.dg/auto-init-uninit-26.c: New test.
>         * gcc.dg/auto-init-uninit-3.c: New test.
>         * gcc.dg/auto-init-uninit-34.c: New test.
>         * gcc.dg/auto-init-uninit-36.c: New test.
>         * gcc.dg/auto-init-uninit-37.c: New test.
>         * gcc.dg/auto-init-uninit-4.c: New test.
>         * gcc.dg/auto-init-uninit-5.c: New test.
>         * gcc.dg/auto-init-uninit-6.c: New test.
>         * gcc.dg/auto-init-uninit-8.c: New test.
>         * gcc.dg/auto-init-uninit-9.c: New test.
>         * gcc.dg/auto-init-uninit-A.c: New test.
>         * gcc.dg/auto-init-uninit-B.c: New test.
>         * gcc.dg/auto-init-uninit-C.c: New test.
>         * gcc.dg/auto-init-uninit-H.c: New test.
>         * gcc.dg/auto-init-uninit-I.c: New test.
>         * gcc.target/aarch64/auto-init-1.c: New test.
>         * gcc.target/aarch64/auto-init-10.c: New test.
>         * gcc.target/aarch64/auto-init-11.c: New test.
>         * gcc.target/aarch64/auto-init-12.c: New test.
>         * gcc.target/aarch64/auto-init-13.c: New test.
>         * gcc.target/aarch64/auto-init-14.c: New test.
>         * gcc.target/aarch64/auto-init-15.c: New test.
>         * gcc.target/aarch64/auto-init-16.c: New test.
>         * gcc.target/aarch64/auto-init-17.c: New test.
>         * gcc.target/aarch64/auto-init-18.c: New test.
>         * gcc.target/aarch64/auto-init-19.c: New test.
>         * gcc.target/aarch64/auto-init-2.c: New test.
>         * gcc.target/aarch64/auto-init-20.c: New test.
>         * gcc.target/aarch64/auto-init-3.c: New test.
>         * gcc.target/aarch64/auto-init-4.c: New test.
>         * gcc.target/aarch64/auto-init-5.c: New test.
>         * gcc.target/aarch64/auto-init-6.c: New test.
>         * gcc.target/aarch64/auto-init-7.c: New test.
>         * gcc.target/aarch64/auto-init-8.c: New test.
>         * gcc.target/aarch64/auto-init-9.c: New test.
>         * gcc.target/i386/auto-init-1.c: New test.
>         * gcc.target/i386/auto-init-10.c: New test.
>         * gcc.target/i386/auto-init-11.c: New test.
>         * gcc.target/i386/auto-init-12.c: New test.
>         * gcc.target/i386/auto-init-13.c: New test.
>         * gcc.target/i386/auto-init-14.c: New test.
>         * gcc.target/i386/auto-init-15.c: New test.
>         * gcc.target/i386/auto-init-16.c: New test.
>         * gcc.target/i386/auto-init-17.c: New test.
>         * gcc.target/i386/auto-init-18.c: New test.
>         * gcc.target/i386/auto-init-19.c: New test.
>         * gcc.target/i386/auto-init-2.c: New test.
>         * gcc.target/i386/auto-init-20.c: New test.
>         * gcc.target/i386/auto-init-3.c: New test.
>         * gcc.target/i386/auto-init-4.c: New test.
>         * gcc.target/i386/auto-init-5.c: New test.
>         * gcc.target/i386/auto-init-6.c: New test.
>         * gcc.target/i386/auto-init-7.c: New test.
>         * gcc.target/i386/auto-init-8.c: New test.
>         * gcc.target/i386/auto-init-9.c: New test.
> 
> ******The complete patch is attached as following:
> 
> 
> 
> <0001-add-ftrivial-auto-var-init-and-variable-attribute-un.patch>


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [patch for gcc12 stage1][version 2] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-03-24 21:21 [patch for gcc12 stage1][version 2] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc Qing Zhao
  2021-04-07 14:44 ` Qing Zhao
@ 2021-04-07 22:19 ` Kees Cook
  2021-04-08 15:22   ` Qing Zhao
  2021-04-23 19:05 ` Richard Sandiford
  2 siblings, 1 reply; 13+ messages in thread
From: Kees Cook @ 2021-04-07 22:19 UTC (permalink / raw)
  To: Qing Zhao; +Cc: richard Sandiford, Richard Biener, Gcc-patches Qing Zhao via

On Wed, Mar 24, 2021 at 04:21:49PM -0500, Qing Zhao wrote:
> This is the 2nd version of the patch for the new security feature for GCC.
> 
> Could you please take a look at it and let me know any comments and issues.

This behaves perfectly as far as I'm able to test in the Linux kernel!
Thank you!

For comparison to v1, here's the stack init test output for version 2 of the patch:

test_stackinit: u8_zero ok
test_stackinit: u16_zero ok
test_stackinit: u32_zero ok
test_stackinit: u64_zero ok
test_stackinit: char_array_zero ok
test_stackinit: small_hole_zero ok
test_stackinit: big_hole_zero ok
test_stackinit: trailing_hole_zero ok
test_stackinit: packed_zero ok
test_stackinit: small_hole_dynamic_partial ok
test_stackinit: big_hole_dynamic_partial ok
test_stackinit: trailing_hole_dynamic_partial ok
test_stackinit: packed_dynamic_partial ok
test_stackinit: small_hole_static_partial ok
test_stackinit: big_hole_static_partial ok
test_stackinit: trailing_hole_static_partial ok
test_stackinit: packed_static_partial ok
test_stackinit: small_hole_static_all ok
test_stackinit: big_hole_static_all ok
test_stackinit: trailing_hole_static_all ok
test_stackinit: packed_static_all ok
test_stackinit: small_hole_dynamic_all ok
test_stackinit: big_hole_dynamic_all ok
test_stackinit: trailing_hole_dynamic_all ok
test_stackinit: packed_dynamic_all ok
test_stackinit: small_hole_runtime_partial ok
test_stackinit: big_hole_runtime_partial ok
test_stackinit: trailing_hole_runtime_partial ok
test_stackinit: packed_runtime_partial ok
test_stackinit: small_hole_runtime_all ok
test_stackinit: big_hole_runtime_all ok
test_stackinit: trailing_hole_runtime_all ok
test_stackinit: packed_runtime_all ok
test_stackinit: u8_none ok
test_stackinit: u16_none ok
test_stackinit: u32_none ok
test_stackinit: u64_none ok
test_stackinit: char_array_none ok
test_stackinit: switch_1_none XFAIL (uninit bytes: 8)
test_stackinit: switch_2_none XFAIL (uninit bytes: 8)
test_stackinit: small_hole_none ok
test_stackinit: big_hole_none ok
test_stackinit: trailing_hole_none ok
test_stackinit: packed_none ok
test_stackinit: user ok
test_stackinit: all tests passed!

The switch cases are an "expected fail" still, and that's totally fine
for now[1]. Those were all purged from real kernel code anyway. ;)

So that's a big "Ack" from me. :)

What are next steps for this patch? I know a lot of people are looking
forward to it. (And then long-open bug[2] for auto-init can be closed.)

Thanks again!

-Kees

[1] Clang doesn't handle this either https://bugs.llvm.org/show_bug.cgi?id=44916
[2] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87210

> 
> Thanks.
> 
> Qing
> 
> ******compared to Version 1, this version added the following new features to address Kees’s comments:
> 
> 1.  correctly handle VLA inside a structure for pattern initialization.
> In tree.c (build_pattern_cst):
> 
> +           /* if the field is a variable length array, it should be the last
> +              field of the record, and no need to initialize.  */
> +           if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
> +               && TYPE_SIZE (TREE_TYPE (field)) == NULL_TREE
> +               && ((TYPE_DOMAIN (TREE_TYPE (field)) != NULL_TREE
> +                   && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field)))
> +                                      == NULL_TREE)
> +                  || TYPE_DOMAIN (TREE_TYPE (field)) == NULL_TREE))
> +             continue;
> 
> 2.  initialize all paddings to zero when -ftrivial-auto-var-init is present.
> In expr.c (store_constructor):
> 
> 	Clear the whole structure when
>         -ftrivial-auto-var-init and the structure has paddings.
> 
> In gimplify.c (gimplify_init_constructor):
> 
> 	Clear the whole structure when
>         -ftrivial-auto-var-init and the structure has paddings.
> 
> As agreed with Kees, treat the issue related to auto variables outside of the cases and inside the switch as a low priority one. 
> 
> 3. Add  the following new testing cases for the above 1 and 2:
> 
>         * c-c++-common/auto-init-13.c: New test.
>         * c-c++-common/auto-init-14.c: New test. 
> 
> 	* gcc.target/aarch64/auto-init-9.c: New test.
> 	* gcc.target/aarch64/auto-init-10.c: New test.
>         * gcc.target/aarch64/auto-init-11.c: New test.
>         * gcc.target/aarch64/auto-init-12.c: New test.
>         * gcc.target/aarch64/auto-init-13.c: New test.
>         * gcc.target/aarch64/auto-init-14.c: New test.
>         * gcc.target/aarch64/auto-init-15.c: New test.
>         * gcc.target/aarch64/auto-init-16.c: New test.
>         * gcc.target/aarch64/auto-init-17.c: New test.
>         * gcc.target/aarch64/auto-init-18.c: New test.
>         * gcc.target/aarch64/auto-init-19.c: New test.
>         * gcc.target/aarch64/auto-init-20.c: New test.
> 
>         * gcc.target/i386/auto-init-9.c: New test.
>         * gcc.target/i386/auto-init-10.c: New test.
>         * gcc.target/i386/auto-init-11.c: New test.
>         * gcc.target/i386/auto-init-12.c: New test.
>         * gcc.target/i386/auto-init-13.c: New test.
>         * gcc.target/i386/auto-init-14.c: New test.
>         * gcc.target/i386/auto-init-15.c: New test.
>         * gcc.target/i386/auto-init-16.c: New test.
>         * gcc.target/i386/auto-init-17.c: New test.
>         * gcc.target/i386/auto-init-18.c: New test.
>         * gcc.target/i386/auto-init-19.c: New test.
>         * gcc.target/i386/auto-init-20.c: New test.
> 
> 4. Update the default approach as D,  then when specify -ftrivial-auto-var-init,  the default approach is the “.DEFERRED_INIT” 
> Approach. No need to add -fauto-var-init-approach=D anymore.
> 
> If we need to compare approach A and D, we can add -fauto-var-init-approach=A to get that implementation. 
> 
> 5.  Delete all -fauto-var-init-approach=D in the testing cases. 
> 
> ****** others are the same as Version 1, please see the version 1 description at:
> 
> https://gcc.gnu.org/pipermail/gcc-patches/2021-February/565581.html
> 
> 
> *******Changelog:
> 
> gcc/:
> 
> 2021-03-24  qing zhao  <qing.zhao@oracle.com>
> 
> 	* common.opt (ftrivial-auto-var-init=): New.
> 	(fauto-var-init-approach=): Likewise.
> 	* doc/extend.texi: Document the uninitialized attribute.
> 	* doc/invoke.texi: Document -ftrivial-auto-var-init.
> 	* expr.c (store_constructor): Clear the whole structure when
> 	-ftrivial-auto-var-init and the structure has paddings.
> 	* flag-types.h (enum auto_init_type): New enumerated type
> 	auto_init_type.
> 	(enum auto_init_approach): New enumerated type auto_init_approach.
> 	* gimple.h (enum gf_mask): Add GF_CALL_MEMSET_FOR_UNINIT case.
> 	(gimple_call_set_memset_for_uninit): New function.
> 	(gimple_call_memset_for_uninit_p): Likewise.
> 	* gimplify.c (gimplify_vla_decl): Add initialization to vla per users'
> 	requests. 
> 	(build_deferred_init): New function.
> 	(gimple_add_init_for_auto_var): Likewise.
> 	(gimplify_decl_expr): Add initialization to automatic variables per
> 	users' requests.
> 	(gimplify_init_constructor): Clear the whole structure when
> 	-ftrivial-auto-var-init and the structure has paddings.
> 	* internal-fn.c (expand_DEFERRED_INIT): New function.
> 	* internal-fn.def (DEFERRED_INIT): New internal function.
> 	* tree-cfg.c (verify_gimple_call): Skip calls to DEFERRED_INIT.
> 	* tree-core.h (tree_decl_with_vis): Add uninitialized field.
> 	* tree-sra.c (sra_stats): Add two new fields deferred_init and
> 	subtree_deferred_init.
> 	(generate_subtree_deferred_init): New function.
> 	(sra_modify_deferred_init): Likewise.
> 	(sra_modify_function_body): Handle calls to DEFERRED_INIT specially.
> 	* tree-ssa-structalias.c (find_func_aliases_for_deferred_init): New
> 	function.
> 	(find_func_aliases_for_call): Handle calls to DEFERRED_INIT specially.
> 	* tree-ssa-uninit.c (warn_uninit): Handle calls to DEFERRED_INIT
> 	specially.
> 	(check_defs): Handle calls to DEFERRED_INIT and MEMSET for uninitialized
> 	variable specially.
> 	(warn_uninitialized_vars): Handle calls to DEFERRED_INIT specially.
> 	* tree-ssa.c (ssa_undefined_value_p): Handle calls to DEFERRED_INIT
> 	specially.
> 	* tree.c (build_pattern_cst): New function.
> 	(type_has_padding): Likewise.
> 	* tree.h (DECL_UNINITIALIZED): New macro.
> 	(build_pattern_cst): New declaration.
> 	(type_has_padding): Likewise.
> 
> gcc/c-family/:
> 
> 2021-03-24  qing zhao  <qing.zhao@oracle.com>
> 
> 	* c-attribs.c (handle_uninitialized_attribute): New function.
> 	(c_common_attribute_table): Add "uninitialized" attribute.
> 
> gcc/testsuite/:
> 
> 2021-03-24  qing zhao  <qing.zhao@oracle.com>
> 
> 	* c-c++-common/auto-init-1.c: New test.
> 	* c-c++-common/auto-init-10.c: New test.
> 	* c-c++-common/auto-init-11.c: New test.
> 	* c-c++-common/auto-init-12.c: New test.
> 	* c-c++-common/auto-init-13.c: New test.
> 	* c-c++-common/auto-init-14.c: New test.
> 	* c-c++-common/auto-init-2.c: New test.
> 	* c-c++-common/auto-init-3.c: New test.
> 	* c-c++-common/auto-init-4.c: New test.
> 	* c-c++-common/auto-init-5.c: New test.
> 	* c-c++-common/auto-init-6.c: New test.
> 	* c-c++-common/auto-init-7.c: New test.
> 	* c-c++-common/auto-init-8.c: New test.
> 	* c-c++-common/auto-init-9.c: New test.
> 	* c-c++-common/auto-init-esra.c: New test.
> 	* g++.dg/auto-init-uninit-pred-1_a.C: New test.
> 	* g++.dg/auto-init-uninit-pred-1_b.C: New test.
> 	* g++.dg/auto-init-uninit-pred-2_a.C: New test.
> 	* g++.dg/auto-init-uninit-pred-2_b.C: New test.
> 	* g++.dg/auto-init-uninit-pred-3_a.C: New test.
> 	* g++.dg/auto-init-uninit-pred-3_b.C: New test.
> 	* g++.dg/auto-init-uninit-pred-4.C: New test.
> 	* g++.dg/auto-init-uninit-pred-loop-1_a.cc: New test.
> 	* g++.dg/auto-init-uninit-pred-loop-1_b.cc: New test.
> 	* g++.dg/auto-init-uninit-pred-loop-1_c.cc: New test.
> 	* g++.dg/auto-init-uninit-pred-loop_1.cc: New test.
> 	* gcc.dg/auto-init-uninit-1.c: New test.
> 	* gcc.dg/auto-init-uninit-11.c: New test.
> 	* gcc.dg/auto-init-uninit-12.c: New test.
> 	* gcc.dg/auto-init-uninit-13.c: New test.
> 	* gcc.dg/auto-init-uninit-14.c: New test.
> 	* gcc.dg/auto-init-uninit-15.c: New test.
> 	* gcc.dg/auto-init-uninit-16.c: New test.
> 	* gcc.dg/auto-init-uninit-17.c: New test.
> 	* gcc.dg/auto-init-uninit-18.c: New test.
> 	* gcc.dg/auto-init-uninit-19.c: New test.
> 	* gcc.dg/auto-init-uninit-2.c: New test.
> 	* gcc.dg/auto-init-uninit-20.c: New test.
> 	* gcc.dg/auto-init-uninit-21.c: New test.
> 	* gcc.dg/auto-init-uninit-22.c: New test.
> 	* gcc.dg/auto-init-uninit-23.c: New test.
> 	* gcc.dg/auto-init-uninit-24.c: New test.
> 	* gcc.dg/auto-init-uninit-25.c: New test.
> 	* gcc.dg/auto-init-uninit-26.c: New test.
> 	* gcc.dg/auto-init-uninit-3.c: New test.
> 	* gcc.dg/auto-init-uninit-34.c: New test.
> 	* gcc.dg/auto-init-uninit-36.c: New test.
> 	* gcc.dg/auto-init-uninit-37.c: New test.
> 	* gcc.dg/auto-init-uninit-4.c: New test.
> 	* gcc.dg/auto-init-uninit-5.c: New test.
> 	* gcc.dg/auto-init-uninit-6.c: New test.
> 	* gcc.dg/auto-init-uninit-8.c: New test.
> 	* gcc.dg/auto-init-uninit-9.c: New test.
> 	* gcc.dg/auto-init-uninit-A.c: New test.
> 	* gcc.dg/auto-init-uninit-B.c: New test.
> 	* gcc.dg/auto-init-uninit-C.c: New test.
> 	* gcc.dg/auto-init-uninit-H.c: New test.
> 	* gcc.dg/auto-init-uninit-I.c: New test.
> 	* gcc.target/aarch64/auto-init-1.c: New test.
> 	* gcc.target/aarch64/auto-init-10.c: New test.
> 	* gcc.target/aarch64/auto-init-11.c: New test.
> 	* gcc.target/aarch64/auto-init-12.c: New test.
> 	* gcc.target/aarch64/auto-init-13.c: New test.
> 	* gcc.target/aarch64/auto-init-14.c: New test.
> 	* gcc.target/aarch64/auto-init-15.c: New test.
> 	* gcc.target/aarch64/auto-init-16.c: New test.
> 	* gcc.target/aarch64/auto-init-17.c: New test.
> 	* gcc.target/aarch64/auto-init-18.c: New test.
> 	* gcc.target/aarch64/auto-init-19.c: New test.
> 	* gcc.target/aarch64/auto-init-2.c: New test.
> 	* gcc.target/aarch64/auto-init-20.c: New test.
> 	* gcc.target/aarch64/auto-init-3.c: New test.
> 	* gcc.target/aarch64/auto-init-4.c: New test.
> 	* gcc.target/aarch64/auto-init-5.c: New test.
> 	* gcc.target/aarch64/auto-init-6.c: New test.
> 	* gcc.target/aarch64/auto-init-7.c: New test.
> 	* gcc.target/aarch64/auto-init-8.c: New test.
> 	* gcc.target/aarch64/auto-init-9.c: New test.
> 	* gcc.target/i386/auto-init-1.c: New test.
> 	* gcc.target/i386/auto-init-10.c: New test.
> 	* gcc.target/i386/auto-init-11.c: New test.
> 	* gcc.target/i386/auto-init-12.c: New test.
> 	* gcc.target/i386/auto-init-13.c: New test.
> 	* gcc.target/i386/auto-init-14.c: New test.
> 	* gcc.target/i386/auto-init-15.c: New test.
> 	* gcc.target/i386/auto-init-16.c: New test.
> 	* gcc.target/i386/auto-init-17.c: New test.
> 	* gcc.target/i386/auto-init-18.c: New test.
> 	* gcc.target/i386/auto-init-19.c: New test.
> 	* gcc.target/i386/auto-init-2.c: New test.
> 	* gcc.target/i386/auto-init-20.c: New test.
> 	* gcc.target/i386/auto-init-3.c: New test.
> 	* gcc.target/i386/auto-init-4.c: New test.
> 	* gcc.target/i386/auto-init-5.c: New test.
> 	* gcc.target/i386/auto-init-6.c: New test.
> 	* gcc.target/i386/auto-init-7.c: New test.
> 	* gcc.target/i386/auto-init-8.c: New test.
> 	* gcc.target/i386/auto-init-9.c: New test.
> 
> ******The complete patch is attached as following:
> 


> 
> 


-- 
Kees Cook

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [patch for gcc12 stage1][version 2] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-04-07 22:19 ` Kees Cook
@ 2021-04-08 15:22   ` Qing Zhao
  0 siblings, 0 replies; 13+ messages in thread
From: Qing Zhao @ 2021-04-08 15:22 UTC (permalink / raw)
  To: Kees Cook; +Cc: richard Sandiford, Richard Biener, Gcc-patches Qing Zhao via

Hi, Kees,

Thanks a lot for your testing on the linux kernel, I am so happy that this time it works well.

> On Apr 7, 2021, at 5:19 PM, Kees Cook <keescook@chromium.org> wrote:
> 
> On Wed, Mar 24, 2021 at 04:21:49PM -0500, Qing Zhao wrote:
>> This is the 2nd version of the patch for the new security feature for GCC.
>> 
>> Could you please take a look at it and let me know any comments and issues.
> 
> This behaves perfectly as far as I'm able to test in the Linux kernel!
> Thank you!
> 
> For comparison to v1, here's the stack init test output for version 2 of the patch:
> 
> test_stackinit: u8_zero ok
> test_stackinit: u16_zero ok
> test_stackinit: u32_zero ok
> test_stackinit: u64_zero ok
> test_stackinit: char_array_zero ok
> test_stackinit: small_hole_zero ok
> test_stackinit: big_hole_zero ok
> test_stackinit: trailing_hole_zero ok
> test_stackinit: packed_zero ok
> test_stackinit: small_hole_dynamic_partial ok
> test_stackinit: big_hole_dynamic_partial ok
> test_stackinit: trailing_hole_dynamic_partial ok
> test_stackinit: packed_dynamic_partial ok
> test_stackinit: small_hole_static_partial ok
> test_stackinit: big_hole_static_partial ok
> test_stackinit: trailing_hole_static_partial ok
> test_stackinit: packed_static_partial ok
> test_stackinit: small_hole_static_all ok
> test_stackinit: big_hole_static_all ok
> test_stackinit: trailing_hole_static_all ok
> test_stackinit: packed_static_all ok
> test_stackinit: small_hole_dynamic_all ok
> test_stackinit: big_hole_dynamic_all ok
> test_stackinit: trailing_hole_dynamic_all ok
> test_stackinit: packed_dynamic_all ok
> test_stackinit: small_hole_runtime_partial ok
> test_stackinit: big_hole_runtime_partial ok
> test_stackinit: trailing_hole_runtime_partial ok
> test_stackinit: packed_runtime_partial ok
> test_stackinit: small_hole_runtime_all ok
> test_stackinit: big_hole_runtime_all ok
> test_stackinit: trailing_hole_runtime_all ok
> test_stackinit: packed_runtime_all ok
> test_stackinit: u8_none ok
> test_stackinit: u16_none ok
> test_stackinit: u32_none ok
> test_stackinit: u64_none ok
> test_stackinit: char_array_none ok
> test_stackinit: switch_1_none XFAIL (uninit bytes: 8)
> test_stackinit: switch_2_none XFAIL (uninit bytes: 8)
> test_stackinit: small_hole_none ok
> test_stackinit: big_hole_none ok
> test_stackinit: trailing_hole_none ok
> test_stackinit: packed_none ok
> test_stackinit: user ok
> test_stackinit: all tests passed!
> 
> The switch cases are an "expected fail" still, and that's totally fine
> for now[1]. Those were all purged from real kernel code anyway. ;)
> 
> So that's a big "Ack" from me. :)
> 
> What are next steps for this patch?

My understanding is, it needs to be reviewed and get approved by the global reviewers first, 
Currently, I am waiting for any comments from global reviewers in order to be able to push 
this patch into gcc12 as early as possible. 

> I know a lot of people are looking
> forward to it. (And then long-open bug[2] for auto-init can be closed.)
> 
> Thanks again!

Thank you!


Qing
> 
> -Kees
> 
> [1] Clang doesn't handle this either https://bugs.llvm.org/show_bug.cgi?id=44916 <https://bugs.llvm.org/show_bug.cgi?id=44916>
> [2] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87210 <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87210>
> 
>> 
>> Thanks.
>> 
>> Qing
>> 
>> ******compared to Version 1, this version added the following new features to address Kees’s comments:
>> 
>> 1.  correctly handle VLA inside a structure for pattern initialization.
>> In tree.c (build_pattern_cst):
>> 
>> +           /* if the field is a variable length array, it should be the last
>> +              field of the record, and no need to initialize.  */
>> +           if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
>> +               && TYPE_SIZE (TREE_TYPE (field)) == NULL_TREE
>> +               && ((TYPE_DOMAIN (TREE_TYPE (field)) != NULL_TREE
>> +                   && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field)))
>> +                                      == NULL_TREE)
>> +                  || TYPE_DOMAIN (TREE_TYPE (field)) == NULL_TREE))
>> +             continue;
>> 
>> 2.  initialize all paddings to zero when -ftrivial-auto-var-init is present.
>> In expr.c (store_constructor):
>> 
>> 	Clear the whole structure when
>>        -ftrivial-auto-var-init and the structure has paddings.
>> 
>> In gimplify.c (gimplify_init_constructor):
>> 
>> 	Clear the whole structure when
>>        -ftrivial-auto-var-init and the structure has paddings.
>> 
>> As agreed with Kees, treat the issue related to auto variables outside of the cases and inside the switch as a low priority one. 
>> 
>> 3. Add  the following new testing cases for the above 1 and 2:
>> 
>>        * c-c++-common/auto-init-13.c: New test.
>>        * c-c++-common/auto-init-14.c: New test. 
>> 
>> 	* gcc.target/aarch64/auto-init-9.c: New test.
>> 	* gcc.target/aarch64/auto-init-10.c: New test.
>>        * gcc.target/aarch64/auto-init-11.c: New test.
>>        * gcc.target/aarch64/auto-init-12.c: New test.
>>        * gcc.target/aarch64/auto-init-13.c: New test.
>>        * gcc.target/aarch64/auto-init-14.c: New test.
>>        * gcc.target/aarch64/auto-init-15.c: New test.
>>        * gcc.target/aarch64/auto-init-16.c: New test.
>>        * gcc.target/aarch64/auto-init-17.c: New test.
>>        * gcc.target/aarch64/auto-init-18.c: New test.
>>        * gcc.target/aarch64/auto-init-19.c: New test.
>>        * gcc.target/aarch64/auto-init-20.c: New test.
>> 
>>        * gcc.target/i386/auto-init-9.c: New test.
>>        * gcc.target/i386/auto-init-10.c: New test.
>>        * gcc.target/i386/auto-init-11.c: New test.
>>        * gcc.target/i386/auto-init-12.c: New test.
>>        * gcc.target/i386/auto-init-13.c: New test.
>>        * gcc.target/i386/auto-init-14.c: New test.
>>        * gcc.target/i386/auto-init-15.c: New test.
>>        * gcc.target/i386/auto-init-16.c: New test.
>>        * gcc.target/i386/auto-init-17.c: New test.
>>        * gcc.target/i386/auto-init-18.c: New test.
>>        * gcc.target/i386/auto-init-19.c: New test.
>>        * gcc.target/i386/auto-init-20.c: New test.
>> 
>> 4. Update the default approach as D,  then when specify -ftrivial-auto-var-init,  the default approach is the “.DEFERRED_INIT” 
>> Approach. No need to add -fauto-var-init-approach=D anymore.
>> 
>> If we need to compare approach A and D, we can add -fauto-var-init-approach=A to get that implementation. 
>> 
>> 5.  Delete all -fauto-var-init-approach=D in the testing cases. 
>> 
>> ****** others are the same as Version 1, please see the version 1 description at:
>> 
>> https://gcc.gnu.org/pipermail/gcc-patches/2021-February/565581.html
>> 
>> 
>> *******Changelog:
>> 
>> gcc/:
>> 
>> 2021-03-24  qing zhao  <qing.zhao@oracle.com>
>> 
>> 	* common.opt (ftrivial-auto-var-init=): New.
>> 	(fauto-var-init-approach=): Likewise.
>> 	* doc/extend.texi: Document the uninitialized attribute.
>> 	* doc/invoke.texi: Document -ftrivial-auto-var-init.
>> 	* expr.c (store_constructor): Clear the whole structure when
>> 	-ftrivial-auto-var-init and the structure has paddings.
>> 	* flag-types.h (enum auto_init_type): New enumerated type
>> 	auto_init_type.
>> 	(enum auto_init_approach): New enumerated type auto_init_approach.
>> 	* gimple.h (enum gf_mask): Add GF_CALL_MEMSET_FOR_UNINIT case.
>> 	(gimple_call_set_memset_for_uninit): New function.
>> 	(gimple_call_memset_for_uninit_p): Likewise.
>> 	* gimplify.c (gimplify_vla_decl): Add initialization to vla per users'
>> 	requests. 
>> 	(build_deferred_init): New function.
>> 	(gimple_add_init_for_auto_var): Likewise.
>> 	(gimplify_decl_expr): Add initialization to automatic variables per
>> 	users' requests.
>> 	(gimplify_init_constructor): Clear the whole structure when
>> 	-ftrivial-auto-var-init and the structure has paddings.
>> 	* internal-fn.c (expand_DEFERRED_INIT): New function.
>> 	* internal-fn.def (DEFERRED_INIT): New internal function.
>> 	* tree-cfg.c (verify_gimple_call): Skip calls to DEFERRED_INIT.
>> 	* tree-core.h (tree_decl_with_vis): Add uninitialized field.
>> 	* tree-sra.c (sra_stats): Add two new fields deferred_init and
>> 	subtree_deferred_init.
>> 	(generate_subtree_deferred_init): New function.
>> 	(sra_modify_deferred_init): Likewise.
>> 	(sra_modify_function_body): Handle calls to DEFERRED_INIT specially.
>> 	* tree-ssa-structalias.c (find_func_aliases_for_deferred_init): New
>> 	function.
>> 	(find_func_aliases_for_call): Handle calls to DEFERRED_INIT specially.
>> 	* tree-ssa-uninit.c (warn_uninit): Handle calls to DEFERRED_INIT
>> 	specially.
>> 	(check_defs): Handle calls to DEFERRED_INIT and MEMSET for uninitialized
>> 	variable specially.
>> 	(warn_uninitialized_vars): Handle calls to DEFERRED_INIT specially.
>> 	* tree-ssa.c (ssa_undefined_value_p): Handle calls to DEFERRED_INIT
>> 	specially.
>> 	* tree.c (build_pattern_cst): New function.
>> 	(type_has_padding): Likewise.
>> 	* tree.h (DECL_UNINITIALIZED): New macro.
>> 	(build_pattern_cst): New declaration.
>> 	(type_has_padding): Likewise.
>> 
>> gcc/c-family/:
>> 
>> 2021-03-24  qing zhao  <qing.zhao@oracle.com>
>> 
>> 	* c-attribs.c (handle_uninitialized_attribute): New function.
>> 	(c_common_attribute_table): Add "uninitialized" attribute.
>> 
>> gcc/testsuite/:
>> 
>> 2021-03-24  qing zhao  <qing.zhao@oracle.com>
>> 
>> 	* c-c++-common/auto-init-1.c: New test.
>> 	* c-c++-common/auto-init-10.c: New test.
>> 	* c-c++-common/auto-init-11.c: New test.
>> 	* c-c++-common/auto-init-12.c: New test.
>> 	* c-c++-common/auto-init-13.c: New test.
>> 	* c-c++-common/auto-init-14.c: New test.
>> 	* c-c++-common/auto-init-2.c: New test.
>> 	* c-c++-common/auto-init-3.c: New test.
>> 	* c-c++-common/auto-init-4.c: New test.
>> 	* c-c++-common/auto-init-5.c: New test.
>> 	* c-c++-common/auto-init-6.c: New test.
>> 	* c-c++-common/auto-init-7.c: New test.
>> 	* c-c++-common/auto-init-8.c: New test.
>> 	* c-c++-common/auto-init-9.c: New test.
>> 	* c-c++-common/auto-init-esra.c: New test.
>> 	* g++.dg/auto-init-uninit-pred-1_a.C: New test.
>> 	* g++.dg/auto-init-uninit-pred-1_b.C: New test.
>> 	* g++.dg/auto-init-uninit-pred-2_a.C: New test.
>> 	* g++.dg/auto-init-uninit-pred-2_b.C: New test.
>> 	* g++.dg/auto-init-uninit-pred-3_a.C: New test.
>> 	* g++.dg/auto-init-uninit-pred-3_b.C: New test.
>> 	* g++.dg/auto-init-uninit-pred-4.C: New test.
>> 	* g++.dg/auto-init-uninit-pred-loop-1_a.cc: New test.
>> 	* g++.dg/auto-init-uninit-pred-loop-1_b.cc: New test.
>> 	* g++.dg/auto-init-uninit-pred-loop-1_c.cc: New test.
>> 	* g++.dg/auto-init-uninit-pred-loop_1.cc: New test.
>> 	* gcc.dg/auto-init-uninit-1.c: New test.
>> 	* gcc.dg/auto-init-uninit-11.c: New test.
>> 	* gcc.dg/auto-init-uninit-12.c: New test.
>> 	* gcc.dg/auto-init-uninit-13.c: New test.
>> 	* gcc.dg/auto-init-uninit-14.c: New test.
>> 	* gcc.dg/auto-init-uninit-15.c: New test.
>> 	* gcc.dg/auto-init-uninit-16.c: New test.
>> 	* gcc.dg/auto-init-uninit-17.c: New test.
>> 	* gcc.dg/auto-init-uninit-18.c: New test.
>> 	* gcc.dg/auto-init-uninit-19.c: New test.
>> 	* gcc.dg/auto-init-uninit-2.c: New test.
>> 	* gcc.dg/auto-init-uninit-20.c: New test.
>> 	* gcc.dg/auto-init-uninit-21.c: New test.
>> 	* gcc.dg/auto-init-uninit-22.c: New test.
>> 	* gcc.dg/auto-init-uninit-23.c: New test.
>> 	* gcc.dg/auto-init-uninit-24.c: New test.
>> 	* gcc.dg/auto-init-uninit-25.c: New test.
>> 	* gcc.dg/auto-init-uninit-26.c: New test.
>> 	* gcc.dg/auto-init-uninit-3.c: New test.
>> 	* gcc.dg/auto-init-uninit-34.c: New test.
>> 	* gcc.dg/auto-init-uninit-36.c: New test.
>> 	* gcc.dg/auto-init-uninit-37.c: New test.
>> 	* gcc.dg/auto-init-uninit-4.c: New test.
>> 	* gcc.dg/auto-init-uninit-5.c: New test.
>> 	* gcc.dg/auto-init-uninit-6.c: New test.
>> 	* gcc.dg/auto-init-uninit-8.c: New test.
>> 	* gcc.dg/auto-init-uninit-9.c: New test.
>> 	* gcc.dg/auto-init-uninit-A.c: New test.
>> 	* gcc.dg/auto-init-uninit-B.c: New test.
>> 	* gcc.dg/auto-init-uninit-C.c: New test.
>> 	* gcc.dg/auto-init-uninit-H.c: New test.
>> 	* gcc.dg/auto-init-uninit-I.c: New test.
>> 	* gcc.target/aarch64/auto-init-1.c: New test.
>> 	* gcc.target/aarch64/auto-init-10.c: New test.
>> 	* gcc.target/aarch64/auto-init-11.c: New test.
>> 	* gcc.target/aarch64/auto-init-12.c: New test.
>> 	* gcc.target/aarch64/auto-init-13.c: New test.
>> 	* gcc.target/aarch64/auto-init-14.c: New test.
>> 	* gcc.target/aarch64/auto-init-15.c: New test.
>> 	* gcc.target/aarch64/auto-init-16.c: New test.
>> 	* gcc.target/aarch64/auto-init-17.c: New test.
>> 	* gcc.target/aarch64/auto-init-18.c: New test.
>> 	* gcc.target/aarch64/auto-init-19.c: New test.
>> 	* gcc.target/aarch64/auto-init-2.c: New test.
>> 	* gcc.target/aarch64/auto-init-20.c: New test.
>> 	* gcc.target/aarch64/auto-init-3.c: New test.
>> 	* gcc.target/aarch64/auto-init-4.c: New test.
>> 	* gcc.target/aarch64/auto-init-5.c: New test.
>> 	* gcc.target/aarch64/auto-init-6.c: New test.
>> 	* gcc.target/aarch64/auto-init-7.c: New test.
>> 	* gcc.target/aarch64/auto-init-8.c: New test.
>> 	* gcc.target/aarch64/auto-init-9.c: New test.
>> 	* gcc.target/i386/auto-init-1.c: New test.
>> 	* gcc.target/i386/auto-init-10.c: New test.
>> 	* gcc.target/i386/auto-init-11.c: New test.
>> 	* gcc.target/i386/auto-init-12.c: New test.
>> 	* gcc.target/i386/auto-init-13.c: New test.
>> 	* gcc.target/i386/auto-init-14.c: New test.
>> 	* gcc.target/i386/auto-init-15.c: New test.
>> 	* gcc.target/i386/auto-init-16.c: New test.
>> 	* gcc.target/i386/auto-init-17.c: New test.
>> 	* gcc.target/i386/auto-init-18.c: New test.
>> 	* gcc.target/i386/auto-init-19.c: New test.
>> 	* gcc.target/i386/auto-init-2.c: New test.
>> 	* gcc.target/i386/auto-init-20.c: New test.
>> 	* gcc.target/i386/auto-init-3.c: New test.
>> 	* gcc.target/i386/auto-init-4.c: New test.
>> 	* gcc.target/i386/auto-init-5.c: New test.
>> 	* gcc.target/i386/auto-init-6.c: New test.
>> 	* gcc.target/i386/auto-init-7.c: New test.
>> 	* gcc.target/i386/auto-init-8.c: New test.
>> 	* gcc.target/i386/auto-init-9.c: New test.
>> 
>> ******The complete patch is attached as following:
>> 
> 
> 
>> 
>> 
> 
> 
> -- 
> Kees Cook


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [patch for gcc12 stage1][version 2] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-03-24 21:21 [patch for gcc12 stage1][version 2] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc Qing Zhao
  2021-04-07 14:44 ` Qing Zhao
  2021-04-07 22:19 ` Kees Cook
@ 2021-04-23 19:05 ` Richard Sandiford
  2021-04-23 19:33   ` Kees Cook
                     ` (2 more replies)
  2 siblings, 3 replies; 13+ messages in thread
From: Richard Sandiford @ 2021-04-23 19:05 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Richard Biener, Kees Cook, Gcc-patches Qing Zhao via

Finally getting to this now that the GCC 11 rush is over.  Sorry for
the slow response.

I've tried to review most of the code below, but skipped the testsuite
parts in the interests of time.  I'll probably have more comments in
future rounds, just wanted to get the ball rolling.

This is realy Richi's area more than mine though, so please take this
with a grain of salt.

Qing Zhao <qing.zhao@oracle.com> writes:
> 2.  initialize all paddings to zero when -ftrivial-auto-var-init is present.
> In expr.c (store_constructor):
>
>         Clear the whole structure when
>         -ftrivial-auto-var-init and the structure has paddings.
>
> In gimplify.c (gimplify_init_constructor):
>
>         Clear the whole structure when
>         -ftrivial-auto-var-init and the structure has paddings.

Just to check: are we sure we want to use zero as the padding fill
value even for -ftrivial-auto-var-init=pattern?  Or should it be
0xAA instead, to match the integer fill pattern?

I can see the arguments both ways, just thought it was worth asking.

> […]
> @@ -1589,6 +1592,24 @@ handle_retain_attribute (tree *pnode, tree name, tree ARG_UNUSED (args),
>    return NULL_TREE;
>  }
>  
> +/* Handle a "uninitialized" attribute; arguments as in

This occurs in existing code too, but s/a/an/.

> +   struct attribute_spec.handler.  */
> +
> +static tree
> +handle_uninitialized_attribute (tree *node, tree name, tree ARG_UNUSED (args),
> +				int ARG_UNUSED (flags), bool *no_add_attrs)
> +{
> +  if (VAR_P (*node))
> +    DECL_UNINITIALIZED (*node) = 1;
> +  else
> +    {
> +      warning (OPT_Wattributes, "%qE attribute ignored", name);
> +      *no_add_attrs = true;
> +    }
> +
> +  return NULL_TREE;
> +}
> +
>  /* Handle a "externally_visible" attribute; arguments as in
>     struct attribute_spec.handler.  */

> […]
> @@ -11689,6 +11689,34 @@ Perform basic block vectorization on trees. This flag is enabled by default at
>  @option{-O3} and by @option{-ftree-vectorize}, @option{-fprofile-use},
>  and @option{-fauto-profile}.
>  
> +@item -ftrivial-auto-var-init=@var{choice}
> +@opindex ftrivial-auto-var-init
> +Initialize automatic variables with either a pattern or with zeroes to increase
> +program security by preventing uninitialized memory disclosure and use.
> +
> +The three values of @var{choice} are:
> +
> +@itemize @bullet
> +@item
> +@samp{uninitialized} doesn't initialize any automatic variables.
> +This is C and C++'s default.
> +
> +@item
> +@samp{pattern} Initialize automatic variables with values which will likely
> +transform logic bugs into crashes down the line, are easily recognized in a
> +crash dump and without being values that programmers can rely on for useful
> +program semantics.
> +The values used for pattern initialization might be changed in the future.
> +
> +@item
> +@samp{zero} Initialize automatic variables with zeroes.
> +@end itemize
> +
> +The default is @samp{uninitialized}.
> +
> +You can control this behavior for a specific variable by using the variable
> +attribute @code{uninitialized} (@pxref{Variable Attributes}).
> +

I think it's important to say here that GCC still considers the
variables to be uninitialised and still considers reading them to
be undefined behaviour.  The option is simply trying to improve the
security and predictability of the program in the presence of these
uninitialised variables.

I think it would also be worth saying that options like -Wuninitialized
still try to warn about uninitialised variables, although using
-ftrivial-auto-var-init may change which warnings are generated.

(The above comments are just a summary, not suitable for direct
inclusion. :-))

>  @item -fvect-cost-model=@var{model}
>  @opindex fvect-cost-model
>  Alter the cost model used for vectorization.  The @var{model} argument
> […]
> diff --git a/gcc/gimplify.c b/gcc/gimplify.c
> index 6da6698..fafd2e9 100644
> --- a/gcc/gimplify.c
> +++ b/gcc/gimplify.c
> @@ -1716,6 +1716,116 @@ gimplify_vla_decl (tree decl, gimple_seq *seq_p)
>  
>    gimplify_and_add (t, seq_p);
>  
> +  /* Add a call to memset or calls to memcpy to initialize this vla
> +     when the user requested.  */
> +  if (!DECL_ARTIFICIAL (decl)
> +      && VAR_P (decl)
> +      && !DECL_EXTERNAL (decl)
> +      && !TREE_STATIC (decl)
> +      && !DECL_UNINITIALIZED (decl))
> +    switch (flag_trivial_auto_var_init)
> +      {
> +      case AUTO_INIT_UNINITIALIZED:
> +	break;
> +      case AUTO_INIT_ZERO:
> +	{
> +	  /* Generate a call to memset to initialize this vla.  */
> +	  gcall *gs;
> +	  t = builtin_decl_implicit (BUILT_IN_MEMSET);
> +	  gs = gimple_build_call (t, 3, addr, integer_zero_node,
> +				  DECL_SIZE_UNIT (decl));
> +	  gimple_call_set_memset_for_uninit (gs, true);
> +	  gimplify_seq_add_stmt (seq_p, gs);
> +	}
> +	break;
> +      case AUTO_INIT_PATTERN:
> +	{
> +	  /* Generate the following sequence to initialize this vla:
> +	     if (DECL_SIZE_UNIT (decl) > 0) goto label_true;
> +					    else goto label_cont;
> +	     label_true:
> +	      {
> +		element_type = TREE_TYPE (TREE_TYPE (decl));
> +		size_of_element = DECL_SIZE_UNIT (element_type);
> +		init_node = build_pattern_cst (element_type);
> +		cur = addr;
> +		offset = DECL_SIZE_UNIT (decl) - size_of_element;
> +		end = addr + offset;
> +
> +		label_loop:
> +		  {
> +		    memcpy (cur, &init_node, size_of_element);
> +		    cur  += size_of_element;
> +		    if (cur <= end) goto label_loop;
> +				    else goto label_cont;
> +		  }
> +	      }
> +	      label_cont:
> +	  */
> +
> +	  tree size_of_element, element_type;
> +	  tree cur, end, offset;
> +	  tree init_node, addrof_init_node;
> +	  tree t;
> +
> +	  tree label_true = create_artificial_label (UNKNOWN_LOCATION);
> +	  tree label_cont = create_artificial_label (UNKNOWN_LOCATION);
> +	  tree label_loop = create_artificial_label (UNKNOWN_LOCATION);
> +
> +	  element_type = TREE_TYPE (TREE_TYPE (decl));
> +
> +	  gcond *cond_stmt = gimple_build_cond (GT_EXPR, DECL_SIZE_UNIT (decl),
> +						build_zero_cst (sizetype),
> +						label_true,
> +						label_cont);
> +	  gimplify_seq_add_stmt (seq_p, cond_stmt);
> +	  gimplify_seq_add_stmt (seq_p, gimple_build_label (label_true));
> +
> +	  size_of_element = create_tmp_var (sizetype,
> +					    ".size_of_element");
> +
> +	  init_node = create_tmp_var (element_type, ".init_node");
> +	  mark_addressable (init_node);
> +	  addrof_init_node = build_fold_addr_expr_loc (UNKNOWN_LOCATION,
> +						       init_node);
> +
> +	  gimplify_assign (size_of_element, TYPE_SIZE_UNIT (element_type),
> +			   seq_p);
> +	  gimplify_assign (init_node, build_pattern_cst (element_type), seq_p);

Rather than building a separate init_node here, would it work to assign
to element 0 instead?  Then the loop could start at element 1.

What about nested VLAs, like:

  void g(void *);
  void f(int a)
  {
    int x[a][a];
    g(x);
  }

?

> +
> +	  cur = create_tmp_var (ptr_type, ".cur_addr");
> +	  end = create_tmp_var (ptr_type, ".end_addr");
> +	  offset = create_tmp_var (sizetype, ".offset");
> +
> +	  gimplify_assign (cur, addr, seq_p);
> +	  gimplify_seq_add_stmt (seq_p,
> +				 gimple_build_assign (offset, MINUS_EXPR,
> +						      DECL_SIZE_UNIT (decl),
> +						      size_of_element));
> +	  gimplify_seq_add_stmt (seq_p,
> +				 gimple_build_assign (end, POINTER_PLUS_EXPR,
> +						      addr, offset));
> +
> +	  gimplify_seq_add_stmt (seq_p, gimple_build_label (label_loop));
> +
> +	  t = builtin_decl_implicit (BUILT_IN_MEMCPY);
> +	  gimplify_seq_add_stmt (seq_p,
> +				 gimple_build_call (t, 3, cur,
> +						    addrof_init_node,
> +						    size_of_element));
> +	  gimplify_seq_add_stmt (seq_p,
> +				 gimple_build_assign (cur, POINTER_PLUS_EXPR,
> +						      cur, size_of_element));
> +	  cond_stmt = gimple_build_cond (LE_EXPR, cur, end, label_loop,
> +					 label_cont);
> +	  gimplify_seq_add_stmt (seq_p, cond_stmt);
> +	  gimplify_seq_add_stmt (seq_p, gimple_build_label (label_cont));
> +	}
> +	break;
> +      default:
> +	gcc_assert (0);
> +      }
> +
>    /* Record the dynamic allocation associated with DECL if requested.  */
>    if (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC)
>      record_dynamic_alloc (decl);
> @@ -1738,6 +1848,65 @@ 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).  */

I don't think it's necessary to repeat the definition here.

> +
> +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);

Nit: indentation is off in the return statement.

> +}
> +
> […]
> @@ -1831,6 +2000,17 @@ 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.  */

I think we should explain why we can skip VLAs here.

> +      else if (flag_trivial_auto_var_init > AUTO_INIT_UNINITIALIZED
> +	       && !DECL_UNINITIALIZED (decl)
> +	       && !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/tree-cfg.c b/gcc/tree-cfg.c
> index 7e3aae5..da02be2 100644
> --- a/gcc/tree-cfg.c
> +++ b/gcc/tree-cfg.c
> @@ -3471,6 +3471,9 @@ verify_gimple_call (gcall *stmt)
>  	}
>      }
>  
> +  if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
> +    return false;
> +

Why is this needed?  I think a comment would be helpful.

>    /* ???  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-core.h b/gcc/tree-core.h
> index d2e6c89..fb42c41 100644
> --- a/gcc/tree-core.h
> +++ b/gcc/tree-core.h
> @@ -1815,6 +1815,7 @@ struct GTY(()) tree_decl_with_vis {
>   unsigned in_text_section : 1;
>   unsigned in_constant_pool : 1;
>   unsigned dllimport_flag : 1;
> + unsigned uninitialized : 1;
>   /* Don't belong to VAR_DECL exclusively.  */
>   unsigned weak_flag : 1;
>  
> @@ -1836,7 +1837,7 @@ struct GTY(()) tree_decl_with_vis {
>   unsigned final : 1;
>   /* Belong to FUNCTION_DECL exclusively.  */
>   unsigned regdecl_flag : 1;
> - /* 14 unused bits. */
> + /* 13 unused bits.  */

It doesn't look like DECL_UNINITIALIZED is used in compile-time-sensitive
code, so it might be better to keep "uninitialized" as a normal attribute
and use lookup_attribute where necessary.

>   /* 32 more unused on 64 bit HW. */
>  };
>  
> diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
> index d177f1b..fe439f7 100644
> --- a/gcc/tree-sra.c
> +++ b/gcc/tree-sra.c
> @@ -384,6 +384,13 @@ static struct
>  
>    /* Numbber of components created when splitting aggregate parameters.  */
>    int param_reductions_created;
> +
> +  /* Number of deferred_init calls that are modified.  */
> +  int deferred_init;
> +
> +  /* Number of deferred_init calls that are created by
> +     generate_subtree_deferred_init.  */
> +  int subtree_deferred_init;
>  } sra_stats;
>  
>  static void
> @@ -4070,6 +4077,105 @@ get_repl_default_def_ssa_name (struct access *racc, tree reg_type)
>    return get_or_create_ssa_default_def (cfun, racc->replacement_decl);
>  }
>  
> +
> +/* Generate statements to call .DEFERRED_INIT to initialize scalar replacements
> +   of accesses within a subtree ACCESS, all its children, siblings and their

IMO reads more easily with “;” rather than “,” before “all”

> +   children are to be processed.  TOP_OFFSET is the offset  of the processed
> +   subtree which has to be subtracted from offsets of individual accesses to
> +   get corresponding offsets for AGG.  GSI is a statement iterator used to place
> +   the new statements.  */
> +static void
> +generate_subtree_deferred_init (struct access *access, tree agg,
> +				enum auto_init_type init_type,
> +				HOST_WIDE_INT top_offset,
> +				gimple_stmt_iterator *gsi,
> +				location_t loc)
> +{
> +  do
> +    {
> +      if (access->grp_to_be_replaced)
> +	{
> +	  tree repl = get_access_replacement (access);
> +	  tree init_type_node
> +	    = build_int_cst (integer_type_node, (int) init_type);
> +	  gimple *call = gimple_build_call_internal (IFN_DEFERRED_INIT, 2,
> +						     repl, init_type_node);
> +	  gimple_call_set_lhs (call, repl);

AFAICT “access” is specifically for the lhs of the original call.
So there seems to be an implicit assumption here that the lhs of the
original call is the same as the first argument of the original call.
Is that guaranteed/required?  If so, I think it's something that
tree-cfg.c should check.  It might also be worth having an assertion
in sra_modify_deferred_init.

If the argument and lhs can be different then I think we need to
handle the access patterns for them both.

Or is the idea that any instance of:

  LHS = .DEFERRED_INIT (RHS, INIT_TYPE)

can be replaced with:

  LHS = .DEFERRED_INIT (LHS, INIT_TYPE)

without affecting semantics?  If so, I think that would be worth
a comment.

> +	  gsi_insert_before (gsi, call, GSI_SAME_STMT);
> +	  update_stmt (call);

It seems odd that we need to call update_stmt for a new stmt, but I see
other code in the file also does this.

> +	  gimple_set_location (call, loc);
> +
> +	  sra_stats.subtree_deferred_init++;
> +	}
> +      else if (access->grp_to_be_debug_replaced)
> +	{
> +	  /* FIXME, this part might have some issue.  */
> +	  tree drhs = build_debug_ref_for_model (loc, agg,
> +						 access->offset - top_offset,
> +						 access);
> +	  gdebug *ds = gimple_build_debug_bind (get_access_replacement (access),
> +						drhs, gsi_stmt (*gsi));
> +	  gsi_insert_before (gsi, ds, GSI_SAME_STMT);

Would be good to fix the FIXME :-)

I guess the thing we need to decide here is whether -ftrivial-auto-var-init
should affect debug-only constructs too.  If it doesn't, exmaining removed
components in a debugger might show uninitialised values in cases where
the user was expecting initialised ones.  There would be no security
concern, but it might be surprising.

I think in principle the DRHS can contain a call to DEFERRED_INIT.
Doing that would probably require further handling elsewhere though.

> +	}
> +      if (access->first_child)
> +	generate_subtree_deferred_init (access->first_child, agg, init_type,
> +					top_offset, gsi, loc);
> +
> +      access = access ->next_sibling;
> +    }
> +  while (access);
> +}
> +
> +/* For a call to .DEFERRED_INIT:
> +   var = .DEFERRED_INIT (var, init_type);
> +   examine the LHS variable VAR and replace it with a scalar replacement if
> +   there is one, also replace the RHS call to a call to .DEFERRED_INIT of
> +   the corresponding scalar relacement variable.  Examine the subtree and
> +   do the scalar replacements in the subtree too.  STMT is the call, GSI is
> +   the statment iterator to place newly created statements.  */

typo: statement

> +
> +static enum assignment_mod_result
> +sra_modify_deferred_init (gimple *stmt, gimple_stmt_iterator *gsi)
> +{
> +  tree lhs = gimple_call_lhs (stmt);
> +  enum auto_init_type init_type
> +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
> +  struct access *access = get_access_for_expr (lhs);
> +  if (!access)
> +    return SRA_AM_NONE;
> +  location_t loc = gimple_location (stmt);
> +
> +  if (access->grp_to_be_replaced)
> +    {
> +      tree repl = get_access_replacement (access);
> +      gimple_call_set_lhs (stmt, repl);
> +      gimple_call_set_arg (stmt, 0, repl);
> +      sra_stats.deferred_init++;
> +    }
> +  else if (access->grp_to_be_debug_replaced)
> +    {
> +      /* FIXME, this part might have some issues.  */
> +      tree drepl = get_access_replacement (access);
> +      gdebug *ds = gimple_build_debug_bind (drepl, NULL_TREE,
> +					    gsi_stmt (*gsi));
> +      gsi_insert_before (gsi, ds, GSI_SAME_STMT);
> +    }

Same comments as above.

> +
> +  if (access->first_child)
> +    generate_subtree_deferred_init (access->first_child, lhs,
> +				    init_type, access->offset,
> +				    gsi, loc);
> +  if (access->grp_covered)
> +    {
> +      unlink_stmt_vdef (stmt);
> +      gsi_remove (gsi, true);
> +      release_defs (stmt);
> +      return SRA_AM_REMOVED;
> +    }
> +
> +  return SRA_AM_MODIFIED;
> +}
> +
>  /* Examine both sides of the assignment statement pointed to by STMT, replace
>     them with a scalare replacement if there is one and generate copying of
>     replacements if scalarized aggregates have been used in the assignment.  GSI
> […]
> @@ -4863,6 +4863,29 @@ find_func_aliases_for_builtin_call (struct function *fn, gcall *t)
>    return false;
>  }
>  
> +static void
> +find_func_aliases_for_deferred_init (gcall *t)
> +{
> +  tree lhsop = gimple_call_lhs (t);
> +  enum auto_init_type init_type
> +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (t, 1));
> +  auto_vec<ce_s, 2> lhsc;
> +  auto_vec<ce_s, 4> rhsc;
> +  struct constraint_expr temp;
> +
> +  get_constraint_for (lhsop, &lhsc);
> +  if (init_type == AUTO_INIT_ZERO && flag_delete_null_pointer_checks)
> +    temp.var = nothing_id;
> +  else
> +    temp.var = nonlocal_id;
> +  temp.type = ADDRESSOF;
> +  temp.offset = 0;
> +  rhsc.safe_push (temp);
> +
> +  process_all_all_constraints (lhsc, rhsc);
> +  return;
> +}
> +

What's the reasoning behind doing it like this?  AFAICT the result
of the call doesn't validly alias anything, regardless of the init type.
Even if there happens to be a valid decl at the address given by the
chosen fill pattern, there's no expectation that accesses to that
decl will be coherent wrt accesses via the result of the call.

>  /* Create constraints for the call T.  */
>  
>  static void
> […]
> diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c
> index 0800f59..0c61f60 100644
> --- a/gcc/tree-ssa-uninit.c
> +++ b/gcc/tree-ssa-uninit.c
> @@ -135,6 +135,20 @@ warn_uninit (enum opt_code wc, tree t, tree expr, tree var,
>    if (is_gimple_assign (context)
>        && gimple_assign_rhs_code (context) == COMPLEX_EXPR)
>      return;
> +
> +  /* Ignore REALPART_EXPR or IMAGPART_EXPR if its operand is
> +     a call to .DEFERRED_INIT.  */
> +  if (is_gimple_assign (context)
> +      && (gimple_assign_rhs_code (context) == REALPART_EXPR
> +	  || gimple_assign_rhs_code (context) == IMAGPART_EXPR))
> +    {
> +      tree v = gimple_assign_rhs1 (context);
> +      if (TREE_CODE (TREE_OPERAND (v, 0)) == SSA_NAME
> +	  && gimple_call_internal_p (SSA_NAME_DEF_STMT (TREE_OPERAND (v, 0)),
> +				     IFN_DEFERRED_INIT))
> +	return;
> +    }
> +

Which case is this handling?  In this context I would have expected
the REALPART_EXPRs and IMAGPART_EXPRs to act like normal rvalue
accessors, i.e. they are returning one half of their argument and
discarding the other half.  Why is this different from, say, accessing
one field of a structure?

>    if (!has_undefined_value_p (t))
>      return;
>  
> @@ -209,6 +223,19 @@ check_defs (ao_ref *ref, tree vdef, void *data_)
>  {
>    check_defs_data *data = (check_defs_data *)data_;
>    gimple *def_stmt = SSA_NAME_DEF_STMT (vdef);
> +
> +  /* Ignore the vdef iff the definition statement is a call
> +     to .DEFERRED_INIT function.  */
> +  if (gimple_call_internal_p (def_stmt, IFN_DEFERRED_INIT))
> +    return false;
> +
> +  /* Ignore the vdef iff the definition statement is a call
> +     to builtin_memset function that is added for uninitialized
> +     auto variable initialization.  */
> +  if (gimple_call_builtin_p (def_stmt, BUILT_IN_MEMSET)
> +      && gimple_call_memset_for_uninit_p (def_stmt))
> +    return false;
> +

s/iff/if/, since the “only if” part doesn't apply.

>    /* If this is a clobber then if it is not a kill walk past it.  */
>    if (gimple_clobber_p (def_stmt))
>      {
> @@ -611,6 +638,9 @@ warn_uninitialized_vars (bool wmaybe_uninit)
>  	  ssa_op_iter op_iter;
>  	  tree use;
>  
> +	  if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
> +	    continue;
> +

I guess the reasoning here is that the call is an artificial use and so
won't give a meaningful error message.  If the result of the call is
used somewhere else then we warn there instead.

I think that deserves a comment though.

>  	  if (is_gimple_debug (stmt))
>  	    continue;
>  
> diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
> index cf54c89..93d6124 100644
> --- a/gcc/tree-ssa.c
> +++ b/gcc/tree-ssa.c
> @@ -1325,6 +1325,23 @@ 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;
> +
> +  if (partial && is_gimple_assign (def_stmt)
> +      && (gimple_assign_rhs_code (def_stmt) == REALPART_EXPR
> +	  || gimple_assign_rhs_code (def_stmt) == IMAGPART_EXPR))
> +    {
> +      tree real_imag_part = TREE_OPERAND (gimple_assign_rhs1 (def_stmt), 0);
> +      if (TREE_CODE (real_imag_part) == SSA_NAME
> +	 && gimple_call_internal_p (SSA_NAME_DEF_STMT (real_imag_part),
> +				    IFN_DEFERRED_INIT))
> +	return true;
> +    }
> +
> +

Same s/iff/if/ comment here.  Also same question as above about the
REALPART_EXPR/IMAGPART_EXPR thing.

Nit: too many blank links at the end.

>    /* Check if the complex was not only partially defined.  */
>    if (partial && is_gimple_assign (def_stmt)
>        && gimple_assign_rhs_code (def_stmt) == COMPLEX_EXPR)
> diff --git a/gcc/tree.c b/gcc/tree.c
> index 7c44c22..2c9acad 100644
> --- a/gcc/tree.c
> +++ b/gcc/tree.c
> @@ -2531,6 +2531,144 @@ build_zero_cst (tree type)
>      }
>  }
>  
> +/* Build pattern constant of type TYPE.  This is used for initializing
> +   auto variables.  */
> +
> +tree
> +build_pattern_cst (tree type)

I think this should have a more descriptive name, since the pattern
is very specific to the use case.

> +{
> +  /* The following value is a guaranteed unmappable pointer value and has a
> +     repeated byte-pattern which makes it easier to synthesize.  We use it for
> +     pointers as well as integers so that aggregates are likely to be
> +     initialized with this repeated value.  */
> +  uint64_t largevalue = 0xAAAAAAAAAAAAAAAAull;
> +  /* For 32-bit platforms it's a bit trickier because, across systems, only the
> +     zero page can reasonably be expected to be unmapped, and even then we need
> +     a very low address.  We use a smaller value, and that value sadly doesn't
> +     have a repeated byte-pattern.  We don't use it for integers.  */
> +  uint32_t smallvalue = 0x000000AA;
> +
> +  switch (TREE_CODE (type))
> +    {
> +    case INTEGER_TYPE:
> +    case ENUMERAL_TYPE:
> +    case BOOLEAN_TYPE:
> +      /* This will initialize a boolean type variable to 0 instead of 1.
> + 	 We think that initializint a boolean variable to 0 other than 1

initializing

> +	 is better even for pattern initialization.  */
> +      return build_int_cstu (type, largevalue);

I've no objection to that choice for booleans, but: booleans in some
languages (like Ada) can have multibit precision.  If we want booleans
to be zero then it would probably be better to treat them as a separate
case and just use build_zero_cst (type) for them.

Also, the above won't work correctly for 128-bit integers: it will
zero-initialize the upper half.  It would probably be better to use
wi::from_buffer to construct the integer instead.

I'm also not sure what effect this will have on enumerations, or when
the fill value is outside the TYPE_MIN_VALUE…TYPE_MAX_VALUE range.
Hopefully Richi will chime in :-)

> +    case POINTER_TYPE:
> +    case OFFSET_TYPE:
> +    case REFERENCE_TYPE:
> +    case NULLPTR_TYPE:
> +      {
> +	poly_uint64 intvalue;
> +
> +	if (POINTER_SIZE == 64)
> +	  intvalue = largevalue;
> +	else if (POINTER_SIZE == 32)
> +	  intvalue = smallvalue;
> +	else
> +	  gcc_assert (0);

GCC supports 16-bit targets, so we can't assert here.  We might as
well just go for 0xAA there too.

In fact it might be simpler to have something like:

  if (POINTER_TYPE_P (type) && TYPE_PRECISION (type) < 64)
    return build_int_cstu (type, 0xAA);

  if (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
    ...the wi::from_buffer thing above...;

I'm not sure if this makes sense for NULLPTR_TYPE.

> +	return build_int_cstu (type, intvalue);
> +      }
> +    case REAL_TYPE:
> +      {
> +	REAL_VALUE_TYPE rnan;
> +
> +	/* create an quiet NAN for REAL TYPE.  */
> +	if (real_nan (&rnan, "", 1, TYPE_MODE (type)))
> +	  return build_real (type, rnan);
> +	return NULL_TREE;

It doesn't look like the callers can cope with a null return value.
Maybe get_max_float would be a good fallback instead.

> +      }
> +
> +    case FIXED_POINT_TYPE:
> +      {
> +	/* FIXME.  What should we put into a fixed point?  */
> +	FIXED_VALUE_TYPE fixed;
> +	fixed_from_string (&fixed, "0xFFFFFFFFFFFFFFFF",
> +			   SCALAR_TYPE_MODE (type));
> +	return build_fixed (type, fixed);
> +      }
> +    case VECTOR_TYPE:
> +      {
> +	tree scalar = build_pattern_cst (TREE_TYPE (type));
> +	return build_vector_from_val (type, scalar);
> +      }
> +    case COMPLEX_TYPE:
> +      {
> +	tree element = build_pattern_cst (TREE_TYPE (type));
> +	return build_complex (type, element, element);
> +      }
> +    case RECORD_TYPE:
> +      {
> +	tree field;
> +	tree field_value;
> +	vec<constructor_elt, va_gc> *v = NULL;
> +	for (field= TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
> +	  {
> +	    if (TREE_CODE (field) != FIELD_DECL)
> +	      continue;
> +	    /* if the field is a variable length array, it should be the last

s/if/If/

> +	       field of the record, and no need to initialize.  */

Why doesn't it need to be initialized though?

> +	    if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
> +		&& TYPE_SIZE (TREE_TYPE (field)) == NULL_TREE
> +		&& ((TYPE_DOMAIN (TREE_TYPE (field)) != NULL_TREE
> +		    && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field)))
> +				       == NULL_TREE)
> +		   || TYPE_DOMAIN (TREE_TYPE (field)) == NULL_TREE))
> +	      continue;
> +	    field_value = build_pattern_cst (TREE_TYPE (field));
> +	    CONSTRUCTOR_APPEND_ELT (v, field, field_value);
> +	  }
> +	return build_constructor (type, v);
> +      }
> +    case UNION_TYPE:
> +    case QUAL_UNION_TYPE:
> +      {
> +	tree field, max_field = NULL;
> +	unsigned max_size = 0;
> +	tree field_value;
> +	vec<constructor_elt, va_gc> *v = NULL;
> +	/* find the field with the largest size.  */

s/find/Find/

> +	for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
> +	  {
> +	    if (TREE_CODE (field) != FIELD_DECL)
> +	      continue;
> +	    if (tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field))) >= max_size)
> +	      {
> +		max_size = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field)));
> +		max_field = field;
> +	      }

This isn't safe.  We shouldn't use tree_to_uhwi without checking whether
tree_fits_uhwi_p.  We then need a fallback for !tree_fits_uhwi_p.

> +	  }
> +	  field_value = build_pattern_cst (TREE_TYPE (max_field));
> +	  CONSTRUCTOR_APPEND_ELT (v, max_field, field_value);
> +	return build_constructor (type, v);
> +      }
> +    case ARRAY_TYPE:
> +      {
> +	vec<constructor_elt, va_gc> *elts = NULL;
> +	tree element = build_pattern_cst (TREE_TYPE (type));
> +	tree nelts = array_type_nelts (type);
> +	if (nelts && tree_fits_uhwi_p (nelts))
> +	  {
> +	    unsigned HOST_WIDE_INT n = tree_to_uhwi (nelts) + 1;
> +	    for (unsigned int i = 0; i < n; i++)
> +	      CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, element);
> +	    return build_constructor (type, elts);
> +	  }
> +	/* variable length array should not be here.  */

s/variable/Variable/

> +	gcc_assert (0);

Should be gcc_unreachable () instead.

> +      }
> +    default:
> +      if (!AGGREGATE_TYPE_P (type))
> +	return fold_convert (type, build_pattern_cst (unsigned_type_node));
> +      else
> +	gcc_assert (0);

Same here.

> @@ -11950,6 +12088,72 @@ lower_bound_in_type (tree outer, tree inner)
>      }
>  }
>  
> +/* Returns true when the given TYPE has padding inside it.
> +   return false otherwise.  */
> +bool
> +type_has_padding (tree type)

Would it be possible to reuse __builtin_clear_padding here?

> +{
> +  switch (TREE_CODE (type))
> +    {
> +    case RECORD_TYPE:
> +      {
> +	unsigned HOST_WIDE_INT record_size
> +	  = tree_to_uhwi (TYPE_SIZE_UNIT (type));

As above, it's not safe to just to use tree_to_uhwi here without checking.
I've skipped the rest of the function because of the builtin question above.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [patch for gcc12 stage1][version 2] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-04-23 19:05 ` Richard Sandiford
@ 2021-04-23 19:33   ` Kees Cook
  2021-04-26 15:09   ` Qing Zhao
  2021-05-05 14:41   ` Qing Zhao
  2 siblings, 0 replies; 13+ messages in thread
From: Kees Cook @ 2021-04-23 19:33 UTC (permalink / raw)
  To: Qing Zhao, Richard Biener, Gcc-patches Qing Zhao via, richard.sandiford

On Fri, Apr 23, 2021 at 08:05:29PM +0100, Richard Sandiford wrote:
> Finally getting to this now that the GCC 11 rush is over.  Sorry for
> the slow response.
> 
> I've tried to review most of the code below, but skipped the testsuite
> parts in the interests of time.  I'll probably have more comments in
> future rounds, just wanted to get the ball rolling.
> 
> This is realy Richi's area more than mine though, so please take this
> with a grain of salt.
> 
> Qing Zhao <qing.zhao@oracle.com> writes:
> > 2.  initialize all paddings to zero when -ftrivial-auto-var-init is present.
> > In expr.c (store_constructor):
> >
> >         Clear the whole structure when
> >         -ftrivial-auto-var-init and the structure has paddings.
> >
> > In gimplify.c (gimplify_init_constructor):
> >
> >         Clear the whole structure when
> >         -ftrivial-auto-var-init and the structure has paddings.
> 
> Just to check: are we sure we want to use zero as the padding fill
> value even for -ftrivial-auto-var-init=pattern?  Or should it be
> 0xAA instead, to match the integer fill pattern?
> 
> I can see the arguments both ways, just thought it was worth asking.

I have no opinion myself, but I can give background.  Originally, Clang
implemented using pattern, but there was discussion around it and the
decision there was to go with zero init, as it seemed to more closely
match the C spec:
https://github.com/llvm/llvm-project/commit/d39fbc7e20d84364e409ce59724ce20625637062

> > +This is C and C++'s default.
> > +
> > +@item
> > +@samp{pattern} Initialize automatic variables with values which will likely
> > +transform logic bugs into crashes down the line, are easily recognized in a
> > +crash dump and without being values that programmers can rely on for useful
> > +program semantics.
> > +The values used for pattern initialization might be changed in the future.
> > +
> > +@item
> > +@samp{zero} Initialize automatic variables with zeroes.
> > +@end itemize
> > +
> > +The default is @samp{uninitialized}.
> > +
> > +You can control this behavior for a specific variable by using the variable
> > +attribute @code{uninitialized} (@pxref{Variable Attributes}).
> > +
> 
> I think it's important to say here that GCC still considers the
> variables to be uninitialised and still considers reading them to
> be undefined behaviour.  The option is simply trying to improve the
> security and predictability of the program in the presence of these
> uninitialised variables.

Excellent point, yes. That'd be good to call out.

> > […]
> > @@ -1831,6 +2000,17 @@ 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.  */
> 
> I think we should explain why we can skip VLAs here.

FWIW, in testing, VLAs do get initialized, so I guess there's a separate
place where it happens.


Thanks for the review!

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [patch for gcc12 stage1][version 2] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-04-23 19:05 ` Richard Sandiford
  2021-04-23 19:33   ` Kees Cook
@ 2021-04-26 15:09   ` Qing Zhao
  2021-04-26 17:47     ` Richard Sandiford
  2021-05-05 17:29     ` Qing Zhao
  2021-05-05 14:41   ` Qing Zhao
  2 siblings, 2 replies; 13+ messages in thread
From: Qing Zhao @ 2021-04-26 15:09 UTC (permalink / raw)
  To: Richard Sandiford, Richard Biener; +Cc: Kees Cook, Gcc-patches Qing Zhao via

Hi, Richard,

Thanks a lot for your review.

> On Apr 23, 2021, at 2:05 PM, Richard Sandiford <richard.sandiford@arm.com> wrote:
> 
> Finally getting to this now that the GCC 11 rush is over.  Sorry for
> the slow response.
> 
> I've tried to review most of the code below, but skipped the testsuite
> parts in the interests of time.  I'll probably have more comments in
> future rounds, just wanted to get the ball rolling.
> 
> This is realy Richi's area more than mine though, so please take this
> with a grain of salt.
> 
> Qing Zhao <qing.zhao@oracle.com> writes:
>> 2.  initialize all paddings to zero when -ftrivial-auto-var-init is present.
>> In expr.c (store_constructor):
>> 
>>        Clear the whole structure when
>>        -ftrivial-auto-var-init and the structure has paddings.
>> 
>> In gimplify.c (gimplify_init_constructor):
>> 
>>        Clear the whole structure when
>>        -ftrivial-auto-var-init and the structure has paddings.
> 
> Just to check: are we sure we want to use zero as the padding fill
> value even for -ftrivial-auto-var-init=pattern?  Or should it be
> 0xAA instead, to match the integer fill pattern?
> 
> I can see the arguments both ways, just thought it was worth asking.

For this question, I think Kees had provided the background information on it.
Yes, this is basically following Clang’s current implementation in order to match C spec.

> 
>> […]
>> @@ -1589,6 +1592,24 @@ handle_retain_attribute (tree *pnode, tree name, tree ARG_UNUSED (args),
>>   return NULL_TREE;
>> }
>> 
>> +/* Handle a "uninitialized" attribute; arguments as in
> 
> This occurs in existing code too, but s/a/an/.
Okay, will fix it.
> 
>> +   struct attribute_spec.handler.  */
>> +
>> +static tree
>> +handle_uninitialized_attribute (tree *node, tree name, tree ARG_UNUSED (args),
>> +				int ARG_UNUSED (flags), bool *no_add_attrs)
>> +{
>> +  if (VAR_P (*node))
>> +    DECL_UNINITIALIZED (*node) = 1;
>> +  else
>> +    {
>> +      warning (OPT_Wattributes, "%qE attribute ignored", name);
>> +      *no_add_attrs = true;
>> +    }
>> +
>> +  return NULL_TREE;
>> +}
>> +
>> /* Handle a "externally_visible" attribute; arguments as in
>>    struct attribute_spec.handler.  */
> 
>> […]
>> @@ -11689,6 +11689,34 @@ Perform basic block vectorization on trees. This flag is enabled by default at
>> @option{-O3} and by @option{-ftree-vectorize}, @option{-fprofile-use},
>> and @option{-fauto-profile}.
>> 
>> +@item -ftrivial-auto-var-init=@var{choice}
>> +@opindex ftrivial-auto-var-init
>> +Initialize automatic variables with either a pattern or with zeroes to increase
>> +program security by preventing uninitialized memory disclosure and use.
>> +
>> +The three values of @var{choice} are:
>> +
>> +@itemize @bullet
>> +@item
>> +@samp{uninitialized} doesn't initialize any automatic variables.
>> +This is C and C++'s default.
>> +
>> +@item
>> +@samp{pattern} Initialize automatic variables with values which will likely
>> +transform logic bugs into crashes down the line, are easily recognized in a
>> +crash dump and without being values that programmers can rely on for useful
>> +program semantics.
>> +The values used for pattern initialization might be changed in the future.
>> +
>> +@item
>> +@samp{zero} Initialize automatic variables with zeroes.
>> +@end itemize
>> +
>> +The default is @samp{uninitialized}.
>> +
>> +You can control this behavior for a specific variable by using the variable
>> +attribute @code{uninitialized} (@pxref{Variable Attributes}).
>> +
> 
> I think it's important to say here that GCC still considers the
> variables to be uninitialised and still considers reading them to
> be undefined behaviour.  The option is simply trying to improve the
> security and predictability of the program in the presence of these
> uninitialised variables.
> 
> I think it would also be worth saying that options like -Wuninitialized
> still try to warn about uninitialised variables, although using
> -ftrivial-auto-var-init may change which warnings are generated.
> 
> (The above comments are just a summary, not suitable for direct
> inclusion. :-))

Agreed.

Will update the documentation per your suggestions.

> 
>> @item -fvect-cost-model=@var{model}
>> @opindex fvect-cost-model
>> Alter the cost model used for vectorization.  The @var{model} argument
>> […]
>> diff --git a/gcc/gimplify.c b/gcc/gimplify.c
>> index 6da6698..fafd2e9 100644
>> --- a/gcc/gimplify.c
>> +++ b/gcc/gimplify.c
>> @@ -1716,6 +1716,116 @@ gimplify_vla_decl (tree decl, gimple_seq *seq_p)
>> 
>>   gimplify_and_add (t, seq_p);
>> 
>> +  /* Add a call to memset or calls to memcpy to initialize this vla
>> +     when the user requested.  */
>> +  if (!DECL_ARTIFICIAL (decl)
>> +      && VAR_P (decl)
>> +      && !DECL_EXTERNAL (decl)
>> +      && !TREE_STATIC (decl)
>> +      && !DECL_UNINITIALIZED (decl))
>> +    switch (flag_trivial_auto_var_init)
>> +      {
>> +      case AUTO_INIT_UNINITIALIZED:
>> +	break;
>> +      case AUTO_INIT_ZERO:
>> +	{
>> +	  /* Generate a call to memset to initialize this vla.  */
>> +	  gcall *gs;
>> +	  t = builtin_decl_implicit (BUILT_IN_MEMSET);
>> +	  gs = gimple_build_call (t, 3, addr, integer_zero_node,
>> +				  DECL_SIZE_UNIT (decl));
>> +	  gimple_call_set_memset_for_uninit (gs, true);
>> +	  gimplify_seq_add_stmt (seq_p, gs);
>> +	}
>> +	break;
>> +      case AUTO_INIT_PATTERN:
>> +	{
>> +	  /* Generate the following sequence to initialize this vla:
>> +	     if (DECL_SIZE_UNIT (decl) > 0) goto label_true;
>> +					    else goto label_cont;
>> +	     label_true:
>> +	      {
>> +		element_type = TREE_TYPE (TREE_TYPE (decl));
>> +		size_of_element = DECL_SIZE_UNIT (element_type);
>> +		init_node = build_pattern_cst (element_type);
>> +		cur = addr;
>> +		offset = DECL_SIZE_UNIT (decl) - size_of_element;
>> +		end = addr + offset;
>> +
>> +		label_loop:
>> +		  {
>> +		    memcpy (cur, &init_node, size_of_element);
>> +		    cur  += size_of_element;
>> +		    if (cur <= end) goto label_loop;
>> +				    else goto label_cont;
>> +		  }
>> +	      }
>> +	      label_cont:
>> +	  */
>> +
>> +	  tree size_of_element, element_type;
>> +	  tree cur, end, offset;
>> +	  tree init_node, addrof_init_node;
>> +	  tree t;
>> +
>> +	  tree label_true = create_artificial_label (UNKNOWN_LOCATION);
>> +	  tree label_cont = create_artificial_label (UNKNOWN_LOCATION);
>> +	  tree label_loop = create_artificial_label (UNKNOWN_LOCATION);
>> +
>> +	  element_type = TREE_TYPE (TREE_TYPE (decl));
>> +
>> +	  gcond *cond_stmt = gimple_build_cond (GT_EXPR, DECL_SIZE_UNIT (decl),
>> +						build_zero_cst (sizetype),
>> +						label_true,
>> +						label_cont);
>> +	  gimplify_seq_add_stmt (seq_p, cond_stmt);
>> +	  gimplify_seq_add_stmt (seq_p, gimple_build_label (label_true));
>> +
>> +	  size_of_element = create_tmp_var (sizetype,
>> +					    ".size_of_element");
>> +
>> +	  init_node = create_tmp_var (element_type, ".init_node");
>> +	  mark_addressable (init_node);
>> +	  addrof_init_node = build_fold_addr_expr_loc (UNKNOWN_LOCATION,
>> +						       init_node);
>> +
>> +	  gimplify_assign (size_of_element, TYPE_SIZE_UNIT (element_type),
>> +			   seq_p);
>> +	  gimplify_assign (init_node, build_pattern_cst (element_type), seq_p);
> 
> Rather than building a separate init_node here, would it work to assign
> to element 0 instead?  Then the loop could start at element 1.
I think that should be fine, can save a little time. 
> 
> What about nested VLAs, like:
> 
>  void g(void *);
>  void f(int a)
>  {
>    int x[a][a];
>    g(x);
>  }
> 
Will check on this. 
> ?
> 
>> +
>> +	  cur = create_tmp_var (ptr_type, ".cur_addr");
>> +	  end = create_tmp_var (ptr_type, ".end_addr");
>> +	  offset = create_tmp_var (sizetype, ".offset");
>> +
>> +	  gimplify_assign (cur, addr, seq_p);
>> +	  gimplify_seq_add_stmt (seq_p,
>> +				 gimple_build_assign (offset, MINUS_EXPR,
>> +						      DECL_SIZE_UNIT (decl),
>> +						      size_of_element));
>> +	  gimplify_seq_add_stmt (seq_p,
>> +				 gimple_build_assign (end, POINTER_PLUS_EXPR,
>> +						      addr, offset));
>> +
>> +	  gimplify_seq_add_stmt (seq_p, gimple_build_label (label_loop));
>> +
>> +	  t = builtin_decl_implicit (BUILT_IN_MEMCPY);
>> +	  gimplify_seq_add_stmt (seq_p,
>> +				 gimple_build_call (t, 3, cur,
>> +						    addrof_init_node,
>> +						    size_of_element));
>> +	  gimplify_seq_add_stmt (seq_p,
>> +				 gimple_build_assign (cur, POINTER_PLUS_EXPR,
>> +						      cur, size_of_element));
>> +	  cond_stmt = gimple_build_cond (LE_EXPR, cur, end, label_loop,
>> +					 label_cont);
>> +	  gimplify_seq_add_stmt (seq_p, cond_stmt);
>> +	  gimplify_seq_add_stmt (seq_p, gimple_build_label (label_cont));
>> +	}
>> +	break;
>> +      default:
>> +	gcc_assert (0);
>> +      }
>> +
>>   /* Record the dynamic allocation associated with DECL if requested.  */
>>   if (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC)
>>     record_dynamic_alloc (decl);
>> @@ -1738,6 +1848,65 @@ 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).  */
> 
> I don't think it's necessary to repeat the definition here.

Okay, will delete it.

> 
>> +
>> +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);
> 
> Nit: indentation is off in the return statement.
Okay.

> 
>> +}
>> +
>> […]
>> @@ -1831,6 +2000,17 @@ 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.  */
> 
> I think we should explain why we can skip VLAs here.

VLA is handled in another place already, it should be initialized with calls to memset/memcpy.

> 
>> +      else if (flag_trivial_auto_var_init > AUTO_INIT_UNINITIALIZED
>> +	       && !DECL_UNINITIALIZED (decl)
>> +	       && !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/tree-cfg.c b/gcc/tree-cfg.c
>> index 7e3aae5..da02be2 100644
>> --- a/gcc/tree-cfg.c
>> +++ b/gcc/tree-cfg.c
>> @@ -3471,6 +3471,9 @@ verify_gimple_call (gcall *stmt)
>> 	}
>>     }
>> 
>> +  if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
>> +    return false;
>> +
> 
> Why is this needed?  I think a comment would be helpful.
Will add the comments.
> 
>>   /* ???  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-core.h b/gcc/tree-core.h
>> index d2e6c89..fb42c41 100644
>> --- a/gcc/tree-core.h
>> +++ b/gcc/tree-core.h
>> @@ -1815,6 +1815,7 @@ struct GTY(()) tree_decl_with_vis {
>>  unsigned in_text_section : 1;
>>  unsigned in_constant_pool : 1;
>>  unsigned dllimport_flag : 1;
>> + unsigned uninitialized : 1;
>>  /* Don't belong to VAR_DECL exclusively.  */
>>  unsigned weak_flag : 1;
>> 
>> @@ -1836,7 +1837,7 @@ struct GTY(()) tree_decl_with_vis {
>>  unsigned final : 1;
>>  /* Belong to FUNCTION_DECL exclusively.  */
>>  unsigned regdecl_flag : 1;
>> - /* 14 unused bits. */
>> + /* 13 unused bits.  */
> 
> It doesn't look like DECL_UNINITIALIZED is used in compile-time-sensitive
> code, so it might be better to keep "uninitialized" as a normal attribute
> and use lookup_attribute where necessary.

Okay. 

> 
>>  /* 32 more unused on 64 bit HW. */
>> };
>> 
>> diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
>> index d177f1b..fe439f7 100644
>> --- a/gcc/tree-sra.c
>> +++ b/gcc/tree-sra.c
>> @@ -384,6 +384,13 @@ static struct
>> 
>>   /* Numbber of components created when splitting aggregate parameters.  */
>>   int param_reductions_created;
>> +
>> +  /* Number of deferred_init calls that are modified.  */
>> +  int deferred_init;
>> +
>> +  /* Number of deferred_init calls that are created by
>> +     generate_subtree_deferred_init.  */
>> +  int subtree_deferred_init;
>> } sra_stats;
>> 
>> static void
>> @@ -4070,6 +4077,105 @@ get_repl_default_def_ssa_name (struct access *racc, tree reg_type)
>>   return get_or_create_ssa_default_def (cfun, racc->replacement_decl);
>> }
>> 
>> +
>> +/* Generate statements to call .DEFERRED_INIT to initialize scalar replacements
>> +   of accesses within a subtree ACCESS, all its children, siblings and their
> 
> IMO reads more easily with “;” rather than “,” before “all”
Okay.

> 
>> +   children are to be processed.  TOP_OFFSET is the offset  of the processed
>> +   subtree which has to be subtracted from offsets of individual accesses to
>> +   get corresponding offsets for AGG.  GSI is a statement iterator used to place
>> +   the new statements.  */
>> +static void
>> +generate_subtree_deferred_init (struct access *access, tree agg,
>> +				enum auto_init_type init_type,
>> +				HOST_WIDE_INT top_offset,
>> +				gimple_stmt_iterator *gsi,
>> +				location_t loc)
>> +{
>> +  do
>> +    {
>> +      if (access->grp_to_be_replaced)
>> +	{
>> +	  tree repl = get_access_replacement (access);
>> +	  tree init_type_node
>> +	    = build_int_cst (integer_type_node, (int) init_type);
>> +	  gimple *call = gimple_build_call_internal (IFN_DEFERRED_INIT, 2,
>> +						     repl, init_type_node);
>> +	  gimple_call_set_lhs (call, repl);
> 
> AFAICT “access” is specifically for the lhs of the original call.
> So there seems to be an implicit assumption here that the lhs of the
> original call is the same as the first argument of the original call.
> Is that guaranteed/required?

For call to DEFFERED_INIT, yes, this is guaranteed.

>  If so, I think it's something that
> tree-cfg.c should check.  It might also be worth having an assertion
> in sra_modify_deferred_init.
I can definitely add an assertion to make sure this.

> 
> If the argument and lhs can be different then I think we need to
> handle the access patterns for them both.
> 
> Or is the idea that any instance of:
> 
>  LHS = .DEFERRED_INIT (RHS, INIT_TYPE)
> 
> can be replaced with:
> 
>  LHS = .DEFERRED_INIT (LHS, INIT_TYPE)
> 
> without affecting semantics?  If so, I think that would be worth
> a comment.
> 
>> +	  gsi_insert_before (gsi, call, GSI_SAME_STMT);
>> +	  update_stmt (call);
> 
> It seems odd that we need to call update_stmt for a new stmt, but I see
> other code in the file also does this.
Will double check on this. 
> 
>> +	  gimple_set_location (call, loc);
>> +
>> +	  sra_stats.subtree_deferred_init++;
>> +	}
>> +      else if (access->grp_to_be_debug_replaced)
>> +	{
>> +	  /* FIXME, this part might have some issue.  */
>> +	  tree drhs = build_debug_ref_for_model (loc, agg,
>> +						 access->offset - top_offset,
>> +						 access);
>> +	  gdebug *ds = gimple_build_debug_bind (get_access_replacement (access),
>> +						drhs, gsi_stmt (*gsi));
>> +	  gsi_insert_before (gsi, ds, GSI_SAME_STMT);
> 
> Would be good to fix the FIXME :-)

This is the part I am not very sure, so I added the FIXME in order to get more review and suggestion
 to make sure it. -:)
> 
> I guess the thing we need to decide here is whether -ftrivial-auto-var-init
> should affect debug-only constructs too.

Where can I get more details on Debug-only constructs ?

>  If it doesn't, exmaining removed
> components in a debugger might show uninitialised values in cases where
> the user was expecting initialised ones.  There would be no security
> concern, but it might be surprising.
> 
> I think in principle the DRHS can contain a call to DEFERRED_INIT.
> Doing that would probably require further handling elsewhere though.

What’s DRHS? Where can I get more info on it?

> 
>> +	}
>> +      if (access->first_child)
>> +	generate_subtree_deferred_init (access->first_child, agg, init_type,
>> +					top_offset, gsi, loc);
>> +
>> +      access = access ->next_sibling;
>> +    }
>> +  while (access);
>> +}
>> +
>> +/* For a call to .DEFERRED_INIT:
>> +   var = .DEFERRED_INIT (var, init_type);
>> +   examine the LHS variable VAR and replace it with a scalar replacement if
>> +   there is one, also replace the RHS call to a call to .DEFERRED_INIT of
>> +   the corresponding scalar relacement variable.  Examine the subtree and
>> +   do the scalar replacements in the subtree too.  STMT is the call, GSI is
>> +   the statment iterator to place newly created statements.  */
> 
> typo: statement
Okay.
> 
>> +
>> +static enum assignment_mod_result
>> +sra_modify_deferred_init (gimple *stmt, gimple_stmt_iterator *gsi)
>> +{
>> +  tree lhs = gimple_call_lhs (stmt);
>> +  enum auto_init_type init_type
>> +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
>> +  struct access *access = get_access_for_expr (lhs);
>> +  if (!access)
>> +    return SRA_AM_NONE;
>> +  location_t loc = gimple_location (stmt);
>> +
>> +  if (access->grp_to_be_replaced)
>> +    {
>> +      tree repl = get_access_replacement (access);
>> +      gimple_call_set_lhs (stmt, repl);
>> +      gimple_call_set_arg (stmt, 0, repl);
>> +      sra_stats.deferred_init++;
>> +    }
>> +  else if (access->grp_to_be_debug_replaced)
>> +    {
>> +      /* FIXME, this part might have some issues.  */
>> +      tree drepl = get_access_replacement (access);
>> +      gdebug *ds = gimple_build_debug_bind (drepl, NULL_TREE,
>> +					    gsi_stmt (*gsi));
>> +      gsi_insert_before (gsi, ds, GSI_SAME_STMT);
>> +    }
> 
> Same comments as above.
OKay, will try to understand Debug-only construct details. 
> 
>> +
>> +  if (access->first_child)
>> +    generate_subtree_deferred_init (access->first_child, lhs,
>> +				    init_type, access->offset,
>> +				    gsi, loc);
>> +  if (access->grp_covered)
>> +    {
>> +      unlink_stmt_vdef (stmt);
>> +      gsi_remove (gsi, true);
>> +      release_defs (stmt);
>> +      return SRA_AM_REMOVED;
>> +    }
>> +
>> +  return SRA_AM_MODIFIED;
>> +}
>> +
>> /* Examine both sides of the assignment statement pointed to by STMT, replace
>>    them with a scalare replacement if there is one and generate copying of
>>    replacements if scalarized aggregates have been used in the assignment.  GSI
>> […]
>> @@ -4863,6 +4863,29 @@ find_func_aliases_for_builtin_call (struct function *fn, gcall *t)
>>   return false;
>> }
>> 
>> +static void
>> +find_func_aliases_for_deferred_init (gcall *t)
>> +{
>> +  tree lhsop = gimple_call_lhs (t);
>> +  enum auto_init_type init_type
>> +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (t, 1));
>> +  auto_vec<ce_s, 2> lhsc;
>> +  auto_vec<ce_s, 4> rhsc;
>> +  struct constraint_expr temp;
>> +
>> +  get_constraint_for (lhsop, &lhsc);
>> +  if (init_type == AUTO_INIT_ZERO && flag_delete_null_pointer_checks)
>> +    temp.var = nothing_id;
>> +  else
>> +    temp.var = nonlocal_id;
>> +  temp.type = ADDRESSOF;
>> +  temp.offset = 0;
>> +  rhsc.safe_push (temp);
>> +
>> +  process_all_all_constraints (lhsc, rhsc);
>> +  return;
>> +}
>> +
> 
> What's the reasoning behind doing it like this?  AFAICT the result
> of the call doesn't validly alias anything, regardless of the init type.
> Even if there happens to be a valid decl at the address given by the
> chosen fill pattern, there's no expectation that accesses to that
> decl will be coherent wrt accesses via the result of the call.

So, you mean the above change will not have any impact at all?

> 
>> /* Create constraints for the call T.  */
>> 
>> static void
>> […]
>> diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c
>> index 0800f59..0c61f60 100644
>> --- a/gcc/tree-ssa-uninit.c
>> +++ b/gcc/tree-ssa-uninit.c
>> @@ -135,6 +135,20 @@ warn_uninit (enum opt_code wc, tree t, tree expr, tree var,
>>   if (is_gimple_assign (context)
>>       && gimple_assign_rhs_code (context) == COMPLEX_EXPR)
>>     return;
>> +
>> +  /* Ignore REALPART_EXPR or IMAGPART_EXPR if its operand is
>> +     a call to .DEFERRED_INIT.  */
>> +  if (is_gimple_assign (context)
>> +      && (gimple_assign_rhs_code (context) == REALPART_EXPR
>> +	  || gimple_assign_rhs_code (context) == IMAGPART_EXPR))
>> +    {
>> +      tree v = gimple_assign_rhs1 (context);
>> +      if (TREE_CODE (TREE_OPERAND (v, 0)) == SSA_NAME
>> +	  && gimple_call_internal_p (SSA_NAME_DEF_STMT (TREE_OPERAND (v, 0)),
>> +				     IFN_DEFERRED_INIT))
>> +	return;
>> +    }
>> +
> 
> Which case is this handling?  In this context I would have expected
> the REALPART_EXPRs and IMAGPART_EXPRs to act like normal rvalue
> accessors, i.e. they are returning one half of their argument and
> discarding the other half.  Why is this different from, say, accessing
> one field of a structure?

I should add comments when I added this part of the code.
I remembered that this was to fix a missed warning for complex expression in the regression test.
But I forgot the details, I will check on this, and add more detailed comments in the code.

> 
>>   if (!has_undefined_value_p (t))
>>     return;
>> 
>> @@ -209,6 +223,19 @@ check_defs (ao_ref *ref, tree vdef, void *data_)
>> {
>>   check_defs_data *data = (check_defs_data *)data_;
>>   gimple *def_stmt = SSA_NAME_DEF_STMT (vdef);
>> +
>> +  /* Ignore the vdef iff the definition statement is a call
>> +     to .DEFERRED_INIT function.  */
>> +  if (gimple_call_internal_p (def_stmt, IFN_DEFERRED_INIT))
>> +    return false;
>> +
>> +  /* Ignore the vdef iff the definition statement is a call
>> +     to builtin_memset function that is added for uninitialized
>> +     auto variable initialization.  */
>> +  if (gimple_call_builtin_p (def_stmt, BUILT_IN_MEMSET)
>> +      && gimple_call_memset_for_uninit_p (def_stmt))
>> +    return false;
>> +
> 
> s/iff/if/, since the “only if” part doesn't apply.
Okay.
> 
>>   /* If this is a clobber then if it is not a kill walk past it.  */
>>   if (gimple_clobber_p (def_stmt))
>>     {
>> @@ -611,6 +638,9 @@ warn_uninitialized_vars (bool wmaybe_uninit)
>> 	  ssa_op_iter op_iter;
>> 	  tree use;
>> 
>> +	  if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
>> +	    continue;
>> +
> 
> I guess the reasoning here is that the call is an artificial use and so
> won't give a meaningful error message.  If the result of the call is
> used somewhere else then we warn there instead.

Yes.
> 
> I think that deserves a comment though.

Will add comments here.
> 
>> 	  if (is_gimple_debug (stmt))
>> 	    continue;
>> 
>> diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
>> index cf54c89..93d6124 100644
>> --- a/gcc/tree-ssa.c
>> +++ b/gcc/tree-ssa.c
>> @@ -1325,6 +1325,23 @@ 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;
>> +
>> +  if (partial && is_gimple_assign (def_stmt)
>> +      && (gimple_assign_rhs_code (def_stmt) == REALPART_EXPR
>> +	  || gimple_assign_rhs_code (def_stmt) == IMAGPART_EXPR))
>> +    {
>> +      tree real_imag_part = TREE_OPERAND (gimple_assign_rhs1 (def_stmt), 0);
>> +      if (TREE_CODE (real_imag_part) == SSA_NAME
>> +	 && gimple_call_internal_p (SSA_NAME_DEF_STMT (real_imag_part),
>> +				    IFN_DEFERRED_INIT))
>> +	return true;
>> +    }
>> +
>> +
> 
> Same s/iff/if/ comment here.  Also same question as above about the
> REALPART_EXPR/IMAGPART_EXPR thing.

Okay, will check on the details and add more comments.
> 
> Nit: too many blank links at the end.

Will fix this.

> 
>>   /* Check if the complex was not only partially defined.  */
>>   if (partial && is_gimple_assign (def_stmt)
>>       && gimple_assign_rhs_code (def_stmt) == COMPLEX_EXPR)
>> diff --git a/gcc/tree.c b/gcc/tree.c
>> index 7c44c22..2c9acad 100644
>> --- a/gcc/tree.c
>> +++ b/gcc/tree.c
>> @@ -2531,6 +2531,144 @@ build_zero_cst (tree type)
>>     }
>> }
>> 
>> +/* Build pattern constant of type TYPE.  This is used for initializing
>> +   auto variables.  */
>> +
>> +tree
>> +build_pattern_cst (tree type)
> 
> I think this should have a more descriptive name, since the pattern
> is very specific to the use case.

Agreed, will change the name more specifically. 
> 
>> +{
>> +  /* The following value is a guaranteed unmappable pointer value and has a
>> +     repeated byte-pattern which makes it easier to synthesize.  We use it for
>> +     pointers as well as integers so that aggregates are likely to be
>> +     initialized with this repeated value.  */
>> +  uint64_t largevalue = 0xAAAAAAAAAAAAAAAAull;
>> +  /* For 32-bit platforms it's a bit trickier because, across systems, only the
>> +     zero page can reasonably be expected to be unmapped, and even then we need
>> +     a very low address.  We use a smaller value, and that value sadly doesn't
>> +     have a repeated byte-pattern.  We don't use it for integers.  */
>> +  uint32_t smallvalue = 0x000000AA;
>> +
>> +  switch (TREE_CODE (type))
>> +    {
>> +    case INTEGER_TYPE:
>> +    case ENUMERAL_TYPE:
>> +    case BOOLEAN_TYPE:
>> +      /* This will initialize a boolean type variable to 0 instead of 1.
>> + 	 We think that initializint a boolean variable to 0 other than 1
> 
> initializing

Okay.
> 
>> +	 is better even for pattern initialization.  */
>> +      return build_int_cstu (type, largevalue);
> 
> I've no objection to that choice for booleans, but: booleans in some
> languages (like Ada) can have multibit precision.  If we want booleans
> to be zero then it would probably be better to treat them as a separate
> case and just use build_zero_cst (type) for them.

Good point, yes, it might be better to handle boolean separately.

> 
> Also, the above won't work correctly for 128-bit integers: it will
> zero-initialize the upper half.  It would probably be better to use
> wi::from_buffer to construct the integer instead.

Okay.

> 
> I'm also not sure what effect this will have on enumerations, or when
> the fill value is outside the TYPE_MIN_VALUE…TYPE_MAX_VALUE range.
> Hopefully Richi will chime in :-)

The pattern initialization part is much more tricky, I am hoping to get more help and
Discussion here to make sure each case.


> 
>> +    case POINTER_TYPE:
>> +    case OFFSET_TYPE:
>> +    case REFERENCE_TYPE:
>> +    case NULLPTR_TYPE:
>> +      {
>> +	poly_uint64 intvalue;
>> +
>> +	if (POINTER_SIZE == 64)
>> +	  intvalue = largevalue;
>> +	else if (POINTER_SIZE == 32)
>> +	  intvalue = smallvalue;
>> +	else
>> +	  gcc_assert (0);
> 
> GCC supports 16-bit targets, so we can't assert here.  We might as
> well just go for 0xAA there too.

Okay.

> 
> In fact it might be simpler to have something like:
> 
>  if (POINTER_TYPE_P (type) && TYPE_PRECISION (type) < 64)
>    return build_int_cstu (type, 0xAA);
> 
>  if (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
>    ...the wi::from_buffer thing above...;

Okay.
> 
> I'm not sure if this makes sense for NULLPTR_TYPE.

Is there a good testing case in gcc test suite about NULLPTR_TYPE that I can take a look?

> 
>> +	return build_int_cstu (type, intvalue);
>> +      }
>> +    case REAL_TYPE:
>> +      {
>> +	REAL_VALUE_TYPE rnan;
>> +
>> +	/* create an quiet NAN for REAL TYPE.  */
>> +	if (real_nan (&rnan, "", 1, TYPE_MODE (type)))
>> +	  return build_real (type, rnan);
>> +	return NULL_TREE;
> 
> It doesn't look like the callers can cope with a null return value.
> Maybe get_max_float would be a good fallback instead.

Okay.
> 
>> +      }
>> +
>> +    case FIXED_POINT_TYPE:
>> +      {
>> +	/* FIXME.  What should we put into a fixed point?  */
>> +	FIXED_VALUE_TYPE fixed;
>> +	fixed_from_string (&fixed, "0xFFFFFFFFFFFFFFFF",
>> +			   SCALAR_TYPE_MODE (type));
>> +	return build_fixed (type, fixed);
>> +      }
>> +    case VECTOR_TYPE:
>> +      {
>> +	tree scalar = build_pattern_cst (TREE_TYPE (type));
>> +	return build_vector_from_val (type, scalar);
>> +      }
>> +    case COMPLEX_TYPE:
>> +      {
>> +	tree element = build_pattern_cst (TREE_TYPE (type));
>> +	return build_complex (type, element, element);
>> +      }
>> +    case RECORD_TYPE:
>> +      {
>> +	tree field;
>> +	tree field_value;
>> +	vec<constructor_elt, va_gc> *v = NULL;
>> +	for (field= TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
>> +	  {
>> +	    if (TREE_CODE (field) != FIELD_DECL)
>> +	      continue;
>> +	    /* if the field is a variable length array, it should be the last
> 
> s/if/If/

Okay.
> 
>> +	       field of the record, and no need to initialize.  */
> 
> Why doesn't it need to be initialized though?

My understanding is, the compiler will not allocate memory for the latest field of the record if its a VLA, it’s the user’s responsibility to allocate 
Memory for it.  Therefore, compiler doesn’t  need to initialize it.
> 
>> +	    if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
>> +		&& TYPE_SIZE (TREE_TYPE (field)) == NULL_TREE
>> +		&& ((TYPE_DOMAIN (TREE_TYPE (field)) != NULL_TREE
>> +		    && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field)))
>> +				       == NULL_TREE)
>> +		   || TYPE_DOMAIN (TREE_TYPE (field)) == NULL_TREE))
>> +	      continue;
>> +	    field_value = build_pattern_cst (TREE_TYPE (field));
>> +	    CONSTRUCTOR_APPEND_ELT (v, field, field_value);
>> +	  }
>> +	return build_constructor (type, v);
>> +      }
>> +    case UNION_TYPE:
>> +    case QUAL_UNION_TYPE:
>> +      {
>> +	tree field, max_field = NULL;
>> +	unsigned max_size = 0;
>> +	tree field_value;
>> +	vec<constructor_elt, va_gc> *v = NULL;
>> +	/* find the field with the largest size.  */
> 
> s/find/Find/

Okay.
> 
>> +	for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
>> +	  {
>> +	    if (TREE_CODE (field) != FIELD_DECL)
>> +	      continue;
>> +	    if (tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field))) >= max_size)
>> +	      {
>> +		max_size = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field)));
>> +		max_field = field;
>> +	      }
> 
> This isn't safe.  We shouldn't use tree_to_uhwi without checking whether
> tree_fits_uhwi_p.  We then need a fallback for !tree_fits_uhwi_p.

Okay, will make sure this.

> 
>> +	  }
>> +	  field_value = build_pattern_cst (TREE_TYPE (max_field));
>> +	  CONSTRUCTOR_APPEND_ELT (v, max_field, field_value);
>> +	return build_constructor (type, v);
>> +      }
>> +    case ARRAY_TYPE:
>> +      {
>> +	vec<constructor_elt, va_gc> *elts = NULL;
>> +	tree element = build_pattern_cst (TREE_TYPE (type));
>> +	tree nelts = array_type_nelts (type);
>> +	if (nelts && tree_fits_uhwi_p (nelts))
>> +	  {
>> +	    unsigned HOST_WIDE_INT n = tree_to_uhwi (nelts) + 1;
>> +	    for (unsigned int i = 0; i < n; i++)
>> +	      CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, element);
>> +	    return build_constructor (type, elts);
>> +	  }
>> +	/* variable length array should not be here.  */
> 
> s/variable/Variable/

Okay.
> 
>> +	gcc_assert (0);
> 
> Should be gcc_unreachable () instead.
Okay.

> 
>> +      }
>> +    default:
>> +      if (!AGGREGATE_TYPE_P (type))
>> +	return fold_convert (type, build_pattern_cst (unsigned_type_node));
>> +      else
>> +	gcc_assert (0);
> 
> Same here.
Okay.
> 
>> @@ -11950,6 +12088,72 @@ lower_bound_in_type (tree outer, tree inner)
>>     }
>> }
>> 
>> +/* Returns true when the given TYPE has padding inside it.
>> +   return false otherwise.  */
>> +bool
>> +type_has_padding (tree type)
> 
> Would it be possible to reuse __builtin_clear_padding here?

Not sure, where can I get more details on __builtin_clear_padding? I can study a little bit more on this to make sure this.
> 
>> +{
>> +  switch (TREE_CODE (type))
>> +    {
>> +    case RECORD_TYPE:
>> +      {
>> +	unsigned HOST_WIDE_INT record_size
>> +	  = tree_to_uhwi (TYPE_SIZE_UNIT (type));
> 
> As above, it's not safe to just to use tree_to_uhwi here without checking.
> I've skipped the rest of the function because of the builtin question above.

Okay.

Thanks a lot again for your review.

Qing
> 
> Thanks,
> Richard


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [patch for gcc12 stage1][version 2] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-04-26 15:09   ` Qing Zhao
@ 2021-04-26 17:47     ` Richard Sandiford
  2021-04-26 20:02       ` Qing Zhao
  2021-04-27  6:30       ` Richard Biener
  2021-05-05 17:29     ` Qing Zhao
  1 sibling, 2 replies; 13+ messages in thread
From: Richard Sandiford @ 2021-04-26 17:47 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Richard Biener, Kees Cook, Gcc-patches Qing Zhao via

Qing Zhao <qing.zhao@oracle.com> writes:
>>> @@ -1831,6 +2000,17 @@ 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.  */
>> 
>> I think we should explain why we can skip VLAs here.
>
> VLA is handled in another place already, it should be initialized with calls to memset/memcpy.

Yeah, what I meant here was that the comment should explain the
difference between the handling of VLAs and non-VLAs.  It's fairly
obvious when reading the patch, but it won't be as obvious once the
patch is applied.

>>> +   children are to be processed.  TOP_OFFSET is the offset  of the processed
>>> +   subtree which has to be subtracted from offsets of individual accesses to
>>> +   get corresponding offsets for AGG.  GSI is a statement iterator used to place
>>> +   the new statements.  */
>>> +static void
>>> +generate_subtree_deferred_init (struct access *access, tree agg,
>>> +				enum auto_init_type init_type,
>>> +				HOST_WIDE_INT top_offset,
>>> +				gimple_stmt_iterator *gsi,
>>> +				location_t loc)
>>> +{
>>> +  do
>>> +    {
>>> +      if (access->grp_to_be_replaced)
>>> +	{
>>> +	  tree repl = get_access_replacement (access);
>>> +	  tree init_type_node
>>> +	    = build_int_cst (integer_type_node, (int) init_type);
>>> +	  gimple *call = gimple_build_call_internal (IFN_DEFERRED_INIT, 2,
>>> +						     repl, init_type_node);
>>> +	  gimple_call_set_lhs (call, repl);
>> 
>> AFAICT “access” is specifically for the lhs of the original call.
>> So there seems to be an implicit assumption here that the lhs of the
>> original call is the same as the first argument of the original call.
>> Is that guaranteed/required?
>
> For call to DEFFERED_INIT, yes, this is guaranteed.

OK, in that case…

>>  If so, I think it's something that
>> tree-cfg.c should check.  It might also be worth having an assertion
>> in sra_modify_deferred_init.
> I can definitely add an assertion to make sure this.

…I think we need the tree-cfg.c check too.  Having the check there
ensures that the invariant is maintained throughout gimple.

>>> +	  gimple_set_location (call, loc);
>>> +
>>> +	  sra_stats.subtree_deferred_init++;
>>> +	}
>>> +      else if (access->grp_to_be_debug_replaced)
>>> +	{
>>> +	  /* FIXME, this part might have some issue.  */
>>> +	  tree drhs = build_debug_ref_for_model (loc, agg,
>>> +						 access->offset - top_offset,
>>> +						 access);
>>> +	  gdebug *ds = gimple_build_debug_bind (get_access_replacement (access),
>>> +						drhs, gsi_stmt (*gsi));
>>> +	  gsi_insert_before (gsi, ds, GSI_SAME_STMT);
>> 
>> Would be good to fix the FIXME :-)
>
> This is the part I am not very sure, so I added the FIXME in order to get more review and suggestion
>  to make sure it. -:)
>> 
>> I guess the thing we need to decide here is whether -ftrivial-auto-var-init
>> should affect debug-only constructs too.
>
> Where can I get more details on Debug-only constructs ?

What I meant by “debug-only construct” is a piece of source-level data
(in this case a field of an aggregate) that has been optimised out of
the executable code but still exists in debug stmts.  AIUI that's what
the code above is handling.

>>> @@ -4863,6 +4863,29 @@ find_func_aliases_for_builtin_call (struct function *fn, gcall *t)
>>>   return false;
>>> }
>>> 
>>> +static void
>>> +find_func_aliases_for_deferred_init (gcall *t)
>>> +{
>>> +  tree lhsop = gimple_call_lhs (t);
>>> +  enum auto_init_type init_type
>>> +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (t, 1));
>>> +  auto_vec<ce_s, 2> lhsc;
>>> +  auto_vec<ce_s, 4> rhsc;
>>> +  struct constraint_expr temp;
>>> +
>>> +  get_constraint_for (lhsop, &lhsc);
>>> +  if (init_type == AUTO_INIT_ZERO && flag_delete_null_pointer_checks)
>>> +    temp.var = nothing_id;
>>> +  else
>>> +    temp.var = nonlocal_id;
>>> +  temp.type = ADDRESSOF;
>>> +  temp.offset = 0;
>>> +  rhsc.safe_push (temp);
>>> +
>>> +  process_all_all_constraints (lhsc, rhsc);
>>> +  return;
>>> +}
>>> +
>> 
>> What's the reasoning behind doing it like this?  AFAICT the result
>> of the call doesn't validly alias anything, regardless of the init type.
>> Even if there happens to be a valid decl at the address given by the
>> chosen fill pattern, there's no expectation that accesses to that
>> decl will be coherent wrt accesses via the result of the call.
>
> So, you mean the above change will not have any impact at all?

Stepping back a bit first: why did you add the code?  What case
it is trying to handle?  Perhaps I misunderstood the motivation.

In the above reply I meant more that the code seems unnecessarily
pessimistic.  It looks like it's based on:

  /* x = integer is all glommed to a single variable, which doesn't
     point to anything by itself.  That is, of course, unless it is an
     integer constant being treated as a pointer, in which case, we
     will return that this is really the addressof anything.  This
     happens below, since it will fall into the default case. The only
     case we know something about an integer treated like a pointer is
     when it is the NULL pointer, and then we just say it points to
     NULL.

     Do not do that if -fno-delete-null-pointer-checks though, because
     in that case *NULL does not fail, so it _should_ alias *anything.
     It is not worth adding a new option or renaming the existing one,
     since this case is relatively obscure.  */
  if ((TREE_CODE (t) == INTEGER_CST
       && integer_zerop (t))
      /* The only valid CONSTRUCTORs in gimple with pointer typed
	 elements are zero-initializer.  But in IPA mode we also
	 process global initializers, so verify at least.  */
      || (TREE_CODE (t) == CONSTRUCTOR
	  && CONSTRUCTOR_NELTS (t) == 0))
    {
      if (flag_delete_null_pointer_checks)
	temp.var = nothing_id;
      else
	temp.var = nonlocal_id;
      temp.type = ADDRESSOF;
      temp.offset = 0;
      results->safe_push (temp);
      return;
    }

But if the user writes:

   intptr_t x = 0;
   *(int *)x = 42;

and compiles with -fno-delete-null-pointer-checks, then we have to
assume that the code is valid and is accessing a global decl that the
user knows is at address 0.  So in that case we need the &nonlocal_id
constraint.

But even with the new option, I don't think:

   intptr_t x;
   *(int *)x = 42;

is well-defined in the same way.  Maybe there's an argument that using
-fno-delete-null-pointer-checks is such a niche case that we might as
well treat it as though it were well-defined.  That'd feel to me like
a half-measure though.  It comes back to Richard Smith's argument
that we shouldn't try to create a new dialect of C/C++.  We're
explicitly not trying to make:

   intptr_t x;

and

   intptr_t x = 0;

equivalent in all respects.  And if we were trying to make them
equivalent, we'd need to do much more than this.

The same applies to the pattern case.  If “x” is initialised to a pattern
that happens to point to a real decl, we don't have to preserve the
order of accesses to the decl wrt accesses to “*x” (especially since
we're hoping that “*x” will trap).

I think for aliasing purposes, the .DEFERRED_INIT return value is still
analogous to an undefined SSA name, even though we will later generate
code to initialise it.

>> In fact it might be simpler to have something like:
>> 
>>  if (POINTER_TYPE_P (type) && TYPE_PRECISION (type) < 64)
>>    return build_int_cstu (type, 0xAA);
>> 
>>  if (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
>>    ...the wi::from_buffer thing above...;
>
> Okay.
>> 
>> I'm not sure if this makes sense for NULLPTR_TYPE.
>
> Is there a good testing case in gcc test suite about NULLPTR_TYPE that I can take a look?

I'm guessing you'll need to construct a new one to exercise this code path.

>>> +    case RECORD_TYPE:
>>> +      {
>>> +	tree field;
>>> +	tree field_value;
>>> +	vec<constructor_elt, va_gc> *v = NULL;
>>> +	for (field= TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
>>> +	  {
>>> +	    if (TREE_CODE (field) != FIELD_DECL)
>>> +	      continue;
>>> +	    /* if the field is a variable length array, it should be the last
>>> +	       field of the record, and no need to initialize.  */
>> 
>> Why doesn't it need to be initialized though?
>
> My understanding is, the compiler will not allocate memory for the latest field of the record if its a VLA, it’s the user’s responsibility to allocate 
> Memory for it.  Therefore, compiler doesn’t  need to initialize it.

Ah, OK.  This sounds like the behaviour for flexible array members rather
than VLA members.  E.g. GCC allows:

  void bar (int *);
  int
  foo (int a)
  {
    // VLA in struct
    struct { int x[a]; } foo;
    bar (foo.x);
  }

In this case the foo.x really does have “a” elements that would
need to be initialised.

I think the case you're talking about is:

  void bar (int *);
  int
  foo (int a)
  {
    // struct ending in a flexible array
    struct { int prefix; int x[]; } foo;
    bar (foo.x);
  }

where foo.x has zero elements.

>>> @@ -11950,6 +12088,72 @@ lower_bound_in_type (tree outer, tree inner)
>>>     }
>>> }
>>> 
>>> +/* Returns true when the given TYPE has padding inside it.
>>> +   return false otherwise.  */
>>> +bool
>>> +type_has_padding (tree type)
>> 
>> Would it be possible to reuse __builtin_clear_padding here?
>
> Not sure, where can I get more details on __builtin_clear_padding? I can study a little bit more on this to make sure this.

It's documented in doc/extend.texi.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [patch for gcc12 stage1][version 2] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-04-26 17:47     ` Richard Sandiford
@ 2021-04-26 20:02       ` Qing Zhao
  2021-04-27  6:30       ` Richard Biener
  1 sibling, 0 replies; 13+ messages in thread
From: Qing Zhao @ 2021-04-26 20:02 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: Richard Biener, Kees Cook, Gcc-patches Qing Zhao via



> On Apr 26, 2021, at 12:47 PM, Richard Sandiford <richard.sandiford@arm.com> wrote:
> 
> Qing Zhao <qing.zhao@oracle.com> writes:
>>>> @@ -1831,6 +2000,17 @@ 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.  */
>>> 
>>> I think we should explain why we can skip VLAs here.
>> 
>> VLA is handled in another place already, it should be initialized with calls to memset/memcpy.
> 
> Yeah, what I meant here was that the comment should explain the
> difference between the handling of VLAs and non-VLAs.  It's fairly
> obvious when reading the patch, but it won't be as obvious once the
> patch is applied.

Okay, I see, will update the comments.
> 
>>>> +   children are to be processed.  TOP_OFFSET is the offset  of the processed
>>>> +   subtree which has to be subtracted from offsets of individual accesses to
>>>> +   get corresponding offsets for AGG.  GSI is a statement iterator used to place
>>>> +   the new statements.  */
>>>> +static void
>>>> +generate_subtree_deferred_init (struct access *access, tree agg,
>>>> +				enum auto_init_type init_type,
>>>> +				HOST_WIDE_INT top_offset,
>>>> +				gimple_stmt_iterator *gsi,
>>>> +				location_t loc)
>>>> +{
>>>> +  do
>>>> +    {
>>>> +      if (access->grp_to_be_replaced)
>>>> +	{
>>>> +	  tree repl = get_access_replacement (access);
>>>> +	  tree init_type_node
>>>> +	    = build_int_cst (integer_type_node, (int) init_type);
>>>> +	  gimple *call = gimple_build_call_internal (IFN_DEFERRED_INIT, 2,
>>>> +						     repl, init_type_node);
>>>> +	  gimple_call_set_lhs (call, repl);
>>> 
>>> AFAICT “access” is specifically for the lhs of the original call.
>>> So there seems to be an implicit assumption here that the lhs of the
>>> original call is the same as the first argument of the original call.
>>> Is that guaranteed/required?
>> 
>> For call to DEFFERED_INIT, yes, this is guaranteed.
> 
> OK, in that case…
> 
>>> If so, I think it's something that
>>> tree-cfg.c should check.  It might also be worth having an assertion
>>> in sra_modify_deferred_init.
>> I can definitely add an assertion to make sure this.
> 
> …I think we need the tree-cfg.c check too.  Having the check there
> ensures that the invariant is maintained throughout gimple.

Okay, will add check in tree-cfg.c too.

> 
>>>> +	  gimple_set_location (call, loc);
>>>> +
>>>> +	  sra_stats.subtree_deferred_init++;
>>>> +	}
>>>> +      else if (access->grp_to_be_debug_replaced)
>>>> +	{
>>>> +	  /* FIXME, this part might have some issue.  */
>>>> +	  tree drhs = build_debug_ref_for_model (loc, agg,
>>>> +						 access->offset - top_offset,
>>>> +						 access);
>>>> +	  gdebug *ds = gimple_build_debug_bind (get_access_replacement (access),
>>>> +						drhs, gsi_stmt (*gsi));
>>>> +	  gsi_insert_before (gsi, ds, GSI_SAME_STMT);
>>> 
>>> Would be good to fix the FIXME :-)
>> 
>> This is the part I am not very sure, so I added the FIXME in order to get more review and suggestion
>> to make sure it. -:)
>>> 
>>> I guess the thing we need to decide here is whether -ftrivial-auto-var-init
>>> should affect debug-only constructs too.
>> 
>> Where can I get more details on Debug-only constructs ?
> 
> What I meant by “debug-only construct” is a piece of source-level data
> (in this case a field of an aggregate) that has been optimised out of
> the executable code but still exists in debug stmts.

Okay, I see now.

Then, we should handle this case too, I think.

>  AIUI that's what
> the code above is handling.
> 
>>>> @@ -4863,6 +4863,29 @@ find_func_aliases_for_builtin_call (struct function *fn, gcall *t)
>>>>  return false;
>>>> }
>>>> 
>>>> +static void
>>>> +find_func_aliases_for_deferred_init (gcall *t)
>>>> +{
>>>> +  tree lhsop = gimple_call_lhs (t);
>>>> +  enum auto_init_type init_type
>>>> +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (t, 1));
>>>> +  auto_vec<ce_s, 2> lhsc;
>>>> +  auto_vec<ce_s, 4> rhsc;
>>>> +  struct constraint_expr temp;
>>>> +
>>>> +  get_constraint_for (lhsop, &lhsc);
>>>> +  if (init_type == AUTO_INIT_ZERO && flag_delete_null_pointer_checks)
>>>> +    temp.var = nothing_id;
>>>> +  else
>>>> +    temp.var = nonlocal_id;
>>>> +  temp.type = ADDRESSOF;
>>>> +  temp.offset = 0;
>>>> +  rhsc.safe_push (temp);
>>>> +
>>>> +  process_all_all_constraints (lhsc, rhsc);
>>>> +  return;
>>>> +}
>>>> +
>>> 
>>> What's the reasoning behind doing it like this?  AFAICT the result
>>> of the call doesn't validly alias anything, regardless of the init type.
>>> Even if there happens to be a valid decl at the address given by the
>>> chosen fill pattern, there's no expectation that accesses to that
>>> decl will be coherent wrt accesses via the result of the call.
>> 
>> So, you mean the above change will not have any impact at all?
> 
> Stepping back a bit first: why did you add the code?  What case
> it is trying to handle?  Perhaps I misunderstood the motivation.
> 
> In the above reply I meant more that the code seems unnecessarily
> pessimistic.  It looks like it's based on:
> 
>  /* x = integer is all glommed to a single variable, which doesn't
>     point to anything by itself.  That is, of course, unless it is an
>     integer constant being treated as a pointer, in which case, we
>     will return that this is really the addressof anything.  This
>     happens below, since it will fall into the default case. The only
>     case we know something about an integer treated like a pointer is
>     when it is the NULL pointer, and then we just say it points to
>     NULL.
> 
>     Do not do that if -fno-delete-null-pointer-checks though, because
>     in that case *NULL does not fail, so it _should_ alias *anything.
>     It is not worth adding a new option or renaming the existing one,
>     since this case is relatively obscure.  */
>  if ((TREE_CODE (t) == INTEGER_CST
>       && integer_zerop (t))
>      /* The only valid CONSTRUCTORs in gimple with pointer typed
> 	 elements are zero-initializer.  But in IPA mode we also
> 	 process global initializers, so verify at least.  */
>      || (TREE_CODE (t) == CONSTRUCTOR
> 	  && CONSTRUCTOR_NELTS (t) == 0))
>    {
>      if (flag_delete_null_pointer_checks)
> 	temp.var = nothing_id;
>      else
> 	temp.var = nonlocal_id;
>      temp.type = ADDRESSOF;
>      temp.offset = 0;
>      results->safe_push (temp);
>      return;
>    }
> 
> But if the user writes:
> 
>   intptr_t x = 0;
>   *(int *)x = 42;
> 
> and compiles with -fno-delete-null-pointer-checks, then we have to
> assume that the code is valid and is accessing a global decl that the
> user knows is at address 0.  So in that case we need the &nonlocal_id
> constraint.
> 
> But even with the new option, I don't think:
> 
>   intptr_t x;
>   *(int *)x = 42;
> 
> is well-defined in the same way.  Maybe there's an argument that using
> -fno-delete-null-pointer-checks is such a niche case that we might as
> well treat it as though it were well-defined.  That'd feel to me like
> a half-measure though.  It comes back to Richard Smith's argument
> that we shouldn't try to create a new dialect of C/C++.  We're
> explicitly not trying to make:
> 
>   intptr_t x;
> 
> and
> 
>   intptr_t x = 0;
> 
> equivalent in all respects.  And if we were trying to make them
> equivalent, we'd need to do much more than this.
> 
> The same applies to the pattern case.  If “x” is initialised to a pattern
> that happens to point to a real decl, we don't have to preserve the
> order of accesses to the decl wrt accesses to “*x” (especially since
> we're hoping that “*x” will trap).
> 
> I think for aliasing purposes, the .DEFERRED_INIT return value is still
> analogous to an undefined SSA name, even though we will later generate
> code to initialise it.

Okay, I see now.

Will delete this part from the code.

> 
>>> In fact it might be simpler to have something like:
>>> 
>>> if (POINTER_TYPE_P (type) && TYPE_PRECISION (type) < 64)
>>>   return build_int_cstu (type, 0xAA);
>>> 
>>> if (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
>>>   ...the wi::from_buffer thing above...;
>> 
>> Okay.
>>> 
>>> I'm not sure if this makes sense for NULLPTR_TYPE.
>> 
>> Is there a good testing case in gcc test suite about NULLPTR_TYPE that I can take a look?
> 
> I'm guessing you'll need to construct a new one to exercise this code path.

Will do this.

> 
>>>> +    case RECORD_TYPE:
>>>> +      {
>>>> +	tree field;
>>>> +	tree field_value;
>>>> +	vec<constructor_elt, va_gc> *v = NULL;
>>>> +	for (field= TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
>>>> +	  {
>>>> +	    if (TREE_CODE (field) != FIELD_DECL)
>>>> +	      continue;
>>>> +	    /* if the field is a variable length array, it should be the last
>>>> +	       field of the record, and no need to initialize.  */
>>> 
>>> Why doesn't it need to be initialized though?
>> 
>> My understanding is, the compiler will not allocate memory for the latest field of the record if its a VLA, it’s the user’s responsibility to allocate 
>> Memory for it.  Therefore, compiler doesn’t  need to initialize it.
> 
> Ah, OK.  This sounds like the behaviour for flexible array members rather
> than VLA members.

Oh, Yes. My bad to use a wrong concept to confuse you.


>  E.g. GCC allows:
> 
>  void bar (int *);
>  int
>  foo (int a)
>  {
>    // VLA in struct
>    struct { int x[a]; } foo;
>    bar (foo.x);
>  }
> 
> In this case the foo.x really does have “a” elements that would
> need to be initialised.
> 
> I think the case you're talking about is:
> 
>  void bar (int *);
>  int
>  foo (int a)
>  {
>    // struct ending in a flexible array
>    struct { int prefix; int x[]; } foo;
>    bar (foo.x);
>  }
> 
> where foo.x has zero elements.

Yes. 

Then, that part of the code currently is okay?

> 
>>>> @@ -11950,6 +12088,72 @@ lower_bound_in_type (tree outer, tree inner)
>>>>    }
>>>> }
>>>> 
>>>> +/* Returns true when the given TYPE has padding inside it.
>>>> +   return false otherwise.  */
>>>> +bool
>>>> +type_has_padding (tree type)
>>> 
>>> Would it be possible to reuse __builtin_clear_padding here?
>> 
>> Not sure, where can I get more details on __builtin_clear_padding? I can study a little bit more on this to make sure this.
> 
> It's documented in doc/extend.texi.

Okay, will check on that.

Thanks a lot.

Qing
> 
> Thanks,
> Richard


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [patch for gcc12 stage1][version 2] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-04-26 17:47     ` Richard Sandiford
  2021-04-26 20:02       ` Qing Zhao
@ 2021-04-27  6:30       ` Richard Biener
  2021-04-27 15:10         ` Qing Zhao
  1 sibling, 1 reply; 13+ messages in thread
From: Richard Biener @ 2021-04-27  6:30 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: Qing Zhao, Kees Cook, Gcc-patches Qing Zhao via

On Mon, 26 Apr 2021, Richard Sandiford wrote:

> Qing Zhao <qing.zhao@oracle.com> writes:
> >>> @@ -1831,6 +2000,17 @@ 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.  */
> >> 
> >> I think we should explain why we can skip VLAs here.
> >
> > VLA is handled in another place already, it should be initialized with calls to memset/memcpy.
> 
> Yeah, what I meant here was that the comment should explain the
> difference between the handling of VLAs and non-VLAs.  It's fairly
> obvious when reading the patch, but it won't be as obvious once the
> patch is applied.
> 
> >>> +   children are to be processed.  TOP_OFFSET is the offset  of the processed
> >>> +   subtree which has to be subtracted from offsets of individual accesses to
> >>> +   get corresponding offsets for AGG.  GSI is a statement iterator used to place
> >>> +   the new statements.  */
> >>> +static void
> >>> +generate_subtree_deferred_init (struct access *access, tree agg,
> >>> +				enum auto_init_type init_type,
> >>> +				HOST_WIDE_INT top_offset,
> >>> +				gimple_stmt_iterator *gsi,
> >>> +				location_t loc)
> >>> +{
> >>> +  do
> >>> +    {
> >>> +      if (access->grp_to_be_replaced)
> >>> +	{
> >>> +	  tree repl = get_access_replacement (access);
> >>> +	  tree init_type_node
> >>> +	    = build_int_cst (integer_type_node, (int) init_type);
> >>> +	  gimple *call = gimple_build_call_internal (IFN_DEFERRED_INIT, 2,
> >>> +						     repl, init_type_node);
> >>> +	  gimple_call_set_lhs (call, repl);
> >> 
> >> AFAICT “access” is specifically for the lhs of the original call.
> >> So there seems to be an implicit assumption here that the lhs of the
> >> original call is the same as the first argument of the original call.
> >> Is that guaranteed/required?
> >
> > For call to DEFFERED_INIT, yes, this is guaranteed.
> 
> OK, in that case…
> 
> >>  If so, I think it's something that
> >> tree-cfg.c should check.  It might also be worth having an assertion
> >> in sra_modify_deferred_init.
> > I can definitely add an assertion to make sure this.
> 
> …I think we need the tree-cfg.c check too.  Having the check there
> ensures that the invariant is maintained throughout gimple.
> 
> >>> +	  gimple_set_location (call, loc);
> >>> +
> >>> +	  sra_stats.subtree_deferred_init++;
> >>> +	}
> >>> +      else if (access->grp_to_be_debug_replaced)
> >>> +	{
> >>> +	  /* FIXME, this part might have some issue.  */
> >>> +	  tree drhs = build_debug_ref_for_model (loc, agg,
> >>> +						 access->offset - top_offset,
> >>> +						 access);
> >>> +	  gdebug *ds = gimple_build_debug_bind (get_access_replacement (access),
> >>> +						drhs, gsi_stmt (*gsi));
> >>> +	  gsi_insert_before (gsi, ds, GSI_SAME_STMT);
> >> 
> >> Would be good to fix the FIXME :-)
> >
> > This is the part I am not very sure, so I added the FIXME in order to get more review and suggestion
> >  to make sure it. -:)
> >> 
> >> I guess the thing we need to decide here is whether -ftrivial-auto-var-init
> >> should affect debug-only constructs too.
> >
> > Where can I get more details on Debug-only constructs ?
> 
> What I meant by “debug-only construct” is a piece of source-level data
> (in this case a field of an aggregate) that has been optimised out of
> the executable code but still exists in debug stmts.  AIUI that's what
> the code above is handling.
> 
> >>> @@ -4863,6 +4863,29 @@ find_func_aliases_for_builtin_call (struct function *fn, gcall *t)
> >>>   return false;
> >>> }
> >>> 
> >>> +static void
> >>> +find_func_aliases_for_deferred_init (gcall *t)
> >>> +{
> >>> +  tree lhsop = gimple_call_lhs (t);
> >>> +  enum auto_init_type init_type
> >>> +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (t, 1));
> >>> +  auto_vec<ce_s, 2> lhsc;
> >>> +  auto_vec<ce_s, 4> rhsc;
> >>> +  struct constraint_expr temp;
> >>> +
> >>> +  get_constraint_for (lhsop, &lhsc);
> >>> +  if (init_type == AUTO_INIT_ZERO && flag_delete_null_pointer_checks)
> >>> +    temp.var = nothing_id;
> >>> +  else
> >>> +    temp.var = nonlocal_id;
> >>> +  temp.type = ADDRESSOF;
> >>> +  temp.offset = 0;
> >>> +  rhsc.safe_push (temp);
> >>> +
> >>> +  process_all_all_constraints (lhsc, rhsc);
> >>> +  return;
> >>> +}
> >>> +
> >> 
> >> What's the reasoning behind doing it like this?  AFAICT the result
> >> of the call doesn't validly alias anything, regardless of the init type.
> >> Even if there happens to be a valid decl at the address given by the
> >> chosen fill pattern, there's no expectation that accesses to that
> >> decl will be coherent wrt accesses via the result of the call.
> >
> > So, you mean the above change will not have any impact at all?
> 
> Stepping back a bit first: why did you add the code?  What case
> it is trying to handle?  Perhaps I misunderstood the motivation.
> 
> In the above reply I meant more that the code seems unnecessarily
> pessimistic.  It looks like it's based on:
> 
>   /* x = integer is all glommed to a single variable, which doesn't
>      point to anything by itself.  That is, of course, unless it is an
>      integer constant being treated as a pointer, in which case, we
>      will return that this is really the addressof anything.  This
>      happens below, since it will fall into the default case. The only
>      case we know something about an integer treated like a pointer is
>      when it is the NULL pointer, and then we just say it points to
>      NULL.
> 
>      Do not do that if -fno-delete-null-pointer-checks though, because
>      in that case *NULL does not fail, so it _should_ alias *anything.
>      It is not worth adding a new option or renaming the existing one,
>      since this case is relatively obscure.  */
>   if ((TREE_CODE (t) == INTEGER_CST
>        && integer_zerop (t))
>       /* The only valid CONSTRUCTORs in gimple with pointer typed
> 	 elements are zero-initializer.  But in IPA mode we also
> 	 process global initializers, so verify at least.  */
>       || (TREE_CODE (t) == CONSTRUCTOR
> 	  && CONSTRUCTOR_NELTS (t) == 0))
>     {
>       if (flag_delete_null_pointer_checks)
> 	temp.var = nothing_id;
>       else
> 	temp.var = nonlocal_id;
>       temp.type = ADDRESSOF;
>       temp.offset = 0;
>       results->safe_push (temp);
>       return;
>     }
> 
> But if the user writes:
> 
>    intptr_t x = 0;
>    *(int *)x = 42;
> 
> and compiles with -fno-delete-null-pointer-checks, then we have to
> assume that the code is valid and is accessing a global decl that the
> user knows is at address 0.  So in that case we need the &nonlocal_id
> constraint.
> 
> But even with the new option, I don't think:
> 
>    intptr_t x;
>    *(int *)x = 42;
> 
> is well-defined in the same way.  Maybe there's an argument that using
> -fno-delete-null-pointer-checks is such a niche case that we might as
> well treat it as though it were well-defined.  That'd feel to me like
> a half-measure though.  It comes back to Richard Smith's argument
> that we shouldn't try to create a new dialect of C/C++.  We're
> explicitly not trying to make:
> 
>    intptr_t x;
> 
> and
> 
>    intptr_t x = 0;
> 
> equivalent in all respects.  And if we were trying to make them
> equivalent, we'd need to do much more than this.
> 
> The same applies to the pattern case.  If “x” is initialised to a pattern
> that happens to point to a real decl, we don't have to preserve the
> order of accesses to the decl wrt accesses to “*x” (especially since
> we're hoping that “*x” will trap).
> 
> I think for aliasing purposes, the .DEFERRED_INIT return value is still
> analogous to an undefined SSA name, even though we will later generate
> code to initialise it.

(only replying to this part, I'll look at the next revised patch series)

Since .DEFERRED_INIT does not produce any pointers and is not a real
initialization you don't need to do anything in PTA - but you might
want to ignore it to not pessimize it by the default handling.  Thus

+  if (gimple_call_internal_p (t, IFN_DEFERRED_INIT))
+    {
+      find_func_aliases_for_deferred_init (t);
+      return;
+    }

should simply return and find_func_aliases_for_deferred_init can be 
removed.


> >> In fact it might be simpler to have something like:
> >> 
> >>  if (POINTER_TYPE_P (type) && TYPE_PRECISION (type) < 64)
> >>    return build_int_cstu (type, 0xAA);
> >> 
> >>  if (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
> >>    ...the wi::from_buffer thing above...;
> >
> > Okay.
> >> 
> >> I'm not sure if this makes sense for NULLPTR_TYPE.
> >
> > Is there a good testing case in gcc test suite about NULLPTR_TYPE that I can take a look?
> 
> I'm guessing you'll need to construct a new one to exercise this code path.
> 
> >>> +    case RECORD_TYPE:
> >>> +      {
> >>> +	tree field;
> >>> +	tree field_value;
> >>> +	vec<constructor_elt, va_gc> *v = NULL;
> >>> +	for (field= TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
> >>> +	  {
> >>> +	    if (TREE_CODE (field) != FIELD_DECL)
> >>> +	      continue;
> >>> +	    /* if the field is a variable length array, it should be the last
> >>> +	       field of the record, and no need to initialize.  */
> >> 
> >> Why doesn't it need to be initialized though?
> >
> > My understanding is, the compiler will not allocate memory for the latest field of the record if its a VLA, it’s the user’s responsibility to allocate 
> > Memory for it.  Therefore, compiler doesn’t  need to initialize it.
> 
> Ah, OK.  This sounds like the behaviour for flexible array members rather
> than VLA members.  E.g. GCC allows:
> 
>   void bar (int *);
>   int
>   foo (int a)
>   {
>     // VLA in struct
>     struct { int x[a]; } foo;
>     bar (foo.x);
>   }
> 
> In this case the foo.x really does have “a” elements that would
> need to be initialised.
> 
> I think the case you're talking about is:
> 
>   void bar (int *);
>   int
>   foo (int a)
>   {
>     // struct ending in a flexible array
>     struct { int prefix; int x[]; } foo;
>     bar (foo.x);
>   }
> 
> where foo.x has zero elements.
> 
> >>> @@ -11950,6 +12088,72 @@ lower_bound_in_type (tree outer, tree inner)
> >>>     }
> >>> }
> >>> 
> >>> +/* Returns true when the given TYPE has padding inside it.
> >>> +   return false otherwise.  */
> >>> +bool
> >>> +type_has_padding (tree type)
> >> 
> >> Would it be possible to reuse __builtin_clear_padding here?
> >
> > Not sure, where can I get more details on __builtin_clear_padding? I can study a little bit more on this to make sure this.
> 
> It's documented in doc/extend.texi.
> 
> Thanks,
> Richard
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [patch for gcc12 stage1][version 2] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-04-27  6:30       ` Richard Biener
@ 2021-04-27 15:10         ` Qing Zhao
  0 siblings, 0 replies; 13+ messages in thread
From: Qing Zhao @ 2021-04-27 15:10 UTC (permalink / raw)
  To: Richard Biener; +Cc: Richard Sandiford, Kees Cook, Gcc-patches Qing Zhao via



> On Apr 27, 2021, at 1:30 AM, Richard Biener <rguenther@suse.de> wrote:
> 
>> 
>> equivalent in all respects.  And if we were trying to make them
>> equivalent, we'd need to do much more than this.
>> 
>> The same applies to the pattern case.  If “x” is initialised to a pattern
>> that happens to point to a real decl, we don't have to preserve the
>> order of accesses to the decl wrt accesses to “*x” (especially since
>> we're hoping that “*x” will trap).
>> 
>> I think for aliasing purposes, the .DEFERRED_INIT return value is still
>> analogous to an undefined SSA name, even though we will later generate
>> code to initialise it.
> 
> (only replying to this part, I'll look at the next revised patch series)

Okay, thanks.

> 
> Since .DEFERRED_INIT does not produce any pointers and is not a real
> initialization you don't need to do anything in PTA - but you might
> want to ignore it to not pessimize it by the default handling.  Thus
> 
> +  if (gimple_call_internal_p (t, IFN_DEFERRED_INIT))
> +    {
> +      find_func_aliases_for_deferred_init (t);
> +      return;
> +    }
> 
> should simply return and find_func_aliases_for_deferred_init can be 
> removed.

Okay. Will do that.

thanks.

Qing


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [patch for gcc12 stage1][version 2] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-04-23 19:05 ` Richard Sandiford
  2021-04-23 19:33   ` Kees Cook
  2021-04-26 15:09   ` Qing Zhao
@ 2021-05-05 14:41   ` Qing Zhao
  2 siblings, 0 replies; 13+ messages in thread
From: Qing Zhao @ 2021-05-05 14:41 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: Richard Biener, Kees Cook, Gcc-patches Qing Zhao via

Hi, Richard, 

During the change for the 2nd version based on your previous comments, I have the following questions need your help:

> 
>> +	  sra_stats.subtree_deferred_init++;
>> +	}
>> +      else if (access->grp_to_be_debug_replaced)
>> +	{
>> +	  /* FIXME, this part might have some issue.  */
>> +	  tree drhs = build_debug_ref_for_model (loc, agg,
>> +						 access->offset - top_offset,
>> +						 access);
>> +	  gdebug *ds = gimple_build_debug_bind (get_access_replacement (access),
>> +						drhs, gsi_stmt (*gsi));
>> +	  gsi_insert_before (gsi, ds, GSI_SAME_STMT);
> 
> Would be good to fix the FIXME :-)
> 
> I guess the thing we need to decide here is whether -ftrivial-auto-var-init
> should affect debug-only constructs too.  If it doesn't, exmaining removed
> components in a debugger might show uninitialised values in cases where
> the user was expecting initialised ones.  There would be no security
> concern, but it might be surprising.
> 
> I think in principle the DRHS can contain a call to DEFERRED_INIT.
> Doing that would probably require further handling elsewhere though.

Right now, what I did is:

  else if (lhs_access->grp_to_be_debug_replaced)
    {
      tree lhs_drepl = get_access_replacement (lhs_access);
      tree init_type_node
           = build_int_cst (integer_type_node, (int) init_type);
      tree call = build_call_expr_internal_loc
                  (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
                  TREE_TYPE (lhs_drepl), 2, lhs_drepl, init_type_node);
      gdebug *ds = gimple_build_debug_bind (lhs_drepl, call,
                                            gsi_stmt (*gsi));
      gsi_insert_before (gsi, ds, GSI_SAME_STMT);
    }

Is the above matching what you suggested?

What do you mean by “further handling elsewhere”?

> 
>> +	 is better even for pattern initialization.  */
>> +      return build_int_cstu (type, largevalue);
> 
> I've no objection to that choice for booleans, but: booleans in some
> languages (like Ada) can have multibit precision.  If we want booleans
> to be zero then it would probably be better to treat them as a separate
> case and just use build_zero_cst (type) for them.
> 
> Also, the above won't work correctly for 128-bit integers: it will
> zero-initialize the upper half.  It would probably be better to use
> wi::from_buffer to construct the integer instead.

You mean using wi::from_buffer to construct all the integer type (including 64-bit, 32-bit, etc.)?

I read the corresponding source codes related to “wi::from_buffer”, but still not very clear
On how to use it for my purpose,

From my current understanding, I should use it like the following:

"

unsigned char *ptr = “0xAAAAAAAAAAAAAAAA”;

Int total_bytes = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type));
wide_int result = wi::from_buffer (ptr, total_bytes);
return wide_int_to_tree (type, result);

“

Is the above correct for INTEGER type?

thanks.

Qing

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [patch for gcc12 stage1][version 2] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-04-26 15:09   ` Qing Zhao
  2021-04-26 17:47     ` Richard Sandiford
@ 2021-05-05 17:29     ` Qing Zhao
  1 sibling, 0 replies; 13+ messages in thread
From: Qing Zhao @ 2021-05-05 17:29 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: Richard Biener, Gcc-patches Qing Zhao via, Kees Cook

> 
>> 
>>> @@ -11950,6 +12088,72 @@ lower_bound_in_type (tree outer, tree inner)
>>>    }
>>> }
>>> 
>>> +/* Returns true when the given TYPE has padding inside it.
>>> +   return false otherwise.  */
>>> +bool
>>> +type_has_padding (tree type)
>> 
>> Would it be possible to reuse __builtin_clear_padding here?
> 
> Not sure, where can I get more details on __builtin_clear_padding? I can study a little bit more on this to make sure this.

After some study, my understanding is, the call to __builtin_clear_padding is expanded during gimplification phase.  
And there is no __bultin_clear_padding expanding during rtx expanding phase.

Is the above understanding correct? 

If so,  for -ftrivial-auto-var-init, padding initialization should be done both in gimplification phase and rtx expanding phase. 
And since the __builtin_clear_padding might not be good for rtx expanding, reusing __builtin_clear_padding might not work.

Let me know if I misunderstand something.

Qing

>> 


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2021-05-05 17:29 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-24 21:21 [patch for gcc12 stage1][version 2] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc Qing Zhao
2021-04-07 14:44 ` Qing Zhao
2021-04-07 22:19 ` Kees Cook
2021-04-08 15:22   ` Qing Zhao
2021-04-23 19:05 ` Richard Sandiford
2021-04-23 19:33   ` Kees Cook
2021-04-26 15:09   ` Qing Zhao
2021-04-26 17:47     ` Richard Sandiford
2021-04-26 20:02       ` Qing Zhao
2021-04-27  6:30       ` Richard Biener
2021-04-27 15:10         ` Qing Zhao
2021-05-05 17:29     ` Qing Zhao
2021-05-05 14:41   ` Qing Zhao

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).