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

            Bug ID: 96482
           Summary: Combination of -finline-small-functions and ipa-cp
                    optimisations causes incorrect values being passed to
                    a function
           Product: gcc
           Version: 11.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: yevh.kolesnikov at gmail dot com
  Target Milestone: ---

The bug was originally reported in mesa:
https://gitlab.freedesktop.org/mesa/mesa/-/issues/3239

Combination of LTO and O3 caused a crash on replaying a video with mpv.
Backtrace showed pretty unrealistic values passed to a function. I reduced a
number of necessary optimisations to:

+ -O1
+ -finline-small-functions
+ -fipa-bit-cp
+ -fipa-cp
+ LTO

It happens with gcc 10.1.0, but not with gcc 9. I bisected the problem to
c7ac9a0c7e3916f192ad41227e16238fd1fa2fbf.

I wasn't able to produce a minimal reproducer, and even though a preprocessed
file doesn't trigger the bug for me (I assume, LTO is essential for this bug),
I'm attaching it anyway.

Looking at the produced assembler, though, shows that it goes wrong somewhere
around a call to addr_to_index at
https://gitlab.freedesktop.org/mesa/mesa/-/blob/7f25f1f106728f0046672adf9c9ed79185265ea5/src/compiler/nir/nir_lower_io.c#L870.
addr_to_index gets inlined and so is nir_channel, called from it.

Those two are pretty simple functions:

static nir_ssa_def *
addr_to_index(nir_builder *b, nir_ssa_def *addr,
              nir_address_format addr_format)
{
   if (addr_format == nir_address_format_32bit_index_offset) {
      assert(addr->num_components == 2);
      return nir_channel(b, addr, 0);
   } else if (addr_format == nir_address_format_vec2_index_32bit_offset) {
      assert(addr->num_components == 3);
      return nir_channels(b, addr, 0x3);
   } else {
      unreachable("bad address format for index");
   }
}

static inline nir_ssa_def *
nir_channel(nir_builder *b, nir_ssa_def *def, unsigned c)
{
   return nir_swizzle(b, def, &c, 1);
}

In the final assembly we end up with just a call to nir_swizzle:
mov    edx,r14d
mov    rsi,r15
mov    rdi,rbp
call   0x7fffd26e0ef9 <nir_swizzle(nir_builder*, nir_ssa_def*, unsigned int
const*, unsigned int)

However, edx, rsi, and rdi contain values, that clearly were ment to the
original addr_to_index function.

Reply via email to