Skip to content

Emit LLVM lifetime intrinsics #1129

Open
@ChuanqiXu9

Description

@ChuanqiXu9
Member

For

struct S {
    int a;
    int b;
};

S getS();

S getS2(const S&);

S foo() {
    return getS2(getS());
}

Compile it with -fclangir -O3 -emit-cir, we got:

cir.func @_Z3foov() -> !ty_S extra(#fn_attr) {
    %0 = cir.alloca !ty_S, !cir.ptr<!ty_S>, ["__retval"] {alignment = 4 : i64} loc(#loc6)
    cir.scope {
      %2 = cir.alloca !ty_S, !cir.ptr<!ty_S>, ["ref.tmp0"] {alignment = 4 : i64} loc(#loc16)
      %3 = cir.call @_Z4getSv() : () -> !ty_S loc(#loc9)
      cir.store %3, %2 : !ty_S, !cir.ptr<!ty_S> loc(#loc9)
      %4 = cir.call @_Z5getS2RK1S(%2) : (!cir.ptr<!ty_S>) -> !ty_S loc(#loc7)
      cir.store %4, %0 : !ty_S, !cir.ptr<!ty_S> loc(#loc7)
    } loc(#loc15)
    %1 = cir.load %0 : !cir.ptr<!ty_S>, !ty_S loc(#loc17)
    cir.return %1 : !ty_S loc(#loc17)
  }

This is good. We explicitly marked the scope for the temporary. However, when we lower it to LLVM, we lost the lifetime informations:

define dso_local %struct.S @_Z3foov() #0 !dbg !7 {
  %1 = alloca %struct.S, i64 1, align 4, !dbg !8
  %2 = alloca %struct.S, i64 1, align 4, !dbg !9
  br label %3, !dbg !8

3:                                                ; preds = %0
  %4 = call %struct.S @_Z4getSv(), !dbg !10
  store %struct.S %4, ptr %1, align 4, !dbg !10
  %5 = call %struct.S @_Z5getS2RK1S(ptr %1), !dbg !11
  store %struct.S %5, ptr %2, align 4, !dbg !11
  br label %6, !dbg !12

6:                                                ; preds = %3
  %7 = load %struct.S, ptr %2, align 4, !dbg !8
  ret %struct.S %7, !dbg !8
}

In the contrary, the emitted LLVM without clangir is:

define dso_local i64 @_Z3foov() #0 {
entry:
  %retval = alloca %struct.S, align 4
  %ref.tmp = alloca %struct.S, align 4
  call void @llvm.lifetime.start.p0(i64 8, ptr %ref.tmp) #3
  %call = call i64 @_Z4getSv()
  store i64 %call, ptr %ref.tmp, align 4
  %call1 = call i64 @_Z5getS2RK1S(ptr noundef nonnull align 4 dereferenceable(8) %ref.tmp)
  store i64 %call1, ptr %retval, align 4
  call void @llvm.lifetime.end.p0(i64 8, ptr %ref.tmp) #3
  %0 = load i64, ptr %retval, align 4
  ret i64 %0
}

where we can see the lifetime markers pretty clearly. The lifetime markers are pretty important for optimizations in the middle end.

We need to do this especially we've already marked the scope clearly.

Activity

bcardosolopes

bcardosolopes commented on Nov 22, 2024

@bcardosolopes
Member

Yes, I'm not sure we have issues tracking this already, but we need to emit lifetime intrinsics, good thing is that we can do that as we unwrap scopes.

changed the title [-]We lack lifetime informations[/-] [+]Emit LLVM lifetime intrinsics[/+] on Nov 22, 2024
Sir-NoChill

Sir-NoChill commented on Dec 1, 2024

@Sir-NoChill

I'm interested in taking a crack at this one, I will likely need some help getting started. I'll keep my updates on this issue.

Sir-NoChill

Sir-NoChill commented on Jan 13, 2025

@Sir-NoChill

Current plan is to create an op (cir::LifetimeOp is my tentative name) that I will emit when we create a temporary within a scope and then when we unroll the scope we can handle the op as required.

bcardosolopes

bcardosolopes commented on Jan 14, 2025

@bcardosolopes
Member

@Sir-NoChill sounds good, keep in mind we need one for start and another for end. Those can probably be an attribute!

Sir-NoChill

Sir-NoChill commented on Jan 14, 2025

@Sir-NoChill

Should these instructions also be associated in some way with the temporary they refer to? Or is it implicit that they are associated with the next instruction?

bcardosolopes

bcardosolopes commented on Jan 14, 2025

@bcardosolopes
Member

As you add the tentative cir::LifetimeOp you should also add the LLVM lowering bits, that will inform you what information you should not miss to add to the operation - the LLVM intrinsics require a size and a pointer, you might be able to derive the size from the original alloca type, but you need to pass in the alloca address. Implicit isn't great because other optimizations can move things around.

el-ev

el-ev commented on Mar 23, 2025

@el-ev
Member

@Sir-NoChill Are you still working on this?

Sir-NoChill

Sir-NoChill commented on Mar 23, 2025

@Sir-NoChill

@el-ev yes, I'm just having difficulty testing... I can push what I have for the op to a branch tomorrow if you want to take a look

Sir-NoChill

Sir-NoChill commented on Mar 31, 2025

@Sir-NoChill

@el-ev The lowering is really wreaking havoc on me, so I think if you still wanted this issue you could take it. I think I need to go practice my lowering passes 🤦

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

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

    Development

    Participants

    @bcardosolopes@el-ev@ChuanqiXu9@Sir-NoChill

    Issue actions

      Emit LLVM lifetime intrinsics · Issue #1129 · llvm/clangir