Path: blob/main/contrib/llvm-project/clang/lib/CodeGen/CGBlocks.h
35233 views
//===-- CGBlocks.h - state for LLVM CodeGen for blocks ----------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This is the internal state used for llvm translation for block literals.9//10//===----------------------------------------------------------------------===//1112#ifndef LLVM_CLANG_LIB_CODEGEN_CGBLOCKS_H13#define LLVM_CLANG_LIB_CODEGEN_CGBLOCKS_H1415#include "CGBuilder.h"16#include "CGCall.h"17#include "CGValue.h"18#include "CodeGenFunction.h"19#include "CodeGenTypes.h"20#include "clang/AST/CharUnits.h"21#include "clang/AST/Expr.h"22#include "clang/AST/ExprCXX.h"23#include "clang/AST/ExprObjC.h"24#include "clang/AST/Type.h"25#include "clang/Basic/TargetInfo.h"2627namespace llvm {28class Value;29}3031namespace clang {32namespace CodeGen {3334class CGBlockInfo;3536// Flags stored in __block variables.37enum BlockByrefFlags {38BLOCK_BYREF_HAS_COPY_DISPOSE = (1 << 25), // compiler39BLOCK_BYREF_LAYOUT_MASK = (0xF << 28), // compiler40BLOCK_BYREF_LAYOUT_EXTENDED = (1 << 28),41BLOCK_BYREF_LAYOUT_NON_OBJECT = (2 << 28),42BLOCK_BYREF_LAYOUT_STRONG = (3 << 28),43BLOCK_BYREF_LAYOUT_WEAK = (4 << 28),44BLOCK_BYREF_LAYOUT_UNRETAINED = (5 << 28)45};4647enum BlockLiteralFlags {48BLOCK_IS_NOESCAPE = (1 << 23),49BLOCK_HAS_COPY_DISPOSE = (1 << 25),50BLOCK_HAS_CXX_OBJ = (1 << 26),51BLOCK_IS_GLOBAL = (1 << 28),52BLOCK_USE_STRET = (1 << 29),53BLOCK_HAS_SIGNATURE = (1 << 30),54BLOCK_HAS_EXTENDED_LAYOUT = (1u << 31)55};56class BlockFlags {57uint32_t flags;5859public:60BlockFlags(uint32_t flags) : flags(flags) {}61BlockFlags() : flags(0) {}62BlockFlags(BlockLiteralFlags flag) : flags(flag) {}63BlockFlags(BlockByrefFlags flag) : flags(flag) {}6465uint32_t getBitMask() const { return flags; }66bool empty() const { return flags == 0; }6768friend BlockFlags operator|(BlockFlags l, BlockFlags r) {69return BlockFlags(l.flags | r.flags);70}71friend BlockFlags &operator|=(BlockFlags &l, BlockFlags r) {72l.flags |= r.flags;73return l;74}75friend bool operator&(BlockFlags l, BlockFlags r) {76return (l.flags & r.flags);77}78bool operator==(BlockFlags r) {79return (flags == r.flags);80}81};82inline BlockFlags operator|(BlockLiteralFlags l, BlockLiteralFlags r) {83return BlockFlags(l) | BlockFlags(r);84}8586enum BlockFieldFlag_t {87BLOCK_FIELD_IS_OBJECT = 0x03, /* id, NSObject, __attribute__((NSObject)),88block, ... */89BLOCK_FIELD_IS_BLOCK = 0x07, /* a block variable */9091BLOCK_FIELD_IS_BYREF = 0x08, /* the on stack structure holding the __block92variable */93BLOCK_FIELD_IS_WEAK = 0x10, /* declared __weak, only used in byref copy94helpers */95BLOCK_FIELD_IS_ARC = 0x40, /* field has ARC-specific semantics */96BLOCK_BYREF_CALLER = 128, /* called from __block (byref) copy/dispose97support routines */98BLOCK_BYREF_CURRENT_MAX = 25699};100101class BlockFieldFlags {102uint32_t flags;103104BlockFieldFlags(uint32_t flags) : flags(flags) {}105public:106BlockFieldFlags() : flags(0) {}107BlockFieldFlags(BlockFieldFlag_t flag) : flags(flag) {}108109uint32_t getBitMask() const { return flags; }110bool empty() const { return flags == 0; }111112/// Answers whether the flags indicate that this field is an object113/// or block pointer that requires _Block_object_assign/dispose.114bool isSpecialPointer() const { return flags & BLOCK_FIELD_IS_OBJECT; }115116friend BlockFieldFlags operator|(BlockFieldFlags l, BlockFieldFlags r) {117return BlockFieldFlags(l.flags | r.flags);118}119friend BlockFieldFlags &operator|=(BlockFieldFlags &l, BlockFieldFlags r) {120l.flags |= r.flags;121return l;122}123friend bool operator&(BlockFieldFlags l, BlockFieldFlags r) {124return (l.flags & r.flags);125}126bool operator==(BlockFieldFlags Other) const {127return flags == Other.flags;128}129};130inline BlockFieldFlags operator|(BlockFieldFlag_t l, BlockFieldFlag_t r) {131return BlockFieldFlags(l) | BlockFieldFlags(r);132}133134/// Information about the layout of a __block variable.135class BlockByrefInfo {136public:137llvm::StructType *Type;138unsigned FieldIndex;139CharUnits ByrefAlignment;140CharUnits FieldOffset;141};142143/// Represents a type of copy/destroy operation that should be performed for an144/// entity that's captured by a block.145enum class BlockCaptureEntityKind {146None,147CXXRecord, // Copy or destroy148ARCWeak,149ARCStrong,150NonTrivialCStruct,151BlockObject, // Assign or release152};153154/// CGBlockInfo - Information to generate a block literal.155class CGBlockInfo {156public:157/// Name - The name of the block, kindof.158StringRef Name;159160/// The field index of 'this' within the block, if there is one.161unsigned CXXThisIndex;162163class Capture {164uintptr_t Data;165EHScopeStack::stable_iterator Cleanup;166CharUnits::QuantityType Offset;167168/// Type of the capture field. Normally, this is identical to the type of169/// the capture's VarDecl, but can be different if there is an enclosing170/// lambda.171QualType FieldType;172173public:174bool isIndex() const { return (Data & 1) != 0; }175bool isConstant() const { return !isIndex(); }176177unsigned getIndex() const {178assert(isIndex());179return Data >> 1;180}181CharUnits getOffset() const {182assert(isIndex());183return CharUnits::fromQuantity(Offset);184}185EHScopeStack::stable_iterator getCleanup() const {186assert(isIndex());187return Cleanup;188}189void setCleanup(EHScopeStack::stable_iterator cleanup) {190assert(isIndex());191Cleanup = cleanup;192}193194llvm::Value *getConstant() const {195assert(isConstant());196return reinterpret_cast<llvm::Value*>(Data);197}198199QualType fieldType() const {200return FieldType;201}202203static Capture204makeIndex(unsigned index, CharUnits offset, QualType FieldType,205BlockCaptureEntityKind CopyKind, BlockFieldFlags CopyFlags,206BlockCaptureEntityKind DisposeKind, BlockFieldFlags DisposeFlags,207const BlockDecl::Capture *Cap) {208Capture v;209v.Data = (index << 1) | 1;210v.Offset = offset.getQuantity();211v.FieldType = FieldType;212v.CopyKind = CopyKind;213v.CopyFlags = CopyFlags;214v.DisposeKind = DisposeKind;215v.DisposeFlags = DisposeFlags;216v.Cap = Cap;217return v;218}219220static Capture makeConstant(llvm::Value *value,221const BlockDecl::Capture *Cap) {222Capture v;223v.Data = reinterpret_cast<uintptr_t>(value);224v.Cap = Cap;225return v;226}227228bool isConstantOrTrivial() const {229return CopyKind == BlockCaptureEntityKind::None &&230DisposeKind == BlockCaptureEntityKind::None;231}232233BlockCaptureEntityKind CopyKind = BlockCaptureEntityKind::None,234DisposeKind = BlockCaptureEntityKind::None;235BlockFieldFlags CopyFlags, DisposeFlags;236const BlockDecl::Capture *Cap;237};238239/// CanBeGlobal - True if the block can be global, i.e. it has240/// no non-constant captures.241bool CanBeGlobal : 1;242243/// True if the block has captures that would necessitate custom copy or244/// dispose helper functions if the block were escaping.245bool NeedsCopyDispose : 1;246247/// Indicates whether the block is non-escaping.248bool NoEscape : 1;249250/// HasCXXObject - True if the block's custom copy/dispose functions251/// need to be run even in GC mode.252bool HasCXXObject : 1;253254/// UsesStret : True if the block uses an stret return. Mutable255/// because it gets set later in the block-creation process.256mutable bool UsesStret : 1;257258/// HasCapturedVariableLayout : True if block has captured variables259/// and their layout meta-data has been generated.260bool HasCapturedVariableLayout : 1;261262/// Indicates whether an object of a non-external C++ class is captured. This263/// bit is used to determine the linkage of the block copy/destroy helper264/// functions.265bool CapturesNonExternalType : 1;266267/// Mapping from variables to pointers to captures in SortedCaptures.268llvm::DenseMap<const VarDecl *, Capture *> Captures;269270/// The block's captures. Non-constant captures are sorted by their offsets.271llvm::SmallVector<Capture, 4> SortedCaptures;272273// Currently we assume that block-pointer types are never signed.274RawAddress LocalAddress;275llvm::StructType *StructureType;276const BlockDecl *Block;277const BlockExpr *BlockExpression;278CharUnits BlockSize;279CharUnits BlockAlign;280CharUnits CXXThisOffset;281282// Offset of the gap caused by block header having a smaller283// alignment than the alignment of the block descriptor. This284// is the gap offset before the first capturued field.285CharUnits BlockHeaderForcedGapOffset;286// Gap size caused by aligning first field after block header.287// This could be zero if no forced alignment is required.288CharUnits BlockHeaderForcedGapSize;289290void buildCaptureMap() {291for (auto &C : SortedCaptures)292Captures[C.Cap->getVariable()] = &C;293}294295const Capture &getCapture(const VarDecl *var) const {296return const_cast<CGBlockInfo*>(this)->getCapture(var);297}298Capture &getCapture(const VarDecl *var) {299auto it = Captures.find(var);300assert(it != Captures.end() && "no entry for variable!");301return *it->second;302}303304const BlockDecl *getBlockDecl() const { return Block; }305const BlockExpr *getBlockExpr() const {306assert(BlockExpression);307assert(BlockExpression->getBlockDecl() == Block);308return BlockExpression;309}310311CGBlockInfo(const BlockDecl *blockDecl, StringRef Name);312};313314} // end namespace CodeGen315} // end namespace clang316317#endif318319320