#include <stdint.h>
#include "mpn_mod.h"
static const uint8_t mul_cutoffs[][2] = {
{37, 91},
{32, 93},
{31, 93},
{80, 90},
{24, 77},
{15, 73},
{16, 113},
{20, 82},
{14, 82},
{14, 109},
{14, 106},
{15, 95},
{10, 90},
{10, 90},
{13, 90},
{14, 81},
{11, 82},
{10, 81},
{10, 97},
{12, 72},
{10, 69},
{9, 70},
{10, 83},
{10, 73},
{8, 69},
{8, 71},
{9, 73},
{10, 54},
{8, 53},
{8, 65},
{8, 65},
{8, 51},
{6, 57},
{6, 67},
{6, 67},
{8, 45},
{6, 50},
{6, 53},
{6, 53},
{8, 40},
{6, 39},
{6, 49},
{6, 65},
{6, 36},
{6, 36},
{6, 41},
{6, 41},
{6, 34},
{6, 34},
{4, 38},
{6, 37},
{6, 36},
{4, 36},
{4, 37},
{4, 37},
{6, 34},
{4, 34},
{4, 34},
{4, 35},
{6, 25},
};
static const uint8_t mul_unbalanced_cutoffs[][2] = {
{54, 55},
{44, 46},
{42, 53},
{63, 63},
{34, 45},
{18, 39},
{12, 50},
{27, 42},
{13, 29},
{12, 37},
{12, 40},
{34, 34},
{12, 33},
{11, 43},
{12, 46},
{39, 39},
{12, 40},
{11, 42},
{11, 44},
{36, 36},
{8, 35},
{8, 40},
{9, 38},
{21, 37},
{8, 35},
{8, 34},
{8, 33},
{23, 32},
{7, 31},
{7, 31},
{7, 30},
{22, 28},
{6, 28},
{7, 27},
{6, 27},
{15, 26},
{7, 25},
{6, 25},
{6, 24},
{11, 24},
{5, 23},
{5, 23},
{5, 22},
{11, 22},
{5, 21},
{4, 21},
{5, 21},
{7, 20},
{6, 20},
{4, 19},
{5, 19},
{6, 19},
{5, 18},
{4, 18},
{4, 18},
{6, 18},
{5, 17},
{5, 17},
{4, 17},
{16, 16},
};
static const uint8_t sqr_cutoffs[][2] = {
{34, 96},
{34, 93},
{43, 93},
{98, 98},
{40, 78},
{24, 76},
{24, 121},
{34, 90},
{20, 100},
{18, 119},
{22, 117},
{32, 100},
{18, 101},
{16, 99},
{20, 117},
{20, 91},
{14, 99},
{14, 103},
{18, 133},
{20, 106},
{18, 88},
{14, 118},
{18, 113},
{18, 109},
{16, 90},
{15, 102},
{16, 99},
{16, 69},
{12, 69},
{8, 90},
{10, 88},
{10, 83},
{10, 83},
{12, 70},
{11, 79},
{16, 57},
{12, 69},
{11, 73},
{8, 72},
{12, 68},
{8, 68},
{8, 67},
{7, 66},
{11, 64},
{8, 63},
{6, 63},
{6, 65},
{8, 59},
{6, 58},
{6, 57},
{7, 57},
{8, 55},
{6, 54},
{6, 53},
{6, 53},
{8, 52},
{6, 51},
{6, 50},
{6, 50},
{8, 34},
};
static const uint8_t mullow_cutoffs[][2] = {
{106, 106},
{104, 104},
{104, 104},
{126, 126},
{84, 84},
{64, 69},
{64, 88},
{84, 84},
{56, 86},
{56, 109},
{56, 113},
{96, 96},
{60, 90},
{60, 95},
{59, 90},
{86, 86},
{48, 82},
{61, 82},
{60, 97},
{75, 75},
{44, 69},
{46, 70},
{47, 83},
{64, 72},
{43, 69},
{32, 71},
{40, 73},
{63, 65},
{40, 54},
{32, 65},
{32, 65},
{47, 58},
{30, 57},
{28, 67},
{28, 67},
{32, 52},
{24, 52},
{24, 54},
{24, 67},
{32, 49},
{27, 41},
{26, 49},
{24, 66},
{31, 42},
{24, 37},
{24, 43},
{24, 51},
{31, 39},
{16, 38},
{16, 38},
{16, 39},
{29, 36},
{24, 36},
{16, 37},
{16, 37},
{29, 35},
{16, 35},
{16, 35},
{16, 35},
{32, 32},
};
static const uint8_t sqrlow_cutoffs[][2] = {
{122, 122},
{110, 110},
{114, 114},
{173, 173},
{98, 98},
{81, 81},
{102, 102},
{97, 97},
{124, 124},
{122, 122},
{120, 120},
{135, 135},
{105, 105},
{111, 117},
{125, 152},
{146, 146},
{104, 104},
{111, 133},
{109, 133},
{127, 127},
{95, 106},
{93, 118},
{93, 113},
{111, 111},
{96, 102},
{80, 102},
{80, 99},
{96, 96},
{90, 90},
{80, 90},
{79, 88},
{85, 85},
{77, 83},
{64, 81},
{63, 79},
{77, 77},
{63, 75},
{48, 73},
{48, 72},
{70, 70},
{60, 68},
{48, 67},
{60, 66},
{64, 64},
{46, 63},
{46, 64},
{47, 65},
{59, 59},
{46, 58},
{44, 57},
{46, 57},
{55, 55},
{46, 54},
{45, 53},
{45, 52},
{48, 52},
{32, 51},
{44, 50},
{44, 51},
{48, 48},
};
int
_mpn_mod_poly_mullow(nn_ptr res, nn_srcptr poly1, slong len1, nn_srcptr poly2, slong len2, slong len, gr_ctx_t ctx)
{
slong n;
slong bits, cutoff_karatsuba, cutoff_fft_KS, tab_i;
len1 = FLINT_MIN(len1, len);
len2 = FLINT_MIN(len2, len);
n = FLINT_MIN(len1, len2);
if (n < 4)
return _mpn_mod_poly_mullow_classical(res, poly1, len1, poly2, len2, len, ctx);
bits = MPN_MOD_CTX_MODULUS_BITS(ctx);
FLINT_ASSERT(bits > FLINT_BITS);
tab_i = (bits - FLINT_BITS - 1) / 16;
if (poly1 == poly2 && len1 == len2)
{
if (len == len1 + len2 - 1)
{
cutoff_karatsuba = sqr_cutoffs[tab_i][0];
cutoff_fft_KS = sqr_cutoffs[tab_i][1];
}
else
{
cutoff_karatsuba = sqrlow_cutoffs[tab_i][0];
cutoff_fft_KS = sqrlow_cutoffs[tab_i][1];
}
}
else
{
if (FLINT_MAX(len1, len2) >= 2 * n)
{
cutoff_karatsuba = mul_unbalanced_cutoffs[tab_i][0];
cutoff_fft_KS = mul_unbalanced_cutoffs[tab_i][1];
}
else if (len == len1 + len2 - 1)
{
cutoff_karatsuba = mul_cutoffs[tab_i][0];
cutoff_fft_KS = mul_cutoffs[tab_i][1];
}
else
{
cutoff_karatsuba = mullow_cutoffs[tab_i][0];
cutoff_fft_KS = mullow_cutoffs[tab_i][1];
}
}
if (n < cutoff_karatsuba)
return _mpn_mod_poly_mullow_classical(res, poly1, len1, poly2, len2, len, ctx);
if (n < cutoff_fft_KS && FLINT_MAX(len1, len2) < 4 * n)
return _mpn_mod_poly_mullow_karatsuba(res, poly1, len1, poly2, len2, len, -1, ctx);
if (GR_SUCCESS == _mpn_mod_poly_mullow_fft_small(res, poly1, len1, poly2, len2, len, ctx))
return GR_SUCCESS;
return _mpn_mod_poly_mullow_KS(res, poly1, len1, poly2, len2, len, ctx);
}