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

Opaque Result Typeの実装

Opaque Result Typeの実装

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