66#include " clad/Differentiator/ReverseModeVisitor.h"
77
88#include " clang/AST/Decl.h"
9+ #include " clang/AST/DeclarationName.h"
910#include " clang/AST/Expr.h"
1011#include " clang/AST/OperationKinds.h"
12+ #include " clang/AST/Type.h"
1113#include " clang/Basic/LLVM.h"
14+ #include " clang/Sema/DeclSpec.h"
15+ #include " clang/Sema/Lookup.h"
16+ #include " clang/Sema/TemplateDeduction.h"
1217
13- #include < llvm/ADT/STLExtras.h>
14- #include < llvm/ADT/SmallVector.h>
18+ #include " llvm/ADT/STLExtras.h"
19+ #include " llvm/ADT/SmallVector.h"
20+
21+ #include < limits>
22+ #include < string>
1523
1624using namespace clang ;
1725
@@ -26,11 +34,6 @@ QualType getUnderlyingArrayType(QualType baseType, ASTContext& C) {
2634 return baseType;
2735}
2836
29- void ErrorEstimationHandler::SetErrorEstimationModel (
30- FPErrorEstimationModel* estModel) {
31- m_EstModel = estModel;
32- }
33-
3437DeclRefExpr* ErrorEstimationHandler::BuildFinalErrorExpr () {
3538 return m_RMV->BuildDeclRef (m_Params->back ());
3639}
@@ -42,8 +45,7 @@ void ErrorEstimationHandler::BuildReturnErrorStmt() {
4245 auto flitr =
4346 FloatingLiteral::Create (m_RMV->m_Context , llvm::APFloat (1.0 ), true ,
4447 m_RMV->m_Context .DoubleTy , noLoc);
45- Expr* finExpr =
46- m_EstModel->AssignError (StmtDiff (m_RetErrorExpr, flitr), " return_expr" );
48+ Expr* finExpr = AssignError (StmtDiff (m_RetErrorExpr, flitr), " return_expr" );
4749 m_RMV->addToCurrentBlock (
4850 m_RMV->BuildOp (BO_AddAssign, BuildFinalErrorExpr (), finExpr),
4951 direction::forward);
@@ -102,9 +104,9 @@ void ErrorEstimationHandler::EmitNestedFunctionParamError(
102104 // if (utils::IsReferenceOrPointerType(fnDecl->getParamDecl(i)->getType()))
103105 // continue;
104106 auto * derefExpr = m_RMV->BuildOp (UO_Deref, ArgResult[i]);
105- Expr* errorExpr = m_EstModel-> AssignError (
106- {derivedCallArgs[i], derefExpr},
107- fnDecl-> getNameInfo (). getAsString () + " _param_" + std::to_string (i));
107+ Expr* errorExpr = AssignError ({derivedCallArgs[i], derefExpr},
108+ fnDecl-> getNameInfo (). getAsString () +
109+ " _param_" + std::to_string (i));
108110 Expr* FinalError = BuildFinalErrorExpr ();
109111 Expr* errorStmt = m_RMV->BuildOp (BO_AddAssign, FinalError, errorExpr);
110112 m_ReverseErrorStmts.push_back (errorStmt);
@@ -265,6 +267,7 @@ void ErrorEstimationHandler::EmitDeclErrorStmts(DeclDiff<VarDecl> VDDiff,
265267
266268void ErrorEstimationHandler::InitialiseRMV (ReverseModeVisitor& RMV ) {
267269 m_RMV = &RMV ;
270+ LookupCustomErrorFunction ();
268271}
269272
270273void ErrorEstimationHandler::ForgetRMV () { m_RMV = nullptr ; }
@@ -333,7 +336,7 @@ void ErrorEstimationHandler::ActAfterProcessingArraySubscriptExpr(
333336 m_RMV->m_Sema .ImpCastExprToType (idx, size->getType (), CK_IntegralCast)
334337 .get ();
335338 llvm::SmallVector<clang::Expr*, 2 > args{size, idx};
336- Expr* extendedSize = m_EstModel ->GetFunctionCall (" max" , " std" , args);
339+ Expr* extendedSize = m_RMV ->GetFunctionCall (" max" , " std" , args);
337340 size = m_RMV->Clone (size);
338341 Stmt* updateSize = m_RMV->BuildOp (BO_Assign, size, extendedSize);
339342 m_RMV->addToCurrentBlock (updateSize, direction::reverse);
@@ -450,6 +453,77 @@ void ErrorEstimationHandler::ActBeforeDifferentiatingCallExpr(
450453 pullbackArgs.push_back (BuildFinalErrorExpr ());
451454}
452455
456+ void ErrorEstimationHandler::LookupCustomErrorFunction () {
457+ Sema& S = m_RMV->m_Sema ;
458+ ASTContext& C = m_RMV->m_Context ;
459+ NamespaceDecl* cladNS = utils::LookupNSD (S, " clad" , /* shouldExist=*/ true );
460+ IdentifierInfo* II = &C.Idents .get (" getErrorVal" );
461+ DeclarationNameInfo DNInfo (DeclarationName (II ), utils::GetValidSLoc (S));
462+ LookupResult R (S, DNInfo, Sema::LookupOrdinaryName);
463+ S.LookupQualifiedName (R, cladNS);
464+ if (R.empty ())
465+ return ;
466+
467+ FunctionProtoType::ExtProtoInfo EPI ;
468+ QualType ConstCharPtr = C.getPointerType (C.getConstType (C.CharTy ));
469+ QualType DoubleTy = C.DoubleTy ;
470+ llvm::SmallVector<QualType, 3 > FnTypes = {DoubleTy, DoubleTy, ConstCharPtr};
471+ QualType FnTy = C.getFunctionType (DoubleTy, FnTypes, EPI );
472+ TemplateSpecCandidateSet FailedCandidates (utils::GetValidSLoc (S),
473+ /* ForTakingAddress=*/ false );
474+ if (utils::MatchOverloadType (S, FnTy, R, FailedCandidates)) {
475+ // FIXME: MatchOverloadType returns an overload expr without the `clad::`
476+ // namespace specifier. Here, we rebuild manually.
477+ CXXScopeSpec SS ;
478+ SS .Extend (C, cladNS, noLoc, noLoc);
479+ m_CustomErrorFunction =
480+ S.BuildDeclarationNameExpr (SS , R, /* ADL=*/ false ).get ();
481+ return ;
482+ }
483+
484+ // We did not match the found candidates. Warn and offer the user hints.
485+ auto errId = S.Diags .getCustomDiagID (
486+ DiagnosticsEngine::Error,
487+ " user-defined derivative error function was provided but not used; "
488+ " expected signature %0 does not match" );
489+ S.Diag (m_RMV->m_DiffReq ->getLocation (), errId) << FnTy;
490+ FailedCandidates.NoteCandidates (S, utils::GetValidSLoc (S));
491+ utils::DiagnoseSignatureMismatch (S, FnTy, R);
492+ }
493+
494+ Expr* ErrorEstimationHandler::AssignError (StmtDiff refExpr,
495+ const std::string& varName) {
496+ Sema& S = m_RMV->m_Sema ;
497+ ASTContext& C = m_RMV->m_Context ;
498+ if (m_CustomErrorFunction) {
499+ llvm::SmallVector<clang::Expr*, 3 > callParams{
500+ refExpr.getExpr_dx (), refExpr.getExpr (),
501+ clad::utils::CreateStringLiteral (C, varName)};
502+ return S
503+ .ActOnCallExpr (m_RMV->getCurrentScope (), m_CustomErrorFunction, noLoc,
504+ callParams, noLoc)
505+ .get ();
506+ }
507+ // Get the machine epsilon value.
508+ double val = std::numeric_limits<float >::epsilon ();
509+ // Convert it into a floating point literal clang::Expr.
510+ Expr* epsExpr =
511+ FloatingLiteral::Create (C, llvm::APFloat (val), true , C.DoubleTy , noLoc);
512+ // Here, we first build a multiplication operation for the following:
513+ // refExpr * <--floating point literal (i.e. machine dependent constant)-->
514+ // Build another multiplication operation with above and the derivative
515+ Expr* errExpr =
516+ m_RMV->BuildOp (BO_Mul, refExpr.getExpr_dx (),
517+ m_RMV->BuildOp (BO_Mul, refExpr.getExpr (), epsExpr));
518+ // Next, build a llvm vector-like container to store the parameters
519+ // of the function call.
520+ llvm::SmallVector<Expr*, 1 > params{errExpr};
521+ // Finally, build a call to std::abs
522+ Expr* absExpr = m_RMV->GetFunctionCall (" abs" , " std" , params);
523+ // Return the built error expression.
524+ return absExpr;
525+ }
526+
453527void ErrorEstimationHandler::ActBeforeFinalizingVisitDeclStmt (
454528 llvm::SmallVectorImpl<Decl*>& decls,
455529 llvm::SmallVectorImpl<Decl*>& declsDiff) {
0 commit comments