Skip to content

[SR-12548] SILCombiner::visitPartialApplyInst verification failure for @convention(method) callees #54992

@dan-zheng

Description

@dan-zheng
Previous ID SR-12548
Radar rdar://problem/62201645
Original Reporter @dan-zheng
Type Bug
Status Closed
Resolution Done
Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug, SILOptimizer
Assignee @dan-zheng
Priority Medium

md5: b55fdb79390cc22b94c51ec8555c6e04

Issue Description:

SILCombiner::visitPartialApplyInst rewrites the following SIL:

  %1 = function_ref @method_func : $@convention(method) (Int32) -> ()
  %2 = partial_apply %1() : $@convention(method) (Int32) -> ()

Into the following SIL, which fails verification:

  %0 = function_ref @method_func : $@convention(method) (Int32) -> ()
  %1 = thin_to_thick_function %0 : $@convention(method) (Int32) -> () to $@callee_owned (Int32) -> ()
SIL verification failed: operand of thin_to_thick_function must be thin: opFTy->getRepresentation() == SILFunctionType::Representation::Thin
Verifying instruction:
     // function_ref specialized Protocol.method()
  %5 = function_ref @$s7crasher8ProtocolPAAE6methodxyFAA6StructV_TG5 : $@convention(method) (@in_guaranteed Struct) -> @out Struct // user: %6
->   %6 = thin_to_thick_function %5 : $@convention(method) (@in_guaranteed Struct) -> @out Struct to $@callee_guaranteed (@in_guaranteed Struct) -> @out Struct // user: %11

Fix ideas:

  • Disable SILCombiner::visitPartialApplyInst for non-@convention(thin) callees.

    • Other code paths that may construct thin_to_thick_function with @convention(method) operands (e.g. CapturePropagation::rewritePartialApply) should be updated similarly.
  • Relax verification to allow thin_to_thick_function with @convention(method) operands. I don't know if this is valid.


SIL reproducer:

import Swift
import Builtin

sil @method_func : $@convention(method) (Int32) -> ()

sil @test_capture_propagation_method_callee : $@convention(thin) () -> @owned @callee_owned (Int32) -> () {
  %1 = function_ref @method_func : $@convention(method) (Int32) -> ()
  %2 = partial_apply %1() : $@convention(method) (Int32) -> ()
  return %2 : $@callee_owned (Int32) -> ()
}

Swift reproducer (via SIL generated by differentiation transform):

import _Differentiation

protocol Protocol: Differentiable {
 @differentiable
 func method() -> Self
}

extension Protocol {
 @differentiable
 func method() -> Self \{ self }
}

struct Struct: Protocol {}

let _: @differentiable (Struct) -> Struct = \{ $0.method() }
$ swiftc -O crasher.swift
SIL verification failed: operand of thin_to_thick_function must be thin: opFTy->getRepresentation() == SILFunctionType::Representation::Thin
Verifying instruction:
     // function_ref specialized Protocol.method()
  %5 = function_ref @$s7crasher8ProtocolPAAE6methodxyFAA6StructV_TG5 : $@convention(method) (@in_guaranteed Struct) -> @out Struct // user: %6
->   %6 = thin_to_thick_function %5 : $@convention(method) (@in_guaranteed Struct) -> @out Struct to $@callee_guaranteed (@in_guaranteed Struct) -> @out Struct // user: %11
     %11 = differentiable_function [parameters 0] %6 : $@callee_guaranteed (@in_guaranteed Struct) -> @out Struct with_derivative {%8 : $@callee_guaranteed (@in_guaranteed Struct) -> (@out Struct, @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <Struct.TangentVector, Struct.TangentVector>), %10 : $@callee_guaranteed (@in_guaranteed Struct) -> (@out Struct, @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <Struct.TangentVector, Struct.TangentVector>)} // users: %18, %16, %13, %12
In function:
// AD__$s7crasherAA6StructVACcfU___vjp_src_0_wrt_0
sil private @AD__$s7crasherAA6StructVACcfU___vjp_src_0_wrt_0 : $@convention(thin) (Struct) -> (Struct, @owned @callee_guaranteed (Struct.TangentVector) -> Struct.TangentVector) {
// %0                                             // users: %4, %1
bb0(%0 : $Struct):
  debug_value %0 : $Struct, let, name "$0", argno 1 // id: %1
  %2 = alloc_stack $Struct                        // users: %26, %20
  %3 = alloc_stack $Struct                        // users: %4, %24, %20
  store %0 to %3 : $*Struct                       // id: %4
  // function_ref specialized Protocol.method()
  %5 = function_ref @$s7crasher8ProtocolPAAE6methodxyFAA6StructV_TG5 : $@convention(method) (@in_guaranteed Struct) -> @out Struct // user: %6
  %6 = thin_to_thick_function %5 : $@convention(method) (@in_guaranteed Struct) -> @out Struct to $@callee_guaranteed (@in_guaranteed Struct) -> @out Struct // user: %11
  %7 = differentiability_witness_function [jvp] [parameters 0] [results 0] <Self where Self : Protocol> @$s7crasher8ProtocolPAAE6methodxyF : $@convention(method) <Self where Self : Protocol> (@in_guaranteed Self) -> @out Self // user: %8
  %8 = partial_apply [callee_guaranteed] %7<Struct>() : $@convention(method) <τ_0_0 where τ_0_0 : Protocol> (@in_guaranteed τ_0_0) -> (@out τ_0_0, @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <τ_0_0.TangentVector, τ_0_0.TangentVector>) // user: %11
  %9 = differentiability_witness_function [vjp] [parameters 0] [results 0] <Self where Self : Protocol> @$s7crasher8ProtocolPAAE6methodxyF : $@convention(method) <Self where Self : Protocol> (@in_guaranteed Self) -> @out Self // user: %10
  %10 = partial_apply [callee_guaranteed] %9<Struct>() : $@convention(method) <τ_0_0 where τ_0_0 : Protocol> (@in_guaranteed τ_0_0) -> (@out τ_0_0, @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <τ_0_0.TangentVector, τ_0_0.TangentVector>) // user: %11
  %11 = differentiable_function [parameters 0] %6 : $@callee_guaranteed (@in_guaranteed Struct) -> @out Struct with_derivative {%8 : $@callee_guaranteed (@in_guaranteed Struct) -> (@out Struct, @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <Struct.TangentVector, Struct.TangentVector>), %10 : $@callee_guaranteed (@in_guaranteed Struct) -> (@out Struct, @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <Struct.TangentVector, Struct.TangentVector>)} // users: %18, %16, %13, %12
  %12 = differentiable_function_extract [vjp] %11 : $@differentiable @callee_guaranteed (@in_guaranteed Struct) -> @out Struct // users: %21, %14, %20
  %13 = differentiable_function_extract [original] %11 : $@differentiable @callee_guaranteed (@in_guaranteed Struct) -> @out Struct // user: %15
  strong_retain %12 : $@callee_guaranteed (@in_guaranteed Struct) -> (@out Struct, @owned @callee_guaranteed (@in_guaranteed Struct.TangentVector) -> @out Struct.TangentVector) // id: %14
  strong_release %13 : $@callee_guaranteed (@in_guaranteed Struct) -> @out Struct // id: %15
  %16 = differentiable_function_extract [jvp] %11 : $@differentiable @callee_guaranteed (@in_guaranteed Struct) -> @out Struct // user: %17
  strong_release %16 : $@callee_guaranteed (@in_guaranteed Struct) -> (@out Struct, @owned @callee_guaranteed (@in_guaranteed Struct.TangentVector) -> @out Struct.TangentVector) // id: %17
  %18 = differentiable_function_extract [vjp] %11 : $@differentiable @callee_guaranteed (@in_guaranteed Struct) -> @out Struct // user: %19
  strong_release %18 : $@callee_guaranteed (@in_guaranteed Struct) -> (@out Struct, @owned @callee_guaranteed (@in_guaranteed Struct.TangentVector) -> @out Struct.TangentVector) // id: %19
  %20 = apply %12(%2, %3) : $@callee_guaranteed (@in_guaranteed Struct) -> (@out Struct, @owned @callee_guaranteed (@in_guaranteed Struct.TangentVector) -> @out Struct.TangentVector) // user: %23
  strong_release %12 : $@callee_guaranteed (@in_guaranteed Struct) -> (@out Struct, @owned @callee_guaranteed (@in_guaranteed Struct.TangentVector) -> @out Struct.TangentVector) // id: %21
  // function_ref thunk for @escaping @callee_guaranteed (@in_guaranteed Struct.TangentVector) -> (@out Struct.TangentVector)
  %22 = function_ref @$s7crasher6StructV13TangentVectorVAEIegnr_A2EIegyd_TR : $@convention(thin) (Struct.TangentVector, @guaranteed @callee_guaranteed (@in_guaranteed Struct.TangentVector) -> @out Struct.TangentVector) -> Struct.TangentVector // user: %23
  %23 = partial_apply [callee_guaranteed] %22(%20) : $@convention(thin) (Struct.TangentVector, @guaranteed @callee_guaranteed (@in_guaranteed Struct.TangentVector) -> @out Struct.TangentVector) -> Struct.TangentVector // user: %27
  dealloc_stack %3 : $*Struct                     // id: %24
  %25 = struct $Struct ()                         // user: %30
  dealloc_stack %2 : $*Struct                     // id: %26
  %27 = struct $_AD__$s7crasherAA6StructVACcfU__bb0__PB__src_0_wrt_0 (%23 : $@callee_guaranteed (Struct.TangentVector) -> Struct.TangentVector) // user: %29
  // function_ref AD__$s7crasherAA6StructVACcfU___pullback_src_0_wrt_0
  %28 = function_ref @AD__$s7crasherAA6StructVACcfU___pullback_src_0_wrt_0 : $@convention(thin) (Struct.TangentVector, @owned _AD__$s7crasherAA6StructVACcfU__bb0__PB__src_0_wrt_0) -> Struct.TangentVector // user: %29
  %29 = partial_apply [callee_guaranteed] %28(%27) : $@convention(thin) (Struct.TangentVector, @owned _AD__$s7crasherAA6StructVACcfU__bb0__PB__src_0_wrt_0) -> Struct.TangentVector // user: %30
  %30 = tuple (%25 : $Struct, %29 : $@callee_guaranteed (Struct.TangentVector) -> Struct.TangentVector) // user: %31
  return %30 : $(Struct, @callee_guaranteed (Struct.TangentVector) -> Struct.TangentVector) // id: %31
} // end sil function 'AD__$s7crasherAA6StructVACcfU___vjp_src_0_wrt_0'

Metadata

Metadata

Assignees

Labels

SILOptimizerArea → compiler: SIL optimization passesbugA deviation from expected or documented behavior. Also: expected but undesirable behavior.compilerThe Swift compiler itself

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions