On Thu, Oct 26, 2023 at 5:44 PM Alexandre Oliva <ol...@adacore.com> wrote:
>
>
> Control flow redundancy may choose abnormal edges for early checking,
> but that breaks because we can't insert checks on such edges.
>
> Introduce conditional checking on the dest block of abnormal edges,
> and leave it for the optimizer to drop the conditional.
>
> Also, oops, I noticed the new files went in with an incorrect copyright
> notice, that this patch fixes.
>
> Regstrapped on x86_64-linux-gnu.  Ok to install?

OK.


>
> for  gcc/ChangeLog
>
>         PR tree-optimization/111943
>         * gimple-harden-control-flow.cc: Adjust copyright year.
>         (rt_bb_visited): Add vfalse and vtrue data members.
>         Zero-initialize them in the ctor.
>         (rt_bb_visited::insert_exit_check_on_edge): Upon encountering
>         abnormal edges, insert initializers for vfalse and vtrue on
>         entry, and insert the check sequence guarded by a conditional
>         in the dest block.
>
> for  libgcc/ChangeLog
>
>         * hardcfr.c: Adjust copyright year.
>
> for  gcc/testsuite/ChangeLog
>
>         PR tree-optimization/111943
>         * gcc.dg/harden-cfr-pr111943.c: New.
> ---
>  gcc/gimple-harden-control-flow.cc          |   78 
> +++++++++++++++++++++++++++-
>  gcc/testsuite/gcc.dg/harden-cfr-pr111943.c |   33 ++++++++++++
>  libgcc/hardcfr.c                           |    2 -
>  3 files changed, 109 insertions(+), 4 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/harden-cfr-pr111943.c
>
> diff --git a/gcc/gimple-harden-control-flow.cc 
> b/gcc/gimple-harden-control-flow.cc
> index 3711b25d09123..77c140178060e 100644
> --- a/gcc/gimple-harden-control-flow.cc
> +++ b/gcc/gimple-harden-control-flow.cc
> @@ -1,5 +1,5 @@
>  /* Control flow redundancy hardening.
> -   Copyright (C) 2022 Free Software Foundation, Inc.
> +   Copyright (C) 2022-2023 Free Software Foundation, Inc.
>     Contributed by Alexandre Oliva <ol...@adacore.com>.
>
>  This file is part of GCC.
> @@ -460,6 +460,10 @@ class rt_bb_visited
>       at the end of a block's predecessors or successors list.  */
>    tree ckfail, ckpart, ckinv, ckblk;
>
> +  /* If we need to deal with abnormal edges, we insert SSA_NAMEs for
> +     boolean true and false.  */
> +  tree vfalse, vtrue;
> +
>    /* Convert a block index N to a block vindex, the index used to
>       identify it in the VISITED array.  Check that it's in range:
>       neither ENTRY nor EXIT, but maybe one-past-the-end, to compute
> @@ -596,7 +600,8 @@ public:
>    /* Prepare to add control flow redundancy testing to CFUN.  */
>    rt_bb_visited (int checkpoints)
>      : nblocks (n_basic_blocks_for_fn (cfun)),
> -      vword_type (NULL), ckseq (NULL), rtcfg (NULL)
> +      vword_type (NULL), ckseq (NULL), rtcfg (NULL),
> +      vfalse (NULL), vtrue (NULL)
>    {
>      /* If we've already added a declaration for the builtin checker,
>         extract vword_type and vword_bits from its declaration.  */
> @@ -703,7 +708,74 @@ public:
>    /* Insert SEQ on E.  */
>    void insert_exit_check_on_edge (gimple_seq seq, edge e)
>    {
> -    gsi_insert_seq_on_edge_immediate (e, seq);
> +    if (!(e->flags & EDGE_ABNORMAL))
> +      {
> +       gsi_insert_seq_on_edge_immediate (e, seq);
> +       return;
> +      }
> +
> +    /* Initialize SSA boolean constants for use in abnormal PHIs.  */
> +    if (!vfalse)
> +      {
> +       vfalse = make_ssa_name (boolean_type_node);
> +       vtrue = make_ssa_name (boolean_type_node);
> +
> +       gimple_seq vft_seq = NULL;
> +       gassign *vfalse_init = gimple_build_assign (vfalse, 
> boolean_false_node);
> +       gimple_seq_add_stmt (&vft_seq, vfalse_init);
> +       gassign *vtrue_init = gimple_build_assign (vtrue, boolean_true_node);
> +       gimple_seq_add_stmt (&vft_seq, vtrue_init);
> +
> +       gsi_insert_seq_on_edge_immediate (single_succ_edge
> +                                         (ENTRY_BLOCK_PTR_FOR_FN (cfun)),
> +                                         vft_seq);
> +      }
> +
> +    /* We can't insert on abnormal edges, but we can arrange for SEQ
> +       to execute conditionally at dest.  Add a PHI boolean with TRUE
> +       from E and FALES from other preds, split the whole block, add a
> +       test for the PHI to run a new block with SEQ or skip straight
> +       to the original block.  If there are multiple incoming abnormal
> +       edges, we'll do this multiple times.  ??? Unless there are
> +       multiple abnormal edges with different postcheck status, we
> +       could split the block and redirect other edges, rearranging the
> +       PHI nodes.  Optimizers already know how to do this, so we can
> +       keep things simple here.  */
> +    basic_block bb = e->dest;
> +    basic_block bb_postcheck = split_block_after_labels (bb)->dest;
> +
> +    basic_block bb_check = create_empty_bb (e->dest);
> +    bb_check->count = e->count ();
> +    if (dom_info_available_p (CDI_DOMINATORS))
> +      set_immediate_dominator (CDI_DOMINATORS, bb_check, bb);
> +    if (current_loops)
> +      add_bb_to_loop (bb_check, current_loops->tree_root);
> +
> +    gimple_stmt_iterator chkpt = gsi_after_labels (bb_check);
> +    gsi_insert_seq_before_without_update (&chkpt, seq, GSI_SAME_STMT);
> +    edge edge_postcheck = make_edge (bb_check, bb_postcheck, EDGE_FALLTHRU);
> +    edge_postcheck->probability = profile_probability::always ();
> +
> +    tree cond_var = make_ssa_name (boolean_type_node);
> +    gcond *cond = gimple_build_cond (NE_EXPR, cond_var, boolean_false_node,
> +                                    NULL, NULL);
> +    gimple_stmt_iterator condpt = gsi_after_labels (bb);
> +    gsi_insert_before (&condpt, cond, GSI_SAME_STMT);
> +    edge edge_nocheck = single_succ_edge (bb);
> +    edge_nocheck->flags &= ~EDGE_FALLTHRU;
> +    edge_nocheck->flags |= EDGE_FALSE_VALUE;
> +    edge edge_check = make_edge (bb, bb_check, EDGE_TRUE_VALUE);
> +    edge_check->probability = e->count ().probability_in (bb->count);
> +    edge_nocheck->probability = edge_check->probability.invert ();
> +
> +    gphi *cond_phi = create_phi_node (cond_var, bb);
> +    for (int i = 0, ei = EDGE_COUNT (bb->preds); i < ei; i++)
> +      {
> +       edge pred = EDGE_PRED (bb, i);
> +       bool check_edge = pred == e;
> +       tree val = check_edge ? vtrue : vfalse;
> +       add_phi_arg (cond_phi, val, pred, UNKNOWN_LOCATION);
> +      }
>    }
>
>    /* Add checking code to CHK_EDGES and CHKCALL_BLOCKS, and
> diff --git a/gcc/testsuite/gcc.dg/harden-cfr-pr111943.c 
> b/gcc/testsuite/gcc.dg/harden-cfr-pr111943.c
> new file mode 100644
> index 0000000000000..5a5a2133b1368
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/harden-cfr-pr111943.c
> @@ -0,0 +1,33 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fharden-control-flow-redundancy 
> --param=max-jump-thread-duplication-stmts=0 -Ofast -fdump-tree-hardcfr 
> -fdump-tree-optimized" } */
> +/* { dg-require-effective-target indirect_jumps } */
> +/* { dg-require-effective-target label_values } */
> +
> +/* Based on gcc.c-torture/compile/20050510-1.c.  */
> +
> +extern void dont_remove (void);
> +
> +void bar (int k)
> +{
> +  void *label = (k) ? &&x : &&y;
> +
> +  if (k >= 0)
> +    goto *label;
> +
> +x:
> +  if (k <= 0)
> +    dont_remove ();
> +  /* else goto y; */
> +
> +y:
> +  return;
> +}
> +
> +/* Check before calling dont_remove(), in the 'else goto y' edge, and in the
> +   abnormal edge to y.  */
> +/* { dg-final { scan-tree-dump-times "hardcfr_check" 3 "hardcfr" } } */
> +/* { dg-final { scan-tree-dump-times "hardcfr_check" 3 "optimized" } } */
> +/* Check that hardcfr introduces an abnormal PHI node (this could be avoided,
> +   but it's not worth the effort), and that it gets optimized out.  */
> +/* { dg-final { scan-tree-dump-times {\(ab\) = PHI .*\(ab\)} 1 "hardcfr" } } 
> */
> +/* { dg-final { scan-tree-dump-not {\(ab\) = PHI .*\(ab\)} "optimized" } } */
> diff --git a/libgcc/hardcfr.c b/libgcc/hardcfr.c
> index 7496095b8666c..25ff06742cb44 100644
> --- a/libgcc/hardcfr.c
> +++ b/libgcc/hardcfr.c
> @@ -1,5 +1,5 @@
>  /* Control flow redundancy hardening
> -   Copyright (C) 2022 Free Software Foundation, Inc.
> +   Copyright (C) 2022-2023 Free Software Foundation, Inc.
>     Contributed by Alexandre Oliva <ol...@adacore.com>
>
>  This file is part of GCC.
>
> --
> Alexandre Oliva, happy hacker            https://FSFLA.org/blogs/lxo/
>    Free Software Activist                   GNU Toolchain Engineer
> More tolerance and less prejudice are key for inclusion and diversity
> Excluding neuro-others for not behaving ""normal"" is *not* inclusive

Reply via email to