Bug 67962 - Optimization opportunity with conditional swap to two MIN/MAX in phiopt
Summary: Optimization opportunity with conditional swap to two MIN/MAX in phiopt
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 5.2.0
: P3 enhancement
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: missed-optimization
Depends on: 125792
Blocks: 80874
  Show dependency treegraph
 
Reported: 2015-10-14 11:06 UTC by Morwenn
Modified: 2026-06-14 21:44 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2016-08-29 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Morwenn 2015-10-14 11:06:21 UTC
If have some algorithms that use an extensive number of conditional swaps like this (a few hundreds I guess):

    if (y < x)
    {
        std::swap(x, y);
    }

I thought that such a construct could be optimized by the compiler, but it appears that the following function is more performant with integers most of the time:

    void swap_if(int& x, int& y)
    {
        int dx = x;
        int dy = y;
        int tmp = x = std::min(dx, dy);
        y ^= dx ^ tmp;
    }

Would it be possible for g++ to recognize this kind of construct and optimize it, at least for integer types? Reordering two values seems like something common enough so that optimizing it could also benefit existing code.

As a side note, I hope that Bugzilla is he right place for this kind of request. Sorry if it isn't.
Comment 1 Richard Biener 2015-10-14 11:43:57 UTC
We miss the opportunity to turn

  <bb 2>:
  if (y_5(D) < x_6(D))
    goto <bb 4>;
  else
    goto <bb 3>;

  <bb 3>:

  <bb 4>:
  # y_4 = PHI <y_5(D)(3), x_6(D)(2)>
  # x_2 = PHI <x_6(D)(3), y_5(D)(2)>

into
 
   y_4 = MAX (x_6, y_5);
   x_2 = MIN (x_6, y_5);

and further optimize MINMAX (ISTR that was suggested elsewhere).  phiopt only
considers a single min/max operation.

Now the question is whether the transform would be profitable in isolation.
Comment 2 Drea Pinski 2016-08-30 06:17:48 UTC
Just for completeness here is the C testcase (std::swap converted below):

int g(int x, int y);
static inline void swap(int *x, int *y)
{
  int t = *x;
  *x = *y;
  *y = t;
}
int f(int x, int y)
{
  if (y < x)
    {
        swap(&x, &y);
    }
  return g(x, y);
}
Comment 3 Drea Pinski 2021-08-30 05:45:28 UTC
Mine, but for gcc 13.  The main problem I see if two cmov might be slower than a branch on x86_64 processors.
Comment 4 Richard Biener 2023-07-21 08:26:11 UTC
(In reply to Andrew Pinski from comment #3)
> Mine, but for gcc 13.  The main problem I see if two cmov might be slower
> than a branch on x86_64 processors.

Two cmov definitely, a min/max pair not.

Now, phiopt will turn

  <bb 2> :
  if (y_16(D) < x_17(D))
    goto <bb 3>; [INV]
  else
    goto <bb 4>; [INV]

  <bb 3> :

  <bb 4> :
  # x_14 = PHI <x_17(D)(2), y_16(D)(3)>
  if (y_16(D) < x_17(D))
    goto <bb 5>; [INV]
  else
    goto <bb 6>; [INV]

  <bb 5> :

  <bb 6> :
  # y_15 = PHI <y_16(D)(2), x_17(D)(3)>

into the desired pair but fails for the equivalent

  <bb 2> :
  if (y_16(D) < x_17(D))
    goto <bb 3>; [INV]
  else
    goto <bb 4>; [INV]

  <bb 3> :

  <bb 4> :
  # x_14 = PHI <x_17(D)(2), y_16(D)(3)>
  # y_15 = PHI <y_16(D)(2), x_17(D)(3)>

We do value-replacement for more than one PHI but not others, not exactly
sure why.  We could dry-run convert all PHIs and only if that succeeds
and the condition goes away perform the transforms.  Of course some
transforms might still not be profitable then.
Comment 5 Drea Pinski 2026-05-09 18:10:39 UTC
.