Skip to content

Commit 4344541

Browse files
authored
Merge pull request #36643 from rjmccall/lower-hop-to-actor
Require that hop_to_executor eventually actually takes an executor
2 parents b70c967 + 4f6f8b3 commit 4344541

24 files changed

+648
-81
lines changed

docs/SIL.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3302,7 +3302,7 @@ hop_to_executor
33023302

33033303
hop_to_executor %0 : $T
33043304

3305-
// $T must conform to the Actor protocol
3305+
// $T must be Builtin.Executor or conform to the Actor protocol
33063306

33073307
Ensures that all instructions, which need to run on the actor's executor
33083308
actually run on that executor.
@@ -3312,6 +3312,11 @@ Checks if the current executor is the one which is bound to the operand actor.
33123312
If not, begins a suspension point and enqueues the continuation to the executor
33133313
which is bound to the operand actor.
33143314

3315+
SIL generation emits this instruction with operands of actor type as
3316+
well as of type ``Builtin.Executor``. The former are expected to be
3317+
lowered by the SIL pipeline, so that IR generation only operands of type
3318+
``Builtin.Executor`` remain.
3319+
33153320
The operand is a guaranteed operand, i.e. not consumed.
33163321

33173322
dealloc_stack

include/swift/AST/ASTSynthesis.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ struct VariadicSynthesizerStorage<> {
135135
constexpr VariadicSynthesizerStorage() {}
136136

137137
template <class Fn>
138-
void visit(const Fn &fn) const {}
138+
void visit(Fn &&fn) const {}
139139
};
140140
template <class Head, class... Tail>
141141
struct VariadicSynthesizerStorage<Head, Tail...> {
@@ -145,7 +145,7 @@ struct VariadicSynthesizerStorage<Head, Tail...> {
145145
: head(head), tail(tail...) {}
146146

147147
template <class Fn>
148-
void visit(const Fn &fn) const {
148+
void visit(Fn &&fn) const {
149149
fn(head);
150150
tail.visit(fn);
151151
}

include/swift/AST/Builtins.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,10 @@ BUILTIN_MISC_OPERATION(ResumeThrowingContinuationReturning,
735735
BUILTIN_MISC_OPERATION(ResumeThrowingContinuationThrowing,
736736
"resumeThrowingContinuationThrowing", "", Special)
737737

738+
/// Build a Builtin.Executor value from the given serial executor reference.
739+
BUILTIN_MISC_OPERATION(BuildSerialExecutorRef,
740+
"buildSerialExecutorRef", "", Special)
741+
738742
// BUILTIN_MISC_OPERATION_WITH_SILGEN - Miscellaneous operations that are
739743
// specially emitted during SIL generation.
740744
//

include/swift/Basic/ScopedTracking.h

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//===--- ScopedTracking.h - Utilities for scoped tracking -------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines some miscellaneous utilities that are useful when
14+
// working with tracked values that can be saved and restored in a scoped
15+
// fashion.
16+
//
17+
//===----------------------------------------------------------------------===//
18+
19+
#ifndef SWIFT_BASIC_SCOPEDTRACKING_H
20+
#define SWIFT_BASIC_SCOPEDTRACKING_H
21+
22+
namespace llvm {
23+
template <class K, class V, class T, class A>
24+
class ScopedHashTable;
25+
template <class K, class V, class T, class A>
26+
class ScopedHashTableScope;
27+
}
28+
29+
namespace swift {
30+
31+
/// Must declare a nested type scope_type which can be initialized
32+
/// with an l-value reference to the tracker type.
33+
template <class Tracker>
34+
struct ScopedTrackingTraits;
35+
36+
template <class K, class V, class T, class A>
37+
struct ScopedTrackingTraits<llvm::ScopedHashTable<K,V,T,A>> {
38+
using scope_type = llvm::ScopedHashTableScope<K,V,T,A>;
39+
};
40+
41+
/// A class which stores scopes for multiple trackers. Can be
42+
/// initialized with a pack of l-value references to the trackers.
43+
template <class... Trackers>
44+
class TrackingScopes;
45+
46+
template <>
47+
class TrackingScopes<> {
48+
public:
49+
TrackingScopes() {}
50+
};
51+
52+
template <class Tracker, class... OtherTrackers>
53+
class TrackingScopes<Tracker, OtherTrackers...> {
54+
typename ScopedTrackingTraits<Tracker>::scope_type Scope;
55+
TrackingScopes<OtherTrackers...> OtherScopes;
56+
public:
57+
TrackingScopes(Tracker &tracker, OtherTrackers &...otherTrackers)
58+
: Scope(tracker), OtherScopes(otherTrackers...) {}
59+
};
60+
61+
} // end namespace swift
62+
63+
#endif

include/swift/SIL/Dominance.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#define SWIFT_SIL_DOMINANCE_H
2020

2121
#include "llvm/Support/GenericDomTree.h"
22+
#include "swift/Basic/ScopedTracking.h"
2223
#include "swift/SIL/CFG.h"
2324

2425
extern template class llvm::DominatorTreeBase<swift::SILBasicBlock, false>;
@@ -184,6 +185,62 @@ class PostDominanceInfo : public PostDominatorTreeBase {
184185
using super::properlyDominates;
185186
};
186187

188+
/// Invoke the given callback for all the reachable blocks
189+
/// in a function. It will be called in a depth-first,
190+
/// dominance-consistent order.
191+
///
192+
/// Furthermore, prior to running each block, a tracking scope will
193+
/// be entered for each of the trackers passed in, as if by:
194+
///
195+
/// typename ScopedTrackingTraits<Tracker>::scope_type scope(tracker);
196+
///
197+
/// This allows state to be saved and restored for each of the trackers,
198+
/// such that each tracker will only represent state that was computed
199+
/// in a dominating block.
200+
template <class... Trackers, class Fn>
201+
void runInDominanceOrderWithScopes(DominanceInfo *dominance, Fn &&fn,
202+
Trackers &...trackers) {
203+
using TrackingStackNode = TrackingScopes<Trackers...>;
204+
llvm::SmallVector<std::unique_ptr<TrackingStackNode>, 8> trackingStack;
205+
206+
// The stack of work to do. A null item means to pop the top
207+
// entry off the tracking stack.
208+
llvm::SmallVector<DominanceInfoNode *, 16> workStack;
209+
workStack.push_back(dominance->getRootNode());
210+
211+
while (!workStack.empty()) {
212+
auto node = workStack.pop_back_val();
213+
214+
// If the node is null, pop the top entry off the tracking stack.
215+
if (node == nullptr) {
216+
(void) trackingStack.pop_back_val();
217+
continue;
218+
}
219+
220+
auto bb = node->getBlock();
221+
222+
// If the node has no children, build the stack node in local
223+
// storage to avoid having to heap-allocate it.
224+
if (node->isLeaf()) {
225+
TrackingStackNode stackNode(trackers...);
226+
227+
fn(bb);
228+
229+
// Otherwise, we have to use the more general approach.
230+
} else {
231+
// Push a tracking stack node.
232+
trackingStack.emplace_back(new TrackingStackNode(trackers...));
233+
// Push a work command to pop the tracking stack node.
234+
workStack.push_back(nullptr);
235+
// Push all the child nodes as work items.
236+
workStack.append(node->begin(), node->end());
237+
238+
fn(bb);
239+
}
240+
}
241+
242+
assert(trackingStack.empty());
243+
}
187244

188245
} // end namespace swift
189246

include/swift/SIL/SILCloner.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3053,7 +3053,7 @@ ::visitHopToExecutorInst(HopToExecutorInst *Inst) {
30533053
recordClonedInstruction(Inst,
30543054
getBuilder().createHopToExecutor(
30553055
getOpLocation(Inst->getLoc()),
3056-
getOpValue(Inst->getActor())));
3056+
getOpValue(Inst->getTargetExecutor())));
30573057
}
30583058

30593059

include/swift/SIL/SILInstruction.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3474,11 +3474,12 @@ class HopToExecutorInst
34743474
{
34753475
friend SILBuilder;
34763476

3477-
HopToExecutorInst(SILDebugLocation DebugLoc, SILValue Actor, bool HasOwnership)
3478-
: UnaryInstructionBase(DebugLoc, Actor) { }
3477+
HopToExecutorInst(SILDebugLocation debugLoc, SILValue executor,
3478+
bool hasOwnership)
3479+
: UnaryInstructionBase(debugLoc, executor) { }
34793480

34803481
public:
3481-
SILValue getActor() const { return getOperand(); }
3482+
SILValue getTargetExecutor() const { return getOperand(); }
34823483
};
34833484

34843485
/// Instantiates a key path object.

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ PASS(HighLevelLICM, "high-level-licm",
210210
"Loop Invariant Code Motion in High-Level SIL")
211211
PASS(IVInfoPrinter, "iv-info-printer",
212212
"Print Induction Variable Information for Testing")
213+
PASS(LowerHopToActor, "lower-hop-to-actor",
214+
"Lower hop_to_executor instructions with actor operands")
213215
PASS(OptimizeHopToExecutor, "optimize-hop-to-executor",
214216
"Optimize hop_to_executor instructions for actor isolated code")
215217
PASS(InstCount, "inst-count",

lib/AST/Builtins.cpp

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,33 @@ namespace {
162162
/// for generics.
163163
enum UnrestrictedGenericParam { _unrestricted };
164164

165+
/// A synthesizer which generates a conformance requirement.
166+
template <class TypeS, class ProtocolS>
167+
struct ConformsToSynthesizer {
168+
TypeS Type;
169+
ProtocolS Protocol;
170+
};
171+
template <class TypeS, class ProtocolS>
172+
constexpr ConformsToSynthesizer<TypeS, ProtocolS>
173+
_conformsTo(TypeS type, ProtocolS protocol) {
174+
return {type, protocol};
175+
}
176+
177+
/// A synthesizer which generates a layout constraint requirement.
178+
template <class TypeS>
179+
struct LayoutConstraintSynthesizer {
180+
TypeS Type;
181+
LayoutConstraint Constraint;
182+
};
183+
template <class TypeS>
184+
LayoutConstraintSynthesizer<TypeS>
185+
_layout(TypeS type, LayoutConstraint constraint) {
186+
return {type, constraint};
187+
}
188+
static LayoutConstraint _classLayout() {
189+
return LayoutConstraint::getLayoutConstraint(LayoutConstraintKind::Class);
190+
}
191+
165192
/// A synthesizer which generates a generic parameter list.
166193
template <class... ParamS>
167194
struct GenericParamListSynthesizer {
@@ -179,6 +206,16 @@ struct CountGenericParameters {
179206
void operator()(UnrestrictedGenericParam _) const {
180207
Count++;
181208
}
209+
210+
template <class TypeS, class ProtoS>
211+
void operator()(const ConformsToSynthesizer<TypeS, ProtoS> &_) const {
212+
// not a parameter
213+
}
214+
215+
template <class TypeS>
216+
void operator()(const LayoutConstraintSynthesizer<TypeS> &_) const {
217+
// not a parameter
218+
}
182219
};
183220

184221
} // end anonymous namespace
@@ -240,15 +277,30 @@ struct CollectGenericParams {
240277
}
241278
}
242279

243-
void operator()(UnrestrictedGenericParam _) const {}
280+
void operator()(UnrestrictedGenericParam _) {}
281+
282+
template <class TypeS, class ProtoS>
283+
void operator()(const ConformsToSynthesizer<TypeS, ProtoS> &conf) {
284+
auto type = synthesizeType(SC, conf.Type);
285+
auto protocolType = synthesizeType(SC, conf.Protocol);
286+
AddedRequirements.push_back({RequirementKind::Conformance,
287+
type, protocolType});
288+
}
289+
290+
template <class TypeS>
291+
void operator()(const LayoutConstraintSynthesizer<TypeS> &req) {
292+
auto type = synthesizeType(SC, req.Type);
293+
AddedRequirements.push_back({RequirementKind::Layout,
294+
type, req.Constraint});
295+
}
244296
};
245297

246298
} // end anonymous namespace
247299

248300
template <class... ParamsS>
249301
static GenericSignature
250302
synthesizeGenericSignature(SynthesisContext &SC,
251-
GenericParamListSynthesizer<ParamsS...> list) {
303+
const GenericParamListSynthesizer<ParamsS...> &list) {
252304
assert(SC.GenericParams && "synthesizeGenericParamList not called first");
253305
CollectGenericParams collector(SC);
254306
list.Params.visit(collector);
@@ -1429,6 +1481,15 @@ static ValueDecl *getResumeContinuationThrowing(ASTContext &ctx,
14291481
_void);
14301482
}
14311483

1484+
static ValueDecl *getBuildSerialExecutorRef(ASTContext &ctx, Identifier id) {
1485+
// TODO: restrict the generic parameter to the SerialExecutor protocol
1486+
return getBuiltinFunction(ctx, id, _thin,
1487+
_generics(_unrestricted,
1488+
_layout(_typeparam(0), _classLayout())),
1489+
_parameters(_typeparam(0)),
1490+
_executor);
1491+
}
1492+
14321493
static ValueDecl *getAutoDiffCreateLinearMapContext(ASTContext &ctx,
14331494
Identifier id) {
14341495
return getBuiltinFunction(
@@ -2606,6 +2667,9 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
26062667
case BuiltinValueKind::ConvertTaskToJob:
26072668
return getConvertTaskToJob(Context, Id);
26082669

2670+
case BuiltinValueKind::BuildSerialExecutorRef:
2671+
return getBuildSerialExecutorRef(Context, Id);
2672+
26092673
case BuiltinValueKind::PoundAssert:
26102674
return getPoundAssert(Context, Id);
26112675

lib/IRGen/GenBuiltin.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,14 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
306306
return;
307307
}
308308

309+
if (Builtin.ID == BuiltinValueKind::BuildSerialExecutorRef) {
310+
auto executor = args.claimNext();
311+
executor = IGF.Builder.CreateBitCast(executor,
312+
IGF.IGM.SwiftExecutorPtrTy);
313+
out.add(executor);
314+
return;
315+
}
316+
309317
// If this is an LLVM IR intrinsic, lower it to an intrinsic call.
310318
const IntrinsicInfo &IInfo = IGF.getSILModule().getIntrinsicInfo(FnId);
311319
llvm::Intrinsic::ID IID = IInfo.ID;

lib/IRGen/IRGenSIL.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6134,6 +6134,7 @@ void IRGenSILFunction::visitCheckedCastAddrBranchInst(
61346134
}
61356135

61366136
void IRGenSILFunction::visitHopToExecutorInst(HopToExecutorInst *i) {
6137+
assert(i->getTargetExecutor()->getType().is<BuiltinExecutorType>());
61376138
llvm::Value *resumeFn = Builder.CreateIntrinsicCall(
61386139
llvm::Intrinsic::coro_async_resume, {});
61396140

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,8 @@ BUILTIN_OPERAND_OWNERSHIP(ForwardingBorrow, AutoDiffProjectTopLevelSubcontext)
814814
// ownership should be 'TrivialUse'.
815815
BUILTIN_OPERAND_OWNERSHIP(ForwardingConsume, ConvertTaskToJob)
816816

817+
BUILTIN_OPERAND_OWNERSHIP(BitwiseEscape, BuildSerialExecutorRef)
818+
817819
BUILTIN_OPERAND_OWNERSHIP(TrivialUse, AutoDiffCreateLinearMapContext)
818820

819821
#undef BUILTIN_OPERAND_OWNERSHIP

lib/SIL/IR/SILPrinter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2144,7 +2144,7 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
21442144
}
21452145

21462146
void visitHopToExecutorInst(HopToExecutorInst *HTEI) {
2147-
*this << getIDAndType(HTEI->getActor());
2147+
*this << getIDAndType(HTEI->getTargetExecutor());
21482148
}
21492149

21502150
void visitSwitchValueInst(SwitchValueInst *SII) {

lib/SIL/IR/ValueOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,7 @@ CONSTANT_OWNERSHIP_BUILTIN(None, GetCurrentExecutor)
552552
CONSTANT_OWNERSHIP_BUILTIN(None, ResumeNonThrowingContinuationReturning)
553553
CONSTANT_OWNERSHIP_BUILTIN(None, ResumeThrowingContinuationReturning)
554554
CONSTANT_OWNERSHIP_BUILTIN(None, ResumeThrowingContinuationThrowing)
555+
CONSTANT_OWNERSHIP_BUILTIN(None, BuildSerialExecutorRef)
555556

556557
#undef CONSTANT_OWNERSHIP_BUILTIN
557558

0 commit comments

Comments
 (0)