diff --git a/include/clad/Differentiator/Differentiator.h b/include/clad/Differentiator/Differentiator.h index c8aaaa286..e8537700b 100644 --- a/include/clad/Differentiator/Differentiator.h +++ b/include/clad/Differentiator/Differentiator.h @@ -21,8 +21,10 @@ #include "Tape.h" #include -#include +#include #include +#include +#include namespace clad { @@ -82,23 +84,57 @@ CUDA_HOST_DEVICE T push(tape& to, ArgsT... val) { } /// The purpose of this function is to initialize adjoints - /// (or all of its differentiable fields) with 0. - // FIXME: Add support for objects. - /// Initialize a non-array variable. - template CUDA_HOST_DEVICE void zero_init(T& x) { new (&x) T(); } + /// (or all of its iteratable elements) with 0. + namespace zero_init_detail { + template struct iterator_traits : std::iterator_traits {}; + template <> struct iterator_traits {}; + template <> struct iterator_traits {}; + + template + std::integral_constant< + bool, !std::is_same::type, + typename iterator_traits::value_type>::value> + is_range_check(It first, It last); + + template + decltype(is_range_check(std::begin(std::declval()), + std::end(std::declval()))) + is_range(int); + template std::false_type is_range(...); + } // namespace zero_init_detail + + template + struct is_range : decltype(zero_init_detail::is_range(0)) {}; + + template void zero_init(T& t); + + template ::value, int>::type = 0> + void zero_impl(volatile T& t) { + // Fill an array with zeros. + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays) + unsigned char tmp[sizeof(T)] = {}; + // Transfer the zeros with the magic function memcpy which can implicitly + // create objects in the destination region of storage immediately prior to + // copying the sequence of characters to the destination [27.5.1(3)]. + // (C++ has deprecated the volatile qualifiers. However, we drop them here + // to make sure things still work with codebases which still have them) + std::memcpy(const_cast(&t), tmp, sizeof(T)); + } - /// Initialize a non-const sized array when the size is known and is equal to - /// N. - template CUDA_HOST_DEVICE void zero_init(T* x, std::size_t N) { - for (std::size_t i = 0; i < N; ++i) - zero_init(x[i]); + template ::value, int>::type = 0> + void zero_impl(T& t) { + for (auto& x : t) + zero_init(x); } + template void zero_init(T& t) { zero_impl(t); } + /// Initialize a const sized array. // NOLINTBEGIN(cppcoreguidelines-avoid-c-arrays) - template - CUDA_HOST_DEVICE void zero_init(T (&arr)[N]) { - zero_init((T*)arr, N); + template CUDA_HOST_DEVICE void zero_init(T* x, std::size_t N) { + for (std::size_t i = 0; i < N; ++i) + zero_init(x[i]); } // NOLINTEND(cppcoreguidelines-avoid-c-arrays) diff --git a/include/clad/Differentiator/STLBuiltins.h b/include/clad/Differentiator/STLBuiltins.h index d6b169ec0..ce3fce0ab 100644 --- a/include/clad/Differentiator/STLBuiltins.h +++ b/include/clad/Differentiator/STLBuiltins.h @@ -451,18 +451,6 @@ void at_pullback(::std::vector* vec, (*d_vec)[idx] += d_y; } -template -::clad::ValueAndAdjoint<::std::vector, ::std::vector> -constructor_reverse_forw(::clad::ConstructorReverseForwTag<::std::vector>, - S count, U val, - typename ::std::vector::allocator_type alloc, - S d_count, U d_val, - typename ::std::vector::allocator_type d_alloc) { - ::std::vector v(count, val); - ::std::vector d_v(count, 0); - return {v, d_v}; -} - template void constructor_pullback(::std::vector* v, S count, U val, typename ::std::vector::allocator_type alloc, diff --git a/lib/Differentiator/ReverseModeVisitor.cpp b/lib/Differentiator/ReverseModeVisitor.cpp index 6db6ee915..541190c1b 100644 --- a/lib/Differentiator/ReverseModeVisitor.cpp +++ b/lib/Differentiator/ReverseModeVisitor.cpp @@ -21,6 +21,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/Stmt.h" #include "clang/AST/TemplateBase.h" +#include "clang/AST/Type.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TokenKinds.h" #include "clang/Sema/Lookup.h" @@ -32,6 +33,7 @@ #include #include #include +#include #include #include "llvm/ADT/SmallString.h" @@ -2762,6 +2764,9 @@ Expr* getArraySizeExpr(const ArrayType* AT, ASTContext& context, bool isConstructInit = VD->getInit() && isa(VD->getInit()->IgnoreImplicit()); + const CXXRecordDecl* RD = VD->getType()->getAsCXXRecordDecl(); + bool isNonAggrClass = RD && !RD->isAggregate(); + bool emptyInitListInit = isNonAggrClass; // VDDerivedInit now serves two purposes -- as the initial derivative value // or the size of the derivative array -- depending on the primal type. @@ -2814,8 +2819,10 @@ Expr* getArraySizeExpr(const ArrayType* AT, ASTContext& context, m_TrackConstructorPullbackInfo = false; constructorPullbackInfo = getConstructorPullbackCallInfo(); resetConstructorPullbackCallInfo(); - if (initDiff.getForwSweepExpr_dx()) + if (initDiff.getForwSweepExpr_dx()) { VDDerivedInit = initDiff.getForwSweepExpr_dx(); + emptyInitListInit = false; + } } // FIXME: Remove the special cases introduced by `specialThisDiffCase` @@ -2864,7 +2871,7 @@ Expr* getArraySizeExpr(const ArrayType* AT, ASTContext& context, BuildGlobalVarDecl(VDDerivedType, "_d_" + VD->getNameAsString(), VDDerivedInit, false, nullptr, VD->getInitStyle()); - if (!m_DiffReq.shouldHaveAdjoint((VD))) + if (!m_DiffReq.shouldHaveAdjoint(VD)) VDDerived = nullptr; // If `VD` is a reference to a local variable, then it is already @@ -2899,11 +2906,11 @@ Expr* getArraySizeExpr(const ArrayType* AT, ASTContext& context, if (VDDerived && isInsideLoop) { Stmt* assignToZero = nullptr; Expr* declRef = BuildDeclRef(VDDerived); - if (!isa(VDDerivedType)) + if (isa(VDDerivedType) || isNonAggrClass) + assignToZero = GetCladZeroInit(declRef); + else assignToZero = BuildOp(BinaryOperatorKind::BO_Assign, declRef, getZeroInit(VDDerivedType)); - else - assignToZero = GetCladZeroInit(declRef); if (!keepLocal) addToCurrentBlock(assignToZero, direction::reverse); } @@ -2946,6 +2953,43 @@ Expr* getArraySizeExpr(const ArrayType* AT, ASTContext& context, VDClone = BuildGlobalVarDecl(VDCloneType, VD->getNameAsString(), initDiff.getExpr(), VD->isDirectInit(), nullptr, VD->getInitStyle()); + + // We initialize adjoints with original variables as part of + // the strategy to maintain the structure of the original variable. + // After that, we'll zero-initialize the adjoint. e.g. + // ``` + // std::vector<...> v{x, y, z}; + // std::vector<...> _d_v{v}; // The length of the vector is preserved + // clad::zero_init(_d_v); + // ``` + // Also, if the original is initialized with a zero-constructor, it can be + // used for the adjoint as well. + if (isConstructInit && emptyInitListInit && + cast(VD->getInit()->IgnoreImplicit())->getNumArgs() != + 0) { + Expr* copyExpr = BuildDeclRef(VDClone); + QualType origTy = VDClone->getType(); + // if VDClone is volatile, we have to use const_cast to be able to use + // most copy constructors. + if (origTy.isVolatileQualified()) { + Qualifiers quals(origTy.getQualifiers()); + quals.removeVolatile(); + QualType castTy = m_Sema.BuildQualifiedType(origTy.getUnqualifiedType(), + noLoc, quals); + castTy = m_Context.getLValueReferenceType(castTy); + SourceRange range = utils::GetValidSRange(m_Sema); + copyExpr = + m_Sema + .BuildCXXNamedCast(noLoc, tok::kw_const_cast, + m_Context.getTrivialTypeSourceInfo( + castTy, utils::GetValidSLoc(m_Sema)), + copyExpr, range, range) + .get(); + } + m_Sema.AddInitializerToDecl(VDDerived, copyExpr, /*DirectInit=*/true); + VDDerived->setInitStyle(VarDecl::InitializationStyle::CallInit); + } + if (isPointerType && derivedVDE) { if (promoteToFnScope) { Expr* assignDerivativeE = BuildOp(BinaryOperatorKind::BO_Assign, @@ -3055,6 +3099,7 @@ Expr* getArraySizeExpr(const ArrayType* AT, ASTContext& context, llvm::SmallVector inits; llvm::SmallVector decls; llvm::SmallVector declsDiff; + llvm::SmallVector classDeclsDiff; llvm::SmallVector memsetCalls; // Need to put array decls inlined. llvm::SmallVector localDeclsDiff; @@ -3143,9 +3188,13 @@ Expr* getArraySizeExpr(const ArrayType* AT, ASTContext& context, decls.push_back(VDDiff.getDecl()); if (VDDiff.getDecl_dx()) { + const CXXRecordDecl* RD = VD->getType()->getAsCXXRecordDecl(); + bool isNonAggrClass = RD && !RD->isAggregate(); if (isa(VD->getType())) localDeclsDiff.push_back(VDDiff.getDecl_dx()); - else { + else if (isNonAggrClass) { + classDeclsDiff.push_back(VDDiff.getDecl_dx()); + } else { VarDecl* VDDerived = VDDiff.getDecl_dx(); declsDiff.push_back(VDDerived); if (Stmt* memsetCall = CheckAndBuildCallToMemset( @@ -3220,7 +3269,43 @@ Expr* getArraySizeExpr(const ArrayType* AT, ASTContext& context, addToBlock(BuildDeclStmt(decl), m_Globals); Stmt* initAssignments = MakeCompoundStmt(inits); initAssignments = utils::unwrapIfSingleStmt(initAssignments); - return StmtDiff(initAssignments); + DSClone = initAssignments; + } + + if (!classDeclsDiff.empty()) { + Stmts& block = + promoteToFnScope ? m_Globals : getCurrentBlock(direction::forward); + addToBlock(DSClone, block); + DSClone = nullptr; + addToBlock(BuildDeclStmt(classDeclsDiff), block); + for (Decl* decl : classDeclsDiff) { + auto* vDecl = cast(decl); + Expr* init = vDecl->getInit(); + if (promoteToFnScope && init) { + auto* declRef = BuildDeclRef(vDecl); + auto* assignment = BuildOp(BO_Assign, declRef, init); + addToCurrentBlock(assignment, direction::forward); + m_Sema.AddInitializerToDecl(vDecl, /*init=*/nullptr, + /*DirectInit=*/true); + } + // Adjoints are initialized with copy-constructors only as a part of + // the strategy to maintain the structure of the original variable. + // In such cases, we need to zero-initialize the adjoint. e.g. + // ``` + // std::vector<...> v{x, y, z}; + // std::vector<...> _d_v{v}; + // clad::zero_init(_d_v); // this line is generated below + // ``` + const auto* CE = dyn_cast(init->IgnoreImplicit()); + bool copyInit = + CE && (CE->getNumArgs() == 0 || + isa(CE->getArg(0)->IgnoreImplicit())); + if (copyInit) { + std::array arg{BuildDeclRef(vDecl)}; + Stmt* initCall = GetCladZeroInit(arg); + addToCurrentBlock(initCall, direction::forward); + } + } } return StmtDiff(DSClone); diff --git a/test/Gradient/Functors.C b/test/Gradient/Functors.C index 07bac5513..b808cf6b2 100644 --- a/test/Gradient/Functors.C +++ b/test/Gradient/Functors.C @@ -222,8 +222,9 @@ int main() { // CHECK-EXEC: 54.00 42.00 // CHECK: void CallFunctor_grad(double i, double j, double *_d_i, double *_d_j) { - // CHECK-NEXT: Experiment _d_E({}); // CHECK-NEXT: Experiment E(3, 5); + // CHECK-NEXT: Experiment _d_E(E); + // CHECK-NEXT: clad::zero_init(_d_E); // CHECK-NEXT: Experiment _t0 = E; // CHECK-NEXT: { // CHECK-NEXT: double _r2 = 0.; @@ -265,8 +266,9 @@ int main() { // CHECK: void FunctorAsArg_pullback(Experiment fn, double i, double j, double _d_y, Experiment *_d_fn, double *_d_i, double *_d_j); // CHECK: void FunctorAsArgWrapper_grad(double i, double j, double *_d_i, double *_d_j) { - // CHECK-NEXT: Experiment _d_E({}); // CHECK-NEXT: Experiment E(3, 5); + // CHECK-NEXT: Experiment _d_E(E); + // CHECK-NEXT: clad::zero_init(_d_E); // CHECK-NEXT: { // CHECK-NEXT: Experiment _r2 = {}; // CHECK-NEXT: double _r3 = 0.; diff --git a/test/Gradient/MemberFunctions.C b/test/Gradient/MemberFunctions.C index 78d58ba5b..c8cb8ad1b 100644 --- a/test/Gradient/MemberFunctions.C +++ b/test/Gradient/MemberFunctions.C @@ -528,17 +528,17 @@ double fn6(double u, double v) { // CHECK-NEXT: double &_d_w = *_d_u; // CHECK-NEXT: double &w = u; // CHECK-NEXT: clad::ValueAndAdjoint _t0 = {{.*}}constructor_reverse_forw(clad::ConstructorReverseForwTag()); -// CHECK-NEXT: SafeTestClass _d_s1(_t0.adjoint); // CHECK-NEXT: SafeTestClass s1(_t0.value); +// CHECK-NEXT: SafeTestClass _d_s1(_t0.adjoint); // CHECK-NEXT: clad::ValueAndAdjoint _t1 = {{.*}}constructor_reverse_forw(clad::ConstructorReverseForwTag(), u, &v, *_d_u, &*_d_v); -// CHECK-NEXT: SafeTestClass _d_s2(_t1.adjoint); // CHECK-NEXT: SafeTestClass s2(_t1.value); +// CHECK-NEXT: SafeTestClass _d_s2(_t1.adjoint); // CHECK-NEXT: clad::ValueAndAdjoint _t2 = {{.*}}constructor_reverse_forw(clad::ConstructorReverseForwTag(), w, _d_w); +// CHECK-NEXT: SafeTestClass s3(_t2.value); // CHECK-NEXT: SafeTestClass _d_s3(_t2.adjoint); -// CHECK-NEXT: SafeTestClass s3(_t2.value); -// CHECK-NEXT: *_d_v += 1; -// CHECK-NEXT: {{.*}}constructor_pullback(&s2, u, &v, &_d_s2, &*_d_u, &*_d_v); -// CHECK-NEXT: } +// CHECK-NEXT: *_d_v += 1; +// CHECK-NEXT: {{.*}}constructor_pullback(&s2, u, &v, &_d_s2, &*_d_u, &*_d_v); +// CHECK-NEXT: } int main() { @@ -632,8 +632,9 @@ int main() { // CHECK: void fn3_grad_2_3(double x, double y, double i, double j, double *_d_i, double *_d_j) { // CHECK-NEXT: double _d_x = 0.; // CHECK-NEXT: double _d_y = 0.; -// CHECK-NEXT: SimpleFunctions _d_sf({}); // CHECK-NEXT: SimpleFunctions sf(x, y); +// CHECK-NEXT: SimpleFunctions _d_sf(sf); +// CHECK-NEXT: clad::zero_init(_d_sf); // CHECK-NEXT: SimpleFunctions _t0 = sf; // CHECK-NEXT: { // CHECK-NEXT: double _r0 = 0.; diff --git a/test/Gradient/NonDifferentiable.C b/test/Gradient/NonDifferentiable.C index 3c8162bea..c7b203335 100644 --- a/test/Gradient/NonDifferentiable.C +++ b/test/Gradient/NonDifferentiable.C @@ -23,6 +23,15 @@ public: } }; +namespace clad { + template <> void zero_init(SimpleFunctions1& f) { + f.x = 0; + f.y = 0; + f.x_pointer = &f.x; + f.y_pointer = &f.y; + } +} + double fn_s1_mem_fn(double i, double j) { SimpleFunctions1 obj(2, 3); return obj.mem_fn_1(i, j) + i * j; @@ -125,8 +134,9 @@ int main() { // CHECK: void mem_fn_1_pullback(double i, double j, double _d_y, SimpleFunctions1 *_d_this, double *_d_i, double *_d_j); // CHECK: void fn_s1_mem_fn_grad(double i, double j, double *_d_i, double *_d_j) { - // CHECK-NEXT: SimpleFunctions1 _d_obj({}); // CHECK-NEXT: SimpleFunctions1 obj(2, 3); + // CHECK-NEXT: SimpleFunctions1 _d_obj(obj); + // CHECK-NEXT: clad::zero_init(_d_obj); // CHECK-NEXT: SimpleFunctions1 _t0 = obj; // CHECK-NEXT: { // CHECK-NEXT: double _r2 = 0.; @@ -144,8 +154,9 @@ int main() { // CHECK-NEXT: } // CHECK: void fn_s1_field_grad(double i, double j, double *_d_i, double *_d_j) { - // CHECK-NEXT: SimpleFunctions1 _d_obj({}); // CHECK-NEXT: SimpleFunctions1 obj(2, 3); + // CHECK-NEXT: SimpleFunctions1 _d_obj(obj); + // CHECK-NEXT: clad::zero_init(_d_obj); // CHECK-NEXT: { // CHECK-NEXT: _d_obj.x += 1 * obj.y; // CHECK-NEXT: *_d_i += 1 * j; @@ -158,8 +169,9 @@ int main() { // CHECK-NEXT: } // CHECK: void fn_s1_field_pointer_grad(double i, double j, double *_d_i, double *_d_j) { - // CHECK-NEXT: SimpleFunctions1 _d_obj({}); // CHECK-NEXT: SimpleFunctions1 obj(2, 3); + // CHECK-NEXT: SimpleFunctions1 _d_obj(obj); + // CHECK-NEXT: clad::zero_init(_d_obj); // CHECK-NEXT: { // CHECK-NEXT: *_d_obj.x_pointer += 1 * *obj.y_pointer; // CHECK-NEXT: *_d_i += 1 * j; diff --git a/test/Gradient/STLCustomDerivatives.C b/test/Gradient/STLCustomDerivatives.C index f480bcce6..187986daf 100644 --- a/test/Gradient/STLCustomDerivatives.C +++ b/test/Gradient/STLCustomDerivatives.C @@ -214,8 +214,9 @@ int main() { } // CHECK: void fn10_grad(double u, double v, double *_d_u, double *_d_v) { -// CHECK-NEXT: std::vector _d_vec({}); // CHECK-NEXT: std::vector vec; +// CHECK-NEXT: std::vector _d_vec({}); +// CHECK-NEXT: clad::zero_init(_d_vec); // CHECK-NEXT: std::vector _t0 = vec; // CHECK-NEXT: {{.*}}class_functions::push_back_reverse_forw(&vec, u, &_d_vec, *_d_u); // CHECK-NEXT: std::vector _t1 = vec; @@ -235,8 +236,9 @@ int main() { // CHECK-NEXT: } // CHECK-NEXT: void fn11_grad(double u, double v, double *_d_u, double *_d_v) { -// CHECK-NEXT: std::vector _d_vec({}); // CHECK-NEXT: std::vector vec; +// CHECK-NEXT: std::vector _d_vec({}); +// CHECK-NEXT: clad::zero_init(_d_vec); // CHECK-NEXT: std::vector _t0 = vec; // CHECK-NEXT: {{.*}}class_functions::push_back_reverse_forw(&vec, u, &_d_vec, *_d_u); // CHECK-NEXT: std::vector _t1 = vec; @@ -293,8 +295,9 @@ int main() { // CHECK-NEXT: double _t24; // CHECK-NEXT: double _d_res = 0.; // CHECK-NEXT: double res = 0; -// CHECK-NEXT: std::vector _d_vec({}); // CHECK-NEXT: std::vector vec; +// CHECK-NEXT: std::vector _d_vec({}); +// CHECK-NEXT: clad::zero_init(_d_vec); // CHECK-NEXT: std::vector _t0 = vec; // CHECK-NEXT: {{.*}}class_functions::resize_reverse_forw(&vec, 3, &_d_vec, _r0); // CHECK-NEXT: { @@ -438,34 +441,36 @@ int main() { // CHECK-NEXT: void fn13_grad(double u, double v, double *_d_u, double *_d_v) { // CHECK-NEXT: double _d_res = 0.; // CHECK-NEXT: double res = u; -// CHECK-NEXT: {{.*}}allocator_type _d_allocator({}); // CHECK-NEXT: {{.*}}allocator_type allocator; +// CHECK-NEXT: {{.*}}allocator_type _d_allocator({}); +// CHECK-NEXT: clad::zero_init(_d_allocator); // CHECK-NEXT: {{.*}} _d_count = {{0U|0UL}}; // CHECK-NEXT: {{.*}} count = 3; -// CHECK-NEXT: {{.*}}ValueAndAdjoint<{{.*}}vector<{{.*}}>, {{.*}}vector<{{.*}}> > _t0 = {{.*}}class_functions::constructor_reverse_forw(clad::ConstructorReverseForwTag >(), count, u, allocator, _d_count, *_d_u, _d_allocator); -// CHECK-NEXT: std::vector _d_vec(_t0.adjoint); -// CHECK-NEXT: std::vector vec(_t0.value); -// CHECK-NEXT: std::vector _t1 = vec; -// CHECK-NEXT: {{.*}}ValueAndAdjoint _t2 = {{.*}}class_functions::operator_subscript_reverse_forw(&vec, 0, &_d_vec, _r0); -// CHECK-NEXT: std::vector _t3 = vec; -// CHECK-NEXT: {{.*}}ValueAndAdjoint _t4 = {{.*}}class_functions::operator_subscript_reverse_forw(&vec, 1, &_d_vec, _r1); -// CHECK-NEXT: std::vector _t5 = vec; -// CHECK-NEXT: {{.*}}ValueAndAdjoint _t6 = {{.*}}class_functions::operator_subscript_reverse_forw(&vec, 2, &_d_vec, _r2); +// CHECK-NEXT: std::vector vec(count, u, allocator); +// CHECK-NEXT: std::vector _d_vec(vec); +// CHECK-NEXT: clad::zero_init(_d_vec); +// CHECK-NEXT: std::vector _t0 = vec; +// CHECK-NEXT: {{.*}}ValueAndAdjoint _t1 = {{.*}}class_functions::operator_subscript_reverse_forw(&vec, 0, &_d_vec, _r0); +// CHECK-NEXT: std::vector _t2 = vec; +// CHECK-NEXT: {{.*}}ValueAndAdjoint _t3 = {{.*}}class_functions::operator_subscript_reverse_forw(&vec, 1, &_d_vec, _r1); +// CHECK-NEXT: std::vector _t4 = vec; +// CHECK-NEXT: {{.*}}ValueAndAdjoint _t5 = {{.*}}class_functions::operator_subscript_reverse_forw(&vec, 2, &_d_vec, _r2); // CHECK-NEXT: { // CHECK-NEXT: {{.*}} _r0 = {{0U|0UL}}; -// CHECK-NEXT: {{.*}}operator_subscript_pullback(&_t1, 0, 1, &_d_vec, &_r0); +// CHECK-NEXT: {{.*}}operator_subscript_pullback(&_t0, 0, 1, &_d_vec, &_r0); // CHECK-NEXT: {{.*}} _r1 = {{0U|0UL}}; -// CHECK-NEXT: {{.*}}operator_subscript_pullback(&_t3, 1, 1, &_d_vec, &_r1); +// CHECK-NEXT: {{.*}}operator_subscript_pullback(&_t2, 1, 1, &_d_vec, &_r1); // CHECK-NEXT: {{.*}} _r2 = {{0U|0UL}}; -// CHECK-NEXT: {{.*}}operator_subscript_pullback(&_t5, 2, 1, &_d_vec, &_r2); +// CHECK-NEXT: {{.*}}operator_subscript_pullback(&_t4, 2, 1, &_d_vec, &_r2); // CHECK-NEXT: } // CHECK-NEXT: {{.*}}constructor_pullback(&vec, count, u, allocator, &_d_vec, &_d_count, &*_d_u, &_d_allocator); // CHECK-NEXT: *_d_u += _d_res; // CHECK-NEXT: } // CHECK: void fn14_grad(double x, double y, double *_d_x, double *_d_y) { -// CHECK-NEXT: std::vector _d_a({}); // CHECK-NEXT: std::vector a; +// CHECK-NEXT: std::vector _d_a({}); +// CHECK-NEXT: clad::zero_init(_d_a); // CHECK-NEXT: std::vector _t0 = a; // CHECK-NEXT: {{.*}}push_back_reverse_forw(&a, x, &_d_a, *_d_x); // CHECK-NEXT: std::vector _t1 = a; @@ -683,8 +688,9 @@ int main() { // CHECK-NEXT: {{.*}}tape<{{.*}}vector > _t3 = {}; // CHECK-NEXT: {{.*}}tape _t4 = {}; // CHECK-NEXT: {{.*}}tape<{{.*}}vector > _t5 = {}; -// CHECK-NEXT: {{.*}}vector _d_v({}); // CHECK-NEXT: {{.*}}vector v; +// CHECK-NEXT: {{.*}}vector _d_v({}); +// CHECK-NEXT: clad::zero_init(_d_v); // CHECK-NEXT: {{.*}} _t0 = {{0U|0UL|0}}; // CHECK-NEXT: for (i = 0; ; ++i) { // CHECK-NEXT: { @@ -773,8 +779,9 @@ int main() { // CHECK-NEXT: } // CHECK: void fn20_grad(double x, double y, double *_d_x, double *_d_y) { -// CHECK-NEXT: {{.*}}vector _d_v({}); // CHECK-NEXT: {{.*}}vector v; +// CHECK-NEXT: {{.*}}vector _d_v({}); +// CHECK-NEXT: clad::zero_init(_d_v); // CHECK-NEXT: {{.*}}vector _t0 = v; // CHECK-NEXT: v.reserve(10); // CHECK-NEXT: {{.*}}vector _t2 = v; @@ -813,8 +820,9 @@ int main() { // CHECK-NEXT: } // CHECK: void fn21_grad(double x, double y, double *_d_x, double *_d_y) { -// CHECK-NEXT: std::vector _d_a({}); // CHECK-NEXT: std::vector a; +// CHECK-NEXT: std::vector _d_a({}); +// CHECK-NEXT: clad::zero_init(_d_a); // CHECK-NEXT: std::vector _t0 = a; // CHECK-NEXT: {{.*}}push_back_reverse_forw(&a, 0{{.*}}, &_d_a, _r0); // CHECK-NEXT: std::vector _t1 = a; diff --git a/test/Gradient/UserDefinedTypes.C b/test/Gradient/UserDefinedTypes.C index 9fb5b14a2..0623e8cd1 100644 --- a/test/Gradient/UserDefinedTypes.C +++ b/test/Gradient/UserDefinedTypes.C @@ -97,8 +97,9 @@ double fn3(double i, double j) { } // CHECK: void fn3_grad(double i, double j, double *_d_i, double *_d_j) { -// CHECK-NEXT: Tangent _d_t({}); // CHECK-NEXT: Tangent t; +// CHECK-NEXT: Tangent _d_t({}); +// CHECK-NEXT: clad::zero_init(_d_t); // CHECK-NEXT: double _t0 = t.data[0]; // CHECK-NEXT: t.data[0] = 2 * i; // CHECK-NEXT: double _t1 = t.data[1]; @@ -130,10 +131,12 @@ double fn4(double i, double j) { } // CHECK: void fn4_grad(double i, double j, double *_d_i, double *_d_j) { -// CHECK-NEXT: pairdd _d_p({}); // CHECK-NEXT: pairdd p(1, 3); -// CHECK-NEXT: pairdd _d_q({}); +// CHECK-NEXT: pairdd _d_p(p); +// CHECK-NEXT: clad::zero_init(_d_p); // CHECK-NEXT: pairdd q({7, 5}); +// CHECK-NEXT: pairdd _d_q(q); +// CHECK-NEXT: clad::zero_init(_d_q); // CHECK-NEXT: { // CHECK-NEXT: _d_p.first += 1 * i; // CHECK-NEXT: *_d_i += p.first * 1; @@ -370,8 +373,9 @@ double fn11(double x, double y) { } // CHECK: void fn11_grad(double x, double y, double *_d_x, double *_d_y) { -// CHECK-NEXT: Tangent _d_t({}); // CHECK-NEXT: Tangent t; +// CHECK-NEXT: Tangent _d_t({}); +// CHECK-NEXT: clad::zero_init(_d_t); // CHECK-NEXT: double _t0 = t.data[0]; // CHECK-NEXT: t.data[0] = -y; // CHECK-NEXT: operator_plus_pullback(x, t, 1, &*_d_x, &_d_t);