Skip to content

Commit 295d138

Browse files
MdSaifAliMollavgvassilev
authored andcommitted
Allow redefining builtin custom derivatives
Lookup now prioritizes custom_derivatives::overrides and falls back to builtin only when no overrides declaration exists. Overrides mismatch suppresses fallback to throw user errors. Closes: #1376.
1 parent f5ea6e8 commit 295d138

2 files changed

Lines changed: 75 additions & 14 deletions

File tree

lib/Differentiator/DiffPlanner.cpp

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -978,15 +978,18 @@ static QualType GetDerivedFunctionType(const CallExpr* CE) {
978978
});
979979
}
980980

981-
static Expr* getOverloadExpr(Sema& S, DeclContext* DC, DiffRequest& R) {
981+
static Expr* getOverloadExpr(Sema& S, DeclContext* DC, DiffRequest& R,
982+
bool* foundAnyDecl = nullptr) {
983+
if (foundAnyDecl)
984+
*foundAnyDecl = false;
982985
// Error estimation only uses forward mode derivatives if they are
983986
// user-prodived to handle builtin derivatives. If found, we have to change
984987
// the mode of the request.
985988
if (R.EnableErrorEstimation && R.Mode == DiffMode::pullback &&
986989
utils::canUsePushforwardInRevMode(R.Function)) {
987990
R.Mode = DiffMode::pushforward;
988991
R.EnableErrorEstimation = false;
989-
if (Expr* overload = getOverloadExpr(S, DC, R)) {
992+
if (Expr* overload = getOverloadExpr(S, DC, R, foundAnyDecl)) {
990993
R.DVI.clear();
991994
return overload;
992995
}
@@ -1026,6 +1029,9 @@ static QualType GetDerivedFunctionType(const CallExpr* CE) {
10261029
if (Found.empty())
10271030
return nullptr; // Nothing found.
10281031

1032+
if (foundAnyDecl)
1033+
*foundAnyDecl = true;
1034+
10291035
TemplateSpecCandidateSet FailedCandidates(R.CallContext->getBeginLoc(),
10301036
/*ForTakingAddress=*/false);
10311037
if (Expr* overload =
@@ -1078,21 +1084,43 @@ static QualType GetDerivedFunctionType(const CallExpr* CE) {
10781084
}
10791085
} else
10801086
fnDecl = request.Function;
1081-
DeclContext* DC = customDerNS;
1082-
1083-
if (isa<CXXMethodDecl>(fnDecl))
1084-
DC = utils::LookupNSD(m_Sema, "class_functions", /*shouldExist=*/false,
1085-
DC);
1086-
else
1087-
DC = utils::FindDeclContext(m_Sema, DC, fnDecl->getDeclContext());
1088-
1089-
if (!DC)
1090-
return false;
1091-
10921087
assert(request.Mode != DiffMode::unknown &&
10931088
"Called lookup without specified DiffMode");
10941089

1095-
if (Expr* overload = getOverloadExpr(m_Sema, DC, request)) {
1090+
auto LookupOverload = [this, fnDecl, &request](NamespaceDecl* NSD,
1091+
bool* foundAnyDecl) {
1092+
DeclContext* DC = NSD;
1093+
if (isa<CXXMethodDecl>(fnDecl))
1094+
DC = utils::LookupNSD(m_Sema, "class_functions",
1095+
/*shouldExist=*/false, DC);
1096+
else
1097+
DC = utils::FindDeclContext(m_Sema, DC, fnDecl->getDeclContext());
1098+
if (!DC)
1099+
return static_cast<Expr*>(nullptr);
1100+
return getOverloadExpr(m_Sema, DC, request, foundAnyDecl);
1101+
};
1102+
1103+
// Look for the user overrides namespace nested inside custom_derivatives
1104+
NamespaceDecl* overridesNS = utils::LookupNSD(
1105+
m_Sema, "overrides", /*shouldExist=*/false, customDerNS);
1106+
1107+
// clad::custom_derivatives::overrides (user overrides, higher priority).
1108+
bool foundOverridesDecl = false;
1109+
if (overridesNS) {
1110+
if (Expr* overload = LookupOverload(overridesNS, &foundOverridesDecl)) {
1111+
// Overload found. Mark the request as custom derivative overrides and
1112+
// save the set of overloads to process later.
1113+
request.CustomDerivative = overload;
1114+
return true;
1115+
}
1116+
// Overrides declaration found but signature mismatch; do not fall back to
1117+
// builtin.
1118+
if (foundOverridesDecl)
1119+
return false;
1120+
}
1121+
1122+
// clad::custom_derivatives (builtins, fallback).
1123+
if (Expr* overload = LookupOverload(customDerNS, nullptr)) {
10961124
// Overload found. Mark the request as custom derivative and save
10971125
// the set of overloads to process later.
10981126
request.CustomDerivative = overload;

test/Regressions/issue-1376.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %cladclang -I%S/../../include %s -o %t 2>&1 | %filecheck %s
2+
// RUN: %t | %filecheck_exec %s
3+
4+
#include "clad/Differentiator/Differentiator.h"
5+
6+
extern "C" int printf(const char*, ...);
7+
8+
namespace clad::custom_derivatives::overrides::std {
9+
template <typename T, typename dT>
10+
CUDA_HOST_DEVICE ValueAndPushforward<T, dT> exp_pushforward(T x, dT d_x) {
11+
return {::std::exp(x), 2 * ::std::exp(x) * d_x};
12+
}
13+
}
14+
double differentiable_code(double x) {
15+
return std::exp(x);
16+
}
17+
18+
// CHECK: void differentiable_code_grad(double x, double *_d_x) {
19+
// CHECK-NEXT: {
20+
// CHECK-NEXT: double _r0 = 0.;
21+
// CHECK-NEXT: _r0 += 1 * clad::custom_derivatives::overrides::std::exp_pushforward(x, 1.).pushforward;
22+
// CHECK-NEXT: *_d_x += _r0;
23+
// CHECK-NEXT: }
24+
// CHECK-NEXT: }
25+
26+
int main() {
27+
auto df = clad::gradient(differentiable_code);
28+
df.dump();
29+
double x = 1.0, d_x = 0;
30+
df.execute(x, &d_x);
31+
printf("d_x = %.5f\n", d_x);
32+
// CHECK-EXEC: d_x = 5.43656
33+
}

0 commit comments

Comments
 (0)