[clang] [libcxx] [clang] Add builtin to clear padding bytes (prework for P0528R3) (PR #75371)

Eli Friedman via cfe-commits cfe-commits at lists.llvm.org
Mon Jul 15 23:10:38 PDT 2024


================
@@ -2538,6 +2541,311 @@ static RValue EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF,
   return RValue::get(CGF->Builder.CreateCall(UBF, Args));
 }
 
+namespace {
+
+struct PaddingClearer {
+  PaddingClearer(CodeGenFunction &F)
+      : CGF(F), CharWidth(CGF.getContext().getCharWidth()) {}
+
+  void run(Value *Ptr, QualType Ty) {
+    OccuppiedIntervals.clear();
+    Queue.clear();
+
+    Queue.push_back(Data{0, Ty, true});
+    while (!Queue.empty()) {
+      auto Current = Queue.front();
+      Queue.pop_front();
+      Visit(Current);
+    }
+
+    MergeOccuppiedIntervals();
+    auto PaddingIntervals =
+        GetPaddingIntervals(CGF.getContext().getTypeSize(Ty));
+    llvm::dbgs() << "Occuppied Bits:\n";
+    for (auto [first, last] : OccuppiedIntervals) {
+      llvm::dbgs() << "[" << first << ", " << last << ")\n";
+    }
+    llvm::dbgs() << "Padding Bits:\n";
+    for (auto [first, last] : PaddingIntervals) {
+      llvm::dbgs() << "[" << first << ", " << last << ")\n";
+    }
+
+    for (const auto &Interval : PaddingIntervals) {
+      ClearPadding(Ptr, Interval);
+    }
+  }
+
+private:
+  struct BitInterval {
+    // [First, Last)
+    uint64_t First;
+    uint64_t Last;
+  };
+
+  struct Data {
+    uint64_t StartBitOffset;
+    QualType Ty;
+    bool VisitVirtualBase;
+  };
+
+  void Visit(Data const &D) {
+    if (auto *AT = dyn_cast<ConstantArrayType>(D.Ty)) {
+      VisitArray(AT, D.StartBitOffset);
+      return;
+    }
+
+    if (auto *Record = D.Ty->getAsCXXRecordDecl()) {
+      VisitStruct(Record, D.StartBitOffset, D.VisitVirtualBase);
+      return;
+    }
+
+    if (D.Ty->isAtomicType()) {
+      auto Unwrapped = D;
+      Unwrapped.Ty = D.Ty.getAtomicUnqualifiedType();
+      Queue.push_back(Unwrapped);
+      return;
+    }
+
+    if (const auto *Complex = D.Ty->getAs<ComplexType>()) {
+      VisitComplex(Complex, D.StartBitOffset);
+      return;
+    }
+
+    auto *Type = CGF.ConvertTypeForMem(D.Ty);
+    auto SizeBit = CGF.CGM.getModule()
+                       .getDataLayout()
+                       .getTypeSizeInBits(Type)
+                       .getKnownMinValue();
+    llvm::dbgs() << "clear_padding primitive type. adding Interval ["
+                 << D.StartBitOffset << ", " << D.StartBitOffset + SizeBit
+                 << ")\n";
+    OccuppiedIntervals.push_back(
+        BitInterval{D.StartBitOffset, D.StartBitOffset + SizeBit});
+  }
+
+  void VisitArray(const ConstantArrayType *AT, uint64_t StartBitOffset) {
+    llvm::dbgs() << "clear_padding visiting constant array starting from "
+                 << StartBitOffset << "\n";
+    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);
+
+      Queue.push_back(
+          Data{StartBitOffset + ArrIndex * Offset.getQuantity() * CharWidth,
+               ElementQualType, true});
+    }
+  }
+
+  void VisitStruct(const CXXRecordDecl *R, uint64_t StartBitOffset,
+                   bool VisitVirtualBase) {
+    llvm::dbgs() << "clear_padding visiting struct: "
+                 << R->getQualifiedNameAsString() << " starting from offset "
+                 << StartBitOffset << '\n';
+    const auto &DL = CGF.CGM.getModule().getDataLayout();
+
+    const ASTRecordLayout &ASTLayout = CGF.getContext().getASTRecordLayout(R);
+    if (ASTLayout.hasOwnVFPtr()) {
+      llvm::dbgs()
+          << "clear_padding found vtable ptr. Adding occuppied interval ["
+          << StartBitOffset << ", "
+          << (StartBitOffset + DL.getPointerSizeInBits()) << ")\n";
+      OccuppiedIntervals.push_back(BitInterval{
+          StartBitOffset, StartBitOffset + DL.getPointerSizeInBits()});
+    }
+
+    const auto VisitBase = [&ASTLayout, StartBitOffset, this](
+                               const CXXBaseSpecifier &Base, auto GetOffset) {
+      auto *BaseRecord = Base.getType()->getAsCXXRecordDecl();
+      if (!BaseRecord) {
+        llvm::dbgs() << "Base is not a CXXRecord!\n";
+        return;
+      }
+      auto BaseOffset =
+          std::invoke(GetOffset, ASTLayout, BaseRecord).getQuantity();
+
+      llvm::dbgs() << "visiting base at offset " << StartBitOffset << " + "
+                   << BaseOffset * CharWidth << '\n';
+      Queue.push_back(
+          Data{StartBitOffset + BaseOffset * CharWidth, Base.getType(), false});
----------------
efriedma-quic wrote:

```suggestion
          Data{StartBitOffset + BaseOffset * CharWidth, Base.getType(), /*VisitVirtualBase*/false});
```

https://github.com/llvm/llvm-project/pull/75371


More information about the cfe-commits mailing list