174309fa0SGor Nishanov //===- CoroFrame.cpp - Builds and manipulates coroutine frame -------------===//
274309fa0SGor Nishanov //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
674309fa0SGor Nishanov //
774309fa0SGor Nishanov //===----------------------------------------------------------------------===//
874309fa0SGor Nishanov // This file contains classes used to discover if for a particular value
974309fa0SGor Nishanov // there from sue to definition that crosses a suspend block.
1074309fa0SGor Nishanov //
1174309fa0SGor Nishanov // Using the information discovered we form a Coroutine Frame structure to
1274309fa0SGor Nishanov // contain those values. All uses of those values are replaced with appropriate
1374309fa0SGor Nishanov // GEP + load from the coroutine frame. At the point of the definition we spill
1474309fa0SGor Nishanov // the value into the coroutine frame.
1574309fa0SGor Nishanov //===----------------------------------------------------------------------===//
1674309fa0SGor Nishanov
1774309fa0SGor Nishanov #include "CoroInternal.h"
18241b041fSGor Nishanov #include "llvm/ADT/BitVector.h"
19bb16e839SChuanqi Xu #include "llvm/ADT/ScopeExit.h"
20465dca79SReid Kleckner #include "llvm/ADT/SmallString.h"
21efe00934SGor Nishanov #include "llvm/Analysis/PtrUseVisitor.h"
22b3a722e6SChuanqi Xu #include "llvm/Analysis/StackLifetime.h"
23432a3883SNico Weber #include "llvm/Config/llvm-config.h"
24241b041fSGor Nishanov #include "llvm/IR/CFG.h"
25aa85b437SBrian Gesiak #include "llvm/IR/DIBuilder.h"
26e188aae4Sserge-sans-paille #include "llvm/IR/DebugInfo.h"
27241b041fSGor Nishanov #include "llvm/IR/Dominators.h"
2874309fa0SGor Nishanov #include "llvm/IR/IRBuilder.h"
29241b041fSGor Nishanov #include "llvm/IR/InstIterator.h"
3019279ffcSMichael Gottesman #include "llvm/IR/IntrinsicInst.h"
31241b041fSGor Nishanov #include "llvm/Support/Debug.h"
32dce9b026SGor Nishanov #include "llvm/Support/MathExtras.h"
338423a6f3SJohn McCall #include "llvm/Support/OptimizedStructLayout.h"
34b3a722e6SChuanqi Xu #include "llvm/Support/circular_raw_ostream.h"
356e5b8f48SChuanqi Xu #include "llvm/Support/raw_ostream.h"
36241b041fSGor Nishanov #include "llvm/Transforms/Utils/BasicBlockUtils.h"
37aa85b437SBrian Gesiak #include "llvm/Transforms/Utils/Local.h"
382133feecSJohn McCall #include "llvm/Transforms/Utils/PromoteMemToReg.h"
39aa85b437SBrian Gesiak #include <algorithm>
4074309fa0SGor Nishanov
4174309fa0SGor Nishanov using namespace llvm;
4274309fa0SGor Nishanov
43241b041fSGor Nishanov // The "coro-suspend-crossing" flag is very noisy. There is another debug type,
44241b041fSGor Nishanov // "coro-frame", which results in leaner debug spew.
45241b041fSGor Nishanov #define DEBUG_TYPE "coro-suspend-crossing"
46241b041fSGor Nishanov
47241b041fSGor Nishanov enum { SmallVectorThreshold = 32 };
48241b041fSGor Nishanov
49241b041fSGor Nishanov // Provides two way mapping between the blocks and numbers.
50241b041fSGor Nishanov namespace {
51241b041fSGor Nishanov class BlockToIndexMapping {
52241b041fSGor Nishanov SmallVector<BasicBlock *, SmallVectorThreshold> V;
53241b041fSGor Nishanov
54241b041fSGor Nishanov public:
size() const55241b041fSGor Nishanov size_t size() const { return V.size(); }
56241b041fSGor Nishanov
BlockToIndexMapping(Function & F)57241b041fSGor Nishanov BlockToIndexMapping(Function &F) {
58241b041fSGor Nishanov for (BasicBlock &BB : F)
59241b041fSGor Nishanov V.push_back(&BB);
600cac726aSFangrui Song llvm::sort(V);
61241b041fSGor Nishanov }
62241b041fSGor Nishanov
blockToIndex(BasicBlock * BB) const63241b041fSGor Nishanov size_t blockToIndex(BasicBlock *BB) const {
64dc8de603SFangrui Song auto *I = llvm::lower_bound(V, BB);
65241b041fSGor Nishanov assert(I != V.end() && *I == BB && "BasicBlockNumberng: Unknown block");
66241b041fSGor Nishanov return I - V.begin();
67241b041fSGor Nishanov }
68241b041fSGor Nishanov
indexToBlock(unsigned Index) const69241b041fSGor Nishanov BasicBlock *indexToBlock(unsigned Index) const { return V[Index]; }
70241b041fSGor Nishanov };
71241b041fSGor Nishanov } // end anonymous namespace
72241b041fSGor Nishanov
73241b041fSGor Nishanov // The SuspendCrossingInfo maintains data that allows to answer a question
74241b041fSGor Nishanov // whether given two BasicBlocks A and B there is a path from A to B that
75241b041fSGor Nishanov // passes through a suspend point.
76241b041fSGor Nishanov //
77241b041fSGor Nishanov // For every basic block 'i' it maintains a BlockData that consists of:
787d18a70dSSimon Pilgrim // Consumes: a bit vector which contains a set of indices of blocks that can
79241b041fSGor Nishanov // reach block 'i'
807d18a70dSSimon Pilgrim // Kills: a bit vector which contains a set of indices of blocks that can
81241b041fSGor Nishanov // reach block 'i', but one of the path will cross a suspend point
82241b041fSGor Nishanov // Suspend: a boolean indicating whether block 'i' contains a suspend point.
83241b041fSGor Nishanov // End: a boolean indicating whether block 'i' contains a coro.end intrinsic.
84241b041fSGor Nishanov //
85241b041fSGor Nishanov namespace {
86241b041fSGor Nishanov struct SuspendCrossingInfo {
87241b041fSGor Nishanov BlockToIndexMapping Mapping;
88241b041fSGor Nishanov
89241b041fSGor Nishanov struct BlockData {
90241b041fSGor Nishanov BitVector Consumes;
91241b041fSGor Nishanov BitVector Kills;
92241b041fSGor Nishanov bool Suspend = false;
93241b041fSGor Nishanov bool End = false;
94241b041fSGor Nishanov };
95241b041fSGor Nishanov SmallVector<BlockData, SmallVectorThreshold> Block;
96241b041fSGor Nishanov
successors__anon8d9a21160311::SuspendCrossingInfo97241b041fSGor Nishanov iterator_range<succ_iterator> successors(BlockData const &BD) const {
98241b041fSGor Nishanov BasicBlock *BB = Mapping.indexToBlock(&BD - &Block[0]);
99241b041fSGor Nishanov return llvm::successors(BB);
100241b041fSGor Nishanov }
101241b041fSGor Nishanov
getBlockData__anon8d9a21160311::SuspendCrossingInfo102241b041fSGor Nishanov BlockData &getBlockData(BasicBlock *BB) {
103241b041fSGor Nishanov return Block[Mapping.blockToIndex(BB)];
104241b041fSGor Nishanov }
105241b041fSGor Nishanov
106241b041fSGor Nishanov void dump() const;
107241b041fSGor Nishanov void dump(StringRef Label, BitVector const &BV) const;
108241b041fSGor Nishanov
109241b041fSGor Nishanov SuspendCrossingInfo(Function &F, coro::Shape &Shape);
110241b041fSGor Nishanov
hasPathCrossingSuspendPoint__anon8d9a21160311::SuspendCrossingInfo111241b041fSGor Nishanov bool hasPathCrossingSuspendPoint(BasicBlock *DefBB, BasicBlock *UseBB) const {
112241b041fSGor Nishanov size_t const DefIndex = Mapping.blockToIndex(DefBB);
113241b041fSGor Nishanov size_t const UseIndex = Mapping.blockToIndex(UseBB);
114241b041fSGor Nishanov
115241b041fSGor Nishanov bool const Result = Block[UseIndex].Kills[DefIndex];
116d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << UseBB->getName() << " => " << DefBB->getName()
117241b041fSGor Nishanov << " answer is " << Result << "\n");
118241b041fSGor Nishanov return Result;
119241b041fSGor Nishanov }
120241b041fSGor Nishanov
isDefinitionAcrossSuspend__anon8d9a21160311::SuspendCrossingInfo121241b041fSGor Nishanov bool isDefinitionAcrossSuspend(BasicBlock *DefBB, User *U) const {
122241b041fSGor Nishanov auto *I = cast<Instruction>(U);
123241b041fSGor Nishanov
124241b041fSGor Nishanov // We rewrote PHINodes, so that only the ones with exactly one incoming
125241b041fSGor Nishanov // value need to be analyzed.
126241b041fSGor Nishanov if (auto *PN = dyn_cast<PHINode>(I))
127241b041fSGor Nishanov if (PN->getNumIncomingValues() > 1)
128241b041fSGor Nishanov return false;
129241b041fSGor Nishanov
130241b041fSGor Nishanov BasicBlock *UseBB = I->getParent();
13194010b2bSJohn McCall
132ea5989b4SArnold Schwaighofer // As a special case, treat uses by an llvm.coro.suspend.retcon or an
133ea5989b4SArnold Schwaighofer // llvm.coro.suspend.async as if they were uses in the suspend's single
134ea5989b4SArnold Schwaighofer // predecessor: the uses conceptually occur before the suspend.
135ea5989b4SArnold Schwaighofer if (isa<CoroSuspendRetconInst>(I) || isa<CoroSuspendAsyncInst>(I)) {
13694010b2bSJohn McCall UseBB = UseBB->getSinglePredecessor();
13794010b2bSJohn McCall assert(UseBB && "should have split coro.suspend into its own block");
13894010b2bSJohn McCall }
13994010b2bSJohn McCall
140241b041fSGor Nishanov return hasPathCrossingSuspendPoint(DefBB, UseBB);
141241b041fSGor Nishanov }
142241b041fSGor Nishanov
isDefinitionAcrossSuspend__anon8d9a21160311::SuspendCrossingInfo143241b041fSGor Nishanov bool isDefinitionAcrossSuspend(Argument &A, User *U) const {
144241b041fSGor Nishanov return isDefinitionAcrossSuspend(&A.getParent()->getEntryBlock(), U);
145241b041fSGor Nishanov }
146241b041fSGor Nishanov
isDefinitionAcrossSuspend__anon8d9a21160311::SuspendCrossingInfo147241b041fSGor Nishanov bool isDefinitionAcrossSuspend(Instruction &I, User *U) const {
14894010b2bSJohn McCall auto *DefBB = I.getParent();
14994010b2bSJohn McCall
15094010b2bSJohn McCall // As a special case, treat values produced by an llvm.coro.suspend.*
15194010b2bSJohn McCall // as if they were defined in the single successor: the uses
15294010b2bSJohn McCall // conceptually occur after the suspend.
15394010b2bSJohn McCall if (isa<AnyCoroSuspendInst>(I)) {
15494010b2bSJohn McCall DefBB = DefBB->getSingleSuccessor();
15594010b2bSJohn McCall assert(DefBB && "should have split coro.suspend into its own block");
15694010b2bSJohn McCall }
15794010b2bSJohn McCall
15894010b2bSJohn McCall return isDefinitionAcrossSuspend(DefBB, U);
159241b041fSGor Nishanov }
160c1359ef0SChuanqi Xu
isDefinitionAcrossSuspend__anon8d9a21160311::SuspendCrossingInfo161c1359ef0SChuanqi Xu bool isDefinitionAcrossSuspend(Value &V, User *U) const {
162c1359ef0SChuanqi Xu if (auto *Arg = dyn_cast<Argument>(&V))
163c1359ef0SChuanqi Xu return isDefinitionAcrossSuspend(*Arg, U);
164c1359ef0SChuanqi Xu if (auto *Inst = dyn_cast<Instruction>(&V))
165c1359ef0SChuanqi Xu return isDefinitionAcrossSuspend(*Inst, U);
166c1359ef0SChuanqi Xu
167c1359ef0SChuanqi Xu llvm_unreachable(
168c1359ef0SChuanqi Xu "Coroutine could only collect Argument and Instruction now.");
169c1359ef0SChuanqi Xu }
170241b041fSGor Nishanov };
171241b041fSGor Nishanov } // end anonymous namespace
172241b041fSGor Nishanov
173615eb470SAaron Ballman #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump(StringRef Label,BitVector const & BV) const174241b041fSGor Nishanov LLVM_DUMP_METHOD void SuspendCrossingInfo::dump(StringRef Label,
175241b041fSGor Nishanov BitVector const &BV) const {
176241b041fSGor Nishanov dbgs() << Label << ":";
177241b041fSGor Nishanov for (size_t I = 0, N = BV.size(); I < N; ++I)
178241b041fSGor Nishanov if (BV[I])
179241b041fSGor Nishanov dbgs() << " " << Mapping.indexToBlock(I)->getName();
180241b041fSGor Nishanov dbgs() << "\n";
181241b041fSGor Nishanov }
182241b041fSGor Nishanov
dump() const183241b041fSGor Nishanov LLVM_DUMP_METHOD void SuspendCrossingInfo::dump() const {
184241b041fSGor Nishanov for (size_t I = 0, N = Block.size(); I < N; ++I) {
185241b041fSGor Nishanov BasicBlock *const B = Mapping.indexToBlock(I);
186241b041fSGor Nishanov dbgs() << B->getName() << ":\n";
187241b041fSGor Nishanov dump(" Consumes", Block[I].Consumes);
188241b041fSGor Nishanov dump(" Kills", Block[I].Kills);
189241b041fSGor Nishanov }
190241b041fSGor Nishanov dbgs() << "\n";
191241b041fSGor Nishanov }
1928c209aa8SMatthias Braun #endif
193241b041fSGor Nishanov
SuspendCrossingInfo(Function & F,coro::Shape & Shape)194241b041fSGor Nishanov SuspendCrossingInfo::SuspendCrossingInfo(Function &F, coro::Shape &Shape)
195241b041fSGor Nishanov : Mapping(F) {
196241b041fSGor Nishanov const size_t N = Mapping.size();
197241b041fSGor Nishanov Block.resize(N);
198241b041fSGor Nishanov
199241b041fSGor Nishanov // Initialize every block so that it consumes itself
200241b041fSGor Nishanov for (size_t I = 0; I < N; ++I) {
201241b041fSGor Nishanov auto &B = Block[I];
202241b041fSGor Nishanov B.Consumes.resize(N);
203241b041fSGor Nishanov B.Kills.resize(N);
204241b041fSGor Nishanov B.Consumes.set(I);
205241b041fSGor Nishanov }
206241b041fSGor Nishanov
207241b041fSGor Nishanov // Mark all CoroEnd Blocks. We do not propagate Kills beyond coro.ends as
208241b041fSGor Nishanov // the code beyond coro.end is reachable during initial invocation of the
209241b041fSGor Nishanov // coroutine.
210241b041fSGor Nishanov for (auto *CE : Shape.CoroEnds)
211241b041fSGor Nishanov getBlockData(CE->getParent()).End = true;
212241b041fSGor Nishanov
213a263a60aSGor Nishanov // Mark all suspend blocks and indicate that they kill everything they
214a263a60aSGor Nishanov // consume. Note, that crossing coro.save also requires a spill, as any code
215241b041fSGor Nishanov // between coro.save and coro.suspend may resume the coroutine and all of the
216241b041fSGor Nishanov // state needs to be saved by that time.
217a263a60aSGor Nishanov auto markSuspendBlock = [&](IntrinsicInst *BarrierInst) {
218a263a60aSGor Nishanov BasicBlock *SuspendBlock = BarrierInst->getParent();
219a263a60aSGor Nishanov auto &B = getBlockData(SuspendBlock);
220241b041fSGor Nishanov B.Suspend = true;
221241b041fSGor Nishanov B.Kills |= B.Consumes;
222a263a60aSGor Nishanov };
22394010b2bSJohn McCall for (auto *CSI : Shape.CoroSuspends) {
224a263a60aSGor Nishanov markSuspendBlock(CSI);
22594010b2bSJohn McCall if (auto *Save = CSI->getCoroSave())
22694010b2bSJohn McCall markSuspendBlock(Save);
227241b041fSGor Nishanov }
228241b041fSGor Nishanov
229a263a60aSGor Nishanov // Iterate propagating consumes and kills until they stop changing.
230dce9b026SGor Nishanov int Iteration = 0;
231dce9b026SGor Nishanov (void)Iteration;
232241b041fSGor Nishanov
233241b041fSGor Nishanov bool Changed;
234241b041fSGor Nishanov do {
235d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "iteration " << ++Iteration);
236d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "==============\n");
237241b041fSGor Nishanov
238241b041fSGor Nishanov Changed = false;
239241b041fSGor Nishanov for (size_t I = 0; I < N; ++I) {
240241b041fSGor Nishanov auto &B = Block[I];
241241b041fSGor Nishanov for (BasicBlock *SI : successors(B)) {
242241b041fSGor Nishanov
243241b041fSGor Nishanov auto SuccNo = Mapping.blockToIndex(SI);
244241b041fSGor Nishanov
245241b041fSGor Nishanov // Saved Consumes and Kills bitsets so that it is easy to see
246241b041fSGor Nishanov // if anything changed after propagation.
247241b041fSGor Nishanov auto &S = Block[SuccNo];
248241b041fSGor Nishanov auto SavedConsumes = S.Consumes;
249241b041fSGor Nishanov auto SavedKills = S.Kills;
250241b041fSGor Nishanov
251241b041fSGor Nishanov // Propagate Kills and Consumes from block B into its successor S.
252241b041fSGor Nishanov S.Consumes |= B.Consumes;
253241b041fSGor Nishanov S.Kills |= B.Kills;
254241b041fSGor Nishanov
255241b041fSGor Nishanov // If block B is a suspend block, it should propagate kills into the
256241b041fSGor Nishanov // its successor for every block B consumes.
257241b041fSGor Nishanov if (B.Suspend) {
258241b041fSGor Nishanov S.Kills |= B.Consumes;
259241b041fSGor Nishanov }
260241b041fSGor Nishanov if (S.Suspend) {
261241b041fSGor Nishanov // If block S is a suspend block, it should kill all of the blocks it
262241b041fSGor Nishanov // consumes.
263241b041fSGor Nishanov S.Kills |= S.Consumes;
264241b041fSGor Nishanov } else if (S.End) {
265241b041fSGor Nishanov // If block S is an end block, it should not propagate kills as the
266241b041fSGor Nishanov // blocks following coro.end() are reached during initial invocation
267241b041fSGor Nishanov // of the coroutine while all the data are still available on the
268241b041fSGor Nishanov // stack or in the registers.
269241b041fSGor Nishanov S.Kills.reset();
270241b041fSGor Nishanov } else {
271241b041fSGor Nishanov // This is reached when S block it not Suspend nor coro.end and it
272241b041fSGor Nishanov // need to make sure that it is not in the kill set.
273241b041fSGor Nishanov S.Kills.reset(SuccNo);
274241b041fSGor Nishanov }
275241b041fSGor Nishanov
276241b041fSGor Nishanov // See if anything changed.
277241b041fSGor Nishanov Changed |= (S.Kills != SavedKills) || (S.Consumes != SavedConsumes);
278241b041fSGor Nishanov
279241b041fSGor Nishanov if (S.Kills != SavedKills) {
280d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "\nblock " << I << " follower " << SI->getName()
281241b041fSGor Nishanov << "\n");
282d34e60caSNicola Zaghen LLVM_DEBUG(dump("S.Kills", S.Kills));
283d34e60caSNicola Zaghen LLVM_DEBUG(dump("SavedKills", SavedKills));
284241b041fSGor Nishanov }
285241b041fSGor Nishanov if (S.Consumes != SavedConsumes) {
286d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "\nblock " << I << " follower " << SI << "\n");
287d34e60caSNicola Zaghen LLVM_DEBUG(dump("S.Consume", S.Consumes));
288d34e60caSNicola Zaghen LLVM_DEBUG(dump("SavedCons", SavedConsumes));
289241b041fSGor Nishanov }
290241b041fSGor Nishanov }
291241b041fSGor Nishanov }
292241b041fSGor Nishanov } while (Changed);
293d34e60caSNicola Zaghen LLVM_DEBUG(dump());
294241b041fSGor Nishanov }
295241b041fSGor Nishanov
296241b041fSGor Nishanov #undef DEBUG_TYPE // "coro-suspend-crossing"
297241b041fSGor Nishanov #define DEBUG_TYPE "coro-frame"
298241b041fSGor Nishanov
299992fc4eaSBenjamin Kramer namespace {
300667dfe39SXun Li class FrameTypeBuilder;
301667dfe39SXun Li // Mapping from the to-be-spilled value to all the users that need reload.
302667dfe39SXun Li using SpillInfo = SmallMapVector<Value *, SmallVector<Instruction *, 2>, 8>;
3039f5a2beaSXun Li struct AllocaInfo {
3049f5a2beaSXun Li AllocaInst *Alloca;
3059f5a2beaSXun Li DenseMap<Instruction *, llvm::Optional<APInt>> Aliases;
3069f5a2beaSXun Li bool MayWriteBeforeCoroBegin;
AllocaInfo__anon8d9a21160511::AllocaInfo3079f5a2beaSXun Li AllocaInfo(AllocaInst *Alloca,
3089f5a2beaSXun Li DenseMap<Instruction *, llvm::Optional<APInt>> Aliases,
3099f5a2beaSXun Li bool MayWriteBeforeCoroBegin)
3109f5a2beaSXun Li : Alloca(Alloca), Aliases(std::move(Aliases)),
3119f5a2beaSXun Li MayWriteBeforeCoroBegin(MayWriteBeforeCoroBegin) {}
3129f5a2beaSXun Li };
313667dfe39SXun Li struct FrameDataInfo {
314667dfe39SXun Li // All the values (that are not allocas) that needs to be spilled to the
315667dfe39SXun Li // frame.
316667dfe39SXun Li SpillInfo Spills;
317667dfe39SXun Li // Allocas contains all values defined as allocas that need to live in the
318667dfe39SXun Li // frame.
3199f5a2beaSXun Li SmallVector<AllocaInfo, 8> Allocas;
320241b041fSGor Nishanov
getAllDefs__anon8d9a21160511::FrameDataInfo321667dfe39SXun Li SmallVector<Value *, 8> getAllDefs() const {
322667dfe39SXun Li SmallVector<Value *, 8> Defs;
323667dfe39SXun Li for (const auto &P : Spills)
324667dfe39SXun Li Defs.push_back(P.first);
3259f5a2beaSXun Li for (const auto &A : Allocas)
3269f5a2beaSXun Li Defs.push_back(A.Alloca);
327667dfe39SXun Li return Defs;
328d4712715SGor Nishanov }
329667dfe39SXun Li
getFieldIndex__anon8d9a21160511::FrameDataInfo330667dfe39SXun Li uint32_t getFieldIndex(Value *V) const {
331667dfe39SXun Li auto Itr = FieldIndexMap.find(V);
332667dfe39SXun Li assert(Itr != FieldIndexMap.end() &&
333667dfe39SXun Li "Value does not have a frame field index");
334667dfe39SXun Li return Itr->second;
335d4712715SGor Nishanov }
336667dfe39SXun Li
setFieldIndex__anon8d9a21160511::FrameDataInfo337667dfe39SXun Li void setFieldIndex(Value *V, uint32_t Index) {
338667dfe39SXun Li assert((LayoutIndexUpdateStarted || FieldIndexMap.count(V) == 0) &&
339667dfe39SXun Li "Cannot set the index for the same field twice.");
340667dfe39SXun Li FieldIndexMap[V] = Index;
341667dfe39SXun Li }
342667dfe39SXun Li
getAlign__anon8d9a21160511::FrameDataInfo34377bba68dSGuillaume Chatelet Align getAlign(Value *V) const {
3446e5b8f48SChuanqi Xu auto Iter = FieldAlignMap.find(V);
3456e5b8f48SChuanqi Xu assert(Iter != FieldAlignMap.end());
3466e5b8f48SChuanqi Xu return Iter->second;
3476e5b8f48SChuanqi Xu }
3486e5b8f48SChuanqi Xu
setAlign__anon8d9a21160511::FrameDataInfo34977bba68dSGuillaume Chatelet void setAlign(Value *V, Align AL) {
3506e5b8f48SChuanqi Xu assert(FieldAlignMap.count(V) == 0);
35177bba68dSGuillaume Chatelet FieldAlignMap.insert({V, AL});
3526e5b8f48SChuanqi Xu }
3536e5b8f48SChuanqi Xu
getDynamicAlign__anon8d9a21160511::FrameDataInfo3545c902af5SArnold Schwaighofer uint64_t getDynamicAlign(Value *V) const {
3555c902af5SArnold Schwaighofer auto Iter = FieldDynamicAlignMap.find(V);
3565c902af5SArnold Schwaighofer assert(Iter != FieldDynamicAlignMap.end());
3575c902af5SArnold Schwaighofer return Iter->second;
3585c902af5SArnold Schwaighofer }
3595c902af5SArnold Schwaighofer
setDynamicAlign__anon8d9a21160511::FrameDataInfo3605c902af5SArnold Schwaighofer void setDynamicAlign(Value *V, uint64_t Align) {
3615c902af5SArnold Schwaighofer assert(FieldDynamicAlignMap.count(V) == 0);
3625c902af5SArnold Schwaighofer FieldDynamicAlignMap.insert({V, Align});
3635c902af5SArnold Schwaighofer }
3645c902af5SArnold Schwaighofer
getOffset__anon8d9a21160511::FrameDataInfo3656e5b8f48SChuanqi Xu uint64_t getOffset(Value *V) const {
3666e5b8f48SChuanqi Xu auto Iter = FieldOffsetMap.find(V);
3676e5b8f48SChuanqi Xu assert(Iter != FieldOffsetMap.end());
3686e5b8f48SChuanqi Xu return Iter->second;
3696e5b8f48SChuanqi Xu }
3706e5b8f48SChuanqi Xu
setOffset__anon8d9a21160511::FrameDataInfo3716e5b8f48SChuanqi Xu void setOffset(Value *V, uint64_t Offset) {
3726e5b8f48SChuanqi Xu assert(FieldOffsetMap.count(V) == 0);
3736e5b8f48SChuanqi Xu FieldOffsetMap.insert({V, Offset});
3746e5b8f48SChuanqi Xu }
3756e5b8f48SChuanqi Xu
376667dfe39SXun Li // Remap the index of every field in the frame, using the final layout index.
377667dfe39SXun Li void updateLayoutIndex(FrameTypeBuilder &B);
378667dfe39SXun Li
379667dfe39SXun Li private:
380667dfe39SXun Li // LayoutIndexUpdateStarted is used to avoid updating the index of any field
381667dfe39SXun Li // twice by mistake.
382667dfe39SXun Li bool LayoutIndexUpdateStarted = false;
383667dfe39SXun Li // Map from values to their slot indexes on the frame. They will be first set
384667dfe39SXun Li // with their original insertion field index. After the frame is built, their
385667dfe39SXun Li // indexes will be updated into the final layout index.
386667dfe39SXun Li DenseMap<Value *, uint32_t> FieldIndexMap;
3876e5b8f48SChuanqi Xu // Map from values to their alignment on the frame. They would be set after
3886e5b8f48SChuanqi Xu // the frame is built.
38977bba68dSGuillaume Chatelet DenseMap<Value *, Align> FieldAlignMap;
3905c902af5SArnold Schwaighofer DenseMap<Value *, uint64_t> FieldDynamicAlignMap;
3916e5b8f48SChuanqi Xu // Map from values to their offset on the frame. They would be set after
3926e5b8f48SChuanqi Xu // the frame is built.
3936e5b8f48SChuanqi Xu DenseMap<Value *, uint64_t> FieldOffsetMap;
394241b041fSGor Nishanov };
395992fc4eaSBenjamin Kramer } // namespace
396241b041fSGor Nishanov
397241b041fSGor Nishanov #ifndef NDEBUG
dumpSpills(StringRef Title,const SpillInfo & Spills)398667dfe39SXun Li static void dumpSpills(StringRef Title, const SpillInfo &Spills) {
399241b041fSGor Nishanov dbgs() << "------------- " << Title << "--------------\n";
400667dfe39SXun Li for (const auto &E : Spills) {
401667dfe39SXun Li E.first->dump();
402241b041fSGor Nishanov dbgs() << " user: ";
403667dfe39SXun Li for (auto *I : E.second)
404667dfe39SXun Li I->dump();
405241b041fSGor Nishanov }
406241b041fSGor Nishanov }
407667dfe39SXun Li
dumpAllocas(const SmallVectorImpl<AllocaInfo> & Allocas)4089f5a2beaSXun Li static void dumpAllocas(const SmallVectorImpl<AllocaInfo> &Allocas) {
409667dfe39SXun Li dbgs() << "------------- Allocas --------------\n";
4109f5a2beaSXun Li for (const auto &A : Allocas) {
4119f5a2beaSXun Li A.Alloca->dump();
4129f5a2beaSXun Li }
413667dfe39SXun Li }
414241b041fSGor Nishanov #endif
41574309fa0SGor Nishanov
4161fc0da48SBenjamin Kramer namespace {
417667dfe39SXun Li using FieldIDType = size_t;
418d4712715SGor Nishanov // We cannot rely solely on natural alignment of a type when building a
419d4712715SGor Nishanov // coroutine frame and if the alignment specified on the Alloca instruction
420d4712715SGor Nishanov // differs from the natural alignment of the alloca type we will need to insert
421d4712715SGor Nishanov // padding.
4229514c048SJohn McCall class FrameTypeBuilder {
423b3a722e6SChuanqi Xu private:
4249514c048SJohn McCall struct Field {
4259514c048SJohn McCall uint64_t Size;
4269514c048SJohn McCall uint64_t Offset;
4279514c048SJohn McCall Type *Ty;
428667dfe39SXun Li FieldIDType LayoutFieldIndex;
4299514c048SJohn McCall Align Alignment;
4309514c048SJohn McCall Align TyAlignment;
4315c902af5SArnold Schwaighofer uint64_t DynamicAlignBuffer;
4329514c048SJohn McCall };
4339514c048SJohn McCall
434d4712715SGor Nishanov const DataLayout &DL;
435d4712715SGor Nishanov LLVMContext &Context;
4369514c048SJohn McCall uint64_t StructSize = 0;
4379514c048SJohn McCall Align StructAlign;
4389514c048SJohn McCall bool IsFinished = false;
439d4712715SGor Nishanov
4402937f8d1SArnold Schwaighofer Optional<Align> MaxFrameAlignment;
4412937f8d1SArnold Schwaighofer
4429514c048SJohn McCall SmallVector<Field, 8> Fields;
4439514c048SJohn McCall DenseMap<Value*, unsigned> FieldIndexByKey;
4449514c048SJohn McCall
4459514c048SJohn McCall public:
FrameTypeBuilder(LLVMContext & Context,const DataLayout & DL,Optional<Align> MaxFrameAlignment)4465f2c53bdSSimon Pilgrim FrameTypeBuilder(LLVMContext &Context, const DataLayout &DL,
4472937f8d1SArnold Schwaighofer Optional<Align> MaxFrameAlignment)
4482937f8d1SArnold Schwaighofer : DL(DL), Context(Context), MaxFrameAlignment(MaxFrameAlignment) {}
449d4712715SGor Nishanov
4509514c048SJohn McCall /// Add a field to this structure for the storage of an `alloca`
4519514c048SJohn McCall /// instruction.
addFieldForAlloca(AllocaInst * AI,bool IsHeader=false)452667dfe39SXun Li LLVM_NODISCARD FieldIDType addFieldForAlloca(AllocaInst *AI,
4539514c048SJohn McCall bool IsHeader = false) {
4549514c048SJohn McCall Type *Ty = AI->getAllocatedType();
4559514c048SJohn McCall
4569514c048SJohn McCall // Make an array type if this is a static array allocation.
4579514c048SJohn McCall if (AI->isArrayAllocation()) {
4589514c048SJohn McCall if (auto *CI = dyn_cast<ConstantInt>(AI->getArraySize()))
4599514c048SJohn McCall Ty = ArrayType::get(Ty, CI->getValue().getZExtValue());
4609514c048SJohn McCall else
4619514c048SJohn McCall report_fatal_error("Coroutines cannot handle non static allocas yet");
462d4712715SGor Nishanov }
463d4712715SGor Nishanov
464667dfe39SXun Li return addField(Ty, AI->getAlign(), IsHeader);
465d4712715SGor Nishanov }
466d4712715SGor Nishanov
467b3a722e6SChuanqi Xu /// We want to put the allocas whose lifetime-ranges are not overlapped
468b3a722e6SChuanqi Xu /// into one slot of coroutine frame.
469b3a722e6SChuanqi Xu /// Consider the example at:https://bugs.llvm.org/show_bug.cgi?id=45566
470b3a722e6SChuanqi Xu ///
471b3a722e6SChuanqi Xu /// cppcoro::task<void> alternative_paths(bool cond) {
472b3a722e6SChuanqi Xu /// if (cond) {
473b3a722e6SChuanqi Xu /// big_structure a;
474b3a722e6SChuanqi Xu /// process(a);
475b3a722e6SChuanqi Xu /// co_await something();
476b3a722e6SChuanqi Xu /// } else {
477b3a722e6SChuanqi Xu /// big_structure b;
478b3a722e6SChuanqi Xu /// process2(b);
479b3a722e6SChuanqi Xu /// co_await something();
480b3a722e6SChuanqi Xu /// }
481b3a722e6SChuanqi Xu /// }
482b3a722e6SChuanqi Xu ///
483b3a722e6SChuanqi Xu /// We want to put variable a and variable b in the same slot to
484b3a722e6SChuanqi Xu /// reduce the size of coroutine frame.
485b3a722e6SChuanqi Xu ///
486b3a722e6SChuanqi Xu /// This function use StackLifetime algorithm to partition the AllocaInsts in
487b3a722e6SChuanqi Xu /// Spills to non-overlapped sets in order to put Alloca in the same
488b3a722e6SChuanqi Xu /// non-overlapped set into the same slot in the Coroutine Frame. Then add
489b3a722e6SChuanqi Xu /// field for the allocas in the same non-overlapped set by using the largest
490b3a722e6SChuanqi Xu /// type as the field type.
491b3a722e6SChuanqi Xu ///
492b3a722e6SChuanqi Xu /// Side Effects: Because We sort the allocas, the order of allocas in the
493b3a722e6SChuanqi Xu /// frame may be different with the order in the source code.
494667dfe39SXun Li void addFieldForAllocas(const Function &F, FrameDataInfo &FrameData,
495b3a722e6SChuanqi Xu coro::Shape &Shape);
496b3a722e6SChuanqi Xu
4979514c048SJohn McCall /// Add a field to this structure.
addField(Type * Ty,MaybeAlign MaybeFieldAlignment,bool IsHeader=false,bool IsSpillOfValue=false)49872968119SGuillaume Chatelet LLVM_NODISCARD FieldIDType addField(Type *Ty, MaybeAlign MaybeFieldAlignment,
4992937f8d1SArnold Schwaighofer bool IsHeader = false,
5002937f8d1SArnold Schwaighofer bool IsSpillOfValue = false) {
5019514c048SJohn McCall assert(!IsFinished && "adding fields to a finished builder");
5029514c048SJohn McCall assert(Ty && "must provide a type for a field");
503d4712715SGor Nishanov
5049514c048SJohn McCall // The field size is always the alloc size of the type.
5059514c048SJohn McCall uint64_t FieldSize = DL.getTypeAllocSize(Ty);
506d4712715SGor Nishanov
507def86413SXun Li // For an alloca with size=0, we don't need to add a field and they
508def86413SXun Li // can just point to any index in the frame. Use index 0.
509def86413SXun Li if (FieldSize == 0) {
510def86413SXun Li return 0;
511def86413SXun Li }
512def86413SXun Li
5139514c048SJohn McCall // The field alignment might not be the type alignment, but we need
5149514c048SJohn McCall // to remember the type alignment anyway to build the type.
5152937f8d1SArnold Schwaighofer // If we are spilling values we don't need to worry about ABI alignment
5162937f8d1SArnold Schwaighofer // concerns.
51772968119SGuillaume Chatelet Align ABIAlign = DL.getABITypeAlign(Ty);
51872968119SGuillaume Chatelet Align TyAlignment = ABIAlign;
51972968119SGuillaume Chatelet if (IsSpillOfValue && MaxFrameAlignment && *MaxFrameAlignment < ABIAlign)
52072968119SGuillaume Chatelet TyAlignment = *MaxFrameAlignment;
52172968119SGuillaume Chatelet Align FieldAlignment = MaybeFieldAlignment.value_or(TyAlignment);
5229514c048SJohn McCall
5235c902af5SArnold Schwaighofer // The field alignment could be bigger than the max frame case, in that case
5245c902af5SArnold Schwaighofer // we request additional storage to be able to dynamically align the
5255c902af5SArnold Schwaighofer // pointer.
5265c902af5SArnold Schwaighofer uint64_t DynamicAlignBuffer = 0;
52772968119SGuillaume Chatelet if (MaxFrameAlignment && (FieldAlignment > *MaxFrameAlignment)) {
5285c902af5SArnold Schwaighofer DynamicAlignBuffer =
52972968119SGuillaume Chatelet offsetToAlignment(MaxFrameAlignment->value(), FieldAlignment);
5305c902af5SArnold Schwaighofer FieldAlignment = *MaxFrameAlignment;
5315c902af5SArnold Schwaighofer FieldSize = FieldSize + DynamicAlignBuffer;
5325c902af5SArnold Schwaighofer }
5335c902af5SArnold Schwaighofer
5349514c048SJohn McCall // Lay out header fields immediately.
5359514c048SJohn McCall uint64_t Offset;
5369514c048SJohn McCall if (IsHeader) {
5379514c048SJohn McCall Offset = alignTo(StructSize, FieldAlignment);
5389514c048SJohn McCall StructSize = Offset + FieldSize;
5399514c048SJohn McCall
5409514c048SJohn McCall // Everything else has a flexible offset.
5419514c048SJohn McCall } else {
5428423a6f3SJohn McCall Offset = OptimizedStructLayoutField::FlexibleOffset;
543d4712715SGor Nishanov }
544d4712715SGor Nishanov
54572968119SGuillaume Chatelet Fields.push_back({FieldSize, Offset, Ty, 0, FieldAlignment, TyAlignment,
5465c902af5SArnold Schwaighofer DynamicAlignBuffer});
547667dfe39SXun Li return Fields.size() - 1;
5489514c048SJohn McCall }
549d4712715SGor Nishanov
5509514c048SJohn McCall /// Finish the layout and set the body on the given type.
5519514c048SJohn McCall void finish(StructType *Ty);
5529514c048SJohn McCall
getStructSize() const5539514c048SJohn McCall uint64_t getStructSize() const {
5549514c048SJohn McCall assert(IsFinished && "not yet finished!");
5559514c048SJohn McCall return StructSize;
5569514c048SJohn McCall }
5579514c048SJohn McCall
getStructAlign() const5589514c048SJohn McCall Align getStructAlign() const {
5599514c048SJohn McCall assert(IsFinished && "not yet finished!");
5609514c048SJohn McCall return StructAlign;
5619514c048SJohn McCall }
5629514c048SJohn McCall
getLayoutFieldIndex(FieldIDType Id) const563667dfe39SXun Li FieldIDType getLayoutFieldIndex(FieldIDType Id) const {
5649514c048SJohn McCall assert(IsFinished && "not yet finished!");
565667dfe39SXun Li return Fields[Id].LayoutFieldIndex;
566d4712715SGor Nishanov }
5676e5b8f48SChuanqi Xu
getLayoutField(FieldIDType Id) const5686e5b8f48SChuanqi Xu Field getLayoutField(FieldIDType Id) const {
5696e5b8f48SChuanqi Xu assert(IsFinished && "not yet finished!");
5706e5b8f48SChuanqi Xu return Fields[Id];
5716e5b8f48SChuanqi Xu }
572d4712715SGor Nishanov };
5731fc0da48SBenjamin Kramer } // namespace
574d4712715SGor Nishanov
updateLayoutIndex(FrameTypeBuilder & B)575667dfe39SXun Li void FrameDataInfo::updateLayoutIndex(FrameTypeBuilder &B) {
576667dfe39SXun Li auto Updater = [&](Value *I) {
5776e5b8f48SChuanqi Xu auto Field = B.getLayoutField(getFieldIndex(I));
5786e5b8f48SChuanqi Xu setFieldIndex(I, Field.LayoutFieldIndex);
57977bba68dSGuillaume Chatelet setAlign(I, Field.Alignment);
5805c902af5SArnold Schwaighofer uint64_t dynamicAlign =
5815c902af5SArnold Schwaighofer Field.DynamicAlignBuffer
5825c902af5SArnold Schwaighofer ? Field.DynamicAlignBuffer + Field.Alignment.value()
5835c902af5SArnold Schwaighofer : 0;
5845c902af5SArnold Schwaighofer setDynamicAlign(I, dynamicAlign);
5856e5b8f48SChuanqi Xu setOffset(I, Field.Offset);
586667dfe39SXun Li };
587667dfe39SXun Li LayoutIndexUpdateStarted = true;
588667dfe39SXun Li for (auto &S : Spills)
589667dfe39SXun Li Updater(S.first);
5909f5a2beaSXun Li for (const auto &A : Allocas)
5919f5a2beaSXun Li Updater(A.Alloca);
592667dfe39SXun Li LayoutIndexUpdateStarted = false;
593667dfe39SXun Li }
594667dfe39SXun Li
addFieldForAllocas(const Function & F,FrameDataInfo & FrameData,coro::Shape & Shape)595667dfe39SXun Li void FrameTypeBuilder::addFieldForAllocas(const Function &F,
596667dfe39SXun Li FrameDataInfo &FrameData,
597b3a722e6SChuanqi Xu coro::Shape &Shape) {
598b3a722e6SChuanqi Xu using AllocaSetType = SmallVector<AllocaInst *, 4>;
599b3a722e6SChuanqi Xu SmallVector<AllocaSetType, 4> NonOverlapedAllocas;
600b3a722e6SChuanqi Xu
601bb16e839SChuanqi Xu // We need to add field for allocas at the end of this function.
602bb16e839SChuanqi Xu auto AddFieldForAllocasAtExit = make_scope_exit([&]() {
603667dfe39SXun Li for (auto AllocaList : NonOverlapedAllocas) {
604667dfe39SXun Li auto *LargestAI = *AllocaList.begin();
605667dfe39SXun Li FieldIDType Id = addFieldForAlloca(LargestAI);
606667dfe39SXun Li for (auto *Alloca : AllocaList)
607667dfe39SXun Li FrameData.setFieldIndex(Alloca, Id);
608b3a722e6SChuanqi Xu }
609b3a722e6SChuanqi Xu });
610b3a722e6SChuanqi Xu
61124e53b01SChuanqi Xu if (!Shape.OptimizeFrame) {
6129f5a2beaSXun Li for (const auto &A : FrameData.Allocas) {
6139f5a2beaSXun Li AllocaInst *Alloca = A.Alloca;
614b3a722e6SChuanqi Xu NonOverlapedAllocas.emplace_back(AllocaSetType(1, Alloca));
615b3a722e6SChuanqi Xu }
616b3a722e6SChuanqi Xu return;
617b3a722e6SChuanqi Xu }
618b3a722e6SChuanqi Xu
619b3a722e6SChuanqi Xu // Because there are pathes from the lifetime.start to coro.end
620b3a722e6SChuanqi Xu // for each alloca, the liferanges for every alloca is overlaped
621b3a722e6SChuanqi Xu // in the blocks who contain coro.end and the successor blocks.
622b3a722e6SChuanqi Xu // So we choose to skip there blocks when we calculates the liferange
623b3a722e6SChuanqi Xu // for each alloca. It should be reasonable since there shouldn't be uses
624b3a722e6SChuanqi Xu // in these blocks and the coroutine frame shouldn't be used outside the
625b3a722e6SChuanqi Xu // coroutine body.
626b3a722e6SChuanqi Xu //
627b3a722e6SChuanqi Xu // Note that the user of coro.suspend may not be SwitchInst. However, this
628b3a722e6SChuanqi Xu // case seems too complex to handle. And it is harmless to skip these
629b3a722e6SChuanqi Xu // patterns since it just prevend putting the allocas to live in the same
630b3a722e6SChuanqi Xu // slot.
631b3a722e6SChuanqi Xu DenseMap<SwitchInst *, BasicBlock *> DefaultSuspendDest;
632b3a722e6SChuanqi Xu for (auto CoroSuspendInst : Shape.CoroSuspends) {
633b3a722e6SChuanqi Xu for (auto U : CoroSuspendInst->users()) {
634b3a722e6SChuanqi Xu if (auto *ConstSWI = dyn_cast<SwitchInst>(U)) {
635b3a722e6SChuanqi Xu auto *SWI = const_cast<SwitchInst *>(ConstSWI);
636b3a722e6SChuanqi Xu DefaultSuspendDest[SWI] = SWI->getDefaultDest();
637b3a722e6SChuanqi Xu SWI->setDefaultDest(SWI->getSuccessor(1));
638b3a722e6SChuanqi Xu }
639b3a722e6SChuanqi Xu }
640b3a722e6SChuanqi Xu }
641b3a722e6SChuanqi Xu
6429f5a2beaSXun Li auto ExtractAllocas = [&]() {
6439f5a2beaSXun Li AllocaSetType Allocas;
6449f5a2beaSXun Li Allocas.reserve(FrameData.Allocas.size());
6459f5a2beaSXun Li for (const auto &A : FrameData.Allocas)
6469f5a2beaSXun Li Allocas.push_back(A.Alloca);
6479f5a2beaSXun Li return Allocas;
6489f5a2beaSXun Li };
6499f5a2beaSXun Li StackLifetime StackLifetimeAnalyzer(F, ExtractAllocas(),
650b3a722e6SChuanqi Xu StackLifetime::LivenessType::May);
651b3a722e6SChuanqi Xu StackLifetimeAnalyzer.run();
652b3a722e6SChuanqi Xu auto IsAllocaInferenre = [&](const AllocaInst *AI1, const AllocaInst *AI2) {
653b3a722e6SChuanqi Xu return StackLifetimeAnalyzer.getLiveRange(AI1).overlaps(
654b3a722e6SChuanqi Xu StackLifetimeAnalyzer.getLiveRange(AI2));
655b3a722e6SChuanqi Xu };
6569f5a2beaSXun Li auto GetAllocaSize = [&](const AllocaInfo &A) {
6578e0148dfSFrancesco Petrogalli Optional<TypeSize> RetSize = A.Alloca->getAllocationSizeInBits(DL);
6588e0148dfSFrancesco Petrogalli assert(RetSize && "Variable Length Arrays (VLA) are not supported.\n");
6598e0148dfSFrancesco Petrogalli assert(!RetSize->isScalable() && "Scalable vectors are not yet supported");
6608e0148dfSFrancesco Petrogalli return RetSize->getFixedSize();
661b3a722e6SChuanqi Xu };
662b3a722e6SChuanqi Xu // Put larger allocas in the front. So the larger allocas have higher
663b3a722e6SChuanqi Xu // priority to merge, which can save more space potentially. Also each
664b3a722e6SChuanqi Xu // AllocaSet would be ordered. So we can get the largest Alloca in one
665b3a722e6SChuanqi Xu // AllocaSet easily.
6669f5a2beaSXun Li sort(FrameData.Allocas, [&](const auto &Iter1, const auto &Iter2) {
667b3a722e6SChuanqi Xu return GetAllocaSize(Iter1) > GetAllocaSize(Iter2);
668b3a722e6SChuanqi Xu });
6699f5a2beaSXun Li for (const auto &A : FrameData.Allocas) {
6709f5a2beaSXun Li AllocaInst *Alloca = A.Alloca;
671b3a722e6SChuanqi Xu bool Merged = false;
672b3a722e6SChuanqi Xu // Try to find if the Alloca is not inferenced with any existing
673b3a722e6SChuanqi Xu // NonOverlappedAllocaSet. If it is true, insert the alloca to that
674b3a722e6SChuanqi Xu // NonOverlappedAllocaSet.
675b3a722e6SChuanqi Xu for (auto &AllocaSet : NonOverlapedAllocas) {
676b3a722e6SChuanqi Xu assert(!AllocaSet.empty() && "Processing Alloca Set is not empty.\n");
677c1bc7981SChuanqi Xu bool NoInference = none_of(AllocaSet, [&](auto Iter) {
678b3a722e6SChuanqi Xu return IsAllocaInferenre(Alloca, Iter);
679b3a722e6SChuanqi Xu });
680c1bc7981SChuanqi Xu // If the alignment of A is multiple of the alignment of B, the address
681c1bc7981SChuanqi Xu // of A should satisfy the requirement for aligning for B.
682c1bc7981SChuanqi Xu //
683c1bc7981SChuanqi Xu // There may be other more fine-grained strategies to handle the alignment
684c1bc7981SChuanqi Xu // infomation during the merging process. But it seems hard to handle
685c1bc7981SChuanqi Xu // these strategies and benefit little.
686c1bc7981SChuanqi Xu bool Alignable = [&]() -> bool {
687c1bc7981SChuanqi Xu auto *LargestAlloca = *AllocaSet.begin();
688c1bc7981SChuanqi Xu return LargestAlloca->getAlign().value() % Alloca->getAlign().value() ==
689c1bc7981SChuanqi Xu 0;
690c1bc7981SChuanqi Xu }();
691c1bc7981SChuanqi Xu bool CouldMerge = NoInference && Alignable;
692b3a722e6SChuanqi Xu if (!CouldMerge)
693b3a722e6SChuanqi Xu continue;
694b3a722e6SChuanqi Xu AllocaSet.push_back(Alloca);
695b3a722e6SChuanqi Xu Merged = true;
696b3a722e6SChuanqi Xu break;
697b3a722e6SChuanqi Xu }
698b3a722e6SChuanqi Xu if (!Merged) {
699b3a722e6SChuanqi Xu NonOverlapedAllocas.emplace_back(AllocaSetType(1, Alloca));
700b3a722e6SChuanqi Xu }
701b3a722e6SChuanqi Xu }
702b3a722e6SChuanqi Xu // Recover the default target destination for each Switch statement
703b3a722e6SChuanqi Xu // reserved.
704b3a722e6SChuanqi Xu for (auto SwitchAndDefaultDest : DefaultSuspendDest) {
705b3a722e6SChuanqi Xu SwitchInst *SWI = SwitchAndDefaultDest.first;
706b3a722e6SChuanqi Xu BasicBlock *DestBB = SwitchAndDefaultDest.second;
707b3a722e6SChuanqi Xu SWI->setDefaultDest(DestBB);
708b3a722e6SChuanqi Xu }
709b3a722e6SChuanqi Xu // This Debug Info could tell us which allocas are merged into one slot.
710b3a722e6SChuanqi Xu LLVM_DEBUG(for (auto &AllocaSet
711b3a722e6SChuanqi Xu : NonOverlapedAllocas) {
712b3a722e6SChuanqi Xu if (AllocaSet.size() > 1) {
713b3a722e6SChuanqi Xu dbgs() << "In Function:" << F.getName() << "\n";
714b3a722e6SChuanqi Xu dbgs() << "Find Union Set "
715b3a722e6SChuanqi Xu << "\n";
716b3a722e6SChuanqi Xu dbgs() << "\tAllocas are \n";
717b3a722e6SChuanqi Xu for (auto Alloca : AllocaSet)
718b3a722e6SChuanqi Xu dbgs() << "\t\t" << *Alloca << "\n";
719b3a722e6SChuanqi Xu }
720b3a722e6SChuanqi Xu });
721b3a722e6SChuanqi Xu }
722b3a722e6SChuanqi Xu
finish(StructType * Ty)7239514c048SJohn McCall void FrameTypeBuilder::finish(StructType *Ty) {
7249514c048SJohn McCall assert(!IsFinished && "already finished!");
7259514c048SJohn McCall
7269514c048SJohn McCall // Prepare the optimal-layout field array.
7279514c048SJohn McCall // The Id in the layout field is a pointer to our Field for it.
7288423a6f3SJohn McCall SmallVector<OptimizedStructLayoutField, 8> LayoutFields;
7299514c048SJohn McCall LayoutFields.reserve(Fields.size());
7309514c048SJohn McCall for (auto &Field : Fields) {
7319514c048SJohn McCall LayoutFields.emplace_back(&Field, Field.Size, Field.Alignment,
7329514c048SJohn McCall Field.Offset);
7339514c048SJohn McCall }
7349514c048SJohn McCall
7359514c048SJohn McCall // Perform layout.
7368423a6f3SJohn McCall auto SizeAndAlign = performOptimizedStructLayout(LayoutFields);
7379514c048SJohn McCall StructSize = SizeAndAlign.first;
7389514c048SJohn McCall StructAlign = SizeAndAlign.second;
7399514c048SJohn McCall
7408423a6f3SJohn McCall auto getField = [](const OptimizedStructLayoutField &LayoutField) -> Field & {
7419514c048SJohn McCall return *static_cast<Field *>(const_cast<void*>(LayoutField.Id));
7429514c048SJohn McCall };
7439514c048SJohn McCall
7449514c048SJohn McCall // We need to produce a packed struct type if there's a field whose
7459514c048SJohn McCall // assigned offset isn't a multiple of its natural type alignment.
7469514c048SJohn McCall bool Packed = [&] {
7479514c048SJohn McCall for (auto &LayoutField : LayoutFields) {
7489514c048SJohn McCall auto &F = getField(LayoutField);
7499514c048SJohn McCall if (!isAligned(F.TyAlignment, LayoutField.Offset))
7509514c048SJohn McCall return true;
7519514c048SJohn McCall }
7529514c048SJohn McCall return false;
7539514c048SJohn McCall }();
7549514c048SJohn McCall
7559514c048SJohn McCall // Build the struct body.
7569514c048SJohn McCall SmallVector<Type*, 16> FieldTypes;
7579514c048SJohn McCall FieldTypes.reserve(LayoutFields.size() * 3 / 2);
7589514c048SJohn McCall uint64_t LastOffset = 0;
7599514c048SJohn McCall for (auto &LayoutField : LayoutFields) {
7609514c048SJohn McCall auto &F = getField(LayoutField);
7619514c048SJohn McCall
7629514c048SJohn McCall auto Offset = LayoutField.Offset;
7639514c048SJohn McCall
7649514c048SJohn McCall // Add a padding field if there's a padding gap and we're either
7659514c048SJohn McCall // building a packed struct or the padding gap is more than we'd
7669514c048SJohn McCall // get from aligning to the field type's natural alignment.
7679514c048SJohn McCall assert(Offset >= LastOffset);
7689514c048SJohn McCall if (Offset != LastOffset) {
7699514c048SJohn McCall if (Packed || alignTo(LastOffset, F.TyAlignment) != Offset)
7709514c048SJohn McCall FieldTypes.push_back(ArrayType::get(Type::getInt8Ty(Context),
7719514c048SJohn McCall Offset - LastOffset));
7729514c048SJohn McCall }
7739514c048SJohn McCall
7749514c048SJohn McCall F.Offset = Offset;
775667dfe39SXun Li F.LayoutFieldIndex = FieldTypes.size();
7769514c048SJohn McCall
7779514c048SJohn McCall FieldTypes.push_back(F.Ty);
7785c902af5SArnold Schwaighofer if (F.DynamicAlignBuffer) {
7795c902af5SArnold Schwaighofer FieldTypes.push_back(
7805c902af5SArnold Schwaighofer ArrayType::get(Type::getInt8Ty(Context), F.DynamicAlignBuffer));
7815c902af5SArnold Schwaighofer }
7829514c048SJohn McCall LastOffset = Offset + F.Size;
7839514c048SJohn McCall }
7849514c048SJohn McCall
7859514c048SJohn McCall Ty->setBody(FieldTypes, Packed);
7869514c048SJohn McCall
7879514c048SJohn McCall #ifndef NDEBUG
7889514c048SJohn McCall // Check that the IR layout matches the offsets we expect.
7899514c048SJohn McCall auto Layout = DL.getStructLayout(Ty);
7909514c048SJohn McCall for (auto &F : Fields) {
791667dfe39SXun Li assert(Ty->getElementType(F.LayoutFieldIndex) == F.Ty);
792667dfe39SXun Li assert(Layout->getElementOffset(F.LayoutFieldIndex) == F.Offset);
7939514c048SJohn McCall }
7949514c048SJohn McCall #endif
7959514c048SJohn McCall
7969514c048SJohn McCall IsFinished = true;
7979514c048SJohn McCall }
7989514c048SJohn McCall
cacheDIVar(FrameDataInfo & FrameData,DenseMap<Value *,DILocalVariable * > & DIVarCache)7996e5b8f48SChuanqi Xu static void cacheDIVar(FrameDataInfo &FrameData,
8006e5b8f48SChuanqi Xu DenseMap<Value *, DILocalVariable *> &DIVarCache) {
8016e5b8f48SChuanqi Xu for (auto *V : FrameData.getAllDefs()) {
8026e5b8f48SChuanqi Xu if (DIVarCache.find(V) != DIVarCache.end())
8036e5b8f48SChuanqi Xu continue;
8046e5b8f48SChuanqi Xu
8056e5b8f48SChuanqi Xu auto DDIs = FindDbgDeclareUses(V);
8066e5b8f48SChuanqi Xu auto *I = llvm::find_if(DDIs, [](DbgDeclareInst *DDI) {
8076e5b8f48SChuanqi Xu return DDI->getExpression()->getNumElements() == 0;
8086e5b8f48SChuanqi Xu });
8096e5b8f48SChuanqi Xu if (I != DDIs.end())
8106e5b8f48SChuanqi Xu DIVarCache.insert({V, (*I)->getVariable()});
8116e5b8f48SChuanqi Xu }
8126e5b8f48SChuanqi Xu }
8136e5b8f48SChuanqi Xu
8146e5b8f48SChuanqi Xu /// Create name for Type. It uses MDString to store new created string to
8156e5b8f48SChuanqi Xu /// avoid memory leak.
solveTypeName(Type * Ty)8166e5b8f48SChuanqi Xu static StringRef solveTypeName(Type *Ty) {
8176e5b8f48SChuanqi Xu if (Ty->isIntegerTy()) {
8186e5b8f48SChuanqi Xu // The longest name in common may be '__int_128', which has 9 bits.
8196e5b8f48SChuanqi Xu SmallString<16> Buffer;
8206e5b8f48SChuanqi Xu raw_svector_ostream OS(Buffer);
8216e5b8f48SChuanqi Xu OS << "__int_" << cast<IntegerType>(Ty)->getBitWidth();
8226e5b8f48SChuanqi Xu auto *MDName = MDString::get(Ty->getContext(), OS.str());
8236e5b8f48SChuanqi Xu return MDName->getString();
8246e5b8f48SChuanqi Xu }
8256e5b8f48SChuanqi Xu
8266e5b8f48SChuanqi Xu if (Ty->isFloatingPointTy()) {
8276e5b8f48SChuanqi Xu if (Ty->isFloatTy())
8286e5b8f48SChuanqi Xu return "__float_";
8296e5b8f48SChuanqi Xu if (Ty->isDoubleTy())
8306e5b8f48SChuanqi Xu return "__double_";
8316e5b8f48SChuanqi Xu return "__floating_type_";
8326e5b8f48SChuanqi Xu }
8336e5b8f48SChuanqi Xu
834479d684bSNikita Popov if (auto *PtrTy = dyn_cast<PointerType>(Ty)) {
835479d684bSNikita Popov if (PtrTy->isOpaque())
836479d684bSNikita Popov return "PointerType";
837479d684bSNikita Popov Type *PointeeTy = PtrTy->getNonOpaquePointerElementType();
8386e5b8f48SChuanqi Xu auto Name = solveTypeName(PointeeTy);
8396e5b8f48SChuanqi Xu if (Name == "UnknownType")
8406e5b8f48SChuanqi Xu return "PointerType";
8416e5b8f48SChuanqi Xu SmallString<16> Buffer;
8426e5b8f48SChuanqi Xu Twine(Name + "_Ptr").toStringRef(Buffer);
8436e5b8f48SChuanqi Xu auto *MDName = MDString::get(Ty->getContext(), Buffer.str());
8446e5b8f48SChuanqi Xu return MDName->getString();
8456e5b8f48SChuanqi Xu }
8466e5b8f48SChuanqi Xu
8476e5b8f48SChuanqi Xu if (Ty->isStructTy()) {
8486e5b8f48SChuanqi Xu if (!cast<StructType>(Ty)->hasName())
8496e5b8f48SChuanqi Xu return "__LiteralStructType_";
8506e5b8f48SChuanqi Xu
8516e5b8f48SChuanqi Xu auto Name = Ty->getStructName();
8526e5b8f48SChuanqi Xu
8536e5b8f48SChuanqi Xu SmallString<16> Buffer(Name);
8543b9707dbSKazu Hirata for (auto &Iter : Buffer)
8556e5b8f48SChuanqi Xu if (Iter == '.' || Iter == ':')
8566e5b8f48SChuanqi Xu Iter = '_';
8576e5b8f48SChuanqi Xu auto *MDName = MDString::get(Ty->getContext(), Buffer.str());
8586e5b8f48SChuanqi Xu return MDName->getString();
8596e5b8f48SChuanqi Xu }
8606e5b8f48SChuanqi Xu
8616e5b8f48SChuanqi Xu return "UnknownType";
8626e5b8f48SChuanqi Xu }
8636e5b8f48SChuanqi Xu
solveDIType(DIBuilder & Builder,Type * Ty,const DataLayout & Layout,DIScope * Scope,unsigned LineNum,DenseMap<Type *,DIType * > & DITypeCache)8645f2c53bdSSimon Pilgrim static DIType *solveDIType(DIBuilder &Builder, Type *Ty,
8655f2c53bdSSimon Pilgrim const DataLayout &Layout, DIScope *Scope,
8665f2c53bdSSimon Pilgrim unsigned LineNum,
8676e5b8f48SChuanqi Xu DenseMap<Type *, DIType *> &DITypeCache) {
8686e5b8f48SChuanqi Xu if (DIType *DT = DITypeCache.lookup(Ty))
8696e5b8f48SChuanqi Xu return DT;
8706e5b8f48SChuanqi Xu
8716e5b8f48SChuanqi Xu StringRef Name = solveTypeName(Ty);
8726e5b8f48SChuanqi Xu
8736e5b8f48SChuanqi Xu DIType *RetType = nullptr;
8746e5b8f48SChuanqi Xu
8756e5b8f48SChuanqi Xu if (Ty->isIntegerTy()) {
8766e5b8f48SChuanqi Xu auto BitWidth = cast<IntegerType>(Ty)->getBitWidth();
8776e5b8f48SChuanqi Xu RetType = Builder.createBasicType(Name, BitWidth, dwarf::DW_ATE_signed,
8786e5b8f48SChuanqi Xu llvm::DINode::FlagArtificial);
8796e5b8f48SChuanqi Xu } else if (Ty->isFloatingPointTy()) {
8806e5b8f48SChuanqi Xu RetType = Builder.createBasicType(Name, Layout.getTypeSizeInBits(Ty),
8816e5b8f48SChuanqi Xu dwarf::DW_ATE_float,
8826e5b8f48SChuanqi Xu llvm::DINode::FlagArtificial);
8836e5b8f48SChuanqi Xu } else if (Ty->isPointerTy()) {
884*e3b4452eSChuanqi Xu // Construct PointerType points to null (aka void *) instead of exploring
885*e3b4452eSChuanqi Xu // pointee type to avoid infinite search problem. For example, we would be
886*e3b4452eSChuanqi Xu // in trouble if we traverse recursively:
8876e5b8f48SChuanqi Xu //
8886e5b8f48SChuanqi Xu // struct Node {
8896e5b8f48SChuanqi Xu // Node* ptr;
8906e5b8f48SChuanqi Xu // };
891*e3b4452eSChuanqi Xu RetType = Builder.createPointerType(nullptr, Layout.getTypeSizeInBits(Ty),
892*e3b4452eSChuanqi Xu Layout.getABITypeAlignment(Ty),
893*e3b4452eSChuanqi Xu /*DWARFAddressSpace=*/None, Name);
8946e5b8f48SChuanqi Xu } else if (Ty->isStructTy()) {
8956e5b8f48SChuanqi Xu auto *DIStruct = Builder.createStructType(
8966e5b8f48SChuanqi Xu Scope, Name, Scope->getFile(), LineNum, Layout.getTypeSizeInBits(Ty),
8976e5b8f48SChuanqi Xu Layout.getPrefTypeAlignment(Ty), llvm::DINode::FlagArtificial, nullptr,
8986e5b8f48SChuanqi Xu llvm::DINodeArray());
8996e5b8f48SChuanqi Xu
9006e5b8f48SChuanqi Xu auto *StructTy = cast<StructType>(Ty);
9016e5b8f48SChuanqi Xu SmallVector<Metadata *, 16> Elements;
9026e5b8f48SChuanqi Xu for (unsigned I = 0; I < StructTy->getNumElements(); I++) {
9036e5b8f48SChuanqi Xu DIType *DITy = solveDIType(Builder, StructTy->getElementType(I), Layout,
9046e5b8f48SChuanqi Xu Scope, LineNum, DITypeCache);
9056e5b8f48SChuanqi Xu assert(DITy);
9066e5b8f48SChuanqi Xu Elements.push_back(Builder.createMemberType(
9076e5b8f48SChuanqi Xu Scope, DITy->getName(), Scope->getFile(), LineNum,
9086e5b8f48SChuanqi Xu DITy->getSizeInBits(), DITy->getAlignInBits(),
9096e5b8f48SChuanqi Xu Layout.getStructLayout(StructTy)->getElementOffsetInBits(I),
9106e5b8f48SChuanqi Xu llvm::DINode::FlagArtificial, DITy));
9116e5b8f48SChuanqi Xu }
9126e5b8f48SChuanqi Xu
9136e5b8f48SChuanqi Xu Builder.replaceArrays(DIStruct, Builder.getOrCreateArray(Elements));
9146e5b8f48SChuanqi Xu
9156e5b8f48SChuanqi Xu RetType = DIStruct;
9166e5b8f48SChuanqi Xu } else {
917*e3b4452eSChuanqi Xu LLVM_DEBUG(dbgs() << "Unresolved Type: " << *Ty << "\n");
918*e3b4452eSChuanqi Xu TypeSize Size = Layout.getTypeSizeInBits(Ty);
919*e3b4452eSChuanqi Xu auto *CharSizeType = Builder.createBasicType(
920*e3b4452eSChuanqi Xu Name, 8, dwarf::DW_ATE_unsigned_char, llvm::DINode::FlagArtificial);
921*e3b4452eSChuanqi Xu
922*e3b4452eSChuanqi Xu if (Size <= 8)
923*e3b4452eSChuanqi Xu RetType = CharSizeType;
924*e3b4452eSChuanqi Xu else {
925*e3b4452eSChuanqi Xu if (Size % 8 != 0)
926*e3b4452eSChuanqi Xu Size = TypeSize::Fixed(Size + 8 - (Size % 8));
927*e3b4452eSChuanqi Xu
928*e3b4452eSChuanqi Xu RetType = Builder.createArrayType(
929*e3b4452eSChuanqi Xu Size, Layout.getPrefTypeAlign(Ty).value(), CharSizeType,
930*e3b4452eSChuanqi Xu Builder.getOrCreateArray(Builder.getOrCreateSubrange(0, Size / 8)));
931*e3b4452eSChuanqi Xu }
9326e5b8f48SChuanqi Xu }
9336e5b8f48SChuanqi Xu
9346e5b8f48SChuanqi Xu DITypeCache.insert({Ty, RetType});
9356e5b8f48SChuanqi Xu return RetType;
9366e5b8f48SChuanqi Xu }
9376e5b8f48SChuanqi Xu
9386e5b8f48SChuanqi Xu /// Build artificial debug info for C++ coroutine frames to allow users to
9396e5b8f48SChuanqi Xu /// inspect the contents of the frame directly
9406e5b8f48SChuanqi Xu ///
9416e5b8f48SChuanqi Xu /// Create Debug information for coroutine frame with debug name "__coro_frame".
9426e5b8f48SChuanqi Xu /// The debug information for the fields of coroutine frame is constructed from
9436e5b8f48SChuanqi Xu /// the following way:
9446e5b8f48SChuanqi Xu /// 1. For all the value in the Frame, we search the use of dbg.declare to find
9456e5b8f48SChuanqi Xu /// the corresponding debug variables for the value. If we can find the
9466e5b8f48SChuanqi Xu /// debug variable, we can get full and accurate debug information.
9476e5b8f48SChuanqi Xu /// 2. If we can't get debug information in step 1 and 2, we could only try to
9486e5b8f48SChuanqi Xu /// build the DIType by Type. We did this in solveDIType. We only handle
9496e5b8f48SChuanqi Xu /// integer, float, double, integer type and struct type for now.
buildFrameDebugInfo(Function & F,coro::Shape & Shape,FrameDataInfo & FrameData)9506e5b8f48SChuanqi Xu static void buildFrameDebugInfo(Function &F, coro::Shape &Shape,
9516e5b8f48SChuanqi Xu FrameDataInfo &FrameData) {
9526e5b8f48SChuanqi Xu DISubprogram *DIS = F.getSubprogram();
9536e5b8f48SChuanqi Xu // If there is no DISubprogram for F, it implies the Function are not compiled
9546e5b8f48SChuanqi Xu // with debug info. So we also don't need to generate debug info for the frame
9556e5b8f48SChuanqi Xu // neither.
9566e5b8f48SChuanqi Xu if (!DIS || !DIS->getUnit() ||
9576e5b8f48SChuanqi Xu !dwarf::isCPlusPlus(
9586e5b8f48SChuanqi Xu (dwarf::SourceLanguage)DIS->getUnit()->getSourceLanguage()))
9596e5b8f48SChuanqi Xu return;
9606e5b8f48SChuanqi Xu
9616e5b8f48SChuanqi Xu assert(Shape.ABI == coro::ABI::Switch &&
9626e5b8f48SChuanqi Xu "We could only build debug infomation for C++ coroutine now.\n");
9636e5b8f48SChuanqi Xu
9646e5b8f48SChuanqi Xu DIBuilder DBuilder(*F.getParent(), /*AllowUnresolved*/ false);
9656e5b8f48SChuanqi Xu
9666e5b8f48SChuanqi Xu AllocaInst *PromiseAlloca = Shape.getPromiseAlloca();
9676e5b8f48SChuanqi Xu assert(PromiseAlloca &&
9686e5b8f48SChuanqi Xu "Coroutine with switch ABI should own Promise alloca");
9696e5b8f48SChuanqi Xu
9706e5b8f48SChuanqi Xu TinyPtrVector<DbgDeclareInst *> DIs = FindDbgDeclareUses(PromiseAlloca);
9716e5b8f48SChuanqi Xu if (DIs.empty())
9726e5b8f48SChuanqi Xu return;
9736e5b8f48SChuanqi Xu
9746e5b8f48SChuanqi Xu DbgDeclareInst *PromiseDDI = DIs.front();
9756e5b8f48SChuanqi Xu DILocalVariable *PromiseDIVariable = PromiseDDI->getVariable();
9766e5b8f48SChuanqi Xu DILocalScope *PromiseDIScope = PromiseDIVariable->getScope();
9776e5b8f48SChuanqi Xu DIFile *DFile = PromiseDIScope->getFile();
9786e5b8f48SChuanqi Xu DILocation *DILoc = PromiseDDI->getDebugLoc().get();
9796e5b8f48SChuanqi Xu unsigned LineNum = PromiseDIVariable->getLine();
9806e5b8f48SChuanqi Xu
9816e5b8f48SChuanqi Xu DICompositeType *FrameDITy = DBuilder.createStructType(
9827137ebc4SChuanqi Xu DIS->getUnit(), Twine(F.getName() + ".coro_frame_ty").str(),
9837137ebc4SChuanqi Xu DFile, LineNum, Shape.FrameSize * 8,
9846e5b8f48SChuanqi Xu Shape.FrameAlign.value() * 8, llvm::DINode::FlagArtificial, nullptr,
9856e5b8f48SChuanqi Xu llvm::DINodeArray());
9866e5b8f48SChuanqi Xu StructType *FrameTy = Shape.FrameTy;
9876e5b8f48SChuanqi Xu SmallVector<Metadata *, 16> Elements;
9886e5b8f48SChuanqi Xu DataLayout Layout = F.getParent()->getDataLayout();
9896e5b8f48SChuanqi Xu
9906e5b8f48SChuanqi Xu DenseMap<Value *, DILocalVariable *> DIVarCache;
9916e5b8f48SChuanqi Xu cacheDIVar(FrameData, DIVarCache);
9926e5b8f48SChuanqi Xu
9936e5b8f48SChuanqi Xu unsigned ResumeIndex = coro::Shape::SwitchFieldIndex::Resume;
9946e5b8f48SChuanqi Xu unsigned DestroyIndex = coro::Shape::SwitchFieldIndex::Destroy;
9956e5b8f48SChuanqi Xu unsigned IndexIndex = Shape.SwitchLowering.IndexField;
9966e5b8f48SChuanqi Xu
9976e5b8f48SChuanqi Xu DenseMap<unsigned, StringRef> NameCache;
9986e5b8f48SChuanqi Xu NameCache.insert({ResumeIndex, "__resume_fn"});
9996e5b8f48SChuanqi Xu NameCache.insert({DestroyIndex, "__destroy_fn"});
10006e5b8f48SChuanqi Xu NameCache.insert({IndexIndex, "__coro_index"});
10016e5b8f48SChuanqi Xu
10026e5b8f48SChuanqi Xu Type *ResumeFnTy = FrameTy->getElementType(ResumeIndex),
10036e5b8f48SChuanqi Xu *DestroyFnTy = FrameTy->getElementType(DestroyIndex),
10046e5b8f48SChuanqi Xu *IndexTy = FrameTy->getElementType(IndexIndex);
10056e5b8f48SChuanqi Xu
10066e5b8f48SChuanqi Xu DenseMap<unsigned, DIType *> TyCache;
10076e5b8f48SChuanqi Xu TyCache.insert(
1008*e3b4452eSChuanqi Xu {ResumeIndex, DBuilder.createPointerType(
1009*e3b4452eSChuanqi Xu nullptr, Layout.getTypeSizeInBits(ResumeFnTy))});
1010*e3b4452eSChuanqi Xu TyCache.insert(
1011*e3b4452eSChuanqi Xu {DestroyIndex, DBuilder.createPointerType(
1012*e3b4452eSChuanqi Xu nullptr, Layout.getTypeSizeInBits(DestroyFnTy))});
10136e5b8f48SChuanqi Xu
10146e5b8f48SChuanqi Xu /// FIXME: If we fill the field `SizeInBits` with the actual size of
10156e5b8f48SChuanqi Xu /// __coro_index in bits, then __coro_index wouldn't show in the debugger.
10166e5b8f48SChuanqi Xu TyCache.insert({IndexIndex, DBuilder.createBasicType(
10176e5b8f48SChuanqi Xu "__coro_index",
10186e5b8f48SChuanqi Xu (Layout.getTypeSizeInBits(IndexTy) < 8)
10196e5b8f48SChuanqi Xu ? 8
10206e5b8f48SChuanqi Xu : Layout.getTypeSizeInBits(IndexTy),
10216e5b8f48SChuanqi Xu dwarf::DW_ATE_unsigned_char)});
10226e5b8f48SChuanqi Xu
10236e5b8f48SChuanqi Xu for (auto *V : FrameData.getAllDefs()) {
10246e5b8f48SChuanqi Xu if (DIVarCache.find(V) == DIVarCache.end())
10256e5b8f48SChuanqi Xu continue;
10266e5b8f48SChuanqi Xu
10276e5b8f48SChuanqi Xu auto Index = FrameData.getFieldIndex(V);
10286e5b8f48SChuanqi Xu
10296e5b8f48SChuanqi Xu NameCache.insert({Index, DIVarCache[V]->getName()});
10306e5b8f48SChuanqi Xu TyCache.insert({Index, DIVarCache[V]->getType()});
10316e5b8f48SChuanqi Xu }
10326e5b8f48SChuanqi Xu
10336e5b8f48SChuanqi Xu // Cache from index to (Align, Offset Pair)
10346e5b8f48SChuanqi Xu DenseMap<unsigned, std::pair<unsigned, unsigned>> OffsetCache;
10356e5b8f48SChuanqi Xu // The Align and Offset of Resume function and Destroy function are fixed.
10366e5b8f48SChuanqi Xu OffsetCache.insert({ResumeIndex, {8, 0}});
10376e5b8f48SChuanqi Xu OffsetCache.insert({DestroyIndex, {8, 8}});
10386e5b8f48SChuanqi Xu OffsetCache.insert(
10396e5b8f48SChuanqi Xu {IndexIndex,
10406e5b8f48SChuanqi Xu {Shape.SwitchLowering.IndexAlign, Shape.SwitchLowering.IndexOffset}});
10416e5b8f48SChuanqi Xu
10426e5b8f48SChuanqi Xu for (auto *V : FrameData.getAllDefs()) {
10436e5b8f48SChuanqi Xu auto Index = FrameData.getFieldIndex(V);
10446e5b8f48SChuanqi Xu
10456e5b8f48SChuanqi Xu OffsetCache.insert(
104677bba68dSGuillaume Chatelet {Index, {FrameData.getAlign(V).value(), FrameData.getOffset(V)}});
10476e5b8f48SChuanqi Xu }
10486e5b8f48SChuanqi Xu
10496e5b8f48SChuanqi Xu DenseMap<Type *, DIType *> DITypeCache;
10506e5b8f48SChuanqi Xu // This counter is used to avoid same type names. e.g., there would be
10516e5b8f48SChuanqi Xu // many i32 and i64 types in one coroutine. And we would use i32_0 and
10526e5b8f48SChuanqi Xu // i32_1 to avoid the same type. Since it makes no sense the name of the
10536e5b8f48SChuanqi Xu // fields confilicts with each other.
10546e5b8f48SChuanqi Xu unsigned UnknownTypeNum = 0;
10556e5b8f48SChuanqi Xu for (unsigned Index = 0; Index < FrameTy->getNumElements(); Index++) {
10566e5b8f48SChuanqi Xu if (OffsetCache.find(Index) == OffsetCache.end())
10576e5b8f48SChuanqi Xu continue;
10586e5b8f48SChuanqi Xu
10596e5b8f48SChuanqi Xu std::string Name;
10606e5b8f48SChuanqi Xu uint64_t SizeInBits;
10616e5b8f48SChuanqi Xu uint32_t AlignInBits;
10626e5b8f48SChuanqi Xu uint64_t OffsetInBits;
10636e5b8f48SChuanqi Xu DIType *DITy = nullptr;
10646e5b8f48SChuanqi Xu
10656e5b8f48SChuanqi Xu Type *Ty = FrameTy->getElementType(Index);
10666e5b8f48SChuanqi Xu assert(Ty->isSized() && "We can't handle type which is not sized.\n");
10676e5b8f48SChuanqi Xu SizeInBits = Layout.getTypeSizeInBits(Ty).getFixedSize();
10686e5b8f48SChuanqi Xu AlignInBits = OffsetCache[Index].first * 8;
10696e5b8f48SChuanqi Xu OffsetInBits = OffsetCache[Index].second * 8;
10706e5b8f48SChuanqi Xu
10716e5b8f48SChuanqi Xu if (NameCache.find(Index) != NameCache.end()) {
10726e5b8f48SChuanqi Xu Name = NameCache[Index].str();
10736e5b8f48SChuanqi Xu DITy = TyCache[Index];
10746e5b8f48SChuanqi Xu } else {
10753638085fSHongtao Yu DITy = solveDIType(DBuilder, Ty, Layout, FrameDITy, LineNum, DITypeCache);
10766e5b8f48SChuanqi Xu assert(DITy && "SolveDIType shouldn't return nullptr.\n");
10776e5b8f48SChuanqi Xu Name = DITy->getName().str();
10786e5b8f48SChuanqi Xu Name += "_" + std::to_string(UnknownTypeNum);
10796e5b8f48SChuanqi Xu UnknownTypeNum++;
10806e5b8f48SChuanqi Xu }
10816e5b8f48SChuanqi Xu
10826e5b8f48SChuanqi Xu Elements.push_back(DBuilder.createMemberType(
10833638085fSHongtao Yu FrameDITy, Name, DFile, LineNum, SizeInBits, AlignInBits, OffsetInBits,
10843638085fSHongtao Yu llvm::DINode::FlagArtificial, DITy));
10856e5b8f48SChuanqi Xu }
10866e5b8f48SChuanqi Xu
10876e5b8f48SChuanqi Xu DBuilder.replaceArrays(FrameDITy, DBuilder.getOrCreateArray(Elements));
10886e5b8f48SChuanqi Xu
10896e5b8f48SChuanqi Xu auto *FrameDIVar = DBuilder.createAutoVariable(PromiseDIScope, "__coro_frame",
10906e5b8f48SChuanqi Xu DFile, LineNum, FrameDITy,
10916e5b8f48SChuanqi Xu true, DINode::FlagArtificial);
10926e5b8f48SChuanqi Xu assert(FrameDIVar->isValidLocationForIntrinsic(PromiseDDI->getDebugLoc()));
10936e5b8f48SChuanqi Xu
10946e5b8f48SChuanqi Xu // Subprogram would have ContainedNodes field which records the debug
10956e5b8f48SChuanqi Xu // variables it contained. So we need to add __coro_frame to the
10966e5b8f48SChuanqi Xu // ContainedNodes of it.
10976e5b8f48SChuanqi Xu //
10986e5b8f48SChuanqi Xu // If we don't add __coro_frame to the RetainedNodes, user may get
10996e5b8f48SChuanqi Xu // `no symbol __coro_frame in context` rather than `__coro_frame`
11006e5b8f48SChuanqi Xu // is optimized out, which is more precise.
11016e5b8f48SChuanqi Xu if (auto *SubProgram = dyn_cast<DISubprogram>(PromiseDIScope)) {
11026e5b8f48SChuanqi Xu auto RetainedNodes = SubProgram->getRetainedNodes();
11036e5b8f48SChuanqi Xu SmallVector<Metadata *, 32> RetainedNodesVec(RetainedNodes.begin(),
11046e5b8f48SChuanqi Xu RetainedNodes.end());
11056e5b8f48SChuanqi Xu RetainedNodesVec.push_back(FrameDIVar);
11066e5b8f48SChuanqi Xu SubProgram->replaceOperandWith(
11076e5b8f48SChuanqi Xu 7, (MDTuple::get(F.getContext(), RetainedNodesVec)));
11086e5b8f48SChuanqi Xu }
11096e5b8f48SChuanqi Xu
11106e5b8f48SChuanqi Xu DBuilder.insertDeclare(Shape.FramePtr, FrameDIVar,
11116e5b8f48SChuanqi Xu DBuilder.createExpression(), DILoc,
11129bca4ea3SNikita Popov Shape.getInsertPtAfterFramePtr());
11136e5b8f48SChuanqi Xu }
11146e5b8f48SChuanqi Xu
111574309fa0SGor Nishanov // Build a struct that will keep state for an active coroutine.
111674309fa0SGor Nishanov // struct f.frame {
111774309fa0SGor Nishanov // ResumeFnTy ResumeFnAddr;
111874309fa0SGor Nishanov // ResumeFnTy DestroyFnAddr;
111974309fa0SGor Nishanov // int ResumeIndex;
112074309fa0SGor Nishanov // ... promise (if present) ...
112174309fa0SGor Nishanov // ... spills ...
112274309fa0SGor Nishanov // };
buildFrameType(Function & F,coro::Shape & Shape,FrameDataInfo & FrameData)112374309fa0SGor Nishanov static StructType *buildFrameType(Function &F, coro::Shape &Shape,
1124667dfe39SXun Li FrameDataInfo &FrameData) {
112574309fa0SGor Nishanov LLVMContext &C = F.getContext();
1126d4712715SGor Nishanov const DataLayout &DL = F.getParent()->getDataLayout();
11279514c048SJohn McCall StructType *FrameTy = [&] {
112874309fa0SGor Nishanov SmallString<32> Name(F.getName());
112974309fa0SGor Nishanov Name.append(".Frame");
11309514c048SJohn McCall return StructType::create(C, Name);
11319514c048SJohn McCall }();
11329514c048SJohn McCall
11332937f8d1SArnold Schwaighofer // We will use this value to cap the alignment of spilled values.
11342937f8d1SArnold Schwaighofer Optional<Align> MaxFrameAlignment;
11352937f8d1SArnold Schwaighofer if (Shape.ABI == coro::ABI::Async)
11362937f8d1SArnold Schwaighofer MaxFrameAlignment = Shape.AsyncLowering.getContextAlignment();
11372937f8d1SArnold Schwaighofer FrameTypeBuilder B(C, DL, MaxFrameAlignment);
113894010b2bSJohn McCall
113994010b2bSJohn McCall AllocaInst *PromiseAlloca = Shape.getPromiseAlloca();
1140667dfe39SXun Li Optional<FieldIDType> SwitchIndexFieldId;
114194010b2bSJohn McCall
114294010b2bSJohn McCall if (Shape.ABI == coro::ABI::Switch) {
114374309fa0SGor Nishanov auto *FramePtrTy = FrameTy->getPointerTo();
114474309fa0SGor Nishanov auto *FnTy = FunctionType::get(Type::getVoidTy(C), FramePtrTy,
114594010b2bSJohn McCall /*IsVarArg=*/false);
114674309fa0SGor Nishanov auto *FnPtrTy = FnTy->getPointerTo();
114774309fa0SGor Nishanov
11489514c048SJohn McCall // Add header fields for the resume and destroy functions.
11499514c048SJohn McCall // We can rely on these being perfectly packed.
1150667dfe39SXun Li (void)B.addField(FnPtrTy, None, /*header*/ true);
1151667dfe39SXun Li (void)B.addField(FnPtrTy, None, /*header*/ true);
11529514c048SJohn McCall
1153667dfe39SXun Li // PromiseAlloca field needs to be explicitly added here because it's
1154667dfe39SXun Li // a header field with a fixed offset based on its alignment. Hence it
1155667dfe39SXun Li // needs special handling and cannot be added to FrameData.Allocas.
1156667dfe39SXun Li if (PromiseAlloca)
1157667dfe39SXun Li FrameData.setFieldIndex(
1158667dfe39SXun Li PromiseAlloca, B.addFieldForAlloca(PromiseAlloca, /*header*/ true));
11599514c048SJohn McCall
11609514c048SJohn McCall // Add a field to store the suspend index. This doesn't need to
11619514c048SJohn McCall // be in the header.
1162dce9b026SGor Nishanov unsigned IndexBits = std::max(1U, Log2_64_Ceil(Shape.CoroSuspends.size()));
116394010b2bSJohn McCall Type *IndexType = Type::getIntNTy(C, IndexBits);
11649514c048SJohn McCall
11659514c048SJohn McCall SwitchIndexFieldId = B.addField(IndexType, None);
116694010b2bSJohn McCall } else {
116794010b2bSJohn McCall assert(PromiseAlloca == nullptr && "lowering doesn't support promises");
116894010b2bSJohn McCall }
116994010b2bSJohn McCall
1170b3a722e6SChuanqi Xu // Because multiple allocas may own the same field slot,
1171b3a722e6SChuanqi Xu // we add allocas to field here.
1172667dfe39SXun Li B.addFieldForAllocas(F, FrameData, Shape);
11735c7dcd7aSYuanfang Chen // Add PromiseAlloca to Allocas list so that
11745c7dcd7aSYuanfang Chen // 1. updateLayoutIndex could update its index after
11755c7dcd7aSYuanfang Chen // `performOptimizedStructLayout`
11765c7dcd7aSYuanfang Chen // 2. it is processed in insertSpills.
11775c7dcd7aSYuanfang Chen if (Shape.ABI == coro::ABI::Switch && PromiseAlloca)
11785c7dcd7aSYuanfang Chen // We assume that the promise alloca won't be modified before
11795c7dcd7aSYuanfang Chen // CoroBegin and no alias will be create before CoroBegin.
11805c7dcd7aSYuanfang Chen FrameData.Allocas.emplace_back(
11815c7dcd7aSYuanfang Chen PromiseAlloca, DenseMap<Instruction *, llvm::Optional<APInt>>{}, false);
1182667dfe39SXun Li // Create an entry for every spilled value.
1183667dfe39SXun Li for (auto &S : FrameData.Spills) {
11843522167eSXun Li Type *FieldType = S.first->getType();
11853522167eSXun Li // For byval arguments, we need to store the pointed value in the frame,
11863522167eSXun Li // instead of the pointer itself.
11873522167eSXun Li if (const Argument *A = dyn_cast<Argument>(S.first))
11883522167eSXun Li if (A->hasByValAttr())
1189ab5693aaSArthur Eubanks FieldType = A->getParamByValType();
11902937f8d1SArnold Schwaighofer FieldIDType Id =
11912937f8d1SArnold Schwaighofer B.addField(FieldType, None, false /*header*/, true /*IsSpillOfValue*/);
1192667dfe39SXun Li FrameData.setFieldIndex(S.first, Id);
1193241b041fSGor Nishanov }
11949514c048SJohn McCall
11959514c048SJohn McCall B.finish(FrameTy);
1196667dfe39SXun Li FrameData.updateLayoutIndex(B);
11979514c048SJohn McCall Shape.FrameAlign = B.getStructAlign();
11989514c048SJohn McCall Shape.FrameSize = B.getStructSize();
119974309fa0SGor Nishanov
120094010b2bSJohn McCall switch (Shape.ABI) {
12016e5b8f48SChuanqi Xu case coro::ABI::Switch: {
1202667dfe39SXun Li // In the switch ABI, remember the switch-index field.
12036e5b8f48SChuanqi Xu auto IndexField = B.getLayoutField(*SwitchIndexFieldId);
12046e5b8f48SChuanqi Xu Shape.SwitchLowering.IndexField = IndexField.LayoutFieldIndex;
12056e5b8f48SChuanqi Xu Shape.SwitchLowering.IndexAlign = IndexField.Alignment.value();
12066e5b8f48SChuanqi Xu Shape.SwitchLowering.IndexOffset = IndexField.Offset;
12079514c048SJohn McCall
12089514c048SJohn McCall // Also round the frame size up to a multiple of its alignment, as is
12099514c048SJohn McCall // generally expected in C/C++.
12109514c048SJohn McCall Shape.FrameSize = alignTo(Shape.FrameSize, Shape.FrameAlign);
121194010b2bSJohn McCall break;
12126e5b8f48SChuanqi Xu }
121394010b2bSJohn McCall
12149514c048SJohn McCall // In the retcon ABI, remember whether the frame is inline in the storage.
121594010b2bSJohn McCall case coro::ABI::Retcon:
121694010b2bSJohn McCall case coro::ABI::RetconOnce: {
121794010b2bSJohn McCall auto Id = Shape.getRetconCoroId();
121894010b2bSJohn McCall Shape.RetconLowering.IsFrameInlineInStorage
12199514c048SJohn McCall = (B.getStructSize() <= Id->getStorageSize() &&
12209514c048SJohn McCall B.getStructAlign() <= Id->getStorageAlignment());
122194010b2bSJohn McCall break;
122294010b2bSJohn McCall }
1223ea5989b4SArnold Schwaighofer case coro::ABI::Async: {
1224ea5989b4SArnold Schwaighofer Shape.AsyncLowering.FrameOffset =
1225ea5989b4SArnold Schwaighofer alignTo(Shape.AsyncLowering.ContextHeaderSize, Shape.FrameAlign);
12268fb73cecSArnold Schwaighofer // Also make the final context size a multiple of the context alignment to
12278fb73cecSArnold Schwaighofer // make allocation easier for allocators.
1228ea5989b4SArnold Schwaighofer Shape.AsyncLowering.ContextSize =
12298fb73cecSArnold Schwaighofer alignTo(Shape.AsyncLowering.FrameOffset + Shape.FrameSize,
12308fb73cecSArnold Schwaighofer Shape.AsyncLowering.getContextAlignment());
1231ea5989b4SArnold Schwaighofer if (Shape.AsyncLowering.getContextAlignment() < Shape.FrameAlign) {
1232ea5989b4SArnold Schwaighofer report_fatal_error(
1233ea5989b4SArnold Schwaighofer "The alignment requirment of frame variables cannot be higher than "
1234ea5989b4SArnold Schwaighofer "the alignment of the async function context");
1235ea5989b4SArnold Schwaighofer }
1236ea5989b4SArnold Schwaighofer break;
1237ea5989b4SArnold Schwaighofer }
123894010b2bSJohn McCall }
123994010b2bSJohn McCall
124074309fa0SGor Nishanov return FrameTy;
124174309fa0SGor Nishanov }
124274309fa0SGor Nishanov
12439f5a2beaSXun Li // We use a pointer use visitor to track how an alloca is being used.
12449f5a2beaSXun Li // The goal is to be able to answer the following three questions:
12459f5a2beaSXun Li // 1. Should this alloca be allocated on the frame instead.
12469f5a2beaSXun Li // 2. Could the content of the alloca be modified prior to CoroBegn, which would
12479f5a2beaSXun Li // require copying the data from alloca to the frame after CoroBegin.
12489f5a2beaSXun Li // 3. Is there any alias created for this alloca prior to CoroBegin, but used
12499f5a2beaSXun Li // after CoroBegin. In that case, we will need to recreate the alias after
12509f5a2beaSXun Li // CoroBegin based off the frame. To answer question 1, we track two things:
12519f5a2beaSXun Li // a. List of all BasicBlocks that use this alloca or any of the aliases of
12529f5a2beaSXun Li // the alloca. In the end, we check if there exists any two basic blocks that
12539f5a2beaSXun Li // cross suspension points. If so, this alloca must be put on the frame. b.
12549f5a2beaSXun Li // Whether the alloca or any alias of the alloca is escaped at some point,
12559f5a2beaSXun Li // either by storing the address somewhere, or the address is used in a
12569f5a2beaSXun Li // function call that might capture. If it's ever escaped, this alloca must be
12579f5a2beaSXun Li // put on the frame conservatively.
12589f5a2beaSXun Li // To answer quetion 2, we track through the variable MayWriteBeforeCoroBegin.
12599f5a2beaSXun Li // Whenever a potential write happens, either through a store instruction, a
12609f5a2beaSXun Li // function call or any of the memory intrinsics, we check whether this
12619f5a2beaSXun Li // instruction is prior to CoroBegin. To answer question 3, we track the offsets
12629f5a2beaSXun Li // of all aliases created for the alloca prior to CoroBegin but used after
12639f5a2beaSXun Li // CoroBegin. llvm::Optional is used to be able to represent the case when the
12649f5a2beaSXun Li // offset is unknown (e.g. when you have a PHINode that takes in different
12659f5a2beaSXun Li // offset values). We cannot handle unknown offsets and will assert. This is the
12669f5a2beaSXun Li // potential issue left out. An ideal solution would likely require a
12679f5a2beaSXun Li // significant redesign.
1268efe00934SGor Nishanov namespace {
1269efe00934SGor Nishanov struct AllocaUseVisitor : PtrUseVisitor<AllocaUseVisitor> {
1270efe00934SGor Nishanov using Base = PtrUseVisitor<AllocaUseVisitor>;
AllocaUseVisitor__anon8d9a21161311::AllocaUseVisitor1271efe00934SGor Nishanov AllocaUseVisitor(const DataLayout &DL, const DominatorTree &DT,
12727c0e0668SArnold Schwaighofer const CoroBeginInst &CB, const SuspendCrossingInfo &Checker,
12737c0e0668SArnold Schwaighofer bool ShouldUseLifetimeStartInfo)
12747c0e0668SArnold Schwaighofer : PtrUseVisitor(DL), DT(DT), CoroBegin(CB), Checker(Checker),
12757c0e0668SArnold Schwaighofer ShouldUseLifetimeStartInfo(ShouldUseLifetimeStartInfo) {}
1276efe00934SGor Nishanov
visit__anon8d9a21161311::AllocaUseVisitor1277efe00934SGor Nishanov void visit(Instruction &I) {
1278c38000a9SXun Li Users.insert(&I);
1279efe00934SGor Nishanov Base::visit(I);
12809f5a2beaSXun Li // If the pointer is escaped prior to CoroBegin, we have to assume it would
12819f5a2beaSXun Li // be written into before CoroBegin as well.
12829f5a2beaSXun Li if (PI.isEscaped() && !DT.dominates(&CoroBegin, PI.getEscapingInst())) {
12839f5a2beaSXun Li MayWriteBeforeCoroBegin = true;
12849f5a2beaSXun Li }
1285efe00934SGor Nishanov }
1286efe00934SGor Nishanov // We need to provide this overload as PtrUseVisitor uses a pointer based
1287efe00934SGor Nishanov // visiting function.
visit__anon8d9a21161311::AllocaUseVisitor1288efe00934SGor Nishanov void visit(Instruction *I) { return visit(*I); }
1289efe00934SGor Nishanov
visitPHINode__anon8d9a21161311::AllocaUseVisitor129059a467eeSXun Li void visitPHINode(PHINode &I) {
12919f5a2beaSXun Li enqueueUsers(I);
12929f5a2beaSXun Li handleAlias(I);
129359a467eeSXun Li }
129459a467eeSXun Li
visitSelectInst__anon8d9a21161311::AllocaUseVisitor129559a467eeSXun Li void visitSelectInst(SelectInst &I) {
12969f5a2beaSXun Li enqueueUsers(I);
12979f5a2beaSXun Li handleAlias(I);
129859a467eeSXun Li }
129959a467eeSXun Li
visitStoreInst__anon8d9a21161311::AllocaUseVisitor13009f5a2beaSXun Li void visitStoreInst(StoreInst &SI) {
13019f5a2beaSXun Li // Regardless whether the alias of the alloca is the value operand or the
13029f5a2beaSXun Li // pointer operand, we need to assume the alloca is been written.
13039f5a2beaSXun Li handleMayWrite(SI);
1304985c5240SXun Li
1305985c5240SXun Li if (SI.getValueOperand() != U->get())
1306985c5240SXun Li return;
1307985c5240SXun Li
1308985c5240SXun Li // We are storing the pointer into a memory location, potentially escaping.
1309985c5240SXun Li // As an optimization, we try to detect simple cases where it doesn't
1310985c5240SXun Li // actually escape, for example:
1311985c5240SXun Li // %ptr = alloca ..
1312985c5240SXun Li // %addr = alloca ..
1313985c5240SXun Li // store %ptr, %addr
1314985c5240SXun Li // %x = load %addr
1315985c5240SXun Li // ..
1316985c5240SXun Li // If %addr is only used by loading from it, we could simply treat %x as
1317985c5240SXun Li // another alias of %ptr, and not considering %ptr being escaped.
1318985c5240SXun Li auto IsSimpleStoreThenLoad = [&]() {
1319985c5240SXun Li auto *AI = dyn_cast<AllocaInst>(SI.getPointerOperand());
1320985c5240SXun Li // If the memory location we are storing to is not an alloca, it
1321985c5240SXun Li // could be an alias of some other memory locations, which is difficult
1322985c5240SXun Li // to analyze.
1323985c5240SXun Li if (!AI)
1324985c5240SXun Li return false;
1325985c5240SXun Li // StoreAliases contains aliases of the memory location stored into.
1326985c5240SXun Li SmallVector<Instruction *, 4> StoreAliases = {AI};
1327985c5240SXun Li while (!StoreAliases.empty()) {
13281238378fSKazu Hirata Instruction *I = StoreAliases.pop_back_val();
1329985c5240SXun Li for (User *U : I->users()) {
1330985c5240SXun Li // If we are loading from the memory location, we are creating an
1331985c5240SXun Li // alias of the original pointer.
1332985c5240SXun Li if (auto *LI = dyn_cast<LoadInst>(U)) {
1333985c5240SXun Li enqueueUsers(*LI);
1334985c5240SXun Li handleAlias(*LI);
1335985c5240SXun Li continue;
1336985c5240SXun Li }
1337985c5240SXun Li // If we are overriding the memory location, the pointer certainly
1338985c5240SXun Li // won't escape.
1339985c5240SXun Li if (auto *S = dyn_cast<StoreInst>(U))
1340985c5240SXun Li if (S->getPointerOperand() == I)
1341985c5240SXun Li continue;
1342985c5240SXun Li if (auto *II = dyn_cast<IntrinsicInst>(U))
1343985c5240SXun Li if (II->isLifetimeStartOrEnd())
1344985c5240SXun Li continue;
1345985c5240SXun Li // BitCastInst creats aliases of the memory location being stored
1346985c5240SXun Li // into.
1347985c5240SXun Li if (auto *BI = dyn_cast<BitCastInst>(U)) {
1348985c5240SXun Li StoreAliases.push_back(BI);
1349985c5240SXun Li continue;
1350985c5240SXun Li }
1351985c5240SXun Li return false;
1352985c5240SXun Li }
1353985c5240SXun Li }
1354985c5240SXun Li
1355985c5240SXun Li return true;
1356985c5240SXun Li };
1357985c5240SXun Li
1358985c5240SXun Li if (!IsSimpleStoreThenLoad())
1359985c5240SXun Li PI.setEscaped(&SI);
13609f5a2beaSXun Li }
1361efe00934SGor Nishanov
136259a467eeSXun Li // All mem intrinsics modify the data.
visitMemIntrinsic__anon8d9a21161311::AllocaUseVisitor13639f5a2beaSXun Li void visitMemIntrinsic(MemIntrinsic &MI) { handleMayWrite(MI); }
136459a467eeSXun Li
visitBitCastInst__anon8d9a21161311::AllocaUseVisitor136559a467eeSXun Li void visitBitCastInst(BitCastInst &BC) {
136659a467eeSXun Li Base::visitBitCastInst(BC);
136759a467eeSXun Li handleAlias(BC);
136859a467eeSXun Li }
136959a467eeSXun Li
visitAddrSpaceCastInst__anon8d9a21161311::AllocaUseVisitor137059a467eeSXun Li void visitAddrSpaceCastInst(AddrSpaceCastInst &ASC) {
137159a467eeSXun Li Base::visitAddrSpaceCastInst(ASC);
137259a467eeSXun Li handleAlias(ASC);
137359a467eeSXun Li }
137459a467eeSXun Li
visitGetElementPtrInst__anon8d9a21161311::AllocaUseVisitor137559a467eeSXun Li void visitGetElementPtrInst(GetElementPtrInst &GEPI) {
137659a467eeSXun Li // The base visitor will adjust Offset accordingly.
137759a467eeSXun Li Base::visitGetElementPtrInst(GEPI);
137859a467eeSXun Li handleAlias(GEPI);
137959a467eeSXun Li }
138059a467eeSXun Li
visitIntrinsicInst__anon8d9a21161311::AllocaUseVisitor1381c38000a9SXun Li void visitIntrinsicInst(IntrinsicInst &II) {
1382ddbf1961SChuanqi Xu // When we found the lifetime markers refers to a
1383ddbf1961SChuanqi Xu // subrange of the original alloca, ignore the lifetime
1384ddbf1961SChuanqi Xu // markers to avoid misleading the analysis.
1385ddbf1961SChuanqi Xu if (II.getIntrinsicID() != Intrinsic::lifetime_start || !IsOffsetKnown ||
1386ddbf1961SChuanqi Xu !Offset.isZero())
1387c38000a9SXun Li return Base::visitIntrinsicInst(II);
1388c38000a9SXun Li LifetimeStarts.insert(&II);
1389c38000a9SXun Li }
1390c38000a9SXun Li
visitCallBase__anon8d9a21161311::AllocaUseVisitor13919f5a2beaSXun Li void visitCallBase(CallBase &CB) {
13924f0225f6SKazu Hirata for (unsigned Op = 0, OpCount = CB.arg_size(); Op < OpCount; ++Op)
13939f5a2beaSXun Li if (U->get() == CB.getArgOperand(Op) && !CB.doesNotCapture(Op))
13949f5a2beaSXun Li PI.setEscaped(&CB);
13959f5a2beaSXun Li handleMayWrite(CB);
13969f5a2beaSXun Li }
13979f5a2beaSXun Li
getShouldLiveOnFrame__anon8d9a21161311::AllocaUseVisitor13989f5a2beaSXun Li bool getShouldLiveOnFrame() const {
13999f5a2beaSXun Li if (!ShouldLiveOnFrame)
14009f5a2beaSXun Li ShouldLiveOnFrame = computeShouldLiveOnFrame();
14017a47ee51SKazu Hirata return *ShouldLiveOnFrame;
14029f5a2beaSXun Li }
14039f5a2beaSXun Li
getMayWriteBeforeCoroBegin__anon8d9a21161311::AllocaUseVisitor14049f5a2beaSXun Li bool getMayWriteBeforeCoroBegin() const { return MayWriteBeforeCoroBegin; }
14059f5a2beaSXun Li
getAliasesCopy__anon8d9a21161311::AllocaUseVisitor14069f5a2beaSXun Li DenseMap<Instruction *, llvm::Optional<APInt>> getAliasesCopy() const {
14079f5a2beaSXun Li assert(getShouldLiveOnFrame() && "This method should only be called if the "
14089f5a2beaSXun Li "alloca needs to live on the frame.");
14099f5a2beaSXun Li for (const auto &P : AliasOffetMap)
14109f5a2beaSXun Li if (!P.second)
14119f5a2beaSXun Li report_fatal_error("Unable to handle an alias with unknown offset "
14129f5a2beaSXun Li "created before CoroBegin.");
14139f5a2beaSXun Li return AliasOffetMap;
141459a467eeSXun Li }
1415efe00934SGor Nishanov
1416efe00934SGor Nishanov private:
1417efe00934SGor Nishanov const DominatorTree &DT;
1418efe00934SGor Nishanov const CoroBeginInst &CoroBegin;
14199f5a2beaSXun Li const SuspendCrossingInfo &Checker;
14209f5a2beaSXun Li // All alias to the original AllocaInst, created before CoroBegin and used
14219f5a2beaSXun Li // after CoroBegin. Each entry contains the instruction and the offset in the
14229f5a2beaSXun Li // original Alloca. They need to be recreated after CoroBegin off the frame.
14239f5a2beaSXun Li DenseMap<Instruction *, llvm::Optional<APInt>> AliasOffetMap{};
1424c38000a9SXun Li SmallPtrSet<Instruction *, 4> Users{};
1425c38000a9SXun Li SmallPtrSet<IntrinsicInst *, 2> LifetimeStarts{};
14269f5a2beaSXun Li bool MayWriteBeforeCoroBegin{false};
14277c0e0668SArnold Schwaighofer bool ShouldUseLifetimeStartInfo{true};
14289f5a2beaSXun Li
14299f5a2beaSXun Li mutable llvm::Optional<bool> ShouldLiveOnFrame{};
14309f5a2beaSXun Li
computeShouldLiveOnFrame__anon8d9a21161311::AllocaUseVisitor14319f5a2beaSXun Li bool computeShouldLiveOnFrame() const {
1432c38000a9SXun Li // If lifetime information is available, we check it first since it's
1433c38000a9SXun Li // more precise. We look at every pair of lifetime.start intrinsic and
1434c38000a9SXun Li // every basic block that uses the pointer to see if they cross suspension
1435c38000a9SXun Li // points. The uses cover both direct uses as well as indirect uses.
14367c0e0668SArnold Schwaighofer if (ShouldUseLifetimeStartInfo && !LifetimeStarts.empty()) {
1437c38000a9SXun Li for (auto *I : Users)
1438c38000a9SXun Li for (auto *S : LifetimeStarts)
1439c38000a9SXun Li if (Checker.isDefinitionAcrossSuspend(*S, I))
1440c38000a9SXun Li return true;
1441c38000a9SXun Li return false;
1442c38000a9SXun Li }
1443c38000a9SXun Li // FIXME: Ideally the isEscaped check should come at the beginning.
1444c38000a9SXun Li // However there are a few loose ends that need to be fixed first before
1445c38000a9SXun Li // we can do that. We need to make sure we are not over-conservative, so
1446c38000a9SXun Li // that the data accessed in-between await_suspend and symmetric transfer
1447c38000a9SXun Li // is always put on the stack, and also data accessed after coro.end is
1448c38000a9SXun Li // always put on the stack (esp the return object). To fix that, we need
1449c38000a9SXun Li // to:
1450c38000a9SXun Li // 1) Potentially treat sret as nocapture in calls
1451c38000a9SXun Li // 2) Special handle the return object and put it on the stack
1452c38000a9SXun Li // 3) Utilize lifetime.end intrinsic
14539f5a2beaSXun Li if (PI.isEscaped())
14549f5a2beaSXun Li return true;
14559f5a2beaSXun Li
1456c38000a9SXun Li for (auto *U1 : Users)
1457c38000a9SXun Li for (auto *U2 : Users)
1458c38000a9SXun Li if (Checker.isDefinitionAcrossSuspend(*U1, U2))
14599f5a2beaSXun Li return true;
14609f5a2beaSXun Li
14619f5a2beaSXun Li return false;
14629f5a2beaSXun Li }
14639f5a2beaSXun Li
handleMayWrite__anon8d9a21161311::AllocaUseVisitor14649f5a2beaSXun Li void handleMayWrite(const Instruction &I) {
14659f5a2beaSXun Li if (!DT.dominates(&CoroBegin, &I))
14669f5a2beaSXun Li MayWriteBeforeCoroBegin = true;
14679f5a2beaSXun Li }
146859a467eeSXun Li
usedAfterCoroBegin__anon8d9a21161311::AllocaUseVisitor146959a467eeSXun Li bool usedAfterCoroBegin(Instruction &I) {
147059a467eeSXun Li for (auto &U : I.uses())
147159a467eeSXun Li if (DT.dominates(&CoroBegin, U))
1472efe00934SGor Nishanov return true;
1473efe00934SGor Nishanov return false;
1474efe00934SGor Nishanov }
1475efe00934SGor Nishanov
handleAlias__anon8d9a21161311::AllocaUseVisitor147659a467eeSXun Li void handleAlias(Instruction &I) {
14779f5a2beaSXun Li // We track all aliases created prior to CoroBegin but used after.
14789f5a2beaSXun Li // These aliases may need to be recreated after CoroBegin if the alloca
14799f5a2beaSXun Li // need to live on the frame.
14809f5a2beaSXun Li if (DT.dominates(&CoroBegin, &I) || !usedAfterCoroBegin(I))
148159a467eeSXun Li return;
148259a467eeSXun Li
14839f5a2beaSXun Li if (!IsOffsetKnown) {
148436fa658dSVitaly Buka AliasOffetMap[&I].reset();
14859f5a2beaSXun Li } else {
14869f5a2beaSXun Li auto Itr = AliasOffetMap.find(&I);
14879f5a2beaSXun Li if (Itr == AliasOffetMap.end()) {
14889f5a2beaSXun Li AliasOffetMap[&I] = Offset;
1489e0e687a6SKazu Hirata } else if (Itr->second && *Itr->second != Offset) {
14909f5a2beaSXun Li // If we have seen two different possible values for this alias, we set
14919f5a2beaSXun Li // it to empty.
149214552595SVitaly Buka AliasOffetMap[&I].reset();
14939f5a2beaSXun Li }
14949f5a2beaSXun Li }
149559a467eeSXun Li }
149659a467eeSXun Li };
149759a467eeSXun Li } // namespace
149859a467eeSXun Li
1499db384855SGor Nishanov // We need to make room to insert a spill after initial PHIs, but before
1500db384855SGor Nishanov // catchswitch instruction. Placing it before violates the requirement that
1501db384855SGor Nishanov // catchswitch, like all other EHPads must be the first nonPHI in a block.
1502db384855SGor Nishanov //
1503db384855SGor Nishanov // Split away catchswitch into a separate block and insert in its place:
1504db384855SGor Nishanov //
1505db384855SGor Nishanov // cleanuppad <InsertPt> cleanupret.
1506db384855SGor Nishanov //
1507db384855SGor Nishanov // cleanupret instruction will act as an insert point for the spill.
splitBeforeCatchSwitch(CatchSwitchInst * CatchSwitch)1508db384855SGor Nishanov static Instruction *splitBeforeCatchSwitch(CatchSwitchInst *CatchSwitch) {
1509db384855SGor Nishanov BasicBlock *CurrentBlock = CatchSwitch->getParent();
1510db384855SGor Nishanov BasicBlock *NewBlock = CurrentBlock->splitBasicBlock(CatchSwitch);
1511db384855SGor Nishanov CurrentBlock->getTerminator()->eraseFromParent();
1512db384855SGor Nishanov
1513db384855SGor Nishanov auto *CleanupPad =
1514db384855SGor Nishanov CleanupPadInst::Create(CatchSwitch->getParentPad(), {}, "", CurrentBlock);
1515db384855SGor Nishanov auto *CleanupRet =
1516db384855SGor Nishanov CleanupReturnInst::Create(CleanupPad, NewBlock, CurrentBlock);
1517db384855SGor Nishanov return CleanupRet;
1518db384855SGor Nishanov }
1519db384855SGor Nishanov
createFramePtr(coro::Shape & Shape)15206e5b8f48SChuanqi Xu static void createFramePtr(coro::Shape &Shape) {
15216e5b8f48SChuanqi Xu auto *CB = Shape.CoroBegin;
15226e5b8f48SChuanqi Xu IRBuilder<> Builder(CB->getNextNode());
15236e5b8f48SChuanqi Xu StructType *FrameTy = Shape.FrameTy;
15246e5b8f48SChuanqi Xu PointerType *FramePtrTy = FrameTy->getPointerTo();
15256e5b8f48SChuanqi Xu Shape.FramePtr =
15266e5b8f48SChuanqi Xu cast<Instruction>(Builder.CreateBitCast(CB, FramePtrTy, "FramePtr"));
15276e5b8f48SChuanqi Xu }
15286e5b8f48SChuanqi Xu
152974309fa0SGor Nishanov // Replace all alloca and SSA values that are accessed across suspend points
153074309fa0SGor Nishanov // with GetElementPointer from coroutine frame + loads and stores. Create an
153174309fa0SGor Nishanov // AllocaSpillBB that will become the new entry block for the resume parts of
153274309fa0SGor Nishanov // the coroutine:
153374309fa0SGor Nishanov //
153474309fa0SGor Nishanov // %hdl = coro.begin(...)
153574309fa0SGor Nishanov // whatever
153674309fa0SGor Nishanov //
153774309fa0SGor Nishanov // becomes:
153874309fa0SGor Nishanov //
153974309fa0SGor Nishanov // %hdl = coro.begin(...)
154074309fa0SGor Nishanov // %FramePtr = bitcast i8* hdl to %f.frame*
154174309fa0SGor Nishanov // br label %AllocaSpillBB
154274309fa0SGor Nishanov //
154374309fa0SGor Nishanov // AllocaSpillBB:
154474309fa0SGor Nishanov // ; geps corresponding to allocas that were moved to coroutine frame
154574309fa0SGor Nishanov // br label PostSpill
154674309fa0SGor Nishanov //
154774309fa0SGor Nishanov // PostSpill:
154874309fa0SGor Nishanov // whatever
154974309fa0SGor Nishanov //
155074309fa0SGor Nishanov //
insertSpills(const FrameDataInfo & FrameData,coro::Shape & Shape)15516467d1d2SNikita Popov static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
155274309fa0SGor Nishanov auto *CB = Shape.CoroBegin;
1553d64455cdSGor Nishanov LLVMContext &C = CB->getContext();
15546e5b8f48SChuanqi Xu IRBuilder<> Builder(C);
155514359ef1SJames Y Knight StructType *FrameTy = Shape.FrameTy;
15569bca4ea3SNikita Popov Value *FramePtr = Shape.FramePtr;
1557efe00934SGor Nishanov DominatorTree DT(*CB->getFunction());
15580554541bSAdrian Prantl SmallDenseMap<llvm::Value *, llvm::AllocaInst *, 4> DbgPtrAllocaCache;
155974309fa0SGor Nishanov
1560d64455cdSGor Nishanov // Create a GEP with the given index into the coroutine frame for the original
1561d64455cdSGor Nishanov // value Orig. Appends an extra 0 index for array-allocas, preserving the
1562d64455cdSGor Nishanov // original type.
1563667dfe39SXun Li auto GetFramePointer = [&](Value *Orig) -> Value * {
1564667dfe39SXun Li FieldIDType Index = FrameData.getFieldIndex(Orig);
1565d64455cdSGor Nishanov SmallVector<Value *, 3> Indices = {
1566d64455cdSGor Nishanov ConstantInt::get(Type::getInt32Ty(C), 0),
1567d64455cdSGor Nishanov ConstantInt::get(Type::getInt32Ty(C), Index),
1568d64455cdSGor Nishanov };
1569d64455cdSGor Nishanov
1570d64455cdSGor Nishanov if (auto *AI = dyn_cast<AllocaInst>(Orig)) {
1571d64455cdSGor Nishanov if (auto *CI = dyn_cast<ConstantInt>(AI->getArraySize())) {
1572d64455cdSGor Nishanov auto Count = CI->getValue().getZExtValue();
1573d64455cdSGor Nishanov if (Count > 1) {
1574d64455cdSGor Nishanov Indices.push_back(ConstantInt::get(Type::getInt32Ty(C), 0));
1575d64455cdSGor Nishanov }
1576d64455cdSGor Nishanov } else {
1577d64455cdSGor Nishanov report_fatal_error("Coroutines cannot handle non static allocas yet");
1578d64455cdSGor Nishanov }
1579d64455cdSGor Nishanov }
1580d64455cdSGor Nishanov
1581b3a722e6SChuanqi Xu auto GEP = cast<GetElementPtrInst>(
1582b3a722e6SChuanqi Xu Builder.CreateInBoundsGEP(FrameTy, FramePtr, Indices));
15835c902af5SArnold Schwaighofer if (auto *AI = dyn_cast<AllocaInst>(Orig)) {
15845c902af5SArnold Schwaighofer if (FrameData.getDynamicAlign(Orig) != 0) {
158577bba68dSGuillaume Chatelet assert(FrameData.getDynamicAlign(Orig) == AI->getAlign().value());
15865c902af5SArnold Schwaighofer auto *M = AI->getModule();
15875c902af5SArnold Schwaighofer auto *IntPtrTy = M->getDataLayout().getIntPtrType(AI->getType());
15885c902af5SArnold Schwaighofer auto *PtrValue = Builder.CreatePtrToInt(GEP, IntPtrTy);
158977bba68dSGuillaume Chatelet auto *AlignMask =
159077bba68dSGuillaume Chatelet ConstantInt::get(IntPtrTy, AI->getAlign().value() - 1);
15915c902af5SArnold Schwaighofer PtrValue = Builder.CreateAdd(PtrValue, AlignMask);
15925c902af5SArnold Schwaighofer PtrValue = Builder.CreateAnd(PtrValue, Builder.CreateNot(AlignMask));
15935c902af5SArnold Schwaighofer return Builder.CreateIntToPtr(PtrValue, AI->getType());
15945c902af5SArnold Schwaighofer }
1595b3a722e6SChuanqi Xu // If the type of GEP is not equal to the type of AllocaInst, it implies
1596b3a722e6SChuanqi Xu // that the AllocaInst may be reused in the Frame slot of other
1597c1bc7981SChuanqi Xu // AllocaInst. So We cast GEP to the AllocaInst here to re-use
1598c1bc7981SChuanqi Xu // the Frame storage.
1599c1bc7981SChuanqi Xu //
1600c1bc7981SChuanqi Xu // Note: If we change the strategy dealing with alignment, we need to refine
1601c1bc7981SChuanqi Xu // this casting.
1602b3a722e6SChuanqi Xu if (GEP->getResultElementType() != Orig->getType())
1603b3a722e6SChuanqi Xu return Builder.CreateBitCast(GEP, Orig->getType(),
1604b3a722e6SChuanqi Xu Orig->getName() + Twine(".cast"));
1605b3a722e6SChuanqi Xu }
1606b3a722e6SChuanqi Xu return GEP;
1607d64455cdSGor Nishanov };
1608d64455cdSGor Nishanov
1609667dfe39SXun Li for (auto const &E : FrameData.Spills) {
1610667dfe39SXun Li Value *Def = E.first;
16112937f8d1SArnold Schwaighofer auto SpillAlignment = Align(FrameData.getAlign(Def));
1612667dfe39SXun Li // Create a store instruction storing the value into the
1613df3d71a7SGor Nishanov // coroutine frame.
1614df3d71a7SGor Nishanov Instruction *InsertPt = nullptr;
161522f4f942SArthur Eubanks Type *ByValTy = nullptr;
1616667dfe39SXun Li if (auto *Arg = dyn_cast<Argument>(Def)) {
1617df3d71a7SGor Nishanov // For arguments, we will place the store instruction right after
1618df3d71a7SGor Nishanov // the coroutine frame pointer instruction, i.e. bitcast of
1619df3d71a7SGor Nishanov // coro.begin from i8* to %f.frame*.
16209bca4ea3SNikita Popov InsertPt = Shape.getInsertPtAfterFramePtr();
162194010b2bSJohn McCall
162294010b2bSJohn McCall // If we're spilling an Argument, make sure we clear 'nocapture'
162394010b2bSJohn McCall // from the coroutine function.
1624667dfe39SXun Li Arg->getParent()->removeParamAttr(Arg->getArgNo(), Attribute::NoCapture);
162594010b2bSJohn McCall
16263522167eSXun Li if (Arg->hasByValAttr())
162722f4f942SArthur Eubanks ByValTy = Arg->getParamByValType();
1628667dfe39SXun Li } else if (auto *CSI = dyn_cast<AnyCoroSuspendInst>(Def)) {
162994010b2bSJohn McCall // Don't spill immediately after a suspend; splitting assumes
163094010b2bSJohn McCall // that the suspend will be followed by a branch.
163194010b2bSJohn McCall InsertPt = CSI->getParent()->getSingleSuccessor()->getFirstNonPHI();
1632df3d71a7SGor Nishanov } else {
1633667dfe39SXun Li auto *I = cast<Instruction>(Def);
16345b533d6cSXun Li if (!DT.dominates(CB, I)) {
16355b533d6cSXun Li // If it is not dominated by CoroBegin, then spill should be
16365b533d6cSXun Li // inserted immediately after CoroFrame is computed.
16379bca4ea3SNikita Popov InsertPt = Shape.getInsertPtAfterFramePtr();
16385b533d6cSXun Li } else if (auto *II = dyn_cast<InvokeInst>(I)) {
16395b533d6cSXun Li // If we are spilling the result of the invoke instruction, split
16405b533d6cSXun Li // the normal edge and insert the spill in the new block.
16415b533d6cSXun Li auto *NewBB = SplitEdge(II->getParent(), II->getNormalDest());
16425b533d6cSXun Li InsertPt = NewBB->getTerminator();
16435b533d6cSXun Li } else if (isa<PHINode>(I)) {
16445b533d6cSXun Li // Skip the PHINodes and EH pads instructions.
16455b533d6cSXun Li BasicBlock *DefBlock = I->getParent();
1646667dfe39SXun Li if (auto *CSI = dyn_cast<CatchSwitchInst>(DefBlock->getTerminator()))
16475b533d6cSXun Li InsertPt = splitBeforeCatchSwitch(CSI);
16485b533d6cSXun Li else
16495b533d6cSXun Li InsertPt = &*DefBlock->getFirstInsertionPt();
16505b533d6cSXun Li } else {
1651efe00934SGor Nishanov assert(!I->isTerminator() && "unexpected terminator");
1652df3d71a7SGor Nishanov // For all other values, the spill is placed immediately after
1653df3d71a7SGor Nishanov // the definition.
1654efe00934SGor Nishanov InsertPt = I->getNextNode();
1655efe00934SGor Nishanov }
1656df3d71a7SGor Nishanov }
1657df3d71a7SGor Nishanov
1658667dfe39SXun Li auto Index = FrameData.getFieldIndex(Def);
1659df3d71a7SGor Nishanov Builder.SetInsertPoint(InsertPt);
1660241b041fSGor Nishanov auto *G = Builder.CreateConstInBoundsGEP2_32(
1661667dfe39SXun Li FrameTy, FramePtr, 0, Index, Def->getName() + Twine(".spill.addr"));
166222f4f942SArthur Eubanks if (ByValTy) {
16633522167eSXun Li // For byval arguments, we need to store the pointed value in the frame,
16643522167eSXun Li // instead of the pointer itself.
166522f4f942SArthur Eubanks auto *Value = Builder.CreateLoad(ByValTy, Def);
16662937f8d1SArnold Schwaighofer Builder.CreateAlignedStore(Value, G, SpillAlignment);
16673522167eSXun Li } else {
16682937f8d1SArnold Schwaighofer Builder.CreateAlignedStore(Def, G, SpillAlignment);
16693522167eSXun Li }
1670667dfe39SXun Li
1671667dfe39SXun Li BasicBlock *CurrentBlock = nullptr;
1672667dfe39SXun Li Value *CurrentReload = nullptr;
1673667dfe39SXun Li for (auto *U : E.second) {
1674667dfe39SXun Li // If we have not seen the use block, create a load instruction to reload
1675667dfe39SXun Li // the spilled value from the coroutine frame. Populates the Value pointer
1676667dfe39SXun Li // reference provided with the frame GEP.
1677667dfe39SXun Li if (CurrentBlock != U->getParent()) {
1678667dfe39SXun Li CurrentBlock = U->getParent();
1679667dfe39SXun Li Builder.SetInsertPoint(&*CurrentBlock->getFirstInsertionPt());
1680667dfe39SXun Li
1681667dfe39SXun Li auto *GEP = GetFramePointer(E.first);
1682667dfe39SXun Li GEP->setName(E.first->getName() + Twine(".reload.addr"));
168322f4f942SArthur Eubanks if (ByValTy)
16843522167eSXun Li CurrentReload = GEP;
16853522167eSXun Li else
16862937f8d1SArnold Schwaighofer CurrentReload = Builder.CreateAlignedLoad(
1687667dfe39SXun Li FrameTy->getElementType(FrameData.getFieldIndex(E.first)), GEP,
16882937f8d1SArnold Schwaighofer SpillAlignment, E.first->getName() + Twine(".reload"));
16890554541bSAdrian Prantl
16900554541bSAdrian Prantl TinyPtrVector<DbgDeclareInst *> DIs = FindDbgDeclareUses(Def);
16910554541bSAdrian Prantl for (DbgDeclareInst *DDI : DIs) {
16920554541bSAdrian Prantl bool AllowUnresolved = false;
16930554541bSAdrian Prantl // This dbg.declare is preserved for all coro-split function
16940554541bSAdrian Prantl // fragments. It will be unreachable in the main function, and
16950554541bSAdrian Prantl // processed by coro::salvageDebugInfo() by CoroCloner.
16960554541bSAdrian Prantl DIBuilder(*CurrentBlock->getParent()->getParent(), AllowUnresolved)
16970554541bSAdrian Prantl .insertDeclare(CurrentReload, DDI->getVariable(),
16980554541bSAdrian Prantl DDI->getExpression(), DDI->getDebugLoc(),
16990554541bSAdrian Prantl &*Builder.GetInsertPoint());
17000554541bSAdrian Prantl // This dbg.declare is for the main function entry point. It
17010554541bSAdrian Prantl // will be deleted in all coro-split functions.
170224e53b01SChuanqi Xu coro::salvageDebugInfo(DbgPtrAllocaCache, DDI, Shape.OptimizeFrame);
17030554541bSAdrian Prantl }
1704241b041fSGor Nishanov }
1705241b041fSGor Nishanov
170619279ffcSMichael Gottesman // Salvage debug info on any dbg.addr that we see. We do not insert them
170719279ffcSMichael Gottesman // into each block where we have a use though.
170819279ffcSMichael Gottesman if (auto *DI = dyn_cast<DbgAddrIntrinsic>(U)) {
170924e53b01SChuanqi Xu coro::salvageDebugInfo(DbgPtrAllocaCache, DI, Shape.OptimizeFrame);
171019279ffcSMichael Gottesman }
171119279ffcSMichael Gottesman
1712667dfe39SXun Li // If we have a single edge PHINode, remove it and replace it with a
1713667dfe39SXun Li // reload from the coroutine frame. (We already took care of multi edge
1714667dfe39SXun Li // PHINodes by rewriting them in the rewritePHIs function).
1715667dfe39SXun Li if (auto *PN = dyn_cast<PHINode>(U)) {
1716667dfe39SXun Li assert(PN->getNumIncomingValues() == 1 &&
1717667dfe39SXun Li "unexpected number of incoming "
1718faf36c2eSGor Nishanov "values in the PHINode");
1719faf36c2eSGor Nishanov PN->replaceAllUsesWith(CurrentReload);
1720faf36c2eSGor Nishanov PN->eraseFromParent();
1721faf36c2eSGor Nishanov continue;
1722faf36c2eSGor Nishanov }
1723faf36c2eSGor Nishanov
1724667dfe39SXun Li // Replace all uses of CurrentValue in the current instruction with
1725667dfe39SXun Li // reload.
1726667dfe39SXun Li U->replaceUsesOfWith(Def, CurrentReload);
1727aa85b437SBrian Gesiak }
1728241b041fSGor Nishanov }
1729241b041fSGor Nishanov
17309bca4ea3SNikita Popov BasicBlock *FramePtrBB = Shape.getInsertPtAfterFramePtr()->getParent();
173174309fa0SGor Nishanov
17329bca4ea3SNikita Popov auto SpillBlock = FramePtrBB->splitBasicBlock(
17339bca4ea3SNikita Popov Shape.getInsertPtAfterFramePtr(), "AllocaSpillBB");
173494010b2bSJohn McCall SpillBlock->splitBasicBlock(&SpillBlock->front(), "PostSpill");
173594010b2bSJohn McCall Shape.AllocaSpillBlock = SpillBlock;
17362e4c5d1cSArnold Schwaighofer
17372e4c5d1cSArnold Schwaighofer // retcon and retcon.once lowering assumes all uses have been sunk.
1738ea5989b4SArnold Schwaighofer if (Shape.ABI == coro::ABI::Retcon || Shape.ABI == coro::ABI::RetconOnce ||
1739ea5989b4SArnold Schwaighofer Shape.ABI == coro::ABI::Async) {
17402e4c5d1cSArnold Schwaighofer // If we found any allocas, replace all of their remaining uses with Geps.
17412e4c5d1cSArnold Schwaighofer Builder.SetInsertPoint(&SpillBlock->front());
1742667dfe39SXun Li for (const auto &P : FrameData.Allocas) {
17439f5a2beaSXun Li AllocaInst *Alloca = P.Alloca;
17449f5a2beaSXun Li auto *G = GetFramePointer(Alloca);
17452e4c5d1cSArnold Schwaighofer
17462e4c5d1cSArnold Schwaighofer // We are not using ReplaceInstWithInst(P.first, cast<Instruction>(G))
17472e4c5d1cSArnold Schwaighofer // here, as we are changing location of the instruction.
17489f5a2beaSXun Li G->takeName(Alloca);
17499f5a2beaSXun Li Alloca->replaceAllUsesWith(G);
17509f5a2beaSXun Li Alloca->eraseFromParent();
17512e4c5d1cSArnold Schwaighofer }
17526467d1d2SNikita Popov return;
17532e4c5d1cSArnold Schwaighofer }
17542e4c5d1cSArnold Schwaighofer
1755aa85b437SBrian Gesiak // If we found any alloca, replace all of their remaining uses with GEP
1756c1359ef0SChuanqi Xu // instructions. To remain debugbility, we replace the uses of allocas for
1757c1359ef0SChuanqi Xu // dbg.declares and dbg.values with the reload from the frame.
1758aa85b437SBrian Gesiak // Note: We cannot replace the alloca with GEP instructions indiscriminately,
1759aa85b437SBrian Gesiak // as some of the uses may not be dominated by CoroBegin.
1760efe00934SGor Nishanov Builder.SetInsertPoint(&Shape.AllocaSpillBlock->front());
1761efe00934SGor Nishanov SmallVector<Instruction *, 4> UsersToUpdate;
17629f5a2beaSXun Li for (const auto &A : FrameData.Allocas) {
17639f5a2beaSXun Li AllocaInst *Alloca = A.Alloca;
1764efe00934SGor Nishanov UsersToUpdate.clear();
17659f5a2beaSXun Li for (User *U : Alloca->users()) {
1766efe00934SGor Nishanov auto *I = cast<Instruction>(U);
1767efe00934SGor Nishanov if (DT.dominates(CB, I))
1768efe00934SGor Nishanov UsersToUpdate.push_back(I);
1769efe00934SGor Nishanov }
17709f5a2beaSXun Li if (UsersToUpdate.empty())
17719f5a2beaSXun Li continue;
17729f5a2beaSXun Li auto *G = GetFramePointer(Alloca);
17739f5a2beaSXun Li G->setName(Alloca->getName() + Twine(".reload.addr"));
1774dc14542aSBruno Cardoso Lopes
1775c1359ef0SChuanqi Xu SmallVector<DbgVariableIntrinsic *, 4> DIs;
1776c1359ef0SChuanqi Xu findDbgUsers(DIs, Alloca);
1777c1359ef0SChuanqi Xu for (auto *DVI : DIs)
1778c1359ef0SChuanqi Xu DVI->replaceUsesOfWith(Alloca, G);
1779667dfe39SXun Li
17800554541bSAdrian Prantl for (Instruction *I : UsersToUpdate)
17819f5a2beaSXun Li I->replaceUsesOfWith(Alloca, G);
1782efe00934SGor Nishanov }
17839bca4ea3SNikita Popov Builder.SetInsertPoint(Shape.getInsertPtAfterFramePtr());
17849f5a2beaSXun Li for (const auto &A : FrameData.Allocas) {
17859f5a2beaSXun Li AllocaInst *Alloca = A.Alloca;
17869f5a2beaSXun Li if (A.MayWriteBeforeCoroBegin) {
178759a467eeSXun Li // isEscaped really means potentially modified before CoroBegin.
17889f5a2beaSXun Li if (Alloca->isArrayAllocation())
1789efe00934SGor Nishanov report_fatal_error(
1790efe00934SGor Nishanov "Coroutines cannot handle copying of array allocas yet");
1791efe00934SGor Nishanov
17929f5a2beaSXun Li auto *G = GetFramePointer(Alloca);
17939f5a2beaSXun Li auto *Value = Builder.CreateLoad(Alloca->getAllocatedType(), Alloca);
1794efe00934SGor Nishanov Builder.CreateStore(Value, G);
1795efe00934SGor Nishanov }
179659a467eeSXun Li // For each alias to Alloca created before CoroBegin but used after
179759a467eeSXun Li // CoroBegin, we recreate them after CoroBegin by appplying the offset
179859a467eeSXun Li // to the pointer in the frame.
17999f5a2beaSXun Li for (const auto &Alias : A.Aliases) {
18009f5a2beaSXun Li auto *FramePtr = GetFramePointer(Alloca);
180159a467eeSXun Li auto *FramePtrRaw =
180259a467eeSXun Li Builder.CreateBitCast(FramePtr, Type::getInt8PtrTy(C));
18037a47ee51SKazu Hirata auto &Value = *Alias.second;
1804950c95cfSNathan Lanza auto ITy = IntegerType::get(C, Value.getBitWidth());
1805950c95cfSNathan Lanza auto *AliasPtr = Builder.CreateGEP(Type::getInt8Ty(C), FramePtrRaw,
1806950c95cfSNathan Lanza ConstantInt::get(ITy, Value));
180759a467eeSXun Li auto *AliasPtrTyped =
180859a467eeSXun Li Builder.CreateBitCast(AliasPtr, Alias.first->getType());
180959a467eeSXun Li Alias.first->replaceUsesWithIf(
181059a467eeSXun Li AliasPtrTyped, [&](Use &U) { return DT.dominates(CB, U); });
181159a467eeSXun Li }
1812efe00934SGor Nishanov }
181374309fa0SGor Nishanov }
181474309fa0SGor Nishanov
1815d2166076SDaniel Paoliello // Moves the values in the PHIs in SuccBB that correspong to PredBB into a new
1816d2166076SDaniel Paoliello // PHI in InsertedBB.
movePHIValuesToInsertedBlock(BasicBlock * SuccBB,BasicBlock * InsertedBB,BasicBlock * PredBB,PHINode * UntilPHI=nullptr)1817d2166076SDaniel Paoliello static void movePHIValuesToInsertedBlock(BasicBlock *SuccBB,
1818d2166076SDaniel Paoliello BasicBlock *InsertedBB,
1819d2166076SDaniel Paoliello BasicBlock *PredBB,
1820d2166076SDaniel Paoliello PHINode *UntilPHI = nullptr) {
1821d2166076SDaniel Paoliello auto *PN = cast<PHINode>(&SuccBB->front());
1822d2166076SDaniel Paoliello do {
1823d2166076SDaniel Paoliello int Index = PN->getBasicBlockIndex(InsertedBB);
1824d2166076SDaniel Paoliello Value *V = PN->getIncomingValue(Index);
1825d2166076SDaniel Paoliello PHINode *InputV = PHINode::Create(
1826d2166076SDaniel Paoliello V->getType(), 1, V->getName() + Twine(".") + SuccBB->getName(),
1827d2166076SDaniel Paoliello &InsertedBB->front());
1828d2166076SDaniel Paoliello InputV->addIncoming(V, PredBB);
1829d2166076SDaniel Paoliello PN->setIncomingValue(Index, InputV);
1830d2166076SDaniel Paoliello PN = dyn_cast<PHINode>(PN->getNextNode());
1831d2166076SDaniel Paoliello } while (PN != UntilPHI);
1832d2166076SDaniel Paoliello }
1833d2166076SDaniel Paoliello
1834d2166076SDaniel Paoliello // Rewrites the PHI Nodes in a cleanuppad.
rewritePHIsForCleanupPad(BasicBlock * CleanupPadBB,CleanupPadInst * CleanupPad)1835d2166076SDaniel Paoliello static void rewritePHIsForCleanupPad(BasicBlock *CleanupPadBB,
1836d2166076SDaniel Paoliello CleanupPadInst *CleanupPad) {
1837d2166076SDaniel Paoliello // For every incoming edge to a CleanupPad we will create a new block holding
1838d2166076SDaniel Paoliello // all incoming values in single-value PHI nodes. We will then create another
1839d2166076SDaniel Paoliello // block to act as a dispather (as all unwind edges for related EH blocks
1840d2166076SDaniel Paoliello // must be the same).
1841d2166076SDaniel Paoliello //
1842d2166076SDaniel Paoliello // cleanuppad:
1843d2166076SDaniel Paoliello // %2 = phi i32[%0, %catchswitch], [%1, %catch.1]
1844d2166076SDaniel Paoliello // %3 = cleanuppad within none []
1845d2166076SDaniel Paoliello //
1846d2166076SDaniel Paoliello // It will create:
1847d2166076SDaniel Paoliello //
1848d2166076SDaniel Paoliello // cleanuppad.corodispatch
1849d2166076SDaniel Paoliello // %2 = phi i8[0, %catchswitch], [1, %catch.1]
1850d2166076SDaniel Paoliello // %3 = cleanuppad within none []
1851d2166076SDaniel Paoliello // switch i8 % 2, label %unreachable
1852d2166076SDaniel Paoliello // [i8 0, label %cleanuppad.from.catchswitch
1853d2166076SDaniel Paoliello // i8 1, label %cleanuppad.from.catch.1]
1854d2166076SDaniel Paoliello // cleanuppad.from.catchswitch:
1855d2166076SDaniel Paoliello // %4 = phi i32 [%0, %catchswitch]
1856d2166076SDaniel Paoliello // br %label cleanuppad
1857d2166076SDaniel Paoliello // cleanuppad.from.catch.1:
1858d2166076SDaniel Paoliello // %6 = phi i32 [%1, %catch.1]
1859d2166076SDaniel Paoliello // br %label cleanuppad
1860d2166076SDaniel Paoliello // cleanuppad:
1861d2166076SDaniel Paoliello // %8 = phi i32 [%4, %cleanuppad.from.catchswitch],
1862d2166076SDaniel Paoliello // [%6, %cleanuppad.from.catch.1]
1863d2166076SDaniel Paoliello
1864d2166076SDaniel Paoliello // Unreachable BB, in case switching on an invalid value in the dispatcher.
1865d2166076SDaniel Paoliello auto *UnreachBB = BasicBlock::Create(
1866d2166076SDaniel Paoliello CleanupPadBB->getContext(), "unreachable", CleanupPadBB->getParent());
1867d2166076SDaniel Paoliello IRBuilder<> Builder(UnreachBB);
1868d2166076SDaniel Paoliello Builder.CreateUnreachable();
1869d2166076SDaniel Paoliello
1870d2166076SDaniel Paoliello // Create a new cleanuppad which will be the dispatcher.
1871d2166076SDaniel Paoliello auto *NewCleanupPadBB =
1872d2166076SDaniel Paoliello BasicBlock::Create(CleanupPadBB->getContext(),
1873d2166076SDaniel Paoliello CleanupPadBB->getName() + Twine(".corodispatch"),
1874d2166076SDaniel Paoliello CleanupPadBB->getParent(), CleanupPadBB);
1875d2166076SDaniel Paoliello Builder.SetInsertPoint(NewCleanupPadBB);
1876d2166076SDaniel Paoliello auto *SwitchType = Builder.getInt8Ty();
1877d2166076SDaniel Paoliello auto *SetDispatchValuePN =
1878d2166076SDaniel Paoliello Builder.CreatePHI(SwitchType, pred_size(CleanupPadBB));
1879d2166076SDaniel Paoliello CleanupPad->removeFromParent();
1880d2166076SDaniel Paoliello CleanupPad->insertAfter(SetDispatchValuePN);
1881d2166076SDaniel Paoliello auto *SwitchOnDispatch = Builder.CreateSwitch(SetDispatchValuePN, UnreachBB,
1882d2166076SDaniel Paoliello pred_size(CleanupPadBB));
1883d2166076SDaniel Paoliello
1884d2166076SDaniel Paoliello int SwitchIndex = 0;
18858f5da41cSKazu Hirata SmallVector<BasicBlock *, 8> Preds(predecessors(CleanupPadBB));
1886d2166076SDaniel Paoliello for (BasicBlock *Pred : Preds) {
1887d2166076SDaniel Paoliello // Create a new cleanuppad and move the PHI values to there.
1888d2166076SDaniel Paoliello auto *CaseBB = BasicBlock::Create(CleanupPadBB->getContext(),
1889d2166076SDaniel Paoliello CleanupPadBB->getName() +
1890d2166076SDaniel Paoliello Twine(".from.") + Pred->getName(),
1891d2166076SDaniel Paoliello CleanupPadBB->getParent(), CleanupPadBB);
1892d2166076SDaniel Paoliello updatePhiNodes(CleanupPadBB, Pred, CaseBB);
1893d2166076SDaniel Paoliello CaseBB->setName(CleanupPadBB->getName() + Twine(".from.") +
1894d2166076SDaniel Paoliello Pred->getName());
1895d2166076SDaniel Paoliello Builder.SetInsertPoint(CaseBB);
1896d2166076SDaniel Paoliello Builder.CreateBr(CleanupPadBB);
1897d2166076SDaniel Paoliello movePHIValuesToInsertedBlock(CleanupPadBB, CaseBB, NewCleanupPadBB);
1898d2166076SDaniel Paoliello
1899d2166076SDaniel Paoliello // Update this Pred to the new unwind point.
1900d2166076SDaniel Paoliello setUnwindEdgeTo(Pred->getTerminator(), NewCleanupPadBB);
1901d2166076SDaniel Paoliello
1902d2166076SDaniel Paoliello // Setup the switch in the dispatcher.
1903d2166076SDaniel Paoliello auto *SwitchConstant = ConstantInt::get(SwitchType, SwitchIndex);
1904d2166076SDaniel Paoliello SetDispatchValuePN->addIncoming(SwitchConstant, Pred);
1905d2166076SDaniel Paoliello SwitchOnDispatch->addCase(SwitchConstant, CaseBB);
1906d2166076SDaniel Paoliello SwitchIndex++;
1907d2166076SDaniel Paoliello }
1908d2166076SDaniel Paoliello }
1909d2166076SDaniel Paoliello
cleanupSinglePredPHIs(Function & F)1910846a530eSArnold Schwaighofer static void cleanupSinglePredPHIs(Function &F) {
1911846a530eSArnold Schwaighofer SmallVector<PHINode *, 32> Worklist;
1912846a530eSArnold Schwaighofer for (auto &BB : F) {
1913846a530eSArnold Schwaighofer for (auto &Phi : BB.phis()) {
1914846a530eSArnold Schwaighofer if (Phi.getNumIncomingValues() == 1) {
1915846a530eSArnold Schwaighofer Worklist.push_back(&Phi);
1916846a530eSArnold Schwaighofer } else
1917846a530eSArnold Schwaighofer break;
1918846a530eSArnold Schwaighofer }
1919846a530eSArnold Schwaighofer }
1920846a530eSArnold Schwaighofer while (!Worklist.empty()) {
192184b07c9bSKazu Hirata auto *Phi = Worklist.pop_back_val();
1922846a530eSArnold Schwaighofer auto *OriginalValue = Phi->getIncomingValue(0);
1923846a530eSArnold Schwaighofer Phi->replaceAllUsesWith(OriginalValue);
1924846a530eSArnold Schwaighofer }
1925846a530eSArnold Schwaighofer }
1926846a530eSArnold Schwaighofer
rewritePHIs(BasicBlock & BB)1927241b041fSGor Nishanov static void rewritePHIs(BasicBlock &BB) {
1928241b041fSGor Nishanov // For every incoming edge we will create a block holding all
1929241b041fSGor Nishanov // incoming values in a single PHI nodes.
1930241b041fSGor Nishanov //
1931241b041fSGor Nishanov // loop:
1932241b041fSGor Nishanov // %n.val = phi i32[%n, %entry], [%inc, %loop]
1933241b041fSGor Nishanov //
1934241b041fSGor Nishanov // It will create:
1935241b041fSGor Nishanov //
1936241b041fSGor Nishanov // loop.from.entry:
1937241b041fSGor Nishanov // %n.loop.pre = phi i32 [%n, %entry]
1938241b041fSGor Nishanov // br %label loop
1939241b041fSGor Nishanov // loop.from.loop:
1940241b041fSGor Nishanov // %inc.loop.pre = phi i32 [%inc, %loop]
1941241b041fSGor Nishanov // br %label loop
1942241b041fSGor Nishanov //
1943241b041fSGor Nishanov // After this rewrite, further analysis will ignore any phi nodes with more
1944241b041fSGor Nishanov // than one incoming edge.
1945241b041fSGor Nishanov
1946241b041fSGor Nishanov // TODO: Simplify PHINodes in the basic block to remove duplicate
1947241b041fSGor Nishanov // predecessors.
1948241b041fSGor Nishanov
1949d2166076SDaniel Paoliello // Special case for CleanupPad: all EH blocks must have the same unwind edge
1950d2166076SDaniel Paoliello // so we need to create an additional "dispatcher" block.
1951d2166076SDaniel Paoliello if (auto *CleanupPad =
1952d2166076SDaniel Paoliello dyn_cast_or_null<CleanupPadInst>(BB.getFirstNonPHI())) {
1953530c5af6SKazu Hirata SmallVector<BasicBlock *, 8> Preds(predecessors(&BB));
1954d2166076SDaniel Paoliello for (BasicBlock *Pred : Preds) {
1955d2166076SDaniel Paoliello if (CatchSwitchInst *CS =
1956d2166076SDaniel Paoliello dyn_cast<CatchSwitchInst>(Pred->getTerminator())) {
1957d2166076SDaniel Paoliello // CleanupPad with a CatchSwitch predecessor: therefore this is an
1958d2166076SDaniel Paoliello // unwind destination that needs to be handle specially.
1959d2166076SDaniel Paoliello assert(CS->getUnwindDest() == &BB);
1960fb98a1beSKazu Hirata (void)CS;
1961d2166076SDaniel Paoliello rewritePHIsForCleanupPad(&BB, CleanupPad);
1962d2166076SDaniel Paoliello return;
1963d2166076SDaniel Paoliello }
1964d2166076SDaniel Paoliello }
1965d2166076SDaniel Paoliello }
1966d2166076SDaniel Paoliello
196723453c11SGor Nishanov LandingPadInst *LandingPad = nullptr;
196823453c11SGor Nishanov PHINode *ReplPHI = nullptr;
196923453c11SGor Nishanov if ((LandingPad = dyn_cast_or_null<LandingPadInst>(BB.getFirstNonPHI()))) {
197023453c11SGor Nishanov // ehAwareSplitEdge will clone the LandingPad in all the edge blocks.
197123453c11SGor Nishanov // We replace the original landing pad with a PHINode that will collect the
197223453c11SGor Nishanov // results from all of them.
197323453c11SGor Nishanov ReplPHI = PHINode::Create(LandingPad->getType(), 1, "", LandingPad);
197423453c11SGor Nishanov ReplPHI->takeName(LandingPad);
197523453c11SGor Nishanov LandingPad->replaceAllUsesWith(ReplPHI);
197623453c11SGor Nishanov // We will erase the original landing pad at the end of this function after
197723453c11SGor Nishanov // ehAwareSplitEdge cloned it in the transition blocks.
197823453c11SGor Nishanov }
197923453c11SGor Nishanov
1980530c5af6SKazu Hirata SmallVector<BasicBlock *, 8> Preds(predecessors(&BB));
1981241b041fSGor Nishanov for (BasicBlock *Pred : Preds) {
198223453c11SGor Nishanov auto *IncomingBB = ehAwareSplitEdge(Pred, &BB, LandingPad, ReplPHI);
1983241b041fSGor Nishanov IncomingBB->setName(BB.getName() + Twine(".from.") + Pred->getName());
1984d2166076SDaniel Paoliello
1985d2166076SDaniel Paoliello // Stop the moving of values at ReplPHI, as this is either null or the PHI
1986d2166076SDaniel Paoliello // that replaced the landing pad.
1987d2166076SDaniel Paoliello movePHIValuesToInsertedBlock(&BB, IncomingBB, Pred, ReplPHI);
198823453c11SGor Nishanov }
198923453c11SGor Nishanov
199023453c11SGor Nishanov if (LandingPad) {
199123453c11SGor Nishanov // Calls to ehAwareSplitEdge function cloned the original lading pad.
199223453c11SGor Nishanov // No longer need it.
199323453c11SGor Nishanov LandingPad->eraseFromParent();
1994241b041fSGor Nishanov }
1995241b041fSGor Nishanov }
1996241b041fSGor Nishanov
rewritePHIs(Function & F)1997241b041fSGor Nishanov static void rewritePHIs(Function &F) {
1998241b041fSGor Nishanov SmallVector<BasicBlock *, 8> WorkList;
1999241b041fSGor Nishanov
2000241b041fSGor Nishanov for (BasicBlock &BB : F)
2001241b041fSGor Nishanov if (auto *PN = dyn_cast<PHINode>(&BB.front()))
2002241b041fSGor Nishanov if (PN->getNumIncomingValues() > 1)
2003241b041fSGor Nishanov WorkList.push_back(&BB);
2004241b041fSGor Nishanov
2005241b041fSGor Nishanov for (BasicBlock *BB : WorkList)
2006241b041fSGor Nishanov rewritePHIs(*BB);
2007241b041fSGor Nishanov }
2008241b041fSGor Nishanov
2009241b041fSGor Nishanov // Check for instructions that we can recreate on resume as opposed to spill
2010241b041fSGor Nishanov // the result into a coroutine frame.
materializable(Instruction & V)2011241b041fSGor Nishanov static bool materializable(Instruction &V) {
2012241b041fSGor Nishanov return isa<CastInst>(&V) || isa<GetElementPtrInst>(&V) ||
2013241b041fSGor Nishanov isa<BinaryOperator>(&V) || isa<CmpInst>(&V) || isa<SelectInst>(&V);
2014241b041fSGor Nishanov }
2015241b041fSGor Nishanov
2016a263a60aSGor Nishanov // Check for structural coroutine intrinsics that should not be spilled into
2017a263a60aSGor Nishanov // the coroutine frame.
isCoroutineStructureIntrinsic(Instruction & I)2018a263a60aSGor Nishanov static bool isCoroutineStructureIntrinsic(Instruction &I) {
20192f55b958SGor Nishanov return isa<CoroIdInst>(&I) || isa<CoroSaveInst>(&I) ||
20202f55b958SGor Nishanov isa<CoroSuspendInst>(&I);
2021a263a60aSGor Nishanov }
2022a263a60aSGor Nishanov
2023241b041fSGor Nishanov // For every use of the value that is across suspend point, recreate that value
2024241b041fSGor Nishanov // after a suspend point.
rewriteMaterializableInstructions(IRBuilder<> & IRB,const SpillInfo & Spills)2025241b041fSGor Nishanov static void rewriteMaterializableInstructions(IRBuilder<> &IRB,
2026667dfe39SXun Li const SpillInfo &Spills) {
2027667dfe39SXun Li for (const auto &E : Spills) {
2028667dfe39SXun Li Value *Def = E.first;
2029241b041fSGor Nishanov BasicBlock *CurrentBlock = nullptr;
2030241b041fSGor Nishanov Instruction *CurrentMaterialization = nullptr;
2031667dfe39SXun Li for (Instruction *U : E.second) {
2032241b041fSGor Nishanov // If we have not seen this block, materialize the value.
2033667dfe39SXun Li if (CurrentBlock != U->getParent()) {
20343dee1e8aSArnold Schwaighofer
20353dee1e8aSArnold Schwaighofer bool IsInCoroSuspendBlock = isa<AnyCoroSuspendInst>(U);
2036b987c283SArnold Schwaighofer CurrentBlock = U->getParent();
2037b987c283SArnold Schwaighofer auto *InsertBlock = IsInCoroSuspendBlock
2038b987c283SArnold Schwaighofer ? CurrentBlock->getSinglePredecessor()
2039b987c283SArnold Schwaighofer : CurrentBlock;
2040667dfe39SXun Li CurrentMaterialization = cast<Instruction>(Def)->clone();
2041667dfe39SXun Li CurrentMaterialization->setName(Def->getName());
2042241b041fSGor Nishanov CurrentMaterialization->insertBefore(
2043b987c283SArnold Schwaighofer IsInCoroSuspendBlock ? InsertBlock->getTerminator()
2044b987c283SArnold Schwaighofer : &*InsertBlock->getFirstInsertionPt());
2045241b041fSGor Nishanov }
2046667dfe39SXun Li if (auto *PN = dyn_cast<PHINode>(U)) {
2047667dfe39SXun Li assert(PN->getNumIncomingValues() == 1 &&
2048667dfe39SXun Li "unexpected number of incoming "
2049241b041fSGor Nishanov "values in the PHINode");
2050241b041fSGor Nishanov PN->replaceAllUsesWith(CurrentMaterialization);
2051241b041fSGor Nishanov PN->eraseFromParent();
2052241b041fSGor Nishanov continue;
2053241b041fSGor Nishanov }
2054667dfe39SXun Li // Replace all uses of Def in the current instruction with the
2055241b041fSGor Nishanov // CurrentMaterialization for the block.
2056667dfe39SXun Li U->replaceUsesOfWith(Def, CurrentMaterialization);
2057667dfe39SXun Li }
2058241b041fSGor Nishanov }
2059241b041fSGor Nishanov }
2060241b041fSGor Nishanov
2061241b041fSGor Nishanov // Splits the block at a particular instruction unless it is the first
2062241b041fSGor Nishanov // instruction in the block with a single predecessor.
splitBlockIfNotFirst(Instruction * I,const Twine & Name)2063241b041fSGor Nishanov static BasicBlock *splitBlockIfNotFirst(Instruction *I, const Twine &Name) {
2064241b041fSGor Nishanov auto *BB = I->getParent();
2065241b041fSGor Nishanov if (&BB->front() == I) {
2066241b041fSGor Nishanov if (BB->getSinglePredecessor()) {
2067241b041fSGor Nishanov BB->setName(Name);
2068241b041fSGor Nishanov return BB;
2069241b041fSGor Nishanov }
2070241b041fSGor Nishanov }
2071241b041fSGor Nishanov return BB->splitBasicBlock(I, Name);
2072241b041fSGor Nishanov }
2073241b041fSGor Nishanov
2074241b041fSGor Nishanov // Split above and below a particular instruction so that it
2075241b041fSGor Nishanov // will be all alone by itself in a block.
splitAround(Instruction * I,const Twine & Name)2076241b041fSGor Nishanov static void splitAround(Instruction *I, const Twine &Name) {
2077241b041fSGor Nishanov splitBlockIfNotFirst(I, Name);
2078241b041fSGor Nishanov splitBlockIfNotFirst(I->getNextNode(), "After" + Name);
2079241b041fSGor Nishanov }
2080241b041fSGor Nishanov
isSuspendBlock(BasicBlock * BB)208162a5dde0SJohn McCall static bool isSuspendBlock(BasicBlock *BB) {
208262a5dde0SJohn McCall return isa<AnyCoroSuspendInst>(BB->front());
208362a5dde0SJohn McCall }
208462a5dde0SJohn McCall
208562a5dde0SJohn McCall typedef SmallPtrSet<BasicBlock*, 8> VisitedBlocksSet;
208662a5dde0SJohn McCall
208762a5dde0SJohn McCall /// Does control flow starting at the given block ever reach a suspend
208862a5dde0SJohn McCall /// instruction before reaching a block in VisitedOrFreeBBs?
isSuspendReachableFrom(BasicBlock * From,VisitedBlocksSet & VisitedOrFreeBBs)208962a5dde0SJohn McCall static bool isSuspendReachableFrom(BasicBlock *From,
209062a5dde0SJohn McCall VisitedBlocksSet &VisitedOrFreeBBs) {
209162a5dde0SJohn McCall // Eagerly try to add this block to the visited set. If it's already
209262a5dde0SJohn McCall // there, stop recursing; this path doesn't reach a suspend before
209362a5dde0SJohn McCall // either looping or reaching a freeing block.
209462a5dde0SJohn McCall if (!VisitedOrFreeBBs.insert(From).second)
209562a5dde0SJohn McCall return false;
209662a5dde0SJohn McCall
209762a5dde0SJohn McCall // We assume that we'll already have split suspends into their own blocks.
209862a5dde0SJohn McCall if (isSuspendBlock(From))
209962a5dde0SJohn McCall return true;
210062a5dde0SJohn McCall
210162a5dde0SJohn McCall // Recurse on the successors.
210262a5dde0SJohn McCall for (auto Succ : successors(From)) {
210362a5dde0SJohn McCall if (isSuspendReachableFrom(Succ, VisitedOrFreeBBs))
210462a5dde0SJohn McCall return true;
210562a5dde0SJohn McCall }
210662a5dde0SJohn McCall
210762a5dde0SJohn McCall return false;
210862a5dde0SJohn McCall }
210962a5dde0SJohn McCall
211062a5dde0SJohn McCall /// Is the given alloca "local", i.e. bounded in lifetime to not cross a
211162a5dde0SJohn McCall /// suspend point?
isLocalAlloca(CoroAllocaAllocInst * AI)211262a5dde0SJohn McCall static bool isLocalAlloca(CoroAllocaAllocInst *AI) {
211362a5dde0SJohn McCall // Seed the visited set with all the basic blocks containing a free
211462a5dde0SJohn McCall // so that we won't pass them up.
211562a5dde0SJohn McCall VisitedBlocksSet VisitedOrFreeBBs;
211662a5dde0SJohn McCall for (auto User : AI->users()) {
211762a5dde0SJohn McCall if (auto FI = dyn_cast<CoroAllocaFreeInst>(User))
211862a5dde0SJohn McCall VisitedOrFreeBBs.insert(FI->getParent());
211962a5dde0SJohn McCall }
212062a5dde0SJohn McCall
212162a5dde0SJohn McCall return !isSuspendReachableFrom(AI->getParent(), VisitedOrFreeBBs);
212262a5dde0SJohn McCall }
212362a5dde0SJohn McCall
212462a5dde0SJohn McCall /// After we split the coroutine, will the given basic block be along
212562a5dde0SJohn McCall /// an obvious exit path for the resumption function?
willLeaveFunctionImmediatelyAfter(BasicBlock * BB,unsigned depth=3)212662a5dde0SJohn McCall static bool willLeaveFunctionImmediatelyAfter(BasicBlock *BB,
212762a5dde0SJohn McCall unsigned depth = 3) {
212862a5dde0SJohn McCall // If we've bottomed out our depth count, stop searching and assume
212962a5dde0SJohn McCall // that the path might loop back.
213062a5dde0SJohn McCall if (depth == 0) return false;
213162a5dde0SJohn McCall
213262a5dde0SJohn McCall // If this is a suspend block, we're about to exit the resumption function.
213362a5dde0SJohn McCall if (isSuspendBlock(BB)) return true;
213462a5dde0SJohn McCall
213562a5dde0SJohn McCall // Recurse into the successors.
213662a5dde0SJohn McCall for (auto Succ : successors(BB)) {
213762a5dde0SJohn McCall if (!willLeaveFunctionImmediatelyAfter(Succ, depth - 1))
213862a5dde0SJohn McCall return false;
213962a5dde0SJohn McCall }
214062a5dde0SJohn McCall
214162a5dde0SJohn McCall // If none of the successors leads back in a loop, we're on an exit/abort.
214262a5dde0SJohn McCall return true;
214362a5dde0SJohn McCall }
214462a5dde0SJohn McCall
localAllocaNeedsStackSave(CoroAllocaAllocInst * AI)214562a5dde0SJohn McCall static bool localAllocaNeedsStackSave(CoroAllocaAllocInst *AI) {
214662a5dde0SJohn McCall // Look for a free that isn't sufficiently obviously followed by
214762a5dde0SJohn McCall // either a suspend or a termination, i.e. something that will leave
214862a5dde0SJohn McCall // the coro resumption frame.
214962a5dde0SJohn McCall for (auto U : AI->users()) {
215062a5dde0SJohn McCall auto FI = dyn_cast<CoroAllocaFreeInst>(U);
215162a5dde0SJohn McCall if (!FI) continue;
215262a5dde0SJohn McCall
215362a5dde0SJohn McCall if (!willLeaveFunctionImmediatelyAfter(FI->getParent()))
215462a5dde0SJohn McCall return true;
215562a5dde0SJohn McCall }
215662a5dde0SJohn McCall
215762a5dde0SJohn McCall // If we never found one, we don't need a stack save.
215862a5dde0SJohn McCall return false;
215962a5dde0SJohn McCall }
216062a5dde0SJohn McCall
216162a5dde0SJohn McCall /// Turn each of the given local allocas into a normal (dynamic) alloca
216262a5dde0SJohn McCall /// instruction.
lowerLocalAllocas(ArrayRef<CoroAllocaAllocInst * > LocalAllocas,SmallVectorImpl<Instruction * > & DeadInsts)2163ac404832SJohn McCall static void lowerLocalAllocas(ArrayRef<CoroAllocaAllocInst*> LocalAllocas,
2164ac404832SJohn McCall SmallVectorImpl<Instruction*> &DeadInsts) {
216562a5dde0SJohn McCall for (auto AI : LocalAllocas) {
216662a5dde0SJohn McCall auto M = AI->getModule();
216762a5dde0SJohn McCall IRBuilder<> Builder(AI);
216862a5dde0SJohn McCall
216962a5dde0SJohn McCall // Save the stack depth. Try to avoid doing this if the stackrestore
217062a5dde0SJohn McCall // is going to immediately precede a return or something.
217162a5dde0SJohn McCall Value *StackSave = nullptr;
217262a5dde0SJohn McCall if (localAllocaNeedsStackSave(AI))
217362a5dde0SJohn McCall StackSave = Builder.CreateCall(
217462a5dde0SJohn McCall Intrinsic::getDeclaration(M, Intrinsic::stacksave));
217562a5dde0SJohn McCall
217662a5dde0SJohn McCall // Allocate memory.
217762a5dde0SJohn McCall auto Alloca = Builder.CreateAlloca(Builder.getInt8Ty(), AI->getSize());
217877bba68dSGuillaume Chatelet Alloca->setAlignment(AI->getAlignment());
217962a5dde0SJohn McCall
218062a5dde0SJohn McCall for (auto U : AI->users()) {
218162a5dde0SJohn McCall // Replace gets with the allocation.
218262a5dde0SJohn McCall if (isa<CoroAllocaGetInst>(U)) {
218362a5dde0SJohn McCall U->replaceAllUsesWith(Alloca);
218462a5dde0SJohn McCall
218562a5dde0SJohn McCall // Replace frees with stackrestores. This is safe because
218662a5dde0SJohn McCall // alloca.alloc is required to obey a stack discipline, although we
218762a5dde0SJohn McCall // don't enforce that structurally.
218862a5dde0SJohn McCall } else {
218962a5dde0SJohn McCall auto FI = cast<CoroAllocaFreeInst>(U);
219062a5dde0SJohn McCall if (StackSave) {
219162a5dde0SJohn McCall Builder.SetInsertPoint(FI);
219262a5dde0SJohn McCall Builder.CreateCall(
219362a5dde0SJohn McCall Intrinsic::getDeclaration(M, Intrinsic::stackrestore),
219462a5dde0SJohn McCall StackSave);
219562a5dde0SJohn McCall }
219662a5dde0SJohn McCall }
2197ac404832SJohn McCall DeadInsts.push_back(cast<Instruction>(U));
219862a5dde0SJohn McCall }
219962a5dde0SJohn McCall
2200ac404832SJohn McCall DeadInsts.push_back(AI);
220162a5dde0SJohn McCall }
220262a5dde0SJohn McCall }
220362a5dde0SJohn McCall
220462a5dde0SJohn McCall /// Turn the given coro.alloca.alloc call into a dynamic allocation.
220562a5dde0SJohn McCall /// This happens during the all-instructions iteration, so it must not
220662a5dde0SJohn McCall /// delete the call.
lowerNonLocalAlloca(CoroAllocaAllocInst * AI,coro::Shape & Shape,SmallVectorImpl<Instruction * > & DeadInsts)220762a5dde0SJohn McCall static Instruction *lowerNonLocalAlloca(CoroAllocaAllocInst *AI,
220862a5dde0SJohn McCall coro::Shape &Shape,
220962a5dde0SJohn McCall SmallVectorImpl<Instruction*> &DeadInsts) {
221062a5dde0SJohn McCall IRBuilder<> Builder(AI);
221162a5dde0SJohn McCall auto Alloc = Shape.emitAlloc(Builder, AI->getSize(), nullptr);
221262a5dde0SJohn McCall
221362a5dde0SJohn McCall for (User *U : AI->users()) {
221462a5dde0SJohn McCall if (isa<CoroAllocaGetInst>(U)) {
221562a5dde0SJohn McCall U->replaceAllUsesWith(Alloc);
221662a5dde0SJohn McCall } else {
221762a5dde0SJohn McCall auto FI = cast<CoroAllocaFreeInst>(U);
221862a5dde0SJohn McCall Builder.SetInsertPoint(FI);
221962a5dde0SJohn McCall Shape.emitDealloc(Builder, Alloc, nullptr);
222062a5dde0SJohn McCall }
222162a5dde0SJohn McCall DeadInsts.push_back(cast<Instruction>(U));
222262a5dde0SJohn McCall }
222362a5dde0SJohn McCall
222462a5dde0SJohn McCall // Push this on last so that it gets deleted after all the others.
222562a5dde0SJohn McCall DeadInsts.push_back(AI);
222662a5dde0SJohn McCall
222762a5dde0SJohn McCall // Return the new allocation value so that we can check for needed spills.
222862a5dde0SJohn McCall return cast<Instruction>(Alloc);
222962a5dde0SJohn McCall }
223062a5dde0SJohn McCall
22312133feecSJohn McCall /// Get the current swifterror value.
emitGetSwiftErrorValue(IRBuilder<> & Builder,Type * ValueTy,coro::Shape & Shape)22322133feecSJohn McCall static Value *emitGetSwiftErrorValue(IRBuilder<> &Builder, Type *ValueTy,
22332133feecSJohn McCall coro::Shape &Shape) {
22342133feecSJohn McCall // Make a fake function pointer as a sort of intrinsic.
22352133feecSJohn McCall auto FnTy = FunctionType::get(ValueTy, {}, false);
22362133feecSJohn McCall auto Fn = ConstantPointerNull::get(FnTy->getPointerTo());
22372133feecSJohn McCall
2238464d4cf7STim Northover auto Call = Builder.CreateCall(FnTy, Fn, {});
22392133feecSJohn McCall Shape.SwiftErrorOps.push_back(Call);
22402133feecSJohn McCall
22412133feecSJohn McCall return Call;
22422133feecSJohn McCall }
22432133feecSJohn McCall
22442133feecSJohn McCall /// Set the given value as the current swifterror value.
22452133feecSJohn McCall ///
22462133feecSJohn McCall /// Returns a slot that can be used as a swifterror slot.
emitSetSwiftErrorValue(IRBuilder<> & Builder,Value * V,coro::Shape & Shape)22472133feecSJohn McCall static Value *emitSetSwiftErrorValue(IRBuilder<> &Builder, Value *V,
22482133feecSJohn McCall coro::Shape &Shape) {
22492133feecSJohn McCall // Make a fake function pointer as a sort of intrinsic.
22502133feecSJohn McCall auto FnTy = FunctionType::get(V->getType()->getPointerTo(),
22512133feecSJohn McCall {V->getType()}, false);
22522133feecSJohn McCall auto Fn = ConstantPointerNull::get(FnTy->getPointerTo());
22532133feecSJohn McCall
2254464d4cf7STim Northover auto Call = Builder.CreateCall(FnTy, Fn, { V });
22552133feecSJohn McCall Shape.SwiftErrorOps.push_back(Call);
22562133feecSJohn McCall
22572133feecSJohn McCall return Call;
22582133feecSJohn McCall }
22592133feecSJohn McCall
22602133feecSJohn McCall /// Set the swifterror value from the given alloca before a call,
22612133feecSJohn McCall /// then put in back in the alloca afterwards.
22622133feecSJohn McCall ///
22632133feecSJohn McCall /// Returns an address that will stand in for the swifterror slot
22642133feecSJohn McCall /// until splitting.
emitSetAndGetSwiftErrorValueAround(Instruction * Call,AllocaInst * Alloca,coro::Shape & Shape)22652133feecSJohn McCall static Value *emitSetAndGetSwiftErrorValueAround(Instruction *Call,
22662133feecSJohn McCall AllocaInst *Alloca,
22672133feecSJohn McCall coro::Shape &Shape) {
22682133feecSJohn McCall auto ValueTy = Alloca->getAllocatedType();
22692133feecSJohn McCall IRBuilder<> Builder(Call);
22702133feecSJohn McCall
22712133feecSJohn McCall // Load the current value from the alloca and set it as the
22722133feecSJohn McCall // swifterror value.
22732133feecSJohn McCall auto ValueBeforeCall = Builder.CreateLoad(ValueTy, Alloca);
22742133feecSJohn McCall auto Addr = emitSetSwiftErrorValue(Builder, ValueBeforeCall, Shape);
22752133feecSJohn McCall
22762133feecSJohn McCall // Move to after the call. Since swifterror only has a guaranteed
22772133feecSJohn McCall // value on normal exits, we can ignore implicit and explicit unwind
22782133feecSJohn McCall // edges.
22792133feecSJohn McCall if (isa<CallInst>(Call)) {
22802133feecSJohn McCall Builder.SetInsertPoint(Call->getNextNode());
22812133feecSJohn McCall } else {
22822133feecSJohn McCall auto Invoke = cast<InvokeInst>(Call);
22832133feecSJohn McCall Builder.SetInsertPoint(Invoke->getNormalDest()->getFirstNonPHIOrDbg());
22842133feecSJohn McCall }
22852133feecSJohn McCall
22862133feecSJohn McCall // Get the current swifterror value and store it to the alloca.
22872133feecSJohn McCall auto ValueAfterCall = emitGetSwiftErrorValue(Builder, ValueTy, Shape);
22882133feecSJohn McCall Builder.CreateStore(ValueAfterCall, Alloca);
22892133feecSJohn McCall
22902133feecSJohn McCall return Addr;
22912133feecSJohn McCall }
22922133feecSJohn McCall
22932133feecSJohn McCall /// Eliminate a formerly-swifterror alloca by inserting the get/set
22942133feecSJohn McCall /// intrinsics and attempting to MemToReg the alloca away.
eliminateSwiftErrorAlloca(Function & F,AllocaInst * Alloca,coro::Shape & Shape)22952133feecSJohn McCall static void eliminateSwiftErrorAlloca(Function &F, AllocaInst *Alloca,
22962133feecSJohn McCall coro::Shape &Shape) {
22970d182d9dSKazu Hirata for (Use &Use : llvm::make_early_inc_range(Alloca->uses())) {
22982133feecSJohn McCall // swifterror values can only be used in very specific ways.
22992133feecSJohn McCall // We take advantage of that here.
23002133feecSJohn McCall auto User = Use.getUser();
23012133feecSJohn McCall if (isa<LoadInst>(User) || isa<StoreInst>(User))
23022133feecSJohn McCall continue;
23032133feecSJohn McCall
23042133feecSJohn McCall assert(isa<CallInst>(User) || isa<InvokeInst>(User));
23052133feecSJohn McCall auto Call = cast<Instruction>(User);
23062133feecSJohn McCall
23072133feecSJohn McCall auto Addr = emitSetAndGetSwiftErrorValueAround(Call, Alloca, Shape);
23082133feecSJohn McCall
23092133feecSJohn McCall // Use the returned slot address as the call argument.
23102133feecSJohn McCall Use.set(Addr);
23112133feecSJohn McCall }
23122133feecSJohn McCall
23132133feecSJohn McCall // All the uses should be loads and stores now.
23142133feecSJohn McCall assert(isAllocaPromotable(Alloca));
23152133feecSJohn McCall }
23162133feecSJohn McCall
23172133feecSJohn McCall /// "Eliminate" a swifterror argument by reducing it to the alloca case
23182133feecSJohn McCall /// and then loading and storing in the prologue and epilog.
23192133feecSJohn McCall ///
23202133feecSJohn McCall /// The argument keeps the swifterror flag.
eliminateSwiftErrorArgument(Function & F,Argument & Arg,coro::Shape & Shape,SmallVectorImpl<AllocaInst * > & AllocasToPromote)23212133feecSJohn McCall static void eliminateSwiftErrorArgument(Function &F, Argument &Arg,
23222133feecSJohn McCall coro::Shape &Shape,
23232133feecSJohn McCall SmallVectorImpl<AllocaInst*> &AllocasToPromote) {
23242133feecSJohn McCall IRBuilder<> Builder(F.getEntryBlock().getFirstNonPHIOrDbg());
23252133feecSJohn McCall
23262133feecSJohn McCall auto ArgTy = cast<PointerType>(Arg.getType());
23273d9386a3SNikita Popov // swifterror arguments are required to have pointer-to-pointer type,
23283d9386a3SNikita Popov // so create a pointer-typed alloca with opaque pointers.
23293d9386a3SNikita Popov auto ValueTy = ArgTy->isOpaque() ? PointerType::getUnqual(F.getContext())
23303d9386a3SNikita Popov : ArgTy->getNonOpaquePointerElementType();
23312133feecSJohn McCall
23322133feecSJohn McCall // Reduce to the alloca case:
23332133feecSJohn McCall
23342133feecSJohn McCall // Create an alloca and replace all uses of the arg with it.
23352133feecSJohn McCall auto Alloca = Builder.CreateAlloca(ValueTy, ArgTy->getAddressSpace());
23362133feecSJohn McCall Arg.replaceAllUsesWith(Alloca);
23372133feecSJohn McCall
23382133feecSJohn McCall // Set an initial value in the alloca. swifterror is always null on entry.
23392133feecSJohn McCall auto InitialValue = Constant::getNullValue(ValueTy);
23402133feecSJohn McCall Builder.CreateStore(InitialValue, Alloca);
23412133feecSJohn McCall
23422133feecSJohn McCall // Find all the suspends in the function and save and restore around them.
23432133feecSJohn McCall for (auto Suspend : Shape.CoroSuspends) {
23442133feecSJohn McCall (void) emitSetAndGetSwiftErrorValueAround(Suspend, Alloca, Shape);
23452133feecSJohn McCall }
23462133feecSJohn McCall
23472133feecSJohn McCall // Find all the coro.ends in the function and restore the error value.
23482133feecSJohn McCall for (auto End : Shape.CoroEnds) {
23492133feecSJohn McCall Builder.SetInsertPoint(End);
23502133feecSJohn McCall auto FinalValue = Builder.CreateLoad(ValueTy, Alloca);
23512133feecSJohn McCall (void) emitSetSwiftErrorValue(Builder, FinalValue, Shape);
23522133feecSJohn McCall }
23532133feecSJohn McCall
23542133feecSJohn McCall // Now we can use the alloca logic.
23552133feecSJohn McCall AllocasToPromote.push_back(Alloca);
23562133feecSJohn McCall eliminateSwiftErrorAlloca(F, Alloca, Shape);
23572133feecSJohn McCall }
23582133feecSJohn McCall
23592133feecSJohn McCall /// Eliminate all problematic uses of swifterror arguments and allocas
23602133feecSJohn McCall /// from the function. We'll fix them up later when splitting the function.
eliminateSwiftError(Function & F,coro::Shape & Shape)23612133feecSJohn McCall static void eliminateSwiftError(Function &F, coro::Shape &Shape) {
23622133feecSJohn McCall SmallVector<AllocaInst*, 4> AllocasToPromote;
23632133feecSJohn McCall
23642133feecSJohn McCall // Look for a swifterror argument.
23652133feecSJohn McCall for (auto &Arg : F.args()) {
23662133feecSJohn McCall if (!Arg.hasSwiftErrorAttr()) continue;
23672133feecSJohn McCall
23682133feecSJohn McCall eliminateSwiftErrorArgument(F, Arg, Shape, AllocasToPromote);
23692133feecSJohn McCall break;
23702133feecSJohn McCall }
23712133feecSJohn McCall
23722133feecSJohn McCall // Look for swifterror allocas.
23732133feecSJohn McCall for (auto &Inst : F.getEntryBlock()) {
23742133feecSJohn McCall auto Alloca = dyn_cast<AllocaInst>(&Inst);
23752133feecSJohn McCall if (!Alloca || !Alloca->isSwiftError()) continue;
23762133feecSJohn McCall
23772133feecSJohn McCall // Clear the swifterror flag.
23782133feecSJohn McCall Alloca->setSwiftError(false);
23792133feecSJohn McCall
23802133feecSJohn McCall AllocasToPromote.push_back(Alloca);
23812133feecSJohn McCall eliminateSwiftErrorAlloca(F, Alloca, Shape);
23822133feecSJohn McCall }
23832133feecSJohn McCall
23842133feecSJohn McCall // If we have any allocas to promote, compute a dominator tree and
23852133feecSJohn McCall // promote them en masse.
23862133feecSJohn McCall if (!AllocasToPromote.empty()) {
23872133feecSJohn McCall DominatorTree DT(F);
23882133feecSJohn McCall PromoteMemToReg(AllocasToPromote, DT);
23892133feecSJohn McCall }
23902133feecSJohn McCall }
23912133feecSJohn McCall
23922e4c5d1cSArnold Schwaighofer /// retcon and retcon.once conventions assume that all spill uses can be sunk
23932e4c5d1cSArnold Schwaighofer /// after the coro.begin intrinsic.
sinkSpillUsesAfterCoroBegin(Function & F,const FrameDataInfo & FrameData,CoroBeginInst * CoroBegin)2394667dfe39SXun Li static void sinkSpillUsesAfterCoroBegin(Function &F,
2395667dfe39SXun Li const FrameDataInfo &FrameData,
23962e4c5d1cSArnold Schwaighofer CoroBeginInst *CoroBegin) {
23972e4c5d1cSArnold Schwaighofer DominatorTree Dom(F);
23982e4c5d1cSArnold Schwaighofer
23992e4c5d1cSArnold Schwaighofer SmallSetVector<Instruction *, 32> ToMove;
24002e4c5d1cSArnold Schwaighofer SmallVector<Instruction *, 32> Worklist;
24012e4c5d1cSArnold Schwaighofer
24022e4c5d1cSArnold Schwaighofer // Collect all users that precede coro.begin.
2403667dfe39SXun Li for (auto *Def : FrameData.getAllDefs()) {
2404667dfe39SXun Li for (User *U : Def->users()) {
24052e4c5d1cSArnold Schwaighofer auto Inst = cast<Instruction>(U);
24062e4c5d1cSArnold Schwaighofer if (Inst->getParent() != CoroBegin->getParent() ||
240743133766SArnold Schwaighofer Dom.dominates(CoroBegin, Inst))
24082e4c5d1cSArnold Schwaighofer continue;
24092e4c5d1cSArnold Schwaighofer if (ToMove.insert(Inst))
24102e4c5d1cSArnold Schwaighofer Worklist.push_back(Inst);
24112e4c5d1cSArnold Schwaighofer }
24122e4c5d1cSArnold Schwaighofer }
24132e4c5d1cSArnold Schwaighofer // Recursively collect users before coro.begin.
24142e4c5d1cSArnold Schwaighofer while (!Worklist.empty()) {
24151238378fSKazu Hirata auto *Def = Worklist.pop_back_val();
24162e4c5d1cSArnold Schwaighofer for (User *U : Def->users()) {
24172e4c5d1cSArnold Schwaighofer auto Inst = cast<Instruction>(U);
24182e4c5d1cSArnold Schwaighofer if (Dom.dominates(CoroBegin, Inst))
24192e4c5d1cSArnold Schwaighofer continue;
24202e4c5d1cSArnold Schwaighofer if (ToMove.insert(Inst))
24212e4c5d1cSArnold Schwaighofer Worklist.push_back(Inst);
24222e4c5d1cSArnold Schwaighofer }
24232e4c5d1cSArnold Schwaighofer }
24242e4c5d1cSArnold Schwaighofer
24252e4c5d1cSArnold Schwaighofer // Sort by dominance.
24262e4c5d1cSArnold Schwaighofer SmallVector<Instruction *, 64> InsertionList(ToMove.begin(), ToMove.end());
24279bcc0d10SKazu Hirata llvm::sort(InsertionList, [&Dom](Instruction *A, Instruction *B) -> bool {
24282e4c5d1cSArnold Schwaighofer // If a dominates b it should preceed (<) b.
24292e4c5d1cSArnold Schwaighofer return Dom.dominates(A, B);
24302e4c5d1cSArnold Schwaighofer });
24312e4c5d1cSArnold Schwaighofer
24322e4c5d1cSArnold Schwaighofer Instruction *InsertPt = CoroBegin->getNextNode();
24332e4c5d1cSArnold Schwaighofer for (Instruction *Inst : InsertionList)
24342e4c5d1cSArnold Schwaighofer Inst->moveBefore(InsertPt);
24352e4c5d1cSArnold Schwaighofer }
24362e4c5d1cSArnold Schwaighofer
2437f0bfad2eSJun Ma /// For each local variable that all of its user are only used inside one of
2438f0bfad2eSJun Ma /// suspended region, we sink their lifetime.start markers to the place where
2439f0bfad2eSJun Ma /// after the suspend block. Doing so minimizes the lifetime of each variable,
2440f0bfad2eSJun Ma /// hence minimizing the amount of data we end up putting on the frame.
sinkLifetimeStartMarkers(Function & F,coro::Shape & Shape,SuspendCrossingInfo & Checker)2441f0bfad2eSJun Ma static void sinkLifetimeStartMarkers(Function &F, coro::Shape &Shape,
2442f0bfad2eSJun Ma SuspendCrossingInfo &Checker) {
2443f0bfad2eSJun Ma DominatorTree DT(F);
2444f0bfad2eSJun Ma
2445f0bfad2eSJun Ma // Collect all possible basic blocks which may dominate all uses of allocas.
2446f0bfad2eSJun Ma SmallPtrSet<BasicBlock *, 4> DomSet;
2447f0bfad2eSJun Ma DomSet.insert(&F.getEntryBlock());
2448f0bfad2eSJun Ma for (auto *CSI : Shape.CoroSuspends) {
2449f0bfad2eSJun Ma BasicBlock *SuspendBlock = CSI->getParent();
2450f0bfad2eSJun Ma assert(isSuspendBlock(SuspendBlock) && SuspendBlock->getSingleSuccessor() &&
2451f0bfad2eSJun Ma "should have split coro.suspend into its own block");
2452f0bfad2eSJun Ma DomSet.insert(SuspendBlock->getSingleSuccessor());
2453f0bfad2eSJun Ma }
2454f0bfad2eSJun Ma
2455f0bfad2eSJun Ma for (Instruction &I : instructions(F)) {
245692f1f1e4SChuanqi Xu AllocaInst* AI = dyn_cast<AllocaInst>(&I);
245792f1f1e4SChuanqi Xu if (!AI)
2458f0bfad2eSJun Ma continue;
2459f0bfad2eSJun Ma
2460f0bfad2eSJun Ma for (BasicBlock *DomBB : DomSet) {
2461f0bfad2eSJun Ma bool Valid = true;
246292f1f1e4SChuanqi Xu SmallVector<Instruction *, 1> Lifetimes;
2463f0bfad2eSJun Ma
246492f1f1e4SChuanqi Xu auto isLifetimeStart = [](Instruction* I) {
246592f1f1e4SChuanqi Xu if (auto* II = dyn_cast<IntrinsicInst>(I))
246692f1f1e4SChuanqi Xu return II->getIntrinsicID() == Intrinsic::lifetime_start;
2467f0bfad2eSJun Ma return false;
2468f0bfad2eSJun Ma };
2469f0bfad2eSJun Ma
247092f1f1e4SChuanqi Xu auto collectLifetimeStart = [&](Instruction *U, AllocaInst *AI) {
247192f1f1e4SChuanqi Xu if (isLifetimeStart(U)) {
247292f1f1e4SChuanqi Xu Lifetimes.push_back(U);
247392f1f1e4SChuanqi Xu return true;
247492f1f1e4SChuanqi Xu }
247592f1f1e4SChuanqi Xu if (!U->hasOneUse() || U->stripPointerCasts() != AI)
247692f1f1e4SChuanqi Xu return false;
247792f1f1e4SChuanqi Xu if (isLifetimeStart(U->user_back())) {
247892f1f1e4SChuanqi Xu Lifetimes.push_back(U->user_back());
247992f1f1e4SChuanqi Xu return true;
248092f1f1e4SChuanqi Xu }
248192f1f1e4SChuanqi Xu return false;
248292f1f1e4SChuanqi Xu };
248392f1f1e4SChuanqi Xu
248492f1f1e4SChuanqi Xu for (User *U : AI->users()) {
2485f0bfad2eSJun Ma Instruction *UI = cast<Instruction>(U);
2486f0bfad2eSJun Ma // For all users except lifetime.start markers, if they are all
2487f0bfad2eSJun Ma // dominated by one of the basic blocks and do not cross
2488f0bfad2eSJun Ma // suspend points as well, then there is no need to spill the
2489f0bfad2eSJun Ma // instruction.
2490f0bfad2eSJun Ma if (!DT.dominates(DomBB, UI->getParent()) ||
249192f1f1e4SChuanqi Xu Checker.isDefinitionAcrossSuspend(DomBB, UI)) {
249292f1f1e4SChuanqi Xu // Skip lifetime.start, GEP and bitcast used by lifetime.start
249392f1f1e4SChuanqi Xu // markers.
249492f1f1e4SChuanqi Xu if (collectLifetimeStart(UI, AI))
2495f0bfad2eSJun Ma continue;
2496f0bfad2eSJun Ma Valid = false;
2497f0bfad2eSJun Ma break;
2498f0bfad2eSJun Ma }
2499f0bfad2eSJun Ma }
2500f0bfad2eSJun Ma // Sink lifetime.start markers to dominate block when they are
2501f0bfad2eSJun Ma // only used outside the region.
250292f1f1e4SChuanqi Xu if (Valid && Lifetimes.size() != 0) {
250392f1f1e4SChuanqi Xu // May be AI itself, when the type of AI is i8*
250492f1f1e4SChuanqi Xu auto *NewBitCast = [&](AllocaInst *AI) -> Value* {
250592f1f1e4SChuanqi Xu if (isa<AllocaInst>(Lifetimes[0]->getOperand(1)))
250692f1f1e4SChuanqi Xu return AI;
250792f1f1e4SChuanqi Xu auto *Int8PtrTy = Type::getInt8PtrTy(F.getContext());
250892f1f1e4SChuanqi Xu return CastInst::Create(Instruction::BitCast, AI, Int8PtrTy, "",
250992f1f1e4SChuanqi Xu DomBB->getTerminator());
251092f1f1e4SChuanqi Xu }(AI);
251192f1f1e4SChuanqi Xu
251292f1f1e4SChuanqi Xu auto *NewLifetime = Lifetimes[0]->clone();
251392f1f1e4SChuanqi Xu NewLifetime->replaceUsesOfWith(NewLifetime->getOperand(1), NewBitCast);
2514f0bfad2eSJun Ma NewLifetime->insertBefore(DomBB->getTerminator());
2515f0bfad2eSJun Ma
2516f0bfad2eSJun Ma // All the outsided lifetime.start markers are no longer necessary.
251792f1f1e4SChuanqi Xu for (Instruction *S : Lifetimes)
251892f1f1e4SChuanqi Xu S->eraseFromParent();
251992f1f1e4SChuanqi Xu
2520f0bfad2eSJun Ma break;
2521f0bfad2eSJun Ma }
2522f0bfad2eSJun Ma }
2523f0bfad2eSJun Ma }
2524f0bfad2eSJun Ma }
2525f0bfad2eSJun Ma
collectFrameAllocas(Function & F,coro::Shape & Shape,const SuspendCrossingInfo & Checker,SmallVectorImpl<AllocaInfo> & Allocas)2526667dfe39SXun Li static void collectFrameAllocas(Function &F, coro::Shape &Shape,
25279f5a2beaSXun Li const SuspendCrossingInfo &Checker,
25289f5a2beaSXun Li SmallVectorImpl<AllocaInfo> &Allocas) {
2529667dfe39SXun Li for (Instruction &I : instructions(F)) {
2530667dfe39SXun Li auto *AI = dyn_cast<AllocaInst>(&I);
2531667dfe39SXun Li if (!AI)
2532667dfe39SXun Li continue;
2533667dfe39SXun Li // The PromiseAlloca will be specially handled since it needs to be in a
2534667dfe39SXun Li // fixed position in the frame.
2535667dfe39SXun Li if (AI == Shape.SwitchLowering.PromiseAlloca) {
2536667dfe39SXun Li continue;
2537667dfe39SXun Li }
25389f5a2beaSXun Li DominatorTree DT(F);
25397c0e0668SArnold Schwaighofer // The code that uses lifetime.start intrinsic does not work for functions
25407c0e0668SArnold Schwaighofer // with loops without exit. Disable it on ABIs we know to generate such
25417c0e0668SArnold Schwaighofer // code.
25427c0e0668SArnold Schwaighofer bool ShouldUseLifetimeStartInfo =
25437c0e0668SArnold Schwaighofer (Shape.ABI != coro::ABI::Async && Shape.ABI != coro::ABI::Retcon &&
25447c0e0668SArnold Schwaighofer Shape.ABI != coro::ABI::RetconOnce);
25459f5a2beaSXun Li AllocaUseVisitor Visitor{F.getParent()->getDataLayout(), DT,
25467c0e0668SArnold Schwaighofer *Shape.CoroBegin, Checker,
25477c0e0668SArnold Schwaighofer ShouldUseLifetimeStartInfo};
25489f5a2beaSXun Li Visitor.visitPtr(*AI);
25499f5a2beaSXun Li if (!Visitor.getShouldLiveOnFrame())
25509f5a2beaSXun Li continue;
25519f5a2beaSXun Li Allocas.emplace_back(AI, Visitor.getAliasesCopy(),
25529f5a2beaSXun Li Visitor.getMayWriteBeforeCoroBegin());
2553667dfe39SXun Li }
2554667dfe39SXun Li }
2555667dfe39SXun Li
salvageDebugInfo(SmallDenseMap<llvm::Value *,llvm::AllocaInst *,4> & DbgPtrAllocaCache,DbgVariableIntrinsic * DVI,bool OptimizeFrame)25560554541bSAdrian Prantl void coro::salvageDebugInfo(
25570554541bSAdrian Prantl SmallDenseMap<llvm::Value *, llvm::AllocaInst *, 4> &DbgPtrAllocaCache,
255824e53b01SChuanqi Xu DbgVariableIntrinsic *DVI, bool OptimizeFrame) {
2559c1359ef0SChuanqi Xu Function *F = DVI->getFunction();
25600554541bSAdrian Prantl IRBuilder<> Builder(F->getContext());
25610554541bSAdrian Prantl auto InsertPt = F->getEntryBlock().getFirstInsertionPt();
25620554541bSAdrian Prantl while (isa<IntrinsicInst>(InsertPt))
25630554541bSAdrian Prantl ++InsertPt;
25640554541bSAdrian Prantl Builder.SetInsertPoint(&F->getEntryBlock(), InsertPt);
2565c1359ef0SChuanqi Xu DIExpression *Expr = DVI->getExpression();
25660554541bSAdrian Prantl // Follow the pointer arithmetic all the way to the incoming
25670554541bSAdrian Prantl // function argument and convert into a DIExpression.
256812de296dSAdrian Prantl bool SkipOutermostLoad = !isa<DbgValueInst>(DVI);
2569c1359ef0SChuanqi Xu Value *Storage = DVI->getVariableLocationOp(0);
2570e5d958c4Sgbtozers Value *OriginalStorage = Storage;
2571733d7cf9SChuanqi Xu
25728ae5e0b1SAdrian Prantl while (auto *Inst = dyn_cast_or_null<Instruction>(Storage)) {
2573a353edb8SAdrian Prantl if (auto *LdInst = dyn_cast<LoadInst>(Inst)) {
25740554541bSAdrian Prantl Storage = LdInst->getOperand(0);
257562140d94SAdrian Prantl // FIXME: This is a heuristic that works around the fact that
257662140d94SAdrian Prantl // LLVM IR debug intrinsics cannot yet distinguish between
257762140d94SAdrian Prantl // memory and value locations: Because a dbg.declare(alloca) is
257862140d94SAdrian Prantl // implicitly a memory location no DW_OP_deref operation for the
257962140d94SAdrian Prantl // last direct load from an alloca is necessary. This condition
258062140d94SAdrian Prantl // effectively drops the *last* DW_OP_deref in the expression.
258112de296dSAdrian Prantl if (!SkipOutermostLoad)
258262140d94SAdrian Prantl Expr = DIExpression::prepend(Expr, DIExpression::DerefBefore);
2583a353edb8SAdrian Prantl } else if (auto *StInst = dyn_cast<StoreInst>(Inst)) {
25840554541bSAdrian Prantl Storage = StInst->getOperand(0);
2585a353edb8SAdrian Prantl } else {
2586d6b68801SAdrian Prantl SmallVector<uint64_t, 16> Ops;
2587d6b68801SAdrian Prantl SmallVector<Value *, 0> AdditionalValues;
2588a353edb8SAdrian Prantl Value *Op = llvm::salvageDebugInfoImpl(
2589a353edb8SAdrian Prantl *Inst, Expr ? Expr->getNumLocationOperands() : 0, Ops,
2590d6b68801SAdrian Prantl AdditionalValues);
2591a353edb8SAdrian Prantl if (!Op || !AdditionalValues.empty()) {
2592a353edb8SAdrian Prantl // If salvaging failed or salvaging produced more than one location
2593a353edb8SAdrian Prantl // operand, give up.
25940554541bSAdrian Prantl break;
25950554541bSAdrian Prantl }
2596a353edb8SAdrian Prantl Storage = Op;
2597a353edb8SAdrian Prantl Expr = DIExpression::appendOpsToArg(Expr, Ops, 0, /*StackValue*/ false);
2598a353edb8SAdrian Prantl }
259912de296dSAdrian Prantl SkipOutermostLoad = false;
2600a353edb8SAdrian Prantl }
26018ae5e0b1SAdrian Prantl if (!Storage)
26028ae5e0b1SAdrian Prantl return;
260316931808SAdrian Prantl
26040554541bSAdrian Prantl // Store a pointer to the coroutine frame object in an alloca so it
26050554541bSAdrian Prantl // is available throughout the function when producing unoptimized
26060554541bSAdrian Prantl // code. Extending the lifetime this way is correct because the
26070554541bSAdrian Prantl // variable has been declared by a dbg.declare intrinsic.
2608eb51dd71SChuanqi Xu //
2609eb51dd71SChuanqi Xu // Avoid to create the alloca would be eliminated by optimization
2610eb51dd71SChuanqi Xu // passes and the corresponding dbg.declares would be invalid.
261124e53b01SChuanqi Xu if (!OptimizeFrame)
2612eb51dd71SChuanqi Xu if (auto *Arg = dyn_cast<llvm::Argument>(Storage)) {
26130554541bSAdrian Prantl auto &Cached = DbgPtrAllocaCache[Storage];
26140554541bSAdrian Prantl if (!Cached) {
26150554541bSAdrian Prantl Cached = Builder.CreateAlloca(Storage->getType(), 0, nullptr,
26160554541bSAdrian Prantl Arg->getName() + ".debug");
26170554541bSAdrian Prantl Builder.CreateStore(Storage, Cached);
26180554541bSAdrian Prantl }
26190554541bSAdrian Prantl Storage = Cached;
262062140d94SAdrian Prantl // FIXME: LLVM lacks nuanced semantics to differentiate between
262162140d94SAdrian Prantl // memory and direct locations at the IR level. The backend will
262262140d94SAdrian Prantl // turn a dbg.declare(alloca, ..., DIExpression()) into a memory
262362140d94SAdrian Prantl // location. Thus, if there are deref and offset operations in the
262462140d94SAdrian Prantl // expression, we need to add a DW_OP_deref at the *start* of the
262562140d94SAdrian Prantl // expression to first load the contents of the alloca before
262662140d94SAdrian Prantl // adjusting it with the expression.
26270554541bSAdrian Prantl Expr = DIExpression::prepend(Expr, DIExpression::DerefBefore);
262862140d94SAdrian Prantl }
2629c1359ef0SChuanqi Xu
2630c1359ef0SChuanqi Xu DVI->replaceVariableLocationOp(OriginalStorage, Storage);
2631c1359ef0SChuanqi Xu DVI->setExpression(Expr);
263219279ffcSMichael Gottesman // We only hoist dbg.declare today since it doesn't make sense to hoist
263319279ffcSMichael Gottesman // dbg.value or dbg.addr since they do not have the same function wide
263419279ffcSMichael Gottesman // guarantees that dbg.declare does.
263519279ffcSMichael Gottesman if (!isa<DbgValueInst>(DVI) && !isa<DbgAddrIntrinsic>(DVI)) {
263684980761SChuanqi Xu if (auto *II = dyn_cast<InvokeInst>(Storage))
263784980761SChuanqi Xu DVI->moveBefore(II->getNormalDest()->getFirstNonPHI());
26382ae50118SChuanqi Xu else if (auto *CBI = dyn_cast<CallBrInst>(Storage))
26392ae50118SChuanqi Xu DVI->moveBefore(CBI->getDefaultDest()->getFirstNonPHI());
264084980761SChuanqi Xu else if (auto *InsertPt = dyn_cast<Instruction>(Storage)) {
264184980761SChuanqi Xu assert(!InsertPt->isTerminator() &&
264284980761SChuanqi Xu "Unimaged terminator that could return a storage.");
2643c1359ef0SChuanqi Xu DVI->moveAfter(InsertPt);
264484980761SChuanqi Xu } else if (isa<Argument>(Storage))
2645c1359ef0SChuanqi Xu DVI->moveAfter(F->getEntryBlock().getFirstNonPHI());
2646c1359ef0SChuanqi Xu }
26470554541bSAdrian Prantl }
26480554541bSAdrian Prantl
buildCoroutineFrame(Function & F,Shape & Shape)264974309fa0SGor Nishanov void coro::buildCoroutineFrame(Function &F, Shape &Shape) {
2650627cfd43SArnold Schwaighofer // Don't eliminate swifterror in async functions that won't be split.
2651627cfd43SArnold Schwaighofer if (Shape.ABI != coro::ABI::Async || !Shape.CoroSuspends.empty())
26522133feecSJohn McCall eliminateSwiftError(F, Shape);
26532133feecSJohn McCall
265494010b2bSJohn McCall if (Shape.ABI == coro::ABI::Switch &&
265594010b2bSJohn McCall Shape.SwitchLowering.PromiseAlloca) {
265694010b2bSJohn McCall Shape.getSwitchCoroId()->clearPromise();
265750d7fb97SGor Nishanov }
2658241b041fSGor Nishanov
2659a263a60aSGor Nishanov // Make sure that all coro.save, coro.suspend and the fallthrough coro.end
2660a263a60aSGor Nishanov // intrinsics are in their own blocks to simplify the logic of building up
2661a263a60aSGor Nishanov // SuspendCrossing data.
266294010b2bSJohn McCall for (auto *CSI : Shape.CoroSuspends) {
266394010b2bSJohn McCall if (auto *Save = CSI->getCoroSave())
266494010b2bSJohn McCall splitAround(Save, "CoroSave");
2665a263a60aSGor Nishanov splitAround(CSI, "CoroSuspend");
2666a263a60aSGor Nishanov }
2667241b041fSGor Nishanov
26681f72d757SGor Nishanov // Put CoroEnds into their own blocks.
2669333108e8SArnold Schwaighofer for (AnyCoroEndInst *CE : Shape.CoroEnds) {
26701f72d757SGor Nishanov splitAround(CE, "CoroEnd");
2671241b041fSGor Nishanov
2672333108e8SArnold Schwaighofer // Emit the musttail call function in a new block before the CoroEnd.
2673333108e8SArnold Schwaighofer // We do this here so that the right suspend crossing info is computed for
2674333108e8SArnold Schwaighofer // the uses of the musttail call function call. (Arguments to the coro.end
2675333108e8SArnold Schwaighofer // instructions would be ignored)
2676333108e8SArnold Schwaighofer if (auto *AsyncEnd = dyn_cast<CoroAsyncEndInst>(CE)) {
2677333108e8SArnold Schwaighofer auto *MustTailCallFn = AsyncEnd->getMustTailCallFunction();
2678333108e8SArnold Schwaighofer if (!MustTailCallFn)
2679333108e8SArnold Schwaighofer continue;
2680333108e8SArnold Schwaighofer IRBuilder<> Builder(AsyncEnd);
2681333108e8SArnold Schwaighofer SmallVector<Value *, 8> Args(AsyncEnd->args());
2682333108e8SArnold Schwaighofer auto Arguments = ArrayRef<Value *>(Args).drop_front(3);
2683333108e8SArnold Schwaighofer auto *Call = createMustTailCall(AsyncEnd->getDebugLoc(), MustTailCallFn,
2684333108e8SArnold Schwaighofer Arguments, Builder);
2685333108e8SArnold Schwaighofer splitAround(Call, "MustTailCall.Before.CoroEnd");
2686333108e8SArnold Schwaighofer }
2687333108e8SArnold Schwaighofer }
2688333108e8SArnold Schwaighofer
2689846a530eSArnold Schwaighofer // Later code makes structural assumptions about single predecessors phis e.g
2690846a530eSArnold Schwaighofer // that they are not live accross a suspend point.
2691846a530eSArnold Schwaighofer cleanupSinglePredPHIs(F);
2692846a530eSArnold Schwaighofer
2693241b041fSGor Nishanov // Transforms multi-edge PHI Nodes, so that any value feeding into a PHI will
2694241b041fSGor Nishanov // never has its definition separated from the PHI by the suspend point.
2695241b041fSGor Nishanov rewritePHIs(F);
2696241b041fSGor Nishanov
2697241b041fSGor Nishanov // Build suspend crossing info.
2698241b041fSGor Nishanov SuspendCrossingInfo Checker(F, Shape);
2699241b041fSGor Nishanov
2700241b041fSGor Nishanov IRBuilder<> Builder(F.getContext());
2701667dfe39SXun Li FrameDataInfo FrameData;
270262a5dde0SJohn McCall SmallVector<CoroAllocaAllocInst*, 4> LocalAllocas;
270362a5dde0SJohn McCall SmallVector<Instruction*, 4> DeadInstructions;
2704241b041fSGor Nishanov
2705667dfe39SXun Li {
2706667dfe39SXun Li SpillInfo Spills;
27071fbc01f7SGor Nishanov for (int Repeat = 0; Repeat < 4; ++Repeat) {
2708241b041fSGor Nishanov // See if there are materializable instructions across suspend points.
2709241b041fSGor Nishanov for (Instruction &I : instructions(F))
2710c1359ef0SChuanqi Xu if (materializable(I)) {
2711241b041fSGor Nishanov for (User *U : I.users())
2712241b041fSGor Nishanov if (Checker.isDefinitionAcrossSuspend(I, U))
2713667dfe39SXun Li Spills[&I].push_back(cast<Instruction>(U));
2714c1359ef0SChuanqi Xu }
2715c1359ef0SChuanqi Xu
27161f72d757SGor Nishanov if (Spills.empty())
27171f72d757SGor Nishanov break;
27181f72d757SGor Nishanov
2719667dfe39SXun Li // Rewrite materializable instructions to be materialized at the use
2720667dfe39SXun Li // point.
2721667dfe39SXun Li LLVM_DEBUG(dumpSpills("Materializations", Spills));
2722241b041fSGor Nishanov rewriteMaterializableInstructions(Builder, Spills);
27231f72d757SGor Nishanov Spills.clear();
27241f72d757SGor Nishanov }
2725667dfe39SXun Li }
2726241b041fSGor Nishanov
272764ba9dd9SArnold Schwaighofer if (Shape.ABI != coro::ABI::Async && Shape.ABI != coro::ABI::Retcon &&
272864ba9dd9SArnold Schwaighofer Shape.ABI != coro::ABI::RetconOnce)
2729f0bfad2eSJun Ma sinkLifetimeStartMarkers(F, Shape, Checker);
273064ba9dd9SArnold Schwaighofer
2731627cfd43SArnold Schwaighofer if (Shape.ABI != coro::ABI::Async || !Shape.CoroSuspends.empty())
2732667dfe39SXun Li collectFrameAllocas(F, Shape, Checker, FrameData.Allocas);
2733667dfe39SXun Li LLVM_DEBUG(dumpAllocas(FrameData.Allocas));
2734a44de12aSJun Ma
2735241b041fSGor Nishanov // Collect the spills for arguments and other not-materializable values.
273645707d4dSReid Kleckner for (Argument &A : F.args())
2737241b041fSGor Nishanov for (User *U : A.users())
2738241b041fSGor Nishanov if (Checker.isDefinitionAcrossSuspend(A, U))
2739667dfe39SXun Li FrameData.Spills[&A].push_back(cast<Instruction>(U));
2740241b041fSGor Nishanov
2741241b041fSGor Nishanov for (Instruction &I : instructions(F)) {
2742a263a60aSGor Nishanov // Values returned from coroutine structure intrinsics should not be part
2743a263a60aSGor Nishanov // of the Coroutine Frame.
27442f55b958SGor Nishanov if (isCoroutineStructureIntrinsic(I) || &I == Shape.CoroBegin)
2745dce9b026SGor Nishanov continue;
274662a5dde0SJohn McCall
274750d7fb97SGor Nishanov // The Coroutine Promise always included into coroutine frame, no need to
274850d7fb97SGor Nishanov // check for suspend crossing.
274994010b2bSJohn McCall if (Shape.ABI == coro::ABI::Switch &&
275094010b2bSJohn McCall Shape.SwitchLowering.PromiseAlloca == &I)
275150d7fb97SGor Nishanov continue;
2752241b041fSGor Nishanov
275362a5dde0SJohn McCall // Handle alloca.alloc specially here.
275462a5dde0SJohn McCall if (auto AI = dyn_cast<CoroAllocaAllocInst>(&I)) {
275562a5dde0SJohn McCall // Check whether the alloca's lifetime is bounded by suspend points.
275662a5dde0SJohn McCall if (isLocalAlloca(AI)) {
275762a5dde0SJohn McCall LocalAllocas.push_back(AI);
275862a5dde0SJohn McCall continue;
275962a5dde0SJohn McCall }
276062a5dde0SJohn McCall
276162a5dde0SJohn McCall // If not, do a quick rewrite of the alloca and then add spills of
276262a5dde0SJohn McCall // the rewritten value. The rewrite doesn't invalidate anything in
276362a5dde0SJohn McCall // Spills because the other alloca intrinsics have no other operands
276462a5dde0SJohn McCall // besides AI, and it doesn't invalidate the iteration because we delay
276562a5dde0SJohn McCall // erasing AI.
276662a5dde0SJohn McCall auto Alloc = lowerNonLocalAlloca(AI, Shape, DeadInstructions);
276762a5dde0SJohn McCall
276862a5dde0SJohn McCall for (User *U : Alloc->users()) {
276962a5dde0SJohn McCall if (Checker.isDefinitionAcrossSuspend(*Alloc, U))
2770667dfe39SXun Li FrameData.Spills[Alloc].push_back(cast<Instruction>(U));
277162a5dde0SJohn McCall }
277262a5dde0SJohn McCall continue;
277362a5dde0SJohn McCall }
277462a5dde0SJohn McCall
2775ac404832SJohn McCall // Ignore alloca.get; we process this as part of coro.alloca.alloc.
2776667dfe39SXun Li if (isa<CoroAllocaGetInst>(I))
2777ac404832SJohn McCall continue;
2778ac404832SJohn McCall
2779667dfe39SXun Li if (isa<AllocaInst>(I))
2780667dfe39SXun Li continue;
2781a44de12aSJun Ma
2782667dfe39SXun Li for (User *U : I.users())
2783667dfe39SXun Li if (Checker.isDefinitionAcrossSuspend(I, U)) {
2784241b041fSGor Nishanov // We cannot spill a token.
2785241b041fSGor Nishanov if (I.getType()->isTokenTy())
2786241b041fSGor Nishanov report_fatal_error(
2787241b041fSGor Nishanov "token definition is separated from the use by a suspend point");
2788667dfe39SXun Li FrameData.Spills[&I].push_back(cast<Instruction>(U));
2789241b041fSGor Nishanov }
2790241b041fSGor Nishanov }
2791c1359ef0SChuanqi Xu
2792c1359ef0SChuanqi Xu // We don't want the layout of coroutine frame to be affected
2793c1359ef0SChuanqi Xu // by debug information. So we only choose to salvage DbgValueInst for
2794c1359ef0SChuanqi Xu // whose value is already in the frame.
2795c1359ef0SChuanqi Xu // We would handle the dbg.values for allocas specially
2796c1359ef0SChuanqi Xu for (auto &Iter : FrameData.Spills) {
2797c1359ef0SChuanqi Xu auto *V = Iter.first;
2798c1359ef0SChuanqi Xu SmallVector<DbgValueInst *, 16> DVIs;
2799c1359ef0SChuanqi Xu findDbgValues(DVIs, V);
28003b9707dbSKazu Hirata for (DbgValueInst *DVI : DVIs)
2801c1359ef0SChuanqi Xu if (Checker.isDefinitionAcrossSuspend(*V, DVI))
2802c1359ef0SChuanqi Xu FrameData.Spills[V].push_back(DVI);
2803c1359ef0SChuanqi Xu }
2804c1359ef0SChuanqi Xu
2805667dfe39SXun Li LLVM_DEBUG(dumpSpills("Spills", FrameData.Spills));
2806ea5989b4SArnold Schwaighofer if (Shape.ABI == coro::ABI::Retcon || Shape.ABI == coro::ABI::RetconOnce ||
2807ea5989b4SArnold Schwaighofer Shape.ABI == coro::ABI::Async)
2808667dfe39SXun Li sinkSpillUsesAfterCoroBegin(F, FrameData, Shape.CoroBegin);
2809667dfe39SXun Li Shape.FrameTy = buildFrameType(F, Shape, FrameData);
28106e5b8f48SChuanqi Xu createFramePtr(Shape);
28116e5b8f48SChuanqi Xu // For now, this works for C++ programs only.
28126e5b8f48SChuanqi Xu buildFrameDebugInfo(F, Shape, FrameData);
28136e5b8f48SChuanqi Xu insertSpills(FrameData, Shape);
2814ac404832SJohn McCall lowerLocalAllocas(LocalAllocas, DeadInstructions);
281562a5dde0SJohn McCall
281662a5dde0SJohn McCall for (auto I : DeadInstructions)
281762a5dde0SJohn McCall I->eraseFromParent();
281874309fa0SGor Nishanov }
2819