Skip to content

Commit 69ecaf6

Browse files
committed
[Coro] Distinguish frame allocation functions.
Doing so enables implementations to allocate extra space in a header.
1 parent eee6f1c commit 69ecaf6

File tree

10 files changed

+242
-57
lines changed

10 files changed

+242
-57
lines changed

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1771,7 +1771,7 @@ def int_coro_id_retcon_once : Intrinsic<[llvm_token_ty],
17711771
[]>;
17721772
def int_coro_id_retcon_once_dynamic : Intrinsic<[llvm_token_ty],
17731773
[llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty, llvm_ptr_ty, llvm_ptr_ty,
1774-
llvm_ptr_ty, llvm_ptr_ty, llvm_ptr_ty],
1774+
llvm_ptr_ty, llvm_ptr_ty, llvm_ptr_ty, llvm_ptr_ty, llvm_ptr_ty],
17751775
[]>;
17761776
def int_coro_alloc : Intrinsic<[llvm_i1_ty], [llvm_token_ty], []>;
17771777
def int_coro_id_async : Intrinsic<[llvm_token_ty],
@@ -1818,8 +1818,11 @@ def int_coro_prepare_retcon : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty],
18181818
[IntrNoMem]>;
18191819
def int_coro_alloca_alloc : Intrinsic<[llvm_token_ty],
18201820
[llvm_anyint_ty, llvm_i32_ty], []>;
1821+
def int_coro_alloca_alloc_frame : Intrinsic<[llvm_token_ty],
1822+
[llvm_anyint_ty, llvm_i32_ty], []>;
18211823
def int_coro_alloca_get : Intrinsic<[llvm_ptr_ty], [llvm_token_ty], []>;
18221824
def int_coro_alloca_free : Intrinsic<[], [llvm_token_ty], []>;
1825+
def int_coro_alloca_free_frame : Intrinsic<[], [llvm_token_ty], []>;
18231826

18241827
// Coroutine Manipulation Intrinsics.
18251828

llvm/include/llvm/Transforms/Coroutines/CoroInstr.h

Lines changed: 73 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,9 @@ class LLVM_LIBRARY_VISIBILITY CoroIdRetconOnceDynamicInst
327327
StorageArg,
328328
PrototypeArg,
329329
AllocArg,
330-
DeallocArg
330+
DeallocArg,
331+
AllocFrameArg,
332+
DeallocFrameArg,
331333
};
332334

333335
public:
@@ -371,6 +373,16 @@ class LLVM_LIBRARY_VISIBILITY CoroIdRetconOnceDynamicInst
371373
return cast<Function>(getArgOperand(DeallocArg)->stripPointerCasts());
372374
}
373375

376+
/// Return the function to use for allocating memory.
377+
Function *getAllocFrameFunction() const {
378+
return cast<Function>(getArgOperand(AllocFrameArg)->stripPointerCasts());
379+
}
380+
381+
/// Return the function to use for deallocating memory.
382+
Function *getDeallocFrameFunction() const {
383+
return cast<Function>(getArgOperand(DeallocFrameArg)->stripPointerCasts());
384+
}
385+
374386
Value *getAllocator() const { return getArgOperand(AllocatorArg); }
375387

376388
// Methods to support type inquiry through isa, cast, and dyn_cast:
@@ -822,8 +834,7 @@ class CoroAsyncEndInst : public AnyCoroEndInst {
822834
}
823835
};
824836

825-
/// This represents the llvm.coro.alloca.alloc instruction.
826-
class CoroAllocaAllocInst : public IntrinsicInst {
837+
class AnyCoroAllocaAllocInst : public IntrinsicInst {
827838
enum { SizeArg, AlignArg };
828839

829840
public:
@@ -832,6 +843,21 @@ class CoroAllocaAllocInst : public IntrinsicInst {
832843
return cast<ConstantInt>(getArgOperand(AlignArg))->getAlignValue();
833844
}
834845

846+
// Methods to support type inquiry through isa, cast, and dyn_cast:
847+
static bool classof(const IntrinsicInst *I) {
848+
auto ID = I->getIntrinsicID();
849+
return ID == Intrinsic::coro_alloca_alloc ||
850+
ID == Intrinsic::coro_alloca_alloc_frame;
851+
}
852+
853+
static bool classof(const Value *V) {
854+
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
855+
}
856+
};
857+
858+
/// This represents the llvm.coro.alloca.alloc instruction.
859+
class CoroAllocaAllocInst : public AnyCoroAllocaAllocInst {
860+
public:
835861
// Methods to support type inquiry through isa, cast, and dyn_cast:
836862
static bool classof(const IntrinsicInst *I) {
837863
return I->getIntrinsicID() == Intrinsic::coro_alloca_alloc;
@@ -841,13 +867,25 @@ class CoroAllocaAllocInst : public IntrinsicInst {
841867
}
842868
};
843869

870+
/// This represents the llvm.coro.alloca.alloc.frame instruction.
871+
class CoroAllocaAllocFrameInst : public AnyCoroAllocaAllocInst {
872+
public:
873+
// Methods to support type inquiry through isa, cast, and dyn_cast:
874+
static bool classof(const IntrinsicInst *I) {
875+
return I->getIntrinsicID() == Intrinsic::coro_alloca_alloc_frame;
876+
}
877+
static bool classof(const Value *V) {
878+
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
879+
}
880+
};
881+
844882
/// This represents the llvm.coro.alloca.get instruction.
845883
class CoroAllocaGetInst : public IntrinsicInst {
846884
enum { AllocArg };
847885

848886
public:
849-
CoroAllocaAllocInst *getAlloc() const {
850-
return cast<CoroAllocaAllocInst>(getArgOperand(AllocArg));
887+
AnyCoroAllocaAllocInst *getAlloc() const {
888+
return cast<AnyCoroAllocaAllocInst>(getArgOperand(AllocArg));
851889
}
852890

853891
// Methods to support type inquiry through isa, cast, and dyn_cast:
@@ -859,15 +897,29 @@ class CoroAllocaGetInst : public IntrinsicInst {
859897
}
860898
};
861899

862-
/// This represents the llvm.coro.alloca.free instruction.
863-
class CoroAllocaFreeInst : public IntrinsicInst {
900+
class AnyCoroAllocaFreeInst : public IntrinsicInst {
864901
enum { AllocArg };
865902

866903
public:
867-
CoroAllocaAllocInst *getAlloc() const {
868-
return cast<CoroAllocaAllocInst>(getArgOperand(AllocArg));
904+
AnyCoroAllocaAllocInst *getAlloc() const {
905+
return cast<AnyCoroAllocaAllocInst>(getArgOperand(AllocArg));
869906
}
870907

908+
// Methods to support type inquiry through isa, cast, and dyn_cast:
909+
static bool classof(const IntrinsicInst *I) {
910+
auto ID = I->getIntrinsicID();
911+
return ID == Intrinsic::coro_alloca_free ||
912+
ID == Intrinsic::coro_alloca_free_frame;
913+
}
914+
915+
static bool classof(const Value *V) {
916+
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
917+
}
918+
};
919+
920+
/// This represents the llvm.coro.alloca.free instruction.
921+
class CoroAllocaFreeInst : public IntrinsicInst {
922+
public:
871923
// Methods to support type inquiry through isa, cast, and dyn_cast:
872924
static bool classof(const IntrinsicInst *I) {
873925
return I->getIntrinsicID() == Intrinsic::coro_alloca_free;
@@ -877,6 +929,18 @@ class CoroAllocaFreeInst : public IntrinsicInst {
877929
}
878930
};
879931

932+
/// This represents the llvm.coro.alloca.free instruction.
933+
class CoroAllocaFreeFrameInst : public IntrinsicInst {
934+
public:
935+
// Methods to support type inquiry through isa, cast, and dyn_cast:
936+
static bool classof(const IntrinsicInst *I) {
937+
return I->getIntrinsicID() == Intrinsic::coro_alloca_free_frame;
938+
}
939+
static bool classof(const Value *V) {
940+
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
941+
}
942+
};
943+
880944
} // End namespace llvm.
881945

882946
#endif // LLVM_TRANSFORMS_COROUTINES_COROINSTR_H

llvm/include/llvm/Transforms/Coroutines/CoroShape.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,9 @@ struct Shape {
135135
struct RetconLoweringStorage {
136136
Function *ResumePrototype;
137137
Function *Alloc;
138+
Function *AllocFrame;
138139
Function *Dealloc;
140+
Function *DeallocFrame;
139141
Value *Allocator;
140142
BasicBlock *ReturnBlock;
141143
bool IsFrameInlineInStorage;
@@ -278,13 +280,13 @@ struct Shape {
278280
///
279281
/// \param CG - if non-null, will be updated for the new call
280282
LLVM_ABI Value *emitAlloc(IRBuilder<> &Builder, Value *Size,
281-
CallGraph *CG) const;
283+
AnyCoroAllocaAllocInst *AI, CallGraph *CG) const;
282284

283285
/// Deallocate memory according to the rules of the active lowering.
284286
///
285287
/// \param CG - if non-null, will be updated for the new call
286288
LLVM_ABI void emitDealloc(IRBuilder<> &Builder, Value *Ptr,
287-
CallGraph *CG) const;
289+
AnyCoroAllocaAllocInst *AI, CallGraph *CG) const;
288290

289291
Shape() = delete;
290292
explicit Shape(Function &F) {

llvm/include/llvm/Transforms/Coroutines/SpillUtils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ void collectSpillsFromArgs(SpillInfo &Spills, Function &F,
3535
void collectSpillsAndAllocasFromInsts(
3636
SpillInfo &Spills, SmallVector<AllocaInfo, 8> &Allocas,
3737
SmallVector<Instruction *, 4> &DeadInstructions,
38-
SmallVector<CoroAllocaAllocInst *, 4> &LocalAllocas, Function &F,
38+
SmallVector<AnyCoroAllocaAllocInst *, 4> &LocalAllocas, Function &F,
3939
const SuspendCrossingInfo &Checker, const DominatorTree &DT,
4040
const coro::Shape &Shape);
4141
void collectSpillsFromDbgInfo(SpillInfo &Spills, Function &F,

llvm/lib/Transforms/Coroutines/CoroFrame.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1598,12 +1598,12 @@ static bool willLeaveFunctionImmediatelyAfter(BasicBlock *BB,
15981598
return true;
15991599
}
16001600

1601-
static bool localAllocaNeedsStackSave(CoroAllocaAllocInst *AI) {
1601+
static bool localAllocaNeedsStackSave(AnyCoroAllocaAllocInst *AI) {
16021602
// Look for a free that isn't sufficiently obviously followed by
16031603
// either a suspend or a termination, i.e. something that will leave
16041604
// the coro resumption frame.
16051605
for (auto *U : AI->users()) {
1606-
auto FI = dyn_cast<CoroAllocaFreeInst>(U);
1606+
auto FI = dyn_cast<AnyCoroAllocaFreeInst>(U);
16071607
if (!FI) continue;
16081608

16091609
if (!willLeaveFunctionImmediatelyAfter(FI->getParent()))
@@ -1616,8 +1616,8 @@ static bool localAllocaNeedsStackSave(CoroAllocaAllocInst *AI) {
16161616

16171617
/// Turn each of the given local allocas into a normal (dynamic) alloca
16181618
/// instruction.
1619-
static void lowerLocalAllocas(ArrayRef<CoroAllocaAllocInst*> LocalAllocas,
1620-
SmallVectorImpl<Instruction*> &DeadInsts) {
1619+
static void lowerLocalAllocas(ArrayRef<AnyCoroAllocaAllocInst *> LocalAllocas,
1620+
SmallVectorImpl<Instruction *> &DeadInsts) {
16211621
for (auto *AI : LocalAllocas) {
16221622
IRBuilder<> Builder(AI);
16231623

@@ -1640,7 +1640,7 @@ static void lowerLocalAllocas(ArrayRef<CoroAllocaAllocInst*> LocalAllocas,
16401640
// alloca.alloc is required to obey a stack discipline, although we
16411641
// don't enforce that structurally.
16421642
} else {
1643-
auto FI = cast<CoroAllocaFreeInst>(U);
1643+
auto FI = cast<AnyCoroAllocaFreeInst>(U);
16441644
if (StackSave) {
16451645
Builder.SetInsertPoint(FI);
16461646
Builder.CreateStackRestore(StackSave);
@@ -2146,7 +2146,7 @@ void coro::BaseABI::buildCoroutineFrame(bool OptimizeFrame) {
21462146
// Collect the spills for arguments and other not-materializable values.
21472147
coro::collectSpillsFromArgs(Spills, F, Checker);
21482148
SmallVector<Instruction *, 4> DeadInstructions;
2149-
SmallVector<CoroAllocaAllocInst *, 4> LocalAllocas;
2149+
SmallVector<AnyCoroAllocaAllocInst *, 4> LocalAllocas;
21502150
coro::collectSpillsAndAllocasFromInsts(Spills, Allocas, DeadInstructions,
21512151
LocalAllocas, F, Checker, DT, Shape);
21522152
coro::collectSpillsFromDbgInfo(Spills, F, Checker);

llvm/lib/Transforms/Coroutines/CoroSplit.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ static void maybeFreeRetconStorage(IRBuilder<> &Builder,
163163
if (Shape.RetconLowering.IsFrameInlineInStorage)
164164
return;
165165

166-
Shape.emitDealloc(Builder, FramePtr, CG);
166+
Shape.emitDealloc(Builder, FramePtr, nullptr, CG);
167167
}
168168

169169
/// Replace an llvm.coro.end.async.
@@ -1903,7 +1903,8 @@ void coro::AnyRetconABI::splitCoroutine(Function &F, coro::Shape &Shape,
19031903
// Allocate. We don't need to update the call graph node because we're
19041904
// going to recompute it from scratch after splitting.
19051905
// FIXME: pass the required alignment
1906-
RawFramePtr = Shape.emitAlloc(Builder, Builder.getInt64(Size), nullptr);
1906+
RawFramePtr =
1907+
Shape.emitAlloc(Builder, Builder.getInt64(Size), nullptr, nullptr);
19071908
RawFramePtr =
19081909
Builder.CreateBitCast(RawFramePtr, Shape.CoroBegin->getType());
19091910

llvm/lib/Transforms/Coroutines/Coroutines.cpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,9 @@ void coro::Shape::analyze(Function &F,
325325
auto Prototype = ContinuationId->getPrototype();
326326
RetconLowering.ResumePrototype = Prototype;
327327
RetconLowering.Alloc = ContinuationId->getAllocFunction();
328+
RetconLowering.AllocFrame = ContinuationId->getAllocFrameFunction();
328329
RetconLowering.Dealloc = ContinuationId->getDeallocFunction();
330+
RetconLowering.DeallocFrame = ContinuationId->getDeallocFrameFunction();
329331
RetconLowering.Storage = ContinuationId->getStorage();
330332
RetconLowering.Allocator = ContinuationId->getAllocator();
331333
RetconLowering.ReturnBlock = nullptr;
@@ -523,7 +525,7 @@ static void addCallToCallGraph(CallGraph *CG, CallInst *Call, Function *Callee){
523525
}
524526

525527
Value *coro::Shape::emitAlloc(IRBuilder<> &Builder, Value *Size,
526-
CallGraph *CG) const {
528+
AnyCoroAllocaAllocInst *AI, CallGraph *CG) const {
527529
switch (ABI) {
528530
case coro::ABI::Switch:
529531
llvm_unreachable("can't allocate memory in coro switch-lowering");
@@ -537,7 +539,13 @@ Value *coro::Shape::emitAlloc(IRBuilder<> &Builder, Value *Size,
537539
sizeParamIndex = 1;
538540
Args.push_back(RetconLowering.Allocator);
539541
}
540-
auto Alloc = RetconLowering.Alloc;
542+
Function *Alloc = nullptr;
543+
if (isa_and_nonnull<CoroAllocaAllocFrameInst>(AI)) {
544+
assert(ABI == coro::ABI::RetconOnceDynamic);
545+
Alloc = RetconLowering.AllocFrame;
546+
} else {
547+
Alloc = RetconLowering.Alloc;
548+
}
541549
Size = Builder.CreateIntCast(
542550
Size, Alloc->getFunctionType()->getParamType(sizeParamIndex),
543551
/*is signed*/ false);
@@ -559,15 +567,21 @@ Value *coro::Shape::emitAlloc(IRBuilder<> &Builder, Value *Size,
559567
}
560568

561569
void coro::Shape::emitDealloc(IRBuilder<> &Builder, Value *Ptr,
562-
CallGraph *CG) const {
570+
AnyCoroAllocaAllocInst *AI, CallGraph *CG) const {
563571
switch (ABI) {
564572
case coro::ABI::Switch:
565573
llvm_unreachable("can't allocate memory in coro switch-lowering");
566574

567575
case coro::ABI::Retcon:
568576
case coro::ABI::RetconOnce:
569577
case coro::ABI::RetconOnceDynamic: {
570-
auto Dealloc = RetconLowering.Dealloc;
578+
Function *Dealloc = nullptr;
579+
if (isa_and_nonnull<CoroAllocaAllocFrameInst>(AI)) {
580+
assert(ABI == coro::ABI::RetconOnceDynamic);
581+
Dealloc = RetconLowering.DeallocFrame;
582+
} else {
583+
Dealloc = RetconLowering.Dealloc;
584+
}
571585
SmallVector<Value *, 2> Args;
572586
unsigned allocationParamIndex = 0;
573587
if (ABI == coro::ABI::RetconOnceDynamic) {

llvm/lib/Transforms/Coroutines/SpillUtils.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,12 @@ static bool isSuspendReachableFrom(BasicBlock *From,
5555

5656
/// Is the given alloca "local", i.e. bounded in lifetime to not cross a
5757
/// suspend point?
58-
static bool isLocalAlloca(CoroAllocaAllocInst *AI) {
58+
static bool isLocalAlloca(AnyCoroAllocaAllocInst *AI) {
5959
// Seed the visited set with all the basic blocks containing a free
6060
// so that we won't pass them up.
6161
VisitedBlocksSet VisitedOrFreeBBs;
6262
for (auto *User : AI->users()) {
63-
if (auto FI = dyn_cast<CoroAllocaFreeInst>(User))
63+
if (auto FI = dyn_cast<AnyCoroAllocaFreeInst>(User))
6464
VisitedOrFreeBBs.insert(FI->getParent());
6565
}
6666

@@ -71,18 +71,18 @@ static bool isLocalAlloca(CoroAllocaAllocInst *AI) {
7171
/// This happens during the all-instructions iteration, so it must not
7272
/// delete the call.
7373
static Instruction *
74-
lowerNonLocalAlloca(CoroAllocaAllocInst *AI, const coro::Shape &Shape,
74+
lowerNonLocalAlloca(AnyCoroAllocaAllocInst *AI, const coro::Shape &Shape,
7575
SmallVectorImpl<Instruction *> &DeadInsts) {
7676
IRBuilder<> Builder(AI);
77-
auto Alloc = Shape.emitAlloc(Builder, AI->getSize(), nullptr);
77+
auto Alloc = Shape.emitAlloc(Builder, AI->getSize(), AI, nullptr);
7878

7979
for (User *U : AI->users()) {
8080
if (isa<CoroAllocaGetInst>(U)) {
8181
U->replaceAllUsesWith(Alloc);
8282
} else {
83-
auto FI = cast<CoroAllocaFreeInst>(U);
83+
auto FI = cast<AnyCoroAllocaFreeInst>(U);
8484
Builder.SetInsertPoint(FI);
85-
Shape.emitDealloc(Builder, Alloc, nullptr);
85+
Shape.emitDealloc(Builder, Alloc, AI, nullptr);
8686
}
8787
DeadInsts.push_back(cast<Instruction>(U));
8888
}
@@ -460,7 +460,7 @@ void collectSpillsFromArgs(SpillInfo &Spills, Function &F,
460460
void collectSpillsAndAllocasFromInsts(
461461
SpillInfo &Spills, SmallVector<AllocaInfo, 8> &Allocas,
462462
SmallVector<Instruction *, 4> &DeadInstructions,
463-
SmallVector<CoroAllocaAllocInst *, 4> &LocalAllocas, Function &F,
463+
SmallVector<AnyCoroAllocaAllocInst *, 4> &LocalAllocas, Function &F,
464464
const SuspendCrossingInfo &Checker, const DominatorTree &DT,
465465
const coro::Shape &Shape) {
466466

@@ -471,7 +471,7 @@ void collectSpillsAndAllocasFromInsts(
471471
continue;
472472

473473
// Handle alloca.alloc specially here.
474-
if (auto AI = dyn_cast<CoroAllocaAllocInst>(&I)) {
474+
if (auto AI = dyn_cast<AnyCoroAllocaAllocInst>(&I)) {
475475
// Check whether the alloca's lifetime is bounded by suspend points.
476476
if (isLocalAlloca(AI)) {
477477
LocalAllocas.push_back(AI);

0 commit comments

Comments
 (0)