Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does stack space required by a function affect inlining decisions in C/C++?

Would a large amount of stack space required by a function prevent it from being inlined? Such as if I had a 10k automatic buffer on the stack, would that make the function less likely to be inlined?

int inlineme(int args) {
  char svar[10000];

  return stringyfunc(args, svar);
}

I'm more concerned about gcc, but icc and llvm would also be nice to know.

I know this isn't ideal, but I'm very curious. The code is probable also pretty bad on cache too.

like image 582
JasonN Avatar asked Feb 14 '19 15:02

JasonN


2 Answers

Yes, the decision to inline or not depends on the complexity of the function, its stack and registers usage and the context in which the call is made. The rules are compiler- and target platform-dependent. Always check the generated assembly when performance matters.

Compare this version with a 10000-char array not being inlined (GCC 8.2, x64, -O2):

inline int inlineme(int args) {
  char svar[10000];

  return stringyfunc(args, svar);
}

int test(int x) {
    return inlineme(x);
}

Generated assembly:

inlineme(int):
        sub     rsp, 10008
        mov     rsi, rsp
        call    stringyfunc(int, char*)
        add     rsp, 10008
        ret
test(int):
        jmp     inlineme(int)

with this one with a much smaller 10-char array, which is inlined:

inline int inlineme(int args) {
  char svar[10];

  return stringyfunc(args, svar);
}

int test(int x) {
    return inlineme(x);
}

Generated assembly:

test(int):
        sub     rsp, 24
        lea     rsi, [rsp+6]
        call    stringyfunc(int, char*)
        add     rsp, 24
        ret
like image 171
rustyx Avatar answered Oct 29 '22 20:10

rustyx


Such as if I had a 10k automatic buffer on the stack, would that make the function less likely to be inlined?

Not necessarily in general. In fact, inline expansion can sometimes reduce stack space usage due to not having to set up space for function arguments.

Expanding a "wide" call into a single frame which calls other "wide" functions can be a problem though, and unless the optimiser guards against that separately, it may have to avoid expansion of "wide" functions in general.

In case of recursion: Most likely yes.

An example of LLVM source:

if (IsCallerRecursive &&
         AllocatedSize > InlineConstants::TotalAllocaSizeRecursiveCaller) {
       InlineResult IR = "recursive and allocates too much stack space";

From GCC source:

For stack growth limits we always base the growth in stack usage of the callers. We want to prevent applications from segfaulting on stack overflow when functions with huge stack frames gets inlined.

Controlling the limit, from GCC manual:

--param name=value

large-function-growth

  • Specifies maximal growth of large function caused by inlining in percents. For example, parameter value 100 limits large function growth to 2.0 times the original size.

large-stack-frame

  • The limit specifying large stack frames. While inlining the algorithm is trying to not grow past this limit too much.

large-stack-frame-growth

  • Specifies maximal growth of large stack frames caused by inlining in percents. For example, parameter value 1000 limits large stack frame growth to 11 times the original size.
like image 24
eerorika Avatar answered Oct 29 '22 22:10

eerorika