blob: 38aab2d3acb4f6fdd796c0e968d9d239b144cf24 [file] [log] [blame]
Anders Carlssonacfde802009-02-12 00:39:25 +00001//===--- CGBlocks.cpp - Emit LLVM Code for declarations -------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This contains code to emit blocks.
11//
12//===----------------------------------------------------------------------===//
13
14#include "CodeGenFunction.h"
15#include "CodeGenModule.h"
16#include "llvm/Module.h"
17
18#include <algorithm>
19
20using namespace clang;
21using namespace CodeGen;
22
23static const llvm::Type *getBlockDescriptorType(CodeGenFunction &CGF) {
24 static const llvm::Type *Ty = 0;
25
26 if (!Ty) {
27 const llvm::Type *UnsignedLongTy =
28 CGF.ConvertType(CGF.getContext().UnsignedLongTy);
29
30 // struct __block_descriptor {
31 // unsigned long reserved;
32 // unsigned long block_size;
33 // };
34 Ty = llvm::StructType::get(UnsignedLongTy,
35 UnsignedLongTy,
36 NULL);
37
38 CGF.CGM.getModule().addTypeName("struct.__block_descriptor", Ty);
39 }
40
41 return Ty;
42}
43
44static const llvm::Type *getGenericBlockLiteralType(CodeGenFunction &CGF) {
45 static const llvm::Type *Ty = 0;
46
47 if (!Ty) {
48 const llvm::Type *Int8PtrTy =
49 llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
50
51 const llvm::Type *BlockDescPtrTy =
52 llvm::PointerType::getUnqual(getBlockDescriptorType(CGF));
53
54 // struct __block_literal_generic {
55 // void *isa;
56 // int flags;
57 // int reserved;
58 // void (*invoke)(void *);
59 // struct __block_descriptor *descriptor;
60 // };
61 Ty = llvm::StructType::get(Int8PtrTy,
62 llvm::Type::Int32Ty,
63 llvm::Type::Int32Ty,
64 Int8PtrTy,
65 BlockDescPtrTy,
66 NULL);
67
68 CGF.CGM.getModule().addTypeName("struct.__block_literal_generic", Ty);
69 }
70
71 return Ty;
72}
73
74/// getBlockFunctionType - Given a BlockPointerType, will return the
75/// function type for the block, including the first block literal argument.
76static QualType getBlockFunctionType(ASTContext &Ctx,
77 const BlockPointerType *BPT)
78{
79 const FunctionTypeProto *FTy = cast<FunctionTypeProto>(BPT->getPointeeType());
80
81 llvm::SmallVector<QualType, 8> Types;
82 Types.push_back(Ctx.getPointerType(Ctx.VoidTy));
83
84 for (FunctionTypeProto::arg_type_iterator i = FTy->arg_type_begin(),
85 e = FTy->arg_type_end(); i != e; ++i)
86 Types.push_back(*i);
87
88 return Ctx.getFunctionType(FTy->getResultType(),
89 &Types[0], Types.size(),
90 FTy->isVariadic(), 0);
91}
92
93RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E)
94{
95 const BlockPointerType *BPT =
96 E->getCallee()->getType()->getAsBlockPointerType();
97
98 llvm::Value *Callee = EmitScalarExpr(E->getCallee());
99
100 // Get a pointer to the generic block literal.
101 const llvm::Type *BlockLiteralTy =
102 llvm::PointerType::getUnqual(getGenericBlockLiteralType(*this));
103
104 // Bitcast the callee to a block literal.
105 llvm::Value *BlockLiteral =
106 Builder.CreateBitCast(Callee, BlockLiteralTy, "block.literal");
107
108 // Get the function pointer from the literal.
109 llvm::Value *FuncPtr = Builder.CreateStructGEP(BlockLiteral, 3, "tmp");
110 llvm::Value *Func = Builder.CreateLoad(FuncPtr, FuncPtr, "tmp");
111
112 // Cast the function pointer to the right type.
113 const llvm::Type *BlockFTy =
114 ConvertType(getBlockFunctionType(getContext(), BPT));
115 const llvm::Type *BlockFTyPtr = llvm::PointerType::getUnqual(BlockFTy);
116 Func = Builder.CreateBitCast(Func, BlockFTyPtr);
117
118 BlockLiteral =
119 Builder.CreateBitCast(BlockLiteral,
120 llvm::PointerType::getUnqual(llvm::Type::Int8Ty),
121 "tmp");
122
123 // Add the block literal.
124 QualType VoidPtrTy = getContext().getPointerType(getContext().VoidTy);
125 CallArgList Args;
126 Args.push_back(std::make_pair(RValue::get(BlockLiteral), VoidPtrTy));
127
128 // And the rest of the arguments.
129 for (CallExpr::const_arg_iterator i = E->arg_begin(), e = E->arg_end();
130 i != e; ++i)
131 Args.push_back(std::make_pair(EmitAnyExprToTemp(*i),
132 i->getType()));
133
134 // And call the block.
135 return EmitCall(CGM.getTypes().getFunctionInfo(E->getType(), Args),
136 Func, Args);
137}