diff options
-rw-r--r-- | clang/lib/CodeGen/CGDecl.cpp | 179 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 13 | ||||
-rw-r--r-- | clang/test/CodeGen/cast-to-union.c | 1 | ||||
-rw-r--r-- | clang/test/CodeGen/decl.c | 28 | ||||
-rw-r--r-- | clang/test/CodeGen/string-init.c | 2 |
5 files changed, 158 insertions, 65 deletions
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 0950d916f7a..372195f5f10 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -86,28 +86,32 @@ void CodeGenFunction::EmitBlockVarDecl(const VarDecl &D) { 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 @@ CodeGenFunction::CreateStaticBlockVarDecl(const VarDecl &D, 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 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) { 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 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { bool isByRef = D.hasAttr<BlocksAttr>(); bool needsDispose = false; unsigned Align = 0; + bool IsSimpleConstantInitializer = false; llvm::Value *DeclPtr; if (Ty->isConstantSizeType()) { @@ -325,27 +342,28 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { // 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 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { 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())) { diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 8a386dec8cc..1a49c944a2e 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -1076,9 +1076,18 @@ public: /// 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. diff --git a/clang/test/CodeGen/cast-to-union.c b/clang/test/CodeGen/cast-to-union.c index 1f7e0457706..b1019da0a37 100644 --- a/clang/test/CodeGen/cast-to-union.c +++ b/clang/test/CodeGen/cast-to-union.c @@ -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; }; diff --git a/clang/test/CodeGen/decl.c b/clang/test/CodeGen/decl.c index e2d55ecaf1c..b26843132c2 100644 --- a/clang/test/CodeGen/decl.c +++ b/clang/test/CodeGen/decl.c @@ -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 @@ void test1() { // 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 +} + diff --git a/clang/test/CodeGen/string-init.c b/clang/test/CodeGen/string-init.c index 0cb6afff611..410a4072825 100644 --- a/clang/test/CodeGen/string-init.c +++ b/clang/test/CodeGen/string-init.c @@ -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 |