https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121936

            Bug ID: 121936
           Summary: Invalid optimisation (at O3) based on bodies of
                    weak-defined functions
           Product: gcc
           Version: 16.0
            Status: UNCONFIRMED
          Keywords: wrong-code
          Severity: normal
          Priority: P3
         Component: ipa
          Assignee: unassigned at gcc dot gnu.org
          Reporter: iains at gcc dot gnu.org
                CC: jamborm at gcc dot gnu.org, jason at gcc dot gnu.org
  Target Milestone: ---

At optimisation level 3, the bodies of referenced weak defined functions can be
inspected and evaluation of that used to guide optimisation of callers (but
without actually inlining the callee).

This is not valid if the evaluation depends on any content of the callee that
is "unspecified" per the language standard(s).  This is because the actual
callee that prevails at dynamic load time could be produced by an
implementation that makes a different choice for that "unspecified" content.

In general, it would seem quite challenging to determine cases where the
dependent analysis was reasonable and therefore, unless this can be done, we
should disable this optimisation.  Note that at least one other platform has
already taken this step.

In the example below the weak definition `depends_on_unspecified_content()` has
a result that depends on the order of call argument evaluation.

(On x86_64 in this example) we conclude that `check_arg_1_value ()` will always
return true and that therefore `depends_on_unspecified_content()` will always
abort if x == 0.

We then use this information to elide the `if (f(0) == 0)` in `main()` and
unconditionally return 20.

This is wrong code because a different implementation can choose to evaluate
the arguments in a different order, which can mean that
`depends_on_unspecified_content()` is no longer guaranteed to abort for x == 0.
 This is not hypothetical, current clang trunk indeed evaluates in the opposite
order.

Since we have no mechanism to guarantee the implementation that will produce
the edition of `depends_on_unspecified_content()` that is linked at dynamic
load time, this can break at runtime.

With thanks to WG21 colleagues for the suggested test-case basis.

======

class Counter {
  int count = 0;
public:
  int nextCount() { return ++count; }
};

// Will return true if args are evaluated R => L.
[[gnu::used, gnu::noinline]]
inline bool
check_arg_1_value (int a, int b)
{
  return a == 2;
}

// Will abort if x == 0 and args are evaluated R => L.
[[gnu::used, gnu::noinline]]
inline int
depends_on_unpsecified_content (int x)
{
  Counter c;
  if (check_arg_1_value (c.nextCount(), c.nextCount())
      && x == 0)
    __builtin_abort();

  return x;
}

int
main ()
{
   if (f(0) == 0)
     return 5;
  return 20;
}

=====

https://godbolt.org/z/bj487x16K

Reply via email to