https://github.com/NewSigma updated https://github.com/llvm/llvm-project/pull/144319
>From 584d47295f7719f96ee77d32a61111b4329f82be Mon Sep 17 00:00:00 2001 From: NewSigma <newsi...@163.com> 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<void> 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 0000000000000..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<LifetimeMovePass> { + /// 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 "llvm/Analysis/StackLifetime.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/DebugInfo.h" @@ -1767,89 +1768,6 @@ static void eliminateSwiftError(Function &F, coro::Shape &Shape) { } } -/// 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, -/// hence minimizing the amount of data we end up putting on the frame. -static void sinkLifetimeStartMarkers(Function &F, coro::Shape &Shape, - SuspendCrossingInfo &Checker, - const DominatorTree &DT) { - if (F.hasOptNone()) - return; - - // Collect all possible basic blocks which may dominate all uses of allocas. - SmallPtrSet<BasicBlock *, 4> DomSet; - DomSet.insert(&F.getEntryBlock()); - for (auto *CSI : Shape.CoroSuspends) { - BasicBlock *SuspendBlock = CSI->getParent(); - assert(coro::isSuspendBlock(SuspendBlock) && - SuspendBlock->getSingleSuccessor() && - "should have split coro.suspend into its own block"); - DomSet.insert(SuspendBlock->getSingleSuccessor()); - } - - for (Instruction &I : instructions(F)) { - AllocaInst* AI = dyn_cast<AllocaInst>(&I); - if (!AI) - continue; - - for (BasicBlock *DomBB : DomSet) { - bool Valid = true; - SmallVector<Instruction *, 1> Lifetimes; - - auto isLifetimeStart = [](Instruction* I) { - if (auto* II = dyn_cast<IntrinsicInst>(I)) - return II->getIntrinsicID() == Intrinsic::lifetime_start; - return false; - }; - - auto collectLifetimeStart = [&](Instruction *U, AllocaInst *AI) { - if (isLifetimeStart(U)) { - Lifetimes.push_back(U); - return true; - } - if (!U->hasOneUse() || U->stripPointerCasts() != AI) - return false; - if (isLifetimeStart(U->user_back())) { - Lifetimes.push_back(U->user_back()); - return true; - } - return false; - }; - - for (User *U : AI->users()) { - Instruction *UI = cast<Instruction>(U); - // For all users except lifetime.start 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. - if (!DT.dominates(DomBB, UI->getParent()) || - Checker.isDefinitionAcrossSuspend(DomBB, UI)) { - // Skip lifetime.start, GEP and bitcast used by lifetime.start - // markers. - if (collectLifetimeStart(UI, AI)) - continue; - Valid = false; - break; - } - } - // Sink lifetime.start markers to dominate block when they are - // only used outside the region. - if (Valid && Lifetimes.size() != 0) { - auto *NewLifetime = Lifetimes[0]->clone(); - NewLifetime->replaceUsesOfWith(NewLifetime->getOperand(1), AI); - NewLifetime->insertBefore(DomBB->getTerminator()->getIterator()); - - // All the outsided lifetime.start markers are no longer necessary. - for (Instruction *S : Lifetimes) - S->eraseFromParent(); - - break; - } - } - } -} - static std::optional<std::pair<Value &, DIExpression &>> salvageDebugInfoImpl(SmallDenseMap<Argument *, AllocaInst *, 4> &ArgToAllocaMap, bool UseEntryValue, Function *F, Value *Storage, @@ -2070,10 +1988,6 @@ void coro::BaseABI::buildCoroutineFrame(bool OptimizeFrame) { doRematerializations(F, Checker, IsMaterializable); const DominatorTree DT(F); - if (Shape.ABI != coro::ABI::Async && Shape.ABI != coro::ABI::Retcon && - Shape.ABI != coro::ABI::RetconOnce) - sinkLifetimeStartMarkers(F, Shape, Checker, DT); - // All values (that are not allocas) that needs to be spilled to the frame. coro::SpillInfo Spills; // All values defined as allocas that need to live in the frame. diff --git a/llvm/lib/Transforms/Scalar/CMakeLists.txt b/llvm/lib/Transforms/Scalar/CMakeLists.txt index 84a5b02043d01..ea0ac853d2716 100644 --- a/llvm/lib/Transforms/Scalar/CMakeLists.txt +++ b/llvm/lib/Transforms/Scalar/CMakeLists.txt @@ -27,6 +27,7 @@ add_llvm_component_library(LLVMScalarOpts JumpThreading.cpp JumpTableToSwitch.cpp LICM.cpp + LifetimeMove.cpp LoopAccessAnalysisPrinter.cpp LoopBoundSplit.cpp LoopSink.cpp diff --git a/llvm/lib/Transforms/Scalar/LifetimeMove.cpp b/llvm/lib/Transforms/Scalar/LifetimeMove.cpp new file mode 100644 index 0000000000000..08349c36d24fc --- /dev/null +++ b/llvm/lib/Transforms/Scalar/LifetimeMove.cpp @@ -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<PHINode>(U)) + return true; + + if (auto *SI = dyn_cast<StoreInst>(U)) + return SI->getValueOperand() == V; + + if (auto *CB = dyn_cast<CallBase>(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<AllocaInst *, 4> 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<Instruction *, 4> CriticalPoints; + + SmallVector<Instruction *, 2> LifetimeStarts; + SmallVector<Instruction *, 2> LifetimeEnds; + SmallVector<Instruction *, 8> OtherUsers; + SmallPtrSet<BasicBlock *, 2> 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<AllocaInst>(&I)) + Allocas.push_back(AI); + else if (isa<AnyCoroSuspendInst>(I)) + CriticalPoints.push_back(&I); + } +} + +void LifetimeMover::run() { + for (auto *AI : Allocas) { + reset(); + + bool Escape = false; + for (User *U : AI->users()) { + auto *I = cast<Instruction>(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<Instruction>(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 LifetimeMover::riseLifetimeEndMarkers() { + auto Update = [this](Instruction *Old, Instruction *New) { + if (Old != nullptr && DT.dominates(Old, New)) + return Old; + + bool DomAll = llvm::all_of(UserBBs, [this, New](BasicBlock *UserBB) { + if (UserBB == New->getParent()) { + return llvm::all_of(OtherUsers, [this, New, UserBB](Instruction *I) { + return UserBB != I->getParent() || DT.dominates(I, New); + }); + } + return DT.dominates(UserBB, New->getParent()); + }); + return DomAll ? New : Old; + }; + + Instruction *DomPoint = nullptr; + for (auto *P : CriticalPoints) + DomPoint = Update(DomPoint, P); + + if (DomPoint != nullptr) { + for (auto *P : LifetimeEnds) + if (isPotentiallyReachable(P, DomPoint) && (P == Update(DomPoint, P))) + return; + + auto *NewEnd = LifetimeEnds[0]->clone(); + NewEnd->insertBefore(DomPoint->getIterator()); + + for (auto *I : LifetimeEnds) + if (DT.dominates(DomPoint, I)) + I->eraseFromParent(); + } +} + +bool LifetimeMover::collectLifetime(Instruction *I) { + if (auto *II = dyn_cast<IntrinsicInst>(I)) { + auto ID = II->getIntrinsicID(); + if (ID == Intrinsic::lifetime_start) { + LifetimeStarts.push_back(I); + return true; + } + + if (ID == Intrinsic::lifetime_end) { + LifetimeEnds.push_back(I); + return true; + } + } + return false; +} + +void LifetimeMover::reset() { + LifetimeStarts.clear(); + LifetimeEnds.clear(); + OtherUsers.clear(); + UserBBs.clear(); +} + +PreservedAnalyses LifetimeMovePass::run(Function &F, + FunctionAnalysisManager &AM) { + // Works for coroutine for now + if (!F.isPresplitCoroutine()) + PreservedAnalyses::all(); + + const DominatorTree &DT = AM.getResult<DominatorTreeAnalysis>(F); + LifetimeMover Mover(F, DT); + Mover.run(); + return PreservedAnalyses::all(); +} +} // namespace llvm diff --git a/llvm/test/Transforms/Coroutines/coro-alloca-07.ll b/llvm/test/Transforms/Coroutines/coro-alloca-07.ll index 3b0acdd794af4..a48bfd0edd0c3 100644 --- a/llvm/test/Transforms/Coroutines/coro-alloca-07.ll +++ b/llvm/test/Transforms/Coroutines/coro-alloca-07.ll @@ -1,6 +1,6 @@ ; Tests that CoroSplit can succesfully determine allocas should live on the frame ; if their aliases are used across suspension points through PHINode. -; RUN: opt < %s -passes='cgscc(coro-split),simplifycfg,early-cse' -S | FileCheck %s +; RUN: opt < %s -passes='cgscc(lifetime-move,coro-split),simplifycfg,early-cse' -S | FileCheck %s define ptr @f(i1 %n) presplitcoroutine { entry: @@ -31,6 +31,8 @@ resume: br label %cleanup cleanup: + call void @llvm.lifetime.end.p0(i64 8, ptr %x) + call void @llvm.lifetime.end.p0(i64 8, ptr %y) %mem = call ptr @llvm.coro.free(token %id, ptr %hdl) call void @free(ptr %mem) br label %suspend diff --git a/llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-01.ll b/llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-01.ll new file mode 100644 index 0000000000000..d38b4deac5533 --- /dev/null +++ b/llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-01.ll @@ -0,0 +1,39 @@ +; Test allocas that do not cross suspension point will not go to frame +; RUN: opt < %s -passes='cgscc(lifetime-move,coro-split),early-cse' -S | FileCheck %s + +; CHECK: %large.alloca = alloca [500 x i8], align 16 +; CHECK-NOT: %large.alloca.reload.addr + +define void @f() presplitcoroutine { +entry: + %large.alloca = alloca [500 x i8], align 16 + %id = call token @llvm.coro.id(i32 16, ptr null, ptr null, ptr null) + %size = call i32 @llvm.coro.size.i32() + %mem = call ptr @malloc(i32 %size) + %hdl = call ptr @llvm.coro.begin(token %id, ptr %mem) + call void @llvm.lifetime.start.p0(i64 500, ptr %large.alloca) + %value = load i8, ptr %large.alloca, align 1 + call void @consume(i8 %value) + %0 = call i8 @llvm.coro.suspend(token none, i1 false) + switch i8 %0, label %exit [ + i8 0, label %suspend + i8 1, label %cleanup + ] + +suspend: + br label %cleanup + +cleanup: + call void @llvm.lifetime.end.p0(i64 500, ptr %large.alloca) + %1 = call ptr @llvm.coro.free(token %id, ptr %mem) + call void @free(ptr %mem) + br label %exit + +exit: + %2 = call i1 @llvm.coro.end(ptr null, i1 false, token none) + ret void +} + +declare void @consume(i8) +declare ptr @malloc(i32) +declare void @free(ptr) diff --git a/llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-02.ll b/llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-02.ll new file mode 100644 index 0000000000000..66a8d2d65727f --- /dev/null +++ b/llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-02.ll @@ -0,0 +1,61 @@ +; Test that we rise lifetime markers to the correct place if there are many suspend points. +; RUN: opt < %s -passes='cgscc(lifetime-move,coro-split),early-cse' -S | FileCheck %s + +; CHECK: %large.alloca = alloca [500 x i8], align 16 +; CHECK-NOT: %large.alloca.reload.addr + +define void @many_suspend() presplitcoroutine { +entry: + %large.alloca = alloca [500 x i8], align 16 + %id = call token @llvm.coro.id(i32 16, ptr null, ptr null, ptr null) + %size = call i64 @llvm.coro.size.i64() + %call = call noalias ptr @malloc(i64 %size) + %hdl = call ptr @llvm.coro.begin(token %id, ptr %call) + call void @llvm.lifetime.start.p0(i64 500, ptr %large.alloca) + %save1 = call token @llvm.coro.save(ptr null) + %sp1 = call i8 @llvm.coro.suspend(token %save1, i1 false) + switch i8 %sp1, label %coro.ret [ + i8 0, label %await.ready + i8 1, label %cleanup + ] + +await.ready: + %save2 = call token @llvm.coro.save(ptr null) + %sp2 = call i8 @llvm.coro.suspend(token %save2, i1 false) + switch i8 %sp2, label %coro.ret [ + i8 0, label %await2.ready + i8 1, label %cleanup + ] + +await2.ready: + %value = load i8, ptr %large.alloca, align 1 + call void @consume(i8 %value) + %save3 = call token @llvm.coro.save(ptr null) + %sp3 = call i8 @llvm.coro.suspend(token %save3, i1 false) + switch i8 %sp3, label %coro.ret [ + i8 0, label %await3.ready + i8 1, label %cleanup + ] + +await3.ready: + %save4 = call token @llvm.coro.save(ptr null) + %sp4 = call i8 @llvm.coro.suspend(token %save4, i1 false) + switch i8 %sp4, label %coro.ret [ + i8 0, label %cleanup + i8 1, label %cleanup + ] + +cleanup: + call void @llvm.lifetime.end.p0(i64 500, ptr %large.alloca) + %mem1 = call ptr @llvm.coro.free(token %id, ptr %hdl) + call void @free(ptr %mem1) + br label %coro.ret + +coro.ret: + %InResumePart = call i1 @llvm.coro.end(ptr null, i1 false, token none) + ret void +} + +declare void @consume(i8) +declare ptr @malloc(i64) +declare void @free(ptr) diff --git a/llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-03.ll b/llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-03.ll new file mode 100644 index 0000000000000..4cbd97a305dab --- /dev/null +++ b/llvm/test/Transforms/Coroutines/coro-split-rise-lifetime-03.ll @@ -0,0 +1,62 @@ +; Test we do not rise lifetime.end for allocas that may escape +; RUN: opt < %s -passes='cgscc(lifetime-move,coro-split),early-cse' -S | FileCheck %s + +; CHECK-NOT: %escape.gep = alloca [500 x i8], align 16 +; CHECK: %escape.gep.reload.addr + +; CHECK-NOT: %escape.store = alloca [500 x i8], align 16 +; CHECK: %escape.store.reload.addr + +; CHECK-NOT: %escape.call = alloca [500 x i8], align 16 +; CHECK: %escape.call.reload.addr + +define void @fn() presplitcoroutine { +entry: + %id = call token @llvm.coro.id(i32 16, ptr null, ptr null, ptr null) + %size = call i64 @llvm.coro.size.i64() + %mem = call ptr @malloc(i64 %size) + %hdl = call ptr @llvm.coro.begin(token %id, ptr %mem) + + %escape.gep = alloca [500 x i8], align 16 + call void @llvm.lifetime.start.p0(i64 500, ptr %escape.gep) + %gep.ptr = getelementptr inbounds nuw i8, ptr %escape.gep, i64 8 + + %escape.store = alloca [500 x i8], align 16 + %store.ptr = alloca ptr, align 8 + call void @llvm.lifetime.start.p0(i64 500, ptr %escape.store) + call void @llvm.lifetime.start.p0(i64 8, ptr %store.ptr) + store ptr %escape.store, ptr %store.ptr, align 8 + + %escape.call = alloca [500 x i8], align 16 + call void @llvm.lifetime.start.p0(i64 500, ptr %escape.call) + call void @consume(ptr %escape.call) + + %save = call token @llvm.coro.save(ptr null) + %suspend = call i8 @llvm.coro.suspend(token %save, i1 false) + switch i8 %suspend, label %coro.ret [ + i8 0, label %await.ready + i8 1, label %cleanup + ] + +await.ready: + %1 = load ptr, ptr %gep.ptr, align 8 + %2 = load ptr, ptr %store.ptr, align 8 + br label %cleanup + +cleanup: + call void @llvm.lifetime.end.p0(i64 500, ptr %escape.gep) + call void @llvm.lifetime.end.p0(i64 500, ptr %escape.store) + call void @llvm.lifetime.end.p0(i64 500, ptr %escape.call) + call void @llvm.lifetime.end.p0(i64 8, ptr %store.ptr) + %mem1 = call ptr @llvm.coro.free(token %id, ptr %hdl) + call void @free(ptr %mem1) + br label %coro.ret + +coro.ret: + %InResumePart = call i1 @llvm.coro.end(ptr null, i1 false, token none) + ret void +} + +declare void @consume(ptr) +declare ptr @malloc(i64) +declare void @free(ptr) diff --git a/llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-01.ll b/llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-01.ll index 1d0cf94c1a979..b002d423ed474 100644 --- a/llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-01.ll +++ b/llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-01.ll @@ -1,6 +1,6 @@ ; Tests that coro-split will optimize the lifetime.start maker of each local variable, ; sink them to the places after the suspend block. -; RUN: opt < %s -passes='cgscc(coro-split),simplifycfg,early-cse,simplifycfg' -S | FileCheck %s +; RUN: opt < %s -passes='cgscc(lifetime-move,coro-split),simplifycfg,early-cse,simplifycfg' -S | FileCheck %s ; CHECK: %a.Frame = type { ptr, ptr, i1 } ; CHECK: %a_optnone.Frame = type { ptr, ptr, i32, i1 } diff --git a/llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-02.ll b/llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-02.ll index 38a2a33efe051..3e6a1ea599745 100644 --- a/llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-02.ll +++ b/llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-02.ll @@ -1,6 +1,6 @@ ; Tests that coro-split will optimize the lifetime.start maker of each local variable, ; sink them to the places after the suspend block. -; RUN: opt < %s -passes='cgscc(coro-split),simplifycfg,early-cse' -S | FileCheck %s +; RUN: opt < %s -passes='cgscc(lifetime-move,coro-split),simplifycfg,early-cse' -S | FileCheck %s %"struct.std::coroutine_handle" = type { ptr } %"struct.std::coroutine_handle.0" = type { %"struct.std::coroutine_handle" } diff --git a/llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-03.ll b/llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-03.ll index de377a6a38b94..4b07e3eb301e2 100644 --- a/llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-03.ll +++ b/llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-03.ll @@ -1,6 +1,6 @@ ; Corresponding to coro-split-sink-lifetime-01.ll. This file tests that whether the CoroFrame ; pass knows the operand of lifetime.start intrinsic may be GEP as well. -; RUN: opt < %s -passes='cgscc(coro-split),simplifycfg,early-cse,simplifycfg' -S | FileCheck %s +; RUN: opt < %s -passes='cgscc(lifetime-move,coro-split),simplifycfg,early-cse,simplifycfg' -S | FileCheck %s %"struct.std::coroutine_handle" = type { ptr } %"struct.std::coroutine_handle.0" = type { %"struct.std::coroutine_handle" } diff --git a/llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-04.ll b/llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-04.ll index 821045583092d..1fd234349ef88 100644 --- a/llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-04.ll +++ b/llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-04.ll @@ -1,6 +1,6 @@ ; Tests that coro-split will optimize the lifetime.start maker of each local variable, ; sink them to the places after the suspend block. -; RUN: opt < %s -passes='cgscc(coro-split),simplifycfg,early-cse,simplifycfg' -S | FileCheck %s +; RUN: opt < %s -passes='cgscc(lifetime-move,coro-split),simplifycfg,early-cse,simplifycfg' -S | FileCheck %s %"struct.std::coroutine_handle" = type { ptr } %"struct.std::coroutine_handle.0" = type { %"struct.std::coroutine_handle" } >From 800fe15cd866e69c89dc6fec2c83ace3f7215840 Mon Sep 17 00:00:00 2001 From: NewSigma <newsi...@163.com> Date: Thu, 12 Jun 2025 11:37:24 +0800 Subject: [PATCH 2/4] Make coro.await.suspend nocapture --- llvm/docs/Coroutines.rst | 6 +++--- llvm/include/llvm/IR/Intrinsics.td | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/llvm/docs/Coroutines.rst b/llvm/docs/Coroutines.rst index 7472c68a70df4..25960d9ad208c 100644 --- a/llvm/docs/Coroutines.rst +++ b/llvm/docs/Coroutines.rst @@ -1863,7 +1863,7 @@ executes a call to ``llvm.coro.suspend.retcon`` after resuming in any way. :: declare void @llvm.coro.await.suspend.void( - ptr <awaiter>, + ptr captures(none) <awaiter>, ptr <handle>, ptr <await_suspend_function>) @@ -1945,7 +1945,7 @@ Example: :: declare i1 @llvm.coro.await.suspend.bool( - ptr <awaiter>, + ptr captures(none) <awaiter>, ptr <handle>, ptr <await_suspend_function>) @@ -2035,7 +2035,7 @@ Example: :: declare void @llvm.coro.await.suspend.handle( - ptr <awaiter>, + ptr captures(none) <awaiter>, ptr <handle>, ptr <await_suspend_function>) diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td index d3899056bc240..54bf5de123855 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -1811,15 +1811,15 @@ def int_coro_promise : Intrinsic<[llvm_ptr_ty], def int_coro_await_suspend_void : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty, llvm_ptr_ty], - [Throws]>; + [Throws, NoCapture<ArgIndex<0>>]>; def int_coro_await_suspend_bool : Intrinsic<[llvm_i1_ty], [llvm_ptr_ty, llvm_ptr_ty, llvm_ptr_ty], - [Throws]>; + [Throws, NoCapture<ArgIndex<0>>]>; def int_coro_await_suspend_handle : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty, llvm_ptr_ty], - [Throws]>; + [Throws, NoCapture<ArgIndex<0>>]>; // Coroutine Lowering Intrinsics. Used internally by coroutine passes. >From 17f75d35b17201798f0f06bbcb1918ef86000c5d Mon Sep 17 00:00:00 2001 From: NewSigma <newsi...@163.com> Date: Sat, 14 Jun 2025 17:09:43 +0800 Subject: [PATCH 3/4] Update pipeline --- llvm/lib/Passes/PassBuilderPipelines.cpp | 9 +++++++++ llvm/test/Other/new-pm-defaults.ll | 3 +++ llvm/test/Other/new-pm-pgo-preinline.ll | 1 + llvm/test/Other/new-pm-thinlto-postlink-defaults.ll | 3 +++ llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll | 3 +++ .../Other/new-pm-thinlto-postlink-samplepgo-defaults.ll | 3 +++ llvm/test/Other/new-pm-thinlto-prelink-defaults.ll | 3 +++ llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll | 4 ++++ .../Other/new-pm-thinlto-prelink-samplepgo-defaults.ll | 3 +++ 9 files changed, 32 insertions(+) diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp index 227390f557fda..e3ef2e735ca9f 100644 --- a/llvm/lib/Passes/PassBuilderPipelines.cpp +++ b/llvm/lib/Passes/PassBuilderPipelines.cpp @@ -100,6 +100,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/LoopDeletion.h" #include "llvm/Transforms/Scalar/LoopDistribute.h" #include "llvm/Transforms/Scalar/LoopFlatten.h" @@ -444,6 +445,7 @@ PassBuilder::buildO1FunctionSimplificationPipeline(OptimizationLevel Level, // Hoisting of scalars and load expressions. FPM.addPass( SimplifyCFGPass(SimplifyCFGOptions().convertSwitchRangeToICmp(true))); + FPM.addPass(LifetimeMovePass()); FPM.addPass(InstCombinePass()); FPM.addPass(LibCallsShrinkWrapPass()); @@ -521,6 +523,7 @@ PassBuilder::buildO1FunctionSimplificationPipeline(OptimizationLevel Level, /*UseBlockFrequencyInfo=*/true)); FPM.addPass( SimplifyCFGPass(SimplifyCFGOptions().convertSwitchRangeToICmp(true))); + FPM.addPass(LifetimeMovePass()); FPM.addPass(InstCombinePass()); // The loop passes in LPM2 (LoopFullUnrollPass) do not preserve MemorySSA. // *All* loop passes must preserve it, in order to be able to use it. @@ -559,6 +562,7 @@ PassBuilder::buildO1FunctionSimplificationPipeline(OptimizationLevel Level, FPM.addPass(ADCEPass()); FPM.addPass( SimplifyCFGPass(SimplifyCFGOptions().convertSwitchRangeToICmp(true))); + FPM.addPass(LifetimeMovePass()); FPM.addPass(InstCombinePass()); invokePeepholeEPCallbacks(FPM, Level); @@ -613,6 +617,7 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level, FPM.addPass( SimplifyCFGPass(SimplifyCFGOptions().convertSwitchRangeToICmp(true))); + FPM.addPass(LifetimeMovePass()); FPM.addPass(InstCombinePass()); FPM.addPass(AggressiveInstCombinePass()); @@ -712,6 +717,7 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level, /*UseBlockFrequencyInfo=*/true)); FPM.addPass( SimplifyCFGPass(SimplifyCFGOptions().convertSwitchRangeToICmp(true))); + FPM.addPass(LifetimeMovePass()); FPM.addPass(InstCombinePass()); // The loop passes in LPM2 (LoopIdiomRecognizePass, IndVarSimplifyPass, // LoopDeletionPass and LoopFullUnrollPass) do not preserve MemorySSA. @@ -781,6 +787,7 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level, .convertSwitchRangeToICmp(true) .hoistCommonInsts(true) .sinkCommonInsts(true))); + FPM.addPass(LifetimeMovePass()); FPM.addPass(InstCombinePass()); invokePeepholeEPCallbacks(FPM, Level); @@ -817,6 +824,7 @@ void PassBuilder::addPreInlinerPasses(ModulePassManager &MPM, FPM.addPass(EarlyCSEPass()); // Catch trivial redundancies. FPM.addPass(SimplifyCFGPass(SimplifyCFGOptions().convertSwitchRangeToICmp( true))); // Merge & remove basic blocks. + FPM.addPass(LifetimeMovePass()); FPM.addPass(InstCombinePass()); // Combine silly sequences. invokePeepholeEPCallbacks(FPM, Level); @@ -1357,6 +1365,7 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level, /*UseBlockFrequencyInfo=*/true)); ExtraPasses.addPass( SimplifyCFGPass(SimplifyCFGOptions().convertSwitchRangeToICmp(true))); + ExtraPasses.addPass(LifetimeMovePass()); ExtraPasses.addPass(InstCombinePass()); FPM.addPass(std::move(ExtraPasses)); } diff --git a/llvm/test/Other/new-pm-defaults.ll b/llvm/test/Other/new-pm-defaults.ll index c554fdbf4c799..8f9e44447ee91 100644 --- a/llvm/test/Other/new-pm-defaults.ll +++ b/llvm/test/Other/new-pm-defaults.ll @@ -163,6 +163,7 @@ ; CHECK-O23SZ-NEXT: Invalidating analysis: LazyValueAnalysis ; CHECK-JUMP-TABLE-TO-SWITCH-NEXT: Running pass: JumpTableToSwitchPass ; CHECK-O-NEXT: Running pass: SimplifyCFGPass +; CHECK-O-NEXT: Running pass: LifetimeMovePass ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O23SZ-NEXT: Running pass: AggressiveInstCombinePass ; CHECK-O1-NEXT: Running pass: LibCallsShrinkWrapPass @@ -188,6 +189,7 @@ ; CHECK-O-NEXT: Running pass: SimpleLoopUnswitchPass ; CHECK-O-NEXT: Running analysis: OuterAnalysisManagerProxy ; CHECK-O-NEXT: Running pass: SimplifyCFGPass +; CHECK-O-NEXT: Running pass: LifetimeMovePass ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O-NEXT: Running pass: LoopSimplifyPass ; CHECK-O-NEXT: Running pass: LCSSAPass @@ -225,6 +227,7 @@ ; CHECK-O23SZ-NEXT: Running pass: CoroElidePass ; CHECK-EP-SCALAR-LATE-NEXT: Running pass: NoOpFunctionPass ; CHECK-O-NEXT: Running pass: SimplifyCFGPass +; CHECK-O-NEXT: Running pass: LifetimeMovePass ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-EP-PEEPHOLE-NEXT: Running pass: NoOpFunctionPass ; CHECK-O-NEXT: Running pass: PostOrderFunctionAttrsPass diff --git a/llvm/test/Other/new-pm-pgo-preinline.ll b/llvm/test/Other/new-pm-pgo-preinline.ll index f07a3728ba3d4..38259274328e0 100644 --- a/llvm/test/Other/new-pm-pgo-preinline.ll +++ b/llvm/test/Other/new-pm-pgo-preinline.ll @@ -12,6 +12,7 @@ ; CHECK-Osz-NEXT: Running pass: SROAPass on foo ; CHECK-Osz-NEXT: Running pass: EarlyCSEPass on foo ; CHECK-Osz-NEXT: Running pass: SimplifyCFGPass on foo +; CHECK-Osz-NEXT: Running pass: LifetimeMovePass on foo ; CHECK-Osz-NEXT: Running pass: InstCombinePass on foo ; CHECK-Osz-NEXT: Invalidating analysis: InlineAdvisorAnalysis ; CHECK-Osz-NEXT: Running pass: GlobalDCEPass diff --git a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll index ed13402e1c4b1..6b791492e38d0 100644 --- a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll +++ b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll @@ -92,6 +92,7 @@ ; CHECK-O23SZ-NEXT: Running pass: CorrelatedValuePropagationPass ; CHECK-O23SZ-NEXT: Invalidating analysis: LazyValueAnalysis ; CHECK-O-NEXT: Running pass: SimplifyCFGPass +; CHECK-O-NEXT: Running pass: LifetimeMovePass ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O23SZ-NEXT: Running pass: AggressiveInstCombinePass ; CHECK-O1-NEXT: Running pass: LibCallsShrinkWrapPass @@ -116,6 +117,7 @@ ; CHECK-O-NEXT: Running pass: SimpleLoopUnswitchPass ; CHECK-O-NEXT: Running analysis: OuterAnalysisManagerProxy ; CHECK-O-NEXT: Running pass: SimplifyCFGPass +; CHECK-O-NEXT: Running pass: LifetimeMovePass ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O-NEXT: Running pass: LoopSimplifyPass ; CHECK-O-NEXT: Running pass: LCSSAPass @@ -149,6 +151,7 @@ ; CHECK-O23SZ-NEXT: Running pass: LICMPass on loop ; CHECK-O23SZ-NEXT: Running pass: CoroElidePass ; CHECK-O-NEXT: Running pass: SimplifyCFGPass +; CHECK-O-NEXT: Running pass: LifetimeMovePass ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O-NEXT: Running pass: PostOrderFunctionAttrsPass ; CHECK-O-NEXT: Running pass: RequireAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis diff --git a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll index c82c34f7ff01e..b4cf6834c2b91 100644 --- a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll +++ b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll @@ -80,6 +80,7 @@ ; CHECK-O23SZ-NEXT: Running pass: CorrelatedValuePropagationPass ; CHECK-O23SZ-NEXT: Invalidating analysis: LazyValueAnalysis ; CHECK-O-NEXT: Running pass: SimplifyCFGPass +; CHECK-O-NEXT: Running pass: LifetimeMove ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O23SZ-NEXT: Running pass: AggressiveInstCombinePass ; CHECK-O1-NEXT: Running pass: LibCallsShrinkWrapPass @@ -102,6 +103,7 @@ ; CHECK-O-NEXT: Running pass: SimpleLoopUnswitchPass ; CHECK-O-NEXT: Running analysis: OuterAnalysisManagerProxy ; CHECK-O-NEXT: Running pass: SimplifyCFGPass +; CHECK-O-NEXT: Running pass: LifetimeMovePass ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O-NEXT: Running pass: LoopSimplifyPass ; CHECK-O-NEXT: Running pass: LCSSAPass @@ -133,6 +135,7 @@ ; CHECK-O23SZ-NEXT: Running pass: LICMPass ; CHECK-O23SZ-NEXT: Running pass: CoroElidePass ; CHECK-O-NEXT: Running pass: SimplifyCFGPass +; CHECK-O-NEXT: Running pass: LifetimeMovePass ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O-NEXT: Running pass: PostOrderFunctionAttrsPass ; CHECK-O-NEXT: Running pass: RequireAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis diff --git a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll index d375747547d61..31f0aa3d36364 100644 --- a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll +++ b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll @@ -89,6 +89,7 @@ ; CHECK-O23SZ-NEXT: Running pass: CorrelatedValuePropagationPass ; CHECK-O23SZ-NEXT: Invalidating analysis: LazyValueAnalysis ; CHECK-O-NEXT: Running pass: SimplifyCFGPass +; CHECK-O-NEXT: Running pass: LifetimeMovePass ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O23SZ-NEXT: Running pass: AggressiveInstCombinePass ; CHECK-O1-NEXT: Running pass: LibCallsShrinkWrapPass @@ -111,6 +112,7 @@ ; CHECK-O-NEXT: Running pass: SimpleLoopUnswitchPass ; CHECK-O-NEXT: Running analysis: OuterAnalysisManagerProxy ; CHECK-O-NEXT: Running pass: SimplifyCFGPass +; CHECK-O-NEXT: Running pass: LifetimeMovePass ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O-NEXT: Running pass: LoopSimplifyPass ; CHECK-O-NEXT: Running pass: LCSSAPass @@ -142,6 +144,7 @@ ; CHECK-O23SZ-NEXT: Running pass: LICMPass ; CHECK-O23SZ-NEXT: Running pass: CoroElidePass ; CHECK-O-NEXT: Running pass: SimplifyCFGPass +; CHECK-O-NEXT: Running pass: LifetimeMovePass ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O-NEXT: Running pass: PostOrderFunctionAttrsPass ; CHECK-O-NEXT: Running pass: RequireAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis diff --git a/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll b/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll index 5aacd26def2be..8953f951bf4eb 100644 --- a/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll +++ b/llvm/test/Other/new-pm-thinlto-prelink-defaults.ll @@ -124,6 +124,7 @@ ; CHECK-O23SZ-NEXT: Running pass: CorrelatedValuePropagationPass ; CHECK-O23SZ-NEXT: Invalidating analysis: LazyValueAnalysis ; CHECK-O-NEXT: Running pass: SimplifyCFGPass +; CHECK-O-NEXT: Running pass: LifetimeMovePass ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O23SZ-NEXT: Running pass: AggressiveInstCombinePass ; CHECK-O1-NEXT: Running pass: LibCallsShrinkWrapPass @@ -148,6 +149,7 @@ ; CHECK-O-NEXT: Running pass: SimpleLoopUnswitchPass ; CHECK-O-NEXT: Running analysis: OuterAnalysisManagerProxy ; CHECK-O-NEXT: Running pass: SimplifyCFGPass +; CHECK-O-NEXT: Running pass: LifetimeMovePass ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O-NEXT: Running pass: LoopSimplifyPass ; CHECK-O-NEXT: Running pass: LCSSAPass @@ -181,6 +183,7 @@ ; CHECK-O23SZ-NEXT: Running pass: LICMPass on loop ; CHECK-O23SZ-NEXT: Running pass: CoroElidePass ; CHECK-O-NEXT: Running pass: SimplifyCFGPass +; CHECK-O-NEXT: Running pass: LifetimeMovePass ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O-NEXT: Running pass: PostOrderFunctionAttrsPass ; CHECK-O-NEXT: Running pass: RequireAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis diff --git a/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll index f6a9406596803..753adfe5ab776 100644 --- a/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll +++ b/llvm/test/Other/new-pm-thinlto-prelink-pgo-defaults.ll @@ -69,6 +69,7 @@ ; CHECK-O-NEXT: Running pass: SROAPass on foo ; CHECK-O-NEXT: Running pass: EarlyCSEPass on foo ; CHECK-O-NEXT: Running pass: SimplifyCFGPass on foo +; CHECK-O-NEXT: Running pass: LifetimeMovePass on foo ; CHECK-O-NEXT: Running pass: InstCombinePass on foo ; CHECK-O-NEXT: Invalidating analysis: InlineAdvisorAnalysis ; CHECK-O-NEXT: Running pass: GlobalDCEPass @@ -122,6 +123,7 @@ ; CHECK-O23SZ-NEXT: Running pass: CorrelatedValuePropagationPass ; CHECK-O23SZ-NEXT: Invalidating analysis: LazyValueAnalysis ; CHECK-O-NEXT: Running pass: SimplifyCFGPass +; CHECK-O-NEXT: Running pass: LifetimeMovePass ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O-NEXT: Running analysis: LastRunTrackingAnalysis ; CHECK-O-NEXT: Running analysis: BlockFrequencyAnalysis on foo @@ -151,6 +153,7 @@ ; CHECK-O-NEXT: Running pass: SimpleLoopUnswitchPass ; CHECK-O-NEXT: Running analysis: OuterAnalysisManagerProxy ; CHECK-O-NEXT: Running pass: SimplifyCFGPass +; CHECK-O-NEXT: Running pass: LifetimeMovePass ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O-NEXT: Running pass: LoopSimplifyPass ; CHECK-O-NEXT: Running pass: LCSSAPass @@ -182,6 +185,7 @@ ; CHECK-O23SZ-NEXT: Running pass: LICMPass ; CHECK-O23SZ-NEXT: Running pass: CoroElidePass ; CHECK-O-NEXT: Running pass: SimplifyCFGPass +; CHECK-O-NEXT: Running pass: LifetimeMovePass ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O-NEXT: Running pass: PostOrderFunctionAttrsPass ; CHECK-O-NEXT: Running pass: RequireAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis diff --git a/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll index 48a9433d24999..ae24961e06edb 100644 --- a/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll +++ b/llvm/test/Other/new-pm-thinlto-prelink-samplepgo-defaults.ll @@ -94,6 +94,7 @@ ; CHECK-O23SZ-NEXT: Running pass: CorrelatedValuePropagationPass ; CHECK-O23SZ-NEXT: Invalidating analysis: LazyValueAnalysis ; CHECK-O-NEXT: Running pass: SimplifyCFGPass +; CHECK-O-NEXT: Running pass: LifetimeMovePass ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O23SZ-NEXT: Running pass: AggressiveInstCombinePass ; CHECK-O1-NEXT: Running pass: LibCallsShrinkWrapPass @@ -116,6 +117,7 @@ ; CHECK-O-NEXT: Running pass: SimpleLoopUnswitchPass ; CHECK-O-NEXT: Running analysis: OuterAnalysisManagerProxy ; CHECK-O-NEXT: Running pass: SimplifyCFGPass +; CHECK-O-NEXT: Running pass: LifetimeMovePass ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O-NEXT: Running pass: LoopSimplifyPass ; CHECK-O-NEXT: Running pass: LCSSAPass @@ -146,6 +148,7 @@ ; CHECK-O23SZ-NEXT: Running pass: LICMPass ; CHECK-O23SZ-NEXT: Running pass: CoroElidePass ; CHECK-O-NEXT: Running pass: SimplifyCFGPass +; CHECK-O-NEXT: Running pass: LifetimeMovePass ; CHECK-O-NEXT: Running pass: InstCombinePass ; CHECK-O-NEXT: Running pass: PostOrderFunctionAttrsPass ; CHECK-O-NEXT: Running pass: RequireAnalysisPass<{{.*}}ShouldNotRunFunctionPassesAnalysis >From 9e27fb19f2054458f106965020601a9764392c7f Mon Sep 17 00:00:00 2001 From: Weibo He <newsi...@163.com> Date: Mon, 16 Jun 2025 18:33:39 +0800 Subject: [PATCH 4/4] Add missing return Co-authored-by: Nikita Popov <git...@npopov.com> --- llvm/lib/Transforms/Scalar/LifetimeMove.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/Scalar/LifetimeMove.cpp b/llvm/lib/Transforms/Scalar/LifetimeMove.cpp index 08349c36d24fc..2517d4553ee23 100644 --- a/llvm/lib/Transforms/Scalar/LifetimeMove.cpp +++ b/llvm/lib/Transforms/Scalar/LifetimeMove.cpp @@ -213,7 +213,7 @@ PreservedAnalyses LifetimeMovePass::run(Function &F, FunctionAnalysisManager &AM) { // Works for coroutine for now if (!F.isPresplitCoroutine()) - PreservedAnalyses::all(); + return PreservedAnalyses::all(); const DominatorTree &DT = AM.getResult<DominatorTreeAnalysis>(F); LifetimeMover Mover(F, DT); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits