Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exhaustive stack usage #43598

Open
apolukhin opened this issue Dec 9, 2019 · 13 comments
Open

Exhaustive stack usage #43598

apolukhin opened this issue Dec 9, 2019 · 13 comments
Labels
bugzilla Issues migrated from bugzilla clang:codegen

Comments

@apolukhin
Copy link
Member

apolukhin commented Dec 9, 2019

Bugzilla Link 44253
Version trunk
OS Linux
CC @apolukhin,@davidbolvansky,@dwblaikie,@efriedma-quic,@francisvm,@zygoloid,@rjmccall

Extended Description

Consider the following example:

struct test {
    test(test&&);

    void Extend(test v);
    int data_[4096];
};


test test_func(test t) {
    t.Extend(static_cast<test&&>(t));
    t.Extend(static_cast<test&&>(t));
    return t;
}

With -std=c++11 -O2 flags Clang uses 32768 bytes of stack, GCC uses 16392 bytes.

Note that adding additional t.Extend(static_cast<test&&>(t)); results in stack usage growth for Clang, while GCC keeps using only 16392 bytes.

Godbolt playground: https://godbolt.org/z/MdaNfa

@efriedma-quic
Copy link
Collaborator

Yes, lifetime markers are missing.

@rjmccall
Copy link
Contributor

Yeah, I think it's a known issue that we don't emit them for temporaries.

@francisvm
Copy link
Collaborator

Adding lifetime markers for the temp from EmitAnyExprToTemp(E) in EmitCallArg brings the stack size to 16424.

@rjmccall
Copy link
Contributor

That should be a fairly localized change that doesn't need a solution to the more general issue with temporaries. Did you have a patch for it, or did you just try adding lifetime markers to the IR?

@apolukhin
Copy link
Member Author

The issue affects users of the stackful coroutines by adding very significant memory overhead (each of the thousands coroutines becomes multiple times bigger).

We'd appreciate a fix for 10.0.

@davidbolvansky
Copy link
Collaborator

Seems like Francis has a patch?

@francisvm
Copy link
Collaborator

Sorry about the delay. I had a quick patch but it seems like Erik addressed this in https://reviews.llvm.org/D74094. I see that this has been reverted due to a ppc failure. I locally re-applied the patch and I see the function using only 16424 bytes.

@llvmbot llvmbot transferred this issue from llvm/llvm-bugzilla-archive Dec 10, 2021
@nickdesaulniers
Copy link
Member

I've revived https://reviews.llvm.org/D74094; let's see what issues with that approach may persist, if any.

@nickdesaulniers nickdesaulniers self-assigned this Aug 7, 2023
nickdesaulniers pushed a commit that referenced this issue Aug 16, 2023
…argument allocas

This reverts commit e26c24b.

These temporaries are only used in the callee, and their memory can be
reused after the call is complete.

rdar://58552124

Link: #38157
Link: #41896
Link: #43598
Link: ClangBuiltLinux/linux#39
Link: https://reviews.llvm.org/rGfafc6e4fdf3673dcf557d6c8ae0c0a4bb3184402

Reviewed By: rjmccall

Differential Revision: https://reviews.llvm.org/D74094
@nickdesaulniers
Copy link
Member

@nickdesaulniers nickdesaulniers added this to the LLVM 18.0.0 Release milestone Aug 17, 2023
@EugeneZelenko EugeneZelenko removed this from the LLVM 18.0.0 Release milestone Aug 17, 2023
@nickdesaulniers
Copy link
Member

razmser pushed a commit to SuduIDE/llvm-project that referenced this issue Oct 2, 2023
…argument allocas

This reverts commit e26c24b.

These temporaries are only used in the callee, and their memory can be
reused after the call is complete.

rdar://58552124

Link: llvm#38157
Link: llvm#41896
Link: llvm#43598
Link: ClangBuiltLinux/linux#39
Link: https://reviews.llvm.org/rGfafc6e4fdf3673dcf557d6c8ae0c0a4bb3184402

Reviewed By: rjmccall

Differential Revision: https://reviews.llvm.org/D74094
razmser pushed a commit to SuduIDE/llvm-project that referenced this issue Oct 2, 2023
…argument allocas

This reverts commit e26c24b.

These temporaries are only used in the callee, and their memory can be
reused after the call is complete.

rdar://58552124

Link: llvm#38157
Link: llvm#41896
Link: llvm#43598
Link: ClangBuiltLinux/linux#39
Link: https://reviews.llvm.org/rGfafc6e4fdf3673dcf557d6c8ae0c0a4bb3184402

Reviewed By: rjmccall

Differential Revision: https://reviews.llvm.org/D74094
razmser pushed a commit to SuduIDE/llvm-project that referenced this issue Oct 2, 2023
…argument allocas

This reverts commit e26c24b.

These temporaries are only used in the callee, and their memory can be
reused after the call is complete.

rdar://58552124

Link: llvm#38157
Link: llvm#41896
Link: llvm#43598
Link: ClangBuiltLinux/linux#39
Link: https://reviews.llvm.org/rGfafc6e4fdf3673dcf557d6c8ae0c0a4bb3184402

Reviewed By: rjmccall

Differential Revision: https://reviews.llvm.org/D74094
razmser pushed a commit to SuduIDE/llvm-project that referenced this issue Oct 3, 2023
…argument allocas

This reverts commit e26c24b.

These temporaries are only used in the callee, and their memory can be
reused after the call is complete.

rdar://58552124

Link: llvm#38157
Link: llvm#41896
Link: llvm#43598
Link: ClangBuiltLinux/linux#39
Link: https://reviews.llvm.org/rGfafc6e4fdf3673dcf557d6c8ae0c0a4bb3184402

Reviewed By: rjmccall

Differential Revision: https://reviews.llvm.org/D74094
razmser pushed a commit to SuduIDE/llvm-project that referenced this issue Oct 3, 2023
…argument allocas

This reverts commit e26c24b.

These temporaries are only used in the callee, and their memory can be
reused after the call is complete.

rdar://58552124

Link: llvm#38157
Link: llvm#41896
Link: llvm#43598
Link: ClangBuiltLinux/linux#39
Link: https://reviews.llvm.org/rGfafc6e4fdf3673dcf557d6c8ae0c0a4bb3184402

Reviewed By: rjmccall

Differential Revision: https://reviews.llvm.org/D74094
razmser pushed a commit to SuduIDE/llvm-project that referenced this issue Oct 6, 2023
…argument allocas

This reverts commit e26c24b.

These temporaries are only used in the callee, and their memory can be
reused after the call is complete.

rdar://58552124

Link: llvm#38157
Link: llvm#41896
Link: llvm#43598
Link: ClangBuiltLinux/linux#39
Link: https://reviews.llvm.org/rGfafc6e4fdf3673dcf557d6c8ae0c0a4bb3184402

Reviewed By: rjmccall

Differential Revision: https://reviews.llvm.org/D74094
@nickdesaulniers
Copy link
Member

nickdesaulniers commented Oct 10, 2023

The latest C23 draft § 6.2.4 Storage durations of objects

8 A non-lvalue expression with structure or union type, where the structure or union contains a
member with array type (including, recursively, members of all contained structures and unions)
refers to an object with automatic storage duration and temporary lifetime. 39) Its lifetime begins when the expression is evaluated and its initial value is the value of the expression. Its lifetime ends
when the evaluation of the containing full expression ends. Any attempt to modify an object with
temporary lifetime results in undefined behavior. An object with temporary lifetime behaves as if it
were declared with the type of its value for the purposes of effective type. Such an object need not
have a unique address.

Speaking more with @AaronBallman , Aaron found https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1285.htm introduced the current wording into c11. https://wiki.sei.cmu.edu/confluence/display/c/EXP35-C.+Do+not+modify+objects+with+temporary+lifetime talks more about this.

I'm kind of hung up on the specific wording: where the structure or union contains a member with array type. Why would that matter if the aggregate contains an array or not?

EDIT: sorry, I should file a new bug about C. https://web.archive.org/web/20231010182056/https://yarchive.net/comp/struct_return.html talks more about this in regards to arrays within the returned struct.

@nickdesaulniers nickdesaulniers removed their assignment Oct 10, 2023
razmser pushed a commit to SuduIDE/llvm-project that referenced this issue Oct 11, 2023
…argument allocas

This reverts commit e26c24b.

These temporaries are only used in the callee, and their memory can be
reused after the call is complete.

rdar://58552124

Link: llvm#38157
Link: llvm#41896
Link: llvm#43598
Link: ClangBuiltLinux/linux#39
Link: https://reviews.llvm.org/rGfafc6e4fdf3673dcf557d6c8ae0c0a4bb3184402

Reviewed By: rjmccall

Differential Revision: https://reviews.llvm.org/D74094
@cramertj
Copy link

cramertj commented Sep 5, 2024

The issue affects users of the stackful coroutines by adding very significant memory overhead (each of the thousands coroutines becomes multiple times bigger).

I noticed this today when using coroutines. This function:

Coro<Status> SimplestCoroWithAwait(CoroContext& cx) {
  co_return co_await SimplestCoro(cx);
}

allocates 88 bytes for storage of its stack, but this one:

Coro<Status> SimplestCoroWithTwoAwaits(CoroContext& cx) {
  co_await SimplestCoro(cx);
  co_await SimplestCoro(cx);
  co_await SimplestCoro(cx);
  co_await SimplestCoro(cx);
  co_await SimplestCoro(cx);
  co_await SimplestCoro(cx);
  co_await SimplestCoro(cx);
  co_await SimplestCoro(cx);
  co_await SimplestCoro(cx);
  co_await SimplestCoro(cx);
  co_return co_await SimplestCoro(cx);
}

allocates 408 bytes for its coroutine stack.

In 2019 a similar issue was fixed in the Rust compiler resulting in significant space savings: rust-lang/rust#60187

I'm interested in helping contribute to a fix here. Is https://reviews.llvm.org/D74094 the latest discussion on this?

@AaronBallman
Copy link
Collaborator

I'm interested in helping contribute to a fix here. Is https://reviews.llvm.org/D74094 the latest discussion on this?

That's the latest discussion I'm aware of.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugzilla Issues migrated from bugzilla clang:codegen
Projects
None yet
Development

No branches or pull requests

9 participants