Skip to content

Instantly share code, notes, and snippets.

@omochi
Created August 11, 2025 04:26
Show Gist options
  • Select an option

  • Save omochi/92ecc485b9be6c3044ccf964ec156e91 to your computer and use it in GitHub Desktop.

Select an option

Save omochi/92ecc485b9be6c3044ccf964ec156e91 to your computer and use it in GitHub Desktop.

Swiftコード

func foo(g: @escaping () -> Void) {}

@_optimize(none)
func sink<X>(_ x: X) {}

func main(a: Int) {
    foo { [a] () in
        sink(a)
    }
}

これをコンパイル

swift -emit-ir a.swift

LLVM-IRが得られる

; ModuleID = '<swift-imported-modules>'
source_filename = "<swift-imported-modules>"
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128-Fn32"
target triple = "arm64-apple-macosx15.0.0"

%swift.full_boxmetadata = type { ptr, ptr, %swift.type, i32, ptr }
%swift.type = type { i64 }
%swift.function = type { ptr, ptr }
%swift.refcounted = type { ptr, i64 }
%TSi = type <{ i64 }>

@"symbolic Si" = linkonce_odr hidden constant <{ [2 x i8], i8 }> <{ [2 x i8] c"Si", i8 0 }>, section "__TEXT,__swift5_typeref, regular", no_sanitize_address, align 2
@"\01l__swift5_reflection_descriptor" = private constant { i32, i32, i32, i32 } { i32 1, i32 0, i32 0, i32 trunc (i64 sub (i64 ptrtoint (ptr @"symbolic Si" to i64), i64 ptrtoint (ptr getelementptr inbounds ({ i32, i32, i32, i32 }, ptr @"\01l__swift5_reflection_descriptor", i32 0, i32 3) to i64)) to i32) }, section "__TEXT,__swift5_capture, regular", no_sanitize_address, align 4
@metadata = private constant %swift.full_boxmetadata { ptr @objectdestroy, ptr null, %swift.type { i64 1024 }, i32 16, ptr @"\01l__swift5_reflection_descriptor" }, align 8
@"\01l_entry_point" = private constant { i32, i32 } { i32 trunc (i64 sub (i64 ptrtoint (ptr @main to i64), i64 ptrtoint (ptr @"\01l_entry_point" to i64)) to i32), i32 0 }, section "__TEXT, __swift5_entry, regular, no_dead_strip", align 4
@"$sSiN" = external global %swift.type, align 8
@__swift_reflection_version = linkonce_odr hidden constant i16 3
@llvm.used = appending global [7 x ptr] [ptr @main, ptr @"$s1a3foo1gyyyc_tF", ptr @"$s1a4sinkyyxlF", ptr @"$s1a4mainAAySi_tF", ptr @"\01l__swift5_reflection_descriptor", ptr @"\01l_entry_point", ptr @__swift_reflection_version], section "llvm.metadata"

define i32 @main(i32 %0, ptr %1) #0 {
entry:
  ret i32 0
}

define hidden swiftcc void @"$s1a3foo1gyyyc_tF"(ptr %0, ptr %1) #0 {
entry:
  %g.debug = alloca %swift.function, align 8
  call void @llvm.memset.p0.i64(ptr align 8 %g.debug, i8 0, i64 16, i1 false)
  call void @llvm.lifetime.start.p0(i64 16, ptr %g.debug)
  %g.debug.fn = getelementptr inbounds %swift.function, ptr %g.debug, i32 0, i32 0
  store ptr %0, ptr %g.debug.fn, align 8
  %g.debug.data = getelementptr inbounds %swift.function, ptr %g.debug, i32 0, i32 1
  store ptr %1, ptr %g.debug.data, align 8
  ret void
}

; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #1

; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write)
declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg) #2

define hidden swiftcc void @"$s1a4sinkyyxlF"(ptr noalias %0, ptr %X) #0 {
entry:
  %X1 = alloca ptr, align 8
  %x.debug = alloca ptr, align 8
  call void @llvm.memset.p0.i64(ptr align 8 %x.debug, i8 0, i64 8, i1 false)
  store ptr %X, ptr %X1, align 8
  store ptr %0, ptr %x.debug, align 8
  ret void
}

define hidden swiftcc void @"$s1a4mainAAySi_tF"(i64 %0) #0 {
entry:
  %a.debug = alloca i64, align 8
  call void @llvm.memset.p0.i64(ptr align 8 %a.debug, i8 0, i64 8, i1 false)
  store i64 %0, ptr %a.debug, align 8
  %1 = call noalias ptr @swift_allocObject(ptr getelementptr inbounds (%swift.full_boxmetadata, ptr @metadata, i32 0, i32 2), i64 24, i64 7) #3
  %2 = getelementptr inbounds <{ %swift.refcounted, %TSi }>, ptr %1, i32 0, i32 1
  %._value = getelementptr inbounds %TSi, ptr %2, i32 0, i32 0
  store i64 %0, ptr %._value, align 8
  call swiftcc void @"$s1a3foo1gyyyc_tF"(ptr @"$s1a4mainAAySi_tFyycfU_TA", ptr %1)
  call void @swift_release(ptr %1) #3
  ret void
}

define internal swiftcc void @"$s1a4mainAAySi_tFyycfU_"(i64 %0) #0 {
entry:
  %a.debug = alloca i64, align 8
  call void @llvm.memset.p0.i64(ptr align 8 %a.debug, i8 0, i64 8, i1 false)
  %1 = alloca %TSi, align 8
  store i64 %0, ptr %a.debug, align 8
  call void @llvm.lifetime.start.p0(i64 8, ptr %1)
  %._value = getelementptr inbounds %TSi, ptr %1, i32 0, i32 0
  store i64 %0, ptr %._value, align 8
  call swiftcc void @"$s1a4sinkyyxlF"(ptr noalias %1, ptr @"$sSiN")
  call void @llvm.lifetime.end.p0(i64 8, ptr %1)
  ret void
}

define private swiftcc void @objectdestroy(ptr swiftself %0) #0 {
entry:
  call void @swift_deallocObject(ptr %0, i64 24, i64 7) #3
  ret void
}

; Function Attrs: nounwind
declare void @swift_deallocObject(ptr, i64, i64) #3

; Function Attrs: nounwind
declare ptr @swift_allocObject(ptr, i64, i64) #3

define internal swiftcc void @"$s1a4mainAAySi_tFyycfU_TA"(ptr swiftself %0) #0 {
entry:
  %1 = getelementptr inbounds <{ %swift.refcounted, %TSi }>, ptr %0, i32 0, i32 1
  %._value = getelementptr inbounds %TSi, ptr %1, i32 0, i32 0
  %2 = load i64, ptr %._value, align 8
  tail call swiftcc void @"$s1a4mainAAySi_tFyycfU_"(i64 %2)
  ret void
}

; Function Attrs: nounwind
declare void @swift_release(ptr) #3

; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #1

attributes #0 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "probe-stack"="__chkstk_darwin" "stack-protector-buffer-size"="8" "target-cpu"="apple-a12" "target-features"="+aes,+ccidx,+complxnum,+crc,+fp-armv8,+fullfp16,+jsconv,+lse,+neon,+pauth,+perfmon,+ras,+rcpc,+rdm,+sha2,+v8.1a,+v8.2a,+v8.3a,+v8a,+zcm,+zcz" }
attributes #1 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
attributes #2 = { nocallback nofree nounwind willreturn memory(argmem: write) }
attributes #3 = { nounwind }

!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11}
!swift.module.flags = !{!12}
!llvm.linker.options = !{!13, !14, !15, !16, !17}

!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 15, i32 5]}
!1 = !{i32 1, !"Objective-C Version", i32 2}
!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
!4 = !{i32 4, !"Objective-C Garbage Collection", i32 100730624}
!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
!7 = !{i32 1, !"wchar_size", i32 4}
!8 = !{i32 8, !"PIC Level", i32 2}
!9 = !{i32 7, !"uwtable", i32 1}
!10 = !{i32 7, !"frame-pointer", i32 1}
!11 = !{i32 1, !"Swift Version", i32 7}
!12 = !{!"standard-library", i1 false}
!13 = !{!"-lswiftSwiftOnoneSupport"}
!14 = !{!"-lswiftCore"}
!15 = !{!"-lswift_Concurrency"}
!16 = !{!"-lswift_StringProcessing"}
!17 = !{!"-lobjc"}

クロージャを作るためにキャプチャオブジェクトを生成するところ

define hidden swiftcc void @"$s1a4mainAAySi_tF"(i64 %0) #0 {
  ...
  %1 = call noalias ptr @swift_allocObject(ptr getelementptr inbounds (%swift.full_boxmetadata, ptr @metadata, i32 0, i32 2), i64 24, i64 7) #3
  ...
}

渡してるメタデータ

@metadata = private constant %swift.full_boxmetadata { ptr @objectdestroy, ptr null, %swift.type { i64 1024 }, i32 16, ptr @"\01l__swift5_reflection_descriptor" }, align 8

5番目のフィールドにリフレクションデータがある

@"\01l__swift5_reflection_descriptor" = private constant { i32, i32, i32, i32 } { 
  i32 1, i32 0, i32 0, 
  ... ptr @"symbolic Si" to i64 ...,
  section "__TEXT,__swift5_capture, regular", no_sanitize_address, align 4

読み解くと、フィールド1個で、それが Swift.Int だと書いてある。

ChatGPT との会話 https://chatgpt.com/share/689970ce-b278-8006-a239-983a9eab341c

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment