• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nickg / nvc / 14691306008

27 Apr 2025 10:55AM UTC coverage: 92.319% (+0.009%) from 92.31%
14691306008

push

github

nickg
Fix assertion failure with large number of array sub-elements

15 of 16 new or added lines in 2 files covered. (93.75%)

71 existing lines in 4 files now uncovered.

69070 of 74817 relevant lines covered (92.32%)

422022.01 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.38
/src/cov/cov-data.c
1
//
2
//  Copyright (C) 2013-2024  Nick Gasson
3
//
4
//  This program is free software: you can redistribute it and/or modify
5
//  it under the terms of the GNU General Public License as published by
6
//  the Free Software Foundation, either version 3 of the License, or
7
//  (at your option) any later version.
8
//
9
//  This program is distributed in the hope that it will be useful,
10
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
//  GNU General Public License for more details.
13
//
14
//  You should have received a copy of the GNU General Public License
15
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
//
17

18
#include "util.h"
19
#include "array.h"
20
#include "cov/cov-api.h"
21
#include "cov/cov-data.h"
22
#include "ident.h"
23
#include "lib.h"
24
#include "object.h"
25
#include "option.h"
26
#include "tree.h"
27
#include "psl/psl-node.h"
28
#include "type.h"
29

30
#include <assert.h>
31
#include <stdio.h>
32
#include <string.h>
33
#include <stdlib.h>
34
#include <limits.h>
35
#include <libgen.h>
36
#include <inttypes.h>
37

38
//#define COVER_DEBUG_EMIT
39
//#define COVER_DEBUG_SCOPE
40
//#define COVER_DEBUG_MERGE
41

42
typedef enum {
43
   CTRL_PUSH_SCOPE,
44
   CTRL_POP_SCOPE,
45
   CTRL_END_OF_FILE,
46
} cov_control_t;
47

48
static const struct {
49
   const char *name;
50
   uint32_t   flag;
51
} bin_map[] = {
52
   { "BIN_TRUE",       COV_FLAG_TRUE},
53
   { "BIN_FALSE",      COV_FLAG_FALSE},
54
   { "BIN_CHOICE",     COV_FLAG_CHOICE},
55
   { "BIN_0_0",        COV_FLAG_00},
56
   { "BIN_0_1",        COV_FLAG_01},
57
   { "BIN_1_0",        COV_FLAG_10},
58
   { "BIN_1_1",        COV_FLAG_11},
59
   { "BIN_0_TO_1",     COV_FLAG_TOGGLE_TO_1},
60
   { "BIN_1_TO_0",     COV_FLAG_TOGGLE_TO_0},
61
};
62

63
#define COVER_FILE_MAGIC   0x6e636462   // ASCII "ncdb"
64
#define COVER_FILE_VERSION 2
65

66
static bool cover_is_branch(tree_t branch)
2,825✔
67
{
68
   return tree_kind(branch) == T_ASSOC || tree_kind(branch) == T_COND_STMT;
2,825✔
69
}
70

71
static cover_src_t get_cover_source(cover_item_kind_t kind, object_t *obj)
46,865✔
72
{
73
   if (obj == NULL)
46,865✔
74
      return COV_SRC_UNKNOWN;
75

76
   tree_t t = tree_from_object(obj);
46,841✔
77
   if (t != NULL) {
46,841✔
78
      switch (kind) {
46,829✔
79
      case COV_ITEM_STMT:
994✔
80
         switch (tree_kind(t)) {
994✔
81
         case T_ASSERT:
9✔
82
            return tree_has_value(t) ? COV_SRC_ASSERT : COV_SRC_REPORT;
9✔
83
         case T_WAIT:
84
            return COV_SRC_WAIT;
85
         case T_FOR:
18✔
86
         case T_WHILE:
87
            return COV_SRC_LOOP_STMT;
18✔
88
         case T_SIGNAL_ASSIGN:
287✔
89
            return COV_SRC_SIGNAL_ASSIGN;
287✔
90
         case T_VAR_ASSIGN:
20✔
91
            return COV_SRC_VAR_ASSIGN;
20✔
92
         case T_IF:
73✔
93
            return COV_SRC_IF_STMT;
73✔
94
         default:
331✔
95
            return COV_SRC_STATEMENT;
331✔
96
         }
97
      case COV_ITEM_BRANCH:
495✔
98
         switch (tree_kind(t)) {
495✔
99
         case T_COND_STMT:
100
         case T_COND_ASSIGN:
101
            return COV_SRC_IF_CONDITION;
102
         case T_ASSOC:
145✔
103
            return COV_SRC_CASE_CHOICE;
145✔
104
         case T_WHILE:
×
105
         case T_EXIT:
106
         case T_NEXT:
107
            return COV_SRC_LOOP_CONTROL;
×
108
         default:
×
109
            return COV_SRC_CONDITION;
×
110
         }
111
      default:
112
         return COV_SRC_UNKNOWN;
113
      }
114
   }
115

116
   psl_node_t p = psl_from_object(obj);
12✔
117
   if (p != NULL) {
12✔
118
      switch (kind) {
12✔
119
      case COV_ITEM_FUNCTIONAL:
120
         return COV_SRC_PSL_COVER;
121
      default:
×
122
         return COV_SRC_UNKNOWN;
×
123
      }
124
   }
125

126
   return COV_SRC_UNKNOWN;
127
}
128

129
const loc_t get_cover_loc(cover_item_kind_t kind, object_t *obj)
49,164✔
130
{
131
   if (obj == NULL)
49,164✔
132
      return LOC_INVALID;
48✔
133

134
   tree_t t = tree_from_object(obj);
49,116✔
135
   if (t != NULL) {
49,116✔
136
      // Refer location of test condition instead of branch statement to
137
      // get accurate test condition location in the coverage report
138
      if (kind == COV_ITEM_BRANCH && tree_kind(t) != T_ASSOC)
49,092✔
139
         return *tree_loc(tree_value(t));
531✔
140
   }
141

142
   return obj->loc;
48,585✔
143
}
144

145
static int32_t cover_add_item(cover_data_t *data, cover_scope_t *cs,
46,865✔
146
                              object_t *obj, ident_t suffix,
147
                              cover_item_kind_t kind, uint32_t flags,
148
                              int consecutive)
149
{
150
   // Everything creates scope, so name of current item is already given
151
   // by scope in hierarchy.
152
   ident_t hier = cs->hier;
46,865✔
153
   if (suffix)
46,865✔
154
      hier = ident_prefix(hier, suffix, '\0');
43,989✔
155

156
   ident_t func_name = NULL;
46,865✔
157
   loc_t loc_lhs = LOC_INVALID, loc_rhs = LOC_INVALID;
46,865✔
158

159
   // Expression items do not nest scope, expression name must be created
160
   if (kind == COV_ITEM_EXPRESSION) {
46,865✔
161
      char buf[16];
859✔
162
      checked_sprintf(buf, sizeof(buf), "_E%d", cs->expression_label);
859✔
163
      hier = ident_prefix(hier, ident_new(buf), '.');
859✔
164
      cs->expression_label++;
859✔
165

166
      tree_t t = tree_from_object(obj);
859✔
167
      assert(t != NULL);
859✔
168

169
      // Query LHS/RHS operand locations of binary expressions
170
      if (flags & COVER_FLAGS_LHS_RHS_BINS) {
859✔
171
         assert(tree_params(t) > 1);
435✔
172
         loc_lhs = *tree_loc(tree_param(t, 0));
435✔
173
         loc_rhs = *tree_loc(tree_param(t, 1));
435✔
174
      }
175

176
      func_name = tree_ident(t);
859✔
177
   }
178

179
   // Append BIN name to the cover item
180
   if (kind == COV_ITEM_BRANCH ||kind == COV_ITEM_TOGGLE || kind == COV_ITEM_EXPRESSION)
46,865✔
181
      hier = ident_prefix(hier, ident_new(cover_bmask_to_bin_str(flags)), '.');
44,974✔
182

183
   int64_t metadata = 0;
46,865✔
184
   if (kind == COV_ITEM_TOGGLE)
46,865✔
185
      metadata = cs->sig_pos;
43,620✔
186

187
   loc_t loc = get_cover_loc(kind, obj);
46,865✔
188

189
   cover_item_t new = {
93,730✔
190
      .kind          = kind,
191
      .tag           = data->next_tag++,
46,865✔
192
      .data          = 0,
193
      .flags         = flags,
194
      .loc           = loc,
195
      .loc_lhs       = loc_lhs,
196
      .loc_rhs       = loc_rhs,
197
      .hier          = hier,
198
      .func_name     = func_name,
199
      .consecutive   = consecutive,
200
      .atleast       = data->threshold,
46,865✔
201
      .metadata      = metadata,
202
      .n_ranges      = 0,
203
      .ranges        = NULL,
204
      .source        = get_cover_source(kind, obj),
46,865✔
205
   };
206

207
#ifdef COVER_DEBUG_EMIT
208
   printf("Item: %s\n", istr(hier));
209
   printf("    Kind:          %s\n", cover_item_kind_str(kind));
210
   printf("    Flags:         0x%x\n", flags);
211
   printf("    Consecutive:   %d\n", consecutive);
212
   printf("    Metadata:      %d\n", metadata);
213
   printf("    Function name: %s\n", istr(func_name));
214
   printf("    First line:    %d\n", loc.first_line);
215
   printf("    First column:  %d\n", loc.first_column);
216
   printf("    Line delta:    %d\n", loc.line_delta);
217
   printf("    Column delta:  %d\n", loc.column_delta);
218
   printf("\n\n");
219
#endif
220

221
   APUSH(cs->items, new);
46,865✔
222

223
   return cs->items.count - 1;
46,865✔
224
}
225

226
///////////////////////////////////////////////////////////////////////////////
227
// Toggle coverage item emit
228
///////////////////////////////////////////////////////////////////////////////
229

230
static bool cover_is_toggle_first(tree_t decl)
2,349✔
231
{
232
   const tree_kind_t kind = tree_kind(decl);
2,349✔
233
   return kind == T_SIGNAL_DECL || kind == T_PORT_DECL;
2,349✔
234
}
235

236
static bool cover_skip_array_toggle(cover_data_t *data, int a_size)
147✔
237
{
238
   assert (data);
147✔
239

240
   // Array is equal to or than configured limit
241
   if (data->array_limit != 0 && a_size >= data->array_limit)
147✔
242
      return true;
243

244
   // Array is multi-dimensional or nested
245
   if ((!cover_enabled(data, COVER_MASK_TOGGLE_INCLUDE_MEMS)) && data->array_depth > 0)
147✔
246
      return true;
×
247

248
   return false;
249
}
250

251
static int32_t cover_add_toggle_items_one_bit(cover_data_t *data,
21,810✔
252
                                              cover_scope_t *cs,
253
                                              object_t *obj,
254
                                              ident_t suffix,
255
                                              unsigned int flags)
256
{
257
   assert (obj != NULL);
21,810✔
258

259
   int32_t first_item_index = cover_add_item(data, cs, obj, suffix,
21,810✔
260
                                             COV_ITEM_TOGGLE,
261
                                             flags | COV_FLAG_TOGGLE_TO_1, 2);
262
   cover_add_item(data, cs, obj, suffix, COV_ITEM_TOGGLE,
21,810✔
263
                  flags | COV_FLAG_TOGGLE_TO_0, 1);
264

265
   return first_item_index;
21,810✔
266
}
267

268
static int32_t cover_add_toggle_items(cover_data_t *data, cover_scope_t *cs,
474✔
269
                                      type_t type, object_t *obj,
270
                                      ident_t prefix, int curr_dim)
271
{
272
   assert (data != NULL);
474✔
273

274
   type_t root = type;
275

276
   // Gets well known type for scalar and vectorized version of
277
   // standard types (std_[u]logic[_vector], signed, unsigned)
278
   while (type_base_kind(root) == T_ARRAY)
653✔
279
      root = type_elem(root);
179✔
280
   root = type_base_recur(root);
474✔
281

282
   well_known_t known = is_well_known(type_ident(root));
474✔
283
   if (known != W_IEEE_ULOGIC && known != W_IEEE_ULOGIC_VECTOR)
474✔
284
      return -1;
285

286
   unsigned int flags = 0;
401✔
287
   if (tree_kind(tree_from_object(obj)) == T_SIGNAL_DECL)
401✔
288
      flags |= COV_FLAG_TOGGLE_SIGNAL;
289
   else
290
      flags |= COV_FLAG_TOGGLE_PORT;
100✔
291

292
   if (type_is_scalar(type))
401✔
293
      return cover_add_toggle_items_one_bit(data, cs, obj, NULL, flags);
246✔
294
   else if (type_is_unconstrained(type))
155✔
295
      return -1;   // Not yet supported
296

297
   int t_dims = dimension_of(type);
149✔
298
   tree_t r = range_of(type, t_dims - curr_dim);
149✔
299
   int64_t low, high;
149✔
300

301
   if (!folded_bounds(r, &low, &high))
149✔
302
      return -1;
303

304
   if (high < low)
149✔
305
      return -1;
306

307
   if (cover_skip_array_toggle(data, high - low + 1))
147✔
308
      return -1;
309

310
   int64_t first, last, i;
147✔
311
   int32_t first_item_index = -1;
147✔
312
   int inc;
147✔
313

314
   data->array_depth++;
147✔
315
#ifdef COVER_DEBUG_SCOPE
316
   printf("Added dimension: %d\n", data->array_depth);
317
#endif
318

319
   switch (tree_subkind(r)) {
147✔
320
   case RANGE_DOWNTO:
99✔
321
      i = high;
99✔
322
      first = high;
99✔
323
      last = low;
99✔
324
      inc = -1;
99✔
325
      break;
99✔
326
   case RANGE_TO:
48✔
327
      i = low;
48✔
328
      first = low;
48✔
329
      last = high;
48✔
330
      inc = +1;
48✔
331
      break;
48✔
332
   default:
×
333
      fatal_trace("invalid subkind for range: %d", tree_subkind(r));
334
   }
335

336
   while (1) {
21,498✔
337
      char arr_index[16];
21,645✔
338
      int32_t tmp = -1;
21,645✔
339
      checked_sprintf(arr_index, sizeof(arr_index), "(%"PRIi64")", i);
21,645✔
340
      ident_t arr_suffix =
21,645✔
341
         ident_prefix(prefix, ident_new(arr_index), '\0');
21,645✔
342

343
      // On lowest dimension walk through elements, if elements
344
      // are arrays, then start new (nested) recursion.
345
      if (curr_dim == 1) {
21,645✔
346
         type_t e_type = type_elem(type);
21,609✔
347
         if (type_is_array(e_type))
21,609✔
348
            tmp = cover_add_toggle_items(data, cs, e_type, obj, arr_suffix,
45✔
349
                                         dimension_of(e_type));
45✔
350
         else
351
            tmp = cover_add_toggle_items_one_bit(data, cs, obj,
21,564✔
352
                                                 arr_suffix, flags);
353
      }
354
      else   // Recurse to lower dimension
355
         tmp = cover_add_toggle_items(data, cs, type, obj, arr_suffix,
36✔
356
                                      curr_dim - 1);
357

358
      if (i == first)
21,645✔
359
         first_item_index = tmp;
147✔
360
      if (i == last)
21,645✔
361
         break;
362

363
      i += inc;
21,498✔
364
   }
365

366
   assert(data->array_depth > 0);
147✔
367
   data->array_depth--;
147✔
368
#ifdef COVER_DEBUG_SCOPE
369
   printf("Subtracted dimension: %d\n", data->array_depth);
370
#endif
371

372
   return first_item_index;
147✔
373
}
374

375
///////////////////////////////////////////////////////////////////////////////
376
// Branch coverage item emit
377
///////////////////////////////////////////////////////////////////////////////
378

379
static int32_t cover_add_branch_items_for(cover_data_t *data, cover_scope_t *cs,
320✔
380
                                          object_t *obj)
381
{
382
   tree_t b = tree_from_object(obj);
320✔
383
   int first_item_index = -1;
320✔
384

385
   // Case choice
386
   if (tree_kind(b) == T_ASSOC)
320✔
387
      first_item_index = cover_add_item(data, cs, obj, NULL, COV_ITEM_BRANCH,
145✔
388
                                        COV_FLAG_CHOICE, 1);
389

390
   // If-else
391
   else {
392
      first_item_index = cover_add_item(data, cs, obj, NULL, COV_ITEM_BRANCH,
175✔
393
                                        COV_FLAG_TRUE, 2);
394
      cover_add_item(data, cs, obj, NULL, COV_ITEM_BRANCH, COV_FLAG_FALSE, 1);
175✔
395
   }
396

397
   return first_item_index;
320✔
398
}
399

400
///////////////////////////////////////////////////////////////////////////////
401
// FSM state coverage item emit
402
///////////////////////////////////////////////////////////////////////////////
403

404
static bool cover_skip_type_state(cover_data_t *data, type_t type)
142✔
405
{
406
   if (!type_is_enum(type))
142✔
407
      return true;
408

409
   // Ignore enums from built-in libraries
410
   ident_t full_name = type_ident(type);
89✔
411
   if (ident_starts_with(full_name, well_known(W_STD)) ||
158✔
412
       ident_starts_with(full_name, well_known(W_IEEE)) ||
84✔
413
       ident_starts_with(full_name, well_known(W_NVC)) ||
30✔
414
       ident_starts_with(full_name, well_known(W_VITAL)))
15✔
415
      return true;
74✔
416

417
   ident_t name = ident_rfrom(full_name, '.');
15✔
418
   cover_spec_t *spc = data->spec;
15✔
419

420
   // Type should be recognized as FSM
421
   if (spc) {
15✔
422
      for (int i = 0; i < spc->fsm_type_include.count; i++)
18✔
423
         if (ident_glob(name, AGET(spc->fsm_type_include, i), -1)) {
15✔
424
#ifdef COVER_DEBUG_EMIT
425
            printf("Cover emit: True, fsm-type (Type: %s, Pattern: %s)\n",
426
                  istr(name), AGET(spc->fsm_type_include, i));
427
#endif
428
            return false;
429
         }
430
   }
431

432
   // By default enums should not included
433
   if (data->mask & COVER_MASK_FSM_NO_DEFAULT_ENUMS)
9✔
434
      return true;
435

436
   // Type should not be included
437
   if (spc) {
6✔
438
      for (int i = 0; i < spc->fsm_type_exclude.count; i++)
×
439
         if (ident_glob(name, AGET(spc->fsm_type_exclude, i), -1)) {
×
440
#ifdef COVER_DEBUG_EMIT
441
            printf("Cover emit: False, fsm-type (Type: %s, Pattern: %s)\n",
442
                   istr(name), AGET(spc->fsm_type_exclude, i));
443
#endif
444
            return true;
445
         }
446
     }
447

448
   return false;
449
}
450

451
static int32_t cover_add_state_items_for(cover_data_t *data, cover_scope_t *cs,
142✔
452
                                         object_t *obj)
453
{
454
   type_t type = tree_type(tree_from_object(obj));
142✔
455

456
   if (cover_skip_type_state(data, type))
142✔
457
      return -1;
458

459
   int64_t low, high;
12✔
460
   if (!folded_bounds(range_of(type, 0), &low, &high))
12✔
461
      return -1;
462

463
   // Add single coverage item per enum literal. This is to track
464
   // literal string in the identifier of the coverage item.
465
   type_t base = type_base_recur(type);
12✔
466
   assert(type_is_enum(base));
12✔
467
   ident_t itype = type_ident(type);
12✔
468
   int64_t first_item_index = 0;
12✔
469

470
   for (int64_t i = low; i <= high; i++) {
873✔
471
      ident_t literal = tree_ident(type_enum_literal(base, i));
861✔
472
      ident_t suffix = ident_prefix(ident_new(".BIN_STATE"), literal, '.');
861✔
473
      int32_t curr_item_index =
861✔
474
         cover_add_item(data, cs, obj, suffix, COV_ITEM_STATE,
1,722✔
475
                        COV_FLAG_STATE, ((int)(high - i)) + 1);
861✔
476

477
      // For FSM State coverage, "func_name" stores name of the FSM Enum type
478
      // TODO: Move this logic into "cover_add_item"
479
      cover_item_t *item = AREF(cs->items, curr_item_index);
861✔
480
      item->func_name = ident_rfrom(itype, '.');
861✔
481
      if (i == low) {
861✔
482
         item->metadata = low;
12✔
483
         first_item_index = curr_item_index;
12✔
484
      }
485
   }
486

487
   return first_item_index;
12✔
488
}
489

490
///////////////////////////////////////////////////////////////////////////////
491
// Expression coverage item emit
492
///////////////////////////////////////////////////////////////////////////////
493

494
static int32_t cover_add_expression_xor_items(cover_data_t *data,
42✔
495
                                              cover_scope_t *cs, object_t *obj,
496
                                              uint32_t flags)
497
{
498
   int first_item_index = cover_add_item(data, cs, obj, NULL,
42✔
499
                                         COV_ITEM_EXPRESSION,
500
                                         flags | COV_FLAG_00, 4);
501

502
   cover_add_item(data, cs, obj, NULL, COV_ITEM_EXPRESSION,
42✔
503
                  flags | COV_FLAG_01, 3);
504
   cover_add_item(data, cs, obj, NULL, COV_ITEM_EXPRESSION,
42✔
505
                  flags | COV_FLAG_10, 2);
506
   cover_add_item(data, cs, obj, NULL, COV_ITEM_EXPRESSION,
42✔
507
                  flags | COV_FLAG_11, 1);
508

509
   return first_item_index;
42✔
510
}
511

512
static int32_t cover_add_expression_and_items(cover_data_t *data,
48✔
513
                                              cover_scope_t *cs,
514
                                              object_t *obj, uint32_t flags)
515
{
516
   int first_item_index = cover_add_item(data, cs, obj, NULL,
48✔
517
                                         COV_ITEM_EXPRESSION,
518
                                         flags | COV_FLAG_01, 3);
519

520
   cover_add_item(data, cs, obj, NULL, COV_ITEM_EXPRESSION,
48✔
521
                  flags | COV_FLAG_10, 2);
522
   cover_add_item(data, cs, obj, NULL, COV_ITEM_EXPRESSION,
48✔
523
                  flags | COV_FLAG_11, 1);
524

525
   return first_item_index;
48✔
526
}
527

528
static int32_t cover_add_expression_or_items(cover_data_t *data,
41✔
529
                                             cover_scope_t *cs,
530
                                             object_t *obj, uint32_t flags)
531
{
532
   int first_item_index = cover_add_item(data, cs, obj, NULL,
41✔
533
                                         COV_ITEM_EXPRESSION,
534
                                         flags | COV_FLAG_00, 3);
535

536
   cover_add_item(data, cs, obj, NULL, COV_ITEM_EXPRESSION,
41✔
537
                  flags | COV_FLAG_01, 2);
538
   cover_add_item(data, cs, obj, NULL, COV_ITEM_EXPRESSION,
41✔
539
                  flags | COV_FLAG_10, 1);
540

541
   return first_item_index;
41✔
542
}
543

544
static int32_t cover_add_builtin_expression_items(cover_data_t *data,
280✔
545
                                                  cover_scope_t *cs,
546
                                                  object_t *obj,
547
                                                  subprogram_kind_t builtin)
548
{
549
   // Handle expression result True or False
550
   switch (builtin) {
280✔
551
   case S_SCALAR_EQ:
212✔
552
   case S_SCALAR_NEQ:
553
   case S_SCALAR_LT:
554
   case S_SCALAR_GT:
555
   case S_SCALAR_LE:
556
   case S_SCALAR_GE:
557
   case S_SCALAR_NOT:
558
   {
559
      int first_item_index = cover_add_item(data, cs, obj, NULL,
212✔
560
                                            COV_ITEM_EXPRESSION,
561
                                            COV_FLAG_FALSE, 2);
562
      cover_add_item(data, cs, obj, NULL, COV_ITEM_EXPRESSION,
212✔
563
                     COV_FLAG_TRUE, 1);
564

565
      return first_item_index;
212✔
566
   }
567

568
   case S_SCALAR_XOR:
18✔
569
   case S_SCALAR_XNOR:
570
      return cover_add_expression_xor_items(data, cs, obj, 0);
18✔
571

572
   case S_SCALAR_OR:
23✔
573
   case S_SCALAR_NOR:
574
      return cover_add_expression_or_items(data, cs, obj, 0);
23✔
575

576
   case S_SCALAR_AND:
27✔
577
   case S_SCALAR_NAND:
578
      return cover_add_expression_and_items(data, cs, obj, 0);
27✔
579

580
   default:
×
581
      fatal_trace("unhandled subprogram kind %d in cover_add_builtin_expression_items",
582
                  builtin);
583
   }
584

585
   return -1;
586
}
587

588
static int32_t cover_add_logic_expression_items(cover_data_t *data,
115✔
589
                                                cover_scope_t *cs,
590
                                                object_t *obj)
591
{
592
   tree_t fcall = tree_from_object(obj);
115✔
593
   tree_t decl = tree_ref(fcall);
115✔
594

595
   if (tree_kind(decl) != T_FUNC_DECL)
115✔
596
      return -1;
597

598
   tree_t container = tree_container(decl);
105✔
599
   if (is_well_known(tree_ident(container)) != W_IEEE_1164)
105✔
600
      return -1;
601

602
   // Only binary expressions
603
   if (tree_params(fcall) != 2)
93✔
604
      return -1;
605

606
   // Skip arrays -> Matches behavior of VCS and Modelsim
607
   if (type_is_array(type_param(tree_type(decl), 0)) ||
138✔
608
       type_is_array(type_param(tree_type(decl), 1)))
66✔
609
      return -1;
9✔
610

611
   ident_t full_name = tree_ident2(decl);
63✔
612

613
   // Emit items for each of AND, NAND, OR, NOR, XOR, XNOR
614
   if (ident_starts_with(full_name, well_known(W_IEEE_1164_AND)) ||
114✔
615
       ident_starts_with(full_name, well_known(W_IEEE_1164_NAND)))
51✔
616
      return cover_add_expression_and_items(data, cs, obj,
21✔
617
                                            COV_FLAG_EXPR_STD_LOGIC);
618

619
   if (ident_starts_with(full_name, well_known(W_IEEE_1164_OR)) ||
75✔
620
       ident_starts_with(full_name, well_known(W_IEEE_1164_NOR)))
33✔
621
      return cover_add_expression_or_items(data, cs, obj,
18✔
622
                                           COV_FLAG_EXPR_STD_LOGIC);
623

624
   if (ident_starts_with(full_name, well_known(W_IEEE_1164_XOR)) ||
33✔
625
       ident_starts_with(full_name, well_known(W_IEEE_1164_XNOR)))
9✔
626
      return cover_add_expression_xor_items(data, cs, obj,
24✔
627
                                            COV_FLAG_EXPR_STD_LOGIC);
628

629
   return -1;
630
}
631

632
///////////////////////////////////////////////////////////////////////////////
633
// Lower EMIT API
634
///////////////////////////////////////////////////////////////////////////////
635

636
cover_item_t *cover_add_items_for(cover_data_t *data, cover_scope_t *cs,
2,365✔
637
                                  object_t *obj, cover_item_kind_t kind)
638
{
639
   assert(data != NULL);
2,365✔
640

641
   if (!cs->emit)
2,365✔
642
      return NULL;
643

644
   // Skip coverage emit when ignored by spec-file -> Common for all item kinds
645
   cover_scope_t *ignore_scope = cs;
646
   for (; ignore_scope->type != CSCOPE_INSTANCE && ignore_scope->parent;
7,806✔
647
        ignore_scope = ignore_scope->parent)
648
      ;
649

650
   const loc_t loc = get_cover_loc(kind, obj);
2,299✔
651

652
   for (int i = 0; i < ignore_scope->ignore_lines.count; i++) {
2,838✔
653
      line_range_t *lr = &(ignore_scope->ignore_lines.items[i]);
558✔
654
      if (loc.first_line > lr->start && loc.first_line <= lr->end)
558✔
655
         return NULL;
656
   }
657

658
   // Emit items based on item kind
659
   int32_t first_item_index = -1;
2,280✔
660

661
   switch (kind) {
2,280✔
662
   case COV_ITEM_STMT:
994✔
663
      first_item_index = cover_add_item(data, cs, obj, NULL,
994✔
664
                                        COV_ITEM_STMT, 0, 1);
665
      break;
994✔
666

667
   case COV_ITEM_BRANCH:
320✔
668
      first_item_index = cover_add_branch_items_for(data, cs, obj);
320✔
669
      break;
320✔
670

671
   case COV_ITEM_STATE:
142✔
672
      first_item_index = cover_add_state_items_for(data, cs, obj);
142✔
673
      break;
142✔
674

675
   case COV_ITEM_FUNCTIONAL:
36✔
676
      first_item_index = cover_add_item(data, cs, obj, NULL,
36✔
677
                                        COV_ITEM_FUNCTIONAL, 0, 1);
678
      break;
36✔
679

680
   case COV_ITEM_TOGGLE:
393✔
681
      {
682
         tree_t tree = tree_from_object(obj);
393✔
683
         type_t type = tree_type(tree);
393✔
684
         const int ndims = dimension_of(type);
393✔
685
         first_item_index =
393✔
686
            cover_add_toggle_items(data, cs, type, obj, NULL, ndims);
393✔
687
      }
688
      break;
393✔
689
   case COV_ITEM_EXPRESSION:
395✔
690
   {
691
      tree_t tree = tree_from_object(obj);
395✔
692
      if (tree_kind(tree) == T_PROT_FCALL)
395✔
693
         break;
694

695
      assert(tree_kind(tree) == T_FCALL);
395✔
696

697
      // Choose if to emit for built-in or "std_logic"
698
      tree_t decl = tree_ref(tree);
395✔
699
      const subprogram_kind_t kind = tree_subkind(decl);
395✔
700

701
      if (is_open_coded_builtin(kind))
395✔
702
         first_item_index =
280✔
703
            cover_add_builtin_expression_items(data, cs, obj, kind);
280✔
704
      else
705
         first_item_index = cover_add_logic_expression_items(data, cs, obj);
115✔
706

707
      break;
708
   }
709

710
   default:
×
711
      fatal("unsupported type of code coverage: %d at 'cover_add_items_for' !", kind);
×
712
   }
713

714
   return (first_item_index == -1) ? NULL : AREF(cs->items, first_item_index);
2,280✔
715
}
716

717
///////////////////////////////////////////////////////////////////////////////
718
// Coverage data write/read to covdb, covdb merging and coverage scope handling
719
///////////////////////////////////////////////////////////////////////////////
720

721
void cover_merge_one_item(cover_item_t *item, int32_t data)
47,571✔
722
{
723
   switch (item->kind) {
47,571✔
724
   case COV_ITEM_STMT:
3,645✔
725
   case COV_ITEM_FUNCTIONAL:
726
   case COV_ITEM_BRANCH:
727
   case COV_ITEM_STATE:
728
   case COV_ITEM_EXPRESSION:
729
      item->data = saturate_add(item->data, data);
3,645✔
730
      break;
3,645✔
731

732
   // Highest bit of run-time data for COV_ITEM_TOGGLE is used to track
733
   // unreachability due to being constant driven. If multiple designs
734
   // like this are merged, the resulting value would underflow and this
735
   // information would be lost. Similarly, if different designs were
736
   // merged, where one was unreachable due to being constant driven and
737
   // the other was driven. So, If the unreachability is detected, enforce
738
   // its propagation further to the merged database
739
   case COV_ITEM_TOGGLE:
43,926✔
740

741
      if ((item->data & COV_FLAG_UNREACHABLE) || (data & COV_FLAG_UNREACHABLE))
43,926✔
742
         item->data = COV_FLAG_UNREACHABLE;
60✔
743
      else
744
         item->data = saturate_add(item->data, data);
43,866✔
745
      break;
746

747
   default:
748
      break;
749
   }
750
}
47,571✔
751

752
static void cover_update_counts(cover_scope_t *s, const int32_t *counts)
3,042✔
753
{
754
   for (int i = 0; i < s->items.count; i++) {
49,842✔
755
      cover_item_t *item = &(s->items.items[i]);
46,800✔
756

757
      const int32_t data = counts ? counts[item->tag] : 0;
46,800✔
758
      cover_merge_one_item(item, data);
46,800✔
759
   }
760

761
   for (int i = 0; i < s->children.count; i++)
5,964✔
762
      cover_update_counts(s->children.items[i], counts);
2,922✔
763
}
3,042✔
764

765
static void cover_write_scope(cover_scope_t *s, fbuf_t *f,
6,378✔
766
                              ident_wr_ctx_t ident_ctx, loc_wr_ctx_t *loc_ctx)
767
{
768
   write_u8(CTRL_PUSH_SCOPE, f);
6,378✔
769

770
   fbuf_put_uint(f, s->type);
6,378✔
771
   ident_write(s->name, ident_ctx);
6,378✔
772
   ident_write(s->hier, ident_ctx);
6,378✔
773
   loc_write(&s->loc, loc_ctx);
6,378✔
774

775
   if (s->type == CSCOPE_INSTANCE)
6,378✔
776
      ident_write(s->block_name, ident_ctx);
480✔
777

778
   fbuf_put_uint(f, s->items.count);
6,378✔
779
   for (int i = 0; i < s->items.count; i++) {
100,347✔
780
      cover_item_t *item = &(s->items.items[i]);
93,969✔
781

782
      fbuf_put_uint(f, item->kind);
93,969✔
783
      fbuf_put_uint(f, item->tag);
93,969✔
784
      fbuf_put_uint(f, item->data);
93,969✔
785
      fbuf_put_uint(f, item->flags);
93,969✔
786
      fbuf_put_uint(f, item->source);
93,969✔
787
      fbuf_put_uint(f, item->consecutive);
93,969✔
788
      fbuf_put_uint(f, item->atleast);
93,969✔
789
      fbuf_put_uint(f, item->n_ranges);
93,969✔
790
      fbuf_put_uint(f, item->metadata);
93,969✔
791

792
      for (int i = 0; i < item->n_ranges; i++) {
93,993✔
793
         fbuf_put_uint(f, item->ranges[i].min);
24✔
794
         fbuf_put_uint(f, item->ranges[i].max);
24✔
795
      }
796

797
      loc_write(&(item->loc), loc_ctx);
93,969✔
798
      if (item->flags & COVER_FLAGS_LHS_RHS_BINS) {
93,969✔
799
         loc_write(&(item->loc_lhs), loc_ctx);
858✔
800
         loc_write(&(item->loc_rhs), loc_ctx);
858✔
801
      }
802

803
      ident_write(item->hier, ident_ctx);
93,969✔
804
      if (item->kind == COV_ITEM_EXPRESSION ||
93,969✔
805
          item->kind == COV_ITEM_STATE ||
93,969✔
806
          item->kind == COV_ITEM_FUNCTIONAL)
807
         ident_write(item->func_name, ident_ctx);
3,510✔
808
   }
809

810
   for (int i = 0; i < s->children.count; i++)
12,510✔
811
      cover_write_scope(s->children.items[i], f, ident_ctx, loc_ctx);
6,132✔
812

813
   write_u8(CTRL_POP_SCOPE, f);
6,378✔
814
}
6,378✔
815

816
LCOV_EXCL_START
817
static void cover_debug_dump(cover_scope_t *s, int indent)
818
{
819
   color_printf("%*s$!blue$%s", indent, "", istr(s->name));
820
   switch (s->type) {
821
   case CSCOPE_INSTANCE: color_printf(" : instance"); break;
822
   default: break;
823
   }
824
   color_printf("$$\n");
825

826
   for (int i = 0; i < s->items.count; i++) {
827
      cover_item_t *item = &(s->items.items[i]);
828

829
      char *path LOCAL = xstrdup(loc_file_str(&item->loc));
830
      printf("%*s%d: %s %s %s:%d => %x\n", indent + 2, "", item->tag,
831
             cover_item_kind_str(item->kind), istr(item->hier),
832
             basename(path), item->loc.first_line, item->data);
833
   }
834

835
   for (int i = 0; i < s->children.count; i++)
836
      cover_debug_dump(s->children.items[i], indent + 2);
837
}
838
LCOV_EXCL_STOP
839

840
void cover_dump_items(cover_data_t *data, fbuf_t *f, cover_dump_t dt,
246✔
841
                      const int32_t *counts)
842
{
843
   if (dt == COV_DUMP_RUNTIME)
246✔
844
      cover_update_counts(data->root_scope, counts);
120✔
845

846
   if (opt_get_int(OPT_COVER_VERBOSE))
246✔
847
      cover_debug_dump(data->root_scope, 0);
×
848

849
   write_u32(COVER_FILE_MAGIC, f);
246✔
850
   fbuf_put_uint(f, COVER_FILE_VERSION);
246✔
851

852
   fbuf_put_uint(f, data->mask);
246✔
853
   fbuf_put_uint(f, data->array_limit);
246✔
854
   fbuf_put_uint(f, data->next_tag);
246✔
855

856
   loc_wr_ctx_t *loc_wr = loc_write_begin(f);
246✔
857
   ident_wr_ctx_t ident_ctx = ident_write_begin(f);
246✔
858

859
   cover_write_scope(data->root_scope, f, ident_ctx, loc_wr);
246✔
860

861
   write_u8(CTRL_END_OF_FILE, f);
246✔
862

863
   loc_write_end(loc_wr);
246✔
864
   ident_write_end(ident_ctx);
246✔
865
}
246✔
866

867
cover_data_t *cover_data_init(cover_mask_t mask, int array_limit, int threshold)
126✔
868
{
869
   cover_data_t *data = xcalloc(sizeof(cover_data_t));
126✔
870
   data->mask = mask;
126✔
871
   data->array_limit = array_limit;
126✔
872
   data->threshold = threshold;
126✔
873

874
   return data;
126✔
875
}
876

877
bool cover_enabled(cover_data_t *data, cover_mask_t mask)
162,086✔
878
{
879
   return data != NULL && (data->mask & mask);
162,086✔
880
}
881

882
static bool cover_should_emit_scope(cover_data_t *data, cover_scope_t *cs,
3,062✔
883
                                    tree_t t)
884
{
885
   cover_spec_t *spc = data->spec;
3,062✔
886
   if (spc == NULL)
3,062✔
887
      return true;
888

889
   // Block (entity, package instance or block) name
890
   if (cs->block_name) {
147✔
891
      ident_t ename = ident_until(cs->block_name, '-');
126✔
892

893
      for (int i = 0; i < spc->block_exclude.count; i++)
216✔
894

895
         if (ident_glob(ename, AGET(spc->block_exclude, i), -1)) {
114✔
896
#ifdef COVER_DEBUG_EMIT
897
            printf("Cover emit: False, block (Block: %s, Pattern: %s)\n",
898
                   istr(cs->block_name), AGET(spc->block_exclude, i));
899
#endif
900
            return false;
901
         }
902

903
      for (int i = 0; i < data->spec->block_include.count; i++)
159✔
904
         if (ident_glob(ename, AGET(spc->block_include, i), -1)) {
90✔
905
#ifdef COVER_DEBUG_EMIT
906
            printf("Cover emit: True, block (Block: %s, Pattern: %s)\n",
907
                   istr(cs->block_name), AGET(spc->block_include, i));
908
#endif
909
            return true;
910
         }
911
   }
912

913
   // Hierarchy
914
   for (int i = 0; i < spc->hier_exclude.count; i++)
150✔
915
      if (ident_glob(cs->hier, AGET(spc->hier_exclude, i), -1)) {
75✔
916
#ifdef COVER_DEBUG_EMIT
917
         printf("Cover emit: False, hierarchy (Hierarchy: %s, Pattern: %s)\n",
918
                istr(cs->hier), AGET(spc->hier_exclude, i));
919
#endif
920
         return false;
921
      }
922

923
   for (int i = 0; i < spc->hier_include.count; i++)
114✔
924
      if (ident_glob(cs->hier, AGET(spc->hier_include, i), -1)) {
75✔
925
#ifdef COVER_DEBUG_EMIT
926
         printf("Cover emit: True, hierarchy (Hierarchy: %s, Pattern: %s)\n",
927
                istr(cs->hier), AGET(spc->hier_include, i));
928
#endif
929
         return true;
930
      }
931

932
   return false;
933
}
934

935
cover_scope_t *cover_create_scope(cover_data_t *data, cover_scope_t *parent,
19,464✔
936
                                  tree_t t, ident_t name)
937
{
938
   if (data == NULL)
19,464✔
939
      return NULL;
940

941
   assert(parent != NULL);
2,825✔
942
   assert(data->root_scope != NULL);
2,825✔
943

944
   cover_scope_t *s = xcalloc(sizeof(cover_scope_t));
2,825✔
945

946
   if (cover_is_branch(t)) {
2,825✔
947
      if (tree_kind(t) == T_ASSOC && tree_subkind(t) == A_OTHERS)
476✔
948
         name = ident_new("_B_OTHERS");
22✔
949
      else
950
         name = ident_sprintf("_B%u", parent->branch_label++);
454✔
951
   }
952
   // For toggle coverage, remember the position where its name in
953
   // the hierarchy starts.
954
   else if (cover_is_toggle_first(t)) {
2,349✔
955
      assert(tree_has_ident(t));
423✔
956
      name = tree_ident(t);
423✔
957
      s->sig_pos = ident_len(parent->hier) + 1;
423✔
958
   }
959
   else if (tree_kind(t) == T_INERTIAL)   // Process without label
1,926✔
960
      name = ident_sprintf("_S%u", parent->stmt_label++);
1✔
961
   else if (name == NULL && tree_has_ident(t))
1,925✔
962
      name = tree_ident(t);
791✔
963
   // Consider everything else as statement
964
   // Expressions do not get scope pushed, so if scope for e.g.
965
   // T_FCALL is pushed it will be concurent function call -> Label as statement
966
   else if (name == NULL)
1,134✔
967
      name = ident_sprintf("_S%u", parent->stmt_label++);
1,122✔
968

969
   s->name       = name;
2,825✔
970
   s->parent     = parent;
2,825✔
971
   s->block_name = s->parent->block_name;
2,825✔
972
   s->loc        = *tree_loc(t);
2,825✔
973
   s->hier       = ident_prefix(s->parent->hier, name, '.');
2,825✔
974
   s->emit       = cover_should_emit_scope(data, s, t);
2,825✔
975

976
   if (s->sig_pos == 0)
2,825✔
977
      s->sig_pos = parent->sig_pos;
2,402✔
978

979
   APUSH(parent->children, s);
2,825✔
980
   return s;
2,825✔
981
}
982

983
cover_scope_t *cover_create_instance(cover_data_t *data, cover_scope_t *parent,
237✔
984
                                     tree_t block, tree_t unit)
985
{
986

987
   if (data == NULL)
237✔
988
      return NULL;
989
   else if (parent == NULL) {
237✔
990
      assert(data->root_scope == NULL);
126✔
991

992
      parent = data->root_scope = xcalloc(sizeof(cover_scope_t));
126✔
993
      parent->name = parent->hier = lib_name(lib_work());
126✔
994
   }
995

996
   // TODO: do not emit scopes for components
997
   assert(tree_kind(unit) == T_ARCH);
237✔
998
   assert(tree_kind(block) == T_BLOCK);
237✔
999

1000
   cover_scope_t *s = xcalloc(sizeof(cover_scope_t));
237✔
1001
   s->name       = tree_ident(block);
237✔
1002
   s->parent     = parent;
237✔
1003
   s->loc        = *tree_loc(block);
237✔
1004
   s->hier       = ident_prefix(s->parent->hier, s->name, '.');
237✔
1005
   s->emit       = cover_should_emit_scope(data, s, block);
237✔
1006
   s->block_name = ident_rfrom(tree_ident(unit), '.');
237✔
1007
   s->type       = CSCOPE_INSTANCE;
237✔
1008

1009
   if (s->sig_pos == 0)
237✔
1010
      s->sig_pos = parent->sig_pos;
237✔
1011

1012
   APUSH(parent->children, s);
237✔
1013
   return s;
237✔
1014
}
1015

1016
static void cover_read_header(fbuf_t *f, cover_data_t *data)
309✔
1017
{
1018
   assert(data != NULL);
309✔
1019

1020
   if (read_u32(f) != COVER_FILE_MAGIC)
309✔
UNCOV
1021
      fatal("%s is not a valid coverage database", fbuf_file_name(f));
×
1022

1023
   const unsigned version = fbuf_get_uint(f);
309✔
1024
   if (version != COVER_FILE_VERSION)
309✔
UNCOV
1025
      fatal("coverage database %s format version %d is not the expected %d",
×
1026
            fbuf_file_name(f), version, COVER_FILE_VERSION);
1027

1028
   data->mask        = fbuf_get_uint(f);
309✔
1029
   data->array_limit = fbuf_get_uint(f);
309✔
1030
   data->next_tag    = fbuf_get_uint(f);
309✔
1031
}
309✔
1032

1033
static void cover_read_one_item(fbuf_t *f, loc_rd_ctx_t *loc_rd,
97,812✔
1034
                                ident_rd_ctx_t ident_ctx, cover_item_t *item)
1035
{
1036
   item->kind        = fbuf_get_uint(f);
97,812✔
1037
   item->tag         = fbuf_get_uint(f);
97,812✔
1038
   item->data        = fbuf_get_uint(f);
97,812✔
1039
   item->flags       = fbuf_get_uint(f);
97,812✔
1040
   item->source      = fbuf_get_uint(f);
97,812✔
1041
   item->consecutive = fbuf_get_uint(f);
97,812✔
1042
   item->atleast     = fbuf_get_uint(f);
97,812✔
1043
   item->n_ranges    = fbuf_get_uint(f);
97,812✔
1044
   item->metadata    = fbuf_get_uint(f);
97,812✔
1045

1046
   if (item->n_ranges > 0)
97,812✔
1047
      item->ranges = xcalloc_array(item->n_ranges, sizeof(cover_range_t));
48✔
1048

1049
   for (int i = 0; i < item->n_ranges; i++) {
97,860✔
1050
      item->ranges[i].min = fbuf_get_uint(f);
48✔
1051
      item->ranges[i].max = fbuf_get_uint(f);
48✔
1052
   }
1053

1054
   loc_read(&(item->loc), loc_rd);
97,812✔
1055
   if (item->flags & COVER_FLAGS_LHS_RHS_BINS) {
97,812✔
1056
      loc_read(&(item->loc_lhs), loc_rd);
1,353✔
1057
      loc_read(&(item->loc_rhs), loc_rd);
1,353✔
1058
   }
1059

1060
   item->hier = ident_read(ident_ctx);
97,812✔
1061
   if (item->kind == COV_ITEM_EXPRESSION ||
97,812✔
1062
       item->kind == COV_ITEM_STATE ||
97,812✔
1063
       item->kind == COV_ITEM_FUNCTIONAL)
1064
      item->func_name = ident_read(ident_ctx);
4,431✔
1065
}
97,812✔
1066

1067
static cover_scope_t *cover_read_scope(fbuf_t *f, ident_rd_ctx_t ident_ctx,
8,901✔
1068
                                       loc_rd_ctx_t *loc_ctx)
1069
{
1070
   cover_scope_t *s = xcalloc(sizeof(cover_scope_t));
8,901✔
1071
   s->type = fbuf_get_uint(f);
8,901✔
1072
   s->name = ident_read(ident_ctx);
8,901✔
1073
   s->hier = ident_read(ident_ctx);
8,901✔
1074

1075
   loc_read(&s->loc, loc_ctx);
8,901✔
1076

1077
   if (s->type == CSCOPE_INSTANCE)
8,901✔
1078
      s->block_name = ident_read(ident_ctx);
582✔
1079

1080
   const int nitems = fbuf_get_uint(f);
8,901✔
1081
   for (int i = 0; i < nitems; i++) {
106,713✔
1082
      cover_item_t new;
97,812✔
1083
      cover_read_one_item(f, loc_ctx, ident_ctx, &new);
97,812✔
1084

1085
      APUSH(s->items, new);
97,812✔
1086
   }
1087

1088
   for (;;) {
26,085✔
1089
      const uint8_t ctrl = read_u8(f);
17,493✔
1090
      switch (ctrl) {
17,493✔
1091
      case CTRL_PUSH_SCOPE:
8,592✔
1092
         {
1093
            cover_scope_t *child = cover_read_scope(f, ident_ctx, loc_ctx);
8,592✔
1094
            APUSH(s->children, child);
8,592✔
1095
         }
1096
         break;
8,592✔
1097
      case CTRL_POP_SCOPE:
8,901✔
1098
         return s;
8,901✔
UNCOV
1099
      default:
×
1100
         fatal_trace("invalid control word %x in cover db", ctrl);
1101
      }
1102
   }
1103
}
1104

1105
cover_data_t *cover_read_items(fbuf_t *f, uint32_t pre_mask)
291✔
1106
{
1107
   cover_data_t *data = xcalloc(sizeof(cover_data_t));
291✔
1108
   cover_read_header(f, data);
291✔
1109
   data->mask |= pre_mask;
291✔
1110

1111
   loc_rd_ctx_t *loc_rd = loc_read_begin(f);
291✔
1112
   ident_rd_ctx_t ident_ctx = ident_read_begin(f);
291✔
1113

1114
   bool eof = false;
291✔
1115
   do {
582✔
1116
      const uint8_t ctrl = read_u8(f);
582✔
1117
      switch (ctrl) {
582✔
1118
      case CTRL_PUSH_SCOPE:
291✔
1119
         data->root_scope = cover_read_scope(f, ident_ctx, loc_rd);
291✔
1120
         break;
291✔
1121
      case CTRL_END_OF_FILE:
1122
         eof = true;
1123
         break;
UNCOV
1124
      default:
×
1125
         fatal_trace("invalid control word %x in cover db", ctrl);
1126
      }
1127
   } while (!eof);
291✔
1128

1129
   ident_read_end(ident_ctx);
291✔
1130
   loc_read_end(loc_rd);
291✔
1131

1132
   return data;
291✔
1133
}
1134

1135
static void cover_merge_scope(cover_scope_t *old_s, cover_scope_t *new_s)
345✔
1136
{
1137
   // Most merged cover scopes have equal items.
1138
   // Start from equal item index in old and new scope instead of iterating
1139
   // for each items.
1140
   // If new scope has extra item in the middle (e.g. due to generic sized array)
1141
   // account for offset. Then there is no reiteration upon added items.
1142
   int n_added = 0;
345✔
1143
   for (int i = 0; i < new_s->items.count; i++) {
1,098✔
1144
      cover_item_t *new = AREF(new_s->items, i);
753✔
1145
      cover_item_t *old = AREF(old_s->items, i - n_added);
753✔
1146

1147
      bool found = false;
753✔
1148
      int n_old_visits = 0;
753✔
1149

1150
      do {
783✔
1151
         if (n_old_visits == old_s->items.count)
768✔
1152
            break;
1153

1154
         if ((new->hier == old->hier) && (new->flags == old->flags)) {
762✔
1155
            assert(new->kind == old->kind);
747✔
1156
#ifdef COVER_DEBUG_MERGE
1157
            printf("Merging coverage item: %s\n", istr(old->hier));
1158
#endif
1159
            cover_merge_one_item(old, new->data);
747✔
1160
            found = true;
747✔
1161
            break;
747✔
1162
         }
1163

1164
         if (old == AREF(old_s->items, old_s->items.count - 1))
15✔
1165
            old = AREF(old_s->items, 0);
1166
         else
1167
            old++;
9✔
1168

1169
         n_old_visits++;
15✔
1170
      } while (true);
1171

1172
      if (!found) {
747✔
1173
         APUSH(old_s->items, *new);
6✔
1174
         n_added++;
6✔
1175
      }
1176
   }
1177

1178
   for (int i = 0; i < new_s->children.count; i++) {
681✔
1179
      cover_scope_t *new_c = new_s->children.items[i];
336✔
1180
      bool found = false;
336✔
1181
      for (int j = 0; j < old_s->children.count; j++) {
705✔
1182
         cover_scope_t *old_c = old_s->children.items[j];
696✔
1183
         if (new_c->name == old_c->name) {
696✔
1184
            cover_merge_scope(old_c, new_c);
327✔
1185
            found = true;
327✔
1186
            break;
327✔
1187
         }
1188
      }
1189

1190
      if (!found)
327✔
1191
         APUSH(old_s->children, new_c);
336✔
1192
   }
1193
}
345✔
1194

1195
void cover_merge_items(fbuf_t *f, cover_data_t *data)
18✔
1196
{
1197
   assert (data != NULL);
18✔
1198

1199
   cover_read_header(f, data);
18✔
1200

1201
   loc_rd_ctx_t *loc_rd = loc_read_begin(f);
18✔
1202
   ident_rd_ctx_t ident_ctx = ident_read_begin(f);
18✔
1203

1204
   bool eof = false;
18✔
1205
   do {
36✔
1206
      const uint8_t ctrl = read_u8(f);
36✔
1207
      switch (ctrl) {
36✔
1208
      case CTRL_PUSH_SCOPE:
18✔
1209
         {
1210
            cover_scope_t *new = cover_read_scope(f, ident_ctx, loc_rd);
18✔
1211
            cover_merge_scope(data->root_scope, new);
18✔
1212
         }
1213
         break;
18✔
1214
      case CTRL_END_OF_FILE:
1215
         eof = true;
1216
         break;
UNCOV
1217
      default:
×
1218
         fatal_trace("invalid control word %x in cover db", ctrl);
1219
      }
1220
   } while (!eof);
18✔
1221

1222
   ident_read_end(ident_ctx);
18✔
1223
   loc_read_end(loc_rd);
18✔
1224
}
18✔
1225

1226
unsigned cover_count_items(cover_data_t *data)
240✔
1227
{
1228
   if (data == NULL)
240✔
1229
      return 0;
1230
   else
1231
      return data->next_tag;
240✔
1232
}
1233

UNCOV
1234
void cover_bmask_to_bin_list(uint32_t bmask, text_buf_t *tb)
×
1235
{
UNCOV
1236
   bool empty = true;
×
UNCOV
1237
   for (int i = 0; i < ARRAY_LEN(bin_map); i++) {
×
UNCOV
1238
      if (bmask & bin_map[i].flag) {
×
UNCOV
1239
         if (!empty)
×
UNCOV
1240
            tb_cat(tb, ", ");
×
UNCOV
1241
         tb_cat(tb, bin_map[i].name);
×
UNCOV
1242
         empty = false;
×
1243
      }
1244
   }
UNCOV
1245
}
×
1246

UNCOV
1247
uint32_t cover_bin_str_to_bmask(const char *bin)
×
1248
{
UNCOV
1249
   for (int i = 0; i < ARRAY_LEN(bin_map); i++) {
×
1250
      if (strcmp(bin, bin_map[i].name) == 0)
×
1251
         return bin_map[i].flag;
×
1252
   }
1253

1254
   return 0;
1255
}
1256

1257
const char *cover_bmask_to_bin_str(uint32_t bmask)
44,974✔
1258
{
1259
   // TODO: Smarter way instead of iterating -> Probably OK for such small array
1260
   //       even if called many times!
1261
   for (int i = 0; i < ARRAY_LEN(bin_map); i++)
374,769✔
1262
      if (bmask & bin_map[i].flag)
374,769✔
1263
         return bin_map[i].name;
44,974✔
1264

1265
   should_not_reach_here();
1266
}
1267

1268
const char *cover_item_kind_str(cover_item_kind_t kind)
44,310✔
1269
{
1270
   static const char* item_kind_str[] = {
44,310✔
1271
      "statement",
1272
      "branch",
1273
      "toggle",
1274
      "expression",
1275
      "FSM state",
1276
      "cover point",
1277
   };
1278
   assert(kind < ARRAY_LEN(item_kind_str));
44,310✔
1279
   return item_kind_str[kind];
44,310✔
1280
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc