//===--- OperandOwnership.cpp ---------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 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
//
//===----------------------------------------------------------------------===//

#include "swift/SIL/ApplySite.h"
#include "swift/SIL/OwnershipUtils.h"
#include "swift/SIL/SILBuiltinVisitor.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILValue.h"
#include "swift/SIL/SILVisitor.h"

using namespace swift;

/// Return true if all OperandOwnership invariants hold.
bool swift::checkOperandOwnershipInvariants(const Operand *operand,
                                            SILModuleConventions *silConv) {
  OperandOwnership opOwnership = operand->getOperandOwnership(silConv);
  if (opOwnership == OperandOwnership::Borrow) {
    // Must be a valid BorrowingOperand.
    return bool(BorrowingOperand(const_cast<Operand *>(operand)));
  }
  return true;
}

//===----------------------------------------------------------------------===//
//                         OperandOwnershipClassifier
//===----------------------------------------------------------------------===//

namespace {

class OperandOwnershipClassifier
  : public SILInstructionVisitor<OperandOwnershipClassifier, OperandOwnership> {
  LLVM_ATTRIBUTE_UNUSED SILModule &mod;
  // Allow module conventions to be overriden while lowering between canonical
  // and lowered SIL stages.
  SILModuleConventions silConv;

  const Operand &op;

public:
  /// Create a new OperandOwnershipClassifier.
  ///
  /// In most cases, one should only pass in \p Op and \p BaseValue will be set
  /// to Op.get(). In cases where one is trying to verify subobjects, Op.get()
  /// should be the subobject and Value should be the parent object. An example
  /// of where one would want to do this is in the case of value projections
  /// like struct_extract.
  OperandOwnershipClassifier(SILModuleConventions silConv, const Operand &op)
      : mod(silConv.getModule()), silConv(silConv), op(op) {}

  SILValue getValue() const { return op.get(); }

  ValueOwnershipKind getOwnershipKind() const {
    return op.get().getOwnershipKind();
  }

  unsigned getOperandIndex() const { return op.getOperandNumber(); }

  SILType getType() const { return op.get()->getType(); }

  bool compatibleWithOwnership(ValueOwnershipKind kind) const {
    return getOwnershipKind().isCompatibleWith(kind);
  }

  bool hasExactOwnership(ValueOwnershipKind kind) const {
    return getOwnershipKind() == kind;
  }

  OperandOwnership visitFullApply(FullApplySite apply);

// Create declarations for all instructions, so we get a warning at compile
// time if any instructions do not have an implementation.
#define INST(Id, Parent) OperandOwnership visit##Id(Id *);
#include "swift/SIL/SILNodes.def"
};

} // end anonymous namespace

/// Implementation for instructions that we should never visit since they are
/// not valid in ossa or do not have operands. Since we should never visit
/// these, we just assert.
#define SHOULD_NEVER_VISIT_INST(INST)                                          \
  OperandOwnership OperandOwnershipClassifier::visit##INST##Inst(              \
      INST##Inst *i) {                                                         \
    llvm::errs() << "Unhandled inst: " << *i;                                  \
    llvm::report_fatal_error(                                                  \
        "Visited instruction that should never be visited?!");                 \
  }
SHOULD_NEVER_VISIT_INST(AllocBox)
SHOULD_NEVER_VISIT_INST(AllocExistentialBox)
SHOULD_NEVER_VISIT_INST(AllocGlobal)
SHOULD_NEVER_VISIT_INST(AllocStack)
SHOULD_NEVER_VISIT_INST(DifferentiabilityWitnessFunction)
SHOULD_NEVER_VISIT_INST(FloatLiteral)
SHOULD_NEVER_VISIT_INST(FunctionRef)
SHOULD_NEVER_VISIT_INST(DynamicFunctionRef)
SHOULD_NEVER_VISIT_INST(PreviousDynamicFunctionRef)
SHOULD_NEVER_VISIT_INST(GlobalAddr)
SHOULD_NEVER_VISIT_INST(GlobalValue)
SHOULD_NEVER_VISIT_INST(BaseAddrForOffset)
SHOULD_NEVER_VISIT_INST(IntegerLiteral)
SHOULD_NEVER_VISIT_INST(Metatype)
SHOULD_NEVER_VISIT_INST(ObjCProtocol)
SHOULD_NEVER_VISIT_INST(RetainValue)
SHOULD_NEVER_VISIT_INST(RetainValueAddr)
SHOULD_NEVER_VISIT_INST(StringLiteral)
SHOULD_NEVER_VISIT_INST(StrongRetain)
SHOULD_NEVER_VISIT_INST(Unreachable)
SHOULD_NEVER_VISIT_INST(Unwind)
SHOULD_NEVER_VISIT_INST(ReleaseValue)
SHOULD_NEVER_VISIT_INST(ReleaseValueAddr)
SHOULD_NEVER_VISIT_INST(StrongRelease)
SHOULD_NEVER_VISIT_INST(GetAsyncContinuation)

#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...)            \
  SHOULD_NEVER_VISIT_INST(StrongRetain##Name)                                  \
  SHOULD_NEVER_VISIT_INST(Name##Retain)
#include "swift/AST/ReferenceStorage.def"
#undef SHOULD_NEVER_VISIT_INST

// FIXME: The assert should be moved to the verifier.
#define OPERAND_OWNERSHIP(OWNERSHIP, INST)                                     \
  OperandOwnership                                                             \
  OperandOwnershipClassifier::visit##INST##Inst(INST##Inst *i) {               \
    assert(i->getNumOperands() && "Expected to have non-zero operands");       \
    return OperandOwnership::OWNERSHIP;                                        \
  }

// Instructions that require trivial operands.
OPERAND_OWNERSHIP(TrivialUse, AwaitAsyncContinuation)
OPERAND_OWNERSHIP(TrivialUse, AddressToPointer)
OPERAND_OWNERSHIP(TrivialUse, AllocRef)        // with tail operand
OPERAND_OWNERSHIP(TrivialUse, AllocRefDynamic) // with tail operand
OPERAND_OWNERSHIP(TrivialUse, BeginAccess)
OPERAND_OWNERSHIP(TrivialUse, BeginUnpairedAccess)
OPERAND_OWNERSHIP(TrivialUse, BindMemory)
OPERAND_OWNERSHIP(TrivialUse, RebindMemory)
OPERAND_OWNERSHIP(TrivialUse, CheckedCastAddrBranch)
OPERAND_OWNERSHIP(TrivialUse, CondBranch)
OPERAND_OWNERSHIP(TrivialUse, CondFail)
OPERAND_OWNERSHIP(TrivialUse, CopyAddr)
OPERAND_OWNERSHIP(TrivialUse, MarkUnresolvedMoveAddr)
OPERAND_OWNERSHIP(TrivialUse, DeallocStack)
OPERAND_OWNERSHIP(TrivialUse, DeinitExistentialAddr)
OPERAND_OWNERSHIP(TrivialUse, DestroyAddr)
OPERAND_OWNERSHIP(TrivialUse, EndAccess)
OPERAND_OWNERSHIP(TrivialUse, EndUnpairedAccess)
OPERAND_OWNERSHIP(TrivialUse, GetAsyncContinuationAddr)
OPERAND_OWNERSHIP(TrivialUse, IndexAddr)
OPERAND_OWNERSHIP(TrivialUse, IndexRawPointer)
OPERAND_OWNERSHIP(TrivialUse, InitBlockStorageHeader)
OPERAND_OWNERSHIP(TrivialUse, InitEnumDataAddr)
OPERAND_OWNERSHIP(TrivialUse, InitExistentialAddr)
OPERAND_OWNERSHIP(TrivialUse, InitExistentialMetatype)
OPERAND_OWNERSHIP(TrivialUse, InjectEnumAddr)
OPERAND_OWNERSHIP(TrivialUse, IsUnique)
OPERAND_OWNERSHIP(TrivialUse, Load)
OPERAND_OWNERSHIP(TrivialUse, LoadBorrow)
OPERAND_OWNERSHIP(TrivialUse, MarkFunctionEscape)
OPERAND_OWNERSHIP(TrivialUse, ObjCExistentialMetatypeToObject)
OPERAND_OWNERSHIP(TrivialUse, ObjCMetatypeToObject)
OPERAND_OWNERSHIP(TrivialUse, ObjCToThickMetatype)
OPERAND_OWNERSHIP(TrivialUse, OpenExistentialAddr)
OPERAND_OWNERSHIP(TrivialUse, OpenExistentialMetatype)
OPERAND_OWNERSHIP(TrivialUse, PointerToAddress)
OPERAND_OWNERSHIP(TrivialUse, PointerToThinFunction)
OPERAND_OWNERSHIP(TrivialUse, ProjectBlockStorage)
OPERAND_OWNERSHIP(TrivialUse, RawPointerToRef)
OPERAND_OWNERSHIP(TrivialUse, SelectEnumAddr)
OPERAND_OWNERSHIP(TrivialUse, StructElementAddr)
OPERAND_OWNERSHIP(TrivialUse, SwitchEnumAddr)
OPERAND_OWNERSHIP(TrivialUse, SwitchValue)
OPERAND_OWNERSHIP(TrivialUse, TailAddr)
OPERAND_OWNERSHIP(TrivialUse, ThickToObjCMetatype)
OPERAND_OWNERSHIP(TrivialUse, ThinFunctionToPointer)
OPERAND_OWNERSHIP(TrivialUse, ThinToThickFunction)
OPERAND_OWNERSHIP(TrivialUse, TupleElementAddr)
OPERAND_OWNERSHIP(TrivialUse, UncheckedAddrCast)
OPERAND_OWNERSHIP(TrivialUse, UncheckedRefCastAddr)
OPERAND_OWNERSHIP(TrivialUse, UncheckedTakeEnumDataAddr)
OPERAND_OWNERSHIP(TrivialUse, UnconditionalCheckedCastAddr)

// The dealloc_stack_ref operand needs to have NonUse ownership because
// this use comes after the last consuming use (which is usually a dealloc_ref).
OPERAND_OWNERSHIP(NonUse, DeallocStackRef)

// Use an owned or guaranteed value only for the duration of the operation.
OPERAND_OWNERSHIP(InstantaneousUse, ExistentialMetatype)
OPERAND_OWNERSHIP(InstantaneousUse, FixLifetime)
OPERAND_OWNERSHIP(InstantaneousUse, WitnessMethod)
OPERAND_OWNERSHIP(InstantaneousUse, DynamicMethodBranch)
OPERAND_OWNERSHIP(InstantaneousUse, ValueMetatype)
OPERAND_OWNERSHIP(InstantaneousUse, IsEscapingClosure)
OPERAND_OWNERSHIP(InstantaneousUse, ClassMethod)
OPERAND_OWNERSHIP(InstantaneousUse, SuperMethod)
OPERAND_OWNERSHIP(InstantaneousUse, ClassifyBridgeObject)
OPERAND_OWNERSHIP(InstantaneousUse, SetDeallocating)
#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...)            \
  OPERAND_OWNERSHIP(InstantaneousUse, StrongCopy##Name##Value)
#define UNCHECKED_REF_STORAGE(Name, ...)                                       \
  OPERAND_OWNERSHIP(InstantaneousUse, StrongCopy##Name##Value)
#include "swift/AST/ReferenceStorage.def"

// Unowned uses ignore the value's ownership
OPERAND_OWNERSHIP(UnownedInstantaneousUse, DebugValue)
OPERAND_OWNERSHIP(UnownedInstantaneousUse, CopyBlock)
OPERAND_OWNERSHIP(UnownedInstantaneousUse, CopyValue)
OPERAND_OWNERSHIP(UnownedInstantaneousUse, ExplicitCopyValue)
OPERAND_OWNERSHIP(UnownedInstantaneousUse, ObjCMethod)
OPERAND_OWNERSHIP(UnownedInstantaneousUse, ObjCSuperMethod)
OPERAND_OWNERSHIP(UnownedInstantaneousUse, UnmanagedRetainValue)
OPERAND_OWNERSHIP(UnownedInstantaneousUse, UnmanagedReleaseValue)
OPERAND_OWNERSHIP(UnownedInstantaneousUse, UnmanagedAutoreleaseValue)

// These act as a form of conversion that does not imply ownership. Thus from an
// operand perspective we treat them as a pointer escape and from a value
// perspective, they return a value with OwnershipKind::Unowned.
#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...)            \
  OPERAND_OWNERSHIP(PointerEscape, RefTo##Name)                                \
  OPERAND_OWNERSHIP(PointerEscape, Name##ToRef)
#define UNCHECKED_REF_STORAGE(Name, ...)                                       \
  OPERAND_OWNERSHIP(PointerEscape, RefTo##Name)
#include "swift/AST/ReferenceStorage.def"

// Instructions that currently violate structural ownership requirements,
// and therefore completely defeat canonicalization and optimization of any
// OSSA value that they use.
OPERAND_OWNERSHIP(PointerEscape, ProjectBox) // The result is a T*.
OPERAND_OWNERSHIP(PointerEscape, ProjectExistentialBox)
OPERAND_OWNERSHIP(PointerEscape, UncheckedOwnershipConversion)
OPERAND_OWNERSHIP(PointerEscape, ConvertEscapeToNoEscape)

// Instructions that escape reference bits with unenforced lifetime.
// TODO: verify that BitwiseEscape results always have a trivial type.
OPERAND_OWNERSHIP(BitwiseEscape, UncheckedBitwiseCast)
OPERAND_OWNERSHIP(BitwiseEscape, ValueToBridgeObject)
OPERAND_OWNERSHIP(BitwiseEscape, RefToRawPointer)
OPERAND_OWNERSHIP(BitwiseEscape, UncheckedTrivialBitCast)
OPERAND_OWNERSHIP(BitwiseEscape, BridgeObjectToWord)

// Instructions that end the lifetime of an owned value.
OPERAND_OWNERSHIP(DestroyingConsume, AutoreleaseValue)
OPERAND_OWNERSHIP(DestroyingConsume, DeallocBox)
OPERAND_OWNERSHIP(DestroyingConsume, DeallocExistentialBox)
OPERAND_OWNERSHIP(DestroyingConsume, DeallocRef)
OPERAND_OWNERSHIP(DestroyingConsume, DestroyValue)
OPERAND_OWNERSHIP(DestroyingConsume, EndLifetime)
OPERAND_OWNERSHIP(DestroyingConsume, BeginCOWMutation)
OPERAND_OWNERSHIP(DestroyingConsume, EndCOWMutation)

// TODO: Should this be a forwarding consume.
OPERAND_OWNERSHIP(DestroyingConsume, MoveValue)

// Instructions that move an owned value.
OPERAND_OWNERSHIP(ForwardingConsume, InitExistentialValue)
OPERAND_OWNERSHIP(ForwardingConsume, DeinitExistentialValue)
OPERAND_OWNERSHIP(ForwardingConsume, MarkUninitialized)
OPERAND_OWNERSHIP(ForwardingConsume, Throw)

// Instructions that expose a pointer within a borrow scope.
OPERAND_OWNERSHIP(InteriorPointer, RefElementAddr)
OPERAND_OWNERSHIP(InteriorPointer, RefTailAddr)
OPERAND_OWNERSHIP(InteriorPointer, OpenExistentialBox)
// FIXME: HopToExecutorInst should be an instantaneous use.
OPERAND_OWNERSHIP(InteriorPointer, HopToExecutor)
OPERAND_OWNERSHIP(InteriorPointer, ExtractExecutor)

// Instructions that propagate a value value within a borrow scope.
OPERAND_OWNERSHIP(ForwardingBorrow, TupleExtract)
OPERAND_OWNERSHIP(ForwardingBorrow, StructExtract)
OPERAND_OWNERSHIP(ForwardingBorrow, DifferentiableFunctionExtract)
OPERAND_OWNERSHIP(ForwardingBorrow, LinearFunctionExtract)
// FIXME: OpenExistential[Box]Value should be able to take owned values too by
// using getForwardingOperandOwnership.
OPERAND_OWNERSHIP(ForwardingBorrow, OpenExistentialValue)
OPERAND_OWNERSHIP(ForwardingBorrow, OpenExistentialBoxValue)

OPERAND_OWNERSHIP(EndBorrow, EndBorrow)

// The begin_apply token represents the borrow scope of all owned and guaranteed
// call arguments. Although SILToken is (currently) trivially typed, it must
// have guaranteed ownership so end_apply and abort_apply will be recognized
// as lifetime-ending uses.
OPERAND_OWNERSHIP(EndBorrow, EndApply)
OPERAND_OWNERSHIP(EndBorrow, AbortApply)

#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...)                          \
  OPERAND_OWNERSHIP(TrivialUse, Load##Name)
#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...)                         \
  OPERAND_OWNERSHIP(DestroyingConsume, Name##Release)
#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...)                      \
  NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, "...")                              \
  ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, "...")
#define UNCHECKED_REF_STORAGE(Name, ...)                                       \
  OPERAND_OWNERSHIP(TrivialUse, Name##ToRef)
#include "swift/AST/ReferenceStorage.def"

#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...)                          \
  OPERAND_OWNERSHIP(InstantaneousUse, Store##Name)
#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...)                      \
  NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, "...")
#include "swift/AST/ReferenceStorage.def"

#undef OPERAND_OWNERSHIP

// Forwarding operations are conditionally either ForwardingConsumes or
// ForwardingBorrows, depending on the instruction's constant ownership
// attribute.
#define FORWARDING_OWNERSHIP(INST)                                             \
  OperandOwnership OperandOwnershipClassifier::visit##INST##Inst(              \
      INST##Inst *i) {                                                         \
    return i->getForwardingOwnershipKind().getForwardingOperandOwnership(      \
        /*allowUnowned*/ false);                                               \
  }
FORWARDING_OWNERSHIP(Object)
FORWARDING_OWNERSHIP(OpenExistentialRef)
FORWARDING_OWNERSHIP(ConvertFunction)
FORWARDING_OWNERSHIP(RefToBridgeObject)
FORWARDING_OWNERSHIP(BridgeObjectToRef)
FORWARDING_OWNERSHIP(UnconditionalCheckedCast)
FORWARDING_OWNERSHIP(InitExistentialRef)
FORWARDING_OWNERSHIP(DifferentiableFunction)
FORWARDING_OWNERSHIP(LinearFunction)
FORWARDING_OWNERSHIP(MarkMustCheck)
#undef FORWARDING_OWNERSHIP

// Arbitrary value casts are forwarding instructions that are also allowed to
// propagate Unowned values.
#define FORWARDING_ANY_OWNERSHIP(INST)                                         \
  OperandOwnership OperandOwnershipClassifier::visit##INST##Inst(              \
      INST##Inst *i) {                                                         \
    return i->getForwardingOwnershipKind().getForwardingOperandOwnership(      \
        /*allowUnowned*/ true);                                                \
  }
FORWARDING_ANY_OWNERSHIP(Upcast)
FORWARDING_ANY_OWNERSHIP(UncheckedRefCast)
FORWARDING_ANY_OWNERSHIP(UncheckedValueCast)
FORWARDING_ANY_OWNERSHIP(CheckedCastBranch)
#undef FORWARDING_ANY_OWNERSHIP

// Any valid ownership kind can be combined with values of None ownership, but
// they cannot be combined with each other. An aggregates result ownership is
// the meet of its operands' ownership. A destructured member has the same
// ownership as its aggregate unless its type gives it None ownership.
//
// TODO: Aggregate operations should be Reborrows, not ForwardingBorrows,
// because the borrowed value is different on either side of the operation and
// the lifetimes of borrowed members could differ.
#define AGGREGATE_OWNERSHIP(INST)                                              \
  OperandOwnership OperandOwnershipClassifier::visit##INST##Inst(              \
      INST##Inst *i) {                                                         \
    return i->getForwardingOwnershipKind().getForwardingOperandOwnership(      \
        /*allowUnowned*/ true);                                                \
  }
AGGREGATE_OWNERSHIP(Tuple)
AGGREGATE_OWNERSHIP(Struct)
AGGREGATE_OWNERSHIP(DestructureStruct)
AGGREGATE_OWNERSHIP(DestructureTuple)
AGGREGATE_OWNERSHIP(Enum)
AGGREGATE_OWNERSHIP(UncheckedEnumData)
AGGREGATE_OWNERSHIP(SwitchEnum)
#undef AGGREGATE_OWNERSHIP

// A begin_borrow is conditionally nested.
OperandOwnership
OperandOwnershipClassifier::visitBeginBorrowInst(BeginBorrowInst *borrow) {
  return OperandOwnership::Borrow;
}

// MARK: Instructions whose use ownership depends on the operand in question.

OperandOwnership OperandOwnershipClassifier::
visitDeallocPartialRefInst(DeallocPartialRefInst *i) {
  if (getValue() == i->getInstance()) {
    return OperandOwnership::DestroyingConsume;
  }
  return OperandOwnership::TrivialUse;
}

OperandOwnership
OperandOwnershipClassifier::visitSelectEnumInst(SelectEnumInst *i) {
  if (getValue() == i->getEnumOperand()) {
    return OperandOwnership::InstantaneousUse;
  }
  return getOwnershipKind().getForwardingOperandOwnership(
    /*allowUnowned*/true);
}

OperandOwnership
OperandOwnershipClassifier::visitSelectValueInst(SelectValueInst *i) {
  if (getValue() == i->getDefaultResult())
    return OperandOwnership::ForwardingBorrow;

  for (unsigned idx = 0, endIdx = i->getNumCases(); idx < endIdx; ++idx) {
    SILValue casevalue;
    SILValue result;
    std::tie(casevalue, result) = i->getCase(idx);

    if (getValue() == casevalue) {
      return OperandOwnership::ForwardingBorrow;
    }
  }
  return OperandOwnership::TrivialUse;
}

OperandOwnership OperandOwnershipClassifier::visitBranchInst(BranchInst *bi) {
  ValueOwnershipKind destBlockArgOwnershipKind =
      bi->getDestBB()->getArgument(getOperandIndex())->getOwnershipKind();

  // FIXME: remove this special case once all aggregate operations behave just
  // like phis.
  if (destBlockArgOwnershipKind == OwnershipKind::Guaranteed) {
    return OperandOwnership::Reborrow;
  }
  return destBlockArgOwnershipKind.getForwardingOperandOwnership(
    /*allowUnowned*/true);
}

OperandOwnership
OperandOwnershipClassifier::visitStoreBorrowInst(StoreBorrowInst *i) {
  if (getValue() == i->getSrc()) {
    return OperandOwnership::InteriorPointer;
  }
  return OperandOwnership::TrivialUse;
}

// Get the OperandOwnership for instaneous apply, yield, and return uses.
// This does not apply to uses that begin an explicit borrow scope in the
// caller, such as begin_apply.
static OperandOwnership getFunctionArgOwnership(SILArgumentConvention argConv,
                                                bool hasScopeInCaller) {

  switch (argConv) {
  case SILArgumentConvention::Indirect_In:
  case SILArgumentConvention::Direct_Owned:
    return OperandOwnership::ForwardingConsume;

  // A guaranteed argument is forwarded into the callee. If the call itself has
  // no scope (i.e. it is a single apply, try_apply or yield), then from the
  // caller's point of view it looks like an instantaneous use. Consequently,
  // owned values may be passed to guaranteed arguments without an explicit
  // borrow scope in the caller. In contrast, a begin_apply /does/ have an
  // explicit borrow scope in the caller so we must treat arguments passed to it
  // as being borrowed for the entire region of coroutine execution.
  case SILArgumentConvention::Indirect_In_Constant:
  case SILArgumentConvention::Indirect_In_Guaranteed:
  case SILArgumentConvention::Direct_Guaranteed:
    // For an apply that begins a borrow scope, its arguments are borrowed
    // throughout the caller's borrow scope.
    return hasScopeInCaller ? OperandOwnership::Borrow
                            : OperandOwnership::InstantaneousUse;

  case SILArgumentConvention::Direct_Unowned:
    return OperandOwnership::UnownedInstantaneousUse;

  case SILArgumentConvention::Indirect_Out:
  case SILArgumentConvention::Indirect_Inout:
  case SILArgumentConvention::Indirect_InoutAliasable:
    llvm_unreachable("Illegal convention for non-address types");
  }
  llvm_unreachable("covered switch");
}

OperandOwnership
OperandOwnershipClassifier::visitFullApply(FullApplySite apply) {
  // Before considering conventions, filter all (trivial) indirect
  // arguments. This also rules out result arguments.
  if (getValue()->getType().isAddress()) {
    return OperandOwnership::TrivialUse;
  }
  auto calleeTy = apply.getSubstCalleeType();
  SILArgumentConvention argConv = [&]() {
    if (apply.isCalleeOperand(op)) {
      return SILArgumentConvention(calleeTy->getCalleeConvention());
    } else {
      unsigned calleeArgIdx = apply.getCalleeArgIndexOfFirstAppliedArg()
                              + apply.getAppliedArgIndex(op);
      return silConv.getFunctionConventions(calleeTy).getSILArgumentConvention(
          calleeArgIdx);
    }
  }();

  auto argOwnership = getFunctionArgOwnership(
    argConv, /*hasScopeInCaller*/ apply.beginsCoroutineEvaluation());

  // OSSA cleanup needs to handle each of these callee ownership cases.
  //
  // OperandOwnership::ForwardingConsume is only for thick @callee_owned.
  //
  // OperandOwnership::Borrow would only happen for a coroutine closure, which
  // isn't yet possible.
  if (apply.isCalleeOperand(op)) {
    assert((argOwnership == OperandOwnership::TrivialUse
            || argOwnership == OperandOwnership::UnownedInstantaneousUse
            || argOwnership == OperandOwnership::InstantaneousUse
            || argOwnership == OperandOwnership::ForwardingConsume
            || argOwnership == OperandOwnership::Borrow) &&
           "unsupported callee ownership");
  }
  return argOwnership;
}

OperandOwnership
OperandOwnershipClassifier::visitBeginApplyInst(BeginApplyInst *i) {
  return visitFullApply(i);
}

OperandOwnership OperandOwnershipClassifier::visitApplyInst(ApplyInst *i) {
  return visitFullApply(i);
}

OperandOwnership
OperandOwnershipClassifier::visitTryApplyInst(TryApplyInst *i) {
  return visitFullApply(i);
}

OperandOwnership
OperandOwnershipClassifier::visitPartialApplyInst(PartialApplyInst *i) {
  // partial_apply [stack] does not take ownership of its operands.
  if (i->isOnStack()) {
    return OperandOwnership::InstantaneousUse;
  }
  // All non-trivial types should be captured.
  return OperandOwnership::ForwardingConsume;
}

OperandOwnership OperandOwnershipClassifier::visitYieldInst(YieldInst *i) {
  // Before considering conventions, filter all indirect arguments.
  if (getValue()->getType().isAddress()) {
    return OperandOwnership::TrivialUse;
  }
  auto fnType = i->getFunction()->getLoweredFunctionType();
  SILArgumentConvention argConv(
    fnType->getYields()[getOperandIndex()].getConvention());
  return getFunctionArgOwnership(argConv, /*hasScopeInCaller*/ false);
}

OperandOwnership OperandOwnershipClassifier::visitReturnInst(ReturnInst *i) {
  switch (i->getOwnershipKind()) {
  case OwnershipKind::Any:
  case OwnershipKind::Guaranteed:
    llvm_unreachable("invalid value ownership");
  case OwnershipKind::None:
    return OperandOwnership::TrivialUse;
  case OwnershipKind::Unowned:
    return OperandOwnership::UnownedInstantaneousUse;
  case OwnershipKind::Owned:
    return OperandOwnership::ForwardingConsume;
  }
  llvm_unreachable("covered switch");
}

OperandOwnership OperandOwnershipClassifier::visitAssignInst(AssignInst *i) {
  if (getValue() != i->getSrc()) {
    return OperandOwnership::TrivialUse;
  }
  return OperandOwnership::DestroyingConsume;
}

OperandOwnership
OperandOwnershipClassifier::visitAssignByWrapperInst(AssignByWrapperInst *i) {
  if (getValue() == i->getSrc()) {
    return OperandOwnership::DestroyingConsume;
  }
  if (getValue() == i->getDest()) {
    return OperandOwnership::TrivialUse;
  }
  return OperandOwnership::InstantaneousUse; // initializer/setter closure
}

OperandOwnership OperandOwnershipClassifier::visitStoreInst(StoreInst *i) {
  if (getValue() != i->getSrc()) {
    return OperandOwnership::TrivialUse;
  }
  return OperandOwnership::DestroyingConsume;
}

OperandOwnership OperandOwnershipClassifier::visitCopyBlockWithoutEscapingInst(
    CopyBlockWithoutEscapingInst *i) {
  // Consumes the closure parameter.
  if (getValue() == i->getClosure()) {
    return OperandOwnership::ForwardingConsume;
  }
  return OperandOwnership::UnownedInstantaneousUse;
}

OperandOwnership
OperandOwnershipClassifier::visitMarkDependenceInst(MarkDependenceInst *mdi) {
  // If we are analyzing "the value", we forward ownership.
  if (getValue() == mdi->getValue()) {
    return getOwnershipKind().getForwardingOperandOwnership(
      /*allowUnowned*/true);
  }
  // FIXME: Add an end_dependence instruction so we can treat mark_dependence as
  // a borrow of the base (mark_dependence %base -> end_dependence is analogous
  // to a borrow scope).
  return OperandOwnership::PointerEscape;
}

OperandOwnership OperandOwnershipClassifier::visitKeyPathInst(KeyPathInst *I) {
  // KeyPath moves the value in memory out of address operands, but the
  // ownership checker doesn't reason about that yet.
  return OperandOwnership::ForwardingConsume;
}

//===----------------------------------------------------------------------===//
//                            Builtin Use Checker
//===----------------------------------------------------------------------===//

namespace {

struct OperandOwnershipBuiltinClassifier
    : SILBuiltinVisitor<OperandOwnershipBuiltinClassifier, OperandOwnership> {
  using Map = OperandOwnership;
      
  const Operand &op;
  OperandOwnershipBuiltinClassifier(const Operand &op) : op(op) {}

  OperandOwnership visitLLVMIntrinsic(BuiltinInst *bi, llvm::Intrinsic::ID id) {
    // LLVM intrinsics do not traffic in ownership, so if we have a result, it
    // must be trivial.
    return OperandOwnership::TrivialUse;
  }

  // BUILTIN_TYPE_CHECKER_OPERATION does not live past the type checker.
#define BUILTIN_TYPE_CHECKER_OPERATION(ID, NAME)

#define BUILTIN(ID, NAME, ATTRS)                                               \
  OperandOwnership visit##ID(BuiltinInst *bi, StringRef attr);
#include "swift/AST/Builtins.def"

  OperandOwnership check(BuiltinInst *bi) { return visit(bi); }
};

} // end anonymous namespace

#define BUILTIN_OPERAND_OWNERSHIP(OWNERSHIP, ID)                               \
  OperandOwnership                                                             \
  OperandOwnershipBuiltinClassifier::visit##ID(BuiltinInst *, StringRef) {     \
    return OperandOwnership::OWNERSHIP;                                        \
  }
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ErrorInMain)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, UnexpectedError)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, WillThrow)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AShr)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericAShr)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Add)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericAdd)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Alignof)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AllocRaw)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, And)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericAnd)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AssertConf)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AssignCopyArrayNoAlias)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AssignCopyArrayFrontToBack)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AssignCopyArrayBackToFront)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AssignTakeArray)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AssumeAlignment)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AssumeNonNegative)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AssumeTrue)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AtomicLoad)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AtomicRMW)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AtomicStore)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, BitCast)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, CanBeObjCClass)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, CondFailMessage)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, CmpXChg)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, CondUnreachable)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, CopyArray)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, DeallocRaw)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, DestroyArray)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ExactSDiv)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericExactSDiv)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ExactUDiv)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericExactUDiv)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ExtractElement)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FAdd)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericFAdd)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FCMP_OEQ)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FCMP_OGE)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FCMP_OGT)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FCMP_OLE)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FCMP_OLT)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FCMP_ONE)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FCMP_ORD)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FCMP_UEQ)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FCMP_UGE)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FCMP_UGT)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FCMP_ULE)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FCMP_ULT)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FCMP_UNE)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FCMP_UNO)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FDiv)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericFDiv)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FMul)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericFMul)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FNeg)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FPExt)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FPToSI)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FPToUI)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FPTrunc)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FRem)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericFRem)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FSub)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericFSub)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Fence)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Ifdef)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GetObjCTypeEncoding)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ICMP_EQ)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ICMP_NE)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ICMP_SGE)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ICMP_SGT)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ICMP_SLE)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ICMP_SLT)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ICMP_UGE)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ICMP_UGT)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ICMP_ULE)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ICMP_ULT)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, InsertElement)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, IntToFPWithOverflow)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, IntToPtr)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, IsOptionalType)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, IsPOD)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, IsConcrete)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, IsBitwiseTakable)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, IsSameMetatype)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, LShr)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericLShr)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Mul)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericMul)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, OnFastPath)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Once)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, OnceWithContext)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Or)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericOr)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, PtrToInt)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, SAddOver)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, SDiv)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericSDiv)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, SExt)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, SExtOrBitCast)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, SIToFP)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, SMulOver)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, SRem)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericSRem)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, SSubOver)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, StackAlloc)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, StackDealloc)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, SToSCheckedTrunc)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, SToUCheckedTrunc)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Expect)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Shl)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericShl)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ShuffleVector)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Sizeof)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, StaticReport)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Strideof)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, StringObjectOr)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Sub)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericSub)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, TakeArrayNoAlias)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, TakeArrayBackToFront)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, TakeArrayFrontToBack)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Trunc)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, TruncOrBitCast)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, TSanInoutAccess)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, UAddOver)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, UDiv)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericUDiv)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, UIToFP)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, UMulOver)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, URem)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericURem)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, USubOver)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, UToSCheckedTrunc)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, UToUCheckedTrunc)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Unreachable)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, UnsafeGuaranteedEnd)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Xor)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GenericXor)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ZExt)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ZExtOrBitCast)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, ZeroInitializer)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Swift3ImplicitObjCEntrypoint)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, PoundAssert)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GlobalStringTablePointer)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, TypePtrAuthDiscriminator)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, TargetOSVersionAtLeast)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, IntInstrprofIncrement)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, Move)
BUILTIN_OPERAND_OWNERSHIP(UnownedInstantaneousUse, Copy)
BUILTIN_OPERAND_OWNERSHIP(DestroyingConsume, StartAsyncLet)
BUILTIN_OPERAND_OWNERSHIP(DestroyingConsume, EndAsyncLet)
BUILTIN_OPERAND_OWNERSHIP(DestroyingConsume, StartAsyncLetWithLocalBuffer)
BUILTIN_OPERAND_OWNERSHIP(DestroyingConsume, EndAsyncLetLifetime)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, CreateTaskGroup)
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, DestroyTaskGroup)

BUILTIN_OPERAND_OWNERSHIP(ForwardingConsume, COWBufferForReading)
BUILTIN_OPERAND_OWNERSHIP(ForwardingConsume, UnsafeGuaranteed)

const int PARAMETER_INDEX_CREATE_ASYNC_TASK_FUTURE_FUNCTION = 2;
const int PARAMETER_INDEX_CREATE_ASYNC_TASK_GROUP_FUTURE_FUNCTION = 3;

OperandOwnership
OperandOwnershipBuiltinClassifier::visitCreateAsyncTask(BuiltinInst *bi,
                                                        StringRef attr) {
  // The function operand is consumed by the new task.
  if (&op == &bi->getOperandRef(PARAMETER_INDEX_CREATE_ASYNC_TASK_FUTURE_FUNCTION))
    return OperandOwnership::DestroyingConsume;
  
  // FIXME: These are considered InteriorPointer because they may propagate a
  // pointer into a borrowed values. If they do not propagate an interior pointer,
  // then they should be InstantaneousUse instead and should not require a
  // guaranteed value.
  return OperandOwnership::InteriorPointer;
}

OperandOwnership
OperandOwnershipBuiltinClassifier::visitCreateAsyncTaskInGroup(BuiltinInst *bi,
                                                               StringRef attr) {
  // The function operand is consumed by the new task.
  if (&op == &bi->getOperandRef(PARAMETER_INDEX_CREATE_ASYNC_TASK_GROUP_FUTURE_FUNCTION))
    return OperandOwnership::DestroyingConsume;
  
  // FIXME: These are considered InteriorPointer because they may propagate a
  // pointer into a borrowed values. If they do not propagate an interior pointer,
  // then they should be InstantaneousUse instead and should not require a
  // guaranteed value.
  return OperandOwnership::InteriorPointer;
}

OperandOwnership OperandOwnershipBuiltinClassifier::
visitResumeNonThrowingContinuationReturning(BuiltinInst *bi, StringRef attr) {
  // The value operand is consumed.
  if (&op == &bi->getOperandRef(1))
    return OperandOwnership::DestroyingConsume;

  return OperandOwnership::TrivialUse;
}

OperandOwnership OperandOwnershipBuiltinClassifier::
visitResumeThrowingContinuationReturning(BuiltinInst *bi, StringRef attr) {
  // The value operand is consumed.
  if (&op == &bi->getOperandRef(1))
    return OperandOwnership::DestroyingConsume;

  return OperandOwnership::TrivialUse;
}

OperandOwnership OperandOwnershipBuiltinClassifier::
visitResumeThrowingContinuationThrowing(BuiltinInst *bi, StringRef attr) {
  // The value operand is consumed.
  if (&op == &bi->getOperandRef(1))
    return OperandOwnership::DestroyingConsume;

  return OperandOwnership::TrivialUse;
}

BUILTIN_OPERAND_OWNERSHIP(InteriorPointer, CancelAsyncTask)
BUILTIN_OPERAND_OWNERSHIP(InteriorPointer, InitializeDefaultActor)
BUILTIN_OPERAND_OWNERSHIP(InteriorPointer, DestroyDefaultActor)

BUILTIN_OPERAND_OWNERSHIP(InteriorPointer, InitializeDistributedRemoteActor)

BUILTIN_OPERAND_OWNERSHIP(PointerEscape, AutoDiffAllocateSubcontext)
BUILTIN_OPERAND_OWNERSHIP(PointerEscape, AutoDiffProjectTopLevelSubcontext)

// FIXME: ConvertTaskToJob is documented as taking NativePointer. It's operand's
// ownership should be 'TrivialUse'.
BUILTIN_OPERAND_OWNERSHIP(ForwardingConsume, ConvertTaskToJob)

BUILTIN_OPERAND_OWNERSHIP(BitwiseEscape, BuildOrdinarySerialExecutorRef)
BUILTIN_OPERAND_OWNERSHIP(BitwiseEscape, BuildDefaultActorExecutorRef)
BUILTIN_OPERAND_OWNERSHIP(BitwiseEscape, BuildMainActorExecutorRef)

BUILTIN_OPERAND_OWNERSHIP(TrivialUse, AutoDiffCreateLinearMapContext)

#undef BUILTIN_OPERAND_OWNERSHIP

#define SHOULD_NEVER_VISIT_BUILTIN(ID)                                         \
  OperandOwnership                                                             \
  OperandOwnershipBuiltinClassifier::visit##ID(BuiltinInst *, StringRef) {     \
    llvm_unreachable(                                                          \
        "Builtin should never be visited! E.x.: It may not have arguments");   \
  }
SHOULD_NEVER_VISIT_BUILTIN(GetCurrentAsyncTask)
SHOULD_NEVER_VISIT_BUILTIN(GetCurrentExecutor)
#undef SHOULD_NEVER_VISIT_BUILTIN

// Builtins that should be lowered to SIL instructions so we should never see
// them.
#define BUILTIN_SIL_OPERATION(ID, NAME, CATEGORY)                              \
  OperandOwnership                                                             \
  OperandOwnershipBuiltinClassifier::visit##ID(BuiltinInst *, StringRef) {     \
    llvm_unreachable("Builtin should have been lowered to SIL instruction?!"); \
  }
#define BUILTIN(X, Y, Z)
#include "swift/AST/Builtins.def"

OperandOwnership OperandOwnershipClassifier::visitBuiltinInst(BuiltinInst *bi) {
  return OperandOwnershipBuiltinClassifier(op).check(bi);
}

//===----------------------------------------------------------------------===//
//                            Top Level Entrypoint
//===----------------------------------------------------------------------===//

OperandOwnership
Operand::getOperandOwnership(SILModuleConventions *silConv) const {
  // A type-dependent operand is a NonUse (as opposed to say an
  // InstantaneousUse) because it does not require liveness.
  if (isTypeDependent())
    return OperandOwnership::NonUse;

  // If we do not have ownership enabled, just return any. This ensures that we
  // do not have any consuming uses and everything from an ownership perspective
  // is just a liveness use short-circuiting many of the optimizations.
  //
  // We do not ever call this function when an instruction isn't in a block.
  assert(getUser()->getParent() &&
         "Can not lookup ownership constraint unless inserted into block");
  if (auto *block = getUser()->getParent()) {
    auto *func = block->getParent();
    // If we don't have a function, then we must have a SILGlobalVariable. In
    // that case, we act as if we aren't in ownership.
    if (!func || !func->hasOwnership()) {
      return OperandOwnership(OperandOwnership::InstantaneousUse);
    }
  }
  SILModuleConventions overrideConv =
      silConv ? *silConv : SILModuleConventions(getUser()->getModule());
  OperandOwnershipClassifier classifier(overrideConv, *this);
  return classifier.visit(const_cast<SILInstruction *>(getUser()));
}
