From cf2ccf10725f96637d1eadd7f20dc929a4e7092a Mon Sep 17 00:00:00 2001
From: Richard Wei <rxwei@apple.com>
Date: Fri, 10 Dec 2021 03:05:36 -0800
Subject: [PATCH] [AutoDiff] Use auto-generated locations for temporary
 allocations.

In `TangentBuilder` temporary allocations are emitted in order to make generic calls to `AdditiveArithmetic.zero` and `AdditiveArithmetic.+`. When we perform accumulation of two adjoint values that correspond to a lexical value in the original function, the stack allocations require a debug variable, as we use the original instruction's location. However such a debug variable wouldn't really make sense as these temporary allocations do not represent the original variable's adjoint. With lexical borrow scopes, we hit a crasher when creating temporary allocations when accumulating adjoints for lexical `begin_borrow` instructions.

This PR makes `TangentBuilder`'s temporary allocations use an auto-generated location. The existing debug info emission behavior is not changed, as we still emit `debug_value` when materializing an `AdjointValue` after any necessary adjoint accumulation.
---
 .../Differentiation/TangentBuilder.cpp        | 10 ++++++----
 .../sr15566-vardecl-adjoint-values.swift      | 20 +++++++++++++++++++
 test/AutoDiff/validation-test/array.swift     |  2 +-
 test/AutoDiff/validation-test/optional.swift  |  2 +-
 .../validation-test/optional_property.swift   |  4 ++--
 5 files changed, 30 insertions(+), 8 deletions(-)
 create mode 100644 test/AutoDiff/compiler_crashers_fixed/sr15566-vardecl-adjoint-values.swift

diff --git a/lib/SILOptimizer/Differentiation/TangentBuilder.cpp b/lib/SILOptimizer/Differentiation/TangentBuilder.cpp
index 9b23945942358..9e0f71f5f7745 100644
--- a/lib/SILOptimizer/Differentiation/TangentBuilder.cpp
+++ b/lib/SILOptimizer/Differentiation/TangentBuilder.cpp
@@ -61,7 +61,8 @@ void TangentBuilder::emitZeroIntoBuffer(SILLocation loc, SILValue buffer,
 SILValue TangentBuilder::emitZero(SILLocation loc, CanType type) {
   auto silType = getModule().Types.getLoweredLoadableType(
       type, TypeExpansionContext::minimal(), getModule());
-  auto *alloc = createAllocStack(loc, silType);
+  auto tempAllocLoc = RegularLocation::getAutoGeneratedLocation();
+  auto *alloc = createAllocStack(tempAllocLoc, silType);
   emitZeroIntoBuffer(loc, alloc, IsInitialization);
   auto zeroValue = emitLoadValueOperation(
       loc, alloc, LoadOwnershipQualifier::Take);
@@ -176,9 +177,10 @@ SILValue TangentBuilder::emitAdd(SILLocation loc, SILValue lhs, SILValue rhs) {
   auto lhsCopy = emitCopyValueOperation(loc, lhs);
   auto rhsCopy = emitCopyValueOperation(loc, rhs);
   // Allocate buffers for inputs and output.
-  auto *resultBuf = createAllocStack(loc, type);
-  auto *lhsBuf = createAllocStack(loc, type);
-  auto *rhsBuf = createAllocStack(loc, type);
+  auto tempAllocLoc = RegularLocation::getAutoGeneratedLocation();
+  auto *resultBuf = createAllocStack(tempAllocLoc, type);
+  auto *lhsBuf = createAllocStack(tempAllocLoc, type);
+  auto *rhsBuf = createAllocStack(tempAllocLoc, type);
   // Initialize input buffers.
   emitStoreValueOperation(loc, lhsCopy, lhsBuf,
                           StoreOwnershipQualifier::Init);
diff --git a/test/AutoDiff/compiler_crashers_fixed/sr15566-vardecl-adjoint-values.swift b/test/AutoDiff/compiler_crashers_fixed/sr15566-vardecl-adjoint-values.swift
new file mode 100644
index 0000000000000..473811a0b80da
--- /dev/null
+++ b/test/AutoDiff/compiler_crashers_fixed/sr15566-vardecl-adjoint-values.swift
@@ -0,0 +1,20 @@
+// RUN: %target-build-swift %s
+// RUN: %target-swift-frontend -c -g -Xllvm -verify-di-holes=true %s
+
+// SR-15566: Differentiable functions with control flow yield an assertion failure: "location is a VarDecl, but SILDebugVariable is empty"
+
+import _Differentiation
+
+public struct Test: Differentiable {
+  public var v1: [[Float]]
+
+  @differentiable(reverse)
+  public init(v1: [[Float]]) {
+    if v1.count != 2 {
+      fatalError("Mismatched counts")
+    }
+    self.v1 = v1
+  }
+}
+
+// Assertion failed: ((!dyn_cast_or_null<VarDecl>(Loc.getAsASTNode<Decl>()) || Var) && "location is a VarDecl, but SILDebugVariable is empty"), function createAllocStack, file SILBuilder.h, line 389.
diff --git a/test/AutoDiff/validation-test/array.swift b/test/AutoDiff/validation-test/array.swift
index f84d6f315838a..c756bac3dbf4b 100644
--- a/test/AutoDiff/validation-test/array.swift
+++ b/test/AutoDiff/validation-test/array.swift
@@ -1,4 +1,4 @@
-// RUN: %target-run-simple-swift(-Xfrontend -enable-lexical-borrow-scopes=false)
+// RUN: %target-run-simple-swift
 
 // REQUIRES: executable_test
 
diff --git a/test/AutoDiff/validation-test/optional.swift b/test/AutoDiff/validation-test/optional.swift
index 4a10255867a76..6bbe8dee2b1f6 100644
--- a/test/AutoDiff/validation-test/optional.swift
+++ b/test/AutoDiff/validation-test/optional.swift
@@ -1,4 +1,4 @@
-// RUN: %target-run-simple-swift(-Xfrontend -enable-lexical-borrow-scopes=false)
+// RUN: %target-run-simple-swift
 
 // REQUIRES: executable_test
 
diff --git a/test/AutoDiff/validation-test/optional_property.swift b/test/AutoDiff/validation-test/optional_property.swift
index 8bf5eafe3cdf5..a28bdaf868df6 100644
--- a/test/AutoDiff/validation-test/optional_property.swift
+++ b/test/AutoDiff/validation-test/optional_property.swift
@@ -1,5 +1,5 @@
-// RUN: %target-run-simple-swift(-Xfrontend -enable-lexical-borrow-scopes=false)
-// RUN: %target-swift-emit-sil -Xllvm -debug-only=differentiation -enable-lexical-borrow-scopes=false -module-name null -o /dev/null 2>&1 %s | %FileCheck %s
+// RUN: %target-run-simple-swift
+// RUN: %target-swift-emit-sil -Xllvm -debug-only=differentiation -module-name null -o /dev/null 2>&1 %s | %FileCheck %s
 
 // REQUIRES: executable_test
 // REQUIRES: asserts