diff options
Diffstat (limited to 'llvm/lib/Transforms/Coroutines')
| -rw-r--r-- | llvm/lib/Transforms/Coroutines/CoroCleanup.cpp | 81 | ||||
| -rw-r--r-- | llvm/lib/Transforms/Coroutines/CoroConditionalWrapper.cpp | 24 | ||||
| -rw-r--r-- | llvm/lib/Transforms/Coroutines/CoroEarly.cpp | 79 | ||||
| -rw-r--r-- | llvm/lib/Transforms/Coroutines/CoroElide.cpp | 125 | ||||
| -rw-r--r-- | llvm/lib/Transforms/Coroutines/CoroFrame.cpp | 177 | ||||
| -rw-r--r-- | llvm/lib/Transforms/Coroutines/CoroInternal.h | 47 | ||||
| -rw-r--r-- | llvm/lib/Transforms/Coroutines/CoroSplit.cpp | 377 | ||||
| -rw-r--r-- | llvm/lib/Transforms/Coroutines/Coroutines.cpp | 193 | 
8 files changed, 310 insertions, 793 deletions
| diff --git a/llvm/lib/Transforms/Coroutines/CoroCleanup.cpp b/llvm/lib/Transforms/Coroutines/CoroCleanup.cpp index 67f8828e4c75..f7bbdcffd2ec 100644 --- a/llvm/lib/Transforms/Coroutines/CoroCleanup.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroCleanup.cpp @@ -10,9 +10,9 @@  #include "CoroInternal.h"  #include "llvm/IR/IRBuilder.h"  #include "llvm/IR/InstIterator.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/Pass.h" -#include "llvm/Transforms/Scalar.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/Function.h" +#include "llvm/Transforms/Scalar/SimplifyCFG.h"  using namespace llvm; @@ -23,19 +23,10 @@ namespace {  struct Lowerer : coro::LowererBase {    IRBuilder<> Builder;    Lowerer(Module &M) : LowererBase(M), Builder(Context) {} -  bool lowerRemainingCoroIntrinsics(Function &F); +  bool lower(Function &F);  };  } -static void simplifyCFG(Function &F) { -  llvm::legacy::FunctionPassManager FPM(F.getParent()); -  FPM.add(createCFGSimplificationPass()); - -  FPM.doInitialization(); -  FPM.run(F); -  FPM.doFinalization(); -} -  static void lowerSubFn(IRBuilder<> &Builder, CoroSubFnInst *SubFn) {    Builder.SetInsertPoint(SubFn);    Value *FrameRaw = SubFn->getFrame(); @@ -53,12 +44,10 @@ static void lowerSubFn(IRBuilder<> &Builder, CoroSubFnInst *SubFn) {    SubFn->replaceAllUsesWith(Load);  } -bool Lowerer::lowerRemainingCoroIntrinsics(Function &F) { +bool Lowerer::lower(Function &F) { +  bool IsPrivateAndUnprocessed = F.isPresplitCoroutine() && F.hasLocalLinkage();    bool Changed = false; -  bool IsPrivateAndUnprocessed = -      F.hasFnAttribute(CORO_PRESPLIT_ATTR) && F.hasLocalLinkage(); -    for (Instruction &I : llvm::make_early_inc_range(instructions(F))) {      if (auto *II = dyn_cast<IntrinsicInst>(&I)) {        switch (II->getIntrinsicID()) { @@ -116,11 +105,6 @@ bool Lowerer::lowerRemainingCoroIntrinsics(Function &F) {      }    } -  if (Changed) { -    // After replacement were made we can cleanup the function body a little. -    simplifyCFG(F); -  } -    return Changed;  } @@ -132,50 +116,21 @@ static bool declaresCoroCleanupIntrinsics(const Module &M) {            "llvm.coro.async.resume"});  } -PreservedAnalyses CoroCleanupPass::run(Function &F, -                                       FunctionAnalysisManager &AM) { -  auto &M = *F.getParent(); -  if (!declaresCoroCleanupIntrinsics(M) || -      !Lowerer(M).lowerRemainingCoroIntrinsics(F)) +PreservedAnalyses CoroCleanupPass::run(Module &M, +                                       ModuleAnalysisManager &MAM) { +  if (!declaresCoroCleanupIntrinsics(M))      return PreservedAnalyses::all(); -  return PreservedAnalyses::none(); -} - -namespace { - -struct CoroCleanupLegacy : FunctionPass { -  static char ID; // Pass identification, replacement for typeid +  FunctionAnalysisManager &FAM = +      MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); -  CoroCleanupLegacy() : FunctionPass(ID) { -    initializeCoroCleanupLegacyPass(*PassRegistry::getPassRegistry()); -  } +  FunctionPassManager FPM; +  FPM.addPass(SimplifyCFGPass()); -  std::unique_ptr<Lowerer> L; +  Lowerer L(M); +  for (auto &F : M) +    if (L.lower(F)) +      FPM.run(F, FAM); -  // This pass has work to do only if we find intrinsics we are going to lower -  // in the module. -  bool doInitialization(Module &M) override { -    if (declaresCoroCleanupIntrinsics(M)) -      L = std::make_unique<Lowerer>(M); -    return false; -  } - -  bool runOnFunction(Function &F) override { -    if (L) -      return L->lowerRemainingCoroIntrinsics(F); -    return false; -  } -  void getAnalysisUsage(AnalysisUsage &AU) const override { -    if (!L) -      AU.setPreservesAll(); -  } -  StringRef getPassName() const override { return "Coroutine Cleanup"; } -}; +  return PreservedAnalyses::none();  } - -char CoroCleanupLegacy::ID = 0; -INITIALIZE_PASS(CoroCleanupLegacy, "coro-cleanup", -                "Lower all coroutine related intrinsics", false, false) - -Pass *llvm::createCoroCleanupLegacyPass() { return new CoroCleanupLegacy(); } diff --git a/llvm/lib/Transforms/Coroutines/CoroConditionalWrapper.cpp b/llvm/lib/Transforms/Coroutines/CoroConditionalWrapper.cpp new file mode 100644 index 000000000000..3d26a43ceba7 --- /dev/null +++ b/llvm/lib/Transforms/Coroutines/CoroConditionalWrapper.cpp @@ -0,0 +1,24 @@ +//===- CoroConditionalWrapper.cpp -----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Coroutines/CoroConditionalWrapper.h" +#include "CoroInternal.h" +#include "llvm/IR/Module.h" + +using namespace llvm; + +CoroConditionalWrapper::CoroConditionalWrapper(ModulePassManager &&PM) +    : PM(std::move(PM)) {} + +PreservedAnalyses CoroConditionalWrapper::run(Module &M, +                                              ModuleAnalysisManager &AM) { +  if (!coro::declaresAnyIntrinsic(M)) +    return PreservedAnalyses::all(); + +  return PM.run(M, AM); +} diff --git a/llvm/lib/Transforms/Coroutines/CoroEarly.cpp b/llvm/lib/Transforms/Coroutines/CoroEarly.cpp index 1533e1805f17..dd7cb23f3f3d 100644 --- a/llvm/lib/Transforms/Coroutines/CoroEarly.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroEarly.cpp @@ -8,10 +8,10 @@  #include "llvm/Transforms/Coroutines/CoroEarly.h"  #include "CoroInternal.h" +#include "llvm/IR/Function.h"  #include "llvm/IR/IRBuilder.h"  #include "llvm/IR/InstIterator.h"  #include "llvm/IR/Module.h" -#include "llvm/Pass.h"  using namespace llvm; @@ -35,7 +35,7 @@ public:          AnyResumeFnPtrTy(FunctionType::get(Type::getVoidTy(Context), Int8Ptr,                                             /*isVarArg=*/false)                               ->getPointerTo()) {} -  bool lowerEarlyIntrinsics(Function &F); +  void lowerEarlyIntrinsics(Function &F);  };  } @@ -145,14 +145,16 @@ static void setCannotDuplicate(CoroIdInst *CoroId) {        CB->setCannotDuplicate();  } -bool Lowerer::lowerEarlyIntrinsics(Function &F) { -  bool Changed = false; +void Lowerer::lowerEarlyIntrinsics(Function &F) {    CoroIdInst *CoroId = nullptr;    SmallVector<CoroFreeInst *, 4> CoroFrees;    bool HasCoroSuspend = false;    for (Instruction &I : llvm::make_early_inc_range(instructions(F))) { -    if (auto *CB = dyn_cast<CallBase>(&I)) { -      switch (CB->getIntrinsicID()) { +    auto *CB = dyn_cast<CallBase>(&I); +    if (!CB) +      continue; + +    switch (CB->getIntrinsicID()) {        default:          continue;        case Intrinsic::coro_free: @@ -178,12 +180,9 @@ bool Lowerer::lowerEarlyIntrinsics(Function &F) {        case Intrinsic::coro_id:          if (auto *CII = cast<CoroIdInst>(&I)) {            if (CII->getInfo().isPreSplit()) { -            assert(F.hasFnAttribute(CORO_PRESPLIT_ATTR) && -                   F.getFnAttribute(CORO_PRESPLIT_ATTR).getValueAsString() == -                       UNPREPARED_FOR_SPLIT && +            assert(F.isPresplitCoroutine() &&                     "The frontend uses Swtich-Resumed ABI should emit " -                   "\"coroutine.presplit\" attribute with value \"0\" for the " -                   "coroutine."); +                   "\"coroutine.presplit\" attribute for the coroutine.");              setCannotDuplicate(CII);              CII->setCoroutineSelf();              CoroId = cast<CoroIdInst>(&I); @@ -193,9 +192,7 @@ bool Lowerer::lowerEarlyIntrinsics(Function &F) {        case Intrinsic::coro_id_retcon:        case Intrinsic::coro_id_retcon_once:        case Intrinsic::coro_id_async: -        // TODO: Remove the line once we support it in the corresponding -        // frontend. -        F.addFnAttr(CORO_PRESPLIT_ATTR, PREPARED_FOR_SPLIT); +        F.setPresplitCoroutine();          break;        case Intrinsic::coro_resume:          lowerResumeOrDestroy(*CB, CoroSubFnInst::ResumeIndex); @@ -209,16 +206,16 @@ bool Lowerer::lowerEarlyIntrinsics(Function &F) {        case Intrinsic::coro_done:          lowerCoroDone(cast<IntrinsicInst>(&I));          break; -      } -      Changed = true;      }    } +    // Make sure that all CoroFree reference the coro.id intrinsic.    // Token type is not exposed through coroutine C/C++ builtins to plain C, so    // we allow specifying none and fixing it up here.    if (CoroId)      for (CoroFreeInst *CF : CoroFrees)        CF->setArgOperand(0, CoroId); +    // Coroutine suspention could potentially lead to any argument modified    // outside of the function, hence arguments should not have noalias    // attributes. @@ -226,7 +223,6 @@ bool Lowerer::lowerEarlyIntrinsics(Function &F) {      for (Argument &A : F.args())        if (A.hasNoAliasAttr())          A.removeAttr(Attribute::NoAlias); -  return Changed;  }  static bool declaresCoroEarlyIntrinsics(const Module &M) { @@ -238,52 +234,15 @@ static bool declaresCoroEarlyIntrinsics(const Module &M) {            "llvm.coro.suspend"});  } -PreservedAnalyses CoroEarlyPass::run(Function &F, FunctionAnalysisManager &) { -  Module &M = *F.getParent(); -  if (!declaresCoroEarlyIntrinsics(M) || !Lowerer(M).lowerEarlyIntrinsics(F)) +PreservedAnalyses CoroEarlyPass::run(Module &M, ModuleAnalysisManager &) { +  if (!declaresCoroEarlyIntrinsics(M))      return PreservedAnalyses::all(); +  Lowerer L(M); +  for (auto &F : M) +    L.lowerEarlyIntrinsics(F); +    PreservedAnalyses PA;    PA.preserveSet<CFGAnalyses>();    return PA;  } - -namespace { - -struct CoroEarlyLegacy : public FunctionPass { -  static char ID; // Pass identification, replacement for typeid. -  CoroEarlyLegacy() : FunctionPass(ID) { -    initializeCoroEarlyLegacyPass(*PassRegistry::getPassRegistry()); -  } - -  std::unique_ptr<Lowerer> L; - -  // This pass has work to do only if we find intrinsics we are going to lower -  // in the module. -  bool doInitialization(Module &M) override { -    if (declaresCoroEarlyIntrinsics(M)) -      L = std::make_unique<Lowerer>(M); -    return false; -  } - -  bool runOnFunction(Function &F) override { -    if (!L) -      return false; - -    return L->lowerEarlyIntrinsics(F); -  } - -  void getAnalysisUsage(AnalysisUsage &AU) const override { -    AU.setPreservesCFG(); -  } -  StringRef getPassName() const override { -    return "Lower early coroutine intrinsics"; -  } -}; -} - -char CoroEarlyLegacy::ID = 0; -INITIALIZE_PASS(CoroEarlyLegacy, "coro-early", -                "Lower early coroutine intrinsics", false, false) - -Pass *llvm::createCoroEarlyLegacyPass() { return new CoroEarlyLegacy(); } diff --git a/llvm/lib/Transforms/Coroutines/CoroElide.cpp b/llvm/lib/Transforms/Coroutines/CoroElide.cpp index 84bebb7bf42d..6f78fc8db311 100644 --- a/llvm/lib/Transforms/Coroutines/CoroElide.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroElide.cpp @@ -14,8 +14,6 @@  #include "llvm/Analysis/InstructionSimplify.h"  #include "llvm/IR/Dominators.h"  #include "llvm/IR/InstIterator.h" -#include "llvm/InitializePasses.h" -#include "llvm/Pass.h"  #include "llvm/Support/ErrorHandling.h"  #include "llvm/Support/FileSystem.h" @@ -103,21 +101,12 @@ static void removeTailCallAttribute(AllocaInst *Frame, AAResults &AA) {  // Given a resume function @f.resume(%f.frame* %frame), returns the size  // and expected alignment of %f.frame type. -static std::pair<uint64_t, Align> getFrameLayout(Function *Resume) { -  // Prefer to pull information from the function attributes. +static Optional<std::pair<uint64_t, Align>> getFrameLayout(Function *Resume) { +  // Pull information from the function attributes.    auto Size = Resume->getParamDereferenceableBytes(0); -  auto Align = Resume->getParamAlign(0); - -  // If those aren't given, extract them from the type. -  if (Size == 0 || !Align) { -    auto *FrameTy = Resume->arg_begin()->getType()->getPointerElementType(); - -    const DataLayout &DL = Resume->getParent()->getDataLayout(); -    if (!Size) Size = DL.getTypeAllocSize(FrameTy); -    if (!Align) Align = DL.getABITypeAlign(FrameTy); -  } - -  return std::make_pair(Size, *Align); +  if (!Size) +    return None; +  return std::make_pair(Size, Resume->getParamAlign(0).valueOrOne());  }  // Finds first non alloca instruction in the entry block of a function. @@ -347,56 +336,37 @@ bool Lowerer::processCoroId(CoroIdInst *CoroId, AAResults &AA,    assert(Resumers && "PostSplit coro.id Info argument must refer to an array"                       "of coroutine subfunctions");    auto *ResumeAddrConstant = -      ConstantExpr::getExtractValue(Resumers, CoroSubFnInst::ResumeIndex); +      Resumers->getAggregateElement(CoroSubFnInst::ResumeIndex);    replaceWithConstant(ResumeAddrConstant, ResumeAddr);    bool ShouldElide = shouldElide(CoroId->getFunction(), DT); -  auto *DestroyAddrConstant = ConstantExpr::getExtractValue( -      Resumers, +  auto *DestroyAddrConstant = Resumers->getAggregateElement(        ShouldElide ? CoroSubFnInst::CleanupIndex : CoroSubFnInst::DestroyIndex);    for (auto &It : DestroyAddr)      replaceWithConstant(DestroyAddrConstant, It.second);    if (ShouldElide) { -    auto FrameSizeAndAlign = getFrameLayout(cast<Function>(ResumeAddrConstant)); -    elideHeapAllocations(CoroId->getFunction(), FrameSizeAndAlign.first, -                         FrameSizeAndAlign.second, AA); -    coro::replaceCoroFree(CoroId, /*Elide=*/true); -    NumOfCoroElided++; +    if (auto FrameSizeAndAlign = +            getFrameLayout(cast<Function>(ResumeAddrConstant))) { +      elideHeapAllocations(CoroId->getFunction(), FrameSizeAndAlign->first, +                           FrameSizeAndAlign->second, AA); +      coro::replaceCoroFree(CoroId, /*Elide=*/true); +      NumOfCoroElided++;  #ifndef NDEBUG -    if (!CoroElideInfoOutputFilename.empty()) -      *getOrCreateLogFile() -          << "Elide " << CoroId->getCoroutine()->getName() << " in " -          << CoroId->getFunction()->getName() << "\n"; +      if (!CoroElideInfoOutputFilename.empty()) +        *getOrCreateLogFile() +            << "Elide " << CoroId->getCoroutine()->getName() << " in " +            << CoroId->getFunction()->getName() << "\n";  #endif +    }    }    return true;  } -// See if there are any coro.subfn.addr instructions referring to coro.devirt -// trigger, if so, replace them with a direct call to devirt trigger function. -static bool replaceDevirtTrigger(Function &F) { -  SmallVector<CoroSubFnInst *, 1> DevirtAddr; -  for (auto &I : instructions(F)) -    if (auto *SubFn = dyn_cast<CoroSubFnInst>(&I)) -      if (SubFn->getIndex() == CoroSubFnInst::RestartTrigger) -        DevirtAddr.push_back(SubFn); - -  if (DevirtAddr.empty()) -    return false; - -  Module &M = *F.getParent(); -  Function *DevirtFn = M.getFunction(CORO_DEVIRT_TRIGGER_FN); -  assert(DevirtFn && "coro.devirt.fn not found"); -  replaceWithConstant(DevirtFn, DevirtAddr); - -  return true; -} -  static bool declaresCoroElideIntrinsics(Module &M) {    return coro::declaresIntrinsics(M, {"llvm.coro.id", "llvm.coro.id.async"});  } @@ -422,62 +392,3 @@ PreservedAnalyses CoroElidePass::run(Function &F, FunctionAnalysisManager &AM) {    return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();  } - -namespace { -struct CoroElideLegacy : FunctionPass { -  static char ID; -  CoroElideLegacy() : FunctionPass(ID) { -    initializeCoroElideLegacyPass(*PassRegistry::getPassRegistry()); -  } - -  std::unique_ptr<Lowerer> L; - -  bool doInitialization(Module &M) override { -    if (declaresCoroElideIntrinsics(M)) -      L = std::make_unique<Lowerer>(M); -    return false; -  } - -  bool runOnFunction(Function &F) override { -    if (!L) -      return false; - -    bool Changed = false; - -    if (F.hasFnAttribute(CORO_PRESPLIT_ATTR)) -      Changed = replaceDevirtTrigger(F); - -    L->CoroIds.clear(); -    L->collectPostSplitCoroIds(&F); -    // If we did not find any coro.id, there is nothing to do. -    if (L->CoroIds.empty()) -      return Changed; - -    AAResults &AA = getAnalysis<AAResultsWrapperPass>().getAAResults(); -    DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree(); - -    for (auto *CII : L->CoroIds) -      Changed |= L->processCoroId(CII, AA, DT); - -    return Changed; -  } -  void getAnalysisUsage(AnalysisUsage &AU) const override { -    AU.addRequired<AAResultsWrapperPass>(); -    AU.addRequired<DominatorTreeWrapperPass>(); -  } -  StringRef getPassName() const override { return "Coroutine Elision"; } -}; -} - -char CoroElideLegacy::ID = 0; -INITIALIZE_PASS_BEGIN( -    CoroElideLegacy, "coro-elide", -    "Coroutine frame allocation elision and indirect calls replacement", false, -    false) -INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) -INITIALIZE_PASS_END( -    CoroElideLegacy, "coro-elide", -    "Coroutine frame allocation elision and indirect calls replacement", false, -    false) - -Pass *llvm::createCoroElideLegacyPass() { return new CoroElideLegacy(); } diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp index 9c16d3750998..d09607bb1c4c 100644 --- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp @@ -27,7 +27,7 @@  #include "llvm/IR/Dominators.h"  #include "llvm/IR/IRBuilder.h"  #include "llvm/IR/InstIterator.h" -#include "llvm/Support/CommandLine.h" +#include "llvm/IR/IntrinsicInst.h"  #include "llvm/Support/Debug.h"  #include "llvm/Support/MathExtras.h"  #include "llvm/Support/OptimizedStructLayout.h" @@ -44,13 +44,6 @@ using namespace llvm;  // "coro-frame", which results in leaner debug spew.  #define DEBUG_TYPE "coro-suspend-crossing" -static cl::opt<bool> EnableReuseStorageInFrame( -    "reuse-storage-in-coroutine-frame", cl::Hidden, -    cl::desc( -        "Enable the optimization which would reuse the storage in the coroutine \ -         frame for allocas whose liferanges are not overlapped, for testing purposes"), -    llvm::cl::init(false)); -  enum { SmallVectorThreshold = 32 };  // Provides two way mapping between the blocks and numbers. @@ -347,15 +340,26 @@ struct FrameDataInfo {      FieldIndexMap[V] = Index;    } -  uint64_t getAlign(Value *V) const { +  Align getAlign(Value *V) const {      auto Iter = FieldAlignMap.find(V);      assert(Iter != FieldAlignMap.end());      return Iter->second;    } -  void setAlign(Value *V, uint64_t Align) { +  void setAlign(Value *V, Align AL) {      assert(FieldAlignMap.count(V) == 0); -    FieldAlignMap.insert({V, Align}); +    FieldAlignMap.insert({V, AL}); +  } + +  uint64_t getDynamicAlign(Value *V) const { +    auto Iter = FieldDynamicAlignMap.find(V); +    assert(Iter != FieldDynamicAlignMap.end()); +    return Iter->second; +  } + +  void setDynamicAlign(Value *V, uint64_t Align) { +    assert(FieldDynamicAlignMap.count(V) == 0); +    FieldDynamicAlignMap.insert({V, Align});    }    uint64_t getOffset(Value *V) const { @@ -382,7 +386,8 @@ private:    DenseMap<Value *, uint32_t> FieldIndexMap;    // Map from values to their alignment on the frame. They would be set after    // the frame is built. -  DenseMap<Value *, uint64_t> FieldAlignMap; +  DenseMap<Value *, Align> FieldAlignMap; +  DenseMap<Value *, uint64_t> FieldDynamicAlignMap;    // Map from values to their offset on the frame. They would be set after    // the frame is built.    DenseMap<Value *, uint64_t> FieldOffsetMap; @@ -423,6 +428,7 @@ private:      FieldIDType LayoutFieldIndex;      Align Alignment;      Align TyAlignment; +    uint64_t DynamicAlignBuffer;    };    const DataLayout &DL; @@ -489,7 +495,7 @@ public:                            coro::Shape &Shape);    /// Add a field to this structure. -  LLVM_NODISCARD FieldIDType addField(Type *Ty, MaybeAlign FieldAlignment, +  LLVM_NODISCARD FieldIDType addField(Type *Ty, MaybeAlign MaybeFieldAlignment,                                        bool IsHeader = false,                                        bool IsSpillOfValue = false) {      assert(!IsFinished && "adding fields to a finished builder"); @@ -508,13 +514,21 @@ public:      // to remember the type alignment anyway to build the type.      // If we are spilling values we don't need to worry about ABI alignment      // concerns. -    auto ABIAlign = DL.getABITypeAlign(Ty); -    Align TyAlignment = -        (IsSpillOfValue && MaxFrameAlignment) -            ? (*MaxFrameAlignment < ABIAlign ? *MaxFrameAlignment : ABIAlign) -            : ABIAlign; -    if (!FieldAlignment) { -      FieldAlignment = TyAlignment; +    Align ABIAlign = DL.getABITypeAlign(Ty); +    Align TyAlignment = ABIAlign; +    if (IsSpillOfValue && MaxFrameAlignment && *MaxFrameAlignment < ABIAlign) +      TyAlignment = *MaxFrameAlignment; +    Align FieldAlignment = MaybeFieldAlignment.value_or(TyAlignment); + +    // The field alignment could be bigger than the max frame case, in that case +    // we request additional storage to be able to dynamically align the +    // pointer. +    uint64_t DynamicAlignBuffer = 0; +    if (MaxFrameAlignment && (FieldAlignment > *MaxFrameAlignment)) { +      DynamicAlignBuffer = +          offsetToAlignment(MaxFrameAlignment->value(), FieldAlignment); +      FieldAlignment = *MaxFrameAlignment; +      FieldSize = FieldSize + DynamicAlignBuffer;      }      // Lay out header fields immediately. @@ -523,12 +537,13 @@ public:        Offset = alignTo(StructSize, FieldAlignment);        StructSize = Offset + FieldSize; -    // Everything else has a flexible offset. +      // Everything else has a flexible offset.      } else {        Offset = OptimizedStructLayoutField::FlexibleOffset;      } -    Fields.push_back({FieldSize, Offset, Ty, 0, *FieldAlignment, TyAlignment}); +    Fields.push_back({FieldSize, Offset, Ty, 0, FieldAlignment, TyAlignment, +                      DynamicAlignBuffer});      return Fields.size() - 1;    } @@ -561,7 +576,12 @@ void FrameDataInfo::updateLayoutIndex(FrameTypeBuilder &B) {    auto Updater = [&](Value *I) {      auto Field = B.getLayoutField(getFieldIndex(I));      setFieldIndex(I, Field.LayoutFieldIndex); -    setAlign(I, Field.Alignment.value()); +    setAlign(I, Field.Alignment); +    uint64_t dynamicAlign = +        Field.DynamicAlignBuffer +            ? Field.DynamicAlignBuffer + Field.Alignment.value() +            : 0; +    setDynamicAlign(I, dynamicAlign);      setOffset(I, Field.Offset);    };    LayoutIndexUpdateStarted = true; @@ -588,7 +608,7 @@ void FrameTypeBuilder::addFieldForAllocas(const Function &F,      }    }); -  if (!Shape.OptimizeFrame && !EnableReuseStorageInFrame) { +  if (!Shape.OptimizeFrame) {      for (const auto &A : FrameData.Allocas) {        AllocaInst *Alloca = A.Alloca;        NonOverlapedAllocas.emplace_back(AllocaSetType(1, Alloca)); @@ -755,6 +775,10 @@ void FrameTypeBuilder::finish(StructType *Ty) {      F.LayoutFieldIndex = FieldTypes.size();      FieldTypes.push_back(F.Ty); +    if (F.DynamicAlignBuffer) { +      FieldTypes.push_back( +          ArrayType::get(Type::getInt8Ty(Context), F.DynamicAlignBuffer)); +    }      LastOffset = Offset + F.Size;    } @@ -807,9 +831,10 @@ static StringRef solveTypeName(Type *Ty) {      return "__floating_type_";    } -  if (Ty->isPointerTy()) { -    auto *PtrTy = cast<PointerType>(Ty); -    Type *PointeeTy = PtrTy->getPointerElementType(); +  if (auto *PtrTy = dyn_cast<PointerType>(Ty)) { +    if (PtrTy->isOpaque()) +      return "PointerType"; +    Type *PointeeTy = PtrTy->getNonOpaquePointerElementType();      auto Name = solveTypeName(PointeeTy);      if (Name == "UnknownType")        return "PointerType"; @@ -826,10 +851,9 @@ static StringRef solveTypeName(Type *Ty) {      auto Name = Ty->getStructName();      SmallString<16> Buffer(Name); -    for_each(Buffer, [](auto &Iter) { +    for (auto &Iter : Buffer)        if (Iter == '.' || Iter == ':')          Iter = '_'; -    });      auto *MDName = MDString::get(Ty->getContext(), Buffer.str());      return MDName->getString();    } @@ -1012,7 +1036,7 @@ static void buildFrameDebugInfo(Function &F, coro::Shape &Shape,      auto Index = FrameData.getFieldIndex(V);      OffsetCache.insert( -        {Index, {FrameData.getAlign(V), FrameData.getOffset(V)}}); +        {Index, {FrameData.getAlign(V).value(), FrameData.getOffset(V)}});    }    DenseMap<Type *, DIType *> DITypeCache; @@ -1078,7 +1102,7 @@ static void buildFrameDebugInfo(Function &F, coro::Shape &Shape,    DBuilder.insertDeclare(Shape.FramePtr, FrameDIVar,                           DBuilder.createExpression(), DILoc, -                         Shape.FramePtr->getNextNode()); +                         Shape.getInsertPtAfterFramePtr());  }  // Build a struct that will keep state for an active coroutine. @@ -1367,7 +1391,7 @@ struct AllocaUseVisitor : PtrUseVisitor<AllocaUseVisitor> {    bool getShouldLiveOnFrame() const {      if (!ShouldLiveOnFrame)        ShouldLiveOnFrame = computeShouldLiveOnFrame(); -    return ShouldLiveOnFrame.getValue(); +    return *ShouldLiveOnFrame;    }    bool getMayWriteBeforeCoroBegin() const { return MayWriteBeforeCoroBegin; } @@ -1455,7 +1479,7 @@ private:        auto Itr = AliasOffetMap.find(&I);        if (Itr == AliasOffetMap.end()) {          AliasOffetMap[&I] = Offset; -      } else if (Itr->second.hasValue() && Itr->second.getValue() != Offset) { +      } else if (Itr->second && *Itr->second != Offset) {          // If we have seen two different possible values for this alias, we set          // it to empty.          AliasOffetMap[&I].reset(); @@ -1517,13 +1541,12 @@ static void createFramePtr(coro::Shape &Shape) {  //    whatever  //  // -static Instruction *insertSpills(const FrameDataInfo &FrameData, -                                 coro::Shape &Shape) { +static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {    auto *CB = Shape.CoroBegin;    LLVMContext &C = CB->getContext();    IRBuilder<> Builder(C);    StructType *FrameTy = Shape.FrameTy; -  Instruction *FramePtr = Shape.FramePtr; +  Value *FramePtr = Shape.FramePtr;    DominatorTree DT(*CB->getFunction());    SmallDenseMap<llvm::Value *, llvm::AllocaInst *, 4> DbgPtrAllocaCache; @@ -1550,7 +1573,18 @@ static Instruction *insertSpills(const FrameDataInfo &FrameData,      auto GEP = cast<GetElementPtrInst>(          Builder.CreateInBoundsGEP(FrameTy, FramePtr, Indices)); -    if (isa<AllocaInst>(Orig)) { +    if (auto *AI = dyn_cast<AllocaInst>(Orig)) { +      if (FrameData.getDynamicAlign(Orig) != 0) { +        assert(FrameData.getDynamicAlign(Orig) == AI->getAlign().value()); +        auto *M = AI->getModule(); +        auto *IntPtrTy = M->getDataLayout().getIntPtrType(AI->getType()); +        auto *PtrValue = Builder.CreatePtrToInt(GEP, IntPtrTy); +        auto *AlignMask = +            ConstantInt::get(IntPtrTy, AI->getAlign().value() - 1); +        PtrValue = Builder.CreateAdd(PtrValue, AlignMask); +        PtrValue = Builder.CreateAnd(PtrValue, Builder.CreateNot(AlignMask)); +        return Builder.CreateIntToPtr(PtrValue, AI->getType()); +      }        // If the type of GEP is not equal to the type of AllocaInst, it implies        // that the AllocaInst may be reused in the Frame slot of other        // AllocaInst. So We cast GEP to the AllocaInst here to re-use @@ -1571,20 +1605,19 @@ static Instruction *insertSpills(const FrameDataInfo &FrameData,      // Create a store instruction storing the value into the      // coroutine frame.      Instruction *InsertPt = nullptr; -    bool NeedToCopyArgPtrValue = false; +    Type *ByValTy = nullptr;      if (auto *Arg = dyn_cast<Argument>(Def)) {        // For arguments, we will place the store instruction right after        // the coroutine frame pointer instruction, i.e. bitcast of        // coro.begin from i8* to %f.frame*. -      InsertPt = FramePtr->getNextNode(); +      InsertPt = Shape.getInsertPtAfterFramePtr();        // If we're spilling an Argument, make sure we clear 'nocapture'        // from the coroutine function.        Arg->getParent()->removeParamAttr(Arg->getArgNo(), Attribute::NoCapture);        if (Arg->hasByValAttr()) -        NeedToCopyArgPtrValue = true; - +        ByValTy = Arg->getParamByValType();      } else if (auto *CSI = dyn_cast<AnyCoroSuspendInst>(Def)) {        // Don't spill immediately after a suspend; splitting assumes        // that the suspend will be followed by a branch. @@ -1594,7 +1627,7 @@ static Instruction *insertSpills(const FrameDataInfo &FrameData,        if (!DT.dominates(CB, I)) {          // If it is not dominated by CoroBegin, then spill should be          // inserted immediately after CoroFrame is computed. -        InsertPt = FramePtr->getNextNode(); +        InsertPt = Shape.getInsertPtAfterFramePtr();        } else if (auto *II = dyn_cast<InvokeInst>(I)) {          // If we are spilling the result of the invoke instruction, split          // the normal edge and insert the spill in the new block. @@ -1619,11 +1652,10 @@ static Instruction *insertSpills(const FrameDataInfo &FrameData,      Builder.SetInsertPoint(InsertPt);      auto *G = Builder.CreateConstInBoundsGEP2_32(          FrameTy, FramePtr, 0, Index, Def->getName() + Twine(".spill.addr")); -    if (NeedToCopyArgPtrValue) { +    if (ByValTy) {        // For byval arguments, we need to store the pointed value in the frame,        // instead of the pointer itself. -      auto *Value = -          Builder.CreateLoad(Def->getType()->getPointerElementType(), Def); +      auto *Value = Builder.CreateLoad(ByValTy, Def);        Builder.CreateAlignedStore(Value, G, SpillAlignment);      } else {        Builder.CreateAlignedStore(Def, G, SpillAlignment); @@ -1641,7 +1673,7 @@ static Instruction *insertSpills(const FrameDataInfo &FrameData,          auto *GEP = GetFramePointer(E.first);          GEP->setName(E.first->getName() + Twine(".reload.addr")); -        if (NeedToCopyArgPtrValue) +        if (ByValTy)            CurrentReload = GEP;          else            CurrentReload = Builder.CreateAlignedLoad( @@ -1664,6 +1696,12 @@ static Instruction *insertSpills(const FrameDataInfo &FrameData,          }        } +      // Salvage debug info on any dbg.addr that we see. We do not insert them +      // into each block where we have a use though. +      if (auto *DI = dyn_cast<DbgAddrIntrinsic>(U)) { +        coro::salvageDebugInfo(DbgPtrAllocaCache, DI, Shape.OptimizeFrame); +      } +        // If we have a single edge PHINode, remove it and replace it with a        // reload from the coroutine frame. (We already took care of multi edge        // PHINodes by rewriting them in the rewritePHIs function). @@ -1682,10 +1720,10 @@ static Instruction *insertSpills(const FrameDataInfo &FrameData,      }    } -  BasicBlock *FramePtrBB = FramePtr->getParent(); +  BasicBlock *FramePtrBB = Shape.getInsertPtAfterFramePtr()->getParent(); -  auto SpillBlock = -      FramePtrBB->splitBasicBlock(FramePtr->getNextNode(), "AllocaSpillBB"); +  auto SpillBlock = FramePtrBB->splitBasicBlock( +      Shape.getInsertPtAfterFramePtr(), "AllocaSpillBB");    SpillBlock->splitBasicBlock(&SpillBlock->front(), "PostSpill");    Shape.AllocaSpillBlock = SpillBlock; @@ -1704,7 +1742,7 @@ static Instruction *insertSpills(const FrameDataInfo &FrameData,        Alloca->replaceAllUsesWith(G);        Alloca->eraseFromParent();      } -    return FramePtr; +    return;    }    // If we found any alloca, replace all of their remaining uses with GEP @@ -1735,7 +1773,7 @@ static Instruction *insertSpills(const FrameDataInfo &FrameData,      for (Instruction *I : UsersToUpdate)        I->replaceUsesOfWith(Alloca, G);    } -  Builder.SetInsertPoint(FramePtr->getNextNode()); +  Builder.SetInsertPoint(Shape.getInsertPtAfterFramePtr());    for (const auto &A : FrameData.Allocas) {      AllocaInst *Alloca = A.Alloca;      if (A.MayWriteBeforeCoroBegin) { @@ -1755,16 +1793,16 @@ static Instruction *insertSpills(const FrameDataInfo &FrameData,        auto *FramePtr = GetFramePointer(Alloca);        auto *FramePtrRaw =            Builder.CreateBitCast(FramePtr, Type::getInt8PtrTy(C)); -      auto *AliasPtr = Builder.CreateGEP( -          Type::getInt8Ty(C), FramePtrRaw, -          ConstantInt::get(Type::getInt64Ty(C), Alias.second.getValue())); +      auto &Value = *Alias.second; +      auto ITy = IntegerType::get(C, Value.getBitWidth()); +      auto *AliasPtr = Builder.CreateGEP(Type::getInt8Ty(C), FramePtrRaw, +                                         ConstantInt::get(ITy, Value));        auto *AliasPtrTyped =            Builder.CreateBitCast(AliasPtr, Alias.first->getType());        Alias.first->replaceUsesWithIf(            AliasPtrTyped, [&](Use &U) { return DT.dominates(CB, U); });      }    } -  return FramePtr;  }  // Moves the values in the PHIs in SuccBB that correspong to PredBB into a new @@ -2130,7 +2168,7 @@ static void lowerLocalAllocas(ArrayRef<CoroAllocaAllocInst*> LocalAllocas,      // Allocate memory.      auto Alloca = Builder.CreateAlloca(Builder.getInt8Ty(), AI->getSize()); -    Alloca->setAlignment(Align(AI->getAlignment())); +    Alloca->setAlignment(AI->getAlignment());      for (auto U : AI->users()) {        // Replace gets with the allocation. @@ -2279,7 +2317,10 @@ static void eliminateSwiftErrorArgument(Function &F, Argument &Arg,    IRBuilder<> Builder(F.getEntryBlock().getFirstNonPHIOrDbg());    auto ArgTy = cast<PointerType>(Arg.getType()); -  auto ValueTy = ArgTy->getPointerElementType(); +  // swifterror arguments are required to have pointer-to-pointer type, +  // so create a pointer-typed alloca with opaque pointers. +  auto ValueTy = ArgTy->isOpaque() ? PointerType::getUnqual(F.getContext()) +                                   : ArgTy->getNonOpaquePointerElementType();    // Reduce to the alloca case: @@ -2520,6 +2561,7 @@ void coro::salvageDebugInfo(    bool SkipOutermostLoad = !isa<DbgValueInst>(DVI);    Value *Storage = DVI->getVariableLocationOp(0);    Value *OriginalStorage = Storage; +    while (auto *Inst = dyn_cast_or_null<Instruction>(Storage)) {      if (auto *LdInst = dyn_cast<LoadInst>(Inst)) {        Storage = LdInst->getOperand(0); @@ -2559,7 +2601,7 @@ void coro::salvageDebugInfo(    //    // Avoid to create the alloca would be eliminated by optimization    // passes and the corresponding dbg.declares would be invalid. -  if (!OptimizeFrame && !EnableReuseStorageInFrame) +  if (!OptimizeFrame)      if (auto *Arg = dyn_cast<llvm::Argument>(Storage)) {        auto &Cached = DbgPtrAllocaCache[Storage];        if (!Cached) { @@ -2575,14 +2617,15 @@ void coro::salvageDebugInfo(        // expression, we need to add a DW_OP_deref at the *start* of the        // expression to first load the contents of the alloca before        // adjusting it with the expression. -      if (Expr && Expr->isComplex()) -        Expr = DIExpression::prepend(Expr, DIExpression::DerefBefore); +      Expr = DIExpression::prepend(Expr, DIExpression::DerefBefore);      }    DVI->replaceVariableLocationOp(OriginalStorage, Storage);    DVI->setExpression(Expr); -  /// It makes no sense to move the dbg.value intrinsic. -  if (!isa<DbgValueInst>(DVI)) { +  // We only hoist dbg.declare today since it doesn't make sense to hoist +  // dbg.value or dbg.addr since they do not have the same function wide +  // guarantees that dbg.declare does. +  if (!isa<DbgValueInst>(DVI) && !isa<DbgAddrIntrinsic>(DVI)) {      if (auto *II = dyn_cast<InvokeInst>(Storage))        DVI->moveBefore(II->getNormalDest()->getFirstNonPHI());      else if (auto *CBI = dyn_cast<CallBrInst>(Storage)) @@ -2661,13 +2704,6 @@ void coro::buildCoroutineFrame(Function &F, Shape &Shape) {            for (User *U : I.users())              if (Checker.isDefinitionAcrossSuspend(I, U))                Spills[&I].push_back(cast<Instruction>(U)); - -          // Manually add dbg.value metadata uses of I. -          SmallVector<DbgValueInst *, 16> DVIs; -          findDbgValues(DVIs, &I); -          for (auto *DVI : DVIs) -            if (Checker.isDefinitionAcrossSuspend(I, DVI)) -              Spills[&I].push_back(DVI);          }        if (Spills.empty()) @@ -2754,10 +2790,9 @@ void coro::buildCoroutineFrame(Function &F, Shape &Shape) {      auto *V = Iter.first;      SmallVector<DbgValueInst *, 16> DVIs;      findDbgValues(DVIs, V); -    llvm::for_each(DVIs, [&](DbgValueInst *DVI) { +    for (DbgValueInst *DVI : DVIs)        if (Checker.isDefinitionAcrossSuspend(*V, DVI))          FrameData.Spills[V].push_back(DVI); -    });    }    LLVM_DEBUG(dumpSpills("Spills", FrameData.Spills)); diff --git a/llvm/lib/Transforms/Coroutines/CoroInternal.h b/llvm/lib/Transforms/Coroutines/CoroInternal.h index 9a17068df3a9..5557370c82ba 100644 --- a/llvm/lib/Transforms/Coroutines/CoroInternal.h +++ b/llvm/lib/Transforms/Coroutines/CoroInternal.h @@ -13,7 +13,6 @@  #include "CoroInstr.h"  #include "llvm/IR/IRBuilder.h" -#include "llvm/Transforms/Coroutines.h"  namespace llvm { @@ -21,40 +20,13 @@ class CallGraph;  class CallGraphSCC;  class PassRegistry; -void initializeCoroEarlyLegacyPass(PassRegistry &); -void initializeCoroSplitLegacyPass(PassRegistry &); -void initializeCoroElideLegacyPass(PassRegistry &); -void initializeCoroCleanupLegacyPass(PassRegistry &); - -// CoroEarly pass marks every function that has coro.begin with a string -// attribute "coroutine.presplit"="0". CoroSplit pass processes the coroutine -// twice. First, it lets it go through complete IPO optimization pipeline as a -// single function. It forces restart of the pipeline by inserting an indirect -// call to an empty function "coro.devirt.trigger" which is devirtualized by -// CoroElide pass that triggers a restart of the pipeline by CGPassManager. -// When CoroSplit pass sees the same coroutine the second time, it splits it up, -// adds coroutine subfunctions to the SCC to be processed by IPO pipeline. -// Async lowering similarily triggers a restart of the pipeline after it has -// split the coroutine. -// -// FIXME: Refactor these attributes as LLVM attributes instead of string -// attributes since these attributes are already used outside LLVM's -// coroutine module. -// FIXME: Remove these values once we remove the Legacy PM. -#define CORO_PRESPLIT_ATTR "coroutine.presplit" -#define UNPREPARED_FOR_SPLIT "0" -#define PREPARED_FOR_SPLIT "1" -#define ASYNC_RESTART_AFTER_SPLIT "2" - -#define CORO_DEVIRT_TRIGGER_FN "coro.devirt.trigger" -  namespace coro { +bool declaresAnyIntrinsic(const Module &M);  bool declaresIntrinsics(const Module &M,                          const std::initializer_list<StringRef>);  void replaceCoroFree(CoroIdInst *CoroId, bool Elide); -void updateCallGraph(Function &Caller, ArrayRef<Function *> Funcs, -                     CallGraph &CG, CallGraphSCC &SCC); +  /// Recover a dbg.declare prepared by the frontend and emit an alloca  /// holding a pointer to the coroutine frame.  void salvageDebugInfo( @@ -128,7 +100,7 @@ struct LLVM_LIBRARY_VISIBILITY Shape {    StructType *FrameTy;    Align FrameAlign;    uint64_t FrameSize; -  Instruction *FramePtr; +  Value *FramePtr;    BasicBlock *AllocaSpillBlock;    /// This would only be true if optimization are enabled. @@ -210,10 +182,9 @@ struct LLVM_LIBRARY_VISIBILITY Shape {    FunctionType *getResumeFunctionType() const {      switch (ABI) { -    case coro::ABI::Switch: { -      auto *FnPtrTy = getSwitchResumePointerType(); -      return cast<FunctionType>(FnPtrTy->getPointerElementType()); -    } +    case coro::ABI::Switch: +      return FunctionType::get(Type::getVoidTy(FrameTy->getContext()), +                               FrameTy->getPointerTo(), /*IsVarArg*/false);      case coro::ABI::Retcon:      case coro::ABI::RetconOnce:        return RetconLowering.ResumePrototype->getFunctionType(); @@ -267,6 +238,12 @@ struct LLVM_LIBRARY_VISIBILITY Shape {      return nullptr;    } +  Instruction *getInsertPtAfterFramePtr() const { +    if (auto *I = dyn_cast<Instruction>(FramePtr)) +      return I->getNextNode(); +    return &cast<Argument>(FramePtr)->getParent()->getEntryBlock().front(); +  } +    /// Allocate memory according to the rules of the active lowering.    ///    /// \param CG - if non-null, will be updated for the new call diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp index b5129809c6a6..ead552d9be4e 100644 --- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp @@ -22,15 +22,17 @@  #include "CoroInstr.h"  #include "CoroInternal.h"  #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PriorityWorklist.h"  #include "llvm/ADT/SmallPtrSet.h"  #include "llvm/ADT/SmallVector.h"  #include "llvm/ADT/StringRef.h"  #include "llvm/ADT/Twine.h"  #include "llvm/Analysis/CFG.h"  #include "llvm/Analysis/CallGraph.h" -#include "llvm/Analysis/CallGraphSCCPass.h"  #include "llvm/Analysis/ConstantFolding.h"  #include "llvm/Analysis/LazyCallGraph.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/BinaryFormat/Dwarf.h"  #include "llvm/IR/Argument.h"  #include "llvm/IR/Attributes.h"  #include "llvm/IR/BasicBlock.h" @@ -50,13 +52,10 @@  #include "llvm/IR/Instructions.h"  #include "llvm/IR/IntrinsicInst.h"  #include "llvm/IR/LLVMContext.h" -#include "llvm/IR/LegacyPassManager.h"  #include "llvm/IR/Module.h"  #include "llvm/IR/Type.h"  #include "llvm/IR/Value.h"  #include "llvm/IR/Verifier.h" -#include "llvm/InitializePasses.h" -#include "llvm/Pass.h"  #include "llvm/Support/Casting.h"  #include "llvm/Support/Debug.h"  #include "llvm/Support/PrettyStackTrace.h" @@ -869,11 +868,16 @@ void CoroCloner::create() {                                    OrigF.getParent()->end(), ActiveSuspend);    } -  // Replace all args with undefs. The buildCoroutineFrame algorithm already -  // rewritten access to the args that occurs after suspend points with loads -  // and stores to/from the coroutine frame. -  for (Argument &A : OrigF.args()) -    VMap[&A] = UndefValue::get(A.getType()); +  // Replace all args with dummy instructions. If an argument is the old frame +  // pointer, the dummy will be replaced by the new frame pointer once it is +  // computed below. Uses of all other arguments should have already been +  // rewritten by buildCoroutineFrame() to use loads/stores on the coroutine +  // frame. +  SmallVector<Instruction *> DummyArgs; +  for (Argument &A : OrigF.args()) { +    DummyArgs.push_back(new FreezeInst(UndefValue::get(A.getType()))); +    VMap[&A] = DummyArgs.back(); +  }    SmallVector<ReturnInst *, 4> Returns; @@ -923,6 +927,12 @@ void CoroCloner::create() {    NewF->setVisibility(savedVisibility);    NewF->setUnnamedAddr(savedUnnamedAddr);    NewF->setDLLStorageClass(savedDLLStorageClass); +  // The function sanitizer metadata needs to match the signature of the +  // function it is being attached to. However this does not hold for split +  // functions here. Thus remove the metadata for split functions. +  if (Shape.ABI == coro::ABI::Switch && +      NewF->hasMetadata(LLVMContext::MD_func_sanitize)) +    NewF->eraseMetadata(LLVMContext::MD_func_sanitize);    // Replace the attributes of the new function:    auto OrigAttrs = NewF->getAttributes(); @@ -932,7 +942,8 @@ void CoroCloner::create() {    case coro::ABI::Switch:      // Bootstrap attributes by copying function attributes from the      // original function.  This should include optimization settings and so on. -    NewAttrs = NewAttrs.addFnAttributes(Context, AttrBuilder(Context, OrigAttrs.getFnAttrs())); +    NewAttrs = NewAttrs.addFnAttributes( +        Context, AttrBuilder(Context, OrigAttrs.getFnAttrs()));      addFramePointerAttrs(NewAttrs, Context, 0,                           Shape.FrameSize, Shape.FrameAlign); @@ -1013,7 +1024,15 @@ void CoroCloner::create() {    auto *NewVFrame = Builder.CreateBitCast(        NewFramePtr, Type::getInt8PtrTy(Builder.getContext()), "vFrame");    Value *OldVFrame = cast<Value>(VMap[Shape.CoroBegin]); -  OldVFrame->replaceAllUsesWith(NewVFrame); +  if (OldVFrame != NewVFrame) +    OldVFrame->replaceAllUsesWith(NewVFrame); + +  // All uses of the arguments should have been resolved by this point, +  // so we can safely remove the dummy values. +  for (Instruction *DummyArg : DummyArgs) { +    DummyArg->replaceAllUsesWith(UndefValue::get(DummyArg->getType())); +    DummyArg->deleteValue(); +  }    switch (Shape.ABI) {    case coro::ABI::Switch: @@ -1063,13 +1082,6 @@ static Function *createClone(Function &F, const Twine &Suffix,    return Cloner.getFunction();  } -/// Remove calls to llvm.coro.end in the original function. -static void removeCoroEnds(const coro::Shape &Shape, CallGraph *CG) { -  for (auto End : Shape.CoroEnds) { -    replaceCoroEnd(End, Shape, Shape.FramePtr, /*in resume*/ false, CG); -  } -} -  static void updateAsyncFuncPointerContextSize(coro::Shape &Shape) {    assert(Shape.ABI == coro::ABI::Async); @@ -1150,7 +1162,8 @@ static void updateCoroFrame(coro::Shape &Shape, Function *ResumeFn,                              Function *DestroyFn, Function *CleanupFn) {    assert(Shape.ABI == coro::ABI::Switch); -  IRBuilder<> Builder(Shape.FramePtr->getNextNode()); +  IRBuilder<> Builder(Shape.getInsertPtAfterFramePtr()); +    auto *ResumeAddr = Builder.CreateStructGEP(        Shape.FrameTy, Shape.FramePtr, coro::Shape::SwitchFieldIndex::Resume,        "resume.addr"); @@ -1559,7 +1572,8 @@ static void simplifySuspendPoints(coro::Shape &Shape) {  }  static void splitSwitchCoroutine(Function &F, coro::Shape &Shape, -                                 SmallVectorImpl<Function *> &Clones) { +                                 SmallVectorImpl<Function *> &Clones, +                                 TargetTransformInfo &TTI) {    assert(Shape.ABI == coro::ABI::Switch);    createResumeEntryBlock(F, Shape); @@ -1574,7 +1588,13 @@ static void splitSwitchCoroutine(Function &F, coro::Shape &Shape,    postSplitCleanup(*DestroyClone);    postSplitCleanup(*CleanupClone); -  addMustTailToCoroResumes(*ResumeClone); +  // Adding musttail call to support symmetric transfer. +  // Skip targets which don't support tail call. +  // +  // FIXME: Could we support symmetric transfer effectively without musttail +  // call? +  if (TTI.supportsTailCalls()) +    addMustTailToCoroResumes(*ResumeClone);    // Store addresses resume/destroy/cleanup functions in the coroutine frame.    updateCoroFrame(Shape, ResumeClone, DestroyClone, CleanupClone); @@ -1661,7 +1681,7 @@ static void splitAsyncCoroutine(Function &F, coro::Shape &Shape,    // Map all uses of llvm.coro.begin to the allocated frame pointer.    {      // Make sure we don't invalidate Shape.FramePtr. -    TrackingVH<Instruction> Handle(Shape.FramePtr); +    TrackingVH<Value> Handle(Shape.FramePtr);      Shape.CoroBegin->replaceAllUsesWith(FramePtr);      Shape.FramePtr = Handle.getValPtr();    } @@ -1773,7 +1793,7 @@ static void splitRetconCoroutine(Function &F, coro::Shape &Shape,    // Map all uses of llvm.coro.begin to the allocated frame pointer.    {      // Make sure we don't invalidate Shape.FramePtr. -    TrackingVH<Instruction> Handle(Shape.FramePtr); +    TrackingVH<Value> Handle(Shape.FramePtr);      Shape.CoroBegin->replaceAllUsesWith(RawFramePtr);      Shape.FramePtr = Handle.getValPtr();    } @@ -1879,6 +1899,7 @@ namespace {  static coro::Shape splitCoroutine(Function &F,                                    SmallVectorImpl<Function *> &Clones, +                                  TargetTransformInfo &TTI,                                    bool OptimizeFrame) {    PrettyStackTraceFunction prettyStackTrace(F); @@ -1901,7 +1922,7 @@ static coro::Shape splitCoroutine(Function &F,    } else {      switch (Shape.ABI) {      case coro::ABI::Switch: -      splitSwitchCoroutine(F, Shape, Clones); +      splitSwitchCoroutine(F, Shape, Clones, TTI);        break;      case coro::ABI::Async:        splitAsyncCoroutine(F, Shape, Clones); @@ -1917,21 +1938,27 @@ static coro::Shape splitCoroutine(Function &F,    // This invalidates SwiftErrorOps in the Shape.    replaceSwiftErrorOps(F, Shape, nullptr); -  return Shape; -} - -static void -updateCallGraphAfterCoroutineSplit(Function &F, const coro::Shape &Shape, -                                   const SmallVectorImpl<Function *> &Clones, -                                   CallGraph &CG, CallGraphSCC &SCC) { -  if (!Shape.CoroBegin) -    return; - -  removeCoroEnds(Shape, &CG); -  postSplitCleanup(F); +  // Finally, salvage the llvm.dbg.{declare,addr} in our original function that +  // point into the coroutine frame. We only do this for the current function +  // since the Cloner salvaged debug info for us in the new coroutine funclets. +  SmallVector<DbgVariableIntrinsic *, 8> Worklist; +  SmallDenseMap<llvm::Value *, llvm::AllocaInst *, 4> DbgPtrAllocaCache; +  for (auto &BB : F) { +    for (auto &I : BB) { +      if (auto *DDI = dyn_cast<DbgDeclareInst>(&I)) { +        Worklist.push_back(DDI); +        continue; +      } +      if (auto *DDI = dyn_cast<DbgAddrIntrinsic>(&I)) { +        Worklist.push_back(DDI); +        continue; +      } +    } +  } +  for (auto *DDI : Worklist) +    coro::salvageDebugInfo(DbgPtrAllocaCache, DDI, Shape.OptimizeFrame); -  // Update call graph and add the functions we created to the SCC. -  coro::updateCallGraph(F, Clones, CG, SCC); +  return Shape;  }  static void updateCallGraphAfterCoroutineSplit( @@ -1976,70 +2003,6 @@ static void updateCallGraphAfterCoroutineSplit(    updateCGAndAnalysisManagerForFunctionPass(CG, C, N, AM, UR, FAM);  } -// When we see the coroutine the first time, we insert an indirect call to a -// devirt trigger function and mark the coroutine that it is now ready for -// split. -// Async lowering uses this after it has split the function to restart the -// pipeline. -static void prepareForSplit(Function &F, CallGraph &CG, -                            bool MarkForAsyncRestart = false) { -  Module &M = *F.getParent(); -  LLVMContext &Context = F.getContext(); -#ifndef NDEBUG -  Function *DevirtFn = M.getFunction(CORO_DEVIRT_TRIGGER_FN); -  assert(DevirtFn && "coro.devirt.trigger function not found"); -#endif - -  F.addFnAttr(CORO_PRESPLIT_ATTR, MarkForAsyncRestart -                                      ? ASYNC_RESTART_AFTER_SPLIT -                                      : PREPARED_FOR_SPLIT); - -  // Insert an indirect call sequence that will be devirtualized by CoroElide -  // pass: -  //    %0 = call i8* @llvm.coro.subfn.addr(i8* null, i8 -1) -  //    %1 = bitcast i8* %0 to void(i8*)* -  //    call void %1(i8* null) -  coro::LowererBase Lowerer(M); -  Instruction *InsertPt = -      MarkForAsyncRestart ? F.getEntryBlock().getFirstNonPHIOrDbgOrLifetime() -                          : F.getEntryBlock().getTerminator(); -  auto *Null = ConstantPointerNull::get(Type::getInt8PtrTy(Context)); -  auto *DevirtFnAddr = -      Lowerer.makeSubFnCall(Null, CoroSubFnInst::RestartTrigger, InsertPt); -  FunctionType *FnTy = FunctionType::get(Type::getVoidTy(Context), -                                         {Type::getInt8PtrTy(Context)}, false); -  auto *IndirectCall = CallInst::Create(FnTy, DevirtFnAddr, Null, "", InsertPt); - -  // Update CG graph with an indirect call we just added. -  CG[&F]->addCalledFunction(IndirectCall, CG.getCallsExternalNode()); -} - -// Make sure that there is a devirtualization trigger function that the -// coro-split pass uses to force a restart of the CGSCC pipeline. If the devirt -// trigger function is not found, we will create one and add it to the current -// SCC. -static void createDevirtTriggerFunc(CallGraph &CG, CallGraphSCC &SCC) { -  Module &M = CG.getModule(); -  if (M.getFunction(CORO_DEVIRT_TRIGGER_FN)) -    return; - -  LLVMContext &C = M.getContext(); -  auto *FnTy = FunctionType::get(Type::getVoidTy(C), Type::getInt8PtrTy(C), -                                 /*isVarArg=*/false); -  Function *DevirtFn = -      Function::Create(FnTy, GlobalValue::LinkageTypes::PrivateLinkage, -                       CORO_DEVIRT_TRIGGER_FN, &M); -  DevirtFn->addFnAttr(Attribute::AlwaysInline); -  auto *Entry = BasicBlock::Create(C, "entry", DevirtFn); -  ReturnInst::Create(C, Entry); - -  auto *Node = CG.getOrInsertFunction(DevirtFn); - -  SmallVector<CallGraphNode *, 8> Nodes(SCC.begin(), SCC.end()); -  Nodes.push_back(Node); -  SCC.initialize(Nodes); -} -  /// Replace a call to llvm.coro.prepare.retcon.  static void replacePrepare(CallInst *Prepare, LazyCallGraph &CG,                             LazyCallGraph::SCC &C) { @@ -2076,59 +2039,6 @@ static void replacePrepare(CallInst *Prepare, LazyCallGraph &CG,      Cast->eraseFromParent();    }  } -/// Replace a call to llvm.coro.prepare.retcon. -static void replacePrepare(CallInst *Prepare, CallGraph &CG) { -  auto CastFn = Prepare->getArgOperand(0); // as an i8* -  auto Fn = CastFn->stripPointerCasts(); // as its original type - -  // Find call graph nodes for the preparation. -  CallGraphNode *PrepareUserNode = nullptr, *FnNode = nullptr; -  if (auto ConcreteFn = dyn_cast<Function>(Fn)) { -    PrepareUserNode = CG[Prepare->getFunction()]; -    FnNode = CG[ConcreteFn]; -  } - -  // Attempt to peephole this pattern: -  //    %0 = bitcast [[TYPE]] @some_function to i8* -  //    %1 = call @llvm.coro.prepare.retcon(i8* %0) -  //    %2 = bitcast %1 to [[TYPE]] -  // ==> -  //    %2 = @some_function -  for (Use &U : llvm::make_early_inc_range(Prepare->uses())) { -    // Look for bitcasts back to the original function type. -    auto *Cast = dyn_cast<BitCastInst>(U.getUser()); -    if (!Cast || Cast->getType() != Fn->getType()) continue; - -    // Check whether the replacement will introduce new direct calls. -    // If so, we'll need to update the call graph. -    if (PrepareUserNode) { -      for (auto &Use : Cast->uses()) { -        if (auto *CB = dyn_cast<CallBase>(Use.getUser())) { -          if (!CB->isCallee(&Use)) -            continue; -          PrepareUserNode->removeCallEdgeFor(*CB); -          PrepareUserNode->addCalledFunction(CB, FnNode); -        } -      } -    } - -    // Replace and remove the cast. -    Cast->replaceAllUsesWith(Fn); -    Cast->eraseFromParent(); -  } - -  // Replace any remaining uses with the function as an i8*. -  // This can never directly be a callee, so we don't need to update CG. -  Prepare->replaceAllUsesWith(CastFn); -  Prepare->eraseFromParent(); - -  // Kill dead bitcasts. -  while (auto *Cast = dyn_cast<BitCastInst>(CastFn)) { -    if (!Cast->use_empty()) break; -    CastFn = Cast->getOperand(0); -    Cast->eraseFromParent(); -  } -}  static bool replaceAllPrepares(Function *PrepareFn, LazyCallGraph &CG,                                 LazyCallGraph::SCC &C) { @@ -2143,30 +2053,6 @@ static bool replaceAllPrepares(Function *PrepareFn, LazyCallGraph &CG,    return Changed;  } -/// Remove calls to llvm.coro.prepare.retcon, a barrier meant to prevent -/// IPO from operating on calls to a retcon coroutine before it's been -/// split.  This is only safe to do after we've split all retcon -/// coroutines in the module.  We can do that this in this pass because -/// this pass does promise to split all retcon coroutines (as opposed to -/// switch coroutines, which are lowered in multiple stages). -static bool replaceAllPrepares(Function *PrepareFn, CallGraph &CG) { -  bool Changed = false; -  for (Use &P : llvm::make_early_inc_range(PrepareFn->uses())) { -    // Intrinsics can only be used in calls. -    auto *Prepare = cast<CallInst>(P.getUser()); -    replacePrepare(Prepare, CG); -    Changed = true; -  } - -  return Changed; -} - -static bool declaresCoroSplitIntrinsics(const Module &M) { -  return coro::declaresIntrinsics(M, {"llvm.coro.begin", -                                      "llvm.coro.prepare.retcon", -                                      "llvm.coro.prepare.async"}); -} -  static void addPrepareFunction(const Module &M,                                 SmallVectorImpl<Function *> &Fns,                                 StringRef Name) { @@ -2185,18 +2071,15 @@ PreservedAnalyses CoroSplitPass::run(LazyCallGraph::SCC &C,    auto &FAM =        AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager(); -  if (!declaresCoroSplitIntrinsics(M)) -    return PreservedAnalyses::all(); -    // Check for uses of llvm.coro.prepare.retcon/async.    SmallVector<Function *, 2> PrepareFns;    addPrepareFunction(M, PrepareFns, "llvm.coro.prepare.retcon");    addPrepareFunction(M, PrepareFns, "llvm.coro.prepare.async");    // Find coroutines for processing. -  SmallVector<LazyCallGraph::Node *, 4> Coroutines; +  SmallVector<LazyCallGraph::Node *> Coroutines;    for (LazyCallGraph::Node &N : C) -    if (N.getFunction().hasFnAttribute(CORO_PRESPLIT_ATTR)) +    if (N.getFunction().isPresplitCoroutine())        Coroutines.push_back(&N);    if (Coroutines.empty() && PrepareFns.empty()) @@ -2212,13 +2095,12 @@ PreservedAnalyses CoroSplitPass::run(LazyCallGraph::SCC &C,    for (LazyCallGraph::Node *N : Coroutines) {      Function &F = N->getFunction();      LLVM_DEBUG(dbgs() << "CoroSplit: Processing coroutine '" << F.getName() -                      << "' state: " -                      << F.getFnAttribute(CORO_PRESPLIT_ATTR).getValueAsString()                        << "\n"); -    F.removeFnAttr(CORO_PRESPLIT_ATTR); +    F.setSplittedCoroutine();      SmallVector<Function *, 4> Clones; -    const coro::Shape Shape = splitCoroutine(F, Clones, OptimizeFrame); +    const coro::Shape Shape = splitCoroutine( +        F, Clones, FAM.getResult<TargetIRAnalysis>(F), OptimizeFrame);      updateCallGraphAfterCoroutineSplit(*N, Shape, Clones, C, CG, AM, UR, FAM);      if (!Shape.CoroSuspends.empty()) { @@ -2237,122 +2119,3 @@ PreservedAnalyses CoroSplitPass::run(LazyCallGraph::SCC &C,    return PreservedAnalyses::none();  } - -namespace { - -// We present a coroutine to LLVM as an ordinary function with suspension -// points marked up with intrinsics. We let the optimizer party on the coroutine -// as a single function for as long as possible. Shortly before the coroutine is -// eligible to be inlined into its callers, we split up the coroutine into parts -// corresponding to initial, resume and destroy invocations of the coroutine, -// add them to the current SCC and restart the IPO pipeline to optimize the -// coroutine subfunctions we extracted before proceeding to the caller of the -// coroutine. -struct CoroSplitLegacy : public CallGraphSCCPass { -  static char ID; // Pass identification, replacement for typeid - -  CoroSplitLegacy(bool OptimizeFrame = false) -      : CallGraphSCCPass(ID), OptimizeFrame(OptimizeFrame) { -    initializeCoroSplitLegacyPass(*PassRegistry::getPassRegistry()); -  } - -  bool Run = false; -  bool OptimizeFrame; - -  // A coroutine is identified by the presence of coro.begin intrinsic, if -  // we don't have any, this pass has nothing to do. -  bool doInitialization(CallGraph &CG) override { -    Run = declaresCoroSplitIntrinsics(CG.getModule()); -    return CallGraphSCCPass::doInitialization(CG); -  } - -  bool runOnSCC(CallGraphSCC &SCC) override { -    if (!Run) -      return false; - -    // Check for uses of llvm.coro.prepare.retcon. -    SmallVector<Function *, 2> PrepareFns; -    auto &M = SCC.getCallGraph().getModule(); -    addPrepareFunction(M, PrepareFns, "llvm.coro.prepare.retcon"); -    addPrepareFunction(M, PrepareFns, "llvm.coro.prepare.async"); - -    // Find coroutines for processing. -    SmallVector<Function *, 4> Coroutines; -    for (CallGraphNode *CGN : SCC) -      if (auto *F = CGN->getFunction()) -        if (F->hasFnAttribute(CORO_PRESPLIT_ATTR)) -          Coroutines.push_back(F); - -    if (Coroutines.empty() && PrepareFns.empty()) -      return false; - -    CallGraph &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph(); - -    if (Coroutines.empty()) { -      bool Changed = false; -      for (auto *PrepareFn : PrepareFns) -        Changed |= replaceAllPrepares(PrepareFn, CG); -      return Changed; -    } - -    createDevirtTriggerFunc(CG, SCC); - -    // Split all the coroutines. -    for (Function *F : Coroutines) { -      Attribute Attr = F->getFnAttribute(CORO_PRESPLIT_ATTR); -      StringRef Value = Attr.getValueAsString(); -      LLVM_DEBUG(dbgs() << "CoroSplit: Processing coroutine '" << F->getName() -                        << "' state: " << Value << "\n"); -      // Async lowering marks coroutines to trigger a restart of the pipeline -      // after it has split them. -      if (Value == ASYNC_RESTART_AFTER_SPLIT) { -        F->removeFnAttr(CORO_PRESPLIT_ATTR); -        continue; -      } -      if (Value == UNPREPARED_FOR_SPLIT) { -        prepareForSplit(*F, CG); -        continue; -      } -      F->removeFnAttr(CORO_PRESPLIT_ATTR); - -      SmallVector<Function *, 4> Clones; -      const coro::Shape Shape = splitCoroutine(*F, Clones, OptimizeFrame); -      updateCallGraphAfterCoroutineSplit(*F, Shape, Clones, CG, SCC); -      if (Shape.ABI == coro::ABI::Async) { -        // Restart SCC passes. -        // Mark function for CoroElide pass. It will devirtualize causing a -        // restart of the SCC pipeline. -        prepareForSplit(*F, CG, true /*MarkForAsyncRestart*/); -      } -    } - -    for (auto *PrepareFn : PrepareFns) -      replaceAllPrepares(PrepareFn, CG); - -    return true; -  } - -  void getAnalysisUsage(AnalysisUsage &AU) const override { -    CallGraphSCCPass::getAnalysisUsage(AU); -  } - -  StringRef getPassName() const override { return "Coroutine Splitting"; } -}; - -} // end anonymous namespace - -char CoroSplitLegacy::ID = 0; - -INITIALIZE_PASS_BEGIN( -    CoroSplitLegacy, "coro-split", -    "Split coroutine into a set of functions driving its state machine", false, -    false) -INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass) -INITIALIZE_PASS_END( -    CoroSplitLegacy, "coro-split", -    "Split coroutine into a set of functions driving its state machine", false, -    false) - -Pass *llvm::createCoroSplitLegacyPass(bool OptimizeFrame) { -  return new CoroSplitLegacy(OptimizeFrame); -} diff --git a/llvm/lib/Transforms/Coroutines/Coroutines.cpp b/llvm/lib/Transforms/Coroutines/Coroutines.cpp index 965a146c143f..1742e9319c3b 100644 --- a/llvm/lib/Transforms/Coroutines/Coroutines.cpp +++ b/llvm/lib/Transforms/Coroutines/Coroutines.cpp @@ -10,14 +10,11 @@  //  //===----------------------------------------------------------------------===// -#include "llvm/Transforms/Coroutines.h"  #include "CoroInstr.h"  #include "CoroInternal.h" -#include "llvm-c/Transforms/Coroutines.h"  #include "llvm/ADT/SmallVector.h"  #include "llvm/ADT/StringRef.h"  #include "llvm/Analysis/CallGraph.h" -#include "llvm/Analysis/CallGraphSCCPass.h"  #include "llvm/IR/Attributes.h"  #include "llvm/IR/Constants.h"  #include "llvm/IR/DerivedTypes.h" @@ -26,14 +23,10 @@  #include "llvm/IR/Instructions.h"  #include "llvm/IR/IntrinsicInst.h"  #include "llvm/IR/Intrinsics.h" -#include "llvm/IR/LegacyPassManager.h"  #include "llvm/IR/Module.h"  #include "llvm/IR/Type.h" -#include "llvm/InitializePasses.h"  #include "llvm/Support/Casting.h"  #include "llvm/Support/ErrorHandling.h" -#include "llvm/Transforms/IPO.h" -#include "llvm/Transforms/IPO/PassManagerBuilder.h"  #include "llvm/Transforms/Utils/Local.h"  #include <cassert>  #include <cstddef> @@ -41,55 +34,6 @@  using namespace llvm; -void llvm::initializeCoroutines(PassRegistry &Registry) { -  initializeCoroEarlyLegacyPass(Registry); -  initializeCoroSplitLegacyPass(Registry); -  initializeCoroElideLegacyPass(Registry); -  initializeCoroCleanupLegacyPass(Registry); -} - -static void addCoroutineOpt0Passes(const PassManagerBuilder &Builder, -                                   legacy::PassManagerBase &PM) { -  PM.add(createCoroSplitLegacyPass()); -  PM.add(createCoroElideLegacyPass()); - -  PM.add(createBarrierNoopPass()); -  PM.add(createCoroCleanupLegacyPass()); -} - -static void addCoroutineEarlyPasses(const PassManagerBuilder &Builder, -                                    legacy::PassManagerBase &PM) { -  PM.add(createCoroEarlyLegacyPass()); -} - -static void addCoroutineScalarOptimizerPasses(const PassManagerBuilder &Builder, -                                              legacy::PassManagerBase &PM) { -  PM.add(createCoroElideLegacyPass()); -} - -static void addCoroutineSCCPasses(const PassManagerBuilder &Builder, -                                  legacy::PassManagerBase &PM) { -  PM.add(createCoroSplitLegacyPass(Builder.OptLevel != 0)); -} - -static void addCoroutineOptimizerLastPasses(const PassManagerBuilder &Builder, -                                            legacy::PassManagerBase &PM) { -  PM.add(createCoroCleanupLegacyPass()); -} - -void llvm::addCoroutinePassesToExtensionPoints(PassManagerBuilder &Builder) { -  Builder.addExtension(PassManagerBuilder::EP_EarlyAsPossible, -                       addCoroutineEarlyPasses); -  Builder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, -                       addCoroutineOpt0Passes); -  Builder.addExtension(PassManagerBuilder::EP_CGSCCOptimizerLate, -                       addCoroutineSCCPasses); -  Builder.addExtension(PassManagerBuilder::EP_ScalarOptimizerLate, -                       addCoroutineScalarOptimizerPasses); -  Builder.addExtension(PassManagerBuilder::EP_OptimizerLast, -                       addCoroutineOptimizerLastPasses); -} -  // Construct the lowerer base class and initialize its members.  coro::LowererBase::LowererBase(Module &M)      : TheModule(M), Context(M.getContext()), @@ -119,44 +63,55 @@ Value *coro::LowererBase::makeSubFnCall(Value *Arg, int Index,    return Bitcast;  } +// NOTE: Must be sorted! +static const char *const CoroIntrinsics[] = { +    "llvm.coro.align", +    "llvm.coro.alloc", +    "llvm.coro.async.context.alloc", +    "llvm.coro.async.context.dealloc", +    "llvm.coro.async.resume", +    "llvm.coro.async.size.replace", +    "llvm.coro.async.store_resume", +    "llvm.coro.begin", +    "llvm.coro.destroy", +    "llvm.coro.done", +    "llvm.coro.end", +    "llvm.coro.end.async", +    "llvm.coro.frame", +    "llvm.coro.free", +    "llvm.coro.id", +    "llvm.coro.id.async", +    "llvm.coro.id.retcon", +    "llvm.coro.id.retcon.once", +    "llvm.coro.noop", +    "llvm.coro.prepare.async", +    "llvm.coro.prepare.retcon", +    "llvm.coro.promise", +    "llvm.coro.resume", +    "llvm.coro.save", +    "llvm.coro.size", +    "llvm.coro.subfn.addr", +    "llvm.coro.suspend", +    "llvm.coro.suspend.async", +    "llvm.coro.suspend.retcon", +}; +  #ifndef NDEBUG  static bool isCoroutineIntrinsicName(StringRef Name) { -  // NOTE: Must be sorted! -  static const char *const CoroIntrinsics[] = { -      "llvm.coro.align", -      "llvm.coro.alloc", -      "llvm.coro.async.context.alloc", -      "llvm.coro.async.context.dealloc", -      "llvm.coro.async.resume", -      "llvm.coro.async.size.replace", -      "llvm.coro.async.store_resume", -      "llvm.coro.begin", -      "llvm.coro.destroy", -      "llvm.coro.done", -      "llvm.coro.end", -      "llvm.coro.end.async", -      "llvm.coro.frame", -      "llvm.coro.free", -      "llvm.coro.id", -      "llvm.coro.id.async", -      "llvm.coro.id.retcon", -      "llvm.coro.id.retcon.once", -      "llvm.coro.noop", -      "llvm.coro.prepare.async", -      "llvm.coro.prepare.retcon", -      "llvm.coro.promise", -      "llvm.coro.resume", -      "llvm.coro.save", -      "llvm.coro.size", -      "llvm.coro.subfn.addr", -      "llvm.coro.suspend", -      "llvm.coro.suspend.async", -      "llvm.coro.suspend.retcon", -  };    return Intrinsic::lookupLLVMIntrinsicByName(CoroIntrinsics, Name) != -1;  }  #endif +bool coro::declaresAnyIntrinsic(const Module &M) { +  for (StringRef Name : CoroIntrinsics) { +    assert(isCoroutineIntrinsicName(Name) && "not a coroutine intrinsic"); +    if (M.getNamedValue(Name)) +      return true; +  } + +  return false; +} +  // Verifies if a module has named values listed. Also, in debug mode verifies  // that names are intrinsic names.  bool coro::declaresIntrinsics(const Module &M, @@ -191,46 +146,6 @@ void coro::replaceCoroFree(CoroIdInst *CoroId, bool Elide) {    }  } -// FIXME: This code is stolen from CallGraph::addToCallGraph(Function *F), which -// happens to be private. It is better for this functionality exposed by the -// CallGraph. -static void buildCGN(CallGraph &CG, CallGraphNode *Node) { -  Function *F = Node->getFunction(); - -  // Look for calls by this function. -  for (Instruction &I : instructions(F)) -    if (auto *Call = dyn_cast<CallBase>(&I)) { -      const Function *Callee = Call->getCalledFunction(); -      if (!Callee || !Intrinsic::isLeaf(Callee->getIntrinsicID())) -        // Indirect calls of intrinsics are not allowed so no need to check. -        // We can be more precise here by using TargetArg returned by -        // Intrinsic::isLeaf. -        Node->addCalledFunction(Call, CG.getCallsExternalNode()); -      else if (!Callee->isIntrinsic()) -        Node->addCalledFunction(Call, CG.getOrInsertFunction(Callee)); -    } -} - -// Rebuild CGN after we extracted parts of the code from ParentFunc into -// NewFuncs. Builds CGNs for the NewFuncs and adds them to the current SCC. -void coro::updateCallGraph(Function &ParentFunc, ArrayRef<Function *> NewFuncs, -                           CallGraph &CG, CallGraphSCC &SCC) { -  // Rebuild CGN from scratch for the ParentFunc -  auto *ParentNode = CG[&ParentFunc]; -  ParentNode->removeAllCalledFunctions(); -  buildCGN(CG, ParentNode); - -  SmallVector<CallGraphNode *, 8> Nodes(SCC.begin(), SCC.end()); - -  for (Function *F : NewFuncs) { -    CallGraphNode *Callee = CG.getOrInsertFunction(F); -    Nodes.push_back(Callee); -    buildCGN(CG, Callee); -  } - -  SCC.initialize(Nodes); -} -  static void clear(coro::Shape &Shape) {    Shape.CoroBegin = nullptr;    Shape.CoroEnds.clear(); @@ -735,25 +650,3 @@ void CoroAsyncEndInst::checkWellFormed() const {           "match the tail arguments",           MustTailCallFunc);  } - -void LLVMAddCoroEarlyPass(LLVMPassManagerRef PM) { -  unwrap(PM)->add(createCoroEarlyLegacyPass()); -} - -void LLVMAddCoroSplitPass(LLVMPassManagerRef PM) { -  unwrap(PM)->add(createCoroSplitLegacyPass()); -} - -void LLVMAddCoroElidePass(LLVMPassManagerRef PM) { -  unwrap(PM)->add(createCoroElideLegacyPass()); -} - -void LLVMAddCoroCleanupPass(LLVMPassManagerRef PM) { -  unwrap(PM)->add(createCoroCleanupLegacyPass()); -} - -void -LLVMPassManagerBuilderAddCoroutinePassesToExtensionPoints(LLVMPassManagerBuilderRef PMB) { -  PassManagerBuilder *Builder = unwrap(PMB); -  addCoroutinePassesToExtensionPoints(*Builder); -} | 
