aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CGBlocks.cpp
blob: 38aab2d3acb4f6fdd796c0e968d9d239b144cf24 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//===--- 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 "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "llvm/Module.h"

#include <algorithm>

using namespace clang;
using namespace CodeGen;

static const llvm::Type *getBlockDescriptorType(CodeGenFunction &CGF) {
  static const llvm::Type *Ty = 0;
    
  if (!Ty) {
    const llvm::Type *UnsignedLongTy = 
      CGF.ConvertType(CGF.getContext().UnsignedLongTy);
        
    // struct __block_descriptor {
    //   unsigned long reserved;
    //   unsigned long block_size;
    // };
    Ty = llvm::StructType::get(UnsignedLongTy, 
                               UnsignedLongTy, 
                               NULL);
        
    CGF.CGM.getModule().addTypeName("struct.__block_descriptor", Ty);
  }
    
  return Ty;
}

static const llvm::Type *getGenericBlockLiteralType(CodeGenFunction &CGF) {
  static const llvm::Type *Ty = 0;
    
  if (!Ty) {
    const llvm::Type *Int8PtrTy = 
      llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
        
    const llvm::Type *BlockDescPtrTy = 
      llvm::PointerType::getUnqual(getBlockDescriptorType(CGF));
        
    // struct __block_literal_generic {
    //   void *isa;
    //   int flags;
    //   int reserved;
    //   void (*invoke)(void *);
    //   struct __block_descriptor *descriptor;
    // };
    Ty = llvm::StructType::get(Int8PtrTy,
                               llvm::Type::Int32Ty,
                               llvm::Type::Int32Ty,
                               Int8PtrTy,
                               BlockDescPtrTy,
                               NULL);
        
    CGF.CGM.getModule().addTypeName("struct.__block_literal_generic", Ty);
  }
  
  return Ty;
}

/// getBlockFunctionType - Given a BlockPointerType, will return the 
/// function type for the block, including the first block literal argument.
static QualType getBlockFunctionType(ASTContext &Ctx,
                                     const BlockPointerType *BPT)
{
  const FunctionTypeProto *FTy = cast<FunctionTypeProto>(BPT->getPointeeType());
  
  llvm::SmallVector<QualType, 8> Types;
  Types.push_back(Ctx.getPointerType(Ctx.VoidTy));
  
  for (FunctionTypeProto::arg_type_iterator i = FTy->arg_type_begin(),
       e = FTy->arg_type_end(); i != e; ++i)
    Types.push_back(*i);
  
  return Ctx.getFunctionType(FTy->getResultType(),
                             &Types[0], Types.size(), 
                             FTy->isVariadic(), 0);
}

RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E)
{
  const BlockPointerType *BPT = 
    E->getCallee()->getType()->getAsBlockPointerType();
  
  llvm::Value *Callee = EmitScalarExpr(E->getCallee());

  // Get a pointer to the generic block literal.
  const llvm::Type *BlockLiteralTy =
    llvm::PointerType::getUnqual(getGenericBlockLiteralType(*this));

  // Bitcast the callee to a block literal.
  llvm::Value *BlockLiteral = 
    Builder.CreateBitCast(Callee, BlockLiteralTy, "block.literal");

  // Get the function pointer from the literal.
  llvm::Value *FuncPtr = Builder.CreateStructGEP(BlockLiteral, 3, "tmp");
  llvm::Value *Func = Builder.CreateLoad(FuncPtr, FuncPtr, "tmp");

  // Cast the function pointer to the right type.
  const llvm::Type *BlockFTy = 
    ConvertType(getBlockFunctionType(getContext(), BPT));
  const llvm::Type *BlockFTyPtr = llvm::PointerType::getUnqual(BlockFTy);
  Func = Builder.CreateBitCast(Func, BlockFTyPtr);

  BlockLiteral = 
    Builder.CreateBitCast(BlockLiteral, 
                          llvm::PointerType::getUnqual(llvm::Type::Int8Ty),
                          "tmp");
  
  // Add the block literal.
  QualType VoidPtrTy = getContext().getPointerType(getContext().VoidTy);
  CallArgList Args;
  Args.push_back(std::make_pair(RValue::get(BlockLiteral), VoidPtrTy));
  
  // And the rest of the arguments.
  for (CallExpr::const_arg_iterator i = E->arg_begin(), e = E->arg_end(); 
       i != e; ++i)
    Args.push_back(std::make_pair(EmitAnyExprToTemp(*i), 
                                  i->getType()));
  
  // And call the block.
  return EmitCall(CGM.getTypes().getFunctionInfo(E->getType(), Args), 
                  Func, Args);
}