llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-coroutines

Author: Jameson Nash (vtjnash)

<details>
<summary>Changes</summary>

Replace coroutine frame struct type with a simple byte array and use
offset-based ptradd operations instead of struct GEP for all field
access. Alloca types have largely lost all meaning to LLVM (even this
pass merges them and uses a random type to represent all of them), and
so they just makes the code to construct alloca more difficult and less
flexible.

Key changes:
- Remove LayoutFieldIndex from frame field tracking
- Remove StructType usage - frame is now a byte array
- Replace all CreateStructGEP/CreateConstInBoundsGEP with CreatePtrAdd
- Store ResumeOffset/DestroyOffset in SwitchLowering for reuse
- Remove Shape.FrameTy, use Shape.FrameSize directly

Bug fix: Uses pointer size and alignment from data layout for header
pointer offsets in debug info instead of hardcoded 8 byte.

Optimization: Replaces load+store patterns with CreateMemCpy for copying
allocas to the frame more efficiently.

Optimization: Add missing inbounds annotations on existing ptradd calls.

Improvement: Preserve debug info of every alloca, even overlapping ones.

The frame type is now completely opaque at the IR level. All structure
is implicit through computed offsets. Debug info still provides detailed
field information using explicit offsets.

See further information in dependent PR 
https://github.com/llvm/llvm-project/pull/178358 as well.

---

Patch is 180.79 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/178359.diff


59 Files Affected:

- (modified) clang/test/CodeGenCoroutines/coro-suspend-cleanups.cpp (+2-2) 
- (modified) llvm/include/llvm/Transforms/Coroutines/CoroShape.h (+9-14) 
- (modified) llvm/lib/Transforms/Coroutines/CoroFrame.cpp (+181-258) 
- (modified) llvm/lib/Transforms/Coroutines/CoroSplit.cpp (+62-39) 
- (modified) llvm/test/Transforms/Coroutines/ArgAddr.ll (+6-5) 
- (modified) llvm/test/Transforms/Coroutines/coro-align16.ll (+5-4) 
- (modified) llvm/test/Transforms/Coroutines/coro-align32.ll (+5-4) 
- (modified) llvm/test/Transforms/Coroutines/coro-align64-02.ll (+5-4) 
- (modified) llvm/test/Transforms/Coroutines/coro-align64.ll (+5-4) 
- (modified) llvm/test/Transforms/Coroutines/coro-align8-02.ll (+4-3) 
- (modified) llvm/test/Transforms/Coroutines/coro-align8.ll (+4-3) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloc-with-param-O0.ll (+4-4) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloc-with-param-O2.ll (+4-4) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloca-01.ll (+7-6) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloca-02.ll (+6-5) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloca-03.ll (+5-4) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloca-04.ll (+6-5) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloca-06.ll (+4-3) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloca-07.ll (+6-6) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloca-08.ll (+6-6) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloca-09.ll (+6-6) 
- (modified) 
llvm/test/Transforms/Coroutines/coro-alloca-loop-carried-address.ll (+4-4) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloca-outside-frame.ll 
(+2-3) 
- (modified) llvm/test/Transforms/Coroutines/coro-alloca-with-addrspace.ll 
(+5-5) 
- (modified) llvm/test/Transforms/Coroutines/coro-async-dyn-align.ll (+7-8) 
- (modified) llvm/test/Transforms/Coroutines/coro-async.ll (+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-await-suspend-lower-invoke.ll 
(+11-12) 
- (modified) llvm/test/Transforms/Coroutines/coro-await-suspend-lower.ll 
(+11-12) 
- (modified) llvm/test/Transforms/Coroutines/coro-byval-param.ll (+8-8) 
- (modified) llvm/test/Transforms/Coroutines/coro-catchswitch.ll (+3-3) 
- (modified) llvm/test/Transforms/Coroutines/coro-debug-coro-frame.ll (+15-13) 
- (modified) llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split-01.ll 
(+8-8) 
- (modified) llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split-02.ll 
(+8-8) 
- (modified) llvm/test/Transforms/Coroutines/coro-frame-arrayalloca.ll (+8-8) 
- (modified) llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-01.ll 
(+6-5) 
- (modified) llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-02.ll 
(+6-5) 
- (modified) llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-04.ll 
(+7-6) 
- (modified) llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-05.ll 
(+6-5) 
- (modified) llvm/test/Transforms/Coroutines/coro-frame.ll (+6-6) 
- (modified) llvm/test/Transforms/Coroutines/coro-lifetime-end.ll (+9-9) 
- (modified) llvm/test/Transforms/Coroutines/coro-materialize.ll (+8-5) 
- (modified) llvm/test/Transforms/Coroutines/coro-noop.ll (-1) 
- (modified) llvm/test/Transforms/Coroutines/coro-padding.ll (+5-5) 
- (modified) llvm/test/Transforms/Coroutines/coro-param-copy.ll (+9-10) 
- (modified) llvm/test/Transforms/Coroutines/coro-retcon-once-value.ll (+1-1) 
- (modified) llvm/test/Transforms/Coroutines/coro-retcon-once-value2.ll 
(+11-11) 
- (modified) llvm/test/Transforms/Coroutines/coro-retcon-remat.ll (+3-3) 
- (modified) llvm/test/Transforms/Coroutines/coro-retcon-resume-values2.ll 
(+9-9) 
- (modified) llvm/test/Transforms/Coroutines/coro-retcon.ll (+3-5) 
- (modified) llvm/test/Transforms/Coroutines/coro-spill-after-phi.ll (+4-5) 
- (modified) llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll (+4-4) 
- (modified) 
llvm/test/Transforms/Coroutines/coro-spill-defs-before-corobegin.ll (+6-5) 
- (modified) llvm/test/Transforms/Coroutines/coro-spill-promise-02.ll (+7-8) 
- (modified) llvm/test/Transforms/Coroutines/coro-spill-promise.ll (+5-5) 
- (modified) llvm/test/Transforms/Coroutines/coro-spill-suspend.ll (+12-14) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-01.ll 
(+2-2) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-02.ll 
(+3-1) 
- (modified) llvm/test/Transforms/Coroutines/coro-split-tbaa-md.ll (+6-4) 
- (modified) llvm/test/Transforms/Coroutines/coro-zero-alloca.ll (+4-4) 


``````````diff
diff --git a/clang/test/CodeGenCoroutines/coro-suspend-cleanups.cpp 
b/clang/test/CodeGenCoroutines/coro-suspend-cleanups.cpp
index d71c2c558996a..77abc53ce2e71 100644
--- a/clang/test/CodeGenCoroutines/coro-suspend-cleanups.cpp
+++ b/clang/test/CodeGenCoroutines/coro-suspend-cleanups.cpp
@@ -47,7 +47,7 @@ coroutine ArrayInitCoro() {
     // CHECK-NEXT:  store ptr %arr.reload.addr, ptr 
%arrayinit.endOfInit.reload.addr, align 8
     // CHECK-NEXT:  call void @_ZN6PrintyC1EPKc(ptr noundef nonnull align 8 
dereferenceable(8) %arr.reload.addr, ptr noundef @.str)
     // CHECK-NEXT:  %arrayinit.element = getelementptr inbounds 
%struct.Printy, ptr %arr.reload.addr, i64 1
-    // CHECK-NEXT:  %arrayinit.element.spill.addr = getelementptr inbounds 
%_Z13ArrayInitCorov.Frame, ptr %0, i32 0, i32 10
+    // CHECK-NEXT:  %arrayinit.element.spill.addr = getelementptr inbounds i8, 
ptr %0, i64 48
     // CHECK-NEXT:  store ptr %arrayinit.element, ptr 
%arrayinit.element.spill.addr, align 8
     // CHECK-NEXT:  store ptr %arrayinit.element, ptr 
%arrayinit.endOfInit.reload.addr, align 8
     co_await Awaiter{}
@@ -61,7 +61,7 @@ coroutine ArrayInitCoro() {
   // CHECK:         br label %cleanup{{.*}}
 
   // CHECK:       await.ready:
-  // CHECK-NEXT:    %arrayinit.element.reload.addr = getelementptr inbounds 
%_Z13ArrayInitCorov.Frame, ptr %0, i32 0, i32 10
+  // CHECK-NEXT:    %arrayinit.element.reload.addr = getelementptr inbounds 
i8, ptr %0, i64 48
   // CHECK-NEXT:    %arrayinit.element.reload = load ptr, ptr 
%arrayinit.element.reload.addr, align 8
   // CHECK-NEXT:    call void @_ZN7Awaiter12await_resumeEv
   // CHECK-NEXT:    store i1 false, ptr %cleanup.isactive.reload.addr, align 1
diff --git a/llvm/include/llvm/Transforms/Coroutines/CoroShape.h 
b/llvm/include/llvm/Transforms/Coroutines/CoroShape.h
index 11b004572957f..88ae4dc306be2 100644
--- a/llvm/include/llvm/Transforms/Coroutines/CoroShape.h
+++ b/llvm/include/llvm/Transforms/Coroutines/CoroShape.h
@@ -75,7 +75,6 @@ struct Shape {
 
     SwiftErrorOps.clear();
 
-    FrameTy = nullptr;
     FramePtr = nullptr;
     AllocaSpillBlock = nullptr;
   }
@@ -113,7 +112,6 @@ struct Shape {
 
   coro::ABI ABI;
 
-  StructType *FrameTy = nullptr;
   Align FrameAlign;
   uint64_t FrameSize = 0;
   Value *FramePtr = nullptr;
@@ -123,7 +121,9 @@ struct Shape {
     SwitchInst *ResumeSwitch;
     AllocaInst *PromiseAlloca;
     BasicBlock *ResumeEntryBlock;
-    unsigned IndexField;
+    IntegerType *IndexType;
+    unsigned ResumeOffset;
+    unsigned DestroyOffset;
     unsigned IndexAlign;
     unsigned IndexOffset;
     bool HasFinalSuspend;
@@ -172,15 +172,10 @@ struct Shape {
     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()));
+    assert(SwitchLowering.IndexType && "index type not assigned");
+    return SwitchLowering.IndexType;
   }
   ConstantInt *getIndex(uint64_t Value) const {
     return ConstantInt::get(getIndexType(), Value);
@@ -188,15 +183,15 @@ struct Shape {
 
   PointerType *getSwitchResumePointerType() const {
     assert(ABI == coro::ABI::Switch);
-    assert(FrameTy && "frame type not assigned");
-    return 
cast<PointerType>(FrameTy->getElementType(SwitchFieldIndex::Resume));
+    assert(CoroBegin && "CoroBegin not assigned");
+    return PointerType::getUnqual(CoroBegin->getContext());
   }
 
   FunctionType *getResumeFunctionType() const {
     switch (ABI) {
     case coro::ABI::Switch:
-      return FunctionType::get(Type::getVoidTy(FrameTy->getContext()),
-                               PointerType::getUnqual(FrameTy->getContext()),
+      return FunctionType::get(Type::getVoidTy(CoroBegin->getContext()),
+                               PointerType::getUnqual(CoroBegin->getContext()),
                                /*IsVarArg=*/false);
     case coro::ABI::Retcon:
     case coro::ABI::RetconOnce:
diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp 
b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp
index 2f2ef7f9eee2c..01bf6ac22790e 100644
--- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp
@@ -77,7 +77,7 @@ struct FrameDataInfo {
   }
 
   void setFieldIndex(Value *V, uint32_t Index) {
-    assert((LayoutIndexUpdateStarted || FieldIndexMap.count(V) == 0) &&
+    assert(FieldIndexMap.count(V) == 0 &&
            "Cannot set the index for the same field twice.");
     FieldIndexMap[V] = Index;
   }
@@ -115,16 +115,11 @@ struct FrameDataInfo {
     FieldOffsetMap.insert({V, Offset});
   }
 
-  // Remap the index of every field in the frame, using the final layout index.
-  void updateLayoutIndex(FrameTypeBuilder &B);
+  // Update field offset and alignment information from FrameTypeBuilder.
+  void updateLayoutInfo(FrameTypeBuilder &B);
 
 private:
-  // LayoutIndexUpdateStarted is used to avoid updating the index of any field
-  // twice by mistake.
-  bool LayoutIndexUpdateStarted = false;
-  // Map from values to their slot indexes on the frame. They will be first set
-  // with their original insertion field index. After the frame is built, their
-  // indexes will be updated into the final layout index.
+  // Map from values to their slot indexes on the frame (insertion order).
   DenseMap<Value *, uint32_t> FieldIndexMap;
   // Map from values to their alignment on the frame. They would be set after
   // the frame is built.
@@ -166,10 +161,7 @@ class FrameTypeBuilder {
   struct Field {
     uint64_t Size;
     uint64_t Offset;
-    Type *Ty;
-    FieldIDType LayoutFieldIndex;
     Align Alignment;
-    Align TyAlignment;
     uint64_t DynamicAlignBuffer;
   };
 
@@ -184,6 +176,8 @@ class FrameTypeBuilder {
   SmallVector<Field, 8> Fields;
   DenseMap<Value*, unsigned> FieldIndexByKey;
 
+  IntegerType *SwitchIndexType = nullptr;
+
 public:
   FrameTypeBuilder(LLVMContext &Context, const DataLayout &DL,
                    std::optional<Align> MaxFrameAlignment)
@@ -193,17 +187,11 @@ class FrameTypeBuilder {
   /// instruction.
   [[nodiscard]] FieldIDType addFieldForAlloca(AllocaInst *AI,
                                               bool IsHeader = false) {
-    Type *Ty = AI->getAllocatedType();
-
-    // Make an array type if this is a static array allocation.
-    if (AI->isArrayAllocation()) {
-      if (auto *CI = dyn_cast<ConstantInt>(AI->getArraySize()))
-        Ty = ArrayType::get(Ty, CI->getValue().getZExtValue());
-      else
-        report_fatal_error("Coroutines cannot handle non static allocas yet");
-    }
-
-    return addField(Ty, AI->getAlign(), IsHeader);
+    auto Size = AI->getAllocationSize(AI->getDataLayout());
+    if (!Size || !Size->isFixed())
+      report_fatal_error(
+          "Coroutines cannot handle non static or vscale allocas yet");
+    return addField(Size->getFixedValue(), AI->getAlign(), IsHeader);
   }
 
   /// We want to put the allocas whose lifetime-ranges are not overlapped
@@ -236,31 +224,33 @@ class FrameTypeBuilder {
   void addFieldForAllocas(const Function &F, FrameDataInfo &FrameData,
                           coro::Shape &Shape, bool OptimizeFrame);
 
-  /// Add a field to this structure.
+  /// Add a field to this structure for a spill.
   [[nodiscard]] FieldIDType addField(Type *Ty, MaybeAlign MaybeFieldAlignment,
                                      bool IsHeader = false,
                                      bool IsSpillOfValue = false) {
-    assert(!IsFinished && "adding fields to a finished builder");
     assert(Ty && "must provide a type for a field");
-
-    // The field size is always the alloc size of the type.
+    // The field size is the alloc size of the type.
     uint64_t FieldSize = DL.getTypeAllocSize(Ty);
-
-    // For an alloca with size=0, we don't need to add a field and they
-    // can just point to any index in the frame. Use index 0.
-    if (FieldSize == 0) {
-      return 0;
-    }
-
-    // The field alignment might not be the type alignment, but we need
-    // to remember the type alignment anyway to build the type.
-    // If we are spilling values we don't need to worry about ABI alignment
+    // The field alignment is usually the type alignment.
+    // But if we are spilling values we don't need to worry about ABI alignment
     // concerns.
     Align ABIAlign = DL.getABITypeAlign(Ty);
     Align TyAlignment = ABIAlign;
     if (IsSpillOfValue && MaxFrameAlignment && *MaxFrameAlignment < ABIAlign)
       TyAlignment = *MaxFrameAlignment;
     Align FieldAlignment = MaybeFieldAlignment.value_or(TyAlignment);
+    return addField(FieldSize, FieldAlignment, IsHeader);
+  }
+
+  /// Add a field to this structure.
+  [[nodiscard]] FieldIDType addField(uint64_t FieldSize, Align FieldAlignment,
+                                     bool IsHeader = false) {
+    assert(!IsFinished && "adding fields to a finished builder");
+
+    // For an alloca with size=0, we don't need to add a field and they
+    // can just point to any index in the frame. Use index 0.
+    if (FieldSize == 0)
+      return 0;
 
     // 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
@@ -284,13 +274,12 @@ class FrameTypeBuilder {
       Offset = OptimizedStructLayoutField::FlexibleOffset;
     }
 
-    Fields.push_back({FieldSize, Offset, Ty, 0, FieldAlignment, TyAlignment,
-                      DynamicAlignBuffer});
+    Fields.push_back({FieldSize, Offset, FieldAlignment, DynamicAlignBuffer});
     return Fields.size() - 1;
   }
 
-  /// Finish the layout and create the struct type with the given name.
-  StructType *finish(StringRef Name);
+  /// Finish the layout and compute final size and alignment.
+  void finish(StringRef Name);
 
   uint64_t getStructSize() const {
     assert(IsFinished && "not yet finished!");
@@ -302,22 +291,21 @@ class FrameTypeBuilder {
     return StructAlign;
   }
 
-  FieldIDType getLayoutFieldIndex(FieldIDType Id) const {
-    assert(IsFinished && "not yet finished!");
-    return Fields[Id].LayoutFieldIndex;
-  }
-
   Field getLayoutField(FieldIDType Id) const {
     assert(IsFinished && "not yet finished!");
     return Fields[Id];
   }
+
+  void setSwitchIndexType(IntegerType *Ty) { SwitchIndexType = Ty; }
+
+  IntegerType *getSwitchIndexType() const { return SwitchIndexType; }
 };
 } // namespace
 
-void FrameDataInfo::updateLayoutIndex(FrameTypeBuilder &B) {
+void FrameDataInfo::updateLayoutInfo(FrameTypeBuilder &B) {
   auto Updater = [&](Value *I) {
-    auto Field = B.getLayoutField(getFieldIndex(I));
-    setFieldIndex(I, Field.LayoutFieldIndex);
+    uint32_t FieldIndex = getFieldIndex(I);
+    auto Field = B.getLayoutField(FieldIndex);
     setAlign(I, Field.Alignment);
     uint64_t dynamicAlign =
         Field.DynamicAlignBuffer
@@ -326,12 +314,10 @@ void FrameDataInfo::updateLayoutIndex(FrameTypeBuilder 
&B) {
     setDynamicAlign(I, dynamicAlign);
     setOffset(I, Field.Offset);
   };
-  LayoutIndexUpdateStarted = true;
   for (auto &S : Spills)
     Updater(S.first);
   for (const auto &A : Allocas)
     Updater(A.Alloca);
-  LayoutIndexUpdateStarted = false;
 }
 
 void FrameTypeBuilder::addFieldForAllocas(const Function &F,
@@ -463,7 +449,7 @@ void FrameTypeBuilder::addFieldForAllocas(const Function &F,
   });
 }
 
-StructType *FrameTypeBuilder::finish(StringRef Name) {
+void FrameTypeBuilder::finish(StringRef Name) {
   assert(!IsFinished && "already finished!");
 
   // Prepare the optimal-layout field array.
@@ -475,7 +461,7 @@ StructType *FrameTypeBuilder::finish(StringRef Name) {
                               Field.Offset);
   }
 
-  // Perform layout.
+  // Perform layout to compute size, alignment, and field offsets.
   auto SizeAndAlign = performOptimizedStructLayout(LayoutFields);
   StructSize = SizeAndAlign.first;
   StructAlign = SizeAndAlign.second;
@@ -484,61 +470,13 @@ StructType *FrameTypeBuilder::finish(StringRef Name) {
     return *static_cast<Field *>(const_cast<void*>(LayoutField.Id));
   };
 
-  // We need to produce a packed struct type if there's a field whose
-  // assigned offset isn't a multiple of its natural type alignment.
-  bool Packed = [&] {
-    for (auto &LayoutField : LayoutFields) {
-      auto &F = getField(LayoutField);
-      if (!isAligned(F.TyAlignment, LayoutField.Offset))
-        return true;
-    }
-    return false;
-  }();
-
-  // Build the struct body.
-  SmallVector<Type*, 16> FieldTypes;
-  FieldTypes.reserve(LayoutFields.size() * 3 / 2);
-  uint64_t LastOffset = 0;
+  // Update field offsets from the computed layout.
   for (auto &LayoutField : LayoutFields) {
     auto &F = getField(LayoutField);
-
-    auto Offset = LayoutField.Offset;
-
-    // Add a padding field if there's a padding gap and we're either
-    // building a packed struct or the padding gap is more than we'd
-    // get from aligning to the field type's natural alignment.
-    assert(Offset >= LastOffset);
-    if (Offset != LastOffset) {
-      if (Packed || alignTo(LastOffset, F.TyAlignment) != Offset)
-        FieldTypes.push_back(ArrayType::get(Type::getInt8Ty(Context),
-                                            Offset - LastOffset));
-    }
-
-    F.Offset = Offset;
-    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;
-  }
-
-  StructType *Ty = StructType::create(Context, FieldTypes, Name, Packed);
-
-#ifndef NDEBUG
-  // Check that the IR layout matches the offsets we expect.
-  auto Layout = DL.getStructLayout(Ty);
-  for (auto &F : Fields) {
-    assert(Ty->getElementType(F.LayoutFieldIndex) == F.Ty);
-    assert(Layout->getElementOffset(F.LayoutFieldIndex) == F.Offset);
+    F.Offset = LayoutField.Offset;
   }
-#endif
 
   IsFinished = true;
-
-  return Ty;
 }
 
 static void cacheDIVar(FrameDataInfo &FrameData,
@@ -710,112 +648,96 @@ static void buildFrameDebugInfo(Function &F, coro::Shape 
&Shape,
   unsigned LineNum = DIS->getLine();
 
   DICompositeType *FrameDITy = DBuilder.createStructType(
-      DIS->getUnit(), Twine(F.getName() + ".coro_frame_ty").str(),
-      DFile, LineNum, Shape.FrameSize * 8,
-      Shape.FrameAlign.value() * 8, llvm::DINode::FlagArtificial, nullptr,
-      llvm::DINodeArray());
-  StructType *FrameTy = Shape.FrameTy;
+      DIS->getUnit(), Twine(F.getName() + ".coro_frame_ty").str(), DFile,
+      LineNum, Shape.FrameSize * 8, Shape.FrameAlign.value() * 8,
+      llvm::DINode::FlagArtificial, nullptr, llvm::DINodeArray());
   SmallVector<Metadata *, 16> Elements;
   DataLayout Layout = F.getDataLayout();
 
   DenseMap<Value *, DILocalVariable *> DIVarCache;
   cacheDIVar(FrameData, DIVarCache);
 
-  unsigned ResumeIndex = coro::Shape::SwitchFieldIndex::Resume;
-  unsigned DestroyIndex = coro::Shape::SwitchFieldIndex::Destroy;
-  unsigned IndexIndex = Shape.SwitchLowering.IndexField;
-
-  DenseMap<unsigned, StringRef> NameCache;
-  NameCache.insert({ResumeIndex, "__resume_fn"});
-  NameCache.insert({DestroyIndex, "__destroy_fn"});
-  NameCache.insert({IndexIndex, "__coro_index"});
-
-  Type *ResumeFnTy = FrameTy->getElementType(ResumeIndex),
-       *DestroyFnTy = FrameTy->getElementType(DestroyIndex),
-       *IndexTy = FrameTy->getElementType(IndexIndex);
-
-  DenseMap<unsigned, DIType *> TyCache;
-  TyCache.insert(
-      {ResumeIndex, DBuilder.createPointerType(
-                        nullptr, Layout.getTypeSizeInBits(ResumeFnTy))});
-  TyCache.insert(
-      {DestroyIndex, DBuilder.createPointerType(
-                         nullptr, Layout.getTypeSizeInBits(DestroyFnTy))});
-
-  /// FIXME: If we fill the field `SizeInBits` with the actual size of
-  /// __coro_index in bits, then __coro_index wouldn't show in the debugger.
-  TyCache.insert({IndexIndex, DBuilder.createBasicType(
-                                  "__coro_index",
-                                  (Layout.getTypeSizeInBits(IndexTy) < 8)
-                                      ? 8
-                                      : Layout.getTypeSizeInBits(IndexTy),
-                                  dwarf::DW_ATE_unsigned_char)});
-
-  for (auto *V : FrameData.getAllDefs()) {
-    auto It = DIVarCache.find(V);
-    if (It == DIVarCache.end())
-      continue;
-
-    auto Index = FrameData.getFieldIndex(V);
-
-    NameCache.insert({Index, It->second->getName()});
-    TyCache.insert({Index, It->second->getType()});
-  }
-
-  // Cache from index to (Align, Offset Pair)
-  DenseMap<unsigned, std::pair<unsigned, unsigned>> OffsetCache;
-  // The Align and Offset of Resume function and Destroy function are fixed.
-  OffsetCache.insert({ResumeIndex, {8, 0}});
-  OffsetCache.insert({DestroyIndex, {8, 8}});
-  OffsetCache.insert(
-      {IndexIndex,
-       {Shape.SwitchLowering.IndexAlign, Shape.SwitchLowering.IndexOffset}});
-
-  for (auto *V : FrameData.getAllDefs()) {
-    auto Index = FrameData.getFieldIndex(V);
-
-    OffsetCache.insert(
-        {Index, {FrameData.getAlign(V).value(), FrameData.getOffset(V)}});
-  }
-
-  DenseMap<Type *, DIType *> DITypeCache;
   // This counter is used to avoid same type names. e.g., there would be
   // many i32 and i64 types in one coroutine. And we would use i32_0 and
   // i32_1 to avoid the same type. Since it makes no sense the name of the
   // fields confilicts with each other.
   unsigned UnknownTypeNum = 0;
-  for (unsigned Index = 0; Index < FrameTy->getNumElements(); Index++) {
-    auto OCIt = OffsetCache.find(Index);
-    if (OCIt == OffsetCache.end())
-      continue;
+  DenseMap<Type *, DIType *> DITypeCache;
+
+  auto addElement = [&](StringRef Name, uint64_t SizeInBits, uint64_t 
Alignment,
+                        uint64_t Offset, DIType *DITy) {
+    Elements.push_back(DBuilder.createMemberType(
+        FrameDITy, Name, DFile, LineNum, SizeInBits, Alignment, Offset * 8,
+        llvm::DINode::FlagArtificial, DITy));
+  };
+
+  auto addDIDef = [&](Value *V) {
+    // Get the offset and alignment for this value.
+    uint64_t Offset = FrameData.getOffset(V);
+    Align Alignment = FrameData.getAlign(V);
 
     std::string Name;
     uint64_t SizeInBits;
-    uint32_t AlignInBits;
-    uint64_t OffsetInBits;
     DIType *DITy = nullptr;
 
-    Type *Ty = FrameTy->getElementType(Index);
-    assert(Ty->isSized() && "We can't handle type which is not sized.\n");
-    SizeInBits = Layout.getTypeSizeInBits(Ty).getFixedValue();
-    AlignInBits = OCIt->second.first * 8;
-    OffsetInBits = OCIt->second.second * 8;
-
-    if (auto It = NameCache.find(Index); It != NameCache.end()) {
-      Name = It->second.str();
-      DITy = TyCache[Index];
+    auto It = DIVarCache.find(V);
+    if (It != DIVarCache.end()) {
+      // Get the type from the debug variable.
+      Name = It->second->getName().str();
+      DITy = It->second->getType();
     } else {
-      DITy = solveDIType(DBuilder, Ty, Layout, FrameDITy, LineNum, 
DITypeCache);
+      if (auto AI = dyn_cast<AllocaInst>(V)) {
+        // Frame alloca
+        DITy = solveDIType(DBuilder, AI->getAllocatedType(), Layout, FrameDITy,
+                           LineNum, DITypeCache);
+      } else {
+        // Spill
+        DITy = solveDIType(DBuilder, V->getType(), Layout, FrameDITy, LineNum,
+                           DITypeCache);
+      }
       assert(DITy && "SolveDIType shouldn't return nullptr.\n");
       Name = DITy->getName().str();
       Name += "_" + std::to_string(UnknownTypeNum);
       UnknownTypeNum++;
     }
 
-    Elements.push_back(DBuilder.createMemberType(
-        FrameDITy, Name, DFile, LineNum, SizeInBits, AlignInBits, OffsetInBits,
-        llvm::DINode::FlagArtificial, DITy));
-  }
+    if (auto AI = dyn_cast<AllocaInst>(V)) {
+      // Lookup the total size of this alloca originally
+      auto Size = AI->getAllocationSize(Layout);
+      assert(Size && Size->isFixed() &&
+             "unreachable due to addFieldForAlloca checks");
+      SizeInBits = Size->getFixedValue() * 8;
+    } else {
+      // Compute the size of th...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/178359
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to