mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
* [Distributed] Initial distributed checking
* [Distributed] initial types shapes and conform to DistributedActor
* [Distributed] Require Codable params and return types
* [Distributed] initial synthesis of fields and constructors
* [Distributed] Field and initializer synthesis
* [Distributed] Codable requirement on distributed funcs; also handle <T: Codable>
* [Distributed] handle generic type params which are Codable in dist func
[Distributed] conformsToProtocol after all
* [Distributed] Implement remote flag on actors
* Implement remote flag on actors
* add test
* actor initializer that sets remote flag
[Distributed] conformances getting there
* [Distributed] dont require async throws; cleanup compile tests
* [Distributed] do not synthesize default implicit init, only our special ones
* [Distributed] properly synth inits and properties; mark actorTransport as _distributedActorIndependent
Also:
- do not synthesize default init() initializer for dist actor
* [Distributed] init(transport:) designated and typechecking
* [Distributed] dist actor initializers MUST delegate to local-init
* [Distributed] check if any ctors in delegation call init(transport:)
* [Distributed] check init(transport:) delegation through many inits; ban invoking init(resolve:using:) explicitly
* [Distributed] disable IRGen test for now
* [Distributed] Rebase cleanups
* [Concurrent] transport and address are concurrent value
* [Distributed] introduce -enable-experimental-distributed flag
* rebase adjustments again
* rebase again...
* [Distributed] distributed functions are implicitly async+throws outside the actor
* [Distributed] implicitly throwing and async distributed funcs
* remove printlns
* add more checks to implicit function test
* [Distributed] resolve initializer now marks the isRemote actor flag
* [Distributed] distributedActor_destroy invoked instead, rather than before normal
* [Distributed] Generate distributed thunk for actors
* [distributed] typechecking for _remote_ functions existing, add tests for remote funcs
* adding one XFAIL'ed task & actor lifetime test
The `executor_deinit1` test fails 100% of the time
(from what I've seen) so I thought we could track
and see when/if someone happens to fix this bug.
Also, added extra coverage for #36298 via `executor_deinit2`
* Fix a memory issue with actors in the runtime system, by @phausler
* add new test that now passes because of patch by @phausler
See previous commit in this PR.
Test is based on one from rdar://74281361
* fix all tests that require the _remote_ function stubs
* Do not infer @actorIndependent onto `let` decls
* REVERT_ME: remove some tests that hacky workarounds will fail
* another flaky test, help build toolchain
* [Distributed] experimental distributed implies experimental concurrency
* [Distributed] Allow distributed function that are not marked async or throws
* [Distributed] make attrs SIMPLE to get serialization generated
* [Distributed] ActorAddress must be Hashable
* [Distributed] Implement transport.actorReady call in local init
* cleanup after rebase
* [Distributed] add availability attributes to all distributed actor code
* cleanup - this fixed some things
* fixing up
* fixing up
* [Distributed] introduce new Distributed module
* [Distributed] diagnose when missing 'import _Distributed'
* [Distributed] make all tests import the module
* more docs on address
* [Distributed] fixup merge issues
* cleanup: remove unnecessary code for now SIMPLE attribute
* fix: fix getActorIsolationOfContext
* [Distributed] cmake: depend on _concurrency module
* fixing tests...
* Revert "another flaky test, help build toolchain"
This reverts commit 83ae6654dd.
* remove xfail
* clenup some IR and SIL tests
* cleanup
* [Distributed] fix cmake test and ScanDependencies/can_import_with_map.swift
* [Distributed] fix flags/build tests
* cleanup: use isDistributed wherever possible
* [Distributed] don't import Dispatch in tests
* dont link distributed in stdlib unittest
* trying always append distributed module
* cleanups
* [Distributed] move all tests to Distributed/ directory
* [lit] try to fix lit test discovery
* [Distributed] update tests after diagnostics for implicit async changed
* [Distributed] Disable remote func tests on Windows for now
* Review cleanups
* [Distributed] fix typo, fixes Concurrency/actor_isolation_objc.swift
* [Distributed] attributes are DistributedOnly (only)
* cleanup
* [Distributed] cleanup: rely on DistributedOnly for guarding the keyword
* Update include/swift/AST/ActorIsolation.h
Co-authored-by: Doug Gregor <dgregor@apple.com>
* introduce isAnyThunk, minor cleanup
* wip
* [Distributed] move some type checking to TypeCheckDistributed.cpp
* [TypeCheckAttr] remove extra debug info
* [Distributed/AutoDiff] fix SILDeclRef creation which caused AutoDiff issue
* cleanups
* [lit] remove json import from lit test suite, not needed after all
* [Distributed] distributed functions only in DistributedActor protocols
* [Distributed] fix flag overlap & build setting
* [Distributed] Simplify noteIsolatedActorMember to not take bool distributed param
* [Distributed] make __isRemote not public
* [Distributed] Fix availability and remove actor class tests
* [actorIndependent] do not apply actorIndependent implicitly to values where it would be illegal to apply
* [Distributed] disable tests until issue fixed
Co-authored-by: Dario Rexin <drexin@apple.com>
Co-authored-by: Kavon Farvardin <kfarvardin@apple.com>
Co-authored-by: Doug Gregor <dgregor@apple.com>
265 lines
10 KiB
C++
265 lines
10 KiB
C++
//===--- AccessEnforcementReleaseSinking.cpp - release sinking opt ---===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2018 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// This function pass sinks releases out of access scopes.
|
|
///
|
|
/// General case:
|
|
/// begin_access A
|
|
/// ...
|
|
/// strong_release / release_value / destroy
|
|
/// end_access
|
|
///
|
|
/// The release instruction can be sunk below the end_access instruction,
|
|
/// This extends the lifetime of the released value, but, might allow us to
|
|
/// Mark the access scope as no nested conflict.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "access-enforcement-release"
|
|
|
|
#include "swift/SIL/ApplySite.h"
|
|
#include "swift/SIL/DebugUtils.h"
|
|
#include "swift/SIL/InstructionUtils.h"
|
|
#include "swift/SIL/SILFunction.h"
|
|
#include "swift/SILOptimizer/PassManager/Transforms.h"
|
|
|
|
using namespace swift;
|
|
|
|
// Returns a bool: If this is a "sinkable" instruction type for this opt
|
|
static bool isSinkable(SILInstruction &inst) {
|
|
switch (inst.getKind()) {
|
|
default:
|
|
return false;
|
|
case SILInstructionKind::DestroyValueInst:
|
|
case SILInstructionKind::ReleaseValueInst:
|
|
case SILInstructionKind::ReleaseValueAddrInst:
|
|
case SILInstructionKind::StrongReleaseInst:
|
|
case SILInstructionKind::UnmanagedReleaseValueInst:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Returns a bool: If this is a "barrier" instruction for this opt
|
|
static bool isBarrier(SILInstruction *inst) {
|
|
// Calls hide many dangers, from checking reference counts, to beginning
|
|
// keypath access, to forcing memory to be live. Checking for these and other
|
|
// possible barries at ever call is certainly not worth it.
|
|
if (FullApplySite::isa(inst) != FullApplySite())
|
|
return true;
|
|
|
|
// Don't extend lifetime past any sort of uniqueness check.
|
|
if (mayCheckRefCount(inst))
|
|
return true;
|
|
|
|
// Don't extend object lifetime past deallocation.
|
|
if (isa<DeallocationInst>(inst))
|
|
return true;
|
|
|
|
// Avoid introducing access conflicts.
|
|
if (isa<BeginAccessInst>(inst) || isa<BeginUnpairedAccessInst>(inst))
|
|
return true;
|
|
|
|
if (auto *BI = dyn_cast<BuiltinInst>(inst)) {
|
|
auto kind = BI->getBuiltinKind();
|
|
if (!kind)
|
|
return false; // LLVM intrinsics are not barriers.
|
|
|
|
// Whitelist the safe builtin categories. Builtins should generally be
|
|
// treated conservatively, because introducing a new builtin does not
|
|
// require updating all passes to be aware of it.
|
|
switch (kind.getValue()) {
|
|
case BuiltinValueKind::None:
|
|
llvm_unreachable("Builtin must has a non-empty kind.");
|
|
|
|
// Unhandled categories don't generate a case. Instead, they result
|
|
// in a build error: enumeration values not handled in switch.
|
|
#define BUILTIN(Id, Name, Attrs)
|
|
|
|
#define BUILTIN_NO_BARRIER(Id) \
|
|
case BuiltinValueKind::Id: \
|
|
return false;
|
|
#define BUILTIN_CAST_OPERATION(Id, Name, Attrs) BUILTIN_NO_BARRIER(Id)
|
|
#define BUILTIN_CAST_OR_BITCAST_OPERATION(Id, Name, Attrs) \
|
|
BUILTIN_NO_BARRIER(Id)
|
|
#define BUILTIN_BINARY_OPERATION(Id, Name, Attrs) BUILTIN_NO_BARRIER(Id)
|
|
#define BUILTIN_BINARY_OPERATION_WITH_OVERFLOW(Id, Name, UncheckedID, Attrs, \
|
|
Overload) \
|
|
BUILTIN_NO_BARRIER(Id)
|
|
#define BUILTIN_UNARY_OPERATION(Id, Name, Attrs, Overload) \
|
|
BUILTIN_NO_BARRIER(Id)
|
|
#define BUILTIN_BINARY_PREDICATE(Id, Name, Attrs, Overload) \
|
|
BUILTIN_NO_BARRIER(Id)
|
|
#define BUILTIN_SIL_OPERATION(Id, Name, Overload) \
|
|
case BuiltinValueKind::Id: \
|
|
llvm_unreachable("SIL operation must be lowered to instructions.");
|
|
#define BUILTIN_RUNTIME_CALL(Id, Name, Attrs) \
|
|
case BuiltinValueKind::Id: \
|
|
return true; // A runtime call could be anything.
|
|
|
|
#define BUILTIN_SANITIZER_OPERATION(Id, Name, Attrs) BUILTIN_NO_BARRIER(Id)
|
|
#define BUILTIN_TYPE_CHECKER_OPERATION(Id, Name) BUILTIN_NO_BARRIER(Id)
|
|
#define BUILTIN_TYPE_TRAIT_OPERATION(Id, Name) BUILTIN_NO_BARRIER(Id)
|
|
#include "swift/AST/Builtins.def"
|
|
|
|
// Handle BUILTIN_MISC_OPERATIONs individually.
|
|
case BuiltinValueKind::Sizeof:
|
|
case BuiltinValueKind::Strideof:
|
|
case BuiltinValueKind::IsPOD:
|
|
case BuiltinValueKind::IsConcrete:
|
|
case BuiltinValueKind::IsBitwiseTakable:
|
|
case BuiltinValueKind::IsSameMetatype:
|
|
case BuiltinValueKind::Alignof:
|
|
case BuiltinValueKind::OnFastPath:
|
|
case BuiltinValueKind::ExtractElement:
|
|
case BuiltinValueKind::InsertElement:
|
|
case BuiltinValueKind::ShuffleVector:
|
|
case BuiltinValueKind::StaticReport:
|
|
case BuiltinValueKind::AssertConf:
|
|
case BuiltinValueKind::StringObjectOr:
|
|
case BuiltinValueKind::UToSCheckedTrunc:
|
|
case BuiltinValueKind::SToUCheckedTrunc:
|
|
case BuiltinValueKind::SToSCheckedTrunc:
|
|
case BuiltinValueKind::UToUCheckedTrunc:
|
|
case BuiltinValueKind::IntToFPWithOverflow:
|
|
case BuiltinValueKind::ZeroInitializer:
|
|
case BuiltinValueKind::Once:
|
|
case BuiltinValueKind::OnceWithContext:
|
|
case BuiltinValueKind::GetObjCTypeEncoding:
|
|
case BuiltinValueKind::Swift3ImplicitObjCEntrypoint:
|
|
case BuiltinValueKind::WillThrow:
|
|
case BuiltinValueKind::CondFailMessage:
|
|
case BuiltinValueKind::PoundAssert:
|
|
case BuiltinValueKind::TypePtrAuthDiscriminator:
|
|
case BuiltinValueKind::GlobalStringTablePointer:
|
|
case BuiltinValueKind::COWBufferForReading:
|
|
case BuiltinValueKind::IntInstrprofIncrement:
|
|
case BuiltinValueKind::GetCurrentAsyncTask:
|
|
case BuiltinValueKind::GetCurrentExecutor:
|
|
case BuiltinValueKind::AutoDiffCreateLinearMapContext:
|
|
case BuiltinValueKind::EndAsyncLet:
|
|
case BuiltinValueKind::CreateTaskGroup:
|
|
case BuiltinValueKind::DestroyTaskGroup:
|
|
return false;
|
|
|
|
// Handle some rare builtins that may be sensitive to object lifetime
|
|
// or deinit side effects conservatively.
|
|
case BuiltinValueKind::AllocRaw:
|
|
case BuiltinValueKind::DeallocRaw:
|
|
case BuiltinValueKind::Fence:
|
|
case BuiltinValueKind::AtomicLoad:
|
|
case BuiltinValueKind::AtomicStore:
|
|
case BuiltinValueKind::AtomicRMW:
|
|
case BuiltinValueKind::Unreachable:
|
|
case BuiltinValueKind::CmpXChg:
|
|
case BuiltinValueKind::CondUnreachable:
|
|
case BuiltinValueKind::DestroyArray:
|
|
case BuiltinValueKind::CopyArray:
|
|
case BuiltinValueKind::TakeArrayNoAlias:
|
|
case BuiltinValueKind::TakeArrayFrontToBack:
|
|
case BuiltinValueKind::TakeArrayBackToFront:
|
|
case BuiltinValueKind::AssignCopyArrayNoAlias:
|
|
case BuiltinValueKind::AssignCopyArrayFrontToBack:
|
|
case BuiltinValueKind::AssignCopyArrayBackToFront:
|
|
case BuiltinValueKind::AssignTakeArray:
|
|
case BuiltinValueKind::UnsafeGuaranteed:
|
|
case BuiltinValueKind::UnsafeGuaranteedEnd:
|
|
case BuiltinValueKind::CancelAsyncTask:
|
|
case BuiltinValueKind::StartAsyncLet:
|
|
case BuiltinValueKind::CreateAsyncTaskFuture:
|
|
case BuiltinValueKind::CreateAsyncTaskGroupFuture:
|
|
case BuiltinValueKind::ConvertTaskToJob:
|
|
case BuiltinValueKind::InitializeDefaultActor:
|
|
case BuiltinValueKind::DestroyDefaultActor:
|
|
case BuiltinValueKind::InitializeDistributedRemoteActor:
|
|
case BuiltinValueKind::DestroyDistributedActor:
|
|
case BuiltinValueKind::BuildOrdinarySerialExecutorRef:
|
|
case BuiltinValueKind::BuildDefaultActorExecutorRef:
|
|
case BuiltinValueKind::BuildMainActorExecutorRef:
|
|
case BuiltinValueKind::ResumeNonThrowingContinuationReturning:
|
|
case BuiltinValueKind::ResumeThrowingContinuationReturning:
|
|
case BuiltinValueKind::ResumeThrowingContinuationThrowing:
|
|
case BuiltinValueKind::AutoDiffProjectTopLevelSubcontext:
|
|
case BuiltinValueKind::AutoDiffAllocateSubcontext:
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Processes a block bottom-up, keeping a lookout for end_access instructions
|
|
// If we encounter a "barrier" we clear out the current end_access
|
|
// If we encounter a "release", and we have a current end_access, we sink it
|
|
static void processBlock(SILBasicBlock &block) {
|
|
EndAccessInst *bottomEndAccessInst = nullptr;
|
|
for (auto reverseIt = block.rbegin(); reverseIt != block.rend();
|
|
++reverseIt) {
|
|
SILInstruction &currIns = *reverseIt;
|
|
if (auto *currEAI = dyn_cast<EndAccessInst>(&currIns)) {
|
|
if (!bottomEndAccessInst) {
|
|
bottomEndAccessInst = currEAI;
|
|
}
|
|
} else if (isBarrier(&currIns)) {
|
|
LLVM_DEBUG(llvm::dbgs() << "Found a barrier " << currIns
|
|
<< ", clearing last seen end_access\n");
|
|
bottomEndAccessInst = nullptr;
|
|
} else if (isSinkable(currIns)) {
|
|
LLVM_DEBUG(llvm::dbgs()
|
|
<< "Found a sinkable instruction " << currIns << "\n");
|
|
if (!bottomEndAccessInst) {
|
|
LLVM_DEBUG(
|
|
llvm::dbgs()
|
|
<< "Cannot be sunk: no open barrier-less end_access found\n");
|
|
continue;
|
|
}
|
|
LLVM_DEBUG(llvm::dbgs() << "Moving sinkable instruction below "
|
|
<< *bottomEndAccessInst << "\n");
|
|
// We need to avoid iterator invalidation:
|
|
// We know this is not the last instruction of the block:
|
|
// 1) not a TermInst
|
|
// 2) bottomEndAccessInst != nil
|
|
assert(reverseIt != block.rbegin() &&
|
|
"Did not expect a sinkable instruction at block's end");
|
|
// Go back to previous iteration
|
|
auto prevIt = reverseIt;
|
|
--prevIt;
|
|
// Move the instruction after the end_access
|
|
currIns.moveAfter(bottomEndAccessInst);
|
|
// make reverseIt into a valid iterator again
|
|
reverseIt = prevIt;
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
struct AccessEnforcementReleaseSinking : public SILFunctionTransform {
|
|
void run() override {
|
|
SILFunction *F = getFunction();
|
|
if (F->empty())
|
|
return;
|
|
|
|
// FIXME: Support ownership.
|
|
if (F->hasOwnership())
|
|
return;
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << "Running AccessEnforcementReleaseSinking on "
|
|
<< F->getName() << "\n");
|
|
|
|
for (SILBasicBlock &currBB : *F) {
|
|
processBlock(currBB);
|
|
}
|
|
}
|
|
};
|
|
} // namespace
|
|
|
|
SILTransform *swift::createAccessEnforcementReleaseSinking() {
|
|
return new AccessEnforcementReleaseSinking();
|
|
}
|