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 =
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!");
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>()) {
bool isByRef = D.hasAttr<BlocksAttr>();
bool needsDispose = false;
unsigned Align = 0;
+ bool IsSimpleConstantInitializer = false;
llvm::Value *DeclPtr;
if (Ty->isConstantSizeType()) {
// 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);
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())) {