LCOV - code coverage report
Current view: top level - vppinfra - vector_avx2.h (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 26 32 81.2 %
Date: 2023-10-26 01:39:38 Functions: 29 36 80.6 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2018 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : #ifndef included_vector_avx2_h
      17             : #define included_vector_avx2_h
      18             : 
      19             : #include <vppinfra/clib.h>
      20             : #include <x86intrin.h>
      21             : 
      22             : /* *INDENT-OFF* */
      23             : #define foreach_avx2_vec256i \
      24             :   _(i,8,32,epi8) _(i,16,16,epi16) _(i,32,8,epi32)  _(i,64,4,epi64)
      25             : #define foreach_avx2_vec256u \
      26             :   _(u,8,32,epi8) _(u,16,16,epi16) _(u,32,8,epi32)  _(u,64,4,epi64)
      27             : #define foreach_avx2_vec256f \
      28             :   _(f,32,8,ps) _(f,64,4,pd)
      29             : 
      30             : #define _mm256_set1_epi64 _mm256_set1_epi64x
      31             : 
      32             : /* splat, load_unaligned, store_unaligned, is_all_zero, is_equal,
      33             :    is_all_equal */
      34             : #define _(t, s, c, i) \
      35             : static_always_inline t##s##x##c                                         \
      36             : t##s##x##c##_splat (t##s x)                                             \
      37             : { return (t##s##x##c) _mm256_set1_##i (x); }                            \
      38             : \
      39             : static_always_inline t##s##x##c                                         \
      40             : t##s##x##c##_load_unaligned (void *p)                                   \
      41             : { return (t##s##x##c) _mm256_loadu_si256 (p); }                         \
      42             : \
      43             : static_always_inline void                                               \
      44             : t##s##x##c##_store_unaligned (t##s##x##c v, void *p)                    \
      45             : { _mm256_storeu_si256 ((__m256i *) p, (__m256i) v); }                   \
      46             : \
      47             : static_always_inline int                                                \
      48             : t##s##x##c##_is_all_zero (t##s##x##c x)                                 \
      49             : { return _mm256_testz_si256 ((__m256i) x, (__m256i) x); }               \
      50             : \
      51             : static_always_inline int                                                \
      52             : t##s##x##c##_is_equal (t##s##x##c a, t##s##x##c b)                      \
      53             : { return t##s##x##c##_is_all_zero (a ^ b); }                            \
      54             : \
      55             : static_always_inline int                                                \
      56             : t##s##x##c##_is_all_equal (t##s##x##c v, t##s x)                        \
      57             : { return t##s##x##c##_is_equal (v, t##s##x##c##_splat (x)); }           \
      58             : \
      59             : static_always_inline t##s##x##c                                         \
      60             : t##s##x##c##_interleave_lo (t##s##x##c a, t##s##x##c b)                 \
      61             : { return (t##s##x##c) _mm256_unpacklo_##i ((__m256i) a, (__m256i) b); } \
      62             : \
      63             : static_always_inline t##s##x##c                                         \
      64             : t##s##x##c##_interleave_hi (t##s##x##c a, t##s##x##c b)                 \
      65             : { return (t##s##x##c) _mm256_unpackhi_##i ((__m256i) a, (__m256i) b); } \
      66             : 
      67             : 
      68 17435973162 : foreach_avx2_vec256i foreach_avx2_vec256u
      69             : #undef _
      70             : /* *INDENT-ON* */
      71             : 
      72             : always_inline u32x8
      73          20 : u32x8_permute (u32x8 v, u32x8 idx)
      74             : {
      75          40 :   return (u32x8) _mm256_permutevar8x32_epi32 ((__m256i) v, (__m256i) idx);
      76             : }
      77             : 
      78             : #define u64x4_permute(v, m0, m1, m2, m3)                                      \
      79             :   (u64x4) _mm256_permute4x64_epi64 (                                          \
      80             :     (__m256i) v, ((m0) | (m1) << 2 | (m2) << 4 | (m3) << 6))
      81             : 
      82             : /* _extract_lo, _extract_hi */
      83             : /* *INDENT-OFF* */
      84             : #define _(t1,t2) \
      85             : always_inline t1                                                        \
      86             : t2##_extract_lo (t2 v)                                                  \
      87             : { return (t1) _mm256_extracti128_si256 ((__m256i) v, 0); }              \
      88             : \
      89             : always_inline t1                                                        \
      90             : t2##_extract_hi (t2 v)                                                  \
      91             : { return (t1) _mm256_extracti128_si256 ((__m256i) v, 1); }              \
      92             : \
      93             : always_inline t2                                                        \
      94             : t2##_insert_lo (t2 v1, t1 v2)                                           \
      95             : { return (t2) _mm256_inserti128_si256 ((__m256i) v1, (__m128i) v2, 0); }\
      96             : \
      97             : always_inline t2                                                        \
      98             : t2##_insert_hi (t2 v1, t1 v2)                                           \
      99             : { return (t2) _mm256_inserti128_si256 ((__m256i) v1, (__m128i) v2, 1); }\
     100             : 
     101           0 : _(u8x16, u8x32)
     102             : _(u16x8, u16x16)
     103           0 : _(u32x4, u32x8)
     104    29221042 : _(u64x2, u64x4)
     105             : #undef _
     106             : /* *INDENT-ON* */
     107             : 
     108             : /* 256 bit packs. */
     109             : #define _(f, t, fn)                                                           \
     110             :   always_inline t t##_pack (f lo, f hi)                                       \
     111             :   {                                                                           \
     112             :     return (t) fn ((__m256i) lo, (__m256i) hi);                               \
     113             :   }
     114             : 
     115    48475640 : _ (i16x16, i8x32, _mm256_packs_epi16)
     116             : _ (i16x16, u8x32, _mm256_packus_epi16)
     117          80 : _ (i32x8, i16x16, _mm256_packs_epi32)
     118             : _ (i32x8, u16x16, _mm256_packus_epi32)
     119             : 
     120             : #undef _
     121             : 
     122             : static_always_inline u32
     123     3692660 : u8x32_msb_mask (u8x32 v)
     124             : {
     125     7385330 :   return _mm256_movemask_epi8 ((__m256i) v);
     126             : }
     127             : 
     128             : static_always_inline u32
     129    24237820 : i8x32_msb_mask (i8x32 v)
     130             : {
     131    48475640 :   return _mm256_movemask_epi8 ((__m256i) v);
     132             : }
     133             : 
     134             : /* _from_ */
     135             : /* *INDENT-OFF* */
     136             : #define _(f,t,i) \
     137             : static_always_inline t                                                  \
     138             : t##_from_##f (f x)                                                      \
     139             : { return (t) _mm256_cvt##i ((__m128i) x); }
     140             : 
     141             : _(u16x8, u32x8, epu16_epi32)
     142             : _(u16x8, u64x4, epu16_epi64)
     143   374608290 : _(u32x4, u64x4, epu32_epi64)
     144             : _ (u8x16, u16x16, epu8_epi16)
     145             : _(u8x16, u32x8, epu8_epi32)
     146             : _(u8x16, u64x4, epu8_epi64)
     147             : _(i16x8, i32x8, epi16_epi32)
     148             : _(i16x8, i64x4, epi16_epi64)
     149             : _(i32x4, i64x4, epi32_epi64)
     150             : _ (i8x16, i16x16, epi8_epi16)
     151             : _(i8x16, i32x8, epi8_epi32)
     152             : _(i8x16, i64x4, epi8_epi64)
     153             : #undef _
     154             : /* *INDENT-ON* */
     155             : 
     156             : static_always_inline u64x4
     157             : u64x4_byte_swap (u64x4 v)
     158             : {
     159             :   u8x32 swap = {
     160             :     7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8,
     161             :     7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8,
     162             :   };
     163             :   return (u64x4) _mm256_shuffle_epi8 ((__m256i) v, (__m256i) swap);
     164             : }
     165             : 
     166             : static_always_inline u32x8
     167             : u32x8_byte_swap (u32x8 v)
     168             : {
     169             :   u8x32 swap = {
     170             :     3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12,
     171             :     3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12
     172             :   };
     173             :   return (u32x8) _mm256_shuffle_epi8 ((__m256i) v, (__m256i) swap);
     174             : }
     175             : 
     176             : static_always_inline u16x16
     177             : u16x16_byte_swap (u16x16 v)
     178             : {
     179             :   u8x32 swap = {
     180             :     1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14,
     181             :     1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14
     182             :   };
     183             :   return (u16x16) _mm256_shuffle_epi8 ((__m256i) v, (__m256i) swap);
     184             : }
     185             : 
     186             : #define u8x32_align_right(a, b, imm) \
     187             :   (u8x32) _mm256_alignr_epi8 ((__m256i) a, (__m256i) b, imm)
     188             : 
     189             : #define u64x4_align_right(a, b, imm)                                          \
     190             :   (u64x4) _mm256_alignr_epi64 ((__m256i) a, (__m256i) b, imm)
     191             : 
     192             : static_always_inline u32
     193             : u32x8_sum_elts (u32x8 sum8)
     194             : {
     195             :   sum8 += (u32x8) u8x32_align_right (sum8, sum8, 8);
     196             :   sum8 += (u32x8) u8x32_align_right (sum8, sum8, 4);
     197             :   return sum8[0] + sum8[4];
     198             : }
     199             : 
     200             : static_always_inline u32x8
     201             : u32x8_hadd (u32x8 v1, u32x8 v2)
     202             : {
     203             :   return (u32x8) _mm256_hadd_epi32 ((__m256i) v1, (__m256i) v2);
     204             : }
     205             : 
     206             : static_always_inline u32
     207             : u32x8_hxor (u32x8 v)
     208             : {
     209             :   u32x4 v4;
     210             :   v4 = u32x8_extract_lo (v) ^ u32x8_extract_hi (v);
     211             :   v4 ^= (u32x4) u8x16_align_right (v4, v4, 8);
     212             :   v4 ^= (u32x4) u8x16_align_right (v4, v4, 4);
     213             :   return v4[0];
     214             : }
     215             : 
     216             : static_always_inline u8x32
     217             : u8x32_xor3 (u8x32 a, u8x32 b, u8x32 c)
     218             : {
     219             : #if __AVX512F__
     220             :   return (u8x32) _mm256_ternarylogic_epi32 ((__m256i) a, (__m256i) b,
     221             :                                             (__m256i) c, 0x96);
     222             : #endif
     223             :   return a ^ b ^ c;
     224             : }
     225             : 
     226             : static_always_inline u8x32
     227             : u8x32_reflect_u8x16 (u8x32 x)
     228             : {
     229             :   static const u8x32 mask = {
     230             :     15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
     231             :     15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
     232             :   };
     233             :   return (u8x32) _mm256_shuffle_epi8 ((__m256i) x, (__m256i) mask);
     234             : }
     235             : 
     236             : static_always_inline u16x16
     237             : u16x16_mask_last (u16x16 v, u8 n_last)
     238             : {
     239             :   const u16x16 masks[17] = {
     240             :     {0},
     241             :     {-1},
     242             :     {-1, -1},
     243             :     {-1, -1, -1},
     244             :     {-1, -1, -1, -1},
     245             :     {-1, -1, -1, -1, -1},
     246             :     {-1, -1, -1, -1, -1, -1},
     247             :     {-1, -1, -1, -1, -1, -1, -1},
     248             :     {-1, -1, -1, -1, -1, -1, -1, -1},
     249             :     {-1, -1, -1, -1, -1, -1, -1, -1, -1},
     250             :     {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
     251             :     {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
     252             :     {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
     253             :     {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
     254             :     {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
     255             :     {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
     256             :     {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
     257             :   };
     258             : 
     259             :   ASSERT (n_last < 17);
     260             : 
     261             :   return v & masks[16 - n_last];
     262             : }
     263             : 
     264             : static_always_inline f32x8
     265             : f32x8_from_u32x8 (u32x8 v)
     266             : {
     267             :   return (f32x8) _mm256_cvtepi32_ps ((__m256i) v);
     268             : }
     269             : 
     270             : static_always_inline u32x8
     271             : u32x8_from_f32x8 (f32x8 v)
     272             : {
     273             :   return (u32x8) _mm256_cvttps_epi32 ((__m256) v);
     274             : }
     275             : 
     276             : #define u32x8_blend(a,b,m) \
     277             :   (u32x8) _mm256_blend_epi32 ((__m256i) a, (__m256i) b, m)
     278             : 
     279             : #define u16x16_blend(v1, v2, mask) \
     280             :   (u16x16) _mm256_blend_epi16 ((__m256i) (v1), (__m256i) (v2), mask)
     281             : 
     282             : static_always_inline u64x4
     283    14898400 : u64x4_gather (void *p0, void *p1, void *p2, void *p3)
     284             : {
     285    14898400 :   u64x4 r = {
     286    14898400 :     *(u64 *) p0, *(u64 *) p1, *(u64 *) p2, *(u64 *) p3
     287             :   };
     288    14898400 :   return r;
     289             : }
     290             : 
     291             : static_always_inline u32x8
     292             : u32x8_gather (void *p0, void *p1, void *p2, void *p3, void *p4, void *p5,
     293             :               void *p6, void *p7)
     294             : {
     295             :   u32x8 r = {
     296             :     *(u32 *) p0, *(u32 *) p1, *(u32 *) p2, *(u32 *) p3,
     297             :     *(u32 *) p4, *(u32 *) p5, *(u32 *) p6, *(u32 *) p7,
     298             :   };
     299             :   return r;
     300             : }
     301             : 
     302             : 
     303             : static_always_inline void
     304    14898400 : u64x4_scatter (u64x4 r, void *p0, void *p1, void *p2, void *p3)
     305             : {
     306    14898400 :   *(u64 *) p0 = r[0];
     307    14898400 :   *(u64 *) p1 = r[1];
     308    14898400 :   *(u64 *) p2 = r[2];
     309    14898400 :   *(u64 *) p3 = r[3];
     310    14898400 : }
     311             : 
     312             : static_always_inline void
     313             : u32x8_scatter (u32x8 r, void *p0, void *p1, void *p2, void *p3, void *p4,
     314             :                void *p5, void *p6, void *p7)
     315             : {
     316             :   *(u32 *) p0 = r[0];
     317             :   *(u32 *) p1 = r[1];
     318             :   *(u32 *) p2 = r[2];
     319             :   *(u32 *) p3 = r[3];
     320             :   *(u32 *) p4 = r[4];
     321             :   *(u32 *) p5 = r[5];
     322             :   *(u32 *) p6 = r[6];
     323             :   *(u32 *) p7 = r[7];
     324             : }
     325             : 
     326             : static_always_inline void
     327             : u64x4_scatter_one (u64x4 r, int index, void *p)
     328             : {
     329             :   *(u64 *) p = r[index];
     330             : }
     331             : 
     332             : static_always_inline void
     333    59593800 : u32x8_scatter_one (u32x8 r, int index, void *p)
     334             : {
     335    59593800 :   *(u32 *) p = r[index];
     336    59593800 : }
     337             : 
     338             : #define u32x8_gather_u32(base, indices, scale)                                \
     339             :   (u32x8) _mm256_i32gather_epi32 (base, (__m256i) indices, scale)
     340             : 
     341             : #ifdef __AVX512F__
     342             : #define u32x8_scatter_u32(base, indices, v, scale)                            \
     343             :   _mm256_i32scatter_epi32 (base, (__m256i) indices, (__m256i) v, scale)
     344             : #else
     345             : #define u32x8_scatter_u32(base, indices, v, scale)                            \
     346             :   for (u32 i = 0; i < 8; i++)                                                 \
     347             :     *((u32u *) ((u8 *) base + (scale) * (indices)[i])) = (v)[i];
     348             : #endif
     349             : 
     350             : static_always_inline u8x32
     351      812256 : u8x32_blend (u8x32 v1, u8x32 v2, u8x32 mask)
     352             : {
     353     1624512 :   return (u8x32) _mm256_blendv_epi8 ((__m256i) v1, (__m256i) v2,
     354             :                                      (__m256i) mask);
     355             : }
     356             : 
     357             : #define u8x32_word_shift_left(a, n)                                           \
     358             :   (u8x32) _mm256_bslli_epi128 ((__m256i) a, n)
     359             : #define u8x32_word_shift_right(a, n)                                          \
     360             :   (u8x32) _mm256_bsrli_epi128 ((__m256i) a, n)
     361             : 
     362             : #define u32x8_permute_lanes(a, b, m) \
     363             :   (u32x8) _mm256_permute2x128_si256 ((__m256i) a, (__m256i) b, m)
     364             : #define u64x4_permute_lanes(a, b, m) \
     365             :   (u64x4) _mm256_permute2x128_si256 ((__m256i) a, (__m256i) b, m)
     366             : 
     367             : static_always_inline u32x8
     368           0 : u32x8_min (u32x8 a, u32x8 b)
     369             : {
     370           0 :   return (u32x8) _mm256_min_epu32 ((__m256i) a, (__m256i) b);
     371             : }
     372             : 
     373             : static_always_inline u32
     374           0 : u32x8_min_scalar (u32x8 v)
     375             : {
     376           0 :   return u32x4_min_scalar (u32x4_min (u32x8_extract_lo (v),
     377             :                                       u32x8_extract_hi (v)));
     378             : }
     379             : 
     380             : static_always_inline void
     381             : u32x8_transpose (u32x8 a[8])
     382             : {
     383             :   u64x4 r[8], x, y;
     384             : 
     385             :   r[0] = (u64x4) u32x8_interleave_lo (a[0], a[1]);
     386             :   r[1] = (u64x4) u32x8_interleave_hi (a[0], a[1]);
     387             :   r[2] = (u64x4) u32x8_interleave_lo (a[2], a[3]);
     388             :   r[3] = (u64x4) u32x8_interleave_hi (a[2], a[3]);
     389             :   r[4] = (u64x4) u32x8_interleave_lo (a[4], a[5]);
     390             :   r[5] = (u64x4) u32x8_interleave_hi (a[4], a[5]);
     391             :   r[6] = (u64x4) u32x8_interleave_lo (a[6], a[7]);
     392             :   r[7] = (u64x4) u32x8_interleave_hi (a[6], a[7]);
     393             : 
     394             :   x = u64x4_interleave_lo (r[0], r[2]);
     395             :   y = u64x4_interleave_lo (r[4], r[6]);
     396             :   a[0] = u32x8_permute_lanes (x, y, 0x20);
     397             :   a[4] = u32x8_permute_lanes (x, y, 0x31);
     398             : 
     399             :   x = u64x4_interleave_hi (r[0], r[2]);
     400             :   y = u64x4_interleave_hi (r[4], r[6]);
     401             :   a[1] = u32x8_permute_lanes (x, y, 0x20);
     402             :   a[5] = u32x8_permute_lanes (x, y, 0x31);
     403             : 
     404             :   x = u64x4_interleave_lo (r[1], r[3]);
     405             :   y = u64x4_interleave_lo (r[5], r[7]);
     406             :   a[2] = u32x8_permute_lanes (x, y, 0x20);
     407             :   a[6] = u32x8_permute_lanes (x, y, 0x31);
     408             : 
     409             :   x = u64x4_interleave_hi (r[1], r[3]);
     410             :   y = u64x4_interleave_hi (r[5], r[7]);
     411             :   a[3] = u32x8_permute_lanes (x, y, 0x20);
     412             :   a[7] = u32x8_permute_lanes (x, y, 0x31);
     413             : }
     414             : 
     415             : static_always_inline void
     416             : u64x4_transpose (u64x4 a[8])
     417             : {
     418             :   u64x4 r[4];
     419             : 
     420             :   r[0] = u64x4_interleave_lo (a[0], a[1]);
     421             :   r[1] = u64x4_interleave_hi (a[0], a[1]);
     422             :   r[2] = u64x4_interleave_lo (a[2], a[3]);
     423             :   r[3] = u64x4_interleave_hi (a[2], a[3]);
     424             : 
     425             :   a[0] = u64x4_permute_lanes (r[0], r[2], 0x20);
     426             :   a[1] = u64x4_permute_lanes (r[1], r[3], 0x20);
     427             :   a[2] = u64x4_permute_lanes (r[0], r[2], 0x31);
     428             :   a[3] = u64x4_permute_lanes (r[1], r[3], 0x31);
     429             : }
     430             : 
     431             : static_always_inline u8x32
     432             : u8x32_splat_u8x16 (u8x16 a)
     433             : {
     434             :   return (u8x32) _mm256_broadcastsi128_si256 ((__m128i) a);
     435             : }
     436             : 
     437             : static_always_inline u32x8
     438             : u32x8_splat_u32x4 (u32x4 a)
     439             : {
     440             :   return (u32x8) _mm256_broadcastsi128_si256 ((__m128i) a);
     441             : }
     442             : 
     443             : static_always_inline u64x4
     444             : u64x4_splat_u64x2 (u64x2 a)
     445             : {
     446             :   return (u64x4) _mm256_broadcastsi128_si256 ((__m128i) a);
     447             : }
     448             : 
     449             : static_always_inline u8x32
     450             : u8x32_load_partial (u8 *data, uword n)
     451             : {
     452             : #if defined(CLIB_HAVE_VEC256_MASK_LOAD_STORE)
     453             :   return u8x32_mask_load_zero (data, pow2_mask (n));
     454             : #else
     455             :   u8x32 r = {};
     456             :   if (n > 16)
     457             :     {
     458             :       r = u8x32_insert_lo (r, *(u8x16u *) data);
     459             :       r = u8x32_insert_hi (r, u8x16_load_partial (data + 16, n - 16));
     460             :     }
     461             :   else
     462             :     r = u8x32_insert_lo (r, u8x16_load_partial (data, n));
     463             :   return r;
     464             : #endif
     465             : }
     466             : 
     467             : static_always_inline void
     468             : u8x32_store_partial (u8x32 r, u8 *data, uword n)
     469             : {
     470             : #if defined(CLIB_HAVE_VEC256_MASK_LOAD_STORE)
     471             :   u8x32_mask_store (r, data, pow2_mask (n));
     472             : #else
     473             :   if (n > 16)
     474             :     {
     475             :       *(u8x16u *) data = u8x32_extract_lo (r);
     476             :       u8x16_store_partial (u8x32_extract_hi (r), data + 16, n - 16);
     477             :     }
     478             :   else
     479             :     u8x16_store_partial (u8x32_extract_lo (r), data, n);
     480             : #endif
     481             : }
     482             : 
     483             : #endif /* included_vector_avx2_h */
     484             : 
     485             : /*
     486             :  * fd.io coding-style-patch-verification: ON
     487             :  *
     488             :  * Local Variables:
     489             :  * eval: (c-set-style "gnu")
     490             :  * End:
     491             :  */

Generated by: LCOV version 1.14