Share
Embed
Transcript
50 slides
-
நԽͷํ๏ • ORTͷΞΠσϯςΟςΟʹରԠ͢ΔOpaque Type Descriptor(OTD)͕࡞ΒΕΔ • OTD͔ΒϥϯλΠϜؔΛհͯ͠Metatype ͱProtocol Witness Table͕औಘͰ͖Δ
• ͪΖΜɺMetatype͔ΒValue Witness Table͕औಘͰ͖Δ 6 -
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 -
// 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 -
! // lib/AST/ASTPrinter.cpp Printer << "@_opaqueReturnTypeOf("; OpaqueTypeDecl *decl = T->getDecl();
Printer.printEscapedStringLiteral( decl->getOpaqueReturnTypeIdentifier().str()); Printer << ", " << T->getInterfaceType() ->castTo<GenericTypeParamType>() ->getIndex(); Printer << u8") \U0001F9B8"; printGenericArgs(T->getSubstitutions().getReplacementTypes()); Ṗ 14 -
// 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 where Self : P> (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 -
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 -
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 -
• swift_getOpaqueTypeMetadataͱ͍͏ϥϯλ ΠϜؔʹɺ $s1a1fQryFQOMQΛ͍ͯ͠Δ • $s1a1fQryFQOMQ opaque type descriptor for
<<opaque return type of a.f() -> some>> • ͜ΕͰ%3ʹMetatype͕औΓग़͞ΕΔ ࣮ࡍʹਅͷܕͰ͋ΔIntͷMetatype͕ಘΒΕ Δ 27 -
• Opaque Type Descriptor͕fͷίϯύΠϧ࣌ʹ Ұॹʹੜ͞Ε͍ͯΔͷͰɺfͷฦ͢ਅͷܕ͕ มߋ͞Εͨͱ͖ʹɺOTDͷதҰॹʹม ߋ͞ΕΔɻ • callerଆͰɺOTDΛϥϯλΠϜؔʹ͠ ͯɺMetatype,
VWT, PWTͳͲΛऔಘͯ͠ಈ࡞ ͢ΔͷͰɺOTDͷத͕มΘͬͯޓੑΛ ҡ࣋Ͱ͖Δɻ 34 -
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 -
// 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 -
• ਅͷܕIntͰalloc_stackͯ͠ɺΞυϨεΛ%0 ʹೖ • ͦΕΛ @_opaqueReturnTypeOf("$s1b1fQryF", 0) ܕͷϙΠϯλʹΩϟετͯ͠ɺ fͷݺͼग़͠ʹ͍ͯ͠Δ •
Intͷprintϝιου$sSi1bE5printyyFΛ ݺͼग़͠ • dealloc_stackͰϝϞϦղ์ 42 -
; 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 -
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