HsiangKai created this revision. HsiangKai added reviewers: craig.topper, frasercrmck, rogfer01. Herald added a subscriber: StephenFan. HsiangKai requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
For scalable struct types, we do not know the exact size of the struct. Do not use memcpy for struct copy. We use extractvalue and insertvalue for the purpose. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D99590 Files: clang/include/clang/AST/Type.h clang/lib/AST/Type.cpp clang/lib/CodeGen/CGExprAgg.cpp Index: clang/lib/CodeGen/CGExprAgg.cpp =================================================================== --- clang/lib/CodeGen/CGExprAgg.cpp +++ clang/lib/CodeGen/CGExprAgg.cpp @@ -2077,6 +2077,23 @@ } } + // Aggregate assignment turns into element-by-element copy. + if (const RecordType *RecordTy = Ty->getAs<RecordType>()) { + if (RecordTy->hasSizelessFields()) { + RecordDecl *Record = RecordTy->getDecl(); + llvm::Value *SrcVec = Builder.CreateLoad(SrcPtr); + llvm::Value *DestVec = llvm::UndefValue::get(ConvertType(Ty)); + llvm::Value *Vec; + for (unsigned I = 0; + I < getContext().getASTRecordLayout(Record).getFieldCount(); ++I) { + Vec = Builder.CreateExtractValue(SrcVec, I); + DestVec = Builder.CreateInsertValue(DestVec, Vec, I); + } + Builder.CreateStore(DestVec, DestPtr); + return; + } + } + // Aggregate assignment turns into llvm.memcpy. This is almost valid per // C99 6.5.16.1p3, which states "If the value being stored in an object is // read from another object that overlaps in anyway the storage of the first Index: clang/lib/AST/Type.cpp =================================================================== --- clang/lib/AST/Type.cpp +++ clang/lib/AST/Type.cpp @@ -3510,6 +3510,28 @@ return false; } +bool RecordType::hasSizelessFields() const { + std::vector<const RecordType *> RecordTypeList; + RecordTypeList.push_back(this); + unsigned NextToCheckIndex = 0; + + while (RecordTypeList.size() > NextToCheckIndex) { + for (FieldDecl *FD : + RecordTypeList[NextToCheckIndex]->getDecl()->fields()) { + QualType FieldTy = FD->getType(); + if (FieldTy.getTypePtr()->isSizelessType()) + return true; + FieldTy = FieldTy.getCanonicalType(); + if (const auto *FieldRecTy = FieldTy->getAs<RecordType>()) { + if (llvm::find(RecordTypeList, FieldRecTy) == RecordTypeList.end()) + RecordTypeList.push_back(FieldRecTy); + } + } + ++NextToCheckIndex; + } + return false; +} + bool AttributedType::isQualifier() const { // FIXME: Generate this with TableGen. switch (getAttrKind()) { Index: clang/include/clang/AST/Type.h =================================================================== --- clang/include/clang/AST/Type.h +++ clang/include/clang/AST/Type.h @@ -4623,6 +4623,10 @@ /// is declared const, return true. Otherwise, return false. bool hasConstFields() const; + /// Recursively check all fields in the record for sizeless. If any field + /// is sizeless type, return true. Otherwise, return false. + bool hasSizelessFields() const; + bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); }
Index: clang/lib/CodeGen/CGExprAgg.cpp =================================================================== --- clang/lib/CodeGen/CGExprAgg.cpp +++ clang/lib/CodeGen/CGExprAgg.cpp @@ -2077,6 +2077,23 @@ } } + // Aggregate assignment turns into element-by-element copy. + if (const RecordType *RecordTy = Ty->getAs<RecordType>()) { + if (RecordTy->hasSizelessFields()) { + RecordDecl *Record = RecordTy->getDecl(); + llvm::Value *SrcVec = Builder.CreateLoad(SrcPtr); + llvm::Value *DestVec = llvm::UndefValue::get(ConvertType(Ty)); + llvm::Value *Vec; + for (unsigned I = 0; + I < getContext().getASTRecordLayout(Record).getFieldCount(); ++I) { + Vec = Builder.CreateExtractValue(SrcVec, I); + DestVec = Builder.CreateInsertValue(DestVec, Vec, I); + } + Builder.CreateStore(DestVec, DestPtr); + return; + } + } + // Aggregate assignment turns into llvm.memcpy. This is almost valid per // C99 6.5.16.1p3, which states "If the value being stored in an object is // read from another object that overlaps in anyway the storage of the first Index: clang/lib/AST/Type.cpp =================================================================== --- clang/lib/AST/Type.cpp +++ clang/lib/AST/Type.cpp @@ -3510,6 +3510,28 @@ return false; } +bool RecordType::hasSizelessFields() const { + std::vector<const RecordType *> RecordTypeList; + RecordTypeList.push_back(this); + unsigned NextToCheckIndex = 0; + + while (RecordTypeList.size() > NextToCheckIndex) { + for (FieldDecl *FD : + RecordTypeList[NextToCheckIndex]->getDecl()->fields()) { + QualType FieldTy = FD->getType(); + if (FieldTy.getTypePtr()->isSizelessType()) + return true; + FieldTy = FieldTy.getCanonicalType(); + if (const auto *FieldRecTy = FieldTy->getAs<RecordType>()) { + if (llvm::find(RecordTypeList, FieldRecTy) == RecordTypeList.end()) + RecordTypeList.push_back(FieldRecTy); + } + } + ++NextToCheckIndex; + } + return false; +} + bool AttributedType::isQualifier() const { // FIXME: Generate this with TableGen. switch (getAttrKind()) { Index: clang/include/clang/AST/Type.h =================================================================== --- clang/include/clang/AST/Type.h +++ clang/include/clang/AST/Type.h @@ -4623,6 +4623,10 @@ /// is declared const, return true. Otherwise, return false. bool hasConstFields() const; + /// Recursively check all fields in the record for sizeless. If any field + /// is sizeless type, return true. Otherwise, return false. + bool hasSizelessFields() const; + bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits