https://github.com/erichkeane updated 
https://github.com/llvm/llvm-project/pull/215823

>From 3518d08a4d299cbfb528864c22e1b2a2dc645e0a Mon Sep 17 00:00:00 2001
From: erichkeane <[email protected]>
Date: Wed, 12 Aug 2026 06:38:46 -0700
Subject: [PATCH 1/5] [NFC] Split PaddingClearer out into a CodeGenUtils shared
 directory

We have plenty of stuff that needs to be shared between Classic-Codegen
and CIR, that we've been copy/pasting too often. This patch
proposes/produces a shared directory of CodeGenUtils that will be for
things that don't really belong elsewhere.  This functionality
(calculating padding for __builtin_clear_padding) is both too complex to
copy/paste, and doesn't really have reason to live anywhere except
CodeGen/CIR-CodeGen.

The type has been split out as faithfully as possible, with only minor
changes to make it LLVM-agnostic.  The part of it that is required to
generate the LLVM-IR is left in CGBuiltin.cpp, but takes the list of
padding-intervals as an input, which will be useful for CIR's
representation.
---
 .../include/clang/CodeGenUtils/CodeGenUtils.h | 283 +++++++++++++
 clang/lib/CodeGen/CGBuiltin.cpp               | 395 +++---------------
 2 files changed, 352 insertions(+), 326 deletions(-)
 create mode 100644 clang/include/clang/CodeGenUtils/CodeGenUtils.h

diff --git a/clang/include/clang/CodeGenUtils/CodeGenUtils.h 
b/clang/include/clang/CodeGenUtils/CodeGenUtils.h
new file mode 100644
index 0000000000000..2da4ddc5aea36
--- /dev/null
+++ b/clang/include/clang/CodeGenUtils/CodeGenUtils.h
@@ -0,0 +1,283 @@
+//===--- CodeGenUtils.h - Shared Classic CodeGen/CIR CodeGen Utils--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
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/APFloat.h"
+
+#include <algorithm>
+#include <utility>
+
+namespace clang::CodeGenUtils {
+// A type that helps represent a padding interval.
+struct BitInterval {
+  // [First, Last)
+  uint64_t First;
+  uint64_t Last;
+};
+
+// PaddingCalculator is a utility class that calculates the padding bits in a
+// c/c++ type. It traverses the type recursively, collecting occupied
+// bit intervals, and then computes the padding intervals.
+// If a byte only contains some padding bits, it gets intervals for only those
+// bits. This is the case for bit-fields.
+struct PaddingCalculator {
+  PaddingCalculator(const ASTContext &Ctx, const TargetInfo &TI,
+                    unsigned PointerSizeInBits)
+      : Ctx(Ctx), TI(TI), PointerSizeInBits(PointerSizeInBits) {}
+
+  void run(QualType Ty) {
+    OccuppiedIntervals.clear();
+    Stack.clear();
+
+    TySizeInBits = Ctx.getTypeSize(Ty);
+
+    Stack.push_back(Data{0, Ty, true});
+    while (!Stack.empty()) {
+      Data Current = Stack.back();
+      Stack.pop_back();
+      Visit(Current);
+    }
+    MergeOccuppiedIntervals();
+  }
+
+  llvm::SmallVector<BitInterval> GetPaddingIntervals() {
+    llvm::SmallVector<BitInterval> Results;
+    if (OccuppiedIntervals.size() == 1 &&
+        OccuppiedIntervals.front().First == 0 &&
+        OccuppiedIntervals.front().Last == TySizeInBits) {
+      return Results;
+    }
+    Results.reserve(OccuppiedIntervals.size() + 1);
+    uint64_t CurrentPos = 0;
+    for (const BitInterval &OccupiedInterval : OccuppiedIntervals) {
+      if (OccupiedInterval.First > CurrentPos) {
+        Results.push_back(BitInterval{CurrentPos, OccupiedInterval.First});
+      }
+      CurrentPos = OccupiedInterval.Last;
+    }
+    if (TySizeInBits > CurrentPos) {
+      Results.push_back(BitInterval{CurrentPos, TySizeInBits});
+    }
+    return Results;
+  }
+
+private:
+  struct Data {
+    uint64_t StartBitOffset;
+    QualType Ty;
+    bool VisitVirtualBase;
+  };
+
+  // Return the number of non padding bits of a scalar type.
+  //
+  // The property that we specifically care about here is whether the scalar
+  // type has padding bits, i.e. are there bits in the type which are not
+  // specified by the ABI.
+  //
+  // We currently don't care about this anywhere else in clang: layout cares
+  // about the ABI size, calling convention code cares about specific types,
+  // but nothing cares about padding specifically. And it's not something we 
can
+  // easily query from LLVM due to the type system mismatches.
+  // DL.getTypeSizeInBits(convertTypeForLoadStore(T)) is probably close, but 
the
+  // DataLayout methods aren't really designed for this usage.
+  //
+  // Therefore, it is better to explicitly list all the scalar types
+  // containing padding bits that we know of, namely, _BitInt(N) and x87 long
+  // double.
+  uint64_t getScalarOccupiedSizeInBits(QualType Ty) const {
+    if (const auto *BIT = Ty->getAs<BitIntType>())
+      return BIT->getNumBits();
+
+    if (const auto *BT = Ty->getAs<BuiltinType>()) {
+      if (BT->getKind() == BuiltinType::LongDouble &&
+          &TI.getLongDoubleFormat() == &llvm::APFloat::x87DoubleExtended())
+        return llvm::APFloat::getSizeInBits(TI.getLongDoubleFormat());
+    }
+
+    return Ctx.getTypeSize(Ty);
+  }
+
+  void Visit(const Data &D) {
+    if (auto *AT = dyn_cast<ConstantArrayType>(D.Ty)) {
+      VisitArray(AT, D.StartBitOffset);
+      return;
+    }
+
+    if (auto *Record = D.Ty->getAsRecordDecl()) {
+      VisitStruct(Record, D.StartBitOffset, D.VisitVirtualBase);
+      return;
+    }
+
+    if (D.Ty->isAtomicType()) {
+      auto Unwrapped = D;
+      Unwrapped.Ty = D.Ty.getAtomicUnqualifiedType();
+      Stack.push_back(Unwrapped);
+      return;
+    }
+
+    if (const auto *Complex = D.Ty->getAs<ComplexType>()) {
+      VisitComplex(Complex, D.StartBitOffset);
+      return;
+    }
+
+    if (const auto *VT = D.Ty->getAs<clang::VectorType>()) {
+      VisitVector(VT, D.StartBitOffset);
+      return;
+    }
+
+    uint64_t SizeBit = getScalarOccupiedSizeInBits(D.Ty);
+    OccuppiedIntervals.push_back(
+        BitInterval{D.StartBitOffset, D.StartBitOffset + SizeBit});
+  }
+
+  void VisitArray(const ConstantArrayType *AT, uint64_t StartBitOffset) {
+    for (uint64_t ArrIndex = 0; ArrIndex < AT->getSize().getLimitedValue();
+         ++ArrIndex) {
+
+      QualType ElementQualType = AT->getElementType();
+      auto ElementSize = Ctx.getTypeSizeInChars(ElementQualType);
+      auto ElementAlign = Ctx.getTypeAlignInChars(ElementQualType);
+      auto Offset = ElementSize.alignTo(ElementAlign);
+
+      Stack.push_back(Data{StartBitOffset + ArrIndex * Offset.getQuantity() *
+                                                Ctx.getCharWidth(),
+                           ElementQualType, /*VisitVirtualBase*/ true});
+    }
+  }
+
+  void VisitStruct(const RecordDecl *R, uint64_t StartBitOffset,
+                   bool VisitVirtualBase) {
+    const ASTRecordLayout &ASTLayout = Ctx.getASTRecordLayout(R);
+    auto *CXXRecord = dyn_cast<CXXRecordDecl>(R);
+
+    if (CXXRecord) {
+      if (ASTLayout.hasOwnVFPtr()) {
+        OccuppiedIntervals.push_back(
+            BitInterval{StartBitOffset, StartBitOffset + PointerSizeInBits});
+      }
+
+      if (ASTLayout.hasOwnVBPtr()) {
+        auto Offset = ASTLayout.getVBPtrOffset().getQuantity();
+        auto StartVBPtr = StartBitOffset + Offset * Ctx.getCharWidth();
+        OccuppiedIntervals.push_back(
+            BitInterval{StartVBPtr, StartVBPtr + PointerSizeInBits});
+      }
+
+      const auto VisitBase = [&ASTLayout, StartBitOffset, this](
+                                 const CXXBaseSpecifier &Base, auto GetOffset) 
{
+        auto *BaseRecord = Base.getType()->getAsCXXRecordDecl();
+        if (!BaseRecord) {
+          return;
+        }
+        auto BaseOffset =
+            std::invoke(GetOffset, ASTLayout, BaseRecord).getQuantity();
+
+        Stack.push_back(Data{StartBitOffset + BaseOffset * Ctx.getCharWidth(),
+                             Base.getType(), /*VisitVirtualBase*/ false});
+      };
+
+      for (auto Base : CXXRecord->bases()) {
+        if (!Base.isVirtual()) {
+          VisitBase(Base, &ASTRecordLayout::getBaseClassOffset);
+        }
+      }
+
+      if (VisitVirtualBase) {
+        for (auto VBase : CXXRecord->vbases()) {
+          VisitBase(VBase, &ASTRecordLayout::getVBaseClassOffset);
+        }
+      }
+    }
+
+    for (auto *Field : R->fields()) {
+      // Treat unnamed bitfields as padding.
+      if (Field->isUnnamedBitField())
+        continue;
+
+      auto FieldOffset = ASTLayout.getFieldOffset(Field->getFieldIndex());
+      if (Field->isBitField()) {
+        OccuppiedIntervals.push_back(BitInterval{
+            StartBitOffset + FieldOffset,
+            StartBitOffset + FieldOffset + Field->getBitWidthValue()});
+      } else {
+        Stack.push_back(Data{StartBitOffset + FieldOffset, Field->getType(),
+                             /*VisitVirtualBase*/ true});
+      }
+    }
+  }
+
+  void VisitComplex(const ComplexType *CT, uint64_t StartBitOffset) {
+    QualType ElementQualType = CT->getElementType();
+    auto ElementSize = Ctx.getTypeSizeInChars(ElementQualType);
+    auto ElementAlign = Ctx.getTypeAlignInChars(ElementQualType);
+    auto ImgOffset = ElementSize.alignTo(ElementAlign);
+
+    Stack.push_back(
+        Data{StartBitOffset, ElementQualType, /*VisitVirtualBase*/ true});
+    Stack.push_back(
+        Data{StartBitOffset + ImgOffset.getQuantity() * Ctx.getCharWidth(),
+             ElementQualType, /*VisitVirtualBase*/ true});
+  }
+
+  void VisitVector(const clang::VectorType *VT, uint64_t StartBitOffset) {
+    uint64_t SizeBit = [&]() -> uint64_t {
+      if (VT->isPackedVectorBoolType(Ctx))
+        return VT->getNumElements();
+      return getScalarOccupiedSizeInBits(VT->getElementType()) *
+             VT->getNumElements();
+    }();
+    OccuppiedIntervals.push_back(
+        BitInterval{StartBitOffset, StartBitOffset + SizeBit});
+  }
+
+  void MergeOccuppiedIntervals() {
+    std::sort(OccuppiedIntervals.begin(), OccuppiedIntervals.end(),
+              [](const BitInterval &lhs, const BitInterval &rhs) {
+                return std::tie(lhs.First, lhs.Last) <
+                       std::tie(rhs.First, rhs.Last);
+              });
+
+    llvm::SmallVector<BitInterval> Merged;
+    Merged.reserve(OccuppiedIntervals.size());
+
+    for (const BitInterval &NextInterval : OccuppiedIntervals) {
+      if (Merged.empty()) {
+        Merged.push_back(NextInterval);
+        continue;
+      }
+      auto &LastInterval = Merged.back();
+
+      if (NextInterval.First > LastInterval.Last) {
+        Merged.push_back(NextInterval);
+      } else {
+        LastInterval.Last = std::max(LastInterval.Last, NextInterval.Last);
+      }
+    }
+
+    OccuppiedIntervals = Merged;
+  }
+
+  const ASTContext &Ctx;
+  const TargetInfo &TI;
+  unsigned PointerSizeInBits;
+  uint64_t TySizeInBits = 0;
+  llvm::SmallVector<Data> Stack;
+  llvm::SmallVector<BitInterval> OccuppiedIntervals;
+};
+
+// Calculate and gets the 'padding intervals' inside of a type.
+llvm::SmallVector<BitInterval>
+CalculatePaddingIntervals(const ASTContext &Ctx, const TargetInfo &TI,
+                          QualType Ty, unsigned PointerSizeInBits) {
+  PaddingCalculator pc{Ctx, TI, PointerSizeInBits};
+  pc.run(Ty);
+  return pc.GetPaddingIntervals();
+}
+} // namespace clang::CodeGenUtils
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 3521fc10f1387..9fa54b8f18b13 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -28,6 +28,7 @@
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/DiagnosticFrontend.h"
 #include "clang/Basic/TargetInfo.h"
+#include "clang/CodeGenUtils/CodeGenUtils.h"
 #include "llvm/ADT/APFloat.h"
 #include "llvm/IR/InlineAsm.h"
 #include "llvm/IR/Instruction.h"
@@ -2598,277 +2599,40 @@ RValue CodeGenFunction::emitStdcFirstBit(const 
CallExpr *E, Intrinsic::ID IntID,
   return RValue::get(Result);
 }
 
-namespace {
-
-// PaddingClearer is a utility class that clears padding bits in a
-// c/c++ type. It traverses the type recursively, collecting occupied
-// bit intervals, and then computes the padding intervals.
-// In the end, it clears the padding bits by writing zeros
-// to the padding intervals bytes-by-bytes. If a byte only contains
-// some padding bits, it writes zeros to only those bits. This is
-// the case for bit-fields.
-struct PaddingClearer {
-  PaddingClearer(CodeGenFunction &F)
-      : CGF(F), CharWidth(CGF.getContext().getCharWidth()) {}
-
-  void run(Address Src, QualType Ty) {
-    OccuppiedIntervals.clear();
-    Stack.clear();
-
-    Stack.push_back(Data{0, Ty, true});
-    while (!Stack.empty()) {
-      auto Current = Stack.back();
-      Stack.pop_back();
-      Visit(Current);
-    }
-
-    MergeOccuppiedIntervals();
-    auto PaddingIntervals =
-        GetPaddingIntervals(CGF.getContext().getTypeSize(Ty));
-    for (const auto &Interval : PaddingIntervals) {
-      ClearPadding(Src, Interval);
-    }
-  }
-
-private:
-  struct BitInterval {
-    // [First, Last)
-    uint64_t First;
-    uint64_t Last;
-  };
-
-  struct Data {
-    uint64_t StartBitOffset;
-    QualType Ty;
-    bool VisitVirtualBase;
-  };
-
-  // Return the number of non padding bits of a scalar type.
-  //
-  // The property that we specifically care about here is whether the scalar
-  // type has padding bits, i.e. are there bits in the type which are not
-  // specified by the ABI.
-  //
-  // We currently don't care about this anywhere else in clang: layout cares
-  // about the ABI size, calling convention code cares about specific types, 
but
-  // nothing cares about padding specifically. And it's not something we can
-  // easily query from LLVM due to the type system mismatches.
-  // DL.getTypeSizeInBits(convertTypeForLoadStore(T)) is probably close, but 
the
-  // DataLayout methods aren't really designed for this usage.
-  //
-  // Therefore, it is better to explicitly list all the scalar types containing
-  // padding bits that we know of, namely, _BitInt(N) and x87 long double.
-  uint64_t getScalarOccupiedSizeInBits(QualType Ty) const {
-    if (const auto *BIT = Ty->getAs<BitIntType>())
-      return BIT->getNumBits();
-
-    if (const auto *BT = Ty->getAs<BuiltinType>()) {
-      if (BT->getKind() == BuiltinType::LongDouble &&
-          &CGF.getTarget().getLongDoubleFormat() ==
-              &APFloat::x87DoubleExtended())
-        return APFloat::getSizeInBits(CGF.getTarget().getLongDoubleFormat());
-    }
-
-    return CGF.getContext().getTypeSize(Ty);
-  }
-
-  void Visit(const Data &D) {
-    if (auto *AT = dyn_cast<ConstantArrayType>(D.Ty)) {
-      VisitArray(AT, D.StartBitOffset);
-      return;
-    }
-
-    if (auto *Record = D.Ty->getAsRecordDecl()) {
-      VisitStruct(Record, D.StartBitOffset, D.VisitVirtualBase);
-      return;
-    }
-
-    if (D.Ty->isAtomicType()) {
-      auto Unwrapped = D;
-      Unwrapped.Ty = D.Ty.getAtomicUnqualifiedType();
-      Stack.push_back(Unwrapped);
-      return;
-    }
-
-    if (const auto *Complex = D.Ty->getAs<ComplexType>()) {
-      VisitComplex(Complex, D.StartBitOffset);
-      return;
-    }
-
-    if (const auto *VT = D.Ty->getAs<clang::VectorType>()) {
-      VisitVector(VT, D.StartBitOffset);
-      return;
-    }
-
-    uint64_t SizeBit = getScalarOccupiedSizeInBits(D.Ty);
-    OccuppiedIntervals.push_back(
-        BitInterval{D.StartBitOffset, D.StartBitOffset + SizeBit});
-  }
-
-  void VisitArray(const ConstantArrayType *AT, uint64_t StartBitOffset) {
-    for (uint64_t ArrIndex = 0; ArrIndex < AT->getSize().getLimitedValue();
-         ++ArrIndex) {
-
-      QualType ElementQualType = AT->getElementType();
-      auto ElementSize = CGF.getContext().getTypeSizeInChars(ElementQualType);
-      auto ElementAlign = 
CGF.getContext().getTypeAlignInChars(ElementQualType);
-      auto Offset = ElementSize.alignTo(ElementAlign);
-
-      Stack.push_back(
-          Data{StartBitOffset + ArrIndex * Offset.getQuantity() * CharWidth,
-               ElementQualType, /*VisitVirtualBase*/ true});
-    }
-  }
-
-  void VisitStruct(const RecordDecl *R, uint64_t StartBitOffset,
-                   bool VisitVirtualBase) {
-    const auto &DL = CGF.CGM.getModule().getDataLayout();
-    const ASTRecordLayout &ASTLayout = CGF.getContext().getASTRecordLayout(R);
-
-    auto *CXXRecord = dyn_cast<CXXRecordDecl>(R);
-
-    if (CXXRecord) {
-      if (ASTLayout.hasOwnVFPtr()) {
-        OccuppiedIntervals.push_back(BitInterval{
-            StartBitOffset, StartBitOffset + DL.getPointerSizeInBits()});
-      }
-
-      if (ASTLayout.hasOwnVBPtr()) {
-        auto Offset = ASTLayout.getVBPtrOffset().getQuantity();
-        auto StartVBPtr = StartBitOffset + Offset * CharWidth;
-        OccuppiedIntervals.push_back(
-            BitInterval{StartVBPtr, StartVBPtr + DL.getPointerSizeInBits()});
-      }
-
-      const auto VisitBase = [&ASTLayout, StartBitOffset, this](
-                                 const CXXBaseSpecifier &Base, auto GetOffset) 
{
-        auto *BaseRecord = Base.getType()->getAsCXXRecordDecl();
-        if (!BaseRecord) {
-          return;
-        }
-        auto BaseOffset =
-            std::invoke(GetOffset, ASTLayout, BaseRecord).getQuantity();
-
-        Stack.push_back(Data{StartBitOffset + BaseOffset * CharWidth,
-                             Base.getType(), /*VisitVirtualBase*/ false});
-      };
-
-      for (auto Base : CXXRecord->bases()) {
-        if (!Base.isVirtual()) {
-          VisitBase(Base, &ASTRecordLayout::getBaseClassOffset);
-        }
-      }
-
-      if (VisitVirtualBase) {
-        for (auto VBase : CXXRecord->vbases()) {
-          VisitBase(VBase, &ASTRecordLayout::getVBaseClassOffset);
-        }
-      }
-    }
-
-    for (auto *Field : R->fields()) {
-      // Treat unnamed bitfields as padding.
-      if (Field->isUnnamedBitField())
-        continue;
-
-      auto FieldOffset = ASTLayout.getFieldOffset(Field->getFieldIndex());
-      if (Field->isBitField()) {
-        OccuppiedIntervals.push_back(BitInterval{
-            StartBitOffset + FieldOffset,
-            StartBitOffset + FieldOffset + Field->getBitWidthValue()});
-      } else {
-        Stack.push_back(Data{StartBitOffset + FieldOffset, Field->getType(),
-                             /*VisitVirtualBase*/ true});
-      }
-    }
-  }
-
-  void VisitComplex(const ComplexType *CT, uint64_t StartBitOffset) {
-    QualType ElementQualType = CT->getElementType();
-    auto ElementSize = CGF.getContext().getTypeSizeInChars(ElementQualType);
-    auto ElementAlign = CGF.getContext().getTypeAlignInChars(ElementQualType);
-    auto ImgOffset = ElementSize.alignTo(ElementAlign);
-
-    Stack.push_back(
-        Data{StartBitOffset, ElementQualType, /*VisitVirtualBase*/ true});
-    Stack.push_back(Data{StartBitOffset + ImgOffset.getQuantity() * CharWidth,
-                         ElementQualType, /*VisitVirtualBase*/ true});
-  }
-
-  void VisitVector(const clang::VectorType *VT, uint64_t StartBitOffset) {
-    ASTContext &Ctx = CGF.getContext();
-    uint64_t SizeBit = [&]() -> uint64_t {
-      if (VT->isPackedVectorBoolType(Ctx))
-        return VT->getNumElements();
-      return getScalarOccupiedSizeInBits(VT->getElementType()) *
-             VT->getNumElements();
-    }();
-    OccuppiedIntervals.push_back(
-        BitInterval{StartBitOffset, StartBitOffset + SizeBit});
-  }
-
-  void MergeOccuppiedIntervals() {
-    std::sort(OccuppiedIntervals.begin(), OccuppiedIntervals.end(),
-              [](const BitInterval &lhs, const BitInterval &rhs) {
-                return std::tie(lhs.First, lhs.Last) <
-                       std::tie(rhs.First, rhs.Last);
-              });
-
-    llvm::SmallVector<BitInterval> Merged;
-    Merged.reserve(OccuppiedIntervals.size());
-
-    for (const BitInterval &NextInterval : OccuppiedIntervals) {
-      if (Merged.empty()) {
-        Merged.push_back(NextInterval);
-        continue;
-      }
-      auto &LastInterval = Merged.back();
-
-      if (NextInterval.First > LastInterval.Last) {
-        Merged.push_back(NextInterval);
-      } else {
-        LastInterval.Last = std::max(LastInterval.Last, NextInterval.Last);
-      }
-    }
-
-    OccuppiedIntervals = Merged;
-  }
-
-  llvm::SmallVector<BitInterval>
-  GetPaddingIntervals(uint64_t SizeInBits) const {
-    llvm::SmallVector<BitInterval> Results;
-    if (OccuppiedIntervals.size() == 1 &&
-        OccuppiedIntervals.front().First == 0 &&
-        OccuppiedIntervals.front().Last == SizeInBits) {
-      return Results;
-    }
-    Results.reserve(OccuppiedIntervals.size() + 1);
-    uint64_t CurrentPos = 0;
-    for (const BitInterval &OccupiedInterval : OccuppiedIntervals) {
-      if (OccupiedInterval.First > CurrentPos) {
-        Results.push_back(BitInterval{CurrentPos, OccupiedInterval.First});
-      }
-      CurrentPos = OccupiedInterval.Last;
-    }
-    if (SizeInBits > CurrentPos) {
-      Results.push_back(BitInterval{CurrentPos, SizeInBits});
-    }
-    return Results;
-  }
-
-  void ClearPadding(Address Src, const BitInterval &PaddingInterval) {
-    auto *I8Ptr =
-        CGF.Builder.CreateBitCast(Src.getBasePointer(), CGF.Int8PtrTy);
-    auto *Zero = ConstantInt::get(CGF.Int8Ty, 0);
-
-    // Calculate byte indices and bit positions
-    auto StartByte = PaddingInterval.First / CharWidth;
-    auto StartBit = PaddingInterval.First % CharWidth;
-    auto EndByte = PaddingInterval.Last / CharWidth;
-    auto EndBit = PaddingInterval.Last % CharWidth;
-
-    if (StartByte == EndByte) {
-      // Interval is within a single byte
+static void ClearPadding(CodeGenFunction &CGF, Address Src,
+                         const CodeGenUtils::BitInterval &PaddingInterval) {
+  uint64_t CharWidth = CGF.getContext().getCharWidth();
+
+  auto *I8Ptr = CGF.Builder.CreateBitCast(Src.getBasePointer(), CGF.Int8PtrTy);
+  auto *Zero = ConstantInt::get(CGF.Int8Ty, 0);
+
+  // Calculate byte indices and bit positions
+  auto StartByte = PaddingInterval.First / CharWidth;
+  auto StartBit = PaddingInterval.First % CharWidth;
+  auto EndByte = PaddingInterval.Last / CharWidth;
+  auto EndBit = PaddingInterval.Last % CharWidth;
+
+  if (StartByte == EndByte) {
+    // Interval is within a single byte
+    auto *Index = ConstantInt::get(CGF.IntTy, StartByte);
+    auto *Element = CGF.Builder.CreateGEP(CGF.Int8Ty, I8Ptr, Index);
+    Address ElementAddr(Element, CGF.Int8Ty,
+                        Src.getAlignment().alignmentAtOffset(
+                            CharUnits::fromQuantity(StartByte)));
+
+    auto *Value = CGF.Builder.CreateLoad(ElementAddr);
+
+    // Create mask to clear bits within the byte
+    // We want to clear bits from StartBit to EndBit-1
+    uint8_t bitsToClear = ((1 << EndBit) - 1) & ~((1 << StartBit) - 1);
+    uint8_t bitsToKeep = ~bitsToClear;
+    auto *MaskValue = ConstantInt::get(CGF.Int8Ty, bitsToKeep);
+    auto *NewValue = CGF.Builder.CreateAnd(Value, MaskValue);
+
+    CGF.Builder.CreateStore(NewValue, ElementAddr);
+  } else {
+    // Handle the start byte
+    if (StartBit != 0) {
       auto *Index = ConstantInt::get(CGF.IntTy, StartByte);
       auto *Element = CGF.Builder.CreateGEP(CGF.Int8Ty, I8Ptr, Index);
       Address ElementAddr(Element, CGF.Int8Ty,
@@ -2877,72 +2641,45 @@ struct PaddingClearer {
 
       auto *Value = CGF.Builder.CreateLoad(ElementAddr);
 
-      // Create mask to clear bits within the byte
-      // We want to clear bits from StartBit to EndBit-1
-      uint8_t bitsToClear = ((1 << EndBit) - 1) & ~((1 << StartBit) - 1);
+      uint8_t bitsToClear = ((1 << (CharWidth - StartBit)) - 1) << StartBit;
       uint8_t bitsToKeep = ~bitsToClear;
       auto *MaskValue = ConstantInt::get(CGF.Int8Ty, bitsToKeep);
       auto *NewValue = CGF.Builder.CreateAnd(Value, MaskValue);
 
       CGF.Builder.CreateStore(NewValue, ElementAddr);
-    } else {
-      // Handle the start byte
-      if (StartBit != 0) {
-        auto *Index = ConstantInt::get(CGF.IntTy, StartByte);
-        auto *Element = CGF.Builder.CreateGEP(CGF.Int8Ty, I8Ptr, Index);
-        Address ElementAddr(Element, CGF.Int8Ty,
-                            Src.getAlignment().alignmentAtOffset(
-                                CharUnits::fromQuantity(StartByte)));
-
-        auto *Value = CGF.Builder.CreateLoad(ElementAddr);
-
-        uint8_t bitsToClear = ((1 << (CharWidth - StartBit)) - 1) << StartBit;
-        uint8_t bitsToKeep = ~bitsToClear;
-        auto *MaskValue = ConstantInt::get(CGF.Int8Ty, bitsToKeep);
-        auto *NewValue = CGF.Builder.CreateAnd(Value, MaskValue);
-
-        CGF.Builder.CreateStore(NewValue, ElementAddr);
-        ++StartByte;
-      }
+      ++StartByte;
+    }
 
-      // Handle full bytes in the middle
-      for (auto Offset = StartByte; Offset < EndByte; ++Offset) {
-        auto *Index = ConstantInt::get(CGF.IntTy, Offset);
-        auto *Element = CGF.Builder.CreateGEP(CGF.Int8Ty, I8Ptr, Index);
-        Address ElementAddr(Element, CGF.Int8Ty,
-                            Src.getAlignment().alignmentAtOffset(
-                                CharUnits::fromQuantity(Offset)));
+    // Handle full bytes in the middle
+    for (auto Offset = StartByte; Offset < EndByte; ++Offset) {
+      auto *Index = ConstantInt::get(CGF.IntTy, Offset);
+      auto *Element = CGF.Builder.CreateGEP(CGF.Int8Ty, I8Ptr, Index);
+      Address ElementAddr(Element, CGF.Int8Ty,
+                          Src.getAlignment().alignmentAtOffset(
+                              CharUnits::fromQuantity(Offset)));
 
-        CGF.Builder.CreateStore(Zero, ElementAddr);
-      }
+      CGF.Builder.CreateStore(Zero, ElementAddr);
+    }
 
-      // Handle the end byte
-      if (EndBit != 0) {
-        auto *Index = ConstantInt::get(CGF.IntTy, EndByte);
-        auto *Element = CGF.Builder.CreateGEP(CGF.Int8Ty, I8Ptr, Index);
-        Address ElementAddr(Element, CGF.Int8Ty,
-                            Src.getAlignment().alignmentAtOffset(
-                                CharUnits::fromQuantity(EndByte)));
+    // Handle the end byte
+    if (EndBit != 0) {
+      auto *Index = ConstantInt::get(CGF.IntTy, EndByte);
+      auto *Element = CGF.Builder.CreateGEP(CGF.Int8Ty, I8Ptr, Index);
+      Address ElementAddr(Element, CGF.Int8Ty,
+                          Src.getAlignment().alignmentAtOffset(
+                              CharUnits::fromQuantity(EndByte)));
 
-        auto *Value = CGF.Builder.CreateLoad(ElementAddr);
+      auto *Value = CGF.Builder.CreateLoad(ElementAddr);
 
-        uint8_t bitsToClear = (1 << EndBit) - 1;
-        uint8_t bitsToKeep = ~bitsToClear;
-        auto *MaskValue = ConstantInt::get(CGF.Int8Ty, bitsToKeep);
-        auto *NewValue = CGF.Builder.CreateAnd(Value, MaskValue);
+      uint8_t bitsToClear = (1 << EndBit) - 1;
+      uint8_t bitsToKeep = ~bitsToClear;
+      auto *MaskValue = ConstantInt::get(CGF.Int8Ty, bitsToKeep);
+      auto *NewValue = CGF.Builder.CreateAnd(Value, MaskValue);
 
-        CGF.Builder.CreateStore(NewValue, ElementAddr);
-      }
+      CGF.Builder.CreateStore(NewValue, ElementAddr);
     }
   }
-
-  CodeGenFunction &CGF;
-  const uint64_t CharWidth;
-  llvm::SmallVector<Data> Stack;
-  llvm::SmallVector<BitInterval> OccuppiedIntervals;
-};
-
-} // namespace
+}
 
 RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned 
BuiltinID,
                                         const CallExpr *E,
@@ -5473,8 +5210,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl 
GD, unsigned BuiltinID,
   case Builtin::BI__builtin_clear_padding: {
     Address Src = EmitPointerWithAlignment(E->getArg(0));
     auto PointeeTy = E->getArg(0)->getType()->getPointeeType();
-    PaddingClearer clearer{*this};
-    clearer.run(Src, PointeeTy);
+
+    llvm::SmallVector<CodeGenUtils::BitInterval> Padding =
+        CodeGenUtils::CalculatePaddingIntervals(
+            getContext(), getTarget(), PointeeTy,
+            CGM.getDataLayout().getPointerSizeInBits());
+    for (const auto &Interval : Padding)
+      ClearPadding(*this, Src, Interval);
+
     return RValue::get(nullptr);
   }
   case Builtin::BI__sync_fetch_and_add:

>From b0dd9b3514156e4542021572c33b1d527082ce64 Mon Sep 17 00:00:00 2001
From: erichkeane <[email protected]>
Date: Wed, 12 Aug 2026 09:02:52 -0700
Subject: [PATCH 2/5] Make generator function inline so that CIR can use it
 without being a duplicate symbol :)

---
 clang/include/clang/CodeGenUtils/CodeGenUtils.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/include/clang/CodeGenUtils/CodeGenUtils.h 
b/clang/include/clang/CodeGenUtils/CodeGenUtils.h
index 2da4ddc5aea36..21c0d2de37978 100644
--- a/clang/include/clang/CodeGenUtils/CodeGenUtils.h
+++ b/clang/include/clang/CodeGenUtils/CodeGenUtils.h
@@ -273,7 +273,7 @@ struct PaddingCalculator {
 };
 
 // Calculate and gets the 'padding intervals' inside of a type.
-llvm::SmallVector<BitInterval>
+inline llvm::SmallVector<BitInterval>
 CalculatePaddingIntervals(const ASTContext &Ctx, const TargetInfo &TI,
                           QualType Ty, unsigned PointerSizeInBits) {
   PaddingCalculator pc{Ctx, TI, PointerSizeInBits};

>From d9b3fc8c7b055f11a5f2a7f18fdee5eb25b12a97 Mon Sep 17 00:00:00 2001
From: erichkeane <[email protected]>
Date: Wed, 12 Aug 2026 12:13:01 -0700
Subject: [PATCH 3/5] Move bit calculations to ASTContext

---
 clang/include/clang/AST/ASTContext.h          |  13 +
 .../include/clang/CodeGenUtils/CodeGenUtils.h | 283 ------------------
 clang/lib/AST/ASTContext.cpp                  | 273 +++++++++++++++++
 clang/lib/CodeGen/CGBuiltin.cpp               |   9 +-
 4 files changed, 289 insertions(+), 289 deletions(-)
 delete mode 100644 clang/include/clang/CodeGenUtils/CodeGenUtils.h

diff --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index 42c9aa0fcf73b..be0d76dabb249 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1881,7 +1881,20 @@ class ASTContext : public RefCountedBase<ASTContext> {
 
   QualType adjustStringLiteralBaseType(QualType StrLTy) const;
 
+  // Represents an inclusive-first/exclusive last bit-offset into a type.
+  struct BitInterval {
+    // [First, Last)
+    uint64_t First;
+    uint64_t Last;
+  };
+
+  // Calculate and get the 'padding intervals' inside of a type.
+  llvm::SmallVector<BitInterval> getPaddingIntervals(QualType Ty) const;
+
 private:
+  mutable llvm::DenseMap<QualType, llvm::SmallVector<BitInterval>>
+      PaddingIntervalCache;
+
   /// Return a normal function type with a typed argument list.
   QualType getFunctionTypeInternal(QualType ResultTy, ArrayRef<QualType> Args,
                                    const FunctionProtoType::ExtProtoInfo &EPI,
diff --git a/clang/include/clang/CodeGenUtils/CodeGenUtils.h 
b/clang/include/clang/CodeGenUtils/CodeGenUtils.h
deleted file mode 100644
index 21c0d2de37978..0000000000000
--- a/clang/include/clang/CodeGenUtils/CodeGenUtils.h
+++ /dev/null
@@ -1,283 +0,0 @@
-//===--- CodeGenUtils.h - Shared Classic CodeGen/CIR CodeGen Utils--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
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Type.h"
-#include "clang/Basic/TargetInfo.h"
-#include "llvm/ADT/APFloat.h"
-
-#include <algorithm>
-#include <utility>
-
-namespace clang::CodeGenUtils {
-// A type that helps represent a padding interval.
-struct BitInterval {
-  // [First, Last)
-  uint64_t First;
-  uint64_t Last;
-};
-
-// PaddingCalculator is a utility class that calculates the padding bits in a
-// c/c++ type. It traverses the type recursively, collecting occupied
-// bit intervals, and then computes the padding intervals.
-// If a byte only contains some padding bits, it gets intervals for only those
-// bits. This is the case for bit-fields.
-struct PaddingCalculator {
-  PaddingCalculator(const ASTContext &Ctx, const TargetInfo &TI,
-                    unsigned PointerSizeInBits)
-      : Ctx(Ctx), TI(TI), PointerSizeInBits(PointerSizeInBits) {}
-
-  void run(QualType Ty) {
-    OccuppiedIntervals.clear();
-    Stack.clear();
-
-    TySizeInBits = Ctx.getTypeSize(Ty);
-
-    Stack.push_back(Data{0, Ty, true});
-    while (!Stack.empty()) {
-      Data Current = Stack.back();
-      Stack.pop_back();
-      Visit(Current);
-    }
-    MergeOccuppiedIntervals();
-  }
-
-  llvm::SmallVector<BitInterval> GetPaddingIntervals() {
-    llvm::SmallVector<BitInterval> Results;
-    if (OccuppiedIntervals.size() == 1 &&
-        OccuppiedIntervals.front().First == 0 &&
-        OccuppiedIntervals.front().Last == TySizeInBits) {
-      return Results;
-    }
-    Results.reserve(OccuppiedIntervals.size() + 1);
-    uint64_t CurrentPos = 0;
-    for (const BitInterval &OccupiedInterval : OccuppiedIntervals) {
-      if (OccupiedInterval.First > CurrentPos) {
-        Results.push_back(BitInterval{CurrentPos, OccupiedInterval.First});
-      }
-      CurrentPos = OccupiedInterval.Last;
-    }
-    if (TySizeInBits > CurrentPos) {
-      Results.push_back(BitInterval{CurrentPos, TySizeInBits});
-    }
-    return Results;
-  }
-
-private:
-  struct Data {
-    uint64_t StartBitOffset;
-    QualType Ty;
-    bool VisitVirtualBase;
-  };
-
-  // Return the number of non padding bits of a scalar type.
-  //
-  // The property that we specifically care about here is whether the scalar
-  // type has padding bits, i.e. are there bits in the type which are not
-  // specified by the ABI.
-  //
-  // We currently don't care about this anywhere else in clang: layout cares
-  // about the ABI size, calling convention code cares about specific types,
-  // but nothing cares about padding specifically. And it's not something we 
can
-  // easily query from LLVM due to the type system mismatches.
-  // DL.getTypeSizeInBits(convertTypeForLoadStore(T)) is probably close, but 
the
-  // DataLayout methods aren't really designed for this usage.
-  //
-  // Therefore, it is better to explicitly list all the scalar types
-  // containing padding bits that we know of, namely, _BitInt(N) and x87 long
-  // double.
-  uint64_t getScalarOccupiedSizeInBits(QualType Ty) const {
-    if (const auto *BIT = Ty->getAs<BitIntType>())
-      return BIT->getNumBits();
-
-    if (const auto *BT = Ty->getAs<BuiltinType>()) {
-      if (BT->getKind() == BuiltinType::LongDouble &&
-          &TI.getLongDoubleFormat() == &llvm::APFloat::x87DoubleExtended())
-        return llvm::APFloat::getSizeInBits(TI.getLongDoubleFormat());
-    }
-
-    return Ctx.getTypeSize(Ty);
-  }
-
-  void Visit(const Data &D) {
-    if (auto *AT = dyn_cast<ConstantArrayType>(D.Ty)) {
-      VisitArray(AT, D.StartBitOffset);
-      return;
-    }
-
-    if (auto *Record = D.Ty->getAsRecordDecl()) {
-      VisitStruct(Record, D.StartBitOffset, D.VisitVirtualBase);
-      return;
-    }
-
-    if (D.Ty->isAtomicType()) {
-      auto Unwrapped = D;
-      Unwrapped.Ty = D.Ty.getAtomicUnqualifiedType();
-      Stack.push_back(Unwrapped);
-      return;
-    }
-
-    if (const auto *Complex = D.Ty->getAs<ComplexType>()) {
-      VisitComplex(Complex, D.StartBitOffset);
-      return;
-    }
-
-    if (const auto *VT = D.Ty->getAs<clang::VectorType>()) {
-      VisitVector(VT, D.StartBitOffset);
-      return;
-    }
-
-    uint64_t SizeBit = getScalarOccupiedSizeInBits(D.Ty);
-    OccuppiedIntervals.push_back(
-        BitInterval{D.StartBitOffset, D.StartBitOffset + SizeBit});
-  }
-
-  void VisitArray(const ConstantArrayType *AT, uint64_t StartBitOffset) {
-    for (uint64_t ArrIndex = 0; ArrIndex < AT->getSize().getLimitedValue();
-         ++ArrIndex) {
-
-      QualType ElementQualType = AT->getElementType();
-      auto ElementSize = Ctx.getTypeSizeInChars(ElementQualType);
-      auto ElementAlign = Ctx.getTypeAlignInChars(ElementQualType);
-      auto Offset = ElementSize.alignTo(ElementAlign);
-
-      Stack.push_back(Data{StartBitOffset + ArrIndex * Offset.getQuantity() *
-                                                Ctx.getCharWidth(),
-                           ElementQualType, /*VisitVirtualBase*/ true});
-    }
-  }
-
-  void VisitStruct(const RecordDecl *R, uint64_t StartBitOffset,
-                   bool VisitVirtualBase) {
-    const ASTRecordLayout &ASTLayout = Ctx.getASTRecordLayout(R);
-    auto *CXXRecord = dyn_cast<CXXRecordDecl>(R);
-
-    if (CXXRecord) {
-      if (ASTLayout.hasOwnVFPtr()) {
-        OccuppiedIntervals.push_back(
-            BitInterval{StartBitOffset, StartBitOffset + PointerSizeInBits});
-      }
-
-      if (ASTLayout.hasOwnVBPtr()) {
-        auto Offset = ASTLayout.getVBPtrOffset().getQuantity();
-        auto StartVBPtr = StartBitOffset + Offset * Ctx.getCharWidth();
-        OccuppiedIntervals.push_back(
-            BitInterval{StartVBPtr, StartVBPtr + PointerSizeInBits});
-      }
-
-      const auto VisitBase = [&ASTLayout, StartBitOffset, this](
-                                 const CXXBaseSpecifier &Base, auto GetOffset) 
{
-        auto *BaseRecord = Base.getType()->getAsCXXRecordDecl();
-        if (!BaseRecord) {
-          return;
-        }
-        auto BaseOffset =
-            std::invoke(GetOffset, ASTLayout, BaseRecord).getQuantity();
-
-        Stack.push_back(Data{StartBitOffset + BaseOffset * Ctx.getCharWidth(),
-                             Base.getType(), /*VisitVirtualBase*/ false});
-      };
-
-      for (auto Base : CXXRecord->bases()) {
-        if (!Base.isVirtual()) {
-          VisitBase(Base, &ASTRecordLayout::getBaseClassOffset);
-        }
-      }
-
-      if (VisitVirtualBase) {
-        for (auto VBase : CXXRecord->vbases()) {
-          VisitBase(VBase, &ASTRecordLayout::getVBaseClassOffset);
-        }
-      }
-    }
-
-    for (auto *Field : R->fields()) {
-      // Treat unnamed bitfields as padding.
-      if (Field->isUnnamedBitField())
-        continue;
-
-      auto FieldOffset = ASTLayout.getFieldOffset(Field->getFieldIndex());
-      if (Field->isBitField()) {
-        OccuppiedIntervals.push_back(BitInterval{
-            StartBitOffset + FieldOffset,
-            StartBitOffset + FieldOffset + Field->getBitWidthValue()});
-      } else {
-        Stack.push_back(Data{StartBitOffset + FieldOffset, Field->getType(),
-                             /*VisitVirtualBase*/ true});
-      }
-    }
-  }
-
-  void VisitComplex(const ComplexType *CT, uint64_t StartBitOffset) {
-    QualType ElementQualType = CT->getElementType();
-    auto ElementSize = Ctx.getTypeSizeInChars(ElementQualType);
-    auto ElementAlign = Ctx.getTypeAlignInChars(ElementQualType);
-    auto ImgOffset = ElementSize.alignTo(ElementAlign);
-
-    Stack.push_back(
-        Data{StartBitOffset, ElementQualType, /*VisitVirtualBase*/ true});
-    Stack.push_back(
-        Data{StartBitOffset + ImgOffset.getQuantity() * Ctx.getCharWidth(),
-             ElementQualType, /*VisitVirtualBase*/ true});
-  }
-
-  void VisitVector(const clang::VectorType *VT, uint64_t StartBitOffset) {
-    uint64_t SizeBit = [&]() -> uint64_t {
-      if (VT->isPackedVectorBoolType(Ctx))
-        return VT->getNumElements();
-      return getScalarOccupiedSizeInBits(VT->getElementType()) *
-             VT->getNumElements();
-    }();
-    OccuppiedIntervals.push_back(
-        BitInterval{StartBitOffset, StartBitOffset + SizeBit});
-  }
-
-  void MergeOccuppiedIntervals() {
-    std::sort(OccuppiedIntervals.begin(), OccuppiedIntervals.end(),
-              [](const BitInterval &lhs, const BitInterval &rhs) {
-                return std::tie(lhs.First, lhs.Last) <
-                       std::tie(rhs.First, rhs.Last);
-              });
-
-    llvm::SmallVector<BitInterval> Merged;
-    Merged.reserve(OccuppiedIntervals.size());
-
-    for (const BitInterval &NextInterval : OccuppiedIntervals) {
-      if (Merged.empty()) {
-        Merged.push_back(NextInterval);
-        continue;
-      }
-      auto &LastInterval = Merged.back();
-
-      if (NextInterval.First > LastInterval.Last) {
-        Merged.push_back(NextInterval);
-      } else {
-        LastInterval.Last = std::max(LastInterval.Last, NextInterval.Last);
-      }
-    }
-
-    OccuppiedIntervals = Merged;
-  }
-
-  const ASTContext &Ctx;
-  const TargetInfo &TI;
-  unsigned PointerSizeInBits;
-  uint64_t TySizeInBits = 0;
-  llvm::SmallVector<Data> Stack;
-  llvm::SmallVector<BitInterval> OccuppiedIntervals;
-};
-
-// Calculate and gets the 'padding intervals' inside of a type.
-inline llvm::SmallVector<BitInterval>
-CalculatePaddingIntervals(const ASTContext &Ctx, const TargetInfo &TI,
-                          QualType Ty, unsigned PointerSizeInBits) {
-  PaddingCalculator pc{Ctx, TI, PointerSizeInBits};
-  pc.run(Ty);
-  return pc.GetPaddingIntervals();
-}
-} // namespace clang::CodeGenUtils
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 47028c616e45c..847b7a5d94a3c 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -15731,3 +15731,276 @@ void ASTContext::recordOffsetOfEvaluation(const 
OffsetOfExpr *E) {
   if (FieldDecl *FD = Comp.getField(); isPFPField(FD))
     PFPFieldsWithEvaluatedOffset.insert(FD);
 }
+
+namespace {
+// PaddingCalculator is a utility class that calculates the padding bits in a
+// c/c++ type. It traverses the type recursively, collecting occupied
+// bit intervals, and then computes the padding intervals.
+// If a byte only contains some padding bits, it gets intervals for only those
+// bits. This is the case for bit-fields.
+struct PaddingCalculator {
+  PaddingCalculator(const ASTContext &Ctx) : Ctx(Ctx) {}
+
+  void run(QualType Ty) {
+    OccuppiedIntervals.clear();
+    Stack.clear();
+
+    TySizeInBits = Ctx.getTypeSize(Ty);
+
+    Stack.push_back(Data{0, Ty, true});
+    while (!Stack.empty()) {
+      Data Current = Stack.back();
+      Stack.pop_back();
+      Visit(Current);
+    }
+    MergeOccuppiedIntervals();
+  }
+
+  llvm::SmallVector<ASTContext::BitInterval> GetPaddingIntervals() {
+    llvm::SmallVector<ASTContext::BitInterval> Results;
+    if (OccuppiedIntervals.size() == 1 &&
+        OccuppiedIntervals.front().First == 0 &&
+        OccuppiedIntervals.front().Last == TySizeInBits) {
+      return Results;
+    }
+    Results.reserve(OccuppiedIntervals.size() + 1);
+    uint64_t CurrentPos = 0;
+    for (const ASTContext::BitInterval &OccupiedInterval : OccuppiedIntervals) 
{
+      if (OccupiedInterval.First > CurrentPos) {
+        Results.push_back(
+            ASTContext::BitInterval{CurrentPos, OccupiedInterval.First});
+      }
+      CurrentPos = OccupiedInterval.Last;
+    }
+    if (TySizeInBits > CurrentPos) {
+      Results.push_back(ASTContext::BitInterval{CurrentPos, TySizeInBits});
+    }
+    return Results;
+  }
+
+private:
+  struct Data {
+    uint64_t StartBitOffset;
+    QualType Ty;
+    bool VisitVirtualBase;
+  };
+
+  // Return the number of non padding bits of a scalar type.
+  //
+  // The property that we specifically care about here is whether the scalar
+  // type has padding bits, i.e. are there bits in the type which are not
+  // specified by the ABI.
+  //
+  // We currently don't care about this anywhere else in clang: layout cares
+  // about the ABI size, calling convention code cares about specific types,
+  // but nothing cares about padding specifically. And it's not something we 
can
+  // easily query from LLVM due to the type system mismatches.
+  // DL.getTypeSizeInBits(convertTypeForLoadStore(T)) is probably close, but 
the
+  // DataLayout methods aren't really designed for this usage.
+  //
+  // Therefore, it is better to explicitly list all the scalar types
+  // containing padding bits that we know of, namely, _BitInt(N) and x87 long
+  // double.
+  uint64_t getScalarOccupiedSizeInBits(QualType Ty) const {
+    if (const auto *BIT = Ty->getAs<BitIntType>())
+      return BIT->getNumBits();
+
+    if (const auto *BT = Ty->getAs<BuiltinType>()) {
+      if (BT->getKind() == BuiltinType::LongDouble &&
+          &Ctx.getTargetInfo().getLongDoubleFormat() ==
+              &llvm::APFloat::x87DoubleExtended())
+        return llvm::APFloat::getSizeInBits(
+            Ctx.getTargetInfo().getLongDoubleFormat());
+    }
+
+    return Ctx.getTypeSize(Ty);
+  }
+
+  void Visit(const Data &D) {
+    if (auto *AT = dyn_cast<ConstantArrayType>(D.Ty)) {
+      VisitArray(AT, D.StartBitOffset);
+      return;
+    }
+
+    if (auto *Record = D.Ty->getAsRecordDecl()) {
+      VisitStruct(Record, D.StartBitOffset, D.VisitVirtualBase);
+      return;
+    }
+
+    if (D.Ty->isAtomicType()) {
+      auto Unwrapped = D;
+      Unwrapped.Ty = D.Ty.getAtomicUnqualifiedType();
+      Stack.push_back(Unwrapped);
+      return;
+    }
+
+    if (const auto *Complex = D.Ty->getAs<ComplexType>()) {
+      VisitComplex(Complex, D.StartBitOffset);
+      return;
+    }
+
+    if (const auto *VT = D.Ty->getAs<clang::VectorType>()) {
+      VisitVector(VT, D.StartBitOffset);
+      return;
+    }
+
+    uint64_t SizeBit = getScalarOccupiedSizeInBits(D.Ty);
+    OccuppiedIntervals.push_back(
+        ASTContext::BitInterval{D.StartBitOffset, D.StartBitOffset + SizeBit});
+  }
+
+  void VisitArray(const ConstantArrayType *AT, uint64_t StartBitOffset) {
+    for (uint64_t ArrIndex = 0; ArrIndex < AT->getSize().getLimitedValue();
+         ++ArrIndex) {
+
+      QualType ElementQualType = AT->getElementType();
+      auto ElementSize = Ctx.getTypeSizeInChars(ElementQualType);
+      auto ElementAlign = Ctx.getTypeAlignInChars(ElementQualType);
+      auto Offset = ElementSize.alignTo(ElementAlign);
+
+      Stack.push_back(Data{StartBitOffset + ArrIndex * Offset.getQuantity() *
+                                                Ctx.getCharWidth(),
+                           ElementQualType, /*VisitVirtualBase*/ true});
+    }
+  }
+
+  void VisitStruct(const RecordDecl *R, uint64_t StartBitOffset,
+                   bool VisitVirtualBase) {
+    const ASTRecordLayout &ASTLayout = Ctx.getASTRecordLayout(R);
+    auto *CXXRecord = dyn_cast<CXXRecordDecl>(R);
+
+    unsigned PointerSizeInBits = Ctx.getTypeSize(Ctx.NullPtrTy);
+
+    if (CXXRecord) {
+      if (ASTLayout.hasOwnVFPtr()) {
+        OccuppiedIntervals.push_back(ASTContext::BitInterval{
+            StartBitOffset, StartBitOffset + PointerSizeInBits});
+      }
+
+      if (ASTLayout.hasOwnVBPtr()) {
+        auto Offset = ASTLayout.getVBPtrOffset().getQuantity();
+        auto StartVBPtr = StartBitOffset + Offset * Ctx.getCharWidth();
+        OccuppiedIntervals.push_back(ASTContext::BitInterval{
+            StartVBPtr, StartVBPtr + PointerSizeInBits});
+      }
+
+      const auto VisitBase = [&ASTLayout, StartBitOffset, this](
+                                 const CXXBaseSpecifier &Base, auto GetOffset) 
{
+        auto *BaseRecord = Base.getType()->getAsCXXRecordDecl();
+        if (!BaseRecord) {
+          return;
+        }
+        auto BaseOffset =
+            std::invoke(GetOffset, ASTLayout, BaseRecord).getQuantity();
+
+        Stack.push_back(Data{StartBitOffset + BaseOffset * Ctx.getCharWidth(),
+                             Base.getType(), /*VisitVirtualBase*/
+                             false});
+      };
+
+      for (auto Base : CXXRecord->bases()) {
+        if (!Base.isVirtual()) {
+          VisitBase(Base, &ASTRecordLayout::getBaseClassOffset);
+        }
+      }
+
+      if (VisitVirtualBase) {
+        for (auto VBase : CXXRecord->vbases()) {
+          VisitBase(VBase, &ASTRecordLayout::getVBaseClassOffset);
+        }
+      }
+    }
+
+    for (auto *Field : R->fields()) {
+      // Treat unnamed bitfields as padding.
+      if (Field->isUnnamedBitField())
+        continue;
+
+      auto FieldOffset = ASTLayout.getFieldOffset(Field->getFieldIndex());
+      if (Field->isBitField()) {
+        OccuppiedIntervals.push_back(ASTContext::BitInterval{
+            StartBitOffset + FieldOffset,
+            StartBitOffset + FieldOffset + Field->getBitWidthValue()});
+      } else {
+        Stack.push_back(Data{StartBitOffset + FieldOffset, Field->getType(),
+                             /*VisitVirtualBase*/ true});
+      }
+    }
+  }
+
+  void VisitComplex(const ComplexType *CT, uint64_t StartBitOffset) {
+    QualType ElementQualType = CT->getElementType();
+    auto ElementSize = Ctx.getTypeSizeInChars(ElementQualType);
+    auto ElementAlign = Ctx.getTypeAlignInChars(ElementQualType);
+    auto ImgOffset = ElementSize.alignTo(ElementAlign);
+
+    Stack.push_back(
+        Data{StartBitOffset, ElementQualType, /*VisitVirtualBase*/ true});
+    Stack.push_back(
+        Data{StartBitOffset + ImgOffset.getQuantity() * Ctx.getCharWidth(),
+             ElementQualType, /*VisitVirtualBase*/ true});
+  }
+
+  void VisitVector(const clang::VectorType *VT, uint64_t StartBitOffset) {
+    uint64_t SizeBit = [&]() -> uint64_t {
+      if (VT->isPackedVectorBoolType(Ctx))
+        return VT->getNumElements();
+      return getScalarOccupiedSizeInBits(VT->getElementType()) *
+             VT->getNumElements();
+    }();
+    OccuppiedIntervals.push_back(
+        ASTContext::BitInterval{StartBitOffset, StartBitOffset + SizeBit});
+  }
+
+  void MergeOccuppiedIntervals() {
+    std::sort(OccuppiedIntervals.begin(), OccuppiedIntervals.end(),
+              [](const ASTContext::BitInterval &lhs,
+                 const ASTContext::BitInterval &rhs) {
+                return std::tie(lhs.First, lhs.Last) <
+                       std::tie(rhs.First, rhs.Last);
+              });
+
+    llvm::SmallVector<ASTContext::BitInterval> Merged;
+    Merged.reserve(OccuppiedIntervals.size());
+
+    for (const ASTContext::BitInterval &NextInterval : OccuppiedIntervals) {
+      if (Merged.empty()) {
+        Merged.push_back(NextInterval);
+        continue;
+      }
+      auto &LastInterval = Merged.back();
+
+      if (NextInterval.First > LastInterval.Last) {
+        Merged.push_back(NextInterval);
+      } else {
+        LastInterval.Last = std::max(LastInterval.Last, NextInterval.Last);
+      }
+    }
+
+    OccuppiedIntervals = Merged;
+  }
+
+  const ASTContext &Ctx;
+  //  unsigned PointerSizeInBits;
+  uint64_t TySizeInBits = 0;
+  llvm::SmallVector<Data> Stack;
+  llvm::SmallVector<ASTContext::BitInterval> OccuppiedIntervals;
+};
+} // namespace
+
+llvm::SmallVector<ASTContext::BitInterval>
+ASTContext::getPaddingIntervals(QualType Ty) const {
+  Ty = Ty.getCanonicalType();
+  auto cached = PaddingIntervalCache.find(Ty);
+  if (cached != PaddingIntervalCache.end())
+    return cached->second;
+
+  PaddingCalculator pc{*this};
+  pc.run(Ty);
+
+  auto result = pc.GetPaddingIntervals();
+  auto [itr, res] = PaddingIntervalCache.insert_or_assign(Ty, result);
+  assert(res && "Failed to insert?");
+
+  return result;
+}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 9fa54b8f18b13..92c711a4a7062 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -28,7 +28,6 @@
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/DiagnosticFrontend.h"
 #include "clang/Basic/TargetInfo.h"
-#include "clang/CodeGenUtils/CodeGenUtils.h"
 #include "llvm/ADT/APFloat.h"
 #include "llvm/IR/InlineAsm.h"
 #include "llvm/IR/Instruction.h"
@@ -2600,7 +2599,7 @@ RValue CodeGenFunction::emitStdcFirstBit(const CallExpr 
*E, Intrinsic::ID IntID,
 }
 
 static void ClearPadding(CodeGenFunction &CGF, Address Src,
-                         const CodeGenUtils::BitInterval &PaddingInterval) {
+                         const ASTContext::BitInterval &PaddingInterval) {
   uint64_t CharWidth = CGF.getContext().getCharWidth();
 
   auto *I8Ptr = CGF.Builder.CreateBitCast(Src.getBasePointer(), CGF.Int8PtrTy);
@@ -5211,10 +5210,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl 
GD, unsigned BuiltinID,
     Address Src = EmitPointerWithAlignment(E->getArg(0));
     auto PointeeTy = E->getArg(0)->getType()->getPointeeType();
 
-    llvm::SmallVector<CodeGenUtils::BitInterval> Padding =
-        CodeGenUtils::CalculatePaddingIntervals(
-            getContext(), getTarget(), PointeeTy,
-            CGM.getDataLayout().getPointerSizeInBits());
+    llvm::SmallVector<ASTContext::BitInterval> Padding =
+        getContext().getPaddingIntervals(PointeeTy);
     for (const auto &Interval : Padding)
       ClearPadding(*this, Src, Interval);
 

>From 86f84cedf7786c2a58ed3467ae3fd0c768deec27 Mon Sep 17 00:00:00 2001
From: erichkeane <[email protected]>
Date: Wed, 12 Aug 2026 12:22:31 -0700
Subject: [PATCH 4/5] Change function to return array-ref to prevent copies...
 riskier for anything that wants to store these long-term, but I don't believe
 that to be the  case anywhere

---
 clang/include/clang/AST/ASTContext.h | 6 ++++--
 clang/lib/AST/ASTContext.cpp         | 8 ++++----
 clang/lib/CodeGen/CGBuiltin.cpp      | 2 +-
 3 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index be0d76dabb249..9e3c437f82c3a 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1888,8 +1888,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
     uint64_t Last;
   };
 
-  // Calculate and get the 'padding intervals' inside of a type.
-  llvm::SmallVector<BitInterval> getPaddingIntervals(QualType Ty) const;
+  // Calculate and get the 'padding intervals' inside of a type. Note: calls to
+  // this potentially invalidate all ArrayRef objects, so effort must be made 
to
+  // copy the data if necessary.
+  llvm::ArrayRef<BitInterval> getPaddingIntervals(QualType Ty) const;
 
 private:
   mutable llvm::DenseMap<QualType, llvm::SmallVector<BitInterval>>
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 847b7a5d94a3c..7004a2ad52ad1 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -15988,7 +15988,7 @@ struct PaddingCalculator {
 };
 } // namespace
 
-llvm::SmallVector<ASTContext::BitInterval>
+llvm::ArrayRef<ASTContext::BitInterval>
 ASTContext::getPaddingIntervals(QualType Ty) const {
   Ty = Ty.getCanonicalType();
   auto cached = PaddingIntervalCache.find(Ty);
@@ -15998,9 +15998,9 @@ ASTContext::getPaddingIntervals(QualType Ty) const {
   PaddingCalculator pc{*this};
   pc.run(Ty);
 
-  auto result = pc.GetPaddingIntervals();
-  auto [itr, res] = PaddingIntervalCache.insert_or_assign(Ty, result);
+  auto [itr, res] =
+      PaddingIntervalCache.insert_or_assign(Ty, pc.GetPaddingIntervals());
   assert(res && "Failed to insert?");
 
-  return result;
+  return itr->second;
 }
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 92c711a4a7062..3f7b090315f5e 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -5210,7 +5210,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl 
GD, unsigned BuiltinID,
     Address Src = EmitPointerWithAlignment(E->getArg(0));
     auto PointeeTy = E->getArg(0)->getType()->getPointeeType();
 
-    llvm::SmallVector<ASTContext::BitInterval> Padding =
+    llvm::ArrayRef<ASTContext::BitInterval> Padding =
         getContext().getPaddingIntervals(PointeeTy);
     for (const auto &Interval : Padding)
       ClearPadding(*this, Src, Interval);

>From 1c7368eef9bdff26fa7e489b84f258f328f6c421 Mon Sep 17 00:00:00 2001
From: erichkeane <[email protected]>
Date: Thu, 13 Aug 2026 07:07:57 -0700
Subject: [PATCH 5/5] Use canonical type, add a FIXME to consider more types.

---
 clang/lib/AST/ASTContext.cpp | 29 +++++++++++++++++++----------
 1 file changed, 19 insertions(+), 10 deletions(-)

diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 7004a2ad52ad1..c8625e993110c 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -15747,7 +15747,7 @@ struct PaddingCalculator {
 
     TySizeInBits = Ctx.getTypeSize(Ty);
 
-    Stack.push_back(Data{0, Ty, true});
+    Stack.push_back(Data{0, Ty.getCanonicalType(), true});
     while (!Stack.empty()) {
       Data Current = Stack.back();
       Stack.pop_back();
@@ -15801,6 +15801,13 @@ struct PaddingCalculator {
   // Therefore, it is better to explicitly list all the scalar types
   // containing padding bits that we know of, namely, _BitInt(N) and x87 long
   // double.
+  //
+  // FIXME: There are likely other scalar types we need to think about here, as
+  // brought up in review for #215823:
+  //  - bool
+  //  - enums(both with/without fixed underlying type)
+  //  - nullptr_t
+  //  - more?
   uint64_t getScalarOccupiedSizeInBits(QualType Ty) const {
     if (const auto *BIT = Ty->getAs<BitIntType>())
       return BIT->getNumBits();
@@ -15829,7 +15836,7 @@ struct PaddingCalculator {
 
     if (D.Ty->isAtomicType()) {
       auto Unwrapped = D;
-      Unwrapped.Ty = D.Ty.getAtomicUnqualifiedType();
+      Unwrapped.Ty = D.Ty.getAtomicUnqualifiedType().getCanonicalType();
       Stack.push_back(Unwrapped);
       return;
     }
@@ -15858,9 +15865,9 @@ struct PaddingCalculator {
       auto ElementAlign = Ctx.getTypeAlignInChars(ElementQualType);
       auto Offset = ElementSize.alignTo(ElementAlign);
 
-      Stack.push_back(Data{StartBitOffset + ArrIndex * Offset.getQuantity() *
-                                                Ctx.getCharWidth(),
-                           ElementQualType, /*VisitVirtualBase*/ true});
+      Stack.push_back(Data{
+          StartBitOffset + ArrIndex * Offset.getQuantity() * 
Ctx.getCharWidth(),
+          ElementQualType.getCanonicalType(), /*VisitVirtualBase*/ true});
     }
   }
 
@@ -15893,9 +15900,10 @@ struct PaddingCalculator {
         auto BaseOffset =
             std::invoke(GetOffset, ASTLayout, BaseRecord).getQuantity();
 
-        Stack.push_back(Data{StartBitOffset + BaseOffset * Ctx.getCharWidth(),
-                             Base.getType(), /*VisitVirtualBase*/
-                             false});
+        Stack.push_back(
+            Data{StartBitOffset + BaseOffset * Ctx.getCharWidth(),
+                 Base.getType().getCanonicalType(), /*VisitVirtualBase*/
+                 false});
       };
 
       for (auto Base : CXXRecord->bases()) {
@@ -15922,14 +15930,15 @@ struct PaddingCalculator {
             StartBitOffset + FieldOffset,
             StartBitOffset + FieldOffset + Field->getBitWidthValue()});
       } else {
-        Stack.push_back(Data{StartBitOffset + FieldOffset, Field->getType(),
+        Stack.push_back(Data{StartBitOffset + FieldOffset,
+                             Field->getType().getCanonicalType(),
                              /*VisitVirtualBase*/ true});
       }
     }
   }
 
   void VisitComplex(const ComplexType *CT, uint64_t StartBitOffset) {
-    QualType ElementQualType = CT->getElementType();
+    QualType ElementQualType = CT->getElementType().getCanonicalType();
     auto ElementSize = Ctx.getTypeSizeInChars(ElementQualType);
     auto ElementAlign = Ctx.getTypeAlignInChars(ElementQualType);
     auto ImgOffset = ElementSize.alignTo(ElementAlign);

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

Reply via email to