//===--- IRGenFunction.h - IR Generation for Swift Functions ----*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file defines the structure used to generate the IR body of a // function. // //===----------------------------------------------------------------------===// #ifndef SWIFT_IRGEN_IRGENFUNCTION_H #define SWIFT_IRGEN_IRGENFUNCTION_H #include "DominancePoint.h" #include "GenPack.h" #include "IRBuilder.h" #include "LocalTypeDataKind.h" #include "swift/AST/ReferenceCounting.h" #include "swift/AST/Type.h" #include "swift/Basic/LLVM.h" #include "swift/SIL/SILLocation.h" #include "swift/SIL/SILType.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SetVector.h" #include "llvm/IR/CallingConv.h" namespace llvm { class AllocaInst; class CallSite; class Constant; class Function; } namespace swift { class ArchetypeType; class IRGenOptions; class SILDebugScope; class SILType; class SourceLoc; enum class MetadataState : size_t; enum class CoroAllocatorKind : uint8_t; namespace Lowering { class TypeConverter; } namespace irgen { class DynamicMetadataRequest; class Explosion; class FunctionRef; class HeapLayout; class HeapNonFixedOffsets; class IRGenModule; class LinkEntity; class LocalTypeDataCache; class MetadataDependencyCollector; class MetadataResponse; class Scope; class TypeInfo; enum class ValueWitness : unsigned; /// IRGenFunction - Primary class for emitting LLVM instructions for a /// specific function. class IRGenFunction { public: IRGenModule &IGM; IRBuilder Builder; /// If != OptimizationMode::NotSet, the optimization mode specified with an /// function attribute. OptimizationMode OptMode; bool isPerformanceConstraint; // Destination basic blocks for condfail traps. llvm::SmallVector FailBBs; llvm::Function *const CurFn; ModuleDecl *getSwiftModule() const; SILModule &getSILModule() const; Lowering::TypeConverter &getSILTypes() const; const IRGenOptions &getOptions() const; IRGenFunction(IRGenModule &IGM, llvm::Function *fn, bool isPerformanceConstraint = false, OptimizationMode Mode = OptimizationMode::NotSet, const SILDebugScope *DbgScope = nullptr, std::optional DbgLoc = std::nullopt); ~IRGenFunction(); void unimplemented(SourceLoc Loc, StringRef Message); friend class Scope; Address createErrorResultSlot(SILType errorType, bool isAsync, bool setSwiftErrorFlag = true, bool isTypedError = false); //--- Function prologue and epilogue //------------------------------------------- public: Explosion collectParameters(); void emitScalarReturn(SILType returnResultType, SILType funcResultType, Explosion &scalars, bool isSwiftCCReturn, bool isOutlined, bool mayPeepholeLoad = false, SILType errorType = {}); void emitScalarReturn(llvm::Type *resultTy, Explosion &scalars); void emitBBForReturn(); bool emitBranchToReturnBB(); llvm::BasicBlock *createExceptionUnwindBlock(); void setCallsThunksWithForeignExceptionTraps() { callsAnyAlwaysInlineThunksWithForeignExceptionTraps = true; } void createExceptionTrapScope( llvm::function_ref invokeEmitter); void emitAllExtractValues(llvm::Value *aggValue, llvm::StructType *type, Explosion &out); /// Return the error result slot to be passed to the callee, given an error /// type. There's always only one error type. /// /// For async functions, this is different from the caller result slot because /// that is a gep into the %swift.context. Address getCalleeErrorResultSlot(SILType errorType, bool isTypedError); /// Return the error result slot provided by the caller. Address getCallerErrorResultSlot(); /// Set the error result slot for the current function. void setCallerErrorResultSlot(Address address); /// Set the error result slot for a typed throw for the current function. void setCallerTypedErrorResultSlot(Address address); Address getCallerTypedErrorResultSlot(); Address getCalleeTypedErrorResultSlot(SILType errorType); void setCalleeTypedErrorResultSlot(Address addr); llvm::ConstantInt* getMallocTypeId(); /// Are we currently emitting a coroutine? bool isCoroutine() { return CoroutineHandle != nullptr; } llvm::Value *getCoroutineHandle() { assert(isCoroutine()); return CoroutineHandle; } bool isCalleeAllocatedCoroutine() { return CoroutineAllocator != nullptr; } llvm::Value *getCoroutineAllocator() { assert(isCoroutine()); return CoroutineAllocator; } void setCoroutineHandle(llvm::Value *handle) { assert(CoroutineHandle == nullptr && "already set handle"); assert(handle != nullptr && "setting a null handle"); CoroutineHandle = handle; } void setCoroutineAllocator(llvm::Value *allocator) { assert(CoroutineAllocator == nullptr && "already set allocator"); assert(allocator != nullptr && "setting a null allocator"); CoroutineAllocator = allocator; } std::optional getDefaultCoroutineAllocatorKind(); llvm::BasicBlock *getCoroutineExitBlock() const { return CoroutineExitBlock; } SmallVector coroutineResults; void setCoroutineExitBlock(llvm::BasicBlock *block) { assert(CoroutineExitBlock == nullptr && "already set exit BB"); assert(block != nullptr && "setting a null exit BB"); CoroutineExitBlock = block; } llvm::Value *getAsyncTask(); llvm::Value *getAsyncContext(); void storeCurrentAsyncContext(llvm::Value *context); llvm::CallInst *emitSuspendAsyncCall(unsigned swiftAsyncContextIndex, llvm::StructType *resultTy, ArrayRef args, bool restoreCurrentContext = true); llvm::Value *emitAsyncResumeProjectContext(llvm::Value *callerContextAddr); llvm::Function *getOrCreateResumePrjFn(); llvm::Value *popAsyncContext(llvm::Value *calleeContext); llvm::Function *createAsyncDispatchFn(const FunctionPointer &fnPtr, ArrayRef args); llvm::Function *createAsyncDispatchFn(const FunctionPointer &fnPtr, ArrayRef argTypes); void emitGetAsyncContinuation(SILType resumeTy, StackAddress optionalResultAddr, Explosion &out, bool canThrow); void emitAwaitAsyncContinuation(SILType resumeTy, bool isIndirectResult, Explosion &outDirectResult, llvm::BasicBlock *&normalBB, llvm::PHINode *&optionalErrorPhi, llvm::BasicBlock *&optionalErrorBB); void emitResumeAsyncContinuationReturning(llvm::Value *continuation, llvm::Value *srcPtr, SILType valueTy, bool throwing); void emitResumeAsyncContinuationThrowing(llvm::Value *continuation, llvm::Value *error); void emitClearSensitive(Address address, llvm::Value *size); FunctionPointer getFunctionPointerForResumeIntrinsic(llvm::Value *resumeIntrinsic); void emitSuspensionPoint(Explosion &executor, llvm::Value *asyncResume); llvm::Function *getOrCreateResumeFromSuspensionFn(); llvm::Function *createAsyncSuspendFn(); private: void emitPrologue(); void emitEpilogue(); Address ReturnSlot; llvm::BasicBlock *ReturnBB; Address CalleeErrorResultSlot; Address AsyncCalleeErrorResultSlot; Address CallerErrorResultSlot; Address CallerTypedErrorResultSlot; Address CalleeTypedErrorResultSlot; llvm::Value *CoroutineHandle = nullptr; llvm::Value *CoroutineAllocator = nullptr; llvm::Value *AsyncCoroutineCurrentResume = nullptr; llvm::Value *AsyncCoroutineCurrentContinuationContext = nullptr; protected: // Whether pack metadata stack promotion is disabled for this function in // particular. bool packMetadataStackPromotionDisabled = false; /// The on-stack pack metadata allocations emitted so far awaiting cleanup. llvm::SmallSetVector OutstandingStackPackAllocs; private: Address asyncContextLocation; /// The unique block that calls @llvm.coro.end. llvm::BasicBlock *CoroutineExitBlock = nullptr; /// The blocks that handle thrown exceptions from all throwing foreign calls /// in this function. llvm::SmallVector ExceptionUnwindBlocks; /// True if this function calls any always inline thunks that have a foreign /// exception trap. bool callsAnyAlwaysInlineThunksWithForeignExceptionTraps = false; public: void emitCoroutineOrAsyncExit(bool isUnwind); //--- Helper methods ----------------------------------------------------------- public: /// Returns the optimization mode for the function. If no mode is set for the /// function, returns the global mode, i.e. the mode in IRGenOptions. OptimizationMode getEffectiveOptimizationMode() const; /// Returns true if this function should be optimized for size. bool optimizeForSize() const { return getEffectiveOptimizationMode() == OptimizationMode::ForSize; } /// Whether metadata/wtable packs allocated on the stack must be eagerly /// heapified. bool canStackPromotePackMetadata() const; bool outliningCanCallValueWitnesses() const; void setupAsync(unsigned asyncContextIndex); bool isAsync() const { return asyncContextLocation.isValid(); } Address createAlloca(llvm::Type *ty, Alignment align, const llvm::Twine &name = ""); Address createAlloca(llvm::Type *ty, llvm::Value *arraySize, Alignment align, const llvm::Twine &name = ""); StackAddress emitDynamicAlloca(SILType type, const llvm::Twine &name = ""); StackAddress emitDynamicAlloca(llvm::Type *eltTy, llvm::Value *arraySize, Alignment align, bool allowTaskAlloc = true, const llvm::Twine &name = ""); void emitDeallocateDynamicAlloca(StackAddress address, bool allowTaskDealloc = true, bool useTaskDeallocThrough = false); llvm::BasicBlock *createBasicBlock(const llvm::Twine &Name); const TypeInfo &getTypeInfoForUnlowered(Type subst); const TypeInfo &getTypeInfoForUnlowered(AbstractionPattern orig, Type subst); const TypeInfo &getTypeInfoForUnlowered(AbstractionPattern orig, CanType subst); const TypeInfo &getTypeInfoForLowered(CanType T); const TypeInfo &getTypeInfo(SILType T); void emitMemCpy(llvm::Value *dest, llvm::Value *src, Size size, Alignment align); void emitMemCpy(llvm::Value *dest, llvm::Value *src, llvm::Value *size, Alignment align); void emitMemCpy(Address dest, Address src, Size size); void emitMemCpy(Address dest, Address src, llvm::Value *size); llvm::Value *emitByteOffsetGEP(llvm::Value *base, llvm::Value *offset, llvm::Type *objectType, const llvm::Twine &name = ""); Address emitByteOffsetGEP(llvm::Value *base, llvm::Value *offset, const TypeInfo &type, const llvm::Twine &name = ""); Address emitAddressAtOffset(llvm::Value *base, Offset offset, llvm::Type *objectType, Alignment objectAlignment, const llvm::Twine &name = ""); llvm::Value *emitInvariantLoad(Address address, const llvm::Twine &name = ""); void emitStoreOfRelativeIndirectablePointer(llvm::Value *value, Address addr, bool isFar); llvm::Value *emitLoadOfRelativePointer(Address addr, bool isFar, llvm::Type *expectedPointedToType, const llvm::Twine &name = ""); llvm::Value * emitLoadOfCompactFunctionPointer(Address addr, bool isFar, llvm::Type *expectedPointedToType, const llvm::Twine &name = ""); llvm::Value *emitAllocObjectCall(llvm::Value *metadata, llvm::Value *size, llvm::Value *alignMask, const llvm::Twine &name = ""); llvm::Value *emitInitStackObjectCall(llvm::Value *metadata, llvm::Value *object, const llvm::Twine &name = ""); llvm::Value *emitInitStaticObjectCall(llvm::Value *metadata, llvm::Value *object, const llvm::Twine &name = ""); llvm::Value *emitVerifyEndOfLifetimeCall(llvm::Value *object, const llvm::Twine &name = ""); llvm::Value *emitAllocRawCall(llvm::Value *size, llvm::Value *alignMask, const llvm::Twine &name =""); void emitDeallocRawCall(llvm::Value *pointer, llvm::Value *size, llvm::Value *alignMask); void emitAllocBoxCall(llvm::Value *typeMetadata, llvm::Value *&box, llvm::Value *&valueAddress); void emitMakeBoxUniqueCall(llvm::Value *box, llvm::Value *typeMetadata, llvm::Value *alignMask, llvm::Value *&outBox, llvm::Value *&outValueAddress); void emitDeallocBoxCall(llvm::Value *box, llvm::Value *typeMetadata); void emitTSanInoutAccessCall(llvm::Value *address); llvm::Value *emitTargetOSVersionAtLeastCall(llvm::Value *major, llvm::Value *minor, llvm::Value *patch); llvm::Value *emitTargetVariantOSVersionAtLeastCall(llvm::Value *major, llvm::Value *minor, llvm::Value *patch); llvm::Value *emitTargetOSVersionOrVariantOSVersionAtLeastCall( llvm::Value *major, llvm::Value *minor, llvm::Value *patch, llvm::Value *variantMajor, llvm::Value *variantMinor, llvm::Value *variantPatch); llvm::Value *emitProjectBoxCall(llvm::Value *box, llvm::Value *typeMetadata); llvm::Value *emitAllocEmptyBoxCall(); // Emit a call to the given generic type metadata access function. MetadataResponse emitGenericTypeMetadataAccessFunctionCall( llvm::Function *accessFunction, ArrayRef args, DynamicMetadataRequest request); // Emit a reference to the canonical type metadata record for the given AST // type. This can be used to identify the type at runtime. For types with // abstraction difference, the metadata contains the layout information for // values in the maximally-abstracted representation of the type; this is // correct for all uses of reabstractable values in opaque contexts. llvm::Value *emitTypeMetadataRef(CanType type); /// Emit a reference to the canonical type metadata record for the given /// formal type. The metadata is only required to be abstract; that is, /// you cannot use the result for layout. llvm::Value *emitAbstractTypeMetadataRef(CanType type); MetadataResponse emitTypeMetadataRef(CanType type, DynamicMetadataRequest request); // Emit a reference to a metadata object that can be used for layout, but // cannot be used to identify a type. This will produce a layout appropriate // to the abstraction level of the given type. It may be able to avoid runtime // calls if there is a standard metadata object with the correct layout for // the type. // // TODO: It might be better to return just a value witness table reference // here, since for some types it's easier to get a shared reference to one // than a metadata reference, and it would be more type-safe. llvm::Value *emitTypeMetadataRefForLayout(SILType type); llvm::Value *emitTypeMetadataRefForLayout(SILType type, DynamicMetadataRequest request); llvm::Value *emitValueGenericRef(CanType type); llvm::Value *emitValueWitnessTableRef(SILType type, llvm::Value **metadataSlot = nullptr); llvm::Value *emitValueWitnessTableRef(SILType type, DynamicMetadataRequest request, llvm::Value **metadataSlot = nullptr); llvm::Value *emitValueWitnessTableRefForMetadata(llvm::Value *metadata); llvm::Value *emitValueWitnessValue(SILType type, ValueWitness index); FunctionPointer emitValueWitnessFunctionRef(SILType type, llvm::Value *&metadataSlot, ValueWitness index); void emitInitializeFieldOffsetVector(SILType T, llvm::Value *metadata, bool isVWTMutable, MetadataDependencyCollector *collector); llvm::Value *optionallyLoadFromConditionalProtocolWitnessTable( llvm::Value *wtable); llvm::Value *emitPackShapeExpression(CanType type); void recordStackPackMetadataAlloc(StackAddress addr, llvm::Value *shape); void eraseStackPackMetadataAlloc(StackAddress addr, llvm::Value *shape); void recordStackPackWitnessTableAlloc(StackAddress addr, llvm::Value *shape); void eraseStackPackWitnessTableAlloc(StackAddress addr, llvm::Value *shape); void withLocalStackPackAllocs(llvm::function_ref fn); /// Emit a load of a reference to the given Objective-C selector. llvm::Value *emitObjCSelectorRefLoad(StringRef selector); /// Return the SILDebugScope for this function. const SILDebugScope *getDebugScope() const { return DbgScope; } llvm::Value *coerceValue(llvm::Value *value, llvm::Type *toTy, const llvm::DataLayout &); Explosion coerceValueTo(SILType fromTy, Explosion &from, SILType toTy); /// Mark a load as invariant. void setInvariantLoad(llvm::LoadInst *load); /// Mark a load as dereferenceable to `size` bytes. void setDereferenceableLoad(llvm::LoadInst *load, unsigned size); /// Emit a non-mergeable trap call, optionally followed by a terminator. void emitTrap(StringRef failureMessage, bool EmitUnreachable); void emitConditionalTrap(llvm::Value *condition, StringRef failureMessage, const SILDebugScope *debugScope = nullptr); /// Given at least a src address to a list of elements, runs body over each /// element passing its address. An optional destination address can be /// provided which this will run over as well to perform things like /// 'initWithTake' from src to dest. void emitLoopOverElements(const TypeInfo &elementTypeInfo, SILType elementType, CanType countType, Address dest, Address src, std::function body); private: llvm::Instruction *AllocaIP; const SILDebugScope *DbgScope; /// The insertion point where we should but instructions we would normally put /// at the beginning of the function. LLVM's coroutine lowering really does /// not like it if we put instructions with side-effectrs before the /// coro.begin. llvm::Instruction *EarliestIP; public: void setEarliestInsertionPoint(llvm::Instruction *inst) { EarliestIP = inst; } /// Returns the first insertion point before which we should insert /// instructions which have side-effects. llvm::Instruction *getEarliestInsertionPoint() const { return EarliestIP; } //--- Reference-counting methods //----------------------------------------------- public: // Returns the default atomicity of the module. Atomicity getDefaultAtomicity(); llvm::Value *emitUnmanagedAlloc(const HeapLayout &layout, const llvm::Twine &name, llvm::Constant *captureDescriptor, const HeapNonFixedOffsets *offsets = 0); // Functions that don't care about the reference-counting style. void emitFixLifetime(llvm::Value *value); // Routines that are generic over the reference-counting style: // - strong references void emitStrongRetain(llvm::Value *value, ReferenceCounting refcounting, Atomicity atomicity); void emitStrongRelease(llvm::Value *value, ReferenceCounting refcounting, Atomicity atomicity); llvm::Value *emitLoadRefcountedPtr(Address addr, ReferenceCounting style); llvm::Value *getReferenceStorageExtraInhabitantIndex(Address src, ReferenceOwnership ownership, ReferenceCounting style); void storeReferenceStorageExtraInhabitant(llvm::Value *index, Address dest, ReferenceOwnership ownership, ReferenceCounting style); #define NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Kind) \ void emit##Kind##Name##Init(llvm::Value *val, Address dest); \ void emit##Kind##Name##Assign(llvm::Value *value, Address dest); \ void emit##Kind##Name##CopyInit(Address destAddr, Address srcAddr); \ void emit##Kind##Name##TakeInit(Address destAddr, Address srcAddr); \ void emit##Kind##Name##CopyAssign(Address destAddr, Address srcAddr); \ void emit##Kind##Name##TakeAssign(Address destAddr, Address srcAddr); \ llvm::Value *emit##Kind##Name##LoadStrong(Address src, \ llvm::Type *resultType); \ llvm::Value *emit##Kind##Name##TakeStrong(Address src, \ llvm::Type *resultType); \ void emit##Kind##Name##Destroy(Address addr); #define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Kind) \ void emit##Kind##Name##Retain(llvm::Value *value, Atomicity atomicity); \ void emit##Kind##Name##Release(llvm::Value *value, Atomicity atomicity); \ void emit##Kind##StrongRetain##Name(llvm::Value *value, Atomicity atomicity);\ void emit##Kind##StrongRetainAnd##Name##Release(llvm::Value *value, \ Atomicity atomicity); #define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Native) \ NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Unknown) \ void emit##Name##Init(llvm::Value *val, Address dest, ReferenceCounting style); \ void emit##Name##Assign(llvm::Value *value, Address dest, \ ReferenceCounting style); \ void emit##Name##CopyInit(Address destAddr, Address srcAddr, \ ReferenceCounting style); \ void emit##Name##TakeInit(Address destAddr, Address srcAddr, \ ReferenceCounting style); \ void emit##Name##CopyAssign(Address destAddr, Address srcAddr, \ ReferenceCounting style); \ void emit##Name##TakeAssign(Address destAddr, Address srcAddr, \ ReferenceCounting style); \ llvm::Value *emit##Name##LoadStrong(Address src, llvm::Type *resultType, \ ReferenceCounting style); \ llvm::Value *emit##Name##TakeStrong(Address src, llvm::Type *resultType, \ ReferenceCounting style); \ void emit##Name##Destroy(Address addr, ReferenceCounting style); #define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, "...") \ ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Native) \ ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Unknown) \ void emit##Name##Retain(llvm::Value *value, ReferenceCounting style, \ Atomicity atomicity); \ void emit##Name##Release(llvm::Value *value, ReferenceCounting style, \ Atomicity atomicity); \ void emitStrongRetain##Name(llvm::Value *value, ReferenceCounting style, \ Atomicity atomicity); \ void emitStrongRetainAnd##Name##Release(llvm::Value *value, \ ReferenceCounting style, \ Atomicity atomicity); #define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE_HELPER(Name, Native) \ void emit##Name##Retain(llvm::Value *value, ReferenceCounting style, \ Atomicity atomicity) { \ assert(style == ReferenceCounting::Native); \ emitNative##Name##Retain(value, atomicity); \ } \ void emit##Name##Release(llvm::Value *value, ReferenceCounting style, \ Atomicity atomicity) { \ assert(style == ReferenceCounting::Native); \ emitNative##Name##Release(value, atomicity); \ } \ void emitStrongRetain##Name(llvm::Value *value, ReferenceCounting style, \ Atomicity atomicity) { \ assert(style == ReferenceCounting::Native); \ emitNativeStrongRetain##Name(value, atomicity); \ } \ void emitStrongRetainAnd##Name##Release(llvm::Value *value, \ ReferenceCounting style, \ Atomicity atomicity) { \ assert(style == ReferenceCounting::Native); \ emitNativeStrongRetainAnd##Name##Release(value, atomicity); \ } #include "swift/AST/ReferenceStorage.def" #undef NEVER_LOADABLE_CHECKED_REF_STORAGE_HELPER #undef ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE_HELPER // Routines for the Swift native reference-counting style. // - strong references void emitNativeStrongAssign(llvm::Value *value, Address addr); void emitNativeStrongInit(llvm::Value *value, Address addr); void emitNativeStrongRetain(llvm::Value *value, Atomicity atomicity); void emitNativeStrongRelease(llvm::Value *value, Atomicity atomicity); void emitNativeSetDeallocating(llvm::Value *value); // Routines for the ObjC reference-counting style. void emitObjCStrongRetain(llvm::Value *value); llvm::Value *emitObjCRetainCall(llvm::Value *value); llvm::Value *emitObjCAutoreleaseCall(llvm::Value *value); void emitObjCStrongRelease(llvm::Value *value); llvm::Value *emitBlockCopyCall(llvm::Value *value); void emitBlockRelease(llvm::Value *value); void emitForeignReferenceTypeLifetimeOperation(ValueDecl *fn, llvm::Value *value, bool needsNullCheck = false); // Routines for an unknown reference-counting style (meaning, // dynamically something compatible with either the ObjC or Swift styles). // - strong references void emitUnknownStrongRetain(llvm::Value *value, Atomicity atomicity); void emitUnknownStrongRelease(llvm::Value *value, Atomicity atomicity); // Routines for the Builtin.NativeObject reference-counting style. void emitBridgeStrongRetain(llvm::Value *value, Atomicity atomicity); void emitBridgeStrongRelease(llvm::Value *value, Atomicity atomicity); // Routines for the ErrorType reference-counting style. void emitErrorStrongRetain(llvm::Value *value); void emitErrorStrongRelease(llvm::Value *value); llvm::Value *emitIsUniqueCall(llvm::Value *value, ReferenceCounting style, SourceLoc loc, bool isNonNull); llvm::Value *emitIsEscapingClosureCall(llvm::Value *value, SourceLoc loc, unsigned verificationType); Address emitTaskAlloc(llvm::Value *size, Alignment alignment); void emitTaskDealloc(Address address); void emitTaskDeallocThrough(Address address); llvm::Value *alignUpToMaximumAlignment(llvm::Type *sizeTy, llvm::Value *val); //--- Expression emission //------------------------------------------------------ public: void emitFakeExplosion(const TypeInfo &type, Explosion &explosion); //--- Type emission ------------------------------------------------------------ public: /// Look up a local type metadata reference, returning a null response /// if no entry was found which can satisfy the request. This may need /// emit code to materialize the reference. /// /// This does a look up for a formal ("AST") type. If you are looking for /// type metadata that will work for working with a representation /// ("lowered", "SIL") type, use getGetLocalTypeMetadataForLayout. MetadataResponse tryGetLocalTypeMetadata(CanType type, DynamicMetadataRequest request); /// Look up a local type data reference, returning null if no entry was /// found. This may need to emit code to materialize the reference. /// /// The data kind cannot be for type metadata; use tryGetLocalTypeMetadata /// for that. llvm::Value *tryGetLocalTypeData(CanType type, LocalTypeDataKind kind); /// The same as tryGetLocalTypeMetadata, but for representation-compatible /// "layout" metadata. The returned metadata may not be for a type that /// has anything to do with the formal type that was lowered to the given /// type; however, it is guaranteed to have equivalent characteristics /// in terms of layout, spare bits, POD-ness, and so on. /// /// We use a separate function name for this to clarify that you should /// only ever be looking for type metadata for a lowered SILType for the /// purposes of local manipulation, such as the layout of a type or /// emitting a value-copy. MetadataResponse tryGetLocalTypeMetadataForLayout(SILType type, DynamicMetadataRequest request); /// The same as tryGetForLocalTypeData, but for representation-compatible /// "layout" metadata. See the comment on tryGetLocalTypeMetadataForLayout. /// /// The data kind cannot be for type metadata; use /// tryGetLocalTypeMetadataForLayout for that. llvm::Value *tryGetLocalTypeDataForLayout(SILType type, LocalTypeDataKind kind); /// Add a local type metadata reference at a point which definitely /// dominates all of its uses. void setUnscopedLocalTypeMetadata(CanType type, MetadataResponse response); /// Add a local type data reference at a point which definitely /// dominates all of its uses. /// /// The data kind cannot be for type metadata; use /// setUnscopedLocalTypeMetadata for that. void setUnscopedLocalTypeData(CanType type, LocalTypeDataKind kind, llvm::Value *data); /// Add a local type metadata reference that is valid at the current /// insertion point. void setScopedLocalTypeMetadata(CanType type, MetadataResponse value); /// Add a local type data reference that is valid at the current /// insertion point. /// /// The data kind cannot be for type metadata; use setScopedLocalTypeMetadata /// for that. void setScopedLocalTypeData(CanType type, LocalTypeDataKind kind, llvm::Value *data); /// The same as setScopedLocalTypeMetadata, but for representation-compatible /// "layout" metadata. See the comment on tryGetLocalTypeMetadataForLayout. void setScopedLocalTypeMetadataForLayout(SILType type, MetadataResponse value); /// The same as setScopedLocalTypeData, but for representation-compatible /// "layout" metadata. See the comment on tryGetLocalTypeMetadataForLayout. /// /// The data kind cannot be for type metadata; use /// setScopedLocalTypeMetadataForLayout for that. void setScopedLocalTypeDataForLayout(SILType type, LocalTypeDataKind kind, llvm::Value *data); // These are for the private use of the LocalTypeData subsystem. MetadataResponse tryGetLocalTypeMetadata(LocalTypeDataKey key, DynamicMetadataRequest request); llvm::Value *tryGetLocalTypeData(LocalTypeDataKey key); MetadataResponse tryGetConcreteLocalTypeData(LocalTypeDataKey key, DynamicMetadataRequest request); void setUnscopedLocalTypeData(LocalTypeDataKey key, MetadataResponse value); void setScopedLocalTypeData(LocalTypeDataKey key, MetadataResponse value, bool mayEmitDebugInfo = true); /// Given a concrete type metadata node, add all the local type data /// that we can reach from it. void bindLocalTypeDataFromTypeMetadata(CanType type, IsExact_t isExact, llvm::Value *metadata, MetadataState metadataState); /// Given the witness table parameter, bind local type data for /// the witness table itself and any conditional requirements. void bindLocalTypeDataFromSelfWitnessTable( const ProtocolConformance *conformance, llvm::Value *selfTable, llvm::function_ref mapTypeIntoContext); void setDominanceResolver(DominanceResolverFunction resolver) { assert(DominanceResolver == nullptr); DominanceResolver = resolver; } bool isActiveDominancePointDominatedBy(DominancePoint point) { // If the point is universal, it dominates. if (point.isUniversal()) return true; assert(!ActiveDominancePoint.isUniversal() && "active dominance point is universal but there exists a" "non-universal point?"); // If we don't have a resolver, we're emitting a simple helper // function; just assume dominance. if (!DominanceResolver) return true; // Otherwise, ask the resolver. return DominanceResolver(*this, ActiveDominancePoint, point); } /// Is the current dominance point conditional in some way not /// tracked by the active dominance point? /// /// This should only be used by the local type data cache code. bool isConditionalDominancePoint() const { return ConditionalDominance != nullptr; } void registerConditionalLocalTypeDataKey(LocalTypeDataKey key) { assert(ConditionalDominance != nullptr && "not in a conditional dominance scope"); ConditionalDominance->registerConditionalLocalTypeDataKey(key); } /// Return the currently-active dominance point. DominancePoint getActiveDominancePoint() const { return ActiveDominancePoint; } /// A RAII object for temporarily changing the dominance of the active /// definition point. class DominanceScope { IRGenFunction &IGF; DominancePoint OldDominancePoint; public: explicit DominanceScope(IRGenFunction &IGF, DominancePoint newPoint) : IGF(IGF), OldDominancePoint(IGF.ActiveDominancePoint) { IGF.ActiveDominancePoint = newPoint; assert(!newPoint.isOrdinary() || IGF.DominanceResolver); } DominanceScope(const DominanceScope &other) = delete; DominanceScope &operator=(const DominanceScope &other) = delete; ~DominanceScope() { IGF.ActiveDominancePoint = OldDominancePoint; } }; /// A RAII object for temporarily suppressing type-data caching at the /// active definition point. Do this if you're adding local control flow /// that isn't modeled by the dominance system. class ConditionalDominanceScope { IRGenFunction &IGF; ConditionalDominanceScope *OldScope; SmallVector RegisteredKeys; public: explicit ConditionalDominanceScope(IRGenFunction &IGF) : IGF(IGF), OldScope(IGF.ConditionalDominance) { IGF.ConditionalDominance = this; } ConditionalDominanceScope(const ConditionalDominanceScope &other) = delete; ConditionalDominanceScope &operator=(const ConditionalDominanceScope &other) = delete; void registerConditionalLocalTypeDataKey(LocalTypeDataKey key) { RegisteredKeys.push_back(key); } ~ConditionalDominanceScope(); }; /// The kind of value DynamicSelf is. enum DynamicSelfKind { /// An object reference. ObjectReference, /// A Swift metatype. SwiftMetatype, /// An ObjC metatype. ObjCMetatype, }; llvm::Value *getDynamicSelfMetadata(); void setDynamicSelfMetadata(CanType selfBaseTy, bool selfIsExact, llvm::Value *value, DynamicSelfKind kind); #ifndef NDEBUG LocalTypeDataCache const *getLocalTypeData() { return LocalTypeData; } #endif /// A forwardable argument is a load that is immediately preceeds the apply it /// is used as argument to. If there is no side-effecting instructions between /// said load and the apply, we can memcpy the loads address to the apply's /// indirect argument alloca. void clearForwardableArguments() { forwardableArguments.clear(); } void setForwardableArgument(unsigned idx) { forwardableArguments.insert(idx); } bool isForwardableArgument(unsigned idx) const { return forwardableArguments.contains(idx); } private: LocalTypeDataCache &getOrCreateLocalTypeData(); void destroyLocalTypeData(); LocalTypeDataCache *LocalTypeData = nullptr; /// The dominance resolver. This can be set at most once; when it's not /// set, this emission must never have a non-null active definition point. DominanceResolverFunction DominanceResolver = nullptr; DominancePoint ActiveDominancePoint = DominancePoint::universal(); ConditionalDominanceScope *ConditionalDominance = nullptr; /// The value that satisfies metadata lookups for DynamicSelfType. llvm::Value *SelfValue = nullptr; /// If set, the dynamic Self type is assumed to be equivalent to this exact class. CanType SelfType; bool SelfTypeIsExact = false; DynamicSelfKind SelfKind; llvm::SmallSetVector forwardableArguments; }; using ConditionalDominanceScope = IRGenFunction::ConditionalDominanceScope; } // end namespace irgen } // end namespace swift #endif