Skip to content

Commit ec5215b

Browse files
committed
Remove the implicit nil inhabitant of Builtin.Executor,
and traffic in Optional<Builtin.Executor> in various places.
1 parent 186c530 commit ec5215b

File tree

16 files changed

+151
-82
lines changed

16 files changed

+151
-82
lines changed

include/swift/AST/Builtins.def

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -757,11 +757,11 @@ BUILTIN_MISC_OPERATION(DestroyTaskGroup,
757757
BUILTIN_MISC_OPERATION(Id, Name, Attrs, Overload)
758758
#endif
759759

760-
// getCurrentExecutor: () async -> Builtin.Executor
760+
// getCurrentExecutor: () async -> Builtin.Executor?
761761
//
762762
// Retrieve the ExecutorRef on which the current asynchronous
763-
// function is executing.
764-
// Does not retain an actor executor.
763+
// function is executing, or nil if the function isn't running
764+
// anywhere in particular.
765765
BUILTIN_MISC_OPERATION_WITH_SILGEN(GetCurrentExecutor, "getCurrentExecutor", "", Special)
766766

767767
// getCurrentAsyncTask: () -> Builtin.NativeObject

lib/AST/Builtins.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1407,7 +1407,7 @@ static ValueDecl *getGetCurrentAsyncTask(ASTContext &ctx, Identifier id) {
14071407
static ValueDecl *getGetCurrentExecutor(ASTContext &ctx, Identifier id) {
14081408
return getBuiltinFunction(ctx, id, _async(_thin),
14091409
_parameters(),
1410-
_executor);
1410+
_optional(_executor));
14111411
}
14121412

14131413
static ValueDecl *getCancelAsyncTask(ASTContext &ctx, Identifier id) {

lib/IRGen/GenBuiltin.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,6 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
223223
// emitGetCurrentExecutor has no arguments.
224224
if (Builtin.ID == BuiltinValueKind::GetCurrentExecutor) {
225225
emitGetCurrentExecutor(IGF, out);
226-
227226
return;
228227
}
229228

lib/IRGen/GenConcurrency.cpp

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,12 @@ class ExecutorTypeInfo :
6565
return ".impl";
6666
}
6767

68-
// The identity pointer is a heap object reference, but it's
69-
// nullable because of the generic executor.
68+
// The identity pointer is a heap object reference.
7069
bool mayHaveExtraInhabitants(IRGenModule &IGM) const override {
7170
return true;
7271
}
73-
7472
PointerInfo getPointerInfo(IRGenModule &IGM) const {
75-
return PointerInfo::forHeapObject(IGM).withNullable(IsNullable);
73+
return PointerInfo::forHeapObject(IGM);
7674
}
7775
unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override {
7876
return getPointerInfo(IGM).getExtraInhabitantCount(IGM);
@@ -89,18 +87,17 @@ class ExecutorTypeInfo :
8987
src = projectFirstElement(IGF, src);
9088
return getPointerInfo(IGF.IGM).getExtraInhabitantIndex(IGF, src);
9189
}
92-
APInt getFixedExtraInhabitantMask(IRGenModule &IGM) const override {
93-
auto pointerSize = IGM.getPointerSize();
94-
auto mask = BitPatternBuilder(IGM.Triple.isLittleEndian());
95-
mask.appendSetBits(pointerSize.getValueInBits());
96-
mask.appendClearBits(pointerSize.getValueInBits());
97-
return mask.build().getValue();
98-
}
9990
void storeExtraInhabitant(IRGenFunction &IGF, llvm::Value *index,
10091
Address dest, SILType T,
10192
bool isOutlined) const override {
102-
dest = projectFirstElement(IGF, dest);
103-
getPointerInfo(IGF.IGM).storeExtraInhabitant(IGF, index, dest);
93+
// Store the extra-inhabitant value in the first (identity) word.
94+
auto first = projectFirstElement(IGF, dest);
95+
getPointerInfo(IGF.IGM).storeExtraInhabitant(IGF, index, first);
96+
97+
// Zero the second word.
98+
auto second = projectSecondElement(IGF, dest);
99+
IGF.Builder.CreateStore(llvm::ConstantInt::get(IGF.IGM.ExecutorSecondTy, 0),
100+
second);
104101
}
105102
};
106103

@@ -139,9 +136,9 @@ void irgen::emitBuildDefaultActorExecutorRef(IRGenFunction &IGF,
139136
unsigned flags = unsigned(ExecutorRefFlags::DefaultActor);
140137

141138
llvm::Value *identity =
142-
IGF.Builder.CreateBitCast(actor, IGF.IGM.ExecutorFirstTy);
139+
IGF.Builder.CreatePtrToInt(actor, IGF.IGM.ExecutorFirstTy);
143140
llvm::Value *impl =
144-
IGF.IGM.getSize(Size(flags));
141+
llvm::ConstantInt::get(IGF.IGM.ExecutorSecondTy, flags);
145142

146143
out.add(identity);
147144
out.add(impl);
@@ -153,10 +150,10 @@ void irgen::emitBuildOrdinarySerialExecutorRef(IRGenFunction &IGF,
153150
ProtocolConformanceRef executorConf,
154151
Explosion &out) {
155152
llvm::Value *identity =
156-
IGF.Builder.CreateBitCast(executor, IGF.IGM.ExecutorFirstTy);
153+
IGF.Builder.CreatePtrToInt(executor, IGF.IGM.ExecutorFirstTy);
157154
llvm::Value *impl =
158155
emitWitnessTableRef(IGF, executorType, executorConf);
159-
impl = IGF.Builder.CreatePtrToInt(impl, IGF.IGM.SizeTy);
156+
impl = IGF.Builder.CreatePtrToInt(impl, IGF.IGM.ExecutorSecondTy);
160157

161158
out.add(identity);
162159
out.add(impl);

lib/IRGen/IRGenModule.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,7 @@ IRGenModule::IRGenModule(IRGenerator &irgen,
620620
SwiftTaskPtrTy = SwiftTaskTy->getPointerTo(DefaultAS);
621621
SwiftAsyncLetPtrTy = Int8PtrTy; // we pass it opaquely (AsyncLet*)
622622
SwiftTaskGroupPtrTy = Int8PtrTy; // we pass it opaquely (TaskGroup*)
623-
ExecutorFirstTy = RefCountedPtrTy;
623+
ExecutorFirstTy = SizeTy;
624624
ExecutorSecondTy = SizeTy;
625625
SwiftExecutorTy = createStructType(*this, "swift.executor", {
626626
ExecutorFirstTy, // identity

lib/IRGen/IRGenModule.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ class IRGenModule {
735735
llvm::PointerType *SwiftAsyncLetPtrTy;
736736
llvm::PointerType *SwiftTaskGroupPtrTy;
737737
llvm::PointerType *SwiftJobPtrTy;
738-
llvm::PointerType *ExecutorFirstTy;
738+
llvm::IntegerType *ExecutorFirstTy;
739739
llvm::IntegerType *ExecutorSecondTy;
740740
llvm::FunctionType *TaskContinuationFunctionTy;
741741
llvm::PointerType *TaskContinuationFunctionPtrTy;

lib/IRGen/IRGenSIL.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6156,12 +6156,8 @@ void IRGenSILFunction::visitCheckedCastAddrBranchInst(
61566156
}
61576157

61586158
void IRGenSILFunction::visitHopToExecutorInst(HopToExecutorInst *i) {
6159-
if (!i->getFunction()->isAsync()) {
6160-
// This should never occur.
6161-
assert(false && "The hop_to_executor should have been eliminated");
6162-
return;
6163-
}
6164-
assert(i->getTargetExecutor()->getType().is<BuiltinExecutorType>());
6159+
assert(i->getTargetExecutor()->getType().getOptionalObjectType()
6160+
.is<BuiltinExecutorType>());
61656161
llvm::Value *resumeFn = Builder.CreateIntrinsicCall(
61666162
llvm::Intrinsic::coro_async_resume, {});
61676163

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,15 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
832832
valueDescription + " cannot apply to a function type");
833833
}
834834

835+
/// Require the operand to be `$Optional<Builtin.Executor>`.
836+
void requireOptionalExecutorType(SILValue value, const Twine &what) {
837+
auto type = value->getType();
838+
require(type.isObject(), what + " must be an object type");
839+
auto objectType = type.getASTType().getOptionalObjectType();
840+
require(objectType && objectType == M->getASTContext().TheExecutorType,
841+
what + " must be Optional<Builtin.Executor>");
842+
}
843+
835844
/// Assert that two types are equal.
836845
void requireSameType(Type type1, Type type2, const Twine &complaint) {
837846
_require(type1->isEqual(type2), complaint,
@@ -1822,6 +1831,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
18221831
}
18231832

18241833
auto builtinKind = BI->getBuiltinKind();
1834+
auto arguments = BI->getArguments();
18251835

18261836
// Check that 'getCurrentAsyncTask' only occurs within an async function.
18271837
if (builtinKind == BuiltinValueKind::GetCurrentAsyncTask) {
@@ -1832,7 +1842,6 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
18321842

18331843
if (builtinKind == BuiltinValueKind::InitializeDefaultActor ||
18341844
builtinKind == BuiltinValueKind::DestroyDefaultActor) {
1835-
auto arguments = BI->getArguments();
18361845
require(arguments.size() == 1,
18371846
"default-actor builtin can only operate on a single object");
18381847
auto argType = arguments[0]->getType().getASTType();
@@ -1844,23 +1853,32 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
18441853
return;
18451854
}
18461855

1856+
// Check that 'getCurrentAsyncTask' only occurs within an async function.
1857+
if (builtinKind == BuiltinValueKind::GetCurrentExecutor) {
1858+
require(F.isAsync(),
1859+
"getCurrentExecutor can only be used in an async function");
1860+
require(arguments.empty(), "getCurrentExecutor takes no arguments");
1861+
requireOptionalExecutorType(BI, "result of getCurrentExecutor");
1862+
return;
1863+
}
1864+
18471865
if (builtinKind == BuiltinValueKind::BuildOrdinarySerialExecutorRef ||
18481866
builtinKind == BuiltinValueKind::BuildDefaultActorExecutorRef) {
1849-
requireObjectType(BuiltinExecutorType, BI,
1850-
"result of building a serial executor");
1851-
auto arguments = BI->getArguments();
18521867
require(arguments.size() == 1,
18531868
"builtin expects one argument");
18541869
require(arguments[0]->getType().isObject(),
18551870
"operand of builtin should have object type");
1871+
requireObjectType(BuiltinExecutorType, BI,
1872+
"result of build*ExecutorRef");
1873+
return;
18561874
}
18571875

18581876
if (builtinKind == BuiltinValueKind::BuildMainActorExecutorRef) {
1859-
requireObjectType(BuiltinExecutorType, BI,
1860-
"result of buildSerialExecutorRef");
1861-
auto arguments = BI->getArguments();
18621877
require(arguments.size() == 0,
18631878
"buildMainActorExecutorRef expects no arguments");
1879+
requireObjectType(BuiltinExecutorType, BI,
1880+
"result of build*ExecutorRef");
1881+
return;
18641882
}
18651883
}
18661884

@@ -4792,9 +4810,8 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
47924810
void checkHopToExecutorInst(HopToExecutorInst *HI) {
47934811
auto executor = HI->getTargetExecutor();
47944812
if (HI->getModule().getStage() == SILStage::Lowered) {
4795-
requireObjectType(BuiltinExecutorType, executor->getType(),
4796-
"hop_to_executor instruction must take a "
4797-
"Builtin.Executor in lowered SIL");
4813+
requireOptionalExecutorType(executor,
4814+
"hop_to_executor operand in lowered SIL");
47984815
}
47994816
}
48004817

lib/SILGen/SILGenProlog.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -704,7 +704,7 @@ SILValue SILGenFunction::emitGetCurrentExecutor(SILLocation loc) {
704704
return B.createBuiltin(
705705
loc,
706706
ctx.getIdentifier(getBuiltinName(BuiltinValueKind::GetCurrentExecutor)),
707-
getLoweredType(ctx.TheExecutorType),
707+
getLoweredType(OptionalType::get(ctx.TheExecutorType)),
708708
SubstitutionMap(), { });
709709
}
710710

lib/SILOptimizer/Mandatory/LowerHopToActor.cpp

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class LowerHopToActor {
5757
bool processHop(HopToExecutorInst *hop);
5858
bool processExtract(ExtractExecutorInst *extract);
5959

60-
SILValue emitGetExecutor(SILLocation loc, SILValue actor);
60+
SILValue emitGetExecutor(SILLocation loc, SILValue actor, bool makeOptional);
6161

6262
public:
6363
LowerHopToActor(SILFunction *f, DominanceInfo *dominance)
@@ -85,19 +85,25 @@ bool LowerHopToActor::run() {
8585
return changed;
8686
}
8787

88+
static bool isOptionalBuiltinExecutor(SILType type) {
89+
if (auto objectType = type.getOptionalObjectType())
90+
return objectType.is<BuiltinExecutorType>();
91+
return false;
92+
}
93+
8894
/// Search for hop_to_executor instructions with actor-typed operands.
8995
bool LowerHopToActor::processHop(HopToExecutorInst *hop) {
9096
auto actor = hop->getTargetExecutor();
9197

92-
// Ignore hops that are already to Builtin.Executor.
93-
if (actor->getType().is<BuiltinExecutorType>())
98+
// Ignore hops that are already to Optional<Builtin.Executor>.
99+
if (isOptionalBuiltinExecutor(actor->getType()))
94100
return false;
95101

96102
B.setInsertionPoint(hop);
97103

98104
// Get the dominating executor value for this actor, if available,
99105
// or else emit code to derive it.
100-
SILValue executor = emitGetExecutor(hop->getLoc(), actor);
106+
SILValue executor = emitGetExecutor(hop->getLoc(), actor, /*optional*/true);
101107

102108
B.createHopToExecutor(hop->getLoc(), executor);
103109

@@ -109,12 +115,12 @@ bool LowerHopToActor::processHop(HopToExecutorInst *hop) {
109115
bool LowerHopToActor::processExtract(ExtractExecutorInst *extract) {
110116
// Dig out the executor.
111117
auto executor = extract->getExpectedExecutor();
112-
if (!executor->getType().is<BuiltinExecutorType>()) {
118+
if (!isOptionalBuiltinExecutor(executor->getType())) {
113119
B.setInsertionPoint(extract);
114-
115-
executor = emitGetExecutor(extract->getLoc(), executor);
120+
executor = emitGetExecutor(extract->getLoc(), executor, /*optional*/false);
116121
}
117122

123+
// Unconditionally replace the extract with the executor.
118124
extract->replaceAllUsesWith(executor);
119125
extract->eraseFromParent();
120126
return true;
@@ -138,12 +144,17 @@ static AccessorDecl *getUnownedExecutorGetter(ASTContext &ctx,
138144
return nullptr;
139145
}
140146

141-
SILValue LowerHopToActor::emitGetExecutor(SILLocation loc, SILValue actor) {
147+
SILValue LowerHopToActor::emitGetExecutor(SILLocation loc, SILValue actor,
148+
bool makeOptional) {
142149
// Get the dominating executor value for this actor, if available,
143150
// or else emit code to derive it.
144151
SILValue executor = ExecutorForActor.lookup(actor);
145-
if (executor)
152+
if (executor) {
153+
if (makeOptional)
154+
executor = B.createOptionalSome(loc, executor,
155+
SILType::getOptionalType(executor->getType()));
146156
return executor;
157+
}
147158

148159
// This is okay because actor types have to be classes and so never
149160
// have multiple abstraction patterns.
@@ -197,9 +208,14 @@ SILValue LowerHopToActor::emitGetExecutor(SILLocation loc, SILValue actor) {
197208
// force the actor to stay alive.
198209
executor = B.createMarkDependence(loc, unmarkedExecutor, actor);
199210

200-
// Cache the result for later.
211+
// Cache the non-optional result for later.
201212
ExecutorForActor.insert(actor, executor);
202213

214+
// Inject the result into an optional if requested.
215+
if (makeOptional)
216+
executor = B.createOptionalSome(loc, executor,
217+
SILType::getOptionalType(executor->getType()));
218+
203219
return executor;
204220
}
205221

0 commit comments

Comments
 (0)