@@ -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