diff --git a/include/swift/SIL/SILNodes.def b/include/swift/SIL/SILNodes.def index e438682d8869b..7148a46b82f9d 100644 --- a/include/swift/SIL/SILNodes.def +++ b/include/swift/SIL/SILNodes.def @@ -592,7 +592,7 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction) // Accessing memory SINGLE_VALUE_INST(LoadInst, load, - SingleValueInstruction, MayRead, DoesNotRelease) + SingleValueInstruction, MayHaveSideEffects, DoesNotRelease) SINGLE_VALUE_INST(LoadBorrowInst, load_borrow, SingleValueInstruction, MayRead, DoesNotRelease) SINGLE_VALUE_INST(BeginBorrowInst, begin_borrow, @@ -852,7 +852,7 @@ NON_VALUE_INST(BeginUnpairedAccessInst, begin_unpaired_access, NON_VALUE_INST(EndUnpairedAccessInst, end_unpaired_access, SILInstruction, MayHaveSideEffects, DoesNotRelease) NON_VALUE_INST(StoreInst, store, - SILInstruction, MayWrite, DoesNotRelease) + SILInstruction, MayHaveSideEffects, MayRelease) NON_VALUE_INST(AssignInst, assign, SILInstruction, MayWrite, DoesNotRelease) NON_VALUE_INST(AssignByWrapperInst, assign_by_wrapper, diff --git a/lib/SIL/IR/SILInstruction.cpp b/lib/SIL/IR/SILInstruction.cpp index 7d05a902c11b8..540c49c086f5c 100644 --- a/lib/SIL/IR/SILInstruction.cpp +++ b/lib/SIL/IR/SILInstruction.cpp @@ -1029,6 +1029,36 @@ SILInstruction::MemoryBehavior SILInstruction::getMemoryBehavior() const { MemoryBehavior::MayHaveSideEffects; } + if (auto *li = dyn_cast(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(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()) { #define FULL_INST(CLASS, TEXTUALNAME, PARENT, MEMBEHAVIOR, RELEASINGBEHAVIOR) \ case SILInstructionKind::CLASS: \ @@ -1138,6 +1168,18 @@ bool SILInstruction::mayRelease() const { } return true; } + case SILInstructionKind::StoreInst: + switch (cast(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?!"); } } diff --git a/lib/SILOptimizer/Analysis/MemoryBehavior.cpp b/lib/SILOptimizer/Analysis/MemoryBehavior.cpp index aac68b590a2d2..c84e2ea670319 100644 --- a/lib/SILOptimizer/Analysis/MemoryBehavior.cpp +++ b/lib/SILOptimizer/Analysis/MemoryBehavior.cpp @@ -242,12 +242,15 @@ MemBehavior MemoryBehaviorVisitor::visitLoadInst(LoadInst *LI) { if (!mayAlias(LI->getOperand())) 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 " - "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; } @@ -257,15 +260,17 @@ MemBehavior MemoryBehaviorVisitor::visitStoreInst(StoreInst *SI) { if (isLetValue() && (getAccessBase(SI->getDest()) != getValueAddress())) { return MemBehavior::None; } - // If the store dest cannot alias the pointer in question, then the - // specified value cannot be modified by the store. - if (!mayAlias(SI->getDest())) + // If the store dest cannot alias the pointer in question and we are not + // releasing anything due to an assign, then the specified value cannot be + // modified by the store. + if (!mayAlias(SI->getDest()) && + SI->getOwnershipQualifier() != StoreOwnershipQualifier::Assign) return MemBehavior::None; // Otherwise, a store just writes. LLVM_DEBUG(llvm::dbgs() << " Could not prove store does not alias inst. " - "Returning MayWrite.\n"); - return MemBehavior::MayWrite; + "Returning default mem behavior.\n"); + return SI->getMemoryBehavior(); } MemBehavior MemoryBehaviorVisitor::visitCopyAddrInst(CopyAddrInst *CAI) { diff --git a/lib/SILOptimizer/Analysis/SideEffectAnalysis.cpp b/lib/SILOptimizer/Analysis/SideEffectAnalysis.cpp index 017edb97342a4..048fd15473a4a 100644 --- a/lib/SILOptimizer/Analysis/SideEffectAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/SideEffectAnalysis.cpp @@ -539,12 +539,29 @@ void FunctionSideEffects::analyzeInstruction(SILInstruction *I) { true; Traps = true; return; - case SILInstructionKind::LoadInst: - getEffectsOn(cast(I)->getOperand())->Reads = true; + case SILInstructionKind::LoadBorrowInst: { + auto *effects = getEffectsOn(cast(I)->getOperand()); + effects->Reads = true; return; - case SILInstructionKind::StoreInst: - getEffectsOn(cast(I)->getDest())->Writes = true; + } + case SILInstructionKind::LoadInst: { + auto *li = cast(I); + auto *effects = getEffectsOn(cast(I)->getOperand()); + effects->Reads = true; + if (li->getOwnershipQualifier() == LoadOwnershipQualifier::Take) + effects->Writes = true; + if (li->getOwnershipQualifier() == LoadOwnershipQualifier::Copy) + effects->Retains = true; + return; + } + case SILInstructionKind::StoreInst: { + auto *si = cast(I); + auto *effects = getEffectsOn(si->getDest()); + effects->Writes = true; + if (si->getOwnershipQualifier() == StoreOwnershipQualifier::Assign) + effects->Releases = true; return; + } case SILInstructionKind::CondFailInst: Traps = true; return;