@@ -1139,6 +1139,7 @@ static QualType GetDerivedFunctionType(const CallExpr* CE) {
11391139 return true ;
11401140
11411141 bool nonDiff = false ;
1142+ bool hasNoMemoryInputForPointerOrRefReturn = false ;
11421143 // FIXME: We might want to support nested calls to differentiate/gradient
11431144 // inside differentiated functions.
11441145 if (!m_TopMostReq) {
@@ -1221,10 +1222,13 @@ static QualType GetDerivedFunctionType(const CallExpr* CE) {
12211222 if (!(MD && MD ->isInstance ()) && !hasPointerOrRefReturn &&
12221223 allArgumentsAreLiterals (E->arguments (), m_ParentReq))
12231224 nonDiff = true ;
1224- // In the reverse mode, such functions don't have dfdx()
1225- if (!utils::hasMemoryTypeParams (FD ) && hasPointerOrRefReturn &&
1226- m_TopMostReq->Mode == DiffMode::reverse)
1227- nonDiff = true ;
1225+ // In reverse mode, calls without memory parameters normally have no
1226+ // adjoint destination for a pointer or reference return. Defer the final
1227+ // decision for instance calls until custom derivatives are known because
1228+ // their implicit object can carry the adjoint.
1229+ hasNoMemoryInputForPointerOrRefReturn =
1230+ !utils::hasMemoryTypeParams (FD ) && hasPointerOrRefReturn &&
1231+ m_TopMostReq->Mode == DiffMode::reverse;
12281232 // Skip reverse-mode scheduling for integral-return helper calls that
12291233 // cannot accumulate through memory arguments. Keep this narrow to avoid
12301234 // suppressing diagnostics on variadic/non-helper calls.
@@ -1371,7 +1375,36 @@ static QualType GetDerivedFunctionType(const CallExpr* CE) {
13711375 E->getDirectCallee ();
13721376 bool shouldUseRestoreTracker =
13731377 utils::shouldUseRestoreTracker (request.Function );
1374- if (!(LookupCustomDerivativeDecl (request) || nonDiff) || requestTBR) {
1378+ bool hasCustomPullback = LookupCustomDerivativeDecl (request);
1379+ // Share one request between early classification and final scheduling.
1380+ DiffRequest forwPassRequest;
1381+ if (request.Mode == DiffMode::pullback) {
1382+ forwPassRequest.Function = request.Function ;
1383+ forwPassRequest.BaseFunctionName = request.BaseFunctionName ;
1384+ forwPassRequest.Mode = DiffMode::reverse_mode_forward_pass;
1385+ forwPassRequest.CallContext = request.CallContext ;
1386+ forwPassRequest.UseRestoreTracker = shouldUseRestoreTracker;
1387+ }
1388+
1389+ if (hasNoMemoryInputForPointerOrRefReturn) {
1390+ const auto * calledMethod = dyn_cast<CXXMethodDecl>(FD );
1391+ bool isRefReturningInstanceCall =
1392+ request.Mode == DiffMode::pullback && calledMethod &&
1393+ calledMethod->isInstance () &&
1394+ utils::isNonConstReferenceType (request->getReturnType ());
1395+ bool hasCustomReverseForw = false ;
1396+ if (isRefReturningInstanceCall)
1397+ hasCustomReverseForw = LookupCustomDerivativeDecl (forwPassRequest);
1398+
1399+ // A reverse_forw still needs a matching pullback. Preserve the existing
1400+ // forward-only contract only when a custom reverse_forw has no custom
1401+ // pullback, as with smart-pointer and reference-wrapper helpers.
1402+ if (!isRefReturningInstanceCall ||
1403+ (hasCustomReverseForw && !hasCustomPullback))
1404+ nonDiff = true ;
1405+ }
1406+
1407+ if (!(hasCustomPullback || nonDiff) || requestTBR) {
13751408 clang::CFG ::BuildOptions Options;
13761409 std::unique_ptr<AnalysisDeclContext> AnalysisDC =
13771410 std::make_unique<AnalysisDeclContext>(
@@ -1445,14 +1478,10 @@ static QualType GetDerivedFunctionType(const CallExpr* CE) {
14451478 }
14461479
14471480 if (request.Mode == DiffMode::pullback) {
1448- DiffRequest forwPassRequest;
1449- forwPassRequest.Function = request.Function ;
1450- forwPassRequest.BaseFunctionName = request.BaseFunctionName ;
1451- forwPassRequest.Mode = DiffMode::reverse_mode_forward_pass;
1452- forwPassRequest.CallContext = request.CallContext ;
1481+ // TBR can prove that no state needs restoring, so refresh this before
1482+ // scheduling the request.
14531483 forwPassRequest.UseRestoreTracker = shouldUseRestoreTracker;
14541484 QualType returnType = request->getReturnType ();
1455- bool hasCustomPullback = request.CustomDerivative != nullptr ;
14561485 bool hasCustomReverseForw = LookupCustomDerivativeDecl (forwPassRequest);
14571486
14581487 if (hasCustomReverseForw ||
0 commit comments