As an optimization, we maintain a cache of generated
___Block_byref_id_object_dispose and ___Block_byref_id_object_copy
functions so that we can simply reuse instead of creating a new one.
Additionally, add an assert to ensure no one yet tries to align a
__block variable beyond the alignment of a pointer as the codegen is
incomplete.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72974 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index ead689c..d5f803b 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -724,6 +724,8 @@
const CGFunctionInfo &FI =
CGM.getTypes().getFunctionInfo(R, Args);
+ // FIXME: We'd like to put these into a mergable by content, with
+ // internal linkage.
std::string Name = std::string("__copy_helper_block_");
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
@@ -803,6 +805,8 @@
const CGFunctionInfo &FI =
CGM.getTypes().getFunctionInfo(R, Args);
+ // FIXME: We'd like to put these into a mergable by content, with
+ // internal linkage.
std::string Name = std::string("__destroy_helper_block_");
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
@@ -889,6 +893,8 @@
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
+ // FIXME: We'd like to put these into a mergable by content, with
+ // internal linkage.
llvm::Function *Fn =
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
Name,
@@ -950,6 +956,8 @@
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
+ // FIXME: We'd like to put these into a mergable by content, with
+ // internal linkage.
llvm::Function *Fn =
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
Name,
@@ -980,13 +988,36 @@
}
llvm::Constant *BlockFunction::BuildbyrefCopyHelper(const llvm::Type *T,
- int flag) {
- return CodeGenFunction(CGM).GeneratebyrefCopyHelperFunction(T, flag);
+ int flag, unsigned Align) {
+ // All alignments below that of pointer alignment collpase down to just
+ // pointer alignment, as we always have at least that much alignment to begin
+ // with.
+ Align /= unsigned(CGF.Target.getPointerAlign(0)/8);
+ // As an optimization, we only generate a single function of each kind we
+ // might need. We need a different one for each alignment and for each
+ // setting of flags. We mix Align and flag to get the kind.
+ uint64_t kind = (uint64_t)Align*BLOCK_BYREF_CURRENT_MAX + flag;
+ llvm::Constant *& Entry = CGM.AssignCache[kind];
+ if (Entry)
+ return Entry;
+ return Entry=CodeGenFunction(CGM).GeneratebyrefCopyHelperFunction(T, flag);
}
llvm::Constant *BlockFunction::BuildbyrefDestroyHelper(const llvm::Type *T,
- int flag) {
- return CodeGenFunction(CGM).GeneratebyrefDestroyHelperFunction(T, flag);
+ int flag,
+ unsigned Align) {
+ // All alignments below that of pointer alignment collpase down to just
+ // pointer alignment, as we always have at least that much alignment to begin
+ // with.
+ Align /= unsigned(CGF.Target.getPointerAlign(0)/8);
+ // As an optimization, we only generate a single function of each kind we
+ // might need. We need a different one for each alignment and for each
+ // setting of flags. We mix Align and flag to get the kind.
+ uint64_t kind = (uint64_t)Align*BLOCK_BYREF_CURRENT_MAX + flag;
+ llvm::Constant *& Entry = CGM.DestroyCache[kind];
+ if (Entry)
+ return Entry;
+ return Entry=CodeGenFunction(CGM).GeneratebyrefDestroyHelperFunction(T, flag);
}
llvm::Value *BlockFunction::getBlockObjectDispose() {
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index 56d3a2d..5d46ac7 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -98,6 +98,9 @@
llvm::Value *BlockObjectDispose;
const llvm::Type *PtrToInt8Ty;
+ std::map<uint64_t, llvm::Constant *> AssignCache;
+ std::map<uint64_t, llvm::Constant *> DestroyCache;
+
BlockModule(ASTContext &C, llvm::Module &M, const llvm::TargetData &TD,
CodeGenTypes &T, CodeGenModule &CodeGen)
: Context(C), TheModule(M), TheTargetData(TD), Types(T),
@@ -131,8 +134,9 @@
variable */
BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy
helpers */
- BLOCK_BYREF_CALLER = 128 /* called from __block (byref) copy/dispose
+ BLOCK_BYREF_CALLER = 128, /* called from __block (byref) copy/dispose
support routines */
+ BLOCK_BYREF_CURRENT_MAX = 256
};
/// BlockInfo - Information to generate a block literal.
@@ -199,8 +203,10 @@
llvm::Constant *GeneratebyrefCopyHelperFunction(const llvm::Type *, int flag);
llvm::Constant *GeneratebyrefDestroyHelperFunction(const llvm::Type *T, int);
- llvm::Constant *BuildbyrefCopyHelper(const llvm::Type *T, int flag);
- llvm::Constant *BuildbyrefDestroyHelper(const llvm::Type *T, int flag);
+ llvm::Constant *BuildbyrefCopyHelper(const llvm::Type *T, int flag,
+ unsigned Align);
+ llvm::Constant *BuildbyrefDestroyHelper(const llvm::Type *T, int flag,
+ unsigned Align);
llvm::Value *getBlockObjectAssign();
llvm::Value *getBlockObjectDispose();
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index bcad77b..29eaaad 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -232,7 +232,9 @@
Types[4] = PtrToInt8Ty;
Types[5] = PtrToInt8Ty;
}
- // FIXME: Align this on at least an Align boundary.
+ // FIXME: Align this on at least an Align boundary, assert if we can't.
+ assert((Align <= unsigned(Target.getPointerAlign(0))/8)
+ && "Can't align more thqn pointer yet");
Types[needsCopyDispose*2 + 4] = LTy;
return llvm::StructType::get(Types, false);
}
@@ -244,22 +246,22 @@
QualType Ty = D.getType();
bool isByRef = D.hasAttr<BlocksAttr>();
bool needsDispose = false;
+ unsigned Align = 0;
llvm::Value *DeclPtr;
if (Ty->isConstantSizeType()) {
if (!Target.useGlobalsForAutomaticVariables()) {
// 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(Ty, getContext().getDeclAlignInBytes(&D));
+ LTy = BuildByRefType(Ty, Align);
llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
Alloc->setName(D.getNameAsString().c_str());
if (isByRef)
- Alloc->setAlignment(std::max(getContext().getDeclAlignInBytes(&D),
- unsigned(Target.getPointerAlign(0) / 8)));
- else
- Alloc->setAlignment(getContext().getDeclAlignInBytes(&D));
+ Align = std::max(Align, unsigned(Target.getPointerAlign(0) / 8));
+ Alloc->setAlignment(Align);
DeclPtr = Alloc;
} else {
// Targets that don't support recursion emit locals as globals.
@@ -401,11 +403,12 @@
if (flags & BLOCK_HAS_COPY_DISPOSE) {
BlockHasCopyDispose = true;
llvm::Value *copy_helper = Builder.CreateStructGEP(DeclPtr, 4);
- Builder.CreateStore(BuildbyrefCopyHelper(DeclPtr->getType(), flag),
+ Builder.CreateStore(BuildbyrefCopyHelper(DeclPtr->getType(), flag, Align),
copy_helper);
llvm::Value *destroy_helper = Builder.CreateStructGEP(DeclPtr, 5);
- Builder.CreateStore(BuildbyrefDestroyHelper(DeclPtr->getType(), flag),
+ Builder.CreateStore(BuildbyrefDestroyHelper(DeclPtr->getType(), flag,
+ Align),
destroy_helper);
}
}