blob: 68ae05ba351929f0a2a638573bc8d8e051aa9b9e [file] [log] [blame] [edit]
// RUN: if [ %llvmver -ge 11 ]; then %clang++ -std=c++17 -O0 %s -S -emit-llvm -o - %loadClangEnzyme | %lli - ; fi
// RUN: if [ %llvmver -ge 11 ]; then %clang++ -std=c++17 -O1 %s -S -emit-llvm -o - %loadClangEnzyme | %lli - ; fi
// RUN: if [ %llvmver -ge 11 ]; then %clang++ -std=c++17 -O2 %s -S -emit-llvm -o - %loadClangEnzyme | %lli - ; fi
// RUN: if [ %llvmver -ge 11 ]; then %clang++ -std=c++17 -O3 %s -S -emit-llvm -o - %loadClangEnzyme | %lli - ; fi
// RUN: if [ %llvmver -ge 12 ]; then %clang++ -std=c++17 -O0 %s -S -emit-llvm -o - %newLoadClangEnzyme | %lli - ; fi
// RUN: if [ %llvmver -ge 12 ]; then %clang++ -std=c++17 -O1 %s -S -emit-llvm -o - %newLoadClangEnzyme | %lli - ; fi
// RUN: if [ %llvmver -ge 12 ]; then %clang++ -std=c++17 -O2 %s -S -emit-llvm -o - %newLoadClangEnzyme | %lli - ; fi
// RUN: if [ %llvmver -ge 12 ]; then %clang++ -std=c++17 -O3 %s -S -emit-llvm -o - %newLoadClangEnzyme | %lli - ; fi
#include "../test_utils.h"
#include <enzyme/enzyme>
float f(float x) { return x * x; }
float g(const float& x) { return x * x; }
float h(const float* x) { return *x * *x; }
static const float x = 10;
static const float etalon = 2 * x;
void test_active() {
{ // Ok, reverse mode + active
const float dfdx = enzyme::get<0>(
enzyme::get<0>(
enzyme::autodiff<enzyme::Reverse>(
f, enzyme::Active{ x }
)
)
);
APPROX_EQ(dfdx, etalon, 1e-10);
}
}
void test_duplicated() {
{ // Ok, reverse mode + reference arg
float dfdx = 0;
enzyme::autodiff<enzyme::Reverse>(
g, enzyme::Duplicated<const float&>{ x, dfdx }
);
APPROX_EQ(dfdx, etalon, 1e-10);
}
{ // Ok, reverse mode + pointer arg
float dfdx = 0;
enzyme::autodiff<enzyme::Reverse>(
h, enzyme::Duplicated<const float*>{ &x, &dfdx }
);
APPROX_EQ(dfdx, etalon, 1e-10);
}
{ // OK, forward mode + pass-by-value
const float dfdx = enzyme::get<0>(
enzyme::autodiff<enzyme::Forward>(
f, enzyme::Duplicated<float>{ x, 1.0f }
)
);
APPROX_EQ(dfdx, etalon, 1e-10);
}
{
/*
* OK: forward mode + pass by reference
* Regular __enzyme_fwddiff will not allow a non-pointer here too
*/
const float dx = 1.0f;
const float dfdx = enzyme::get<0>(
enzyme::autodiff<enzyme::Forward>(
g, enzyme::Duplicated<const float&>{ x, dx }
)
);
APPROX_EQ(dfdx, etalon, 1e-10);
}
{
/*
* OK: forward mode + pass by pointer
* Regular __enzyme_fwddiff will not allow a non-pointer here too
*/
const float dx = 1.0f;
const float dfdx = enzyme::get<0>(
enzyme::autodiff<enzyme::Forward>(
h, enzyme::Duplicated<const float*>{ &x, &dx }
)
);
APPROX_EQ(dfdx, etalon, 1e-10);
}
#if 0 // Lambdas don't work with the C++ interface yet :(
{
const auto l = [] (const float& x) { return x * x; };
float dfdx = 0;
enzyme::autodiff<enzyme::Reverse>(
l, enzyme::Duplicated<const float&>{ x, dfdx }
);
APPROX_EQ(dfdx, etalon, 1e-10);
}
#endif
}
float f2(float x, float y) { return x * y; }
float g2(float x, const float& y) { return x * y; }
float h2(float x, float& y) { return x * (y++); }
float j2(float x, const float* y) { return x * (*y); }
static const float y = 5;
static const float etalon2 = 5;
void test_const() {
{
// OK: By-value const for by-value arg
const auto dfdx = enzyme::get<0>(
enzyme::get<0>(
enzyme::autodiff<enzyme::Reverse>(
f2, enzyme::Active{ x }, enzyme::Const<float>{ y }
)
)
);
APPROX_EQ(dfdx, etalon2, 1e-10);
}
{
// OK: By-const-ref const for by-const-ref arg
const auto dfdx = enzyme::get<0>(
enzyme::get<0>(
enzyme::autodiff<enzyme::Reverse>(
g2, enzyme::Active{ x }, enzyme::Const<const float&>{ y }
)
)
);
APPROX_EQ(dfdx, etalon2, 1e-10);
}
{
// OK: By-non-const-ref Const for by-non-const-ref arg
// fun fact: putting `const T*` instead of `T*` in `enzyme/utils:108`
// not only is semantically incorrect, but also makes the compiler
// crash on this example!
float y2 = y;
const auto dfdx = enzyme::get<0>(
enzyme::get<0>(
enzyme::autodiff<enzyme::Reverse>(
h2, enzyme::Active{ x }, enzyme::Const<float&>{ y2 }
)
)
);
APPROX_EQ(dfdx, etalon2, 1e-10);
APPROX_EQ(y2, y + 1, 1e-10);
}
{
// OK: By-pointer Const for by-pointer arg
// I feel like testing with non-const pointer too would be excessive
const auto dfdx = enzyme::get<0>(
enzyme::get<0>(
enzyme::autodiff<enzyme::Reverse>(
j2, enzyme::Active{ x }, enzyme::Const<const float*>{ &y }
)
)
);
APPROX_EQ(dfdx, etalon2, 1e-10);
}
}
int main() {
test_active();
test_duplicated();
test_const();
return 0;
}