[cfe-commits] r90658 - in /cfe/trunk: lib/CodeGen/CGDecl.cpp lib/CodeGen/CodeGenFunction.h test/CodeGen/cast-to-union.c test/CodeGen/decl.c test/CodeGen/string-init.c

Chris Lattner sabre at nondot.org
Sat Dec 5 00:22:11 PST 2009


Author: lattner
Date: Sat Dec  5 02:22:11 2009
New Revision: 90658

URL: http://llvm.org/viewvc/llvm-project?rev=90658&view=rev
Log:
implement rdar://7346691 by codegen'ing struct/array initializers
to a memset or a memcpy from a global when possible.

Modified:
    cfe/trunk/lib/CodeGen/CGDecl.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/test/CodeGen/cast-to-union.c
    cfe/trunk/test/CodeGen/decl.c
    cfe/trunk/test/CodeGen/string-init.c

Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=90658&r1=90657&r2=90658&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Sat Dec  5 02:22:11 2009
@@ -86,28 +86,32 @@
   assert(0 && "Unknown storage class");
 }
 
+static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D,
+                                     const char *Separator) {
+  CodeGenModule &CGM = CGF.CGM;
+  if (CGF.getContext().getLangOptions().CPlusPlus)
+    return CGM.getMangledName(&D);
+  
+  std::string ContextName;
+  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CGF.CurFuncDecl))
+    ContextName = CGM.getMangledName(FD);
+  else if (isa<ObjCMethodDecl>(CGF.CurFuncDecl))
+    ContextName = CGF.CurFn->getName();
+  else
+    // FIXME: What about in a block??
+    assert(0 && "Unknown context for block var decl");
+  
+  return ContextName + Separator + D.getNameAsString();
+}
+
 llvm::GlobalVariable *
 CodeGenFunction::CreateStaticBlockVarDecl(const VarDecl &D,
                                           const char *Separator,
-                                          llvm::GlobalValue::LinkageTypes
-                                          Linkage) {
+                                      llvm::GlobalValue::LinkageTypes Linkage) {
   QualType Ty = D.getType();
   assert(Ty->isConstantSizeType() && "VLAs can't be static");
 
-  std::string Name;
-  if (getContext().getLangOptions().CPlusPlus) {
-    Name = CGM.getMangledName(&D);
-  } else {
-    std::string ContextName;
-    if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurFuncDecl))
-      ContextName = CGM.getMangledName(FD);
-    else if (isa<ObjCMethodDecl>(CurFuncDecl))
-      ContextName = CurFn->getName();
-    else
-      assert(0 && "Unknown context for block var decl");
-
-    Name = ContextName + Separator + D.getNameAsString();
-  }
+  std::string Name = GetStaticDeclName(*this, D, Separator);
 
   const llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty);
   llvm::GlobalVariable *GV =
@@ -119,6 +123,54 @@
   return GV;
 }
 
+/// AddInitializerToGlobalBlockVarDecl - Add the initializer for 'D' to the
+/// global variable that has already been created for it.  If the initializer
+/// has a different type than GV does, this may free GV and return a different
+/// one.  Otherwise it just returns GV.
+llvm::GlobalVariable *
+CodeGenFunction::AddInitializerToGlobalBlockVarDecl(const VarDecl &D,
+                                                    llvm::GlobalVariable *GV) {
+  llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(), D.getType(), this);
+  
+  // If constant emission failed, then this should be a C++ static
+  // initializer.
+  if (!Init) {
+    if (!getContext().getLangOptions().CPlusPlus)
+      CGM.ErrorUnsupported(D.getInit(), "constant l-value expression");
+    else
+      EmitStaticCXXBlockVarDeclInit(D, GV);
+    return GV;
+  }
+  
+  // The initializer may differ in type from the global. Rewrite
+  // the global to match the initializer.  (We have to do this
+  // because some types, like unions, can't be completely represented
+  // in the LLVM type system.)
+  if (GV->getType() != Init->getType()) {
+    llvm::GlobalVariable *OldGV = GV;
+    
+    GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(),
+                                  OldGV->isConstant(),
+                                  OldGV->getLinkage(), Init, "",
+                                  0, D.isThreadSpecified(),
+                                  D.getType().getAddressSpace());
+    
+    // Steal the name of the old global
+    GV->takeName(OldGV);
+    
+    // Replace all uses of the old global with the new global
+    llvm::Constant *NewPtrForOldDecl =
+    llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
+    OldGV->replaceAllUsesWith(NewPtrForOldDecl);
+    
+    // Erase the old global, since it is no longer used.
+    OldGV->eraseFromParent();
+  }
+  
+  GV->setInitializer(Init);
+  return GV;
+}
+
 void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) {
   llvm::Value *&DMEntry = LocalDeclMap[&D];
   assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
@@ -136,45 +188,9 @@
   if (D.getType()->isVariablyModifiedType())
     EmitVLASize(D.getType());
 
-  if (D.getInit()) {
-    llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(), D.getType(), this);
-
-    // If constant emission failed, then this should be a C++ static
-    // initializer.
-    if (!Init) {
-      if (!getContext().getLangOptions().CPlusPlus)
-        CGM.ErrorUnsupported(D.getInit(), "constant l-value expression");
-      else
-        EmitStaticCXXBlockVarDeclInit(D, GV);
-    } else {
-      // The initializer may differ in type from the global. Rewrite
-      // the global to match the initializer.  (We have to do this
-      // because some types, like unions, can't be completely represented
-      // in the LLVM type system.)
-      if (GV->getType() != Init->getType()) {
-        llvm::GlobalVariable *OldGV = GV;
-
-        GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(),
-                                      OldGV->isConstant(),
-                                      OldGV->getLinkage(), Init, "",
-                                      0, D.isThreadSpecified(),
-                                      D.getType().getAddressSpace());
-
-        // Steal the name of the old global
-        GV->takeName(OldGV);
-
-        // Replace all uses of the old global with the new global
-        llvm::Constant *NewPtrForOldDecl =
-          llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
-        OldGV->replaceAllUsesWith(NewPtrForOldDecl);
-
-        // Erase the old global, since it is no longer used.
-        OldGV->eraseFromParent();
-      }
-
-      GV->setInitializer(Init);
-    }
-  }
+  // If this value has an initializer, emit it.
+  if (D.getInit())
+    GV = AddInitializerToGlobalBlockVarDecl(D, GV);
 
   // FIXME: Merge attribute handling.
   if (const AnnotateAttr *AA = D.getAttr<AnnotateAttr>()) {
@@ -318,6 +334,7 @@
   bool isByRef = D.hasAttr<BlocksAttr>();
   bool needsDispose = false;
   unsigned Align = 0;
+  bool IsSimpleConstantInitializer = false;
 
   llvm::Value *DeclPtr;
   if (Ty->isConstantSizeType()) {
@@ -325,27 +342,28 @@
       
       // If this value is an array or struct, is POD, and if the initializer is
       // a staticly determinable constant, try to optimize it.
-      if (D.getInit() &&
+      if (D.getInit() && !isByRef &&
           (Ty->isArrayType() || Ty->isRecordType()) &&
           Ty->isPODType() &&
           D.getInit()->isConstantInitializer(getContext())) {
-
         // If this variable is marked 'const', emit the value as a global.
         if (CGM.getCodeGenOpts().MergeAllConstants &&
             Ty.isConstant(getContext())) {
           EmitStaticBlockVarDecl(D);
           return;
         }
+        
+        IsSimpleConstantInitializer = true;
       }
       
       // A normal fixed sized variable becomes an alloca in the entry block.
       const llvm::Type *LTy = ConvertTypeForMem(Ty);
-      Align = getContext().getDeclAlignInBytes(&D);
       if (isByRef)
         LTy = BuildByRefType(&D);
       llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
       Alloc->setName(D.getNameAsString().c_str());
 
+      Align = getContext().getDeclAlignInBytes(&D);
       if (isByRef)
         Align = std::max(Align, unsigned(Target.getPointerAlign(0) / 8));
       Alloc->setAlignment(Align);
@@ -439,9 +457,48 @@
       Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D), 
                                     D.getNameAsString());
 
-    bool isVolatile = (getContext().getCanonicalType(D.getType())
-                       .isVolatileQualified());
-    if (Ty->isReferenceType()) {
+    bool isVolatile =
+      getContext().getCanonicalType(D.getType()).isVolatileQualified();
+    
+    // If the initializer was a simple constant initializer, we can optimize it
+    // in various ways.
+    if (IsSimpleConstantInitializer) {
+      llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(),D.getType(),this);
+      assert(Init != 0 && "Wasn't a simple constant init?");
+      
+      llvm::Value *AlignVal = 
+        llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Align);
+      const llvm::Type *IntPtr =
+        llvm::IntegerType::get(VMContext, LLVMPointerWidth);
+      llvm::Value *SizeVal =
+        llvm::ConstantInt::get(IntPtr, getContext().getTypeSizeInBytes(Ty));
+
+      const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext);
+      if (Loc->getType() != BP)
+        Loc = Builder.CreateBitCast(Loc, BP, "tmp");
+      
+      // If the initializer is all zeros, codegen with memset.
+      if (isa<llvm::ConstantAggregateZero>(Init)) {
+        llvm::Value *Zero =
+          llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 0);
+        Builder.CreateCall4(CGM.getMemSetFn(), Loc, Zero, SizeVal, AlignVal);
+      } else {
+        // Otherwise, create a temporary global with the initializer then 
+        // memcpy from the global to the alloca.
+        std::string Name = GetStaticDeclName(*this, D, ".");
+        llvm::GlobalVariable *GV =
+          new llvm::GlobalVariable(CGM.getModule(), Init->getType(), true,
+                                   llvm::GlobalValue::InternalLinkage,
+                                   Init, Name, 0, false, 0);
+        GV->setAlignment(Align);
+
+        llvm::Value *SrcPtr = GV;
+        if (SrcPtr->getType() != BP)
+          SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp");
+        
+        Builder.CreateCall4(CGM.getMemCpyFn(), Loc, SrcPtr, SizeVal, AlignVal);
+      }
+    } else if (Ty->isReferenceType()) {
       RValue RV = EmitReferenceBindingToExpr(Init, Ty, /*IsInitializer=*/true);
       EmitStoreOfScalar(RV.getScalarVal(), Loc, false, Ty);
     } else if (!hasAggregateLLVMType(Init->getType())) {

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=90658&r1=90657&r2=90658&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Sat Dec  5 02:22:11 2009
@@ -1076,9 +1076,18 @@
 
   /// CreateStaticBlockVarDecl - Create a zero-initialized LLVM global for a
   /// static block var decl.
-  llvm::GlobalVariable * CreateStaticBlockVarDecl(const VarDecl &D,
-                                                  const char *Separator,
+  llvm::GlobalVariable *CreateStaticBlockVarDecl(const VarDecl &D,
+                                                 const char *Separator,
                                        llvm::GlobalValue::LinkageTypes Linkage);
+  
+  /// AddInitializerToGlobalBlockVarDecl - Add the initializer for 'D' to the
+  /// global variable that has already been created for it.  If the initializer
+  /// has a different type than GV does, this may free GV and return a different
+  /// one.  Otherwise it just returns GV.
+  llvm::GlobalVariable *
+  AddInitializerToGlobalBlockVarDecl(const VarDecl &D,
+                                     llvm::GlobalVariable *GV);
+  
 
   /// EmitStaticCXXBlockVarDeclInit - Create the initializer for a C++ runtime
   /// initialized static block var decl.

Modified: cfe/trunk/test/CodeGen/cast-to-union.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/cast-to-union.c?rev=90658&r1=90657&r2=90658&view=diff

==============================================================================
--- cfe/trunk/test/CodeGen/cast-to-union.c (original)
+++ cfe/trunk/test/CodeGen/cast-to-union.c Sat Dec  5 02:22:11 2009
@@ -1,7 +1,6 @@
 // RUN: clang-cc -emit-llvm  %s -o - | FileCheck %s
 // CHECK: w = global %0 { i32 2, [4 x i8] undef }
 // CHECK: y = global %union.u { double 7.300000e+0{{[0]*}}1 }
-// CHECK: store i32 351, i32
 
 union u { int i; double d; };
 

Modified: cfe/trunk/test/CodeGen/decl.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/decl.c?rev=90658&r1=90657&r2=90658&view=diff

==============================================================================
--- cfe/trunk/test/CodeGen/decl.c (original)
+++ cfe/trunk/test/CodeGen/decl.c Sat Dec  5 02:22:11 2009
@@ -1,6 +1,9 @@
 // RUN: clang-cc -emit-llvm < %s | FileCheck %s
 
 // CHECK: @test1.x = internal constant [12 x i32] [i32 1
+// CHECK: @test2.x = internal constant [13 x i32] [i32 1,
+
+#include <string.h>
 
 void test1() {
   // This should codegen as a "@test1.x" global.
@@ -10,3 +13,28 @@
 // CHECK: @test1()
 // CHECK: {{call.*@foo.*@test1.x}}
 }
+
+
+// rdar://7346691
+void test2() {
+  // This should codegen as a "@test2.x" global + memcpy.
+  int x[] = { 1, 2, 3, 4, 6, 8, 9, 10, 123, 231, 123,23, 24 };
+  foo(x);
+  
+  // CHECK: @test2()
+  // CHECK: %x = alloca [13 x i32]
+  // CHECK: call void @llvm.memcpy
+  // CHECK: call{{.*}}@foo{{.*}}i32* %
+}
+
+
+void test3() {
+  // This should codegen as a "@test3.x" global + memcpy.
+  int x[100] = { 0 };
+  foo(x);
+  
+  // CHECK: @test3()
+  // CHECK: %x = alloca [100 x i32]
+  // CHECK: call void @llvm.memset
+}
+

Modified: cfe/trunk/test/CodeGen/string-init.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/string-init.c?rev=90658&r1=90657&r2=90658&view=diff

==============================================================================
--- cfe/trunk/test/CodeGen/string-init.c (original)
+++ cfe/trunk/test/CodeGen/string-init.c Sat Dec  5 02:22:11 2009
@@ -1,5 +1,5 @@
 // RUN: clang-cc -emit-llvm %s -o %t
-// RUN: grep 'private constant \[10 x i8\]' %t
+// RUN: grep 'internal constant \[10 x i8\]' %t
 // RUN: not grep -F "[5 x i8]" %t
 // RUN: not grep "store " %t
 





More information about the cfe-commits mailing list