On Sun, Sep 24, 2023 at 3:09 PM Jørgen Kvalsvik <j...@lambda.is> wrote:
>
> This is a request for feedback and a proof-of-concept, not something I
> intend to merge as-is.  It would be nice if gcc, maybe just under some
> circumstances, always generated an else-block for coverage purposes.
>
> I am working on the MC/DC support by CFG analysis for a while
> https://gcc.gnu.org/pipermail/gcc-patches/2023-June/621449.html and have
> ironed out a lot of problems. The last problem I know about, which is
> impossible to actually fix right now, is the "fusing" of nested ifs.
> Here is an example:
>
>     if (a) if (b) if (c) { ... } // 3 conditions, 6 outcomes
>     if (a && b && c) { ... }     // 3 conditions, 6 outcomes
>
> These form isomorphic CFGs which means there is no way for my algorithm
> to distinguish them. This is sort-of acceptable since the coverage
> measurements more accurately measure the semantics (and not the syntax),
> but this also happens when there is code in-between the nesting:
>
>     if (a) // measures to 2 conditions, 4 outcomes
>     {
>         a += b * 10;
>         b -= a + 2;
>         if (b)
>         {
>             ...
>         }
>     }
>
> You would expect this to be measured as:
>
>     if (a) // 1 condition, 2 outcomes
>     {
>         a += b * 10;
>         b -= a + 2;
>         if (b) // 1 condition, 2 outcomes
>         {
>             ...
>         }
>     }
>
> The source of the problem is the missing (or empty) else block, as the
> algorithm uses the outcome (then/else) edges to determine the limits of
> expressions. If, however, the else blocks are generated, the conditions
> are counted as you would expect.
>
> So I have a few questions:
>
> 1. Is something like this even acceptable? The semantics of the program
>    should not change, assuming the else-block only exists but is without
>    significant behavior. It will only be generated if there is no
>    explicit else in source.
> 2. Should this only be generated when necessary (e.g. under condition
>    coverage? No optimization?)
> 3. I used a simple int-init { int __mcdc_barrier = 0; } but there might
>    be better contents for the block that does not add anything
>    operationally. I am not very familiar with this part of gcc and would
>    like to see someting better. Any suggestions?

Can you in theory handle this by splitting the 'else' edge before
coverage instrumentation rather than using a stmt inserted during
gimplification?

> ---
>  gcc/gimplify.cc | 8 ++++++++
>  1 file changed, 8 insertions(+)
>
> diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
> index ade6e335da7..43af38df742 100644
> --- a/gcc/gimplify.cc
> +++ b/gcc/gimplify.cc
> @@ -4370,6 +4370,14 @@ gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, 
> fallback_t fallback)
>    enum tree_code pred_code;
>    gimple_seq seq = NULL;
>
> +  if (TREE_OPERAND (expr, 2) == NULL_TREE)
> +  {
> +      tree var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier
> +                           ("__mcdc_barrier"), integer_type_node);
> +      tree val = build_int_cst (integer_type_node, 0);
> +      TREE_OPERAND (expr, 2) = build2 (INIT_EXPR, TREE_TYPE (var), var, val);
> +  }
> +
>    /* If this COND_EXPR has a value, copy the values into a temporary within
>       the arms.  */
>    if (!VOID_TYPE_P (type))
> --
> 2.30.2
>

Reply via email to