[clang] [libc++] Add builtin to clear padding bytes (prework for P0528R3) (PR #75371)
Eli Friedman via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 26 10:56:59 PST 2024
================
@@ -2456,6 +2461,139 @@ static RValue EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF,
return RValue::get(CGF->Builder.CreateCall(UBF, Args));
}
+template <class T>
+void RecursivelyClearPaddingImpl(CodeGenFunction &CGF, Value *Ptr, QualType Ty, size_t CurrentStartOffset, size_t &RunningOffset, T&& WriteZeroAtOffset);
+
+template <class T>
+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<CXXRecordDecl>(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<CXXRecordDecl>(Base.getType()->getAsRecordDecl());
+ auto Offset = static_cast<size_t>(
+ 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 <class T>
+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 <class T>
+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<ConstantArrayType>(Ty)) {
+ ClearPaddingConstantArray(CGF, Ptr, Type, AT, CurrentStartOffset, RunningOffset, WriteZeroAtOffset);
+ }
+ else if (auto *ST = dyn_cast<StructType>(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 " << RunningOffset + Size << std::endl;
+ RunningOffset = std::max(RunningOffset, CurrentStartOffset + static_cast<size_t>(Size));
----------------
efriedma-quic wrote:
Oh, I see, this is querying the typesize from LLVM. I guess that works for most cases...? I don't think it works for _Complex long double. Maybe worth adding a comment explicitly noting how this size computation works.
https://github.com/llvm/llvm-project/pull/75371
More information about the cfe-commits
mailing list