Slide 1

Slide 1 text

Opaque Result Typeͷ࣮૷ omochimetaru Θ͍Θ͍swiftc #11 1

Slide 2

Slide 2 text

ٙ໰ 2

Slide 3

Slide 3 text

ORTʹΑΔந৅Խ ޙ͔ΒਅͷܕΛมߋՄೳ ϦίϯύΠϧͤͣʹมߋՄೳ ͲͷΑ͏ʹ࣮ݱ͢Δͷ͔ʁ 3

Slide 4

Slide 4 text

ਅͷܕʹΑΔಛघԽ ਅͷܕ͕Θ͔Δͱ͖͸ɺͦͷܕͰಛघԽͯ͠औΓ ѻ͏ ͲͷΑ͏ʹ࣮ݱ͢Δͷ͔ʁ 4

Slide 5

Slide 5 text

౴͑ 5

Slide 6

Slide 6 text

ந৅Խͷํ๏ • ORTͷΞΠσϯςΟςΟʹରԠ͢ΔOpaque Type Descriptor(OTD)͕࡞ΒΕΔ • OTD͔Β͸ϥϯλΠϜؔ਺Λհͯ͠Metatype ͱProtocol Witness Table͕औಘͰ͖Δ • ΋ͪΖΜɺMetatype͔Β͸Value Witness Table͕औಘͰ͖Δ 6

Slide 7

Slide 7 text

ಛघԽͷํ๏ • ݺͼग़͠ଆͰϙΠϯλΛΩϟετ͢Δ 7

Slide 8

Slide 8 text

࣮ݧ 8

Slide 9

Slide 9 text

protocol P { func print() } extension Int : P {} func f() -> some P { return Int(3) } func callF() { let p1 = f() // ORTΛฦؔ͢਺ͷݺͼग़͠ let p2 = p1 // ORTܕಉ࢜ͷίϐʔ p2.print() // ϓϩτίϧϝιουͷݺͼग़͠ } 9

Slide 10

Slide 10 text

callee SIL 10

Slide 11

Slide 11 text

// f() sil hidden @$s1a1fQryF : $@convention(thin) () -> @out @_opaqueReturnTypeOf("$s1a1fQryF", 0) { // %0 // user: %1 bb0(%0 : $*@_opaqueReturnTypeOf("$s1a1fQryF", 0) ): %1 = unchecked_addr_cast %0 : $*@_opaqueReturnTypeOf("$s1a1fQryF", 0) to $*Int // user: %4 %2 = integer_literal $Builtin.Int64, 3 // user: %3 %3 = struct $Int (%2 : $Builtin.Int64) // user: %4 store %3 to %1 : $*Int // id: %4 %5 = tuple () // user: %6 return %5 : $() // id: %6 } // end sil function '$s1a1fQryF' 11

Slide 12

Slide 12 text

• ฦΓ஋ͷܕͷදݱ͸ @_opaqueReturnTypeOf("$s1a1fQryF", 0) ܕ໊ʹؔ਺໊͕ຒΊࠐ·Ε͍ͯΔ • @out͕͍͍ͭͯΔͷͰɺϙΠϯλʹΑΔؒ઀ฦ ͠ • bb0ͷҾ਺ͷܕΛݟͯ΋ϙΠϯλͩͱΘ͔Δ 12

Slide 13

Slide 13 text

• unchecked_addr_castͰIntͷϙΠϯλʹΩϟ ετ • storeͰͦͷϙΠϯλʹ݁ՌΛॻ͖ࠐΉ 13

Slide 14

Slide 14 text

! // lib/AST/ASTPrinter.cpp Printer << "@_opaqueReturnTypeOf("; OpaqueTypeDecl *decl = T->getDecl(); Printer.printEscapedStringLiteral( decl->getOpaqueReturnTypeIdentifier().str()); Printer << ", " << T->getInterfaceType() ->castTo() ->getIndex(); Printer << u8") \U0001F9B8"; printGenericArgs(T->getSubstitutions().getReplacementTypes()); Ṗ 14

Slide 15

Slide 15 text

caller SIL 15

Slide 16

Slide 16 text

// callF() sil hidden @$s1a5callFyyF : $@convention(thin) () -> () { bb0: %0 = alloc_stack $@_opaqueReturnTypeOf("$s1a1fQryF", 0) , let, name "p1" // users: %10, %9, %4, %2 // function_ref f() %1 = function_ref @$s1a1fQryF : $@convention(thin) () -> @out @_opaqueReturnTypeOf("$s1a1fQryF", 0) // user: %2 %2 = apply %1(%0) : $@convention(thin) () -> @out @_opaqueReturnTypeOf("$s1a1fQryF", 0) %3 = alloc_stack $@_opaqueReturnTypeOf("$s1a1fQryF", 0) , let, name "p2" // users: %8, %7, %6, %4 copy_addr %0 to [initialization] %3 : $*@_opaqueReturnTypeOf("$s1a1fQryF", 0) ! // id: %4 %5 = witness_method $@_opaqueReturnTypeOf("$s1a1fQryF", 0) , #P.print!1 : (Self) -> () -> () : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> () // user: %6 %6 = apply %5<@_opaqueReturnTypeOf("$s1a1fQryF", 0) >(%3) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> () destroy_addr %3 : $*@_opaqueReturnTypeOf("$s1a1fQryF", 0) // id: %7 dealloc_stack %3 : $*@_opaqueReturnTypeOf("$s1a1fQryF", 0) // id: %8 destroy_addr %0 : $*@_opaqueReturnTypeOf("$s1a1fQryF", 0) // id: %9 dealloc_stack %0 : $*@_opaqueReturnTypeOf("$s1a1fQryF", 0) // id: %10 %11 = tuple () // user: %12 return %11 : $() // id: %12 } // end sil function '$s1a5callFyyF' 16

Slide 17

Slide 17 text

• $@_opaqueReturnTypeOf("$s1a1fQryF", 0) ܕ Ͱalloc_stackͯ͠ɺ ݁ՌΛड͚औΔม਺ΛελοΫʹ֬อ ͦͷΞυϨεΛ%0ʹ୅ೖ • function_ref,applyͰfΛݺͼग़͢ Ҿ਺ʹ֬อͨ͠ϝϞϦྖҬΛ౉͢ • ݺͼग़͠ޙ͸%0ʹ݁Ռ͕ೖ͍ͬͯΔ 17

Slide 18

Slide 18 text

• ίϐʔઌม਺Λಉ༷ʹ࡞੒ɺ %3ͰΞυϨεΛอ࣋ • copy_addrͰ%0͔Β%3ʹίϐʔ 18

Slide 19

Slide 19 text

• witness_methodͰɺ $@_opaqueReturnTypeOf("$s1a1fQryF", 0) ܕ ͷP.printϝιουΛऔಘ • applyͰݺͼग़͢ 19

Slide 20

Slide 20 text

• destroy_addrͰ%3ͷத਎Λഁغ • dealloc_stackͰ%3ͷϝϞϦΛղ์ • destroy_addrͰ%0ͷத਎Λഁغ • dealloc_stackͰ%0ͷϝϞϦΛղ์ 20

Slide 21

Slide 21 text

• ؔ਺໊ΛຒΊࠐΜͩܕ໊ɺ $@_opaqueReturnTypeOf("$s1a1fQryF", 0) Ͱදݱ • callee͸ਅͷܕΛΩϟετͯ͠ॻ͖ࠐΈ • caller͸ܕ໊Ҏ֎ී௨ 21

Slide 22

Slide 22 text

callee LLVM-IR 22

Slide 23

Slide 23 text

define hidden swiftcc void @"$s1a1fQryF" (%swift.opaque* noalias nocapture sret) #0 { entry: %1 = bitcast %swift.opaque* %0 to %TSi* %._value = getelementptr inbounds %TSi, %TSi* %1, i32 0, i32 0 store i64 3, i64* %._value, align 1 ret void } 23

Slide 24

Slide 24 text

• ܕ໊͸ফ͍͑ͯΔ • Ҿ਺ͰopaqueϙΠϯλΛड͚औΔ • ͦΕΛIntͷϙΠϯλʹΩϟετ • storeͰॻ͖ࠐΈ 24

Slide 25

Slide 25 text

caller LLVM-IR 25

Slide 26

Slide 26 text

define hidden swiftcc void @"$s1a5callFyyF"() #0 { entry: %p2.debug = alloca i8*, align 8 %0 = bitcast i8** %p2.debug to i8* call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false) %p1.debug = alloca i8*, align 8 %1 = bitcast i8** %p1.debug to i8* call void @llvm.memset.p0i8.i64(i8* align 8 %1, i8 0, i64 8, i1 false) %2 = call swiftcc %swift.metadata_response @swift_getOpaqueTypeMetadata( i64 0, i8* undef, %swift.type_descriptor* bitcast ( <{ i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32, i32, i32 }>* @"$s1a1fQryFQOMQ" to %swift.type_descriptor* ), i64 0 ) #5 %3 = extractvalue %swift.metadata_response %2, 0 %4 = bitcast %swift.type* %3 to i8*** %5 = getelementptr inbounds i8**, i8*** %4, i64 -1 %.valueWitnesses = load i8**, i8*** %5, align 8, !invariant.load !42, !dereferenceable !43 %6 = bitcast i8** %.valueWitnesses to %swift.vwtable* %7 = getelementptr inbounds %swift.vwtable, %swift.vwtable* %6, i32 0, i32 8 %size = load i64, i64* %7, align 8, !invariant.load !42 %p2 = alloca i8, i64 %size, align 16 call void @llvm.lifetime.start.p0i8(i64 -1, i8* %p2) %8 = bitcast i8* %p2 to %swift.opaque* store i8* %p2, i8** %p2.debug, align 8 %p1 = alloca i8, i64 %size, align 16 call void @llvm.lifetime.start.p0i8(i64 -1, i8* %p1) %9 = bitcast i8* %p1 to %swift.opaque* store i8* %p1, i8** %p1.debug, align 8 call swiftcc void @"$s1a1fQryF"(%swift.opaque* noalias nocapture sret %9) %10 = getelementptr inbounds i8*, i8** %.valueWitnesses, i32 2 %11 = load i8*, i8** %10, align 8, !invariant.load !42 %initializeWithCopy = bitcast i8* %11 to %swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* %12 = call %swift.opaque* %initializeWithCopy(%swift.opaque* noalias %8, %swift.opaque* noalias %9, %swift.type* %3) #3 %13 = call swiftcc i8** @swift_getOpaqueTypeConformance( i8* undef, %swift.type_descriptor* bitcast ( <{ i32, i32, i16, i16, i16, i16, i8, i8, i8, i8, i32, i32, i32, i32, i32 }>* @"$s1a1fQryFQOMQ" to %swift.type_descriptor* ), i64 1 ) #5 %14 = getelementptr inbounds i8*, i8** %13, i32 1 %15 = load i8*, i8** %14, align 8, !invariant.load !42 %16 = bitcast i8* %15 to void (%swift.opaque*, %swift.type*, i8**)* call swiftcc void %16(%swift.opaque* noalias nocapture swiftself %8, %swift.type* %3, i8** %13) %17 = getelementptr inbounds i8*, i8** %.valueWitnesses, i32 1 %18 = load i8*, i8** %17, align 8, !invariant.load !42 %destroy = bitcast i8* %18 to void (%swift.opaque*, %swift.type*)* call void %destroy(%swift.opaque* noalias %8, %swift.type* %3) #3 call void %destroy(%swift.opaque* noalias %9, %swift.type* %3) #3 %19 = bitcast %swift.opaque* %9 to i8* call void @llvm.lifetime.end.p0i8(i64 -1, i8* %19) %20 = bitcast %swift.opaque* %8 to i8* call void @llvm.lifetime.end.p0i8(i64 -1, i8* %20) ret void } 26

Slide 27

Slide 27 text

• swift_getOpaqueTypeMetadataͱ͍͏ϥϯλ ΠϜؔ਺ʹɺ $s1a1fQryFQOMQΛ౉͍ͯ͠Δ • $s1a1fQryFQOMQ͸ opaque type descriptor for < some>> • ͜ΕͰ%3ʹMetatype͕औΓग़͞ΕΔ ࣮ࡍʹ͸ਅͷܕͰ͋ΔIntͷMetatype͕ಘΒΕ Δ 27

Slide 28

Slide 28 text

• getelementptrͷ-1Ͱ%5ʹValue Witness TableΛऔΓग़͢ • getelementptrͷ8Ͱ%7ʹܕͷϝϞϦαΠζΛ औΓग़͢ • ͜ͷαΠζΛ࢖ͬͯɺallocaͰϝϞϦ֬อ͠ ͯɺ %p1ͱ%p2ʹΞυϨεΛ୅ೖ 28

Slide 29

Slide 29 text

• bitcastͰ%p1ΛopaqueϙΠϯλʹΩϟετ • callͰfΛݺͼग़͠ɺͦͷϙΠϯλΛҾ਺ʹ౉ ͢ 29

Slide 30

Slide 30 text

• ͖ͬ͞औΓग़ͨ͠VWT͔Βgetelementptrͷ2 Ͱ initializeWithCopyΛऔΓग़͢ • callͰͦΕΛݺͼग़ͯ͠ίϐʔΛ࣮ߦ 30

Slide 31

Slide 31 text

• swift_getOpaqueTypeConformanceͱ͍͏ϥ ϯλΠϜؔ਺ʹɺ OTDͱ1Λ౉͍ͯ͠Δɻ ͜ͷ1͸͜ͷܕ͕४ڌ͢ΔϓϩτίϧϦετ͔ ΒPΛࢦఆ͢Δ൪߸ • ͜ΕʹΑͬͯ%13ʹProtocol Witness Table͕औ Γग़ͤΔ ࣮ࡍʹ͸ਅͷܕͰ͋ΔIntͷPͷPWT 31

Slide 32

Slide 32 text

• getelementptrͷ1ͰPWT͔ΒϝιουΛ%14 ʹऔΓग़͢ • callͰϓϩτίϧϝιουͷݺͼग़͠ 32

Slide 33

Slide 33 text

• getelementptrͷ1ͰVWT͔ΒdestroyΛऔΓ ग़͢ • callͰͦΕΛݺͼग़ͯ͠p1ͱp2Λഁغ • ϝϞϦղ์͸allocaͳͷͰίʔυແ͠ 33

Slide 34

Slide 34 text

• Opaque Type Descriptor͕fͷίϯύΠϧ࣌ʹ Ұॹʹੜ੒͞Ε͍ͯΔͷͰɺfͷฦ͢ਅͷܕ͕ มߋ͞Εͨͱ͖ʹ͸ɺOTDͷத਎΋Ұॹʹม ߋ͞ΕΔɻ • callerଆͰ͸ɺOTDΛϥϯλΠϜؔ਺ʹ౉͠ ͯɺMetatype, VWT, PWTͳͲΛऔಘͯ͠ಈ࡞ ͢ΔͷͰɺOTDͷத਎͕มΘͬͯ΋ޓ׵ੑΛ ҡ࣋Ͱ͖Δɻ 34

Slide 35

Slide 35 text

ಛघԽͷ࣮ݧ 35

Slide 36

Slide 36 text

࠷దԽͰfͷݺͼग़͕͠ফڈ͞Εͳ͍Α͏ʹɺ fʹ@inline(never)Λ෇͚Δɻ 36

Slide 37

Slide 37 text

callee SIL 37

Slide 38

Slide 38 text

sil hidden [noinline] @$s1b1fQryF : $@convention(thin) () -> @out @_opaqueReturnTypeOf("$s1b1fQryF", 0) { // %0 // user: %1 bb0(%0 : $*@_opaqueReturnTypeOf("$s1b1fQryF", 0) ): %1 = unchecked_addr_cast %0 : $*@_opaqueReturnTypeOf("$s1b1fQryF", 0) to $*Int // user: %4 %2 = integer_literal $Builtin.Int64, 3 // user: %3 %3 = struct $Int (%2 : $Builtin.Int64) // user: %4 store %3 to %1 : $*Int // id: %4 %5 = tuple () // user: %6 return %5 : $() // id: %6 } // end sil function '$s1b1fQryF' 38

Slide 39

Slide 39 text

• ࠷దԽલͱมԽແ͠ʂ 39

Slide 40

Slide 40 text

caller SIL 40

Slide 41

Slide 41 text

// callF() sil hidden @$s1b5callFyyF : $@convention(thin) () -> () { bb0: %0 = alloc_stack $Int // users: %2, %7, %4 // function_ref f() %1 = function_ref @$s1b1fQryF : $@convention(thin) () -> @out @_opaqueReturnTypeOf("$s1b1fQryF", 0) // user: %3 %2 = unchecked_addr_cast %0 : $*Int to $*@_opaqueReturnTypeOf("$s1b1fQryF", 0) // user: %3 %3 = apply %1(%2) : $@convention(thin) () -> @out @_opaqueReturnTypeOf("$s1b1fQryF", 0) %4 = load %0 : $*Int // user: %6 // function_ref Int.print() %5 = function_ref @$sSi1bE5printyyF : $@convention(method) (Int) -> () // user: %6 %6 = apply %5(%4) : $@convention(method) (Int) -> () dealloc_stack %0 : $*Int // id: %7 %8 = tuple () // user: %9 return %8 : $() // id: %9 } // end sil function '$s1b5callFyyF' 41

Slide 42

Slide 42 text

• ਅͷܕIntͰalloc_stackͯ͠ɺΞυϨεΛ%0 ʹ୅ೖ • ͦΕΛ @_opaqueReturnTypeOf("$s1b1fQryF", 0) ܕͷϙΠϯλʹΩϟετͯ͠ɺ fͷݺͼग़͠ʹ౉͍ͯ͠Δ • Intͷprintϝιου$sSi1bE5printyyFΛ௚ ઀ݺͼग़͠ • dealloc_stackͰϝϞϦղ์ 42

Slide 43

Slide 43 text

• ORTܕͰͷૢ࡞͕ͳ͘ͳΓɺIntΛ௚઀ѻͬͯ ͍Δ • fΛݺͼग़࣌͢ʹɺInt΁ͷϙΠϯλΛORTܕ ΁ͷϙΠϯλʹΩϟετ͚ͨͩ͠ 43

Slide 44

Slide 44 text

caller LLVM-IR 44

Slide 45

Slide 45 text

; Function Attrs: noinline norecurse nounwind writeonly define hidden swiftcc void @"$s1b1fQryF" (%swift.opaque* noalias nocapture sret) local_unnamed_addr #5 { entry: %._value = bitcast %swift.opaque* %0 to i64* store i64 3, i64* %._value, align 1 ret void } 45

Slide 46

Slide 46 text

• ΄΅มԽແ͠ʂ 46

Slide 47

Slide 47 text

callee LLVM-IR 47

Slide 48

Slide 48 text

define hidden swiftcc void @"$s1b5callFyyF"() local_unnamed_addr #1 { entry: %0 = alloca %TSi, align 8 %1 = bitcast %TSi* %0 to i8* call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %1) %2 = bitcast %TSi* %0 to %swift.opaque* call swiftcc void @"$s1b1fQryF"(%swift.opaque* noalias nocapture nonnull sret %2) %._value = getelementptr inbounds %TSi, %TSi* %0, i64 0, i32 0 %3 = load i64, i64* %._value, align 8 tail call swiftcc void @"$sSi1bE5printyyF"(i64 %3) call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %1) ret void } 48

Slide 49

Slide 49 text

• allocaͰIntܕͷม਺Λ֬อ • ͦͷΞυϨεΛ%swift.opaque*ʹΩϟετ • ͦΕΛҾ਺ʹ౉ͯ͠fΛݺͼग़͢ • Intͷprintϝιου$sSi1bE5printyyFΛݺ ͼग़͠ 49

Slide 50

Slide 50 text

• ฦΓ஋͕opaque pointerͰͷؒ઀ฦ͠ʹͳͬ ͍ͯΔࣄҎ֎͸ɺී௨ʹIntΛѻ͏ίʔυͱಉ ͡ɻ • ࠷దԽʹΑΓɺOTDͱϥϯλΠϜؔ਺ͷ࢖༻ ͕ফڈ͞Ε͍ͯΔɻ • ந৅ԽʹΑΔύϑΥʔϚϯεͷϩε͕ແ͍ࣄ͕ Θ͔Δɻ 50