Slide 1

Slide 1 text

2025/01/17 w a iw a i swiftc shiz Swift compiler 101 How async function works &

Slide 2

Slide 2 text

Self-introduction •shiz(sizu) X: @stzn3 GitHub: @stzn •iOS engineer in Fukuoka, Japan .ZCPPLT +BQBOFTFUSBOTMBUJPOPG4XJGUHVJEFT

Slide 3

Slide 3 text

Contents •Swift compiler 101 •Two features of Swift async function (overview) •Two features of Swift async function (detail)

Slide 4

Slide 4 text

Used Swift version •swift-DEVELOPMENT-SNAPSHOT-2024-12-22- a(Swift6.2)

Slide 5

Slide 5 text

Contents •Swift compiler 101 •Two features of Swift async function (overview) •Two features of Swift async function (detail)

Slide 6

Slide 6 text

What complier does?

Slide 7

Slide 7 text

Compiler •A program that translate source code from a high-level programming language to a low- level programming language

Slide 8

Slide 8 text

Mainly compiler does •Parsing • Divide the source code into the smallest meaningful units "tokens." •Lexical analysis • Check syntax rules based on tokens and analyze the structure of the program. Generate AST •Semantic analysis • Check the type and scope of the variable and check if the program is semantically correct •IR generation • Generate code to make the compiler optimized •Optimization • Transform IR into functionally equivalent but faster (or smaller) forms •Code generation • Translate transformed IR into machine language ⚠Depends on the compiler and so on….

Slide 9

Slide 9 text

The main pipelines of compiler • Parsing • Divide the source code into the smallest meaningful units "tokens." • Lexical analysis • Check syntax rules based on tokens and analyze the structure of the program. Generate AST • Semantic analysis • Check the type and scope of the variable and check if the program is semantically correct •IR generation • Generate code to make the compiler optimized • Optimization • Transform IR into functionally equivalent but faster (or smaller) forms • Code generation • Translate transformed IR into machine language ⚠Depends on the compiler and so on….

Slide 10

Slide 10 text

IR •Intermediate Representation •Intermediate code generated in the process of converting programming language code to machine language

Slide 11

Slide 11 text

IR • Intermediate Representation • Intermediate code generated in the process of converting programming language code to machine language •Why needed? • The structure is simple and the code is easy to optimize • Generate code for various targets (e.g. Apple Silicon's MacOS) • Development e ff i ciency by separating compiler processes

Slide 12

Slide 12 text

What Swi ft compiler does?

Slide 13

Slide 13 text

The main pipelines of Swift compiler 1. Parse(Parsing, Lexical analysis) 2. Sema(Semantic Analysis) 3. SILGen(IR generation) 4.SILOptimizer(Optimization) 5. IRGen(IR generation) 6.LLVM(Optimization, Code generation) https://qiita.com/rintaro/items/3ad640e3938207218c20 ❶ ❷ ❸ ❹ ❺ ❻

Slide 14

Slide 14 text

More info about Swift compiler(Japanese) https://qiita.com/rintaro/items/3ad640e3938207218c20

Slide 15

Slide 15 text

More info about Swift compiler https://www.swift.org/documentation/swift-compiler/

Slide 16

Slide 16 text

Some supplements

Slide 17

Slide 17 text

The main pipelines of Swift compiler 1. Parse(Parsing, Lexical analysis) 2. Sema(Semantic Analysis) 3.SILGen(IR generation) 4. SILOptimizer(Optimization) 5.IRGen(IR generation) 6. LLVM(Optimization, Code generation) https://qiita.com/rintaro/items/3ad640e3938207218c20 ⚠More IRs are generated (e.g. AST)

Slide 18

Slide 18 text

SILGen •Generate SIL •SIL: Swift Intermediate Language •High-level, Swift-speci fi c intermediate language suitable for further analysis and optimization of Swift code TIPS: Documentation about SIL was updated recently

Slide 19

Slide 19 text

IRGen •Generate LLVM IR •IR for LLVM generated to facilitate optimization in the process of generating the fi nal machine language

Slide 20

Slide 20 text

LLVMʁ

Slide 21

Slide 21 text

The main pipelines of Swift compiler 1. Parse(Parsing, Lexical analysis) 2. Sema(Semantic Analysis) 3. SILGen(IR generation) 4. SILOptimizer(Optimization) 5. IRGen(IR generation) 6.LLVM(Optimization, Code generation) https://qiita.com/rintaro/items/3ad640e3938207218c20

Slide 22

Slide 22 text

LLVM •Not Swift •Compiler backend •Generate machine languages for various targets from LLVM IR •Optimization according to the target •Used universally(C++ɺRustɺ ActionScript…)

Slide 23

Slide 23 text

More info about LLVM https://github.com/learn-llvm/awesome-llvm

Slide 24

Slide 24 text

SIL & LLVM IR Swift SIL LLVM IR

Slide 25

Slide 25 text

SIL & LLVM IR Swift SIL LLVM IR string integer Array i64 i32 ptr

Slide 26

Slide 26 text

Contents •Swift compiler 101 •Two features of Swift async function (overview) •Two features of Swift async function (detail)

Slide 27

Slide 27 text

Contents •Swift compiler 101 •Two features of Swift async function (overview) •Two features of Swift async function (detail)

Slide 28

Slide 28 text

Explore Swift performance Two features of Swift async function

Slide 29

Slide 29 text

Two features of Swift async function •Keep local state on a special stack •Split functions into partial functions that run between suspensions

Slide 30

Slide 30 text

Two features of Swift async function •Keep local state on a special stack •Split functions into partial functions that run between suspensions

Slide 31

Slide 31 text

Stack memory Sync function Call stack(※) on stack memory Call stack func1 func2 func3 Thread ※ A data structure that stores info about active functions

Slide 32

Slide 32 text

Stack(data structure) Stack Element LIFO(Last-In, First-Out) Element Stack Element Element Last-In First-Out push pop

Slide 33

Slide 33 text

Stack(data structure) Stack Element LIFO(Last-In, First-Out) Element Stack Element Element Last-In First-Out ⚠Stack can also be used in heap memory

Slide 34

Slide 34 text

Call stack func1 func2 func3 Thread Stack frame Parameters Local variables Return address …and so on

Slide 35

Slide 35 text

Thread Sync function Start Finish Call stack func1 func2 foo Call stack func1 func2 Thread foo Pop Push disappear

Slide 36

Slide 36 text

Let's think about it with the async function

Slide 37

Slide 37 text

Start is the same Start Call stack func1 func2 Thread async

Slide 38

Slide 38 text

Call stack func1 func2 Thread async Need to pop the frame on suspends Await Call stack func1 func2 Thread async async Run other operations Start disappear

Slide 39

Slide 39 text

Call stack func1 func2 Thread async Need the frame again Call stack func1 func2 Thread async Call stack func1 func2 func3 Thread Resume async Hmm…? Await ⚠Might be a di ff erent thread Start

Slide 40

Slide 40 text

So

Slide 41

Slide 41 text

Keep local state on a special stack

Slide 42

Slide 42 text

async Heap memory Stack memory Store to another stack Thread func1 func2 async Call stack Stack Stack on heap memory

Slide 43

Slide 43 text

Only info across suspend points async Stack Call stack async a b Suspend point

Slide 44

Slide 44 text

async Stack Call stack async Async frame Information without any suspend points in- between Information across suspend points

Slide 45

Slide 45 text

Stack memory Return to call stack on resume Stack Thread ⚠might be a di ff erent thread func4 func5 async Call stack Heap memory

Slide 46

Slide 46 text

Task Task manages async process

Slide 47

Slide 47 text

Task TaskAllocator manages memory TaskAllocator

Slide 48

Slide 48 text

Heap memory Hold memory areas Task TaskAllocator Memory 💡It is done when creating a Task Task TaskAllocator Memory

Slide 49

Slide 49 text

Heap memory Task TaskAllocator Memory Task TaskAllocator Memory async Allocate as needed

Slide 50

Slide 50 text

Heap memory Task TaskAllocator Memory async Memory Allocate a new memory if needed

Slide 51

Slide 51 text

Heap memory Task More detail TaskAllocator Memory async StackAllocator(TaskAllocator is a kind of typealias) Slab Continuous memory Stack discipline + Bump pointer allocation Mechanism for e ff i cient memory allocation

Slide 52

Slide 52 text

Two features of Swift async function •Keep local state on a special stack •Split functions into partial functions that run between suspensions

Slide 53

Slide 53 text

Two features of Swift async function •Keep local state on a special stack •Split functions into partial functions that run between suspensions

Slide 54

Slide 54 text

Split functions?

Slide 55

Slide 55 text

Split function between await Partial function hoge1 hoge2 Partial function await = potential suspend point

Slide 56

Slide 56 text

Appendix: ramp & resume function •ramp function: By the fi rst await •resume function: After await

Slide 57

Slide 57 text

hoge1 hoge2 resume function created await by await hoge3

Slide 58

Slide 58 text

hoge1 Call the process a ft er await on resume await hoge2 https://github.com/swiftlang/swift/blob/main/docs/SIL/Types.md#async-functions async frame Process on resume

Slide 59

Slide 59 text

hoge1 await hoge2 https://github.com/swiftlang/swift/blob/main/docs/SIL/Types.md#async-functions async frame Process on resume 💡Information where to run on the Call stack Call the process a ft er await on resume

Slide 60

Slide 60 text

Two more features •Tail call •AsyncContext

Slide 61

Slide 61 text

Two more features •Tail call •AsyncContext

Slide 62

Slide 62 text

hoge1 await await hoge2 async frame Process on resume Function Pointer Pass address directly

Slide 63

Slide 63 text

hoge1 Call when complete the process await await hoge2 async frame Process on resume Function Pointer call

Slide 64

Slide 64 text

hoge1 await await hoge2 async frame Process on resume Function Pointer call Tail call 💡No need to use stack(Memory optimization)

Slide 65

Slide 65 text

Two more features •Tail call •AsyncContext

Slide 66

Slide 66 text

Task Entire task info async frame async frame async frame One async function info AsyncContext

Slide 67

Slide 67 text

hoge1 await hoge2 async frame Process on resume AsyncContext pointer Get info from AsyncContext via pointer AsyncContext pointer AsyncContext pointer

Slide 68

Slide 68 text

Where split function?

Slide 69

Slide 69 text

LLVM! 1. Parse(Parsing, Lexical analysis) 2. Sema(Semantic Analysis) 3. SILGen(IR generation) 4. SILOptimizer(Optimization) 5. IRGen(IR generation) 6.LLVM(Optimization, Code generation) https://qiita.com/rintaro/items/3ad640e3938207218c20

Slide 70

Slide 70 text

Async lowering https://llvm.org/docs/Coroutines.html#async-lowering

Slide 71

Slide 71 text

Originally implemented for Swi f

Slide 72

Slide 72 text

Why needed? •Minimize overhead • Omit unnecessary process • Originally suitable for C++ & not fi t for the usage of Swift(e.g. for loop) • Emphasis on advanced optimization on the Swift side • Compatible with Swift's unique calling conventions • Supports future language features • Flexible memory management by the caller(via Task)

Slide 73

Slide 73 text

Coroutine Representations and ABIs in LLVM

Slide 74

Slide 74 text

⚠ Returned-Continuation Lowering → Async Lowering LLVMͷϓϩϙʔβϧ

Slide 75

Slide 75 text

Contents •Swift compiler 101 •Two features of Swift async function (overview) •Two features of Swift async function (detail)

Slide 76

Slide 76 text

Contents •Swift compiler 101 •Two features of Swift async function (overview) •Two features of Swift async function (detail)

Slide 77

Slide 77 text

Mostly about LLVM

Slide 78

Slide 78 text

LLVM IR 101

Slide 79

Slide 79 text

Module Structure of LLVM IR Function BasicBlock Instruction Manage the entire program One program List of instructions executed in order Actual instruction to the machine

Slide 80

Slide 80 text

Function Function Module Almost like this if … else BasicBlock Instruction Instruction … BasicBlock Instruction Instruction … if … else BasicBlock Instruction Instruction … BasicBlock Instruction Instruction …

Slide 81

Slide 81 text

Two features of Swift async function •Keep local state on a special stack •Split functions into partial functions that run between suspensions

Slide 82

Slide 82 text

Heap memory Stack async b Only info across suspend points

Slide 83

Slide 83 text

How to know whether it is necessary or not?

Slide 84

Slide 84 text

•Common parent classes for all values (variables, constants, functions, instructions, etc.) •def-use chain: Hold a list of other Values that use this value(UseList) Value class https://llvm.org/doxygen/classllvm_1_1Value.html LLVM

Slide 85

Slide 85 text

•If two BasicBlocks A and B are given, check whether the path from A to B passes through the suspend point (whether a suspend instruction is included) SuspendCrossingInfo class https://github.com/swiftlang/llvm-project/blob/next/llvm/include/llvm/Transforms/Coroutines/SuspendCrossingInfo.h LLVM

Slide 86

Slide 86 text

BasicBlock Value What does it do? UseList BasicBlock Value BasicBlock Value BasicBlock Value … LLVM Across suspend point? SuspendCrossingInfo compares BasicBlocks after splitting functions

Slide 87

Slide 87 text

Can reduce memory usage

Slide 88

Slide 88 text

...It should be

Slide 89

Slide 89 text

Bug https://github.com/swiftlang/swift/issues/72289

Slide 90

Slide 90 text

Unnecessary async frame… Nothing across suspend point Async frame is created but https://github.com/swiftlang/swift/issues/72289

Slide 91

Slide 91 text

Investigation Need a memory if a value is included in Spills Is it because swift_task_alloc(※) is called? ※ Called when AsyncContext requires a dynamic size https://github.com/swiftlang/swift/issues/72289

Slide 92

Slide 92 text

All async functions calls it = AsyncContext size ❌static https://github.com/swiftlang/swift/blob/main/lib/IRGen/GenCall.cpp#L166 https://github.com/swiftlang/swift/issues/72289 Investigation

Slide 93

Slide 93 text

•My understanding is correct? •How solve it? •If not across suspend point, use a static AsyncContextSize? (Not sure how to judge) •Erase swift_task_alloc on SILOptimizer or LLVM? Hmm…🤔 https://github.com/swiftlang/swift/issues/72289

Slide 94

Slide 94 text

BTW

Slide 95

Slide 95 text

Two features of Swift async function •Keep local state on a special stack •Split functions into partial functions that run between suspensions

Slide 96

Slide 96 text

Code optimization in LLVM ม׵લ LLVM IR ม׵ޙ LLVM IR

Slide 97

Slide 97 text

Optimization with multiple passes ม׵લ LLVM IR Pass Pass ม׵ޙ LLVM IR … Parse & Optimization

Slide 98

Slide 98 text

Functions split is one of them ม׵લ LLVM IR Pass Pass ม׵ޙ LLVM IR … Function split

Slide 99

Slide 99 text

Coroutine Transformation Passes •CoroEarly •CoroSplit •CoroAnnotationElide •CoroElide •CoroCleanup https://llvm.org/docs/Coroutines.html#coroutine-transformation-passes LLVM Coro = Coroutine Mechanism to handle async process (etc.) in LLVM

Slide 100

Slide 100 text

Function split in CoroSplit •CoroEarly •CoroSplit •CoroAnnotationElide •CoroElide •CoroCleanup https://llvm.org/docs/Coroutines.html#coroutine-transformation-passes LLVM

Slide 101

Slide 101 text

Split BasicBlocks Function BasicBlock … Suspend Instruction … BasicBlock … BasicBlock Suspend Instruction … ✂ https://github.com/swiftlang/llvm-project/blob/next/llvm/lib/Transforms/Coroutines/CoroSplit.cpp

Slide 102

Slide 102 text

Contents •Swift compiler 101 •Two features of Swift async function (overview) •Two features of Swift async function (detail)

Slide 103

Slide 103 text

One last thing

Slide 104

Slide 104 text

It's best to touch it yourself!

Slide 105

Slide 105 text

https://zenn.dev/omochimetaru/articles/8a7f35c5e23a24 ⚠It’s Japanese, but we can follow commands in it.

Slide 106

Slide 106 text

How to debug https://github.com/swiftlang/swift/blob/main/docs/DebuggingTheCompiler.md

Slide 107

Slide 107 text

•Even if you are not familiar with C++, it's okay at fi rst •Debug and grasp the processing fl ow (it’s important to fi nd the entry point) •Get used to frequent words and abbreviations •Don't be misled by casting For those who are interested in Swift compilers

Slide 108

Slide 108 text

• Swift ίϯύΠϥͷΞʔΩςΫνϟ(The architecture of Swift compiler) • Swift Compiler • Awesome LLVM • SwiftίϯύΠϥ։ൃೖ໳(The introduction of Swift compiler dvelopment) • Explore Swift performance • Swift concurrency: Behind the scenes • Swift repository • LLVM repository(forked by Apple) • Async lowering • Issue about unnecessary async frame References

Slide 109

Slide 109 text

Thank you!