//===--- CGBlocks.cpp - Emit LLVM Code for declarations -------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This contains code to emit blocks.
//
//===----------------------------------------------------------------------===//
#include "CGDebugInfo.h"
#include "CodeGenFunction.h"
#include "CGObjCRuntime.h"
#include "CodeGenModule.h"
#include "clang/AST/DeclObjC.h"
#include "llvm/Module.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Target/TargetData.h"
#include <algorithm>
using namespace clang;
using namespace CodeGen;
llvm::Constant *CodeGenFunction::
BuildDescriptorBlockDecl(const BlockExpr *BE, bool BlockHasCopyDispose, CharUnits Size,
const llvm::StructType* Ty,
std::vector<HelperInfo> *NoteForHelper) {
const llvm::Type *UnsignedLongTy
= CGM.getTypes().ConvertType(getContext().UnsignedLongTy);
llvm::Constant *C;
std::vector<llvm::Constant*> Elts;
// reserved
C = llvm::ConstantInt::get(UnsignedLongTy, 0);
Elts.push_back(C);
// Size
// FIXME: What is the right way to say this doesn't fit? We should give
// a user diagnostic in that case. Better fix would be to change the
// API to size_t.
C = llvm::ConstantInt::get(UnsignedLongTy, Size.getQuantity());
Elts.push_back(C);
// optional copy/dispose helpers
if (BlockHasCopyDispose) {
// copy_func_helper_decl
Elts.push_back(BuildCopyHelper(Ty, NoteForHelper));
// destroy_func_decl
Elts.push_back(BuildDestroyHelper(Ty, NoteForHelper));
}
// Signature. non-optional ObjC-style method descriptor @encode sequence
std::string BlockTypeEncoding;
CGM.getContext().getObjCEncodingForBlock(BE, BlockTypeEncoding);
Elts.push_back(llvm::ConstantExpr::getBitCast(
CGM.GetAddrOfConstantCString(BlockTypeEncoding), PtrToInt8Ty));
// Layout.
C = llvm::ConstantInt::get(UnsignedLongTy, 0);
Elts.push_back(C);
C = llvm::ConstantStruct::get(VMContext, Elts, false);
C = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true,
llvm::GlobalValue::InternalLinkage,
C, "__block_descriptor_tmp");
return C;
}
llvm::Constant *BlockModule::getNSConcreteGlobalBlock() {
if (NSConcreteGlobalBlock == 0)
NSConcreteGlobalBlock = CGM.CreateRuntimeVariable(PtrToInt8Ty,
"_NSConcreteGlobalBlock");
return NSConcreteGlobalBlock;
}
llvm::Constant *BlockModule::getNSConcreteStackBlock() {
if (NSConcreteStackBlock == 0)
NSConcreteStackBlock = CGM.CreateRuntimeVariable(PtrToInt8Ty,
"_NSConcreteStackBlock");
return NSConcreteStackBlock;
}
static void CollectBlockDeclRefInfo(
const Stmt *S, CodeGenFunction::BlockInfo &Info,
llvm::SmallSet<const DeclContext *, 16> &InnerContexts) {
for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end();
I != E; ++I)
if (*I)
CollectBlockDeclRefInfo(*I, Info, InnerContexts);