Skip to content

Commit 3543cf8

Browse files
committed
Cleanup MemAccessUtils.
Organize the utilities in this file by section to make subsequent diffs easier to read and prepare for adding more utilities.
1 parent 6061fe6 commit 3543cf8

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)