// RUN: %clang++ -std=c++11 -fno-exceptions -ffast-math -O1 %s -S -emit-llvm -o - | %opt - %loadEnzyme -enzyme -S | %lli -
// RUN: %clang++ -std=c++11 -fno-exceptions -ffast-math -O2 %s -S -emit-llvm -o - | %opt - %loadEnzyme -enzyme -S | %lli -
// RUN: %clang++ -std=c++11 -fno-exceptions -ffast-math -O3 %s -S -emit-llvm -o - | %opt - %loadEnzyme -enzyme -S | %lli -
// RUN: %clang++ -std=c++11 -fno-exceptions -ffast-math -O1 %s -S -emit-llvm -o - | %opt - %loadEnzyme -enzyme -enzyme-inline=1 -S | %lli -
// RUN: %clang++ -std=c++11 -fno-exceptions -ffast-math -O2 %s -S -emit-llvm -o - | %opt - %loadEnzyme -enzyme -enzyme-inline=1 -S | %lli -
// RUN: %clang++ -std=c++11 -fno-exceptions -ffast-math -O3 %s -S -emit-llvm -o - | %opt - %loadEnzyme -enzyme -enzyme-inline=1 -S | %lli -

#include <stdio.h>
#include "object1.h"
#include "object2.h"

// void __enzyme_autodiff(...) __attribute__((weak));

template <typename... Args>
double __enzyme_autodiff(void *, Args...) __attribute__((weak));

int enzyme_dup, enzyme_const, enzyme_out, enzyme_dupnoneed;

double eval(Object &o, double v)
{
    return o.eval(v).sum();
}

double deval(Object &o, Object &d_o, double v)
{
    return __enzyme_autodiff((void *)(eval),
                             enzyme_dup, &o, &d_o,
                             v);
}

template <typename T>
T __enzyme_virtualreverse(T) __attribute__((weak));

int main()
{
    double v = 10;
    Object *o = new Object1();
    Object *d_o = new Object1();
    *((void **)d_o) = __enzyme_virtualreverse(*(void **)d_o);
    // d_o->val = 0;
    // double res;
    deval(*o, *d_o, v);
    // printf("res=%f\n", res);

    // o = new Object2();
    // // o->val = 2;
    // d_o = new Object2();
    // *((void **)d_o) = __enzyme_virtualreverse(*(void **)d_o);
    // // d_o->val = 0;
    // res = deval(*o, *d_o, v);
    // printf("res=%f\n", res);
}