ConstantTensorDescriptor.hip.hpp 16.9 KB
Newer Older
Chao Liu's avatar
Chao Liu committed
1
#pragma once
2
#include "common.hip.hpp"
Chao Liu's avatar
Chao Liu committed
3

4
template <class Lengths>
Chao Liu's avatar
Chao Liu committed
5
__host__ __device__ constexpr auto calculate_tensor_strides_packed(Lengths)
6
{
7
    return reverse_inclusive_scan_sequence(Lengths{}.PopFront(), mod_conv::multiplies<index_t>{})
8
        .PushBack(Number<1>{});
9
10
}

11
template <class Lengths, index_t Align>
Chao Liu's avatar
Chao Liu committed
12
__host__ __device__ constexpr auto calculate_tensor_strides_aligned(Lengths, Number<Align>)
Chao Liu's avatar
Chao Liu committed
13
{
14
15
    constexpr index_t L_back_align =
        Align * mod_conv::integer_divide_ceiler<index_t>{}(Lengths{}.Back(), Align);
Chao Liu's avatar
Chao Liu committed
16

Chao Liu's avatar
Chao Liu committed
17
    return calculate_tensor_strides_packed(
18
        Lengths{}.Modify(Number<Lengths{}.GetSize() - 1>{}, Number<L_back_align>{}));
19
20
}

Chao Liu's avatar
Chao Liu committed
21
template <class Lengths, class Strides>
Chao Liu's avatar
Chao Liu committed
22
23
struct ConstantTensorDescriptor
{
Chao Liu's avatar
Chao Liu committed
24
25
    using Type = ConstantTensorDescriptor;

26
    static constexpr index_t nDim = Lengths::GetSize();
Chao Liu's avatar
Chao Liu committed
27
28
29

    __host__ __device__ constexpr ConstantTensorDescriptor()
    {
Chao Liu's avatar
Chao Liu committed
30
        static_assert(Lengths::GetSize() == Strides::GetSize(), "nDim not consistent");
Chao Liu's avatar
Chao Liu committed
31
32
    }

33
34
35
36
37
38
39
40
    __host__ __device__ static constexpr auto GetOriginalTensorDescriptor() { return Type{}; }

    template <index_t IDim>
    __host__ __device__ static constexpr auto GetContainedOriginalDimensions(Number<IDim>)
    {
        return Sequence<IDim>{};
    }

Chao Liu's avatar
Chao Liu committed
41
    __host__ __device__ static constexpr index_t GetNumOfDimension() { return nDim; }
Chao Liu's avatar
Chao Liu committed
42

43
    __host__ __device__ static constexpr auto GetLengths() { return Lengths{}; }
Chao Liu's avatar
Chao Liu committed
44

45
46
    __host__ __device__ static constexpr auto GetStrides() { return Strides{}; }

Chao Liu's avatar
Chao Liu committed
47
    template <index_t I>
48
    __host__ __device__ static constexpr index_t GetLength(Number<I>)
Chao Liu's avatar
Chao Liu committed
49
    {
Chao Liu's avatar
Chao Liu committed
50
        return Lengths{}.Get(Number<I>{});
Chao Liu's avatar
Chao Liu committed
51
52
    }

Chao Liu's avatar
Chao Liu committed
53
    template <index_t I>
54
    __host__ __device__ static constexpr index_t GetStride(Number<I>)
Chao Liu's avatar
Chao Liu committed
55
    {
Chao Liu's avatar
Chao Liu committed
56
        return Strides{}.Get(Number<I>{});
Chao Liu's avatar
Chao Liu committed
57
58
    }

59
60
61
62
63
64
65
66
67
68
69
70
71
    __host__ __device__ static constexpr bool AreStridesNonAscending()
    {
        bool flag = true;

        static_for<0, nDim - 1, 1>{}([&](auto IDim) {
            constexpr auto IDim_p1 = Number<IDim.Get() + 1>{};

            flag = flag && (GetLength(IDim) >= GetLength(IDim_p1));
        });

        return flag;
    }

Chao Liu's avatar
Chao Liu committed
72
73
74
75
76
77
    template <class T>
    __host__ __device__ static constexpr bool ContainMultipleOriginalDimensions(T)
    {
        return false;
    }

78
    __host__ __device__ static constexpr index_t GetElementSize()
Chao Liu's avatar
Chao Liu committed
79
    {
80
        return accumulate_on_sequence(Lengths{}, mod_conv::multiplies<index_t>{}, Number<1>{});
81
    }
82

Chao Liu's avatar
Chao Liu committed
83
    template <class Align = Number<1>>
84
    __host__ __device__ static constexpr index_t GetElementSpace(Align align = Align{})
Chao Liu's avatar
Chao Liu committed
85
    {
Chao Liu's avatar
Chao Liu committed
86
87
        // This is WRONG! align shouldbe applied to the last memory rank, not the last tensor
        // dimension
Chao Liu's avatar
Chao Liu committed
88
        constexpr index_t element_space_unaligned = accumulate_on_sequence(
89
            (GetLengths() - Number<1>{}) * GetStrides(), mod_conv::plus<index_t>{}, Number<1>{});
Chao Liu's avatar
Chao Liu committed
90
91

        return align.Get() * ((element_space_unaligned + align.Get() - 1) / align.Get());
Chao Liu's avatar
Chao Liu committed
92
    }
Chao Liu's avatar
Chao Liu committed
93

94
    template <index_t NSize>
95
    __host__ __device__ static index_t GetOffsetFromMultiIndex(Array<index_t, NSize> multi_id)
Chao Liu's avatar
Chao Liu committed
96
    {
97
        static_assert(NSize == nDim, "wrong! Dimension not consistent");
Chao Liu's avatar
Chao Liu committed
98

99
        index_t offset = 0;
Chao Liu's avatar
Chao Liu committed
100

101
        static_for<0, nDim, 1>{}([&](auto IDim) {
Chao Liu's avatar
Chao Liu committed
102
            constexpr index_t idim = IDim.Get();
103
            offset += multi_id[idim] * GetStride(IDim);
104
        });
Chao Liu's avatar
Chao Liu committed
105

106
        return offset;
107
108
    }

109
    template <class... Is>
110
    __host__ __device__ static index_t GetOffsetFromMultiIndex(Is... is)
111
    {
112
        return GetOffsetFromMultiIndex(Array<index_t, sizeof...(Is)>{is...});
113
114
    }

115
    template <index_t... Is>
116
    __host__ __device__ static constexpr index_t GetOffsetFromMultiIndex(Sequence<Is...>)
117
118
119
    {
        static_assert(sizeof...(Is) == nDim, "wrong! Dimension not consistent");

Chao Liu's avatar
Chao Liu committed
120
121
        constexpr auto multi_id = Sequence<Is...>{};

122
123
        return accumulate_on_sequence(
            multi_id * GetStrides(), mod_conv::plus<index_t>{}, Number<0>{});
124
125
    }

126
    __host__ __device__ static Array<index_t, nDim> GetMultiIndexFrom1dIndex(index_t id)
127
    {
128
129
        Array<index_t, nDim> multi_id;

Chao Liu's avatar
Chao Liu committed
130
        constexpr auto dummy_strides = calculate_tensor_strides_packed(GetLengths());
131

Chao Liu's avatar
Chao Liu committed
132
        // calculate index in each of the dimensions in the order of their dimension
133
134
135
136
137
138
139
140
141
142
        static_for<0, nDim - 1, 1>{}([&](auto IDim) {
            constexpr index_t idim   = IDim.Get();
            constexpr index_t stride = dummy_strides.Get(Number<idim>{});
            multi_id[idim]           = id / stride;
            id -= multi_id[idim] * stride;
        });

        multi_id[nDim - 1] = id / dummy_strides.Get(Number<nDim - 1>{});

        return multi_id;
143
    }
Chao Liu's avatar
Chao Liu committed
144

145
146
147
148
149
150
151
152
153
    __host__ __device__ static auto
    GetOriginalMultiIndexFromMultiIndex(Array<index_t, nDim> multi_id)
    {
        return multi_id;
    }

    // This function doesn't do carry check on the highest dimension, for performance reason.
    // It is the user's responsibility to make sure the result "new_mutli_id" is not out-of-bound
    // on the highest dimension
154
    template <bool PositiveDirection>
155
156
    __host__ __device__ static Array<index_t, nDim>
    UpdateMultiIndexGivenStepSizeOf1dIndex(Array<index_t, nDim> old_multi_id,
157
158
                                           index_t step_size_of_1d_index,
                                           integral_constant<bool, PositiveDirection>)
159
    {
160
161
162
163
164
165
166
167
168
169
170
        Array<index_t, nDim> new_multi_id;

        const auto step_sizes = GetMultiIndexFrom1dIndex(step_size_of_1d_index);

        static_if<PositiveDirection>{}([&](auto) {
            new_multi_id = old_multi_id + step_sizes;

            bool carry = false;

            // do carry check in reversed order, starting from lowest dimension
            // don't check the highest dimension
Chao Liu's avatar
Chao Liu committed
171
            static_for<0, nDim, 1>{}([&](auto IDimReverse) {
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
                constexpr index_t idim = nDim - 1 - IDimReverse.Get();
                constexpr auto IDim    = Number<idim>{};

                if(carry)
                {
                    ++new_multi_id[idim];
                }

                carry = false;

                if(new_multi_id[idim] >= GetLength(IDim))
                {
                    new_multi_id[idim] -= GetLength(IDim);
                    carry = true;
                }
            });
        }).Else([&](auto) {
            // shift up multi-id to avoid unsigned integer underflow during intermediate
            // calculations. After the shift, should have new_multi_id[...] >= 1
            new_multi_id = old_multi_id + (GetLengths() - step_sizes);

            bool borrow = false;

            // do borrow check in reversed order, starting from lowest dimension
            // don't check the highest dimension
Chao Liu's avatar
Chao Liu committed
197
            static_for<0, nDim, 1>{}([&](auto IDimReverse) {
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
                constexpr index_t idim = nDim - 1 - IDimReverse.Get();
                constexpr auto IDim    = Number<idim>{};

                if(borrow)
                {
                    --new_multi_id[idim];
                }

                borrow = false;

                if(new_multi_id[idim] < GetLength(IDim))
                {
                    new_multi_id[idim] += GetLength(IDim);
                    borrow = true;
                }
            });

            // shift back down multi-id
            // here, should have new_multi_id[...] >= GetLengths()
            new_multi_id = new_multi_id - GetLengths();
218
219
220
221
222
        });

        return new_multi_id;
    }

Chao Liu's avatar
Chao Liu committed
223
    template <index_t... IDims>
Chao Liu's avatar
Chao Liu committed
224
    __host__ __device__ static constexpr auto Extract(Number<IDims>... extract_dims)
Chao Liu's avatar
Chao Liu committed
225
    {
Chao Liu's avatar
Chao Liu committed
226
227
        static_assert(sizeof...(IDims) <= GetNumOfDimension(),
                      "wrong! too many number of dimensions to be extracted");
Chao Liu's avatar
Chao Liu committed
228

Chao Liu's avatar
Chao Liu committed
229
230
        using extract_lengths = decltype(Lengths::Extract(extract_dims...));
        using extract_strides = decltype(Strides::Extract(extract_dims...));
231

Chao Liu's avatar
Chao Liu committed
232
        return ConstantTensorDescriptor<extract_lengths, extract_strides>{};
Chao Liu's avatar
Chao Liu committed
233
234
    }

Chao Liu's avatar
Chao Liu committed
235
236
237
238
239
240
    template <index_t... IDims>
    __host__ __device__ static constexpr auto Extract(Sequence<IDims...>)
    {
        return Extract(Number<IDims>{}...);
    }

241
    template <class... Ts>
242
    __host__ __device__ static constexpr auto Embed(ConstantTensorDescriptor<Ts...>)
243
244
245
246
    {
        using leaf_tensor = ConstantTensorDescriptor<Ts...>;

        return ConstantTensorDescriptor<decltype(GetLengths().Append(leaf_tensor::GetLengths())),
Chao Liu's avatar
Chao Liu committed
247
                                        decltype(GetStrides().Append(leaf_tensor::GetStrides()))>{};
248
249
    }

Chao Liu's avatar
Chao Liu committed
250
251
252
    template <index_t IDim, index_t SliceLen>
    __host__ __device__ static constexpr auto Slice(Number<IDim>, Number<SliceLen>)
    {
253
254
        using slice_lengths = decltype(Lengths{}.Modify(Number<IDim>{}, Number<SliceLen>{}));

Chao Liu's avatar
Chao Liu committed
255
        return ConstantTensorDescriptor<slice_lengths, Strides>{};
Chao Liu's avatar
Chao Liu committed
256
257
    }

Chao Liu's avatar
Chao Liu committed
258
    template <index_t IDim, index_t... FoldIntervals>
Chao Liu's avatar
Chao Liu committed
259
    __host__ __device__ static constexpr auto Fold(Number<IDim>, Number<FoldIntervals>...)
Chao Liu's avatar
Chao Liu committed
260
    {
Chao Liu's avatar
Chao Liu committed
261
262
        constexpr auto fold_intervals = Sequence<FoldIntervals...>{};

Chao Liu's avatar
Chao Liu committed
263
        constexpr index_t fold_intervals_product =
264
            accumulate_on_sequence(fold_intervals, mod_conv::multiplies<index_t>{}, Number<1>{});
Chao Liu's avatar
Chao Liu committed
265
266
267
268
269
270

        constexpr auto unfold_length = GetLength(Number<IDim>{});
        constexpr auto unfold_stride = GetStride(Number<IDim>{});

        // length of the dimension to be folded needs to be dividable by fold_interval_product,
        // otherwise, folding is invalid
Chao Liu's avatar
Chao Liu committed
271
        static_assert(unfold_length % fold_intervals_product == 0,
Chao Liu's avatar
Chao Liu committed
272
273
274
275
                      "wrong! length on the dimension to be folded cannot be evenly divided!");

        // folded lengths
        constexpr auto fold_lengths =
Chao Liu's avatar
Chao Liu committed
276
            Sequence<unfold_length / fold_intervals_product>{}.Append(fold_intervals);
Chao Liu's avatar
Chao Liu committed
277
278

        // folded strides
Chao Liu's avatar
Chao Liu committed
279
280
        constexpr auto fold_strides =
            Number<unfold_stride>{} *
Chao Liu's avatar
Chao Liu committed
281
            reverse_inclusive_scan_sequence(fold_intervals.PushBack(Number<1>{}),
282
                                            mod_conv::multiplies<index_t>{});
Chao Liu's avatar
Chao Liu committed
283

284
285
286
287
288
289
290
291
292
293
        // left and right
        constexpr auto left = typename arithmetic_sequence_gen<0, IDim, 1>::SeqType{};
        constexpr auto right =
            typename arithmetic_sequence_gen<IDim + 1, GetNumOfDimension(), 1>::SeqType{};

        constexpr auto new_lengths =
            GetLengths().Extract(left).Append(fold_lengths).Append(GetLengths().Extract(right));
        constexpr auto new_strides =
            GetStrides().Extract(left).Append(fold_strides).Append(GetStrides().Extract(right));

Chao Liu's avatar
Chao Liu committed
294
        return ConstantTensorDescriptor<decltype(new_lengths), decltype(new_strides)>{};
Chao Liu's avatar
Chao Liu committed
295
296
    }

297
298
299
300
301
302
303
304
305
    template <index_t Threashold, index_t Delta>
    struct f_unfold_impl
    {
        __host__ __device__ constexpr index_t operator()(index_t x) const
        {
            return x > Threashold ? x - Delta : x;
        }
    };

Chao Liu's avatar
Chao Liu committed
306
307
308
    template <index_t FirstUnfoldDim, index_t LastUnfoldDim>
    __host__ __device__ static constexpr auto Unfold(Number<FirstUnfoldDim>, Number<LastUnfoldDim>)
    {
Chao Liu's avatar
Chao Liu committed
309
310
311
312
        static_assert(FirstUnfoldDim >= 0 && LastUnfoldDim < nDim &&
                          FirstUnfoldDim <= LastUnfoldDim,
                      "wrong! should have FirstUnfoldDim <= LastUnfoldDim!");

Chao Liu's avatar
Chao Liu committed
313
#if 0 // cannot compile: compiler complain about constexpr
Chao Liu's avatar
Chao Liu committed
314
315
        // dimensions to be unfold need to be in descending order (w.r.t. strides), and need to be
        // packed in memory, otherwise, unfolding is invalid
Chao Liu's avatar
Chao Liu committed
316
317
        static_for<FirstUnfoldDim, LastUnfoldDim, 1>{}([&](auto IDim_) {
            constexpr auto IDim    = decltype(IDim_){};
318
319
320
            constexpr auto IDim_p1 = IDim + Number<1>{};

            // check stride
Chao Liu's avatar
Chao Liu committed
321
            static_assert(
322
                GetStride(IDim) >= GetStride(IDim_p1),
Chao Liu's avatar
Chao Liu committed
323
324
                "wrong! dimensions to be unfolded need to be in descending order w.r.t strides");

325
326
            // check if packed
            static_assert(GetStride(IDim_p1) * GetLength(IDim_p1) == GetStride(IDim),
Chao Liu's avatar
Chao Liu committed
327
328
                          "wrong! dimensions to be unfolded need to be packed");
        });
Chao Liu's avatar
Chao Liu committed
329
#endif
Chao Liu's avatar
Chao Liu committed
330

Chao Liu's avatar
Chao Liu committed
331
        // left and right
332
333
334
335
336
337
        constexpr auto left = typename arithmetic_sequence_gen<0, FirstUnfoldDim, 1>::SeqType{};
        constexpr auto middle =
            typename arithmetic_sequence_gen<FirstUnfoldDim, LastUnfoldDim + 1, 1>::SeqType{};
        constexpr auto right =
            typename arithmetic_sequence_gen<LastUnfoldDim + 1, GetNumOfDimension(), 1>::SeqType{};

Chao Liu's avatar
Chao Liu committed
338
        // unfolded length, stride
Chao Liu's avatar
Chao Liu committed
339
        constexpr index_t unfold_length = accumulate_on_sequence(
340
            GetLengths().Extract(middle), mod_conv::multiplies<index_t>{}, Number<1>{});
Chao Liu's avatar
Chao Liu committed
341
342
343

        constexpr index_t unfold_stride = GetStride(Number<LastUnfoldDim>{});

Chao Liu's avatar
Chao Liu committed
344
        // new lengths, strides
345
346
347
348
349
350
351
352
353
354
        constexpr auto new_lengths = GetLengths()
                                         .Extract(left)
                                         .PushBack(Number<unfold_length>{})
                                         .Append(GetLengths().Extract(right));

        constexpr auto new_strides = GetStrides()
                                         .Extract(left)
                                         .PushBack(Number<unfold_stride>{})
                                         .Append(GetStrides().Extract(right));

Chao Liu's avatar
Chao Liu committed
355
        return ConstantTensorDescriptor<decltype(new_lengths), decltype(new_strides)>{};
356
357
358
359
360
361
    }

    template <class MapNew2Old>
    __host__ __device__ static constexpr auto ReorderGivenNew2Old(MapNew2Old)
    {
        return ConstantTensorDescriptor<decltype(Lengths{}.ReorderGivenNew2Old(MapNew2Old{})),
Chao Liu's avatar
Chao Liu committed
362
                                        decltype(Strides{}.ReorderGivenNew2Old(MapNew2Old{}))>{};
Chao Liu's avatar
Chao Liu committed
363
364
    }

365
366
367
#if 0 // require sequence_sort, which is not implemented yet
    template <class MapOld2New>
    __host__ __device__ static constexpr auto ReorderGivenOld2New(MapOld2New)
Chao Liu's avatar
Chao Liu committed
368
    {
369
        return ConstantTensorDescriptor<decltype(Lengths{}.ReorderGivenOld2New(MapOld2New{})),
Chao Liu's avatar
Chao Liu committed
370
                                        decltype(Strides{}.ReorderGivenOld2New(MapOld2New{}))>{}
Chao Liu's avatar
Chao Liu committed
371
    }
372
#endif
Chao Liu's avatar
Chao Liu committed
373
};
Chao Liu's avatar
Chao Liu committed
374
375

template <class Lengths>
Chao Liu's avatar
Chao Liu committed
376
__host__ __device__ constexpr auto make_ConstantTensorDescriptor_packed(Lengths)
Chao Liu's avatar
Chao Liu committed
377
{
Chao Liu's avatar
Chao Liu committed
378
379
    using Strides = decltype(calculate_tensor_strides_packed(Lengths{}));
    return ConstantTensorDescriptor<Lengths, Strides>{};
Chao Liu's avatar
Chao Liu committed
380
381
382
}

template <class Lengths, class Strides>
Chao Liu's avatar
Chao Liu committed
383
__host__ __device__ constexpr auto make_ConstantTensorDescriptor(Lengths, Strides)
Chao Liu's avatar
Chao Liu committed
384
{
Chao Liu's avatar
Chao Liu committed
385
    return ConstantTensorDescriptor<Lengths, Strides>{};
Chao Liu's avatar
Chao Liu committed
386
387
}

Chao Liu's avatar
Chao Liu committed
388
template <class Lengths, index_t Align>
Chao Liu's avatar
Chao Liu committed
389
__host__ __device__ constexpr auto make_ConstantTensorDescriptor_aligned(Lengths, Number<Align>)
Chao Liu's avatar
Chao Liu committed
390
{
Chao Liu's avatar
Chao Liu committed
391
392
    using Strides = decltype(calculate_tensor_strides_aligned(Lengths{}, Number<Align>{}));
    return ConstantTensorDescriptor<Lengths, Strides>{};
Chao Liu's avatar
Chao Liu committed
393
394
}

Chao Liu's avatar
Chao Liu committed
395
396
397
398
template <index_t... Lengths, index_t... Strides>
__host__ __device__ void
print_ConstantTensorDescriptor(const char* s,
                               ConstantTensorDescriptor<Sequence<Lengths...>, Sequence<Strides...>>)
Chao Liu's avatar
Chao Liu committed
399
{
Chao Liu's avatar
Chao Liu committed
400
    constexpr index_t ndim = sizeof...(Lengths);
401

Chao Liu's avatar
Chao Liu committed
402
    static_assert(ndim > 0 && ndim <= 10, "wrong!");
403

Chao Liu's avatar
Chao Liu committed
404
405
    static_if<ndim == 1>{}([&](auto) {
        printf("%s dim %u, lengths {%u}, strides {%u}\n", s, ndim, Lengths..., Strides...);
406
    });
Chao Liu's avatar
Chao Liu committed
407

Chao Liu's avatar
Chao Liu committed
408
409
    static_if<ndim == 2>{}([&](auto) {
        printf("%s dim %u, lengths {%u %u}, strides {%u %u}\n", s, ndim, Lengths..., Strides...);
Chao Liu's avatar
Chao Liu committed
410
411
    });

Chao Liu's avatar
Chao Liu committed
412
413
414
    static_if<ndim == 3>{}([&](auto) {
        printf(
            "%s dim %u, lengths {%u %u %u}, strides {%u %u %u}\n", s, ndim, Lengths..., Strides...);
Chao Liu's avatar
Chao Liu committed
415
416
    });

Chao Liu's avatar
Chao Liu committed
417
418
    static_if<ndim == 4>{}([&](auto) {
        printf("%s dim %u, lengths {%u %u %u %u}, strides {%u %u %u %u}\n",
Chao Liu's avatar
Chao Liu committed
419
               s,
Chao Liu's avatar
Chao Liu committed
420
421
422
               ndim,
               Lengths...,
               Strides...);
Chao Liu's avatar
Chao Liu committed
423
424
    });

Chao Liu's avatar
Chao Liu committed
425
426
    static_if<ndim == 5>{}([&](auto) {
        printf("%s dim %u, lengths {%u %u %u %u %u}, strides {%u %u %u %u %u}\n",
427
               s,
Chao Liu's avatar
Chao Liu committed
428
429
430
               ndim,
               Lengths...,
               Strides...);
Chao Liu's avatar
Chao Liu committed
431
432
    });

Chao Liu's avatar
Chao Liu committed
433
434
    static_if<ndim == 6>{}([&](auto) {
        printf("%s dim %u, lengths {%u %u %u %u %u %u}, strides {%u %u %u %u %u %u}\n",
435
               s,
Chao Liu's avatar
Chao Liu committed
436
437
438
               ndim,
               Lengths...,
               Strides...);
Chao Liu's avatar
Chao Liu committed
439
440
    });

Chao Liu's avatar
Chao Liu committed
441
442
    static_if<ndim == 7>{}([&](auto) {
        printf("%s dim %u, lengths {%u %u %u %u %u %u %u}, strides {%u %u %u %u %u %u %u}\n",
443
               s,
Chao Liu's avatar
Chao Liu committed
444
445
446
               ndim,
               Lengths...,
               Strides...);
Chao Liu's avatar
Chao Liu committed
447
448
    });

Chao Liu's avatar
Chao Liu committed
449
450
    static_if<ndim == 8>{}([&](auto) {
        printf("%s dim %u, lengths {%u %u %u %u %u %u %u %u}, strides {%u %u %u %u %u %u %u %u}\n",
451
               s,
Chao Liu's avatar
Chao Liu committed
452
453
454
               ndim,
               Lengths...,
               Strides...);
Chao Liu's avatar
Chao Liu committed
455
456
    });

Chao Liu's avatar
Chao Liu committed
457
    static_if<ndim == 9>{}([&](auto) {
Chao Liu's avatar
tidy yp  
Chao Liu committed
458
        printf("%s dim %u, lengths {%u %u %u %u %u %u %u %u %u}, strides {%u %u %u %u %u %u %u %u "
Chao Liu's avatar
Chao Liu committed
459
               "%u}\n",
Chao Liu's avatar
Chao Liu committed
460
               s,
Chao Liu's avatar
Chao Liu committed
461
462
463
               ndim,
               Lengths...,
               Strides...);
Chao Liu's avatar
Chao Liu committed
464
465
    });

Chao Liu's avatar
Chao Liu committed
466
    static_if<ndim == 10>{}([&](auto) {
Chao Liu's avatar
tidy yp  
Chao Liu committed
467
        printf("%s dim %u, lengths {%u %u %u %u %u %u %u %u %u %u}, strides {%u %u %u %u %u %u %u "
Chao Liu's avatar
Chao Liu committed
468
               "%u %u %u}\n",
Chao Liu's avatar
Chao Liu committed
469
               s,
Chao Liu's avatar
Chao Liu committed
470
471
472
               ndim,
               Lengths...,
               Strides...);
Chao Liu's avatar
Chao Liu committed
473
    });
Chao Liu's avatar
Chao Liu committed
474
}