blob: 211cd5a53c1f032ee228001b0c31a1f01e0522e3 [file] [log] [blame]
//===--- 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() {}
//===----------------------------------------------------------------------===//
// Shared Borrow Formal Evaluation
//===----------------------------------------------------------------------===//
void SharedBorrowFormalAccess::finishImpl(SILGenFunction &gen) {
gen.B.createEndBorrow(CleanupLocation::get(loc), borrowedValue,
originalValue);
}
//===----------------------------------------------------------------------===//
// OwnedFormalAccess
//===----------------------------------------------------------------------===//
void OwnedFormalAccess::finishImpl(SILGenFunction &gen) {
auto cleanupLoc = CleanupLocation::get(loc);
if (value->getType().isAddress())
gen.B.createDestroyAddr(cleanupLoc, value);
else
gen.B.emitDestroyValueOperation(cleanupLoc, value);
}
//===----------------------------------------------------------------------===//
// Formal Evaluation Scope
//===----------------------------------------------------------------------===//
FormalEvaluationScope::FormalEvaluationScope(SILGenFunction &gen)
: gen(gen), savedDepth(gen.FormalEvalContext.stable_begin()),
wasInWritebackScope(gen.InWritebackScope) {
if (gen.InInOutConversionScope) {
savedDepth.reset();
return;
}
gen.InWritebackScope = true;
}
FormalEvaluationScope::FormalEvaluationScope(FormalEvaluationScope &&o)
: gen(o.gen), savedDepth(o.savedDepth),
wasInWritebackScope(o.wasInWritebackScope) {
o.savedDepth.reset();
}
void FormalEvaluationScope::popImpl() {
// Pop the InWritebackScope bit.
gen.InWritebackScope = wasInWritebackScope;
// Check to see if there is anything going on here.
auto &context = gen.FormalEvalContext;
using iterator = FormalEvaluationContext::iterator;
using stable_iterator = FormalEvaluationContext::stable_iterator;
iterator unwrappedSavedDepth = context.find(savedDepth.getValue());
iterator iter = context.begin();
if (iter == unwrappedSavedDepth)
return;
// Save our start point to make sure that we are not adding any new cleanups
// to the front of the stack.
stable_iterator originalBegin = context.stable_begin();
// Then working down the stack until we visit unwrappedSavedDepth...
for (; iter != unwrappedSavedDepth; ++iter) {
// Grab the next evaluation...
FormalAccess &access = *iter;
// 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");
// and deactivate the cleanup. This will set the isFinished bit for owned
// FormalAccess.
gen.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) {
iterator j = iter;
++j;
for (; j != unwrappedSavedDepth; ++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, gen);
}
}
// 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.
access.finish(gen);
}
// Then check that we did not add any additional cleanups to the beginning of
// the stack...
assert(originalBegin == context.stable_begin() &&
"more writebacks placed onto context during writeback scope pop?!");
// And then pop off all stack elements until we reach the savedDepth.
context.pop(savedDepth.getValue());
}
//===----------------------------------------------------------------------===//
// Formal Evaluation Context
//===----------------------------------------------------------------------===//
void FormalEvaluationContext::dump(SILGenFunction &gen) {
for (auto II = begin(), IE = end(); II != IE; ++II) {
FormalAccess &access = *II;
gen.Cleanups.dump(access.getCleanup());
}
}