Skip to content

[AutoDiff] Fix forward-mode differentiation ownership verification failure. #33898

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 11, 2020

Conversation

dan-zheng
Copy link
Contributor

Previously, LinearMapInfo::shouldDifferentiateInstruction had a special case
for copy_value, returning true for copy_value instructions with an active
operand.

This is unexpected and led to "leaked owned value" ownership verification
failures due to unnecessarily cloned copy_value instructions during
differential generation.

Now, the special case is removed, fixing the failures.
shouldDifferentiateInstruction returns true for copy_value instructions
whose operand and result are both active.

Resolves SR-13530.


Example:

import DifferentiationUnittest

// Note: `NonresilientTracked` is a non-trivial, non-resilient type.
@differentiable
func foo(_ x: NonresilientTracked<Float>) -> NonresilientTracked<Float> {
  precondition(x.value >= 0)
  return x
}

Before: ownership verification failure.

$ swiftc -Xfrontend -enable-experimental-forward-mode-differentiation -Xllvm -debug-only=differentiation error.swift

...

[AD] Activity info for foo at (parameters=(0) results=(0))
bb0:
[ACTIVE] %0 = argument of bb0 : $NonresilientTracked<Float> // users: %23, %3, %1
[NONE]   // function_ref implicit closure #1 in foo(_:)
  %2 = function_ref @$s5error3fooy23DifferentiationUnittest19NonresilientTrackedVySfGAFFSbyXEfu_ : $@convention(thin) (@guaranteed NonresilientTracked<Float>) -> Bool // user: %4
[VARIED]   %3 = copy_value %0 : $NonresilientTracked<Float> // user: %4
[VARIED]   %4 = partial_apply [callee_guaranteed] %2(%3) : $@convention(thin) (@guaranteed NonresilientTracked<Float>) -> Bool // users: %22, %5
[VARIED]   %5 = convert_escape_to_noescape [not_guaranteed] %4 : $@callee_guaranteed () -> Bool to $@noescape @callee_guaranteed () -> Bool // user: %20
[NONE]   %6 = string_literal utf8 "error/error.swift"    // user: %11
[NONE]   %7 = integer_literal $Builtin.Word, 17          // user: %11
[NONE]   %8 = integer_literal $Builtin.Int1, -1          // user: %11
[NONE]   %9 = metatype $@thin StaticString.Type          // user: %11
[NONE]   // function_ref StaticString.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:)
  %10 = function_ref @$ss12StaticStringV08_builtinB7Literal17utf8CodeUnitCount7isASCIIABBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin StaticString.Type) -> StaticString // user: %11
[NONE]   %11 = apply %10(%6, %7, %8, %9) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin StaticString.Type) -> StaticString // user: %20
[NONE]   %12 = integer_literal $Builtin.IntLiteral, 6    // user: %15
[NONE]   %13 = metatype $@thin UInt.Type                 // user: %15
[NONE]   // function_ref UInt.init(_builtinIntegerLiteral:)
  %14 = function_ref @$sSu22_builtinIntegerLiteralSuBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin UInt.Type) -> UInt // user: %15
[NONE]   %15 = apply %14(%12, %13) : $@convention(method) (Builtin.IntLiteral, @thin UInt.Type) -> UInt // user: %20
[NONE]   // function_ref default argument 1 of precondition(_:_:file:line:)
  %16 = function_ref @$ss12precondition__4file4lineySbyXK_SSyXKs12StaticStringVSutFfA0_ : $@convention(thin) () -> @owned @callee_guaranteed () -> @owned String // user: %17
[NONE]   %17 = apply %16() : $@convention(thin) () -> @owned @callee_guaranteed () -> @owned String // users: %21, %18
[NONE]   %18 = convert_escape_to_noescape [not_guaranteed] %17 : $@callee_guaranteed () -> @owned String to $@noescape @callee_guaranteed () -> @owned String // user: %20
[NONE]   // function_ref precondition(_:_:file:line:)
  %19 = function_ref @$ss12precondition__4file4lineySbyXK_SSyXKs12StaticStringVSutF : $@convention(thin) (@noescape @callee_guaranteed () -> Bool, @noescape @callee_guaranteed () -> @owned String, StaticString, UInt) -> () // user: %20
[NONE]   %20 = apply %19(%5, %18, %11, %15) : $@convention(thin) (@noescape @callee_guaranteed () -> Bool, @noescape @callee_guaranteed () -> @owned String, StaticString, UInt) -> ()
[ACTIVE]   %23 = copy_value %0 : $NonresilientTracked<Float> // user: %24

...

[AD] Original bb0: To differentiate or not to differentiate?
[ ]   debug_value %0 : $NonresilientTracked<Float>, let, name "x", argno 1 // id: %1
[ ]   // function_ref implicit closure #1 in foo(_:)
  %2 = function_ref @$s5error3fooy23DifferentiationUnittest19NonresilientTrackedVySfGAFFSbyXEfu_ : $@convention(thin) (@guaranteed NonresilientTracked<Float>) -> Bool // user: %4
[x]   %3 = copy_value %0 : $NonresilientTracked<Float> // user: %4
[ ]   %4 = partial_apply [callee_guaranteed] %2(%3) : $@convention(thin) (@guaranteed NonresilientTracked<Float>) -> Bool // users: %22, %5
[ ]   %5 = convert_escape_to_noescape [not_guaranteed] %4 : $@callee_guaranteed () -> Bool to $@noescape @callee_guaranteed () -> Bool // user: %20
[ ]   %6 = string_literal utf8 "error/error.swift"    // user: %11
[ ]   %7 = integer_literal $Builtin.Word, 17          // user: %11
[ ]   %8 = integer_literal $Builtin.Int1, -1          // user: %11
[ ]   %9 = metatype $@thin StaticString.Type          // user: %11
[ ]   // function_ref StaticString.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:)
  %10 = function_ref @$ss12StaticStringV08_builtinB7Literal17utf8CodeUnitCount7isASCIIABBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin StaticString.Type) -> StaticString // user: %11
[ ]   %11 = apply %10(%6, %7, %8, %9) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin StaticString.Type) -> StaticString // user: %20
[ ]   %12 = integer_literal $Builtin.IntLiteral, 6    // user: %15
[ ]   %13 = metatype $@thin UInt.Type                 // user: %15
[ ]   // function_ref UInt.init(_builtinIntegerLiteral:)
  %14 = function_ref @$sSu22_builtinIntegerLiteralSuBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin UInt.Type) -> UInt // user: %15
[ ]   %15 = apply %14(%12, %13) : $@convention(method) (Builtin.IntLiteral, @thin UInt.Type) -> UInt // user: %20
[ ]   // function_ref default argument 1 of precondition(_:_:file:line:)
  %16 = function_ref @$ss12precondition__4file4lineySbyXK_SSyXKs12StaticStringVSutFfA0_ : $@convention(thin) () -> @owned @callee_guaranteed () -> @owned String // user: %17
[ ]   %17 = apply %16() : $@convention(thin) () -> @owned @callee_guaranteed () -> @owned String // users: %21, %18
[ ]   %18 = convert_escape_to_noescape [not_guaranteed] %17 : $@callee_guaranteed () -> @owned String to $@noescape @callee_guaranteed () -> @owned String // user: %20
[ ]   // function_ref precondition(_:_:file:line:)
  %19 = function_ref @$ss12precondition__4file4lineySbyXK_SSyXKs12StaticStringVSutF : $@convention(thin) (@noescape @callee_guaranteed () -> Bool, @noescape @callee_guaranteed () -> @owned String, StaticString, UInt) -> () // user: %20
[ ]   %20 = apply %19(%5, %18, %11, %15) : $@convention(thin) (@noescape @callee_guaranteed () -> Bool, @noescape @callee_guaranteed () -> @owned String, StaticString, UInt) -> ()
[ ]   destroy_value %17 : $@callee_guaranteed () -> @owned String // id: %21
[ ]   destroy_value %4 : $@callee_guaranteed () -> Bool // id: %22
[x]   %23 = copy_value %0 : $NonresilientTracked<Float> // user: %24
[ ]   return %23 : $NonresilientTracked<Float>        // id: %24

...

[AD] Generated differential for foo:
// AD__foo__differential_src_0_wrt_0
sil hidden [ossa] @AD__foo__differential_src_0_wrt_0 : $@convention(thin) (@guaranteed NonresilientTracked<Float>, @owned _AD__foo_bb0__DF__src_0_wrt_0) -> @owned NonresilientTracked<Float> {
// %0                                             // users: %4, %3
// %1                                             // user: %2
bb0(%0 : @guaranteed $NonresilientTracked<Float>, %1 : $_AD__foo_bb0__DF__src_0_wrt_0):
  destructure_struct %1 : $_AD__foo_bb0__DF__src_0_wrt_0 // id: %2
  %3 = copy_value %0 : $NonresilientTracked<Float>
  %4 = copy_value %0 : $NonresilientTracked<Float> // user: %5
  return %4 : $NonresilientTracked<Float>         // id: %5
} // end sil function 'AD__foo__differential_src_0_wrt_0'

...

Begin Error in Function: 'AD__foo__differential_src_0_wrt_0'
Error! Found a leaked owned value that was never consumed.
Value:   %3 = copy_value %0 : $NonresilientTracked<Float>

End Error in Function: 'AD__foo__differential_src_0_wrt_0'
Found ownership error?!
triggering standard assertion failure routine

After: no error.

…ilure.

Previously, `LinearMapInfo::shouldDifferentiateInstruction` had a special case
for `copy_value`, returning true for `copy_value` instructions with an active
operand.

This is unexpected and led to "leaked owned value" ownership verification
failures due to unnecessarily cloned `copy_value` instructions during
differential generation.

Now, the special case is removed, fixing the failures.
`shouldDifferentiateInstruction` returns true for `copy_value` instructions
whose operand and result are both active.

Resolves SR-13530.
Comment on lines -540 to -543
// Should differentiate any instruction that creates an SSA copy of an
// active operand.
if (isa<CopyValueInst>(inst))
return true;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I tried to track down the origin of this code. I found it was added by this commit, though it existed in a different form prior to the commit.

I think this special-case for copy_value was just an oversight/latent error.

@dan-zheng
Copy link
Contributor Author

@swift-ci Please smoke test

@dan-zheng
Copy link
Contributor Author

The Windows CI failure seems unrelated. Merging now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants