//===--- SILFunction.h - Defines the SILFunction class ----------*- 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 SILFunction class.
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_SIL_SILFUNCTION_H
#define SWIFT_SIL_SILFUNCTION_H

#include "swift/AST/ASTNode.h"
#include "swift/AST/AvailabilityRange.h"
#include "swift/AST/Module.h"
#include "swift/AST/ResilienceExpansion.h"
#include "swift/Basic/ProfileCounter.h"
#include "swift/Basic/SwiftObjectHeader.h"
#include "swift/SIL/SILBasicBlock.h"
#include "swift/SIL/SILDebugScope.h"
#include "swift/SIL/SILDeclRef.h"
#include "swift/SIL/SILLinkage.h"
#include "swift/SIL/SILPrintContext.h"
#include "swift/SIL/SILUndef.h"
#include "llvm/ADT/MapVector.h"

namespace swift {

class ASTContext;
class SILInstruction;
class SILModule;
class SILFunctionBuilder;
class SILProfiler;
class BasicBlockBitfield;
class NodeBitfield;
class OperandBitfield;
class CalleeCache;
class SILUndef;

namespace Lowering {
class TypeLowering;
class AbstractionPattern;
}

enum IsBare_t { IsNotBare, IsBare };
enum IsTransparent_t { IsNotTransparent, IsTransparent };
enum Inline_t { InlineDefault, NoInline, AlwaysInline };
enum IsThunk_t {
  IsNotThunk,
  IsThunk,
  IsReabstractionThunk,
  IsSignatureOptimizedThunk,
  IsBackDeployedThunk,
};
enum IsDynamicallyReplaceable_t {
  IsNotDynamic,
  IsDynamic
};
enum IsExactSelfClass_t {
  IsNotExactSelfClass,
  IsExactSelfClass,
};
enum IsDistributed_t {
  IsNotDistributed,
  IsDistributed,
};
enum IsRuntimeAccessible_t {
  IsNotRuntimeAccessible,
  IsRuntimeAccessible
};

enum ForceEnableLexicalLifetimes_t {
  DoNotForceEnableLexicalLifetimes,
  DoForceEnableLexicalLifetimes
};

enum UseStackForPackMetadata_t {
  DoNotUseStackForPackMetadata,
  DoUseStackForPackMetadata,
};

enum class PerformanceConstraints : uint8_t {
  None = 0,
  NoAllocation = 1,
  NoLocks = 2,
  NoRuntime = 3,
  NoExistentials = 4,
  NoObjCBridging = 5
};

class SILSpecializeAttr final {
  friend SILFunction;
public:
  enum class SpecializationKind {
    Full,
    Partial
  };

  static GenericSignature buildTypeErasedSignature(
      GenericSignature sig, ArrayRef<Type> typeErasedParams);

  static SILSpecializeAttr *
  create(SILModule &M, GenericSignature specializedSignature,
         ArrayRef<Type> typeErasedParams, bool exported,
         SpecializationKind kind, SILFunction *target, Identifier spiGroup,
         const ModuleDecl *spiModule, AvailabilityRange availability);

  bool isExported() const {
    return exported;
  }

  bool isFullSpecialization() const {
    return kind == SpecializationKind::Full;
  }

  bool isPartialSpecialization() const {
    return kind == SpecializationKind::Partial;
  }

  SpecializationKind getSpecializationKind() const {
    return kind;
  }

  GenericSignature getSpecializedSignature() const {
    return specializedSignature;
  }

  GenericSignature getUnerasedSpecializedSignature() const {
    return unerasedSpecializedSignature;
  }

  ArrayRef<Type> getTypeErasedParams() const {
    return typeErasedParams;
  }

  SILFunction *getFunction() const {
    return F;
  }

  SILFunction *getTargetFunction() const {
    return targetFunction;
  }

  Identifier getSPIGroup() const {
    return spiGroup;
  }

  const ModuleDecl *getSPIModule() const {
    return spiModule;
  }

  AvailabilityRange getAvailability() const {
    return availability;
  }

  void print(llvm::raw_ostream &OS) const;

private:
  SpecializationKind kind;
  bool exported;
  GenericSignature specializedSignature;
  GenericSignature unerasedSpecializedSignature;
  llvm::SmallVector<Type, 2> typeErasedParams;
  Identifier spiGroup;
  AvailabilityRange availability;
  const ModuleDecl *spiModule = nullptr;
  SILFunction *F = nullptr;
  SILFunction *targetFunction = nullptr;

  SILSpecializeAttr(bool exported, SpecializationKind kind,
                    GenericSignature specializedSignature,
                    GenericSignature unerasedSpecializedSignature,
                    ArrayRef<Type> typeErasedParams,
                    SILFunction *target, Identifier spiGroup,
                    const ModuleDecl *spiModule,
                    AvailabilityRange availability);
};

/// SILFunction - A function body that has been lowered to SIL. This consists of
/// zero or more SIL SILBasicBlock objects that contain the SILInstruction
/// objects making up the function.
class SILFunction
  : public llvm::ilist_node<SILFunction>, public SILAllocated<SILFunction>,
    public SwiftObjectHeader {
    
private:
  void *libswiftSpecificData[4];

public:
  using BlockListType = llvm::iplist<SILBasicBlock>;

  // For more information see docs/SIL.rst
  enum class Purpose : uint8_t {
    None,
    GlobalInit,
    GlobalInitOnceFunction,
    LazyPropertyGetter
  };

private:
  friend class SILBasicBlock;
  friend class SILModule;
  friend class SILFunctionBuilder;
  template <typename, unsigned> friend class BasicBlockData;
  template <class, class> friend class SILBitfield;
  friend class BasicBlockBitfield;
  friend class NodeBitfield;
  friend class OperandBitfield;
  friend SILUndef;

  /// Module - The SIL module that the function belongs to.
  SILModule &Module;

  /// The mangled name of the SIL function, which will be propagated
  /// to the binary.  A pointer into the module's lookup table.
  StringRef Name;

  /// A single-linked list of snapshots of the function.
  ///
  /// Snapshots are copies of the current function at a given point in time.
  SILFunction *snapshots = nullptr;
  
  /// The snapshot ID of this function.
  ///
  /// 0 means, it's not a snapshot, but the original function.
  int snapshotID = 0;

  /// The lowered type of the function.
  CanSILFunctionType LoweredType;

  /// The context archetypes of the function.
  GenericEnvironment *GenericEnv = nullptr;

  /// Captured local generic environments.
  ArrayRef<GenericEnvironment *> CapturedEnvs;

  /// The information about specialization.
  /// Only set if this function is a specialization of another function.
  const GenericSpecializationInformation *SpecializationInfo = nullptr;

  /// The forwarding substitution map, lazily computed.
  SubstitutionMap ForwardingSubMap;

  /// The collection of all BasicBlocks in the SILFunction. Empty for external
  /// function references.
  BlockListType BlockList;

  /// The owning declaration of this function's clang node, if applicable.
  ValueDecl *ClangNodeOwner = nullptr;

  /// The source location and scope of the function.
  const SILDebugScope *DebugScope = nullptr;

  /// The AST decl context of the function.
  DeclContext *DeclCtxt = nullptr;

  /// The module that defines this function. This member should only be set as
  /// a fallback when a \c DeclCtxt is unavailable.
  ModuleDecl *ParentModule = nullptr;

  /// The profiler for instrumentation based profiling, or null if profiling is
  /// disabled.
  SILProfiler *Profiler = nullptr;

  /// The function this function is meant to replace. Null if this is not a
  /// @_dynamicReplacement(for:) function.
  SILFunction *ReplacedFunction = nullptr;

  /// The SILDeclRef that this function was created for by SILGen if one exists.
  SILDeclRef DeclRef = SILDeclRef();

  /// This SILFunction REFerences an ad-hoc protocol requirement witness in
  /// order to keep it alive, such that it main be obtained in IRGen. Without
  /// this explicit reference, the witness would seem not-used, and not be
  /// accessible for IRGen.
  ///
  /// Specifically, one such case is the DistributedTargetInvocationDecoder's
  /// 'decodeNextArgument' which must be retained, as it is only used from IRGen
  /// and such, appears as-if unused in SIL and would get optimized away.
  // TODO: Consider making this a general "references adhoc functions" and make it an array?
  SILFunction *RefAdHocRequirementFunction = nullptr;

  Identifier ObjCReplacementFor;

  /// The head of a single-linked list of currently alive BasicBlockBitfield.
  BasicBlockBitfield *newestAliveBlockBitfield = nullptr;

  /// The head of a single-linked list of currently alive NodeBitfield.
  NodeBitfield *newestAliveNodeBitfield = nullptr;

  /// The head of a single-linked list of currently alive OperandBitfields.
  OperandBitfield *newestAliveOperandBitfield = nullptr;

  /// A monotonically increasing ID which is incremented whenever a
  /// BasicBlockBitfield, NodeBitfield, or OperandBitfield is constructed.  For
  /// details see SILBitfield::bitfieldID;
  uint64_t currentBitfieldID = 1;

  /// Unique identifier for vector indexing and deterministic sorting.
  /// May be reused when zombie functions are recovered.
  unsigned index;

  /// The function's set of semantics attributes.
  ///
  /// TODO: Why is this using a std::string? Why don't we use uniqued
  /// StringRefs?
  std::vector<std::string> SemanticsAttrSet;

  /// The function's remaining set of specialize attributes.
  std::vector<SILSpecializeAttr*> SpecializeAttrSet;

  /// Name of a section if @_section attribute was used, otherwise empty.
  StringRef Section;

  /// Name of a Wasm export if @_expose(wasm) attribute was used, otherwise
  /// empty.
  StringRef WasmExportName;

  /// Name of a Wasm import module and field if @_extern(wasm) attribute
  std::optional<std::pair<StringRef, StringRef>> WasmImportModuleAndField;

  /// Has value if there's a profile for this function
  /// Contains Function Entry Count
  ProfileCounter EntryCount;

  /// The availability used to determine if declarations of this function
  /// should use weak linking.
  AvailabilityRange Availability;

  Purpose specialPurpose = Purpose::None;

  PerformanceConstraints perfConstraints = PerformanceConstraints::None;

  /// The undefs of each type in the function.
  llvm::SmallMapVector<SILType, SILUndef *, 1> undefValues;

  /// This is the number of uses of this SILFunction inside the SIL.
  /// It does not include references from debug scopes.
  unsigned RefCount = 0;

  /// Used to verify if a BasicBlockData is not valid anymore.
  /// This counter is incremented every time a BasicBlockData re-assigns new
  /// block indices.
  unsigned BlockListChangeIdx = 0;

  /// The isolation of this function.
  std::optional<ActorIsolation> actorIsolation;

  /// The function's bare attribute. Bare means that the function is SIL-only
  /// and does not require debug info.
  unsigned Bare : 1;

  /// The function's transparent attribute.
  unsigned Transparent : 1;

  /// The function's serialized attribute.
  unsigned SerializedKind : 2;

  /// Specifies if this function is a thunk or a reabstraction thunk.
  ///
  /// The inliner uses this information to avoid inlining (non-trivial)
  /// functions into the thunk.
  unsigned Thunk : 3;

  /// The scope in which the parent class can be subclassed, if this is a method
  /// which is contained in the vtable of that class.
  unsigned ClassSubclassScope : 2;

  /// The function's global_init attribute.
  unsigned GlobalInitFlag : 1;

  /// The function's noinline attribute.
  unsigned InlineStrategy : 2;

  /// The linkage of the function.
  unsigned Linkage : NumSILLinkageBits;

  /// Set if the function may be referenced from C code and should thus be
  /// preserved and exported more widely than its Swift linkage and usage
  /// would indicate.
  unsigned HasCReferences : 1;

  /// Whether attribute @_used was present
  unsigned MarkedAsUsed : 1;

  /// Whether cross-module references to this function should always use weak
  /// linking.
  unsigned IsAlwaysWeakImported : 1;

  /// Whether the implementation can be dynamically replaced.
  unsigned IsDynamicReplaceable : 1;

  /// If true, this indicates that a class method implementation will always be
  /// invoked with a `self` argument of the exact base class type.
  unsigned ExactSelfClass : 1;

  /// Check whether this is a distributed method.
  unsigned IsDistributed : 1;

  /// Check whether this function could be looked up at runtime via special API.
  unsigned IsRuntimeAccessible : 1;

  unsigned stackProtection : 1;

  /// True if this function is inlined at least once. This means that the
  /// debug info keeps a pointer to this function.
  unsigned Inlined : 1;

  /// True if this function is a zombie function. This means that the function
  /// is dead and not referenced from anywhere inside the SIL. But it is kept
  /// for other purposes:
  /// *) It is inlined and the debug info keeps a reference to the function.
  /// *) It is a dead method of a class which has higher visibility than the
  ///    method itself. In this case we need to create a vtable stub for it.
  /// *) It is a function referenced by the specialization information.
  unsigned Zombie : 1;

  /// True if this function is in Ownership SSA form and thus must pass
  /// ownership verification.
  ///
  /// This enables the verifier to easily prove that before the Ownership Model
  /// Eliminator runs on a function, we only see a non-semantic-arc world and
  /// after the pass runs, we only see a semantic-arc world.
  unsigned HasOwnership : 1;

  /// Set if the function body was deserialized from canonical SIL. This implies
  /// that the function's home module performed SIL diagnostics prior to
  /// serialization.
  unsigned WasDeserializedCanonical : 1;

  /// True if this is a reabstraction thunk of escaping function type whose
  /// single argument is a potentially non-escaping closure. This is an escape
  /// hatch to allow non-escaping functions to be stored or passed as an
  /// argument with escaping function type. The thunk argument's function type
  /// is not necessarily @noescape. The only relevant aspect of the argument is
  /// that it may have unboxed capture (i.e. @inout_aliasable parameters).
  unsigned IsWithoutActuallyEscapingThunk : 1;

  /// If != OptimizationMode::NotSet, the optimization mode specified with an
  /// function attribute.
  unsigned OptMode : NumOptimizationModeBits;

  /// The function's effects attribute.
  unsigned EffectsKindAttr : NumEffectsKindBits;

  /// If true, the function has lexical lifetimes even if the module does not.
  unsigned ForceEnableLexicalLifetimes : 1;

  /// If true, the function contains an instruction that prevents stack nesting
  /// from running with pack metadata markers in place.
  unsigned UseStackForPackMetadata : 1;

  /// If true, the function returns a non-escapable value without any
  /// lifetime-dependence on an argument.
  unsigned HasUnsafeNonEscapableResult : 1;

  /// True, if this function or a caller (transitively) has a performance
  /// constraint.
  /// If true, optimizations must not introduce new runtime calls or metadata
  /// creation, which are not there after SILGen.
  /// Note that this flag is not serialized, because it's computed locally
  /// within a module by the MandatoryOptimizations pass.
  unsigned IsPerformanceConstraint : 1;

  static void
  validateSubclassScope(SubclassScope scope, IsThunk_t isThunk,
                        const GenericSpecializationInformation *genericInfo) {
#ifndef NDEBUG
    // The _original_ function for a method can turn into a thunk through
    // signature optimization, meaning it needs to retain its subclassScope, but
    // other thunks and specializations are implementation details and so
    // shouldn't be connected to their parent class.
    bool thunkCanHaveSubclassScope;
    switch (isThunk) {
    case IsNotThunk:
    case IsSignatureOptimizedThunk:
      thunkCanHaveSubclassScope = true;
      break;
    case IsThunk:
    case IsReabstractionThunk:
    case IsBackDeployedThunk:
      thunkCanHaveSubclassScope = false;
      break;
    }
    auto allowsInterestingScopes = thunkCanHaveSubclassScope && !genericInfo;
    assert(
        allowsInterestingScopes ||
        scope == SubclassScope::NotApplicable &&
            "SubclassScope on specialization or non-signature-optimized thunk");
#endif
  }

  SILFunction(SILModule &module, SILLinkage linkage, StringRef mangledName,
              CanSILFunctionType loweredType, GenericEnvironment *genericEnv,
              IsBare_t isBareSILFunction, IsTransparent_t isTrans,
              SerializedKind_t serializedKind, ProfileCounter entryCount,
              IsThunk_t isThunk, SubclassScope classSubclassScope,
              Inline_t inlineStrategy, EffectsKind E,
              const SILDebugScope *debugScope,
              IsDynamicallyReplaceable_t isDynamic,
              IsExactSelfClass_t isExactSelfClass,
              IsDistributed_t isDistributed,
              IsRuntimeAccessible_t isRuntimeAccessible);

  static SILFunction *
  create(SILModule &M, SILLinkage linkage, StringRef name,
         CanSILFunctionType loweredType, GenericEnvironment *genericEnv,
         std::optional<SILLocation> loc, IsBare_t isBareSILFunction,
         IsTransparent_t isTrans, SerializedKind_t serializedKind,
         ProfileCounter entryCount, IsDynamicallyReplaceable_t isDynamic,
         IsDistributed_t isDistributed,
         IsRuntimeAccessible_t isRuntimeAccessible,
         IsExactSelfClass_t isExactSelfClass, IsThunk_t isThunk = IsNotThunk,
         SubclassScope classSubclassScope = SubclassScope::NotApplicable,
         Inline_t inlineStrategy = InlineDefault,
         EffectsKind EffectsKindAttr = EffectsKind::Unspecified,
         SILFunction *InsertBefore = nullptr,
         const SILDebugScope *DebugScope = nullptr);

  void init(SILLinkage Linkage, StringRef Name, CanSILFunctionType LoweredType,
            GenericEnvironment *genericEnv, IsBare_t isBareSILFunction,
            IsTransparent_t isTrans, SerializedKind_t serializedKind,
            ProfileCounter entryCount, IsThunk_t isThunk,
            SubclassScope classSubclassScope, Inline_t inlineStrategy,
            EffectsKind E, const SILDebugScope *DebugScope,
            IsDynamicallyReplaceable_t isDynamic,
            IsExactSelfClass_t isExactSelfClass, IsDistributed_t isDistributed,
            IsRuntimeAccessible_t isRuntimeAccessible);

  /// Set has ownership to the given value. True means that the function has
  /// ownership, false means it does not.
  ///
  /// Only for use by FunctionBuilders!
  void setHasOwnership(bool newValue) { HasOwnership = newValue; }

  void setName(StringRef name) {
    // All the snapshots share the same name.
    SILFunction *sn = this;
    do {
      sn->Name = name;
    } while ((sn = sn->snapshots) != nullptr);
  }

public:
  ~SILFunction();

  SILModule &getModule() const { return Module; }

  /// Creates a snapshot with a given `ID` from the current function.
  void createSnapshot(int ID);
  
  /// Returns the snapshot with the given `ID` or null if no such snapshot exists.
  SILFunction *getSnapshot(int ID);
  
  /// Restores the current function from a given snapshot.
  void restoreFromSnapshot(int ID);
  
  /// Deletes a snapshot with the `ID`.
  void deleteSnapshot(int ID);

  SILType getLoweredType() const {
    return SILType::getPrimitiveObjectType(LoweredType);
  }
  CanSILFunctionType getLoweredFunctionType() const {
    return LoweredType;
  }
  CanSILFunctionType
  getLoweredFunctionTypeInContext(TypeExpansionContext context) const;

  SILType getLoweredTypeInContext(TypeExpansionContext context) const {
    return SILType::getPrimitiveObjectType(
        getLoweredFunctionTypeInContext(context));
  }

  SILFunctionConventions getConventions() const {
    return SILFunctionConventions(LoweredType, getModule());
  }

  SILFunctionConventions getConventionsInContext() const {
    auto fnType = getLoweredFunctionTypeInContext(getTypeExpansionContext());
    return SILFunctionConventions(fnType, getModule());
  }

  unsigned getIndex() const { return index; }

  SILProfiler *getProfiler() const { return Profiler; }

  SILFunction *getDynamicallyReplacedFunction() const {
    return ReplacedFunction;
  }

  void setDynamicallyReplacedFunction(SILFunction *f) {
    assert(ReplacedFunction == nullptr && "already set");
    assert(!hasObjCReplacement());

    if (f == nullptr)
      return;
    ReplacedFunction = f;
    ReplacedFunction->incrementRefCount();
  }
  /// This function should only be called when SILFunctions are bulk deleted.
  void dropDynamicallyReplacedFunction() {
    if (!ReplacedFunction)
      return;
    ReplacedFunction->decrementRefCount();
    ReplacedFunction = nullptr;
  }

  SILFunction *getReferencedAdHocRequirementWitnessFunction() const {
    return RefAdHocRequirementFunction;
  }
  // Marks that this `SILFunction` uses the passed in ad-hoc protocol
  // requirement witness `f` and therefore must retain it explicitly,
  // otherwise we might not be able to get a reference to it.
  void setReferencedAdHocRequirementWitnessFunction(SILFunction *f) {
    assert(RefAdHocRequirementFunction == nullptr && "already set");

    if (f == nullptr)
      return;
    RefAdHocRequirementFunction = f;
    RefAdHocRequirementFunction->incrementRefCount();
  }
  void dropReferencedAdHocRequirementWitnessFunction() {
    if (!RefAdHocRequirementFunction)
      return;
    RefAdHocRequirementFunction->decrementRefCount();
    RefAdHocRequirementFunction = nullptr;
  }

  bool hasObjCReplacement() const {
    return !ObjCReplacementFor.empty();
  }

  Identifier getObjCReplacement() const {
    return ObjCReplacementFor;
  }

  void setObjCReplacement(AbstractFunctionDecl *replacedDecl);
  void setObjCReplacement(Identifier replacedDecl);

  void setProfiler(SILProfiler *InheritedProfiler) {
    assert(!Profiler && "Function already has a profiler");
    Profiler = InheritedProfiler;
  }

  void createProfiler(SILDeclRef Ref);

  ProfileCounter getEntryCount() const { return EntryCount; }

  void setEntryCount(ProfileCounter Count) { EntryCount = Count; }

  bool isNoReturnFunction(TypeExpansionContext context) const;

  /// Unsafely rewrite the lowered type of this function.
  ///
  /// This routine does not touch the entry block arguments
  /// or return instructions; you need to do that yourself
  /// if you care.
  ///
  /// This routine does not update all the references in the module
  /// You have to do that yourself
  void rewriteLoweredTypeUnsafe(CanSILFunctionType newType) {
    LoweredType = newType;
  }

  /// Return the number of entities referring to this function (other
  /// than the SILModule).
  unsigned getRefCount() const { return RefCount; }

  /// Increment the reference count.
  void incrementRefCount() {
    RefCount++;
    assert(RefCount != 0 && "Overflow of reference count!");
  }

  /// Decrement the reference count.
  void decrementRefCount() {
    assert(RefCount != 0 && "Expected non-zero reference count on decrement!");
    RefCount--;
  }

  /// Drops all uses belonging to instructions in this function. The only valid
  /// operation performable on this object after this is called is called the
  /// destructor or deallocation.
  void dropAllReferences() {
    for (SILBasicBlock &BB : *this)
      BB.dropAllReferences();
  }

  /// Notify that this function was inlined. This implies that it is still
  /// needed for debug info generation, even if it is removed afterwards.
  void setInlined() {
    assert(!isZombie() && "Can't inline a zombie function");
    Inlined = true;
  }

  /// Returns true if this function was inlined.
  bool isInlined() const { return Inlined; }

  /// Mark this function as removed from the module's function list, but kept
  /// as "zombie" for debug info or vtable stub generation.
  void setZombie() {
    assert(!isZombie() && "Function is a zombie function already");
    Zombie = true;
  }

  /// Returns true if this function is dead, but kept in the module's zombie list.
  bool isZombie() const { return Zombie; }

  /// Returns true if this function has qualified ownership instructions in it.
  bool hasOwnership() const { return HasOwnership; }

  /// Sets the HasOwnership flag to false. This signals to SIL that no
  /// ownership instructions should be in this function any more.
  void setOwnershipEliminated() { setHasOwnership(false); }

  /// Returns true if this function was deserialized from canonical
  /// SIL. (.swiftmodule files contain canonical SIL; .sib files may be 'raw'
  /// SIL). If so, diagnostics should not be reapplied.
  bool wasDeserializedCanonical() const { return WasDeserializedCanonical; }

  void setWasDeserializedCanonical(bool val = true) {
    WasDeserializedCanonical = val;
  }

  ForceEnableLexicalLifetimes_t forceEnableLexicalLifetimes() const {
    return ForceEnableLexicalLifetimes_t(ForceEnableLexicalLifetimes);
  }

  void setForceEnableLexicalLifetimes(ForceEnableLexicalLifetimes_t value) {
    ForceEnableLexicalLifetimes = value;
  }

  UseStackForPackMetadata_t useStackForPackMetadata() const {
    return UseStackForPackMetadata_t(UseStackForPackMetadata);
  }

  void setUseStackForPackMetadata(UseStackForPackMetadata_t value) {
    UseStackForPackMetadata = value;
  }

  bool hasUnsafeNonEscapableResult() const {
    return HasUnsafeNonEscapableResult;
  }

  void setHasUnsafeNonEscapableResult(bool value) {
    HasUnsafeNonEscapableResult = value;
  }

  /// Returns true if this is a reabstraction thunk of escaping function type
  /// whose single argument is a potentially non-escaping closure. i.e. the
  /// thunks' function argument may itself have @inout_aliasable parameters.
  bool isWithoutActuallyEscapingThunk() const {
    return IsWithoutActuallyEscapingThunk;
  }

  void setWithoutActuallyEscapingThunk(bool val = true) {
    assert(!val || isThunk() == IsReabstractionThunk);
    IsWithoutActuallyEscapingThunk = val;
  }

  bool isAsync() const { return LoweredType->isAsync(); }

  /// Returns the calling convention used by this entry point.
  SILFunctionTypeRepresentation getRepresentation() const {
    return getLoweredFunctionType()->getRepresentation();
  }

  ResilienceExpansion getResilienceExpansion() const;

  // Returns the type expansion context to be used inside this function.
  TypeExpansionContext getTypeExpansionContext() const {
    return TypeExpansionContext(*this);
  }

  const Lowering::TypeLowering &
  getTypeLowering(Lowering::AbstractionPattern orig, Type subst);

  const Lowering::TypeLowering &getTypeLowering(Type t) const;

  SILType getLoweredType(Lowering::AbstractionPattern orig, Type subst) const;

  SILType getLoweredType(Type t) const;

  CanType getLoweredRValueType(Lowering::AbstractionPattern orig, Type subst) const;

  CanType getLoweredRValueType(Type t) const;

  SILType getLoweredLoadableType(Type t) const;

  SILType getLoweredType(SILType t) const;

  const Lowering::TypeLowering &getTypeLowering(SILType type) const;

  bool isTypeABIAccessible(SILType type) const;

  /// Returns true if this function has a calling convention that has a self
  /// argument.
  bool hasSelfParam() const {
    return getLoweredFunctionType()->hasSelfParam();
  }

  /// Returns true if the function has parameters that are consumed by the
  // callee.
  bool hasOwnedParameters() const {
    for (auto &ParamInfo : getLoweredFunctionType()->getParameters()) {
      if (ParamInfo.isConsumedInCallee())
        return true;
    }
    return false;
  }

  // Returns true if the function has indirect out parameters.
  bool hasIndirectFormalResults() const {
    return getLoweredFunctionType()->hasIndirectFormalResults();
  }

  // Returns true if the function has any generic arguments.
  bool isGeneric() const {
    auto s = getLoweredFunctionType()->getInvocationGenericSignature();
    return s && !s->areAllParamsConcrete();
  }

  /// Returns true if this function ie either a class method, or a
  /// closure that captures the 'self' value or its metatype.
  ///
  /// If this returns true, DynamicSelfType can be used in the body
  /// of the function.
  ///
  /// Note that this is not the same as hasSelfParam().
  ///
  /// For closures that capture DynamicSelfType, hasDynamicSelfMetadata()
  /// is true and hasSelfParam() is false. For methods on value types,
  /// hasSelfParam() is true and hasDynamicSelfMetadata() is false.
  bool hasDynamicSelfMetadata() const;

  /// Return the mangled name of this SILFunction.
  StringRef getName() const { return Name; }

  /// A convenience function which checks if the function has a specific
  /// \p name. It is equivalent to getName() == Name, but as it is not
  /// inlined it can be called from the debugger.
  bool hasName(const char *Name) const;

  /// True if this is a declaration of a function defined in another module.
  bool isExternalDeclaration() const { return BlockList.empty(); }

  /// Returns true if this is a definition of a function defined in this module.
  bool isDefinition() const { return !isExternalDeclaration(); }

  /// Returns true if there exist pre-specializations.
  bool hasPrespecialization() const;

  /// Get this function's linkage attribute.
  SILLinkage getLinkage() const { return SILLinkage(Linkage); }

  /// Set the function's linkage attribute.
  void setLinkage(SILLinkage linkage) { Linkage = unsigned(linkage); }

///   Checks if this (callee) function body can be inlined into the caller
///   by comparing their `SerializedKind_t` values.
///
///   If both callee and caller are `not_serialized`, the callee can be inlined
///   into the caller during SIL inlining passes even if it (and the caller)
///   might contain private symbols. If this callee is `serialized_for_pkg`,
///   it can only be referenced by a serialized caller but not inlined into
///   it.
///
///  ```
///   canInlineInto:                                 Caller
///                              | not_serialized | serialized_for_pkg | serialized
///          not_serialized      |      ok        |       no           |    no
///  Callee  serialized_for_pkg  |      ok        |       ok           |    no
///          serialized          |      ok        |       ok           |    ok
///
///  ```
///
/// \p callerSerializedKind The caller's SerializedKind.
  bool canBeInlinedIntoCaller(SerializedKind_t callerSerializedKind) const;

  /// Returns true if this function can be referenced from a fragile function
  /// body.
  /// \p callerSerializedKind The caller's SerializedKind. Used to be passed to
  ///                         \c canBeInlinedIntoCaller.
  bool hasValidLinkageForFragileRef(SerializedKind_t callerSerializedKind) const;

  /// Get's the effective linkage which is used to derive the llvm linkage.
  /// Usually this is the same as getLinkage(), except in one case: if this
  /// function is a method in a class which has higher visibility than the
  /// method itself, the function can be referenced from vtables of derived
  /// classes in other compilation units.
  SILLinkage getEffectiveSymbolLinkage() const {
    return effectiveLinkageForClassMember(getLinkage(),
                                          getClassSubclassScope());
  }
    
  /// Helper method which returns true if this function has "external" linkage.
  bool isAvailableExternally() const {
    return swift::isAvailableExternally(getLinkage());
  }

  /// Helper method which returns true if the linkage of the SILFunction
  /// indicates that the object's definition might be required outside the
  /// current SILModule.
  bool isPossiblyUsedExternally() const;

  /// Helper method which returns whether this function should be preserved so
  /// it can potentially be used in the debugger.
  bool shouldBePreservedForDebugger() const;

  /// In addition to isPossiblyUsedExternally() it returns also true if this
  /// is a (private or internal) vtable method which can be referenced by
  /// vtables of derived classes outside the compilation unit.
  bool isExternallyUsedSymbol() const;

  /// Return whether this function may be referenced by C code.
  bool hasCReferences() const { return HasCReferences; }
  void setHasCReferences(bool value) { HasCReferences = value; }

  /// Returns the availability context used to determine if the function's
  /// symbol should be weakly referenced across module boundaries.
  AvailabilityRange getAvailabilityForLinkage() const {
    return Availability;
  }

  void setAvailabilityForLinkage(AvailabilityRange availability) {
    Availability = availability;
  }

  /// Returns whether this function's symbol must always be weakly referenced
  /// across module boundaries.
  bool isAlwaysWeakImported() const { return IsAlwaysWeakImported; }

  void setIsAlwaysWeakImported(bool value) { IsAlwaysWeakImported = value; }

  bool isWeakImported(ModuleDecl *module) const;

  /// Returns whether this function implementation can be dynamically replaced.
  IsDynamicallyReplaceable_t isDynamicallyReplaceable() const {
    return IsDynamicallyReplaceable_t(IsDynamicReplaceable);
  }
  void setIsDynamic(IsDynamicallyReplaceable_t value = IsDynamic) {
    IsDynamicReplaceable = value;
    assert(!Transparent || !IsDynamicReplaceable);
  }

  IsExactSelfClass_t isExactSelfClass() const {
    return IsExactSelfClass_t(ExactSelfClass);
  }
  void setIsExactSelfClass(IsExactSelfClass_t t) {
    ExactSelfClass = t;
  }

  IsDistributed_t isDistributed() const {
    return IsDistributed_t(IsDistributed);
  }
  void
  setIsDistributed(IsDistributed_t value = IsDistributed_t::IsDistributed) {
    IsDistributed = value;
  }

  IsRuntimeAccessible_t isRuntimeAccessible() const {
    return IsRuntimeAccessible_t(IsRuntimeAccessible);
  }
  void setIsRuntimeAccessible(IsRuntimeAccessible_t value =
                                  IsRuntimeAccessible_t::IsRuntimeAccessible) {
    IsRuntimeAccessible = value;
  }

  bool needsStackProtection() const { return stackProtection; }
  void setNeedStackProtection(bool needSP) { stackProtection = needSP; }

  /// Get the DeclContext of this function.
  DeclContext *getDeclContext() const { return DeclCtxt; }

  /// \returns True if the function is marked with the @_semantics attribute
  /// and has special semantics that the optimizer can use to optimize the
  /// function.
  bool hasSemanticsAttrs() const { return !SemanticsAttrSet.empty(); }

  /// \returns True if the function has a semantic attribute that starts with a
  /// specific string.
  ///
  /// TODO: This needs a better name.
  bool hasSemanticsAttrThatStartsWith(StringRef S) {
    return count_if(getSemanticsAttrs(), [&S](const std::string &Attr) -> bool {
      return StringRef(Attr).starts_with(S);
    });
  }

  /// \returns the semantics tag that describes this function.
  ArrayRef<std::string> getSemanticsAttrs() const { return SemanticsAttrSet; }

  /// \returns True if the function has the semantics flag \p Value;
  bool hasSemanticsAttr(StringRef Value) const {
    return count(SemanticsAttrSet, Value);
  }

  /// Add the given semantics attribute to the attr list set.
  void addSemanticsAttr(StringRef Ref) {
    if (hasSemanticsAttr(Ref))
      return;
    SemanticsAttrSet.push_back(Ref.str());
    std::sort(SemanticsAttrSet.begin(), SemanticsAttrSet.end());
  }

  /// Remove the semantics
  void removeSemanticsAttr(StringRef Ref) {
    auto Iter =
        std::remove(SemanticsAttrSet.begin(), SemanticsAttrSet.end(), Ref);
    SemanticsAttrSet.erase(Iter);
  }

  /// \returns the range of specialize attributes.
  ArrayRef<SILSpecializeAttr*> getSpecializeAttrs() const {
    return SpecializeAttrSet;
  }

  /// Removes all specialize attributes from this function.
  void clearSpecializeAttrs() {
    forEachSpecializeAttrTargetFunction(
        [](SILFunction *targetFun) { targetFun->decrementRefCount(); });
    SpecializeAttrSet.clear();
  }

  void addSpecializeAttr(SILSpecializeAttr *Attr);

  void removeSpecializeAttr(SILSpecializeAttr *attr);

  void forEachSpecializeAttrTargetFunction(
      llvm::function_ref<void(SILFunction *)> action);

  /// Get this function's optimization mode or OptimizationMode::NotSet if it is
  /// not set for this specific function.
  OptimizationMode getOptimizationMode() const {
    return OptimizationMode(OptMode);
  }

  /// Returns the optimization mode for the function. If no mode is set for the
  /// function, returns the global mode, i.e. the mode of the module's options.
  OptimizationMode getEffectiveOptimizationMode() const;

  void setOptimizationMode(OptimizationMode mode) {
    OptMode = unsigned(mode);
  }

  /// True if debug information must be preserved (-Onone).
  ///
  /// If this is false (-O), then the presence of debug info must not affect the
  /// outcome of any transformations.
  ///
  /// Typically used to determine whether a debug_value is a normal SSA use or
  /// incidental use.
  bool preserveDebugInfo() const;

  PerformanceConstraints getPerfConstraints() const { return perfConstraints; }

  void setPerfConstraints(PerformanceConstraints perfConstr) {
    perfConstraints = perfConstr;
  }

  // see `IsPerformanceConstraint`
  bool isPerformanceConstraint() const { return IsPerformanceConstraint; }

  void setIsPerformanceConstraint(bool flag = true) {
    IsPerformanceConstraint = flag;
  }

  /// \returns True if the function is optimizable (i.e. not marked as no-opt),
  ///          or is raw SIL (so that the mandatory passes still run).
  bool shouldOptimize() const;

  /// Returns true if this function should be optimized for size.
  bool optimizeForSize() const {
    return getEffectiveOptimizationMode() == OptimizationMode::ForSize;
  }

  /// Returns true if this is a function that should have its ownership
  /// verified.
  bool shouldVerifyOwnership() const;

  /// Check if the function has a location.
  /// FIXME: All functions should have locations, so this method should not be
  /// necessary.
  bool hasLocation() const {
    return DebugScope && !DebugScope->Loc.isNull();
  }

  /// Get the source location of the function.
  SILLocation getLocation() const {
    if (!DebugScope) {
      return SILLocation::invalid();
    }
    return getDebugScope()->Loc;
  }

  /// Initialize the debug scope of the function and also set the DeclCtxt.
  void setDebugScope(const SILDebugScope *DS) {
    DebugScope = DS;
    DeclCtxt = (DS ? DebugScope->Loc.getAsDeclContext() : nullptr);
  }

  /// Returns the module that defines this function.
  ModuleDecl *getParentModule() const {
    return DeclCtxt ? DeclCtxt->getParentModule() : ParentModule;
  }

  /// Sets \c ParentModule as fallback if \c DeclCtxt is not available to
  /// provide the parent module.
  void setParentModule(ModuleDecl *module) {
    assert(!DeclCtxt && "already have a DeclCtxt");
    ParentModule = module;
  }

  /// Initialize the debug scope for debug info on SIL level
  /// (-sil-based-debuginfo).
  void setSILDebugScope(const SILDebugScope *DS) {
    DebugScope = DS;
  }

  /// Get the source location of the function.
  const SILDebugScope *getDebugScope() const { return DebugScope; }

  /// Return the SILDeclRef for this SILFunction if one was assigned by SILGen.
  SILDeclRef getDeclRef() const { return DeclRef; }

  /// Set the SILDeclRef for this SILFunction. Used mainly by SILGen.
  void setDeclRef(SILDeclRef declRef) { DeclRef = declRef; }

  /// Get this function's bare attribute.
  IsBare_t isBare() const { return IsBare_t(Bare); }
  void setBare(IsBare_t isB) { Bare = isB; }

  /// Get this function's transparent attribute.
  IsTransparent_t isTransparent() const { return IsTransparent_t(Transparent); }
  void setTransparent(IsTransparent_t isT) {
    Transparent = isT;
    assert(!Transparent || !IsDynamicReplaceable);
  }

  bool isSerialized() const {
    return SerializedKind_t(SerializedKind) == IsSerialized;
  }
  bool isAnySerialized() const {
    return SerializedKind_t(SerializedKind) == IsSerialized ||
           SerializedKind_t(SerializedKind) == IsSerializedForPackage;
  }

  /// Get this function's serialized attribute.
  SerializedKind_t getSerializedKind() const {
    return SerializedKind_t(SerializedKind);
  }
  void setSerializedKind(SerializedKind_t serializedKind) {
    SerializedKind = serializedKind;
    assert(this->getSerializedKind() == serializedKind &&
           "too few bits for Serialized storage");
  }

  /// Get this function's thunk attribute.
  IsThunk_t isThunk() const { return IsThunk_t(Thunk); }
  void setThunk(IsThunk_t isThunk) {
    validateSubclassScope(getClassSubclassScope(), isThunk, SpecializationInfo);
    Thunk = isThunk;
  }

  /// Get the class visibility (relevant for class methods).
  SubclassScope getClassSubclassScope() const {
    return SubclassScope(ClassSubclassScope);
  }
  void setClassSubclassScope(SubclassScope scope) {
    validateSubclassScope(scope, isThunk(), SpecializationInfo);
    ClassSubclassScope = static_cast<unsigned>(scope);
  }

  /// Get this function's noinline attribute.
  Inline_t getInlineStrategy() const { return Inline_t(InlineStrategy); }
  void setInlineStrategy(Inline_t inStr) { InlineStrategy = inStr; }

  /// \return the function side effects information.
  EffectsKind getEffectsKind() const { return EffectsKind(EffectsKindAttr); }

  /// \return True if the function is annotated with the @_effects attribute.
  bool hasEffectsKind() const {
    return EffectsKind(EffectsKindAttr) != EffectsKind::Unspecified;
  }

  /// Set the function side effect information.
  void setEffectsKind(EffectsKind E) {
    EffectsKindAttr = unsigned(E);
  }
  
  std::pair<const char *, int>  parseArgumentEffectsFromSource(StringRef effectStr,
                                                              ArrayRef<StringRef> paramNames);
  std::pair<const char *, int>  parseArgumentEffectsFromSIL(StringRef effectStr,
                                                           int argumentIndex);
  std::pair<const char *, int>  parseGlobalEffectsFromSIL(StringRef effectStr);
  std::pair<const char *, int>  parseMultipleEffectsFromSIL(StringRef effectStr);
  void writeEffect(llvm::raw_ostream &OS, int effectIdx) const;
  void writeEffects(llvm::raw_ostream &OS) const {
    writeEffect(OS, -1);
  }
  void copyEffects(SILFunction *from);
  bool hasArgumentEffects() const;
  void visitArgEffects(std::function<void(int, int, bool)> c) const;
  MemoryBehavior getMemoryBehavior(bool observeRetains);

  // Used by the MemoryLifetimeVerifier
  bool argumentMayRead(Operand *argOp, SILValue addr);

  Purpose getSpecialPurpose() const { return specialPurpose; }

  /// Get this function's global_init attribute.
  ///
  /// The implied semantics are:
  /// - side-effects can occur any time before the first invocation.
  /// - all calls to the same global_init function have the same side-effects.
  /// - any operation that may observe the initializer's side-effects must be
  ///   preceded by a call to the initializer.
  ///
  /// This is currently true if the function is an addressor that was lazily
  /// generated from a global variable access. Note that the initialization
  /// function itself does not need this attribute. It is private and only
  /// called within the addressor.
  bool isGlobalInit() const { return specialPurpose == Purpose::GlobalInit; }
    
  bool isGlobalInitOnceFunction() const {
    return specialPurpose == Purpose::GlobalInitOnceFunction;
  }

  bool isLazyPropertyGetter() const {
    return specialPurpose == Purpose::LazyPropertyGetter;
  }

  void setSpecialPurpose(Purpose purpose) { specialPurpose = purpose; }

  /// Return whether this function has a foreign implementation which can
  /// be emitted on demand.
  bool hasForeignBody() const;

  /// Return whether this function corresponds to a Clang node.
  bool hasClangNode() const {
    return ClangNodeOwner != nullptr;
  }

  /// Set the owning declaration of the Clang node associated with this
  /// function.  We have to store an owner (a Swift declaration) instead of
  /// directly referencing the original declaration due to current
  /// limitations in the serializer.
  void setClangNodeOwner(ValueDecl *owner) {
    assert(owner->hasClangNode());
    ClangNodeOwner = owner;
  }

  /// Return the owning declaration of the Clang node associated with this
  /// function.  This should only be used for serialization.
  ValueDecl *getClangNodeOwner() const {
    return ClangNodeOwner;
  }

  /// Return the Clang node associated with this function if it has one.
  ClangNode getClangNode() const {
    return (ClangNodeOwner ? ClangNodeOwner->getClangNode() : ClangNode());
  }
  const clang::Decl *getClangDecl() const {
    return (ClangNodeOwner ? ClangNodeOwner->getClangDecl() : nullptr);
  }

  /// Returns whether this function is a specialization.
  bool isSpecialization() const { return SpecializationInfo != nullptr; }

  /// Return the specialization information.
  const GenericSpecializationInformation *getSpecializationInfo() const {
    assert(isSpecialization());
    return SpecializationInfo;
  }

  void setSpecializationInfo(const GenericSpecializationInformation *Info) {
    assert(!isSpecialization());
    validateSubclassScope(getClassSubclassScope(), isThunk(), Info);
    SpecializationInfo = Info;
  }
  
  /// If this function is a specialization, return the original function from
  /// which this function was specialized.
  const SILFunction *getOriginOfSpecialization() const;

  /// Retrieve the generic environment containing the mapping from interface
  /// types to context archetypes for this function. Only present if the
  /// function has a body.
  GenericEnvironment *getGenericEnvironment() const {
    return GenericEnv;
  }

  /// Return any captured local generic environments, currently used for pack
  /// element environments only. After SILGen, these are rewritten into
  /// primary archetypes.
  ArrayRef<GenericEnvironment *> getCapturedEnvironments() const {
    return CapturedEnvs;
  }

  void setGenericEnvironment(GenericEnvironment *env);

  void setGenericEnvironment(GenericEnvironment *env,
                             ArrayRef<GenericEnvironment *> capturedEnvs,
                             SubstitutionMap forwardingSubs) {
    GenericEnv = env;
    CapturedEnvs = capturedEnvs;
    ForwardingSubMap = forwardingSubs;
  }

  /// Retrieve the generic signature from the generic environment of this
  /// function, if any. Else returns the null \c GenericSignature.
  GenericSignature getGenericSignature() const;

  /// Map the given type, which is based on an interface SILFunctionType and may
  /// therefore be dependent, to a type based on the context archetypes of this
  /// SILFunction.
  Type mapTypeIntoContext(Type type) const;

  /// Map the given type, which is based on an interface SILFunctionType and may
  /// therefore be dependent, to a type based on the context archetypes of this
  /// SILFunction.
  SILType mapTypeIntoContext(SILType type) const;

  /// Converts the given function definition to a declaration.
  void convertToDeclaration() {
    assert(isDefinition() && "Can only convert definitions to declarations");
    clear();
  }

  void clear();

  /// Like `clear`, but does not call `dropAllReferences`, which is the
  /// responsibility of the caller.
  void eraseAllBlocks();

  /// A substitution map that sends the generic parameters of the invocation
  /// generic signature to some combination of primar and local archetypes.
  ///
  /// CAUTION: If this is a SILFunction that captures pack element environments,
  /// then at SILGen time, this is not actually the forwarding substitution map
  /// of the SILFunction's generic environment. This is because:
  ///
  /// 1) The SILFunction's generic signature includes extra generic parameters,
  ///    to model captured pack elements;
  /// 2) The SILFunction's generic environment is the AST generic environment,
  ///    so it's based on the original generic signature;
  /// 3) SILGen uses this AST generic environment together with local archetypes
  ///    for lowering SIL instructions.
  ///
  /// Therefore, the SILFunction's forwarding substitution map takes the extended
  /// generic signature (1). It maps the original generic parameters to the
  /// archetypes of (2), and the extended generic parameters to the local archetypes
  /// of (3).
  ///
  /// After SILGen, all archetypes are re-instantiated inside the SIL function,
  /// and the forwarding substitution map and generic environment then align.
  SubstitutionMap getForwardingSubstitutionMap() const {
    return ForwardingSubMap;
  }

  /// Returns true if this SILFunction must be a defer statement.
  ///
  /// NOTE: This may return false for defer statements that have been
  /// deserialized without a DeclContext. This means that this is guaranteed to
  /// be correct for SILFunctions in Raw SIL that were not deserialized as
  /// canonical. Thus one can use it for diagnostics.
  bool isDefer() const {
    if (auto *dc = getDeclContext())
      if (auto *decl = dyn_cast_or_null<FuncDecl>(dc->getAsDecl()))
        return decl->isDeferBody();
    return false;
  }

  /// Returns true if this function belongs to a declaration that
  /// has `@_alwaysEmitIntoClient` attribute.
  bool markedAsAlwaysEmitIntoClient() const {
    if (!hasLocation())
      return false;

    auto *V = getLocation().getAsASTNode<ValueDecl>();
    return V && V->getAttrs().hasAttribute<AlwaysEmitIntoClientAttr>();
  }

  /// Return whether this function has attribute @_used on it
  bool markedAsUsed() const { return MarkedAsUsed; }
  void setMarkedAsUsed(bool value) { MarkedAsUsed = value; }

  /// Return custom section name if @_section was used, otherwise empty
  StringRef section() const { return Section; }
  void setSection(StringRef value) { Section = value; }

  /// Return Wasm export name if @_expose(wasm) was used, otherwise empty
  StringRef wasmExportName() const { return WasmExportName; }
  void setWasmExportName(StringRef value) { WasmExportName = value; }

  /// Return Wasm import module name if @_extern(wasm) was used otherwise empty
  StringRef wasmImportModuleName() const {
    if (WasmImportModuleAndField)
      return WasmImportModuleAndField->first;
    return StringRef();
  }

  /// Return Wasm import field name if @_extern(wasm) was used otherwise empty
  StringRef wasmImportFieldName() const {
    if (WasmImportModuleAndField)
      return WasmImportModuleAndField->second;
    return StringRef();
  }

  void setWasmImportModuleAndField(StringRef module, StringRef field) {
    WasmImportModuleAndField = std::make_pair(module, field);
  }

  bool isExternForwardDeclaration() const {
    if (isExternalDeclaration()) {
      if (auto declContext = getDeclContext()) {
        if (auto decl = declContext->getAsDecl()) {
          if (decl->getAttrs().hasAttribute<ExternAttr>())
            return true;
          if (decl->getAttrs().hasAttribute<SILGenNameAttr>())
            return true;
        }
      }
    }
    return false;
  }

  /// Returns true if this function belongs to a declaration that returns
  /// an opaque result type with one or more availability conditions that are
  /// allowed to produce a different underlying type at runtime.
  bool hasOpaqueResultTypeWithAvailabilityConditions() const {
    if (!hasLocation())
      return false;

    if (auto *V = getLocation().getAsASTNode<ValueDecl>()) {
      auto *opaqueResult = V->getOpaqueResultTypeDecl();
      return opaqueResult &&
             opaqueResult->hasConditionallyAvailableSubstitutions();
    }

    return false;
  }

  void setActorIsolation(ActorIsolation newActorIsolation) {
    actorIsolation = newActorIsolation;
  }

  std::optional<ActorIsolation> getActorIsolation() const {
    return actorIsolation;
  }

  /// Return the source file that this SILFunction belongs to if it exists.
  SourceFile *getSourceFile() const;

  //===--------------------------------------------------------------------===//
  // Block List Access
  //===--------------------------------------------------------------------===//

  using iterator = BlockListType::iterator;
  using reverse_iterator = BlockListType::reverse_iterator;
  using const_iterator = BlockListType::const_iterator;

  bool empty() const { return BlockList.empty(); }
  iterator begin() { return BlockList.begin(); }
  iterator end() { return BlockList.end(); }
  reverse_iterator rbegin() { return BlockList.rbegin(); }
  reverse_iterator rend() { return BlockList.rend(); }
  const_iterator begin() const { return BlockList.begin(); }
  const_iterator end() const { return BlockList.end(); }
  unsigned size() const { return BlockList.size(); }

  SILBasicBlock &front() { return *begin(); }
  const SILBasicBlock &front() const { return *begin(); }

  SILBasicBlock *getEntryBlock() { return &front(); }
  const SILBasicBlock *getEntryBlock() const { return &front(); }

  SILBasicBlock *createBasicBlock();
  SILBasicBlock *createBasicBlock(llvm::StringRef debugName);
  SILBasicBlock *createBasicBlockAfter(SILBasicBlock *afterBB);
  SILBasicBlock *createBasicBlockBefore(SILBasicBlock *beforeBB);

  /// Removes and destroys \p BB;
  void eraseBlock(SILBasicBlock *BB) {
    assert(BB->getParent() == this);
    BlockList.erase(BB);
  }

  /// Transfer all blocks of \p F into this function, at the begin of the block
  /// list.
  void moveAllBlocksFromOtherFunction(SILFunction *F);
  
  /// Transfer \p blockInOtherFunction of another function into this function,
  /// before \p insertPointInThisFunction.
  void moveBlockFromOtherFunction(SILBasicBlock *blockInOtherFunction,
                                  iterator insertPointInThisFunction);

  /// Move block \p BB to immediately before the iterator \p IP.
  ///
  /// The block must be part of this function.
  void moveBlockBefore(SILBasicBlock *BB, SILFunction::iterator IP);

  /// Move block \p BB to immediately after block \p After.
  ///
  /// The block must be part of this function.
  void moveBlockAfter(SILBasicBlock *BB, SILBasicBlock *After) {
    moveBlockBefore(BB, std::next(After->getIterator()));
  }

  /// Return the unique basic block containing a return inst if it
  /// exists. Otherwise, returns end.
  iterator findReturnBB() {
    return std::find_if(begin(), end(),
      [](const SILBasicBlock &BB) -> bool {
        const TermInst *TI = BB.getTerminator();
        return isa<ReturnInst>(TI);
    });
  }

  /// Return the unique basic block containing a return inst if it
  /// exists. Otherwise, returns end.
  const_iterator findReturnBB() const {
    return std::find_if(begin(), end(),
      [](const SILBasicBlock &BB) -> bool {
        const TermInst *TI = BB.getTerminator();
        return isa<ReturnInst>(TI);
    });
  }

  /// Return the unique basic block containing a throw inst if it
  /// exists. Otherwise, returns end.
  iterator findThrowBB() {
    return std::find_if(begin(), end(),
                        [](const SILBasicBlock &BB) -> bool {
                          const TermInst *TI = BB.getTerminator();
                          return isa<ThrowInst>(TI) || isa<ThrowAddrInst>(TI);
                        });
  }
  
  /// Return the unique basic block containing a throw inst if it
  /// exists. Otherwise, returns end.
  const_iterator findThrowBB() const {
    return std::find_if(begin(), end(),
                        [](const SILBasicBlock &BB) -> bool {
                          const TermInst *TI = BB.getTerminator();
                          return isa<ThrowInst>(TI) || isa<ThrowAddrInst>(TI);
                        });
  }

  /// Loop over all blocks in this function and add all function exiting blocks
  /// to output.
  void findExitingBlocks(llvm::SmallVectorImpl<SILBasicBlock *> &output) const {
    for (auto &Block : const_cast<SILFunction &>(*this)) {
      if (Block.getTerminator()->isFunctionExiting()) {
        output.emplace_back(&Block);
      }
    }
  }

  /// Populate \p output with every block terminated by an unreachable
  /// instruction.
  void visitUnreachableTerminatedBlocks(
      llvm::function_ref<void(SILBasicBlock &)> visitor) const {
    for (auto &block : const_cast<SILFunction &>(*this)) {
      if (isa<UnreachableInst>(block.getTerminator())) {
        visitor(block);
      }
    }
  }

  //===--------------------------------------------------------------------===//
  // Argument Helper Methods
  //===--------------------------------------------------------------------===//

  SILArgument *getArgument(unsigned i) {
    assert(!empty() && "Cannot get argument of a function without a body");
    return begin()->getArgument(i);
  }

  const SILArgument *getArgument(unsigned i) const {
    assert(!empty() && "Cannot get argument of a function without a body");
    return begin()->getArgument(i);
  }

  ArrayRef<SILArgument *> getArguments() const {
    assert(!empty() && "Cannot get arguments of a function without a body");
    return begin()->getArguments();
  }

  ArrayRef<SILArgument *> getIndirectResults() const {
    assert(!empty() && "Cannot get arguments of a function without a body");
    return begin()->getArguments().slice(
        0, getConventions().getNumIndirectSILResults());
  }

  ArrayRef<SILArgument *> getArgumentsWithoutIndirectResults() const {
    assert(!empty() && "Cannot get arguments of a function without a body");
    return begin()->getArguments().slice(
        getConventions().getNumIndirectSILResults() +
          getConventions().getNumIndirectSILErrorResults());
  }

  const SILArgument *getSelfArgument() const {
    assert(hasSelfParam() && "This method can only be called if the "
                             "SILFunction has a self parameter");
    return getArguments().back();
  }

  /// Like getSelfArgument() except it returns a nullptr if we do not have a
  /// selfparam.
  const SILArgument *maybeGetSelfArgument() const {
    if (!hasSelfParam())
      return nullptr;
    return getArguments().back();
  }

  /// If we have an isolated argument, return that. Returns nullptr otherwise.
  const SILArgument *maybeGetIsolatedArgument() const {
    for (auto *arg : getArgumentsWithoutIndirectResults()) {
      if (cast<SILFunctionArgument>(arg)->getKnownParameterInfo().hasOption(
              SILParameterInfo::Isolated))
        return arg;
    }

    return nullptr;
  }

  const SILArgument *getDynamicSelfMetadata() const {
    assert(hasDynamicSelfMetadata() && "This method can only be called if the "
           "SILFunction has a self-metadata parameter");
    return getArguments().back();
  }

  //===--------------------------------------------------------------------===//
  // Miscellaneous
  //===--------------------------------------------------------------------===//

  /// A value's lifetime, determined by looking at annotations on its decl and
  /// the default lifetime for the type.
  Lifetime getLifetime(VarDecl *decl, SILType ty) {
    return ty.getLifetime(*this).getLifetimeForAnnotatedValue(
        decl->getLifetimeAnnotation());
  }

  ArrayRef<std::pair<SILType, SILUndef *>> getUndefValues() {
    return {undefValues.begin(), undefValues.end()};
  }

  /// verify - Run the SIL verifier to make sure that the SILFunction follows
  /// invariants.
  void verify(CalleeCache *calleeCache = nullptr,
              bool SingleFunction = true,
              bool isCompleteOSSA = true,
              bool checkLinearLifetime = true) const;

  /// Run the SIL verifier without assuming OSSA lifetimes end at dead end
  /// blocks.
  void verifyIncompleteOSSA() const {
    verify(/*calleeCache*/nullptr, /*SingleFunction=*/true, /*completeOSSALifetimes=*/false);
  }

  /// Verifies the lifetime of memory locations in the function.
  void verifyMemoryLifetime(CalleeCache *calleeCache);

  /// Verifies ownership of the function.
  /// Since we don't have complete lifetimes everywhere, computes DeadEndBlocks
  /// and calls verifyOwnership(DeadEndBlocks *deadEndBlocks)
  void verifyOwnership() const;

  /// Run the SIL ownership verifier to check that all values with ownership
  /// have a linear lifetime. Regular OSSA invariants are checked separately in
  /// normal SIL verification.
  ///
  /// \p deadEndBlocks is nullptr when OSSA lifetimes are complete.
  ///
  /// NOTE: The ownership verifier is run when performing normal IR
  /// verification, so this verification can be viewed as a subset of
  /// SILFunction::verify(checkLinearLifetimes=true).
  void verifyOwnership(DeadEndBlocks *deadEndBlocks) const;

  /// Verify that all non-cond-br critical edges have been split.
  ///
  /// This is a fast subset of the checks performed in the SILVerifier.
  void verifyCriticalEdges() const;

  /// Validate that all SILUndefs stored in the function's type -> SILUndef map
  /// have this function as their parent function.
  ///
  /// Please only call this from the SILVerifier.
  void verifySILUndefMap() const;

  /// Pretty-print the SILFunction.
  void dump(bool Verbose) const;
  void dump() const;
  
  /// Pretty-print the SILFunction.
  /// Useful for dumping the function when running in a debugger.
  /// Warning: no error handling is done. Fails with an assert if the file
  /// cannot be opened.
  void dump(const char *FileName) const;

  /// Pretty-print the SILFunction to the tream \p OS.
  ///
  /// \param Verbose Dump SIL location information in verbose mode.
  void print(raw_ostream &OS, bool Verbose = false) const {
    SILPrintContext PrintCtx(OS, Verbose);
    print(PrintCtx);
  }

  /// Pretty-print the SILFunction with the context \p PrintCtx.
  void print(SILPrintContext &PrintCtx) const;

  /// Pretty-print the SILFunction's name using SIL syntax,
  /// '@function_mangled_name'.
  void printName(raw_ostream &OS) const;

  /// Assigns consecutive numbers to all the SILNodes in the function.
  /// For instructions, both the instruction node and the value nodes of
  /// any results will be assigned numbers; the instruction node will
  /// be numbered the same as the first result, if there are any results.
  void numberValues(llvm::DenseMap<const SILNode*, unsigned> &nodeToNumberMap)
    const;

  ASTContext &getASTContext() const;

  /// This function is meant for use from the debugger.  You can just say 'call
  /// F->viewCFG()' and a ghostview window should pop up from the program,
  /// displaying the CFG of the current function with the code for each basic
  /// block inside.  This depends on there being a 'dot' and 'gv' program in
  /// your path.
  void viewCFG() const;
  /// Like ViewCFG, but the graph does not show the contents of basic blocks.
  void viewCFGOnly() const;

};

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
                                     const SILFunction &F) {
  F.print(OS);
  return OS;
}

} // end swift namespace

//===----------------------------------------------------------------------===//
// ilist_traits for SILFunction
//===----------------------------------------------------------------------===//

namespace llvm {

template <>
struct ilist_traits<::swift::SILFunction> :
public ilist_node_traits<::swift::SILFunction> {
  using SILFunction = ::swift::SILFunction;

public:
  static void deleteNode(SILFunction *V) { V->~SILFunction(); }

private:
  void createNode(const SILFunction &);
};

} // end llvm namespace

//===----------------------------------------------------------------------===//
// Inline SIL implementations
//===----------------------------------------------------------------------===//

namespace swift {

inline bool SILBasicBlock::isEntry() const {
  return this == &*getParent()->begin();
}

inline SILModule &SILInstruction::getModule() const {
  return getFunction()->getModule();
}

} // end swift namespace

#endif
