Skip to content

Add access marker removal to AccessEnforcementOpts. #16771

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 72 additions & 27 deletions include/swift/SIL/MemAccessUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,17 @@ class ObjectProjection {
}
};

/// Represents the identity of a storage location being accessed.
/// Represents the identity of a storage object being accessed.
///
/// AccessedStorage may be one of several kinds of "identified" storage
/// locations, or may be valid, but Unidentified storage. An identified location
/// objects, or may be valid, but Unidentified storage. An identified object
/// is known to identify the base of the accessed storage, whether that is a
/// SILValue that produces the base address, or a variable
/// declaration. "Uniquely identified" storage refers to identified storage that
/// cannot be aliased. For example, local allocations are uniquely identified,
/// while global variables and class properties are not. Unidentified storage is
/// associated with a SILValue that produces the accessed address but has not
/// been determined to be the base of a storage location. It may, for example,
/// been determined to be the base of a storage object. It may, for example,
/// be a SILPHIArgument.
///
/// An invalid AccessedStorage object is marked Unidentified and contains an
Expand All @@ -72,19 +72,19 @@ class ObjectProjection {
/// SILVerification could allow the optimizer to aggressively assert that
/// AccessedStorage is always valid.
///
/// Note that the SILValue that represents a storage location is not
/// Note that the SILValue that represents a storage object is not
/// necessarilly an address type. It may instead be a SILBoxType.
///
/// AccessedStorage hashing and comparison is used to determine when two
/// 'begin_access' instructions access the same or disjoint underlying
/// locations.
/// AccessedStorage hashing and comparison (via DenseMapInfo) is used to
/// determine when two 'begin_access' instructions access the same or disjoint
/// underlying objects.
///
/// Equality guarantees that two AccessStorage values refer to the same
/// memory if both values are valid.
/// `DenseMapInfo::isEqual()` guarantees that two AccessStorage values refer to
/// the same memory if both values are valid.
///
/// Inequality does not guarantee that two identified AccessStorage values
/// distinct. Inequality does guarantee that two *uniquely* identified
/// AccessStorage values are distinct.
/// `!DenseMapInfo::isEqual()` does not guarantee that two identified
/// AccessStorage values are distinct. Inequality does, however, guarantee that
/// two *uniquely* identified AccessStorage values are distinct.
class AccessedStorage {
public:
/// Enumerate over all valid begin_access bases. Clients can use a covered
Expand All @@ -111,26 +111,42 @@ class AccessedStorage {
// with the fields used within this class as a common prefix.
//
// This allows passes to embed analysis flags, and reserves enough space to
// embed a unique access index.
// embed a unique index.
//
// AccessedStorageAnalysis defines an StorageAccessInfo object that maps each
// storage object within a function to its unique storage index and summary
// information of that storage object.
//
// AccessEnforcementOpts defines an AccessEnforcementOptsInfo object that maps
// each begin_access to its storage object, unique access index, and summary
// info for that access.
union {
uint64_t OpaqueBits;
SWIFT_INLINE_BITFIELD_BASE(AccessedStorage, bitmax(NumKindBits, 8), Kind
: bitmax(NumKindBits, 8));
SWIFT_INLINE_BITFIELD_BASE(AccessedStorage, bitmax(NumKindBits, 8),
Kind : bitmax(NumKindBits, 8));

// Define bits for use in the AccessEnforcementOpts pass. Reserve the high
// bit for a seenNestedConflict flag, which is the result of pass-specific
// analysis. The remaning bits are sufficient to index all
// Define bits for use in AccessedStorageAnalysis. Each identified storage
// object is mapped to one instance of this subclass.
SWIFT_INLINE_BITFIELD_FULL(StorageAccessInfo, AccessedStorage,
64 - NumAccessedStorageBits,
accessKind : NumSILAccessKindBits,
noNestedConflict : 1,
storageIndex : 64 - (NumAccessedStorageBits
+ NumSILAccessKindBits
+ 1));

// Define bits for use in the AccessEnforcementOpts pass. Each begin_access
// in the function is mapped to one instance of this subclass. Reserve a
// bit for a seenNestedConflict flag, which is the per-begin-access result
// of pass-specific analysis. The remaning bits are sufficient to index all
// begin_[unpaired_]access instructions.
//
// `AccessEnforcementOpts` does not need to be a defined class. This macro
// simply defines the pass-specific name "AccessEnforcementOptsBitfield".
//
// `AccessedStorage` identifies the AccessedStoredBitfield defined above,
// `AccessedStorage` refers to the AccessedStorageBitfield defined above,
// setting aside enough bits for common data.
SWIFT_INLINE_BITFIELD_FULL(AccessEnforcementOptsInfo, AccessedStorage,
64 - NumAccessedStorageBits,
beginAccessIndex : 63 - NumAccessedStorageBits,
seenNestedConflict : 1);
seenNestedConflict : 1,
beginAccessIndex : 63 - NumAccessedStorageBits);
} Bits;

private:
Expand All @@ -156,7 +172,7 @@ class AccessedStorage {
initKind(Class);
}

// Return true if this is a valid storage location.
// Return true if this is a valid storage object.
operator bool() const { return getKind() != Unidentified || value; }

Kind getKind() const { return static_cast<Kind>(Bits.AccessedStorage.Kind); }
Expand Down Expand Up @@ -205,6 +221,20 @@ class AccessedStorage {
}
}

bool isLocal() const {
switch (getKind()) {
case Box:
case Stack:
return true;
case Global:
case Class:
case Argument:
case Nested:
case Unidentified:
return false;
}
}

bool isUniquelyIdentified() const {
switch (getKind()) {
case Box:
Expand All @@ -231,6 +261,13 @@ class AccessedStorage {

void print(raw_ostream &os) const;
void dump() const;

private:
// Disable direct comparison because we allow subclassing with bitfields.
// Currently, we use DenseMapInfo to unique storage, which defines key
// equalilty only in terms of the base AccessedStorage class bits.
bool operator==(const AccessedStorage &) const = delete;
bool operator!=(const AccessedStorage &) const = delete;
};
} // end namespace swift

Expand Down Expand Up @@ -300,9 +337,9 @@ namespace swift {
/// memory, return an AccessedStorage object that identifies the formal access.
///
/// The returned AccessedStorage represents the best attempt to find the base of
/// the storage location being accessed at `sourceAddr`. This may be a fully
/// the storage object being accessed at `sourceAddr`. This may be a fully
/// identified storage base of known kind, or a valid but Unidentified storage
/// location, such as a SILPHIArgument.
/// object, such as a SILPHIArgument.
///
/// This may return an invalid storage object if the address producer is not
/// recognized by a whitelist of recognizable access patterns. The result must
Expand Down Expand Up @@ -347,6 +384,14 @@ bool isPossibleFormalAccessBase(const AccessedStorage &storage, SILFunction *F);
void visitAccessedAddress(SILInstruction *I,
llvm::function_ref<void(Operand *)> visitor);

/// Perform a RAUW operation on begin_access with it's own source operand.
/// Then erase the begin_access and all associated end_access instructions.
/// Return an iterator to the following instruction.
///
/// The caller should use this iterator rather than assuming that the
/// instruction following this begin_access was not also erased.
SILBasicBlock::iterator removeBeginAccess(BeginAccessInst *beginAccess);

} // end namespace swift

#endif
4 changes: 3 additions & 1 deletion include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -3184,8 +3184,10 @@ enum class SILAccessKind : uint8_t {
Deinit,

// This enum is encoded.
Last = Deinit
Last = Deinit,
};
enum { NumSILAccessKindBits = 2 };

StringRef getSILAccessKindName(SILAccessKind kind);

/// Different kinds of exclusivity enforcement for accesses.
Expand Down
Loading