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(); }
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; } }
// 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(); } }
/// 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); } } }
/// 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; } }
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"); }
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; } } }
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; } } }
/// 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; } }
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"); }
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; } } }
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; } }
/// 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; } }
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; }
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; } }
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; } } }
/// 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; }
// 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."); } } }