[llvm] 4c040c0 - [Coroutines] Move Shape to its own header (#108242)

via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 13 11:11:35 PDT 2024


Author: Tyler Nowicki
Date: 2024-09-13T14:11:30-04:00
New Revision: 4c040c027575f3a30dc94bfab4c975567195bdc7

URL: https://github.com/llvm/llvm-project/commit/4c040c027575f3a30dc94bfab4c975567195bdc7
DIFF: https://github.com/llvm/llvm-project/commit/4c040c027575f3a30dc94bfab4c975567195bdc7.diff

LOG: [Coroutines] Move Shape to its own header (#108242)

* To create custom ABIs plugin libraries need access to CoroShape.
* As a step in enabling plugin libraries, move Shape into its own header
* The header will eventually be moved into include/llvm/Transforms/Coroutines

See RFC for more info:
https://discourse.llvm.org/t/rfc-abi-objects-for-coroutines/81057

Added: 
    llvm/lib/Transforms/Coroutines/CoroShape.h

Modified: 
    llvm/lib/Transforms/Coroutines/CoroEarly.cpp
    llvm/lib/Transforms/Coroutines/CoroInternal.h
    llvm/lib/Transforms/Coroutines/Coroutines.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Coroutines/CoroEarly.cpp b/llvm/lib/Transforms/Coroutines/CoroEarly.cpp
index 13b6680264c87c..5f8efd1a8f32ea 100644
--- a/llvm/lib/Transforms/Coroutines/CoroEarly.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroEarly.cpp
@@ -8,6 +8,7 @@
 
 #include "llvm/Transforms/Coroutines/CoroEarly.h"
 #include "CoroInternal.h"
+#include "CoroShape.h"
 #include "llvm/IR/DIBuilder.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/IRBuilder.h"

diff  --git a/llvm/lib/Transforms/Coroutines/CoroInternal.h b/llvm/lib/Transforms/Coroutines/CoroInternal.h
index 891798f53b2d00..fcbd31878bdea7 100644
--- a/llvm/lib/Transforms/Coroutines/CoroInternal.h
+++ b/llvm/lib/Transforms/Coroutines/CoroInternal.h
@@ -12,6 +12,7 @@
 #define LLVM_LIB_TRANSFORMS_COROUTINES_COROINTERNAL_H
 
 #include "CoroInstr.h"
+#include "CoroShape.h"
 #include "llvm/Analysis/TargetTransformInfo.h"
 #include "llvm/IR/IRBuilder.h"
 
@@ -58,229 +59,6 @@ struct LowererBase {
   CallInst *makeSubFnCall(Value *Arg, int Index, Instruction *InsertPt);
 };
 
-enum class ABI {
-  /// The "resume-switch" lowering, where there are separate resume and
-  /// destroy functions that are shared between all suspend points.  The
-  /// coroutine frame implicitly stores the resume and destroy functions,
-  /// the current index, and any promise value.
-  Switch,
-
-  /// The "returned-continuation" lowering, where each suspend point creates a
-  /// single continuation function that is used for both resuming and
-  /// destroying.  Does not support promises.
-  Retcon,
-
-  /// The "unique returned-continuation" lowering, where each suspend point
-  /// creates a single continuation function that is used for both resuming
-  /// and destroying.  Does not support promises.  The function is known to
-  /// suspend at most once during its execution, and the return value of
-  /// the continuation is void.
-  RetconOnce,
-
-  /// The "async continuation" lowering, where each suspend point creates a
-  /// single continuation function. The continuation function is available as an
-  /// intrinsic.
-  Async,
-};
-
-// Holds structural Coroutine Intrinsics for a particular function and other
-// values used during CoroSplit pass.
-struct LLVM_LIBRARY_VISIBILITY Shape {
-  CoroBeginInst *CoroBegin;
-  SmallVector<AnyCoroEndInst *, 4> CoroEnds;
-  SmallVector<CoroSizeInst *, 2> CoroSizes;
-  SmallVector<CoroAlignInst *, 2> CoroAligns;
-  SmallVector<AnyCoroSuspendInst *, 4> CoroSuspends;
-  SmallVector<CallInst*, 2> SwiftErrorOps;
-  SmallVector<CoroAwaitSuspendInst *, 4> CoroAwaitSuspends;
-  SmallVector<CallInst *, 2> SymmetricTransfers;
-
-  // Field indexes for special fields in the switch lowering.
-  struct SwitchFieldIndex {
-    enum {
-      Resume,
-      Destroy
-
-      // The promise field is always at a fixed offset from the start of
-      // frame given its type, but the index isn't a constant for all
-      // possible frames.
-
-      // The switch-index field isn't at a fixed offset or index, either;
-      // we just work it in where it fits best.
-    };
-  };
-
-  coro::ABI ABI;
-
-  StructType *FrameTy;
-  Align FrameAlign;
-  uint64_t FrameSize;
-  Value *FramePtr;
-  BasicBlock *AllocaSpillBlock;
-
-  /// This would only be true if optimization are enabled.
-  bool OptimizeFrame;
-
-  struct SwitchLoweringStorage {
-    SwitchInst *ResumeSwitch;
-    AllocaInst *PromiseAlloca;
-    BasicBlock *ResumeEntryBlock;
-    unsigned IndexField;
-    unsigned IndexAlign;
-    unsigned IndexOffset;
-    bool HasFinalSuspend;
-    bool HasUnwindCoroEnd;
-  };
-
-  struct RetconLoweringStorage {
-    Function *ResumePrototype;
-    Function *Alloc;
-    Function *Dealloc;
-    BasicBlock *ReturnBlock;
-    bool IsFrameInlineInStorage;
-  };
-
-  struct AsyncLoweringStorage {
-    Value *Context;
-    CallingConv::ID AsyncCC;
-    unsigned ContextArgNo;
-    uint64_t ContextHeaderSize;
-    uint64_t ContextAlignment;
-    uint64_t FrameOffset; // Start of the frame.
-    uint64_t ContextSize; // Includes frame size.
-    GlobalVariable *AsyncFuncPointer;
-
-    Align getContextAlignment() const { return Align(ContextAlignment); }
-  };
-
-  union {
-    SwitchLoweringStorage SwitchLowering;
-    RetconLoweringStorage RetconLowering;
-    AsyncLoweringStorage AsyncLowering;
-  };
-
-  CoroIdInst *getSwitchCoroId() const {
-    assert(ABI == coro::ABI::Switch);
-    return cast<CoroIdInst>(CoroBegin->getId());
-  }
-
-  AnyCoroIdRetconInst *getRetconCoroId() const {
-    assert(ABI == coro::ABI::Retcon ||
-           ABI == coro::ABI::RetconOnce);
-    return cast<AnyCoroIdRetconInst>(CoroBegin->getId());
-  }
-
-  CoroIdAsyncInst *getAsyncCoroId() const {
-    assert(ABI == coro::ABI::Async);
-    return cast<CoroIdAsyncInst>(CoroBegin->getId());
-  }
-
-  unsigned getSwitchIndexField() const {
-    assert(ABI == coro::ABI::Switch);
-    assert(FrameTy && "frame type not assigned");
-    return SwitchLowering.IndexField;
-  }
-  IntegerType *getIndexType() const {
-    assert(ABI == coro::ABI::Switch);
-    assert(FrameTy && "frame type not assigned");
-    return cast<IntegerType>(FrameTy->getElementType(getSwitchIndexField()));
-  }
-  ConstantInt *getIndex(uint64_t Value) const {
-    return ConstantInt::get(getIndexType(), Value);
-  }
-
-  PointerType *getSwitchResumePointerType() const {
-    assert(ABI == coro::ABI::Switch);
-  assert(FrameTy && "frame type not assigned");
-  return cast<PointerType>(FrameTy->getElementType(SwitchFieldIndex::Resume));
-  }
-
-  FunctionType *getResumeFunctionType() const {
-    switch (ABI) {
-    case coro::ABI::Switch:
-      return FunctionType::get(Type::getVoidTy(FrameTy->getContext()),
-                               PointerType::getUnqual(FrameTy->getContext()),
-                               /*IsVarArg=*/false);
-    case coro::ABI::Retcon:
-    case coro::ABI::RetconOnce:
-      return RetconLowering.ResumePrototype->getFunctionType();
-    case coro::ABI::Async:
-      // Not used. The function type depends on the active suspend.
-      return nullptr;
-    }
-
-    llvm_unreachable("Unknown coro::ABI enum");
-  }
-
-  ArrayRef<Type*> getRetconResultTypes() const {
-    assert(ABI == coro::ABI::Retcon ||
-           ABI == coro::ABI::RetconOnce);
-    auto FTy = CoroBegin->getFunction()->getFunctionType();
-
-    // The safety of all this is checked by checkWFRetconPrototype.
-    if (auto STy = dyn_cast<StructType>(FTy->getReturnType())) {
-      return STy->elements().slice(1);
-    } else {
-      return ArrayRef<Type*>();
-    }
-  }
-
-  ArrayRef<Type*> getRetconResumeTypes() const {
-    assert(ABI == coro::ABI::Retcon ||
-           ABI == coro::ABI::RetconOnce);
-
-    // The safety of all this is checked by checkWFRetconPrototype.
-    auto FTy = RetconLowering.ResumePrototype->getFunctionType();
-    return FTy->params().slice(1);
-  }
-
-  CallingConv::ID getResumeFunctionCC() const {
-    switch (ABI) {
-    case coro::ABI::Switch:
-      return CallingConv::Fast;
-
-    case coro::ABI::Retcon:
-    case coro::ABI::RetconOnce:
-      return RetconLowering.ResumePrototype->getCallingConv();
-    case coro::ABI::Async:
-      return AsyncLowering.AsyncCC;
-    }
-    llvm_unreachable("Unknown coro::ABI enum");
-  }
-
-  AllocaInst *getPromiseAlloca() const {
-    if (ABI == coro::ABI::Switch)
-      return SwitchLowering.PromiseAlloca;
-    return nullptr;
-  }
-
-  BasicBlock::iterator getInsertPtAfterFramePtr() const {
-    if (auto *I = dyn_cast<Instruction>(FramePtr)) {
-      BasicBlock::iterator It = std::next(I->getIterator());
-      It.setHeadBit(true); // Copy pre-RemoveDIs behaviour.
-      return It;
-    }
-    return cast<Argument>(FramePtr)->getParent()->getEntryBlock().begin();
-  }
-
-  /// Allocate memory according to the rules of the active lowering.
-  ///
-  /// \param CG - if non-null, will be updated for the new call
-  Value *emitAlloc(IRBuilder<> &Builder, Value *Size, CallGraph *CG) const;
-
-  /// Deallocate memory according to the rules of the active lowering.
-  ///
-  /// \param CG - if non-null, will be updated for the new call
-  void emitDealloc(IRBuilder<> &Builder, Value *Ptr, CallGraph *CG) const;
-
-  Shape() = default;
-  explicit Shape(Function &F, bool OptimizeFrame = false)
-      : OptimizeFrame(OptimizeFrame) {
-    buildFrom(F);
-  }
-  void buildFrom(Function &F);
-};
-
 bool defaultMaterializable(Instruction &V);
 void normalizeCoroutine(Function &F, coro::Shape &Shape,
                         TargetTransformInfo &TTI);

diff  --git a/llvm/lib/Transforms/Coroutines/CoroShape.h b/llvm/lib/Transforms/Coroutines/CoroShape.h
new file mode 100644
index 00000000000000..f5798b63bf7325
--- /dev/null
+++ b/llvm/lib/Transforms/Coroutines/CoroShape.h
@@ -0,0 +1,249 @@
+//===- CoroShape.h - Coroutine info for lowering --------------*- C++ -*---===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+// This file declares the shape info struct that is required by many coroutine
+// utility methods.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_COROUTINES_COROSHAPE_H
+#define LLVM_TRANSFORMS_COROUTINES_COROSHAPE_H
+
+#include "CoroInstr.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class CallGraph;
+
+namespace coro {
+
+enum class ABI {
+  /// The "resume-switch" lowering, where there are separate resume and
+  /// destroy functions that are shared between all suspend points.  The
+  /// coroutine frame implicitly stores the resume and destroy functions,
+  /// the current index, and any promise value.
+  Switch,
+
+  /// The "returned-continuation" lowering, where each suspend point creates a
+  /// single continuation function that is used for both resuming and
+  /// destroying.  Does not support promises.
+  Retcon,
+
+  /// The "unique returned-continuation" lowering, where each suspend point
+  /// creates a single continuation function that is used for both resuming
+  /// and destroying.  Does not support promises.  The function is known to
+  /// suspend at most once during its execution, and the return value of
+  /// the continuation is void.
+  RetconOnce,
+
+  /// The "async continuation" lowering, where each suspend point creates a
+  /// single continuation function. The continuation function is available as an
+  /// intrinsic.
+  Async,
+};
+
+// Holds structural Coroutine Intrinsics for a particular function and other
+// values used during CoroSplit pass.
+struct LLVM_LIBRARY_VISIBILITY Shape {
+  CoroBeginInst *CoroBegin;
+  SmallVector<AnyCoroEndInst *, 4> CoroEnds;
+  SmallVector<CoroSizeInst *, 2> CoroSizes;
+  SmallVector<CoroAlignInst *, 2> CoroAligns;
+  SmallVector<AnyCoroSuspendInst *, 4> CoroSuspends;
+  SmallVector<CallInst *, 2> SwiftErrorOps;
+  SmallVector<CoroAwaitSuspendInst *, 4> CoroAwaitSuspends;
+  SmallVector<CallInst *, 2> SymmetricTransfers;
+
+  // Field indexes for special fields in the switch lowering.
+  struct SwitchFieldIndex {
+    enum {
+      Resume,
+      Destroy
+
+      // The promise field is always at a fixed offset from the start of
+      // frame given its type, but the index isn't a constant for all
+      // possible frames.
+
+      // The switch-index field isn't at a fixed offset or index, either;
+      // we just work it in where it fits best.
+    };
+  };
+
+  coro::ABI ABI;
+
+  StructType *FrameTy;
+  Align FrameAlign;
+  uint64_t FrameSize;
+  Value *FramePtr;
+  BasicBlock *AllocaSpillBlock;
+
+  /// This would only be true if optimization are enabled.
+  bool OptimizeFrame;
+
+  struct SwitchLoweringStorage {
+    SwitchInst *ResumeSwitch;
+    AllocaInst *PromiseAlloca;
+    BasicBlock *ResumeEntryBlock;
+    unsigned IndexField;
+    unsigned IndexAlign;
+    unsigned IndexOffset;
+    bool HasFinalSuspend;
+    bool HasUnwindCoroEnd;
+  };
+
+  struct RetconLoweringStorage {
+    Function *ResumePrototype;
+    Function *Alloc;
+    Function *Dealloc;
+    BasicBlock *ReturnBlock;
+    bool IsFrameInlineInStorage;
+  };
+
+  struct AsyncLoweringStorage {
+    Value *Context;
+    CallingConv::ID AsyncCC;
+    unsigned ContextArgNo;
+    uint64_t ContextHeaderSize;
+    uint64_t ContextAlignment;
+    uint64_t FrameOffset; // Start of the frame.
+    uint64_t ContextSize; // Includes frame size.
+    GlobalVariable *AsyncFuncPointer;
+
+    Align getContextAlignment() const { return Align(ContextAlignment); }
+  };
+
+  union {
+    SwitchLoweringStorage SwitchLowering;
+    RetconLoweringStorage RetconLowering;
+    AsyncLoweringStorage AsyncLowering;
+  };
+
+  CoroIdInst *getSwitchCoroId() const {
+    assert(ABI == coro::ABI::Switch);
+    return cast<CoroIdInst>(CoroBegin->getId());
+  }
+
+  AnyCoroIdRetconInst *getRetconCoroId() const {
+    assert(ABI == coro::ABI::Retcon || ABI == coro::ABI::RetconOnce);
+    return cast<AnyCoroIdRetconInst>(CoroBegin->getId());
+  }
+
+  CoroIdAsyncInst *getAsyncCoroId() const {
+    assert(ABI == coro::ABI::Async);
+    return cast<CoroIdAsyncInst>(CoroBegin->getId());
+  }
+
+  unsigned getSwitchIndexField() const {
+    assert(ABI == coro::ABI::Switch);
+    assert(FrameTy && "frame type not assigned");
+    return SwitchLowering.IndexField;
+  }
+  IntegerType *getIndexType() const {
+    assert(ABI == coro::ABI::Switch);
+    assert(FrameTy && "frame type not assigned");
+    return cast<IntegerType>(FrameTy->getElementType(getSwitchIndexField()));
+  }
+  ConstantInt *getIndex(uint64_t Value) const {
+    return ConstantInt::get(getIndexType(), Value);
+  }
+
+  PointerType *getSwitchResumePointerType() const {
+    assert(ABI == coro::ABI::Switch);
+    assert(FrameTy && "frame type not assigned");
+    return cast<PointerType>(FrameTy->getElementType(SwitchFieldIndex::Resume));
+  }
+
+  FunctionType *getResumeFunctionType() const {
+    switch (ABI) {
+    case coro::ABI::Switch:
+      return FunctionType::get(Type::getVoidTy(FrameTy->getContext()),
+                               PointerType::getUnqual(FrameTy->getContext()),
+                               /*IsVarArg=*/false);
+    case coro::ABI::Retcon:
+    case coro::ABI::RetconOnce:
+      return RetconLowering.ResumePrototype->getFunctionType();
+    case coro::ABI::Async:
+      // Not used. The function type depends on the active suspend.
+      return nullptr;
+    }
+
+    llvm_unreachable("Unknown coro::ABI enum");
+  }
+
+  ArrayRef<Type *> getRetconResultTypes() const {
+    assert(ABI == coro::ABI::Retcon || ABI == coro::ABI::RetconOnce);
+    auto FTy = CoroBegin->getFunction()->getFunctionType();
+
+    // The safety of all this is checked by checkWFRetconPrototype.
+    if (auto STy = dyn_cast<StructType>(FTy->getReturnType())) {
+      return STy->elements().slice(1);
+    } else {
+      return ArrayRef<Type *>();
+    }
+  }
+
+  ArrayRef<Type *> getRetconResumeTypes() const {
+    assert(ABI == coro::ABI::Retcon || ABI == coro::ABI::RetconOnce);
+
+    // The safety of all this is checked by checkWFRetconPrototype.
+    auto FTy = RetconLowering.ResumePrototype->getFunctionType();
+    return FTy->params().slice(1);
+  }
+
+  CallingConv::ID getResumeFunctionCC() const {
+    switch (ABI) {
+    case coro::ABI::Switch:
+      return CallingConv::Fast;
+
+    case coro::ABI::Retcon:
+    case coro::ABI::RetconOnce:
+      return RetconLowering.ResumePrototype->getCallingConv();
+    case coro::ABI::Async:
+      return AsyncLowering.AsyncCC;
+    }
+    llvm_unreachable("Unknown coro::ABI enum");
+  }
+
+  AllocaInst *getPromiseAlloca() const {
+    if (ABI == coro::ABI::Switch)
+      return SwitchLowering.PromiseAlloca;
+    return nullptr;
+  }
+
+  BasicBlock::iterator getInsertPtAfterFramePtr() const {
+    if (auto *I = dyn_cast<Instruction>(FramePtr)) {
+      BasicBlock::iterator It = std::next(I->getIterator());
+      It.setHeadBit(true); // Copy pre-RemoveDIs behaviour.
+      return It;
+    }
+    return cast<Argument>(FramePtr)->getParent()->getEntryBlock().begin();
+  }
+
+  /// Allocate memory according to the rules of the active lowering.
+  ///
+  /// \param CG - if non-null, will be updated for the new call
+  Value *emitAlloc(IRBuilder<> &Builder, Value *Size, CallGraph *CG) const;
+
+  /// Deallocate memory according to the rules of the active lowering.
+  ///
+  /// \param CG - if non-null, will be updated for the new call
+  void emitDealloc(IRBuilder<> &Builder, Value *Ptr, CallGraph *CG) const;
+
+  Shape() = default;
+  explicit Shape(Function &F, bool OptimizeFrame = false)
+      : OptimizeFrame(OptimizeFrame) {
+    buildFrom(F);
+  }
+  void buildFrom(Function &F);
+};
+
+} // end namespace coro
+
+} // end namespace llvm
+
+#endif // LLVM_TRANSFORMS_COROUTINES_COROSHAPE_H

diff  --git a/llvm/lib/Transforms/Coroutines/Coroutines.cpp b/llvm/lib/Transforms/Coroutines/Coroutines.cpp
index cdc442bc819c37..5cc13a584aef32 100644
--- a/llvm/lib/Transforms/Coroutines/Coroutines.cpp
+++ b/llvm/lib/Transforms/Coroutines/Coroutines.cpp
@@ -12,6 +12,7 @@
 
 #include "CoroInstr.h"
 #include "CoroInternal.h"
+#include "CoroShape.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Analysis/CallGraph.h"


        


More information about the llvm-commits mailing list