Bug 40207 - request for enhancement: delay argument loading until needed
Summary: request for enhancement: delay argument loading until needed
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 4.3.0
: P3 enhancement
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: missed-optimization
Depends on: 59299
Blocks:
  Show dependency treegraph
 
Reported: 2009-05-20 15:15 UTC by Jason Baron
Modified: 2021-08-08 20:08 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work: 5.1.0, 6.1.0, 7.1.0, 8.1.0
Known to fail: 4.9.1
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jason Baron 2009-05-20 15:15:37 UTC
While working on some Linux kernel code, I've found that functions that
are declared as 'static inline' are having their arguments evaluated
well before they are used. For example I have a function:

static inline void trace(arg1, arg2)
{
    if (unlikely(enabled)) {
        <use the arguments>
    }
}

To make this more concrete here is a simple .c program:


#include <stdio.h>

# define unlikely(x)    __builtin_expect(!!(x), 0)

int enabled = 0;

struct foo {
        int value;
};

struct foo a = {
        .value = 10
};

static inline evaluate(int value) {
        if (unlikely(enabled)) {
                printf("value is: %d\n", value);
        }
}


/*

#define evaluate(val) \
do { \
        if (unlikely(enabled)) { \
                printf("value is: %d\n", val); \
        } \
} while (0)

*/

int main() {

        evaluate((&a)->value);
}


With the macro commented out I get:
00000000004004cc <main>:
  4004cc:       55                      push   %rbp
  4004cd:       48 89 e5                mov    %rsp,%rbp
  4004d0:       48 83 ec 10             sub    $0x10,%rsp
  4004d4:       8b 3d 22 04 20 00       mov    0x200422(%rip),%edi        # 6008fc <a>
  4004da:       e8 02 00 00 00          callq  4004e1 <evaluate>

Thus, a is loaded before the call to 'evaluate'

However, if i compile the macro version of 'evaluate' i get:

00000000004004cc <main>:
  4004cc:       55                      push   %rbp
  4004cd:       48 89 e5                mov    %rsp,%rbp
  4004d0:       48 83 ec 10             sub    $0x10,%rsp
  4004d4:       8b 05 ee 03 20 00       mov    0x2003ee(%rip),%eax        # 6008c8 <enabled>
  4004da:       85 c0                   test   %eax,%eax
  4004dc:       0f 95 c0                setne  %al
  4004df:       0f b6 c0                movzbl %al,%eax
  4004e2:       48 85 c0                test   %rax,%rax
  4004e5:       74 15                   je     4004fc <main+0x30>
  4004e7:       8b 35 c7 03 20 00       mov    0x2003c7(%rip),%esi        # 6008b4 <a>
  4004ed:       bf f8 05 40 00          mov    $0x4005f8,%edi
  4004f2:       b8 00 00 00 00          mov    $0x0,%eax
  4004f7:       e8 bc fe ff ff          callq  4003b8 <printf@plt>


Thus, the load of 'a' happens after the 'unlikely' test as I would like it. It would be nice if gcc could optimize the 'unlikely' case in the 'static inline' function case.

thanks.
Comment 1 Andrew Pinski 2009-05-20 15:21:19 UTC
The define and the static inline functions are not equivalent at all.
#define evaluate(val) \
do { \
      typeof(val) tmpval = val; \
        if (unlikely(enabled)) { \
                printf("value is: %d\n", tmpval); \
        } \
} while (0)

makes the define equivalent to the static inline funciton.
Comment 2 Frank Ch. Eigler 2009-05-20 16:56:10 UTC
(In reply to comment #1)
> The define and the static inline functions are not equivalent at all.

Right, in general, but if the expressions are side-effect-free,
gcc could move their evaluation farther down.
Comment 3 Andrew Pinski 2021-08-08 20:08:55 UTC
Fixed in GCC 5+ by r5-1146.