blob: 8d10c4f69b2026b4c5d254eadc2d037e88058d36 [file] [log] [blame]
//===-- CGBlocks.h - state for LLVM CodeGen for blocks ----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This is the internal state used for llvm translation for block literals.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_LIB_CODEGEN_CGBLOCKS_H
#define LLVM_CLANG_LIB_CODEGEN_CGBLOCKS_H
#include "CGBuilder.h"
#include "CGCall.h"
#include "CGValue.h"
#include "CodeGenFunction.h"
#include "CodeGenTypes.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/Type.h"
#include "clang/Basic/TargetInfo.h"
namespace llvm {
class Value;
}
namespace clang {
namespace CodeGen {
class CGBlockInfo;
// Flags stored in __block variables.
enum BlockByrefFlags {
BLOCK_BYREF_HAS_COPY_DISPOSE = (1 << 25), // compiler
BLOCK_BYREF_LAYOUT_MASK = (0xF << 28), // compiler
BLOCK_BYREF_LAYOUT_EXTENDED = (1 << 28),
BLOCK_BYREF_LAYOUT_NON_OBJECT = (2 << 28),
BLOCK_BYREF_LAYOUT_STRONG = (3 << 28),
BLOCK_BYREF_LAYOUT_WEAK = (4 << 28),
BLOCK_BYREF_LAYOUT_UNRETAINED = (5 << 28)
};
enum BlockLiteralFlags {
BLOCK_IS_NOESCAPE = (1 << 23),
BLOCK_HAS_COPY_DISPOSE = (1 << 25),
BLOCK_HAS_CXX_OBJ = (1 << 26),
BLOCK_IS_GLOBAL = (1 << 28),
BLOCK_USE_STRET = (1 << 29),
BLOCK_HAS_SIGNATURE = (1 << 30),
BLOCK_HAS_EXTENDED_LAYOUT = (1u << 31)
};
class BlockFlags {
uint32_t flags;
public:
BlockFlags(uint32_t flags) : flags(flags) {}
BlockFlags() : flags(0) {}
BlockFlags(BlockLiteralFlags flag) : flags(flag) {}
BlockFlags(BlockByrefFlags flag) : flags(flag) {}
uint32_t getBitMask() const { return flags; }
bool empty() const { return flags == 0; }
friend BlockFlags operator|(BlockFlags l, BlockFlags r) {
return BlockFlags(l.flags | r.flags);
}
friend BlockFlags &operator|=(BlockFlags &l, BlockFlags r) {
l.flags |= r.flags;
return l;
}
friend bool operator&(BlockFlags l, BlockFlags r) {
return (l.flags & r.flags);
}
bool operator==(BlockFlags r) {
return (flags == r.flags);
}
};
inline BlockFlags operator|(BlockLiteralFlags l, BlockLiteralFlags r) {
return BlockFlags(l) | BlockFlags(r);
}
enum BlockFieldFlag_t {
BLOCK_FIELD_IS_OBJECT = 0x03, /* id, NSObject, __attribute__((NSObject)),
block, ... */
BLOCK_FIELD_IS_BLOCK = 0x07, /* a block variable */
BLOCK_FIELD_IS_BYREF = 0x08, /* the on stack structure holding the __block
variable */
BLOCK_FIELD_IS_WEAK = 0x10, /* declared __weak, only used in byref copy
helpers */
BLOCK_FIELD_IS_ARC = 0x40, /* field has ARC-specific semantics */
BLOCK_BYREF_CALLER = 128, /* called from __block (byref) copy/dispose
support routines */
BLOCK_BYREF_CURRENT_MAX = 256
};
class BlockFieldFlags {
uint32_t flags;
BlockFieldFlags(uint32_t flags) : flags(flags) {}
public:
BlockFieldFlags() : flags(0) {}
BlockFieldFlags(BlockFieldFlag_t flag) : flags(flag) {}
uint32_t getBitMask() const { return flags; }
bool empty() const { return flags == 0; }
/// Answers whether the flags indicate that this field is an object
/// or block pointer that requires _Block_object_assign/dispose.
bool isSpecialPointer() const { return flags & BLOCK_FIELD_IS_OBJECT; }
friend BlockFieldFlags operator|(BlockFieldFlags l, BlockFieldFlags r) {
return BlockFieldFlags(l.flags | r.flags);
}
friend BlockFieldFlags &operator|=(BlockFieldFlags &l, BlockFieldFlags r) {
l.flags |= r.flags;
return l;
}
friend bool operator&(BlockFieldFlags l, BlockFieldFlags r) {
return (l.flags & r.flags);
}
bool operator==(BlockFieldFlags Other) const {
return flags == Other.flags;
}
};
inline BlockFieldFlags operator|(BlockFieldFlag_t l, BlockFieldFlag_t r) {
return BlockFieldFlags(l) | BlockFieldFlags(r);
}
/// Information about the layout of a __block variable.
class BlockByrefInfo {
public:
llvm::StructType *Type;
unsigned FieldIndex;
CharUnits ByrefAlignment;
CharUnits FieldOffset;
};
/// Represents a type of copy/destroy operation that should be performed for an
/// entity that's captured by a block.
enum class BlockCaptureEntityKind {
None,
CXXRecord, // Copy or destroy
ARCWeak,
ARCStrong,
NonTrivialCStruct,
BlockObject, // Assign or release
};
/// CGBlockInfo - Information to generate a block literal.
class CGBlockInfo {
public:
/// Name - The name of the block, kindof.
StringRef Name;
/// The field index of 'this' within the block, if there is one.
unsigned CXXThisIndex;
class Capture {
uintptr_t Data;
EHScopeStack::stable_iterator Cleanup;
CharUnits::QuantityType Offset;
/// Type of the capture field. Normally, this is identical to the type of
/// the capture's VarDecl, but can be different if there is an enclosing
/// lambda.
QualType FieldType;
public:
bool isIndex() const { return (Data & 1) != 0; }
bool isConstant() const { return !isIndex(); }
unsigned getIndex() const {
assert(isIndex());
return Data >> 1;
}
CharUnits getOffset() const {
assert(isIndex());
return CharUnits::fromQuantity(Offset);
}
EHScopeStack::stable_iterator getCleanup() const {
assert(isIndex());
return Cleanup;
}
void setCleanup(EHScopeStack::stable_iterator cleanup) {
assert(isIndex());
Cleanup = cleanup;
}
llvm::Value *getConstant() const {
assert(isConstant());
return reinterpret_cast<llvm::Value*>(Data);
}
QualType fieldType() const {
return FieldType;
}
static Capture
makeIndex(unsigned index, CharUnits offset, QualType FieldType,
BlockCaptureEntityKind CopyKind, BlockFieldFlags CopyFlags,
BlockCaptureEntityKind DisposeKind, BlockFieldFlags DisposeFlags,
const BlockDecl::Capture *Cap) {
Capture v;
v.Data = (index << 1) | 1;
v.Offset = offset.getQuantity();
v.FieldType = FieldType;
v.CopyKind = CopyKind;
v.CopyFlags = CopyFlags;
v.DisposeKind = DisposeKind;
v.DisposeFlags = DisposeFlags;
v.Cap = Cap;
return v;
}
static Capture makeConstant(llvm::Value *value,
const BlockDecl::Capture *Cap) {
Capture v;
v.Data = reinterpret_cast<uintptr_t>(value);
v.Cap = Cap;
return v;
}
bool isConstantOrTrivial() const {
return CopyKind == BlockCaptureEntityKind::None &&
DisposeKind == BlockCaptureEntityKind::None;
}
BlockCaptureEntityKind CopyKind = BlockCaptureEntityKind::None,
DisposeKind = BlockCaptureEntityKind::None;
BlockFieldFlags CopyFlags, DisposeFlags;
const BlockDecl::Capture *Cap;
};
/// CanBeGlobal - True if the block can be global, i.e. it has
/// no non-constant captures.
bool CanBeGlobal : 1;
/// True if the block has captures that would necessitate custom copy or
/// dispose helper functions if the block were escaping.
bool NeedsCopyDispose : 1;
/// Indicates whether the block is non-escaping.
bool NoEscape : 1;
/// HasCXXObject - True if the block's custom copy/dispose functions
/// need to be run even in GC mode.
bool HasCXXObject : 1;
/// UsesStret : True if the block uses an stret return. Mutable
/// because it gets set later in the block-creation process.
mutable bool UsesStret : 1;
/// HasCapturedVariableLayout : True if block has captured variables
/// and their layout meta-data has been generated.
bool HasCapturedVariableLayout : 1;
/// Indicates whether an object of a non-external C++ class is captured. This
/// bit is used to determine the linkage of the block copy/destroy helper
/// functions.
bool CapturesNonExternalType : 1;
/// Mapping from variables to pointers to captures in SortedCaptures.
llvm::DenseMap<const VarDecl *, Capture *> Captures;
/// The block's captures. Non-constant captures are sorted by their offsets.
llvm::SmallVector<Capture, 4> SortedCaptures;
// Currently we assume that block-pointer types are never signed.
RawAddress LocalAddress;
llvm::StructType *StructureType;
const BlockDecl *Block;
const BlockExpr *BlockExpression;
CharUnits BlockSize;
CharUnits BlockAlign;
CharUnits CXXThisOffset;
// Offset of the gap caused by block header having a smaller
// alignment than the alignment of the block descriptor. This
// is the gap offset before the first capturued field.
CharUnits BlockHeaderForcedGapOffset;
// Gap size caused by aligning first field after block header.
// This could be zero if no forced alignment is required.
CharUnits BlockHeaderForcedGapSize;
void buildCaptureMap() {
for (auto &C : SortedCaptures)
Captures[C.Cap->getVariable()] = &C;
}
const Capture &getCapture(const VarDecl *var) const {
return const_cast<CGBlockInfo*>(this)->getCapture(var);
}
Capture &getCapture(const VarDecl *var) {
auto it = Captures.find(var);
assert(it != Captures.end() && "no entry for variable!");
return *it->second;
}
const BlockDecl *getBlockDecl() const { return Block; }
const BlockExpr *getBlockExpr() const {
assert(BlockExpression);
assert(BlockExpression->getBlockDecl() == Block);
return BlockExpression;
}
CGBlockInfo(const BlockDecl *blockDecl, StringRef Name);
};
} // end namespace CodeGen
} // end namespace clang
#endif