mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
The original design was to make it so that end_borrow tied at the use level its original/borrowed value. So we would have: ``` %borrowedVal = begin_borrow %original ... end_borrow %borrowedVal from %original ``` In the end we decided not to use that design and instead just use: ``` %borrowedVal = begin_borrow %original ... end_borrow %borrowedVal ``` In order to enable that transition, I left the old API for end_borrow that took both original and borrowedVal and reimplemented it on top of the new API that just took the borrowedVal (i.e. the original was just a dead arg). Now given where we are in the development, it makes sense to get rid of that transition API and move to just use the new API.
203 lines
7.2 KiB
C++
203 lines
7.2 KiB
C++
//===--- FormalEvaluation.cpp ---------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "FormalEvaluation.h"
|
|
#include "LValue.h"
|
|
#include "SILGenFunction.h"
|
|
|
|
using namespace swift;
|
|
using namespace Lowering;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Formal Access
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
void FormalAccess::_anchor() {}
|
|
|
|
void FormalAccess::verify(SILGenFunction &SGF) const {
|
|
#ifndef NDEBUG
|
|
// If this access was already finished, continue. This can happen if an
|
|
// owned formal access was forwarded.
|
|
if (isFinished()) {
|
|
assert(getKind() == FormalAccess::Owned &&
|
|
"Only owned formal accesses should be forwarded.");
|
|
// We can not check that our cleanup is actually dead since the cleanup
|
|
// may have been popped at this point and the stack may have new values.
|
|
return;
|
|
}
|
|
|
|
assert(!isFinished() && "Can not finish a formal access cleanup "
|
|
"twice");
|
|
|
|
// Now try to look up the cleanup handle of the formal access.
|
|
SGF.Cleanups.checkIterator(getCleanup());
|
|
#endif
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Shared Borrow Formal Evaluation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
void SharedBorrowFormalAccess::finishImpl(SILGenFunction &SGF) {
|
|
SGF.B.createEndBorrow(CleanupLocation::get(loc), borrowedValue);
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// OwnedFormalAccess
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
void OwnedFormalAccess::finishImpl(SILGenFunction &SGF) {
|
|
auto cleanupLoc = CleanupLocation::get(loc);
|
|
if (value->getType().isAddress())
|
|
SGF.B.createDestroyAddr(cleanupLoc, value);
|
|
else
|
|
SGF.B.emitDestroyValueOperation(cleanupLoc, value);
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Formal Evaluation Scope
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
FormalEvaluationScope::FormalEvaluationScope(SILGenFunction &SGF)
|
|
: SGF(SGF), savedDepth(SGF.FormalEvalContext.stable_begin()),
|
|
previous(SGF.FormalEvalContext.innermostScope),
|
|
wasInInOutConversionScope(SGF.InInOutConversionScope) {
|
|
if (wasInInOutConversionScope) {
|
|
savedDepth.reset();
|
|
assert(isPopped());
|
|
return;
|
|
}
|
|
SGF.FormalEvalContext.innermostScope = this;
|
|
}
|
|
|
|
FormalEvaluationScope::FormalEvaluationScope(FormalEvaluationScope &&o)
|
|
: SGF(o.SGF), savedDepth(o.savedDepth), previous(o.previous),
|
|
wasInInOutConversionScope(o.wasInInOutConversionScope) {
|
|
|
|
// Replace the scope in the active-scope chain if it's present.
|
|
if (!o.isPopped()) {
|
|
for (auto c = &SGF.FormalEvalContext.innermostScope; ; c = &(*c)->previous){
|
|
if (*c == &o) {
|
|
*c = this;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
o.savedDepth.reset();
|
|
assert(o.isPopped());
|
|
}
|
|
|
|
void FormalEvaluationScope::popImpl() {
|
|
auto &context = SGF.FormalEvalContext;
|
|
|
|
// Remove the innermost scope from the chain.
|
|
assert(context.innermostScope == this &&
|
|
"popping formal-evaluation scopes out of order");
|
|
context.innermostScope = previous;
|
|
|
|
auto endDepth = *savedDepth;
|
|
|
|
// Check to see if there is anything going on here.
|
|
if (endDepth == context.stable_begin())
|
|
return;
|
|
|
|
#ifndef NDEBUG
|
|
// Verify that all the accesses are valid.
|
|
for (auto i = context.begin(), e = context.find(endDepth); i != e; ++i) {
|
|
i->verify(SGF);
|
|
}
|
|
#endif
|
|
|
|
// Save our start point to make sure that we are not adding any new cleanups
|
|
// to the front of the stack.
|
|
auto originalBegin = context.stable_begin();
|
|
|
|
// Then working down the stack until we visit unwrappedSavedDepth...
|
|
auto i = originalBegin;
|
|
do {
|
|
// Grab the next evaluation.
|
|
FormalAccess &access = context.findAndAdvance(i);
|
|
|
|
// If this access was already finished, continue. This can happen if an
|
|
// owned formal access was forwarded.
|
|
if (access.isFinished()) {
|
|
assert(access.getKind() == FormalAccess::Owned &&
|
|
"Only owned formal accesses should be forwarded.");
|
|
// We can not check that our cleanup is actually dead since the cleanup
|
|
// may have been popped at this point and the stack may have new values.
|
|
continue;
|
|
}
|
|
|
|
assert(!access.isFinished() && "Can not finish a formal access cleanup "
|
|
"twice");
|
|
|
|
// Set the finished bit to appease various invariants.
|
|
access.setFinished();
|
|
|
|
// Deactivate the cleanup.
|
|
SGF.Cleanups.setCleanupState(access.getCleanup(), CleanupState::Dead);
|
|
|
|
// Attempt to diagnose problems where obvious aliasing introduces illegal
|
|
// code. We do a simple N^2 comparison here to detect this because it is
|
|
// extremely unlikely more than a few writebacks are active at once.
|
|
if (access.getKind() == FormalAccess::Exclusive) {
|
|
// Note that we already advanced 'iter' above, so we can just start
|
|
// iterating from there. Also, this doesn't invalidate the iterators.
|
|
for (auto j = context.find(i), je = context.find(endDepth); j != je; ++j){
|
|
FormalAccess &other = *j;
|
|
if (other.getKind() != FormalAccess::Exclusive)
|
|
continue;
|
|
auto &lhs = static_cast<ExclusiveBorrowFormalAccess &>(access);
|
|
auto &rhs = static_cast<ExclusiveBorrowFormalAccess &>(other);
|
|
lhs.diagnoseConflict(rhs, SGF);
|
|
}
|
|
}
|
|
|
|
// Claim the address of each and then perform the writeback from the
|
|
// temporary allocation to the source we copied from.
|
|
//
|
|
// This evaluates arbitrary code, so it's best to be paranoid
|
|
// about iterators on the context.
|
|
DiverseValueBuffer<FormalAccess> copiedAccess(access);
|
|
copiedAccess.getCopy().finish(SGF);
|
|
|
|
} while (i != endDepth);
|
|
|
|
// Then check that we did not add any additional cleanups to the beginning of
|
|
// the stack...
|
|
assert(originalBegin == context.stable_begin() &&
|
|
"pushed more formal evaluations while popping formal evaluations?!");
|
|
|
|
// And then pop off all stack elements until we reach the savedDepth.
|
|
context.pop(endDepth);
|
|
}
|
|
|
|
void FormalEvaluationScope::verify() const {
|
|
// Walk up the stack to the saved depth.
|
|
auto &context = SGF.FormalEvalContext;
|
|
for (auto i = context.begin(), e = context.find(*savedDepth); i != e; ++i) {
|
|
i->verify(SGF);
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Formal Evaluation Context
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
void FormalEvaluationContext::dump(SILGenFunction &SGF) {
|
|
for (auto II = begin(), IE = end(); II != IE; ++II) {
|
|
FormalAccess &access = *II;
|
|
SGF.Cleanups.dump(access.getCleanup());
|
|
}
|
|
}
|