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

no lifetime markers emitted for compound literals #68746

Open
nickdesaulniers opened this issue Oct 10, 2023 · 4 comments
Open

no lifetime markers emitted for compound literals #68746

nickdesaulniers opened this issue Oct 10, 2023 · 4 comments

Comments

@nickdesaulniers
Copy link
Member

nickdesaulniers commented Oct 10, 2023

C23 6.2.4 Storage durations of objects:

5 An object whose identifier is declared with no linkage and without the storage-class specifier static
has automatic storage duration, as do some compound literals. The result of attempting to indirectly
access an object with automatic storage duration from a thread other than the one with which the
object is associated is implementation-defined.
6 For such an object that does not have a variable length array type, its lifetime extends from entry
into the block with which it is associated until execution of that block ends in any way

as noted here: https://reviews.llvm.org/D74094#4647616

example:

struct foo { long long x, y, z; int w; };

void bar (struct foo);

void baz (void) {
    {
        bar((struct foo){
            .x = 42,
            .y = 25,
            .z = 77,
        });
    }
    {
        bar((struct foo){
            .x = 42,
            .y = 25,
            .z = 77,
        });
    }
}

we should emit lifetime markers for those allocas as we should be able to reuse their stack slots. That should help us reduce stack usage for C codebases. cc @rjmccall @ilovepi

It should be noted that C23 added support for static storage duration for those literals (add the static keyword before struct in the literal); AFAICT clang doesn't support those yet, but care should be taken not to emit any lifetime markers for static storage variables (this might not be a concern, since those shouldn't have a corresponding alloca I think).

@llvmbot
Copy link
Collaborator

llvmbot commented Oct 10, 2023

@llvm/issue-subscribers-c

Author: Nick Desaulniers (nickdesaulniers)

C23 6.2.4 Storage durations of objects:

> 5 An object whose identifier is declared with no linkage and without the storage-class specifier static
has automatic storage duration, as do some compound literals. The result of attempting to indirectly
access an object with automatic storage duration from a thread other than the one with which the
object is associated is implementation-defined.
6 For such an object that does not have a variable length array type, its lifetime extends from entry
into the block with which it is associated until execution of that block ends in any way

as noted here: https://reviews.llvm.org/D74094#4647616

example:

struct foo { long long x, y, z; int w; };

void bar (struct foo);

void baz (void) {
    {
        bar((struct foo){
            .x = 42,
            .y = 25,
            .z = 77,
        });
    }
    {
        bar((struct foo){
            .x = 42,
            .y = 25,
            .z = 77,
        });
    }
}

we should emit lifetime markers for those allocas as we should be able to reuse their stack slots. That should help us reduce stack usage for C codebases. cc @rjmccall @ilovepi

@llvmbot
Copy link
Collaborator

llvmbot commented Oct 10, 2023

@llvm/issue-subscribers-clang-codegen

Author: Nick Desaulniers (nickdesaulniers)

C23 6.2.4 Storage durations of objects:

> 5 An object whose identifier is declared with no linkage and without the storage-class specifier static
has automatic storage duration, as do some compound literals. The result of attempting to indirectly
access an object with automatic storage duration from a thread other than the one with which the
object is associated is implementation-defined.
6 For such an object that does not have a variable length array type, its lifetime extends from entry
into the block with which it is associated until execution of that block ends in any way

as noted here: https://reviews.llvm.org/D74094#4647616

example:

struct foo { long long x, y, z; int w; };

void bar (struct foo);

void baz (void) {
    {
        bar((struct foo){
            .x = 42,
            .y = 25,
            .z = 77,
        });
    }
    {
        bar((struct foo){
            .x = 42,
            .y = 25,
            .z = 77,
        });
    }
}

we should emit lifetime markers for those allocas as we should be able to reuse their stack slots. That should help us reduce stack usage for C codebases. cc @rjmccall @ilovepi

@nickdesaulniers
Copy link
Member Author

CodeGenFunction::EmitCompoundLiteralLValue has a comment:

// Block-scope compound literals are destroyed at the end of the enclosing
// scope in C.
if (!getLangOpts().CPlusPlus)
if (QualType::DestructionKind DtorKind = E->getType().isDestructedType())
pushLifetimeExtendedDestroy(getCleanupKind(DtorKind), DeclPtr,
E->getType(), getDestroyer(DtorKind),
DtorKind & EHCleanup);

  4682 ▏ // Block-scope compound literals are destroyed at the end of the enclosing                                    
  4683 ▏ // scope in C.

I wonder why there doesn't seem to be lifetime end markers inserted by calling EmitLifetimeEnd...hmm...

cc @ahatanaka author of 40568fe

@AaronBallman
Copy link
Collaborator

AaronBallman commented Nov 27, 2023

Another thing to keep in mind regarding compound literals in C is that we implement them in a way that is problematic for C23. We implement compound literals as though we gin up memory as-if by magic and then we've got our lvalue, but the model in the C standard is as-if there was a declared object, not just a region of storage. This matters even more now that we have storage class specifiers for compound literals: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3038.htm -- whatever approach we end up taking to solve this for automatics should keep in mind that we're going to need to support static and thread_local compound literals in the near future.

I think we should explore changing compound literals to instead be a DeclRefExpr which references a VarDecl with an invented name. Then storage class specifiers are trivial to support -- put the storage class specifier onto the unnamed variable and emit it as we would any other variable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants