[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