]> granicus.if.org Git - clang/commitdiff
Patch to provide ir-gen support in copying array members
authorFariborz Jahanian <fjahanian@apple.com>
Fri, 21 Aug 2009 18:30:26 +0000 (18:30 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Fri, 21 Aug 2009 18:30:26 +0000 (18:30 +0000)
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

lib/CodeGen/CGCXX.cpp
lib/CodeGen/CodeGenFunction.h
test/CodeGenCXX/copy-constructor-synthesis.cpp

index 5bc8b40c63730394973a92bb218935e88cd3fbcc..9389af62d6f841d7017b80ac0e9c70aed71c6113 100644 (file)
@@ -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);
       
index 71614c451ced40157e71844af46e5d497607ffcc..583bfe3bfdb2db3e764dc2bf2bff0cbdcae9b570 100644 (file)
@@ -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,
index 121fd41b5cc61463cadbd3aefab1909dff88bc6c..2fe196d69410326b44d4f989795c1603bc31dcad 100644 (file)
@@ -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