https://github.com/NewSigma created https://github.com/llvm/llvm-project/pull/144319
As suggested by @ChuanqiXu9 in #143333 , 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 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/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<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/3] 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/3] 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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits