Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Opaque Result Typeの実装

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

Opaque Result Typeの実装

Avatar for omochimetaru

omochimetaru

May 24, 2019
Tweet

More Decks by omochimetaru

Other Decks in Programming

Transcript

  1. 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
  2. // 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
  3. ! // 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
  4. // 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
  5. 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
  6. 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
  7. • swift_getOpaqueTypeMetadataͱ͍͏ϥϯλ ΠϜؔ਺ʹɺ $s1a1fQryFQOMQΛ౉͍ͯ͠Δ • $s1a1fQryFQOMQ͸ opaque type descriptor for

    <<opaque return type of a.f() -> some>> • ͜ΕͰ%3ʹMetatype͕औΓग़͞ΕΔ ࣮ࡍʹ͸ਅͷܕͰ͋ΔIntͷMetatype͕ಘΒΕ Δ 27
  8. 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
  9. // 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
  10. ; 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
  11. 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