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

nickg / nvc / 13041553816

29 Jan 2025 10:09PM UTC coverage: 92.166% (-0.007%) from 92.173%
13041553816

push

github

nickg
Share model between elaboration and runtime

243 of 254 new or added lines in 8 files covered. (95.67%)

15 existing lines in 4 files now uncovered.

64170 of 69624 relevant lines covered (92.17%)

507303.4 hits per line

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

85.14
/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.h"
25
#include "jit/jit-ffi.h"
26
#include "lib.h"
27
#include "lower.h"
28
#include "option.h"
29
#include "phase.h"
30
#include "tree.h"
31
#include "type.h"
32
#include "vcode.h"
33

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

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

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

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

61
      tree_t lit = type_enum_literal(base, value.integer);
2,126✔
62

63
      tree = tree_new(T_REF);
2,126✔
64
      tree_set_ref(tree, lit);
2,126✔
65
      tree_set_ident(tree, tree_ident(lit));
2,126✔
66
   }
67
   else if (type_is_integer(type)) {
8,546✔
68
      tree = tree_new(T_LITERAL);
2,306✔
69
      tree_set_subkind(tree, L_INT);
2,306✔
70
      tree_set_ival(tree, value.integer);
2,306✔
71
   }
72
   else if (type_is_real(type)) {
6,240✔
73
      tree = tree_new(T_LITERAL);
6,121✔
74
      tree_set_subkind(tree, L_REAL);
6,121✔
75
      tree_set_dval(tree, value.real);
6,121✔
76
   }
77
   else if (type_is_physical(type)) {
119✔
78
      tree = tree_new(T_LITERAL);
119✔
79
      tree_set_subkind(tree, L_PHYSICAL);
119✔
80
      tree_set_ival(tree, value.integer);
119✔
81
   }
82
   else
83
      fatal_trace("cannot convert 0x%"PRIx64" to %s", value.integer,
84
                  type_pp(type));
85

86
   tree_set_type(tree, type);
10,672✔
87
   tree_set_loc(tree, loc);
10,672✔
88
   return tree;
10,672✔
89
}
90

91
static void *thunk_result_cb(jit_scalar_t *args, void *user)
10,875✔
92
{
93
   tree_t expr = user;
10,875✔
94
   type_t type = tree_type(expr);
10,875✔
95
   const loc_t *loc = tree_loc(expr);
10,875✔
96

97
   if (type_is_array(type)) {
10,875✔
98
      assert(dimension_of(type) == 1);
215✔
99

100
      type_t elem = type_elem(type);
215✔
101
      assert(type_is_scalar(elem));
215✔
102

103
      type_t base = type_base_recur(elem);
215✔
104

105
      bool all_chars = true;
215✔
106
      tree_t *lits LOCAL = NULL;
430✔
107
      if (type_is_enum(elem)) {
215✔
108
         const int nlits = type_enum_literals(base);
210✔
109
         lits = xcalloc_array(nlits, sizeof(tree_t));
210✔
110
      }
111
      else
112
         all_chars = false;
113

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

127
         dir = tree_subkind(r);
1✔
128
         ileft = assume_int(tree_left(r));
1✔
129
         iright = assume_int(tree_right(r));
1✔
130
      }
131

132
      const int bytes = (type_bit_width(elem) + 7) / 8;
215✔
133
      tree_t *elts LOCAL = xmalloc_array(length, sizeof(tree_t));
430✔
134
      for (int i = 0; i < length; i++) {
2,372✔
135
#define UNPACK_VALUE(type) do {                                    \
136
            value.integer = ((type *)args[0].pointer)[i];          \
137
         } while (0);
138

139
         jit_scalar_t value = { .integer = 0 };
2,157✔
140
         FOR_ALL_SIZES(bytes, UNPACK_VALUE);
2,157✔
141

142
         if (lits != NULL) {
2,157✔
143
            assert(value.integer >= 0);
2,145✔
144

145
            if (lits[value.integer] == NULL) {
2,145✔
146
               tree_t li = type_enum_literal(base, value.integer);
375✔
147
               lits[value.integer] = make_ref(li);
375✔
148
               all_chars &= ident_char(tree_ident(li), 0) == '\'';
375✔
149
            }
150

151
            elts[i] = lits[value.integer];
2,145✔
152
         }
153
         else
154
            elts[i] = eval_value_to_tree(value, elem, loc);
12✔
155
      }
156

157
      type_t sub = type_new(T_SUBTYPE);
215✔
158
      type_set_base(sub, type);
215✔
159

160
      type_t index_type = index_type_of(type, 0);
215✔
161

162
      tree_t left = NULL, right = NULL;
215✔
163
      if (type_is_enum(index_type)) {
215✔
164
         left = get_enum_lit(expr, index_type, ileft);
×
165
         right = get_enum_lit(expr, index_type, iright);
×
166
      }
167
      else {
168
         left = get_int_lit(expr, index_type, ileft);
215✔
169
         right = get_int_lit(expr, index_type, iright);
215✔
170
      }
171

172
      tree_t r = tree_new(T_RANGE);
215✔
173
      tree_set_subkind(r, dir);
215✔
174
      tree_set_left(r, left);
215✔
175
      tree_set_right(r, right);
215✔
176
      tree_set_loc(r, loc);
215✔
177
      tree_set_type(r, index_type);
215✔
178

179
      tree_t c = tree_new(T_CONSTRAINT);
215✔
180
      tree_set_subkind(c, C_INDEX);
215✔
181
      tree_add_range(c, r);
215✔
182
      tree_set_loc(c, loc);
215✔
183

184
      type_add_constraint(sub, c);
215✔
185

186
      if (all_chars) {
215✔
187
         tree_t tree = tree_new(T_STRING);
209✔
188

189
         for (int i = 0; i < length; i++)
2,352✔
190
            tree_add_char(tree, elts[i]);
2,143✔
191

192
         tree_set_loc(tree, loc);
209✔
193
         tree_set_type(tree, sub);
209✔
194
         return tree;
209✔
195
      }
196
      else {
197
         tree_t tree = tree_new(T_AGGREGATE);
6✔
198
         tree_set_type(tree, sub);
6✔
199
         tree_set_loc(tree, loc);
6✔
200

201
         for (int i = 0; i < length; i++) {
20✔
202
            tree_t a = tree_new(T_ASSOC);
14✔
203
            tree_set_loc(a, loc);
14✔
204
            tree_set_subkind(a, A_POS);
14✔
205
            tree_set_pos(a, i);
14✔
206
            tree_set_value(a, elts[i]);
14✔
207

208
            tree_add_assoc(tree, a);
14✔
209
         }
210

211
         return tree;
212
      }
213
   }
214
   else
215
      return eval_value_to_tree(args[0], tree_type(expr), tree_loc(expr));
10,660✔
216
}
217

218
static tree_t eval_do_fold(jit_t *jit, tree_t expr, lower_unit_t *parent,
12,380✔
219
                           unit_registry_t *registry, void *context)
220
{
221
   vcode_unit_t thunk = lower_thunk(registry, expr, parent);
12,380✔
222
   if (thunk == NULL)
12,380✔
223
      return expr;
224

225
   const bool verbose = opt_get_verbose(OPT_EVAL_VERBOSE, NULL);
11,294✔
226

227
   tree_t result = jit_call_thunk(jit, thunk, context, thunk_result_cb, expr);
11,294✔
228

229
   vcode_unit_unref(thunk);
11,290✔
230
   thunk = NULL;
11,290✔
231

232
   if (result != NULL) {
11,290✔
233
      if (verbose) {
10,875✔
234
         LOCAL_TEXT_BUF tb = tb_new();
×
235
         capture_syntax(tb);
×
236
         dump(result);
×
237
         capture_syntax(NULL);
×
238
         tb_strip(tb);
×
239

240
         debugf("evaluating %s returned %s", eval_expr_name(expr), tb_get(tb));
×
241
      }
242

243
      return result;
10,875✔
244
   }
245
   else if (verbose) {
415✔
246
      diag_t *d = diag_new(DIAG_DEBUG, tree_loc(expr));
×
247
      diag_printf(d, "failed to evaluate %s", eval_expr_name(expr));
×
248
      diag_emit(d);
×
249
   }
250

251
   return expr;
252
}
253

254
tree_t eval_try_fold(jit_t *jit, tree_t expr, unit_registry_t *registry,
12,255✔
255
                     lower_unit_t *parent, void *context)
256
{
257
   const bool verbose = opt_get_verbose(OPT_EVAL_VERBOSE, NULL);
12,255✔
258
   jit_set_silent(jit, !verbose);
12,255✔
259

260
   tree_t result = eval_do_fold(jit, expr, parent, registry, context);
12,255✔
261

262
   jit_set_silent(jit, false);
12,251✔
263
   jit_reset_exit_status(jit);
12,251✔
264

265
   return result;
12,251✔
266
}
267

268
tree_t eval_must_fold(jit_t *jit, tree_t expr, unit_registry_t *registry,
125✔
269
                      lower_unit_t *parent, void *context)
270
{
271
   return eval_do_fold(jit, expr, parent, registry, context);
125✔
272
}
273

274
static bool eval_not_possible(tree_t t, const char *why)
10,491✔
275
{
276
   if (opt_get_verbose(OPT_EVAL_VERBOSE, NULL))
10,491✔
277
      warn_at(tree_loc(t), "%s prevents constant folding", why);
×
278

279
   return false;
10,491✔
280
}
281

282
bool eval_possible(tree_t t, unit_registry_t *ur)
89,459✔
283
{
284
   switch (tree_kind(t)) {
99,825✔
285
   case T_FCALL:
47,266✔
286
      {
287
         const tree_flags_t flags = tree_flags(t);
47,266✔
288
         if (!(flags & (TREE_F_LOCALLY_STATIC | TREE_F_GLOBALLY_STATIC)))
47,266✔
289
            return eval_not_possible(t, "non-static expression");
62✔
290

291
         tree_t decl = tree_ref(t);
47,204✔
292
         const subprogram_kind_t kind = tree_subkind(decl);
47,204✔
293
         if (tree_flags(decl) & TREE_F_IMPURE)
47,204✔
294
            return eval_not_possible(t, "call to impure function");
×
295
         else if (kind != S_USER && !is_open_coded_builtin(kind)
47,204✔
296
                  && unit_registry_get(ur, tree_ident2(decl)) == NULL)
4,139✔
297
            return eval_not_possible(t, "not yet lowered predef");
165✔
298
         else if (kind == S_USER && !is_package(tree_container(decl)))
47,039✔
299
            return eval_not_possible(t, "subprogram not in package");
761✔
300

301
         const int nparams = tree_params(t);
46,278✔
302
         for (int i = 0; i < nparams; i++) {
63,158✔
303
            tree_t p = tree_value(tree_param(t, i));
51,976✔
304
            if (!eval_possible(p, ur))
51,976✔
305
               return false;
306
            else if (tree_kind(p) == T_FCALL && type_is_scalar(tree_type(p)))
17,552✔
307
               return false;  // Would have been folded already if possible
308
         }
309

310
         return true;
311
      }
312

313
   case T_LITERAL:
314
   case T_STRING:
315
      return true;
316

317
   case T_TYPE_CONV:
7,033✔
318
   case T_QUALIFIED:
319
      {
320
         tree_t value = tree_value(t);
7,033✔
321
         if (tree_kind(value) == T_FCALL)
7,033✔
322
            return false;   // Would have been folded already if possible
323

324
         return eval_possible(value, ur);
325
      }
326

327
   case T_REF:
20,278✔
328
      {
329
         tree_t decl = tree_ref(t);
20,278✔
330
         switch (tree_kind(decl)) {
20,278✔
331
         case T_UNIT_DECL:
332
         case T_ENUM_LIT:
333
            return true;
334

335
         case T_CONST_DECL:
2,547✔
336
            if (tree_has_value(decl))
2,547✔
337
               return eval_possible(tree_value(decl), ur);
2,525✔
338
            else
339
               return false;
340

341
         default:
9,281✔
342
            return eval_not_possible(t, "reference");
9,281✔
343
         }
344
      }
345

346
   case T_RECORD_REF:
398✔
347
      return eval_possible(tree_value(t), ur);
398✔
348

349
   case T_ARRAY_REF:
1,503✔
350
      {
351
         const int nparams = tree_params(t);
1,503✔
352
         for (int i = 0; i < nparams; i++) {
2,966✔
353
            if (!eval_possible(tree_value(tree_param(t, i)), ur))
1,538✔
354
               return false;
355
         }
356

357
         return eval_possible(tree_value(t), ur);
1,428✔
358
      }
359

360
   case T_AGGREGATE:
1,671✔
361
      {
362
         const int nassocs = tree_assocs(t);
1,671✔
363
         for (int i = 0; i < nassocs; i++) {
10,553✔
364
            if (!eval_possible(tree_value(tree_assoc(t, i)), ur))
8,906✔
365
               return false;
366
         }
367

368
         // Check for missing choices in constrained array aggregates
369
         type_t composite_type = tree_type(t);
1,647✔
370
         if (type_is_array(composite_type)
1,647✔
371
             && !type_is_unconstrained(composite_type)) {
1,547✔
372
            int64_t count = 0, elem_count = 0;
1,544✔
373
            bool known_elem_count = false;
1,544✔
374
            bool has_others = false;
1,544✔
375
            bool has_range = false;
1,544✔
376
            for (int i = 0; i < nassocs; i++) {
10,146✔
377
               tree_t a = tree_assoc(t, i);
8,602✔
378
               const assoc_kind_t akind = tree_subkind(a);
8,602✔
379

380
               switch (akind) {
8,602✔
381

382
               case A_NAMED:
8,509✔
383
               case A_POS:
384
                  known_elem_count = true;
8,509✔
385
                  elem_count = 1;
8,509✔
386
                  break;
8,509✔
387

388
               case A_RANGE:
53✔
389
                  known_elem_count = false;
53✔
390
                  has_range = true;
53✔
391
                  break;
53✔
392

393
               case A_OTHERS:
40✔
394
                  known_elem_count = false;
40✔
395
                  has_others = true;
40✔
396
                  break;
40✔
397

398
               case A_SLICE:
×
399
               case A_CONCAT:
400
                  {
401
                     type_t v_type = tree_type(tree_value(a));
×
402
                     known_elem_count = true;
×
403
                     if (type_is_unconstrained(v_type))
×
404
                        known_elem_count = false;
405
                     else if (!folded_length(range_of(v_type, 0), &elem_count))
×
406
                        known_elem_count = false;
×
407
                     break;
408
                  }
409
               }
410

411
               if (known_elem_count)
8,602✔
412
                  count += elem_count;
8,509✔
413
            }
414

415
            if (has_range)
1,544✔
416
               // Range could overlap, defer to bounds check
417
               return eval_not_possible(t, "range as choice");
54✔
418

419
            if (!has_others) {
1,491✔
420
               int64_t type_count;
1,451✔
421
               if (folded_length(range_of(composite_type, 0), &type_count))
1,451✔
422
                  if (count != type_count)
1,451✔
423
                     return eval_not_possible(t, "missing choice");
1✔
424
            }
425
         }
426

427
         return true;
428
      }
429

430
   case T_ATTR_REF:
3,362✔
431
      {
432
         if (tree_subkind(t) == ATTR_USER)
3,362✔
433
            return eval_not_possible(t, "user defined attribute");
×
434

435
         if (!eval_possible(tree_name(t), ur))
3,362✔
436
            return false;
437

438
         const int nparams = tree_params(t);
×
439
         for (int i = 0; i < nparams; i++) {
×
440
            if (!eval_possible(tree_value(tree_param(t, i)), ur))
×
441
               return false;
442
         }
443

444
         return true;
445
      }
446

447
   default:
168✔
448
      return eval_not_possible(t, tree_kind_str(tree_kind(t)));
168✔
449
   }
450
}
451

452
static void *case_result_cb(jit_scalar_t *args, void *user)
9✔
453
{
454
   jit_scalar_t *result = user;
9✔
455
   result->integer = args[0].integer;
9✔
456
   return result;
9✔
457
}
458

459
tree_t eval_case(jit_t *jit, tree_t stmt, lower_unit_t *parent, void *context)
9✔
460
{
461
   assert(tree_kind(stmt) == T_CASE_GENERATE);
9✔
462

463
   vcode_unit_t thunk = lower_case_generate_thunk(parent, stmt);
9✔
464

465
   jit_scalar_t result = { .integer = -1 };
9✔
466
   if (jit_call_thunk(jit, thunk, context, case_result_cb, &result) == NULL)
9✔
467
      error_at(tree_loc(tree_value(stmt)), "generate expression is not static");
×
468

469
   vcode_unit_unref(thunk);
9✔
470

471
   if (result.integer == -1)
9✔
472
      return NULL;
473
   else
474
      return tree_stmt(stmt, result.integer);
9✔
475
}
476

UNCOV
477
void *eval_instance(jit_t *jit, ident_t name, void *context)
×
478
{
UNCOV
479
   jit_handle_t h = jit_lazy_compile(jit, name);
×
UNCOV
480
   if (h == JIT_HANDLE_INVALID)
×
481
      fatal_trace("failed to compile instance %s", istr(name));
482

UNCOV
483
   jit_scalar_t result;
×
UNCOV
484
   if (!jit_try_call(jit, h, &result, context, context))
×
485
      return NULL;
486

UNCOV
487
   return result.pointer;
×
488
}
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