/// \brief True if the given aggregate type requires special GC API calls. bool AggExprEmitter::TypeRequiresGCollection(QualType T) { // Only record types have members that might require garbage collection. const RecordType *RecordTy = T->getAs<RecordType>(); if (!RecordTy) return false; // Don't mess with non-trivial C++ types. RecordDecl *Record = RecordTy->getDecl(); if (isa<CXXRecordDecl>(Record) && (!cast<CXXRecordDecl>(Record)->hasTrivialCopyConstructor() || !cast<CXXRecordDecl>(Record)->hasTrivialDestructor())) return false; // Check whether the type has an object member. return Record->hasObjectMember(); }
void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, llvm::Value *SrcPtr, QualType Ty, bool isVolatile, unsigned Alignment) { assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex"); if (getContext().getLangOptions().CPlusPlus) { if (const RecordType *RT = Ty->getAs<RecordType>()) { CXXRecordDecl *Record = cast<CXXRecordDecl>(RT->getDecl()); assert((Record->hasTrivialCopyConstructor() || Record->hasTrivialCopyAssignment() || Record->hasTrivialMoveConstructor() || Record->hasTrivialMoveAssignment()) && "Trying to aggregate-copy a type without a trivial copy " "constructor or assignment operator"); // Ignore empty classes in C++. if (Record->isEmpty()) 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 // object, then the overlap shall be exact and the two objects shall have // qualified or unqualified versions of a compatible type." // // memcpy is not defined if the source and destination pointers are exactly // equal, but other compilers do this optimization, and almost every memcpy // implementation handles this case safely. If there is a libc that does not // safely handle this, we can add a target hook. // Get size and alignment info for this aggregate. std::pair<CharUnits, CharUnits> TypeInfo = getContext().getTypeInfoInChars(Ty); if (!Alignment) Alignment = TypeInfo.second.getQuantity(); // FIXME: Handle variable sized types. // FIXME: If we have a volatile struct, the optimizer can remove what might // appear to be `extra' memory ops: // // volatile struct { int i; } a, b; // // int main() { // a = b; // a = b; // } // // we need to use a different call here. We use isVolatile to indicate when // either the source or the destination is volatile. llvm::PointerType *DPT = cast<llvm::PointerType>(DestPtr->getType()); llvm::Type *DBP = llvm::Type::getInt8PtrTy(getLLVMContext(), DPT->getAddressSpace()); DestPtr = Builder.CreateBitCast(DestPtr, DBP); llvm::PointerType *SPT = cast<llvm::PointerType>(SrcPtr->getType()); llvm::Type *SBP = llvm::Type::getInt8PtrTy(getLLVMContext(), SPT->getAddressSpace()); SrcPtr = Builder.CreateBitCast(SrcPtr, SBP); // Don't do any of the memmove_collectable tests if GC isn't set. if (CGM.getLangOptions().getGC() == LangOptions::NonGC) { // fall through } else if (const RecordType *RecordTy = Ty->getAs<RecordType>()) { RecordDecl *Record = RecordTy->getDecl(); if (Record->hasObjectMember()) { CharUnits size = TypeInfo.first; llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size.getQuantity()); CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestPtr, SrcPtr, SizeVal); return; } } else if (Ty->isArrayType()) { QualType BaseType = getContext().getBaseElementType(Ty); if (const RecordType *RecordTy = BaseType->getAs<RecordType>()) { if (RecordTy->getDecl()->hasObjectMember()) { CharUnits size = TypeInfo.first; llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size.getQuantity()); CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestPtr, SrcPtr, SizeVal); return; } } } Builder.CreateMemCpy(DestPtr, SrcPtr, llvm::ConstantInt::get(IntPtrTy, TypeInfo.first.getQuantity()), Alignment, isVolatile); }