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

Georg-Johann Lay <gjl at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |gjl at gcc dot gnu.org

--- Comment #2 from Georg-Johann Lay <gjl at gcc dot gnu.org> ---
GCC performs poor on code expanded from macros that (recursively) duplicate
macro arguments.  Some time ago I digged into it, and the reason was that it
failed to recognize MIN_EXPR / MAX_EXPR because some optimizations factor out
common subextressions.  Yet another problem is that the expressions inside the
conditions get promoted to int resp. unsigned, whereas the target values remain
types smaller than int.  (Is was actually more complex code that implemented
saturation by nested MIN / MAX expressions.

As a work around, you can try to use inline functions so that GCC will
recognize MAX_EXPR and MIN_EXPR as expected.  The drawback is that you need a
series or macros for each input type like: int8_t, uint8_t, int16_t, ...
(unsigned and signed should be enough thou).

Sample work around for unsigned char:

#define MAX_1(VAR, ...) \
  (VAR)

#define MAX_2(VAR, ...) \
  (((VAR)>MAX_1(__VA_ARGS__))?(VAR):MAX_1(__VA_ARGS__))

__attribute__((__always_inline__))
static inline unsigned char max2 (unsigned char a, unsigned char b)
{
    return MAX_2 (a, b);
}

#undef  MAX_2
#define MAX_2(a, b)  max2 (a, b)

#define MAX_3(VAR, ...) \
  (MAX_2 ((VAR), MAX_2(__VA_ARGS__)))

#define MAX_4(VAR, ...) \
  (MAX_2 ((VAR), MAX_3(__VA_ARGS__)))

#define MAX_5(VAR, ...) \
  (MAX_2 ((VAR), MAX_4(__VA_ARGS__)))

#define MAX_6(VAR, ...) \
  (MAX_2 ((VAR), MAX_5(__VA_ARGS__)))


The .original dump as generated with -fdump-tree-original reads now:


;; Function max2 (null)
{
  return MAX_EXPR <b, a>;
}

;; Function f1_unsigned (null)
{
  return max2 (a1, max2 (a2, max2 (a3, max2 (a1, max2 (a2, a3)))));
}

;; Function f2_unsigned (null)
{
  return max2 (a1, max2 (a2, a3));
}

and after inline expansion everything is nice with MAX_EXPR whereas your
original code leads to:


; Function f1_unsigned (null)
{
  return (unsigned char) MAX_EXPR <MAX_EXPR <MAX_EXPR <MAX_EXPR <a2 > a3 ?
(int) a2 : (int) a3, (int) a1>, (int) a3>, (int) a2>, (int) a1>;
}

;; Function f2_unsigned (null)
{
  return (unsigned char) MAX_EXPR <a2 > a3 ? (int) a2 : (int) a3, (int) a1>;
}


Not all of the expressions are recognized as MAX_EXPR.

Reply via email to