/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Transforms/Coroutines/CoroCleanup.cpp
Line | Count | Source |
1 | | //===- CoroCleanup.cpp - Coroutine Cleanup Pass ---------------------------===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | // This pass lowers all remaining coroutine intrinsics. |
9 | | //===----------------------------------------------------------------------===// |
10 | | |
11 | | #include "CoroInternal.h" |
12 | | #include "llvm/IR/IRBuilder.h" |
13 | | #include "llvm/IR/InstIterator.h" |
14 | | #include "llvm/IR/LegacyPassManager.h" |
15 | | #include "llvm/Pass.h" |
16 | | #include "llvm/Transforms/Scalar.h" |
17 | | |
18 | | using namespace llvm; |
19 | | |
20 | | #define DEBUG_TYPE "coro-cleanup" |
21 | | |
22 | | namespace { |
23 | | // Created on demand if CoroCleanup pass has work to do. |
24 | | struct Lowerer : coro::LowererBase { |
25 | | IRBuilder<> Builder; |
26 | 11 | Lowerer(Module &M) : LowererBase(M), Builder(Context) {} |
27 | | bool lowerRemainingCoroIntrinsics(Function &F); |
28 | | }; |
29 | | } |
30 | | |
31 | 18 | static void simplifyCFG(Function &F) { |
32 | 18 | llvm::legacy::FunctionPassManager FPM(F.getParent()); |
33 | 18 | FPM.add(createCFGSimplificationPass()); |
34 | 18 | |
35 | 18 | FPM.doInitialization(); |
36 | 18 | FPM.run(F); |
37 | 18 | FPM.doFinalization(); |
38 | 18 | } |
39 | | |
40 | 2 | static void lowerSubFn(IRBuilder<> &Builder, CoroSubFnInst *SubFn) { |
41 | 2 | Builder.SetInsertPoint(SubFn); |
42 | 2 | Value *FrameRaw = SubFn->getFrame(); |
43 | 2 | int Index = SubFn->getIndex(); |
44 | 2 | |
45 | 2 | auto *FrameTy = StructType::get( |
46 | 2 | SubFn->getContext(), {Builder.getInt8PtrTy(), Builder.getInt8PtrTy()}); |
47 | 2 | PointerType *FramePtrTy = FrameTy->getPointerTo(); |
48 | 2 | |
49 | 2 | Builder.SetInsertPoint(SubFn); |
50 | 2 | auto *FramePtr = Builder.CreateBitCast(FrameRaw, FramePtrTy); |
51 | 2 | auto *Gep = Builder.CreateConstInBoundsGEP2_32(FrameTy, FramePtr, 0, Index); |
52 | 2 | auto *Load = Builder.CreateLoad(FrameTy->getElementType(Index), Gep); |
53 | 2 | |
54 | 2 | SubFn->replaceAllUsesWith(Load); |
55 | 2 | } |
56 | | |
57 | 59 | bool Lowerer::lowerRemainingCoroIntrinsics(Function &F) { |
58 | 59 | bool Changed = false; |
59 | 59 | |
60 | 1.01k | for (auto IB = inst_begin(F), E = inst_end(F); IB != E;) { |
61 | 958 | Instruction &I = *IB++; |
62 | 958 | if (auto *II = dyn_cast<IntrinsicInst>(&I)) { |
63 | 47 | switch (II->getIntrinsicID()) { |
64 | 47 | default: |
65 | 5 | continue; |
66 | 47 | case Intrinsic::coro_begin: |
67 | 17 | II->replaceAllUsesWith(II->getArgOperand(1)); |
68 | 17 | break; |
69 | 47 | case Intrinsic::coro_free: |
70 | 1 | II->replaceAllUsesWith(II->getArgOperand(1)); |
71 | 1 | break; |
72 | 47 | case Intrinsic::coro_alloc: |
73 | 5 | II->replaceAllUsesWith(ConstantInt::getTrue(Context)); |
74 | 5 | break; |
75 | 47 | case Intrinsic::coro_id: |
76 | 17 | II->replaceAllUsesWith(ConstantTokenNone::get(Context)); |
77 | 17 | break; |
78 | 47 | case Intrinsic::coro_subfn_addr: |
79 | 2 | lowerSubFn(Builder, cast<CoroSubFnInst>(II)); |
80 | 2 | break; |
81 | 42 | } |
82 | 42 | II->eraseFromParent(); |
83 | 42 | Changed = true; |
84 | 42 | } |
85 | 958 | } |
86 | 59 | |
87 | 59 | if (Changed) { |
88 | 18 | // After replacement were made we can cleanup the function body a little. |
89 | 18 | simplifyCFG(F); |
90 | 18 | } |
91 | 59 | return Changed; |
92 | 59 | } |
93 | | |
94 | | //===----------------------------------------------------------------------===// |
95 | | // Top Level Driver |
96 | | //===----------------------------------------------------------------------===// |
97 | | |
98 | | namespace { |
99 | | |
100 | | struct CoroCleanup : FunctionPass { |
101 | | static char ID; // Pass identification, replacement for typeid |
102 | | |
103 | 37 | CoroCleanup() : FunctionPass(ID) { |
104 | 37 | initializeCoroCleanupPass(*PassRegistry::getPassRegistry()); |
105 | 37 | } |
106 | | |
107 | | std::unique_ptr<Lowerer> L; |
108 | | |
109 | | // This pass has work to do only if we find intrinsics we are going to lower |
110 | | // in the module. |
111 | 37 | bool doInitialization(Module &M) override { |
112 | 37 | if (coro::declaresIntrinsics(M, {"llvm.coro.alloc", "llvm.coro.begin", |
113 | 37 | "llvm.coro.subfn.addr", "llvm.coro.free", |
114 | 37 | "llvm.coro.id"})) |
115 | 11 | L = llvm::make_unique<Lowerer>(M); |
116 | 37 | return false; |
117 | 37 | } |
118 | | |
119 | 198 | bool runOnFunction(Function &F) override { |
120 | 198 | if (L) |
121 | 59 | return L->lowerRemainingCoroIntrinsics(F); |
122 | 139 | return false; |
123 | 139 | } |
124 | 37 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
125 | 37 | if (!L) |
126 | 37 | AU.setPreservesAll(); |
127 | 37 | } |
128 | 198 | StringRef getPassName() const override { return "Coroutine Cleanup"; } |
129 | | }; |
130 | | } |
131 | | |
132 | | char CoroCleanup::ID = 0; |
133 | | INITIALIZE_PASS(CoroCleanup, "coro-cleanup", |
134 | | "Lower all coroutine related intrinsics", false, false) |
135 | | |
136 | 36 | Pass *llvm::createCoroCleanupPass() { return new CoroCleanup(); } |