[clang] [libcxx] [clang] Add builtin to clear padding bytes (prework for P0528R3) (PR #75371)
@@ -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)
@@ -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)
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)
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)
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)
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)
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)
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)
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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
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)
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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
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)
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)
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,