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

nickg / nvc / 13887457702

16 Mar 2025 09:12PM UTC coverage: 92.285% (-0.04%) from 92.324%
13887457702

push

github

nickg
Tag Docker images on releases. Fixes #1165

68273 of 73981 relevant lines covered (92.28%)

423265.54 hits per line

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

97.37
/src/lower.c
1
//
2
//  Copyright (C) 2014-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 "common.h"
21
#include "cov/cov-api.h"
22
#include "diag.h"
23
#include "driver.h"
24
#include "hash.h"
25
#include "lib.h"
26
#include "lower.h"
27
#include "object.h"
28
#include "option.h"
29
#include "phase.h"
30
#include "psl/psl-phase.h"
31
#include "rt/assert.h"
32
#include "rt/rt.h"
33
#include "type.h"
34
#include "vcode.h"
35

36
#include <assert.h>
37
#include <stdlib.h>
38
#include <stddef.h>
39
#include <inttypes.h>
40
#include <string.h>
41
#include <ctype.h>
42
#include <float.h>
43

44
typedef enum {
45
   EXPR_LVALUE,
46
   EXPR_RVALUE,
47
} expr_ctx_t;
48

49
typedef struct _loop_stack loop_stack_t;
50
typedef struct _lazy_cscope lazy_cscope_t;
51

52
struct _loop_stack {
53
   loop_stack_t  *up;
54
   ident_t        name;
55
   vcode_block_t  test_bb;
56
   vcode_block_t  exit_bb;
57
};
58

59
typedef struct _lazy_cscope {
60
   lazy_cscope_t *parent;
61
   lower_unit_t  *owner;
62
   cover_scope_t *cscope;
63
   tree_t         tree;
64
} lazy_cscope_t;
65

66
typedef enum {
67
   LOWER_NORMAL,
68
   LOWER_THUNK
69
} lower_mode_t;
70

71
#define INSTANCE_BIT  0x80000000
72
#define PARAM_VAR_BIT 0x40000000
73

74
typedef A(vcode_var_t) var_list_t;
75

76
typedef struct _lower_unit {
77
   unit_registry_t *registry;
78
   hash_t          *objects;
79
   lower_unit_t    *parent;
80
   ident_t          name;
81
   tree_t           container;
82
   var_list_t       free_temps;
83
   vcode_unit_t     vunit;
84
   cover_data_t    *cover;
85
   cover_scope_t   *cscope;
86
   bool             finished;
87
   lower_mode_t     mode;
88
   unsigned         deferred;
89
   lazy_cscope_t   *lazy_cscope;
90
} lower_unit_t;
91

92
typedef enum {
93
   PART_ALL,
94
   PART_ELEM,
95
   PART_FIELD,
96
   PART_PUSH_FIELD,
97
   PART_PUSH_ELEM,
98
   PART_POP,
99
   PART_SLICE
100
} part_kind_t;
101

102
typedef struct {
103
   part_kind_t kind;
104
   vcode_reg_t reg;
105
   vcode_reg_t off;
106
   tree_t      target;
107
} target_part_t;
108

109
typedef struct {
110
   tree_t      value;
111
   type_t      type;
112
   vcode_reg_t reg;
113
} concat_param_t;
114

115
typedef void (*lower_field_fn_t)(lower_unit_t *, tree_t, vcode_reg_t,
116
                                 vcode_reg_t, vcode_reg_t, void *);
117
typedef void (*convert_emit_fn)(vcode_reg_t, vcode_reg_t, vcode_reg_t);
118
typedef vcode_reg_t (*resolved_fn_t)(vcode_reg_t, vcode_reg_t);
119

120
typedef A(concat_param_t) concat_list_t;
121

122
typedef struct {
123
   resolved_fn_t  fn;
124
   const char    *suffix;
125
   vcode_var_t    var;
126
} last_time_params_t;
127

128
static vcode_reg_t lower_expr(lower_unit_t *lu, tree_t expr, expr_ctx_t ctx);
129
static void lower_stmt(lower_unit_t *lu, tree_t stmt, loop_stack_t *loops);
130
static void lower_func_body(lower_unit_t *lu, object_t *obj);
131
static void lower_proc_body(lower_unit_t *lu, object_t *obj);
132
static vcode_reg_t lower_record_aggregate(lower_unit_t *lu, tree_t expr,
133
                                          bool nest, bool is_const,
134
                                          vcode_reg_t hint);
135
static vcode_reg_t lower_aggregate(lower_unit_t *lu, tree_t expr,
136
                                   vcode_reg_t hint);
137
static void lower_decls(lower_unit_t *lu, tree_t scope);
138
static void lower_check_array_sizes(lower_unit_t *lu, type_t ltype,
139
                                    type_t rtype, vcode_reg_t lval,
140
                                    vcode_reg_t rval, vcode_reg_t locus);
141
static vcode_type_t lower_alias_type(tree_t alias);
142
static void lower_predef(lower_unit_t *lu, object_t *obj);
143
static ident_t lower_predef_func_name(type_t type, const char *op);
144
static void lower_generics(lower_unit_t *lu, tree_t block, tree_t primary);
145
static vcode_reg_t lower_default_value(lower_unit_t *lu, type_t type,
146
                                       vcode_reg_t hint_reg);
147
static vcode_reg_t lower_array_total_len(lower_unit_t *lu, type_t type,
148
                                         vcode_reg_t reg);
149
static vcode_var_t lower_temp_var(lower_unit_t *lu, const char *prefix,
150
                                  vcode_type_t vtype, vcode_type_t vbounds);
151
static void lower_release_temp(lower_unit_t *lu, vcode_var_t tmp);
152
static vcode_reg_t lower_resolved(lower_unit_t *lu, type_t type,
153
                                  vcode_reg_t reg);
154
static void lower_copy_record(lower_unit_t *lu, type_t type,
155
                              vcode_reg_t dst_ptr, vcode_reg_t src_ptr,
156
                              vcode_reg_t locus);
157
static bool lower_is_signal_ref(tree_t expr);
158
static vcode_reg_t lower_rewrap(vcode_reg_t data, vcode_reg_t bounds);
159
static void lower_predef_field_eq_cb(lower_unit_t *lu, tree_t field,
160
                                     vcode_reg_t r0, vcode_reg_t r1,
161
                                     vcode_reg_t locus, void *context);
162
static void lower_check_indexes(lower_unit_t *lu, type_t from, type_t to,
163
                                vcode_reg_t array, tree_t where);
164
static vcode_reg_t lower_conversion(lower_unit_t *lu, vcode_reg_t value_reg,
165
                                    tree_t where, type_t from, type_t to);
166
static vcode_reg_t lower_get_type_bounds(lower_unit_t *lu, type_t type);
167
static vcode_reg_t lower_attr_prefix(lower_unit_t *lu, tree_t prefix);
168
static void lower_subprogram_ports(lower_unit_t *lu, tree_t body,
169
                                   bool params_as_vars);
170
static vcode_type_t lower_func_result_type(type_t result);
171
static vcode_reg_t lower_context_for_call(lower_unit_t *lu, ident_t unit_name);
172
static void lower_driver_field_cb(lower_unit_t *lu, tree_t field,
173
                                  vcode_reg_t ptr, vcode_reg_t unused,
174
                                  vcode_reg_t locus, void *__ctx);
175

176
typedef vcode_reg_t (*lower_signal_flag_fn_t)(vcode_reg_t, vcode_reg_t);
177
typedef vcode_reg_t (*arith_fn_t)(vcode_reg_t, vcode_reg_t);
178

179
#define PUSH_DEBUG_INFO(t)                              \
180
   __attribute__((cleanup(emit_debug_info), unused))    \
181
   const loc_t _old_loc = *vcode_last_loc();            \
182
   emit_debug_info(tree_loc((t)));                      \
183

184
#define PUSH_COVER_SCOPE(lu, t)                         \
185
   __attribute__((cleanup(_lower_pop_cover_scope)))     \
186
   lazy_cscope_t __lcs = {                              \
187
      .parent = (lu)->lazy_cscope,                      \
188
      .owner = (lu),                                    \
189
      .tree = (t)                                       \
190
   };                                                   \
191
   (lu)->lazy_cscope = &__lcs;
192

193
__attribute__((always_inline))
194
static inline void _lower_pop_cover_scope(lazy_cscope_t *lcs)
92,808✔
195
{
196
   assert(lcs->owner->lazy_cscope == lcs);
92,571✔
197
   lcs->owner->lazy_cscope = lcs->parent;
92,808✔
198
}
199

200
static bool lower_is_const(tree_t t)
71,071✔
201
{
202
   switch (tree_kind(t)) {
71,071✔
203
   case T_AGGREGATE:
11,104✔
204
      {
205
         type_t type = tree_type(t);
11,104✔
206
         if (type_is_record(type) && !type_const_bounds(type))
11,104✔
207
            return false;
208

209
         const int nassocs = tree_assocs(t);
10,886✔
210
         for (int i = 0; i < nassocs; i++) {
70,356✔
211
            tree_t a = tree_assoc(t, i);
60,408✔
212
            switch (tree_subkind(a)) {
60,408✔
213
            case A_NAMED:
2,759✔
214
               if (!lower_is_const(tree_name(a)))
2,759✔
215
                  return false;
216
               break;
217
            case A_RANGE:
336✔
218
            case A_SLICE:
219
               {
220
                  tree_t r = tree_range(a, 0);
336✔
221
                  if (tree_subkind(r) == RANGE_EXPR)
336✔
222
                     return false;
223
                  else if (!lower_is_const(tree_left(r)))
336✔
224
                     return false;
225
                  else if (!lower_is_const(tree_right(r)))
336✔
226
                     return false;
227
               }
228
               break;
229
            }
230

231
            if (!lower_is_const(tree_value(tree_assoc(t, i))))
60,405✔
232
               return false;
233
         }
234

235
         return true;
236
      }
237

238
   case T_REF:
35,126✔
239
      {
240
         tree_t decl = tree_ref(t);
35,126✔
241
         const tree_kind_t decl_kind = tree_kind(decl);
35,126✔
242
         if (decl_kind == T_CONST_DECL && type_is_scalar(tree_type(t)))
35,126✔
243
            return tree_has_value(decl) && lower_is_const(tree_value(decl));
36✔
244
         else
245
            return decl_kind == T_ENUM_LIT || decl_kind == T_FIELD_DECL;
35,108✔
246
      }
247

248
   case T_LITERAL:
249
   case T_STRING:
250
      return true;
251

252
   case T_RANGE:
×
253
      if (tree_subkind(t) == RANGE_EXPR)
×
254
         return lower_is_const(tree_value(t));
×
255
      else
256
         return lower_is_const(tree_left(t)) && lower_is_const(tree_right(t));
×
257

258
   default:
460✔
259
      return false;
460✔
260
   }
261
}
262

263
static bool needs_bounds_var(type_t type)
30,887✔
264
{
265
   // A constrained array subtype with non-constant bounds should have
266
   // its bounds evaluated once and stored in a variable
267
   if (type_is_unconstrained(type))
30,887✔
268
      return false;
269
   else
270
      return !type_const_bounds(type);
27,073✔
271
}
272

273
static int dims_for_type(type_t type)
88,565✔
274
{
275
   int ndims = dimension_of(type);
88,565✔
276

277
   for (type_t e = type_elem(type);
88,565✔
278
        type_is_array(e) && !type_const_bounds(e);
89,854✔
279
        e = type_elem(e))
1,289✔
280
      ndims += dimension_of(e);
1,289✔
281

282
   return ndims;
88,565✔
283
}
284

285
static bool have_uarray_ptr(vcode_reg_t reg)
46,848✔
286
{
287
   vcode_type_t vtype = vcode_reg_type(reg);
46,848✔
288
   if (vtype_kind(vtype) != VCODE_TYPE_POINTER)
46,848✔
289
      return false;
290

291
   return vtype_kind(vtype_pointed(vtype)) == VCODE_TYPE_UARRAY;
19,523✔
292
}
293

294
static bool lower_trivially_copyable(type_t type)
17,069✔
295
{
296
   if (type_is_record(type))
26,301✔
297
      return type_const_bounds(type);
1,974✔
298
   else if (type_is_array(type))
24,327✔
299
      return lower_trivially_copyable(type_elem_recur(type));
9,232✔
300
   else
301
      return true;
302
}
303

304
static vcode_reg_t lower_range_expr(lower_unit_t *lu, tree_t r, int *dim)
6,418✔
305
{
306
   assert(tree_subkind(r) == RANGE_EXPR);
6,418✔
307

308
   tree_t value = tree_value(r);
6,418✔
309
   assert(tree_kind(value) == T_ATTR_REF);
6,418✔
310

311
   if (tree_params(value) > 0)
6,418✔
312
      *dim = assume_int(tree_value(tree_param(value, 0)));
72✔
313

314
   if (tree_subkind(value) == ATTR_REVERSE_RANGE)
6,418✔
315
      *dim *= -1;
165✔
316

317
   tree_t prefix = tree_name(value);
6,418✔
318
   type_t type = tree_type(prefix);
6,418✔
319
   assert(!type_const_bounds(type));
6,418✔
320

321
   vcode_reg_t prefix_reg = lower_attr_prefix(lu, prefix);
6,418✔
322
   if (prefix_reg == VCODE_INVALID_REG)
6,418✔
323
      return lower_get_type_bounds(lu, type);
738✔
324

325
   assert(vcode_reg_kind(prefix_reg) == VCODE_TYPE_UARRAY);
5,680✔
326
   return prefix_reg;
327
}
328

329
static vcode_reg_t lower_range_left(lower_unit_t *lu, tree_t r)
64,101✔
330
{
331
   assert(tree_kind(r) == T_RANGE);
64,101✔
332

333
   type_t type = tree_type(r);
64,101✔
334
   vcode_type_t vtype = lower_type(type);
64,101✔
335
   vcode_type_t vbounds = lower_bounds(type);
64,101✔
336

337
   vcode_reg_t left_reg;
64,101✔
338
   if (tree_subkind(r) == RANGE_EXPR) {
64,101✔
339
      int dim = 1;
2,087✔
340
      vcode_reg_t array_reg = lower_range_expr(lu, r, &dim);
2,087✔
341

342
      if (dim < 0)
2,087✔
343
         left_reg = emit_uarray_right(array_reg, -dim - 1);
55✔
344
      else
345
         left_reg = emit_uarray_left(array_reg, dim - 1);
2,032✔
346
   }
347
   else
348
      left_reg = lower_rvalue(lu, tree_left(r));
62,014✔
349

350
   return emit_cast(vtype, vbounds, left_reg);
64,101✔
351
}
352

353
static vcode_reg_t lower_range_right(lower_unit_t *lu, tree_t r)
48,573✔
354
{
355
   assert(tree_kind(r) == T_RANGE);
48,573✔
356

357
   type_t type = tree_type(r);
48,573✔
358
   vcode_type_t vtype = lower_type(type);
48,573✔
359
   vcode_type_t vbounds = lower_bounds(type);
48,573✔
360

361
   vcode_reg_t right_reg;
48,573✔
362
   if (tree_subkind(r) == RANGE_EXPR) {
48,573✔
363
      int dim = 1;
2,167✔
364
      vcode_reg_t array_reg = lower_range_expr(lu, r, &dim);
2,167✔
365

366
      if (dim < 0)
2,167✔
367
         right_reg = emit_uarray_left(array_reg, -dim - 1);
55✔
368
      else
369
         right_reg = emit_uarray_right(array_reg, dim - 1);
2,112✔
370

371
      type_t type = tree_type(r);
2,167✔
372
      vcode_type_t vtype = lower_type(type);
2,167✔
373
      vcode_type_t vbounds = lower_bounds(type);
2,167✔
374
      return emit_cast(vtype, vbounds, right_reg);
2,167✔
375
   }
376
   else
377
      right_reg = lower_rvalue(lu, tree_right(r));
46,406✔
378

379
   return emit_cast(vtype, vbounds, right_reg);
46,406✔
380
}
381

382
static vcode_reg_t lower_range_dir(lower_unit_t *lu, tree_t r)
49,415✔
383
{
384
   const range_kind_t rkind = tree_subkind(r);
49,415✔
385

386
   switch (rkind) {
49,415✔
387
   case RANGE_TO:
47,251✔
388
   case RANGE_DOWNTO:
389
      return emit_const(vtype_bool(), rkind);
47,251✔
390

391
   case RANGE_EXPR:
2,164✔
392
      {
393
         int dim = 1;
2,164✔
394
         vcode_reg_t array_reg = lower_range_expr(lu, r, &dim);
2,164✔
395

396
         if (dim < 0)
2,164✔
397
            return emit_not(emit_uarray_dir(array_reg, -dim - 1));
55✔
398
         else
399
            return emit_uarray_dir(array_reg, dim - 1);
2,109✔
400
      }
401

402
   case RANGE_ERROR:
403
      break;
404
   }
405

406
   return VCODE_INVALID_REG;
407
}
408

409
static vcode_reg_t lower_array_data(vcode_reg_t reg)
131,881✔
410
{
411
   vcode_type_t type = vcode_reg_type(reg);
131,881✔
412
   switch (vtype_kind(type)) {
131,881✔
413
   case VCODE_TYPE_UARRAY:
36,591✔
414
      return emit_unwrap(reg);
36,591✔
415

416
   case VCODE_TYPE_POINTER:
48,256✔
417
      if (vtype_kind(vtype_pointed(type)) == VCODE_TYPE_UARRAY)
48,256✔
418
         return emit_unwrap(emit_load_indirect(reg));
327✔
419
      else
420
         return reg;
421

422
   case VCODE_TYPE_SIGNAL:
423
      return reg;
424

425
   default:
×
426
      vcode_dump();
×
427
      fatal_trace("invalid type in lower_array_data r%d", reg);
428
   }
429
}
430

431
static bool have_array_metadata(type_t type, vcode_reg_t reg)
156,320✔
432
{
433
   if (reg == VCODE_INVALID_REG)
156,320✔
434
      return false;
435
   else if (type_const_bounds(type))
153,791✔
436
      return false;
437
   else if (type_is_unconstrained(type)) {
77,518✔
438
      assert(reg != VCODE_INVALID_REG);
33,262✔
439
      assert(vcode_reg_kind(reg) == VCODE_TYPE_UARRAY);
33,262✔
440
      return true;
441
   }
442
   else
443
      return vcode_reg_kind(reg) == VCODE_TYPE_UARRAY;
44,256✔
444
}
445

446
static vcode_reg_t lower_array_left(lower_unit_t *lu, type_t type, int dim,
40,896✔
447
                                    vcode_reg_t reg)
448
{
449
   if (have_array_metadata(type, reg)) {
40,896✔
450
      type_t index_type = index_type_of(type, dim);
27,525✔
451
      return emit_cast(lower_type(index_type), lower_bounds(index_type),
27,525✔
452
                       emit_uarray_left(reg, dim));
453
   }
454
   else
455
      return lower_range_left(lu, range_of(type, dim));
13,371✔
456
}
457

458
static vcode_reg_t lower_array_right(lower_unit_t *lu, type_t type, int dim,
31,736✔
459
                                     vcode_reg_t reg)
460
{
461
   if (have_array_metadata(type, reg)) {
31,736✔
462
      type_t index_type = index_type_of(type, dim);
18,365✔
463
      return emit_cast(lower_type(index_type), lower_bounds(index_type),
18,365✔
464
                       emit_uarray_right(reg, dim));
465
   }
466
   else
467
      return lower_range_right(lu, range_of(type, dim));
13,371✔
468
}
469

470
static vcode_reg_t lower_array_dir(lower_unit_t *lu, type_t type, int dim,
31,638✔
471
                                   vcode_reg_t reg)
472
{
473
   if (have_array_metadata(type, reg))
31,638✔
474
      return emit_uarray_dir(reg, dim);
18,267✔
475
   else
476
      return lower_range_dir(lu, range_of(type, dim));
13,371✔
477
}
478

479
static vcode_reg_t lower_array_len(lower_unit_t *lu, type_t type, int dim,
108,163✔
480
                                   vcode_reg_t reg)
481
{
482
   assert(type_is_array(type));
108,163✔
483

484
   if (type_const_bounds(type)) {
108,163✔
485
      tree_t r = range_of(type, dim);
59,958✔
486

487
      int64_t low, high;
59,958✔
488
      if (!folded_bounds(r, &low, &high))
59,958✔
489
         fatal_trace("type %s bounds not constant", type_pp(type));
490

491
      return emit_const(vtype_offset(), MAX(high - low + 1, 0));
59,958✔
492
   }
493
   else if (reg != VCODE_INVALID_REG
48,205✔
494
            // TODO: fix lower_default_value to not pass garbage
495
            && vcode_reg_kind(reg) == VCODE_TYPE_UARRAY)
47,600✔
496
      return emit_uarray_len(reg, dim);
47,185✔
497
   else {
498
      vcode_reg_t bounds_reg = lower_get_type_bounds(lu, type);
1,020✔
499
      return emit_uarray_len(bounds_reg, dim);
1,020✔
500
   }
501
}
502

503
static vcode_reg_t lower_array_stride(lower_unit_t *lu, type_t type,
22,777✔
504
                                      vcode_reg_t reg)
505
{
506
   vcode_type_t voffset = vtype_offset();
22,777✔
507
   vcode_reg_t stride = emit_const(voffset, 1);
22,777✔
508

509
   type_t elem = type_elem(type);
22,777✔
510
   if (!type_is_array(elem))
22,777✔
511
      return stride;
512

513
   int udims = 0, dim = 0;
3,433✔
514
   if (have_array_metadata(type, reg)) {
3,433✔
515
      udims = dims_for_type(type);
603✔
516
      dim = dimension_of(type);   // Skip to element dimensions
603✔
517

518
      assert(vtype_dims(vcode_reg_type(reg)) == udims);
603✔
519
   }
520

521
   do {
3,681✔
522
      const int edims = dimension_of(elem);
3,681✔
523
      for (int i = 0; i < edims; i++, dim++) {
7,575✔
524
         vcode_reg_t len_reg;
3,894✔
525
         if (dim < udims)
3,894✔
526
            len_reg = emit_uarray_len(reg, dim);
503✔
527
         else {
528
            tree_t r = range_of(elem, i);
3,391✔
529

530
            int64_t low, high;
3,391✔
531
            if (!folded_bounds(r, &low, &high)) {
3,391✔
532
               // TODO: this should be a fatal error but lower_type_bounds
533
               //       does not work for records
534

535
               emit_comment("Workaround for missing record type bounds");
3✔
536

537
               vcode_reg_t left_reg  = lower_range_left(lu, r);
3✔
538
               vcode_reg_t right_reg = lower_range_right(lu, r);
3✔
539
               vcode_reg_t dir_reg   = lower_range_dir(lu, r);
3✔
540

541
               len_reg = emit_range_length(left_reg, right_reg, dir_reg);
3✔
542
            }
543
            else
544
               len_reg = emit_const(voffset, MAX(high - low + 1, 0));
3,388✔
545
         }
546

547
         stride = emit_mul(stride, len_reg);
3,894✔
548
      }
549
   } while (type_is_array((elem = type_elem(elem))));
3,681✔
550

551
   emit_comment("Array of array stride is r%d", stride);
3,433✔
552
   return stride;
3,433✔
553
}
554

555
static vcode_reg_t lower_array_total_len(lower_unit_t *lu, type_t type,
40,557✔
556
                                         vcode_reg_t reg)
557
{
558
   const int ndims = dimension_of(type);
40,557✔
559

560
   vcode_reg_t total = VCODE_INVALID_REG;
40,557✔
561
   for (int i = 0; i < ndims; i++) {
82,326✔
562
      vcode_reg_t this = lower_array_len(lu, type, i, reg);
41,769✔
563
      if (total == VCODE_INVALID_REG)
41,769✔
564
         total = this;
565
      else
566
         total = emit_mul(this, total);
1,212✔
567
   }
568

569
   type_t elem = type_elem(type);
40,557✔
570
   if (type_is_array(elem))
40,557✔
571
      return emit_mul(total, lower_array_stride(lu, type, reg));
1,616✔
572
   else
573
      return total;
574
}
575

576
static vcode_reg_t lower_type_width(lower_unit_t *lu, type_t type,
18,462✔
577
                                    vcode_reg_t reg)
578
{
579
   if (type_is_array(type))
18,462✔
580
      return lower_array_total_len(lu, type, reg);
3,493✔
581
   else {
582
      assert(type_is_scalar(type));
14,969✔
583
      return emit_const(vtype_offset(), 1);
14,969✔
584
   }
585
}
586

587
static int lower_array_const_size(type_t type)
23,886✔
588
{
589
   const int ndims = dimension_of(type);
23,886✔
590

591
   int size = 1;
23,886✔
592
   for (int i = 0; i < ndims; i++) {
50,340✔
593
      tree_t r = range_of(type, i);
26,454✔
594
      int64_t low, high;
26,454✔
595
      range_bounds(r, &low, &high);
26,454✔
596
      size *= MAX(high - low + 1, 0);
26,454✔
597
   }
598

599
   type_t elem = type_elem(type);
23,886✔
600
   return type_is_array(elem) ? size * lower_array_const_size(elem) : size;
23,886✔
601
}
602

603
static vcode_type_t lower_array_type(type_t type)
48,059✔
604
{
605
   type_t elem = type_elem_recur(type);
48,059✔
606

607
   vcode_type_t elem_type   = lower_type(elem);
48,059✔
608
   vcode_type_t elem_bounds = lower_bounds(elem);
48,059✔
609

610
   if (type_const_bounds(type))
48,059✔
611
      return vtype_carray(lower_array_const_size(type), elem_type, elem_bounds);
12,463✔
612
   else
613
      return vtype_uarray(dims_for_type(type), elem_type, elem_bounds);
35,596✔
614
}
615

616
vcode_type_t lower_type(type_t type)
893,812✔
617
{
618
   switch (type_kind(type)) {
1,157,780✔
619
   case T_SUBTYPE:
286,645✔
620
      if (type_is_array(type))
286,645✔
621
         return lower_array_type(type);
22,677✔
622
      else
623
         return lower_type(type_base(type));
263,968✔
624

625
   case T_ARRAY:
25,382✔
626
      return lower_array_type(type);
25,382✔
627

628
   case T_PHYSICAL:
449,211✔
629
   case T_INTEGER:
630
      {
631
         tree_t r = type_dim(type, 0);
449,211✔
632
         int64_t low, high;
449,211✔
633
         const bool folded = folded_bounds(r, &low, &high);
449,211✔
634
         if (folded)
449,211✔
635
            return vtype_int(low, high);
449,211✔
636
         else
637
            return vtype_int(INT64_MIN, INT64_MAX);
×
638
      }
639

640
   case T_ENUM:
312,789✔
641
      return vtype_int(0, type_enum_literals(type) - 1);
312,789✔
642

643
   case T_RECORD:
23,753✔
644
      {
645
         ident_t name = type_ident(type);
23,753✔
646
         vcode_type_t record = vtype_find_named_record(name);
23,753✔
647
         if (record == VCODE_INVALID_TYPE) {
23,753✔
648
            vtype_named_record(name, NULL, 0);  // Forward-declare the name
4,323✔
649

650
            const int nfields = type_fields(type);
4,323✔
651
            vcode_type_t fields[nfields];
4,323✔
652
            for (int i = 0; i < nfields; i++)
17,904✔
653
               fields[i] = lower_type(tree_type(type_field(type, i)));
13,581✔
654

655
            record = vtype_named_record(name, fields, nfields);
4,323✔
656
         }
657

658
         return record;
659
      }
660

661
   case T_PROTECTED:
1,472✔
662
      return vtype_context(type_ident(type));
1,472✔
663

664
   case T_FILE:
618✔
665
      return vtype_file(lower_type(type_designated(type)));
618✔
666

667
   case T_ACCESS:
3,945✔
668
      {
669
         type_t access = type_designated(type);
3,945✔
670
         if (type_is_array(access) && type_const_bounds(access))
3,945✔
671
            return vtype_access(lower_type(type_elem_recur(access)));
175✔
672
         else
673
            return vtype_access(lower_type(access));
3,770✔
674
      }
675

676
   case T_REAL:
52,874✔
677
      {
678
         tree_t r = type_dim(type, 0);
52,874✔
679
         double low, high;
52,874✔
680
         const bool folded = folded_bounds_real(r, &low, &high);
52,874✔
681
         if (folded)
52,874✔
682
            return vtype_real(low, high);
52,874✔
683
         else
684
            return vtype_real(-DBL_MAX, DBL_MAX);
×
685
      }
686

687
   case T_INCOMPLETE:
1,091✔
688
      return vtype_opaque();
1,091✔
689

690
   default:
×
691
      fatal_trace("cannot lower type kind %s", type_kind_str(type_kind(type)));
692
   }
693
}
694

695
vcode_type_t lower_bounds(type_t type)
326,270✔
696
{
697
   if (type_kind(type) == T_SUBTYPE) {
326,270✔
698
      if (type_is_integer(type) || type_is_enum(type)) {
148,193✔
699
         tree_t r = range_of(type, 0);
130,199✔
700
         int64_t low, high;
130,199✔
701
         if (folded_bounds(r, &low, &high))
130,199✔
702
            return vtype_int(low, high);
128,918✔
703
      }
704
      else if (type_is_real(type)) {
17,994✔
705
         tree_t r = range_of(type, 0);
187✔
706
         double low, high;
187✔
707
         if (folded_bounds_real(r, &low, &high))
187✔
708
            return vtype_real(low, high);
186✔
709
      }
710
   }
711

712
   if (type_is_array(type))
197,166✔
713
      return lower_bounds(type_elem(type));
33,517✔
714

715
   return lower_type(type);
163,649✔
716
}
717

718
static vcode_type_t lower_signal_type(type_t type)
27,086✔
719
{
720
   if (type_is_array(type)) {
27,086✔
721
      if (type_is_homogeneous(type)) {
8,801✔
722
         vcode_type_t base = vtype_signal(lower_type(type_elem_recur(type)));
7,709✔
723
         if (type_const_bounds(type))
7,709✔
724
            return base;
725
         else
726
            return vtype_uarray(dims_for_type(type), base, base);
2,078✔
727
      }
728
      else {
729
         vcode_type_t base = lower_signal_type(type_elem_recur(type));
1,092✔
730
         if (type_const_bounds(type))
1,092✔
731
            return vtype_carray(lower_array_const_size(type), base, base);
365✔
732
         else
733
            return vtype_uarray(dims_for_type(type), base, base);
727✔
734
      }
735
   }
736
   else if (type_is_record(type)) {
18,285✔
737
      type_t base = type_base_recur(type);
3,138✔
738
      ident_t name = ident_prefix(type_ident(base), ident_new("$"), '\0');
3,138✔
739
      vcode_type_t record = vtype_find_named_record(name);
3,138✔
740
      if (record == VCODE_INVALID_TYPE) {
3,138✔
741
         vtype_named_record(name, NULL, 0);  // Forward-declare the name
1,573✔
742

743
         const int nfields = type_fields(base);
1,573✔
744
         vcode_type_t fields[nfields];
1,573✔
745
         for (int i = 0; i < nfields; i++)
7,534✔
746
            fields[i] = lower_signal_type(tree_type(type_field(base, i)));
5,961✔
747

748
         record = vtype_named_record(name, fields, nfields);
1,573✔
749
      }
750

751
      return record;
3,138✔
752
   }
753
   else
754
      return vtype_signal(lower_type(type));
15,147✔
755
}
756

757
static vcode_reg_t lower_debug_locus(tree_t t)
119,810✔
758
{
759
   return emit_debug_locus(tree_to_object(t));
119,810✔
760
}
761

762
static vcode_reg_t lower_wrap_with_new_bounds(lower_unit_t *lu,
24,944✔
763
                                              type_t from_type,
764
                                              type_t to_type,
765
                                              vcode_reg_t array,
766
                                              vcode_reg_t data)
767
{
24,944✔
768
   assert(type_is_array(from_type));
24,944✔
769
   assert(type_is_array(to_type));
24,944✔
770

771
   const int ncons = dims_for_type(to_type);
24,944✔
772
   vcode_dim_t dims[ncons];
24,944✔
773
   int dptr = 0;
24,944✔
774

775
   int udims = 0;
24,944✔
776
   if (have_array_metadata(from_type, array)) {
24,944✔
777
      udims = dims_for_type(from_type);
2,532✔
778
      assert(vtype_dims(vcode_reg_type(array)) == udims);
2,532✔
779
   }
780

781
   for (; dptr < ncons; from_type = type_elem(from_type),
75,296✔
782
           to_type = type_elem(to_type)) {
25,176✔
783

784
      const int ndims = dimension_of(from_type);
25,176✔
785
      for (int i = 0; i < ndims; i++, dptr++) {
50,446✔
786
         if (dptr < udims) {
25,270✔
787
            dims[dptr].left  = emit_uarray_left(array, dptr);
2,538✔
788
            dims[dptr].right = emit_uarray_right(array, dptr);
2,538✔
789
            dims[dptr].dir   = emit_uarray_dir(array, dptr);
2,538✔
790
         }
791
         else {
792
            type_t src_type =
45,464✔
793
               type_is_unconstrained(to_type) ? from_type : to_type;
22,732✔
794
            tree_t r = range_of(src_type, i);
22,732✔
795
            dims[dptr].left  = lower_range_left(lu, r);
22,732✔
796
            dims[dptr].right = lower_range_right(lu, r);
22,732✔
797
            dims[dptr].dir   = lower_range_dir(lu, r);
22,732✔
798
         }
799
      }
800
   }
801

802
   assert(dptr == ncons);
24,944✔
803

804
   return emit_wrap(lower_array_data(data), dims, ncons);
24,944✔
805
}
806

807
static vcode_reg_t lower_wrap(lower_unit_t *lu, type_t type, vcode_reg_t data)
3,071✔
808
{
809
   return lower_wrap_with_new_bounds(lu, type, type, data, data);
3,071✔
810
}
811

812
static vcode_reg_t lower_wrap_element(lower_unit_t *lu, type_t type,
339✔
813
                                      vcode_reg_t array, vcode_reg_t data)
814
{
339✔
815
   assert(type_is_array(type));
339✔
816
   assert(!type_const_bounds(type_elem(type)));
339✔
817
   assert(array != VCODE_INVALID_REG);
339✔
818

819
   const int ndims = dimension_of(type);
339✔
820
   const int ncons = vtype_dims(vcode_reg_type(array)) - ndims;
339✔
821
   assert(ncons > 0);
339✔
822

823
   vcode_dim_t dims[ncons];
339✔
824
   for (int i = 0; i < ncons; i++) {
693✔
825
      dims[i].left  = emit_uarray_left(array, ndims + i);
354✔
826
      dims[i].right = emit_uarray_right(array, ndims + i);
354✔
827
      dims[i].dir   = emit_uarray_dir(array, ndims + i);
354✔
828
   }
829

830
   return emit_wrap(lower_array_data(data), dims, ncons);
339✔
831
}
832

833
static vcode_reg_t lower_rewrap(vcode_reg_t data, vcode_reg_t bounds)
6,145✔
834
{
6,145✔
835
   const int ndims = vtype_dims(vcode_reg_type(bounds));
6,145✔
836
   vcode_dim_t dims[ndims];
6,145✔
837

838
   for (int i = 0; i < ndims; i++) {
12,425✔
839
      dims[i].left  = emit_uarray_left(bounds, i);
6,280✔
840
      dims[i].right = emit_uarray_right(bounds, i);
6,280✔
841
      dims[i].dir   = emit_uarray_dir(bounds, i);
6,280✔
842
   }
843

844
   return emit_wrap(data, dims, ndims);
6,145✔
845
}
846

847
static void lower_for_each_field_2(lower_unit_t *lu, type_t type1, type_t type2,
4,592✔
848
                                   vcode_reg_t rec1_ptr, vcode_reg_t rec2_ptr,
849
                                   vcode_reg_t locus, lower_field_fn_t fn,
850
                                   void *context)
851
{
852
   assert(type2 == NULL || type_eq(type1, type2));
4,592✔
853

854
   if (type_is_array(type1)) {
4,592✔
855
      assert(!type_is_homogeneous(type1));   // Otherwise why call this
853✔
856

857
      if (have_uarray_ptr(rec1_ptr))
853✔
858
         rec1_ptr = emit_load_indirect(rec1_ptr);
97✔
859

860
      if (rec2_ptr != VCODE_INVALID_REG && have_uarray_ptr(rec2_ptr))
853✔
861
         rec2_ptr = emit_load_indirect(rec2_ptr);
14✔
862

863
      if (locus != VCODE_INVALID_REG && rec2_ptr != VCODE_INVALID_REG)
853✔
864
         lower_check_array_sizes(lu, type1, type2, rec1_ptr, rec2_ptr, locus);
289✔
865

866
      vcode_type_t voffset = vtype_offset();
853✔
867
      vcode_var_t i_var = lower_temp_var(lu, "i", voffset, voffset);
853✔
868
      emit_store(emit_const(voffset, 0), i_var);
853✔
869

870
      vcode_reg_t count1_reg = lower_array_total_len(lu, type1, rec1_ptr);
853✔
871
      vcode_reg_t data1_reg  = lower_array_data(rec1_ptr);
853✔
872

873
      vcode_block_t body_bb = emit_block();
853✔
874
      vcode_block_t exit_bb = emit_block();
853✔
875

876
      vcode_block_t null_reg = emit_cmp(VCODE_CMP_EQ, count1_reg,
853✔
877
                                        emit_const(voffset, 0));
878
      emit_cond(null_reg, exit_bb, body_bb);
853✔
879

880
      vcode_select_block(body_bb);
853✔
881

882
      vcode_reg_t i_reg = emit_load(i_var);
853✔
883
      vcode_reg_t ptr1_reg = emit_array_ref(data1_reg, i_reg);
853✔
884

885
      vcode_reg_t ptr2_reg = VCODE_INVALID_REG;
853✔
886
      if (rec2_ptr != VCODE_INVALID_REG) {
853✔
887
         vcode_reg_t data2_reg = lower_array_data(rec2_ptr);
398✔
888
         ptr2_reg = emit_array_ref(data2_reg, i_reg);
398✔
889
      }
890

891
      type_t elem1 = type_elem_recur(type1);
853✔
892
      type_t elem2 = type2 == NULL ? NULL : type_elem_recur(type2);
853✔
893
      lower_for_each_field_2(lu, elem1, elem2, ptr1_reg, ptr2_reg, locus,
853✔
894
                             fn, context);
895

896
      vcode_reg_t next_reg = emit_add(i_reg, emit_const(voffset, 1));
853✔
897
      emit_store(next_reg, i_var);
853✔
898

899
      vcode_reg_t done_reg = emit_cmp(VCODE_CMP_EQ, next_reg, count1_reg);
853✔
900
      emit_cond(done_reg, exit_bb, body_bb);
853✔
901

902
      vcode_select_block(exit_bb);
853✔
903
      lower_release_temp(lu, i_var);
853✔
904
   }
905
   else {
906
      assert(vcode_reg_kind(rec1_ptr) == VCODE_TYPE_POINTER);
3,739✔
907

908
      const int nfields = type_fields(type1);
3,739✔
909
      for (int i = 0; i < nfields; i++) {
16,117✔
910
         tree_t f = type_field(type1, i);
12,378✔
911
         vcode_reg_t f1_reg = emit_record_ref(rec1_ptr, i);
12,378✔
912
         vcode_reg_t f2_reg = VCODE_INVALID_REG;
12,378✔
913
         if (rec2_ptr != VCODE_INVALID_REG)
12,378✔
914
            f2_reg = emit_record_ref(rec2_ptr, i);
7,619✔
915
         (*fn)(lu, f, f1_reg, f2_reg, locus, context);
12,378✔
916
      }
917
   }
918
}
4,592✔
919

920
static void lower_for_each_field(lower_unit_t *lu, type_t type,
1,643✔
921
                                 vcode_reg_t rec1_ptr, vcode_reg_t locus,
922
                                 lower_field_fn_t fn, void *context)
923
{
924
   lower_for_each_field_2(lu, type, type, rec1_ptr, VCODE_INVALID_REG,
1,643✔
925
                          locus, fn, context);
926
}
1,643✔
927

928
static void lower_get_scalar_type_bounds(lower_unit_t *lu, type_t type,
19,796✔
929
                                         vcode_reg_t *left_reg,
930
                                         vcode_reg_t *right_reg,
931
                                         vcode_reg_t *dir_reg)
932
{
933
   assert(type_is_scalar(type));
19,796✔
934

935
   tree_t r = range_of(type, 0);
19,796✔
936
   const range_kind_t rkind = tree_subkind(r);
19,796✔
937

938
   if (rkind != RANGE_EXPR) {
19,796✔
939
      tree_t left = tree_left(r), right = tree_right(r);
19,658✔
940

941
      int64_t ileft, iright;
19,658✔
942
      double rleft, rright;
19,658✔
943
      if (folded_int(left, &ileft) && folded_int(right, &iright)) {
19,658✔
944
         vcode_type_t vtype = lower_type(type);
12,973✔
945
         *left_reg  = emit_const(vtype, ileft);
12,973✔
946
         *right_reg = emit_const(vtype, iright);
12,973✔
947
         *dir_reg   = emit_const(vtype_bool(), rkind);
12,973✔
948
         return;
19,011✔
949
      }
950
      else if (folded_real(left, &rleft) && folded_real(right, &rright)) {
6,685✔
951
         vcode_type_t vtype = lower_type(type);
6,038✔
952
         *left_reg  = emit_const_real(vtype, rleft);
6,038✔
953
         *right_reg = emit_const_real(vtype, rright);
6,038✔
954
         *dir_reg   = emit_const(vtype_bool(), rkind);
6,038✔
955
         return;
6,038✔
956
      }
957
   }
958

959
   if (type_has_ident(type) && needs_bounds_var(type)) {
1,321✔
960
      vcode_type_t vtype = lower_type(type);
536✔
961
      vcode_type_t vbounds = lower_bounds(type);
536✔
962

963
      vcode_reg_t wrap_reg;
536✔
964
      int hops = 0;
536✔
965
      vcode_var_t var = lower_search_vcode_obj(type, lu, &hops);
536✔
966
      if (var == VCODE_INVALID_VAR) {
536✔
967
         // Type or subtype declared in package
968
         ident_t id = type_ident(type);
257✔
969
         vcode_reg_t context = emit_link_package(ident_runtil(id, '.'));
257✔
970
         vcode_type_t vuarray = vtype_uarray(1, vtype, vbounds);
257✔
971
         vcode_reg_t ptr_reg = emit_link_var(context, id, vuarray);
257✔
972
         wrap_reg = emit_load_indirect(ptr_reg);
257✔
973
      }
974
      else if (hops == 0)
279✔
975
         wrap_reg = emit_load(var);
279✔
976
      else {
977
         vcode_reg_t ptr_reg = emit_var_upref(hops, var);
×
978
         wrap_reg = emit_load_indirect(ptr_reg);
×
979
      }
980

981
      *left_reg  = emit_cast(vtype, vbounds, emit_uarray_left(wrap_reg, 0));
536✔
982
      *right_reg = emit_cast(vtype, vbounds, emit_uarray_right(wrap_reg, 0));
536✔
983
      *dir_reg   = emit_uarray_dir(wrap_reg, 0);
536✔
984
   }
985
   else {
986
      *left_reg  = lower_range_left(lu, r);
249✔
987
      *right_reg = lower_range_right(lu, r);
249✔
988
      *dir_reg   = lower_range_dir(lu, r);
249✔
989
   }
990
}
991

992
static vcode_reg_t lower_scalar_type_left(lower_unit_t *lu, type_t type)
21,395✔
993
{
994
   assert(type_is_scalar(type));
21,395✔
995

996
   tree_t r = range_of(type, 0);
21,395✔
997
   const range_kind_t rkind = tree_subkind(r);
21,395✔
998

999
   if (rkind != RANGE_EXPR) {
21,395✔
1000
      tree_t left = tree_left(r);
21,392✔
1001

1002
      // Handle common case of constant bounds without generating the
1003
      // right bound or direction
1004
      double rleft;
21,392✔
1005
      int64_t ileft;
21,392✔
1006
      if (folded_int(left, &ileft))
21,392✔
1007
         return emit_const(lower_type(type), ileft);
21,380✔
1008
      else if (folded_real(left, &rleft))
1,386✔
1009
         return emit_const_real(lower_type(type), rleft);
1,374✔
1010
   }
1011

1012
   vcode_reg_t left_reg, right_reg, dir_reg;
15✔
1013
   lower_get_scalar_type_bounds(lu, type, &left_reg, &right_reg, &dir_reg);
15✔
1014

1015
   return left_reg;
15✔
1016
}
1017

1018
static void lower_check_scalar_bounds(lower_unit_t *lu, vcode_reg_t value,
67,924✔
1019
                                      type_t type, tree_t where, tree_t hint)
1020
{
1021
   tree_t r = range_of(type, 0);
67,924✔
1022

1023
   int64_t low, high;
67,924✔
1024
   if (folded_bounds(r, &low, &high) && low <= high) {
67,924✔
1025
      vcode_type_t vbounds = vcode_reg_bounds(value);
61,614✔
1026
      if (vtype_low(vbounds) >= low && vtype_high(vbounds) <= high)
61,614✔
1027
         return;   // Avoid generating debug locus
59,117✔
1028
   }
1029

1030
   vcode_reg_t left_reg, right_reg, dir_reg;
8,807✔
1031
   lower_get_scalar_type_bounds(lu, type, &left_reg, &right_reg, &dir_reg);
8,807✔
1032

1033
   vcode_reg_t locus = lower_debug_locus(where);
8,807✔
1034

1035
   vcode_reg_t hint_locus = locus;
8,807✔
1036
   if (hint != NULL && hint != where)
8,807✔
1037
      hint_locus = lower_debug_locus(hint);
5,661✔
1038

1039
   emit_range_check(value, left_reg, right_reg, dir_reg, locus, hint_locus);
8,807✔
1040
}
1041

1042
static bool lower_have_signal(vcode_reg_t reg)
142,464✔
1043
{
1044
   return vtype_is_signal(vcode_reg_type(reg));
142,464✔
1045
}
1046

1047
static vcode_reg_t lower_coerce_arrays(lower_unit_t *lu, type_t from, type_t to,
45,542✔
1048
                                       vcode_reg_t reg)
1049
{
1050
   vcode_type_t reg_vtype = vcode_reg_type(reg);
45,542✔
1051
   const bool have_uarray = vtype_kind(reg_vtype) == VCODE_TYPE_UARRAY;
45,542✔
1052
   const bool need_uarray = !type_const_bounds(to);
45,542✔
1053

1054
   if (have_uarray && need_uarray && vtype_dims(reg_vtype) == dims_for_type(to))
45,542✔
1055
      return reg;
1056
   else if (need_uarray) {
26,952✔
1057
      // Need to wrap array with metadata
1058
      return lower_wrap_with_new_bounds(lu, from, to, reg, reg);
20,957✔
1059
   }
1060
   else if (have_uarray && !need_uarray) {
5,995✔
1061
      // Need to unwrap array to get raw pointer
1062
      return emit_unwrap(reg);
107✔
1063
   }
1064
   else
1065
      return reg;
1066
}
1067

1068
static void lower_resolved_field_cb(lower_unit_t *lu, tree_t field,
1,489✔
1069
                                    vcode_reg_t field_ptr, vcode_reg_t dst_ptr,
1070
                                    vcode_reg_t locus, void *ctx)
1071
{
1072
   type_t ftype = tree_type(field);
1,489✔
1073
   if (!type_is_homogeneous(ftype)) {
1,489✔
1074
      if (have_uarray_ptr(dst_ptr)) {
78✔
1075
         // Need to allocate memory for the array
1076
         assert(have_uarray_ptr(field_ptr));
3✔
1077

1078
         vcode_reg_t field_reg = emit_load_indirect(field_ptr);
3✔
1079
         vcode_reg_t count_reg = lower_array_total_len(lu, ftype, field_reg);
3✔
1080

1081
         type_t elem = type_elem_recur(ftype);
3✔
1082
         vcode_type_t vtype = lower_type(elem);
3✔
1083
         vcode_type_t vbounds = lower_bounds(elem);
3✔
1084

1085
         vcode_reg_t mem_reg = emit_alloc(vtype, vbounds, count_reg);
3✔
1086

1087
         vcode_reg_t wrap_reg =
3✔
1088
            lower_wrap_with_new_bounds(lu, ftype, ftype, field_reg, mem_reg);
3✔
1089
         emit_store_indirect(wrap_reg, dst_ptr);
3✔
1090
      }
1091

1092
      lower_for_each_field_2(lu, ftype, ftype, field_ptr, dst_ptr, locus,
78✔
1093
                             lower_resolved_field_cb, ctx);
1094
   }
1095
   else {
1096
      resolved_fn_t fn = ctx;
1,411✔
1097
      vcode_reg_t sig_reg = emit_load_indirect(field_ptr);
1,411✔
1098

1099
      if (type_is_array(ftype)) {
1,411✔
1100
         vcode_reg_t count_reg = lower_array_total_len(lu, ftype, sig_reg);
628✔
1101
         vcode_reg_t r_reg = (*fn)(lower_array_data(sig_reg), count_reg);
628✔
1102

1103
         if (type_const_bounds(ftype))
628✔
1104
            emit_copy(dst_ptr, r_reg, count_reg);
548✔
1105
         else {
1106
            vcode_reg_t wrap_reg = lower_rewrap(r_reg, sig_reg);
80✔
1107
            emit_store_indirect(wrap_reg, dst_ptr);
80✔
1108
         }
1109
      }
1110
      else {
1111
         vcode_reg_t r_reg = (*fn)(sig_reg, VCODE_INVALID_REG);
783✔
1112
         emit_store_indirect(emit_load_indirect(r_reg), dst_ptr);
783✔
1113
      }
1114
   }
1115
}
1,489✔
1116

1117
static vcode_reg_t lower_signal_record_aggregate(lower_unit_t *lu, tree_t expr)
6✔
1118
{
1119
   type_t type = tree_type(expr);
6✔
1120
   const int nfields = type_fields(type);
6✔
1121
   const int nassocs = tree_assocs(expr);
6✔
1122

1123
   vcode_reg_t *vals LOCAL = xcalloc_array(nfields, sizeof(vcode_reg_t));
12✔
1124
   for (int i = 0; i < nfields; i++)
24✔
1125
      vals[i] = VCODE_INVALID_REG;
18✔
1126

1127
   type_t *value_types LOCAL = xcalloc_array(nfields, sizeof(type));
6✔
1128

1129
   for (int i = 0; i < nassocs; i++) {
24✔
1130
      tree_t a = tree_assoc(expr, i);
18✔
1131
      tree_t value = tree_value(a);
18✔
1132

1133
      int pos = 0;
18✔
1134
      switch (tree_subkind(a)) {
18✔
1135
      case A_POS:
×
1136
         pos = tree_pos(a);
×
1137
         break;
×
1138
      case A_NAMED:
18✔
1139
         pos = tree_pos(tree_ref(tree_name(a)));
18✔
1140
         break;
18✔
1141
      case A_OTHERS:
×
1142
      case A_RANGE:
1143
         fatal_trace("unexpected association in record signal aggregate");
1144
      }
1145

1146
      vals[pos] = lower_lvalue(lu, value);
18✔
1147
      value_types[pos] = tree_type(value);
18✔
1148
   }
1149

1150
   for (int i = 0; i < nfields; i++)
24✔
1151
      assert(vals[i] != VCODE_INVALID_REG);
18✔
1152

1153
   vcode_type_t vtype = lower_signal_type(type);
6✔
1154
   vcode_var_t tmp_var = lower_temp_var(lu, "signalagg", vtype, vtype);
6✔
1155
   vcode_reg_t mem_reg = emit_index(tmp_var, VCODE_INVALID_REG);
6✔
1156

1157
   for (int i = 0; i < nfields; i++) {
24✔
1158
      type_t ftype = tree_type(type_field(type, i));
18✔
1159
      vcode_reg_t ptr_reg = emit_record_ref(mem_reg, i);
18✔
1160
      vcode_reg_t val_reg = vals[i];
18✔
1161
      assert(lower_have_signal(val_reg));
18✔
1162

1163
      if (type_is_record(ftype))
18✔
1164
         emit_copy(ptr_reg, val_reg, VCODE_INVALID_REG);
×
1165
      else
1166
         emit_store_indirect(val_reg, ptr_reg);
18✔
1167
   }
1168

1169
   return mem_reg;
6✔
1170
}
1171

1172
static vcode_reg_t lower_signal_array_aggregate(lower_unit_t *lu, tree_t expr)
6✔
1173
{
1174
   const int nassocs = tree_assocs(expr);
6✔
1175
   if (nassocs != 1)
6✔
1176
      fatal_at(tree_loc(expr), "sorry, this form of parameter is not "
×
1177
               "yet supported");
1178

1179
   tree_t a0 = tree_assoc(expr, 0);
6✔
1180
   vcode_reg_t a0_reg = lower_lvalue(lu, tree_value(a0));
6✔
1181

1182
   type_t type = tree_type(expr);
6✔
1183
   if (type_is_unconstrained(type)) {
6✔
1184
      assert(tree_subkind(a0) == A_NAMED);
×
1185
      vcode_reg_t left_reg = lower_rvalue(lu, tree_name(a0));
×
1186
      vcode_reg_t dir_reg = emit_const(vtype_bool(), RANGE_TO);
×
1187
      vcode_dim_t dims[1] = { { left_reg, left_reg, dir_reg } };
×
1188
      return emit_wrap(a0_reg, dims, 1);
×
1189
   }
1190
   else if (!type_const_bounds(type))
6✔
1191
      return lower_wrap(lu, type, a0_reg);
×
1192
   else
1193
      return a0_reg;
1194
}
1195

1196
static vcode_reg_t lower_subprogram_arg(lower_unit_t *lu, tree_t fcall,
154,049✔
1197
                                        unsigned nth)
1198
{
1199
   if (nth >= tree_params(fcall))
154,049✔
1200
      return VCODE_INVALID_REG;
1201

1202
   tree_t param = tree_param(fcall, nth);
145,465✔
1203

1204
   assert(tree_subkind(param) == P_POS);
145,465✔
1205
   assert(tree_pos(param) == nth);
145,465✔
1206

1207
   tree_t value = tree_value(param);
145,465✔
1208
   tree_t decl = tree_ref(fcall);
145,465✔
1209

1210
   port_mode_t mode = PORT_IN;
145,465✔
1211
   if (nth < tree_ports(decl))
145,465✔
1212
      mode = tree_subkind(tree_port(decl, nth));
145,465✔
1213

1214
   tree_t port = NULL;
145,465✔
1215
   if (!is_open_coded_builtin(tree_subkind(decl)))
145,465✔
1216
      port = tree_port(decl, nth);
64,502✔
1217

1218
   type_t value_type = tree_type(value);
145,465✔
1219
   type_t port_type = port ? tree_type(port) : value_type;
145,465✔
1220

1221
   const class_t class = port ? tree_class(port) : C_DEFAULT;
145,465✔
1222

1223
   vcode_reg_t reg;
64,502✔
1224
   if (class == C_SIGNAL && tree_kind(value) == T_AGGREGATE) {
64,502✔
1225
      if (type_is_record(value_type))
12✔
1226
         reg = lower_signal_record_aggregate(lu, value);
6✔
1227
      else
1228
         reg = lower_signal_array_aggregate(lu, value);
6✔
1229
   }
1230
   else if (class == C_SIGNAL || class == C_FILE || mode != PORT_IN)
145,453✔
1231
      reg = lower_lvalue(lu, value);
5,374✔
1232
   else
1233
      reg = lower_rvalue(lu, value);
140,079✔
1234

1235
   if (reg == VCODE_INVALID_REG)
145,465✔
1236
      return reg;
1237

1238
   if (type_is_array(value_type)) {
145,465✔
1239
      if (port != NULL && !type_is_unconstrained(port_type)) {
32,014✔
1240
         vcode_reg_t locus = lower_debug_locus(port);
365✔
1241
         lower_check_array_sizes(lu, port_type, value_type,
365✔
1242
                                 VCODE_INVALID_REG, reg, locus);
1243
      }
1244
      return lower_coerce_arrays(lu, value_type, port_type, reg);
32,014✔
1245
   }
1246
   else if (class == C_SIGNAL || class == C_FILE)
113,451✔
1247
      return reg;
1248
   else if (mode == PORT_OUT || port == NULL || !type_is_scalar(port_type))
112,276✔
1249
      return reg;
85,220✔
1250
   else if (mode == PORT_INOUT) {
27,056✔
1251
      vcode_reg_t scalar_reg = emit_load_indirect(reg);
141✔
1252
      lower_check_scalar_bounds(lu, scalar_reg, port_type, value, port);
141✔
1253
      return reg;
141✔
1254
   }
1255
   else {
1256
      lower_check_scalar_bounds(lu, reg, port_type, value, port);
26,915✔
1257
      return reg;
26,915✔
1258
   }
1259
}
1260

1261
static void lower_signal_flag_field_cb(lower_unit_t *lu, tree_t field,
24✔
1262
                                       vcode_reg_t field_ptr,
1263
                                       vcode_reg_t unused, vcode_reg_t locus,
1264
                                       void *__ctx)
1265
{
1266
   type_t ftype = tree_type(field);
24✔
1267
   if (!type_is_homogeneous(ftype))
24✔
1268
      lower_for_each_field_2(lu, ftype, ftype, field_ptr, VCODE_INVALID_REG,
×
1269
                             locus, lower_signal_flag_field_cb, __ctx);
1270
   else {
1271
      struct {
24✔
1272
         lower_signal_flag_fn_t fn;
1273
         vcode_var_t            result;
1274
      } *args = __ctx;
24✔
1275

1276
      vcode_reg_t flag;
24✔
1277
      if (type_is_array(ftype)) {
24✔
1278
         vcode_reg_t nets_reg = emit_load_indirect(field_ptr);
×
1279
         vcode_reg_t len_reg = lower_array_total_len(lu, ftype, nets_reg);
×
1280
         flag = (*args->fn)(nets_reg, len_reg);
×
1281
      }
1282
      else {
1283
         vcode_reg_t nets_reg = emit_load_indirect(field_ptr);
24✔
1284
         flag = (*args->fn)(nets_reg, emit_const(vtype_offset(), 1));
24✔
1285
      }
1286

1287
      vcode_reg_t cur_reg = emit_load(args->result);
24✔
1288
      vcode_reg_t new_reg = emit_or(cur_reg, flag);
24✔
1289
      emit_store(new_reg, args->result);
24✔
1290
   }
1291
}
24✔
1292

1293
static vcode_reg_t lower_signal_flag(lower_unit_t *lu, tree_t ref,
530✔
1294
                                     lower_signal_flag_fn_t fn)
1295
{
1296
   vcode_reg_t nets = lower_lvalue(lu, ref);
530✔
1297
   if (nets == VCODE_INVALID_REG)
530✔
1298
      return emit_const(vtype_bool(), 0);
×
1299

1300
   type_t type = tree_type(ref);
530✔
1301
   if (!type_is_homogeneous(type)) {
530✔
1302
      vcode_type_t vbool = vtype_bool();
21✔
1303
      vcode_var_t tmp_var = lower_temp_var(lu, "flag", vbool, vbool);
21✔
1304
      emit_store(emit_const(vbool, 0), tmp_var);
21✔
1305

1306
      struct {
21✔
1307
         lower_signal_flag_fn_t fn;
1308
         vcode_var_t            result;
1309
      } args = { fn, tmp_var };
21✔
1310
      lower_for_each_field(lu, type, nets, VCODE_INVALID_REG,
21✔
1311
                           lower_signal_flag_field_cb, &args);
1312

1313
      vcode_reg_t result_reg = emit_load(tmp_var);
21✔
1314
      lower_release_temp(lu, tmp_var);
21✔
1315
      return result_reg;
21✔
1316
   }
1317
   else if (type_is_array(type)) {
509✔
1318
      vcode_reg_t data_reg = lower_array_data(nets);
100✔
1319
      vcode_reg_t len_reg = lower_array_total_len(lu, type, nets);
100✔
1320
      return (*fn)(data_reg, len_reg);
100✔
1321
   }
1322
   else
1323
      return (*fn)(nets, emit_const(vtype_offset(), 1));
409✔
1324
}
1325

1326
static vcode_reg_t lower_last_value(lower_unit_t *lu, tree_t ref)
53✔
1327
{
1328
   vcode_reg_t nets = lower_lvalue(lu, ref);
53✔
1329

1330
   type_t type = tree_type(ref);
53✔
1331
   if (type_is_homogeneous(type)) {
53✔
1332
      vcode_reg_t data_reg =
41✔
1333
         emit_last_value(lower_array_data(nets), VCODE_INVALID_REG);
41✔
1334
      if (vcode_reg_kind(nets) == VCODE_TYPE_UARRAY)
41✔
1335
         return lower_rewrap(data_reg, nets);
3✔
1336
      else
1337
         return data_reg;
1338
   }
1339
   else {
1340
      // Use a helper function to convert a record signal into a record
1341
      // containing the resolved values
1342

1343
      ident_t base_id = type_ident(type_base_recur(type));
12✔
1344
      ident_t helper_func = ident_prefix(base_id, ident_new("last_value"), '$');
12✔
1345

1346
      vcode_reg_t arg_reg = nets;
12✔
1347
      if (type_is_array(type) && vcode_reg_kind(arg_reg) != VCODE_TYPE_UARRAY)
12✔
1348
         arg_reg = lower_wrap(lu, type, nets);
6✔
1349

1350
      vcode_type_t vrtype = lower_func_result_type(type);
12✔
1351

1352
      vcode_reg_t context_reg = lower_context_for_call(lu, helper_func);
12✔
1353
      vcode_reg_t args[] = { context_reg, arg_reg };
12✔
1354
      return emit_fcall(helper_func, vrtype, vrtype, args, 2);
12✔
1355
   }
1356
}
1357

1358
static type_t lower_arg_type(tree_t fcall, int nth)
79,460✔
1359
{
1360
   if (nth >= tree_params(fcall))
79,460✔
1361
      return NULL;
1362
   else
1363
      return tree_type(tree_value(tree_param(fcall, nth)));
70,876✔
1364
}
1365

1366
static vcode_reg_t lower_wrap_string(const char *str)
2,824✔
1367
{
2,824✔
1368
   const size_t len = strlen(str);
2,824✔
1369
   vcode_reg_t chars[len + 1];
2,824✔
1370
   vcode_type_t ctype = vtype_char();
2,824✔
1371

1372
   for (int j = 0; j < len; j++)
26,271✔
1373
      chars[j] = emit_const(ctype, str[j]);
23,447✔
1374

1375
   vcode_type_t str_type = vtype_carray(len, ctype, ctype);
2,824✔
1376
   vcode_reg_t data = emit_const_array(str_type, chars, len);
2,824✔
1377

1378
   vcode_dim_t dim0 = {
2,824✔
1379
      .left  = emit_const(vtype_offset(), 1),
2,824✔
1380
      .right = emit_const(vtype_offset(), len),
2,824✔
1381
      .dir   = emit_const(vtype_bool(), RANGE_TO)
2,824✔
1382
   };
1383
   return emit_wrap(emit_address_of(data), &dim0, 1);
2,824✔
1384
}
1385

1386
static void get_hierarchical_name(text_buf_t *tb, lower_unit_t *lu,
554✔
1387
                                  attr_kind_t which)
1388
{
1389
   switch (tree_kind(lu->container)) {
554✔
1390
   case T_BLOCK:
362✔
1391
   case T_PACK_BODY:
1392
   case T_PACKAGE:
1393
   case T_PACK_INST:
1394
      tb_append(tb, ':');
362✔
1395
      break;
362✔
1396

1397
   case T_PROC_BODY:
45✔
1398
   case T_FUNC_BODY:
1399
   case T_PROC_INST:
1400
   case T_FUNC_INST:
1401
      get_hierarchical_name(tb, lu->parent, which);
45✔
1402

1403
      tb_istr(tb, tree_ident(lu->container));
45✔
1404

1405
      if (standard() >= STD_02)
45✔
1406
         type_signature(tree_type(lu->container), tb);
33✔
1407

1408
      tb_append(tb, ':');
45✔
1409
      tb_downcase(tb);
45✔
1410
      break;
45✔
1411

1412
   case T_PROCESS:
102✔
1413
      get_hierarchical_name(tb, lu->parent, which);
102✔
1414

1415
      if (!(tree_flags(lu->container) & TREE_F_SYNTHETIC_NAME))
102✔
1416
         tb_istr(tb, tree_ident(lu->container));
84✔
1417

1418
      tb_append(tb, ':');
102✔
1419
      tb_downcase(tb);
102✔
1420
      break;
102✔
1421

1422
   case T_PROT_BODY:
45✔
1423
      // LCS-2016-032 requires dynamic name
1424
      if (standard() < STD_19) {
45✔
1425
         get_hierarchical_name(tb, lu->parent, which);
×
1426
         tb_istr(tb, tree_ident(lu->container));
×
1427
         tb_downcase(tb);
×
1428
      }
1429
      tb_append(tb, ':');
45✔
1430
      break;
45✔
1431

1432
   default:
×
1433
      fatal_at(tree_loc(lu->container), "cannot get hierarchical name");
×
1434
   }
1435
}
554✔
1436

1437
static vcode_reg_t lower_name_attr(lower_unit_t *lu, tree_t decl,
841✔
1438
                                   attr_kind_t which)
1439
{
1440
   LOCAL_TEXT_BUF tb = tb_new();
1,682✔
1441
   lower_unit_t *scope = lu;
841✔
1442
   int extra_hops = 0;
841✔
1443

1444
   switch (tree_kind(decl)) {
841✔
1445
   case T_PACK_BODY:
355✔
1446
      decl = tree_primary(decl);
355✔
1447
      // Fall-through
1448
   case T_PACKAGE:
370✔
1449
   case T_PACK_INST:
1450
      tb_append(tb, ':');
370✔
1451
      tb_istr(tb, tree_ident(decl));
370✔
1452
      tb_append(tb, ':');
370✔
1453
      tb_replace(tb, '.', ':');
370✔
1454
      tb_downcase(tb);
370✔
1455
      return lower_wrap_string(tb_get(tb));
370✔
1456

1457
   case T_INSTANCE:
3✔
1458
      tb_append(tb, ':');
3✔
1459
      tb_istr(tb, tree_ident(decl));
3✔
1460
      tb_downcase(tb);
3✔
1461
      break;
3✔
1462

1463
   case T_BLOCK:
93✔
1464
   case T_ENTITY:
1465
   case T_ARCH:
1466
   case T_PROT_DECL:
1467
   case T_PROT_BODY:
1468
   case T_FOR_GENERATE:
1469
   case T_IF_GENERATE:
1470
   case T_CASE_GENERATE:
1471
      tb_append(tb, ':');
93✔
1472
      break;
93✔
1473

1474
   case T_PROCESS:
30✔
1475
      tb_append(tb, ':');
30✔
1476
      tb_istr(tb, tree_ident(decl));
30✔
1477
      tb_append(tb, ':');
30✔
1478
      tb_downcase(tb);
30✔
1479
      break;
30✔
1480

1481
   case T_PROC_DECL:
57✔
1482
   case T_FUNC_DECL:
1483
   case T_PROC_BODY:
1484
   case T_FUNC_BODY:
1485
   case T_PROC_INST:
1486
   case T_FUNC_INST:
1487
      {
1488
         vcode_unit_t parent =
57✔
1489
            unit_registry_get_parent(lu->registry, tree_ident2(decl));
57✔
1490

1491
         if (parent != NULL) {
57✔
1492
            for (; scope != NULL; scope = scope->parent, extra_hops++) {
123✔
1493
               if (scope->vunit == parent) {
117✔
1494
                  get_hierarchical_name(tb, scope, which);
51✔
1495

1496
                  tb_istr(tb, tree_ident(decl));
51✔
1497

1498
                  if (standard() >= STD_02)
51✔
1499
                     type_signature(tree_type(decl), tb);
30✔
1500

1501
                  tb_append(tb, ':');
51✔
1502
                  tb_downcase(tb);
51✔
1503
                  break;
51✔
1504
               }
1505
            }
1506
         }
1507
         else
1508
            scope = NULL;
1509
      }
1510
      break;
1511

1512
   case T_VAR_DECL:
288✔
1513
   case T_SIGNAL_DECL:
1514
   case T_ALIAS:
1515
   case T_PORT_DECL:
1516
   case T_CONST_DECL:
1517
   case T_GENERIC_DECL:
1518
   case T_PARAM_DECL:
1519
      {
1520
         int obj = lower_search_vcode_obj(decl, lu, &extra_hops);
288✔
1521
         if (obj != -1) {
288✔
1522
            for (int i = 0; i < extra_hops; i++, scope = scope->parent);
433✔
1523

1524
            get_hierarchical_name(tb, scope, which);
280✔
1525

1526
            tb_istr(tb, tree_ident(decl));
280✔
1527
            tb_downcase(tb);
280✔
1528
         }
1529
         else
1530
            scope = NULL;
1531
      }
1532
      break;
1533

1534
   default:
×
1535
      fatal_trace("cannot handle decl kind %s in lower_name_attr",
1536
                  tree_kind_str(tree_kind(decl)));
1537
   }
1538

1539
   if (scope == NULL) {
463✔
1540
      tree_t container = tree_container(decl);
14✔
1541
      if (is_package((container))) {
14✔
1542
         tb_append(tb, ':');
14✔
1543
         tb_istr(tb, tree_ident(primary_unit_of(container)));
14✔
1544
         tb_append(tb, ':');
14✔
1545
         tb_replace(tb, '.', ':');
14✔
1546
         tb_istr(tb, tree_ident(decl));
14✔
1547
         if (is_container(decl) || is_subprogram(decl))
14✔
1548
            tb_append(tb, ':');
6✔
1549
         tb_downcase(tb);
14✔
1550

1551
         return lower_wrap_string(tb_get(tb));
14✔
1552
      }
1553

1554
      fatal_at(tree_loc(decl), "cannot get hierachical name");
×
1555
   }
1556

1557
   ident_t var_name =
457✔
1558
      well_known(which == ATTR_PATH_NAME ? W_PATH_NAME : W_INSTANCE_NAME);
651✔
1559

1560
   int hops = 0;
457✔
1561
   vcode_var_t var = lower_search_vcode_obj(var_name, scope, &hops);
457✔
1562
   assert(var != VCODE_INVALID_VAR);
457✔
1563

1564
   vcode_reg_t array_reg;
457✔
1565
   if (hops + extra_hops == 0)
457✔
1566
      array_reg = emit_load(var);
61✔
1567
   else {
1568
      vcode_reg_t ptr_reg = emit_var_upref(hops + extra_hops, var);
396✔
1569
      array_reg = emit_load_indirect(ptr_reg);
396✔
1570
   }
1571

1572
   if (tb_len(tb) == 0)
457✔
1573
      return array_reg;
1574

1575
   vcode_type_t ctype = vtype_char();
457✔
1576
   vcode_type_t voffset = vtype_offset();
457✔
1577

1578
   const size_t suffix_len = tb_len(tb);
457✔
1579
   vcode_reg_t chars[suffix_len];
457✔
1580

1581
   for (int j = 0; j < suffix_len; j++)
3,734✔
1582
      chars[j] = emit_const(ctype, tb_get(tb)[j]);
3,277✔
1583

1584
   vcode_type_t str_type = vtype_carray(suffix_len, ctype, ctype);
457✔
1585
   vcode_reg_t suffix_reg = emit_const_array(str_type, chars, suffix_len);
457✔
1586

1587
   vcode_reg_t prefix_len_reg = emit_uarray_len(array_reg, 0);
457✔
1588
   vcode_reg_t suffix_len_reg = emit_const(voffset, suffix_len);
457✔
1589
   vcode_reg_t total_len_reg = emit_add(prefix_len_reg, suffix_len_reg);
457✔
1590
   vcode_reg_t mem_reg = emit_alloc(ctype, ctype, total_len_reg);
457✔
1591
   vcode_reg_t suffix_ptr_reg = emit_array_ref(mem_reg, prefix_len_reg);
457✔
1592

1593
   emit_copy(mem_reg, emit_unwrap(array_reg), prefix_len_reg);
457✔
1594
   emit_copy(suffix_ptr_reg, emit_address_of(suffix_reg), suffix_len_reg);
457✔
1595

1596
   vcode_dim_t dim0 = {
457✔
1597
      .left  = emit_const(voffset, 1),
457✔
1598
      .right = total_len_reg,
1599
      .dir   = emit_const(vtype_bool(), RANGE_TO)
457✔
1600
   };
1601
   return emit_wrap(mem_reg, &dim0, 1);
457✔
1602
}
1603

1604
static vcode_reg_t lower_arith(tree_t fcall, subprogram_kind_t kind,
13,041✔
1605
                               vcode_reg_t r0, vcode_reg_t r1)
1606
{
1607
   type_t type = tree_type(fcall);
13,041✔
1608

1609
   switch (kind) {
13,041✔
1610
   case S_ADD:
3,217✔
1611
      if (type_is_integer(type))
3,217✔
1612
         return emit_trap_add(r0, r1, lower_debug_locus(fcall));
2,857✔
1613
      else
1614
         return emit_add(r0, r1);
360✔
1615
   case S_MUL:
1,630✔
1616
      if (type_is_integer(type))
1,630✔
1617
         return emit_trap_mul(r0, r1, lower_debug_locus(fcall));
902✔
1618
      else
1619
         return emit_mul(r0, r1);
728✔
1620
   case S_SUB:
6,070✔
1621
      if (type_is_integer(type))
6,070✔
1622
         return emit_trap_sub(r0, r1, lower_debug_locus(fcall));
5,756✔
1623
      else
1624
         return emit_sub(r0, r1);
314✔
1625
   case S_MOD: return emit_mod(r0, r1);
198✔
1626
   case S_REM: return emit_rem(r0, r1);
83✔
1627
   case S_DIV: return emit_div(r0, r1);
948✔
1628
   case S_EXP:
895✔
1629
      if (type_is_integer(type))
895✔
1630
         return emit_trap_exp(r0, r1, lower_debug_locus(fcall));
816✔
1631
      else
1632
         return emit_exp(r0, r1);
79✔
1633
   default:
×
1634
      fatal_trace("invalid subprogram kind %d in lower_arith", kind);
1635
   }
1636
}
1637

1638
static void lower_branch_coverage(lower_unit_t *lu, tree_t b,
332✔
1639
                                  vcode_block_t true_bb, vcode_block_t false_bb)
1640
{
1641
   assert(cover_enabled(lu->cover, COVER_MASK_BRANCH));
332✔
1642

1643
   object_t *obj = tree_to_object(b);
332✔
1644

1645
   cover_scope_t *cs = lower_get_cover_scope(lu);
332✔
1646
   cover_item_t *item = cover_add_items_for(lu->cover, cs, obj,
332✔
1647
                                            COV_ITEM_BRANCH);
1648
   if (item == NULL)
332✔
1649
      return;
12✔
1650

1651
   vcode_block_t blocks[2] = { true_bb, false_bb };
320✔
1652

1653
   for (int i = 0; i < item->consecutive; i++) {
815✔
1654
      assert(blocks[i] != VCODE_INVALID_BLOCK);
495✔
1655

1656
      vcode_select_block(blocks[i]);
495✔
1657
      emit_cover_branch(item[i].tag);
495✔
1658
   }
1659
}
1660

1661
static void lower_stmt_coverage(lower_unit_t *lu, tree_t stmt)
70,813✔
1662
{
1663
   if (!cover_enabled(lu->cover, COVER_MASK_STMT))
70,813✔
1664
      return;
1665

1666
   cover_scope_t *cs = lower_get_cover_scope(lu);
1,034✔
1667
   cover_item_t *item = cover_add_items_for(lu->cover, cs,
1,034✔
1668
                                            tree_to_object(stmt),
1669
                                            COV_ITEM_STMT);
1670
   if (item != NULL)
1,034✔
1671
      emit_cover_stmt(item->tag);
994✔
1672
}
1673

1674
static void lower_toggle_coverage_cb(lower_unit_t *lu, tree_t field,
27✔
1675
                                     vcode_reg_t field_ptr,
1676
                                     vcode_reg_t unused, vcode_reg_t locus,
1677
                                     void *ctx)
1678
{
1679
   type_t ftype = tree_type(field);
27✔
1680

1681
   PUSH_COVER_SCOPE(lu, field);
54✔
1682

1683
   if (!type_is_homogeneous(ftype))
27✔
1684
      lower_for_each_field(lu, ftype, field_ptr, locus,
3✔
1685
                           lower_toggle_coverage_cb, NULL);
1686
   else {
1687
      cover_scope_t *cscope = lower_get_cover_scope(lu);
24✔
1688
      cover_item_t *first = cover_add_items_for(lu->cover, cscope,
24✔
1689
                                                tree_to_object(field),
1690
                                                COV_ITEM_TOGGLE);
1691
      if (first != NULL) {
24✔
1692
         vcode_reg_t nets_reg = emit_load_indirect(field_ptr);
21✔
1693
         emit_cover_toggle(nets_reg, first->tag);
21✔
1694
      }
1695
   }
1696
}
27✔
1697

1698
static void lower_toggle_coverage(lower_unit_t *lu, tree_t decl)
402✔
1699
{
1700
   assert(cover_enabled(lu->cover, COVER_MASK_TOGGLE));
402✔
1701

1702
   int hops = 0;
402✔
1703
   vcode_var_t var = lower_search_vcode_obj(decl, lu, &hops);
402✔
1704
   assert(var != VCODE_INVALID_VAR);
402✔
1705
   assert(hops == 0);
402✔
1706

1707
   type_t type = tree_type(decl);
402✔
1708
   if (!type_is_homogeneous(type)) {
402✔
1709
      vcode_reg_t rec_ptr = emit_index(var, VCODE_INVALID_REG);
12✔
1710
      lower_for_each_field(lu, type, rec_ptr, VCODE_INVALID_REG,
12✔
1711
                           lower_toggle_coverage_cb, NULL);
1712
   }
1713
   else {
1714
      cover_scope_t *cscope = lower_get_cover_scope(lu);
390✔
1715
      cover_item_t *first = cover_add_items_for(lu->cover, cscope,
390✔
1716
                                                tree_to_object(decl),
1717
                                                COV_ITEM_TOGGLE);
1718
      if (first != NULL) {
390✔
1719
         vcode_reg_t nets_reg = emit_load(var);
292✔
1720
         emit_cover_toggle(nets_reg, first->tag);
292✔
1721
      }
1722
   }
1723
}
402✔
1724

1725
static void lower_state_coverage(lower_unit_t *lu, tree_t decl)
148✔
1726
{
1727
   assert(cover_enabled(lu->cover, COVER_MASK_STATE));
148✔
1728

1729
   cover_scope_t *cscope = lower_get_cover_scope(lu);
148✔
1730

1731
   int hops = 0;
148✔
1732
   vcode_var_t var = lower_search_vcode_obj(decl, lu, &hops);
148✔
1733
   assert(var != VCODE_INVALID_VAR);
148✔
1734

1735
   cover_item_t *item = cover_add_items_for(lu->cover, cscope,
148✔
1736
                                            tree_to_object(decl),
1737
                                            COV_ITEM_STATE);
1738
   if (item) {
148✔
1739
      vcode_reg_t nets_reg = emit_load(var);
12✔
1740

1741
      // If a type is sub-type, then lower bound may be non-zero.
1742
      // Then value of lower bound will correspond to first coverage
1743
      // tag.  Need to remember the lower bound, so that run-time can
1744
      // subtract lower bound to get correct index of coverage data.
1745
      vcode_reg_t low_reg = emit_const(vtype_int(INT64_MIN, INT64_MAX),
12✔
1746
                                       item->metadata);
1747
      emit_cover_state(nets_reg, low_reg, item->tag);
12✔
1748
   }
1749
}
148✔
1750

1751
static vcode_reg_t lower_logical(lower_unit_t *lu, tree_t fcall,
23,861✔
1752
                                 vcode_reg_t result, vcode_reg_t lhs,
1753
                                 vcode_reg_t rhs, subprogram_kind_t builtin,
1754
                                 unsigned unrc_msk)
1755
{
1756
   if (!cover_enabled(lu->cover, COVER_MASK_EXPRESSION))
23,861✔
1757
      return result;
1758

1759
   cover_scope_t *cscope = lower_get_cover_scope(lu);
279✔
1760
   cover_item_t *first = cover_add_items_for(lu->cover, cscope,
279✔
1761
                                             tree_to_object(fcall),
1762
                                             COV_ITEM_EXPRESSION);
1763
   if (first == NULL)
279✔
1764
      return result;
1765

1766
   cover_item_t *current = first;
279✔
1767

1768
   vcode_reg_t lhs_n = VCODE_INVALID_REG;
279✔
1769
   vcode_reg_t rhs_n = VCODE_INVALID_REG;
279✔
1770

1771
   if (first->flags & COVER_FLAGS_LHS_RHS_BINS) {
279✔
1772
      lhs_n = emit_not(lhs);
67✔
1773
      rhs_n = emit_not(rhs);
67✔
1774
   }
1775

1776
   struct {
279✔
1777
      unsigned    flag;
1778
      vcode_reg_t lhs;
1779
      vcode_reg_t rhs;
1780
   } bins[] = {
279✔
1781
      { COV_FLAG_00, lhs_n, rhs_n },
1782
      { COV_FLAG_01, lhs_n, rhs   },
1783
      { COV_FLAG_10, lhs,   rhs_n },
1784
      { COV_FLAG_11, lhs,   rhs   },
1785
   };
1786

1787
   for (int i = 0; i < first->consecutive; i++) {
922✔
1788
      vcode_block_t next_bb = emit_block();
643✔
1789
      vcode_block_t match_bb = emit_block();
643✔
1790

1791
      if (unrc_msk & current->flags)
643✔
1792
         current->flags |= COV_FLAG_UNREACHABLE;
6✔
1793

1794
      // Unary expressions
1795
      if ((current->flags & COV_FLAG_TRUE) || (current->flags & COV_FLAG_FALSE)) {
643✔
1796
         vcode_reg_t test = (current->flags & COV_FLAG_TRUE) ? result : emit_not(result);
424✔
1797
         emit_cond(test, match_bb, next_bb);
424✔
1798

1799
         vcode_select_block(match_bb);
424✔
1800
         emit_cover_expr(current->tag);
424✔
1801
         emit_jump(next_bb);
424✔
1802

1803
         vcode_select_block(next_bb);
424✔
1804
      }
1805

1806
      // Binary expressions
1807
      else {
1808
         for (int j = 0; j < ARRAY_LEN(bins); j++) {
555✔
1809
            if (current->flags & bins[j].flag) {
555✔
1810
               vcode_reg_t test = emit_and(bins[j].lhs, bins[j].rhs);
219✔
1811
               emit_cond(test, match_bb, next_bb);
219✔
1812

1813
               vcode_select_block(match_bb);
219✔
1814
               emit_cover_expr(current->tag);
219✔
1815
               emit_jump(next_bb);
219✔
1816

1817
               vcode_select_block(next_bb);
219✔
1818
               break;
219✔
1819
            }
1820
         }
1821
      }
1822

1823
      current++;
643✔
1824
   }
1825

1826
   return result;
1827
}
1828

1829
static void lower_logic_expr_coverage(lower_unit_t *lu, tree_t fcall,
121✔
1830
                                      vcode_reg_t *args)
1831
{
1832
   cover_scope_t *cscope = lower_get_cover_scope(lu);
121✔
1833
   cover_item_t *first = cover_add_items_for(lu->cover, cscope,
121✔
1834
                                             tree_to_object(fcall),
1835
                                             COV_ITEM_EXPRESSION);
1836

1837
   if (first == NULL)
121✔
1838
      return;
58✔
1839

1840
   vcode_reg_t lhs = args[1];
63✔
1841
   vcode_reg_t rhs = args[2];
63✔
1842

1843
   // Corresponds to how std_ulogic enum is translated
1844
   vcode_type_t vc_logic = vcode_reg_type(lhs);
63✔
1845
   vcode_reg_t log_0 = emit_const(vc_logic, 2);
63✔
1846
   vcode_reg_t log_1 = emit_const(vc_logic, 3);
63✔
1847

1848
   struct {
63✔
1849
      unsigned flag;
1850
      vcode_reg_t lhs_exp;
1851
      vcode_reg_t rhs_exp;
1852
   } bins[] = {
63✔
1853
      { COV_FLAG_00, log_0, log_0 },
1854
      { COV_FLAG_01, log_0, log_1 },
1855
      { COV_FLAG_10, log_1, log_0 },
1856
      { COV_FLAG_11, log_1, log_1 },
1857
   };
1858

1859
   cover_item_t *current = first;
63✔
1860
   for (int i = 0; i < first->consecutive; i++) {
276✔
1861
      vcode_block_t next_bb = emit_block();
213✔
1862
      vcode_block_t match_bb = emit_block();
213✔
1863

1864
      // Build logic to check combinations of LHS and RHS
1865
      for (int j = 0; j < ARRAY_LEN(bins); j++) {
1,065✔
1866
         if (current->flags & bins[j].flag) {
852✔
1867
            vcode_reg_t cmp_lhs = emit_cmp(VCODE_CMP_EQ, lhs, bins[j].lhs_exp);
213✔
1868
            vcode_reg_t cmp_rhs = emit_cmp(VCODE_CMP_EQ, rhs, bins[j].rhs_exp);
213✔
1869
            vcode_reg_t test = emit_and(cmp_lhs, cmp_rhs);
213✔
1870

1871
            emit_cond(test, match_bb, next_bb);
213✔
1872

1873
            vcode_select_block(match_bb);
213✔
1874
            emit_cover_expr(current->tag);
213✔
1875
            emit_jump(next_bb);
213✔
1876

1877
            vcode_select_block(next_bb);
213✔
1878
         }
1879
      }
1880

1881
      current++;
213✔
1882
   }
1883
}
1884

1885

1886
static bool lower_side_effect_free(tree_t expr)
17,495✔
1887
{
1888
   // True if expression is side-effect free with no function calls
1889
   switch (tree_kind(expr)) {
17,722✔
1890
   case T_REF:
1891
   case T_LITERAL:
1892
   case T_STRING:
1893
      return true;
1894
   case T_FCALL:
5,686✔
1895
      {
1896
         const subprogram_kind_t kind = tree_subkind(tree_ref(expr));
5,686✔
1897
         if (kind == S_DIV || kind == S_DIV_PR || kind == S_DIV_RI
5,686✔
1898
             || kind == S_REM || kind == S_MOD)
5,677✔
1899
            return false;
1900
         else if (kind == S_CONCAT)
5,677✔
1901
            return false;   // Allocates memory
1902
         else if (kind == S_USER || !is_open_coded_builtin(kind))
5,287✔
1903
            return false;
1,418✔
1904

1905
         const int nparams = tree_params(expr);
3,869✔
1906
         for (int i = 0; i < nparams; i++) {
7,783✔
1907
            if (!lower_side_effect_free(tree_value(tree_param(expr, i))))
5,874✔
1908
               return false;
1909
         }
1910

1911
         return true;
1912
      }
1913
      break;
199✔
1914
   case T_RECORD_REF:
199✔
1915
   case T_QUALIFIED:
1916
   case T_TYPE_CONV:
1917
      return lower_side_effect_free(tree_value(expr));
199✔
1918
   case T_ATTR_REF:
581✔
1919
      {
1920
         const attr_kind_t kind = tree_subkind(expr);
581✔
1921
         if (kind == ATTR_EVENT || kind == ATTR_ACTIVE)
581✔
1922
            return lower_side_effect_free(tree_name(expr));
28✔
1923
         else
1924
            return false;
1925
      }
1926
   default:
1,295✔
1927
      return false;
1,295✔
1928
   }
1929
}
1930

1931
static vcode_var_t lower_temp_var(lower_unit_t *lu, const char *prefix,
9,690✔
1932
                                  vcode_type_t vtype, vcode_type_t vbounds)
1933
{
1934
   vcode_var_t tmp = VCODE_INVALID_VAR;
9,690✔
1935
   unsigned pos = 0;
9,690✔
1936
   for (; pos < lu->free_temps.count; pos++) {
9,934✔
1937
      tmp = lu->free_temps.items[pos];
3,992✔
1938
      if (vtype_eq(vcode_var_type(tmp), vtype)
3,992✔
1939
          && vtype_eq(vcode_var_bounds(tmp), vbounds))
3,751✔
1940
         break;
1941
   }
1942

1943
   if (pos == lu->free_temps.count)
9,690✔
1944
      return emit_var(vtype, vbounds, ident_uniq("%s", prefix), VAR_TEMP);
5,942✔
1945

1946
   emit_comment("Reusing temp var %s", istr(vcode_var_name(tmp)));
3,748✔
1947

1948
   for (; pos < lu->free_temps.count - 1; pos++)
7,728✔
1949
      lu->free_temps.items[pos] = lu->free_temps.items[pos + 1];
232✔
1950
   APOP(lu->free_temps);
3,748✔
1951

1952
   return tmp;
3,748✔
1953
}
1954

1955
static void lower_release_temp(lower_unit_t *lu, vcode_var_t tmp)
6,419✔
1956
{
1957
   assert(vcode_var_flags(tmp) & VAR_TEMP);
6,419✔
1958
   APUSH(lu->free_temps, tmp);
6,419✔
1959
}
6,419✔
1960

1961
static vcode_reg_t lower_short_circuit(lower_unit_t *lu, tree_t fcall,
5,019✔
1962
                                       subprogram_kind_t builtin)
1963
{
1964
   vcode_reg_t r0 = lower_subprogram_arg(lu, fcall, 0);
5,019✔
1965
   int64_t value;
5,019✔
1966
   if (vcode_reg_const(r0, &value)) {
5,019✔
1967
      vcode_reg_t result = VCODE_INVALID_REG;
148✔
1968
      switch (builtin) {
148✔
1969
      case S_SCALAR_AND:
79✔
1970
         result = value ? lower_subprogram_arg(lu, fcall, 1) : r0;
79✔
1971
         break;
1972
      case S_SCALAR_OR:
68✔
1973
         result = value ? r0 : lower_subprogram_arg(lu, fcall, 1);
68✔
1974
         break;
1975
      case S_SCALAR_NOR:
1✔
1976
         result = emit_not(value ? r0 : lower_subprogram_arg(lu, fcall, 1));
1✔
1977
         break;
1✔
1978
      case S_SCALAR_NAND:
×
1979
         result = emit_not(value ? lower_subprogram_arg(lu, fcall, 1) : r0);
×
1980
         break;
×
1981
      default:
×
1982
         fatal_trace("unhandled subprogram kind %d in lower_short_circuit",
1983
                      builtin);
1984
      }
1985

1986
      return result;
148✔
1987
   }
1988

1989
   if (lower_side_effect_free(tree_value(tree_param(fcall, 1)))) {
4,871✔
1990
      vcode_reg_t r1 = lower_subprogram_arg(lu, fcall, 1);
1,842✔
1991
      switch (builtin) {
1,842✔
1992
      case S_SCALAR_AND:
1,197✔
1993
         return lower_logical(lu, fcall, emit_and(r0, r1), r0, r1, builtin, 0);
1,197✔
1994
      case S_SCALAR_OR:
571✔
1995
         return lower_logical(lu, fcall, emit_or(r0, r1), r0, r1, builtin, 0);
571✔
1996
      case S_SCALAR_NOR:
37✔
1997
         return lower_logical(lu, fcall, emit_nor(r0, r1), r0, r1, builtin, 0);
37✔
1998
      case S_SCALAR_NAND:
37✔
1999
         return lower_logical(lu, fcall, emit_nand(r0, r1), r0, r1, builtin, 0);
37✔
2000
      default:
×
2001
         fatal_trace("unhandled subprogram kind %d in lower_short_circuit",
2002
                      builtin);
2003
      }
2004
   }
2005

2006
   vcode_block_t arg1_bb = emit_block();
3,029✔
2007
   vcode_block_t after_bb = emit_block();
3,029✔
2008

2009
   vcode_type_t vbool = vtype_bool();
3,029✔
2010
   vcode_var_t tmp_var = lower_temp_var(lu, "shortcircuit", vbool, vbool);
3,029✔
2011

2012
   if (builtin == S_SCALAR_NOR || builtin == S_SCALAR_NAND)
3,029✔
2013
      emit_store(emit_not(r0), tmp_var);
25✔
2014
   else
2015
      emit_store(r0, tmp_var);
3,004✔
2016

2017
   if (builtin == S_SCALAR_AND || builtin == S_SCALAR_NAND)
3,029✔
2018
      emit_cond(r0, arg1_bb, after_bb);
2,244✔
2019
   else
2020
      emit_cond(r0, after_bb, arg1_bb);
785✔
2021

2022
   vcode_select_block(arg1_bb);
3,029✔
2023
   vcode_reg_t r1 = lower_subprogram_arg(lu, fcall, 1);
3,029✔
2024

2025
   switch (builtin) {
3,029✔
2026
   case S_SCALAR_AND:
2,232✔
2027
      emit_store(emit_and(r0, r1), tmp_var);
2,232✔
2028
      break;
2,232✔
2029
   case S_SCALAR_OR:
772✔
2030
      emit_store(emit_or(r0, r1), tmp_var);
772✔
2031
      break;
772✔
2032
   case S_SCALAR_NOR:
13✔
2033
      emit_store(emit_nor(r0, r1), tmp_var);
13✔
2034
      break;
13✔
2035
   case S_SCALAR_NAND:
12✔
2036
      emit_store(emit_nand(r0, r1), tmp_var);
12✔
2037
      break;
12✔
2038
   default:
×
2039
      fatal_trace("unhandled subprogram kind %d in lower_short_circuit",
2040
                      builtin);
2041
   }
2042

2043
   // Automaticaly flag non-executed bins as un-reachable if configured
2044
   unsigned unrc_msk = 0;
3,029✔
2045
   if (cover_enabled(lu->cover, COVER_MASK_EXCLUDE_UNREACHABLE)) {
3,029✔
2046
      if (builtin == S_SCALAR_AND || builtin == S_SCALAR_NAND)
6✔
2047
         unrc_msk = COV_FLAG_00 | COV_FLAG_01;
2048
      else
2049
         unrc_msk = COV_FLAG_11 | COV_FLAG_10;
3✔
2050
   }
2051

2052
   // Only emit expression coverage when also arg1 is evaluated.
2053
   lower_logical(lu, fcall, emit_load(tmp_var), r0, r1, builtin, unrc_msk);
3,029✔
2054

2055
   emit_jump(after_bb);
3,029✔
2056

2057
   vcode_select_block(after_bb);
3,029✔
2058
   vcode_reg_t result = emit_load(tmp_var);
3,029✔
2059
   lower_release_temp(lu, tmp_var);
3,029✔
2060

2061
   return result;
3,029✔
2062
}
2063

2064
static void lower_flatten_concat(lower_unit_t *lu, tree_t arg,
3,430✔
2065
                                 concat_list_t *list)
2066
{
2067
   if (tree_kind(arg) == T_FCALL && tree_subkind(tree_ref(arg)) == S_CONCAT) {
5,609✔
2068
      assert(tree_params(arg) == 2);
2,179✔
2069
      lower_flatten_concat(lu, tree_value(tree_param(arg, 0)), list);
2,179✔
2070
      lower_flatten_concat(lu, tree_value(tree_param(arg, 1)), list);
2,179✔
2071
   }
2072
   else {
2073
      vcode_reg_t reg = lower_rvalue(lu, arg);
3,430✔
2074
      APUSH(*list, ((concat_param_t){ arg, tree_type(arg), reg }));
3,430✔
2075
   }
2076
}
3,430✔
2077

2078
static vcode_reg_t lower_concat(lower_unit_t *lu, tree_t expr, vcode_reg_t hint,
1,251✔
2079
                                vcode_reg_t hint_count)
2080
{
2081
   assert(tree_params(expr) == 2);
1,251✔
2082

2083
   concat_list_t args = AINIT;
1,251✔
2084
   lower_flatten_concat(lu, expr, &args);
1,251✔
2085

2086
   type_t type = tree_type(expr);
1,251✔
2087
   type_t elem = type_elem(type);
1,251✔
2088
   assert(type_is_unconstrained(type));
1,251✔
2089

2090
   type_t scalar_elem = type_elem_recur(elem);
1,251✔
2091

2092
   vcode_type_t voffset = vtype_offset();
1,251✔
2093

2094
   type_t index_type = index_type_of(type, 0);
1,251✔
2095
   tree_t index_r = range_of(index_type, 0);
1,251✔
2096
   vcode_type_t itype = lower_type(index_type);
1,251✔
2097
   vcode_type_t ibounds = lower_bounds(index_type);
1,251✔
2098

2099
   vcode_reg_t len   = emit_const(voffset, 0);
1,251✔
2100
   vcode_reg_t elems = emit_const(voffset, -1);
1,251✔
2101
   vcode_reg_t dir   = lower_range_dir(lu, index_r);
1,251✔
2102
   vcode_reg_t left  = lower_range_left(lu, index_r);
1,251✔
2103

2104
   for (unsigned i = 0; i < args.count; i++) {
4,681✔
2105
      concat_param_t *p = &(args.items[i]);
3,430✔
2106
      if (type_is_array(p->type) && type_eq(p->type, type)) {
3,430✔
2107
         elems = emit_add(elems, lower_array_len(lu, p->type, 0, p->reg));
3,064✔
2108
         len   = emit_add(len, lower_array_total_len(lu, p->type, p->reg));
3,064✔
2109
      }
2110
      else {
2111
         vcode_reg_t one_reg = emit_const(vtype_offset(), 1);
366✔
2112
         elems = emit_add(elems, one_reg);
366✔
2113
         len   = emit_add(len, one_reg);
366✔
2114
      }
2115
   }
2116

2117
   vcode_reg_t mem_reg;
1,251✔
2118
   if (hint != VCODE_INVALID_REG && len == hint_count)
1,251✔
2119
      mem_reg = hint;
2120
   else
2121
      mem_reg = emit_alloc(lower_type(scalar_elem),
1,185✔
2122
                           lower_bounds(scalar_elem), len);
2123

2124
   vcode_reg_t cast_reg   = emit_cast(itype, ibounds, elems);
1,251✔
2125
   vcode_reg_t right_to   = emit_add(left, cast_reg);
1,251✔
2126
   vcode_reg_t right_down = emit_sub(left, cast_reg);
1,251✔
2127
   vcode_reg_t right      = emit_select(dir, right_down, right_to);
1,251✔
2128

2129
   vcode_dim_t dims[1] = { { left, right, dir } };
1,251✔
2130
   vcode_reg_t var_reg = emit_wrap(mem_reg, dims, 1);
1,251✔
2131

2132
   vcode_reg_t off_reg = emit_const(voffset, 0);
1,251✔
2133
   for (unsigned i = 0; i < args.count; i++) {
4,681✔
2134
      concat_param_t *p = &(args.items[i]);
3,430✔
2135
      vcode_reg_t ptr = emit_array_ref(mem_reg, off_reg);
3,430✔
2136
      if (type_is_array(p->type)) {
3,430✔
2137
         vcode_reg_t src_len = lower_array_total_len(lu, p->type, p->reg);
3,067✔
2138

2139
         vcode_reg_t data_reg;
3,067✔
2140
         if (lower_have_signal(p->reg))
3,067✔
2141
            data_reg = lower_array_data(lower_resolved(lu, p->type, p->reg));
×
2142
         else
2143
            data_reg = lower_array_data(p->reg);
3,067✔
2144

2145
         emit_copy(ptr, data_reg, src_len);
3,067✔
2146
         if (i + 1 < args.count)
3,067✔
2147
            off_reg = emit_add(off_reg, src_len);
1,912✔
2148
      }
2149
      else if (type_is_record(p->type)) {
363✔
2150
         emit_copy(ptr, p->reg, VCODE_INVALID_REG);
12✔
2151
         if (i + 1 < args.count)
12✔
2152
            off_reg = emit_add(off_reg, emit_const(vtype_offset(), 1));
6✔
2153
      }
2154
      else {
2155
         emit_store_indirect(p->reg, ptr);
351✔
2156
         if (i + 1 < args.count)
351✔
2157
            off_reg = emit_add(off_reg, emit_const(vtype_offset(), 1));
261✔
2158
      }
2159
   }
2160

2161
   ACLEAR(args);
1,251✔
2162
   return var_reg;
1,251✔
2163
}
2164

2165
static vcode_reg_t lower_comparison(lower_unit_t *lu, tree_t fcall,
17,453✔
2166
                                    subprogram_kind_t builtin,
2167
                                    vcode_reg_t r0, vcode_reg_t r1)
2168
{
2169
   vcode_cmp_t cmp;
17,453✔
2170
   switch (builtin) {
17,453✔
2171
   case S_SCALAR_EQ:  cmp = VCODE_CMP_EQ; break;
2172
   case S_SCALAR_NEQ: cmp = VCODE_CMP_NEQ; break;
2173
   case S_SCALAR_LT:  cmp = VCODE_CMP_LT; break;
2174
   case S_SCALAR_GT:  cmp = VCODE_CMP_GT; break;
2175
   case S_SCALAR_LE:  cmp = VCODE_CMP_LEQ; break;
2176
   case S_SCALAR_GE:  cmp = VCODE_CMP_GEQ; break;
2177
   default:
×
2178
      fatal_trace("unhandled built-in comparison %d", builtin);
2179
   }
2180

2181
   vcode_reg_t result = emit_cmp(cmp, r0, r1);
17,453✔
2182
   return lower_logical(lu, fcall, result, r0, r1, builtin, 0);
17,453✔
2183
}
2184

2185
static vcode_reg_t lower_builtin(lower_unit_t *lu, tree_t fcall,
45,908✔
2186
                                 subprogram_kind_t builtin,
2187
                                 vcode_reg_t *out_r0, vcode_reg_t *out_r1)
2188
{
2189
   if (builtin == S_SCALAR_AND || builtin == S_SCALAR_OR ||
45,908✔
2190
       builtin == S_SCALAR_NOR || builtin == S_SCALAR_NAND)
45,908✔
2191
      return lower_short_circuit(lu, fcall, builtin);
5,019✔
2192
   else if (builtin == S_CONCAT)
40,889✔
2193
      return lower_concat(lu, fcall, VCODE_INVALID_REG, VCODE_INVALID_REG);
1,170✔
2194

2195
   vcode_reg_t r0 = lower_subprogram_arg(lu, fcall, 0);
39,719✔
2196
   vcode_reg_t r1 = lower_subprogram_arg(lu, fcall, 1);
39,719✔
2197

2198
   if (out_r0 != NULL) *out_r0 = r0;
39,719✔
2199
   if (out_r1 != NULL) *out_r1 = r1;
39,719✔
2200

2201
   type_t r0_type = lower_arg_type(fcall, 0);
39,719✔
2202
   type_t r1_type = lower_arg_type(fcall, 1);
39,719✔
2203

2204
   switch (builtin) {
39,719✔
2205
   case S_SCALAR_EQ:
17,453✔
2206
   case S_SCALAR_NEQ:
2207
   case S_SCALAR_LT:
2208
   case S_SCALAR_GT:
2209
   case S_SCALAR_LE:
2210
   case S_SCALAR_GE:
2211
      return lower_comparison(lu, fcall, builtin, r0, r1);
17,453✔
2212
   case S_MOD:
1,229✔
2213
   case S_REM:
2214
   case S_DIV:
2215
      if (type_is_integer(r1_type)) {
1,229✔
2216
         vcode_reg_t locus = lower_debug_locus(fcall);
1,006✔
2217
         emit_zero_check(r1, locus);
1,006✔
2218
      }
2219
      // Fall-through
2220
   case S_MUL:
2221
   case S_ADD:
2222
   case S_SUB:
2223
      return lower_arith(fcall, builtin, r0, r1);
12,146✔
2224
   case S_EXP:
895✔
2225
      {
2226
         if (type_is_integer(r0_type)) {
895✔
2227
            vcode_reg_t locus = lower_debug_locus(fcall);
816✔
2228
            emit_exponent_check(r1, locus);
816✔
2229
         }
2230

2231
         if (!type_eq(r0_type, r1_type))
895✔
2232
            r1 = emit_cast(lower_type(r0_type), lower_bounds(r0_type), r1);
98✔
2233

2234
         return lower_arith(fcall, S_EXP, r0, r1);
895✔
2235
      }
2236
   case S_NEGATE:
6,727✔
2237
      {
2238
         if (type_is_integer(r0_type)) {
6,727✔
2239
            vcode_reg_t locus = lower_debug_locus(fcall);
785✔
2240
            return emit_trap_neg(r0, locus);
785✔
2241
         }
2242
         else
2243
            return emit_neg(r0);
5,942✔
2244
      }
2245
   case S_ABS:
237✔
2246
      return emit_abs(r0);
237✔
2247
   case S_IDENTITY:
2248
      return r0;
2249
   case S_SCALAR_NOT:
1,406✔
2250
      return lower_logical(lu, fcall, emit_not(r0), r0, 0, builtin, 0);
1,406✔
2251
   case S_SCALAR_XOR:
76✔
2252
      return lower_logical(lu, fcall, emit_xor(r0, r1), r0, r1, builtin, 0);
76✔
2253
   case S_SCALAR_XNOR:
55✔
2254
      return lower_logical(lu, fcall, emit_xnor(r0, r1), r0, r1, builtin, 0);
55✔
2255
   case S_FILE_OPEN1:
138✔
2256
      {
2257
         vcode_reg_t name   = lower_array_data(r1);
138✔
2258
         vcode_reg_t length = lower_array_len(lu, r1_type, 0, r1);
138✔
2259
         vcode_reg_t kind   = lower_subprogram_arg(lu, fcall, 2);
138✔
2260
         emit_file_open(r0, name, length, kind, VCODE_INVALID_REG);
138✔
2261
         return VCODE_INVALID_REG;
138✔
2262
      }
2263
   case S_FILE_OPEN2:
22✔
2264
      {
2265
         type_t arg_type = lower_arg_type(fcall, 2);
22✔
2266
         vcode_reg_t r2     = lower_subprogram_arg(lu, fcall, 2);
22✔
2267
         vcode_reg_t name   = lower_array_data(r2);
22✔
2268
         vcode_reg_t length = lower_array_len(lu, arg_type, 0, r2);
22✔
2269
         vcode_reg_t kind   = lower_subprogram_arg(lu, fcall, 3);
22✔
2270
         emit_file_open(r1, name, length, kind, r0);
22✔
2271
         return VCODE_INVALID_REG;
22✔
2272
      }
2273
   case S_FILE_WRITE:
125✔
2274
      {
2275
         vcode_reg_t length = VCODE_INVALID_REG;
125✔
2276
         vcode_reg_t data   = r1;
125✔
2277
         if (type_is_array(r1_type)) {
125✔
2278
            length = lower_array_total_len(lu, r1_type, r1);
68✔
2279
            data   = lower_array_data(r1);
68✔
2280
         }
2281
         emit_file_write(r0, data, length);
125✔
2282
         return VCODE_INVALID_REG;
125✔
2283
      }
2284
   case S_FILE_READ:
75✔
2285
      {
2286
         vcode_reg_t inlen = VCODE_INVALID_REG;
75✔
2287
         if (type_is_array(r1_type))
75✔
2288
            inlen = lower_array_total_len(lu, r1_type, r1);
27✔
2289

2290
         vcode_reg_t outlen = VCODE_INVALID_REG;
75✔
2291
         if (tree_params(fcall) == 3)
75✔
2292
            outlen = lower_subprogram_arg(lu, fcall, 2);
18✔
2293

2294
         emit_file_read(r0, r1, inlen, outlen);
75✔
2295
         return VCODE_INVALID_REG;
75✔
2296
      }
2297
   case S_DEALLOCATE:
207✔
2298
      emit_deallocate(r0);
207✔
2299
      return VCODE_INVALID_REG;
207✔
2300
   case S_MUL_RP:
4✔
2301
   case S_MUL_RI:
2302
      {
2303
         vcode_type_t vreal = vtype_real(-DBL_MAX, DBL_MAX);
4✔
2304
         vcode_type_t rtype = lower_type(tree_type(fcall));
4✔
2305
         return emit_cast(rtype, rtype,
4✔
2306
                          emit_mul(r0, emit_cast(vreal, vreal, r1)));
2307
      }
2308
   case S_MUL_PR:
7✔
2309
   case S_MUL_IR:
2310
      {
2311
         vcode_type_t vreal = vtype_real(-DBL_MAX, DBL_MAX);
7✔
2312
         vcode_type_t rtype = lower_type(tree_type(fcall));
7✔
2313
         return emit_cast(rtype, rtype,
7✔
2314
                          emit_mul(emit_cast(vreal, vreal, r0), r1));
2315
      }
2316
   case S_MUL_IP:
53✔
2317
      {
2318
         vcode_type_t rtype = lower_type(tree_type(fcall));
53✔
2319
         vcode_reg_t cast_reg = emit_cast(rtype, rtype, r0);
53✔
2320
         return emit_mul(cast_reg, r1);
53✔
2321
      }
2322
   case S_MUL_PI:
18✔
2323
      {
2324
         vcode_type_t rtype = lower_type(tree_type(fcall));
18✔
2325
         vcode_reg_t cast_reg = emit_cast(rtype, rtype, r1);
18✔
2326
         return emit_mul(r0, cast_reg);
18✔
2327
      }
2328
   case S_DIV_PR:
7✔
2329
      {
2330
         vcode_type_t vreal = vtype_real(-DBL_MAX, DBL_MAX);
7✔
2331
         vcode_type_t rtype = lower_type(tree_type(fcall));
7✔
2332
         return emit_cast(rtype, rtype,
7✔
2333
                          emit_div(emit_cast(vreal, vreal, r0), r1));
2334
      }
2335
   case S_DIV_RI:
1✔
2336
      {
2337
         vcode_type_t vreal = vtype_real(-DBL_MAX, DBL_MAX);
1✔
2338
         vcode_type_t rtype = lower_type(tree_type(fcall));
1✔
2339
         vcode_reg_t locus = lower_debug_locus(fcall);
1✔
2340
         emit_zero_check(r1, locus);
1✔
2341
         return emit_cast(rtype, rtype,
1✔
2342
                          emit_div(r0, emit_cast(vreal, vreal, r1)));
2343
      }
2344
   case S_DIV_PP:
12✔
2345
      {
2346
         vcode_reg_t locus = lower_debug_locus(fcall);
12✔
2347
         emit_zero_check(r1, locus);
12✔
2348
         vcode_reg_t div_reg = emit_div(r0, r1);
12✔
2349
         vcode_type_t rtype = lower_type(tree_type(fcall));
12✔
2350
         return emit_cast(rtype, rtype, div_reg);
12✔
2351
      }
2352
   case S_DIV_PI:
48✔
2353
      {
2354
         vcode_reg_t locus = lower_debug_locus(fcall);
48✔
2355
         emit_zero_check(r1, locus);
48✔
2356
         vcode_type_t rtype = lower_type(tree_type(fcall));
48✔
2357
         vcode_reg_t cast_reg = emit_cast(rtype, rtype, r1);
48✔
2358
         return emit_div(r0, cast_reg);
48✔
2359
      }
2360
   default:
×
2361
      fatal_at(tree_loc(fcall), "cannot lower builtin %d", builtin);
×
2362
   }
2363
}
2364

2365
static vcode_type_t lower_func_result_type(type_t result)
52,568✔
2366
{
2367
   if (type_is_array(result) && type_const_bounds(result))
52,568✔
2368
      return vtype_pointer(lower_type(type_elem_recur(result)));
443✔
2369
   else if (type_is_record(result))
52,125✔
2370
      return vtype_pointer(lower_type(result));
1,848✔
2371
   else
2372
      return lower_type(result);
50,277✔
2373
}
2374

2375
static vcode_type_t lower_param_type(type_t type, class_t class,
18,353✔
2376
                                     port_mode_t mode)
2377
{
2378
   switch (class) {
18,353✔
2379
   case C_SIGNAL:
665✔
2380
      if (type_is_homogeneous(type))
665✔
2381
         return lower_signal_type(type);
229✔
2382
      else if (type_is_array(type)) {
436✔
2383
         if (type_const_bounds(type))
113✔
2384
            return vtype_pointer(lower_signal_type(type_elem_recur(type)));
9✔
2385
         else
2386
            return lower_signal_type(type);
104✔
2387
      }
2388
      else
2389
         return vtype_pointer(lower_signal_type(type));
323✔
2390

2391
   case C_VARIABLE:
17,568✔
2392
   case C_DEFAULT:
2393
   case C_CONSTANT:
2394
      {
2395
         if (type_is_array(type)) {
17,568✔
2396
            if (type_const_bounds(type))
9,311✔
2397
               return vtype_pointer(lower_type(type_elem_recur(type)));
197✔
2398
            else
2399
               return lower_type(type);
9,114✔
2400
         }
2401
         else if (type_is_record(type))
8,257✔
2402
            return vtype_pointer(lower_type(type));
1,047✔
2403
         else if (mode == PORT_OUT || mode == PORT_INOUT)
7,210✔
2404
            return vtype_pointer(lower_type(type));
910✔
2405
         else
2406
            return lower_type(type);
6,300✔
2407
      }
2408
      break;
120✔
2409

2410
   case C_FILE:
120✔
2411
      return vtype_pointer(lower_type(type));
120✔
2412

2413
   default:
×
2414
      fatal_trace("unhandled class %s in lower_param_type", class_str(class));
2415
   }
2416
}
2417

2418
static vcode_reg_t lower_context_for_call(lower_unit_t *lu, ident_t unit_name)
38,479✔
2419
{
2420
   // XXX: this should call unit_registery_get_parent
2421
   if (lu->registry != NULL && unit_registry_query(lu->registry, unit_name)) {
38,479✔
2422
      vcode_unit_t vu = unit_registry_get(lu->registry, unit_name);
21,357✔
2423

2424
      vcode_unit_t context = vcode_unit_context(vu);
21,357✔
2425
      assert(context != NULL);
21,357✔
2426

2427
      vcode_unit_t ancestor = lu->vunit;
21,357✔
2428
      int hops = 0;
21,357✔
2429
      for (; ancestor && ancestor != context;
47,535✔
2430
           hops++, ancestor = vcode_unit_context(ancestor))
26,178✔
2431
         ;
2432

2433
      if (ancestor != NULL)
21,357✔
2434
         return emit_context_upref(hops);
15,479✔
2435
      else if (vcode_unit_kind(context) == VCODE_UNIT_PACKAGE) {
5,878✔
2436
         ident_t context_name = vcode_unit_name(context);
5,877✔
2437
         if (vcode_unit_kind(lu->vunit) == VCODE_UNIT_THUNK)
5,877✔
2438
            return emit_package_init(context_name, VCODE_INVALID_REG);
877✔
2439
         else
2440
            return emit_link_package(context_name);
5,000✔
2441
      }
2442
   }
2443

2444
   int hops = 0;
17,123✔
2445
   for (vcode_unit_t it = lu->vunit; ; hops++) {
17,123✔
2446
      ident_t this = vcode_unit_name(it);
33,371✔
2447
      assert(this != unit_name);
33,371✔
2448
      if (ident_starts_with(unit_name, this)
33,371✔
2449
          && ident_char(unit_name, ident_len(this)) == '.')
2✔
2450
         return emit_context_upref(hops);
×
2451

2452
      vcode_unit_t context = vcode_unit_context(it);
33,371✔
2453
      if (context == NULL)
33,371✔
2454
         break;
2455

2456
      it = context;
16,248✔
2457
   }
2458

2459
   ident_t it = unit_name;
17,123✔
2460
   ident_t lname = ident_walk_selected(&it);
17,123✔
2461
   ident_t uname = ident_walk_selected(&it);
17,123✔
2462

2463
   lib_t lib = lib_require(lname);
17,123✔
2464

2465
   ident_t base_name = ident_prefix(lname, uname, '.');
17,123✔
2466
   tree_t unit = lib_get(lib, base_name);
17,123✔
2467
   if (unit == NULL)
17,123✔
2468
      fatal_trace("cannot find unit for %s", istr(unit_name));
2469

2470
   const tree_kind_t kind = tree_kind(unit);
17,123✔
2471
   if (kind == T_ENTITY || kind == T_ARCH) {
17,123✔
2472
      // Call to function defined in architecture
2473
      return emit_null(vtype_context(unit_name));
1✔
2474
   }
2475

2476
   assert(is_package(unit));
17,122✔
2477
   assert(!is_uninstantiated_package(unit));
17,122✔
2478

2479
   vcode_reg_t pack_reg;
17,122✔
2480
   if (vcode_unit_kind(lu->vunit) == VCODE_UNIT_THUNK)
17,122✔
2481
      pack_reg = emit_package_init(base_name, VCODE_INVALID_REG);
2,194✔
2482
   else
2483
      pack_reg = emit_link_package(base_name);
14,928✔
2484

2485
   for (;;) {
3✔
2486
      // Context package may be nested inside another package
2487
      ident_t var_name = ident_walk_selected(&it);
17,125✔
2488
      if (it == NULL || ident_pos(var_name, '(') != -1)
17,125✔
2489
         return pack_reg;
17,122✔
2490

2491
      ident_t qual = ident_prefix(base_name, var_name, '.');
3✔
2492
      vcode_reg_t var_reg = emit_link_var(pack_reg, qual, vtype_context(qual));
3✔
2493
      pack_reg = emit_load_indirect(var_reg);
3✔
2494
      base_name = qual;
3✔
2495
   }
2496
}
2497

2498
static vcode_reg_t lower_fcall(lower_unit_t *lu, tree_t fcall,
65,978✔
2499
                               vcode_reg_t bounds_reg)
2500
{
2501
   tree_t decl = tree_ref(fcall);
65,978✔
2502

2503
   const subprogram_kind_t kind = tree_subkind(decl);
65,978✔
2504
   if (is_open_coded_builtin(kind))
65,978✔
2505
      return lower_builtin(lu, fcall, kind, NULL, NULL);
39,455✔
2506

2507
   const int nparams = tree_params(fcall);
26,523✔
2508
   SCOPED_A(vcode_reg_t) args = AINIT;
53,046✔
2509

2510
   ident_t name = tree_ident2(decl);
26,523✔
2511

2512
   if (tree_kind(fcall) == T_PROT_FCALL && tree_has_name(fcall))
26,523✔
2513
      APUSH(args, lower_rvalue(lu, tree_name(fcall)));
780✔
2514
   else
2515
      APUSH(args, lower_context_for_call(lu, name));
25,743✔
2516

2517
   for (int i = 0; i < nparams; i++) {
76,387✔
2518
      vcode_reg_t arg_reg = lower_subprogram_arg(lu, fcall, i);
49,864✔
2519
      APUSH(args, arg_reg);
49,864✔
2520
   }
2521

2522
   if (bounds_reg != VCODE_INVALID_REG)
26,523✔
2523
      APUSH(args, bounds_reg);
39✔
2524

2525
   type_t result = tree_type(fcall);
26,523✔
2526
   vcode_type_t rtype = lower_func_result_type(result);
26,523✔
2527
   vcode_type_t rbounds = lower_bounds(result);
26,523✔
2528

2529
   if (cover_enabled(lu->cover, COVER_MASK_EXPRESSION))
26,523✔
2530
      lower_logic_expr_coverage(lu, fcall, args.items);
121✔
2531

2532
   return emit_fcall(name, rtype, rbounds, args.items, args.count);
26,523✔
2533
}
2534

2535
static vcode_reg_t lower_known_subtype(lower_unit_t *lu, tree_t value,
12,151✔
2536
                                       type_t type, vcode_reg_t bounds_reg)
2537
{
2538
   if (tree_kind(value) != T_FCALL)
12,151✔
2539
      return lower_rvalue(lu, value);
7,783✔
2540

2541
   tree_t decl = tree_ref(value);
4,368✔
2542
   if (!(tree_flags(decl) & TREE_F_KNOWS_SUBTYPE))
4,368✔
2543
      return lower_rvalue(lu, value);
4,329✔
2544

2545
   if (type_is_array(type)) {
39✔
2546
      if (bounds_reg == VCODE_INVALID_REG
21✔
2547
          || vcode_reg_kind(bounds_reg) != VCODE_TYPE_UARRAY) {
15✔
2548
         vcode_type_t velem = lower_type(type_elem_recur(type));
21✔
2549
         vcode_reg_t null_reg = emit_null(vtype_pointer(velem));
21✔
2550
         bounds_reg = lower_wrap(lu, type, null_reg);
21✔
2551
      }
2552
   }
2553
   else if (type_is_record(type)) {
18✔
2554
      if (bounds_reg == VCODE_INVALID_REG) {
18✔
2555
         // This is inefficient but should only occur in declarations
2556
         bounds_reg = lower_default_value(lu, type, VCODE_INVALID_REG);
6✔
2557
      }
2558
      else if (vtype_is_signal(vcode_reg_type(bounds_reg)))
12✔
2559
         bounds_reg = lower_resolved(lu, type, bounds_reg);
6✔
2560
   }
2561

2562
   return lower_fcall(lu, value, bounds_reg);
39✔
2563
}
2564

2565
static vcode_reg_t *lower_string_literal_chars(tree_t lit, int *nchars)
20,434✔
2566
{
2567
   type_t ltype = tree_type(lit);
20,434✔
2568
   vcode_type_t vtype = lower_type(type_elem(ltype));
20,434✔
2569

2570
   *nchars = tree_chars(lit);
20,434✔
2571
   vcode_reg_t *tmp = xmalloc_array(*nchars, sizeof(vcode_reg_t));
20,434✔
2572

2573
   for (int i = 0; i < *nchars; i++)
277,141✔
2574
      tmp[i] = emit_const(vtype, assume_int(tree_char(lit, i)));
256,707✔
2575

2576
   return tmp;
20,434✔
2577
}
2578

2579
static vcode_reg_t lower_string_literal(tree_t lit, bool nest)
20,052✔
2580
{
2581
   int nchars;
20,052✔
2582
   vcode_reg_t *tmp LOCAL = lower_string_literal_chars(lit, &nchars);
40,104✔
2583

2584
   type_t type = tree_type(lit);
20,052✔
2585
   vcode_type_t elem = lower_type(type_elem(type));
20,052✔
2586
   vcode_type_t array_type = vtype_carray(nchars, elem, elem);
20,052✔
2587

2588
   vcode_reg_t array_reg = emit_const_array(array_type, tmp, nchars);
20,052✔
2589

2590
   if (type_is_array(type) && !type_const_bounds(type)) {
20,052✔
2591
      vcode_dim_t dim0 = {
×
2592
         .left  = emit_const(vtype_offset(), 1),
×
2593
         .right = emit_const(vtype_offset(), nchars),
×
2594
         .dir   = emit_const(vtype_bool(), RANGE_TO)
×
2595
      };
2596
      return emit_wrap(emit_address_of(array_reg), &dim0, 1);
×
2597
   }
2598
   else if (nest)
20,052✔
2599
      return array_reg;
2600
   else
2601
      return emit_address_of(array_reg);
19,740✔
2602
}
2603

2604
static vcode_reg_t lower_literal(tree_t lit)
178,947✔
2605
{
2606
   switch (tree_subkind(lit)) {
178,947✔
2607
   case L_PHYSICAL:
7,809✔
2608
      assert(!tree_has_ref(lit));
7,809✔
2609
      // Fall-through
2610
   case L_INT:
2611
      return emit_const(lower_type(tree_type(lit)), tree_ival(lit));
152,512✔
2612

2613
   case L_NULL:
132✔
2614
      return emit_null(lower_type(tree_type(lit)));
132✔
2615

2616
   case L_REAL:
26,303✔
2617
      return emit_const_real(lower_type(tree_type(lit)), tree_dval(lit));
26,303✔
2618

2619
   default:
×
2620
      fatal_at(tree_loc(lit), "cannot lower literal kind %d",
×
2621
               tree_subkind(lit));
2622
   }
2623
}
2624

2625
int lower_search_vcode_obj(void *key, lower_unit_t *scope, int *hops)
156,760✔
2626
{
2627
   *hops = 0;
156,760✔
2628
   for (; scope != NULL; scope = scope->parent) {
233,554✔
2629
      const void *ptr = hash_get(scope->objects, key);
227,930✔
2630
      const int obj = (uintptr_t)ptr - 1;
227,930✔
2631
      if (obj != VCODE_INVALID_REG)
227,930✔
2632
         return obj;
151,136✔
2633
      (*hops)++;
76,794✔
2634
   }
2635

2636
   *hops = 0;
5,624✔
2637
   return VCODE_INVALID_REG;
5,624✔
2638
}
2639

2640
void lower_put_vcode_obj(void *key, int obj, lower_unit_t *scope)
60,520✔
2641
{
2642
   hash_put(scope->objects, key, (void *)(uintptr_t)(obj + 1));
60,520✔
2643
}
60,520✔
2644

2645
static vcode_var_t lower_get_var(lower_unit_t *lu, tree_t decl, int *hops)
58,542✔
2646
{
2647
   return lower_search_vcode_obj(decl, lu, hops);
58,542✔
2648
}
2649

2650
static vcode_reg_t lower_get_type_bounds(lower_unit_t *lu, type_t type)
7,022✔
2651
{
2652
   assert(!type_is_unconstrained(type));
7,022✔
2653

2654
   if (type_is_record(type))
7,022✔
2655
      return VCODE_INVALID_REG;  // TODO
2656
   else if (type_is_scalar(type)) {
6,864✔
2657
      vcode_reg_t left_reg, right_reg, dir_reg;
496✔
2658
      lower_get_scalar_type_bounds(lu, type, &left_reg, &right_reg, &dir_reg);
496✔
2659

2660
      vcode_dim_t dims[1] = { { left_reg, right_reg, dir_reg } };
496✔
2661

2662
      vcode_reg_t null_reg = emit_null(vtype_pointer(lower_type(type)));
496✔
2663
      return emit_wrap(null_reg, dims, 1);
496✔
2664
   }
2665
   else if (type_has_ident(type)) {
6,368✔
2666
      int hops = 0;
1,155✔
2667
      vcode_var_t var = lower_search_vcode_obj(type, lu, &hops);
1,155✔
2668
      if (var == VCODE_INVALID_VAR) {
1,155✔
2669
         // Type or subtype declared in package
2670
         ident_t id = type_ident(type);
32✔
2671
         vcode_reg_t context = emit_link_package(ident_runtil(id, '.'));
32✔
2672
         vcode_reg_t ptr_reg = emit_link_var(context, id, lower_type(type));
32✔
2673
         return emit_load_indirect(ptr_reg);
32✔
2674
      }
2675
      else if (hops == 0)
1,123✔
2676
         return emit_load(var);
855✔
2677
      else {
2678
         vcode_reg_t ptr_reg = emit_var_upref(hops, var);
268✔
2679
         return emit_load_indirect(ptr_reg);
268✔
2680
      }
2681
   }
2682
   else {
5,213✔
2683
      vcode_type_t vtype = lower_type(type);
5,213✔
2684
      assert(vtype_kind(vtype) == VCODE_TYPE_UARRAY);
5,213✔
2685

2686
      const int ndims = vtype_dims(vtype);
5,213✔
2687
      int dptr = 0;
5,213✔
2688
      vcode_dim_t dims[ndims];
5,213✔
2689

2690
      const int tdims = dimension_of(type);
5,213✔
2691
      for (int i = 0; i < tdims; i++, dptr++) {
10,447✔
2692
         tree_t r = range_of(type, i);
5,234✔
2693
         dims[dptr].left  = lower_range_left(lu, r);
5,234✔
2694
         dims[dptr].right = lower_range_right(lu, r);
5,234✔
2695
         dims[dptr].dir   = lower_range_dir(lu, r);
5,234✔
2696
      }
2697

2698
      if (dptr < ndims) {
5,213✔
2699
         type_t elem = type_elem(type);
41✔
2700
         vcode_reg_t bounds_reg = lower_get_type_bounds(lu, elem);
41✔
2701
         assert(dptr + vtype_dims(vcode_reg_type(bounds_reg)) == ndims);
41✔
2702

2703
         for (int i = 0; dptr < ndims; i++, dptr++) {
82✔
2704
            dims[dptr].left  = emit_uarray_left(bounds_reg, i);
41✔
2705
            dims[dptr].right = emit_uarray_right(bounds_reg, i);
41✔
2706
            dims[dptr].dir   = emit_uarray_dir(bounds_reg, i);
41✔
2707
         }
2708
      }
2709

2710
      vcode_reg_t null_reg = emit_null(vtype_pointer(vtype_elem(vtype)));
5,213✔
2711
      return emit_wrap(null_reg, dims, ndims);
5,213✔
2712
   }
2713
}
2714

2715
static vcode_type_t lower_var_type(tree_t decl)
5,129✔
2716
{
2717
   if (tree_kind(decl) == T_ALIAS)
5,129✔
2718
      return lower_alias_type(decl);
10✔
2719
   else {
2720
      type_t type = tree_type(decl);
5,119✔
2721
      if (class_of(decl) == C_SIGNAL)
5,119✔
2722
         return lower_signal_type(type);
2,257✔
2723
      else if (type_is_array(type) && type_const_bounds(type))
2,862✔
2724
         return lower_type(type_elem_recur(type));
1,766✔
2725
      else
2726
         return lower_type(type);
1,096✔
2727
   }
2728
}
2729

2730
static vcode_reg_t lower_link_var(lower_unit_t *lu, tree_t decl)
5,091✔
2731
{
2732
   tree_t container = tree_container(decl);
5,091✔
2733
   const tree_kind_t kind = tree_kind(container);
5,091✔
2734
   vcode_reg_t context = VCODE_INVALID_REG;
5,091✔
2735
   vcode_type_t vtype = lower_var_type(decl);
5,091✔
2736

2737
   if (kind != T_PACKAGE && kind != T_PACK_INST) {
5,091✔
2738
      if (lu->mode == LOWER_THUNK)
1,442✔
2739
         return emit_undefined(vtype_pointer(vtype), vtype);
1,442✔
2740
      else {
2741
         vcode_dump();
×
2742
         fatal_trace("invalid container kind %s for %s", tree_kind_str(kind),
2743
                     istr(tree_ident(decl)));
2744
      }
2745
   }
2746
   else if (lu->mode == LOWER_THUNK && container == lu->container) {
3,649✔
2747
      // Must avoid circular references to the current package but for
2748
      // simple constants we can just regenerate the value inline
2749
      assert(tree_kind(decl) == T_CONST_DECL);
9✔
2750

2751
      if (tree_has_value(decl)) {
9✔
2752
         tree_t value = tree_value(decl);
9✔
2753
         if (lower_is_const(value))
9✔
2754
            return lower_rvalue(lu, value);
9✔
2755
      }
2756

2757
      return emit_undefined(vtype_pointer(vtype), vtype);
×
2758
   }
2759

2760
   assert(!is_uninstantiated_package(container));
3,640✔
2761

2762
   if (lu->mode == LOWER_THUNK)
3,640✔
2763
      context = emit_package_init(tree_ident(container), VCODE_INVALID_REG);
33✔
2764
   else
2765
      context = emit_link_package(tree_ident(container));
3,607✔
2766

2767
   return emit_link_var(context, tree_ident(decl), vtype);
3,640✔
2768
}
2769

2770
static vcode_reg_t lower_var_ref(lower_unit_t *lu, tree_t decl, expr_ctx_t ctx)
48,008✔
2771
{
2772
   type_t type = tree_type(decl);
48,008✔
2773

2774
   vcode_reg_t ptr_reg = VCODE_INVALID_REG;
48,008✔
2775
   int hops = 0;
48,008✔
2776
   vcode_var_t var = lower_get_var(lu, decl, &hops);
48,008✔
2777
   if (var == VCODE_INVALID_VAR)
48,008✔
2778
      ptr_reg = lower_link_var(lu, decl);   // External variable
2,824✔
2779
   else if (var & INSTANCE_BIT) {
45,184✔
2780
      // This variable is declared in an instantiated package
2781
      vcode_var_t pkg_var = var & ~INSTANCE_BIT;
25✔
2782
      vcode_reg_t pkg_reg;
25✔
2783
      if (hops == 0)
25✔
2784
         pkg_reg = emit_load(pkg_var);
1✔
2785
      else
2786
         pkg_reg = emit_load_indirect(emit_var_upref(hops, pkg_var));
24✔
2787

2788
      vcode_type_t vtype = lower_var_type(decl);
25✔
2789
      ptr_reg = emit_link_var(pkg_reg, tree_ident(decl), vtype);
25✔
2790
   }
2791
   else if (hops > 0)
45,159✔
2792
      ptr_reg = emit_var_upref(hops, var);
4,831✔
2793

2794
   if (ptr_reg != VCODE_INVALID_REG) {
7,680✔
2795
      if (ctx == EXPR_LVALUE)
7,680✔
2796
         return ptr_reg;
2797
      else if (type_is_scalar(type))
6,985✔
2798
         return emit_load_indirect(ptr_reg);
1,538✔
2799
      else if (have_uarray_ptr(ptr_reg))
5,447✔
2800
         return emit_load_indirect(ptr_reg);
683✔
2801
      else
2802
         return ptr_reg;
2803
   }
2804
   else if (type_is_array(type) && type_const_bounds(type))
40,328✔
2805
      return emit_index(var, VCODE_INVALID_REG);
8,467✔
2806
   else if (type_is_record(type) || type_is_protected(type))
31,861✔
2807
      return emit_index(var, VCODE_INVALID_REG);
2,382✔
2808
   else if ((type_is_scalar(type) || type_is_file(type) || type_is_access(type))
29,479✔
2809
            && ctx == EXPR_LVALUE)
18,801✔
2810
      return emit_index(var, VCODE_INVALID_REG);
2,943✔
2811
   else
2812
      return emit_load(var);
26,536✔
2813
}
2814

2815
static vcode_reg_t lower_signal_ref(lower_unit_t *lu, tree_t decl)
30,593✔
2816
{
2817
   int hops = 0;
30,593✔
2818
   vcode_var_t var = lower_search_vcode_obj(decl, lu, &hops);
30,593✔
2819

2820
   vcode_reg_t ptr_reg;
30,593✔
2821
   if (var == VCODE_INVALID_VAR) {
30,593✔
2822
      // Link to external package signal
2823
      ptr_reg = lower_link_var(lu, decl);
2,257✔
2824
   }
2825
   else if (var & INSTANCE_BIT) {
28,336✔
2826
      // This signal is declared in an instantiated package
2827
      vcode_var_t pkg_var = var & ~INSTANCE_BIT;
45✔
2828
      vcode_reg_t pkg_reg;
45✔
2829
      if (hops == 0)
45✔
2830
         pkg_reg = emit_load(pkg_var);
×
2831
      else
2832
         pkg_reg = emit_load_indirect(emit_var_upref(hops, pkg_var));
45✔
2833

2834
      vcode_type_t vtype = lower_signal_type(tree_type(decl));
45✔
2835
      ptr_reg = emit_link_var(pkg_reg, tree_ident(decl), vtype);
45✔
2836
   }
2837
   else if (hops == 0 && vtype_is_scalar(vcode_var_type(var)))
28,291✔
2838
      return emit_load(var);
69✔
2839
   else if (hops == 0)
28,222✔
2840
      ptr_reg = emit_index(var, VCODE_INVALID_REG);
12✔
2841
   else
2842
      ptr_reg = emit_var_upref(hops, var);
28,210✔
2843

2844
   if (!vtype_is_scalar(vtype_pointed(vcode_reg_type(ptr_reg))))
30,524✔
2845
      return ptr_reg;
2846

2847
   return emit_load_indirect(ptr_reg);
27,627✔
2848
}
2849

2850
static vcode_reg_t lower_port_ref(lower_unit_t *lu, tree_t decl)
17,902✔
2851
{
2852
   int hops = 0;
17,902✔
2853
   vcode_var_t var = lower_search_vcode_obj(decl, lu, &hops);
17,902✔
2854
   if (var == VCODE_INVALID_VAR) {
17,902✔
2855
      vcode_dump();
×
2856
      fatal_trace("missing variable for port %s", istr(tree_ident(decl)));
2857
   }
2858

2859
   if (hops == 0 && vtype_is_scalar(vcode_var_type(var)))
17,902✔
2860
      return emit_load(var);
674✔
2861

2862
   vcode_reg_t ptr_reg;
17,228✔
2863
   if (hops == 0)
17,228✔
2864
      ptr_reg = emit_index(var, VCODE_INVALID_REG);
426✔
2865
   else
2866
      ptr_reg = emit_var_upref(hops, var);
16,802✔
2867

2868
   if (!vtype_is_scalar(vtype_pointed(vcode_reg_type(ptr_reg))))
17,228✔
2869
      return ptr_reg;
2870

2871
   return emit_load_indirect(ptr_reg);
15,479✔
2872
}
2873

2874
static vcode_reg_t lower_param_ref(lower_unit_t *lu, tree_t decl)
37,280✔
2875
{
2876
   int hops = 0;
37,280✔
2877
   int obj = lower_search_vcode_obj(decl, lu, &hops);
37,280✔
2878

2879
   const bool is_proc_var = (obj != -1 && !!(obj & PARAM_VAR_BIT));
37,280✔
2880
   obj &= ~PARAM_VAR_BIT;
37,280✔
2881

2882
   if (hops > 0) {
37,280✔
2883
      // Reference to parameter in parent subprogram
2884
      return emit_load_indirect(emit_var_upref(hops, obj));
77✔
2885
   }
2886
   else if (is_proc_var)
37,203✔
2887
      return emit_load(obj);
1,941✔
2888
   else {
2889
      vcode_reg_t reg = obj;
35,262✔
2890
      const bool undefined_in_thunk =
70,524✔
2891
         lu->mode == LOWER_THUNK && (reg == VCODE_INVALID_REG
35,262✔
2892
                                     || tree_class(decl) == C_SIGNAL
×
2893
                                     || type_is_protected(tree_type(decl)));
×
2894
      if (undefined_in_thunk) {
35,262✔
2895
         type_t type = tree_type(decl);
×
2896
         emit_comment("Cannot resolve reference to %s", istr(tree_ident(decl)));
×
2897
         if (tree_class(decl) == C_SIGNAL)
×
2898
            return emit_undefined(lower_signal_type(type), lower_bounds(type));
×
2899
         else {
2900
            vcode_type_t vtype = lower_type(tree_type(decl));
×
2901
            if (vtype_kind(vtype) == VCODE_TYPE_RECORD)
×
2902
               return emit_undefined(vtype_pointer(vtype), lower_bounds(type));
×
2903
            else
2904
               return emit_undefined(vtype, lower_bounds(type));
×
2905
         }
2906
      }
2907
      else if (reg == VCODE_INVALID_REG) {
2908
         vcode_dump();
2909
         fatal_trace("missing register for parameter %s",
2910
                     istr(tree_ident(decl)));
2911
      }
2912

2913
      return reg;
2914
   }
2915
}
2916

2917
static vcode_reg_t lower_generic_ref(lower_unit_t *lu, tree_t decl,
3,140✔
2918
                                     expr_ctx_t ctx)
2919
{
2920
   type_t type = tree_type(decl);
3,140✔
2921

2922
   int hops = 0;
3,140✔
2923
   vcode_var_t var = lower_search_vcode_obj(decl, lu, &hops);
3,140✔
2924
   vcode_reg_t ptr_reg = VCODE_INVALID_REG;
3,140✔
2925

2926
   if (var == VCODE_INVALID_VAR) {
3,140✔
2927
      tree_t unit;
41✔
2928
      if (tree_kind((unit = tree_container(decl))) == T_PACK_INST) {
41✔
2929
         vcode_reg_t context = emit_link_package(tree_ident(unit));
26✔
2930
         ptr_reg = emit_link_var(context, tree_ident(decl), lower_type(type));
26✔
2931
      }
2932
      else if (lu->mode == LOWER_THUNK) {
15✔
2933
         type_t type = tree_type(decl);
15✔
2934
         emit_comment("Cannot resolve generic %s", istr(tree_ident(decl)));
15✔
2935
         return emit_undefined(lower_type(type), lower_bounds(type));
15✔
2936
      }
2937
      else {
2938
         vcode_dump();
×
2939
         fatal_trace("missing variable for generic %s in %s",
2940
                     istr(tree_ident(decl)), istr(tree_ident(unit)));
2941
      }
2942
   }
2943
   else if (var & INSTANCE_BIT) {
3,099✔
2944
      // This generic is declared in an instantiated package
2945
      vcode_var_t pkg_var = var & ~INSTANCE_BIT;
13✔
2946
      vcode_reg_t pkg_reg;
13✔
2947
      if (hops == 0)
13✔
2948
         pkg_reg = emit_load(pkg_var);
1✔
2949
      else
2950
         pkg_reg = emit_load_indirect(emit_var_upref(hops, pkg_var));
12✔
2951

2952
      vcode_type_t vtype = lower_var_type(decl);
13✔
2953
      ptr_reg = emit_link_var(pkg_reg, tree_ident(decl), vtype);
13✔
2954
   }
2955
   else if (hops > 0)
3,086✔
2956
      ptr_reg = emit_var_upref(hops, var);
1,505✔
2957

2958
   if (ptr_reg != VCODE_INVALID_REG) {
1,544✔
2959
      if (type_is_scalar(type))
1,544✔
2960
         return emit_load_indirect(ptr_reg);
1,085✔
2961
      else if (type_is_array(type) && !type_const_bounds(type))
459✔
2962
         return emit_load_indirect(ptr_reg);
208✔
2963
      else
2964
         return ptr_reg;
251✔
2965
   }
2966
   else if (type_is_array(type) && type_const_bounds(type))
1,581✔
2967
      return emit_index(var, VCODE_INVALID_REG);
7✔
2968
   else if (type_is_record(type) || type_is_protected(type))
1,574✔
2969
      return emit_index(var, VCODE_INVALID_REG);
98✔
2970
   else
2971
      return emit_load(var);
1,476✔
2972
}
2973

2974
static vcode_reg_t lower_alias_ref(lower_unit_t *lu, tree_t alias,
1,751✔
2975
                                   expr_ctx_t ctx)
2976
{
2977
   tree_t value = tree_value(alias);
1,751✔
2978
   type_t type = tree_type(tree_has_type(alias) ? alias : value);
1,999✔
2979

2980
   if (tree_kind(value) == T_EXTERNAL_NAME) {
1,751✔
2981
      // Elaborating the alias declaration already warmed the cache
2982
      int hops = 0;
90✔
2983
      vcode_var_t var = lower_search_vcode_obj(value, lu, &hops);
90✔
2984
      assert(var != VCODE_INVALID_VAR);
90✔
2985

2986
      vcode_reg_t ptr_reg;
90✔
2987
      if (hops == 0)
90✔
2988
         ptr_reg = emit_index(var, VCODE_INVALID_REG);
87✔
2989
      else
2990
         ptr_reg = emit_var_upref(hops, var);
3✔
2991

2992
      vcode_reg_t result_reg = emit_load_indirect(ptr_reg);
90✔
2993
      if (type_is_record(type))
90✔
2994
         return result_reg;
2995
      else
2996
         return emit_load_indirect(result_reg);
69✔
2997
   }
2998
   else if (!type_is_array(type))
1,661✔
2999
      return lower_expr(lu, value, ctx);
157✔
3000

3001
   int hops = 0;
1,504✔
3002
   vcode_var_t var = lower_get_var(lu, alias, &hops);
1,504✔
3003
   if (var == VCODE_INVALID_VAR) {
1,504✔
3004
      if (lu->mode == LOWER_THUNK)
10✔
3005
         return emit_undefined(lower_type(type), lower_bounds(type));
×
3006
      else {
3007
         // External alias variable
3008
         return lower_link_var(lu, alias);
10✔
3009
      }
3010
   }
3011
   else if (var & INSTANCE_BIT) {
1,494✔
3012
      // This alias is declared in an instantiated package
3013
      vcode_var_t pkg_var = var & ~INSTANCE_BIT;
6✔
3014
      vcode_reg_t pkg_reg;
6✔
3015
      if (hops == 0)
6✔
3016
         pkg_reg = emit_load(pkg_var);
×
3017
      else
3018
         pkg_reg = emit_load_indirect(emit_var_upref(hops, pkg_var));
6✔
3019

3020
      vcode_type_t vtype = lower_alias_type(alias);
6✔
3021
      return emit_link_var(pkg_reg, tree_ident(alias), vtype);
6✔
3022
   }
3023

3024
   if (hops == 0)
1,488✔
3025
      return emit_load(var);
1,272✔
3026
   else
3027
      return emit_load_indirect(emit_var_upref(hops, var));
216✔
3028
}
3029

3030
static bool lower_is_trivial_constant(tree_t decl)
15,603✔
3031
{
3032
   if (!type_is_scalar(tree_type(decl)))
15,603✔
3033
      return false;
3034
   else if (!tree_has_value(decl))
7,473✔
3035
      return false;
3036
   else
3037
      return tree_kind(tree_value(decl)) == T_LITERAL;
6,910✔
3038
}
3039

3040
static vcode_reg_t lower_ref(lower_unit_t *lu, tree_t ref, expr_ctx_t ctx)
204,054✔
3041
{
3042
   tree_t decl = tree_ref(ref);
204,054✔
3043

3044
   tree_kind_t kind = tree_kind(decl);
204,054✔
3045
   switch (kind) {
204,054✔
3046
   case T_ENUM_LIT:
65,672✔
3047
      if (ctx == EXPR_LVALUE)
65,672✔
3048
         return VCODE_INVALID_REG;
3049
      else
3050
         return emit_const(lower_type(tree_type(decl)), tree_pos(decl));
65,672✔
3051

3052
   case T_VAR_DECL:
32,385✔
3053
   case T_FILE_DECL:
3054
      return lower_var_ref(lu, decl, ctx);
32,385✔
3055

3056
   case T_PORT_DECL:
17,798✔
3057
      return lower_port_ref(lu, decl);
17,798✔
3058

3059
   case T_PARAM_DECL:
37,208✔
3060
      return lower_param_ref(lu, decl);
37,208✔
3061

3062
   case T_GENERIC_DECL:
3,140✔
3063
      return lower_generic_ref(lu, decl, ctx);
3,140✔
3064

3065
   case T_SIGNAL_DECL:
30,425✔
3066
   case T_IMPLICIT_SIGNAL:
3067
      return lower_signal_ref(lu, decl);
30,425✔
3068

3069
   case T_TYPE_DECL:
3070
      return VCODE_INVALID_REG;
3071

3072
   case T_CONST_DECL:
15,603✔
3073
      if (ctx == EXPR_LVALUE)
15,603✔
3074
         return VCODE_INVALID_REG;
3075
      else if (lower_is_trivial_constant(decl))
15,603✔
3076
         return lower_expr(lu, tree_value(decl), ctx);
×
3077
      else
3078
         return lower_var_ref(lu, decl, ctx);
15,603✔
3079

3080
   case T_UNIT_DECL:
×
3081
      return lower_expr(lu, tree_value(decl), ctx);
×
3082

3083
   case T_ALIAS:
1,751✔
3084
      return lower_alias_ref(lu, decl, ctx);
1,751✔
3085

3086
   case T_FUNC_BODY:
72✔
3087
      // Used to implement the "function knows result size" feature
3088
      assert(standard() >= STD_19);
72✔
3089
      assert(tree_flags(decl) & TREE_F_KNOWS_SUBTYPE);
72✔
3090
      return lower_param_ref(lu, decl);
72✔
3091

3092
   default:
×
3093
      vcode_dump();
×
3094
      fatal_trace("cannot lower reference to %s", tree_kind_str(kind));
3095
   }
3096
}
3097

3098
static vcode_reg_t lower_external_name(lower_unit_t *lu, tree_t ref)
200✔
3099
{
3100
   type_t type = tree_type(ref), base = type_base_recur(type);
200✔
3101

3102
   vcode_type_t vtype, vbounds = lower_bounds(type);
200✔
3103
   if (tree_class(ref) == C_SIGNAL)
200✔
3104
      vtype = lower_signal_type(base);
168✔
3105
   else
3106
      vtype = lower_type(base);
32✔
3107

3108
   ident_t scope;
200✔
3109
   for (vcode_unit_t vu = lu->vunit;; vu = vcode_unit_context(vu)) {
398✔
3110
      scope = vcode_unit_name(vu);
398✔
3111

3112
      const vunit_kind_t kind = vcode_unit_kind(vu);
398✔
3113
      if (kind == VCODE_UNIT_PACKAGE || kind == VCODE_UNIT_INSTANCE)
398✔
3114
         break;
3115
   }
3116

3117
   int hops = 0;
200✔
3118
   vcode_var_t var = lower_search_vcode_obj(ref, lu, &hops);
200✔
3119
   assert(var != VCODE_INVALID_VAR);
200✔
3120

3121
   vcode_reg_t ptr_reg;
200✔
3122
   if (hops == 0)
200✔
3123
      ptr_reg = emit_index(var, VCODE_INVALID_REG);
194✔
3124
   else
3125
      ptr_reg = emit_var_upref(hops, var);
6✔
3126

3127
   vcode_reg_t cache_reg = emit_load_indirect(ptr_reg);
200✔
3128
   vcode_reg_t null_reg = emit_null(vcode_reg_type(cache_reg));
200✔
3129
   vcode_reg_t test_reg = emit_cmp(VCODE_CMP_EQ, cache_reg, null_reg);
200✔
3130

3131
   vcode_block_t bind_bb = emit_block();
200✔
3132
   vcode_block_t cached_bb = emit_block();
200✔
3133
   emit_cond(test_reg, bind_bb, cached_bb);
200✔
3134

3135
   vcode_select_block(bind_bb);
200✔
3136

3137
   vcode_reg_t locus = lower_debug_locus(ref);
200✔
3138
   vcode_reg_t ext_reg = emit_bind_external(locus, scope, vtype, vbounds);
200✔
3139

3140
   // The external name subtype indication does not have to exactly
3141
   // match the subtype of the referenced object
3142
   if (type_is_array(type) && !type_is_unconstrained(type)) {
200✔
3143
      vcode_reg_t array_reg = emit_load_indirect(ext_reg);
12✔
3144
      lower_check_array_sizes(lu, type, base, VCODE_INVALID_REG,
12✔
3145
                              array_reg, locus);
3146
   }
3147

3148
   emit_store_indirect(ext_reg, ptr_reg);
200✔
3149
   emit_jump(cached_bb);
200✔
3150

3151
   vcode_select_block(cached_bb);
200✔
3152

3153
   vcode_reg_t result_reg = emit_load_indirect(ptr_reg);
200✔
3154
   if (type_is_record(type))
200✔
3155
      return result_reg;
3156
   else
3157
      return emit_load_indirect(result_reg);
196✔
3158
}
3159

3160
static void lower_external_name_cache(tree_t t, void *ctx)
172✔
3161
{
3162
   ident_t suffix = tree_ident(tree_part(t, tree_parts(t) - 1));
172✔
3163
   ident_t name = ident_prefix(suffix, ident_uniq("ename"), '.');
172✔
3164

3165
   type_t type = tree_type(t), base = type_base_recur(type);
172✔
3166
   vcode_type_t vtype, vbounds = lower_bounds(type);
172✔
3167
   if (tree_class(t) == C_SIGNAL)
172✔
3168
      vtype = vtype_pointer(lower_signal_type(base));
140✔
3169
   else
3170
      vtype = vtype_pointer(lower_type(base));
32✔
3171

3172
   vcode_var_t var = emit_var(vtype, vbounds, name, 0);
172✔
3173
   lower_put_vcode_obj(t, var, ctx);
172✔
3174

3175
   emit_store(emit_null(vtype), var);
172✔
3176
}
172✔
3177

3178
static vcode_reg_t lower_resolved(lower_unit_t *lu, type_t type,
23,803✔
3179
                                  vcode_reg_t reg)
3180
{
3181
   if (!lower_have_signal(reg))
23,803✔
3182
      return reg;
3183
   else if (have_uarray_ptr(reg))
14,146✔
3184
      reg = emit_load_indirect(reg);
3✔
3185

3186
   if (type_is_homogeneous(type)) {
14,146✔
3187
      vcode_reg_t data_reg, count_reg = VCODE_INVALID_REG;
13,118✔
3188
      if (vcode_reg_kind(reg) == VCODE_TYPE_POINTER)
13,118✔
3189
         data_reg = emit_resolved(emit_load_indirect(reg), count_reg);
932✔
3190
      else
3191
         data_reg = emit_resolved(lower_array_data(reg), count_reg);
12,186✔
3192

3193
      if (vcode_reg_kind(reg) == VCODE_TYPE_UARRAY)
13,118✔
3194
         return lower_rewrap(data_reg, reg);
311✔
3195
      else
3196
         return data_reg;
3197
   }
3198
   else {
3199
      // Use a helper function to convert a record signal into a record
3200
      // containing the resolved values
3201

3202
      ident_t base_id = type_ident(type_base_recur(type));
1,028✔
3203
      ident_t helper_func = ident_prefix(base_id, ident_new("resolved"), '$');
1,028✔
3204

3205
      vcode_reg_t arg_reg = reg;
1,028✔
3206
      if (type_is_array(type)) {
1,028✔
3207
         if (have_uarray_ptr(arg_reg))
308✔
3208
            arg_reg = emit_load_indirect(arg_reg);
×
3209
         else if (vcode_reg_kind(arg_reg) != VCODE_TYPE_UARRAY)
308✔
3210
            arg_reg = lower_wrap(lu, type, reg);
110✔
3211
      }
3212

3213
      vcode_type_t vrtype = lower_func_result_type(type);
1,028✔
3214

3215
      vcode_reg_t args[] = { lower_context_for_call(lu, helper_func), arg_reg };
1,028✔
3216
      return emit_fcall(helper_func, vrtype, vrtype, args, 2);
1,028✔
3217
   }
3218
}
3219

3220
static vcode_reg_t lower_array_off(lower_unit_t *lu, vcode_reg_t off,
22,748✔
3221
                                   vcode_reg_t array, type_t type,
3222
                                   unsigned dim)
3223
{
3224
   // Convert VHDL offset 'off' to a zero-based array offset
3225

3226
   assert(vtype_kind(vcode_reg_type(off)) == VCODE_TYPE_INT);
22,748✔
3227

3228
   vcode_reg_t zeroed = VCODE_INVALID_REG;
22,748✔
3229
   if (have_array_metadata(type, array)) {
22,748✔
3230
      vcode_reg_t left_reg = lower_array_left(lu, type, dim, array);
8,862✔
3231

3232
      vcode_reg_t downto = emit_sub(left_reg, off);
8,862✔
3233
      vcode_reg_t upto   = emit_sub(off, left_reg);
8,862✔
3234
      zeroed = emit_select(emit_uarray_dir(array, dim), downto, upto);
8,862✔
3235
   }
3236
   else {
3237
      tree_t r = range_of(type, dim);
13,886✔
3238
      vcode_reg_t left = lower_range_left(lu, r);
13,886✔
3239
      switch (tree_subkind(r)) {
13,886✔
3240
      case RANGE_TO:
10,523✔
3241
         zeroed = emit_sub(off, left);
10,523✔
3242
         break;
10,523✔
3243
      case RANGE_DOWNTO:
3,363✔
3244
         zeroed = emit_sub(left, off);
3,363✔
3245
         break;
3,363✔
3246
      case RANGE_EXPR:
×
3247
         {
3248
            vcode_reg_t dir = lower_range_dir(lu, r);
×
3249
            vcode_reg_t to = emit_sub(off, left);
×
3250
            vcode_reg_t downto = emit_sub(left, off);
×
3251
            zeroed = emit_select(dir, downto, to);
×
3252
         }
3253
         break;
×
3254
      }
3255
   }
3256

3257
   return emit_cast(vtype_offset(), VCODE_INVALID_TYPE, zeroed);
22,748✔
3258
}
3259

3260
static vcode_reg_t lower_array_ref(lower_unit_t *lu, tree_t ref, expr_ctx_t ctx)
18,152✔
3261
{
3262
   tree_t value = tree_value(ref);
18,152✔
3263

3264
   vcode_reg_t array = lower_expr(lu, value, ctx);
18,152✔
3265
   if (array == VCODE_INVALID_REG)
18,152✔
3266
      return array;
3267

3268
   if (have_uarray_ptr(array))
18,152✔
3269
      array = emit_load_indirect(array);
9✔
3270

3271
   DEBUG_ONLY({
18,152✔
3272
         const vtype_kind_t vtkind = vtype_kind(vcode_reg_type(array));
3273
         assert(vtkind == VCODE_TYPE_POINTER || vtkind == VCODE_TYPE_UARRAY
3274
                || vtkind == VCODE_TYPE_SIGNAL);
3275
      });
18,152✔
3276

3277
   type_t value_type = tree_type(value);
18,152✔
3278

3279
   const bool elide_bounds = tree_flags(ref) & TREE_F_ELIDE_BOUNDS;
18,152✔
3280

3281
   vcode_reg_t offset_reg = emit_const(vtype_offset(), 0);
18,152✔
3282
   const int nparams = tree_params(ref);
18,152✔
3283
   for (int i = 0; i < nparams; i++) {
37,872✔
3284
      tree_t p = tree_param(ref, i);
19,720✔
3285
      assert(tree_subkind(p) == P_POS);
19,720✔
3286

3287
      tree_t index = tree_value(p);
19,720✔
3288
      vcode_reg_t index_reg = lower_rvalue(lu, index);
19,720✔
3289

3290
      if (!elide_bounds) {
19,720✔
3291
         vcode_reg_t left_reg  = lower_array_left(lu, value_type, i, array);
12,858✔
3292
         vcode_reg_t right_reg = lower_array_right(lu, value_type, i, array);
12,858✔
3293
         vcode_reg_t dir_reg   = lower_array_dir(lu, value_type, i, array);
12,858✔
3294

3295
         vcode_reg_t locus = lower_debug_locus(index);
12,858✔
3296
         emit_index_check(index_reg, left_reg, right_reg, dir_reg,
12,858✔
3297
                          locus, locus);
3298
      }
3299

3300
      if (i > 0) {
19,720✔
3301
         vcode_reg_t stride = lower_array_len(lu, value_type, i, array);
1,568✔
3302
         offset_reg = emit_mul(offset_reg, stride);
1,568✔
3303
      }
3304

3305
      vcode_reg_t zerored_reg =
19,720✔
3306
         lower_array_off(lu, index_reg, array, value_type, i);
19,720✔
3307
      offset_reg = emit_add(offset_reg, zerored_reg);
19,720✔
3308
   }
3309

3310
   vcode_reg_t stride_reg = lower_array_stride(lu, value_type, array);
18,152✔
3311
   offset_reg = emit_mul(offset_reg, stride_reg);
18,152✔
3312

3313
   vcode_reg_t data_reg = lower_array_data(array);
18,152✔
3314
   vcode_reg_t ptr_reg = emit_array_ref(data_reg, offset_reg);
18,152✔
3315

3316
   type_t elem_type = type_elem(value_type);
18,152✔
3317
   if (type_is_array(elem_type) && !type_const_bounds(elem_type))
18,152✔
3318
      return lower_wrap_element(lu, value_type, array, ptr_reg);
252✔
3319
   else
3320
      return ptr_reg;
17,900✔
3321
}
3322

3323
static vcode_reg_t lower_array_slice(lower_unit_t *lu, tree_t slice,
2,641✔
3324
                                     expr_ctx_t ctx)
3325
{
3326
   tree_t value = tree_value(slice);
2,641✔
3327
   tree_t r     = tree_range(slice, 0);
2,641✔
3328
   type_t type  = tree_type(value);
2,641✔
3329

3330
   vcode_reg_t left_reg  = lower_range_left(lu, r);
2,641✔
3331
   vcode_reg_t right_reg = lower_range_right(lu, r);
2,641✔
3332
   vcode_reg_t kind_reg  = lower_range_dir(lu, r);
2,641✔
3333
   vcode_reg_t null_reg  = emit_range_null(left_reg, right_reg, kind_reg);
2,641✔
3334
   vcode_reg_t array_reg = lower_expr(lu, value, ctx);
2,641✔
3335

3336
   int64_t null_const;
2,641✔
3337
   const bool known_not_null =
5,282✔
3338
      vcode_reg_const(null_reg, &null_const) && null_const == 0;
2,641✔
3339

3340
   vcode_block_t after_bounds_bb = VCODE_INVALID_BLOCK;
2,641✔
3341
   if (!known_not_null) {
2,641✔
3342
      vcode_block_t not_null_bb = emit_block();
1,476✔
3343
      after_bounds_bb = emit_block();
1,476✔
3344
      emit_cond(null_reg, after_bounds_bb, not_null_bb);
1,476✔
3345

3346
      vcode_select_block(not_null_bb);
1,476✔
3347
   }
3348

3349
   vcode_reg_t aleft_reg  = lower_array_left(lu, type, 0, array_reg);
2,641✔
3350
   vcode_reg_t aright_reg = lower_array_right(lu, type, 0, array_reg);
2,641✔
3351
   vcode_reg_t adir_reg   = lower_array_dir(lu, type, 0, array_reg);
2,641✔
3352

3353
   vcode_reg_t locus = lower_debug_locus(r);
2,641✔
3354
   emit_index_check(left_reg, aleft_reg, aright_reg, adir_reg,
2,641✔
3355
                    locus, locus);
3356
   emit_index_check(right_reg, aleft_reg, aright_reg, adir_reg,
2,641✔
3357
                    locus, locus);
3358

3359
   if (!known_not_null) {
2,641✔
3360
      emit_jump(after_bounds_bb);
1,476✔
3361
      vcode_select_block(after_bounds_bb);
1,476✔
3362
   }
3363

3364
   if (array_reg == VCODE_INVALID_REG)
2,641✔
3365
      return VCODE_INVALID_REG;
3366

3367
   vcode_reg_t stride_reg = lower_array_stride(lu, type, array_reg);
2,641✔
3368

3369
   vcode_reg_t data_reg = lower_array_data(array_reg);
2,641✔
3370
   vcode_reg_t off_reg = lower_array_off(lu, left_reg, array_reg, type, 0);
2,641✔
3371
   vcode_reg_t ptr_reg =
2,641✔
3372
      emit_array_ref(data_reg, emit_mul(off_reg, stride_reg));
2,641✔
3373

3374
   if (type_const_bounds(type))
2,641✔
3375
      return ptr_reg;
3376

3377
   vcode_dim_t dim0 = {
1,480✔
3378
      .left  = left_reg,
3379
      .right = right_reg,
3380
      .dir   = kind_reg
3381
   };
3382

3383
   const int ndims = dims_for_type(type);
1,480✔
3384
   if (ndims > 1) {
1,480✔
3385
      assert(vcode_reg_kind(array_reg) == VCODE_TYPE_UARRAY);
3✔
3386

3387
      vcode_dim_t *dims LOCAL = xmalloc_array(ndims, sizeof(vcode_dim_t));
6✔
3388
      dims[0] = dim0;
3✔
3389
      for (int i = 1; i < ndims; i++) {
6✔
3390
         dims[i].left  = emit_uarray_left(array_reg, i);
3✔
3391
         dims[i].right = emit_uarray_right(array_reg, i);
3✔
3392
         dims[i].dir   = emit_uarray_dir(array_reg, i);
3✔
3393
      }
3394

3395
      return emit_wrap(ptr_reg, dims, ndims);
3✔
3396
   }
3397
   else
3398
      return emit_wrap(ptr_reg, &dim0, 1);
1,477✔
3399
}
3400

3401
static inline void lower_copy_vals(vcode_reg_t *restrict dst,
186,096✔
3402
                                   const vcode_reg_t *restrict src, int n)
3403
{
3404
   assert(n >= 0);
186,096✔
3405
   memcpy(dst, src, n * sizeof(vcode_reg_t));
186,096✔
3406
}
186,096✔
3407

3408
static vcode_reg_t *lower_const_array_aggregate(lower_unit_t *lu, tree_t t,
6,483✔
3409
                                                type_t type, int dim,
3410
                                                int *n_elems)
3411
{
3412
   if ((*n_elems = lower_array_const_size(type)) == 0)
6,483✔
3413
      return NULL;
3414

3415
   vcode_reg_t *vals = xmalloc_array(*n_elems, sizeof(vcode_reg_t));
6,363✔
3416

3417
   for (int i = 0; i < *n_elems; i++)
1,696,744✔
3418
      vals[i] = VCODE_INVALID_REG;
1,690,381✔
3419

3420
   tree_t r = range_of(type, dim);
6,363✔
3421
   const int64_t left = assume_int(tree_left(r));
6,363✔
3422
   const bool is_downto = (tree_subkind(r) == RANGE_DOWNTO);
6,363✔
3423

3424
   int pos = 0;
6,363✔
3425
   const int nassocs = tree_assocs(t);
6,363✔
3426
   for (int i = 0; i < nassocs; i++) {
58,669✔
3427
      tree_t a = tree_assoc(t, i);
52,306✔
3428
      tree_t value = tree_value(a);
52,306✔
3429
      type_t value_type = tree_type(value);
52,306✔
3430

3431
      const tree_kind_t value_kind = tree_kind(value);
52,306✔
3432

3433
      vcode_reg_t tmp = VCODE_INVALID_REG;
52,306✔
3434
      vcode_reg_t *sub = &tmp;
52,306✔
3435
      int nsub = 1;
52,306✔
3436
      if (value_kind == T_AGGREGATE) {
52,306✔
3437
         if (type_is_array(value_type))
3,703✔
3438
            sub = lower_const_array_aggregate(lu, value, value_type, 0, &nsub);
3,296✔
3439
         else if (type_is_record(value_type))
407✔
3440
            *sub = lower_record_aggregate(lu, value, true,
407✔
3441
                                          lower_is_const(value),
407✔
3442
                                          VCODE_INVALID_REG);
3443
         else
3444
            should_not_reach_here();
3445
      }
3446
      else if (value_kind == T_STRING)
48,603✔
3447
         sub = lower_string_literal_chars(value, &nsub);
382✔
3448
      else
3449
         *sub = lower_rvalue(lu, value);
48,221✔
3450

3451
      switch (tree_subkind(a)) {
52,306✔
3452
      case A_POS:
49,757✔
3453
      case A_CONCAT:
3454
         lower_copy_vals(vals + pos, sub, nsub);
49,757✔
3455
         pos += nsub;
49,757✔
3456
         break;
49,757✔
3457

3458
      case A_NAMED:
1,850✔
3459
         {
3460
            const int64_t name = assume_int(tree_name(a));
1,850✔
3461
            const int64_t off  = is_downto ? left - name : name - left;
1,850✔
3462
            lower_copy_vals(vals + (off * nsub), sub, nsub);
1,850✔
3463
         }
3464
         break;
1,850✔
3465

3466
      case A_OTHERS:
409✔
3467
         assert((*n_elems % nsub) == 0);
409✔
3468
         for (int j = 0; j < (*n_elems / nsub); j++) {
129,154✔
3469
            if (vals[j * nsub] == VCODE_INVALID_REG)
128,745✔
3470
               lower_copy_vals(vals + (j * nsub), sub, nsub);
127,332✔
3471
         }
3472
         break;
3473

3474
      case A_RANGE:
284✔
3475
         {
3476
            tree_t r = tree_range(a, 0);
284✔
3477

3478
            int64_t r_low, r_high;
284✔
3479
            range_bounds(r, &r_low, &r_high);
284✔
3480

3481
            for (int j = r_low; j <= r_high; j++) {
7,435✔
3482
               const int64_t off = is_downto ? left - j : j - left;
7,151✔
3483
               lower_copy_vals(vals + (off * nsub), sub, nsub);
7,151✔
3484
            }
3485
         }
3486
         break;
284✔
3487

3488
      case A_SLICE:
6✔
3489
         {
3490
            assert(standard() >= STD_08);
6✔
3491

3492
            tree_t r = tree_range(a, 0);
6✔
3493
            const int64_t r_left = assume_int(tree_left(r));
6✔
3494
            const int64_t off = is_downto ? left - r_left : r_left - left;
6✔
3495

3496
            lower_copy_vals(vals + off, sub, nsub);
6✔
3497
         }
3498
         break;
6✔
3499
      }
3500

3501
      if (sub != &tmp)
52,306✔
3502
         free(sub);
3,678✔
3503
   }
3504

3505
#ifdef DEBUG
3506
   for (int i = 0; i < *n_elems; i++) {
1,696,744✔
3507
      if (vals[i] == VCODE_INVALID_REG) {
1,690,381✔
3508
         vcode_dump();
×
3509
         fatal_trace("missing constant array element %d", i);
3510
      }
3511
   }
3512
#endif
3513

3514
   return vals;
3515
}
3516

3517
static vcode_reg_t lower_record_sub_aggregate(lower_unit_t *lu, tree_t value,
6,722✔
3518
                                              tree_t field, bool is_const)
3519
{
3520
   type_t ftype = tree_type(field);
6,722✔
3521

3522
   if (is_const && type_is_array(ftype)) {
6,722✔
3523
      if (tree_kind(value) == T_STRING)
407✔
3524
         return lower_string_literal(value, true);
312✔
3525
      else if (lu->mode == LOWER_THUNK && !type_const_bounds(ftype))
95✔
3526
         return emit_undefined(lower_type(ftype), lower_bounds(ftype));
×
3527
      else {
3528
         int nvals;
95✔
3529
         vcode_reg_t *values LOCAL =
190✔
3530
            lower_const_array_aggregate(lu, value, ftype, 0, &nvals);
95✔
3531
         return emit_const_array(lower_type(ftype), values, nvals);
95✔
3532
      }
3533
   }
3534
   else if (is_const && type_is_record(ftype))
6,315✔
3535
      return lower_record_aggregate(lu, value, true, true, VCODE_INVALID_REG);
90✔
3536
   else if (type_is_scalar(ftype) || type_is_access(ftype))
6,225✔
3537
      return lower_rvalue(lu, value);
5,287✔
3538
   else if (type_is_array(ftype)) {
938✔
3539
      vcode_reg_t value_reg = lower_rvalue(lu, value);
829✔
3540
      if (!type_is_unconstrained(ftype)) {
829✔
3541
         vcode_reg_t locus = lower_debug_locus(field);
631✔
3542
         lower_check_array_sizes(lu, ftype, tree_type(value),
631✔
3543
                                 VCODE_INVALID_REG, value_reg, locus);
3544
      }
3545
      return lower_coerce_arrays(lu, tree_type(value), ftype, value_reg);
829✔
3546
   }
3547
   else
3548
      return lower_rvalue(lu, value);
109✔
3549
}
3550

3551
static vcode_reg_t lower_record_aggregate(lower_unit_t *lu, tree_t expr,
2,799✔
3552
                                          bool nest, bool is_const,
3553
                                          vcode_reg_t hint)
3554
{
3555
   type_t type = tree_type(expr);
2,799✔
3556
   const int nfields = type_fields(type);
2,799✔
3557
   const int nassocs = tree_assocs(expr);
2,799✔
3558

3559
   vcode_reg_t *vals LOCAL = xcalloc_array(nfields, sizeof(vcode_reg_t));
5,598✔
3560
   for (int i = 0; i < nfields; i++)
9,521✔
3561
      vals[i] = VCODE_INVALID_REG;
6,722✔
3562

3563
   tree_t *map LOCAL = xcalloc_array(nfields, sizeof(tree_t));
5,598✔
3564

3565
   for (int i = 0; i < nassocs; i++) {
9,376✔
3566
      tree_t a = tree_assoc(expr, i);
6,577✔
3567
      tree_t value = tree_value(a);
6,577✔
3568

3569
      switch (tree_subkind(a)) {
6,577✔
3570
      case A_POS:
5,599✔
3571
         {
3572
            const int pos = tree_pos(a);
5,599✔
3573
            tree_t field = type_field(type, pos);
5,599✔
3574
            vals[pos] = lower_record_sub_aggregate(lu, value, field, is_const);
5,599✔
3575
            map[pos] = value;
5,599✔
3576
         }
3577
         break;
5,599✔
3578

3579
      case A_NAMED:
896✔
3580
         {
3581
            const int pos = tree_pos(tree_ref(tree_name(a)));
896✔
3582
            tree_t field = type_field(type, pos);
896✔
3583
            vals[pos] = lower_record_sub_aggregate(lu, value, field, is_const);
896✔
3584
            map[pos] = value;
896✔
3585
         }
3586
         break;
896✔
3587

3588
      case A_OTHERS:
3589
         for (int j = 0; j < nfields; j++) {
334✔
3590
            if (vals[j] == VCODE_INVALID_REG) {
252✔
3591
               tree_t field = type_field(type, j);
227✔
3592
               vals[j] = lower_record_sub_aggregate(lu, value, field, is_const);
227✔
3593
               map[j] = value;
227✔
3594
            }
3595
         }
3596
         break;
3597

3598
      default:
×
3599
         fatal_trace("unexpected range association in record aggregate");
3600
      }
3601
   }
3602

3603
   for (int i = 0; i < nfields; i++)
9,521✔
3604
      assert(vals[i] != VCODE_INVALID_REG);
6,722✔
3605

3606
   if (is_const) {
2,799✔
3607
      vcode_reg_t reg = emit_const_record(lower_type(type), vals, nfields);
2,140✔
3608
      return nest ? reg : emit_address_of(reg);
2,140✔
3609
   }
3610
   else {
3611
      vcode_type_t vtype = lower_type(type);
659✔
3612
      vcode_reg_t mem_reg = hint;
659✔
3613
      if (mem_reg == VCODE_INVALID_REG) {
659✔
3614
         vcode_var_t tmp_var = lower_temp_var(lu, "record", vtype, vtype);
420✔
3615
         mem_reg = emit_index(tmp_var, VCODE_INVALID_REG);
420✔
3616
      }
3617

3618
      for (int i = 0; i < nfields; i++) {
2,307✔
3619
         tree_t f = type_field(type, i), cons;
1,648✔
3620
         type_t ftype = tree_type(f);
1,648✔
3621
         vcode_reg_t ptr_reg = emit_record_ref(mem_reg, i);
1,648✔
3622
         if (type_is_array(ftype)) {
1,648✔
3623
            if (have_uarray_ptr(ptr_reg)) {
829✔
3624
               type_t value_type = tree_type(map[i]);
238✔
3625
               vcode_reg_t wrap_reg =
238✔
3626
                  lower_wrap_with_new_bounds(lu, value_type, ftype,
476✔
3627
                                             vals[i], vals[i]);
238✔
3628

3629
               if ((cons = type_constraint_for_field(type, f))) {
238✔
3630
                  // Element constraint may be OPEN for constants
3631
                  type_t ctype = tree_type(cons);
74✔
3632
                  if (!type_is_unconstrained(ctype)) {
74✔
3633
                     vcode_reg_t locus = lower_debug_locus(map[i]);
74✔
3634
                     lower_check_array_sizes(lu, ctype, value_type,
74✔
3635
                                             VCODE_INVALID_REG,
3636
                                             wrap_reg, locus);
3637
                  }
3638
               }
3639

3640
               emit_store_indirect(wrap_reg, ptr_reg);
238✔
3641
            }
3642
            else {
3643
               vcode_reg_t src_reg = lower_array_data(vals[i]);
591✔
3644
               vcode_reg_t length_reg =
591✔
3645
                  lower_array_total_len(lu, ftype, vals[i]);
591✔
3646
               emit_copy(ptr_reg, src_reg, length_reg);
591✔
3647
            }
3648
         }
3649
         else if (type_is_record(ftype))
819✔
3650
            emit_copy(ptr_reg, vals[i], VCODE_INVALID_REG);
109✔
3651
         else
3652
            emit_store_indirect(vals[i], ptr_reg);
710✔
3653
      }
3654

3655
      return mem_reg;
3656
   }
3657
}
3658

3659
static bool lower_can_use_const_rep(tree_t expr, int *length, tree_t *elem)
3,969✔
3660
{
3661
   switch (tree_kind(expr)) {
3,969✔
3662
   case T_AGGREGATE:
3,957✔
3663
      {
3664
         type_t type = tree_type(expr);
3,957✔
3665
         assert(type_const_bounds(type));
3,957✔
3666

3667
         tree_t a0 = tree_assoc(expr, 0);
3,957✔
3668
         if (tree_subkind(a0) != A_OTHERS)
3,957✔
3669
            return false;
3670

3671
         tree_t others = tree_value(a0);
1,007✔
3672
         type_t elem_type = tree_type(others);
1,007✔
3673

3674
         if (type_is_array(elem_type)) {
1,007✔
3675
            if (!lower_can_use_const_rep(others, length, elem))
184✔
3676
               return false;
3677
         }
3678
         else if (type_is_scalar(elem_type))
823✔
3679
            *elem = others;
808✔
3680
         else
3681
            return false;
3682

3683
         *length = lower_array_const_size(type);
969✔
3684
         return true;
969✔
3685
      }
3686

3687
   case T_STRING:
12✔
3688
      {
3689
         const int nchars = tree_chars(expr);
12✔
3690
         if (nchars == 0)
12✔
3691
            return false;
3692

3693
         tree_t c0 = tree_char(expr, 0);
11✔
3694
         tree_t d0 = tree_ref(c0);
11✔
3695

3696
         for (int i = 1; i < nchars; i++) {
45✔
3697
            if (tree_ref(tree_char(expr, i)) != d0)
41✔
3698
               return false;
3699
         }
3700

3701
         *elem = c0;
4✔
3702
         *length = nchars;
4✔
3703
         return true;
4✔
3704
      }
3705

3706
   default:
3707
      return false;
3708
   }
3709
}
3710

3711
static vcode_reg_t lower_aggregate_bounds(lower_unit_t *lu, tree_t expr,
227✔
3712
                                          vcode_reg_t *value_regs)
3713
{
3714
   // Calculate the direction and bounds of an unconstrained array
3715
   // aggregate using the rules in LRM 93 7.3.2.2
3716

3717
   type_t type = tree_type(expr);
227✔
3718
   assert(type_is_unconstrained(type));
227✔
3719

3720
   type_t index_type = index_type_of(type, 0);
227✔
3721

3722
   vcode_reg_t left_reg = VCODE_INVALID_REG,
227✔
3723
      right_reg = VCODE_INVALID_REG,
227✔
3724
      dir_reg = VCODE_INVALID_REG;
227✔
3725

3726
   range_kind_t dir;
227✔
3727
   int64_t ileft, iright;
227✔
3728
   if (calculate_aggregate_bounds(expr, &dir, &ileft, &iright)) {
227✔
3729
      vcode_type_t vindex = lower_type(index_type);
18✔
3730
      left_reg = emit_const(vindex, ileft);
18✔
3731
      right_reg = emit_const(vindex, iright);
18✔
3732
      dir_reg = emit_const(vtype_bool(), dir);
18✔
3733
   }
3734
   else {
3735
      vcode_type_t voffset = vtype_offset();
209✔
3736
      vcode_reg_t length_reg = VCODE_INVALID_REG;
209✔
3737

3738
      const int nassocs = tree_assocs(expr);
209✔
3739
      for (int i = 0; i < nassocs; i++) {
428✔
3740
         tree_t a = tree_assoc(expr, i);
219✔
3741
         const assoc_kind_t akind = tree_subkind(a);
219✔
3742

3743
         switch (akind) {
219✔
3744
         case A_NAMED:
3✔
3745
            assert(nassocs == 1);    // Must have a single association
3✔
3746
            left_reg = right_reg = lower_rvalue(lu, tree_name(a));
3✔
3747
            dir_reg = lower_range_dir(lu, range_of(index_type, 0));
3✔
3748
            break;
3✔
3749
         case A_RANGE:
196✔
3750
         case A_SLICE:
3751
            {
3752
               tree_t r = tree_range(a, 0);
196✔
3753
               left_reg = lower_range_left(lu, r);
196✔
3754
               right_reg = lower_range_right(lu, r);
196✔
3755
               dir_reg = lower_range_dir(lu, r);
196✔
3756
            }
3757
            break;
196✔
3758
         case A_POS:
20✔
3759
         case A_CONCAT:
3760
            {
3761
               vcode_reg_t count_reg;
20✔
3762
               if (akind == A_CONCAT) {
20✔
3763
                  type_t value_type = tree_type(tree_value(a));
19✔
3764
                  count_reg = lower_array_len(lu, value_type, 0, value_regs[i]);
19✔
3765
               }
3766
               else
3767
                  count_reg = emit_const(voffset, 1);
1✔
3768

3769
               if (length_reg == VCODE_INVALID_REG)
20✔
3770
                  length_reg = count_reg;
3771
               else
3772
                  length_reg = emit_add(length_reg, count_reg);
10✔
3773
            }
3774
            break;
3775
         default:
×
3776
            fatal_trace("unexpected association kind %d in unconstrained "
3777
                        "aggregate", tree_subkind(a));
3778
         }
3779
      }
3780

3781
      if (length_reg != VCODE_INVALID_REG) {
209✔
3782
         vcode_type_t vindex = lower_type(index_type);
10✔
3783
         vcode_reg_t delta_reg = emit_sub(length_reg, emit_const(voffset, 1));
10✔
3784
         vcode_reg_t cast_reg = emit_cast(vindex, vindex, delta_reg);
10✔
3785

3786
         vcode_reg_t index_right_reg;
10✔
3787
         lower_get_scalar_type_bounds(lu, index_type, &left_reg,
10✔
3788
                                      &index_right_reg, &dir_reg);
3789

3790
         right_reg = emit_add(left_reg, cast_reg);
10✔
3791
      }
3792
   }
3793

3794
   vcode_reg_t null_reg = emit_null(vtype_pointer(vtype_offset()));
227✔
3795

3796
   const int ndims = dims_for_type(type);
227✔
3797
   if (ndims > 1) {
227✔
3798
      vcode_dim_t *dims LOCAL = xmalloc_array(ndims, sizeof(vcode_dim_t));
22✔
3799

3800
      dims[0].left  = left_reg;
11✔
3801
      dims[0].right = right_reg;
11✔
3802
      dims[0].dir   = dir_reg;
11✔
3803

3804
      tree_t a0 = tree_value(tree_assoc(expr, 0));
11✔
3805
      vcode_reg_t a0_reg = value_regs[0];
11✔
3806
      assert(a0_reg != VCODE_INVALID_REG);
11✔
3807

3808
      if (vcode_reg_kind(a0_reg) == VCODE_TYPE_UARRAY) {
11✔
3809
         for (int i = 1; i < ndims; i++) {
23✔
3810
            dims[i].left  = emit_uarray_left(a0_reg, i - 1);
12✔
3811
            dims[i].right = emit_uarray_right(a0_reg, i - 1);
12✔
3812
            dims[i].dir   = emit_uarray_dir(a0_reg, i - 1);
12✔
3813
         }
3814
      }
3815
      else {
3816
         type_t a0_type = tree_type(a0);
×
3817
         for (int i = 1; i < ndims; i++) {
×
3818
            dims[i].left  = lower_array_left(lu, a0_type, i - 1, a0_reg);
×
3819
            dims[i].right = lower_array_right(lu, a0_type, i - 1, a0_reg);
×
3820
            dims[i].dir   = lower_array_dir(lu, a0_type, i - 1, a0_reg);
×
3821
         }
3822
      }
3823

3824
      return emit_wrap(null_reg, dims, ndims);
11✔
3825
   }
3826
   else {
3827
      vcode_dim_t dims[] = {
216✔
3828
         { left_reg, right_reg, dir_reg }
3829
      };
3830
      return emit_wrap(null_reg, dims, 1);
216✔
3831
   }
3832
}
3833

3834
static vcode_reg_t lower_array_aggregate(lower_unit_t *lu, tree_t expr,
5,551✔
3835
                                         vcode_reg_t hint)
3836
{
3837
   emit_debug_info(tree_loc(expr));
5,551✔
3838

3839
   type_t type = tree_type(expr);
5,551✔
3840
   type_t elem_type = type_elem(type);
5,551✔
3841
   type_t scalar_elem_type = type_elem_recur(type);
5,551✔
3842

3843
   if (type_const_bounds(type) && lower_is_const(expr)) {
5,551✔
3844
      int rep_size = -1;
3,785✔
3845
      tree_t rep_elem = NULL;
3,785✔
3846
      if (lower_can_use_const_rep(expr, &rep_size, &rep_elem) && rep_size > 1) {
3,785✔
3847
         vcode_reg_t elem_reg = lower_rvalue(lu, rep_elem);
693✔
3848
         if (hint != VCODE_INVALID_REG) {
693✔
3849
            emit_memset(hint, elem_reg, emit_const(vtype_offset(), rep_size));
563✔
3850
            return hint;
563✔
3851
         }
3852
         else {
3853
            vcode_type_t vtype = lower_type(type);
130✔
3854
            vcode_reg_t array = emit_const_rep(vtype, elem_reg, rep_size);
130✔
3855
            return emit_address_of(array);
130✔
3856
         }
3857
      }
3858
      else {
3859
         int nvals;
3,092✔
3860
         vcode_reg_t *values LOCAL =
6,184✔
3861
            lower_const_array_aggregate(lu, expr, type, 0, &nvals);
3,092✔
3862

3863
         vcode_reg_t array = emit_const_array(lower_type(type), values, nvals);
3,092✔
3864
         return emit_address_of(array);
3,092✔
3865
      }
3866
   }
3867

3868
   bool all_literals = true;
1,766✔
3869
   tree_t def_value = NULL;
1,766✔
3870
   const int nassocs = tree_assocs(expr);
1,766✔
3871
   for (int i = 0; i < nassocs; i++) {
4,638✔
3872
      tree_t a = tree_assoc(expr, i);
2,872✔
3873
      switch (tree_subkind(a)) {
2,872✔
3874
      case A_POS:
1,137✔
3875
         all_literals &= (tree_kind(tree_value(a)) == T_LITERAL);
1,137✔
3876
         break;
1,137✔
3877
      case A_OTHERS:
1,299✔
3878
         def_value = tree_value(a);
1,299✔
3879
         // Fall-through
3880
      default:
3881
         all_literals = false;
3882
         break;
3883
      }
3884
   }
3885

3886
   emit_comment("Begin array aggregrate line %d", tree_loc(expr)->first_line);
1,766✔
3887

3888
   assert(hint == VCODE_INVALID_REG || !have_uarray_ptr(hint));
1,766✔
3889

3890
   const int ndims = dimension_of(type);
1,766✔
3891
   const bool multidim = ndims > 1;
1,766✔
3892
   const bool array_of_array = type_is_array(elem_type);
1,766✔
3893
   const bool is_unconstrained = type_is_unconstrained(type);
1,766✔
3894

3895
   vcode_reg_t *value_regs LOCAL = xmalloc_array(nassocs, sizeof(vcode_reg_t));
3,532✔
3896
   for (int i = 0; i < nassocs; i++) {
4,638✔
3897
      tree_t a = tree_assoc(expr, i);
2,872✔
3898
      tree_t value = tree_value(a);
2,872✔
3899
      const assoc_kind_t akind = tree_subkind(a);
2,872✔
3900

3901
      if (akind == A_CONCAT || akind == A_SLICE)
2,872✔
3902
         value_regs[i] = lower_rvalue(lu, value);   // Always need length
77✔
3903
      else if (is_unconstrained && i == 0 && (array_of_array || multidim))
2,795✔
3904
         value_regs[i] = lower_rvalue(lu, value);
11✔
3905
      else if (tree_kind(value) == T_AGGREGATE)
2,784✔
3906
         value_regs[i] = VCODE_INVALID_REG;   // Prefer to generate in-place
87✔
3907
      else
3908
         value_regs[i] = lower_rvalue(lu, value);
2,697✔
3909
   }
3910

3911
   vcode_reg_t bounds_reg = VCODE_INVALID_REG;
1,766✔
3912
   if (is_unconstrained)
1,766✔
3913
      bounds_reg = lower_aggregate_bounds(lu, expr, value_regs);
227✔
3914
   else if (hint != VCODE_INVALID_REG
1,539✔
3915
            && vcode_reg_kind(hint) == VCODE_TYPE_UARRAY)
596✔
3916
      bounds_reg = hint;
3917
   else if (needs_bounds_var(type))
1,310✔
3918
      bounds_reg = lower_get_type_bounds(lu, type);
859✔
3919

3920
   vcode_reg_t dir_reg = lower_array_dir(lu, type, 0, bounds_reg);
1,766✔
3921
   vcode_reg_t left_reg = lower_array_left(lu, type, 0, bounds_reg);
1,766✔
3922
   vcode_reg_t right_reg = lower_array_right(lu, type, 0, bounds_reg);
1,766✔
3923

3924
   vcode_reg_t null_reg = emit_range_null(left_reg, right_reg, dir_reg);
1,766✔
3925

3926
   vcode_type_t velem   = lower_type(scalar_elem_type);
1,766✔
3927
   vcode_type_t vbounds = lower_bounds(scalar_elem_type);
1,766✔
3928
   vcode_type_t voffset = vtype_offset();
1,766✔
3929

3930
   if (all_literals) {
1,766✔
3931
      // The array has non-constant bounds but the elements are all
3932
      // constants so just create a constant array and wrap it
3933
      vcode_type_t velem = lower_type(elem_type);
4✔
3934
      vcode_type_t vbounds = lower_bounds(elem_type);
4✔
3935
      vcode_type_t vtype = vtype_carray(nassocs, velem, vbounds);
4✔
3936

3937
      vcode_reg_t array_reg = emit_const_array(vtype, value_regs, nassocs);
4✔
3938
      vcode_reg_t mem_reg = emit_address_of(array_reg);
4✔
3939

3940
      vcode_reg_t nassocs_reg = emit_const(voffset, nassocs);
4✔
3941
      vcode_reg_t length_reg = emit_range_length(left_reg, right_reg, dir_reg);
4✔
3942

3943
      vcode_reg_t locus = lower_debug_locus(expr);
4✔
3944
      emit_length_check(length_reg, nassocs_reg, locus, VCODE_INVALID_REG);
4✔
3945

3946
      vcode_dim_t dims[1] = {
4✔
3947
         { left_reg, right_reg, dir_reg }
3948
      };
3949
      return emit_wrap(mem_reg, dims, 1);
4✔
3950
   }
3951

3952
   int64_t null_const;
1,762✔
3953
   bool known_not_null = false;
1,762✔
3954
   if (vcode_reg_const(null_reg, &null_const)) {
1,762✔
3955
      if (null_const) {
616✔
3956
         vcode_type_t vtype = vtype_carray(0, velem, vbounds);
1✔
3957
         vcode_reg_t mem_reg =
1✔
3958
            emit_address_of(emit_const_array(vtype, NULL, 0));
1✔
3959

3960
         if (bounds_reg != VCODE_INVALID_REG)
1✔
3961
            return lower_rewrap(mem_reg, bounds_reg);
×
3962
         else
3963
            return mem_reg;
3964
      }
3965
      else
3966
         known_not_null = true;
3967
   }
3968

3969
   vcode_reg_t stride;
1,761✔
3970
   if (array_of_array)
1,761✔
3971
      stride = lower_array_stride(lu, type, bounds_reg);
191✔
3972
   else
3973
      stride = emit_const(voffset, 1);
1,570✔
3974

3975
   if (multidim) {
1,761✔
3976
      for (int i = 1; i < ndims; i++)
34✔
3977
         stride = emit_mul(stride, lower_array_len(lu, type, i, bounds_reg));
17✔
3978
      emit_comment("Multidimensional array stride is r%d", stride);
17✔
3979
   }
3980

3981
   vcode_reg_t dim0_len = lower_array_len(lu, type, 0, bounds_reg);
1,761✔
3982
   vcode_reg_t len_reg = emit_mul(dim0_len, stride);
1,761✔
3983

3984
   if (is_unconstrained)
1,761✔
3985
      hint = VCODE_INVALID_REG;
3986
   else if (hint != VCODE_INVALID_REG && def_value == NULL) {
1,534✔
3987
      // It is not safe to use the hint location if the aggregate has
3988
      // non-static bounds and those bounds were not derived from the
3989
      // context in the case of an OTHERS association
3990
      int64_t rlow, rhigh;
143✔
3991
      if (!folded_bounds(range_of(type, 0), &rlow, &rhigh))
143✔
3992
         hint = VCODE_INVALID_REG;
3✔
3993
   }
3994

3995
   vcode_reg_t mem_reg;
1,534✔
3996
   if (hint != VCODE_INVALID_REG)
1,534✔
3997
      mem_reg = lower_array_data(hint);
588✔
3998
   else
3999
      mem_reg = emit_alloc(velem, vbounds, len_reg);
1,173✔
4000

4001
   vcode_reg_t wrap_reg;
1,761✔
4002
   if (type_const_bounds(type))
1,761✔
4003
      wrap_reg = mem_reg;
4004
   else if (bounds_reg != VCODE_INVALID_REG)
1,311✔
4005
      wrap_reg = lower_rewrap(mem_reg, bounds_reg);
1,311✔
4006
   else if (multidim) {
×
4007
      vcode_dim_t *dims LOCAL = xmalloc_array(ndims, sizeof(vcode_dim_t));
×
4008
      for (int i = 0; i < ndims; i++) {
×
4009
         dims[i].left  = lower_array_left(lu, type, i, bounds_reg);
×
4010
         dims[i].right = lower_array_right(lu, type, i, bounds_reg);
×
4011
         dims[i].dir   = lower_array_dir(lu, type, i, bounds_reg);
×
4012
      }
4013
      wrap_reg = emit_wrap(mem_reg, dims, ndims);
×
4014
   }
4015
   else if (array_of_array)
×
4016
      wrap_reg = lower_wrap(lu, type, mem_reg);
×
4017
   else {
4018
      vcode_dim_t dim0 = {
×
4019
         .left  = left_reg,
4020
         .right = right_reg,
4021
         .dir   = dir_reg
4022
      };
4023
      wrap_reg = emit_wrap(mem_reg, &dim0, 1);
×
4024
   }
4025

4026
   vcode_block_t skip_bb = VCODE_INVALID_BLOCK;
1,761✔
4027
   if (!known_not_null) {
1,761✔
4028
      vcode_block_t not_null_bb = emit_block();
1,146✔
4029
      skip_bb = emit_block();
1,146✔
4030
      emit_cond(null_reg, skip_bb, not_null_bb);
1,146✔
4031

4032
      vcode_select_block(not_null_bb);
1,146✔
4033
   }
4034

4035
   if (def_value != NULL) {
1,761✔
4036
      // Initialise the array with the default value
4037
      if (type_is_scalar(elem_type) && !multidim) {
2,066✔
4038
         vcode_reg_t def_reg = lower_rvalue(lu, def_value);
768✔
4039
         emit_memset(mem_reg, def_reg, len_reg);
768✔
4040
      }
4041
      else {
4042
         vcode_block_t loop_bb = emit_block();
530✔
4043
         vcode_block_t exit_bb = emit_block();
530✔
4044

4045
         vcode_var_t i_var = lower_temp_var(lu, "i", voffset, voffset);
530✔
4046
         emit_store(emit_const(voffset, 0), i_var);
530✔
4047

4048
         // TODO: this is a hack to work around the lack of a block
4049
         // ordering pass in vcode
4050
         vcode_reg_t def_reg = VCODE_INVALID_REG;
530✔
4051
         if (type_is_scalar(elem_type) && !multidim)
530✔
4052
            def_reg = lower_rvalue(lu, def_value);
×
4053

4054
         emit_cond(null_reg, exit_bb, loop_bb);
530✔
4055

4056
         vcode_select_block(loop_bb);
530✔
4057

4058
         vcode_reg_t inc_reg = stride;
530✔
4059
         if (inc_reg == VCODE_INVALID_REG)
530✔
4060
            inc_reg = emit_const(voffset, 1);
×
4061

4062
         vcode_reg_t i_reg = emit_load(i_var);
530✔
4063
         vcode_reg_t next_reg = emit_add(i_reg, inc_reg);
530✔
4064
         emit_store(next_reg, i_var);
530✔
4065

4066
         vcode_reg_t ptr_reg = emit_array_ref(mem_reg, i_reg);
530✔
4067

4068
         if (def_reg == VCODE_INVALID_REG) {
530✔
4069
            if (tree_kind(def_value) == T_AGGREGATE) {
530✔
4070
               vcode_reg_t elem_reg = ptr_reg;
26✔
4071
               if (array_of_array && !multidim
26✔
4072
                   && !type_const_bounds(elem_type)) {
3✔
4073
                  assert(bounds_reg != VCODE_INVALID_REG);
3✔
4074
                  elem_reg = lower_wrap_element(lu, type, bounds_reg, ptr_reg);
3✔
4075
               }
4076

4077
               def_reg = lower_aggregate(lu, def_value, elem_reg);
26✔
4078
            }
4079
            else
4080
               def_reg = lower_rvalue(lu, def_value);
504✔
4081
         }
4082

4083
         if (array_of_array || multidim) {
530✔
4084
            assert(stride != VCODE_INVALID_REG);
133✔
4085
            vcode_reg_t src_reg = lower_array_data(def_reg);
133✔
4086
            emit_copy(ptr_reg, src_reg, stride);
133✔
4087
         }
4088
         else if (type_is_record(elem_type))
397✔
4089
            emit_copy(ptr_reg, def_reg, VCODE_INVALID_REG);
397✔
4090
         else
4091
            emit_store_indirect(def_reg, ptr_reg);
×
4092

4093
         vcode_reg_t done_reg = emit_cmp(VCODE_CMP_EQ, next_reg, len_reg);
530✔
4094
         emit_cond(done_reg, exit_bb, loop_bb);
530✔
4095

4096
         vcode_select_block(exit_bb);
530✔
4097
         lower_release_temp(lu, i_var);
530✔
4098
      }
4099
   }
4100

4101
   vcode_reg_t next_pos = VCODE_INVALID_REG;
1,761✔
4102

4103
   type_t index_type = index_type_of(type, 0);
1,761✔
4104
   tree_t index_r = range_of(index_type, 0);
1,761✔
4105

4106
   vcode_type_t vindex = lower_type(index_type);
1,761✔
4107

4108
   vcode_reg_t low_reg = emit_select(dir_reg, right_reg, left_reg);
1,761✔
4109

4110
   for (int i = 0; i < nassocs; i++) {
4,609✔
4111
      tree_t a = tree_assoc(expr, i);
2,848✔
4112
      tree_t value = tree_value(a);
2,848✔
4113

4114
      const assoc_kind_t akind = tree_subkind(a);
2,848✔
4115

4116
      vcode_reg_t count_reg = VCODE_INVALID_REG;
2,848✔
4117
      if (akind == A_CONCAT || akind == A_SLICE)
2,848✔
4118
         count_reg = lower_array_len(lu, tree_type(value), 0, value_regs[i]);
77✔
4119

4120
      vcode_reg_t loop_bb = VCODE_INVALID_BLOCK;
2,848✔
4121
      vcode_reg_t exit_bb = VCODE_INVALID_BLOCK;
2,848✔
4122

4123
      vcode_var_t tmp_var = VCODE_INVALID_VAR;
2,848✔
4124
      vcode_reg_t off_reg = VCODE_INVALID_REG;
2,848✔
4125

4126
      switch (tree_subkind(a)) {
2,848✔
4127
      case A_POS:
1,114✔
4128
         {
4129
            if (next_pos == VCODE_INVALID_REG)
1,114✔
4130
               off_reg = emit_const(voffset, tree_pos(a));
1,104✔
4131
            else {
4132
               off_reg = next_pos;
10✔
4133
               next_pos = emit_add(next_pos, emit_const(voffset, 1));
10✔
4134
            }
4135

4136
            vcode_reg_t locus = lower_debug_locus(a);
1,114✔
4137
            vcode_reg_t hint = lower_debug_locus(index_r);
1,114✔
4138

4139
            vcode_reg_t off_cast_reg = emit_cast(vindex, vindex, off_reg);
1,114✔
4140
            vcode_reg_t index_reg = emit_add(low_reg, off_cast_reg);
1,114✔
4141

4142
            emit_index_check(index_reg, left_reg, right_reg,
1,114✔
4143
                             dir_reg, locus, hint);
4144
         }
4145
         break;
1,114✔
4146

4147
      case A_CONCAT:
49✔
4148
         {
4149
            if (next_pos == VCODE_INVALID_REG) {
49✔
4150
               off_reg = emit_const(voffset, tree_pos(a));
28✔
4151
               next_pos = count_reg;
28✔
4152
            }
4153
            else {
4154
               off_reg = next_pos;
21✔
4155
               next_pos = emit_add(next_pos, count_reg);
21✔
4156
            }
4157

4158
            vcode_reg_t locus = lower_debug_locus(a);
49✔
4159
            vcode_reg_t hint = lower_debug_locus(index_r);
49✔
4160

4161
            vcode_reg_t index_off_reg = emit_cast(vindex, vindex, off_reg);
49✔
4162
            vcode_reg_t low_index_reg = emit_add(low_reg, index_off_reg);
49✔
4163

4164
            emit_index_check(low_index_reg, left_reg, right_reg,
49✔
4165
                             dir_reg, locus, hint);
4166

4167
            vcode_reg_t one_reg = emit_const(vindex, 1);
49✔
4168
            vcode_reg_t next_index_reg =
49✔
4169
               emit_sub(emit_cast(vindex, vindex, count_reg), one_reg);
49✔
4170
            vcode_reg_t high_index_reg =
49✔
4171
               emit_add(low_index_reg, next_index_reg);
49✔
4172

4173
            emit_index_check(high_index_reg, left_reg, right_reg,
49✔
4174
                             dir_reg, locus, hint);
4175
         }
4176
         break;
49✔
4177

4178
      case A_NAMED:
126✔
4179
         {
4180
            tree_t name = tree_name(a);
126✔
4181
            vcode_reg_t name_reg = lower_rvalue(lu, name);
126✔
4182
            vcode_reg_t locus = lower_debug_locus(name);
126✔
4183
            emit_index_check(name_reg, left_reg, right_reg, dir_reg,
126✔
4184
                             locus, locus);
4185
            off_reg = lower_array_off(lu, name_reg, wrap_reg, type, 0);
126✔
4186
         }
4187
         break;
126✔
4188

4189
      case A_RANGE:
233✔
4190
         {
4191
            loop_bb = emit_block();
233✔
4192
            exit_bb = emit_block();
233✔
4193

4194
            tree_t r = tree_range(a, 0);
233✔
4195
            type_t rtype = tree_type(r);
233✔
4196

4197
            vcode_reg_t r_left_reg  = lower_range_left(lu, r);
233✔
4198
            vcode_reg_t r_right_reg = lower_range_right(lu, r);
233✔
4199
            vcode_reg_t r_dir_reg   = lower_range_dir(lu, r);
233✔
4200

4201
            vcode_reg_t locus = lower_debug_locus(r);
233✔
4202
            emit_index_check(r_left_reg, left_reg, right_reg, dir_reg,
233✔
4203
                             locus, locus);
4204
            emit_index_check(r_right_reg, left_reg, right_reg, dir_reg,
233✔
4205
                             locus, locus);
4206

4207
            vcode_type_t vtype   = lower_type(rtype);
233✔
4208
            vcode_type_t vbounds = lower_bounds(rtype);
233✔
4209

4210
            tmp_var = lower_temp_var(lu, "i", vtype, vbounds);
233✔
4211
            emit_store(r_left_reg, tmp_var);
233✔
4212

4213
            vcode_reg_t null_reg =
233✔
4214
               emit_range_null(r_left_reg, r_right_reg, r_dir_reg);
233✔
4215
            emit_cond(null_reg, exit_bb, loop_bb);
233✔
4216

4217
            vcode_select_block(loop_bb);
233✔
4218
            emit_debug_info(tree_loc(a));
233✔
4219

4220
            vcode_reg_t i_reg = emit_load(tmp_var);
233✔
4221
            off_reg = lower_array_off(lu, i_reg, wrap_reg, type, 0);
233✔
4222
         }
4223
         break;
233✔
4224

4225
      case A_SLICE:
28✔
4226
         {
4227
            tree_t r = tree_range(a, 0);
28✔
4228

4229
            vcode_reg_t r_left_reg  = lower_range_left(lu, r);
28✔
4230
            vcode_reg_t r_right_reg = lower_range_right(lu, r);
28✔
4231
            vcode_reg_t r_dir_reg   = lower_range_dir(lu, r);
28✔
4232

4233
            vcode_reg_t locus = lower_debug_locus(a);
28✔
4234
            emit_index_check(r_left_reg, left_reg, right_reg, dir_reg,
28✔
4235
                             locus, locus);
4236
            emit_index_check(r_right_reg, left_reg, right_reg, dir_reg,
28✔
4237
                             locus, locus);
4238

4239
            vcode_reg_t expect_reg =
28✔
4240
               emit_range_length(r_left_reg, r_right_reg, r_dir_reg);
28✔
4241
            emit_length_check(expect_reg, count_reg, locus, VCODE_INVALID_REG);
28✔
4242

4243
            vcode_reg_t dir_cmp_reg =
28✔
4244
               emit_cmp(VCODE_CMP_EQ, dir_reg, r_dir_reg);
28✔
4245
            vcode_reg_t base_reg =
28✔
4246
               emit_select(dir_cmp_reg, r_left_reg, r_right_reg);
28✔
4247

4248
            off_reg = lower_array_off(lu, base_reg, wrap_reg, type, 0);
28✔
4249
         }
4250
         break;
28✔
4251

4252
      case A_OTHERS:
1,298✔
4253
         // Handled above
4254
         continue;
1,298✔
4255
      }
4256

4257
      if (stride != VCODE_INVALID_REG)
1,550✔
4258
         off_reg = emit_mul(off_reg, stride);
1,550✔
4259

4260
      vcode_reg_t ptr_reg = emit_array_ref(mem_reg, off_reg);
1,550✔
4261

4262
      if (value_regs[i] == VCODE_INVALID_REG) {
1,550✔
4263
         // Prefer generating aggregates in-place
4264
         assert(tree_kind(value) == T_AGGREGATE);
60✔
4265
         value_regs[i] = lower_aggregate(lu, value, ptr_reg);
60✔
4266
      }
4267

4268
      if (array_of_array && i > 0 && ndims == 1
1,550✔
4269
          && vcode_reg_kind(value_regs[0]) == VCODE_TYPE_UARRAY) {
745✔
4270
         // Element type is unconstrained so we need a length check here
4271
         vcode_reg_t locus = lower_debug_locus(a);
586✔
4272
         lower_check_array_sizes(lu, elem_type, elem_type,
586✔
4273
                                 value_regs[0], value_regs[i], locus);
586✔
4274
      }
4275

4276
      if (count_reg != VCODE_INVALID_REG) {
1,550✔
4277
         vcode_reg_t src_reg = lower_array_data(value_regs[i]);
77✔
4278
         emit_copy(ptr_reg, src_reg, count_reg);
77✔
4279
      }
4280
      else if (array_of_array || multidim) {
1,473✔
4281
         assert(stride != VCODE_INVALID_REG);
819✔
4282
         vcode_reg_t src_reg = lower_array_data(value_regs[i]);
819✔
4283
         emit_copy(ptr_reg, src_reg, stride);
819✔
4284
      }
4285
      else if (type_is_record(elem_type))
654✔
4286
         emit_copy(ptr_reg, value_regs[i], VCODE_INVALID_REG);
145✔
4287
      else
4288
         emit_store_indirect(value_regs[i], ptr_reg);
509✔
4289

4290
      if (loop_bb != VCODE_INVALID_BLOCK) {
1,550✔
4291
         assert(tree_subkind(a) == A_RANGE);
233✔
4292
         tree_t r = tree_range(a, 0);
233✔
4293

4294
         vcode_type_t vtype = lower_type(tree_type(r));
233✔
4295

4296
         vcode_reg_t r_dir_reg = lower_range_dir(lu, r);
233✔
4297
         vcode_reg_t step_down = emit_const(vtype, -1);
233✔
4298
         vcode_reg_t step_up   = emit_const(vtype, 1);
233✔
4299
         vcode_reg_t step_reg  = emit_select(r_dir_reg, step_down, step_up);
233✔
4300
         vcode_reg_t i_reg     = emit_load(tmp_var);
233✔
4301
         vcode_reg_t next_reg  = emit_add(i_reg, step_reg);
233✔
4302
         emit_store(next_reg, tmp_var);
233✔
4303

4304
         vcode_reg_t r_right_reg = lower_range_right(lu, r);
233✔
4305
         vcode_reg_t done_reg    = emit_cmp(VCODE_CMP_EQ, i_reg, r_right_reg);
233✔
4306
         emit_cond(done_reg, exit_bb, loop_bb);
233✔
4307

4308
         vcode_select_block(exit_bb);
233✔
4309
      }
4310

4311
      if (tmp_var != VCODE_INVALID_VAR)
1,550✔
4312
         lower_release_temp(lu, tmp_var);
233✔
4313
   }
4314

4315
   if (skip_bb != VCODE_INVALID_BLOCK) {
1,761✔
4316
      emit_jump(skip_bb);
1,146✔
4317
      vcode_select_block(skip_bb);
1,146✔
4318
   }
4319

4320
   return wrap_reg;
4321
}
4322

4323
static vcode_reg_t lower_aggregate(lower_unit_t *lu, tree_t expr,
7,853✔
4324
                                   vcode_reg_t hint)
4325
{
4326
   type_t type = tree_type(expr);
7,853✔
4327

4328
   if (type_is_record(type))
7,853✔
4329
      return lower_record_aggregate(lu, expr, false,
2,302✔
4330
                                    lower_is_const(expr), hint);
2,302✔
4331
   else if (type_is_array(type))
5,551✔
4332
      return lower_array_aggregate(lu, expr, hint);
5,551✔
4333
   else
4334
      fatal_trace("invalid type %s in lower_aggregate", type_pp(type));
4335
}
4336

4337
static vcode_reg_t lower_record_ref(lower_unit_t *lu, tree_t expr,
6,728✔
4338
                                    expr_ctx_t ctx)
4339
{
4340
   tree_t value = tree_value(expr);
6,728✔
4341
   type_t type = tree_type(value);
6,728✔
4342
   vcode_reg_t record = lower_expr(lu, value, ctx);
6,728✔
4343

4344
   const int index = tree_pos(tree_ref(expr));
6,728✔
4345
   type_t ftype = tree_type(type_field(type, index));
6,728✔
4346

4347
   vcode_reg_t f_reg = emit_record_ref(record, index);
6,728✔
4348
   if (lower_have_signal(f_reg) && type_is_homogeneous(ftype))
6,728✔
4349
      return emit_load_indirect(f_reg);
2,746✔
4350
   else if (type_is_array(ftype) && !type_const_bounds(ftype)) {
3,982✔
4351
      // The field type may be unconstrained but this particular
4352
      // instance has a record element constraint
4353
      vcode_reg_t array = emit_load_indirect(f_reg);
707✔
4354
      if (type_const_bounds(tree_type(expr)))
707✔
4355
         return lower_array_data(array);
141✔
4356
      else
4357
         return array;
4358
   }
4359
   else
4360
      return f_reg;
3,275✔
4361
}
4362

4363
static vcode_reg_t lower_prot_ref(lower_unit_t *lu, tree_t expr)
12✔
4364
{
4365
   assert(standard() >= STD_19);
12✔
4366

4367
   vcode_reg_t prefix = lower_rvalue(lu, tree_value(expr));
12✔
4368

4369
   vcode_type_t vtype = lower_type(tree_type(expr));
12✔
4370
   return emit_link_var(prefix, tree_ident(expr), vtype);
12✔
4371
}
4372

4373
static vcode_reg_t lower_protected_init(lower_unit_t *lu, type_t type,
163✔
4374
                                        tree_t decl)
4375
{
4376
   vcode_reg_t names[2] = { VCODE_INVALID_REG, VCODE_INVALID_REG };
163✔
4377

4378
   if (standard() >= STD_19) {
163✔
4379
      // Pass path name and instance names as arguments for LCS-2016-032
4380

4381
      LOCAL_TEXT_BUF tb = tb_new();
76✔
4382
      static const attr_kind_t which[2] = {
38✔
4383
         ATTR_PATH_NAME, ATTR_INSTANCE_NAME
4384
      };
4385

4386
      for (int i = 0; i < 2; i++) {
114✔
4387
         tb_rewind(tb);
76✔
4388
         get_hierarchical_name(tb, lu, which[i]);
76✔
4389
         if (decl != NULL)
76✔
4390
            tb_istr(tb, tree_ident(decl));
58✔
4391
         tb_append(tb, ':');
76✔
4392
         tb_downcase(tb);
76✔
4393

4394
         names[i] = lower_name_attr(lu, decl ?: lu->container, which[i]);
76✔
4395
      }
4396
   }
4397

4398
   vcode_type_t vtype = lower_type(type);
163✔
4399
   vcode_reg_t context_reg = lower_context_for_call(lu, type_ident(type));
163✔
4400
   return emit_protected_init(vtype, context_reg, names[0], names[1]);
163✔
4401
}
4402

4403
static void lower_new_record(lower_unit_t *lu, type_t type,
973✔
4404
                             vcode_reg_t dst_ptr, vcode_reg_t src_ptr)
4405
{
4406
   if (src_ptr == dst_ptr)
973✔
4407
      return;
4408
   else if (type_const_bounds(type))
718✔
4409
      emit_copy(dst_ptr, src_ptr, VCODE_INVALID_REG);
679✔
4410
   else {
4411
      ident_t base_id = type_ident(type_base_recur(type));
39✔
4412
      ident_t helper_func = ident_prefix(base_id, ident_new("new"), '$');
39✔
4413

4414
      vcode_reg_t args[] = {
39✔
4415
         lower_context_for_call(lu, helper_func),
39✔
4416
         dst_ptr,
4417
         src_ptr,
4418
      };
4419
      emit_fcall(helper_func, VCODE_INVALID_TYPE, VCODE_INVALID_TYPE,
39✔
4420
                 args, ARRAY_LEN(args));
4421
   }
4422
}
4423

4424
static vcode_reg_t lower_new(lower_unit_t *lu, tree_t expr)
392✔
4425
{
4426
   tree_t qual = tree_value(expr);
392✔
4427
   assert(tree_kind(qual) == T_QUALIFIED);
392✔
4428

4429
   type_t type = tree_type(qual);
392✔
4430

4431
   if (type_is_array(type)) {
392✔
4432
      type_t value_type = type, result_type = type_designated(tree_type(expr));
301✔
4433
      type_t elem = type_elem_recur(type);
301✔
4434

4435
      const bool wrap_result = !type_const_bounds(result_type);
301✔
4436
      const bool wrap_value = !type_const_bounds(type);
301✔
4437

4438
      type_t alloc_type = wrap_result ? result_type : elem;
301✔
4439

4440
      vcode_reg_t init_reg = VCODE_INVALID_REG, bounds_reg = VCODE_INVALID_REG;
301✔
4441
      tree_t value = NULL;
301✔
4442
      if (tree_has_value(qual)) {
301✔
4443
         value = tree_value(qual);
178✔
4444
         value_type = tree_type(value);
178✔
4445

4446
         const bool in_place_aggregate =
356✔
4447
            tree_kind(value) == T_AGGREGATE && type_const_bounds(value_type);
178✔
4448

4449
         if (!in_place_aggregate)
178✔
4450
            init_reg = bounds_reg = lower_rvalue(lu, qual);
168✔
4451
      }
4452
      else if (wrap_value)
123✔
4453
         bounds_reg = lower_get_type_bounds(lu, type);
26✔
4454

4455
      vcode_reg_t length_reg =
301✔
4456
         lower_array_total_len(lu, value_type, bounds_reg);
301✔
4457
      vcode_reg_t mem_reg = emit_new(lower_type(alloc_type), length_reg);
301✔
4458
      vcode_reg_t all_reg = emit_all(mem_reg);
301✔
4459
      vcode_reg_t data_reg = lower_array_data(all_reg);
301✔
4460

4461
      vcode_reg_t array_reg = all_reg;
301✔
4462
      if (wrap_value)
301✔
4463
         array_reg = lower_wrap_with_new_bounds(lu, value_type, type,
177✔
4464
                                                bounds_reg, data_reg);
4465

4466
      if (value == NULL)
301✔
4467
         init_reg = lower_default_value(lu, type, array_reg);
123✔
4468
      else if (init_reg == VCODE_INVALID_REG)
178✔
4469
         init_reg = lower_aggregate(lu, value, data_reg);
10✔
4470

4471
      if (init_reg != array_reg) {
301✔
4472
         vcode_reg_t src_reg = lower_array_data(init_reg);
187✔
4473
         emit_copy(data_reg, src_reg, length_reg);
187✔
4474
      }
4475

4476
      if (wrap_result) {
301✔
4477
         // Need to initialise the array bounds
4478
         vcode_reg_t meta_reg =
244✔
4479
            lower_wrap_with_new_bounds(lu, value_type, result_type,
244✔
4480
                                       bounds_reg, data_reg);
4481
         emit_store_indirect(meta_reg, all_reg);
244✔
4482
      }
4483

4484
      return mem_reg;
301✔
4485
   }
4486
   else if (type_is_record(type)) {
91✔
4487
      vcode_reg_t result_reg =
54✔
4488
         emit_new(lower_type(type), VCODE_INVALID_REG);
54✔
4489
      vcode_reg_t all_reg = emit_all(result_reg);
54✔
4490

4491
      vcode_reg_t init_reg;
54✔
4492
      if (tree_has_value(qual)) {
54✔
4493
         tree_t value = tree_value(qual);
19✔
4494
         if (tree_kind(value) == T_AGGREGATE && type_const_bounds(type))
19✔
4495
            init_reg = lower_aggregate(lu, value, all_reg);
4✔
4496
         else
4497
            init_reg = lower_rvalue(lu, qual);
15✔
4498
      }
4499
      else
4500
         init_reg = lower_default_value(lu, type, all_reg);
35✔
4501

4502
      lower_new_record(lu, type, all_reg, init_reg);
54✔
4503
      return result_reg;
54✔
4504
   }
4505
   else if (type_is_protected(type)) {
37✔
4506
      vcode_reg_t obj_reg = lower_protected_init(lu, type, NULL);
9✔
4507
      vcode_reg_t result_reg = emit_new(lower_type(type), VCODE_INVALID_REG);
9✔
4508
      vcode_reg_t all_reg = emit_all(result_reg);
9✔
4509
      emit_store_indirect(obj_reg, all_reg);
9✔
4510
      return result_reg;
9✔
4511
   }
4512
   else {
4513
      vcode_reg_t result_reg = emit_new(lower_type(type), VCODE_INVALID_REG);
28✔
4514
      vcode_reg_t all_reg = emit_all(result_reg);
28✔
4515

4516
      vcode_reg_t init_reg;
28✔
4517
      if (tree_has_value(qual))
28✔
4518
         init_reg = lower_rvalue(lu, qual);
18✔
4519
      else
4520
         init_reg = lower_default_value(lu, type, VCODE_INVALID_REG);
10✔
4521

4522
      emit_store_indirect(init_reg, all_reg);
28✔
4523
      return result_reg;
28✔
4524
   }
4525
}
4526

4527
static vcode_reg_t lower_incomplete_access(vcode_reg_t in_reg, type_t type)
3,056✔
4528
{
4529
   assert(vcode_reg_kind(in_reg) == VCODE_TYPE_ACCESS);
3,056✔
4530

4531
   vcode_type_t pointed = vtype_pointed(vcode_reg_type(in_reg));
3,056✔
4532

4533
   const bool have_opaque = vtype_kind(pointed) == VCODE_TYPE_OPAQUE;
3,056✔
4534
   const bool have_incomplete = type_is_incomplete(type);
3,056✔
4535

4536
   if (have_incomplete ^ have_opaque) {
3,056✔
4537
      vcode_type_t ptr_type = vtype_access(lower_type(type));
474✔
4538
      return emit_cast(ptr_type, ptr_type, in_reg);
474✔
4539
   }
4540

4541
   return in_reg;
4542
}
4543

4544
static vcode_reg_t lower_all(lower_unit_t *lu, tree_t all, expr_ctx_t ctx)
1,755✔
4545
{
4546
   type_t type = tree_type(all);
1,755✔
4547
   vcode_reg_t access_reg = lower_rvalue(lu, tree_value(all));
1,755✔
4548
   emit_null_check(access_reg, lower_debug_locus(all));
1,755✔
4549
   access_reg = lower_incomplete_access(access_reg, tree_type(all));
1,755✔
4550
   vcode_reg_t all_reg = emit_all(access_reg);
1,755✔
4551

4552
   if (type_is_array(type) && !type_const_bounds(type))
1,755✔
4553
      return emit_load_indirect(all_reg);
776✔
4554
   else
4555
      return all_reg;
979✔
4556
}
4557

4558
static void lower_convert_record(lower_unit_t *lu, vcode_reg_t value_reg,
15✔
4559
                                 tree_t where, type_t from, type_t to,
4560
                                 vcode_reg_t ptr_reg)
4561
{
4562
   const int to_nf = type_fields(to);
15✔
4563
   const int from_nf = type_fields(from);
15✔
4564

4565
   for (int i = 0; i < to_nf; i++) {
51✔
4566
      tree_t to_f = type_field(to, i);
36✔
4567
      type_t to_type = tree_type(to_f), from_type = NULL;
36✔
4568
      ident_t name = tree_ident(to_f);
36✔
4569

4570
      vcode_reg_t from_reg = VCODE_INVALID_REG;
36✔
4571
      for (int j = 0; j < from_nf; j++) {
63✔
4572
         tree_t f = type_field(from, j);
63✔
4573
         if (tree_ident(f) == name) {
63✔
4574
            from_reg = emit_record_ref(value_reg, j);
36✔
4575
            from_type = tree_type(f);
36✔
4576
            break;
36✔
4577
         }
4578
      }
4579
      assert(from_reg != VCODE_INVALID_REG);
36✔
4580

4581
      if (have_uarray_ptr(from_reg))
36✔
4582
         from_reg = emit_load_indirect(from_reg);
3✔
4583

4584
      vcode_reg_t to_reg = emit_record_ref(ptr_reg, i);
36✔
4585

4586
      if (type_is_array(to_type)) {
36✔
4587
         vcode_reg_t conv_reg =
6✔
4588
            lower_conversion(lu, from_reg, where, from_type, to_type);
6✔
4589

4590
         // Shallow copy is ok here as the result of this conversion is
4591
         // effectively constant
4592
         if (have_uarray_ptr(to_reg)) {
6✔
4593
            assert(vcode_reg_kind(conv_reg) == VCODE_TYPE_UARRAY);
3✔
4594
            emit_store_indirect(conv_reg, to_reg);
3✔
4595
         }
4596
         else {
4597
            vcode_reg_t data_reg = lower_array_data(conv_reg);
3✔
4598
            vcode_reg_t count_reg =
3✔
4599
               lower_array_total_len(lu, to_type, conv_reg);
3✔
4600
            emit_copy(to_reg, data_reg, count_reg);
3✔
4601
         }
4602
      }
4603
      else if (type_is_record(to_type))
30✔
4604
         lower_convert_record(lu, from_reg, where, from_type, to_type, to_reg);
6✔
4605
      else {
4606
         vcode_reg_t elem_reg = emit_load_indirect(from_reg);
24✔
4607
         vcode_reg_t conv_reg =
24✔
4608
            lower_conversion(lu, elem_reg, where, from_type, to_type);
24✔
4609
         emit_store_indirect(conv_reg, to_reg);
24✔
4610
      }
4611
   }
4612
}
15✔
4613

4614
static vcode_reg_t lower_conversion(lower_unit_t *lu, vcode_reg_t value_reg,
4,332✔
4615
                                    tree_t where, type_t from, type_t to)
4616
{
4617
   type_kind_t from_k = type_kind(type_base_recur(from));
4,332✔
4618
   type_kind_t to_k   = type_kind(type_base_recur(to));
4,332✔
4619

4620
   if (from_k == T_REAL && to_k == T_INTEGER) {
4,332✔
4621
      vcode_type_t vtype = lower_type(to);
91✔
4622
      vcode_type_t vbounds = vtype_int(INT64_MIN, INT64_MAX);
91✔
4623
      vcode_reg_t cast = emit_cast(vtype, vbounds, value_reg);
91✔
4624
      lower_check_scalar_bounds(lu, cast, to, where, NULL);
91✔
4625
      return cast;
91✔
4626
   }
4627
   else if (from_k == T_INTEGER && to_k == T_REAL) {
4,241✔
4628
      vcode_type_t vtype = lower_type(to);
179✔
4629
      vcode_type_t vbounds = vtype_real((double)INT64_MIN, (double)INT64_MAX);
179✔
4630
      return emit_cast(vtype, vbounds, value_reg);
179✔
4631
   }
4632
   else if (from_k == T_ARRAY && to_k == T_ARRAY) {
4,062✔
4633
      type_t from_e = type_elem_recur(from);
2,462✔
4634
      type_t to_e = type_elem_recur(to);
2,462✔
4635

4636
      vcode_reg_t result_reg = value_reg;
2,462✔
4637

4638
      if (standard() >= STD_08 && !type_eq(from_e, to_e)) {
2,462✔
4639
         // VHDL-2008 allows closely related element types which might
4640
         // need conversion and/or bounds checks
4641

4642
         vcode_type_t velem = lower_type(to_e);
15✔
4643
         vcode_type_t vbounds = lower_bounds(from_e);
15✔
4644
         vcode_type_t voffset = vtype_offset();
15✔
4645

4646
         vcode_reg_t count_reg = lower_array_total_len(lu, from, value_reg);
15✔
4647
         vcode_reg_t mem_reg = emit_alloc(velem, vbounds, count_reg);
15✔
4648
         vcode_reg_t zero_reg = emit_const(voffset, 0);
15✔
4649
         vcode_reg_t data_reg = lower_array_data(value_reg);
15✔
4650

4651
         vcode_var_t i_var = lower_temp_var(lu, "i", voffset, voffset);
15✔
4652
         emit_store(zero_reg, i_var);
15✔
4653

4654
         vcode_block_t body_bb = emit_block();
15✔
4655
         vcode_block_t exit_bb = emit_block();
15✔
4656

4657
         vcode_reg_t null_reg = emit_cmp(VCODE_CMP_EQ, count_reg, zero_reg);
15✔
4658
         emit_cond(null_reg, exit_bb, body_bb);
15✔
4659

4660
         vcode_select_block(body_bb);
15✔
4661

4662
         vcode_reg_t i_reg = emit_load(i_var);
15✔
4663
         vcode_reg_t src_reg = emit_array_ref(data_reg, i_reg);
15✔
4664
         vcode_reg_t elem_reg = emit_load_indirect(src_reg);
15✔
4665

4666
         vcode_reg_t conv_reg =
15✔
4667
            lower_conversion(lu, elem_reg, where, from_e, to_e);
15✔
4668

4669
         vcode_reg_t dest_reg = emit_array_ref(mem_reg, i_reg);
15✔
4670
         emit_store_indirect(conv_reg, dest_reg);
15✔
4671

4672
         vcode_reg_t next_reg = emit_add(i_reg, emit_const(voffset, 1));
15✔
4673
         vcode_reg_t done_reg = emit_cmp(VCODE_CMP_EQ, next_reg, count_reg);
15✔
4674
         emit_store(next_reg, i_var);
15✔
4675
         emit_cond(done_reg, exit_bb, body_bb);
15✔
4676

4677
         vcode_select_block(exit_bb);
15✔
4678

4679
         lower_release_temp(lu, i_var);
15✔
4680

4681
         result_reg = mem_reg;
15✔
4682
      }
4683

4684
      if (!type_const_bounds(to))   // Need to wrap in metadata
2,462✔
4685
         result_reg = lower_wrap(lu, from, result_reg);
2,432✔
4686

4687
      if (type_is_unconstrained(to))
2,462✔
4688
         lower_check_indexes(lu, from, to, result_reg, where);
2,418✔
4689
      else {
4690
         vcode_reg_t locus = lower_debug_locus(where);
44✔
4691
         lower_check_array_sizes(lu, to, from, value_reg, result_reg, locus);
44✔
4692
      }
4693

4694
      return result_reg;
2,462✔
4695
   }
4696
   else if ((from_k == T_INTEGER && to_k == T_INTEGER)
1,600✔
4697
            || (from_k == T_REAL && to_k == T_REAL)) {
51✔
4698
      // Possibly change width
4699
      lower_check_scalar_bounds(lu, value_reg, to, where, NULL);
1,571✔
4700
      return emit_cast(lower_type(to), lower_bounds(to), value_reg);
1,571✔
4701
   }
4702
   else if (from_k == T_RECORD && to_k == T_RECORD) {
29✔
4703
      vcode_type_t vtype_to = lower_type(to);
9✔
4704
      vcode_var_t tmp_var = lower_temp_var(lu, "conv", vtype_to, vtype_to);
9✔
4705
      vcode_reg_t ptr_reg = emit_index(tmp_var, VCODE_INVALID_REG);
9✔
4706
      lower_convert_record(lu, value_reg, where, from, to, ptr_reg);
9✔
4707
      return ptr_reg;
9✔
4708
   }
4709
   else {
4710
      // No conversion to perform
4711
      return value_reg;
4712
   }
4713
}
4714

4715
static vcode_reg_t lower_type_conv(lower_unit_t *lu, tree_t expr)
4,263✔
4716
{
4717
   tree_t value = tree_value(expr);
4,263✔
4718

4719
   type_t from = tree_type(value);
4,263✔
4720
   type_t to   = tree_type(expr);
4,263✔
4721

4722
   vcode_reg_t value_reg = lower_rvalue(lu, value);
4,263✔
4723
   return lower_conversion(lu, value_reg, expr, from, to);
4,263✔
4724
}
4725

4726
static vcode_reg_t lower_driving_value(lower_unit_t *lu, tree_t name)
134✔
4727
{
4728
   vcode_reg_t name_reg = lower_lvalue(lu, name);
134✔
4729

4730
   type_t name_type = tree_type(name);
134✔
4731
   if (type_is_homogeneous(name_type)) {
134✔
4732
      if (type_is_array(name_type)) {
128✔
4733
         vcode_reg_t len_reg = lower_array_total_len(lu, name_type, name_reg);
30✔
4734
         vcode_reg_t ptr_reg = emit_driving_value(name_reg, len_reg);
30✔
4735
         if (vcode_reg_kind(name_reg) == VCODE_TYPE_UARRAY)
30✔
4736
            return lower_rewrap(name_reg, ptr_reg);
×
4737
         else
4738
            return ptr_reg;
4739
      }
4740
      else {
4741
         vcode_reg_t ptr_reg = emit_driving_value(name_reg, VCODE_INVALID_REG);
98✔
4742
         return emit_load_indirect(ptr_reg);
98✔
4743
      }
4744
   }
4745
   else {
4746
      type_t base = type_base_recur(name_type);
6✔
4747
      ident_t base_id = type_ident(base);
6✔
4748
      ident_t helper_func = ident_prefix(base_id, ident_new("driving"), '$');
6✔
4749

4750
      vcode_reg_t arg_reg;
6✔
4751
      if (type_is_array(base))
6✔
4752
         arg_reg = lower_coerce_arrays(lu, name_type, base, name_reg);
×
4753
      else
4754
         arg_reg = name_reg;
4755

4756
      vcode_type_t vrtype = lower_func_result_type(base);
6✔
4757

4758
      vcode_reg_t context_reg = lower_context_for_call(lu, helper_func);
6✔
4759
      vcode_reg_t args[] = { context_reg, arg_reg };
6✔
4760
      return emit_fcall(helper_func, vrtype, vrtype, args, 2);
6✔
4761
   }
4762
}
4763

4764
static const int lower_get_attr_dimension(tree_t expr)
11,238✔
4765
{
4766
   if (tree_params(expr) > 0)
11,238✔
4767
      return assume_int(tree_value(tree_param(expr, 0))) - 1;
24✔
4768
   else
4769
      return 0;
4770
}
4771

4772
static vcode_reg_t lower_attr_prefix(lower_unit_t *lu, tree_t prefix)
16,419✔
4773
{
4774
   switch (class_of(prefix)) {
16,419✔
4775
   case C_SIGNAL:
879✔
4776
      {
4777
         vcode_reg_t reg = lower_lvalue(lu, prefix);
879✔
4778
         if (have_uarray_ptr(reg))
879✔
4779
            return emit_load_indirect(reg);
×
4780
         else
4781
            return reg;
4782
      }
4783
   case C_TYPE:
4784
   case C_SUBTYPE:
4785
      return VCODE_INVALID_REG;
4786
   default:
14,799✔
4787
      return lower_rvalue(lu, prefix);
14,799✔
4788
   }
4789
}
4790

4791
static vcode_reg_t lower_reflect_attr(lower_unit_t *lu, tree_t expr)
87✔
4792
{
4793
   tree_t name = tree_name(expr);
87✔
4794
   type_t type = tree_type(expr);
87✔
4795

4796
   ident_t init_func = type_ident(type);
87✔
4797
   vcode_reg_t context_reg = lower_context_for_call(lu, init_func);
87✔
4798

4799
   type_t value_mirror = reflection_type(REFLECT_VALUE_MIRROR);
87✔
4800
   const bool is_value_mirror = type_eq(type, value_mirror);
87✔
4801

4802
   vcode_reg_t value_reg = VCODE_INVALID_REG, bounds_reg = VCODE_INVALID_REG;
87✔
4803
   if (is_value_mirror)
87✔
4804
      value_reg = lower_attr_prefix(lu, name);
45✔
4805

4806
   type_t value_type = tree_type(name);
87✔
4807
   if (type_is_array(value_type))
87✔
4808
      bounds_reg = lower_wrap(lu, value_type, value_reg);
6✔
4809

4810
   vcode_reg_t locus = lower_debug_locus(name);
87✔
4811

4812
   if (is_value_mirror)
87✔
4813
      return emit_reflect_value(value_reg, context_reg, locus, bounds_reg);
45✔
4814
   else
4815
      return emit_reflect_subtype(context_reg, locus, bounds_reg);
42✔
4816
}
4817

4818
static vcode_reg_t lower_attr_param(lower_unit_t *lu, tree_t value,
1,305✔
4819
                                    type_t port_type, class_t class)
4820
{
4821
   type_t value_type = tree_type(value);
1,305✔
4822

4823
   vcode_reg_t reg;
1,305✔
4824
   if (class == C_SIGNAL || class == C_FILE)
1,305✔
4825
      reg = lower_lvalue(lu, value);
×
4826
   else
4827
      reg = lower_rvalue(lu, value);
1,305✔
4828

4829
   if (reg == VCODE_INVALID_REG)
1,305✔
4830
      return reg;
4831

4832
   if (type_is_array(value_type))
1,305✔
4833
      return lower_coerce_arrays(lu, value_type, port_type ?: value_type, reg);
21✔
4834
   else if (class == C_SIGNAL || class == C_FILE)
4835
      return reg;
4836
   else
4837
      return reg;
4838
}
4839

4840
static vcode_reg_t lower_attr_ref(lower_unit_t *lu, tree_t expr)
14,259✔
4841
{
4842
   tree_t name = tree_name(expr);
14,259✔
4843

4844
   const attr_kind_t predef = tree_subkind(expr);
14,259✔
4845
   switch (predef) {
14,259✔
4846
   case ATTR_LEFT:
1,099✔
4847
   case ATTR_RIGHT:
4848
      {
4849
         const int dim = lower_get_attr_dimension(expr);
1,099✔
4850

4851
         type_t type = tree_type(name);
1,099✔
4852
         if (type_is_unconstrained(type)) {
1,099✔
4853
            vcode_reg_t array_reg = lower_attr_prefix(lu, name);
596✔
4854
            if (predef == ATTR_LEFT)
596✔
4855
               return lower_array_left(lu, type, dim, array_reg);
447✔
4856
            else
4857
               return lower_array_right(lu, type, dim, array_reg);
149✔
4858
         }
4859
         else {
4860
            tree_t r = range_of(type, dim);
503✔
4861
            if (predef == ATTR_LEFT)
503✔
4862
               return lower_range_left(lu, r);
469✔
4863
            else
4864
               return lower_range_right(lu, r);
34✔
4865
         }
4866
      }
4867

4868
   case ATTR_LOW:
4,444✔
4869
   case ATTR_HIGH:
4870
      {
4871
         const int dim = lower_get_attr_dimension(expr);
4,444✔
4872

4873
         vcode_reg_t left_reg  = VCODE_INVALID_REG;
4,444✔
4874
         vcode_reg_t right_reg = VCODE_INVALID_REG;
4,444✔
4875
         vcode_reg_t dir_reg   = VCODE_INVALID_REG;
4,444✔
4876

4877
         type_t type = tree_type(name);
4,444✔
4878
         if (type_is_unconstrained(type)) {
4,444✔
4879
            vcode_reg_t array_reg = lower_attr_prefix(lu, name);
3,515✔
4880
            left_reg  = lower_array_left(lu, type, dim, array_reg);
3,515✔
4881
            right_reg = lower_array_right(lu, type, dim, array_reg);
3,515✔
4882
            dir_reg   = lower_array_dir(lu, type, dim, array_reg);
3,515✔
4883
         }
4884
         else {
4885
            tree_t r = range_of(type, dim);
929✔
4886
            const range_kind_t rkind = tree_subkind(r);
929✔
4887
            if (rkind == RANGE_TO) {
929✔
4888
               return predef == ATTR_LOW
281✔
4889
                  ? lower_range_left(lu, r) : lower_range_right(lu, r);
281✔
4890
            }
4891
            else if (rkind == RANGE_DOWNTO) {
648✔
4892
               return predef == ATTR_LOW
506✔
4893
                  ? lower_range_right(lu, r) : lower_range_left(lu, r);
506✔
4894
            }
4895

4896
            left_reg  = lower_range_left(lu, r);
142✔
4897
            right_reg = lower_range_right(lu, r);
142✔
4898
            dir_reg   = lower_range_dir(lu, r);
142✔
4899
         }
4900

4901
         if (predef == ATTR_LOW)
3,657✔
4902
            return emit_select(dir_reg, right_reg, left_reg);
1,830✔
4903
         else
4904
            return emit_select(dir_reg, left_reg, right_reg);
1,827✔
4905
      }
4906

4907
   case ATTR_LENGTH:
5,644✔
4908
      {
4909
         const int dim = lower_get_attr_dimension(expr);
5,644✔
4910
         vcode_reg_t name_reg = lower_attr_prefix(lu, name);
5,644✔
4911
         vcode_reg_t len_reg =
5,644✔
4912
            lower_array_len(lu, tree_type(name), dim, name_reg);
5,644✔
4913
         return emit_cast(lower_type(tree_type(expr)),
5,644✔
4914
                          VCODE_INVALID_TYPE, len_reg);
4915
      }
4916

4917
   case ATTR_ELEMENT:
24✔
4918
      {
4919
         vcode_reg_t array_reg = lower_attr_prefix(lu, name);
24✔
4920
         type_t type = tree_type(name);
24✔
4921
         type_t elem = type_elem_recur(type);
24✔
4922
         vcode_reg_t null_reg = emit_null(vtype_pointer(lower_type(elem)));
24✔
4923
         return lower_wrap_element(lu, type, array_reg, null_reg);
24✔
4924
      }
4925

4926
   case ATTR_ASCENDING:
51✔
4927
      {
4928
         type_t type = tree_type(name);
51✔
4929
         const int dim = lower_get_attr_dimension(expr);
51✔
4930
         if (type_const_bounds(type))
51✔
4931
            return emit_const(vtype_bool(),
×
4932
                              direction_of(type, dim) == RANGE_TO);
×
4933
         else {
4934
            vcode_reg_t name_reg = lower_attr_prefix(lu, name);
51✔
4935
            return emit_not(lower_array_dir(lu, type, dim, name_reg));
51✔
4936
         }
4937
      }
4938

4939
   case ATTR_LAST_EVENT:
72✔
4940
   case ATTR_LAST_ACTIVE:
4941
      {
4942
         vcode_reg_t name_reg = lower_attr_prefix(lu, name);
72✔
4943
         type_t name_type = tree_type(name);
72✔
4944

4945
         if (type_is_homogeneous(name_type)) {
72✔
4946
            vcode_reg_t len_reg = VCODE_INVALID_REG;
51✔
4947
            if (type_is_array(name_type)) {
51✔
4948
               len_reg = lower_array_total_len(lu, name_type, name_reg);
15✔
4949
               name_reg = lower_array_data(name_reg);
15✔
4950
            }
4951

4952
            if (predef == ATTR_LAST_EVENT)
51✔
4953
               return emit_last_event(name_reg, len_reg);
24✔
4954
            else
4955
               return emit_last_active(name_reg, len_reg);
27✔
4956
         }
4957
         else {
4958
            ident_t base_id = type_ident(type_base_recur(name_type));
21✔
4959
            const char *suffix = predef == ATTR_LAST_EVENT
42✔
4960
               ? "last_event" : "last_active";
21✔
4961
            ident_t helper_func = ident_sprintf("%s$%s", istr(base_id), suffix);
21✔
4962

4963
            vcode_reg_t arg_reg = name_reg;
21✔
4964
            if (type_is_array(name_type)
21✔
4965
                && vcode_reg_kind(arg_reg) != VCODE_TYPE_UARRAY)
×
4966
               arg_reg = lower_wrap(lu, name_type, name_reg);
×
4967

4968
            vcode_type_t vtime = vtype_time();
21✔
4969
            vcode_reg_t context_reg = lower_context_for_call(lu, helper_func);
21✔
4970
            vcode_reg_t args[] = { context_reg, arg_reg };
21✔
4971
            return emit_fcall(helper_func, vtime, vtime, args, 2);
21✔
4972
         }
4973
      }
4974

4975
   case ATTR_DRIVING_VALUE:
27✔
4976
      return lower_driving_value(lu, name);
27✔
4977

4978
   case ATTR_EVENT:
250✔
4979
      return lower_signal_flag(lu, name, emit_event_flag);
250✔
4980

4981
   case ATTR_ACTIVE:
208✔
4982
      return lower_signal_flag(lu, name, emit_active_flag);
208✔
4983

4984
   case ATTR_DRIVING:
36✔
4985
      return lower_signal_flag(lu, name, emit_driving_flag);
36✔
4986

4987
   case ATTR_LAST_VALUE:
53✔
4988
      return lower_last_value(lu, name);
53✔
4989

4990
   case ATTR_INSTANCE_NAME:
765✔
4991
   case ATTR_PATH_NAME:
4992
      if (lu->mode == LOWER_THUNK) {
765✔
4993
         vcode_type_t vchar = vtype_char();
×
4994
         vcode_type_t vstring = vtype_uarray(1, vchar, vchar);
×
4995
         return emit_undefined(vstring, vchar);
×
4996
      }
4997
      else
4998
         return lower_name_attr(lu, tree_ref(name), predef);
765✔
4999

5000
   case ATTR_SIMPLE_NAME:
69✔
5001
      {
5002
         LOCAL_TEXT_BUF tb = tb_new();
138✔
5003
         tb_istr(tb, tree_ident(tree_ref(name)));
69✔
5004
         tb_downcase(tb);
69✔
5005
         return lower_wrap_string(tb_get(tb));
69✔
5006
      }
5007

5008
   case ATTR_IMAGE:
1,006✔
5009
      {
5010
         tree_t value = tree_value(tree_param(expr, 0));
1,006✔
5011
         type_t type = tree_type(value);
1,006✔
5012
         type_t base = type_base_recur(type);
1,006✔
5013
         ident_t func = ident_prefix(type_ident(base), ident_new("image"), '$');
1,006✔
5014
         vcode_type_t ctype = vtype_char();
1,006✔
5015
         vcode_type_t strtype = vtype_uarray(1, ctype, ctype);
1,006✔
5016

5017
         vcode_reg_t arg_reg = lower_attr_param(lu, value, base, C_CONSTANT);
1,006✔
5018

5019
         vcode_reg_t args[] = {
1,006✔
5020
            lower_context_for_call(lu, func),
1,006✔
5021
            arg_reg,
5022
         };
5023
         return emit_fcall(func, strtype, strtype, args, 2);
1,006✔
5024
      }
5025

5026
   case ATTR_VALUE:
125✔
5027
      {
5028
         type_t name_type = tree_type(name);
125✔
5029
         tree_t value = tree_value(tree_param(expr, 0));
125✔
5030
         type_t value_type = tree_type(value);
125✔
5031

5032
         vcode_reg_t value_reg = lower_rvalue(lu, value);
125✔
5033

5034
         if (lower_have_signal(value_reg))
125✔
5035
            value_reg = emit_resolved(value_reg, VCODE_INVALID_REG);
×
5036

5037
         if (vcode_reg_kind(value_reg) != VCODE_TYPE_UARRAY)
125✔
5038
            value_reg = lower_wrap(lu, value_type, value_reg);
105✔
5039

5040
         type_t base = type_base_recur(name_type);
125✔
5041
         ident_t func = ident_prefix(type_ident(base), ident_new("value"), '$');
125✔
5042
         vcode_reg_t args[] = {
125✔
5043
            lower_context_for_call(lu, func),
125✔
5044
            value_reg
5045
         };
5046
         vcode_reg_t reg = emit_fcall(func, lower_type(base),
125✔
5047
                                      lower_bounds(base), args, 2);
5048

5049
         if (type_is_scalar(name_type))
125✔
5050
            lower_check_scalar_bounds(lu, reg, name_type, expr, NULL);
95✔
5051
         else if (type_is_array(name_type) && type_const_bounds(name_type)) {
30✔
5052
            vcode_reg_t locus = lower_debug_locus(expr);
6✔
5053
            lower_check_array_sizes(lu, name_type, base, VCODE_INVALID_REG,
6✔
5054
                                    reg, locus);
5055
         }
5056

5057
         return reg;
125✔
5058
      }
5059

5060
   case ATTR_SUCC:
4✔
5061
      {
5062
         tree_t value = tree_value(tree_param(expr, 0));
4✔
5063
         vcode_reg_t arg_reg = lower_attr_param(lu, value, NULL, C_CONSTANT);
4✔
5064
         return emit_add(arg_reg, emit_const(vcode_reg_type(arg_reg), 1));
4✔
5065
      }
5066

5067
   case ATTR_PRED:
13✔
5068
      {
5069
         tree_t value = tree_value(tree_param(expr, 0));
13✔
5070
         vcode_reg_t arg_reg = lower_attr_param(lu, value, NULL, C_CONSTANT);
13✔
5071
         return emit_sub(arg_reg, emit_const(vcode_reg_type(arg_reg), 1));
13✔
5072
      }
5073

5074
   case ATTR_LEFTOF:
14✔
5075
      {
5076
         tree_t value = tree_value(tree_param(expr, 0));
14✔
5077
         vcode_reg_t arg_reg = lower_attr_param(lu, value, NULL, C_CONSTANT);
14✔
5078

5079
         type_t type = tree_type(expr);
14✔
5080
         const int dir =
28✔
5081
            (type_is_enum(type) || direction_of(type, 0) == RANGE_TO) ? -1 : 1;
14✔
5082
         return emit_add(arg_reg, emit_const(vcode_reg_type(arg_reg), dir));
14✔
5083
      }
5084

5085
   case ATTR_RIGHTOF:
11✔
5086
      {
5087
         tree_t value = tree_value(tree_param(expr, 0));
11✔
5088
         vcode_reg_t arg_reg = lower_attr_param(lu, value, NULL, C_CONSTANT);
11✔
5089

5090
         type_t type = tree_type(expr);
11✔
5091
         const int dir =
22✔
5092
            (type_is_enum(type) || direction_of(type, 0) == RANGE_TO) ? 1 : -1;
11✔
5093
         return emit_add(arg_reg, emit_const(vcode_reg_type(arg_reg), dir));
11✔
5094
      }
5095

5096
   case ATTR_POS:
97✔
5097
      {
5098
         tree_t value = tree_value(tree_param(expr, 0));
97✔
5099
         vcode_reg_t arg_reg = lower_attr_param(lu, value, NULL, C_CONSTANT);
97✔
5100

5101
         type_t type = tree_type(expr);
97✔
5102
         return emit_cast(lower_type(type), lower_bounds(type), arg_reg);
97✔
5103
      }
5104

5105
   case ATTR_VAL:
160✔
5106
      {
5107
         tree_t value = tree_value(tree_param(expr, 0));
160✔
5108
         vcode_reg_t arg_reg = lower_attr_param(lu, value, NULL, C_CONSTANT);
160✔
5109

5110
         type_t type = tree_type(expr);
160✔
5111
         lower_check_scalar_bounds(lu, arg_reg, type, expr, NULL);
160✔
5112
         return emit_cast(lower_type(type), lower_bounds(type), arg_reg);
160✔
5113
      }
5114

5115
   case ATTR_REFLECT:
87✔
5116
      return lower_reflect_attr(lu, expr);
87✔
5117

5118
   default:
×
5119
      fatal_at(tree_loc(expr), "cannot lower attribute %s (%d)",
×
5120
               istr(tree_ident(expr)), predef);
5121
   }
5122
}
5123

5124
static vcode_reg_t lower_qualified(lower_unit_t *lu, tree_t expr)
4,251✔
5125
{
5126
   tree_t value = tree_value(expr);
4,251✔
5127

5128
   type_t from_type = tree_type(value);
4,251✔
5129
   type_t to_type = tree_type(expr);
4,251✔
5130

5131
   vcode_reg_t value_reg = lower_rvalue(lu, value);
4,251✔
5132

5133
   if (type_is_array(to_type))
4,251✔
5134
      return lower_coerce_arrays(lu, from_type, to_type, value_reg);
3,160✔
5135
   else
5136
      return value_reg;
5137
}
5138

5139
static vcode_reg_t lower_cond_value(lower_unit_t *lu, tree_t expr)
9✔
5140
{
5141
   vcode_block_t exit_bb = VCODE_INVALID_BLOCK;
9✔
5142

5143
   // TODO: vcode really needs phi nodes...
5144
   type_t type = tree_type(expr);
9✔
5145
   vcode_type_t vtype = lower_type(type);
9✔
5146
   vcode_type_t vbounds = lower_bounds(type);
9✔
5147
   vcode_var_t temp_var = lower_temp_var(lu, "cond", vtype, vbounds);
9✔
5148

5149
   const int nconds = tree_conds(expr);
9✔
5150
   for (int i = 0; i < nconds; i++) {
21✔
5151
      tree_t c = tree_cond(expr, i);
21✔
5152
      assert(tree_kind(c) == T_COND_EXPR);
21✔
5153

5154
      vcode_block_t next_bb = VCODE_INVALID_BLOCK;
21✔
5155

5156
      if (tree_has_value(c)) {
21✔
5157
         vcode_reg_t test = lower_rvalue(lu, tree_value(c));
12✔
5158

5159
         vcode_block_t btrue = emit_block();
12✔
5160

5161
         if (i == nconds - 1) {
12✔
5162
            if (exit_bb == VCODE_INVALID_BLOCK)
×
5163
               exit_bb = emit_block();
×
5164
            next_bb = exit_bb;
5165
         }
5166
         else
5167
            next_bb = emit_block();
12✔
5168

5169
         emit_cond(test, btrue, next_bb);
12✔
5170
         vcode_select_block(btrue);
12✔
5171
      }
5172

5173
      vcode_reg_t result_reg = lower_rvalue(lu, tree_result(c));
21✔
5174

5175
      if (type_is_array(type) && type_const_bounds(type)) {
27✔
5176
         vcode_reg_t count_reg =
6✔
5177
            lower_array_total_len(lu, type, VCODE_INVALID_REG);
6✔
5178
         vcode_reg_t dest_reg = emit_index(temp_var, VCODE_INVALID_REG);
6✔
5179
         vcode_reg_t src_reg = lower_array_data(result_reg);
6✔
5180
         emit_copy(dest_reg, src_reg, count_reg);
6✔
5181
      }
5182
      else if (type_is_record(type)) {
15✔
5183
         vcode_reg_t dest_reg = emit_index(temp_var, VCODE_INVALID_REG);
9✔
5184
         emit_copy(dest_reg, result_reg, VCODE_INVALID_REG);
9✔
5185
      }
5186
      else
5187
         emit_store(result_reg, temp_var);
6✔
5188

5189
      if (exit_bb == VCODE_INVALID_BLOCK)
21✔
5190
         exit_bb = emit_block();
9✔
5191
      emit_jump(exit_bb);
21✔
5192

5193
      if (next_bb == VCODE_INVALID_BLOCK)
21✔
5194
         break;
5195
      else
5196
         vcode_select_block(next_bb);
12✔
5197
   }
5198

5199
   if (exit_bb != VCODE_INVALID_BLOCK)
9✔
5200
      vcode_select_block(exit_bb);
9✔
5201

5202
   if (type_is_scalar(type))
9✔
5203
      return emit_load(temp_var);
3✔
5204
   else
5205
      return emit_index(temp_var, VCODE_INVALID_REG);
6✔
5206
}
5207

5208
static vcode_reg_t lower_expr(lower_unit_t *lu, tree_t expr, expr_ctx_t ctx)
525,497✔
5209
{
5210
   PUSH_DEBUG_INFO(expr);
1,050,994✔
5211

5212
   switch (tree_kind(expr)) {
525,497✔
5213
   case T_FCALL:
65,939✔
5214
   case T_PROT_FCALL:
5215
      return lower_fcall(lu, expr, VCODE_INVALID_REG);
65,939✔
5216
   case T_PSL_FCALL:
36✔
5217
      return psl_lower_fcall(lu, tree_psl(expr));
36✔
5218
   case T_LITERAL:
178,947✔
5219
      return lower_literal(expr);
178,947✔
5220
   case T_STRING:
19,740✔
5221
      return lower_string_literal(expr, false);
19,740✔
5222
   case T_REF:
204,054✔
5223
      return lower_ref(lu, expr, ctx);
204,054✔
5224
   case T_EXTERNAL_NAME:
161✔
5225
      return lower_external_name(lu, expr);
161✔
5226
   case T_AGGREGATE:
4,157✔
5227
      return lower_aggregate(lu, expr, VCODE_INVALID_VAR);
4,157✔
5228
   case T_ARRAY_REF:
18,152✔
5229
      return lower_array_ref(lu, expr, ctx);
18,152✔
5230
   case T_ARRAY_SLICE:
2,641✔
5231
      return lower_array_slice(lu, expr, ctx);
2,641✔
5232
   case T_RECORD_REF:
6,728✔
5233
      return lower_record_ref(lu, expr, ctx);
6,728✔
5234
   case T_PROT_REF:
12✔
5235
      return lower_prot_ref(lu, expr);
12✔
5236
   case T_NEW:
392✔
5237
      return lower_new(lu, expr);
392✔
5238
   case T_ALL:
1,755✔
5239
      return lower_all(lu, expr, ctx);
1,755✔
5240
   case T_TYPE_CONV:
4,263✔
5241
      return lower_type_conv(lu, expr);
4,263✔
5242
   case T_ATTR_REF:
14,259✔
5243
      return lower_attr_ref(lu, expr);
14,259✔
5244
   case T_QUALIFIED:
4,251✔
5245
      return lower_qualified(lu, expr);
4,251✔
5246
   case T_OPEN:
5247
      return VCODE_INVALID_REG;
5248
   case T_COND_VALUE:
9✔
5249
      return lower_cond_value(lu, expr);
9✔
5250
   default:
×
5251
      fatal_at(tree_loc(expr), "cannot lower expression kind %s",
×
5252
               tree_kind_str(tree_kind(expr)));
5253
   }
5254
}
5255

5256
static vcode_reg_t lower_nested_default_value(lower_unit_t *lu, type_t type)
4,310✔
5257
{
5258
   if (type_is_scalar(type))
4,310✔
5259
      return lower_scalar_type_left(lu, type);
3,151✔
5260
   else if (type_is_array(type)) {
1,159✔
5261
      assert(type_const_bounds(type));
521✔
5262
      type_t elem = type_elem_recur(type);
521✔
5263
      vcode_reg_t elem_reg = lower_nested_default_value(lu, elem);
521✔
5264
      const int size = lower_array_const_size(type);
521✔
5265

5266
      if (vtype_is_scalar(vcode_reg_type(elem_reg)))
521✔
5267
         return emit_const_rep(lower_type(type), elem_reg, size);
471✔
5268
      else {
5269
         vcode_reg_t *values LOCAL = xmalloc_array(size, sizeof(vcode_reg_t));
100✔
5270
         for (int i = 0; i < size; i++)
400✔
5271
            values[i] = elem_reg;
350✔
5272
         return emit_const_array(lower_type(type), values, size);
50✔
5273
      }
5274
   }
5275
   else if (type_is_record(type)) {
638✔
5276
      assert(type_const_bounds(type));
583✔
5277
      const int nfields = type_fields(type);
583✔
5278
      vcode_type_t vtype = lower_type(type);
583✔
5279

5280
      vcode_reg_t *values LOCAL = xmalloc_array(nfields, sizeof(vcode_reg_t));
1,166✔
5281
      for (int i = 0; i < nfields; i++) {
2,432✔
5282
         type_t ftype = tree_type(type_field(type, i));
1,849✔
5283
         values[i] = lower_nested_default_value(lu, ftype);
1,849✔
5284
      }
5285

5286
      return emit_const_record(vtype, values, nfields);
583✔
5287
   }
5288
   else if (type_is_access(type))
55✔
5289
      return emit_null(lower_type(type));
55✔
5290

5291
   fatal_trace("cannot handle type %s in lower_nested_default_value",
5292
               type_pp(type));
5293
}
5294

5295
static vcode_reg_t lower_default_value(lower_unit_t *lu, type_t type,
11,004✔
5296
                                       vcode_reg_t hint_reg)
5297
{
5298
   if (type_is_scalar(type))
11,004✔
5299
      return lower_scalar_type_left(lu, type);
5,314✔
5300
   else if (type_is_array(type)) {
5,690✔
5301
      assert(!type_is_unconstrained(type));
4,477✔
5302

5303
      type_t elem_type = type_elem_recur(type);
4,477✔
5304

5305
      if (type_const_bounds(type)) {
4,477✔
5306
         if (type_is_scalar(elem_type)) {
1,548✔
5307
            vcode_reg_t elem_reg = lower_nested_default_value(lu, elem_type);
1,507✔
5308
            const int size = lower_array_const_size(type);
1,507✔
5309
            if (hint_reg == VCODE_INVALID_REG) {
1,507✔
5310
               vcode_type_t vtype = lower_type(type);
18✔
5311
               return emit_address_of(emit_const_rep(vtype, elem_reg, size));
18✔
5312
            }
5313
            else {
5314
               vcode_reg_t count_reg = emit_const(vtype_offset(), size);
1,489✔
5315
               vcode_reg_t data_reg = lower_array_data(hint_reg);
1,489✔
5316
               emit_memset(data_reg, elem_reg, count_reg);
1,489✔
5317
               return hint_reg;
1,489✔
5318
            }
5319
         }
5320
         else
5321
            return emit_address_of(lower_nested_default_value(lu, type));
41✔
5322
      }
5323

5324
      vcode_reg_t count_reg = lower_array_total_len(lu, type, hint_reg);
2,929✔
5325
      vcode_reg_t def_reg =
2,929✔
5326
         lower_default_value(lu, elem_type, VCODE_INVALID_REG);
2,929✔
5327

5328
      if (hint_reg == VCODE_INVALID_REG) {
2,929✔
5329
         vcode_type_t velem = lower_type(elem_type);
×
5330
         vcode_type_t vbounds = lower_bounds(elem_type);
×
5331
         hint_reg = emit_alloc(velem, vbounds, count_reg);
×
5332
      }
5333

5334
      vcode_reg_t data_reg = lower_array_data(hint_reg);
2,929✔
5335

5336
      if (type_is_scalar(elem_type))
2,929✔
5337
         emit_memset(data_reg, def_reg, count_reg);
2,882✔
5338
      else {
5339
         // Loop to initialise the array
5340
         vcode_type_t voffset = vtype_offset();
47✔
5341
         vcode_var_t i_var = lower_temp_var(lu, "i", voffset, voffset);
47✔
5342
         emit_store(emit_const(voffset, 0), i_var);
47✔
5343

5344
         vcode_block_t body_bb = emit_block();
47✔
5345
         vcode_block_t exit_bb = emit_block();
47✔
5346

5347
         vcode_block_t null_reg = emit_cmp(VCODE_CMP_EQ, count_reg,
47✔
5348
                                           emit_const(voffset, 0));
5349
         emit_cond(null_reg, exit_bb, body_bb);
47✔
5350

5351
         vcode_select_block(body_bb);
47✔
5352

5353
         vcode_reg_t i_reg = emit_load(i_var);
47✔
5354
         vcode_reg_t ptr_reg = emit_array_ref(data_reg, i_reg);
47✔
5355

5356
         if (type_is_scalar(elem_type))
47✔
5357
            emit_store_indirect(def_reg, ptr_reg);
×
5358
         else if (type_is_record(elem_type))
47✔
5359
            lower_new_record(lu, elem_type, ptr_reg, def_reg);
47✔
5360
         else
5361
            emit_store_indirect(def_reg, ptr_reg);
×
5362

5363
         vcode_reg_t next_reg = emit_add(i_reg, emit_const(voffset, 1));
47✔
5364
         emit_store(next_reg, i_var);
47✔
5365

5366
         vcode_reg_t done_reg = emit_cmp(VCODE_CMP_EQ, next_reg, count_reg);
47✔
5367
         emit_cond(done_reg, exit_bb, body_bb);
47✔
5368

5369
         vcode_select_block(exit_bb);
47✔
5370
         lower_release_temp(lu, i_var);
47✔
5371
      }
5372

5373
      return hint_reg;
2,929✔
5374
   }
5375
   else if (type_is_record(type)) {
1,213✔
5376
      if (type_const_bounds(type))
583✔
5377
         return emit_address_of(lower_nested_default_value(lu, type));
392✔
5378

5379
      type_t base = type_base_recur(type);
191✔
5380
      const int nfields = type_fields(base);
191✔
5381
      vcode_type_t vtype = lower_type(type);
191✔
5382

5383
      vcode_reg_t mem_reg = hint_reg;
191✔
5384
      if (hint_reg == VCODE_INVALID_REG) {
191✔
5385
         vcode_var_t tmp_var = lower_temp_var(lu, "def", vtype, vtype);
33✔
5386
         mem_reg = emit_index(tmp_var, VCODE_INVALID_REG);
33✔
5387
      }
5388

5389
      for (int i = 0; i < nfields; i++) {
572✔
5390
         tree_t f = type_field(base, i);
381✔
5391
         vcode_reg_t ptr_reg = emit_record_ref(mem_reg, i);
381✔
5392

5393
         type_t ftype = tree_type(f);
381✔
5394
         if (base != type && type_is_unconstrained(ftype)) {
381✔
5395
            tree_t ec = type_constraint_for_field(type, f);
175✔
5396
            assert(ec != NULL);
175✔
5397
            ftype = tree_type(ec);
175✔
5398
         }
5399

5400
         if (type_is_scalar(ftype)) {
381✔
5401
            vcode_reg_t def_reg = lower_default_value(lu, ftype, ptr_reg);
106✔
5402
            emit_store_indirect(def_reg, ptr_reg);
106✔
5403
         }
5404
         else if (type_is_array(ftype)) {
275✔
5405
            if (have_uarray_ptr(ptr_reg)) {
257✔
5406
               // Need to allocate memory for the array
5407
               type_t elem_type = type_elem_recur(ftype);
254✔
5408
               vcode_type_t vtype = lower_type(elem_type);
254✔
5409
               vcode_type_t vbounds = lower_bounds(elem_type);
254✔
5410

5411
               vcode_reg_t count_reg =
254✔
5412
                  lower_array_total_len(lu, ftype, VCODE_INVALID_REG);
254✔
5413
               vcode_reg_t mem_reg = emit_alloc(vtype, vbounds, count_reg);
254✔
5414
               vcode_reg_t def_reg = lower_default_value(lu, ftype, mem_reg);
254✔
5415
               assert(def_reg == mem_reg);
254✔
5416

5417
               vcode_reg_t wrap_reg =
254✔
5418
                  lower_wrap_with_new_bounds(lu, ftype, tree_type(f),
254✔
5419
                                             def_reg, mem_reg);
5420
               emit_store_indirect(wrap_reg, ptr_reg);
254✔
5421
            }
5422
            else {
5423
               vcode_reg_t def_reg = lower_default_value(lu, ftype, ptr_reg);
3✔
5424
               vcode_reg_t count_reg =
3✔
5425
                  lower_array_total_len(lu, ftype, VCODE_INVALID_REG);
3✔
5426
               emit_copy(ptr_reg, def_reg, count_reg);
3✔
5427
            }
5428
         }
5429
         else if (type_is_record(ftype)) {
18✔
5430
            vcode_reg_t def_reg =
15✔
5431
               lower_default_value(lu, ftype, VCODE_INVALID_REG);
15✔
5432

5433
            emit_copy(ptr_reg, def_reg, VCODE_INVALID_REG);
15✔
5434
         }
5435
         else {
5436
            vcode_reg_t def_reg = lower_default_value(lu, ftype, ptr_reg);
3✔
5437
            emit_store_indirect(def_reg, ptr_reg);
3✔
5438
         }
5439
      }
5440

5441
      return mem_reg;
5442
   }
5443
   else if (type_is_access(type))
630✔
5444
      return emit_null(lower_type(type));
630✔
5445
   else
5446
      fatal_trace("cannot handle type %s in lower_default_value",
5447
                  type_pp(type));
5448
}
5449

5450
static void lower_report(lower_unit_t *lu, tree_t stmt)
1,989✔
5451
{
5452
   lower_stmt_coverage(lu, stmt);
1,989✔
5453

5454
   vcode_reg_t severity_reg = VCODE_INVALID_REG;
1,989✔
5455
   if (tree_has_severity(stmt))
1,989✔
5456
      severity_reg = lower_rvalue(lu, tree_severity(stmt));
405✔
5457
   else {
5458
      vcode_type_t vseverity = vtype_int(0, 3);
1,584✔
5459
      severity_reg = emit_const(vseverity, SEVERITY_NOTE);
1,584✔
5460
   }
5461

5462
   vcode_reg_t message = VCODE_INVALID_REG, length = VCODE_INVALID_REG;
1,989✔
5463
   if (tree_has_message(stmt)) {
1,989✔
5464
      tree_t m = tree_message(stmt);
1,989✔
5465

5466
      vcode_reg_t message_wrapped = lower_rvalue(lu, m);
1,989✔
5467
      message = lower_array_data(message_wrapped);
1,989✔
5468
      length  = lower_array_len(lu, tree_type(m), 0, message_wrapped);
1,989✔
5469
   }
5470

5471
   vcode_reg_t locus = lower_debug_locus(stmt);
1,989✔
5472
   emit_report(message, length, severity_reg, locus);
1,989✔
5473
}
1,989✔
5474

5475
static bool lower_can_hint_assert(tree_t expr)
10,342✔
5476
{
5477
   if (tree_kind(expr) != T_FCALL)
10,342✔
5478
      return false;
5479

5480
   switch (tree_subkind(tree_ref(expr))) {
9,789✔
5481
   case S_SCALAR_EQ:
5482
   case S_SCALAR_NEQ:
5483
   case S_SCALAR_LT:
5484
   case S_SCALAR_LE:
5485
   case S_SCALAR_GT:
5486
   case S_SCALAR_GE:
5487
      return true;
5488
   default:
3,903✔
5489
      return false;
3,903✔
5490
   }
5491
}
5492

5493
static void lower_assert(lower_unit_t *lu, tree_t stmt)
14,028✔
5494
{
5495
   lower_stmt_coverage(lu, stmt);
14,028✔
5496

5497
   tree_t value = tree_value(stmt);
14,028✔
5498

5499
   vcode_reg_t value_reg,
14,028✔
5500
      hint_left_reg = VCODE_INVALID_REG,
14,028✔
5501
      hint_right_reg = VCODE_INVALID_REG;
14,028✔
5502

5503
   if (!tree_has_message(stmt) && lower_can_hint_assert(value))
14,028✔
5504
      value_reg = lower_builtin(lu, value, tree_subkind(tree_ref(value)),
5,886✔
5505
                                &hint_left_reg, &hint_right_reg);
5506
   else
5507
      value_reg = lower_rvalue(lu, value);
8,142✔
5508

5509
   int64_t value_const;
14,028✔
5510
   if (vcode_reg_const(value_reg, &value_const) && value_const)
14,028✔
5511
      return;
150✔
5512

5513
   vcode_block_t fail_bb = VCODE_INVALID_BLOCK;
13,878✔
5514
   vcode_block_t exit_bb = VCODE_INVALID_BLOCK;
13,878✔
5515

5516
   tree_t message = tree_has_message(stmt) ? tree_message(stmt) : NULL;
13,878✔
5517
   tree_t severity = tree_has_severity(stmt) ? tree_severity(stmt) : NULL;
13,878✔
5518

5519
   // If evaluating the message or severity expressions can have side
5520
   // effects then branch to a new block
5521
   const bool has_side_effects =
27,756✔
5522
      (message != NULL && !lower_side_effect_free(message))
3,682✔
5523
      || (severity != NULL && !lower_side_effect_free(severity));
16,955✔
5524

5525
   if (has_side_effects) {
13,878✔
5526
      fail_bb = emit_block();
636✔
5527
      exit_bb = emit_block();
636✔
5528
      emit_cond(value_reg, exit_bb, fail_bb);
636✔
5529
      vcode_select_block(fail_bb);
636✔
5530
   }
5531

5532
   vcode_reg_t message_reg = VCODE_INVALID_REG, length_reg = VCODE_INVALID_REG;
13,878✔
5533
   if (message != NULL) {
13,878✔
5534
      vcode_reg_t message_wrapped = lower_rvalue(lu, message);
3,682✔
5535
      message_reg = lower_array_data(message_wrapped);
3,682✔
5536
      length_reg  = lower_array_len(lu, tree_type(message), 0, message_wrapped);
3,682✔
5537
   }
5538

5539
   vcode_reg_t severity_reg = VCODE_INVALID_REG;
13,878✔
5540
   if (severity != NULL)
13,878✔
5541
      severity_reg = lower_rvalue(lu, severity);
3,387✔
5542
   else {
5543
      vcode_type_t vseverity = vtype_int(0, 3);
10,491✔
5544
      severity_reg = emit_const(vseverity, SEVERITY_ERROR);
10,491✔
5545
   }
5546

5547
   vcode_reg_t locus = lower_debug_locus(value);
13,878✔
5548
   emit_assert(value_reg, message_reg, length_reg, severity_reg, locus,
13,878✔
5549
               hint_left_reg, hint_right_reg);
5550

5551
   if (exit_bb != VCODE_INVALID_BLOCK) {
13,878✔
5552
      emit_jump(exit_bb);
636✔
5553
      vcode_select_block(exit_bb);
636✔
5554
   }
5555
}
5556

5557
static void lower_sched_event_field_cb(lower_unit_t *lu, tree_t field,
1,560✔
5558
                                       vcode_reg_t ptr, vcode_reg_t unused,
5559
                                       vcode_reg_t locus, void *ctx)
5560
{
5561
   type_t type = tree_type(field);
1,560✔
5562
   if (!type_is_homogeneous(type))
1,560✔
5563
      lower_for_each_field(lu, type, ptr, locus,
12✔
5564
                           lower_sched_event_field_cb, ctx);
5565
   else {
5566
      vcode_reg_t nets_reg = emit_load_indirect(ptr);
1,548✔
5567
      vcode_reg_t data_reg = lower_array_data(nets_reg);
1,548✔
5568
      vcode_reg_t count_reg = lower_type_width(lu, type, nets_reg);
1,548✔
5569

5570
      const bool clear = (uintptr_t)ctx;
1,548✔
5571
      if (clear)
1,548✔
5572
         emit_clear_event(data_reg, count_reg);
13✔
5573
      else
5574
         emit_sched_event(data_reg, count_reg);
1,535✔
5575
   }
5576
}
1,560✔
5577

5578
static void lower_sched_event(lower_unit_t *lu, tree_t on)
4,463✔
5579
{
5580
   type_t type = tree_type(on);
4,463✔
5581

5582
   vcode_reg_t nets_reg = lower_lvalue(lu, on);
4,463✔
5583
   assert(nets_reg != VCODE_INVALID_REG);
4,463✔
5584

5585
   if (!type_is_homogeneous(type))
4,463✔
5586
      lower_for_each_field(lu, type, nets_reg, VCODE_INVALID_REG,
584✔
5587
                           lower_sched_event_field_cb, NULL);
5588
   else {
5589
      vcode_reg_t count_reg = lower_type_width(lu, type, nets_reg);
3,879✔
5590
      vcode_reg_t data_reg = lower_array_data(nets_reg);
3,879✔
5591
      emit_sched_event(data_reg, count_reg);
3,879✔
5592
   }
5593
}
4,463✔
5594

5595
static void lower_clear_event(lower_unit_t *lu, tree_t on)
498✔
5596
{
5597
   type_t type = tree_type(on);
498✔
5598

5599
   vcode_reg_t nets_reg = lower_lvalue(lu, on);
498✔
5600
   assert(nets_reg != VCODE_INVALID_REG);
498✔
5601

5602
   if (!type_is_homogeneous(type))
498✔
5603
      lower_for_each_field(lu, type, nets_reg, VCODE_INVALID_REG,
4✔
5604
                           lower_sched_event_field_cb, (void *)1);
5605
   else {
5606
      vcode_reg_t count_reg = lower_type_width(lu, type, nets_reg);
494✔
5607
      vcode_reg_t data_reg = lower_array_data(nets_reg);
494✔
5608
      emit_clear_event(data_reg, count_reg);
494✔
5609
   }
5610
}
498✔
5611

5612
static vcode_reg_t lower_call_now(void)
24✔
5613
{
5614
   ident_t func = ident_new("STD.STANDARD.NOW()25STD.STANDARD.DELAY_LENGTH");
24✔
5615
   vcode_type_t rtype = vtype_time();
24✔
5616
   vcode_reg_t context_reg = emit_link_package(well_known(W_STD_STANDARD));
24✔
5617
   vcode_reg_t args[1] = { context_reg };
24✔
5618
   return emit_fcall(func, rtype, rtype, args, ARRAY_LEN(args));
24✔
5619
}
5620

5621
static void lower_wait(lower_unit_t *lu, tree_t wait)
12,914✔
5622
{
5623
   const bool is_static = !!(tree_flags(wait) & TREE_F_STATIC_WAIT);
12,914✔
5624
   assert(!is_static || (!tree_has_delay(wait) && !tree_has_value(wait)));
12,914✔
5625

5626
   const int ntriggers = tree_triggers(wait);
12,914✔
5627

5628
   if (!is_static) {
12,914✔
5629
      lower_stmt_coverage(lu, wait);
9,149✔
5630

5631
      // The _sched_event for static waits is emitted in the reset block
5632
      for (int i = 0; i < ntriggers; i++)
9,647✔
5633
         lower_sched_event(lu, tree_trigger(wait, i));
498✔
5634
   }
5635

5636
   const bool has_delay = tree_has_delay(wait);
12,914✔
5637
   const bool has_value = tree_has_value(wait);
12,914✔
5638

5639
   vcode_reg_t delay = VCODE_INVALID_REG;
12,914✔
5640
   if (has_delay)
12,914✔
5641
      delay = lower_rvalue(lu, tree_delay(wait));
4,957✔
5642

5643
   vcode_var_t remain = VCODE_INVALID_VAR;
12,914✔
5644
   if (has_value && has_delay) {
12,914✔
5645
      ident_t remain_i = ident_new("wait_remain");
12✔
5646
      remain = vcode_find_var(remain_i);
12✔
5647
      if (remain == VCODE_INVALID_VAR) {
12✔
5648
         vcode_type_t time = vtype_time();
12✔
5649
         remain = emit_var(time, time, remain_i, 0);
12✔
5650
      }
5651

5652
      vcode_reg_t now_reg = lower_call_now();
12✔
5653
      vcode_reg_t abs_reg = emit_add(now_reg, delay);
12✔
5654
      emit_store(abs_reg, remain);
12✔
5655
   }
5656

5657
   vcode_block_t resume = emit_block();
12,914✔
5658
   emit_wait(resume, delay);
12,914✔
5659

5660
   vcode_select_block(resume);
12,914✔
5661

5662
   if (!is_static) {
12,914✔
5663
      for (int i = 0; i < ntriggers; i++)
9,647✔
5664
         lower_clear_event(lu, tree_trigger(wait, i));
498✔
5665
   }
5666

5667
   if (has_value) {
12,914✔
5668
      // Generate code to loop until condition is met
5669

5670
      vcode_reg_t until_reg = lower_rvalue(lu, tree_value(wait));
277✔
5671

5672
      vcode_reg_t timeout_reg = VCODE_INVALID_REG;
277✔
5673
      vcode_reg_t done_reg = until_reg;
277✔
5674
      if (has_delay) {
277✔
5675
         vcode_reg_t remain_reg = emit_load(remain);
12✔
5676
         vcode_reg_t now_reg = lower_call_now();
12✔
5677
         timeout_reg = emit_sub(remain_reg, now_reg);
12✔
5678

5679
         vcode_reg_t expired_reg = emit_cmp(VCODE_CMP_EQ, timeout_reg,
12✔
5680
                                            emit_const(vtype_time(), 0));
5681
         done_reg = emit_or(expired_reg, until_reg);
12✔
5682
      }
5683

5684
      vcode_block_t done_bb  = emit_block();
277✔
5685
      vcode_block_t again_bb = emit_block();
277✔
5686

5687
      emit_cond(done_reg, done_bb, again_bb);
277✔
5688

5689
      vcode_select_block(again_bb);
277✔
5690

5691
      for (int i = 0; i < ntriggers; i++)
560✔
5692
         lower_sched_event(lu, tree_trigger(wait, i));
283✔
5693

5694
      emit_wait(resume, timeout_reg);
277✔
5695

5696
      vcode_select_block(done_bb);
277✔
5697
   }
5698
}
12,914✔
5699

5700
static void lower_check_array_sizes(lower_unit_t *lu, type_t ltype,
20,951✔
5701
                                    type_t rtype, vcode_reg_t lval,
5702
                                    vcode_reg_t rval, vcode_reg_t locus)
5703
{
5704
   const int ndims = dimension_of(ltype);
20,951✔
5705
   for (int i = 0; i < ndims; i++) {
42,861✔
5706
      vcode_reg_t llen_reg = lower_array_len(lu, ltype, i, lval);
21,910✔
5707
      vcode_reg_t rlen_reg = lower_array_len(lu, rtype, i, rval);
21,910✔
5708

5709
      vcode_reg_t dim_reg = VCODE_INVALID_REG;
21,910✔
5710
      if (ndims > 1)
21,910✔
5711
         dim_reg = emit_const(vtype_offset(), i + 1);
1,769✔
5712

5713
      emit_length_check(llen_reg, rlen_reg, locus, dim_reg);
21,910✔
5714
   }
5715
}
20,951✔
5716

5717
static void lower_find_matching_refs(tree_t ref, void *context)
1,879✔
5718
{
5719
   tree_t *decl = (tree_t *)context;
1,879✔
5720
   if (tree_ref(ref) == *decl)
1,879✔
5721
      *decl = NULL;
21✔
5722
}
1,879✔
5723

5724
static bool lower_can_hint_aggregate(tree_t target, tree_t value)
13,656✔
5725
{
5726
   if (tree_kind(value) != T_AGGREGATE)
13,656✔
5727
      return false;
5728

5729
   type_t type = tree_type(target);
1,431✔
5730
   if (!type_const_bounds(type))
1,431✔
5731
      return false;
5732

5733
   tree_t ref = name_to_ref(target);
833✔
5734
   if (ref == NULL)
833✔
5735
      return false;
5736

5737
   tree_t decl = tree_ref(ref);
833✔
5738
   tree_visit_only(value, lower_find_matching_refs, &decl, T_REF);
833✔
5739
   return decl != NULL;
833✔
5740
}
5741

5742
static bool lower_can_hint_concat(tree_t target, tree_t value)
13,111✔
5743
{
5744
   if (tree_kind(value) != T_FCALL)
13,111✔
5745
      return false;
5746

5747
   tree_t fdecl = tree_ref(value);
3,538✔
5748
   if (tree_subkind(fdecl) != S_CONCAT)
3,538✔
5749
      return false;
5750

5751
   if (!type_const_bounds(tree_type(target)))
140✔
5752
      return false;
5753

5754
   tree_t ref = name_to_ref(target);
93✔
5755
   if (ref == NULL)
93✔
5756
      return false;
5757

5758
   tree_t decl = tree_ref(ref);
93✔
5759
   tree_visit_only(value, lower_find_matching_refs, &decl, T_REF);
93✔
5760
   return decl != NULL;
93✔
5761
}
5762

5763
static int lower_count_target_parts(tree_t target, int depth)
8,643✔
5764
{
5765
   if (tree_kind(target) == T_AGGREGATE) {
8,643✔
5766
      int count = 0;
132✔
5767
      const int nassocs = tree_assocs(target);
132✔
5768
      for (int i = 0; i < nassocs; i++) {
456✔
5769
         tree_t value = tree_value(tree_assoc(target, i));
324✔
5770
         count += lower_count_target_parts(value, depth + 1);
324✔
5771
      }
5772

5773
      return count + (depth > 0 ? 2 : 1);
246✔
5774
   }
5775
   else
5776
      return depth == 0 ? 2 : 1;
8,511✔
5777
}
5778

5779
static void lower_fill_target_parts(lower_unit_t *lu, tree_t target,
8,643✔
5780
                                    part_kind_t kind, target_part_t **ptr)
5781
{
5782
   type_t target_type = tree_type(target);
8,643✔
5783

5784
   if (tree_kind(target) == T_AGGREGATE) {
8,643✔
5785
      const bool is_record = type_is_record(target_type);
132✔
5786
      const int ndims = dimension_of(target_type);
132✔
5787

5788
      if (kind != PART_ALL) {
132✔
5789
         (*ptr)->reg    = VCODE_INVALID_REG;
18✔
5790
         (*ptr)->off    = VCODE_INVALID_REG;
18✔
5791
         (*ptr)->target = NULL;
18✔
5792
         (*ptr)->kind   = kind == PART_FIELD ? PART_PUSH_FIELD : PART_PUSH_ELEM;
18✔
5793
         ++(*ptr);
18✔
5794
      }
5795

5796
      vcode_reg_t sum_reg = emit_const(vtype_offset(), 0);
132✔
5797

5798
      const int nassocs = tree_assocs(target);
132✔
5799
      for (int i = 0; i < nassocs; i++) {
456✔
5800
         tree_t value = tree_value(tree_assoc(target, i));
324✔
5801

5802
         part_kind_t newkind;
324✔
5803
         if (is_record)
324✔
5804
            newkind = PART_FIELD;
5805
         else if (ndims == 1 && type_eq(tree_type(value), target_type))
231✔
5806
            newkind = PART_SLICE;
5807
         else
5808
            newkind = PART_ELEM;
5809

5810
         lower_fill_target_parts(lu, value, newkind, ptr);
324✔
5811

5812
         vcode_reg_t len_reg;
324✔
5813
         if (newkind == PART_SLICE)
324✔
5814
            len_reg = (*ptr - 1)->off;
42✔
5815
         else
5816
            len_reg = emit_const(vtype_offset(), 1);
282✔
5817

5818
         sum_reg = emit_add(sum_reg, len_reg);
324✔
5819
      }
5820

5821
      (*ptr)->reg    = VCODE_INVALID_REG;
132✔
5822
      (*ptr)->off    = sum_reg;
132✔
5823
      (*ptr)->target = NULL;
132✔
5824
      (*ptr)->kind   = PART_POP;
132✔
5825
      ++(*ptr);
132✔
5826
   }
5827
   else {
5828
      (*ptr)->reg    = lower_lvalue(lu, target);
8,511✔
5829
      (*ptr)->target = target;
8,511✔
5830
      (*ptr)->kind   = kind;
8,511✔
5831

5832
      if (type_is_array(target_type))
8,511✔
5833
         (*ptr)->off = lower_array_total_len(lu, target_type, (*ptr)->reg);
1,924✔
5834
      else
5835
         (*ptr)->off = emit_const(vtype_offset(), 1);
6,587✔
5836

5837
      ++(*ptr);
8,511✔
5838

5839
      if (kind == PART_ALL) {
8,511✔
5840
         (*ptr)->reg    = VCODE_INVALID_REG;
8,205✔
5841
         (*ptr)->off    = (*ptr - 1)->off;
8,205✔
5842
         (*ptr)->target = NULL;
8,205✔
5843
         (*ptr)->kind   = PART_POP;
8,205✔
5844
         ++(*ptr);
8,205✔
5845
      }
5846
   }
5847
}
8,643✔
5848

5849
static void lower_copy_record(lower_unit_t *lu, type_t type,
433✔
5850
                              vcode_reg_t dst_ptr, vcode_reg_t src_ptr,
5851
                              vcode_reg_t locus)
5852
{
5853
   if (dst_ptr == src_ptr)
433✔
5854
      return;
5855
   else if (lower_trivially_copyable(type))
340✔
5856
      emit_copy(dst_ptr, src_ptr, VCODE_INVALID_REG);
285✔
5857
   else {
5858
      ident_t base_id = type_ident(type_base_recur(type));
55✔
5859
      ident_t helper_func = ident_prefix(base_id, ident_new("copy"), '$');
55✔
5860

5861
      vcode_reg_t args[] = {
55✔
5862
         lower_context_for_call(lu, helper_func),
55✔
5863
         dst_ptr,
5864
         src_ptr,
5865
         locus
5866
      };
5867
      emit_fcall(helper_func, VCODE_INVALID_TYPE, VCODE_INVALID_TYPE,
55✔
5868
                 args, ARRAY_LEN(args));
5869
   }
5870
}
5871

5872
static void lower_copy_array(lower_unit_t *lu, type_t dst_type, type_t src_type,
5,039✔
5873
                             vcode_reg_t dst_array, vcode_reg_t src_array,
5874
                             vcode_reg_t locus)
5875
{
5876
   if (dst_array == src_array)
5,039✔
5877
      return;
5878
   else if (lower_trivially_copyable(dst_type)) {
4,956✔
5879
      lower_check_array_sizes(lu, dst_type, src_type, dst_array,
4,947✔
5880
                              src_array, locus);
5881

5882
      vcode_reg_t count_reg = lower_array_total_len(lu, dst_type, dst_array);
4,947✔
5883

5884
      vcode_reg_t src_data = lower_array_data(src_array);
4,947✔
5885
      vcode_reg_t dst_data = lower_array_data(dst_array);
4,947✔
5886
      emit_copy(dst_data, src_data, count_reg);
4,947✔
5887
   }
5888
   else {
5889
      ident_t base_id = type_ident(type_base_recur(dst_type));
9✔
5890
      ident_t helper_func = ident_prefix(base_id, ident_new("copy"), '$');
9✔
5891

5892
      assert(vcode_reg_kind(dst_array) == VCODE_TYPE_UARRAY);
9✔
5893
      assert(vcode_reg_kind(src_array) == VCODE_TYPE_UARRAY);
9✔
5894

5895
      vcode_reg_t args[] = {
9✔
5896
         lower_context_for_call(lu, helper_func),
9✔
5897
         dst_array,
5898
         src_array,
5899
         locus
5900
      };
5901
      emit_fcall(helper_func, VCODE_INVALID_TYPE, VCODE_INVALID_TYPE,
9✔
5902
                 args, ARRAY_LEN(args));
5903
   }
5904
}
5905

5906
static void lower_var_assign_target(lower_unit_t *lu, target_part_t **ptr,
63✔
5907
                                    tree_t where, vcode_reg_t rhs,
5908
                                    type_t rhs_type)
5909
{
5910
   int fieldno = 0;
63✔
5911
   for (const target_part_t *p = (*ptr)++; p->kind != PART_POP; p = (*ptr)++) {
210✔
5912
      vcode_reg_t src_reg = rhs;
147✔
5913
      type_t src_type = rhs_type;
147✔
5914
      if (p->kind == PART_FIELD || p->kind == PART_PUSH_FIELD) {
147✔
5915
         assert(vcode_reg_kind(rhs) == VCODE_TYPE_POINTER);
39✔
5916
         src_reg = emit_record_ref(rhs, fieldno);
39✔
5917
         src_type = tree_type(type_field(src_type, fieldno));
39✔
5918
         fieldno++;
39✔
5919
      }
5920

5921
      if (p->kind == PART_PUSH_FIELD || p->kind == PART_PUSH_ELEM) {
147✔
5922
         lower_var_assign_target(lu, ptr, where, src_reg, src_type);
9✔
5923
         continue;
9✔
5924
      }
5925
      else if (p->reg == VCODE_INVALID_REG)
138✔
5926
         continue;
×
5927

5928
      if (p->kind == PART_ELEM)
138✔
5929
         src_type = type_elem(src_type);
84✔
5930

5931
      type_t type = tree_type(p->target);
138✔
5932

5933
      if (p->kind != PART_SLICE && type_is_array(type)) {
138✔
5934
         vcode_reg_t locus = lower_debug_locus(p->target);
15✔
5935
         lower_check_array_sizes(lu, type, src_type, p->reg, src_reg, locus);
15✔
5936
      }
5937

5938
      if (p->kind == PART_ELEM || p->kind == PART_SLICE)
138✔
5939
         src_reg = lower_array_data(src_reg);
105✔
5940

5941
      vcode_reg_t scalar_reg = src_reg;
138✔
5942
      if ((p->kind == PART_ELEM || p->kind == PART_FIELD)
138✔
5943
          && !type_is_composite(type))
117✔
5944
         scalar_reg = emit_load_indirect(src_reg);
102✔
5945

5946
      if (type_is_scalar(type)) {
138✔
5947
         lower_check_scalar_bounds(lu, scalar_reg, type, where, p->target);
96✔
5948
         emit_store_indirect(scalar_reg, p->reg);
96✔
5949
      }
5950
      else if (type_is_array(type)) {
42✔
5951
         vcode_reg_t data_reg = lower_array_data(src_reg);
36✔
5952
         vcode_reg_t count_reg = lower_array_total_len(lu, type, p->reg);
36✔
5953
         vcode_reg_t dest_reg = lower_array_data(p->reg);
36✔
5954

5955
         emit_copy(dest_reg, data_reg, count_reg);
36✔
5956
      }
5957
      else if (type_is_record(type)) {
6✔
5958
         vcode_reg_t locus = lower_debug_locus(where);
×
5959
         lower_copy_record(lu, type, p->reg, src_reg, locus);
×
5960
      }
5961
      else
5962
         emit_store_indirect(scalar_reg, p->reg);
6✔
5963

5964
      if (p->kind == PART_ELEM || p->kind == PART_SLICE) {
138✔
5965
         assert(vcode_reg_kind(src_reg) == VCODE_TYPE_POINTER);
105✔
5966
         rhs = emit_array_ref(src_reg, p->off);
105✔
5967
      }
5968
   }
5969
}
63✔
5970

5971
static void lower_var_assign(lower_unit_t *lu, tree_t stmt)
12,841✔
5972
{
5973
   tree_t value  = tree_value(stmt);
12,841✔
5974
   tree_t target = tree_target(stmt);
12,841✔
5975
   type_t type   = tree_type(target);
12,841✔
5976

5977
   lower_stmt_coverage(lu, stmt);
12,841✔
5978

5979
   const bool is_var_decl =
25,682✔
5980
      tree_kind(target) == T_REF && tree_kind(tree_ref(target)) == T_VAR_DECL;
12,841✔
5981
   const bool is_scalar = type_is_scalar(type);
12,841✔
5982
   const bool is_access = type_is_access(type);
12,841✔
5983

5984
   if (is_scalar || is_access) {
12,841✔
5985
      vcode_reg_t value_reg = lower_rvalue(lu, value);
7,484✔
5986
      vcode_var_t var = VCODE_INVALID_VAR;
7,484✔
5987
      int hops = 0;
7,484✔
5988
      if (is_scalar)
7,484✔
5989
         lower_check_scalar_bounds(lu, value_reg, type, value, target);
6,900✔
5990
      else
5991
         value_reg = lower_incomplete_access(value_reg, type_designated(type));
584✔
5992

5993
      if (is_var_decl
7,484✔
5994
          && (var = lower_get_var(lu, tree_ref(target),
4,591✔
5995
                                  &hops)) != VCODE_INVALID_VAR
5996
          && hops == 0)
4,585✔
5997
         emit_store(value_reg, var);
4,402✔
5998
      else {
5999
         vcode_reg_t ptr_reg = lower_lvalue(lu, target);
3,082✔
6000
         emit_store_indirect(value_reg, ptr_reg);
3,082✔
6001
      }
6002
   }
6003
   else if (tree_kind(target) == T_AGGREGATE) {
5,357✔
6004
      const int nparts = lower_count_target_parts(target, 0);
48✔
6005
      target_part_t *parts LOCAL = xmalloc_array(nparts, sizeof(target_part_t));
96✔
6006

6007
      target_part_t *ptr = parts;
48✔
6008
      lower_fill_target_parts(lu, target, PART_ALL, &ptr);
48✔
6009
      assert(ptr == parts + nparts);
48✔
6010

6011
      vcode_reg_t rhs = lower_rvalue(lu, value);
48✔
6012

6013
      if (type_is_array(type)) {
48✔
6014
         vcode_reg_t rhs_len = lower_array_len(lu, tree_type(value), 0, rhs);
39✔
6015
         vcode_reg_t locus = lower_debug_locus(target);
39✔
6016
         assert(parts[nparts - 1].kind == PART_POP);
39✔
6017
         emit_length_check(parts[nparts - 1].off, rhs_len, locus,
39✔
6018
                           VCODE_INVALID_REG);
6019
      }
6020

6021
      ptr = parts;
48✔
6022
      lower_var_assign_target(lu, &ptr, value, rhs, tree_type(value));
48✔
6023
      assert(ptr == parts + nparts);
48✔
6024
   }
6025
   else if (type_is_array(type)) {
5,309✔
6026
      vcode_reg_t target_reg = lower_lvalue(lu, target);
4,993✔
6027

6028
      vcode_reg_t value_reg;
4,993✔
6029
      if (lower_can_hint_aggregate(target, value))
4,993✔
6030
         value_reg = lower_aggregate(lu, value, lower_array_data(target_reg));
273✔
6031
      else if (lower_can_hint_concat(target, value)) {
4,720✔
6032
         vcode_reg_t hint_reg = lower_array_data(target_reg);
37✔
6033
         vcode_reg_t count_reg = lower_array_total_len(lu, type, target_reg);
37✔
6034
         value_reg = lower_concat(lu, value, hint_reg, count_reg);
37✔
6035
      }
6036
      else
6037
         value_reg = lower_known_subtype(lu, value, type, target_reg);
4,683✔
6038

6039
      vcode_reg_t locus = lower_debug_locus(target);
4,993✔
6040

6041
      type_t value_type = tree_type(value);
4,993✔
6042
      lower_copy_array(lu, type, value_type, target_reg, value_reg, locus);
4,993✔
6043
   }
6044
   else {
6045
      vcode_reg_t target_reg = lower_lvalue(lu, target);
316✔
6046

6047
      vcode_reg_t value_reg;
316✔
6048
      if (lower_can_hint_aggregate(target, value))
316✔
6049
         value_reg = lower_aggregate(lu, value, target_reg);
34✔
6050
      else
6051
         value_reg = lower_known_subtype(lu, value, type, target_reg);
282✔
6052

6053
      vcode_reg_t locus = lower_debug_locus(stmt);
316✔
6054
      lower_copy_record(lu, type, target_reg, value_reg, locus);
316✔
6055
   }
6056
}
12,841✔
6057

6058
static void lower_signal_target_field_cb(lower_unit_t *lu, tree_t field,
2,806✔
6059
                                         vcode_reg_t dst_ptr,
6060
                                         vcode_reg_t src_ptr,
6061
                                         vcode_reg_t locus, void *__ctx)
6062
{
6063
   type_t type = tree_type(field);
2,806✔
6064
   vcode_reg_t *args = __ctx;
2,806✔
6065

6066
   if (!type_is_homogeneous(type))
2,806✔
6067
      lower_for_each_field_2(lu, type, type, dst_ptr, src_ptr, locus,
89✔
6068
                             lower_signal_target_field_cb, __ctx);
6069
   else if (type_is_array(type)) {
2,717✔
6070
      vcode_reg_t src_array = VCODE_INVALID_REG;
702✔
6071
      vcode_reg_t dst_array = VCODE_INVALID_REG;
702✔
6072

6073
      vcode_reg_t nets_reg;
702✔
6074
      if (have_uarray_ptr(dst_ptr)) {
702✔
6075
         dst_array = emit_load_indirect(dst_ptr);
102✔
6076
         nets_reg  = lower_array_data(dst_array);
102✔
6077
      }
6078
      else
6079
         nets_reg = emit_load_indirect(dst_ptr);
600✔
6080

6081
      vcode_reg_t array_reg;
702✔
6082
      if (have_uarray_ptr(src_ptr)) {
702✔
6083
         src_array = emit_load_indirect(src_ptr);
102✔
6084
         array_reg = lower_resolved(lu, type, src_array);
102✔
6085
      }
6086
      else
6087
         array_reg = lower_resolved(lu, type, src_ptr);
600✔
6088

6089
      lower_check_array_sizes(lu, type, type, dst_array, src_array, locus);
702✔
6090

6091
      vcode_reg_t count_reg = lower_array_total_len(lu, type, array_reg);
702✔
6092
      vcode_reg_t data_reg  = lower_array_data(array_reg);
702✔
6093
      emit_sched_waveform(nets_reg, count_reg, data_reg,
702✔
6094
                          args[0], args[1]);
6095
   }
6096
   else {
6097
      vcode_reg_t nets_reg = emit_load_indirect(dst_ptr);
2,015✔
6098
      vcode_reg_t data_reg = lower_resolved(lu, type, src_ptr);
2,015✔
6099
      emit_sched_waveform(nets_reg, emit_const(vtype_offset(), 1),
2,015✔
6100
                          data_reg, args[0], args[1]);
6101
   }
6102
}
2,806✔
6103

6104
static void lower_signal_assign_target(lower_unit_t *lu, target_part_t **ptr,
8,572✔
6105
                                       tree_t where, vcode_reg_t rhs,
6106
                                       type_t rhs_type, vcode_reg_t reject,
6107
                                       vcode_reg_t after)
6108
{
6109
   int fieldno = 0;
8,572✔
6110
   for (const target_part_t *p = (*ptr)++; p->kind != PART_POP; p = (*ptr)++) {
17,252✔
6111
      vcode_reg_t src_reg = rhs;
8,680✔
6112
      type_t src_type = rhs_type;
8,680✔
6113
      if (p->kind == PART_FIELD || p->kind == PART_PUSH_FIELD) {
8,680✔
6114
         assert(vcode_reg_kind(rhs) == VCODE_TYPE_POINTER);
54✔
6115
         src_reg = emit_record_ref(rhs, fieldno);
54✔
6116
         src_type = tree_type(type_field(src_type, fieldno));
54✔
6117
         fieldno++;
54✔
6118
      }
6119

6120
      if (p->kind == PART_PUSH_FIELD || p->kind == PART_PUSH_ELEM) {
8,680✔
6121
         lower_signal_assign_target(lu, ptr, where, src_reg, src_type,
9✔
6122
                                    reject, after);
6123
         continue;
9✔
6124
      }
6125
      else if (p->reg == VCODE_INVALID_REG)
8,671✔
6126
         continue;
×
6127

6128
      if (p->kind == PART_ELEM)
8,671✔
6129
         src_type = type_elem(src_type);
99✔
6130

6131
      type_t type = tree_type(p->target);
8,671✔
6132

6133
      if (p->kind != PART_SLICE && type_is_array(type)) {
8,671✔
6134
         vcode_reg_t locus = lower_debug_locus(p->target);
1,943✔
6135
         lower_check_array_sizes(lu, type, src_type, p->reg, src_reg, locus);
1,943✔
6136
      }
6137

6138
      if (p->kind == PART_ELEM || p->kind == PART_SLICE)
8,671✔
6139
         src_reg = lower_array_data(src_reg);
120✔
6140

6141
      if (type_is_scalar(type))
8,671✔
6142
         lower_check_scalar_bounds(lu, src_reg, type, where, p->target);
6,057✔
6143

6144
      if (!type_is_homogeneous(type)) {
8,671✔
6145
         vcode_reg_t args[2] = { reject, after };
790✔
6146
         vcode_reg_t locus = lower_debug_locus(where);
790✔
6147
         lower_for_each_field_2(lu, type, src_type, p->reg, src_reg, locus,
790✔
6148
                                lower_signal_target_field_cb, &args);
6149
      }
6150
      else if (type_is_array(type)) {
7,881✔
6151
         vcode_reg_t resolved_reg = lower_resolved(lu, type, src_reg);
1,824✔
6152
         vcode_reg_t data_reg = lower_array_data(resolved_reg);
1,824✔
6153
         vcode_reg_t count_reg = lower_array_total_len(lu, type, p->reg);
1,824✔
6154
         vcode_reg_t nets_raw = lower_array_data(p->reg);
1,824✔
6155

6156
         emit_sched_waveform(nets_raw, count_reg, data_reg, reject, after);
1,824✔
6157
      }
6158
      else {
6159
         vcode_reg_t data_reg = lower_resolved(lu, type, src_reg);
6,057✔
6160
         emit_sched_waveform(p->reg, emit_const(vtype_offset(), 1),
6,057✔
6161
                             data_reg, reject, after);
6162
      }
6163

6164
      if (p->kind == PART_ELEM || p->kind == PART_SLICE) {
8,671✔
6165
         assert(vcode_reg_kind(src_reg) == VCODE_TYPE_POINTER);
120✔
6166
         rhs = emit_array_ref(src_reg, p->off);
120✔
6167
      }
6168
   }
6169
}
8,572✔
6170

6171
static void lower_disconnect_target(lower_unit_t *lu, target_part_t **ptr,
24✔
6172
                                    vcode_reg_t reject, vcode_reg_t after)
6173
{
6174
   for (const target_part_t *p = (*ptr)++; p->kind != PART_POP; p = (*ptr)++) {
48✔
6175
      if (p->kind == PART_PUSH_FIELD || p->kind == PART_PUSH_ELEM) {
24✔
6176
         lower_disconnect_target(lu, ptr, reject, after);
×
6177
         continue;
×
6178
      }
6179
      else if (p->reg == VCODE_INVALID_REG)
24✔
6180
         continue;
×
6181

6182
      vcode_reg_t nets_reg = lower_array_data(p->reg);
24✔
6183

6184
      type_t type = tree_type(p->target);
24✔
6185

6186
      if (type_is_record(type)) {
24✔
6187
         // XXX: this seems wrong
6188
         const int width = type_width(type);
×
6189
         emit_disconnect(nets_reg, emit_const(vtype_offset(), width),
×
6190
                         reject, after);
6191
      }
6192
      else {
6193
         vcode_reg_t count_reg = lower_type_width(lu, type, p->reg);
24✔
6194
         emit_disconnect(nets_reg, count_reg, reject, after);
24✔
6195
      }
6196
   }
6197
}
24✔
6198

6199
static void lower_signal_assign(lower_unit_t *lu, tree_t stmt)
8,265✔
6200
{
6201
   lower_stmt_coverage(lu, stmt);
8,265✔
6202

6203
   tree_t target = tree_target(stmt);
8,265✔
6204

6205
   const int nparts = lower_count_target_parts(target, 0);
8,265✔
6206
   target_part_t *parts LOCAL = xmalloc_array(nparts, sizeof(target_part_t));
16,530✔
6207

6208
   target_part_t *ptr = parts;
8,265✔
6209
   lower_fill_target_parts(lu, target, PART_ALL, &ptr);
8,265✔
6210
   assert(ptr == parts + nparts);
8,265✔
6211

6212
   const int nwaveforms = tree_waveforms(stmt);
8,265✔
6213
   for (int i = 0; i < nwaveforms; i++) {
16,740✔
6214
      tree_t w = tree_waveform(stmt, i);
8,475✔
6215

6216
      tree_t delay = NULL;
8,475✔
6217
      vcode_reg_t delay_reg;
8,475✔
6218
      if (tree_has_delay(w)) {
8,475✔
6219
         delay = tree_delay(w);
720✔
6220
         delay_reg = lower_rvalue(lu, delay);
720✔
6221
      }
6222
      else
6223
         delay_reg = emit_const(vtype_time(), 0);
7,755✔
6224

6225
      vcode_reg_t reject_reg;
8,475✔
6226
      if (i == 0 && tree_has_reject(stmt)) {
8,475✔
6227
         tree_t reject = tree_reject(stmt);
498✔
6228
         if (reject == delay) {
498✔
6229
            // If delay is the same as reject ensure the expression is
6230
            // only evaluated once
6231
            reject_reg = delay_reg;
6232
         }
6233
         else
6234
            reject_reg = lower_rvalue(lu, reject);
27✔
6235
      }
6236
      else {
6237
         // All but the first waveform have zero reject time
6238
         reject_reg = emit_const(vtype_time(), 0);
7,977✔
6239
      }
6240

6241
      vcode_var_t tmp_var = VCODE_INVALID_VAR;
8,475✔
6242

6243
      target_part_t *ptr = parts;
8,475✔
6244
      if (tree_has_value(w)) {
8,475✔
6245
         tree_t wvalue = tree_value(w);
8,451✔
6246
         type_t wtype = tree_type(wvalue);
8,451✔
6247
         vcode_reg_t rhs = VCODE_INVALID_REG;
8,451✔
6248
         if (ptr->kind == PART_ALL) {
8,451✔
6249
            if (lower_can_hint_concat(ptr->target, wvalue)) {
8,391✔
6250
               type_t ptype = tree_type(ptr->target);
44✔
6251

6252
               vcode_type_t vtype = lower_type(ptype);
44✔
6253
               vcode_type_t vbounds = lower_bounds(ptype);
44✔
6254
               tmp_var = lower_temp_var(lu, "tmp", vtype, vbounds);
44✔
6255

6256
               vcode_reg_t count_reg =
44✔
6257
                  lower_array_total_len(lu, ptype, ptr->reg);
44✔
6258
               vcode_reg_t hint_reg = emit_index(tmp_var, VCODE_INVALID_REG);
44✔
6259
               rhs = lower_concat(lu, wvalue, hint_reg, count_reg);
44✔
6260
            }
6261
            else if (lower_can_hint_aggregate(ptr->target, wvalue)) {
8,347✔
6262
               type_t ptype = tree_type(ptr->target);
517✔
6263

6264
               vcode_type_t vtype = lower_type(ptype);
517✔
6265
               vcode_type_t vbounds = lower_bounds(ptype);
517✔
6266
               tmp_var = lower_temp_var(lu, "tmp", vtype, vbounds);
517✔
6267

6268
               vcode_reg_t hint_reg  = emit_index(tmp_var, VCODE_INVALID_REG);
517✔
6269
               rhs = lower_aggregate(lu, wvalue, hint_reg);
517✔
6270
            }
6271
            else if (type_is_record(wtype) && lower_is_signal_ref(wvalue)) {
7,830✔
6272
               // If the RHS is another record signal we can avoid creating
6273
               // a temporary resolved copy of the whole record by
6274
               // resolving each field individually in the field callback.
6275
               rhs = lower_lvalue(lu, wvalue);
283✔
6276
            }
6277
            else if (standard() >= STD_19) {
7,547✔
6278
               type_t ptype = tree_type(ptr->target);
172✔
6279
               rhs = lower_known_subtype(lu, wvalue, ptype, ptr->reg);
172✔
6280
            }
6281
         }
6282

6283
         if (rhs == VCODE_INVALID_REG)
1,016✔
6284
            rhs = lower_rvalue(lu, wvalue);
7,435✔
6285

6286
         if (ptr->kind != PART_ALL && type_is_array(wtype)) {
8,451✔
6287
            vcode_reg_t rhs_len = lower_array_len(lu, wtype, 0, rhs);
45✔
6288
            vcode_reg_t locus = lower_debug_locus(target);
45✔
6289
            assert(parts[nparts - 1].kind == PART_POP);
45✔
6290
            emit_length_check(parts[nparts - 1].off, rhs_len, locus,
45✔
6291
                              VCODE_INVALID_REG);
6292
         }
6293

6294
         lower_signal_assign_target(lu, &ptr, wvalue, rhs, wtype,
8,451✔
6295
                                    reject_reg, delay_reg);
6296
      }
6297
      else
6298
         lower_disconnect_target(lu, &ptr, reject_reg, delay_reg);
24✔
6299
      assert(ptr == parts + nparts);
8,475✔
6300

6301
      if (tmp_var != VCODE_INVALID_VAR)
8,475✔
6302
         lower_release_temp(lu, tmp_var);
561✔
6303
   }
6304
}
8,265✔
6305

6306
static void lower_force_field_cb(lower_unit_t *lu, tree_t field,
9✔
6307
                                 vcode_reg_t ptr, vcode_reg_t value,
6308
                                 vcode_reg_t locus, void *__ctx)
6309
{
6310
   type_t type = tree_type(field);
9✔
6311
   if (type_is_homogeneous(type)) {
9✔
6312
      vcode_reg_t nets_reg = emit_load_indirect(ptr);
9✔
6313
      vcode_reg_t count_reg = lower_type_width(lu, type, nets_reg);
9✔
6314
      emit_force(lower_array_data(nets_reg), count_reg, value);
9✔
6315
   }
6316
   else
6317
      lower_for_each_field_2(lu, type, type, ptr, value, locus,
×
6318
                             lower_force_field_cb, NULL);
6319
}
9✔
6320

6321
static void lower_force(lower_unit_t *lu, tree_t stmt)
54✔
6322
{
6323
   tree_t target = tree_target(stmt);
54✔
6324
   type_t type = tree_type(target);
54✔
6325

6326
   vcode_reg_t nets = lower_lvalue(lu, target);
54✔
6327

6328
   tree_t value = tree_value(stmt);
54✔
6329
   type_t value_type = tree_type(value);
54✔
6330
   vcode_reg_t value_reg = lower_rvalue(lu, value);
54✔
6331

6332
   if (type_is_array(type)) {
54✔
6333
      vcode_reg_t locus = lower_debug_locus(target);
12✔
6334
      lower_check_array_sizes(lu, type, value_type, nets, value_reg, locus);
12✔
6335

6336
      vcode_reg_t count_reg = lower_array_total_len(lu, type, nets);
12✔
6337
      vcode_reg_t data_reg = lower_array_data(value_reg);
12✔
6338
      emit_force(lower_array_data(nets), count_reg, data_reg);
12✔
6339
   }
6340
   else if (type_is_record(type)) {
42✔
6341
      vcode_reg_t locus = lower_debug_locus(value);
3✔
6342
      lower_for_each_field_2(lu, type, value_type, nets, value_reg, locus,
3✔
6343
                             lower_force_field_cb, NULL);
6344
   }
6345
   else
6346
      emit_force(nets, emit_const(vtype_offset(), 1), value_reg);
39✔
6347
}
54✔
6348

6349
static void lower_release(lower_unit_t *lu, tree_t stmt)
30✔
6350
{
6351
   tree_t target = tree_target(stmt);
30✔
6352
   type_t type = tree_type(target);
30✔
6353

6354
   vcode_reg_t nets = lower_lvalue(lu, target);
30✔
6355

6356
   if (type_is_array(type)) {
30✔
6357
      vcode_reg_t count_reg = lower_array_total_len(lu, type, nets);
6✔
6358
      emit_release(lower_array_data(nets), count_reg);
6✔
6359
   }
6360
   else if (type_is_record(type)) {
24✔
6361
      should_not_reach_here();
6362
   }
6363
   else
6364
      emit_release(nets, emit_const(vtype_offset(), 1));
24✔
6365
}
30✔
6366

6367
static void lower_sequence(lower_unit_t *lu, tree_t block, loop_stack_t *loops)
28,625✔
6368
{
6369
   const int nstmts = tree_stmts(block);
28,625✔
6370
   for (int i = 0; i < nstmts; i++)
103,733✔
6371
      lower_stmt(lu, tree_stmt(block, i), loops);
75,108✔
6372
}
28,625✔
6373

6374
static void lower_if(lower_unit_t *lu, tree_t stmt, loop_stack_t *loops)
5,604✔
6375
{
6376
   lower_stmt_coverage(lu, stmt);
5,604✔
6377

6378
   vcode_block_t exit_bb = VCODE_INVALID_BLOCK;
5,604✔
6379
   const bool want_coverage = cover_enabled(lu->cover, COVER_MASK_BRANCH);
5,604✔
6380

6381
   const int nconds = tree_conds(stmt);
5,604✔
6382
   for (int i = 0; i < nconds; i++) {
11,942✔
6383
      tree_t c = tree_cond(stmt, i);
8,527✔
6384
      vcode_block_t next_bb = VCODE_INVALID_BLOCK;
8,527✔
6385
      PUSH_COVER_SCOPE(lu, c);
17,054✔
6386

6387
      if (tree_has_value(c)) {
8,527✔
6388
         vcode_reg_t test = lower_rvalue(lu, tree_value(c));
6,338✔
6389
         vcode_block_t btrue = emit_block();
6,338✔
6390

6391
         if (i == nconds - 1 && !want_coverage) {
6,338✔
6392
            if (exit_bb == VCODE_INVALID_BLOCK)
3,384✔
6393
               exit_bb = emit_block();
3,271✔
6394
            next_bb = exit_bb;
6395
         }
6396
         else
6397
            next_bb = emit_block();
2,954✔
6398

6399
         emit_cond(test, btrue, next_bb);
6,338✔
6400

6401
         if (want_coverage)
6,338✔
6402
            lower_branch_coverage(lu, c, btrue, next_bb);
181✔
6403

6404
         vcode_select_block(btrue);
6,338✔
6405
      }
6406

6407
      lower_sequence(lu, c, loops);
8,527✔
6408

6409
      if (!vcode_block_finished()) {
8,527✔
6410
         if (exit_bb == VCODE_INVALID_BLOCK)
4,708✔
6411
            exit_bb = emit_block();
1,629✔
6412
         emit_jump(exit_bb);
4,708✔
6413
      }
6414

6415
      if (next_bb == VCODE_INVALID_BLOCK)
8,527✔
6416
         break;
6417

6418
      vcode_select_block(next_bb);
6,338✔
6419

6420
      if (i == nconds - 1 && want_coverage) {
6,338✔
6421
         if (exit_bb == VCODE_INVALID_BLOCK)
31✔
6422
            exit_bb = emit_block();
3✔
6423
         emit_jump(exit_bb);
31✔
6424
      }
6425
   }
6426

6427
   if (exit_bb != VCODE_INVALID_BLOCK)
5,604✔
6428
      vcode_select_block(exit_bb);
4,903✔
6429
}
5,604✔
6430

6431
static void lower_leave_subprogram(lower_unit_t *lu)
11,033✔
6432
{
6433
   // Release resources for protected and file variables
6434

6435
   const int ndecls = tree_decls(lu->container);
11,033✔
6436
   for (int i = 0; i < ndecls; i++) {
28,666✔
6437
      tree_t d = tree_decl(lu->container, i);
17,633✔
6438
      switch (tree_kind(d)) {
17,633✔
6439
      case T_VAR_DECL:
11,377✔
6440
         if (type_is_protected(tree_type(d))) {
11,377✔
6441
            int hops = 0;
7✔
6442
            vcode_var_t var = lower_get_var(lu, d, &hops);
7✔
6443
            assert(var != VCODE_INVALID_VAR);
7✔
6444

6445
            vcode_reg_t obj_reg;
7✔
6446
            if (hops == 0)
7✔
6447
               obj_reg = emit_load(var);
7✔
6448
            else
6449
               obj_reg = emit_load_indirect(emit_var_upref(hops, var));
×
6450

6451
            emit_protected_free(obj_reg);
7✔
6452
         }
6453
         break;
6454

6455
      case T_FILE_DECL:
20✔
6456
         {
6457
            type_t base = type_base_recur(tree_type(d));
20✔
6458

6459
            LOCAL_TEXT_BUF tb = tb_new();
40✔
6460
            tb_istr(tb, ident_runtil(type_ident(base), '.'));
20✔
6461
            tb_cat(tb, ".FILE_CLOSE(");
20✔
6462
            mangle_one_type(tb, base);
20✔
6463
            tb_cat(tb, ")");
20✔
6464
            tb_cat(tb, "$predef");
20✔
6465

6466
            ident_t func = ident_new(tb_get(tb));
20✔
6467

6468
            vcode_reg_t ptr_reg = lower_var_ref(lu, d, EXPR_LVALUE);
20✔
6469
            vcode_reg_t context_reg = lower_context_for_call(lu, func);
20✔
6470
            vcode_reg_t args[] = { context_reg, ptr_reg };
20✔
6471
            emit_fcall(func, VCODE_INVALID_TYPE, VCODE_INVALID_TYPE,
20✔
6472
                       args, ARRAY_LEN(args));
6473
         }
6474
         break;
20✔
6475

6476
      default:
6477
         break;
6478
      }
6479
   }
6480
}
11,033✔
6481

6482
static void lower_return(lower_unit_t *lu, tree_t stmt)
9,538✔
6483
{
6484
   lower_stmt_coverage(lu, stmt);
9,538✔
6485

6486
   if (is_subprogram(lu->container))
9,538✔
6487
      lower_leave_subprogram(lu);
9,538✔
6488

6489
   if (tree_has_value(stmt)) {
9,538✔
6490
      tree_t value = tree_value(stmt);
9,291✔
6491
      type_t type = tree_type(value);
9,291✔
6492

6493
      vcode_reg_t value_reg = lower_rvalue(lu, value);
9,291✔
6494

6495
      if (type_is_scalar(type)) {
9,291✔
6496
         lower_check_scalar_bounds(lu, value_reg, type, value, NULL);
4,871✔
6497
         emit_return(value_reg);
4,871✔
6498
      }
6499
      else if (type_is_access(type)) {
4,420✔
6500
         type_t access = type_designated(type);
92✔
6501
         emit_return(lower_incomplete_access(value_reg, access));
92✔
6502
      }
6503
      else if (type_is_array(type)) {
4,328✔
6504
         type_t rtype = type_result(tree_type(lu->container));
3,646✔
6505
         emit_return(lower_coerce_arrays(lu, type, rtype, value_reg));
3,646✔
6506
      }
6507
      else
6508
         emit_return(value_reg);
682✔
6509
   }
6510
   else
6511
      emit_return(VCODE_INVALID_REG);
247✔
6512
}
9,538✔
6513

6514
static void lower_pcall(lower_unit_t *lu, tree_t pcall)
6,125✔
6515
{
6516
   lower_stmt_coverage(lu, pcall);
6,125✔
6517

6518
   tree_t decl = tree_ref(pcall);
6,125✔
6519

6520
   const subprogram_kind_t kind = tree_subkind(decl);
6,125✔
6521
   if (is_open_coded_builtin(kind)) {
6,125✔
6522
      lower_builtin(lu, pcall, kind, NULL, NULL);
567✔
6523
      return;
567✔
6524
   }
6525

6526
   bool use_fcall;
5,558✔
6527
   switch (vcode_unit_kind(lu->vunit)) {
5,558✔
6528
   case VCODE_UNIT_FUNCTION:
6529
   case VCODE_UNIT_THUNK:
6530
      use_fcall = true;
6531
      break;
6532
   case VCODE_UNIT_PROCESS:
4,127✔
6533
      {
6534
         tree_t wait = tree_stmt(lu->container, tree_stmts(lu->container) - 1);
4,127✔
6535
         if (tree_kind(wait) == T_WAIT
4,127✔
6536
             && (tree_flags(wait) & TREE_F_STATIC_WAIT)) {
3,926✔
6537
            // This process has a sensitivity list and therefore cannot
6538
            // wait inside a procedure
6539
            use_fcall = true;
6540
            break;
6541
         }
6542
      }
6543
      // Fall-through
6544
   default:
6545
      use_fcall = !!(tree_flags(decl) & TREE_F_NEVER_WAITS);
4,234✔
6546
      break;
4,234✔
6547
   }
6548

6549
   const int nparams = tree_params(pcall);
5,558✔
6550
   SCOPED_A(vcode_reg_t) args = AINIT;
11,116✔
6551

6552
   ident_t name = tree_ident2(decl);
5,558✔
6553

6554
   if (tree_kind(pcall) == T_PROT_PCALL && tree_has_name(pcall))
5,558✔
6555
      APUSH(args, lower_rvalue(lu, tree_name(pcall)));
180✔
6556
   else
6557
      APUSH(args, lower_context_for_call(lu, name));
5,378✔
6558

6559
   const int arg0 = args.count;
5,558✔
6560
   for (int i = 0; i < nparams; i++) {
20,054✔
6561
      vcode_reg_t arg_reg = lower_subprogram_arg(lu, pcall, i);
14,496✔
6562
      if (!use_fcall)
14,496✔
6563
         vcode_heap_allocate(arg_reg);
1,361✔
6564

6565
      APUSH(args, arg_reg);
14,496✔
6566
   }
6567

6568
   if (use_fcall)
5,558✔
6569
      emit_fcall(name, VCODE_INVALID_TYPE, VCODE_INVALID_TYPE,
4,675✔
6570
                 args.items, args.count);
4,675✔
6571
   else {
6572
      vcode_block_t resume_bb = emit_block();
883✔
6573

6574
      emit_pcall(name, args.items, args.count, resume_bb);
883✔
6575
      vcode_select_block(resume_bb);
883✔
6576
      emit_resume(name);
883✔
6577
   }
6578

6579
   // Copy any out parameters passed as aggregates
6580
   const int nports = tree_ports(decl);
5,558✔
6581
   for (int i = 0; i < nports; i++) {
20,054✔
6582
      tree_t p = tree_port(decl, i);
14,496✔
6583
      if (tree_class(p) != C_VARIABLE || tree_subkind(p) == PORT_IN)
14,496✔
6584
         continue;
14,490✔
6585

6586
      tree_t value = tree_value(tree_param(pcall, i));
3,420✔
6587
      if (tree_kind(value) != T_AGGREGATE)
3,420✔
6588
         continue;
3,414✔
6589

6590
      const int nparts = lower_count_target_parts(value, 0);
6✔
6591
      target_part_t *parts LOCAL = xmalloc_array(nparts, sizeof(target_part_t));
12✔
6592

6593
      target_part_t *ptr = parts;
6✔
6594
      lower_fill_target_parts(lu, value, PART_ALL, &ptr);
6✔
6595
      assert(ptr == parts + nparts);
6✔
6596

6597
      vcode_reg_t arg_reg = args.items[arg0 + i];
6✔
6598

6599
      ptr = parts;
6✔
6600
      lower_var_assign_target(lu, &ptr, value, arg_reg, tree_type(value));
6✔
6601
      assert(ptr == parts + nparts);
6✔
6602
   }
6603
}
6604

6605
static void lower_wait_free_cb(tree_t t, void *ctx)
31,487✔
6606
{
6607
   int *count = ctx;
31,487✔
6608

6609
   const tree_kind_t kind = tree_kind(t);
31,487✔
6610
   if (kind == T_PCALL || kind == T_PROT_PCALL || kind == T_WAIT)
31,487✔
6611
      (*count)++;
265✔
6612
}
31,487✔
6613

6614
static bool lower_is_wait_free(lower_unit_t *lu, tree_t stmt)
2,201✔
6615
{
6616
   switch (vcode_unit_kind(lu->vunit)) {
2,201✔
6617
   case VCODE_UNIT_PROCEDURE:
831✔
6618
   case VCODE_UNIT_PROCESS:
6619
      {
6620
         int count = 0;
831✔
6621
         tree_visit(stmt, lower_wait_free_cb, &count);
831✔
6622
         return count == 0;
831✔
6623
      }
6624
   default:
6625
      return true;   // Can never wait
6626
   }
6627
}
6628

6629
static void lower_for(lower_unit_t *lu, tree_t stmt, loop_stack_t *loops)
2,210✔
6630
{
6631
   lower_stmt_coverage(lu, stmt);
2,210✔
6632

6633
   tree_t r = tree_range(stmt, 0);
2,210✔
6634
   vcode_reg_t left_reg  = lower_range_left(lu, r);
2,210✔
6635
   vcode_reg_t right_reg = lower_range_right(lu, r);
2,210✔
6636
   vcode_reg_t dir_reg   = lower_range_dir(lu, r);
2,210✔
6637
   vcode_reg_t null_reg  = emit_range_null(left_reg, right_reg, dir_reg);
2,210✔
6638

6639
   vcode_block_t exit_bb = VCODE_INVALID_BLOCK;
2,210✔
6640

6641
   int64_t null_const;
2,210✔
6642
   if (vcode_reg_const(null_reg, &null_const) && null_const)
2,210✔
6643
      return;   // Loop range is always null
9✔
6644
   else {
6645
      vcode_block_t init_bb = emit_block();
2,201✔
6646
      exit_bb = emit_block();
2,201✔
6647
      emit_cond(null_reg, exit_bb, init_bb);
2,201✔
6648
      vcode_select_block(init_bb);
2,201✔
6649
   }
6650

6651
   tree_t idecl = tree_decl(stmt, 0);
2,201✔
6652

6653
   vcode_type_t vtype  = lower_type(tree_type(idecl));
2,201✔
6654
   vcode_type_t bounds = vtype;
2,201✔
6655

6656
   vcode_reg_t step_down = emit_const(vtype, -1);
2,201✔
6657
   vcode_reg_t step_up   = emit_const(vtype, 1);
2,201✔
6658
   vcode_reg_t step_reg  = emit_select(dir_reg, step_down, step_up);
2,201✔
6659

6660
   // If the body of the loop may wait we need to store the bounds in a
6661
   // variable as the range is evaluated only on entry to the loop
6662
   const bool is_wait_free = lower_is_wait_free(lu, stmt);
2,201✔
6663
   vcode_var_t right_var = VCODE_INVALID_VAR, step_var = VCODE_INVALID_VAR;
2,201✔
6664
   if (!is_wait_free) {
2,201✔
6665
      right_var = lower_temp_var(lu, "right", vtype, vtype);
202✔
6666
      emit_store(right_reg, right_var);
202✔
6667

6668
      step_var = lower_temp_var(lu, "step", vtype, vtype);
202✔
6669
      emit_store(step_reg, step_var);
202✔
6670
   }
6671

6672
   int64_t lconst, rconst, dconst;
2,201✔
6673
   const bool l_is_const = vcode_reg_const(left_reg, &lconst);
2,201✔
6674
   const bool r_is_const = vcode_reg_const(right_reg, &rconst);
2,201✔
6675
   if (l_is_const && r_is_const)
2,201✔
6676
      bounds = vtype_int(MIN(lconst, rconst), MAX(lconst, rconst));
1,077✔
6677
   else if ((l_is_const || r_is_const) && vcode_reg_const(dir_reg, &dconst)) {
1,124✔
6678
      if (dconst == RANGE_TO)
350✔
6679
         bounds = vtype_int(l_is_const ? lconst : vtype_low(vtype),
630✔
6680
                            r_is_const ? rconst : vtype_high(vtype));
315✔
6681
      else
6682
         bounds = vtype_int(r_is_const ? rconst : vtype_low(vtype),
66✔
6683
                            l_is_const ? lconst : vtype_high(vtype));
31✔
6684
   }
6685

6686
   ident_t ident = ident_prefix(tree_ident(idecl), tree_ident(stmt), '.');
2,201✔
6687
   vcode_var_t ivar = emit_var(vtype, bounds, ident, 0);
2,201✔
6688

6689
   emit_store(left_reg, ivar);
2,201✔
6690

6691
   vcode_block_t body_bb = emit_block();
2,201✔
6692
   emit_jump(body_bb);
2,201✔
6693
   vcode_select_block(body_bb);
2,201✔
6694

6695
   vcode_reg_t ireg = VCODE_INVALID_VAR;
2,201✔
6696
   if (is_wait_free) {
2,201✔
6697
      ireg = emit_load(ivar);
1,999✔
6698
      lower_put_vcode_obj(idecl, ireg, lu);
1,999✔
6699
   }
6700
   else
6701
      lower_put_vcode_obj(idecl, ivar | PARAM_VAR_BIT, lu);
202✔
6702

6703
   if (exit_bb == VCODE_INVALID_BLOCK)
2,201✔
6704
      exit_bb = emit_block();
×
6705

6706
   loop_stack_t this = {
2,201✔
6707
      .up      = loops,
6708
      .name    = tree_ident(stmt),
2,201✔
6709
      .test_bb = VCODE_INVALID_BLOCK,
6710
      .exit_bb = exit_bb
6711
   };
6712

6713
   lower_sequence(lu, stmt, &this);
2,201✔
6714

6715
   if (this.test_bb != VCODE_INVALID_BLOCK) {
2,201✔
6716
      // Loop body contained a "next" statement
6717
      if (!vcode_block_finished())
17✔
6718
         emit_jump(this.test_bb);
16✔
6719
      vcode_select_block(this.test_bb);
17✔
6720
   }
6721

6722
   vcode_reg_t rightn_reg = right_reg;
2,201✔
6723
   if (right_var != VCODE_INVALID_VAR)
2,201✔
6724
      rightn_reg = emit_load(right_var);
202✔
6725

6726
   vcode_reg_t stepn_reg = step_reg;
2,201✔
6727
   if (step_var != VCODE_INVALID_VAR)
2,201✔
6728
      stepn_reg = emit_load(step_var);
202✔
6729

6730
   if (ireg == VCODE_INVALID_REG)
2,201✔
6731
      ireg = emit_load(ivar);
202✔
6732

6733
   if (!vcode_block_finished()) {
2,201✔
6734
      vcode_reg_t next_reg = emit_add(ireg, stepn_reg);
2,200✔
6735
      emit_store(next_reg, ivar);
2,200✔
6736

6737
      vcode_reg_t done_reg = emit_cmp(VCODE_CMP_EQ, ireg, rightn_reg);
2,200✔
6738
      emit_cond(done_reg, exit_bb, body_bb);
2,200✔
6739
   }
6740

6741
   vcode_select_block(exit_bb);
2,201✔
6742

6743
   if (!is_wait_free) {
2,201✔
6744
      lower_release_temp(lu, right_var);
202✔
6745
      lower_release_temp(lu, step_var);
202✔
6746
   }
6747
}
6748

6749
static void lower_while(lower_unit_t *lu, tree_t stmt, loop_stack_t *loops)
183✔
6750
{
6751
   lower_stmt_coverage(lu, stmt);
183✔
6752

6753
   vcode_block_t test_bb = emit_block();
183✔
6754
   vcode_block_t body_bb = emit_block();
183✔
6755
   vcode_block_t exit_bb = emit_block();
183✔
6756

6757
   emit_jump(test_bb);
183✔
6758

6759
   vcode_select_block(test_bb);
183✔
6760

6761
   vcode_reg_t test = lower_rvalue(lu, tree_value(stmt));
183✔
6762

6763
   emit_cond(test, body_bb, exit_bb);
183✔
6764

6765
   if (cover_enabled(lu->cover, COVER_MASK_BRANCH))
183✔
6766
      lower_branch_coverage(lu, stmt, body_bb, exit_bb);
×
6767

6768
   vcode_select_block(body_bb);
183✔
6769

6770
   loop_stack_t this = {
183✔
6771
      .up      = loops,
6772
      .name    = tree_ident(stmt),
183✔
6773
      .test_bb = test_bb,
6774
      .exit_bb = exit_bb
6775
   };
6776

6777
   lower_sequence(lu, stmt, &this);
183✔
6778

6779
   if (!vcode_block_finished())
183✔
6780
      emit_jump(test_bb);
183✔
6781

6782
   vcode_select_block(exit_bb);
183✔
6783
}
183✔
6784

6785
static void lower_loop(lower_unit_t *lu, tree_t stmt, loop_stack_t *loops)
101✔
6786
{
6787
   lower_stmt_coverage(lu, stmt);
101✔
6788

6789
   vcode_block_t body_bb = emit_block();
101✔
6790
   vcode_block_t exit_bb = emit_block();
101✔
6791

6792
   emit_jump(body_bb);
101✔
6793

6794
   vcode_select_block(body_bb);
101✔
6795

6796
   loop_stack_t this = {
101✔
6797
      .up      = loops,
6798
      .name    = tree_ident(stmt),
101✔
6799
      .test_bb = body_bb,
6800
      .exit_bb = exit_bb
6801
   };
6802

6803
   lower_sequence(lu, stmt, &this);
101✔
6804

6805
   if (!vcode_block_finished())
101✔
6806
      emit_jump(body_bb);
101✔
6807

6808
   vcode_select_block(exit_bb);
101✔
6809
}
101✔
6810

6811
static void lower_loop_control(lower_unit_t *lu, tree_t stmt,
279✔
6812
                               loop_stack_t *loops)
6813
{
6814
   lower_stmt_coverage(lu, stmt);
279✔
6815

6816
   vcode_block_t false_bb = emit_block();
279✔
6817

6818
   if (tree_has_value(stmt)) {
279✔
6819
      vcode_block_t true_bb = emit_block();
137✔
6820
      vcode_reg_t result = lower_rvalue(lu, tree_value(stmt));
137✔
6821

6822
      emit_cond(result, true_bb, false_bb);
137✔
6823

6824
      if (cover_enabled(lu->cover, COVER_MASK_BRANCH))
137✔
6825
         lower_branch_coverage(lu, stmt, true_bb, false_bb);
×
6826

6827
      vcode_select_block(true_bb);
137✔
6828
   }
6829

6830
   ident_t label = tree_ident2(stmt);
279✔
6831
   loop_stack_t *it;
279✔
6832
   for (it = loops; it != NULL && it->name != label; it = it->up)
567✔
6833
      ;
6834
   assert(it != NULL);
279✔
6835

6836
   if (tree_kind(stmt) == T_EXIT)
279✔
6837
      emit_jump(it->exit_bb);
241✔
6838
   else {
6839
      if (it->test_bb == VCODE_INVALID_BLOCK)
38✔
6840
         it->test_bb = emit_block();
17✔
6841
      emit_jump(it->test_bb);
38✔
6842
   }
6843

6844
   vcode_select_block(false_bb);
279✔
6845
}
279✔
6846

6847
static void lower_case_scalar(lower_unit_t *lu, tree_t stmt,
260✔
6848
                              loop_stack_t *loops)
6849
{
6850
   const int nstmts = tree_stmts(stmt);
260✔
6851
   const bool want_coverage = cover_enabled(lu->cover, COVER_MASK_BRANCH);
260✔
6852

6853
   vcode_block_t def_bb = VCODE_INVALID_BLOCK;
260✔
6854
   vcode_block_t exit_bb = emit_block();
260✔
6855

6856
   vcode_reg_t value_reg = lower_rvalue(lu, tree_value(stmt));
260✔
6857

6858
   int nchoices = 0;
260✔
6859
   for (int i = 0; i < nstmts; i++) {
1,410✔
6860
      tree_t alt = tree_stmt(stmt, i);
1,150✔
6861

6862
      const int nassocs = tree_assocs(alt);
1,150✔
6863
      nchoices += nassocs;
1,150✔
6864

6865
      for (int j = 0; j < nassocs; j++) {
2,692✔
6866
         tree_t a = tree_assoc(alt, j);
1,542✔
6867

6868
         // Pre-filter range choices in case the number of elements is large
6869
         if (tree_subkind(a) == A_RANGE) {
1,542✔
6870
            tree_t r = tree_range(a, 0);
17✔
6871
            vcode_reg_t left_reg = lower_range_left(lu, r);
17✔
6872
            vcode_reg_t right_reg = lower_range_right(lu, r);
17✔
6873

6874
            const range_kind_t dir = tree_subkind(r);
17✔
6875
            vcode_reg_t low_reg = dir == RANGE_TO ? left_reg : right_reg;
17✔
6876
            vcode_reg_t high_reg = dir == RANGE_TO ? right_reg : left_reg;
17✔
6877

6878
            vcode_reg_t lcmp_reg = emit_cmp(VCODE_CMP_GEQ, value_reg, low_reg);
17✔
6879
            vcode_reg_t hcmp_reg = emit_cmp(VCODE_CMP_LEQ, value_reg, high_reg);
17✔
6880
            vcode_reg_t hit_reg = emit_and(lcmp_reg, hcmp_reg);
17✔
6881

6882
            vcode_block_t skip_bb = emit_block();
17✔
6883
            vcode_block_t hit_bb = emit_block();
17✔
6884

6885
            emit_cond(hit_reg, hit_bb, skip_bb);
17✔
6886

6887
            if (want_coverage) {
17✔
6888
               PUSH_COVER_SCOPE(lu, a);
2✔
6889
               lower_branch_coverage(lu, a, hit_bb, VCODE_INVALID_BLOCK);
1✔
6890
            }
6891

6892
            vcode_select_block(hit_bb);
17✔
6893

6894
            lower_sequence(lu, alt, loops);
17✔
6895

6896
            if (!vcode_block_finished())
17✔
6897
               emit_jump(exit_bb);
17✔
6898

6899
            vcode_select_block(skip_bb);
17✔
6900
         }
6901
      }
6902
   }
6903

6904
   vcode_block_t start_bb = vcode_active_block();
260✔
6905

6906
   vcode_reg_t *cases LOCAL = xcalloc_array(nchoices, sizeof(vcode_reg_t));
520✔
6907
   vcode_block_t *blocks LOCAL = xcalloc_array(nchoices, sizeof(vcode_block_t));
520✔
6908

6909
   int cptr = 0;
260✔
6910
   for (int i = 0; i < nstmts; i++) {
1,410✔
6911
      tree_t alt = tree_stmt(stmt, i);
1,150✔
6912
      vcode_block_t hit_bb = VCODE_INVALID_BLOCK;
1,150✔
6913

6914
      const int nassocs = tree_assocs(alt);
1,150✔
6915
      for (int j = 0; j < nassocs; j++) {
2,692✔
6916
         tree_t a = tree_assoc(alt, j);
1,542✔
6917
         const assoc_kind_t kind = tree_subkind(a);
1,542✔
6918

6919
         if (kind == A_RANGE)
1,542✔
6920
            continue;    // Handled separately above
17✔
6921

6922
         PUSH_COVER_SCOPE(lu, a);
3,050✔
6923

6924
         if (hit_bb == VCODE_INVALID_BLOCK)
1,525✔
6925
            hit_bb = emit_block();
1,136✔
6926

6927
         // Must track each branch cover item separately
6928
         vcode_block_t cover_bb = hit_bb;
1,525✔
6929
         if (want_coverage && nassocs > 1)
1,525✔
6930
            cover_bb = emit_block();
5✔
6931

6932
         if (kind == A_OTHERS) {
1,525✔
6933
            assert(def_bb == VCODE_INVALID_BLOCK);
192✔
6934
            if (want_coverage) {
192✔
6935
               def_bb = cover_bb;
16✔
6936
               lower_branch_coverage(lu, a, cover_bb, VCODE_INVALID_BLOCK);
16✔
6937
            }
6938
            else
6939
               def_bb = hit_bb;
6940
         }
6941
         else {
6942
            vcode_select_block(start_bb);
1,333✔
6943
            cases[cptr] = lower_rvalue(lu, tree_name(a));
1,333✔
6944

6945
            if (want_coverage) {
1,333✔
6946
               blocks[cptr] = cover_bb;
77✔
6947
               lower_branch_coverage(lu, a, cover_bb, VCODE_INVALID_BLOCK);
77✔
6948
            }
6949
            else
6950
               blocks[cptr] = hit_bb;
1,256✔
6951

6952
            cptr++;
1,333✔
6953
         }
6954

6955
         if (cover_bb != hit_bb) {
1,525✔
6956
            vcode_select_block(cover_bb);
5✔
6957
            emit_jump(hit_bb);
5✔
6958
         }
6959
      }
6960

6961
      if (hit_bb == VCODE_INVALID_BLOCK)
1,150✔
6962
         continue;
14✔
6963

6964
      vcode_select_block(hit_bb);
1,136✔
6965

6966
      lower_sequence(lu, alt, loops);
1,136✔
6967

6968
      if (!vcode_block_finished())
1,136✔
6969
         emit_jump(exit_bb);
879✔
6970
   }
6971

6972
   assert(cptr <= nchoices);
260✔
6973

6974
   if (def_bb == VCODE_INVALID_BLOCK)
260✔
6975
      def_bb = exit_bb;
68✔
6976

6977
   vcode_select_block(start_bb);
260✔
6978

6979
   emit_case(value_reg, def_bb, cases, blocks, cptr);
260✔
6980
   vcode_select_block(exit_bb);
260✔
6981
}
260✔
6982

6983
static void lower_case_array(lower_unit_t *lu, tree_t stmt, loop_stack_t *loops)
86✔
6984
{
6985
   vcode_type_t vint64 = vtype_int(INT64_MIN, INT64_MAX);
86✔
6986
   vcode_type_t voffset = vtype_offset();
86✔
6987

6988
   tree_t value = tree_value(stmt);
86✔
6989
   type_t type = tree_type(value);
86✔
6990
   vcode_reg_t val_reg = lower_rvalue(lu, tree_value(stmt));
86✔
6991
   vcode_reg_t data_ptr = lower_array_data(val_reg);
86✔
6992

6993
   vcode_block_t def_bb   = VCODE_INVALID_BLOCK;
86✔
6994
   vcode_block_t exit_bb  = emit_block();
86✔
6995
   vcode_block_t hit_bb   = VCODE_INVALID_BLOCK;
86✔
6996
   vcode_block_t start_bb = vcode_active_block();
86✔
6997

6998
   int64_t length = INT64_MAX;
86✔
6999
   if (type_is_unconstrained(type)
86✔
7000
       || !folded_length(range_of(type, 0), &length)) {
77✔
7001
      vcode_reg_t length_reg = lower_array_len(lu, type, 0, val_reg);
12✔
7002

7003
      // Need a runtime check of expression length against choice length
7004
      vcode_reg_t c0_length_reg;
12✔
7005
      tree_t a0 = tree_assoc(tree_stmt(stmt, 0), 0);
12✔
7006
      if (tree_subkind(a0) == A_NAMED) {
12✔
7007
         tree_t c0 = tree_name(a0);
12✔
7008
         vcode_reg_t c0_reg = lower_rvalue(lu, c0);
12✔
7009
         c0_length_reg = lower_array_len(lu, tree_type(c0), 0, c0_reg);
12✔
7010
      }
7011
      else
7012
         c0_length_reg = length_reg;   // Only others choice
7013

7014
      if (!vcode_reg_const(length_reg, &length)) {
12✔
7015
         if (!vcode_reg_const(c0_length_reg, &length)) {
6✔
7016
            error_at(tree_loc(stmt), "cannot determine length of "
×
7017
                     "case expression");
7018
            return;
×
7019
         }
7020
      }
7021

7022
      vcode_reg_t locus = lower_debug_locus(stmt);
12✔
7023
      emit_length_check(c0_length_reg, length_reg, locus, VCODE_INVALID_REG);
12✔
7024
   }
7025

7026
   type_t base = type_base_recur(type_elem(type));
86✔
7027
   assert(type_kind(base) == T_ENUM);
86✔
7028

7029
   const int nbits = ilog2(type_enum_literals(base));
86✔
7030
   const bool exact_map = length * nbits <= 64;
86✔
7031

7032
   // Limit the number of cases branches we generate so it can be
7033
   // efficiently implemented with a jump table
7034
   static const int max_cases = 256;
86✔
7035

7036
   if (!exact_map) {
86✔
7037
      // Hash function may have collisions so need to emit calls to
7038
      // comparison function
7039
      if (vcode_reg_kind(val_reg) != VCODE_TYPE_UARRAY)
6✔
7040
         val_reg = lower_wrap(lu, type, val_reg);
3✔
7041
   }
7042

7043
   vcode_type_t enc_type = VCODE_INVALID_TYPE;
86✔
7044
   vcode_reg_t enc_reg = VCODE_INVALID_REG;
86✔
7045
   if (exact_map && length <= 4) {
86✔
7046
      // Unroll the encoding calculation
7047
      enc_type = voffset;
67✔
7048
      enc_reg = emit_const(enc_type, 0);
67✔
7049
      for (int64_t i = 0; i < length; i++) {
299✔
7050
         vcode_reg_t i_reg = emit_const(voffset, i);
232✔
7051
         vcode_reg_t ptr_reg = emit_array_ref(data_ptr, i_reg);
232✔
7052
         vcode_reg_t byte_reg = emit_load_indirect(ptr_reg);
232✔
7053
         enc_reg = emit_mul(enc_reg, emit_const(enc_type, 1 << nbits));
232✔
7054
         enc_reg = emit_add(enc_reg, emit_cast(enc_type, enc_type, byte_reg));
232✔
7055
      }
7056
   }
7057
   else {
7058
      enc_type = vint64;
19✔
7059
      vcode_var_t enc_var = lower_temp_var(lu, "enc", enc_type, enc_type);
19✔
7060
      emit_store(emit_const(enc_type, 0), enc_var);
19✔
7061

7062
      vcode_var_t i_var = lower_temp_var(lu, "i", voffset, voffset);
19✔
7063
      emit_store(emit_const(voffset, 0), i_var);
19✔
7064

7065
      vcode_block_t body_bb = emit_block();
19✔
7066
      vcode_block_t exit_bb = start_bb = emit_block();
19✔
7067

7068
      emit_jump(body_bb);
19✔
7069

7070
      vcode_select_block(body_bb);
19✔
7071

7072
      vcode_reg_t i_reg    = emit_load(i_var);
19✔
7073
      vcode_reg_t ptr_reg  = emit_array_ref(data_ptr, i_reg);
19✔
7074
      vcode_reg_t byte_reg = emit_load_indirect(ptr_reg);
19✔
7075
      vcode_reg_t tmp_reg  = emit_load(enc_var);
19✔
7076

7077
      if (exact_map)
19✔
7078
         tmp_reg = emit_mul(tmp_reg, emit_const(enc_type, 1 << nbits));
13✔
7079
      else
7080
         tmp_reg = emit_mul(tmp_reg, emit_const(enc_type, 0x27d4eb2d));
6✔
7081
      tmp_reg = emit_add(tmp_reg, emit_cast(enc_type, enc_type, byte_reg));
19✔
7082
      emit_store(tmp_reg, enc_var);
19✔
7083

7084
      vcode_reg_t i_next = emit_add(i_reg, emit_const(voffset, 1));
19✔
7085
      emit_store(i_next, i_var);
19✔
7086

7087
      vcode_reg_t done_reg = emit_cmp(VCODE_CMP_EQ, i_next,
19✔
7088
                                      emit_const(voffset, length));
7089
      emit_cond(done_reg, exit_bb, body_bb);
19✔
7090

7091
      vcode_select_block(exit_bb);
19✔
7092

7093
      enc_reg = emit_load(enc_var);
19✔
7094

7095
      if (!exact_map)
19✔
7096
         enc_reg = emit_rem(enc_reg, emit_const(enc_type, max_cases));
6✔
7097

7098
      lower_release_temp(lu, i_var);
19✔
7099
      lower_release_temp(lu, enc_var);
19✔
7100
   }
7101

7102
   int nchoices = 0;
86✔
7103
   const int nstmts = tree_stmts(stmt);
86✔
7104
   for (int i = 0; i < nstmts; i++)
642✔
7105
      nchoices += tree_assocs(tree_stmt(stmt, i));
556✔
7106

7107
   vcode_reg_t *cases LOCAL = xcalloc_array(nchoices, sizeof(vcode_reg_t));
172✔
7108
   vcode_block_t *blocks LOCAL = xcalloc_array(nchoices, sizeof(vcode_block_t));
172✔
7109
   int64_t *encoding LOCAL = xcalloc_array(nchoices, sizeof(int64_t));
172✔
7110

7111
   ident_t cmp_func = NULL;
86✔
7112
   vcode_type_t vbool = vtype_bool();
86✔
7113
   vcode_block_t fallthrough_bb = VCODE_INVALID_BLOCK;
86✔
7114

7115
   if (!exact_map) {
86✔
7116
      fallthrough_bb = emit_block();
6✔
7117
      cmp_func = lower_predef_func_name(tree_type(value), "=");
6✔
7118
   }
7119

7120
   int cptr = 0;
86✔
7121
   for (int i = 0; i < nstmts; i++) {
642✔
7122
      tree_t alt = tree_stmt(stmt, i);
556✔
7123

7124
      const int nassocs = tree_assocs(alt);
556✔
7125
      for (int j = 0; j < nassocs; j++) {
1,142✔
7126
         tree_t a = tree_assoc(alt, j);
586✔
7127
         const assoc_kind_t kind = tree_subkind(a);
586✔
7128
         assert(kind != A_RANGE);
586✔
7129

7130
         hit_bb = emit_block();
586✔
7131

7132
         PUSH_COVER_SCOPE(lu, a);
1,172✔
7133

7134
         if (kind == A_OTHERS) {
586✔
7135
            assert(def_bb == VCODE_INVALID_BLOCK);
76✔
7136
            def_bb = hit_bb;
76✔
7137

7138
             if (cover_enabled(lu->cover, COVER_MASK_BRANCH))
76✔
7139
                lower_branch_coverage(lu, a, hit_bb, VCODE_INVALID_BLOCK);
6✔
7140
         }
7141
         else {
7142
            tree_t name = tree_name(a);
510✔
7143
            const int exact_bits = exact_map ? nbits : 0;
510✔
7144
            int64_t enc = encode_case_choice(name, length, exact_bits);
510✔
7145
            if (!exact_map) enc %= max_cases;
510✔
7146

7147
            vcode_block_t entry_bb = hit_bb;
510✔
7148
            bool have_dup = false;
510✔
7149
            if (!exact_map) {
510✔
7150
               // There may be collisions in the hash function
7151
               vcode_block_t chain_bb = fallthrough_bb;
513✔
7152
               for (int k = 0; k < cptr; k++) {
513✔
7153
                  if (encoding[k] == enc) {
459✔
7154
                     chain_bb  = blocks[k];
3✔
7155
                     blocks[k] = hit_bb;
3✔
7156
                     have_dup  = true;
3✔
7157
                     break;
3✔
7158
                  }
7159
               }
7160

7161
               vcode_select_block(hit_bb);
57✔
7162
               hit_bb = emit_block();
57✔
7163

7164
               vcode_reg_t name_reg = lower_rvalue(lu, name);
57✔
7165
               if (vcode_reg_kind(name_reg) != VCODE_TYPE_UARRAY)
57✔
7166
                  name_reg = lower_wrap(lu, tree_type(name), name_reg);
57✔
7167

7168
               vcode_reg_t context_reg = lower_context_for_call(lu, cmp_func);
57✔
7169
               vcode_reg_t args[] = { context_reg, name_reg, val_reg };
57✔
7170
               vcode_reg_t eq_reg = emit_fcall(cmp_func, vbool, vbool, args, 3);
57✔
7171
               emit_cond(eq_reg, hit_bb, chain_bb);
57✔
7172
            }
7173

7174
            if (!have_dup) {
510✔
7175
               vcode_select_block(start_bb);
507✔
7176
               cases[cptr]    = emit_const(enc_type, enc);
507✔
7177
               blocks[cptr]   = entry_bb;
507✔
7178
               encoding[cptr] = enc;
507✔
7179

7180
               // TODO: How to handle have_dup == true ?
7181
               if (cover_enabled(lu->cover, COVER_MASK_BRANCH))
507✔
7182
                  lower_branch_coverage(lu, a, hit_bb, VCODE_INVALID_BLOCK);
51✔
7183

7184
               cptr++;
507✔
7185
            }
7186
         }
7187

7188
         vcode_select_block(hit_bb);
586✔
7189

7190
         lower_sequence(lu, alt, loops);
586✔
7191

7192
         if (!vcode_block_finished())
586✔
7193
            emit_jump(exit_bb);
454✔
7194
      }
7195
   }
7196

7197
   assert(cptr <= nchoices);
86✔
7198

7199
   if (def_bb == VCODE_INVALID_BLOCK)
86✔
7200
      def_bb = exit_bb;
10✔
7201

7202
   if (fallthrough_bb != VCODE_INVALID_BLOCK) {
86✔
7203
      vcode_select_block(fallthrough_bb);
6✔
7204
      emit_jump(def_bb);
6✔
7205
   }
7206

7207
   vcode_select_block(start_bb);
86✔
7208

7209
   emit_case(enc_reg, def_bb, cases, blocks, cptr);
86✔
7210

7211
   vcode_select_block(exit_bb);
86✔
7212
}
7213

7214
static void lower_case(lower_unit_t *lu, tree_t stmt, loop_stack_t *loops)
346✔
7215
{
7216
   lower_stmt_coverage(lu, stmt);
346✔
7217

7218
   if (type_is_scalar(tree_type(tree_value(stmt))))
346✔
7219
      lower_case_scalar(lu, stmt, loops);
260✔
7220
   else
7221
      lower_case_array(lu, stmt, loops);
86✔
7222
}
346✔
7223

7224
static void lower_match_case(lower_unit_t *lu, tree_t stmt, loop_stack_t *loops)
36✔
7225
{
7226
   vcode_block_t exit_bb = VCODE_INVALID_BLOCK;
36✔
7227

7228
   tree_t value = tree_value(stmt);
36✔
7229
   type_t type = tree_type(value);
36✔
7230

7231
   const bool is_array = type_is_array(type);
36✔
7232
   type_t scalar = is_array ? type_elem(type) : type;
36✔
7233

7234
   if (type_eq(scalar, std_type(NULL, STD_BIT))) {
36✔
7235
      // The "?=" operator on BIT is the same as "=" so just use a
7236
      // normal case statement
7237
      lower_case(lu, stmt, loops);
6✔
7238
      return;
6✔
7239
   }
7240

7241
   vcode_reg_t value_reg = lower_rvalue(lu, value);
30✔
7242
   if (is_array && vcode_reg_kind(value_reg) != VCODE_TYPE_UARRAY)
30✔
7243
      value_reg = lower_wrap(lu, type, value_reg);
21✔
7244

7245
   // Call support function to check argument does not contain '-'
7246
   {
7247
      ident_t func = ident_new(
36✔
7248
         is_array ? "NVC.IEEE_SUPPORT.CHECK_MATCH_EXPRESSION(Y)"
7249
         : "NVC.IEEE_SUPPORT.CHECK_MATCH_EXPRESSION(U)");
7250
      vcode_reg_t context_reg = lower_context_for_call(lu, func);
30✔
7251

7252
      vcode_reg_t args[] = { context_reg, value_reg };
30✔
7253
      emit_fcall(func, VCODE_INVALID_REG, VCODE_INVALID_REG,
30✔
7254
                 args, ARRAY_LEN(args));
7255
   }
7256

7257
   ident_t func = ident_new(is_array ? "IEEE.STD_LOGIC_1164.\"?=\"(YY)U$predef"
36✔
7258
                            : "IEEE.STD_LOGIC_1164.\"?=\"(UU)U$predef");
7259
   vcode_reg_t context_reg = lower_context_for_call(lu, func);
30✔
7260

7261
   vcode_type_t vscalar = lower_type(scalar);
30✔
7262
   vcode_reg_t true_reg = emit_const(vscalar, 3);  // STD_LOGIC'POS('1')
30✔
7263

7264
   const int nstmts = tree_stmts(stmt);
30✔
7265
   for (int i = 0; i < nstmts; i++) {
147✔
7266
      tree_t alt = tree_stmt(stmt, i);
117✔
7267

7268
      vcode_block_t hit_bb = emit_block();
117✔
7269
      vcode_block_t skip_bb = VCODE_INVALID_BLOCK;
117✔
7270

7271
      const int nassocs = tree_assocs(alt);
117✔
7272
      for (int j = 0; j < nassocs; j++) {
237✔
7273
         vcode_block_t loop_bb = VCODE_INVALID_BLOCK;
120✔
7274
         vcode_reg_t test_reg = VCODE_INVALID_REG;
120✔
7275
         vcode_var_t tmp_var = VCODE_INVALID_VAR;
120✔
7276

7277
         tree_t a = tree_assoc(alt, j);
120✔
7278
         switch (tree_subkind(a)) {
120✔
7279
         case A_NAMED:
90✔
7280
            {
7281
               tree_t name = tree_name(a);
90✔
7282
               test_reg = lower_rvalue(lu, name);
90✔
7283

7284
               if (is_array && vcode_reg_kind(test_reg) != VCODE_TYPE_UARRAY)
90✔
7285
                  test_reg = lower_wrap(lu, tree_type(name), test_reg);
84✔
7286

7287
               skip_bb = emit_block();
90✔
7288
            }
7289
            break;
90✔
7290

7291
         case A_RANGE:
6✔
7292
            {
7293
               tree_t r = tree_range(a, 0);
6✔
7294
               vcode_reg_t left_reg  = lower_range_left(lu, r);
6✔
7295
               vcode_reg_t right_reg = lower_range_right(lu, r);
6✔
7296
               vcode_reg_t dir_reg   = lower_range_dir(lu, r);
6✔
7297

7298
               if (tmp_var == VCODE_INVALID_VAR)
6✔
7299
                  tmp_var = lower_temp_var(lu, "i", vscalar, vscalar);
6✔
7300

7301
               emit_store(left_reg, tmp_var);
6✔
7302

7303
               vcode_reg_t null_reg  =
6✔
7304
                  emit_range_null(left_reg, right_reg, dir_reg);
6✔
7305

7306
               vcode_block_t body_bb = emit_block();
6✔
7307
               loop_bb = emit_block();
6✔
7308
               skip_bb = emit_block();
6✔
7309

7310
               emit_cond(null_reg, skip_bb, body_bb);
6✔
7311

7312
               vcode_select_block(body_bb);
6✔
7313

7314
               test_reg = emit_load(tmp_var);
6✔
7315

7316
               vcode_select_block(loop_bb);
6✔
7317

7318
               vcode_reg_t step_down = emit_const(vscalar, -1);
6✔
7319
               vcode_reg_t step_up   = emit_const(vscalar, 1);
6✔
7320
               vcode_reg_t step_reg  = emit_select(dir_reg, step_down, step_up);
6✔
7321
               vcode_reg_t next_reg  = emit_add(test_reg, step_reg);
6✔
7322
               emit_store(next_reg, tmp_var);
6✔
7323

7324
               vcode_reg_t done_reg =
6✔
7325
                  emit_cmp(VCODE_CMP_EQ, test_reg, right_reg);
6✔
7326
               emit_cond(done_reg, skip_bb, body_bb);
6✔
7327

7328
               vcode_select_block(body_bb);
6✔
7329
            }
7330
            break;
6✔
7331

7332
         case A_OTHERS:
24✔
7333
            emit_jump(hit_bb);
24✔
7334
            continue;
24✔
7335
         }
7336

7337
         vcode_reg_t args[] = {
96✔
7338
            context_reg,
7339
            value_reg,
7340
            test_reg,
7341
         };
7342
         vcode_reg_t result_reg = emit_fcall(func, vscalar, vscalar,
96✔
7343
                                             args, ARRAY_LEN(args));
7344
         vcode_reg_t cmp_reg = emit_cmp(VCODE_CMP_EQ, result_reg, true_reg);
96✔
7345

7346
         if (loop_bb != VCODE_INVALID_BLOCK)
96✔
7347
            emit_cond(cmp_reg, hit_bb, loop_bb);
6✔
7348
         else
7349
            emit_cond(cmp_reg, hit_bb, skip_bb);
90✔
7350

7351
         vcode_select_block(skip_bb);
96✔
7352

7353
         if (tmp_var != VCODE_INVALID_VAR)
96✔
7354
            lower_release_temp(lu, tmp_var);
6✔
7355
      }
7356

7357
      vcode_select_block(hit_bb);
117✔
7358
      lower_sequence(lu, alt, loops);
117✔
7359

7360
      if (!vcode_block_finished()) {
117✔
7361
         if (exit_bb == VCODE_INVALID_BLOCK)
105✔
7362
            exit_bb = emit_block();
27✔
7363
         emit_jump(exit_bb);
105✔
7364
      }
7365

7366
      if (skip_bb != VCODE_INVALID_BLOCK)
117✔
7367
         vcode_select_block(skip_bb);
93✔
7368
   }
7369

7370
   if (exit_bb != VCODE_INVALID_BLOCK) {
30✔
7371
      if (!vcode_block_finished())
27✔
7372
         emit_jump(exit_bb);
6✔
7373
      vcode_select_block(exit_bb);
27✔
7374
   }
7375
}
7376

7377
static void lower_sequential_block(lower_unit_t *lu, tree_t stmt,
408✔
7378
                                   loop_stack_t *loops)
7379
{
7380
   lower_decls(lu, stmt);
408✔
7381
   lower_sequence(lu, stmt, loops);
408✔
7382
}
408✔
7383

7384
static void lower_stmt(lower_unit_t *lu, tree_t stmt, loop_stack_t *loops)
75,108✔
7385
{
7386
   if (vcode_block_finished())
75,108✔
7387
      return;   // Unreachable
13✔
7388

7389
   PUSH_DEBUG_INFO(stmt);
75,095✔
7390
   PUSH_COVER_SCOPE(lu, stmt);
150,190✔
7391

7392
   switch (tree_kind(stmt)) {
75,095✔
7393
   case T_ASSERT:
14,028✔
7394
      lower_assert(lu, stmt);
14,028✔
7395
      break;
14,028✔
7396
   case T_REPORT:
1,989✔
7397
      lower_report(lu, stmt);
1,989✔
7398
      break;
1,989✔
7399
   case T_WAIT:
12,759✔
7400
      lower_wait(lu, stmt);
12,759✔
7401
      break;
12,759✔
7402
   case T_VAR_ASSIGN:
12,841✔
7403
      lower_var_assign(lu, stmt);
12,841✔
7404
      break;
12,841✔
7405
   case T_SIGNAL_ASSIGN:
8,265✔
7406
      lower_signal_assign(lu, stmt);
8,265✔
7407
      break;
8,265✔
7408
   case T_FORCE:
54✔
7409
      lower_force(lu, stmt);
54✔
7410
      break;
54✔
7411
   case T_RELEASE:
30✔
7412
      lower_release(lu, stmt);
30✔
7413
      break;
30✔
7414
   case T_IF:
5,604✔
7415
      lower_if(lu, stmt, loops);
5,604✔
7416
      break;
5,604✔
7417
   case T_RETURN:
9,538✔
7418
      lower_return(lu, stmt);
9,538✔
7419
      break;
9,538✔
7420
   case T_PCALL:
6,125✔
7421
   case T_PROT_PCALL:
7422
      lower_pcall(lu, stmt);
6,125✔
7423
      break;
6,125✔
7424
   case T_WHILE:
183✔
7425
      lower_while(lu, stmt, loops);
183✔
7426
      break;
183✔
7427
   case T_LOOP:
101✔
7428
      lower_loop(lu, stmt, loops);
101✔
7429
      break;
101✔
7430
   case T_FOR:
2,210✔
7431
      lower_for(lu, stmt, loops);
2,210✔
7432
      break;
2,210✔
7433
   case T_SEQUENCE:
408✔
7434
      lower_sequential_block(lu, stmt, loops);
408✔
7435
      break;
408✔
7436
   case T_EXIT:
279✔
7437
   case T_NEXT:
7438
      lower_loop_control(lu, stmt, loops);
279✔
7439
      break;
279✔
7440
   case T_CASE:
340✔
7441
      lower_case(lu, stmt, loops);
340✔
7442
      break;
340✔
7443
   case T_MATCH_CASE:
36✔
7444
      lower_match_case(lu, stmt, loops);
36✔
7445
      break;
36✔
7446
   case T_DUMMY_DRIVER:
7447
      break;
7448
   default:
×
7449
      fatal_at(tree_loc(stmt), "cannot lower statement kind %s",
×
7450
               tree_kind_str(tree_kind(stmt)));
7451
   }
7452
}
7453

7454
static void lower_check_indexes(lower_unit_t *lu, type_t from, type_t to,
9,715✔
7455
                                vcode_reg_t array, tree_t where)
7456
{
7457
   const int ndims = dimension_of(to);
9,715✔
7458
   for (int i = 0; i < ndims; i++) {
20,183✔
7459
      type_t index = index_type_of(to, i);
10,468✔
7460

7461
      vcode_reg_t ileft_reg, iright_reg, idir_reg;
10,468✔
7462
      lower_get_scalar_type_bounds(lu, index, &ileft_reg,
10,468✔
7463
                                   &iright_reg, &idir_reg);
7464

7465
      vcode_reg_t aleft_reg  = lower_array_left(lu, from, i, array);
10,468✔
7466
      vcode_reg_t aright_reg = lower_array_right(lu, from, i, array);
10,468✔
7467
      vcode_reg_t adir_reg   = lower_array_dir(lu, from, i, array);
10,468✔
7468

7469
      vcode_reg_t null_reg = emit_range_null(aleft_reg, aright_reg, adir_reg);
10,468✔
7470

7471
      vcode_block_t after_bb = VCODE_INVALID_BLOCK;
10,468✔
7472

7473
      int64_t null_const;
10,468✔
7474
      if (vcode_reg_const(null_reg, &null_const)) {
10,468✔
7475
         if (null_const == 1)
5,206✔
7476
            continue;   // Array range is statically known to be null
137✔
7477
      }
7478
      else {
7479
         vcode_block_t check_bb = emit_block();
5,262✔
7480
         after_bb = emit_block();
5,262✔
7481
         emit_cond(null_reg, after_bb, check_bb);
5,262✔
7482
         vcode_select_block(check_bb);
5,262✔
7483
      }
7484

7485
      vcode_reg_t hint_reg;
10,331✔
7486
      if (type_is_unconstrained(to))
10,331✔
7487
         hint_reg = lower_debug_locus(range_of(index, 0));
2,418✔
7488
      else
7489
         hint_reg = lower_debug_locus(range_of(to, i));
7,913✔
7490

7491
      vcode_reg_t locus = where ? lower_debug_locus(where) : hint_reg;
10,331✔
7492

7493
      emit_index_check(aleft_reg, ileft_reg, iright_reg, idir_reg,
10,331✔
7494
                       locus, hint_reg);
7495
      emit_index_check(aright_reg, ileft_reg, iright_reg, idir_reg,
10,331✔
7496
                       locus, hint_reg);
7497

7498
      if (after_bb != VCODE_INVALID_BLOCK) {
10,331✔
7499
         emit_jump(after_bb);
5,262✔
7500
         vcode_select_block(after_bb);
5,262✔
7501
      }
7502
   }
7503
}
9,715✔
7504

7505
static vcode_reg_t lower_var_constraints(lower_unit_t *lu, type_t var_type,
925✔
7506
                                         type_t init_type, vcode_reg_t init_reg,
7507
                                         vcode_reg_t mem_reg)
7508
{
925✔
7509
   assert(type_is_array(var_type));
925✔
7510
   assert(type_is_array(init_type));
925✔
7511

7512
   const int ncons = dims_for_type(var_type);
925✔
7513
   vcode_dim_t dims[ncons];
925✔
7514
   int dptr = 0;
925✔
7515

7516
   int udims = 0;
925✔
7517
   if (have_array_metadata(init_type, init_reg))
925✔
7518
      udims = vtype_dims(vcode_reg_type(init_reg));
864✔
7519

7520
   for (; dptr < ncons; init_type = type_elem(init_type),
2,805✔
7521
           var_type = type_elem(var_type)) {
940✔
7522

7523
      tree_t c = NULL;
955✔
7524
      for (type_t iter = var_type; type_kind(iter) == T_SUBTYPE;
955✔
7525
           iter = type_base(iter)) {
15✔
7526
         if (type_has_constraint(iter)) {
861✔
7527
            tree_t c0 = type_constraint(iter);
846✔
7528
            if (tree_subkind(c0) == C_INDEX) {
846✔
7529
               c = c0;
7530
               break;
7531
            }
7532
         }
7533
      }
7534

7535
      const int ndims = dimension_of(var_type);
940✔
7536
      for (int i = 0; i < ndims; i++, dptr++) {
1,884✔
7537
         if (c != NULL) {
944✔
7538
            tree_t r = tree_range(c, i);
846✔
7539
            dims[dptr].left  = lower_range_left(lu, r);
846✔
7540
            dims[dptr].right = lower_range_right(lu, r);
846✔
7541
            dims[dptr].dir   = lower_range_dir(lu, r);
846✔
7542
         }
7543
         else if (dptr < udims) {
98✔
7544
            dims[dptr].left  = emit_uarray_left(init_reg, dptr);
92✔
7545
            dims[dptr].right = emit_uarray_right(init_reg, dptr);
92✔
7546
            dims[dptr].dir   = emit_uarray_dir(init_reg, dptr);
92✔
7547
         }
7548
         else {
7549
            tree_t r = range_of(init_type, i);
6✔
7550
            dims[dptr].left  = lower_range_left(lu, r);
6✔
7551
            dims[dptr].right = lower_range_right(lu, r);
6✔
7552
            dims[dptr].dir   = lower_range_dir(lu, r);
6✔
7553
         }
7554
      }
7555
   }
7556

7557
   assert(dptr == ncons);
925✔
7558

7559
   return emit_wrap(mem_reg, dims, ncons);
925✔
7560
}
7561

7562
static void lower_var_decl(lower_unit_t *lu, tree_t decl)
15,588✔
7563
{
7564
   type_t type = tree_type(decl);
15,588✔
7565
   vcode_type_t vtype = lower_type(type);
15,588✔
7566
   vcode_type_t vbounds = lower_bounds(type);
15,588✔
7567
   const bool is_const = tree_kind(decl) == T_CONST_DECL;
15,588✔
7568

7569
   bool skip_copy = false;
15,588✔
7570
   if (is_const && !tree_has_value(decl)) {
15,588✔
7571
      // Deferred constant in package
7572
      return;
7573
   }
7574
   else if (is_const && type_is_array(type)
15,280✔
7575
            && !type_const_bounds(type)  // TODO: remove this restriction
2,837✔
7576
            && lower_is_const(tree_value(decl))) {
263✔
7577
      skip_copy = true;   // Will be allocated in constant data
121✔
7578
   }
7579

7580
   vcode_var_flags_t flags = 0;
15,280✔
7581
   if (is_const) flags |= VAR_CONST;
15,280✔
7582

7583
   vcode_var_t var = emit_var(vtype, vbounds, tree_ident(decl), flags);
15,280✔
7584
   lower_put_vcode_obj(decl, var, lu);
15,280✔
7585

7586
   if (type_is_protected(type)) {
15,280✔
7587
      vcode_reg_t obj_reg = lower_protected_init(lu, type, decl);
154✔
7588
      emit_store(obj_reg, var);
154✔
7589
      return;
154✔
7590
   }
7591

7592
   emit_debug_info(tree_loc(decl));
15,126✔
7593

7594
   vcode_reg_t bounds_reg = VCODE_INVALID_REG;
15,126✔
7595
   vcode_reg_t dest_reg  = VCODE_INVALID_REG;
15,126✔
7596
   vcode_reg_t count_reg = VCODE_INVALID_REG;
15,126✔
7597
   vcode_reg_t mem_reg = VCODE_INVALID_REG;
15,126✔
7598

7599
   if (type_is_record(type))
15,126✔
7600
      dest_reg = emit_index(var, VCODE_INVALID_REG);
869✔
7601
   else if (type_is_array(type)) {
14,257✔
7602
      if (needs_bounds_var(type)) {
7,506✔
7603
         bounds_reg = lower_get_type_bounds(lu, type);
3,064✔
7604
         count_reg = lower_array_total_len(lu, type, bounds_reg);
3,064✔
7605

7606
         vcode_type_t velem = lower_type(type_elem_recur(type));
3,064✔
7607
         mem_reg = emit_alloc(velem, vbounds, count_reg);
3,064✔
7608

7609
         dest_reg = lower_rewrap(mem_reg, bounds_reg);
3,064✔
7610
         emit_store(dest_reg, var);
3,064✔
7611
      }
7612
      else if (!type_is_unconstrained(type)) {
4,442✔
7613
         count_reg = lower_array_total_len(lu, type, bounds_reg);
4,261✔
7614
         dest_reg = mem_reg = emit_index(var, VCODE_INVALID_REG);
4,261✔
7615
      }
7616
   }
7617

7618
   type_t value_type = NULL;
15,126✔
7619
   vcode_reg_t value_reg;
15,126✔
7620
   if (tree_has_value(decl)) {
15,126✔
7621
      tree_t value = tree_value(decl);
7,785✔
7622
      value_type = tree_type(value);
7,785✔
7623
      if (tree_kind(value) == T_AGGREGATE)
7,785✔
7624
         value_reg = lower_aggregate(lu, value, dest_reg);
2,755✔
7625
      else
7626
         value_reg = lower_known_subtype(lu, value, type, bounds_reg);
5,030✔
7627
   }
7628
   else {
7629
      value_type = type;
7,341✔
7630
      value_reg = lower_default_value(lu, type, dest_reg);
7,341✔
7631
   }
7632

7633
   if (type_is_array(type)) {
15,126✔
7634
      vcode_reg_t data_reg = lower_array_data(value_reg);
7,506✔
7635

7636
      if (is_const && skip_copy) {
7,506✔
7637
         vcode_reg_t wrap_reg =
121✔
7638
            lower_coerce_arrays(lu, value_type, type, value_reg);
121✔
7639
         emit_store(wrap_reg, var);
121✔
7640
      }
7641
      else if (type_is_unconstrained(type)) {
7,385✔
7642
         count_reg = lower_array_total_len(lu, value_type, value_reg);
88✔
7643

7644
         type_t scalar_elem = type_elem_recur(type);
88✔
7645
         dest_reg = emit_alloc(lower_type(scalar_elem),
88✔
7646
                               lower_bounds(scalar_elem),
7647
                               count_reg);
7648
         emit_copy(dest_reg, data_reg, count_reg);
88✔
7649

7650
         vcode_reg_t wrap_reg =
88✔
7651
            lower_var_constraints(lu, type, value_type, value_reg, dest_reg);
88✔
7652

7653
         vcode_reg_t locus = lower_debug_locus(decl);
88✔
7654
         lower_check_array_sizes(lu, type, value_type,
88✔
7655
                                 wrap_reg, value_reg, locus);
7656

7657
         emit_store(wrap_reg, var);
88✔
7658
      }
7659
      else {
7660
         vcode_reg_t locus = lower_debug_locus(decl);
7,297✔
7661
         lower_check_indexes(lu, value_type, type, value_reg, NULL);
7,297✔
7662
         lower_check_array_sizes(lu, type, value_type,
7,297✔
7663
                                 dest_reg, value_reg, locus);
7664
         emit_copy(mem_reg, data_reg, count_reg);
7,297✔
7665
      }
7666
   }
7667
   else if (type_is_record(type))
7,620✔
7668
      lower_new_record(lu, type, dest_reg, value_reg);
869✔
7669
   else if (type_is_scalar(type)) {
6,751✔
7670
      lower_check_scalar_bounds(lu, value_reg, type, decl, decl);
6,126✔
7671
      emit_store(value_reg, var);
6,126✔
7672
   }
7673
   else if (type_is_access(type)) {
625✔
7674
      type_t designated = type_designated(type);
625✔
7675
      vcode_reg_t src_reg = lower_incomplete_access(value_reg, designated);
625✔
7676
      emit_store(src_reg, var);
625✔
7677
   }
7678
   else
7679
      emit_store(value_reg, var);
×
7680
}
7681

7682
static vcode_reg_t lower_resolution_func(lower_unit_t *lu, type_t type,
17,952✔
7683
                                         bool *is_array)
7684
{
7685
   tree_t rname = NULL;
23,802✔
7686
   for (type_t t = type; type_kind(t) == T_SUBTYPE; t = type_base(t)) {
32,948✔
7687
      if (type_has_resolution(t)) {
12,355✔
7688
         rname = type_resolution(t);
3,209✔
7689
         break;
3,209✔
7690
      }
7691
   }
7692

7693
   if (rname == NULL && type_is_array(type))
23,802✔
7694
      return lower_resolution_func(lu, type_elem(type), is_array);
5,850✔
7695
   else if (rname == NULL)
17,952✔
7696
      return VCODE_INVALID_REG;
7697

7698
   while (tree_kind(rname) == T_ELEM_RESOLUTION) {
4,051✔
7699
      assert(type_is_array(type));
842✔
7700
      assert(tree_assocs(rname) == 1);
842✔
7701

7702
      rname = tree_value(tree_assoc(rname, 0));
842✔
7703
      type = type_elem(type);
842✔
7704
   }
7705

7706
   tree_t rdecl = tree_ref(rname);
3,209✔
7707
   ident_t rfunc = tree_ident2(rdecl);
3,209✔
7708
   vcode_type_t vtype = lower_type(type);
3,209✔
7709

7710
   type_t uarray_param = type_param(tree_type(rdecl), 0);
3,209✔
7711
   assert(type_kind(uarray_param) == T_ARRAY);
3,209✔
7712
   tree_t r = range_of(type_index(uarray_param, 0), 0);
3,209✔
7713

7714
   vcode_reg_t ileft_reg = emit_const(vtype_offset(), assume_int(tree_left(r)));
3,209✔
7715

7716
   vcode_reg_t nlits_reg;
3,209✔
7717
   if (type_is_enum(type)) {
3,209✔
7718
      // This resolution function can potentially be memoised
7719
      if (type_kind(type) == T_SUBTYPE) {
2,938✔
7720
         int64_t low, high;
2,099✔
7721
         range_bounds(range_of(type, 0), &low, &high);
2,099✔
7722
         nlits_reg = emit_const(vtype_offset(), high - low + 1);
2,099✔
7723
      }
7724
      else
7725
         nlits_reg = emit_const(vtype_offset(), type_enum_literals(type));
839✔
7726
   }
7727
   else
7728
      nlits_reg = emit_const(vtype_offset(), 0);
271✔
7729

7730
   *is_array = vtype_kind(vtype) == VCODE_TYPE_CARRAY;
3,209✔
7731

7732
   vcode_type_t elem = *is_array ? vtype_elem(vtype) : vtype;
3,209✔
7733
   vcode_type_t rtype = lower_func_result_type(type);
3,209✔
7734
   vcode_type_t atype = vtype_uarray(1, elem, vtype_int(0, INT32_MAX));
3,209✔
7735

7736
   vcode_reg_t context_reg = lower_context_for_call(lu, rfunc);
3,209✔
7737
   vcode_reg_t closure_reg = emit_closure(rfunc, context_reg, atype, rtype);
3,209✔
7738
   return emit_resolution_wrapper(rtype, closure_reg, ileft_reg, nlits_reg);
3,209✔
7739
}
7740

7741
static void lower_sub_signals(lower_unit_t *lu, type_t type, type_t var_type,
18,105✔
7742
                              type_t init_type, tree_t where, tree_t view,
7743
                              vcode_var_t sig_var, vcode_reg_t sig_ptr,
7744
                              vcode_reg_t init_reg, vcode_reg_t resolution,
7745
                              vcode_reg_t null_reg, sig_flags_t flags,
7746
                              vcode_reg_t bounds_reg)
7747
{
7748
   bool has_scope = false;
18,105✔
7749
   if (resolution == VCODE_INVALID_REG)
18,105✔
7750
      resolution = lower_resolution_func(lu, type, &has_scope);
17,952✔
7751

7752
   if (type_is_scalar(type)) {
18,105✔
7753
      vcode_type_t voffset = vtype_offset();
10,184✔
7754
      vcode_reg_t size_reg = emit_const(voffset, type_byte_width(type));
10,184✔
7755
      vcode_reg_t len_reg = emit_const(voffset, 1);
10,184✔
7756
      vcode_type_t vtype = lower_type(type);
10,184✔
7757

7758
      vcode_reg_t locus = lower_debug_locus(where);
10,184✔
7759

7760
      if (init_reg == VCODE_INVALID_REG)
10,184✔
7761
         init_reg = lower_scalar_type_left(lu, type);
7,948✔
7762

7763
      lower_check_scalar_bounds(lu, init_reg, type, where, where);
10,184✔
7764

7765
      assert(!has_scope);
10,184✔
7766

7767
      well_known_t wk = is_well_known(type_ident(type_base_recur(type)));
10,184✔
7768
      if (wk == W_IEEE_ULOGIC || wk == W_IEEE_LOGIC)
10,184✔
7769
         flags |= SIG_F_STD_LOGIC;
1,681✔
7770

7771
      vcode_reg_t flags_reg = emit_const(voffset, flags);
10,184✔
7772
      vcode_reg_t sig = emit_init_signal(vtype, len_reg, size_reg, init_reg,
10,184✔
7773
                                         flags_reg, locus, null_reg);
7774

7775
      if (resolution != VCODE_INVALID_REG)
10,184✔
7776
         emit_resolve_signal(sig, resolution);
1,913✔
7777

7778
      if (sig_var != VCODE_INVALID_VAR)
10,184✔
7779
         emit_store(sig, sig_var);
6,749✔
7780
      else
7781
         emit_store_indirect(sig, sig_ptr);
3,435✔
7782
   }
7783
   else if (type_is_homogeneous(type)) {
7,921✔
7784
      assert(type_is_array(type));
5,687✔
7785

7786
      vcode_type_t voffset = vtype_offset();
5,687✔
7787
      vcode_reg_t size_reg = emit_const(voffset, type_byte_width(type));
5,687✔
7788
      vcode_reg_t len_reg = lower_array_total_len(lu, type, bounds_reg);
5,687✔
7789
      vcode_type_t vtype = lower_type(type_elem_recur(type));
5,687✔
7790

7791
      vcode_reg_t locus = lower_debug_locus(where);
5,687✔
7792

7793
      if (init_reg == VCODE_INVALID_REG)
5,687✔
7794
         init_reg = lower_scalar_type_left(lu, type_elem_recur(type));
4,982✔
7795
      else {
7796
         lower_check_array_sizes(lu, type, init_type, bounds_reg,
705✔
7797
                                 init_reg, locus);
7798
         init_reg = lower_array_data(init_reg);
705✔
7799
      }
7800

7801
      if (has_scope)
5,687✔
7802
         emit_array_scope(locus, lower_type(type));
3✔
7803

7804
      well_known_t wk = is_well_known(type_ident(type_base_recur(type)));
5,687✔
7805
      if (wk == W_IEEE_ULOGIC_VECTOR || wk == W_IEEE_LOGIC_VECTOR)
5,687✔
7806
         flags |= SIG_F_STD_LOGIC;
983✔
7807

7808
      vcode_reg_t flags_reg = emit_const(voffset, flags);
5,687✔
7809
      vcode_reg_t sig = emit_init_signal(vtype, len_reg, size_reg, init_reg,
5,687✔
7810
                                         flags_reg, locus, null_reg);
7811

7812
      if (resolution != VCODE_INVALID_REG)
5,687✔
7813
         emit_resolve_signal(sig, resolution);
1,410✔
7814

7815
      if (bounds_reg != VCODE_INVALID_REG)
5,687✔
7816
         sig = lower_rewrap(sig, bounds_reg);
698✔
7817
      else
7818
         sig = lower_coerce_arrays(lu, type, var_type, sig);
4,989✔
7819

7820
      if (sig_var != VCODE_INVALID_VAR)
5,687✔
7821
         emit_store(sig, sig_var);
3,515✔
7822
      else
7823
         emit_store_indirect(sig, sig_ptr);
2,172✔
7824

7825
      if (has_scope)
5,687✔
7826
         emit_pop_scope();
3✔
7827
   }
7828
   else if (type_is_array(type)) {
2,234✔
7829
      // Array of non-homogeneous type (e.g. records). Need a loop to
7830
      // initialise each sub-signal.
7831

7832
      type_t elem = type_elem_recur(type);
629✔
7833

7834
      if (null_reg == VCODE_INVALID_REG || have_uarray_ptr(null_reg))
629✔
7835
         null_reg = emit_null(vtype_pointer(lower_type(elem)));
578✔
7836

7837
      if (sig_ptr == VCODE_INVALID_REG)
629✔
7838
         sig_ptr = emit_index(sig_var, VCODE_INVALID_REG);
561✔
7839

7840
      vcode_reg_t locus = lower_debug_locus(where);
629✔
7841

7842
      if (init_reg != VCODE_INVALID_REG)
629✔
7843
         lower_check_array_sizes(lu, type, init_type, VCODE_INVALID_REG,
310✔
7844
                                 init_reg, locus);
7845

7846
      vcode_reg_t len_reg = lower_array_total_len(lu, type, bounds_reg);
629✔
7847

7848
      if (have_uarray_ptr(sig_ptr)) {
629✔
7849
         // Need to allocate separate memory for the array
7850
         vcode_type_t vtype = lower_signal_type(elem);
421✔
7851
         vcode_type_t vbounds = lower_bounds(elem);
421✔
7852
         vcode_reg_t mem_reg = emit_alloc(vtype, vbounds, len_reg);
421✔
7853

7854
         vcode_reg_t wrap_reg;
421✔
7855
         if (bounds_reg != VCODE_INVALID_REG)
421✔
7856
            wrap_reg = lower_rewrap(mem_reg, bounds_reg);
404✔
7857
         else
7858
            wrap_reg = lower_wrap(lu, type, mem_reg);
17✔
7859

7860
         emit_store_indirect(wrap_reg, sig_ptr);
421✔
7861

7862
         sig_ptr = mem_reg;
421✔
7863
      }
7864

7865
      vcode_type_t voffset = vtype_offset();
629✔
7866
      vcode_var_t i_var = lower_temp_var(lu, "i", voffset, voffset);
629✔
7867
      emit_store(emit_const(voffset, 0), i_var);
629✔
7868

7869
      emit_array_scope(locus, lower_type(type));
629✔
7870

7871
      vcode_block_t cmp_bb  = emit_block();
629✔
7872
      vcode_block_t body_bb = emit_block();
629✔
7873
      vcode_block_t exit_bb = emit_block();
629✔
7874

7875
      emit_jump(cmp_bb);
629✔
7876

7877
      vcode_select_block(cmp_bb);
629✔
7878

7879
      vcode_reg_t i_reg  = emit_load(i_var);
629✔
7880
      vcode_reg_t eq_reg = emit_cmp(VCODE_CMP_EQ, i_reg, len_reg);
629✔
7881
      emit_cond(eq_reg, exit_bb, body_bb);
629✔
7882

7883
      vcode_select_block(body_bb);
629✔
7884

7885
      vcode_reg_t ptr_reg = emit_array_ref(sig_ptr, i_reg);
629✔
7886
      vcode_reg_t null_off_reg = emit_array_ref(null_reg, i_reg);
629✔
7887

7888
      vcode_reg_t data_reg = VCODE_INVALID_REG;
629✔
7889
      if (init_reg != VCODE_INVALID_REG)
629✔
7890
         data_reg = emit_array_ref(lower_array_data(init_reg), i_reg);
310✔
7891

7892
      vcode_reg_t ebounds_reg = VCODE_INVALID_REG;
629✔
7893
      if (bounds_reg != VCODE_INVALID_REG && type_is_unconstrained(elem))
629✔
7894
         ebounds_reg = emit_unwrap(bounds_reg);
9✔
7895

7896
      lower_sub_signals(lu, elem, elem, elem, where, view, VCODE_INVALID_VAR,
629✔
7897
                        ptr_reg, data_reg, resolution, null_off_reg,
7898
                        flags, ebounds_reg);
7899

7900
      emit_store(emit_add(i_reg, emit_const(voffset, 1)), i_var);
629✔
7901

7902
      emit_jump(cmp_bb);
629✔
7903

7904
      vcode_select_block(exit_bb);
629✔
7905
      emit_pop_scope();
629✔
7906
      lower_release_temp(lu, i_var);
629✔
7907
   }
7908
   else if (type_is_record(type)) {
1,605✔
7909
      vcode_type_t vtype = lower_type(type);
1,605✔
7910
      emit_record_scope(lower_debug_locus(where), vtype);
1,605✔
7911

7912
      if (null_reg == VCODE_INVALID_REG)
1,605✔
7913
         null_reg = emit_null(vtype_pointer(vtype));
747✔
7914

7915
      if (sig_ptr == VCODE_INVALID_REG)
1,605✔
7916
         sig_ptr = emit_index(sig_var, VCODE_INVALID_REG);
747✔
7917

7918
      type_t base = type_base_recur(type);
1,605✔
7919

7920
      const int nfields = type_fields(base);
1,605✔
7921
      for (int i = 0; i < nfields; i++) {
7,509✔
7922
         tree_t f = type_field(base, i);
5,904✔
7923

7924
         type_t ft = tree_type(f), et = ft;
5,904✔
7925
         if (base != type && type_is_unconstrained(ft)) {
5,904✔
7926
            tree_t ec = type_constraint_for_field(type, f);
411✔
7927
            if (ec != NULL)
411✔
7928
               et = tree_type(ec);
408✔
7929
         }
7930

7931
         sig_flags_t newflags = flags;
5,904✔
7932
         tree_t fview = NULL;
5,904✔
7933
         if (view != NULL) {
5,904✔
7934
            bool converse = false;
126✔
7935
            tree_t e = find_element_mode_indication(view, f, &converse);
126✔
7936
            assert(e != NULL);
126✔
7937

7938
            switch (tree_subkind(e)) {
126✔
7939
            case PORT_INOUT:
6✔
7940
               newflags |= NET_F_EFFECTIVE | NET_F_INOUT;
6✔
7941
               break;
6✔
7942
            case PORT_ARRAY_VIEW:
6✔
7943
            case PORT_RECORD_VIEW:
7944
               fview = tree_value(e);
6✔
7945
               break;
6✔
7946
            }
7947
         }
7948

7949
         vcode_type_t fvtype = vtype_field(vtype, i);
5,904✔
7950

7951
         vcode_reg_t null_field_reg;
5,904✔
7952
         if (vtype_kind(fvtype) == VCODE_TYPE_UARRAY)
5,904✔
7953
            null_field_reg = emit_null(vtype_pointer(fvtype));
592✔
7954
         else
7955
            null_field_reg = emit_record_ref(null_reg, i);
5,312✔
7956

7957
         vcode_reg_t field_reg = VCODE_INVALID_REG;
5,904✔
7958
         if (init_reg != VCODE_INVALID_REG) {
5,904✔
7959
            field_reg = emit_record_ref(init_reg, i);
1,020✔
7960

7961
            if (have_uarray_ptr(field_reg))
1,020✔
7962
               field_reg = emit_load_indirect(field_reg);
59✔
7963
            else if (type_is_scalar(ft))
961✔
7964
               field_reg = emit_load_indirect(field_reg);
826✔
7965
         }
7966

7967
         vcode_reg_t fbounds_reg = VCODE_INVALID_REG;
5,904✔
7968
         if (bounds_reg != VCODE_INVALID_REG && type_is_unconstrained(ft)) {
5,904✔
7969
            fbounds_reg = emit_record_ref(bounds_reg, i);
190✔
7970

7971
            if (have_uarray_ptr(fbounds_reg))
190✔
7972
               fbounds_reg = emit_load_indirect(fbounds_reg);
190✔
7973
         }
7974

7975
         vcode_reg_t ptr_reg = emit_record_ref(sig_ptr, i);
5,904✔
7976

7977
         lower_sub_signals(lu, et, ft, ft, f, fview, VCODE_INVALID_VAR, ptr_reg,
5,904✔
7978
                           field_reg, resolution, null_field_reg, newflags,
7979
                           fbounds_reg);
7980
      }
7981

7982
      emit_pop_scope();
1,605✔
7983
   }
7984
   else
7985
      fatal_trace("unhandled type %s in lower_sub_signals", type_pp(type));
7986
}
18,105✔
7987

7988
static void lower_signal_decl(lower_unit_t *lu, tree_t decl)
6,749✔
7989
{
7990
   type_t type = tree_type(decl);
6,749✔
7991
   vcode_type_t vtype = lower_signal_type(type);
6,749✔
7992
   vcode_type_t vbounds = lower_bounds(type);
6,749✔
7993
   vcode_var_t var = emit_var(vtype, vbounds, tree_ident(decl), VAR_SIGNAL);
6,749✔
7994
   lower_put_vcode_obj(decl, var, lu);
6,749✔
7995

7996
   type_t value_type = type;
6,749✔
7997
   vcode_reg_t init_reg = VCODE_INVALID_REG;
6,749✔
7998
   if (tree_has_value(decl)) {
6,749✔
7999
      tree_t value = tree_value(decl);
1,984✔
8000
      value_type = tree_type(value);
1,984✔
8001
      init_reg = lower_known_subtype(lu, value, type, VCODE_INVALID_REG);
1,984✔
8002
   }
8003

8004
   vcode_reg_t bounds_reg = VCODE_INVALID_REG;
6,749✔
8005
   if (standard() >= STD_19 && type_is_unconstrained(type)) {
6,749✔
8006
      type = value_type;
8007
      bounds_reg = init_reg;
8008
   }
8009
   else if (needs_bounds_var(type))
6,743✔
8010
      bounds_reg = lower_get_type_bounds(lu, type);
578✔
8011

8012
   sig_flags_t flags = 0;
6,749✔
8013
   if (tree_flags(decl) & TREE_F_REGISTER)
6,749✔
8014
      flags |= SIG_F_REGISTER;
3✔
8015

8016
   lower_sub_signals(lu, type, type, value_type, decl, NULL, var,
6,749✔
8017
                     VCODE_INVALID_REG, init_reg, VCODE_INVALID_REG,
8018
                     VCODE_INVALID_REG, flags, bounds_reg);
8019

8020
   PUSH_COVER_SCOPE(lu, decl);
13,498✔
8021

8022
   if (cover_enabled(lu->cover, COVER_MASK_TOGGLE))
6,749✔
8023
      lower_toggle_coverage(lu, decl);
290✔
8024

8025
   if (cover_enabled(lu->cover, COVER_MASK_STATE))
6,749✔
8026
      lower_state_coverage(lu, decl);
148✔
8027
}
6,749✔
8028

8029
static void lower_build_wait_field_cb(lower_unit_t *lu, tree_t field,
15✔
8030
                                      vcode_reg_t ptr, vcode_reg_t value,
8031
                                      vcode_reg_t locus, void *ctx)
8032
{
8033
   type_t ftype = tree_type(field);
15✔
8034

8035
   if (type_is_homogeneous(ftype)) {
15✔
8036
      vcode_reg_t nets_reg = emit_load_indirect(ptr);
15✔
8037
      vcode_reg_t count_reg = lower_type_width(lu, ftype, nets_reg);
15✔
8038
      vcode_reg_t data_reg = lower_array_data(nets_reg);
15✔
8039
      emit_sched_event(data_reg, count_reg);
15✔
8040
   }
8041
   else
8042
      lower_for_each_field_2(lu, ftype, ftype, ptr, value, locus,
×
8043
                             lower_build_wait_field_cb, ctx);
8044
}
15✔
8045

8046
static void lower_build_wait_cb(tree_t expr, void *ctx)
133✔
8047
{
8048
   lower_unit_t *lu = ctx;
133✔
8049
   type_t type = tree_type(expr);
133✔
8050

8051
   vcode_reg_t nets_reg = lower_lvalue(lu, expr);
133✔
8052

8053
   if (type_is_homogeneous(type)) {
133✔
8054
      vcode_reg_t count_reg = lower_type_width(lu, type, nets_reg);
121✔
8055
      vcode_reg_t data_reg = lower_array_data(nets_reg);
121✔
8056
      emit_sched_event(data_reg, count_reg);
121✔
8057
   }
8058
   else
8059
      lower_for_each_field(lu, type, nets_reg, VCODE_INVALID_REG,
12✔
8060
                           lower_build_wait_field_cb, NULL);
8061
}
133✔
8062

8063
static void lower_implicit_field_cb(lower_unit_t *lu, tree_t field,
9✔
8064
                                    vcode_reg_t ptr, vcode_reg_t value,
8065
                                    vcode_reg_t locus, void *ctx)
8066
{
8067
   vcode_reg_t sig_reg = (intptr_t)ctx;
9✔
8068
   type_t ftype = tree_type(field);
9✔
8069

8070
   if (type_is_homogeneous(ftype)) {
9✔
8071
      vcode_reg_t nets_reg = emit_load_indirect(ptr);
9✔
8072
      vcode_reg_t count_reg = lower_type_width(lu, ftype, nets_reg);
9✔
8073
      vcode_reg_t data_reg = lower_array_data(nets_reg);
9✔
8074

8075
      emit_map_implicit(data_reg, sig_reg, count_reg);
9✔
8076
   }
8077
   else
8078
      lower_for_each_field(lu, ftype, ptr, locus,
×
8079
                           lower_implicit_field_cb, ctx);
8080
}
9✔
8081

8082
static void lower_implicit_decl(lower_unit_t *parent, tree_t decl)
159✔
8083
{
8084
   ident_t name = tree_ident(decl);
159✔
8085
   type_t type = tree_type(decl);
159✔
8086
   const implicit_kind_t kind = tree_subkind(decl);
159✔
8087

8088
   vcode_type_t signal_type = lower_signal_type(type);
159✔
8089
   vcode_type_t vtype = lower_type(type);
159✔
8090
   vcode_type_t vbounds = lower_bounds(type);
159✔
8091
   vcode_var_t var = emit_var(signal_type, vbounds, name, VAR_SIGNAL);
159✔
8092
   lower_put_vcode_obj(decl, var, parent);
159✔
8093

8094
   switch (kind) {
159✔
8095
   case IMPLICIT_GUARD:
21✔
8096
      {
8097
         tree_t expr = tree_value(decl);
21✔
8098

8099
         ident_t qual = ident_prefix(parent->name, name, '.');
21✔
8100
         ident_t func = ident_prefix(qual, ident_new("guard"), '$');
21✔
8101

8102
         vcode_state_t state;
21✔
8103
         vcode_state_save(&state);
21✔
8104

8105
         object_t *obj = tree_to_object(expr);
21✔
8106
         vcode_unit_t vu = emit_function(func, obj, parent->vunit);
21✔
8107
         vcode_set_result(vtype);
21✔
8108

8109
         vcode_type_t vcontext = vtype_context(parent->name);
21✔
8110
         emit_param(vcontext, vcontext, ident_new("context"));
21✔
8111

8112
         lower_unit_t *lu = lower_unit_new(parent->registry, parent,
21✔
8113
                                           vu, NULL, NULL);
8114
         unit_registry_put(parent->registry, lu);
21✔
8115

8116
         build_wait(expr, lower_build_wait_cb, lu);
21✔
8117

8118
         emit_return(lower_rvalue(lu, expr));
21✔
8119

8120
         unit_registry_finalise(parent->registry, lu);
21✔
8121

8122
         vcode_state_restore(&state);
21✔
8123

8124
         vcode_reg_t one_reg = emit_const(vtype_offset(), 1);
21✔
8125
         vcode_reg_t locus = lower_debug_locus(decl);
21✔
8126
         vcode_reg_t context_reg = lower_context_for_call(parent, func);
21✔
8127
         vcode_reg_t closure =
21✔
8128
            emit_closure(func, context_reg, VCODE_INVALID_TYPE, vtype);
21✔
8129
         vcode_reg_t delay_reg = emit_const(vtype_time(), TIME_HIGH);
21✔
8130
         vcode_reg_t kind_reg = emit_const(vtype_offset(), IMPLICIT_GUARD);
21✔
8131
         vcode_reg_t sig = emit_implicit_signal(vtype, one_reg, one_reg, locus,
21✔
8132
                                                kind_reg, closure, delay_reg);
8133
         emit_store(sig, var);
21✔
8134
      }
8135
      break;
21✔
8136

8137
   case IMPLICIT_DELAYED:
84✔
8138
      {
8139
         tree_t wave = tree_value(decl);
84✔
8140
         assert(tree_kind(wave) == T_WAVEFORM);
84✔
8141

8142
         tree_t expr = tree_value(wave);
84✔
8143

8144
         vcode_reg_t init_reg =
84✔
8145
            lower_default_value(parent, type, VCODE_INVALID_REG);
84✔
8146

8147
         lower_sub_signals(parent, type, type, type, decl, NULL, var,
84✔
8148
                           VCODE_INVALID_REG, init_reg, VCODE_INVALID_REG,
8149
                           VCODE_INVALID_REG, 0, VCODE_INVALID_REG);
8150

8151
         vcode_state_t state;
84✔
8152
         vcode_state_save(&state);
84✔
8153

8154
         object_t *obj = tree_to_object(decl);
84✔
8155
         ident_t name = ident_prefix(parent->name, tree_ident(decl), '.');
84✔
8156
         vcode_unit_t vu = emit_process(name, obj, parent->vunit);
84✔
8157

8158
         lower_unit_t *lu = lower_unit_new(parent->registry, parent,
84✔
8159
                                           vu, NULL, NULL);
8160
         unit_registry_put(parent->registry, lu);
84✔
8161

8162
         vcode_reg_t nets_reg = lower_signal_ref(lu, decl);
84✔
8163

8164
         if (type_is_homogeneous(type)) {
84✔
8165
            vcode_reg_t count_reg = lower_type_width(lu, type, nets_reg);
78✔
8166
            vcode_reg_t data_reg = lower_array_data(nets_reg);
78✔
8167
            emit_drive_signal(data_reg, count_reg);
78✔
8168
         }
8169
         else
8170
            lower_for_each_field(lu, type, nets_reg, VCODE_INVALID_REG,
6✔
8171
                                 lower_driver_field_cb, NULL);
8172

8173
         build_wait(expr, lower_build_wait_cb, lu);
84✔
8174

8175
         emit_return(VCODE_INVALID_REG);
84✔
8176

8177
         vcode_block_t main_bb = emit_block();
84✔
8178
         vcode_select_block(main_bb);
84✔
8179

8180
         vcode_type_t vtime = vtype_time();
84✔
8181

8182
         vcode_reg_t delay_reg;
84✔
8183
         if (tree_has_delay(wave))
84✔
8184
            delay_reg = lower_rvalue(lu, tree_delay(wave));
60✔
8185
         else
8186
            delay_reg = emit_const(vtime, 0);
24✔
8187

8188
         vcode_reg_t reject_reg = emit_const(vtime, 0);
84✔
8189
         vcode_reg_t value_reg = lower_rvalue(lu, expr);
84✔
8190

8191
         target_part_t parts[] = {
84✔
8192
            { .kind = PART_ALL,
8193
              .reg = lower_signal_ref(lu, decl),
84✔
8194
              .off = VCODE_INVALID_REG,
8195
              .target = decl },
8196
            { .kind = PART_POP,
8197
              .reg = VCODE_INVALID_REG,
8198
              .off = VCODE_INVALID_REG,
8199
            }
8200
         };
8201

8202
         target_part_t *ptr = parts;
84✔
8203
         lower_signal_assign_target(lu, &ptr, decl, value_reg, type,
84✔
8204
                                    reject_reg, delay_reg);
8205

8206
         emit_return(VCODE_INVALID_REG);
84✔
8207

8208
         unit_registry_finalise(parent->registry, lu);
84✔
8209

8210
         vcode_state_restore(&state);
84✔
8211

8212
         emit_process_init(name, lower_debug_locus(decl));
84✔
8213
      }
8214
      break;
84✔
8215

8216
   case IMPLICIT_TRANSACTION:
18✔
8217
      {
8218
         vcode_state_t state;
18✔
8219
         vcode_state_save(&state);
18✔
8220

8221
         object_t *obj = tree_to_object(decl);
18✔
8222
         ident_t qual = ident_prefix(parent->name, name, '.');
18✔
8223
         vcode_unit_t vu = emit_function(qual, obj, parent->vunit);
18✔
8224
         vcode_set_result(vtype);
18✔
8225

8226
         vcode_type_t vcontext = vtype_context(parent->name);
18✔
8227
         emit_param(vcontext, vcontext, ident_new("context"));
18✔
8228

8229
         vcode_reg_t preg = emit_param(vtype, vtype, ident_new("p"));
18✔
8230

8231
         lower_unit_t *lu = lower_unit_new(parent->registry, parent,
18✔
8232
                                           vu, NULL, NULL);
8233
         unit_registry_put(parent->registry, lu);
18✔
8234

8235
         emit_return(emit_not(preg));
18✔
8236

8237
         unit_registry_finalise(parent->registry, lu);
18✔
8238

8239
         vcode_state_restore(&state);
18✔
8240

8241
         vcode_reg_t locus = lower_debug_locus(decl);
18✔
8242

8243
         vcode_type_t voffset = vtype_offset();
18✔
8244
         vcode_reg_t one_reg = emit_const(voffset, 1);
18✔
8245

8246
         vcode_reg_t delay_reg = emit_const(vtype_time(), TIME_HIGH);
18✔
8247
         vcode_reg_t kind_reg = emit_const(voffset, IMPLICIT_TRANSACTION);
18✔
8248
         vcode_reg_t context_reg = lower_context_for_call(parent, qual);
18✔
8249
         vcode_reg_t closure = emit_closure(qual, context_reg, vtype, vtype);
18✔
8250

8251
         vcode_reg_t sig = emit_implicit_signal(vtype, one_reg, one_reg, locus,
18✔
8252
                                                kind_reg, closure, delay_reg);
8253
         emit_store(sig, var);
18✔
8254

8255
         tree_t prefix = tree_value(decl);
18✔
8256
         type_t type = tree_type(prefix);
18✔
8257

8258
         vcode_reg_t prefix_reg = lower_attr_prefix(parent, prefix);
18✔
8259

8260
         if (type_is_homogeneous(type)) {
18✔
8261
            vcode_reg_t count_reg = lower_type_width(parent, type, prefix_reg);
15✔
8262
            vcode_reg_t nets_reg = lower_array_data(prefix_reg);
15✔
8263

8264
            emit_map_implicit(nets_reg, sig, count_reg);
15✔
8265
         }
8266
         else
8267
            lower_for_each_field(parent, type, prefix_reg,
3✔
8268
                                 locus, lower_implicit_field_cb,
8269
                                 (void *)(intptr_t)sig);
3✔
8270
      }
8271
      break;
18✔
8272

8273
   case IMPLICIT_STABLE:
36✔
8274
   case IMPLICIT_QUIET:
8275
      {
8276
         tree_t w = tree_value(decl);
36✔
8277
         assert(tree_kind(w) == T_WAVEFORM);
36✔
8278

8279
         tree_t prefix = tree_value(w);
36✔
8280
         ident_t qual = ident_prefix(parent->name, name, '.');
36✔
8281

8282
         {
8283
            vcode_state_t state;
36✔
8284
            vcode_state_save(&state);
36✔
8285

8286
            object_t *obj = tree_to_object(prefix);
36✔
8287
            vcode_unit_t vu = emit_function(qual, obj, parent->vunit);
36✔
8288
            vcode_set_result(vtype);
36✔
8289

8290
            vcode_type_t vcontext = vtype_context(parent->name);
36✔
8291
            emit_param(vcontext, vcontext, ident_new("context"));
36✔
8292

8293
            lower_unit_t *lu = lower_unit_new(parent->registry, parent,
36✔
8294
                                           vu, NULL, NULL);
8295
            unit_registry_put(parent->registry, lu);
36✔
8296

8297
            lower_signal_flag_fn_t fn =
72✔
8298
               kind == IMPLICIT_STABLE ? emit_event_flag : emit_active_flag;
36✔
8299
            vcode_reg_t flag_reg = lower_signal_flag(lu, prefix, fn);
36✔
8300

8301
            emit_return(emit_not(flag_reg));
36✔
8302

8303
            unit_registry_finalise(parent->registry, lu);
36✔
8304

8305
            vcode_state_restore(&state);
36✔
8306
         }
8307

8308
         vcode_reg_t delay_reg;
36✔
8309
         if (tree_has_delay(w))
36✔
8310
            delay_reg = lower_rvalue(parent, tree_delay(w));
21✔
8311
         else
8312
            delay_reg = emit_const(vtype_time(), 0);
15✔
8313

8314
         vcode_reg_t one_reg = emit_const(vtype_offset(), 1);
36✔
8315
         vcode_reg_t locus = lower_debug_locus(decl);
36✔
8316
         vcode_reg_t context_reg = lower_context_for_call(parent, qual);
36✔
8317
         vcode_reg_t closure = emit_closure(qual, context_reg, vtype, vtype);
36✔
8318
         vcode_reg_t kind_reg = emit_const(vtype_offset(), kind);
36✔
8319
         vcode_reg_t sig = emit_implicit_signal(vtype, one_reg, one_reg, locus,
36✔
8320
                                                kind_reg, closure, delay_reg);
8321
         emit_store(sig, var);
36✔
8322

8323
         vcode_reg_t prefix_reg = lower_attr_prefix(parent, prefix);
36✔
8324

8325
         type_t prefix_type = tree_type(prefix);
36✔
8326
         if (type_is_homogeneous(prefix_type)) {
36✔
8327
            vcode_reg_t count_reg =
33✔
8328
               lower_type_width(parent, prefix_type, prefix_reg);
33✔
8329
            vcode_reg_t nets_reg = lower_array_data(prefix_reg);
33✔
8330

8331
            emit_map_implicit(nets_reg, sig, count_reg);
33✔
8332
         }
8333
         else
8334
            lower_for_each_field(parent, prefix_type, prefix_reg,
3✔
8335
                                 locus, lower_implicit_field_cb,
8336
                                 (void *)(intptr_t)sig);
3✔
8337
      }
8338
      break;
8339
   }
8340
}
159✔
8341

8342
static void lower_file_decl(lower_unit_t *lu, tree_t decl)
198✔
8343
{
8344
   type_t type = tree_type(decl);
198✔
8345
   vcode_type_t vtype = lower_type(type);
198✔
8346
   vcode_var_t var = emit_var(vtype, vtype, tree_ident(decl), 0);
198✔
8347
   lower_put_vcode_obj(decl, var, lu);
198✔
8348

8349
   emit_store(emit_null(vtype), var);
198✔
8350

8351
   if (tree_has_value(decl)) {
198✔
8352
      // Generate initial call to file_open
8353

8354
      tree_t value = tree_value(decl);
98✔
8355

8356
      vcode_reg_t name_array = lower_rvalue(lu, tree_value(decl));
98✔
8357
      vcode_reg_t name_data  = lower_array_data(name_array);
98✔
8358
      vcode_reg_t name_len   = lower_array_len(lu, tree_type(value), 0,
98✔
8359
                                               name_array);
8360
      vcode_reg_t file_ptr   = emit_index(var, VCODE_INVALID_REG);
98✔
8361
      vcode_reg_t mode       = lower_rvalue(lu, tree_file_mode(decl));
98✔
8362

8363
      emit_file_open(file_ptr, name_data, name_len, mode, VCODE_INVALID_REG);
98✔
8364
   }
8365
}
198✔
8366

8367
static vcode_type_t lower_alias_type(tree_t alias)
6,325✔
8368
{
8369
   tree_t value = tree_value(alias);
6,325✔
8370
   const class_t class = class_of(value);
6,325✔
8371

8372
   type_t type = tree_has_type(alias) ? tree_type(alias) : tree_type(value);
6,325✔
8373

8374
   if (type_is_array(type)) {
6,325✔
8375
      vcode_type_t velem;
940✔
8376
      switch (class) {
940✔
8377
      case C_SIGNAL:
140✔
8378
         velem = lower_signal_type(type_elem_recur(type));
140✔
8379
         break;
140✔
8380
      case C_VARIABLE:
713✔
8381
      case C_CONSTANT:
8382
         velem = lower_type(type_elem_recur(type));
713✔
8383
         break;
713✔
8384
      default:
8385
         return VCODE_INVALID_TYPE;
8386
      }
8387

8388
      vcode_type_t vbounds = lower_bounds(type);
853✔
8389
      return vtype_uarray(dims_for_type(type), velem, vbounds);
853✔
8390
   }
8391
   else
8392
      return VCODE_INVALID_TYPE;
8393
}
8394

8395
static void lower_alias_decl(lower_unit_t *lu, tree_t decl)
6,348✔
8396
{
8397
   tree_t value = tree_value(decl);
6,348✔
8398
   if (tree_kind(value) == T_EXTERNAL_NAME) {
6,348✔
8399
      // Avoid null check on every access to the external name
8400
      lower_external_name(lu, value);
39✔
8401
      return;
39✔
8402
   }
8403

8404
   vcode_type_t vtype = lower_alias_type(decl);
6,309✔
8405
   if (vtype == VCODE_INVALID_TYPE)
6,309✔
8406
      return;
8407

8408
   type_t value_type = tree_type(value);
837✔
8409
   type_t type = tree_has_type(decl) ? tree_type(decl) : value_type;
837✔
8410

8411
   vcode_reg_t value_reg;
837✔
8412
   vcode_var_flags_t flags = 0;
837✔
8413
   if (class_of(value) == C_SIGNAL) {
837✔
8414
      flags |= VAR_SIGNAL;
125✔
8415
      value_reg = lower_lvalue(lu, value);
125✔
8416
   }
8417
   else
8418
      value_reg = lower_rvalue(lu, value);
712✔
8419

8420
   vcode_type_t vbounds = lower_bounds(type);
837✔
8421
   vcode_var_t var = emit_var(vtype, vbounds, tree_ident(decl), flags);
837✔
8422
   lower_put_vcode_obj(decl, var, lu);
837✔
8423

8424
   if (type_is_array(type)) {
837✔
8425
      vcode_reg_t data_reg = lower_array_data(value_reg);
837✔
8426
      vcode_reg_t wrap_reg =
837✔
8427
         lower_var_constraints(lu, type, value_type, value_reg, data_reg);
837✔
8428

8429
      vcode_reg_t locus = lower_debug_locus(decl);
837✔
8430
      lower_check_array_sizes(lu, type, value_type, wrap_reg, value_reg, locus);
837✔
8431

8432
      emit_store(wrap_reg, var);
837✔
8433
   }
8434
   else
8435
      emit_store(value_reg, var);
×
8436
}
8437

8438
static void lower_enum_image_helper(type_t type, vcode_reg_t preg)
88✔
8439
{
8440
   const int nlits = type_enum_literals(type);
88✔
8441
   assert(nlits >= 1);
88✔
8442

8443
   vcode_block_t *blocks LOCAL = xmalloc_array(nlits, sizeof(vcode_block_t));
176✔
8444
   vcode_reg_t *cases LOCAL = xmalloc_array(nlits, sizeof(vcode_reg_t));
176✔
8445

8446
   vcode_type_t vtype = lower_type(type);
88✔
8447

8448
   for (int i = 0; i < nlits; i++) {
2,226✔
8449
      cases[i]  = emit_const(vtype, i);
2,138✔
8450
      blocks[i] = emit_block();
2,138✔
8451
   }
8452

8453
   emit_case(preg, blocks[0], cases, blocks, nlits);
88✔
8454

8455
   for (int i = 0; i < nlits; i++) {
2,226✔
8456
      // LRM specifies result is lowercase for enumerated types when
8457
      // the value is a basic identifier
8458
      ident_t id = tree_ident(type_enum_literal(type, i));
2,138✔
8459
      if (ident_char(id, 0) != '\'')
2,138✔
8460
         id = ident_downcase(id);
714✔
8461

8462
      vcode_select_block(blocks[i]);
2,138✔
8463
      vcode_reg_t str = lower_wrap_string(istr(id));
2,138✔
8464
      emit_return(str);
2,138✔
8465
   }
8466
}
88✔
8467

8468
static void lower_physical_image_helper(lower_unit_t *lu, type_t type,
15✔
8469
                                        vcode_reg_t preg)
8470
{
8471
   vcode_type_t vint64 = vtype_int(INT64_MIN, INT64_MAX);
15✔
8472
   vcode_type_t vchar = vtype_char();
15✔
8473
   vcode_type_t vstring = vtype_uarray(1, vchar, vchar);
15✔
8474

8475
   vcode_reg_t cast_reg = emit_cast(vint64, vint64, preg);
15✔
8476
   ident_t conv_fn =
15✔
8477
      ident_new("NVC.TEXT_UTIL.INT_TO_STRING(21NVC.TEXT_UTIL.T_INT64)S");
15✔
8478
   vcode_reg_t conv_args[] = {
15✔
8479
      lower_context_for_call(lu, conv_fn),
15✔
8480
      cast_reg
8481
   };
8482
   vcode_reg_t num_reg = emit_fcall(conv_fn, vstring, vstring, conv_args, 2);
15✔
8483

8484
   vcode_reg_t num_len = emit_uarray_len(num_reg, 0);
15✔
8485

8486
   const char *unit0 = istr(ident_downcase(tree_ident(type_unit(type, 0))));
15✔
8487

8488
   vcode_reg_t append_len = emit_const(vtype_offset(), strlen(unit0) + 1);
15✔
8489
   vcode_reg_t total_len = emit_add(num_len, append_len);
15✔
8490

8491
   vcode_type_t ctype = vtype_char();
15✔
8492
   vcode_reg_t mem_reg = emit_alloc(ctype, ctype, total_len);
15✔
8493
   emit_copy(mem_reg, emit_unwrap(num_reg), num_len);
15✔
8494

8495
   vcode_reg_t ptr0_reg = emit_array_ref(mem_reg, num_len);
15✔
8496
   emit_store_indirect(emit_const(ctype, ' '), ptr0_reg);
15✔
8497

8498
   vcode_reg_t unit_reg = lower_wrap_string(unit0);
15✔
8499
   vcode_reg_t ptr1_reg =
15✔
8500
      emit_array_ref(ptr0_reg, emit_const(vtype_offset(), 1));
15✔
8501
   emit_copy(ptr1_reg, emit_unwrap(unit_reg),
15✔
8502
             emit_const(vtype_offset(), strlen(unit0)));
15✔
8503

8504
   vcode_dim_t dims[] = {
15✔
8505
      { .left  = emit_const(vtype_offset(), 1),
15✔
8506
        .right = total_len,
8507
        .dir   = emit_const(vtype_bool(), RANGE_TO)
15✔
8508
      }
8509
   };
8510
   emit_return(emit_wrap(mem_reg, dims, 1));
15✔
8511
}
15✔
8512

8513
static void lower_numeric_image_helper(lower_unit_t *lu, type_t type,
71✔
8514
                                       vcode_reg_t preg)
8515
{
8516
   vcode_type_t vchar = vtype_char();
71✔
8517
   vcode_type_t vstring = vtype_uarray(1, vchar, vchar);
71✔
8518

8519
   ident_t conv_fn;
71✔
8520
   vcode_reg_t arg_reg;
71✔
8521

8522
   if (type_is_real(type)) {
71✔
8523
      arg_reg = preg;
10✔
8524
      conv_fn = ident_new("NVC.TEXT_UTIL.REAL_TO_STRING(R)S");
10✔
8525
   }
8526
   else {
8527
      vcode_type_t vint64 = vtype_int(INT64_MIN, INT64_MAX);
61✔
8528
      arg_reg = emit_cast(vint64, vint64, preg);
61✔
8529
      conv_fn = ident_new(
61✔
8530
         "NVC.TEXT_UTIL.INT_TO_STRING(21NVC.TEXT_UTIL.T_INT64)S");
8531
   }
8532

8533
   vcode_reg_t conv_args[] = {
71✔
8534
      lower_context_for_call(lu, conv_fn),
71✔
8535
      arg_reg
8536
   };
8537
   vcode_reg_t str_reg = emit_fcall(conv_fn, vstring, vstring, conv_args, 2);
71✔
8538
   emit_return(str_reg);
71✔
8539
}
71✔
8540

8541
static void lower_record_image_helper(lower_unit_t *lu, type_t type,
10✔
8542
                                      vcode_reg_t preg)
8543
{
10✔
8544
   const int nfields = type_fields(type);
10✔
8545
   vcode_reg_t regs[nfields];
10✔
8546
   vcode_reg_t lengths[nfields];
10✔
8547

8548
   vcode_type_t ctype = vtype_char();
10✔
8549
   vcode_type_t strtype = vtype_uarray(1, ctype, ctype);
10✔
8550
   vcode_type_t voffset = vtype_offset();
10✔
8551

8552
   vcode_reg_t sum_reg = emit_const(voffset, nfields + 1);
10✔
8553

8554
   for (int i = 0; i < nfields; i++) {
40✔
8555
      type_t ftype = type_base_recur(tree_type(type_field(type, i)));
30✔
8556
      ident_t func = ident_prefix(type_ident(ftype), ident_new("image"), '$');
30✔
8557

8558
      vcode_reg_t context_reg = lower_context_for_call(lu, func);
30✔
8559
      vcode_reg_t field_reg = emit_record_ref(preg, i);
30✔
8560

8561
      if (type_is_scalar(ftype) || have_uarray_ptr(field_reg))
30✔
8562
         field_reg = emit_load_indirect(field_reg);
27✔
8563

8564
      vcode_reg_t args[] = { context_reg, field_reg };
30✔
8565
      regs[i] = emit_fcall(func, strtype, strtype, args, 2);
30✔
8566
      lengths[i] = emit_uarray_len(regs[i], 0);
30✔
8567

8568
      sum_reg = emit_add(sum_reg, lengths[i]);
30✔
8569
   }
8570

8571
   vcode_reg_t mem_reg = emit_alloc(ctype, ctype, sum_reg);
10✔
8572

8573
   vcode_reg_t lparen_reg = emit_array_ref(mem_reg, emit_const(voffset, 0));
10✔
8574
   emit_store_indirect(emit_const(ctype, '('), lparen_reg);
10✔
8575

8576
   vcode_reg_t index_reg = emit_const(voffset, 1);
10✔
8577
   for (int i = 0; i < nfields; i++) {
40✔
8578
      if (i > 0) {
30✔
8579
         vcode_reg_t comma_reg = emit_array_ref(mem_reg, index_reg);
20✔
8580
         emit_store_indirect(emit_const(ctype, ','), comma_reg);
20✔
8581
         index_reg = emit_add(index_reg, emit_const(voffset, 1));
20✔
8582
      }
8583

8584
      vcode_reg_t src_reg = emit_unwrap(regs[i]);
30✔
8585
      vcode_reg_t dest_reg = emit_array_ref(mem_reg, index_reg);
30✔
8586
      emit_copy(dest_reg, src_reg, lengths[i]);
30✔
8587
      index_reg = emit_add(index_reg, lengths[i]);
30✔
8588
   }
8589

8590
   vcode_reg_t rparen_reg = emit_array_ref(mem_reg, index_reg);
10✔
8591
   emit_store_indirect(emit_const(ctype, ')'), rparen_reg);
10✔
8592

8593
   vcode_dim_t dims[] = {
10✔
8594
      { .left  = emit_const(vtype_offset(), 1),
10✔
8595
        .right = sum_reg,
8596
        .dir   = emit_const(vtype_bool(), RANGE_TO)
10✔
8597
      }
8598
   };
8599
   emit_return(emit_wrap(mem_reg, dims, 1));
10✔
8600
}
10✔
8601

8602
static void lower_array_image_helper(lower_unit_t *lu, type_t type,
19✔
8603
                                     vcode_reg_t preg)
8604
{
8605
   vcode_type_t ctype = vtype_char();
19✔
8606
   vcode_type_t strtype = vtype_uarray(1, ctype, ctype);
19✔
8607
   vcode_type_t voffset = vtype_offset();
19✔
8608
   vcode_type_t fields[] = { vtype_pointer(ctype), voffset };
19✔
8609
   vcode_type_t rtype = vtype_named_record(ident_new("elem"), fields, 2);
19✔
8610

8611
   vcode_reg_t length_reg = lower_array_len(lu, type, 0, preg);
19✔
8612

8613
   vcode_reg_t elems_reg = emit_alloc(rtype, rtype, length_reg);
19✔
8614
   vcode_reg_t zero_reg = emit_const(voffset, 0);
19✔
8615
   vcode_reg_t one_reg = emit_const(voffset, 1);
19✔
8616
   vcode_reg_t data_reg = lower_array_data(preg);
19✔
8617

8618
   vcode_var_t i_var = lower_temp_var(lu, "i", voffset, voffset);
19✔
8619
   emit_store(zero_reg, i_var);
19✔
8620

8621
   vcode_block_t loop1_bb = emit_block();
19✔
8622
   vcode_block_t alloc_bb = emit_block();
19✔
8623

8624
   vcode_var_t sum_var = lower_temp_var(lu, "sum", voffset, voffset);
19✔
8625
   emit_store(emit_add(length_reg, one_reg), sum_var);
19✔
8626

8627
   type_t elem = type_base_recur(type_elem(type));
19✔
8628
   ident_t func = ident_prefix(type_ident(elem), ident_new("image"), '$');
19✔
8629

8630
   vcode_reg_t context_reg = lower_context_for_call(lu, func);
19✔
8631

8632
   vcode_reg_t null_reg = emit_cmp(VCODE_CMP_EQ, length_reg, zero_reg);
19✔
8633
   emit_cond(null_reg, alloc_bb, loop1_bb);
19✔
8634

8635
   vcode_select_block(loop1_bb);
19✔
8636

8637
   {
8638
      vcode_reg_t i_reg = emit_load(i_var);
19✔
8639
      vcode_reg_t sum_reg = emit_load(sum_var);
19✔
8640

8641
      vcode_reg_t elem_reg = emit_array_ref(data_reg, i_reg);
19✔
8642
      if (type_is_scalar(elem))
19✔
8643
         elem_reg = emit_load_indirect(elem_reg);
15✔
8644

8645
      vcode_reg_t args[] = { context_reg, elem_reg };
19✔
8646
      vcode_reg_t str_reg = emit_fcall(func, strtype, strtype, args, 2);
19✔
8647

8648
      vcode_reg_t edata_reg = emit_unwrap(str_reg);
19✔
8649
      vcode_reg_t elen_reg = emit_uarray_len(str_reg, 0);
19✔
8650
      emit_store(emit_add(sum_reg, elen_reg), sum_var);
19✔
8651

8652
      vcode_reg_t rptr_reg = emit_array_ref(elems_reg, i_reg);
19✔
8653
      emit_store_indirect(edata_reg, emit_record_ref(rptr_reg, 0));
19✔
8654
      emit_store_indirect(elen_reg, emit_record_ref(rptr_reg, 1));
19✔
8655

8656
      vcode_reg_t next_reg = emit_add(i_reg, one_reg);
19✔
8657
      emit_store(next_reg, i_var);
19✔
8658

8659
      vcode_reg_t done_reg = emit_cmp(VCODE_CMP_EQ, next_reg, length_reg);
19✔
8660
      emit_cond(done_reg, alloc_bb, loop1_bb);
19✔
8661
   }
8662

8663
   vcode_select_block(alloc_bb);
19✔
8664

8665
   vcode_reg_t sum_reg = emit_load(sum_var);
19✔
8666
   vcode_reg_t mem_reg = emit_alloc(ctype, ctype, sum_reg);
19✔
8667

8668
   vcode_reg_t lparen_reg = emit_array_ref(mem_reg, zero_reg);
19✔
8669
   emit_store_indirect(emit_const(ctype, '('), lparen_reg);
19✔
8670

8671
   vcode_block_t loop2_bb = emit_block();
19✔
8672
   vcode_block_t exit_bb = emit_block();
19✔
8673

8674
   vcode_var_t index_var = lower_temp_var(lu, "index", voffset, voffset);
19✔
8675
   emit_store(zero_reg, i_var);
19✔
8676
   emit_store(one_reg, index_var);
19✔
8677

8678
   emit_cond(null_reg, exit_bb, loop2_bb);
19✔
8679

8680
   vcode_select_block(loop2_bb);
19✔
8681

8682
   {
8683
      vcode_reg_t i_reg = emit_load(i_var);
19✔
8684
      vcode_reg_t index_reg = emit_load(index_var);
19✔
8685

8686
      vcode_reg_t rptr_reg = emit_array_ref(elems_reg, i_reg);
19✔
8687
      vcode_reg_t edata_reg = emit_load_indirect(emit_record_ref(rptr_reg, 0));
19✔
8688
      vcode_reg_t elen_reg = emit_load_indirect(emit_record_ref(rptr_reg, 1));
19✔
8689

8690
      vcode_reg_t dest_reg = emit_array_ref(mem_reg, index_reg);
19✔
8691
      emit_copy(dest_reg, edata_reg, elen_reg);
19✔
8692

8693
      index_reg = emit_add(index_reg, elen_reg);
19✔
8694
      vcode_reg_t comma_reg = emit_array_ref(mem_reg, index_reg);
19✔
8695
      emit_store_indirect(emit_const(ctype, ','), comma_reg);
19✔
8696

8697
      emit_store(emit_add(index_reg, one_reg), index_var);
19✔
8698

8699
      vcode_reg_t next_reg = emit_add(i_reg, one_reg);
19✔
8700
      emit_store(next_reg, i_var);
19✔
8701

8702
      vcode_reg_t done_reg = emit_cmp(VCODE_CMP_EQ, next_reg, length_reg);
19✔
8703
      emit_cond(done_reg, exit_bb, loop2_bb);
19✔
8704
   }
8705

8706
   vcode_select_block(exit_bb);
19✔
8707

8708
   vcode_reg_t last_reg = emit_sub(sum_reg, one_reg);
19✔
8709
   vcode_reg_t rparen_reg = emit_array_ref(mem_reg, last_reg);
19✔
8710
   emit_store_indirect(emit_const(ctype, ')'), rparen_reg);
19✔
8711

8712
   vcode_dim_t dims[] = {
19✔
8713
      { .left  = emit_const(voffset, 1),
19✔
8714
        .right = sum_reg,
8715
        .dir   = emit_const(vtype_bool(), RANGE_TO)
19✔
8716
      }
8717
   };
8718
   emit_return(emit_wrap(mem_reg, dims, 1));
19✔
8719
}
19✔
8720

8721
static void lower_character_array_image_helper(lower_unit_t *lu, type_t type,
81✔
8722
                                               vcode_reg_t preg, bool quote)
8723
{
8724
   type_t elem = type_base_recur(type_elem(type));
81✔
8725
   vcode_type_t ctype = vtype_char();
81✔
8726
   vcode_type_t voffset = vtype_offset();
81✔
8727

8728
   const int nlits = type_enum_literals(elem);
81✔
8729
   vcode_reg_t *map LOCAL = xmalloc_array(nlits, sizeof(vcode_reg_t));
162✔
8730
   for (int i = 0; i < nlits; i++) {
556✔
8731
      const ident_t id = tree_ident(type_enum_literal(elem, i));
475✔
8732
      assert(ident_char(id, 0) == '\'');
475✔
8733
      map[i] = emit_const(ctype, ident_char(id, 1));
475✔
8734
   }
8735

8736
   vcode_type_t map_vtype = vtype_carray(nlits, ctype, ctype);
81✔
8737
   vcode_reg_t map_reg = emit_const_array(map_vtype, map, nlits);
81✔
8738

8739
   vcode_reg_t zero_reg = emit_const(voffset, 0);
81✔
8740
   vcode_reg_t one_reg = emit_const(voffset, 1);
81✔
8741
   vcode_reg_t two_reg = emit_const(voffset, 2);
81✔
8742

8743
   vcode_reg_t length_reg = lower_array_len(lu, type, 0, preg);
81✔
8744
   vcode_reg_t data_reg = lower_array_data(preg);
81✔
8745
   vcode_reg_t total_reg = quote ? emit_add(length_reg, two_reg) : length_reg;
81✔
8746

8747
   vcode_reg_t mem_reg = emit_alloc(ctype, ctype, total_reg);
81✔
8748

8749
   vcode_var_t i_var = lower_temp_var(lu, "i", voffset, voffset);
81✔
8750
   emit_store(zero_reg, i_var);
81✔
8751

8752
   if (quote) {
81✔
8753
      vcode_reg_t lquote_reg = emit_array_ref(mem_reg, zero_reg);
42✔
8754
      emit_store_indirect(emit_const(ctype, '"'), lquote_reg);
42✔
8755
   }
8756

8757
   vcode_reg_t null_reg = emit_cmp(VCODE_CMP_EQ, length_reg, zero_reg);
81✔
8758

8759
   vcode_block_t body_bb = emit_block();
81✔
8760
   vcode_block_t exit_bb = emit_block();
81✔
8761

8762
   emit_cond(null_reg, exit_bb, body_bb);
81✔
8763

8764
   vcode_select_block(body_bb);
81✔
8765

8766
   vcode_reg_t i_reg    = emit_load(i_var);
81✔
8767
   vcode_reg_t sptr_reg = emit_array_ref(data_reg, i_reg);
81✔
8768
   vcode_reg_t src_reg  = emit_load_indirect(sptr_reg);
81✔
8769
   vcode_reg_t off_reg  = emit_cast(voffset, voffset, src_reg);
81✔
8770
   vcode_reg_t lptr_reg = emit_array_ref(emit_address_of(map_reg), off_reg);
81✔
8771
   vcode_reg_t doff_reg = quote ? emit_add(i_reg, one_reg) : i_reg;
81✔
8772
   vcode_reg_t dptr_reg = emit_array_ref(mem_reg, doff_reg);
81✔
8773

8774
   emit_store_indirect(emit_load_indirect(lptr_reg), dptr_reg);
81✔
8775

8776
   vcode_reg_t next_reg = emit_add(i_reg, one_reg);
81✔
8777
   vcode_reg_t cmp_reg  = emit_cmp(VCODE_CMP_EQ, next_reg, length_reg);
81✔
8778
   emit_store(next_reg, i_var);
81✔
8779
   emit_cond(cmp_reg, exit_bb, body_bb);
81✔
8780

8781
   vcode_select_block(exit_bb);
81✔
8782

8783
   if (quote) {
81✔
8784
      vcode_reg_t right_reg = emit_add(length_reg, one_reg);
42✔
8785
      vcode_reg_t rquote_reg = emit_array_ref(mem_reg, right_reg);
42✔
8786
      emit_store_indirect(emit_const(ctype, '"'), rquote_reg);
42✔
8787
   }
8788

8789
   vcode_dim_t dims[] = {
81✔
8790
      {
8791
         .left  = emit_const(voffset, 1),
81✔
8792
         .right = total_reg,
8793
         .dir   = emit_const(vtype_bool(), RANGE_TO)
81✔
8794
      }
8795
   };
8796
   emit_return(emit_wrap(mem_reg, dims, 1));
81✔
8797
}
81✔
8798

8799
static void lower_image_helper(lower_unit_t *lu, object_t *obj)
245✔
8800
{
8801
   tree_t decl = tree_from_object(obj);
245✔
8802

8803
   type_t type = tree_type(decl);
245✔
8804
   assert(type_is_representable(type));
245✔
8805

8806
   vcode_type_t ctype = vtype_char();
245✔
8807
   vcode_type_t strtype = vtype_uarray(1, ctype, ctype);
245✔
8808
   vcode_set_result(strtype);
245✔
8809

8810
   vcode_type_t vcontext = vtype_context(lu->parent->name);
245✔
8811
   emit_param(vcontext, vcontext, ident_new("context"));
245✔
8812

8813
   vcode_type_t ptype = lower_param_type(type, C_CONSTANT, PORT_IN);
245✔
8814
   vcode_reg_t preg = emit_param(ptype, lower_bounds(type), ident_new("VAL"));
245✔
8815

8816
   switch (type_kind(type)) {
245✔
8817
   case T_ENUM:
88✔
8818
      lower_enum_image_helper(type, preg);
88✔
8819
      break;
88✔
8820
   case T_INTEGER:
71✔
8821
   case T_REAL:
8822
      lower_numeric_image_helper(lu, type, preg);
71✔
8823
      break;
71✔
8824
   case T_PHYSICAL:
15✔
8825
      lower_physical_image_helper(lu, type, preg);
15✔
8826
      break;
15✔
8827
   case T_RECORD:
10✔
8828
      lower_record_image_helper(lu, type, preg);
10✔
8829
      break;
10✔
8830
   case T_SUBTYPE:
11✔
8831
      assert(type_is_array(type));
11✔
8832
      // Fall-through
8833
   case T_ARRAY:
8834
      {
8835
         type_t elem = type_elem(type);
61✔
8836
         if (type_is_enum(elem) && all_character_literals(elem))
61✔
8837
            lower_character_array_image_helper(lu, type, preg, true);
42✔
8838
         else
8839
            lower_array_image_helper(lu, type, preg);
19✔
8840
      }
8841
      break;
8842
   default:
×
8843
      fatal_trace("cannot lower image helper for type %s", type_pp(type));
8844
   }
8845
}
245✔
8846

8847
static void lower_enum_value_helper(lower_unit_t *lu, type_t type,
65✔
8848
                                    tree_t decl, vcode_reg_t preg)
8849
{
8850
   const int nlits = type_enum_literals(type);
65✔
8851
   assert(nlits >= 1);
65✔
8852

8853
   vcode_reg_t arg_len_reg  = emit_uarray_len(preg, 0);
65✔
8854
   vcode_reg_t arg_data_reg = emit_unwrap(preg);
65✔
8855

8856
   vcode_type_t voffset = vtype_offset();
65✔
8857
   vcode_type_t vchar = vtype_char();
65✔
8858
   vcode_type_t vstring = vtype_uarray(1, vchar, vchar);
65✔
8859

8860
   ident_t canon_fn = ident_new("NVC.TEXT_UTIL.CANON_VALUE(S)S");
65✔
8861
   vcode_reg_t canon_args[] = {
65✔
8862
      lower_context_for_call(lu, canon_fn),
65✔
8863
      preg,
8864
   };
8865
   vcode_reg_t canon_reg = emit_fcall(canon_fn, vstring, vchar,
65✔
8866
                                      canon_args, ARRAY_LEN(canon_args));
8867
   vcode_reg_t canon_len_reg  = emit_uarray_len(canon_reg, 0);
65✔
8868

8869
   size_t stride = 0;
65✔
8870
   vcode_reg_t *len_regs LOCAL = xmalloc_array(nlits, sizeof(vcode_reg_t));
130✔
8871
   for (int i = 0; i < nlits; i++) {
1,127✔
8872
      size_t len = ident_len(tree_ident(type_enum_literal(type, i)));
1,062✔
8873
      len_regs[i] = emit_const(voffset, len);
1,062✔
8874
      stride = MAX(stride, len);
1,062✔
8875
   }
8876

8877
   vcode_type_t len_array_type = vtype_carray(nlits, voffset, voffset);
65✔
8878
   vcode_reg_t len_array_reg =
65✔
8879
      emit_const_array(len_array_type, len_regs, nlits);
65✔
8880
   vcode_reg_t len_array_ptr = emit_address_of(len_array_reg);
65✔
8881

8882
   const size_t nchars = nlits * stride;
65✔
8883
   vcode_reg_t *char_regs LOCAL = xmalloc_array(nchars, sizeof(vcode_reg_t));
130✔
8884
   for (int i = 0; i < nlits; i++) {
1,127✔
8885
      const char *str = istr(tree_ident(type_enum_literal(type, i)));
1,062✔
8886
      size_t pos = 0;
1,062✔
8887
      for (const char *p = str; *p; p++, pos++)
5,258✔
8888
         char_regs[(i * stride) + pos] = emit_const(vchar, *p);
4,196✔
8889
      for (; pos < stride; pos++)
2,202✔
8890
         char_regs[(i * stride) + pos] = emit_const(vchar, 0);
1,140✔
8891
   }
8892

8893
   vcode_type_t char_array_type = vtype_carray(nchars, vchar, vchar);
65✔
8894
   vcode_reg_t char_array_reg =
65✔
8895
      emit_const_array(char_array_type, char_regs, nchars);
65✔
8896
   vcode_reg_t char_array_ptr = emit_address_of(char_array_reg);
65✔
8897

8898
   vcode_var_t i_var = lower_temp_var(lu, "i", voffset, voffset);
65✔
8899
   emit_store(emit_const(voffset, 0), i_var);
65✔
8900

8901
   vcode_block_t head_bb = emit_block();
65✔
8902
   vcode_block_t fail_bb = emit_block();
65✔
8903
   emit_jump(head_bb);
65✔
8904

8905
   const loc_t *loc = vcode_last_loc();
65✔
8906

8907
   vcode_select_block(head_bb);
65✔
8908

8909
   vcode_reg_t i_reg = emit_load(i_var);
65✔
8910

8911
   vcode_block_t memcmp_bb = emit_block();
65✔
8912
   vcode_block_t skip_bb   = emit_block();
65✔
8913
   vcode_block_t match_bb  = emit_block();
65✔
8914

8915
   vcode_reg_t len_ptr = emit_array_ref(len_array_ptr, i_reg);
65✔
8916
   vcode_reg_t len_reg = emit_load_indirect(len_ptr);
65✔
8917
   vcode_reg_t len_eq  = emit_cmp(VCODE_CMP_EQ, len_reg, canon_len_reg);
65✔
8918
   emit_cond(len_eq, memcmp_bb, skip_bb);
65✔
8919

8920
   vcode_select_block(memcmp_bb);
65✔
8921
   vcode_reg_t char_off = emit_mul(i_reg, emit_const(voffset, stride));
65✔
8922
   vcode_reg_t char_ptr = emit_array_ref(char_array_ptr, char_off);
65✔
8923

8924
   vcode_dim_t dims[] = {
65✔
8925
      { .left  = emit_const(vtype_offset(), 1),
65✔
8926
        .right = len_reg,
8927
        .dir   = emit_const(vtype_bool(), RANGE_TO)
65✔
8928
      }
8929
   };
8930
   vcode_reg_t str_reg = emit_wrap(char_ptr, dims, 1);
65✔
8931

8932
   type_t std_string = std_type(NULL, STD_STRING);
65✔
8933
   ident_t func = lower_predef_func_name(std_string, "=");
65✔
8934

8935
   vcode_type_t vbool = vtype_bool();
65✔
8936
   vcode_reg_t context_reg = lower_context_for_call(lu, func);
65✔
8937
   vcode_reg_t str_cmp_args[] = { context_reg, str_reg, canon_reg };
65✔
8938
   vcode_reg_t eq_reg = emit_fcall(func, vbool, vbool, str_cmp_args, 3);
65✔
8939
   emit_cond(eq_reg, match_bb, skip_bb);
65✔
8940

8941
   vcode_select_block(skip_bb);
65✔
8942

8943
   vcode_reg_t i_next = emit_add(i_reg, emit_const(voffset, 1));
65✔
8944
   emit_store(i_next, i_var);
65✔
8945

8946
   vcode_reg_t done_reg = emit_cmp(VCODE_CMP_EQ, i_next,
65✔
8947
                                   emit_const(voffset, nlits));
8948
   emit_cond(done_reg, fail_bb, head_bb);
65✔
8949

8950
   vcode_select_block(fail_bb);
65✔
8951
   emit_debug_info(loc);
65✔
8952

8953
   vcode_type_t vseverity = vtype_int(0, SEVERITY_FAILURE - 1);
65✔
8954
   vcode_reg_t failure_reg = emit_const(vseverity, SEVERITY_FAILURE);
65✔
8955

8956
   vcode_reg_t const_str_reg =
65✔
8957
      lower_wrap_string("\" is not a valid enumeration value");
65✔
8958
   vcode_reg_t const_str_len = emit_uarray_len(const_str_reg, 0);
65✔
8959
   vcode_reg_t extra_len = emit_add(const_str_len, emit_const(voffset, 1));
65✔
8960
   vcode_reg_t msg_len = emit_add(arg_len_reg, extra_len);
65✔
8961
   vcode_reg_t mem_reg = emit_alloc(vchar, vchar, msg_len);
65✔
8962

8963
   emit_store_indirect(emit_const(vchar, '\"'), mem_reg);
65✔
8964

8965
   vcode_reg_t ptr1_reg = emit_array_ref(mem_reg, emit_const(voffset, 1));
65✔
8966
   emit_copy(ptr1_reg, arg_data_reg, arg_len_reg);
65✔
8967

8968
   vcode_reg_t ptr2_reg = emit_array_ref(ptr1_reg, arg_len_reg);
65✔
8969
   emit_copy(ptr2_reg, emit_unwrap(const_str_reg), const_str_len);
65✔
8970

8971
   vcode_type_t vtype = lower_type(type);
65✔
8972
   vcode_type_t vbounds = lower_bounds(type);
65✔
8973

8974
   vcode_reg_t locus = lower_debug_locus(type_enum_literal(type, 0));
65✔
8975
   emit_report(mem_reg, msg_len, failure_reg, locus);
65✔
8976
   emit_return(emit_const(vtype, 0));
65✔
8977

8978
   vcode_select_block(match_bb);
65✔
8979

8980
   lower_check_scalar_bounds(lu, i_reg, type, decl, NULL);
65✔
8981
   emit_return(emit_cast(vtype, vbounds, i_reg));
65✔
8982
}
65✔
8983

8984
static void lower_physical_value_helper(lower_unit_t *lu, type_t type,
7✔
8985
                                        tree_t decl, vcode_reg_t preg)
8986
{
8987
   vcode_reg_t arg_len_reg  = emit_uarray_len(preg, 0);
7✔
8988
   vcode_reg_t arg_data_reg = emit_unwrap(preg);
7✔
8989

8990
   vcode_type_t voffset = vtype_offset();
7✔
8991
   vcode_type_t vchar = vtype_char();
7✔
8992
   vcode_type_t vint64 = vtype_int(INT64_MIN, INT64_MAX);
7✔
8993
   vcode_type_t vstring = vtype_uarray(1, vchar, vchar);
7✔
8994

8995
   vcode_type_t vstdint = (standard() < STD_19)
7✔
8996
      ? vtype_int(INT32_MIN, INT32_MAX) : vtype_int(INT64_MIN, INT64_MAX);
7✔
8997

8998
   vcode_var_t used_var = lower_temp_var(lu, "used", vstdint, vstdint);
7✔
8999
   vcode_reg_t used_ptr = emit_index(used_var, VCODE_INVALID_REG);
7✔
9000

9001
   vcode_var_t int_var = lower_temp_var(lu, "int", vint64, vint64);
7✔
9002
   vcode_reg_t int_ptr = emit_index(int_var, VCODE_INVALID_REG);
7✔
9003

9004
   ident_t conv_fn =
7✔
9005
      ident_new("NVC.TEXT_UTIL.STRING_TO_INT(S21NVC.TEXT_UTIL.T_INT64N)");
7✔
9006
   vcode_reg_t text_util_reg = lower_context_for_call(lu, conv_fn);
7✔
9007
   vcode_reg_t conv_args[] = {
7✔
9008
      text_util_reg,
9009
      preg,
9010
      int_ptr,
9011
      used_ptr,
9012
   };
9013
   emit_fcall(conv_fn, VCODE_INVALID_TYPE, VCODE_INVALID_TYPE,
7✔
9014
              conv_args, ARRAY_LEN(conv_args));
9015

9016
   vcode_reg_t int_reg = emit_load(int_var);
7✔
9017
   vcode_reg_t used_reg = emit_cast(voffset, voffset, emit_load(used_var));
7✔
9018

9019
   vcode_reg_t tail_ptr = emit_array_ref(arg_data_reg, used_reg);
7✔
9020
   vcode_reg_t tail_len = emit_sub(arg_len_reg, used_reg);
7✔
9021

9022
   vcode_reg_t one_reg = emit_const(vtype_offset(), 1);
7✔
9023
   vcode_reg_t to_reg = emit_const(vtype_bool(), RANGE_TO);
7✔
9024

9025
   vcode_dim_t tail_dims[1] = {
7✔
9026
      { .left  = one_reg,
9027
        .right = tail_len,
9028
        .dir   = to_reg
9029
      },
9030
   };
9031
   vcode_reg_t tail_reg = emit_wrap(tail_ptr, tail_dims, 1);
7✔
9032

9033
   ident_t canon_fn = ident_new("NVC.TEXT_UTIL.CANON_VALUE(S)S");
7✔
9034
   vcode_reg_t canon_args[] = {
7✔
9035
      text_util_reg,
9036
      tail_reg,
9037
   };
9038
   vcode_reg_t canon_reg = emit_fcall(canon_fn, vstring, vchar,
7✔
9039
                                      canon_args, ARRAY_LEN(canon_args));
9040
   vcode_reg_t canon_len_reg = emit_uarray_len(canon_reg, 0);
7✔
9041

9042
   const int nunits = type_units(type);
7✔
9043
   assert(nunits >= 1);
7✔
9044

9045
   size_t stride = 0;
7✔
9046
   vcode_reg_t *len_regs LOCAL = xmalloc_array(nunits, sizeof(vcode_reg_t));
14✔
9047
   vcode_reg_t *mul_regs LOCAL = xmalloc_array(nunits, sizeof(vcode_reg_t));
14✔
9048
   for (int i = 0; i < nunits; i++) {
48✔
9049
      tree_t unit = type_unit(type, i);
41✔
9050
      size_t len = ident_len(tree_ident(unit));
41✔
9051
      len_regs[i] = emit_const(voffset, len);
41✔
9052
      stride = MAX(stride, len);
41✔
9053

9054
      vcode_reg_t value_reg = lower_rvalue(lu, tree_value(unit));
41✔
9055
      mul_regs[i] = emit_cast(vint64, vint64, value_reg);
41✔
9056
   }
9057

9058
   vcode_type_t len_array_type = vtype_carray(nunits, voffset, voffset);
7✔
9059
   vcode_reg_t len_array_reg =
7✔
9060
      emit_const_array(len_array_type, len_regs, nunits);
7✔
9061
   vcode_reg_t len_array_ptr = emit_address_of(len_array_reg);
7✔
9062

9063
   vcode_type_t mul_array_type = vtype_carray(nunits, vint64, vint64);
7✔
9064
   vcode_reg_t mul_array_reg =
7✔
9065
      emit_const_array(mul_array_type, mul_regs, nunits);
7✔
9066
   vcode_reg_t mul_array_ptr = emit_address_of(mul_array_reg);
7✔
9067

9068
   const size_t nchars = nunits * stride;
7✔
9069
   vcode_reg_t *char_regs LOCAL = xmalloc_array(nchars, sizeof(vcode_reg_t));
14✔
9070
   for (int i = 0; i < nunits; i++) {
48✔
9071
      const char *str = istr(tree_ident(type_unit(type, i)));
41✔
9072
      size_t pos = 0;
41✔
9073
      for (const char *p = str; *p; p++, pos++)
146✔
9074
         char_regs[(i * stride) + pos] = emit_const(vchar, *p);
105✔
9075
      for (; pos < stride; pos++)
68✔
9076
         char_regs[(i * stride) + pos] = emit_const(vchar, 0);
27✔
9077
   }
9078

9079
   vcode_type_t char_array_type = vtype_carray(nchars, vchar, vchar);
7✔
9080
   vcode_reg_t char_array_reg =
7✔
9081
      emit_const_array(char_array_type, char_regs, nchars);
7✔
9082
   vcode_reg_t char_array_ptr = emit_address_of(char_array_reg);
7✔
9083

9084
   vcode_var_t i_var = lower_temp_var(lu, "i", voffset, voffset);
7✔
9085
   emit_store(emit_const(voffset, 0), i_var);
7✔
9086

9087
   vcode_block_t head_bb = emit_block();
7✔
9088
   vcode_block_t fail_bb = emit_block();
7✔
9089
   emit_jump(head_bb);
7✔
9090

9091
   const loc_t *loc = vcode_last_loc();
7✔
9092

9093
   vcode_select_block(head_bb);
7✔
9094

9095
   vcode_reg_t i_reg = emit_load(i_var);
7✔
9096

9097
   vcode_block_t memcmp_bb = emit_block();
7✔
9098
   vcode_block_t skip_bb   = emit_block();
7✔
9099
   vcode_block_t match_bb  = emit_block();
7✔
9100

9101
   vcode_reg_t len_ptr = emit_array_ref(len_array_ptr, i_reg);
7✔
9102
   vcode_reg_t len_reg = emit_load_indirect(len_ptr);
7✔
9103
   vcode_reg_t len_eq  = emit_cmp(VCODE_CMP_EQ, len_reg, canon_len_reg);
7✔
9104
   emit_cond(len_eq, memcmp_bb, skip_bb);
7✔
9105

9106
   vcode_select_block(memcmp_bb);
7✔
9107
   vcode_reg_t char_off = emit_mul(i_reg, emit_const(voffset, stride));
7✔
9108
   vcode_reg_t char_ptr = emit_array_ref(char_array_ptr, char_off);
7✔
9109

9110
   vcode_dim_t dims[] = {
7✔
9111
      { .left  = one_reg,
9112
        .right = len_reg,
9113
        .dir   = to_reg,
9114
      }
9115
   };
9116
   vcode_reg_t str_reg = emit_wrap(char_ptr, dims, 1);
7✔
9117

9118
   type_t std_string = std_type(NULL, STD_STRING);
7✔
9119
   ident_t func = lower_predef_func_name(std_string, "=");
7✔
9120

9121
   vcode_reg_t std_reg = emit_link_package(well_known(W_STD_STANDARD));
7✔
9122
   vcode_type_t vbool = vtype_bool();
7✔
9123
   vcode_reg_t str_cmp_args[] = { std_reg, str_reg, canon_reg };
7✔
9124
   vcode_reg_t eq_reg = emit_fcall(func, vbool, vbool, str_cmp_args, 3);
7✔
9125
   emit_cond(eq_reg, match_bb, skip_bb);
7✔
9126

9127
   vcode_select_block(skip_bb);
7✔
9128

9129
   vcode_reg_t i_next = emit_add(i_reg, emit_const(voffset, 1));
7✔
9130
   emit_store(i_next, i_var);
7✔
9131

9132
   vcode_reg_t done_reg = emit_cmp(VCODE_CMP_EQ, i_next,
7✔
9133
                                   emit_const(voffset, nunits));
9134
   emit_cond(done_reg, fail_bb, head_bb);
7✔
9135

9136
   vcode_select_block(fail_bb);
7✔
9137
   emit_debug_info(loc);
7✔
9138

9139
   vcode_type_t vseverity = vtype_int(0, SEVERITY_FAILURE - 1);
7✔
9140
   vcode_reg_t failure_reg = emit_const(vseverity, SEVERITY_FAILURE);
7✔
9141

9142
   vcode_reg_t const_str_reg = lower_wrap_string("\" is not a valid unit name");
7✔
9143
   vcode_reg_t const_str_len = emit_uarray_len(const_str_reg, 0);
7✔
9144
   vcode_reg_t extra_len = emit_add(const_str_len, emit_const(voffset, 1));
7✔
9145
   vcode_reg_t msg_len = emit_add(tail_len, extra_len);
7✔
9146
   vcode_reg_t mem_reg = emit_alloc(vchar, vchar, msg_len);
7✔
9147

9148
   emit_store_indirect(emit_const(vchar, '\"'), mem_reg);
7✔
9149

9150
   vcode_reg_t ptr1_reg = emit_array_ref(mem_reg, emit_const(voffset, 1));
7✔
9151
   emit_copy(ptr1_reg, tail_ptr, tail_len);
7✔
9152

9153
   vcode_reg_t ptr2_reg = emit_array_ref(ptr1_reg, tail_len);
7✔
9154
   emit_copy(ptr2_reg, emit_unwrap(const_str_reg), const_str_len);
7✔
9155

9156
   vcode_type_t vtype = lower_type(type);
7✔
9157
   vcode_type_t vbounds = lower_bounds(type);
7✔
9158

9159
   vcode_reg_t locus = lower_debug_locus(type_unit(type, 0));
7✔
9160
   emit_report(mem_reg, msg_len, failure_reg, locus);
7✔
9161
   emit_return(emit_const(vtype, 0));
7✔
9162

9163
   vcode_select_block(match_bb);
7✔
9164

9165
   vcode_reg_t mul_ptr = emit_array_ref(mul_array_ptr, i_reg);
7✔
9166
   vcode_reg_t mul_reg = emit_load_indirect(mul_ptr);
7✔
9167
   vcode_reg_t result_reg = emit_mul(int_reg, mul_reg);
7✔
9168

9169
   lower_check_scalar_bounds(lu, result_reg, type, decl, NULL);
7✔
9170
   emit_return(emit_cast(vtype, vbounds, result_reg));
7✔
9171
}
7✔
9172

9173
static void lower_numeric_value_helper(lower_unit_t *lu, type_t type,
49✔
9174
                                       tree_t decl, vcode_reg_t preg)
9175
{
9176
   vcode_reg_t result_reg;
49✔
9177
   if (type_is_real(type)) {
49✔
9178
      ident_t conv_fn = ident_new("NVC.TEXT_UTIL.STRING_TO_REAL(S)R");
13✔
9179

9180
      vcode_reg_t text_util_reg = lower_context_for_call(lu, conv_fn);
13✔
9181
      vcode_reg_t conv_args[] = { text_util_reg, preg };
13✔
9182

9183
      vcode_type_t vreal = vtype_real(-DBL_MAX, DBL_MAX);
13✔
9184

9185
      result_reg = emit_fcall(conv_fn, vreal, vreal,
13✔
9186
                              conv_args, ARRAY_LEN(conv_args));
9187
   }
9188
   else {
9189
      ident_t conv_fn =
36✔
9190
         ident_new("NVC.TEXT_UTIL.STRING_TO_INT(S)21NVC.TEXT_UTIL.T_INT64");
36✔
9191

9192
      vcode_reg_t text_util_reg = lower_context_for_call(lu, conv_fn);
36✔
9193
      vcode_reg_t conv_args[] = { text_util_reg, preg };
36✔
9194

9195
      vcode_type_t vint64 = vtype_int(INT64_MIN, INT64_MAX);
36✔
9196

9197
      result_reg = emit_fcall(conv_fn, vint64, vint64,
36✔
9198
                              conv_args, ARRAY_LEN(conv_args));
9199
   }
9200

9201
   vcode_type_t vtype = lower_type(type);
49✔
9202
   vcode_type_t vbounds = lower_bounds(type);
49✔
9203

9204
   lower_check_scalar_bounds(lu, result_reg, type, decl, NULL);
49✔
9205
   emit_return(emit_cast(vtype, vbounds, result_reg));
49✔
9206
}
49✔
9207

9208
static void lower_record_value_helper(lower_unit_t *lu, type_t type,
13✔
9209
                                      tree_t decl, vcode_reg_t preg)
9210
{
9211
   vcode_type_t voffset = vtype_offset();
13✔
9212
   vcode_type_t ctype = vtype_char();
13✔
9213
   vcode_type_t strtype = vtype_uarray(1, ctype, ctype);
13✔
9214
   vcode_type_t vtype = lower_type(type);
13✔
9215
   vcode_type_t vnat = vtype_int(0, INT64_MAX);
13✔
9216

9217
   vcode_reg_t locus = lower_debug_locus(decl);
13✔
9218

9219
   vcode_var_t result_var =
13✔
9220
      emit_var(vtype, vtype, ident_new("result"), VAR_HEAP);
13✔
9221

9222
   ident_t find_open_fn = ident_new("NVC.TEXT_UTIL.FIND_OPEN(S)N");
13✔
9223
   ident_t find_close_fn = ident_new("NVC.TEXT_UTIL.FIND_CLOSE(SN)");
13✔
9224
   ident_t next_delim_fn = ident_new("NVC.TEXT_UTIL.NEXT_DELIMITER(SN)S");
13✔
9225
   vcode_reg_t text_util_reg = lower_context_for_call(lu, next_delim_fn);
13✔
9226

9227
   vcode_reg_t open_args[] = { text_util_reg, preg };
13✔
9228
   vcode_reg_t open_reg = emit_fcall(find_open_fn, vnat, vnat, open_args, 2);
13✔
9229

9230
   vcode_reg_t off_reg = emit_cast(voffset, voffset, open_reg);
13✔
9231
   vcode_reg_t ptr_reg = emit_index(result_var, VCODE_INVALID_REG);
13✔
9232

9233
   const int nfields = type_fields(type);
13✔
9234
   for (int i = 0; i < nfields; i++) {
52✔
9235
      vcode_reg_t nd_args[] = { text_util_reg, preg, off_reg };
39✔
9236
      vcode_reg_t nd_reg = emit_fcall(next_delim_fn, strtype, ctype,
39✔
9237
                                      nd_args, 3);
9238

9239
      type_t ftype = type_base_recur(tree_type(type_field(type, i)));
39✔
9240

9241
      ident_t func = ident_prefix(type_ident(ftype), ident_new("value"), '$');
39✔
9242
      vcode_reg_t args[] = {
39✔
9243
         lower_context_for_call(lu, func),
39✔
9244
         nd_reg,
9245
      };
9246

9247
      vcode_type_t fvtype = lower_func_result_type(ftype);
39✔
9248
      vcode_type_t fvbounds = lower_bounds(ftype);
39✔
9249

9250
      vcode_reg_t value_reg = emit_fcall(func, fvtype, fvbounds, args, 2);
39✔
9251

9252
      vcode_reg_t vlen_reg = emit_uarray_len(nd_reg, 0);
39✔
9253
      off_reg = emit_add(off_reg, vlen_reg);
39✔
9254
      off_reg = emit_add(off_reg, emit_const(voffset, 1));   // Skip comma
39✔
9255

9256
      vcode_reg_t fptr_reg = emit_record_ref(ptr_reg, i);
39✔
9257
      if (type_is_array(ftype)) {
39✔
9258
         vcode_reg_t data_reg = lower_array_data(value_reg);
3✔
9259
         vcode_reg_t count_reg = lower_array_total_len(lu, ftype, value_reg);
3✔
9260
         emit_copy(fptr_reg, data_reg, count_reg);
3✔
9261
      }
9262
      else if (type_is_record(ftype))
36✔
9263
         lower_copy_record(lu, ftype, fptr_reg, value_reg, locus);
3✔
9264
      else
9265
         emit_store_indirect(value_reg, fptr_reg);
33✔
9266
   }
9267

9268
   vcode_reg_t close_args[] = { text_util_reg, preg, off_reg };
13✔
9269
   emit_fcall(find_close_fn, VCODE_INVALID_TYPE, VCODE_INVALID_TYPE,
13✔
9270
              close_args, ARRAY_LEN(close_args));
9271

9272
   emit_return(ptr_reg);
13✔
9273
}
13✔
9274

9275
static void lower_array_value_helper(lower_unit_t *lu, type_t type,
64✔
9276
                                     tree_t decl, vcode_reg_t preg)
9277
{
9278
   vcode_type_t voffset = vtype_offset();
64✔
9279
   vcode_type_t ctype = vtype_char();
64✔
9280
   vcode_type_t strtype = vtype_uarray(1, ctype, ctype);
64✔
9281
   vcode_type_t vnat = vtype_int(0, INT64_MAX);
64✔
9282

9283
   vcode_reg_t locus = lower_debug_locus(decl);
64✔
9284

9285
   vcode_reg_t zero_reg = emit_const(voffset, 0);
64✔
9286
   vcode_reg_t one_reg = emit_const(voffset, 1);
64✔
9287

9288
   vcode_var_t i_var = lower_temp_var(lu, "i", voffset, voffset);
64✔
9289
   emit_store(zero_reg, i_var);
64✔
9290

9291
   ident_t next_delim_fn = ident_new("NVC.TEXT_UTIL.NEXT_DELIMITER(SN)S");
64✔
9292
   ident_t count_delim_fn = ident_new("NVC.TEXT_UTIL.COUNT_DELIMITERS(S)N");
64✔
9293
   ident_t trim_ws_fn = ident_new("NVC.TEXT_UTIL.TRIM_WS(SNN)");
64✔
9294
   ident_t find_open_fn = ident_new("NVC.TEXT_UTIL.FIND_OPEN(S)N");
64✔
9295
   ident_t find_close_fn = ident_new("NVC.TEXT_UTIL.FIND_CLOSE(SN)");
64✔
9296
   ident_t bad_char_fn = ident_new("NVC.TEXT_UTIL.REPORT_BAD_CHAR(SC)");
64✔
9297
   vcode_reg_t text_util_reg = lower_context_for_call(lu, next_delim_fn);
64✔
9298

9299
   type_t elem = type_base_recur(type_elem_recur(type));
64✔
9300
   vcode_type_t velem = lower_type(elem);
64✔
9301
   vcode_type_t vbounds = lower_bounds(elem);
64✔
9302

9303
   if (type_is_character_array(type)) {
64✔
9304
      vcode_block_t body_bb = emit_block();
47✔
9305
      vcode_block_t bad_bb = emit_block();
47✔
9306
      vcode_block_t good_bb = emit_block();
47✔
9307
      vcode_block_t exit_bb = emit_block();
47✔
9308
      vcode_block_t paren_bb = emit_block();
47✔
9309

9310
      vcode_var_t first_var = emit_var(vnat, vnat, ident_new("first"), 0);
47✔
9311
      vcode_var_t last_var = emit_var(vnat, vnat, ident_new("last"), 0);
47✔
9312

9313
      vcode_reg_t first_ptr = emit_index(first_var, VCODE_INVALID_REG);
47✔
9314
      vcode_reg_t last_ptr = emit_index(last_var, VCODE_INVALID_REG);
47✔
9315

9316
      vcode_reg_t trim_args[] = { text_util_reg, preg, first_ptr, last_ptr };
47✔
9317
      emit_fcall(trim_ws_fn, VCODE_INVALID_TYPE, VCODE_INVALID_TYPE,
47✔
9318
                 trim_args, ARRAY_LEN(trim_args));
9319

9320
      vcode_reg_t first_reg = emit_cast(voffset, voffset, emit_load(first_var));
47✔
9321
      vcode_reg_t last_reg = emit_cast(voffset, voffset, emit_load(last_var));
47✔
9322

9323
      vcode_reg_t count_reg = emit_add(emit_sub(last_reg, first_reg), one_reg);
47✔
9324
      vcode_reg_t mem_reg = emit_alloc(velem, vbounds, count_reg);
47✔
9325

9326
      vcode_var_t pos_var = lower_temp_var(lu, "pos", voffset, voffset);
47✔
9327
      emit_store(emit_cast(voffset, voffset, first_reg), pos_var);
47✔
9328

9329
      const int nlits = type_enum_literals(elem);
47✔
9330
      vcode_reg_t entry_vtype = vtype_int(0, nlits);
47✔
9331
      vcode_reg_t map[256], def_reg = emit_const(entry_vtype, nlits);
47✔
9332
      for (int i = 0; i < 256; i++)
12,079✔
9333
         map[i] = def_reg;
12,032✔
9334
      for (int i = 0; i < nlits; i++) {
1,099✔
9335
         const ident_t id = tree_ident(type_enum_literal(elem, i));
1,052✔
9336
         if (ident_char(id, 0) == '\'')
1,052✔
9337
            map[(uint8_t)ident_char(id, 1)] = emit_const(entry_vtype, i);
855✔
9338
      }
9339

9340
      vcode_type_t map_vtype = vtype_carray(256, entry_vtype, entry_vtype);
47✔
9341
      vcode_reg_t map_array_reg = emit_const_array(map_vtype, map, 256);
47✔
9342
      vcode_reg_t map_reg = emit_address_of(map_array_reg);
47✔
9343

9344
      vcode_reg_t data_reg = lower_array_data(preg);
47✔
9345

9346
      vcode_reg_t null_reg = emit_cmp(VCODE_CMP_EQ, count_reg, zero_reg);
47✔
9347
      emit_cond(null_reg, exit_bb, body_bb);
47✔
9348

9349
      vcode_select_block(body_bb);
47✔
9350

9351
      vcode_reg_t i_reg = emit_load(i_var);
47✔
9352
      vcode_reg_t pos_reg = emit_load(pos_var);
47✔
9353
      vcode_reg_t sptr_reg = emit_array_ref(data_reg, pos_reg);
47✔
9354
      vcode_reg_t dptr_reg = emit_array_ref(mem_reg, i_reg);
47✔
9355
      vcode_reg_t char_reg = emit_load_indirect(sptr_reg);
47✔
9356
      vcode_reg_t cast_reg = emit_cast(voffset, ctype, char_reg);
47✔
9357
      vcode_reg_t mptr_reg = emit_array_ref(map_reg, cast_reg);
47✔
9358
      vcode_reg_t entry_reg = emit_load_indirect(mptr_reg);
47✔
9359

9360
      vcode_reg_t bad_reg = emit_cmp(VCODE_CMP_EQ, entry_reg, def_reg);
47✔
9361
      emit_cond(bad_reg, bad_bb, good_bb);
47✔
9362

9363
      vcode_select_block(good_bb);
47✔
9364

9365
      vcode_reg_t good_reg = emit_cast(velem, velem, entry_reg);
47✔
9366
      emit_store_indirect(good_reg, dptr_reg);
47✔
9367

9368
      vcode_reg_t next_pos_reg = emit_add(pos_reg, one_reg);
47✔
9369
      emit_store(next_pos_reg, pos_var);
47✔
9370

9371
      vcode_reg_t next_i_reg = emit_add(i_reg, one_reg);
47✔
9372
      emit_store(next_i_reg, i_var);
47✔
9373

9374
      vcode_reg_t done_reg = emit_cmp(VCODE_CMP_EQ, next_i_reg, count_reg);
47✔
9375
      emit_cond(done_reg, exit_bb, body_bb);
47✔
9376

9377
      vcode_select_block(bad_bb);
47✔
9378

9379
      vcode_reg_t bad_char_args[] = { text_util_reg, preg, char_reg };
47✔
9380
      emit_fcall(bad_char_fn, VCODE_INVALID_TYPE, VCODE_INVALID_TYPE,
47✔
9381
                 bad_char_args, ARRAY_LEN(bad_char_args));
9382

9383
      emit_unreachable(locus);
47✔
9384

9385
      vcode_select_block(exit_bb);
47✔
9386

9387
      vcode_dim_t dims[] = {
47✔
9388
         { .left  = emit_const(vtype_offset(), 1),
47✔
9389
           .right = count_reg,
9390
           .dir   = emit_const(vtype_bool(), RANGE_TO)
47✔
9391
         }
9392
      };
9393

9394
      vcode_reg_t wrap_reg = emit_wrap(mem_reg, dims, 1);
47✔
9395
      emit_return(wrap_reg);
47✔
9396

9397
      vcode_select_block(paren_bb);
47✔
9398

9399
      lower_release_temp(lu, pos_var);
47✔
9400
   }
9401

9402
   vcode_block_t body_bb = emit_block();
64✔
9403
   vcode_block_t exit_bb = emit_block();
64✔
9404

9405
   vcode_reg_t count_args[] = { text_util_reg, preg };
64✔
9406
   vcode_reg_t count_result_reg = emit_fcall(count_delim_fn, vnat, vnat,
64✔
9407
                                             count_args, 2);
9408
   vcode_reg_t count_reg = emit_cast(voffset, voffset, count_result_reg);
64✔
9409

9410
   vcode_reg_t mem_reg = emit_alloc(velem, vbounds, count_reg);
64✔
9411

9412
   vcode_reg_t open_args[] = { text_util_reg, preg };
64✔
9413
   vcode_reg_t open_reg = emit_fcall(find_open_fn, vnat, vnat, open_args, 2);
64✔
9414

9415
   vcode_var_t pos_var = lower_temp_var(lu, "pos", voffset, voffset);
64✔
9416
   emit_store(emit_cast(voffset, voffset, open_reg), pos_var);
64✔
9417

9418
   vcode_reg_t null_reg = emit_cmp(VCODE_CMP_EQ, count_reg, zero_reg);
64✔
9419
   emit_cond(null_reg, exit_bb, body_bb);
64✔
9420

9421
   vcode_select_block(body_bb);
64✔
9422

9423
   vcode_reg_t i_reg = emit_load(i_var);
64✔
9424
   vcode_reg_t pos_reg = emit_load(pos_var);
64✔
9425

9426
   vcode_reg_t nd_args[] = { text_util_reg, preg, pos_reg };
64✔
9427
   vcode_reg_t nd_reg = emit_fcall(next_delim_fn, strtype, ctype, nd_args, 3);
64✔
9428

9429
   ident_t func = ident_prefix(type_ident(elem), ident_new("value"), '$');
64✔
9430
   vcode_reg_t args[] = {
64✔
9431
      lower_context_for_call(lu, func),
64✔
9432
      nd_reg,
9433
   };
9434

9435
   vcode_reg_t value_reg = emit_fcall(func, lower_func_result_type(elem),
64✔
9436
                                      vbounds, args, 2);
9437
   vcode_reg_t ptr_reg = emit_array_ref(mem_reg, i_reg);
64✔
9438

9439
   if (type_is_record(elem))
64✔
9440
      lower_copy_record(lu, elem, ptr_reg, value_reg, locus);
7✔
9441
   else
9442
      emit_store_indirect(value_reg, ptr_reg);
57✔
9443

9444
   vcode_reg_t next_i_reg = emit_add(i_reg, one_reg);
64✔
9445
   emit_store(next_i_reg, i_var);
64✔
9446

9447
   vcode_reg_t vlen_reg = emit_add(emit_uarray_len(nd_reg, 0), one_reg);
64✔
9448
   vcode_reg_t next_pos_reg = emit_add(pos_reg, vlen_reg);
64✔
9449
   emit_store(next_pos_reg, pos_var);
64✔
9450

9451
   vcode_reg_t done_reg = emit_cmp(VCODE_CMP_EQ, next_i_reg, count_reg);
64✔
9452
   emit_cond(done_reg, exit_bb, body_bb);
64✔
9453

9454
   vcode_select_block(exit_bb);
64✔
9455

9456
   vcode_reg_t close_args[] = { text_util_reg, preg, emit_load(pos_var) };
64✔
9457
   emit_fcall(find_close_fn, VCODE_INVALID_TYPE, VCODE_INVALID_TYPE,
64✔
9458
              close_args, ARRAY_LEN(close_args));
9459

9460
   vcode_dim_t dims[] = {
64✔
9461
      { .left  = emit_const(vtype_offset(), 1),
64✔
9462
        .right = count_reg,
9463
        .dir   = emit_const(vtype_bool(), RANGE_TO)
64✔
9464
      }
9465
   };
9466

9467
   vcode_reg_t wrap_reg = emit_wrap(mem_reg, dims, 1);
64✔
9468
   emit_return(wrap_reg);
64✔
9469
}
64✔
9470

9471
static void lower_value_helper(lower_unit_t *lu, object_t *obj)
198✔
9472
{
9473
   tree_t decl = tree_from_object(obj);
198✔
9474

9475
   type_t type = type_base_recur(tree_type(decl));
198✔
9476
   assert(type_is_representable(type));
198✔
9477

9478
   vcode_set_result(lower_func_result_type(type));
198✔
9479

9480
   vcode_type_t vcontext = vtype_context(lu->parent->name);
198✔
9481
   emit_param(vcontext, vcontext, ident_new("context"));
198✔
9482

9483
   vcode_type_t ctype = vtype_char();
198✔
9484
   vcode_type_t strtype = vtype_uarray(1, ctype, ctype);
198✔
9485
   vcode_reg_t preg = emit_param(strtype, strtype, ident_new("VAL"));
198✔
9486

9487
   switch (type_kind(type)) {
198✔
9488
   case T_ENUM:
65✔
9489
      lower_enum_value_helper(lu, type, decl, preg);
65✔
9490
      break;
65✔
9491
   case T_INTEGER:
49✔
9492
   case T_REAL:
9493
      lower_numeric_value_helper(lu, type, decl, preg);
49✔
9494
      break;
49✔
9495
   case T_PHYSICAL:
7✔
9496
      lower_physical_value_helper(lu, type, decl, preg);
7✔
9497
      break;
7✔
9498
   case T_RECORD:
13✔
9499
      lower_record_value_helper(lu, type, decl, preg);
13✔
9500
      break;
13✔
9501
   case T_ARRAY:
64✔
9502
      lower_array_value_helper(lu, type, decl, preg);
64✔
9503
      break;
64✔
9504
   default:
×
9505
      fatal_trace("cannot lower value helper for type %s", type_pp(type));
9506
   }
9507
}
198✔
9508

9509
static void lower_resolved_record_fn(lower_unit_t *lu, object_t *obj,
321✔
9510
                                     resolved_fn_t fn)
9511
{
9512
   tree_t decl = tree_from_object(obj);
321✔
9513

9514
   type_t type = tree_type(decl);
321✔
9515
   assert(!type_is_homogeneous(type) && can_be_signal(type));
321✔
9516

9517
   vcode_set_result(lower_func_result_type(type));
321✔
9518

9519
   vcode_type_t vtype = lower_type(type);
321✔
9520
   vcode_type_t vbounds = lower_bounds(type);
321✔
9521
   vcode_type_t vatype = lower_param_type(type, C_SIGNAL, PORT_IN);
321✔
9522

9523
   vcode_type_t vcontext = vtype_context(lu->parent->name);
321✔
9524
   emit_param(vcontext, vcontext, ident_new("context"));
321✔
9525

9526
   vcode_reg_t p_reg = emit_param(vatype, vbounds, ident_new("p"));
321✔
9527

9528
   vcode_var_t var = emit_var(vtype, vbounds, ident_new("result"), 0);
321✔
9529

9530
   vcode_reg_t data_reg, result_reg;
321✔
9531
   if (vtype_kind(vtype) == VCODE_TYPE_UARRAY) {
321✔
9532
      type_t elem = type_elem_recur(type);
85✔
9533
      vcode_reg_t count_reg = lower_array_total_len(lu, type, p_reg);
85✔
9534
      data_reg = emit_alloc(lower_type(elem), lower_bounds(elem),
85✔
9535
                            count_reg);
9536

9537
      result_reg = lower_rewrap(data_reg, p_reg);
85✔
9538
      emit_store(result_reg, var);
85✔
9539
   }
9540
   else
9541
      data_reg = result_reg = emit_index(var, VCODE_INVALID_VAR);
236✔
9542

9543
   lower_for_each_field_2(lu, type, type, p_reg, data_reg, VCODE_INVALID_REG,
321✔
9544
                          lower_resolved_field_cb, fn);
9545
   emit_return(result_reg);
321✔
9546
}
321✔
9547

9548
static void lower_resolved_helper(lower_unit_t *lu, object_t *obj)
283✔
9549
{
9550
   lower_resolved_record_fn(lu, obj, emit_resolved);
283✔
9551
}
283✔
9552

9553
static void lower_last_value_helper(lower_unit_t *lu, object_t *obj)
19✔
9554
{
9555
   lower_resolved_record_fn(lu, obj, emit_last_value);
19✔
9556
}
19✔
9557

9558
static void lower_driving_value_helper(lower_unit_t *lu, object_t *obj)
19✔
9559
{
9560
   lower_resolved_record_fn(lu, obj, emit_driving_value);
19✔
9561
}
19✔
9562

9563
static void lower_last_time_field_cb(lower_unit_t *lu, tree_t field,
96✔
9564
                                     vcode_reg_t field_ptr, vcode_reg_t dst_ptr,
9565
                                     vcode_reg_t locus, void *ctx)
9566
{
9567
   last_time_params_t *params = ctx;
96✔
9568
   vcode_reg_t last_reg = VCODE_INVALID_REG;
96✔
9569

9570
   type_t ftype = tree_type(field);
96✔
9571
   if (type_is_homogeneous(ftype)) {
96✔
9572
      vcode_reg_t field_reg = emit_load_indirect(field_ptr);
84✔
9573

9574
      if (type_is_array(ftype)) {
84✔
9575
         vcode_reg_t data_reg = lower_array_data(field_reg);
×
9576
         vcode_reg_t count_reg = lower_array_total_len(lu, ftype, field_reg);
×
9577
         last_reg = (*params->fn)(data_reg, count_reg);
×
9578
      }
9579
      else
9580
         last_reg = (*params->fn)(field_reg, VCODE_INVALID_REG);
84✔
9581
   }
9582
   else {
9583
      ident_t base_id = type_ident(type_base_recur(ftype));
12✔
9584
      ident_t helper_func =
12✔
9585
         ident_sprintf("%s$%s", istr(base_id), params->suffix);
12✔
9586

9587
      vcode_reg_t arg_reg = field_ptr;
12✔
9588
      if (type_is_array(ftype)
12✔
9589
          && vcode_reg_kind(arg_reg) != VCODE_TYPE_UARRAY)
6✔
9590
         arg_reg = lower_wrap(lu, ftype, field_ptr);
6✔
9591

9592
      vcode_type_t vtime = vtype_time();
12✔
9593
      vcode_reg_t context_reg = lower_context_for_call(lu, helper_func);
12✔
9594
      vcode_reg_t args[] = { context_reg, arg_reg };
12✔
9595
      last_reg = emit_fcall(helper_func, vtime, vtime, args, 2);
12✔
9596
   }
9597

9598
   vcode_reg_t cur_reg = emit_load(params->var);
96✔
9599
   vcode_reg_t cmp_reg = emit_cmp(VCODE_CMP_LT, last_reg, cur_reg);
96✔
9600
   vcode_reg_t new_reg = emit_select(cmp_reg, last_reg, cur_reg);
96✔
9601
   emit_store(new_reg, params->var);
96✔
9602
}
96✔
9603

9604
static void lower_last_time_fn(lower_unit_t *lu, object_t *obj,
44✔
9605
                               resolved_fn_t fn, const char *suffix)
9606
{
9607
   tree_t decl = tree_from_object(obj);
44✔
9608

9609
   type_t type = tree_type(decl);
44✔
9610
   assert(!type_is_homogeneous(type) && can_be_signal(type));
44✔
9611

9612
   vcode_type_t vtime = vtype_time();
44✔
9613
   vcode_type_t vatype = lower_param_type(type, C_SIGNAL, PORT_IN);
44✔
9614
   vcode_type_t vbounds = lower_bounds(type);
44✔
9615

9616
   vcode_set_result(vtime);
44✔
9617

9618
   vcode_type_t vcontext = vtype_context(lu->parent->name);
44✔
9619
   emit_param(vcontext, vcontext, ident_new("context"));
44✔
9620

9621
   vcode_reg_t p_reg = emit_param(vatype, vbounds, ident_new("p"));
44✔
9622

9623
   vcode_var_t var = emit_var(vtime, vtime, ident_new("result"), 0);
44✔
9624
   emit_store(emit_const(vtime, TIME_HIGH), var);
44✔
9625

9626
   last_time_params_t params = { fn, suffix, var };
44✔
9627
   lower_for_each_field(lu, type, p_reg, VCODE_INVALID_REG,
44✔
9628
                        lower_last_time_field_cb, &params);
9629

9630
   emit_return(emit_load(var));
44✔
9631
}
44✔
9632

9633
static void lower_last_event_helper(lower_unit_t *lu, object_t *obj)
22✔
9634
{
9635
   lower_last_time_fn(lu, obj, emit_last_event, "last_event");
22✔
9636
}
22✔
9637

9638
static void lower_last_active_helper(lower_unit_t *lu, object_t *obj)
22✔
9639
{
9640
   lower_last_time_fn(lu, obj, emit_last_active, "last_active");
22✔
9641
}
22✔
9642

9643
static void lower_copy_helper(lower_unit_t *lu, object_t *obj)
46✔
9644
{
9645
   tree_t decl = tree_from_object(obj);
46✔
9646

9647
   type_t type = tree_type(decl);
46✔
9648
   assert(!lower_trivially_copyable(type));
46✔
9649

9650
   vcode_type_t vbounds = lower_bounds(type);
46✔
9651
   vcode_type_t vdtype = lower_param_type(type, C_VARIABLE, PORT_OUT);
46✔
9652
   vcode_type_t vstype = lower_param_type(type, C_VARIABLE, PORT_IN);
46✔
9653
   vcode_type_t vlocus = vtype_debug_locus();
46✔
9654
   vcode_type_t vcontext = vtype_context(lu->parent->name);
46✔
9655
   emit_param(vcontext, vcontext, ident_new("context"));
46✔
9656

9657
   vcode_reg_t pdst_reg = emit_param(vdtype, vbounds, ident_new("dest"));
46✔
9658
   vcode_reg_t psrc_reg = emit_param(vstype, vbounds, ident_new("src"));
46✔
9659
   vcode_reg_t plocus = emit_param(vlocus, vlocus, ident_new("locus"));
46✔
9660

9661
   if (type_is_record(type)) {
46✔
9662
      const int nfields = type_fields(type);
40✔
9663
      for (int i = 0; i < nfields; i++) {
107✔
9664
         type_t ftype = tree_type(type_field(type, i));
67✔
9665

9666
         vcode_reg_t dst_ptr = emit_record_ref(pdst_reg, i);
67✔
9667
         vcode_reg_t src_ptr = emit_record_ref(psrc_reg, i);
67✔
9668

9669
         if (type_is_scalar(ftype) || type_is_access(ftype)) {
82✔
9670
            vcode_reg_t src_reg = emit_load_indirect(src_ptr);
15✔
9671
            emit_store_indirect(src_reg, dst_ptr);
15✔
9672
         }
9673
         else if (type_is_array(ftype)) {
52✔
9674
            vcode_reg_t src_reg = src_ptr;
46✔
9675
            if (have_uarray_ptr(src_reg))
46✔
9676
               src_reg = emit_load_indirect(src_ptr);
46✔
9677

9678
            vcode_reg_t dst_reg = dst_ptr;
46✔
9679
            if (have_uarray_ptr(dst_reg))
46✔
9680
               dst_reg = emit_load_indirect(dst_ptr);
46✔
9681

9682
            lower_copy_array(lu, ftype, ftype, dst_reg, src_reg, plocus);
46✔
9683
         }
9684
         else if (type_is_record(ftype))
6✔
9685
            lower_copy_record(lu, ftype, dst_ptr, src_ptr, plocus);
6✔
9686
         else
9687
            fatal_trace("unhandled field type %s in lower_copy_helper",
9688
                        type_pp(ftype));
9689
      }
9690
   }
9691
   else {
9692
      assert(type_is_array(type));
6✔
9693

9694
      type_t elem = type_elem_recur(type);
6✔
9695
      lower_check_array_sizes(lu, type, type, pdst_reg, psrc_reg, plocus);
6✔
9696

9697
      vcode_reg_t count_reg = lower_array_total_len(lu, type, psrc_reg);
6✔
9698

9699
      vcode_reg_t src_data = lower_array_data(psrc_reg);
6✔
9700
      vcode_reg_t dst_data = lower_array_data(pdst_reg);
6✔
9701

9702
      assert(!lower_trivially_copyable(elem));
6✔
9703

9704
      vcode_type_t voffset = vtype_offset();
6✔
9705

9706
      vcode_var_t i_var = lower_temp_var(lu, "i", voffset, voffset);
6✔
9707
      vcode_reg_t zero_reg = emit_const(voffset, 0);
6✔
9708
      emit_store(zero_reg, i_var);
6✔
9709

9710
      vcode_block_t body_bb = emit_block();
6✔
9711
      vcode_block_t exit_bb = emit_block();
6✔
9712

9713
      vcode_reg_t null_reg = emit_cmp(VCODE_CMP_EQ, count_reg, zero_reg);
6✔
9714
      emit_cond(null_reg, exit_bb, body_bb);
6✔
9715

9716
      vcode_select_block(body_bb);
6✔
9717

9718
      vcode_reg_t i_reg = emit_load(i_var);
6✔
9719
      vcode_reg_t dptr_reg = emit_array_ref(dst_data, i_reg);
6✔
9720
      vcode_reg_t sptr_reg = emit_array_ref(src_data, i_reg);
6✔
9721

9722
      lower_copy_record(lu, elem, dptr_reg, sptr_reg, plocus);
6✔
9723

9724
      vcode_reg_t next_reg = emit_add(i_reg, emit_const(voffset, 1));
6✔
9725
      emit_store(next_reg, i_var);
6✔
9726

9727
      vcode_reg_t done_reg = emit_cmp(VCODE_CMP_EQ, next_reg, count_reg);
6✔
9728
      emit_cond(done_reg, exit_bb, body_bb);
6✔
9729

9730
      vcode_select_block(exit_bb);
6✔
9731

9732
      lower_release_temp(lu, i_var);
6✔
9733
   }
9734

9735
   emit_return(VCODE_INVALID_REG);
46✔
9736
}
46✔
9737

9738
static void lower_new_helper(lower_unit_t *lu, object_t *obj)
36✔
9739
{
9740
   tree_t decl = tree_from_object(obj);
36✔
9741

9742
   type_t type = tree_type(decl);
36✔
9743
   assert(type_is_record(type) && !type_const_bounds(type));
36✔
9744

9745
   vcode_type_t vbounds = lower_bounds(type);
36✔
9746
   vcode_type_t vdtype = lower_param_type(type, C_VARIABLE, PORT_OUT);
36✔
9747
   vcode_type_t vstype = lower_param_type(type, C_VARIABLE, PORT_IN);
36✔
9748
   vcode_type_t vcontext = vtype_context(lu->parent->name);
36✔
9749
   emit_param(vcontext, vcontext, ident_new("context"));
36✔
9750

9751
   vcode_reg_t pdst_reg = emit_param(vdtype, vbounds, ident_new("dest"));
36✔
9752
   vcode_reg_t psrc_reg = emit_param(vstype, vbounds, ident_new("src"));
36✔
9753

9754
   const int nfields = type_fields(type);
36✔
9755
   for (int i = 0; i < nfields; i++) {
96✔
9756
      type_t ftype = tree_type(type_field(type, i));
60✔
9757

9758
      vcode_reg_t dst_ptr = emit_record_ref(pdst_reg, i);
60✔
9759
      vcode_reg_t src_ptr = emit_record_ref(psrc_reg, i);
60✔
9760

9761
      if (type_is_scalar(ftype) || type_is_access(ftype)) {
81✔
9762
         vcode_reg_t src_reg = emit_load_indirect(src_ptr);
21✔
9763
         emit_store_indirect(src_reg, dst_ptr);
21✔
9764
      }
9765
      else if (type_is_array(ftype)) {
39✔
9766
         vcode_reg_t src_reg = src_ptr;
36✔
9767
         if (have_uarray_ptr(src_reg))
36✔
9768
            src_reg = emit_load_indirect(src_ptr);
36✔
9769

9770
         vcode_reg_t count_reg = lower_array_total_len(lu, ftype, src_reg);
36✔
9771
         vcode_reg_t dst_reg = dst_ptr;
36✔
9772

9773
         if (have_uarray_ptr(dst_reg)) {
36✔
9774
            type_t scalar_elem = type_elem_recur(ftype);
36✔
9775
            vcode_type_t vtype = lower_type(scalar_elem);
36✔
9776
            vcode_reg_t mem_reg = emit_new(vtype, count_reg);
36✔
9777
            vcode_reg_t all_reg = emit_all(mem_reg);
36✔
9778
            vcode_reg_t wrap_reg = lower_rewrap(all_reg, src_reg);
36✔
9779

9780
            emit_store_indirect(wrap_reg, dst_ptr);
36✔
9781
            dst_reg = wrap_reg;
36✔
9782
         }
9783

9784
         vcode_reg_t src_data = lower_array_data(src_reg);
36✔
9785
         vcode_reg_t dst_data = lower_array_data(dst_reg);
36✔
9786
         emit_copy(dst_data, src_data, count_reg);
36✔
9787
      }
9788
      else if (type_is_record(ftype))
3✔
9789
         lower_new_record(lu, ftype, dst_ptr, src_ptr);
3✔
9790
      else
9791
         fatal_trace("unhandled type %s in lower_new_helper", type_pp(ftype));
9792
   }
9793

9794
   emit_return(VCODE_INVALID_REG);
36✔
9795
}
36✔
9796

9797
static void lower_instantiated_package(lower_unit_t *parent, tree_t decl)
183✔
9798
{
9799
   vcode_state_t state;
183✔
9800
   vcode_state_save(&state);
183✔
9801

9802
   vcode_select_unit(parent->vunit);
183✔
9803

9804
   ident_t context_id = vcode_unit_name(parent->vunit);
183✔
9805
   ident_t name = ident_prefix(context_id, tree_ident(decl), '.');
183✔
9806

9807
   vcode_unit_t vu = emit_package(name, tree_to_object(decl), parent->vunit);
183✔
9808

9809
   lower_unit_t *lu = lower_unit_new(parent->registry, parent,
183✔
9810
                                     vu, parent->cover, decl);
9811
   unit_registry_put(parent->registry, lu);
183✔
9812

9813
   lu->cscope = cover_create_scope(lu->cover, parent->cscope, decl, NULL);
183✔
9814

9815
   lower_generics(lu, decl, NULL);
183✔
9816
   lower_decls(lu, decl);
183✔
9817

9818
   emit_return(VCODE_INVALID_REG);
183✔
9819

9820
   unit_registry_finalise(parent->registry, lu);
183✔
9821

9822
   vcode_state_restore(&state);
183✔
9823

9824
   vcode_type_t vcontext = vtype_context(name);
183✔
9825
   vcode_var_t var = emit_var(vcontext, vcontext, name, 0);
183✔
9826
   lower_put_vcode_obj(decl, var, parent);
183✔
9827

9828
   vcode_reg_t pkg_reg = emit_package_init(name, emit_context_upref(0));
183✔
9829
   emit_store(pkg_reg, var);
183✔
9830

9831
   const int ngenerics = tree_generics(tree_ref(decl));
183✔
9832
   for (int i = 0; i < ngenerics; i++)
752✔
9833
      lower_put_vcode_obj(tree_generic(decl, i), var | INSTANCE_BIT, parent);
569✔
9834

9835
   const int ndecls = tree_decls(tree_ref(decl));
183✔
9836
   for (int i = 0; i < ndecls; i++)
589✔
9837
      lower_put_vcode_obj(tree_decl(decl, i), var | INSTANCE_BIT, parent);
406✔
9838
}
183✔
9839

9840
static void lower_type_bounds_var(lower_unit_t *lu, type_t type)
284✔
9841
{
9842
   if (type_is_array(type)) {
284✔
9843
      vcode_type_t vtype = lower_type(type);
161✔
9844
      assert(vtype_kind(vtype) == VCODE_TYPE_UARRAY);
161✔
9845

9846
      type_t elem = type_elem_recur(type);
161✔
9847
      vcode_type_t velem = lower_type(elem);
161✔
9848
      vcode_type_t vbounds = lower_bounds(elem);
161✔
9849

9850
      vcode_var_t var = emit_var(vtype, vbounds, type_ident(type), VAR_CONST);
161✔
9851

9852
      vcode_reg_t null_reg = emit_null(vtype_pointer(velem));
161✔
9853
      vcode_reg_t wrap_reg = lower_wrap(lu, type, null_reg);
161✔
9854
      emit_store(wrap_reg, var);
161✔
9855

9856
      lower_put_vcode_obj(type, var, lu);
161✔
9857
   }
9858
   else if (type_is_scalar(type)) {
123✔
9859
      vcode_type_t velem = lower_type(type);
31✔
9860
      vcode_type_t vbounds = lower_bounds(type);
31✔
9861

9862
      vcode_type_t vtype = vtype_uarray(1, velem, vbounds);
31✔
9863

9864
      vcode_var_t var = emit_var(vtype, vbounds, type_ident(type), VAR_CONST);
31✔
9865

9866
      tree_t r = range_of(type, 0);
31✔
9867
      vcode_reg_t left_reg = lower_range_left(lu, r);
31✔
9868
      vcode_reg_t right_reg = lower_range_right(lu, r);
31✔
9869
      vcode_reg_t dir_reg = lower_range_dir(lu, r);
31✔
9870

9871
      vcode_dim_t dims[1] = {
31✔
9872
         { left_reg, right_reg, dir_reg },
9873
      };
9874

9875
      vcode_reg_t null_reg = emit_null(vtype_pointer(velem));
31✔
9876
      vcode_reg_t wrap_reg = emit_wrap(null_reg, dims, 1);
31✔
9877
      emit_store(wrap_reg, var);
31✔
9878

9879
      lower_put_vcode_obj(type, var, lu);
31✔
9880
   }
9881
   else if (type_is_record(type)) {
92✔
9882
      vcode_type_t vtype = lower_type(type);
92✔
9883
      assert(vtype_kind(vtype) == VCODE_TYPE_RECORD);
92✔
9884

9885
      vcode_var_t var = emit_var(vtype, vtype, type_ident(type), VAR_CONST);
92✔
9886

9887
      vcode_reg_t ptr_reg = emit_index(var, VCODE_INVALID_REG);
92✔
9888
      vcode_reg_t value_reg = lower_default_value(lu, type, ptr_reg);
92✔
9889
      lower_copy_record(lu, type, ptr_reg, value_reg, VCODE_INVALID_REG);
92✔
9890

9891
      lower_put_vcode_obj(type, var, lu);
92✔
9892
   }
9893
   else
9894
      fatal_trace("unexpected type %s in lower_type_bounds", type_pp(type));
9895
}
284✔
9896

9897
static void lower_foreign_stub(lower_unit_t *lu, object_t *obj)
141✔
9898
{
9899
   tree_t spec = tree_from_object(obj);
141✔
9900
   assert(tree_kind(spec) == T_ATTR_SPEC);
141✔
9901

9902
   tree_t value = tree_value(spec);
141✔
9903
   type_t str_type = tree_type(value);
141✔
9904

9905
   tree_t sub = tree_ref(spec);
141✔
9906
   assert(is_subprogram(sub));
141✔
9907

9908
   type_t type = tree_type(sub);
141✔
9909
   if (type_has_result(type))
141✔
9910
      vcode_set_result(lower_func_result_type(type_result(type)));
90✔
9911

9912
   vcode_type_t vcontext = vtype_context(lu->parent->name);
141✔
9913
   emit_param(vcontext, vcontext, ident_new("context"));
141✔
9914

9915
   lower_subprogram_ports(lu, sub, false);
141✔
9916

9917
   vcode_reg_t spec_reg = lower_rvalue(lu, value);
141✔
9918
   vcode_reg_t data_reg = lower_array_data(spec_reg);
141✔
9919
   vcode_reg_t length_reg = lower_array_len(lu, str_type, 0, spec_reg);
141✔
9920
   vcode_reg_t locus = lower_debug_locus(spec);
141✔
9921

9922
   emit_bind_foreign(data_reg, length_reg, locus);
141✔
9923
   emit_unreachable(VCODE_INVALID_REG);
141✔
9924
}
141✔
9925

9926
static void lower_decl(lower_unit_t *lu, tree_t decl)
56,365✔
9927
{
9928
   PUSH_DEBUG_INFO(decl);
112,730✔
9929

9930
   switch (tree_kind(decl)) {
56,365✔
9931
   case T_CONST_DECL:
15,588✔
9932
   case T_VAR_DECL:
9933
      lower_var_decl(lu, decl);
15,588✔
9934
      break;
15,588✔
9935

9936
   case T_SIGNAL_DECL:
6,749✔
9937
      lower_signal_decl(lu, decl);
6,749✔
9938
      break;
6,749✔
9939

9940
   case T_IMPLICIT_SIGNAL:
159✔
9941
      lower_implicit_decl(lu, decl);
159✔
9942
      break;
159✔
9943

9944
   case T_FILE_DECL:
198✔
9945
      lower_file_decl(lu, decl);
198✔
9946
      break;
198✔
9947

9948
   case T_ALIAS:
6,348✔
9949
      lower_alias_decl(lu, decl);
6,348✔
9950
      break;
6,348✔
9951

9952
   case T_TYPE_DECL:
11,721✔
9953
      {
9954
         type_t type = tree_type(decl);
11,721✔
9955
         ident_t id = type_ident(type);
11,721✔
9956
         object_t *obj = tree_to_object(decl);
11,721✔
9957

9958
         if (needs_bounds_var(type))
11,721✔
9959
            lower_type_bounds_var(lu, type);
102✔
9960

9961
         if (type_is_representable(type)) {
11,721✔
9962
            ident_t image = ident_prefix(id, ident_new("image"), '$');
7,241✔
9963
            unit_registry_defer(lu->registry, image, lu, emit_function,
7,241✔
9964
                                lower_image_helper, NULL, obj);
9965

9966
            ident_t value = ident_prefix(id, ident_new("value"), '$');
7,241✔
9967
            unit_registry_defer(lu->registry, value, lu, emit_function,
7,241✔
9968
                                lower_value_helper, NULL, obj);
9969
         }
9970

9971
         if (!type_is_homogeneous(type) && can_be_signal(type)) {
11,721✔
9972
            ident_t resolved = ident_prefix(id, ident_new("resolved"), '$');
1,498✔
9973
            unit_registry_defer(lu->registry, resolved, lu, emit_function,
1,498✔
9974
                                lower_resolved_helper, NULL, obj);
9975

9976
            ident_t last_value = ident_prefix(id, ident_new("last_value"), '$');
1,498✔
9977
            unit_registry_defer(lu->registry, last_value, lu, emit_function,
1,498✔
9978
                                lower_last_value_helper, NULL, obj);
9979

9980
            ident_t last_event = ident_sprintf("%s$last_event", istr(id));
1,498✔
9981
            unit_registry_defer(lu->registry, last_event, lu, emit_function,
1,498✔
9982
                                lower_last_event_helper, NULL, obj);
9983

9984
            ident_t last_active = ident_sprintf("%s$last_active", istr(id));
1,498✔
9985
            unit_registry_defer(lu->registry, last_active, lu, emit_function,
1,498✔
9986
                                lower_last_active_helper, NULL, obj);
9987

9988
            ident_t driving = ident_prefix(id, ident_new("driving"), '$');
1,498✔
9989
            unit_registry_defer(lu->registry, driving, lu, emit_function,
1,498✔
9990
                                lower_driving_value_helper, NULL, obj);
9991
         }
9992

9993
         if (!lower_trivially_copyable(type)) {
11,721✔
9994
            ident_t copy = ident_prefix(id, ident_new("copy"), '$');
351✔
9995
            unit_registry_defer(lu->registry, copy, lu, emit_function,
351✔
9996
                                lower_copy_helper, NULL, obj);
9997
         }
9998

9999
         if (type_is_record(type) && !type_const_bounds(type)) {
11,721✔
10000
            ident_t new = ident_prefix(id, ident_new("new"), '$');
295✔
10001
            unit_registry_defer(lu->registry, new, lu, emit_function,
295✔
10002
                                lower_new_helper, NULL, obj);
10003
         }
10004
      }
10005
      break;
10006

10007
   case T_SUBTYPE_DECL:
3,023✔
10008
      {
10009
         type_t type = tree_type(decl);
3,023✔
10010
         if (needs_bounds_var(type))
3,023✔
10011
            lower_type_bounds_var(lu, type);
182✔
10012
      }
10013
      break;
10014

10015
   case T_FUNC_DECL:
10016
   case T_PROC_DECL:
10017
   case T_ATTR_DECL:
10018
   case T_COMPONENT:
10019
   case T_USE:
10020
   case T_SPEC:
10021
   case T_GROUP:
10022
   case T_GROUP_TEMPLATE:
10023
   case T_VIEW_DECL:
10024
   case T_PROT_DECL:
10025
   case T_HIER:
10026
   case T_ATTR_SPEC:
10027
      break;
10028

10029
   case T_PACKAGE:
195✔
10030
   case T_PACK_BODY:
10031
   case T_PACK_INST:
10032
      if (unit_needs_cgen(decl))
195✔
10033
         lower_instantiated_package(lu, decl);
183✔
10034
      break;
10035

10036
   case T_PSL_DECL:
72✔
10037
      psl_lower_decl(lu->registry, lu, tree_psl(decl), tree_ident(decl));
72✔
10038
      break;
72✔
10039

10040
   default:
×
10041
      fatal_trace("cannot lower decl kind %s", tree_kind_str(tree_kind(decl)));
10042
   }
10043
}
56,365✔
10044

10045
void lower_finished(lower_unit_t *lu, vcode_unit_t shape)
44,873✔
10046
{
10047
   assert(!lu->finished);
44,873✔
10048

10049
   vcode_select_unit(lu->vunit);
44,873✔
10050
   vcode_opt();
44,873✔
10051

10052
   if (opt_get_verbose(OPT_DUMP_VCODE, istr(lu->name)))
44,873✔
10053
      vcode_dump();
×
10054

10055
   if (shape != NULL)
44,873✔
10056
      vcode_check_shape(lu->vunit, shape);
90✔
10057

10058
   lu->finished = true;
44,873✔
10059
}
44,873✔
10060

10061
static void lower_protected_body(lower_unit_t *lu, object_t *obj)
175✔
10062
{
10063
   tree_t body = tree_from_object(obj);
175✔
10064
   assert(tree_kind(body) == T_PROT_BODY);
175✔
10065

10066
   lu->cscope = cover_create_scope(lu->cover, lu->cscope, body, NULL);
175✔
10067

10068
   if (standard() >= STD_19) {
175✔
10069
      // LCS-2016-032 requires dynamic 'PATH_NAME and 'INSTANCE_NAME for
10070
      // protected type
10071
      ident_t path_i = well_known(W_PATH_NAME);
49✔
10072
      ident_t inst_i = well_known(W_INSTANCE_NAME);
49✔
10073

10074
      vcode_type_t vchar = vtype_char();
49✔
10075
      vcode_type_t vstring = vtype_uarray(1, vchar, vchar);
49✔
10076
      vcode_reg_t path_reg = emit_param(vstring, vchar, path_i);
49✔
10077
      vcode_reg_t inst_reg = emit_param(vstring, vchar, inst_i);
49✔
10078

10079
      const tree_global_flags_t gflags = tree_global_flags(body);
49✔
10080

10081
      if (gflags & TREE_GF_INSTANCE_NAME) {
49✔
10082
         vcode_var_t path_var = emit_var(vstring, vchar, path_i, VAR_CONST);
46✔
10083
         lower_put_vcode_obj(path_i, path_var, lu);
46✔
10084
         emit_store(path_reg, path_var);
46✔
10085
      }
10086

10087
      if (gflags & TREE_GF_PATH_NAME) {
49✔
10088
         vcode_var_t inst_var = emit_var(vstring, vchar, inst_i, VAR_CONST);
46✔
10089
         lower_put_vcode_obj(inst_i, inst_var, lu);
46✔
10090
         emit_store(inst_reg, inst_var);
46✔
10091
      }
10092

10093
      lower_decls(lu, tree_primary(body));
49✔
10094
   }
10095

10096
   lower_decls(lu, body);
175✔
10097
   emit_return(VCODE_INVALID_REG);
175✔
10098
}
175✔
10099

10100
static void lower_decls(lower_unit_t *lu, tree_t scope)
29,561✔
10101
{
10102
   const int ndecls = tree_decls(scope);
29,561✔
10103
   for (int i = 0; i < ndecls; i++) {
263,013✔
10104
      tree_t d = tree_decl(scope, i);
233,452✔
10105
      if (tree_kind(d) != T_ATTR_SPEC)
233,452✔
10106
         continue;
231,422✔
10107
      else if (ident_casecmp(tree_ident(d), well_known(W_FOREIGN)))
2,030✔
10108
         unit_registry_defer(lu->registry, tree_ident2(tree_ref(d)), lu,
762✔
10109
                             emit_function, lower_foreign_stub, NULL,
10110
                             tree_to_object(d));
10111
   }
10112

10113
   for (int i = 0; i < ndecls; i++) {
263,013✔
10114
      tree_t d = tree_decl(scope, i);
233,452✔
10115
      switch (tree_kind(d)) {
233,452✔
10116
      case T_FUNC_INST:
39✔
10117
         if (!is_body(tree_ref(d)))
39✔
10118
            break;   // Deferred instantiation in package body
10119
         // Fall-through
10120
      case T_FUNC_BODY:
10121
         {
10122
            ident_t mangled = tree_ident2(d);
19,292✔
10123
            if (!unit_registry_query(lu->registry, mangled))
19,292✔
10124
               unit_registry_defer(lu->registry, mangled, lu,
18,632✔
10125
                                   emit_function, lower_func_body,
10126
                                   lu->cover, tree_to_object(d));
10127
         }
10128
         break;
10129
      case T_PROC_INST:
48✔
10130
         if (!is_body(tree_ref(d)))
48✔
10131
            break;   // Deferred instantiation in package body
10132
         // Fall-through
10133
      case T_PROC_BODY:
10134
         {
10135
            const bool never_waits = !!(tree_flags(d) & TREE_F_NEVER_WAITS)
4,625✔
10136
               || (tree_flags(d) & TREE_F_PROTECTED);
4,625✔
10137
            emit_fn_t emitfn = never_waits ? emit_function : emit_procedure;
4,625✔
10138
            ident_t mangled = tree_ident2(d);
4,625✔
10139

10140
            if (!unit_registry_query(lu->registry, mangled))
4,625✔
10141
               unit_registry_defer(lu->registry, tree_ident2(d),
4,523✔
10142
                                   lu, emitfn, lower_proc_body, lu->cover,
10143
                                   tree_to_object(d));
10144
         }
10145
         break;
10146
      case T_PROT_BODY:
176✔
10147
         unit_registry_defer(lu->registry, type_ident(tree_type(d)),
176✔
10148
                             lu, emit_protected, lower_protected_body,
10149
                             lu->cover, tree_to_object(d));
10150
         break;
176✔
10151
      case T_FUNC_DECL:
152,988✔
10152
      case T_PROC_DECL:
10153
        {
10154
           const subprogram_kind_t kind = tree_subkind(d);
152,988✔
10155
           if (kind == S_USER || is_open_coded_builtin(kind))
152,988✔
10156
              continue;
99,150✔
10157

10158
           unit_registry_defer(lu->registry, tree_ident2(d),
53,838✔
10159
                               lu, emit_function, lower_predef,
10160
                               lu->cover, tree_to_object(d));
10161
        }
10162
        break;
53,838✔
10163
      default:
56,365✔
10164
         lower_decl(lu, d);
56,365✔
10165
         break;
56,365✔
10166
      }
10167
   }
10168
}
29,561✔
10169

10170
static bool lower_has_subprograms(tree_t scope)
7,605✔
10171
{
10172
   const int ndecls = tree_decls(scope);
7,605✔
10173
   for (int i = 0; i < ndecls; i++) {
15,536✔
10174
      tree_t d = tree_decl(scope, i);
8,054✔
10175
      const tree_kind_t kind = tree_kind(d);
8,054✔
10176
      if (kind == T_FUNC_BODY || kind == T_PROC_BODY)
8,054✔
10177
         return true;
10178
      else if (kind == T_FUNC_INST || kind == T_PROC_INST)
7,973✔
10179
         return true;
10180
      else if (kind == T_TYPE_DECL) {
7,973✔
10181
         // Predefined operators for certain types may reference the
10182
         // parameters: e.g. an array with non-static length
10183
         type_t type = tree_type(d);
50✔
10184
         if (type_is_record(type) || type_is_array(type))
50✔
10185
            return true;
42✔
10186
      }
10187
   }
10188

10189
   return false;
10190
}
10191

10192
static void lower_subprogram_ports(lower_unit_t *lu, tree_t body,
10,203✔
10193
                                   bool params_as_vars)
10194
{
10195
   const int nports = tree_ports(body);
10,203✔
10196
   for (int i = 0; i < nports; i++) {
27,773✔
10197
      tree_t p = tree_port(body, i);
17,570✔
10198
      type_t type = tree_type(p);
17,570✔
10199

10200
      const class_t class = tree_class(p);
17,570✔
10201
      const port_mode_t mode = tree_subkind(p);
17,570✔
10202

10203
      vcode_type_t vtype = lower_param_type(type, class, mode);
17,570✔
10204
      vcode_type_t vbounds = lower_bounds(type);
17,570✔
10205

10206
      vcode_reg_t preg = emit_param(vtype, vbounds, tree_ident(p));
17,570✔
10207
      if (params_as_vars) {
17,570✔
10208
         vcode_var_t var = emit_var(vtype, vbounds, tree_ident(p), 0);
735✔
10209
         emit_store(preg, var);
735✔
10210
         lower_put_vcode_obj(p, var | PARAM_VAR_BIT, lu);
735✔
10211
      }
10212
      else
10213
         lower_put_vcode_obj(p, preg, lu);
16,835✔
10214
   }
10215
}
10,203✔
10216

10217
static ident_t lower_predef_func_name(type_t type, const char *op)
441✔
10218
{
10219
   type_t base = type_base_recur(type);
441✔
10220

10221
   LOCAL_TEXT_BUF tb = tb_new();
882✔
10222
   tb_printf(tb, "%s.\"%s\"(", istr(ident_runtil(type_ident(base), '.')), op);
441✔
10223
   mangle_one_type(tb, base);
441✔
10224
   mangle_one_type(tb, base);
441✔
10225
   tb_cat(tb, ")");
441✔
10226
   mangle_one_type(tb, std_type(NULL, STD_BOOLEAN));
441✔
10227
   tb_cat(tb, "$predef");
441✔
10228

10229
   return ident_new(tb_get(tb));
441✔
10230
}
10231

10232
static void lower_array_cmp_inner(lower_unit_t *lu,
1,693✔
10233
                                  vcode_reg_t lhs_data,
10234
                                  vcode_reg_t rhs_data,
10235
                                  vcode_reg_t lhs_array,
10236
                                  vcode_reg_t rhs_array,
10237
                                  type_t left_type,
10238
                                  type_t right_type,
10239
                                  vcode_cmp_t pred,
10240
                                  vcode_block_t fail_bb)
10241
{
10242
   // Behaviour of relational operators on arrays is described in
10243
   // LRM 93 section 7.2.2
10244

10245
   assert(pred == VCODE_CMP_EQ || pred == VCODE_CMP_LT
1,693✔
10246
          || pred == VCODE_CMP_LEQ);
10247

10248
   const int ndims = dimension_of(left_type);
1,693✔
10249
   assert(dimension_of(right_type) == ndims);
1,693✔
10250

10251
   vcode_reg_t left_len = lower_array_len(lu, left_type, 0, lhs_array);
1,693✔
10252
   for (int i = 1; i < ndims; i++) {
1,738✔
10253
      vcode_reg_t dim_len = lower_array_len(lu, left_type, i, lhs_array);
45✔
10254
      left_len = emit_mul(dim_len, left_len);
45✔
10255
   }
10256

10257
   vcode_reg_t right_len = lower_array_len(lu, right_type, 0, rhs_array);
1,693✔
10258
   for (int i = 1; i < ndims; i++) {
1,738✔
10259
      vcode_reg_t dim_len = lower_array_len(lu, right_type, i, rhs_array);
45✔
10260
      right_len = emit_mul(dim_len, right_len);
45✔
10261
   }
10262

10263
   vcode_type_t voffset = vtype_offset();
1,693✔
10264
   vcode_var_t i_var = lower_temp_var(lu, "i", voffset, voffset);
1,693✔
10265
   emit_store(emit_const(voffset, 0), i_var);
1,693✔
10266

10267
   vcode_block_t test_bb = emit_block();
1,693✔
10268
   vcode_block_t body_bb = emit_block();
1,693✔
10269
   vcode_block_t exit_bb = emit_block();
1,693✔
10270

10271
   type_t elem_type = type_elem(left_type);
1,693✔
10272

10273
   vcode_reg_t stride = VCODE_INVALID_REG;
1,693✔
10274
   if (type_is_array(elem_type))
1,693✔
10275
      stride = lower_array_stride(lu, left_type, lhs_array);
177✔
10276

10277
   vcode_reg_t len_eq = emit_cmp(VCODE_CMP_EQ, left_len, right_len);
1,693✔
10278

10279
   if (pred == VCODE_CMP_EQ)
1,693✔
10280
      emit_cond(len_eq, test_bb, fail_bb);
1,547✔
10281
   else
10282
      emit_jump(test_bb);
146✔
10283

10284
   // Loop test
10285

10286
   vcode_select_block(test_bb);
1,693✔
10287

10288
   vcode_reg_t i_loaded = emit_load(i_var);
1,693✔
10289

10290
   if (pred == VCODE_CMP_EQ) {
1,693✔
10291
      vcode_reg_t done = emit_cmp(VCODE_CMP_EQ, i_loaded, left_len);
1,547✔
10292
      emit_cond(done, exit_bb, body_bb);
1,547✔
10293
   }
10294
   else {
10295
      vcode_block_t check_r_len_bb = emit_block();
146✔
10296

10297
      vcode_reg_t len_ge_l = emit_cmp(VCODE_CMP_GEQ, i_loaded, left_len);
146✔
10298
      emit_cond(len_ge_l, exit_bb, check_r_len_bb);
146✔
10299

10300
      vcode_select_block(check_r_len_bb);
146✔
10301

10302
      vcode_reg_t len_ge_r = emit_cmp(VCODE_CMP_GEQ, i_loaded, right_len);
146✔
10303
      emit_cond(len_ge_r, fail_bb, body_bb);
146✔
10304
   }
10305

10306
   // Loop body
10307

10308
   vcode_select_block(body_bb);
1,693✔
10309

10310
   vcode_reg_t ptr_inc = i_loaded;
1,693✔
10311
   if (stride != VCODE_INVALID_REG)
1,693✔
10312
      ptr_inc = emit_mul(ptr_inc, stride);
177✔
10313

10314
   vcode_reg_t inc = emit_add(i_loaded, emit_const(voffset, 1));
1,693✔
10315
   emit_store(inc, i_var);
1,693✔
10316

10317
   vcode_reg_t i_eq_len = emit_cmp(VCODE_CMP_EQ, inc, left_len);
1,693✔
10318

10319
   vcode_reg_t l_ptr = emit_array_ref(lhs_data, ptr_inc);
1,693✔
10320
   vcode_reg_t r_ptr = emit_array_ref(rhs_data, ptr_inc);
1,693✔
10321

10322
   if (type_is_array(elem_type)) {
1,693✔
10323
      vcode_reg_t lhs_sub_array = VCODE_INVALID_REG;
177✔
10324
      vcode_reg_t rhs_sub_array = VCODE_INVALID_REG;
177✔
10325
      if (type_is_unconstrained(elem_type)) {
177✔
10326
         lhs_sub_array = lower_wrap_element(lu, left_type, lhs_array, l_ptr);
30✔
10327
         rhs_sub_array = lower_wrap_element(lu, right_type, rhs_array, r_ptr);
30✔
10328
      }
10329

10330
      lower_array_cmp_inner(lu, l_ptr, r_ptr, lhs_sub_array, rhs_sub_array,
177✔
10331
                            type_elem(left_type), type_elem(right_type),
10332
                            pred, fail_bb);
10333
      emit_jump(test_bb);
177✔
10334
   }
10335
   else if (type_is_record(elem_type)) {
1,516✔
10336
      lower_for_each_field_2(lu, elem_type, elem_type, l_ptr, r_ptr,
109✔
10337
                             VCODE_INVALID_REG, lower_predef_field_eq_cb,
10338
                             (void *)(uintptr_t)fail_bb);
109✔
10339
      emit_jump(test_bb);
109✔
10340
   }
10341
   else {
10342
      vcode_reg_t l_val = emit_load_indirect(l_ptr);
1,407✔
10343
      vcode_reg_t r_val = emit_load_indirect(r_ptr);
1,407✔
10344

10345
      if (pred == VCODE_CMP_EQ) {
1,407✔
10346
         vcode_reg_t eq = emit_cmp(pred, l_val, r_val);
1,261✔
10347
         emit_cond(eq, test_bb, fail_bb);
1,261✔
10348
      }
10349
      else {
10350
         vcode_reg_t cmp = emit_cmp(pred, l_val, r_val);
146✔
10351
         vcode_reg_t eq  = emit_cmp(VCODE_CMP_EQ, l_val, r_val);
146✔
10352

10353
         vcode_reg_t done = emit_or(emit_not(eq), emit_and(len_eq, i_eq_len));
146✔
10354

10355
         vcode_block_t cmp_result_bb = emit_block();
146✔
10356
         emit_cond(done, cmp_result_bb, test_bb);
146✔
10357

10358
         vcode_select_block(cmp_result_bb);
146✔
10359
         emit_cond(cmp, exit_bb, fail_bb);
146✔
10360
      }
10361
   }
10362

10363
   // Epilogue
10364

10365
   vcode_select_block(exit_bb);
1,693✔
10366
}
1,693✔
10367

10368
static void lower_predef_array_cmp(lower_unit_t *lu, tree_t decl,
846✔
10369
                                   vcode_cmp_t pred)
10370
{
10371
   type_t r0_type = tree_type(tree_port(decl, 0));
846✔
10372
   type_t r1_type = tree_type(tree_port(decl, 1));
846✔
10373

10374
   vcode_reg_t r0 = 1, r1 = 2;
846✔
10375
   vcode_reg_t r0_data = lower_array_data(r0);
846✔
10376
   vcode_reg_t r1_data = lower_array_data(r1);
846✔
10377

10378
   vcode_block_t fail_bb = emit_block();
846✔
10379

10380
   lower_array_cmp_inner(lu, r0_data, r1_data, r0, r1, r0_type, r1_type,
846✔
10381
                         pred, fail_bb);
10382

10383
   emit_return(emit_const(vtype_bool(), 1));
846✔
10384

10385
   vcode_select_block(fail_bb);
846✔
10386
   emit_return(emit_const(vtype_bool(), 0));
846✔
10387
}
846✔
10388

10389
static void lower_predef_field_eq_cb(lower_unit_t *lu, tree_t field,
1,540✔
10390
                                     vcode_reg_t r0, vcode_reg_t r1,
10391
                                     vcode_reg_t locus, void *context)
10392
{
10393
   vcode_block_t fail_bb = (uintptr_t)context;
1,540✔
10394

10395
   type_t ftype = tree_type(field);
1,540✔
10396
   if (type_is_array(ftype)) {
1,540✔
10397
      vcode_reg_t r0_data = r0, r0_array = VCODE_INVALID_REG;
670✔
10398
      if (have_uarray_ptr(r0)) {
670✔
10399
         r0_array = emit_load_indirect(r0);
33✔
10400
         r0_data = lower_array_data(r0_array);
33✔
10401
      }
10402

10403
      vcode_reg_t r1_data = r1, r1_array = VCODE_INVALID_REG;
670✔
10404
      if (have_uarray_ptr(r1)) {
670✔
10405
         r1_array = emit_load_indirect(r1);
33✔
10406
         r1_data = lower_array_data(r1_array);
33✔
10407
      }
10408

10409
      lower_array_cmp_inner(lu, r0_data, r1_data, r0_array, r1_array,
670✔
10410
                            ftype, ftype, VCODE_CMP_EQ, fail_bb);
10411
   }
10412
   else if (type_is_record(ftype))
870✔
10413
      lower_for_each_field_2(lu, ftype, ftype, r0, r1, locus,
72✔
10414
                             lower_predef_field_eq_cb,
10415
                             (void *)(uintptr_t)fail_bb);
72✔
10416
   else {
10417
      vcode_reg_t r0_load = emit_load_indirect(r0);
798✔
10418
      vcode_reg_t r1_load = emit_load_indirect(r1);
798✔
10419
      vcode_reg_t cmp_reg = emit_cmp(VCODE_CMP_EQ, r0_load, r1_load);
798✔
10420

10421
      vcode_block_t next_bb = emit_block();
798✔
10422
      emit_cond(cmp_reg, next_bb, fail_bb);
798✔
10423
      vcode_select_block(next_bb);
798✔
10424
   }
10425
}
1,540✔
10426

10427
static void lower_predef_record_eq(lower_unit_t *lu, tree_t decl)
222✔
10428
{
10429
   vcode_reg_t r0 = 1, r1 = 2;
222✔
10430
   type_t type = tree_type(tree_port(decl, 0));
222✔
10431

10432
   vcode_block_t fail_bb = emit_block();
222✔
10433

10434
   lower_for_each_field_2(lu, type, type, r0, r1, VCODE_INVALID_REG,
222✔
10435
                          lower_predef_field_eq_cb, (void *)(uintptr_t)fail_bb);
222✔
10436

10437
   emit_return(emit_const(vtype_bool(), 1));
222✔
10438

10439
   vcode_select_block(fail_bb);
222✔
10440
   emit_return(emit_const(vtype_bool(), 0));
222✔
10441
}
222✔
10442

10443
static void lower_predef_to_string(lower_unit_t *lu, tree_t decl)
165✔
10444
{
10445
   // LRM 08 section 5.7 on string representations
10446

10447
   type_t arg_type = tree_type(tree_port(decl, 0));
165✔
10448
   vcode_reg_t context_reg = 0, r0 = 1;
165✔
10449

10450
   if (type_is_array(arg_type)) {
165✔
10451
      type_t elem = type_elem(arg_type);
55✔
10452
      if (type_is_enum(elem) && all_character_literals(elem)) {
55✔
10453
         lower_character_array_image_helper(lu, arg_type, r0, false);
39✔
10454
         return;
39✔
10455
      }
10456
   }
10457

10458
   assert(type_is_representable(arg_type));
126✔
10459

10460
   ident_t func = ident_prefix(type_ident(arg_type), ident_new("image"), '$');
126✔
10461
   vcode_type_t ctype = vtype_char();
126✔
10462
   vcode_type_t rtype = vtype_uarray(1, ctype, ctype);
126✔
10463
   vcode_reg_t args[] = { context_reg, r0 };
126✔
10464
   vcode_reg_t str_reg = emit_fcall(func, rtype, ctype, args, 2);
126✔
10465

10466
   if (type_is_enum(arg_type)) {
126✔
10467
      // If the result is a character literal return just the character
10468
      // without the quotes
10469
      vcode_reg_t quote_reg = emit_const(ctype, '\'');
55✔
10470
      vcode_reg_t data_reg  = lower_array_data(str_reg);
55✔
10471
      vcode_reg_t char0_reg = emit_load_indirect(data_reg);
55✔
10472
      vcode_reg_t is_quote  = emit_cmp(VCODE_CMP_EQ, char0_reg, quote_reg);
55✔
10473

10474
      vcode_block_t char_bb  = emit_block();
55✔
10475
      vcode_block_t other_bb = emit_block();
55✔
10476

10477
      emit_cond(is_quote, char_bb, other_bb);
55✔
10478

10479
      vcode_select_block(char_bb);
55✔
10480

10481
      vcode_reg_t one_reg   = emit_const(vtype_offset(), 1);
55✔
10482
      vcode_reg_t char1_ptr = emit_array_ref(data_reg, one_reg);
55✔
10483
      vcode_reg_t left_reg  = emit_uarray_left(str_reg, 0);
55✔
10484
      vcode_reg_t dir_reg   = emit_uarray_dir(str_reg, 0);
55✔
10485

10486
      vcode_dim_t dims[] = {
55✔
10487
         { .left  = left_reg,
10488
           .right = left_reg,
10489
           .dir   = dir_reg
10490
         }
10491
      };
10492
      emit_return(emit_wrap(char1_ptr, dims, 1));
55✔
10493

10494
      vcode_select_block(other_bb);
55✔
10495
   }
10496

10497
   emit_return(str_reg);
126✔
10498
}
10499

10500
static void lower_predef_bit_shift(lower_unit_t *lu, tree_t decl,
72✔
10501
                                   subprogram_kind_t kind)
10502
{
10503
   type_t type = tree_type(tree_port(decl, 0));
72✔
10504
   type_t elem = type_elem(type);
72✔
10505

10506
   vcode_type_t vtype = lower_type(elem);
72✔
10507
   vcode_type_t vbounds = lower_bounds(elem);
72✔
10508
   vcode_type_t voffset = vtype_offset();
72✔
10509

10510
   vcode_reg_t r0 = 1, r1 = 2;
72✔
10511

10512
   vcode_reg_t data_reg = lower_array_data(r0);
72✔
10513
   vcode_reg_t len_reg  = lower_array_len(lu, type, 0, r0);
72✔
10514

10515
   vcode_block_t null_bb = emit_block();
72✔
10516
   vcode_block_t non_null_bb = emit_block();
72✔
10517

10518
   vcode_reg_t is_null_reg =
72✔
10519
      emit_cmp(VCODE_CMP_EQ, len_reg, emit_const(voffset, 0));
72✔
10520
   emit_cond(is_null_reg, null_bb, non_null_bb);
72✔
10521

10522
   vcode_select_block(null_bb);
72✔
10523
   emit_return(r0);
72✔
10524

10525
   vcode_select_block(non_null_bb);
72✔
10526

10527
   vcode_reg_t shift_reg = emit_cast(voffset, voffset, r1);
72✔
10528
   vcode_reg_t mem_reg = emit_alloc(vtype, vbounds, len_reg);
72✔
10529

10530
   vcode_var_t i_var = lower_temp_var(lu, "i", voffset, voffset);
72✔
10531
   emit_store(emit_const(voffset, 0), i_var);
72✔
10532

10533
   vcode_block_t cmp_bb  = emit_block();
72✔
10534
   vcode_block_t body_bb = emit_block();
72✔
10535
   vcode_block_t exit_bb = emit_block();
72✔
10536

10537
   vcode_reg_t def_reg = VCODE_INVALID_REG;
72✔
10538
   switch (kind) {
72✔
10539
   case S_SLL: case S_SRL: case S_ROL: case S_ROR:
48✔
10540
      def_reg = emit_const(vtype, 0);
48✔
10541
      break;
48✔
10542
   case S_SRA:
12✔
10543
      {
10544
         vcode_reg_t len_minus_1 = emit_sub(len_reg, emit_const(voffset, 1));
12✔
10545
         vcode_reg_t last_ptr = emit_array_ref(data_reg, len_minus_1);
12✔
10546
         def_reg = emit_load_indirect(last_ptr);
12✔
10547
      }
10548
      break;
12✔
10549
   case S_SLA:
12✔
10550
      def_reg = emit_load_indirect(data_reg);
12✔
10551
      break;
12✔
10552
   default:
10553
      break;
10554
   }
10555

10556
   vcode_reg_t shift_is_neg =
72✔
10557
      emit_cmp(VCODE_CMP_LT, shift_reg, emit_const(voffset, 0));
72✔
10558

10559
   emit_jump(cmp_bb);
72✔
10560

10561
   vcode_select_block(cmp_bb);
72✔
10562

10563
   vcode_reg_t i_reg  = emit_load(i_var);
72✔
10564
   vcode_reg_t eq_reg = emit_cmp(VCODE_CMP_EQ, i_reg, len_reg);
72✔
10565
   emit_cond(eq_reg, exit_bb, body_bb);
72✔
10566

10567
   vcode_select_block(body_bb);
72✔
10568

10569
   vcode_reg_t cmp_reg = VCODE_INVALID_REG;
72✔
10570
   switch (kind) {
72✔
10571
   case S_SRL: case S_SRA:
24✔
10572
      {
10573
         vcode_reg_t neg_reg =
24✔
10574
            emit_cmp(VCODE_CMP_LT, i_reg, emit_add(len_reg, shift_reg));
24✔
10575
         vcode_reg_t pos_reg =
24✔
10576
            emit_cmp(VCODE_CMP_GEQ, i_reg, shift_reg);
24✔
10577
         cmp_reg = emit_select(shift_is_neg, neg_reg, pos_reg);
24✔
10578
      }
10579
      break;
24✔
10580
   case S_SLL: case S_SLA:
24✔
10581
      {
10582
         vcode_reg_t neg_reg =
24✔
10583
            emit_cmp(VCODE_CMP_GEQ, i_reg, emit_neg(shift_reg));
24✔
10584
         vcode_reg_t pos_reg =
24✔
10585
            emit_cmp(VCODE_CMP_LT, i_reg, emit_sub(len_reg, shift_reg));
24✔
10586
         cmp_reg = emit_select(shift_is_neg, neg_reg, pos_reg);
24✔
10587
      }
10588
      break;
24✔
10589
   case S_ROL: case S_ROR:
24✔
10590
      cmp_reg = emit_const(vtype_bool(), 1);
24✔
10591
   default:
10592
      break;
10593
   }
10594

10595
   vcode_reg_t dst_ptr = emit_array_ref(mem_reg, i_reg);
72✔
10596

10597
   vcode_reg_t next_reg = emit_add(i_reg, emit_const(vtype_offset(), 1));
72✔
10598
   emit_store(next_reg, i_var);
72✔
10599

10600
   vcode_block_t true_bb = emit_block();
72✔
10601
   vcode_block_t false_bb = emit_block();
72✔
10602

10603
   emit_cond(cmp_reg, true_bb, false_bb);
72✔
10604

10605
   vcode_select_block(true_bb);
72✔
10606

10607
   vcode_reg_t src_reg = VCODE_INVALID_REG;
72✔
10608
   switch (kind) {
72✔
10609
   case S_SLL: case S_SLA:
24✔
10610
      src_reg = emit_add(i_reg, shift_reg);
24✔
10611
      break;
24✔
10612
   case S_SRL: case S_SRA:
24✔
10613
      src_reg = emit_sub(i_reg, shift_reg);
24✔
10614
      break;
24✔
10615
   case S_ROL:
12✔
10616
      src_reg = emit_mod(emit_add(i_reg, emit_add(len_reg, shift_reg)),
12✔
10617
                         len_reg);
10618
      break;
12✔
10619
   case S_ROR:
12✔
10620
      src_reg = emit_mod(emit_add(i_reg, emit_sub(len_reg, shift_reg)),
12✔
10621
                         len_reg);
10622
      break;
12✔
10623
   default:
10624
      break;
10625
   }
10626

10627
   vcode_reg_t load_reg = emit_load_indirect(emit_array_ref(data_reg, src_reg));
72✔
10628
   emit_store_indirect(load_reg, dst_ptr);
72✔
10629
   emit_jump(cmp_bb);
72✔
10630

10631
   vcode_select_block(false_bb);
72✔
10632
   emit_store_indirect(def_reg, dst_ptr);
72✔
10633
   emit_jump(cmp_bb);
72✔
10634

10635
   vcode_select_block(exit_bb);
72✔
10636

10637
   vcode_reg_t left_reg  = emit_uarray_left(r0, 0);
72✔
10638
   vcode_reg_t right_reg = emit_uarray_right(r0, 0);
72✔
10639
   vcode_reg_t dir_reg   = emit_uarray_dir(r0, 0);
72✔
10640

10641
   vcode_dim_t dims[] = { { left_reg, right_reg, dir_reg } };
72✔
10642
   emit_return(emit_wrap(mem_reg, dims, 1));
72✔
10643
}
72✔
10644

10645
static void lower_predef_bit_vec_op(lower_unit_t *lu, tree_t decl,
113✔
10646
                                    subprogram_kind_t kind)
10647
{
10648
   type_t type = tree_type(tree_port(decl, 0));
113✔
10649
   type_t elem = type_elem(type);
113✔
10650

10651
   vcode_type_t vtype = lower_type(elem);
113✔
10652
   vcode_type_t vbounds = lower_bounds(elem);
113✔
10653
   vcode_type_t voffset = vtype_offset();
113✔
10654

10655
   vcode_reg_t r0 = 1, r1 = 2;
113✔
10656

10657
   vcode_reg_t data0_reg = lower_array_data(r0);
113✔
10658
   vcode_reg_t data1_reg = VCODE_INVALID_REG;
113✔
10659
   if (kind != S_ARRAY_NOT)
113✔
10660
      data1_reg = lower_array_data(r1);
96✔
10661

10662
   vcode_reg_t len0_reg = lower_array_len(lu, type, 0, r0);
113✔
10663
   vcode_reg_t len1_reg = VCODE_INVALID_REG;
113✔
10664
   if (kind != S_ARRAY_NOT) {
113✔
10665
      len1_reg = lower_array_len(lu, type, 0, r1);
96✔
10666

10667
      vcode_block_t fail_bb = emit_block();
96✔
10668
      vcode_block_t cont_bb = emit_block();
96✔
10669

10670
      vcode_reg_t len_eq = emit_cmp(VCODE_CMP_EQ, len0_reg, len1_reg);
96✔
10671
      emit_cond(len_eq, cont_bb, fail_bb);
96✔
10672

10673
      vcode_select_block(fail_bb);
96✔
10674

10675
      vcode_type_t vseverity = vtype_int(0, SEVERITY_FAILURE - 1);
96✔
10676
      vcode_reg_t failure_reg = emit_const(vseverity, SEVERITY_FAILURE);
96✔
10677

10678
      vcode_reg_t msg_reg =
96✔
10679
         lower_wrap_string("arguments have different lengths");
96✔
10680
      vcode_reg_t msg_len = emit_uarray_len(msg_reg, 0);
96✔
10681

10682
      vcode_reg_t locus = lower_debug_locus(decl);
96✔
10683
      emit_report(emit_unwrap(msg_reg), msg_len, failure_reg, locus);
96✔
10684
      emit_return(r0);
96✔
10685

10686
      vcode_select_block(cont_bb);
96✔
10687
   }
10688

10689
   vcode_reg_t mem_reg = emit_alloc(vtype, vbounds, len0_reg);
113✔
10690

10691
   vcode_var_t i_var = lower_temp_var(lu, "i", voffset, voffset);
113✔
10692
   emit_store(emit_const(voffset, 0), i_var);
113✔
10693

10694
   vcode_block_t cmp_bb  = emit_block();
113✔
10695
   vcode_block_t body_bb = emit_block();
113✔
10696
   vcode_block_t exit_bb = emit_block();
113✔
10697

10698
   emit_jump(cmp_bb);
113✔
10699

10700
   vcode_select_block(cmp_bb);
113✔
10701

10702
   vcode_reg_t i_reg  = emit_load(i_var);
113✔
10703
   vcode_reg_t eq_reg = emit_cmp(VCODE_CMP_EQ, i_reg, len0_reg);
113✔
10704
   emit_cond(eq_reg, exit_bb, body_bb);
113✔
10705

10706
   vcode_select_block(body_bb);
113✔
10707

10708
   vcode_reg_t dst_ptr = emit_array_ref(mem_reg, i_reg);
113✔
10709

10710
   vcode_reg_t src0_reg = emit_load_indirect(emit_array_ref(data0_reg, i_reg));
113✔
10711
   vcode_reg_t src1_reg = VCODE_INVALID_REG;
113✔
10712
   if (kind != S_ARRAY_NOT)
113✔
10713
      src1_reg = emit_load_indirect(emit_array_ref(data1_reg, i_reg));
96✔
10714

10715
   vcode_reg_t op_reg;
113✔
10716
   switch (kind) {
113✔
10717
   case S_ARRAY_NOT:  op_reg = emit_not(src0_reg); break;
17✔
10718
   case S_ARRAY_AND:  op_reg = emit_and(src0_reg, src1_reg); break;
38✔
10719
   case S_ARRAY_OR:   op_reg = emit_or(src0_reg, src1_reg); break;
12✔
10720
   case S_ARRAY_XOR:  op_reg = emit_xor(src0_reg, src1_reg); break;
11✔
10721
   case S_ARRAY_XNOR: op_reg = emit_xnor(src0_reg, src1_reg); break;
11✔
10722
   case S_ARRAY_NAND: op_reg = emit_nand(src0_reg, src1_reg); break;
12✔
10723
   case S_ARRAY_NOR:  op_reg = emit_nor(src0_reg, src1_reg); break;
12✔
10724
   default:
×
10725
      fatal_trace("unhandled bitvec operator kind %d", kind);
10726
   }
10727

10728
   emit_store_indirect(op_reg, dst_ptr);
113✔
10729

10730
   vcode_reg_t next_reg = emit_add(i_reg, emit_const(vtype_offset(), 1));
113✔
10731
   emit_store(next_reg, i_var);
113✔
10732
   emit_jump(cmp_bb);
113✔
10733

10734
   vcode_select_block(exit_bb);
113✔
10735

10736
   vcode_reg_t left_reg  = emit_uarray_left(r0, 0);
113✔
10737
   vcode_reg_t right_reg = emit_uarray_right(r0, 0);
113✔
10738
   vcode_reg_t dir_reg   = emit_uarray_dir(r0, 0);
113✔
10739

10740
   vcode_dim_t dims[] = { { left_reg, right_reg, dir_reg } };
113✔
10741
   emit_return(emit_wrap(mem_reg, dims, 1));
113✔
10742
}
113✔
10743

10744
static void lower_predef_mixed_bit_vec_op(lower_unit_t *lu, tree_t decl,
114✔
10745
                                          subprogram_kind_t kind)
10746
{
10747
   // Mixed scalar/array bit vector operations
10748

10749
   vcode_reg_t r0 = 1, r1 = 2;
114✔
10750

10751
   type_t r0_type = tree_type(tree_port(decl, 0));
114✔
10752
   type_t r1_type = tree_type(tree_port(decl, 1));
114✔
10753

10754
   vcode_type_t voffset = vtype_offset();
114✔
10755

10756
   vcode_var_t i_var = lower_temp_var(lu, "i", voffset, voffset);
114✔
10757
   emit_store(emit_const(vtype_offset(), 0), i_var);
114✔
10758

10759
   const bool r0_is_array = type_is_array(r0_type);
114✔
10760

10761
   type_t array_type = r0_is_array ? r0_type : r1_type;
114✔
10762
   vcode_reg_t array_reg = r0_is_array ? r0 : r1;
114✔
10763

10764
   vcode_reg_t len_reg   = lower_array_len(lu, array_type, 0, array_reg);
114✔
10765
   vcode_reg_t data_reg  = lower_array_data(array_reg);
114✔
10766
   vcode_reg_t left_reg  = lower_array_left(lu, array_type, 0, array_reg);
114✔
10767
   vcode_reg_t right_reg = lower_array_right(lu, array_type, 0, array_reg);
114✔
10768
   vcode_reg_t dir_reg   = lower_array_dir(lu, array_type, 0, array_reg);
114✔
10769
   vcode_reg_t null_reg  = emit_range_null(left_reg, right_reg, dir_reg);
114✔
10770

10771
   vcode_reg_t mem_reg = emit_alloc(vtype_bool(), vtype_bool(), len_reg);
114✔
10772

10773
   vcode_block_t body_bb = emit_block();
114✔
10774
   vcode_block_t exit_bb = emit_block();
114✔
10775

10776
   emit_cond(null_reg, exit_bb, body_bb);
114✔
10777

10778
   vcode_select_block(body_bb);
114✔
10779

10780
   vcode_reg_t i_reg = emit_load(i_var);
114✔
10781
   vcode_reg_t l_reg = emit_load_indirect(emit_array_ref(data_reg, i_reg));
114✔
10782
   vcode_reg_t r_reg = r0_is_array ? r1 : r0;
114✔
10783

10784
   vcode_reg_t result_reg = VCODE_INVALID_REG;
114✔
10785
   switch (kind) {
114✔
10786
   case S_MIXED_AND:  result_reg = emit_and(l_reg, r_reg);  break;
19✔
10787
   case S_MIXED_OR:   result_reg = emit_or(l_reg, r_reg);   break;
19✔
10788
   case S_MIXED_NAND: result_reg = emit_nand(l_reg, r_reg); break;
19✔
10789
   case S_MIXED_NOR:  result_reg = emit_nor(l_reg, r_reg);  break;
19✔
10790
   case S_MIXED_XOR:  result_reg = emit_xor(l_reg, r_reg);  break;
19✔
10791
   case S_MIXED_XNOR: result_reg = emit_xnor(l_reg, r_reg); break;
19✔
10792
   default: break;
10793
   }
10794

10795
   emit_store_indirect(result_reg, emit_array_ref(mem_reg, i_reg));
114✔
10796

10797
   vcode_reg_t next_reg = emit_add(i_reg, emit_const(voffset, 1));
114✔
10798
   vcode_reg_t cmp_reg  = emit_cmp(VCODE_CMP_EQ, next_reg, len_reg);
114✔
10799
   emit_store(next_reg, i_var);
114✔
10800
   emit_cond(cmp_reg, exit_bb, body_bb);
114✔
10801

10802
   vcode_select_block(exit_bb);
114✔
10803

10804
   vcode_dim_t dims[1] = {
114✔
10805
      {
10806
         .left  = left_reg,
10807
         .right = right_reg,
10808
         .dir   = dir_reg
10809
      }
10810
   };
10811
   emit_return(emit_wrap(mem_reg, dims, 1));
114✔
10812
}
114✔
10813

10814
static void lower_predef_reduction_op(lower_unit_t *lu, tree_t decl,
51✔
10815
                                      subprogram_kind_t kind)
10816
{
10817
   vcode_reg_t r0 = 1;
51✔
10818
   type_t r0_type = tree_type(tree_port(decl, 0));
51✔
10819

10820
   vcode_type_t vbool = vtype_bool();
51✔
10821
   vcode_type_t voffset = vtype_offset();
51✔
10822

10823
   vcode_var_t result_var = lower_temp_var(lu, "result", vbool, vbool);
51✔
10824
   vcode_reg_t init_reg =
51✔
10825
      emit_const(vbool, kind == S_REDUCE_NAND || kind == S_REDUCE_AND);
51✔
10826
   emit_store(init_reg, result_var);
51✔
10827

10828
   vcode_var_t i_var = lower_temp_var(lu, "i", voffset, voffset);
51✔
10829
   emit_store(emit_const(vtype_offset(), 0), i_var);
51✔
10830

10831
   vcode_reg_t len_reg   = lower_array_len(lu, r0_type, 0, r0);
51✔
10832
   vcode_reg_t data_reg  = lower_array_data(r0);
51✔
10833
   vcode_reg_t left_reg  = lower_array_left(lu, r0_type, 0, r0);
51✔
10834
   vcode_reg_t right_reg = lower_array_right(lu, r0_type, 0, r0);
51✔
10835
   vcode_reg_t dir_reg   = lower_array_dir(lu, r0_type, 0, r0);
51✔
10836
   vcode_reg_t null_reg  = emit_range_null(left_reg, right_reg, dir_reg);
51✔
10837

10838
   vcode_block_t body_bb = emit_block();
51✔
10839
   vcode_block_t exit_bb = emit_block();
51✔
10840

10841
   emit_cond(null_reg, exit_bb, body_bb);
51✔
10842

10843
   vcode_select_block(body_bb);
51✔
10844

10845
   vcode_reg_t i_reg   = emit_load(i_var);
51✔
10846
   vcode_reg_t src_reg = emit_load_indirect(emit_array_ref(data_reg, i_reg));
51✔
10847
   vcode_reg_t cur_reg = emit_load(result_var);
51✔
10848

10849
   vcode_reg_t result_reg = VCODE_INVALID_REG;
51✔
10850
   switch (kind) {
51✔
10851
   case S_REDUCE_OR:
16✔
10852
   case S_REDUCE_NOR:
10853
      result_reg = emit_or(cur_reg, src_reg);
16✔
10854
      break;
16✔
10855
   case S_REDUCE_AND:
19✔
10856
   case S_REDUCE_NAND:
10857
      result_reg = emit_and(cur_reg, src_reg);
19✔
10858
      break;
19✔
10859
   case S_REDUCE_XOR:
16✔
10860
   case S_REDUCE_XNOR:
10861
      result_reg = emit_xor(cur_reg, src_reg);
16✔
10862
      break;
16✔
10863
   default:
10864
      break;
10865
   }
10866

10867
   emit_store(result_reg, result_var);
51✔
10868

10869
   vcode_reg_t next_reg = emit_add(i_reg, emit_const(vtype_offset(), 1));
51✔
10870
   vcode_reg_t cmp_reg  = emit_cmp(VCODE_CMP_EQ, next_reg, len_reg);
51✔
10871
   emit_store(next_reg, i_var);
51✔
10872
   emit_cond(cmp_reg, exit_bb, body_bb);
51✔
10873

10874
   vcode_select_block(exit_bb);
51✔
10875

10876
   if (kind == S_REDUCE_NOR || kind == S_REDUCE_NAND || kind == S_REDUCE_XNOR)
51✔
10877
      emit_return(emit_not(emit_load(result_var)));
24✔
10878
   else
10879
      emit_return(emit_load(result_var));
27✔
10880
}
51✔
10881

10882
static void lower_predef_match_op(lower_unit_t *lu, tree_t decl,
93✔
10883
                                  subprogram_kind_t kind)
10884
{
10885
   vcode_reg_t r0 = 1, r1 = 2;
93✔
10886

10887
   type_t r0_type = tree_type(tree_port(decl, 0));
93✔
10888
   type_t r1_type = tree_type(tree_port(decl, 1));
93✔
10889

10890
   vcode_cmp_t cmp;
93✔
10891
   bool invert = false;
93✔
10892
   switch (kind) {
93✔
10893
   case S_MATCH_NEQ:
10894
      invert = true;
10895
   case S_MATCH_EQ:
10896
      cmp = VCODE_CMP_EQ;
10897
      break;
10898
   case S_MATCH_GE:
10899
      invert = true;
10900
   case S_MATCH_LT:
10901
      cmp = VCODE_CMP_LT;
10902
      break;
10903
   case S_MATCH_GT:
10904
      invert = true;
10905
   case S_MATCH_LE:
10906
      cmp = VCODE_CMP_LEQ;
10907
      break;
10908
   default:
×
10909
      fatal_trace("invalid match operator %d", kind);
10910
   }
10911

10912
   bool is_array = false, is_bit = false;
93✔
10913
   if (type_is_array(r0_type)) {
93✔
10914
      is_array = true;
50✔
10915
      is_bit = type_ident(type_elem(r0_type)) == well_known(W_STD_BIT);
50✔
10916
   }
10917
   else
10918
      is_bit = type_ident(r0_type) == well_known(W_STD_BIT);
43✔
10919

10920
   vcode_reg_t result = VCODE_INVALID_REG;
93✔
10921
   if (is_array) {
93✔
10922
      assert(kind == S_MATCH_EQ || kind == S_MATCH_NEQ);
50✔
10923

10924
      vcode_reg_t len0_reg = lower_array_len(lu, r0_type, 0, r0);
50✔
10925
      vcode_reg_t len1_reg = lower_array_len(lu, r1_type, 0, r1);
50✔
10926

10927
      vcode_block_t fail_bb = emit_block();
50✔
10928
      vcode_block_t cont_bb = emit_block();
50✔
10929

10930
      vcode_reg_t len_eq = emit_cmp(VCODE_CMP_EQ, len0_reg, len1_reg);
50✔
10931
      emit_cond(len_eq, cont_bb, fail_bb);
50✔
10932

10933
      vcode_select_block(fail_bb);
50✔
10934

10935
      vcode_type_t vseverity = vtype_int(0, SEVERITY_FAILURE - 1);
50✔
10936
      vcode_reg_t failure_reg = emit_const(vseverity, SEVERITY_FAILURE);
50✔
10937

10938
      vcode_reg_t msg_reg =
50✔
10939
         lower_wrap_string("arguments have different lengths");
50✔
10940
      vcode_reg_t msg_len = emit_uarray_len(msg_reg, 0);
50✔
10941

10942
      vcode_reg_t locus = lower_debug_locus(decl);
50✔
10943
      emit_report(emit_unwrap(msg_reg), msg_len, failure_reg, locus);
50✔
10944
      emit_jump(cont_bb);
50✔
10945

10946
      vcode_select_block(cont_bb);
50✔
10947

10948
      vcode_type_t vtype = lower_type(type_elem(r0_type));
50✔
10949
      vcode_type_t vbounds = lower_bounds(type_elem(r0_type));
50✔
10950
      vcode_reg_t mem_reg = emit_alloc(vtype, vbounds, len0_reg);
50✔
10951

10952
      vcode_var_t result_var = lower_temp_var(lu, "result", vtype, vbounds);
50✔
10953
      emit_store(emit_const(vtype, 0), result_var);
50✔
10954

10955
      vcode_type_t voffset = vtype_offset();
50✔
10956
      vcode_var_t i_var = lower_temp_var(lu, "i", voffset, voffset);
50✔
10957
      emit_store(emit_const(vtype_offset(), 0), i_var);
50✔
10958

10959
      vcode_reg_t left_reg  = lower_array_left(lu, r0_type, 0, r0);
50✔
10960
      vcode_reg_t right_reg = lower_array_right(lu, r0_type, 0, r0);
50✔
10961
      vcode_reg_t dir_reg   = lower_array_dir(lu, r0_type, 0, r0);
50✔
10962
      vcode_reg_t null_reg  = emit_range_null(left_reg, right_reg, dir_reg);
50✔
10963

10964
      vcode_reg_t r0_ptr = lower_array_data(r0);
50✔
10965
      vcode_reg_t r1_ptr = lower_array_data(r1);
50✔
10966

10967
      vcode_block_t body_bb = emit_block();
50✔
10968
      vcode_block_t exit_bb = emit_block();
50✔
10969

10970
      emit_cond(null_reg, exit_bb, body_bb);
50✔
10971

10972
      vcode_select_block(body_bb);
50✔
10973

10974
      vcode_reg_t i_reg = emit_load(i_var);
50✔
10975

10976
      vcode_reg_t i0_ptr = emit_array_ref(r0_ptr, i_reg);
50✔
10977
      vcode_reg_t i1_ptr = emit_array_ref(r1_ptr, i_reg);
50✔
10978

10979
      vcode_reg_t r0_src_reg = emit_load_indirect(i0_ptr);
50✔
10980
      vcode_reg_t r1_src_reg = emit_load_indirect(i1_ptr);
50✔
10981

10982
      vcode_reg_t tmp;
50✔
10983
      if (is_bit)
50✔
10984
         tmp = emit_cmp(cmp, r0_src_reg, r1_src_reg);
18✔
10985
      else {
10986
         ident_t func = ident_new("NVC.IEEE_SUPPORT.REL_MATCH_EQ(UU)U");
32✔
10987
         vcode_reg_t context_reg = lower_context_for_call(lu, func);
32✔
10988
         vcode_reg_t args[] = { context_reg, r0_src_reg, r1_src_reg };
32✔
10989
         tmp = emit_fcall(func, vtype, vbounds, args, 3);
32✔
10990
      }
10991
      emit_store_indirect(tmp, emit_array_ref(mem_reg, i_reg));
50✔
10992

10993
      vcode_reg_t next_reg = emit_add(i_reg, emit_const(vtype_offset(), 1));
50✔
10994
      vcode_reg_t cmp_reg  = emit_cmp(VCODE_CMP_EQ, next_reg, len0_reg);
50✔
10995
      emit_store(next_reg, i_var);
50✔
10996
      emit_cond(cmp_reg, exit_bb, body_bb);
50✔
10997

10998
      vcode_select_block(exit_bb);
50✔
10999

11000
      vcode_dim_t dims[1] = {
50✔
11001
         {
11002
            .left  = left_reg,
11003
            .right = right_reg,
11004
            .dir   = dir_reg
11005
         }
11006
      };
11007
      vcode_reg_t wrap_reg = emit_wrap(mem_reg, dims, 1);
50✔
11008

11009
      ident_t func = is_bit
100✔
11010
         ? ident_new("STD.STANDARD.\"and\"(Q)J$predef")
18✔
11011
         : ident_new("IEEE.STD_LOGIC_1164.\"and\"(Y)U");
50✔
11012
      vcode_reg_t context_reg = lower_context_for_call(lu, func);
50✔
11013
      vcode_reg_t args[] = { context_reg, wrap_reg };
50✔
11014
      result = emit_fcall(func, vtype, vbounds, args, 2);
50✔
11015
   }
11016
   else if (is_bit)
43✔
11017
      result = emit_cmp(cmp, r0, r1);
30✔
11018
   else {
11019
      ident_t func = NULL;
13✔
11020
      switch (cmp) {
13✔
11021
      case VCODE_CMP_LT:
4✔
11022
         func = ident_new("NVC.IEEE_SUPPORT.REL_MATCH_LT(UU)U");
4✔
11023
         break;
4✔
11024
      case VCODE_CMP_LEQ:
4✔
11025
         func = ident_new("NVC.IEEE_SUPPORT.REL_MATCH_LEQ(UU)U");
4✔
11026
         break;
4✔
11027
      case VCODE_CMP_EQ:
5✔
11028
         func = ident_new("NVC.IEEE_SUPPORT.REL_MATCH_EQ(UU)U");
5✔
11029
         break;
5✔
11030
      default:
×
11031
         fatal_trace("unexpected comparison operator %d", cmp);
11032
      }
11033

11034
      vcode_reg_t context_reg = lower_context_for_call(lu, func);
13✔
11035
      vcode_reg_t args[3] = { context_reg, r0, r1 };
13✔
11036

11037
      vcode_type_t rtype = lower_type(r0_type);
13✔
11038
      result = emit_fcall(func, rtype, rtype, args, 3);
13✔
11039
   }
11040

11041
   if (invert && is_bit)
93✔
11042
      emit_return(emit_not(result));
24✔
11043
   else if (invert) {
69✔
11044
      ident_t func = ident_new(
22✔
11045
         "IEEE.STD_LOGIC_1164.\"not\"(U)24IEEE.STD_LOGIC_1164.UX01");
11046
      vcode_reg_t context_reg = lower_context_for_call(lu, func);
22✔
11047
      vcode_reg_t args[2] = { context_reg, result };
22✔
11048
      vcode_type_t rtype = vcode_reg_type(result);
22✔
11049
      emit_return(emit_fcall(func, rtype, rtype, args, 2));
22✔
11050
   }
11051
   else
11052
      emit_return(result);
47✔
11053
}
93✔
11054

11055
static void lower_predef_min_max(lower_unit_t *lu, tree_t decl, vcode_cmp_t cmp)
373✔
11056
{
11057
   type_t type = tree_type(tree_port(decl, 0));
373✔
11058

11059
   if (type_is_array(type) && tree_ports(decl) == 1) {
497✔
11060
      type_t elem = type_elem(type);
124✔
11061
      assert(type_is_scalar(elem));
124✔
11062

11063
      vcode_reg_t array_reg = 1;
124✔
11064
      vcode_type_t voffset = vtype_offset();
124✔
11065

11066
      vcode_var_t i_var = lower_temp_var(lu, "i", voffset, voffset);
124✔
11067
      emit_store(emit_const(voffset, 0), i_var);
124✔
11068

11069
      vcode_type_t elem_vtype = lower_type(elem);
124✔
11070
      vcode_var_t result_var =
124✔
11071
         lower_temp_var(lu, "result", elem_vtype, elem_vtype);
124✔
11072

11073
      tree_t elem_r = range_of(elem, 0);
124✔
11074
      vcode_reg_t def_reg =
248✔
11075
         (cmp == VCODE_CMP_GT && tree_subkind(elem_r) == RANGE_TO)
62✔
11076
         || (cmp == VCODE_CMP_LT && tree_subkind(elem_r) == RANGE_DOWNTO)
62✔
11077
         ? lower_range_left(lu, elem_r)
62✔
11078
         : lower_range_right(lu, elem_r);
186✔
11079

11080
      emit_store(def_reg, result_var);
124✔
11081

11082
      vcode_reg_t left_reg  = lower_array_left(lu, type, 0, array_reg);
124✔
11083
      vcode_reg_t right_reg = lower_array_right(lu, type, 0, array_reg);
124✔
11084
      vcode_reg_t len_reg   = lower_array_len(lu, type, 0, array_reg);
124✔
11085
      vcode_reg_t kind_reg  = lower_array_dir(lu, type, 0, array_reg);
124✔
11086
      vcode_reg_t data_reg  = lower_array_data(array_reg);
124✔
11087
      vcode_reg_t null_reg  = emit_range_null(left_reg, right_reg, kind_reg);
124✔
11088

11089
      vcode_block_t body_bb = emit_block();
124✔
11090
      vcode_block_t exit_bb = emit_block();
124✔
11091

11092
      emit_cond(null_reg, exit_bb, body_bb);
124✔
11093

11094
      vcode_select_block(body_bb);
124✔
11095

11096
      vcode_reg_t i_reg    = emit_load(i_var);
124✔
11097
      vcode_reg_t elem_ptr = emit_array_ref(data_reg, i_reg);
124✔
11098
      vcode_reg_t elem_reg = emit_load_indirect(elem_ptr);
124✔
11099
      vcode_reg_t cur_reg  = emit_load(result_var);
124✔
11100
      vcode_reg_t cmp_reg  = emit_cmp(cmp, elem_reg, cur_reg);
124✔
11101
      vcode_reg_t next_reg = emit_select(cmp_reg, elem_reg, cur_reg);
124✔
11102
      emit_store(next_reg, result_var);
124✔
11103

11104
      vcode_reg_t i_next = emit_add(i_reg, emit_const(voffset, 1));
124✔
11105
      emit_store(i_next, i_var);
124✔
11106

11107
      vcode_reg_t done_reg = emit_cmp(VCODE_CMP_EQ, i_next, len_reg);
124✔
11108
      emit_cond(done_reg, exit_bb, body_bb);
124✔
11109

11110
      vcode_select_block(exit_bb);
124✔
11111
      emit_return(emit_load(result_var));
124✔
11112
   }
11113
   else {
11114
      vcode_reg_t context_reg = 0, r0 = 1, r1 = 2;
249✔
11115

11116
      vcode_reg_t test_reg;
249✔
11117
      if (type_is_scalar(type))
249✔
11118
         test_reg = emit_cmp(cmp, r0, r1);
149✔
11119
      else {
11120
         const char *op = cmp == VCODE_CMP_GT ? ">" : "<";
100✔
11121
         ident_t func = lower_predef_func_name(type, op);
100✔
11122
         vcode_reg_t args[] = { context_reg, r0, r1 };
100✔
11123
         vcode_type_t vbool = vtype_bool();
100✔
11124
         test_reg = emit_fcall(func, vbool, vbool, args, 3);
100✔
11125
      }
11126

11127
      emit_return(emit_select(test_reg, r0, r1));
249✔
11128
   }
11129
}
373✔
11130

11131
static void lower_predef_negate(tree_t decl, const char *op)
249✔
11132
{
11133
   type_t type = tree_type(tree_port(decl, 0));
249✔
11134
   vcode_type_t vbool = vtype_bool();
249✔
11135
   vcode_reg_t args[] = { 0, 1, 2 };
249✔
11136
   vcode_reg_t eq_reg = emit_fcall(lower_predef_func_name(type, op),
249✔
11137
                                   vbool, vbool, args, 3);
11138

11139
   emit_return(emit_not(eq_reg));
249✔
11140
}
249✔
11141

11142
static void lower_foreign_predef(lower_unit_t *lu, tree_t decl, const char *fn)
135✔
11143
{
11144
   static const char prefix[] = "INTERNAL ";
135✔
11145
   const size_t fnlen = strlen(fn);
135✔
11146
   const size_t nchars = fnlen + sizeof(prefix) - 1;
135✔
11147
   vcode_reg_t *chars LOCAL = xmalloc_array(nchars, sizeof(vcode_reg_t));
270✔
11148
   vcode_type_t ctype = vtype_char();
135✔
11149
   vcode_type_t stype = vtype_carray(nchars, ctype, ctype);
135✔
11150

11151
   int pos = 0;
135✔
11152
   for (int i = 0; i < sizeof(prefix) - 1; i++)
1,350✔
11153
      chars[pos++] = emit_const(ctype, prefix[i]);
1,215✔
11154
   for (int i = 0; i < fnlen; i++)
2,368✔
11155
      chars[pos++] = emit_const(ctype, fn[i]);
2,233✔
11156
   assert(pos == nchars);
135✔
11157

11158
   vcode_reg_t array_reg = emit_const_array(stype, chars, nchars);
135✔
11159
   vcode_reg_t data_reg = emit_address_of(array_reg);
135✔
11160
   vcode_reg_t length_reg = emit_const(vtype_offset(), nchars);
135✔
11161

11162
   emit_bind_foreign(data_reg, length_reg, VCODE_INVALID_REG);
135✔
11163
   emit_unreachable(VCODE_INVALID_REG);
135✔
11164
}
135✔
11165

11166
static void lower_predef_file_open3(lower_unit_t *lu, tree_t decl)
4✔
11167
{
11168
   vcode_type_t rtype = vcode_unit_result(lu->vunit);
4✔
11169
   vcode_var_t status_var = emit_var(rtype, rtype, ident_new("status"), 0);
4✔
11170

11171
   vcode_reg_t status_reg = emit_index(status_var, VCODE_INVALID_REG);
4✔
11172
   vcode_reg_t data_reg = emit_unwrap(2);
4✔
11173
   vcode_reg_t length_reg = emit_uarray_len(2, 0);
4✔
11174

11175
   emit_file_open(1, data_reg, length_reg, 3, status_reg);
4✔
11176
   emit_return(emit_load(status_var));
4✔
11177
}
4✔
11178

11179
static void lower_edge_predef(lower_unit_t *lu, tree_t decl)
20✔
11180
{
11181
   vcode_reg_t nets_reg = vcode_param_reg(1);
20✔
11182
   vcode_reg_t count_reg = emit_const(vtype_offset(), 1);
20✔
11183
   vcode_reg_t value_reg =
20✔
11184
      emit_load_indirect(emit_resolved(nets_reg, count_reg));
20✔
11185

11186
   if (tree_subkind(decl) == S_FALLING_EDGE)
20✔
11187
      value_reg = emit_not(value_reg);
10✔
11188

11189
   vcode_reg_t event_reg = emit_event_flag(nets_reg, count_reg);
20✔
11190
   emit_return(emit_and(event_reg, value_reg));
20✔
11191
}
20✔
11192

11193
static void lower_predef(lower_unit_t *lu, object_t *obj)
2,457✔
11194
{
11195
   tree_t decl = tree_from_object(obj);
2,457✔
11196

11197
   const subprogram_kind_t kind = tree_subkind(decl);
2,457✔
11198
   assert(kind != S_USER);
2,457✔
11199
   assert(!is_open_coded_builtin(kind));
2,457✔
11200

11201
   type_t type = tree_type(decl);
2,457✔
11202
   if (type_has_result(type))
2,457✔
11203
      vcode_set_result(lower_func_result_type(type_result(type)));
2,385✔
11204

11205
   vcode_type_t vcontext = vtype_context(lu->parent->name);
2,457✔
11206
   emit_param(vcontext, vcontext, ident_new("context"));
2,457✔
11207

11208
   lower_subprogram_ports(lu, decl, false);
2,457✔
11209

11210
   switch (tree_subkind(decl)) {
2,457✔
11211
   case S_ARRAY_EQ:
700✔
11212
      lower_predef_array_cmp(lu, decl, VCODE_CMP_EQ);
700✔
11213
      break;
700✔
11214
   case S_ARRAY_LE:
69✔
11215
      lower_predef_array_cmp(lu, decl, VCODE_CMP_LEQ);
69✔
11216
      break;
69✔
11217
   case S_ARRAY_LT:
77✔
11218
      lower_predef_array_cmp(lu, decl, VCODE_CMP_LT);
77✔
11219
      break;
77✔
11220
   case S_ARRAY_GE:
69✔
11221
      lower_predef_negate(decl, "<");
69✔
11222
      break;
69✔
11223
   case S_ARRAY_GT:
69✔
11224
      lower_predef_negate(decl, "<=");
69✔
11225
      break;
69✔
11226
   case S_RECORD_EQ:
222✔
11227
      lower_predef_record_eq(lu, decl);
222✔
11228
      break;
222✔
11229
   case S_ARRAY_NEQ:
111✔
11230
   case S_RECORD_NEQ:
11231
      lower_predef_negate(decl, "=");
111✔
11232
      break;
111✔
11233
   case S_TO_STRING:
165✔
11234
      lower_predef_to_string(lu, decl);
165✔
11235
      break;
165✔
11236
   case S_TO_STRING_TIME:
8✔
11237
      lower_foreign_predef(lu, decl, "_std_to_string_time");
8✔
11238
      break;
8✔
11239
   case S_TO_STRING_REAL_DIGITS:
5✔
11240
      lower_foreign_predef(lu, decl, "_std_to_string_real_digits");
5✔
11241
      break;
5✔
11242
   case S_TO_STRING_REAL_FORMAT:
5✔
11243
      lower_foreign_predef(lu, decl, "_std_to_string_real_format");
5✔
11244
      break;
5✔
11245
   case S_TO_HSTRING_BITVEC:
5✔
11246
      lower_foreign_predef(lu, decl, "_std_to_hstring_bit_vec");
5✔
11247
      break;
5✔
11248
   case S_TO_OSTRING_BITVEC:
5✔
11249
      lower_foreign_predef(lu, decl, "_std_to_ostring_bit_vec");
5✔
11250
      break;
5✔
11251
   case S_SLL:
72✔
11252
   case S_SRL:
11253
   case S_SLA:
11254
   case S_SRA:
11255
   case S_ROL:
11256
   case S_ROR:
11257
      lower_predef_bit_shift(lu, decl, kind);
72✔
11258
      break;
72✔
11259
   case S_ARRAY_NOT:
113✔
11260
   case S_ARRAY_AND:
11261
   case S_ARRAY_OR:
11262
   case S_ARRAY_XOR:
11263
   case S_ARRAY_XNOR:
11264
   case S_ARRAY_NAND:
11265
   case S_ARRAY_NOR:
11266
      lower_predef_bit_vec_op(lu, decl, kind);
113✔
11267
      break;
113✔
11268
   case S_MIXED_AND:
114✔
11269
   case S_MIXED_OR:
11270
   case S_MIXED_XOR:
11271
   case S_MIXED_XNOR:
11272
   case S_MIXED_NAND:
11273
   case S_MIXED_NOR:
11274
      lower_predef_mixed_bit_vec_op(lu, decl, kind);
114✔
11275
      break;
114✔
11276
   case S_REDUCE_OR:
51✔
11277
   case S_REDUCE_AND:
11278
   case S_REDUCE_NAND:
11279
   case S_REDUCE_NOR:
11280
   case S_REDUCE_XOR:
11281
   case S_REDUCE_XNOR:
11282
      lower_predef_reduction_op(lu, decl, kind);
51✔
11283
      break;
51✔
11284
   case S_MATCH_EQ:
93✔
11285
   case S_MATCH_NEQ:
11286
   case S_MATCH_LT:
11287
   case S_MATCH_LE:
11288
   case S_MATCH_GT:
11289
   case S_MATCH_GE:
11290
      lower_predef_match_op(lu, decl, kind);
93✔
11291
      break;
93✔
11292
   case S_MAXIMUM:
188✔
11293
      lower_predef_min_max(lu, decl, VCODE_CMP_GT);
188✔
11294
      break;
188✔
11295
   case S_MINIMUM:
185✔
11296
      lower_predef_min_max(lu, decl, VCODE_CMP_LT);
185✔
11297
      break;
185✔
11298
   case S_FILE_FLUSH:
8✔
11299
      lower_foreign_predef(lu, decl, "__nvc_flush");
8✔
11300
      break;
8✔
11301
   case S_FILE_OPEN3:
4✔
11302
      lower_predef_file_open3(lu, decl);
4✔
11303
      break;
4✔
11304
   case S_FILE_CLOSE:
52✔
11305
      lower_foreign_predef(lu, decl, "__nvc_file_close");
52✔
11306
      break;
52✔
11307
   case S_ENDFILE:
15✔
11308
      lower_foreign_predef(lu, decl, "__nvc_endfile");
15✔
11309
      break;
15✔
11310
   case S_FILE_MODE:
4✔
11311
      lower_foreign_predef(lu, decl, "__nvc_file_mode");
4✔
11312
      break;
4✔
11313
   case S_FILE_CANSEEK:
4✔
11314
      lower_foreign_predef(lu, decl, "__nvc_file_canseek");
4✔
11315
      break;
4✔
11316
   case S_FILE_SIZE:
4✔
11317
      lower_foreign_predef(lu, decl, "__nvc_file_size");
4✔
11318
      break;
4✔
11319
   case S_FILE_REWIND:
4✔
11320
      lower_foreign_predef(lu, decl, "__nvc_rewind");
4✔
11321
      break;
4✔
11322
   case S_FILE_SEEK:
4✔
11323
      lower_foreign_predef(lu, decl, "__nvc_seek");
4✔
11324
      break;
4✔
11325
   case S_FILE_TRUNCATE:
4✔
11326
      lower_foreign_predef(lu, decl, "__nvc_truncate");
4✔
11327
      break;
4✔
11328
   case S_FILE_STATE:
4✔
11329
      lower_foreign_predef(lu, decl, "__nvc_file_state");
4✔
11330
      break;
4✔
11331
   case S_FILE_POSITION:
4✔
11332
      lower_foreign_predef(lu, decl, "__nvc_file_position");
4✔
11333
      break;
4✔
11334
   case S_RISING_EDGE:
20✔
11335
   case S_FALLING_EDGE:
11336
      return lower_edge_predef(lu, decl);
20✔
11337
   default:
×
11338
      fatal_trace("cannot lower predefined function %s", type_pp(type));
11339
   }
11340
}
11341

11342
static void lower_proc_body(lower_unit_t *lu, object_t *obj)
1,495✔
11343
{
11344
   tree_t body = tree_from_object(obj);
1,495✔
11345
   assert(!is_uninstantiated_subprogram(body));
1,495✔
11346

11347
   lu->cscope = cover_create_scope(lu->cover, lu->parent->cscope, body, NULL);
1,495✔
11348

11349
   vcode_type_t vcontext = vtype_context(lu->parent->name);
1,495✔
11350
   emit_param(vcontext, vcontext, ident_new("context"));
1,495✔
11351

11352
   if (tree_kind(body) == T_PROC_INST)
1,495✔
11353
      lower_generics(lu, body, NULL);
39✔
11354

11355
   const bool never_waits = vcode_unit_kind(lu->vunit) == VCODE_UNIT_FUNCTION;
1,495✔
11356
   const bool has_subprograms = lower_has_subprograms(body);
1,495✔
11357
   lower_subprogram_ports(lu, body, has_subprograms || !never_waits);
1,495✔
11358

11359
   lower_decls(lu, body);
1,495✔
11360

11361
   lower_sequence(lu, body, NULL);
1,495✔
11362

11363
   if (!vcode_block_finished()) {
1,495✔
11364
      lower_leave_subprogram(lu);
1,495✔
11365
      emit_return(VCODE_INVALID_REG);
1,495✔
11366
   }
11367
}
1,495✔
11368

11369
static void lower_func_body(lower_unit_t *lu, object_t *obj)
6,110✔
11370
{
11371
   tree_t body = tree_from_object(obj);
6,110✔
11372
   assert(!is_uninstantiated_subprogram(body));
6,110✔
11373

11374
   type_t result = type_result(tree_type(body));
6,110✔
11375
   vcode_set_result(lower_func_result_type(result));
6,110✔
11376

11377
   vcode_type_t vcontext = vtype_context(lu->parent->name);
6,110✔
11378
   emit_param(vcontext, vcontext, ident_new("context"));
6,110✔
11379

11380
   lu->cscope = cover_create_scope(lu->cover, lu->parent->cscope, body, NULL);
6,110✔
11381

11382
   if (tree_kind(body) == T_FUNC_INST)
6,110✔
11383
      lower_generics(lu, body, NULL);
39✔
11384

11385
   const bool has_subprograms = lower_has_subprograms(body);
6,110✔
11386
   lower_subprogram_ports(lu, body, has_subprograms);
6,110✔
11387

11388
   if (tree_flags(body) & TREE_F_KNOWS_SUBTYPE) {
6,110✔
11389
      // Extra hidden parameter for result bounds
11390
      vcode_type_t vresult = lower_param_type(result, C_CONSTANT, PORT_IN);
9✔
11391
      vcode_reg_t bounds_reg =
9✔
11392
         emit_param(vresult, vresult, ident_new("result"));
9✔
11393

11394
      lower_put_vcode_obj(body, bounds_reg, lu);
9✔
11395
   }
11396

11397
   lower_decls(lu, body);
6,110✔
11398

11399
   lower_sequence(lu, body, NULL);
6,110✔
11400

11401
   if (!vcode_block_finished())
6,110✔
11402
      emit_unreachable(lower_debug_locus(body));
90✔
11403
}
6,110✔
11404

11405
static void lower_driver_field_cb(lower_unit_t *lu, tree_t field,
2,737✔
11406
                                  vcode_reg_t ptr, vcode_reg_t unused,
11407
                                  vcode_reg_t locus, void *__ctx)
11408
{
11409
   tree_t view = untag_pointer(__ctx, void), elem = NULL;
2,737✔
11410
   bool converse = !!pointer_tag(__ctx);
2,737✔
11411

11412
   type_t type = tree_type(field);
2,737✔
11413

11414
   if (view != NULL) {
2,737✔
11415
      elem = find_element_mode_indication(view, field, &converse);
30✔
11416
      assert(elem != NULL);
30✔
11417

11418
      if (converse_mode(elem, converse) == PORT_IN)
30✔
11419
         return;
15✔
11420
   }
11421

11422
   if (type_is_homogeneous(type)) {
2,722✔
11423
      vcode_reg_t nets_reg = emit_load_indirect(ptr);
2,618✔
11424
      vcode_reg_t count_reg = lower_type_width(lu, type, nets_reg);
2,618✔
11425
      vcode_reg_t data_reg = lower_array_data(nets_reg);
2,618✔
11426

11427
      emit_drive_signal(data_reg, count_reg);
2,618✔
11428
   }
11429
   else if (elem != NULL && tree_subkind(elem) == PORT_RECORD_VIEW) {
104✔
11430
      void *new_ctx = tag_pointer(tree_value(elem), converse);
×
11431
      lower_for_each_field(lu, type, ptr, VCODE_INVALID_REG,
×
11432
                           lower_driver_field_cb, new_ctx);
11433
   }
11434
   else
11435
      lower_for_each_field(lu, type, ptr, VCODE_INVALID_REG,
104✔
11436
                           lower_driver_field_cb, NULL);
11437
}
11438

11439
static bool can_use_transfer_signal(tree_t proc, driver_set_t *ds)
8,922✔
11440
{
11441
   driver_info_t *di = get_drivers(ds, proc);
8,922✔
11442
   if (di == NULL || di->chain_proc != NULL)
8,922✔
11443
      return false;
11444
   else if (tree_stmts(proc) != 2)
5,463✔
11445
      return false;
11446

11447
   tree_t s0 = tree_stmt(proc, 0);
4,583✔
11448
   if (tree_kind(s0) != T_SIGNAL_ASSIGN)
4,583✔
11449
      return false;
11450
   else if (tree_target(s0) != di->prefix)
3,653✔
11451
      return false;
11452
   else if (!type_is_homogeneous(tree_type(di->prefix)))
3,644✔
11453
      return false;
11454
   else if (tree_waveforms(s0) != 1)
3,124✔
11455
      return false;
11456

11457
   tree_t w0 = tree_waveform(s0, 0);
3,034✔
11458
   if (tree_has_delay(w0)) {
3,034✔
11459
      tree_t d = tree_delay(w0);
474✔
11460
      if (tree_kind(d) != T_LITERAL)
474✔
11461
         return false;
11462
   }
11463

11464
   if (tree_has_reject(s0)) {
3,028✔
11465
      tree_t r = tree_reject(s0);
468✔
11466
      if (tree_kind(r) != T_LITERAL)
468✔
11467
         return false;
11468
   }
11469

11470
   tree_t value = tree_value(w0), ref = name_to_ref(value);
3,025✔
11471
   if (ref == NULL || class_of(ref) != C_SIGNAL)
3,025✔
11472
      return false;
1,765✔
11473
   else if (value != longest_static_prefix(value))
1,260✔
11474
      return false;
11475

11476
   tree_t s1 = tree_stmt(proc, 1);
1,242✔
11477
   if (tree_kind(s1) != T_WAIT)
1,242✔
11478
      return false;
11479
   else if (!(tree_flags(s1) & TREE_F_STATIC_WAIT))
1,242✔
11480
      return false;
11481
   else if (tree_triggers(s1) != 1)
1,242✔
11482
      return false;
11483

11484
   tree_t t0 = tree_trigger(s1, 0);
1,242✔
11485
   if (!same_tree(t0, value))
1,242✔
11486
      return false;
33✔
11487

11488
   return true;
11489
}
11490

11491
static vcode_reg_t lower_trigger(lower_unit_t *lu, tree_t fcall, tree_t proc)
509✔
11492
{
11493
   tree_t decl = tree_ref(fcall);
509✔
11494

11495
   const subprogram_kind_t kind = tree_subkind(decl);
509✔
11496
   if (kind == S_SCALAR_EQ) {
509✔
11497
      tree_t p0 = tree_value(tree_param(fcall, 0)), p1;
69✔
11498

11499
      if (is_literal(p0))   // Commute arguments
69✔
11500
         p1 = p0, p0 = tree_value(tree_param(fcall, 1));
×
11501
      else
11502
         p1 = tree_value(tree_param(fcall, 1));
69✔
11503

11504
      if (tree_kind(p0) != T_REF || class_of(p0) != C_SIGNAL)
69✔
11505
         return VCODE_INVALID_REG;
6✔
11506
      else if (!is_literal(p1))
63✔
11507
         return VCODE_INVALID_REG;
11508

11509
      vcode_reg_t left_reg = lower_lvalue(lu, p0);
63✔
11510
      vcode_reg_t right_reg = lower_rvalue(lu, p1);
63✔
11511

11512
      return emit_cmp_trigger(left_reg, right_reg);
63✔
11513
   }
11514
   else if (kind == S_SCALAR_AND) {
440✔
11515
      // Testing x'event is redundant if the process is only
11516
      // sensitive to x
11517
      tree_t w = tree_stmt(proc, 1);
230✔
11518
      assert(tree_kind(w) == T_WAIT);
230✔
11519

11520
      if (tree_triggers(w) != 1)
230✔
11521
         return VCODE_INVALID_REG;
11522

11523
      tree_t p0 = tree_value(tree_param(fcall, 0));
4✔
11524
      tree_t p1 = tree_value(tree_param(fcall, 1));
4✔
11525
      tree_t aref, other;
4✔
11526

11527
      if (tree_kind(p0) == T_ATTR_REF)
4✔
11528
         aref = p0, other = p1;
11529
      else if (tree_kind(p1) == T_ATTR_REF)
×
11530
         aref = p1, other = p0;
11531
      else
11532
         return VCODE_INVALID_REG;
11533

11534
      if (tree_subkind(aref) != ATTR_EVENT)
4✔
11535
         return VCODE_INVALID_REG;
11536
      else if (tree_kind(other) != T_FCALL)
4✔
11537
         return VCODE_INVALID_REG;
11538

11539
      if (!same_tree(tree_name(aref), tree_trigger(w, 0)))
4✔
11540
         return VCODE_INVALID_REG;
11541

11542
      return lower_trigger(lu, other, proc);
4✔
11543
   }
11544
   else if (kind != S_USER && kind != S_FALLING_EDGE && kind != S_RISING_EDGE)
210✔
11545
      return VCODE_INVALID_REG;
11546
   else if (tree_flags(decl) & TREE_F_IMPURE)
149✔
11547
      return VCODE_INVALID_REG;
11548

11549
   const int nparams = tree_params(fcall);
149✔
11550
   if (nparams != tree_ports(decl))
149✔
11551
      return VCODE_INVALID_REG;
11552

11553
   for (int i = 0; i < nparams; i++) {
291✔
11554
      tree_t p = tree_param(fcall, i);
149✔
11555
      tree_t value = tree_value(p);
149✔
11556
      if (is_literal(value))
149✔
11557
         continue;
×
11558
      else if (tree_kind(value) == T_REF && class_of(value) == C_SIGNAL) {
149✔
11559
         // Must be passing as a signal not the resolved value
11560
         if (tree_subkind(p) != P_POS)
146✔
11561
            return VCODE_INVALID_REG;
11562
         else if (tree_class(tree_port(decl, tree_pos(p))) != C_SIGNAL)
146✔
11563
            return VCODE_INVALID_REG;
11564
      }
11565
      else
11566
         return VCODE_INVALID_REG;
3✔
11567
   }
11568

11569
   ident_t name = tree_ident2(decl);
142✔
11570

11571
   vcode_reg_t *args LOCAL = xmalloc_array(nparams + 1, sizeof(vcode_reg_t));
284✔
11572
   args[0] = lower_context_for_call(lu, name);
142✔
11573

11574
   for (int i = 0; i < nparams; i++)
284✔
11575
      args[i + 1] = lower_subprogram_arg(lu, fcall, i);
142✔
11576

11577
   return emit_function_trigger(name, args, nparams + 1);
142✔
11578
}
11579

11580
static vcode_reg_t lower_process_trigger(lower_unit_t *lu, tree_t proc)
3,765✔
11581
{
11582
   if (cover_enabled(lu->cover, COVER_MASK_BRANCH | COVER_MASK_EXPRESSION))
3,765✔
11583
      return VCODE_INVALID_REG;   // Would have incorrect branch coverage
11584
   else if (tree_stmts(proc) != 2)
3,457✔
11585
      return VCODE_INVALID_REG;
11586

11587
   // Preconditions
11588
   assert(tree_kind(tree_stmt(proc, 1)) == T_WAIT);
3,374✔
11589
   assert(tree_flags(tree_stmt(proc, 1)) & TREE_F_STATIC_WAIT);
3,374✔
11590

11591
   tree_t s0 = tree_stmt(proc, 0);
3,374✔
11592
   if (tree_kind(s0) != T_IF)
3,374✔
11593
      return VCODE_INVALID_REG;
11594

11595
   const int nconds = tree_conds(s0);
517✔
11596
   if (nconds > 2)
517✔
11597
      return VCODE_INVALID_REG;
11598

11599
   vcode_reg_t branches[2] = { VCODE_INVALID_REG, VCODE_INVALID_REG };
511✔
11600
   for (int i = 0; i < nconds; i++) {
1,016✔
11601
      tree_t c = tree_cond(s0, i);
798✔
11602
      if (!tree_has_value(c))
798✔
11603
         return VCODE_INVALID_REG;
11604

11605
      tree_t value = tree_value(c);
555✔
11606
      if (tree_kind(value) != T_FCALL)
555✔
11607
         return VCODE_INVALID_REG;
11608

11609
      branches[i] = lower_trigger(lu, value, proc);
505✔
11610
   }
11611

11612
   if (nconds == 1)
218✔
11613
      return branches[0];
174✔
11614
   else if (branches[0] == VCODE_INVALID_REG
44✔
11615
            || branches[1] == VCODE_INVALID_REG)
41✔
11616
      return VCODE_INVALID_REG;
11617
   else
11618
      return emit_or_trigger(branches[0], branches[1]);
31✔
11619
}
11620

11621
void lower_process(lower_unit_t *parent, tree_t proc, driver_set_t *ds)
8,922✔
11622
{
11623
   assert(tree_kind(proc) == T_PROCESS);
8,922✔
11624

11625
   ident_t label = tree_ident(proc);
8,922✔
11626
   ident_t name = ident_prefix(parent->name, label, '.');
8,922✔
11627
   vcode_unit_t vu = emit_process(name, tree_to_object(proc), parent->vunit);
8,922✔
11628

11629
   // The code generator assumes the first state starts at block number
11630
   // one. Allocate it here in case lowering the declarations generates
11631
   // additional basic blocks.
11632
   vcode_block_t start_bb = emit_block();
8,922✔
11633
   assert(start_bb == 1);
8,922✔
11634

11635
   lower_unit_t *lu = lower_unit_new(parent->registry, parent, vu,
8,922✔
11636
                                     parent->cover, proc);
11637
   unit_registry_put(parent->registry, lu);
8,922✔
11638

11639
   lu->cscope = cover_create_scope(lu->cover, parent->cscope, proc, NULL);
8,922✔
11640

11641
   if (tree_global_flags(proc) & TREE_GF_EXTERNAL_NAME)
8,922✔
11642
      tree_visit_only(proc, lower_external_name_cache, lu, T_EXTERNAL_NAME);
115✔
11643

11644
   lower_decls(lu, proc);
8,922✔
11645

11646
   driver_info_t *di = get_drivers(ds, proc);
8,922✔
11647
   for (; di; di = di->chain_proc) {
25,095✔
11648
      assert(!di->tentative);
7,251✔
11649
      type_t prefix_type = tree_type(di->prefix);
7,251✔
11650
      vcode_reg_t nets_reg = lower_lvalue(lu, di->prefix);
7,251✔
11651

11652
      if (!type_is_homogeneous(prefix_type))
7,251✔
11653
         lower_for_each_field(lu, prefix_type, nets_reg, VCODE_INVALID_REG,
739✔
11654
                              lower_driver_field_cb, di->view);
739✔
11655
      else {
11656
         assert(di->view == NULL);
6,512✔
11657
         vcode_reg_t count_reg = lower_type_width(lu, prefix_type, nets_reg);
6,512✔
11658
         emit_drive_signal(lower_array_data(nets_reg), count_reg);
6,512✔
11659
      }
11660
   }
11661

11662
   const bool transfer = can_use_transfer_signal(proc, ds);
8,922✔
11663
   vcode_reg_t trigger_reg = VCODE_INVALID_REG;
8,922✔
11664

11665
   if (transfer) {
8,922✔
11666
      tree_t s0 = tree_stmt(proc, 0);
1,209✔
11667
      assert(tree_kind(s0) == T_SIGNAL_ASSIGN);
1,209✔
11668
      assert(tree_waveforms(s0) == 1);
1,209✔
11669

11670
      emit_debug_info(tree_loc(s0));
1,209✔
11671

11672
      tree_t target = tree_target(s0);
1,209✔
11673
      vcode_reg_t target_reg = lower_lvalue(lu, target);
1,209✔
11674

11675
      tree_t w0 = tree_waveform(s0, 0);
1,209✔
11676
      vcode_reg_t source_reg = lower_lvalue(lu, tree_value(w0));
1,209✔
11677

11678
      vcode_reg_t count_reg =
1,209✔
11679
         lower_type_width(lu, tree_type(target), target_reg);
1,209✔
11680

11681
      vcode_reg_t delay_reg;
1,209✔
11682
      if (tree_has_delay(w0))
1,209✔
11683
         delay_reg = lower_rvalue(lu, tree_delay(w0));
336✔
11684
      else
11685
         delay_reg = emit_const(vtype_time(), 0);
873✔
11686

11687
      vcode_reg_t reject_reg = delay_reg;
1,209✔
11688
      if (tree_has_reject(s0))
1,209✔
11689
         reject_reg = lower_rvalue(lu, tree_reject(s0));
336✔
11690

11691
      vcode_reg_t target_nets = lower_array_data(target_reg);
1,209✔
11692
      vcode_reg_t source_nets = lower_array_data(source_reg);
1,209✔
11693
      emit_transfer_signal(target_nets, source_nets, count_reg,
1,209✔
11694
                           reject_reg, delay_reg);
11695
   }
11696
   else {
11697
      // If the last statement in the process is a static wait then this
11698
      // process is always sensitive to the same set of signals and we can
11699
      // emit a single _sched_event call in the reset block
11700
      tree_t wait = NULL;
7,713✔
11701
      const int nstmts = tree_stmts(proc);
7,713✔
11702
      if (nstmts > 0
7,713✔
11703
          && tree_kind((wait = tree_stmt(proc, nstmts - 1))) == T_WAIT
7,712✔
11704
          && (tree_flags(wait) & TREE_F_STATIC_WAIT)) {
7,541✔
11705

11706
         const int ntriggers = tree_triggers(wait);
3,765✔
11707
         for (int i = 0; i < ntriggers; i++)
7,447✔
11708
            lower_sched_event(lu, tree_trigger(wait, i));
3,682✔
11709

11710
         trigger_reg = lower_process_trigger(lu, proc);
3,765✔
11711

11712
         if (trigger_reg != VCODE_INVALID_REG)
3,765✔
11713
            emit_add_trigger(trigger_reg);
155✔
11714
      }
11715
   }
11716

11717
   emit_return(VCODE_INVALID_REG);
8,922✔
11718

11719
   vcode_select_block(start_bb);
8,922✔
11720

11721
   if (transfer)
8,922✔
11722
      emit_return(VCODE_INVALID_REG);
1,209✔
11723
   else if (trigger_reg != VCODE_INVALID_REG) {
7,713✔
11724
      tree_t s0 = tree_stmt(proc, 0);
155✔
11725
      assert(tree_kind(s0) == T_IF);
155✔
11726
      lower_stmt_coverage(lu, s0);
155✔
11727

11728
      const int nconds = tree_conds(s0);
155✔
11729
      if (nconds == 1) {
155✔
11730
         tree_t c = tree_cond(s0, 0);
124✔
11731
         PUSH_COVER_SCOPE(lu, c);
248✔
11732
         lower_sequence(lu, c, NULL);
124✔
11733
      }
11734
      else {
11735
         assert(nconds == 2);
31✔
11736
         tree_t c0 = tree_cond(s0, 0), c1 = tree_cond(s0, 1);
31✔
11737

11738
         vcode_reg_t test = lower_rvalue(lu, tree_value(c0));
31✔
11739
         vcode_block_t btrue = emit_block();
31✔
11740
         vcode_block_t bfalse = emit_block();
31✔
11741
         vcode_block_t bjoin = emit_block();
31✔
11742
         emit_cond(test, btrue, bfalse);
31✔
11743

11744
         {
11745
            vcode_select_block(btrue);
31✔
11746

11747
            PUSH_COVER_SCOPE(lu, c0);
62✔
11748
            lower_sequence(lu, c0, NULL);
31✔
11749

11750
            if (!vcode_block_finished())
31✔
11751
               emit_jump(bjoin);
31✔
11752
         }
11753

11754
         {
11755
            vcode_select_block(bfalse);
31✔
11756

11757
            PUSH_COVER_SCOPE(lu, c1);
62✔
11758
            lower_sequence(lu, c1, NULL);
31✔
11759

11760
            if (!vcode_block_finished())
31✔
11761
               emit_jump(bjoin);
31✔
11762
         }
11763

11764
         vcode_select_block(bjoin);
31✔
11765
      }
11766

11767
      tree_t s1 = tree_stmt(proc, 1);
155✔
11768
      assert(tree_kind(s1) == T_WAIT);
155✔
11769

11770
      lower_wait(lu, s1);
155✔
11771
   }
11772
   else
11773
      lower_sequence(lu, proc, NULL);
7,558✔
11774

11775
   if (!vcode_block_finished())
8,922✔
11776
      emit_jump(start_bb);
7,713✔
11777

11778
   lower_finished(lu, NULL);
8,922✔
11779
   unit_registry_finalise(parent->registry, lu);
8,922✔
11780
}
8,922✔
11781

11782
static bool lower_is_signal_ref(tree_t expr)
20,410✔
11783
{
11784
   switch (tree_kind(expr)) {
28,188✔
11785
   case T_REF:
18,452✔
11786
      return class_of(tree_ref(expr)) == C_SIGNAL;
18,452✔
11787

11788
   case T_ALIAS:
7,778✔
11789
   case T_ARRAY_SLICE:
11790
   case T_ARRAY_REF:
11791
   case T_RECORD_REF:
11792
   case T_QUALIFIED:
11793
   case T_TYPE_CONV:
11794
      return lower_is_signal_ref(tree_value(expr));
7,778✔
11795

11796
   default:
11797
      return false;
11798
   }
11799
}
11800

11801
static void lower_conv_field_cb(lower_unit_t *lu, tree_t field,
168✔
11802
                                vcode_reg_t target_ptr, vcode_reg_t result_ptr,
11803
                                vcode_reg_t locus, void *ctx)
11804
{
11805
   type_t ftype = tree_type(field);
168✔
11806

11807
   if (type_is_homogeneous(ftype)) {
168✔
11808
      vcode_reg_t nets_reg = emit_load_indirect(target_ptr);
168✔
11809
      vcode_reg_t count_reg, data_reg = result_ptr;
168✔
11810
      if (type_is_array(ftype)) {
168✔
11811
         count_reg = lower_array_total_len(lu, ftype, nets_reg);
138✔
11812
         data_reg = lower_array_data(result_ptr);
138✔
11813
         nets_reg = lower_array_data(nets_reg);
138✔
11814
      }
11815
      else {
11816
         count_reg = emit_const(vtype_offset(), 1);
30✔
11817
         nets_reg = emit_load_indirect(target_ptr);
30✔
11818
      }
11819

11820
      vcode_reg_t cf_reg = (uintptr_t)ctx;
168✔
11821
      emit_put_conversion(cf_reg, nets_reg, count_reg, data_reg);
168✔
11822
   }
11823
   else
11824
      lower_for_each_field_2(lu, ftype, ftype, target_ptr, result_ptr, locus,
×
11825
                             lower_conv_field_cb, ctx);
11826
}
168✔
11827

11828
static vcode_reg_t lower_converter(lower_unit_t *parent, tree_t dst, tree_t src,
310✔
11829
                                   tree_t conv, port_mode_t dir)
11830
{
11831
   type_t dst_type = tree_type(dst);
310✔
11832
   type_t src_type = tree_type(src);
310✔
11833
   type_t conv_type = tree_type(conv);
310✔
11834

11835
   // Detect some trivial cases and avoid generating a conversion function
11836
   const tree_kind_t kind = tree_kind(conv);
310✔
11837
   if (kind == T_TYPE_CONV) {
310✔
11838
      if (type_is_array(conv_type) && type_is_array(src_type)) {
31✔
11839
         if (type_eq(type_elem(conv_type), type_elem(src_type)))
13✔
11840
            return VCODE_INVALID_REG;
11841
      }
11842
      else if (type_is_enum(conv_type) && type_is_enum(src_type))
18✔
11843
         return VCODE_INVALID_REG;
11844
   }
11845

11846
   vcode_state_t state;
303✔
11847
   vcode_state_save(&state);
303✔
11848

11849
   ident_t name;
303✔
11850
   if (tree_kind(dst) == T_PORT_DECL)
303✔
11851
      name = ident_sprintf("%s.%s.convert_%s", istr(parent->name),
104✔
11852
                           istr(tree_ident(dst)),
11853
                           dir == PORT_IN ? "in" : "out");
11854
   else
11855
      name = ident_uniq("%s.%s.convert_%s.part", istr(parent->name),
306✔
11856
                        istr(tree_ident(tree_ref(name_to_ref(dst)))),
11857
                        dir == PORT_IN ? "in" : "out");
11858

11859
   vcode_unit_t vu = emit_function(name, tree_to_object(dst), parent->vunit);
303✔
11860
   emit_debug_info(tree_loc(src));
303✔
11861

11862
   // Dummy return value to force function calling convention
11863
   vcode_type_t voffset = vtype_offset();
303✔
11864
   vcode_set_result(voffset);
303✔
11865

11866
   lower_unit_t *lu = lower_unit_new(parent->registry, parent, vu, NULL, NULL);
303✔
11867
   unit_registry_put(parent->registry, lu);
303✔
11868

11869
   vcode_type_t vcontext = vtype_context(parent->name);
303✔
11870
   emit_param(vcontext, vcontext, ident_new("context"));
303✔
11871

11872
   vcode_type_t vconv = vtype_conversion();
303✔
11873
   vcode_reg_t cf_reg = emit_param(vconv, vconv, ident_new("cf"));
303✔
11874

11875
   vcode_reg_t target_reg;
303✔
11876
   if (tree_kind(dst) == T_PORT_DECL)
303✔
11877
      target_reg = lower_port_ref(lu, dst);
104✔
11878
   else
11879
      target_reg = lower_lvalue(lu, dst);
199✔
11880

11881
   vcode_reg_t in_reg;
303✔
11882
   if (dir == PORT_IN)
303✔
11883
      in_reg = lower_rvalue(lu, src);
196✔
11884
   else
11885
      in_reg = lower_driving_value(lu, src);
107✔
11886

11887
   vcode_reg_t result_reg = in_reg;
303✔
11888
   if (kind == T_TYPE_CONV)
303✔
11889
      result_reg = lower_conversion(lu, in_reg, conv, src_type, conv_type);
24✔
11890
   else {
11891
      tree_t fdecl = tree_ref(conv);
279✔
11892

11893
      type_t p0_type = tree_type(tree_port(fdecl, 0));
279✔
11894
      vcode_reg_t arg_reg = in_reg;
279✔
11895
      if (type_is_array(p0_type))
279✔
11896
         arg_reg = lower_coerce_arrays(lu, src_type, p0_type, in_reg);
78✔
11897

11898
      vcode_type_t vrtype = lower_func_result_type(conv_type);
279✔
11899
      vcode_type_t vrbounds = lower_bounds(conv_type);
279✔
11900

11901
      ident_t func = tree_ident2(fdecl);
279✔
11902
      vcode_reg_t context_reg = lower_context_for_call(lu, func);
279✔
11903
      vcode_reg_t args[] = { context_reg, arg_reg };
279✔
11904
      result_reg = emit_fcall(func, vrtype, vrbounds, args, 2);
279✔
11905

11906
      if (type_is_array(dst_type)) {
279✔
11907
         vcode_reg_t locus = lower_debug_locus(conv);
69✔
11908
         lower_check_array_sizes(lu, dst_type, conv_type, target_reg,
69✔
11909
                                 result_reg, locus);
11910
      }
11911
   }
11912

11913
   if (type_is_homogeneous(dst_type)) {
303✔
11914
      vcode_reg_t count_reg, data_reg = result_reg, nets_reg = target_reg;
255✔
11915
      if (type_is_array(dst_type)) {
255✔
11916
         count_reg = lower_array_total_len(lu, dst_type, target_reg);
48✔
11917
         data_reg = lower_array_data(result_reg);
48✔
11918
         nets_reg = lower_array_data(target_reg);
48✔
11919
      }
11920
      else
11921
         count_reg = emit_const(voffset, 1);
207✔
11922

11923
      emit_put_conversion(cf_reg, nets_reg, count_reg, data_reg);
255✔
11924
   }
11925
   else {
11926
      vcode_reg_t locus = lower_debug_locus(conv);
48✔
11927
      lower_for_each_field_2(lu, dst_type, conv_type, target_reg,
48✔
11928
                             result_reg, locus, lower_conv_field_cb,
11929
                             (void *)(uintptr_t)cf_reg);
48✔
11930
   }
11931

11932
   emit_return(emit_const(voffset, 0));
303✔
11933

11934
   unit_registry_finalise(parent->registry, lu);
303✔
11935

11936
   vcode_state_restore(&state);
303✔
11937

11938
   vcode_reg_t context_reg = lower_context_for_call(parent, name);
303✔
11939
   vcode_reg_t vdummy = vtype_opaque();
303✔
11940
   return emit_closure(name, context_reg, vdummy, vdummy);
303✔
11941
}
11942

11943
static void lower_map_signal_field_cb(lower_unit_t *lu, tree_t field,
1,493✔
11944
                                      vcode_reg_t src_ptr, vcode_reg_t dst_ptr,
11945
                                      vcode_reg_t locus, void *ctx)
11946
{
11947
   type_t ftype = tree_type(field);
1,493✔
11948

11949
   if (type_is_homogeneous(ftype)) {
1,493✔
11950
      vcode_reg_t dst_reg = emit_load_indirect(dst_ptr);
1,483✔
11951

11952
      vcode_reg_t src_reg;
1,483✔
11953
      if (lower_have_signal(src_ptr))
1,483✔
11954
         src_reg = emit_load_indirect(src_ptr);
1,444✔
11955
      else if (have_uarray_ptr(src_ptr))
39✔
11956
         src_reg = emit_load_indirect(src_ptr);
×
11957
      else
11958
         src_reg = src_ptr;
11959

11960
      if (type_is_array(ftype))
1,483✔
11961
         lower_check_array_sizes(lu, ftype, ftype, src_reg, dst_reg, locus);
161✔
11962

11963
      vcode_reg_t count_reg = lower_type_width(lu, ftype, dst_reg);
1,483✔
11964

11965
      src_reg = lower_array_data(src_reg);
1,483✔
11966
      dst_reg = lower_array_data(dst_reg);
1,483✔
11967

11968
      if (lower_have_signal(src_reg))
1,483✔
11969
         emit_map_signal(src_reg, dst_reg, count_reg);
1,444✔
11970
      else
11971
         emit_map_const(src_reg, dst_reg, count_reg);
39✔
11972
   }
11973
   else
11974
      lower_for_each_field_2(lu, ftype, ftype, src_ptr, dst_ptr, locus,
10✔
11975
                             lower_map_signal_field_cb, ctx);
11976
}
1,493✔
11977

11978
static void lower_map_view_field_cb(lower_unit_t *lu, tree_t field,
114✔
11979
                                    vcode_reg_t src_ptr, vcode_reg_t dst_ptr,
11980
                                    vcode_reg_t locus, void *__ctx)
11981
{
11982
   tree_t view = untag_pointer(__ctx, void);
114✔
11983
   bool converse = !!pointer_tag(__ctx);
114✔
11984

11985
   tree_t elem = find_element_mode_indication(view, field, &converse);
114✔
11986
   assert(elem != NULL);
114✔
11987

11988
   type_t ftype = tree_type(field);
114✔
11989
   if (type_is_homogeneous(ftype)) {
114✔
11990
      vcode_reg_t src_reg = emit_load_indirect(src_ptr);
99✔
11991
      vcode_reg_t dst_reg = emit_load_indirect(dst_ptr);
99✔
11992

11993
      if (type_is_array(ftype))
99✔
11994
         lower_check_array_sizes(lu, ftype, ftype, src_reg, dst_reg, locus);
20✔
11995

11996
      vcode_reg_t count_reg = lower_type_width(lu, ftype, src_reg);
99✔
11997

11998
      vcode_reg_t src_nets = lower_array_data(src_reg);
99✔
11999
      vcode_reg_t dst_nets = lower_array_data(dst_reg);
99✔
12000

12001
      switch (converse_mode(elem, converse)) {
99✔
12002
      case PORT_IN:
45✔
12003
         emit_map_signal(dst_nets, src_nets, count_reg);
45✔
12004
         break;
45✔
12005
      case PORT_OUT:
54✔
12006
      case PORT_INOUT:
12007
      case PORT_BUFFER:
12008
         emit_map_signal(src_nets, dst_nets, count_reg);
54✔
12009
         break;
54✔
12010
      default:
×
12011
         fatal_trace("unhandled port mode in lower_map_view_field_cb");
12012
      }
12013
   }
12014
   else if (tree_subkind(elem) == PORT_RECORD_VIEW) {
15✔
12015
      void *new_ctx = tag_pointer(tree_value(elem), converse);
6✔
12016
      lower_for_each_field_2(lu, ftype, ftype, src_ptr, dst_ptr, locus,
6✔
12017
                             lower_map_view_field_cb, new_ctx);
12018
   }
12019
   else if (converse_mode(elem, converse) == PORT_IN)
9✔
12020
      lower_for_each_field_2(lu, ftype, ftype, dst_ptr, src_ptr, locus,
6✔
12021
                             lower_map_signal_field_cb, NULL);
12022
   else
12023
      lower_for_each_field_2(lu, ftype, ftype, src_ptr, dst_ptr, locus,
3✔
12024
                             lower_map_signal_field_cb, NULL);
12025
}
114✔
12026

12027
static void lower_map_signal(lower_unit_t *lu, vcode_reg_t src_reg,
4,240✔
12028
                             vcode_reg_t dst_reg, type_t src_type,
12029
                             type_t dst_type, tree_t where)
12030
{
12031
   if (!type_is_homogeneous(src_type)) {
4,240✔
12032
      vcode_reg_t locus = lower_debug_locus(where);
295✔
12033
      lower_for_each_field_2(lu, src_type, dst_type, src_reg, dst_reg, locus,
295✔
12034
                             lower_map_signal_field_cb, NULL);
12035
   }
12036
   else if (type_is_array(src_type)) {
3,945✔
12037
      vcode_reg_t locus = lower_debug_locus(where);
1,251✔
12038
      lower_check_array_sizes(lu, dst_type, src_type, dst_reg, src_reg, locus);
1,251✔
12039

12040
      vcode_reg_t src_nets = lower_array_data(src_reg);
1,251✔
12041
      vcode_reg_t dst_nets = lower_array_data(dst_reg);
1,251✔
12042

12043
      vcode_reg_t count_reg = lower_array_total_len(lu, dst_type, dst_reg);
1,251✔
12044

12045
      if (lower_have_signal(src_reg))
1,251✔
12046
         emit_map_signal(src_nets, dst_nets, count_reg);
1,161✔
12047
      else
12048
         emit_map_const(src_nets, dst_nets, count_reg);
90✔
12049
   }
12050
   else {
12051
      vcode_reg_t count_reg = emit_const(vtype_offset(), 1);
2,694✔
12052
      vcode_reg_t dst_nets = lower_array_data(dst_reg);
2,694✔
12053

12054
      if (lower_have_signal(src_reg))
2,694✔
12055
         emit_map_signal(src_reg, dst_nets, count_reg);
2,607✔
12056
      else
12057
         emit_map_const(src_reg, dst_nets, count_reg);
87✔
12058
   }
12059
}
4,240✔
12060

12061
static void lower_convert_signal_field_cb(lower_unit_t *lu, tree_t field,
291✔
12062
                                          vcode_reg_t src_ptr,
12063
                                          vcode_reg_t dst_ptr,
12064
                                          vcode_reg_t conv_func, void *ctx)
12065
{
12066
   type_t ftype = tree_type(field);
291✔
12067
   void (*emit_fn)(vcode_reg_t, vcode_reg_t, vcode_reg_t) = ctx;
291✔
12068

12069
   if (type_is_homogeneous(ftype)) {
291✔
12070
      vcode_reg_t nets_reg = emit_load_indirect(src_ptr);
291✔
12071
      vcode_reg_t count_reg = lower_type_width(lu, ftype, nets_reg);
291✔
12072
      vcode_reg_t data_reg = lower_array_data(nets_reg);
291✔
12073
      (*emit_fn)(conv_func, data_reg, count_reg);
291✔
12074
   }
12075
   else
12076
      lower_for_each_field_2(lu, ftype, ftype, src_ptr, dst_ptr, conv_func,
×
12077
                             lower_convert_signal_field_cb, ctx);
12078
}
291✔
12079

12080
static void lower_convert_signal(lower_unit_t *lu, vcode_reg_t src_reg,
570✔
12081
                                 type_t type, vcode_reg_t conv_func,
12082
                                 convert_emit_fn emit_fn)
12083
{
12084
   if (!type_is_homogeneous(type))
570✔
12085
      lower_for_each_field(lu, type, src_reg, conv_func,
93✔
12086
                           lower_convert_signal_field_cb, emit_fn);
12087
   else if (type_is_array(type)) {
477✔
12088
      vcode_reg_t count_reg = lower_array_total_len(lu, type, src_reg);
102✔
12089
      vcode_reg_t nets_reg = lower_array_data(src_reg);
102✔
12090
      (*emit_fn)(conv_func, nets_reg, count_reg);
102✔
12091
   }
12092
   else {
12093
      vcode_reg_t count_reg = emit_const(vtype_offset(), 1);
375✔
12094
      vcode_reg_t nets_reg = lower_array_data(src_reg);
375✔
12095
      (*emit_fn)(conv_func, nets_reg, count_reg);
375✔
12096
   }
12097
}
570✔
12098

12099
static void lower_inertial_actual(lower_unit_t *parent, tree_t dst,
28✔
12100
                                  type_t type, vcode_reg_t port_reg,
12101
                                  tree_t actual)
12102
{
12103
   // Construct the equivalent process according the procedure in LRM 08
12104
   // section 6.5.6.3
12105

12106
   assert(standard() >= STD_08);
28✔
12107

12108
   ident_t name;
28✔
12109
   if (tree_kind(dst) == T_PORT_DECL)
28✔
12110
      name = ident_sprintf("%s_actual", istr(tree_ident(dst)));
19✔
12111
   else
12112
      name = ident_uniq("%s_actual.part", istr(tree_ident(name_to_ref(dst))));
9✔
12113

12114
   vcode_type_t signal_type = lower_signal_type(type);
28✔
12115
   vcode_type_t vbounds = lower_bounds(type);
28✔
12116
   vcode_var_t var = emit_var(signal_type, vbounds, name, VAR_SIGNAL);
28✔
12117

12118
   if (type_is_record(type)) {
28✔
12119
      vcode_reg_t locus = lower_debug_locus(dst);
3✔
12120
      vcode_reg_t ptr_reg = emit_index(var, VCODE_INVALID_REG);
3✔
12121
      lower_copy_record(parent, type, ptr_reg, port_reg, locus);
3✔
12122
   }
12123
   else
12124
      emit_store(port_reg, var);
25✔
12125

12126
   tree_t expr = tree_value(actual);
28✔
12127
   tree_t target = tree_target(actual);
28✔
12128

12129
   vcode_state_t state;
28✔
12130
   vcode_state_save(&state);
28✔
12131

12132
   ident_t pname = ident_prefix(parent->name, name, '.');
28✔
12133
   vcode_unit_t vu = emit_process(pname, tree_to_object(actual), parent->vunit);
28✔
12134

12135
   lower_unit_t *lu = lower_unit_new(parent->registry, parent, vu, NULL, NULL);
28✔
12136
   unit_registry_put(parent->registry, lu);
28✔
12137

12138
   // Block number one must be the non-reset entry point
12139
   vcode_block_t main_bb = emit_block();
28✔
12140
   assert(main_bb == 1);
28✔
12141

12142
   if (tree_global_flags(actual) & TREE_GF_EXTERNAL_NAME)
28✔
12143
      tree_visit_only(actual, lower_external_name_cache, lu, T_EXTERNAL_NAME);
1✔
12144

12145
   if (type_is_homogeneous(type)) {
28✔
12146
      vcode_reg_t nets_reg = emit_load_indirect(emit_var_upref(1, var));
25✔
12147
      vcode_reg_t count_reg = lower_type_width(lu, type, nets_reg);
25✔
12148
      vcode_reg_t data_reg = lower_array_data(nets_reg);
25✔
12149

12150
      emit_drive_signal(data_reg, count_reg);
25✔
12151
   }
12152
   else {
12153
      vcode_reg_t ptr_reg = emit_var_upref(1, var);
3✔
12154
      lower_for_each_field(lu, type, ptr_reg, VCODE_INVALID_REG,
3✔
12155
                           lower_driver_field_cb, NULL);
12156
   }
12157

12158
   build_wait(expr, lower_build_wait_cb, lu);
28✔
12159

12160
   emit_return(VCODE_INVALID_REG);
28✔
12161

12162
   vcode_select_block(main_bb);
28✔
12163

12164
   vcode_reg_t zero_time_reg = emit_const(vtype_time(), 0);
28✔
12165
   vcode_reg_t value_reg = lower_rvalue(lu, expr);
28✔
12166
   vcode_reg_t nets_reg = emit_var_upref(1, var);
28✔
12167

12168
   if (!type_is_record(type))
28✔
12169
      nets_reg = emit_load_indirect(nets_reg);
25✔
12170

12171
   target_part_t parts[] = {
28✔
12172
      { .kind = PART_ALL,
12173
        .reg = nets_reg,
12174
        .off = VCODE_INVALID_REG,
12175
        .target = target },
12176
      { .kind = PART_POP,
12177
        .reg = VCODE_INVALID_REG,
12178
        .off = VCODE_INVALID_REG,
12179
      }
12180
   };
12181

12182
   target_part_t *ptr = parts;
28✔
12183
   lower_signal_assign_target(lu, &ptr, target, value_reg, tree_type(expr),
28✔
12184
                              zero_time_reg, zero_time_reg);
12185

12186
   emit_return(VCODE_INVALID_REG);
28✔
12187

12188
   unit_registry_finalise(parent->registry, lu);
28✔
12189

12190
   vcode_state_restore(&state);
28✔
12191

12192
   emit_process_init(pname, lower_debug_locus(actual));
28✔
12193
}
28✔
12194

12195
static void lower_port_map(lower_unit_t *lu, tree_t block, tree_t map,
5,119✔
12196
                           vcode_reg_t value_reg)
12197
{
12198
   vcode_reg_t port_reg = VCODE_INVALID_REG;
5,119✔
12199
   tree_t view = NULL, name;
5,119✔
12200
   vcode_reg_t out_conv = VCODE_INVALID_REG;
5,119✔
12201
   vcode_reg_t in_conv = VCODE_INVALID_REG;
5,119✔
12202
   tree_t value = tree_value(map);
5,119✔
12203
   port_mode_t mode = PORT_IN;
5,119✔
12204

12205
   tree_t value_conv = NULL;
5,119✔
12206
   const tree_kind_t value_kind = tree_kind(value);
5,119✔
12207
   if (value_kind == T_CONV_FUNC || value_kind == T_TYPE_CONV) {
5,119✔
12208
      assert(value_reg == VCODE_INVALID_REG);
203✔
12209
      tree_t p0 = tree_value(value);
203✔
12210
      if (lower_is_signal_ref(p0)) {
203✔
12211
         value_conv = p0;
203✔
12212
         value_reg = lower_lvalue(lu, p0);
203✔
12213
      }
12214
      else
12215
         value_reg = lower_rvalue(lu, value);
×
12216
   }
12217

12218
   switch (tree_subkind(map)) {
5,119✔
12219
   case P_POS:
4,416✔
12220
      {
12221
         tree_t port = name = tree_port(block, tree_pos(map));
4,416✔
12222
         mode = tree_subkind(port);
4,416✔
12223

12224
         if (mode == PORT_ARRAY_VIEW || mode == PORT_RECORD_VIEW)
4,416✔
12225
            view = tree_value(port);
38✔
12226

12227
         int hops;
4,416✔
12228
         vcode_var_t var = lower_get_var(lu, port, &hops);
4,416✔
12229
         assert(hops == 0);
4,416✔
12230

12231
         if (type_is_homogeneous(tree_type(port)))
4,416✔
12232
            port_reg = emit_load(var);
4,011✔
12233
         else
12234
            port_reg = emit_index(var, VCODE_INVALID_REG);
405✔
12235
      }
12236
      break;
4,416✔
12237
   case P_NAMED:
703✔
12238
      {
12239
         name = tree_name(map);
703✔
12240

12241
         const tree_kind_t kind = tree_kind(name);
703✔
12242
         if (kind == T_CONV_FUNC || kind == T_TYPE_CONV) {
703✔
12243
            tree_t p0 = tree_value(name);
107✔
12244
            out_conv = lower_converter(lu, value_conv ?: value, p0,
107✔
12245
                                       name, PORT_OUT);
12246
            name = p0;
107✔
12247
         }
12248

12249
         tree_t port = tree_ref(name_to_ref(name));
703✔
12250
         mode = tree_subkind(port);
703✔
12251

12252
         if (mode == PORT_ARRAY_VIEW || mode == PORT_RECORD_VIEW) {
703✔
12253
            view = tree_value(port);
18✔
12254

12255
            // Adjust view for partial association
12256
            bool converse = false;
18✔
12257
            for (tree_t it = name; tree_kind(name) == T_RECORD_REF;
18✔
12258
                 it = tree_value(it)) {
×
12259
               tree_t elem = find_element_mode_indication(view, tree_ref(it),
12✔
12260
                                                          &converse);
12261
               assert(elem != NULL);
12✔
12262

12263
               mode = converse_mode(elem, converse);
12✔
12264

12265
               if (mode != PORT_ARRAY_VIEW && mode != PORT_RECORD_VIEW)
12✔
12266
                  break;
12267

12268
               view = tree_value(view);
×
12269
            }
12270
         }
12271

12272
         port_reg = lower_lvalue(lu, name);
703✔
12273
      }
12274
      break;
703✔
12275
   default:
×
12276
      should_not_reach_here();
12277
   }
12278

12279
   if (value_conv != NULL) {
5,119✔
12280
      // Value has conversion function
12281
      in_conv = lower_converter(lu, name, value_conv, value, PORT_IN);
203✔
12282
      value = value_conv;
203✔
12283
   }
12284

12285
   if (mode == PORT_ARRAY_VIEW || mode == PORT_RECORD_VIEW) {
5,119✔
12286
      assert(lower_is_signal_ref(value));
44✔
12287
      vcode_reg_t locus = lower_debug_locus(view);
44✔
12288
      lower_for_each_field_2(lu, tree_type(name), tree_type(value), port_reg,
44✔
12289
                             value_reg, locus, lower_map_view_field_cb, view);
12290
   }
12291
   else if (lower_is_signal_ref(value)) {
5,075✔
12292
      type_t value_type = tree_type(value);
4,342✔
12293
      type_t name_type = tree_type(name);
4,342✔
12294

12295
      vcode_reg_t src_reg = mode == PORT_IN ? value_reg : port_reg;
4,342✔
12296
      vcode_reg_t dst_reg = mode == PORT_IN ? port_reg : value_reg;
4,342✔
12297
      vcode_reg_t conv_func = mode == PORT_IN ? in_conv : out_conv;
4,342✔
12298

12299
      type_t src_type = mode == PORT_IN ? value_type : name_type;
4,342✔
12300
      type_t dst_type = mode == PORT_IN ? name_type : value_type;
4,342✔
12301

12302
      if (conv_func != VCODE_INVALID_REG) {
4,342✔
12303
         vcode_reg_t conv_reg = emit_port_conversion(conv_func, in_conv);
285✔
12304
         lower_convert_signal(lu, dst_reg, dst_type,
285✔
12305
                              conv_reg, emit_convert_out);
12306
         lower_convert_signal(lu, src_reg, src_type,
285✔
12307
                              conv_reg, emit_convert_in);
12308
      }
12309
      else
12310
         lower_map_signal(lu, src_reg, dst_reg, src_type, dst_type, map);
4,057✔
12311
   }
12312
   else if (tree_kind(value) == T_INERTIAL)
733✔
12313
      lower_inertial_actual(lu, name, tree_type(name), port_reg, value);
28✔
12314
   else if (value_reg != VCODE_INVALID_REG) {
705✔
12315
      type_t value_type = tree_type(value);
183✔
12316
      type_t name_type = tree_type(name);
183✔
12317
      lower_map_signal(lu, value_reg, port_reg, value_type, name_type, map);
183✔
12318
   }
12319
}
5,119✔
12320

12321
static void lower_direct_mapped_port(lower_unit_t *lu, driver_set_t *ds,
9,573✔
12322
                                     tree_t block, tree_t map, hset_t *direct,
12323
                                     hset_t **poison, vcode_reg_t src_reg)
12324
{
12325
   tree_t port = NULL;
9,573✔
12326
   int field = -1;
9,573✔
12327
   switch (tree_subkind(map)) {
9,573✔
12328
   case P_POS:
8,843✔
12329
      port = tree_port(block, tree_pos(map));
8,843✔
12330
      break;
8,843✔
12331
   case P_NAMED:
730✔
12332
      {
12333
         tree_t name = tree_name(map);
730✔
12334
         tree_kind_t kind = tree_kind(name);
730✔
12335

12336
         if (kind == T_RECORD_REF) {
730✔
12337
            field = tree_pos(tree_ref(name));
380✔
12338
            name  = tree_value(name);
380✔
12339
            kind  = tree_kind(name);
380✔
12340
         }
12341

12342
         if (kind != T_REF)
730✔
12343
            return;
5,116✔
12344

12345
         port = tree_ref(name);
472✔
12346
      }
12347
      break;
472✔
12348
   }
12349

12350
   assert(tree_kind(port) == T_PORT_DECL);
9,315✔
12351

12352
   tree_t value = tree_value(map);
9,315✔
12353

12354
   if (tree_class(port) == C_VARIABLE) {
9,315✔
12355
      // Variable ports are always directly aliased to the actual
12356
      // variable in the parent scope
12357
      vcode_type_t vtype = lower_type(tree_type(port));
3✔
12358
      vcode_var_t var = emit_var(vtype, vtype, tree_ident(port), 0);
3✔
12359
      lower_put_vcode_obj(port, var, lu);
3✔
12360

12361
      vcode_reg_t src_reg = lower_rvalue(lu, value);
3✔
12362
      emit_store(src_reg, var);
3✔
12363

12364
      hset_insert(direct, map);
3✔
12365
      hset_insert(direct, port);
3✔
12366
      return;
3✔
12367
   }
12368
   else if (tree_subkind(port) != PORT_IN)
9,312✔
12369
      return;    // Not safe in general
12370
   else if (!lower_is_signal_ref(value) || tree_kind(value) == T_TYPE_CONV) {
5,297✔
12371
      if (field != -1) {
528✔
12372
         // We can't use direct mapping for this record element so make
12373
         // sure we don't direct map any other elements of this signal
12374
         if (*poison == NULL)
9✔
12375
            *poison = hset_new(32);
6✔
12376
         hset_insert(*poison, port);
9✔
12377
      }
12378
      return;
528✔
12379
   }
12380
   else if (*poison != NULL && hset_contains(*poison, port))
4,769✔
12381
      return;
12382

12383
   type_t type = tree_type(value);
4,763✔
12384
   type_t port_type = tree_type(port);
4,763✔
12385

12386
   if (type_is_unconstrained(port_type))
4,763✔
12387
      return;   // Not supported for now
12388

12389
   int hops = 0;
4,457✔
12390
   vcode_var_t var = lower_search_vcode_obj(port, lu, &hops);
4,457✔
12391
   assert(var != VCODE_INVALID_VAR);
4,457✔
12392
   assert(hops == 0);
4,457✔
12393

12394
   type_t field_type = port_type;
4,457✔
12395
   if (field != -1) {
4,457✔
12396
      tree_t f = type_field(port_type, field);
23✔
12397
      tree_t cons = type_constraint_for_field(port_type, f);
23✔
12398
      field_type = tree_type(cons ?: f);
41✔
12399
      port_type = tree_type(f);
23✔
12400
   }
12401

12402
   vcode_reg_t bounds_reg = VCODE_INVALID_REG;
4,457✔
12403
   if (!type_const_bounds(field_type))
4,457✔
12404
      bounds_reg = lower_get_type_bounds(lu, field_type);
157✔
12405

12406
   if (type_is_array(type)) {
4,457✔
12407
      vcode_reg_t locus = lower_debug_locus(map);
415✔
12408
      lower_check_array_sizes(lu, field_type, type, bounds_reg, src_reg, locus);
415✔
12409
   }
12410

12411
   if (field != -1) {
4,457✔
12412
      vcode_reg_t ptr_reg = emit_index(var, VCODE_INVALID_REG);
23✔
12413
      vcode_reg_t field_reg = emit_record_ref(ptr_reg, field);
23✔
12414

12415
      if (type_is_record(type))
23✔
12416
         emit_copy(field_reg, src_reg, VCODE_INVALID_REG);
×
12417
      else if (type_is_array(type)) {
23✔
12418
         if (type_is_homogeneous(type)){
9✔
12419
            vcode_reg_t coerce_reg =
9✔
12420
               lower_coerce_arrays(lu, type, port_type, src_reg);
9✔
12421
            emit_store_indirect(coerce_reg, field_reg);
9✔
12422
         }
12423
         else {
12424
            vcode_reg_t data_reg = lower_array_data(src_reg);
×
12425
            vcode_reg_t count_reg = lower_array_total_len(lu, type, src_reg);
×
12426
            emit_copy(field_reg, data_reg, count_reg);
×
12427
         }
12428
      }
12429
      else
12430
         emit_store_indirect(src_reg, field_reg);
14✔
12431
   }
12432
   else if (type_is_record(type)) {
4,434✔
12433
      vcode_reg_t ptr_reg = emit_index(var, VCODE_INVALID_REG);
131✔
12434
      emit_copy(ptr_reg, src_reg, VCODE_INVALID_REG);
131✔
12435
   }
12436
   else if (type_is_array(type)) {
4,303✔
12437
      vcode_reg_t data_reg = lower_array_data(src_reg);
406✔
12438

12439
      if (vcode_reg_kind(data_reg) == VCODE_TYPE_SIGNAL)
406✔
12440
         emit_alias_signal(data_reg, lower_debug_locus(port));
305✔
12441

12442
      if (bounds_reg != VCODE_INVALID_REG) {
406✔
12443
         vcode_reg_t wrap_reg = lower_rewrap(data_reg, bounds_reg);
153✔
12444
         emit_store(wrap_reg, var);
153✔
12445
      }
12446
      else if (!type_is_homogeneous(type)) {
253✔
12447
         vcode_reg_t ptr_reg = emit_index(var, VCODE_INVALID_REG);
7✔
12448
         vcode_reg_t count_reg = lower_array_total_len(lu, type, src_reg);
7✔
12449
         emit_copy(ptr_reg, data_reg, count_reg);
7✔
12450
      }
12451
      else
12452
         emit_store(data_reg, var);
246✔
12453
   }
12454
   else {
12455
      emit_alias_signal(src_reg, lower_debug_locus(port));
3,897✔
12456
      emit_store(src_reg, var);
3,897✔
12457
   }
12458

12459
   hset_insert(direct, map);
4,457✔
12460
   hset_insert(direct, port);
4,457✔
12461
}
12462

12463
static void lower_port_signal(lower_unit_t *lu, tree_t port,
4,739✔
12464
                              vcode_var_t var, vcode_reg_t bounds_reg)
12465
{
12466
   type_t type = tree_type(port);
4,739✔
12467
   type_t value_type = type;
4,739✔
12468

12469
   const port_mode_t mode = tree_subkind(port);
4,739✔
12470
   tree_t view = NULL;
4,739✔
12471
   vcode_reg_t init_reg = VCODE_INVALID_REG;
4,739✔
12472
   if (mode == PORT_RECORD_VIEW || mode == PORT_ARRAY_VIEW) {
4,739✔
12473
      // No explicit initial value
12474
      view = tree_value(port);
50✔
12475
   }
12476
   else if (tree_has_value(port)) {
4,689✔
12477
      tree_t value = tree_value(port);
275✔
12478
      value_type = tree_type(value);
275✔
12479
      init_reg = lower_rvalue(lu, value);
275✔
12480
   }
12481

12482
   sig_flags_t flags = 0;
4,739✔
12483
   if (tree_flags(port) & TREE_F_REGISTER)
4,739✔
12484
      flags |= SIG_F_REGISTER;
×
12485

12486
   // Port signals will need separate driving/effective values if they
12487
   // are inout or have conversion functions.
12488
   if (mode == PORT_INOUT)
4,739✔
12489
      flags |= NET_F_EFFECTIVE | NET_F_INOUT;
258✔
12490

12491
   lower_sub_signals(lu, type, type, value_type, port, view, var,
4,739✔
12492
                     VCODE_INVALID_REG, init_reg, VCODE_INVALID_REG,
12493
                     VCODE_INVALID_REG, flags, bounds_reg);
12494
}
4,739✔
12495

12496
static vcode_reg_t lower_constrain_port(lower_unit_t *lu, tree_t port, int pos,
177✔
12497
                                        tree_t block, vcode_reg_t *map_regs)
12498
{
12499
   vcode_reg_t left_reg = VCODE_INVALID_REG, right_reg = VCODE_INVALID_REG;
177✔
12500
   type_t port_type = tree_type(port);
177✔
12501

12502
   vcode_reg_t rptr_reg = VCODE_INVALID_VAR;
177✔
12503
   if (type_is_record(port_type)) {
177✔
12504
      vcode_type_t vtype = lower_signal_type(port_type);
70✔
12505
      ident_t name = ident_prefix(tree_ident(port), ident_new("cons"), '$');
70✔
12506
      vcode_var_t rec_var = emit_var(vtype, vtype, name, 0);
70✔
12507
      rptr_reg = emit_index(rec_var, VCODE_INVALID_REG);
70✔
12508
   }
12509

12510
   const int nparams = tree_params(block);
177✔
12511
   for (int i = 0; i < nparams; i++) {
1,493✔
12512
      tree_t map = tree_param(block, i), name = NULL;
1,447✔
12513
      switch (tree_subkind(map)) {
1,447✔
12514
      case P_POS:
303✔
12515
         if (tree_pos(map) != pos)
303✔
12516
            continue;
176✔
12517
         break;
12518

12519
      case P_NAMED:
1,144✔
12520
         {
12521
            tree_t ref = name_to_ref((name = tree_name(map)));
1,144✔
12522
            if (ref == NULL || tree_ref(ref) != port)
1,144✔
12523
               continue;
800✔
12524
         }
12525
         break;
12526
      }
12527

12528
      vcode_reg_t bounds_reg;
471✔
12529
      if (map_regs[i] == VCODE_INVALID_REG) {
471✔
12530
         // Has conversion function
12531
         tree_t value = tree_value(map);
3✔
12532
         assert(tree_kind(value) == T_CONV_FUNC);
3✔
12533

12534
         // TODO: lower_get_type_bounds does not support records
12535
         type_t type = tree_type(value);
3✔
12536
         if (type_is_record(type))
3✔
12537
            bounds_reg = lower_default_value(lu, type, VCODE_INVALID_REG);
3✔
12538
         else
12539
            bounds_reg = lower_get_type_bounds(lu, type);
×
12540
      }
12541
      else
12542
         bounds_reg = map_regs[i];
12543

12544
      if (name == NULL || tree_kind(name) == T_REF) {
471✔
12545
         type_t value_type = tree_type(tree_value(map));
131✔
12546
         if (type_is_array(port_type))
131✔
12547
            return lower_coerce_arrays(lu, value_type, port_type, bounds_reg);
94✔
12548
         else
12549
            return bounds_reg;
12550
      }
12551

12552
      switch (tree_kind(name)) {
340✔
12553
      case T_ARRAY_REF:
16✔
12554
         {
12555
            // The name is of the form X(I) so use this to derive
12556
            // the bounds of a single-element array
12557
            tree_t value = tree_value(tree_param(name, 0));
16✔
12558

12559
            if (left_reg == VCODE_INVALID_REG)
16✔
12560
               left_reg = right_reg = lower_rvalue(lu, value);
13✔
12561
            else {
12562
               vcode_reg_t value_reg = lower_rvalue(lu, value);
3✔
12563
               vcode_reg_t below_reg =
3✔
12564
                  emit_cmp(VCODE_CMP_LT, value_reg, left_reg);
3✔
12565
               vcode_reg_t above_reg =
3✔
12566
                  emit_cmp(VCODE_CMP_GT, value_reg, right_reg);
3✔
12567

12568
               left_reg = emit_select(below_reg, value_reg, left_reg);
3✔
12569
               right_reg = emit_select(above_reg, value_reg, right_reg);
3✔
12570
            }
12571
         }
12572
         break;
12573

12574
      case T_RECORD_REF:
324✔
12575
         {
12576
            tree_t f = tree_ref(name);
324✔
12577
            assert(tree_kind(f) == T_FIELD_DECL);
324✔
12578

12579
            type_t ftype = tree_type(f);
324✔
12580
            if (!type_is_unconstrained(ftype))
324✔
12581
               continue;
216✔
12582

12583
            type_t value_type = tree_type(tree_value(map));
108✔
12584

12585
            vcode_reg_t value_reg;
108✔
12586
            if (type_is_array(ftype))
108✔
12587
               value_reg = lower_coerce_arrays(lu, value_type, ftype,
108✔
12588
                                               bounds_reg);
12589
            else
12590
               value_reg = bounds_reg;
12591

12592
            vcode_reg_t field_reg = emit_record_ref(rptr_reg, tree_pos(f));
108✔
12593
            emit_store_indirect(value_reg, field_reg);
108✔
12594
         }
12595
         break;
108✔
12596

12597
      default:
×
12598
         // TODO: this should be an assert and a proper error generated
12599
         //       during sem/elab
12600
         fatal_at(tree_loc(name), "invalid formal name for unconstrained "
×
12601
                 "port %s", istr(tree_ident(port)));
12602
      }
12603
   }
12604

12605
   if (rptr_reg != VCODE_INVALID_REG)
46✔
12606
      return rptr_reg;
12607
   else {
12608
      assert(left_reg != VCODE_INVALID_REG);
13✔
12609

12610
      type_t elem = type_elem_recur(port_type);
13✔
12611
      vcode_type_t velem = lower_type(elem);
13✔
12612

12613
      vcode_reg_t dir_reg = emit_const(vtype_bool(), RANGE_TO);
13✔
12614
      vcode_reg_t null_reg = emit_null(vtype_pointer(velem));
13✔
12615
      vcode_dim_t dims[] = {
13✔
12616
         { left_reg, right_reg, dir_reg },
12617
      };
12618
      return emit_wrap(null_reg, dims, 1);
13✔
12619
   }
12620
}
12621

12622
static vcode_reg_t lower_open_port_map(lower_unit_t *lu, tree_t block, tree_t p)
547✔
12623
{
12624
   tree_t port;
547✔
12625
   if (tree_subkind(p) == P_NAMED) {
547✔
12626
      tree_t name = tree_name(p);
7✔
12627
      if (tree_kind(name) == T_REF)
7✔
12628
         port = tree_ref(name);
1✔
12629
      else {
12630
         // VHDL-2019 partially connected vectors in port map
12631
         assert(standard() >= STD_19);
6✔
12632
         return VCODE_INVALID_REG;
12633
      }
12634
   }
12635
   else
12636
      port = tree_port(block, tree_pos(p));
540✔
12637

12638
   if (tree_has_value(port)) {
541✔
12639
      tree_t def = tree_value(port);
25✔
12640
      vcode_reg_t def_reg = lower_rvalue(lu, def);
25✔
12641

12642
      type_t port_type = tree_type(port);
25✔
12643
      if (type_is_array(port_type))
25✔
12644
         return lower_coerce_arrays(lu, tree_type(def), port_type, def_reg);
14✔
12645

12646
      return def_reg;
12647
   }
12648
   else
12649
      return VCODE_INVALID_REG;
12650
}
12651

12652
static void lower_ports(lower_unit_t *lu, driver_set_t *ds, tree_t block)
9,410✔
12653
{
12654
   const int nports = tree_ports(block);
9,410✔
12655
   const int nparams = tree_params(block);
9,410✔
12656

12657
   hset_t *direct = hset_new(nports * 2), *poison = NULL;
9,410✔
12658
   vcode_reg_t *map_regs LOCAL = xmalloc_array(nparams, sizeof(vcode_reg_t));
18,820✔
12659
   vcode_var_t *port_vars LOCAL = xmalloc_array(nports, sizeof(vcode_var_t));
18,820✔
12660

12661
   for (int i = 0; i < nparams; i++) {
18,989✔
12662
      tree_t p = tree_param(block, i);
9,579✔
12663

12664
      tree_t value = tree_value(p);
9,579✔
12665
      const tree_kind_t kind = tree_kind(value);
9,579✔
12666
      if (kind == T_TYPE_CONV || kind == T_CONV_FUNC || kind == T_INERTIAL)
9,579✔
12667
         map_regs[i] = VCODE_INVALID_REG;
231✔
12668
      else if (lower_is_signal_ref(value))
9,348✔
12669
         map_regs[i] = lower_lvalue(lu, value);
8,640✔
12670
      else if (tree_kind(value) == T_OPEN)
708✔
12671
         map_regs[i] = lower_open_port_map(lu, block, p);
547✔
12672
      else
12673
         map_regs[i] = lower_rvalue(lu, value);
161✔
12674
   }
12675

12676
   for (int i = 0; i < nports; i++) {
18,595✔
12677
      tree_t port = tree_port(block, i);
9,185✔
12678
      type_t type = tree_type(port);
9,185✔
12679

12680
      vcode_type_t vtype = lower_signal_type(type);
9,185✔
12681
      port_vars[i] = emit_var(vtype, vtype, tree_ident(port), VAR_SIGNAL);
9,185✔
12682
      lower_put_vcode_obj(port, port_vars[i], lu);
9,185✔
12683
   }
12684

12685
   if (!opt_get_int(OPT_NO_COLLAPSE)) {
9,410✔
12686
      // Filter out "direct mapped" inputs which can be aliased to
12687
      // signals in the scope above
12688
      for (int i = 0; i < nparams; i++)
18,977✔
12689
         lower_direct_mapped_port(lu, ds, block, tree_param(block, i), direct,
9,573✔
12690
                                  &poison, map_regs[i]);
9,573✔
12691
   }
12692

12693
   for (int i = 0; i < nports; i++) {
18,595✔
12694
      tree_t port = tree_port(block, i);
9,185✔
12695
      type_t type = tree_type(port);
9,185✔
12696

12697
      vcode_reg_t bounds_reg = VCODE_INVALID_REG;
9,185✔
12698
      if (type_is_unconstrained(type))
9,185✔
12699
         bounds_reg = lower_constrain_port(lu, port, i, block, map_regs);
177✔
12700
      else if (!type_const_bounds(type))
9,008✔
12701
         bounds_reg = lower_get_type_bounds(lu, type);
539✔
12702

12703
      if (!hset_contains(direct, port))
9,185✔
12704
         lower_port_signal(lu, port, port_vars[i], bounds_reg);
4,739✔
12705
      else if (poison != NULL && hset_contains(poison, port))
4,446✔
12706
         lower_port_signal(lu, port, port_vars[i], bounds_reg);
×
12707
   }
12708

12709
   for (int i = 0; i < nparams; i++) {
18,989✔
12710
      tree_t map = tree_param(block, i);
9,579✔
12711
      if (!hset_contains(direct, map))
9,579✔
12712
         lower_port_map(lu, block, map, map_regs[i]);
5,119✔
12713
      else if (poison != NULL && tree_subkind(map) == P_NAMED) {
4,460✔
12714
         tree_t port = tree_ref(name_to_ref(tree_name(map)));
×
12715
         if (hset_contains(poison, port))
×
12716
            lower_port_map(lu, block, map, map_regs[i]);
×
12717
      }
12718
   }
12719

12720
   if (cover_enabled(lu->cover, COVER_MASK_TOGGLE)) {
9,410✔
12721
      for (int i = 0; i < nports; i++) {
382✔
12722
         tree_t p = tree_port(block, i);
112✔
12723
         PUSH_COVER_SCOPE(lu, p);
224✔
12724
         lower_toggle_coverage(lu, p);
112✔
12725
      }
12726
   }
12727

12728
   hset_free(direct);
9,410✔
12729
   if (poison != NULL)
9,410✔
12730
      hset_free(poison);
6✔
12731
}
9,410✔
12732

12733
static void lower_check_generic_constraint(lower_unit_t *lu, tree_t expect,
17✔
12734
                                           tree_t generic, vcode_reg_t locus)
12735
{
12736
   vcode_reg_t expect_reg = lower_rvalue(lu, expect);
17✔
12737
   if (expect_reg == VCODE_INVALID_REG)
17✔
12738
      return;   // Was OPEN
1✔
12739

12740
   int hops;
16✔
12741
   vcode_var_t actual_var = lower_get_var(lu, generic, &hops);
16✔
12742
   assert(actual_var != VCODE_INVALID_VAR);
16✔
12743
   assert(hops == 0);
16✔
12744

12745
   type_t type = tree_type(expect);
16✔
12746

12747
   vcode_reg_t test_reg;
16✔
12748
   if (type_is_scalar(type)) {
16✔
12749
      vcode_reg_t actual_reg = emit_load(actual_var);
11✔
12750
      test_reg = emit_cmp(VCODE_CMP_EQ, expect_reg, actual_reg);
11✔
12751
   }
12752
   else {
12753
      vcode_reg_t actual_reg;
5✔
12754
      if (vtype_kind(vcode_var_type(actual_var)) == VCODE_TYPE_UARRAY)
5✔
12755
         actual_reg = emit_load(actual_var);
×
12756
      else
12757
         actual_reg = emit_index(actual_var, VCODE_INVALID_REG);
5✔
12758

12759
      vcode_reg_t left_reg = actual_reg, right_reg = expect_reg;
5✔
12760
      if (type_is_array(type)) {
5✔
12761
         left_reg = lower_wrap(lu, type, actual_reg);
3✔
12762
         right_reg = lower_wrap(lu, type, expect_reg);
3✔
12763
      }
12764

12765
      ident_t func = lower_predef_func_name(type, "=");
5✔
12766
      vcode_reg_t context_reg = lower_context_for_call(lu, func);
5✔
12767
      vcode_reg_t args[] = { context_reg, left_reg, right_reg };
5✔
12768
      vcode_type_t vbool = vtype_bool();
5✔
12769
      test_reg = emit_fcall(func, vbool, vbool, args, 3);
5✔
12770
   }
12771

12772
   vcode_type_t vseverity = vtype_int(0, SEVERITY_FAILURE - 1);
16✔
12773
   vcode_reg_t error_reg = emit_const(vseverity, SEVERITY_ERROR);
16✔
12774

12775
   emit_assert(test_reg, VCODE_INVALID_REG, VCODE_INVALID_REG, error_reg,
16✔
12776
               locus, VCODE_INVALID_REG, VCODE_INVALID_REG);
12777
}
12778

12779
static void lower_pack_inst_generics(lower_unit_t *lu, tree_t inst, tree_t map)
80✔
12780
{
12781
   int hops = 0;
80✔
12782
   vcode_reg_t var = lower_search_vcode_obj(inst, lu, &hops);
80✔
12783

12784
   vcode_reg_t context;
80✔
12785
   if (var == VCODE_INVALID_VAR)
80✔
12786
      context = emit_link_package(tree_ident(inst));
14✔
12787
   else
12788
      context = emit_load_indirect(emit_var_upref(hops, var));
66✔
12789

12790
   const int ngenerics = tree_generics(inst);
80✔
12791
   for (int i = 0; i < ngenerics; i++) {
357✔
12792
      tree_t g = tree_generic(inst, i);
277✔
12793
      if (tree_class(g) != C_CONSTANT)
277✔
12794
         continue;
162✔
12795

12796
      type_t type = tree_type(g);
115✔
12797
      vcode_type_t vtype = lower_type(type);
115✔
12798
      vcode_type_t vbounds = lower_bounds(type);
115✔
12799

12800
      ident_t name = tree_ident(g);
115✔
12801
      vcode_var_t var = emit_var(vtype, vbounds, name, VAR_CONST);
115✔
12802

12803
      vcode_reg_t ptr_reg = emit_link_var(context, name, vtype);
115✔
12804

12805
      if (type_is_scalar(type))
115✔
12806
         emit_store(emit_load_indirect(ptr_reg), var);
109✔
12807
      else if (type_is_array(type)) {
6✔
12808
         if (type_const_bounds(type)) {
4✔
12809
            vcode_reg_t count_reg = lower_array_total_len(lu, type, ptr_reg);
4✔
12810
            vcode_reg_t dest_reg = emit_index(var, VCODE_INVALID_REG);
4✔
12811
            vcode_reg_t src_reg = lower_array_data(ptr_reg);
4✔
12812
            emit_copy(dest_reg, src_reg, count_reg);
4✔
12813
         }
12814
      }
12815
      else {
12816
         vcode_reg_t dest_reg = emit_index(var, VCODE_INVALID_REG);
2✔
12817
         emit_copy(dest_reg, ptr_reg, VCODE_INVALID_REG);
2✔
12818
      }
12819

12820
      lower_put_vcode_obj(g, var, lu);
115✔
12821

12822
      tree_t g0 = tree_generic(tree_ref(inst), i);
115✔
12823
      lower_put_vcode_obj(g0, var, lu);
115✔
12824
   }
12825

12826
   switch (tree_subkind(map)) {
80✔
12827
   case PACKAGE_MAP_MATCHING:
6✔
12828
      {
12829
         const int count = tree_genmaps(map);
6✔
12830
         for (int i = 0; i < count; i++) {
16✔
12831
            tree_t m = tree_genmap(map, i);
10✔
12832
            assert(tree_subkind(m) == P_POS);
10✔
12833

12834
            tree_t g = tree_generic(inst, i);
10✔
12835

12836
            vcode_reg_t locus = lower_debug_locus(m);
10✔
12837
            lower_check_generic_constraint(lu, tree_value(m), g, locus);
10✔
12838
         }
12839
      }
12840
      break;
12841

12842
   case PACKAGE_MAP_DEFAULT:
12843
      for (int i = 0; i < ngenerics; i++) {
10✔
12844
         tree_t g = tree_generic(inst, i);
7✔
12845
         tree_t g0 = tree_generic(tree_ref(map), i);
7✔
12846

12847
         vcode_reg_t locus = lower_debug_locus(map);
7✔
12848
         lower_check_generic_constraint(lu, tree_value(g0), g, locus);
7✔
12849
      }
12850
      break;
12851

12852
   case PACKAGE_MAP_BOX:
12853
      break;
12854
   }
12855
}
80✔
12856

12857
static void lower_generics(lower_unit_t *lu, tree_t block, tree_t primary)
10,124✔
12858
{
12859
   const int ngenerics = tree_generics(block);
10,124✔
12860
   assert(ngenerics == tree_genmaps(block));
10,124✔
12861

12862
   for (int i = 0; i < ngenerics; i++) {
16,608✔
12863
      tree_t g = tree_generic(block, i);
6,484✔
12864
      tree_t m = tree_genmap(block, i);
6,484✔
12865
      assert(tree_subkind(m) == P_POS);
6,484✔
12866

12867
      const class_t class = tree_class(g);
6,484✔
12868
      if (class == C_PACKAGE) {
6,484✔
12869
         // Make generics in a package instance passed via a package
12870
         // interface generic available
12871
         tree_t map = tree_value(g);
80✔
12872
         assert(tree_kind(map) == T_PACKAGE_MAP);
80✔
12873

12874
         tree_t inst = tree_ref(tree_value(m));
80✔
12875
         assert(tree_kind(inst) == T_PACK_INST);
80✔
12876

12877
         lower_pack_inst_generics(lu, inst, map);
80✔
12878
      }
12879

12880
      if (class != C_CONSTANT)
6,484✔
12881
         continue;   // Skip type generics, etc.
1,450✔
12882

12883
      type_t type = tree_type(g);
5,034✔
12884

12885
      vcode_type_t vtype = lower_type(type);
5,034✔
12886
      vcode_type_t vbounds = lower_bounds(type);
5,034✔
12887
      vcode_var_t var = emit_var(vtype, vbounds, tree_ident(g), VAR_CONST);
5,034✔
12888

12889
      vcode_reg_t mem_reg = VCODE_INVALID_REG, count_reg = VCODE_INVALID_REG;
5,034✔
12890

12891
      const bool is_array = type_is_array(type);
5,034✔
12892

12893
      if (is_array && type_const_bounds(type)) {
5,034✔
12894
         mem_reg = emit_index(var, VCODE_INVALID_REG);
166✔
12895
         count_reg = lower_array_total_len(lu, type, VCODE_INVALID_REG);
166✔
12896
      }
12897
      else if (type_is_record(type))
4,868✔
12898
         mem_reg = emit_index(var, VCODE_INVALID_REG);
82✔
12899

12900
      tree_t value = tree_value(m);
5,034✔
12901
      vcode_reg_t value_reg;
5,034✔
12902
      switch (tree_kind(value)) {
5,034✔
12903
      case T_AGGREGATE:
17✔
12904
         value_reg = lower_aggregate(lu, value, mem_reg);
17✔
12905
         break;
17✔
12906
      case T_OPEN:
192✔
12907
         assert(tree_has_value(g));
192✔
12908
         value = tree_value(g);
192✔
12909
         // Fall-through
12910
      default:
5,017✔
12911
         value_reg = lower_rvalue(lu, value);
5,017✔
12912
         break;
5,017✔
12913
      }
12914

12915
      if (is_array && mem_reg != VCODE_INVALID_REG) {
5,034✔
12916
         vcode_reg_t locus = lower_debug_locus(g);
166✔
12917
         lower_check_array_sizes(lu, type, tree_type(value),
166✔
12918
                                 VCODE_INVALID_REG, value_reg, locus);
12919
      }
12920
      else if (type_is_scalar(type))
4,868✔
12921
         lower_check_scalar_bounds(lu, value_reg, type, value, g);
4,596✔
12922

12923
      if (mem_reg != VCODE_INVALID_REG)
5,034✔
12924
         emit_copy(mem_reg, lower_array_data(value_reg), count_reg);
248✔
12925
      else if (is_array) {
4,786✔
12926
         vcode_reg_t wrap_reg = lower_coerce_arrays(lu, tree_type(value),
190✔
12927
                                                    type, value_reg);
12928
         emit_store(wrap_reg, var);
190✔
12929
      }
12930
      else
12931
         emit_store(value_reg, var);
4,596✔
12932

12933
      lower_put_vcode_obj(g, var, lu);
5,034✔
12934

12935
      if (primary != NULL) {
5,034✔
12936
         // The generic object in the instance may have been copied in
12937
         // which case we also need to associate the variable with the
12938
         // original generic in the primary unit
12939
         tree_t g2 = tree_generic(primary, i);
2,434✔
12940
         assert(tree_ident(g2) == tree_ident(g));
2,434✔
12941
         if (g2 != g) lower_put_vcode_obj(g2, var, lu);
2,434✔
12942
      }
12943
   }
12944
}
10,124✔
12945

12946
static void lower_deps_cb(ident_t unit_name, void *__ctx)
70,330✔
12947
{
12948
   lower_unit_t *lu = __ctx;
70,330✔
12949

12950
   object_t *obj = lib_load_handler(unit_name);
70,330✔
12951

12952
   tree_t unit = tree_from_object(obj);
70,330✔
12953
   if (unit == NULL)
70,330✔
12954
      return;
12955

12956
   const tree_kind_t kind = tree_kind(unit);
70,199✔
12957
   if (kind != T_ENTITY && unit_name == lu->name)
70,199✔
12958
      return;   // Package body depends on package
12959

12960
   if (kind == T_PACKAGE && standard() >= STD_08) {
69,021✔
12961
      if (is_uninstantiated_package(unit))
9,029✔
12962
         return;   // No code generated for uninstantiated packages
12963
   }
12964

12965
   if (kind == T_PACKAGE || kind == T_PACK_INST)
68,604✔
12966
      emit_package_init(unit_name, VCODE_INVALID_REG);
27,470✔
12967
}
12968

12969
static void lower_dependencies(lower_unit_t *lu, tree_t unit)
11,041✔
12970
{
12971
   tree_walk_deps(unit, lower_deps_cb, lu);
24,259✔
12972

12973
   switch (tree_kind(unit)) {
24,259✔
12974
   case T_ARCH:
7,198✔
12975
   case T_PACK_BODY:
12976
      lower_dependencies(lu, tree_primary(unit));
7,198✔
12977
      break;
7,198✔
12978
   case T_BLOCK:
9,410✔
12979
      {
12980
         tree_t hier = tree_decl(unit, 0);
9,410✔
12981
         assert(tree_kind(hier) == T_HIER);
9,410✔
12982

12983
         tree_t src = tree_ref(hier);
9,410✔
12984
         if (is_design_unit(src))
9,410✔
12985
            lower_dependencies(lu, src);
12986
      }
12987
      break;
12988
   default:
12989
      break;
12990
   }
12991
}
11,041✔
12992

12993
static bool lower_push_package_scope(tree_t pack)
2,801✔
12994
{
12995
   const int ndecls = tree_decls(pack);
2,801✔
12996
   for (int i = 0; i < ndecls; i++) {
191,563✔
12997
      tree_t d = tree_decl(pack, i);
188,807✔
12998
      if (tree_kind(d) == T_SIGNAL_DECL) {
188,807✔
12999
         vcode_reg_t locus = lower_debug_locus(pack);
45✔
13000
         emit_package_scope(locus);
45✔
13001
         return true;
45✔
13002
      }
13003
   }
13004

13005
   return false;
13006
}
13007

13008
static void lower_cache_instance_name(lower_unit_t *lu, attr_kind_t which)
812✔
13009
{
13010
   ident_t name =
812✔
13011
      well_known(which == ATTR_INSTANCE_NAME ? W_INSTANCE_NAME : W_PATH_NAME);
1,265✔
13012

13013
   vcode_type_t vchar = vtype_char();
812✔
13014
   vcode_type_t vstring = vtype_uarray(1, vchar, vchar);
812✔
13015
   vcode_var_t var = emit_var(vstring, vchar, name, VAR_CONST);
812✔
13016
   vcode_reg_t kind_reg = emit_const(vtype_offset(), which);
812✔
13017
   vcode_reg_t str_reg = emit_instance_name(kind_reg);
812✔
13018
   emit_store(str_reg, var);
812✔
13019

13020
   lower_put_vcode_obj(name, var, lu);
812✔
13021
}
812✔
13022

13023
static void lower_pack_body(lower_unit_t *lu, object_t *obj)
1,178✔
13024
{
13025
   tree_t body = tree_from_object(obj);
1,178✔
13026

13027
   tree_t pack = tree_primary(body);
1,178✔
13028
   assert(!is_uninstantiated_package(pack));
1,178✔
13029

13030
   if (standard() >= STD_08 && is_well_known(lu->name) == W_IEEE_1164) {
1,178✔
13031
      // VHDL-2008 and later matching operators on STD_LOGIC are
13032
      // implemented in the support package
13033
      ident_t ieee_support = ident_new("NVC.IEEE_SUPPORT");
35✔
13034
      emit_package_init(ieee_support, VCODE_INVALID_REG);
35✔
13035
   }
13036

13037
   tree_global_flags_t gflags = tree_global_flags(body);
1,178✔
13038
   gflags |= tree_global_flags(pack);
1,178✔
13039

13040
   if (gflags & TREE_GF_INSTANCE_NAME)
1,178✔
13041
      lower_cache_instance_name(lu, ATTR_INSTANCE_NAME);
20✔
13042

13043
   if (gflags & TREE_GF_PATH_NAME)
1,178✔
13044
      lower_cache_instance_name(lu, ATTR_PATH_NAME);
14✔
13045

13046
   if (gflags & TREE_GF_EXTERNAL_NAME) {
1,178✔
13047
      tree_visit_only(pack, lower_external_name_cache, lu, T_EXTERNAL_NAME);
3✔
13048
      tree_visit_only(body, lower_external_name_cache, lu, T_EXTERNAL_NAME);
3✔
13049
   }
13050

13051
   lower_dependencies(lu, body);
1,178✔
13052

13053
   const bool has_scope =
2,356✔
13054
      lower_push_package_scope(pack) || lower_push_package_scope(body);
1,178✔
13055

13056
   lower_decls(lu, pack);
1,178✔
13057
   lower_decls(lu, body);
1,178✔
13058

13059
   if (has_scope)
1,178✔
13060
      emit_pop_scope();
8✔
13061

13062
   emit_return(VCODE_INVALID_REG);
1,178✔
13063
}
1,178✔
13064

13065
static void lower_package(lower_unit_t *lu, object_t *obj)
453✔
13066
{
13067
   tree_t pack = tree_from_object(obj);
453✔
13068
   assert(!is_uninstantiated_package(pack));
453✔
13069

13070
   const tree_global_flags_t gflags = tree_global_flags(pack);
453✔
13071

13072
   if (gflags & TREE_GF_INSTANCE_NAME)
453✔
13073
      lower_cache_instance_name(lu, ATTR_INSTANCE_NAME);
11✔
13074

13075
   if (gflags & TREE_GF_PATH_NAME)
453✔
13076
      lower_cache_instance_name(lu, ATTR_PATH_NAME);
3✔
13077

13078
   if (gflags & TREE_GF_EXTERNAL_NAME)
453✔
13079
      tree_visit_only(pack, lower_external_name_cache, lu, T_EXTERNAL_NAME);
1✔
13080

13081
   lower_dependencies(lu, pack);
453✔
13082

13083
   const bool has_scope = lower_push_package_scope(pack);
453✔
13084

13085
   lower_generics(lu, pack, NULL);
453✔
13086
   lower_decls(lu, pack);
453✔
13087

13088
   if (has_scope)
453✔
13089
      emit_pop_scope();
37✔
13090

13091
   emit_return(VCODE_INVALID_REG);
453✔
13092
}
453✔
13093

13094
vcode_reg_t lower_lvalue(lower_unit_t *lu, tree_t expr)
49,178✔
13095
{
13096
   return lower_expr(lu, expr, EXPR_LVALUE);
49,178✔
13097
}
13098

13099
vcode_reg_t lower_rvalue(lower_unit_t *lu, tree_t expr)
448,641✔
13100
{
13101
   vcode_reg_t reg = lower_expr(lu, expr, EXPR_RVALUE);
448,641✔
13102
   if (reg == VCODE_INVALID_REG)
448,641✔
13103
      return reg;
13104

13105
   for (;;) {
461,342✔
13106
      switch (vcode_reg_kind(reg)) {
461,342✔
13107
      case VCODE_TYPE_SIGNAL:
11,875✔
13108
         reg = lower_resolved(lu, tree_type(expr), reg);
11,875✔
13109
         continue;
11,875✔
13110
      case VCODE_TYPE_POINTER:
57,000✔
13111
         {
13112
            type_t type = tree_type(expr);
57,000✔
13113
            if (lower_have_signal(reg)) {
57,000✔
13114
               reg = lower_resolved(lu, tree_type(expr), reg);
827✔
13115
               continue;
827✔
13116
            }
13117
            else if (!type_is_composite(type))
56,173✔
13118
               return emit_load_indirect(reg);
19,078✔
13119
            else
13120
               return reg;
13121
         }
13122
      case VCODE_TYPE_UARRAY:
44,812✔
13123
         if (lower_have_signal(reg))
44,812✔
13124
            return lower_resolved(lu, tree_type(expr), reg);
497✔
13125
         else
13126
            return reg;
13127
      default:
13128
         return reg;
13129
      }
13130
   }
13131
}
13132

13133
vcode_unit_t lower_case_generate_thunk(lower_unit_t *parent, tree_t t)
9✔
13134
{
13135
   // TODO: this should really be in eval.c
13136

13137
   vcode_unit_t context = parent ? parent->vunit : NULL;
9✔
13138
   vcode_unit_t thunk = emit_thunk(NULL, tree_to_object(t), context);
9✔
13139
   lower_unit_t *lu = lower_unit_new(parent->registry, parent, thunk, NULL, NULL);
9✔
13140

13141
   vcode_type_t vbool = vtype_bool();
9✔
13142
   vcode_type_t vint = vtype_int(INT32_MIN, INT32_MAX);
9✔
13143
   vcode_set_result(vint);
9✔
13144

13145
   if (parent != NULL) {
9✔
13146
      vcode_type_t vcontext = vtype_context(parent->name);
9✔
13147
      emit_param(vcontext, vcontext, ident_new("context"));
9✔
13148
   }
13149

13150
   tree_t value = tree_value(t);
9✔
13151
   type_t type = tree_type(value);
9✔
13152

13153
   ident_t cmp_func = NULL;
9✔
13154
   if (!type_is_scalar(type))
9✔
13155
      cmp_func = lower_predef_func_name(tree_type(value), "=");
9✔
13156

13157
   vcode_reg_t value_reg = lower_rvalue(lu, value);
9✔
13158

13159
   if (cmp_func != NULL)
9✔
13160
      value_reg = lower_wrap(lu, type, value_reg);
9✔
13161

13162
   const int nstmts = tree_stmts(t);
9✔
13163
   for (int i = 0; i < nstmts; i++) {
45✔
13164
      tree_t alt = tree_stmt(t, i);
36✔
13165

13166
      const int nassocs = tree_assocs(alt);
36✔
13167
      for (int j = 0; j < nassocs; j++) {
72✔
13168
         tree_t a = tree_assoc(alt, j);
36✔
13169
         switch (tree_subkind(a)) {
36✔
13170
         case A_NAMED:
27✔
13171
            {
13172
               tree_t name = tree_name(a);
27✔
13173
               vcode_reg_t name_reg = lower_rvalue(lu, name);
27✔
13174
               vcode_block_t match_bb = emit_block();
27✔
13175
               vcode_block_t skip_bb = emit_block();
27✔
13176

13177
               if (cmp_func != NULL) {
27✔
13178
                  if (vcode_reg_kind(name_reg) != VCODE_TYPE_UARRAY)
27✔
13179
                     name_reg = lower_wrap(lu, tree_type(name), name_reg);
27✔
13180

13181
                  vcode_reg_t context_reg =
27✔
13182
                     lower_context_for_call(lu, cmp_func);
27✔
13183
                  vcode_reg_t args[] = { context_reg, name_reg, value_reg };
27✔
13184
                  vcode_reg_t eq_reg = emit_fcall(cmp_func, vbool, vbool,
27✔
13185
                                                  args, 3);
13186
                  emit_cond(eq_reg, match_bb, skip_bb);
27✔
13187
               }
13188
               else {
13189
                  vcode_reg_t eq_reg =
×
13190
                     emit_cmp(VCODE_CMP_EQ, name_reg, value_reg);
×
13191
                  emit_cond(eq_reg, match_bb, skip_bb);
×
13192
               }
13193

13194
               vcode_select_block(match_bb);
27✔
13195
               emit_return(emit_const(vint, i));
27✔
13196

13197
               vcode_select_block(skip_bb);
27✔
13198
            }
13199
            break;
27✔
13200

13201
         case A_OTHERS:
9✔
13202
            emit_return(emit_const(vint, i));
9✔
13203
            break;
9✔
13204

13205
         default:
×
13206
            fatal_at(tree_loc(a), "sorry, this form of choice is not "
×
13207
                     "yet supported");
13208
         }
13209
      }
13210
   }
13211

13212
   if (!vcode_block_finished())
9✔
13213
      emit_return(emit_const(vint, -1));
×
13214

13215
   lower_finished(lu, NULL);
9✔
13216
   lower_unit_free(lu);
9✔
13217

13218
   return thunk;
9✔
13219
}
13220

13221
vcode_unit_t lower_thunk(unit_registry_t *registry, tree_t t,
12,372✔
13222
                         lower_unit_t *parent)
13223
{
13224
   tree_t container = primary_unit_of(tree_container(t));
12,372✔
13225

13226
   assert(parent == NULL || parent->registry == registry);
12,372✔
13227

13228
   vcode_unit_t context = parent ? parent->vunit : NULL;
12,372✔
13229
   vcode_unit_t thunk = emit_thunk(NULL, tree_to_object(t), context);
12,372✔
13230
   lower_unit_t *lu = lower_unit_new(registry, parent, thunk, NULL, container);
12,372✔
13231

13232
   type_t to_type = tree_type(t), from_type = to_type;
12,372✔
13233

13234
   vcode_type_t vtype = VCODE_INVALID_TYPE;
12,372✔
13235
   switch (tree_kind(t)) {
12,372✔
13236
   case T_FCALL:
9,982✔
13237
      from_type = tree_type(tree_ref(t));
9,982✔
13238
      vtype = lower_func_result_type(type_result(from_type));
9,982✔
13239
      break;
9,982✔
13240
   case T_ATTR_REF:
68✔
13241
      vtype = lower_type(to_type);
68✔
13242
      break;
68✔
13243
   default:
2,322✔
13244
      vtype = lower_func_result_type(to_type);
2,322✔
13245
      break;
2,322✔
13246
   }
13247

13248
   vcode_set_result(vtype);
12,372✔
13249

13250
   if (parent != NULL) {
12,372✔
13251
      vcode_type_t vcontext = vtype_context(parent->name);
907✔
13252
      emit_param(vcontext, vcontext, ident_new("context"));
907✔
13253
   }
13254

13255
   vcode_reg_t result_reg = lower_rvalue(lu, t);
12,372✔
13256

13257
   if (type_is_scalar(tree_type(t)))
12,372✔
13258
      emit_return(emit_cast(vtype, vtype, result_reg));
12,103✔
13259
   else if (type_is_array(to_type))
269✔
13260
      emit_return(lower_coerce_arrays(lu, from_type, to_type, result_reg));
269✔
13261
   else
13262
      emit_return(result_reg);
×
13263

13264
   lower_finished(lu, NULL);
12,372✔
13265
   lower_unit_free(lu);
12,372✔
13266

13267
   if (vcode_unit_has_undefined(thunk)) {
12,372✔
13268
      vcode_unit_unref(thunk);
1,094✔
13269
      return NULL;
1,094✔
13270
   }
13271

13272
   vcode_close();
11,278✔
13273
   return thunk;
11,278✔
13274
}
13275

13276
lower_unit_t *lower_instance(unit_registry_t *ur, lower_unit_t *parent,
9,410✔
13277
                             vcode_unit_t shape, driver_set_t *ds,
13278
                             cover_data_t *cover, tree_t block)
13279
{
13280
   assert(tree_kind(block) == T_BLOCK);
9,410✔
13281

13282
   vcode_select_unit(parent ? parent->vunit : NULL);
9,410✔
13283

13284
   ident_t prefix = parent ? parent->name : lib_name(lib_work());
9,410✔
13285
   ident_t label = tree_ident(block);
9,410✔
13286
   ident_t name = ident_prefix(prefix, label, '.');
9,410✔
13287

13288
   vcode_unit_t vu = emit_instance(name, tree_to_object(block),
9,410✔
13289
                                   parent ? parent->vunit : NULL);
13290

13291
   tree_t hier = tree_decl(block, 0);
9,410✔
13292
   assert(tree_kind(hier) == T_HIER);
9,410✔
13293

13294
   tree_t unit = tree_ref(hier), primary = NULL;
9,410✔
13295
   if (is_design_unit(unit))
9,410✔
13296
      primary = primary_unit_of(unit);
6,020✔
13297

13298
   // Do not create coverage scopes for the implicit block from a
13299
   // component instantiation
13300
   if (cover != NULL && tree_kind(unit) == T_COMPONENT)
9,410✔
13301
      cover = NULL;
6✔
13302

13303
   lower_unit_t *lu = lower_unit_new(ur, parent, vu, cover, block);
9,410✔
13304
   unit_registry_put(ur, lu);
9,410✔
13305

13306
   if (cover != NULL) {
9,410✔
13307
      if (parent == NULL)
329✔
13308
         lu->cscope = cover_create_instance(cover, NULL, block, unit);
125✔
13309
      else if (parent != NULL && parent->cover == NULL) {
204✔
13310
         // Collapse this coverage scope with the block for the
13311
         // component above
13312
         assert(tree_subkind(tree_decl(parent->container, 0)) == T_COMPONENT);
6✔
13313
         lu->cscope = cover_create_instance(cover, parent->parent->cscope,
6✔
13314
                                            parent->container, unit);
13315
      }
13316
      else if (tree_kind(unit) == T_ARCH)
198✔
13317
         lu->cscope = cover_create_instance(cover, parent->cscope, block, unit);
105✔
13318
      else
13319
         lu->cscope = cover_create_scope(cover, parent->cscope, block, NULL);
93✔
13320

13321
      cover_ignore_from_pragmas(cover, lu->cscope, unit);
329✔
13322
   }
13323

13324
   tree_global_flags_t gflags = tree_global_flags(unit);
9,410✔
13325
   if (primary != NULL)
9,410✔
13326
      gflags |= tree_global_flags(primary);
6,020✔
13327

13328
   if (gflags & TREE_GF_INSTANCE_NAME)
9,410✔
13329
      lower_cache_instance_name(lu, ATTR_INSTANCE_NAME);
328✔
13330

13331
   if (gflags & TREE_GF_PATH_NAME)
9,410✔
13332
      lower_cache_instance_name(lu, ATTR_PATH_NAME);
436✔
13333

13334
   if (gflags & TREE_GF_EXTERNAL_NAME)
9,410✔
13335
      tree_visit_only(block, lower_external_name_cache, lu, T_EXTERNAL_NAME);
122✔
13336

13337
   lower_dependencies(lu, block);
9,410✔
13338
   lower_generics(lu, block, primary);
9,410✔
13339
   lower_ports(lu, ds, block);
9,410✔
13340
   lower_decls(lu, block);
9,410✔
13341

13342
   emit_return(VCODE_INVALID_REG);
9,410✔
13343

13344
   lower_finished(lu, shape);
9,410✔
13345
   return lu;
9,410✔
13346
}
13347

13348
lower_unit_t *lower_unit_new(unit_registry_t *ur, lower_unit_t *parent,
44,873✔
13349
                             vcode_unit_t vunit, cover_data_t *cover,
13350
                             tree_t container)
13351
{
13352
   lower_unit_t *new = xcalloc(sizeof(lower_unit_t));
44,873✔
13353
   new->parent    = parent;
44,873✔
13354
   new->objects   = hash_new(128);
44,873✔
13355
   new->container = container;
44,873✔
13356
   new->vunit     = vunit;
44,873✔
13357
   new->cover     = cover;
44,873✔
13358
   new->registry  = ur;
44,873✔
13359

13360
   const vunit_kind_t kind = vcode_unit_kind(vunit);
44,873✔
13361

13362
   new->name = vcode_unit_name(vunit);
44,873✔
13363
   new->mode = (kind == VCODE_UNIT_THUNK) ? LOWER_THUNK : LOWER_NORMAL;
44,873✔
13364

13365
   return new;
44,873✔
13366
}
13367

13368
void lower_unit_free(lower_unit_t *lu)
44,873✔
13369
{
13370
   assert(lu->finished);
44,873✔
13371

13372
   hash_free(lu->objects);
44,873✔
13373
   ACLEAR(lu->free_temps);
44,873✔
13374
   free(lu);
44,873✔
13375
}
44,873✔
13376

13377
vcode_unit_t get_vcode(lower_unit_t *lu)
499✔
13378
{
13379
   return lu->vunit;
499✔
13380
}
13381

13382
static cover_scope_t *lower_emit_cover_scopes(lower_unit_t *lu,
4,523✔
13383
                                              lazy_cscope_t *lcs)
13384
{
13385
   if (lcs == NULL)
4,523✔
13386
      return lu->cscope;
1,296✔
13387
   else if (lcs->cscope != NULL)
3,227✔
13388
      return lcs->cscope;
13389
   else {
13390
      cover_scope_t *parent = lower_emit_cover_scopes(lu, lcs->parent);
2,183✔
13391
      return (lcs->cscope = cover_create_scope(lu->cover, parent,
2,183✔
13392
                                               lcs->tree, NULL));
13393
   }
13394
}
13395

13396
cover_scope_t *lower_get_cover_scope(lower_unit_t *lu)
2,538✔
13397
{
13398
   if (lu->cover == NULL)
2,538✔
13399
      return NULL;
13400
   else
13401
      return lower_emit_cover_scopes(lu, lu->lazy_cscope);
2,340✔
13402
}
13403

13404
////////////////////////////////////////////////////////////////////////////////
13405

13406
typedef enum {
13407
   UNIT_DEFERRED = 1,
13408
   UNIT_GENERATED = 2,
13409
   UNIT_FINALISED = 3,
13410
} unit_kind_t;
13411

13412
typedef void (*dep_visit_fn_t)(vcode_unit_t, void *);
13413
typedef bool (*dep_filter_fn_t)(ident_t, void *);
13414

13415
typedef struct _unit_registry {
13416
   hash_t *map;
13417
   hset_t *visited;
13418
} unit_registry_t;
13419

13420
typedef struct {
13421
   lower_unit_t *parent;
13422
   emit_fn_t     emit_fn;
13423
   lower_fn_t    fn;
13424
   object_t     *object;
13425
   cover_data_t *cover;
13426
} deferred_unit_t;
13427

13428
unit_registry_t *unit_registry_new(void)
7,660✔
13429
{
13430
   unit_registry_t *ur = xcalloc(sizeof(unit_registry_t));
7,660✔
13431
   ur->map = hash_new(128);
7,660✔
13432

13433
   return ur;
7,660✔
13434
}
13435

13436
void unit_registry_free(unit_registry_t *ur)
7,641✔
13437
{
13438
   vcode_close();
7,641✔
13439

13440
   const void *key;
7,641✔
13441
   void *value;
7,641✔
13442
   for (hash_iter_t it = HASH_BEGIN; hash_iter(ur->map, &it, &key, &value); ) {
129,308✔
13443

13444
      switch (pointer_tag(value)) {
121,667✔
13445
      case UNIT_FINALISED:
29,271✔
13446
         {
13447
            vcode_unit_t vu = untag_pointer(value, struct _vcode_unit);
29,271✔
13448
            vcode_unit_unref(vu);
29,271✔
13449
         }
13450
         break;
29,271✔
13451

13452
      case UNIT_GENERATED:
3,215✔
13453
         {
13454
            lower_unit_t *lu = untag_pointer(value, lower_unit_t);
3,215✔
13455
            assert(lu->finished);
3,215✔
13456
            assert(lu->registry == ur);
3,215✔
13457
            vcode_unit_unref(lu->vunit);
3,215✔
13458
            lower_unit_free(lu);
3,215✔
13459
         }
13460
         break;
3,215✔
13461

13462
      case UNIT_DEFERRED:
89,181✔
13463
         {
13464
            deferred_unit_t *du = untag_pointer(value, deferred_unit_t);
89,181✔
13465
            free(du);
89,181✔
13466
         }
13467
         break;
89,181✔
13468

13469
      default:
×
13470
         fatal_trace("invalid tagged pointer %p", value);
13471
      }
13472
   }
13473

13474
   hash_free(ur->map);
7,641✔
13475
   free(ur);
7,641✔
13476
}
7,641✔
13477

13478
void unit_registry_put(unit_registry_t *ur, lower_unit_t *lu)
19,593✔
13479
{
13480
   assert(hash_get(ur->map, lu->name) == NULL);
19,593✔
13481
   hash_put(ur->map, lu->name, tag_pointer(lu, UNIT_GENERATED));
19,593✔
13482
}
19,593✔
13483

13484
bool unit_registry_query(unit_registry_t *ur, ident_t ident)
62,396✔
13485
{
13486
   return hash_get(ur->map, ident) != NULL;
62,396✔
13487
}
13488

13489
void unit_registry_purge(unit_registry_t *ur, ident_t prefix)
10,188✔
13490
{
13491
   if (hash_get(ur->map, prefix) == NULL)
10,188✔
13492
      return;   // Fail fast if root not registered
10,188✔
13493

13494
   const void *key;
×
13495
   void *value;
×
13496
   for (hash_iter_t it = HASH_BEGIN; hash_iter(ur->map, &it, &key, &value); ) {
×
13497
      if (ident_starts_with((ident_t)key, prefix)) {
×
13498
         switch (pointer_tag(value)) {
×
13499
         case UNIT_FINALISED:
×
13500
            // TODO: unref vcode unit?
13501
            hash_delete(ur->map, key);
×
13502
            break;
×
13503

13504
         case UNIT_GENERATED:
×
13505
         case UNIT_DEFERRED:
13506
            fatal_trace("cannot purge this unit kind");
13507

13508
         default:
×
13509
            fatal_trace("invalid tagged pointer %p", value);
13510
         }
13511
      }
13512
   }
13513
}
13514

13515
static void walk_dependency_cb(ident_t name, void *ctx)
53,900✔
13516
{
13517
   unit_registry_t *ur = ctx;
53,900✔
13518

13519
   if (hset_contains(ur->visited, name))
53,900✔
13520
      return;
13521

13522
   hset_insert(ur->visited, name);
30,590✔
13523

13524
   void *ptr = hash_get(ur->map, name);
30,590✔
13525
   if (ptr == NULL)
30,590✔
13526
      return;
13527

13528
   vcode_unit_t vu = NULL;
23,921✔
13529
   switch (pointer_tag(ptr)) {
23,921✔
13530
   case UNIT_DEFERRED:
147✔
13531
      {
13532
         deferred_unit_t *du = untag_pointer(ptr, deferred_unit_t);
147✔
13533
         if (arena_frozen(object_arena(du->object)))
147✔
13534
            return;
13535

13536
         vu = unit_registry_get(ur, name);
113✔
13537
      }
13538
      break;
113✔
13539
   case UNIT_FINALISED:
21,159✔
13540
      vu = untag_pointer(ptr, struct _vcode_unit);
21,159✔
13541
      break;
21,159✔
13542
   case UNIT_GENERATED:
2,615✔
13543
      {
13544
         lower_unit_t *lu = untag_pointer(ptr, lower_unit_t);
2,615✔
13545
         vu = lu->vunit;
2,615✔
13546
      }
13547
      break;
2,615✔
13548
   default:
×
13549
      fatal_trace("invalid tagged pointer %p", ptr);
13550
   }
13551

13552
   if (arena_frozen(object_arena(vcode_unit_object(vu))))
23,887✔
13553
      return;
13554

13555
   vcode_walk_dependencies(vu, walk_dependency_cb, ur);
15,453✔
13556

13557
   for (vcode_unit_t it = vcode_unit_child(vu); it; it = vcode_unit_next(it)) {
33,917✔
13558
      assert(vcode_unit_kind(it) != VCODE_UNIT_THUNK);
18,464✔
13559
      walk_dependency_cb(vcode_unit_name(it), ctx);
18,464✔
13560
   }
13561
}
13562

13563
void unit_registry_flush(unit_registry_t *ur, ident_t name)
3,567✔
13564
{
13565
   assert(ur->visited == NULL);
3,567✔
13566
   ur->visited = hset_new(128);
3,567✔
13567

13568
   // Make sure all transitive dependencies of this unit which contain
13569
   // references to non-frozen objects are generated
13570
   walk_dependency_cb(name, ur);
3,567✔
13571

13572
   hset_free(ur->visited);
3,567✔
13573
   ur->visited = NULL;
3,567✔
13574
}
3,567✔
13575

13576
void unit_registry_finalise(unit_registry_t *ur, lower_unit_t *lu)
32,492✔
13577
{
13578
   assert(pointer_tag(hash_get(ur->map, lu->name)) == UNIT_GENERATED);
32,492✔
13579

13580
   if (!lu->finished)
32,492✔
13581
      lower_finished(lu, NULL);
14,071✔
13582

13583
   if (lu->deferred > 0)
32,492✔
13584
      return;
13585

13586
   hash_put(ur->map, lu->name, tag_pointer(lu->vunit, UNIT_FINALISED));
29,277✔
13587

13588
   lower_unit_free(lu);
29,277✔
13589
}
13590

13591
vcode_unit_t unit_registry_get(unit_registry_t *ur, ident_t ident)
69,854✔
13592
{
13593
   void *ptr = hash_get(ur->map, ident);
69,854✔
13594
   if (ptr == NULL) {
69,854✔
13595
      ident_t it = ident;
1,800✔
13596
      ident_t lname = ident_walk_selected(&it);
1,800✔
13597
      ident_t uname = ident_walk_selected(&it);
1,800✔
13598

13599
      lib_t lib = lib_require(lname);
1,800✔
13600

13601
      ident_t unit_name = ident_prefix(lname, uname, '.');
1,800✔
13602
      tree_t unit = lib_get(lib, unit_name);
1,800✔
13603
      if (unit == NULL || !is_package(unit))
1,800✔
13604
         return NULL;
166✔
13605

13606
      if (tree_kind(unit) == T_PACKAGE && package_needs_body(unit)) {
2,813✔
13607
         tree_t body = body_of(unit);
1,182✔
13608
         if (body == NULL)
1,179✔
13609
            return NULL;
13610

13611
         unit_registry_defer(ur, unit_name, NULL, emit_package,
1,178✔
13612
                             lower_pack_body, NULL, tree_to_object(body));
13613
      }
13614
      else
13615
         unit_registry_defer(ur, unit_name, NULL, emit_package,
453✔
13616
                             lower_package, NULL, tree_to_object(unit));
13617

13618
      if (unit_name != ident) {
1,631✔
13619
         // We actually wanted a unit inside this package so need to
13620
         // force code generation
13621
         (void)unit_registry_get(ur, unit_name);
242✔
13622
      }
13623

13624
      if ((ptr = hash_get(ur->map, ident)) == NULL)
1,631✔
13625
         return NULL;
13626
   }
13627

13628
   switch (pointer_tag(ptr)) {
69,685✔
13629
   case UNIT_DEFERRED:
12,899✔
13630
      {
13631
         deferred_unit_t *du = untag_pointer(ptr, deferred_unit_t);
12,899✔
13632

13633
         vcode_state_t state;
12,899✔
13634
         vcode_state_save(&state);
12,899✔
13635

13636
         vcode_unit_t context = du->parent ? du->parent->vunit : NULL;
12,899✔
13637
         vcode_unit_t vu = (*du->emit_fn)(ident, du->object, context);
12,899✔
13638
         tree_t container = tree_from_object(du->object);
12,899✔
13639
         lower_unit_t *lu = lower_unit_new(ur, du->parent, vu,
12,899✔
13640
                                           du->cover, container);
13641

13642
         hash_put(ur->map, ident, tag_pointer(lu, UNIT_GENERATED));
12,899✔
13643

13644
         (*du->fn)(lu, du->object);
12,899✔
13645

13646
         for (lower_unit_t *p = du->parent; p; p = p->parent) {
25,537✔
13647
            assert(p->deferred > 0);
12,638✔
13648
            p->deferred--;
12,638✔
13649
         }
13650

13651
         unit_registry_finalise(ur, lu);
12,899✔
13652

13653
         vcode_state_restore(&state);
12,899✔
13654

13655
         free(du);
12,899✔
13656
         return vu;
12,899✔
13657
      }
13658

13659
   case UNIT_GENERATED:
10,488✔
13660
      {
13661
         lower_unit_t *lu = untag_pointer(ptr, lower_unit_t);
10,488✔
13662
         return lu->vunit;
10,488✔
13663
      }
13664

13665
   case UNIT_FINALISED:
46,298✔
13666
      return untag_pointer(ptr, struct _vcode_unit);
46,298✔
13667

13668
   default:
×
13669
      fatal_trace("invalid tagged pointer %p", ptr);
13670
   }
13671
}
13672

13673
vcode_unit_t unit_registry_get_parent(unit_registry_t *ur, ident_t name)
57✔
13674
{
13675
   void *ptr = hash_get(ur->map, name);
57✔
13676
   if (ptr == NULL)
57✔
13677
      return NULL;
13678

13679
   switch (pointer_tag(ptr)) {
57✔
13680
   case UNIT_DEFERRED:
6✔
13681
      {
13682
         deferred_unit_t *du = untag_pointer(ptr, deferred_unit_t);
6✔
13683
         return du->parent->vunit;
6✔
13684
      }
13685
      break;
6✔
13686

13687
   case UNIT_FINALISED:
6✔
13688
      {
13689
         vcode_unit_t vu = untag_pointer(ptr, struct _vcode_unit);
6✔
13690
         return vcode_unit_context(vu);
6✔
13691
      }
13692

13693
   case UNIT_GENERATED:
45✔
13694
      {
13695
         lower_unit_t *lu = untag_pointer(ptr, lower_unit_t);
45✔
13696
         return lu->parent->vunit;
45✔
13697
      }
13698
      break;
×
13699

13700
   default:
×
13701
      fatal_trace("invalid tagged pointer %p", ptr);
13702
   }
13703
}
13704

13705
void unit_registry_defer(unit_registry_t *ur, ident_t ident,
102,180✔
13706
                         lower_unit_t *parent, emit_fn_t emit_fn,
13707
                         lower_fn_t fn, cover_data_t *cover,
13708
                         object_t *object)
13709
{
13710
   void *ptr = hash_get(ur->map, ident);
102,180✔
13711
   if (ptr == NULL) {
102,180✔
13712
      deferred_unit_t *du = xcalloc(sizeof(deferred_unit_t));
102,080✔
13713
      du->emit_fn = emit_fn;
102,080✔
13714
      du->fn      = fn;
102,080✔
13715
      du->parent  = parent;
102,080✔
13716
      du->cover   = cover;
102,080✔
13717
      du->object  = object;
102,080✔
13718

13719
      for (lower_unit_t *p = du->parent; p; p = p->parent)
206,208✔
13720
         p->deferred++;
104,128✔
13721

13722
      hash_put(ur->map, ident, tag_pointer(du, UNIT_DEFERRED));
102,080✔
13723
   }
13724
#ifdef DEBUG
13725
   else if (pointer_tag(ptr) == UNIT_DEFERRED) {
100✔
13726
      deferred_unit_t *du = untag_pointer(ptr, deferred_unit_t);
99✔
13727
      assert(du->emit_fn == emit_fn);
99✔
13728
      assert(du->fn == fn);
99✔
13729
      assert(du->cover == cover);
99✔
13730
      assert(du->object == object);
99✔
13731
   }
13732
#endif
13733
}
102,180✔
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