================ @@ -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<LifetimeMover> { + using This = LifetimeMover; + using Base = PtrUseVisitor<LifetimeMover>; + + const DominatorTree &DT; + const LoopInfo &LI; + + SmallVector<AllocaInst *, 4> 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<Instruction *, 4> CriticalPoints; + + SmallVector<Instruction *, 2> LifetimeStarts; + SmallVector<Instruction *, 2> LifetimeEnds; + SmallVector<Instruction *, 8> OtherUsers; + SmallPtrSet<BasicBlock *, 2> LifetimeStartBBs; + SmallPtrSet<BasicBlock *, 2> 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<AllocaInst>(&I)) + Allocas.push_back(AI); + else if (isa<LifetimeIntrinsic>(I)) + continue; + else if (isa<AnyCoroSuspendInst>(I)) + CriticalPoints.push_back(&I); + else if (isa<CallInst>(I)) + CriticalPoints.push_back(&I); + else if (isa<InvokeInst>(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(); ---------------- tmiasko wrote:
Should both of those transformation be limited only to allocas that don't have their address captured? There are no executions where allocas are live at the same time and their storage overlaps. In contrast, if allocas aren't live at the time, their storage might overlap. Therefore shrinking a live range of an alloca that has its address captured (relatively to another alloca that also has its address captured) could introduce a new observable behavior. Alive2 demonstration https://alive2.llvm.org/ce/z/uB4MzV. 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