diff options
author | Fariborz Jahanian <fjahanian@apple.com> | 2009-08-21 18:30:26 +0000 |
---|---|---|
committer | Fariborz Jahanian <fjahanian@apple.com> | 2009-08-21 18:30:26 +0000 |
commit | eb0b6d556ff2b4a5053e89fd084eb34e44cea14c (patch) | |
tree | dd7c01ab6cd422153f3b5ee274b534e4f9fd155a | |
parent | 666a91edc949f5b52eeef481601e2a60de4fdebe (diff) |
Patch to provide ir-gen support in copying array members
when synthesizing a copy constructor. Arrays's base element
may have a trivial or non-trivial copy constructor.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@79653 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/CodeGen/CGCXX.cpp | 106 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 6 | ||||
-rw-r--r-- | test/CodeGenCXX/copy-constructor-synthesis.cpp | 34 |
3 files changed, 136 insertions, 10 deletions
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 5bc8b40c63..9389af62d6 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -1093,9 +1093,85 @@ llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) { return vtable; } +/// EmitClassAggrMemberwiseCopy - This routine generates code to copy a class +/// array of objects from SrcValue to DestValue. Copying can be either a bitwise +/// copy or via a copy constructor call. +void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest, + llvm::Value *Src, + const ArrayType *Array, + const CXXRecordDecl *BaseClassDecl, + QualType Ty) { + const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array); + assert(CA && "VLA cannot be copied over"); + bool BitwiseCopy = BaseClassDecl->hasTrivialCopyConstructor(); + + // Create a temporary for the loop index and initialize it with 0. + llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext), + "loop.index"); + llvm::Value* zeroConstant = + llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)); + Builder.CreateStore(zeroConstant, IndexPtr, false); + // Start the loop with a block that tests the condition. + llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); + llvm::BasicBlock *AfterFor = createBasicBlock("for.end"); + + EmitBlock(CondBlock); + + llvm::BasicBlock *ForBody = createBasicBlock("for.body"); + // Generate: if (loop-index < number-of-elements fall to the loop body, + // otherwise, go to the block after the for-loop. + uint64_t NumElements = getContext().getConstantArrayElementCount(CA); + llvm::Value * NumElementsPtr = + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements); + llvm::Value *Counter = Builder.CreateLoad(IndexPtr); + llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr, + "isless"); + // If the condition is true, execute the body. + Builder.CreateCondBr(IsLess, ForBody, AfterFor); + + EmitBlock(ForBody); + llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc"); + // Inside the loop body, emit the constructor call on the array element. + Counter = Builder.CreateLoad(IndexPtr); + Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress"); + Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress"); + if (BitwiseCopy) + EmitAggregateCopy(Dest, Src, Ty); + else if (CXXConstructorDecl *BaseCopyCtor = + BaseClassDecl->getCopyConstructor(getContext(), 0)) { + llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor, + Ctor_Complete); + CallArgList CallArgs; + // Push the this (Dest) ptr. + CallArgs.push_back(std::make_pair(RValue::get(Dest), + BaseCopyCtor->getThisType(getContext()))); + + // Push the Src ptr. + CallArgs.push_back(std::make_pair(RValue::get(Src), + BaseCopyCtor->getParamDecl(0)->getType())); + QualType ResultType = + BaseCopyCtor->getType()->getAsFunctionType()->getResultType(); + EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + Callee, CallArgs, BaseCopyCtor); + } + EmitBlock(ContinueBlock); + + // Emit the increment of the loop counter. + llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1); + Counter = Builder.CreateLoad(IndexPtr); + NextVal = Builder.CreateAdd(Counter, NextVal, "inc"); + Builder.CreateStore(NextVal, IndexPtr, false); + + // Finally, branch back up to the condition for the next iteration. + EmitBranch(CondBlock); + + // Emit the fall-through block. + EmitBlock(AfterFor, true); +} + /// EmitClassMemberwiseCopy - This routine generates code to copy a class /// object from SrcValue to DestValue. Copying can be either a bitwise copy -/// of via a copy constructor call. +/// or via a copy constructor call. void CodeGenFunction::EmitClassMemberwiseCopy( llvm::Value *Dest, llvm::Value *Src, const CXXRecordDecl *ClassDecl, @@ -1230,19 +1306,29 @@ void CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *CD, FieldEnd = ClassDecl->field_end(); Field != FieldEnd; ++Field) { QualType FieldType = getContext().getCanonicalType((*Field)->getType()); - - // FIXME. How about copying arrays! - assert(!getContext().getAsArrayType(FieldType) && - "FIXME. Copying arrays NYI"); - + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = getContext().getBaseElementType(FieldType); + if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(FieldClassType->getDecl()); LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0); - - EmitClassMemberwiseCopy(LHS.getAddress(), RHS.getAddress(), - 0 /*ClassDecl*/, FieldClassDecl, FieldType); + if (Array) { + const llvm::Type *BasePtr = ConvertType(FieldType); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *DestBaseAddrPtr = + Builder.CreateBitCast(LHS.getAddress(), BasePtr); + llvm::Value *SrcBaseAddrPtr = + Builder.CreateBitCast(RHS.getAddress(), BasePtr); + EmitClassAggrMemberwiseCopy(DestBaseAddrPtr, SrcBaseAddrPtr, Array, + FieldClassDecl, FieldType); + } + else + EmitClassMemberwiseCopy(LHS.getAddress(), RHS.getAddress(), + 0 /*ClassDecl*/, FieldClassDecl, FieldType); continue; } // Do a built-in assignment of scalar data members. @@ -1363,7 +1449,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD) { FieldDecl *Field = Member->getMember(); QualType FieldType = getContext().getCanonicalType((Field)->getType()); const ConstantArrayType *Array = - getContext().getAsConstantArrayType(FieldType); + getContext().getAsConstantArrayType(FieldType); if (Array) FieldType = getContext().getBaseElementType(FieldType); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 71614c451c..583bfe3bfd 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -568,6 +568,12 @@ public: const CXXRecordDecl *ClassDecl, const CXXRecordDecl *BaseClassDecl); + void EmitClassAggrMemberwiseCopy(llvm::Value *DestValue, + llvm::Value *SrcValue, + const ArrayType *Array, + const CXXRecordDecl *BaseClassDecl, + QualType Ty); + void EmitClassMemberwiseCopy(llvm::Value *DestValue, llvm::Value *SrcValue, const CXXRecordDecl *ClassDecl, const CXXRecordDecl *BaseClassDecl, diff --git a/test/CodeGenCXX/copy-constructor-synthesis.cpp b/test/CodeGenCXX/copy-constructor-synthesis.cpp index 121fd41b5c..2fe196d694 100644 --- a/test/CodeGenCXX/copy-constructor-synthesis.cpp +++ b/test/CodeGenCXX/copy-constructor-synthesis.cpp @@ -57,6 +57,36 @@ struct X : M, N, P { // ... }; }; +static int ix = 1; +// class with user-defined copy constructor. +struct S { + S() : iS(ix++) { } + S(const S& arg) { *this = arg; } + int iS; +}; + +// class with trivial copy constructor. +struct I { + I() : iI(ix++) { } + int iI; +}; + +struct XM { + XM() { } + double dXM; + S ARR_S[3][4][2]; + void pr() { + for (unsigned i = 0; i < 3; i++) + for (unsigned j = 0; j < 4; j++) + for (unsigned k = 0; k < 2; k++) + printf("ARR_S[%d][%d][%d] = %d\n", i,j,k, ARR_S[i][j][k].iS); + for (unsigned i = 0; i < 3; i++) + for (unsigned k = 0; k < 2; k++) + printf("ARR_I[%d][%d] = %d\n", i,k, ARR_I[i][k].iI); + } + I ARR_I[3][2]; +}; + int main() { X a; @@ -65,6 +95,10 @@ int main() X x; X c(x); c.pr(); + + XM m0; + XM m1 = m0; + m1.pr(); } // CHECK-LP64: .globl __ZN1XC1ERK1X // CHECK-LP64: .weak_definition __ZN1XC1ERK1X |