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

2024-07-15 Thread Eli Friedman via cfe-commits


@@ -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(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()) {
+  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
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-07-15 Thread Eli Friedman via cfe-commits


@@ -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();

efriedma-quic wrote:

Can you just use back()/pop_back() here (so you don't need an std::deque)?

https://github.com/llvm/llvm-project/pull/75371
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-07-15 Thread Eli Friedman via cfe-commits

https://github.com/efriedma-quic edited 
https://github.com/llvm/llvm-project/pull/75371
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-07-15 Thread Eli Friedman via cfe-commits

https://github.com/efriedma-quic commented:

Bitfield load and store operations should be done using the same offset/size we 
normally use to access the bitfield; unconditionally using byte load/store 
operations will impair optimizations/performance.  I guess this might not be 
possible when unions are involved, but it shouldn't be that hard for the 
non-union cases.

The format of builtin-clear-padding-codegen.cpp seems mostly fine, but consider 
using update_cc_test_checks.py to automate writing the CHECK lines.  Please add 
a couple tests for empty classes and unions.

A few comments in the code outlining how the recursion and the interval 
representation work would be helpful.

https://github.com/llvm/llvm-project/pull/75371
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-07-03 Thread via cfe-commits

https://github.com/huixie90 edited 
https://github.com/llvm/llvm-project/pull/75371
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-07-03 Thread via cfe-commits

huixie90 wrote:

> If you want to modify part of a bitfield unit, you need to load/store the 
> whole bitfield unit, as computed by the CGRecordLayout. This is true whether 
> you're modifying an actual field, or padding adjacent to a field. Since any 
> padding has to be adjacent to a bitfield, you can get the relevant 
> information out of the CGBitFieldInfo for that bitfield.

Hello, this is now working with the bitfield. Iterating over the field of a 
struct also gives me information about where bit fields are

https://github.com/llvm/llvm-project/pull/75371
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-07-03 Thread via cfe-commits

https://github.com/huixie90 edited 
https://github.com/llvm/llvm-project/pull/75371
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-07-03 Thread via cfe-commits

huixie90 wrote:

@efriedma-quic  could you please have a look at the updated version? it works 
for bit field.  May I have some help on how to write these IR tests?  

https://github.com/llvm/llvm-project/pull/75371
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-14 Thread Louis Dionne via cfe-commits

https://github.com/ldionne edited 
https://github.com/llvm/llvm-project/pull/75371
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-14 Thread Eli Friedman via cfe-commits


@@ -2456,6 +2461,139 @@ static RValue 
EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF,
   return RValue::get(CGF->Builder.CreateCall(UBF, Args));
 }
 
+template 
+void RecursivelyClearPaddingImpl(CodeGenFunction &CGF, Value *Ptr, QualType 
Ty, size_t CurrentStartOffset, size_t &RunningOffset, T&& WriteZeroAtOffset);
+
+template 
+void ClearPaddingStruct(CodeGenFunction &CGF, Value *Ptr, QualType Ty, 
StructType *ST, 
+size_t CurrentStartOffset, size_t &RunningOffset, T&& 
WriteZeroAtOffset) {
+  std::cerr << "\n struct! " << ST->getName().data() << std::endl;
+  auto SL = CGF.CGM.getModule().getDataLayout().getStructLayout(ST);
+
+  auto R = dyn_cast(Ty->getAsRecordDecl());
+  if(!R) {
+std::cerr << "\n not a CXXRecordDecl" << std::endl;
+
+  }
+  const ASTRecordLayout &ASTLayout = CGF.getContext().getASTRecordLayout(R);
+  for (auto Base : R->bases()) {

efriedma-quic wrote:

Empty fields that are `[[no_unique_address]]` can be out-of-order, if that 
matters.

https://github.com/llvm/llvm-project/pull/75371
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-14 Thread Eli Friedman via cfe-commits


@@ -2538,6 +2539,205 @@ static RValue 
EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF,
   return RValue::get(CGF->Builder.CreateCall(UBF, Args));
 }
 
+template 
+void RecursivelyClearPaddingImpl(CodeGenFunction &CGF, Value *Ptr, QualType Ty,
+ size_t CurrentStartOffset,
+ size_t &RunningOffset, T &&WriteZeroAtOffset,
+ bool VisitVirtualBase);
+
+template 
+void ClearPaddingStruct(CodeGenFunction &CGF, Value *Ptr, QualType Ty,
+StructType *ST, size_t CurrentStartOffset,
+size_t &RunningOffset, T &&WriteZeroAtOffset,
+bool VisitVirtualBase) {
+  llvm::dbgs() << "clear padding struct: " << ST->getName().data() << '\n';
+  const auto &DL = CGF.CGM.getModule().getDataLayout();
+  auto *SL = DL.getStructLayout(ST);
+  auto *R = dyn_cast(Ty->getAsRecordDecl());
+  if (!R) {
+llvm::dbgs() << "Not a CXXRecordDecl\n";
+return;
+  }
+  const ASTRecordLayout &ASTLayout = CGF.getContext().getASTRecordLayout(R);
+  if (ASTLayout.hasOwnVFPtr()) {
+llvm::dbgs() << "vtable ptr. Incrementing RunningOffset from "
+ << RunningOffset << " to "
+ << RunningOffset + DL.getPointerSizeInBits() / 8 << '\n';
+RunningOffset += DL.getPointerSizeInBits() / 8;
+  }
+  std::vector> Bases;
+  Bases.reserve(R->getNumBases());
+  // todo get vbases
+  for (auto Base : R->bases()) {
+auto *BaseRecord = cast(Base.getType()->getAsRecordDecl());
+if (!Base.isVirtual()) {
+  auto Offset = static_cast(

efriedma-quic wrote:

Don't use size_t for target offsets.  Prefer CharUnits, or if you need a raw 
number for some reason, uint64_t.  (We want to make sure cross-compilation 
works correctly on 32-bit hosts.)

https://github.com/llvm/llvm-project/pull/75371
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-14 Thread Eli Friedman via cfe-commits


@@ -2456,6 +2461,139 @@ static RValue 
EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF,
   return RValue::get(CGF->Builder.CreateCall(UBF, Args));
 }
 
+template 
+void RecursivelyClearPaddingImpl(CodeGenFunction &CGF, Value *Ptr, QualType 
Ty, size_t CurrentStartOffset, size_t &RunningOffset, T&& WriteZeroAtOffset);
+
+template 
+void ClearPaddingStruct(CodeGenFunction &CGF, Value *Ptr, QualType Ty, 
StructType *ST, 
+size_t CurrentStartOffset, size_t &RunningOffset, T&& 
WriteZeroAtOffset) {
+  std::cerr << "\n struct! " << ST->getName().data() << std::endl;
+  auto SL = CGF.CGM.getModule().getDataLayout().getStructLayout(ST);
+
+  auto R = dyn_cast(Ty->getAsRecordDecl());
+  if(!R) {
+std::cerr << "\n not a CXXRecordDecl" << std::endl;
+
+  }
+  const ASTRecordLayout &ASTLayout = CGF.getContext().getASTRecordLayout(R);
+  for (auto Base : R->bases()) {
+std::cerr << "\n\n base!"  << std::endl;
+// Zero padding between base elements.
+auto BaseRecord = cast(Base.getType()->getAsRecordDecl());
+auto Offset = static_cast(
+ASTLayout.getBaseClassOffset(BaseRecord).getQuantity());
+// Recursively zero out base classes.
+auto Index = SL->getElementContainingOffset(Offset);
+Value *Idx = CGF.Builder.getSize(Index);
+llvm::Type *CurrentBaseType = CGF.ConvertTypeForMem(Base.getType());
+Value *BaseElement = CGF.Builder.CreateGEP(CurrentBaseType, Ptr, Idx);
+RecursivelyClearPaddingImpl(CGF, BaseElement, Base.getType(), 
CurrentStartOffset + Offset, RunningOffset, WriteZeroAtOffset);
+  }
+
+  size_t NumFields = std::distance(R->field_begin(), R->field_end());
+  auto CurrentField = R->field_begin();
+  for (size_t I = 0; I < NumFields; ++I, ++CurrentField) {
+// Size needs to be in bytes so we can compare it later.
+auto Offset = ASTLayout.getFieldOffset(I) / 8;
+auto Index = SL->getElementContainingOffset(Offset);
+Value *Idx = CGF.Builder.getSize(Index);
+llvm::Type *CurrentFieldType = 
CGF.ConvertTypeForMem(CurrentField->getType());
+Value *Element = CGF.Builder.CreateGEP(CurrentFieldType, Ptr, Idx);
+RecursivelyClearPaddingImpl(CGF, Element, CurrentField->getType(), 
CurrentStartOffset + Offset, RunningOffset, WriteZeroAtOffset);
+  }
+}
+
+template 
+void ClearPaddingConstantArray(CodeGenFunction &CGF, Value *Ptr, llvm::Type 
*Type, ConstantArrayType const *AT, 
+   size_t CurrentStartOffset, size_t 
&RunningOffset, T&& WriteZeroAtOffset) {
+  for (size_t ArrIndex = 0; ArrIndex < AT->getSize().getLimitedValue();
+   ++ArrIndex) {
+
+QualType ElementQualType = AT->getElementType();
+
+auto *ElementRecord = ElementQualType->getAsRecordDecl();
+if(!ElementRecord){
+  std::cerr<< "\n\n null!" << std::endl;
+}
+auto ElementAlign =ElementRecord?
+CGF.getContext().getASTRecordLayout(ElementRecord).getAlignment():
+CGF.getContext().getTypeAlignInChars(ElementQualType);
+
+  std::cerr<< "\n\n align: " << ElementAlign.getQuantity() << std::endl;
+
+// Value *Idx = CGF.Builder.getSize(0);
+// Value *ArrayElement = CGF.Builder.CreateGEP(ElementType, Ptr, Idx);
+
+Address FieldElementAddr{Ptr, Type, ElementAlign};
+
+auto Element =
+CGF.Builder.CreateConstArrayGEP(FieldElementAddr, ArrIndex);
+auto *ElementType = CGF.ConvertTypeForMem(ElementQualType);
+auto AllocSize = 
CGF.CGM.getModule().getDataLayout().getTypeAllocSize(ElementType);
+std::cerr << "\n\n clearing array index! " << ArrIndex << std::endl;
+RecursivelyClearPaddingImpl(CGF, Element.getPointer(), ElementQualType, 
CurrentStartOffset + ArrIndex * AllocSize.getKnownMinValue(), RunningOffset, 
WriteZeroAtOffset);
+  }
+}
+
+template 
+void RecursivelyClearPaddingImpl(CodeGenFunction &CGF, Value *Ptr, QualType 
Ty, size_t CurrentStartOffset, 
+ size_t& RunningOffset, T&& WriteZeroAtOffset) 
{
+
+  std::cerr << "\n\n  zero padding before current  ["<< RunningOffset << ", " 
<< CurrentStartOffset<< ")"<< std::endl;
+  for (; RunningOffset < CurrentStartOffset; ++RunningOffset) {
+WriteZeroAtOffset(RunningOffset);
+  }
+  auto Type = CGF.ConvertTypeForMem(Ty);
+  auto Size = CGF.CGM.getModule()
+.getDataLayout()
+.getTypeSizeInBits(Type)
+.getKnownMinValue() / 8;
+
+  if (auto *AT = dyn_cast(Ty)) {
+ClearPaddingConstantArray(CGF, Ptr, Type, AT, CurrentStartOffset, 
RunningOffset, WriteZeroAtOffset);
+  }
+  else if (auto *ST = dyn_cast(Type); ST && Ty->isRecordType()) {
+ClearPaddingStruct(CGF, Ptr, Ty, ST, CurrentStartOffset, RunningOffset, 
WriteZeroAtOffset);
+  } else if (Ty->isAtomicType()) {
+RecursivelyClearPaddingImpl(CGF, Ptr, Ty.getAtomicUnqualifiedType(), 
CurrentStartOffset, RunningOffset, WriteZeroAtOffset);
+  } else {
+std::cerr << "\n\n increment running offset from: " << RunningOffset << " 
to "

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

2024-06-14 Thread Eli Friedman via cfe-commits


@@ -0,0 +1,807 @@
+//===--===//
+//
+// 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
+//
+//===--===//
+// UNSUPPORTED: c++03

efriedma-quic wrote:

There is no mechanism for clang/ tests to run on target.  Usually, if we think 
it's important, we add tests to SingleSource/UnitTests in llvm-test-suite.  But 
usually we just rely on clang regression testing.

https://github.com/llvm/llvm-project/pull/75371
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-15 Thread via cfe-commits

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

>From cb64639669286e5f48421ae8f569208e1e9717be Mon Sep 17 00:00:00 2001
From: zoecarver 
Date: Sat, 2 Dec 2023 20:00:30 +
Subject: [PATCH 1/2] [Builtin] Add __builtin_clear_padding

Adds `__builtin_clear_padding` to zero all padding bits of a struct. This 
builtin should match the behavior of those in NVCC and GCC (and MSVC?). There 
are some tests in this patch but hopefully we'll also get tests from other 
compilers (so all builtins can be as similar as possible).

I'm planning to add support for unions, bitfields (both as members and members 
of sub-objects), and booleans as follow up patches.

Differential Revision: https://reviews.llvm.org/D87974

overlapping subobjects + opague pointer

union, rename, scalar types
---
 clang/include/clang/Basic/Builtins.td |   6 +
 clang/lib/CodeGen/CGBuiltin.cpp   | 207 +
 clang/lib/Sema/SemaChecking.cpp   |  31 +
 .../builtin-clear-padding-codegen.cpp | 112 +++
 clang/test/SemaCXX/builtin-clear-padding.cpp  |  15 +
 .../atomics/builtin_clear_padding.pass.cpp| 807 ++
 6 files changed, 1178 insertions(+)
 create mode 100644 clang/test/CodeGenCXX/builtin-clear-padding-codegen.cpp
 create mode 100644 clang/test/SemaCXX/builtin-clear-padding.cpp
 create mode 100644 libcxx/test/libcxx/atomics/builtin_clear_padding.pass.cpp

diff --git a/clang/include/clang/Basic/Builtins.td 
b/clang/include/clang/Basic/Builtins.td
index 11982af3fa609..44a239e50d5d8 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -932,6 +932,12 @@ def IsConstantEvaluated : LangBuiltin<"CXX_LANG"> {
   let Prototype = "bool()";
 }
 
+def ClearPadding : LangBuiltin<"CXX_LANG"> {
+  let Spellings = ["__builtin_clear_padding"];
+  let Attributes = [NoThrow];
+  let Prototype = "void(...)";
+}
+
 // GCC exception builtins
 def EHReturn : Builtin {
   let Spellings = ["__builtin_eh_return"];
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index c16b69ba87567..e1d8135933bb3 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -63,6 +63,7 @@
 #include "llvm/Support/ScopedPrinter.h"
 #include "llvm/TargetParser/AArch64TargetParser.h"
 #include "llvm/TargetParser/X86TargetParser.h"
+#include 
 #include 
 #include 
 
@@ -2538,6 +2539,205 @@ static RValue 
EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF,
   return RValue::get(CGF->Builder.CreateCall(UBF, Args));
 }
 
+template 
+void RecursivelyClearPaddingImpl(CodeGenFunction &CGF, Value *Ptr, QualType Ty,
+ size_t CurrentStartOffset,
+ size_t &RunningOffset, T &&WriteZeroAtOffset,
+ bool VisitVirtualBase);
+
+template 
+void ClearPaddingStruct(CodeGenFunction &CGF, Value *Ptr, QualType Ty,
+StructType *ST, size_t CurrentStartOffset,
+size_t &RunningOffset, T &&WriteZeroAtOffset,
+bool VisitVirtualBase) {
+  llvm::dbgs() << "clear padding struct: " << ST->getName().data() << '\n';
+  const auto &DL = CGF.CGM.getModule().getDataLayout();
+  auto *SL = DL.getStructLayout(ST);
+  auto *R = dyn_cast(Ty->getAsRecordDecl());
+  if (!R) {
+llvm::dbgs() << "Not a CXXRecordDecl\n";
+return;
+  }
+  const ASTRecordLayout &ASTLayout = CGF.getContext().getASTRecordLayout(R);
+  if (ASTLayout.hasOwnVFPtr()) {
+llvm::dbgs() << "vtable ptr. Incrementing RunningOffset from "
+ << RunningOffset << " to "
+ << RunningOffset + DL.getPointerSizeInBits() / 8 << '\n';
+RunningOffset += DL.getPointerSizeInBits() / 8;
+  }
+  std::vector> Bases;
+  Bases.reserve(R->getNumBases());
+  // todo get vbases
+  for (auto Base : R->bases()) {
+auto *BaseRecord = cast(Base.getType()->getAsRecordDecl());
+if (!Base.isVirtual()) {
+  auto Offset = static_cast(
+  ASTLayout.getBaseClassOffset(BaseRecord).getQuantity());
+  Bases.emplace_back(Offset, Base);
+}
+  }
+
+  auto VisitBases =
+  [&](std::vector> &BasesToVisit) {
+std::sort(
+BasesToVisit.begin(), BasesToVisit.end(),
+[](const auto &P1, const auto &P2) { return P1.first < P2.first; 
});
+for (const auto &Pair : BasesToVisit) {
+  // is it OK to use structured binding in clang? what is the language
+  // version?
+  auto Offset = Pair.first;
+  auto Base = Pair.second;
+
+  llvm::dbgs() << "visiting base at offset " << Offset << '\n';
+  // Recursively zero out base classes.
+  auto Index = SL->getElementContainingOffset(Offset);
+  Value *Idx = CGF.Builder.getSize(Index);
+  llvm::Type *CurrentBaseType = CGF.ConvertTypeForMem(Base.getType());
+  Value *BaseElement = CGF.Builder.CreateGEP(CurrentBaseType, Ptr, 

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

2024-06-16 Thread via cfe-commits

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

>From cb64639669286e5f48421ae8f569208e1e9717be Mon Sep 17 00:00:00 2001
From: zoecarver 
Date: Sat, 2 Dec 2023 20:00:30 +
Subject: [PATCH 1/2] [Builtin] Add __builtin_clear_padding

Adds `__builtin_clear_padding` to zero all padding bits of a struct. This 
builtin should match the behavior of those in NVCC and GCC (and MSVC?). There 
are some tests in this patch but hopefully we'll also get tests from other 
compilers (so all builtins can be as similar as possible).

I'm planning to add support for unions, bitfields (both as members and members 
of sub-objects), and booleans as follow up patches.

Differential Revision: https://reviews.llvm.org/D87974

overlapping subobjects + opague pointer

union, rename, scalar types
---
 clang/include/clang/Basic/Builtins.td |   6 +
 clang/lib/CodeGen/CGBuiltin.cpp   | 207 +
 clang/lib/Sema/SemaChecking.cpp   |  31 +
 .../builtin-clear-padding-codegen.cpp | 112 +++
 clang/test/SemaCXX/builtin-clear-padding.cpp  |  15 +
 .../atomics/builtin_clear_padding.pass.cpp| 807 ++
 6 files changed, 1178 insertions(+)
 create mode 100644 clang/test/CodeGenCXX/builtin-clear-padding-codegen.cpp
 create mode 100644 clang/test/SemaCXX/builtin-clear-padding.cpp
 create mode 100644 libcxx/test/libcxx/atomics/builtin_clear_padding.pass.cpp

diff --git a/clang/include/clang/Basic/Builtins.td 
b/clang/include/clang/Basic/Builtins.td
index 11982af3fa609..44a239e50d5d8 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -932,6 +932,12 @@ def IsConstantEvaluated : LangBuiltin<"CXX_LANG"> {
   let Prototype = "bool()";
 }
 
+def ClearPadding : LangBuiltin<"CXX_LANG"> {
+  let Spellings = ["__builtin_clear_padding"];
+  let Attributes = [NoThrow];
+  let Prototype = "void(...)";
+}
+
 // GCC exception builtins
 def EHReturn : Builtin {
   let Spellings = ["__builtin_eh_return"];
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index c16b69ba87567..e1d8135933bb3 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -63,6 +63,7 @@
 #include "llvm/Support/ScopedPrinter.h"
 #include "llvm/TargetParser/AArch64TargetParser.h"
 #include "llvm/TargetParser/X86TargetParser.h"
+#include 
 #include 
 #include 
 
@@ -2538,6 +2539,205 @@ static RValue 
EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF,
   return RValue::get(CGF->Builder.CreateCall(UBF, Args));
 }
 
+template 
+void RecursivelyClearPaddingImpl(CodeGenFunction &CGF, Value *Ptr, QualType Ty,
+ size_t CurrentStartOffset,
+ size_t &RunningOffset, T &&WriteZeroAtOffset,
+ bool VisitVirtualBase);
+
+template 
+void ClearPaddingStruct(CodeGenFunction &CGF, Value *Ptr, QualType Ty,
+StructType *ST, size_t CurrentStartOffset,
+size_t &RunningOffset, T &&WriteZeroAtOffset,
+bool VisitVirtualBase) {
+  llvm::dbgs() << "clear padding struct: " << ST->getName().data() << '\n';
+  const auto &DL = CGF.CGM.getModule().getDataLayout();
+  auto *SL = DL.getStructLayout(ST);
+  auto *R = dyn_cast(Ty->getAsRecordDecl());
+  if (!R) {
+llvm::dbgs() << "Not a CXXRecordDecl\n";
+return;
+  }
+  const ASTRecordLayout &ASTLayout = CGF.getContext().getASTRecordLayout(R);
+  if (ASTLayout.hasOwnVFPtr()) {
+llvm::dbgs() << "vtable ptr. Incrementing RunningOffset from "
+ << RunningOffset << " to "
+ << RunningOffset + DL.getPointerSizeInBits() / 8 << '\n';
+RunningOffset += DL.getPointerSizeInBits() / 8;
+  }
+  std::vector> Bases;
+  Bases.reserve(R->getNumBases());
+  // todo get vbases
+  for (auto Base : R->bases()) {
+auto *BaseRecord = cast(Base.getType()->getAsRecordDecl());
+if (!Base.isVirtual()) {
+  auto Offset = static_cast(
+  ASTLayout.getBaseClassOffset(BaseRecord).getQuantity());
+  Bases.emplace_back(Offset, Base);
+}
+  }
+
+  auto VisitBases =
+  [&](std::vector> &BasesToVisit) {
+std::sort(
+BasesToVisit.begin(), BasesToVisit.end(),
+[](const auto &P1, const auto &P2) { return P1.first < P2.first; 
});
+for (const auto &Pair : BasesToVisit) {
+  // is it OK to use structured binding in clang? what is the language
+  // version?
+  auto Offset = Pair.first;
+  auto Base = Pair.second;
+
+  llvm::dbgs() << "visiting base at offset " << Offset << '\n';
+  // Recursively zero out base classes.
+  auto Index = SL->getElementContainingOffset(Offset);
+  Value *Idx = CGF.Builder.getSize(Index);
+  llvm::Type *CurrentBaseType = CGF.ConvertTypeForMem(Base.getType());
+  Value *BaseElement = CGF.Builder.CreateGEP(CurrentBaseType, Ptr, 

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

2024-06-16 Thread via cfe-commits


@@ -2456,6 +2461,139 @@ static RValue 
EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF,
   return RValue::get(CGF->Builder.CreateCall(UBF, Args));
 }
 
+template 
+void RecursivelyClearPaddingImpl(CodeGenFunction &CGF, Value *Ptr, QualType 
Ty, size_t CurrentStartOffset, size_t &RunningOffset, T&& WriteZeroAtOffset);
+
+template 
+void ClearPaddingStruct(CodeGenFunction &CGF, Value *Ptr, QualType Ty, 
StructType *ST, 
+size_t CurrentStartOffset, size_t &RunningOffset, T&& 
WriteZeroAtOffset) {
+  std::cerr << "\n struct! " << ST->getName().data() << std::endl;
+  auto SL = CGF.CGM.getModule().getDataLayout().getStructLayout(ST);
+
+  auto R = dyn_cast(Ty->getAsRecordDecl());
+  if(!R) {
+std::cerr << "\n not a CXXRecordDecl" << std::endl;
+
+  }
+  const ASTRecordLayout &ASTLayout = CGF.getContext().getASTRecordLayout(R);
+  for (auto Base : R->bases()) {

huixie90 wrote:

anyway. I changed the approach now.the new approach should work regardless of 
the orders

https://github.com/llvm/llvm-project/pull/75371
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-16 Thread via cfe-commits


@@ -2456,6 +2461,139 @@ static RValue 
EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF,
   return RValue::get(CGF->Builder.CreateCall(UBF, Args));
 }
 
+template 
+void RecursivelyClearPaddingImpl(CodeGenFunction &CGF, Value *Ptr, QualType 
Ty, size_t CurrentStartOffset, size_t &RunningOffset, T&& WriteZeroAtOffset);
+
+template 
+void ClearPaddingStruct(CodeGenFunction &CGF, Value *Ptr, QualType Ty, 
StructType *ST, 
+size_t CurrentStartOffset, size_t &RunningOffset, T&& 
WriteZeroAtOffset) {
+  std::cerr << "\n struct! " << ST->getName().data() << std::endl;
+  auto SL = CGF.CGM.getModule().getDataLayout().getStructLayout(ST);
+
+  auto R = dyn_cast(Ty->getAsRecordDecl());
+  if(!R) {
+std::cerr << "\n not a CXXRecordDecl" << std::endl;
+
+  }
+  const ASTRecordLayout &ASTLayout = CGF.getContext().getASTRecordLayout(R);
+  for (auto Base : R->bases()) {
+std::cerr << "\n\n base!"  << std::endl;
+// Zero padding between base elements.
+auto BaseRecord = cast(Base.getType()->getAsRecordDecl());
+auto Offset = static_cast(
+ASTLayout.getBaseClassOffset(BaseRecord).getQuantity());
+// Recursively zero out base classes.
+auto Index = SL->getElementContainingOffset(Offset);

huixie90 wrote:

I removed all the code using LLVM layouts

https://github.com/llvm/llvm-project/pull/75371
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-16 Thread via cfe-commits


@@ -2456,6 +2461,139 @@ static RValue 
EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF,
   return RValue::get(CGF->Builder.CreateCall(UBF, Args));
 }
 
+template 
+void RecursivelyClearPaddingImpl(CodeGenFunction &CGF, Value *Ptr, QualType 
Ty, size_t CurrentStartOffset, size_t &RunningOffset, T&& WriteZeroAtOffset);
+
+template 
+void ClearPaddingStruct(CodeGenFunction &CGF, Value *Ptr, QualType Ty, 
StructType *ST, 
+size_t CurrentStartOffset, size_t &RunningOffset, T&& 
WriteZeroAtOffset) {
+  std::cerr << "\n struct! " << ST->getName().data() << std::endl;
+  auto SL = CGF.CGM.getModule().getDataLayout().getStructLayout(ST);
+
+  auto R = dyn_cast(Ty->getAsRecordDecl());
+  if(!R) {
+std::cerr << "\n not a CXXRecordDecl" << std::endl;
+
+  }
+  const ASTRecordLayout &ASTLayout = CGF.getContext().getASTRecordLayout(R);
+  for (auto Base : R->bases()) {
+std::cerr << "\n\n base!"  << std::endl;
+// Zero padding between base elements.
+auto BaseRecord = cast(Base.getType()->getAsRecordDecl());
+auto Offset = static_cast(
+ASTLayout.getBaseClassOffset(BaseRecord).getQuantity());
+// Recursively zero out base classes.
+auto Index = SL->getElementContainingOffset(Offset);
+Value *Idx = CGF.Builder.getSize(Index);
+llvm::Type *CurrentBaseType = CGF.ConvertTypeForMem(Base.getType());
+Value *BaseElement = CGF.Builder.CreateGEP(CurrentBaseType, Ptr, Idx);
+RecursivelyClearPaddingImpl(CGF, BaseElement, Base.getType(), 
CurrentStartOffset + Offset, RunningOffset, WriteZeroAtOffset);
+  }
+
+  size_t NumFields = std::distance(R->field_begin(), R->field_end());
+  auto CurrentField = R->field_begin();
+  for (size_t I = 0; I < NumFields; ++I, ++CurrentField) {
+// Size needs to be in bytes so we can compare it later.
+auto Offset = ASTLayout.getFieldOffset(I) / 8;
+auto Index = SL->getElementContainingOffset(Offset);

huixie90 wrote:

It is almost working now. I managed to get all the Padding in bits now. the 
remaining thing is to zeroing them out, instead of current generating store 
instruction with zeros, i need to basically do this for the bits that don't 
occupy the entire byte
```
byte &= ~PaddingBitMask
```
How can I generate that IR ?

https://github.com/llvm/llvm-project/pull/75371
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-16 Thread via cfe-commits


@@ -2456,6 +2461,139 @@ static RValue 
EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF,
   return RValue::get(CGF->Builder.CreateCall(UBF, Args));
 }
 
+template 
+void RecursivelyClearPaddingImpl(CodeGenFunction &CGF, Value *Ptr, QualType 
Ty, size_t CurrentStartOffset, size_t &RunningOffset, T&& WriteZeroAtOffset);
+
+template 
+void ClearPaddingStruct(CodeGenFunction &CGF, Value *Ptr, QualType Ty, 
StructType *ST, 
+size_t CurrentStartOffset, size_t &RunningOffset, T&& 
WriteZeroAtOffset) {
+  std::cerr << "\n struct! " << ST->getName().data() << std::endl;
+  auto SL = CGF.CGM.getModule().getDataLayout().getStructLayout(ST);
+
+  auto R = dyn_cast(Ty->getAsRecordDecl());
+  if(!R) {
+std::cerr << "\n not a CXXRecordDecl" << std::endl;
+
+  }
+  const ASTRecordLayout &ASTLayout = CGF.getContext().getASTRecordLayout(R);
+  for (auto Base : R->bases()) {
+std::cerr << "\n\n base!"  << std::endl;
+// Zero padding between base elements.
+auto BaseRecord = cast(Base.getType()->getAsRecordDecl());
+auto Offset = static_cast(
+ASTLayout.getBaseClassOffset(BaseRecord).getQuantity());
+// Recursively zero out base classes.
+auto Index = SL->getElementContainingOffset(Offset);
+Value *Idx = CGF.Builder.getSize(Index);
+llvm::Type *CurrentBaseType = CGF.ConvertTypeForMem(Base.getType());
+Value *BaseElement = CGF.Builder.CreateGEP(CurrentBaseType, Ptr, Idx);
+RecursivelyClearPaddingImpl(CGF, BaseElement, Base.getType(), 
CurrentStartOffset + Offset, RunningOffset, WriteZeroAtOffset);
+  }
+
+  size_t NumFields = std::distance(R->field_begin(), R->field_end());
+  auto CurrentField = R->field_begin();
+  for (size_t I = 0; I < NumFields; ++I, ++CurrentField) {
+// Size needs to be in bytes so we can compare it later.
+auto Offset = ASTLayout.getFieldOffset(I) / 8;
+auto Index = SL->getElementContainingOffset(Offset);
+Value *Idx = CGF.Builder.getSize(Index);
+llvm::Type *CurrentFieldType = 
CGF.ConvertTypeForMem(CurrentField->getType());
+Value *Element = CGF.Builder.CreateGEP(CurrentFieldType, Ptr, Idx);
+RecursivelyClearPaddingImpl(CGF, Element, CurrentField->getType(), 
CurrentStartOffset + Offset, RunningOffset, WriteZeroAtOffset);
+  }
+}
+
+template 
+void ClearPaddingConstantArray(CodeGenFunction &CGF, Value *Ptr, llvm::Type 
*Type, ConstantArrayType const *AT, 
+   size_t CurrentStartOffset, size_t 
&RunningOffset, T&& WriteZeroAtOffset) {
+  for (size_t ArrIndex = 0; ArrIndex < AT->getSize().getLimitedValue();
+   ++ArrIndex) {
+
+QualType ElementQualType = AT->getElementType();
+
+auto *ElementRecord = ElementQualType->getAsRecordDecl();
+if(!ElementRecord){
+  std::cerr<< "\n\n null!" << std::endl;
+}
+auto ElementAlign =ElementRecord?
+CGF.getContext().getASTRecordLayout(ElementRecord).getAlignment():

huixie90 wrote:

removed

https://github.com/llvm/llvm-project/pull/75371
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-16 Thread via cfe-commits


@@ -2456,6 +2461,139 @@ static RValue 
EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF,
   return RValue::get(CGF->Builder.CreateCall(UBF, Args));
 }
 
+template 
+void RecursivelyClearPaddingImpl(CodeGenFunction &CGF, Value *Ptr, QualType 
Ty, size_t CurrentStartOffset, size_t &RunningOffset, T&& WriteZeroAtOffset);
+
+template 
+void ClearPaddingStruct(CodeGenFunction &CGF, Value *Ptr, QualType Ty, 
StructType *ST, 
+size_t CurrentStartOffset, size_t &RunningOffset, T&& 
WriteZeroAtOffset) {
+  std::cerr << "\n struct! " << ST->getName().data() << std::endl;
+  auto SL = CGF.CGM.getModule().getDataLayout().getStructLayout(ST);
+
+  auto R = dyn_cast(Ty->getAsRecordDecl());
+  if(!R) {
+std::cerr << "\n not a CXXRecordDecl" << std::endl;
+
+  }
+  const ASTRecordLayout &ASTLayout = CGF.getContext().getASTRecordLayout(R);
+  for (auto Base : R->bases()) {
+std::cerr << "\n\n base!"  << std::endl;
+// Zero padding between base elements.
+auto BaseRecord = cast(Base.getType()->getAsRecordDecl());
+auto Offset = static_cast(
+ASTLayout.getBaseClassOffset(BaseRecord).getQuantity());
+// Recursively zero out base classes.
+auto Index = SL->getElementContainingOffset(Offset);
+Value *Idx = CGF.Builder.getSize(Index);
+llvm::Type *CurrentBaseType = CGF.ConvertTypeForMem(Base.getType());
+Value *BaseElement = CGF.Builder.CreateGEP(CurrentBaseType, Ptr, Idx);
+RecursivelyClearPaddingImpl(CGF, BaseElement, Base.getType(), 
CurrentStartOffset + Offset, RunningOffset, WriteZeroAtOffset);
+  }
+
+  size_t NumFields = std::distance(R->field_begin(), R->field_end());
+  auto CurrentField = R->field_begin();
+  for (size_t I = 0; I < NumFields; ++I, ++CurrentField) {
+// Size needs to be in bytes so we can compare it later.
+auto Offset = ASTLayout.getFieldOffset(I) / 8;
+auto Index = SL->getElementContainingOffset(Offset);
+Value *Idx = CGF.Builder.getSize(Index);
+llvm::Type *CurrentFieldType = 
CGF.ConvertTypeForMem(CurrentField->getType());
+Value *Element = CGF.Builder.CreateGEP(CurrentFieldType, Ptr, Idx);
+RecursivelyClearPaddingImpl(CGF, Element, CurrentField->getType(), 
CurrentStartOffset + Offset, RunningOffset, WriteZeroAtOffset);
+  }
+}
+
+template 
+void ClearPaddingConstantArray(CodeGenFunction &CGF, Value *Ptr, llvm::Type 
*Type, ConstantArrayType const *AT, 
+   size_t CurrentStartOffset, size_t 
&RunningOffset, T&& WriteZeroAtOffset) {
+  for (size_t ArrIndex = 0; ArrIndex < AT->getSize().getLimitedValue();
+   ++ArrIndex) {
+
+QualType ElementQualType = AT->getElementType();
+
+auto *ElementRecord = ElementQualType->getAsRecordDecl();
+if(!ElementRecord){
+  std::cerr<< "\n\n null!" << std::endl;
+}
+auto ElementAlign =ElementRecord?
+CGF.getContext().getASTRecordLayout(ElementRecord).getAlignment():
+CGF.getContext().getTypeAlignInChars(ElementQualType);
+
+  std::cerr<< "\n\n align: " << ElementAlign.getQuantity() << std::endl;
+
+// Value *Idx = CGF.Builder.getSize(0);
+// Value *ArrayElement = CGF.Builder.CreateGEP(ElementType, Ptr, Idx);
+
+Address FieldElementAddr{Ptr, Type, ElementAlign};
+
+auto Element =
+CGF.Builder.CreateConstArrayGEP(FieldElementAddr, ArrIndex);
+auto *ElementType = CGF.ConvertTypeForMem(ElementQualType);
+auto AllocSize = 
CGF.CGM.getModule().getDataLayout().getTypeAllocSize(ElementType);
+std::cerr << "\n\n clearing array index! " << ArrIndex << std::endl;
+RecursivelyClearPaddingImpl(CGF, Element.getPointer(), ElementQualType, 
CurrentStartOffset + ArrIndex * AllocSize.getKnownMinValue(), RunningOffset, 
WriteZeroAtOffset);
+  }
+}
+
+template 
+void RecursivelyClearPaddingImpl(CodeGenFunction &CGF, Value *Ptr, QualType 
Ty, size_t CurrentStartOffset, 
+ size_t& RunningOffset, T&& WriteZeroAtOffset) 
{
+
+  std::cerr << "\n\n  zero padding before current  ["<< RunningOffset << ", " 
<< CurrentStartOffset<< ")"<< std::endl;
+  for (; RunningOffset < CurrentStartOffset; ++RunningOffset) {
+WriteZeroAtOffset(RunningOffset);
+  }
+  auto Type = CGF.ConvertTypeForMem(Ty);
+  auto Size = CGF.CGM.getModule()
+.getDataLayout()
+.getTypeSizeInBits(Type)
+.getKnownMinValue() / 8;
+
+  if (auto *AT = dyn_cast(Ty)) {
+ClearPaddingConstantArray(CGF, Ptr, Type, AT, CurrentStartOffset, 
RunningOffset, WriteZeroAtOffset);
+  }
+  else if (auto *ST = dyn_cast(Type); ST && Ty->isRecordType()) {
+ClearPaddingStruct(CGF, Ptr, Ty, ST, CurrentStartOffset, RunningOffset, 
WriteZeroAtOffset);
+  } else if (Ty->isAtomicType()) {
+RecursivelyClearPaddingImpl(CGF, Ptr, Ty.getAtomicUnqualifiedType(), 
CurrentStartOffset, RunningOffset, WriteZeroAtOffset);
+  } else {
+std::cerr << "\n\n increment running offset from: " << RunningOffset << " 
to "

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

2024-06-16 Thread via cfe-commits


@@ -2538,6 +2539,205 @@ static RValue 
EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF,
   return RValue::get(CGF->Builder.CreateCall(UBF, Args));
 }
 
+template 
+void RecursivelyClearPaddingImpl(CodeGenFunction &CGF, Value *Ptr, QualType Ty,
+ size_t CurrentStartOffset,
+ size_t &RunningOffset, T &&WriteZeroAtOffset,
+ bool VisitVirtualBase);
+
+template 
+void ClearPaddingStruct(CodeGenFunction &CGF, Value *Ptr, QualType Ty,
+StructType *ST, size_t CurrentStartOffset,
+size_t &RunningOffset, T &&WriteZeroAtOffset,
+bool VisitVirtualBase) {
+  llvm::dbgs() << "clear padding struct: " << ST->getName().data() << '\n';
+  const auto &DL = CGF.CGM.getModule().getDataLayout();
+  auto *SL = DL.getStructLayout(ST);
+  auto *R = dyn_cast(Ty->getAsRecordDecl());
+  if (!R) {
+llvm::dbgs() << "Not a CXXRecordDecl\n";
+return;
+  }
+  const ASTRecordLayout &ASTLayout = CGF.getContext().getASTRecordLayout(R);
+  if (ASTLayout.hasOwnVFPtr()) {
+llvm::dbgs() << "vtable ptr. Incrementing RunningOffset from "
+ << RunningOffset << " to "
+ << RunningOffset + DL.getPointerSizeInBits() / 8 << '\n';
+RunningOffset += DL.getPointerSizeInBits() / 8;
+  }
+  std::vector> Bases;
+  Bases.reserve(R->getNumBases());
+  // todo get vbases
+  for (auto Base : R->bases()) {
+auto *BaseRecord = cast(Base.getType()->getAsRecordDecl());
+if (!Base.isVirtual()) {
+  auto Offset = static_cast(

huixie90 wrote:

removed `size_t`

https://github.com/llvm/llvm-project/pull/75371
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-16 Thread via cfe-commits

huixie90 wrote:

@efriedma-quic 

I refactored the code which does the following
1. Breadth first search the AST type, fill in "occupied bits intervals"
2. sort and merge the occupied bits interval and work out the "padding" bits 
intervals
3. clear the padding intervals.  current converting to the byte level and write 
zeros byte. todo: need to deal with bits that don't occupy the full byte. need 
to generate instructions like `Byte &= ~PaddingBitMask` . How to generate such 
an IR instruction ?

https://github.com/llvm/llvm-project/pull/75371
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-21 Thread Eli Friedman via cfe-commits

efriedma-quic wrote:

If you want to modify part of a bitfield unit, you need to load/store the whole 
bitfield unit, as computed by the CGRecordLayout.  This is true whether you're 
modifying an actual field, or padding adjacent to a field.  Since any padding 
has to be adjacent to a bitfield, you can get the relevant information out of 
the CGBitFieldInfo for that bitfield.

https://github.com/llvm/llvm-project/pull/75371
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-23 Thread via cfe-commits

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

>From cb64639669286e5f48421ae8f569208e1e9717be Mon Sep 17 00:00:00 2001
From: zoecarver 
Date: Sat, 2 Dec 2023 20:00:30 +
Subject: [PATCH 1/3] [Builtin] Add __builtin_clear_padding

Adds `__builtin_clear_padding` to zero all padding bits of a struct. This 
builtin should match the behavior of those in NVCC and GCC (and MSVC?). There 
are some tests in this patch but hopefully we'll also get tests from other 
compilers (so all builtins can be as similar as possible).

I'm planning to add support for unions, bitfields (both as members and members 
of sub-objects), and booleans as follow up patches.

Differential Revision: https://reviews.llvm.org/D87974

overlapping subobjects + opague pointer

union, rename, scalar types
---
 clang/include/clang/Basic/Builtins.td |   6 +
 clang/lib/CodeGen/CGBuiltin.cpp   | 207 +
 clang/lib/Sema/SemaChecking.cpp   |  31 +
 .../builtin-clear-padding-codegen.cpp | 112 +++
 clang/test/SemaCXX/builtin-clear-padding.cpp  |  15 +
 .../atomics/builtin_clear_padding.pass.cpp| 807 ++
 6 files changed, 1178 insertions(+)
 create mode 100644 clang/test/CodeGenCXX/builtin-clear-padding-codegen.cpp
 create mode 100644 clang/test/SemaCXX/builtin-clear-padding.cpp
 create mode 100644 libcxx/test/libcxx/atomics/builtin_clear_padding.pass.cpp

diff --git a/clang/include/clang/Basic/Builtins.td 
b/clang/include/clang/Basic/Builtins.td
index 11982af3fa609..44a239e50d5d8 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -932,6 +932,12 @@ def IsConstantEvaluated : LangBuiltin<"CXX_LANG"> {
   let Prototype = "bool()";
 }
 
+def ClearPadding : LangBuiltin<"CXX_LANG"> {
+  let Spellings = ["__builtin_clear_padding"];
+  let Attributes = [NoThrow];
+  let Prototype = "void(...)";
+}
+
 // GCC exception builtins
 def EHReturn : Builtin {
   let Spellings = ["__builtin_eh_return"];
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index c16b69ba87567..e1d8135933bb3 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -63,6 +63,7 @@
 #include "llvm/Support/ScopedPrinter.h"
 #include "llvm/TargetParser/AArch64TargetParser.h"
 #include "llvm/TargetParser/X86TargetParser.h"
+#include 
 #include 
 #include 
 
@@ -2538,6 +2539,205 @@ static RValue 
EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF,
   return RValue::get(CGF->Builder.CreateCall(UBF, Args));
 }
 
+template 
+void RecursivelyClearPaddingImpl(CodeGenFunction &CGF, Value *Ptr, QualType Ty,
+ size_t CurrentStartOffset,
+ size_t &RunningOffset, T &&WriteZeroAtOffset,
+ bool VisitVirtualBase);
+
+template 
+void ClearPaddingStruct(CodeGenFunction &CGF, Value *Ptr, QualType Ty,
+StructType *ST, size_t CurrentStartOffset,
+size_t &RunningOffset, T &&WriteZeroAtOffset,
+bool VisitVirtualBase) {
+  llvm::dbgs() << "clear padding struct: " << ST->getName().data() << '\n';
+  const auto &DL = CGF.CGM.getModule().getDataLayout();
+  auto *SL = DL.getStructLayout(ST);
+  auto *R = dyn_cast(Ty->getAsRecordDecl());
+  if (!R) {
+llvm::dbgs() << "Not a CXXRecordDecl\n";
+return;
+  }
+  const ASTRecordLayout &ASTLayout = CGF.getContext().getASTRecordLayout(R);
+  if (ASTLayout.hasOwnVFPtr()) {
+llvm::dbgs() << "vtable ptr. Incrementing RunningOffset from "
+ << RunningOffset << " to "
+ << RunningOffset + DL.getPointerSizeInBits() / 8 << '\n';
+RunningOffset += DL.getPointerSizeInBits() / 8;
+  }
+  std::vector> Bases;
+  Bases.reserve(R->getNumBases());
+  // todo get vbases
+  for (auto Base : R->bases()) {
+auto *BaseRecord = cast(Base.getType()->getAsRecordDecl());
+if (!Base.isVirtual()) {
+  auto Offset = static_cast(
+  ASTLayout.getBaseClassOffset(BaseRecord).getQuantity());
+  Bases.emplace_back(Offset, Base);
+}
+  }
+
+  auto VisitBases =
+  [&](std::vector> &BasesToVisit) {
+std::sort(
+BasesToVisit.begin(), BasesToVisit.end(),
+[](const auto &P1, const auto &P2) { return P1.first < P2.first; 
});
+for (const auto &Pair : BasesToVisit) {
+  // is it OK to use structured binding in clang? what is the language
+  // version?
+  auto Offset = Pair.first;
+  auto Base = Pair.second;
+
+  llvm::dbgs() << "visiting base at offset " << Offset << '\n';
+  // Recursively zero out base classes.
+  auto Index = SL->getElementContainingOffset(Offset);
+  Value *Idx = CGF.Builder.getSize(Index);
+  llvm::Type *CurrentBaseType = CGF.ConvertTypeForMem(Base.getType());
+  Value *BaseElement = CGF.Builder.CreateGEP(CurrentBaseType, Ptr,