Skip to content

Commit ccabaca

Browse files
committedSep 5, 2016
[Coroutines] Part12: Handle alloca address-taken
Summary: Move early uses of spilled variables after CoroBegin. For example, if a parameter had address taken, we may end up with the code like: define @f(i32 %n) { %n.addr = alloca i32 store %n, %n.addr ... call @coro.begin This patch fixes the problem by moving uses of spilled variables after CoroBegin. Reviewers: majnemer Subscribers: mehdi_amini, llvm-commits Differential Revision: https://reviews.llvm.org/D24234 llvm-svn: 280678
1 parent eea2ef7 commit ccabaca

File tree

2 files changed

+113
-1
lines changed

2 files changed

+113
-1
lines changed
 

‎llvm/lib/Transforms/Coroutines/CoroFrame.cpp

+46-1
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,51 @@ static void rewriteMaterializableInstructions(IRBuilder<> &IRB,
560560
}
561561
}
562562

563+
// Move early uses of spilled variable after CoroBegin.
564+
// For example, if a parameter had address taken, we may end up with the code
565+
// like:
566+
// define @f(i32 %n) {
567+
// %n.addr = alloca i32
568+
// store %n, %n.addr
569+
// ...
570+
// call @coro.begin
571+
// we need to move the store after coro.begin
572+
static void moveSpillUsesAfterCoroBegin(Function &F, SpillInfo const &Spills,
573+
CoroBeginInst *CoroBegin) {
574+
DominatorTree DT(F);
575+
SmallVector<Instruction *, 8> NeedsMoving;
576+
577+
Value *CurrentValue = nullptr;
578+
579+
for (auto const &E : Spills) {
580+
if (CurrentValue == E.def())
581+
continue;
582+
583+
CurrentValue = E.def();
584+
585+
for (User *U : CurrentValue->users()) {
586+
Instruction *I = cast<Instruction>(U);
587+
if (!DT.dominates(CoroBegin, I)) {
588+
// TODO: Make this more robust. Currently if we run into a situation
589+
// where simple instruction move won't work we panic and
590+
// report_fatal_error.
591+
for (User *UI : I->users()) {
592+
if (!DT.dominates(CoroBegin, cast<Instruction>(UI)))
593+
report_fatal_error("cannot move instruction since its users are not"
594+
" dominated by CoroBegin");
595+
}
596+
597+
DEBUG(dbgs() << "will move: " << *I << "\n");
598+
NeedsMoving.push_back(I);
599+
}
600+
}
601+
}
602+
603+
Instruction *InsertPt = CoroBegin->getNextNode();
604+
for (Instruction *I : NeedsMoving)
605+
I->moveBefore(InsertPt);
606+
}
607+
563608
// Splits the block at a particular instruction unless it is the first
564609
// instruction in the block with a single predecessor.
565610
static BasicBlock *splitBlockIfNotFirst(Instruction *I, const Twine &Name) {
@@ -656,7 +701,7 @@ void coro::buildCoroutineFrame(Function &F, Shape &Shape) {
656701
}
657702
std::sort(Spills.begin(), Spills.end());
658703
DEBUG(dump("Spills", Spills));
659-
704+
moveSpillUsesAfterCoroBegin(F, Spills, Shape.CoroBegin);
660705
Shape.FrameTy = buildFrameType(F, Shape, Spills);
661706
Shape.FramePtr = insertSpills(Spills, Shape);
662707
}
+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
; Need to move users of allocas that were moved into the coroutine frame after
2+
; coro.begin.
3+
; RUN: opt < %s -O2 -enable-coroutines -S | FileCheck %s
4+
5+
define nonnull i8* @f(i32 %n) {
6+
entry:
7+
%id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null);
8+
%n.addr = alloca i32
9+
store i32 %n, i32* %n.addr ; this needs to go after coro.begin
10+
%0 = tail call i32 @llvm.coro.size.i32()
11+
%call = tail call i8* @malloc(i32 %0)
12+
%1 = tail call noalias nonnull i8* @llvm.coro.begin(token %id, i8* %call)
13+
%2 = bitcast i32* %n.addr to i8*
14+
call void @ctor(i8* %2)
15+
br label %for.cond
16+
17+
for.cond:
18+
%3 = load i32, i32* %n.addr
19+
%dec = add nsw i32 %3, -1
20+
store i32 %dec, i32* %n.addr
21+
call void @print(i32 %3)
22+
%4 = call i8 @llvm.coro.suspend(token none, i1 false)
23+
%conv = sext i8 %4 to i32
24+
switch i32 %conv, label %coro_Suspend [
25+
i32 0, label %for.cond
26+
i32 1, label %coro_Cleanup
27+
]
28+
29+
coro_Cleanup:
30+
%5 = call i8* @llvm.coro.free(token %id, i8* nonnull %1)
31+
call void @free(i8* %5)
32+
br label %coro_Suspend
33+
34+
coro_Suspend:
35+
call void @llvm.coro.end(i8* null, i1 false)
36+
ret i8* %1
37+
}
38+
39+
; CHECK-LABEL: @main
40+
define i32 @main() {
41+
entry:
42+
%hdl = call i8* @f(i32 4)
43+
call void @llvm.coro.resume(i8* %hdl)
44+
call void @llvm.coro.resume(i8* %hdl)
45+
call void @llvm.coro.destroy(i8* %hdl)
46+
ret i32 0
47+
; CHECK: call void @ctor
48+
; CHECK-NEXT: call void @print(i32 4)
49+
; CHECK-NEXT: call void @print(i32 3)
50+
; CHECK-NEXT: call void @print(i32 2)
51+
; CHECK: ret i32 0
52+
}
53+
54+
declare i8* @malloc(i32)
55+
declare void @free(i8*)
56+
declare void @print(i32)
57+
declare void @ctor(i8* nocapture readonly)
58+
59+
declare token @llvm.coro.id(i32, i8*, i8*, i8*)
60+
declare i32 @llvm.coro.size.i32()
61+
declare i8* @llvm.coro.begin(token, i8*)
62+
declare i8 @llvm.coro.suspend(token, i1)
63+
declare i8* @llvm.coro.free(token, i8*)
64+
declare void @llvm.coro.end(i8*, i1)
65+
66+
declare void @llvm.coro.resume(i8*)
67+
declare void @llvm.coro.destroy(i8*)

0 commit comments

Comments
 (0)