[clang] [Clang][CodeGen] Do not emit lifetime intrinsics for coro promise alloca (PR #140548)
NewSigma wrote: After further consideration, I think this is not a satisfactory solution to the issue. I may revisit it if I develop a concrete plan. Apologies for any inconvenience. https://github.com/llvm/llvm-project/pull/140548 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen] Do not emit lifetime intrinsics for coro promise alloca (PR #140548)
https://github.com/NewSigma closed https://github.com/llvm/llvm-project/pull/140548 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen] Do not emit lifetime intrinsics for coro promise alloca (PR #140548)
https://github.com/NewSigma created https://github.com/llvm/llvm-project/pull/140548 Coro promise has same lifetime as coro frame. It do not need explicit lifetime guarding. If we add lifetimes to it, middle end passes may assume promise dead after lifetime.end, leading to mis-optimizations. Fix #120200 >From d2e1a8d8a650f2a38387c500f942a0c6722c8a84 Mon Sep 17 00:00:00 2001 From: NewSigma Date: Mon, 19 May 2025 22:12:45 +0800 Subject: [PATCH] Do not emit lifetime intrinsics for coro promise alloca --- clang/lib/CodeGen/CGDecl.cpp | 5 + clang/test/CodeGenCoroutines/coro-params.cpp | 3 --- clang/test/CodeGenCoroutines/coro-suspend-cleanups.cpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 4a8f7f6a42ecb..556adebc6fa39 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -1343,6 +1343,11 @@ llvm::Value *CodeGenFunction::EmitLifetimeStart(llvm::TypeSize Size, if (!ShouldEmitLifetimeMarkers) return nullptr; + // No lifetimes on promise alloca, or middle end passes will assume promise + // dead after lifetime.end, leading to mis-optimization + if (Addr->getName() == "__promise") +return nullptr; + assert(Addr->getType()->getPointerAddressSpace() == CGM.getDataLayout().getAllocaAddrSpace() && "Pointer should be in alloca address space"); diff --git a/clang/test/CodeGenCoroutines/coro-params.cpp b/clang/test/CodeGenCoroutines/coro-params.cpp index 719726cca29c5..4f13e093197ff 100644 --- a/clang/test/CodeGenCoroutines/coro-params.cpp +++ b/clang/test/CodeGenCoroutines/coro-params.cpp @@ -84,7 +84,6 @@ void f(int val, MoveOnly moParam, MoveAndCopy mcParam, TrivialABI trivialParam) // CHECK-NEXT: call void @_ZN11MoveAndCopyC1EOS_(ptr {{[^,]*}} %[[McCopy]], ptr noundef nonnull align 4 dereferenceable(4) %[[McParam]]) # // CHECK-NEXT: call void @llvm.lifetime.start.p0( // CHECK-NEXT: call void @_ZN10TrivialABIC1EOS_(ptr {{[^,]*}} %[[TrivialCopy]], ptr {{[^,]*}} %[[TrivialAlloca]]) - // CHECK-NEXT: call void @llvm.lifetime.start.p0( // CHECK-NEXT: invoke void @_ZNSt16coroutine_traitsIJvi8MoveOnly11MoveAndCopy10TrivialABIEE12promise_typeC1Ev( // CHECK: call void @_ZN14suspend_always12await_resumeEv( @@ -106,7 +105,6 @@ void f(int val, MoveOnly moParam, MoveAndCopy mcParam, TrivialABI trivialParam) // Destroy promise, then parameter copies: // CHECK: call void @_ZNSt16coroutine_traitsIJvi8MoveOnly11MoveAndCopy10TrivialABIEE12promise_typeD1Ev(ptr {{[^,]*}} %__promise) - // CHECK-NEXT: call void @llvm.lifetime.end.p0( // CHECK-NEXT: call void @_ZN10TrivialABID1Ev(ptr {{[^,]*}} %[[TrivialCopy]]) // CHECK-NEXT: call void @llvm.lifetime.end.p0( // CHECK-NEXT: call void @_ZN11MoveAndCopyD1Ev(ptr {{[^,]*}} %[[McCopy]]) @@ -135,7 +133,6 @@ void dependent_params(T x, U, U y) { // CHECK-NEXT: call void @_ZN1BC1EOS_(ptr {{[^,]*}} %[[unnamed_copy]], ptr noundef nonnull align 4 dereferenceable(512) %0) // CHECK-NEXT: call void @llvm.lifetime.start.p0( // CHECK-NEXT: call void @_ZN1BC1EOS_(ptr {{[^,]*}} %[[y_copy]], ptr noundef nonnull align 4 dereferenceable(512) %y) - // CHECK-NEXT: call void @llvm.lifetime.start.p0( // CHECK-NEXT: invoke void @_ZNSt16coroutine_traitsIJv1A1BS1_EE12promise_typeC1Ev( co_return; diff --git a/clang/test/CodeGenCoroutines/coro-suspend-cleanups.cpp b/clang/test/CodeGenCoroutines/coro-suspend-cleanups.cpp index d71c2c558996a..d028c127e1e21 100644 --- a/clang/test/CodeGenCoroutines/coro-suspend-cleanups.cpp +++ b/clang/test/CodeGenCoroutines/coro-suspend-cleanups.cpp @@ -52,7 +52,7 @@ coroutine ArrayInitCoro() { // CHECK-NEXT: store ptr %arrayinit.element, ptr %arrayinit.endOfInit.reload.addr, align 8 co_await Awaiter{} // CHECK-NEXT: @_ZNSt14suspend_always11await_readyEv -// CHECK-NEXT: br i1 %{{.+}}, label %await.ready, label %CoroSave30 +// CHECK-NEXT: br i1 %{{.+}}, label %await.ready, label %CoroSave29 }; // CHECK: await.cleanup:; preds = %AfterCoroSuspend{{.*}} // CHECK-NEXT:br label %cleanup{{.*}}.from.await.cleanup ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen] Do not emit lifetime intrinsics for coro promise alloca (PR #140548)
NewSigma wrote: Here is a example ``` LLVM define i32 @fn() { entry: %__promise = alloca i32, align 4 %id = call token @llvm.coro.id(i32 16, ptr nonnull %__promise, ptr nonnull @fn, ptr null) %hdl = call ptr @llvm.coro.begin(token %id, ptr null) #14 %promise.addr = call ptr @llvm.coro.promise(ptr %hdl, i32 4, i1 false) #14 call void @llvm.lifetime.start.p0(i64 4, ptr %promise.addr) #2 store i32 5, ptr %promise.addr, align 4 ; DSE eliminates call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %promise.addr) #2 %0 = call i1 @llvm.coro.end(ptr null, i1 false, token none) #14 %value = load i32, ptr %promise.addr, align 4 ret i32 %value } ``` https://github.com/llvm/llvm-project/pull/140548 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen] Do not emit lifetime intrinsics for coro promise alloca (PR #140548)
https://github.com/NewSigma updated https://github.com/llvm/llvm-project/pull/140548 >From d2e1a8d8a650f2a38387c500f942a0c6722c8a84 Mon Sep 17 00:00:00 2001 From: NewSigma Date: Mon, 19 May 2025 22:12:45 +0800 Subject: [PATCH 1/2] Do not emit lifetime intrinsics for coro promise alloca --- clang/lib/CodeGen/CGDecl.cpp | 5 + clang/test/CodeGenCoroutines/coro-params.cpp | 3 --- clang/test/CodeGenCoroutines/coro-suspend-cleanups.cpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 4a8f7f6a42ecb..556adebc6fa39 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -1343,6 +1343,11 @@ llvm::Value *CodeGenFunction::EmitLifetimeStart(llvm::TypeSize Size, if (!ShouldEmitLifetimeMarkers) return nullptr; + // No lifetimes on promise alloca, or middle end passes will assume promise + // dead after lifetime.end, leading to mis-optimization + if (Addr->getName() == "__promise") +return nullptr; + assert(Addr->getType()->getPointerAddressSpace() == CGM.getDataLayout().getAllocaAddrSpace() && "Pointer should be in alloca address space"); diff --git a/clang/test/CodeGenCoroutines/coro-params.cpp b/clang/test/CodeGenCoroutines/coro-params.cpp index 719726cca29c5..4f13e093197ff 100644 --- a/clang/test/CodeGenCoroutines/coro-params.cpp +++ b/clang/test/CodeGenCoroutines/coro-params.cpp @@ -84,7 +84,6 @@ void f(int val, MoveOnly moParam, MoveAndCopy mcParam, TrivialABI trivialParam) // CHECK-NEXT: call void @_ZN11MoveAndCopyC1EOS_(ptr {{[^,]*}} %[[McCopy]], ptr noundef nonnull align 4 dereferenceable(4) %[[McParam]]) # // CHECK-NEXT: call void @llvm.lifetime.start.p0( // CHECK-NEXT: call void @_ZN10TrivialABIC1EOS_(ptr {{[^,]*}} %[[TrivialCopy]], ptr {{[^,]*}} %[[TrivialAlloca]]) - // CHECK-NEXT: call void @llvm.lifetime.start.p0( // CHECK-NEXT: invoke void @_ZNSt16coroutine_traitsIJvi8MoveOnly11MoveAndCopy10TrivialABIEE12promise_typeC1Ev( // CHECK: call void @_ZN14suspend_always12await_resumeEv( @@ -106,7 +105,6 @@ void f(int val, MoveOnly moParam, MoveAndCopy mcParam, TrivialABI trivialParam) // Destroy promise, then parameter copies: // CHECK: call void @_ZNSt16coroutine_traitsIJvi8MoveOnly11MoveAndCopy10TrivialABIEE12promise_typeD1Ev(ptr {{[^,]*}} %__promise) - // CHECK-NEXT: call void @llvm.lifetime.end.p0( // CHECK-NEXT: call void @_ZN10TrivialABID1Ev(ptr {{[^,]*}} %[[TrivialCopy]]) // CHECK-NEXT: call void @llvm.lifetime.end.p0( // CHECK-NEXT: call void @_ZN11MoveAndCopyD1Ev(ptr {{[^,]*}} %[[McCopy]]) @@ -135,7 +133,6 @@ void dependent_params(T x, U, U y) { // CHECK-NEXT: call void @_ZN1BC1EOS_(ptr {{[^,]*}} %[[unnamed_copy]], ptr noundef nonnull align 4 dereferenceable(512) %0) // CHECK-NEXT: call void @llvm.lifetime.start.p0( // CHECK-NEXT: call void @_ZN1BC1EOS_(ptr {{[^,]*}} %[[y_copy]], ptr noundef nonnull align 4 dereferenceable(512) %y) - // CHECK-NEXT: call void @llvm.lifetime.start.p0( // CHECK-NEXT: invoke void @_ZNSt16coroutine_traitsIJv1A1BS1_EE12promise_typeC1Ev( co_return; diff --git a/clang/test/CodeGenCoroutines/coro-suspend-cleanups.cpp b/clang/test/CodeGenCoroutines/coro-suspend-cleanups.cpp index d71c2c558996a..d028c127e1e21 100644 --- a/clang/test/CodeGenCoroutines/coro-suspend-cleanups.cpp +++ b/clang/test/CodeGenCoroutines/coro-suspend-cleanups.cpp @@ -52,7 +52,7 @@ coroutine ArrayInitCoro() { // CHECK-NEXT: store ptr %arrayinit.element, ptr %arrayinit.endOfInit.reload.addr, align 8 co_await Awaiter{} // CHECK-NEXT: @_ZNSt14suspend_always11await_readyEv -// CHECK-NEXT: br i1 %{{.+}}, label %await.ready, label %CoroSave30 +// CHECK-NEXT: br i1 %{{.+}}, label %await.ready, label %CoroSave29 }; // CHECK: await.cleanup:; preds = %AfterCoroSuspend{{.*}} // CHECK-NEXT:br label %cleanup{{.*}}.from.await.cleanup >From 8f3a3bdc40d418d1b9325c63236b5d5741d0d760 Mon Sep 17 00:00:00 2001 From: NewSigma Date: Tue, 20 May 2025 08:03:02 +0800 Subject: [PATCH 2/2] Use VarDecl::getName instead of Value::getName --- clang/lib/CodeGen/CGDecl.cpp | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 556adebc6fa39..a308b8bf2c387 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -1343,11 +1343,6 @@ llvm::Value *CodeGenFunction::EmitLifetimeStart(llvm::TypeSize Size, if (!ShouldEmitLifetimeMarkers) return nullptr; - // No lifetimes on promise alloca, or middle end passes will assume promise - // dead after lifetime.end, leading to mis-optimization - if (Addr->getName() == "__promise") -return nullptr; - assert(Addr->getType()->getPointerAddressSpace() == CGM.getDataLayout().getAllocaAddrSpace() && "Poin
[clang] [Clang][CodeGen] Do not emit lifetime intrinsics for coro promise alloca (PR #140548)
@@ -1343,6 +1343,11 @@ llvm::Value *CodeGenFunction::EmitLifetimeStart(llvm::TypeSize Size, if (!ShouldEmitLifetimeMarkers) return nullptr; + // No lifetimes on promise alloca, or middle end passes will assume promise + // dead after lifetime.end, leading to mis-optimization + if (Addr->getName() == "__promise") NewSigma wrote: Thank you for catching that. I've now used VarDecl::getName and tested it on non-assert builds. https://github.com/llvm/llvm-project/pull/140548 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [LLVM][Coro] Add LifetimeMovePass (PR #144319)
https://github.com/NewSigma created https://github.com/llvm/llvm-project/pull/144319 As suggested by @ChuanqiXu9 in #14 , I propose LifetimeMovePass, which was previously part of the CoroSplit pass, should now appear as a general pass. Lifetime markers determine whether we place alloca on the frame or on the stack. By moving these markers to optimized positions, we can reduce the coroutine frame size, leading to significant memory savings. The LifetimeMovePass is positioned between SimplifyCFG and InstCombine. Currently, it only applies to pre-split coroutines, as I have not yet developed a concrete plan for its interaction with non-coroutine code. This patch is WIP, feel free to share your feedback or suggestions. Close #49716 >From 584d47295f7719f96ee77d32a6b4329f82be Mon Sep 17 00:00:00 2001 From: NewSigma Date: Mon, 16 Jun 2025 15:36:53 +0800 Subject: [PATCH 1/3] Add LifetimeMovePass --- clang/test/CodeGenCoroutines/pr56919.cpp | 6 +- .../llvm/Transforms/Scalar/LifetimeMove.h | 23 ++ llvm/lib/Passes/PassBuilder.cpp | 1 + llvm/lib/Passes/PassRegistry.def | 1 + llvm/lib/Transforms/Coroutines/CoroFrame.cpp | 88 +-- llvm/lib/Transforms/Scalar/CMakeLists.txt | 1 + llvm/lib/Transforms/Scalar/LifetimeMove.cpp | 223 ++ .../Transforms/Coroutines/coro-alloca-07.ll | 4 +- .../Coroutines/coro-split-rise-lifetime-01.ll | 39 +++ .../Coroutines/coro-split-rise-lifetime-02.ll | 61 + .../Coroutines/coro-split-rise-lifetime-03.ll | 62 + .../Coroutines/coro-split-sink-lifetime-01.ll | 2 +- .../Coroutines/coro-split-sink-lifetime-02.ll | 2 +- .../Coroutines/coro-split-sink-lifetime-03.ll | 2 +- .../Coroutines/coro-split-sink-lifetime-04.ll | 2 +- 15 files changed, 422 insertions(+), 95 deletions(-) create mode 100644 llvm/include/llvm/Transforms/Scalar/LifetimeMove.h create mode 100644 llvm/lib/Transforms/Scalar/LifetimeMove.cpp create mode 100644 llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-01.ll create mode 100644 llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-02.ll create mode 100644 llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-03.ll diff --git a/clang/test/CodeGenCoroutines/pr56919.cpp b/clang/test/CodeGenCoroutines/pr56919.cpp index baa8c27ce6649..e709cecf6d93a 100644 --- a/clang/test/CodeGenCoroutines/pr56919.cpp +++ b/clang/test/CodeGenCoroutines/pr56919.cpp @@ -111,15 +111,15 @@ Task Bar() { co_await Baz(); } // CHECK: _Z3Quxv.destroy:{{.*}} // CHECK-NEXT: # -// CHECK-NEXT: movl$40, %esi +// CHECK-NEXT: movl$32, %esi // CHECK-NEXT: jmp _ZdlPvm@PLT // CHECK: _Z3Bazv.destroy:{{.*}} // CHECK-NEXT: # -// CHECK-NEXT: movl$80, %esi +// CHECK-NEXT: movl$64, %esi // CHECK-NEXT: jmp _ZdlPvm // CHECK: _Z3Barv.destroy:{{.*}} // CHECK-NEXT: # -// CHECK-NEXT: movl$120, %esi +// CHECK-NEXT: movl$96, %esi // CHECK-NEXT: jmp _ZdlPvm diff --git a/llvm/include/llvm/Transforms/Scalar/LifetimeMove.h b/llvm/include/llvm/Transforms/Scalar/LifetimeMove.h new file mode 100644 index 0..f9a690433cb77 --- /dev/null +++ b/llvm/include/llvm/Transforms/Scalar/LifetimeMove.h @@ -0,0 +1,23 @@ +//===- LifetimeMove.h - Narrowing lifetimes -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLVM_TRANSFORMS_SCALAR_LIFETIMEMOVER_H +#define LLVM_TRANSFORMS_SCALAR_LIFETIMEMOVER_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +struct LifetimeMovePass : PassInfoMixin { + /// Run the pass over the function. + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; + +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_SCALAR_LIFETIMEMOVER_H diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index a6c59c1ca846e..03ed9c51c2b74 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -279,6 +279,7 @@ #include "llvm/Transforms/Scalar/JumpTableToSwitch.h" #include "llvm/Transforms/Scalar/JumpThreading.h" #include "llvm/Transforms/Scalar/LICM.h" +#include "llvm/Transforms/Scalar/LifetimeMove.h" #include "llvm/Transforms/Scalar/LoopAccessAnalysisPrinter.h" #include "llvm/Transforms/Scalar/LoopBoundSplit.h" #include "llvm/Transforms/Scalar/LoopDataPrefetch.h" diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index fe6f13477bb12..c457efc307bb4 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -402,6 +402,7 @@ FUNCTION_PASS("kcfi", KCFIPass()) FUNCTION_PASS("kernel-info", KernelInfoPrinter(TM)) FUNCTION_PASS("lcssa", LCSSAPass()) FUNCTION_PASS("libcalls-shrinkwrap", LibCallsShrink
[clang] [llvm] [Transforms] Add LifetimeMovePass (PR #144319)
https://github.com/NewSigma updated https://github.com/llvm/llvm-project/pull/144319 >From 584d47295f7719f96ee77d32a6b4329f82be Mon Sep 17 00:00:00 2001 From: NewSigma Date: Mon, 16 Jun 2025 15:36:53 +0800 Subject: [PATCH 1/8] Add LifetimeMovePass --- clang/test/CodeGenCoroutines/pr56919.cpp | 6 +- .../llvm/Transforms/Scalar/LifetimeMove.h | 23 ++ llvm/lib/Passes/PassBuilder.cpp | 1 + llvm/lib/Passes/PassRegistry.def | 1 + llvm/lib/Transforms/Coroutines/CoroFrame.cpp | 88 +-- llvm/lib/Transforms/Scalar/CMakeLists.txt | 1 + llvm/lib/Transforms/Scalar/LifetimeMove.cpp | 223 ++ .../Transforms/Coroutines/coro-alloca-07.ll | 4 +- .../Coroutines/coro-split-rise-lifetime-01.ll | 39 +++ .../Coroutines/coro-split-rise-lifetime-02.ll | 61 + .../Coroutines/coro-split-rise-lifetime-03.ll | 62 + .../Coroutines/coro-split-sink-lifetime-01.ll | 2 +- .../Coroutines/coro-split-sink-lifetime-02.ll | 2 +- .../Coroutines/coro-split-sink-lifetime-03.ll | 2 +- .../Coroutines/coro-split-sink-lifetime-04.ll | 2 +- 15 files changed, 422 insertions(+), 95 deletions(-) create mode 100644 llvm/include/llvm/Transforms/Scalar/LifetimeMove.h create mode 100644 llvm/lib/Transforms/Scalar/LifetimeMove.cpp create mode 100644 llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-01.ll create mode 100644 llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-02.ll create mode 100644 llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-03.ll diff --git a/clang/test/CodeGenCoroutines/pr56919.cpp b/clang/test/CodeGenCoroutines/pr56919.cpp index baa8c27ce6649..e709cecf6d93a 100644 --- a/clang/test/CodeGenCoroutines/pr56919.cpp +++ b/clang/test/CodeGenCoroutines/pr56919.cpp @@ -111,15 +111,15 @@ Task Bar() { co_await Baz(); } // CHECK: _Z3Quxv.destroy:{{.*}} // CHECK-NEXT: # -// CHECK-NEXT: movl$40, %esi +// CHECK-NEXT: movl$32, %esi // CHECK-NEXT: jmp _ZdlPvm@PLT // CHECK: _Z3Bazv.destroy:{{.*}} // CHECK-NEXT: # -// CHECK-NEXT: movl$80, %esi +// CHECK-NEXT: movl$64, %esi // CHECK-NEXT: jmp _ZdlPvm // CHECK: _Z3Barv.destroy:{{.*}} // CHECK-NEXT: # -// CHECK-NEXT: movl$120, %esi +// CHECK-NEXT: movl$96, %esi // CHECK-NEXT: jmp _ZdlPvm diff --git a/llvm/include/llvm/Transforms/Scalar/LifetimeMove.h b/llvm/include/llvm/Transforms/Scalar/LifetimeMove.h new file mode 100644 index 0..f9a690433cb77 --- /dev/null +++ b/llvm/include/llvm/Transforms/Scalar/LifetimeMove.h @@ -0,0 +1,23 @@ +//===- LifetimeMove.h - Narrowing lifetimes -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLVM_TRANSFORMS_SCALAR_LIFETIMEMOVER_H +#define LLVM_TRANSFORMS_SCALAR_LIFETIMEMOVER_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +struct LifetimeMovePass : PassInfoMixin { + /// Run the pass over the function. + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; + +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_SCALAR_LIFETIMEMOVER_H diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index a6c59c1ca846e..03ed9c51c2b74 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -279,6 +279,7 @@ #include "llvm/Transforms/Scalar/JumpTableToSwitch.h" #include "llvm/Transforms/Scalar/JumpThreading.h" #include "llvm/Transforms/Scalar/LICM.h" +#include "llvm/Transforms/Scalar/LifetimeMove.h" #include "llvm/Transforms/Scalar/LoopAccessAnalysisPrinter.h" #include "llvm/Transforms/Scalar/LoopBoundSplit.h" #include "llvm/Transforms/Scalar/LoopDataPrefetch.h" diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index fe6f13477bb12..c457efc307bb4 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -402,6 +402,7 @@ FUNCTION_PASS("kcfi", KCFIPass()) FUNCTION_PASS("kernel-info", KernelInfoPrinter(TM)) FUNCTION_PASS("lcssa", LCSSAPass()) FUNCTION_PASS("libcalls-shrinkwrap", LibCallsShrinkWrapPass()) +FUNCTION_PASS("lifetime-move", LifetimeMovePass()) FUNCTION_PASS("load-store-vectorizer", LoadStoreVectorizerPass()) FUNCTION_PASS("loop-data-prefetch", LoopDataPrefetchPass()) FUNCTION_PASS("loop-distribute", LoopDistributePass()) diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp index 53d78edda2e9f..a7d7e6ef6d710 100644 --- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp @@ -18,6 +18,7 @@ #include "CoroInternal.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Analysis/PostDominators.h" #include "ll
[clang] [llvm] [Transforms] Add LifetimeMovePass (PR #144319)
https://github.com/NewSigma updated https://github.com/llvm/llvm-project/pull/144319 >From 584d47295f7719f96ee77d32a6b4329f82be Mon Sep 17 00:00:00 2001 From: NewSigma Date: Mon, 16 Jun 2025 15:36:53 +0800 Subject: [PATCH 1/9] Add LifetimeMovePass --- clang/test/CodeGenCoroutines/pr56919.cpp | 6 +- .../llvm/Transforms/Scalar/LifetimeMove.h | 23 ++ llvm/lib/Passes/PassBuilder.cpp | 1 + llvm/lib/Passes/PassRegistry.def | 1 + llvm/lib/Transforms/Coroutines/CoroFrame.cpp | 88 +-- llvm/lib/Transforms/Scalar/CMakeLists.txt | 1 + llvm/lib/Transforms/Scalar/LifetimeMove.cpp | 223 ++ .../Transforms/Coroutines/coro-alloca-07.ll | 4 +- .../Coroutines/coro-split-rise-lifetime-01.ll | 39 +++ .../Coroutines/coro-split-rise-lifetime-02.ll | 61 + .../Coroutines/coro-split-rise-lifetime-03.ll | 62 + .../Coroutines/coro-split-sink-lifetime-01.ll | 2 +- .../Coroutines/coro-split-sink-lifetime-02.ll | 2 +- .../Coroutines/coro-split-sink-lifetime-03.ll | 2 +- .../Coroutines/coro-split-sink-lifetime-04.ll | 2 +- 15 files changed, 422 insertions(+), 95 deletions(-) create mode 100644 llvm/include/llvm/Transforms/Scalar/LifetimeMove.h create mode 100644 llvm/lib/Transforms/Scalar/LifetimeMove.cpp create mode 100644 llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-01.ll create mode 100644 llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-02.ll create mode 100644 llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-03.ll diff --git a/clang/test/CodeGenCoroutines/pr56919.cpp b/clang/test/CodeGenCoroutines/pr56919.cpp index baa8c27ce6649..e709cecf6d93a 100644 --- a/clang/test/CodeGenCoroutines/pr56919.cpp +++ b/clang/test/CodeGenCoroutines/pr56919.cpp @@ -111,15 +111,15 @@ Task Bar() { co_await Baz(); } // CHECK: _Z3Quxv.destroy:{{.*}} // CHECK-NEXT: # -// CHECK-NEXT: movl$40, %esi +// CHECK-NEXT: movl$32, %esi // CHECK-NEXT: jmp _ZdlPvm@PLT // CHECK: _Z3Bazv.destroy:{{.*}} // CHECK-NEXT: # -// CHECK-NEXT: movl$80, %esi +// CHECK-NEXT: movl$64, %esi // CHECK-NEXT: jmp _ZdlPvm // CHECK: _Z3Barv.destroy:{{.*}} // CHECK-NEXT: # -// CHECK-NEXT: movl$120, %esi +// CHECK-NEXT: movl$96, %esi // CHECK-NEXT: jmp _ZdlPvm diff --git a/llvm/include/llvm/Transforms/Scalar/LifetimeMove.h b/llvm/include/llvm/Transforms/Scalar/LifetimeMove.h new file mode 100644 index 0..f9a690433cb77 --- /dev/null +++ b/llvm/include/llvm/Transforms/Scalar/LifetimeMove.h @@ -0,0 +1,23 @@ +//===- LifetimeMove.h - Narrowing lifetimes -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLVM_TRANSFORMS_SCALAR_LIFETIMEMOVER_H +#define LLVM_TRANSFORMS_SCALAR_LIFETIMEMOVER_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +struct LifetimeMovePass : PassInfoMixin { + /// Run the pass over the function. + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; + +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_SCALAR_LIFETIMEMOVER_H diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index a6c59c1ca846e..03ed9c51c2b74 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -279,6 +279,7 @@ #include "llvm/Transforms/Scalar/JumpTableToSwitch.h" #include "llvm/Transforms/Scalar/JumpThreading.h" #include "llvm/Transforms/Scalar/LICM.h" +#include "llvm/Transforms/Scalar/LifetimeMove.h" #include "llvm/Transforms/Scalar/LoopAccessAnalysisPrinter.h" #include "llvm/Transforms/Scalar/LoopBoundSplit.h" #include "llvm/Transforms/Scalar/LoopDataPrefetch.h" diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index fe6f13477bb12..c457efc307bb4 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -402,6 +402,7 @@ FUNCTION_PASS("kcfi", KCFIPass()) FUNCTION_PASS("kernel-info", KernelInfoPrinter(TM)) FUNCTION_PASS("lcssa", LCSSAPass()) FUNCTION_PASS("libcalls-shrinkwrap", LibCallsShrinkWrapPass()) +FUNCTION_PASS("lifetime-move", LifetimeMovePass()) FUNCTION_PASS("load-store-vectorizer", LoadStoreVectorizerPass()) FUNCTION_PASS("loop-data-prefetch", LoopDataPrefetchPass()) FUNCTION_PASS("loop-distribute", LoopDistributePass()) diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp index 53d78edda2e9f..a7d7e6ef6d710 100644 --- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp @@ -18,6 +18,7 @@ #include "CoroInternal.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Analysis/PostDominators.h" #include "ll
[clang] [llvm] [Transforms] Add LifetimeMovePass (PR #144319)
NewSigma wrote: RFC: https://discourse.llvm.org/t/rfc-add-lifetimemovepass/87005 https://github.com/llvm/llvm-project/pull/144319 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [Transforms] Add LifetimeMovePass (PR #144319)
https://github.com/NewSigma updated https://github.com/llvm/llvm-project/pull/144319 >From 584d47295f7719f96ee77d32a6b4329f82be Mon Sep 17 00:00:00 2001 From: NewSigma Date: Mon, 16 Jun 2025 15:36:53 +0800 Subject: [PATCH 01/10] Add LifetimeMovePass --- clang/test/CodeGenCoroutines/pr56919.cpp | 6 +- .../llvm/Transforms/Scalar/LifetimeMove.h | 23 ++ llvm/lib/Passes/PassBuilder.cpp | 1 + llvm/lib/Passes/PassRegistry.def | 1 + llvm/lib/Transforms/Coroutines/CoroFrame.cpp | 88 +-- llvm/lib/Transforms/Scalar/CMakeLists.txt | 1 + llvm/lib/Transforms/Scalar/LifetimeMove.cpp | 223 ++ .../Transforms/Coroutines/coro-alloca-07.ll | 4 +- .../Coroutines/coro-split-rise-lifetime-01.ll | 39 +++ .../Coroutines/coro-split-rise-lifetime-02.ll | 61 + .../Coroutines/coro-split-rise-lifetime-03.ll | 62 + .../Coroutines/coro-split-sink-lifetime-01.ll | 2 +- .../Coroutines/coro-split-sink-lifetime-02.ll | 2 +- .../Coroutines/coro-split-sink-lifetime-03.ll | 2 +- .../Coroutines/coro-split-sink-lifetime-04.ll | 2 +- 15 files changed, 422 insertions(+), 95 deletions(-) create mode 100644 llvm/include/llvm/Transforms/Scalar/LifetimeMove.h create mode 100644 llvm/lib/Transforms/Scalar/LifetimeMove.cpp create mode 100644 llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-01.ll create mode 100644 llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-02.ll create mode 100644 llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-03.ll diff --git a/clang/test/CodeGenCoroutines/pr56919.cpp b/clang/test/CodeGenCoroutines/pr56919.cpp index baa8c27ce6649..e709cecf6d93a 100644 --- a/clang/test/CodeGenCoroutines/pr56919.cpp +++ b/clang/test/CodeGenCoroutines/pr56919.cpp @@ -111,15 +111,15 @@ Task Bar() { co_await Baz(); } // CHECK: _Z3Quxv.destroy:{{.*}} // CHECK-NEXT: # -// CHECK-NEXT: movl$40, %esi +// CHECK-NEXT: movl$32, %esi // CHECK-NEXT: jmp _ZdlPvm@PLT // CHECK: _Z3Bazv.destroy:{{.*}} // CHECK-NEXT: # -// CHECK-NEXT: movl$80, %esi +// CHECK-NEXT: movl$64, %esi // CHECK-NEXT: jmp _ZdlPvm // CHECK: _Z3Barv.destroy:{{.*}} // CHECK-NEXT: # -// CHECK-NEXT: movl$120, %esi +// CHECK-NEXT: movl$96, %esi // CHECK-NEXT: jmp _ZdlPvm diff --git a/llvm/include/llvm/Transforms/Scalar/LifetimeMove.h b/llvm/include/llvm/Transforms/Scalar/LifetimeMove.h new file mode 100644 index 0..f9a690433cb77 --- /dev/null +++ b/llvm/include/llvm/Transforms/Scalar/LifetimeMove.h @@ -0,0 +1,23 @@ +//===- LifetimeMove.h - Narrowing lifetimes -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLVM_TRANSFORMS_SCALAR_LIFETIMEMOVER_H +#define LLVM_TRANSFORMS_SCALAR_LIFETIMEMOVER_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +struct LifetimeMovePass : PassInfoMixin { + /// Run the pass over the function. + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; + +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_SCALAR_LIFETIMEMOVER_H diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index a6c59c1ca846e..03ed9c51c2b74 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -279,6 +279,7 @@ #include "llvm/Transforms/Scalar/JumpTableToSwitch.h" #include "llvm/Transforms/Scalar/JumpThreading.h" #include "llvm/Transforms/Scalar/LICM.h" +#include "llvm/Transforms/Scalar/LifetimeMove.h" #include "llvm/Transforms/Scalar/LoopAccessAnalysisPrinter.h" #include "llvm/Transforms/Scalar/LoopBoundSplit.h" #include "llvm/Transforms/Scalar/LoopDataPrefetch.h" diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index fe6f13477bb12..c457efc307bb4 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -402,6 +402,7 @@ FUNCTION_PASS("kcfi", KCFIPass()) FUNCTION_PASS("kernel-info", KernelInfoPrinter(TM)) FUNCTION_PASS("lcssa", LCSSAPass()) FUNCTION_PASS("libcalls-shrinkwrap", LibCallsShrinkWrapPass()) +FUNCTION_PASS("lifetime-move", LifetimeMovePass()) FUNCTION_PASS("load-store-vectorizer", LoadStoreVectorizerPass()) FUNCTION_PASS("loop-data-prefetch", LoopDataPrefetchPass()) FUNCTION_PASS("loop-distribute", LoopDistributePass()) diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp index 53d78edda2e9f..a7d7e6ef6d710 100644 --- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp @@ -18,6 +18,7 @@ #include "CoroInternal.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Analysis/PostDominators.h" #include "
[clang] [llvm] [LLVM][Coro] Add LifetimeMovePass (PR #144319)
NewSigma wrote: cc @ChuanqiXu9 @nikic https://github.com/llvm/llvm-project/pull/144319 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [LLVM][Coro] Add LifetimeMovePass (PR #144319)
https://github.com/NewSigma updated https://github.com/llvm/llvm-project/pull/144319 >From 584d47295f7719f96ee77d32a6b4329f82be Mon Sep 17 00:00:00 2001 From: NewSigma Date: Mon, 16 Jun 2025 15:36:53 +0800 Subject: [PATCH 1/4] Add LifetimeMovePass --- clang/test/CodeGenCoroutines/pr56919.cpp | 6 +- .../llvm/Transforms/Scalar/LifetimeMove.h | 23 ++ llvm/lib/Passes/PassBuilder.cpp | 1 + llvm/lib/Passes/PassRegistry.def | 1 + llvm/lib/Transforms/Coroutines/CoroFrame.cpp | 88 +-- llvm/lib/Transforms/Scalar/CMakeLists.txt | 1 + llvm/lib/Transforms/Scalar/LifetimeMove.cpp | 223 ++ .../Transforms/Coroutines/coro-alloca-07.ll | 4 +- .../Coroutines/coro-split-rise-lifetime-01.ll | 39 +++ .../Coroutines/coro-split-rise-lifetime-02.ll | 61 + .../Coroutines/coro-split-rise-lifetime-03.ll | 62 + .../Coroutines/coro-split-sink-lifetime-01.ll | 2 +- .../Coroutines/coro-split-sink-lifetime-02.ll | 2 +- .../Coroutines/coro-split-sink-lifetime-03.ll | 2 +- .../Coroutines/coro-split-sink-lifetime-04.ll | 2 +- 15 files changed, 422 insertions(+), 95 deletions(-) create mode 100644 llvm/include/llvm/Transforms/Scalar/LifetimeMove.h create mode 100644 llvm/lib/Transforms/Scalar/LifetimeMove.cpp create mode 100644 llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-01.ll create mode 100644 llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-02.ll create mode 100644 llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-03.ll diff --git a/clang/test/CodeGenCoroutines/pr56919.cpp b/clang/test/CodeGenCoroutines/pr56919.cpp index baa8c27ce6649..e709cecf6d93a 100644 --- a/clang/test/CodeGenCoroutines/pr56919.cpp +++ b/clang/test/CodeGenCoroutines/pr56919.cpp @@ -111,15 +111,15 @@ Task Bar() { co_await Baz(); } // CHECK: _Z3Quxv.destroy:{{.*}} // CHECK-NEXT: # -// CHECK-NEXT: movl$40, %esi +// CHECK-NEXT: movl$32, %esi // CHECK-NEXT: jmp _ZdlPvm@PLT // CHECK: _Z3Bazv.destroy:{{.*}} // CHECK-NEXT: # -// CHECK-NEXT: movl$80, %esi +// CHECK-NEXT: movl$64, %esi // CHECK-NEXT: jmp _ZdlPvm // CHECK: _Z3Barv.destroy:{{.*}} // CHECK-NEXT: # -// CHECK-NEXT: movl$120, %esi +// CHECK-NEXT: movl$96, %esi // CHECK-NEXT: jmp _ZdlPvm diff --git a/llvm/include/llvm/Transforms/Scalar/LifetimeMove.h b/llvm/include/llvm/Transforms/Scalar/LifetimeMove.h new file mode 100644 index 0..f9a690433cb77 --- /dev/null +++ b/llvm/include/llvm/Transforms/Scalar/LifetimeMove.h @@ -0,0 +1,23 @@ +//===- LifetimeMove.h - Narrowing lifetimes -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#ifndef LLVM_TRANSFORMS_SCALAR_LIFETIMEMOVER_H +#define LLVM_TRANSFORMS_SCALAR_LIFETIMEMOVER_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +struct LifetimeMovePass : PassInfoMixin { + /// Run the pass over the function. + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; + +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_SCALAR_LIFETIMEMOVER_H diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index a6c59c1ca846e..03ed9c51c2b74 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -279,6 +279,7 @@ #include "llvm/Transforms/Scalar/JumpTableToSwitch.h" #include "llvm/Transforms/Scalar/JumpThreading.h" #include "llvm/Transforms/Scalar/LICM.h" +#include "llvm/Transforms/Scalar/LifetimeMove.h" #include "llvm/Transforms/Scalar/LoopAccessAnalysisPrinter.h" #include "llvm/Transforms/Scalar/LoopBoundSplit.h" #include "llvm/Transforms/Scalar/LoopDataPrefetch.h" diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index fe6f13477bb12..c457efc307bb4 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -402,6 +402,7 @@ FUNCTION_PASS("kcfi", KCFIPass()) FUNCTION_PASS("kernel-info", KernelInfoPrinter(TM)) FUNCTION_PASS("lcssa", LCSSAPass()) FUNCTION_PASS("libcalls-shrinkwrap", LibCallsShrinkWrapPass()) +FUNCTION_PASS("lifetime-move", LifetimeMovePass()) FUNCTION_PASS("load-store-vectorizer", LoadStoreVectorizerPass()) FUNCTION_PASS("loop-data-prefetch", LoopDataPrefetchPass()) FUNCTION_PASS("loop-distribute", LoopDistributePass()) diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp index 53d78edda2e9f..a7d7e6ef6d710 100644 --- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp @@ -18,6 +18,7 @@ #include "CoroInternal.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Analysis/PostDominators.h" #include "ll
[clang] [llvm] [LLVM][Coro] Add LifetimeMovePass (PR #144319)
@@ -0,0 +1,223 @@ +//===- LifetimeMove.cpp - Narrowing lifetimes -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +// +// The LifetimeMovePass identifies the precise lifetime range of allocas +// +//===--===// + +#include "llvm/Transforms/Scalar/LifetimeMove.h" +#include "llvm/Analysis/CFG.h" +#include "llvm/Analysis/CaptureTracking.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/Transforms/Coroutines/CoroInstr.h" + +#define DEBUG_TYPE "lifetime-move" + +namespace llvm { +static bool mayEscape(Value *V, User *U) { + if (V == U->stripInBoundsOffsets() || isa(U)) +return true; + + if (auto *SI = dyn_cast(U)) +return SI->getValueOperand() == V; + + if (auto *CB = dyn_cast(U)) { +unsigned OpCount = CB->arg_size(); +for (unsigned Op = 0; Op < OpCount; ++Op) + if (V == CB->getArgOperand(Op) && !CB->doesNotCapture(Op)) +return true; + } + return false; +} + +namespace { +class LifetimeMover { + const DominatorTree &DT; + + SmallVector Allocas; + // Critical points are instructions where the crossing of a variable's + // lifetime makes a difference. We attempt to move lifetime.end + // before critical points and lifetime.start after them. + SmallVector CriticalPoints; + + SmallVector LifetimeStarts; + SmallVector LifetimeEnds; + SmallVector OtherUsers; + SmallPtrSet UserBBs; + +public: + LifetimeMover(Function &F, const DominatorTree &DT); + + void run(); + +private: + void sinkLifetimeStartMarkers(AllocaInst *AI); + void riseLifetimeEndMarkers(); + bool collectLifetime(Instruction *I); + void reset(); +}; +} // namespace + +LifetimeMover::LifetimeMover(Function &F, const DominatorTree &DT) : DT(DT) { + for (Instruction &I : instructions(F)) { +if (auto *AI = dyn_cast(&I)) + Allocas.push_back(AI); +else if (isa(I)) + CriticalPoints.push_back(&I); + } +} + +void LifetimeMover::run() { + for (auto *AI : Allocas) { +reset(); + +bool Escape = false; +for (User *U : AI->users()) { + auto *I = cast(U); + // lifetime markers are not actual uses + if (collectLifetime(I)) +continue; + + // GEP and bitcast used by lifetime markers + if (U->hasOneUse() && U->stripPointerCasts() == AI) { +auto *U1 = cast(U->user_back()); +if (collectLifetime(U1)) + continue; + } + + Escape |= mayEscape(AI, U); + OtherUsers.push_back(I); + UserBBs.insert(I->getParent()); +} + +if (!LifetimeStarts.empty()) + sinkLifetimeStartMarkers(AI); + +// Do not move lifetime.end if alloca escapes +if (!LifetimeEnds.empty() && !Escape) + riseLifetimeEndMarkers(); + } +} +/// For each local variable that all of its user are dominated by one of the +/// critical point, we sink their lifetime.start markers to the place where +/// after the critical point. Doing so minimizes the lifetime of each variable. +void LifetimeMover::sinkLifetimeStartMarkers(AllocaInst *AI) { + auto Update = [this](Instruction *Old, Instruction *New) { +// Reject if the new proposal lengthens the lifetime +if (DT.dominates(New, Old)) + return Old; + +bool DomAll = llvm::all_of(UserBBs, [this, New](BasicBlock *UserBB) { + // Instruction level analysis if lifetime and users share a common BB + if (UserBB == New->getParent()) { +return llvm::all_of(OtherUsers, [this, New, UserBB](Instruction *I) { + return UserBB != I->getParent() || DT.dominates(New, I); +}); + } + // Otherwise, BB level analysis is enough + return DT.dominates(New, UserBB); +}); + +return DomAll ? New : Old; + }; + + // AllocaInst is a trivial critical point + Instruction *DomPoint = AI; + for (auto *P : CriticalPoints) +DomPoint = Update(DomPoint, P); + + // Sink lifetime.start markers to dominate block when they are + // only used outside the region. + if (DomPoint != AI) { +// If existing position is better, do nothing +for (auto *P : LifetimeStarts) + if (isPotentiallyReachable(DomPoint, P) && (P == Update(DomPoint, P))) +return; + +auto *NewStart = LifetimeStarts[0]->clone(); +NewStart->replaceUsesOfWith(NewStart->getOperand(1), AI); +NewStart->insertAfter(DomPoint->getIterator()); + +// All the outsided lifetime.start markers are no longer necessary. +for (auto *I : LifetimeStarts) + if (DT.dominates(I, DomPoint)) +I->eraseFromParent(); + } +} +// Find the critical point that is dominated by all users of alloca, +// we will rise lifetime.end markers before the critical point. +void Lifetime
[clang] [llvm] [Transforms] Add LifetimeMovePass (PR #144319)
https://github.com/NewSigma edited https://github.com/llvm/llvm-project/pull/144319 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [CoroSplit] Rise lifetime.end to get smaller frame size (PR #143333)
https://github.com/NewSigma created https://github.com/llvm/llvm-project/pull/14 Lifetime markers determine whether we place alloca on the frame or on the stack. We can move `lifetime.end` to an optimized position to reduce the coroutine frame size. I propose finding the suspend point that dominates all uses of alloca and raising the `lifetime.end` markers to the end of the corresponding save block. This should significantly reduce the frame size. Close #49716 >From 771ff1c9cc7d4b7f95d78d4219288d5c7ca0b83e Mon Sep 17 00:00:00 2001 From: NewSigma Date: Thu, 5 Jun 2025 21:51:06 +0800 Subject: [PATCH] Rise lifetime.end to get smaller frame size --- clang/test/CodeGenCoroutines/pr56919.cpp | 6 +- llvm/lib/Transforms/Coroutines/CoroFrame.cpp | 94 ++- .../Transforms/Coroutines/coro-alloca-06.ll | 2 + .../Transforms/Coroutines/coro-alloca-07.ll | 2 + .../Coroutines/coro-split-rise-lifetime-01.ll | 39 .../Coroutines/coro-split-rise-lifetime-02.ll | 61 .../Coroutines/coro-split-rise-lifetime-03.ll | 62 7 files changed, 259 insertions(+), 7 deletions(-) create mode 100644 llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-01.ll create mode 100644 llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-02.ll create mode 100644 llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-03.ll diff --git a/clang/test/CodeGenCoroutines/pr56919.cpp b/clang/test/CodeGenCoroutines/pr56919.cpp index baa8c27ce6649..e709cecf6d93a 100644 --- a/clang/test/CodeGenCoroutines/pr56919.cpp +++ b/clang/test/CodeGenCoroutines/pr56919.cpp @@ -111,15 +111,15 @@ Task Bar() { co_await Baz(); } // CHECK: _Z3Quxv.destroy:{{.*}} // CHECK-NEXT: # -// CHECK-NEXT: movl$40, %esi +// CHECK-NEXT: movl$32, %esi // CHECK-NEXT: jmp _ZdlPvm@PLT // CHECK: _Z3Bazv.destroy:{{.*}} // CHECK-NEXT: # -// CHECK-NEXT: movl$80, %esi +// CHECK-NEXT: movl$64, %esi // CHECK-NEXT: jmp _ZdlPvm // CHECK: _Z3Barv.destroy:{{.*}} // CHECK-NEXT: # -// CHECK-NEXT: movl$120, %esi +// CHECK-NEXT: movl$96, %esi // CHECK-NEXT: jmp _ZdlPvm diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp index 53d78edda2e9f..fb56832dec9e3 100644 --- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp @@ -18,6 +18,7 @@ #include "CoroInternal.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Analysis/PostDominators.h" #include "llvm/Analysis/StackLifetime.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/DebugInfo.h" @@ -1767,6 +1768,18 @@ static void eliminateSwiftError(Function &F, coro::Shape &Shape) { } } +static bool isLifetimeStart(Instruction *I) { + if (auto *II = dyn_cast(I)) +return II->getIntrinsicID() == Intrinsic::lifetime_start; + return false; +} + +static bool isLifetimeEnd(Instruction *I) { + if (auto *II = dyn_cast(I)) +return II->getIntrinsicID() == Intrinsic::lifetime_end; + return false; +} + /// For each local variable that all of its user are only used inside one of /// suspended region, we sink their lifetime.start markers to the place where /// after the suspend block. Doing so minimizes the lifetime of each variable, @@ -1819,7 +1832,7 @@ static void sinkLifetimeStartMarkers(Function &F, coro::Shape &Shape, for (User *U : AI->users()) { Instruction *UI = cast(U); -// For all users except lifetime.start markers, if they are all +// For all users except lifetime markers, if they are all // dominated by one of the basic blocks and do not cross // suspend points as well, then there is no need to spill the // instruction. @@ -1827,7 +1840,7 @@ static void sinkLifetimeStartMarkers(Function &F, coro::Shape &Shape, Checker.isDefinitionAcrossSuspend(DomBB, UI)) { // Skip lifetime.start, GEP and bitcast used by lifetime.start // markers. - if (collectLifetimeStart(UI, AI)) + if (collectLifetimeStart(UI, AI) || isLifetimeEnd(UI)) continue; Valid = false; break; @@ -1850,6 +1863,78 @@ static void sinkLifetimeStartMarkers(Function &F, coro::Shape &Shape, } } +static bool mayEscape(Value *V, User *U) { + if (V == U->stripInBoundsOffsets() || isa(U)) +return true; + + if (auto *SI = dyn_cast(U)) +return SI->getValueOperand() == V; + + if (auto *CB = dyn_cast(U)) { +unsigned OpCount = CB->arg_size(); +for (unsigned Op = 0; Op < OpCount; ++Op) + if (V == CB->getArgOperand(Op) && !CB->doesNotCapture(Op)) +return true; + } + return false; +} + +// Find the suspend point that dominate all uses of alloca, +// we will rise lifetime.end markers to the end of corresponding save block. +static void riseLifetimeEndMarkers(Function &F, const coro::Shape &Shape) { + const PostDominatorTree PDT(F
[clang] [llvm] [CoroSplit] Rise lifetime.end to get smaller frame size (PR #143333)
https://github.com/NewSigma updated https://github.com/llvm/llvm-project/pull/14 >From 771ff1c9cc7d4b7f95d78d4219288d5c7ca0b83e Mon Sep 17 00:00:00 2001 From: NewSigma Date: Thu, 5 Jun 2025 21:51:06 +0800 Subject: [PATCH 1/2] Rise lifetime.end to get smaller frame size --- clang/test/CodeGenCoroutines/pr56919.cpp | 6 +- llvm/lib/Transforms/Coroutines/CoroFrame.cpp | 94 ++- .../Transforms/Coroutines/coro-alloca-06.ll | 2 + .../Transforms/Coroutines/coro-alloca-07.ll | 2 + .../Coroutines/coro-split-rise-lifetime-01.ll | 39 .../Coroutines/coro-split-rise-lifetime-02.ll | 61 .../Coroutines/coro-split-rise-lifetime-03.ll | 62 7 files changed, 259 insertions(+), 7 deletions(-) create mode 100644 llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-01.ll create mode 100644 llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-02.ll create mode 100644 llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-03.ll diff --git a/clang/test/CodeGenCoroutines/pr56919.cpp b/clang/test/CodeGenCoroutines/pr56919.cpp index baa8c27ce6649..e709cecf6d93a 100644 --- a/clang/test/CodeGenCoroutines/pr56919.cpp +++ b/clang/test/CodeGenCoroutines/pr56919.cpp @@ -111,15 +111,15 @@ Task Bar() { co_await Baz(); } // CHECK: _Z3Quxv.destroy:{{.*}} // CHECK-NEXT: # -// CHECK-NEXT: movl$40, %esi +// CHECK-NEXT: movl$32, %esi // CHECK-NEXT: jmp _ZdlPvm@PLT // CHECK: _Z3Bazv.destroy:{{.*}} // CHECK-NEXT: # -// CHECK-NEXT: movl$80, %esi +// CHECK-NEXT: movl$64, %esi // CHECK-NEXT: jmp _ZdlPvm // CHECK: _Z3Barv.destroy:{{.*}} // CHECK-NEXT: # -// CHECK-NEXT: movl$120, %esi +// CHECK-NEXT: movl$96, %esi // CHECK-NEXT: jmp _ZdlPvm diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp index 53d78edda2e9f..fb56832dec9e3 100644 --- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp @@ -18,6 +18,7 @@ #include "CoroInternal.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Analysis/PostDominators.h" #include "llvm/Analysis/StackLifetime.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/DebugInfo.h" @@ -1767,6 +1768,18 @@ static void eliminateSwiftError(Function &F, coro::Shape &Shape) { } } +static bool isLifetimeStart(Instruction *I) { + if (auto *II = dyn_cast(I)) +return II->getIntrinsicID() == Intrinsic::lifetime_start; + return false; +} + +static bool isLifetimeEnd(Instruction *I) { + if (auto *II = dyn_cast(I)) +return II->getIntrinsicID() == Intrinsic::lifetime_end; + return false; +} + /// For each local variable that all of its user are only used inside one of /// suspended region, we sink their lifetime.start markers to the place where /// after the suspend block. Doing so minimizes the lifetime of each variable, @@ -1819,7 +1832,7 @@ static void sinkLifetimeStartMarkers(Function &F, coro::Shape &Shape, for (User *U : AI->users()) { Instruction *UI = cast(U); -// For all users except lifetime.start markers, if they are all +// For all users except lifetime markers, if they are all // dominated by one of the basic blocks and do not cross // suspend points as well, then there is no need to spill the // instruction. @@ -1827,7 +1840,7 @@ static void sinkLifetimeStartMarkers(Function &F, coro::Shape &Shape, Checker.isDefinitionAcrossSuspend(DomBB, UI)) { // Skip lifetime.start, GEP and bitcast used by lifetime.start // markers. - if (collectLifetimeStart(UI, AI)) + if (collectLifetimeStart(UI, AI) || isLifetimeEnd(UI)) continue; Valid = false; break; @@ -1850,6 +1863,78 @@ static void sinkLifetimeStartMarkers(Function &F, coro::Shape &Shape, } } +static bool mayEscape(Value *V, User *U) { + if (V == U->stripInBoundsOffsets() || isa(U)) +return true; + + if (auto *SI = dyn_cast(U)) +return SI->getValueOperand() == V; + + if (auto *CB = dyn_cast(U)) { +unsigned OpCount = CB->arg_size(); +for (unsigned Op = 0; Op < OpCount; ++Op) + if (V == CB->getArgOperand(Op) && !CB->doesNotCapture(Op)) +return true; + } + return false; +} + +// Find the suspend point that dominate all uses of alloca, +// we will rise lifetime.end markers to the end of corresponding save block. +static void riseLifetimeEndMarkers(Function &F, const coro::Shape &Shape) { + const PostDominatorTree PDT(F); + for (Instruction &I : instructions(F)) { +AllocaInst *AI = dyn_cast(&I); +if (!AI) + continue; + +SmallVector LifetimeEnds; +SmallPtrSet UserBBs{}; +bool Escape = false; +for (User *U : AI->users()) { + auto *I = cast(U); + // lifetime markers are not actual uses + if (isLifetimeStart(I)) +continue; + + if (isLifetimeEnd(I
[clang] [llvm] [CoroSplit] Rise lifetime.end to get smaller frame size (PR #143333)
NewSigma wrote: It sounds interesting, though I still don’t have a clear idea about it. What are the benefits for non-coroutine code, and where exactly should we place it in the pipeline? https://github.com/llvm/llvm-project/pull/14 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [CoroSplit] Rise lifetime.end to get smaller frame size (PR #143333)
NewSigma wrote: Prefer make it a general pass https://github.com/llvm/llvm-project/pull/14 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [CoroSplit] Rise lifetime.end to get smaller frame size (PR #143333)
https://github.com/NewSigma closed https://github.com/llvm/llvm-project/pull/14 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [Transforms] Add LifetimeMovePass (PR #144319)
@@ -0,0 +1,341 @@ +//===- LifetimeMove.cpp - Narrowing lifetimes -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +// +// The LifetimeMovePass identifies the precise lifetime range of allocas and +// repositions lifetime markers to stricter positions. +// +//===--===// + +#include "llvm/Transforms/Utils/LifetimeMove.h" +#include "llvm/Analysis/CFG.h" +#include "llvm/Analysis/CaptureTracking.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/PostDominators.h" +#include "llvm/Analysis/PtrUseVisitor.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/Transforms/Coroutines/CoroInstr.h" + +#define DEBUG_TYPE "lifetime-move" + +namespace llvm { +namespace { +class LifetimeMover : public PtrUseVisitor { + using This = LifetimeMover; + using Base = PtrUseVisitor; + + const DominatorTree &DT; + const LoopInfo &LI; + + SmallVector Allocas; + // Critical points are instructions where the crossing of a variable's + // lifetime makes a difference. We attempt to rise lifetime.end + // before critical points and sink lifetime.start after them. + SmallVector CriticalPoints; + + SmallVector LifetimeStarts; + SmallVector LifetimeEnds; + SmallVector OtherUsers; + SmallPtrSet LifetimeStartBBs; + SmallPtrSet UserBBs; + +public: + LifetimeMover(Function &F, const DominatorTree &DT, const LoopInfo &LI); + + bool run(); + + void visitInstruction(Instruction &I); + void visitPHINode(PHINode &I); + void visitSelectInst(SelectInst &I); + void visitStoreInst(StoreInst &SI); + void visitIntrinsicInst(IntrinsicInst &II); + void visitMemIntrinsic(MemIntrinsic &I); + void visitCallBase(CallBase &CB); + +private: + bool sinkLifetimeStartMarkers(AllocaInst *AI); + bool riseLifetimeEndMarkers(); + void reset(); +}; +} // namespace + +LifetimeMover::LifetimeMover(Function &F, const DominatorTree &DT, + const LoopInfo &LI) +: Base(F.getDataLayout()), DT(DT), LI(LI) { + for (Instruction &I : instructions(F)) { +if (auto *AI = dyn_cast(&I)) + Allocas.push_back(AI); +else if (isa(I)) + continue; +else if (isa(I)) + CriticalPoints.push_back(&I); +else if (isa(I)) + CriticalPoints.push_back(&I); +else if (isa(I)) + CriticalPoints.push_back(&I); + } +} + +bool LifetimeMover::run() { + bool Changed = false; + for (auto *AI : Allocas) { +reset(); +Base::visitPtr(*AI); + +if (!LifetimeStarts.empty()) + Changed |= sinkLifetimeStartMarkers(AI); + +// Do not move lifetime.end if alloca escapes +if (!LifetimeEnds.empty() && !PI.isEscaped()) + Changed |= riseLifetimeEndMarkers(); NewSigma wrote: > Should both of those transformation be limited only to allocas that don't > have their address captured? We do not have to check it if alloca has not been captured. And this is the case for the very first `lifetime.start`, as we are doing here. > There are no executions where allocas are live at the same time and their > storage overlaps. You mean 'does not overlap'? > Alive2 demonstration The community has not yet reached a consensus on comparing a pointer outside its lifetime range, according to the RFC above. Therefore, the input IR should be considered invalid. What do we expect transform passes do on an invalid input? Specifically for the demo, LifetimeMovePass does nothing. https://github.com/llvm/llvm-project/pull/144319 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [Transforms] Add LifetimeMovePass (PR #144319)
https://github.com/NewSigma edited https://github.com/llvm/llvm-project/pull/144319 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [Transforms] Add LifetimeMovePass (PR #144319)
https://github.com/NewSigma ready_for_review https://github.com/llvm/llvm-project/pull/144319 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [Transforms] Add LifetimeMovePass (PR #144319)
NewSigma wrote: CI fail seems not related. I'm marking it ready for review because it works in my tests with ASAN enabled, both for coro code and non-coro code. The non-coro part should be landed in another PR if current patch looks good. https://github.com/llvm/llvm-project/pull/144319 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [Transforms] Add LifetimeMovePass (PR #144319)
@@ -0,0 +1,341 @@ +//===- LifetimeMove.cpp - Narrowing lifetimes -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +// +// The LifetimeMovePass identifies the precise lifetime range of allocas and +// repositions lifetime markers to stricter positions. +// +//===--===// + +#include "llvm/Transforms/Utils/LifetimeMove.h" +#include "llvm/Analysis/CFG.h" +#include "llvm/Analysis/CaptureTracking.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/PostDominators.h" +#include "llvm/Analysis/PtrUseVisitor.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/Transforms/Coroutines/CoroInstr.h" + +#define DEBUG_TYPE "lifetime-move" + +namespace llvm { +namespace { +class LifetimeMover : public PtrUseVisitor { + using This = LifetimeMover; + using Base = PtrUseVisitor; + + const DominatorTree &DT; + const LoopInfo &LI; + + SmallVector Allocas; + // Critical points are instructions where the crossing of a variable's + // lifetime makes a difference. We attempt to rise lifetime.end + // before critical points and sink lifetime.start after them. + SmallVector CriticalPoints; + + SmallVector LifetimeStarts; + SmallVector LifetimeEnds; + SmallVector OtherUsers; + SmallPtrSet LifetimeStartBBs; + SmallPtrSet UserBBs; + +public: + LifetimeMover(Function &F, const DominatorTree &DT, const LoopInfo &LI); + + bool run(); + + void visitInstruction(Instruction &I); + void visitPHINode(PHINode &I); + void visitSelectInst(SelectInst &I); + void visitStoreInst(StoreInst &SI); + void visitIntrinsicInst(IntrinsicInst &II); + void visitMemIntrinsic(MemIntrinsic &I); + void visitCallBase(CallBase &CB); + +private: + bool sinkLifetimeStartMarkers(AllocaInst *AI); + bool riseLifetimeEndMarkers(); + void reset(); +}; +} // namespace + +LifetimeMover::LifetimeMover(Function &F, const DominatorTree &DT, + const LoopInfo &LI) +: Base(F.getDataLayout()), DT(DT), LI(LI) { + for (Instruction &I : instructions(F)) { +if (auto *AI = dyn_cast(&I)) + Allocas.push_back(AI); +else if (isa(I)) + continue; +else if (isa(I)) + CriticalPoints.push_back(&I); +else if (isa(I)) + CriticalPoints.push_back(&I); +else if (isa(I)) + CriticalPoints.push_back(&I); + } +} + +bool LifetimeMover::run() { + bool Changed = false; + for (auto *AI : Allocas) { +reset(); +Base::visitPtr(*AI); + +if (!LifetimeStarts.empty()) + Changed |= sinkLifetimeStartMarkers(AI); + +// Do not move lifetime.end if alloca escapes +if (!LifetimeEnds.empty() && !PI.isEscaped()) + Changed |= riseLifetimeEndMarkers(); NewSigma wrote: If we want to align with Alive2, restricting to allocas that never escape shall not work. Because 1. Escape is a subset of capturing 2. We do not consider the lifetime of other allocas when optimizing a specific alloca. > I think Alive2 quite correctly points out that this changes observable > behavior. The demo is essentially doing ``` C int src() { char a[1000]; char* p_b; { char b[1000]; p_b = b; } return a == p_b; } int tgt() { char* p_b; { char b[1000]; p_b = b; } char a[1000]; return a == p_b; } ``` The transform looks OK to me. Anyway, what’s the point of comparing alloca pointers except to demonstrate that the optimization works? We might understand the behavior from the backend's perspective. Lifetime markers are hints for optimization, not a requirement, and it is the backend's freedom not to respect them. Correct behavior should not rely on it. https://github.com/llvm/llvm-project/pull/144319 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits