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