public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
@ 2021-07-27  3:26 Qing Zhao
  2021-07-28 20:21 ` Kees Cook
  2021-08-09 14:09 ` Richard Biener
  0 siblings, 2 replies; 60+ messages in thread
From: Qing Zhao @ 2021-07-27  3:26 UTC (permalink / raw)
  To: Richard Biener, Martin Jambor, Jakub Jelinek
  Cc: Kees Cook, Nick Alcock via Gcc-patches, Richard Biener

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

Hi,

This is the 6th version of the patch for the new security feature for GCC.

I have tested it with bootstrap on both x86 and aarch64, regression testing on both x86 and aarch64.
Also compile CPU2017 (running is ongoing), without any issue. (With the fix to bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101586).

Please take a look and let me know any issue.

Thanks

Qing

******Compared with the 5th version, the changes are:

 1. Fix two issues raised by Martin Jambor in tree-sra.c:

   A. Inside "scan_function", Do not set cannot_scalarize_away_bitmap for a call to DEFERRED_INIT.
   B. Fix a potential issue for single-field structure.

 2. Add two testing cases based on gcc/testsuite/gcc.dg/tree-ssa/sra-12.c to verity SRA total scalarization will not be confused by auto initializatoin.

******the 5th version compared with the 4th version, the following are the major changes:

1. delete the code for handling "grp_to_be_debug_replaced" since they are not needed per Martin Jambor's suggestion.
2. for Pattern init, call __builtin_clear_padding after the call to .DEFERRED_INIT to initialize the paddings to zeroes;
3. for partially or fully initialized auto variables, call   __builtin_clear_padding before the real initialization to initialize
   the paddings to zeroes.
4. Update the documentation with padding initialization to zeroes.
5. in order to reuse __builtin_clear_padding for auto init purpose, add one more dummy argument to indiciate whether it's for auto init or not,
  if for auto init, do not emit error messages to avoid confusing users.
6. Add new testing cases to verify padding initializations.
7. rename some of the old testing cases to make the file name reflecting the testing purpose per Kees Cook's suggestions.

******Please see version 5 at:
https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575977.html

******ChangeLog is:

gcc/ChangeLog:

2021-07-26  qing zhao  <qing.zhao@oracle.com>

        * builtins.c (expand_builtin_memset): Make external visible.
        * builtins.h (expand_builtin_memset): Declare extern.
        * common.opt (ftrivial-auto-var-init=): New option.
        * doc/extend.texi: Document the uninitialized attribute.
        * doc/invoke.texi: Document -ftrivial-auto-var-init.
        * flag-types.h (enum auto_init_type): New enumerated type
        auto_init_type.
        * gimple-fold.c (clear_padding_type): Add one new parameter.
        (clear_padding_union): Likewise.
        (clear_padding_emit_loop): Likewise.
        (clear_type_padding_in_mask): Likewise.
        (gimple_fold_builtin_clear_padding): Handle this new parameter.
        * gimplify.c (gimple_add_init_for_auto_var): New function.
        (maybe_with_size_expr): Forword declaration.
        (build_deferred_init): New function.
        (gimple_add_padding_init_for_auto_var): New function.
        (gimplify_decl_expr): Add initialization to automatic variables per
        users' requests.
        (gimplify_call_expr): Add one new parameter for call to
        __builtin_clear_padding.
        (gimplify_modify_expr_rhs): Add padding initialization before
        gimplify_init_constructor.
        * internal-fn.c (INIT_PATTERN_VALUE): New macro.
        (expand_DEFERRED_INIT): New function.
        * internal-fn.def (DEFERRED_INIT): New internal function.
        * tree-cfg.c (verify_gimple_call): Verify calls to .DEFERRED_INIT.
        * tree-sra.c (generate_subtree_deferred_init): New function.
        (scan_function): Avoid setting cannot_scalarize_away_bitmap for
        calls to .DEFERRED_INIT.
        (sra_modify_deferred_init): New function.
        (sra_modify_function_body): Handle calls to DEFERRED_INIT specially.
        * tree-ssa-structalias.c (find_func_aliases_for_call): Likewise.
        * tree-ssa-uninit.c (warn_uninit): Handle calls to DEFERRED_INIT
        specially.
        (check_defs): Likewise.
        (warn_uninitialized_vars): Likewise.
        * tree-ssa.c (ssa_undefined_value_p): Likewise.

gcc/c-family/ChangeLog:

2021-07-26  qing zhao  <qing.zhao@oracle.com>

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

gcc/testsuite/ChangeLog:


2021-07-26  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-15.c: New test.
        * c-c++-common/auto-init-16.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.
        * c-c++-common/auto-init-padding-1.c: New test.
        * c-c++-common/auto-init-padding-2.c: New test.
        * c-c++-common/auto-init-padding-3.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-sra-1.c: New test.
        * gcc.dg/auto-init-sra-2.c: 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-2.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-padding-1.c: New test.
        * gcc.target/aarch64/auto-init-padding-10.c: New test.
        * gcc.target/aarch64/auto-init-padding-11.c: New test.
        * gcc.target/aarch64/auto-init-padding-12.c: New test.
        * gcc.target/aarch64/auto-init-padding-2.c: New test.
        * gcc.target/aarch64/auto-init-padding-3.c: New test.
        * gcc.target/aarch64/auto-init-padding-4.c: New test.
        * gcc.target/aarch64/auto-init-padding-5.c: New test.
        * gcc.target/aarch64/auto-init-padding-6.c: New test.
        * gcc.target/aarch64/auto-init-padding-7.c: New test.
        * gcc.target/aarch64/auto-init-padding-8.c: New test.
        * gcc.target/aarch64/auto-init-padding-9.c: New test.
        * gcc.target/i386/auto-init-1.c: New test.
        * gcc.target/i386/auto-init-2.c: New test.
        * gcc.target/i386/auto-init-21.c: New test.
        * gcc.target/i386/auto-init-22.c: New test.
        * gcc.target/i386/auto-init-23.c: New test.
        * gcc.target/i386/auto-init-24.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-padding-1.c: New test.
        * gcc.target/i386/auto-init-padding-10.c: New test.
        * gcc.target/i386/auto-init-padding-11.c: New test.
        * gcc.target/i386/auto-init-padding-12.c: New test.
        * gcc.target/i386/auto-init-padding-2.c: New test.
        * gcc.target/i386/auto-init-padding-3.c: New test.
        * gcc.target/i386/auto-init-padding-4.c: New test.
        * gcc.target/i386/auto-init-padding-5.c: New test.
        * gcc.target/i386/auto-init-padding-6.c: New test.
        * gcc.target/i386/auto-init-padding-7.c: New test.
        * gcc.target/i386/auto-init-padding-8.c: New test.
        * gcc.target/i386/auto-init-padding-9.c: New test.

******The complete 6th version of the patch is:



[-- Attachment #2: 0001-the-6th-version.patch --]
[-- Type: application/octet-stream, Size: 170515 bytes --]

From a894af20c1505ccabd7da7ae1e37171c54c94072 Mon Sep 17 00:00:00 2001
From: Qing Zhao <qing.zhao@oracle.com>
Date: Tue, 20 Jul 2021 19:43:13 +0000
Subject: [PATCH] the 6th version

---
 gcc/builtins.c                                |   3 +-
 gcc/builtins.h                                |   1 +
 gcc/c-family/c-attribs.c                      |  19 ++
 gcc/common.opt                                |  16 ++
 gcc/doc/extend.texi                           |  16 ++
 gcc/doc/invoke.texi                           |  41 ++-
 gcc/flag-types.h                              |   7 +
 gcc/gimple-fold.c                             |  48 ++--
 gcc/gimplify.c                                | 162 +++++++++++-
 gcc/internal-fn.c                             | 108 ++++++++
 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-15.c     |  13 +
 gcc/testsuite/c-c++-common/auto-init-16.c     |  13 +
 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 +++
 .../c-c++-common/auto-init-padding-1.c        |  23 ++
 .../c-c++-common/auto-init-padding-2.c        | 114 +++++++++
 .../c-c++-common/auto-init-padding-3.c        | 114 +++++++++
 .../g++.dg/auto-init-uninit-pred-1_a.C        |  63 +++++
 .../g++.dg/auto-init-uninit-pred-1_b.C        |  63 +++++
 .../g++.dg/auto-init-uninit-pred-2_a.C        |  62 +++++
 .../g++.dg/auto-init-uninit-pred-2_b.C        |  62 +++++
 .../g++.dg/auto-init-uninit-pred-3_a.C        |  77 ++++++
 .../g++.dg/auto-init-uninit-pred-3_b.C        |  87 +++++++
 .../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-sra-1.c        |  24 ++
 gcc/testsuite/gcc.dg/auto-init-sra-2.c        |  24 ++
 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.target/aarch64/auto-init-1.c          |  32 +++
 .../gcc.target/aarch64/auto-init-2.c          |  35 +++
 .../gcc.target/aarch64/auto-init-3.c          |  17 ++
 .../gcc.target/aarch64/auto-init-4.c          |  19 ++
 .../gcc.target/aarch64/auto-init-5.c          |  19 ++
 .../gcc.target/aarch64/auto-init-6.c          |  18 ++
 .../gcc.target/aarch64/auto-init-7.c          |  32 +++
 .../gcc.target/aarch64/auto-init-8.c          |  32 +++
 .../gcc.target/aarch64/auto-init-padding-1.c  |  17 ++
 .../gcc.target/aarch64/auto-init-padding-10.c |  22 ++
 .../gcc.target/aarch64/auto-init-padding-11.c |  27 ++
 .../gcc.target/aarch64/auto-init-padding-12.c |  27 ++
 .../gcc.target/aarch64/auto-init-padding-2.c  |  18 ++
 .../gcc.target/aarch64/auto-init-padding-3.c  |  27 ++
 .../gcc.target/aarch64/auto-init-padding-4.c  |  27 ++
 .../gcc.target/aarch64/auto-init-padding-5.c  |  22 ++
 .../gcc.target/aarch64/auto-init-padding-6.c  |  20 ++
 .../gcc.target/aarch64/auto-init-padding-7.c  |  20 ++
 .../gcc.target/aarch64/auto-init-padding-8.c  |  22 ++
 .../gcc.target/aarch64/auto-init-padding-9.c  |  21 ++
 gcc/testsuite/gcc.target/i386/auto-init-1.c   |  32 +++
 gcc/testsuite/gcc.target/i386/auto-init-2.c   |  36 +++
 gcc/testsuite/gcc.target/i386/auto-init-21.c  |  14 ++
 gcc/testsuite/gcc.target/i386/auto-init-22.c  |  14 ++
 gcc/testsuite/gcc.target/i386/auto-init-23.c  |  13 +
 gcc/testsuite/gcc.target/i386/auto-init-24.c  |  13 +
 gcc/testsuite/gcc.target/i386/auto-init-3.c   |  17 ++
 gcc/testsuite/gcc.target/i386/auto-init-4.c   |  20 ++
 gcc/testsuite/gcc.target/i386/auto-init-5.c   |  20 ++
 gcc/testsuite/gcc.target/i386/auto-init-6.c   |  19 ++
 gcc/testsuite/gcc.target/i386/auto-init-7.c   |  32 +++
 gcc/testsuite/gcc.target/i386/auto-init-8.c   |  35 +++
 .../gcc.target/i386/auto-init-padding-1.c     |  19 ++
 .../gcc.target/i386/auto-init-padding-10.c    |  21 ++
 .../gcc.target/i386/auto-init-padding-11.c    |  26 ++
 .../gcc.target/i386/auto-init-padding-12.c    |  26 ++
 .../gcc.target/i386/auto-init-padding-2.c     |  19 ++
 .../gcc.target/i386/auto-init-padding-3.c     |  30 +++
 .../gcc.target/i386/auto-init-padding-4.c     |  28 +++
 .../gcc.target/i386/auto-init-padding-5.c     |  22 ++
 .../gcc.target/i386/auto-init-padding-6.c     |  22 ++
 .../gcc.target/i386/auto-init-padding-7.c     |  22 ++
 .../gcc.target/i386/auto-init-padding-8.c     |  22 ++
 .../gcc.target/i386/auto-init-padding-9.c     |  23 ++
 gcc/tree-cfg.c                                |  99 ++++++--
 gcc/tree-sra.c                                | 124 ++++++++-
 gcc/tree-ssa-structalias.c                    |   3 +
 gcc/tree-ssa-uninit.c                         |  47 ++++
 gcc/tree-ssa.c                                |  40 +++
 125 files changed, 4286 insertions(+), 56 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-15.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-16.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/c-c++-common/auto-init-padding-1.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-padding-2.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-padding-3.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-sra-1.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-sra-2.c
 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-2.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-padding-1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-padding-10.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-padding-11.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-padding-12.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-padding-2.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-padding-3.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-padding-4.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-padding-5.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-padding-6.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-padding-7.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-padding-8.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-padding-9.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-1.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-2.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-21.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-22.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-23.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-24.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-padding-1.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-padding-10.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-padding-11.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-padding-12.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-padding-2.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-padding-3.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-padding-4.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-padding-5.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-padding-6.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-padding-7.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-padding-8.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-padding-9.c

diff --git a/gcc/builtins.c b/gcc/builtins.c
index 39ab139b7e1c..aa8e3e499e48 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -145,7 +145,6 @@ static rtx expand_builtin_stpcpy (tree, rtx, machine_mode);
 static rtx expand_builtin_stpncpy (tree, rtx);
 static rtx expand_builtin_strncat (tree, rtx);
 static rtx expand_builtin_strncpy (tree, rtx);
-static rtx expand_builtin_memset (tree, rtx, machine_mode);
 static rtx expand_builtin_memset_args (tree, tree, tree, rtx, machine_mode, tree);
 static rtx expand_builtin_bzero (tree);
 static rtx expand_builtin_strlen (tree, rtx, machine_mode);
@@ -6757,7 +6756,7 @@ builtin_memset_gen_str (void *data, void *prevp,
    try to get the result in TARGET, if convenient (and in mode MODE if that's
    convenient).  */
 
-static rtx
+rtx
 expand_builtin_memset (tree exp, rtx target, machine_mode mode)
 {
   if (!validate_arglist (exp,
diff --git a/gcc/builtins.h b/gcc/builtins.h
index a64ece3f1cd9..b18fe079ec3a 100644
--- a/gcc/builtins.h
+++ b/gcc/builtins.h
@@ -114,6 +114,7 @@ extern rtx builtin_strncpy_read_str (void *, void *, HOST_WIDE_INT,
 				     scalar_int_mode);
 extern rtx builtin_memset_read_str (void *, void *, HOST_WIDE_INT,
 				    scalar_int_mode);
+extern rtx expand_builtin_memset (tree, rtx, machine_mode);
 extern rtx expand_builtin_saveregs (void);
 extern tree std_build_builtin_va_list (void);
 extern tree std_fn_abi_va_list (tree);
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index e60fb31d8c8e..9b594006fe44 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -83,6 +83,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,
@@ -331,6 +332,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,
@@ -1613,6 +1616,22 @@ handle_retain_attribute (tree *pnode, tree name, tree ARG_UNUSED (args),
   return NULL_TREE;
 }
 
+/* Handle an "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))
+    {
+      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 d9da1131edaa..5e4221e8af64 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -3078,6 +3078,22 @@ 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_auto_var_init) Init(AUTO_INIT_UNINITIALIZED) Optimization
+-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)
+
 ; -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 b83cd4919bb1..54ee99d29407 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -7540,6 +7540,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 32697e6117c0..092e4a91774f 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -573,9 +573,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}
@@ -11818,6 +11818,41 @@ 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
+the security and predictability of a program by preventing uninitialized memory
+disclosure and use.
+GCC still considers an automatic variable that doesn't have an explicit
+initializer as uninitialized, -Wuninitialized will still report warning messages
+on such automatic variables.
+With this option, GCC will also initialize any padding of automatic variables
+that have structure or union types to zeroes.
+
+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 current value is byte-repeatable pattern with byte "0xFE".
+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/flag-types.h b/gcc/flag-types.h
index e43d1de490df..6fb0aefbfc7b 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -276,6 +276,13 @@ 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
+};
+
 /* Different instrumentation modes.  */
 enum sanitize_code {
   /* AddressSanitizer.  */
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index a3afe871f6b4..5458ee8ce54f 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -4517,12 +4517,14 @@ clear_padding_add_padding (clear_padding_struct *buf,
     }
 }
 
-static void clear_padding_type (clear_padding_struct *, tree, HOST_WIDE_INT);
+static void clear_padding_type (clear_padding_struct *, tree,
+				HOST_WIDE_INT, bool);
 
 /* Clear padding bits of union type TYPE.  */
 
 static void
-clear_padding_union (clear_padding_struct *buf, tree type, HOST_WIDE_INT sz)
+clear_padding_union (clear_padding_struct *buf, tree type,
+		     HOST_WIDE_INT sz, bool for_auto_init)
 {
   clear_padding_struct *union_buf;
   HOST_WIDE_INT start_off = 0, next_off = 0;
@@ -4567,7 +4569,7 @@ clear_padding_union (clear_padding_struct *buf, tree type, HOST_WIDE_INT sz)
 	      continue;
 	    gcc_assert (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
 			&& !COMPLETE_TYPE_P (TREE_TYPE (field)));
-	    if (!buf->clear_in_mask)
+	    if (!buf->clear_in_mask && !for_auto_init)
 	      error_at (buf->loc, "flexible array member %qD does not have "
 				  "well defined padding bits for %qs",
 			field, "__builtin_clear_padding");
@@ -4578,7 +4580,7 @@ clear_padding_union (clear_padding_struct *buf, tree type, HOST_WIDE_INT sz)
 	union_buf->off = start_off;
 	union_buf->size = start_size;
 	memset (union_buf->buf, ~0, start_size);
-	clear_padding_type (union_buf, TREE_TYPE (field), fldsz);
+	clear_padding_type (union_buf, TREE_TYPE (field), fldsz, for_auto_init);
 	clear_padding_add_padding (union_buf, sz - fldsz);
 	clear_padding_flush (union_buf, true);
       }
@@ -4648,7 +4650,8 @@ clear_padding_type_may_have_padding_p (tree type)
      __builtin_clear_padding (buf.base);  */
 
 static void
-clear_padding_emit_loop (clear_padding_struct *buf, tree type, tree end)
+clear_padding_emit_loop (clear_padding_struct *buf, tree type,
+			 tree end, bool for_auto_init)
 {
   tree l1 = create_artificial_label (buf->loc);
   tree l2 = create_artificial_label (buf->loc);
@@ -4659,7 +4662,7 @@ clear_padding_emit_loop (clear_padding_struct *buf, tree type, tree end)
   g = gimple_build_label (l1);
   gimple_set_location (g, buf->loc);
   gsi_insert_before (buf->gsi, g, GSI_SAME_STMT);
-  clear_padding_type (buf, type, buf->sz);
+  clear_padding_type (buf, type, buf->sz, for_auto_init);
   clear_padding_flush (buf, true);
   g = gimple_build_assign (buf->base, POINTER_PLUS_EXPR, buf->base,
 			   size_int (buf->sz));
@@ -4677,10 +4680,13 @@ clear_padding_emit_loop (clear_padding_struct *buf, tree type, tree end)
 }
 
 /* Clear padding bits for TYPE.  Called recursively from
-   gimple_fold_builtin_clear_padding.  */
+   gimple_fold_builtin_clear_padding. If FOR_AUTO_INIT,
+   not emit some of the error messages since doing that
+   might confuse the end user.  */
 
 static void
-clear_padding_type (clear_padding_struct *buf, tree type, HOST_WIDE_INT sz)
+clear_padding_type (clear_padding_struct *buf, tree type,
+		    HOST_WIDE_INT sz, bool for_auto_init)
 {
   switch (TREE_CODE (type))
     {
@@ -4762,7 +4768,7 @@ clear_padding_type (clear_padding_struct *buf, tree type, HOST_WIDE_INT sz)
 		  continue;
 		gcc_assert (TREE_CODE (ftype) == ARRAY_TYPE
 			    && !COMPLETE_TYPE_P (ftype));
-		if (!buf->clear_in_mask)
+		if (!buf->clear_in_mask && !for_auto_init)
 		  error_at (buf->loc, "flexible array member %qD does not "
 				      "have well defined padding bits for %qs",
 			    field, "__builtin_clear_padding");
@@ -4776,7 +4782,8 @@ clear_padding_type (clear_padding_struct *buf, tree type, HOST_WIDE_INT sz)
 		gcc_assert (pos >= 0 && fldsz >= 0 && pos >= cur_pos);
 		clear_padding_add_padding (buf, pos - cur_pos);
 		cur_pos = pos;
-		clear_padding_type (buf, TREE_TYPE (field), fldsz);
+		clear_padding_type (buf, TREE_TYPE (field),
+				    fldsz, for_auto_init);
 		cur_pos += fldsz;
 	      }
 	  }
@@ -4816,7 +4823,7 @@ clear_padding_type (clear_padding_struct *buf, tree type, HOST_WIDE_INT sz)
 	  buf->align = TYPE_ALIGN (elttype);
 	  buf->off = 0;
 	  buf->size = 0;
-	  clear_padding_emit_loop (buf, elttype, end);
+	  clear_padding_emit_loop (buf, elttype, end, for_auto_init);
 	  buf->base = base;
 	  buf->sz = prev_sz;
 	  buf->align = prev_align;
@@ -4826,10 +4833,10 @@ clear_padding_type (clear_padding_struct *buf, tree type, HOST_WIDE_INT sz)
 	  break;
 	}
       for (HOST_WIDE_INT i = 0; i < nelts; i++)
-	clear_padding_type (buf, TREE_TYPE (type), fldsz);
+	clear_padding_type (buf, TREE_TYPE (type), fldsz, for_auto_init);
       break;
     case UNION_TYPE:
-      clear_padding_union (buf, type, sz);
+      clear_padding_union (buf, type, sz, for_auto_init);
       break;
     case REAL_TYPE:
       gcc_assert ((size_t) sz <= clear_padding_unit);
@@ -4853,14 +4860,14 @@ clear_padding_type (clear_padding_struct *buf, tree type, HOST_WIDE_INT sz)
       break;
     case COMPLEX_TYPE:
       fldsz = int_size_in_bytes (TREE_TYPE (type));
-      clear_padding_type (buf, TREE_TYPE (type), fldsz);
-      clear_padding_type (buf, TREE_TYPE (type), fldsz);
+      clear_padding_type (buf, TREE_TYPE (type), fldsz, for_auto_init);
+      clear_padding_type (buf, TREE_TYPE (type), fldsz, for_auto_init);
       break;
     case VECTOR_TYPE:
       nelts = TYPE_VECTOR_SUBPARTS (type).to_constant ();
       fldsz = int_size_in_bytes (TREE_TYPE (type));
       for (HOST_WIDE_INT i = 0; i < nelts; i++)
-	clear_padding_type (buf, TREE_TYPE (type), fldsz);
+	clear_padding_type (buf, TREE_TYPE (type), fldsz, for_auto_init);
       break;
     case NULLPTR_TYPE:
       gcc_assert ((size_t) sz <= clear_padding_unit);
@@ -4896,7 +4903,7 @@ clear_type_padding_in_mask (tree type, unsigned char *mask)
   buf.sz = int_size_in_bytes (type);
   buf.size = 0;
   buf.union_ptr = mask;
-  clear_padding_type (&buf, type, buf.sz);
+  clear_padding_type (&buf, type, buf.sz, false);
   clear_padding_flush (&buf, true);
 }
 
@@ -4906,9 +4913,10 @@ static bool
 gimple_fold_builtin_clear_padding (gimple_stmt_iterator *gsi)
 {
   gimple *stmt = gsi_stmt (*gsi);
-  gcc_assert (gimple_call_num_args (stmt) == 2);
+  gcc_assert (gimple_call_num_args (stmt) == 3);
   tree ptr = gimple_call_arg (stmt, 0);
   tree typearg = gimple_call_arg (stmt, 1);
+  bool for_auto_init = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
   tree type = TREE_TYPE (TREE_TYPE (typearg));
   location_t loc = gimple_location (stmt);
   clear_padding_struct buf;
@@ -4965,7 +4973,7 @@ gimple_fold_builtin_clear_padding (gimple_stmt_iterator *gsi)
 	  buf.sz = eltsz;
 	  buf.align = TYPE_ALIGN (elttype);
 	  buf.alias_type = build_pointer_type (elttype);
-	  clear_padding_emit_loop (&buf, elttype, end);
+	  clear_padding_emit_loop (&buf, elttype, end, for_auto_init);
 	}
     }
   else
@@ -4978,7 +4986,7 @@ gimple_fold_builtin_clear_padding (gimple_stmt_iterator *gsi)
 	  gsi_insert_before (gsi, g, GSI_SAME_STMT);
 	}
       buf.alias_type = build_pointer_type (type);
-      clear_padding_type (&buf, type, buf.sz);
+      clear_padding_type (&buf, type, buf.sz, for_auto_init);
       clear_padding_flush (&buf, true);
     }
 
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 93a2121fea18..cee8649cf3a7 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -249,6 +249,11 @@ static enum gimplify_status gimplify_compound_expr (tree *, gimple_seq *, bool);
 static hash_map<tree, tree> *oacc_declare_returns;
 static enum gimplify_status gimplify_expr (tree *, gimple_seq *, gimple_seq *,
 					   bool (*) (tree), fallback_t, bool);
+static void gimple_add_init_for_auto_var (tree, enum auto_init_type, bool,
+					  gimple_seq *);
+static void maybe_with_size_expr (tree *);
+static void prepare_gimple_addressable (tree *, gimple_seq *);
+
 
 /* Shorter alias name for the above function for use in gimplify.c
    only.  */
@@ -1743,6 +1748,114 @@ 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: SIZE of the DECL;
+   2nd argument: INIT_TYPE;
+   3rd argument: IS_VLA, 0 NO, 1 YES;
+
+   as DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA).  */
+
+static gimple *
+build_deferred_init (tree decl,
+		     enum auto_init_type init_type,
+		     bool is_vla)
+{
+  gcc_assert ((is_vla && TREE_CODE (decl) == WITH_SIZE_EXPR)
+	      || (!is_vla && TREE_CODE (decl) != WITH_SIZE_EXPR));
+
+  tree decl_size = NULL_TREE;
+  tree init_type_node
+    = build_int_cst (integer_type_node, (int) init_type);
+  tree is_vla_node
+    = build_int_cst (integer_type_node, (int) is_vla);
+
+   if (TREE_CODE (decl) == WITH_SIZE_EXPR)
+     decl_size = TREE_OPERAND (decl, 1);
+   else
+     decl_size = TYPE_SIZE_UNIT (TREE_TYPE (decl));
+
+   return gimple_build_call_internal (IFN_DEFERRED_INIT, 3,
+				      decl_size, init_type_node, is_vla_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,
+			      bool is_vla,
+			      gimple_seq *seq_p)
+{
+  gcc_assert (VAR_P (decl) && !DECL_EXTERNAL (decl) && !TREE_STATIC (decl));
+  gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
+
+  /* If this DECL is a variable sized type, we must remember the size.  */
+  tree orig_decl = decl;
+  maybe_with_size_expr (&decl);
+
+  gimple *call = build_deferred_init (decl, init_type, is_vla);
+  gimple_call_set_lhs (call, orig_decl);
+  gimplify_seq_add_stmt (seq_p, call);
+}
+
+/* Generate padding initialization for automatic vairable DECL.
+   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 padding is initialized to zero. So, we always initialize paddings
+   to zeroes regardless INIT_TYPE.
+   To do the padding initialization, we insert a call to
+   __BUILTIN_CLEAR_PADDING (&decl, 0, for_auto_init = true).
+   */
+static void
+gimple_add_padding_init_for_auto_var (tree decl, bool is_vla,
+				      gimple_seq *seq_p)
+{
+  tree addr_of_decl = NULL_TREE;
+  bool for_auto_init = true;
+  tree fn = builtin_decl_explicit (BUILT_IN_CLEAR_PADDING);
+
+  if (is_vla)
+    {
+      /* The temporary address variable for this vla should be
+	 created in gimplify_vla_decl.  */
+      gcc_assert (DECL_HAS_VALUE_EXPR_P (decl));
+      gcc_assert (TREE_CODE (DECL_VALUE_EXPR (decl)) == INDIRECT_REF);
+      addr_of_decl = TREE_OPERAND (DECL_VALUE_EXPR (decl), 0);
+    }
+  else
+    {
+      prepare_gimple_addressable (&decl, seq_p);
+      mark_addressable (decl);
+      addr_of_decl = build_fold_addr_expr (decl);
+    }
+
+
+  /* for languages that do not support BUILT_IN_CLEAR_PADDING, create the
+     function node for padding initialization.  */
+  if (!fn)
+    {
+      tree ftype = build_function_type_list (void_type_node,
+					     ptr_type_node,
+					     ptr_type_node,
+					     integer_type_node,
+					     NULL_TREE);
+      fn = add_builtin_function ("__builtin_clear_padding", ftype,
+				 BUILT_IN_CLEAR_PADDING, BUILT_IN_NORMAL,
+				 NULL, NULL_TREE);
+      set_call_expr_flags (fn, ECF_NOTHROW | ECF_LEAF);
+      set_builtin_decl (BUILT_IN_CLEAR_PADDING, fn, false);
+    }
+
+  gimple *call = gimple_build_call (fn,
+				    3, addr_of_decl,
+				    build_zero_cst (TREE_TYPE (addr_of_decl)),
+				    build_int_cst (integer_type_node,
+						   (int) for_auto_init));
+  gimplify_seq_add_stmt (seq_p, call);
+}
+
+
 /* Gimplify a DECL_EXPR node *STMT_P by making any necessary allocation
    and initialization explicit.  */
 
@@ -1839,6 +1952,31 @@ 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.  */
+      else if (opt_for_fn (current_function_decl, flag_auto_var_init)
+		 > AUTO_INIT_UNINITIALIZED
+	       && !lookup_attribute ("uninitialized", DECL_ATTRIBUTES (decl))
+	       && !TREE_STATIC (decl))
+	{
+	  gimple_add_init_for_auto_var (decl,
+					opt_for_fn (current_function_decl,
+						    flag_auto_var_init),
+					is_vla,
+					seq_p);
+	  /* The expanding of a call to the above .DEFERRED_INIT will apply
+	     block initialization to the whole space covered by this variable.
+	     As a result, all the paddings will be initialized to zeroes
+	     for zero initialization and 0xFE byte-repeatable patterns for
+	     pattern initialization.
+	     In order to make the paddings as zeroes for pattern init, We
+	     should add a call to __builtin_clear_padding to clear the
+	     paddings to zero in compatiple with CLANG.  */
+	  if (opt_for_fn (current_function_decl, flag_auto_var_init)
+	      == AUTO_INIT_PATTERN)
+	    gimple_add_padding_init_for_auto_var (decl, is_vla, seq_p);
+	}
     }
 
   return GS_ALL_DONE;
@@ -3410,11 +3548,15 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
 	  {
 	    /* Remember the original type of the argument in an internal
 	       dummy second argument, as in GIMPLE pointer conversions are
-	       useless.  */
+	       useless. also mark this call as not for automatic initialization
+	       in the internal dummy third argument.  */
 	    p = CALL_EXPR_ARG (*expr_p, 0);
+	    bool for_auto_init = false;
 	    *expr_p
-	      = build_call_expr_loc (EXPR_LOCATION (*expr_p), fndecl, 2, p,
-				     build_zero_cst (TREE_TYPE (p)));
+	      = build_call_expr_loc (EXPR_LOCATION (*expr_p), fndecl, 3, p,
+				     build_zero_cst (TREE_TYPE (p)),
+				     build_int_cst (integer_type_node,
+						    (int) for_auto_init));
 	    return GS_OK;
 	  }
 	break;
@@ -5280,6 +5422,7 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p,
 {
   enum gimplify_status ret = GS_UNHANDLED;
   bool changed;
+  tree object = NULL_TREE;
 
   do
     {
@@ -5394,6 +5537,19 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p,
 	     crack at this before we break it down.  */
 	  if (ret != GS_UNHANDLED)
 	    break;
+	  /* If the user requests to initialize automatic variables, we
+	     should initialize paddings inside the variable. Add a call to
+	     __BUILTIN_CLEAR_PADDING (&object, 0, for_auto_init = true) to
+	     initialize paddings of object always to zero regardless of
+	     INIT_TYPE.  */
+	  object = TREE_OPERAND (*expr_p, 0);
+	  if (opt_for_fn (current_function_decl, flag_auto_var_init)
+		> AUTO_INIT_UNINITIALIZED
+	      && VAR_P (object)
+	      && !DECL_EXTERNAL (object)
+	      && !TREE_STATIC (object))
+	    gimple_add_padding_init_for_auto_var (object, false, pre_p);
+
 	  /* If we're initializing from a CONSTRUCTOR, break this into
 	     individual MODIFY_EXPRs.  */
 	  return gimplify_init_constructor (expr_p, pre_p, post_p, want_value,
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 1360a00f0b93..620a2f9fee2a 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -2977,6 +2977,114 @@ expand_UNIQUE (internal_fn, gcall *stmt)
     emit_insn (pattern);
 }
 
+/* Expand the IFN_DEFERRED_INIT function:
+   Initialize the LHS variable with zero/pattern according to its second
+   argument INIT_TYPE.
+   if INIT_TYPE is AUTO_INIT_ZERO, use zeroes to initialize;
+   if INIT_TYPE is AUTO_INIT_PATTERN, use 0xFE byte-repeatable pattern
+     to initialize;
+   all the memory covered by this LHS variable is initialized including
+   paddings.
+   The reasons to choose 0xFE for pattern initialization are:
+     1. It is a non-canonical virtual address on x86_64, and at the
+	high end of the i386 kernel address space.
+     2. It is a very large float value (-1.694739530317379e+38).
+     3. It is also an unusual number for integers.  */
+#define INIT_PATTERN_VALUE  0xFE
+static void
+expand_DEFERRED_INIT (internal_fn, gcall *stmt)
+{
+  tree var = gimple_call_lhs (stmt);
+  tree size_of_var = gimple_call_arg (stmt, 0);
+  tree vlaaddr = NULL_TREE;
+  tree var_type = TREE_TYPE (var);
+  bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
+  enum auto_init_type init_type
+    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
+
+  gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
+
+  /* if this variable is a VLA, get its SIZE and ADDR first.  */
+  if (is_vla)
+    {
+      /* The temporary address variable for this vla should have been
+	 created during gimplification phase.  Refer to gimplify_vla_decl
+	 for details.  */
+      tree var_decl = (TREE_CODE (var) == SSA_NAME) ?
+		       SSA_NAME_VAR (var) : var;
+      gcc_assert (DECL_HAS_VALUE_EXPR_P (var_decl));
+      gcc_assert (TREE_CODE (DECL_VALUE_EXPR (var_decl)) == INDIRECT_REF);
+      /* Get the address of this vla variable.  */
+      vlaaddr = TREE_OPERAND (DECL_VALUE_EXPR (var_decl), 0);
+    }
+
+  if (is_vla || (!use_register_for_decl (var)))
+    {
+    /* If this is a VLA or the variable is not in register,
+       expand to a memset to initialize it.  */
+      if (TREE_CODE (var) == SSA_NAME)
+	var = SSA_NAME_VAR (var);
+      tree addr = is_vla ? vlaaddr: build_fold_addr_expr (var);
+      tree value = (init_type == AUTO_INIT_PATTERN) ?
+		    build_int_cst (unsigned_char_type_node,
+				   INIT_PATTERN_VALUE) :
+		    build_zero_cst (unsigned_char_type_node);
+      tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
+				     3, addr, value, size_of_var);
+      /* Expand this memset call.  */
+      expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
+    }
+  else
+    {
+    /* If this variable is in a register, use expand_assignment might
+       generate better code.  */
+      tree pattern = NULL_TREE;
+      unsigned HOST_WIDE_INT total_bytes
+	= tree_to_uhwi (TYPE_SIZE_UNIT (var_type));
+
+      if (INTEGRAL_TYPE_P (var_type) || POINTER_TYPE_P (var_type))
+	{
+	  unsigned char *ptr = (unsigned char *)xmalloc (total_bytes);
+	  for (unsigned int i = 0; i < total_bytes; i++)
+	    ptr[i] = INIT_PATTERN_VALUE;
+	  wide_int result = wi::from_buffer (ptr, total_bytes);
+	  pattern =  wide_int_to_tree (var_type, result);
+	}
+      else if (SCALAR_FLOAT_TYPE_P (var_type))
+	{
+	  unsigned int max_index = 2 + 2 * total_bytes;
+	  char *ptr= (char *)xmalloc (max_index);
+	  ptr[0] = '0';
+	  ptr[1] = 'x';
+	  for (unsigned int i = 2; i < max_index; i += 2)
+	    ptr[i] = 'F';
+	  for (unsigned int i = 3; i < max_index; i += 2)
+	    ptr[i] = 'E';
+	  REAL_VALUE_TYPE r_var;
+	  real_from_string (&r_var, ptr);
+	  pattern = build_real (var_type, r_var);
+	}
+      else
+	{
+	  tree index_type = build_index_type (size_int (total_bytes - 1));
+	  tree array_type = build_array_type (unsigned_char_type_node,
+					      index_type);
+	  tree element = build_int_cst (unsigned_char_type_node,
+					INIT_PATTERN_VALUE);
+	  vec<constructor_elt, va_gc> *elts = NULL;
+	  for (unsigned int i = 0; i < total_bytes; i++)
+	    CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, element);
+	  pattern = build_constructor (array_type, elts);
+	  pattern = build1 (VIEW_CONVERT_EXPR, var_type, pattern);
+	}
+
+      tree init = (init_type == AUTO_INIT_PATTERN) ?
+		   pattern :
+		   build_zero_cst (TREE_TYPE (var));
+      expand_assignment (var, init, false);
+    }
+}
+
 /* The size of an OpenACC compute dimension.  */
 
 static void
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index 3ac9ae68b2a6..dc84b7b7ca79 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -360,6 +360,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 000000000000..8b8ba3dd7e8d
--- /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 \\(1, 2, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(2, 2, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(4, 2, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp4 = .DEFERRED_INIT \\(4, 2, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp5 = .DEFERRED_INIT \\(8, 2, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp6 = .DEFERRED_INIT \\(8, 2, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp7 = .DEFERRED_INIT \\(8, 2, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp8 = .DEFERRED_INIT \\(1, 2, 0\\)" "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 000000000000..0a8841e6e0f9
--- /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 \\(2, 1, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump-not "temp2 = .DEFERRED_INIT \\(" "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 000000000000..a2d66908d83e
--- /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 ".DEFERRED_INIT \\(D.\\d*, 2, 1\\)" "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 000000000000..f05d743fda02
--- /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 ".DEFERRED_INIT \\(D.\\d*, 1, 1\\)" "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 000000000000..b0c0365b288a
--- /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 \\(4, 1, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "var = .DEFERRED_INIT \\(4, 1, 0\\)" "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 000000000000..986bb19faaf0
--- /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 \\(4, 2, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "var = .DEFERRED_INIT \\(4, 2, 0\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-15.c b/gcc/testsuite/c-c++-common/auto-init-15.c
new file mode 100644
index 000000000000..aa9d7fab68a6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-15.c
@@ -0,0 +1,13 @@
+/* Verify the auto initialization of nested VLA.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-tree-gimple" } */
+
+void g(void *);
+
+void foo(int a)
+{
+  int x[a][a];
+  g(x);
+}
+
+/* { dg-final { scan-tree-dump ".DEFERRED_INIT \\(D.\\d*, 2, 1\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-16.c b/gcc/testsuite/c-c++-common/auto-init-16.c
new file mode 100644
index 000000000000..86493eef9e47
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-16.c
@@ -0,0 +1,13 @@
+/* Verify the auto initialization of nested VLA.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-tree-gimple" } */
+
+void g(void *);
+
+void foo(int a)
+{
+  int x[a][a];
+  g(x);
+}
+
+/* { dg-final { scan-tree-dump ".DEFERRED_INIT \\(D.\\d*, 1, 1\\)" "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 000000000000..71955b54ba03
--- /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 \\(1, 1, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(2, 1, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(4, 1, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp4 = .DEFERRED_INIT \\(4, 1, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp5 = .DEFERRED_INIT \\(8, 1, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp6 = .DEFERRED_INIT \\(8, 1, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp7 = .DEFERRED_INIT \\(8, 1, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp8 = .DEFERRED_INIT \\(1, 1, 0\\)" "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 000000000000..312275666381
--- /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 \\(4, 2, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(8, 2, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(16, 2, 0\\)" "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 000000000000..15a431726dcd
--- /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 \\(4, 1, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(8, 1, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(16, 1, 0\\)" "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 000000000000..54f90bc890b5
--- /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 \\(8, 2, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(16, 2, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(32, 2, 0\\)" "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 000000000000..4124a2b183aa
--- /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 \\(8, 1, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(16, 1, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(32, 1, 0\\)" "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 000000000000..19986969a8f7
--- /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 \\(12, 2, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(24, 2, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(28, 2, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp4 = .DEFERRED_INIT \\(8, 2, 0\\)" "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 000000000000..9778e911e3ad
--- /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 \\(12, 1, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(24, 1, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(28, 1, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp4 = .DEFERRED_INIT \\(8, 1, 0\\)" "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 000000000000..90bbd8cb1afe
--- /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 \\(2, 2, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump-not "temp2 = .DEFERRED_INIT \\(8, 2, 0\\)" "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 000000000000..77ec02355df4
--- /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 -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 \\(24, 2, 0\\)" 1 "gimple" } } */
+/* { dg-final { scan-tree-dump-times ".DEFERRED_INIT \\(8, 2, 0\\)" 3 "esra" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-padding-1.c b/gcc/testsuite/c-c++-common/auto-init-padding-1.c
new file mode 100644
index 000000000000..97f78ee7d56a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-padding-1.c
@@ -0,0 +1,23 @@
+/* Verify the padding initialization for pattern initialization, we always emit
+ * a call to __builtin_clear_padding to initialize the paddings to zero.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-tree-gimple" } */
+
+
+struct test_small_hole {
+  int one;
+  char two;
+  /* 3 byte padding hole here. */
+  int three;
+  unsigned long four;
+};
+
+extern void g (struct test_small_hole);
+void foo(int a)
+{
+  struct test_small_hole s; 
+  g(s);
+}
+
+/* { dg-final { scan-tree-dump ".DEFERRED_INIT \\(24, 1, 0\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "__builtin_clear_padding" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-padding-2.c b/gcc/testsuite/c-c++-common/auto-init-padding-2.c
new file mode 100644
index 000000000000..e2b50dc5ae8e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-padding-2.c
@@ -0,0 +1,114 @@
+/* To test that the compiler can fill all the paddings to zeroes for the 
+   structures when the auto variable is partially initialized,  fully 
+   initialized, or not initialized for -ftrivial-auto-var-init=zero.  */
+/* { dg-do run} */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+/* Structure with no padding. */
+struct test_packed {
+  unsigned long one;
+  unsigned long two;
+  unsigned long three;
+  unsigned long four;
+} p1;
+
+/* Simple structure with padding likely to be covered by compiler. */
+struct test_small_hole {
+  unsigned long one;
+  char two;
+  /* 3 byte padding hole here. */
+  int three;
+  unsigned long four;
+} sh1;
+
+/* Try to trigger unhandled padding in a structure. */
+struct test_aligned {
+  unsigned int internal1;
+  unsigned long long internal2;
+} __attribute__((__aligned__(64)));
+
+struct test_aligned a1;
+
+struct test_big_hole {
+  unsigned char one;
+  unsigned char two;
+  unsigned char three;
+  /* 61 byte padding hole here. */
+  struct test_aligned four;
+} __attribute__((__aligned__(64))); 
+
+struct test_big_hole bh1;
+
+struct test_trailing_hole {
+  char *one;
+  char *two;
+  char *three;
+  char four;
+  /* "sizeof(unsigned long) - 1" byte padding hole here. */
+} th1;
+
+__attribute__((noipa)) void
+foo (struct test_packed *p, struct test_small_hole *sh, struct test_aligned *a,
+     struct test_big_hole *bh, struct test_trailing_hole *th)
+{
+  p->one = 1; p->two = 2; p->three = 3; p->four = 4;
+  sh->one = 11; sh->two = 12; sh->three = 13; sh->four = 14;
+  a->internal1 = 21; a->internal2 = 22;
+  bh->one = 31; bh->two = 32; bh->three = 33;
+  bh->four.internal1 = 34; bh->four.internal2 = 35; 
+  th->one = 0; th->two = 0; th->three = 0; th->four = 44;
+}
+
+int main ()
+{
+  struct test_packed p2;
+  struct test_small_hole sh2;
+  struct test_aligned a2;
+  struct test_big_hole bh2;
+  struct test_trailing_hole th2;
+
+  struct test_packed p3 = {.one = 1};
+  struct test_small_hole sh3 = {.two = 12};
+  struct test_aligned a3 = {.internal1 = 21};
+  struct test_big_hole bh3 = {.one = 31};
+  struct test_trailing_hole th3 = {.three = 0};
+
+  struct test_packed p4 = {.one = 1, .two = 2, .three = 3, .four = 4};
+  struct test_small_hole sh4 = {.one = 11, .two = 12, .three = 13, .four = 14};
+  struct test_aligned a4 = {.internal1 = 21, .internal2 = 22};
+  struct test_big_hole bh4 = {.one = 31, .two = 32, .three = 33};
+  struct test_trailing_hole th4 = {.one = 0, .two = 0, .three = 0, .four = 44};
+
+  foo (&p1, &sh1, &a1, &bh1, &th1);
+  foo (&p2, &sh2, &a2, &bh2, &th2);
+  foo (&p3, &sh3, &a3, &bh3, &th3);
+  bh4.four.internal1 = 34; bh4.four.internal2 = 35;
+
+  __builtin_clear_padding (&p1);
+  __builtin_clear_padding (&sh1);
+  __builtin_clear_padding (&a1);
+  __builtin_clear_padding (&bh1);
+  __builtin_clear_padding (&th1);
+
+  if (__builtin_memcmp (&p1, &p2, sizeof (p1))
+      || __builtin_memcmp (&sh1, &sh2, sizeof (sh1))
+      || __builtin_memcmp (&a1, &a2, sizeof (a1))
+      || __builtin_memcmp (&bh1, &bh2, sizeof (bh1))
+      || __builtin_memcmp (&th1, &th2, sizeof (th1)))
+    __builtin_abort ();
+  if (__builtin_memcmp (&p1, &p3, sizeof (p1))
+      || __builtin_memcmp (&sh1, &sh3, sizeof (sh1))
+      || __builtin_memcmp (&a1, &a3, sizeof (a1))
+      || __builtin_memcmp (&bh1, &bh3, sizeof (bh1))
+      || __builtin_memcmp (&th1, &th3, sizeof (th1)))
+    __builtin_abort ();
+  if (__builtin_memcmp (&p1, &p4, sizeof (p1))
+      || __builtin_memcmp (&sh1, &sh4, sizeof (sh1))
+      || __builtin_memcmp (&a1, &a4, sizeof (a1))
+      || __builtin_memcmp (&bh1, &bh4, sizeof (bh1))
+      || __builtin_memcmp (&th1, &th4, sizeof (th1)))
+    __builtin_abort ();
+
+
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/auto-init-padding-3.c b/gcc/testsuite/c-c++-common/auto-init-padding-3.c
new file mode 100644
index 000000000000..e2c48c002c95
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-padding-3.c
@@ -0,0 +1,114 @@
+/* To test that the compiler can fill all the paddings to zeroes for the 
+   structures when the auto variable is partially initialized,  fully 
+   initialized, or not initialized for -ftrivial-auto-var-init=pattern.  */
+/* { dg-do run} */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+/* Structure with no padding. */
+struct test_packed {
+  unsigned long one;
+  unsigned long two;
+  unsigned long three;
+  unsigned long four;
+} p1;
+
+/* Simple structure with padding likely to be covered by compiler. */
+struct test_small_hole {
+  unsigned long one;
+  char two;
+  /* 3 byte padding hole here. */
+  int three;
+  unsigned long four;
+} sh1;
+
+/* Try to trigger unhandled padding in a structure. */
+struct test_aligned {
+  unsigned int internal1;
+  unsigned long long internal2;
+} __attribute__((__aligned__(64)));
+
+struct test_aligned a1;
+
+struct test_big_hole {
+  unsigned char one;
+  unsigned char two;
+  unsigned char three;
+  /* 61 byte padding hole here. */
+  struct test_aligned four;
+} __attribute__((__aligned__(64))); 
+
+struct test_big_hole bh1;
+
+struct test_trailing_hole {
+  char *one;
+  char *two;
+  char *three;
+  char four;
+  /* "sizeof(unsigned long) - 1" byte padding hole here. */
+} th1;
+
+__attribute__((noipa)) void
+foo (struct test_packed *p, struct test_small_hole *sh, struct test_aligned *a,
+     struct test_big_hole *bh, struct test_trailing_hole *th)
+{
+  p->one = 1; p->two = 2; p->three = 3; p->four = 4;
+  sh->one = 11; sh->two = 12; sh->three = 13; sh->four = 14;
+  a->internal1 = 21; a->internal2 = 22;
+  bh->one = 31; bh->two = 32; bh->three = 33;
+  bh->four.internal1 = 34; bh->four.internal2 = 35; 
+  th->one = 0; th->two = 0; th->three = 0; th->four = 44;
+}
+
+int main ()
+{
+  struct test_packed p2;
+  struct test_small_hole sh2;
+  struct test_aligned a2;
+  struct test_big_hole bh2;
+  struct test_trailing_hole th2;
+
+  struct test_packed p3 = {.one = 1};
+  struct test_small_hole sh3 = {.two = 12};
+  struct test_aligned a3 = {.internal1 = 21};
+  struct test_big_hole bh3 = {.one = 31};
+  struct test_trailing_hole th3 = {.three = 0};
+
+  struct test_packed p4 = {.one = 1, .two = 2, .three = 3, .four = 4};
+  struct test_small_hole sh4 = {.one = 11, .two = 12, .three = 13, .four = 14};
+  struct test_aligned a4 = {.internal1 = 21, .internal2 = 22};
+  struct test_big_hole bh4 = {.one = 31, .two = 32, .three = 33};
+  struct test_trailing_hole th4 = {.one = 0, .two = 0, .three = 0, .four = 44};
+
+  foo (&p1, &sh1, &a1, &bh1, &th1);
+  foo (&p2, &sh2, &a2, &bh2, &th2);
+  foo (&p3, &sh3, &a3, &bh3, &th3);
+  bh4.four.internal1 = 34; bh4.four.internal2 = 35;
+
+  __builtin_clear_padding (&p1);
+  __builtin_clear_padding (&sh1);
+  __builtin_clear_padding (&a1);
+  __builtin_clear_padding (&bh1);
+  __builtin_clear_padding (&th1);
+
+  if (__builtin_memcmp (&p1, &p2, sizeof (p1))
+      || __builtin_memcmp (&sh1, &sh2, sizeof (sh1))
+      || __builtin_memcmp (&a1, &a2, sizeof (a1))
+      || __builtin_memcmp (&bh1, &bh2, sizeof (bh1))
+      || __builtin_memcmp (&th1, &th2, sizeof (th1)))
+    __builtin_abort ();
+  if (__builtin_memcmp (&p1, &p3, sizeof (p1))
+      || __builtin_memcmp (&sh1, &sh3, sizeof (sh1))
+      || __builtin_memcmp (&a1, &a3, sizeof (a1))
+      || __builtin_memcmp (&bh1, &bh3, sizeof (bh1))
+      || __builtin_memcmp (&th1, &th3, sizeof (th1)))
+    __builtin_abort ();
+  if (__builtin_memcmp (&p1, &p4, sizeof (p1))
+      || __builtin_memcmp (&sh1, &sh4, sizeof (sh1))
+      || __builtin_memcmp (&a1, &a4, sizeof (a1))
+      || __builtin_memcmp (&bh1, &bh4, sizeof (bh1))
+      || __builtin_memcmp (&th1, &th4, sizeof (th1)))
+    __builtin_abort ();
+
+
+  return 0;
+}
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 000000000000..33c17441384f
--- /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 000000000000..6b6bdaed71e0
--- /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 000000000000..fc18cb1e7c91
--- /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 000000000000..e85a36f16fff
--- /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 000000000000..09ed69215320
--- /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 000000000000..8e7b8541725e
--- /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 000000000000..c48770ae44dd
--- /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 000000000000..629677a60259
--- /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 000000000000..04ab364ac83e
--- /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 000000000000..82a1846c6e0b
--- /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 000000000000..629677a60259
--- /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-sra-1.c b/gcc/testsuite/gcc.dg/auto-init-sra-1.c
new file mode 100644
index 000000000000..88fd66678f29
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-sra-1.c
@@ -0,0 +1,24 @@
+/* Verify that SRA total scalarization will not be confused by padding
+   and also not confused by auto initialization.  */
+/* { dg-do compile } */
+/* { dg-options "-O1 --param sra-max-scalarization-size-Ospeed=16 -fdump-tree-release_ssa -ftrivial-auto-var-init=zero" } */
+
+struct S
+{
+  int i;
+  unsigned short f1;
+  char f2;
+  unsigned short f3, f4;
+};
+
+
+int foo (struct S *p)
+{
+  struct S l;
+
+  l = *p;
+  l.i++;
+  *p = l;
+}
+
+/* { dg-final { scan-tree-dump-times "l;" 0 "release_ssa" } } */
diff --git a/gcc/testsuite/gcc.dg/auto-init-sra-2.c b/gcc/testsuite/gcc.dg/auto-init-sra-2.c
new file mode 100644
index 000000000000..d260f5ae934e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-sra-2.c
@@ -0,0 +1,24 @@
+/* Verify that SRA total scalarization will not be confused by padding
+   and also not confused by auto initialization.  */
+/* { dg-do compile } */
+/* { dg-options "-O1 --param sra-max-scalarization-size-Ospeed=16 -fdump-tree-release_ssa -ftrivial-auto-var-init=pattern" } */
+
+struct S
+{
+  int i;
+  unsigned short f1;
+  char f2;
+  unsigned short f3, f4;
+};
+
+
+int foo (struct S *p)
+{
+  struct S l;
+
+  l = *p;
+  l.i++;
+  *p = l;
+}
+
+/* { dg-final { scan-tree-dump-times "l;" 0 "release_ssa" } } */
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 000000000000..cb0e7cc62545
--- /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 000000000000..559e2d963376
--- /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 000000000000..acff725722dc
--- /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 000000000000..87dd8b587e00
--- /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 000000000000..592052a9e9d0
--- /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 000000000000..121f0cff274a
--- /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 000000000000..0e4f336f726f
--- /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 000000000000..9eec9440c75e
--- /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 000000000000..4922848f6dc7
--- /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 000000000000..38d27e4f9548
--- /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 000000000000..da03bf8f6d98
--- /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 000000000000..f533ce9c70e7
--- /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 000000000000..6044eab27870
--- /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 000000000000..0200d734a2c3
--- /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 000000000000..7dce8d052e16
--- /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 000000000000..1f6740c123ad
--- /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 000000000000..f36d95f9d279
--- /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 000000000000..ae97ecfa71e1
--- /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 000000000000..7ff228501f8d
--- /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 000000000000..98fc366c871f
--- /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 000000000000..64377d380ee9
--- /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 000000000000..da3c9db1840a
--- /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 000000000000..482c837cacb2
--- /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 000000000000..ada81c912bdd
--- /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 000000000000..e6cba4ef22c0
--- /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 000000000000..6c298870c679
--- /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 000000000000..9d65493bde2a
--- /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 000000000000..01fcf59f4504
--- /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 000000000000..0b2837127209
--- /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 000000000000..a4aa629bf930
--- /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 000000000000..71e2e2d68d7f
--- /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 000000000000..09680fe9790d
--- /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 000000000000..0fa470880bf5
--- /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-2.c b/gcc/testsuite/gcc.target/aarch64/auto-init-2.c
new file mode 100644
index 000000000000..2c54e6d60382
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-2.c
@@ -0,0 +1,35 @@
+/* Verify pattern initialization for integer and pointer type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-O -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 "0xfe\\\]" 1 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xfffffffffffffefe" 1 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xfffffffffefefefe" 2 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xfefefefefefefefe" 2 "expand" } } */
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 000000000000..1adc147a3000
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-3.c
@@ -0,0 +1,17 @@
+/* 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-times "const_int 0" 7 "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 000000000000..9ee8335065f1
--- /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 "-O -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 "fefefefe" "expand" } } */
+/* { dg-final { scan-rtl-dump "fefefefefefefefe" "expand" } } */
+/* { dg-final { scan-rtl-dump "fefefefefefefefefefefefefefefefe" "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 000000000000..1874d961d5de
--- /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 -fdump-rtl-expand" } */
+
+
+_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-rtl-dump-times "const_int 0" 12 "expand" } } */
+
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 000000000000..27c16b336789
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-6.c
@@ -0,0 +1,18 @@
+/* Verify pattern initialization for complex type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */
+
+
+_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-rtl-dump-times "0xfffffffffffffffe\\\]\\\) repeated x16" 3 "expand" } } */
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 000000000000..ac27fbe92f4a
--- /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 000000000000..3943f5a4d6b2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-8.c
@@ -0,0 +1,32 @@
+/* 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 "0xfffffffffffffffe\\\]\\\) repeated x16" 4 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-padding-1.c b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-1.c
new file mode 100644
index 000000000000..d3a88c724545
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-1.c
@@ -0,0 +1,17 @@
+/* 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/aarch64/auto-init-padding-10.c b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-10.c
new file mode 100644
index 000000000000..b0f3acb2f528
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-10.c
@@ -0,0 +1,22 @@
+/* Verify pattern initialization for array type with structure element with
+   padding.  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */
+
+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-rtl-dump-times "0xfffffffffffffffe\\\]\\\) repeated x16" 1 "expand" } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-padding-11.c b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-11.c
new file mode 100644
index 000000000000..02f7edc51008
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-11.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-padding-12.c b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-12.c
new file mode 100644
index 000000000000..555972f1728f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-12.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 -fdump-rtl-expand" } */
+
+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-rtl-dump-times "0xfffffffffffffffe\\\]\\\) repeated x16" 1 "expand" } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-padding-2.c b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-2.c
new file mode 100644
index 000000000000..aceceb87fbe1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-2.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-padding-3.c b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-3.c
new file mode 100644
index 000000000000..085c38629210
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-3.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-padding-4.c b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-4.c
new file mode 100644
index 000000000000..7a6ddbc20ee1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-4.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," 5 } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-padding-5.c b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-5.c
new file mode 100644
index 000000000000..3c45a6c6288d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-5.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-padding-6.c b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-6.c
new file mode 100644
index 000000000000..bfef23d52a10
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-6.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 -fdump-rtl-expand" } */
+
+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-rtl-dump-times "0xfffffffffffffffe\\\]\\\) repeated x16" 1 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-padding-7.c b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-7.c
new file mode 100644
index 000000000000..cb96c3a1e4b2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-7.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-padding-8.c b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-8.c
new file mode 100644
index 000000000000..ce7c7cd31c1f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-8.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-padding-9.c b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-9.c
new file mode 100644
index 000000000000..c81e5ff28b0b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-padding-9.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/i386/auto-init-1.c b/gcc/testsuite/gcc.target/i386/auto-init-1.c
new file mode 100644
index 000000000000..b7690df24060
--- /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-2.c b/gcc/testsuite/gcc.target/i386/auto-init-2.c
new file mode 100644
index 000000000000..e76fc2565168
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-2.c
@@ -0,0 +1,36 @@
+/* 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 "0xfffffffffffffffe" 2 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xfffffffffffffefe" 1 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xfffffffffefefefe" 2 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xfefefefefefefefe" 3 "expand" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-21.c b/gcc/testsuite/gcc.target/i386/auto-init-21.c
new file mode 100644
index 000000000000..1192a908f9df
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-21.c
@@ -0,0 +1,14 @@
+/* Verify zero initialization for VLA automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand" } */
+
+extern void bar (int);
+
+void foo(int n)
+{
+  int arr[n];
+  bar (arr[2]);
+  return;
+}
+
+/* { dg-final { scan-rtl-dump "__builtin_memset" "expand" } } */
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-22.c b/gcc/testsuite/gcc.target/i386/auto-init-22.c
new file mode 100644
index 000000000000..431d9664e94f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-22.c
@@ -0,0 +1,14 @@
+/* Verify zero initialization for VLA automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */
+
+extern void bar (int);
+
+void foo(int n)
+{
+  int arr[n];
+  bar (arr[2]);
+  return;
+}
+
+/* { dg-final { scan-rtl-dump "__builtin_memset" "expand" } } */
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-23.c b/gcc/testsuite/gcc.target/i386/auto-init-23.c
new file mode 100644
index 000000000000..72094f6bdb92
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-23.c
@@ -0,0 +1,13 @@
+/* Verify the auto initialization of nested VLA.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand" } */
+
+void g(void *);
+
+void foo(int a)
+{
+  int x[a][a];
+  g(x);
+}
+
+/* { dg-final { scan-rtl-dump "__builtin_memset" "expand" } } */
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-24.c b/gcc/testsuite/gcc.target/i386/auto-init-24.c
new file mode 100644
index 000000000000..5cc3a756a1c5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-24.c
@@ -0,0 +1,13 @@
+/* Verify the auto initialization of nested VLA.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */
+
+void g(void *);
+
+void foo(int a)
+{
+  int x[a][a];
+  g(x);
+}
+
+/* { dg-final { scan-rtl-dump "__builtin_memset" "expand" } } */
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 000000000000..130e55fe2e84
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-3.c
@@ -0,0 +1,17 @@
+/* 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-times "const_int 0" 3 "expand" } } */
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 000000000000..55125b537bbd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-4.c
@@ -0,0 +1,20 @@
+/* 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-times "0xfffffffffefefefe" 1 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "\\\[0xfefefefefefefefe\\\]" 1 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xfefefefefefefefefefefefefefefefe" 1 "expand" } } */
+
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 000000000000..06c15bf935b2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-5.c
@@ -0,0 +1,20 @@
+/* Verify zero initialization for complex type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand" } */
+
+
+_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-rtl-dump-times "const_int 0" 4 "expand" } } */
+
+
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 000000000000..80bd56bcb9a7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-6.c
@@ -0,0 +1,19 @@
+/* Verify pattern initialization for complex type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */
+
+
+_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-rtl-dump-times "\\\[0xfefefefefefefefe\\\]" 1 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xfefefefefefefefefefefefefefefefe" 3 "expand" } } */
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 000000000000..e91a024631da
--- /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" 7 "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 000000000000..55e55be3bdd2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/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-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 "0xfffffffffefefefe" 1 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "\\\[0xfefefefefefefefe\\\]" 3 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xfefefefefefefefefefefefefefefefe" 3 "expand" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-padding-1.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-1.c
new file mode 100644
index 000000000000..b4069797d939
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-1.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/testsuite/gcc.target/i386/auto-init-padding-10.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-10.c
new file mode 100644
index 000000000000..af7a6028c5ce
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-10.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 -fdump-rtl-expand" } */
+
+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-rtl-dump-times "0xfefefefefefefefefefefefefefefefe" 10 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-padding-11.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-11.c
new file mode 100644
index 000000000000..31a3ee1fe971
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-11.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-padding-12.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-12.c
new file mode 100644
index 000000000000..bf9ea5d629a3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-12.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 -fdump-rtl-expand" } */
+
+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-rtl-dump-times "0xfefefefefefefefefefefefefefefefe" 1 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-padding-2.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-2.c
new file mode 100644
index 000000000000..2dc2d035a6c9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-2.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 -fdump-rtl-expand" } */
+
+struct test_aligned {
+        int internal1;
+        long long internal2;
+} __attribute__ ((aligned(64)));
+
+int foo ()
+{
+  struct test_aligned var;
+  return var.internal1;
+}
+
+/* { dg-final { scan-rtl-dump-times "0xfefefefefefefefefefefefefefefefe" 4 "expand" } } */
+
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-padding-3.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-3.c
new file mode 100644
index 000000000000..8a6d764b9fa4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-3.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-padding-4.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-4.c
new file mode 100644
index 000000000000..1ad60243aa4c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-4.c
@@ -0,0 +1,28 @@
+/* Verify pattern initialization for nested structure type automatic variables with
+   padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */
+
+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-rtl-dump-times "0xfefefefefefefefefefefefefefefefe" 8 "expand" } } */
+
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-padding-5.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-5.c
new file mode 100644
index 000000000000..e18bc3073e18
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-5.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-padding-6.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-6.c
new file mode 100644
index 000000000000..738a340efb61
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-6.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 -fdump-rtl-expand" } */
+
+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-rtl-dump-times "0xfefefefefefefefefefefefefefefefe" 2 "expand" } } */
+
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-padding-7.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-7.c
new file mode 100644
index 000000000000..b5abffb0fc66
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-7.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-padding-8.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-8.c
new file mode 100644
index 000000000000..66591cff4488
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-8.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-padding-9.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-9.c
new file mode 100644
index 000000000000..40fccadf920d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-9.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/tree-cfg.c b/gcc/tree-cfg.c
index c8b0f7b33e12..8d3187d19665 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -3457,31 +3457,92 @@ verify_gimple_call (gcall *stmt)
 	}
     }
 
+  /* For a call to .DEFERRED_INIT, we should guarantee that the 1st and the 3rd
+     argument is consistent, i.e.:
+     1st argument: SIZE of the DECL;
+     3rd argument: IS_VLA, 0 NO, 1 YES;
+
+     if IS_VLA is false, the 1st argument should be a constant and the same as
+     the size of the LHS.  */
+  if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
+    {
+      tree size_of_arg0 = gimple_call_arg (stmt, 0);
+      tree size_of_lhs = TYPE_SIZE_UNIT (TREE_TYPE (lhs));
+      tree is_vla_node = gimple_call_arg (stmt, 2);
+      bool is_vla = (bool) TREE_INT_CST_LOW (is_vla_node);
+
+      if (TREE_CODE (lhs) == SSA_NAME)
+       lhs = SSA_NAME_VAR (lhs);
+
+      poly_uint64 size_from_arg0, size_from_lhs;
+      bool is_constant_size_arg0 = poly_int_tree_p (size_of_arg0,
+						    &size_from_arg0);
+      bool is_constant_size_lhs = poly_int_tree_p (size_of_lhs,
+						   &size_from_lhs);
+      if (!is_vla)
+	{
+	  if (!is_constant_size_arg0)
+	    {
+	      error ("%<DEFFERED_INIT%> calls for non-VLA should have "
+		     "constant size for the first argument");
+	      return true;
+	    }
+	  else if (!is_constant_size_lhs)
+	    {
+	      error ("%<DEFFERED_INIT%> calls for non-VLA should have "
+		     "constant size for the LHS");
+	      return true;
+	    }
+	  else if (maybe_ne (size_from_arg0, size_from_lhs))
+	    {
+	      error ("%<DEFFERED_INIT%> calls for non-VLA should have same "
+		     "constant size for the first argument and LHS");
+	      return true;
+	    }
+	}
+    }
+
+  /* We will not verify the arguments for the calls to .DEFERRED_INIT.
+     Such call is not a real call, just a placeholder for a later
+     initialization during expand phase.
+     This is mainly to avoid assertion failure for the following
+     case:
+
+     uni_var = .DEFERRED_INIT (var_size, INIT_TYPE, is_vla);
+     foo (&uni_var);
+
+     in the above, the uninitialized auto variable "uni_var" is
+     addressable, therefore should not be in registers, resulting
+     the assertion failure in the following argument verification.  */
+  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
      unit-at-a-time we have a chance to fix this.  */
 
-  for (i = 0; i < gimple_call_num_args (stmt); ++i)
-    {
-      tree arg = gimple_call_arg (stmt, i);
-      if ((is_gimple_reg_type (TREE_TYPE (arg))
-	   && !is_gimple_val (arg))
-	  || (!is_gimple_reg_type (TREE_TYPE (arg))
-	      && !is_gimple_lvalue (arg)))
-	{
-	  error ("invalid argument to gimple call");
-	  debug_generic_expr (arg);
-	  return true;
-	}
-      if (!is_gimple_reg (arg))
-	{
-	  if (TREE_CODE (arg) == WITH_SIZE_EXPR)
-	    arg = TREE_OPERAND (arg, 0);
-	  if (verify_types_in_gimple_reference (arg, false))
+  else
+    for (i = 0; i < gimple_call_num_args (stmt); ++i)
+      {
+	tree arg = gimple_call_arg (stmt, i);
+	if ((is_gimple_reg_type (TREE_TYPE (arg))
+	     && !is_gimple_val (arg))
+	    || (!is_gimple_reg_type (TREE_TYPE (arg))
+		&& !is_gimple_lvalue (arg)))
+	  {
+	    error ("invalid argument to gimple call");
+	    debug_generic_expr (arg);
 	    return true;
-	}
-    }
+	  }
+	if (!is_gimple_reg (arg))
+	  {
+	    if (TREE_CODE (arg) == WITH_SIZE_EXPR)
+	      arg = TREE_OPERAND (arg, 0);
+	    if (verify_types_in_gimple_reference (arg, false))
+	      return true;
+	  }
+      }
 
   return false;
 }
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index c05d22f3e8f1..45c9e916f55a 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
@@ -1388,7 +1395,14 @@ scan_function (void)
 
 	      t = gimple_call_lhs (stmt);
 	      if (t && !disqualify_if_bad_bb_terminating_stmt (stmt, t, NULL))
-		ret |= build_access_from_expr (t, stmt, true);
+		{
+		  /* If the STMT is a call to DEFERRED_INIT, avoid setting
+		     cannot_scalarize_away_bitmap.  */
+		  if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
+		    ret |= !!build_access_from_expr_1 (t, stmt, true);
+		  else
+		    ret |= build_access_from_expr (t, stmt, true);
+		}
 	      break;
 
 	    case GIMPLE_ASM:
@@ -4096,6 +4110,88 @@ 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.
+   GSI is a statement iterator used to place the new statements.  */
+static void
+generate_subtree_deferred_init (struct access *access,
+				tree init_type,
+				tree is_vla,
+				gimple_stmt_iterator *gsi,
+				location_t loc)
+{
+  do
+    {
+      if (access->grp_to_be_replaced)
+	{
+	  tree repl = get_access_replacement (access);
+	  gimple *call
+	    = gimple_build_call_internal (IFN_DEFERRED_INIT, 3,
+					  TYPE_SIZE_UNIT (TREE_TYPE (repl)),
+					  init_type, is_vla);
+	  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++;
+	}
+      if (access->first_child)
+	generate_subtree_deferred_init (access->first_child, init_type,
+					is_vla, gsi, loc);
+
+      access = access ->next_sibling;
+    }
+  while (access);
+}
+
+/* For a call to .DEFERRED_INIT:
+   var = .DEFERRED_INIT (size_of_var, init_type, is_vla);
+   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 statement.  */
+
+static enum assignment_mod_result
+sra_modify_deferred_init (gimple *stmt, gimple_stmt_iterator *gsi)
+{
+  tree lhs = gimple_call_lhs (stmt);
+  tree init_type = gimple_call_arg (stmt, 1);
+  tree is_vla = gimple_call_arg (stmt, 2);
+
+  struct access *lhs_access = get_access_for_expr (lhs);
+  if (!lhs_access)
+    return SRA_AM_NONE;
+
+  location_t loc = gimple_location (stmt);
+
+  if (lhs_access->grp_to_be_replaced)
+    {
+      tree lhs_repl = get_access_replacement (lhs_access);
+      gimple_call_set_lhs (stmt, lhs_repl);
+      tree arg0_repl = TYPE_SIZE_UNIT (TREE_TYPE (lhs_repl));
+      gimple_call_set_arg (stmt, 0, arg0_repl);
+      sra_stats.deferred_init++;
+      gcc_assert (!lhs_access->first_child);
+      return SRA_AM_MODIFIED;
+    }
+
+  if (lhs_access->first_child)
+    generate_subtree_deferred_init (lhs_access->first_child,
+				    init_type, is_vla, gsi, loc);
+  if (lhs_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
@@ -4460,17 +4556,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 71894b38ff92..4e8e0194753d 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -4907,6 +4907,9 @@ 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))
+    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 24ac031a693c..445b739bcd88 100644
--- a/gcc/tree-ssa-uninit.c
+++ b/gcc/tree-ssa-uninit.c
@@ -152,6 +152,42 @@ 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.  This is for handling the following case correctly:
+
+  1 typedef _Complex float C;
+  2 C foo (int cond)
+  3 {
+  4   C f;
+  5   __imag__ f = 0;
+  6   if (cond)
+  7     {
+  8       __real__ f = 1;
+  9       return f;
+ 10     }
+ 11   return f;
+ 12 }
+
+    with -ftrivial-auto-var-init, compiler will insert the following
+    artificial initialization at line 4:
+  f = .DEFERRED_INIT (f, 2);
+  _1 = REALPART_EXPR <f>;
+
+    without the following special handling, _1 = REALPART_EXPR <f> will
+    be treated as the uninitialized use point, which is incorrect. (the
+    real uninitialized use point is at line 11).  */
+  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;
 
@@ -227,6 +263,11 @@ 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 if the definition statement is a call
+     to .DEFERRED_INIT function.  */
+  if (gimple_call_internal_p (def_stmt, IFN_DEFERRED_INIT))
+    return false;
+
   /* The ASAN_MARK intrinsic doesn't modify the variable.  */
   if (is_gimple_call (def_stmt)
       && gimple_call_internal_p (def_stmt, IFN_ASAN_MARK))
@@ -642,6 +683,12 @@ warn_uninitialized_vars (bool wmaybe_uninit)
 	  ssa_op_iter op_iter;
 	  tree use;
 
+	  /* The call is an artificial use, will not provide meaningful
+	     error message.  If the result of the call is used somewhere
+	     else, we warn there instead.  */
+	  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 4cc400d3c2eb..0fba404babe9 100644
--- a/gcc/tree-ssa.c
+++ b/gcc/tree-ssa.c
@@ -1325,6 +1325,46 @@ ssa_undefined_value_p (tree t, bool partial)
   if (gimple_nop_p (def_stmt))
     return true;
 
+  /* The value is undefined if the definition statement is a call
+     to .DEFERRED_INIT function.  */
+  if (gimple_call_internal_p (def_stmt, IFN_DEFERRED_INIT))
+    return true;
+
+  /* The value is partially undefined if the definition statement is
+     a REALPART_EXPR or IMAGPART_EXPR and its operand is defined by
+     the call to .DEFERRED_INIT function.  This is for handling the
+     following case:
+
+  1 typedef _Complex float C;
+  2 C foo (int cond)
+  3 {
+  4   C f;
+  5   __imag__ f = 0;
+  6   if (cond)
+  7     {
+  8       __real__ f = 1;
+  9       return f;
+ 10     }
+ 11   return f;
+ 12 }
+
+    with -ftrivial-auto-var-init, compiler will insert the following
+    artificial initialization:
+  f = .DEFERRED_INIT (f, 2);
+  _1 = REALPART_EXPR <f>;
+
+    we should treat the definition _1 = REALPART_EXPR <f> as undefined.  */
+  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)
-- 
2.27.0


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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-07-27  3:26 [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc Qing Zhao
@ 2021-07-28 20:21 ` Kees Cook
  2021-07-28 21:53   ` Qing Zhao
  2021-08-09 14:09 ` Richard Biener
  1 sibling, 1 reply; 60+ messages in thread
From: Kees Cook @ 2021-07-28 20:21 UTC (permalink / raw)
  To: Qing Zhao
  Cc: Richard Biener, Martin Jambor, Jakub Jelinek,
	Nick Alcock via Gcc-patches, Richard Biener

On Tue, Jul 27, 2021 at 03:26:00AM +0000, Qing Zhao wrote:
> This is the 6th version of the patch for the new security feature for GCC.
> 
> I have tested it with bootstrap on both x86 and aarch64, regression testing on both x86 and aarch64.
> Also compile CPU2017 (running is ongoing), without any issue. (With the fix to bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101586).
> 
> Please take a look and let me know any issue.

Good news, this passes all my initialization tests in the kernel. Yay! :)

However, I see an unexpected side-effect from some static initializations:

net/core/sock.c: In function 'sock_no_sendpage':
net/core/sock.c:2849:23: warning: 'msg' is used uninitialized [-Wuninitialized]
 2849 |         struct msghdr msg = {.msg_flags = flags};
      |                       ^~~           

It seems like -Wuninitialized has suddenly stopped noticing explicit
static initializers when there are bit fields in the struct. Here's a
minimized case:

$ cat init.c
struct weird {
        int bit : 1;
        int val;
};

int func(int val)
{
        struct weird obj = { .val = val };
        return obj.val;
}

$ gcc -c -o init.o -Wall -O2 -ftrivial-auto-var-init=zero init.c
init.c: In function ‘func’:
init.c:8:22: warning: ‘obj’ is used uninitialized [-Wuninitialized]
    8 |         struct weird obj = { .val = val };
      |                      ^~~
init.c:8:22: note: ‘obj’ declared here
    8 |         struct weird obj = { .val = val };
      |                      ^~~



-- 
Kees Cook

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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-07-28 20:21 ` Kees Cook
@ 2021-07-28 21:53   ` Qing Zhao
  0 siblings, 0 replies; 60+ messages in thread
From: Qing Zhao @ 2021-07-28 21:53 UTC (permalink / raw)
  To: Kees Cook
  Cc: Richard Biener, Martin Jambor, Jakub Jelinek,
	Nick Alcock via Gcc-patches, Richard Biener

Hi, Kees,

Thanks a lot for your testing and the small testing case.

I just studied the root cause of this bug, and found that it’s because the call to “__builtin_clear_padding()” should NOT be inserted BEFORE
the variable initialization. It should be inserted AFTER the variable initialization. 

Currently since the call to “__builtin_clear_padding()” is inserted Before the variable initialization like the following:

      __builtin_clear_padding (&obj, 0B, 1);
      obj = {};
      obj.val = val;

Then as a result, the reference to “obj” in the call to “__builtin_clear_padding” is considered as an uninitialized usage.  
I will move the call to __builtin_clear_padding after the variable initialization. 

Thanks.

Qing

> On Jul 28, 2021, at 3:21 PM, Kees Cook <keescook@chromium.org> wrote:
> 
> On Tue, Jul 27, 2021 at 03:26:00AM +0000, Qing Zhao wrote:
>> This is the 6th version of the patch for the new security feature for GCC.
>> 
>> I have tested it with bootstrap on both x86 and aarch64, regression testing on both x86 and aarch64.
>> Also compile CPU2017 (running is ongoing), without any issue. (With the fix to bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101586).
>> 
>> Please take a look and let me know any issue.
> 
> Good news, this passes all my initialization tests in the kernel. Yay! :)
> 
> However, I see an unexpected side-effect from some static initializations:
> 
> net/core/sock.c: In function 'sock_no_sendpage':
> net/core/sock.c:2849:23: warning: 'msg' is used uninitialized [-Wuninitialized]
> 2849 |         struct msghdr msg = {.msg_flags = flags};
>      |                       ^~~           
> 
> It seems like -Wuninitialized has suddenly stopped noticing explicit
> static initializers when there are bit fields in the struct. Here's a
> minimized case:
> 
> $ cat init.c
> struct weird {
>        int bit : 1;
>        int val;
> };
> 
> int func(int val)
> {
>        struct weird obj = { .val = val };
>        return obj.val;
> }
> 
> $ gcc -c -o init.o -Wall -O2 -ftrivial-auto-var-init=zero init.c
> init.c: In function ‘func’:
> init.c:8:22: warning: ‘obj’ is used uninitialized [-Wuninitialized]
>    8 |         struct weird obj = { .val = val };
>      |                      ^~~
> init.c:8:22: note: ‘obj’ declared here
>    8 |         struct weird obj = { .val = val };
>      |                      ^~~
> 
> 
> 
> -- 
> Kees Cook


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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-07-27  3:26 [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc Qing Zhao
  2021-07-28 20:21 ` Kees Cook
@ 2021-08-09 14:09 ` Richard Biener
  2021-08-09 16:38   ` Qing Zhao
  2021-08-12 19:24   ` Qing Zhao
  1 sibling, 2 replies; 60+ messages in thread
From: Richard Biener @ 2021-08-09 14:09 UTC (permalink / raw)
  To: Qing Zhao
  Cc: Martin Jambor, Jakub Jelinek, Kees Cook,
	Nick Alcock via Gcc-patches, Richard Biener

On Tue, 27 Jul 2021, Qing Zhao wrote:

> Hi,
> 
> This is the 6th version of the patch for the new security feature for GCC.
> 
> I have tested it with bootstrap on both x86 and aarch64, regression testing on both x86 and aarch64.
> Also compile CPU2017 (running is ongoing), without any issue. (With the fix to bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101586).
> 
> Please take a look and let me know any issue.

+/* Handle an "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))
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }

you are documenting this attribute for automatic variables but
here you allow placement on globals as well (not sure if at this
point TREE_STATIC / DECL_EXTERNAL are set correctly).

+  /* for languages that do not support BUILT_IN_CLEAR_PADDING, create the
+     function node for padding initialization.  */
+  if (!fn)
+    {
+      tree ftype = build_function_type_list (void_type_node,
+                                            ptr_type_node,

the "appropriate" place to do this would be 
tree.c:build_common_builtin_nodes

You seem to marshall the is_vla argument as for_auto_init when
expanding/folding the builtin and there it's used to suppress
diagnostics (and make covered pieces not initialized?).  I suggest
to re-name is_vla/for_auto_init to something more descriptive.

+   gimple_fold_builtin_clear_padding. If FOR_AUTO_INIT,
+   not emit some of the error messages since doing that
+   might confuse the end user.  */

doesn't explain to me whether errors still might be raised or
what the actual behavior is.

+static gimple *
+build_deferred_init (tree decl,
+                    enum auto_init_type init_type,
+                    bool is_vla)
+{
+  gcc_assert ((is_vla && TREE_CODE (decl) == WITH_SIZE_EXPR)
+             || (!is_vla && TREE_CODE (decl) != WITH_SIZE_EXPR));

so the is_vla parameter looks redundant (and the assert dangerous?).
Either the caller knows it deals with a VLA, then that should be
passed through - constant sizes can also later appear during
optimization after all - or is_vla should be determined here
based on whether the size at gimplification time is constant.

+         /* If the user requests to initialize automatic variables, we
+            should initialize paddings inside the variable. Add a call to
+            __BUILTIN_CLEAR_PADDING (&object, 0, for_auto_init = true) to
+            initialize paddings of object always to zero regardless of
+            INIT_TYPE.  */
+         if (opt_for_fn (current_function_decl, flag_auto_var_init)
+               > AUTO_INIT_UNINITIALIZED
+             && VAR_P (object)
+             && !DECL_EXTERNAL (object)
+             && !TREE_STATIC (object))
+           gimple_add_padding_init_for_auto_var (object, false, pre_p);
+         return ret;

I think you want to use either auto_var_p (object) or
auto_var_in_fn_p (object, current_function_decl).  Don't you also
want to check for the 'uninitialized' attribute here?  I suggest
to abstract the check on whether 'object' should be subject
to autoinit to a helper function.

There's another path above this calling gimplify_init_constructor
for the case of

 const struct S x = { ... };
 struct S y = x;

where it will try to init 'y' from the CTOR directly, it seems you
do not cover this case.  I also think that the above place applies
to all aggregate assignment statements, not only to INIT_EXPRs?
So don't you want to restrict clear-padding emit here?

+static void
+expand_DEFERRED_INIT (internal_fn, gcall *stmt)
+{
+  tree var = gimple_call_lhs (stmt);
+  tree size_of_var = gimple_call_arg (stmt, 0);
+  tree vlaaddr = NULL_TREE;
+  tree var_type = TREE_TYPE (var);
+  bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
+  enum auto_init_type init_type
+    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
+
+  gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
+
+  /* if this variable is a VLA, get its SIZE and ADDR first.  */
+  if (is_vla)
+    {
+      /* The temporary address variable for this vla should have been
+        created during gimplification phase.  Refer to gimplify_vla_decl
+        for details.  */
+      tree var_decl = (TREE_CODE (var) == SSA_NAME) ?
+                      SSA_NAME_VAR (var) : var;
+      gcc_assert (DECL_HAS_VALUE_EXPR_P (var_decl));
+      gcc_assert (TREE_CODE (DECL_VALUE_EXPR (var_decl)) == 
INDIRECT_REF);
+      /* Get the address of this vla variable.  */
+      vlaaddr = TREE_OPERAND (DECL_VALUE_EXPR (var_decl), 0);

err - isn't the address of the decl represented by the LHS 
regardless whether this is a VLA or not?  Looking at DECL_VALUE_EXPR
looks quite fragile since that's not sth data dependence honors.
It looks you only partly gimplify the build init here?  All
DECL_VALUE_EXPRs should have been resolved.

+  if (is_vla || (!use_register_for_decl (var)))
...
+  else
+    {
+    /* If this variable is in a register, use expand_assignment might
+       generate better code.  */

you compute the patter initializer even when not needing it,
that's wasteful.  It's also quite ugly, IMHO you should
use can_native_interpret_type_p (var_type) and native_interpret
a char [] array initialized to the pattern and if
!can_native_interpret_type_p () go the memset route.

+  /* We will not verify the arguments for the calls to .DEFERRED_INIT.
+     Such call is not a real call, just a placeholder for a later
+     initialization during expand phase.
+     This is mainly to avoid assertion failure for the following
+     case:
+
+     uni_var = .DEFERRED_INIT (var_size, INIT_TYPE, is_vla);
+     foo (&uni_var);
+
+     in the above, the uninitialized auto variable "uni_var" is
+     addressable, therefore should not be in registers, resulting
+     the assertion failure in the following argument verification.  */
+  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
      unit-at-a-time we have a chance to fix this.  */

-  for (i = 0; i < gimple_call_num_args (stmt); ++i)

isn't that from the time there was a decl argument to .DEFERRED_INIT?

+  if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
+    {
+      tree size_of_arg0 = gimple_call_arg (stmt, 0);
+      tree size_of_lhs = TYPE_SIZE_UNIT (TREE_TYPE (lhs));
+      tree is_vla_node = gimple_call_arg (stmt, 2);
+      bool is_vla = (bool) TREE_INT_CST_LOW (is_vla_node);
+
+      if (TREE_CODE (lhs) == SSA_NAME)
+       lhs = SSA_NAME_VAR (lhs);
+

'lhs' is not looked at after this, no need to look at SSA_NAME_VAR.


Thanks and sorry for the delay in reviewing this (again).

Richard.


> Thanks
> 
> Qing
> 
> ******Compared with the 5th version, the changes are:
> 
>  1. Fix two issues raised by Martin Jambor in tree-sra.c:
> 
>    A. Inside "scan_function", Do not set cannot_scalarize_away_bitmap for a call to DEFERRED_INIT.
>    B. Fix a potential issue for single-field structure.
> 
>  2. Add two testing cases based on gcc/testsuite/gcc.dg/tree-ssa/sra-12.c to verity SRA total scalarization will not be confused by auto initializatoin.
> 
> ******the 5th version compared with the 4th version, the following are the major changes:
> 
> 1. delete the code for handling "grp_to_be_debug_replaced" since they are not needed per Martin Jambor's suggestion.
> 2. for Pattern init, call __builtin_clear_padding after the call to .DEFERRED_INIT to initialize the paddings to zeroes;
> 3. for partially or fully initialized auto variables, call   __builtin_clear_padding before the real initialization to initialize
>    the paddings to zeroes.
> 4. Update the documentation with padding initialization to zeroes.
> 5. in order to reuse __builtin_clear_padding for auto init purpose, add one more dummy argument to indiciate whether it's for auto init or not,
>   if for auto init, do not emit error messages to avoid confusing users.
> 6. Add new testing cases to verify padding initializations.
> 7. rename some of the old testing cases to make the file name reflecting the testing purpose per Kees Cook's suggestions.
> 
> ******Please see version 5 at:
> https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575977.html
> 
> ******ChangeLog is:
> 
> gcc/ChangeLog:
> 
> 2021-07-26  qing zhao  <qing.zhao@oracle.com>
> 
>         * builtins.c (expand_builtin_memset): Make external visible.
>         * builtins.h (expand_builtin_memset): Declare extern.
>         * common.opt (ftrivial-auto-var-init=): New option.
>         * doc/extend.texi: Document the uninitialized attribute.
>         * doc/invoke.texi: Document -ftrivial-auto-var-init.
>         * flag-types.h (enum auto_init_type): New enumerated type
>         auto_init_type.
>         * gimple-fold.c (clear_padding_type): Add one new parameter.
>         (clear_padding_union): Likewise.
>         (clear_padding_emit_loop): Likewise.
>         (clear_type_padding_in_mask): Likewise.
>         (gimple_fold_builtin_clear_padding): Handle this new parameter.
>         * gimplify.c (gimple_add_init_for_auto_var): New function.
>         (maybe_with_size_expr): Forword declaration.
>         (build_deferred_init): New function.
>         (gimple_add_padding_init_for_auto_var): New function.
>         (gimplify_decl_expr): Add initialization to automatic variables per
>         users' requests.
>         (gimplify_call_expr): Add one new parameter for call to
>         __builtin_clear_padding.
>         (gimplify_modify_expr_rhs): Add padding initialization before
>         gimplify_init_constructor.
>         * internal-fn.c (INIT_PATTERN_VALUE): New macro.
>         (expand_DEFERRED_INIT): New function.
>         * internal-fn.def (DEFERRED_INIT): New internal function.
>         * tree-cfg.c (verify_gimple_call): Verify calls to .DEFERRED_INIT.
>         * tree-sra.c (generate_subtree_deferred_init): New function.
>         (scan_function): Avoid setting cannot_scalarize_away_bitmap for
>         calls to .DEFERRED_INIT.
>         (sra_modify_deferred_init): New function.
>         (sra_modify_function_body): Handle calls to DEFERRED_INIT specially.
>         * tree-ssa-structalias.c (find_func_aliases_for_call): Likewise.
>         * tree-ssa-uninit.c (warn_uninit): Handle calls to DEFERRED_INIT
>         specially.
>         (check_defs): Likewise.
>         (warn_uninitialized_vars): Likewise.
>         * tree-ssa.c (ssa_undefined_value_p): Likewise.
> 
> gcc/c-family/ChangeLog:
> 
> 2021-07-26  qing zhao  <qing.zhao@oracle.com>
> 
>         * c-attribs.c (handle_uninitialized_attribute): New function.
>         (c_common_attribute_table): Add "uninitialized" attribute.
> 
> gcc/testsuite/ChangeLog:
> 
> 
> 2021-07-26  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-15.c: New test.
>         * c-c++-common/auto-init-16.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.
>         * c-c++-common/auto-init-padding-1.c: New test.
>         * c-c++-common/auto-init-padding-2.c: New test.
>         * c-c++-common/auto-init-padding-3.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-sra-1.c: New test.
>         * gcc.dg/auto-init-sra-2.c: 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-2.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-padding-1.c: New test.
>         * gcc.target/aarch64/auto-init-padding-10.c: New test.
>         * gcc.target/aarch64/auto-init-padding-11.c: New test.
>         * gcc.target/aarch64/auto-init-padding-12.c: New test.
>         * gcc.target/aarch64/auto-init-padding-2.c: New test.
>         * gcc.target/aarch64/auto-init-padding-3.c: New test.
>         * gcc.target/aarch64/auto-init-padding-4.c: New test.
>         * gcc.target/aarch64/auto-init-padding-5.c: New test.
>         * gcc.target/aarch64/auto-init-padding-6.c: New test.
>         * gcc.target/aarch64/auto-init-padding-7.c: New test.
>         * gcc.target/aarch64/auto-init-padding-8.c: New test.
>         * gcc.target/aarch64/auto-init-padding-9.c: New test.
>         * gcc.target/i386/auto-init-1.c: New test.
>         * gcc.target/i386/auto-init-2.c: New test.
>         * gcc.target/i386/auto-init-21.c: New test.
>         * gcc.target/i386/auto-init-22.c: New test.
>         * gcc.target/i386/auto-init-23.c: New test.
>         * gcc.target/i386/auto-init-24.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-padding-1.c: New test.
>         * gcc.target/i386/auto-init-padding-10.c: New test.
>         * gcc.target/i386/auto-init-padding-11.c: New test.
>         * gcc.target/i386/auto-init-padding-12.c: New test.
>         * gcc.target/i386/auto-init-padding-2.c: New test.
>         * gcc.target/i386/auto-init-padding-3.c: New test.
>         * gcc.target/i386/auto-init-padding-4.c: New test.
>         * gcc.target/i386/auto-init-padding-5.c: New test.
>         * gcc.target/i386/auto-init-padding-6.c: New test.
>         * gcc.target/i386/auto-init-padding-7.c: New test.
>         * gcc.target/i386/auto-init-padding-8.c: New test.
>         * gcc.target/i386/auto-init-padding-9.c: New test.
> 
> ******The complete 6th version of the patch is:
> 
> 
> 

-- 
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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-09 14:09 ` Richard Biener
@ 2021-08-09 16:38   ` Qing Zhao
  2021-08-09 17:14     ` Richard Biener
  2021-08-10  7:36     ` Richard Biener
  2021-08-12 19:24   ` Qing Zhao
  1 sibling, 2 replies; 60+ messages in thread
From: Qing Zhao @ 2021-08-09 16:38 UTC (permalink / raw)
  To: Richard Biener
  Cc: Martin Jambor, Jakub Jelinek, Kees Cook,
	Nick Alcock via Gcc-patches, Richard Biener

Hi, Richard,

Thanks a lot for you review.

Although these comments are not made on the latest patch (7th version) :-), all the comments are valid since the parts you commented
are not changed in the 7th version.


> On Aug 9, 2021, at 9:09 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Tue, 27 Jul 2021, Qing Zhao wrote:
> 
>> Hi,
>> 
>> This is the 6th version of the patch for the new security feature for GCC.
>> 
>> I have tested it with bootstrap on both x86 and aarch64, regression testing on both x86 and aarch64.
>> Also compile CPU2017 (running is ongoing), without any issue. (With the fix to bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101586).
>> 
>> Please take a look and let me know any issue.
> 
> +/* Handle an "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))
> +    {
> +      warning (OPT_Wattributes, "%qE attribute ignored", name);
> +      *no_add_attrs = true;
> +    }
> 
> you are documenting this attribute for automatic variables but
> here you allow placement on globals as well (not sure if at this
> point TREE_STATIC / DECL_EXTERNAL are set correctly).

Right, I should warn when the attribute is placed for globals or static variables. 
I will try TREE_STATIC/DECL_EXTERNAL to see whether it’s work or not.

> 
> +  /* for languages that do not support BUILT_IN_CLEAR_PADDING, create the
> +     function node for padding initialization.  */
> +  if (!fn)
> +    {
> +      tree ftype = build_function_type_list (void_type_node,
> +                                            ptr_type_node,
> 
> the "appropriate" place to do this would be 
> tree.c:build_common_builtin_nodes

Sure, will move the creation of  function node of BUILT_IN_CLEAR_PADDING for Fortran etc. to tree.c:build_common_builtin_nodes.

> 
> You seem to marshall the is_vla argument as for_auto_init when
> expanding/folding the builtin and there it's used to suppress
> diagnostics (and make covered pieces not initialized?).

Yes, I added an extra argument “for_auto_init” for “BUILT_IN_CLEAR_PADDING”, this argument is added to suppress errors emitted during folding
BUILT_IN_CLEAR_PADDING for flexible array member . Such errors should Not be emitted when “BUILT_IN_CLEAR_PADDING” is called with compiler automatic initialization.
Please see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101586, comment #6 from Jakub Jelinek.

>  I suggest
> to re-name is_vla/for_auto_init to something more descriptive.

Okay, I will. 
> 
> +   gimple_fold_builtin_clear_padding. If FOR_AUTO_INIT,
> +   not emit some of the error messages since doing that
> +   might confuse the end user.  */
> 
> doesn't explain to me whether errors still might be raised or
> what the actual behavior is.

Okay, will make this more clear in the comments.

> 
> +static gimple *
> +build_deferred_init (tree decl,
> +                    enum auto_init_type init_type,
> +                    bool is_vla)
> +{
> +  gcc_assert ((is_vla && TREE_CODE (decl) == WITH_SIZE_EXPR)
> +             || (!is_vla && TREE_CODE (decl) != WITH_SIZE_EXPR));
> 
> so the is_vla parameter looks redundant (and the assert dangerous?).
> Either the caller knows it deals with a VLA, then that should be
> passed through - constant sizes can also later appear during
> optimization after all - or is_vla should be determined here
> based on whether the size at gimplification time is constant.

The routine “build_deferred_init” is ONLY called during gimplification phase by the routine “gimple_add_init_for_auto_var", at this place,
Is_vla should be determined by the caller to check the size of the DECL. If it’s a vla, the “maybe_with_size_expr” will be applied for
DECL to make it to a WITH_SIZE_EXPR.  So, the assertion is purely to make sure this at gimplification phase.

Yes, the size of the VLA decl might become a constant later due to constant propagation, etc.  but during the gimplification phase, the assertion should be true.
> 
> +         /* If the user requests to initialize automatic variables, we
> +            should initialize paddings inside the variable. Add a call to
> +            __BUILTIN_CLEAR_PADDING (&object, 0, for_auto_init = true) to
> +            initialize paddings of object always to zero regardless of
> +            INIT_TYPE.  */
> +         if (opt_for_fn (current_function_decl, flag_auto_var_init)
> +               > AUTO_INIT_UNINITIALIZED
> +             && VAR_P (object)
> +             && !DECL_EXTERNAL (object)
> +             && !TREE_STATIC (object))
> +           gimple_add_padding_init_for_auto_var (object, false, pre_p);
> +         return ret;
> 
> I think you want to use either auto_var_p (object) or
> auto_var_in_fn_p (object, current_function_decl).  Don't you also
> want to check for the 'uninitialized' attribute here?  I suggest
> to abstract the check on whether 'object' should be subject
> to autoinit to a helper function.

Thanks for the suggestion, I will do this.


> 
> There's another path above this calling gimplify_init_constructor
> for the case of
> 
> const struct S x = { ... };
> struct S y = x;
> 
> where it will try to init 'y' from the CTOR directly, it seems you
> do not cover this case.

Yes, you are right, this case was not covered right now, and this should be covered.

Looks like that I need to move the “gimple_add_padding_init_for_auto_var” inside the routine “gimplify_init_constructor” to
Cover all the cases. 

>  I also think that the above place applies
> to all aggregate assignment statements, not only to INIT_EXPRs?

> So don't you want to restrict clear-padding emit here?

You are right, I might need to restrict it Only to INIT_EXPR. 
Will update.

> 
> +static void
> +expand_DEFERRED_INIT (internal_fn, gcall *stmt)
> +{
> +  tree var = gimple_call_lhs (stmt);
> +  tree size_of_var = gimple_call_arg (stmt, 0);
> +  tree vlaaddr = NULL_TREE;
> +  tree var_type = TREE_TYPE (var);
> +  bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
> +  enum auto_init_type init_type
> +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
> +
> +  gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
> +
> +  /* if this variable is a VLA, get its SIZE and ADDR first.  */
> +  if (is_vla)
> +    {
> +      /* The temporary address variable for this vla should have been
> +        created during gimplification phase.  Refer to gimplify_vla_decl
> +        for details.  */
> +      tree var_decl = (TREE_CODE (var) == SSA_NAME) ?
> +                      SSA_NAME_VAR (var) : var;
> +      gcc_assert (DECL_HAS_VALUE_EXPR_P (var_decl));
> +      gcc_assert (TREE_CODE (DECL_VALUE_EXPR (var_decl)) == 
> INDIRECT_REF);
> +      /* Get the address of this vla variable.  */
> +      vlaaddr = TREE_OPERAND (DECL_VALUE_EXPR (var_decl), 0);
> 
> err - isn't the address of the decl represented by the LHS 
> regardless whether this is a VLA or not?

The LHS of the call to .DEFERRED_INIT is the DECL itself whatever it’s a VLA or not. 

In order to create a memset call, we need the Address of this DECL as the first argument. 
If the DECL is not a VLA, we just simply apply “build_fold_addr_expr” on this DECL to get its address,
However, for VLA, during gimplification phase “gimplify_vla_decl”, we have already created a temporary
address variable for this DECL, and recorded this address variable with “DECL_VALUE_EXPR(DECL), 
We should use this already created address variable  for VLAs. 


>  Looking at DECL_VALUE_EXPR
> looks quite fragile since that's not sth data dependence honors.
> It looks you only partly gimplify the build init here?  All
> DECL_VALUE_EXPRs should have been resolved.

Don’t quite understand here. you mean that all the “DECL_VALUE_EXPRs” have been resolved at the phase RTL expansion,
So I cannot use this to get the address variable of the VLA?

(However, my unit testing cases for VLAs are all looks fine).

> 
> +  if (is_vla || (!use_register_for_decl (var)))
> ...
> +  else
> +    {
> +    /* If this variable is in a register, use expand_assignment might
> +       generate better code.  */
> 
> you compute the patter initializer even when not needing it,
> that's wasteful.

Okay, I will restrict the pattern initializer computation when really needed. 

>  It's also quite ugly, IMHO you should
> use can_native_interpret_type_p (var_type) and native_interpret
> a char [] array initialized to the pattern and if
> !can_native_interpret_type_p () go the memset route.

Thanks for the suggestion. 

Will try this. 

> 
> +  /* We will not verify the arguments for the calls to .DEFERRED_INIT.
> +     Such call is not a real call, just a placeholder for a later
> +     initialization during expand phase.
> +     This is mainly to avoid assertion failure for the following
> +     case:
> +
> +     uni_var = .DEFERRED_INIT (var_size, INIT_TYPE, is_vla);
> +     foo (&uni_var);
> +
> +     in the above, the uninitialized auto variable "uni_var" is
> +     addressable, therefore should not be in registers, resulting
> +     the assertion failure in the following argument verification.  */
> +  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
>      unit-at-a-time we have a chance to fix this.  */
> 
> -  for (i = 0; i < gimple_call_num_args (stmt); ++i)
> 
> isn't that from the time there was a decl argument to .DEFERRED_INIT?

You mean this issue is only there when the decl is the first argument (the old design for .DEFERRED_INIT).
With the new design, this issue is not there anymore?

> 
> +  if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
> +    {
> +      tree size_of_arg0 = gimple_call_arg (stmt, 0);
> +      tree size_of_lhs = TYPE_SIZE_UNIT (TREE_TYPE (lhs));
> +      tree is_vla_node = gimple_call_arg (stmt, 2);
> +      bool is_vla = (bool) TREE_INT_CST_LOW (is_vla_node);
> +
> +      if (TREE_CODE (lhs) == SSA_NAME)
> +       lhs = SSA_NAME_VAR (lhs);
> +
> 
> 'lhs' is not looked at after this, no need to look at SSA_NAME_VAR.

Okay, will update this.

> 
> 
> Thanks and sorry for the delay in reviewing this (again).

Thanks again for your detailed review and suggestions.

I will update the patch accordingly and send the updated patch soon.

Qing
> 
> Richard.
> 
> 
>> Thanks
>> 


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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-09 16:38   ` Qing Zhao
@ 2021-08-09 17:14     ` Richard Biener
  2021-08-10  7:36     ` Richard Biener
  1 sibling, 0 replies; 60+ messages in thread
From: Richard Biener @ 2021-08-09 17:14 UTC (permalink / raw)
  To: Qing Zhao
  Cc: Martin Jambor, Jakub Jelinek, Kees Cook,
	Nick Alcock via Gcc-patches, Richard Biener

On August 9, 2021 6:38:21 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>Hi, Richard,
>
>Thanks a lot for you review.
>
>Although these comments are not made on the latest patch (7th version) :-), all the comments are valid since the parts you commented
>are not changed in the 7th version.

I actually reviewed the 7th patch, just appearantly picked the wrong mail to reply to... 

>
>> On Aug 9, 2021, at 9:09 AM, Richard Biener <rguenther@suse.de> wrote:
>> 
>> On Tue, 27 Jul 2021, Qing Zhao wrote:
>> 
>>> Hi,
>>> 
>>> This is the 6th version of the patch for the new security feature for GCC.
>>> 
>>> I have tested it with bootstrap on both x86 and aarch64, regression testing on both x86 and aarch64.
>>> Also compile CPU2017 (running is ongoing), without any issue. (With the fix to bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101586).
>>> 
>>> Please take a look and let me know any issue.
>> 
>> +/* Handle an "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))
>> +    {
>> +      warning (OPT_Wattributes, "%qE attribute ignored", name);
>> +      *no_add_attrs = true;
>> +    }
>> 
>> you are documenting this attribute for automatic variables but
>> here you allow placement on globals as well (not sure if at this
>> point TREE_STATIC / DECL_EXTERNAL are set correctly).
>
>Right, I should warn when the attribute is placed for globals or static variables. 
>I will try TREE_STATIC/DECL_EXTERNAL to see whether it’s work or not.
>
>> 
>> +  /* for languages that do not support BUILT_IN_CLEAR_PADDING, create the
>> +     function node for padding initialization.  */
>> +  if (!fn)
>> +    {
>> +      tree ftype = build_function_type_list (void_type_node,
>> +                                            ptr_type_node,
>> 
>> the "appropriate" place to do this would be 
>> tree.c:build_common_builtin_nodes
>
>Sure, will move the creation of  function node of BUILT_IN_CLEAR_PADDING for Fortran etc. to tree.c:build_common_builtin_nodes.
>
>> 
>> You seem to marshall the is_vla argument as for_auto_init when
>> expanding/folding the builtin and there it's used to suppress
>> diagnostics (and make covered pieces not initialized?).
>
>Yes, I added an extra argument “for_auto_init” for “BUILT_IN_CLEAR_PADDING”, this argument is added to suppress errors emitted during folding
>BUILT_IN_CLEAR_PADDING for flexible array member . Such errors should Not be emitted when “BUILT_IN_CLEAR_PADDING” is called with compiler automatic initialization.
>Please see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101586, comment #6 from Jakub Jelinek.
>
>>  I suggest
>> to re-name is_vla/for_auto_init to something more descriptive.
>
>Okay, I will. 
>> 
>> +   gimple_fold_builtin_clear_padding. If FOR_AUTO_INIT,
>> +   not emit some of the error messages since doing that
>> +   might confuse the end user.  */
>> 
>> doesn't explain to me whether errors still might be raised or
>> what the actual behavior is.
>
>Okay, will make this more clear in the comments.
>
>> 
>> +static gimple *
>> +build_deferred_init (tree decl,
>> +                    enum auto_init_type init_type,
>> +                    bool is_vla)
>> +{
>> +  gcc_assert ((is_vla && TREE_CODE (decl) == WITH_SIZE_EXPR)
>> +             || (!is_vla && TREE_CODE (decl) != WITH_SIZE_EXPR));
>> 
>> so the is_vla parameter looks redundant (and the assert dangerous?).
>> Either the caller knows it deals with a VLA, then that should be
>> passed through - constant sizes can also later appear during
>> optimization after all - or is_vla should be determined here
>> based on whether the size at gimplification time is constant.
>
>The routine “build_deferred_init” is ONLY called during gimplification phase by the routine “gimple_add_init_for_auto_var", at this place,
>Is_vla should be determined by the caller to check the size of the DECL. If it’s a vla, the “maybe_with_size_expr” will be applied for
>DECL to make it to a WITH_SIZE_EXPR.  So, the assertion is purely to make sure this at gimplification phase.
>
>Yes, the size of the VLA decl might become a constant later due to constant propagation, etc.  but during the gimplification phase, the assertion should be true.
>> 
>> +         /* If the user requests to initialize automatic variables, we
>> +            should initialize paddings inside the variable. Add a call to
>> +            __BUILTIN_CLEAR_PADDING (&object, 0, for_auto_init = true) to
>> +            initialize paddings of object always to zero regardless of
>> +            INIT_TYPE.  */
>> +         if (opt_for_fn (current_function_decl, flag_auto_var_init)
>> +               > AUTO_INIT_UNINITIALIZED
>> +             && VAR_P (object)
>> +             && !DECL_EXTERNAL (object)
>> +             && !TREE_STATIC (object))
>> +           gimple_add_padding_init_for_auto_var (object, false, pre_p);
>> +         return ret;
>> 
>> I think you want to use either auto_var_p (object) or
>> auto_var_in_fn_p (object, current_function_decl).  Don't you also
>> want to check for the 'uninitialized' attribute here?  I suggest
>> to abstract the check on whether 'object' should be subject
>> to autoinit to a helper function.
>
>Thanks for the suggestion, I will do this.
>
>
>> 
>> There's another path above this calling gimplify_init_constructor
>> for the case of
>> 
>> const struct S x = { ... };
>> struct S y = x;
>> 
>> where it will try to init 'y' from the CTOR directly, it seems you
>> do not cover this case.
>
>Yes, you are right, this case was not covered right now, and this should be covered.
>
>Looks like that I need to move the “gimple_add_padding_init_for_auto_var” inside the routine “gimplify_init_constructor” to
>Cover all the cases. 
>
>>  I also think that the above place applies
>> to all aggregate assignment statements, not only to INIT_EXPRs?
>
>> So don't you want to restrict clear-padding emit here?
>
>You are right, I might need to restrict it Only to INIT_EXPR. 
>Will update.
>
>> 
>> +static void
>> +expand_DEFERRED_INIT (internal_fn, gcall *stmt)
>> +{
>> +  tree var = gimple_call_lhs (stmt);
>> +  tree size_of_var = gimple_call_arg (stmt, 0);
>> +  tree vlaaddr = NULL_TREE;
>> +  tree var_type = TREE_TYPE (var);
>> +  bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
>> +  enum auto_init_type init_type
>> +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
>> +
>> +  gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>> +
>> +  /* if this variable is a VLA, get its SIZE and ADDR first.  */
>> +  if (is_vla)
>> +    {
>> +      /* The temporary address variable for this vla should have been
>> +        created during gimplification phase.  Refer to gimplify_vla_decl
>> +        for details.  */
>> +      tree var_decl = (TREE_CODE (var) == SSA_NAME) ?
>> +                      SSA_NAME_VAR (var) : var;
>> +      gcc_assert (DECL_HAS_VALUE_EXPR_P (var_decl));
>> +      gcc_assert (TREE_CODE (DECL_VALUE_EXPR (var_decl)) == 
>> INDIRECT_REF);
>> +      /* Get the address of this vla variable.  */
>> +      vlaaddr = TREE_OPERAND (DECL_VALUE_EXPR (var_decl), 0);
>> 
>> err - isn't the address of the decl represented by the LHS 
>> regardless whether this is a VLA or not?
>
>The LHS of the call to .DEFERRED_INIT is the DECL itself whatever it’s a VLA or not. 
>
>In order to create a memset call, we need the Address of this DECL as the first argument. 
>If the DECL is not a VLA, we just simply apply “build_fold_addr_expr” on this DECL to get its address,
>However, for VLA, during gimplification phase “gimplify_vla_decl”, we have already created a temporary
>address variable for this DECL, and recorded this address variable with “DECL_VALUE_EXPR(DECL), 
>We should use this already created address variable  for VLAs. 
>
>
>>  Looking at DECL_VALUE_EXPR
>> looks quite fragile since that's not sth data dependence honors.
>> It looks you only partly gimplify the build init here?  All
>> DECL_VALUE_EXPRs should have been resolved.
>
>Don’t quite understand here. you mean that all the “DECL_VALUE_EXPRs” have been resolved at the phase RTL expansion,
>So I cannot use this to get the address variable of the VLA?
>
>(However, my unit testing cases for VLAs are all looks fine).
>
>> 
>> +  if (is_vla || (!use_register_for_decl (var)))
>> ...
>> +  else
>> +    {
>> +    /* If this variable is in a register, use expand_assignment might
>> +       generate better code.  */
>> 
>> you compute the patter initializer even when not needing it,
>> that's wasteful.
>
>Okay, I will restrict the pattern initializer computation when really needed. 
>
>>  It's also quite ugly, IMHO you should
>> use can_native_interpret_type_p (var_type) and native_interpret
>> a char [] array initialized to the pattern and if
>> !can_native_interpret_type_p () go the memset route.
>
>Thanks for the suggestion. 
>
>Will try this. 
>
>> 
>> +  /* We will not verify the arguments for the calls to .DEFERRED_INIT.
>> +     Such call is not a real call, just a placeholder for a later
>> +     initialization during expand phase.
>> +     This is mainly to avoid assertion failure for the following
>> +     case:
>> +
>> +     uni_var = .DEFERRED_INIT (var_size, INIT_TYPE, is_vla);
>> +     foo (&uni_var);
>> +
>> +     in the above, the uninitialized auto variable "uni_var" is
>> +     addressable, therefore should not be in registers, resulting
>> +     the assertion failure in the following argument verification.  */
>> +  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
>>      unit-at-a-time we have a chance to fix this.  */
>> 
>> -  for (i = 0; i < gimple_call_num_args (stmt); ++i)
>> 
>> isn't that from the time there was a decl argument to .DEFERRED_INIT?
>
>You mean this issue is only there when the decl is the first argument (the old design for .DEFERRED_INIT).
>With the new design, this issue is not there anymore?
>
>> 
>> +  if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
>> +    {
>> +      tree size_of_arg0 = gimple_call_arg (stmt, 0);
>> +      tree size_of_lhs = TYPE_SIZE_UNIT (TREE_TYPE (lhs));
>> +      tree is_vla_node = gimple_call_arg (stmt, 2);
>> +      bool is_vla = (bool) TREE_INT_CST_LOW (is_vla_node);
>> +
>> +      if (TREE_CODE (lhs) == SSA_NAME)
>> +       lhs = SSA_NAME_VAR (lhs);
>> +
>> 
>> 'lhs' is not looked at after this, no need to look at SSA_NAME_VAR.
>
>Okay, will update this.
>
>> 
>> 
>> Thanks and sorry for the delay in reviewing this (again).
>
>Thanks again for your detailed review and suggestions.
>
>I will update the patch accordingly and send the updated patch soon.
>
>Qing
>> 
>> Richard.
>> 
>> 
>>> Thanks
>>> 
>


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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-09 16:38   ` Qing Zhao
  2021-08-09 17:14     ` Richard Biener
@ 2021-08-10  7:36     ` Richard Biener
  2021-08-10 13:39       ` Qing Zhao
  1 sibling, 1 reply; 60+ messages in thread
From: Richard Biener @ 2021-08-10  7:36 UTC (permalink / raw)
  To: Qing Zhao
  Cc: Martin Jambor, Jakub Jelinek, Kees Cook,
	Nick Alcock via Gcc-patches, Richard Biener

On Mon, 9 Aug 2021, Qing Zhao wrote:

> Hi, Richard,
> 
> Thanks a lot for you review.
> 
> Although these comments are not made on the latest patch (7th version) :-), all the comments are valid since the parts you commented
> are not changed in the 7th version.
> 
> 
> > On Aug 9, 2021, at 9:09 AM, Richard Biener <rguenther@suse.de> wrote:
> > 
> > On Tue, 27 Jul 2021, Qing Zhao wrote:
> > 
> >> Hi,
> >> 
> >> This is the 6th version of the patch for the new security feature for GCC.
> >> 
> >> I have tested it with bootstrap on both x86 and aarch64, regression testing on both x86 and aarch64.
> >> Also compile CPU2017 (running is ongoing), without any issue. (With the fix to bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101586).
> >> 
> >> Please take a look and let me know any issue.
> > 
> > +/* Handle an "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))
> > +    {
> > +      warning (OPT_Wattributes, "%qE attribute ignored", name);
> > +      *no_add_attrs = true;
> > +    }
> > 
> > you are documenting this attribute for automatic variables but
> > here you allow placement on globals as well (not sure if at this
> > point TREE_STATIC / DECL_EXTERNAL are set correctly).
> 
> Right, I should warn when the attribute is placed for globals or static variables. 
> I will try TREE_STATIC/DECL_EXTERNAL to see whether it’s work or not.
> 
> > 
> > +  /* for languages that do not support BUILT_IN_CLEAR_PADDING, create the
> > +     function node for padding initialization.  */
> > +  if (!fn)
> > +    {
> > +      tree ftype = build_function_type_list (void_type_node,
> > +                                            ptr_type_node,
> > 
> > the "appropriate" place to do this would be 
> > tree.c:build_common_builtin_nodes
> 
> Sure, will move the creation of  function node of BUILT_IN_CLEAR_PADDING for Fortran etc. to tree.c:build_common_builtin_nodes.
> 
> > 
> > You seem to marshall the is_vla argument as for_auto_init when
> > expanding/folding the builtin and there it's used to suppress
> > diagnostics (and make covered pieces not initialized?).
> 
> Yes, I added an extra argument “for_auto_init” for “BUILT_IN_CLEAR_PADDING”, this argument is added to suppress errors emitted during folding
> BUILT_IN_CLEAR_PADDING for flexible array member . Such errors should Not be emitted when “BUILT_IN_CLEAR_PADDING” is called with compiler automatic initialization.
> Please see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101586, comment #6 from Jakub Jelinek.
> 
> >  I suggest
> > to re-name is_vla/for_auto_init to something more descriptive.
> 
> Okay, I will. 
> > 
> > +   gimple_fold_builtin_clear_padding. If FOR_AUTO_INIT,
> > +   not emit some of the error messages since doing that
> > +   might confuse the end user.  */
> > 
> > doesn't explain to me whether errors still might be raised or
> > what the actual behavior is.
> 
> Okay, will make this more clear in the comments.
> 
> > 
> > +static gimple *
> > +build_deferred_init (tree decl,
> > +                    enum auto_init_type init_type,
> > +                    bool is_vla)
> > +{
> > +  gcc_assert ((is_vla && TREE_CODE (decl) == WITH_SIZE_EXPR)
> > +             || (!is_vla && TREE_CODE (decl) != WITH_SIZE_EXPR));
> > 
> > so the is_vla parameter looks redundant (and the assert dangerous?).
> > Either the caller knows it deals with a VLA, then that should be
> > passed through - constant sizes can also later appear during
> > optimization after all - or is_vla should be determined here
> > based on whether the size at gimplification time is constant.
> 
> The routine “build_deferred_init” is ONLY called during gimplification phase by the routine “gimple_add_init_for_auto_var", at this place,
> Is_vla should be determined by the caller to check the size of the DECL. If it’s a vla, the “maybe_with_size_expr” will be applied for
> DECL to make it to a WITH_SIZE_EXPR.  So, the assertion is purely to make sure this at gimplification phase.
> 
> Yes, the size of the VLA decl might become a constant later due to constant propagation, etc.  but during the gimplification phase, the assertion should be true.
> > 
> > +         /* If the user requests to initialize automatic variables, we
> > +            should initialize paddings inside the variable. Add a call to
> > +            __BUILTIN_CLEAR_PADDING (&object, 0, for_auto_init = true) to
> > +            initialize paddings of object always to zero regardless of
> > +            INIT_TYPE.  */
> > +         if (opt_for_fn (current_function_decl, flag_auto_var_init)
> > +               > AUTO_INIT_UNINITIALIZED
> > +             && VAR_P (object)
> > +             && !DECL_EXTERNAL (object)
> > +             && !TREE_STATIC (object))
> > +           gimple_add_padding_init_for_auto_var (object, false, pre_p);
> > +         return ret;
> > 
> > I think you want to use either auto_var_p (object) or
> > auto_var_in_fn_p (object, current_function_decl).  Don't you also
> > want to check for the 'uninitialized' attribute here?  I suggest
> > to abstract the check on whether 'object' should be subject
> > to autoinit to a helper function.
> 
> Thanks for the suggestion, I will do this.
> 
> 
> > 
> > There's another path above this calling gimplify_init_constructor
> > for the case of
> > 
> > const struct S x = { ... };
> > struct S y = x;
> > 
> > where it will try to init 'y' from the CTOR directly, it seems you
> > do not cover this case.
> 
> Yes, you are right, this case was not covered right now, and this should be covered.
> 
> Looks like that I need to move the “gimple_add_padding_init_for_auto_var” inside the routine “gimplify_init_constructor” to
> Cover all the cases. 
> 
> >  I also think that the above place applies
> > to all aggregate assignment statements, not only to INIT_EXPRs?
> 
> > So don't you want to restrict clear-padding emit here?
> 
> You are right, I might need to restrict it Only to INIT_EXPR. 
> Will update.
> 
> > 
> > +static void
> > +expand_DEFERRED_INIT (internal_fn, gcall *stmt)
> > +{
> > +  tree var = gimple_call_lhs (stmt);
> > +  tree size_of_var = gimple_call_arg (stmt, 0);
> > +  tree vlaaddr = NULL_TREE;
> > +  tree var_type = TREE_TYPE (var);
> > +  bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
> > +  enum auto_init_type init_type
> > +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
> > +
> > +  gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
> > +
> > +  /* if this variable is a VLA, get its SIZE and ADDR first.  */
> > +  if (is_vla)
> > +    {
> > +      /* The temporary address variable for this vla should have been
> > +        created during gimplification phase.  Refer to gimplify_vla_decl
> > +        for details.  */
> > +      tree var_decl = (TREE_CODE (var) == SSA_NAME) ?
> > +                      SSA_NAME_VAR (var) : var;
> > +      gcc_assert (DECL_HAS_VALUE_EXPR_P (var_decl));
> > +      gcc_assert (TREE_CODE (DECL_VALUE_EXPR (var_decl)) == 
> > INDIRECT_REF);
> > +      /* Get the address of this vla variable.  */
> > +      vlaaddr = TREE_OPERAND (DECL_VALUE_EXPR (var_decl), 0);
> > 
> > err - isn't the address of the decl represented by the LHS 
> > regardless whether this is a VLA or not?
> 
> The LHS of the call to .DEFERRED_INIT is the DECL itself whatever it’s a VLA or not. 
> 
> In order to create a memset call, we need the Address of this DECL as the first argument. 
> If the DECL is not a VLA, we just simply apply “build_fold_addr_expr” on this DECL to get its address,
> However, for VLA, during gimplification phase “gimplify_vla_decl”, we have already created a temporary
> address variable for this DECL, and recorded this address variable with “DECL_VALUE_EXPR(DECL), 
> We should use this already created address variable  for VLAs. 

So the issue is that the LHS of the .DEFERRED_INIT call is not properly
gimplified.  We should not have such decl there but I see we do not
have IL verification that covers this.

The gimplifier usually does this in gimplify_var_or_parm_decl,
but you can of course substitute DECL_VALUE_EXPR yourself if the
decl was already gimplified (was it?)

> 
> >  Looking at DECL_VALUE_EXPR
> > looks quite fragile since that's not sth data dependence honors.
> > It looks you only partly gimplify the build init here?  All
> > DECL_VALUE_EXPRs should have been resolved.
> 
> Don’t quite understand here. you mean that all the “DECL_VALUE_EXPRs” have been resolved at the phase RTL expansion,
> So I cannot use this to get the address variable of the VLA?
> 
> (However, my unit testing cases for VLAs are all looks fine).
> 
> > 
> > +  if (is_vla || (!use_register_for_decl (var)))
> > ...
> > +  else
> > +    {
> > +    /* If this variable is in a register, use expand_assignment might
> > +       generate better code.  */
> > 
> > you compute the patter initializer even when not needing it,
> > that's wasteful.
> 
> Okay, I will restrict the pattern initializer computation when really needed. 
> 
> >  It's also quite ugly, IMHO you should
> > use can_native_interpret_type_p (var_type) and native_interpret
> > a char [] array initialized to the pattern and if
> > !can_native_interpret_type_p () go the memset route.
> 
> Thanks for the suggestion. 
> 
> Will try this. 
> 
> > 
> > +  /* We will not verify the arguments for the calls to .DEFERRED_INIT.
> > +     Such call is not a real call, just a placeholder for a later
> > +     initialization during expand phase.
> > +     This is mainly to avoid assertion failure for the following
> > +     case:
> > +
> > +     uni_var = .DEFERRED_INIT (var_size, INIT_TYPE, is_vla);
> > +     foo (&uni_var);
> > +
> > +     in the above, the uninitialized auto variable "uni_var" is
> > +     addressable, therefore should not be in registers, resulting
> > +     the assertion failure in the following argument verification.  */
> > +  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
> >      unit-at-a-time we have a chance to fix this.  */
> > 
> > -  for (i = 0; i < gimple_call_num_args (stmt); ++i)
> > 
> > isn't that from the time there was a decl argument to .DEFERRED_INIT?
> 
> You mean this issue is only there when the decl is the first argument (the old design for .DEFERRED_INIT).
> With the new design, this issue is not there anymore?

I think so, yes - the change should no longer be needed.

Ricahrd.

> > 
> > +  if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
> > +    {
> > +      tree size_of_arg0 = gimple_call_arg (stmt, 0);
> > +      tree size_of_lhs = TYPE_SIZE_UNIT (TREE_TYPE (lhs));
> > +      tree is_vla_node = gimple_call_arg (stmt, 2);
> > +      bool is_vla = (bool) TREE_INT_CST_LOW (is_vla_node);
> > +
> > +      if (TREE_CODE (lhs) == SSA_NAME)
> > +       lhs = SSA_NAME_VAR (lhs);
> > +
> > 
> > 'lhs' is not looked at after this, no need to look at SSA_NAME_VAR.
> 
> Okay, will update this.
> 
> > 
> > 
> > Thanks and sorry for the delay in reviewing this (again).
> 
> Thanks again for your detailed review and suggestions.
> 
> I will update the patch accordingly and send the updated patch soon.
> 
> Qing
> > 
> > Richard.
> > 
> > 
> >> Thanks
> >> 
> 
> 

-- 
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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-10  7:36     ` Richard Biener
@ 2021-08-10 13:39       ` Qing Zhao
  2021-08-10 14:16         ` Richard Biener
  0 siblings, 1 reply; 60+ messages in thread
From: Qing Zhao @ 2021-08-10 13:39 UTC (permalink / raw)
  To: Richard Biener
  Cc: Martin Jambor, Jakub Jelinek, Kees Cook,
	Nick Alcock via Gcc-patches, Richard Biener



> On Aug 10, 2021, at 2:36 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Mon, 9 Aug 2021, Qing Zhao wrote:
> 
>> Hi, Richard,
>> 
>> Thanks a lot for you review.
>> 
>> Although these comments are not made on the latest patch (7th version) :-), all the comments are valid since the parts you commented
>> are not changed in the 7th version.
>> 
>> 
>>> On Aug 9, 2021, at 9:09 AM, Richard Biener <rguenther@suse.de> wrote:
>>> 
>>> On Tue, 27 Jul 2021, Qing Zhao wrote:
>>> 
>>>> Hi,
>>>> 
>>>> This is the 6th version of the patch for the new security feature for GCC.
>>>> 
>>>> I have tested it with bootstrap on both x86 and aarch64, regression testing on both x86 and aarch64.
>>>> Also compile CPU2017 (running is ongoing), without any issue. (With the fix to bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101586).
>>>> 
>>>> Please take a look and let me know any issue.
>>> 
>>> +/* Handle an "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))
>>> +    {
>>> +      warning (OPT_Wattributes, "%qE attribute ignored", name);
>>> +      *no_add_attrs = true;
>>> +    }
>>> 
>>> you are documenting this attribute for automatic variables but
>>> here you allow placement on globals as well (not sure if at this
>>> point TREE_STATIC / DECL_EXTERNAL are set correctly).
>> 
>> Right, I should warn when the attribute is placed for globals or static variables. 
>> I will try TREE_STATIC/DECL_EXTERNAL to see whether it’s work or not.
>> 
>>> 
>>> +  /* for languages that do not support BUILT_IN_CLEAR_PADDING, create the
>>> +     function node for padding initialization.  */
>>> +  if (!fn)
>>> +    {
>>> +      tree ftype = build_function_type_list (void_type_node,
>>> +                                            ptr_type_node,
>>> 
>>> the "appropriate" place to do this would be 
>>> tree.c:build_common_builtin_nodes
>> 
>> Sure, will move the creation of  function node of BUILT_IN_CLEAR_PADDING for Fortran etc. to tree.c:build_common_builtin_nodes.
>> 
>>> 
>>> You seem to marshall the is_vla argument as for_auto_init when
>>> expanding/folding the builtin and there it's used to suppress
>>> diagnostics (and make covered pieces not initialized?).
>> 
>> Yes, I added an extra argument “for_auto_init” for “BUILT_IN_CLEAR_PADDING”, this argument is added to suppress errors emitted during folding
>> BUILT_IN_CLEAR_PADDING for flexible array member . Such errors should Not be emitted when “BUILT_IN_CLEAR_PADDING” is called with compiler automatic initialization.
>> Please see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101586, comment #6 from Jakub Jelinek.
>> 
>>> I suggest
>>> to re-name is_vla/for_auto_init to something more descriptive.
>> 
>> Okay, I will. 
>>> 
>>> +   gimple_fold_builtin_clear_padding. If FOR_AUTO_INIT,
>>> +   not emit some of the error messages since doing that
>>> +   might confuse the end user.  */
>>> 
>>> doesn't explain to me whether errors still might be raised or
>>> what the actual behavior is.
>> 
>> Okay, will make this more clear in the comments.
>> 
>>> 
>>> +static gimple *
>>> +build_deferred_init (tree decl,
>>> +                    enum auto_init_type init_type,
>>> +                    bool is_vla)
>>> +{
>>> +  gcc_assert ((is_vla && TREE_CODE (decl) == WITH_SIZE_EXPR)
>>> +             || (!is_vla && TREE_CODE (decl) != WITH_SIZE_EXPR));
>>> 
>>> so the is_vla parameter looks redundant (and the assert dangerous?).
>>> Either the caller knows it deals with a VLA, then that should be
>>> passed through - constant sizes can also later appear during
>>> optimization after all - or is_vla should be determined here
>>> based on whether the size at gimplification time is constant.
>> 
>> The routine “build_deferred_init” is ONLY called during gimplification phase by the routine “gimple_add_init_for_auto_var", at this place,
>> Is_vla should be determined by the caller to check the size of the DECL. If it’s a vla, the “maybe_with_size_expr” will be applied for
>> DECL to make it to a WITH_SIZE_EXPR.  So, the assertion is purely to make sure this at gimplification phase.
>> 
>> Yes, the size of the VLA decl might become a constant later due to constant propagation, etc.  but during the gimplification phase, the assertion should be true.
>>> 
>>> +         /* If the user requests to initialize automatic variables, we
>>> +            should initialize paddings inside the variable. Add a call to
>>> +            __BUILTIN_CLEAR_PADDING (&object, 0, for_auto_init = true) to
>>> +            initialize paddings of object always to zero regardless of
>>> +            INIT_TYPE.  */
>>> +         if (opt_for_fn (current_function_decl, flag_auto_var_init)
>>> +               > AUTO_INIT_UNINITIALIZED
>>> +             && VAR_P (object)
>>> +             && !DECL_EXTERNAL (object)
>>> +             && !TREE_STATIC (object))
>>> +           gimple_add_padding_init_for_auto_var (object, false, pre_p);
>>> +         return ret;
>>> 
>>> I think you want to use either auto_var_p (object) or
>>> auto_var_in_fn_p (object, current_function_decl).  Don't you also
>>> want to check for the 'uninitialized' attribute here?  I suggest
>>> to abstract the check on whether 'object' should be subject
>>> to autoinit to a helper function.
>> 
>> Thanks for the suggestion, I will do this.
>> 
>> 
>>> 
>>> There's another path above this calling gimplify_init_constructor
>>> for the case of
>>> 
>>> const struct S x = { ... };
>>> struct S y = x;
>>> 
>>> where it will try to init 'y' from the CTOR directly, it seems you
>>> do not cover this case.
>> 
>> Yes, you are right, this case was not covered right now, and this should be covered.
>> 
>> Looks like that I need to move the “gimple_add_padding_init_for_auto_var” inside the routine “gimplify_init_constructor” to
>> Cover all the cases. 
>> 
>>> I also think that the above place applies
>>> to all aggregate assignment statements, not only to INIT_EXPRs?
>> 
>>> So don't you want to restrict clear-padding emit here?
>> 
>> You are right, I might need to restrict it Only to INIT_EXPR. 
>> Will update.
>> 
>>> 
>>> +static void
>>> +expand_DEFERRED_INIT (internal_fn, gcall *stmt)
>>> +{
>>> +  tree var = gimple_call_lhs (stmt);
>>> +  tree size_of_var = gimple_call_arg (stmt, 0);
>>> +  tree vlaaddr = NULL_TREE;
>>> +  tree var_type = TREE_TYPE (var);
>>> +  bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
>>> +  enum auto_init_type init_type
>>> +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
>>> +
>>> +  gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>>> +
>>> +  /* if this variable is a VLA, get its SIZE and ADDR first.  */
>>> +  if (is_vla)
>>> +    {
>>> +      /* The temporary address variable for this vla should have been
>>> +        created during gimplification phase.  Refer to gimplify_vla_decl
>>> +        for details.  */
>>> +      tree var_decl = (TREE_CODE (var) == SSA_NAME) ?
>>> +                      SSA_NAME_VAR (var) : var;
>>> +      gcc_assert (DECL_HAS_VALUE_EXPR_P (var_decl));
>>> +      gcc_assert (TREE_CODE (DECL_VALUE_EXPR (var_decl)) == 
>>> INDIRECT_REF);
>>> +      /* Get the address of this vla variable.  */
>>> +      vlaaddr = TREE_OPERAND (DECL_VALUE_EXPR (var_decl), 0);
>>> 
>>> err - isn't the address of the decl represented by the LHS 
>>> regardless whether this is a VLA or not?
>> 
>> The LHS of the call to .DEFERRED_INIT is the DECL itself whatever it’s a VLA or not. 
>> 
>> In order to create a memset call, we need the Address of this DECL as the first argument. 
>> If the DECL is not a VLA, we just simply apply “build_fold_addr_expr” on this DECL to get its address,
>> However, for VLA, during gimplification phase “gimplify_vla_decl”, we have already created a temporary
>> address variable for this DECL, and recorded this address variable with “DECL_VALUE_EXPR(DECL), 
>> We should use this already created address variable  for VLAs. 
> 
> So the issue is that the LHS of the .DEFERRED_INIT call is not properly
> gimplified.  We should not have such decl there but I see we do not
> have IL verification that covers this.

Don’t quite understand here:  do you mean all the LHS of .DEFERRED_INIT call are not properly gimplified, or
Only the LHS of .DEFERRED_INIT call for VLA are not properly gimplified?

What do you mean by “such” decl? A decl whole “DECL_VALUE_EXPR(DECL)” is valid?

Qing
> 
> The gimplifier usually does this in gimplify_var_or_parm_decl,
> but you can of course substitute DECL_VALUE_EXPR yourself if the
> decl was already gimplified (was it?)
> 
>> 
>>> Looking at DECL_VALUE_EXPR
>>> looks quite fragile since that's not sth data dependence honors.
>>> It looks you only partly gimplify the build init here?  All
>>> DECL_VALUE_EXPRs should have been resolved.
>> 
>> Don’t quite understand here. you mean that all the “DECL_VALUE_EXPRs” have been resolved at the phase RTL expansion,
>> So I cannot use this to get the address variable of the VLA?
>> 
>> (However, my unit testing cases for VLAs are all looks fine).
>> 
>>> 
>>> +  if (is_vla || (!use_register_for_decl (var)))
>>> ...
>>> +  else
>>> +    {
>>> +    /* If this variable is in a register, use expand_assignment might
>>> +       generate better code.  */
>>> 
>>> you compute the patter initializer even when not needing it,
>>> that's wasteful.
>> 
>> Okay, I will restrict the pattern initializer computation when really needed. 
>> 
>>> It's also quite ugly, IMHO you should
>>> use can_native_interpret_type_p (var_type) and native_interpret
>>> a char [] array initialized to the pattern and if
>>> !can_native_interpret_type_p () go the memset route.
>> 
>> Thanks for the suggestion. 
>> 
>> Will try this. 
>> 
>>> 
>>> +  /* We will not verify the arguments for the calls to .DEFERRED_INIT.
>>> +     Such call is not a real call, just a placeholder for a later
>>> +     initialization during expand phase.
>>> +     This is mainly to avoid assertion failure for the following
>>> +     case:
>>> +
>>> +     uni_var = .DEFERRED_INIT (var_size, INIT_TYPE, is_vla);
>>> +     foo (&uni_var);
>>> +
>>> +     in the above, the uninitialized auto variable "uni_var" is
>>> +     addressable, therefore should not be in registers, resulting
>>> +     the assertion failure in the following argument verification.  */
>>> +  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
>>>     unit-at-a-time we have a chance to fix this.  */
>>> 
>>> -  for (i = 0; i < gimple_call_num_args (stmt); ++i)
>>> 
>>> isn't that from the time there was a decl argument to .DEFERRED_INIT?
>> 
>> You mean this issue is only there when the decl is the first argument (the old design for .DEFERRED_INIT).
>> With the new design, this issue is not there anymore?
> 
> I think so, yes - the change should no longer be needed.
> 
> Ricahrd.
> 
>>> 
>>> +  if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
>>> +    {
>>> +      tree size_of_arg0 = gimple_call_arg (stmt, 0);
>>> +      tree size_of_lhs = TYPE_SIZE_UNIT (TREE_TYPE (lhs));
>>> +      tree is_vla_node = gimple_call_arg (stmt, 2);
>>> +      bool is_vla = (bool) TREE_INT_CST_LOW (is_vla_node);
>>> +
>>> +      if (TREE_CODE (lhs) == SSA_NAME)
>>> +       lhs = SSA_NAME_VAR (lhs);
>>> +
>>> 
>>> 'lhs' is not looked at after this, no need to look at SSA_NAME_VAR.
>> 
>> Okay, will update this.
>> 
>>> 
>>> 
>>> Thanks and sorry for the delay in reviewing this (again).
>> 
>> Thanks again for your detailed review and suggestions.
>> 
>> I will update the patch accordingly and send the updated patch soon.
>> 
>> Qing
>>> 
>>> Richard.
>>> 
>>> 
>>>> Thanks
>>>> 
>> 
>> 
> 
> -- 
> 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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-10 13:39       ` Qing Zhao
@ 2021-08-10 14:16         ` Richard Biener
  2021-08-10 15:02           ` Qing Zhao
  0 siblings, 1 reply; 60+ messages in thread
From: Richard Biener @ 2021-08-10 14:16 UTC (permalink / raw)
  To: Qing Zhao
  Cc: Martin Jambor, Jakub Jelinek, Kees Cook,
	Nick Alcock via Gcc-patches, Richard Biener

On Tue, 10 Aug 2021, Qing Zhao wrote:

> 
> 
> > On Aug 10, 2021, at 2:36 AM, Richard Biener <rguenther@suse.de> wrote:
> > 
> > On Mon, 9 Aug 2021, Qing Zhao wrote:
> > 
> >> Hi, Richard,
> >> 
> >> Thanks a lot for you review.
> >> 
> >> Although these comments are not made on the latest patch (7th version) :-), all the comments are valid since the parts you commented
> >> are not changed in the 7th version.
> >> 
> >> 
> >>> On Aug 9, 2021, at 9:09 AM, Richard Biener <rguenther@suse.de> wrote:
> >>> 
> >>> On Tue, 27 Jul 2021, Qing Zhao wrote:
> >>> 
> >>>> Hi,
> >>>> 
> >>>> This is the 6th version of the patch for the new security feature for GCC.
> >>>> 
> >>>> I have tested it with bootstrap on both x86 and aarch64, regression testing on both x86 and aarch64.
> >>>> Also compile CPU2017 (running is ongoing), without any issue. (With the fix to bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101586).
> >>>> 
> >>>> Please take a look and let me know any issue.
> >>> 
> >>> +/* Handle an "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))
> >>> +    {
> >>> +      warning (OPT_Wattributes, "%qE attribute ignored", name);
> >>> +      *no_add_attrs = true;
> >>> +    }
> >>> 
> >>> you are documenting this attribute for automatic variables but
> >>> here you allow placement on globals as well (not sure if at this
> >>> point TREE_STATIC / DECL_EXTERNAL are set correctly).
> >> 
> >> Right, I should warn when the attribute is placed for globals or static variables. 
> >> I will try TREE_STATIC/DECL_EXTERNAL to see whether it’s work or not.
> >> 
> >>> 
> >>> +  /* for languages that do not support BUILT_IN_CLEAR_PADDING, create the
> >>> +     function node for padding initialization.  */
> >>> +  if (!fn)
> >>> +    {
> >>> +      tree ftype = build_function_type_list (void_type_node,
> >>> +                                            ptr_type_node,
> >>> 
> >>> the "appropriate" place to do this would be 
> >>> tree.c:build_common_builtin_nodes
> >> 
> >> Sure, will move the creation of  function node of BUILT_IN_CLEAR_PADDING for Fortran etc. to tree.c:build_common_builtin_nodes.
> >> 
> >>> 
> >>> You seem to marshall the is_vla argument as for_auto_init when
> >>> expanding/folding the builtin and there it's used to suppress
> >>> diagnostics (and make covered pieces not initialized?).
> >> 
> >> Yes, I added an extra argument “for_auto_init” for “BUILT_IN_CLEAR_PADDING”, this argument is added to suppress errors emitted during folding
> >> BUILT_IN_CLEAR_PADDING for flexible array member . Such errors should Not be emitted when “BUILT_IN_CLEAR_PADDING” is called with compiler automatic initialization.
> >> Please see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101586, comment #6 from Jakub Jelinek.
> >> 
> >>> I suggest
> >>> to re-name is_vla/for_auto_init to something more descriptive.
> >> 
> >> Okay, I will. 
> >>> 
> >>> +   gimple_fold_builtin_clear_padding. If FOR_AUTO_INIT,
> >>> +   not emit some of the error messages since doing that
> >>> +   might confuse the end user.  */
> >>> 
> >>> doesn't explain to me whether errors still might be raised or
> >>> what the actual behavior is.
> >> 
> >> Okay, will make this more clear in the comments.
> >> 
> >>> 
> >>> +static gimple *
> >>> +build_deferred_init (tree decl,
> >>> +                    enum auto_init_type init_type,
> >>> +                    bool is_vla)
> >>> +{
> >>> +  gcc_assert ((is_vla && TREE_CODE (decl) == WITH_SIZE_EXPR)
> >>> +             || (!is_vla && TREE_CODE (decl) != WITH_SIZE_EXPR));
> >>> 
> >>> so the is_vla parameter looks redundant (and the assert dangerous?).
> >>> Either the caller knows it deals with a VLA, then that should be
> >>> passed through - constant sizes can also later appear during
> >>> optimization after all - or is_vla should be determined here
> >>> based on whether the size at gimplification time is constant.
> >> 
> >> The routine “build_deferred_init” is ONLY called during gimplification phase by the routine “gimple_add_init_for_auto_var", at this place,
> >> Is_vla should be determined by the caller to check the size of the DECL. If it’s a vla, the “maybe_with_size_expr” will be applied for
> >> DECL to make it to a WITH_SIZE_EXPR.  So, the assertion is purely to make sure this at gimplification phase.
> >> 
> >> Yes, the size of the VLA decl might become a constant later due to constant propagation, etc.  but during the gimplification phase, the assertion should be true.
> >>> 
> >>> +         /* If the user requests to initialize automatic variables, we
> >>> +            should initialize paddings inside the variable. Add a call to
> >>> +            __BUILTIN_CLEAR_PADDING (&object, 0, for_auto_init = true) to
> >>> +            initialize paddings of object always to zero regardless of
> >>> +            INIT_TYPE.  */
> >>> +         if (opt_for_fn (current_function_decl, flag_auto_var_init)
> >>> +               > AUTO_INIT_UNINITIALIZED
> >>> +             && VAR_P (object)
> >>> +             && !DECL_EXTERNAL (object)
> >>> +             && !TREE_STATIC (object))
> >>> +           gimple_add_padding_init_for_auto_var (object, false, pre_p);
> >>> +         return ret;
> >>> 
> >>> I think you want to use either auto_var_p (object) or
> >>> auto_var_in_fn_p (object, current_function_decl).  Don't you also
> >>> want to check for the 'uninitialized' attribute here?  I suggest
> >>> to abstract the check on whether 'object' should be subject
> >>> to autoinit to a helper function.
> >> 
> >> Thanks for the suggestion, I will do this.
> >> 
> >> 
> >>> 
> >>> There's another path above this calling gimplify_init_constructor
> >>> for the case of
> >>> 
> >>> const struct S x = { ... };
> >>> struct S y = x;
> >>> 
> >>> where it will try to init 'y' from the CTOR directly, it seems you
> >>> do not cover this case.
> >> 
> >> Yes, you are right, this case was not covered right now, and this should be covered.
> >> 
> >> Looks like that I need to move the “gimple_add_padding_init_for_auto_var” inside the routine “gimplify_init_constructor” to
> >> Cover all the cases. 
> >> 
> >>> I also think that the above place applies
> >>> to all aggregate assignment statements, not only to INIT_EXPRs?
> >> 
> >>> So don't you want to restrict clear-padding emit here?
> >> 
> >> You are right, I might need to restrict it Only to INIT_EXPR. 
> >> Will update.
> >> 
> >>> 
> >>> +static void
> >>> +expand_DEFERRED_INIT (internal_fn, gcall *stmt)
> >>> +{
> >>> +  tree var = gimple_call_lhs (stmt);
> >>> +  tree size_of_var = gimple_call_arg (stmt, 0);
> >>> +  tree vlaaddr = NULL_TREE;
> >>> +  tree var_type = TREE_TYPE (var);
> >>> +  bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
> >>> +  enum auto_init_type init_type
> >>> +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
> >>> +
> >>> +  gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
> >>> +
> >>> +  /* if this variable is a VLA, get its SIZE and ADDR first.  */
> >>> +  if (is_vla)
> >>> +    {
> >>> +      /* The temporary address variable for this vla should have been
> >>> +        created during gimplification phase.  Refer to gimplify_vla_decl
> >>> +        for details.  */
> >>> +      tree var_decl = (TREE_CODE (var) == SSA_NAME) ?
> >>> +                      SSA_NAME_VAR (var) : var;
> >>> +      gcc_assert (DECL_HAS_VALUE_EXPR_P (var_decl));
> >>> +      gcc_assert (TREE_CODE (DECL_VALUE_EXPR (var_decl)) == 
> >>> INDIRECT_REF);
> >>> +      /* Get the address of this vla variable.  */
> >>> +      vlaaddr = TREE_OPERAND (DECL_VALUE_EXPR (var_decl), 0);
> >>> 
> >>> err - isn't the address of the decl represented by the LHS 
> >>> regardless whether this is a VLA or not?
> >> 
> >> The LHS of the call to .DEFERRED_INIT is the DECL itself whatever it’s a VLA or not. 
> >> 
> >> In order to create a memset call, we need the Address of this DECL as the first argument. 
> >> If the DECL is not a VLA, we just simply apply “build_fold_addr_expr” on this DECL to get its address,
> >> However, for VLA, during gimplification phase “gimplify_vla_decl”, we have already created a temporary
> >> address variable for this DECL, and recorded this address variable with “DECL_VALUE_EXPR(DECL), 
> >> We should use this already created address variable  for VLAs. 
> > 
> > So the issue is that the LHS of the .DEFERRED_INIT call is not properly
> > gimplified.  We should not have such decl there but I see we do not
> > have IL verification that covers this.
> 
> Don’t quite understand here:  do you mean all the LHS of .DEFERRED_INIT call are not properly gimplified, or
> Only the LHS of .DEFERRED_INIT call for VLA are not properly gimplified?

Especially in the VLA case but likely also in general (though unlikely
since usually the receiver of initializations are simple enough).  I'd
expect the VLA case end up as

 *ptr_to_decl = .DEFERRED_INIT (...);

where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.

> What do you mean by “such” decl? A decl whole “DECL_VALUE_EXPR(DECL)” is valid?

A 'decl' that has a DECL_VALUE_EXPR should not appear in the IL, it should
always be refered to as its DECL_VALUE_EXPR.

Richard.

> Qing
> > 
> > The gimplifier usually does this in gimplify_var_or_parm_decl,
> > but you can of course substitute DECL_VALUE_EXPR yourself if the
> > decl was already gimplified (was it?)
> > 
> >> 
> >>> Looking at DECL_VALUE_EXPR
> >>> looks quite fragile since that's not sth data dependence honors.
> >>> It looks you only partly gimplify the build init here?  All
> >>> DECL_VALUE_EXPRs should have been resolved.
> >> 
> >> Don’t quite understand here. you mean that all the “DECL_VALUE_EXPRs” have been resolved at the phase RTL expansion,
> >> So I cannot use this to get the address variable of the VLA?
> >> 
> >> (However, my unit testing cases for VLAs are all looks fine).
> >> 
> >>> 
> >>> +  if (is_vla || (!use_register_for_decl (var)))
> >>> ...
> >>> +  else
> >>> +    {
> >>> +    /* If this variable is in a register, use expand_assignment might
> >>> +       generate better code.  */
> >>> 
> >>> you compute the patter initializer even when not needing it,
> >>> that's wasteful.
> >> 
> >> Okay, I will restrict the pattern initializer computation when really needed. 
> >> 
> >>> It's also quite ugly, IMHO you should
> >>> use can_native_interpret_type_p (var_type) and native_interpret
> >>> a char [] array initialized to the pattern and if
> >>> !can_native_interpret_type_p () go the memset route.
> >> 
> >> Thanks for the suggestion. 
> >> 
> >> Will try this. 
> >> 
> >>> 
> >>> +  /* We will not verify the arguments for the calls to .DEFERRED_INIT.
> >>> +     Such call is not a real call, just a placeholder for a later
> >>> +     initialization during expand phase.
> >>> +     This is mainly to avoid assertion failure for the following
> >>> +     case:
> >>> +
> >>> +     uni_var = .DEFERRED_INIT (var_size, INIT_TYPE, is_vla);
> >>> +     foo (&uni_var);
> >>> +
> >>> +     in the above, the uninitialized auto variable "uni_var" is
> >>> +     addressable, therefore should not be in registers, resulting
> >>> +     the assertion failure in the following argument verification.  */
> >>> +  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
> >>>     unit-at-a-time we have a chance to fix this.  */
> >>> 
> >>> -  for (i = 0; i < gimple_call_num_args (stmt); ++i)
> >>> 
> >>> isn't that from the time there was a decl argument to .DEFERRED_INIT?
> >> 
> >> You mean this issue is only there when the decl is the first argument (the old design for .DEFERRED_INIT).
> >> With the new design, this issue is not there anymore?
> > 
> > I think so, yes - the change should no longer be needed.
> > 
> > Ricahrd.
> > 
> >>> 
> >>> +  if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
> >>> +    {
> >>> +      tree size_of_arg0 = gimple_call_arg (stmt, 0);
> >>> +      tree size_of_lhs = TYPE_SIZE_UNIT (TREE_TYPE (lhs));
> >>> +      tree is_vla_node = gimple_call_arg (stmt, 2);
> >>> +      bool is_vla = (bool) TREE_INT_CST_LOW (is_vla_node);
> >>> +
> >>> +      if (TREE_CODE (lhs) == SSA_NAME)
> >>> +       lhs = SSA_NAME_VAR (lhs);
> >>> +
> >>> 
> >>> 'lhs' is not looked at after this, no need to look at SSA_NAME_VAR.
> >> 
> >> Okay, will update this.
> >> 
> >>> 
> >>> 
> >>> Thanks and sorry for the delay in reviewing this (again).
> >> 
> >> Thanks again for your detailed review and suggestions.
> >> 
> >> I will update the patch accordingly and send the updated patch soon.
> >> 
> >> Qing
> >>> 
> >>> Richard.
> >>> 
> >>> 
> >>>> Thanks
> >>>> 
> >> 
> >> 
> > 
> > -- 
> > Richard Biener <rguenther@suse.de>
> > SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> > Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
> 
> 

-- 
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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-10 14:16         ` Richard Biener
@ 2021-08-10 15:02           ` Qing Zhao
  2021-08-10 15:22             ` Richard Biener
  0 siblings, 1 reply; 60+ messages in thread
From: Qing Zhao @ 2021-08-10 15:02 UTC (permalink / raw)
  To: Richard Biener
  Cc: Martin Jambor, Jakub Jelinek, Kees Cook,
	Nick Alcock via Gcc-patches, Richard Biener

Hi,

> On Aug 10, 2021, at 9:16 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Tue, 10 Aug 2021, Qing Zhao wrote:
> 
>>>>> 
>>>>> +static void
>>>>> +expand_DEFERRED_INIT (internal_fn, gcall *stmt)
>>>>> +{
>>>>> +  tree var = gimple_call_lhs (stmt);
>>>>> +  tree size_of_var = gimple_call_arg (stmt, 0);
>>>>> +  tree vlaaddr = NULL_TREE;
>>>>> +  tree var_type = TREE_TYPE (var);
>>>>> +  bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
>>>>> +  enum auto_init_type init_type
>>>>> +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
>>>>> +
>>>>> +  gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>>>>> +
>>>>> +  /* if this variable is a VLA, get its SIZE and ADDR first.  */
>>>>> +  if (is_vla)
>>>>> +    {
>>>>> +      /* The temporary address variable for this vla should have been
>>>>> +        created during gimplification phase.  Refer to gimplify_vla_decl
>>>>> +        for details.  */
>>>>> +      tree var_decl = (TREE_CODE (var) == SSA_NAME) ?
>>>>> +                      SSA_NAME_VAR (var) : var;
>>>>> +      gcc_assert (DECL_HAS_VALUE_EXPR_P (var_decl));
>>>>> +      gcc_assert (TREE_CODE (DECL_VALUE_EXPR (var_decl)) == 
>>>>> INDIRECT_REF);
>>>>> +      /* Get the address of this vla variable.  */
>>>>> +      vlaaddr = TREE_OPERAND (DECL_VALUE_EXPR (var_decl), 0);
>>>>> 
>>>>> err - isn't the address of the decl represented by the LHS 
>>>>> regardless whether this is a VLA or not?
>>>> 
>>>> The LHS of the call to .DEFERRED_INIT is the DECL itself whatever it’s a VLA or not. 
>>>> 
>>>> In order to create a memset call, we need the Address of this DECL as the first argument. 
>>>> If the DECL is not a VLA, we just simply apply “build_fold_addr_expr” on this DECL to get its address,
>>>> However, for VLA, during gimplification phase “gimplify_vla_decl”, we have already created a temporary
>>>> address variable for this DECL, and recorded this address variable with “DECL_VALUE_EXPR(DECL), 
>>>> We should use this already created address variable  for VLAs. 
>>> 
>>> So the issue is that the LHS of the .DEFERRED_INIT call is not properly
>>> gimplified.  We should not have such decl there but I see we do not
>>> have IL verification that covers this.
>> 
>> Don’t quite understand here:  do you mean all the LHS of .DEFERRED_INIT call are not properly gimplified, or
>> Only the LHS of .DEFERRED_INIT call for VLA are not properly gimplified?
> 
> Especially in the VLA case but likely also in general (though unlikely
> since usually the receiver of initializations are simple enough).  I'd
> expect the VLA case end up as
> 
> *ptr_to_decl = .DEFERRED_INIT (...);
> 
> where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.

So, for the following small testing case:

====
extern void bar (int);

void foo(int n)
{
  int arr[n];
  bar (arr[2]);
  return;
}
=====

If I compile it with -ftrivial-auto-var-init=zero -fdump-tree-gimple -S -o auto-init-11.s -fdump-rtl-expand, the *.gimple dump is:

=====
void foo (int n)
{
  int n.0;
  sizetype D.1950;
  bitsizetype D.1951;
  sizetype D.1952;
  bitsizetype D.1953;
  sizetype D.1954;
  int[0:D.1950] * arr.1;
  void * saved_stack.2;
  int arr[0:D.1950] [value-expr: *arr.1];

  saved_stack.2 = __builtin_stack_save ();
  try
    {
      n.0 = n;
      _1 = (long int) n.0;
      _2 = _1 + -1;
      _3 = (sizetype) _2;
      D.1950 = _3;
      _4 = (sizetype) n.0;
      _5 = (bitsizetype) _4;
      _6 = _5 * 32;
      D.1951 = _6;
      _7 = (sizetype) n.0;
      _8 = _7 * 4;
      D.1952 = _8;
      _9 = (sizetype) n.0;
      _10 = (bitsizetype) _9;
      _11 = _10 * 32;
      D.1953 = _11;
      _12 = (sizetype) n.0;
      _13 = _12 * 4;
      D.1954 = _13;
      arr.1 = __builtin_alloca_with_align (D.1954, 32);
      arr = .DEFERRED_INIT (D.1952, 2, 1);
      _14 = (*arr.1)[2];
      bar (_14);
      return;
    }
  finally
    {
      __builtin_stack_restore (saved_stack.2);
    }
}

====

You think that the above .DEFEERED_INIT is not correct?
It should be:

*arr.1 = .DEFERRED_INIT (D.1952. 2, 1);

?

> 
>> What do you mean by “such” decl? A decl whole “DECL_VALUE_EXPR(DECL)” is valid?
> 
> A 'decl' that has a DECL_VALUE_EXPR should not appear in the IL, it should
> always be refered to as its DECL_VALUE_EXPR.

Okay.

Qing
> 
> Richard.
> 
>> Qing
>>> 


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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-10 15:02           ` Qing Zhao
@ 2021-08-10 15:22             ` Richard Biener
  2021-08-10 15:55               ` Qing Zhao
  2021-08-10 20:16               ` Qing Zhao
  0 siblings, 2 replies; 60+ messages in thread
From: Richard Biener @ 2021-08-10 15:22 UTC (permalink / raw)
  To: Qing Zhao
  Cc: Martin Jambor, Jakub Jelinek, Kees Cook,
	Nick Alcock via Gcc-patches, Richard Biener

On Tue, 10 Aug 2021, Qing Zhao wrote:

> Hi,
> 
> > On Aug 10, 2021, at 9:16 AM, Richard Biener <rguenther@suse.de> wrote:
> > 
> > On Tue, 10 Aug 2021, Qing Zhao wrote:
> > 
> >>>>> 
> >>>>> +static void
> >>>>> +expand_DEFERRED_INIT (internal_fn, gcall *stmt)
> >>>>> +{
> >>>>> +  tree var = gimple_call_lhs (stmt);
> >>>>> +  tree size_of_var = gimple_call_arg (stmt, 0);
> >>>>> +  tree vlaaddr = NULL_TREE;
> >>>>> +  tree var_type = TREE_TYPE (var);
> >>>>> +  bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
> >>>>> +  enum auto_init_type init_type
> >>>>> +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
> >>>>> +
> >>>>> +  gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
> >>>>> +
> >>>>> +  /* if this variable is a VLA, get its SIZE and ADDR first.  */
> >>>>> +  if (is_vla)
> >>>>> +    {
> >>>>> +      /* The temporary address variable for this vla should have been
> >>>>> +        created during gimplification phase.  Refer to gimplify_vla_decl
> >>>>> +        for details.  */
> >>>>> +      tree var_decl = (TREE_CODE (var) == SSA_NAME) ?
> >>>>> +                      SSA_NAME_VAR (var) : var;
> >>>>> +      gcc_assert (DECL_HAS_VALUE_EXPR_P (var_decl));
> >>>>> +      gcc_assert (TREE_CODE (DECL_VALUE_EXPR (var_decl)) == 
> >>>>> INDIRECT_REF);
> >>>>> +      /* Get the address of this vla variable.  */
> >>>>> +      vlaaddr = TREE_OPERAND (DECL_VALUE_EXPR (var_decl), 0);
> >>>>> 
> >>>>> err - isn't the address of the decl represented by the LHS 
> >>>>> regardless whether this is a VLA or not?
> >>>> 
> >>>> The LHS of the call to .DEFERRED_INIT is the DECL itself whatever it’s a VLA or not. 
> >>>> 
> >>>> In order to create a memset call, we need the Address of this DECL as the first argument. 
> >>>> If the DECL is not a VLA, we just simply apply “build_fold_addr_expr” on this DECL to get its address,
> >>>> However, for VLA, during gimplification phase “gimplify_vla_decl”, we have already created a temporary
> >>>> address variable for this DECL, and recorded this address variable with “DECL_VALUE_EXPR(DECL), 
> >>>> We should use this already created address variable  for VLAs. 
> >>> 
> >>> So the issue is that the LHS of the .DEFERRED_INIT call is not properly
> >>> gimplified.  We should not have such decl there but I see we do not
> >>> have IL verification that covers this.
> >> 
> >> Don’t quite understand here:  do you mean all the LHS of .DEFERRED_INIT call are not properly gimplified, or
> >> Only the LHS of .DEFERRED_INIT call for VLA are not properly gimplified?
> > 
> > Especially in the VLA case but likely also in general (though unlikely
> > since usually the receiver of initializations are simple enough).  I'd
> > expect the VLA case end up as
> > 
> > *ptr_to_decl = .DEFERRED_INIT (...);
> > 
> > where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.
> 
> So, for the following small testing case:
> 
> ====
> extern void bar (int);
> 
> void foo(int n)
> {
>   int arr[n];
>   bar (arr[2]);
>   return;
> }
> =====
> 
> If I compile it with -ftrivial-auto-var-init=zero -fdump-tree-gimple -S -o auto-init-11.s -fdump-rtl-expand, the *.gimple dump is:
> 
> =====
> void foo (int n)
> {
>   int n.0;
>   sizetype D.1950;
>   bitsizetype D.1951;
>   sizetype D.1952;
>   bitsizetype D.1953;
>   sizetype D.1954;
>   int[0:D.1950] * arr.1;
>   void * saved_stack.2;
>   int arr[0:D.1950] [value-expr: *arr.1];
> 
>   saved_stack.2 = __builtin_stack_save ();
>   try
>     {
>       n.0 = n;
>       _1 = (long int) n.0;
>       _2 = _1 + -1;
>       _3 = (sizetype) _2;
>       D.1950 = _3;
>       _4 = (sizetype) n.0;
>       _5 = (bitsizetype) _4;
>       _6 = _5 * 32;
>       D.1951 = _6;
>       _7 = (sizetype) n.0;
>       _8 = _7 * 4;
>       D.1952 = _8;
>       _9 = (sizetype) n.0;
>       _10 = (bitsizetype) _9;
>       _11 = _10 * 32;
>       D.1953 = _11;
>       _12 = (sizetype) n.0;
>       _13 = _12 * 4;
>       D.1954 = _13;
>       arr.1 = __builtin_alloca_with_align (D.1954, 32);
>       arr = .DEFERRED_INIT (D.1952, 2, 1);
>       _14 = (*arr.1)[2];
>       bar (_14);
>       return;
>     }
>   finally
>     {
>       __builtin_stack_restore (saved_stack.2);
>     }
> }
> 
> ====
> 
> You think that the above .DEFEERED_INIT is not correct?
> It should be:
> 
> *arr.1 = .DEFERRED_INIT (D.1952. 2, 1);
> 
> ?

Yes.

> > 
> >> What do you mean by “such” decl? A decl whole “DECL_VALUE_EXPR(DECL)” is valid?
> > 
> > A 'decl' that has a DECL_VALUE_EXPR should not appear in the IL, it should
> > always be refered to as its DECL_VALUE_EXPR.
> 
> Okay.

I'm going to test

diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c
index ebf7eea3b04..15c73b6d6f4 100644
--- a/gcc/tree-ssa-operands.c
+++ b/gcc/tree-ssa-operands.c
@@ -799,10 +799,11 @@ operands_scanner::get_expr_operands (tree *expr_p, 
int flags)
                         flags | opf_not_non_addressable | 
opf_address_taken);
       return;
 
-    case SSA_NAME:
     case VAR_DECL:
     case PARM_DECL:
     case RESULT_DECL:
+      gcc_checking_assert (!DECL_HAS_VALUE_EXPR_P (expr));
+    case SSA_NAME:
     case STRING_CST:
     case CONST_DECL:
       if (!(flags & opf_address_taken))

which should pass on unmodified trunk (fingers crossing ;)), but
it would likely trip on the current -ftrivial-auto-init patch.

The issue with the current IL is that nothing keeps arr.1 live
and thus the allocation could be DCEd but the .DEFERRED_INIT
call would remain, eventually being expanded to zero storage
that isn't there.

Richard.

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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-10 15:22             ` Richard Biener
@ 2021-08-10 15:55               ` Qing Zhao
  2021-08-10 20:16               ` Qing Zhao
  1 sibling, 0 replies; 60+ messages in thread
From: Qing Zhao @ 2021-08-10 15:55 UTC (permalink / raw)
  To: Richard Biener
  Cc: Martin Jambor, Jakub Jelinek, Kees Cook,
	Nick Alcock via Gcc-patches, Richard Biener



> On Aug 10, 2021, at 10:22 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Tue, 10 Aug 2021, Qing Zhao wrote:
> 
>> Hi,
>> 
>>> On Aug 10, 2021, at 9:16 AM, Richard Biener <rguenther@suse.de> wrote:
>>> 
>>> On Tue, 10 Aug 2021, Qing Zhao wrote:
>>> 
>>>>>>> 
>>>>>>> +static void
>>>>>>> +expand_DEFERRED_INIT (internal_fn, gcall *stmt)
>>>>>>> +{
>>>>>>> +  tree var = gimple_call_lhs (stmt);
>>>>>>> +  tree size_of_var = gimple_call_arg (stmt, 0);
>>>>>>> +  tree vlaaddr = NULL_TREE;
>>>>>>> +  tree var_type = TREE_TYPE (var);
>>>>>>> +  bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
>>>>>>> +  enum auto_init_type init_type
>>>>>>> +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
>>>>>>> +
>>>>>>> +  gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>>>>>>> +
>>>>>>> +  /* if this variable is a VLA, get its SIZE and ADDR first.  */
>>>>>>> +  if (is_vla)
>>>>>>> +    {
>>>>>>> +      /* The temporary address variable for this vla should have been
>>>>>>> +        created during gimplification phase.  Refer to gimplify_vla_decl
>>>>>>> +        for details.  */
>>>>>>> +      tree var_decl = (TREE_CODE (var) == SSA_NAME) ?
>>>>>>> +                      SSA_NAME_VAR (var) : var;
>>>>>>> +      gcc_assert (DECL_HAS_VALUE_EXPR_P (var_decl));
>>>>>>> +      gcc_assert (TREE_CODE (DECL_VALUE_EXPR (var_decl)) == 
>>>>>>> INDIRECT_REF);
>>>>>>> +      /* Get the address of this vla variable.  */
>>>>>>> +      vlaaddr = TREE_OPERAND (DECL_VALUE_EXPR (var_decl), 0);
>>>>>>> 
>>>>>>> err - isn't the address of the decl represented by the LHS 
>>>>>>> regardless whether this is a VLA or not?
>>>>>> 
>>>>>> The LHS of the call to .DEFERRED_INIT is the DECL itself whatever it’s a VLA or not. 
>>>>>> 
>>>>>> In order to create a memset call, we need the Address of this DECL as the first argument. 
>>>>>> If the DECL is not a VLA, we just simply apply “build_fold_addr_expr” on this DECL to get its address,
>>>>>> However, for VLA, during gimplification phase “gimplify_vla_decl”, we have already created a temporary
>>>>>> address variable for this DECL, and recorded this address variable with “DECL_VALUE_EXPR(DECL), 
>>>>>> We should use this already created address variable  for VLAs. 
>>>>> 
>>>>> So the issue is that the LHS of the .DEFERRED_INIT call is not properly
>>>>> gimplified.  We should not have such decl there but I see we do not
>>>>> have IL verification that covers this.
>>>> 
>>>> Don’t quite understand here:  do you mean all the LHS of .DEFERRED_INIT call are not properly gimplified, or
>>>> Only the LHS of .DEFERRED_INIT call for VLA are not properly gimplified?
>>> 
>>> Especially in the VLA case but likely also in general (though unlikely
>>> since usually the receiver of initializations are simple enough).  I'd
>>> expect the VLA case end up as
>>> 
>>> *ptr_to_decl = .DEFERRED_INIT (...);
>>> 
>>> where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.
>> 
>> So, for the following small testing case:
>> 
>> ====
>> extern void bar (int);
>> 
>> void foo(int n)
>> {
>>  int arr[n];
>>  bar (arr[2]);
>>  return;
>> }
>> =====
>> 
>> If I compile it with -ftrivial-auto-var-init=zero -fdump-tree-gimple -S -o auto-init-11.s -fdump-rtl-expand, the *.gimple dump is:
>> 
>> =====
>> void foo (int n)
>> {
>>  int n.0;
>>  sizetype D.1950;
>>  bitsizetype D.1951;
>>  sizetype D.1952;
>>  bitsizetype D.1953;
>>  sizetype D.1954;
>>  int[0:D.1950] * arr.1;
>>  void * saved_stack.2;
>>  int arr[0:D.1950] [value-expr: *arr.1];
>> 
>>  saved_stack.2 = __builtin_stack_save ();
>>  try
>>    {
>>      n.0 = n;
>>      _1 = (long int) n.0;
>>      _2 = _1 + -1;
>>      _3 = (sizetype) _2;
>>      D.1950 = _3;
>>      _4 = (sizetype) n.0;
>>      _5 = (bitsizetype) _4;
>>      _6 = _5 * 32;
>>      D.1951 = _6;
>>      _7 = (sizetype) n.0;
>>      _8 = _7 * 4;
>>      D.1952 = _8;
>>      _9 = (sizetype) n.0;
>>      _10 = (bitsizetype) _9;
>>      _11 = _10 * 32;
>>      D.1953 = _11;
>>      _12 = (sizetype) n.0;
>>      _13 = _12 * 4;
>>      D.1954 = _13;
>>      arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>      arr = .DEFERRED_INIT (D.1952, 2, 1);
>>      _14 = (*arr.1)[2];
>>      bar (_14);
>>      return;
>>    }
>>  finally
>>    {
>>      __builtin_stack_restore (saved_stack.2);
>>    }
>> }
>> 
>> ====
>> 
>> You think that the above .DEFEERED_INIT is not correct?
>> It should be:
>> 
>> *arr.1 = .DEFERRED_INIT (D.1952. 2, 1);
>> 
>> ?
> 
> Yes.
> 
>>> 
>>>> What do you mean by “such” decl? A decl whole “DECL_VALUE_EXPR(DECL)” is valid?
>>> 
>>> A 'decl' that has a DECL_VALUE_EXPR should not appear in the IL, it should
>>> always be refered to as its DECL_VALUE_EXPR.
>> 
>> Okay.
> 
> I'm going to test
> 
> diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c
> index ebf7eea3b04..15c73b6d6f4 100644
> --- a/gcc/tree-ssa-operands.c
> +++ b/gcc/tree-ssa-operands.c
> @@ -799,10 +799,11 @@ operands_scanner::get_expr_operands (tree *expr_p, 
> int flags)
>                         flags | opf_not_non_addressable | 
> opf_address_taken);
>       return;
> 
> -    case SSA_NAME:
>     case VAR_DECL:
>     case PARM_DECL:
>     case RESULT_DECL:
> +      gcc_checking_assert (!DECL_HAS_VALUE_EXPR_P (expr));
> +    case SSA_NAME:
>     case STRING_CST:
>     case CONST_DECL:
>       if (!(flags & opf_address_taken))
> 
> which should pass on unmodified trunk (fingers crossing ;)), but
> it would likely trip on the current -ftrivial-auto-init patch.
I will try this. 
> 
> The issue with the current IL is that nothing keeps arr.1 live
> and thus the allocation could be DCEd but the .DEFERRED_INIT
> call would remain, eventually being expanded to zero storage
> that isn't there.

Okay, I see now.
Will updated the VLA part in gimplify.c and internal-fn.c.

Qing

> 
> Richard.


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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-10 15:22             ` Richard Biener
  2021-08-10 15:55               ` Qing Zhao
@ 2021-08-10 20:16               ` Qing Zhao
  2021-08-10 22:26                 ` Qing Zhao
  1 sibling, 1 reply; 60+ messages in thread
From: Qing Zhao @ 2021-08-10 20:16 UTC (permalink / raw)
  To: Richard Biener
  Cc: Martin Jambor, Jakub Jelinek, Kees Cook,
	Nick Alcock via Gcc-patches, Richard Biener

Hi, Richard,

> On Aug 10, 2021, at 10:22 AM, Richard Biener <rguenther@suse.de> wrote:
>>> 
>>> Especially in the VLA case but likely also in general (though unlikely
>>> since usually the receiver of initializations are simple enough).  I'd
>>> expect the VLA case end up as
>>> 
>>> *ptr_to_decl = .DEFERRED_INIT (...);
>>> 
>>> where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.
>> 
>> So, for the following small testing case:
>> 
>> ====
>> extern void bar (int);
>> 
>> void foo(int n)
>> {
>>  int arr[n];
>>  bar (arr[2]);
>>  return;
>> }
>> =====
>> 
>> If I compile it with -ftrivial-auto-var-init=zero -fdump-tree-gimple -S -o auto-init-11.s -fdump-rtl-expand, the *.gimple dump is:
>> 
>> =====
>> void foo (int n)
>> {
>>  int n.0;
>>  sizetype D.1950;
>>  bitsizetype D.1951;
>>  sizetype D.1952;
>>  bitsizetype D.1953;
>>  sizetype D.1954;
>>  int[0:D.1950] * arr.1;
>>  void * saved_stack.2;
>>  int arr[0:D.1950] [value-expr: *arr.1];
>> 
>>  saved_stack.2 = __builtin_stack_save ();
>>  try
>>    {
>>      n.0 = n;
>>      _1 = (long int) n.0;
>>      _2 = _1 + -1;
>>      _3 = (sizetype) _2;
>>      D.1950 = _3;
>>      _4 = (sizetype) n.0;
>>      _5 = (bitsizetype) _4;
>>      _6 = _5 * 32;
>>      D.1951 = _6;
>>      _7 = (sizetype) n.0;
>>      _8 = _7 * 4;
>>      D.1952 = _8;
>>      _9 = (sizetype) n.0;
>>      _10 = (bitsizetype) _9;
>>      _11 = _10 * 32;
>>      D.1953 = _11;
>>      _12 = (sizetype) n.0;
>>      _13 = _12 * 4;
>>      D.1954 = _13;
>>      arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>      arr = .DEFERRED_INIT (D.1952, 2, 1);
>>      _14 = (*arr.1)[2];
>>      bar (_14);
>>      return;
>>    }
>>  finally
>>    {
>>      __builtin_stack_restore (saved_stack.2);
>>    }
>> }
>> 
>> ====
>> 
>> You think that the above .DEFEERED_INIT is not correct?
>> It should be:
>> 
>> *arr.1 = .DEFERRED_INIT (D.1952. 2, 1);
>> 
>> ?
> 
> Yes.
> 

I updated gimplify.c for VLA and now it emits the call to .DEFERRED_INIT as:

      arr.1 = __builtin_alloca_with_align (D.1954, 32);
      *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);

However, this call triggered the assertion failure in verify_gimple_call of tree-cfg.c because the LHS is not a valid LHS. 
Then I modify tree-cfg.c as:

diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 330eb7dd89bf..180d4f1f9e32 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -3375,7 +3375,11 @@ verify_gimple_call (gcall *stmt)
      }
 
   tree lhs = gimple_call_lhs (stmt);
+  /* For .DEFERRED_INIT call, the LHS might be an indirection of
+     a pointer for the VLA variable, which is not a valid LHS of
+     a gimple call, we ignore the asssertion on this.  */ 
   if (lhs
+      && (!gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
       && (!is_gimple_reg (lhs)
          && (!is_gimple_lvalue (lhs)
              || verify_types_in_gimple_reference

The assertion failure in tree-cfg.c got resolved, but I got another assertion failure in operands_scanner::get_expr_operands (tree *expr_p, int flags), line 945:

 939   /* If we get here, something has gone wrong.  */
 940   if (flag_checking)
 941     {
 942       fprintf (stderr, "unhandled expression in get_expr_operands():\n");
 943       debug_tree (expr);
 944       fputs ("\n", stderr);
 945       gcc_unreachable ();
 946     }

Looks like that  the gimple statement:
    *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);

Is not valid.  i.e, the LHS should not be an indirection to a pointer. 

How to resolve this issue?

Thanks a lot for your help.

Qing
>>> 
>>>> What do you mean by “such” decl? A decl whole “DECL_VALUE_EXPR(DECL)” is valid?
>>> 
>>> A 'decl' that has a DECL_VALUE_EXPR should not appear in the IL, it should
>>> always be refered to as its DECL_VALUE_EXPR.
>> 
>> Okay.
> 
> I'm going to test
> 
> diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c
> index ebf7eea3b04..15c73b6d6f4 100644
> --- a/gcc/tree-ssa-operands.c
> +++ b/gcc/tree-ssa-operands.c
> @@ -799,10 +799,11 @@ operands_scanner::get_expr_operands (tree *expr_p, 
> int flags)
>                         flags | opf_not_non_addressable | 
> opf_address_taken);
>       return;
> 
> -    case SSA_NAME:
>     case VAR_DECL:
>     case PARM_DECL:
>     case RESULT_DECL:
> +      gcc_checking_assert (!DECL_HAS_VALUE_EXPR_P (expr));
> +    case SSA_NAME:
>     case STRING_CST:
>     case CONST_DECL:
>       if (!(flags & opf_address_taken))
> 
> which should pass on unmodified trunk (fingers crossing ;)), but
> it would likely trip on the current -ftrivial-auto-init patch.
> 
> The issue with the current IL is that nothing keeps arr.1 live
> and thus the allocation could be DCEd but the .DEFERRED_INIT
> call would remain, eventually being expanded to zero storage
> that isn't there.
> 
> Richard.


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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-10 20:16               ` Qing Zhao
@ 2021-08-10 22:26                 ` Qing Zhao
  2021-08-11  7:02                   ` Richard Biener
  2021-08-11  9:02                   ` Richard Sandiford
  0 siblings, 2 replies; 60+ messages in thread
From: Qing Zhao @ 2021-08-10 22:26 UTC (permalink / raw)
  To: Qing Zhao, Richard Biener
  Cc: Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook



> On Aug 10, 2021, at 3:16 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> 
> Hi, Richard,
> 
>> On Aug 10, 2021, at 10:22 AM, Richard Biener <rguenther@suse.de> wrote:
>>>> 
>>>> Especially in the VLA case but likely also in general (though unlikely
>>>> since usually the receiver of initializations are simple enough).  I'd
>>>> expect the VLA case end up as
>>>> 
>>>> *ptr_to_decl = .DEFERRED_INIT (...);
>>>> 
>>>> where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.
>>> 
>>> So, for the following small testing case:
>>> 
>>> ====
>>> extern void bar (int);
>>> 
>>> void foo(int n)
>>> {
>>> int arr[n];
>>> bar (arr[2]);
>>> return;
>>> }
>>> =====
>>> 
>>> If I compile it with -ftrivial-auto-var-init=zero -fdump-tree-gimple -S -o auto-init-11.s -fdump-rtl-expand, the *.gimple dump is:
>>> 
>>> =====
>>> void foo (int n)
>>> {
>>> int n.0;
>>> sizetype D.1950;
>>> bitsizetype D.1951;
>>> sizetype D.1952;
>>> bitsizetype D.1953;
>>> sizetype D.1954;
>>> int[0:D.1950] * arr.1;
>>> void * saved_stack.2;
>>> int arr[0:D.1950] [value-expr: *arr.1];
>>> 
>>> saved_stack.2 = __builtin_stack_save ();
>>> try
>>>   {
>>>     n.0 = n;
>>>     _1 = (long int) n.0;
>>>     _2 = _1 + -1;
>>>     _3 = (sizetype) _2;
>>>     D.1950 = _3;
>>>     _4 = (sizetype) n.0;
>>>     _5 = (bitsizetype) _4;
>>>     _6 = _5 * 32;
>>>     D.1951 = _6;
>>>     _7 = (sizetype) n.0;
>>>     _8 = _7 * 4;
>>>     D.1952 = _8;
>>>     _9 = (sizetype) n.0;
>>>     _10 = (bitsizetype) _9;
>>>     _11 = _10 * 32;
>>>     D.1953 = _11;
>>>     _12 = (sizetype) n.0;
>>>     _13 = _12 * 4;
>>>     D.1954 = _13;
>>>     arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>     arr = .DEFERRED_INIT (D.1952, 2, 1);
>>>     _14 = (*arr.1)[2];
>>>     bar (_14);
>>>     return;
>>>   }
>>> finally
>>>   {
>>>     __builtin_stack_restore (saved_stack.2);
>>>   }
>>> }
>>> 
>>> ====
>>> 
>>> You think that the above .DEFEERED_INIT is not correct?
>>> It should be:
>>> 
>>> *arr.1 = .DEFERRED_INIT (D.1952. 2, 1);
>>> 
>>> ?
>> 
>> Yes.
>> 
> 
> I updated gimplify.c for VLA and now it emits the call to .DEFERRED_INIT as:
> 
>      arr.1 = __builtin_alloca_with_align (D.1954, 32);
>      *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
> 
> However, this call triggered the assertion failure in verify_gimple_call of tree-cfg.c because the LHS is not a valid LHS. 
> Then I modify tree-cfg.c as:
> 
> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
> index 330eb7dd89bf..180d4f1f9e32 100644
> --- a/gcc/tree-cfg.c
> +++ b/gcc/tree-cfg.c
> @@ -3375,7 +3375,11 @@ verify_gimple_call (gcall *stmt)
>      }
> 
>   tree lhs = gimple_call_lhs (stmt);
> +  /* For .DEFERRED_INIT call, the LHS might be an indirection of
> +     a pointer for the VLA variable, which is not a valid LHS of
> +     a gimple call, we ignore the asssertion on this.  */ 
>   if (lhs
> +      && (!gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
>       && (!is_gimple_reg (lhs)
>          && (!is_gimple_lvalue (lhs)
>              || verify_types_in_gimple_reference
> 
> The assertion failure in tree-cfg.c got resolved, but I got another assertion failure in operands_scanner::get_expr_operands (tree *expr_p, int flags), line 945:
> 
> 939   /* If we get here, something has gone wrong.  */
> 940   if (flag_checking)
> 941     {
> 942       fprintf (stderr, "unhandled expression in get_expr_operands():\n");
> 943       debug_tree (expr);
> 944       fputs ("\n", stderr);
> 945       gcc_unreachable ();
> 946     }
> 
> Looks like that  the gimple statement:
>    *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
> 
> Is not valid.  i.e, the LHS should not be an indirection to a pointer. 
> 
> How to resolve this issue?

I came up with the following solution:

Define the IFN_DEFERRED_INIT function as:

   LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA);

   if IS_VLA is false, the LHS is the DECL itself,
   if IS_VLA is true, the LHS is the pointer to this DECL that created by
   gimplify_vla_decl.


The benefit of this solution are:

1. Resolved the invalid IR issue;
2. The call stmt carries the address of the VLA natually;

The issue with this solution is:

For VLA and non-VLA, the LHS will be different, 

Do you see any other potential issues with this solution?

thanks.

Qing





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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-10 22:26                 ` Qing Zhao
@ 2021-08-11  7:02                   ` Richard Biener
  2021-08-11 13:33                     ` Qing Zhao
  2021-08-11  9:02                   ` Richard Sandiford
  1 sibling, 1 reply; 60+ messages in thread
From: Richard Biener @ 2021-08-11  7:02 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook

On Tue, 10 Aug 2021, Qing Zhao wrote:

> 
> 
> > On Aug 10, 2021, at 3:16 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> > 
> > Hi, Richard,
> > 
> >> On Aug 10, 2021, at 10:22 AM, Richard Biener <rguenther@suse.de> wrote:
> >>>> 
> >>>> Especially in the VLA case but likely also in general (though unlikely
> >>>> since usually the receiver of initializations are simple enough).  I'd
> >>>> expect the VLA case end up as
> >>>> 
> >>>> *ptr_to_decl = .DEFERRED_INIT (...);
> >>>> 
> >>>> where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.
> >>> 
> >>> So, for the following small testing case:
> >>> 
> >>> ====
> >>> extern void bar (int);
> >>> 
> >>> void foo(int n)
> >>> {
> >>> int arr[n];
> >>> bar (arr[2]);
> >>> return;
> >>> }
> >>> =====
> >>> 
> >>> If I compile it with -ftrivial-auto-var-init=zero -fdump-tree-gimple -S -o auto-init-11.s -fdump-rtl-expand, the *.gimple dump is:
> >>> 
> >>> =====
> >>> void foo (int n)
> >>> {
> >>> int n.0;
> >>> sizetype D.1950;
> >>> bitsizetype D.1951;
> >>> sizetype D.1952;
> >>> bitsizetype D.1953;
> >>> sizetype D.1954;
> >>> int[0:D.1950] * arr.1;
> >>> void * saved_stack.2;
> >>> int arr[0:D.1950] [value-expr: *arr.1];
> >>> 
> >>> saved_stack.2 = __builtin_stack_save ();
> >>> try
> >>>   {
> >>>     n.0 = n;
> >>>     _1 = (long int) n.0;
> >>>     _2 = _1 + -1;
> >>>     _3 = (sizetype) _2;
> >>>     D.1950 = _3;
> >>>     _4 = (sizetype) n.0;
> >>>     _5 = (bitsizetype) _4;
> >>>     _6 = _5 * 32;
> >>>     D.1951 = _6;
> >>>     _7 = (sizetype) n.0;
> >>>     _8 = _7 * 4;
> >>>     D.1952 = _8;
> >>>     _9 = (sizetype) n.0;
> >>>     _10 = (bitsizetype) _9;
> >>>     _11 = _10 * 32;
> >>>     D.1953 = _11;
> >>>     _12 = (sizetype) n.0;
> >>>     _13 = _12 * 4;
> >>>     D.1954 = _13;
> >>>     arr.1 = __builtin_alloca_with_align (D.1954, 32);
> >>>     arr = .DEFERRED_INIT (D.1952, 2, 1);
> >>>     _14 = (*arr.1)[2];
> >>>     bar (_14);
> >>>     return;
> >>>   }
> >>> finally
> >>>   {
> >>>     __builtin_stack_restore (saved_stack.2);
> >>>   }
> >>> }
> >>> 
> >>> ====
> >>> 
> >>> You think that the above .DEFEERED_INIT is not correct?
> >>> It should be:
> >>> 
> >>> *arr.1 = .DEFERRED_INIT (D.1952. 2, 1);
> >>> 
> >>> ?
> >> 
> >> Yes.
> >> 
> > 
> > I updated gimplify.c for VLA and now it emits the call to .DEFERRED_INIT as:
> > 
> >      arr.1 = __builtin_alloca_with_align (D.1954, 32);
> >      *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
> > 
> > However, this call triggered the assertion failure in verify_gimple_call of tree-cfg.c because the LHS is not a valid LHS. 
> > Then I modify tree-cfg.c as:
> > 
> > diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
> > index 330eb7dd89bf..180d4f1f9e32 100644
> > --- a/gcc/tree-cfg.c
> > +++ b/gcc/tree-cfg.c
> > @@ -3375,7 +3375,11 @@ verify_gimple_call (gcall *stmt)
> >      }
> > 
> >   tree lhs = gimple_call_lhs (stmt);
> > +  /* For .DEFERRED_INIT call, the LHS might be an indirection of
> > +     a pointer for the VLA variable, which is not a valid LHS of
> > +     a gimple call, we ignore the asssertion on this.  */ 
> >   if (lhs
> > +      && (!gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
> >       && (!is_gimple_reg (lhs)
> >          && (!is_gimple_lvalue (lhs)
> >              || verify_types_in_gimple_reference
> > 
> > The assertion failure in tree-cfg.c got resolved, but I got another assertion failure in operands_scanner::get_expr_operands (tree *expr_p, int flags), line 945:
> > 
> > 939   /* If we get here, something has gone wrong.  */
> > 940   if (flag_checking)
> > 941     {
> > 942       fprintf (stderr, "unhandled expression in get_expr_operands():\n");
> > 943       debug_tree (expr);
> > 944       fputs ("\n", stderr);
> > 945       gcc_unreachable ();
> > 946     }
> > 
> > Looks like that  the gimple statement:
> >    *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
> > 
> > Is not valid.  i.e, the LHS should not be an indirection to a pointer. 
> > 
> > How to resolve this issue?

It sounds like the LHS is an INDIRECT_REF maybe?  That means it's
still not properly gimplified because it should end up as a MEM_REF
instead.

But I'm just guessing here ... if you are in a debugger then you can
invoke debug_tree (lhs) in the inferior to see what it exactly is
at the point of the failure.

> I came up with the following solution:
> 
> Define the IFN_DEFERRED_INIT function as:
> 
>    LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA);
> 
>    if IS_VLA is false, the LHS is the DECL itself,
>    if IS_VLA is true, the LHS is the pointer to this DECL that created by
>    gimplify_vla_decl.
> 
> 
> The benefit of this solution are:
> 
> 1. Resolved the invalid IR issue;
> 2. The call stmt carries the address of the VLA natually;
> 
> The issue with this solution is:
> 
> For VLA and non-VLA, the LHS will be different, 
> 
> Do you see any other potential issues with this solution?
> 
> thanks.
> 
> Qing
> 
> 
> 
> 
> 

-- 
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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-10 22:26                 ` Qing Zhao
  2021-08-11  7:02                   ` Richard Biener
@ 2021-08-11  9:02                   ` Richard Sandiford
  2021-08-11 13:44                     ` Qing Zhao
  1 sibling, 1 reply; 60+ messages in thread
From: Richard Sandiford @ 2021-08-11  9:02 UTC (permalink / raw)
  To: Qing Zhao via Gcc-patches
  Cc: Qing Zhao, Richard Biener, Jakub Jelinek, Kees Cook

Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
>> On Aug 10, 2021, at 3:16 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>> 
>> Hi, Richard,
>> 
>>> On Aug 10, 2021, at 10:22 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>> 
>>>>> Especially in the VLA case but likely also in general (though unlikely
>>>>> since usually the receiver of initializations are simple enough).  I'd
>>>>> expect the VLA case end up as
>>>>> 
>>>>> *ptr_to_decl = .DEFERRED_INIT (...);
>>>>> 
>>>>> where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.
>>>> 
>>>> So, for the following small testing case:
>>>> 
>>>> ====
>>>> extern void bar (int);
>>>> 
>>>> void foo(int n)
>>>> {
>>>> int arr[n];
>>>> bar (arr[2]);
>>>> return;
>>>> }
>>>> =====
>>>> 
>>>> If I compile it with -ftrivial-auto-var-init=zero -fdump-tree-gimple -S -o auto-init-11.s -fdump-rtl-expand, the *.gimple dump is:
>>>> 
>>>> =====
>>>> void foo (int n)
>>>> {
>>>> int n.0;
>>>> sizetype D.1950;
>>>> bitsizetype D.1951;
>>>> sizetype D.1952;
>>>> bitsizetype D.1953;
>>>> sizetype D.1954;
>>>> int[0:D.1950] * arr.1;
>>>> void * saved_stack.2;
>>>> int arr[0:D.1950] [value-expr: *arr.1];
>>>> 
>>>> saved_stack.2 = __builtin_stack_save ();
>>>> try
>>>>   {
>>>>     n.0 = n;
>>>>     _1 = (long int) n.0;
>>>>     _2 = _1 + -1;
>>>>     _3 = (sizetype) _2;
>>>>     D.1950 = _3;
>>>>     _4 = (sizetype) n.0;
>>>>     _5 = (bitsizetype) _4;
>>>>     _6 = _5 * 32;
>>>>     D.1951 = _6;
>>>>     _7 = (sizetype) n.0;
>>>>     _8 = _7 * 4;
>>>>     D.1952 = _8;
>>>>     _9 = (sizetype) n.0;
>>>>     _10 = (bitsizetype) _9;
>>>>     _11 = _10 * 32;
>>>>     D.1953 = _11;
>>>>     _12 = (sizetype) n.0;
>>>>     _13 = _12 * 4;
>>>>     D.1954 = _13;
>>>>     arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>     arr = .DEFERRED_INIT (D.1952, 2, 1);
>>>>     _14 = (*arr.1)[2];
>>>>     bar (_14);
>>>>     return;
>>>>   }
>>>> finally
>>>>   {
>>>>     __builtin_stack_restore (saved_stack.2);
>>>>   }
>>>> }
>>>> 
>>>> ====
>>>> 
>>>> You think that the above .DEFEERED_INIT is not correct?
>>>> It should be:
>>>> 
>>>> *arr.1 = .DEFERRED_INIT (D.1952. 2, 1);
>>>> 
>>>> ?
>>> 
>>> Yes.
>>> 
>> 
>> I updated gimplify.c for VLA and now it emits the call to .DEFERRED_INIT as:
>> 
>>      arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>      *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>> 
>> However, this call triggered the assertion failure in verify_gimple_call of tree-cfg.c because the LHS is not a valid LHS. 
>> Then I modify tree-cfg.c as:
>> 
>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
>> index 330eb7dd89bf..180d4f1f9e32 100644
>> --- a/gcc/tree-cfg.c
>> +++ b/gcc/tree-cfg.c
>> @@ -3375,7 +3375,11 @@ verify_gimple_call (gcall *stmt)
>>      }
>> 
>>   tree lhs = gimple_call_lhs (stmt);
>> +  /* For .DEFERRED_INIT call, the LHS might be an indirection of
>> +     a pointer for the VLA variable, which is not a valid LHS of
>> +     a gimple call, we ignore the asssertion on this.  */ 
>>   if (lhs
>> +      && (!gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
>>       && (!is_gimple_reg (lhs)
>>          && (!is_gimple_lvalue (lhs)
>>              || verify_types_in_gimple_reference
>> 
>> The assertion failure in tree-cfg.c got resolved, but I got another assertion failure in operands_scanner::get_expr_operands (tree *expr_p, int flags), line 945:
>> 
>> 939   /* If we get here, something has gone wrong.  */
>> 940   if (flag_checking)
>> 941     {
>> 942       fprintf (stderr, "unhandled expression in get_expr_operands():\n");
>> 943       debug_tree (expr);
>> 944       fputs ("\n", stderr);
>> 945       gcc_unreachable ();
>> 946     }
>> 
>> Looks like that  the gimple statement:
>>    *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>> 
>> Is not valid.  i.e, the LHS should not be an indirection to a pointer. 
>> 
>> How to resolve this issue?
>
> I came up with the following solution:
>
> Define the IFN_DEFERRED_INIT function as:
>
>    LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA);
>
>    if IS_VLA is false, the LHS is the DECL itself,
>    if IS_VLA is true, the LHS is the pointer to this DECL that created by
>    gimplify_vla_decl.
>
>
> The benefit of this solution are:
>
> 1. Resolved the invalid IR issue;
> 2. The call stmt carries the address of the VLA natually;
>
> The issue with this solution is:
>
> For VLA and non-VLA, the LHS will be different, 
>
> Do you see any other potential issues with this solution?

The idea behind the DECL version of the .DEFERRED_INIT semantics was
that .DEFERRED_INIT just returns a SIZE-byte value that the caller
then assigns to a SIZE-byte lhs (with the caller choosing the lhs).
.DEFEREED_INIT itself doesn't read or write memory and so can be const,
which in turn allows alias analysis to be more precise.

If we want to handle the VLA case using pointers instead then I think
that needs to be a different IFN.

If we did handle the VLA case using pointers (not expressing an opinion
on that), then it would be the caller's job to allocate the VLA and work
out the address of the VLA; this isn't something that .DEFERRED_INIT
would work out on the caller's behalf.  The address of the VLA should
therefore be an argument to the new IFN, rather than something that
the IFN returns.

Thanks,
Richard


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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-11  7:02                   ` Richard Biener
@ 2021-08-11 13:33                     ` Qing Zhao
  2021-08-11 13:37                       ` Richard Biener
  0 siblings, 1 reply; 60+ messages in thread
From: Qing Zhao @ 2021-08-11 13:33 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook



> On Aug 11, 2021, at 2:02 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Tue, 10 Aug 2021, Qing Zhao wrote:
> 
>> 
>> 
>>> On Aug 10, 2021, at 3:16 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>> 
>>> Hi, Richard,
>>> 
>>>> On Aug 10, 2021, at 10:22 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>> 
>>>>>> Especially in the VLA case but likely also in general (though unlikely
>>>>>> since usually the receiver of initializations are simple enough).  I'd
>>>>>> expect the VLA case end up as
>>>>>> 
>>>>>> *ptr_to_decl = .DEFERRED_INIT (...);
>>>>>> 
>>>>>> where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.
>>>>> 
>>>>> So, for the following small testing case:
>>>>> 
>>>>> ====
>>>>> extern void bar (int);
>>>>> 
>>>>> void foo(int n)
>>>>> {
>>>>> int arr[n];
>>>>> bar (arr[2]);
>>>>> return;
>>>>> }
>>>>> =====
>>>>> 
>>>>> If I compile it with -ftrivial-auto-var-init=zero -fdump-tree-gimple -S -o auto-init-11.s -fdump-rtl-expand, the *.gimple dump is:
>>>>> 
>>>>> =====
>>>>> void foo (int n)
>>>>> {
>>>>> int n.0;
>>>>> sizetype D.1950;
>>>>> bitsizetype D.1951;
>>>>> sizetype D.1952;
>>>>> bitsizetype D.1953;
>>>>> sizetype D.1954;
>>>>> int[0:D.1950] * arr.1;
>>>>> void * saved_stack.2;
>>>>> int arr[0:D.1950] [value-expr: *arr.1];
>>>>> 
>>>>> saved_stack.2 = __builtin_stack_save ();
>>>>> try
>>>>>  {
>>>>>    n.0 = n;
>>>>>    _1 = (long int) n.0;
>>>>>    _2 = _1 + -1;
>>>>>    _3 = (sizetype) _2;
>>>>>    D.1950 = _3;
>>>>>    _4 = (sizetype) n.0;
>>>>>    _5 = (bitsizetype) _4;
>>>>>    _6 = _5 * 32;
>>>>>    D.1951 = _6;
>>>>>    _7 = (sizetype) n.0;
>>>>>    _8 = _7 * 4;
>>>>>    D.1952 = _8;
>>>>>    _9 = (sizetype) n.0;
>>>>>    _10 = (bitsizetype) _9;
>>>>>    _11 = _10 * 32;
>>>>>    D.1953 = _11;
>>>>>    _12 = (sizetype) n.0;
>>>>>    _13 = _12 * 4;
>>>>>    D.1954 = _13;
>>>>>    arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>>    arr = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>    _14 = (*arr.1)[2];
>>>>>    bar (_14);
>>>>>    return;
>>>>>  }
>>>>> finally
>>>>>  {
>>>>>    __builtin_stack_restore (saved_stack.2);
>>>>>  }
>>>>> }
>>>>> 
>>>>> ====
>>>>> 
>>>>> You think that the above .DEFEERED_INIT is not correct?
>>>>> It should be:
>>>>> 
>>>>> *arr.1 = .DEFERRED_INIT (D.1952. 2, 1);
>>>>> 
>>>>> ?
>>>> 
>>>> Yes.
>>>> 
>>> 
>>> I updated gimplify.c for VLA and now it emits the call to .DEFERRED_INIT as:
>>> 
>>>     arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>     *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>> 
>>> However, this call triggered the assertion failure in verify_gimple_call of tree-cfg.c because the LHS is not a valid LHS. 
>>> Then I modify tree-cfg.c as:
>>> 
>>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
>>> index 330eb7dd89bf..180d4f1f9e32 100644
>>> --- a/gcc/tree-cfg.c
>>> +++ b/gcc/tree-cfg.c
>>> @@ -3375,7 +3375,11 @@ verify_gimple_call (gcall *stmt)
>>>     }
>>> 
>>>  tree lhs = gimple_call_lhs (stmt);
>>> +  /* For .DEFERRED_INIT call, the LHS might be an indirection of
>>> +     a pointer for the VLA variable, which is not a valid LHS of
>>> +     a gimple call, we ignore the asssertion on this.  */ 
>>>  if (lhs
>>> +      && (!gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
>>>      && (!is_gimple_reg (lhs)
>>>         && (!is_gimple_lvalue (lhs)
>>>             || verify_types_in_gimple_reference
>>> 
>>> The assertion failure in tree-cfg.c got resolved, but I got another assertion failure in operands_scanner::get_expr_operands (tree *expr_p, int flags), line 945:
>>> 
>>> 939   /* If we get here, something has gone wrong.  */
>>> 940   if (flag_checking)
>>> 941     {
>>> 942       fprintf (stderr, "unhandled expression in get_expr_operands():\n");
>>> 943       debug_tree (expr);
>>> 944       fputs ("\n", stderr);
>>> 945       gcc_unreachable ();
>>> 946     }
>>> 
>>> Looks like that  the gimple statement:
>>>   *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>> 
>>> Is not valid.  i.e, the LHS should not be an indirection to a pointer. 
>>> 
>>> How to resolve this issue?
> 
> It sounds like the LHS is an INDIRECT_REF maybe?  That means it's
> still not properly gimplified because it should end up as a MEM_REF
> instead.
> 
> But I'm just guessing here ... if you are in a debugger then you can
> invoke debug_tree (lhs) in the inferior to see what it exactly is
> at the point of the failure.

Yes, it’s an INDIRECT_REF at the point of the failure even though I added a 

gimplify_var_or_parm_decl  (lhs) 

Qing

> 
>> I came up with the following solution:
>> 
>> Define the IFN_DEFERRED_INIT function as:
>> 
>>   LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA);
>> 
>>   if IS_VLA is false, the LHS is the DECL itself,
>>   if IS_VLA is true, the LHS is the pointer to this DECL that created by
>>   gimplify_vla_decl.
>> 
>> 
>> The benefit of this solution are:
>> 
>> 1. Resolved the invalid IR issue;
>> 2. The call stmt carries the address of the VLA natually;
>> 
>> The issue with this solution is:
>> 
>> For VLA and non-VLA, the LHS will be different, 
>> 
>> Do you see any other potential issues with this solution?
>> 
>> thanks.
>> 
>> Qing
>> 
>> 
>> 
>> 
>> 
> 
> -- 
> 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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-11 13:33                     ` Qing Zhao
@ 2021-08-11 13:37                       ` Richard Biener
  2021-08-11 13:54                         ` Qing Zhao
  0 siblings, 1 reply; 60+ messages in thread
From: Richard Biener @ 2021-08-11 13:37 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook

On Wed, 11 Aug 2021, Qing Zhao wrote:

> 
> 
> > On Aug 11, 2021, at 2:02 AM, Richard Biener <rguenther@suse.de> wrote:
> > 
> > On Tue, 10 Aug 2021, Qing Zhao wrote:
> > 
> >> 
> >> 
> >>> On Aug 10, 2021, at 3:16 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> >>> 
> >>> Hi, Richard,
> >>> 
> >>>> On Aug 10, 2021, at 10:22 AM, Richard Biener <rguenther@suse.de> wrote:
> >>>>>> 
> >>>>>> Especially in the VLA case but likely also in general (though unlikely
> >>>>>> since usually the receiver of initializations are simple enough).  I'd
> >>>>>> expect the VLA case end up as
> >>>>>> 
> >>>>>> *ptr_to_decl = .DEFERRED_INIT (...);
> >>>>>> 
> >>>>>> where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.
> >>>>> 
> >>>>> So, for the following small testing case:
> >>>>> 
> >>>>> ====
> >>>>> extern void bar (int);
> >>>>> 
> >>>>> void foo(int n)
> >>>>> {
> >>>>> int arr[n];
> >>>>> bar (arr[2]);
> >>>>> return;
> >>>>> }
> >>>>> =====
> >>>>> 
> >>>>> If I compile it with -ftrivial-auto-var-init=zero -fdump-tree-gimple -S -o auto-init-11.s -fdump-rtl-expand, the *.gimple dump is:
> >>>>> 
> >>>>> =====
> >>>>> void foo (int n)
> >>>>> {
> >>>>> int n.0;
> >>>>> sizetype D.1950;
> >>>>> bitsizetype D.1951;
> >>>>> sizetype D.1952;
> >>>>> bitsizetype D.1953;
> >>>>> sizetype D.1954;
> >>>>> int[0:D.1950] * arr.1;
> >>>>> void * saved_stack.2;
> >>>>> int arr[0:D.1950] [value-expr: *arr.1];
> >>>>> 
> >>>>> saved_stack.2 = __builtin_stack_save ();
> >>>>> try
> >>>>>  {
> >>>>>    n.0 = n;
> >>>>>    _1 = (long int) n.0;
> >>>>>    _2 = _1 + -1;
> >>>>>    _3 = (sizetype) _2;
> >>>>>    D.1950 = _3;
> >>>>>    _4 = (sizetype) n.0;
> >>>>>    _5 = (bitsizetype) _4;
> >>>>>    _6 = _5 * 32;
> >>>>>    D.1951 = _6;
> >>>>>    _7 = (sizetype) n.0;
> >>>>>    _8 = _7 * 4;
> >>>>>    D.1952 = _8;
> >>>>>    _9 = (sizetype) n.0;
> >>>>>    _10 = (bitsizetype) _9;
> >>>>>    _11 = _10 * 32;
> >>>>>    D.1953 = _11;
> >>>>>    _12 = (sizetype) n.0;
> >>>>>    _13 = _12 * 4;
> >>>>>    D.1954 = _13;
> >>>>>    arr.1 = __builtin_alloca_with_align (D.1954, 32);
> >>>>>    arr = .DEFERRED_INIT (D.1952, 2, 1);
> >>>>>    _14 = (*arr.1)[2];
> >>>>>    bar (_14);
> >>>>>    return;
> >>>>>  }
> >>>>> finally
> >>>>>  {
> >>>>>    __builtin_stack_restore (saved_stack.2);
> >>>>>  }
> >>>>> }
> >>>>> 
> >>>>> ====
> >>>>> 
> >>>>> You think that the above .DEFEERED_INIT is not correct?
> >>>>> It should be:
> >>>>> 
> >>>>> *arr.1 = .DEFERRED_INIT (D.1952. 2, 1);
> >>>>> 
> >>>>> ?
> >>>> 
> >>>> Yes.
> >>>> 
> >>> 
> >>> I updated gimplify.c for VLA and now it emits the call to .DEFERRED_INIT as:
> >>> 
> >>>     arr.1 = __builtin_alloca_with_align (D.1954, 32);
> >>>     *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
> >>> 
> >>> However, this call triggered the assertion failure in verify_gimple_call of tree-cfg.c because the LHS is not a valid LHS. 
> >>> Then I modify tree-cfg.c as:
> >>> 
> >>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
> >>> index 330eb7dd89bf..180d4f1f9e32 100644
> >>> --- a/gcc/tree-cfg.c
> >>> +++ b/gcc/tree-cfg.c
> >>> @@ -3375,7 +3375,11 @@ verify_gimple_call (gcall *stmt)
> >>>     }
> >>> 
> >>>  tree lhs = gimple_call_lhs (stmt);
> >>> +  /* For .DEFERRED_INIT call, the LHS might be an indirection of
> >>> +     a pointer for the VLA variable, which is not a valid LHS of
> >>> +     a gimple call, we ignore the asssertion on this.  */ 
> >>>  if (lhs
> >>> +      && (!gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
> >>>      && (!is_gimple_reg (lhs)
> >>>         && (!is_gimple_lvalue (lhs)
> >>>             || verify_types_in_gimple_reference
> >>> 
> >>> The assertion failure in tree-cfg.c got resolved, but I got another assertion failure in operands_scanner::get_expr_operands (tree *expr_p, int flags), line 945:
> >>> 
> >>> 939   /* If we get here, something has gone wrong.  */
> >>> 940   if (flag_checking)
> >>> 941     {
> >>> 942       fprintf (stderr, "unhandled expression in get_expr_operands():\n");
> >>> 943       debug_tree (expr);
> >>> 944       fputs ("\n", stderr);
> >>> 945       gcc_unreachable ();
> >>> 946     }
> >>> 
> >>> Looks like that  the gimple statement:
> >>>   *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
> >>> 
> >>> Is not valid.  i.e, the LHS should not be an indirection to a pointer. 
> >>> 
> >>> How to resolve this issue?
> > 
> > It sounds like the LHS is an INDIRECT_REF maybe?  That means it's
> > still not properly gimplified because it should end up as a MEM_REF
> > instead.
> > 
> > But I'm just guessing here ... if you are in a debugger then you can
> > invoke debug_tree (lhs) in the inferior to see what it exactly is
> > at the point of the failure.
> 
> Yes, it’s an INDIRECT_REF at the point of the failure even though I added a 
> 
> gimplify_var_or_parm_decl  (lhs) 

I think the easiest is to build the .DEFERRED_INIT as GENERIC
and use gimplify_assign () to gimplify and add the result
to the sequence.  Thus, build a GENERIC CALL_EXPR and then
gimplify_assign (lhs, call_expr, seq);

Richard.

> Qing
> 
> > 
> >> I came up with the following solution:
> >> 
> >> Define the IFN_DEFERRED_INIT function as:
> >> 
> >>   LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA);
> >> 
> >>   if IS_VLA is false, the LHS is the DECL itself,
> >>   if IS_VLA is true, the LHS is the pointer to this DECL that created by
> >>   gimplify_vla_decl.
> >> 
> >> 
> >> The benefit of this solution are:
> >> 
> >> 1. Resolved the invalid IR issue;
> >> 2. The call stmt carries the address of the VLA natually;
> >> 
> >> The issue with this solution is:
> >> 
> >> For VLA and non-VLA, the LHS will be different, 
> >> 
> >> Do you see any other potential issues with this solution?
> >> 
> >> thanks.
> >> 
> >> Qing
> >> 
> >> 
> >> 
> >> 
> >> 
> > 
> > -- 
> > Richard Biener <rguenther@suse.de>
> > SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> > Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
> 
> 

-- 
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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-11  9:02                   ` Richard Sandiford
@ 2021-08-11 13:44                     ` Qing Zhao
  2021-08-11 16:15                       ` Richard Sandiford
  0 siblings, 1 reply; 60+ messages in thread
From: Qing Zhao @ 2021-08-11 13:44 UTC (permalink / raw)
  To: Richard Sandiford
  Cc: Qing Zhao via Gcc-patches, Richard Biener, Jakub Jelinek, Kees Cook



> On Aug 11, 2021, at 4:02 AM, Richard Sandiford <richard.sandiford@arm.com> wrote:
> 
> Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
>>> On Aug 10, 2021, at 3:16 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>> 
>>> Hi, Richard,
>>> 
>>>> On Aug 10, 2021, at 10:22 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>> 
>>>>>> Especially in the VLA case but likely also in general (though unlikely
>>>>>> since usually the receiver of initializations are simple enough).  I'd
>>>>>> expect the VLA case end up as
>>>>>> 
>>>>>> *ptr_to_decl = .DEFERRED_INIT (...);
>>>>>> 
>>>>>> where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.
>>>>> 
>>>>> So, for the following small testing case:
>>>>> 
>>>>> ====
>>>>> extern void bar (int);
>>>>> 
>>>>> void foo(int n)
>>>>> {
>>>>> int arr[n];
>>>>> bar (arr[2]);
>>>>> return;
>>>>> }
>>>>> =====
>>>>> 
>>>>> If I compile it with -ftrivial-auto-var-init=zero -fdump-tree-gimple -S -o auto-init-11.s -fdump-rtl-expand, the *.gimple dump is:
>>>>> 
>>>>> =====
>>>>> void foo (int n)
>>>>> {
>>>>> int n.0;
>>>>> sizetype D.1950;
>>>>> bitsizetype D.1951;
>>>>> sizetype D.1952;
>>>>> bitsizetype D.1953;
>>>>> sizetype D.1954;
>>>>> int[0:D.1950] * arr.1;
>>>>> void * saved_stack.2;
>>>>> int arr[0:D.1950] [value-expr: *arr.1];
>>>>> 
>>>>> saved_stack.2 = __builtin_stack_save ();
>>>>> try
>>>>>  {
>>>>>    n.0 = n;
>>>>>    _1 = (long int) n.0;
>>>>>    _2 = _1 + -1;
>>>>>    _3 = (sizetype) _2;
>>>>>    D.1950 = _3;
>>>>>    _4 = (sizetype) n.0;
>>>>>    _5 = (bitsizetype) _4;
>>>>>    _6 = _5 * 32;
>>>>>    D.1951 = _6;
>>>>>    _7 = (sizetype) n.0;
>>>>>    _8 = _7 * 4;
>>>>>    D.1952 = _8;
>>>>>    _9 = (sizetype) n.0;
>>>>>    _10 = (bitsizetype) _9;
>>>>>    _11 = _10 * 32;
>>>>>    D.1953 = _11;
>>>>>    _12 = (sizetype) n.0;
>>>>>    _13 = _12 * 4;
>>>>>    D.1954 = _13;
>>>>>    arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>>    arr = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>    _14 = (*arr.1)[2];
>>>>>    bar (_14);
>>>>>    return;
>>>>>  }
>>>>> finally
>>>>>  {
>>>>>    __builtin_stack_restore (saved_stack.2);
>>>>>  }
>>>>> }
>>>>> 
>>>>> ====
>>>>> 
>>>>> You think that the above .DEFEERED_INIT is not correct?
>>>>> It should be:
>>>>> 
>>>>> *arr.1 = .DEFERRED_INIT (D.1952. 2, 1);
>>>>> 
>>>>> ?
>>>> 
>>>> Yes.
>>>> 
>>> 
>>> I updated gimplify.c for VLA and now it emits the call to .DEFERRED_INIT as:
>>> 
>>>     arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>     *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>> 
>>> However, this call triggered the assertion failure in verify_gimple_call of tree-cfg.c because the LHS is not a valid LHS. 
>>> Then I modify tree-cfg.c as:
>>> 
>>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
>>> index 330eb7dd89bf..180d4f1f9e32 100644
>>> --- a/gcc/tree-cfg.c
>>> +++ b/gcc/tree-cfg.c
>>> @@ -3375,7 +3375,11 @@ verify_gimple_call (gcall *stmt)
>>>     }
>>> 
>>>  tree lhs = gimple_call_lhs (stmt);
>>> +  /* For .DEFERRED_INIT call, the LHS might be an indirection of
>>> +     a pointer for the VLA variable, which is not a valid LHS of
>>> +     a gimple call, we ignore the asssertion on this.  */ 
>>>  if (lhs
>>> +      && (!gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
>>>      && (!is_gimple_reg (lhs)
>>>         && (!is_gimple_lvalue (lhs)
>>>             || verify_types_in_gimple_reference
>>> 
>>> The assertion failure in tree-cfg.c got resolved, but I got another assertion failure in operands_scanner::get_expr_operands (tree *expr_p, int flags), line 945:
>>> 
>>> 939   /* If we get here, something has gone wrong.  */
>>> 940   if (flag_checking)
>>> 941     {
>>> 942       fprintf (stderr, "unhandled expression in get_expr_operands():\n");
>>> 943       debug_tree (expr);
>>> 944       fputs ("\n", stderr);
>>> 945       gcc_unreachable ();
>>> 946     }
>>> 
>>> Looks like that  the gimple statement:
>>>   *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>> 
>>> Is not valid.  i.e, the LHS should not be an indirection to a pointer. 
>>> 
>>> How to resolve this issue?
>> 
>> I came up with the following solution:
>> 
>> Define the IFN_DEFERRED_INIT function as:
>> 
>>   LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA);
>> 
>>   if IS_VLA is false, the LHS is the DECL itself,
>>   if IS_VLA is true, the LHS is the pointer to this DECL that created by
>>   gimplify_vla_decl.
>> 
>> 
>> The benefit of this solution are:
>> 
>> 1. Resolved the invalid IR issue;
>> 2. The call stmt carries the address of the VLA natually;
>> 
>> The issue with this solution is:
>> 
>> For VLA and non-VLA, the LHS will be different, 
>> 
>> Do you see any other potential issues with this solution?
> 
> The idea behind the DECL version of the .DEFERRED_INIT semantics was
> that .DEFERRED_INIT just returns a SIZE-byte value that the caller
> then assigns to a SIZE-byte lhs (with the caller choosing the lhs).
> .DEFEREED_INIT itself doesn't read or write memory and so can be const,
> which in turn allows alias analysis to be more precise.
Yes. That’s right.

> 
> If we want to handle the VLA case using pointers instead then I think
> that needs to be a different IFN.
> 
> If we did handle the VLA case using pointers (not expressing an opinion
> on that), then it would be the caller's job to allocate the VLA and work
> out the address of the VLA;

the current routine “gimplify_vla_decl” has done this already:

It created a temporary variable for the address of the VLA, and created a call to “alloca” to allocate the VLA.

My -ftrivial-auto-var-init work just try to use the “address variable of the VLA” in the new .DEFERRED_INIT call to carry it to RTL expansion phase.


> this isn't something that .DEFERRED_INIT
> would work out on the caller's behalf.  The address of the VLA should
> therefore be an argument to the new IFN, rather than something that
> the IFN returns.

Then what’s the LHS of this call? Currently the major issue is the LHS is invalid gimple.

Qing
> 
> Thanks,
> Richard
> 


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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-11 13:37                       ` Richard Biener
@ 2021-08-11 13:54                         ` Qing Zhao
  2021-08-11 13:58                           ` Richard Biener
  0 siblings, 1 reply; 60+ messages in thread
From: Qing Zhao @ 2021-08-11 13:54 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook



> On Aug 11, 2021, at 8:37 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Wed, 11 Aug 2021, Qing Zhao wrote:
> 
>> 
>> 
>>> On Aug 11, 2021, at 2:02 AM, Richard Biener <rguenther@suse.de> wrote:
>>> 
>>> On Tue, 10 Aug 2021, Qing Zhao wrote:
>>> 
>>>> 
>>>> 
>>>>> On Aug 10, 2021, at 3:16 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>>>> 
>>>>> Hi, Richard,
>>>>> 
>>>>>> On Aug 10, 2021, at 10:22 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>>> 
>>>>>>>> Especially in the VLA case but likely also in general (though unlikely
>>>>>>>> since usually the receiver of initializations are simple enough).  I'd
>>>>>>>> expect the VLA case end up as
>>>>>>>> 
>>>>>>>> *ptr_to_decl = .DEFERRED_INIT (...);
>>>>>>>> 
>>>>>>>> where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.
>>>>>>> 
>>>>>>> So, for the following small testing case:
>>>>>>> 
>>>>>>> ====
>>>>>>> extern void bar (int);
>>>>>>> 
>>>>>>> void foo(int n)
>>>>>>> {
>>>>>>> int arr[n];
>>>>>>> bar (arr[2]);
>>>>>>> return;
>>>>>>> }
>>>>>>> =====
>>>>>>> 
>>>>>>> If I compile it with -ftrivial-auto-var-init=zero -fdump-tree-gimple -S -o auto-init-11.s -fdump-rtl-expand, the *.gimple dump is:
>>>>>>> 
>>>>>>> =====
>>>>>>> void foo (int n)
>>>>>>> {
>>>>>>> int n.0;
>>>>>>> sizetype D.1950;
>>>>>>> bitsizetype D.1951;
>>>>>>> sizetype D.1952;
>>>>>>> bitsizetype D.1953;
>>>>>>> sizetype D.1954;
>>>>>>> int[0:D.1950] * arr.1;
>>>>>>> void * saved_stack.2;
>>>>>>> int arr[0:D.1950] [value-expr: *arr.1];
>>>>>>> 
>>>>>>> saved_stack.2 = __builtin_stack_save ();
>>>>>>> try
>>>>>>> {
>>>>>>>   n.0 = n;
>>>>>>>   _1 = (long int) n.0;
>>>>>>>   _2 = _1 + -1;
>>>>>>>   _3 = (sizetype) _2;
>>>>>>>   D.1950 = _3;
>>>>>>>   _4 = (sizetype) n.0;
>>>>>>>   _5 = (bitsizetype) _4;
>>>>>>>   _6 = _5 * 32;
>>>>>>>   D.1951 = _6;
>>>>>>>   _7 = (sizetype) n.0;
>>>>>>>   _8 = _7 * 4;
>>>>>>>   D.1952 = _8;
>>>>>>>   _9 = (sizetype) n.0;
>>>>>>>   _10 = (bitsizetype) _9;
>>>>>>>   _11 = _10 * 32;
>>>>>>>   D.1953 = _11;
>>>>>>>   _12 = (sizetype) n.0;
>>>>>>>   _13 = _12 * 4;
>>>>>>>   D.1954 = _13;
>>>>>>>   arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>>>>   arr = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>   _14 = (*arr.1)[2];
>>>>>>>   bar (_14);
>>>>>>>   return;
>>>>>>> }
>>>>>>> finally
>>>>>>> {
>>>>>>>   __builtin_stack_restore (saved_stack.2);
>>>>>>> }
>>>>>>> }
>>>>>>> 
>>>>>>> ====
>>>>>>> 
>>>>>>> You think that the above .DEFEERED_INIT is not correct?
>>>>>>> It should be:
>>>>>>> 
>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952. 2, 1);
>>>>>>> 
>>>>>>> ?
>>>>>> 
>>>>>> Yes.
>>>>>> 
>>>>> 
>>>>> I updated gimplify.c for VLA and now it emits the call to .DEFERRED_INIT as:
>>>>> 
>>>>>    arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>>    *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>>>> 
>>>>> However, this call triggered the assertion failure in verify_gimple_call of tree-cfg.c because the LHS is not a valid LHS. 
>>>>> Then I modify tree-cfg.c as:
>>>>> 
>>>>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
>>>>> index 330eb7dd89bf..180d4f1f9e32 100644
>>>>> --- a/gcc/tree-cfg.c
>>>>> +++ b/gcc/tree-cfg.c
>>>>> @@ -3375,7 +3375,11 @@ verify_gimple_call (gcall *stmt)
>>>>>    }
>>>>> 
>>>>> tree lhs = gimple_call_lhs (stmt);
>>>>> +  /* For .DEFERRED_INIT call, the LHS might be an indirection of
>>>>> +     a pointer for the VLA variable, which is not a valid LHS of
>>>>> +     a gimple call, we ignore the asssertion on this.  */ 
>>>>> if (lhs
>>>>> +      && (!gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
>>>>>     && (!is_gimple_reg (lhs)
>>>>>        && (!is_gimple_lvalue (lhs)
>>>>>            || verify_types_in_gimple_reference
>>>>> 
>>>>> The assertion failure in tree-cfg.c got resolved, but I got another assertion failure in operands_scanner::get_expr_operands (tree *expr_p, int flags), line 945:
>>>>> 
>>>>> 939   /* If we get here, something has gone wrong.  */
>>>>> 940   if (flag_checking)
>>>>> 941     {
>>>>> 942       fprintf (stderr, "unhandled expression in get_expr_operands():\n");
>>>>> 943       debug_tree (expr);
>>>>> 944       fputs ("\n", stderr);
>>>>> 945       gcc_unreachable ();
>>>>> 946     }
>>>>> 
>>>>> Looks like that  the gimple statement:
>>>>>  *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>>>> 
>>>>> Is not valid.  i.e, the LHS should not be an indirection to a pointer. 
>>>>> 
>>>>> How to resolve this issue?
>>> 
>>> It sounds like the LHS is an INDIRECT_REF maybe?  That means it's
>>> still not properly gimplified because it should end up as a MEM_REF
>>> instead.
>>> 
>>> But I'm just guessing here ... if you are in a debugger then you can
>>> invoke debug_tree (lhs) in the inferior to see what it exactly is
>>> at the point of the failure.
>> 
>> Yes, it’s an INDIRECT_REF at the point of the failure even though I added a 
>> 
>> gimplify_var_or_parm_decl  (lhs) 
> 
> I think the easiest is to build the .DEFERRED_INIT as GENERIC
> and use gimplify_assign () to gimplify and add the result
> to the sequence.  Thus, build a GENERIC CALL_EXPR and then
> gimplify_assign (lhs, call_expr, seq);

Which utility routine is used to build an Internal generic call?
Currently, I used “gimple_build_call_internal” to build this internal gimple call.

For the generic call, shall I use “build_call_expr_loc” ? 
Qing

> 
> Richard.
> 
>> Qing
>> 
>>> 
>>>> I came up with the following solution:
>>>> 
>>>> Define the IFN_DEFERRED_INIT function as:
>>>> 
>>>>  LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA);
>>>> 
>>>>  if IS_VLA is false, the LHS is the DECL itself,
>>>>  if IS_VLA is true, the LHS is the pointer to this DECL that created by
>>>>  gimplify_vla_decl.
>>>> 
>>>> 
>>>> The benefit of this solution are:
>>>> 
>>>> 1. Resolved the invalid IR issue;
>>>> 2. The call stmt carries the address of the VLA natually;
>>>> 
>>>> The issue with this solution is:
>>>> 
>>>> For VLA and non-VLA, the LHS will be different, 
>>>> 
>>>> Do you see any other potential issues with this solution?
>>>> 
>>>> thanks.
>>>> 
>>>> Qing
>>>> 
>>>> 
>>>> 
>>>> 
>>>> 
>>> 
>>> -- 
>>> Richard Biener <rguenther@suse.de>
>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>> 
>> 
> 
> -- 
> 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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-11 13:54                         ` Qing Zhao
@ 2021-08-11 13:58                           ` Richard Biener
  2021-08-11 14:00                             ` Qing Zhao
  2021-08-11 15:30                             ` Qing Zhao
  0 siblings, 2 replies; 60+ messages in thread
From: Richard Biener @ 2021-08-11 13:58 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook

On Wed, 11 Aug 2021, Qing Zhao wrote:

> 
> 
> > On Aug 11, 2021, at 8:37 AM, Richard Biener <rguenther@suse.de> wrote:
> > 
> > On Wed, 11 Aug 2021, Qing Zhao wrote:
> > 
> >> 
> >> 
> >>> On Aug 11, 2021, at 2:02 AM, Richard Biener <rguenther@suse.de> wrote:
> >>> 
> >>> On Tue, 10 Aug 2021, Qing Zhao wrote:
> >>> 
> >>>> 
> >>>> 
> >>>>> On Aug 10, 2021, at 3:16 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> >>>>> 
> >>>>> Hi, Richard,
> >>>>> 
> >>>>>> On Aug 10, 2021, at 10:22 AM, Richard Biener <rguenther@suse.de> wrote:
> >>>>>>>> 
> >>>>>>>> Especially in the VLA case but likely also in general (though unlikely
> >>>>>>>> since usually the receiver of initializations are simple enough).  I'd
> >>>>>>>> expect the VLA case end up as
> >>>>>>>> 
> >>>>>>>> *ptr_to_decl = .DEFERRED_INIT (...);
> >>>>>>>> 
> >>>>>>>> where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.
> >>>>>>> 
> >>>>>>> So, for the following small testing case:
> >>>>>>> 
> >>>>>>> ====
> >>>>>>> extern void bar (int);
> >>>>>>> 
> >>>>>>> void foo(int n)
> >>>>>>> {
> >>>>>>> int arr[n];
> >>>>>>> bar (arr[2]);
> >>>>>>> return;
> >>>>>>> }
> >>>>>>> =====
> >>>>>>> 
> >>>>>>> If I compile it with -ftrivial-auto-var-init=zero -fdump-tree-gimple -S -o auto-init-11.s -fdump-rtl-expand, the *.gimple dump is:
> >>>>>>> 
> >>>>>>> =====
> >>>>>>> void foo (int n)
> >>>>>>> {
> >>>>>>> int n.0;
> >>>>>>> sizetype D.1950;
> >>>>>>> bitsizetype D.1951;
> >>>>>>> sizetype D.1952;
> >>>>>>> bitsizetype D.1953;
> >>>>>>> sizetype D.1954;
> >>>>>>> int[0:D.1950] * arr.1;
> >>>>>>> void * saved_stack.2;
> >>>>>>> int arr[0:D.1950] [value-expr: *arr.1];
> >>>>>>> 
> >>>>>>> saved_stack.2 = __builtin_stack_save ();
> >>>>>>> try
> >>>>>>> {
> >>>>>>>   n.0 = n;
> >>>>>>>   _1 = (long int) n.0;
> >>>>>>>   _2 = _1 + -1;
> >>>>>>>   _3 = (sizetype) _2;
> >>>>>>>   D.1950 = _3;
> >>>>>>>   _4 = (sizetype) n.0;
> >>>>>>>   _5 = (bitsizetype) _4;
> >>>>>>>   _6 = _5 * 32;
> >>>>>>>   D.1951 = _6;
> >>>>>>>   _7 = (sizetype) n.0;
> >>>>>>>   _8 = _7 * 4;
> >>>>>>>   D.1952 = _8;
> >>>>>>>   _9 = (sizetype) n.0;
> >>>>>>>   _10 = (bitsizetype) _9;
> >>>>>>>   _11 = _10 * 32;
> >>>>>>>   D.1953 = _11;
> >>>>>>>   _12 = (sizetype) n.0;
> >>>>>>>   _13 = _12 * 4;
> >>>>>>>   D.1954 = _13;
> >>>>>>>   arr.1 = __builtin_alloca_with_align (D.1954, 32);
> >>>>>>>   arr = .DEFERRED_INIT (D.1952, 2, 1);
> >>>>>>>   _14 = (*arr.1)[2];
> >>>>>>>   bar (_14);
> >>>>>>>   return;
> >>>>>>> }
> >>>>>>> finally
> >>>>>>> {
> >>>>>>>   __builtin_stack_restore (saved_stack.2);
> >>>>>>> }
> >>>>>>> }
> >>>>>>> 
> >>>>>>> ====
> >>>>>>> 
> >>>>>>> You think that the above .DEFEERED_INIT is not correct?
> >>>>>>> It should be:
> >>>>>>> 
> >>>>>>> *arr.1 = .DEFERRED_INIT (D.1952. 2, 1);
> >>>>>>> 
> >>>>>>> ?
> >>>>>> 
> >>>>>> Yes.
> >>>>>> 
> >>>>> 
> >>>>> I updated gimplify.c for VLA and now it emits the call to .DEFERRED_INIT as:
> >>>>> 
> >>>>>    arr.1 = __builtin_alloca_with_align (D.1954, 32);
> >>>>>    *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
> >>>>> 
> >>>>> However, this call triggered the assertion failure in verify_gimple_call of tree-cfg.c because the LHS is not a valid LHS. 
> >>>>> Then I modify tree-cfg.c as:
> >>>>> 
> >>>>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
> >>>>> index 330eb7dd89bf..180d4f1f9e32 100644
> >>>>> --- a/gcc/tree-cfg.c
> >>>>> +++ b/gcc/tree-cfg.c
> >>>>> @@ -3375,7 +3375,11 @@ verify_gimple_call (gcall *stmt)
> >>>>>    }
> >>>>> 
> >>>>> tree lhs = gimple_call_lhs (stmt);
> >>>>> +  /* For .DEFERRED_INIT call, the LHS might be an indirection of
> >>>>> +     a pointer for the VLA variable, which is not a valid LHS of
> >>>>> +     a gimple call, we ignore the asssertion on this.  */ 
> >>>>> if (lhs
> >>>>> +      && (!gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
> >>>>>     && (!is_gimple_reg (lhs)
> >>>>>        && (!is_gimple_lvalue (lhs)
> >>>>>            || verify_types_in_gimple_reference
> >>>>> 
> >>>>> The assertion failure in tree-cfg.c got resolved, but I got another assertion failure in operands_scanner::get_expr_operands (tree *expr_p, int flags), line 945:
> >>>>> 
> >>>>> 939   /* If we get here, something has gone wrong.  */
> >>>>> 940   if (flag_checking)
> >>>>> 941     {
> >>>>> 942       fprintf (stderr, "unhandled expression in get_expr_operands():\n");
> >>>>> 943       debug_tree (expr);
> >>>>> 944       fputs ("\n", stderr);
> >>>>> 945       gcc_unreachable ();
> >>>>> 946     }
> >>>>> 
> >>>>> Looks like that  the gimple statement:
> >>>>>  *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
> >>>>> 
> >>>>> Is not valid.  i.e, the LHS should not be an indirection to a pointer. 
> >>>>> 
> >>>>> How to resolve this issue?
> >>> 
> >>> It sounds like the LHS is an INDIRECT_REF maybe?  That means it's
> >>> still not properly gimplified because it should end up as a MEM_REF
> >>> instead.
> >>> 
> >>> But I'm just guessing here ... if you are in a debugger then you can
> >>> invoke debug_tree (lhs) in the inferior to see what it exactly is
> >>> at the point of the failure.
> >> 
> >> Yes, it’s an INDIRECT_REF at the point of the failure even though I added a 
> >> 
> >> gimplify_var_or_parm_decl  (lhs) 
> > 
> > I think the easiest is to build the .DEFERRED_INIT as GENERIC
> > and use gimplify_assign () to gimplify and add the result
> > to the sequence.  Thus, build a GENERIC CALL_EXPR and then
> > gimplify_assign (lhs, call_expr, seq);
> 
> Which utility routine is used to build an Internal generic call?
> Currently, I used “gimple_build_call_internal” to build this internal gimple call.
> 
> For the generic call, shall I use “build_call_expr_loc” ? 

For example look at build_asan_poison_call_expr which does such thing
for ASAN poison internal function call insertion at gimplification time.

Richard.

> Qing
> 
> > 
> > Richard.
> > 
> >> Qing
> >> 
> >>> 
> >>>> I came up with the following solution:
> >>>> 
> >>>> Define the IFN_DEFERRED_INIT function as:
> >>>> 
> >>>>  LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA);
> >>>> 
> >>>>  if IS_VLA is false, the LHS is the DECL itself,
> >>>>  if IS_VLA is true, the LHS is the pointer to this DECL that created by
> >>>>  gimplify_vla_decl.
> >>>> 
> >>>> 
> >>>> The benefit of this solution are:
> >>>> 
> >>>> 1. Resolved the invalid IR issue;
> >>>> 2. The call stmt carries the address of the VLA natually;
> >>>> 
> >>>> The issue with this solution is:
> >>>> 
> >>>> For VLA and non-VLA, the LHS will be different, 
> >>>> 
> >>>> Do you see any other potential issues with this solution?
> >>>> 
> >>>> thanks.
> >>>> 
> >>>> Qing
> >>>> 
> >>>> 
> >>>> 
> >>>> 
> >>>> 
> >>> 
> >>> -- 
> >>> Richard Biener <rguenther@suse.de>
> >>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> >>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
> >> 
> >> 
> > 
> > -- 
> > Richard Biener <rguenther@suse.de>
> > SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> > Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
> 
> 

-- 
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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-11 13:58                           ` Richard Biener
@ 2021-08-11 14:00                             ` Qing Zhao
  2021-08-11 15:30                             ` Qing Zhao
  1 sibling, 0 replies; 60+ messages in thread
From: Qing Zhao @ 2021-08-11 14:00 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook



> On Aug 11, 2021, at 8:58 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Wed, 11 Aug 2021, Qing Zhao wrote:
> 
>> 
>> 
>>> On Aug 11, 2021, at 8:37 AM, Richard Biener <rguenther@suse.de> wrote:
>>> 
>>> On Wed, 11 Aug 2021, Qing Zhao wrote:
>>> 
>>>> 
>>>> 
>>>>> On Aug 11, 2021, at 2:02 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>> 
>>>>> On Tue, 10 Aug 2021, Qing Zhao wrote:
>>>>> 
>>>>>> 
>>>>>> 
>>>>>>> On Aug 10, 2021, at 3:16 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>>>>>> 
>>>>>>> Hi, Richard,
>>>>>>> 
>>>>>>>> On Aug 10, 2021, at 10:22 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>>>>> 
>>>>>>>>>> Especially in the VLA case but likely also in general (though unlikely
>>>>>>>>>> since usually the receiver of initializations are simple enough).  I'd
>>>>>>>>>> expect the VLA case end up as
>>>>>>>>>> 
>>>>>>>>>> *ptr_to_decl = .DEFERRED_INIT (...);
>>>>>>>>>> 
>>>>>>>>>> where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.
>>>>>>>>> 
>>>>>>>>> So, for the following small testing case:
>>>>>>>>> 
>>>>>>>>> ====
>>>>>>>>> extern void bar (int);
>>>>>>>>> 
>>>>>>>>> void foo(int n)
>>>>>>>>> {
>>>>>>>>> int arr[n];
>>>>>>>>> bar (arr[2]);
>>>>>>>>> return;
>>>>>>>>> }
>>>>>>>>> =====
>>>>>>>>> 
>>>>>>>>> If I compile it with -ftrivial-auto-var-init=zero -fdump-tree-gimple -S -o auto-init-11.s -fdump-rtl-expand, the *.gimple dump is:
>>>>>>>>> 
>>>>>>>>> =====
>>>>>>>>> void foo (int n)
>>>>>>>>> {
>>>>>>>>> int n.0;
>>>>>>>>> sizetype D.1950;
>>>>>>>>> bitsizetype D.1951;
>>>>>>>>> sizetype D.1952;
>>>>>>>>> bitsizetype D.1953;
>>>>>>>>> sizetype D.1954;
>>>>>>>>> int[0:D.1950] * arr.1;
>>>>>>>>> void * saved_stack.2;
>>>>>>>>> int arr[0:D.1950] [value-expr: *arr.1];
>>>>>>>>> 
>>>>>>>>> saved_stack.2 = __builtin_stack_save ();
>>>>>>>>> try
>>>>>>>>> {
>>>>>>>>>  n.0 = n;
>>>>>>>>>  _1 = (long int) n.0;
>>>>>>>>>  _2 = _1 + -1;
>>>>>>>>>  _3 = (sizetype) _2;
>>>>>>>>>  D.1950 = _3;
>>>>>>>>>  _4 = (sizetype) n.0;
>>>>>>>>>  _5 = (bitsizetype) _4;
>>>>>>>>>  _6 = _5 * 32;
>>>>>>>>>  D.1951 = _6;
>>>>>>>>>  _7 = (sizetype) n.0;
>>>>>>>>>  _8 = _7 * 4;
>>>>>>>>>  D.1952 = _8;
>>>>>>>>>  _9 = (sizetype) n.0;
>>>>>>>>>  _10 = (bitsizetype) _9;
>>>>>>>>>  _11 = _10 * 32;
>>>>>>>>>  D.1953 = _11;
>>>>>>>>>  _12 = (sizetype) n.0;
>>>>>>>>>  _13 = _12 * 4;
>>>>>>>>>  D.1954 = _13;
>>>>>>>>>  arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>>>>>>  arr = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>>>  _14 = (*arr.1)[2];
>>>>>>>>>  bar (_14);
>>>>>>>>>  return;
>>>>>>>>> }
>>>>>>>>> finally
>>>>>>>>> {
>>>>>>>>>  __builtin_stack_restore (saved_stack.2);
>>>>>>>>> }
>>>>>>>>> }
>>>>>>>>> 
>>>>>>>>> ====
>>>>>>>>> 
>>>>>>>>> You think that the above .DEFEERED_INIT is not correct?
>>>>>>>>> It should be:
>>>>>>>>> 
>>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952. 2, 1);
>>>>>>>>> 
>>>>>>>>> ?
>>>>>>>> 
>>>>>>>> Yes.
>>>>>>>> 
>>>>>>> 
>>>>>>> I updated gimplify.c for VLA and now it emits the call to .DEFERRED_INIT as:
>>>>>>> 
>>>>>>>   arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>>>>   *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>> 
>>>>>>> However, this call triggered the assertion failure in verify_gimple_call of tree-cfg.c because the LHS is not a valid LHS. 
>>>>>>> Then I modify tree-cfg.c as:
>>>>>>> 
>>>>>>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
>>>>>>> index 330eb7dd89bf..180d4f1f9e32 100644
>>>>>>> --- a/gcc/tree-cfg.c
>>>>>>> +++ b/gcc/tree-cfg.c
>>>>>>> @@ -3375,7 +3375,11 @@ verify_gimple_call (gcall *stmt)
>>>>>>>   }
>>>>>>> 
>>>>>>> tree lhs = gimple_call_lhs (stmt);
>>>>>>> +  /* For .DEFERRED_INIT call, the LHS might be an indirection of
>>>>>>> +     a pointer for the VLA variable, which is not a valid LHS of
>>>>>>> +     a gimple call, we ignore the asssertion on this.  */ 
>>>>>>> if (lhs
>>>>>>> +      && (!gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
>>>>>>>    && (!is_gimple_reg (lhs)
>>>>>>>       && (!is_gimple_lvalue (lhs)
>>>>>>>           || verify_types_in_gimple_reference
>>>>>>> 
>>>>>>> The assertion failure in tree-cfg.c got resolved, but I got another assertion failure in operands_scanner::get_expr_operands (tree *expr_p, int flags), line 945:
>>>>>>> 
>>>>>>> 939   /* If we get here, something has gone wrong.  */
>>>>>>> 940   if (flag_checking)
>>>>>>> 941     {
>>>>>>> 942       fprintf (stderr, "unhandled expression in get_expr_operands():\n");
>>>>>>> 943       debug_tree (expr);
>>>>>>> 944       fputs ("\n", stderr);
>>>>>>> 945       gcc_unreachable ();
>>>>>>> 946     }
>>>>>>> 
>>>>>>> Looks like that  the gimple statement:
>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>> 
>>>>>>> Is not valid.  i.e, the LHS should not be an indirection to a pointer. 
>>>>>>> 
>>>>>>> How to resolve this issue?
>>>>> 
>>>>> It sounds like the LHS is an INDIRECT_REF maybe?  That means it's
>>>>> still not properly gimplified because it should end up as a MEM_REF
>>>>> instead.
>>>>> 
>>>>> But I'm just guessing here ... if you are in a debugger then you can
>>>>> invoke debug_tree (lhs) in the inferior to see what it exactly is
>>>>> at the point of the failure.
>>>> 
>>>> Yes, it’s an INDIRECT_REF at the point of the failure even though I added a 
>>>> 
>>>> gimplify_var_or_parm_decl  (lhs) 
>>> 
>>> I think the easiest is to build the .DEFERRED_INIT as GENERIC
>>> and use gimplify_assign () to gimplify and add the result
>>> to the sequence.  Thus, build a GENERIC CALL_EXPR and then
>>> gimplify_assign (lhs, call_expr, seq);
>> 
>> Which utility routine is used to build an Internal generic call?
>> Currently, I used “gimple_build_call_internal” to build this internal gimple call.
>> 
>> For the generic call, shall I use “build_call_expr_loc” ? 
> 
> For example look at build_asan_poison_call_expr which does such thing
> for ASAN poison internal function call insertion at gimplification time.

Okay, got it.

Will try.

Qing
> 
> Richard.
> 
>> Qing
>> 
>>> 
>>> Richard.
>>> 
>>>> Qing
>>>> 
>>>>> 
>>>>>> I came up with the following solution:
>>>>>> 
>>>>>> Define the IFN_DEFERRED_INIT function as:
>>>>>> 
>>>>>> LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA);
>>>>>> 
>>>>>> if IS_VLA is false, the LHS is the DECL itself,
>>>>>> if IS_VLA is true, the LHS is the pointer to this DECL that created by
>>>>>> gimplify_vla_decl.
>>>>>> 
>>>>>> 
>>>>>> The benefit of this solution are:
>>>>>> 
>>>>>> 1. Resolved the invalid IR issue;
>>>>>> 2. The call stmt carries the address of the VLA natually;
>>>>>> 
>>>>>> The issue with this solution is:
>>>>>> 
>>>>>> For VLA and non-VLA, the LHS will be different, 
>>>>>> 
>>>>>> Do you see any other potential issues with this solution?
>>>>>> 
>>>>>> thanks.
>>>>>> 
>>>>>> Qing
>>>>>> 
>>>>>> 
>>>>>> 
>>>>>> 
>>>>>> 
>>>>> 
>>>>> -- 
>>>>> Richard Biener <rguenther@suse.de>
>>>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>>>> 
>>>> 
>>> 
>>> -- 
>>> Richard Biener <rguenther@suse.de>
>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>> 
>> 
> 
> -- 
> 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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-11 13:58                           ` Richard Biener
  2021-08-11 14:00                             ` Qing Zhao
@ 2021-08-11 15:30                             ` Qing Zhao
  2021-08-11 15:53                               ` Richard Biener
  1 sibling, 1 reply; 60+ messages in thread
From: Qing Zhao @ 2021-08-11 15:30 UTC (permalink / raw)
  To: Richard Biener, Richard Sandiford
  Cc: Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook

I modified the routine “gimple_add_init_for_auto_var” as the following:
====
/* Generate initialization to automatic variable DECL based on INIT_TYPE.
   Build a call to internal const function DEFERRED_INIT:
   1st argument: SIZE of the DECL;
   2nd argument: INIT_TYPE;
   3rd argument: IS_VLA, 0 NO, 1 YES;

   as DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA).  */
static void
gimple_add_init_for_auto_var (tree decl,
                              enum auto_init_type init_type,
                              bool is_vla,
                              gimple_seq *seq_p)
{
  gcc_assert (VAR_P (decl) && !DECL_EXTERNAL (decl) && !TREE_STATIC (decl));
  gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
  tree decl_size = TYPE_SIZE_UNIT (TREE_TYPE (decl));

  tree init_type_node
    = build_int_cst (integer_type_node, (int) init_type);
  tree is_vla_node
    = build_int_cst (integer_type_node, (int) is_vla);

  tree call = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
                                            TREE_TYPE (decl), 3,
                                            decl_size, init_type_node,
                                            is_vla_node);

  /* If this DECL is a VLA, a temporary address variable for it has been
     created, the replacement for DECL is recorded in DECL_VALUE_EXPR (decl),
     we should use it as the LHS of the call.  */

  tree lhs_call
    = is_vla ? DECL_VALUE_EXPR (decl) : decl;
  gimplify_assign (lhs_call, call, seq_p);
}

With this change, the current issue is resolved, the gimple dump now is:

 (*arr.1) = .DEFERRED_INIT (D.1952, 2, 1);

However, there is another new issue:

For the following testing case:

======
[opc@qinzhao-ol8u3-x86 gcc]$ cat t.c
int bar;

extern void decode_reloc(int *);

void testfunc()
{
  int alt_reloc;

  decode_reloc(&alt_reloc);

  if (alt_reloc) /* { dg-warning "may be used uninitialized" } */
    bar = 42; 
}
=====

In the above, the auto var “alt_reloc” is address taken, then the gimple dump for it when compiled with -ftrivial-auto-var-init=zero is:

void testfunc ()
{
  int alt_reloc;

  try
    {
      _1 = .DEFERRED_INIT (4, 2, 0);
      alt_reloc = _1;
      decode_reloc (&alt_reloc);
      alt_reloc.0_2 = alt_reloc;
      if (alt_reloc.0_2 != 0) goto <D.1949>; else goto <D.1950>;
      <D.1949>:
      bar = 42;
      <D.1950>:
    }
  finally
    {
      alt_reloc = {CLOBBER};
    }
}

I.e, instead of the expected IR:

alt_reloc = .DEFERRED_INIT (4, 2, 0);

We got the following:

 _1 = .DEFERRED_INIT (4, 2, 0);
      alt_reloc = _1;

I guess the temp “_1” is created because “alt_reloc” is address taken. 

My questions:

Shall we accept such IR for .DEFERRED_INIT purpose when the auto var is address taken? 
If so, “uninitialized analysis” phase need to be further adjusted to specially handle such IR. 

If not, what should we do when the auto var is address taken?

Thanks a lot.

Qing


> On Aug 11, 2021, at 8:58 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Wed, 11 Aug 2021, Qing Zhao wrote:
> 
>> 
>> 
>>> On Aug 11, 2021, at 8:37 AM, Richard Biener <rguenther@suse.de> wrote:
>>> 
>>> On Wed, 11 Aug 2021, Qing Zhao wrote:
>>> 
>>>> 
>>>> 
>>>>> On Aug 11, 2021, at 2:02 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>> 
>>>>> On Tue, 10 Aug 2021, Qing Zhao wrote:
>>>>> 
>>>>>> 
>>>>>> 
>>>>>>> On Aug 10, 2021, at 3:16 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>>>>>> 
>>>>>>> Hi, Richard,
>>>>>>> 
>>>>>>>> On Aug 10, 2021, at 10:22 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>>>>> 
>>>>>>>>>> Especially in the VLA case but likely also in general (though unlikely
>>>>>>>>>> since usually the receiver of initializations are simple enough).  I'd
>>>>>>>>>> expect the VLA case end up as
>>>>>>>>>> 
>>>>>>>>>> *ptr_to_decl = .DEFERRED_INIT (...);
>>>>>>>>>> 
>>>>>>>>>> where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.
>>>>>>>>> 
>>>>>>>>> So, for the following small testing case:
>>>>>>>>> 
>>>>>>>>> ====
>>>>>>>>> extern void bar (int);
>>>>>>>>> 
>>>>>>>>> void foo(int n)
>>>>>>>>> {
>>>>>>>>> int arr[n];
>>>>>>>>> bar (arr[2]);
>>>>>>>>> return;
>>>>>>>>> }
>>>>>>>>> =====
>>>>>>>>> 
>>>>>>>>> If I compile it with -ftrivial-auto-var-init=zero -fdump-tree-gimple -S -o auto-init-11.s -fdump-rtl-expand, the *.gimple dump is:
>>>>>>>>> 
>>>>>>>>> =====
>>>>>>>>> void foo (int n)
>>>>>>>>> {
>>>>>>>>> int n.0;
>>>>>>>>> sizetype D.1950;
>>>>>>>>> bitsizetype D.1951;
>>>>>>>>> sizetype D.1952;
>>>>>>>>> bitsizetype D.1953;
>>>>>>>>> sizetype D.1954;
>>>>>>>>> int[0:D.1950] * arr.1;
>>>>>>>>> void * saved_stack.2;
>>>>>>>>> int arr[0:D.1950] [value-expr: *arr.1];
>>>>>>>>> 
>>>>>>>>> saved_stack.2 = __builtin_stack_save ();
>>>>>>>>> try
>>>>>>>>> {
>>>>>>>>>  n.0 = n;
>>>>>>>>>  _1 = (long int) n.0;
>>>>>>>>>  _2 = _1 + -1;
>>>>>>>>>  _3 = (sizetype) _2;
>>>>>>>>>  D.1950 = _3;
>>>>>>>>>  _4 = (sizetype) n.0;
>>>>>>>>>  _5 = (bitsizetype) _4;
>>>>>>>>>  _6 = _5 * 32;
>>>>>>>>>  D.1951 = _6;
>>>>>>>>>  _7 = (sizetype) n.0;
>>>>>>>>>  _8 = _7 * 4;
>>>>>>>>>  D.1952 = _8;
>>>>>>>>>  _9 = (sizetype) n.0;
>>>>>>>>>  _10 = (bitsizetype) _9;
>>>>>>>>>  _11 = _10 * 32;
>>>>>>>>>  D.1953 = _11;
>>>>>>>>>  _12 = (sizetype) n.0;
>>>>>>>>>  _13 = _12 * 4;
>>>>>>>>>  D.1954 = _13;
>>>>>>>>>  arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>>>>>>  arr = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>>>  _14 = (*arr.1)[2];
>>>>>>>>>  bar (_14);
>>>>>>>>>  return;
>>>>>>>>> }
>>>>>>>>> finally
>>>>>>>>> {
>>>>>>>>>  __builtin_stack_restore (saved_stack.2);
>>>>>>>>> }
>>>>>>>>> }
>>>>>>>>> 
>>>>>>>>> ====
>>>>>>>>> 
>>>>>>>>> You think that the above .DEFEERED_INIT is not correct?
>>>>>>>>> It should be:
>>>>>>>>> 
>>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952. 2, 1);
>>>>>>>>> 
>>>>>>>>> ?
>>>>>>>> 
>>>>>>>> Yes.
>>>>>>>> 
>>>>>>> 
>>>>>>> I updated gimplify.c for VLA and now it emits the call to .DEFERRED_INIT as:
>>>>>>> 
>>>>>>>   arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>>>>   *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>> 
>>>>>>> However, this call triggered the assertion failure in verify_gimple_call of tree-cfg.c because the LHS is not a valid LHS. 
>>>>>>> Then I modify tree-cfg.c as:
>>>>>>> 
>>>>>>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
>>>>>>> index 330eb7dd89bf..180d4f1f9e32 100644
>>>>>>> --- a/gcc/tree-cfg.c
>>>>>>> +++ b/gcc/tree-cfg.c
>>>>>>> @@ -3375,7 +3375,11 @@ verify_gimple_call (gcall *stmt)
>>>>>>>   }
>>>>>>> 
>>>>>>> tree lhs = gimple_call_lhs (stmt);
>>>>>>> +  /* For .DEFERRED_INIT call, the LHS might be an indirection of
>>>>>>> +     a pointer for the VLA variable, which is not a valid LHS of
>>>>>>> +     a gimple call, we ignore the asssertion on this.  */ 
>>>>>>> if (lhs
>>>>>>> +      && (!gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
>>>>>>>    && (!is_gimple_reg (lhs)
>>>>>>>       && (!is_gimple_lvalue (lhs)
>>>>>>>           || verify_types_in_gimple_reference
>>>>>>> 
>>>>>>> The assertion failure in tree-cfg.c got resolved, but I got another assertion failure in operands_scanner::get_expr_operands (tree *expr_p, int flags), line 945:
>>>>>>> 
>>>>>>> 939   /* If we get here, something has gone wrong.  */
>>>>>>> 940   if (flag_checking)
>>>>>>> 941     {
>>>>>>> 942       fprintf (stderr, "unhandled expression in get_expr_operands():\n");
>>>>>>> 943       debug_tree (expr);
>>>>>>> 944       fputs ("\n", stderr);
>>>>>>> 945       gcc_unreachable ();
>>>>>>> 946     }
>>>>>>> 
>>>>>>> Looks like that  the gimple statement:
>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>> 
>>>>>>> Is not valid.  i.e, the LHS should not be an indirection to a pointer. 
>>>>>>> 
>>>>>>> How to resolve this issue?
>>>>> 
>>>>> It sounds like the LHS is an INDIRECT_REF maybe?  That means it's
>>>>> still not properly gimplified because it should end up as a MEM_REF
>>>>> instead.
>>>>> 
>>>>> But I'm just guessing here ... if you are in a debugger then you can
>>>>> invoke debug_tree (lhs) in the inferior to see what it exactly is
>>>>> at the point of the failure.
>>>> 
>>>> Yes, it’s an INDIRECT_REF at the point of the failure even though I added a 
>>>> 
>>>> gimplify_var_or_parm_decl  (lhs) 
>>> 
>>> I think the easiest is to build the .DEFERRED_INIT as GENERIC
>>> and use gimplify_assign () to gimplify and add the result
>>> to the sequence.  Thus, build a GENERIC CALL_EXPR and then
>>> gimplify_assign (lhs, call_expr, seq);
>> 
>> Which utility routine is used to build an Internal generic call?
>> Currently, I used “gimple_build_call_internal” to build this internal gimple call.
>> 
>> For the generic call, shall I use “build_call_expr_loc” ? 
> 
> For example look at build_asan_poison_call_expr which does such thing
> for ASAN poison internal function call insertion at gimplification time.
> 
> Richard.
> 
>> Qing
>> 
>>> 
>>> Richard.
>>> 
>>>> Qing
>>>> 
>>>>> 
>>>>>> I came up with the following solution:
>>>>>> 
>>>>>> Define the IFN_DEFERRED_INIT function as:
>>>>>> 
>>>>>> LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA);
>>>>>> 
>>>>>> if IS_VLA is false, the LHS is the DECL itself,
>>>>>> if IS_VLA is true, the LHS is the pointer to this DECL that created by
>>>>>> gimplify_vla_decl.
>>>>>> 
>>>>>> 
>>>>>> The benefit of this solution are:
>>>>>> 
>>>>>> 1. Resolved the invalid IR issue;
>>>>>> 2. The call stmt carries the address of the VLA natually;
>>>>>> 
>>>>>> The issue with this solution is:
>>>>>> 
>>>>>> For VLA and non-VLA, the LHS will be different, 
>>>>>> 
>>>>>> Do you see any other potential issues with this solution?
>>>>>> 
>>>>>> thanks.
>>>>>> 
>>>>>> Qing
>>>>>> 
>>>>>> 
>>>>>> 
>>>>>> 
>>>>>> 
>>>>> 
>>>>> -- 
>>>>> Richard Biener <rguenther@suse.de>
>>>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>>>> 
>>>> 
>>> 
>>> -- 
>>> Richard Biener <rguenther@suse.de>
>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>> 
>> 
> 
> -- 
> 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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-11 15:30                             ` Qing Zhao
@ 2021-08-11 15:53                               ` Richard Biener
  2021-08-11 16:22                                 ` Qing Zhao
  0 siblings, 1 reply; 60+ messages in thread
From: Richard Biener @ 2021-08-11 15:53 UTC (permalink / raw)
  To: Qing Zhao, Richard Sandiford
  Cc: Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook

On August 11, 2021 5:30:40 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>I modified the routine “gimple_add_init_for_auto_var” as the following:
>====
>/* Generate initialization to automatic variable DECL based on INIT_TYPE.
>   Build a call to internal const function DEFERRED_INIT:
>   1st argument: SIZE of the DECL;
>   2nd argument: INIT_TYPE;
>   3rd argument: IS_VLA, 0 NO, 1 YES;
>
>   as DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA).  */
>static void
>gimple_add_init_for_auto_var (tree decl,
>                              enum auto_init_type init_type,
>                              bool is_vla,
>                              gimple_seq *seq_p)
>{
>  gcc_assert (VAR_P (decl) && !DECL_EXTERNAL (decl) && !TREE_STATIC (decl));
>  gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>  tree decl_size = TYPE_SIZE_UNIT (TREE_TYPE (decl));
>
>  tree init_type_node
>    = build_int_cst (integer_type_node, (int) init_type);
>  tree is_vla_node
>    = build_int_cst (integer_type_node, (int) is_vla);
>
>  tree call = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
>                                            TREE_TYPE (decl), 3,
>                                            decl_size, init_type_node,
>                                            is_vla_node);
>
>  /* If this DECL is a VLA, a temporary address variable for it has been
>     created, the replacement for DECL is recorded in DECL_VALUE_EXPR (decl),
>     we should use it as the LHS of the call.  */
>
>  tree lhs_call
>    = is_vla ? DECL_VALUE_EXPR (decl) : decl;
>  gimplify_assign (lhs_call, call, seq_p);
>}
>
>With this change, the current issue is resolved, the gimple dump now is:
>
> (*arr.1) = .DEFERRED_INIT (D.1952, 2, 1);
>
>However, there is another new issue:
>
>For the following testing case:
>
>======
>[opc@qinzhao-ol8u3-x86 gcc]$ cat t.c
>int bar;
>
>extern void decode_reloc(int *);
>
>void testfunc()
>{
>  int alt_reloc;
>
>  decode_reloc(&alt_reloc);
>
>  if (alt_reloc) /* { dg-warning "may be used uninitialized" } */
>    bar = 42; 
>}
>=====
>
>In the above, the auto var “alt_reloc” is address taken, then the gimple dump for it when compiled with -ftrivial-auto-var-init=zero is:
>
>void testfunc ()
>{
>  int alt_reloc;
>
>  try
>    {
>      _1 = .DEFERRED_INIT (4, 2, 0);
>      alt_reloc = _1;
>      decode_reloc (&alt_reloc);
>      alt_reloc.0_2 = alt_reloc;
>      if (alt_reloc.0_2 != 0) goto <D.1949>; else goto <D.1950>;
>      <D.1949>:
>      bar = 42;
>      <D.1950>:
>    }
>  finally
>    {
>      alt_reloc = {CLOBBER};
>    }
>}
>
>I.e, instead of the expected IR:
>
>alt_reloc = .DEFERRED_INIT (4, 2, 0);
>
>We got the following:
>
> _1 = .DEFERRED_INIT (4, 2, 0);
>      alt_reloc = _1;
>
>I guess the temp “_1” is created because “alt_reloc” is address taken. 

Yes and no. The reason is that alt_reloc is memory (because it is address taken) and that GIMPLE says that register typed stores need to use a is_gimple_val RHS which the call is not.

>My questions:
>
>Shall we accept such IR for .DEFERRED_INIT purpose when the auto var is address taken? 

I think so. Note it doesn't necessarily need address taking but any other reason that prevents SSA rewriting the variable suffices. 

The only other option is to force. DEFERED_INIT making the LHS address taken which I think could be achieved by passing it the address as argument instead of having a LHS. But let's not go down this route - it will have quite bad behavior on alias analysis and optimization. 

>If so, “uninitialized analysis” phase need to be further adjusted to specially handle such IR. 
>
>If not, what should we do when the auto var is address taken?
>
>Thanks a lot.
>
>Qing
>
>
>> On Aug 11, 2021, at 8:58 AM, Richard Biener <rguenther@suse.de> wrote:
>> 
>> On Wed, 11 Aug 2021, Qing Zhao wrote:
>> 
>>> 
>>> 
>>>> On Aug 11, 2021, at 8:37 AM, Richard Biener <rguenther@suse.de> wrote:
>>>> 
>>>> On Wed, 11 Aug 2021, Qing Zhao wrote:
>>>> 
>>>>> 
>>>>> 
>>>>>> On Aug 11, 2021, at 2:02 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>> 
>>>>>> On Tue, 10 Aug 2021, Qing Zhao wrote:
>>>>>> 
>>>>>>> 
>>>>>>> 
>>>>>>>> On Aug 10, 2021, at 3:16 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>>>>>>> 
>>>>>>>> Hi, Richard,
>>>>>>>> 
>>>>>>>>> On Aug 10, 2021, at 10:22 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>>>>>> 
>>>>>>>>>>> Especially in the VLA case but likely also in general (though unlikely
>>>>>>>>>>> since usually the receiver of initializations are simple enough).  I'd
>>>>>>>>>>> expect the VLA case end up as
>>>>>>>>>>> 
>>>>>>>>>>> *ptr_to_decl = .DEFERRED_INIT (...);
>>>>>>>>>>> 
>>>>>>>>>>> where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.
>>>>>>>>>> 
>>>>>>>>>> So, for the following small testing case:
>>>>>>>>>> 
>>>>>>>>>> ====
>>>>>>>>>> extern void bar (int);
>>>>>>>>>> 
>>>>>>>>>> void foo(int n)
>>>>>>>>>> {
>>>>>>>>>> int arr[n];
>>>>>>>>>> bar (arr[2]);
>>>>>>>>>> return;
>>>>>>>>>> }
>>>>>>>>>> =====
>>>>>>>>>> 
>>>>>>>>>> If I compile it with -ftrivial-auto-var-init=zero -fdump-tree-gimple -S -o auto-init-11.s -fdump-rtl-expand, the *.gimple dump is:
>>>>>>>>>> 
>>>>>>>>>> =====
>>>>>>>>>> void foo (int n)
>>>>>>>>>> {
>>>>>>>>>> int n.0;
>>>>>>>>>> sizetype D.1950;
>>>>>>>>>> bitsizetype D.1951;
>>>>>>>>>> sizetype D.1952;
>>>>>>>>>> bitsizetype D.1953;
>>>>>>>>>> sizetype D.1954;
>>>>>>>>>> int[0:D.1950] * arr.1;
>>>>>>>>>> void * saved_stack.2;
>>>>>>>>>> int arr[0:D.1950] [value-expr: *arr.1];
>>>>>>>>>> 
>>>>>>>>>> saved_stack.2 = __builtin_stack_save ();
>>>>>>>>>> try
>>>>>>>>>> {
>>>>>>>>>>  n.0 = n;
>>>>>>>>>>  _1 = (long int) n.0;
>>>>>>>>>>  _2 = _1 + -1;
>>>>>>>>>>  _3 = (sizetype) _2;
>>>>>>>>>>  D.1950 = _3;
>>>>>>>>>>  _4 = (sizetype) n.0;
>>>>>>>>>>  _5 = (bitsizetype) _4;
>>>>>>>>>>  _6 = _5 * 32;
>>>>>>>>>>  D.1951 = _6;
>>>>>>>>>>  _7 = (sizetype) n.0;
>>>>>>>>>>  _8 = _7 * 4;
>>>>>>>>>>  D.1952 = _8;
>>>>>>>>>>  _9 = (sizetype) n.0;
>>>>>>>>>>  _10 = (bitsizetype) _9;
>>>>>>>>>>  _11 = _10 * 32;
>>>>>>>>>>  D.1953 = _11;
>>>>>>>>>>  _12 = (sizetype) n.0;
>>>>>>>>>>  _13 = _12 * 4;
>>>>>>>>>>  D.1954 = _13;
>>>>>>>>>>  arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>>>>>>>  arr = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>>>>  _14 = (*arr.1)[2];
>>>>>>>>>>  bar (_14);
>>>>>>>>>>  return;
>>>>>>>>>> }
>>>>>>>>>> finally
>>>>>>>>>> {
>>>>>>>>>>  __builtin_stack_restore (saved_stack.2);
>>>>>>>>>> }
>>>>>>>>>> }
>>>>>>>>>> 
>>>>>>>>>> ====
>>>>>>>>>> 
>>>>>>>>>> You think that the above .DEFEERED_INIT is not correct?
>>>>>>>>>> It should be:
>>>>>>>>>> 
>>>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952. 2, 1);
>>>>>>>>>> 
>>>>>>>>>> ?
>>>>>>>>> 
>>>>>>>>> Yes.
>>>>>>>>> 
>>>>>>>> 
>>>>>>>> I updated gimplify.c for VLA and now it emits the call to .DEFERRED_INIT as:
>>>>>>>> 
>>>>>>>>   arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>>>>>   *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>> 
>>>>>>>> However, this call triggered the assertion failure in verify_gimple_call of tree-cfg.c because the LHS is not a valid LHS. 
>>>>>>>> Then I modify tree-cfg.c as:
>>>>>>>> 
>>>>>>>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
>>>>>>>> index 330eb7dd89bf..180d4f1f9e32 100644
>>>>>>>> --- a/gcc/tree-cfg.c
>>>>>>>> +++ b/gcc/tree-cfg.c
>>>>>>>> @@ -3375,7 +3375,11 @@ verify_gimple_call (gcall *stmt)
>>>>>>>>   }
>>>>>>>> 
>>>>>>>> tree lhs = gimple_call_lhs (stmt);
>>>>>>>> +  /* For .DEFERRED_INIT call, the LHS might be an indirection of
>>>>>>>> +     a pointer for the VLA variable, which is not a valid LHS of
>>>>>>>> +     a gimple call, we ignore the asssertion on this.  */ 
>>>>>>>> if (lhs
>>>>>>>> +      && (!gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
>>>>>>>>    && (!is_gimple_reg (lhs)
>>>>>>>>       && (!is_gimple_lvalue (lhs)
>>>>>>>>           || verify_types_in_gimple_reference
>>>>>>>> 
>>>>>>>> The assertion failure in tree-cfg.c got resolved, but I got another assertion failure in operands_scanner::get_expr_operands (tree *expr_p, int flags), line 945:
>>>>>>>> 
>>>>>>>> 939   /* If we get here, something has gone wrong.  */
>>>>>>>> 940   if (flag_checking)
>>>>>>>> 941     {
>>>>>>>> 942       fprintf (stderr, "unhandled expression in get_expr_operands():\n");
>>>>>>>> 943       debug_tree (expr);
>>>>>>>> 944       fputs ("\n", stderr);
>>>>>>>> 945       gcc_unreachable ();
>>>>>>>> 946     }
>>>>>>>> 
>>>>>>>> Looks like that  the gimple statement:
>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>> 
>>>>>>>> Is not valid.  i.e, the LHS should not be an indirection to a pointer. 
>>>>>>>> 
>>>>>>>> How to resolve this issue?
>>>>>> 
>>>>>> It sounds like the LHS is an INDIRECT_REF maybe?  That means it's
>>>>>> still not properly gimplified because it should end up as a MEM_REF
>>>>>> instead.
>>>>>> 
>>>>>> But I'm just guessing here ... if you are in a debugger then you can
>>>>>> invoke debug_tree (lhs) in the inferior to see what it exactly is
>>>>>> at the point of the failure.
>>>>> 
>>>>> Yes, it’s an INDIRECT_REF at the point of the failure even though I added a 
>>>>> 
>>>>> gimplify_var_or_parm_decl  (lhs) 
>>>> 
>>>> I think the easiest is to build the .DEFERRED_INIT as GENERIC
>>>> and use gimplify_assign () to gimplify and add the result
>>>> to the sequence.  Thus, build a GENERIC CALL_EXPR and then
>>>> gimplify_assign (lhs, call_expr, seq);
>>> 
>>> Which utility routine is used to build an Internal generic call?
>>> Currently, I used “gimple_build_call_internal” to build this internal gimple call.
>>> 
>>> For the generic call, shall I use “build_call_expr_loc” ? 
>> 
>> For example look at build_asan_poison_call_expr which does such thing
>> for ASAN poison internal function call insertion at gimplification time.
>> 
>> Richard.
>> 
>>> Qing
>>> 
>>>> 
>>>> Richard.
>>>> 
>>>>> Qing
>>>>> 
>>>>>> 
>>>>>>> I came up with the following solution:
>>>>>>> 
>>>>>>> Define the IFN_DEFERRED_INIT function as:
>>>>>>> 
>>>>>>> LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA);
>>>>>>> 
>>>>>>> if IS_VLA is false, the LHS is the DECL itself,
>>>>>>> if IS_VLA is true, the LHS is the pointer to this DECL that created by
>>>>>>> gimplify_vla_decl.
>>>>>>> 
>>>>>>> 
>>>>>>> The benefit of this solution are:
>>>>>>> 
>>>>>>> 1. Resolved the invalid IR issue;
>>>>>>> 2. The call stmt carries the address of the VLA natually;
>>>>>>> 
>>>>>>> The issue with this solution is:
>>>>>>> 
>>>>>>> For VLA and non-VLA, the LHS will be different, 
>>>>>>> 
>>>>>>> Do you see any other potential issues with this solution?
>>>>>>> 
>>>>>>> thanks.
>>>>>>> 
>>>>>>> Qing
>>>>>>> 
>>>>>>> 
>>>>>>> 
>>>>>>> 
>>>>>>> 
>>>>>> 
>>>>>> -- 
>>>>>> Richard Biener <rguenther@suse.de>
>>>>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>>>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>>>>> 
>>>>> 
>>>> 
>>>> -- 
>>>> Richard Biener <rguenther@suse.de>
>>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>>> 
>>> 
>> 
>> -- 
>> 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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-11 13:44                     ` Qing Zhao
@ 2021-08-11 16:15                       ` Richard Sandiford
  2021-08-11 16:29                         ` Qing Zhao
  0 siblings, 1 reply; 60+ messages in thread
From: Richard Sandiford @ 2021-08-11 16:15 UTC (permalink / raw)
  To: Qing Zhao
  Cc: Qing Zhao via Gcc-patches, Richard Biener, Jakub Jelinek, Kees Cook

Qing Zhao <qing.zhao@oracle.com> writes:
>> On Aug 11, 2021, at 4:02 AM, Richard Sandiford <richard.sandiford@arm.com> wrote:
>>> I came up with the following solution:
>>> 
>>> Define the IFN_DEFERRED_INIT function as:
>>> 
>>>   LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA);
>>> 
>>>   if IS_VLA is false, the LHS is the DECL itself,
>>>   if IS_VLA is true, the LHS is the pointer to this DECL that created by
>>>   gimplify_vla_decl.
>>> 
>>> 
>>> The benefit of this solution are:
>>> 
>>> 1. Resolved the invalid IR issue;
>>> 2. The call stmt carries the address of the VLA natually;
>>> 
>>> The issue with this solution is:
>>> 
>>> For VLA and non-VLA, the LHS will be different, 
>>> 
>>> Do you see any other potential issues with this solution?
>> 
>> The idea behind the DECL version of the .DEFERRED_INIT semantics was
>> that .DEFERRED_INIT just returns a SIZE-byte value that the caller
>> then assigns to a SIZE-byte lhs (with the caller choosing the lhs).
>> .DEFEREED_INIT itself doesn't read or write memory and so can be const,
>> which in turn allows alias analysis to be more precise.
> Yes. That’s right.
>
>> 
>> If we want to handle the VLA case using pointers instead then I think
>> that needs to be a different IFN.
>> 
>> If we did handle the VLA case using pointers (not expressing an opinion
>> on that), then it would be the caller's job to allocate the VLA and work
>> out the address of the VLA;
>
> the current routine “gimplify_vla_decl” has done this already:
>
> It created a temporary variable for the address of the VLA, and created a call to “alloca” to allocate the VLA.

Right, that's what I mean.  It's this alloca that allocates the VLA
and determines its address.  This address is therefore logically an
input rather than an output to the following zero/pattern initialisation.

In C you wouldn't write:

  addr = alloca(size);
  addr = initialise(size);

to allocate and initialise a size-byte buffer, because initialise()
would need to know the address of the memory it's supposed to initialise.
The same is true for this gimple code.

> My -ftrivial-auto-var-init work just try to use the “address variable of the VLA” in the new .DEFERRED_INIT call to carry it to RTL expansion phase.
>
>
>> this isn't something that .DEFERRED_INIT
>> would work out on the caller's behalf.  The address of the VLA should
>> therefore be an argument to the new IFN, rather than something that
>> the IFN returns.
>
> Then what’s the LHS of this call? Currently the major issue is the LHS is invalid gimple.

For this (different, address-taking, VLA-only) IFN, there would be no lhs.
The IFN would be similar to a memset.

Like I say, this is all hypothetical, based on “if we did handle the VLA
case using pointers”.  As discussed, it would make alias analysis less
precise.  I was just answering the question about whether there were
potential issues.

Thanks,
Richard

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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-11 15:53                               ` Richard Biener
@ 2021-08-11 16:22                                 ` Qing Zhao
  2021-08-11 16:55                                   ` Richard Biener
  0 siblings, 1 reply; 60+ messages in thread
From: Qing Zhao @ 2021-08-11 16:22 UTC (permalink / raw)
  To: Richard Biener
  Cc: Richard Sandiford, Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook



> On Aug 11, 2021, at 10:53 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On August 11, 2021 5:30:40 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>> I modified the routine “gimple_add_init_for_auto_var” as the following:
>> ====
>> /* Generate initialization to automatic variable DECL based on INIT_TYPE.
>>  Build a call to internal const function DEFERRED_INIT:
>>  1st argument: SIZE of the DECL;
>>  2nd argument: INIT_TYPE;
>>  3rd argument: IS_VLA, 0 NO, 1 YES;
>> 
>>  as DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA).  */
>> static void
>> gimple_add_init_for_auto_var (tree decl,
>>                             enum auto_init_type init_type,
>>                             bool is_vla,
>>                             gimple_seq *seq_p)
>> {
>> gcc_assert (VAR_P (decl) && !DECL_EXTERNAL (decl) && !TREE_STATIC (decl));
>> gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>> tree decl_size = TYPE_SIZE_UNIT (TREE_TYPE (decl));
>> 
>> tree init_type_node
>>   = build_int_cst (integer_type_node, (int) init_type);
>> tree is_vla_node
>>   = build_int_cst (integer_type_node, (int) is_vla);
>> 
>> tree call = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
>>                                           TREE_TYPE (decl), 3,
>>                                           decl_size, init_type_node,
>>                                           is_vla_node);
>> 
>> /* If this DECL is a VLA, a temporary address variable for it has been
>>    created, the replacement for DECL is recorded in DECL_VALUE_EXPR (decl),
>>    we should use it as the LHS of the call.  */
>> 
>> tree lhs_call
>>   = is_vla ? DECL_VALUE_EXPR (decl) : decl;
>> gimplify_assign (lhs_call, call, seq_p);
>> }
>> 
>> With this change, the current issue is resolved, the gimple dump now is:
>> 
>> (*arr.1) = .DEFERRED_INIT (D.1952, 2, 1);
>> 
>> However, there is another new issue:
>> 
>> For the following testing case:
>> 
>> ======
>> [opc@qinzhao-ol8u3-x86 gcc]$ cat t.c
>> int bar;
>> 
>> extern void decode_reloc(int *);
>> 
>> void testfunc()
>> {
>> int alt_reloc;
>> 
>> decode_reloc(&alt_reloc);
>> 
>> if (alt_reloc) /* { dg-warning "may be used uninitialized" } */
>>   bar = 42; 
>> }
>> =====
>> 
>> In the above, the auto var “alt_reloc” is address taken, then the gimple dump for it when compiled with -ftrivial-auto-var-init=zero is:
>> 
>> void testfunc ()
>> {
>> int alt_reloc;
>> 
>> try
>>   {
>>     _1 = .DEFERRED_INIT (4, 2, 0);
>>     alt_reloc = _1;
>>     decode_reloc (&alt_reloc);
>>     alt_reloc.0_2 = alt_reloc;
>>     if (alt_reloc.0_2 != 0) goto <D.1949>; else goto <D.1950>;
>>     <D.1949>:
>>     bar = 42;
>>     <D.1950>:
>>   }
>> finally
>>   {
>>     alt_reloc = {CLOBBER};
>>   }
>> }
>> 
>> I.e, instead of the expected IR:
>> 
>> alt_reloc = .DEFERRED_INIT (4, 2, 0);
>> 
>> We got the following:
>> 
>> _1 = .DEFERRED_INIT (4, 2, 0);
>>     alt_reloc = _1;
>> 
>> I guess the temp “_1” is created because “alt_reloc” is address taken. 
> 
> Yes and no. The reason is that alt_reloc is memory (because it is address taken) and that GIMPLE says that register typed stores need to use a is_gimple_val RHS which the call is not.

Okay.
> 
>> My questions:
>> 
>> Shall we accept such IR for .DEFERRED_INIT purpose when the auto var is address taken? 
> 
> I think so. Note it doesn't necessarily need address taking but any other reason that prevents SSA rewriting the variable suffices. 

You mean, in addition to “address taken”, there are other situations that will introduce such IR:

temp = .DEFERRED_INIT();
auto_var = temp;

So, such IR is unavoidable and we have to handle it?

If we have to handle it,  what’ the best way to do it?

The solution in my mind is:
1. During uninitialized analysis phase, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then decide that “auto_var” is uninitialized.

2. During RTL expansion, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then delete “temp”, and then expand .DEFERRED_INIT to auto_var.

Let me know your comments and suggestions on this.


> 
> The only other option is to force. DEFERED_INIT making the LHS address taken which I think could be achieved by passing it the address as argument instead of having a LHS. But let's not go down this route - it will have quite bad behavior on alias analysis and optimization. 

Okay.

Qing
> 
>> If so, “uninitialized analysis” phase need to be further adjusted to specially handle such IR. 
>> 
>> If not, what should we do when the auto var is address taken?
>> 
>> Thanks a lot.
>> 
>> Qing
>> 
>> 
>>> On Aug 11, 2021, at 8:58 AM, Richard Biener <rguenther@suse.de> wrote:
>>> 
>>> On Wed, 11 Aug 2021, Qing Zhao wrote:
>>> 
>>>> 
>>>> 
>>>>> On Aug 11, 2021, at 8:37 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>> 
>>>>> On Wed, 11 Aug 2021, Qing Zhao wrote:
>>>>> 
>>>>>> 
>>>>>> 
>>>>>>> On Aug 11, 2021, at 2:02 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>> 
>>>>>>> On Tue, 10 Aug 2021, Qing Zhao wrote:
>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>>> On Aug 10, 2021, at 3:16 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>>>>>>>> 
>>>>>>>>> Hi, Richard,
>>>>>>>>> 
>>>>>>>>>> On Aug 10, 2021, at 10:22 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>>>>>>> 
>>>>>>>>>>>> Especially in the VLA case but likely also in general (though unlikely
>>>>>>>>>>>> since usually the receiver of initializations are simple enough).  I'd
>>>>>>>>>>>> expect the VLA case end up as
>>>>>>>>>>>> 
>>>>>>>>>>>> *ptr_to_decl = .DEFERRED_INIT (...);
>>>>>>>>>>>> 
>>>>>>>>>>>> where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.
>>>>>>>>>>> 
>>>>>>>>>>> So, for the following small testing case:
>>>>>>>>>>> 
>>>>>>>>>>> ====
>>>>>>>>>>> extern void bar (int);
>>>>>>>>>>> 
>>>>>>>>>>> void foo(int n)
>>>>>>>>>>> {
>>>>>>>>>>> int arr[n];
>>>>>>>>>>> bar (arr[2]);
>>>>>>>>>>> return;
>>>>>>>>>>> }
>>>>>>>>>>> =====
>>>>>>>>>>> 
>>>>>>>>>>> If I compile it with -ftrivial-auto-var-init=zero -fdump-tree-gimple -S -o auto-init-11.s -fdump-rtl-expand, the *.gimple dump is:
>>>>>>>>>>> 
>>>>>>>>>>> =====
>>>>>>>>>>> void foo (int n)
>>>>>>>>>>> {
>>>>>>>>>>> int n.0;
>>>>>>>>>>> sizetype D.1950;
>>>>>>>>>>> bitsizetype D.1951;
>>>>>>>>>>> sizetype D.1952;
>>>>>>>>>>> bitsizetype D.1953;
>>>>>>>>>>> sizetype D.1954;
>>>>>>>>>>> int[0:D.1950] * arr.1;
>>>>>>>>>>> void * saved_stack.2;
>>>>>>>>>>> int arr[0:D.1950] [value-expr: *arr.1];
>>>>>>>>>>> 
>>>>>>>>>>> saved_stack.2 = __builtin_stack_save ();
>>>>>>>>>>> try
>>>>>>>>>>> {
>>>>>>>>>>> n.0 = n;
>>>>>>>>>>> _1 = (long int) n.0;
>>>>>>>>>>> _2 = _1 + -1;
>>>>>>>>>>> _3 = (sizetype) _2;
>>>>>>>>>>> D.1950 = _3;
>>>>>>>>>>> _4 = (sizetype) n.0;
>>>>>>>>>>> _5 = (bitsizetype) _4;
>>>>>>>>>>> _6 = _5 * 32;
>>>>>>>>>>> D.1951 = _6;
>>>>>>>>>>> _7 = (sizetype) n.0;
>>>>>>>>>>> _8 = _7 * 4;
>>>>>>>>>>> D.1952 = _8;
>>>>>>>>>>> _9 = (sizetype) n.0;
>>>>>>>>>>> _10 = (bitsizetype) _9;
>>>>>>>>>>> _11 = _10 * 32;
>>>>>>>>>>> D.1953 = _11;
>>>>>>>>>>> _12 = (sizetype) n.0;
>>>>>>>>>>> _13 = _12 * 4;
>>>>>>>>>>> D.1954 = _13;
>>>>>>>>>>> arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>>>>>>>> arr = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>>>>> _14 = (*arr.1)[2];
>>>>>>>>>>> bar (_14);
>>>>>>>>>>> return;
>>>>>>>>>>> }
>>>>>>>>>>> finally
>>>>>>>>>>> {
>>>>>>>>>>> __builtin_stack_restore (saved_stack.2);
>>>>>>>>>>> }
>>>>>>>>>>> }
>>>>>>>>>>> 
>>>>>>>>>>> ====
>>>>>>>>>>> 
>>>>>>>>>>> You think that the above .DEFEERED_INIT is not correct?
>>>>>>>>>>> It should be:
>>>>>>>>>>> 
>>>>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952. 2, 1);
>>>>>>>>>>> 
>>>>>>>>>>> ?
>>>>>>>>>> 
>>>>>>>>>> Yes.
>>>>>>>>>> 
>>>>>>>>> 
>>>>>>>>> I updated gimplify.c for VLA and now it emits the call to .DEFERRED_INIT as:
>>>>>>>>> 
>>>>>>>>>  arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>>>>>>  *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>>> 
>>>>>>>>> However, this call triggered the assertion failure in verify_gimple_call of tree-cfg.c because the LHS is not a valid LHS. 
>>>>>>>>> Then I modify tree-cfg.c as:
>>>>>>>>> 
>>>>>>>>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
>>>>>>>>> index 330eb7dd89bf..180d4f1f9e32 100644
>>>>>>>>> --- a/gcc/tree-cfg.c
>>>>>>>>> +++ b/gcc/tree-cfg.c
>>>>>>>>> @@ -3375,7 +3375,11 @@ verify_gimple_call (gcall *stmt)
>>>>>>>>>  }
>>>>>>>>> 
>>>>>>>>> tree lhs = gimple_call_lhs (stmt);
>>>>>>>>> +  /* For .DEFERRED_INIT call, the LHS might be an indirection of
>>>>>>>>> +     a pointer for the VLA variable, which is not a valid LHS of
>>>>>>>>> +     a gimple call, we ignore the asssertion on this.  */ 
>>>>>>>>> if (lhs
>>>>>>>>> +      && (!gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
>>>>>>>>>   && (!is_gimple_reg (lhs)
>>>>>>>>>      && (!is_gimple_lvalue (lhs)
>>>>>>>>>          || verify_types_in_gimple_reference
>>>>>>>>> 
>>>>>>>>> The assertion failure in tree-cfg.c got resolved, but I got another assertion failure in operands_scanner::get_expr_operands (tree *expr_p, int flags), line 945:
>>>>>>>>> 
>>>>>>>>> 939   /* If we get here, something has gone wrong.  */
>>>>>>>>> 940   if (flag_checking)
>>>>>>>>> 941     {
>>>>>>>>> 942       fprintf (stderr, "unhandled expression in get_expr_operands():\n");
>>>>>>>>> 943       debug_tree (expr);
>>>>>>>>> 944       fputs ("\n", stderr);
>>>>>>>>> 945       gcc_unreachable ();
>>>>>>>>> 946     }
>>>>>>>>> 
>>>>>>>>> Looks like that  the gimple statement:
>>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>>> 
>>>>>>>>> Is not valid.  i.e, the LHS should not be an indirection to a pointer. 
>>>>>>>>> 
>>>>>>>>> How to resolve this issue?
>>>>>>> 
>>>>>>> It sounds like the LHS is an INDIRECT_REF maybe?  That means it's
>>>>>>> still not properly gimplified because it should end up as a MEM_REF
>>>>>>> instead.
>>>>>>> 
>>>>>>> But I'm just guessing here ... if you are in a debugger then you can
>>>>>>> invoke debug_tree (lhs) in the inferior to see what it exactly is
>>>>>>> at the point of the failure.
>>>>>> 
>>>>>> Yes, it’s an INDIRECT_REF at the point of the failure even though I added a 
>>>>>> 
>>>>>> gimplify_var_or_parm_decl  (lhs) 
>>>>> 
>>>>> I think the easiest is to build the .DEFERRED_INIT as GENERIC
>>>>> and use gimplify_assign () to gimplify and add the result
>>>>> to the sequence.  Thus, build a GENERIC CALL_EXPR and then
>>>>> gimplify_assign (lhs, call_expr, seq);
>>>> 
>>>> Which utility routine is used to build an Internal generic call?
>>>> Currently, I used “gimple_build_call_internal” to build this internal gimple call.
>>>> 
>>>> For the generic call, shall I use “build_call_expr_loc” ? 
>>> 
>>> For example look at build_asan_poison_call_expr which does such thing
>>> for ASAN poison internal function call insertion at gimplification time.
>>> 
>>> Richard.
>>> 
>>>> Qing
>>>> 
>>>>> 
>>>>> Richard.
>>>>> 
>>>>>> Qing
>>>>>> 
>>>>>>> 
>>>>>>>> I came up with the following solution:
>>>>>>>> 
>>>>>>>> Define the IFN_DEFERRED_INIT function as:
>>>>>>>> 
>>>>>>>> LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA);
>>>>>>>> 
>>>>>>>> if IS_VLA is false, the LHS is the DECL itself,
>>>>>>>> if IS_VLA is true, the LHS is the pointer to this DECL that created by
>>>>>>>> gimplify_vla_decl.
>>>>>>>> 
>>>>>>>> 
>>>>>>>> The benefit of this solution are:
>>>>>>>> 
>>>>>>>> 1. Resolved the invalid IR issue;
>>>>>>>> 2. The call stmt carries the address of the VLA natually;
>>>>>>>> 
>>>>>>>> The issue with this solution is:
>>>>>>>> 
>>>>>>>> For VLA and non-VLA, the LHS will be different, 
>>>>>>>> 
>>>>>>>> Do you see any other potential issues with this solution?
>>>>>>>> 
>>>>>>>> thanks.
>>>>>>>> 
>>>>>>>> Qing
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>> 
>>>>>>> -- 
>>>>>>> Richard Biener <rguenther@suse.de>
>>>>>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>>>>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>>>>>> 
>>>>>> 
>>>>> 
>>>>> -- 
>>>>> Richard Biener <rguenther@suse.de>
>>>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>>>> 
>>>> 
>>> 
>>> -- 
>>> 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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-11 16:15                       ` Richard Sandiford
@ 2021-08-11 16:29                         ` Qing Zhao
  0 siblings, 0 replies; 60+ messages in thread
From: Qing Zhao @ 2021-08-11 16:29 UTC (permalink / raw)
  To: Richard Sandiford
  Cc: Qing Zhao via Gcc-patches, Richard Biener, Jakub Jelinek, Kees Cook



> On Aug 11, 2021, at 11:15 AM, Richard Sandiford <richard.sandiford@arm.com> wrote:
> 
> Qing Zhao <qing.zhao@oracle.com> writes:
>>> On Aug 11, 2021, at 4:02 AM, Richard Sandiford <richard.sandiford@arm.com> wrote:
>>>> I came up with the following solution:
>>>> 
>>>> Define the IFN_DEFERRED_INIT function as:
>>>> 
>>>>  LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA);
>>>> 
>>>>  if IS_VLA is false, the LHS is the DECL itself,
>>>>  if IS_VLA is true, the LHS is the pointer to this DECL that created by
>>>>  gimplify_vla_decl.
>>>> 
>>>> 
>>>> The benefit of this solution are:
>>>> 
>>>> 1. Resolved the invalid IR issue;
>>>> 2. The call stmt carries the address of the VLA natually;
>>>> 
>>>> The issue with this solution is:
>>>> 
>>>> For VLA and non-VLA, the LHS will be different, 
>>>> 
>>>> Do you see any other potential issues with this solution?
>>> 
>>> The idea behind the DECL version of the .DEFERRED_INIT semantics was
>>> that .DEFERRED_INIT just returns a SIZE-byte value that the caller
>>> then assigns to a SIZE-byte lhs (with the caller choosing the lhs).
>>> .DEFEREED_INIT itself doesn't read or write memory and so can be const,
>>> which in turn allows alias analysis to be more precise.
>> Yes. That’s right.
>> 
>>> 
>>> If we want to handle the VLA case using pointers instead then I think
>>> that needs to be a different IFN.
>>> 
>>> If we did handle the VLA case using pointers (not expressing an opinion
>>> on that), then it would be the caller's job to allocate the VLA and work
>>> out the address of the VLA;
>> 
>> the current routine “gimplify_vla_decl” has done this already:
>> 
>> It created a temporary variable for the address of the VLA, and created a call to “alloca” to allocate the VLA.
> 
> Right, that's what I mean.  It's this alloca that allocates the VLA
> and determines its address.  This address is therefore logically an
> input rather than an output to the following zero/pattern initialisation.
> 
> In C you wouldn't write:
> 
>  addr = alloca(size);
>  addr = initialise(size);
> 
> to allocate and initialise a size-byte buffer, because initialise()
> would need to know the address of the memory it's supposed to initialise.
> The same is true for this gimple code.

This really make good sense to me.  :-)

> 
>> My -ftrivial-auto-var-init work just try to use the “address variable of the VLA” in the new .DEFERRED_INIT call to carry it to RTL expansion phase.
>> 
>> 
>>> this isn't something that .DEFERRED_INIT
>>> would work out on the caller's behalf.  The address of the VLA should
>>> therefore be an argument to the new IFN, rather than something that
>>> the IFN returns.
>> 
>> Then what’s the LHS of this call? Currently the major issue is the LHS is invalid gimple.
> 
> For this (different, address-taking, VLA-only) IFN, there would be no lhs.
> The IFN would be similar to a memset.

I see. 
> 
> Like I say, this is all hypothetical, based on “if we did handle the VLA
> case using pointers”.  As discussed, it would make alias analysis less
> precise.  I was just answering the question about whether there were
> potential issues.

Okay,  understood.

I will not handle the VLA case using pointers at this time. 

Per discussion with Richard Biener in the other emails, I might go the other route to special handle the 

_1 = .DEFERRED_INIT (4, 2, 0);
  alt_reloc = _1;

To see whether that can resolve the issues.

Let me know your opinion.

Thanks a lot.

Qing

> 
> Thanks,
> Richard


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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-11 16:22                                 ` Qing Zhao
@ 2021-08-11 16:55                                   ` Richard Biener
  2021-08-11 16:57                                     ` Qing Zhao
  2021-08-11 20:30                                     ` Qing Zhao
  0 siblings, 2 replies; 60+ messages in thread
From: Richard Biener @ 2021-08-11 16:55 UTC (permalink / raw)
  To: Qing Zhao
  Cc: Richard Sandiford, Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook

On August 11, 2021 6:22:00 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>
>
>> On Aug 11, 2021, at 10:53 AM, Richard Biener <rguenther@suse.de> wrote:
>> 
>> On August 11, 2021 5:30:40 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>>> I modified the routine “gimple_add_init_for_auto_var” as the following:
>>> ====
>>> /* Generate initialization to automatic variable DECL based on INIT_TYPE.
>>>  Build a call to internal const function DEFERRED_INIT:
>>>  1st argument: SIZE of the DECL;
>>>  2nd argument: INIT_TYPE;
>>>  3rd argument: IS_VLA, 0 NO, 1 YES;
>>> 
>>>  as DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA).  */
>>> static void
>>> gimple_add_init_for_auto_var (tree decl,
>>>                             enum auto_init_type init_type,
>>>                             bool is_vla,
>>>                             gimple_seq *seq_p)
>>> {
>>> gcc_assert (VAR_P (decl) && !DECL_EXTERNAL (decl) && !TREE_STATIC (decl));
>>> gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>>> tree decl_size = TYPE_SIZE_UNIT (TREE_TYPE (decl));
>>> 
>>> tree init_type_node
>>>   = build_int_cst (integer_type_node, (int) init_type);
>>> tree is_vla_node
>>>   = build_int_cst (integer_type_node, (int) is_vla);
>>> 
>>> tree call = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
>>>                                           TREE_TYPE (decl), 3,
>>>                                           decl_size, init_type_node,
>>>                                           is_vla_node);
>>> 
>>> /* If this DECL is a VLA, a temporary address variable for it has been
>>>    created, the replacement for DECL is recorded in DECL_VALUE_EXPR (decl),
>>>    we should use it as the LHS of the call.  */
>>> 
>>> tree lhs_call
>>>   = is_vla ? DECL_VALUE_EXPR (decl) : decl;
>>> gimplify_assign (lhs_call, call, seq_p);
>>> }
>>> 
>>> With this change, the current issue is resolved, the gimple dump now is:
>>> 
>>> (*arr.1) = .DEFERRED_INIT (D.1952, 2, 1);
>>> 
>>> However, there is another new issue:
>>> 
>>> For the following testing case:
>>> 
>>> ======
>>> [opc@qinzhao-ol8u3-x86 gcc]$ cat t.c
>>> int bar;
>>> 
>>> extern void decode_reloc(int *);
>>> 
>>> void testfunc()
>>> {
>>> int alt_reloc;
>>> 
>>> decode_reloc(&alt_reloc);
>>> 
>>> if (alt_reloc) /* { dg-warning "may be used uninitialized" } */
>>>   bar = 42; 
>>> }
>>> =====
>>> 
>>> In the above, the auto var “alt_reloc” is address taken, then the gimple dump for it when compiled with -ftrivial-auto-var-init=zero is:
>>> 
>>> void testfunc ()
>>> {
>>> int alt_reloc;
>>> 
>>> try
>>>   {
>>>     _1 = .DEFERRED_INIT (4, 2, 0);
>>>     alt_reloc = _1;
>>>     decode_reloc (&alt_reloc);
>>>     alt_reloc.0_2 = alt_reloc;
>>>     if (alt_reloc.0_2 != 0) goto <D.1949>; else goto <D.1950>;
>>>     <D.1949>:
>>>     bar = 42;
>>>     <D.1950>:
>>>   }
>>> finally
>>>   {
>>>     alt_reloc = {CLOBBER};
>>>   }
>>> }
>>> 
>>> I.e, instead of the expected IR:
>>> 
>>> alt_reloc = .DEFERRED_INIT (4, 2, 0);
>>> 
>>> We got the following:
>>> 
>>> _1 = .DEFERRED_INIT (4, 2, 0);
>>>     alt_reloc = _1;
>>> 
>>> I guess the temp “_1” is created because “alt_reloc” is address taken. 
>> 
>> Yes and no. The reason is that alt_reloc is memory (because it is address taken) and that GIMPLE says that register typed stores need to use a is_gimple_val RHS which the call is not.
>
>Okay.
>> 
>>> My questions:
>>> 
>>> Shall we accept such IR for .DEFERRED_INIT purpose when the auto var is address taken? 
>> 
>> I think so. Note it doesn't necessarily need address taking but any other reason that prevents SSA rewriting the variable suffices. 
>
>You mean, in addition to “address taken”, there are other situations that will introduce such IR:
>
>temp = .DEFERRED_INIT();
>auto_var = temp;
>
>So, such IR is unavoidable and we have to handle it?

Yes. 

>If we have to handle it,  what’ the best way to do it?
>
>The solution in my mind is:
>1. During uninitialized analysis phase, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then decide that “auto_var” is uninitialized.

Yes. Basically if there's an artificial variable auto initialized you have to look at its uses. 

>2. During RTL expansion, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then delete “temp”, and then expand .DEFERRED_INIT to auto_var.

That shouldn't be necessary. You'd initialize a temporary register which is then copied to the real variable. That's good enough and should be optimized by the RTL pipeline. 

>Let me know your comments and suggestions on this.
>
>
>> 
>> The only other option is to force. DEFERED_INIT making the LHS address taken which I think could be achieved by passing it the address as argument instead of having a LHS. But let's not go down this route - it will have quite bad behavior on alias analysis and optimization. 
>
>Okay.
>
>Qing
>> 
>>> If so, “uninitialized analysis” phase need to be further adjusted to specially handle such IR. 
>>> 
>>> If not, what should we do when the auto var is address taken?
>>> 
>>> Thanks a lot.
>>> 
>>> Qing
>>> 
>>> 
>>>> On Aug 11, 2021, at 8:58 AM, Richard Biener <rguenther@suse.de> wrote:
>>>> 
>>>> On Wed, 11 Aug 2021, Qing Zhao wrote:
>>>> 
>>>>> 
>>>>> 
>>>>>> On Aug 11, 2021, at 8:37 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>> 
>>>>>> On Wed, 11 Aug 2021, Qing Zhao wrote:
>>>>>> 
>>>>>>> 
>>>>>>> 
>>>>>>>> On Aug 11, 2021, at 2:02 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>>> 
>>>>>>>> On Tue, 10 Aug 2021, Qing Zhao wrote:
>>>>>>>> 
>>>>>>>>> 
>>>>>>>>> 
>>>>>>>>>> On Aug 10, 2021, at 3:16 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>>>>>>>>> 
>>>>>>>>>> Hi, Richard,
>>>>>>>>>> 
>>>>>>>>>>> On Aug 10, 2021, at 10:22 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>>>>>>>> 
>>>>>>>>>>>>> Especially in the VLA case but likely also in general (though unlikely
>>>>>>>>>>>>> since usually the receiver of initializations are simple enough).  I'd
>>>>>>>>>>>>> expect the VLA case end up as
>>>>>>>>>>>>> 
>>>>>>>>>>>>> *ptr_to_decl = .DEFERRED_INIT (...);
>>>>>>>>>>>>> 
>>>>>>>>>>>>> where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.
>>>>>>>>>>>> 
>>>>>>>>>>>> So, for the following small testing case:
>>>>>>>>>>>> 
>>>>>>>>>>>> ====
>>>>>>>>>>>> extern void bar (int);
>>>>>>>>>>>> 
>>>>>>>>>>>> void foo(int n)
>>>>>>>>>>>> {
>>>>>>>>>>>> int arr[n];
>>>>>>>>>>>> bar (arr[2]);
>>>>>>>>>>>> return;
>>>>>>>>>>>> }
>>>>>>>>>>>> =====
>>>>>>>>>>>> 
>>>>>>>>>>>> If I compile it with -ftrivial-auto-var-init=zero -fdump-tree-gimple -S -o auto-init-11.s -fdump-rtl-expand, the *.gimple dump is:
>>>>>>>>>>>> 
>>>>>>>>>>>> =====
>>>>>>>>>>>> void foo (int n)
>>>>>>>>>>>> {
>>>>>>>>>>>> int n.0;
>>>>>>>>>>>> sizetype D.1950;
>>>>>>>>>>>> bitsizetype D.1951;
>>>>>>>>>>>> sizetype D.1952;
>>>>>>>>>>>> bitsizetype D.1953;
>>>>>>>>>>>> sizetype D.1954;
>>>>>>>>>>>> int[0:D.1950] * arr.1;
>>>>>>>>>>>> void * saved_stack.2;
>>>>>>>>>>>> int arr[0:D.1950] [value-expr: *arr.1];
>>>>>>>>>>>> 
>>>>>>>>>>>> saved_stack.2 = __builtin_stack_save ();
>>>>>>>>>>>> try
>>>>>>>>>>>> {
>>>>>>>>>>>> n.0 = n;
>>>>>>>>>>>> _1 = (long int) n.0;
>>>>>>>>>>>> _2 = _1 + -1;
>>>>>>>>>>>> _3 = (sizetype) _2;
>>>>>>>>>>>> D.1950 = _3;
>>>>>>>>>>>> _4 = (sizetype) n.0;
>>>>>>>>>>>> _5 = (bitsizetype) _4;
>>>>>>>>>>>> _6 = _5 * 32;
>>>>>>>>>>>> D.1951 = _6;
>>>>>>>>>>>> _7 = (sizetype) n.0;
>>>>>>>>>>>> _8 = _7 * 4;
>>>>>>>>>>>> D.1952 = _8;
>>>>>>>>>>>> _9 = (sizetype) n.0;
>>>>>>>>>>>> _10 = (bitsizetype) _9;
>>>>>>>>>>>> _11 = _10 * 32;
>>>>>>>>>>>> D.1953 = _11;
>>>>>>>>>>>> _12 = (sizetype) n.0;
>>>>>>>>>>>> _13 = _12 * 4;
>>>>>>>>>>>> D.1954 = _13;
>>>>>>>>>>>> arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>>>>>>>>> arr = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>>>>>> _14 = (*arr.1)[2];
>>>>>>>>>>>> bar (_14);
>>>>>>>>>>>> return;
>>>>>>>>>>>> }
>>>>>>>>>>>> finally
>>>>>>>>>>>> {
>>>>>>>>>>>> __builtin_stack_restore (saved_stack.2);
>>>>>>>>>>>> }
>>>>>>>>>>>> }
>>>>>>>>>>>> 
>>>>>>>>>>>> ====
>>>>>>>>>>>> 
>>>>>>>>>>>> You think that the above .DEFEERED_INIT is not correct?
>>>>>>>>>>>> It should be:
>>>>>>>>>>>> 
>>>>>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952. 2, 1);
>>>>>>>>>>>> 
>>>>>>>>>>>> ?
>>>>>>>>>>> 
>>>>>>>>>>> Yes.
>>>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>>> I updated gimplify.c for VLA and now it emits the call to .DEFERRED_INIT as:
>>>>>>>>>> 
>>>>>>>>>>  arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>>>>>>>  *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>>>> 
>>>>>>>>>> However, this call triggered the assertion failure in verify_gimple_call of tree-cfg.c because the LHS is not a valid LHS. 
>>>>>>>>>> Then I modify tree-cfg.c as:
>>>>>>>>>> 
>>>>>>>>>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
>>>>>>>>>> index 330eb7dd89bf..180d4f1f9e32 100644
>>>>>>>>>> --- a/gcc/tree-cfg.c
>>>>>>>>>> +++ b/gcc/tree-cfg.c
>>>>>>>>>> @@ -3375,7 +3375,11 @@ verify_gimple_call (gcall *stmt)
>>>>>>>>>>  }
>>>>>>>>>> 
>>>>>>>>>> tree lhs = gimple_call_lhs (stmt);
>>>>>>>>>> +  /* For .DEFERRED_INIT call, the LHS might be an indirection of
>>>>>>>>>> +     a pointer for the VLA variable, which is not a valid LHS of
>>>>>>>>>> +     a gimple call, we ignore the asssertion on this.  */ 
>>>>>>>>>> if (lhs
>>>>>>>>>> +      && (!gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
>>>>>>>>>>   && (!is_gimple_reg (lhs)
>>>>>>>>>>      && (!is_gimple_lvalue (lhs)
>>>>>>>>>>          || verify_types_in_gimple_reference
>>>>>>>>>> 
>>>>>>>>>> The assertion failure in tree-cfg.c got resolved, but I got another assertion failure in operands_scanner::get_expr_operands (tree *expr_p, int flags), line 945:
>>>>>>>>>> 
>>>>>>>>>> 939   /* If we get here, something has gone wrong.  */
>>>>>>>>>> 940   if (flag_checking)
>>>>>>>>>> 941     {
>>>>>>>>>> 942       fprintf (stderr, "unhandled expression in get_expr_operands():\n");
>>>>>>>>>> 943       debug_tree (expr);
>>>>>>>>>> 944       fputs ("\n", stderr);
>>>>>>>>>> 945       gcc_unreachable ();
>>>>>>>>>> 946     }
>>>>>>>>>> 
>>>>>>>>>> Looks like that  the gimple statement:
>>>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>>>> 
>>>>>>>>>> Is not valid.  i.e, the LHS should not be an indirection to a pointer. 
>>>>>>>>>> 
>>>>>>>>>> How to resolve this issue?
>>>>>>>> 
>>>>>>>> It sounds like the LHS is an INDIRECT_REF maybe?  That means it's
>>>>>>>> still not properly gimplified because it should end up as a MEM_REF
>>>>>>>> instead.
>>>>>>>> 
>>>>>>>> But I'm just guessing here ... if you are in a debugger then you can
>>>>>>>> invoke debug_tree (lhs) in the inferior to see what it exactly is
>>>>>>>> at the point of the failure.
>>>>>>> 
>>>>>>> Yes, it’s an INDIRECT_REF at the point of the failure even though I added a 
>>>>>>> 
>>>>>>> gimplify_var_or_parm_decl  (lhs) 
>>>>>> 
>>>>>> I think the easiest is to build the .DEFERRED_INIT as GENERIC
>>>>>> and use gimplify_assign () to gimplify and add the result
>>>>>> to the sequence.  Thus, build a GENERIC CALL_EXPR and then
>>>>>> gimplify_assign (lhs, call_expr, seq);
>>>>> 
>>>>> Which utility routine is used to build an Internal generic call?
>>>>> Currently, I used “gimple_build_call_internal” to build this internal gimple call.
>>>>> 
>>>>> For the generic call, shall I use “build_call_expr_loc” ? 
>>>> 
>>>> For example look at build_asan_poison_call_expr which does such thing
>>>> for ASAN poison internal function call insertion at gimplification time.
>>>> 
>>>> Richard.
>>>> 
>>>>> Qing
>>>>> 
>>>>>> 
>>>>>> Richard.
>>>>>> 
>>>>>>> Qing
>>>>>>> 
>>>>>>>> 
>>>>>>>>> I came up with the following solution:
>>>>>>>>> 
>>>>>>>>> Define the IFN_DEFERRED_INIT function as:
>>>>>>>>> 
>>>>>>>>> LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA);
>>>>>>>>> 
>>>>>>>>> if IS_VLA is false, the LHS is the DECL itself,
>>>>>>>>> if IS_VLA is true, the LHS is the pointer to this DECL that created by
>>>>>>>>> gimplify_vla_decl.
>>>>>>>>> 
>>>>>>>>> 
>>>>>>>>> The benefit of this solution are:
>>>>>>>>> 
>>>>>>>>> 1. Resolved the invalid IR issue;
>>>>>>>>> 2. The call stmt carries the address of the VLA natually;
>>>>>>>>> 
>>>>>>>>> The issue with this solution is:
>>>>>>>>> 
>>>>>>>>> For VLA and non-VLA, the LHS will be different, 
>>>>>>>>> 
>>>>>>>>> Do you see any other potential issues with this solution?
>>>>>>>>> 
>>>>>>>>> thanks.
>>>>>>>>> 
>>>>>>>>> Qing
>>>>>>>>> 
>>>>>>>>> 
>>>>>>>>> 
>>>>>>>>> 
>>>>>>>>> 
>>>>>>>> 
>>>>>>>> -- 
>>>>>>>> Richard Biener <rguenther@suse.de>
>>>>>>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>>>>>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>>>>>>> 
>>>>>>> 
>>>>>> 
>>>>>> -- 
>>>>>> Richard Biener <rguenther@suse.de>
>>>>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>>>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>>>>> 
>>>>> 
>>>> 
>>>> -- 
>>>> 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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-11 16:55                                   ` Richard Biener
@ 2021-08-11 16:57                                     ` Qing Zhao
  2021-08-11 20:30                                     ` Qing Zhao
  1 sibling, 0 replies; 60+ messages in thread
From: Qing Zhao @ 2021-08-11 16:57 UTC (permalink / raw)
  To: Richard Biener
  Cc: Richard Sandiford, Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook



> On Aug 11, 2021, at 11:55 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On August 11, 2021 6:22:00 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>> 
>> 
>>> On Aug 11, 2021, at 10:53 AM, Richard Biener <rguenther@suse.de> wrote:
>>> 
>>> On August 11, 2021 5:30:40 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>>>> I modified the routine “gimple_add_init_for_auto_var” as the following:
>>>> ====
>>>> /* Generate initialization to automatic variable DECL based on INIT_TYPE.
>>>> Build a call to internal const function DEFERRED_INIT:
>>>> 1st argument: SIZE of the DECL;
>>>> 2nd argument: INIT_TYPE;
>>>> 3rd argument: IS_VLA, 0 NO, 1 YES;
>>>> 
>>>> as DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA).  */
>>>> static void
>>>> gimple_add_init_for_auto_var (tree decl,
>>>>                            enum auto_init_type init_type,
>>>>                            bool is_vla,
>>>>                            gimple_seq *seq_p)
>>>> {
>>>> gcc_assert (VAR_P (decl) && !DECL_EXTERNAL (decl) && !TREE_STATIC (decl));
>>>> gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>>>> tree decl_size = TYPE_SIZE_UNIT (TREE_TYPE (decl));
>>>> 
>>>> tree init_type_node
>>>>  = build_int_cst (integer_type_node, (int) init_type);
>>>> tree is_vla_node
>>>>  = build_int_cst (integer_type_node, (int) is_vla);
>>>> 
>>>> tree call = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
>>>>                                          TREE_TYPE (decl), 3,
>>>>                                          decl_size, init_type_node,
>>>>                                          is_vla_node);
>>>> 
>>>> /* If this DECL is a VLA, a temporary address variable for it has been
>>>>   created, the replacement for DECL is recorded in DECL_VALUE_EXPR (decl),
>>>>   we should use it as the LHS of the call.  */
>>>> 
>>>> tree lhs_call
>>>>  = is_vla ? DECL_VALUE_EXPR (decl) : decl;
>>>> gimplify_assign (lhs_call, call, seq_p);
>>>> }
>>>> 
>>>> With this change, the current issue is resolved, the gimple dump now is:
>>>> 
>>>> (*arr.1) = .DEFERRED_INIT (D.1952, 2, 1);
>>>> 
>>>> However, there is another new issue:
>>>> 
>>>> For the following testing case:
>>>> 
>>>> ======
>>>> [opc@qinzhao-ol8u3-x86 gcc]$ cat t.c
>>>> int bar;
>>>> 
>>>> extern void decode_reloc(int *);
>>>> 
>>>> void testfunc()
>>>> {
>>>> int alt_reloc;
>>>> 
>>>> decode_reloc(&alt_reloc);
>>>> 
>>>> if (alt_reloc) /* { dg-warning "may be used uninitialized" } */
>>>>  bar = 42; 
>>>> }
>>>> =====
>>>> 
>>>> In the above, the auto var “alt_reloc” is address taken, then the gimple dump for it when compiled with -ftrivial-auto-var-init=zero is:
>>>> 
>>>> void testfunc ()
>>>> {
>>>> int alt_reloc;
>>>> 
>>>> try
>>>>  {
>>>>    _1 = .DEFERRED_INIT (4, 2, 0);
>>>>    alt_reloc = _1;
>>>>    decode_reloc (&alt_reloc);
>>>>    alt_reloc.0_2 = alt_reloc;
>>>>    if (alt_reloc.0_2 != 0) goto <D.1949>; else goto <D.1950>;
>>>>    <D.1949>:
>>>>    bar = 42;
>>>>    <D.1950>:
>>>>  }
>>>> finally
>>>>  {
>>>>    alt_reloc = {CLOBBER};
>>>>  }
>>>> }
>>>> 
>>>> I.e, instead of the expected IR:
>>>> 
>>>> alt_reloc = .DEFERRED_INIT (4, 2, 0);
>>>> 
>>>> We got the following:
>>>> 
>>>> _1 = .DEFERRED_INIT (4, 2, 0);
>>>>    alt_reloc = _1;
>>>> 
>>>> I guess the temp “_1” is created because “alt_reloc” is address taken. 
>>> 
>>> Yes and no. The reason is that alt_reloc is memory (because it is address taken) and that GIMPLE says that register typed stores need to use a is_gimple_val RHS which the call is not.
>> 
>> Okay.
>>> 
>>>> My questions:
>>>> 
>>>> Shall we accept such IR for .DEFERRED_INIT purpose when the auto var is address taken? 
>>> 
>>> I think so. Note it doesn't necessarily need address taking but any other reason that prevents SSA rewriting the variable suffices. 
>> 
>> You mean, in addition to “address taken”, there are other situations that will introduce such IR:
>> 
>> temp = .DEFERRED_INIT();
>> auto_var = temp;
>> 
>> So, such IR is unavoidable and we have to handle it?
> 
> Yes. 
> 
>> If we have to handle it,  what’ the best way to do it?
>> 
>> The solution in my mind is:
>> 1. During uninitialized analysis phase, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then decide that “auto_var” is uninitialized.
> 
> Yes. Basically if there's an artificial variable auto initialized you have to look at its uses. 
Okay. 

> 
>> 2. During RTL expansion, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then delete “temp”, and then expand .DEFERRED_INIT to auto_var.
> 
> That shouldn't be necessary. You'd initialize a temporary register which is then copied to the real variable. That's good enough and should be optimized by the RTL pipeline. 

Okay, I see. 

I will try to update the code to see whether all the issues can be resolved.

Thanks a lot for your help.

Qing
> 
>> Let me know your comments and suggestions on this.
>> 
>> 
>>> 
>>> The only other option is to force. DEFERED_INIT making the LHS address taken which I think could be achieved by passing it the address as argument instead of having a LHS. But let's not go down this route - it will have quite bad behavior on alias analysis and optimization. 
>> 
>> Okay.
>> 
>> Qing
>>> 
>>>> If so, “uninitialized analysis” phase need to be further adjusted to specially handle such IR. 
>>>> 
>>>> If not, what should we do when the auto var is address taken?
>>>> 
>>>> Thanks a lot.
>>>> 
>>>> Qing
>>>> 
>>>> 
>>>>> On Aug 11, 2021, at 8:58 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>> 
>>>>> On Wed, 11 Aug 2021, Qing Zhao wrote:
>>>>> 
>>>>>> 
>>>>>> 
>>>>>>> On Aug 11, 2021, at 8:37 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>> 
>>>>>>> On Wed, 11 Aug 2021, Qing Zhao wrote:
>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>>> On Aug 11, 2021, at 2:02 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>>>> 
>>>>>>>>> On Tue, 10 Aug 2021, Qing Zhao wrote:
>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>>>> On Aug 10, 2021, at 3:16 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>>>>>>>>>> 
>>>>>>>>>>> Hi, Richard,
>>>>>>>>>>> 
>>>>>>>>>>>> On Aug 10, 2021, at 10:22 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> Especially in the VLA case but likely also in general (though unlikely
>>>>>>>>>>>>>> since usually the receiver of initializations are simple enough).  I'd
>>>>>>>>>>>>>> expect the VLA case end up as
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> *ptr_to_decl = .DEFERRED_INIT (...);
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.
>>>>>>>>>>>>> 
>>>>>>>>>>>>> So, for the following small testing case:
>>>>>>>>>>>>> 
>>>>>>>>>>>>> ====
>>>>>>>>>>>>> extern void bar (int);
>>>>>>>>>>>>> 
>>>>>>>>>>>>> void foo(int n)
>>>>>>>>>>>>> {
>>>>>>>>>>>>> int arr[n];
>>>>>>>>>>>>> bar (arr[2]);
>>>>>>>>>>>>> return;
>>>>>>>>>>>>> }
>>>>>>>>>>>>> =====
>>>>>>>>>>>>> 
>>>>>>>>>>>>> If I compile it with -ftrivial-auto-var-init=zero -fdump-tree-gimple -S -o auto-init-11.s -fdump-rtl-expand, the *.gimple dump is:
>>>>>>>>>>>>> 
>>>>>>>>>>>>> =====
>>>>>>>>>>>>> void foo (int n)
>>>>>>>>>>>>> {
>>>>>>>>>>>>> int n.0;
>>>>>>>>>>>>> sizetype D.1950;
>>>>>>>>>>>>> bitsizetype D.1951;
>>>>>>>>>>>>> sizetype D.1952;
>>>>>>>>>>>>> bitsizetype D.1953;
>>>>>>>>>>>>> sizetype D.1954;
>>>>>>>>>>>>> int[0:D.1950] * arr.1;
>>>>>>>>>>>>> void * saved_stack.2;
>>>>>>>>>>>>> int arr[0:D.1950] [value-expr: *arr.1];
>>>>>>>>>>>>> 
>>>>>>>>>>>>> saved_stack.2 = __builtin_stack_save ();
>>>>>>>>>>>>> try
>>>>>>>>>>>>> {
>>>>>>>>>>>>> n.0 = n;
>>>>>>>>>>>>> _1 = (long int) n.0;
>>>>>>>>>>>>> _2 = _1 + -1;
>>>>>>>>>>>>> _3 = (sizetype) _2;
>>>>>>>>>>>>> D.1950 = _3;
>>>>>>>>>>>>> _4 = (sizetype) n.0;
>>>>>>>>>>>>> _5 = (bitsizetype) _4;
>>>>>>>>>>>>> _6 = _5 * 32;
>>>>>>>>>>>>> D.1951 = _6;
>>>>>>>>>>>>> _7 = (sizetype) n.0;
>>>>>>>>>>>>> _8 = _7 * 4;
>>>>>>>>>>>>> D.1952 = _8;
>>>>>>>>>>>>> _9 = (sizetype) n.0;
>>>>>>>>>>>>> _10 = (bitsizetype) _9;
>>>>>>>>>>>>> _11 = _10 * 32;
>>>>>>>>>>>>> D.1953 = _11;
>>>>>>>>>>>>> _12 = (sizetype) n.0;
>>>>>>>>>>>>> _13 = _12 * 4;
>>>>>>>>>>>>> D.1954 = _13;
>>>>>>>>>>>>> arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>>>>>>>>>> arr = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>>>>>>> _14 = (*arr.1)[2];
>>>>>>>>>>>>> bar (_14);
>>>>>>>>>>>>> return;
>>>>>>>>>>>>> }
>>>>>>>>>>>>> finally
>>>>>>>>>>>>> {
>>>>>>>>>>>>> __builtin_stack_restore (saved_stack.2);
>>>>>>>>>>>>> }
>>>>>>>>>>>>> }
>>>>>>>>>>>>> 
>>>>>>>>>>>>> ====
>>>>>>>>>>>>> 
>>>>>>>>>>>>> You think that the above .DEFEERED_INIT is not correct?
>>>>>>>>>>>>> It should be:
>>>>>>>>>>>>> 
>>>>>>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952. 2, 1);
>>>>>>>>>>>>> 
>>>>>>>>>>>>> ?
>>>>>>>>>>>> 
>>>>>>>>>>>> Yes.
>>>>>>>>>>>> 
>>>>>>>>>>> 
>>>>>>>>>>> I updated gimplify.c for VLA and now it emits the call to .DEFERRED_INIT as:
>>>>>>>>>>> 
>>>>>>>>>>> arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>>>>> 
>>>>>>>>>>> However, this call triggered the assertion failure in verify_gimple_call of tree-cfg.c because the LHS is not a valid LHS. 
>>>>>>>>>>> Then I modify tree-cfg.c as:
>>>>>>>>>>> 
>>>>>>>>>>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
>>>>>>>>>>> index 330eb7dd89bf..180d4f1f9e32 100644
>>>>>>>>>>> --- a/gcc/tree-cfg.c
>>>>>>>>>>> +++ b/gcc/tree-cfg.c
>>>>>>>>>>> @@ -3375,7 +3375,11 @@ verify_gimple_call (gcall *stmt)
>>>>>>>>>>> }
>>>>>>>>>>> 
>>>>>>>>>>> tree lhs = gimple_call_lhs (stmt);
>>>>>>>>>>> +  /* For .DEFERRED_INIT call, the LHS might be an indirection of
>>>>>>>>>>> +     a pointer for the VLA variable, which is not a valid LHS of
>>>>>>>>>>> +     a gimple call, we ignore the asssertion on this.  */ 
>>>>>>>>>>> if (lhs
>>>>>>>>>>> +      && (!gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
>>>>>>>>>>>  && (!is_gimple_reg (lhs)
>>>>>>>>>>>     && (!is_gimple_lvalue (lhs)
>>>>>>>>>>>         || verify_types_in_gimple_reference
>>>>>>>>>>> 
>>>>>>>>>>> The assertion failure in tree-cfg.c got resolved, but I got another assertion failure in operands_scanner::get_expr_operands (tree *expr_p, int flags), line 945:
>>>>>>>>>>> 
>>>>>>>>>>> 939   /* If we get here, something has gone wrong.  */
>>>>>>>>>>> 940   if (flag_checking)
>>>>>>>>>>> 941     {
>>>>>>>>>>> 942       fprintf (stderr, "unhandled expression in get_expr_operands():\n");
>>>>>>>>>>> 943       debug_tree (expr);
>>>>>>>>>>> 944       fputs ("\n", stderr);
>>>>>>>>>>> 945       gcc_unreachable ();
>>>>>>>>>>> 946     }
>>>>>>>>>>> 
>>>>>>>>>>> Looks like that  the gimple statement:
>>>>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>>>>> 
>>>>>>>>>>> Is not valid.  i.e, the LHS should not be an indirection to a pointer. 
>>>>>>>>>>> 
>>>>>>>>>>> How to resolve this issue?
>>>>>>>>> 
>>>>>>>>> It sounds like the LHS is an INDIRECT_REF maybe?  That means it's
>>>>>>>>> still not properly gimplified because it should end up as a MEM_REF
>>>>>>>>> instead.
>>>>>>>>> 
>>>>>>>>> But I'm just guessing here ... if you are in a debugger then you can
>>>>>>>>> invoke debug_tree (lhs) in the inferior to see what it exactly is
>>>>>>>>> at the point of the failure.
>>>>>>>> 
>>>>>>>> Yes, it’s an INDIRECT_REF at the point of the failure even though I added a 
>>>>>>>> 
>>>>>>>> gimplify_var_or_parm_decl  (lhs) 
>>>>>>> 
>>>>>>> I think the easiest is to build the .DEFERRED_INIT as GENERIC
>>>>>>> and use gimplify_assign () to gimplify and add the result
>>>>>>> to the sequence.  Thus, build a GENERIC CALL_EXPR and then
>>>>>>> gimplify_assign (lhs, call_expr, seq);
>>>>>> 
>>>>>> Which utility routine is used to build an Internal generic call?
>>>>>> Currently, I used “gimple_build_call_internal” to build this internal gimple call.
>>>>>> 
>>>>>> For the generic call, shall I use “build_call_expr_loc” ? 
>>>>> 
>>>>> For example look at build_asan_poison_call_expr which does such thing
>>>>> for ASAN poison internal function call insertion at gimplification time.
>>>>> 
>>>>> Richard.
>>>>> 
>>>>>> Qing
>>>>>> 
>>>>>>> 
>>>>>>> Richard.
>>>>>>> 
>>>>>>>> Qing
>>>>>>>> 
>>>>>>>>> 
>>>>>>>>>> I came up with the following solution:
>>>>>>>>>> 
>>>>>>>>>> Define the IFN_DEFERRED_INIT function as:
>>>>>>>>>> 
>>>>>>>>>> LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA);
>>>>>>>>>> 
>>>>>>>>>> if IS_VLA is false, the LHS is the DECL itself,
>>>>>>>>>> if IS_VLA is true, the LHS is the pointer to this DECL that created by
>>>>>>>>>> gimplify_vla_decl.
>>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>>> The benefit of this solution are:
>>>>>>>>>> 
>>>>>>>>>> 1. Resolved the invalid IR issue;
>>>>>>>>>> 2. The call stmt carries the address of the VLA natually;
>>>>>>>>>> 
>>>>>>>>>> The issue with this solution is:
>>>>>>>>>> 
>>>>>>>>>> For VLA and non-VLA, the LHS will be different, 
>>>>>>>>>> 
>>>>>>>>>> Do you see any other potential issues with this solution?
>>>>>>>>>> 
>>>>>>>>>> thanks.
>>>>>>>>>> 
>>>>>>>>>> Qing
>>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>> 
>>>>>>>>> -- 
>>>>>>>>> Richard Biener <rguenther@suse.de>
>>>>>>>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>>>>>>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>>>>>>>> 
>>>>>>>> 
>>>>>>> 
>>>>>>> -- 
>>>>>>> Richard Biener <rguenther@suse.de>
>>>>>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>>>>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>>>>>> 
>>>>>> 
>>>>> 
>>>>> -- 
>>>>> 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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-11 16:55                                   ` Richard Biener
  2021-08-11 16:57                                     ` Qing Zhao
@ 2021-08-11 20:30                                     ` Qing Zhao
  2021-08-11 22:03                                       ` Qing Zhao
  2021-08-16  7:11                                       ` Richard Biener
  1 sibling, 2 replies; 60+ messages in thread
From: Qing Zhao @ 2021-08-11 20:30 UTC (permalink / raw)
  To: Richard Biener
  Cc: Richard Sandiford, Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook

Hi, 

I met another issue for “address taken” auto variable, see below for details:

**** the testing case: (gcc/testsuite/gcc.dg/uninit-16.c)

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;
}

****When compiled with -ftrivial-auto-var-init=zero -O2 -Wuninitialized -fdump-tree-all:

.*************gimple dump:

void testfunc ()
{ 
  int alt_reloc;

  try
    {
      _1 = .DEFERRED_INIT (4, 2, 0);
      alt_reloc = _1;
      foo.0_2 = foo;
      decode_reloc (foo.0_2, &alt_reloc);
      alt_reloc.1_3 = alt_reloc;
      if (alt_reloc.1_3 != 0) goto <D.1952>; else goto <D.1953>;
      <D.1952>:
      bar = 42;
      <D.1953>:
    }
  finally
    {
      alt_reloc = {CLOBBER};
    }
}

**************fre1 dump:

void testfunc ()
{
  int alt_reloc;
  int _1;
  int foo.0_2;

  <bb 2> :
  _1 = .DEFERRED_INIT (4, 2, 0);
  foo.0_2 = foo;
  if (foo.0_2 > 19)
    goto <bb 3>; [50.00%]
  else
    goto <bb 4>; [50.00%]

  <bb 3> :
  goto <bb 7>; [100.00%]

  <bb 4> :
  if (foo.0_2 > 9)
    goto <bb 5>; [50.00%]
  else
    goto <bb 6>; [50.00%]

  <bb 5> :
  goto <bb 8>; [100.00%]

  <bb 6> :
  if (_1 != 0)
    goto <bb 7>; [INV]
  else
    goto <bb 8>; [INV]

  <bb 7> :
  bar = 42;

  <bb 8> :
  return;

}

From the above IR file after “FRE”, we can see that the major issue with this IR is:

The address taken auto variable “alt_reloc” has been completely replaced by the temporary variable “_1” in all
the uses of the original “alt_reloc”. 

The major problem with such IR is,  during uninitialized analysis phase, the original use of “alt_reloc” disappeared completely.
So, the warning cannot be reported.


My questions:

1. Is it possible to get the original “alt_reloc” through the temporary variable “_1” with some available information recorded in the IR?
2. If not, then we have to record the relationship between “alt_reloc” and “_1” when the original “alt_reloc” is replaced by “_1” and get such relationship during
    Uninitialized analysis phase.  Is this doable?
3. Looks like that for “address taken” auto variable, if we have to introduce a new temporary variable and split the call to .DEFERRED_INIT into two:

      temp = .DEFERRED_INIT (4, 2, 0);
      alt_reloc = temp;

   More issues might possible.

Any comments and suggestions on this issue?

Qing

j
> On Aug 11, 2021, at 11:55 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On August 11, 2021 6:22:00 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>> 
>> 
>>> On Aug 11, 2021, at 10:53 AM, Richard Biener <rguenther@suse.de> wrote:
>>> 
>>> On August 11, 2021 5:30:40 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>>>> I modified the routine “gimple_add_init_for_auto_var” as the following:
>>>> ====
>>>> /* Generate initialization to automatic variable DECL based on INIT_TYPE.
>>>> Build a call to internal const function DEFERRED_INIT:
>>>> 1st argument: SIZE of the DECL;
>>>> 2nd argument: INIT_TYPE;
>>>> 3rd argument: IS_VLA, 0 NO, 1 YES;
>>>> 
>>>> as DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA).  */
>>>> static void
>>>> gimple_add_init_for_auto_var (tree decl,
>>>>                            enum auto_init_type init_type,
>>>>                            bool is_vla,
>>>>                            gimple_seq *seq_p)
>>>> {
>>>> gcc_assert (VAR_P (decl) && !DECL_EXTERNAL (decl) && !TREE_STATIC (decl));
>>>> gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>>>> tree decl_size = TYPE_SIZE_UNIT (TREE_TYPE (decl));
>>>> 
>>>> tree init_type_node
>>>>  = build_int_cst (integer_type_node, (int) init_type);
>>>> tree is_vla_node
>>>>  = build_int_cst (integer_type_node, (int) is_vla);
>>>> 
>>>> tree call = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
>>>>                                          TREE_TYPE (decl), 3,
>>>>                                          decl_size, init_type_node,
>>>>                                          is_vla_node);
>>>> 
>>>> /* If this DECL is a VLA, a temporary address variable for it has been
>>>>   created, the replacement for DECL is recorded in DECL_VALUE_EXPR (decl),
>>>>   we should use it as the LHS of the call.  */
>>>> 
>>>> tree lhs_call
>>>>  = is_vla ? DECL_VALUE_EXPR (decl) : decl;
>>>> gimplify_assign (lhs_call, call, seq_p);
>>>> }
>>>> 
>>>> With this change, the current issue is resolved, the gimple dump now is:
>>>> 
>>>> (*arr.1) = .DEFERRED_INIT (D.1952, 2, 1);
>>>> 
>>>> However, there is another new issue:
>>>> 
>>>> For the following testing case:
>>>> 
>>>> ======
>>>> [opc@qinzhao-ol8u3-x86 gcc]$ cat t.c
>>>> int bar;
>>>> 
>>>> extern void decode_reloc(int *);
>>>> 
>>>> void testfunc()
>>>> {
>>>> int alt_reloc;
>>>> 
>>>> decode_reloc(&alt_reloc);
>>>> 
>>>> if (alt_reloc) /* { dg-warning "may be used uninitialized" } */
>>>>  bar = 42; 
>>>> }
>>>> =====
>>>> 
>>>> In the above, the auto var “alt_reloc” is address taken, then the gimple dump for it when compiled with -ftrivial-auto-var-init=zero is:
>>>> 
>>>> void testfunc ()
>>>> {
>>>> int alt_reloc;
>>>> 
>>>> try
>>>>  {
>>>>    _1 = .DEFERRED_INIT (4, 2, 0);
>>>>    alt_reloc = _1;
>>>>    decode_reloc (&alt_reloc);
>>>>    alt_reloc.0_2 = alt_reloc;
>>>>    if (alt_reloc.0_2 != 0) goto <D.1949>; else goto <D.1950>;
>>>>    <D.1949>:
>>>>    bar = 42;
>>>>    <D.1950>:
>>>>  }
>>>> finally
>>>>  {
>>>>    alt_reloc = {CLOBBER};
>>>>  }
>>>> }
>>>> 
>>>> I.e, instead of the expected IR:
>>>> 
>>>> alt_reloc = .DEFERRED_INIT (4, 2, 0);
>>>> 
>>>> We got the following:
>>>> 
>>>> _1 = .DEFERRED_INIT (4, 2, 0);
>>>>    alt_reloc = _1;
>>>> 
>>>> I guess the temp “_1” is created because “alt_reloc” is address taken. 
>>> 
>>> Yes and no. The reason is that alt_reloc is memory (because it is address taken) and that GIMPLE says that register typed stores need to use a is_gimple_val RHS which the call is not.
>> 
>> Okay.
>>> 
>>>> My questions:
>>>> 
>>>> Shall we accept such IR for .DEFERRED_INIT purpose when the auto var is address taken? 
>>> 
>>> I think so. Note it doesn't necessarily need address taking but any other reason that prevents SSA rewriting the variable suffices. 
>> 
>> You mean, in addition to “address taken”, there are other situations that will introduce such IR:
>> 
>> temp = .DEFERRED_INIT();
>> auto_var = temp;
>> 
>> So, such IR is unavoidable and we have to handle it?
> 
> Yes. 
> 
>> If we have to handle it,  what’ the best way to do it?
>> 
>> The solution in my mind is:
>> 1. During uninitialized analysis phase, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then decide that “auto_var” is uninitialized.
> 
> Yes. Basically if there's an artificial variable auto initialized you have to look at its uses. 
> 
>> 2. During RTL expansion, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then delete “temp”, and then expand .DEFERRED_INIT to auto_var.
> 
> That shouldn't be necessary. You'd initialize a temporary register which is then copied to the real variable. That's good enough and should be optimized by the RTL pipeline. 
> 
>> Let me know your comments and suggestions on this.
>> 
>> 
>>> 
>>> The only other option is to force. DEFERED_INIT making the LHS address taken which I think could be achieved by passing it the address as argument instead of having a LHS. But let's not go down this route - it will have quite bad behavior on alias analysis and optimization. 
>> 
>> Okay.
>> 
>> Qing
>>> 
>>>> If so, “uninitialized analysis” phase need to be further adjusted to specially handle such IR. 
>>>> 
>>>> If not, what should we do when the auto var is address taken?
>>>> 
>>>> Thanks a lot.
>>>> 
>>>> Qing
>>>> 
>>>> 
>>>>> On Aug 11, 2021, at 8:58 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>> 
>>>>> On Wed, 11 Aug 2021, Qing Zhao wrote:
>>>>> 
>>>>>> 
>>>>>> 
>>>>>>> On Aug 11, 2021, at 8:37 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>> 
>>>>>>> On Wed, 11 Aug 2021, Qing Zhao wrote:
>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>>> On Aug 11, 2021, at 2:02 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>>>> 
>>>>>>>>> On Tue, 10 Aug 2021, Qing Zhao wrote:
>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>>>> On Aug 10, 2021, at 3:16 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>>>>>>>>>> 
>>>>>>>>>>> Hi, Richard,
>>>>>>>>>>> 
>>>>>>>>>>>> On Aug 10, 2021, at 10:22 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> Especially in the VLA case but likely also in general (though unlikely
>>>>>>>>>>>>>> since usually the receiver of initializations are simple enough).  I'd
>>>>>>>>>>>>>> expect the VLA case end up as
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> *ptr_to_decl = .DEFERRED_INIT (...);
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.
>>>>>>>>>>>>> 
>>>>>>>>>>>>> So, for the following small testing case:
>>>>>>>>>>>>> 
>>>>>>>>>>>>> ====
>>>>>>>>>>>>> extern void bar (int);
>>>>>>>>>>>>> 
>>>>>>>>>>>>> void foo(int n)
>>>>>>>>>>>>> {
>>>>>>>>>>>>> int arr[n];
>>>>>>>>>>>>> bar (arr[2]);
>>>>>>>>>>>>> return;
>>>>>>>>>>>>> }
>>>>>>>>>>>>> =====
>>>>>>>>>>>>> 
>>>>>>>>>>>>> If I compile it with -ftrivial-auto-var-init=zero -fdump-tree-gimple -S -o auto-init-11.s -fdump-rtl-expand, the *.gimple dump is:
>>>>>>>>>>>>> 
>>>>>>>>>>>>> =====
>>>>>>>>>>>>> void foo (int n)
>>>>>>>>>>>>> {
>>>>>>>>>>>>> int n.0;
>>>>>>>>>>>>> sizetype D.1950;
>>>>>>>>>>>>> bitsizetype D.1951;
>>>>>>>>>>>>> sizetype D.1952;
>>>>>>>>>>>>> bitsizetype D.1953;
>>>>>>>>>>>>> sizetype D.1954;
>>>>>>>>>>>>> int[0:D.1950] * arr.1;
>>>>>>>>>>>>> void * saved_stack.2;
>>>>>>>>>>>>> int arr[0:D.1950] [value-expr: *arr.1];
>>>>>>>>>>>>> 
>>>>>>>>>>>>> saved_stack.2 = __builtin_stack_save ();
>>>>>>>>>>>>> try
>>>>>>>>>>>>> {
>>>>>>>>>>>>> n.0 = n;
>>>>>>>>>>>>> _1 = (long int) n.0;
>>>>>>>>>>>>> _2 = _1 + -1;
>>>>>>>>>>>>> _3 = (sizetype) _2;
>>>>>>>>>>>>> D.1950 = _3;
>>>>>>>>>>>>> _4 = (sizetype) n.0;
>>>>>>>>>>>>> _5 = (bitsizetype) _4;
>>>>>>>>>>>>> _6 = _5 * 32;
>>>>>>>>>>>>> D.1951 = _6;
>>>>>>>>>>>>> _7 = (sizetype) n.0;
>>>>>>>>>>>>> _8 = _7 * 4;
>>>>>>>>>>>>> D.1952 = _8;
>>>>>>>>>>>>> _9 = (sizetype) n.0;
>>>>>>>>>>>>> _10 = (bitsizetype) _9;
>>>>>>>>>>>>> _11 = _10 * 32;
>>>>>>>>>>>>> D.1953 = _11;
>>>>>>>>>>>>> _12 = (sizetype) n.0;
>>>>>>>>>>>>> _13 = _12 * 4;
>>>>>>>>>>>>> D.1954 = _13;
>>>>>>>>>>>>> arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>>>>>>>>>> arr = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>>>>>>> _14 = (*arr.1)[2];
>>>>>>>>>>>>> bar (_14);
>>>>>>>>>>>>> return;
>>>>>>>>>>>>> }
>>>>>>>>>>>>> finally
>>>>>>>>>>>>> {
>>>>>>>>>>>>> __builtin_stack_restore (saved_stack.2);
>>>>>>>>>>>>> }
>>>>>>>>>>>>> }
>>>>>>>>>>>>> 
>>>>>>>>>>>>> ====
>>>>>>>>>>>>> 
>>>>>>>>>>>>> You think that the above .DEFEERED_INIT is not correct?
>>>>>>>>>>>>> It should be:
>>>>>>>>>>>>> 
>>>>>>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952. 2, 1);
>>>>>>>>>>>>> 
>>>>>>>>>>>>> ?
>>>>>>>>>>>> 
>>>>>>>>>>>> Yes.
>>>>>>>>>>>> 
>>>>>>>>>>> 
>>>>>>>>>>> I updated gimplify.c for VLA and now it emits the call to .DEFERRED_INIT as:
>>>>>>>>>>> 
>>>>>>>>>>> arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>>>>> 
>>>>>>>>>>> However, this call triggered the assertion failure in verify_gimple_call of tree-cfg.c because the LHS is not a valid LHS. 
>>>>>>>>>>> Then I modify tree-cfg.c as:
>>>>>>>>>>> 
>>>>>>>>>>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
>>>>>>>>>>> index 330eb7dd89bf..180d4f1f9e32 100644
>>>>>>>>>>> --- a/gcc/tree-cfg.c
>>>>>>>>>>> +++ b/gcc/tree-cfg.c
>>>>>>>>>>> @@ -3375,7 +3375,11 @@ verify_gimple_call (gcall *stmt)
>>>>>>>>>>> }
>>>>>>>>>>> 
>>>>>>>>>>> tree lhs = gimple_call_lhs (stmt);
>>>>>>>>>>> +  /* For .DEFERRED_INIT call, the LHS might be an indirection of
>>>>>>>>>>> +     a pointer for the VLA variable, which is not a valid LHS of
>>>>>>>>>>> +     a gimple call, we ignore the asssertion on this.  */ 
>>>>>>>>>>> if (lhs
>>>>>>>>>>> +      && (!gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
>>>>>>>>>>>  && (!is_gimple_reg (lhs)
>>>>>>>>>>>     && (!is_gimple_lvalue (lhs)
>>>>>>>>>>>         || verify_types_in_gimple_reference
>>>>>>>>>>> 
>>>>>>>>>>> The assertion failure in tree-cfg.c got resolved, but I got another assertion failure in operands_scanner::get_expr_operands (tree *expr_p, int flags), line 945:
>>>>>>>>>>> 
>>>>>>>>>>> 939   /* If we get here, something has gone wrong.  */
>>>>>>>>>>> 940   if (flag_checking)
>>>>>>>>>>> 941     {
>>>>>>>>>>> 942       fprintf (stderr, "unhandled expression in get_expr_operands():\n");
>>>>>>>>>>> 943       debug_tree (expr);
>>>>>>>>>>> 944       fputs ("\n", stderr);
>>>>>>>>>>> 945       gcc_unreachable ();
>>>>>>>>>>> 946     }
>>>>>>>>>>> 
>>>>>>>>>>> Looks like that  the gimple statement:
>>>>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>>>>> 
>>>>>>>>>>> Is not valid.  i.e, the LHS should not be an indirection to a pointer. 
>>>>>>>>>>> 
>>>>>>>>>>> How to resolve this issue?
>>>>>>>>> 
>>>>>>>>> It sounds like the LHS is an INDIRECT_REF maybe?  That means it's
>>>>>>>>> still not properly gimplified because it should end up as a MEM_REF
>>>>>>>>> instead.
>>>>>>>>> 
>>>>>>>>> But I'm just guessing here ... if you are in a debugger then you can
>>>>>>>>> invoke debug_tree (lhs) in the inferior to see what it exactly is
>>>>>>>>> at the point of the failure.
>>>>>>>> 
>>>>>>>> Yes, it’s an INDIRECT_REF at the point of the failure even though I added a 
>>>>>>>> 
>>>>>>>> gimplify_var_or_parm_decl  (lhs) 
>>>>>>> 
>>>>>>> I think the easiest is to build the .DEFERRED_INIT as GENERIC
>>>>>>> and use gimplify_assign () to gimplify and add the result
>>>>>>> to the sequence.  Thus, build a GENERIC CALL_EXPR and then
>>>>>>> gimplify_assign (lhs, call_expr, seq);
>>>>>> 
>>>>>> Which utility routine is used to build an Internal generic call?
>>>>>> Currently, I used “gimple_build_call_internal” to build this internal gimple call.
>>>>>> 
>>>>>> For the generic call, shall I use “build_call_expr_loc” ? 
>>>>> 
>>>>> For example look at build_asan_poison_call_expr which does such thing
>>>>> for ASAN poison internal function call insertion at gimplification time.
>>>>> 
>>>>> Richard.
>>>>> 
>>>>>> Qing
>>>>>> 
>>>>>>> 
>>>>>>> Richard.
>>>>>>> 
>>>>>>>> Qing
>>>>>>>> 
>>>>>>>>> 
>>>>>>>>>> I came up with the following solution:
>>>>>>>>>> 
>>>>>>>>>> Define the IFN_DEFERRED_INIT function as:
>>>>>>>>>> 
>>>>>>>>>> LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA);
>>>>>>>>>> 
>>>>>>>>>> if IS_VLA is false, the LHS is the DECL itself,
>>>>>>>>>> if IS_VLA is true, the LHS is the pointer to this DECL that created by
>>>>>>>>>> gimplify_vla_decl.
>>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>>> The benefit of this solution are:
>>>>>>>>>> 
>>>>>>>>>> 1. Resolved the invalid IR issue;
>>>>>>>>>> 2. The call stmt carries the address of the VLA natually;
>>>>>>>>>> 
>>>>>>>>>> The issue with this solution is:
>>>>>>>>>> 
>>>>>>>>>> For VLA and non-VLA, the LHS will be different, 
>>>>>>>>>> 
>>>>>>>>>> Do you see any other potential issues with this solution?
>>>>>>>>>> 
>>>>>>>>>> thanks.
>>>>>>>>>> 
>>>>>>>>>> Qing
>>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>> 
>>>>>>>>> -- 
>>>>>>>>> Richard Biener <rguenther@suse.de>
>>>>>>>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>>>>>>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>>>>>>>> 
>>>>>>>> 
>>>>>>> 
>>>>>>> -- 
>>>>>>> Richard Biener <rguenther@suse.de>
>>>>>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>>>>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>>>>>> 
>>>>>> 
>>>>> 
>>>>> -- 
>>>>> 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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-11 20:30                                     ` Qing Zhao
@ 2021-08-11 22:03                                       ` Qing Zhao
  2021-08-16  7:12                                         ` Richard Biener
  2021-08-16  7:11                                       ` Richard Biener
  1 sibling, 1 reply; 60+ messages in thread
From: Qing Zhao @ 2021-08-11 22:03 UTC (permalink / raw)
  To: Richard Biener
  Cc: Jakub Jelinek, Richard Sandiford, Nick Alcock via Gcc-patches, Kees Cook

Hi, 

I finally decided to take another approach to resolve this issue, it resolved all the potential issues with the “address taken” auto variable.

The basic idea is to avoid generating the temporary variable in the beginning. 
As you mentioned, "The reason is that alt_reloc is memory (because it is address taken) and that GIMPLE says that register typed stores 
need to use a is_gimple_val RHS which the call is not.”
In order to avoid generating the temporary variable for “address taken” auto variable, I updated the utility routine “is_gimple_val” as following:

diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c
index a2563a45c37d..d5ef1aef8cea 100644
--- a/gcc/gimple-expr.c
+++ b/gcc/gimple-expr.c
@@ -787,8 +787,20 @@ is_gimple_reg (tree t)
   return !DECL_NOT_GIMPLE_REG_P (t);
 }
 
+/* Return true if T is a call to .DEFERRED_INIT internal function.  */ 
+static bool
+is_deferred_init_call (tree t)
+{
+  if (TREE_CODE (t) == CALL_EXPR
+      &&  CALL_EXPR_IFN (t) == IFN_DEFERRED_INIT)
+    return true;
+  return false;
+}
+
 
-/* Return true if T is a GIMPLE rvalue, i.e. an identifier or a constant.  */
+/* Return true if T is a GIMPLE rvalue, i.e. an identifier or a constant,
+   or a call to .DEFERRED_INIT internal function because the call to
+   .DEFERRED_INIT will eventually be expanded as a constant.  */
 
 bool
 is_gimple_val (tree t)
@@ -799,7 +811,8 @@ is_gimple_val (tree t)
       && !is_gimple_reg (t))
     return false;
 
-  return (is_gimple_variable (t) || is_gimple_min_invariant (t));
+  return (is_gimple_variable (t) || is_gimple_min_invariant (t)
+         || is_deferred_init_call (t));
 }
 
With this change, the temporary variable will not be created for “address taken” auto variable, and uninitialized analysis does not need any change. 
Everything works well.

And I believe that treating “call to .DEFERRED_INIT” as “is_gimple_val” is reasonable since this call actually is a constant. 

Let me know if you have any objection on this solution.

thanks.

Qing

> On Aug 11, 2021, at 3:30 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> 
> Hi, 
> 
> I met another issue for “address taken” auto variable, see below for details:
> 
> **** the testing case: (gcc/testsuite/gcc.dg/uninit-16.c)
> 
> 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;
> }
> 
> ****When compiled with -ftrivial-auto-var-init=zero -O2 -Wuninitialized -fdump-tree-all:
> 
> .*************gimple dump:
> 
> void testfunc ()
> { 
>  int alt_reloc;
> 
>  try
>    {
>      _1 = .DEFERRED_INIT (4, 2, 0);
>      alt_reloc = _1;
>      foo.0_2 = foo;
>      decode_reloc (foo.0_2, &alt_reloc);
>      alt_reloc.1_3 = alt_reloc;
>      if (alt_reloc.1_3 != 0) goto <D.1952>; else goto <D.1953>;
>      <D.1952>:
>      bar = 42;
>      <D.1953>:
>    }
>  finally
>    {
>      alt_reloc = {CLOBBER};
>    }
> }
> 
> **************fre1 dump:
> 
> void testfunc ()
> {
>  int alt_reloc;
>  int _1;
>  int foo.0_2;
> 
>  <bb 2> :
>  _1 = .DEFERRED_INIT (4, 2, 0);
>  foo.0_2 = foo;
>  if (foo.0_2 > 19)
>    goto <bb 3>; [50.00%]
>  else
>    goto <bb 4>; [50.00%]
> 
>  <bb 3> :
>  goto <bb 7>; [100.00%]
> 
>  <bb 4> :
>  if (foo.0_2 > 9)
>    goto <bb 5>; [50.00%]
>  else
>    goto <bb 6>; [50.00%]
> 
>  <bb 5> :
>  goto <bb 8>; [100.00%]
> 
>  <bb 6> :
>  if (_1 != 0)
>    goto <bb 7>; [INV]
>  else
>    goto <bb 8>; [INV]
> 
>  <bb 7> :
>  bar = 42;
> 
>  <bb 8> :
>  return;
> 
> }
> 
> From the above IR file after “FRE”, we can see that the major issue with this IR is:
> 
> The address taken auto variable “alt_reloc” has been completely replaced by the temporary variable “_1” in all
> the uses of the original “alt_reloc”. 
> 
> The major problem with such IR is,  during uninitialized analysis phase, the original use of “alt_reloc” disappeared completely.
> So, the warning cannot be reported.
> 
> 
> My questions:
> 
> 1. Is it possible to get the original “alt_reloc” through the temporary variable “_1” with some available information recorded in the IR?
> 2. If not, then we have to record the relationship between “alt_reloc” and “_1” when the original “alt_reloc” is replaced by “_1” and get such relationship during
>    Uninitialized analysis phase.  Is this doable?
> 3. Looks like that for “address taken” auto variable, if we have to introduce a new temporary variable and split the call to .DEFERRED_INIT into two:
> 
>      temp = .DEFERRED_INIT (4, 2, 0);
>      alt_reloc = temp;
> 
>   More issues might possible.
> 
> Any comments and suggestions on this issue?
> 
> Qing
> 
> j
>> On Aug 11, 2021, at 11:55 AM, Richard Biener <rguenther@suse.de> wrote:
>> 
>> On August 11, 2021 6:22:00 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>>> 
>>> 
>>>> On Aug 11, 2021, at 10:53 AM, Richard Biener <rguenther@suse.de> wrote:
>>>> 
>>>> On August 11, 2021 5:30:40 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>>>>> I modified the routine “gimple_add_init_for_auto_var” as the following:
>>>>> ====
>>>>> /* Generate initialization to automatic variable DECL based on INIT_TYPE.
>>>>> Build a call to internal const function DEFERRED_INIT:
>>>>> 1st argument: SIZE of the DECL;
>>>>> 2nd argument: INIT_TYPE;
>>>>> 3rd argument: IS_VLA, 0 NO, 1 YES;
>>>>> 
>>>>> as DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA).  */
>>>>> static void
>>>>> gimple_add_init_for_auto_var (tree decl,
>>>>>                           enum auto_init_type init_type,
>>>>>                           bool is_vla,
>>>>>                           gimple_seq *seq_p)
>>>>> {
>>>>> gcc_assert (VAR_P (decl) && !DECL_EXTERNAL (decl) && !TREE_STATIC (decl));
>>>>> gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>>>>> tree decl_size = TYPE_SIZE_UNIT (TREE_TYPE (decl));
>>>>> 
>>>>> tree init_type_node
>>>>> = build_int_cst (integer_type_node, (int) init_type);
>>>>> tree is_vla_node
>>>>> = build_int_cst (integer_type_node, (int) is_vla);
>>>>> 
>>>>> tree call = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
>>>>>                                         TREE_TYPE (decl), 3,
>>>>>                                         decl_size, init_type_node,
>>>>>                                         is_vla_node);
>>>>> 
>>>>> /* If this DECL is a VLA, a temporary address variable for it has been
>>>>>  created, the replacement for DECL is recorded in DECL_VALUE_EXPR (decl),
>>>>>  we should use it as the LHS of the call.  */
>>>>> 
>>>>> tree lhs_call
>>>>> = is_vla ? DECL_VALUE_EXPR (decl) : decl;
>>>>> gimplify_assign (lhs_call, call, seq_p);
>>>>> }
>>>>> 
>>>>> With this change, the current issue is resolved, the gimple dump now is:
>>>>> 
>>>>> (*arr.1) = .DEFERRED_INIT (D.1952, 2, 1);
>>>>> 
>>>>> However, there is another new issue:
>>>>> 
>>>>> For the following testing case:
>>>>> 
>>>>> ======
>>>>> [opc@qinzhao-ol8u3-x86 gcc]$ cat t.c
>>>>> int bar;
>>>>> 
>>>>> extern void decode_reloc(int *);
>>>>> 
>>>>> void testfunc()
>>>>> {
>>>>> int alt_reloc;
>>>>> 
>>>>> decode_reloc(&alt_reloc);
>>>>> 
>>>>> if (alt_reloc) /* { dg-warning "may be used uninitialized" } */
>>>>> bar = 42; 
>>>>> }
>>>>> =====
>>>>> 
>>>>> In the above, the auto var “alt_reloc” is address taken, then the gimple dump for it when compiled with -ftrivial-auto-var-init=zero is:
>>>>> 
>>>>> void testfunc ()
>>>>> {
>>>>> int alt_reloc;
>>>>> 
>>>>> try
>>>>> {
>>>>>   _1 = .DEFERRED_INIT (4, 2, 0);
>>>>>   alt_reloc = _1;
>>>>>   decode_reloc (&alt_reloc);
>>>>>   alt_reloc.0_2 = alt_reloc;
>>>>>   if (alt_reloc.0_2 != 0) goto <D.1949>; else goto <D.1950>;
>>>>>   <D.1949>:
>>>>>   bar = 42;
>>>>>   <D.1950>:
>>>>> }
>>>>> finally
>>>>> {
>>>>>   alt_reloc = {CLOBBER};
>>>>> }
>>>>> }
>>>>> 
>>>>> I.e, instead of the expected IR:
>>>>> 
>>>>> alt_reloc = .DEFERRED_INIT (4, 2, 0);
>>>>> 
>>>>> We got the following:
>>>>> 
>>>>> _1 = .DEFERRED_INIT (4, 2, 0);
>>>>>   alt_reloc = _1;
>>>>> 
>>>>> I guess the temp “_1” is created because “alt_reloc” is address taken. 
>>>> 
>>>> Yes and no. The reason is that alt_reloc is memory (because it is address taken) and that GIMPLE says that register typed stores need to use a is_gimple_val RHS which the call is not.
>>> 
>>> Okay.
>>>> 
>>>>> My questions:
>>>>> 
>>>>> Shall we accept such IR for .DEFERRED_INIT purpose when the auto var is address taken? 
>>>> 
>>>> I think so. Note it doesn't necessarily need address taking but any other reason that prevents SSA rewriting the variable suffices. 
>>> 
>>> You mean, in addition to “address taken”, there are other situations that will introduce such IR:
>>> 
>>> temp = .DEFERRED_INIT();
>>> auto_var = temp;
>>> 
>>> So, such IR is unavoidable and we have to handle it?
>> 
>> Yes. 
>> 
>>> If we have to handle it,  what’ the best way to do it?
>>> 
>>> The solution in my mind is:
>>> 1. During uninitialized analysis phase, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then decide that “auto_var” is uninitialized.
>> 
>> Yes. Basically if there's an artificial variable auto initialized you have to look at its uses. 
>> 
>>> 2. During RTL expansion, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then delete “temp”, and then expand .DEFERRED_INIT to auto_var.
>> 
>> That shouldn't be necessary. You'd initialize a temporary register which is then copied to the real variable. That's good enough and should be optimized by the RTL pipeline. 
>> 
>>> Let me know your comments and suggestions on this.
>>> 
>>> 
>>>> 
>>>> The only other option is to force. DEFERED_INIT making the LHS address taken which I think could be achieved by passing it the address as argument instead of having a LHS. But let's not go down this route - it will have quite bad behavior on alias analysis and optimization. 
>>> 
>>> Okay.
>>> 
>>> Qing
>>>> 
>>>>> If so, “uninitialized analysis” phase need to be further adjusted to specially handle such IR. 
>>>>> 
>>>>> If not, what should we do when the auto var is address taken?


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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-09 14:09 ` Richard Biener
  2021-08-09 16:38   ` Qing Zhao
@ 2021-08-12 19:24   ` Qing Zhao
  2021-08-12 22:45     ` Qing Zhao
  2021-08-16  7:40     ` Richard Biener
  1 sibling, 2 replies; 60+ messages in thread
From: Qing Zhao @ 2021-08-12 19:24 UTC (permalink / raw)
  To: Richard Biener
  Cc: Martin Jambor, Jakub Jelinek, Kees Cook,
	Nick Alcock via Gcc-patches, Richard Biener

Hi, Richard,

For RTL expansion of call to .DEFERRED_INIT, I changed my code per your suggestions like following:

======================
#define INIT_PATTERN_VALUE  0xFE
static void
expand_DEFERRED_INIT (internal_fn, gcall *stmt)
{
  tree lhs = gimple_call_lhs (stmt);
  tree var_size = gimple_call_arg (stmt, 0);
  enum auto_init_type init_type
    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
  bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));

  tree var_type = TREE_TYPE (lhs);
  gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);

  if (is_vla || (!can_native_interpret_type_p (var_type)))
    {
    /* If this is a VLA or the type of the variable cannot be natively
       interpreted, expand to a memset to initialize it.  */
      if (TREE_CODE (lhs) == SSA_NAME)
        lhs = SSA_NAME_VAR (lhs);
      tree var_addr = NULL_TREE;
      if (is_vla)
        var_addr = TREE_OPERAND (lhs, 0);
      else
        {
         TREE_ADDRESSABLE (lhs) = 1;
         var_addr = build_fold_addr_expr (lhs);
        }
      tree value = (init_type == AUTO_INIT_PATTERN) ?
                    build_int_cst (unsigned_char_type_node,
                                   INIT_PATTERN_VALUE) :
                    build_zero_cst (unsigned_char_type_node);
      tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
                                     3, var_addr, value, var_size);
      /* Expand this memset call.  */
      expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
    }
  else
    {
    /* If this is not a VLA and the type of the variable can be natively 
       interpreted, expand to assignment to generate better code.  */
      tree pattern = NULL_TREE;
      unsigned HOST_WIDE_INT total_bytes
        = tree_to_uhwi (TYPE_SIZE_UNIT (var_type));

      if (init_type == AUTO_INIT_PATTERN)
        {
          unsigned char *buf = (unsigned char *) xmalloc (total_bytes);
          memset (buf, INIT_PATTERN_VALUE, total_bytes);
          pattern = native_interpret_expr (var_type, buf, total_bytes);
          gcc_assert (pattern);
        }

      tree init = (init_type == AUTO_INIT_PATTERN) ?
                   pattern :
                   build_zero_cst (var_type);
      expand_assignment (lhs, init, false);
    }
}
===========================

Now, I used “can_native_interpret_type_p (var_type)” instead of “use_register_for_decl (lhs)” to decide 
whether to use “memset” or use “assign” to expand this function.

However, this exposed an bug that is very hard to be addressed:

*******For the testing case: test suite/gcc.dg/uninit-I.c:

/* { dg-do compile } */
/* { dg-options "-O2 -Wuninitialized" } */

int sys_msgctl (void)
{
  struct { int mode; } setbuf;
  return setbuf.mode;  /* { dg-warning "'setbuf\.mode' is used" } */
==

******the above auto var “setbuf” has “struct” type, which “can_native_interpret_type_p(var_type)” is false, therefore, 
Expanding this .DEFERRED_INIT call went down the “memset” expansion route. 

However, this structure type can be fitted into a register, therefore cannot be taken address anymore at this stage, even though I tried:

         TREE_ADDRESSABLE (lhs) = 1;
         var_addr = build_fold_addr_expr (lhs);

To create an address variable for it, the expansion still failed at expr.c: line 8412:
during RTL pass: expand
/home/opc/Work/GCC/latest-gcc/gcc/testsuite/gcc.dg/auto-init-uninit-I.c:6:24: internal compiler error: in expand_expr_addr_expr_1, at expr.c:8412
0xd04104 expand_expr_addr_expr_1
	../../latest-gcc/gcc/expr.c:8412
0xd04a95 expand_expr_addr_expr
	../../latest-gcc/gcc/expr.c:8525
0xd13592 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
	../../latest-gcc/gcc/expr.c:11741
0xd05142 expand_expr_real(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
	../../latest-gcc/gcc/expr.c:8713
0xaed1d3 expand_expr
	../../latest-gcc/gcc/expr.h:301
0xaf0d89 get_memory_rtx
	../../latest-gcc/gcc/builtins.c:1370
0xafb4fb expand_builtin_memset_args
	../../latest-gcc/gcc/builtins.c:4102
0xafacde expand_builtin_memset(tree_node*, rtx_def*, machine_mode)
	../../latest-gcc/gcc/builtins.c:3886
0xe97fb3 expand_DEFERRED_INIT

******That’s the major reason why I chose “use_register_for_decl(lhs)” to decide “memset” expansion or “assign” expansion, “memset” expansion
needs to take address of the variable, if the variable has been decided to fit into a register, then its address cannot taken anymore at this stage.

******using “can_native_interpret_type_p” did make the “pattern” generation part much  cleaner and simpler, however, looks like it didn’t work correctly.

Based on this, I’d like to keep my previous implementation by using “use_register_for_decl” to decide whether to take “memset” expansion or “assign” expansion.
Therefore, I might still need to keep the “UGLY”  implementation of generatting “pattern” constant for different types?

Let me know your opinion on this.

Thanks a lot for the help.

Qing


> On Aug 9, 2021, at 9:09 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Tue, 27 Jul 2021, Qing Zhao wrote:
> 
> +        created during gimplification phase.  Refer to gimplify_vla_decl
> +        for details.  */
> +      tree var_decl = (TREE_CODE (var) == SSA_NAME) ?
> +                      SSA_NAME_VAR (var) : var;
> +      gcc_assert (DECL_HAS_VALUE_EXPR_P (var_decl));
> +      gcc_assert (TREE_CODE (DECL_VALUE_EXPR (var_decl)) == 
> INDIRECT_REF);
> +      /* Get the address of this vla variable.  */
> +      vlaaddr = TREE_OPERAND (DECL_VALUE_EXPR (var_decl), 0);
> 
> err - isn't the address of the decl represented by the LHS 
> regardless whether this is a VLA or not?  Looking at DECL_VALUE_EXPR
> looks quite fragile since that's not sth data dependence honors.
> It looks you only partly gimplify the build init here?  All
> DECL_VALUE_EXPRs should have been resolved.
> 
> +  if (is_vla || (!use_register_for_decl (var)))
> ...
> +  else
> +    {
> +    /* If this variable is in a register, use expand_assignment might
> +       generate better code.  */
> 
> you compute the patter initializer even when not needing it,
> that's wasteful.  It's also quite ugly, IMHO you should
> use can_native_interpret_type_p (var_type) and native_interpret
> a char [] array initialized to the pattern and if
> !can_native_interpret_type_p () go the memset route.

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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-12 19:24   ` Qing Zhao
@ 2021-08-12 22:45     ` Qing Zhao
  2021-08-16  7:40     ` Richard Biener
  1 sibling, 0 replies; 60+ messages in thread
From: Qing Zhao @ 2021-08-12 22:45 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook

Hi,
Although I kept my previous "use_register_for_decl(lhs)” to decide “memset” expansion or “assign” expansion when expanding .DEFERRED_INIT 

When generating “pattern” for “assign” expansion, I found that “can_native_interpret_type_p(var_type)”  combined with “native_interpret_expr” make
the implementation cleaner and simpler as following:

      if (init_type == AUTO_INIT_PATTERN)
        {
          if (can_native_interpret_type_p (var_type))
            {
              unsigned char *buf = (unsigned char *) xmalloc (total_bytes);
              memset (buf, INIT_PATTERN_VALUE, total_bytes);
              pattern = native_interpret_expr (var_type, buf, total_bytes);
              gcc_assert (pattern);
            }
          else
            {
              tree index_type = build_index_type (size_int (total_bytes - 1));
              tree array_type = build_array_type (unsigned_char_type_node,
                                                  index_type);
              tree element = build_int_cst (unsigned_char_type_node,
                                            INIT_PATTERN_VALUE);
              vec<constructor_elt, va_gc> *elts = NULL;
              for (unsigned int i = 0; i < total_bytes; i++)
                CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, element);
              pattern = build_constructor (array_type, elts);
              pattern = build1 (VIEW_CONVERT_EXPR, var_type, pattern);
            }
        }

Thanks.

Qing

On Aug 12, 2021, at 2:24 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> 
> 
> Hi, Richard,
> 
> For RTL expansion of call to .DEFERRED_INIT, I changed my code per your suggestions like following:
> 
> ======================
> #define INIT_PATTERN_VALUE  0xFE
> static void
> expand_DEFERRED_INIT (internal_fn, gcall *stmt)
> {
>  tree lhs = gimple_call_lhs (stmt);
>  tree var_size = gimple_call_arg (stmt, 0);
>  enum auto_init_type init_type
>    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
>  bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
> 
>  tree var_type = TREE_TYPE (lhs);
>  gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
> 
>  if (is_vla || (!can_native_interpret_type_p (var_type)))
>    {
>    /* If this is a VLA or the type of the variable cannot be natively
>       interpreted, expand to a memset to initialize it.  */
>      if (TREE_CODE (lhs) == SSA_NAME)
>        lhs = SSA_NAME_VAR (lhs);
>      tree var_addr = NULL_TREE;
>      if (is_vla)
>        var_addr = TREE_OPERAND (lhs, 0);
>      else
>        {
>         TREE_ADDRESSABLE (lhs) = 1;
>         var_addr = build_fold_addr_expr (lhs);
>        }
>      tree value = (init_type == AUTO_INIT_PATTERN) ?
>                    build_int_cst (unsigned_char_type_node,
>                                   INIT_PATTERN_VALUE) :
>                    build_zero_cst (unsigned_char_type_node);
>      tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
>                                     3, var_addr, value, var_size);
>      /* Expand this memset call.  */
>      expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
>    }
>  else
>    {
>    /* If this is not a VLA and the type of the variable can be natively 
>       interpreted, expand to assignment to generate better code.  */
>      tree pattern = NULL_TREE;
>      unsigned HOST_WIDE_INT total_bytes
>        = tree_to_uhwi (TYPE_SIZE_UNIT (var_type));
> 
>      if (init_type == AUTO_INIT_PATTERN)
>        {
>          unsigned char *buf = (unsigned char *) xmalloc (total_bytes);
>          memset (buf, INIT_PATTERN_VALUE, total_bytes);
>          pattern = native_interpret_expr (var_type, buf, total_bytes);
>          gcc_assert (pattern);
>        }
> 
>      tree init = (init_type == AUTO_INIT_PATTERN) ?
>                   pattern :
>                   build_zero_cst (var_type);
>      expand_assignment (lhs, init, false);
>    }
> }
> ===========================
> 
> Now, I used “can_native_interpret_type_p (var_type)” instead of “use_register_for_decl (lhs)” to decide 
> whether to use “memset” or use “assign” to expand this function.
> 
> However, this exposed an bug that is very hard to be addressed:
> 
> *******For the testing case: test suite/gcc.dg/uninit-I.c:
> 
> /* { dg-do compile } */
> /* { dg-options "-O2 -Wuninitialized" } */
> 
> int sys_msgctl (void)
> {
>  struct { int mode; } setbuf;
>  return setbuf.mode;  /* { dg-warning "'setbuf\.mode' is used" } */
> ==
> 
> ******the above auto var “setbuf” has “struct” type, which “can_native_interpret_type_p(var_type)” is false, therefore, 
> Expanding this .DEFERRED_INIT call went down the “memset” expansion route. 
> 
> However, this structure type can be fitted into a register, therefore cannot be taken address anymore at this stage, even though I tried:
> 
>         TREE_ADDRESSABLE (lhs) = 1;
>         var_addr = build_fold_addr_expr (lhs);
> 
> To create an address variable for it, the expansion still failed at expr.c: line 8412:
> during RTL pass: expand
> /home/opc/Work/GCC/latest-gcc/gcc/testsuite/gcc.dg/auto-init-uninit-I.c:6:24: internal compiler error: in expand_expr_addr_expr_1, at expr.c:8412
> 0xd04104 expand_expr_addr_expr_1
> 	../../latest-gcc/gcc/expr.c:8412
> 0xd04a95 expand_expr_addr_expr
> 	../../latest-gcc/gcc/expr.c:8525
> 0xd13592 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
> 	../../latest-gcc/gcc/expr.c:11741
> 0xd05142 expand_expr_real(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
> 	../../latest-gcc/gcc/expr.c:8713
> 0xaed1d3 expand_expr
> 	../../latest-gcc/gcc/expr.h:301
> 0xaf0d89 get_memory_rtx
> 	../../latest-gcc/gcc/builtins.c:1370
> 0xafb4fb expand_builtin_memset_args
> 	../../latest-gcc/gcc/builtins.c:4102
> 0xafacde expand_builtin_memset(tree_node*, rtx_def*, machine_mode)
> 	../../latest-gcc/gcc/builtins.c:3886
> 0xe97fb3 expand_DEFERRED_INIT
> 
> ******That’s the major reason why I chose “use_register_for_decl(lhs)” to decide “memset” expansion or “assign” expansion, “memset” expansion
> needs to take address of the variable, if the variable has been decided to fit into a register, then its address cannot taken anymore at this stage.
> 
> ******using “can_native_interpret_type_p” did make the “pattern” generation part much  cleaner and simpler, however, looks like it didn’t work correctly.
> 
> Based on this, I’d like to keep my previous implementation by using “use_register_for_decl” to decide whether to take “memset” expansion or “assign” expansion.
> Therefore, I might still need to keep the “UGLY”  implementation of generatting “pattern” constant for different types?
> 
> Let me know your opinion on this.
> 
> Thanks a lot for the help.
> 
> Qing
> 
> 
>> On Aug 9, 2021, at 9:09 AM, Richard Biener <rguenther@suse.de> wrote:
>> 
>> On Tue, 27 Jul 2021, Qing Zhao wrote:
>> 
>> +        created during gimplification phase.  Refer to gimplify_vla_decl
>> +        for details.  */
>> +      tree var_decl = (TREE_CODE (var) == SSA_NAME) ?
>> +                      SSA_NAME_VAR (var) : var;
>> +      gcc_assert (DECL_HAS_VALUE_EXPR_P (var_decl));
>> +      gcc_assert (TREE_CODE (DECL_VALUE_EXPR (var_decl)) == 
>> INDIRECT_REF);
>> +      /* Get the address of this vla variable.  */
>> +      vlaaddr = TREE_OPERAND (DECL_VALUE_EXPR (var_decl), 0);
>> 
>> err - isn't the address of the decl represented by the LHS 
>> regardless whether this is a VLA or not?  Looking at DECL_VALUE_EXPR
>> looks quite fragile since that's not sth data dependence honors.
>> It looks you only partly gimplify the build init here?  All
>> DECL_VALUE_EXPRs should have been resolved.
>> 
>> +  if (is_vla || (!use_register_for_decl (var)))
>> ...
>> +  else
>> +    {
>> +    /* If this variable is in a register, use expand_assignment might
>> +       generate better code.  */
>> 
>> you compute the patter initializer even when not needing it,
>> that's wasteful.  It's also quite ugly, IMHO you should
>> use can_native_interpret_type_p (var_type) and native_interpret
>> a char [] array initialized to the pattern and if
>> !can_native_interpret_type_p () go the memset route.


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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-11 20:30                                     ` Qing Zhao
  2021-08-11 22:03                                       ` Qing Zhao
@ 2021-08-16  7:11                                       ` Richard Biener
  2021-08-16 16:48                                         ` Qing Zhao
  1 sibling, 1 reply; 60+ messages in thread
From: Richard Biener @ 2021-08-16  7:11 UTC (permalink / raw)
  To: Qing Zhao
  Cc: Richard Sandiford, Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook

On Wed, 11 Aug 2021, Qing Zhao wrote:

> Hi, 
> 
> I met another issue for “address taken” auto variable, see below for details:
> 
> **** the testing case: (gcc/testsuite/gcc.dg/uninit-16.c)
> 
> 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;
> }
> 
> ****When compiled with -ftrivial-auto-var-init=zero -O2 -Wuninitialized -fdump-tree-all:
> 
> .*************gimple dump:
> 
> void testfunc ()
> { 
>   int alt_reloc;
> 
>   try
>     {
>       _1 = .DEFERRED_INIT (4, 2, 0);
>       alt_reloc = _1;
>       foo.0_2 = foo;
>       decode_reloc (foo.0_2, &alt_reloc);
>       alt_reloc.1_3 = alt_reloc;
>       if (alt_reloc.1_3 != 0) goto <D.1952>; else goto <D.1953>;
>       <D.1952>:
>       bar = 42;
>       <D.1953>:
>     }
>   finally
>     {
>       alt_reloc = {CLOBBER};
>     }
> }
> 
> **************fre1 dump:
> 
> void testfunc ()
> {
>   int alt_reloc;
>   int _1;
>   int foo.0_2;
> 
>   <bb 2> :
>   _1 = .DEFERRED_INIT (4, 2, 0);
>   foo.0_2 = foo;
>   if (foo.0_2 > 19)
>     goto <bb 3>; [50.00%]
>   else
>     goto <bb 4>; [50.00%]
> 
>   <bb 3> :
>   goto <bb 7>; [100.00%]
> 
>   <bb 4> :
>   if (foo.0_2 > 9)
>     goto <bb 5>; [50.00%]
>   else
>     goto <bb 6>; [50.00%]
> 
>   <bb 5> :
>   goto <bb 8>; [100.00%]
> 
>   <bb 6> :
>   if (_1 != 0)
>     goto <bb 7>; [INV]
>   else
>     goto <bb 8>; [INV]
> 
>   <bb 7> :
>   bar = 42;
> 
>   <bb 8> :
>   return;
> 
> }
> 
> From the above IR file after “FRE”, we can see that the major issue with this IR is:
> 
> The address taken auto variable “alt_reloc” has been completely replaced by the temporary variable “_1” in all
> the uses of the original “alt_reloc”. 

Well, this can happen with regular code as well, there's no need for
.DEFERRED_INIT.  This is the usual problem with reporting uninitialized
uses late.

IMHO this shouldn't be a blocker.  The goal of zero "regressions" wrt
-Wuninitialized isn't really achievable.

> The major problem with such IR is,  during uninitialized analysis phase, the original use of “alt_reloc” disappeared completely.
> So, the warning cannot be reported.
> 
> 
> My questions:
> 
> 1. Is it possible to get the original “alt_reloc” through the temporary variable “_1” with some available information recorded in the IR?
> 2. If not, then we have to record the relationship between “alt_reloc” and “_1” when the original “alt_reloc” is replaced by “_1” and get such relationship during
>     Uninitialized analysis phase.  Is this doable?

Well, you could add a fake argument to .DEFERRED_INIT for the purpose of
diagnostics.  The difficulty is to avoid tracking it as actual use so
you could for example pass a string with the declarations name though
this wouldn't give the association with the actual decl.

> 3. Looks like that for “address taken” auto variable, if we have to introduce a new temporary variable and split the call to .DEFERRED_INIT into two:
> 
>       temp = .DEFERRED_INIT (4, 2, 0);
>       alt_reloc = temp;
> 
>    More issues might possible.
> 
> Any comments and suggestions on this issue?

I don't see any good possibilities that would not make optimizing code
as good as w/o .DEFERRED_INIT more difficult.  My stake here is always
that GCC is an optimizing compiler, not a static analysis engine and
thus I side with "broken" diagnostics and better optimization.

Richard.

> Qing
> 
> j
> > On Aug 11, 2021, at 11:55 AM, Richard Biener <rguenther@suse.de> wrote:
> > 
> > On August 11, 2021 6:22:00 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
> >> 
> >> 
> >>> On Aug 11, 2021, at 10:53 AM, Richard Biener <rguenther@suse.de> wrote:
> >>> 
> >>> On August 11, 2021 5:30:40 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
> >>>> I modified the routine “gimple_add_init_for_auto_var” as the following:
> >>>> ====
> >>>> /* Generate initialization to automatic variable DECL based on INIT_TYPE.
> >>>> Build a call to internal const function DEFERRED_INIT:
> >>>> 1st argument: SIZE of the DECL;
> >>>> 2nd argument: INIT_TYPE;
> >>>> 3rd argument: IS_VLA, 0 NO, 1 YES;
> >>>> 
> >>>> as DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA).  */
> >>>> static void
> >>>> gimple_add_init_for_auto_var (tree decl,
> >>>>                            enum auto_init_type init_type,
> >>>>                            bool is_vla,
> >>>>                            gimple_seq *seq_p)
> >>>> {
> >>>> gcc_assert (VAR_P (decl) && !DECL_EXTERNAL (decl) && !TREE_STATIC (decl));
> >>>> gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
> >>>> tree decl_size = TYPE_SIZE_UNIT (TREE_TYPE (decl));
> >>>> 
> >>>> tree init_type_node
> >>>>  = build_int_cst (integer_type_node, (int) init_type);
> >>>> tree is_vla_node
> >>>>  = build_int_cst (integer_type_node, (int) is_vla);
> >>>> 
> >>>> tree call = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
> >>>>                                          TREE_TYPE (decl), 3,
> >>>>                                          decl_size, init_type_node,
> >>>>                                          is_vla_node);
> >>>> 
> >>>> /* If this DECL is a VLA, a temporary address variable for it has been
> >>>>   created, the replacement for DECL is recorded in DECL_VALUE_EXPR (decl),
> >>>>   we should use it as the LHS of the call.  */
> >>>> 
> >>>> tree lhs_call
> >>>>  = is_vla ? DECL_VALUE_EXPR (decl) : decl;
> >>>> gimplify_assign (lhs_call, call, seq_p);
> >>>> }
> >>>> 
> >>>> With this change, the current issue is resolved, the gimple dump now is:
> >>>> 
> >>>> (*arr.1) = .DEFERRED_INIT (D.1952, 2, 1);
> >>>> 
> >>>> However, there is another new issue:
> >>>> 
> >>>> For the following testing case:
> >>>> 
> >>>> ======
> >>>> [opc@qinzhao-ol8u3-x86 gcc]$ cat t.c
> >>>> int bar;
> >>>> 
> >>>> extern void decode_reloc(int *);
> >>>> 
> >>>> void testfunc()
> >>>> {
> >>>> int alt_reloc;
> >>>> 
> >>>> decode_reloc(&alt_reloc);
> >>>> 
> >>>> if (alt_reloc) /* { dg-warning "may be used uninitialized" } */
> >>>>  bar = 42; 
> >>>> }
> >>>> =====
> >>>> 
> >>>> In the above, the auto var “alt_reloc” is address taken, then the gimple dump for it when compiled with -ftrivial-auto-var-init=zero is:
> >>>> 
> >>>> void testfunc ()
> >>>> {
> >>>> int alt_reloc;
> >>>> 
> >>>> try
> >>>>  {
> >>>>    _1 = .DEFERRED_INIT (4, 2, 0);
> >>>>    alt_reloc = _1;
> >>>>    decode_reloc (&alt_reloc);
> >>>>    alt_reloc.0_2 = alt_reloc;
> >>>>    if (alt_reloc.0_2 != 0) goto <D.1949>; else goto <D.1950>;
> >>>>    <D.1949>:
> >>>>    bar = 42;
> >>>>    <D.1950>:
> >>>>  }
> >>>> finally
> >>>>  {
> >>>>    alt_reloc = {CLOBBER};
> >>>>  }
> >>>> }
> >>>> 
> >>>> I.e, instead of the expected IR:
> >>>> 
> >>>> alt_reloc = .DEFERRED_INIT (4, 2, 0);
> >>>> 
> >>>> We got the following:
> >>>> 
> >>>> _1 = .DEFERRED_INIT (4, 2, 0);
> >>>>    alt_reloc = _1;
> >>>> 
> >>>> I guess the temp “_1” is created because “alt_reloc” is address taken. 
> >>> 
> >>> Yes and no. The reason is that alt_reloc is memory (because it is address taken) and that GIMPLE says that register typed stores need to use a is_gimple_val RHS which the call is not.
> >> 
> >> Okay.
> >>> 
> >>>> My questions:
> >>>> 
> >>>> Shall we accept such IR for .DEFERRED_INIT purpose when the auto var is address taken? 
> >>> 
> >>> I think so. Note it doesn't necessarily need address taking but any other reason that prevents SSA rewriting the variable suffices. 
> >> 
> >> You mean, in addition to “address taken”, there are other situations that will introduce such IR:
> >> 
> >> temp = .DEFERRED_INIT();
> >> auto_var = temp;
> >> 
> >> So, such IR is unavoidable and we have to handle it?
> > 
> > Yes. 
> > 
> >> If we have to handle it,  what’ the best way to do it?
> >> 
> >> The solution in my mind is:
> >> 1. During uninitialized analysis phase, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then decide that “auto_var” is uninitialized.
> > 
> > Yes. Basically if there's an artificial variable auto initialized you have to look at its uses. 
> > 
> >> 2. During RTL expansion, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then delete “temp”, and then expand .DEFERRED_INIT to auto_var.
> > 
> > That shouldn't be necessary. You'd initialize a temporary register which is then copied to the real variable. That's good enough and should be optimized by the RTL pipeline. 
> > 
> >> Let me know your comments and suggestions on this.
> >> 
> >> 
> >>> 
> >>> The only other option is to force. DEFERED_INIT making the LHS address taken which I think could be achieved by passing it the address as argument instead of having a LHS. But let's not go down this route - it will have quite bad behavior on alias analysis and optimization. 
> >> 
> >> Okay.
> >> 
> >> Qing
> >>> 
> >>>> If so, “uninitialized analysis” phase need to be further adjusted to specially handle such IR. 
> >>>> 
> >>>> If not, what should we do when the auto var is address taken?
> >>>> 
> >>>> Thanks a lot.
> >>>> 
> >>>> Qing
> >>>> 
> >>>> 
> >>>>> On Aug 11, 2021, at 8:58 AM, Richard Biener <rguenther@suse.de> wrote:
> >>>>> 
> >>>>> On Wed, 11 Aug 2021, Qing Zhao wrote:
> >>>>> 
> >>>>>> 
> >>>>>> 
> >>>>>>> On Aug 11, 2021, at 8:37 AM, Richard Biener <rguenther@suse.de> wrote:
> >>>>>>> 
> >>>>>>> On Wed, 11 Aug 2021, Qing Zhao wrote:
> >>>>>>> 
> >>>>>>>> 
> >>>>>>>> 
> >>>>>>>>> On Aug 11, 2021, at 2:02 AM, Richard Biener <rguenther@suse.de> wrote:
> >>>>>>>>> 
> >>>>>>>>> On Tue, 10 Aug 2021, Qing Zhao wrote:
> >>>>>>>>> 
> >>>>>>>>>> 
> >>>>>>>>>> 
> >>>>>>>>>>> On Aug 10, 2021, at 3:16 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> >>>>>>>>>>> 
> >>>>>>>>>>> Hi, Richard,
> >>>>>>>>>>> 
> >>>>>>>>>>>> On Aug 10, 2021, at 10:22 AM, Richard Biener <rguenther@suse.de> wrote:
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>> Especially in the VLA case but likely also in general (though unlikely
> >>>>>>>>>>>>>> since usually the receiver of initializations are simple enough).  I'd
> >>>>>>>>>>>>>> expect the VLA case end up as
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>> *ptr_to_decl = .DEFERRED_INIT (...);
> >>>>>>>>>>>>>> 
> >>>>>>>>>>>>>> where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> So, for the following small testing case:
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> ====
> >>>>>>>>>>>>> extern void bar (int);
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> void foo(int n)
> >>>>>>>>>>>>> {
> >>>>>>>>>>>>> int arr[n];
> >>>>>>>>>>>>> bar (arr[2]);
> >>>>>>>>>>>>> return;
> >>>>>>>>>>>>> }
> >>>>>>>>>>>>> =====
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> If I compile it with -ftrivial-auto-var-init=zero -fdump-tree-gimple -S -o auto-init-11.s -fdump-rtl-expand, the *.gimple dump is:
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> =====
> >>>>>>>>>>>>> void foo (int n)
> >>>>>>>>>>>>> {
> >>>>>>>>>>>>> int n.0;
> >>>>>>>>>>>>> sizetype D.1950;
> >>>>>>>>>>>>> bitsizetype D.1951;
> >>>>>>>>>>>>> sizetype D.1952;
> >>>>>>>>>>>>> bitsizetype D.1953;
> >>>>>>>>>>>>> sizetype D.1954;
> >>>>>>>>>>>>> int[0:D.1950] * arr.1;
> >>>>>>>>>>>>> void * saved_stack.2;
> >>>>>>>>>>>>> int arr[0:D.1950] [value-expr: *arr.1];
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> saved_stack.2 = __builtin_stack_save ();
> >>>>>>>>>>>>> try
> >>>>>>>>>>>>> {
> >>>>>>>>>>>>> n.0 = n;
> >>>>>>>>>>>>> _1 = (long int) n.0;
> >>>>>>>>>>>>> _2 = _1 + -1;
> >>>>>>>>>>>>> _3 = (sizetype) _2;
> >>>>>>>>>>>>> D.1950 = _3;
> >>>>>>>>>>>>> _4 = (sizetype) n.0;
> >>>>>>>>>>>>> _5 = (bitsizetype) _4;
> >>>>>>>>>>>>> _6 = _5 * 32;
> >>>>>>>>>>>>> D.1951 = _6;
> >>>>>>>>>>>>> _7 = (sizetype) n.0;
> >>>>>>>>>>>>> _8 = _7 * 4;
> >>>>>>>>>>>>> D.1952 = _8;
> >>>>>>>>>>>>> _9 = (sizetype) n.0;
> >>>>>>>>>>>>> _10 = (bitsizetype) _9;
> >>>>>>>>>>>>> _11 = _10 * 32;
> >>>>>>>>>>>>> D.1953 = _11;
> >>>>>>>>>>>>> _12 = (sizetype) n.0;
> >>>>>>>>>>>>> _13 = _12 * 4;
> >>>>>>>>>>>>> D.1954 = _13;
> >>>>>>>>>>>>> arr.1 = __builtin_alloca_with_align (D.1954, 32);
> >>>>>>>>>>>>> arr = .DEFERRED_INIT (D.1952, 2, 1);
> >>>>>>>>>>>>> _14 = (*arr.1)[2];
> >>>>>>>>>>>>> bar (_14);
> >>>>>>>>>>>>> return;
> >>>>>>>>>>>>> }
> >>>>>>>>>>>>> finally
> >>>>>>>>>>>>> {
> >>>>>>>>>>>>> __builtin_stack_restore (saved_stack.2);
> >>>>>>>>>>>>> }
> >>>>>>>>>>>>> }
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> ====
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> You think that the above .DEFEERED_INIT is not correct?
> >>>>>>>>>>>>> It should be:
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952. 2, 1);
> >>>>>>>>>>>>> 
> >>>>>>>>>>>>> ?
> >>>>>>>>>>>> 
> >>>>>>>>>>>> Yes.
> >>>>>>>>>>>> 
> >>>>>>>>>>> 
> >>>>>>>>>>> I updated gimplify.c for VLA and now it emits the call to .DEFERRED_INIT as:
> >>>>>>>>>>> 
> >>>>>>>>>>> arr.1 = __builtin_alloca_with_align (D.1954, 32);
> >>>>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
> >>>>>>>>>>> 
> >>>>>>>>>>> However, this call triggered the assertion failure in verify_gimple_call of tree-cfg.c because the LHS is not a valid LHS. 
> >>>>>>>>>>> Then I modify tree-cfg.c as:
> >>>>>>>>>>> 
> >>>>>>>>>>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
> >>>>>>>>>>> index 330eb7dd89bf..180d4f1f9e32 100644
> >>>>>>>>>>> --- a/gcc/tree-cfg.c
> >>>>>>>>>>> +++ b/gcc/tree-cfg.c
> >>>>>>>>>>> @@ -3375,7 +3375,11 @@ verify_gimple_call (gcall *stmt)
> >>>>>>>>>>> }
> >>>>>>>>>>> 
> >>>>>>>>>>> tree lhs = gimple_call_lhs (stmt);
> >>>>>>>>>>> +  /* For .DEFERRED_INIT call, the LHS might be an indirection of
> >>>>>>>>>>> +     a pointer for the VLA variable, which is not a valid LHS of
> >>>>>>>>>>> +     a gimple call, we ignore the asssertion on this.  */ 
> >>>>>>>>>>> if (lhs
> >>>>>>>>>>> +      && (!gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
> >>>>>>>>>>>  && (!is_gimple_reg (lhs)
> >>>>>>>>>>>     && (!is_gimple_lvalue (lhs)
> >>>>>>>>>>>         || verify_types_in_gimple_reference
> >>>>>>>>>>> 
> >>>>>>>>>>> The assertion failure in tree-cfg.c got resolved, but I got another assertion failure in operands_scanner::get_expr_operands (tree *expr_p, int flags), line 945:
> >>>>>>>>>>> 
> >>>>>>>>>>> 939   /* If we get here, something has gone wrong.  */
> >>>>>>>>>>> 940   if (flag_checking)
> >>>>>>>>>>> 941     {
> >>>>>>>>>>> 942       fprintf (stderr, "unhandled expression in get_expr_operands():\n");
> >>>>>>>>>>> 943       debug_tree (expr);
> >>>>>>>>>>> 944       fputs ("\n", stderr);
> >>>>>>>>>>> 945       gcc_unreachable ();
> >>>>>>>>>>> 946     }
> >>>>>>>>>>> 
> >>>>>>>>>>> Looks like that  the gimple statement:
> >>>>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
> >>>>>>>>>>> 
> >>>>>>>>>>> Is not valid.  i.e, the LHS should not be an indirection to a pointer. 
> >>>>>>>>>>> 
> >>>>>>>>>>> How to resolve this issue?
> >>>>>>>>> 
> >>>>>>>>> It sounds like the LHS is an INDIRECT_REF maybe?  That means it's
> >>>>>>>>> still not properly gimplified because it should end up as a MEM_REF
> >>>>>>>>> instead.
> >>>>>>>>> 
> >>>>>>>>> But I'm just guessing here ... if you are in a debugger then you can
> >>>>>>>>> invoke debug_tree (lhs) in the inferior to see what it exactly is
> >>>>>>>>> at the point of the failure.
> >>>>>>>> 
> >>>>>>>> Yes, it’s an INDIRECT_REF at the point of the failure even though I added a 
> >>>>>>>> 
> >>>>>>>> gimplify_var_or_parm_decl  (lhs) 
> >>>>>>> 
> >>>>>>> I think the easiest is to build the .DEFERRED_INIT as GENERIC
> >>>>>>> and use gimplify_assign () to gimplify and add the result
> >>>>>>> to the sequence.  Thus, build a GENERIC CALL_EXPR and then
> >>>>>>> gimplify_assign (lhs, call_expr, seq);
> >>>>>> 
> >>>>>> Which utility routine is used to build an Internal generic call?
> >>>>>> Currently, I used “gimple_build_call_internal” to build this internal gimple call.
> >>>>>> 
> >>>>>> For the generic call, shall I use “build_call_expr_loc” ? 
> >>>>> 
> >>>>> For example look at build_asan_poison_call_expr which does such thing
> >>>>> for ASAN poison internal function call insertion at gimplification time.
> >>>>> 
> >>>>> Richard.
> >>>>> 
> >>>>>> Qing
> >>>>>> 
> >>>>>>> 
> >>>>>>> Richard.
> >>>>>>> 
> >>>>>>>> Qing
> >>>>>>>> 
> >>>>>>>>> 
> >>>>>>>>>> I came up with the following solution:
> >>>>>>>>>> 
> >>>>>>>>>> Define the IFN_DEFERRED_INIT function as:
> >>>>>>>>>> 
> >>>>>>>>>> LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA);
> >>>>>>>>>> 
> >>>>>>>>>> if IS_VLA is false, the LHS is the DECL itself,
> >>>>>>>>>> if IS_VLA is true, the LHS is the pointer to this DECL that created by
> >>>>>>>>>> gimplify_vla_decl.
> >>>>>>>>>> 
> >>>>>>>>>> 
> >>>>>>>>>> The benefit of this solution are:
> >>>>>>>>>> 
> >>>>>>>>>> 1. Resolved the invalid IR issue;
> >>>>>>>>>> 2. The call stmt carries the address of the VLA natually;
> >>>>>>>>>> 
> >>>>>>>>>> The issue with this solution is:
> >>>>>>>>>> 
> >>>>>>>>>> For VLA and non-VLA, the LHS will be different, 
> >>>>>>>>>> 
> >>>>>>>>>> Do you see any other potential issues with this solution?
> >>>>>>>>>> 
> >>>>>>>>>> thanks.
> >>>>>>>>>> 
> >>>>>>>>>> Qing
> >>>>>>>>>> 
> >>>>>>>>>> 
> >>>>>>>>>> 
> >>>>>>>>>> 
> >>>>>>>>>> 
> >>>>>>>>> 
> >>>>>>>>> -- 
> >>>>>>>>> Richard Biener <rguenther@suse.de>
> >>>>>>>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> >>>>>>>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
> >>>>>>>> 
> >>>>>>>> 
> >>>>>>> 
> >>>>>>> -- 
> >>>>>>> Richard Biener <rguenther@suse.de>
> >>>>>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> >>>>>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
> >>>>>> 
> >>>>>> 
> >>>>> 
> >>>>> -- 
> >>>>> Richard Biener <rguenther@suse.de>
> >>>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> >>>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
> 
> 

-- 
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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-11 22:03                                       ` Qing Zhao
@ 2021-08-16  7:12                                         ` Richard Biener
  2021-08-16 14:48                                           ` Qing Zhao
  0 siblings, 1 reply; 60+ messages in thread
From: Richard Biener @ 2021-08-16  7:12 UTC (permalink / raw)
  To: Qing Zhao
  Cc: Jakub Jelinek, Richard Sandiford, Nick Alcock via Gcc-patches, Kees Cook

On Wed, 11 Aug 2021, Qing Zhao wrote:

> Hi, 
> 
> I finally decided to take another approach to resolve this issue, it resolved all the potential issues with the “address taken” auto variable.
> 
> The basic idea is to avoid generating the temporary variable in the beginning. 
> As you mentioned, "The reason is that alt_reloc is memory (because it is address taken) and that GIMPLE says that register typed stores 
> need to use a is_gimple_val RHS which the call is not.”
> In order to avoid generating the temporary variable for “address taken” auto variable, I updated the utility routine “is_gimple_val” as following:
> 
> diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c
> index a2563a45c37d..d5ef1aef8cea 100644
> --- a/gcc/gimple-expr.c
> +++ b/gcc/gimple-expr.c
> @@ -787,8 +787,20 @@ is_gimple_reg (tree t)
>    return !DECL_NOT_GIMPLE_REG_P (t);
>  }
>  
> +/* Return true if T is a call to .DEFERRED_INIT internal function.  */ 
> +static bool
> +is_deferred_init_call (tree t)
> +{
> +  if (TREE_CODE (t) == CALL_EXPR
> +      &&  CALL_EXPR_IFN (t) == IFN_DEFERRED_INIT)
> +    return true;
> +  return false;
> +}
> +
>  
> -/* Return true if T is a GIMPLE rvalue, i.e. an identifier or a constant.  */
> +/* Return true if T is a GIMPLE rvalue, i.e. an identifier or a constant,
> +   or a call to .DEFERRED_INIT internal function because the call to
> +   .DEFERRED_INIT will eventually be expanded as a constant.  */
>  
>  bool
>  is_gimple_val (tree t)
> @@ -799,7 +811,8 @@ is_gimple_val (tree t)
>        && !is_gimple_reg (t))
>      return false;
>  
> -  return (is_gimple_variable (t) || is_gimple_min_invariant (t));
> +  return (is_gimple_variable (t) || is_gimple_min_invariant (t)
> +         || is_deferred_init_call (t));
>  }
>  
> With this change, the temporary variable will not be created for “address taken” auto variable, and uninitialized analysis does not need any change. 
> Everything works well.
> 
> And I believe that treating “call to .DEFERRED_INIT” as “is_gimple_val” is reasonable since this call actually is a constant.
>
> Let me know if you have any objection on this solution.

Yeah, I object to this solution.

Richard.

> thanks.
> 
> Qing
> 
> > On Aug 11, 2021, at 3:30 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> > 
> > Hi, 
> > 
> > I met another issue for “address taken” auto variable, see below for details:
> > 
> > **** the testing case: (gcc/testsuite/gcc.dg/uninit-16.c)
> > 
> > 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;
> > }
> > 
> > ****When compiled with -ftrivial-auto-var-init=zero -O2 -Wuninitialized -fdump-tree-all:
> > 
> > .*************gimple dump:
> > 
> > void testfunc ()
> > { 
> >  int alt_reloc;
> > 
> >  try
> >    {
> >      _1 = .DEFERRED_INIT (4, 2, 0);
> >      alt_reloc = _1;
> >      foo.0_2 = foo;
> >      decode_reloc (foo.0_2, &alt_reloc);
> >      alt_reloc.1_3 = alt_reloc;
> >      if (alt_reloc.1_3 != 0) goto <D.1952>; else goto <D.1953>;
> >      <D.1952>:
> >      bar = 42;
> >      <D.1953>:
> >    }
> >  finally
> >    {
> >      alt_reloc = {CLOBBER};
> >    }
> > }
> > 
> > **************fre1 dump:
> > 
> > void testfunc ()
> > {
> >  int alt_reloc;
> >  int _1;
> >  int foo.0_2;
> > 
> >  <bb 2> :
> >  _1 = .DEFERRED_INIT (4, 2, 0);
> >  foo.0_2 = foo;
> >  if (foo.0_2 > 19)
> >    goto <bb 3>; [50.00%]
> >  else
> >    goto <bb 4>; [50.00%]
> > 
> >  <bb 3> :
> >  goto <bb 7>; [100.00%]
> > 
> >  <bb 4> :
> >  if (foo.0_2 > 9)
> >    goto <bb 5>; [50.00%]
> >  else
> >    goto <bb 6>; [50.00%]
> > 
> >  <bb 5> :
> >  goto <bb 8>; [100.00%]
> > 
> >  <bb 6> :
> >  if (_1 != 0)
> >    goto <bb 7>; [INV]
> >  else
> >    goto <bb 8>; [INV]
> > 
> >  <bb 7> :
> >  bar = 42;
> > 
> >  <bb 8> :
> >  return;
> > 
> > }
> > 
> > From the above IR file after “FRE”, we can see that the major issue with this IR is:
> > 
> > The address taken auto variable “alt_reloc” has been completely replaced by the temporary variable “_1” in all
> > the uses of the original “alt_reloc”. 
> > 
> > The major problem with such IR is,  during uninitialized analysis phase, the original use of “alt_reloc” disappeared completely.
> > So, the warning cannot be reported.
> > 
> > 
> > My questions:
> > 
> > 1. Is it possible to get the original “alt_reloc” through the temporary variable “_1” with some available information recorded in the IR?
> > 2. If not, then we have to record the relationship between “alt_reloc” and “_1” when the original “alt_reloc” is replaced by “_1” and get such relationship during
> >    Uninitialized analysis phase.  Is this doable?
> > 3. Looks like that for “address taken” auto variable, if we have to introduce a new temporary variable and split the call to .DEFERRED_INIT into two:
> > 
> >      temp = .DEFERRED_INIT (4, 2, 0);
> >      alt_reloc = temp;
> > 
> >   More issues might possible.
> > 
> > Any comments and suggestions on this issue?
> > 
> > Qing
> > 
> > j
> >> On Aug 11, 2021, at 11:55 AM, Richard Biener <rguenther@suse.de> wrote:
> >> 
> >> On August 11, 2021 6:22:00 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
> >>> 
> >>> 
> >>>> On Aug 11, 2021, at 10:53 AM, Richard Biener <rguenther@suse.de> wrote:
> >>>> 
> >>>> On August 11, 2021 5:30:40 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
> >>>>> I modified the routine “gimple_add_init_for_auto_var” as the following:
> >>>>> ====
> >>>>> /* Generate initialization to automatic variable DECL based on INIT_TYPE.
> >>>>> Build a call to internal const function DEFERRED_INIT:
> >>>>> 1st argument: SIZE of the DECL;
> >>>>> 2nd argument: INIT_TYPE;
> >>>>> 3rd argument: IS_VLA, 0 NO, 1 YES;
> >>>>> 
> >>>>> as DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA).  */
> >>>>> static void
> >>>>> gimple_add_init_for_auto_var (tree decl,
> >>>>>                           enum auto_init_type init_type,
> >>>>>                           bool is_vla,
> >>>>>                           gimple_seq *seq_p)
> >>>>> {
> >>>>> gcc_assert (VAR_P (decl) && !DECL_EXTERNAL (decl) && !TREE_STATIC (decl));
> >>>>> gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
> >>>>> tree decl_size = TYPE_SIZE_UNIT (TREE_TYPE (decl));
> >>>>> 
> >>>>> tree init_type_node
> >>>>> = build_int_cst (integer_type_node, (int) init_type);
> >>>>> tree is_vla_node
> >>>>> = build_int_cst (integer_type_node, (int) is_vla);
> >>>>> 
> >>>>> tree call = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
> >>>>>                                         TREE_TYPE (decl), 3,
> >>>>>                                         decl_size, init_type_node,
> >>>>>                                         is_vla_node);
> >>>>> 
> >>>>> /* If this DECL is a VLA, a temporary address variable for it has been
> >>>>>  created, the replacement for DECL is recorded in DECL_VALUE_EXPR (decl),
> >>>>>  we should use it as the LHS of the call.  */
> >>>>> 
> >>>>> tree lhs_call
> >>>>> = is_vla ? DECL_VALUE_EXPR (decl) : decl;
> >>>>> gimplify_assign (lhs_call, call, seq_p);
> >>>>> }
> >>>>> 
> >>>>> With this change, the current issue is resolved, the gimple dump now is:
> >>>>> 
> >>>>> (*arr.1) = .DEFERRED_INIT (D.1952, 2, 1);
> >>>>> 
> >>>>> However, there is another new issue:
> >>>>> 
> >>>>> For the following testing case:
> >>>>> 
> >>>>> ======
> >>>>> [opc@qinzhao-ol8u3-x86 gcc]$ cat t.c
> >>>>> int bar;
> >>>>> 
> >>>>> extern void decode_reloc(int *);
> >>>>> 
> >>>>> void testfunc()
> >>>>> {
> >>>>> int alt_reloc;
> >>>>> 
> >>>>> decode_reloc(&alt_reloc);
> >>>>> 
> >>>>> if (alt_reloc) /* { dg-warning "may be used uninitialized" } */
> >>>>> bar = 42; 
> >>>>> }
> >>>>> =====
> >>>>> 
> >>>>> In the above, the auto var “alt_reloc” is address taken, then the gimple dump for it when compiled with -ftrivial-auto-var-init=zero is:
> >>>>> 
> >>>>> void testfunc ()
> >>>>> {
> >>>>> int alt_reloc;
> >>>>> 
> >>>>> try
> >>>>> {
> >>>>>   _1 = .DEFERRED_INIT (4, 2, 0);
> >>>>>   alt_reloc = _1;
> >>>>>   decode_reloc (&alt_reloc);
> >>>>>   alt_reloc.0_2 = alt_reloc;
> >>>>>   if (alt_reloc.0_2 != 0) goto <D.1949>; else goto <D.1950>;
> >>>>>   <D.1949>:
> >>>>>   bar = 42;
> >>>>>   <D.1950>:
> >>>>> }
> >>>>> finally
> >>>>> {
> >>>>>   alt_reloc = {CLOBBER};
> >>>>> }
> >>>>> }
> >>>>> 
> >>>>> I.e, instead of the expected IR:
> >>>>> 
> >>>>> alt_reloc = .DEFERRED_INIT (4, 2, 0);
> >>>>> 
> >>>>> We got the following:
> >>>>> 
> >>>>> _1 = .DEFERRED_INIT (4, 2, 0);
> >>>>>   alt_reloc = _1;
> >>>>> 
> >>>>> I guess the temp “_1” is created because “alt_reloc” is address taken. 
> >>>> 
> >>>> Yes and no. The reason is that alt_reloc is memory (because it is address taken) and that GIMPLE says that register typed stores need to use a is_gimple_val RHS which the call is not.
> >>> 
> >>> Okay.
> >>>> 
> >>>>> My questions:
> >>>>> 
> >>>>> Shall we accept such IR for .DEFERRED_INIT purpose when the auto var is address taken? 
> >>>> 
> >>>> I think so. Note it doesn't necessarily need address taking but any other reason that prevents SSA rewriting the variable suffices. 
> >>> 
> >>> You mean, in addition to “address taken”, there are other situations that will introduce such IR:
> >>> 
> >>> temp = .DEFERRED_INIT();
> >>> auto_var = temp;
> >>> 
> >>> So, such IR is unavoidable and we have to handle it?
> >> 
> >> Yes. 
> >> 
> >>> If we have to handle it,  what’ the best way to do it?
> >>> 
> >>> The solution in my mind is:
> >>> 1. During uninitialized analysis phase, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then decide that “auto_var” is uninitialized.
> >> 
> >> Yes. Basically if there's an artificial variable auto initialized you have to look at its uses. 
> >> 
> >>> 2. During RTL expansion, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then delete “temp”, and then expand .DEFERRED_INIT to auto_var.
> >> 
> >> That shouldn't be necessary. You'd initialize a temporary register which is then copied to the real variable. That's good enough and should be optimized by the RTL pipeline. 
> >> 
> >>> Let me know your comments and suggestions on this.
> >>> 
> >>> 
> >>>> 
> >>>> The only other option is to force. DEFERED_INIT making the LHS address taken which I think could be achieved by passing it the address as argument instead of having a LHS. But let's not go down this route - it will have quite bad behavior on alias analysis and optimization. 
> >>> 
> >>> Okay.
> >>> 
> >>> Qing
> >>>> 
> >>>>> If so, “uninitialized analysis” phase need to be further adjusted to specially handle such IR. 
> >>>>> 
> >>>>> If not, what should we do when the auto var is address taken?
> 
> 

-- 
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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-12 19:24   ` Qing Zhao
  2021-08-12 22:45     ` Qing Zhao
@ 2021-08-16  7:40     ` Richard Biener
  2021-08-16 15:45       ` Qing Zhao
  2021-08-16 19:49       ` Qing Zhao
  1 sibling, 2 replies; 60+ messages in thread
From: Richard Biener @ 2021-08-16  7:40 UTC (permalink / raw)
  To: Qing Zhao
  Cc: Martin Jambor, Jakub Jelinek, Kees Cook,
	Nick Alcock via Gcc-patches, Richard Biener

On Thu, 12 Aug 2021, Qing Zhao wrote:

> Hi, Richard,
> 
> For RTL expansion of call to .DEFERRED_INIT, I changed my code per your suggestions like following:
> 
> ======================
> #define INIT_PATTERN_VALUE  0xFE
> static void
> expand_DEFERRED_INIT (internal_fn, gcall *stmt)
> {
>   tree lhs = gimple_call_lhs (stmt);
>   tree var_size = gimple_call_arg (stmt, 0);
>   enum auto_init_type init_type
>     = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
>   bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
> 
>   tree var_type = TREE_TYPE (lhs);
>   gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
> 
>   if (is_vla || (!can_native_interpret_type_p (var_type)))
>     {
>     /* If this is a VLA or the type of the variable cannot be natively
>        interpreted, expand to a memset to initialize it.  */
>       if (TREE_CODE (lhs) == SSA_NAME)
>         lhs = SSA_NAME_VAR (lhs);
>       tree var_addr = NULL_TREE;
>       if (is_vla)
>         var_addr = TREE_OPERAND (lhs, 0);
>       else
>         {
>          TREE_ADDRESSABLE (lhs) = 1;
>          var_addr = build_fold_addr_expr (lhs);
>         }
>       tree value = (init_type == AUTO_INIT_PATTERN) ?
>                     build_int_cst (unsigned_char_type_node,
>                                    INIT_PATTERN_VALUE) :
>                     build_zero_cst (unsigned_char_type_node);
>       tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
>                                      3, var_addr, value, var_size);
>       /* Expand this memset call.  */
>       expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
>     }
>   else
>     {
>     /* If this is not a VLA and the type of the variable can be natively 
>        interpreted, expand to assignment to generate better code.  */
>       tree pattern = NULL_TREE;
>       unsigned HOST_WIDE_INT total_bytes
>         = tree_to_uhwi (TYPE_SIZE_UNIT (var_type));
> 
>       if (init_type == AUTO_INIT_PATTERN)
>         {
>           unsigned char *buf = (unsigned char *) xmalloc (total_bytes);
>           memset (buf, INIT_PATTERN_VALUE, total_bytes);
>           pattern = native_interpret_expr (var_type, buf, total_bytes);
>           gcc_assert (pattern);
>         }
> 
>       tree init = (init_type == AUTO_INIT_PATTERN) ?
>                    pattern :
>                    build_zero_cst (var_type);
>       expand_assignment (lhs, init, false);
>     }
> }
> ===========================
> 
> Now, I used “can_native_interpret_type_p (var_type)” instead of “use_register_for_decl (lhs)” to decide 
> whether to use “memset” or use “assign” to expand this function.
> 
> However, this exposed an bug that is very hard to be addressed:
> 
> *******For the testing case: test suite/gcc.dg/uninit-I.c:
> 
> /* { dg-do compile } */
> /* { dg-options "-O2 -Wuninitialized" } */
> 
> int sys_msgctl (void)
> {
>   struct { int mode; } setbuf;
>   return setbuf.mode;  /* { dg-warning "'setbuf\.mode' is used" } */
> ==
> 
> ******the above auto var “setbuf” has “struct” type, which “can_native_interpret_type_p(var_type)” is false, therefore, 
> Expanding this .DEFERRED_INIT call went down the “memset” expansion route. 
> 
> However, this structure type can be fitted into a register, therefore cannot be taken address anymore at this stage, even though I tried:
> 
>          TREE_ADDRESSABLE (lhs) = 1;
>          var_addr = build_fold_addr_expr (lhs);
> 
> To create an address variable for it, the expansion still failed at expr.c: line 8412:
> during RTL pass: expand
> /home/opc/Work/GCC/latest-gcc/gcc/testsuite/gcc.dg/auto-init-uninit-I.c:6:24: internal compiler error: in expand_expr_addr_expr_1, at expr.c:8412
> 0xd04104 expand_expr_addr_expr_1
> 	../../latest-gcc/gcc/expr.c:8412
> 0xd04a95 expand_expr_addr_expr
> 	../../latest-gcc/gcc/expr.c:8525
> 0xd13592 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
> 	../../latest-gcc/gcc/expr.c:11741
> 0xd05142 expand_expr_real(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
> 	../../latest-gcc/gcc/expr.c:8713
> 0xaed1d3 expand_expr
> 	../../latest-gcc/gcc/expr.h:301
> 0xaf0d89 get_memory_rtx
> 	../../latest-gcc/gcc/builtins.c:1370
> 0xafb4fb expand_builtin_memset_args
> 	../../latest-gcc/gcc/builtins.c:4102
> 0xafacde expand_builtin_memset(tree_node*, rtx_def*, machine_mode)
> 	../../latest-gcc/gcc/builtins.c:3886
> 0xe97fb3 expand_DEFERRED_INIT
> 
> ******That’s the major reason why I chose “use_register_for_decl(lhs)” to decide “memset” expansion or “assign” expansion, “memset” expansion
> needs to take address of the variable, if the variable has been decided to fit into a register, then its address cannot taken anymore at this stage.
> 
> ******using “can_native_interpret_type_p” did make the “pattern” generation part much  cleaner and simpler, however, looks like it didn’t work correctly.
> 
> Based on this, I’d like to keep my previous implementation by using “use_register_for_decl” to decide whether to take “memset” expansion or “assign” expansion.
> Therefore, I might still need to keep the “UGLY”  implementation of generatting “pattern” constant for different types?
> 
> Let me know your opinion on this.

Hmm, I think you can use use_register_for_decl(lhs) to decide to use an
alternate type to generate the pattern (and feed to 
can_native_interpret_type_p) by using
lang_hooks.type_for_mode (TYPE_MODE (TREE_TYPE (lhs))).  You can then
build the assignment from the pattern as

 VIEW_CONVERT <reg-type> (lhs) = pattern_cst;

note that more RTL-expand-ish would be to simply expand 'lhs' and
see whether it's a REG_P or a MEM_P and decide based on that.  Of course
that no longer allows you to use the high-level expand_assignment
or memset but you'd need to work on a lower level then.

Richard.

> Thanks a lot for the help.
> 
> Qing
> 
> 
> > On Aug 9, 2021, at 9:09 AM, Richard Biener <rguenther@suse.de> wrote:
> > 
> > On Tue, 27 Jul 2021, Qing Zhao wrote:
> > 
> > +        created during gimplification phase.  Refer to gimplify_vla_decl
> > +        for details.  */
> > +      tree var_decl = (TREE_CODE (var) == SSA_NAME) ?
> > +                      SSA_NAME_VAR (var) : var;
> > +      gcc_assert (DECL_HAS_VALUE_EXPR_P (var_decl));
> > +      gcc_assert (TREE_CODE (DECL_VALUE_EXPR (var_decl)) == 
> > INDIRECT_REF);
> > +      /* Get the address of this vla variable.  */
> > +      vlaaddr = TREE_OPERAND (DECL_VALUE_EXPR (var_decl), 0);
> > 
> > err - isn't the address of the decl represented by the LHS 
> > regardless whether this is a VLA or not?  Looking at DECL_VALUE_EXPR
> > looks quite fragile since that's not sth data dependence honors.
> > It looks you only partly gimplify the build init here?  All
> > DECL_VALUE_EXPRs should have been resolved.
> > 
> > +  if (is_vla || (!use_register_for_decl (var)))
> > ...
> > +  else
> > +    {
> > +    /* If this variable is in a register, use expand_assignment might
> > +       generate better code.  */
> > 
> > you compute the patter initializer even when not needing it,
> > that's wasteful.  It's also quite ugly, IMHO you should
> > use can_native_interpret_type_p (var_type) and native_interpret
> > a char [] array initialized to the pattern and if
> > !can_native_interpret_type_p () go the memset route.
> 

-- 
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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-16  7:12                                         ` Richard Biener
@ 2021-08-16 14:48                                           ` Qing Zhao
  2021-08-16 15:08                                             ` Richard Biener
  0 siblings, 1 reply; 60+ messages in thread
From: Qing Zhao @ 2021-08-16 14:48 UTC (permalink / raw)
  To: Richard Biener
  Cc: Jakub Jelinek, Richard Sandiford, Nick Alcock via Gcc-patches, Kees Cook



> On Aug 16, 2021, at 2:12 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Wed, 11 Aug 2021, Qing Zhao wrote:
> 
>> Hi, 
>> 
>> I finally decided to take another approach to resolve this issue, it resolved all the potential issues with the “address taken” auto variable.
>> 
>> The basic idea is to avoid generating the temporary variable in the beginning. 
>> As you mentioned, "The reason is that alt_reloc is memory (because it is address taken) and that GIMPLE says that register typed stores 
>> need to use a is_gimple_val RHS which the call is not.”
>> In order to avoid generating the temporary variable for “address taken” auto variable, I updated the utility routine “is_gimple_val” as following:
>> 
>> diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c
>> index a2563a45c37d..d5ef1aef8cea 100644
>> --- a/gcc/gimple-expr.c
>> +++ b/gcc/gimple-expr.c
>> @@ -787,8 +787,20 @@ is_gimple_reg (tree t)
>>   return !DECL_NOT_GIMPLE_REG_P (t);
>> }
>> 
>> +/* Return true if T is a call to .DEFERRED_INIT internal function.  */ 
>> +static bool
>> +is_deferred_init_call (tree t)
>> +{
>> +  if (TREE_CODE (t) == CALL_EXPR
>> +      &&  CALL_EXPR_IFN (t) == IFN_DEFERRED_INIT)
>> +    return true;
>> +  return false;
>> +}
>> +
>> 
>> -/* Return true if T is a GIMPLE rvalue, i.e. an identifier or a constant.  */
>> +/* Return true if T is a GIMPLE rvalue, i.e. an identifier or a constant,
>> +   or a call to .DEFERRED_INIT internal function because the call to
>> +   .DEFERRED_INIT will eventually be expanded as a constant.  */
>> 
>> bool
>> is_gimple_val (tree t)
>> @@ -799,7 +811,8 @@ is_gimple_val (tree t)
>>       && !is_gimple_reg (t))
>>     return false;
>> 
>> -  return (is_gimple_variable (t) || is_gimple_min_invariant (t));
>> +  return (is_gimple_variable (t) || is_gimple_min_invariant (t)
>> +         || is_deferred_init_call (t));
>> }
>> 
>> With this change, the temporary variable will not be created for “address taken” auto variable, and uninitialized analysis does not need any change. 
>> Everything works well.
>> 
>> And I believe that treating “call to .DEFERRED_INIT” as “is_gimple_val” is reasonable since this call actually is a constant.
>> 
>> Let me know if you have any objection on this solution.
> 
> Yeah, I object to this solution.

Can you explain what’s the major issue for this solution? 

To me,  treating “call to .DEFERRED_INIT” as “is_gimple_val” is reasonable since this call actually is a constant.

Thanks.

Qing
> Richard.
> 
>> thanks.
>> 
>> Qing
>> 
>>> On Aug 11, 2021, at 3:30 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>> 
>>> Hi, 
>>> 
>>> I met another issue for “address taken” auto variable, see below for details:
>>> 
>>> **** the testing case: (gcc/testsuite/gcc.dg/uninit-16.c)
>>> 
>>> 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;
>>> }
>>> 
>>> ****When compiled with -ftrivial-auto-var-init=zero -O2 -Wuninitialized -fdump-tree-all:
>>> 
>>> .*************gimple dump:
>>> 
>>> void testfunc ()
>>> { 
>>> int alt_reloc;
>>> 
>>> try
>>>   {
>>>     _1 = .DEFERRED_INIT (4, 2, 0);
>>>     alt_reloc = _1;
>>>     foo.0_2 = foo;
>>>     decode_reloc (foo.0_2, &alt_reloc);
>>>     alt_reloc.1_3 = alt_reloc;
>>>     if (alt_reloc.1_3 != 0) goto <D.1952>; else goto <D.1953>;
>>>     <D.1952>:
>>>     bar = 42;
>>>     <D.1953>:
>>>   }
>>> finally
>>>   {
>>>     alt_reloc = {CLOBBER};
>>>   }
>>> }
>>> 
>>> **************fre1 dump:
>>> 
>>> void testfunc ()
>>> {
>>> int alt_reloc;
>>> int _1;
>>> int foo.0_2;
>>> 
>>> <bb 2> :
>>> _1 = .DEFERRED_INIT (4, 2, 0);
>>> foo.0_2 = foo;
>>> if (foo.0_2 > 19)
>>>   goto <bb 3>; [50.00%]
>>> else
>>>   goto <bb 4>; [50.00%]
>>> 
>>> <bb 3> :
>>> goto <bb 7>; [100.00%]
>>> 
>>> <bb 4> :
>>> if (foo.0_2 > 9)
>>>   goto <bb 5>; [50.00%]
>>> else
>>>   goto <bb 6>; [50.00%]
>>> 
>>> <bb 5> :
>>> goto <bb 8>; [100.00%]
>>> 
>>> <bb 6> :
>>> if (_1 != 0)
>>>   goto <bb 7>; [INV]
>>> else
>>>   goto <bb 8>; [INV]
>>> 
>>> <bb 7> :
>>> bar = 42;
>>> 
>>> <bb 8> :
>>> return;
>>> 
>>> }
>>> 
>>> From the above IR file after “FRE”, we can see that the major issue with this IR is:
>>> 
>>> The address taken auto variable “alt_reloc” has been completely replaced by the temporary variable “_1” in all
>>> the uses of the original “alt_reloc”. 
>>> 
>>> The major problem with such IR is,  during uninitialized analysis phase, the original use of “alt_reloc” disappeared completely.
>>> So, the warning cannot be reported.
>>> 
>>> 
>>> My questions:
>>> 
>>> 1. Is it possible to get the original “alt_reloc” through the temporary variable “_1” with some available information recorded in the IR?
>>> 2. If not, then we have to record the relationship between “alt_reloc” and “_1” when the original “alt_reloc” is replaced by “_1” and get such relationship during
>>>   Uninitialized analysis phase.  Is this doable?
>>> 3. Looks like that for “address taken” auto variable, if we have to introduce a new temporary variable and split the call to .DEFERRED_INIT into two:
>>> 
>>>     temp = .DEFERRED_INIT (4, 2, 0);
>>>     alt_reloc = temp;
>>> 
>>>  More issues might possible.
>>> 
>>> Any comments and suggestions on this issue?
>>> 
>>> Qing
>>> 
>>> j
>>>> On Aug 11, 2021, at 11:55 AM, Richard Biener <rguenther@suse.de> wrote:
>>>> 
>>>> On August 11, 2021 6:22:00 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>>>>> 
>>>>> 
>>>>>> On Aug 11, 2021, at 10:53 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>> 
>>>>>> On August 11, 2021 5:30:40 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>>>>>>> I modified the routine “gimple_add_init_for_auto_var” as the following:
>>>>>>> ====
>>>>>>> /* Generate initialization to automatic variable DECL based on INIT_TYPE.
>>>>>>> Build a call to internal const function DEFERRED_INIT:
>>>>>>> 1st argument: SIZE of the DECL;
>>>>>>> 2nd argument: INIT_TYPE;
>>>>>>> 3rd argument: IS_VLA, 0 NO, 1 YES;
>>>>>>> 
>>>>>>> as DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA).  */
>>>>>>> static void
>>>>>>> gimple_add_init_for_auto_var (tree decl,
>>>>>>>                          enum auto_init_type init_type,
>>>>>>>                          bool is_vla,
>>>>>>>                          gimple_seq *seq_p)
>>>>>>> {
>>>>>>> gcc_assert (VAR_P (decl) && !DECL_EXTERNAL (decl) && !TREE_STATIC (decl));
>>>>>>> gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>>>>>>> tree decl_size = TYPE_SIZE_UNIT (TREE_TYPE (decl));
>>>>>>> 
>>>>>>> tree init_type_node
>>>>>>> = build_int_cst (integer_type_node, (int) init_type);
>>>>>>> tree is_vla_node
>>>>>>> = build_int_cst (integer_type_node, (int) is_vla);
>>>>>>> 
>>>>>>> tree call = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
>>>>>>>                                        TREE_TYPE (decl), 3,
>>>>>>>                                        decl_size, init_type_node,
>>>>>>>                                        is_vla_node);
>>>>>>> 
>>>>>>> /* If this DECL is a VLA, a temporary address variable for it has been
>>>>>>> created, the replacement for DECL is recorded in DECL_VALUE_EXPR (decl),
>>>>>>> we should use it as the LHS of the call.  */
>>>>>>> 
>>>>>>> tree lhs_call
>>>>>>> = is_vla ? DECL_VALUE_EXPR (decl) : decl;
>>>>>>> gimplify_assign (lhs_call, call, seq_p);
>>>>>>> }
>>>>>>> 
>>>>>>> With this change, the current issue is resolved, the gimple dump now is:
>>>>>>> 
>>>>>>> (*arr.1) = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>> 
>>>>>>> However, there is another new issue:
>>>>>>> 
>>>>>>> For the following testing case:
>>>>>>> 
>>>>>>> ======
>>>>>>> [opc@qinzhao-ol8u3-x86 gcc]$ cat t.c
>>>>>>> int bar;
>>>>>>> 
>>>>>>> extern void decode_reloc(int *);
>>>>>>> 
>>>>>>> void testfunc()
>>>>>>> {
>>>>>>> int alt_reloc;
>>>>>>> 
>>>>>>> decode_reloc(&alt_reloc);
>>>>>>> 
>>>>>>> if (alt_reloc) /* { dg-warning "may be used uninitialized" } */
>>>>>>> bar = 42; 
>>>>>>> }
>>>>>>> =====
>>>>>>> 
>>>>>>> In the above, the auto var “alt_reloc” is address taken, then the gimple dump for it when compiled with -ftrivial-auto-var-init=zero is:
>>>>>>> 
>>>>>>> void testfunc ()
>>>>>>> {
>>>>>>> int alt_reloc;
>>>>>>> 
>>>>>>> try
>>>>>>> {
>>>>>>>  _1 = .DEFERRED_INIT (4, 2, 0);
>>>>>>>  alt_reloc = _1;
>>>>>>>  decode_reloc (&alt_reloc);
>>>>>>>  alt_reloc.0_2 = alt_reloc;
>>>>>>>  if (alt_reloc.0_2 != 0) goto <D.1949>; else goto <D.1950>;
>>>>>>>  <D.1949>:
>>>>>>>  bar = 42;
>>>>>>>  <D.1950>:
>>>>>>> }
>>>>>>> finally
>>>>>>> {
>>>>>>>  alt_reloc = {CLOBBER};
>>>>>>> }
>>>>>>> }
>>>>>>> 
>>>>>>> I.e, instead of the expected IR:
>>>>>>> 
>>>>>>> alt_reloc = .DEFERRED_INIT (4, 2, 0);
>>>>>>> 
>>>>>>> We got the following:
>>>>>>> 
>>>>>>> _1 = .DEFERRED_INIT (4, 2, 0);
>>>>>>>  alt_reloc = _1;
>>>>>>> 
>>>>>>> I guess the temp “_1” is created because “alt_reloc” is address taken. 
>>>>>> 
>>>>>> Yes and no. The reason is that alt_reloc is memory (because it is address taken) and that GIMPLE says that register typed stores need to use a is_gimple_val RHS which the call is not.
>>>>> 
>>>>> Okay.
>>>>>> 
>>>>>>> My questions:
>>>>>>> 
>>>>>>> Shall we accept such IR for .DEFERRED_INIT purpose when the auto var is address taken? 
>>>>>> 
>>>>>> I think so. Note it doesn't necessarily need address taking but any other reason that prevents SSA rewriting the variable suffices. 
>>>>> 
>>>>> You mean, in addition to “address taken”, there are other situations that will introduce such IR:
>>>>> 
>>>>> temp = .DEFERRED_INIT();
>>>>> auto_var = temp;
>>>>> 
>>>>> So, such IR is unavoidable and we have to handle it?
>>>> 
>>>> Yes. 
>>>> 
>>>>> If we have to handle it,  what’ the best way to do it?
>>>>> 
>>>>> The solution in my mind is:
>>>>> 1. During uninitialized analysis phase, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then decide that “auto_var” is uninitialized.
>>>> 
>>>> Yes. Basically if there's an artificial variable auto initialized you have to look at its uses. 
>>>> 
>>>>> 2. During RTL expansion, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then delete “temp”, and then expand .DEFERRED_INIT to auto_var.
>>>> 
>>>> That shouldn't be necessary. You'd initialize a temporary register which is then copied to the real variable. That's good enough and should be optimized by the RTL pipeline. 
>>>> 
>>>>> Let me know your comments and suggestions on this.
>>>>> 
>>>>> 
>>>>>> 
>>>>>> The only other option is to force. DEFERED_INIT making the LHS address taken which I think could be achieved by passing it the address as argument instead of having a LHS. But let's not go down this route - it will have quite bad behavior on alias analysis and optimization. 
>>>>> 
>>>>> Okay.
>>>>> 
>>>>> Qing
>>>>>> 
>>>>>>> If so, “uninitialized analysis” phase need to be further adjusted to specially handle such IR. 
>>>>>>> 
>>>>>>> If not, what should we do when the auto var is address taken?
>> 
>> 
> 
> -- 
> 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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-16 14:48                                           ` Qing Zhao
@ 2021-08-16 15:08                                             ` Richard Biener
  2021-08-16 15:39                                               ` Qing Zhao
  0 siblings, 1 reply; 60+ messages in thread
From: Richard Biener @ 2021-08-16 15:08 UTC (permalink / raw)
  To: Qing Zhao
  Cc: Jakub Jelinek, Richard Sandiford, Nick Alcock via Gcc-patches, Kees Cook

On August 16, 2021 4:48:16 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>
>
>> On Aug 16, 2021, at 2:12 AM, Richard Biener <rguenther@suse.de> wrote:
>> 
>> On Wed, 11 Aug 2021, Qing Zhao wrote:
>> 
>>> Hi, 
>>> 
>>> I finally decided to take another approach to resolve this issue, it resolved all the potential issues with the “address taken” auto variable.
>>> 
>>> The basic idea is to avoid generating the temporary variable in the beginning. 
>>> As you mentioned, "The reason is that alt_reloc is memory (because it is address taken) and that GIMPLE says that register typed stores 
>>> need to use a is_gimple_val RHS which the call is not.”
>>> In order to avoid generating the temporary variable for “address taken” auto variable, I updated the utility routine “is_gimple_val” as following:
>>> 
>>> diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c
>>> index a2563a45c37d..d5ef1aef8cea 100644
>>> --- a/gcc/gimple-expr.c
>>> +++ b/gcc/gimple-expr.c
>>> @@ -787,8 +787,20 @@ is_gimple_reg (tree t)
>>>   return !DECL_NOT_GIMPLE_REG_P (t);
>>> }
>>> 
>>> +/* Return true if T is a call to .DEFERRED_INIT internal function.  */ 
>>> +static bool
>>> +is_deferred_init_call (tree t)
>>> +{
>>> +  if (TREE_CODE (t) == CALL_EXPR
>>> +      &&  CALL_EXPR_IFN (t) == IFN_DEFERRED_INIT)
>>> +    return true;
>>> +  return false;
>>> +}
>>> +
>>> 
>>> -/* Return true if T is a GIMPLE rvalue, i.e. an identifier or a constant.  */
>>> +/* Return true if T is a GIMPLE rvalue, i.e. an identifier or a constant,
>>> +   or a call to .DEFERRED_INIT internal function because the call to
>>> +   .DEFERRED_INIT will eventually be expanded as a constant.  */
>>> 
>>> bool
>>> is_gimple_val (tree t)
>>> @@ -799,7 +811,8 @@ is_gimple_val (tree t)
>>>       && !is_gimple_reg (t))
>>>     return false;
>>> 
>>> -  return (is_gimple_variable (t) || is_gimple_min_invariant (t));
>>> +  return (is_gimple_variable (t) || is_gimple_min_invariant (t)
>>> +         || is_deferred_init_call (t));
>>> }
>>> 
>>> With this change, the temporary variable will not be created for “address taken” auto variable, and uninitialized analysis does not need any change. 
>>> Everything works well.
>>> 
>>> And I believe that treating “call to .DEFERRED_INIT” as “is_gimple_val” is reasonable since this call actually is a constant.
>>> 
>>> Let me know if you have any objection on this solution.
>> 
>> Yeah, I object to this solution.
>
>Can you explain what’s the major issue for this solution? 

It punches a hole into the GIMPLE IL which is very likely incomplete and will cause issues elsewhere. In particular the corresponding type check is missing and not computable since the RHS of this call isn't separately available. 

If you go down this route then you should have added a new constant class tree code instead of an internal function call. 

>To me,  treating “call to .DEFERRED_INIT” as “is_gimple_val” is reasonable since this call actually is a constant.

Sure, but it's not represented as such. 

Richard. 

>Thanks.
>
>Qing
>> Richard.
>> 
>>> thanks.
>>> 
>>> Qing
>>> 
>>>> On Aug 11, 2021, at 3:30 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>>> 
>>>> Hi, 
>>>> 
>>>> I met another issue for “address taken” auto variable, see below for details:
>>>> 
>>>> **** the testing case: (gcc/testsuite/gcc.dg/uninit-16.c)
>>>> 
>>>> 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;
>>>> }
>>>> 
>>>> ****When compiled with -ftrivial-auto-var-init=zero -O2 -Wuninitialized -fdump-tree-all:
>>>> 
>>>> .*************gimple dump:
>>>> 
>>>> void testfunc ()
>>>> { 
>>>> int alt_reloc;
>>>> 
>>>> try
>>>>   {
>>>>     _1 = .DEFERRED_INIT (4, 2, 0);
>>>>     alt_reloc = _1;
>>>>     foo.0_2 = foo;
>>>>     decode_reloc (foo.0_2, &alt_reloc);
>>>>     alt_reloc.1_3 = alt_reloc;
>>>>     if (alt_reloc.1_3 != 0) goto <D.1952>; else goto <D.1953>;
>>>>     <D.1952>:
>>>>     bar = 42;
>>>>     <D.1953>:
>>>>   }
>>>> finally
>>>>   {
>>>>     alt_reloc = {CLOBBER};
>>>>   }
>>>> }
>>>> 
>>>> **************fre1 dump:
>>>> 
>>>> void testfunc ()
>>>> {
>>>> int alt_reloc;
>>>> int _1;
>>>> int foo.0_2;
>>>> 
>>>> <bb 2> :
>>>> _1 = .DEFERRED_INIT (4, 2, 0);
>>>> foo.0_2 = foo;
>>>> if (foo.0_2 > 19)
>>>>   goto <bb 3>; [50.00%]
>>>> else
>>>>   goto <bb 4>; [50.00%]
>>>> 
>>>> <bb 3> :
>>>> goto <bb 7>; [100.00%]
>>>> 
>>>> <bb 4> :
>>>> if (foo.0_2 > 9)
>>>>   goto <bb 5>; [50.00%]
>>>> else
>>>>   goto <bb 6>; [50.00%]
>>>> 
>>>> <bb 5> :
>>>> goto <bb 8>; [100.00%]
>>>> 
>>>> <bb 6> :
>>>> if (_1 != 0)
>>>>   goto <bb 7>; [INV]
>>>> else
>>>>   goto <bb 8>; [INV]
>>>> 
>>>> <bb 7> :
>>>> bar = 42;
>>>> 
>>>> <bb 8> :
>>>> return;
>>>> 
>>>> }
>>>> 
>>>> From the above IR file after “FRE”, we can see that the major issue with this IR is:
>>>> 
>>>> The address taken auto variable “alt_reloc” has been completely replaced by the temporary variable “_1” in all
>>>> the uses of the original “alt_reloc”. 
>>>> 
>>>> The major problem with such IR is,  during uninitialized analysis phase, the original use of “alt_reloc” disappeared completely.
>>>> So, the warning cannot be reported.
>>>> 
>>>> 
>>>> My questions:
>>>> 
>>>> 1. Is it possible to get the original “alt_reloc” through the temporary variable “_1” with some available information recorded in the IR?
>>>> 2. If not, then we have to record the relationship between “alt_reloc” and “_1” when the original “alt_reloc” is replaced by “_1” and get such relationship during
>>>>   Uninitialized analysis phase.  Is this doable?
>>>> 3. Looks like that for “address taken” auto variable, if we have to introduce a new temporary variable and split the call to .DEFERRED_INIT into two:
>>>> 
>>>>     temp = .DEFERRED_INIT (4, 2, 0);
>>>>     alt_reloc = temp;
>>>> 
>>>>  More issues might possible.
>>>> 
>>>> Any comments and suggestions on this issue?
>>>> 
>>>> Qing
>>>> 
>>>> j
>>>>> On Aug 11, 2021, at 11:55 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>> 
>>>>> On August 11, 2021 6:22:00 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>>>>>> 
>>>>>> 
>>>>>>> On Aug 11, 2021, at 10:53 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>> 
>>>>>>> On August 11, 2021 5:30:40 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>>>>>>>> I modified the routine “gimple_add_init_for_auto_var” as the following:
>>>>>>>> ====
>>>>>>>> /* Generate initialization to automatic variable DECL based on INIT_TYPE.
>>>>>>>> Build a call to internal const function DEFERRED_INIT:
>>>>>>>> 1st argument: SIZE of the DECL;
>>>>>>>> 2nd argument: INIT_TYPE;
>>>>>>>> 3rd argument: IS_VLA, 0 NO, 1 YES;
>>>>>>>> 
>>>>>>>> as DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA).  */
>>>>>>>> static void
>>>>>>>> gimple_add_init_for_auto_var (tree decl,
>>>>>>>>                          enum auto_init_type init_type,
>>>>>>>>                          bool is_vla,
>>>>>>>>                          gimple_seq *seq_p)
>>>>>>>> {
>>>>>>>> gcc_assert (VAR_P (decl) && !DECL_EXTERNAL (decl) && !TREE_STATIC (decl));
>>>>>>>> gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>>>>>>>> tree decl_size = TYPE_SIZE_UNIT (TREE_TYPE (decl));
>>>>>>>> 
>>>>>>>> tree init_type_node
>>>>>>>> = build_int_cst (integer_type_node, (int) init_type);
>>>>>>>> tree is_vla_node
>>>>>>>> = build_int_cst (integer_type_node, (int) is_vla);
>>>>>>>> 
>>>>>>>> tree call = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
>>>>>>>>                                        TREE_TYPE (decl), 3,
>>>>>>>>                                        decl_size, init_type_node,
>>>>>>>>                                        is_vla_node);
>>>>>>>> 
>>>>>>>> /* If this DECL is a VLA, a temporary address variable for it has been
>>>>>>>> created, the replacement for DECL is recorded in DECL_VALUE_EXPR (decl),
>>>>>>>> we should use it as the LHS of the call.  */
>>>>>>>> 
>>>>>>>> tree lhs_call
>>>>>>>> = is_vla ? DECL_VALUE_EXPR (decl) : decl;
>>>>>>>> gimplify_assign (lhs_call, call, seq_p);
>>>>>>>> }
>>>>>>>> 
>>>>>>>> With this change, the current issue is resolved, the gimple dump now is:
>>>>>>>> 
>>>>>>>> (*arr.1) = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>> 
>>>>>>>> However, there is another new issue:
>>>>>>>> 
>>>>>>>> For the following testing case:
>>>>>>>> 
>>>>>>>> ======
>>>>>>>> [opc@qinzhao-ol8u3-x86 gcc]$ cat t.c
>>>>>>>> int bar;
>>>>>>>> 
>>>>>>>> extern void decode_reloc(int *);
>>>>>>>> 
>>>>>>>> void testfunc()
>>>>>>>> {
>>>>>>>> int alt_reloc;
>>>>>>>> 
>>>>>>>> decode_reloc(&alt_reloc);
>>>>>>>> 
>>>>>>>> if (alt_reloc) /* { dg-warning "may be used uninitialized" } */
>>>>>>>> bar = 42; 
>>>>>>>> }
>>>>>>>> =====
>>>>>>>> 
>>>>>>>> In the above, the auto var “alt_reloc” is address taken, then the gimple dump for it when compiled with -ftrivial-auto-var-init=zero is:
>>>>>>>> 
>>>>>>>> void testfunc ()
>>>>>>>> {
>>>>>>>> int alt_reloc;
>>>>>>>> 
>>>>>>>> try
>>>>>>>> {
>>>>>>>>  _1 = .DEFERRED_INIT (4, 2, 0);
>>>>>>>>  alt_reloc = _1;
>>>>>>>>  decode_reloc (&alt_reloc);
>>>>>>>>  alt_reloc.0_2 = alt_reloc;
>>>>>>>>  if (alt_reloc.0_2 != 0) goto <D.1949>; else goto <D.1950>;
>>>>>>>>  <D.1949>:
>>>>>>>>  bar = 42;
>>>>>>>>  <D.1950>:
>>>>>>>> }
>>>>>>>> finally
>>>>>>>> {
>>>>>>>>  alt_reloc = {CLOBBER};
>>>>>>>> }
>>>>>>>> }
>>>>>>>> 
>>>>>>>> I.e, instead of the expected IR:
>>>>>>>> 
>>>>>>>> alt_reloc = .DEFERRED_INIT (4, 2, 0);
>>>>>>>> 
>>>>>>>> We got the following:
>>>>>>>> 
>>>>>>>> _1 = .DEFERRED_INIT (4, 2, 0);
>>>>>>>>  alt_reloc = _1;
>>>>>>>> 
>>>>>>>> I guess the temp “_1” is created because “alt_reloc” is address taken. 
>>>>>>> 
>>>>>>> Yes and no. The reason is that alt_reloc is memory (because it is address taken) and that GIMPLE says that register typed stores need to use a is_gimple_val RHS which the call is not.
>>>>>> 
>>>>>> Okay.
>>>>>>> 
>>>>>>>> My questions:
>>>>>>>> 
>>>>>>>> Shall we accept such IR for .DEFERRED_INIT purpose when the auto var is address taken? 
>>>>>>> 
>>>>>>> I think so. Note it doesn't necessarily need address taking but any other reason that prevents SSA rewriting the variable suffices. 
>>>>>> 
>>>>>> You mean, in addition to “address taken”, there are other situations that will introduce such IR:
>>>>>> 
>>>>>> temp = .DEFERRED_INIT();
>>>>>> auto_var = temp;
>>>>>> 
>>>>>> So, such IR is unavoidable and we have to handle it?
>>>>> 
>>>>> Yes. 
>>>>> 
>>>>>> If we have to handle it,  what’ the best way to do it?
>>>>>> 
>>>>>> The solution in my mind is:
>>>>>> 1. During uninitialized analysis phase, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then decide that “auto_var” is uninitialized.
>>>>> 
>>>>> Yes. Basically if there's an artificial variable auto initialized you have to look at its uses. 
>>>>> 
>>>>>> 2. During RTL expansion, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then delete “temp”, and then expand .DEFERRED_INIT to auto_var.
>>>>> 
>>>>> That shouldn't be necessary. You'd initialize a temporary register which is then copied to the real variable. That's good enough and should be optimized by the RTL pipeline. 
>>>>> 
>>>>>> Let me know your comments and suggestions on this.
>>>>>> 
>>>>>> 
>>>>>>> 
>>>>>>> The only other option is to force. DEFERED_INIT making the LHS address taken which I think could be achieved by passing it the address as argument instead of having a LHS. But let's not go down this route - it will have quite bad behavior on alias analysis and optimization. 
>>>>>> 
>>>>>> Okay.
>>>>>> 
>>>>>> Qing
>>>>>>> 
>>>>>>>> If so, “uninitialized analysis” phase need to be further adjusted to specially handle such IR. 
>>>>>>>> 
>>>>>>>> If not, what should we do when the auto var is address taken?
>>> 
>>> 
>> 
>> -- 
>> 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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-16 15:08                                             ` Richard Biener
@ 2021-08-16 15:39                                               ` Qing Zhao
  0 siblings, 0 replies; 60+ messages in thread
From: Qing Zhao @ 2021-08-16 15:39 UTC (permalink / raw)
  To: Richard Biener
  Cc: Jakub Jelinek, Richard Sandiford, Nick Alcock via Gcc-patches, Kees Cook



> On Aug 16, 2021, at 10:08 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On August 16, 2021 4:48:16 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>> 
>> 
>>> On Aug 16, 2021, at 2:12 AM, Richard Biener <rguenther@suse.de> wrote:
>>> 
>>> On Wed, 11 Aug 2021, Qing Zhao wrote:
>>> 
>>>> Hi, 
>>>> 
>>>> I finally decided to take another approach to resolve this issue, it resolved all the potential issues with the “address taken” auto variable.
>>>> 
>>>> The basic idea is to avoid generating the temporary variable in the beginning. 
>>>> As you mentioned, "The reason is that alt_reloc is memory (because it is address taken) and that GIMPLE says that register typed stores 
>>>> need to use a is_gimple_val RHS which the call is not.”
>>>> In order to avoid generating the temporary variable for “address taken” auto variable, I updated the utility routine “is_gimple_val” as following:
>>>> 
>>>> diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c
>>>> index a2563a45c37d..d5ef1aef8cea 100644
>>>> --- a/gcc/gimple-expr.c
>>>> +++ b/gcc/gimple-expr.c
>>>> @@ -787,8 +787,20 @@ is_gimple_reg (tree t)
>>>>  return !DECL_NOT_GIMPLE_REG_P (t);
>>>> }
>>>> 
>>>> +/* Return true if T is a call to .DEFERRED_INIT internal function.  */ 
>>>> +static bool
>>>> +is_deferred_init_call (tree t)
>>>> +{
>>>> +  if (TREE_CODE (t) == CALL_EXPR
>>>> +      &&  CALL_EXPR_IFN (t) == IFN_DEFERRED_INIT)
>>>> +    return true;
>>>> +  return false;
>>>> +}
>>>> +
>>>> 
>>>> -/* Return true if T is a GIMPLE rvalue, i.e. an identifier or a constant.  */
>>>> +/* Return true if T is a GIMPLE rvalue, i.e. an identifier or a constant,
>>>> +   or a call to .DEFERRED_INIT internal function because the call to
>>>> +   .DEFERRED_INIT will eventually be expanded as a constant.  */
>>>> 
>>>> bool
>>>> is_gimple_val (tree t)
>>>> @@ -799,7 +811,8 @@ is_gimple_val (tree t)
>>>>      && !is_gimple_reg (t))
>>>>    return false;
>>>> 
>>>> -  return (is_gimple_variable (t) || is_gimple_min_invariant (t));
>>>> +  return (is_gimple_variable (t) || is_gimple_min_invariant (t)
>>>> +         || is_deferred_init_call (t));
>>>> }
>>>> 
>>>> With this change, the temporary variable will not be created for “address taken” auto variable, and uninitialized analysis does not need any change. 
>>>> Everything works well.
>>>> 
>>>> And I believe that treating “call to .DEFERRED_INIT” as “is_gimple_val” is reasonable since this call actually is a constant.
>>>> 
>>>> Let me know if you have any objection on this solution.
>>> 
>>> Yeah, I object to this solution.
>> 
>> Can you explain what’s the major issue for this solution? 
> 
> It punches a hole into the GIMPLE IL which is very likely incomplete and will cause issues elsewhere. In particular the corresponding type check is missing and not computable since the RHS of this call isn't separately available. 
> 
> If you go down this route then you should have added a new constant class tree code instead of an internal function call. 

Okay. I see. 
> 
>> To me,  treating “call to .DEFERRED_INIT” as “is_gimple_val” is reasonable since this call actually is a constant.
> 
> Sure, but it's not represented as such. 

Thank you!.

Qing
> 
> Richard. 
> 
>> Thanks.
>> 
>> Qing
>>> Richard.
>>> 
>>>> thanks.
>>>> 
>>>> Qing
>>>> 
>>>>> On Aug 11, 2021, at 3:30 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>>>> 
>>>>> Hi, 
>>>>> 
>>>>> I met another issue for “address taken” auto variable, see below for details:
>>>>> 
>>>>> **** the testing case: (gcc/testsuite/gcc.dg/uninit-16.c)
>>>>> 
>>>>> 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;
>>>>> }
>>>>> 
>>>>> ****When compiled with -ftrivial-auto-var-init=zero -O2 -Wuninitialized -fdump-tree-all:
>>>>> 
>>>>> .*************gimple dump:
>>>>> 
>>>>> void testfunc ()
>>>>> { 
>>>>> int alt_reloc;
>>>>> 
>>>>> try
>>>>>  {
>>>>>    _1 = .DEFERRED_INIT (4, 2, 0);
>>>>>    alt_reloc = _1;
>>>>>    foo.0_2 = foo;
>>>>>    decode_reloc (foo.0_2, &alt_reloc);
>>>>>    alt_reloc.1_3 = alt_reloc;
>>>>>    if (alt_reloc.1_3 != 0) goto <D.1952>; else goto <D.1953>;
>>>>>    <D.1952>:
>>>>>    bar = 42;
>>>>>    <D.1953>:
>>>>>  }
>>>>> finally
>>>>>  {
>>>>>    alt_reloc = {CLOBBER};
>>>>>  }
>>>>> }
>>>>> 
>>>>> **************fre1 dump:
>>>>> 
>>>>> void testfunc ()
>>>>> {
>>>>> int alt_reloc;
>>>>> int _1;
>>>>> int foo.0_2;
>>>>> 
>>>>> <bb 2> :
>>>>> _1 = .DEFERRED_INIT (4, 2, 0);
>>>>> foo.0_2 = foo;
>>>>> if (foo.0_2 > 19)
>>>>>  goto <bb 3>; [50.00%]
>>>>> else
>>>>>  goto <bb 4>; [50.00%]
>>>>> 
>>>>> <bb 3> :
>>>>> goto <bb 7>; [100.00%]
>>>>> 
>>>>> <bb 4> :
>>>>> if (foo.0_2 > 9)
>>>>>  goto <bb 5>; [50.00%]
>>>>> else
>>>>>  goto <bb 6>; [50.00%]
>>>>> 
>>>>> <bb 5> :
>>>>> goto <bb 8>; [100.00%]
>>>>> 
>>>>> <bb 6> :
>>>>> if (_1 != 0)
>>>>>  goto <bb 7>; [INV]
>>>>> else
>>>>>  goto <bb 8>; [INV]
>>>>> 
>>>>> <bb 7> :
>>>>> bar = 42;
>>>>> 
>>>>> <bb 8> :
>>>>> return;
>>>>> 
>>>>> }
>>>>> 
>>>>> From the above IR file after “FRE”, we can see that the major issue with this IR is:
>>>>> 
>>>>> The address taken auto variable “alt_reloc” has been completely replaced by the temporary variable “_1” in all
>>>>> the uses of the original “alt_reloc”. 
>>>>> 
>>>>> The major problem with such IR is,  during uninitialized analysis phase, the original use of “alt_reloc” disappeared completely.
>>>>> So, the warning cannot be reported.
>>>>> 
>>>>> 
>>>>> My questions:
>>>>> 
>>>>> 1. Is it possible to get the original “alt_reloc” through the temporary variable “_1” with some available information recorded in the IR?
>>>>> 2. If not, then we have to record the relationship between “alt_reloc” and “_1” when the original “alt_reloc” is replaced by “_1” and get such relationship during
>>>>>  Uninitialized analysis phase.  Is this doable?
>>>>> 3. Looks like that for “address taken” auto variable, if we have to introduce a new temporary variable and split the call to .DEFERRED_INIT into two:
>>>>> 
>>>>>    temp = .DEFERRED_INIT (4, 2, 0);
>>>>>    alt_reloc = temp;
>>>>> 
>>>>> More issues might possible.
>>>>> 
>>>>> Any comments and suggestions on this issue?
>>>>> 
>>>>> Qing
>>>>> 
>>>>> j
>>>>>> On Aug 11, 2021, at 11:55 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>> 
>>>>>> On August 11, 2021 6:22:00 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>>>>>>> 
>>>>>>> 
>>>>>>>> On Aug 11, 2021, at 10:53 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>>> 
>>>>>>>> On August 11, 2021 5:30:40 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>>>>>>>>> I modified the routine “gimple_add_init_for_auto_var” as the following:
>>>>>>>>> ====
>>>>>>>>> /* Generate initialization to automatic variable DECL based on INIT_TYPE.
>>>>>>>>> Build a call to internal const function DEFERRED_INIT:
>>>>>>>>> 1st argument: SIZE of the DECL;
>>>>>>>>> 2nd argument: INIT_TYPE;
>>>>>>>>> 3rd argument: IS_VLA, 0 NO, 1 YES;
>>>>>>>>> 
>>>>>>>>> as DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA).  */
>>>>>>>>> static void
>>>>>>>>> gimple_add_init_for_auto_var (tree decl,
>>>>>>>>>                         enum auto_init_type init_type,
>>>>>>>>>                         bool is_vla,
>>>>>>>>>                         gimple_seq *seq_p)
>>>>>>>>> {
>>>>>>>>> gcc_assert (VAR_P (decl) && !DECL_EXTERNAL (decl) && !TREE_STATIC (decl));
>>>>>>>>> gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>>>>>>>>> tree decl_size = TYPE_SIZE_UNIT (TREE_TYPE (decl));
>>>>>>>>> 
>>>>>>>>> tree init_type_node
>>>>>>>>> = build_int_cst (integer_type_node, (int) init_type);
>>>>>>>>> tree is_vla_node
>>>>>>>>> = build_int_cst (integer_type_node, (int) is_vla);
>>>>>>>>> 
>>>>>>>>> tree call = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
>>>>>>>>>                                       TREE_TYPE (decl), 3,
>>>>>>>>>                                       decl_size, init_type_node,
>>>>>>>>>                                       is_vla_node);
>>>>>>>>> 
>>>>>>>>> /* If this DECL is a VLA, a temporary address variable for it has been
>>>>>>>>> created, the replacement for DECL is recorded in DECL_VALUE_EXPR (decl),
>>>>>>>>> we should use it as the LHS of the call.  */
>>>>>>>>> 
>>>>>>>>> tree lhs_call
>>>>>>>>> = is_vla ? DECL_VALUE_EXPR (decl) : decl;
>>>>>>>>> gimplify_assign (lhs_call, call, seq_p);
>>>>>>>>> }
>>>>>>>>> 
>>>>>>>>> With this change, the current issue is resolved, the gimple dump now is:
>>>>>>>>> 
>>>>>>>>> (*arr.1) = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>>> 
>>>>>>>>> However, there is another new issue:
>>>>>>>>> 
>>>>>>>>> For the following testing case:
>>>>>>>>> 
>>>>>>>>> ======
>>>>>>>>> [opc@qinzhao-ol8u3-x86 gcc]$ cat t.c
>>>>>>>>> int bar;
>>>>>>>>> 
>>>>>>>>> extern void decode_reloc(int *);
>>>>>>>>> 
>>>>>>>>> void testfunc()
>>>>>>>>> {
>>>>>>>>> int alt_reloc;
>>>>>>>>> 
>>>>>>>>> decode_reloc(&alt_reloc);
>>>>>>>>> 
>>>>>>>>> if (alt_reloc) /* { dg-warning "may be used uninitialized" } */
>>>>>>>>> bar = 42; 
>>>>>>>>> }
>>>>>>>>> =====
>>>>>>>>> 
>>>>>>>>> In the above, the auto var “alt_reloc” is address taken, then the gimple dump for it when compiled with -ftrivial-auto-var-init=zero is:
>>>>>>>>> 
>>>>>>>>> void testfunc ()
>>>>>>>>> {
>>>>>>>>> int alt_reloc;
>>>>>>>>> 
>>>>>>>>> try
>>>>>>>>> {
>>>>>>>>> _1 = .DEFERRED_INIT (4, 2, 0);
>>>>>>>>> alt_reloc = _1;
>>>>>>>>> decode_reloc (&alt_reloc);
>>>>>>>>> alt_reloc.0_2 = alt_reloc;
>>>>>>>>> if (alt_reloc.0_2 != 0) goto <D.1949>; else goto <D.1950>;
>>>>>>>>> <D.1949>:
>>>>>>>>> bar = 42;
>>>>>>>>> <D.1950>:
>>>>>>>>> }
>>>>>>>>> finally
>>>>>>>>> {
>>>>>>>>> alt_reloc = {CLOBBER};
>>>>>>>>> }
>>>>>>>>> }
>>>>>>>>> 
>>>>>>>>> I.e, instead of the expected IR:
>>>>>>>>> 
>>>>>>>>> alt_reloc = .DEFERRED_INIT (4, 2, 0);
>>>>>>>>> 
>>>>>>>>> We got the following:
>>>>>>>>> 
>>>>>>>>> _1 = .DEFERRED_INIT (4, 2, 0);
>>>>>>>>> alt_reloc = _1;
>>>>>>>>> 
>>>>>>>>> I guess the temp “_1” is created because “alt_reloc” is address taken. 
>>>>>>>> 
>>>>>>>> Yes and no. The reason is that alt_reloc is memory (because it is address taken) and that GIMPLE says that register typed stores need to use a is_gimple_val RHS which the call is not.
>>>>>>> 
>>>>>>> Okay.
>>>>>>>> 
>>>>>>>>> My questions:
>>>>>>>>> 
>>>>>>>>> Shall we accept such IR for .DEFERRED_INIT purpose when the auto var is address taken? 
>>>>>>>> 
>>>>>>>> I think so. Note it doesn't necessarily need address taking but any other reason that prevents SSA rewriting the variable suffices. 
>>>>>>> 
>>>>>>> You mean, in addition to “address taken”, there are other situations that will introduce such IR:
>>>>>>> 
>>>>>>> temp = .DEFERRED_INIT();
>>>>>>> auto_var = temp;
>>>>>>> 
>>>>>>> So, such IR is unavoidable and we have to handle it?
>>>>>> 
>>>>>> Yes. 
>>>>>> 
>>>>>>> If we have to handle it,  what’ the best way to do it?
>>>>>>> 
>>>>>>> The solution in my mind is:
>>>>>>> 1. During uninitialized analysis phase, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then decide that “auto_var” is uninitialized.
>>>>>> 
>>>>>> Yes. Basically if there's an artificial variable auto initialized you have to look at its uses. 
>>>>>> 
>>>>>>> 2. During RTL expansion, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then delete “temp”, and then expand .DEFERRED_INIT to auto_var.
>>>>>> 
>>>>>> That shouldn't be necessary. You'd initialize a temporary register which is then copied to the real variable. That's good enough and should be optimized by the RTL pipeline. 
>>>>>> 
>>>>>>> Let me know your comments and suggestions on this.
>>>>>>> 
>>>>>>> 
>>>>>>>> 
>>>>>>>> The only other option is to force. DEFERED_INIT making the LHS address taken which I think could be achieved by passing it the address as argument instead of having a LHS. But let's not go down this route - it will have quite bad behavior on alias analysis and optimization. 
>>>>>>> 
>>>>>>> Okay.
>>>>>>> 
>>>>>>> Qing
>>>>>>>> 
>>>>>>>>> If so, “uninitialized analysis” phase need to be further adjusted to specially handle such IR. 
>>>>>>>>> 
>>>>>>>>> If not, what should we do when the auto var is address taken?
>>>> 
>>>> 
>>> 
>>> -- 
>>> 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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-16  7:40     ` Richard Biener
@ 2021-08-16 15:45       ` Qing Zhao
  2021-08-17  8:29         ` Richard Biener
  2021-08-16 19:49       ` Qing Zhao
  1 sibling, 1 reply; 60+ messages in thread
From: Qing Zhao @ 2021-08-16 15:45 UTC (permalink / raw)
  To: Richard Biener
  Cc: Martin Jambor, Jakub Jelinek, Kees Cook,
	Nick Alcock via Gcc-patches, Richard Biener



> On Aug 16, 2021, at 2:40 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Thu, 12 Aug 2021, Qing Zhao wrote:
> 
>> Hi, Richard,
>> 
>> For RTL expansion of call to .DEFERRED_INIT, I changed my code per your suggestions like following:
>> 
>> ======================
>> #define INIT_PATTERN_VALUE  0xFE
>> static void
>> expand_DEFERRED_INIT (internal_fn, gcall *stmt)
>> {
>>  tree lhs = gimple_call_lhs (stmt);
>>  tree var_size = gimple_call_arg (stmt, 0);
>>  enum auto_init_type init_type
>>    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
>>  bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
>> 
>>  tree var_type = TREE_TYPE (lhs);
>>  gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>> 
>>  if (is_vla || (!can_native_interpret_type_p (var_type)))
>>    {
>>    /* If this is a VLA or the type of the variable cannot be natively
>>       interpreted, expand to a memset to initialize it.  */
>>      if (TREE_CODE (lhs) == SSA_NAME)
>>        lhs = SSA_NAME_VAR (lhs);
>>      tree var_addr = NULL_TREE;
>>      if (is_vla)
>>        var_addr = TREE_OPERAND (lhs, 0);
>>      else
>>        {
>>         TREE_ADDRESSABLE (lhs) = 1;
>>         var_addr = build_fold_addr_expr (lhs);
>>        }
>>      tree value = (init_type == AUTO_INIT_PATTERN) ?
>>                    build_int_cst (unsigned_char_type_node,
>>                                   INIT_PATTERN_VALUE) :
>>                    build_zero_cst (unsigned_char_type_node);
>>      tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
>>                                     3, var_addr, value, var_size);
>>      /* Expand this memset call.  */
>>      expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
>>    }
>>  else
>>    {
>>    /* If this is not a VLA and the type of the variable can be natively 
>>       interpreted, expand to assignment to generate better code.  */
>>      tree pattern = NULL_TREE;
>>      unsigned HOST_WIDE_INT total_bytes
>>        = tree_to_uhwi (TYPE_SIZE_UNIT (var_type));
>> 
>>      if (init_type == AUTO_INIT_PATTERN)
>>        {
>>          unsigned char *buf = (unsigned char *) xmalloc (total_bytes);
>>          memset (buf, INIT_PATTERN_VALUE, total_bytes);
>>          pattern = native_interpret_expr (var_type, buf, total_bytes);
>>          gcc_assert (pattern);
>>        }
>> 
>>      tree init = (init_type == AUTO_INIT_PATTERN) ?
>>                   pattern :
>>                   build_zero_cst (var_type);
>>      expand_assignment (lhs, init, false);
>>    }
>> }
>> ===========================
>> 
>> Now, I used “can_native_interpret_type_p (var_type)” instead of “use_register_for_decl (lhs)” to decide 
>> whether to use “memset” or use “assign” to expand this function.
>> 
>> However, this exposed an bug that is very hard to be addressed:
>> 
>> *******For the testing case: test suite/gcc.dg/uninit-I.c:
>> 
>> /* { dg-do compile } */
>> /* { dg-options "-O2 -Wuninitialized" } */
>> 
>> int sys_msgctl (void)
>> {
>>  struct { int mode; } setbuf;
>>  return setbuf.mode;  /* { dg-warning "'setbuf\.mode' is used" } */
>> ==
>> 
>> ******the above auto var “setbuf” has “struct” type, which “can_native_interpret_type_p(var_type)” is false, therefore, 
>> Expanding this .DEFERRED_INIT call went down the “memset” expansion route. 
>> 
>> However, this structure type can be fitted into a register, therefore cannot be taken address anymore at this stage, even though I tried:
>> 
>>         TREE_ADDRESSABLE (lhs) = 1;
>>         var_addr = build_fold_addr_expr (lhs);
>> 
>> To create an address variable for it, the expansion still failed at expr.c: line 8412:
>> during RTL pass: expand
>> /home/opc/Work/GCC/latest-gcc/gcc/testsuite/gcc.dg/auto-init-uninit-I.c:6:24: internal compiler error: in expand_expr_addr_expr_1, at expr.c:8412
>> 0xd04104 expand_expr_addr_expr_1
>> 	../../latest-gcc/gcc/expr.c:8412
>> 0xd04a95 expand_expr_addr_expr
>> 	../../latest-gcc/gcc/expr.c:8525
>> 0xd13592 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
>> 	../../latest-gcc/gcc/expr.c:11741
>> 0xd05142 expand_expr_real(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
>> 	../../latest-gcc/gcc/expr.c:8713
>> 0xaed1d3 expand_expr
>> 	../../latest-gcc/gcc/expr.h:301
>> 0xaf0d89 get_memory_rtx
>> 	../../latest-gcc/gcc/builtins.c:1370
>> 0xafb4fb expand_builtin_memset_args
>> 	../../latest-gcc/gcc/builtins.c:4102
>> 0xafacde expand_builtin_memset(tree_node*, rtx_def*, machine_mode)
>> 	../../latest-gcc/gcc/builtins.c:3886
>> 0xe97fb3 expand_DEFERRED_INIT
>> 
>> ******That’s the major reason why I chose “use_register_for_decl(lhs)” to decide “memset” expansion or “assign” expansion, “memset” expansion
>> needs to take address of the variable, if the variable has been decided to fit into a register, then its address cannot taken anymore at this stage.
>> 
>> ******using “can_native_interpret_type_p” did make the “pattern” generation part much  cleaner and simpler, however, looks like it didn’t work correctly.
>> 
>> Based on this, I’d like to keep my previous implementation by using “use_register_for_decl” to decide whether to take “memset” expansion or “assign” expansion.
>> Therefore, I might still need to keep the “UGLY”  implementation of generatting “pattern” constant for different types?
>> 
>> Let me know your opinion on this.
> 
> Hmm, I think you can use use_register_for_decl(lhs) to decide to use an
> alternate type to generate the pattern (and feed to 
> can_native_interpret_type_p) by using
> lang_hooks.type_for_mode (TYPE_MODE (TREE_TYPE (lhs))).  You can then
> build the assignment from the pattern as
> 
> VIEW_CONVERT <reg-type> (lhs) = pattern_cst;
> 
> note that more RTL-expand-ish would be to simply expand 'lhs' and
> see whether it's a REG_P or a MEM_P and decide based on that.  Of course
> that no longer allows you to use the high-level expand_assignment
> or memset but you'd need to work on a lower level then.
> 
> Richard.


My current code for expand_DEFERRED_INIT is like the following, could you check and see whether there is any issue for it:

#define INIT_PATTERN_VALUE  0xFE
static void
expand_DEFERRED_INIT (internal_fn, gcall *stmt)
{
  tree lhs = gimple_call_lhs (stmt);
  tree var_size = gimple_call_arg (stmt, 0);
  enum auto_init_type init_type
    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
  bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));

  tree var_type = TREE_TYPE (lhs);
  gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);

  if (is_vla || (!use_register_for_decl (lhs)))
    {
      if (TREE_CODE (lhs) == SSA_NAME)
        lhs = SSA_NAME_VAR (lhs);
    /* If this is a VLA or the variable is not in register,
       expand to a memset to initialize it.  */
      tree var_addr = NULL_TREE;
      if (is_vla)
        var_addr = TREE_OPERAND (lhs, 0);
      else
        {
          TREE_ADDRESSABLE (lhs) = 1;
          var_addr = build_fold_addr_expr (lhs);
        }

      tree value = (init_type == AUTO_INIT_PATTERN) ?
                    build_int_cst (unsigned_char_type_node,
                                   INIT_PATTERN_VALUE) :
                    build_zero_cst (unsigned_char_type_node);
      tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
                                     3, var_addr, value, var_size);
      /* Expand this memset call.  */
      expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
    }
  else
    {
    /* If this variable is in a register, use expand_assignment might
       generate better code.  */
      tree pattern = NULL_TREE;
      unsigned HOST_WIDE_INT total_bytes
        = tree_to_uhwi (TYPE_SIZE_UNIT (var_type));

      if (init_type == AUTO_INIT_PATTERN)
        {
          if (can_native_interpret_type_p (var_type))
            {
              unsigned char *buf = (unsigned char *) xmalloc (total_bytes);
              memset (buf, INIT_PATTERN_VALUE, total_bytes);
              pattern = native_interpret_expr (var_type, buf, total_bytes);
              gcc_assert (pattern);
            }
          else
            {
              tree index_type = build_index_type (size_int (total_bytes - 1));
              tree array_type = build_array_type (unsigned_char_type_node,
                                                  index_type);
              tree element = build_int_cst (unsigned_char_type_node,
                                            INIT_PATTERN_VALUE);
              vec<constructor_elt, va_gc> *elts = NULL;
              for (unsigned int i = 0; i < total_bytes; i++)
                CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, element);
              pattern = build_constructor (array_type, elts);
              pattern = build1 (VIEW_CONVERT_EXPR, var_type, pattern);
            }
        }

      tree init = (init_type == AUTO_INIT_PATTERN) ?
                   pattern :
                   build_zero_cst (var_type);
      expand_assignment (lhs, init, false);
    }
}

Thanks.

Qing




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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-16  7:11                                       ` Richard Biener
@ 2021-08-16 16:48                                         ` Qing Zhao
  2021-08-17 15:04                                           ` Qing Zhao
  0 siblings, 1 reply; 60+ messages in thread
From: Qing Zhao @ 2021-08-16 16:48 UTC (permalink / raw)
  To: Richard Biener
  Cc: Richard Sandiford, Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook



> On Aug 16, 2021, at 2:11 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Wed, 11 Aug 2021, Qing Zhao wrote:
> 
>> Hi, 
>> 
>> I met another issue for “address taken” auto variable, see below for details:
>> 
>> **** the testing case: (gcc/testsuite/gcc.dg/uninit-16.c)
>> 
>> 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;
>> }
>> 
>> ****When compiled with -ftrivial-auto-var-init=zero -O2 -Wuninitialized -fdump-tree-all:
>> 
>> .*************gimple dump:
>> 
>> void testfunc ()
>> { 
>>  int alt_reloc;
>> 
>>  try
>>    {
>>      _1 = .DEFERRED_INIT (4, 2, 0);
>>      alt_reloc = _1;
>>      foo.0_2 = foo;
>>      decode_reloc (foo.0_2, &alt_reloc);
>>      alt_reloc.1_3 = alt_reloc;
>>      if (alt_reloc.1_3 != 0) goto <D.1952>; else goto <D.1953>;
>>      <D.1952>:
>>      bar = 42;
>>      <D.1953>:
>>    }
>>  finally
>>    {
>>      alt_reloc = {CLOBBER};
>>    }
>> }
>> 
>> **************fre1 dump:
>> 
>> void testfunc ()
>> {
>>  int alt_reloc;
>>  int _1;
>>  int foo.0_2;
>> 
>>  <bb 2> :
>>  _1 = .DEFERRED_INIT (4, 2, 0);
>>  foo.0_2 = foo;
>>  if (foo.0_2 > 19)
>>    goto <bb 3>; [50.00%]
>>  else
>>    goto <bb 4>; [50.00%]
>> 
>>  <bb 3> :
>>  goto <bb 7>; [100.00%]
>> 
>>  <bb 4> :
>>  if (foo.0_2 > 9)
>>    goto <bb 5>; [50.00%]
>>  else
>>    goto <bb 6>; [50.00%]
>> 
>>  <bb 5> :
>>  goto <bb 8>; [100.00%]
>> 
>>  <bb 6> :
>>  if (_1 != 0)
>>    goto <bb 7>; [INV]
>>  else
>>    goto <bb 8>; [INV]
>> 
>>  <bb 7> :
>>  bar = 42;
>> 
>>  <bb 8> :
>>  return;
>> 
>> }
>> 
>> From the above IR file after “FRE”, we can see that the major issue with this IR is:
>> 
>> The address taken auto variable “alt_reloc” has been completely replaced by the temporary variable “_1” in all
>> the uses of the original “alt_reloc”. 
> 
> Well, this can happen with regular code as well, there's no need for
> .DEFERRED_INIT.  This is the usual problem with reporting uninitialized
> uses late.
> 
> IMHO this shouldn't be a blocker.  The goal of zero "regressions" wrt
> -Wuninitialized isn't really achievable.

Okay. Sounds reasonable to me too.

> 
>> The major problem with such IR is,  during uninitialized analysis phase, the original use of “alt_reloc” disappeared completely.
>> So, the warning cannot be reported.
>> 
>> 
>> My questions:
>> 
>> 1. Is it possible to get the original “alt_reloc” through the temporary variable “_1” with some available information recorded in the IR?
>> 2. If not, then we have to record the relationship between “alt_reloc” and “_1” when the original “alt_reloc” is replaced by “_1” and get such relationship during
>>    Uninitialized analysis phase.  Is this doable?
> 
> Well, you could add a fake argument to .DEFERRED_INIT for the purpose of
> diagnostics.  The difficulty is to avoid tracking it as actual use so
> you could for example pass a string with the declarations name though
> this wouldn't give the association with the actual decl.
Good suggestion, I can try this a little bit. 

> 
>> 3. Looks like that for “address taken” auto variable, if we have to introduce a new temporary variable and split the call to .DEFERRED_INIT into two:
>> 
>>      temp = .DEFERRED_INIT (4, 2, 0);
>>      alt_reloc = temp;
>> 
>>   More issues might possible.
>> 
>> Any comments and suggestions on this issue?
> 
> I don't see any good possibilities that would not make optimizing code
> as good as w/o .DEFERRED_INIT more difficult.  My stake here is always
> that GCC is an optimizing compiler, not a static analysis engine and
> thus I side with "broken" diagnostics and better optimization.
That’s true and reasonable, too.

thanks.

Qing
> 
> Richard.
> 
>> Qing
>> 
>> j
>>> On Aug 11, 2021, at 11:55 AM, Richard Biener <rguenther@suse.de> wrote:
>>> 
>>> On August 11, 2021 6:22:00 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>>>> 
>>>> 
>>>>> On Aug 11, 2021, at 10:53 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>> 
>>>>> On August 11, 2021 5:30:40 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>>>>>> I modified the routine “gimple_add_init_for_auto_var” as the following:
>>>>>> ====
>>>>>> /* Generate initialization to automatic variable DECL based on INIT_TYPE.
>>>>>> Build a call to internal const function DEFERRED_INIT:
>>>>>> 1st argument: SIZE of the DECL;
>>>>>> 2nd argument: INIT_TYPE;
>>>>>> 3rd argument: IS_VLA, 0 NO, 1 YES;
>>>>>> 
>>>>>> as DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA).  */
>>>>>> static void
>>>>>> gimple_add_init_for_auto_var (tree decl,
>>>>>>                           enum auto_init_type init_type,
>>>>>>                           bool is_vla,
>>>>>>                           gimple_seq *seq_p)
>>>>>> {
>>>>>> gcc_assert (VAR_P (decl) && !DECL_EXTERNAL (decl) && !TREE_STATIC (decl));
>>>>>> gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>>>>>> tree decl_size = TYPE_SIZE_UNIT (TREE_TYPE (decl));
>>>>>> 
>>>>>> tree init_type_node
>>>>>> = build_int_cst (integer_type_node, (int) init_type);
>>>>>> tree is_vla_node
>>>>>> = build_int_cst (integer_type_node, (int) is_vla);
>>>>>> 
>>>>>> tree call = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
>>>>>>                                         TREE_TYPE (decl), 3,
>>>>>>                                         decl_size, init_type_node,
>>>>>>                                         is_vla_node);
>>>>>> 
>>>>>> /* If this DECL is a VLA, a temporary address variable for it has been
>>>>>>  created, the replacement for DECL is recorded in DECL_VALUE_EXPR (decl),
>>>>>>  we should use it as the LHS of the call.  */
>>>>>> 
>>>>>> tree lhs_call
>>>>>> = is_vla ? DECL_VALUE_EXPR (decl) : decl;
>>>>>> gimplify_assign (lhs_call, call, seq_p);
>>>>>> }
>>>>>> 
>>>>>> With this change, the current issue is resolved, the gimple dump now is:
>>>>>> 
>>>>>> (*arr.1) = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>> 
>>>>>> However, there is another new issue:
>>>>>> 
>>>>>> For the following testing case:
>>>>>> 
>>>>>> ======
>>>>>> [opc@qinzhao-ol8u3-x86 gcc]$ cat t.c
>>>>>> int bar;
>>>>>> 
>>>>>> extern void decode_reloc(int *);
>>>>>> 
>>>>>> void testfunc()
>>>>>> {
>>>>>> int alt_reloc;
>>>>>> 
>>>>>> decode_reloc(&alt_reloc);
>>>>>> 
>>>>>> if (alt_reloc) /* { dg-warning "may be used uninitialized" } */
>>>>>> bar = 42; 
>>>>>> }
>>>>>> =====
>>>>>> 
>>>>>> In the above, the auto var “alt_reloc” is address taken, then the gimple dump for it when compiled with -ftrivial-auto-var-init=zero is:
>>>>>> 
>>>>>> void testfunc ()
>>>>>> {
>>>>>> int alt_reloc;
>>>>>> 
>>>>>> try
>>>>>> {
>>>>>>   _1 = .DEFERRED_INIT (4, 2, 0);
>>>>>>   alt_reloc = _1;
>>>>>>   decode_reloc (&alt_reloc);
>>>>>>   alt_reloc.0_2 = alt_reloc;
>>>>>>   if (alt_reloc.0_2 != 0) goto <D.1949>; else goto <D.1950>;
>>>>>>   <D.1949>:
>>>>>>   bar = 42;
>>>>>>   <D.1950>:
>>>>>> }
>>>>>> finally
>>>>>> {
>>>>>>   alt_reloc = {CLOBBER};
>>>>>> }
>>>>>> }
>>>>>> 
>>>>>> I.e, instead of the expected IR:
>>>>>> 
>>>>>> alt_reloc = .DEFERRED_INIT (4, 2, 0);
>>>>>> 
>>>>>> We got the following:
>>>>>> 
>>>>>> _1 = .DEFERRED_INIT (4, 2, 0);
>>>>>>   alt_reloc = _1;
>>>>>> 
>>>>>> I guess the temp “_1” is created because “alt_reloc” is address taken. 
>>>>> 
>>>>> Yes and no. The reason is that alt_reloc is memory (because it is address taken) and that GIMPLE says that register typed stores need to use a is_gimple_val RHS which the call is not.
>>>> 
>>>> Okay.
>>>>> 
>>>>>> My questions:
>>>>>> 
>>>>>> Shall we accept such IR for .DEFERRED_INIT purpose when the auto var is address taken? 
>>>>> 
>>>>> I think so. Note it doesn't necessarily need address taking but any other reason that prevents SSA rewriting the variable suffices. 
>>>> 
>>>> You mean, in addition to “address taken”, there are other situations that will introduce such IR:
>>>> 
>>>> temp = .DEFERRED_INIT();
>>>> auto_var = temp;
>>>> 
>>>> So, such IR is unavoidable and we have to handle it?
>>> 
>>> Yes. 
>>> 
>>>> If we have to handle it,  what’ the best way to do it?
>>>> 
>>>> The solution in my mind is:
>>>> 1. During uninitialized analysis phase, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then decide that “auto_var” is uninitialized.
>>> 
>>> Yes. Basically if there's an artificial variable auto initialized you have to look at its uses. 
>>> 
>>>> 2. During RTL expansion, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then delete “temp”, and then expand .DEFERRED_INIT to auto_var.
>>> 
>>> That shouldn't be necessary. You'd initialize a temporary register which is then copied to the real variable. That's good enough and should be optimized by the RTL pipeline. 
>>> 
>>>> Let me know your comments and suggestions on this.
>>>> 
>>>> 
>>>>> 
>>>>> The only other option is to force. DEFERED_INIT making the LHS address taken which I think could be achieved by passing it the address as argument instead of having a LHS. But let's not go down this route - it will have quite bad behavior on alias analysis and optimization. 
>>>> 
>>>> Okay.
>>>> 
>>>> Qing
>>>>> 
>>>>>> If so, “uninitialized analysis” phase need to be further adjusted to specially handle such IR. 
>>>>>> 
>>>>>> If not, what should we do when the auto var is address taken?
>>>>>> 
>>>>>> Thanks a lot.
>>>>>> 
>>>>>> Qing
>>>>>> 
>>>>>> 
>>>>>>> On Aug 11, 2021, at 8:58 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>> 
>>>>>>> On Wed, 11 Aug 2021, Qing Zhao wrote:
>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>>> On Aug 11, 2021, at 8:37 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>>>> 
>>>>>>>>> On Wed, 11 Aug 2021, Qing Zhao wrote:
>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>>>> On Aug 11, 2021, at 2:02 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>>>>>> 
>>>>>>>>>>> On Tue, 10 Aug 2021, Qing Zhao wrote:
>>>>>>>>>>> 
>>>>>>>>>>>> 
>>>>>>>>>>>> 
>>>>>>>>>>>>> On Aug 10, 2021, at 3:16 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>>>>>>>>>>>> 
>>>>>>>>>>>>> Hi, Richard,
>>>>>>>>>>>>> 
>>>>>>>>>>>>>> On Aug 10, 2021, at 10:22 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>>> Especially in the VLA case but likely also in general (though unlikely
>>>>>>>>>>>>>>>> since usually the receiver of initializations are simple enough).  I'd
>>>>>>>>>>>>>>>> expect the VLA case end up as
>>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>>> *ptr_to_decl = .DEFERRED_INIT (...);
>>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>>> where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.
>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>> So, for the following small testing case:
>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>> ====
>>>>>>>>>>>>>>> extern void bar (int);
>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>> void foo(int n)
>>>>>>>>>>>>>>> {
>>>>>>>>>>>>>>> int arr[n];
>>>>>>>>>>>>>>> bar (arr[2]);
>>>>>>>>>>>>>>> return;
>>>>>>>>>>>>>>> }
>>>>>>>>>>>>>>> =====
>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>> If I compile it with -ftrivial-auto-var-init=zero -fdump-tree-gimple -S -o auto-init-11.s -fdump-rtl-expand, the *.gimple dump is:
>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>> =====
>>>>>>>>>>>>>>> void foo (int n)
>>>>>>>>>>>>>>> {
>>>>>>>>>>>>>>> int n.0;
>>>>>>>>>>>>>>> sizetype D.1950;
>>>>>>>>>>>>>>> bitsizetype D.1951;
>>>>>>>>>>>>>>> sizetype D.1952;
>>>>>>>>>>>>>>> bitsizetype D.1953;
>>>>>>>>>>>>>>> sizetype D.1954;
>>>>>>>>>>>>>>> int[0:D.1950] * arr.1;
>>>>>>>>>>>>>>> void * saved_stack.2;
>>>>>>>>>>>>>>> int arr[0:D.1950] [value-expr: *arr.1];
>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>> saved_stack.2 = __builtin_stack_save ();
>>>>>>>>>>>>>>> try
>>>>>>>>>>>>>>> {
>>>>>>>>>>>>>>> n.0 = n;
>>>>>>>>>>>>>>> _1 = (long int) n.0;
>>>>>>>>>>>>>>> _2 = _1 + -1;
>>>>>>>>>>>>>>> _3 = (sizetype) _2;
>>>>>>>>>>>>>>> D.1950 = _3;
>>>>>>>>>>>>>>> _4 = (sizetype) n.0;
>>>>>>>>>>>>>>> _5 = (bitsizetype) _4;
>>>>>>>>>>>>>>> _6 = _5 * 32;
>>>>>>>>>>>>>>> D.1951 = _6;
>>>>>>>>>>>>>>> _7 = (sizetype) n.0;
>>>>>>>>>>>>>>> _8 = _7 * 4;
>>>>>>>>>>>>>>> D.1952 = _8;
>>>>>>>>>>>>>>> _9 = (sizetype) n.0;
>>>>>>>>>>>>>>> _10 = (bitsizetype) _9;
>>>>>>>>>>>>>>> _11 = _10 * 32;
>>>>>>>>>>>>>>> D.1953 = _11;
>>>>>>>>>>>>>>> _12 = (sizetype) n.0;
>>>>>>>>>>>>>>> _13 = _12 * 4;
>>>>>>>>>>>>>>> D.1954 = _13;
>>>>>>>>>>>>>>> arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>>>>>>>>>>>> arr = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>>>>>>>>> _14 = (*arr.1)[2];
>>>>>>>>>>>>>>> bar (_14);
>>>>>>>>>>>>>>> return;
>>>>>>>>>>>>>>> }
>>>>>>>>>>>>>>> finally
>>>>>>>>>>>>>>> {
>>>>>>>>>>>>>>> __builtin_stack_restore (saved_stack.2);
>>>>>>>>>>>>>>> }
>>>>>>>>>>>>>>> }
>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>> ====
>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>> You think that the above .DEFEERED_INIT is not correct?
>>>>>>>>>>>>>>> It should be:
>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952. 2, 1);
>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>> ?
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> Yes.
>>>>>>>>>>>>>> 
>>>>>>>>>>>>> 
>>>>>>>>>>>>> I updated gimplify.c for VLA and now it emits the call to .DEFERRED_INIT as:
>>>>>>>>>>>>> 
>>>>>>>>>>>>> arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>>>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>>>>>>> 
>>>>>>>>>>>>> However, this call triggered the assertion failure in verify_gimple_call of tree-cfg.c because the LHS is not a valid LHS. 
>>>>>>>>>>>>> Then I modify tree-cfg.c as:
>>>>>>>>>>>>> 
>>>>>>>>>>>>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
>>>>>>>>>>>>> index 330eb7dd89bf..180d4f1f9e32 100644
>>>>>>>>>>>>> --- a/gcc/tree-cfg.c
>>>>>>>>>>>>> +++ b/gcc/tree-cfg.c
>>>>>>>>>>>>> @@ -3375,7 +3375,11 @@ verify_gimple_call (gcall *stmt)
>>>>>>>>>>>>> }
>>>>>>>>>>>>> 
>>>>>>>>>>>>> tree lhs = gimple_call_lhs (stmt);
>>>>>>>>>>>>> +  /* For .DEFERRED_INIT call, the LHS might be an indirection of
>>>>>>>>>>>>> +     a pointer for the VLA variable, which is not a valid LHS of
>>>>>>>>>>>>> +     a gimple call, we ignore the asssertion on this.  */ 
>>>>>>>>>>>>> if (lhs
>>>>>>>>>>>>> +      && (!gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
>>>>>>>>>>>>> && (!is_gimple_reg (lhs)
>>>>>>>>>>>>>    && (!is_gimple_lvalue (lhs)
>>>>>>>>>>>>>        || verify_types_in_gimple_reference
>>>>>>>>>>>>> 
>>>>>>>>>>>>> The assertion failure in tree-cfg.c got resolved, but I got another assertion failure in operands_scanner::get_expr_operands (tree *expr_p, int flags), line 945:
>>>>>>>>>>>>> 
>>>>>>>>>>>>> 939   /* If we get here, something has gone wrong.  */
>>>>>>>>>>>>> 940   if (flag_checking)
>>>>>>>>>>>>> 941     {
>>>>>>>>>>>>> 942       fprintf (stderr, "unhandled expression in get_expr_operands():\n");
>>>>>>>>>>>>> 943       debug_tree (expr);
>>>>>>>>>>>>> 944       fputs ("\n", stderr);
>>>>>>>>>>>>> 945       gcc_unreachable ();
>>>>>>>>>>>>> 946     }
>>>>>>>>>>>>> 
>>>>>>>>>>>>> Looks like that  the gimple statement:
>>>>>>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>>>>>>> 
>>>>>>>>>>>>> Is not valid.  i.e, the LHS should not be an indirection to a pointer. 
>>>>>>>>>>>>> 
>>>>>>>>>>>>> How to resolve this issue?
>>>>>>>>>>> 
>>>>>>>>>>> It sounds like the LHS is an INDIRECT_REF maybe?  That means it's
>>>>>>>>>>> still not properly gimplified because it should end up as a MEM_REF
>>>>>>>>>>> instead.
>>>>>>>>>>> 
>>>>>>>>>>> But I'm just guessing here ... if you are in a debugger then you can
>>>>>>>>>>> invoke debug_tree (lhs) in the inferior to see what it exactly is
>>>>>>>>>>> at the point of the failure.
>>>>>>>>>> 
>>>>>>>>>> Yes, it’s an INDIRECT_REF at the point of the failure even though I added a 
>>>>>>>>>> 
>>>>>>>>>> gimplify_var_or_parm_decl  (lhs) 
>>>>>>>>> 
>>>>>>>>> I think the easiest is to build the .DEFERRED_INIT as GENERIC
>>>>>>>>> and use gimplify_assign () to gimplify and add the result
>>>>>>>>> to the sequence.  Thus, build a GENERIC CALL_EXPR and then
>>>>>>>>> gimplify_assign (lhs, call_expr, seq);
>>>>>>>> 
>>>>>>>> Which utility routine is used to build an Internal generic call?
>>>>>>>> Currently, I used “gimple_build_call_internal” to build this internal gimple call.
>>>>>>>> 
>>>>>>>> For the generic call, shall I use “build_call_expr_loc” ? 
>>>>>>> 
>>>>>>> For example look at build_asan_poison_call_expr which does such thing
>>>>>>> for ASAN poison internal function call insertion at gimplification time.
>>>>>>> 
>>>>>>> Richard.
>>>>>>> 
>>>>>>>> Qing
>>>>>>>> 
>>>>>>>>> 
>>>>>>>>> Richard.
>>>>>>>>> 
>>>>>>>>>> Qing
>>>>>>>>>> 
>>>>>>>>>>> 
>>>>>>>>>>>> I came up with the following solution:
>>>>>>>>>>>> 
>>>>>>>>>>>> Define the IFN_DEFERRED_INIT function as:
>>>>>>>>>>>> 
>>>>>>>>>>>> LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA);
>>>>>>>>>>>> 
>>>>>>>>>>>> if IS_VLA is false, the LHS is the DECL itself,
>>>>>>>>>>>> if IS_VLA is true, the LHS is the pointer to this DECL that created by
>>>>>>>>>>>> gimplify_vla_decl.
>>>>>>>>>>>> 
>>>>>>>>>>>> 
>>>>>>>>>>>> The benefit of this solution are:
>>>>>>>>>>>> 
>>>>>>>>>>>> 1. Resolved the invalid IR issue;
>>>>>>>>>>>> 2. The call stmt carries the address of the VLA natually;
>>>>>>>>>>>> 
>>>>>>>>>>>> The issue with this solution is:
>>>>>>>>>>>> 
>>>>>>>>>>>> For VLA and non-VLA, the LHS will be different, 
>>>>>>>>>>>> 
>>>>>>>>>>>> Do you see any other potential issues with this solution?
>>>>>>>>>>>> 
>>>>>>>>>>>> thanks.
>>>>>>>>>>>> 
>>>>>>>>>>>> Qing
>>>>>>>>>>>> 
>>>>>>>>>>>> 
>>>>>>>>>>>> 
>>>>>>>>>>>> 
>>>>>>>>>>>> 
>>>>>>>>>>> 
>>>>>>>>>>> -- 
>>>>>>>>>>> Richard Biener <rguenther@suse.de>
>>>>>>>>>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>>>>>>>>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>> 
>>>>>>>>> -- 
>>>>>>>>> Richard Biener <rguenther@suse.de>
>>>>>>>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>>>>>>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>>>>>>>> 
>>>>>>>> 
>>>>>>> 
>>>>>>> -- 
>>>>>>> Richard Biener <rguenther@suse.de>
>>>>>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>>>>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>> 
>> 
> 
> -- 
> 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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-16  7:40     ` Richard Biener
  2021-08-16 15:45       ` Qing Zhao
@ 2021-08-16 19:49       ` Qing Zhao
  2021-08-17  8:43         ` Richard Biener
  1 sibling, 1 reply; 60+ messages in thread
From: Qing Zhao @ 2021-08-16 19:49 UTC (permalink / raw)
  To: Richard Biener
  Cc: Martin Jambor, Jakub Jelinek, Kees Cook,
	Nick Alcock via Gcc-patches, Richard Biener



> On Aug 16, 2021, at 2:40 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Thu, 12 Aug 2021, Qing Zhao wrote:
> 
>> Hi, Richard,
>> 
>> For RTL expansion of call to .DEFERRED_INIT, I changed my code per your suggestions like following:
>> 
>> ======================
>> #define INIT_PATTERN_VALUE  0xFE
>> static void
>> expand_DEFERRED_INIT (internal_fn, gcall *stmt)
>> {
>>  tree lhs = gimple_call_lhs (stmt);
>>  tree var_size = gimple_call_arg (stmt, 0);
>>  enum auto_init_type init_type
>>    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
>>  bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
>> 
>>  tree var_type = TREE_TYPE (lhs);
>>  gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>> 
>>  if (is_vla || (!can_native_interpret_type_p (var_type)))
>>    {
>>    /* If this is a VLA or the type of the variable cannot be natively
>>       interpreted, expand to a memset to initialize it.  */
>>      if (TREE_CODE (lhs) == SSA_NAME)
>>        lhs = SSA_NAME_VAR (lhs);
>>      tree var_addr = NULL_TREE;
>>      if (is_vla)
>>        var_addr = TREE_OPERAND (lhs, 0);
>>      else
>>        {
>>         TREE_ADDRESSABLE (lhs) = 1;
>>         var_addr = build_fold_addr_expr (lhs);
>>        }
>>      tree value = (init_type == AUTO_INIT_PATTERN) ?
>>                    build_int_cst (unsigned_char_type_node,
>>                                   INIT_PATTERN_VALUE) :
>>                    build_zero_cst (unsigned_char_type_node);
>>      tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
>>                                     3, var_addr, value, var_size);
>>      /* Expand this memset call.  */
>>      expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
>>    }
>>  else
>>    {
>>    /* If this is not a VLA and the type of the variable can be natively 
>>       interpreted, expand to assignment to generate better code.  */
>>      tree pattern = NULL_TREE;
>>      unsigned HOST_WIDE_INT total_bytes
>>        = tree_to_uhwi (TYPE_SIZE_UNIT (var_type));
>> 
>>      if (init_type == AUTO_INIT_PATTERN)
>>        {
>>          unsigned char *buf = (unsigned char *) xmalloc (total_bytes);
>>          memset (buf, INIT_PATTERN_VALUE, total_bytes);
>>          pattern = native_interpret_expr (var_type, buf, total_bytes);
>>          gcc_assert (pattern);
>>        }
>> 
>>      tree init = (init_type == AUTO_INIT_PATTERN) ?
>>                   pattern :
>>                   build_zero_cst (var_type);
>>      expand_assignment (lhs, init, false);
>>    }
>> }
>> ===========================
>> 
>> Now, I used “can_native_interpret_type_p (var_type)” instead of “use_register_for_decl (lhs)” to decide 
>> whether to use “memset” or use “assign” to expand this function.
>> 
>> However, this exposed an bug that is very hard to be addressed:
>> 
>> *******For the testing case: test suite/gcc.dg/uninit-I.c:
>> 
>> /* { dg-do compile } */
>> /* { dg-options "-O2 -Wuninitialized" } */
>> 
>> int sys_msgctl (void)
>> {
>>  struct { int mode; } setbuf;
>>  return setbuf.mode;  /* { dg-warning "'setbuf\.mode' is used" } */
>> ==
>> 
>> ******the above auto var “setbuf” has “struct” type, which “can_native_interpret_type_p(var_type)” is false, therefore, 
>> Expanding this .DEFERRED_INIT call went down the “memset” expansion route. 
>> 
>> However, this structure type can be fitted into a register, therefore cannot be taken address anymore at this stage, even though I tried:
>> 
>>         TREE_ADDRESSABLE (lhs) = 1;
>>         var_addr = build_fold_addr_expr (lhs);
>> 
>> To create an address variable for it, the expansion still failed at expr.c: line 8412:
>> during RTL pass: expand
>> /home/opc/Work/GCC/latest-gcc/gcc/testsuite/gcc.dg/auto-init-uninit-I.c:6:24: internal compiler error: in expand_expr_addr_expr_1, at expr.c:8412
>> 0xd04104 expand_expr_addr_expr_1
>> 	../../latest-gcc/gcc/expr.c:8412
>> 0xd04a95 expand_expr_addr_expr
>> 	../../latest-gcc/gcc/expr.c:8525
>> 0xd13592 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
>> 	../../latest-gcc/gcc/expr.c:11741
>> 0xd05142 expand_expr_real(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
>> 	../../latest-gcc/gcc/expr.c:8713
>> 0xaed1d3 expand_expr
>> 	../../latest-gcc/gcc/expr.h:301
>> 0xaf0d89 get_memory_rtx
>> 	../../latest-gcc/gcc/builtins.c:1370
>> 0xafb4fb expand_builtin_memset_args
>> 	../../latest-gcc/gcc/builtins.c:4102
>> 0xafacde expand_builtin_memset(tree_node*, rtx_def*, machine_mode)
>> 	../../latest-gcc/gcc/builtins.c:3886
>> 0xe97fb3 expand_DEFERRED_INIT
>> 
>> ******That’s the major reason why I chose “use_register_for_decl(lhs)” to decide “memset” expansion or “assign” expansion, “memset” expansion
>> needs to take address of the variable, if the variable has been decided to fit into a register, then its address cannot taken anymore at this stage.
>> 
>> ******using “can_native_interpret_type_p” did make the “pattern” generation part much  cleaner and simpler, however, looks like it didn’t work correctly.
>> 
>> Based on this, I’d like to keep my previous implementation by using “use_register_for_decl” to decide whether to take “memset” expansion or “assign” expansion.
>> Therefore, I might still need to keep the “UGLY”  implementation of generatting “pattern” constant for different types?
>> 
>> Let me know your opinion on this.
> 
> Hmm, I think you can use use_register_for_decl(lhs) to decide to use an
> alternate type to generate the pattern (and feed to 
> can_native_interpret_type_p) by using
> lang_hooks.type_for_mode (TYPE_MODE (TREE_TYPE (lhs))).

Do you mean that the TYPE returned by “lang_hooks.type_for_mode(TYPE_MODE (TREE_TYPE (lhs))” will always satisfy “can_native_interpret_type_p”? 
Even for big structure types?

i.e, 

tree var_type = TREE_TYPE(lhs);
tree pattern = NULL_TREE;
unsigned HOST_WIDE_INT total_bytes
        = tree_to_uhwi (TYPE_SIZE_UNIT (var_type));

If (use_register_for_decl(lhs)==false)
  {
    tree alt_type = lang_hooks.type_for_mode(TYPE_MODE(var_type), TYPE_UNSIGNED(var_type);
    If (can_native_interpret_type_p (alt_type))
      {
	unsigned char *buf = (unsigned char *) xmalloc (total_bytes); 
	memset (buf, INIT_PATTERN_VALUE, total_bytes); 
	pattern = native_interpret_expr (alt_type, buf, total_bytes); 
	gcc_assert (pattern); 
      }
    else
      gcc_unreachable ();
  }

?
Don’t quite understand here. Please clarify.

>  You can then
> build the assignment from the pattern as
> 
> VIEW_CONVERT <reg-type> (lhs) = pattern_cst;

What’s the <reg_type> in the above? The type “alt_type” returned by “lang_hooks.type_for_mode(TREE_TYPE(lhs))?
Do I need to build “MODIFY_EXPR” for the above? 

lhs =  build1 (VIEW_CONVERT_EXPR, alt_type, lhs);
tree  final = build2 (MODIFY_EXPR, TREE_TYPE (alt_type), lhs, pattern);

Then how to expand this”final"? 
> 
> note that more RTL-expand-ish would be to simply expand 'lhs' and
> see whether it's a REG_P or a MEM_P and decide based on that.

You mean that the current RTL expansion will automatically expand LHS to memset route or assignment route based on whether
LHS is a REG_P or MEM_P? I don’t need to explicitly code for “expand_builtin_memset” or “expand_assign”?

>  Of course
> that no longer allows you to use the high-level expand_assignment
> or memset but you'd need to work on a lower level then.
Don’t understand here, so, I need more coding on the RTL expansing for what part?

Qing

> 
> Richard.
> 


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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-16 15:45       ` Qing Zhao
@ 2021-08-17  8:29         ` Richard Biener
  2021-08-17 14:50           ` Qing Zhao
  0 siblings, 1 reply; 60+ messages in thread
From: Richard Biener @ 2021-08-17  8:29 UTC (permalink / raw)
  To: Qing Zhao
  Cc: Martin Jambor, Jakub Jelinek, Kees Cook,
	Nick Alcock via Gcc-patches, Richard Biener

On Mon, 16 Aug 2021, Qing Zhao wrote:

> My current code for expand_DEFERRED_INIT is like the following, could you check and see whether there is any issue for it:
> 
> #define INIT_PATTERN_VALUE  0xFE
> static void
> expand_DEFERRED_INIT (internal_fn, gcall *stmt)
> {
>   tree lhs = gimple_call_lhs (stmt);
>   tree var_size = gimple_call_arg (stmt, 0);
>   enum auto_init_type init_type
>     = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
>   bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
> 
>   tree var_type = TREE_TYPE (lhs);
>   gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
> 
>   if (is_vla || (!use_register_for_decl (lhs)))
>     {
>       if (TREE_CODE (lhs) == SSA_NAME)
>         lhs = SSA_NAME_VAR (lhs);

this should not be necessary (in fact you shouldn't see a SSA_NAME
here, if you do then using SSA_NAME_VAR is wrong)

>     /* If this is a VLA or the variable is not in register,
>        expand to a memset to initialize it.  */
>       tree var_addr = NULL_TREE;
>       if (is_vla)
>         var_addr = TREE_OPERAND (lhs, 0);
>       else
>         {
>           TREE_ADDRESSABLE (lhs) = 1;
>           var_addr = build_fold_addr_expr (lhs);
>         }

use, independent of is_vla

         mark_addressable (lhs);
         var_addr = build_fold_addr_expr (lhs);

> 
>       tree value = (init_type == AUTO_INIT_PATTERN) ?
>                     build_int_cst (unsigned_char_type_node,
>                                    INIT_PATTERN_VALUE) :
>                     build_zero_cst (unsigned_char_type_node);

since memset has an integer argument for the value use
integer_zero_node for the zero case and build_int_cst (integer_type_node, 
...) for the pattern case

>       tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
>                                      3, var_addr, value, var_size);
>       /* Expand this memset call.  */
>       expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
>     }
>   else
>     {
>     /* If this variable is in a register, use expand_assignment might
>        generate better code.  */
>       tree pattern = NULL_TREE;
>       unsigned HOST_WIDE_INT total_bytes
>         = tree_to_uhwi (TYPE_SIZE_UNIT (var_type));
> 
>       if (init_type == AUTO_INIT_PATTERN)
>         {
>           if (can_native_interpret_type_p (var_type))
>             {
>               unsigned char *buf = (unsigned char *) xmalloc (total_bytes);
>               memset (buf, INIT_PATTERN_VALUE, total_bytes);
>               pattern = native_interpret_expr (var_type, buf, total_bytes);
>               gcc_assert (pattern);
>             }
>           else
>             {
>               tree index_type = build_index_type (size_int (total_bytes - 1));
>               tree array_type = build_array_type (unsigned_char_type_node,
>                                                   index_type);
>               tree element = build_int_cst (unsigned_char_type_node,
>                                             INIT_PATTERN_VALUE);
>               vec<constructor_elt, va_gc> *elts = NULL;
>               for (unsigned int i = 0; i < total_bytes; i++)
>                 CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, element);
>               pattern = build_constructor (array_type, elts);
>               pattern = build1 (VIEW_CONVERT_EXPR, var_type, pattern);
>             }
>         }
> 
>       tree init = (init_type == AUTO_INIT_PATTERN) ?
>                    pattern :
>                    build_zero_cst (var_type);

maybe conditionally initialize init instead of pattern and init?
Thus replace pattern by init and do

        else
          init = build_zero_cst (var_type);


the above should work, as said the RTL expansion part can possibly
be improved but we can do this as followup as well.

>       expand_assignment (lhs, init, false);
>     }
> }
> 
> Thanks.
> 
> Qing
> 
> 
> 
> 

-- 
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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-16 19:49       ` Qing Zhao
@ 2021-08-17  8:43         ` Richard Biener
  2021-08-17 14:03           ` Qing Zhao
  0 siblings, 1 reply; 60+ messages in thread
From: Richard Biener @ 2021-08-17  8:43 UTC (permalink / raw)
  To: Qing Zhao
  Cc: Martin Jambor, Jakub Jelinek, Kees Cook,
	Nick Alcock via Gcc-patches, Richard Biener

On Mon, 16 Aug 2021, Qing Zhao wrote:

> 
> 
> > On Aug 16, 2021, at 2:40 AM, Richard Biener <rguenther@suse.de> wrote:
> > 
> > On Thu, 12 Aug 2021, Qing Zhao wrote:
> > 
> >> Hi, Richard,
> >> 
> >> For RTL expansion of call to .DEFERRED_INIT, I changed my code per your suggestions like following:
> >> 
> >> ======================
> >> #define INIT_PATTERN_VALUE  0xFE
> >> static void
> >> expand_DEFERRED_INIT (internal_fn, gcall *stmt)
> >> {
> >>  tree lhs = gimple_call_lhs (stmt);
> >>  tree var_size = gimple_call_arg (stmt, 0);
> >>  enum auto_init_type init_type
> >>    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
> >>  bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
> >> 
> >>  tree var_type = TREE_TYPE (lhs);
> >>  gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
> >> 
> >>  if (is_vla || (!can_native_interpret_type_p (var_type)))
> >>    {
> >>    /* If this is a VLA or the type of the variable cannot be natively
> >>       interpreted, expand to a memset to initialize it.  */
> >>      if (TREE_CODE (lhs) == SSA_NAME)
> >>        lhs = SSA_NAME_VAR (lhs);
> >>      tree var_addr = NULL_TREE;
> >>      if (is_vla)
> >>        var_addr = TREE_OPERAND (lhs, 0);
> >>      else
> >>        {
> >>         TREE_ADDRESSABLE (lhs) = 1;
> >>         var_addr = build_fold_addr_expr (lhs);
> >>        }
> >>      tree value = (init_type == AUTO_INIT_PATTERN) ?
> >>                    build_int_cst (unsigned_char_type_node,
> >>                                   INIT_PATTERN_VALUE) :
> >>                    build_zero_cst (unsigned_char_type_node);
> >>      tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
> >>                                     3, var_addr, value, var_size);
> >>      /* Expand this memset call.  */
> >>      expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
> >>    }
> >>  else
> >>    {
> >>    /* If this is not a VLA and the type of the variable can be natively 
> >>       interpreted, expand to assignment to generate better code.  */
> >>      tree pattern = NULL_TREE;
> >>      unsigned HOST_WIDE_INT total_bytes
> >>        = tree_to_uhwi (TYPE_SIZE_UNIT (var_type));
> >> 
> >>      if (init_type == AUTO_INIT_PATTERN)
> >>        {
> >>          unsigned char *buf = (unsigned char *) xmalloc (total_bytes);
> >>          memset (buf, INIT_PATTERN_VALUE, total_bytes);
> >>          pattern = native_interpret_expr (var_type, buf, total_bytes);
> >>          gcc_assert (pattern);
> >>        }
> >> 
> >>      tree init = (init_type == AUTO_INIT_PATTERN) ?
> >>                   pattern :
> >>                   build_zero_cst (var_type);
> >>      expand_assignment (lhs, init, false);
> >>    }
> >> }
> >> ===========================
> >> 
> >> Now, I used “can_native_interpret_type_p (var_type)” instead of “use_register_for_decl (lhs)” to decide 
> >> whether to use “memset” or use “assign” to expand this function.
> >> 
> >> However, this exposed an bug that is very hard to be addressed:
> >> 
> >> *******For the testing case: test suite/gcc.dg/uninit-I.c:
> >> 
> >> /* { dg-do compile } */
> >> /* { dg-options "-O2 -Wuninitialized" } */
> >> 
> >> int sys_msgctl (void)
> >> {
> >>  struct { int mode; } setbuf;
> >>  return setbuf.mode;  /* { dg-warning "'setbuf\.mode' is used" } */
> >> ==
> >> 
> >> ******the above auto var “setbuf” has “struct” type, which “can_native_interpret_type_p(var_type)” is false, therefore, 
> >> Expanding this .DEFERRED_INIT call went down the “memset” expansion route. 
> >> 
> >> However, this structure type can be fitted into a register, therefore cannot be taken address anymore at this stage, even though I tried:
> >> 
> >>         TREE_ADDRESSABLE (lhs) = 1;
> >>         var_addr = build_fold_addr_expr (lhs);
> >> 
> >> To create an address variable for it, the expansion still failed at expr.c: line 8412:
> >> during RTL pass: expand
> >> /home/opc/Work/GCC/latest-gcc/gcc/testsuite/gcc.dg/auto-init-uninit-I.c:6:24: internal compiler error: in expand_expr_addr_expr_1, at expr.c:8412
> >> 0xd04104 expand_expr_addr_expr_1
> >> 	../../latest-gcc/gcc/expr.c:8412
> >> 0xd04a95 expand_expr_addr_expr
> >> 	../../latest-gcc/gcc/expr.c:8525
> >> 0xd13592 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
> >> 	../../latest-gcc/gcc/expr.c:11741
> >> 0xd05142 expand_expr_real(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
> >> 	../../latest-gcc/gcc/expr.c:8713
> >> 0xaed1d3 expand_expr
> >> 	../../latest-gcc/gcc/expr.h:301
> >> 0xaf0d89 get_memory_rtx
> >> 	../../latest-gcc/gcc/builtins.c:1370
> >> 0xafb4fb expand_builtin_memset_args
> >> 	../../latest-gcc/gcc/builtins.c:4102
> >> 0xafacde expand_builtin_memset(tree_node*, rtx_def*, machine_mode)
> >> 	../../latest-gcc/gcc/builtins.c:3886
> >> 0xe97fb3 expand_DEFERRED_INIT
> >> 
> >> ******That’s the major reason why I chose “use_register_for_decl(lhs)” to decide “memset” expansion or “assign” expansion, “memset” expansion
> >> needs to take address of the variable, if the variable has been decided to fit into a register, then its address cannot taken anymore at this stage.
> >> 
> >> ******using “can_native_interpret_type_p” did make the “pattern” generation part much  cleaner and simpler, however, looks like it didn’t work correctly.
> >> 
> >> Based on this, I’d like to keep my previous implementation by using “use_register_for_decl” to decide whether to take “memset” expansion or “assign” expansion.
> >> Therefore, I might still need to keep the “UGLY”  implementation of generatting “pattern” constant for different types?
> >> 
> >> Let me know your opinion on this.
> > 
> > Hmm, I think you can use use_register_for_decl(lhs) to decide to use an
> > alternate type to generate the pattern (and feed to 
> > can_native_interpret_type_p) by using
> > lang_hooks.type_for_mode (TYPE_MODE (TREE_TYPE (lhs))).
> 
> Do you mean that the TYPE returned by “lang_hooks.type_for_mode(TYPE_MODE (TREE_TYPE (lhs))” will always satisfy “can_native_interpret_type_p”? 
> Even for big structure types?

I meant that for use_register_for_decl (lhs) the structures will be
always small and the structure type will have a mode that is not BLKmode
(but for example DImode for struct { int i; int j; }).

> i.e, 
> 
> tree var_type = TREE_TYPE(lhs);
> tree pattern = NULL_TREE;
> unsigned HOST_WIDE_INT total_bytes
>         = tree_to_uhwi (TYPE_SIZE_UNIT (var_type));
> 
> If (use_register_for_decl(lhs)==false)
>   {
>     tree alt_type = lang_hooks.type_for_mode(TYPE_MODE(var_type), TYPE_UNSIGNED(var_type);
>     If (can_native_interpret_type_p (alt_type))
>       {
> 	unsigned char *buf = (unsigned char *) xmalloc (total_bytes); 
> 	memset (buf, INIT_PATTERN_VALUE, total_bytes); 
> 	pattern = native_interpret_expr (alt_type, buf, total_bytes); 
> 	gcc_assert (pattern); 
>       }
>     else
>       gcc_unreachable ();
>   }
> 
> ?
> Don’t quite understand here. Please clarify.

For !use_register_for_decl you use memset already, but for
use_register_for_decl not all types satisfy can_native_interpret_type_p
(in particular all struct and union types).  But when we use a
register for the decl then we can of course directly initialize the
register.  As said, it would be much cleaner (and maybe also easier)
to then simply expand the RTL directly rather than going through
expand_assignment.  It's also easier to directly see whether the
LHS is a MEM_P or a REG_P but then for the MEM_P case it's a bit
more "awkward" to use the easy way of the generic expand code
(esp. if we eventually want to emit actual calls to memset - do we?)

> >  You can then
> > build the assignment from the pattern as
> > 
> > VIEW_CONVERT <reg-type> (lhs) = pattern_cst;
> 
> What’s the <reg_type> in the above? The type “alt_type” returned by “lang_hooks.type_for_mode(TREE_TYPE(lhs))?
> Do I need to build “MODIFY_EXPR” for the above? 

Yes, the lang_hook.type_for_mode result and no, you could go through
expand_assignment.

> lhs =  build1 (VIEW_CONVERT_EXPR, alt_type, lhs);
> tree  final = build2 (MODIFY_EXPR, TREE_TYPE (alt_type), lhs, pattern);
> 
> Then how to expand this”final"? 
> > 
> > note that more RTL-expand-ish would be to simply expand 'lhs' and
> > see whether it's a REG_P or a MEM_P and decide based on that.
> 
> You mean that the current RTL expansion will automatically expand LHS to memset route or assignment route based on whether
> LHS is a REG_P or MEM_P? I don’t need to explicitly code for “expand_builtin_memset” or “expand_assign”?

No.  But you are inside the expander for the internal function call
and this is expected to generate RTL.  You can simply generate
RTL directly without "faking" new GENERIC calls or assignments and
expanding those.

But lets not go there for now.

Richard.

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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-17  8:43         ` Richard Biener
@ 2021-08-17 14:03           ` Qing Zhao
  2021-08-17 14:45             ` Richard Biener
  0 siblings, 1 reply; 60+ messages in thread
From: Qing Zhao @ 2021-08-17 14:03 UTC (permalink / raw)
  To: Richard Biener
  Cc: Martin Jambor, Jakub Jelinek, Kees Cook,
	Nick Alcock via Gcc-patches, Richard Biener



> On Aug 17, 2021, at 3:43 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Mon, 16 Aug 2021, Qing Zhao wrote:
> 
>> 
>> 
>>> On Aug 16, 2021, at 2:40 AM, Richard Biener <rguenther@suse.de> wrote:
>>> 
>>> On Thu, 12 Aug 2021, Qing Zhao wrote:
>>> 
>>>> Hi, Richard,
>>>> 
>>>> For RTL expansion of call to .DEFERRED_INIT, I changed my code per your suggestions like following:
>>>> 
>>>> ======================
>>>> #define INIT_PATTERN_VALUE  0xFE
>>>> static void
>>>> expand_DEFERRED_INIT (internal_fn, gcall *stmt)
>>>> {
>>>> tree lhs = gimple_call_lhs (stmt);
>>>> tree var_size = gimple_call_arg (stmt, 0);
>>>> enum auto_init_type init_type
>>>>   = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
>>>> bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
>>>> 
>>>> tree var_type = TREE_TYPE (lhs);
>>>> gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>>>> 
>>>> if (is_vla || (!can_native_interpret_type_p (var_type)))
>>>>   {
>>>>   /* If this is a VLA or the type of the variable cannot be natively
>>>>      interpreted, expand to a memset to initialize it.  */
>>>>     if (TREE_CODE (lhs) == SSA_NAME)
>>>>       lhs = SSA_NAME_VAR (lhs);
>>>>     tree var_addr = NULL_TREE;
>>>>     if (is_vla)
>>>>       var_addr = TREE_OPERAND (lhs, 0);
>>>>     else
>>>>       {
>>>>        TREE_ADDRESSABLE (lhs) = 1;
>>>>        var_addr = build_fold_addr_expr (lhs);
>>>>       }
>>>>     tree value = (init_type == AUTO_INIT_PATTERN) ?
>>>>                   build_int_cst (unsigned_char_type_node,
>>>>                                  INIT_PATTERN_VALUE) :
>>>>                   build_zero_cst (unsigned_char_type_node);
>>>>     tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
>>>>                                    3, var_addr, value, var_size);
>>>>     /* Expand this memset call.  */
>>>>     expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
>>>>   }
>>>> else
>>>>   {
>>>>   /* If this is not a VLA and the type of the variable can be natively 
>>>>      interpreted, expand to assignment to generate better code.  */
>>>>     tree pattern = NULL_TREE;
>>>>     unsigned HOST_WIDE_INT total_bytes
>>>>       = tree_to_uhwi (TYPE_SIZE_UNIT (var_type));
>>>> 
>>>>     if (init_type == AUTO_INIT_PATTERN)
>>>>       {
>>>>         unsigned char *buf = (unsigned char *) xmalloc (total_bytes);
>>>>         memset (buf, INIT_PATTERN_VALUE, total_bytes);
>>>>         pattern = native_interpret_expr (var_type, buf, total_bytes);
>>>>         gcc_assert (pattern);
>>>>       }
>>>> 
>>>>     tree init = (init_type == AUTO_INIT_PATTERN) ?
>>>>                  pattern :
>>>>                  build_zero_cst (var_type);
>>>>     expand_assignment (lhs, init, false);
>>>>   }
>>>> }
>>>> ===========================
>>>> 
>>>> Now, I used “can_native_interpret_type_p (var_type)” instead of “use_register_for_decl (lhs)” to decide 
>>>> whether to use “memset” or use “assign” to expand this function.
>>>> 
>>>> However, this exposed an bug that is very hard to be addressed:
>>>> 
>>>> *******For the testing case: test suite/gcc.dg/uninit-I.c:
>>>> 
>>>> /* { dg-do compile } */
>>>> /* { dg-options "-O2 -Wuninitialized" } */
>>>> 
>>>> int sys_msgctl (void)
>>>> {
>>>> struct { int mode; } setbuf;
>>>> return setbuf.mode;  /* { dg-warning "'setbuf\.mode' is used" } */
>>>> ==
>>>> 
>>>> ******the above auto var “setbuf” has “struct” type, which “can_native_interpret_type_p(var_type)” is false, therefore, 
>>>> Expanding this .DEFERRED_INIT call went down the “memset” expansion route. 
>>>> 
>>>> However, this structure type can be fitted into a register, therefore cannot be taken address anymore at this stage, even though I tried:
>>>> 
>>>>        TREE_ADDRESSABLE (lhs) = 1;
>>>>        var_addr = build_fold_addr_expr (lhs);
>>>> 
>>>> To create an address variable for it, the expansion still failed at expr.c: line 8412:
>>>> during RTL pass: expand
>>>> /home/opc/Work/GCC/latest-gcc/gcc/testsuite/gcc.dg/auto-init-uninit-I.c:6:24: internal compiler error: in expand_expr_addr_expr_1, at expr.c:8412
>>>> 0xd04104 expand_expr_addr_expr_1
>>>> 	../../latest-gcc/gcc/expr.c:8412
>>>> 0xd04a95 expand_expr_addr_expr
>>>> 	../../latest-gcc/gcc/expr.c:8525
>>>> 0xd13592 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
>>>> 	../../latest-gcc/gcc/expr.c:11741
>>>> 0xd05142 expand_expr_real(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
>>>> 	../../latest-gcc/gcc/expr.c:8713
>>>> 0xaed1d3 expand_expr
>>>> 	../../latest-gcc/gcc/expr.h:301
>>>> 0xaf0d89 get_memory_rtx
>>>> 	../../latest-gcc/gcc/builtins.c:1370
>>>> 0xafb4fb expand_builtin_memset_args
>>>> 	../../latest-gcc/gcc/builtins.c:4102
>>>> 0xafacde expand_builtin_memset(tree_node*, rtx_def*, machine_mode)
>>>> 	../../latest-gcc/gcc/builtins.c:3886
>>>> 0xe97fb3 expand_DEFERRED_INIT
>>>> 
>>>> ******That’s the major reason why I chose “use_register_for_decl(lhs)” to decide “memset” expansion or “assign” expansion, “memset” expansion
>>>> needs to take address of the variable, if the variable has been decided to fit into a register, then its address cannot taken anymore at this stage.
>>>> 
>>>> ******using “can_native_interpret_type_p” did make the “pattern” generation part much  cleaner and simpler, however, looks like it didn’t work correctly.
>>>> 
>>>> Based on this, I’d like to keep my previous implementation by using “use_register_for_decl” to decide whether to take “memset” expansion or “assign” expansion.
>>>> Therefore, I might still need to keep the “UGLY”  implementation of generatting “pattern” constant for different types?
>>>> 
>>>> Let me know your opinion on this.
>>> 
>>> Hmm, I think you can use use_register_for_decl(lhs) to decide to use an
>>> alternate type to generate the pattern (and feed to 
>>> can_native_interpret_type_p) by using
>>> lang_hooks.type_for_mode (TYPE_MODE (TREE_TYPE (lhs))).
>> 
>> Do you mean that the TYPE returned by “lang_hooks.type_for_mode(TYPE_MODE (TREE_TYPE (lhs))” will always satisfy “can_native_interpret_type_p”? 
>> Even for big structure types?
> 
> I meant that for use_register_for_decl (lhs) the structures will be
> always small and the structure type will have a mode that is not BLKmode
> (but for example DImode for struct { int i; int j; }).

Oh, I see.

> 
>> i.e, 
>> 
>> tree var_type = TREE_TYPE(lhs);
>> tree pattern = NULL_TREE;
>> unsigned HOST_WIDE_INT total_bytes
>>        = tree_to_uhwi (TYPE_SIZE_UNIT (var_type));
>> 
>> If (use_register_for_decl(lhs)==false)
>>  {
>>    tree alt_type = lang_hooks.type_for_mode(TYPE_MODE(var_type), TYPE_UNSIGNED(var_type);
>>    If (can_native_interpret_type_p (alt_type))
>>      {
>> 	unsigned char *buf = (unsigned char *) xmalloc (total_bytes); 
>> 	memset (buf, INIT_PATTERN_VALUE, total_bytes); 
>> 	pattern = native_interpret_expr (alt_type, buf, total_bytes); 
>> 	gcc_assert (pattern); 
>>      }
>>    else
>>      gcc_unreachable ();
>>  }
>> 
>> ?
>> Don’t quite understand here. Please clarify.
> 
> For !use_register_for_decl you use memset already, but for
> use_register_for_decl not all types satisfy can_native_interpret_type_p
> (in particular all struct and union types).  But when we use a
> register for the decl then we can of course directly initialize the
> register.

So, you mean the following:

If (is_vla || (!use_register_for_decl (lhs)))
{
  /* expand as memset that is done currently.  */
}
else 
 {
   tree alt_type = lang_hooks.type_for_mode(TYPE_MODE(var_type), TYPE_UNSIGNED(var_type);
   If (can_native_interpret_type_p (alt_type))
     {
	unsigned char *buf = (unsigned char *) xmalloc (total_bytes); 
	memset (buf, INIT_PATTERN_VALUE, total_bytes); 
	pattern = native_interpret_expr (alt_type, buf, total_bytes); 
	gcc_assert (pattern); 
     }
   else
     gcc_unreachable ();

     tree init = (init_type == AUTO_INIT_PATTERN) ?
                   pattern :
                   build_zero_cst (alt_type);

    /* here build VIEW_CONVERT <alt_type> (lhs) = init;
       And then expand it.  */
 }

?

>  As said, it would be much cleaner (and maybe also easier)
> to then simply expand the RTL directly rather than going through
> expand_assignment.

Dump questions here:  

1. When building VIEW_CONVERT  <alt_type> (lhs) = init and expand it:

Is the following correct:

 lhs = build1 (VIEW_CONVERT_EXPR, alt_type, lhs);
expand_assignment (lhs, init);


which utility routines should be used to building the assignment and then expand it?

Are the above utility routines correct?


>  It's also easier to directly see whether the
> LHS is a MEM_P or a REG_P but then for the MEM_P case it's a bit
> more "awkward" to use the easy way of the generic expand code
> (esp. if we eventually want to emit actual calls to memset - do we?)

If all these are guarded by “use_register_for_decl” already, the lhs should be fit into registers, 
Under such situation, I don’t think that we want to emit actual calls to memset. That’s too expensive.

> 
>>> You can then
>>> build the assignment from the pattern as
>>> 
>>> VIEW_CONVERT <reg-type> (lhs) = pattern_cst;
>> 
>> What’s the <reg_type> in the above? The type “alt_type” returned by “lang_hooks.type_for_mode(TREE_TYPE(lhs))?
>> Do I need to build “MODIFY_EXPR” for the above? 
> 
> Yes, the lang_hook.type_for_mode result and no, you could go through
> expand_assignment.

Okay. So, still use “expand_assigment” to expand it?
> 
>> lhs =  build1 (VIEW_CONVERT_EXPR, alt_type, lhs);
>> tree  final = build2 (MODIFY_EXPR, TREE_TYPE (alt_type), lhs, pattern);
>> 
>> Then how to expand this”final"? 
>>> 
>>> note that more RTL-expand-ish would be to simply expand 'lhs' and
>>> see whether it's a REG_P or a MEM_P and decide based on that.
>> 
>> You mean that the current RTL expansion will automatically expand LHS to memset route or assignment route based on whether
>> LHS is a REG_P or MEM_P? I don’t need to explicitly code for “expand_builtin_memset” or “expand_assign”?
> 
> No.  But you are inside the expander for the internal function call
> and this is expected to generate RTL.  You can simply generate
> RTL directly without "faking" new GENERIC calls or assignments and
> expanding those.
> 
> But lets not go there for now.

Okay. I see now.

Qing
> 
> Richard.


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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-17 14:03           ` Qing Zhao
@ 2021-08-17 14:45             ` Richard Biener
  2021-08-17 14:53               ` Qing Zhao
  0 siblings, 1 reply; 60+ messages in thread
From: Richard Biener @ 2021-08-17 14:45 UTC (permalink / raw)
  To: Qing Zhao
  Cc: Martin Jambor, Jakub Jelinek, Kees Cook,
	Nick Alcock via Gcc-patches, Richard Biener

On Tue, 17 Aug 2021, Qing Zhao wrote:

> 
> 
> > On Aug 17, 2021, at 3:43 AM, Richard Biener <rguenther@suse.de> wrote:
> > 
> > On Mon, 16 Aug 2021, Qing Zhao wrote:
> > 
> >> 
> >> 
> >>> On Aug 16, 2021, at 2:40 AM, Richard Biener <rguenther@suse.de> wrote:
> >>> 
> >>> On Thu, 12 Aug 2021, Qing Zhao wrote:
> >>> 
> >>>> Hi, Richard,
> >>>> 
> >>>> For RTL expansion of call to .DEFERRED_INIT, I changed my code per your suggestions like following:
> >>>> 
> >>>> ======================
> >>>> #define INIT_PATTERN_VALUE  0xFE
> >>>> static void
> >>>> expand_DEFERRED_INIT (internal_fn, gcall *stmt)
> >>>> {
> >>>> tree lhs = gimple_call_lhs (stmt);
> >>>> tree var_size = gimple_call_arg (stmt, 0);
> >>>> enum auto_init_type init_type
> >>>>   = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
> >>>> bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
> >>>> 
> >>>> tree var_type = TREE_TYPE (lhs);
> >>>> gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
> >>>> 
> >>>> if (is_vla || (!can_native_interpret_type_p (var_type)))
> >>>>   {
> >>>>   /* If this is a VLA or the type of the variable cannot be natively
> >>>>      interpreted, expand to a memset to initialize it.  */
> >>>>     if (TREE_CODE (lhs) == SSA_NAME)
> >>>>       lhs = SSA_NAME_VAR (lhs);
> >>>>     tree var_addr = NULL_TREE;
> >>>>     if (is_vla)
> >>>>       var_addr = TREE_OPERAND (lhs, 0);
> >>>>     else
> >>>>       {
> >>>>        TREE_ADDRESSABLE (lhs) = 1;
> >>>>        var_addr = build_fold_addr_expr (lhs);
> >>>>       }
> >>>>     tree value = (init_type == AUTO_INIT_PATTERN) ?
> >>>>                   build_int_cst (unsigned_char_type_node,
> >>>>                                  INIT_PATTERN_VALUE) :
> >>>>                   build_zero_cst (unsigned_char_type_node);
> >>>>     tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
> >>>>                                    3, var_addr, value, var_size);
> >>>>     /* Expand this memset call.  */
> >>>>     expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
> >>>>   }
> >>>> else
> >>>>   {
> >>>>   /* If this is not a VLA and the type of the variable can be natively 
> >>>>      interpreted, expand to assignment to generate better code.  */
> >>>>     tree pattern = NULL_TREE;
> >>>>     unsigned HOST_WIDE_INT total_bytes
> >>>>       = tree_to_uhwi (TYPE_SIZE_UNIT (var_type));
> >>>> 
> >>>>     if (init_type == AUTO_INIT_PATTERN)
> >>>>       {
> >>>>         unsigned char *buf = (unsigned char *) xmalloc (total_bytes);
> >>>>         memset (buf, INIT_PATTERN_VALUE, total_bytes);
> >>>>         pattern = native_interpret_expr (var_type, buf, total_bytes);
> >>>>         gcc_assert (pattern);
> >>>>       }
> >>>> 
> >>>>     tree init = (init_type == AUTO_INIT_PATTERN) ?
> >>>>                  pattern :
> >>>>                  build_zero_cst (var_type);
> >>>>     expand_assignment (lhs, init, false);
> >>>>   }
> >>>> }
> >>>> ===========================
> >>>> 
> >>>> Now, I used “can_native_interpret_type_p (var_type)” instead of “use_register_for_decl (lhs)” to decide 
> >>>> whether to use “memset” or use “assign” to expand this function.
> >>>> 
> >>>> However, this exposed an bug that is very hard to be addressed:
> >>>> 
> >>>> *******For the testing case: test suite/gcc.dg/uninit-I.c:
> >>>> 
> >>>> /* { dg-do compile } */
> >>>> /* { dg-options "-O2 -Wuninitialized" } */
> >>>> 
> >>>> int sys_msgctl (void)
> >>>> {
> >>>> struct { int mode; } setbuf;
> >>>> return setbuf.mode;  /* { dg-warning "'setbuf\.mode' is used" } */
> >>>> ==
> >>>> 
> >>>> ******the above auto var “setbuf” has “struct” type, which “can_native_interpret_type_p(var_type)” is false, therefore, 
> >>>> Expanding this .DEFERRED_INIT call went down the “memset” expansion route. 
> >>>> 
> >>>> However, this structure type can be fitted into a register, therefore cannot be taken address anymore at this stage, even though I tried:
> >>>> 
> >>>>        TREE_ADDRESSABLE (lhs) = 1;
> >>>>        var_addr = build_fold_addr_expr (lhs);
> >>>> 
> >>>> To create an address variable for it, the expansion still failed at expr.c: line 8412:
> >>>> during RTL pass: expand
> >>>> /home/opc/Work/GCC/latest-gcc/gcc/testsuite/gcc.dg/auto-init-uninit-I.c:6:24: internal compiler error: in expand_expr_addr_expr_1, at expr.c:8412
> >>>> 0xd04104 expand_expr_addr_expr_1
> >>>> 	../../latest-gcc/gcc/expr.c:8412
> >>>> 0xd04a95 expand_expr_addr_expr
> >>>> 	../../latest-gcc/gcc/expr.c:8525
> >>>> 0xd13592 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
> >>>> 	../../latest-gcc/gcc/expr.c:11741
> >>>> 0xd05142 expand_expr_real(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
> >>>> 	../../latest-gcc/gcc/expr.c:8713
> >>>> 0xaed1d3 expand_expr
> >>>> 	../../latest-gcc/gcc/expr.h:301
> >>>> 0xaf0d89 get_memory_rtx
> >>>> 	../../latest-gcc/gcc/builtins.c:1370
> >>>> 0xafb4fb expand_builtin_memset_args
> >>>> 	../../latest-gcc/gcc/builtins.c:4102
> >>>> 0xafacde expand_builtin_memset(tree_node*, rtx_def*, machine_mode)
> >>>> 	../../latest-gcc/gcc/builtins.c:3886
> >>>> 0xe97fb3 expand_DEFERRED_INIT
> >>>> 
> >>>> ******That’s the major reason why I chose “use_register_for_decl(lhs)” to decide “memset” expansion or “assign” expansion, “memset” expansion
> >>>> needs to take address of the variable, if the variable has been decided to fit into a register, then its address cannot taken anymore at this stage.
> >>>> 
> >>>> ******using “can_native_interpret_type_p” did make the “pattern” generation part much  cleaner and simpler, however, looks like it didn’t work correctly.
> >>>> 
> >>>> Based on this, I’d like to keep my previous implementation by using “use_register_for_decl” to decide whether to take “memset” expansion or “assign” expansion.
> >>>> Therefore, I might still need to keep the “UGLY”  implementation of generatting “pattern” constant for different types?
> >>>> 
> >>>> Let me know your opinion on this.
> >>> 
> >>> Hmm, I think you can use use_register_for_decl(lhs) to decide to use an
> >>> alternate type to generate the pattern (and feed to 
> >>> can_native_interpret_type_p) by using
> >>> lang_hooks.type_for_mode (TYPE_MODE (TREE_TYPE (lhs))).
> >> 
> >> Do you mean that the TYPE returned by “lang_hooks.type_for_mode(TYPE_MODE (TREE_TYPE (lhs))” will always satisfy “can_native_interpret_type_p”? 
> >> Even for big structure types?
> > 
> > I meant that for use_register_for_decl (lhs) the structures will be
> > always small and the structure type will have a mode that is not BLKmode
> > (but for example DImode for struct { int i; int j; }).
> 
> Oh, I see.
> 
> > 
> >> i.e, 
> >> 
> >> tree var_type = TREE_TYPE(lhs);
> >> tree pattern = NULL_TREE;
> >> unsigned HOST_WIDE_INT total_bytes
> >>        = tree_to_uhwi (TYPE_SIZE_UNIT (var_type));
> >> 
> >> If (use_register_for_decl(lhs)==false)
> >>  {
> >>    tree alt_type = lang_hooks.type_for_mode(TYPE_MODE(var_type), TYPE_UNSIGNED(var_type);
> >>    If (can_native_interpret_type_p (alt_type))
> >>      {
> >> 	unsigned char *buf = (unsigned char *) xmalloc (total_bytes); 
> >> 	memset (buf, INIT_PATTERN_VALUE, total_bytes); 
> >> 	pattern = native_interpret_expr (alt_type, buf, total_bytes); 
> >> 	gcc_assert (pattern); 
> >>      }
> >>    else
> >>      gcc_unreachable ();
> >>  }
> >> 
> >> ?
> >> Don’t quite understand here. Please clarify.
> > 
> > For !use_register_for_decl you use memset already, but for
> > use_register_for_decl not all types satisfy can_native_interpret_type_p
> > (in particular all struct and union types).  But when we use a
> > register for the decl then we can of course directly initialize the
> > register.
> 
> So, you mean the following:
> 
> If (is_vla || (!use_register_for_decl (lhs)))
> {
>   /* expand as memset that is done currently.  */
> }
> else 
>  {
>    tree alt_type = lang_hooks.type_for_mode(TYPE_MODE(var_type), TYPE_UNSIGNED(var_type);
>    If (can_native_interpret_type_p (alt_type))

you can use var_type when it satisfies can_native_interpret_type_p

>      {
> 	unsigned char *buf = (unsigned char *) xmalloc (total_bytes); 
> 	memset (buf, INIT_PATTERN_VALUE, total_bytes); 
> 	pattern = native_interpret_expr (alt_type, buf, total_bytes); 
> 	gcc_assert (pattern); 
>      }
>    else
>      gcc_unreachable ();
> 
>      tree init = (init_type == AUTO_INIT_PATTERN) ?
>                    pattern :
>                    build_zero_cst (alt_type);
> 
>     /* here build VIEW_CONVERT <alt_type> (lhs) = init;
>        And then expand it.  */
>  }
> 
> ?
> 
> >  As said, it would be much cleaner (and maybe also easier)
> > to then simply expand the RTL directly rather than going through
> > expand_assignment.
> 
> Dump questions here:  
> 
> 1. When building VIEW_CONVERT  <alt_type> (lhs) = init and expand it:
> 
> Is the following correct:
> 
>  lhs = build1 (VIEW_CONVERT_EXPR, alt_type, lhs);
> expand_assignment (lhs, init);

yes, I think so.

> 
> which utility routines should be used to building the assignment and then expand it?
> 
> Are the above utility routines correct?

yes.
 
> 
> >  It's also easier to directly see whether the
> > LHS is a MEM_P or a REG_P but then for the MEM_P case it's a bit
> > more "awkward" to use the easy way of the generic expand code
> > (esp. if we eventually want to emit actual calls to memset - do we?)
> 
> If all these are guarded by “use_register_for_decl” already, the lhs should be fit into registers, 
> Under such situation, I don’t think that we want to emit actual calls to memset. That’s too expensive.
> 
> > 
> >>> You can then
> >>> build the assignment from the pattern as
> >>> 
> >>> VIEW_CONVERT <reg-type> (lhs) = pattern_cst;
> >> 
> >> What’s the <reg_type> in the above? The type “alt_type” returned by “lang_hooks.type_for_mode(TREE_TYPE(lhs))?
> >> Do I need to build “MODIFY_EXPR” for the above? 
> > 
> > Yes, the lang_hook.type_for_mode result and no, you could go through
> > expand_assignment.
> 
> Okay. So, still use “expand_assigment” to expand it?

yes.

> > 
> >> lhs =  build1 (VIEW_CONVERT_EXPR, alt_type, lhs);
> >> tree  final = build2 (MODIFY_EXPR, TREE_TYPE (alt_type), lhs, pattern);
> >> 
> >> Then how to expand this”final"? 
> >>> 
> >>> note that more RTL-expand-ish would be to simply expand 'lhs' and
> >>> see whether it's a REG_P or a MEM_P and decide based on that.
> >> 
> >> You mean that the current RTL expansion will automatically expand LHS to memset route or assignment route based on whether
> >> LHS is a REG_P or MEM_P? I don’t need to explicitly code for “expand_builtin_memset” or “expand_assign”?
> > 
> > No.  But you are inside the expander for the internal function call
> > and this is expected to generate RTL.  You can simply generate
> > RTL directly without "faking" new GENERIC calls or assignments and
> > expanding those.
> > 
> > But lets not go there for now.
> 
> Okay. I see now.
> 
> Qing
> > 
> > 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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-17  8:29         ` Richard Biener
@ 2021-08-17 14:50           ` Qing Zhao
  2021-08-17 16:08             ` Qing Zhao
  0 siblings, 1 reply; 60+ messages in thread
From: Qing Zhao @ 2021-08-17 14:50 UTC (permalink / raw)
  To: Richard Biener
  Cc: Martin Jambor, Jakub Jelinek, Kees Cook,
	Nick Alcock via Gcc-patches, Richard Biener



> On Aug 17, 2021, at 3:29 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Mon, 16 Aug 2021, Qing Zhao wrote:
> 
>> My current code for expand_DEFERRED_INIT is like the following, could you check and see whether there is any issue for it:
>> 
>> #define INIT_PATTERN_VALUE  0xFE
>> static void
>> expand_DEFERRED_INIT (internal_fn, gcall *stmt)
>> {
>>  tree lhs = gimple_call_lhs (stmt);
>>  tree var_size = gimple_call_arg (stmt, 0);
>>  enum auto_init_type init_type
>>    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
>>  bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
>> 
>>  tree var_type = TREE_TYPE (lhs);
>>  gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>> 
>>  if (is_vla || (!use_register_for_decl (lhs)))
>>    {
>>      if (TREE_CODE (lhs) == SSA_NAME)
>>        lhs = SSA_NAME_VAR (lhs);
> 
> this should not be necessary (in fact you shouldn't see a SSA_NAME
> here, if you do then using SSA_NAME_VAR is wrong)
You mean during RTL expansion phase, all SSA_NAMEs are gone already?
> 
>>    /* If this is a VLA or the variable is not in register,
>>       expand to a memset to initialize it.  */
>>      tree var_addr = NULL_TREE;
>>      if (is_vla)
>>        var_addr = TREE_OPERAND (lhs, 0);
>>      else
>>        {
>>          TREE_ADDRESSABLE (lhs) = 1;
>>          var_addr = build_fold_addr_expr (lhs);
>>        }
> 
> use, independent of is_vla
> 
>         mark_addressable (lhs);
>         var_addr = build_fold_addr_expr (lhs);
Okay.
> 
>> 
>>      tree value = (init_type == AUTO_INIT_PATTERN) ?
>>                    build_int_cst (unsigned_char_type_node,
>>                                   INIT_PATTERN_VALUE) :
>>                    build_zero_cst (unsigned_char_type_node);
> 
> since memset has an integer argument for the value use
> integer_zero_node for the zero case and build_int_cst (integer_type_node, 
> ...) for the pattern case

Okay.

> 
>>      tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
>>                                     3, var_addr, value, var_size);
>>      /* Expand this memset call.  */
>>      expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
>>    }
>>  else
>>    {
>>    /* If this variable is in a register, use expand_assignment might
>>       generate better code.  */
>>      tree pattern = NULL_TREE;
>>      unsigned HOST_WIDE_INT total_bytes
>>        = tree_to_uhwi (TYPE_SIZE_UNIT (var_type));
>> 
>>      if (init_type == AUTO_INIT_PATTERN)
>>        {
>>          if (can_native_interpret_type_p (var_type))
>>            {
>>              unsigned char *buf = (unsigned char *) xmalloc (total_bytes);
>>              memset (buf, INIT_PATTERN_VALUE, total_bytes);
>>              pattern = native_interpret_expr (var_type, buf, total_bytes);
>>              gcc_assert (pattern);
>>            }
>>          else
>>            {
>>              tree index_type = build_index_type (size_int (total_bytes - 1));
>>              tree array_type = build_array_type (unsigned_char_type_node,
>>                                                  index_type);
>>              tree element = build_int_cst (unsigned_char_type_node,
>>                                            INIT_PATTERN_VALUE);
>>              vec<constructor_elt, va_gc> *elts = NULL;
>>              for (unsigned int i = 0; i < total_bytes; i++)
>>                CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, element);
>>              pattern = build_constructor (array_type, elts);
>>              pattern = build1 (VIEW_CONVERT_EXPR, var_type, pattern);
>>            }
>>        }
>> 
>>      tree init = (init_type == AUTO_INIT_PATTERN) ?
>>                   pattern :
>>                   build_zero_cst (var_type);
> 
> maybe conditionally initialize init instead of pattern and init?
> Thus replace pattern by init and do
> 
>        else
>          init = build_zero_cst (var_type);

You mean the following:


tree init = pattern;
If (init_type != AUTO_INIT_PATTERN)
  Init = build_zero_cst (var_type);

Or something else?

> 
> 
> the above should work, as said the RTL expansion part can possibly
> be improved but we can do this as followup as well.

Okay.

Qing
> 
>>      expand_assignment (lhs, init, false);
>>    }
>> }
>> 
>> Thanks.
>> 
>> Qing
>> 
>> 
>> 
>> 
> 
> -- 
> 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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-17 14:45             ` Richard Biener
@ 2021-08-17 14:53               ` Qing Zhao
  0 siblings, 0 replies; 60+ messages in thread
From: Qing Zhao @ 2021-08-17 14:53 UTC (permalink / raw)
  To: Richard Biener
  Cc: Martin Jambor, Jakub Jelinek, Kees Cook,
	Nick Alcock via Gcc-patches, Richard Biener



> On Aug 17, 2021, at 9:45 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Tue, 17 Aug 2021, Qing Zhao wrote:
> 
>> 
>> 
>>> On Aug 17, 2021, at 3:43 AM, Richard Biener <rguenther@suse.de> wrote:
>>> 
>>> On Mon, 16 Aug 2021, Qing Zhao wrote:
>>> 
>>>> 
>>>> 
>>>>> On Aug 16, 2021, at 2:40 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>> 
>>>>> On Thu, 12 Aug 2021, Qing Zhao wrote:
>>>>> 
>>>>>> Hi, Richard,
>>>>>> 
>>>>>> For RTL expansion of call to .DEFERRED_INIT, I changed my code per your suggestions like following:
>>>>>> 
>>>>>> ======================
>>>>>> #define INIT_PATTERN_VALUE  0xFE
>>>>>> static void
>>>>>> expand_DEFERRED_INIT (internal_fn, gcall *stmt)
>>>>>> {
>>>>>> tree lhs = gimple_call_lhs (stmt);
>>>>>> tree var_size = gimple_call_arg (stmt, 0);
>>>>>> enum auto_init_type init_type
>>>>>>  = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
>>>>>> bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
>>>>>> 
>>>>>> tree var_type = TREE_TYPE (lhs);
>>>>>> gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>>>>>> 
>>>>>> if (is_vla || (!can_native_interpret_type_p (var_type)))
>>>>>>  {
>>>>>>  /* If this is a VLA or the type of the variable cannot be natively
>>>>>>     interpreted, expand to a memset to initialize it.  */
>>>>>>    if (TREE_CODE (lhs) == SSA_NAME)
>>>>>>      lhs = SSA_NAME_VAR (lhs);
>>>>>>    tree var_addr = NULL_TREE;
>>>>>>    if (is_vla)
>>>>>>      var_addr = TREE_OPERAND (lhs, 0);
>>>>>>    else
>>>>>>      {
>>>>>>       TREE_ADDRESSABLE (lhs) = 1;
>>>>>>       var_addr = build_fold_addr_expr (lhs);
>>>>>>      }
>>>>>>    tree value = (init_type == AUTO_INIT_PATTERN) ?
>>>>>>                  build_int_cst (unsigned_char_type_node,
>>>>>>                                 INIT_PATTERN_VALUE) :
>>>>>>                  build_zero_cst (unsigned_char_type_node);
>>>>>>    tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
>>>>>>                                   3, var_addr, value, var_size);
>>>>>>    /* Expand this memset call.  */
>>>>>>    expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
>>>>>>  }
>>>>>> else
>>>>>>  {
>>>>>>  /* If this is not a VLA and the type of the variable can be natively 
>>>>>>     interpreted, expand to assignment to generate better code.  */
>>>>>>    tree pattern = NULL_TREE;
>>>>>>    unsigned HOST_WIDE_INT total_bytes
>>>>>>      = tree_to_uhwi (TYPE_SIZE_UNIT (var_type));
>>>>>> 
>>>>>>    if (init_type == AUTO_INIT_PATTERN)
>>>>>>      {
>>>>>>        unsigned char *buf = (unsigned char *) xmalloc (total_bytes);
>>>>>>        memset (buf, INIT_PATTERN_VALUE, total_bytes);
>>>>>>        pattern = native_interpret_expr (var_type, buf, total_bytes);
>>>>>>        gcc_assert (pattern);
>>>>>>      }
>>>>>> 
>>>>>>    tree init = (init_type == AUTO_INIT_PATTERN) ?
>>>>>>                 pattern :
>>>>>>                 build_zero_cst (var_type);
>>>>>>    expand_assignment (lhs, init, false);
>>>>>>  }
>>>>>> }
>>>>>> ===========================
>>>>>> 
>>>>>> Now, I used “can_native_interpret_type_p (var_type)” instead of “use_register_for_decl (lhs)” to decide 
>>>>>> whether to use “memset” or use “assign” to expand this function.
>>>>>> 
>>>>>> However, this exposed an bug that is very hard to be addressed:
>>>>>> 
>>>>>> *******For the testing case: test suite/gcc.dg/uninit-I.c:
>>>>>> 
>>>>>> /* { dg-do compile } */
>>>>>> /* { dg-options "-O2 -Wuninitialized" } */
>>>>>> 
>>>>>> int sys_msgctl (void)
>>>>>> {
>>>>>> struct { int mode; } setbuf;
>>>>>> return setbuf.mode;  /* { dg-warning "'setbuf\.mode' is used" } */
>>>>>> ==
>>>>>> 
>>>>>> ******the above auto var “setbuf” has “struct” type, which “can_native_interpret_type_p(var_type)” is false, therefore, 
>>>>>> Expanding this .DEFERRED_INIT call went down the “memset” expansion route. 
>>>>>> 
>>>>>> However, this structure type can be fitted into a register, therefore cannot be taken address anymore at this stage, even though I tried:
>>>>>> 
>>>>>>       TREE_ADDRESSABLE (lhs) = 1;
>>>>>>       var_addr = build_fold_addr_expr (lhs);
>>>>>> 
>>>>>> To create an address variable for it, the expansion still failed at expr.c: line 8412:
>>>>>> during RTL pass: expand
>>>>>> /home/opc/Work/GCC/latest-gcc/gcc/testsuite/gcc.dg/auto-init-uninit-I.c:6:24: internal compiler error: in expand_expr_addr_expr_1, at expr.c:8412
>>>>>> 0xd04104 expand_expr_addr_expr_1
>>>>>> 	../../latest-gcc/gcc/expr.c:8412
>>>>>> 0xd04a95 expand_expr_addr_expr
>>>>>> 	../../latest-gcc/gcc/expr.c:8525
>>>>>> 0xd13592 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
>>>>>> 	../../latest-gcc/gcc/expr.c:11741
>>>>>> 0xd05142 expand_expr_real(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
>>>>>> 	../../latest-gcc/gcc/expr.c:8713
>>>>>> 0xaed1d3 expand_expr
>>>>>> 	../../latest-gcc/gcc/expr.h:301
>>>>>> 0xaf0d89 get_memory_rtx
>>>>>> 	../../latest-gcc/gcc/builtins.c:1370
>>>>>> 0xafb4fb expand_builtin_memset_args
>>>>>> 	../../latest-gcc/gcc/builtins.c:4102
>>>>>> 0xafacde expand_builtin_memset(tree_node*, rtx_def*, machine_mode)
>>>>>> 	../../latest-gcc/gcc/builtins.c:3886
>>>>>> 0xe97fb3 expand_DEFERRED_INIT
>>>>>> 
>>>>>> ******That’s the major reason why I chose “use_register_for_decl(lhs)” to decide “memset” expansion or “assign” expansion, “memset” expansion
>>>>>> needs to take address of the variable, if the variable has been decided to fit into a register, then its address cannot taken anymore at this stage.
>>>>>> 
>>>>>> ******using “can_native_interpret_type_p” did make the “pattern” generation part much  cleaner and simpler, however, looks like it didn’t work correctly.
>>>>>> 
>>>>>> Based on this, I’d like to keep my previous implementation by using “use_register_for_decl” to decide whether to take “memset” expansion or “assign” expansion.
>>>>>> Therefore, I might still need to keep the “UGLY”  implementation of generatting “pattern” constant for different types?
>>>>>> 
>>>>>> Let me know your opinion on this.
>>>>> 
>>>>> Hmm, I think you can use use_register_for_decl(lhs) to decide to use an
>>>>> alternate type to generate the pattern (and feed to 
>>>>> can_native_interpret_type_p) by using
>>>>> lang_hooks.type_for_mode (TYPE_MODE (TREE_TYPE (lhs))).
>>>> 
>>>> Do you mean that the TYPE returned by “lang_hooks.type_for_mode(TYPE_MODE (TREE_TYPE (lhs))” will always satisfy “can_native_interpret_type_p”? 
>>>> Even for big structure types?
>>> 
>>> I meant that for use_register_for_decl (lhs) the structures will be
>>> always small and the structure type will have a mode that is not BLKmode
>>> (but for example DImode for struct { int i; int j; }).
>> 
>> Oh, I see.
>> 
>>> 
>>>> i.e, 
>>>> 
>>>> tree var_type = TREE_TYPE(lhs);
>>>> tree pattern = NULL_TREE;
>>>> unsigned HOST_WIDE_INT total_bytes
>>>>       = tree_to_uhwi (TYPE_SIZE_UNIT (var_type));
>>>> 
>>>> If (use_register_for_decl(lhs)==false)
>>>> {
>>>>   tree alt_type = lang_hooks.type_for_mode(TYPE_MODE(var_type), TYPE_UNSIGNED(var_type);
>>>>   If (can_native_interpret_type_p (alt_type))
>>>>     {
>>>> 	unsigned char *buf = (unsigned char *) xmalloc (total_bytes); 
>>>> 	memset (buf, INIT_PATTERN_VALUE, total_bytes); 
>>>> 	pattern = native_interpret_expr (alt_type, buf, total_bytes); 
>>>> 	gcc_assert (pattern); 
>>>>     }
>>>>   else
>>>>     gcc_unreachable ();
>>>> }
>>>> 
>>>> ?
>>>> Don’t quite understand here. Please clarify.
>>> 
>>> For !use_register_for_decl you use memset already, but for
>>> use_register_for_decl not all types satisfy can_native_interpret_type_p
>>> (in particular all struct and union types).  But when we use a
>>> register for the decl then we can of course directly initialize the
>>> register.
>> 
>> So, you mean the following:
>> 
>> If (is_vla || (!use_register_for_decl (lhs)))
>> {
>>  /* expand as memset that is done currently.  */
>> }
>> else 
>> {
>>   tree alt_type = lang_hooks.type_for_mode(TYPE_MODE(var_type), TYPE_UNSIGNED(var_type);
>>   If (can_native_interpret_type_p (alt_type))
> 
> you can use var_type when it satisfies can_native_interpret_type_p

Yes, then under that situation, no VIEW_CONVERT is needed.

> 
>>     {
>> 	unsigned char *buf = (unsigned char *) xmalloc (total_bytes); 
>> 	memset (buf, INIT_PATTERN_VALUE, total_bytes); 
>> 	pattern = native_interpret_expr (alt_type, buf, total_bytes); 
>> 	gcc_assert (pattern); 
>>     }
>>   else
>>     gcc_unreachable ();
>> 
>>     tree init = (init_type == AUTO_INIT_PATTERN) ?
>>                   pattern :
>>                   build_zero_cst (alt_type);
>> 
>>    /* here build VIEW_CONVERT <alt_type> (lhs) = init;
>>       And then expand it.  */
>> }
>> 
>> ?
>> 
>>> As said, it would be much cleaner (and maybe also easier)
>>> to then simply expand the RTL directly rather than going through
>>> expand_assignment.
>> 
>> Dump questions here:  
>> 
>> 1. When building VIEW_CONVERT  <alt_type> (lhs) = init and expand it:
>> 
>> Is the following correct:
>> 
>> lhs = build1 (VIEW_CONVERT_EXPR, alt_type, lhs);
>> expand_assignment (lhs, init);
> 
> yes, I think so.

Okay.
> 
>> 
>> which utility routines should be used to building the assignment and then expand it?
>> 
>> Are the above utility routines correct?
> 
> yes.
> 
>> 
>>> It's also easier to directly see whether the
>>> LHS is a MEM_P or a REG_P but then for the MEM_P case it's a bit
>>> more "awkward" to use the easy way of the generic expand code
>>> (esp. if we eventually want to emit actual calls to memset - do we?)
>> 
>> If all these are guarded by “use_register_for_decl” already, the lhs should be fit into registers, 
>> Under such situation, I don’t think that we want to emit actual calls to memset. That’s too expensive.
>> 
>>> 
>>>>> You can then
>>>>> build the assignment from the pattern as
>>>>> 
>>>>> VIEW_CONVERT <reg-type> (lhs) = pattern_cst;
>>>> 
>>>> What’s the <reg_type> in the above? The type “alt_type” returned by “lang_hooks.type_for_mode(TREE_TYPE(lhs))?
>>>> Do I need to build “MODIFY_EXPR” for the above? 
>>> 
>>> Yes, the lang_hook.type_for_mode result and no, you could go through
>>> expand_assignment.
>> 
>> Okay. So, still use “expand_assigment” to expand it?
> 
> yes.

Thanks a lot.

Now, I am clean on this part -:)

Qing
> 
>>> 
>>>> lhs =  build1 (VIEW_CONVERT_EXPR, alt_type, lhs);
>>>> tree  final = build2 (MODIFY_EXPR, TREE_TYPE (alt_type), lhs, pattern);
>>>> 
>>>> Then how to expand this”final"? 
>>>>> 
>>>>> note that more RTL-expand-ish would be to simply expand 'lhs' and
>>>>> see whether it's a REG_P or a MEM_P and decide based on that.
>>>> 
>>>> You mean that the current RTL expansion will automatically expand LHS to memset route or assignment route based on whether
>>>> LHS is a REG_P or MEM_P? I don’t need to explicitly code for “expand_builtin_memset” or “expand_assign”?
>>> 
>>> No.  But you are inside the expander for the internal function call
>>> and this is expected to generate RTL.  You can simply generate
>>> RTL directly without "faking" new GENERIC calls or assignments and
>>> expanding those.
>>> 
>>> But lets not go there for now.
>> 
>> Okay. I see now.
>> 
>> Qing
>>> 
>>> 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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-16 16:48                                         ` Qing Zhao
@ 2021-08-17 15:04                                           ` Qing Zhao
  2021-08-17 20:40                                             ` Qing Zhao
  0 siblings, 1 reply; 60+ messages in thread
From: Qing Zhao @ 2021-08-17 15:04 UTC (permalink / raw)
  To: Richard Biener
  Cc: Jakub Jelinek, Richard Sandiford, Nick Alcock via Gcc-patches, Kees Cook



> On Aug 16, 2021, at 11:48 AM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> 
>>> From the above IR file after “FRE”, we can see that the major issue with this IR is:
>>> 
>>> The address taken auto variable “alt_reloc” has been completely replaced by the temporary variable “_1” in all
>>> the uses of the original “alt_reloc”. 
>> 
>> Well, this can happen with regular code as well, there's no need for
>> .DEFERRED_INIT.  This is the usual problem with reporting uninitialized
>> uses late.
>> 
>> IMHO this shouldn't be a blocker.  The goal of zero "regressions" wrt
>> -Wuninitialized isn't really achievable.
> 
> Okay. Sounds reasonable to me too.
> 
>> 
>>> The major problem with such IR is,  during uninitialized analysis phase, the original use of “alt_reloc” disappeared completely.
>>> So, the warning cannot be reported.
>>> 
>>> 
>>> My questions:
>>> 
>>> 1. Is it possible to get the original “alt_reloc” through the temporary variable “_1” with some available information recorded in the IR?
>>> 2. If not, then we have to record the relationship between “alt_reloc” and “_1” when the original “alt_reloc” is replaced by “_1” and get such relationship during
>>>   Uninitialized analysis phase.  Is this doable?
>> 
>> Well, you could add a fake argument to .DEFERRED_INIT for the purpose of
>> diagnostics.  The difficulty is to avoid tracking it as actual use so
>> you could for example pass a string with the declarations name though
>> this wouldn't give the association with the actual decl.
> Good suggestion, I can try this a little bit. 

I tried this yesterday, added the 4th argument to .DEFERRED_INIT as:

    1st argument: SIZE of the DECL;
    2nd argument: INIT_TYPE;
    3rd argument: IS_VLA, 0 NO, 1 YES;
+   4th argument: The NAME for the DECL;
 
-   as LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA)
+   as LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA, NAME)

+  tree name_node
+    = build_string_literal (IDENTIFIER_LENGTH (DECL_NAME (decl)),
+                           IDENTIFIER_POINTER (DECL_NAME (decl)));
 
   tree call = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
-                                           TREE_TYPE (decl), 3,
+                                           TREE_TYPE (decl), 4,
                                            decl_size, init_type_node,
-                                           is_vla_node);
+                                           is_vla_node, name_node);


And got the following IR in .uninit1 dump:


….

  _1 = .DEFERRED_INIT (4, 2, 0, &"alt_reloc"[0]);
  if (_1 != 0)
….


My questions:

1. Is “build_string_literal” the correct utility routine to use for this new argument? 
2. Will Such string literal nodes have potential other impact?

Qing

> 
>> 
>>> 3. Looks like that for “address taken” auto variable, if we have to introduce a new temporary variable and split the call to .DEFERRED_INIT into two:
>>> 
>>>     temp = .DEFERRED_INIT (4, 2, 0);
>>>     alt_reloc = temp;
>>> 
>>>  More issues might possible.
>>> 
>>> Any comments and suggestions on this issue?
>> 
>> I don't see any good possibilities that would not make optimizing code
>> as good as w/o .DEFERRED_INIT more difficult.  My stake here is always
>> that GCC is an optimizing compiler, not a static analysis engine and
>> thus I side with "broken" diagnostics and better optimization.
> That’s true and reasonable, too.
> 
> thanks.
> 
> Qing
>> 
>> Richard.
>> 
>>> Qing
>>> 
>>> j
>>>> On Aug 11, 2021, at 11:55 AM, Richard Biener <rguenther@suse.de> wrote:
>>>> 
>>>> On August 11, 2021 6:22:00 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>>>>> 
>>>>> 
>>>>>> On Aug 11, 2021, at 10:53 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>> 
>>>>>> On August 11, 2021 5:30:40 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>>>>>>> I modified the routine “gimple_add_init_for_auto_var” as the following:
>>>>>>> ====
>>>>>>> /* Generate initialization to automatic variable DECL based on INIT_TYPE.
>>>>>>> Build a call to internal const function DEFERRED_INIT:
>>>>>>> 1st argument: SIZE of the DECL;
>>>>>>> 2nd argument: INIT_TYPE;
>>>>>>> 3rd argument: IS_VLA, 0 NO, 1 YES;
>>>>>>> 
>>>>>>> as DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA).  */
>>>>>>> static void
>>>>>>> gimple_add_init_for_auto_var (tree decl,
>>>>>>>                          enum auto_init_type init_type,
>>>>>>>                          bool is_vla,
>>>>>>>                          gimple_seq *seq_p)
>>>>>>> {
>>>>>>> gcc_assert (VAR_P (decl) && !DECL_EXTERNAL (decl) && !TREE_STATIC (decl));
>>>>>>> gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>>>>>>> tree decl_size = TYPE_SIZE_UNIT (TREE_TYPE (decl));
>>>>>>> 
>>>>>>> tree init_type_node
>>>>>>> = build_int_cst (integer_type_node, (int) init_type);
>>>>>>> tree is_vla_node
>>>>>>> = build_int_cst (integer_type_node, (int) is_vla);
>>>>>>> 
>>>>>>> tree call = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
>>>>>>>                                        TREE_TYPE (decl), 3,
>>>>>>>                                        decl_size, init_type_node,
>>>>>>>                                        is_vla_node);
>>>>>>> 
>>>>>>> /* If this DECL is a VLA, a temporary address variable for it has been
>>>>>>> created, the replacement for DECL is recorded in DECL_VALUE_EXPR (decl),
>>>>>>> we should use it as the LHS of the call.  */
>>>>>>> 
>>>>>>> tree lhs_call
>>>>>>> = is_vla ? DECL_VALUE_EXPR (decl) : decl;
>>>>>>> gimplify_assign (lhs_call, call, seq_p);
>>>>>>> }
>>>>>>> 
>>>>>>> With this change, the current issue is resolved, the gimple dump now is:
>>>>>>> 
>>>>>>> (*arr.1) = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>> 
>>>>>>> However, there is another new issue:
>>>>>>> 
>>>>>>> For the following testing case:
>>>>>>> 
>>>>>>> ======
>>>>>>> [opc@qinzhao-ol8u3-x86 gcc]$ cat t.c
>>>>>>> int bar;
>>>>>>> 
>>>>>>> extern void decode_reloc(int *);
>>>>>>> 
>>>>>>> void testfunc()
>>>>>>> {
>>>>>>> int alt_reloc;
>>>>>>> 
>>>>>>> decode_reloc(&alt_reloc);
>>>>>>> 
>>>>>>> if (alt_reloc) /* { dg-warning "may be used uninitialized" } */
>>>>>>> bar = 42; 
>>>>>>> }
>>>>>>> =====
>>>>>>> 
>>>>>>> In the above, the auto var “alt_reloc” is address taken, then the gimple dump for it when compiled with -ftrivial-auto-var-init=zero is:
>>>>>>> 
>>>>>>> void testfunc ()
>>>>>>> {
>>>>>>> int alt_reloc;
>>>>>>> 
>>>>>>> try
>>>>>>> {
>>>>>>>  _1 = .DEFERRED_INIT (4, 2, 0);
>>>>>>>  alt_reloc = _1;
>>>>>>>  decode_reloc (&alt_reloc);
>>>>>>>  alt_reloc.0_2 = alt_reloc;
>>>>>>>  if (alt_reloc.0_2 != 0) goto <D.1949>; else goto <D.1950>;
>>>>>>>  <D.1949>:
>>>>>>>  bar = 42;
>>>>>>>  <D.1950>:
>>>>>>> }
>>>>>>> finally
>>>>>>> {
>>>>>>>  alt_reloc = {CLOBBER};
>>>>>>> }
>>>>>>> }
>>>>>>> 
>>>>>>> I.e, instead of the expected IR:
>>>>>>> 
>>>>>>> alt_reloc = .DEFERRED_INIT (4, 2, 0);
>>>>>>> 
>>>>>>> We got the following:
>>>>>>> 
>>>>>>> _1 = .DEFERRED_INIT (4, 2, 0);
>>>>>>>  alt_reloc = _1;
>>>>>>> 
>>>>>>> I guess the temp “_1” is created because “alt_reloc” is address taken. 
>>>>>> 
>>>>>> Yes and no. The reason is that alt_reloc is memory (because it is address taken) and that GIMPLE says that register typed stores need to use a is_gimple_val RHS which the call is not.
>>>>> 
>>>>> Okay.
>>>>>> 
>>>>>>> My questions:
>>>>>>> 
>>>>>>> Shall we accept such IR for .DEFERRED_INIT purpose when the auto var is address taken? 
>>>>>> 
>>>>>> I think so. Note it doesn't necessarily need address taking but any other reason that prevents SSA rewriting the variable suffices. 
>>>>> 
>>>>> You mean, in addition to “address taken”, there are other situations that will introduce such IR:
>>>>> 
>>>>> temp = .DEFERRED_INIT();
>>>>> auto_var = temp;
>>>>> 
>>>>> So, such IR is unavoidable and we have to handle it?
>>>> 
>>>> Yes. 
>>>> 
>>>>> If we have to handle it,  what’ the best way to do it?
>>>>> 
>>>>> The solution in my mind is:
>>>>> 1. During uninitialized analysis phase, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then decide that “auto_var” is uninitialized.
>>>> 
>>>> Yes. Basically if there's an artificial variable auto initialized you have to look at its uses. 
>>>> 
>>>>> 2. During RTL expansion, following the data flow to connect .DEFERRED_INIT to “auto_var”, and then delete “temp”, and then expand .DEFERRED_INIT to auto_var.
>>>> 
>>>> That shouldn't be necessary. You'd initialize a temporary register which is then copied to the real variable. That's good enough and should be optimized by the RTL pipeline. 
>>>> 
>>>>> Let me know your comments and suggestions on this.
>>>>> 
>>>>> 
>>>>>> 
>>>>>> The only other option is to force. DEFERED_INIT making the LHS address taken which I think could be achieved by passing it the address as argument instead of having a LHS. But let's not go down this route - it will have quite bad behavior on alias analysis and optimization. 
>>>>> 
>>>>> Okay.
>>>>> 
>>>>> Qing
>>>>>> 
>>>>>>> If so, “uninitialized analysis” phase need to be further adjusted to specially handle such IR. 
>>>>>>> 
>>>>>>> If not, what should we do when the auto var is address taken?
>>>>>>> 
>>>>>>> Thanks a lot.
>>>>>>> 
>>>>>>> Qing
>>>>>>> 
>>>>>>> 
>>>>>>>> On Aug 11, 2021, at 8:58 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>>> 
>>>>>>>> On Wed, 11 Aug 2021, Qing Zhao wrote:
>>>>>>>> 
>>>>>>>>> 
>>>>>>>>> 
>>>>>>>>>> On Aug 11, 2021, at 8:37 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>>>>> 
>>>>>>>>>> On Wed, 11 Aug 2021, Qing Zhao wrote:
>>>>>>>>>> 
>>>>>>>>>>> 
>>>>>>>>>>> 
>>>>>>>>>>>> On Aug 11, 2021, at 2:02 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>>>>>>> 
>>>>>>>>>>>> On Tue, 10 Aug 2021, Qing Zhao wrote:
>>>>>>>>>>>> 
>>>>>>>>>>>>> 
>>>>>>>>>>>>> 
>>>>>>>>>>>>>> On Aug 10, 2021, at 3:16 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> Hi, Richard,
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>> On Aug 10, 2021, at 10:22 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>>>> Especially in the VLA case but likely also in general (though unlikely
>>>>>>>>>>>>>>>>> since usually the receiver of initializations are simple enough).  I'd
>>>>>>>>>>>>>>>>> expect the VLA case end up as
>>>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>>>> *ptr_to_decl = .DEFERRED_INIT (...);
>>>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>>>> where *ptr_to_decl is the DECL_VALUE_EXPR of the decl.
>>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>>> So, for the following small testing case:
>>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>>> ====
>>>>>>>>>>>>>>>> extern void bar (int);
>>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>>> void foo(int n)
>>>>>>>>>>>>>>>> {
>>>>>>>>>>>>>>>> int arr[n];
>>>>>>>>>>>>>>>> bar (arr[2]);
>>>>>>>>>>>>>>>> return;
>>>>>>>>>>>>>>>> }
>>>>>>>>>>>>>>>> =====
>>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>>> If I compile it with -ftrivial-auto-var-init=zero -fdump-tree-gimple -S -o auto-init-11.s -fdump-rtl-expand, the *.gimple dump is:
>>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>>> =====
>>>>>>>>>>>>>>>> void foo (int n)
>>>>>>>>>>>>>>>> {
>>>>>>>>>>>>>>>> int n.0;
>>>>>>>>>>>>>>>> sizetype D.1950;
>>>>>>>>>>>>>>>> bitsizetype D.1951;
>>>>>>>>>>>>>>>> sizetype D.1952;
>>>>>>>>>>>>>>>> bitsizetype D.1953;
>>>>>>>>>>>>>>>> sizetype D.1954;
>>>>>>>>>>>>>>>> int[0:D.1950] * arr.1;
>>>>>>>>>>>>>>>> void * saved_stack.2;
>>>>>>>>>>>>>>>> int arr[0:D.1950] [value-expr: *arr.1];
>>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>>> saved_stack.2 = __builtin_stack_save ();
>>>>>>>>>>>>>>>> try
>>>>>>>>>>>>>>>> {
>>>>>>>>>>>>>>>> n.0 = n;
>>>>>>>>>>>>>>>> _1 = (long int) n.0;
>>>>>>>>>>>>>>>> _2 = _1 + -1;
>>>>>>>>>>>>>>>> _3 = (sizetype) _2;
>>>>>>>>>>>>>>>> D.1950 = _3;
>>>>>>>>>>>>>>>> _4 = (sizetype) n.0;
>>>>>>>>>>>>>>>> _5 = (bitsizetype) _4;
>>>>>>>>>>>>>>>> _6 = _5 * 32;
>>>>>>>>>>>>>>>> D.1951 = _6;
>>>>>>>>>>>>>>>> _7 = (sizetype) n.0;
>>>>>>>>>>>>>>>> _8 = _7 * 4;
>>>>>>>>>>>>>>>> D.1952 = _8;
>>>>>>>>>>>>>>>> _9 = (sizetype) n.0;
>>>>>>>>>>>>>>>> _10 = (bitsizetype) _9;
>>>>>>>>>>>>>>>> _11 = _10 * 32;
>>>>>>>>>>>>>>>> D.1953 = _11;
>>>>>>>>>>>>>>>> _12 = (sizetype) n.0;
>>>>>>>>>>>>>>>> _13 = _12 * 4;
>>>>>>>>>>>>>>>> D.1954 = _13;
>>>>>>>>>>>>>>>> arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>>>>>>>>>>>>> arr = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>>>>>>>>>> _14 = (*arr.1)[2];
>>>>>>>>>>>>>>>> bar (_14);
>>>>>>>>>>>>>>>> return;
>>>>>>>>>>>>>>>> }
>>>>>>>>>>>>>>>> finally
>>>>>>>>>>>>>>>> {
>>>>>>>>>>>>>>>> __builtin_stack_restore (saved_stack.2);
>>>>>>>>>>>>>>>> }
>>>>>>>>>>>>>>>> }
>>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>>> ====
>>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>>> You think that the above .DEFEERED_INIT is not correct?
>>>>>>>>>>>>>>>> It should be:
>>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952. 2, 1);
>>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>>> ?
>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>> Yes.
>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> I updated gimplify.c for VLA and now it emits the call to .DEFERRED_INIT as:
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> arr.1 = __builtin_alloca_with_align (D.1954, 32);
>>>>>>>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> However, this call triggered the assertion failure in verify_gimple_call of tree-cfg.c because the LHS is not a valid LHS. 
>>>>>>>>>>>>>> Then I modify tree-cfg.c as:
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
>>>>>>>>>>>>>> index 330eb7dd89bf..180d4f1f9e32 100644
>>>>>>>>>>>>>> --- a/gcc/tree-cfg.c
>>>>>>>>>>>>>> +++ b/gcc/tree-cfg.c
>>>>>>>>>>>>>> @@ -3375,7 +3375,11 @@ verify_gimple_call (gcall *stmt)
>>>>>>>>>>>>>> }
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> tree lhs = gimple_call_lhs (stmt);
>>>>>>>>>>>>>> +  /* For .DEFERRED_INIT call, the LHS might be an indirection of
>>>>>>>>>>>>>> +     a pointer for the VLA variable, which is not a valid LHS of
>>>>>>>>>>>>>> +     a gimple call, we ignore the asssertion on this.  */ 
>>>>>>>>>>>>>> if (lhs
>>>>>>>>>>>>>> +      && (!gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
>>>>>>>>>>>>>> && (!is_gimple_reg (lhs)
>>>>>>>>>>>>>>   && (!is_gimple_lvalue (lhs)
>>>>>>>>>>>>>>       || verify_types_in_gimple_reference
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> The assertion failure in tree-cfg.c got resolved, but I got another assertion failure in operands_scanner::get_expr_operands (tree *expr_p, int flags), line 945:
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> 939   /* If we get here, something has gone wrong.  */
>>>>>>>>>>>>>> 940   if (flag_checking)
>>>>>>>>>>>>>> 941     {
>>>>>>>>>>>>>> 942       fprintf (stderr, "unhandled expression in get_expr_operands():\n");
>>>>>>>>>>>>>> 943       debug_tree (expr);
>>>>>>>>>>>>>> 944       fputs ("\n", stderr);
>>>>>>>>>>>>>> 945       gcc_unreachable ();
>>>>>>>>>>>>>> 946     }
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> Looks like that  the gimple statement:
>>>>>>>>>>>>>> *arr.1 = .DEFERRED_INIT (D.1952, 2, 1);
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> Is not valid.  i.e, the LHS should not be an indirection to a pointer. 
>>>>>>>>>>>>>> 
>>>>>>>>>>>>>> How to resolve this issue?
>>>>>>>>>>>> 
>>>>>>>>>>>> It sounds like the LHS is an INDIRECT_REF maybe?  That means it's
>>>>>>>>>>>> still not properly gimplified because it should end up as a MEM_REF
>>>>>>>>>>>> instead.
>>>>>>>>>>>> 
>>>>>>>>>>>> But I'm just guessing here ... if you are in a debugger then you can
>>>>>>>>>>>> invoke debug_tree (lhs) in the inferior to see what it exactly is
>>>>>>>>>>>> at the point of the failure.
>>>>>>>>>>> 
>>>>>>>>>>> Yes, it’s an INDIRECT_REF at the point of the failure even though I added a 
>>>>>>>>>>> 
>>>>>>>>>>> gimplify_var_or_parm_decl  (lhs) 
>>>>>>>>>> 
>>>>>>>>>> I think the easiest is to build the .DEFERRED_INIT as GENERIC
>>>>>>>>>> and use gimplify_assign () to gimplify and add the result
>>>>>>>>>> to the sequence.  Thus, build a GENERIC CALL_EXPR and then
>>>>>>>>>> gimplify_assign (lhs, call_expr, seq);
>>>>>>>>> 
>>>>>>>>> Which utility routine is used to build an Internal generic call?
>>>>>>>>> Currently, I used “gimple_build_call_internal” to build this internal gimple call.
>>>>>>>>> 
>>>>>>>>> For the generic call, shall I use “build_call_expr_loc” ? 
>>>>>>>> 
>>>>>>>> For example look at build_asan_poison_call_expr which does such thing
>>>>>>>> for ASAN poison internal function call insertion at gimplification time.
>>>>>>>> 
>>>>>>>> Richard.
>>>>>>>> 
>>>>>>>>> Qing
>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>>> Richard.
>>>>>>>>>> 
>>>>>>>>>>> Qing
>>>>>>>>>>> 
>>>>>>>>>>>> 
>>>>>>>>>>>>> I came up with the following solution:
>>>>>>>>>>>>> 
>>>>>>>>>>>>> Define the IFN_DEFERRED_INIT function as:
>>>>>>>>>>>>> 
>>>>>>>>>>>>> LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA);
>>>>>>>>>>>>> 
>>>>>>>>>>>>> if IS_VLA is false, the LHS is the DECL itself,
>>>>>>>>>>>>> if IS_VLA is true, the LHS is the pointer to this DECL that created by
>>>>>>>>>>>>> gimplify_vla_decl.
>>>>>>>>>>>>> 
>>>>>>>>>>>>> 
>>>>>>>>>>>>> The benefit of this solution are:
>>>>>>>>>>>>> 
>>>>>>>>>>>>> 1. Resolved the invalid IR issue;
>>>>>>>>>>>>> 2. The call stmt carries the address of the VLA natually;
>>>>>>>>>>>>> 
>>>>>>>>>>>>> The issue with this solution is:
>>>>>>>>>>>>> 
>>>>>>>>>>>>> For VLA and non-VLA, the LHS will be different, 
>>>>>>>>>>>>> 
>>>>>>>>>>>>> Do you see any other potential issues with this solution?
>>>>>>>>>>>>> 
>>>>>>>>>>>>> thanks.
>>>>>>>>>>>>> 
>>>>>>>>>>>>> Qing
>>>>>>>>>>>>> 
>>>>>>>>>>>>> 
>>>>>>>>>>>>> 
>>>>>>>>>>>>> 
>>>>>>>>>>>>> 
>>>>>>>>>>>> 
>>>>>>>>>>>> -- 
>>>>>>>>>>>> Richard Biener <rguenther@suse.de>
>>>>>>>>>>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>>>>>>>>>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>>>>>>>>>>> 
>>>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>>> -- 
>>>>>>>>>> Richard Biener <rguenther@suse.de>
>>>>>>>>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>>>>>>>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>>>>>>>>> 
>>>>>>>>> 
>>>>>>>> 
>>>>>>>> -- 
>>>>>>>> Richard Biener <rguenther@suse.de>
>>>>>>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>>>>>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>>> 
>>> 
>> 
>> -- 
>> 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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-17 14:50           ` Qing Zhao
@ 2021-08-17 16:08             ` Qing Zhao
  2021-08-18  7:15               ` Richard Biener
  0 siblings, 1 reply; 60+ messages in thread
From: Qing Zhao @ 2021-08-17 16:08 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook



> On Aug 17, 2021, at 9:50 AM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> 
> 
> 
>> On Aug 17, 2021, at 3:29 AM, Richard Biener <rguenther@suse.de> wrote:
>> 
>> On Mon, 16 Aug 2021, Qing Zhao wrote:
>> 
>>> My current code for expand_DEFERRED_INIT is like the following, could you check and see whether there is any issue for it:
>>> 
>>> #define INIT_PATTERN_VALUE  0xFE
>>> static void
>>> expand_DEFERRED_INIT (internal_fn, gcall *stmt)
>>> {
>>> tree lhs = gimple_call_lhs (stmt);
>>> tree var_size = gimple_call_arg (stmt, 0);
>>> enum auto_init_type init_type
>>>   = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
>>> bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
>>> 
>>> tree var_type = TREE_TYPE (lhs);
>>> gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>>> 
>>> if (is_vla || (!use_register_for_decl (lhs)))
>>>   {
>>>     if (TREE_CODE (lhs) == SSA_NAME)
>>>       lhs = SSA_NAME_VAR (lhs);
>> 
>> this should not be necessary (in fact you shouldn't see a SSA_NAME
>> here, if you do then using SSA_NAME_VAR is wrong)
> You mean during RTL expansion phase, all SSA_NAMEs are gone already?

Actually, the lhs could be SSA_NAME here, 

Breakpoint 1, expand_DEFERRED_INIT (stmt=0x7fffe96ae348) at ../../latest-gcc/gcc/internal-fn.c:3021
3021	      mark_addressable (lhs);
(gdb) call debug_tree(lhs)
 <ssa_name 0x7fffe9584e58
    type <real_type 0x7fffe959b2a0 float sizes-gimplified SF
        size <integer_cst 0x7fffe9579f48 constant 32>
        unit-size <integer_cst 0x7fffe9579f60 constant 4>
        align:32 warn_if_not_align:0 symtab:0 alias-set 2 canonical-type 0x7fffe959b2a0 precision:32
        pointer_to_this <pointer_type 0x7fffe959b7e0>>
    visited var <var_decl 0x7ffff7ff7bd0 temp1>
    def_stmt temp1_5 = .DEFERRED_INIT (4, 2, 0, &"temp1"[0]);
    version:5>

 when I deleted:

 if (TREE_CODE (lhs) == SSA_NAME
   lhs = SSA_NAME_VAR (lhs);

Many testing cases failed with internal compiler error:

/home/opc/Work/GCC/latest-gcc/gcc/testsuite/c-c++-common/auto-init-3.c:9:9: internal compiler error: in expand_expr_addr_expr_1, at expr.c:8437
0xe237aa expand_expr_addr_expr_1
	../../latest-gcc/gcc/expr.c:8437
0xe24059 expand_expr_addr_expr
	../../latest-gcc/gcc/expr.c:8525
0xe32b56 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
	../../latest-gcc/gcc/expr.c:11741
0xe2da52 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
	../../latest-gcc/gcc/expr.c:10777
0xe24706 expand_expr_real(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
	../../latest-gcc/gcc/expr.c:8713
0xc13f15 expand_expr
	../../latest-gcc/gcc/expr.h:301
0xc17acb get_memory_rtx
	../../latest-gcc/gcc/builtins.c:1370
0xc2223d expand_builtin_memset_args
	../../latest-gcc/gcc/builtins.c:4102
0xc21a20 expand_builtin_memset(tree_node*, rtx_def*, machine_mode)
	../../latest-gcc/gcc/builtins.c:3886
0xfb5c85 expand_DEFERRED_INIT
	../../latest-gcc/gcc/internal-fn.c:3031


So, did I do anything wrong?

Qing

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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-17 15:04                                           ` Qing Zhao
@ 2021-08-17 20:40                                             ` Qing Zhao
  2021-08-18  7:19                                               ` Richard Biener
  0 siblings, 1 reply; 60+ messages in thread
From: Qing Zhao @ 2021-08-17 20:40 UTC (permalink / raw)
  To: Richard Biener, kees Cook
  Cc: Jakub Jelinek, Richard Sandiford, Nick Alcock via Gcc-patches, Kees Cook



> On Aug 17, 2021, at 10:04 AM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> 
> 
> 
>> On Aug 16, 2021, at 11:48 AM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>> 
>>>> From the above IR file after “FRE”, we can see that the major issue with this IR is:
>>>> 
>>>> The address taken auto variable “alt_reloc” has been completely replaced by the temporary variable “_1” in all
>>>> the uses of the original “alt_reloc”. 
>>> 
>>> Well, this can happen with regular code as well, there's no need for
>>> .DEFERRED_INIT.  This is the usual problem with reporting uninitialized
>>> uses late.
>>> 
>>> IMHO this shouldn't be a blocker.  The goal of zero "regressions" wrt
>>> -Wuninitialized isn't really achievable.
>> 
>> Okay. Sounds reasonable to me too.
>> 
>>> 
>>>> The major problem with such IR is,  during uninitialized analysis phase, the original use of “alt_reloc” disappeared completely.
>>>> So, the warning cannot be reported.
>>>> 
>>>> 
>>>> My questions:
>>>> 
>>>> 1. Is it possible to get the original “alt_reloc” through the temporary variable “_1” with some available information recorded in the IR?
>>>> 2. If not, then we have to record the relationship between “alt_reloc” and “_1” when the original “alt_reloc” is replaced by “_1” and get such relationship during
>>>>  Uninitialized analysis phase.  Is this doable?
>>> 
>>> Well, you could add a fake argument to .DEFERRED_INIT for the purpose of
>>> diagnostics.  The difficulty is to avoid tracking it as actual use so
>>> you could for example pass a string with the declarations name though
>>> this wouldn't give the association with the actual decl.
>> Good suggestion, I can try this a little bit. 
> 
> I tried this yesterday, added the 4th argument to .DEFERRED_INIT as:
> 
>    1st argument: SIZE of the DECL;
>    2nd argument: INIT_TYPE;
>    3rd argument: IS_VLA, 0 NO, 1 YES;
> +   4th argument: The NAME for the DECL;
> 
> -   as LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA)
> +   as LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA, NAME)
> 
> +  tree name_node
> +    = build_string_literal (IDENTIFIER_LENGTH (DECL_NAME (decl)),
> +                           IDENTIFIER_POINTER (DECL_NAME (decl)));
> 
>   tree call = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
> -                                           TREE_TYPE (decl), 3,
> +                                           TREE_TYPE (decl), 4,
>                                            decl_size, init_type_node,
> -                                           is_vla_node);
> +                                           is_vla_node, name_node);
> 
> 
> And got the following IR in .uninit1 dump:
> 
> 
> ….
> 
>  _1 = .DEFERRED_INIT (4, 2, 0, &"alt_reloc"[0]);
>  if (_1 != 0)
> ….
> 
> 
> My questions:
> 
> 1. Is “build_string_literal” the correct utility routine to use for this new argument? 
> 2. Will Such string literal nodes have potential other impact?

I tried to get the 4th argument from the call to .DEFERED_INIT during uninitialized variable analysis in tree-ssa-uninit.c:

@@ -197,18 +197,25 @@ warn_uninit (enum opt_code wc, tree t, tree expr, tree var,
      the COMPLEX_EXPRs real part in that case.  See PR71581.  */
   if (expr == NULL_TREE
       && var == NULL_TREE
-      && SSA_NAME_VAR (t) == NULL_TREE
-      && is_gimple_assign (SSA_NAME_DEF_STMT (t))
-      && gimple_assign_rhs_code (SSA_NAME_DEF_STMT (t)) == COMPLEX_EXPR)
-    {
-      tree v = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (t));
-      if (TREE_CODE (v) == SSA_NAME
-         && has_undefined_value_p (v)
-         && zerop (gimple_assign_rhs2 (SSA_NAME_DEF_STMT (t))))
+      && SSA_NAME_VAR (t) == NULL_TREE)
+    {
+      if (is_gimple_assign (SSA_NAME_DEF_STMT (t))
+         && (gimple_assign_rhs_code (SSA_NAME_DEF_STMT (t)) == COMPLEX_EXPR))
        {
-         expr = SSA_NAME_VAR (v);
-         var = expr;
+         tree v = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (t));
+         if (TREE_CODE (v) == SSA_NAME
+             && has_undefined_value_p (v)
+             && zerop (gimple_assign_rhs2 (SSA_NAME_DEF_STMT (t))))
+           {
+             expr = SSA_NAME_VAR (v);
+             var = expr;
+           }
        }
+      else if (gimple_call_internal_p (SSA_NAME_DEF_STMT (t), IFN_DEFERRED_INIT))
+      {
+       expr = gimple_call_arg (SSA_NAME_DEF_STMT (t), 3);
+       var = expr;
+      }
     }

However, this 4th argument is not a regular variable, it’s just an ADDR_EXPR that includes the constant string for the name of 
the deleted variable. 
If we’d like to report the warning based on this ADDR_EXPR, a complete new code to report the warnings other than the current one that based on 
“Variables” need to be added, this might make the code very ugly. 

My questions:

1. Is there better way to do this?
1. As you mentioned before, it’s very unrealistic to meet the goal of “zero regression” for -Wuninitialized, can we leave this part of work in a later patch to improve
The warning for “address taken” auto variables?


Thanks.

Qing

> 
> Qing
> 


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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-17 16:08             ` Qing Zhao
@ 2021-08-18  7:15               ` Richard Biener
  2021-08-18 16:02                 ` Qing Zhao
  0 siblings, 1 reply; 60+ messages in thread
From: Richard Biener @ 2021-08-18  7:15 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook

On Tue, 17 Aug 2021, Qing Zhao wrote:

> 
> 
> > On Aug 17, 2021, at 9:50 AM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> > 
> > 
> > 
> >> On Aug 17, 2021, at 3:29 AM, Richard Biener <rguenther@suse.de> wrote:
> >> 
> >> On Mon, 16 Aug 2021, Qing Zhao wrote:
> >> 
> >>> My current code for expand_DEFERRED_INIT is like the following, could you check and see whether there is any issue for it:
> >>> 
> >>> #define INIT_PATTERN_VALUE  0xFE
> >>> static void
> >>> expand_DEFERRED_INIT (internal_fn, gcall *stmt)
> >>> {
> >>> tree lhs = gimple_call_lhs (stmt);
> >>> tree var_size = gimple_call_arg (stmt, 0);
> >>> enum auto_init_type init_type
> >>>   = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
> >>> bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
> >>> 
> >>> tree var_type = TREE_TYPE (lhs);
> >>> gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
> >>> 
> >>> if (is_vla || (!use_register_for_decl (lhs)))
> >>>   {
> >>>     if (TREE_CODE (lhs) == SSA_NAME)
> >>>       lhs = SSA_NAME_VAR (lhs);
> >> 
> >> this should not be necessary (in fact you shouldn't see a SSA_NAME
> >> here, if you do then using SSA_NAME_VAR is wrong)
> > You mean during RTL expansion phase, all SSA_NAMEs are gone already?
> 
> Actually, the lhs could be SSA_NAME here, 
> 
> Breakpoint 1, expand_DEFERRED_INIT (stmt=0x7fffe96ae348) at ../../latest-gcc/gcc/internal-fn.c:3021
> 3021	      mark_addressable (lhs);
> (gdb) call debug_tree(lhs)
>  <ssa_name 0x7fffe9584e58
>     type <real_type 0x7fffe959b2a0 float sizes-gimplified SF
>         size <integer_cst 0x7fffe9579f48 constant 32>
>         unit-size <integer_cst 0x7fffe9579f60 constant 4>
>         align:32 warn_if_not_align:0 symtab:0 alias-set 2 canonical-type 0x7fffe959b2a0 precision:32
>         pointer_to_this <pointer_type 0x7fffe959b7e0>>
>     visited var <var_decl 0x7ffff7ff7bd0 temp1>
>     def_stmt temp1_5 = .DEFERRED_INIT (4, 2, 0, &"temp1"[0]);
>     version:5>
> 
>  when I deleted:
> 
>  if (TREE_CODE (lhs) == SSA_NAME
>    lhs = SSA_NAME_VAR (lhs);

but then using SSA_NAME_VAR is broken.  I suspect use_register_for_decl
isn't the correct thing to look at.  I think we need to look at what
the LHS expanded to if it is a SSA_VAR_P (that includes SSA names
but also plain DECLs but not what we get from VLAs where we'd see
*ptr).  So sth like

  bool reg_lhs;
  if (SSA_VAR_P (lhs))
    {
      rtx tem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
      reg_lhs = !MEM_P (tem);
      /* If not MEM_P reg_lhs should be REG_P or SUBREG_P (but maybe
         also CONCAT or lowpart...?)  */
    }
  else
    {
      gcc_assert (is_vla);
      reg_lhs = false;
    }

  if (!reg_lhs)
    memset path
  else
    expand_assignment path

> Many testing cases failed with internal compiler error:
> 
> /home/opc/Work/GCC/latest-gcc/gcc/testsuite/c-c++-common/auto-init-3.c:9:9: internal compiler error: in expand_expr_addr_expr_1, at expr.c:8437
> 0xe237aa expand_expr_addr_expr_1
> 	../../latest-gcc/gcc/expr.c:8437
> 0xe24059 expand_expr_addr_expr
> 	../../latest-gcc/gcc/expr.c:8525
> 0xe32b56 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
> 	../../latest-gcc/gcc/expr.c:11741
> 0xe2da52 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
> 	../../latest-gcc/gcc/expr.c:10777
> 0xe24706 expand_expr_real(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
> 	../../latest-gcc/gcc/expr.c:8713
> 0xc13f15 expand_expr
> 	../../latest-gcc/gcc/expr.h:301
> 0xc17acb get_memory_rtx
> 	../../latest-gcc/gcc/builtins.c:1370
> 0xc2223d expand_builtin_memset_args
> 	../../latest-gcc/gcc/builtins.c:4102
> 0xc21a20 expand_builtin_memset(tree_node*, rtx_def*, machine_mode)
> 	../../latest-gcc/gcc/builtins.c:3886
> 0xfb5c85 expand_DEFERRED_INIT
> 	../../latest-gcc/gcc/internal-fn.c:3031
> 
> 
> So, did I do anything wrong?
> 
> Qing

-- 
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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-17 20:40                                             ` Qing Zhao
@ 2021-08-18  7:19                                               ` Richard Biener
  2021-08-18 14:39                                                 ` Qing Zhao
  0 siblings, 1 reply; 60+ messages in thread
From: Richard Biener @ 2021-08-18  7:19 UTC (permalink / raw)
  To: Qing Zhao
  Cc: kees Cook, Jakub Jelinek, Richard Sandiford, Nick Alcock via Gcc-patches

On Tue, 17 Aug 2021, Qing Zhao wrote:

> 
> 
> > On Aug 17, 2021, at 10:04 AM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> > 
> > 
> > 
> >> On Aug 16, 2021, at 11:48 AM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> >> 
> >>>> From the above IR file after “FRE”, we can see that the major issue with this IR is:
> >>>> 
> >>>> The address taken auto variable “alt_reloc” has been completely replaced by the temporary variable “_1” in all
> >>>> the uses of the original “alt_reloc”. 
> >>> 
> >>> Well, this can happen with regular code as well, there's no need for
> >>> .DEFERRED_INIT.  This is the usual problem with reporting uninitialized
> >>> uses late.
> >>> 
> >>> IMHO this shouldn't be a blocker.  The goal of zero "regressions" wrt
> >>> -Wuninitialized isn't really achievable.
> >> 
> >> Okay. Sounds reasonable to me too.
> >> 
> >>> 
> >>>> The major problem with such IR is,  during uninitialized analysis phase, the original use of “alt_reloc” disappeared completely.
> >>>> So, the warning cannot be reported.
> >>>> 
> >>>> 
> >>>> My questions:
> >>>> 
> >>>> 1. Is it possible to get the original “alt_reloc” through the temporary variable “_1” with some available information recorded in the IR?
> >>>> 2. If not, then we have to record the relationship between “alt_reloc” and “_1” when the original “alt_reloc” is replaced by “_1” and get such relationship during
> >>>>  Uninitialized analysis phase.  Is this doable?
> >>> 
> >>> Well, you could add a fake argument to .DEFERRED_INIT for the purpose of
> >>> diagnostics.  The difficulty is to avoid tracking it as actual use so
> >>> you could for example pass a string with the declarations name though
> >>> this wouldn't give the association with the actual decl.
> >> Good suggestion, I can try this a little bit. 
> > 
> > I tried this yesterday, added the 4th argument to .DEFERRED_INIT as:
> > 
> >    1st argument: SIZE of the DECL;
> >    2nd argument: INIT_TYPE;
> >    3rd argument: IS_VLA, 0 NO, 1 YES;
> > +   4th argument: The NAME for the DECL;
> > 
> > -   as LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA)
> > +   as LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA, NAME)
> > 
> > +  tree name_node
> > +    = build_string_literal (IDENTIFIER_LENGTH (DECL_NAME (decl)),
> > +                           IDENTIFIER_POINTER (DECL_NAME (decl)));
> > 
> >   tree call = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
> > -                                           TREE_TYPE (decl), 3,
> > +                                           TREE_TYPE (decl), 4,
> >                                            decl_size, init_type_node,
> > -                                           is_vla_node);
> > +                                           is_vla_node, name_node);
> > 
> > 
> > And got the following IR in .uninit1 dump:
> > 
> > 
> > ….
> > 
> >  _1 = .DEFERRED_INIT (4, 2, 0, &"alt_reloc"[0]);
> >  if (_1 != 0)
> > ….
> > 
> > 
> > My questions:
> > 
> > 1. Is “build_string_literal” the correct utility routine to use for this new argument? 
> > 2. Will Such string literal nodes have potential other impact?
> 
> I tried to get the 4th argument from the call to .DEFERED_INIT during uninitialized variable analysis in tree-ssa-uninit.c:
> 
> @@ -197,18 +197,25 @@ warn_uninit (enum opt_code wc, tree t, tree expr, tree var,
>       the COMPLEX_EXPRs real part in that case.  See PR71581.  */
>    if (expr == NULL_TREE
>        && var == NULL_TREE
> -      && SSA_NAME_VAR (t) == NULL_TREE
> -      && is_gimple_assign (SSA_NAME_DEF_STMT (t))
> -      && gimple_assign_rhs_code (SSA_NAME_DEF_STMT (t)) == COMPLEX_EXPR)
> -    {
> -      tree v = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (t));
> -      if (TREE_CODE (v) == SSA_NAME
> -         && has_undefined_value_p (v)
> -         && zerop (gimple_assign_rhs2 (SSA_NAME_DEF_STMT (t))))
> +      && SSA_NAME_VAR (t) == NULL_TREE)
> +    {
> +      if (is_gimple_assign (SSA_NAME_DEF_STMT (t))
> +         && (gimple_assign_rhs_code (SSA_NAME_DEF_STMT (t)) == COMPLEX_EXPR))
>         {
> -         expr = SSA_NAME_VAR (v);
> -         var = expr;
> +         tree v = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (t));
> +         if (TREE_CODE (v) == SSA_NAME
> +             && has_undefined_value_p (v)
> +             && zerop (gimple_assign_rhs2 (SSA_NAME_DEF_STMT (t))))
> +           {
> +             expr = SSA_NAME_VAR (v);
> +             var = expr;
> +           }
>         }
> +      else if (gimple_call_internal_p (SSA_NAME_DEF_STMT (t), IFN_DEFERRED_INIT))
> +      {
> +       expr = gimple_call_arg (SSA_NAME_DEF_STMT (t), 3);
> +       var = expr;
> +      }
>      }
> 
> However, this 4th argument is not a regular variable, it’s just an ADDR_EXPR that includes the constant string for the name of 
> the deleted variable. 
> If we’d like to report the warning based on this ADDR_EXPR, a complete new code to report the warnings other than the current one that based on 
> “Variables” need to be added, this might make the code very ugly. 
>
> My questions:
> 
> 1. Is there better way to do this?

Adding a variable as extra argument won't work, so no, I don't see a nice
way of carrying the extra information.  Btw, if you make sure to set
the location of the .DEFERRED_INIT call to the DECL_SOURCE_LOCATION
of the decl we initialize we should be able to diagnose sth like

warning: variable is used uninitialized
note: variable declared here

and point to the correct declartion point which should reveal the
variable name (to the user, not to the compiler).

> 1. As you mentioned before, it’s very unrealistic to meet the goal of “zero regression” for -Wuninitialized, can we leave this part of work in a later patch to improve
> The warning for “address taken” auto variables?

Yes, as said, I'd simply ignore this particular issue for now since I
don't see a good way to fix it.

Richard.

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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-18  7:19                                               ` Richard Biener
@ 2021-08-18 14:39                                                 ` Qing Zhao
  0 siblings, 0 replies; 60+ messages in thread
From: Qing Zhao @ 2021-08-18 14:39 UTC (permalink / raw)
  To: Richard Biener
  Cc: kees Cook, Jakub Jelinek, Richard Sandiford, Nick Alcock via Gcc-patches



> On Aug 18, 2021, at 2:19 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Tue, 17 Aug 2021, Qing Zhao wrote:
> 
>> 
>> 
>>> On Aug 17, 2021, at 10:04 AM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>> 
>>> 
>>> 
>>>> On Aug 16, 2021, at 11:48 AM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>>> 
>>>>>> From the above IR file after “FRE”, we can see that the major issue with this IR is:
>>>>>> 
>>>>>> The address taken auto variable “alt_reloc” has been completely replaced by the temporary variable “_1” in all
>>>>>> the uses of the original “alt_reloc”. 
>>>>> 
>>>>> Well, this can happen with regular code as well, there's no need for
>>>>> .DEFERRED_INIT.  This is the usual problem with reporting uninitialized
>>>>> uses late.
>>>>> 
>>>>> IMHO this shouldn't be a blocker.  The goal of zero "regressions" wrt
>>>>> -Wuninitialized isn't really achievable.
>>>> 
>>>> Okay. Sounds reasonable to me too.
>>>> 
>>>>> 
>>>>>> The major problem with such IR is,  during uninitialized analysis phase, the original use of “alt_reloc” disappeared completely.
>>>>>> So, the warning cannot be reported.
>>>>>> 
>>>>>> 
>>>>>> My questions:
>>>>>> 
>>>>>> 1. Is it possible to get the original “alt_reloc” through the temporary variable “_1” with some available information recorded in the IR?
>>>>>> 2. If not, then we have to record the relationship between “alt_reloc” and “_1” when the original “alt_reloc” is replaced by “_1” and get such relationship during
>>>>>> Uninitialized analysis phase.  Is this doable?
>>>>> 
>>>>> Well, you could add a fake argument to .DEFERRED_INIT for the purpose of
>>>>> diagnostics.  The difficulty is to avoid tracking it as actual use so
>>>>> you could for example pass a string with the declarations name though
>>>>> this wouldn't give the association with the actual decl.
>>>> Good suggestion, I can try this a little bit. 
>>> 
>>> I tried this yesterday, added the 4th argument to .DEFERRED_INIT as:
>>> 
>>>   1st argument: SIZE of the DECL;
>>>   2nd argument: INIT_TYPE;
>>>   3rd argument: IS_VLA, 0 NO, 1 YES;
>>> +   4th argument: The NAME for the DECL;
>>> 
>>> -   as LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA)
>>> +   as LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA, NAME)
>>> 
>>> +  tree name_node
>>> +    = build_string_literal (IDENTIFIER_LENGTH (DECL_NAME (decl)),
>>> +                           IDENTIFIER_POINTER (DECL_NAME (decl)));
>>> 
>>>  tree call = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
>>> -                                           TREE_TYPE (decl), 3,
>>> +                                           TREE_TYPE (decl), 4,
>>>                                           decl_size, init_type_node,
>>> -                                           is_vla_node);
>>> +                                           is_vla_node, name_node);
>>> 
>>> 
>>> And got the following IR in .uninit1 dump:
>>> 
>>> 
>>> ….
>>> 
>>> _1 = .DEFERRED_INIT (4, 2, 0, &"alt_reloc"[0]);
>>> if (_1 != 0)
>>> ….
>>> 
>>> 
>>> My questions:
>>> 
>>> 1. Is “build_string_literal” the correct utility routine to use for this new argument? 
>>> 2. Will Such string literal nodes have potential other impact?
>> 
>> I tried to get the 4th argument from the call to .DEFERED_INIT during uninitialized variable analysis in tree-ssa-uninit.c:
>> 
>> @@ -197,18 +197,25 @@ warn_uninit (enum opt_code wc, tree t, tree expr, tree var,
>>      the COMPLEX_EXPRs real part in that case.  See PR71581.  */
>>   if (expr == NULL_TREE
>>       && var == NULL_TREE
>> -      && SSA_NAME_VAR (t) == NULL_TREE
>> -      && is_gimple_assign (SSA_NAME_DEF_STMT (t))
>> -      && gimple_assign_rhs_code (SSA_NAME_DEF_STMT (t)) == COMPLEX_EXPR)
>> -    {
>> -      tree v = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (t));
>> -      if (TREE_CODE (v) == SSA_NAME
>> -         && has_undefined_value_p (v)
>> -         && zerop (gimple_assign_rhs2 (SSA_NAME_DEF_STMT (t))))
>> +      && SSA_NAME_VAR (t) == NULL_TREE)
>> +    {
>> +      if (is_gimple_assign (SSA_NAME_DEF_STMT (t))
>> +         && (gimple_assign_rhs_code (SSA_NAME_DEF_STMT (t)) == COMPLEX_EXPR))
>>        {
>> -         expr = SSA_NAME_VAR (v);
>> -         var = expr;
>> +         tree v = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (t));
>> +         if (TREE_CODE (v) == SSA_NAME
>> +             && has_undefined_value_p (v)
>> +             && zerop (gimple_assign_rhs2 (SSA_NAME_DEF_STMT (t))))
>> +           {
>> +             expr = SSA_NAME_VAR (v);
>> +             var = expr;
>> +           }
>>        }
>> +      else if (gimple_call_internal_p (SSA_NAME_DEF_STMT (t), IFN_DEFERRED_INIT))
>> +      {
>> +       expr = gimple_call_arg (SSA_NAME_DEF_STMT (t), 3);
>> +       var = expr;
>> +      }
>>     }
>> 
>> However, this 4th argument is not a regular variable, it’s just an ADDR_EXPR that includes the constant string for the name of 
>> the deleted variable. 
>> If we’d like to report the warning based on this ADDR_EXPR, a complete new code to report the warnings other than the current one that based on 
>> “Variables” need to be added, this might make the code very ugly. 
>> 
>> My questions:
>> 
>> 1. Is there better way to do this?
> 
> Adding a variable as extra argument won't work, so no, I don't see a nice
> way of carrying the extra information.  Btw, if you make sure to set
> the location of the .DEFERRED_INIT call to the DECL_SOURCE_LOCATION
> of the decl we initialize,

This should be easy to do.

> we should be able to diagnose sth like
> 
> warning: variable is used uninitialized
> note: variable declared here

I.e, report the warnings without the name of the variable?
> 
> and point to the correct declartion point which should reveal the
> variable name (to the user, not to the compiler).
> 
>> 1. As you mentioned before, it’s very unrealistic to meet the goal of “zero regression” for -Wuninitialized, can we leave this part of work in a later patch to improve
>> The warning for “address taken” auto variables?
> 
> Yes, as said, I'd simply ignore this particular issue for now since I
> don't see a good way to fix it.

Okay, I will just ignore this issue for now and resolve it in a later patch.

How about the testing cases that are currently failed due to this issue? Should I keep them but mark them as expected failure?

Qing

> 
> Richard.


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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-18  7:15               ` Richard Biener
@ 2021-08-18 16:02                 ` Qing Zhao
  2021-08-19  9:00                   ` Richard Biener
  0 siblings, 1 reply; 60+ messages in thread
From: Qing Zhao @ 2021-08-18 16:02 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook



> On Aug 18, 2021, at 2:15 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Tue, 17 Aug 2021, Qing Zhao wrote:
> 
>> 
>> 
>>> On Aug 17, 2021, at 9:50 AM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>> 
>>> 
>>> 
>>>> On Aug 17, 2021, at 3:29 AM, Richard Biener <rguenther@suse.de> wrote:
>>>> 
>>>> On Mon, 16 Aug 2021, Qing Zhao wrote:
>>>> 
>>>>> My current code for expand_DEFERRED_INIT is like the following, could you check and see whether there is any issue for it:
>>>>> 
>>>>> #define INIT_PATTERN_VALUE  0xFE
>>>>> static void
>>>>> expand_DEFERRED_INIT (internal_fn, gcall *stmt)
>>>>> {
>>>>> tree lhs = gimple_call_lhs (stmt);
>>>>> tree var_size = gimple_call_arg (stmt, 0);
>>>>> enum auto_init_type init_type
>>>>>  = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
>>>>> bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
>>>>> 
>>>>> tree var_type = TREE_TYPE (lhs);
>>>>> gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>>>>> 
>>>>> if (is_vla || (!use_register_for_decl (lhs)))
>>>>>  {
>>>>>    if (TREE_CODE (lhs) == SSA_NAME)
>>>>>      lhs = SSA_NAME_VAR (lhs);
>>>> 
>>>> this should not be necessary (in fact you shouldn't see a SSA_NAME
>>>> here, if you do then using SSA_NAME_VAR is wrong)
>>> You mean during RTL expansion phase, all SSA_NAMEs are gone already?
>> 
>> Actually, the lhs could be SSA_NAME here, 
>> 
>> Breakpoint 1, expand_DEFERRED_INIT (stmt=0x7fffe96ae348) at ../../latest-gcc/gcc/internal-fn.c:3021
>> 3021	      mark_addressable (lhs);
>> (gdb) call debug_tree(lhs)
>> <ssa_name 0x7fffe9584e58
>>    type <real_type 0x7fffe959b2a0 float sizes-gimplified SF
>>        size <integer_cst 0x7fffe9579f48 constant 32>
>>        unit-size <integer_cst 0x7fffe9579f60 constant 4>
>>        align:32 warn_if_not_align:0 symtab:0 alias-set 2 canonical-type 0x7fffe959b2a0 precision:32
>>        pointer_to_this <pointer_type 0x7fffe959b7e0>>
>>    visited var <var_decl 0x7ffff7ff7bd0 temp1>
>>    def_stmt temp1_5 = .DEFERRED_INIT (4, 2, 0, &"temp1"[0]);
>>    version:5>
>> 
>> when I deleted:
>> 
>> if (TREE_CODE (lhs) == SSA_NAME
>>   lhs = SSA_NAME_VAR (lhs);
> 
> but then using SSA_NAME_VAR is broken.  I suspect use_register_for_decl
> isn't the correct thing to look at.  I think we need to look at what
> the LHS expanded to if it is a SSA_VAR_P (that includes SSA names
> but also plain DECLs but not what we get from VLAs where we'd see
> *ptr).  So sth like
> 
>  bool reg_lhs;
>  if (SSA_VAR_P (lhs))
>    {
>      rtx tem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
>      reg_lhs = !MEM_P (tem);
>      /* If not MEM_P reg_lhs should be REG_P or SUBREG_P (but maybe
>         also CONCAT or lowpart...?)  */
>    }
>  else
>    {
>      gcc_assert (is_vla);
>      reg_lhs = false;
>    }
> 
>  if (!reg_lhs)
>    memset path
>  else
>    expand_assignment path

After making the following change:

+  bool reg_lhs = true;
 
   tree var_type = TREE_TYPE (lhs);
   gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
 
-  if (is_vla || (!use_register_for_decl (lhs)))
+  if (SSA_VAR_P (lhs))
+    {
+      rtx tem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+      reg_lhs = !MEM_P (tem);
+    }
+  else
+    {
+      gcc_assert (is_vla);
+      reg_lhs = false;
+    }
+
+  if (!reg_lhs)
     {

I got exactly the same internal error that failed at expr.c:

 8436   /* We must have made progress.  */
 8437   gcc_assert (inner != exp);


Looks like for the following code:

3026   if (!reg_lhs)
3027     {
3028     /* If this is a VLA or the variable is not in register,
3029        expand to a memset to initialize it.  */
3030       mark_addressable (lhs);
3031       tree var_addr = build_fold_addr_expr (lhs);
3032 
3033       tree value = (init_type == AUTO_INIT_PATTERN) ?
3034                     build_int_cst (integer_type_node,
3035                                    INIT_PATTERN_VALUE) :
3036                     integer_zero_node;
3037       tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
3038                                      3, var_addr, value, var_size);
3039       /* Expand this memset call.  */
3040       expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
3041     }

At line 3030, “lhs” could be a SSA_NAME.

My questions are:

1. Could the routine “mark_addressable” and “build_fold_addr_expr” be applied on SSA_NAME?
2. Could the routine “expand_builtin_memset” be applied on the memset call whose “DEST” is
    an address expression on SSA_NAME? 
3. Within “expand_DEFERRED_INIT”, can I call “expand_builtin_memset” to expand .DEFERRED_INIT?

I suspect that one of the above 3 might be the issue, but not sure which one?

Thanks a lot.

Qing
   


> bool reg_lhs;
>  if (SSA_VAR_P (lhs))
>    {
>      rtx tem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
>      reg_lhs = !MEM_P (tem);
>      /* If not MEM_P reg_lhs should be REG_P or SUBREG_P (but maybe
>         also CONCAT or lowpart...?)  */
>    }
>  else
>    {
>      gcc_assert (is_vla);
>      reg_lhs = false;
>    }


> 
>> Many testing cases failed with internal compiler error:
>> 
>> /home/opc/Work/GCC/latest-gcc/gcc/testsuite/c-c++-common/auto-init-3.c:9:9: internal compiler error: in expand_expr_addr_expr_1, at expr.c:8437
>> 0xe237aa expand_expr_addr_expr_1
>> 	../../latest-gcc/gcc/expr.c:8437
>> 0xe24059 expand_expr_addr_expr
>> 	../../latest-gcc/gcc/expr.c:8525
>> 0xe32b56 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
>> 	../../latest-gcc/gcc/expr.c:11741
>> 0xe2da52 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
>> 	../../latest-gcc/gcc/expr.c:10777
>> 0xe24706 expand_expr_real(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
>> 	../../latest-gcc/gcc/expr.c:8713
>> 0xc13f15 expand_expr
>> 	../../latest-gcc/gcc/expr.h:301
>> 0xc17acb get_memory_rtx
>> 	../../latest-gcc/gcc/builtins.c:1370
>> 0xc2223d expand_builtin_memset_args
>> 	../../latest-gcc/gcc/builtins.c:4102
>> 0xc21a20 expand_builtin_memset(tree_node*, rtx_def*, machine_mode)
>> 	../../latest-gcc/gcc/builtins.c:3886
>> 0xfb5c85 expand_DEFERRED_INIT
>> 	../../latest-gcc/gcc/internal-fn.c:3031
>> 
>> 
>> So, did I do anything wrong?
>> 
>> Qing
> 
> -- 
> 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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-18 16:02                 ` Qing Zhao
@ 2021-08-19  9:00                   ` Richard Biener
  2021-08-19 13:54                     ` Qing Zhao
  0 siblings, 1 reply; 60+ messages in thread
From: Richard Biener @ 2021-08-19  9:00 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook

On Wed, 18 Aug 2021, Qing Zhao wrote:

> 
> 
> > On Aug 18, 2021, at 2:15 AM, Richard Biener <rguenther@suse.de> wrote:
> > 
> > On Tue, 17 Aug 2021, Qing Zhao wrote:
> > 
> >> 
> >> 
> >>> On Aug 17, 2021, at 9:50 AM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> >>> 
> >>> 
> >>> 
> >>>> On Aug 17, 2021, at 3:29 AM, Richard Biener <rguenther@suse.de> wrote:
> >>>> 
> >>>> On Mon, 16 Aug 2021, Qing Zhao wrote:
> >>>> 
> >>>>> My current code for expand_DEFERRED_INIT is like the following, could you check and see whether there is any issue for it:
> >>>>> 
> >>>>> #define INIT_PATTERN_VALUE  0xFE
> >>>>> static void
> >>>>> expand_DEFERRED_INIT (internal_fn, gcall *stmt)
> >>>>> {
> >>>>> tree lhs = gimple_call_lhs (stmt);
> >>>>> tree var_size = gimple_call_arg (stmt, 0);
> >>>>> enum auto_init_type init_type
> >>>>>  = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
> >>>>> bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
> >>>>> 
> >>>>> tree var_type = TREE_TYPE (lhs);
> >>>>> gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
> >>>>> 
> >>>>> if (is_vla || (!use_register_for_decl (lhs)))
> >>>>>  {
> >>>>>    if (TREE_CODE (lhs) == SSA_NAME)
> >>>>>      lhs = SSA_NAME_VAR (lhs);
> >>>> 
> >>>> this should not be necessary (in fact you shouldn't see a SSA_NAME
> >>>> here, if you do then using SSA_NAME_VAR is wrong)
> >>> You mean during RTL expansion phase, all SSA_NAMEs are gone already?
> >> 
> >> Actually, the lhs could be SSA_NAME here, 
> >> 
> >> Breakpoint 1, expand_DEFERRED_INIT (stmt=0x7fffe96ae348) at ../../latest-gcc/gcc/internal-fn.c:3021
> >> 3021	      mark_addressable (lhs);
> >> (gdb) call debug_tree(lhs)
> >> <ssa_name 0x7fffe9584e58
> >>    type <real_type 0x7fffe959b2a0 float sizes-gimplified SF
> >>        size <integer_cst 0x7fffe9579f48 constant 32>
> >>        unit-size <integer_cst 0x7fffe9579f60 constant 4>
> >>        align:32 warn_if_not_align:0 symtab:0 alias-set 2 canonical-type 0x7fffe959b2a0 precision:32
> >>        pointer_to_this <pointer_type 0x7fffe959b7e0>>
> >>    visited var <var_decl 0x7ffff7ff7bd0 temp1>
> >>    def_stmt temp1_5 = .DEFERRED_INIT (4, 2, 0, &"temp1"[0]);
> >>    version:5>
> >> 
> >> when I deleted:
> >> 
> >> if (TREE_CODE (lhs) == SSA_NAME
> >>   lhs = SSA_NAME_VAR (lhs);
> > 
> > but then using SSA_NAME_VAR is broken.  I suspect use_register_for_decl
> > isn't the correct thing to look at.  I think we need to look at what
> > the LHS expanded to if it is a SSA_VAR_P (that includes SSA names
> > but also plain DECLs but not what we get from VLAs where we'd see
> > *ptr).  So sth like
> > 
> >  bool reg_lhs;
> >  if (SSA_VAR_P (lhs))
> >    {
> >      rtx tem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
> >      reg_lhs = !MEM_P (tem);
> >      /* If not MEM_P reg_lhs should be REG_P or SUBREG_P (but maybe
> >         also CONCAT or lowpart...?)  */
> >    }
> >  else
> >    {
> >      gcc_assert (is_vla);
> >      reg_lhs = false;
> >    }
> > 
> >  if (!reg_lhs)
> >    memset path
> >  else
> >    expand_assignment path
> 
> After making the following change:
> 
> +  bool reg_lhs = true;
>  
>    tree var_type = TREE_TYPE (lhs);
>    gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>  
> -  if (is_vla || (!use_register_for_decl (lhs)))
> +  if (SSA_VAR_P (lhs))
> +    {
> +      rtx tem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
> +      reg_lhs = !MEM_P (tem);
> +    }
> +  else
> +    {
> +      gcc_assert (is_vla);
> +      reg_lhs = false;
> +    }
> +
> +  if (!reg_lhs)
>      {
> 
> I got exactly the same internal error that failed at expr.c:
> 
>  8436   /* We must have made progress.  */
>  8437   gcc_assert (inner != exp);
> 
> 
> Looks like for the following code:
> 
> 3026   if (!reg_lhs)
> 3027     {
> 3028     /* If this is a VLA or the variable is not in register,
> 3029        expand to a memset to initialize it.  */
> 3030       mark_addressable (lhs);
> 3031       tree var_addr = build_fold_addr_expr (lhs);
> 3032 
> 3033       tree value = (init_type == AUTO_INIT_PATTERN) ?
> 3034                     build_int_cst (integer_type_node,
> 3035                                    INIT_PATTERN_VALUE) :
> 3036                     integer_zero_node;
> 3037       tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
> 3038                                      3, var_addr, value, var_size);
> 3039       /* Expand this memset call.  */
> 3040       expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
> 3041     }
> 
> At line 3030, “lhs” could be a SSA_NAME.
> 
> My questions are:
> 
> 1. Could the routine “mark_addressable” and “build_fold_addr_expr” be applied on SSA_NAME?

No.

> 2. Could the routine “expand_builtin_memset” be applied on the memset call whose “DEST” is
>     an address expression on SSA_NAME? 

No.

> 3. Within “expand_DEFERRED_INIT”, can I call “expand_builtin_memset” to expand .DEFERRED_INIT?

Well, not with "invalid" GENERIC I fear (address of a SSA name).

> I suspect that one of the above 3 might be the issue, but not sure which one?

All of the above ;)  So while reg_lhs is now precise as to how the
variable will end up (the SSA name will end up as a stack variable in this
case, for whatever reason), expansion via memcpy only works when
working on the RTL representation.  The usual "workaround" (ugh)
is to use make_tree (), so in the !reg_lhs path you'd do

  /* Get a new GENERIC representation for the RTL.  That's necesary
     in case LHS is an SSA name.  */
  lhs = make_tree (TREE_TYPE (lhs), tem);

alternatively you could maybe do

  if (DECL_P (lhs))
    {
+      rtx tem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+      reg_lhs = !MEM_P (tem);
    }
  else if (TREE_CODE (lhs) == SSA_NAME)
    reg_lhs = true;
  else
    reg_lhs = false;

thus treat SSA names as register storage always (even if it will end
up on the stack).

Richard.

> Thanks a lot.
> 
> Qing
>    
> 
> 
> > bool reg_lhs;
> >  if (SSA_VAR_P (lhs))
> >    {
> >      rtx tem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
> >      reg_lhs = !MEM_P (tem);
> >      /* If not MEM_P reg_lhs should be REG_P or SUBREG_P (but maybe
> >         also CONCAT or lowpart...?)  */
> >    }
> >  else
> >    {
> >      gcc_assert (is_vla);
> >      reg_lhs = false;
> >    }
> 
> 
> > 
> >> Many testing cases failed with internal compiler error:
> >> 
> >> /home/opc/Work/GCC/latest-gcc/gcc/testsuite/c-c++-common/auto-init-3.c:9:9: internal compiler error: in expand_expr_addr_expr_1, at expr.c:8437
> >> 0xe237aa expand_expr_addr_expr_1
> >> 	../../latest-gcc/gcc/expr.c:8437
> >> 0xe24059 expand_expr_addr_expr
> >> 	../../latest-gcc/gcc/expr.c:8525
> >> 0xe32b56 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
> >> 	../../latest-gcc/gcc/expr.c:11741
> >> 0xe2da52 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
> >> 	../../latest-gcc/gcc/expr.c:10777
> >> 0xe24706 expand_expr_real(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
> >> 	../../latest-gcc/gcc/expr.c:8713
> >> 0xc13f15 expand_expr
> >> 	../../latest-gcc/gcc/expr.h:301
> >> 0xc17acb get_memory_rtx
> >> 	../../latest-gcc/gcc/builtins.c:1370
> >> 0xc2223d expand_builtin_memset_args
> >> 	../../latest-gcc/gcc/builtins.c:4102
> >> 0xc21a20 expand_builtin_memset(tree_node*, rtx_def*, machine_mode)
> >> 	../../latest-gcc/gcc/builtins.c:3886
> >> 0xfb5c85 expand_DEFERRED_INIT
> >> 	../../latest-gcc/gcc/internal-fn.c:3031
> >> 
> >> 
> >> So, did I do anything wrong?
> >> 
> >> Qing
> > 
> > -- 
> > Richard Biener <rguenther@suse.de>
> > SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> > Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
> 
> 

-- 
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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-19  9:00                   ` Richard Biener
@ 2021-08-19 13:54                     ` Qing Zhao
  2021-08-20 14:52                       ` Qing Zhao
  2021-08-23 13:55                       ` Richard Biener
  0 siblings, 2 replies; 60+ messages in thread
From: Qing Zhao @ 2021-08-19 13:54 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook



> On Aug 19, 2021, at 4:00 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Wed, 18 Aug 2021, Qing Zhao wrote:
> 
>> 
>> 
>>> On Aug 18, 2021, at 2:15 AM, Richard Biener <rguenther@suse.de> wrote:
>>> 
>>> On Tue, 17 Aug 2021, Qing Zhao wrote:
>>> 
>>>> 
>>>> 
>>>>> On Aug 17, 2021, at 9:50 AM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>>>> 
>>>>> 
>>>>> 
>>>>>> On Aug 17, 2021, at 3:29 AM, Richard Biener <rguenther@suse.de> wrote:
>>>>>> 
>>>>>> On Mon, 16 Aug 2021, Qing Zhao wrote:
>>>>>> 
>>>>>>> My current code for expand_DEFERRED_INIT is like the following, could you check and see whether there is any issue for it:
>>>>>>> 
>>>>>>> #define INIT_PATTERN_VALUE  0xFE
>>>>>>> static void
>>>>>>> expand_DEFERRED_INIT (internal_fn, gcall *stmt)
>>>>>>> {
>>>>>>> tree lhs = gimple_call_lhs (stmt);
>>>>>>> tree var_size = gimple_call_arg (stmt, 0);
>>>>>>> enum auto_init_type init_type
>>>>>>> = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
>>>>>>> bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
>>>>>>> 
>>>>>>> tree var_type = TREE_TYPE (lhs);
>>>>>>> gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>>>>>>> 
>>>>>>> if (is_vla || (!use_register_for_decl (lhs)))
>>>>>>> {
>>>>>>>   if (TREE_CODE (lhs) == SSA_NAME)
>>>>>>>     lhs = SSA_NAME_VAR (lhs);
>>>>>> 
>>>>>> this should not be necessary (in fact you shouldn't see a SSA_NAME
>>>>>> here, if you do then using SSA_NAME_VAR is wrong)
>>>>> You mean during RTL expansion phase, all SSA_NAMEs are gone already?
>>>> 
>>>> Actually, the lhs could be SSA_NAME here, 
>>>> 
>>>> Breakpoint 1, expand_DEFERRED_INIT (stmt=0x7fffe96ae348) at ../../latest-gcc/gcc/internal-fn.c:3021
>>>> 3021	      mark_addressable (lhs);
>>>> (gdb) call debug_tree(lhs)
>>>> <ssa_name 0x7fffe9584e58
>>>>   type <real_type 0x7fffe959b2a0 float sizes-gimplified SF
>>>>       size <integer_cst 0x7fffe9579f48 constant 32>
>>>>       unit-size <integer_cst 0x7fffe9579f60 constant 4>
>>>>       align:32 warn_if_not_align:0 symtab:0 alias-set 2 canonical-type 0x7fffe959b2a0 precision:32
>>>>       pointer_to_this <pointer_type 0x7fffe959b7e0>>
>>>>   visited var <var_decl 0x7ffff7ff7bd0 temp1>
>>>>   def_stmt temp1_5 = .DEFERRED_INIT (4, 2, 0, &"temp1"[0]);
>>>>   version:5>
>>>> 
>>>> when I deleted:
>>>> 
>>>> if (TREE_CODE (lhs) == SSA_NAME
>>>>  lhs = SSA_NAME_VAR (lhs);
>>> 
>>> but then using SSA_NAME_VAR is broken.  I suspect use_register_for_decl
>>> isn't the correct thing to look at.  I think we need to look at what
>>> the LHS expanded to if it is a SSA_VAR_P (that includes SSA names
>>> but also plain DECLs but not what we get from VLAs where we'd see
>>> *ptr).  So sth like
>>> 
>>> bool reg_lhs;
>>> if (SSA_VAR_P (lhs))
>>>   {
>>>     rtx tem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
>>>     reg_lhs = !MEM_P (tem);
>>>     /* If not MEM_P reg_lhs should be REG_P or SUBREG_P (but maybe
>>>        also CONCAT or lowpart...?)  */
>>>   }
>>> else
>>>   {
>>>     gcc_assert (is_vla);
>>>     reg_lhs = false;
>>>   }
>>> 
>>> if (!reg_lhs)
>>>   memset path
>>> else
>>>   expand_assignment path
>> 
>> After making the following change:
>> 
>> +  bool reg_lhs = true;
>> 
>>   tree var_type = TREE_TYPE (lhs);
>>   gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>> 
>> -  if (is_vla || (!use_register_for_decl (lhs)))
>> +  if (SSA_VAR_P (lhs))
>> +    {
>> +      rtx tem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
>> +      reg_lhs = !MEM_P (tem);
>> +    }
>> +  else
>> +    {
>> +      gcc_assert (is_vla);
>> +      reg_lhs = false;
>> +    }
>> +
>> +  if (!reg_lhs)
>>     {
>> 
>> I got exactly the same internal error that failed at expr.c:
>> 
>> 8436   /* We must have made progress.  */
>> 8437   gcc_assert (inner != exp);
>> 
>> 
>> Looks like for the following code:
>> 
>> 3026   if (!reg_lhs)
>> 3027     {
>> 3028     /* If this is a VLA or the variable is not in register,
>> 3029        expand to a memset to initialize it.  */
>> 3030       mark_addressable (lhs);
>> 3031       tree var_addr = build_fold_addr_expr (lhs);
>> 3032 
>> 3033       tree value = (init_type == AUTO_INIT_PATTERN) ?
>> 3034                     build_int_cst (integer_type_node,
>> 3035                                    INIT_PATTERN_VALUE) :
>> 3036                     integer_zero_node;
>> 3037       tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
>> 3038                                      3, var_addr, value, var_size);
>> 3039       /* Expand this memset call.  */
>> 3040       expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
>> 3041     }
>> 
>> At line 3030, “lhs” could be a SSA_NAME.
>> 
>> My questions are:
>> 
>> 1. Could the routine “mark_addressable” and “build_fold_addr_expr” be applied on SSA_NAME?
> 
> No.
> 
>> 2. Could the routine “expand_builtin_memset” be applied on the memset call whose “DEST” is
>>    an address expression on SSA_NAME? 
> 
> No.
> 
>> 3. Within “expand_DEFERRED_INIT”, can I call “expand_builtin_memset” to expand .DEFERRED_INIT?
> 
> Well, not with "invalid" GENERIC I fear (address of a SSA name).
> 
>> I suspect that one of the above 3 might be the issue, but not sure which one?
> 
> All of the above ;)  So while reg_lhs is now precise as to how the
> variable will end up (the SSA name will end up as a stack variable in this
> case, for whatever reason), expansion via memcpy only works when
> working on the RTL representation.  The usual "workaround" (ugh)
> is to use make_tree (), so in the !reg_lhs path you'd do
> 
>  /* Get a new GENERIC representation for the RTL.  That's necesary
>     in case LHS is an SSA name.  */
>  lhs = make_tree (TREE_TYPE (lhs), tem);

This resolved the issue.

Another question,

Previously, I used

    if (TREE_CODE (lhs) == SSA_NAME)
       lhs = SSA_NAME_VAR (lhs);

To resolve this issue. The purpose looks like the same as “make_tree”, just get an generic tree for the LHS. 

Why you said using SSA_NAME_VAR is broken?  Is it because SSA_NAME_VAR will not always return a valid TREE?

I should use as following


   If (TREE_CODE (lhs) == SSA_NAME) && SSA_NAME_VAR (lhs))
      Lhs = SSA_NAME_VAR (lhs)

?

> 
> alternatively you could maybe do
> 
>  if (DECL_P (lhs))
>    {
> +      rtx tem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
> +      reg_lhs = !MEM_P (tem);
>    }
>  else if (TREE_CODE (lhs) == SSA_NAME)
>    reg_lhs = true;
>  else
>    reg_lhs = false;
> 
> thus treat SSA names as register storage always (even if it will end
> up on the stack).

My question here, for a complicate structure SSA_NAME, will expanding through memset better than expand_asssignment? 

Qing
> 
> Richard.
> 
>> Thanks a lot.
>> 
>> Qing
>> 
>> 
>> 
>>> bool reg_lhs;
>>> if (SSA_VAR_P (lhs))
>>>   {
>>>     rtx tem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
>>>     reg_lhs = !MEM_P (tem);
>>>     /* If not MEM_P reg_lhs should be REG_P or SUBREG_P (but maybe
>>>        also CONCAT or lowpart...?)  */
>>>   }
>>> else
>>>   {
>>>     gcc_assert (is_vla);
>>>     reg_lhs = false;
>>>   }
>> 
>> 
>>> 
>>>> Many testing cases failed with internal compiler error:
>>>> 
>>>> /home/opc/Work/GCC/latest-gcc/gcc/testsuite/c-c++-common/auto-init-3.c:9:9: internal compiler error: in expand_expr_addr_expr_1, at expr.c:8437
>>>> 0xe237aa expand_expr_addr_expr_1
>>>> 	../../latest-gcc/gcc/expr.c:8437
>>>> 0xe24059 expand_expr_addr_expr
>>>> 	../../latest-gcc/gcc/expr.c:8525
>>>> 0xe32b56 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
>>>> 	../../latest-gcc/gcc/expr.c:11741
>>>> 0xe2da52 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
>>>> 	../../latest-gcc/gcc/expr.c:10777
>>>> 0xe24706 expand_expr_real(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
>>>> 	../../latest-gcc/gcc/expr.c:8713
>>>> 0xc13f15 expand_expr
>>>> 	../../latest-gcc/gcc/expr.h:301
>>>> 0xc17acb get_memory_rtx
>>>> 	../../latest-gcc/gcc/builtins.c:1370
>>>> 0xc2223d expand_builtin_memset_args
>>>> 	../../latest-gcc/gcc/builtins.c:4102
>>>> 0xc21a20 expand_builtin_memset(tree_node*, rtx_def*, machine_mode)
>>>> 	../../latest-gcc/gcc/builtins.c:3886
>>>> 0xfb5c85 expand_DEFERRED_INIT
>>>> 	../../latest-gcc/gcc/internal-fn.c:3031
>>>> 
>>>> 
>>>> So, did I do anything wrong?
>>>> 
>>>> Qing
>>> 
>>> -- 
>>> Richard Biener <rguenther@suse.de>
>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>> 
>> 
> 
> -- 
> 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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-19 13:54                     ` Qing Zhao
@ 2021-08-20 14:52                       ` Qing Zhao
  2021-08-23 13:55                       ` Richard Biener
  1 sibling, 0 replies; 60+ messages in thread
From: Qing Zhao @ 2021-08-20 14:52 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook



> On Aug 19, 2021, at 8:54 AM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> 
>>>>> Breakpoint 1, expand_DEFERRED_INIT (stmt=0x7fffe96ae348) at ../../latest-gcc/gcc/internal-fn.c:3021
>>>>> 3021	      mark_addressable (lhs);
>>>>> (gdb) call debug_tree(lhs)
>>>>> <ssa_name 0x7fffe9584e58
>>>>>  type <real_type 0x7fffe959b2a0 float sizes-gimplified SF
>>>>>      size <integer_cst 0x7fffe9579f48 constant 32>
>>>>>      unit-size <integer_cst 0x7fffe9579f60 constant 4>
>>>>>      align:32 warn_if_not_align:0 symtab:0 alias-set 2 canonical-type 0x7fffe959b2a0 precision:32
>>>>>      pointer_to_this <pointer_type 0x7fffe959b7e0>>
>>>>>  visited var <var_decl 0x7ffff7ff7bd0 temp1>
>>>>>  def_stmt temp1_5 = .DEFERRED_INIT (4, 2, 0, &"temp1"[0]);
>>>>>  version:5>
>>>>> 
>>>>> when I deleted:
>>>>> 
>>>>> if (TREE_CODE (lhs) == SSA_NAME
>>>>> lhs = SSA_NAME_VAR (lhs);
>>>> 
>>>> but then using SSA_NAME_VAR is broken.  I suspect use_register_for_decl
>>>> isn't the correct thing to look at.  I think we need to look at what
>>>> the LHS expanded to if it is a SSA_VAR_P (that includes SSA names
>>>> but also plain DECLs but not what we get from VLAs where we'd see
>>>> *ptr).  So sth like
>>>> 
>>>> bool reg_lhs;
>>>> if (SSA_VAR_P (lhs))
>>>>  {
>>>>    rtx tem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
>>>>    reg_lhs = !MEM_P (tem);
>>>>    /* If not MEM_P reg_lhs should be REG_P or SUBREG_P (but maybe
>>>>       also CONCAT or lowpart...?)  */
>>>>  }
>>>> else
>>>>  {
>>>>    gcc_assert (is_vla);
>>>>    reg_lhs = false;
>>>>  }
>>>> 
>>>> if (!reg_lhs)
>>>>  memset path
>>>> else
>>>>  expand_assignment path
>>> 
>>> After making the following change:
>>> 
>>> +  bool reg_lhs = true;
>>> 
>>>  tree var_type = TREE_TYPE (lhs);
>>>  gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
>>> 
>>> -  if (is_vla || (!use_register_for_decl (lhs)))
>>> +  if (SSA_VAR_P (lhs))
>>> +    {
>>> +      rtx tem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
>>> +      reg_lhs = !MEM_P (tem);
>>> +    }
>>> +  else
>>> +    {
>>> +      gcc_assert (is_vla);
>>> +      reg_lhs = false;
>>> +    }
>>> +
>>> +  if (!reg_lhs)
>>>    {
>>> 
>>> I got exactly the same internal error that failed at expr.c:
>>> 
>>> 8436   /* We must have made progress.  */
>>> 8437   gcc_assert (inner != exp);
>>> 
>>> 
>>> Looks like for the following code:
>>> 
>>> 3026   if (!reg_lhs)
>>> 3027     {
>>> 3028     /* If this is a VLA or the variable is not in register,
>>> 3029        expand to a memset to initialize it.  */
>>> 3030       mark_addressable (lhs);
>>> 3031       tree var_addr = build_fold_addr_expr (lhs);
>>> 3032 
>>> 3033       tree value = (init_type == AUTO_INIT_PATTERN) ?
>>> 3034                     build_int_cst (integer_type_node,
>>> 3035                                    INIT_PATTERN_VALUE) :
>>> 3036                     integer_zero_node;
>>> 3037       tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
>>> 3038                                      3, var_addr, value, var_size);
>>> 3039       /* Expand this memset call.  */
>>> 3040       expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
>>> 3041     }
>>> 
>>> At line 3030, “lhs” could be a SSA_NAME.
>>> 
>>> My questions are:
>>> 
>>> 1. Could the routine “mark_addressable” and “build_fold_addr_expr” be applied on SSA_NAME?
>> 
>> No.
>> 
>>> 2. Could the routine “expand_builtin_memset” be applied on the memset call whose “DEST” is
>>>   an address expression on SSA_NAME? 
>> 
>> No.
>> 
>>> 3. Within “expand_DEFERRED_INIT”, can I call “expand_builtin_memset” to expand .DEFERRED_INIT?
>> 
>> Well, not with "invalid" GENERIC I fear (address of a SSA name).
>> 
>>> I suspect that one of the above 3 might be the issue, but not sure which one?
>> 
>> All of the above ;)  So while reg_lhs is now precise as to how the
>> variable will end up (the SSA name will end up as a stack variable in this
>> case, for whatever reason), expansion via memcpy only works when
>> working on the RTL representation.  The usual "workaround" (ugh)
>> is to use make_tree (), so in the !reg_lhs path you'd do
>> 
>> /* Get a new GENERIC representation for the RTL.  That's necesary
>>    in case LHS is an SSA name.  */
>> lhs = make_tree (TREE_TYPE (lhs), tem);
> 
> This resolved the issue.

However, there was two runtime errors with CPU2017 with this change.

I guess that there might be some issue with “expand_expr” + “make_tree” here. 

So, I changed the code to use the alternative solution that you suggested:

> 
>> 
>> alternatively you could maybe do
>> 
>> if (DECL_P (lhs))
>>   {
>> +      rtx tem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
>> +      reg_lhs = !MEM_P (tem);
>>   }
>> else if (TREE_CODE (lhs) == SSA_NAME)
>>   reg_lhs = true;
>> else
>>   reg_lhs = false;
>> 
>> thus treat SSA names as register storage always (even if it will end
>> up on the stack).

This did resolve all the issues including CPU2017 runtime errors.
With this solution, all SSA_NAMEs will be expanded through “expand_assignment” even though they are in stack.
the generated code will be correct. But the performance might be a little bit different than through memset. 

Qing
 
> 
> My question here, for a complicate structure SSA_NAME, will expanding through memset better than expand_asssignment? 
> 
> Qing
>> 


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

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-19 13:54                     ` Qing Zhao
  2021-08-20 14:52                       ` Qing Zhao
@ 2021-08-23 13:55                       ` Richard Biener
  2021-09-02 17:24                         ` Qing Zhao
  1 sibling, 1 reply; 60+ messages in thread
From: Richard Biener @ 2021-08-23 13:55 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook

On Thu, 19 Aug 2021, Qing Zhao wrote:

> 
> 
> > On Aug 19, 2021, at 4:00 AM, Richard Biener <rguenther@suse.de> wrote:
> > 
> > On Wed, 18 Aug 2021, Qing Zhao wrote:
> > 
> >> 
> >> 
> >>> On Aug 18, 2021, at 2:15 AM, Richard Biener <rguenther@suse.de> wrote:
> >>> 
> >>> On Tue, 17 Aug 2021, Qing Zhao wrote:
> >>> 
> >>>> 
> >>>> 
> >>>>> On Aug 17, 2021, at 9:50 AM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> >>>>> 
> >>>>> 
> >>>>> 
> >>>>>> On Aug 17, 2021, at 3:29 AM, Richard Biener <rguenther@suse.de> wrote:
> >>>>>> 
> >>>>>> On Mon, 16 Aug 2021, Qing Zhao wrote:
> >>>>>> 
> >>>>>>> My current code for expand_DEFERRED_INIT is like the following, could you check and see whether there is any issue for it:
> >>>>>>> 
> >>>>>>> #define INIT_PATTERN_VALUE  0xFE
> >>>>>>> static void
> >>>>>>> expand_DEFERRED_INIT (internal_fn, gcall *stmt)
> >>>>>>> {
> >>>>>>> tree lhs = gimple_call_lhs (stmt);
> >>>>>>> tree var_size = gimple_call_arg (stmt, 0);
> >>>>>>> enum auto_init_type init_type
> >>>>>>> = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
> >>>>>>> bool is_vla = (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 2));
> >>>>>>> 
> >>>>>>> tree var_type = TREE_TYPE (lhs);
> >>>>>>> gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
> >>>>>>> 
> >>>>>>> if (is_vla || (!use_register_for_decl (lhs)))
> >>>>>>> {
> >>>>>>>   if (TREE_CODE (lhs) == SSA_NAME)
> >>>>>>>     lhs = SSA_NAME_VAR (lhs);
> >>>>>> 
> >>>>>> this should not be necessary (in fact you shouldn't see a SSA_NAME
> >>>>>> here, if you do then using SSA_NAME_VAR is wrong)
> >>>>> You mean during RTL expansion phase, all SSA_NAMEs are gone already?
> >>>> 
> >>>> Actually, the lhs could be SSA_NAME here, 
> >>>> 
> >>>> Breakpoint 1, expand_DEFERRED_INIT (stmt=0x7fffe96ae348) at ../../latest-gcc/gcc/internal-fn.c:3021
> >>>> 3021	      mark_addressable (lhs);
> >>>> (gdb) call debug_tree(lhs)
> >>>> <ssa_name 0x7fffe9584e58
> >>>>   type <real_type 0x7fffe959b2a0 float sizes-gimplified SF
> >>>>       size <integer_cst 0x7fffe9579f48 constant 32>
> >>>>       unit-size <integer_cst 0x7fffe9579f60 constant 4>
> >>>>       align:32 warn_if_not_align:0 symtab:0 alias-set 2 canonical-type 0x7fffe959b2a0 precision:32
> >>>>       pointer_to_this <pointer_type 0x7fffe959b7e0>>
> >>>>   visited var <var_decl 0x7ffff7ff7bd0 temp1>
> >>>>   def_stmt temp1_5 = .DEFERRED_INIT (4, 2, 0, &"temp1"[0]);
> >>>>   version:5>
> >>>> 
> >>>> when I deleted:
> >>>> 
> >>>> if (TREE_CODE (lhs) == SSA_NAME
> >>>>  lhs = SSA_NAME_VAR (lhs);
> >>> 
> >>> but then using SSA_NAME_VAR is broken.  I suspect use_register_for_decl
> >>> isn't the correct thing to look at.  I think we need to look at what
> >>> the LHS expanded to if it is a SSA_VAR_P (that includes SSA names
> >>> but also plain DECLs but not what we get from VLAs where we'd see
> >>> *ptr).  So sth like
> >>> 
> >>> bool reg_lhs;
> >>> if (SSA_VAR_P (lhs))
> >>>   {
> >>>     rtx tem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
> >>>     reg_lhs = !MEM_P (tem);
> >>>     /* If not MEM_P reg_lhs should be REG_P or SUBREG_P (but maybe
> >>>        also CONCAT or lowpart...?)  */
> >>>   }
> >>> else
> >>>   {
> >>>     gcc_assert (is_vla);
> >>>     reg_lhs = false;
> >>>   }
> >>> 
> >>> if (!reg_lhs)
> >>>   memset path
> >>> else
> >>>   expand_assignment path
> >> 
> >> After making the following change:
> >> 
> >> +  bool reg_lhs = true;
> >> 
> >>   tree var_type = TREE_TYPE (lhs);
> >>   gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
> >> 
> >> -  if (is_vla || (!use_register_for_decl (lhs)))
> >> +  if (SSA_VAR_P (lhs))
> >> +    {
> >> +      rtx tem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
> >> +      reg_lhs = !MEM_P (tem);
> >> +    }
> >> +  else
> >> +    {
> >> +      gcc_assert (is_vla);
> >> +      reg_lhs = false;
> >> +    }
> >> +
> >> +  if (!reg_lhs)
> >>     {
> >> 
> >> I got exactly the same internal error that failed at expr.c:
> >> 
> >> 8436   /* We must have made progress.  */
> >> 8437   gcc_assert (inner != exp);
> >> 
> >> 
> >> Looks like for the following code:
> >> 
> >> 3026   if (!reg_lhs)
> >> 3027     {
> >> 3028     /* If this is a VLA or the variable is not in register,
> >> 3029        expand to a memset to initialize it.  */
> >> 3030       mark_addressable (lhs);
> >> 3031       tree var_addr = build_fold_addr_expr (lhs);
> >> 3032 
> >> 3033       tree value = (init_type == AUTO_INIT_PATTERN) ?
> >> 3034                     build_int_cst (integer_type_node,
> >> 3035                                    INIT_PATTERN_VALUE) :
> >> 3036                     integer_zero_node;
> >> 3037       tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
> >> 3038                                      3, var_addr, value, var_size);
> >> 3039       /* Expand this memset call.  */
> >> 3040       expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
> >> 3041     }
> >> 
> >> At line 3030, “lhs” could be a SSA_NAME.
> >> 
> >> My questions are:
> >> 
> >> 1. Could the routine “mark_addressable” and “build_fold_addr_expr” be applied on SSA_NAME?
> > 
> > No.
> > 
> >> 2. Could the routine “expand_builtin_memset” be applied on the memset call whose “DEST” is
> >>    an address expression on SSA_NAME? 
> > 
> > No.
> > 
> >> 3. Within “expand_DEFERRED_INIT”, can I call “expand_builtin_memset” to expand .DEFERRED_INIT?
> > 
> > Well, not with "invalid" GENERIC I fear (address of a SSA name).
> > 
> >> I suspect that one of the above 3 might be the issue, but not sure which one?
> > 
> > All of the above ;)  So while reg_lhs is now precise as to how the
> > variable will end up (the SSA name will end up as a stack variable in this
> > case, for whatever reason), expansion via memcpy only works when
> > working on the RTL representation.  The usual "workaround" (ugh)
> > is to use make_tree (), so in the !reg_lhs path you'd do
> > 
> >  /* Get a new GENERIC representation for the RTL.  That's necesary
> >     in case LHS is an SSA name.  */
> >  lhs = make_tree (TREE_TYPE (lhs), tem);
> 
> This resolved the issue.
> 
> Another question,
> 
> Previously, I used
> 
>     if (TREE_CODE (lhs) == SSA_NAME)
>        lhs = SSA_NAME_VAR (lhs);
> 
> To resolve this issue. The purpose looks like the same as “make_tree”, just get an generic tree for the LHS. 
> 
> Why you said using SSA_NAME_VAR is broken?  Is it because SSA_NAME_VAR will not always return a valid TREE?

Because it's simply the wrong entity - I have no idea why that even
worked.  Ah, cfgexpand associates it with some DECL_RTL for the 
benefit of debug info.  But it's still wrong.

> I should use as following
> 
> 
>    If (TREE_CODE (lhs) == SSA_NAME) && SSA_NAME_VAR (lhs))
>       Lhs = SSA_NAME_VAR (lhs)
> 
> ?

No.  A SSA_NAME_VAR can have multiple SSA_NAMEs (obviously) and
they do not necessarily have to be allocated to the same variable
partition - that is, there's no 1:1 relationship between SSA_NAME
and stack slot or (pseudo) register.  You want to initialize the
storage associated with the SSA_NAME in the .DEFERRED_INIT call,
not some other storage.

> > 
> > alternatively you could maybe do
> > 
> >  if (DECL_P (lhs))
> >    {
> > +      rtx tem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
> > +      reg_lhs = !MEM_P (tem);
> >    }
> >  else if (TREE_CODE (lhs) == SSA_NAME)
> >    reg_lhs = true;
> >  else
> >    reg_lhs = false;
> > 
> > thus treat SSA names as register storage always (even if it will end
> > up on the stack).
> 
> My question here, for a complicate structure SSA_NAME, will expanding through memset better than expand_asssignment? 

It depends.  In the end I'd consider it a missed-optimization bug on
the side that generates worse code - but I do expect cases will exist
for both.  Clearly memset will be worse when dealing with register
initialization (thus the !MEM_P check) and I expect memset to be OK
for stack where member-wise init esp. with non-zero might turn up
worse code.

Richard.

> Qing
> > 
> > Richard.
> > 
> >> Thanks a lot.
> >> 
> >> Qing
> >> 
> >> 
> >> 
> >>> bool reg_lhs;
> >>> if (SSA_VAR_P (lhs))
> >>>   {
> >>>     rtx tem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
> >>>     reg_lhs = !MEM_P (tem);
> >>>     /* If not MEM_P reg_lhs should be REG_P or SUBREG_P (but maybe
> >>>        also CONCAT or lowpart...?)  */
> >>>   }
> >>> else
> >>>   {
> >>>     gcc_assert (is_vla);
> >>>     reg_lhs = false;
> >>>   }
> >> 
> >> 
> >>> 
> >>>> Many testing cases failed with internal compiler error:
> >>>> 
> >>>> /home/opc/Work/GCC/latest-gcc/gcc/testsuite/c-c++-common/auto-init-3.c:9:9: internal compiler error: in expand_expr_addr_expr_1, at expr.c:8437
> >>>> 0xe237aa expand_expr_addr_expr_1
> >>>> 	../../latest-gcc/gcc/expr.c:8437
> >>>> 0xe24059 expand_expr_addr_expr
> >>>> 	../../latest-gcc/gcc/expr.c:8525
> >>>> 0xe32b56 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
> >>>> 	../../latest-gcc/gcc/expr.c:11741
> >>>> 0xe2da52 expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
> >>>> 	../../latest-gcc/gcc/expr.c:10777
> >>>> 0xe24706 expand_expr_real(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool)
> >>>> 	../../latest-gcc/gcc/expr.c:8713
> >>>> 0xc13f15 expand_expr
> >>>> 	../../latest-gcc/gcc/expr.h:301
> >>>> 0xc17acb get_memory_rtx
> >>>> 	../../latest-gcc/gcc/builtins.c:1370
> >>>> 0xc2223d expand_builtin_memset_args
> >>>> 	../../latest-gcc/gcc/builtins.c:4102
> >>>> 0xc21a20 expand_builtin_memset(tree_node*, rtx_def*, machine_mode)
> >>>> 	../../latest-gcc/gcc/builtins.c:3886
> >>>> 0xfb5c85 expand_DEFERRED_INIT
> >>>> 	../../latest-gcc/gcc/internal-fn.c:3031
> >>>> 
> >>>> 
> >>>> So, did I do anything wrong?
> >>>> 
> >>>> Qing
> >>> 
> >>> -- 
> >>> Richard Biener <rguenther@suse.de>
> >>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> >>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
> >> 
> >> 
> > 
> > -- 
> > Richard Biener <rguenther@suse.de>
> > SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> > Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
> 
> 

-- 
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] 60+ messages in thread

* Re: [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-08-23 13:55                       ` Richard Biener
@ 2021-09-02 17:24                         ` Qing Zhao
  0 siblings, 0 replies; 60+ messages in thread
From: Qing Zhao @ 2021-09-02 17:24 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jakub Jelinek, Nick Alcock via Gcc-patches, Kees Cook

Sorry for my late reply (I just came back from vacation last night).

> On Aug 23, 2021, at 8:55 AM, Richard Biener <rguenther@suse.de> wrote:
> 
>>>> 
>>>> 
>>>> Looks like for the following code:
>>>> 
>>>> 3026   if (!reg_lhs)
>>>> 3027     {
>>>> 3028     /* If this is a VLA or the variable is not in register,
>>>> 3029        expand to a memset to initialize it.  */
>>>> 3030       mark_addressable (lhs);
>>>> 3031       tree var_addr = build_fold_addr_expr (lhs);
>>>> 3032 
>>>> 3033       tree value = (init_type == AUTO_INIT_PATTERN) ?
>>>> 3034                     build_int_cst (integer_type_node,
>>>> 3035                                    INIT_PATTERN_VALUE) :
>>>> 3036                     integer_zero_node;
>>>> 3037       tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
>>>> 3038                                      3, var_addr, value, var_size);
>>>> 3039       /* Expand this memset call.  */
>>>> 3040       expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
>>>> 3041     }
>>>> 
>>>> At line 3030, “lhs” could be a SSA_NAME.
>>>> 
>>>> My questions are:
>>>> 
>>>> 1. Could the routine “mark_addressable” and “build_fold_addr_expr” be applied on SSA_NAME?
>>> 
>>> No.
>>> 
>>>> 2. Could the routine “expand_builtin_memset” be applied on the memset call whose “DEST” is
>>>>   an address expression on SSA_NAME? 
>>> 
>>> No.
>>> 
>>>> 3. Within “expand_DEFERRED_INIT”, can I call “expand_builtin_memset” to expand .DEFERRED_INIT?
>>> 
>>> Well, not with "invalid" GENERIC I fear (address of a SSA name).
>>> 
>>>> I suspect that one of the above 3 might be the issue, but not sure which one?
>>> 
>>> All of the above ;)  So while reg_lhs is now precise as to how the
>>> variable will end up (the SSA name will end up as a stack variable in this
>>> case, for whatever reason), expansion via memcpy only works when
>>> working on the RTL representation.  The usual "workaround" (ugh)
>>> is to use make_tree (), so in the !reg_lhs path you'd do
>>> 
>>> /* Get a new GENERIC representation for the RTL.  That's necesary
>>>    in case LHS is an SSA name.  */
>>> lhs = make_tree (TREE_TYPE (lhs), tem);
>> 
>> This resolved the issue.
>> 
>> Another question,
>> 
>> Previously, I used
>> 
>>    if (TREE_CODE (lhs) == SSA_NAME)
>>       lhs = SSA_NAME_VAR (lhs);
>> 
>> To resolve this issue. The purpose looks like the same as “make_tree”, just get an generic tree for the LHS. 
>> 
>> Why you said using SSA_NAME_VAR is broken?  Is it because SSA_NAME_VAR will not always return a valid TREE?
> 
> Because it's simply the wrong entity - I have no idea why that even
> worked.  Ah, cfgexpand associates it with some DECL_RTL for the 
> benefit of debug info.  But it's still wrong.
> 
>> I should use as following
>> 
>> 
>>   If (TREE_CODE (lhs) == SSA_NAME) && SSA_NAME_VAR (lhs))
>>      Lhs = SSA_NAME_VAR (lhs)
>> 
>> ?
> 
> No.  A SSA_NAME_VAR can have multiple SSA_NAMEs (obviously) and
> they do not necessarily have to be allocated to the same variable
> partition - that is, there's no 1:1 relationship between SSA_NAME
> and stack slot or (pseudo) register.  You want to initialize the
> storage associated with the SSA_NAME in the .DEFERRED_INIT call,
> not some other storage.

Okay, thanks for the explanation. Now I understand.
> 
>>> 
>>> alternatively you could maybe do
>>> 
>>> if (DECL_P (lhs))
>>>   {
>>> +      rtx tem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
>>> +      reg_lhs = !MEM_P (tem);
>>>   }
>>> else if (TREE_CODE (lhs) == SSA_NAME)
>>>   reg_lhs = true;
>>> else
>>>   reg_lhs = false;
>>> 
>>> thus treat SSA names as register storage always (even if it will end
>>> up on the stack).
>> 
>> My question here, for a complicate structure SSA_NAME, will expanding through memset better than expand_asssignment? 
> 
> It depends.  In the end I'd consider it a missed-optimization bug on
> the side that generates worse code - but I do expect cases will exist
> for both.
Okay. I agree.

>  Clearly memset will be worse when dealing with register
> initialization (thus the !MEM_P check) and I expect memset to be OK
> for stack where member-wise init esp. with non-zero might turn up
> worse code.

So, for SSA_NAME, since they are all treated as reg_lhs, they will be expanded through “expand_assignment” 
as member-wise init, therefore might generate worse code for a SSA_NAME that is in stack actually.

Qing

> 
> Richard.
> 
>> Qing
>>> 


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

end of thread, other threads:[~2021-09-02 17:24 UTC | newest]

Thread overview: 60+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-27  3:26 [patch][version 6] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc Qing Zhao
2021-07-28 20:21 ` Kees Cook
2021-07-28 21:53   ` Qing Zhao
2021-08-09 14:09 ` Richard Biener
2021-08-09 16:38   ` Qing Zhao
2021-08-09 17:14     ` Richard Biener
2021-08-10  7:36     ` Richard Biener
2021-08-10 13:39       ` Qing Zhao
2021-08-10 14:16         ` Richard Biener
2021-08-10 15:02           ` Qing Zhao
2021-08-10 15:22             ` Richard Biener
2021-08-10 15:55               ` Qing Zhao
2021-08-10 20:16               ` Qing Zhao
2021-08-10 22:26                 ` Qing Zhao
2021-08-11  7:02                   ` Richard Biener
2021-08-11 13:33                     ` Qing Zhao
2021-08-11 13:37                       ` Richard Biener
2021-08-11 13:54                         ` Qing Zhao
2021-08-11 13:58                           ` Richard Biener
2021-08-11 14:00                             ` Qing Zhao
2021-08-11 15:30                             ` Qing Zhao
2021-08-11 15:53                               ` Richard Biener
2021-08-11 16:22                                 ` Qing Zhao
2021-08-11 16:55                                   ` Richard Biener
2021-08-11 16:57                                     ` Qing Zhao
2021-08-11 20:30                                     ` Qing Zhao
2021-08-11 22:03                                       ` Qing Zhao
2021-08-16  7:12                                         ` Richard Biener
2021-08-16 14:48                                           ` Qing Zhao
2021-08-16 15:08                                             ` Richard Biener
2021-08-16 15:39                                               ` Qing Zhao
2021-08-16  7:11                                       ` Richard Biener
2021-08-16 16:48                                         ` Qing Zhao
2021-08-17 15:04                                           ` Qing Zhao
2021-08-17 20:40                                             ` Qing Zhao
2021-08-18  7:19                                               ` Richard Biener
2021-08-18 14:39                                                 ` Qing Zhao
2021-08-11  9:02                   ` Richard Sandiford
2021-08-11 13:44                     ` Qing Zhao
2021-08-11 16:15                       ` Richard Sandiford
2021-08-11 16:29                         ` Qing Zhao
2021-08-12 19:24   ` Qing Zhao
2021-08-12 22:45     ` Qing Zhao
2021-08-16  7:40     ` Richard Biener
2021-08-16 15:45       ` Qing Zhao
2021-08-17  8:29         ` Richard Biener
2021-08-17 14:50           ` Qing Zhao
2021-08-17 16:08             ` Qing Zhao
2021-08-18  7:15               ` Richard Biener
2021-08-18 16:02                 ` Qing Zhao
2021-08-19  9:00                   ` Richard Biener
2021-08-19 13:54                     ` Qing Zhao
2021-08-20 14:52                       ` Qing Zhao
2021-08-23 13:55                       ` Richard Biener
2021-09-02 17:24                         ` Qing Zhao
2021-08-16 19:49       ` Qing Zhao
2021-08-17  8:43         ` Richard Biener
2021-08-17 14:03           ` Qing Zhao
2021-08-17 14:45             ` Richard Biener
2021-08-17 14:53               ` 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).