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

nickg / nvc / 20579380967

29 Dec 2025 06:01PM UTC coverage: 92.567% (+0.002%) from 92.565%
20579380967

push

github

nickg
Add subprogram kinds for IEEE operations

133 of 136 new or added lines in 5 files covered. (97.79%)

1 existing line in 1 file now uncovered.

75747 of 81829 relevant lines covered (92.57%)

455172.58 hits per line

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

88.37
/src/eval.c
1
//
2
//  Copyright (C) 2013-2023  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 "common.h"
20
#include "diag.h"
21
#include "eval.h"
22
#include "hash.h"
23
#include "ident.h"
24
#include "jit/jit-ffi.h"
25
#include "jit/jit.h"
26
#include "lib.h"
27
#include "lower.h"
28
#include "mir/mir-unit.h"
29
#include "option.h"
30
#include "phase.h"
31
#include "rt/assert.h"
32
#include "tree.h"
33
#include "type.h"
34
#include "vcode.h"
35

36
#include <assert.h>
37
#include <stdint.h>
38
#include <stdlib.h>
39
#include <stdarg.h>
40
#include <inttypes.h>
41
#include <string.h>
42

43
static const char *eval_expr_name(tree_t expr)
×
44
{
45
   const tree_kind_t kind = tree_kind(expr);
×
46
   if (kind == T_FCALL)
×
47
      return istr(tree_ident(expr));
×
48
   else
49
      return tree_kind_str(kind);
×
50
}
51

52
static tree_t eval_value_to_tree(jit_scalar_t value, type_t type,
10,746✔
53
                                 const loc_t *loc)
54
{
55
   tree_t tree = NULL;
10,746✔
56

57
   if (type_is_enum(type)) {
10,746✔
58
      type_t base = type_base_recur(type);
2,760✔
59
      if ((unsigned)value.integer >= type_enum_literals(base))
2,760✔
60
         fatal_at(loc, "enum position %"PRIi64" out of range for type %s",
×
61
                  value.integer, type_pp(base));
62

63
      tree_t lit = type_enum_literal(base, value.integer);
2,760✔
64

65
      tree = tree_new(T_REF);
2,760✔
66
      tree_set_ref(tree, lit);
2,760✔
67
      tree_set_ident(tree, tree_ident(lit));
2,760✔
68
   }
69
   else if (type_is_integer(type)) {
7,986✔
70
      tree = tree_new(T_LITERAL);
1,786✔
71
      tree_set_subkind(tree, L_INT);
1,786✔
72
      tree_set_ival(tree, value.integer);
1,786✔
73
   }
74
   else if (type_is_real(type)) {
6,200✔
75
      tree = tree_new(T_LITERAL);
6,132✔
76
      tree_set_subkind(tree, L_REAL);
6,132✔
77
      tree_set_dval(tree, value.real);
6,132✔
78
   }
79
   else if (type_is_physical(type)) {
68✔
80
      tree = tree_new(T_LITERAL);
68✔
81
      tree_set_subkind(tree, L_PHYSICAL);
68✔
82
      tree_set_ival(tree, value.integer);
68✔
83
      tree_set_ident(tree, tree_ident(type_unit(type_base_recur(type), 0)));
68✔
84
   }
85
   else
86
      fatal_trace("cannot convert 0x%"PRIx64" to %s", value.integer,
87
                  type_pp(type));
88

89
   tree_set_type(tree, type);
10,746✔
90
   tree_set_loc(tree, loc);
10,746✔
91
   return tree;
10,746✔
92
}
93

94
static void *thunk_result_cb(jit_scalar_t *args, void *user)
11,045✔
95
{
96
   tree_t expr = user;
11,045✔
97
   type_t type = tree_type(expr);
11,045✔
98
   const loc_t *loc = tree_loc(expr);
11,045✔
99

100
   if (type_is_array(type)) {
11,045✔
101
      assert(dimension_of(type) == 1);
311✔
102

103
      type_t elem = type_elem(type);
311✔
104
      assert(type_is_scalar(elem));
311✔
105

106
      type_t base = type_base_recur(elem);
311✔
107

108
      bool all_chars = true;
311✔
109
      tree_t *lits LOCAL = NULL;
622✔
110
      if (type_is_enum(elem)) {
311✔
111
         const int nlits = type_enum_literals(base);
306✔
112
         lits = xcalloc_array(nlits, sizeof(tree_t));
306✔
113
      }
114
      else
115
         all_chars = false;
116

117
      range_kind_t dir;
311✔
118
      int64_t length, ileft, iright;
311✔
119
      if (!type_const_bounds(type)) {
311✔
120
         length = ffi_array_length(args[2].integer);
288✔
121
         dir = ffi_array_dir(args[2].integer);
288✔
122
         ileft = args[1].integer;
288✔
123
         iright = ffi_array_right(args[1].integer, args[2].integer);
444✔
124
      }
125
      else {
126
         tree_t r = range_of(type, 0);
23✔
127
         if (!folded_length(r, &length))
23✔
128
            fatal_at(loc, "cannot determine static length of array");
×
129

130
         dir = tree_subkind(r);
23✔
131
         ileft = assume_int(tree_left(r));
23✔
132
         iright = assume_int(tree_right(r));
23✔
133
      }
134

135
      const int bytes = (type_bit_width(elem) + 7) / 8;
311✔
136
      tree_t *elts LOCAL = xmalloc_array(length, sizeof(tree_t));
622✔
137
      for (int i = 0; i < length; i++) {
4,708✔
138
#define UNPACK_VALUE(type) do {                                    \
139
            value.integer = ((type *)args[0].pointer)[i];          \
140
         } while (0);
141

142
         jit_scalar_t value = { .integer = 0 };
4,397✔
143
         FOR_ALL_SIZES(bytes, UNPACK_VALUE);
4,397✔
144

145
         if (lits != NULL) {
4,397✔
146
            assert(value.integer >= 0);
4,385✔
147

148
            if (lits[value.integer] == NULL) {
4,385✔
149
               tree_t li = type_enum_literal(base, value.integer);
588✔
150
               lits[value.integer] = make_ref(li);
588✔
151
               all_chars &= ident_char(tree_ident(li), 0) == '\'';
588✔
152
            }
153

154
            elts[i] = lits[value.integer];
4,385✔
155
         }
156
         else
157
            elts[i] = eval_value_to_tree(value, elem, loc);
12✔
158
      }
159

160
      type_t sub = type_new(T_SUBTYPE);
311✔
161
      type_set_base(sub, type);
311✔
162

163
      type_t index_type = index_type_of(type, 0);
311✔
164

165
      tree_t left = NULL, right = NULL;
311✔
166
      if (type_is_enum(index_type)) {
311✔
167
         left = get_enum_lit(expr, index_type, ileft);
18✔
168
         right = get_enum_lit(expr, index_type, iright);
18✔
169
      }
170
      else {
171
         left = get_int_lit(expr, index_type, ileft);
293✔
172
         right = get_int_lit(expr, index_type, iright);
293✔
173
      }
174

175
      tree_t r = tree_new(T_RANGE);
311✔
176
      tree_set_subkind(r, dir);
311✔
177
      tree_set_left(r, left);
311✔
178
      tree_set_right(r, right);
311✔
179
      tree_set_loc(r, loc);
311✔
180
      tree_set_type(r, index_type);
311✔
181

182
      tree_t c = tree_new(T_CONSTRAINT);
311✔
183
      tree_set_subkind(c, C_INDEX);
311✔
184
      tree_add_range(c, r);
311✔
185
      tree_set_loc(c, loc);
311✔
186

187
      type_set_constraint(sub, c);
311✔
188

189
      if (all_chars) {
311✔
190
         tree_t tree = tree_new(T_STRING);
269✔
191

192
         for (int i = 0; i < length; i++)
4,508✔
193
            tree_add_char(tree, elts[i]);
4,239✔
194

195
         tree_set_loc(tree, loc);
269✔
196
         tree_set_type(tree, sub);
269✔
197
         return tree;
269✔
198
      }
199
      else {
200
         tree_t tree = tree_new(T_AGGREGATE);
42✔
201
         tree_set_type(tree, sub);
42✔
202
         tree_set_loc(tree, loc);
42✔
203

204
         for (int i = 0; i < length; i++) {
200✔
205
            tree_t a = tree_new(T_ASSOC);
158✔
206
            tree_set_loc(a, loc);
158✔
207
            tree_set_subkind(a, A_POS);
158✔
208
            tree_set_pos(a, i);
158✔
209
            tree_set_value(a, elts[i]);
158✔
210

211
            tree_add_assoc(tree, a);
158✔
212
         }
213

214
         return tree;
215
      }
216
   }
217
   else
218
      return eval_value_to_tree(args[0], tree_type(expr), tree_loc(expr));
10,734✔
219
}
220

221
static tree_t eval_do_fold(jit_t *jit, tree_t expr, lower_unit_t *parent,
11,157✔
222
                           unit_registry_t *registry, void *context)
223
{
224
   vcode_unit_t thunk;
11,157✔
225
   if (parent != NULL)
11,157✔
226
      thunk = lower_thunk_in_context(registry, expr, parent);
274✔
227
   else
228
      thunk = lower_global_thunk(registry, expr);
10,883✔
229

230
   if (thunk == NULL)
11,157✔
231
      return expr;
232

233
   const bool verbose = opt_get_verbose(OPT_EVAL_VERBOSE, NULL);
11,094✔
234

235
   tree_t result = jit_call_thunk(jit, thunk, context, thunk_result_cb, expr);
11,094✔
236

237
   vcode_unit_unref(thunk);
11,090✔
238
   thunk = NULL;
11,090✔
239

240
   if (result != NULL) {
11,090✔
241
      if (verbose) {
11,045✔
242
         LOCAL_TEXT_BUF tb = tb_new();
×
243
         capture_syntax(tb);
×
244
         dump(result);
×
245
         capture_syntax(NULL);
×
246
         tb_strip(tb);
×
247

248
         debugf("evaluating %s returned %s", eval_expr_name(expr), tb_get(tb));
×
249
      }
250

251
      return result;
11,045✔
252
   }
253
   else if (verbose) {
45✔
254
      diag_t *d = diag_new(DIAG_DEBUG, tree_loc(expr));
×
255
      diag_printf(d, "failed to evaluate %s", eval_expr_name(expr));
×
256
      diag_emit(d);
×
257
   }
258

259
   return expr;
260
}
261

262
tree_t eval_try_fold(jit_t *jit, tree_t expr, unit_registry_t *registry,
10,883✔
263
                     lower_unit_t *parent, void *context)
264
{
265
   const bool verbose = opt_get_verbose(OPT_EVAL_VERBOSE, NULL);
10,883✔
266
   jit_set_silent(jit, !verbose);
10,883✔
267

268
   tree_t result = eval_do_fold(jit, expr, parent, registry, context);
10,883✔
269

270
   jit_set_silent(jit, false);
10,879✔
271
   jit_reset_exit_status(jit);
10,879✔
272

273
   clear_vhdl_assert();
10,879✔
274

275
   return result;
10,879✔
276
}
277

278
tree_t eval_must_fold(jit_t *jit, tree_t expr, unit_registry_t *registry,
274✔
279
                      lower_unit_t *parent, void *context)
280
{
281
   return eval_do_fold(jit, expr, parent, registry, context);
274✔
282
}
283

284
static bool eval_not_possible(tree_t t, const char *why)
5,458✔
285
{
286
   if (opt_get_verbose(OPT_EVAL_VERBOSE, NULL))
5,458✔
287
      warn_at(tree_loc(t), "%s prevents constant folding", why);
×
288

289
   return false;
5,458✔
290
}
291

292
bool eval_possible(tree_t t, unit_registry_t *ur, mir_context_t *mc)
42,695✔
293
{
294
   switch (tree_kind(t)) {
51,134✔
295
   case T_FCALL:
13,994✔
296
      {
297
         const tree_flags_t flags = tree_flags(t);
13,994✔
298
         if (!(flags & (TREE_F_LOCALLY_STATIC | TREE_F_GLOBALLY_STATIC)))
13,994✔
299
            return eval_not_possible(t, "non-static expression");
55✔
300

301
         tree_t decl = tree_ref(t);
13,939✔
302

303
         const subprogram_kind_t kind = tree_subkind(decl);
13,939✔
304
         switch (kind) {
13,939✔
305
         case S_USER:
2,729✔
306
            if (tree_flags(decl) & TREE_F_IMPURE)
2,729✔
NEW
307
               return eval_not_possible(t, "call to impure function");
×
308
            else if (!is_package(tree_container(decl)))
2,729✔
309
               return eval_not_possible(t, "subprogram not in package");
830✔
310
            break;
311
         case S_IEEE_MISC:
312
            break;
313
         default:
11,040✔
314
            if (!is_open_coded_builtin(kind)
11,040✔
315
                && unit_registry_get(ur, tree_ident2(decl)) == NULL
1,418✔
316
                && mir_get_unit(mc, tree_ident2(decl)) == NULL)
1,322✔
317
               return eval_not_possible(t, "not yet lowered predef");
168✔
318
            break;
319
         }
320

321
         const int nparams = tree_params(t);
12,941✔
322
         for (int i = 0; i < nparams; i++) {
26,192✔
323
            tree_t p = tree_value(tree_param(t, i));
16,662✔
324
            if (!eval_possible(p, ur, mc))
16,662✔
325
               return false;
326
            else if (tree_kind(p) == T_FCALL && type_is_scalar(tree_type(p)))
13,303✔
327
               return false;  // Would have been folded already if possible
328
         }
329

330
         return true;
331
      }
332

333
   case T_LITERAL:
334
   case T_STRING:
335
   case T_OPEN:
336
      return true;
337

338
   case T_TYPE_CONV:
6,979✔
339
   case T_QUALIFIED:
340
      {
341
         tree_t value = tree_value(t);
6,979✔
342
         if (tree_kind(value) == T_FCALL)
6,979✔
343
            return false;   // Would have been folded already if possible
344

345
         return eval_possible(value, ur, mc);
346
      }
347

348
   case T_REF:
11,136✔
349
      {
350
         tree_t decl = tree_ref(t);
11,136✔
351
         switch (tree_kind(decl)) {
11,136✔
352
         case T_UNIT_DECL:
353
         case T_ENUM_LIT:
354
            return true;
355

356
         case T_CONST_DECL:
1,350✔
357
            if (tree_has_value(decl))
1,350✔
358
               return eval_possible(tree_value(decl), ur, mc);
1,329✔
359
            else
360
               return false;
361

362
         default:
4,163✔
363
            return eval_not_possible(t, "reference");
4,163✔
364
         }
365
      }
366

367
   case T_RECORD_REF:
307✔
368
      return eval_possible(tree_value(t), ur, mc);
307✔
369

370
   case T_ARRAY_REF:
954✔
371
      {
372
         const int nparams = tree_params(t);
954✔
373
         for (int i = 0; i < nparams; i++) {
1,856✔
374
            if (!eval_possible(tree_value(tree_param(t, i)), ur, mc))
989✔
375
               return false;
376
         }
377

378
         return eval_possible(tree_value(t), ur, mc);
867✔
379
      }
380

381
   case T_AGGREGATE:
1,139✔
382
      {
383
         const int nassocs = tree_assocs(t);
1,139✔
384
         for (int i = 0; i < nassocs; i++) {
7,816✔
385
            if (!eval_possible(tree_value(tree_assoc(t, i)), ur, mc))
6,711✔
386
               return false;
387
         }
388

389
         // Check for missing choices in constrained array aggregates
390
         type_t composite_type = tree_type(t);
1,105✔
391
         if (type_is_array(composite_type)
1,105✔
392
             && !type_is_unconstrained(composite_type)) {
995✔
393
            int64_t count = 0, elem_count = 0;
977✔
394
            bool known_elem_count = false;
977✔
395
            bool has_others = false;
977✔
396
            bool has_range = false;
977✔
397
            for (int i = 0; i < nassocs; i++) {
7,286✔
398
               tree_t a = tree_assoc(t, i);
6,309✔
399
               const assoc_kind_t akind = tree_subkind(a);
6,309✔
400

401
               switch (akind) {
6,309✔
402

403
               case A_NAMED:
6,172✔
404
               case A_POS:
405
                  known_elem_count = true;
6,172✔
406
                  elem_count = 1;
6,172✔
407
                  break;
6,172✔
408

409
               case A_RANGE:
53✔
410
                  known_elem_count = false;
53✔
411
                  has_range = true;
53✔
412
                  break;
53✔
413

414
               case A_OTHERS:
42✔
415
                  known_elem_count = false;
42✔
416
                  has_others = true;
42✔
417
                  break;
42✔
418

419
               case A_SLICE:
42✔
420
               case A_CONCAT:
421
                  {
422
                     type_t v_type = tree_type(tree_value(a));
42✔
423
                     known_elem_count = true;
42✔
424
                     if (type_is_unconstrained(v_type))
42✔
425
                        known_elem_count = false;
426
                     else if (!folded_length(range_of(v_type, 0), &elem_count))
42✔
427
                        known_elem_count = false;
×
428
                     break;
429
                  }
430
               }
431

432
               if (known_elem_count)
6,309✔
433
                  count += elem_count;
6,214✔
434
            }
435

436
            if (has_range)
977✔
437
               // Range could overlap, defer to bounds check
438
               return eval_not_possible(t, "range as choice");
56✔
439

440
            if (!has_others) {
924✔
441
               int64_t type_count;
882✔
442
               if (folded_length(range_of(composite_type, 0), &type_count))
882✔
443
                  if (count != type_count)
882✔
444
                     return eval_not_possible(t, "missing choice");
3✔
445
            }
446
         }
447

448
         return true;
449
      }
450

451
   case T_ATTR_REF:
876✔
452
      {
453
         if (tree_subkind(t) == ATTR_USER)
876✔
454
            return eval_not_possible(t, "user defined attribute");
×
455

456
         if (!eval_possible(tree_name(t), ur, mc))
876✔
457
            return false;
458

459
         const int nparams = tree_params(t);
×
460
         for (int i = 0; i < nparams; i++) {
×
461
            if (!eval_possible(tree_value(tree_param(t, i)), ur, mc))
×
462
               return false;
463
         }
464

465
         return true;
466
      }
467

468
   default:
186✔
469
      return eval_not_possible(t, tree_kind_str(tree_kind(t)));
186✔
470
   }
471
}
472

473
static void *case_result_cb(jit_scalar_t *args, void *user)
12✔
474
{
475
   jit_scalar_t *result = user;
12✔
476
   result->integer = args[0].integer;
12✔
477
   return result;
12✔
478
}
479

480
tree_t eval_case(jit_t *jit, tree_t stmt, lower_unit_t *parent, void *context)
12✔
481
{
482
   assert(tree_kind(stmt) == T_CASE_GENERATE);
12✔
483

484
   vcode_unit_t thunk = lower_case_generate_thunk(parent, stmt);
12✔
485

486
   jit_scalar_t result = { .integer = -1 };
12✔
487
   if (jit_call_thunk(jit, thunk, context, case_result_cb, &result) == NULL)
12✔
488
      error_at(tree_loc(tree_value(stmt)), "generate expression is not static");
×
489

490
   vcode_unit_unref(thunk);
12✔
491

492
   if (result.integer == -1)
12✔
493
      return NULL;
494
   else
495
      return tree_stmt(stmt, result.integer);
12✔
496
}
497

498
void *eval_instance(jit_t *jit, ident_t name, void *context)
×
499
{
500
   jit_handle_t h = jit_lazy_compile(jit, name);
×
501
   if (h == JIT_HANDLE_INVALID)
×
502
      fatal_trace("failed to compile instance %s", istr(name));
503

504
   jit_scalar_t result;
×
505
   if (!jit_try_call(jit, h, &result, context, context))
×
506
      return NULL;
507

508
   return result.pointer;
×
509
}
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

© 2026 Coveralls, Inc