static SILValue stripRCIdentityPreservingInsts(SILValue V) {
  // First strip off RC identity preserving casts.
  if (isRCIdentityPreservingCast(V->getKind()))
    return cast<SILInstruction>(V)->getOperand(0);

  // Then if we have a struct_extract that is extracting a non-trivial member
  // from a struct with no other non-trivial members, a ref count operation on
  // the struct is equivalent to a ref count operation on the extracted
  // member. Strip off the extract.
  if (auto *SEI = dyn_cast<StructExtractInst>(V))
    if (SEI->isFieldOnlyNonTrivialField())
      return SEI->getOperand();

  // If we have a struct instruction with only one non-trivial stored field, the
  // only reference count that can be modified is the non-trivial field. Return
  // the non-trivial field.
  if (auto *SI = dyn_cast<StructInst>(V))
    if (SILValue NewValue = SI->getUniqueNonTrivialFieldValue())
      return NewValue;

  // If we have an unchecked_enum_data, strip off the unchecked_enum_data.
  if (auto *UEDI = dyn_cast<UncheckedEnumDataInst>(V))
    return UEDI->getOperand();

  // If we have an enum instruction with a payload, strip off the enum to
  // expose the enum's payload.
  if (auto *EI = dyn_cast<EnumInst>(V))
    if (EI->hasOperand())
      return EI->getOperand();

  // If we have a tuple_extract that is extracting the only non trivial member
  // of a tuple, a retain_value on the tuple is equivalent to a retain_value on
  // the extracted value.
  if (auto *TEI = dyn_cast<TupleExtractInst>(V))
    if (TEI->isEltOnlyNonTrivialElt())
      return TEI->getOperand();

  // If we are forming a tuple and the tuple only has one element with reference
  // semantics, a retain_value on the tuple is equivalent to a retain value on
  // the tuple operand.
  if (auto *TI = dyn_cast<TupleInst>(V))
    if (SILValue NewValue = TI->getUniqueNonTrivialElt())
      return NewValue;

  // Any SILArgument with a single predecessor from a "phi" perspective is
  // dead. In such a case, the SILArgument must be rc-identical.
  //
  // This is the easy case. The difficult case is when you have an argument with
  // /multiple/ predecessors.
  //
  // We do not need to insert this SILArgument into the visited SILArgument set
  // since we will only visit it twice if we go around a back edge due to a
  // different SILArgument that is actually being used for its phi node like
  // purposes.
  if (auto *A = dyn_cast<SILArgument>(V))
    if (SILValue Result = A->getSingleIncomingValue())
      return Result;

  return SILValue();
}
Exemple #2
0
AccessedStorage::Kind AccessedStorage::classify(SILValue base) {
  switch (base->getKind()) {
  // An AllocBox is a fully identified memory location.
  case ValueKind::AllocBoxInst:
    return Box;
  // An AllocStack is a fully identified memory location, which may occur
  // after inlining code already subjected to stack promotion.
  case ValueKind::AllocStackInst:
    return Stack;
  case ValueKind::GlobalAddrInst:
    return Global;
  case ValueKind::RefElementAddrInst:
    return Class;
  // A function argument is effectively a nested access, enforced
  // independently in the caller and callee.
  case ValueKind::SILFunctionArgument:
    return Argument;
  // View the outer begin_access as a separate location because nested
  // accesses do not conflict with each other.
  case ValueKind::BeginAccessInst:
    return Nested;
  default:
    return Unidentified;
  }
}
Exemple #3
0
// Return the list of functions that can be called via the given callee.
CalleeList CalleeCache::getCalleeListForCalleeKind(SILValue Callee) const {
  switch (Callee->getKind()) {
  default:
    assert(!isa<MethodInst>(Callee) &&
           "Unhandled method instruction in callee determination!");
    return CalleeList();

  case ValueKind::ThinToThickFunctionInst:
    Callee = cast<ThinToThickFunctionInst>(Callee)->getOperand();
    SWIFT_FALLTHROUGH;

  case ValueKind::FunctionRefInst:
    return CalleeList(cast<FunctionRefInst>(Callee)->getReferencedFunction());

  case ValueKind::PartialApplyInst:
    return getCalleeListForCalleeKind(
        cast<PartialApplyInst>(Callee)->getCallee());

  case ValueKind::WitnessMethodInst:
    return getCalleeList(cast<WitnessMethodInst>(Callee));

  case ValueKind::ClassMethodInst:
    return getCalleeList(cast<ClassMethodInst>(Callee));

  case ValueKind::SuperMethodInst:
  case ValueKind::DynamicMethodInst:
    return CalleeList();
  }
}
Exemple #4
0
/// Is this a literal which we know cannot refer to a global object?
///
/// FIXME: function_ref?
static bool isLocalLiteral(SILValue V) {
  switch (V->getKind()) {
  case ValueKind::IntegerLiteralInst:
  case ValueKind::FloatLiteralInst:
  case ValueKind::StringLiteralInst:
    return true;
  default:
    return false;
  }
}
SILValue swift::stripAddressAccess(SILValue V) {
  while (true) {
    switch (V->getKind()) {
    default:
      return V;
    case ValueKind::BeginBorrowInst:
    case ValueKind::BeginAccessInst:
      V = cast<SingleValueInstruction>(V)->getOperand(0);
    }
  }
}
SILValue swift::stripOwnershipInsts(SILValue v) {
  while (true) {
    switch (v->getKind()) {
    default:
      return v;
    case ValueKind::CopyValueInst:
    case ValueKind::BeginBorrowInst:
      v = cast<SingleValueInstruction>(v)->getOperand(0);
    }
  }
}
Exemple #7
0
/// Return true if the given value is an instruction or block argument that is
/// known to produce a nonaliasing address with respect to TBAA rules (i.e. the
/// pointer is not type punned). The only way to produce an aliasing typed
/// address is with pointer_to_address (via UnsafePointer) or
/// unchecked_addr_cast (via Builtin.reinterpretCast). Consequently, if the
/// given value is directly derived from a memory location, it cannot
/// alias. Call arguments also cannot alias because they must follow \@in, @out,
/// @inout, or \@in_guaranteed conventions.
///
/// FIXME: pointer_to_address should contain a flag that indicates whether the
/// address is aliasing. Currently, we aggressively assume that
/// pointer-to-address is never used for type punning, which is not yet
/// clearly specified by our UnsafePointer API.
static bool isAddressRootTBAASafe(SILValue V) {
  if (auto *Arg = dyn_cast<SILArgument>(V))
    return Arg->isFunctionArg();

  switch (V->getKind()) {
  default:
    return false;
  case ValueKind::AllocStackInst:
  case ValueKind::AllocBoxInst:
  case ValueKind::PointerToAddressInst:
    return true;
  }
}
SILValue swift::stripCastsWithoutMarkDependence(SILValue V) {
  while (true) {
    V = stripSinglePredecessorArgs(V);

    auto K = V->getKind();
    if (isRCIdentityPreservingCast(K) ||
        K == ValueKind::UncheckedTrivialBitCastInst) {
      V = cast<SingleValueInstruction>(V)->getOperand(0);
      continue;
    }

    return V;
  }
}
Exemple #9
0
static SILValue skipValueProjections(SILValue V) {
  for (;;) {
    switch (V->getKind()) {
      case ValueKind::StructExtractInst:
      case ValueKind::TupleExtractInst:
      case ValueKind::UncheckedEnumDataInst:
      case ValueKind::UncheckedTrivialBitCastInst:
        V = cast<SILInstruction>(V)->getOperand(0);
        break;
      default:
        return V;
    }
  }
  llvm_unreachable("there is no escape from an infinite loop");
}
Exemple #10
0
void Operand::hoistAddressProjections(SILInstruction *InsertBefore,
                                      DominanceInfo *DomTree) {
  SILValue V = get();
  SILInstruction *Prev = nullptr;
  auto *InsertPt = InsertBefore;
  while (true) {
    SILValue Incoming = stripSinglePredecessorArgs(V);

    // Forward the incoming arg from a single predeccessor.
    if (V != Incoming) {
      if (V == get()) {
        // If we are the operand itself set the operand to the incoming
        // argument.
        set(Incoming);
        V = Incoming;
      } else {
        // Otherwise, set the previous projections operand to the incoming
        // argument.
        assert(Prev && "Must have seen a projection");
        Prev->setOperand(0, Incoming);
        V = Incoming;
      }
    }

    switch (V->getKind()) {
    case ValueKind::StructElementAddrInst:
    case ValueKind::TupleElementAddrInst:
    case ValueKind::RefElementAddrInst:
    case ValueKind::UncheckedTakeEnumDataAddrInst: {
      auto *Inst = cast<SILInstruction>(V);
      // We are done once the current projection dominates the insert point.
      if (DomTree->dominates(Inst->getParent(), InsertBefore->getParent()))
        return;

      // Move the current projection and memorize it for the next iteration.
      Prev = Inst;
      Inst->moveBefore(InsertPt);
      InsertPt = Inst;
      V = Inst->getOperand(0);
      continue;
    }
    default:
      assert(DomTree->dominates(V->getParentBB(), InsertBefore->getParent()) &&
             "The projected value must dominate the insertion point");
      return;
    }
  }
}
Exemple #11
0
SILValue SILValue::stripValueProjections() {
  SILValue V = *this;

  while (true) {
    V = stripSinglePredecessorArgs(V);

    switch (V->getKind()) {
    case ValueKind::StructExtractInst:
    case ValueKind::TupleExtractInst:
      V = cast<SILInstruction>(V.getDef())->getOperand(0);
      continue;
    default:
      return V;
    }
  }
}
Exemple #12
0
/// Return true if the given value is an instruction or block argument that is
/// known to produce a nonaliasing address with respect to TBAA rules (i.e. the
/// pointer is not type punned). The only way to produce an aliasing typed
/// address is with pointer_to_address (via UnsafePointer) or
/// unchecked_addr_cast (via Builtin.reinterpretCast). Consequently, if the
/// given value is directly derived from a memory location, it cannot
/// alias. Call arguments also cannot alias because they must follow \@in, @out,
/// @inout, or \@in_guaranteed conventions.
static bool isAddressRootTBAASafe(SILValue V) {
  if (isa<SILFunctionArgument>(V))
    return true;

  if (auto *PtrToAddr = dyn_cast<PointerToAddressInst>(V))
    return PtrToAddr->isStrict();

  switch (V->getKind()) {
  default:
    return false;
  case ValueKind::AllocStackInst:
  case ValueKind::ProjectBoxInst:
  case ValueKind::RefElementAddrInst:
  case ValueKind::RefTailAddrInst:
    return true;
  }
}
Exemple #13
0
SILValue SILValue::stripCasts() {
  SILValue V = *this;

  while (true) {
    V = stripSinglePredecessorArgs(V);

    auto K = V->getKind();
    if (isRCIdentityPreservingCast(K)
        || K == ValueKind::UncheckedTrivialBitCastInst
        || K == ValueKind::MarkDependenceInst) {
      V = cast<SILInstruction>(V.getDef())->getOperand(0);
      continue;
    }

    return V;
  }
}
static SILValue skipAddrProjections(SILValue V) {
  for (;;) {
    switch (V->getKind()) {
      case ValueKind::IndexAddrInst:
      case ValueKind::IndexRawPointerInst:
      case ValueKind::StructElementAddrInst:
      case ValueKind::TupleElementAddrInst:
      case ValueKind::RefElementAddrInst:
      case ValueKind::UncheckedTakeEnumDataAddrInst:
      case ValueKind::PointerToAddressInst:
        V = cast<SILInstruction>(V)->getOperand(0);
        break;
      default:
        return V;
    }
  }
  llvm_unreachable("there is no escape from an infinite loop");
}
Exemple #15
0
SILValue SILValue::stripAddressProjections() {
  SILValue V = *this;

  while (true) {
    V = stripSinglePredecessorArgs(V);

    switch (V->getKind()) {
    case ValueKind::StructElementAddrInst:
    case ValueKind::TupleElementAddrInst:
    case ValueKind::RefElementAddrInst:
    case ValueKind::UncheckedTakeEnumDataAddrInst:
      V = cast<SILInstruction>(V.getDef())->getOperand(0);
      continue;
    default:
      return V;
    }
  }
}
Exemple #16
0
SILValue swift::stripCasts(SILValue v) {
  while (true) {
    v = stripSinglePredecessorArgs(v);
    
    auto k = v->getKind();
    if (isRCIdentityPreservingCast(k)
        || k == ValueKind::UncheckedTrivialBitCastInst
        || k == ValueKind::MarkDependenceInst) {
      v = cast<SingleValueInstruction>(v)->getOperand(0);
      continue;
    }

    SILValue v2 = stripOwnershipInsts(v);
    if (v2 != v) {
      v = v2;
      continue;
    }

    return v;
  }
}
Exemple #17
0
/// Return true if the given address value is produced by a special address
/// producer that is only used for local initialization, not formal access.
static bool isAddressForLocalInitOnly(SILValue sourceAddr) {
  switch (sourceAddr->getKind()) {
  default:
    return false;

  // Value to address conversions: the operand is the non-address source
  // value. These allow local mutation of the value but should never be used
  // for formal access of an lvalue.
  case ValueKind::OpenExistentialBoxInst:
  case ValueKind::ProjectExistentialBoxInst:
    return true;

  // Self-evident local initialization.
  case ValueKind::InitEnumDataAddrInst:
  case ValueKind::InitExistentialAddrInst:
  case ValueKind::AllocExistentialBoxInst:
  case ValueKind::AllocValueBufferInst:
  case ValueKind::ProjectValueBufferInst:
    return true;
  }
}
Exemple #18
0
FunctionSideEffectFlags *FunctionSideEffects::getEffectsOn(SILValue Addr) {
  SILValue BaseAddr = skipValueProjections(skipAddrProjections(Addr));
  switch (BaseAddr->getKind()) {
  case swift::ValueKind::SILFunctionArgument: {
    // Can we associate the address to a function parameter?
    auto *Arg = cast<SILFunctionArgument>(BaseAddr);
    return &ParamEffects[Arg->getIndex()];
    break;
    }
    case ValueKind::AllocStackInst:
    case ValueKind::AllocRefInst:
    case ValueKind::AllocRefDynamicInst:
    case ValueKind::AllocBoxInst:
      // Effects on locally allocated storage.
      return &LocalEffects;
    default:
      break;
  }
  // Everything else.
  return &GlobalEffects;
}
Exemple #19
0
AccessedStorage::Kind AccessedStorage::classify(SILValue base) {
  switch (base->getKind()) {
  // An AllocBox is a fully identified memory location.
  case ValueKind::AllocBoxInst:
    return Box;
  // An AllocStack is a fully identified memory location, which may occur
  // after inlining code already subjected to stack promotion.
  case ValueKind::AllocStackInst:
    return Stack;
  case ValueKind::GlobalAddrInst:
    return Global;
  case ValueKind::ApplyInst: {
    FullApplySite apply(cast<ApplyInst>(base));
    if (auto *funcRef = apply.getReferencedFunction()) {
      if (getVariableOfGlobalInit(funcRef))
        return Global;
    }
    return Unidentified;
  }
  case ValueKind::RefElementAddrInst:
    return Class;
  // A yield is effectively a nested access, enforced independently in
  // the caller and callee.
  case ValueKind::BeginApplyResult:
    return Yield;
  // A function argument is effectively a nested access, enforced
  // independently in the caller and callee.
  case ValueKind::SILFunctionArgument:
    return Argument;
  // View the outer begin_access as a separate location because nested
  // accesses do not conflict with each other.
  case ValueKind::BeginAccessInst:
    return Nested;
  default:
    return Unidentified;
  }
}
Exemple #20
0
AccessedStorage swift::findAccessedStorage(SILValue sourceAddr) {
  SILValue address = sourceAddr;
  while (true) {
    AccessedStorage::Kind kind = AccessedStorage::classify(address);
    // First handle identified cases: these are always valid as the base of a
    // formal access.
    if (kind != AccessedStorage::Unidentified)
      return AccessedStorage(address, kind);

    // Handle other unidentified address sources.
    switch (address->getKind()) {
    default:
      if (isAddressForLocalInitOnly(address))
        return AccessedStorage(address, AccessedStorage::Unidentified);
      return AccessedStorage();

    case ValueKind::PointerToAddressInst:
    case ValueKind::SILUndef:
      return AccessedStorage(address, AccessedStorage::Unidentified);

    // A block argument may be a box value projected out of
    // switch_enum. Address-type block arguments are not allowed.
    case ValueKind::SILPHIArgument:
      if (address->getType().isAddress())
        return AccessedStorage();

      checkSwitchEnumBlockArg(cast<SILPHIArgument>(address));
      return AccessedStorage(address, AccessedStorage::Unidentified);

    // Load a box from an indirect payload of an opaque enum.
    // We must have peeked past the project_box earlier in this loop.
    // (the indirectness makes it a box, the load is for address-only).
    // 
    // %payload_adr = unchecked_take_enum_data_addr %enum : $*Enum, #Enum.case
    // %box = load [take] %payload_adr : $*{ var Enum }
    //
    // FIXME: this case should go away with opaque values.
    case ValueKind::LoadInst: {
      assert(address->getType().is<SILBoxType>());
      address = cast<LoadInst>(address)->getOperand();
      assert(isa<UncheckedTakeEnumDataAddrInst>(address));
      continue;
    }
    // Inductive cases:
    // Look through address casts to find the source address.
    case ValueKind::MarkUninitializedInst:
    case ValueKind::OpenExistentialAddrInst:
    case ValueKind::UncheckedAddrCastInst:
    // Inductive cases that apply to any type.
    case ValueKind::CopyValueInst:
    case ValueKind::MarkDependenceInst:
    // Look through a project_box to identify the underlying alloc_box as the
    // accesed object. It must be possible to reach either the alloc_box or the
    // containing enum in this loop, only looking through simple value
    // propagation such as copy_value.
    case ValueKind::ProjectBoxInst:
    // Handle project_block_storage just like project_box.
    case ValueKind::ProjectBlockStorageInst:
    // Look through begin_borrow in case a local box is borrowed.
    case ValueKind::BeginBorrowInst:
      address = cast<SingleValueInstruction>(address)->getOperand(0);
      continue;

    // Subobject projections.
    case ValueKind::StructElementAddrInst:
    case ValueKind::TupleElementAddrInst:
    case ValueKind::UncheckedTakeEnumDataAddrInst:
    case ValueKind::RefTailAddrInst:
    case ValueKind::TailAddrInst:
    case ValueKind::IndexAddrInst:
      address = cast<SingleValueInstruction>(address)->getOperand(0);
      continue;
    }
  }
}
Exemple #21
0
/// Check if the value \p Value is known to be zero, non-zero or unknown.
IsZeroKind swift::isZeroValue(SILValue Value) {
  // Inspect integer literals.
  if (auto *L = dyn_cast<IntegerLiteralInst>(Value)) {
    if (!L->getValue())
      return IsZeroKind::Zero;
    return IsZeroKind::NotZero;
  }

  // Inspect Structs.
  switch (Value->getKind()) {
    // Bitcast of zero is zero.
    case ValueKind::UncheckedTrivialBitCastInst:
    // Extracting from a zero class returns a zero.
    case ValueKind::StructExtractInst:
      return isZeroValue(cast<SILInstruction>(Value)->getOperand(0));
    default:
      break;
  }

  // Inspect casts.
  if (auto *BI = dyn_cast<BuiltinInst>(Value)) {
    switch (BI->getBuiltinInfo().ID) {
      case BuiltinValueKind::IntToPtr:
      case BuiltinValueKind::PtrToInt:
      case BuiltinValueKind::ZExt:
        return isZeroValue(BI->getArguments()[0]);
      case BuiltinValueKind::UDiv:
      case BuiltinValueKind::SDiv: {
        if (IsZeroKind::Zero == isZeroValue(BI->getArguments()[0]))
          return IsZeroKind::Zero;
        return IsZeroKind::Unknown;
      }
      case BuiltinValueKind::Mul:
      case BuiltinValueKind::SMulOver:
      case BuiltinValueKind::UMulOver: {
        IsZeroKind LHS = isZeroValue(BI->getArguments()[0]);
        IsZeroKind RHS = isZeroValue(BI->getArguments()[1]);
        if (LHS == IsZeroKind::Zero || RHS == IsZeroKind::Zero)
          return IsZeroKind::Zero;

        return IsZeroKind::Unknown;
      }
      default:
        return IsZeroKind::Unknown;
    }
  }

  // Handle results of XXX_with_overflow arithmetic.
  if (auto *T = dyn_cast<TupleExtractInst>(Value)) {
    // Make sure we are extracting the number value and not
    // the overflow flag.
    if (T->getFieldNo() != 0)
      return IsZeroKind::Unknown;

    BuiltinInst *BI = dyn_cast<BuiltinInst>(T->getOperand());
    if (!BI)
      return IsZeroKind::Unknown;

    return isZeroValue(BI);
  }

  //Inspect allocations and pointer literals.
  if (isa<StringLiteralInst>(Value) ||
      isa<AllocationInst>(Value) ||
      isa<GlobalAddrInst>(Value))
    return IsZeroKind::NotZero;

  return IsZeroKind::Unknown;
}
Exemple #22
0
// AccessEnforcementWMO makes a strong assumption that all accesses are either
// identified or are *not* accessing a global variable or class property defined
// in this module. Consequently, we cannot simply bail out on
// PointerToAddressInst as an Unidentified access.
static AccessedStorageResult getAccessedStorageFromAddress(SILValue sourceAddr) {
  AccessedStorage::Kind kind = AccessedStorage::classify(sourceAddr);
  // First handle identified cases: these are always valid as the base of
  // a formal access.
  if (kind != AccessedStorage::Unidentified)
    return AccessedStorage(sourceAddr, kind);

  // If the sourceAddr producer cannot immediately be classified, follow the
  // use-def chain of sourceAddr, box, or RawPointer producers.
  assert(sourceAddr->getType().isAddress()
         || isa<SILBoxType>(sourceAddr->getType().getASTType())
         || isa<BuiltinRawPointerType>(sourceAddr->getType().getASTType()));

  // Handle other unidentified address sources.
  switch (sourceAddr->getKind()) {
  default:
    if (isAddressForLocalInitOnly(sourceAddr))
      return AccessedStorage(sourceAddr, AccessedStorage::Unidentified);
    return AccessedStorage();

  case ValueKind::SILUndef:
    return AccessedStorage(sourceAddr, AccessedStorage::Unidentified);

  case ValueKind::ApplyInst:
    if (isExternalGlobalAddressor(cast<ApplyInst>(sourceAddr)))
      return AccessedStorage(sourceAddr, AccessedStorage::Unidentified);

    // Don't currently allow any other calls to return an accessed address.
    return AccessedStorage();

  case ValueKind::StructExtractInst:
    // Handle nested access to a KeyPath projection. The projection itself
    // uses a Builtin. However, the returned UnsafeMutablePointer may be
    // converted to an address and accessed via an inout argument.
    if (isUnsafePointerExtraction(cast<StructExtractInst>(sourceAddr)))
      return AccessedStorage(sourceAddr, AccessedStorage::Unidentified);
    return AccessedStorage();

  case ValueKind::SILPhiArgument: {
    auto *phiArg = cast<SILPhiArgument>(sourceAddr);
    if (phiArg->isPhiArgument())
      return AccessedStorageResult::incomplete(phiArg);

    // A non-phi block argument may be a box value projected out of
    // switch_enum. Address-type block arguments are not allowed.
    if (sourceAddr->getType().isAddress())
      return AccessedStorage();

    checkSwitchEnumBlockArg(cast<SILPhiArgument>(sourceAddr));
    return AccessedStorage(sourceAddr, AccessedStorage::Unidentified);
  }
  // Load a box from an indirect payload of an opaque enum.
  // We must have peeked past the project_box earlier in this loop.
  // (the indirectness makes it a box, the load is for address-only).
  //
  // %payload_adr = unchecked_take_enum_data_addr %enum : $*Enum, #Enum.case
  // %box = load [take] %payload_adr : $*{ var Enum }
  //
  // FIXME: this case should go away with opaque values.
  //
  // Otherwise return invalid AccessedStorage.
  case ValueKind::LoadInst:
    if (sourceAddr->getType().is<SILBoxType>()) {
      SILValue operAddr = cast<LoadInst>(sourceAddr)->getOperand();
      assert(isa<UncheckedTakeEnumDataAddrInst>(operAddr));
      return AccessedStorageResult::incomplete(operAddr);
    }
    return AccessedStorage();

  // ref_tail_addr project an address from a reference.
  // This is a valid address producer for nested @inout argument
  // access, but it is never used for formal access of identified objects.
  case ValueKind::RefTailAddrInst:
    return AccessedStorage(sourceAddr, AccessedStorage::Unidentified);

  // Inductive single-operand cases:
  // Look through address casts to find the source address.
  case ValueKind::MarkUninitializedInst:
  case ValueKind::OpenExistentialAddrInst:
  case ValueKind::UncheckedAddrCastInst:
  // Inductive cases that apply to any type.
  case ValueKind::CopyValueInst:
  case ValueKind::MarkDependenceInst:
  // Look through a project_box to identify the underlying alloc_box as the
  // accesed object. It must be possible to reach either the alloc_box or the
  // containing enum in this loop, only looking through simple value
  // propagation such as copy_value.
  case ValueKind::ProjectBoxInst:
  // Handle project_block_storage just like project_box.
  case ValueKind::ProjectBlockStorageInst:
  // Look through begin_borrow in case a local box is borrowed.
  case ValueKind::BeginBorrowInst:
    return AccessedStorageResult::incomplete(
      cast<SingleValueInstruction>(sourceAddr)->getOperand(0));

  // Access to a Builtin.RawPointer. Treat this like the inductive cases
  // above because some RawPointers originate from identified locations. See
  // the special case for global addressors, which return RawPointer, above.
  //
  // If the inductive search does not find a valid addressor, it will
  // eventually reach the default case that returns in invalid location. This
  // is correct for RawPointer because, although accessing a RawPointer is
  // legal SIL, there is no way to guarantee that it doesn't access class or
  // global storage, so returning a valid unidentified storage object would be
  // incorrect. It is the caller's responsibility to know that formal access
  // to such a location can be safely ignored.
  //
  // For example:
  //
  // - KeyPath Builtins access RawPointer. However, the caller can check
  // that the access `isFromBuilin` and ignore the storage.
  //
  // - lldb generates RawPointer access for debugger variables, but SILGen
  // marks debug VarDecl access as 'Unsafe' and SIL passes don't need the
  // AccessedStorage for 'Unsafe' access.
  case ValueKind::PointerToAddressInst:
    return AccessedStorageResult::incomplete(
      cast<SingleValueInstruction>(sourceAddr)->getOperand(0));

  // Address-to-address subobject projections.
  case ValueKind::StructElementAddrInst:
  case ValueKind::TupleElementAddrInst:
  case ValueKind::UncheckedTakeEnumDataAddrInst:
  case ValueKind::TailAddrInst:
  case ValueKind::IndexAddrInst:
    return AccessedStorageResult::incomplete(
      cast<SingleValueInstruction>(sourceAddr)->getOperand(0));
  }
}
/// Look through a value to find the underlying storage accessed.
static AccessedStorage findAccessedStorage(SILValue Source) {
  SILValue Iter = Source;
  while (true) {
    // Base case for globals: make sure ultimate source is recognized.
    if (auto *GAI = dyn_cast<GlobalAddrInst>(Iter)) {
      return AccessedStorage(GAI->getReferencedGlobal());
    }

    // Base case for class objects.
    if (auto *REA = dyn_cast<RefElementAddrInst>(Iter)) {
      // Do a best-effort to find the identity of the object being projected
      // from. It is OK to be unsound here (i.e. miss when two ref_element_addrs
      // actually refer the same address) because these will be dynamically
      // checked.
      SILValue Object = findUnderlyingObject(REA->getOperand());
      const ObjectProjection &OP = ObjectProjection(Object,
                                                    Projection(REA));
      return AccessedStorage(AccessedStorageKind::ClassProperty, OP);
    }

    switch (Iter->getKind()) {
    // Inductive cases: look through operand to find ultimate source.
    case ValueKind::ProjectBoxInst:
    case ValueKind::CopyValueInst:
    case ValueKind::MarkUninitializedInst:
    case ValueKind::UncheckedAddrCastInst:
    // Inlined access to subobjects.
    case ValueKind::StructElementAddrInst:
    case ValueKind::TupleElementAddrInst:
    case ValueKind::UncheckedTakeEnumDataAddrInst:
    case ValueKind::RefTailAddrInst:
    case ValueKind::TailAddrInst:
    case ValueKind::IndexAddrInst:
      Iter = cast<SILInstruction>(Iter)->getOperand(0);
      continue;

    // Base address producers.
    case ValueKind::AllocBoxInst:
      // An AllocBox is a fully identified memory location.
    case ValueKind::AllocStackInst:
      // An AllocStack is a fully identified memory location, which may occur
      // after inlining code already subjected to stack promotion.
    case ValueKind::BeginAccessInst:
      // The current access is nested within another access.
      // View the outer access as a separate location because nested accesses do
      // not conflict with each other.
    case ValueKind::SILFunctionArgument:
      // A function argument is effectively a nested access, enforced
      // independently in the caller and callee.
    case ValueKind::PointerToAddressInst:
      // An addressor provides access to a global or class property via a
      // RawPointer. Calling the addressor casts that raw pointer to an address.
      return AccessedStorage(Iter);

    // Unsupported address producers.
    // Initialization is always local.
    case ValueKind::InitEnumDataAddrInst:
    case ValueKind::InitExistentialAddrInst:
    // Accessing an existential value requires a cast.
    case ValueKind::OpenExistentialAddrInst:
    default:
      DEBUG(llvm::dbgs() << "Bad memory access source: " << Iter);
      llvm_unreachable("Unexpected access source.");
    }
  }
}