Skip to content

Commit 7366a32

Browse files
committed
Merge remote-tracking branch 'origin/master' into master-rebranch
2 parents fdfa9d9 + c0ec48c commit 7366a32

File tree

4 files changed

+426
-296
lines changed

4 files changed

+426
-296
lines changed

include/swift/SIL/MemAccessUtils.h

Lines changed: 240 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,11 @@
3636
#ifndef SWIFT_SIL_MEMACCESSUTILS_H
3737
#define SWIFT_SIL_MEMACCESSUTILS_H
3838

39+
#include "swift/SIL/ApplySite.h"
3940
#include "swift/SIL/InstructionUtils.h"
4041
#include "swift/SIL/SILArgument.h"
4142
#include "swift/SIL/SILBasicBlock.h"
43+
#include "swift/SIL/SILGlobalVariable.h"
4244
#include "swift/SIL/SILInstruction.h"
4345
#include "llvm/ADT/DenseMap.h"
4446

@@ -117,10 +119,6 @@ class AccessedStorage {
117119

118120
static const char *getKindName(Kind k);
119121

120-
/// If the given address source is an identified access base, return the kind
121-
/// of access base. Otherwise, return Unidentified.
122-
static AccessedStorage::Kind classify(SILValue base);
123-
124122
/// Directly create an AccessedStorage for class property access.
125123
static AccessedStorage forClass(SILValue object, unsigned propertyIndex) {
126124
AccessedStorage storage;
@@ -406,6 +404,58 @@ template <> struct DenseMapInfo<swift::AccessedStorage> {
406404

407405
namespace swift {
408406

407+
/// Abstract CRTP class for a visitor passed to \c visitAccessUseDefChain.
408+
template<typename Impl, typename Result = void>
409+
class AccessUseDefChainVisitor {
410+
protected:
411+
Impl &asImpl() {
412+
return static_cast<Impl&>(*this);
413+
}
414+
public:
415+
// Subclasses can provide a method for any identified access base:
416+
// Result visitBase(SILValue base, AccessedStorage::Kind kind);
417+
418+
// Visitors for specific identified access kinds. These default to calling out
419+
// to visitIdentified.
420+
421+
Result visitClassAccess(RefElementAddrInst *field) {
422+
return asImpl().visitBase(field, AccessedStorage::Class);
423+
}
424+
Result visitArgumentAccess(SILFunctionArgument *arg) {
425+
return asImpl().visitBase(arg, AccessedStorage::Argument);
426+
}
427+
Result visitBoxAccess(AllocBoxInst *box) {
428+
return asImpl().visitBase(box, AccessedStorage::Box);
429+
}
430+
/// The argument may be either a GlobalAddrInst or the ApplyInst for a global accessor function.
431+
Result visitGlobalAccess(SILValue global) {
432+
return asImpl().visitBase(global, AccessedStorage::Global);
433+
}
434+
Result visitYieldAccess(BeginApplyResult *yield) {
435+
return asImpl().visitBase(yield, AccessedStorage::Yield);
436+
}
437+
Result visitStackAccess(AllocStackInst *stack) {
438+
return asImpl().visitBase(stack, AccessedStorage::Stack);
439+
}
440+
Result visitNestedAccess(BeginAccessInst *access) {
441+
return asImpl().visitBase(access, AccessedStorage::Nested);
442+
}
443+
444+
// Visitors for unidentified base values.
445+
446+
Result visitUnidentified(SILValue base) {
447+
return asImpl().visitBase(base, AccessedStorage::Unidentified);
448+
}
449+
450+
// Subclasses must provide implementations to visit non-access bases
451+
// and phi arguments, and for incomplete projections from the access:
452+
// void visitNonAccess(SILValue base);
453+
// void visitPhi(SILPhiArgument *phi);
454+
// void visitIncomplete(SILValue projectedAddr, SILValue parentAddr);
455+
456+
Result visit(SILValue sourceAddr);
457+
};
458+
409459
/// Given an address accessed by an instruction that reads or modifies
410460
/// memory, return an AccessedStorage object that identifies the formal access.
411461
///
@@ -468,6 +518,192 @@ void visitAccessedAddress(SILInstruction *I,
468518
/// instruction following this begin_access was not also erased.
469519
SILBasicBlock::iterator removeBeginAccess(BeginAccessInst *beginAccess);
470520

521+
/// Return true if the given address value is produced by a special address
522+
/// producer that is only used for local initialization, not formal access.
523+
bool isAddressForLocalInitOnly(SILValue sourceAddr);
524+
/// Return true if the given apply invokes a global addressor defined in another
525+
/// module.
526+
bool isExternalGlobalAddressor(ApplyInst *AI);
527+
/// Return true if the given StructExtractInst extracts the RawPointer from
528+
/// Unsafe[Mutable]Pointer.
529+
bool isUnsafePointerExtraction(StructExtractInst *SEI);
530+
/// Given a block argument address base, check if it is actually a box projected
531+
/// from a switch_enum. This is a valid pattern at any SIL stage resulting in a
532+
/// block-type phi. In later SIL stages, the optimizer may form address-type
533+
/// phis, causing this assert if called on those cases.
534+
void checkSwitchEnumBlockArg(SILPhiArgument *arg);
535+
536+
template<typename Impl, typename Result>
537+
Result AccessUseDefChainVisitor<Impl, Result>::visit(SILValue sourceAddr) {
538+
// Handle immediately-identifiable instructions.
539+
while (true) {
540+
switch (sourceAddr->getKind()) {
541+
// An AllocBox is a fully identified memory location.
542+
case ValueKind::AllocBoxInst:
543+
return asImpl().visitBoxAccess(cast<AllocBoxInst>(sourceAddr));
544+
// An AllocStack is a fully identified memory location, which may occur
545+
// after inlining code already subjected to stack promotion.
546+
case ValueKind::AllocStackInst:
547+
return asImpl().visitStackAccess(cast<AllocStackInst>(sourceAddr));
548+
case ValueKind::GlobalAddrInst:
549+
return asImpl().visitGlobalAccess(sourceAddr);
550+
case ValueKind::ApplyInst: {
551+
FullApplySite apply(cast<ApplyInst>(sourceAddr));
552+
if (auto *funcRef = apply.getReferencedFunctionOrNull()) {
553+
if (getVariableOfGlobalInit(funcRef)) {
554+
return asImpl().visitGlobalAccess(sourceAddr);
555+
}
556+
}
557+
// Try to classify further below.
558+
break;
559+
}
560+
case ValueKind::RefElementAddrInst:
561+
return asImpl().visitClassAccess(cast<RefElementAddrInst>(sourceAddr));
562+
// A yield is effectively a nested access, enforced independently in
563+
// the caller and callee.
564+
case ValueKind::BeginApplyResult:
565+
return asImpl().visitYieldAccess(cast<BeginApplyResult>(sourceAddr));
566+
// A function argument is effectively a nested access, enforced
567+
// independently in the caller and callee.
568+
case ValueKind::SILFunctionArgument:
569+
return asImpl().visitArgumentAccess(cast<SILFunctionArgument>(sourceAddr));
570+
// View the outer begin_access as a separate location because nested
571+
// accesses do not conflict with each other.
572+
case ValueKind::BeginAccessInst:
573+
return asImpl().visitNestedAccess(cast<BeginAccessInst>(sourceAddr));
574+
default:
575+
// Try to classify further below.
576+
break;
577+
}
578+
579+
// If the sourceAddr producer cannot immediately be classified, follow the
580+
// use-def chain of sourceAddr, box, or RawPointer producers.
581+
assert(sourceAddr->getType().isAddress()
582+
|| isa<SILBoxType>(sourceAddr->getType().getASTType())
583+
|| isa<BuiltinRawPointerType>(sourceAddr->getType().getASTType()));
584+
585+
// Handle other unidentified address sources.
586+
switch (sourceAddr->getKind()) {
587+
default:
588+
if (isAddressForLocalInitOnly(sourceAddr))
589+
return asImpl().visitUnidentified(sourceAddr);
590+
return asImpl().visitNonAccess(sourceAddr);
591+
592+
case ValueKind::SILUndef:
593+
return asImpl().visitUnidentified(sourceAddr);
594+
595+
case ValueKind::ApplyInst:
596+
if (isExternalGlobalAddressor(cast<ApplyInst>(sourceAddr)))
597+
return asImpl().visitUnidentified(sourceAddr);
598+
599+
// Don't currently allow any other calls to return an accessed address.
600+
return asImpl().visitNonAccess(sourceAddr);
601+
602+
case ValueKind::StructExtractInst:
603+
// Handle nested access to a KeyPath projection. The projection itself
604+
// uses a Builtin. However, the returned UnsafeMutablePointer may be
605+
// converted to an address and accessed via an inout argument.
606+
if (isUnsafePointerExtraction(cast<StructExtractInst>(sourceAddr)))
607+
return asImpl().visitUnidentified(sourceAddr);
608+
return asImpl().visitNonAccess(sourceAddr);
609+
610+
case ValueKind::SILPhiArgument: {
611+
auto *phiArg = cast<SILPhiArgument>(sourceAddr);
612+
if (phiArg->isPhiArgument()) {
613+
return asImpl().visitPhi(phiArg);
614+
}
615+
616+
// A non-phi block argument may be a box value projected out of
617+
// switch_enum. Address-type block arguments are not allowed.
618+
if (sourceAddr->getType().isAddress())
619+
return asImpl().visitNonAccess(sourceAddr);
620+
621+
checkSwitchEnumBlockArg(cast<SILPhiArgument>(sourceAddr));
622+
return asImpl().visitUnidentified(sourceAddr);
623+
}
624+
// Load a box from an indirect payload of an opaque enum.
625+
// We must have peeked past the project_box earlier in this loop.
626+
// (the indirectness makes it a box, the load is for address-only).
627+
//
628+
// %payload_adr = unchecked_take_enum_data_addr %enum : $*Enum, #Enum.case
629+
// %box = load [take] %payload_adr : $*{ var Enum }
630+
//
631+
// FIXME: this case should go away with opaque values.
632+
//
633+
// Otherwise return invalid AccessedStorage.
634+
case ValueKind::LoadInst:
635+
if (sourceAddr->getType().is<SILBoxType>()) {
636+
SILValue operAddr = cast<LoadInst>(sourceAddr)->getOperand();
637+
assert(isa<UncheckedTakeEnumDataAddrInst>(operAddr));
638+
return asImpl().visitIncomplete(sourceAddr, operAddr);
639+
}
640+
return asImpl().visitNonAccess(sourceAddr);
641+
642+
// ref_tail_addr project an address from a reference.
643+
// This is a valid address producer for nested @inout argument
644+
// access, but it is never used for formal access of identified objects.
645+
case ValueKind::RefTailAddrInst:
646+
return asImpl().visitUnidentified(sourceAddr);
647+
648+
// Inductive single-operand cases:
649+
// Look through address casts to find the source address.
650+
case ValueKind::MarkUninitializedInst:
651+
case ValueKind::OpenExistentialAddrInst:
652+
case ValueKind::UncheckedAddrCastInst:
653+
// Inductive cases that apply to any type.
654+
case ValueKind::CopyValueInst:
655+
case ValueKind::MarkDependenceInst:
656+
// Look through a project_box to identify the underlying alloc_box as the
657+
// accesed object. It must be possible to reach either the alloc_box or the
658+
// containing enum in this loop, only looking through simple value
659+
// propagation such as copy_value.
660+
case ValueKind::ProjectBoxInst:
661+
// Handle project_block_storage just like project_box.
662+
case ValueKind::ProjectBlockStorageInst:
663+
// Look through begin_borrow in case a local box is borrowed.
664+
case ValueKind::BeginBorrowInst:
665+
return asImpl().visitIncomplete(sourceAddr,
666+
cast<SingleValueInstruction>(sourceAddr)->getOperand(0));
667+
668+
// Access to a Builtin.RawPointer. Treat this like the inductive cases
669+
// above because some RawPointers originate from identified locations. See
670+
// the special case for global addressors, which return RawPointer,
671+
// above. AddressToPointer is also handled because it results from inlining a
672+
// global addressor without folding the AddressToPointer->PointerToAddress.
673+
//
674+
// If the inductive search does not find a valid addressor, it will
675+
// eventually reach the default case that returns in invalid location. This
676+
// is correct for RawPointer because, although accessing a RawPointer is
677+
// legal SIL, there is no way to guarantee that it doesn't access class or
678+
// global storage, so returning a valid unidentified storage object would be
679+
// incorrect. It is the caller's responsibility to know that formal access
680+
// to such a location can be safely ignored.
681+
//
682+
// For example:
683+
//
684+
// - KeyPath Builtins access RawPointer. However, the caller can check
685+
// that the access `isFromBuilin` and ignore the storage.
686+
//
687+
// - lldb generates RawPointer access for debugger variables, but SILGen
688+
// marks debug VarDecl access as 'Unsafe' and SIL passes don't need the
689+
// AccessedStorage for 'Unsafe' access.
690+
case ValueKind::PointerToAddressInst:
691+
case ValueKind::AddressToPointerInst:
692+
return asImpl().visitIncomplete(sourceAddr,
693+
cast<SingleValueInstruction>(sourceAddr)->getOperand(0));
694+
695+
// Address-to-address subobject projections.
696+
case ValueKind::StructElementAddrInst:
697+
case ValueKind::TupleElementAddrInst:
698+
case ValueKind::UncheckedTakeEnumDataAddrInst:
699+
case ValueKind::TailAddrInst:
700+
case ValueKind::IndexAddrInst:
701+
return asImpl().visitIncomplete(sourceAddr,
702+
cast<SingleValueInstruction>(sourceAddr)->getOperand(0));
703+
}
704+
};
705+
}
706+
471707
} // end namespace swift
472708

473709
#endif

0 commit comments

Comments
 (0)