LCOV - code coverage report
Current view: top level - lib/bpf - bpf_value_set.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 116 126 92.1 %
Date: 2026-08-01 17:54:00 Functions: 18 18 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 102 148 68.9 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright(c) 2026 Huawei Technologies Co., Ltd
       3                 :            :  */
       4                 :            : 
       5                 :            : #include "bpf_value_set.h"
       6                 :            : 
       7                 :            : #include <rte_debug.h>
       8                 :            : 
       9                 :            : /* Helper interval operations and checks.  */
      10                 :            : 
      11                 :            : /* One of many possible full intervals. */
      12                 :            : static const struct value_set_interval canonical_full_interval = {
      13                 :            :         .first = 0,
      14                 :            :         .last = UINT64_MAX,
      15                 :            : };
      16                 :            : 
      17                 :            : /* Translate ("shift") interval by `offset`. */
      18                 :            : static void
      19                 :            : interval_translate(struct value_set_interval *interval, uint64_t offset)
      20                 :            : {
      21                 :      18344 :         interval->first += offset;
      22                 :      18344 :         interval->last += offset;
      23                 :            : }
      24                 :            : 
      25                 :            : /* Return true if the interval includes all possible values. */
      26                 :            : static bool
      27                 :            : interval_is_full(struct value_set_interval interval)
      28                 :            : {
      29                 :       2164 :         return interval.last + 1 == interval.first;
      30                 :            : }
      31                 :            : 
      32                 :            : /* Return true if the interval includes `value`. */
      33                 :            : static bool
      34                 :            : interval_contains(struct value_set_interval interval, uint64_t value)
      35                 :            : {
      36                 :       7304 :         return value - interval.first <= interval.last - interval.first;
      37                 :            : }
      38                 :            : 
      39                 :            : /* Return true if the interval `lhs` includes all values from `rhs`. */
      40                 :            : static bool
      41                 :            : interval_covers(struct value_set_interval lhs, struct value_set_interval rhs)
      42                 :            : {
      43                 :            :         const uint64_t offset = -lhs.first;
      44                 :            :         interval_translate(&lhs, offset);
      45                 :            :         interval_translate(&rhs, offset);
      46                 :            :         RTE_ASSERT(lhs.first == 0);
      47                 :            : 
      48   [ +  -  +  + ]:         96 :         return lhs.last == UINT64_MAX ||
      49         [ +  + ]:         68 :                 (lhs.last >= rhs.last && rhs.last >= rhs.first);
      50                 :            : }
      51                 :            : 
      52                 :            : /* Return true if the interval includes step from UINT64_MAX to 0. */
      53                 :            : static bool
      54                 :            : interval_crosses_zero(struct value_set_interval interval)
      55                 :            : {
      56                 :            :         return interval.last < interval.first;
      57                 :            : }
      58                 :            : 
      59                 :            : /* Return number of elements in a non-full elements, 0 for full interval. */
      60                 :            : static uint64_t
      61                 :            : interval_size(struct value_set_interval interval)
      62                 :            : {
      63                 :         96 :         return interval.last - interval.first + 1;
      64                 :            : }
      65                 :            : 
      66                 :            : /* Return true if two intervals represent same sets of values. */
      67                 :            : static bool
      68                 :            : intervals_equal(struct value_set_interval lhs, struct value_set_interval rhs)
      69                 :            : {
      70   [ -  +  -  -  :       1972 :         return (interval_is_full(lhs) && interval_is_full(rhs)) ||
                   +  - ]
      71         [ +  - ]:       1972 :                 (lhs.first == rhs.first && lhs.last == rhs.last);
      72                 :            : }
      73                 :            : 
      74                 :            : /* Return true if two intervals have common elements. */
      75                 :            : static bool
      76                 :            : intervals_intersect(struct value_set_interval lhs, struct value_set_interval rhs)
      77                 :            : {
      78   [ -  +  -  - ]:       7304 :         return interval_contains(lhs, rhs.first) || interval_contains(rhs, lhs.first);
      79                 :            : }
      80                 :            : 
      81                 :            : /* Return true if `rhs.first` follows `lhs.last` with some gap. Does not check other ends! */
      82                 :            : static bool
      83                 :            : intervals_follow_with_gap(struct value_set_interval lhs, struct value_set_interval rhs)
      84                 :            : {
      85   [ +  -  +  +  :      26416 :         return lhs.last != UINT64_MAX && rhs.first > lhs.last + 1;
                   -  + ]
      86                 :            : }
      87                 :            : 
      88                 :            : /* Return true if `(l - o) < (r - o)` for all `(o in origin, l in lhs, r in rhs)`. */
      89                 :            : static bool
      90                 :            : intervals_based_less(struct value_set_interval origin, struct value_set_interval lhs,
      91                 :            :         struct value_set_interval rhs)
      92                 :            : {
      93                 :            :         /* Translate all intervals for the origin to start at 0. */
      94                 :            :         const uint64_t offset = -origin.first;
      95                 :            :         interval_translate(&origin, offset);
      96                 :            :         interval_translate(&lhs, offset);
      97                 :            :         interval_translate(&rhs, offset);
      98                 :            :         RTE_ASSERT(origin.first == 0);
      99                 :            : 
     100         [ +  + ]:       7304 :         return origin.last <= lhs.first &&
     101         [ -  + ]:       7220 :                 lhs.first <= lhs.last &&
     102   [ +  -  -  - ]:       7304 :                 lhs.last < rhs.first &&
     103                 :            :                 rhs.first <= rhs.last;
     104                 :            : }
     105                 :            : 
     106                 :            : /* Return true if `(l - o) <= (r - o)` for all `(o in origin, l in lhs, r in rhs)`. */
     107                 :            : static bool
     108                 :       7304 : intervals_based_less_or_equal(struct value_set_interval origin, struct value_set_interval lhs,
     109                 :            :         struct value_set_interval rhs)
     110                 :            : {
     111                 :            :         /* Translate all intervals for the origin to start at 0. */
     112                 :            :         const uint64_t offset = -origin.first;
     113                 :            :         interval_translate(&origin, offset);
     114                 :            :         interval_translate(&lhs, offset);
     115                 :            :         interval_translate(&rhs, offset);
     116                 :            :         RTE_ASSERT(origin.first == 0);
     117                 :            : 
     118                 :            :         /* Special cases. */
     119   [ +  +  +  +  :       7304 :         if (origin.last == 0 && lhs.first == 0 && lhs.last == 0)
                   +  + ]
     120                 :            :                 return true;
     121   [ +  +  +  +  :       7013 :         if (origin.last == 0 && rhs.first == UINT64_MAX && rhs.last == UINT64_MAX)
                   -  + ]
     122                 :            :                 return true;
     123   [ +  +  +  -  :       6834 :         if (lhs.first == lhs.last && lhs.last == rhs.first && rhs.first == rhs.last)
                   +  + ]
     124                 :            :                 return true;
     125                 :            : 
     126         [ +  - ]:       5036 :         return origin.last <= lhs.first &&
     127         [ +  - ]:       5036 :                 lhs.first <= lhs.last &&
     128   [ +  -  -  + ]:      10072 :                 lhs.last <= rhs.first &&
     129                 :            :                 rhs.first <= rhs.last;
     130                 :            : }
     131                 :            : 
     132                 :            : /* Append interval rhs to list of intervals in lhs. */
     133                 :            : static void
     134                 :      28648 : value_set_append(struct value_set *lhs, struct value_set_interval rhs)
     135                 :            : {
     136         [ -  + ]:      28648 :         RTE_VERIFY(lhs->nb_interval < VALUE_SET_NB_INTERVAL_MAX);
     137   [ +  +  +  -  :      28824 :         RTE_VERIFY(lhs->nb_interval == 0 ||
                   -  + ]
     138                 :            :                 intervals_follow_with_gap(lhs->interval[lhs->nb_interval - 1], rhs));
     139                 :      28648 :         lhs->interval[lhs->nb_interval++] = rhs;
     140                 :      28648 : }
     141                 :            : 
     142                 :            : /*
     143                 :            :  * Helper operations on noncyclic value set and intervals.
     144                 :            :  * Noncyclic means no interval crosses zero,
     145                 :            :  * but in return last value set interval may touch first.
     146                 :            :  */
     147                 :            : 
     148                 :            : static struct value_set
     149                 :      13448 : noncyclic_value_set_union_interval(const struct value_set *lhs, const struct value_set_interval rhs)
     150                 :            : {
     151                 :      13448 :         struct value_set result = {};
     152                 :            :         uint32_t index = 0;
     153                 :            : 
     154                 :            :         RTE_ASSERT(lhs->nb_interval == 0 ||
     155                 :            :                 !interval_crosses_zero(lhs->interval[lhs->nb_interval - 1]));
     156                 :            :         RTE_ASSERT(!interval_crosses_zero(rhs));
     157                 :            : 
     158                 :            :         /* Append to result all lhs intervals preceding rhs. */
     159         [ +  - ]:      13448 :         for (; index != lhs->nb_interval; ++index) {
     160         [ +  + ]:      13448 :                 const struct value_set_interval lhs_interval = lhs->interval[index];
     161         [ -  + ]:      13448 :                 if (!intervals_follow_with_gap(lhs_interval, rhs))
     162                 :            :                         break;
     163                 :            : 
     164                 :          0 :                 value_set_append(&result, lhs_interval);
     165                 :            :         }
     166                 :            : 
     167                 :            :         /* Appendinterval joined from rhs and all lhs intervals intersecting or touching it. */
     168                 :      13448 :         struct value_set_interval joint_interval = rhs;
     169         [ +  + ]:      26720 :         for (; index != lhs->nb_interval; ++index) {
     170         [ +  + ]:      13448 :                 const struct value_set_interval lhs_interval = lhs->interval[index];
     171         [ +  + ]:      13448 :                 if (intervals_follow_with_gap(rhs, lhs_interval))
     172                 :            :                         break;
     173                 :            : 
     174                 :      13272 :                 joint_interval.first = RTE_MIN(joint_interval.first, lhs_interval.first);
     175                 :      13272 :                 joint_interval.last = RTE_MAX(joint_interval.last, lhs_interval.last);
     176                 :            :         }
     177                 :      13448 :         value_set_append(&result, joint_interval);
     178                 :            : 
     179                 :            :         /* Append to result all lhs intervals following rhs. */
     180         [ +  + ]:      13624 :         for (; index != lhs->nb_interval; ++index)
     181                 :        176 :                 value_set_append(&result, lhs->interval[index]);
     182                 :            : 
     183                 :      13448 :         return result;
     184                 :            : }
     185                 :            : 
     186                 :            : /* Make "normal" maximal disjoint interval value set out of noncyclic one. */
     187                 :            : static struct value_set
     188                 :      13448 : value_set_from_noncyclic(const struct value_set *set)
     189                 :            : {
     190                 :      13448 :         struct value_set result = {};
     191                 :            :         uint32_t index = 0;
     192                 :            : 
     193         [ +  + ]:      13448 :         if (set->nb_interval <= 1)
     194                 :      13272 :                 return *set;
     195                 :            : 
     196                 :        176 :         struct value_set_interval last_interval = set->interval[set->nb_interval - 1];
     197   [ +  -  +  - ]:        176 :         if (last_interval.last == UINT64_MAX && set->interval[0].first == 0) {
     198                 :            :                 /* Join first interval with the last one instead of copying it. */
     199                 :        176 :                 last_interval.last = set->interval[0].last;
     200                 :            :                 ++index;
     201                 :            :         }
     202                 :            : 
     203         [ -  + ]:        176 :         for (; index != set->nb_interval - 1; ++index)
     204                 :          0 :                 value_set_append(&result, set->interval[index]);
     205                 :            : 
     206                 :        176 :         value_set_append(&result, last_interval);
     207                 :            : 
     208                 :        176 :         return result;
     209                 :            : }
     210                 :            : 
     211                 :            : /* Make lhs a union of lhs and rhs. */
     212                 :            : static void
     213                 :      28296 : value_set_union_interval(struct value_set *lhs, const struct value_set_interval rhs)
     214                 :            : {
     215                 :            :         struct value_set temp;
     216                 :            : 
     217         [ +  + ]:      28296 :         if (value_set_is_empty(lhs)) {
     218                 :      14848 :                 value_set_append(lhs, rhs);
     219                 :      14848 :                 return;
     220                 :            :         }
     221                 :            : 
     222                 :      13448 :         struct value_set_interval *const last_interval = &lhs->interval[lhs->nb_interval - 1];
     223                 :            :         const bool last_interval_crossed_zero = interval_crosses_zero(*last_interval);
     224                 :            :         const uint64_t wrapping_last = last_interval->last;
     225                 :            : 
     226         [ -  + ]:      13448 :         if (last_interval_crossed_zero)
     227                 :            :                 /* Make value set noncyclic by removing crossing part of last interval. */
     228                 :          0 :                 last_interval->last = UINT64_MAX;
     229                 :            : 
     230         [ -  + ]:      13448 :         if (interval_crosses_zero(rhs)) {
     231                 :            :                 /* Add parts before and after zero separately. */
     232                 :          0 :                 temp = noncyclic_value_set_union_interval(lhs,
     233                 :          0 :                         (struct value_set_interval){
     234                 :            :                                 .first = rhs.first,
     235                 :            :                                 .last = UINT64_MAX,
     236                 :            :                         });
     237                 :          0 :                 temp = noncyclic_value_set_union_interval(lhs,
     238                 :          0 :                         (struct value_set_interval){
     239                 :            :                                 .first = 0,
     240                 :            :                                 .last = rhs.last,
     241                 :            :                         });
     242                 :            :         } else
     243                 :      13448 :                 temp = noncyclic_value_set_union_interval(lhs, rhs);
     244                 :            : 
     245         [ -  + ]:      13448 :         if (last_interval_crossed_zero)
     246                 :            :                 /* Restore previously removed part. */
     247                 :          0 :                 temp = noncyclic_value_set_union_interval(&temp,
     248                 :          0 :                         (struct value_set_interval){
     249                 :            :                                 .first = 0,
     250                 :            :                                 .last = wrapping_last,
     251                 :            :                         });
     252                 :            : 
     253                 :      13448 :         *lhs = value_set_from_noncyclic(&temp);
     254                 :            : }
     255                 :            : 
     256                 :            : /* Set `lhs` to the set of possible sums between values from `lhs` and `rhs`. */
     257                 :            : static void
     258                 :         96 : value_set_add_interval(struct value_set *lhs, struct value_set_interval rhs)
     259                 :            : {
     260                 :         96 :         const struct value_set temp = *lhs;
     261                 :         96 :         lhs->nb_interval = 0;
     262                 :            : 
     263         [ +  + ]:        192 :         for (uint32_t index = 0; index != temp.nb_interval; ++index) {
     264                 :         96 :                 const struct value_set_interval interval = temp.interval[index];
     265   [ +  -  +  - ]:         96 :                 if (interval_is_full(rhs) || interval_is_full(interval) ||
     266         [ -  + ]:         96 :                                 interval_size(interval) > UINT64_MAX - interval_size(rhs)) {
     267                 :          0 :                         value_set_append(lhs, canonical_full_interval);
     268                 :            :                         return;
     269                 :            :                 }
     270                 :            :         }
     271                 :            : 
     272         [ +  + ]:        192 :         for (uint32_t index = 0; index != temp.nb_interval; ++index)
     273                 :         96 :                 value_set_union_interval(lhs, (struct value_set_interval){
     274                 :            :                         /* Checked sizes above, so these interval expansions won't overflow. */
     275                 :         96 :                         .first = temp.interval[index].first + rhs.first,
     276                 :         96 :                         .last = temp.interval[index].last + rhs.last,
     277                 :            :                 });
     278                 :            : }
     279                 :            : 
     280                 :            : struct value_set
     281                 :      29120 : value_set_singleton(uint64_t value)
     282                 :            : {
     283                 :      29120 :         return value_set_contiguous(value, value);
     284                 :            : }
     285                 :            : 
     286                 :            : struct value_set
     287                 :      29168 : value_set_contiguous(uint64_t first, uint64_t last)
     288                 :            : {
     289                 :      29168 :         return (struct value_set){
     290                 :            :                 .nb_interval = 1,
     291                 :            :                 .interval = {
     292                 :            :                         { .first = first, .last = last },
     293                 :            :                 },
     294                 :            :         };
     295                 :            : }
     296                 :            : 
     297                 :            : struct value_set
     298                 :      14752 : value_set_from_pair(uint64_t first1, uint64_t last1, uint64_t first2, uint64_t last2)
     299                 :            : {
     300                 :      14752 :         struct value_set result = {};
     301                 :            : 
     302         [ +  + ]:      14752 :         if (first1 - first2 <= last2 - first2)
     303                 :            :                 /* Interval 1 starts within interval 2. */
     304                 :      14096 :                 value_set_union_interval(&result, (struct value_set_interval){
     305                 :            :                                 .first = first1,
     306                 :      14096 :                                 .last = first1 + RTE_MIN(last1 - first1, last2 - first1),
     307                 :            :                         });
     308                 :            : 
     309         [ +  + ]:      14752 :         if (first2 - first1 <= last1 - first1)
     310                 :            :                 /* Interval 2 starts within interval 1. */
     311                 :      14104 :                 value_set_union_interval(&result, (struct value_set_interval){
     312                 :            :                                 .first = first2,
     313                 :      14104 :                                 .last = first2 + RTE_MIN(last2 - first2, last1 - first2),
     314                 :            :                         });
     315                 :            : 
     316                 :      14752 :         return result;
     317                 :            : }
     318                 :            : 
     319                 :            : bool
     320                 :      28296 : value_set_is_empty(const struct value_set *set)
     321                 :            : {
     322                 :      28296 :         return set->nb_interval == 0;
     323                 :            : }
     324                 :            : 
     325                 :            : bool
     326                 :       7304 : value_set_is_singleton(const struct value_set *set)
     327                 :            : {
     328   [ +  -  +  + ]:       7304 :         return set->nb_interval == 1 && interval_size(set->interval[0]) == 1;
     329                 :            : }
     330                 :            : 
     331                 :            : bool
     332                 :       1972 : value_sets_equal(const struct value_set *lhs, const struct value_set *rhs)
     333                 :            : {
     334         [ +  - ]:       1972 :         if (lhs->nb_interval != rhs->nb_interval)
     335                 :            :                 return false;
     336                 :            : 
     337         [ +  + ]:       3944 :         for (uint32_t index = 0; index != lhs->nb_interval; ++index)
     338         [ +  - ]:       1972 :                 if (!intervals_equal(lhs->interval[index], rhs->interval[index]))
     339                 :            :                         return false;
     340                 :            : 
     341                 :            :         return true;
     342                 :            : }
     343                 :            : 
     344                 :            : bool
     345                 :       7304 : value_sets_intersect(const struct value_set *lhs, const struct value_set *rhs)
     346                 :            : {
     347         [ +  - ]:       7304 :         for (uint32_t lhs_index = 0; lhs_index != lhs->nb_interval; ++lhs_index)
     348         [ +  - ]:       7304 :                 for (uint32_t rhs_index = 0; rhs_index != rhs->nb_interval; ++rhs_index)
     349         [ -  + ]:       7304 :                         if (intervals_intersect(lhs->interval[lhs_index], rhs->interval[rhs_index]))
     350                 :            :                                 return true;
     351                 :            : 
     352                 :            :         return false;
     353                 :            : }
     354                 :            : 
     355                 :            : bool
     356                 :         96 : value_set_is_covered_by_contiguous(const struct value_set *lhs, uint64_t first, uint64_t last)
     357                 :            : {
     358                 :            :         const struct value_set_interval rhs = { .first = first, .last = last };
     359         [ +  + ]:        144 :         for (uint32_t lhs_index = 0; lhs_index != lhs->nb_interval; ++lhs_index)
     360         [ +  + ]:         96 :                 if (!interval_covers(rhs, lhs->interval[lhs_index]))
     361                 :            :                         return false;
     362                 :            : 
     363                 :            :         return true;
     364                 :            : }
     365                 :            : 
     366                 :            : bool
     367                 :       7304 : value_sets_based_less(const struct value_set *origin, const struct value_set *lhs,
     368                 :            :         const struct value_set *rhs)
     369                 :            : {
     370         [ +  - ]:       7304 :         for (uint32_t origin_index = 0; origin_index != origin->nb_interval; ++origin_index)
     371         [ +  - ]:       7304 :                 for (uint32_t lhs_index = 0; lhs_index != lhs->nb_interval; ++lhs_index)
     372         [ +  - ]:       7304 :                         for (uint32_t rhs_index = 0; rhs_index != rhs->nb_interval; ++rhs_index)
     373         [ -  + ]:       7304 :                                 if (!intervals_based_less(origin->interval[origin_index],
     374                 :            :                                                 lhs->interval[lhs_index], rhs->interval[rhs_index]))
     375                 :            :                                         return false;
     376                 :            :         return true;
     377                 :            : }
     378                 :            : 
     379                 :            : bool
     380                 :       7304 : value_sets_based_less_or_equal(const struct value_set *origin, const struct value_set *lhs,
     381                 :            :         const struct value_set *rhs)
     382                 :            : {
     383         [ +  + ]:      14608 :         for (uint32_t origin_index = 0; origin_index != origin->nb_interval; ++origin_index)
     384         [ +  + ]:      14608 :                 for (uint32_t lhs_index = 0; lhs_index != lhs->nb_interval; ++lhs_index)
     385         [ +  + ]:      14608 :                         for (uint32_t rhs_index = 0; rhs_index != rhs->nb_interval; ++rhs_index)
     386         [ +  - ]:       7304 :                                 if (!intervals_based_less_or_equal(origin->interval[origin_index],
     387                 :            :                                                 lhs->interval[lhs_index], rhs->interval[rhs_index]))
     388                 :            :                                         return false;
     389                 :            :         return true;
     390                 :            : }
     391                 :            : 
     392                 :            : void
     393                 :      18344 : value_set_translate(struct value_set *set, uint64_t offset)
     394                 :            : {
     395         [ +  + ]:      36688 :         for (uint32_t index = 0; index != set->nb_interval; ++index)
     396                 :            :                 interval_translate(&set->interval[index], offset);
     397                 :      18344 : }
     398                 :            : 
     399                 :            : void
     400                 :         96 : value_set_add_contiguous(struct value_set *lhs, uint64_t first, uint64_t last)
     401                 :            : {
     402                 :         96 :         value_set_add_interval(lhs, (struct value_set_interval){ .first = first, .last = last });
     403                 :         96 : }

Generated by: LCOV version 1.14