[membehavior] Fix base memory behavior/releasing of Load/Store for ownership.

load, store in ossa can have side-effects and stores can release. Specifically:

Memory Behavior
---------------

* Load: unqualified, trivial, take have a read side-effect, but copy retains so
  has side-effects.

* Store: unqualified, trivial, init may write but assign releases so it may have
  side-effects.

Release Behavior
----------------

* Load: No changes.

* Store: May release if store has assign as an ownership qualifier.
This commit is contained in:
Michael Gottesman
2020-11-02 12:14:23 -08:00
parent 891e115b53
commit c3681a6eef
4 changed files with 80 additions and 16 deletions

View File

@@ -592,7 +592,7 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction)
// Accessing memory // Accessing memory
SINGLE_VALUE_INST(LoadInst, load, SINGLE_VALUE_INST(LoadInst, load,
SingleValueInstruction, MayRead, DoesNotRelease) SingleValueInstruction, MayHaveSideEffects, DoesNotRelease)
SINGLE_VALUE_INST(LoadBorrowInst, load_borrow, SINGLE_VALUE_INST(LoadBorrowInst, load_borrow,
SingleValueInstruction, MayRead, DoesNotRelease) SingleValueInstruction, MayRead, DoesNotRelease)
SINGLE_VALUE_INST(BeginBorrowInst, begin_borrow, SINGLE_VALUE_INST(BeginBorrowInst, begin_borrow,
@@ -852,7 +852,7 @@ NON_VALUE_INST(BeginUnpairedAccessInst, begin_unpaired_access,
NON_VALUE_INST(EndUnpairedAccessInst, end_unpaired_access, NON_VALUE_INST(EndUnpairedAccessInst, end_unpaired_access,
SILInstruction, MayHaveSideEffects, DoesNotRelease) SILInstruction, MayHaveSideEffects, DoesNotRelease)
NON_VALUE_INST(StoreInst, store, NON_VALUE_INST(StoreInst, store,
SILInstruction, MayWrite, DoesNotRelease) SILInstruction, MayHaveSideEffects, MayRelease)
NON_VALUE_INST(AssignInst, assign, NON_VALUE_INST(AssignInst, assign,
SILInstruction, MayWrite, DoesNotRelease) SILInstruction, MayWrite, DoesNotRelease)
NON_VALUE_INST(AssignByWrapperInst, assign_by_wrapper, NON_VALUE_INST(AssignByWrapperInst, assign_by_wrapper,

View File

@@ -1029,6 +1029,36 @@ SILInstruction::MemoryBehavior SILInstruction::getMemoryBehavior() const {
MemoryBehavior::MayHaveSideEffects; MemoryBehavior::MayHaveSideEffects;
} }
if (auto *li = dyn_cast<LoadInst>(this)) {
switch (li->getOwnershipQualifier()) {
case LoadOwnershipQualifier::Unqualified:
case LoadOwnershipQualifier::Trivial:
return MemoryBehavior::MayRead;
case LoadOwnershipQualifier::Take:
// Take deinitializes the underlying memory. Until we separate notions of
// memory writing from deinitialization (since a take doesn't actually
// write to the memory), lets be conservative and treat it as may read
// write.
return MemoryBehavior::MayReadWrite;
case LoadOwnershipQualifier::Copy:
return MemoryBehavior::MayHaveSideEffects;
}
llvm_unreachable("Covered switch isn't covered?!");
}
if (auto *si = dyn_cast<StoreInst>(this)) {
switch (si->getOwnershipQualifier()) {
case StoreOwnershipQualifier::Unqualified:
case StoreOwnershipQualifier::Trivial:
case StoreOwnershipQualifier::Init:
return MemoryBehavior::MayWrite;
case StoreOwnershipQualifier::Assign:
// For the release.
return MemoryBehavior::MayHaveSideEffects;
}
llvm_unreachable("Covered switch isn't covered?!");
}
switch (getKind()) { switch (getKind()) {
#define FULL_INST(CLASS, TEXTUALNAME, PARENT, MEMBEHAVIOR, RELEASINGBEHAVIOR) \ #define FULL_INST(CLASS, TEXTUALNAME, PARENT, MEMBEHAVIOR, RELEASINGBEHAVIOR) \
case SILInstructionKind::CLASS: \ case SILInstructionKind::CLASS: \
@@ -1138,6 +1168,18 @@ bool SILInstruction::mayRelease() const {
} }
return true; return true;
} }
case SILInstructionKind::StoreInst:
switch (cast<StoreInst>(this)->getOwnershipQualifier()) {
case StoreOwnershipQualifier::Unqualified:
case StoreOwnershipQualifier::Init:
case StoreOwnershipQualifier::Trivial:
return false;
case StoreOwnershipQualifier::Assign:
// Assign destroys the old value that was in the memory location before we
// write the new value into the location.
return true;
}
llvm_unreachable("Covered switch isn't covered?!");
} }
} }

View File

@@ -242,12 +242,15 @@ MemBehavior MemoryBehaviorVisitor::visitLoadInst(LoadInst *LI) {
if (!mayAlias(LI->getOperand())) if (!mayAlias(LI->getOperand()))
return MemBehavior::None; return MemBehavior::None;
// A take is modelled as a write. See MemoryBehavior::MayWrite.
if (LI->getOwnershipQualifier() == LoadOwnershipQualifier::Take)
return MemBehavior::MayReadWrite;
LLVM_DEBUG(llvm::dbgs() << " Could not prove that load inst does not alias " LLVM_DEBUG(llvm::dbgs() << " Could not prove that load inst does not alias "
"pointer. Returning may read.\n"); "pointer. ");
if (LI->getOwnershipQualifier() == LoadOwnershipQualifier::Take) {
LLVM_DEBUG(llvm::dbgs() << "Is a take so return MayReadWrite.\n");
return MemBehavior::MayReadWrite;
}
LLVM_DEBUG(llvm::dbgs() << "Not a take so returning MayRead.\n");
return MemBehavior::MayRead; return MemBehavior::MayRead;
} }
@@ -257,15 +260,17 @@ MemBehavior MemoryBehaviorVisitor::visitStoreInst(StoreInst *SI) {
if (isLetValue() && (getAccessBase(SI->getDest()) != getValueAddress())) { if (isLetValue() && (getAccessBase(SI->getDest()) != getValueAddress())) {
return MemBehavior::None; return MemBehavior::None;
} }
// If the store dest cannot alias the pointer in question, then the // If the store dest cannot alias the pointer in question and we are not
// specified value cannot be modified by the store. // releasing anything due to an assign, then the specified value cannot be
if (!mayAlias(SI->getDest())) // modified by the store.
if (!mayAlias(SI->getDest()) &&
SI->getOwnershipQualifier() != StoreOwnershipQualifier::Assign)
return MemBehavior::None; return MemBehavior::None;
// Otherwise, a store just writes. // Otherwise, a store just writes.
LLVM_DEBUG(llvm::dbgs() << " Could not prove store does not alias inst. " LLVM_DEBUG(llvm::dbgs() << " Could not prove store does not alias inst. "
"Returning MayWrite.\n"); "Returning default mem behavior.\n");
return MemBehavior::MayWrite; return SI->getMemoryBehavior();
} }
MemBehavior MemoryBehaviorVisitor::visitCopyAddrInst(CopyAddrInst *CAI) { MemBehavior MemoryBehaviorVisitor::visitCopyAddrInst(CopyAddrInst *CAI) {

View File

@@ -539,12 +539,29 @@ void FunctionSideEffects::analyzeInstruction(SILInstruction *I) {
true; true;
Traps = true; Traps = true;
return; return;
case SILInstructionKind::LoadInst: case SILInstructionKind::LoadBorrowInst: {
getEffectsOn(cast<LoadInst>(I)->getOperand())->Reads = true; auto *effects = getEffectsOn(cast<LoadBorrowInst>(I)->getOperand());
effects->Reads = true;
return; return;
case SILInstructionKind::StoreInst: }
getEffectsOn(cast<StoreInst>(I)->getDest())->Writes = true; case SILInstructionKind::LoadInst: {
auto *li = cast<LoadInst>(I);
auto *effects = getEffectsOn(cast<LoadInst>(I)->getOperand());
effects->Reads = true;
if (li->getOwnershipQualifier() == LoadOwnershipQualifier::Take)
effects->Writes = true;
if (li->getOwnershipQualifier() == LoadOwnershipQualifier::Copy)
effects->Retains = true;
return; return;
}
case SILInstructionKind::StoreInst: {
auto *si = cast<StoreInst>(I);
auto *effects = getEffectsOn(si->getDest());
effects->Writes = true;
if (si->getOwnershipQualifier() == StoreOwnershipQualifier::Assign)
effects->Releases = true;
return;
}
case SILInstructionKind::CondFailInst: case SILInstructionKind::CondFailInst:
Traps = true; Traps = true;
return; return;