RuntimeEffect swift::getRuntimeEffect()

in lib/SIL/Utils/InstructionUtils.cpp [383:862]


RuntimeEffect swift::getRuntimeEffect(SILInstruction *inst, SILType &impactType) {
  switch (inst->getKind()) {
  case SILInstructionKind::TailAddrInst:
  case SILInstructionKind::IndexRawPointerInst:
  case SILInstructionKind::FunctionRefInst:
  case SILInstructionKind::DynamicFunctionRefInst:
  case SILInstructionKind::PreviousDynamicFunctionRefInst:
  case SILInstructionKind::GlobalAddrInst:
  case SILInstructionKind::BaseAddrForOffsetInst:
  case SILInstructionKind::IntegerLiteralInst:
  case SILInstructionKind::FloatLiteralInst:
  case SILInstructionKind::StringLiteralInst:
  case SILInstructionKind::ClassMethodInst:
  case SILInstructionKind::ObjCMethodInst:
  case SILInstructionKind::ObjCSuperMethodInst:
  case SILInstructionKind::UpcastInst:
  case SILInstructionKind::AddressToPointerInst:
  case SILInstructionKind::PointerToAddressInst:
  case SILInstructionKind::UncheckedRefCastInst:
  case SILInstructionKind::UncheckedAddrCastInst:
  case SILInstructionKind::UncheckedTrivialBitCastInst:
  case SILInstructionKind::UncheckedBitwiseCastInst:
  case SILInstructionKind::UncheckedValueCastInst:
  case SILInstructionKind::RefToRawPointerInst:
  case SILInstructionKind::RawPointerToRefInst:
#define LOADABLE_REF_STORAGE(Name, ...)                                        \
  case SILInstructionKind::RefTo##Name##Inst:                                  \
  case SILInstructionKind::Name##ToRefInst:
#include "swift/AST/ReferenceStorage.def"
#undef LOADABLE_REF_STORAGE_HELPER
  case SILInstructionKind::ConvertFunctionInst:
  case SILInstructionKind::ConvertEscapeToNoEscapeInst:
  case SILInstructionKind::ThinFunctionToPointerInst:
  case SILInstructionKind::PointerToThinFunctionInst:
  case SILInstructionKind::RefToBridgeObjectInst:
  case SILInstructionKind::BridgeObjectToRefInst:
  case SILInstructionKind::BridgeObjectToWordInst:
  case SILInstructionKind::ThinToThickFunctionInst:
  case SILInstructionKind::ThickToObjCMetatypeInst:
  case SILInstructionKind::ObjCMetatypeToObjectInst:
  case SILInstructionKind::ObjCExistentialMetatypeToObjectInst:
  case SILInstructionKind::ClassifyBridgeObjectInst:
  case SILInstructionKind::ValueToBridgeObjectInst:
  case SILInstructionKind::MarkDependenceInst:
  case SILInstructionKind::MoveValueInst:
  case SILInstructionKind::UncheckedOwnershipConversionInst:
  case SILInstructionKind::LoadInst:
  case SILInstructionKind::LoadBorrowInst:
  case SILInstructionKind::BeginBorrowInst:
  case SILInstructionKind::StoreBorrowInst:
  case SILInstructionKind::MarkUninitializedInst:
  case SILInstructionKind::ProjectExistentialBoxInst:
  case SILInstructionKind::ObjCProtocolInst:
  case SILInstructionKind::ObjectInst:
  case SILInstructionKind::TupleInst:
  case SILInstructionKind::TupleExtractInst:
  case SILInstructionKind::StructInst:
  case SILInstructionKind::StructExtractInst:
  case SILInstructionKind::RefElementAddrInst:
  case SILInstructionKind::EnumInst:
  case SILInstructionKind::UncheckedEnumDataInst:
  case SILInstructionKind::InitEnumDataAddrInst:
  case SILInstructionKind::UncheckedTakeEnumDataAddrInst:
  case SILInstructionKind::SelectEnumInst:
  case SILInstructionKind::SelectEnumAddrInst:
  case SILInstructionKind::SelectValueInst:
  case SILInstructionKind::OpenExistentialMetatypeInst:
  case SILInstructionKind::OpenExistentialBoxInst:
  case SILInstructionKind::OpenExistentialValueInst:
  case SILInstructionKind::OpenExistentialBoxValueInst:
  case SILInstructionKind::ProjectBlockStorageInst:
  case SILInstructionKind::UnreachableInst:
  case SILInstructionKind::ReturnInst:
  case SILInstructionKind::ThrowInst:
  case SILInstructionKind::YieldInst:
  case SILInstructionKind::UnwindInst:
  case SILInstructionKind::BranchInst:
  case SILInstructionKind::CondBranchInst:
  case SILInstructionKind::SwitchValueInst:
  case SILInstructionKind::SwitchEnumInst:
  case SILInstructionKind::DeallocStackInst:
  case SILInstructionKind::DeallocStackRefInst:
  case SILInstructionKind::AutoreleaseValueInst:
  case SILInstructionKind::BindMemoryInst:
  case SILInstructionKind::RebindMemoryInst:
  case SILInstructionKind::FixLifetimeInst:
  case SILInstructionKind::EndBorrowInst:
  case SILInstructionKind::AssignInst:
  case SILInstructionKind::AssignByWrapperInst:
  case SILInstructionKind::MarkFunctionEscapeInst:
  case SILInstructionKind::EndLifetimeInst:
  case SILInstructionKind::EndApplyInst:
  case SILInstructionKind::AbortApplyInst:
  case SILInstructionKind::CondFailInst:
  case SILInstructionKind::DestructureStructInst:
  case SILInstructionKind::DestructureTupleInst:
  case SILInstructionKind::DifferentiableFunctionInst:
  case SILInstructionKind::DifferentiableFunctionExtractInst:
  case SILInstructionKind::LinearFunctionInst:
  case SILInstructionKind::LinearFunctionExtractInst:
  case SILInstructionKind::DifferentiabilityWitnessFunctionInst:
  case SILInstructionKind::EndCOWMutationInst:
    return RuntimeEffect::NoEffect;

  case SILInstructionKind::DebugValueInst:
    // Ignore runtime calls of debug_vlaue
    return RuntimeEffect::NoEffect;

  case SILInstructionKind::GetAsyncContinuationInst:
  case SILInstructionKind::GetAsyncContinuationAddrInst:
  case SILInstructionKind::AwaitAsyncContinuationInst:
  case SILInstructionKind::HopToExecutorInst:
  case SILInstructionKind::ExtractExecutorInst:
    return RuntimeEffect::Concurrency;

  case SILInstructionKind::KeyPathInst:
    return RuntimeEffect::Allocating | RuntimeEffect::Releasing |
           RuntimeEffect::MetaData;

  case SILInstructionKind::SwitchEnumAddrInst:
  case SILInstructionKind::InjectEnumAddrInst:
  case SILInstructionKind::TupleElementAddrInst:
  case SILInstructionKind::StructElementAddrInst:
  case SILInstructionKind::IndexAddrInst:
    // TODO: hasArchetype() ?
    if (!inst->getOperand(0)->getType().isLoadable(*inst->getFunction())) {
      impactType = inst->getOperand(0)->getType();
      return RuntimeEffect::MetaData;
    }
    return RuntimeEffect::NoEffect;

  case SILInstructionKind::RefTailAddrInst:
    if (!cast<RefTailAddrInst>(inst)->getTailType().isLoadable(*inst->getFunction())) {
      impactType = cast<RefTailAddrInst>(inst)->getTailType();
      return RuntimeEffect::MetaData;
    }
    return RuntimeEffect::NoEffect;

  case SILInstructionKind::BeginAccessInst:
    if (cast<BeginAccessInst>(inst)->getEnforcement() ==
        SILAccessEnforcement::Dynamic)
      return RuntimeEffect::ExclusivityChecking;
    return RuntimeEffect::NoEffect;
  case SILInstructionKind::EndAccessInst:
    if (cast<EndAccessInst>(inst)->getBeginAccess()->getEnforcement() ==
        SILAccessEnforcement::Dynamic)
      return RuntimeEffect::ExclusivityChecking;
    return RuntimeEffect::NoEffect;
  case SILInstructionKind::BeginUnpairedAccessInst:
    if (cast<BeginUnpairedAccessInst>(inst)->getEnforcement() ==
        SILAccessEnforcement::Dynamic)
      return RuntimeEffect::ExclusivityChecking;
    return RuntimeEffect::NoEffect;
  case SILInstructionKind::EndUnpairedAccessInst:
    if (cast<EndUnpairedAccessInst>(inst)->getEnforcement() ==
        SILAccessEnforcement::Dynamic)
      return RuntimeEffect::ExclusivityChecking;
    return RuntimeEffect::NoEffect;

  case SILInstructionKind::InitExistentialAddrInst:
  case SILInstructionKind::InitExistentialValueInst:
    impactType = inst->getOperand(0)->getType();
    return RuntimeEffect::Allocating | RuntimeEffect::Releasing |
           RuntimeEffect::MetaData;

  case SILInstructionKind::InitExistentialRefInst:
  case SILInstructionKind::InitExistentialMetatypeInst:
  case SILInstructionKind::ObjCToThickMetatypeInst:
    impactType = inst->getOperand(0)->getType();
    return RuntimeEffect::MetaData;

  case SILInstructionKind::OpenExistentialAddrInst:
    if (cast<OpenExistentialAddrInst>(inst)->getAccessKind() ==
        OpenedExistentialAccess::Mutable)
      return RuntimeEffect::Allocating;
    return RuntimeEffect::NoEffect;

  case SILInstructionKind::OpenExistentialRefInst: {
    SILType opType = cast<OpenExistentialRefInst>(inst)->getOperand()->getType();
    impactType = opType;
    if (opType.getASTType()->isObjCExistentialType()) {
      return RuntimeEffect::MetaData;
    }
    return RuntimeEffect::MetaData;
    // TODO: should be NoEffect
    //return RuntimeEffect::NoEffect;
  }

  case SILInstructionKind::UnconditionalCheckedCastValueInst:
  case SILInstructionKind::UnconditionalCheckedCastInst:
    impactType = inst->getOperand(0)->getType();
    return RuntimeEffect::Casting | metadataEffect(impactType) |
           metadataEffect(cast<SingleValueInstruction>(inst)->getType());
  case SILInstructionKind::UnconditionalCheckedCastAddrInst:
  case SILInstructionKind::CheckedCastAddrBranchInst:
  case SILInstructionKind::UncheckedRefCastAddrInst:
    impactType = inst->getOperand(0)->getType();
    return RuntimeEffect::Casting | metadataEffect(impactType) |
           metadataEffect(inst->getOperand(1)->getType());
  case SILInstructionKind::CheckedCastBranchInst:
    impactType = inst->getOperand(0)->getType();
    return RuntimeEffect::Casting | metadataEffect(impactType) |
      metadataEffect(cast<CheckedCastBranchInst>(inst)->getTargetLoweredType());
  case SILInstructionKind::CheckedCastValueBranchInst:
    impactType = inst->getOperand(0)->getType();
    return RuntimeEffect::Casting | metadataEffect(impactType) |
      metadataEffect(cast<CheckedCastValueBranchInst>(inst)->getTargetLoweredType());

  case SILInstructionKind::AllocStackInst:
  case SILInstructionKind::ProjectBoxInst:
    if (!cast<SingleValueInstruction>(inst)->getType().
          isLoadable(*inst->getFunction())) {
      impactType = cast<SingleValueInstruction>(inst)->getType();
      return RuntimeEffect::MetaData;
    }
    return RuntimeEffect::NoEffect;

  case SILInstructionKind::AllocGlobalInst: {
    SILType glTy = cast<AllocGlobalInst>(inst)->getReferencedGlobal()->
                      getLoweredType();
    if (glTy.hasOpaqueArchetype()) {
      impactType = glTy;
      return RuntimeEffect::Allocating | RuntimeEffect::MetaData;
    }
    return RuntimeEffect::Allocating;
  }
  case SILInstructionKind::AllocBoxInst:
  case SILInstructionKind::AllocExistentialBoxInst:
  case SILInstructionKind::AllocRefInst:
  case SILInstructionKind::AllocRefDynamicInst:
    impactType = cast<SingleValueInstruction>(inst)->getType();
    return RuntimeEffect::Allocating | RuntimeEffect::MetaData |
           // TODO: why Releasing?
           RuntimeEffect::Releasing;

  case SILInstructionKind::DeallocRefInst:
  case SILInstructionKind::DeallocPartialRefInst:
  case SILInstructionKind::DeallocBoxInst:
  case SILInstructionKind::DeallocExistentialBoxInst:
  case SILInstructionKind::DeinitExistentialAddrInst:
  case SILInstructionKind::DeinitExistentialValueInst:
    return RuntimeEffect::Deallocating;

  case SILInstructionKind::CopyAddrInst: {
    auto *ca = cast<CopyAddrInst>(inst);
    impactType = ca->getSrc()->getType();
    if (!ca->isInitializationOfDest())
      return RuntimeEffect::MetaData | RuntimeEffect::Releasing;
    if (!ca->isTakeOfSrc())
      return RuntimeEffect::MetaData | RuntimeEffect::RefCounting;
    return RuntimeEffect::MetaData;
  }
  // Equialent to a copy_addr [init]
  case SILInstructionKind::MarkUnresolvedMoveAddrInst: {
    return RuntimeEffect::MetaData | RuntimeEffect::RefCounting;
  }

  case SILInstructionKind::StoreInst:
    switch (cast<StoreInst>(inst)->getOwnershipQualifier()) {
      case StoreOwnershipQualifier::Unqualified:
      case StoreOwnershipQualifier::Trivial:
        return RuntimeEffect::NoEffect;
      case StoreOwnershipQualifier::Init:
        return RuntimeEffect::RefCounting;
      case StoreOwnershipQualifier::Assign:
        return RuntimeEffect::Releasing;
    }

  case SILInstructionKind::DestroyAddrInst:
    impactType = inst->getOperand(0)->getType();
    if (impactType.isTrivial(*inst->getFunction()))
      return RuntimeEffect::NoEffect;
    if (!impactType.isLoadable(*inst->getFunction()))
      return RuntimeEffect::Releasing | RuntimeEffect::MetaData;
    return RuntimeEffect::Releasing;

  case SILInstructionKind::ValueMetatypeInst:
  case SILInstructionKind::MetatypeInst: {
    auto metaTy = cast<SingleValueInstruction>(inst)->getType().castTo<MetatypeType>();
    if (metaTy->getRepresentation() != MetatypeRepresentation::Thin) {
      Type instTy = metaTy->getInstanceType();
      if (instTy->isLegalSILType())
        impactType = SILType::getPrimitiveObjectType(CanType(instTy));
      if (auto selfType = instTy->getAs<DynamicSelfType>())
        instTy = selfType->getSelfType();
      auto *cl = instTy->getClassOrBoundGenericClass();
      bool isForeign =
          cl->getObjectModel() == ReferenceCounting::ObjC ||
          cl->isForeign();
      if ((cl && isForeign) || instTy->isAnyObject())
        return RuntimeEffect::MetaData | RuntimeEffect::ObjectiveC;
      return RuntimeEffect::MetaData;
    }
    return RuntimeEffect::NoEffect;
  }

  case SILInstructionKind::ExistentialMetatypeInst: {
    SILType opType = cast<ExistentialMetatypeInst>(inst)->getOperand()->getType();
    impactType = opType;
    switch (opType.getPreferredExistentialRepresentation()) {
    case ExistentialRepresentation::Metatype:
    case ExistentialRepresentation::Boxed:
    case ExistentialRepresentation::Opaque:
      return RuntimeEffect::MetaData;
    case ExistentialRepresentation::Class: {
      auto *cl = opType.getClassOrBoundGenericClass();
      bool usesObjCModel = cl->getObjectModel() == ReferenceCounting::ObjC;
      if ((cl && usesObjCModel) || opType.isAnyObject())
        return RuntimeEffect::MetaData | RuntimeEffect::ObjectiveC;
      return RuntimeEffect::MetaData | RuntimeEffect::ObjectiveC;
    }
    case ExistentialRepresentation::None:
      return RuntimeEffect::NoEffect;
    }
    llvm_unreachable("Bad existential representation");
  }
  case SILInstructionKind::StrongRetainInst:
  case SILInstructionKind::UnmanagedRetainValueInst:
  case SILInstructionKind::RetainValueAddrInst:
  case SILInstructionKind::RetainValueInst:
  case SILInstructionKind::BeginCOWMutationInst:
  case SILInstructionKind::CopyValueInst:
  case SILInstructionKind::ExplicitCopyValueInst:
  case SILInstructionKind::SetDeallocatingInst:
  case SILInstructionKind::IsUniqueInst:
  case SILInstructionKind::IsEscapingClosureInst:
  case SILInstructionKind::CopyBlockInst:
  case SILInstructionKind::CopyBlockWithoutEscapingInst:
    return RuntimeEffect::RefCounting;

  case SILInstructionKind::InitBlockStorageHeaderInst:
    return RuntimeEffect::Releasing;

  case SILInstructionKind::StrongReleaseInst:
  case SILInstructionKind::UnmanagedReleaseValueInst:
  case SILInstructionKind::UnmanagedAutoreleaseValueInst:
  case SILInstructionKind::ReleaseValueInst:
  case SILInstructionKind::ReleaseValueAddrInst:
  case SILInstructionKind::DestroyValueInst:
    impactType = inst->getOperand(0)->getType();
    if (impactType.isBlockPointerCompatible())
      return RuntimeEffect::ObjectiveC | RuntimeEffect::Releasing;
    return RuntimeEffect::Releasing;

#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...)            \
  case SILInstructionKind::StrongRetain##Name##Inst:                           \
  case SILInstructionKind::Name##RetainInst:                                   \
    return RuntimeEffect::RefCounting;                                        \
  case SILInstructionKind::Name##ReleaseInst:                                  \
    return RuntimeEffect::Releasing;
#include "swift/AST/ReferenceStorage.def"
#undef ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE

#define UNCHECKED_REF_STORAGE(Name, ...)                                       \
  case SILInstructionKind::StrongCopy##Name##ValueInst:                        \
    return RuntimeEffect::RefCounting;
#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...)            \
  case SILInstructionKind::StrongCopy##Name##ValueInst:                        \
    return RuntimeEffect::RefCounting;
#include "swift/AST/ReferenceStorage.def"
#undef UNCHECKED_REF_STORAGE
#undef ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE

#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...)             \
  case SILInstructionKind::Store##Name##Inst:                                  \
    return RuntimeEffect::Releasing;
#include "swift/AST/ReferenceStorage.def"
#undef NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE

#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...)       \
  case SILInstructionKind::Load##Name##Inst:                                   \
    return RuntimeEffect::RefCounting;
#include "swift/AST/ReferenceStorage.def"
#undef NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE

  case SILInstructionKind::GlobalValueInst:
    return RuntimeEffect::Locking | RuntimeEffect::MetaData;

  case SILInstructionKind::DynamicMethodBranchInst:
    return RuntimeEffect::ObjectiveC;

  case SILInstructionKind::PartialApplyInst:
  case SILInstructionKind::ApplyInst:
  case SILInstructionKind::TryApplyInst:
  case SILInstructionKind::BeginApplyInst: {
    RuntimeEffect rt = RuntimeEffect::NoEffect;
    auto as = ApplySite(inst);

    switch (as.getSubstCalleeType()->getRepresentation()) {
    case SILFunctionTypeRepresentation::ObjCMethod:
    case SILFunctionTypeRepresentation::Block:
      rt |= RuntimeEffect::ObjectiveC | RuntimeEffect::MetaData;
      break;
    case SILFunctionTypeRepresentation::WitnessMethod:
      rt |= RuntimeEffect::MetaData;
      break;
    case SILFunctionTypeRepresentation::CFunctionPointer:
    case SILFunctionTypeRepresentation::CXXMethod:
    case SILFunctionTypeRepresentation::Thin:
    case SILFunctionTypeRepresentation::Method:
    case SILFunctionTypeRepresentation::Closure:
    case SILFunctionTypeRepresentation::Thick:
      break;
    }

    if (isa<BeginApplyInst>(inst))
      rt |= RuntimeEffect::Allocating;      

    if (auto *pa = dyn_cast<PartialApplyInst>(inst)) {
      if (pa->isOnStack()) {
        for (SILValue arg : pa->getArguments()) {
          if (!arg->getType().isTrivial(*pa->getFunction()))
            rt |= RuntimeEffect::RefCounting;
        }
      } else {
        rt |= RuntimeEffect::Allocating | RuntimeEffect::Releasing;
      }
    }

    if (!as.getSubstitutionMap().empty())
      rt |= RuntimeEffect::MetaData;
    if (auto *pa = dyn_cast<PartialApplyInst>(inst)) {
      if (!pa->isOnStack())
        rt |= RuntimeEffect::MetaData;
    }
    return rt;
  }
  case SILInstructionKind::WitnessMethodInst: {
    return RuntimeEffect::MetaData;
  }
  case SILInstructionKind::SuperMethodInst: {
    auto method = cast<SuperMethodInst>(inst)->getMember().getOverriddenVTableEntry();
    auto *classDecl = cast<ClassDecl>(method.getDecl()->getDeclContext());
    if (classDecl->hasResilientMetadata())
      return RuntimeEffect::MetaData;
    return RuntimeEffect::NoEffect;
  }

  case SILInstructionKind::BuiltinInst:
    switch (cast<BuiltinInst>(inst)->getBuiltinInfo().ID) {
    case BuiltinValueKind::Once:
    case BuiltinValueKind::OnceWithContext:
      return RuntimeEffect::Locking;
    case BuiltinValueKind::IsUnique:
      return RuntimeEffect::RefCounting;
    case BuiltinValueKind::IsOptionalType:
      return RuntimeEffect::Casting;
    case BuiltinValueKind::AllocRaw:
      return RuntimeEffect::Allocating;
    case BuiltinValueKind::DeallocRaw:
      return RuntimeEffect::Deallocating;
    case BuiltinValueKind::Fence:
    case BuiltinValueKind::CmpXChg:
    case BuiltinValueKind::AtomicLoad:
    case BuiltinValueKind::AtomicStore:
    case BuiltinValueKind::AtomicRMW:
      return RuntimeEffect::Locking;
    case BuiltinValueKind::DestroyArray:
      return RuntimeEffect::Releasing;
    case BuiltinValueKind::CopyArray:
      return RuntimeEffect::RefCounting;
    case BuiltinValueKind::AssignCopyArrayNoAlias:
    case BuiltinValueKind::AssignCopyArrayFrontToBack:
    case BuiltinValueKind::AssignCopyArrayBackToFront:
    case BuiltinValueKind::AssignTakeArray:
      return RuntimeEffect::RefCounting | RuntimeEffect::Deallocating;
    case BuiltinValueKind::Swift3ImplicitObjCEntrypoint:
      return RuntimeEffect::ObjectiveC | RuntimeEffect::Allocating;
    case BuiltinValueKind::BuildOrdinarySerialExecutorRef:
    case BuiltinValueKind::BuildDefaultActorExecutorRef:
    case BuiltinValueKind::BuildMainActorExecutorRef:
    case BuiltinValueKind::StartAsyncLet:
    case BuiltinValueKind::StartAsyncLetWithLocalBuffer:
      return RuntimeEffect::MetaData;
    default:
      break;
    }
    return RuntimeEffect::NoEffect;
  }
}