From e42344c5f6f1d6e37099915da9725e104c23d797 Mon Sep 17 00:00:00 2001 From: Hui Date: Sun, 16 Jun 2024 00:05:25 +0100 Subject: [PATCH] new approach --- clang/lib/CodeGen/CGBuiltin.cpp | 410 ++++++++++-------- .../atomics/builtin_clear_padding.pass.cpp | 181 ++++---- 2 files changed, 332 insertions(+), 259 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index e1d8135933bb39..8d3e9ad1602ce1 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -65,6 +65,8 @@ #include "llvm/TargetParser/X86TargetParser.h" #include #include +#include +#include #include using namespace clang; @@ -2539,204 +2541,254 @@ 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); +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); } } - 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, Idx); - RecursivelyClearPaddingImpl(CGF, BaseElement, Base.getType(), - CurrentStartOffset + Offset, - RunningOffset, WriteZeroAtOffset, false); - } - }; +private: + struct BitInterval { + // [First, Last) + uint64_t First; + uint64_t Last; + }; - VisitBases(Bases); - - size_t NumFields = std::distance(R->field_begin(), R->field_end()); - std::vector FieldOffsets; - FieldOffsets.reserve(NumFields); - 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; - llvm::dbgs() << "visiting field at offset " << Offset << '\n'; - 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, true); - } - - if (VisitVirtualBase) { - - std::vector> VBases; - VBases.reserve(R->getNumVBases()); - for (auto VBase : R->vbases()) { - auto *BaseRecord = - cast(VBase.getType()->getAsRecordDecl()); - auto Offset = static_cast( - ASTLayout.getVBaseClassOffset(BaseRecord).getQuantity()); - VBases.emplace_back(Offset, VBase); + 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; } - VisitBases(VBases); + 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}); + } } -} -template -void ClearPaddingConstantArray(CodeGenFunction &CGF, Value *Ptr, - llvm::Type *Type, ConstantArrayType const *AT, - size_t CurrentStartOffset, size_t &RunningOffset, - T &&WriteZeroAtOffset) { - llvm::dbgs() << "clear padding constant array\n"; - for (size_t ArrIndex = 0; ArrIndex < AT->getSize().getLimitedValue(); - ++ArrIndex) { + 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()}); + } - QualType ElementQualType = AT->getElementType(); + 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(); - auto *ElementRecord = ElementQualType->getAsRecordDecl(); - if (!ElementRecord) { - llvm::dbgs() << "null!\n"; + llvm::dbgs() << "visiting base at offset " << StartBitOffset << " + " + << BaseOffset * CharWidth << '\n'; + Queue.push_back( + Data{StartBitOffset + BaseOffset * CharWidth, Base.getType(), false}); + }; + + for (auto Base : R->bases()) { + if (!Base.isVirtual()) { + VisitBase(Base, &ASTRecordLayout::getBaseClassOffset); + } + } + + if (VisitVirtualBase) { + for (auto VBase : R->vbases()) { + VisitBase(VBase, &ASTRecordLayout::getVBaseClassOffset); + } + } + + for (auto *Field : R->fields()) { + auto FieldOffset = ASTLayout.getFieldOffset(Field->getFieldIndex()); + llvm::dbgs() << "visiting field at offset " << StartBitOffset << " + " + << FieldOffset << '\n'; + if (Field->isBitField()) { + llvm::dbgs() << "clear_padding found bit field. Adding Interval [" + << StartBitOffset + FieldOffset << " , " + << FieldOffset + Field->getBitWidthValue(CGF.getContext()) + << ")\n"; + OccuppiedIntervals.push_back( + BitInterval{StartBitOffset + FieldOffset, + StartBitOffset + FieldOffset + + Field->getBitWidthValue(CGF.getContext())}); + } else { + Queue.push_back( + Data{StartBitOffset + FieldOffset, Field->getType(), true}); + } } - auto ElementAlign = - ElementRecord - ? CGF.getContext().getASTRecordLayout(ElementRecord).getAlignment() - : CGF.getContext().getTypeAlignInChars(ElementQualType); - - 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); - llvm::dbgs() << "clearing array index! " << ArrIndex << '\n'; - RecursivelyClearPaddingImpl(CGF, Element.getBasePointer(), ElementQualType, - CurrentStartOffset + - ArrIndex * AllocSize.getKnownMinValue(), - RunningOffset, WriteZeroAtOffset, true); } -} -template -void RecursivelyClearPaddingImpl(CodeGenFunction &CGF, Value *Ptr, QualType Ty, - size_t CurrentStartOffset, - size_t &RunningOffset, T &&WriteZeroAtOffset, - bool VisitVirtualBase) { - - llvm::dbgs() << "clear padding before current [" << RunningOffset << ", " - << CurrentStartOffset << ")\n"; - 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, VisitVirtualBase); - } else if (Ty->isAtomicType()) { - RecursivelyClearPaddingImpl(CGF, Ptr, Ty.getAtomicUnqualifiedType(), - CurrentStartOffset, RunningOffset, - WriteZeroAtOffset, true); - } else { - llvm::dbgs() << "increment running offset from: " << RunningOffset << " to " - << RunningOffset + Size << '\n'; - RunningOffset = - std::max(RunningOffset, CurrentStartOffset + static_cast(Size)); + void VisitComplex(const ComplexType *CT, uint64_t StartBitOffset) { + QualType ElementQualType = CT->getElementType(); + auto ElementSize = CGF.getContext().getTypeSizeInChars(ElementQualType); + auto ElementAlign = CGF.getContext().getTypeAlignInChars(ElementQualType); + auto ImgOffset = ElementSize.alignTo(ElementAlign); + + llvm::dbgs() << "clear_padding visiting Complex Type. Real from " + << StartBitOffset << "Img from " + << StartBitOffset + ImgOffset.getQuantity() * CharWidth + << "\n"; + Queue.push_back(Data{StartBitOffset, ElementQualType, true}); + Queue.push_back(Data{StartBitOffset + ImgOffset.getQuantity() * CharWidth, + ElementQualType, true}); } -} -static void RecursivelyClearPadding(CodeGenFunction &CGF, Value *Ptr, - QualType Ty) { - auto *I8Ptr = CGF.Builder.CreateBitCast(Ptr, CGF.Int8PtrTy); - auto *Zero = ConstantInt::get(CGF.Int8Ty, 0); - auto WriteZeroAtOffset = [&](uint64_t Offset) { - auto *Index = ConstantInt::get(CGF.IntTy, Offset); - auto *Element = CGF.Builder.CreateGEP(CGF.Int8Ty, I8Ptr, Index); - CGF.Builder.CreateAlignedStore( - Zero, Element, - CharUnits::One().alignmentAtOffset(CharUnits::fromQuantity(Offset))); - }; + void MergeOccuppiedIntervals() { + std::sort(OccuppiedIntervals.begin(), OccuppiedIntervals.end(), + [](const BitInterval &lhs, const BitInterval &rhs) { + return std::tie(lhs.First, lhs.Last) < + std::tie(rhs.First, rhs.Last); + }); - size_t RunningOffset = 0; + std::vector Merged; + Merged.reserve(OccuppiedIntervals.size()); - RecursivelyClearPaddingImpl(CGF, Ptr, Ty, 0, RunningOffset, WriteZeroAtOffset, - true); + for (const BitInterval &NextInterval : OccuppiedIntervals) { + if (Merged.empty()) { + Merged.push_back(NextInterval); + continue; + } + auto &LastInterval = Merged.back(); - // Clear tail padding - auto *Type = CGF.ConvertTypeForMem(Ty); + if (NextInterval.First > LastInterval.Last) { + Merged.push_back(NextInterval); + } else { + LastInterval.Last = std::max(LastInterval.Last, NextInterval.Last); + } + } - auto Size = CGF.CGM.getModule() - .getDataLayout() - .getTypeAllocSize(Type) - .getKnownMinValue(); + OccuppiedIntervals = Merged; + } - llvm::dbgs() << "clear tail padding [" << RunningOffset << ", " << Size - << ")\n"; - for (; RunningOffset < Size; ++RunningOffset) { - WriteZeroAtOffset(RunningOffset); + std::vector GetPaddingIntervals(uint64_t SizeInBits) const { + std::vector Results; + if (OccuppiedIntervals.size() == 1 && + OccuppiedIntervals.front().First == 0 && + OccuppiedIntervals.end()->Last == SizeInBits) { + return Results; + } + Results.reserve(OccuppiedIntervals.size() + 1); + uint64_t CurrentPos = 0; + for (const BitInterval &OccupiedInterval : OccuppiedIntervals) { + if (OccupiedInterval.First > CurrentPos) { + Results.push_back(BitInterval{CurrentPos, OccupiedInterval.First}); + } + CurrentPos = OccupiedInterval.Last; + } + if (SizeInBits > CurrentPos) { + Results.push_back(BitInterval{CurrentPos, SizeInBits}); + } + return Results; + } + + void ClearPadding(Value *Ptr, const BitInterval &PaddingInteval) { + // TODO: support clearning non-one-byte clearing + auto *I8Ptr = CGF.Builder.CreateBitCast(Ptr, CGF.Int8PtrTy); + auto *Zero = ConstantInt::get(CGF.Int8Ty, 0); + for (auto Offset = PaddingInteval.First / CharWidth; + Offset < PaddingInteval.Last / CharWidth; ++Offset) { + auto *Index = ConstantInt::get(CGF.IntTy, Offset); + auto *Element = CGF.Builder.CreateGEP(CGF.Int8Ty, I8Ptr, Index); + CGF.Builder.CreateAlignedStore( + Zero, Element, + CharUnits::One().alignmentAtOffset(CharUnits::fromQuantity(Offset))); + } } -} + + CodeGenFunction &CGF; + const uint64_t CharWidth; + std::deque Queue; + std::vector OccuppiedIntervals; +}; + +} // namespace RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, const CallExpr *E, @@ -4666,7 +4718,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, const Expr *Op = E->getArg(0); Value *Address = EmitScalarExpr(Op); auto PointeeTy = Op->getType()->getPointeeType(); - RecursivelyClearPadding(*this, Address, PointeeTy); + PaddingClearer clearer{*this}; + clearer.run(Address, PointeeTy); + //RecursivelyClearPadding(*this, Address, PointeeTy); return RValue::get(nullptr); } case Builtin::BI__sync_fetch_and_add: diff --git a/libcxx/test/libcxx/atomics/builtin_clear_padding.pass.cpp b/libcxx/test/libcxx/atomics/builtin_clear_padding.pass.cpp index d504ac58e43ae5..49c57b1473447d 100644 --- a/libcxx/test/libcxx/atomics/builtin_clear_padding.pass.cpp +++ b/libcxx/test/libcxx/atomics/builtin_clear_padding.pass.cpp @@ -30,6 +30,12 @@ void print_bytes(const T* object) { template void __builtin_clear_padding2(T t) { __builtin_clear_padding(t); + (void)t; +} + +void assert2(bool b){ + assert(b); + (void)b; } template @@ -98,9 +104,9 @@ void testAllStructsForType(T a, T b, T c, T d) { memset(&basic2, 42, sizeof(B)); basic2.x = a; basic2.y = b; - assert(memcmp(&basic1, &basic2, sizeof(B)) != 0); + assert2(memcmp(&basic1, &basic2, sizeof(B)) != 0); __builtin_clear_padding2(&basic2); - assert(memcmp(&basic1, &basic2, sizeof(B)) == 0); + assert2(memcmp(&basic1, &basic2, sizeof(B)) == 0); } // spaced array @@ -119,9 +125,9 @@ void testAllStructsForType(T a, T b, T c, T d) { arr2.y[0] = c; arr2.y[1] = d; arr2.c = 0; - assert(memcmp(&arr1, &arr2, sizeof(A)) != 0); + assert2(memcmp(&arr1, &arr2, sizeof(A)) != 0); __builtin_clear_padding2(&arr2); - assert(memcmp(&arr1, &arr2, sizeof(A)) == 0); + assert2(memcmp(&arr1, &arr2, sizeof(A)) == 0); } // pointer members @@ -135,9 +141,9 @@ void testAllStructsForType(T a, T b, T c, T d) { memset(&ptr2, 42, sizeof(P)); ptr2.x = &a; ptr2.y = &b; - assert(memcmp(&ptr1, &ptr2, sizeof(P)) != 0); + assert2(memcmp(&ptr1, &ptr2, sizeof(P)) != 0); __builtin_clear_padding2(&ptr2); - assert(memcmp(&ptr1, &ptr2, sizeof(P)) == 0); + assert2(memcmp(&ptr1, &ptr2, sizeof(P)) == 0); } // three members @@ -154,7 +160,7 @@ void testAllStructsForType(T a, T b, T c, T d) { three2.y = b; three2.z = c; __builtin_clear_padding2(&three2); - assert(memcmp(&three1, &three2, sizeof(Three)) == 0); + assert2(memcmp(&three1, &three2, sizeof(Three)) == 0); } // Normal struct no padding @@ -169,7 +175,7 @@ void testAllStructsForType(T a, T b, T c, T d) { normal2.a = a; normal2.b = b; __builtin_clear_padding2(&normal2); - assert(memcmp(&normal1, &normal2, sizeof(N)) == 0); + assert2(memcmp(&normal1, &normal2, sizeof(N)) == 0); } // base class @@ -189,9 +195,9 @@ void testAllStructsForType(T a, T b, T c, T d) { base2.x = c; base2.y = d; base2.z = a; - assert(memcmp(&base1, &base2, sizeof(H)) != 0); + assert2(memcmp(&base1, &base2, sizeof(H)) != 0); __builtin_clear_padding2(&base2); - assert(memcmp(&base1, &base2, sizeof(H)) == 0); + assert2(memcmp(&base1, &base2, sizeof(H)) == 0); } } @@ -220,10 +226,10 @@ void otherStructTests() { u2->buf[1] = 2; u2->buf[2] = 3; u2->buf[3] = 4; - assert(memcmp(u1, u2, sizeof(UnsizedTail)) != 0); + assert2(memcmp(u1, u2, sizeof(UnsizedTail)) != 0); __builtin_clear_padding2(u2); - assert(memcmp(u1, u2, sizeof(UnsizedTail)) == 0); + assert2(memcmp(u1, u2, sizeof(UnsizedTail)) == 0); } // basic padding on the heap @@ -237,9 +243,9 @@ void otherStructTests() { memset(basic2, 42, sizeof(B)); basic2->x = 1; basic2->y = 2; - assert(memcmp(basic1, basic2, sizeof(B)) != 0); + assert2(memcmp(basic1, basic2, sizeof(B)) != 0); __builtin_clear_padding2(basic2); - assert(memcmp(basic1, basic2, sizeof(B)) == 0); + assert2(memcmp(basic1, basic2, sizeof(B)) == 0); delete basic2; delete basic1; } @@ -255,10 +261,10 @@ void otherStructTests() { memset(basic4, 42, sizeof(B)); basic4->x = 1; basic4->y = 2; - assert(memcmp(basic3, basic4, sizeof(B)) != 0); + assert2(memcmp(basic3, basic4, sizeof(B)) != 0); __builtin_clear_padding2(const_cast(basic4)); __builtin_clear_padding2(basic4); - assert(memcmp(basic3, basic4, sizeof(B)) == 0); + assert2(memcmp(basic3, basic4, sizeof(B)) == 0); delete basic4; delete basic3; } @@ -277,8 +283,8 @@ void primitiveTests() { { int i1 = 42, i2 = 42; __builtin_clear_padding2(&i1); // does nothing - assert(i1 == 42); - assert(memcmp(&i1, &i2, sizeof(int)) == 0); + assert2(i1 == 42); + assert2(memcmp(&i1, &i2, sizeof(int)) == 0); } // long double @@ -291,8 +297,20 @@ void primitiveTests() { d2 = 3.0L; __builtin_clear_padding2(&d1); - assert(d1 == 3.0L); - assert(memcmp(&d1, &d2, sizeof(long double)) == 0); + assert2(d1 == 3.0L); + assert2(memcmp(&d1, &d2, sizeof(long double)) == 0); + } + + // _Complex + { + _Complex long double c1, c2; + + memset(&c1, 42, sizeof(_Complex long double)); + memset(&c2, 0, sizeof(_Complex long double)); + c1 = 3.0L ; + c1 = 3.0L ; + __builtin_clear_padding2(&c1); + //TODO } } @@ -320,13 +338,13 @@ void structTests() { s2.s.c = 'a'; s2.b = true; - assert(memcmp(&s1, &s2, sizeof(S2)) != 0); + assert2(memcmp(&s1, &s2, sizeof(S2)) != 0); __builtin_clear_padding2(&s1); - assert(s1.s.x == 4); - assert(s1.s.c == 'a'); - assert(s1.b == true); + assert2(s1.s.x == 4); + assert2(s1.s.c == 'a'); + assert2(s1.b == true); - assert(memcmp(&s1, &s2, sizeof(S2)) == 0); + assert2(memcmp(&s1, &s2, sizeof(S2)) == 0); } // struct with long double @@ -345,11 +363,11 @@ void structTests() { s2.l = 3.0L; s2.b = true; - assert(memcmp(&s1, &s2, sizeof(S)) != 0); + assert2(memcmp(&s1, &s2, sizeof(S)) != 0); __builtin_clear_padding2(&s1); - assert(s1.l == 3.0L); - assert(s1.b == true); - assert(memcmp(&s1, &s2, sizeof(S)) == 0); + assert2(s1.l == 3.0L); + assert2(s1.b == true); + assert2(memcmp(&s1, &s2, sizeof(S)) == 0); } // EBO @@ -371,11 +389,11 @@ void structTests() { s2.i = 4; s2.b = true; - assert(memcmp(&s1, &s2, sizeof(S)) != 0); + assert2(memcmp(&s1, &s2, sizeof(S)) != 0); __builtin_clear_padding2(&s1); - assert(s1.i == 4); - assert(s1.b == true); - assert(memcmp(&s1, &s2, sizeof(S)) == 0); + assert2(s1.i == 4); + assert2(s1.b == true); + assert2(memcmp(&s1, &s2, sizeof(S)) == 0); } // padding between bases @@ -398,11 +416,11 @@ void structTests() { s2.c1 = 'a'; s2.c2 = 'b'; - assert(memcmp(&s1, &s2, sizeof(S)) != 0); + assert2(memcmp(&s1, &s2, sizeof(S)) != 0); __builtin_clear_padding2(&s1); - assert(s1.c1 == 'a'); - assert(s1.c2 == 'b'); - assert(memcmp(&s1, &s2, sizeof(S)) == 0); + assert2(s1.c1 == 'a'); + assert2(s1.c2 == 'b'); + assert2(memcmp(&s1, &s2, sizeof(S)) == 0); } // padding after last base @@ -429,12 +447,12 @@ void structTests() { s2.c2 = 'b'; s2.c3 = 'c'; - assert(memcmp(&s1, &s2, sizeof(S)) != 0); + assert2(memcmp(&s1, &s2, sizeof(S)) != 0); __builtin_clear_padding2(&s1); - assert(s1.c1 == 'a'); - assert(s1.c2 == 'b'); - assert(s1.c3 == 'c'); - assert(memcmp(&s1, &s2, sizeof(S)) == 0); + assert2(s1.c1 == 'a'); + assert2(s1.c2 == 'b'); + assert2(s1.c3 == 'c'); + assert2(memcmp(&s1, &s2, sizeof(S)) == 0); } // vtable @@ -469,11 +487,11 @@ void structTests() { s1->z = true; s2->z = true; __builtin_clear_padding2(s2); - assert(s2->x == 0xFFFFFFFF); - assert(s2->y == 'a'); - assert(s2->z == true); - assert(s2->call() == 5); - assert(memcmp(s1, s2, sizeof(S)) == 0); + assert2(s2->x == 0xFFFFFFFF); + assert2(s2->y == 'a'); + assert2(s2->z == true); + assert2(s2->call() == 5); + assert2(memcmp(s1, s2, sizeof(S)) == 0); } // multiple bases with vtable @@ -524,13 +542,13 @@ void structTests() { s1->z = true; s2->z = true; __builtin_clear_padding2(s2); - assert(s2->x1 == 0xFFFFFFFF); - assert(s2->x2 == 0xFAFAFAFA); - assert(s2->x3 == 0xAAAAAAAA); - assert(s2->y == 'a'); - assert(s2->z == true); - assert(s2->call1() == 5); - assert(memcmp(s1, s2, sizeof(S)) == 0); + assert2(s2->x1 == 0xFFFFFFFF); + assert2(s2->x2 == 0xFAFAFAFA); + assert2(s2->x3 == 0xAAAAAAAA); + assert2(s2->y == 'a'); + assert2(s2->z == true); + assert2(s2->call1() == 5); + assert2(memcmp(s1, s2, sizeof(S)) == 0); } // chain of bases with virtual functions @@ -580,7 +598,7 @@ void structTests() { s1->z = true; s2->z = true; __builtin_clear_padding2(s2); - assert(memcmp(s1, s2, sizeof(S)) == 0); + assert2(memcmp(s1, s2, sizeof(S)) == 0); } // virtual inheritance @@ -621,7 +639,7 @@ void structTests() { s1->s = true; s2->s = true; __builtin_clear_padding2(s2); - assert(memcmp(s1, s2, sizeof(S)) == 0); + assert2(memcmp(s1, s2, sizeof(S)) == 0); } // bit fields @@ -644,11 +662,12 @@ void structTests() { s2.b2 = 27; s1.b3 = 3; s2.b3 = 3; - __builtin_clear_padding(&s2); - print_bytes(&s1); - print_bytes(&s2); + __builtin_clear_padding2(&s2); + //print_bytes(&s1); + //print_bytes(&s2); + //assert(false); //TODO - //assert(memcmp(&s1, &s2, sizeof(S)) == 0); + //assert2(memcmp(&s1, &s2, sizeof(S)) == 0); } testAllStructsForType<32, 16, char>(11, 22, 33, 44); @@ -692,9 +711,9 @@ void unionTests() { u2.c = '4'; __builtin_clear_padding2(&u1); // should have no effect - assert(u1.c == '4'); + assert2(u1.c == '4'); - assert(memcmp(&u1, &u2, sizeof(u)) == 0); + assert2(memcmp(&u1, &u2, sizeof(u)) == 0); } // tail padding of longest member @@ -715,10 +734,10 @@ void unionTests() { u1.s1.c1 = '4'; u2.s1.c1 = '4'; - assert(memcmp(&u1, &u2, sizeof(u)) != 0); + assert2(memcmp(&u1, &u2, sizeof(u)) != 0); __builtin_clear_padding2(&u1); - assert(u1.s1.c1 == '4'); - assert(memcmp(&u1, &u2, sizeof(u)) == 0); + assert2(u1.s1.c1 == '4'); + assert2(memcmp(&u1, &u2, sizeof(u)) == 0); } } @@ -729,9 +748,9 @@ void arrayTests() { int i2[2] = {1, 2}; __builtin_clear_padding2(&i1); - assert(i1[0] == 1); - assert(i1[1] == 2); - assert(memcmp(&i1, &i2, 2 * sizeof(int)) == 0); + assert2(i1[0] == 1); + assert2(i1[1] == 2); + assert2(memcmp(&i1, &i2, 2 * sizeof(int)) == 0); } // long double @@ -746,9 +765,9 @@ void arrayTests() { d2[1] = 4.0L; __builtin_clear_padding2(&d1); - assert(d1[0] == 3.0L); - assert(d2[1] == 4.0L); - assert(memcmp(&d1, &d2, 2 * sizeof(long double)) == 0); + assert2(d1[0] == 3.0L); + assert2(d2[1] == 4.0L); + assert2(memcmp(&d1, &d2, 2 * sizeof(long double)) == 0); } // struct @@ -782,18 +801,18 @@ void arrayTests() { s2[1].i2 = 4; s2[1].c2 = 'd'; - assert(memcmp(&s1, &s2, 2 * sizeof(S)) != 0); + assert2(memcmp(&s1, &s2, 2 * sizeof(S)) != 0); __builtin_clear_padding2(&s1); - assert(s1[0].i1 == 1); - assert(s1[0].c1 == 'a'); - assert(s1[0].i2 == 2); - assert(s1[0].c2 == 'b'); - assert(s1[1].i1 == 3); - assert(s1[1].c1 == 'c'); - assert(s1[1].i2 == 4); - assert(s1[1].c2 == 'd'); - assert(memcmp(&s1, &s2, 2 * sizeof(S)) == 0); + assert2(s1[0].i1 == 1); + assert2(s1[0].c1 == 'a'); + assert2(s1[0].i2 == 2); + assert2(s1[0].c2 == 'b'); + assert2(s1[1].i1 == 3); + assert2(s1[1].c1 == 'c'); + assert2(s1[1].i2 == 4); + assert2(s1[1].c2 == 'd'); + assert2(memcmp(&s1, &s2, 2 * sizeof(S)) == 0); } }