Skip to content

Commit 2bc97cf

Browse files
authored
Merge pull request swiftlang#32790 from atrick/cleanup-memaccess
2 parents 69ff5be + 3543cf8 commit 2bc97cf

File tree

2 files changed

+294
-264
lines changed

2 files changed

+294
-264
lines changed

include/swift/SIL/MemAccessUtils.h

Lines changed: 130 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@
4444
#include "swift/SIL/SILInstruction.h"
4545
#include "llvm/ADT/DenseMap.h"
4646

47+
//===----------------------------------------------------------------------===//
48+
// MARK: General Helpers
49+
//===----------------------------------------------------------------------===//
50+
4751
namespace swift {
4852

4953
/// Get the base address of a formal access by stripping access markers and
@@ -103,6 +107,14 @@ inline bool accessKindMayConflict(SILAccessKind a, SILAccessKind b) {
103107
return !(a == SILAccessKind::Read && b == SILAccessKind::Read);
104108
}
105109

110+
} // end namespace swift
111+
112+
//===----------------------------------------------------------------------===//
113+
// MARK: AccessedStorage
114+
//===----------------------------------------------------------------------===//
115+
116+
namespace swift {
117+
106118
/// Represents the identity of a storage object being accessed.
107119
///
108120
/// AccessedStorage is carefully designed to solve three problems:
@@ -406,24 +418,23 @@ class AccessedStorage {
406418
bool operator==(const AccessedStorage &) const = delete;
407419
bool operator!=(const AccessedStorage &) const = delete;
408420
};
421+
409422
} // end namespace swift
410423

411424
namespace llvm {
412-
413425
/// Enable using AccessedStorage as a key in DenseMap.
414426
/// Do *not* include any extra pass data in key equality.
415427
template <> struct DenseMapInfo<swift::AccessedStorage> {
416428
static swift::AccessedStorage getEmptyKey() {
417429
return swift::AccessedStorage(swift::SILValue::getFromOpaqueValue(
418-
llvm::DenseMapInfo<void *>::getEmptyKey()),
419-
swift::AccessedStorage::Unidentified);
430+
llvm::DenseMapInfo<void *>::getEmptyKey()),
431+
swift::AccessedStorage::Unidentified);
420432
}
421433

422434
static swift::AccessedStorage getTombstoneKey() {
423-
return swift::AccessedStorage(
424-
swift::SILValue::getFromOpaqueValue(
425-
llvm::DenseMapInfo<void *>::getTombstoneKey()),
426-
swift::AccessedStorage::Unidentified);
435+
return swift::AccessedStorage(swift::SILValue::getFromOpaqueValue(
436+
llvm::DenseMapInfo<void *>::getTombstoneKey()),
437+
swift::AccessedStorage::Unidentified);
427438
}
428439

429440
static unsigned getHashValue(swift::AccessedStorage storage) {
@@ -450,63 +461,10 @@ template <> struct DenseMapInfo<swift::AccessedStorage> {
450461
return LHS.hasIdenticalBase(RHS);
451462
}
452463
};
453-
454-
} // end namespace llvm
464+
} // namespace llvm
455465

456466
namespace swift {
457467

458-
/// Abstract CRTP class for a visitor passed to \c visitAccessUseDefChain.
459-
template<typename Impl, typename Result = void>
460-
class AccessUseDefChainVisitor {
461-
protected:
462-
Impl &asImpl() {
463-
return static_cast<Impl&>(*this);
464-
}
465-
public:
466-
// Subclasses can provide a method for any identified access base:
467-
// Result visitBase(SILValue base, AccessedStorage::Kind kind);
468-
469-
// Visitors for specific identified access kinds. These default to calling out
470-
// to visitIdentified.
471-
472-
Result visitClassAccess(RefElementAddrInst *field) {
473-
return asImpl().visitBase(field, AccessedStorage::Class);
474-
}
475-
Result visitArgumentAccess(SILFunctionArgument *arg) {
476-
return asImpl().visitBase(arg, AccessedStorage::Argument);
477-
}
478-
Result visitBoxAccess(AllocBoxInst *box) {
479-
return asImpl().visitBase(box, AccessedStorage::Box);
480-
}
481-
/// The argument may be either a GlobalAddrInst or the ApplyInst for a global accessor function.
482-
Result visitGlobalAccess(SILValue global) {
483-
return asImpl().visitBase(global, AccessedStorage::Global);
484-
}
485-
Result visitYieldAccess(BeginApplyResult *yield) {
486-
return asImpl().visitBase(yield, AccessedStorage::Yield);
487-
}
488-
Result visitStackAccess(AllocStackInst *stack) {
489-
return asImpl().visitBase(stack, AccessedStorage::Stack);
490-
}
491-
Result visitNestedAccess(BeginAccessInst *access) {
492-
return asImpl().visitBase(access, AccessedStorage::Nested);
493-
}
494-
495-
// Visitors for unidentified base values.
496-
497-
Result visitUnidentified(SILValue base) {
498-
return asImpl().visitBase(base, AccessedStorage::Unidentified);
499-
}
500-
501-
// Subclasses must provide implementations to visit non-access bases
502-
// and phi arguments, and for incomplete projections from the access:
503-
// void visitNonAccess(SILValue base);
504-
// void visitPhi(SILPhiArgument *phi);
505-
// void visitIncomplete(SILValue projectedAddr, SILValue parentAddr);
506-
507-
Result visit(SILValue sourceAddr);
508-
};
509-
510468
/// Given an address accessed by an instruction that reads or modifies
511469
/// memory, return an AccessedStorage object that identifies the formal access.
512470
///
@@ -534,6 +492,14 @@ AccessedStorage findAccessedStorage(SILValue sourceAddr);
534492
/// access has Unsafe enforcement.
535493
AccessedStorage findAccessedStorageNonNested(SILValue sourceAddr);
536494

495+
} // end namespace swift
496+
497+
//===----------------------------------------------------------------------===//
498+
// MARK: Helper API
499+
//===----------------------------------------------------------------------===//
500+
501+
namespace swift {
502+
537503
/// Return true if the given address operand is used by a memory operation that
538504
/// initializes the memory at that address, implying that the previous value is
539505
/// uninitialized.
@@ -550,6 +516,24 @@ bool memInstMustInitialize(Operand *memOper);
550516
bool isSingleInitAllocStack(AllocStackInst *asi,
551517
SmallVectorImpl<Operand *> &destroyingUses);
552518

519+
/// Return true if the given address value is produced by a special address
520+
/// producer that is only used for local initialization, not formal access.
521+
bool isAddressForLocalInitOnly(SILValue sourceAddr);
522+
523+
/// Return true if the given apply invokes a global addressor defined in another
524+
/// module.
525+
bool isExternalGlobalAddressor(ApplyInst *AI);
526+
527+
/// Return true if the given StructExtractInst extracts the RawPointer from
528+
/// Unsafe[Mutable]Pointer.
529+
bool isUnsafePointerExtraction(StructExtractInst *SEI);
530+
531+
/// Given a block argument address base, check if it is actually a box projected
532+
/// from a switch_enum. This is a valid pattern at any SIL stage resulting in a
533+
/// block-type phi. In later SIL stages, the optimizer may form address-type
534+
/// phis, causing this assert if called on those cases.
535+
void checkSwitchEnumBlockArg(SILPhiArgument *arg);
536+
553537
/// Return true if the given address producer may be the source of a formal
554538
/// access (a read or write of a potentially aliased, user visible variable).
555539
///
@@ -560,17 +544,14 @@ bool isSingleInitAllocStack(AllocStackInst *asi,
560544
/// storage = findAccessedStorage(address)
561545
/// needsAccessMarker = storage && isPossibleFormalAccessBase(storage)
562546
///
563-
/// Warning: This is only valid for SIL with well-formed accessed. For example,
547+
/// Warning: This is only valid for SIL with well-formed accesses. For example,
564548
/// it will not handle address-type phis. Optimization passes after
565549
/// DiagnoseStaticExclusivity may violate these assumptions.
566-
bool isPossibleFormalAccessBase(const AccessedStorage &storage, SILFunction *F);
567-
568-
/// Visit each address accessed by the given memory operation.
569550
///
570-
/// This only visits instructions that modify memory in some user-visible way,
571-
/// which could be considered part of a formal access.
572-
void visitAccessedAddress(SILInstruction *I,
573-
llvm::function_ref<void(Operand *)> visitor);
551+
/// This is not a member of AccessedStorage because it only makes sense to use
552+
/// in SILGen before access markers are emitted, or when verifying access
553+
/// markers.
554+
bool isPossibleFormalAccessBase(const AccessedStorage &storage, SILFunction *F);
574555

575556
/// Perform a RAUW operation on begin_access with it's own source operand.
576557
/// Then erase the begin_access and all associated end_access instructions.
@@ -580,20 +561,65 @@ void visitAccessedAddress(SILInstruction *I,
580561
/// instruction following this begin_access was not also erased.
581562
SILBasicBlock::iterator removeBeginAccess(BeginAccessInst *beginAccess);
582563

583-
/// Return true if the given address value is produced by a special address
584-
/// producer that is only used for local initialization, not formal access.
585-
bool isAddressForLocalInitOnly(SILValue sourceAddr);
586-
/// Return true if the given apply invokes a global addressor defined in another
587-
/// module.
588-
bool isExternalGlobalAddressor(ApplyInst *AI);
589-
/// Return true if the given StructExtractInst extracts the RawPointer from
590-
/// Unsafe[Mutable]Pointer.
591-
bool isUnsafePointerExtraction(StructExtractInst *SEI);
592-
/// Given a block argument address base, check if it is actually a box projected
593-
/// from a switch_enum. This is a valid pattern at any SIL stage resulting in a
594-
/// block-type phi. In later SIL stages, the optimizer may form address-type
595-
/// phis, causing this assert if called on those cases.
596-
void checkSwitchEnumBlockArg(SILPhiArgument *arg);
564+
} // end namespace swift
565+
566+
//===----------------------------------------------------------------------===//
567+
// MARK: AccessUseDefChainVisitor
568+
//===----------------------------------------------------------------------===//
569+
570+
namespace swift {
571+
572+
/// Abstract CRTP class for a visitor passed to \c visitAccessUseDefChain.
573+
template <typename Impl, typename Result = void>
574+
class AccessUseDefChainVisitor {
575+
protected:
576+
Impl &asImpl() { return static_cast<Impl &>(*this); }
577+
578+
public:
579+
// Subclasses can provide a method for any identified access base:
580+
// Result visitBase(SILValue base, AccessedStorage::Kind kind);
581+
582+
// Visitors for specific identified access kinds. These default to calling out
583+
// to visitIdentified.
584+
585+
Result visitClassAccess(RefElementAddrInst *field) {
586+
return asImpl().visitBase(field, AccessedStorage::Class);
587+
}
588+
Result visitArgumentAccess(SILFunctionArgument *arg) {
589+
return asImpl().visitBase(arg, AccessedStorage::Argument);
590+
}
591+
Result visitBoxAccess(AllocBoxInst *box) {
592+
return asImpl().visitBase(box, AccessedStorage::Box);
593+
}
594+
/// The argument may be either a GlobalAddrInst or the ApplyInst for a global
595+
/// accessor function.
596+
Result visitGlobalAccess(SILValue global) {
597+
return asImpl().visitBase(global, AccessedStorage::Global);
598+
}
599+
Result visitYieldAccess(BeginApplyResult *yield) {
600+
return asImpl().visitBase(yield, AccessedStorage::Yield);
601+
}
602+
Result visitStackAccess(AllocStackInst *stack) {
603+
return asImpl().visitBase(stack, AccessedStorage::Stack);
604+
}
605+
Result visitNestedAccess(BeginAccessInst *access) {
606+
return asImpl().visitBase(access, AccessedStorage::Nested);
607+
}
608+
609+
// Visitors for unidentified base values.
610+
611+
Result visitUnidentified(SILValue base) {
612+
return asImpl().visitBase(base, AccessedStorage::Unidentified);
613+
}
614+
615+
// Subclasses must provide implementations to visit non-access bases
616+
// and phi arguments, and for incomplete projections from the access:
617+
// void visitNonAccess(SILValue base);
618+
// void visitPhi(SILPhiArgument *phi);
619+
// void visitIncomplete(SILValue projectedAddr, SILValue parentAddr);
620+
621+
Result visit(SILValue sourceAddr);
622+
};
597623

598624
template<typename Impl, typename Result>
599625
Result AccessUseDefChainVisitor<Impl, Result>::visit(SILValue sourceAddr) {
@@ -727,11 +753,12 @@ Result AccessUseDefChainVisitor<Impl, Result>::visit(SILValue sourceAddr) {
727753
return asImpl().visitIncomplete(sourceAddr,
728754
cast<SingleValueInstruction>(sourceAddr)->getOperand(0));
729755

730-
// Access to a Builtin.RawPointer. Treat this like the inductive cases
731-
// above because some RawPointers originate from identified locations. See
732-
// the special case for global addressors, which return RawPointer,
733-
// above. AddressToPointer is also handled because it results from inlining a
734-
// global addressor without folding the AddressToPointer->PointerToAddress.
756+
// Access to a Builtin.RawPointer. Treat this like the inductive cases above
757+
// because some RawPointers originate from identified locations. See the
758+
// special case for global addressors, which return RawPointer,
759+
// above. AddressToPointer is also handled because it results from inlining
760+
// a global addressor without folding the
761+
// AddressToPointer->PointerToAddress.
735762
//
736763
// If the inductive search does not find a valid addressor, it will
737764
// eventually reach the default case that returns in invalid location. This
@@ -768,4 +795,19 @@ Result AccessUseDefChainVisitor<Impl, Result>::visit(SILValue sourceAddr) {
768795

769796
} // end namespace swift
770797

798+
//===----------------------------------------------------------------------===//
799+
// MARK: Verification
800+
//===----------------------------------------------------------------------===//
801+
802+
namespace swift {
803+
804+
/// Visit each address accessed by the given memory operation.
805+
///
806+
/// This only visits instructions that modify memory in some user-visible way,
807+
/// which could be considered part of a formal access.
808+
void visitAccessedAddress(SILInstruction *I,
809+
llvm::function_ref<void(Operand *)> visitor);
810+
811+
} // end namespace swift
812+
771813
#endif

0 commit comments

Comments
 (0)