Coverage Report

Created: 2026-09-26 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/AK/BigIntBase.h
Line
Count
Source
1
/*
2
 * Copyright (c) 2023, Dan Klishch <danilklishch@gmail.com>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#pragma once
8
9
#include <AK/BuiltinWrappers.h>
10
#include <AK/Span.h>
11
#include <AK/StdLibExtras.h>
12
#include <AK/Types.h>
13
14
namespace AK {
15
16
namespace Detail {
17
18
template<typename T>
19
struct DoubleWordHelper;
20
21
template<>
22
struct DoubleWordHelper<u32> {
23
    using Type = u64;
24
    using SignedType = i64;
25
};
26
template<typename T>
27
using DoubleWord = typename DoubleWordHelper<T>::Type;
28
template<typename T>
29
using SignedDoubleWord = typename DoubleWordHelper<T>::SignedType;
30
31
// Ideally, we want to store data in the native processor's words. However, for some algorithms,
32
// particularly multiplication, we require double of the amount of the native word size.
33
#if defined(__SIZEOF_INT128__) && defined(AK_ARCH_64_BIT)
34
template<>
35
struct DoubleWordHelper<u64> {
36
    using Type = unsigned __int128;
37
    using SignedType = __int128;
38
};
39
using NativeWord = u64;
40
#else
41
using NativeWord = u32;
42
#endif
43
44
using NativeDoubleWord = DoubleWord<NativeWord>;
45
using SignedNativeDoubleWord = SignedDoubleWord<NativeWord>;
46
47
template<typename WordType, bool sign>
48
using ConditionallySignedDoubleWord = Conditional<sign, SignedDoubleWord<WordType>, DoubleWord<WordType>>;
49
50
template<typename T>
51
concept BuiltInUFixedInt = OneOf<T, bool, u8, u16, u32, u64, unsigned long, unsigned long long, NativeDoubleWord>;
52
53
template<typename T>
54
constexpr inline size_t bit_width = sizeof(T) * 8;
55
56
constexpr size_t native_word_size = bit_width<NativeWord>;
57
constexpr NativeWord max_native_word = NumericLimits<NativeWord>::max();
58
static_assert(native_word_size == 32 || native_word_size == 64);
59
60
// Max big integer length is 256 MiB (2.1e9 bits) for 32-bit, 4 GiB (3.4e10 bits) for 64-bit.
61
constexpr size_t max_big_int_length = 1 << (native_word_size == 32 ? 26 : 29);
62
63
// ===== Static storage for big integers =====
64
template<typename T, typename WordType = NativeWord>
65
concept IntegerStorage = requires(T storage, size_t index) {
66
    {
67
        storage.is_negative()
68
    } -> SameAs<bool>;
69
    {
70
        storage.size()
71
    } -> SameAs<size_t>;
72
    {
73
        storage[index]
74
    } -> ConvertibleTo<WordType&>;
75
    {
76
        storage.data()
77
    } -> ConvertibleTo<WordType*>;
78
};
79
80
template<typename T, typename WordType = NativeWord>
81
concept IntegerReadonlyStorage = IntegerStorage<T, WordType const>;
82
83
struct NullAllocator {
84
0
    NativeWord* allocate(size_t) { VERIFY_NOT_REACHED(); }
85
};
86
87
template<typename Word, bool is_signed_>
88
struct StorageSpan : AK::Span<Word> {
89
    using AK::Span<Word>::Span;
90
91
    constexpr static bool is_signed = is_signed_;
92
93
    explicit constexpr StorageSpan(AK::Span<Word> span)
94
0
        : AK::Span<Word>(span)
95
0
    {
96
0
    }
Unexecuted instantiation: AK::Detail::StorageSpan<unsigned int, false>::StorageSpan(AK::Span<unsigned int>)
Unexecuted instantiation: AK::Detail::StorageSpan<unsigned long, false>::StorageSpan(AK::Span<unsigned long>)
97
98
    constexpr bool is_negative() const
99
333k
    {
100
333k
        return is_signed && this->last() >> (bit_width<Word> - 1);
101
333k
    }
AK::Detail::StorageSpan<unsigned long, false>::is_negative() const
Line
Count
Source
99
287k
    {
100
287k
        return is_signed && this->last() >> (bit_width<Word> - 1);
101
287k
    }
AK::Detail::StorageSpan<unsigned long const, false>::is_negative() const
Line
Count
Source
99
45.5k
    {
100
45.5k
        return is_signed && this->last() >> (bit_width<Word> - 1);
101
45.5k
    }
Unexecuted instantiation: AK::Detail::StorageSpan<unsigned int, false>::is_negative() const
102
};
103
104
using UnsignedStorageSpan = StorageSpan<NativeWord, false>;
105
using UnsignedStorageReadonlySpan = StorageSpan<NativeWord const, false>;
106
107
// Sometimes we want to know the exact maximum amount of the bits required to represent the number.
108
// However, the bit size only acts as a hint for wide multiply operations. For all other purposes,
109
// `bit_size`-sized and `ceil(bit_size / word_size) * word_size`-sized `StaticStorage`s will act the
110
// same.
111
template<bool is_signed_, size_t bit_size>
112
requires(bit_size <= max_big_int_length * native_word_size) struct StaticStorage {
113
    constexpr static size_t static_size = (bit_size + native_word_size - 1) / native_word_size;
114
    constexpr static bool is_signed = is_signed_;
115
116
    // We store integers in little-endian regardless of the host endianness. We use two's complement
117
    // representation of negative numbers and do not bother at all if `bit_size % word_size != 0`
118
    // (i. e. do not properly handle overflows).
119
    NativeWord m_data[static_size];
120
121
    constexpr bool is_negative() const
122
14.7M
    {
123
14.7M
        return is_signed_ && m_data[static_size - 1] >> (native_word_size - 1);
124
14.7M
    }
AK::Detail::StaticStorage<false, 64ul>::is_negative() const
Line
Count
Source
122
10.0M
    {
123
10.0M
        return is_signed_ && m_data[static_size - 1] >> (native_word_size - 1);
124
10.0M
    }
AK::Detail::StaticStorage<false, 128ul>::is_negative() const
Line
Count
Source
122
4.72M
    {
123
4.72M
        return is_signed_ && m_data[static_size - 1] >> (native_word_size - 1);
124
4.72M
    }
Unexecuted instantiation: AK::Detail::StaticStorage<false, 32ul>::is_negative() const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 4096ul>::is_negative() const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 256ul>::is_negative() const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 512ul>::is_negative() const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 8ul>::is_negative() const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 384ul>::is_negative() const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 768ul>::is_negative() const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 257ul>::is_negative() const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 513ul>::is_negative() const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 385ul>::is_negative() const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 769ul>::is_negative() const
125
126
    constexpr static size_t size()
127
22.3M
    {
128
22.3M
        return static_size;
129
22.3M
    }
AK::Detail::StaticStorage<false, 64ul>::size()
Line
Count
Source
127
12.5M
    {
128
12.5M
        return static_size;
129
12.5M
    }
AK::Detail::StaticStorage<false, 128ul>::size()
Line
Count
Source
127
9.76M
    {
128
9.76M
        return static_size;
129
9.76M
    }
Unexecuted instantiation: AK::Detail::StaticStorage<false, 32ul>::size()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 4096ul>::size()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 4160ul>::size()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 5248ul>::size()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 8ul>::size()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 192ul>::size()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 256ul>::size()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 512ul>::size()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 384ul>::size()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 768ul>::size()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 257ul>::size()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 321ul>::size()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 513ul>::size()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 577ul>::size()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 385ul>::size()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 449ul>::size()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 769ul>::size()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 833ul>::size()
130
131
    constexpr NativeWord operator[](size_t i) const
132
20.2M
    {
133
20.2M
        return m_data[i];
134
20.2M
    }
AK::Detail::StaticStorage<false, 64ul>::operator[](unsigned long) const
Line
Count
Source
132
10.0M
    {
133
10.0M
        return m_data[i];
134
10.0M
    }
AK::Detail::StaticStorage<false, 128ul>::operator[](unsigned long) const
Line
Count
Source
132
10.2M
    {
133
10.2M
        return m_data[i];
134
10.2M
    }
Unexecuted instantiation: AK::Detail::StaticStorage<false, 32ul>::operator[](unsigned long) const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 4096ul>::operator[](unsigned long) const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 8ul>::operator[](unsigned long) const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 256ul>::operator[](unsigned long) const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 512ul>::operator[](unsigned long) const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 384ul>::operator[](unsigned long) const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 768ul>::operator[](unsigned long) const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 257ul>::operator[](unsigned long) const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 513ul>::operator[](unsigned long) const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 385ul>::operator[](unsigned long) const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 769ul>::operator[](unsigned long) const
135
136
    constexpr NativeWord& operator[](size_t i)
137
12.2M
    {
138
12.2M
        return m_data[i];
139
12.2M
    }
AK::Detail::StaticStorage<false, 64ul>::operator[](unsigned long)
Line
Count
Source
137
2.51M
    {
138
2.51M
        return m_data[i];
139
2.51M
    }
AK::Detail::StaticStorage<false, 128ul>::operator[](unsigned long)
Line
Count
Source
137
9.76M
    {
138
9.76M
        return m_data[i];
139
9.76M
    }
Unexecuted instantiation: AK::Detail::StaticStorage<false, 32ul>::operator[](unsigned long)
Unexecuted instantiation: AK::Detail::StaticStorage<false, 4096ul>::operator[](unsigned long)
Unexecuted instantiation: AK::Detail::StaticStorage<false, 4160ul>::operator[](unsigned long)
Unexecuted instantiation: AK::Detail::StaticStorage<false, 5248ul>::operator[](unsigned long)
Unexecuted instantiation: AK::Detail::StaticStorage<false, 192ul>::operator[](unsigned long)
Unexecuted instantiation: AK::Detail::StaticStorage<false, 256ul>::operator[](unsigned long)
Unexecuted instantiation: AK::Detail::StaticStorage<false, 512ul>::operator[](unsigned long)
Unexecuted instantiation: AK::Detail::StaticStorage<false, 384ul>::operator[](unsigned long)
Unexecuted instantiation: AK::Detail::StaticStorage<false, 768ul>::operator[](unsigned long)
Unexecuted instantiation: AK::Detail::StaticStorage<false, 257ul>::operator[](unsigned long)
Unexecuted instantiation: AK::Detail::StaticStorage<false, 321ul>::operator[](unsigned long)
Unexecuted instantiation: AK::Detail::StaticStorage<false, 513ul>::operator[](unsigned long)
Unexecuted instantiation: AK::Detail::StaticStorage<false, 577ul>::operator[](unsigned long)
Unexecuted instantiation: AK::Detail::StaticStorage<false, 385ul>::operator[](unsigned long)
Unexecuted instantiation: AK::Detail::StaticStorage<false, 449ul>::operator[](unsigned long)
Unexecuted instantiation: AK::Detail::StaticStorage<false, 769ul>::operator[](unsigned long)
Unexecuted instantiation: AK::Detail::StaticStorage<false, 833ul>::operator[](unsigned long)
140
141
    constexpr NativeWord const* data() const
142
0
    {
143
0
        return m_data;
144
0
    }
Unexecuted instantiation: AK::Detail::StaticStorage<false, 64ul>::data() const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 32ul>::data() const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 4096ul>::data() const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 5248ul>::data() const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 256ul>::data() const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 384ul>::data() const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 257ul>::data() const
Unexecuted instantiation: AK::Detail::StaticStorage<false, 385ul>::data() const
145
146
    constexpr NativeWord* data()
147
0
    {
148
0
        return m_data;
149
0
    }
Unexecuted instantiation: AK::Detail::StaticStorage<false, 256ul>::data()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 384ul>::data()
150
151
0
    constexpr operator StorageSpan<NativeWord, is_signed>() { return { m_data, static_size }; }
Unexecuted instantiation: AK::Detail::StaticStorage<false, 4160ul>::operator AK::Detail::StorageSpan<unsigned long, false>()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 4096ul>::operator AK::Detail::StorageSpan<unsigned long, false>()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 192ul>::operator AK::Detail::StorageSpan<unsigned long, false>()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 128ul>::operator AK::Detail::StorageSpan<unsigned long, false>()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 321ul>::operator AK::Detail::StorageSpan<unsigned long, false>()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 257ul>::operator AK::Detail::StorageSpan<unsigned long, false>()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 577ul>::operator AK::Detail::StorageSpan<unsigned long, false>()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 256ul>::operator AK::Detail::StorageSpan<unsigned long, false>()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 513ul>::operator AK::Detail::StorageSpan<unsigned long, false>()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 449ul>::operator AK::Detail::StorageSpan<unsigned long, false>()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 385ul>::operator AK::Detail::StorageSpan<unsigned long, false>()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 833ul>::operator AK::Detail::StorageSpan<unsigned long, false>()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 384ul>::operator AK::Detail::StorageSpan<unsigned long, false>()
Unexecuted instantiation: AK::Detail::StaticStorage<false, 769ul>::operator AK::Detail::StorageSpan<unsigned long, false>()
152
};
153
154
struct IntegerWrapper {
155
    StaticStorage<false, bit_width<int>> m_data;
156
157
    // There is no reason to ban u128{0} + 1 (although the second argument type is signed, the value
158
    // is known at the compile time to be non-negative). In order to do so, we provide overloads in
159
    // UFixedBigInt which take IntegerWrapper as an argument.
160
    consteval IntegerWrapper(int value)
161
0
    {
162
0
        if (value < 0)
163
0
            compiletime_fail("Requested implicit conversion of an integer to the unsigned one will underflow.");
164
0
        m_data[0] = static_cast<NativeWord>(value);
165
0
    }
166
};
167
168
0
constexpr inline auto get_storage_of(IntegerWrapper value) { return value.m_data; }
169
170
template<BuiltInUFixedInt T>
171
constexpr StaticStorage<false, bit_width<T>> get_storage_of(T value)
172
7.54M
{
173
    if constexpr (sizeof(T) > sizeof(NativeWord)) {
174
        static_assert(sizeof(T) == 2 * sizeof(NativeWord));
175
        return { static_cast<NativeWord>(value), static_cast<NativeWord>(value >> native_word_size) };
176
    }
177
7.54M
    return { static_cast<NativeWord>(value) };
178
7.54M
}
_ZN2AK6Detail14get_storage_ofITkNS0_16BuiltInUFixedIntEmEENS0_13StaticStorageILb0EX9bit_widthIT_EEEES3_
Line
Count
Source
172
7.54M
{
173
    if constexpr (sizeof(T) > sizeof(NativeWord)) {
174
        static_assert(sizeof(T) == 2 * sizeof(NativeWord));
175
        return { static_cast<NativeWord>(value), static_cast<NativeWord>(value >> native_word_size) };
176
    }
177
7.54M
    return { static_cast<NativeWord>(value) };
178
7.54M
}
Unexecuted instantiation: _ZN2AK6Detail14get_storage_ofITkNS0_16BuiltInUFixedIntEjEENS0_13StaticStorageILb0EX9bit_widthIT_EEEES3_
Unexecuted instantiation: _ZN2AK6Detail14get_storage_ofITkNS0_16BuiltInUFixedIntEyEENS0_13StaticStorageILb0EX9bit_widthIT_EEEES3_
Unexecuted instantiation: _ZN2AK6Detail14get_storage_ofITkNS0_16BuiltInUFixedIntEhEENS0_13StaticStorageILb0EX9bit_widthIT_EEEES3_
Unexecuted instantiation: _ZN2AK6Detail14get_storage_ofITkNS0_16BuiltInUFixedIntEbEENS0_13StaticStorageILb0EX9bit_widthIT_EEEES3_
179
180
// ===== Utilities =====
181
template<typename Word>
182
ALWAYS_INLINE constexpr Word extend_sign(bool sign)
183
10.0M
{
184
10.0M
    return sign ? NumericLimits<Word>::max() : 0;
185
10.0M
}
unsigned long AK::Detail::extend_sign<unsigned long>(bool)
Line
Count
Source
183
10.0M
{
184
10.0M
    return sign ? NumericLimits<Word>::max() : 0;
185
10.0M
}
Unexecuted instantiation: unsigned int AK::Detail::extend_sign<unsigned int>(bool)
186
187
// FIXME: If available, we might try to use AVX2 and AVX512.
188
template<typename WordType>
189
ALWAYS_INLINE constexpr WordType add_words(WordType word1, WordType word2, bool& carry)
190
7.99M
{
191
7.99M
    if (!is_constant_evaluated()) {
192
7.99M
#if __has_builtin(__builtin_addc)
193
7.99M
        WordType ncarry, output;
194
        if constexpr (SameAs<WordType, unsigned int>)
195
0
            output = __builtin_addc(word1, word2, carry, reinterpret_cast<unsigned int*>(&ncarry));
196
        else if constexpr (SameAs<WordType, unsigned long>)
197
7.99M
            output = __builtin_addcl(word1, word2, carry, reinterpret_cast<unsigned long*>(&ncarry));
198
        else if constexpr (SameAs<WordType, unsigned long long>)
199
            output = __builtin_addcll(word1, word2, carry, reinterpret_cast<unsigned long long*>(&ncarry));
200
        else
201
7.99M
            VERIFY_NOT_REACHED();
202
7.99M
        carry = ncarry;
203
7.99M
        return output;
204
#elif ARCH(X86_64)
205
        if constexpr (SameAs<WordType, unsigned int>) {
206
            unsigned int output;
207
            carry = __builtin_ia32_addcarryx_u32(carry, word1, word2, &output);
208
            return output;
209
        } else if constexpr (OneOf<WordType, unsigned long, unsigned long long>) {
210
            unsigned long long output;
211
            carry = __builtin_ia32_addcarryx_u64(carry, word1, word2, &output);
212
            return output;
213
        } else {
214
            VERIFY_NOT_REACHED();
215
        }
216
#endif
217
7.99M
    }
218
    // Note: This is usually too confusing for both GCC and Clang.
219
0
    WordType output;
220
0
    bool ncarry = __builtin_add_overflow(word1, word2, &output);
221
0
    if (carry) {
222
0
        ++output;
223
0
        if (output == 0)
224
0
            ncarry = true;
225
0
    }
226
0
    carry = ncarry;
227
0
    return output;
228
7.99M
}
unsigned long AK::Detail::add_words<unsigned long>(unsigned long, unsigned long, bool&)
Line
Count
Source
190
7.99M
{
191
7.99M
    if (!is_constant_evaluated()) {
192
7.99M
#if __has_builtin(__builtin_addc)
193
7.99M
        WordType ncarry, output;
194
        if constexpr (SameAs<WordType, unsigned int>)
195
            output = __builtin_addc(word1, word2, carry, reinterpret_cast<unsigned int*>(&ncarry));
196
        else if constexpr (SameAs<WordType, unsigned long>)
197
7.99M
            output = __builtin_addcl(word1, word2, carry, reinterpret_cast<unsigned long*>(&ncarry));
198
        else if constexpr (SameAs<WordType, unsigned long long>)
199
            output = __builtin_addcll(word1, word2, carry, reinterpret_cast<unsigned long long*>(&ncarry));
200
        else
201
7.99M
            VERIFY_NOT_REACHED();
202
7.99M
        carry = ncarry;
203
7.99M
        return output;
204
#elif ARCH(X86_64)
205
        if constexpr (SameAs<WordType, unsigned int>) {
206
            unsigned int output;
207
            carry = __builtin_ia32_addcarryx_u32(carry, word1, word2, &output);
208
            return output;
209
        } else if constexpr (OneOf<WordType, unsigned long, unsigned long long>) {
210
            unsigned long long output;
211
            carry = __builtin_ia32_addcarryx_u64(carry, word1, word2, &output);
212
            return output;
213
        } else {
214
            VERIFY_NOT_REACHED();
215
        }
216
#endif
217
7.99M
    }
218
    // Note: This is usually too confusing for both GCC and Clang.
219
0
    WordType output;
220
0
    bool ncarry = __builtin_add_overflow(word1, word2, &output);
221
0
    if (carry) {
222
0
        ++output;
223
0
        if (output == 0)
224
0
            ncarry = true;
225
0
    }
226
0
    carry = ncarry;
227
0
    return output;
228
7.99M
}
Unexecuted instantiation: unsigned int AK::Detail::add_words<unsigned int>(unsigned int, unsigned int, bool&)
229
230
template<typename WordType>
231
ALWAYS_INLINE constexpr WordType sub_words(WordType word1, WordType word2, bool& carry)
232
0
{
233
0
    if (!is_constant_evaluated()) {
234
0
#if __has_builtin(__builtin_subc) && !defined(AK_BUILTIN_SUBC_BROKEN)
235
0
        WordType ncarry, output;
236
        if constexpr (SameAs<WordType, unsigned int>)
237
0
            output = __builtin_subc(word1, word2, carry, reinterpret_cast<unsigned int*>(&ncarry));
238
        else if constexpr (SameAs<WordType, unsigned long>)
239
0
            output = __builtin_subcl(word1, word2, carry, reinterpret_cast<unsigned long*>(&ncarry));
240
        else if constexpr (SameAs<WordType, unsigned long long>)
241
            output = __builtin_subcll(word1, word2, carry, reinterpret_cast<unsigned long long*>(&ncarry));
242
        else
243
0
            VERIFY_NOT_REACHED();
244
0
        carry = ncarry;
245
0
        return output;
246
#elif ARCH(X86_64) && defined(AK_COMPILER_GCC)
247
        if constexpr (SameAs<WordType, unsigned int>) {
248
            unsigned int output;
249
            carry = __builtin_ia32_sbb_u32(carry, word1, word2, &output);
250
            return output;
251
        } else if constexpr (OneOf<WordType, unsigned long, unsigned long long>) {
252
            unsigned long long output;
253
            carry = __builtin_ia32_sbb_u64(carry, word1, word2, &output);
254
            return output;
255
        } else {
256
            VERIFY_NOT_REACHED();
257
        }
258
#endif
259
0
    }
260
    // Note: This is usually too confusing for both GCC and Clang.
261
0
    WordType output;
262
0
    bool ncarry = __builtin_sub_overflow(word1, word2, &output);
263
0
    if (carry) {
264
0
        if (output == 0)
265
0
            ncarry = true;
266
0
        --output;
267
0
    }
268
0
    carry = ncarry;
269
0
    return output;
270
0
}
Unexecuted instantiation: unsigned long AK::Detail::sub_words<unsigned long>(unsigned long, unsigned long, bool&)
Unexecuted instantiation: unsigned int AK::Detail::sub_words<unsigned int>(unsigned int, unsigned int, bool&)
271
272
template<typename WordType>
273
ALWAYS_INLINE constexpr DoubleWord<WordType> wide_multiply(WordType word1, WordType word2)
274
0
{
275
0
    return static_cast<DoubleWord<WordType>>(word1) * word2;
276
0
}
Unexecuted instantiation: AK::Detail::DoubleWordHelper<unsigned long>::Type AK::Detail::wide_multiply<unsigned long>(unsigned long, unsigned long)
Unexecuted instantiation: AK::Detail::DoubleWordHelper<unsigned int>::Type AK::Detail::wide_multiply<unsigned int>(unsigned int, unsigned int)
277
278
template<typename WordType>
279
constexpr DoubleWord<WordType> dword(WordType low, WordType high)
280
0
{
281
0
    return (static_cast<DoubleWord<WordType>>(high) << bit_width<WordType>) | low;
282
0
}
Unexecuted instantiation: AK::Detail::DoubleWordHelper<unsigned long>::Type AK::Detail::dword<unsigned long>(unsigned long, unsigned long)
Unexecuted instantiation: AK::Detail::DoubleWordHelper<unsigned int>::Type AK::Detail::dword<unsigned int>(unsigned int, unsigned int)
283
284
// Calculate ((dividend_high << word_size) + dividend_low) / divisor. Quotient should be guaranteed to fit
285
// into WordType.
286
template<typename WordType>
287
ALWAYS_INLINE constexpr WordType div_mod_words(WordType dividend_low, WordType dividend_high, WordType divisor, WordType& remainder)
288
0
{
289
0
    auto dividend = dword(dividend_low, dividend_high);
290
0
    remainder = static_cast<WordType>(dividend % divisor);
291
0
    return static_cast<WordType>(dividend / divisor);
292
0
}
Unexecuted instantiation: unsigned long AK::Detail::div_mod_words<unsigned long>(unsigned long, unsigned long, unsigned long, unsigned long&)
Unexecuted instantiation: unsigned int AK::Detail::div_mod_words<unsigned int>(unsigned int, unsigned int, unsigned int, unsigned int&)
293
294
// ===== Operations on integer storages =====
295
// Naming scheme for variables belonging to one of the operands or the result is as follows:
296
// trailing digit in a name is 1 if a variable belongs to `operand1` (or the only `operand`), 2 --
297
// for `operand2` and no trailing digit -- for `result`.
298
template<typename WordType = NativeWord>
299
struct StorageOperations {
300
    static constexpr size_t word_size = bit_width<WordType>;
301
    using DoubleWordType = DoubleWord<WordType>;
302
303
    static constexpr void copy(IntegerReadonlyStorage<WordType> auto const& operand, IntegerStorage<WordType> auto&& result, size_t offset = 0)
304
2.52M
    {
305
2.52M
        auto fill = extend_sign<WordType>(operand.is_negative());
306
2.52M
        size_t size1 = operand.size(), size = result.size();
307
308
5.05M
        for (size_t i = 0; i < size; ++i)
309
2.52M
            result[i] = i + offset < size1 ? operand[i + offset] : fill;
310
2.52M
    }
_ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm64EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_OT0_m
Line
Count
Source
304
2.51M
    {
305
2.51M
        auto fill = extend_sign<WordType>(operand.is_negative());
306
2.51M
        size_t size1 = operand.size(), size = result.size();
307
308
5.03M
        for (size_t i = 0; i < size; ++i)
309
2.51M
            result[i] = i + offset < size1 ? operand[i + offset] : fill;
310
2.51M
    }
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm32EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_OT0_m
_ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm64EEETkNS0_14IntegerStorageIS5_EENS0_11StorageSpanImLb0EEEEEvRKS5_OT0_m
Line
Count
Source
304
10.6k
    {
305
10.6k
        auto fill = extend_sign<WordType>(operand.is_negative());
306
10.6k
        size_t size1 = operand.size(), size = result.size();
307
308
21.3k
        for (size_t i = 0; i < size; ++i)
309
10.6k
            result[i] = i + offset < size1 ? operand[i + offset] : fill;
310
10.6k
    }
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm32EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm4096EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm4096EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm128EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm4096EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm4160EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm128EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm128EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm192EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm32EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm128EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm32EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm256EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm512EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm256EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm8EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm256EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm32EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm384EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm768EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm384EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm8EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm384EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm256EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm257EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm32EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm257EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm257EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm257EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm321EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm257EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm256EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm32EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm513EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm513EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm256EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm513EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm577EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm384EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm385EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm32EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm385EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm385EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm385EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm449EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm385EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm384EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm32EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm769EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm769EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm384EEEEEvRKS5_OT0_m
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE4copyITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm769EEETkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm833EEEEEvRKS5_OT0_m
311
312
    static constexpr void set(WordType value, auto&& result)
313
0
    {
314
0
        result[0] = value;
315
0
        for (size_t i = 1; i < result.size(); ++i)
316
0
            result[i] = 0;
317
0
    }
Unexecuted instantiation: void AK::Detail::StorageOperations<unsigned long>::set<AK::Detail::StaticStorage<false, 4096ul>&>(unsigned long, AK::Detail::StaticStorage<false, 4096ul>&)
Unexecuted instantiation: void AK::Detail::StorageOperations<unsigned long>::set<AK::Detail::StaticStorage<false, 128ul>&>(unsigned long, AK::Detail::StaticStorage<false, 128ul>&)
Unexecuted instantiation: void AK::Detail::StorageOperations<unsigned long>::set<AK::Detail::StaticStorage<false, 257ul>&>(unsigned long, AK::Detail::StaticStorage<false, 257ul>&)
Unexecuted instantiation: void AK::Detail::StorageOperations<unsigned long>::set<AK::Detail::StaticStorage<false, 256ul>&>(unsigned long, AK::Detail::StaticStorage<false, 256ul>&)
Unexecuted instantiation: void AK::Detail::StorageOperations<unsigned long>::set<AK::Detail::StaticStorage<false, 513ul>&>(unsigned long, AK::Detail::StaticStorage<false, 513ul>&)
Unexecuted instantiation: void AK::Detail::StorageOperations<unsigned long>::set<AK::Detail::StaticStorage<false, 385ul>&>(unsigned long, AK::Detail::StaticStorage<false, 385ul>&)
Unexecuted instantiation: void AK::Detail::StorageOperations<unsigned long>::set<AK::Detail::StaticStorage<false, 384ul>&>(unsigned long, AK::Detail::StaticStorage<false, 384ul>&)
Unexecuted instantiation: void AK::Detail::StorageOperations<unsigned long>::set<AK::Detail::StaticStorage<false, 769ul>&>(unsigned long, AK::Detail::StaticStorage<false, 769ul>&)
318
319
    // `is_for_inequality' is a hint to compiler that we do not need to differentiate between < and >.
320
    static constexpr int compare(IntegerReadonlyStorage<WordType> auto const& operand1, IntegerReadonlyStorage<WordType> auto const& operand2, bool is_for_inequality)
321
10.6k
    {
322
10.6k
        bool sign1 = operand1.is_negative(), sign2 = operand2.is_negative();
323
10.6k
        size_t size1 = operand1.size(), size2 = operand2.size();
324
325
10.6k
        if (sign1 != sign2) {
326
0
            if (sign1)
327
0
                return -1;
328
0
            return 1;
329
0
        }
330
331
10.6k
        WordType compare_value = extend_sign<WordType>(sign1);
332
10.6k
        bool differ_in_high_bits = false;
333
334
10.6k
        if (size1 > size2) {
335
0
            for (size_t i = size1; i-- > size2;)
336
0
                if (operand1[i] != compare_value)
337
0
                    differ_in_high_bits = true;
338
10.6k
        } else if (size1 < size2) {
339
0
            for (size_t i = size2; i-- > size1;)
340
0
                if (operand2[i] != compare_value)
341
0
                    differ_in_high_bits = true;
342
0
        }
343
344
10.6k
        if (differ_in_high_bits)
345
0
            return (size1 > size2) ^ sign1 ? 1 : -1;
346
347
        // FIXME: Using min(size1, size2) in the next line triggers -Warray-bounds on GCC with -O2 and
348
        //        -fsanitize=address. I have not reported this.
349
        //        Reduced testcase: https://godbolt.org/z/TE3MbfhnE
350
23.6k
        for (size_t i = (size1 > size2 ? size2 : size1); i--;) {
351
20.1k
            auto word1 = operand1[i], word2 = operand2[i];
352
353
20.1k
            if (is_for_inequality) {
354
0
                if (word1 != word2)
355
0
                    return 1;
356
20.1k
            } else {
357
20.1k
                if (word1 > word2)
358
3.23k
                    return 1;
359
16.9k
                if (word1 < word2)
360
3.92k
                    return -1;
361
16.9k
            }
362
20.1k
        }
363
3.54k
        return 0;
364
10.6k
    }
_ZN2AK6Detail17StorageOperationsImE7compareITkNS0_22IntegerReadonlyStorageIT_EENS0_11StorageSpanIKmLb0EEETkNS4_IS5_EES8_EEiRKS5_RKT0_b
Line
Count
Source
321
10.6k
    {
322
10.6k
        bool sign1 = operand1.is_negative(), sign2 = operand2.is_negative();
323
10.6k
        size_t size1 = operand1.size(), size2 = operand2.size();
324
325
10.6k
        if (sign1 != sign2) {
326
0
            if (sign1)
327
0
                return -1;
328
0
            return 1;
329
0
        }
330
331
10.6k
        WordType compare_value = extend_sign<WordType>(sign1);
332
10.6k
        bool differ_in_high_bits = false;
333
334
10.6k
        if (size1 > size2) {
335
0
            for (size_t i = size1; i-- > size2;)
336
0
                if (operand1[i] != compare_value)
337
0
                    differ_in_high_bits = true;
338
10.6k
        } else if (size1 < size2) {
339
0
            for (size_t i = size2; i-- > size1;)
340
0
                if (operand2[i] != compare_value)
341
0
                    differ_in_high_bits = true;
342
0
        }
343
344
10.6k
        if (differ_in_high_bits)
345
0
            return (size1 > size2) ^ sign1 ? 1 : -1;
346
347
        // FIXME: Using min(size1, size2) in the next line triggers -Warray-bounds on GCC with -O2 and
348
        //        -fsanitize=address. I have not reported this.
349
        //        Reduced testcase: https://godbolt.org/z/TE3MbfhnE
350
23.6k
        for (size_t i = (size1 > size2 ? size2 : size1); i--;) {
351
20.1k
            auto word1 = operand1[i], word2 = operand2[i];
352
353
20.1k
            if (is_for_inequality) {
354
0
                if (word1 != word2)
355
0
                    return 1;
356
20.1k
            } else {
357
20.1k
                if (word1 > word2)
358
3.23k
                    return 1;
359
16.9k
                if (word1 < word2)
360
3.92k
                    return -1;
361
16.9k
            }
362
20.1k
        }
363
3.54k
        return 0;
364
10.6k
    }
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE7compareITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm4096EEETkNS4_IS5_EES7_EEiRKS5_RKT0_b
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE7compareITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm256EEETkNS4_IS5_EENS6_ILb0ELm32EEEEEiRKS5_RKT0_b
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE7compareITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm384EEETkNS4_IS5_EENS6_ILb0ELm32EEEEEiRKS5_RKT0_b
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE7compareITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm256EEETkNS4_IS5_EES7_EEiRKS5_RKT0_b
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE7compareITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm384EEETkNS4_IS5_EES7_EEiRKS5_RKT0_b
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE7compareITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm128EEETkNS4_IS5_EENS6_ILb0ELm32EEEEEiRKS5_RKT0_b
365
366
    enum class Bitwise {
367
        AND,
368
        OR,
369
        XOR,
370
        INVERT,
371
    };
372
373
    // Requirements:
374
    //  - !operand1.is_signed && !operand2.is_signed && !result.is_signed (the function will also work
375
    //    for signed storages but will extend them with zeroes regardless of the actual sign).
376
    template<Bitwise operation>
377
    static constexpr void compute_bitwise(IntegerReadonlyStorage<WordType> auto const& operand1, IntegerReadonlyStorage<WordType> auto const& operand2, IntegerStorage<WordType> auto&& result)
378
0
    {
379
0
        size_t size1 = operand1.size(), size2 = operand2.size(), size = result.size();
380
381
0
        for (size_t i = 0; i < size; ++i) {
382
0
            auto word1 = i < size1 ? operand1[i] : 0;
383
0
            auto word2 = i < size2 ? operand2[i] : 0;
384
385
            if constexpr (operation == Bitwise::AND)
386
0
                result[i] = word1 & word2;
387
            else if constexpr (operation == Bitwise::OR)
388
0
                result[i] = word1 | word2;
389
            else if constexpr (operation == Bitwise::XOR)
390
0
                result[i] = word1 ^ word2;
391
            else if constexpr (operation == Bitwise::INVERT)
392
0
                result[i] = ~word1;
393
            else
394
                static_assert(((void)operation, false));
395
0
        }
396
0
    }
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE15compute_bitwiseILNS2_7BitwiseE1ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm128EEETkNS5_IS6_EENS7_ILb0ELm8EEETkNS0_14IntegerStorageIS6_EERS8_EEvRKT0_RKT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE15compute_bitwiseILNS2_7BitwiseE0ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm256EEETkNS5_IS6_EENS7_ILb0ELm32EEETkNS0_14IntegerStorageIS6_EERS8_EEvRKT0_RKT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE15compute_bitwiseILNS2_7BitwiseE0ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm256EEETkNS5_IS6_EES8_TkNS0_14IntegerStorageIS6_EERS8_EEvRKT0_RKT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE15compute_bitwiseILNS2_7BitwiseE1ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm256EEETkNS5_IS6_EES8_TkNS0_14IntegerStorageIS6_EERS8_EEvRKT0_RKT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE15compute_bitwiseILNS2_7BitwiseE3ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm256EEETkNS5_IS6_EES8_TkNS0_14IntegerStorageIS6_EERS8_EEvRKT0_RKT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE15compute_bitwiseILNS2_7BitwiseE0ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm384EEETkNS5_IS6_EENS7_ILb0ELm32EEETkNS0_14IntegerStorageIS6_EERS8_EEvRKT0_RKT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE15compute_bitwiseILNS2_7BitwiseE0ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm384EEETkNS5_IS6_EES8_TkNS0_14IntegerStorageIS6_EERS8_EEvRKT0_RKT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE15compute_bitwiseILNS2_7BitwiseE1ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm384EEETkNS5_IS6_EES8_TkNS0_14IntegerStorageIS6_EERS8_EEvRKT0_RKT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE15compute_bitwiseILNS2_7BitwiseE3ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm384EEETkNS5_IS6_EES8_TkNS0_14IntegerStorageIS6_EERS8_EEvRKT0_RKT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE15compute_bitwiseILNS2_7BitwiseE2ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm128EEETkNS5_IS6_EES8_TkNS0_14IntegerStorageIS6_EERS8_EEvRKT0_RKT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE15compute_bitwiseILNS2_7BitwiseE0ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm128EEETkNS5_IS6_EES8_TkNS0_14IntegerStorageIS6_EERS8_EEvRKT0_RKT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE15compute_bitwiseILNS2_7BitwiseE1ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm128EEETkNS5_IS6_EES8_TkNS0_14IntegerStorageIS6_EERS8_EEvRKT0_RKT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE15compute_bitwiseILNS2_7BitwiseE3ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm128EEETkNS5_IS6_EES8_TkNS0_14IntegerStorageIS6_EERS8_EEvRKT0_RKT1_OT2_
397
398
    // See `storage_compute_bitwise` for the signedness requirements.
399
    //
400
    // NOTE: We want to be able to call all of the storage_* functions like
401
    //       `storage_*(operand1, operand2, result)`, even if some of the operands are unused (in order
402
    //       to then easily generate most of the operators via defines). That is why we have unused
403
    //       first operand here.
404
    template<Bitwise operation>
405
    static constexpr void compute_inplace_bitwise(IntegerReadonlyStorage<WordType> auto const&, IntegerReadonlyStorage<WordType> auto const& operand2, IntegerStorage<WordType> auto&& result)
406
0
    {
407
0
        size_t min_size = min(result.size(), operand2.size());
408
409
0
        for (size_t i = 0; i < min_size; ++i) {
410
            if constexpr (operation == Bitwise::AND)
411
                result[i] &= operand2[i];
412
            else if constexpr (operation == Bitwise::OR)
413
0
                result[i] |= operand2[i];
414
            else if constexpr (operation == Bitwise::XOR)
415
                result[i] ^= operand2[i];
416
            else
417
                static_assert(((void)operation, false));
418
0
        }
419
0
    }
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE23compute_inplace_bitwiseILNS2_7BitwiseE1ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm256EEETkNS5_IS6_EES8_TkNS0_14IntegerStorageIS6_EERS8_EEvRKT0_RKT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE23compute_inplace_bitwiseILNS2_7BitwiseE1ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm256EEETkNS5_IS6_EENS7_ILb0ELm8EEETkNS0_14IntegerStorageIS6_EERS8_EEvRKT0_RKT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE23compute_inplace_bitwiseILNS2_7BitwiseE1ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm384EEETkNS5_IS6_EES8_TkNS0_14IntegerStorageIS6_EERS8_EEvRKT0_RKT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE23compute_inplace_bitwiseILNS2_7BitwiseE1ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm384EEETkNS5_IS6_EENS7_ILb0ELm8EEETkNS0_14IntegerStorageIS6_EERS8_EEvRKT0_RKT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE23compute_inplace_bitwiseILNS2_7BitwiseE1ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm256EEETkNS5_IS6_EENS7_ILb0ELm32EEETkNS0_14IntegerStorageIS6_EERS8_EEvRKT0_RKT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE23compute_inplace_bitwiseILNS2_7BitwiseE1ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm384EEETkNS5_IS6_EENS7_ILb0ELm32EEETkNS0_14IntegerStorageIS6_EERS8_EEvRKT0_RKT1_OT2_
420
421
    // Requirements for the next two functions:
422
    //  - shift < result.size() * word_size;
423
    //  - result.size() == operand.size().
424
    static constexpr void shift_left(IntegerReadonlyStorage<WordType> auto const& operand, size_t shift, IntegerStorage<WordType> auto&& result)
425
11.6k
    {
426
11.6k
        size_t size = operand.size();
427
11.6k
        size_t offset = shift / word_size, remainder = shift % word_size;
428
429
11.6k
        if (shift % word_size == 0) {
430
1.37k
            for (size_t i = size; i-- > offset;)
431
1.05k
                result[i] = operand[i - offset];
432
2.53k
            for (size_t i = 0; i < offset; ++i)
433
2.21k
                result[i] = 0;
434
11.3k
        } else {
435
118k
            for (size_t i = size; --i > offset;)
436
107k
                result[i] = (operand[i - offset] << remainder) | (operand[i - offset - 1] >> (word_size - remainder));
437
11.3k
            result[offset] = operand[0] << remainder;
438
50.1k
            for (size_t i = 0; i < offset; ++i)
439
38.8k
                result[i] = 0;
440
11.3k
        }
441
11.6k
    }
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE10shift_leftITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm128EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_mOT0_
_ZN2AK6Detail17StorageOperationsImE10shift_leftITkNS0_22IntegerReadonlyStorageIT_EENS0_11StorageSpanImLb0EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_mOT0_
Line
Count
Source
425
11.6k
    {
426
11.6k
        size_t size = operand.size();
427
11.6k
        size_t offset = shift / word_size, remainder = shift % word_size;
428
429
11.6k
        if (shift % word_size == 0) {
430
1.37k
            for (size_t i = size; i-- > offset;)
431
1.05k
                result[i] = operand[i - offset];
432
2.53k
            for (size_t i = 0; i < offset; ++i)
433
2.21k
                result[i] = 0;
434
11.3k
        } else {
435
118k
            for (size_t i = size; --i > offset;)
436
107k
                result[i] = (operand[i - offset] << remainder) | (operand[i - offset - 1] >> (word_size - remainder));
437
11.3k
            result[offset] = operand[0] << remainder;
438
50.1k
            for (size_t i = 0; i < offset; ++i)
439
38.8k
                result[i] = 0;
440
11.3k
        }
441
11.6k
    }
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE10shift_leftITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm4096EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_mOT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsIjE10shift_leftITkNS0_22IntegerReadonlyStorageIT_EENS0_11StorageSpanIjLb0EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_mOT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE10shift_leftITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm256EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_mOT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE10shift_leftITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm384EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_mOT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE10shift_leftITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm257EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_mOT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE10shift_leftITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm513EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_mOT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE10shift_leftITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm385EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_mOT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE10shift_leftITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm769EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_mOT0_
442
443
    static constexpr void shift_right(IntegerReadonlyStorage<WordType> auto const& operand, size_t shift, IntegerStorage<WordType> auto&& result)
444
0
    {
445
0
        size_t size = operand.size();
446
0
        size_t offset = shift / word_size, remainder = shift % word_size;
447
448
0
        if (shift % word_size == 0) {
449
0
            for (size_t i = 0; i < size - offset; ++i)
450
0
                result[i] = operand[i + offset];
451
0
            for (size_t i = size - offset; i < size; ++i)
452
0
                result[i] = 0;
453
0
        } else {
454
0
            for (size_t i = 0; i < size - offset - 1; ++i)
455
0
                result[i] = (operand[i + offset] >> remainder) | (operand[i + offset + 1] << (word_size - remainder));
456
0
            result[size - offset - 1] = operand[size - 1] >> remainder;
457
0
            for (size_t i = size - offset; i < size; ++i)
458
0
                result[i] = 0;
459
0
        }
460
0
    }
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE11shift_rightITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm128EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_mOT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE11shift_rightITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm4096EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_mOT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsIjE11shift_rightITkNS0_22IntegerReadonlyStorageIT_EENS0_11StorageSpanIKjLb0EEETkNS0_14IntegerStorageIS5_EENS6_IjLb0EEEEEvRKS5_mOT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsIjE11shift_rightITkNS0_22IntegerReadonlyStorageIT_EENS0_11StorageSpanIjLb0EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_mOT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE11shift_rightITkNS0_22IntegerReadonlyStorageIT_EENS0_11StorageSpanImLb0EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_mOT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE11shift_rightITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm512EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_mOT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE11shift_rightITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm256EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_mOT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE11shift_rightITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm768EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_mOT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE11shift_rightITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm384EEETkNS0_14IntegerStorageIS5_EERS7_EEvRKS5_mOT0_
461
462
    // Requirements:
463
    //  - result.size() >= max(operand1.size(), operand2.size()) (not a real constraint but overflow
464
    //    detection will not work otherwise).
465
    //
466
    // Return value:
467
    // Let r be the return value of the function and a, b, c -- the integer values stored in `operand1`,
468
    // `operand2` and `result`, respectively. Then,
469
    //     a + b * (-1) ** subtract = c + r * 2 ** (result.size() * word_size).
470
    // In particular, r equals 0 iff no overflow has happened.
471
    template<bool subtract>
472
    static constexpr int add(IntegerReadonlyStorage<WordType> auto const& operand1, IntegerReadonlyStorage<WordType> auto const& operand2, IntegerStorage<WordType> auto&& result, bool carry = false)
473
2.49M
    {
474
2.49M
        bool sign1 = operand1.is_negative(), sign2 = operand2.is_negative();
475
2.49M
        auto fill1 = extend_sign<WordType>(sign1), fill2 = extend_sign<WordType>(sign2);
476
2.49M
        size_t size1 = operand1.size(), size2 = operand2.size(), size = result.size();
477
478
9.65M
        for (size_t i = 0; i < size; ++i) {
479
7.16M
            auto word1 = i < size1 ? operand1[i] : fill1;
480
7.16M
            auto word2 = i < size2 ? operand2[i] : fill2;
481
482
            if constexpr (!subtract)
483
7.16M
                result[i] = add_words(word1, word2, carry);
484
            else
485
0
                result[i] = sub_words(word1, word2, carry);
486
7.16M
        }
487
488
        if constexpr (!subtract)
489
2.49M
            return -sign1 - sign2 + carry + result.is_negative();
490
        else
491
0
            return -sign1 + sign2 - carry + result.is_negative();
492
2.49M
    }
_ZN2AK6Detail17StorageOperationsImE3addILb0ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm128EEETkNS4_IS5_EENS6_ILb0ELm64EEETkNS0_14IntegerStorageIS5_EERS7_EEiRKT0_RKT1_OT2_b
Line
Count
Source
473
2.36M
    {
474
2.36M
        bool sign1 = operand1.is_negative(), sign2 = operand2.is_negative();
475
2.36M
        auto fill1 = extend_sign<WordType>(sign1), fill2 = extend_sign<WordType>(sign2);
476
2.36M
        size_t size1 = operand1.size(), size2 = operand2.size(), size = result.size();
477
478
7.08M
        for (size_t i = 0; i < size; ++i) {
479
4.72M
            auto word1 = i < size1 ? operand1[i] : fill1;
480
4.72M
            auto word2 = i < size2 ? operand2[i] : fill2;
481
482
            if constexpr (!subtract)
483
4.72M
                result[i] = add_words(word1, word2, carry);
484
            else
485
                result[i] = sub_words(word1, word2, carry);
486
4.72M
        }
487
488
        if constexpr (!subtract)
489
2.36M
            return -sign1 - sign2 + carry + result.is_negative();
490
        else
491
            return -sign1 + sign2 - carry + result.is_negative();
492
2.36M
    }
_ZN2AK6Detail17StorageOperationsImE3addILb0ETkNS0_22IntegerReadonlyStorageIT_EENS0_11StorageSpanImLb0EEETkNS4_IS5_EENS0_13StaticStorageILb0ELm64EEETkNS0_14IntegerStorageIS5_EERS7_EEiRKT0_RKT1_OT2_b
Line
Count
Source
473
131k
    {
474
131k
        bool sign1 = operand1.is_negative(), sign2 = operand2.is_negative();
475
131k
        auto fill1 = extend_sign<WordType>(sign1), fill2 = extend_sign<WordType>(sign2);
476
131k
        size_t size1 = operand1.size(), size2 = operand2.size(), size = result.size();
477
478
2.57M
        for (size_t i = 0; i < size; ++i) {
479
2.44M
            auto word1 = i < size1 ? operand1[i] : fill1;
480
2.44M
            auto word2 = i < size2 ? operand2[i] : fill2;
481
482
            if constexpr (!subtract)
483
2.44M
                result[i] = add_words(word1, word2, carry);
484
            else
485
                result[i] = sub_words(word1, word2, carry);
486
2.44M
        }
487
488
        if constexpr (!subtract)
489
131k
            return -sign1 - sign2 + carry + result.is_negative();
490
        else
491
            return -sign1 + sign2 - carry + result.is_negative();
492
131k
    }
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE3addILb0ETkNS0_22IntegerReadonlyStorageIT_EENS0_11StorageSpanImLb0EEETkNS4_IS5_EES7_TkNS0_14IntegerStorageIS5_EERS7_EEiRKT0_RKT1_OT2_b
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE3addILb0ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm4096EEETkNS4_IS5_EENS6_ILb0ELm32EEETkNS0_14IntegerStorageIS5_EERS7_EEiRKT0_RKT1_OT2_b
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsIjE3addILb0ETkNS0_22IntegerReadonlyStorageIT_EENS0_11StorageSpanIjLb0EEETkNS4_IS5_EES7_TkNS0_14IntegerStorageIS5_EERS7_EEiRKT0_RKT1_OT2_b
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE3addILb0ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm256EEETkNS4_IS5_EES7_TkNS0_14IntegerStorageIS5_EERS7_EEiRKT0_RKT1_OT2_b
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE3addILb1ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm256EEETkNS4_IS5_EES7_TkNS0_14IntegerStorageIS5_EERS7_EEiRKT0_RKT1_OT2_b
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE3addILb1ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm256EEETkNS4_IS5_EENS6_ILb0ELm32EEETkNS0_14IntegerStorageIS5_EERS7_EEiRKT0_RKT1_OT2_b
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE3addILb0ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm384EEETkNS4_IS5_EES7_TkNS0_14IntegerStorageIS5_EERS7_EEiRKT0_RKT1_OT2_b
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE3addILb1ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm384EEETkNS4_IS5_EES7_TkNS0_14IntegerStorageIS5_EERS7_EEiRKT0_RKT1_OT2_b
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE3addILb1ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm384EEETkNS4_IS5_EENS6_ILb0ELm32EEETkNS0_14IntegerStorageIS5_EERS7_EEiRKT0_RKT1_OT2_b
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE3addILb1ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm257EEETkNS4_IS5_EES7_TkNS0_14IntegerStorageIS5_EERS7_EEiRKT0_RKT1_OT2_b
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE3addILb1ETkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm385EEETkNS4_IS5_EES7_TkNS0_14IntegerStorageIS5_EERS7_EEiRKT0_RKT1_OT2_b
493
494
    // See `storage_add` for the meaning of the return value.
495
    template<bool subtract>
496
    static constexpr int increment(IntegerStorage<WordType> auto&& operand)
497
    {
498
        bool carry = true;
499
        bool sign = operand.is_negative();
500
        size_t size = operand.size();
501
502
        for (size_t i = 0; i < size; ++i) {
503
            if constexpr (!subtract)
504
                operand[i] = add_words<WordType>(operand[i], 0, carry);
505
            else
506
                operand[i] = sub_words<WordType>(operand[i], 0, carry);
507
        }
508
509
        if constexpr (!subtract)
510
            return -sign + carry + operand.is_negative();
511
        else
512
            return -sign - carry + operand.is_negative();
513
    }
514
515
    // Requirements:
516
    //  - result.size() == operand.size().
517
    //
518
    // Return value: operand != 0.
519
    static constexpr bool negate(IntegerReadonlyStorage<WordType> auto const& operand, IntegerStorage<WordType> auto&& result)
520
0
    {
521
0
        bool carry = false;
522
0
        size_t size = operand.size();
523
0
        for (size_t i = 0; i < size; ++i)
524
0
            result[i] = sub_words<WordType>(0, operand[i], carry);
525
0
        return carry;
526
0
    }
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE6negateITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm64EEETkNS0_14IntegerStorageIS5_EENS0_11StorageSpanImLb0EEEEEbRKS5_OT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE6negateITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm128EEETkNS0_14IntegerStorageIS5_EERS7_EEbRKS5_OT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE6negateITkNS0_22IntegerReadonlyStorageIT_EENS0_11StorageSpanImLb0EEETkNS0_14IntegerStorageIS5_EES7_EEbRKS5_OT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE6negateITkNS0_22IntegerReadonlyStorageIT_EENS0_11StorageSpanImLb0EEETkNS0_14IntegerStorageIS5_EERS7_EEbRKS5_OT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE6negateITkNS0_22IntegerReadonlyStorageIT_EENS0_11StorageSpanIKmLb0EEETkNS0_14IntegerStorageIS5_EENS6_ImLb0EEEEEbRKS5_OT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE6negateITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm32EEETkNS0_14IntegerStorageIS5_EENS0_11StorageSpanImLb0EEEEEbRKS5_OT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE6negateITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm4096EEETkNS0_14IntegerStorageIS5_EENS0_11StorageSpanImLb0EEEEEbRKS5_OT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE6negateITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm4096EEETkNS0_14IntegerStorageIS5_EERS7_EEbRKS5_OT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE6negateITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm256EEETkNS0_14IntegerStorageIS5_EENS0_11StorageSpanImLb0EEEEEbRKS5_OT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE6negateITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm512EEETkNS0_14IntegerStorageIS5_EERS7_EEbRKS5_OT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE6negateITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm256EEETkNS0_14IntegerStorageIS5_EERS7_EEbRKS5_OT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE6negateITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm384EEETkNS0_14IntegerStorageIS5_EENS0_11StorageSpanImLb0EEEEEbRKS5_OT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE6negateITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm768EEETkNS0_14IntegerStorageIS5_EERS7_EEbRKS5_OT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE6negateITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm384EEETkNS0_14IntegerStorageIS5_EERS7_EEbRKS5_OT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE6negateITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm257EEETkNS0_14IntegerStorageIS5_EENS0_11StorageSpanImLb0EEEEEbRKS5_OT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE6negateITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm257EEETkNS0_14IntegerStorageIS5_EERS7_EEbRKS5_OT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE6negateITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm385EEETkNS0_14IntegerStorageIS5_EENS0_11StorageSpanImLb0EEEEEbRKS5_OT0_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE6negateITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm385EEETkNS0_14IntegerStorageIS5_EERS7_EEbRKS5_OT0_
527
528
    // No allocations will occur if both operands are unsigned.
529
    template<IntegerReadonlyStorage<WordType> Operand1, IntegerReadonlyStorage<WordType> Operand2>
530
    static constexpr void baseline_mul(Operand1 const& operand1, Operand2 const& operand2, IntegerStorage<WordType> auto&& __restrict__ result, auto&& buffer)
531
2.54M
    {
532
2.54M
        bool sign1 = operand1.is_negative(), sign2 = operand2.is_negative();
533
2.54M
        size_t size1 = operand1.size(), size2 = operand2.size(), size = result.size();
534
535
2.54M
        if (size1 == 1 && size2 == 1) {
536
            // We do not want to compete with the cleverness of the compiler of multiplying NativeWords.
537
2.51M
            ConditionallySignedDoubleWord<WordType, Operand1::is_signed> word1 = operand1[0];
538
2.51M
            ConditionallySignedDoubleWord<WordType, Operand2::is_signed> word2 = operand2[0];
539
2.51M
            auto value = static_cast<DoubleWordType>(word1 * word2);
540
541
2.51M
            result[0] = value;
542
2.51M
            if (size > 1) {
543
2.51M
                result[1] = value >> word_size;
544
545
2.51M
                auto fill = extend_sign<WordType>(sign1 ^ sign2);
546
2.51M
                for (size_t i = 2; i < result.size(); ++i)
547
0
                    result[i] = fill;
548
2.51M
            }
549
2.51M
            return;
550
2.51M
        }
551
552
24.1k
        if (size1 < size2) {
553
8.99k
            baseline_mul(operand2, operand1, result, buffer);
554
8.99k
            return;
555
8.99k
        }
556
        // Now size1 >= size2
557
558
        // Normalize signs
559
15.1k
        auto data1 = operand1.data(), data2 = operand2.data();
560
15.1k
        if (size2 < size) {
561
15.1k
            if (sign1) {
562
0
                auto inverted = buffer.allocate(size1);
563
0
                negate(operand1, StorageSpan<WordType, false> { inverted, size1 });
564
0
                data1 = inverted;
565
0
            }
566
15.1k
            if (sign2) {
567
0
                auto inverted = buffer.allocate(size2);
568
0
                negate(operand2, StorageSpan<WordType, false> { inverted, size2 });
569
0
                data2 = inverted;
570
0
            }
571
15.1k
        }
572
15.1k
        size1 = min(size1, size), size2 = min(size2, size);
573
574
        // Do schoolbook O(size1 * size2).
575
15.1k
        DoubleWordType carry = 0;
576
196k
        for (size_t i = 0; i < size; ++i) {
577
181k
            result[i] = static_cast<WordType>(carry);
578
181k
            carry >>= word_size;
579
580
181k
            size_t start_index = i >= size2 ? i - size2 + 1 : 0;
581
181k
            size_t end_index = min(i + 1, size1);
582
583
1.00M
            for (size_t j = start_index; j < end_index; ++j) {
584
826k
                auto x = static_cast<DoubleWordType>(data1[j]) * data2[i - j];
585
586
826k
                bool ncarry = false;
587
826k
                result[i] = add_words(result[i], static_cast<WordType>(x), ncarry);
588
826k
                carry += (x >> word_size) + ncarry;
589
826k
            }
590
181k
        }
591
592
15.1k
        if (size2 < size && (sign1 ^ sign2))
593
0
            negate(result, result);
594
15.1k
    }
_ZN2AK6Detail17StorageOperationsImE12baseline_mulITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm64EEETkNS4_IS5_EES7_TkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm128EEERNS0_13NullAllocatorEEEvRKS5_RKT0_OT1_OT2_
Line
Count
Source
531
2.51M
    {
532
2.51M
        bool sign1 = operand1.is_negative(), sign2 = operand2.is_negative();
533
2.51M
        size_t size1 = operand1.size(), size2 = operand2.size(), size = result.size();
534
535
2.51M
        if (size1 == 1 && size2 == 1) {
536
            // We do not want to compete with the cleverness of the compiler of multiplying NativeWords.
537
2.51M
            ConditionallySignedDoubleWord<WordType, Operand1::is_signed> word1 = operand1[0];
538
2.51M
            ConditionallySignedDoubleWord<WordType, Operand2::is_signed> word2 = operand2[0];
539
2.51M
            auto value = static_cast<DoubleWordType>(word1 * word2);
540
541
2.51M
            result[0] = value;
542
2.51M
            if (size > 1) {
543
2.51M
                result[1] = value >> word_size;
544
545
2.51M
                auto fill = extend_sign<WordType>(sign1 ^ sign2);
546
2.51M
                for (size_t i = 2; i < result.size(); ++i)
547
0
                    result[i] = fill;
548
2.51M
            }
549
2.51M
            return;
550
2.51M
        }
551
552
0
        if (size1 < size2) {
553
0
            baseline_mul(operand2, operand1, result, buffer);
554
0
            return;
555
0
        }
556
        // Now size1 >= size2
557
558
        // Normalize signs
559
0
        auto data1 = operand1.data(), data2 = operand2.data();
560
0
        if (size2 < size) {
561
0
            if (sign1) {
562
0
                auto inverted = buffer.allocate(size1);
563
0
                negate(operand1, StorageSpan<WordType, false> { inverted, size1 });
564
0
                data1 = inverted;
565
0
            }
566
0
            if (sign2) {
567
0
                auto inverted = buffer.allocate(size2);
568
0
                negate(operand2, StorageSpan<WordType, false> { inverted, size2 });
569
0
                data2 = inverted;
570
0
            }
571
0
        }
572
0
        size1 = min(size1, size), size2 = min(size2, size);
573
574
        // Do schoolbook O(size1 * size2).
575
0
        DoubleWordType carry = 0;
576
0
        for (size_t i = 0; i < size; ++i) {
577
0
            result[i] = static_cast<WordType>(carry);
578
0
            carry >>= word_size;
579
580
0
            size_t start_index = i >= size2 ? i - size2 + 1 : 0;
581
0
            size_t end_index = min(i + 1, size1);
582
583
0
            for (size_t j = start_index; j < end_index; ++j) {
584
0
                auto x = static_cast<DoubleWordType>(data1[j]) * data2[i - j];
585
586
0
                bool ncarry = false;
587
0
                result[i] = add_words(result[i], static_cast<WordType>(x), ncarry);
588
0
                carry += (x >> word_size) + ncarry;
589
0
            }
590
0
        }
591
592
0
        if (size2 < size && (sign1 ^ sign2))
593
0
            negate(result, result);
594
0
    }
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE12baseline_mulITkNS0_22IntegerReadonlyStorageIT_EENS0_11StorageSpanImLb0EEETkNS4_IS5_EENS0_13StaticStorageILb0ELm64EEETkNS0_14IntegerStorageIS5_EES7_RNS0_13NullAllocatorEEEvRKS5_RKT0_OT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE12baseline_mulITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm64EEETkNS4_IS5_EENS0_11StorageSpanImLb0EEETkNS0_14IntegerStorageIS5_EERS9_RNS0_13NullAllocatorEEEvRKS5_RKT0_OT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE12baseline_mulITkNS0_22IntegerReadonlyStorageIT_EENS0_11StorageSpanImLb0EEETkNS4_IS5_EENS0_13StaticStorageILb0ELm64EEETkNS0_14IntegerStorageIS5_EERS7_RNS0_13NullAllocatorEEEvRKS5_RKT0_OT1_OT2_
_ZN2AK6Detail17StorageOperationsImE12baseline_mulITkNS0_22IntegerReadonlyStorageIT_EENS0_11StorageSpanImLb0EEETkNS4_IS5_EENS6_IKmLb0EEETkNS0_14IntegerStorageIS5_EES7_RNS0_13NullAllocatorEEEvRKS5_RKT0_OT1_OT2_
Line
Count
Source
531
15.1k
    {
532
15.1k
        bool sign1 = operand1.is_negative(), sign2 = operand2.is_negative();
533
15.1k
        size_t size1 = operand1.size(), size2 = operand2.size(), size = result.size();
534
535
15.1k
        if (size1 == 1 && size2 == 1) {
536
            // We do not want to compete with the cleverness of the compiler of multiplying NativeWords.
537
0
            ConditionallySignedDoubleWord<WordType, Operand1::is_signed> word1 = operand1[0];
538
0
            ConditionallySignedDoubleWord<WordType, Operand2::is_signed> word2 = operand2[0];
539
0
            auto value = static_cast<DoubleWordType>(word1 * word2);
540
541
0
            result[0] = value;
542
0
            if (size > 1) {
543
0
                result[1] = value >> word_size;
544
545
0
                auto fill = extend_sign<WordType>(sign1 ^ sign2);
546
0
                for (size_t i = 2; i < result.size(); ++i)
547
0
                    result[i] = fill;
548
0
            }
549
0
            return;
550
0
        }
551
552
15.1k
        if (size1 < size2) {
553
8.99k
            baseline_mul(operand2, operand1, result, buffer);
554
8.99k
            return;
555
8.99k
        }
556
        // Now size1 >= size2
557
558
        // Normalize signs
559
6.15k
        auto data1 = operand1.data(), data2 = operand2.data();
560
6.15k
        if (size2 < size) {
561
6.15k
            if (sign1) {
562
0
                auto inverted = buffer.allocate(size1);
563
0
                negate(operand1, StorageSpan<WordType, false> { inverted, size1 });
564
0
                data1 = inverted;
565
0
            }
566
6.15k
            if (sign2) {
567
0
                auto inverted = buffer.allocate(size2);
568
0
                negate(operand2, StorageSpan<WordType, false> { inverted, size2 });
569
0
                data2 = inverted;
570
0
            }
571
6.15k
        }
572
6.15k
        size1 = min(size1, size), size2 = min(size2, size);
573
574
        // Do schoolbook O(size1 * size2).
575
6.15k
        DoubleWordType carry = 0;
576
48.0k
        for (size_t i = 0; i < size; ++i) {
577
41.9k
            result[i] = static_cast<WordType>(carry);
578
41.9k
            carry >>= word_size;
579
580
41.9k
            size_t start_index = i >= size2 ? i - size2 + 1 : 0;
581
41.9k
            size_t end_index = min(i + 1, size1);
582
583
122k
            for (size_t j = start_index; j < end_index; ++j) {
584
80.6k
                auto x = static_cast<DoubleWordType>(data1[j]) * data2[i - j];
585
586
80.6k
                bool ncarry = false;
587
80.6k
                result[i] = add_words(result[i], static_cast<WordType>(x), ncarry);
588
80.6k
                carry += (x >> word_size) + ncarry;
589
80.6k
            }
590
41.9k
        }
591
592
6.15k
        if (size2 < size && (sign1 ^ sign2))
593
0
            negate(result, result);
594
6.15k
    }
_ZN2AK6Detail17StorageOperationsImE12baseline_mulITkNS0_22IntegerReadonlyStorageIT_EENS0_11StorageSpanIKmLb0EEETkNS4_IS5_EENS6_ImLb0EEETkNS0_14IntegerStorageIS5_EERS9_RNS0_13NullAllocatorEEEvRKS5_RKT0_OT1_OT2_
Line
Count
Source
531
8.99k
    {
532
8.99k
        bool sign1 = operand1.is_negative(), sign2 = operand2.is_negative();
533
8.99k
        size_t size1 = operand1.size(), size2 = operand2.size(), size = result.size();
534
535
8.99k
        if (size1 == 1 && size2 == 1) {
536
            // We do not want to compete with the cleverness of the compiler of multiplying NativeWords.
537
0
            ConditionallySignedDoubleWord<WordType, Operand1::is_signed> word1 = operand1[0];
538
0
            ConditionallySignedDoubleWord<WordType, Operand2::is_signed> word2 = operand2[0];
539
0
            auto value = static_cast<DoubleWordType>(word1 * word2);
540
541
0
            result[0] = value;
542
0
            if (size > 1) {
543
0
                result[1] = value >> word_size;
544
545
0
                auto fill = extend_sign<WordType>(sign1 ^ sign2);
546
0
                for (size_t i = 2; i < result.size(); ++i)
547
0
                    result[i] = fill;
548
0
            }
549
0
            return;
550
0
        }
551
552
8.99k
        if (size1 < size2) {
553
0
            baseline_mul(operand2, operand1, result, buffer);
554
0
            return;
555
0
        }
556
        // Now size1 >= size2
557
558
        // Normalize signs
559
8.99k
        auto data1 = operand1.data(), data2 = operand2.data();
560
8.99k
        if (size2 < size) {
561
8.99k
            if (sign1) {
562
0
                auto inverted = buffer.allocate(size1);
563
0
                negate(operand1, StorageSpan<WordType, false> { inverted, size1 });
564
0
                data1 = inverted;
565
0
            }
566
8.99k
            if (sign2) {
567
0
                auto inverted = buffer.allocate(size2);
568
0
                negate(operand2, StorageSpan<WordType, false> { inverted, size2 });
569
0
                data2 = inverted;
570
0
            }
571
8.99k
        }
572
8.99k
        size1 = min(size1, size), size2 = min(size2, size);
573
574
        // Do schoolbook O(size1 * size2).
575
8.99k
        DoubleWordType carry = 0;
576
148k
        for (size_t i = 0; i < size; ++i) {
577
139k
            result[i] = static_cast<WordType>(carry);
578
139k
            carry >>= word_size;
579
580
139k
            size_t start_index = i >= size2 ? i - size2 + 1 : 0;
581
139k
            size_t end_index = min(i + 1, size1);
582
583
885k
            for (size_t j = start_index; j < end_index; ++j) {
584
745k
                auto x = static_cast<DoubleWordType>(data1[j]) * data2[i - j];
585
586
745k
                bool ncarry = false;
587
745k
                result[i] = add_words(result[i], static_cast<WordType>(x), ncarry);
588
745k
                carry += (x >> word_size) + ncarry;
589
745k
            }
590
139k
        }
591
592
8.99k
        if (size2 < size && (sign1 ^ sign2))
593
0
            negate(result, result);
594
8.99k
    }
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE12baseline_mulITkNS0_22IntegerReadonlyStorageIT_EENS0_11StorageSpanImLb0EEETkNS4_IS5_EENS6_IKmLb0EEETkNS0_14IntegerStorageIS5_EERS7_RNS0_13NullAllocatorEEEvRKS5_RKT0_OT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE12baseline_mulITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm32EEETkNS4_IS5_EENS6_ILb0ELm4096EEETkNS0_14IntegerStorageIS5_EERS8_RNS0_13NullAllocatorEEEvRKS5_RKT0_OT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE12baseline_mulITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm4096EEETkNS4_IS5_EENS6_ILb0ELm32EEETkNS0_14IntegerStorageIS5_EERS7_RNS0_13NullAllocatorEEEvRKS5_RKT0_OT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE12baseline_mulITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm256EEETkNS4_IS5_EES7_TkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm512EEERNS0_13NullAllocatorEEEvRKS5_RKT0_OT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE12baseline_mulITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm256EEETkNS4_IS5_EES7_TkNS0_14IntegerStorageIS5_EERS7_RNS0_13NullAllocatorEEEvRKS5_RKT0_OT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE12baseline_mulITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm384EEETkNS4_IS5_EES7_TkNS0_14IntegerStorageIS5_EERNS6_ILb0ELm768EEERNS0_13NullAllocatorEEEvRKS5_RKT0_OT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE12baseline_mulITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm384EEETkNS4_IS5_EES7_TkNS0_14IntegerStorageIS5_EERS7_RNS0_13NullAllocatorEEEvRKS5_RKT0_OT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE12baseline_mulITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm257EEETkNS4_IS5_EES7_TkNS0_14IntegerStorageIS5_EERS7_RNS0_13NullAllocatorEEEvRKS5_RKT0_OT1_OT2_
Unexecuted instantiation: _ZN2AK6Detail17StorageOperationsImE12baseline_mulITkNS0_22IntegerReadonlyStorageIT_EENS0_13StaticStorageILb0ELm385EEETkNS4_IS5_EES7_TkNS0_14IntegerStorageIS5_EERS7_RNS0_13NullAllocatorEEEvRKS5_RKT0_OT1_OT2_
595
596
    template<bool restore_remainder = false>
597
    static constexpr void div_mod_internal(
598
        StorageSpan<WordType, false> dividend, StorageSpan<WordType, false> divisor,
599
        StorageSpan<WordType, false> quotient, StorageSpan<WordType, false> remainder,
600
        size_t dividend_len, size_t divisor_len)
601
0
    {
602
        // Knuth's algorithm D
603
        // D1. Normalize
604
        // FIXME: Investigate GCC producing bogus -Warray-bounds when dividing u128 by u32. This code
605
        //        should not be reachable at all in this case because fast paths above cover all cases
606
        //        when `operand2.size() == 1`.
607
0
        AK_IGNORE_DIAGNOSTIC("-Warray-bounds", size_t shift = count_leading_zeroes(divisor[divisor_len - 1]);)
608
0
        shift_left(dividend, shift, dividend);
609
0
        shift_left(divisor, shift, divisor);
610
611
0
        auto divisor_approx = divisor[divisor_len - 1];
612
613
0
        for (size_t i = dividend_len + 1; i-- > divisor_len;) {
614
            // D3. Calculate qhat
615
0
            WordType qhat;
616
0
            VERIFY(dividend[i] <= divisor_approx);
617
0
            if (dividend[i] == divisor_approx) {
618
0
                qhat = NumericLimits<WordType>::max();
619
0
            } else {
620
0
                WordType rhat;
621
0
                qhat = div_mod_words(dividend[i - 1], dividend[i], divisor_approx, rhat);
622
623
0
                auto is_qhat_too_large = [&] {
624
0
                    return wide_multiply(qhat, divisor[divisor_len - 2]) > dword(dividend[i - 2], rhat);
625
0
                };
Unexecuted instantiation: AK::Detail::StorageOperations<unsigned int>::div_mod_internal<true>(AK::Detail::StorageSpan<unsigned int, false>, AK::Detail::StorageSpan<unsigned int, false>, AK::Detail::StorageSpan<unsigned int, false>, AK::Detail::StorageSpan<unsigned int, false>, unsigned long, unsigned long)::{lambda()#1}::operator()() const
Unexecuted instantiation: AK::Detail::StorageOperations<unsigned long>::div_mod_internal<true>(AK::Detail::StorageSpan<unsigned long, false>, AK::Detail::StorageSpan<unsigned long, false>, AK::Detail::StorageSpan<unsigned long, false>, AK::Detail::StorageSpan<unsigned long, false>, unsigned long, unsigned long)::{lambda()#1}::operator()() const
626
0
                if (is_qhat_too_large()) {
627
0
                    --qhat;
628
0
                    bool carry = false;
629
0
                    rhat = add_words(rhat, divisor_approx, carry);
630
0
                    if (!carry && is_qhat_too_large())
631
0
                        --qhat;
632
0
                }
633
0
            }
634
635
            // D4. Multiply & subtract
636
0
            WordType mul_carry = 0;
637
0
            bool sub_carry = false;
638
0
            for (size_t j = 0; j < divisor_len; ++j) {
639
0
                auto mul_result = wide_multiply(qhat, divisor[j]) + mul_carry;
640
0
                auto& output = dividend[i + j - divisor_len];
641
0
                output = sub_words(output, static_cast<WordType>(mul_result), sub_carry);
642
0
                mul_carry = mul_result >> word_size;
643
0
            }
644
0
            dividend[i] = sub_words(dividend[i], mul_carry, sub_carry);
645
646
0
            if (sub_carry) {
647
                // D6. Add back
648
0
                auto dividend_part = StorageSpan<WordType, false> { dividend.slice(i - divisor_len, divisor_len + 1) };
649
0
                auto overflow = add<false>(dividend_part, divisor, dividend_part);
650
0
                VERIFY(overflow == 1);
651
0
            }
652
653
0
            quotient[i - divisor_len] = qhat - sub_carry;
654
0
        }
655
656
0
        for (size_t i = dividend_len - divisor_len + 1; i < quotient.size(); ++i)
657
0
            quotient[i] = 0;
658
659
        // D8. Unnormalize
660
        if constexpr (restore_remainder)
661
0
            shift_right(StorageSpan<WordType, false> { dividend.trim(remainder.size()) }, shift, remainder);
662
0
    }
Unexecuted instantiation: void AK::Detail::StorageOperations<unsigned long>::div_mod_internal<false>(AK::Detail::StorageSpan<unsigned long, false>, AK::Detail::StorageSpan<unsigned long, false>, AK::Detail::StorageSpan<unsigned long, false>, AK::Detail::StorageSpan<unsigned long, false>, unsigned long, unsigned long)
Unexecuted instantiation: void AK::Detail::StorageOperations<unsigned int>::div_mod_internal<true>(AK::Detail::StorageSpan<unsigned int, false>, AK::Detail::StorageSpan<unsigned int, false>, AK::Detail::StorageSpan<unsigned int, false>, AK::Detail::StorageSpan<unsigned int, false>, unsigned long, unsigned long)
Unexecuted instantiation: void AK::Detail::StorageOperations<unsigned long>::div_mod_internal<true>(AK::Detail::StorageSpan<unsigned long, false>, AK::Detail::StorageSpan<unsigned long, false>, AK::Detail::StorageSpan<unsigned long, false>, AK::Detail::StorageSpan<unsigned long, false>, unsigned long, unsigned long)
Unexecuted instantiation: void AK::Detail::StorageOperations<unsigned long>::div_mod_internal<true>(AK::Detail::StorageSpan<unsigned long, false>, AK::Detail::StorageSpan<unsigned long, false>, AK::Detail::StorageSpan<unsigned long, false>, AK::Detail::StorageSpan<unsigned long, false>, unsigned long, unsigned long)
663
};
664
665
}
666
667
using Detail::StorageOperations, Detail::NativeWord, Detail::native_word_size, Detail::max_native_word,
668
    Detail::UnsignedStorageSpan, Detail::UnsignedStorageReadonlySpan;
669
670
inline Detail::NullAllocator g_null_allocator;
671
672
}