From 627746581b8fde4143533937130f420bbbdf9ddf Mon Sep 17 00:00:00 2001 From: yabinc Date: Tue, 15 Oct 2024 00:32:24 +0100 Subject: Reapply "[clang][CodeGen] Zero init unspecified fields in initializers in C" (#109898) (#110051) This reverts commit d50eaac12f0cdfe27e942290942b06889ab12a8c. Also fixes a bug calculating offsets for bit fields in the original patch. --- clang/lib/CodeGen/CGExprAgg.cpp | 73 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 2 deletions(-) (limited to 'clang/lib/CodeGen/CGExprAgg.cpp') diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 74d4c5e..2ad6587 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -12,6 +12,7 @@ #include "CGCXXABI.h" #include "CGObjCRuntime.h" +#include "CGRecordLayout.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "ConstantEmitter.h" @@ -64,6 +65,9 @@ class AggExprEmitter : public StmtVisitor { void withReturnValueSlot(const Expr *E, llvm::function_ref Fn); + void DoZeroInitPadding(uint64_t &PaddingStart, uint64_t PaddingEnd, + const FieldDecl *NextField); + public: AggExprEmitter(CodeGenFunction &cgf, AggValueSlot Dest, bool IsResultUnused) : CGF(cgf), Builder(CGF.Builder), Dest(Dest), @@ -1698,6 +1702,9 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( // Prepare a 'this' for CXXDefaultInitExprs. CodeGenFunction::FieldConstructionScope FCS(CGF, Dest.getAddress()); + const bool ZeroInitPadding = + CGF.CGM.shouldZeroInitPadding() && !Dest.isZeroed(); + if (record->isUnion()) { // Only initialize one field of a union. The field itself is // specified by the initializer list. @@ -1722,16 +1729,27 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( if (NumInitElements) { // Store the initializer into the field EmitInitializationToLValue(InitExprs[0], FieldLoc); + if (ZeroInitPadding) { + uint64_t TotalSize = CGF.getContext().toBits( + Dest.getPreferredSize(CGF.getContext(), DestLV.getType())); + uint64_t FieldSize = CGF.getContext().getTypeSize(FieldLoc.getType()); + DoZeroInitPadding(FieldSize, TotalSize, nullptr); + } } else { // Default-initialize to null. - EmitNullInitializationToLValue(FieldLoc); + if (ZeroInitPadding) + EmitNullInitializationToLValue(DestLV); + else + EmitNullInitializationToLValue(FieldLoc); } - return; } // Here we iterate over the fields; this makes it simpler to both // default-initialize fields and skip over unnamed fields. + const ASTRecordLayout &Layout = CGF.getContext().getASTRecordLayout(record); + uint64_t PaddingStart = 0; + for (const auto *field : record->fields()) { // We're done once we hit the flexible array member. if (field->getType()->isIncompleteArrayType()) @@ -1748,6 +1766,9 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( CGF.getTypes().isZeroInitializable(ExprToVisit->getType())) break; + if (ZeroInitPadding) + DoZeroInitPadding(PaddingStart, + Layout.getFieldOffset(field->getFieldIndex()), field); LValue LV = CGF.EmitLValueForFieldInitialization(DestLV, field); // We never generate write-barries for initialized fields. @@ -1774,6 +1795,54 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( } } } + if (ZeroInitPadding) { + uint64_t TotalSize = CGF.getContext().toBits( + Dest.getPreferredSize(CGF.getContext(), DestLV.getType())); + DoZeroInitPadding(PaddingStart, TotalSize, nullptr); + } +} + +void AggExprEmitter::DoZeroInitPadding(uint64_t &PaddingStart, + uint64_t PaddingEnd, + const FieldDecl *NextField) { + + auto InitBytes = [&](uint64_t StartBit, uint64_t EndBit) { + CharUnits Start = CGF.getContext().toCharUnitsFromBits(StartBit); + CharUnits End = CGF.getContext().toCharUnitsFromBits(EndBit); + Address Addr = Dest.getAddress().withElementType(CGF.CharTy); + if (!Start.isZero()) + Addr = Builder.CreateConstGEP(Addr, Start.getQuantity()); + llvm::Constant *SizeVal = Builder.getInt64((End - Start).getQuantity()); + CGF.Builder.CreateMemSet(Addr, Builder.getInt8(0), SizeVal, false); + }; + + if (NextField != nullptr && NextField->isBitField()) { + // For bitfield, zero init StorageSize before storing the bits. So we don't + // need to handle big/little endian. + const CGRecordLayout &RL = + CGF.getTypes().getCGRecordLayout(NextField->getParent()); + const CGBitFieldInfo &Info = RL.getBitFieldInfo(NextField); + uint64_t StorageStart = CGF.getContext().toBits(Info.StorageOffset); + if (StorageStart + Info.StorageSize > PaddingStart) { + if (StorageStart > PaddingStart) + InitBytes(PaddingStart, StorageStart); + Address Addr = Dest.getAddress(); + if (!Info.StorageOffset.isZero()) + Addr = Builder.CreateConstGEP(Addr.withElementType(CGF.CharTy), + Info.StorageOffset.getQuantity()); + Addr = Addr.withElementType( + llvm::Type::getIntNTy(CGF.getLLVMContext(), Info.StorageSize)); + Builder.CreateStore(Builder.getIntN(Info.StorageSize, 0), Addr); + PaddingStart = StorageStart + Info.StorageSize; + } + return; + } + + if (PaddingStart < PaddingEnd) + InitBytes(PaddingStart, PaddingEnd); + if (NextField != nullptr) + PaddingStart = + PaddingEnd + CGF.getContext().getTypeSize(NextField->getType()); } void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E, -- cgit v1.1