Commit 414efe98 authored by Philip Trettner's avatar Philip Trettner
Browse files

Merge branch 'feature/cleanup-fixed_int' into 'develop'

Feature/cleanup fixed int

See merge request !31
parents d9c8fbd1 e232f888
Pipeline #13729 passed with stage
in 6 minutes and 14 seconds
typed-geometry @ d6bdfdd3
Subproject commit 1d9862713da6b845580b378275cd2c02382a16d4
Subproject commit d6bdfdd3de932143316d9afc850bbfa8c1c6010d
......@@ -423,7 +423,6 @@ TG_FUZZ_TEST(TypedGeometry, FixedIntMul)
check_mul<2, 2, 1>(rng);
check_mul<2, 2, 2>(rng);
check_mul<3, 1, 1>(rng);
check_mul<3, 1, 2>(rng);
check_mul<3, 2, 1>(rng);
check_mul<3, 2, 2>(rng);
......@@ -433,9 +432,6 @@ TG_FUZZ_TEST(TypedGeometry, FixedIntMul)
check_mul<3, 3, 2>(rng);
check_mul<3, 3, 3>(rng);
check_mul<4, 1, 1>(rng);
check_mul<4, 1, 2>(rng);
check_mul<4, 2, 1>(rng);
check_mul<4, 2, 2>(rng);
check_mul<4, 1, 3>(rng);
check_mul<4, 3, 1>(rng);
......
......@@ -355,7 +355,6 @@ TG_FUZZ_TEST(TypedGeometry, FixedUintMul)
check_mul<2, 2, 1>(rng);
check_mul<2, 2, 2>(rng);
check_mul<3, 1, 1>(rng);
check_mul<3, 1, 2>(rng);
check_mul<3, 2, 1>(rng);
check_mul<3, 2, 2>(rng);
......@@ -365,9 +364,6 @@ TG_FUZZ_TEST(TypedGeometry, FixedUintMul)
check_mul<3, 3, 2>(rng);
check_mul<3, 3, 3>(rng);
check_mul<4, 1, 1>(rng);
check_mul<4, 1, 2>(rng);
check_mul<4, 2, 1>(rng);
check_mul<4, 2, 2>(rng);
check_mul<4, 1, 3>(rng);
check_mul<4, 3, 1>(rng);
......
......@@ -6,6 +6,30 @@
namespace
{
[[maybe_unused]] std::string imul()
{
return "inline u64 imul(u64 lhs, u64 rhs, u64* high)\n"
"{\n"
"#ifdef _MSC_VER\n"
" return _mul128(lhs, rhs, &(i64(high)));\n"
"#else\n"
" __int128 res_i = __int128(i64(lhs)) * i64(rhs);\n"
" u64 v[2] = {};\n"
" memcpy(&v, &res_i, sizeof(__int128));\n"
" *high = v[1];\n"
" return v[0];\n"
"#endif\n"
"}\n";
}
[[maybe_unused]] std::string mul()
{
return "inline u64 mul(u64 lhs, u64 rhs, u64* high)\n"
"{\n"
" return _mulx_u64(lhs, rhs, high);\n"
"}\n";
}
std::string generate_mul(int w_r, int w_a, int w_b)
{
auto const out_type = "u" + std::to_string(w_r * 64);
......@@ -59,10 +83,9 @@ std::string generate_mul(int w_r, int w_a, int w_b)
}
std::string result;
result += "template<>\n";
// result += "inline fixed_uint<" + std::to_string(w_r) + "> mul(" + a_type + (w_a > 1 ? " const&" : "") + " lhs, " + b_type + (w_b > 1 ? " const&" : "") + " rhs)\n{\n";
result += "inline fixed_uint<" + std::to_string(w_r) + "> mul(" + a_type + " const&" + " lhs, " + b_type + " const&" + " rhs)\n{\n";
result += " fixed_uint<" + std::to_string(w_r) + "> res;\n";
result += "template <>\n";
result += "inline " + out_type + " mul(" + a_type + " lhs, " + b_type + " rhs)\n{\n";
result += " " + out_type + " res;\n";
for (auto i = 0u; i < vars_l.size(); ++i)
result += " u64 " + l_of(vars_l[i]) + " = 0;\n";
......@@ -107,6 +130,63 @@ std::string generate_mul(int w_r, int w_a, int w_b)
return result;
}
/// special case
std::string imul_128_64_128()
{
return "template <>\n"
"inline i128 imul(i64 lhs, i128 rhs)\n"
"{\n"
"#ifdef _MSC_VER\n"
" return imul<2>(i128(lhs), rhs);\n"
"#else\n"
" intrinsic_i128 l = lhs;\n"
" intrinsic_i128 r;\n"
" memcpy(&r, &rhs, sizeof(intrinsic_i128));\n"
" intrinsic_i128 inres = l * r;\n"
" i128 res;\n"
" memcpy(&res, &inres, sizeof(intrinsic_i128));\n"
" return res;\n"
"#endif\n"
"}\n";
}
std::string imul_128_128_64()
{
return "template <>\n"
"inline i128 imul(i128 lhs, i64 rhs)\n"
"{\n"
"#ifdef _MSC_VER\n"
" return imul<2>(lhs, i128(rhs));\n"
"#else\n"
" intrinsic_i128 l;\n"
" intrinsic_i128 r = rhs;\n"
" memcpy(&l, &lhs, sizeof(intrinsic_i128));\n"
" intrinsic_i128 inres = l * r;\n"
" i128 res;\n"
" memcpy(&res, &inres, sizeof(intrinsic_i128));\n"
" return res;\n"
"#endif\n"
"}\n";
}
std::string imul_128_64_64()
{
return "template <>\n"
"inline i128 imul(i64 lhs, i64 rhs)\n"
"{\n"
"#ifdef _MSC_VER\n"
" return imul<2>(i128(lhs), i128(rhs));\n"
"#else\n"
" intrinsic_i128 l = lhs;\n"
" intrinsic_i128 r = rhs;\n"
" intrinsic_i128 inres = l * r;\n"
" i128 res;\n"
" memcpy(&res, &inres, sizeof(intrinsic_i128));\n"
" return res;\n"
"#endif\n"
"}\n";
}
std::string generate_imul(int w_r, int w_a, int w_b)
{
auto const out_type = "i" + std::to_string(w_r * 64);
......@@ -124,15 +204,15 @@ std::string generate_imul(int w_r, int w_a, int w_b)
auto const h_of = [](std::pair<int, int> const& pair) { return "h" + std::to_string(pair.first) + std::to_string(pair.second); };
auto const lhs_of = [&](int v) {
if (w_a == 1)
return std::string("l");
return std::string("lhs");
else
return "l.d[" + std::to_string(v) + "]";
return "lhs.d[" + std::to_string(v) + "]";
};
auto const rhs_of = [&](int v) {
if (w_b == 1)
return std::string("r");
return std::string("rhs");
else
return "r.d[" + std::to_string(v) + "]";
return "rhs.d[" + std::to_string(v) + "]";
};
for (auto i = 0; i < w_a; ++i)
......@@ -173,19 +253,20 @@ std::string generate_imul(int w_r, int w_a, int w_b)
result += " }\n";
};
result += "template<>\n";
result += "inline fixed_int<" + std::to_string(w_r) + "> imul(" + a_type + " const&" + " lhs, " + b_type + " const&" + " rhs)\n{\n";
result += "template <>\n";
result += "inline " + out_type + " imul(" + a_type + " lhs, " + b_type + " rhs)\n{\n";
// result += "fixed_int<" + std::to_string(w_r) + "> imul(" + a_type + (w_a > 1 ? " const&" : "") + " lhs, " + b_type + (w_b > 1 ? " const&" : "") + " rhs)\n{\n";
result += " fixed_int<" + std::to_string(w_r) + "> res;\n";
result += " " + out_type + " res;\n";
result += " " + a_type + " l = lhs;\n";
result += " " + b_type + " r = rhs;\n";
result += " u64 s_l = u64(i64(" + lhs_of(w_a - 1) + ") >> 63); // 0 iff > 0, -1 otherwise\n";
result += " u64 s_r = u64(i64(" + rhs_of(w_b - 1) + ") >> 63); // 0 iff > 0, -1 otherwise\n";
result += " u64 s_res = s_l ^ s_r;\n";
// conditional inversion
conditional_invert(lhs_of, "s_l", w_a);
conditional_invert(rhs_of, "s_r", w_b);
if (w_a != w_b || w_a != w_r)
{
result += " u64 s_l = u64(i64(" + lhs_of(w_a - 1) + ") >> 63); // 0 iff > 0, -1 otherwise\n";
result += " u64 s_r = u64(i64(" + rhs_of(w_b - 1) + ") >> 63); // 0 iff > 0, -1 otherwise\n";
result += " u64 s_res = s_l ^ s_r;\n";
conditional_invert(lhs_of, "s_l", w_a);
conditional_invert(rhs_of, "s_r", w_b);
}
for (auto i = 0u; i < vars_l.size(); ++i)
result += " u64 " + l_of(vars_l[i]) + " = 0;\n";
......@@ -224,7 +305,8 @@ std::string generate_imul(int w_r, int w_a, int w_b)
}
result += ";\n";
conditional_invert([](int i) { return "res.d[" + std::to_string(i) + "]"; }, "s_res", w_r);
if (w_a != w_b || w_a != w_r)
conditional_invert([](int i) { return "res.d[" + std::to_string(i) + "]"; }, "s_res", w_r);
result += " return res;\n";
result += "}\n";
......@@ -247,17 +329,18 @@ void generate_mul_file()
file << "#include <x86intrin.h>\n";
file << "#endif\n\n";
file << "#include <typed-geometry/feature/fixed_uint.hh>\n\n";
file << "#include <typed-geometry/feature/fixed_int.hh>\n\n";
file << "namespace tg::detail\n{\n";
file << "template <int w_res, class T0, class T1>\n";
file << "fixed_uint<w_res> mul(T0 const& lhs, T1 const& rhs);\n\n";
for (auto r = 2; r <= 4; ++r)
for (auto j = 1; j <= 4; ++j)
for (auto i = 1; i <= 4; ++i)
{
file << generate_mul(r, i, j);
file << "\n";
}
for (auto j = 1; j <= r; ++j)
for (auto i = 1; i <= r; ++i)
if (i + j >= r)
{
file << generate_mul(r, i, j);
file << "\n";
}
file << "} // namespace tg::detail";
}
......@@ -274,24 +357,40 @@ void generate_imul_file()
file << "#include <intrin.h>\n";
file << "#else\n";
file << "#include <x86intrin.h>\n";
file << "#include <cstring>\n";
file << "#endif\n\n";
file << "#include <typed-geometry/feature/fixed_int.hh>\n\n";
file << "namespace tg::detail\n{\n";
file << "template <int w_res, class T0, class T1>\n";
file << "fixed_int<w_res> imul(T0 const& lhs, T1 const& rhs);\n\n";
for (auto r = 2; r <= 4; ++r)
for (auto j = 1; j <= 4; ++j)
for (auto i = 1; i <= 4; ++i)
{
file << generate_imul(r, i, j);
file << "\n";
}
// gcc / msvc special case
file << "/// GCC warns that __int128 is not iso-c++\n"
"#ifndef _MSC_VER // MSVC does not support __int128\n"
"#pragma GCC diagnostic push\n"
"#pragma GCC diagnostic ignored \"-Wpedantic\"\n"
"using intrinsic_i128 = __int128;\n"
"#pragma GCC diagnostic pop\n"
"#endif\n\n";
// special cases
// msvc requires this one to come first
file << generate_imul(2, 2, 2) << "\n";
file << imul_128_64_64() << "\n";
file << imul_128_128_64() << "\n";
file << imul_128_64_128() << "\n";
for (auto r = 3; r <= 4; ++r)
for (auto j = 1; j <= r; ++j)
for (auto i = 1; i <= r; ++i)
if (i + j >= r)
{
file << generate_imul(r, i, j);
file << "\n";
}
file << "} // namespace tg::detail";
}
} // namespace
TEST_CASE("tg generate multiplications")
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment