[llvm] Reland "[CodeGen] Use byte offsets and ptradd in ShadowStackGCLowering" (PR #197436)

Jameson Nash via llvm-commits llvm-commits at lists.llvm.org
Wed May 13 06:21:07 PDT 2026


https://github.com/vtjnash created https://github.com/llvm/llvm-project/pull/197436

Replace typed struct GEPs with byte array allocation and ptradd operations:

1. Track root offsets as byte offsets instead of building typed struct.
2. Use `ComputeFrameLayout` to compute byte offsets based on DataLayout, properly accounting for each root's size and alignment.
3. Allocate frame as `[FrameSize x i8]` byte array instead of typed struct.
4. Replace all CreateGEP operations with CreatePtrAdd using computed offsets.
5. Frame layout unchanged: `[Next ptr | Map ptr | Root 0 | Root 1 | ... | Root N]` where each root is placed at its computed aligned offset.
6. Zero out padding between roots with memset for deterministic frame contents for GC.

Benefits:
- Removes dependency on `getAllocatedType` for building frame struct
- Properly handles root alignment requirements (fixes TODO in code)

Relands #178436, after fixing the tests that I'd added specifically to show what changed in that PR, but forgot to rerun. And the logic bug that having tests uncovered (using the wrong size for the frame in the metadata)

>From 05139eadb422a32ab78e8df568ccffa85a4f4cb7 Mon Sep 17 00:00:00 2001
From: Jameson Nash <vtjnash+github at gmail.com>
Date: Wed, 28 Jan 2026 03:25:23 +0000
Subject: [PATCH 1/2] Reland "[CodeGen] Use byte offsets and ptradd in
 ShadowStackGCLowering"

Replace typed struct GEPs with byte array allocation and ptradd
operations:

1. Track root offsets as byte offsets instead of building typed struct.
2. Use `ComputeFrameLayout` to compute byte offsets based on DataLayout,
   properly accounting for each root's size and alignment.
3. Allocate frame as `[FrameSize x i8]` byte array instead of typed
   struct.
4. Replace all CreateGEP operations with CreatePtrAdd using computed
   offsets.
5. Frame layout unchanged:
   `[Next ptr | Map ptr | Root 0 | Root 1 | ... | Root N]`
   where each root is placed at its computed aligned offset.
6. Zero out padding between roots with memset for deterministic frame
   contents for GC.

Benefits:
- Removes dependency on `getAllocatedType` for building frame struct
- Properly handles root alignment requirements (fixes TODO in code)

Co-Authored-By: Claude Sonnet 4.5 <noreply at anthropic.com>
---
 llvm/lib/CodeGen/ShadowStackGCLowering.cpp | 187 +++++++++++----------
 1 file changed, 101 insertions(+), 86 deletions(-)

diff --git a/llvm/lib/CodeGen/ShadowStackGCLowering.cpp b/llvm/lib/CodeGen/ShadowStackGCLowering.cpp
index 000d6d842c6be..deb5d0e9c1555 100644
--- a/llvm/lib/CodeGen/ShadowStackGCLowering.cpp
+++ b/llvm/lib/CodeGen/ShadowStackGCLowering.cpp
@@ -24,6 +24,7 @@
 #include "llvm/IR/BasicBlock.h"
 #include "llvm/IR/Constant.h"
 #include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/Function.h"
@@ -38,7 +39,9 @@
 #include "llvm/IR/Value.h"
 #include "llvm/InitializePasses.h"
 #include "llvm/Pass.h"
+#include "llvm/Support/Alignment.h"
 #include "llvm/Support/Casting.h"
+#include "llvm/Support/MathExtras.h"
 #include "llvm/Transforms/Utils/EscapeEnumerator.h"
 #include <cassert>
 #include <optional>
@@ -56,14 +59,16 @@ class ShadowStackGCLoweringImpl {
   /// roots.
   GlobalVariable *Head = nullptr;
 
-  /// StackEntryTy - Abstract type of a link in the shadow stack.
-  StructType *StackEntryTy = nullptr;
   StructType *FrameMapTy = nullptr;
 
   /// Roots - GC roots in the current function. Each is a pair of the
   /// intrinsic call and its corresponding alloca.
   std::vector<std::pair<CallInst *, AllocaInst *>> Roots;
 
+  /// RootOffsets - Byte offsets and sizes of each root within the frame.
+  /// Each element is a pair of (offset, size).
+  std::vector<std::pair<uint64_t, uint64_t>> RootOffsets;
+
 public:
   ShadowStackGCLoweringImpl() = default;
 
@@ -72,16 +77,9 @@ class ShadowStackGCLoweringImpl {
 
 private:
   bool IsNullValue(Value *V);
-  Constant *GetFrameMap(Function &F);
-  Type *GetConcreteStackEntryType(Function &F);
+  Constant *GetFrameMap(Function &F, uint64_t FrameSizeInPtrs);
+  std::pair<uint64_t, Align> ComputeFrameLayout(Function &F);
   void CollectRoots(Function &F);
-
-  static GetElementPtrInst *CreateGEP(LLVMContext &Context, IRBuilder<> &B,
-                                      Type *Ty, Value *BasePtr, int Idx1,
-                                      const char *Name);
-  static GetElementPtrInst *CreateGEP(LLVMContext &Context, IRBuilder<> &B,
-                                      Type *Ty, Value *BasePtr, int Idx1, int Idx2,
-                                      const char *Name);
 };
 
 class ShadowStackGCLowering : public FunctionPass {
@@ -143,7 +141,8 @@ FunctionPass *llvm::createShadowStackGCLoweringPass() { return new ShadowStackGC
 
 ShadowStackGCLowering::ShadowStackGCLowering() : FunctionPass(ID) {}
 
-Constant *ShadowStackGCLoweringImpl::GetFrameMap(Function &F) {
+Constant *ShadowStackGCLoweringImpl::GetFrameMap(Function &F,
+                                                 uint64_t FrameSizeInPtrs) {
   // doInitialization creates the abstract type of this value.
   Type *VoidPtr = PointerType::getUnqual(F.getContext());
 
@@ -161,7 +160,7 @@ Constant *ShadowStackGCLoweringImpl::GetFrameMap(Function &F) {
   Type *Int32Ty = Type::getInt32Ty(F.getContext());
 
   Constant *BaseElts[] = {
-      ConstantInt::get(Int32Ty, Roots.size(), false),
+      ConstantInt::get(Int32Ty, FrameSizeInPtrs, false),
       ConstantInt::get(Int32Ty, NumMeta, false),
   };
 
@@ -192,14 +191,44 @@ Constant *ShadowStackGCLoweringImpl::GetFrameMap(Function &F) {
                                     "__gc_" + F.getName());
 }
 
-Type *ShadowStackGCLoweringImpl::GetConcreteStackEntryType(Function &F) {
-  // doInitialization creates the generic version of this type.
-  std::vector<Type *> EltTys;
-  EltTys.push_back(StackEntryTy);
-  for (const std::pair<CallInst *, AllocaInst *> &Root : Roots)
-    EltTys.push_back(Root.second->getAllocatedType());
+std::pair<uint64_t, Align>
+ShadowStackGCLoweringImpl::ComputeFrameLayout(Function &F) {
+  // Compute the layout of the shadow stack frame using byte offsets.
+  // Layout: [Next ptr | Map ptr | Root 0 | Root 1 | ... | Root N]
+
+  const DataLayout &DL = F.getParent()->getDataLayout();
+  uint64_t PtrSize = DL.getPointerSize(0);
+  Align PtrAlign = DL.getPointerABIAlignment(0);
+
+  RootOffsets.clear();
+  Align MaxAlign = PtrAlign;
+
+  // Offset 0: Next pointer
+  // Offset PtrSize: Map pointer
+  uint64_t Offset = 2 * PtrSize;
+
+  // Compute offsets and sizes for each root
+  for (const std::pair<CallInst *, AllocaInst *> &Root : Roots) {
+    AllocaInst *AI = Root.second;
+    std::optional<TypeSize> RootSize = AI->getAllocationSize(DL);
+    if (!RootSize || !RootSize->isFixed())
+      reportFatalUsageError(
+          "Intrinsic::gcroot requires a fixed size stack object");
+    uint64_t Size = RootSize->getFixedValue();
+    Align RootAlign = AI->getAlign();
+    MaxAlign = std::max(MaxAlign, RootAlign);
+
+    // Align the offset for this root
+    uint64_t AlignedOffset = alignTo(Offset, RootAlign);
+
+    // Store both offset and size as a pair
+    RootOffsets.push_back({AlignedOffset, Size});
+    Offset = AlignedOffset + Size;
+  }
 
-  return StructType::create(EltTys, ("gc_stackentry." + F.getName()).str());
+  // Final frame size, aligned to maximum alignment
+  uint64_t FrameSize = alignTo(Offset, MaxAlign);
+  return {FrameSize, MaxAlign};
 }
 
 /// doInitialization - If this module uses the GC intrinsics, find them now. If
@@ -226,21 +255,11 @@ bool ShadowStackGCLoweringImpl::doInitialization(Module &M) {
   // Specifies length of variable length array.
   EltTys.push_back(Type::getInt32Ty(M.getContext()));
   FrameMapTy = StructType::create(EltTys, "gc_map");
-  PointerType *FrameMapPtrTy = PointerType::getUnqual(M.getContext());
-
-  // struct StackEntry {
-  //   ShadowStackEntry *Next; // Caller's stack entry.
-  //   FrameMap *Map;          // Pointer to constant FrameMap.
-  //   void *Roots[];          // Stack roots (in-place array, so we pretend).
-  // };
 
+  // The shadow stack linked list uses opaque pointers.
+  // Each frame is a byte array with: [Next ptr | Map ptr | Roots...]
   PointerType *StackEntryPtrTy = PointerType::getUnqual(M.getContext());
 
-  EltTys.clear();
-  EltTys.push_back(StackEntryPtrTy);
-  EltTys.push_back(FrameMapPtrTy);
-  StackEntryTy = StructType::create(EltTys, "gc_stackentry");
-
   // Get the root chain if it already exists.
   Head = M.getGlobalVariable("llvm_gc_root_chain");
   if (!Head) {
@@ -264,10 +283,6 @@ bool ShadowStackGCLoweringImpl::IsNullValue(Value *V) {
 }
 
 void ShadowStackGCLoweringImpl::CollectRoots(Function &F) {
-  // FIXME: Account for original alignment. Could fragment the root array.
-  //   Approach 1: Null initialize empty slots at runtime. Yuck.
-  //   Approach 2: Emit a map of the array instead of just a count.
-
   assert(Roots.empty() && "Not cleaned up?");
 
   SmallVector<std::pair<CallInst *, AllocaInst *>, 16> MetaRoots;
@@ -291,34 +306,6 @@ void ShadowStackGCLoweringImpl::CollectRoots(Function &F) {
   Roots.insert(Roots.begin(), MetaRoots.begin(), MetaRoots.end());
 }
 
-GetElementPtrInst *
-ShadowStackGCLoweringImpl::CreateGEP(LLVMContext &Context, IRBuilder<> &B,
-                                     Type *Ty, Value *BasePtr, int Idx,
-                                     int Idx2, const char *Name) {
-  Value *Indices[] = {ConstantInt::get(Type::getInt32Ty(Context), 0),
-                      ConstantInt::get(Type::getInt32Ty(Context), Idx),
-                      ConstantInt::get(Type::getInt32Ty(Context), Idx2)};
-  Value *Val = B.CreateGEP(Ty, BasePtr, Indices, Name);
-
-  assert(isa<GetElementPtrInst>(Val) && "Unexpected folded constant");
-
-  return dyn_cast<GetElementPtrInst>(Val);
-}
-
-GetElementPtrInst *ShadowStackGCLoweringImpl::CreateGEP(LLVMContext &Context,
-                                                        IRBuilder<> &B,
-                                                        Type *Ty,
-                                                        Value *BasePtr, int Idx,
-                                                        const char *Name) {
-  Value *Indices[] = {ConstantInt::get(Type::getInt32Ty(Context), 0),
-                      ConstantInt::get(Type::getInt32Ty(Context), Idx)};
-  Value *Val = B.CreateGEP(Ty, BasePtr, Indices, Name);
-
-  assert(isa<GetElementPtrInst>(Val) && "Unexpected folded constant");
-
-  return dyn_cast<GetElementPtrInst>(Val);
-}
-
 /// runOnFunction - Insert code to maintain the shadow stack.
 bool ShadowStackGCLoweringImpl::runOnFunction(Function &F,
                                               DomTreeUpdater *DTU) {
@@ -327,6 +314,7 @@ bool ShadowStackGCLoweringImpl::runOnFunction(Function &F,
     return false;
 
   LLVMContext &Context = F.getContext();
+  const DataLayout &DL = F.getParent()->getDataLayout();
 
   // Find calls to llvm.gcroot.
   CollectRoots(F);
@@ -336,16 +324,20 @@ bool ShadowStackGCLoweringImpl::runOnFunction(Function &F,
   if (Roots.empty())
     return false;
 
-  // Build the constant map and figure the type of the shadow stack entry.
-  Value *FrameMap = GetFrameMap(F);
-  Type *ConcreteStackEntryTy = GetConcreteStackEntryType(F);
+  // Compute frame layout using byte offsets first.
+  auto [FrameSize, FrameAlign] = ComputeFrameLayout(F);
+
+  // Build the constant map with frame size in pointer-sized units.
+  uint64_t PtrSize = DL.getPointerSize();
+  Value *FrameMap = GetFrameMap(F, FrameSize / PtrSize);
 
   // Build the shadow stack entry at the very start of the function.
   BasicBlock::iterator IP = F.getEntryBlock().begin();
   IRBuilder<> AtEntry(IP->getParent(), IP);
-
-  Instruction *StackEntry =
-      AtEntry.CreateAlloca(ConcreteStackEntryTy, nullptr, "gc_frame");
+  Type *Int8Ty = Type::getInt8Ty(Context);
+  AllocaInst *StackEntry = AtEntry.CreateAlloca(
+      ArrayType::get(Int8Ty, FrameSize), nullptr, "gc_frame");
+  StackEntry->setAlignment(FrameAlign);
 
   AtEntry.SetInsertPointPastAllocas(&F);
   IP = AtEntry.GetInsertPoint();
@@ -353,20 +345,45 @@ bool ShadowStackGCLoweringImpl::runOnFunction(Function &F,
   // Initialize the map pointer and load the current head of the shadow stack.
   Instruction *CurrentHead =
       AtEntry.CreateLoad(AtEntry.getPtrTy(), Head, "gc_currhead");
-  Instruction *EntryMapPtr = CreateGEP(Context, AtEntry, ConcreteStackEntryTy,
-                                       StackEntry, 0, 1, "gc_frame.map");
+
+  // Map pointer is at offset PtrSize (after the Next pointer)
+  Value *EntryMapPtr = AtEntry.CreatePtrAdd(
+      StackEntry, AtEntry.getInt64(PtrSize), "gc_frame.map");
   AtEntry.CreateStore(FrameMap, EntryMapPtr);
 
-  // After all the allocas...
+  // Zero out any padding between roots to ensure deterministic frame contents.
+  // This includes the region after the map pointer up to the first root.
+  uint64_t LastEnd = 2 * PtrSize; // End of Map pointer field
+  assert(RootOffsets.size() == Roots.size());
   for (unsigned I = 0, E = Roots.size(); I != E; ++I) {
-    // For each root, find the corresponding slot in the aggregate...
-    Value *SlotPtr = CreateGEP(Context, AtEntry, ConcreteStackEntryTy,
-                               StackEntry, 1 + I, "gc_root");
+    auto [RootOffset, RootSize] = RootOffsets[I];
+
+    // Zero any padding before this root
+    if (RootOffset > LastEnd) {
+      Value *PaddingPtr =
+          AtEntry.CreatePtrAdd(StackEntry, AtEntry.getInt64(LastEnd));
+      AtEntry.CreateMemSet(PaddingPtr, AtEntry.getInt8(0), RootOffset - LastEnd,
+                           Align(1));
+    }
+
+    // For each root, compute pointer using precomputed offset
+    Value *SlotPtr = AtEntry.CreatePtrAdd(
+        StackEntry, AtEntry.getInt64(RootOffset), "gc_root");
 
     // And use it in lieu of the alloca.
     AllocaInst *OriginalAlloca = Roots[I].second;
     SlotPtr->takeName(OriginalAlloca);
     OriginalAlloca->replaceAllUsesWith(SlotPtr);
+
+    LastEnd = RootOffset + RootSize;
+  }
+
+  // Zero any padding at the end of the frame
+  if (FrameSize > LastEnd) {
+    Value *PaddingPtr =
+        AtEntry.CreatePtrAdd(StackEntry, AtEntry.getInt64(LastEnd));
+    AtEntry.CreateMemSet(PaddingPtr, AtEntry.getInt8(0), FrameSize - LastEnd,
+                         Align(1));
   }
 
   // Move past the original stores inserted by GCStrategy::InitRoots. This isn't
@@ -378,23 +395,20 @@ bool ShadowStackGCLoweringImpl::runOnFunction(Function &F,
   AtEntry.SetInsertPoint(IP->getParent(), IP);
 
   // Push the entry onto the shadow stack.
-  Instruction *EntryNextPtr = CreateGEP(Context, AtEntry, ConcreteStackEntryTy,
-                                        StackEntry, 0, 0, "gc_frame.next");
-  Instruction *NewHeadVal = CreateGEP(Context, AtEntry, ConcreteStackEntryTy,
-                                      StackEntry, 0, "gc_newhead");
-  AtEntry.CreateStore(CurrentHead, EntryNextPtr);
-  AtEntry.CreateStore(NewHeadVal, Head);
+  // Next pointer is at offset 0, so it's just the frame pointer
+  AtEntry.CreateStore(CurrentHead, StackEntry);
+  // The new head value is also the frame pointer (the linked list links to
+  // frame base)
+  AtEntry.CreateStore(StackEntry, Head);
 
   // For each instruction that escapes...
   EscapeEnumerator EE(F, "gc_cleanup", /*HandleExceptions=*/true, DTU);
   while (IRBuilder<> *AtExit = EE.Next()) {
     // Pop the entry from the shadow stack. Don't reuse CurrentHead from
     // AtEntry, since that would make the value live for the entire function.
-    Instruction *EntryNextPtr2 =
-        CreateGEP(Context, *AtExit, ConcreteStackEntryTy, StackEntry, 0, 0,
-                  "gc_frame.next");
+    // Next pointer is at offset 0, so load from the frame base
     Value *SavedHead =
-        AtExit->CreateLoad(AtExit->getPtrTy(), EntryNextPtr2, "gc_savedhead");
+        AtExit->CreateLoad(AtExit->getPtrTy(), StackEntry, "gc_savedhead");
     AtExit->CreateStore(SavedHead, Head);
   }
 
@@ -407,5 +421,6 @@ bool ShadowStackGCLoweringImpl::runOnFunction(Function &F,
   }
 
   Roots.clear();
+  RootOffsets.clear();
   return true;
 }

>From eb8b4268ef6e96c814be04fd6ba12bf4396842f2 Mon Sep 17 00:00:00 2001
From: Jameson Nash <vtjnash at gmail.com>
Date: Wed, 13 May 2026 13:19:14 +0000
Subject: [PATCH 2/2] fix test and logic bug

---
 llvm/lib/CodeGen/ShadowStackGCLowering.cpp    |  2 +-
 .../Generic/shadow-stack-gc-lowering.ll       | 74 ++++++++-----------
 2 files changed, 31 insertions(+), 45 deletions(-)

diff --git a/llvm/lib/CodeGen/ShadowStackGCLowering.cpp b/llvm/lib/CodeGen/ShadowStackGCLowering.cpp
index deb5d0e9c1555..56b9f938ed140 100644
--- a/llvm/lib/CodeGen/ShadowStackGCLowering.cpp
+++ b/llvm/lib/CodeGen/ShadowStackGCLowering.cpp
@@ -329,7 +329,7 @@ bool ShadowStackGCLoweringImpl::runOnFunction(Function &F,
 
   // Build the constant map with frame size in pointer-sized units.
   uint64_t PtrSize = DL.getPointerSize();
-  Value *FrameMap = GetFrameMap(F, FrameSize / PtrSize);
+  Value *FrameMap = GetFrameMap(F, FrameSize / PtrSize - 2);
 
   // Build the shadow stack entry at the very start of the function.
   BasicBlock::iterator IP = F.getEntryBlock().begin();
diff --git a/llvm/test/CodeGen/Generic/shadow-stack-gc-lowering.ll b/llvm/test/CodeGen/Generic/shadow-stack-gc-lowering.ll
index 422ecf2a5e215..3df1147b19e52 100644
--- a/llvm/test/CodeGen/Generic/shadow-stack-gc-lowering.ll
+++ b/llvm/test/CodeGen/Generic/shadow-stack-gc-lowering.ll
@@ -1,6 +1,8 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
 ; RUN: opt -S -passes='require<collector-metadata>,shadow-stack-gc-lowering' < %s | FileCheck %s
 
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
 declare void @llvm.gcroot(ptr, ptr)
 
 ; A gc "shadow-stack" function with a single root: the pass should create a
@@ -18,18 +20,15 @@ declare void @llvm.gcroot(ptr, ptr)
 define void @single_root(ptr %obj) gc "shadow-stack" {
 ; CHECK-LABEL: @single_root(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[GC_FRAME:%.*]] = alloca [[GC_STACKENTRY_SINGLE_ROOT:%.*]], align 8
+; CHECK-NEXT:    [[GC_FRAME_NEXT:%.*]] = alloca [24 x i8], align 8
 ; CHECK-NEXT:    [[GC_CURRHEAD:%.*]] = load ptr, ptr @llvm_gc_root_chain, align 8
-; CHECK-NEXT:    [[GC_FRAME_MAP:%.*]] = getelementptr [[GC_STACKENTRY_SINGLE_ROOT]], ptr [[GC_FRAME]], i32 0, i32 0, i32 1
+; CHECK-NEXT:    [[GC_FRAME_MAP:%.*]] = getelementptr i8, ptr [[GC_FRAME_NEXT]], i64 8
 ; CHECK-NEXT:    store ptr @__gc_single_root, ptr [[GC_FRAME_MAP]], align 8
-; CHECK-NEXT:    [[ROOT:%.*]] = getelementptr [[GC_STACKENTRY_SINGLE_ROOT]], ptr [[GC_FRAME]], i32 0, i32 1
-; CHECK-NEXT:    [[GC_FRAME_NEXT:%.*]] = getelementptr [[GC_STACKENTRY_SINGLE_ROOT]], ptr [[GC_FRAME]], i32 0, i32 0, i32 0
-; CHECK-NEXT:    [[GC_NEWHEAD:%.*]] = getelementptr [[GC_STACKENTRY_SINGLE_ROOT]], ptr [[GC_FRAME]], i32 0, i32 0
+; CHECK-NEXT:    [[ROOT:%.*]] = getelementptr i8, ptr [[GC_FRAME_NEXT]], i64 16
 ; CHECK-NEXT:    store ptr [[GC_CURRHEAD]], ptr [[GC_FRAME_NEXT]], align 8
-; CHECK-NEXT:    store ptr [[GC_NEWHEAD]], ptr @llvm_gc_root_chain, align 8
+; CHECK-NEXT:    store ptr [[GC_FRAME_NEXT]], ptr @llvm_gc_root_chain, align 8
 ; CHECK-NEXT:    store ptr [[OBJ:%.*]], ptr [[ROOT]], align 8
-; CHECK-NEXT:    [[GC_FRAME_NEXT1:%.*]] = getelementptr [[GC_STACKENTRY_SINGLE_ROOT]], ptr [[GC_FRAME]], i32 0, i32 0, i32 0
-; CHECK-NEXT:    [[GC_SAVEDHEAD:%.*]] = load ptr, ptr [[GC_FRAME_NEXT1]], align 8
+; CHECK-NEXT:    [[GC_SAVEDHEAD:%.*]] = load ptr, ptr [[GC_FRAME_NEXT]], align 8
 ; CHECK-NEXT:    store ptr [[GC_SAVEDHEAD]], ptr @llvm_gc_root_chain, align 8
 ; CHECK-NEXT:    ret void
 ;
@@ -45,20 +44,17 @@ entry:
 define void @two_roots(ptr %a, ptr %b) gc "shadow-stack" {
 ; CHECK-LABEL: @two_roots(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[GC_FRAME:%.*]] = alloca [[GC_STACKENTRY_TWO_ROOTS:%.*]], align 8
+; CHECK-NEXT:    [[GC_FRAME_NEXT:%.*]] = alloca [32 x i8], align 8
 ; CHECK-NEXT:    [[GC_CURRHEAD:%.*]] = load ptr, ptr @llvm_gc_root_chain, align 8
-; CHECK-NEXT:    [[GC_FRAME_MAP:%.*]] = getelementptr [[GC_STACKENTRY_TWO_ROOTS]], ptr [[GC_FRAME]], i32 0, i32 0, i32 1
+; CHECK-NEXT:    [[GC_FRAME_MAP:%.*]] = getelementptr i8, ptr [[GC_FRAME_NEXT]], i64 8
 ; CHECK-NEXT:    store ptr @__gc_two_roots, ptr [[GC_FRAME_MAP]], align 8
-; CHECK-NEXT:    [[ROOTA:%.*]] = getelementptr [[GC_STACKENTRY_TWO_ROOTS]], ptr [[GC_FRAME]], i32 0, i32 1
-; CHECK-NEXT:    [[ROOTB:%.*]] = getelementptr [[GC_STACKENTRY_TWO_ROOTS]], ptr [[GC_FRAME]], i32 0, i32 2
-; CHECK-NEXT:    [[GC_FRAME_NEXT:%.*]] = getelementptr [[GC_STACKENTRY_TWO_ROOTS]], ptr [[GC_FRAME]], i32 0, i32 0, i32 0
-; CHECK-NEXT:    [[GC_NEWHEAD:%.*]] = getelementptr [[GC_STACKENTRY_TWO_ROOTS]], ptr [[GC_FRAME]], i32 0, i32 0
+; CHECK-NEXT:    [[ROOTA:%.*]] = getelementptr i8, ptr [[GC_FRAME_NEXT]], i64 16
+; CHECK-NEXT:    [[ROOTB:%.*]] = getelementptr i8, ptr [[GC_FRAME_NEXT]], i64 24
 ; CHECK-NEXT:    store ptr [[GC_CURRHEAD]], ptr [[GC_FRAME_NEXT]], align 8
-; CHECK-NEXT:    store ptr [[GC_NEWHEAD]], ptr @llvm_gc_root_chain, align 8
+; CHECK-NEXT:    store ptr [[GC_FRAME_NEXT]], ptr @llvm_gc_root_chain, align 8
 ; CHECK-NEXT:    store ptr [[A:%.*]], ptr [[ROOTA]], align 8
 ; CHECK-NEXT:    store ptr [[B:%.*]], ptr [[ROOTB]], align 8
-; CHECK-NEXT:    [[GC_FRAME_NEXT1:%.*]] = getelementptr [[GC_STACKENTRY_TWO_ROOTS]], ptr [[GC_FRAME]], i32 0, i32 0, i32 0
-; CHECK-NEXT:    [[GC_SAVEDHEAD:%.*]] = load ptr, ptr [[GC_FRAME_NEXT1]], align 8
+; CHECK-NEXT:    [[GC_SAVEDHEAD:%.*]] = load ptr, ptr [[GC_FRAME_NEXT]], align 8
 ; CHECK-NEXT:    store ptr [[GC_SAVEDHEAD]], ptr @llvm_gc_root_chain, align 8
 ; CHECK-NEXT:    ret void
 ;
@@ -80,18 +76,15 @@ entry:
 define void @root_with_metadata(ptr %obj) gc "shadow-stack" {
 ; CHECK-LABEL: @root_with_metadata(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[GC_FRAME:%.*]] = alloca [[GC_STACKENTRY_ROOT_WITH_METADATA:%.*]], align 8
+; CHECK-NEXT:    [[GC_FRAME_NEXT:%.*]] = alloca [24 x i8], align 8
 ; CHECK-NEXT:    [[GC_CURRHEAD:%.*]] = load ptr, ptr @llvm_gc_root_chain, align 8
-; CHECK-NEXT:    [[GC_FRAME_MAP:%.*]] = getelementptr [[GC_STACKENTRY_ROOT_WITH_METADATA]], ptr [[GC_FRAME]], i32 0, i32 0, i32 1
+; CHECK-NEXT:    [[GC_FRAME_MAP:%.*]] = getelementptr i8, ptr [[GC_FRAME_NEXT]], i64 8
 ; CHECK-NEXT:    store ptr @__gc_root_with_metadata, ptr [[GC_FRAME_MAP]], align 8
-; CHECK-NEXT:    [[ROOT:%.*]] = getelementptr [[GC_STACKENTRY_ROOT_WITH_METADATA]], ptr [[GC_FRAME]], i32 0, i32 1
-; CHECK-NEXT:    [[GC_FRAME_NEXT:%.*]] = getelementptr [[GC_STACKENTRY_ROOT_WITH_METADATA]], ptr [[GC_FRAME]], i32 0, i32 0, i32 0
-; CHECK-NEXT:    [[GC_NEWHEAD:%.*]] = getelementptr [[GC_STACKENTRY_ROOT_WITH_METADATA]], ptr [[GC_FRAME]], i32 0, i32 0
+; CHECK-NEXT:    [[ROOT:%.*]] = getelementptr i8, ptr [[GC_FRAME_NEXT]], i64 16
 ; CHECK-NEXT:    store ptr [[GC_CURRHEAD]], ptr [[GC_FRAME_NEXT]], align 8
-; CHECK-NEXT:    store ptr [[GC_NEWHEAD]], ptr @llvm_gc_root_chain, align 8
+; CHECK-NEXT:    store ptr [[GC_FRAME_NEXT]], ptr @llvm_gc_root_chain, align 8
 ; CHECK-NEXT:    store ptr [[OBJ:%.*]], ptr [[ROOT]], align 8
-; CHECK-NEXT:    [[GC_FRAME_NEXT1:%.*]] = getelementptr [[GC_STACKENTRY_ROOT_WITH_METADATA]], ptr [[GC_FRAME]], i32 0, i32 0, i32 0
-; CHECK-NEXT:    [[GC_SAVEDHEAD:%.*]] = load ptr, ptr [[GC_FRAME_NEXT1]], align 8
+; CHECK-NEXT:    [[GC_SAVEDHEAD:%.*]] = load ptr, ptr [[GC_FRAME_NEXT]], align 8
 ; CHECK-NEXT:    store ptr [[GC_SAVEDHEAD]], ptr @llvm_gc_root_chain, align 8
 ; CHECK-NEXT:    ret void
 ;
@@ -107,20 +100,17 @@ entry:
 define void @mixed_metadata(ptr %a, ptr %b) gc "shadow-stack" {
 ; CHECK-LABEL: @mixed_metadata(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[GC_FRAME:%.*]] = alloca [[GC_STACKENTRY_MIXED_METADATA:%.*]], align 8
+; CHECK-NEXT:    [[GC_FRAME_NEXT:%.*]] = alloca [32 x i8], align 8
 ; CHECK-NEXT:    [[GC_CURRHEAD:%.*]] = load ptr, ptr @llvm_gc_root_chain, align 8
-; CHECK-NEXT:    [[GC_FRAME_MAP:%.*]] = getelementptr [[GC_STACKENTRY_MIXED_METADATA]], ptr [[GC_FRAME]], i32 0, i32 0, i32 1
+; CHECK-NEXT:    [[GC_FRAME_MAP:%.*]] = getelementptr i8, ptr [[GC_FRAME_NEXT]], i64 8
 ; CHECK-NEXT:    store ptr @__gc_mixed_metadata, ptr [[GC_FRAME_MAP]], align 8
-; CHECK-NEXT:    [[ROOTB:%.*]] = getelementptr [[GC_STACKENTRY_MIXED_METADATA]], ptr [[GC_FRAME]], i32 0, i32 1
-; CHECK-NEXT:    [[ROOTA:%.*]] = getelementptr [[GC_STACKENTRY_MIXED_METADATA]], ptr [[GC_FRAME]], i32 0, i32 2
-; CHECK-NEXT:    [[GC_FRAME_NEXT:%.*]] = getelementptr [[GC_STACKENTRY_MIXED_METADATA]], ptr [[GC_FRAME]], i32 0, i32 0, i32 0
-; CHECK-NEXT:    [[GC_NEWHEAD:%.*]] = getelementptr [[GC_STACKENTRY_MIXED_METADATA]], ptr [[GC_FRAME]], i32 0, i32 0
+; CHECK-NEXT:    [[ROOTB:%.*]] = getelementptr i8, ptr [[GC_FRAME_NEXT]], i64 16
+; CHECK-NEXT:    [[ROOTA:%.*]] = getelementptr i8, ptr [[GC_FRAME_NEXT]], i64 24
 ; CHECK-NEXT:    store ptr [[GC_CURRHEAD]], ptr [[GC_FRAME_NEXT]], align 8
-; CHECK-NEXT:    store ptr [[GC_NEWHEAD]], ptr @llvm_gc_root_chain, align 8
+; CHECK-NEXT:    store ptr [[GC_FRAME_NEXT]], ptr @llvm_gc_root_chain, align 8
 ; CHECK-NEXT:    store ptr [[A:%.*]], ptr [[ROOTA]], align 8
 ; CHECK-NEXT:    store ptr [[B:%.*]], ptr [[ROOTB]], align 8
-; CHECK-NEXT:    [[GC_FRAME_NEXT1:%.*]] = getelementptr [[GC_STACKENTRY_MIXED_METADATA]], ptr [[GC_FRAME]], i32 0, i32 0, i32 0
-; CHECK-NEXT:    [[GC_SAVEDHEAD:%.*]] = load ptr, ptr [[GC_FRAME_NEXT1]], align 8
+; CHECK-NEXT:    [[GC_SAVEDHEAD:%.*]] = load ptr, ptr [[GC_FRAME_NEXT]], align 8
 ; CHECK-NEXT:    store ptr [[GC_SAVEDHEAD]], ptr @llvm_gc_root_chain, align 8
 ; CHECK-NEXT:    ret void
 ;
@@ -153,28 +143,24 @@ declare ptr @__gxx_personality_v0(...)
 define void @with_invoke(ptr %obj) gc "shadow-stack" personality ptr @__gxx_personality_v0 {
 ; CHECK-LABEL: @with_invoke(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[GC_FRAME:%.*]] = alloca [[GC_STACKENTRY_WITH_INVOKE:%.*]], align 8
+; CHECK-NEXT:    [[GC_FRAME_NEXT:%.*]] = alloca [24 x i8], align 8
 ; CHECK-NEXT:    [[GC_CURRHEAD:%.*]] = load ptr, ptr @llvm_gc_root_chain, align 8
-; CHECK-NEXT:    [[GC_FRAME_MAP:%.*]] = getelementptr [[GC_STACKENTRY_WITH_INVOKE]], ptr [[GC_FRAME]], i32 0, i32 0, i32 1
+; CHECK-NEXT:    [[GC_FRAME_MAP:%.*]] = getelementptr i8, ptr [[GC_FRAME_NEXT]], i64 8
 ; CHECK-NEXT:    store ptr @__gc_with_invoke, ptr [[GC_FRAME_MAP]], align 8
-; CHECK-NEXT:    [[ROOT:%.*]] = getelementptr [[GC_STACKENTRY_WITH_INVOKE]], ptr [[GC_FRAME]], i32 0, i32 1
-; CHECK-NEXT:    [[GC_FRAME_NEXT:%.*]] = getelementptr [[GC_STACKENTRY_WITH_INVOKE]], ptr [[GC_FRAME]], i32 0, i32 0, i32 0
-; CHECK-NEXT:    [[GC_NEWHEAD:%.*]] = getelementptr [[GC_STACKENTRY_WITH_INVOKE]], ptr [[GC_FRAME]], i32 0, i32 0
+; CHECK-NEXT:    [[ROOT:%.*]] = getelementptr i8, ptr [[GC_FRAME_NEXT]], i64 16
 ; CHECK-NEXT:    store ptr [[GC_CURRHEAD]], ptr [[GC_FRAME_NEXT]], align 8
-; CHECK-NEXT:    store ptr [[GC_NEWHEAD]], ptr @llvm_gc_root_chain, align 8
+; CHECK-NEXT:    store ptr [[GC_FRAME_NEXT]], ptr @llvm_gc_root_chain, align 8
 ; CHECK-NEXT:    store ptr [[OBJ:%.*]], ptr [[ROOT]], align 8
 ; CHECK-NEXT:    invoke void @may_throw()
 ; CHECK-NEXT:            to label [[NORMAL:%.*]] unwind label [[UNWIND:%.*]]
 ; CHECK:       normal:
-; CHECK-NEXT:    [[GC_FRAME_NEXT1:%.*]] = getelementptr [[GC_STACKENTRY_WITH_INVOKE]], ptr [[GC_FRAME]], i32 0, i32 0, i32 0
-; CHECK-NEXT:    [[GC_SAVEDHEAD:%.*]] = load ptr, ptr [[GC_FRAME_NEXT1]], align 8
+; CHECK-NEXT:    [[GC_SAVEDHEAD:%.*]] = load ptr, ptr [[GC_FRAME_NEXT]], align 8
 ; CHECK-NEXT:    store ptr [[GC_SAVEDHEAD]], ptr @llvm_gc_root_chain, align 8
 ; CHECK-NEXT:    ret void
 ; CHECK:       unwind:
 ; CHECK-NEXT:    [[LP:%.*]] = landingpad { ptr, i32 }
 ; CHECK-NEXT:            cleanup
-; CHECK-NEXT:    [[GC_FRAME_NEXT2:%.*]] = getelementptr [[GC_STACKENTRY_WITH_INVOKE]], ptr [[GC_FRAME]], i32 0, i32 0, i32 0
-; CHECK-NEXT:    [[GC_SAVEDHEAD3:%.*]] = load ptr, ptr [[GC_FRAME_NEXT2]], align 8
+; CHECK-NEXT:    [[GC_SAVEDHEAD3:%.*]] = load ptr, ptr [[GC_FRAME_NEXT]], align 8
 ; CHECK-NEXT:    store ptr [[GC_SAVEDHEAD3]], ptr @llvm_gc_root_chain, align 8
 ; CHECK-NEXT:    resume { ptr, i32 } [[LP]]
 ;



More information about the llvm-commits mailing list