//===--- 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 "swift/Basic/LLVM.h" #include "swift/AST/Type.h" #include "swift/SIL/SILLocation.h" #include "swift/SIL/SILType.h" #include "llvm/ADT/DenseMap.h" #include "llvm/IR/CallingConv.h" #include "IRBuilder.h" #include "LocalTypeDataKind.h" #include "DominancePoint.h" namespace llvm { class AllocaInst; class CallSite; class Constant; class Function; } namespace swift { class ArchetypeType; class AssociatedTypeDecl; class ClassDecl; class ConstructorDecl; class Decl; class ExtensionDecl; class FuncDecl; class EnumElementDecl; class EnumType; class Pattern; class PatternBindingDecl; class SILDebugScope; class SILType; class KeyPathInst; class SourceLoc; class StructType; class Substitution; class ValueDecl; class VarDecl; namespace Lowering { class TypeConverter; } namespace irgen { class Explosion; class FunctionRef; class HeapLayout; class HeapNonFixedOffsets; class IRGenModule; class LinkEntity; class LocalTypeDataCache; class Scope; class TypeInfo; enum class ValueWitness : unsigned; enum class ReferenceCounting : unsigned char; /// IRGenFunction - Primary class for emitting LLVM instructions for a /// specific function. class IRGenFunction { public: IRGenModule &IGM; IRBuilder Builder; llvm::Function *CurFn; ModuleDecl *getSwiftModule() const; SILModule &getSILModule() const; Lowering::TypeConverter &getSILTypes() const; IRGenFunction(IRGenModule &IGM, llvm::Function *fn, const SILDebugScope *DbgScope = nullptr, Optional DbgLoc = None); ~IRGenFunction(); void unimplemented(SourceLoc Loc, StringRef Message); friend class Scope; //--- Function prologue and epilogue ------------------------------------------- public: Explosion collectParameters(); void emitScalarReturn(SILType resultTy, Explosion &scalars, bool isSwiftCCReturn); void emitScalarReturn(llvm::Type *resultTy, Explosion &scalars); void emitBBForReturn(); bool emitBranchToReturnBB(); /// Return the error result slot, given an error type. There's /// always only one error type. Address getErrorResultSlot(SILType errorType); /// Return the error result slot provided by the caller. Address getCallerErrorResultSlot(); /// Set the error result slot. void setErrorResultSlot(llvm::Value *address); private: void emitPrologue(); void emitEpilogue(); Address ReturnSlot; llvm::BasicBlock *ReturnBB; llvm::Value *ErrorResultSlot = nullptr; //--- Helper methods ----------------------------------------------------------- public: 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); Address createFixedSizeBufferAlloca(const llvm::Twine &name); 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 = ""); void emitStoreOfRelativeIndirectablePointer(llvm::Value *value, Address addr, bool isFar); llvm::Value * emitLoadOfRelativeIndirectablePointer(Address addr, bool isFar, llvm::PointerType *expectedType, 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 *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 *emitProjectBoxCall(llvm::Value *box, llvm::Value *typeMetadata); llvm::Value *emitAllocEmptyBoxCall(); // 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 a type layout record for the given type. The referenced // data is enough to lay out an aggregate containing a value of the type, but // can't uniquely represent the type or perform value witness operations on // it. llvm::Value *emitTypeLayoutRef(SILType type); // 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 *emitValueWitnessTableRef(CanType type); llvm::Value *emitValueWitnessTableRefForLayout(SILType type); llvm::Value *emitValueWitnessTableRefForMetadata(llvm::Value *metadata); llvm::Value *emitValueWitness(CanType type, ValueWitness index); llvm::Value *emitValueWitnessForLayout(SILType type, ValueWitness index); /// 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 &); /// 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); private: llvm::Instruction *AllocaIP; const SILDebugScope *DbgScope; //--- 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); // - unowned references void emitUnownedRetain(llvm::Value *value, ReferenceCounting style, Atomicity atomicity); void emitUnownedRelease(llvm::Value *value, ReferenceCounting style, Atomicity atomicity); void emitStrongRetainUnowned(llvm::Value *value, ReferenceCounting style, Atomicity atomicity); void emitStrongRetainAndUnownedRelease(llvm::Value *value, ReferenceCounting style, Atomicity atomicity); void emitUnownedInit(llvm::Value *val, Address dest, ReferenceCounting style); void emitUnownedAssign(llvm::Value *value, Address dest, ReferenceCounting style); void emitUnownedCopyInit(Address destAddr, Address srcAddr, ReferenceCounting style); void emitUnownedTakeInit(Address destAddr, Address srcAddr, ReferenceCounting style); void emitUnownedCopyAssign(Address destAddr, Address srcAddr, ReferenceCounting style); void emitUnownedTakeAssign(Address destAddr, Address srcAddr, ReferenceCounting style); llvm::Value *emitUnownedLoadStrong(Address src, llvm::Type *resultType, ReferenceCounting style); llvm::Value *emitUnownedTakeStrong(Address src, llvm::Type *resultType, ReferenceCounting style); void emitUnownedDestroy(Address addr, ReferenceCounting style); llvm::Value *getUnownedExtraInhabitantIndex(Address src, ReferenceCounting style); void storeUnownedExtraInhabitant(llvm::Value *index, Address dest, ReferenceCounting style); // - weak references void emitWeakInit(llvm::Value *ref, Address dest, ReferenceCounting style); void emitWeakAssign(llvm::Value *ref, Address dest, ReferenceCounting style); void emitWeakCopyInit(Address destAddr, Address srcAddr, ReferenceCounting style); void emitWeakTakeInit(Address destAddr, Address srcAddr, ReferenceCounting style); void emitWeakCopyAssign(Address destAddr, Address srcAddr, ReferenceCounting style); void emitWeakTakeAssign(Address destAddr, Address srcAddr, ReferenceCounting style); llvm::Value *emitWeakLoadStrong(Address src, llvm::Type *resultType, ReferenceCounting style); llvm::Value *emitWeakTakeStrong(Address src, llvm::Type *resultType, ReferenceCounting style); void emitWeakDestroy(Address addr, ReferenceCounting style); // 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); // - unowned references void emitNativeUnownedRetain(llvm::Value *value, Atomicity atomicity); void emitNativeUnownedRelease(llvm::Value *value, Atomicity atomicity); void emitNativeStrongRetainUnowned(llvm::Value *value, Atomicity atomicity); void emitNativeStrongRetainAndUnownedRelease(llvm::Value *value, Atomicity atomicity); void emitNativeUnownedInit(llvm::Value *val, Address dest); void emitNativeUnownedAssign(llvm::Value *value, Address dest); void emitNativeUnownedCopyInit(Address destAddr, Address srcAddr); void emitNativeUnownedTakeInit(Address destAddr, Address srcAddr); void emitNativeUnownedCopyAssign(Address destAddr, Address srcAddr); void emitNativeUnownedTakeAssign(Address destAddr, Address srcAddr); llvm::Value *emitNativeUnownedLoadStrong(Address src, llvm::Type *resultType); llvm::Value *emitNativeUnownedTakeStrong(Address src, llvm::Type *resultType); void emitNativeUnownedDestroy(Address addr); // - weak references void emitNativeWeakInit(llvm::Value *value, Address dest); void emitNativeWeakAssign(llvm::Value *value, Address dest); llvm::Value *emitNativeWeakLoadStrong(Address src, llvm::Type *type); llvm::Value *emitNativeWeakTakeStrong(Address src, llvm::Type *type); void emitNativeWeakDestroy(Address addr); void emitNativeWeakCopyInit(Address destAddr, Address srcAddr); void emitNativeWeakTakeInit(Address destAddr, Address srcAddr); void emitNativeWeakCopyAssign(Address destAddr, Address srcAddr); void emitNativeWeakTakeAssign(Address destAddr, Address srcAddr); // - other operations llvm::Value *emitNativeTryPin(llvm::Value *object, Atomicity atomicity); void emitNativeUnpin(llvm::Value *handle, Atomicity atomicity); // 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); // 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); // - unowned references void emitUnknownUnownedInit(llvm::Value *val, Address dest); void emitUnknownUnownedAssign(llvm::Value *value, Address dest); void emitUnknownUnownedCopyInit(Address destAddr, Address srcAddr); void emitUnknownUnownedTakeInit(Address destAddr, Address srcAddr); void emitUnknownUnownedCopyAssign(Address destAddr, Address srcAddr); void emitUnknownUnownedTakeAssign(Address destAddr, Address srcAddr); llvm::Value *emitUnknownUnownedLoadStrong(Address src, llvm::Type *resultTy); llvm::Value *emitUnknownUnownedTakeStrong(Address src, llvm::Type *resultTy); void emitUnknownUnownedDestroy(Address addr); // - weak references void emitUnknownWeakDestroy(Address addr); void emitUnknownWeakCopyInit(Address destAddr, Address srcAddr); void emitUnknownWeakTakeInit(Address destAddr, Address srcAddr); void emitUnknownWeakCopyAssign(Address destAddr, Address srcAddr); void emitUnknownWeakTakeAssign(Address destAddr, Address srcAddr); void emitUnknownWeakInit(llvm::Value *value, Address dest); void emitUnknownWeakAssign(llvm::Value *value, Address dest); llvm::Value *emitUnknownWeakLoadStrong(Address src, llvm::Type *type); llvm::Value *emitUnknownWeakTakeStrong(Address src, llvm::Type *type); // 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, SourceLoc loc, bool isNonNull, bool checkPinned); //--- Expression emission ------------------------------------------------------ public: void emitFakeExplosion(const TypeInfo &type, Explosion &explosion); //--- Declaration emission ----------------------------------------------------- public: void bindArchetype(ArchetypeType *type, llvm::Value *metadata, ArrayRef wtables); //--- Type emission ------------------------------------------------------------ public: /// Look up a local type data reference, returning null if no entry was /// found. This will emit code to materialize the reference if an /// "abstract" entry is present. llvm::Value *tryGetLocalTypeData(CanType type, LocalTypeDataKind kind) { return tryGetLocalTypeData(LocalTypeDataKey{type, kind}); } llvm::Value *tryGetLocalTypeData(LocalTypeDataKey key); /// Look up a local type data reference, returning null if no entry was /// found or if the only viable entries are abstract. This will never /// emit code. llvm::Value *tryGetConcreteLocalTypeData(LocalTypeDataKey key); /// Retrieve a local type data reference which is known to exist. llvm::Value *getLocalTypeData(CanType type, LocalTypeDataKind kind); /// Add a local type-metadata reference at a point which definitely /// dominates all of its uses. void setUnscopedLocalTypeData(CanType type, LocalTypeDataKind kind, llvm::Value *data) { setUnscopedLocalTypeData(LocalTypeDataKey{type, kind}, data); } void setUnscopedLocalTypeData(LocalTypeDataKey key, llvm::Value *data); /// Add a local type-metadata reference, valid at the current insertion /// point. void setScopedLocalTypeData(CanType type, LocalTypeDataKind kind, llvm::Value *data) { setScopedLocalTypeData(LocalTypeDataKey{type, kind}, data); } void setScopedLocalTypeData(LocalTypeDataKey key, llvm::Value *data); /// The same as tryGetLocalTypeData, just for the Layout metadata. /// /// We use a separate function name for this to clarify that you should /// only ever be looking type metadata for a lowered SILType for the /// purposes of local layout (e.g. of a tuple). llvm::Value *tryGetLocalTypeDataForLayout(SILType type, LocalTypeDataKind kind) { return tryGetLocalTypeData(type.getSwiftRValueType(), kind); } /// Add a local type-metadata reference, which is valid for the containing /// block. void setScopedLocalTypeDataForLayout(SILType type, LocalTypeDataKind kind, llvm::Value *data) { setScopedLocalTypeData(type.getSwiftRValueType(), kind, data); } /// 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); 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 LocalSelf is. enum LocalSelfKind { /// An object reference. ObjectReference, /// A Swift metatype. SwiftMetatype, /// An ObjC metatype. ObjCMetatype, }; llvm::Value *getLocalSelfMetadata(); void setLocalSelfMetadata(llvm::Value *value, LocalSelfKind kind); 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 dynamic Self. llvm::Value *LocalSelf = nullptr; LocalSelfKind SelfKind; }; using ConditionalDominanceScope = IRGenFunction::ConditionalDominanceScope; } // end namespace irgen } // end namespace swift #endif