#include "CGDebugInfo.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "CGOpenCLRuntime.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/GlobalVariable.h"
#include "llvm/Intrinsics.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Type.h"
using namespace clang;
using namespace CodeGen;
void CodeGenFunction::EmitDecl(const Decl &D) {
switch (D.getKind()) {
case Decl::TranslationUnit:
case Decl::Namespace:
case Decl::UnresolvedUsingTypename:
case Decl::ClassTemplateSpecialization:
case Decl::ClassTemplatePartialSpecialization:
case Decl::TemplateTypeParm:
case Decl::UnresolvedUsingValue:
case Decl::NonTypeTemplateParm:
case Decl::CXXMethod:
case Decl::CXXConstructor:
case Decl::CXXDestructor:
case Decl::CXXConversion:
case Decl::Field:
case Decl::IndirectField:
case Decl::ObjCIvar:
case Decl::ObjCAtDefsField:
case Decl::ParmVar:
case Decl::ImplicitParam:
case Decl::ClassTemplate:
case Decl::FunctionTemplate:
case Decl::TypeAliasTemplate:
case Decl::TemplateTemplateParm:
case Decl::ObjCMethod:
case Decl::ObjCCategory:
case Decl::ObjCProtocol:
case Decl::ObjCInterface:
case Decl::ObjCCategoryImpl:
case Decl::ObjCImplementation:
case Decl::ObjCProperty:
case Decl::ObjCCompatibleAlias:
case Decl::AccessSpec:
case Decl::LinkageSpec:
case Decl::ObjCPropertyImpl:
case Decl::FileScopeAsm:
case Decl::Friend:
case Decl::FriendTemplate:
case Decl::Block:
case Decl::ClassScopeFunctionSpecialization:
llvm_unreachable("Declaration should not be in declstmts!");
case Decl::Function: case Decl::Record: case Decl::Enum: case Decl::EnumConstant: case Decl::CXXRecord: case Decl::Using: case Decl::UsingShadow:
case Decl::UsingDirective: case Decl::NamespaceAlias:
case Decl::StaticAssert: case Decl::Label: case Decl::Import:
return;
case Decl::Var: {
const VarDecl &VD = cast<VarDecl>(D);
assert(VD.isLocalVarDecl() &&
"Should not see file-scope variables inside a function!");
return EmitVarDecl(VD);
}
case Decl::Typedef: case Decl::TypeAlias: { const TypedefNameDecl &TD = cast<TypedefNameDecl>(D);
QualType Ty = TD.getUnderlyingType();
if (Ty->isVariablyModifiedType())
EmitVariablyModifiedType(Ty);
}
}
}
void CodeGenFunction::EmitVarDecl(const VarDecl &D) {
switch (D.getStorageClass()) {
case SC_None:
case SC_Auto:
case SC_Register:
return EmitAutoVarDecl(D);
case SC_Static: {
llvm::GlobalValue::LinkageTypes Linkage =
llvm::GlobalValue::InternalLinkage;
if (getContext().getLangOptions().CPlusPlus)
if (llvm::GlobalValue::isWeakForLinker(CurFn->getLinkage()))
Linkage = CurFn->getLinkage();
return EmitStaticVarDecl(D, Linkage);
}
case SC_Extern:
case SC_PrivateExtern:
return;
case SC_OpenCLWorkGroupLocal:
return CGM.getOpenCLRuntime().EmitWorkGroupLocalVarDecl(*this, D);
}
llvm_unreachable("Unknown storage class");
}
static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D,
const char *Separator) {
CodeGenModule &CGM = CGF.CGM;
if (CGF.getContext().getLangOptions().CPlusPlus) {
StringRef Name = CGM.getMangledName(&D);
return Name.str();
}
std::string ContextName;
if (!CGF.CurFuncDecl) {
const NamedDecl *ND = cast<NamedDecl>(&D);
const DeclContext *DC = ND->getDeclContext();
if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) {
MangleBuffer Name;
CGM.getBlockMangledName(GlobalDecl(), Name, BD);
ContextName = Name.getString();
}
else
llvm_unreachable("Unknown context for block static var decl");
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CGF.CurFuncDecl)) {
StringRef Name = CGM.getMangledName(FD);
ContextName = Name.str();
} else if (isa<ObjCMethodDecl>(CGF.CurFuncDecl))
ContextName = CGF.CurFn->getName();
else
llvm_unreachable("Unknown context for static var decl");
return ContextName + Separator + D.getNameAsString();
}
llvm::GlobalVariable *
CodeGenFunction::CreateStaticVarDecl(const VarDecl &D,
const char *Separator,
llvm::GlobalValue::LinkageTypes Linkage) {
QualType Ty = D.getType();
assert(Ty->isConstantSizeType() && "VLAs can't be static");
std::string Name;
if (D.hasAttr<AsmLabelAttr>())
Name = CGM.getMangledName(&D);
else
Name = GetStaticDeclName(*this, D, Separator);
llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty);
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), LTy,
Ty.isConstant(getContext()), Linkage,
CGM.EmitNullConstant(D.getType()), Name, 0,
D.isThreadSpecified(),
CGM.getContext().getTargetAddressSpace(Ty));
GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
if (Linkage != llvm::GlobalValue::InternalLinkage)
GV->setVisibility(CurFn->getVisibility());
return GV;
}
static bool hasNontrivialDestruction(QualType T) {
CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
return RD && !RD->hasTrivialDestructor();
}
llvm::GlobalVariable *
CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
llvm::GlobalVariable *GV) {
llvm::Constant *Init = CGM.EmitConstantInit(D, this);
if (!Init) {
if (!getContext().getLangOptions().CPlusPlus)
CGM.ErrorUnsupported(D.getInit(), "constant l-value expression");
else if (Builder.GetInsertBlock()) {
GV->setConstant(false);
EmitCXXGuardedInit(D, GV, true);
}
return GV;
}
if (GV->getType()->getElementType() != Init->getType()) {
llvm::GlobalVariable *OldGV = GV;
GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(),
OldGV->isConstant(),
OldGV->getLinkage(), Init, "",
OldGV,
D.isThreadSpecified(),
CGM.getContext().getTargetAddressSpace(D.getType()));
GV->setVisibility(OldGV->getVisibility());
GV->takeName(OldGV);
llvm::Constant *NewPtrForOldDecl =
llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
OldGV->replaceAllUsesWith(NewPtrForOldDecl);
OldGV->eraseFromParent();
}
GV->setConstant(CGM.isTypeConstant(D.getType(), true));
GV->setInitializer(Init);
if (hasNontrivialDestruction(D.getType())) {
EmitCXXGuardedInit(D, GV, false);
}
return GV;
}
void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
llvm::GlobalValue::LinkageTypes Linkage) {
llvm::Value *&DMEntry = LocalDeclMap[&D];
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
llvm::GlobalVariable *GV = CreateStaticVarDecl(D, ".", Linkage);
DMEntry = GV;
if (D.getType()->isVariablyModifiedType())
EmitVariablyModifiedType(D.getType());
CGM.setStaticLocalDeclAddress(&D, GV);
if (D.getInit())
GV = AddInitializerToStaticVarDecl(D, GV);
GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
if (D.hasAttr<AnnotateAttr>())
CGM.AddGlobalAnnotations(&D, GV);
if (const SectionAttr *SA = D.getAttr<SectionAttr>())
GV->setSection(SA->getName());
if (D.hasAttr<UsedAttr>())
CGM.AddUsedGlobal(GV);
llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(D.getType());
llvm::Type *LPtrTy =
LTy->getPointerTo(CGM.getContext().getTargetAddressSpace(D.getType()));
DMEntry = llvm::ConstantExpr::getBitCast(GV, LPtrTy);
CGDebugInfo *DI = getDebugInfo();
if (DI) {
DI->setLocation(D.getLocation());
DI->EmitGlobalVariable(static_cast<llvm::GlobalVariable *>(GV), &D);
}
}
namespace {
struct DestroyObject : EHScopeStack::Cleanup {
DestroyObject(llvm::Value *addr, QualType type,
CodeGenFunction::Destroyer *destroyer,
bool useEHCleanupForArray)
: addr(addr), type(type), destroyer(destroyer),
useEHCleanupForArray(useEHCleanupForArray) {}
llvm::Value *addr;
QualType type;
CodeGenFunction::Destroyer *destroyer;
bool useEHCleanupForArray;
void Emit(CodeGenFunction &CGF, Flags flags) {
bool useEHCleanupForArray =
flags.isForNormalCleanup() && this->useEHCleanupForArray;
CGF.emitDestroy(addr, type, destroyer, useEHCleanupForArray);
}
};
struct DestroyNRVOVariable : EHScopeStack::Cleanup {
DestroyNRVOVariable(llvm::Value *addr,
const CXXDestructorDecl *Dtor,
llvm::Value *NRVOFlag)
: Dtor(Dtor), NRVOFlag(NRVOFlag), Loc(addr) {}
const CXXDestructorDecl *Dtor;
llvm::Value *NRVOFlag;
llvm::Value *Loc;
void Emit(CodeGenFunction &CGF, Flags flags) {
bool NRVO = flags.isForNormalCleanup() && NRVOFlag;
llvm::BasicBlock *SkipDtorBB = 0;
if (NRVO) {
llvm::BasicBlock *RunDtorBB = CGF.createBasicBlock("nrvo.unused");
SkipDtorBB = CGF.createBasicBlock("nrvo.skipdtor");
llvm::Value *DidNRVO = CGF.Builder.CreateLoad(NRVOFlag, "nrvo.val");
CGF.Builder.CreateCondBr(DidNRVO, SkipDtorBB, RunDtorBB);
CGF.EmitBlock(RunDtorBB);
}
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
false, Loc);
if (NRVO) CGF.EmitBlock(SkipDtorBB);
}
};
struct CallStackRestore : EHScopeStack::Cleanup {
llvm::Value *Stack;
CallStackRestore(llvm::Value *Stack) : Stack(Stack) {}
void Emit(CodeGenFunction &CGF, Flags flags) {
llvm::Value *V = CGF.Builder.CreateLoad(Stack);
llvm::Value *F = CGF.CGM.getIntrinsic(llvm::Intrinsic::stackrestore);
CGF.Builder.CreateCall(F, V);
}
};
struct ExtendGCLifetime : EHScopeStack::Cleanup {
const VarDecl &Var;
ExtendGCLifetime(const VarDecl *var) : Var(*var) {}
void Emit(CodeGenFunction &CGF, Flags flags) {
DeclRefExpr DRE(const_cast<VarDecl*>(&Var), Var.getType(), VK_LValue,
SourceLocation());
llvm::Value *value = CGF.EmitLoadOfScalar(CGF.EmitDeclRefLValue(&DRE));
CGF.EmitExtendGCLifetime(value);
}
};
struct CallCleanupFunction : EHScopeStack::Cleanup {
llvm::Constant *CleanupFn;
const CGFunctionInfo &FnInfo;
const VarDecl &Var;
CallCleanupFunction(llvm::Constant *CleanupFn, const CGFunctionInfo *Info,
const VarDecl *Var)
: CleanupFn(CleanupFn), FnInfo(*Info), Var(*Var) {}
void Emit(CodeGenFunction &CGF, Flags flags) {
DeclRefExpr DRE(const_cast<VarDecl*>(&Var), Var.getType(), VK_LValue,
SourceLocation());
llvm::Value *Addr = CGF.EmitDeclRefLValue(&DRE).getAddress();
QualType ArgTy = FnInfo.arg_begin()->type;
llvm::Value *Arg =
CGF.Builder.CreateBitCast(Addr, CGF.ConvertType(ArgTy));
CallArgList Args;
Args.add(RValue::get(Arg),
CGF.getContext().getPointerType(Var.getType()));
CGF.EmitCall(FnInfo, CleanupFn, ReturnValueSlot(), Args);
}
};
}
static void EmitAutoVarWithLifetime(CodeGenFunction &CGF, const VarDecl &var,
llvm::Value *addr,
Qualifiers::ObjCLifetime lifetime) {
switch (lifetime) {
case Qualifiers::OCL_None:
llvm_unreachable("present but none");
case Qualifiers::OCL_ExplicitNone:
break;
case Qualifiers::OCL_Strong: {
CodeGenFunction::Destroyer *destroyer =
(var.hasAttr<ObjCPreciseLifetimeAttr>()
? CodeGenFunction::destroyARCStrongPrecise
: CodeGenFunction::destroyARCStrongImprecise);
CleanupKind cleanupKind = CGF.getARCCleanupKind();
CGF.pushDestroy(cleanupKind, addr, var.getType(), destroyer,
cleanupKind & EHCleanup);
break;
}
case Qualifiers::OCL_Autoreleasing:
break;
case Qualifiers::OCL_Weak:
CGF.pushDestroy(NormalAndEHCleanup, addr, var.getType(),
CodeGenFunction::destroyARCWeak,
true);
break;
}
}
static bool isAccessedBy(const VarDecl &var, const Stmt *s) {
if (const Expr *e = dyn_cast<Expr>(s)) {
s = e = e->IgnoreParenCasts();
if (const DeclRefExpr *ref = dyn_cast<DeclRefExpr>(e))
return (ref->getDecl() == &var);
}
for (Stmt::const_child_range children = s->children(); children; ++children)
if ((*children) && isAccessedBy(var, *children))
return true;
return false;
}
static bool isAccessedBy(const ValueDecl *decl, const Expr *e) {
if (!decl) return false;
if (!isa<VarDecl>(decl)) return false;
const VarDecl *var = cast<VarDecl>(decl);
return isAccessedBy(*var, e);
}
static void drillIntoBlockVariable(CodeGenFunction &CGF,
LValue &lvalue,
const VarDecl *var) {
lvalue.setAddress(CGF.BuildBlockByrefAddress(lvalue.getAddress(), var));
}
void CodeGenFunction::EmitScalarInit(const Expr *init,
const ValueDecl *D,
LValue lvalue,
bool capturedByInit) {
Qualifiers::ObjCLifetime lifetime = lvalue.getObjCLifetime();
if (!lifetime) {
llvm::Value *value = EmitScalarExpr(init);
if (capturedByInit)
drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
EmitStoreThroughLValue(RValue::get(value), lvalue, true);
return;
}
if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(init)) {
enterFullExpression(ewc);
init = ewc->getSubExpr();
}
CodeGenFunction::RunCleanupsScope Scope(*this);
bool accessedByInit = false;
if (lifetime != Qualifiers::OCL_ExplicitNone)
accessedByInit = (capturedByInit || isAccessedBy(D, init));
if (accessedByInit) {
LValue tempLV = lvalue;
if (capturedByInit) {
tempLV.setAddress(Builder.CreateStructGEP(tempLV.getAddress(),
getByRefValueLLVMField(cast<VarDecl>(D))));
}
llvm::PointerType *ty
= cast<llvm::PointerType>(tempLV.getAddress()->getType());
ty = cast<llvm::PointerType>(ty->getElementType());
llvm::Value *zero = llvm::ConstantPointerNull::get(ty);
if (lifetime == Qualifiers::OCL_Weak)
EmitARCInitWeak(tempLV.getAddress(), zero);
else
EmitStoreOfScalar(zero, tempLV, true);
}
llvm::Value *value = 0;
switch (lifetime) {
case Qualifiers::OCL_None:
llvm_unreachable("present but none");
case Qualifiers::OCL_ExplicitNone:
value = EmitScalarExpr(init);
break;
case Qualifiers::OCL_Strong: {
value = EmitARCRetainScalarExpr(init);
break;
}
case Qualifiers::OCL_Weak: {
value = EmitScalarExpr(init);
if (capturedByInit) drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
if (accessedByInit)
EmitARCStoreWeak(lvalue.getAddress(), value, true);
else
EmitARCInitWeak(lvalue.getAddress(), value);
return;
}
case Qualifiers::OCL_Autoreleasing:
value = EmitARCRetainAutoreleaseScalarExpr(init);
break;
}
if (capturedByInit) drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
if (accessedByInit && lifetime == Qualifiers::OCL_Strong) {
llvm::Value *oldValue = EmitLoadOfScalar(lvalue);
EmitStoreOfScalar(value, lvalue, true);
EmitARCRelease(oldValue, false);
return;
}
EmitStoreOfScalar(value, lvalue, true);
}
void CodeGenFunction::EmitScalarInit(llvm::Value *init, LValue lvalue) {
Qualifiers::ObjCLifetime lifetime = lvalue.getObjCLifetime();
if (!lifetime)
return EmitStoreThroughLValue(RValue::get(init), lvalue, true);
switch (lifetime) {
case Qualifiers::OCL_None:
llvm_unreachable("present but none");
case Qualifiers::OCL_ExplicitNone:
break;
case Qualifiers::OCL_Strong:
init = EmitARCRetain(lvalue.getType(), init);
break;
case Qualifiers::OCL_Weak:
EmitARCInitWeak(lvalue.getAddress(), init);
return;
case Qualifiers::OCL_Autoreleasing:
init = EmitARCRetainAutorelease(lvalue.getType(), init);
break;
}
EmitStoreOfScalar(init, lvalue, true);
}
static bool canEmitInitWithFewStoresAfterMemset(llvm::Constant *Init,
unsigned &NumStores) {
if (isa<llvm::ConstantAggregateZero>(Init) ||
isa<llvm::ConstantPointerNull>(Init) ||
isa<llvm::UndefValue>(Init))
return true;
if (isa<llvm::ConstantInt>(Init) || isa<llvm::ConstantFP>(Init) ||
isa<llvm::ConstantVector>(Init) || isa<llvm::BlockAddress>(Init) ||
isa<llvm::ConstantExpr>(Init))
return Init->isNullValue() || NumStores--;
if (isa<llvm::ConstantArray>(Init) || isa<llvm::ConstantStruct>(Init)) {
for (unsigned i = 0, e = Init->getNumOperands(); i != e; ++i) {
llvm::Constant *Elt = cast<llvm::Constant>(Init->getOperand(i));
if (!canEmitInitWithFewStoresAfterMemset(Elt, NumStores))
return false;
}
return true;
}
if (llvm::ConstantDataSequential *CDS =
dyn_cast<llvm::ConstantDataSequential>(Init)) {
for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) {
llvm::Constant *Elt = CDS->getElementAsConstant(i);
if (!canEmitInitWithFewStoresAfterMemset(Elt, NumStores))
return false;
}
return true;
}
return false;
}
static void emitStoresForInitAfterMemset(llvm::Constant *Init, llvm::Value *Loc,
bool isVolatile, CGBuilderTy &Builder) {
if (Init->isNullValue() || isa<llvm::UndefValue>(Init))
return;
if (isa<llvm::ConstantInt>(Init) || isa<llvm::ConstantFP>(Init) ||
isa<llvm::ConstantVector>(Init) || isa<llvm::BlockAddress>(Init) ||
isa<llvm::ConstantExpr>(Init)) {
Builder.CreateStore(Init, Loc, isVolatile);
return;
}
if (llvm::ConstantDataSequential *CDS =
dyn_cast<llvm::ConstantDataSequential>(Init)) {
for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) {
llvm::Constant *Elt = CDS->getElementAsConstant(i);
emitStoresForInitAfterMemset(Elt, Builder.CreateConstGEP2_32(Loc, 0, i),
isVolatile, Builder);
}
return;
}
assert((isa<llvm::ConstantStruct>(Init) || isa<llvm::ConstantArray>(Init)) &&
"Unknown value type!");
for (unsigned i = 0, e = Init->getNumOperands(); i != e; ++i) {
llvm::Constant *Elt = cast<llvm::Constant>(Init->getOperand(i));
emitStoresForInitAfterMemset(Elt, Builder.CreateConstGEP2_32(Loc, 0, i),
isVolatile, Builder);
}
}
static bool shouldUseMemSetPlusStoresToInitialize(llvm::Constant *Init,
uint64_t GlobalSize) {
if (isa<llvm::ConstantAggregateZero>(Init)) return true;
unsigned StoreBudget = 6;
uint64_t SizeLimit = 32;
return GlobalSize > SizeLimit &&
canEmitInitWithFewStoresAfterMemset(Init, StoreBudget);
}
void CodeGenFunction::EmitAutoVarDecl(const VarDecl &D) {
AutoVarEmission emission = EmitAutoVarAlloca(D);
EmitAutoVarInit(emission);
EmitAutoVarCleanups(emission);
}
CodeGenFunction::AutoVarEmission
CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
QualType Ty = D.getType();
AutoVarEmission emission(D);
bool isByRef = D.hasAttr<BlocksAttr>();
emission.IsByRef = isByRef;
CharUnits alignment = getContext().getDeclAlign(&D);
emission.Alignment = alignment;
if (Ty->isVariablyModifiedType())
EmitVariablyModifiedType(Ty);
llvm::Value *DeclPtr;
if (Ty->isConstantSizeType()) {
if (!Target.useGlobalsForAutomaticVariables()) {
bool NRVO = getContext().getLangOptions().ElideConstructors &&
D.isNRVOVariable();
if (D.getInit() &&
(Ty->isArrayType() || Ty->isRecordType()) &&
(Ty.isPODType(getContext()) ||
getContext().getBaseElementType(Ty)->isObjCObjectPointerType()) &&
D.getInit()->isConstantInitializer(getContext(), false)) {
if (CGM.getCodeGenOpts().MergeAllConstants && !NRVO && !isByRef &&
CGM.isTypeConstant(Ty, true)) {
EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
emission.Address = 0; assert(emission.wasEmittedAsGlobal());
return emission;
}
emission.IsConstantAggregate = true;
}
llvm::Type *LTy = ConvertTypeForMem(Ty);
if (NRVO) {
DeclPtr = ReturnValue;
if (const RecordType *RecordTy = Ty->getAs<RecordType>()) {
if (!cast<CXXRecordDecl>(RecordTy->getDecl())->hasTrivialDestructor()) {
llvm::Value *Zero = Builder.getFalse();
llvm::Value *NRVOFlag = CreateTempAlloca(Zero->getType(), "nrvo");
EnsureInsertPoint();
Builder.CreateStore(Zero, NRVOFlag);
NRVOFlags[&D] = NRVOFlag;
emission.NRVOFlag = NRVOFlag;
}
}
} else {
if (isByRef)
LTy = BuildByRefType(&D);
llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
Alloc->setName(D.getName());
CharUnits allocaAlignment = alignment;
if (isByRef)
allocaAlignment = std::max(allocaAlignment,
getContext().toCharUnitsFromBits(Target.getPointerAlign(0)));
Alloc->setAlignment(allocaAlignment.getQuantity());
DeclPtr = Alloc;
}
} else {
const char *Class =
D.getStorageClass() == SC_Register ? ".reg." : ".auto.";
DeclPtr = CreateStaticVarDecl(D, Class,
llvm::GlobalValue::InternalLinkage);
}
} else {
EnsureInsertPoint();
if (!DidCallStackSave) {
llvm::Value *Stack = CreateTempAlloca(Int8PtrTy, "saved_stack");
llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::stacksave);
llvm::Value *V = Builder.CreateCall(F);
Builder.CreateStore(V, Stack);
DidCallStackSave = true;
EHStack.pushCleanup<CallStackRestore>(NormalCleanup, Stack);
}
llvm::Value *elementCount;
QualType elementType;
llvm::tie(elementCount, elementType) = getVLASize(Ty);
llvm::Type *llvmTy = ConvertTypeForMem(elementType);
llvm::AllocaInst *vla = Builder.CreateAlloca(llvmTy, elementCount, "vla");
vla->setAlignment(alignment.getQuantity());
DeclPtr = vla;
}
llvm::Value *&DMEntry = LocalDeclMap[&D];
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
DMEntry = DeclPtr;
emission.Address = DeclPtr;
if (HaveInsertPoint())
if (CGDebugInfo *DI = getDebugInfo()) {
DI->setLocation(D.getLocation());
if (Target.useGlobalsForAutomaticVariables()) {
DI->EmitGlobalVariable(static_cast<llvm::GlobalVariable *>(DeclPtr), &D);
} else
DI->EmitDeclareOfAutoVariable(&D, DeclPtr, Builder);
}
if (D.hasAttr<AnnotateAttr>())
EmitVarAnnotations(&D, emission.Address);
return emission;
}
static bool isCapturedBy(const VarDecl &var, const Expr *e) {
e = e->IgnoreParenCasts();
if (const BlockExpr *be = dyn_cast<BlockExpr>(e)) {
const BlockDecl *block = be->getBlockDecl();
for (BlockDecl::capture_const_iterator i = block->capture_begin(),
e = block->capture_end(); i != e; ++i) {
if (i->getVariable() == &var)
return true;
}
return false;
}
if (const StmtExpr *SE = dyn_cast<StmtExpr>(e)) {
const CompoundStmt *CS = SE->getSubStmt();
for (CompoundStmt::const_body_iterator BI = CS->body_begin(),
BE = CS->body_end(); BI != BE; ++BI)
if (Expr *E = dyn_cast<Expr>((*BI))) {
if (isCapturedBy(var, E))
return true;
}
else if (DeclStmt *DS = dyn_cast<DeclStmt>((*BI))) {
for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end();
I != E; ++I) {
if (VarDecl *VD = dyn_cast<VarDecl>((*I))) {
Expr *Init = VD->getInit();
if (Init && isCapturedBy(var, Init))
return true;
}
}
}
else
return true;
return false;
}
for (Stmt::const_child_range children = e->children(); children; ++children)
if (isCapturedBy(var, cast<Expr>(*children)))
return true;
return false;
}
static bool isTrivialInitializer(const Expr *Init) {
if (!Init)
return true;
if (const CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init))
if (CXXConstructorDecl *Constructor = Construct->getConstructor())
if (Constructor->isTrivial() &&
Constructor->isDefaultConstructor() &&
!Construct->requiresZeroInitialization())
return true;
return false;
}
void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
assert(emission.Variable && "emission was not valid!");
if (emission.wasEmittedAsGlobal()) return;
const VarDecl &D = *emission.Variable;
QualType type = D.getType();
const Expr *Init = D.getInit();
if (!HaveInsertPoint()) {
if (!Init || !ContainsLabel(Init)) return;
EnsureInsertPoint();
}
if (emission.IsByRef)
emitByrefStructureInit(emission);
if (isTrivialInitializer(Init))
return;
CharUnits alignment = emission.Alignment;
bool capturedByInit = emission.IsByRef && isCapturedBy(D, Init);
llvm::Value *Loc =
capturedByInit ? emission.Address : emission.getObjectAddress(*this);
llvm::Constant *constant = 0;
if (emission.IsConstantAggregate) {
assert(!capturedByInit && "constant init contains a capturing block?");
constant = CGM.EmitConstantInit(D, this);
}
if (!constant) {
LValue lv = MakeAddrLValue(Loc, type, alignment);
lv.setNonGC(true);
return EmitExprAsInit(Init, &D, lv, capturedByInit);
}
bool isVolatile = type.isVolatileQualified();
llvm::Value *SizeVal =
llvm::ConstantInt::get(IntPtrTy,
getContext().getTypeSizeInChars(type).getQuantity());
llvm::Type *BP = Int8PtrTy;
if (Loc->getType() != BP)
Loc = Builder.CreateBitCast(Loc, BP);
if (shouldUseMemSetPlusStoresToInitialize(constant,
CGM.getTargetData().getTypeAllocSize(constant->getType()))) {
Builder.CreateMemSet(Loc, llvm::ConstantInt::get(Int8Ty, 0), SizeVal,
alignment.getQuantity(), isVolatile);
if (!constant->isNullValue()) {
Loc = Builder.CreateBitCast(Loc, constant->getType()->getPointerTo());
emitStoresForInitAfterMemset(constant, Loc, isVolatile, Builder);
}
} else {
std::string Name = GetStaticDeclName(*this, D, ".");
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), constant->getType(), true,
llvm::GlobalValue::PrivateLinkage,
constant, Name, 0, false, 0);
GV->setAlignment(alignment.getQuantity());
GV->setUnnamedAddr(true);
llvm::Value *SrcPtr = GV;
if (SrcPtr->getType() != BP)
SrcPtr = Builder.CreateBitCast(SrcPtr, BP);
Builder.CreateMemCpy(Loc, SrcPtr, SizeVal, alignment.getQuantity(),
isVolatile);
}
}
void CodeGenFunction::EmitExprAsInit(const Expr *init,
const ValueDecl *D,
LValue lvalue,
bool capturedByInit) {
QualType type = D->getType();
if (type->isReferenceType()) {
RValue rvalue = EmitReferenceBindingToExpr(init, D);
if (capturedByInit)
drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
EmitStoreThroughLValue(rvalue, lvalue, true);
} else if (!hasAggregateLLVMType(type)) {
EmitScalarInit(init, D, lvalue, capturedByInit);
} else if (type->isAnyComplexType()) {
ComplexPairTy complex = EmitComplexExpr(init);
if (capturedByInit)
drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
StoreComplexToAddr(complex, lvalue.getAddress(), lvalue.isVolatile());
} else {
EmitAggExpr(init, AggValueSlot::forLValue(lvalue,
AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased));
MaybeEmitStdInitializerListCleanup(lvalue.getAddress(), init);
}
}
void CodeGenFunction::emitAutoVarTypeCleanup(
const CodeGenFunction::AutoVarEmission &emission,
QualType::DestructionKind dtorKind) {
assert(dtorKind != QualType::DK_none);
llvm::Value *addr = emission.getObjectAddress(*this);
const VarDecl *var = emission.Variable;
QualType type = var->getType();
CleanupKind cleanupKind = NormalAndEHCleanup;
CodeGenFunction::Destroyer *destroyer = 0;
switch (dtorKind) {
case QualType::DK_none:
llvm_unreachable("no cleanup for trivially-destructible variable");
case QualType::DK_cxx_destructor:
if (emission.NRVOFlag) {
assert(!type->isArrayType());
CXXDestructorDecl *dtor = type->getAsCXXRecordDecl()->getDestructor();
EHStack.pushCleanup<DestroyNRVOVariable>(cleanupKind, addr, dtor,
emission.NRVOFlag);
return;
}
break;
case QualType::DK_objc_strong_lifetime:
if (var->isARCPseudoStrong()) return;
cleanupKind = getARCCleanupKind();
if (!var->hasAttr<ObjCPreciseLifetimeAttr>())
destroyer = CodeGenFunction::destroyARCStrongImprecise;
break;
case QualType::DK_objc_weak_lifetime:
break;
}
if (!destroyer) destroyer = getDestroyer(dtorKind);
bool useEHCleanup = (cleanupKind & EHCleanup);
EHStack.pushCleanup<DestroyObject>(cleanupKind, addr, type, destroyer,
useEHCleanup);
}
void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
assert(emission.Variable && "emission was not valid!");
if (emission.wasEmittedAsGlobal()) return;
const VarDecl &D = *emission.Variable;
if (QualType::DestructionKind dtorKind = D.getType().isDestructedType())
emitAutoVarTypeCleanup(emission, dtorKind);
if (getLangOptions().getGC() != LangOptions::NonGC &&
D.hasAttr<ObjCPreciseLifetimeAttr>()) {
EHStack.pushCleanup<ExtendGCLifetime>(NormalCleanup, &D);
}
if (const CleanupAttr *CA = D.getAttr<CleanupAttr>()) {
const FunctionDecl *FD = CA->getFunctionDecl();
llvm::Constant *F = CGM.GetAddrOfFunction(FD);
assert(F && "Could not find function!");
const CGFunctionInfo &Info = CGM.getTypes().arrangeFunctionDeclaration(FD);
EHStack.pushCleanup<CallCleanupFunction>(NormalAndEHCleanup, F, &Info, &D);
}
if (emission.IsByRef)
enterByrefCleanup(emission);
}
CodeGenFunction::Destroyer *
CodeGenFunction::getDestroyer(QualType::DestructionKind kind) {
switch (kind) {
case QualType::DK_none: llvm_unreachable("no destroyer for trivial dtor");
case QualType::DK_cxx_destructor:
return destroyCXXObject;
case QualType::DK_objc_strong_lifetime:
return destroyARCStrongPrecise;
case QualType::DK_objc_weak_lifetime:
return destroyARCWeak;
}
llvm_unreachable("Unknown DestructionKind");
}
void CodeGenFunction::pushDestroy(QualType::DestructionKind dtorKind,
llvm::Value *addr, QualType type) {
assert(dtorKind && "cannot push destructor for trivial type");
CleanupKind cleanupKind = getCleanupKind(dtorKind);
pushDestroy(cleanupKind, addr, type, getDestroyer(dtorKind),
cleanupKind & EHCleanup);
}
void CodeGenFunction::pushDestroy(CleanupKind cleanupKind, llvm::Value *addr,
QualType type, Destroyer *destroyer,
bool useEHCleanupForArray) {
pushFullExprCleanup<DestroyObject>(cleanupKind, addr, type,
destroyer, useEHCleanupForArray);
}
void CodeGenFunction::emitDestroy(llvm::Value *addr, QualType type,
Destroyer *destroyer,
bool useEHCleanupForArray) {
const ArrayType *arrayType = getContext().getAsArrayType(type);
if (!arrayType)
return destroyer(*this, addr, type);
llvm::Value *begin = addr;
llvm::Value *length = emitArrayLength(arrayType, type, begin);
bool checkZeroLength = true;
if (llvm::ConstantInt *constLength = dyn_cast<llvm::ConstantInt>(length)) {
if (constLength->isZero()) return;
checkZeroLength = false;
}
llvm::Value *end = Builder.CreateInBoundsGEP(begin, length);
emitArrayDestroy(begin, end, type, destroyer,
checkZeroLength, useEHCleanupForArray);
}
void CodeGenFunction::emitArrayDestroy(llvm::Value *begin,
llvm::Value *end,
QualType type,
Destroyer *destroyer,
bool checkZeroLength,
bool useEHCleanup) {
assert(!type->isArrayType());
llvm::BasicBlock *bodyBB = createBasicBlock("arraydestroy.body");
llvm::BasicBlock *doneBB = createBasicBlock("arraydestroy.done");
if (checkZeroLength) {
llvm::Value *isEmpty = Builder.CreateICmpEQ(begin, end,
"arraydestroy.isempty");
Builder.CreateCondBr(isEmpty, doneBB, bodyBB);
}
llvm::BasicBlock *entryBB = Builder.GetInsertBlock();
EmitBlock(bodyBB);
llvm::PHINode *elementPast =
Builder.CreatePHI(begin->getType(), 2, "arraydestroy.elementPast");
elementPast->addIncoming(end, entryBB);
llvm::Value *negativeOne = llvm::ConstantInt::get(SizeTy, -1, true);
llvm::Value *element = Builder.CreateInBoundsGEP(elementPast, negativeOne,
"arraydestroy.element");
if (useEHCleanup)
pushRegularPartialArrayCleanup(begin, element, type, destroyer);
destroyer(*this, element, type);
if (useEHCleanup)
PopCleanupBlock();
llvm::Value *done = Builder.CreateICmpEQ(element, begin, "arraydestroy.done");
Builder.CreateCondBr(done, doneBB, bodyBB);
elementPast->addIncoming(element, Builder.GetInsertBlock());
EmitBlock(doneBB);
}
static void emitPartialArrayDestroy(CodeGenFunction &CGF,
llvm::Value *begin, llvm::Value *end,
QualType type,
CodeGenFunction::Destroyer *destroyer) {
unsigned arrayDepth = 0;
while (const ArrayType *arrayType = CGF.getContext().getAsArrayType(type)) {
if (!isa<VariableArrayType>(arrayType))
arrayDepth++;
type = arrayType->getElementType();
}
if (arrayDepth) {
llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, arrayDepth+1);
SmallVector<llvm::Value*,4> gepIndices(arrayDepth, zero);
begin = CGF.Builder.CreateInBoundsGEP(begin, gepIndices, "pad.arraybegin");
end = CGF.Builder.CreateInBoundsGEP(end, gepIndices, "pad.arrayend");
}
CGF.emitArrayDestroy(begin, end, type, destroyer,
true, false);
}
namespace {
class RegularPartialArrayDestroy : public EHScopeStack::Cleanup {
llvm::Value *ArrayBegin;
llvm::Value *ArrayEnd;
QualType ElementType;
CodeGenFunction::Destroyer *Destroyer;
public:
RegularPartialArrayDestroy(llvm::Value *arrayBegin, llvm::Value *arrayEnd,
QualType elementType,
CodeGenFunction::Destroyer *destroyer)
: ArrayBegin(arrayBegin), ArrayEnd(arrayEnd),
ElementType(elementType), Destroyer(destroyer) {}
void Emit(CodeGenFunction &CGF, Flags flags) {
emitPartialArrayDestroy(CGF, ArrayBegin, ArrayEnd,
ElementType, Destroyer);
}
};
class IrregularPartialArrayDestroy : public EHScopeStack::Cleanup {
llvm::Value *ArrayBegin;
llvm::Value *ArrayEndPointer;
QualType ElementType;
CodeGenFunction::Destroyer *Destroyer;
public:
IrregularPartialArrayDestroy(llvm::Value *arrayBegin,
llvm::Value *arrayEndPointer,
QualType elementType,
CodeGenFunction::Destroyer *destroyer)
: ArrayBegin(arrayBegin), ArrayEndPointer(arrayEndPointer),
ElementType(elementType), Destroyer(destroyer) {}
void Emit(CodeGenFunction &CGF, Flags flags) {
llvm::Value *arrayEnd = CGF.Builder.CreateLoad(ArrayEndPointer);
emitPartialArrayDestroy(CGF, ArrayBegin, arrayEnd,
ElementType, Destroyer);
}
};
}
void CodeGenFunction::pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin,
llvm::Value *arrayEndPointer,
QualType elementType,
Destroyer *destroyer) {
pushFullExprCleanup<IrregularPartialArrayDestroy>(EHCleanup,
arrayBegin, arrayEndPointer,
elementType, destroyer);
}
void CodeGenFunction::pushRegularPartialArrayCleanup(llvm::Value *arrayBegin,
llvm::Value *arrayEnd,
QualType elementType,
Destroyer *destroyer) {
pushFullExprCleanup<RegularPartialArrayDestroy>(EHCleanup,
arrayBegin, arrayEnd,
elementType, destroyer);
}
namespace {
struct ConsumeARCParameter : EHScopeStack::Cleanup {
ConsumeARCParameter(llvm::Value *param) : Param(param) {}
llvm::Value *Param;
void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.EmitARCRelease(Param, false);
}
};
}
void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
unsigned ArgNo) {
assert((isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D)) &&
"Invalid argument to EmitParmDecl");
Arg->setName(D.getName());
if (isa<ImplicitParamDecl>(D)) {
if (BlockInfo) {
LocalDeclMap[&D] = Arg;
if (CGDebugInfo *DI = getDebugInfo()) {
DI->setLocation(D.getLocation());
DI->EmitDeclareOfBlockLiteralArgVariable(*BlockInfo, Arg, Builder);
}
return;
}
}
QualType Ty = D.getType();
llvm::Value *DeclPtr;
if (!Ty->isConstantSizeType() ||
CodeGenFunction::hasAggregateLLVMType(Ty)) {
DeclPtr = Arg;
} else {
llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertTypeForMem(Ty),
D.getName() + ".addr");
Alloc->setAlignment(getContext().getDeclAlign(&D).getQuantity());
DeclPtr = Alloc;
bool doStore = true;
Qualifiers qs = Ty.getQualifiers();
if (Qualifiers::ObjCLifetime lt = qs.getObjCLifetime()) {
bool isConsumed = D.hasAttr<NSConsumedAttr>();
if (D.isARCPseudoStrong()) {
const ObjCMethodDecl *method = cast<ObjCMethodDecl>(CurCodeDecl);
assert(&D == method->getSelfDecl());
assert(lt == Qualifiers::OCL_Strong);
assert(qs.hasConst());
assert(method->getMethodFamily() != OMF_init);
(void) method;
lt = Qualifiers::OCL_ExplicitNone;
}
if (lt == Qualifiers::OCL_Strong) {
if (!isConsumed)
Arg = EmitARCRetainNonBlock(Arg);
} else {
if (isConsumed)
EHStack.pushCleanup<ConsumeARCParameter>(getARCCleanupKind(), Arg);
if (lt == Qualifiers::OCL_Weak) {
EmitARCInitWeak(DeclPtr, Arg);
doStore = false; }
}
EmitAutoVarWithLifetime(*this, D, DeclPtr, lt);
}
if (doStore) {
LValue lv = MakeAddrLValue(DeclPtr, Ty,
getContext().getDeclAlign(&D));
EmitStoreOfScalar(Arg, lv, true);
}
}
llvm::Value *&DMEntry = LocalDeclMap[&D];
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
DMEntry = DeclPtr;
if (CGDebugInfo *DI = getDebugInfo())
DI->EmitDeclareOfArgVariable(&D, DeclPtr, ArgNo, Builder);
if (D.hasAttr<AnnotateAttr>())
EmitVarAnnotations(&D, DeclPtr);
}