Skip to content

Commit 5cda4f4

Browse files
authored
Merge pull request #41382 from rjmccall/async-special-convention-orthogonality
[NFC] Split up the "special convention" for runtime async functions
2 parents d7d3fe3 + 58fe89f commit 5cda4f4

File tree

10 files changed

+328
-232
lines changed

10 files changed

+328
-232
lines changed

lib/IRGen/Callee.h

Lines changed: 132 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,7 @@ namespace irgen {
159159
}
160160
};
161161

162-
/// A function pointer value.
163-
class FunctionPointer {
162+
class FunctionPointerKind {
164163
public:
165164
enum class BasicKind {
166165
Function,
@@ -179,85 +178,124 @@ namespace irgen {
179178
DistributedExecuteTarget,
180179
};
181180

182-
class Kind {
183-
static constexpr unsigned SpecialOffset = 2;
184-
unsigned value;
185-
public:
186-
static constexpr BasicKind Function =
187-
BasicKind::Function;
188-
static constexpr BasicKind AsyncFunctionPointer =
189-
BasicKind::AsyncFunctionPointer;
190-
191-
Kind(BasicKind kind) : value(unsigned(kind)) {}
192-
Kind(SpecialKind kind) : value(unsigned(kind) + SpecialOffset) {}
193-
Kind(CanSILFunctionType fnType)
194-
: Kind(fnType->isAsync() ? BasicKind::AsyncFunctionPointer
195-
: BasicKind::Function) {}
196-
197-
BasicKind getBasicKind() const {
198-
return value < SpecialOffset ? BasicKind(value) : BasicKind::Function;
199-
}
200-
bool isAsyncFunctionPointer() const {
201-
return value == unsigned(BasicKind::AsyncFunctionPointer);
202-
}
203-
204-
bool isSpecial() const {
205-
return value >= SpecialOffset;
181+
private:
182+
static constexpr unsigned SpecialOffset = 2;
183+
unsigned value;
184+
public:
185+
static constexpr BasicKind Function =
186+
BasicKind::Function;
187+
static constexpr BasicKind AsyncFunctionPointer =
188+
BasicKind::AsyncFunctionPointer;
189+
190+
FunctionPointerKind(BasicKind kind)
191+
: value(unsigned(kind)) {}
192+
FunctionPointerKind(SpecialKind kind)
193+
: value(unsigned(kind) + SpecialOffset) {}
194+
FunctionPointerKind(CanSILFunctionType fnType)
195+
: FunctionPointerKind(fnType->isAsync()
196+
? BasicKind::AsyncFunctionPointer
197+
: BasicKind::Function) {}
198+
199+
static FunctionPointerKind defaultSync() {
200+
return BasicKind::Function;
201+
}
202+
static FunctionPointerKind defaultAsync() {
203+
return BasicKind::AsyncFunctionPointer;
204+
}
205+
206+
BasicKind getBasicKind() const {
207+
return value < SpecialOffset ? BasicKind(value) : BasicKind::Function;
208+
}
209+
bool isAsyncFunctionPointer() const {
210+
return value == unsigned(BasicKind::AsyncFunctionPointer);
211+
}
212+
213+
bool isSpecial() const {
214+
return value >= SpecialOffset;
215+
}
216+
SpecialKind getSpecialKind() const {
217+
assert(isSpecial());
218+
return SpecialKind(value - SpecialOffset);
219+
}
220+
221+
222+
/// Given that this is an async function, does it have a
223+
/// statically-specified size for its async context?
224+
///
225+
/// Returning a non-None value is necessary for special functions
226+
/// defined in the runtime. Without this, we'll attempt to load
227+
/// the context size from an async FP symbol which the runtime
228+
/// doesn't actually emit.
229+
Optional<Size> getStaticAsyncContextSize(IRGenModule &IGM) const;
230+
231+
/// Given that this is an async function, should we pass the
232+
/// continuation function pointer and context directly to it
233+
/// rather than building a frame?
234+
///
235+
/// This is a micro-optimization that is reasonable for functions
236+
/// that are expected to return immediately in a common fast path.
237+
/// Other functions should not do this.
238+
bool shouldPassContinuationDirectly() const {
239+
if (!isSpecial()) return false;
240+
241+
switch (getSpecialKind()) {
242+
case SpecialKind::TaskFutureWaitThrowing:
243+
case SpecialKind::TaskFutureWait:
244+
case SpecialKind::AsyncLetWait:
245+
case SpecialKind::AsyncLetWaitThrowing:
246+
case SpecialKind::AsyncLetGet:
247+
case SpecialKind::AsyncLetGetThrowing:
248+
case SpecialKind::AsyncLetFinish:
249+
case SpecialKind::TaskGroupWaitNext:
250+
case SpecialKind::DistributedExecuteTarget:
251+
return true;
206252
}
207-
SpecialKind getSpecialKind() const {
208-
assert(isSpecial());
209-
return SpecialKind(value - SpecialOffset);
210-
}
211-
212-
bool isSpecialAsyncLet() const {
213-
if (!isSpecial()) return false;
214-
switch (getSpecialKind()) {
215-
case SpecialKind::AsyncLetGet:
216-
case SpecialKind::AsyncLetGetThrowing:
217-
case SpecialKind::AsyncLetFinish:
218-
return true;
219-
220-
case SpecialKind::TaskFutureWaitThrowing:
221-
case SpecialKind::TaskFutureWait:
222-
case SpecialKind::AsyncLetWait:
223-
case SpecialKind::AsyncLetWaitThrowing:
224-
case SpecialKind::TaskGroupWaitNext:
225-
case SpecialKind::DistributedExecuteTarget:
226-
return false;
227-
}
228-
229-
return false;
253+
llvm_unreachable("covered switch");
254+
}
255+
256+
/// Should we suppress passing arguments associated with the generic
257+
/// signature from the given function?
258+
///
259+
/// This is a micro-optimization for certain runtime functions that
260+
/// are known to not need the generic arguments, probably because
261+
/// they've already been stored elsewhere.
262+
///
263+
/// This may only work for async function types right now. If so,
264+
/// that's a totally unnecessary restriction which should be easy
265+
/// to lift, if you have a sync runtime function that would benefit
266+
/// from this.
267+
bool shouldSuppressPolymorphicArguments() const {
268+
if (!isSpecial()) return false;
269+
270+
switch (getSpecialKind()) {
271+
case SpecialKind::TaskFutureWaitThrowing:
272+
case SpecialKind::TaskFutureWait:
273+
case SpecialKind::AsyncLetWait:
274+
case SpecialKind::AsyncLetWaitThrowing:
275+
case SpecialKind::AsyncLetGet:
276+
case SpecialKind::AsyncLetGetThrowing:
277+
case SpecialKind::AsyncLetFinish:
278+
case SpecialKind::TaskGroupWaitNext:
279+
case SpecialKind::DistributedExecuteTarget:
280+
return true;
230281
}
282+
llvm_unreachable("covered switch");
283+
}
231284

232-
/// Should we suppress the generic signature from the given function?
233-
///
234-
/// This is a micro-optimization we apply to certain special functions
235-
/// that we know don't need generics.
236-
bool useSpecialConvention() const {
237-
if (!isSpecial()) return false;
238-
239-
switch (getSpecialKind()) {
240-
case SpecialKind::TaskFutureWaitThrowing:
241-
case SpecialKind::TaskFutureWait:
242-
case SpecialKind::AsyncLetWait:
243-
case SpecialKind::AsyncLetWaitThrowing:
244-
case SpecialKind::AsyncLetGet:
245-
case SpecialKind::AsyncLetGetThrowing:
246-
case SpecialKind::AsyncLetFinish:
247-
case SpecialKind::TaskGroupWaitNext:
248-
case SpecialKind::DistributedExecuteTarget:
249-
return true;
250-
}
251-
llvm_unreachable("covered switch");
252-
}
285+
friend bool operator==(FunctionPointerKind lhs, FunctionPointerKind rhs) {
286+
return lhs.value == rhs.value;
287+
}
288+
friend bool operator!=(FunctionPointerKind lhs, FunctionPointerKind rhs) {
289+
return !(lhs == rhs);
290+
}
291+
};
253292

254-
friend bool operator==(Kind lhs, Kind rhs) {
255-
return lhs.value == rhs.value;
256-
}
257-
friend bool operator!=(Kind lhs, Kind rhs) {
258-
return !(lhs == rhs);
259-
}
260-
};
293+
/// A function pointer value.
294+
class FunctionPointer {
295+
public:
296+
using Kind = FunctionPointerKind;
297+
using BasicKind = Kind::BasicKind;
298+
using SpecialKind = Kind::SpecialKind;
261299

262300
private:
263301
Kind kind;
@@ -388,11 +426,15 @@ namespace irgen {
388426
/// Form a FunctionPointer whose Kind is ::Function.
389427
FunctionPointer getAsFunction(IRGenFunction &IGF) const;
390428

391-
bool useStaticContextSize() const {
392-
return !kind.isAsyncFunctionPointer();
429+
Optional<Size> getStaticAsyncContextSize(IRGenModule &IGM) const {
430+
return kind.getStaticAsyncContextSize(IGM);
431+
}
432+
bool shouldPassContinuationDirectly() const {
433+
return kind.shouldPassContinuationDirectly();
434+
}
435+
bool shouldSuppressPolymorphicArguments() const {
436+
return kind.shouldSuppressPolymorphicArguments();
393437
}
394-
395-
bool useSpecialConvention() const { return kind.useSpecialConvention(); }
396438
};
397439

398440
class Callee {
@@ -456,7 +498,15 @@ namespace irgen {
456498
return Fn.getSignature();
457499
}
458500

459-
bool useSpecialConvention() const { return Fn.useSpecialConvention(); }
501+
Optional<Size> getStaticAsyncContextSize(IRGenModule &IGM) const {
502+
return Fn.getStaticAsyncContextSize(IGM);
503+
}
504+
bool shouldPassContinuationDirectly() const {
505+
return Fn.shouldPassContinuationDirectly();
506+
}
507+
bool shouldSuppressPolymorphicArguments() const {
508+
return Fn.shouldSuppressPolymorphicArguments();
509+
}
460510

461511
/// If this callee has a value for the Swift context slot, return
462512
/// it; otherwise return non-null.

0 commit comments

Comments
 (0)