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

nickg / nvc / 19617482215

23 Nov 2025 09:08PM UTC coverage: 92.559% (-0.01%) from 92.572%
19617482215

push

github

nickg
Structure sharing for component instances

139 of 147 new or added lines in 1 file covered. (94.56%)

327 existing lines in 10 files now uncovered.

75133 of 81173 relevant lines covered (92.56%)

453457.88 hits per line

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

96.79
/src/vcode.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 "diag.h"
22
#include "hash.h"
23
#include "lib.h"
24
#include "object.h"
25
#include "tree.h"
26
#include "vcode.h"
27

28
#include <assert.h>
29
#include <inttypes.h>
30
#include <string.h>
31
#include <stdlib.h>
32
#include <float.h>
33
#include <math.h>
34

35
DECLARE_AND_DEFINE_ARRAY(vcode_reg);
10,310,032✔
36
DECLARE_AND_DEFINE_ARRAY(vcode_block);
361,808✔
37
DECLARE_AND_DEFINE_ARRAY(vcode_type);
82,147✔
38

39
#define OP_HAS_TYPE(x)                                                  \
40
   (x == VCODE_OP_ALLOC || x == VCODE_OP_COPY                           \
41
    || x == VCODE_OP_CONST || x == VCODE_OP_CAST                        \
42
    || x == VCODE_OP_CONST_RECORD                                       \
43
    || x == VCODE_OP_BIND_EXTERNAL || x == VCODE_OP_ARRAY_SCOPE         \
44
    || x == VCODE_OP_RECORD_SCOPE || x == VCODE_OP_SYSCALL)
45
#define OP_HAS_ADDRESS(x)                                               \
46
   (x == VCODE_OP_LOAD || x == VCODE_OP_STORE || x == VCODE_OP_INDEX    \
47
    || x == VCODE_OP_VAR_UPREF)
48
#define OP_HAS_FUNC(x)                                                  \
49
   (x == VCODE_OP_FCALL || x == VCODE_OP_PCALL || x == VCODE_OP_RESUME  \
50
    || x == VCODE_OP_CLOSURE || x == VCODE_OP_PROTECTED_INIT            \
51
    || x == VCODE_OP_PACKAGE_INIT || x == VCODE_OP_PROCESS_INIT \
52
    || x == VCODE_OP_FUNCTION_TRIGGER || x == VCODE_OP_SYSCALL)
53
#define OP_HAS_IDENT(x)                                                 \
54
   (x == VCODE_OP_LINK_VAR || x == VCODE_OP_LINK_PACKAGE                \
55
    || x == VCODE_OP_DEBUG_LOCUS || x == VCODE_OP_BIND_EXTERNAL)
56
#define OP_HAS_OBJECT(x)                                                 \
57
   (x == VCODE_OP_DEBUG_LOCUS)
58
#define OP_HAS_REAL(x)                                                  \
59
   (x == VCODE_OP_CONST_REAL)
60
#define OP_HAS_VALUE(x)                                                 \
61
   (x == VCODE_OP_CONST || x == VCODE_OP_CONST_REP)
62
#define OP_HAS_DIM(x)                                                   \
63
   (x == VCODE_OP_UARRAY_LEFT || x == VCODE_OP_UARRAY_RIGHT             \
64
    || x == VCODE_OP_UARRAY_DIR || x == VCODE_OP_UARRAY_LEN)
65
#define OP_HAS_HOPS(x)                                                  \
66
   (x == VCODE_OP_VAR_UPREF || x == VCODE_OP_CONTEXT_UPREF)
67
#define OP_HAS_FIELD(x)                                                 \
68
   (x == VCODE_OP_RECORD_REF)
69
#define OP_HAS_CMP(x)                                                   \
70
   (x == VCODE_OP_CMP)
71
#define OP_HAS_TAG(x)                                                   \
72
   (x == VCODE_OP_COVER_STMT || x == VCODE_OP_COVER_BRANCH              \
73
    || x == VCODE_OP_COVER_TOGGLE || x == VCODE_OP_COVER_EXPR           \
74
    || x == VCODE_OP_COVER_STATE)
75
#define OP_HAS_COMMENT(x)                                               \
76
   (x == VCODE_OP_COMMENT)
77
#define OP_HAS_TARGET(x)                                                \
78
   (x == VCODE_OP_WAIT || x == VCODE_OP_JUMP || x == VCODE_OP_COND      \
79
    || x == VCODE_OP_PCALL || x == VCODE_OP_CASE)
80

81
typedef struct {
82
   vcode_op_t              kind;
83
   vcode_reg_t             result;
84
   vcode_reg_array_t       args;
85
   loc_t                   loc;
86
   vcode_type_t            type;      // OP_HAS_TYPE
87
   union {
88
      ident_t              func;      // OP_HAS_FUNC
89
      ident_t              ident;     // OP_HAS_IDENT
90
      object_t            *object;    // OP_HAS_OBJECT
91
      vcode_var_t          address;   // OP_HAS_ADDRESS
92
   };
93
   union {
94
      vcode_cmp_t          cmp;       // OP_HAS_CMP
95
      int64_t              value;     // OP_HAS_VALUE
96
      double               real;      // OP_HAS_REAL
97
      char                *comment;   // OP_HAS_COMMENT
98
      unsigned             dim;       // OP_HAS_DIM
99
      unsigned             hops;      // OP_HAS_HOPS
100
      unsigned             field;     // OP_HAS_FIELD
101
      uint32_t             tag;       // OP_HAS_TAG
102
      vcode_block_array_t  targets;   // OP_HAS_TARGET
103
   };
104
} op_t;
105

106
DECLARE_AND_DEFINE_ARRAY(op);
12,436,845✔
107

108
typedef struct {
109
   op_array_t ops;
110
   loc_t      last_loc;
111
} block_t;
112

113
typedef struct {
114
   vcode_type_t type;
115
   vcode_type_t bounds;
116
} reg_t;
117

118
typedef struct {
119
   vtype_kind_t kind;
120
   vtype_repr_t repr;
121
   union {
122
      struct {
123
         int64_t low;
124
         int64_t high;
125
      };
126
      struct {
127
         double rlow;
128
         double rhigh;
129
      };
130
      struct {
131
         unsigned      dims;
132
         unsigned      size;
133
         vcode_type_t  elem;
134
         vcode_type_t  bounds;
135
      };
136
      vcode_type_t pointed;
137
      vcode_type_t base;
138
      struct {
139
         ident_t            name;
140
         vcode_type_array_t fields;
141
      };
142
   };
143
} vtype_t;
144

145
typedef struct {
146
   vcode_type_t      type;
147
   vcode_type_t      bounds;
148
   ident_t           name;
149
   vcode_var_flags_t flags;
150
} var_t;
151

152
typedef struct {
153
   vcode_type_t type;
154
   vcode_type_t bounds;
155
   ident_t      name;
156
   vcode_reg_t  reg;
157
} param_t;
158

159
DECLARE_AND_DEFINE_ARRAY(param);
32,191✔
160
DECLARE_AND_DEFINE_ARRAY(var);
445,982✔
161
DECLARE_AND_DEFINE_ARRAY(reg);
9,932,117✔
162
DECLARE_AND_DEFINE_ARRAY(block);
145,300✔
163
DECLARE_AND_DEFINE_ARRAY(vtype);
87,541,404✔
164

165
typedef enum {
166
   UNIT_UNDEFINED     = (1 << 1),
167
} unit_flags_t;
168

169
struct _vcode_unit {
170
   vunit_kind_t   kind;
171
   vcode_unit_t   context;
172
   ident_t        name;
173
   vcode_type_t   result;
174
   block_array_t  blocks;
175
   reg_array_t    regs;
176
   vtype_array_t  types;
177
   var_array_t    vars;
178
   param_array_t  params;
179
   unsigned       depth;
180
   unit_flags_t   flags;
181
   vcode_unit_t   children;
182
   vcode_unit_t   next;
183
   object_t      *object;
184
};
185

186
#define MASK_CONTEXT(x)   ((x) >> 24)
187
#define MASK_INDEX(x)     ((x) & 0xffffff)
188
#define MAKE_HANDLE(c, i) (((c) & 0xff) << 24 | ((i) & 0xffffff))
189

190
#define VCODE_ASSERT(expr, ...) do                                      \
191
      if (unlikely(!(expr))) {                                          \
192
         vcode_dump_with_mark(vcode_block_data()->ops.count - 1,        \
193
                              NULL, NULL);                              \
194
         fatal_trace(__VA_ARGS__);                                      \
195
      } while (0)
196

197
#define VCODE_FOR_EACH_OP(name)                                 \
198
   block_t *_b = vcode_block_data();                            \
199
   op_t *name; int _i;                                          \
200
   if (_b->ops.count > 0)                                       \
201
      for (_i = _b->ops.count - 1, name = &(_b->ops.items[_i]); \
202
           _i >= 0; name = &(_b->ops.items[--_i]))
203

204
#define VCODE_FOR_EACH_MATCHING_OP(name, k) \
205
   block_t *_b = vcode_block_data();                            \
206
   op_t *name; int _i;                                          \
207
   if (_b->ops.count > 0)                                       \
208
      for (_i = 0, name = &(_b->ops.items[_i]);                 \
209
           _i < _b->ops.count; name = &(_b->ops.items[++_i]))   \
210
         if (name->kind == (k))
211

212
#define VCODE_CHECK_UNIONS 0
213

214
static __thread vcode_unit_t  active_unit  = NULL;
215
static __thread vcode_block_t active_block = VCODE_INVALID_BLOCK;
216

217
static inline int64_t sadd64(int64_t a, int64_t b)
41,114✔
218
{
219
   int64_t result;
41,114✔
220
   if (__builtin_add_overflow(a, b, &result))
41,114✔
221
      return b < 0 ? INT64_MIN : INT64_MAX;
8,768✔
222

223
   return result;
224
}
225

226
static inline int64_t ssub64(int64_t a, int64_t b)
69,314✔
227
{
228
   int64_t result;
69,314✔
229
   if (__builtin_sub_overflow(a, b, &result))
69,314✔
230
      return b > 0 ? INT64_MIN : INT64_MAX;
848✔
231

232
   return result;
233
}
234

235
static inline int64_t smul64(int64_t a, int64_t b)
18,332✔
236
{
237
   int64_t result;
18,332✔
238
   if (__builtin_mul_overflow(a, b, &result))
18,332✔
239
      return (a > 0 && b > 0) || (a < 0 && b < 0) ? INT64_MAX : INT64_MIN;
1,774✔
240

241
   return result;
242
}
243

244
static vcode_reg_t vcode_add_reg(vcode_type_t type)
1,524,352✔
245
{
246
   assert(active_unit != NULL);
1,524,352✔
247

248
   vcode_reg_t reg = active_unit->regs.count;
1,524,352✔
249
   reg_t *r = reg_array_alloc(&(active_unit->regs));
1,524,352✔
250
   memset(r, '\0', sizeof(reg_t));
1,524,352✔
251
   r->type   = type;
1,524,352✔
252
   r->bounds = type;
1,524,352✔
253

254
   return reg;
1,524,352✔
255
}
256

257
static block_t *vcode_block_data(void)
8,573,013✔
258
{
259
   assert(active_unit != NULL);
8,573,013✔
260
   assert(active_block != -1);
8,573,013✔
261
   return &(active_unit->blocks.items[active_block]);
8,573,013✔
262
}
263

264
static op_t *vcode_add_op(vcode_op_t kind)
1,955,121✔
265
{
266
   assert(active_unit != NULL);
1,955,121✔
267
   assert(active_block != VCODE_INVALID_BLOCK);
1,955,121✔
268

269
   VCODE_ASSERT(
1,955,121✔
270
      !vcode_block_finished(),
271
      "attempt to add to already finished block %d", active_block);
272

273
   block_t *block = vcode_block_data();
1,955,121✔
274

275
   op_t *op = op_array_alloc(&(block->ops));
1,955,121✔
276
   memset(op, '\0', sizeof(op_t));
1,955,121✔
277
   op->kind   = kind;
1,955,121✔
278
   op->result = VCODE_INVALID_REG;
1,955,121✔
279
   op->loc    = block->last_loc;
1,955,121✔
280

281
   return op;
1,955,121✔
282
}
283

284
static void vcode_add_arg(op_t *op, vcode_reg_t arg)
3,384,546✔
285
{
286
   vcode_reg_array_add(&(op->args), arg);
3,384,546✔
287
}
3,384,546✔
288

289
static void vcode_add_target(op_t *op, vcode_block_t block)
119,695✔
290
{
291
   vcode_block_array_add(&(op->targets), block);
119,695✔
292
}
119,695✔
293

294
static op_t *vcode_op_data(int op)
10,481,724✔
295
{
296
   assert(active_unit != NULL);
10,481,724✔
297
   assert(active_block != VCODE_INVALID_BLOCK);
10,481,724✔
298

299
   block_t *b = &(active_unit->blocks.items[active_block]);
10,481,724✔
300
   return op_array_nth_ptr(&(b->ops), op);
10,481,724✔
301
}
302

303
static op_t *vcode_find_definition(vcode_reg_t reg)
1,682,468✔
304
{
305
   for (int i = active_block; i >= 0; i--) {
1,713,739✔
306
      block_t *b = &(active_unit->blocks.items[i]);
1,712,340✔
307
      for (int j = b->ops.count - 1; j >= 0; j--) {
33,234,164✔
308
         if (b->ops.items[j].result == reg)
33,202,893✔
309
            return &(b->ops.items[j]);
1,681,069✔
310
      }
311
   }
312

313
   return NULL;
314
}
315

316
#ifdef DEBUG
317
static void vcode_assert_const(vcode_reg_t reg, const char *what)
1,665,718✔
318
{
319
   op_t *defn = vcode_find_definition(reg);
1,665,718✔
320
   VCODE_ASSERT(defn != NULL, "constant %s uses parameter r%d",
1,665,718✔
321
                what, reg);
322
   VCODE_ASSERT(defn->kind == VCODE_OP_CONST
1,665,718✔
323
                || defn->kind == VCODE_OP_CONST_REAL
324
                || defn->kind == VCODE_OP_CONST_RECORD
325
                || defn->kind == VCODE_OP_CONST_ARRAY
326
                || defn->kind == VCODE_OP_CONST_REP
327
                || defn->kind == VCODE_OP_NULL
328
                || defn->kind == VCODE_OP_UNDEFINED,
329
                "constant %s argument r%d is not constant", what, reg);
330
}
1,665,718✔
331
#endif
332

333
static reg_t *vcode_reg_data(vcode_reg_t reg)
8,407,765✔
334
{
335
   assert(active_unit != NULL);
8,407,765✔
336
   assert(reg != VCODE_INVALID_REG);
8,407,765✔
337
   return reg_array_nth_ptr(&(active_unit->regs), reg);
8,407,765✔
338
}
339

340
static vtype_t *vcode_type_data(vcode_type_t type)
84,090,708✔
341
{
342
   assert(type != VCODE_INVALID_TYPE);
84,090,708✔
343
   assert(active_unit != NULL);
84,090,708✔
344
   vcode_unit_t unit = active_unit;
84,090,708✔
345

346
   int depth = MASK_CONTEXT(type);
84,090,708✔
347
   assert(depth <= unit->depth);
84,090,708✔
348
   while (depth != unit->depth)
85,510,852✔
349
      unit = unit->context;
1,420,144✔
350

351
   return vtype_array_nth_ptr(&(unit->types), MASK_INDEX(type));
84,090,708✔
352
}
353

354
static var_t *vcode_var_data(vcode_var_t var)
375,642✔
355
{
356
   assert(active_unit != NULL);
375,642✔
357
   assert(var != VCODE_INVALID_VAR);
375,642✔
358

359
   return var_array_nth_ptr(&(active_unit->vars), var);
375,642✔
360
}
361

362
void vcode_heap_allocate(vcode_reg_t reg)
11,370✔
363
{
364
   op_t *defn = vcode_find_definition(reg);
16,750✔
365
   if (defn == NULL) {
16,750✔
366
      // It is always safe to return a pointer to an argument
367
      return;
368
   }
369

370
   switch (defn->kind) {
15,351✔
371
   case VCODE_OP_CONST:
372
   case VCODE_OP_CONST_REAL:
373
   case VCODE_OP_CONST_ARRAY:
374
   case VCODE_OP_CONST_REP:
375
   case VCODE_OP_NULL:
376
   case VCODE_OP_UNDEFINED:
377
   case VCODE_OP_ADDRESS_OF:
378
   case VCODE_OP_LINK_VAR:
379
   case VCODE_OP_LINK_PACKAGE:
380
   case VCODE_OP_CONTEXT_UPREF:
381
   case VCODE_OP_PACKAGE_INIT:
382
   case VCODE_OP_BIND_EXTERNAL:
383
      break;
384

385
   case VCODE_OP_ALLOC:
386
   case VCODE_OP_REFLECT_SUBTYPE:
387
   case VCODE_OP_REFLECT_VALUE:
388
      // Always allocated in mspace
389
      break;
390

391
   case VCODE_OP_INDEX:
1,241✔
392
      vcode_var_data(defn->address)->flags |= VAR_HEAP;
1,241✔
393
      break;
1,241✔
394

395
   case VCODE_OP_VAR_UPREF:
640✔
396
      {
397
         vcode_unit_t vu = vcode_active_unit();
640✔
398
         for (int i = 0; i < defn->hops; i++)
1,286✔
399
            vu = vcode_unit_context(vu);
646✔
400

401
         vcode_state_t state;
640✔
402
         vcode_state_save(&state);
640✔
403

404
         vcode_select_unit(vu);
640✔
405

406
         vcode_var_data(defn->address)->flags |= VAR_HEAP;
640✔
407

408
         vcode_state_restore(&state);
640✔
409
      }
410
      break;
640✔
411

412
   case VCODE_OP_ARRAY_REF:
478✔
413
      vcode_heap_allocate(defn->args.items[0]);
478✔
414
      break;
478✔
415

416
   case VCODE_OP_WRAP:
4,558✔
417
   case VCODE_OP_UNWRAP:
418
   case VCODE_OP_RESOLVED:
419
      vcode_heap_allocate(defn->args.items[0]);
4,558✔
420
      break;
4,558✔
421

422
   case VCODE_OP_LAST_VALUE:
423
      // Returns a pointer into the C heap
424
      break;
425

426
   case VCODE_OP_LOAD:
1,171✔
427
      {
428
         if (vcode_reg_kind(reg) != VCODE_TYPE_UARRAY)
1,171✔
429
            return;
430

431
         // Any store to this variable must be heap allocated
432
         for (int i = 0; i < active_unit->blocks.count; i++) {
18,356✔
433
            block_t *b = &(active_unit->blocks.items[i]);
17,232✔
434
            for (int j = 0; j < b->ops.count; j++) {
236,405✔
435
               op_t *op = &(b->ops.items[j]);
219,173✔
436
               if (op->kind == VCODE_OP_STORE && op->address == defn->address)
219,173✔
437
                  vcode_heap_allocate(op->args.items[0]);
1,124✔
438

439
               VCODE_ASSERT(
219,173✔
440
                  op->kind != VCODE_OP_INDEX || op->address != defn->address,
441
                  "cannot heap allocate aliased pointer r%d", reg);
442
            }
443
         }
444
      }
445
      break;
446

447
   case VCODE_OP_FCALL:
448
      for (int i = 0; i < defn->args.count; i++) {
6,280✔
449
         const vtype_kind_t rkind = vcode_reg_kind(reg);
4,580✔
450
         if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY) {
4,580✔
451
            // Function may return a pointer to its argument
452
            vcode_heap_allocate(defn->args.items[i]);
4,479✔
453
         }
454
      }
455
      break;
456

457
   case VCODE_OP_RECORD_REF:
24✔
458
      vcode_heap_allocate(defn->args.items[0]);
24✔
459
      break;
24✔
460

461
   case VCODE_OP_SELECT:
40✔
462
      vcode_heap_allocate(defn->args.items[1]);
40✔
463
      vcode_heap_allocate(defn->args.items[2]);
40✔
464
      break;
40✔
465

466
   case VCODE_OP_LOAD_INDIRECT:
298✔
467
      {
468
         // Always OK if scalar otherwise check the pointer source
469
         const vtype_kind_t vtkind = vcode_reg_kind(reg);
298✔
470
         if (vtkind != VCODE_TYPE_INT && vtkind != VCODE_TYPE_REAL)
298✔
471
            vcode_heap_allocate(defn->args.items[0]);
280✔
472
      }
473
      break;
474

475
   case VCODE_OP_ALL:
476
      // Must have been allocated on the heap
477
      break;
478

479
   case VCODE_OP_NEW:
480
      // On the heap by definition
481
      break;
482

483
   case VCODE_OP_SUB:
484
   case VCODE_OP_MUL:
485
   case VCODE_OP_DIV:
486
   case VCODE_OP_CAST:
487
   case VCODE_OP_CMP:
488
   case VCODE_OP_OR:
489
   case VCODE_OP_NOT:
490
   case VCODE_OP_AND:
491
   case VCODE_OP_NOR:
492
   case VCODE_OP_NAND:
493
   case VCODE_OP_XOR:
494
   case VCODE_OP_XNOR:
495
   case VCODE_OP_EVENT:
496
   case VCODE_OP_ACTIVE:
497
   case VCODE_OP_UARRAY_LEN:
498
   case VCODE_OP_UARRAY_LEFT:
499
   case VCODE_OP_UARRAY_RIGHT:
500
   case VCODE_OP_UARRAY_DIR:
501
   case VCODE_OP_LAST_EVENT:
502
   case VCODE_OP_NEG:
503
   case VCODE_OP_EXP:
504
   case VCODE_OP_ABS:
505
   case VCODE_OP_MOD:
506
   case VCODE_OP_REM:
507
   case VCODE_OP_ADD:
508
   case VCODE_OP_TRAP_ADD:
509
   case VCODE_OP_TRAP_SUB:
510
   case VCODE_OP_TRAP_MUL:
511
   case VCODE_OP_TRAP_NEG:
512
   case VCODE_OP_TRAP_EXP:
513
      // Result cannot reference pointer
514
      break;
515

516
   default:
517
      VCODE_ASSERT(false, "cannot heap allocate r%d", reg);
×
518
   }
519
}
520

521
void vcode_state_save(vcode_state_t *state)
38,828✔
522
{
523
   state->unit  = active_unit;
38,828✔
524
   state->block = active_block;
38,828✔
525
}
38,828✔
526

527
void vcode_state_restore(const vcode_state_t *state)
38,828✔
528
{
529
   active_unit  = state->unit;
38,828✔
530
   active_block = state->block;
38,828✔
531
}
38,828✔
532

533
void vcode_unit_unref(vcode_unit_t unit)
53,055✔
534
{
535
   assert(unit != NULL);
53,055✔
536

537
   if (unit == active_unit)
53,055✔
538
      vcode_close();
11,536✔
539

540
   for (vcode_unit_t it = unit->children; it != NULL; it = it->next) {
68,973✔
541
      assert(it->context == unit);
15,918✔
542
      it->context = NULL;
15,918✔
543
   }
544
   unit->children = NULL;
53,055✔
545

546
   if (unit->context != NULL) {
53,055✔
547
      vcode_unit_t *it = &(unit->context->children);
13,751✔
548
      for (; *it != NULL && *it != unit; it = &((*it)->next))
37,587✔
549
         ;
550
      assert(*it != NULL);
13,751✔
551
      *it = (*it)->next;
13,751✔
552
   }
553

554
   for (unsigned i = 0; i < unit->blocks.count; i++) {
198,257✔
555
      block_t *b = &(unit->blocks.items[i]);
145,202✔
556

557
      for (unsigned j = 0; j < b->ops.count; j++) {
2,013,957✔
558
         op_t *o = &(b->ops.items[j]);
1,868,755✔
559
         if (OP_HAS_COMMENT(o->kind))
1,868,755✔
560
            free(o->comment);
200,715✔
561
         if (OP_HAS_TARGET(o->kind))
1,868,755✔
562
            free(o->targets.items);
85,770✔
563
         free(o->args.items);
1,868,755✔
564
      }
565
      free(b->ops.items);
145,202✔
566
   }
567
   free(unit->blocks.items);
53,055✔
568

569
   for (unsigned i = 0; i < unit->types.count; i++) {
736,944✔
570
      vtype_t *vt = &(unit->types.items[i]);
683,889✔
571
      if (vt->kind == VCODE_TYPE_RECORD)
683,889✔
572
         free(vt->fields.items);
5,846✔
573
   }
574
   free(unit->types.items);
53,055✔
575

576
   free(unit->regs.items);
53,055✔
577
   free(unit->vars.items);
53,055✔
578
   free(unit->params.items);
53,055✔
579
   free(unit);
53,055✔
580
}
53,055✔
581

582
vcode_unit_t vcode_unit_next(vcode_unit_t unit)
18,114✔
583
{
584
   return unit->next;
18,114✔
585
}
586

587
vcode_unit_t vcode_unit_child(vcode_unit_t unit)
16,094✔
588
{
589
   return unit->children;
16,094✔
590
}
591

592
int vcode_count_regs(void)
53,017✔
593
{
594
   assert(active_unit != NULL);
53,017✔
595
   return active_unit->regs.count;
53,017✔
596
}
597

598
vcode_type_t vcode_reg_type(vcode_reg_t reg)
5,589,706✔
599
{
600
   return vcode_reg_data(reg)->type;
5,589,706✔
601
}
602

603
vtype_kind_t vcode_reg_kind(vcode_reg_t reg)
1,429,229✔
604
{
605
   return vtype_kind(vcode_reg_type(reg));
1,429,229✔
606
}
607

608
vcode_type_t vcode_reg_bounds(vcode_reg_t reg)
466,475✔
609
{
610
   return vcode_reg_data(reg)->bounds;
466,475✔
611
}
612

613
bool vcode_reg_const(vcode_reg_t reg, int64_t *value)
904,897✔
614
{
615
   reg_t *r = vcode_reg_data(reg);
904,897✔
616

617
   vtype_kind_t kind = vtype_kind(r->type);
904,897✔
618
   if (kind != VCODE_TYPE_INT && kind != VCODE_TYPE_OFFSET)
904,897✔
619
      return false;
620

621
   vtype_t *bounds = vcode_type_data(r->bounds);
874,789✔
622

623
   VCODE_ASSERT(
874,789✔
624
      bounds->kind == VCODE_TYPE_INT || bounds->kind == VCODE_TYPE_OFFSET,
625
      "integer register r%d has non-integer bounds", reg);
626

627
   if (bounds->low == bounds->high) {
874,789✔
628
      if (value) *value = bounds->low;
486,772✔
629
      return true;
486,772✔
630
   }
631
   else
632
      return false;
633
}
634

635
void vcode_opt(void)
53,081✔
636
{
637
   // Prune assignments to unused registers
638

639
   int *uses LOCAL = xmalloc_array(active_unit->regs.count, sizeof(int));
106,162✔
640

641
   int pruned = 0;
53,081✔
642
   do {
76,448✔
643
      memset(uses, '\0', active_unit->regs.count * sizeof(int));
76,448✔
644
      pruned = 0;
76,448✔
645

646
      for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
315,702✔
647
         block_t *b = &(active_unit->blocks.items[i]);
239,254✔
648

649
         for (int j = b->ops.count - 1; j >= 0; j--) {
3,689,337✔
650
            op_t *o = &(b->ops.items[j]);
3,450,083✔
651

652
            switch (o->kind) {
3,450,083✔
653
            case VCODE_OP_FCALL:
56,698✔
654
               if (o->result == VCODE_INVALID_REG)
56,698✔
655
                  break;
656
            case VCODE_OP_CONST:
657
            case VCODE_OP_CONST_REAL:
658
            case VCODE_OP_CONST_ARRAY:
659
            case VCODE_OP_CONST_RECORD:
660
            case VCODE_OP_CONST_REP:
661
            case VCODE_OP_LOAD:
662
            case VCODE_OP_LOAD_INDIRECT:
663
            case VCODE_OP_VAR_UPREF:
664
            case VCODE_OP_ADD:
665
            case VCODE_OP_ARRAY_REF:
666
            case VCODE_OP_SUB:
667
            case VCODE_OP_MUL:
668
            case VCODE_OP_CMP:
669
            case VCODE_OP_INDEX:
670
            case VCODE_OP_WRAP:
671
            case VCODE_OP_EXP:
672
            case VCODE_OP_UNDEFINED:
673
            case VCODE_OP_UARRAY_LEN:
674
            case VCODE_OP_UARRAY_DIR:
675
            case VCODE_OP_UARRAY_LEFT:
676
            case VCODE_OP_UARRAY_RIGHT:
677
            case VCODE_OP_UNWRAP:
678
            case VCODE_OP_NULL:
679
            case VCODE_OP_ADDRESS_OF:
680
            case VCODE_OP_RANGE_NULL:
681
            case VCODE_OP_RANGE_LENGTH:
682
            case VCODE_OP_DEBUG_LOCUS:
683
            case VCODE_OP_SELECT:
684
            case VCODE_OP_CAST:
685
            case VCODE_OP_RESOLVED:
686
            case VCODE_OP_TRAP_ADD:
687
            case VCODE_OP_TRAP_SUB:
688
            case VCODE_OP_TRAP_MUL:
689
            case VCODE_OP_TRAP_EXP:
690
            case VCODE_OP_ALLOC:
691
            case VCODE_OP_FUNCTION_TRIGGER:
692
            case VCODE_OP_CMP_TRIGGER:
693
            case VCODE_OP_OR_TRIGGER:
694
               if (uses[o->result] == -1) {
2,208,072✔
695
                  vcode_dump_with_mark(j, NULL, NULL);
×
696
                  fatal_trace("definition of r%d does not dominate all uses",
697
                              o->result);
698
               }
699
               else if (uses[o->result] == 0) {
2,208,072✔
700
                  if (false DEBUG_ONLY(|| o->kind != VCODE_OP_CONST)) {
206,541✔
701
                     o->comment = xasprintf("Dead %s definition of r%d",
121,065✔
702
                                            vcode_op_string(o->kind),
703
                                            o->result);
704
                     o->kind = VCODE_OP_COMMENT;
121,065✔
705
                  }
706
                  else
707
                     o->kind = (vcode_op_t)-1;
85,476✔
708
                  vcode_reg_array_resize(&(o->args), 0, VCODE_INVALID_REG);
206,541✔
709
                  pruned++;
206,541✔
710
               }
711
               uses[o->result] = -1;
2,208,072✔
712
               break;
2,208,072✔
713

714
            default:
715
               break;
716
            }
717

718
            for (int k = 0; k < o->args.count; k++) {
9,606,955✔
719
               if (o->args.items[k] != VCODE_INVALID_REG)
6,156,872✔
720
                  uses[o->args.items[k]]++;
6,120,870✔
721
            }
722
         }
723
      }
724
   } while (pruned > 0);
76,448✔
725

726
   for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
198,381✔
727
      block_t *b = &(active_unit->blocks.items[i]);
145,300✔
728
      op_t *dst = &(b->ops.items[0]);
145,300✔
729
      size_t copied = 0;
145,300✔
730
      for (int j = 0; j < b->ops.count; j++) {
2,100,421✔
731
         const op_t *src = &(b->ops.items[j]);
1,955,121✔
732
         if (src->kind != (vcode_op_t)-1) {
1,955,121✔
733
            if (src != dst) {
1,869,645✔
734
               assert(dst < src);
615,455✔
735
               *dst = *src;
615,455✔
736
            }
737
            dst++;
1,869,645✔
738
            copied++;
1,869,645✔
739
         }
740
      }
741

742
      assert(copied <= b->ops.count);
145,300✔
743
      b->ops.count = copied;
145,300✔
744
   }
745
}
53,081✔
746

747
void vcode_close(void)
31,429✔
748
{
749
   active_unit  = NULL;
31,429✔
750
   active_block = -1;
31,429✔
751
}
31,429✔
752

753
int vcode_count_blocks(void)
69,378✔
754
{
755
   assert(active_unit != NULL);
69,378✔
756
   return active_unit->blocks.count;
69,378✔
757
}
758

759
int vcode_count_ops(void)
189,396✔
760
{
761
   assert(active_unit != NULL);
189,396✔
762
   assert(active_block != VCODE_INVALID_BLOCK);
189,396✔
763
   return active_unit->blocks.items[active_block].ops.count;
189,396✔
764
}
765

766
int vcode_count_vars(void)
53,029✔
767
{
768
   assert(active_unit != NULL);
53,029✔
769
   return active_unit->vars.count;
53,029✔
770
}
771

772
vcode_var_t vcode_find_var(ident_t name)
15✔
773
{
774
   assert(active_unit != NULL);
15✔
775
   for (int i = 0; i < active_unit->vars.count; i++) {
27✔
776
      if (active_unit->vars.items[i].name == name)
12✔
777
         return i;
×
778
   }
779

780
   return VCODE_INVALID_VAR;
781
}
782

783
ident_t vcode_var_name(vcode_var_t var)
75,146✔
784
{
785
   return vcode_var_data(var)->name;
75,146✔
786
}
787

788
vcode_type_t vcode_var_type(vcode_var_t var)
75,904✔
789
{
790
   return vcode_var_data(var)->type;
75,904✔
791
}
792

793
vcode_type_t vcode_var_bounds(vcode_var_t var)
4,170✔
794
{
795
   return vcode_var_data(var)->bounds;
4,170✔
796
}
797

798
vcode_var_flags_t vcode_var_flags(vcode_var_t var)
77,349✔
799
{
800
   return vcode_var_data(var)->flags;
77,349✔
801
}
802

803
vcode_op_t vcode_get_op(int op)
2,550,627✔
804
{
805
   return vcode_op_data(op)->kind;
2,550,627✔
806
}
807

808
ident_t vcode_get_func(int op)
97,838✔
809
{
810
   op_t *o = vcode_op_data(op);
97,838✔
811
   assert(OP_HAS_FUNC(o->kind));
97,838✔
812
   return o->func;
97,838✔
813
}
814

815
ident_t vcode_get_ident(int op)
13,310✔
816
{
817
   op_t *o = vcode_op_data(op);
13,310✔
818
   assert(OP_HAS_IDENT(o->kind));
13,310✔
819
   return o->ident;
13,310✔
820
}
821

822
object_t *vcode_get_object(int op)
78,043✔
823
{
824
   op_t *o = vcode_op_data(op);
78,043✔
825
   assert(OP_HAS_IDENT(o->kind));
78,043✔
826
   return o->object;
78,043✔
827
}
828

829
int64_t vcode_get_value(int op)
387,921✔
830
{
831
   op_t *o = vcode_op_data(op);
387,921✔
832
   assert(OP_HAS_VALUE(o->kind));
387,921✔
833
   return o->value;
387,921✔
834
}
835

836
double vcode_get_real(int op)
22,219✔
837
{
838
   op_t *o = vcode_op_data(op);
22,219✔
839
   assert(OP_HAS_REAL(o->kind));
22,219✔
840
   return o->real;
22,219✔
841
}
842

843
vcode_var_t vcode_get_address(int op)
192,130✔
844
{
845
   op_t *o = vcode_op_data(op);
192,130✔
846
   assert(OP_HAS_ADDRESS(o->kind));
192,130✔
847
   return o->address;
192,130✔
848
}
849

850
unsigned vcode_get_dim(int op)
66,252✔
851
{
852
   op_t *o = vcode_op_data(op);
66,252✔
853
   assert(OP_HAS_DIM(o->kind));
66,252✔
854
   return o->dim;
66,252✔
855
}
856

857
int vcode_get_hops(int op)
63,267✔
858
{
859
   op_t *o = vcode_op_data(op);
63,267✔
860
   assert(OP_HAS_HOPS(o->kind));
63,267✔
861
   return o->hops;
63,267✔
862
}
863

864
int vcode_get_field(int op)
36,195✔
865
{
866
   op_t *o = vcode_op_data(op);
36,195✔
867
   assert(OP_HAS_FIELD(o->kind));
36,195✔
868
   return o->field;
36,195✔
869
}
870

871
vcode_var_t vcode_get_type(int op)
66,911✔
872
{
873
   op_t *o = vcode_op_data(op);
66,911✔
874
   assert(OP_HAS_TYPE(o->kind));
66,911✔
875
   return o->type;
66,911✔
876
}
877

878
int vcode_count_args(int op)
255,708✔
879
{
880
   return vcode_op_data(op)->args.count;
255,708✔
881
}
882

883
vcode_reg_t vcode_get_arg(int op, int arg)
3,334,107✔
884
{
885
   op_t *o = vcode_op_data(op);
3,334,107✔
886
   return vcode_reg_array_nth(&(o->args), arg);
3,334,107✔
887
}
888

889
vcode_reg_t vcode_get_result(int op)
1,290,249✔
890
{
891
   op_t *o = vcode_op_data(op);
1,290,249✔
892
   return o->result;
1,290,249✔
893
}
894

895
vcode_cmp_t vcode_get_cmp(int op)
34,499✔
896
{
897
   op_t *o = vcode_op_data(op);
34,499✔
898
   assert(OP_HAS_CMP(o->kind));
34,499✔
899
   return o->cmp;
34,499✔
900
}
901

902
uint32_t vcode_get_tag(int op)
3,029✔
903
{
904
   op_t *o = vcode_op_data(op);
3,029✔
905
   assert(OP_HAS_TAG(o->kind));
3,029✔
906
   return o->tag;
3,029✔
907
}
908

909
const loc_t *vcode_get_loc(int op)
1,868,687✔
910
{
911
   op_t *o = vcode_op_data(op);
1,868,687✔
912
   return &(o->loc);
1,868,687✔
913
}
914

915
vcode_block_t vcode_get_target(int op, int nth)
120,732✔
916
{
917
   op_t *o = vcode_op_data(op);
120,732✔
918
   assert(OP_HAS_TARGET(o->kind));
120,732✔
919
   return vcode_block_array_nth(&(o->targets), nth);
120,732✔
920
}
921

922
bool vcode_block_empty(void)
×
923
{
924
   assert(active_unit != NULL);
×
925
   assert(active_block != VCODE_INVALID_BLOCK);
×
926

927
   return active_unit->blocks.items[active_block].ops.count == 0;
×
928
}
929

930
bool vcode_block_finished(void)
2,077,815✔
931
{
932
   assert(active_unit != NULL);
2,077,815✔
933
   assert(active_block != VCODE_INVALID_BLOCK);
2,077,815✔
934

935
   const block_t *b = &(active_unit->blocks.items[active_block]);
2,077,815✔
936
   if (b->ops.count == 0)
2,077,815✔
937
      return false;
938
   else {
939
      vcode_op_t kind = b->ops.items[b->ops.count - 1].kind;
1,880,280✔
940
      return kind == VCODE_OP_WAIT || kind == VCODE_OP_JUMP
1,880,280✔
941
         || kind == VCODE_OP_COND || kind == VCODE_OP_PCALL
1,880,262✔
942
         || kind == VCODE_OP_RETURN || kind == VCODE_OP_CASE
943
         || kind == VCODE_OP_UNREACHABLE;
3,760,542✔
944
   }
945
}
946

947
const char *vcode_op_string(vcode_op_t op)
121,065✔
948
{
949
   static const char *strs[] = {
121,065✔
950
      "cmp", "fcall", "wait", "const", "assert", "jump", "load", "store",
951
      "mul", "add", "comment", "const array", "index", "sub", "cast",
952
      "load indirect", "store indirect", "return", "sched waveform",
953
      "cond", "report", "div", "neg", "exp", "abs", "mod", "rem", "alloc",
954
      "select", "or", "wrap", "uarray left", "uarray right", "uarray dir",
955
      "unwrap", "not", "and", "event", "active", "const record", "record ref",
956
      "copy", "sched event", "pcall", "resume", "xor", "xnor", "nand", "nor",
957
      "memset", "case", "file open", "file write",
958
      "file read", "null", "new", "null check", "deallocate", "all",
959
      "const real", "last event", "debug out", "cover stmt", "cover branch",
960
      "cover toggle", "cover expr", "cover state", "uarray len", "undefined",
961
      "range null", "var upref", "resolved", "last value", "init signal",
962
      "map signal", "drive signal", "link var", "resolution wrapper",
963
      "last active", "driving", "driving value", "address of", "closure",
964
      "protected init", "context upref", "const rep", "protected free",
965
      "implicit signal", "disconnect", "link package",
966
      "index check", "debug locus", "length check", "range check", "array ref",
967
      "range length", "exponent check", "zero check", "map const",
968
      "resolve signal", "package scope", "pop scope", "alias signal",
969
      "trap add", "trap sub", "trap mul", "force", "release",
970
      "unreachable", "package init", "trap neg", "process init", "clear event",
971
      "trap exp", "enter state", "reflect value", "reflect subtype",
972
      "function trigger", "add trigger", "transfer signal",
973
      "port conversion", "convert in", "convert out", "bind foreign",
974
      "or trigger", "cmp trigger", "instance name",
975
      "map implicit", "bind external", "array scope", "record scope", "syscall",
976
      "put conversion", "dir check", "sched process",
977
   };
978
   if ((unsigned)op >= ARRAY_LEN(strs))
121,065✔
979
      return "???";
980
   else
981
      return strs[op];
121,065✔
982
}
983

984
LCOV_EXCL_START
985
static int vcode_dump_reg(vcode_reg_t reg)
986
{
987
   if (reg == VCODE_INVALID_REG)
988
      return color_printf("$red$invalid$$");
989
   else
990
      return color_printf("$green$r%d$$", reg);
991
}
992

993
static int vcode_pretty_print_int(int64_t n)
994
{
995
   if (n == INT64_MAX)
996
      return printf("2^63-1");
997
   else if (n == INT64_MIN)
998
      return printf("-2^63");
999
   else if (n == INT32_MAX)
1000
      return printf("2^31-1");
1001
   else if (n == INT32_MIN)
1002
      return printf("-2^31");
1003
   else
1004
      return printf("%"PRIi64, n);
1005
}
1006

1007
static int vcode_dump_one_type(vcode_type_t type)
1008
{
1009
   int col = 0;
1010
   vtype_t *vt = vcode_type_data(type);
1011
   switch (vt->kind) {
1012
   case VCODE_TYPE_INT:
1013
      if (vt->low != vt->high) {
1014
         col += vcode_pretty_print_int(vt->low);
1015
         col += printf("..");
1016
         col += vcode_pretty_print_int(vt->high);
1017
      }
1018
      else
1019
         col += vcode_pretty_print_int(vt->low);
1020
      break;
1021

1022
   case VCODE_TYPE_REAL:
1023
      if (vt->rlow == -DBL_MAX && vt->rhigh == DBL_MAX)
1024
         col += printf("%%");
1025
      else if (vt->rlow == vt->rhigh)
1026
         col += printf("%f", vt->rlow);
1027
      else
1028
         col += printf("%f..%f", vt->rlow, vt->rhigh);
1029
      break;
1030

1031
   case VCODE_TYPE_CARRAY:
1032
      {
1033
         col += printf("[%u] : ", vt->size);
1034
         col += vcode_dump_one_type(vt->elem);
1035
         if (!vtype_eq(vt->elem, vt->bounds)) {
1036
            col += printf(" => ");
1037
            col += vcode_dump_one_type(vt->bounds);
1038
         }
1039
      }
1040
      break;
1041

1042
   case VCODE_TYPE_UARRAY:
1043
      {
1044
         col += printf("[");
1045
         for (unsigned i = 0; i < vt->dims; i++)
1046
            col += printf("%s*", i > 0 ? ", " : "");
1047
         col += printf("] : ");
1048
         col += vcode_dump_one_type(vt->elem);
1049
         if (!vtype_eq(vt->elem, vt->bounds)) {
1050
            col += printf(" => ");
1051
            col += vcode_dump_one_type(vt->bounds);
1052
         }
1053
      }
1054
      break;
1055

1056
   case VCODE_TYPE_POINTER:
1057
      col += printf("@<");
1058
      col += vcode_dump_one_type(vt->pointed);
1059
      col += printf(">");
1060
      break;
1061

1062
   case VCODE_TYPE_ACCESS:
1063
      col += printf("A<");
1064
      col += vcode_dump_one_type(vt->pointed);
1065
      col += printf(">");
1066
      break;
1067

1068
   case VCODE_TYPE_SIGNAL:
1069
      col += printf("$<");
1070
      col += vcode_dump_one_type(vt->base);
1071
      col += printf(">");
1072
      break;
1073

1074
   case VCODE_TYPE_OFFSET:
1075
      col += printf("#");
1076
      break;
1077

1078
   case VCODE_TYPE_RECORD:
1079
      col += printf("%s{}", istr(vt->name));
1080
      break;
1081

1082
   case VCODE_TYPE_FILE:
1083
      col += printf("F<");
1084
      col += vcode_dump_one_type(vt->base);
1085
      col += printf(">");
1086
      break;
1087

1088
   case VCODE_TYPE_OPAQUE:
1089
      col += printf("?");
1090
      break;
1091

1092
   case VCODE_TYPE_RESOLUTION:
1093
      col += printf("R<");
1094
      col += vcode_dump_one_type(vt->base);
1095
      col += printf(">");
1096
      break;
1097

1098
   case VCODE_TYPE_CLOSURE:
1099
      col += printf("C<");
1100
      col += vcode_dump_one_type(vt->base);
1101
      col += printf(">");
1102
      break;
1103

1104
   case VCODE_TYPE_CONTEXT:
1105
      col += printf("P<%s>", istr(vt->name));
1106
      break;
1107

1108
   case VCODE_TYPE_DEBUG_LOCUS:
1109
      col += printf("D<>");
1110
      break;
1111

1112
   case VCODE_TYPE_TRIGGER:
1113
      col += printf("T<>");
1114
      break;
1115

1116
   case VCODE_TYPE_CONVERSION:
1117
      col += printf("X<>");
1118
      break;
1119
   }
1120

1121
   return col;
1122
}
1123

1124
static void vcode_dump_tab(int col, int to_col)
1125
{
1126
   if (col >= to_col)
1127
      printf(" ");
1128
   else {
1129
      while (col < to_col)
1130
         col += printf(" ");
1131
   }
1132
}
1133

1134
static void vcode_dump_comment(int col)
1135
{
1136
   vcode_dump_tab(col, 40);
1137
   color_printf("$cyan$// ");
1138
}
1139

1140
static void vcode_dump_type(int col, vcode_type_t type, vcode_type_t bounds)
1141
{
1142
   vcode_dump_comment(col);
1143
   vcode_dump_one_type(type);
1144
   if (!vtype_eq(type, bounds)) {
1145
      printf(" => ");
1146
      vcode_dump_one_type(bounds);
1147
   }
1148
}
1149

1150
static void vcode_dump_result_type(int col, const op_t *op)
1151
{
1152
   if (op->result != VCODE_INVALID_REG) {
1153
      reg_t *r = vcode_reg_data(op->result);
1154
      vcode_dump_type(col, r->type, r->bounds);
1155
   }
1156
}
1157

1158
static int vcode_dump_var(vcode_var_t var, int hops)
1159
{
1160
   vcode_unit_t owner = active_unit;
1161
   while (owner && hops--)
1162
      owner = owner->context;
1163

1164
   if (owner == NULL || var >= owner->vars.count)
1165
      return color_printf("$red$invalid$$");
1166
   else {
1167
      var_t *v = var_array_nth_ptr(&(owner->vars), var);
1168
      return color_printf("$magenta$%s$$", istr(v->name));
1169
   }
1170
}
1171

1172
void vcode_dump_with_mark(int mark_op, vcode_dump_fn_t callback, void *arg)
1173
{
1174
   assert(active_unit != NULL);
1175

1176
   const vcode_unit_t vu = active_unit;
1177
   vcode_block_t old_block = active_block;
1178

1179
   printf("\n");
1180
   if (vu->name != NULL)
1181
      color_printf("Name       $cyan$%s$$\n", istr(vu->name));
1182
   color_printf("Kind       $cyan$");
1183
   switch (vu->kind) {
1184
   case VCODE_UNIT_PROCESS:   printf("process"); break;
1185
   case VCODE_UNIT_FUNCTION:  printf("function"); break;
1186
   case VCODE_UNIT_PROCEDURE: printf("procedure"); break;
1187
   case VCODE_UNIT_INSTANCE:  printf("instance"); break;
1188
   case VCODE_UNIT_THUNK:     printf("thunk"); break;
1189
   case VCODE_UNIT_PACKAGE:   printf("package"); break;
1190
   case VCODE_UNIT_PROTECTED: printf("protected"); break;
1191
   case VCODE_UNIT_PROPERTY:  printf("property"); break;
1192
   }
1193
   color_printf("$$\n");
1194
   if (vu->context != NULL)
1195
      color_printf("Context    $cyan$%s$$\n", istr(vu->context->name));
1196
   printf("Blocks     %d\n", vu->blocks.count);
1197
   printf("Registers  %d\n", vu->regs.count);
1198
   printf("Types      %d\n", vu->types.count);
1199

1200
   for (int i = 0; i < vu->types.count; i++) {
1201
      const vtype_t *t = &(vu->types.items[i]);
1202
      if (t->kind == VCODE_TYPE_RECORD) {
1203
         int col = 0;
1204
         col += color_printf("  $magenta$%s$$", istr(t->name));
1205
         vcode_dump_tab(col, 40);
1206
         color_printf("$cyan${");
1207
         for (unsigned i = 0; i < t->fields.count; i++) {
1208
            if (i > 0)
1209
               printf(", ");
1210
            vcode_dump_one_type(t->fields.items[i]);
1211
         }
1212
         color_printf("}$$\n");
1213
      }
1214
   }
1215

1216
   printf("Variables  %d\n", vu->vars.count);
1217

1218
   for (int i = 0; i < vu->vars.count; i++) {
1219
      const var_t *v = &(vu->vars.items[i]);
1220
      int col = printf("  ");
1221
      col += color_printf("$magenta$%s$$", istr(v->name));
1222
      vcode_dump_type(col, v->type, v->bounds);
1223
      if (v->flags & VAR_SIGNAL)
1224
         col += printf(", signal");
1225
      if (v->flags & VAR_HEAP)
1226
         col += printf(", heap");
1227
      if (v->flags & VAR_CONST)
1228
         col += printf(", constant");
1229
      if (v->flags & VAR_TEMP)
1230
         col += printf(", temp");
1231
      color_printf("$$\n");
1232
   }
1233

1234
   if (vu->result != VCODE_INVALID_TYPE) {
1235
      color_printf("Result     $cyan$");
1236
      vcode_dump_one_type(vu->result);
1237
      color_printf("$$\n");
1238
   }
1239

1240
   if (vu->kind == VCODE_UNIT_FUNCTION
1241
       || vu->kind == VCODE_UNIT_PROCEDURE
1242
       || vu->kind == VCODE_UNIT_PROPERTY
1243
       || (vu->kind == VCODE_UNIT_PROTECTED && vu->params.count > 0)) {
1244

1245
      printf("Parameters %d\n", vu->params.count);
1246

1247
      for (size_t i = 0; i < vu->params.count; i++) {
1248
         const param_t *p = &(vu->params.items[i]);
1249
         int col = printf("  ");
1250
         col += vcode_dump_reg(p->reg);
1251
         while (col < 8)
1252
            col += printf(" ");
1253
         col += color_printf("$magenta$%s$$", istr(p->name));
1254
         vcode_dump_type(col, p->type, p->bounds);
1255
         color_printf("$$\n");
1256
      }
1257
   }
1258

1259
   printf("Begin\n");
1260
   for (int i = 0; i < vu->blocks.count; i++) {
1261
      active_block = i;
1262
      const block_t *b = &(vu->blocks.items[i]);
1263
      for (int j = 0; j < b->ops.count; j++) {
1264
         int col = 0;
1265
         if (j == 0)
1266
            col += color_printf("  $yellow$%2d:$$ ", i);
1267
         else
1268
            col += printf("      ");
1269

1270
         const op_t *op = &(b->ops.items[j]);
1271
         switch (op->kind) {
1272
         case VCODE_OP_CMP:
1273
            {
1274
               vcode_dump_reg(op->result);
1275
               printf(" := %s ", vcode_op_string(op->kind));
1276
               vcode_dump_reg(op->args.items[0]);
1277
               switch (op->cmp) {
1278
               case VCODE_CMP_EQ:  printf(" == "); break;
1279
               case VCODE_CMP_NEQ: printf(" != "); break;
1280
               case VCODE_CMP_LT:  printf(" < "); break;
1281
               case VCODE_CMP_GT:  printf(" > "); break;
1282
               case VCODE_CMP_LEQ: printf(" <= "); break;
1283
               case VCODE_CMP_GEQ: printf(" >= "); break;
1284
               }
1285
               vcode_dump_reg(op->args.items[1]);
1286
            }
1287
            break;
1288

1289
         case VCODE_OP_CONST:
1290
            {
1291
               col += vcode_dump_reg(op->result);
1292
               col += printf(" := %s %"PRIi64"",
1293
                             vcode_op_string(op->kind),
1294
                             op->value);
1295
               vcode_dump_result_type(col, op);
1296
            }
1297
            break;
1298

1299
         case VCODE_OP_CONST_REAL:
1300
            {
1301
               col += vcode_dump_reg(op->result);
1302
               col += printf(" := %s %g",
1303
                             vcode_op_string(op->kind),
1304
                             op->real);
1305
               vcode_dump_result_type(col, op);
1306
            }
1307
            break;
1308

1309
         case VCODE_OP_ALLOC:
1310
            {
1311
               col += vcode_dump_reg(op->result);
1312
               col += printf(" := %s ", vcode_op_string(op->kind));
1313
               col += vcode_dump_reg(op->args.items[0]);
1314
               vcode_dump_result_type(col, op);
1315
            }
1316
            break;
1317

1318
         case VCODE_OP_FCALL:
1319
            {
1320
               if (op->result != VCODE_INVALID_REG) {
1321
                  col += vcode_dump_reg(op->result);
1322
                  col += printf(" := ");
1323
               }
1324
               col += color_printf("%s $magenta$%s$$ ",
1325
                                   vcode_op_string(op->kind),
1326
                                   istr(op->func));
1327
               for (int i = 0; i < op->args.count; i++) {
1328
                  if (i > 0)
1329
                     col += printf(", ");
1330
                  col += vcode_dump_reg(op->args.items[i]);
1331
               }
1332
               vcode_dump_result_type(col, op);
1333
            }
1334
            break;
1335

1336
         case VCODE_OP_SYSCALL:
1337
            {
1338
               if (op->result != VCODE_INVALID_REG) {
1339
                  col += vcode_dump_reg(op->result);
1340
                  col += printf(" := ");
1341
               }
1342
               col += color_printf("%s $magenta$%s$$ ",
1343
                                   vcode_op_string(op->kind),
1344
                                   istr(op->func));
1345
               for (int i = 1; i < op->args.count; i++) {
1346
                  if (i > 1) col += printf(", ");
1347
                  col += vcode_dump_reg(op->args.items[i]);
1348
               }
1349
               if (op->args.count > 1) col += printf(" ");
1350
               col += color_printf("locus ");
1351
               col += vcode_dump_reg(op->args.items[0]);
1352
               vcode_dump_result_type(col, op);
1353
            }
1354
            break;
1355

1356
         case VCODE_OP_MAP_CONST:
1357
         case VCODE_OP_MAP_SIGNAL:
1358
         case VCODE_OP_MAP_IMPLICIT:
1359
            {
1360
               printf("%s ", vcode_op_string(op->kind));
1361
               vcode_dump_reg(op->args.items[0]);
1362
               printf(" to ");
1363
               vcode_dump_reg(op->args.items[1]);
1364
               printf(" count ");
1365
               vcode_dump_reg(op->args.items[2]);
1366
            }
1367
            break;
1368

1369
         case VCODE_OP_DRIVE_SIGNAL:
1370
            {
1371
               printf("%s ", vcode_op_string(op->kind));
1372
               vcode_dump_reg(op->args.items[0]);
1373
               printf(" count ");
1374
               vcode_dump_reg(op->args.items[1]);
1375
            }
1376
            break;
1377

1378
         case VCODE_OP_TRANSFER_SIGNAL:
1379
            {
1380
               printf("%s ", vcode_op_string(op->kind));
1381
               vcode_dump_reg(op->args.items[0]);
1382
               printf(" to ");
1383
               vcode_dump_reg(op->args.items[1]);
1384
               printf(" count ");
1385
               vcode_dump_reg(op->args.items[2]);
1386
               printf(" reject ");
1387
               vcode_dump_reg(op->args.items[3]);
1388
               printf(" after ");
1389
               vcode_dump_reg(op->args.items[4]);
1390
            }
1391
            break;
1392

1393
         case VCODE_OP_RESOLVE_SIGNAL:
1394
            {
1395
               printf("%s ", vcode_op_string(op->kind));
1396
               vcode_dump_reg(op->args.items[0]);
1397
               printf(" resolution ");
1398
               vcode_dump_reg(op->args.items[1]);
1399
            }
1400
            break;
1401

1402
         case VCODE_OP_PACKAGE_SCOPE:
1403
         case VCODE_OP_ARRAY_SCOPE:
1404
         case VCODE_OP_RECORD_SCOPE:
1405
            {
1406
               col += printf("%s locus ", vcode_op_string(op->kind));
1407
               col += vcode_dump_reg(op->args.items[0]);
1408
               vcode_dump_type(col, op->type, op->type);
1409
            }
1410
            break;
1411

1412
         case VCODE_OP_POP_SCOPE:
1413
            {
1414
               printf("%s", vcode_op_string(op->kind));
1415
            }
1416
            break;
1417

1418
         case VCODE_OP_INIT_SIGNAL:
1419
            {
1420
               col += vcode_dump_reg(op->result);
1421
               col += printf(" := ");
1422
               col += printf("%s count ", vcode_op_string(op->kind));
1423
               col += vcode_dump_reg(op->args.items[0]);
1424
               col += printf(" size ");
1425
               col += vcode_dump_reg(op->args.items[1]);
1426
               col += printf(" value ");
1427
               col += vcode_dump_reg(op->args.items[2]);
1428
               col += printf(" flags ");
1429
               col += vcode_dump_reg(op->args.items[3]);
1430
               col += printf(" locus ");
1431
               col += vcode_dump_reg(op->args.items[4]);
1432
               if (op->args.count > 5) {
1433
                  col += printf(" offset ");
1434
                  col += vcode_dump_reg(op->args.items[5]);
1435
               }
1436
               vcode_dump_result_type(col, op);
1437
            }
1438
            break;
1439

1440
         case VCODE_OP_IMPLICIT_SIGNAL:
1441
            {
1442
               col += vcode_dump_reg(op->result);
1443
               col += printf(" := %s count ", vcode_op_string(op->kind));
1444
               col += vcode_dump_reg(op->args.items[0]);
1445
               col += printf(" size ");
1446
               col += vcode_dump_reg(op->args.items[1]);
1447
               col += printf(" locus ");
1448
               col += vcode_dump_reg(op->args.items[2]);
1449
               col += printf(" kind ");
1450
               col += vcode_dump_reg(op->args.items[3]);
1451
               col += printf(" closure ");
1452
               col += vcode_dump_reg(op->args.items[4]);
1453
            }
1454
            break;
1455

1456
         case VCODE_OP_RESOLUTION_WRAPPER:
1457
            {
1458
               col += vcode_dump_reg(op->result);
1459
               col += color_printf(" := %s ", vcode_op_string(op->kind));
1460
               col += vcode_dump_reg(op->args.items[0]);
1461
               col += printf(" nlits ");
1462
               col += vcode_dump_reg(op->args.items[1]);
1463
               vcode_dump_result_type(col, op);
1464
            }
1465
            break;
1466

1467
         case VCODE_OP_CLOSURE:
1468
         case VCODE_OP_PROTECTED_INIT:
1469
            {
1470
               col += vcode_dump_reg(op->result);
1471
               col += color_printf(" := %s $magenta$%s$$ context ",
1472
                                   vcode_op_string(op->kind), istr(op->func));
1473
               col += vcode_dump_reg(op->args.items[0]);
1474
               if (op->args.count >= 3) {
1475
                  col += printf(" path " );
1476
                  col += vcode_dump_reg(op->args.items[1]);
1477
                  col += printf(" instance " );
1478
                  col += vcode_dump_reg(op->args.items[2]);
1479
               }
1480
               vcode_dump_result_type(col, op);
1481
            }
1482
            break;
1483

1484
         case VCODE_OP_PACKAGE_INIT:
1485
            {
1486
               col += vcode_dump_reg(op->result);
1487
               col += color_printf(" := %s $magenta$%s$$",
1488
                                   vcode_op_string(op->kind), istr(op->func));
1489
               if (op->args.count > 0) {
1490
                  col += printf(" context " );
1491
                  col += vcode_dump_reg(op->args.items[0]);
1492
               }
1493
               vcode_dump_result_type(col, op);
1494
            }
1495
            break;
1496

1497
         case VCODE_OP_PROCESS_INIT:
1498
            {
1499
               color_printf("%s $magenta$%s$$ locus ",
1500
                            vcode_op_string(op->kind), istr(op->func));
1501
               vcode_dump_reg(op->args.items[0]);
1502
            }
1503
            break;
1504

1505
         case VCODE_OP_PROTECTED_FREE:
1506
            {
1507
               printf("%s ", vcode_op_string(op->kind));
1508
               vcode_dump_reg(op->args.items[0]);
1509
            }
1510
            break;
1511

1512
         case VCODE_OP_WAIT:
1513
            {
1514
               color_printf("%s $yellow$%d$$", vcode_op_string(op->kind),
1515
                            op->targets.items[0]);
1516
            }
1517
            break;
1518

1519
         case VCODE_OP_SCHED_PROCESS:
1520
            {
1521
               color_printf("%s after ", vcode_op_string(op->kind));
1522
               vcode_dump_reg(op->args.items[0]);
1523
            }
1524
            break;
1525

1526
         case VCODE_OP_JUMP:
1527
            {
1528
               color_printf("%s $yellow$%d$$", vcode_op_string(op->kind),
1529
                            op->targets.items[0]);
1530
            }
1531
            break;
1532

1533
         case VCODE_OP_COND:
1534
            {
1535
               printf("%s ", vcode_op_string(op->kind));
1536
               vcode_dump_reg(op->args.items[0]);
1537
               color_printf(" then $yellow$%d$$ else $yellow$%d$$",
1538
                            op->targets.items[0], op->targets.items[1]);
1539
            }
1540
            break;
1541

1542
         case VCODE_OP_ASSERT:
1543
            {
1544
               printf("%s ", vcode_op_string(op->kind));
1545
               vcode_dump_reg(op->args.items[0]);
1546
               if (op->args.items[2] != VCODE_INVALID_REG) {
1547
                  printf(" report ");
1548
                  vcode_dump_reg(op->args.items[2]);
1549
                  printf(" length ");
1550
                  vcode_dump_reg(op->args.items[3]);
1551
               }
1552
               printf(" severity ");
1553
               vcode_dump_reg(op->args.items[1]);
1554
               printf(" locus ");
1555
               vcode_dump_reg(op->args.items[4]);
1556
               if (op->args.count > 5) {
1557
                  printf(" hint ");
1558
                  vcode_dump_reg(op->args.items[5]);
1559
                  printf(" ");
1560
                  vcode_dump_reg(op->args.items[6]);
1561
               }
1562
            }
1563
            break;
1564

1565
         case VCODE_OP_REPORT:
1566
            {
1567
               printf("%s ", vcode_op_string(op->kind));
1568
               vcode_dump_reg(op->args.items[1]);
1569
               printf(" length ");
1570
               vcode_dump_reg(op->args.items[2]);
1571
               printf(" severity ");
1572
               vcode_dump_reg(op->args.items[0]);
1573
               printf(" locus ");
1574
               vcode_dump_reg(op->args.items[3]);
1575
            }
1576
            break;
1577

1578
         case VCODE_OP_LOAD:
1579
            {
1580
               col += vcode_dump_reg(op->result);
1581
               col += printf(" := %s ", vcode_op_string(op->kind));
1582
               col += vcode_dump_var(op->address, 0);
1583
               vcode_dump_result_type(col, op);
1584
            }
1585
            break;
1586

1587
         case VCODE_OP_LOAD_INDIRECT:
1588
            {
1589
               col += vcode_dump_reg(op->result);
1590
               col += color_printf(" := %s ", vcode_op_string(op->kind));
1591
               col += vcode_dump_reg(op->args.items[0]);
1592
               vcode_dump_result_type(col, op);
1593
            }
1594
            break;
1595

1596
         case VCODE_OP_STORE:
1597
            {
1598
               vcode_dump_var(op->address, 0);
1599
               printf(" := %s ", vcode_op_string(op->kind));
1600
               vcode_dump_reg(op->args.items[0]);
1601
            }
1602
            break;
1603

1604
         case VCODE_OP_STORE_INDIRECT:
1605
            {
1606
               vcode_dump_reg(op->args.items[1]);
1607
               printf(" := %s ", vcode_op_string(op->kind));
1608
               vcode_dump_reg(op->args.items[0]);
1609
            }
1610
            break;
1611

1612
         case VCODE_OP_INDEX:
1613
            {
1614
               col += vcode_dump_reg(op->result);
1615
               col += printf(" := %s ", vcode_op_string(op->kind));
1616
               col += vcode_dump_var(op->address, 0);
1617
               if (op->args.count > 0) {
1618
                  col += printf(" + ");
1619
                  col += vcode_dump_reg(op->args.items[0]);
1620
               }
1621
               vcode_dump_result_type(col, op);
1622
            }
1623
            break;
1624

1625
         case VCODE_OP_MUL:
1626
         case VCODE_OP_ADD:
1627
         case VCODE_OP_SUB:
1628
         case VCODE_OP_DIV:
1629
         case VCODE_OP_EXP:
1630
         case VCODE_OP_MOD:
1631
         case VCODE_OP_REM:
1632
         case VCODE_OP_OR:
1633
         case VCODE_OP_AND:
1634
         case VCODE_OP_XOR:
1635
         case VCODE_OP_XNOR:
1636
         case VCODE_OP_NAND:
1637
         case VCODE_OP_NOR:
1638
            {
1639
               col += vcode_dump_reg(op->result);
1640
               col += printf(" := %s ", vcode_op_string(op->kind));
1641
               col += vcode_dump_reg(op->args.items[0]);
1642
               switch (op->kind) {
1643
               case VCODE_OP_MUL:  col += printf(" * "); break;
1644
               case VCODE_OP_ADD:  col += printf(" + "); break;
1645
               case VCODE_OP_SUB:  col += printf(" - "); break;
1646
               case VCODE_OP_DIV:  col += printf(" / "); break;
1647
               case VCODE_OP_EXP:  col += printf(" ** "); break;
1648
               case VCODE_OP_MOD:  col += printf(" %% "); break;
1649
               case VCODE_OP_REM:  col += printf(" %% "); break;
1650
               case VCODE_OP_OR:   col += printf(" || "); break;
1651
               case VCODE_OP_AND:  col += printf(" && "); break;
1652
               case VCODE_OP_XOR:  col += printf(" ^ "); break;
1653
               case VCODE_OP_XNOR: col += printf(" !^ "); break;
1654
               case VCODE_OP_NAND: col += printf(" !& "); break;
1655
               case VCODE_OP_NOR:  col += printf(" !| "); break;
1656
               default: break;
1657
               }
1658
               col += vcode_dump_reg(op->args.items[1]);
1659
               vcode_dump_result_type(col, op);
1660
            }
1661
            break;
1662

1663
         case VCODE_OP_TRAP_ADD:
1664
         case VCODE_OP_TRAP_SUB:
1665
         case VCODE_OP_TRAP_MUL:
1666
         case VCODE_OP_TRAP_EXP:
1667
            {
1668
               col += vcode_dump_reg(op->result);
1669
               col += printf(" := %s ", vcode_op_string(op->kind));
1670
               col += vcode_dump_reg(op->args.items[0]);
1671
               switch (op->kind) {
1672
               case VCODE_OP_TRAP_ADD: col += printf(" + "); break;
1673
               case VCODE_OP_TRAP_SUB: col += printf(" - "); break;
1674
               case VCODE_OP_TRAP_MUL: col += printf(" * "); break;
1675
               case VCODE_OP_TRAP_EXP: col += printf(" ** "); break;
1676
               default: break;
1677
               }
1678
               col += vcode_dump_reg(op->args.items[1]);
1679
               col += printf(" locus ");
1680
               col += vcode_dump_reg(op->args.items[2]);
1681
               vcode_dump_result_type(col, op);
1682
            }
1683
            break;
1684

1685
         case VCODE_OP_NOT:
1686
            {
1687
               col += vcode_dump_reg(op->result);
1688
               col += printf(" := %s ", vcode_op_string(op->kind));
1689
               col += vcode_dump_reg(op->args.items[0]);
1690
               vcode_dump_result_type(col, op);
1691
            }
1692
            break;
1693

1694
         case VCODE_OP_COMMENT:
1695
            {
1696
               color_printf("$cyan$// %s$$ ", op->comment);
1697
            }
1698
            break;
1699

1700
         case VCODE_OP_CONST_ARRAY:
1701
         case VCODE_OP_CONST_RECORD:
1702
            {
1703
               col += vcode_dump_reg(op->result);
1704
               col += printf(" := const %c",
1705
                             op->kind == VCODE_OP_CONST_ARRAY ? '[' : '{');
1706
               for (int k = 0; k < op->args.count; k++) {
1707
                  if (k > 0)
1708
                     col += printf(",");
1709
                  col += vcode_dump_reg(op->args.items[k]);
1710
               }
1711

1712
               putchar(op->kind == VCODE_OP_CONST_ARRAY ? ']' : '}');
1713
               vcode_dump_result_type(col + 1, op);
1714
            }
1715
            break;
1716

1717
         case VCODE_OP_CONST_REP:
1718
            {
1719
               col += vcode_dump_reg(op->result);
1720
               col += printf(" := const [");
1721
               col += vcode_dump_reg(op->args.items[0]);
1722
               col += printf("]*%"PRIi64, op->value);
1723
               vcode_dump_result_type(col, op);
1724
            }
1725
            break;
1726

1727
         case VCODE_OP_ADDRESS_OF:
1728
         case VCODE_OP_CAST:
1729
            {
1730
               col += vcode_dump_reg(op->result);
1731
               col += printf(" := %s ", vcode_op_string(op->kind));
1732
               col += vcode_dump_reg(op->args.items[0]);
1733
               vcode_dump_result_type(col, op);
1734
            }
1735
            break;
1736

1737
         case VCODE_OP_RETURN:
1738
            {
1739
               printf("%s ", vcode_op_string(op->kind));
1740
               if (op->args.count > 0)
1741
                  vcode_dump_reg(op->args.items[0]);
1742
            }
1743
            break;
1744

1745
         case VCODE_OP_SCHED_WAVEFORM:
1746
            {
1747
               printf("%s ", vcode_op_string(op->kind));
1748
               vcode_dump_reg(op->args.items[0]);
1749
               printf(" count ");
1750
               vcode_dump_reg(op->args.items[1]);
1751
               printf(" values ");
1752
               vcode_dump_reg(op->args.items[2]);
1753
               printf(" reject ");
1754
               vcode_dump_reg(op->args.items[3]);
1755
               printf(" after ");
1756
               vcode_dump_reg(op->args.items[4]);
1757
            }
1758
            break;
1759

1760
         case VCODE_OP_FORCE:
1761
         case VCODE_OP_RELEASE:
1762
            {
1763
               printf("%s ", vcode_op_string(op->kind));
1764
               vcode_dump_reg(op->args.items[0]);
1765
               printf(" count ");
1766
               vcode_dump_reg(op->args.items[1]);
1767
               if (op->args.count > 2) {
1768
                  printf(" values ");
1769
                  vcode_dump_reg(op->args.items[2]);
1770
               }
1771
            }
1772
            break;
1773

1774
         case VCODE_OP_DISCONNECT:
1775
            {
1776
               printf("%s ", vcode_op_string(op->kind));
1777
               vcode_dump_reg(op->args.items[0]);
1778
               printf(" count ");
1779
               vcode_dump_reg(op->args.items[1]);
1780
               printf(" reject ");
1781
               vcode_dump_reg(op->args.items[2]);
1782
               printf(" after ");
1783
               vcode_dump_reg(op->args.items[3]);
1784
            }
1785
            break;
1786

1787
         case VCODE_OP_NEG:
1788
         case VCODE_OP_TRAP_NEG:
1789
         case VCODE_OP_ABS:
1790
         case VCODE_OP_RESOLVED:
1791
         case VCODE_OP_LAST_VALUE:
1792
            {
1793
               col += vcode_dump_reg(op->result);
1794
               col += printf(" := %s ", vcode_op_string(op->kind));
1795
               col += vcode_dump_reg(op->args.items[0]);
1796
               if (op->args.count > 1) {
1797
                  col += printf(" locus ");
1798
                  col += vcode_dump_reg(op->args.items[1]);
1799
               }
1800
               vcode_dump_result_type(col, op);
1801
            }
1802
            break;
1803

1804
         case VCODE_OP_SELECT:
1805
            {
1806
               col += vcode_dump_reg(op->result);
1807
               col += printf(" := %s ", vcode_op_string(op->kind));
1808
               col += vcode_dump_reg(op->args.items[0]);
1809
               col += printf(" then ");
1810
               col += vcode_dump_reg(op->args.items[1]);
1811
               col += printf(" else ");
1812
               col += vcode_dump_reg(op->args.items[2]);
1813
               vcode_dump_result_type(col, op);
1814
            }
1815
            break;
1816

1817
         case VCODE_OP_WRAP:
1818
            {
1819
               col += vcode_dump_reg(op->result);
1820
               col += printf(" := %s ", vcode_op_string(op->kind));
1821
               col += vcode_dump_reg(op->args.items[0]);
1822
               col += printf(" [");
1823
               for (int i = 1; i < op->args.count; i += 3) {
1824
                  if (i > 1)
1825
                     col += printf(", ");
1826
                  col += vcode_dump_reg(op->args.items[i + 0]);
1827
                  col += printf(" ");
1828
                  col += vcode_dump_reg(op->args.items[i + 1]);
1829
                  col += printf(" ");
1830
                  col += vcode_dump_reg(op->args.items[i + 2]);
1831
               }
1832
               col += printf("]");
1833
               vcode_dump_result_type(col, op);
1834
            }
1835
            break;
1836

1837
         case VCODE_OP_UARRAY_LEFT:
1838
         case VCODE_OP_UARRAY_RIGHT:
1839
         case VCODE_OP_UARRAY_DIR:
1840
         case VCODE_OP_UARRAY_LEN:
1841
            {
1842
               col += vcode_dump_reg(op->result);
1843
               col += printf(" := %s ", vcode_op_string(op->kind));
1844
               col += vcode_dump_reg(op->args.items[0]);
1845
               col += printf(" dim %d", op->dim);
1846
               vcode_dump_result_type(col, op);
1847
            }
1848
            break;
1849

1850
         case VCODE_OP_UNWRAP:
1851
            {
1852
               col += vcode_dump_reg(op->result);
1853
               col += printf(" := %s ", vcode_op_string(op->kind));
1854
               col += vcode_dump_reg(op->args.items[0]);
1855
               vcode_dump_result_type(col, op);
1856
            }
1857
            break;
1858

1859
         case VCODE_OP_VAR_UPREF:
1860
            {
1861
               col += vcode_dump_reg(op->result);
1862
               col += printf(" := %s %d, ", vcode_op_string(op->kind),
1863
                             op->hops);
1864
               col += vcode_dump_var(op->address, op->hops);
1865
               vcode_dump_result_type(col, op);
1866
            }
1867
            break;
1868

1869
         case VCODE_OP_CONTEXT_UPREF:
1870
            {
1871
               col += vcode_dump_reg(op->result);
1872
               col += printf(" := %s %d", vcode_op_string(op->kind), op->hops);
1873
               vcode_dump_result_type(col, op);
1874
            }
1875
            break;
1876

1877
         case VCODE_OP_ACTIVE:
1878
         case VCODE_OP_EVENT:
1879
         case VCODE_OP_DRIVING:
1880
            {
1881
               col += vcode_dump_reg(op->result);
1882
               col += printf(" := %s ", vcode_op_string(op->kind));
1883
               col += vcode_dump_reg(op->args.items[0]);
1884
               col += printf(" length ");
1885
               col += vcode_dump_reg(op->args.items[1]);
1886
               vcode_dump_result_type(col, op);
1887
            }
1888
            break;
1889

1890
         case VCODE_OP_RECORD_REF:
1891
            {
1892
               col += vcode_dump_reg(op->result);
1893
               col += printf(" := %s ", vcode_op_string(op->kind));
1894
               col += vcode_dump_reg(op->args.items[0]);
1895
               col += printf(" field %d", op->field);
1896
               vcode_dump_result_type(col, op);
1897
            }
1898
            break;
1899

1900
         case VCODE_OP_ARRAY_REF:
1901
            {
1902
               col += vcode_dump_reg(op->result);
1903
               col += printf(" := %s ", vcode_op_string(op->kind));
1904
               col += vcode_dump_reg(op->args.items[0]);
1905
               col += printf(" offset ");
1906
               col += vcode_dump_reg(op->args.items[1]);
1907
               vcode_dump_result_type(col, op);
1908
            }
1909
            break;
1910

1911
         case VCODE_OP_COPY:
1912
            {
1913
               vcode_dump_reg(op->args.items[0]);
1914
               printf(" := %s ", vcode_op_string(op->kind));
1915
               vcode_dump_reg(op->args.items[1]);
1916
               if (op->args.count > 2) {
1917
                  printf(" count " );
1918
                  vcode_dump_reg(op->args.items[2]);
1919
               }
1920
            }
1921
            break;
1922

1923
         case VCODE_OP_SCHED_EVENT:
1924
         case VCODE_OP_CLEAR_EVENT:
1925
            {
1926
               printf("%s on ", vcode_op_string(op->kind));
1927
               vcode_dump_reg(op->args.items[0]);
1928
               printf(" count ");
1929
               vcode_dump_reg(op->args.items[1]);
1930
            }
1931
            break;
1932

1933
         case VCODE_OP_PCALL:
1934
            {
1935
               color_printf("%s $magenta$%s$$", vcode_op_string(op->kind),
1936
                            istr(op->func));
1937
               for (int i = 0; i < op->args.count; i++) {
1938
                  printf("%s", i > 0 ? ", " : " ");
1939
                  vcode_dump_reg(op->args.items[i]);
1940
               }
1941
               if (op->targets.count > 0)
1942
                  color_printf(" resume $yellow$%d$$", op->targets.items[0]);
1943
            }
1944
            break;
1945

1946
         case VCODE_OP_RESUME:
1947
            {
1948
               color_printf("%s $magenta$%s$$", vcode_op_string(op->kind),
1949
                            istr(op->func));
1950
            }
1951
            break;
1952

1953
         case VCODE_OP_MEMSET:
1954
            {
1955
               vcode_dump_reg(op->args.items[0]);
1956
               printf(" := %s ", vcode_op_string(op->kind));
1957
               vcode_dump_reg(op->args.items[1]);
1958
               printf(" length ");
1959
               vcode_dump_reg(op->args.items[2]);
1960
            }
1961
            break;
1962

1963
         case VCODE_OP_CASE:
1964
            {
1965
               printf("%s ", vcode_op_string(op->kind));
1966
               vcode_dump_reg(op->args.items[0]);
1967
               color_printf(" default $yellow$%d$$", op->targets.items[0]);
1968
               for (int i = 1; i < op->args.count; i++) {
1969
                  printf(" [");
1970
                  vcode_dump_reg(op->args.items[i]);
1971
                  color_printf(" $yellow$%d$$]", op->targets.items[i]);
1972
               }
1973
            }
1974
            break;
1975

1976
         case VCODE_OP_FILE_OPEN:
1977
            {
1978
               printf("%s ", vcode_op_string(op->kind));
1979
               vcode_dump_reg(op->args.items[0]);
1980
               printf(" name ");
1981
               vcode_dump_reg(op->args.items[1]);
1982
               printf(" length ");
1983
               vcode_dump_reg(op->args.items[2]);
1984
               printf(" kind ");
1985
               vcode_dump_reg(op->args.items[3]);
1986
               if (op->args.count == 5) {
1987
                  printf(" status ");
1988
                  vcode_dump_reg(op->args.items[4]);
1989
               }
1990
            }
1991
            break;
1992

1993
         case VCODE_OP_FILE_WRITE:
1994
            {
1995
               printf("%s ", vcode_op_string(op->kind));
1996
               vcode_dump_reg(op->args.items[0]);
1997
               printf(" value ");
1998
               vcode_dump_reg(op->args.items[1]);
1999
               if (op->args.count == 3) {
2000
                  printf(" length ");
2001
                  vcode_dump_reg(op->args.items[2]);
2002
               }
2003
            }
2004
            break;
2005

2006
         case VCODE_OP_FILE_READ:
2007
            {
2008
               printf("%s ", vcode_op_string(op->kind));
2009
               vcode_dump_reg(op->args.items[0]);
2010
               printf(" ptr ");
2011
               vcode_dump_reg(op->args.items[1]);
2012
               if (op->args.count >= 3) {
2013
                  printf(" inlen ");
2014
                  vcode_dump_reg(op->args.items[2]);
2015
                  if (op->args.count >= 4) {
2016
                     printf(" outlen ");
2017
                     vcode_dump_reg(op->args.items[3]);
2018
                  }
2019
               }
2020
            }
2021
            break;
2022

2023
         case VCODE_OP_NULL:
2024
         case VCODE_OP_NEW:
2025
            {
2026
               col += vcode_dump_reg(op->result);
2027
               col += printf(" := %s", vcode_op_string(op->kind));
2028
               if (op->args.count == 1) {
2029
                  col += printf(" length ");
2030
                  col += vcode_dump_reg(op->args.items[0]);
2031
               }
2032
               vcode_dump_result_type(col, op);
2033
            }
2034
            break;
2035

2036
         case VCODE_OP_NULL_CHECK:
2037
            {
2038
               col += printf("%s ", vcode_op_string(op->kind));
2039
               col += vcode_dump_reg(op->args.items[0]);
2040
               col += printf(" locus ");
2041
               col += vcode_dump_reg(op->args.items[1]);
2042
            }
2043
            break;
2044

2045
         case VCODE_OP_DEALLOCATE:
2046
            {
2047
               col += printf("%s ", vcode_op_string(op->kind));
2048
               col += vcode_dump_reg(op->args.items[0]);
2049
            }
2050
            break;
2051

2052
         case VCODE_OP_ALL:
2053
            {
2054
               col += vcode_dump_reg(op->result);
2055
               col += printf(" := %s ", vcode_op_string(op->kind));
2056
               col += vcode_dump_reg(op->args.items[0]);
2057
               vcode_dump_result_type(col, op);
2058
            }
2059
            break;
2060

2061
         case VCODE_OP_LAST_EVENT:
2062
         case VCODE_OP_LAST_ACTIVE:
2063
         case VCODE_OP_DRIVING_VALUE:
2064
            {
2065
               col += vcode_dump_reg(op->result);
2066
               col += printf(" := %s ", vcode_op_string(op->kind));
2067
               col += vcode_dump_reg(op->args.items[0]);
2068
               if (op->args.count > 1) {
2069
                  col += printf(" length ");
2070
                  col += vcode_dump_reg(op->args.items[1]);
2071
               }
2072
               vcode_dump_result_type(col, op);
2073
            }
2074
            break;
2075

2076
         case VCODE_OP_ALIAS_SIGNAL:
2077
            {
2078
               printf("%s ", vcode_op_string(op->kind));
2079
               vcode_dump_reg(op->args.items[0]);
2080
               printf(" locus ");
2081
               vcode_dump_reg(op->args.items[1]);
2082
            }
2083
            break;
2084

2085
         case VCODE_OP_LENGTH_CHECK:
2086
            {
2087
               col += printf("%s left ", vcode_op_string(op->kind));
2088
               col += vcode_dump_reg(op->args.items[0]);
2089
               col += printf(" == right ");
2090
               col += vcode_dump_reg(op->args.items[1]);
2091
               col += printf(" locus ");
2092
               col += vcode_dump_reg(op->args.items[2]);
2093
               if (op->args.count > 3) {
2094
                  col += printf(" dim ");
2095
                  col += vcode_dump_reg(op->args.items[3]);
2096
               }
2097
            }
2098
            break;
2099

2100
         case VCODE_OP_EXPONENT_CHECK:
2101
         case VCODE_OP_ZERO_CHECK:
2102
            {
2103
               col += printf("%s ", vcode_op_string(op->kind));
2104
               col += vcode_dump_reg(op->args.items[0]);
2105
               col += printf(" locus ");
2106
               col += vcode_dump_reg(op->args.items[1]);
2107
            }
2108
            break;
2109

2110
         case VCODE_OP_INDEX_CHECK:
2111
         case VCODE_OP_RANGE_CHECK:
2112
            {
2113
               col += printf("%s ", vcode_op_string(op->kind));
2114
               col += vcode_dump_reg(op->args.items[0]);
2115
               col += printf(" left ");
2116
               col += vcode_dump_reg(op->args.items[1]);
2117
               col += printf(" right ");
2118
               col += vcode_dump_reg(op->args.items[2]);
2119
               col += printf(" dir ");
2120
               col += vcode_dump_reg(op->args.items[3]);
2121
               col += printf(" locus ");
2122
               col += vcode_dump_reg(op->args.items[4]);
2123
               if (op->args.items[5] != op->args.items[4]) {
2124
                  col += printf(" hint ");
2125
                  col += vcode_dump_reg(op->args.items[5]);
2126
               }
2127
            }
2128
            break;
2129

2130
         case VCODE_OP_DIR_CHECK:
2131
            {
2132
               col += printf("%s ", vcode_op_string(op->kind));
2133
               col += vcode_dump_reg(op->args.items[0]);
2134
               col += printf(" == ");
2135
               col += vcode_dump_reg(op->args.items[1]);
2136
               col += printf(" locus ");
2137
               col += vcode_dump_reg(op->args.items[2]);
2138
            }
2139
            break;
2140

2141
         case VCODE_OP_DEBUG_OUT:
2142
            {
2143
               col += printf("%s ", vcode_op_string(op->kind));
2144
               col += vcode_dump_reg(op->args.items[0]);
2145
            }
2146
            break;
2147

2148
         case VCODE_OP_COVER_STMT:
2149
         case VCODE_OP_COVER_BRANCH:
2150
         case VCODE_OP_COVER_EXPR:
2151
            {
2152
               printf("%s %u ", vcode_op_string(op->kind), op->tag);
2153
            }
2154
            break;
2155

2156
         case VCODE_OP_COVER_TOGGLE:
2157
         case VCODE_OP_COVER_STATE:
2158
            {
2159
               printf("%s %u ", vcode_op_string(op->kind), op->tag);
2160
               vcode_dump_reg(op->args.items[0]);
2161
            }
2162
            break;
2163

2164
         case VCODE_OP_UNDEFINED:
2165
            {
2166
               col += vcode_dump_reg(op->result);
2167
               col += printf(" := %s", vcode_op_string(op->kind));
2168
               vcode_dump_result_type(col, op);
2169
            }
2170
            break;
2171

2172
         case VCODE_OP_RANGE_LENGTH:
2173
         case VCODE_OP_RANGE_NULL:
2174
            {
2175
               col += vcode_dump_reg(op->result);
2176
               col += printf(" := %s left ", vcode_op_string(op->kind));
2177
               vcode_dump_reg(op->args.items[0]);
2178
               col += printf(" right ");
2179
               vcode_dump_reg(op->args.items[1]);
2180
               col += printf(" dir ");
2181
               col += vcode_dump_reg(op->args.items[2]);
2182
               vcode_dump_result_type(col, op);
2183
            }
2184
            break;
2185

2186
         case VCODE_OP_LINK_PACKAGE:
2187
            {
2188
               col += vcode_dump_reg(op->result);
2189
               col += color_printf(" := %s $magenta$%s$$",
2190
                                   vcode_op_string(op->kind), istr(op->ident));
2191
               if (op->args.count > 0) {
2192
                  col += printf(" locus ");
2193
                  col += vcode_dump_reg(op->args.items[0]);
2194
               }
2195
               vcode_dump_result_type(col, op);
2196
            }
2197
            break;
2198

2199
         case VCODE_OP_LINK_VAR:
2200
            {
2201
               col += vcode_dump_reg(op->result);
2202
               col += color_printf(" := %s ", vcode_op_string(op->kind));
2203
               col += vcode_dump_reg(op->args.items[0]);
2204
               col += color_printf(" $magenta$%s$$", istr(op->ident));
2205
               vcode_dump_result_type(col, op);
2206
            }
2207
            break;
2208

2209
         case VCODE_OP_UNREACHABLE:
2210
            {
2211
               printf("%s", vcode_op_string(op->kind));
2212
               if (op->args.count > 0) {
2213
                  printf(" ");
2214
                  vcode_dump_reg(op->args.items[0]);
2215
               }
2216
            }
2217
            break;
2218

2219
         case VCODE_OP_DEBUG_LOCUS:
2220
            {
2221
               col += vcode_dump_reg(op->result);
2222
               col += color_printf(" := %s $magenta$",
2223
                                   vcode_op_string(op->kind));
2224

2225
               tree_t t = tree_from_object(op->object);
2226
               if (t != NULL)
2227
                  col += printf("%s@", tree_kind_str(tree_kind(t)));
2228

2229
               col += color_printf("%p$$", op->object);
2230
               vcode_dump_result_type(col, op);
2231
            }
2232
            break;
2233

2234
         case VCODE_OP_ENTER_STATE:
2235
            {
2236
               printf("%s ", vcode_op_string(op->kind));
2237
               vcode_dump_reg(op->args.items[0]);
2238
               if (op->args.count > 1) {
2239
                  printf(" strong ");
2240
                  vcode_dump_reg(op->args.items[1]);
2241
               }
2242
            }
2243
            break;
2244

2245
         case VCODE_OP_REFLECT_VALUE:
2246
            {
2247
               col += vcode_dump_reg(op->result);
2248
               col += printf(" := %s ", vcode_op_string(op->kind));
2249
               vcode_dump_reg(op->args.items[0]);
2250
               col += printf(" context ");
2251
               vcode_dump_reg(op->args.items[1]);
2252
               col += printf(" locus ");
2253
               col += vcode_dump_reg(op->args.items[2]);
2254
               if (op->args.count > 3) {
2255
                  col += printf(" bounds ");
2256
                  col += vcode_dump_reg(op->args.items[3]);
2257
               }
2258
               vcode_dump_result_type(col, op);
2259
            }
2260
            break;
2261

2262
         case VCODE_OP_REFLECT_SUBTYPE:
2263
            {
2264
               col += vcode_dump_reg(op->result);
2265
               col += printf(" := %s context ", vcode_op_string(op->kind));
2266
               vcode_dump_reg(op->args.items[0]);
2267
               col += printf(" locus ");
2268
               col += vcode_dump_reg(op->args.items[1]);
2269
               if (op->args.count > 2) {
2270
                  col += printf(" bounds ");
2271
                  col += vcode_dump_reg(op->args.items[2]);
2272
               }
2273
               vcode_dump_result_type(col, op);
2274
            }
2275
            break;
2276

2277
         case VCODE_OP_FUNCTION_TRIGGER:
2278
            {
2279
               col += vcode_dump_reg(op->result);
2280
               col += color_printf(" := %s $magenta$%s$$ ",
2281
                                   vcode_op_string(op->kind), istr(op->func));
2282
               for (int i = 0; i < op->args.count; i++) {
2283
                  if (i > 0) col += printf(", ");
2284
                  col += vcode_dump_reg(op->args.items[i]);
2285
               }
2286
               vcode_dump_result_type(col, op);
2287
            }
2288
            break;
2289

2290
         case VCODE_OP_OR_TRIGGER:
2291
         case VCODE_OP_CMP_TRIGGER:
2292
            {
2293
               col += vcode_dump_reg(op->result);
2294
               col += color_printf(" := %s ", vcode_op_string(op->kind));
2295
               col += vcode_dump_reg(op->args.items[0]);
2296
               if (op->kind == VCODE_OP_OR_TRIGGER)
2297
                  col += printf(" || ");
2298
               else
2299
                  col += printf(" == ");
2300
               col += vcode_dump_reg(op->args.items[1]);
2301
               vcode_dump_result_type(col, op);
2302
            }
2303
            break;
2304

2305
         case VCODE_OP_ADD_TRIGGER:
2306
            {
2307
               printf("%s ", vcode_op_string(op->kind));
2308
               vcode_dump_reg(op->args.items[0]);
2309
            }
2310
            break;
2311

2312
         case VCODE_OP_PUT_CONVERSION:
2313
            {
2314
               color_printf("%s ", vcode_op_string(op->kind));
2315
               vcode_dump_reg(op->args.items[0]);
2316
               printf(" signal ");
2317
               vcode_dump_reg(op->args.items[1]);
2318
               printf(" count ");
2319
               vcode_dump_reg(op->args.items[2]);
2320
               printf(" values ");
2321
               vcode_dump_reg(op->args.items[3]);
2322
            }
2323
            break;
2324

2325
         case VCODE_OP_PORT_CONVERSION:
2326
            {
2327
               col += vcode_dump_reg(op->result);
2328
               col += color_printf(" := %s ", vcode_op_string(op->kind));
2329
               col += vcode_dump_reg(op->args.items[0]);
2330
               if (op->args.count > 1) {
2331
                  col += printf(" effective ");
2332
                  col += vcode_dump_reg(op->args.items[1]);
2333
               }
2334
               vcode_dump_result_type(col, op);
2335
            }
2336
            break;
2337

2338
         case VCODE_OP_CONVERT_IN:
2339
         case VCODE_OP_CONVERT_OUT:
2340
            {
2341
               color_printf("%s ", vcode_op_string(op->kind));
2342
               vcode_dump_reg(op->args.items[0]);
2343
               printf(" signal ");
2344
               vcode_dump_reg(op->args.items[1]);
2345
               printf(" count ");
2346
               vcode_dump_reg(op->args.items[2]);
2347
            }
2348
            break;
2349

2350
         case VCODE_OP_BIND_FOREIGN:
2351
            {
2352
               color_printf("%s ", vcode_op_string(op->kind));
2353
               vcode_dump_reg(op->args.items[0]);
2354
               printf(" length ");
2355
               vcode_dump_reg(op->args.items[1]);
2356
               if (op->args.count > 2) {
2357
                  printf(" locus ");
2358
                  vcode_dump_reg(op->args.items[1]);
2359
               }
2360
            }
2361
            break;
2362

2363
         case VCODE_OP_INSTANCE_NAME:
2364
         case VCODE_OP_BIND_EXTERNAL:
2365
            {
2366
               col += vcode_dump_reg(op->result);
2367
               col += color_printf(" := %s ", vcode_op_string(op->kind));
2368
               col += vcode_dump_reg(op->args.items[0]);
2369
               col += color_printf(" scope $magenta$%s$$ ", istr(op->ident));
2370
               for (int i = 1; i < op->args.count; i++) {
2371
                  if (i > 1) col += printf(", ");
2372
                  col += vcode_dump_reg(op->args.items[i]);
2373
               }
2374
               vcode_dump_result_type(col, op);
2375
            }
2376
            break;
2377
         }
2378

2379
         if (j == mark_op && i == old_block)
2380
            color_printf("\t $red$<----$$");
2381

2382
         color_printf("$$\n");
2383

2384
         if (callback != NULL)
2385
            (*callback)(j, arg);
2386
      }
2387

2388
      if (b->ops.count == 0)
2389
         color_printf("  $yellow$%2d:$$ $red$Empty basic block$$\n", i);
2390
   }
2391

2392
   printf("\n");
2393
   fflush(stdout);
2394

2395
   active_block = old_block;
2396
}
2397
LCOV_EXCL_STOP
2398

2399
bool vtype_eq(vcode_type_t a, vcode_type_t b)
41,039,530✔
2400
{
2401
   assert(active_unit != NULL);
41,660,096✔
2402

2403
   if (a == b)
41,660,096✔
2404
      return true;
2405
   else {
2406
      const vtype_t *at = vcode_type_data(a);
37,976,579✔
2407
      const vtype_t *bt = vcode_type_data(b);
37,976,579✔
2408

2409
      if (at->kind != bt->kind)
37,976,579✔
2410
         return false;
2411

2412
      switch (at->kind) {
16,918,405✔
2413
      case VCODE_TYPE_INT:
14,673,100✔
2414
         return (at->low == bt->low) && (at->high == bt->high);
27,331,295✔
2415
      case VCODE_TYPE_REAL:
929,270✔
2416
         return (at->rlow == bt->rlow) && (at->rhigh == bt->rhigh);
1,789,327✔
2417
      case VCODE_TYPE_CARRAY:
110,274✔
2418
         return at->size == bt->size && vtype_eq(at->elem, bt->elem);
119,871✔
2419
      case VCODE_TYPE_UARRAY:
84,318✔
2420
         return at->dims == bt->dims && vtype_eq(at->elem, bt->elem);
106,958✔
2421
      case VCODE_TYPE_POINTER:
516,101✔
2422
      case VCODE_TYPE_ACCESS:
2423
         return vtype_eq(at->pointed, bt->pointed);
516,101✔
2424
      case VCODE_TYPE_OFFSET:
2425
      case VCODE_TYPE_OPAQUE:
2426
      case VCODE_TYPE_DEBUG_LOCUS:
2427
      case VCODE_TYPE_TRIGGER:
2428
      case VCODE_TYPE_CONVERSION:
2429
         return true;
2430
      case VCODE_TYPE_RESOLUTION:
104,465✔
2431
      case VCODE_TYPE_CLOSURE:
2432
      case VCODE_TYPE_SIGNAL:
2433
      case VCODE_TYPE_FILE:
2434
         return vtype_eq(at->base, bt->base);
104,465✔
2435
      case VCODE_TYPE_RECORD:
84,928✔
2436
      case VCODE_TYPE_CONTEXT:
2437
         return at->name == bt->name;
84,928✔
2438
      }
2439

2440
      return false;
×
2441
   }
2442
}
2443

UNCOV
2444
void vcode_dump(void)
×
2445
{
UNCOV
2446
   vcode_dump_with_mark(-1, NULL, NULL);
×
UNCOV
2447
}
×
2448

2449
static vcode_type_t vtype_new(vtype_t *new)
3,450,696✔
2450
{
2451
   int index = active_unit->types.count - 1;
3,450,696✔
2452
   vcode_type_t type = MAKE_HANDLE(active_unit->depth, index);
3,450,696✔
2453

2454
   for (int i = 0; i < index; i++) {
37,630,994✔
2455
      vcode_type_t this = MAKE_HANDLE(active_unit->depth, i);
36,946,739✔
2456
      if (vtype_eq(this, type)) {
36,946,739✔
2457
         active_unit->types.count--;
2,766,441✔
2458
         return this;
2,766,441✔
2459
      }
2460
   }
2461

2462
   return type;
2463
}
2464

2465
vcode_type_t vtype_int(int64_t low, int64_t high)
2,383,117✔
2466
{
2467
   assert(active_unit != NULL);
2,383,117✔
2468

2469
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
2,383,117✔
2470
   n->kind = VCODE_TYPE_INT;
2,383,117✔
2471
   n->low  = low;
2,383,117✔
2472
   n->high = high;
2,383,117✔
2473

2474
   switch (bits_for_range(low, high)) {
2,383,117✔
2475
   case 64:
136,738✔
2476
      n->repr = low < 0 ? VCODE_REPR_I64 : VCODE_REPR_U64;
136,738✔
2477
      break;
136,738✔
2478
   case 32:
644,243✔
2479
      n->repr = low < 0 ? VCODE_REPR_I32 : VCODE_REPR_U32;
644,243✔
2480
      break;
644,243✔
2481
   case 16:
4,460✔
2482
      n->repr = low < 0 ? VCODE_REPR_I16 : VCODE_REPR_U16;
4,460✔
2483
      break;
4,460✔
2484
   case 8:
922,155✔
2485
      n->repr = low < 0 ? VCODE_REPR_I8 : VCODE_REPR_U8;
922,155✔
2486
      break;
922,155✔
2487
   case 1:
675,520✔
2488
      n->repr = VCODE_REPR_U1;
675,520✔
2489
      break;
675,520✔
2490
   case 0:
1✔
2491
      n->repr = VCODE_REPR_I64;    // Null range
1✔
2492
      break;
1✔
UNCOV
2493
   default:
×
2494
      fatal_trace("cannot represent %"PRIi64"..%"PRIi64, low, high);
2495
   }
2496

2497
   return vtype_new(n);
2,383,117✔
2498
}
2499

2500
vcode_type_t vtype_bool(void)
343,852✔
2501
{
2502
   return vtype_int(0, 1);
343,852✔
2503
}
2504

2505
vcode_type_t vtype_carray(int size, vcode_type_t elem, vcode_type_t bounds)
56,464✔
2506
{
2507
   assert(active_unit != NULL);
56,464✔
2508

2509
   const vtype_kind_t ekind = vtype_kind(elem);
56,464✔
2510
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
56,464✔
2511
                "array types may not be nested");
2512

2513
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
56,464✔
2514
   memset(n, '\0', sizeof(vtype_t));
56,464✔
2515
   n->kind   = VCODE_TYPE_CARRAY;
56,464✔
2516
   n->elem   = elem;
56,464✔
2517
   n->bounds = bounds;
56,464✔
2518
   n->size   = MAX(size, 0);
56,464✔
2519

2520
   return vtype_new(n);
56,464✔
2521
}
2522

2523
vcode_type_t vtype_find_named_record(ident_t name)
37,907✔
2524
{
2525
   assert(active_unit != NULL);
37,907✔
2526

2527
   for (int i = 0; i < active_unit->types.count; i++) {
480,763✔
2528
      vtype_t *other = &(active_unit->types.items[i]);
469,071✔
2529
      if (other->kind == VCODE_TYPE_RECORD && other->name == name)
469,071✔
2530
         return MAKE_HANDLE(active_unit->depth, i);
26,215✔
2531
   }
2532

2533
   return VCODE_INVALID_TYPE;
2534
}
2535

2536
vcode_type_t vtype_named_record(ident_t name, const vcode_type_t *field_types,
11,692✔
2537
                                int nfields)
2538
{
2539
   assert(active_unit != NULL);
11,692✔
2540

2541
   vtype_t *data = NULL;
11,692✔
2542
   vcode_type_t handle = vtype_find_named_record(name);
11,692✔
2543
   if (handle == VCODE_INVALID_TYPE) {
11,692✔
2544
      data = vtype_array_alloc(&(active_unit->types));
5,846✔
2545
      memset(data, '\0', sizeof(vtype_t));
5,846✔
2546
      data->kind = VCODE_TYPE_RECORD;
5,846✔
2547
      data->name = name;
5,846✔
2548

2549
      handle = vtype_new(data);
5,846✔
2550
   }
2551
   else {
2552
      data = vcode_type_data(handle);
5,846✔
2553
      VCODE_ASSERT(data->fields.count == 0,
5,846✔
2554
                    "record type %s already defined", istr(name));
2555
   }
2556

2557
   vcode_type_array_resize(&(data->fields), 0, VCODE_INVALID_TYPE);
11,692✔
2558
   for (int i = 0; i < nfields; i++)
31,207✔
2559
      vcode_type_array_add(&(data->fields), field_types[i]);
19,515✔
2560

2561
   return handle;
11,692✔
2562
}
2563

2564
vcode_type_t vtype_uarray(int ndim, vcode_type_t elem, vcode_type_t bounds)
78,790✔
2565
{
2566
   assert(active_unit != NULL);
78,790✔
2567

2568
   const vtype_kind_t ekind = vtype_kind(elem);
78,790✔
2569
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
78,790✔
2570
                "array types may not be nested");
2571

2572
   VCODE_ASSERT(ndim > 0, "uarray must have at least one dimension");
78,790✔
2573

2574
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
78,790✔
2575
   memset(n, '\0', sizeof(vtype_t));
78,790✔
2576
   n->kind   = VCODE_TYPE_UARRAY;
78,790✔
2577
   n->elem   = elem;
78,790✔
2578
   n->bounds = bounds;
78,790✔
2579
   n->dims   = ndim;
78,790✔
2580

2581
   return vtype_new(n);
78,790✔
2582
}
2583

2584
vcode_type_t vtype_pointer(vcode_type_t to)
218,053✔
2585
{
2586
   assert(active_unit != NULL);
218,053✔
2587

2588
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
218,053✔
2589
   n->kind    = VCODE_TYPE_POINTER;
218,053✔
2590
   n->pointed = to;
218,053✔
2591

2592
   VCODE_ASSERT(vtype_kind(to) != VCODE_TYPE_CARRAY,
218,053✔
2593
                "cannot get pointer to carray type");
2594

2595
   return vtype_new(n);
218,053✔
2596
}
2597

2598
vcode_type_t vtype_access(vcode_type_t to)
9,393✔
2599
{
2600
   assert(active_unit != NULL);
9,393✔
2601

2602
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
9,393✔
2603
   n->kind    = VCODE_TYPE_ACCESS;
9,393✔
2604
   n->pointed = to;
9,393✔
2605

2606
   return vtype_new(n);
9,393✔
2607
}
2608

2609
vcode_type_t vtype_signal(vcode_type_t base)
39,399✔
2610
{
2611
   assert(active_unit != NULL);
39,399✔
2612

2613
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
39,399✔
2614
   n->kind = VCODE_TYPE_SIGNAL;
39,399✔
2615
   n->base = base;
39,399✔
2616

2617
   VCODE_ASSERT(vtype_is_scalar(base), "signal base type must be scalar");
39,399✔
2618

2619
   return vtype_new(n);
39,399✔
2620
}
2621

2622
vcode_type_t vtype_resolution(vcode_type_t base)
8,199✔
2623
{
2624
   assert(active_unit != NULL);
8,199✔
2625

2626
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
8,199✔
2627
   n->kind = VCODE_TYPE_RESOLUTION;
8,199✔
2628
   n->base = base;
8,199✔
2629

2630
   return vtype_new(n);
8,199✔
2631
}
2632

2633
vcode_type_t vtype_closure(vcode_type_t result)
5,333✔
2634
{
2635
   assert(active_unit != NULL);
5,333✔
2636

2637
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
5,333✔
2638
   n->kind = VCODE_TYPE_CLOSURE;
5,333✔
2639
   n->base = result;
5,333✔
2640

2641
   return vtype_new(n);
5,333✔
2642
}
2643

2644
vcode_type_t vtype_context(ident_t name)
59,657✔
2645
{
2646
   assert(active_unit != NULL);
59,657✔
2647
   assert(name != NULL);
59,657✔
2648

2649
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
59,657✔
2650
   n->kind = VCODE_TYPE_CONTEXT;
59,657✔
2651
   n->name = name;
59,657✔
2652

2653
   return vtype_new(n);
59,657✔
2654
}
2655

2656
vcode_type_t vtype_file(vcode_type_t base)
1,827✔
2657
{
2658
   assert(active_unit != NULL);
1,827✔
2659

2660
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
1,827✔
2661
   n->kind = VCODE_TYPE_FILE;
1,827✔
2662
   n->base = base;
1,827✔
2663

2664
   return vtype_new(n);
1,827✔
2665
}
2666

2667
vcode_type_t vtype_offset(void)
308,913✔
2668
{
2669
   assert(active_unit != NULL);
308,913✔
2670

2671
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
308,913✔
2672
   n->kind = VCODE_TYPE_OFFSET;
308,913✔
2673
   n->low  = INT64_MIN;
308,913✔
2674
   n->high = INT64_MAX;
308,913✔
2675
   n->repr = VCODE_REPR_I64;
308,913✔
2676

2677
   return vtype_new(n);
308,913✔
2678
}
2679

2680
vcode_type_t vtype_time(void)
18,149✔
2681
{
2682
   return vtype_int(INT64_MIN, INT64_MAX);
18,149✔
2683
}
2684

2685
vcode_type_t vtype_char(void)
8,872✔
2686
{
2687
   return vtype_int(0, 255);
8,872✔
2688
}
2689

2690
vcode_type_t vtype_opaque(void)
3,474✔
2691
{
2692
   assert(active_unit != NULL);
3,474✔
2693

2694
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
3,474✔
2695
   n->kind = VCODE_TYPE_OPAQUE;
3,474✔
2696

2697
   return vtype_new(n);
3,474✔
2698
}
2699

2700
vcode_type_t vtype_debug_locus(void)
159,868✔
2701
{
2702
   assert(active_unit != NULL);
159,868✔
2703

2704
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
159,868✔
2705
   n->kind = VCODE_TYPE_DEBUG_LOCUS;
159,868✔
2706

2707
   return vtype_new(n);
159,868✔
2708
}
2709

2710
vcode_type_t vtype_trigger(void)
416✔
2711
{
2712
   assert(active_unit != NULL);
416✔
2713

2714
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
416✔
2715
   n->kind = VCODE_TYPE_TRIGGER;
416✔
2716

2717
   return vtype_new(n);
416✔
2718
}
2719

2720
vcode_type_t vtype_conversion(void)
426✔
2721
{
2722
   assert(active_unit != NULL);
426✔
2723

2724
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
426✔
2725
   n->kind = VCODE_TYPE_CONVERSION;
426✔
2726

2727
   return vtype_new(n);
426✔
2728
}
2729

2730
vcode_type_t vtype_real(double low, double high)
111,521✔
2731
{
2732
   assert(active_unit != NULL);
111,521✔
2733

2734
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
111,521✔
2735
   n->kind  = VCODE_TYPE_REAL;
111,521✔
2736
   n->rlow  = low;
111,521✔
2737
   n->rhigh = high;
111,521✔
2738

2739
   return vtype_new(n);
111,521✔
2740
}
2741

2742
vtype_kind_t vtype_kind(vcode_type_t type)
5,024,725✔
2743
{
2744
   vtype_t *vt = vcode_type_data(type);
5,024,725✔
2745
   return vt->kind;
5,024,725✔
2746
}
2747

2748
vtype_repr_t vtype_repr(vcode_type_t type)
59,797✔
2749
{
2750
   vtype_t *vt = vcode_type_data(type);
59,797✔
2751
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
59,797✔
2752
   return vt->repr;
59,797✔
2753
}
2754

2755
vcode_type_t vtype_elem(vcode_type_t type)
164,164✔
2756
{
2757
   vtype_t *vt = vcode_type_data(type);
164,164✔
2758
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
164,164✔
2759
   return vt->elem;
164,164✔
2760
}
2761

2762
vcode_type_t vtype_base(vcode_type_t type)
53,930✔
2763
{
2764
   vtype_t *vt = vcode_type_data(type);
53,930✔
2765
   assert(vt->kind == VCODE_TYPE_SIGNAL || vt->kind == VCODE_TYPE_FILE
53,930✔
2766
          || vt->kind == VCODE_TYPE_RESOLUTION
2767
          || vt->kind == VCODE_TYPE_CLOSURE);
2768
   return vt->base;
53,930✔
2769
}
2770

2771
vcode_type_t vtype_bounds(vcode_type_t type)
22,456✔
2772
{
2773
   vtype_t *vt = vcode_type_data(type);
22,456✔
2774
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
22,456✔
2775
   return vt->bounds;
22,456✔
2776
}
2777

2778
unsigned vtype_dims(vcode_type_t type)
43,776✔
2779
{
2780
   vtype_t *vt = vcode_type_data(type);
43,776✔
2781
   assert(vt->kind == VCODE_TYPE_UARRAY);
43,776✔
2782
   return vt->dims;
43,776✔
2783
}
2784

2785
unsigned vtype_size(vcode_type_t type)
54,116✔
2786
{
2787
   vtype_t *vt = vcode_type_data(type);
54,116✔
2788
   assert(vt->kind == VCODE_TYPE_CARRAY);
54,116✔
2789
   return vt->size;
54,116✔
2790
}
2791

2792
int vtype_fields(vcode_type_t type)
8,124✔
2793
{
2794
   vtype_t *vt = vcode_type_data(type);
8,124✔
2795
   assert(vt->kind == VCODE_TYPE_RECORD);
8,124✔
2796
   return vt->fields.count;
8,124✔
2797
}
2798

2799
vcode_type_t vtype_field(vcode_type_t type, int field)
31,425✔
2800
{
2801
   vtype_t *vt = vcode_type_data(type);
31,425✔
2802
   assert(vt->kind == VCODE_TYPE_RECORD);
31,425✔
2803
   return vcode_type_array_nth(&(vt->fields), field);
31,425✔
2804
}
2805

2806
ident_t vtype_name(vcode_type_t type)
19,364✔
2807
{
2808
   vtype_t *vt = vcode_type_data(type);
19,364✔
2809
   assert(vt->kind == VCODE_TYPE_RECORD || vt->kind == VCODE_TYPE_CONTEXT);
19,364✔
2810
   return vt->name;
19,364✔
2811
}
2812

2813
vcode_type_t vtype_pointed(vcode_type_t type)
362,932✔
2814
{
2815
   vtype_t *vt = vcode_type_data(type);
362,932✔
2816
   assert(vt->kind == VCODE_TYPE_POINTER || vt->kind == VCODE_TYPE_ACCESS);
362,932✔
2817
   return vt->pointed;
362,932✔
2818
}
2819

2820
int64_t vtype_low(vcode_type_t type)
258,757✔
2821
{
2822
   vtype_t *vt = vcode_type_data(type);
258,757✔
2823
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
258,757✔
2824
   return vt->low;
258,757✔
2825
}
2826

2827
int64_t vtype_high(vcode_type_t type)
256,003✔
2828
{
2829
   vtype_t *vt = vcode_type_data(type);
256,003✔
2830
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
256,003✔
2831
   return vt->high;
256,003✔
2832
}
2833

2834
static bool vtype_is_pointer(vcode_type_t type, vtype_kind_t to)
1,564✔
2835
{
2836
   return vtype_kind(type) == VCODE_TYPE_POINTER
1,564✔
2837
      && vtype_kind(vtype_pointed(type)) == to;
1,564✔
2838
}
2839

2840
bool vtype_is_scalar(vcode_type_t type)
443,572✔
2841
{
2842
   const vtype_kind_t kind = vtype_kind(type);
443,572✔
2843
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
443,572✔
2844
      || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_POINTER
179,028✔
2845
      || kind == VCODE_TYPE_FILE || kind == VCODE_TYPE_ACCESS
2846
      || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_SIGNAL
2847
      || kind == VCODE_TYPE_CONTEXT || kind == VCODE_TYPE_TRIGGER
2848
      || kind == VCODE_TYPE_RESOLUTION;
443,572✔
2849
}
2850

2851
bool vtype_is_composite(vcode_type_t type)
32,767✔
2852
{
2853
   const vtype_kind_t kind = vtype_kind(type);
32,767✔
2854
   return kind == VCODE_TYPE_RECORD || kind == VCODE_TYPE_CARRAY;
32,767✔
2855
}
2856

2857
bool vtype_is_signal(vcode_type_t type)
167,300✔
2858
{
2859
   vtype_t *vt = vcode_type_data(type);
294,492✔
2860
   switch (vt->kind) {
294,492✔
2861
   case VCODE_TYPE_SIGNAL:
2862
      return true;
2863
   case VCODE_TYPE_POINTER:
76,112✔
2864
      return vtype_is_signal(vt->pointed);
76,112✔
2865
   case VCODE_TYPE_RECORD:
2866
      for (int i = 0; i < vt->fields.count; i++) {
35,013✔
2867
         if (vtype_is_signal(vt->fields.items[i]))
27,672✔
2868
            return true;
2869
      }
2870
      return false;
2871
   case VCODE_TYPE_UARRAY:
51,080✔
2872
   case VCODE_TYPE_CARRAY:
2873
      return vtype_is_signal(vt->elem);
51,080✔
2874
   default:
130,467✔
2875
      return false;
130,467✔
2876
   }
2877
}
2878

UNCOV
2879
int vtype_repr_bits(vtype_repr_t repr)
×
2880
{
UNCOV
2881
   switch (repr) {
×
2882
   case VCODE_REPR_U1: return 1;
2883
   case VCODE_REPR_U8: case VCODE_REPR_I8: return 8;
2884
   case VCODE_REPR_U16: case VCODE_REPR_I16: return 16;
2885
   case VCODE_REPR_U32: case VCODE_REPR_I32: return 32;
2886
   case VCODE_REPR_U64: case VCODE_REPR_I64: return 64;
2887
   default: return -1;
2888
   }
2889
}
2890

UNCOV
2891
bool vtype_repr_signed(vtype_repr_t repr)
×
2892
{
UNCOV
2893
   return repr == VCODE_REPR_I8 || repr == VCODE_REPR_I16
×
UNCOV
2894
      || repr == VCODE_REPR_I32 || repr == VCODE_REPR_I64;
×
2895
}
2896

2897
static int64_t vtype_repr_low(vtype_repr_t repr)
15,316✔
2898
{
2899
   switch (repr) {
15,316✔
2900
   case VCODE_REPR_U1:
2901
   case VCODE_REPR_U8:
2902
   case VCODE_REPR_U16:
2903
   case VCODE_REPR_U32:
2904
   case VCODE_REPR_U64: return 0;
2905
   case VCODE_REPR_I8:  return INT8_MIN;
2906
   case VCODE_REPR_I16: return INT16_MIN;
2907
   case VCODE_REPR_I32: return INT32_MIN;
2908
   case VCODE_REPR_I64: return INT64_MIN;
2909
   default:             return 0;
2910
   }
2911
}
2912

2913
static uint64_t vtype_repr_high(vtype_repr_t repr)
15,316✔
2914
{
2915
   switch (repr) {
15,316✔
2916
   case VCODE_REPR_U1:  return 1;
2917
   case VCODE_REPR_U8:  return UINT8_MAX;
2918
   case VCODE_REPR_U16: return UINT16_MAX;
2919
   case VCODE_REPR_U32: return UINT32_MAX;
2920
   case VCODE_REPR_U64: return UINT64_MAX;
2921
   case VCODE_REPR_I8:  return INT8_MAX;
2922
   case VCODE_REPR_I16: return INT16_MAX;
2923
   case VCODE_REPR_I32: return INT32_MAX;
2924
   case VCODE_REPR_I64: return INT64_MAX;
2925
   default:             return 0;
2926
   }
2927
}
2928

2929
static bool vtype_clamp_to_repr(vtype_repr_t repr, int64_t *low, int64_t *high)
15,316✔
2930
{
2931
   int64_t clamp_low = vtype_repr_low(repr);
15,316✔
2932
   uint64_t clamp_high = vtype_repr_high(repr);
15,316✔
2933

2934
   if (*low >= clamp_low && *high <= clamp_high)
15,316✔
2935
      return true;
2936
   else {
2937
      *low = MAX(clamp_low, *low);
7,049✔
2938
      *high = MIN(clamp_high, *high);
7,049✔
2939
      return false;
7,049✔
2940
   }
2941
}
2942

2943
int vcode_count_params(void)
13,497✔
2944
{
2945
   assert(active_unit != NULL);
13,497✔
2946
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
13,497✔
2947
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2948
          || active_unit->kind == VCODE_UNIT_PROPERTY
2949
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2950

2951
   return active_unit->params.count;
13,497✔
2952
}
2953

2954
vcode_type_t vcode_param_type(int param)
31,905✔
2955
{
2956
   assert(active_unit != NULL);
31,905✔
2957
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
31,905✔
2958
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2959
          || active_unit->kind == VCODE_UNIT_PROPERTY
2960
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2961
   assert(param < active_unit->params.count);
31,905✔
2962

2963
   return active_unit->params.items[param].type;
31,905✔
2964
}
2965

2966
ident_t vcode_param_name(int param)
31,905✔
2967
{
2968
   assert(active_unit != NULL);
31,905✔
2969
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
31,905✔
2970
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2971
          || active_unit->kind == VCODE_UNIT_PROPERTY
2972
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2973
   assert(param < active_unit->params.count);
31,905✔
2974

2975
   return active_unit->params.items[param].name;
31,905✔
2976
}
2977

2978
vcode_reg_t vcode_param_reg(int param)
31,905✔
2979
{
2980
   assert(active_unit != NULL);
31,905✔
2981
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
31,905✔
2982
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2983
          || active_unit->kind == VCODE_UNIT_PROPERTY
2984
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2985
   assert(param < active_unit->params.count);
31,905✔
2986

2987
   return active_unit->params.items[param].reg;
31,905✔
2988
}
2989

2990
vcode_block_t emit_block(void)
145,300✔
2991
{
2992
   assert(active_unit != NULL);
145,300✔
2993

2994
   vcode_block_t bnum = active_unit->blocks.count;
145,300✔
2995

2996
   block_t *bptr = block_array_alloc(&(active_unit->blocks));
145,300✔
2997
   memset(bptr, '\0', sizeof(block_t));
145,300✔
2998

2999
   if (active_block != VCODE_INVALID_BLOCK)
145,300✔
3000
      bptr->last_loc = active_unit->blocks.items[active_block].last_loc;
92,219✔
3001
   else
3002
      bptr->last_loc = LOC_INVALID;
53,081✔
3003

3004
   return bnum;
145,300✔
3005
}
3006

3007
void vcode_select_unit(vcode_unit_t unit)
186,169✔
3008
{
3009
   active_unit  = unit;
186,169✔
3010
   active_block = VCODE_INVALID_BLOCK;
186,169✔
3011
}
186,169✔
3012

3013
void vcode_select_block(vcode_block_t block)
342,227✔
3014
{
3015
   assert(active_unit != NULL);
342,227✔
3016
   active_block = block;
342,227✔
3017
}
342,227✔
3018

3019
vcode_block_t vcode_active_block(void)
731✔
3020
{
3021
   assert(active_unit != NULL);
731✔
3022
   assert(active_block != -1);
731✔
3023
   return active_block;
731✔
3024
}
3025

3026
const loc_t *vcode_last_loc(void)
1,206,316✔
3027
{
3028
   return &(vcode_block_data()->last_loc);
1,206,316✔
3029
}
3030

3031
vcode_unit_t vcode_active_unit(void)
731✔
3032
{
3033
   assert(active_unit != NULL);
731✔
3034
   return active_unit;
731✔
3035
}
3036

3037
ident_t vcode_unit_name(vcode_unit_t vu)
165,882✔
3038
{
3039
   assert(vu != NULL);
165,882✔
3040
   return vu->name;
165,882✔
3041
}
3042

3043
bool vcode_unit_has_undefined(vcode_unit_t vu)
11,528✔
3044
{
3045
   assert(vu != NULL);
11,528✔
3046
   return !!(vu->flags & UNIT_UNDEFINED);
11,528✔
3047
}
3048

UNCOV
3049
int vcode_unit_depth(vcode_unit_t vu)
×
3050
{
UNCOV
3051
   assert(vu != NULL);
×
UNCOV
3052
   return vu->depth;
×
3053
}
3054

3055
void vcode_set_result(vcode_type_t type)
21,935✔
3056
{
3057
   assert(active_unit != NULL);
21,935✔
3058
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
21,935✔
3059
          || active_unit->kind == VCODE_UNIT_THUNK);
3060

3061
   active_unit->result = type;
21,935✔
3062
}
21,935✔
3063

3064
vcode_type_t vcode_unit_result(vcode_unit_t vu)
23,986✔
3065
{
3066
   assert(vu != NULL);
23,986✔
3067
   assert(vu->kind == VCODE_UNIT_FUNCTION || vu->kind == VCODE_UNIT_THUNK);
23,986✔
3068
   return vu->result;
23,986✔
3069
}
3070

3071
vunit_kind_t vcode_unit_kind(vcode_unit_t vu)
147,532✔
3072
{
3073
   assert(vu != NULL);
147,532✔
3074
   return vu->kind;
147,532✔
3075
}
3076

3077
vcode_unit_t vcode_unit_context(vcode_unit_t vu)
80,865✔
3078
{
3079
   assert(vu != NULL);
80,865✔
3080
   return vu->context;
80,865✔
3081
}
3082

3083
object_t *vcode_unit_object(vcode_unit_t vu)
92,579✔
3084
{
3085
   assert(vu != NULL);
92,579✔
3086
   return vu->object;
92,579✔
3087
}
3088

3089
static unsigned vcode_unit_calc_depth(vcode_unit_t unit)
64,621✔
3090
{
3091
   int hops = 0;
64,621✔
3092
   for (; (unit = unit->context); hops++)
165,593✔
3093
      ;
3094
   return hops;
64,621✔
3095
}
3096

3097
static void vcode_add_child(vcode_unit_t context, vcode_unit_t child)
29,675✔
3098
{
3099
   assert(context->kind != VCODE_UNIT_THUNK);
29,675✔
3100

3101
   child->next = NULL;
29,675✔
3102
   if (context->children == NULL)
29,675✔
3103
      context->children = child;
13,564✔
3104
   else {
3105
      vcode_unit_t it;
3106
      for (it = context->children; it->next != NULL; it = it->next)
73,651✔
3107
         ;
3108
      it->next = child;
16,111✔
3109
   }
3110
}
29,675✔
3111

3112
vcode_unit_t emit_function(ident_t name, object_t *obj, vcode_unit_t context)
12,507✔
3113
{
3114
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
12,507✔
3115
   vu->kind     = VCODE_UNIT_FUNCTION;
12,507✔
3116
   vu->name     = name;
12,507✔
3117
   vu->context  = context;
12,507✔
3118
   vu->result   = VCODE_INVALID_TYPE;
12,507✔
3119
   vu->depth    = vcode_unit_calc_depth(vu);
12,507✔
3120
   vu->object   = obj;
12,507✔
3121

3122
   vcode_add_child(context, vu);
12,507✔
3123

3124
   vcode_select_unit(vu);
12,507✔
3125
   vcode_select_block(emit_block());
12,507✔
3126
   emit_debug_info(&(obj->loc));
12,507✔
3127

3128
   return vu;
12,507✔
3129
}
3130

3131
vcode_unit_t emit_procedure(ident_t name, object_t *obj, vcode_unit_t context)
216✔
3132
{
3133
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
216✔
3134
   vu->kind     = VCODE_UNIT_PROCEDURE;
216✔
3135
   vu->name     = name;
216✔
3136
   vu->context  = context;
216✔
3137
   vu->result   = VCODE_INVALID_TYPE;
216✔
3138
   vu->depth    = vcode_unit_calc_depth(vu);
216✔
3139
   vu->object   = obj;
216✔
3140

3141
   vcode_add_child(context, vu);
216✔
3142

3143
   vcode_select_unit(vu);
216✔
3144
   vcode_select_block(emit_block());
216✔
3145
   emit_debug_info(&(obj->loc));
216✔
3146

3147
   return vu;
216✔
3148
}
3149

3150
vcode_unit_t emit_process(ident_t name, object_t *obj, vcode_unit_t context)
9,470✔
3151
{
3152
   assert(context->kind == VCODE_UNIT_INSTANCE);
9,470✔
3153

3154
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
9,470✔
3155
   vu->kind     = VCODE_UNIT_PROCESS;
9,470✔
3156
   vu->name     = name;
9,470✔
3157
   vu->context  = context;
9,470✔
3158
   vu->depth    = vcode_unit_calc_depth(vu);
9,470✔
3159
   vu->result   = VCODE_INVALID_TYPE;
9,470✔
3160
   vu->object   = obj;
9,470✔
3161

3162
   vcode_add_child(context, vu);
9,470✔
3163

3164
   vcode_select_unit(vu);
9,470✔
3165
   vcode_select_block(emit_block());
9,470✔
3166
   emit_debug_info(&(obj->loc));
9,470✔
3167

3168
   return vu;
9,470✔
3169
}
3170

3171
vcode_unit_t emit_instance(ident_t name, object_t *obj, vcode_unit_t context)
9,974✔
3172
{
3173
   assert(context == NULL || context->kind == VCODE_UNIT_INSTANCE);
9,974✔
3174

3175
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
9,974✔
3176
   vu->kind     = VCODE_UNIT_INSTANCE;
9,974✔
3177
   vu->name     = name;
9,974✔
3178
   vu->context  = context;
9,974✔
3179
   vu->depth    = vcode_unit_calc_depth(vu);
9,974✔
3180
   vu->result   = VCODE_INVALID_TYPE;
9,974✔
3181
   vu->object   = obj;
9,974✔
3182

3183
   if (context != NULL)
9,974✔
3184
      vcode_add_child(context, vu);
6,233✔
3185

3186
   vcode_select_unit(vu);
9,974✔
3187
   vcode_select_block(emit_block());
9,974✔
3188
   emit_debug_info(&(obj->loc));
9,974✔
3189

3190
   return vu;
9,974✔
3191
}
3192

3193
vcode_unit_t emit_package(ident_t name, object_t *obj, vcode_unit_t context)
8,600✔
3194
{
3195
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
8,600✔
3196
   vu->kind     = VCODE_UNIT_PACKAGE;
8,600✔
3197
   vu->name     = name;
8,600✔
3198
   vu->context  = context;
8,600✔
3199
   vu->depth    = vcode_unit_calc_depth(vu);
8,600✔
3200
   vu->result   = VCODE_INVALID_TYPE;
8,600✔
3201
   vu->object   = obj;
8,600✔
3202

3203
   if (context != NULL)
8,600✔
3204
      vcode_add_child(context, vu);
189✔
3205

3206
   vcode_select_unit(vu);
8,600✔
3207
   vcode_select_block(emit_block());
8,600✔
3208
   emit_debug_info(&(obj->loc));
8,600✔
3209

3210
   return vu;
8,600✔
3211
}
3212

3213
vcode_unit_t emit_protected(ident_t name, object_t *obj, vcode_unit_t context)
534✔
3214
{
3215
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
534✔
3216
   vu->kind     = VCODE_UNIT_PROTECTED;
534✔
3217
   vu->name     = name;
534✔
3218
   vu->context  = context;
534✔
3219
   vu->depth    = vcode_unit_calc_depth(vu);
534✔
3220
   vu->result   = VCODE_INVALID_TYPE;
534✔
3221
   vu->object   = obj;
534✔
3222

3223
   if (context != NULL)
534✔
3224
      vcode_add_child(context, vu);
534✔
3225

3226
   vcode_select_unit(vu);
534✔
3227
   vcode_select_block(emit_block());
534✔
3228
   emit_debug_info(&(obj->loc));
534✔
3229

3230
   return vu;
534✔
3231
}
3232

3233
vcode_unit_t emit_property(ident_t name, object_t *obj, vcode_unit_t context)
240✔
3234
{
3235
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
240✔
3236
   vu->kind     = VCODE_UNIT_PROPERTY;
240✔
3237
   vu->name     = name;
240✔
3238
   vu->context  = context;
240✔
3239
   vu->depth    = vcode_unit_calc_depth(vu);
240✔
3240
   vu->result   = VCODE_INVALID_TYPE;
240✔
3241
   vu->object   = obj;
240✔
3242

3243
   if (context != NULL)
240✔
3244
      vcode_add_child(context, vu);
240✔
3245

3246
   vcode_select_unit(vu);
240✔
3247
   vcode_select_block(emit_block());
240✔
3248
   emit_debug_info(&(obj->loc));
240✔
3249

3250
   return vu;
240✔
3251
}
3252

3253
vcode_unit_t emit_thunk(ident_t name, object_t *obj, vcode_unit_t context)
11,540✔
3254
{
3255
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
11,540✔
3256
   vu->kind     = VCODE_UNIT_THUNK;
11,540✔
3257
   vu->name     = name;
11,540✔
3258
   vu->context  = context;
11,540✔
3259
   vu->depth    = vcode_unit_calc_depth(vu);
11,540✔
3260
   vu->result   = VCODE_INVALID_TYPE;
11,540✔
3261
   vu->depth    = vcode_unit_calc_depth(vu);
11,540✔
3262
   vu->object   = obj;
11,540✔
3263

3264
   if (context != NULL)
11,540✔
3265
      vcode_add_child(context, vu);
286✔
3266

3267
   vcode_select_unit(vu);
11,540✔
3268
   vcode_select_block(emit_block());
11,540✔
3269

3270
   return vu;
11,540✔
3271
}
3272

3273
void emit_assert(vcode_reg_t value, vcode_reg_t message, vcode_reg_t length,
14,807✔
3274
                 vcode_reg_t severity, vcode_reg_t locus, vcode_reg_t hint_left,
3275
                 vcode_reg_t hint_right)
3276
{
3277
   int64_t value_const;
14,807✔
3278
   if (vcode_reg_const(value, &value_const) && value_const != 0) {
14,807✔
3279
      emit_comment("Always true assertion on r%d", value);
30✔
3280
      return;
30✔
3281
   }
3282

3283
   op_t *op = vcode_add_op(VCODE_OP_ASSERT);
14,777✔
3284
   vcode_add_arg(op, value);
14,777✔
3285
   vcode_add_arg(op, severity);
14,777✔
3286
   vcode_add_arg(op, message);
14,777✔
3287
   vcode_add_arg(op, length);
14,777✔
3288
   vcode_add_arg(op, locus);
14,777✔
3289

3290
   if (hint_left != VCODE_INVALID_REG) {
14,777✔
3291
      vcode_add_arg(op, hint_left);
6,047✔
3292
      vcode_add_arg(op, hint_right);
6,047✔
3293

3294
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_left)),
6,047✔
3295
                   "left hint must be scalar");
3296
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_right)),
6,047✔
3297
                   "right hint must be scalar");
3298
   }
3299

3300
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
14,777✔
3301
                "value parameter to assert is not bool");
3302
   VCODE_ASSERT(message == VCODE_INVALID_REG
14,777✔
3303
                || vcode_reg_kind(message) == VCODE_TYPE_POINTER,
3304
                "message parameter to assert is not a pointer");
3305
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
14,777✔
3306
                "value parameter to assert is not bool");
3307
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
14,777✔
3308
                "locus argument to report must be a debug locus");
3309
}
3310

3311
void emit_report(vcode_reg_t message, vcode_reg_t length, vcode_reg_t severity,
2,095✔
3312
                 vcode_reg_t locus)
3313
{
3314
   op_t *op = vcode_add_op(VCODE_OP_REPORT);
2,095✔
3315
   vcode_add_arg(op, severity);
2,095✔
3316
   vcode_add_arg(op, message);
2,095✔
3317
   vcode_add_arg(op, length);
2,095✔
3318
   vcode_add_arg(op, locus);
2,095✔
3319

3320
   VCODE_ASSERT(vcode_reg_kind(message) == VCODE_TYPE_POINTER,
2,095✔
3321
                "message parameter to report is not a pointer");
3322
   VCODE_ASSERT(vtype_eq(vtype_pointed(vcode_reg_type(message)), vtype_char()),
2,095✔
3323
                "message parameter to report is not a character pointer");
3324
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,095✔
3325
                "locus argument to report must be a debug locus");
3326
}
2,095✔
3327

3328
vcode_reg_t emit_cmp(vcode_cmp_t cmp, vcode_reg_t lhs, vcode_reg_t rhs)
35,365✔
3329
{
3330
   if (lhs == rhs) {
35,365✔
3331
      if (cmp == VCODE_CMP_EQ)
398✔
3332
         return emit_const(vtype_bool(), 1);
242✔
3333
      else if (cmp == VCODE_CMP_NEQ)
156✔
UNCOV
3334
         return emit_const(vtype_bool(), 0);
×
3335
      else if (cmp == VCODE_CMP_LEQ || cmp == VCODE_CMP_GEQ)
156✔
UNCOV
3336
         return emit_const(vtype_bool(), 1);
×
3337
      else if (cmp == VCODE_CMP_LT || cmp == VCODE_CMP_GT)
156✔
3338
         return emit_const(vtype_bool(), 0);
156✔
3339
   }
3340

3341
   int64_t lconst, rconst;
34,967✔
3342
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)) {
34,967✔
3343
      switch (cmp) {
328✔
3344
      case VCODE_CMP_EQ:
312✔
3345
         return emit_const(vtype_bool(), lconst == rconst);
312✔
3346
      case VCODE_CMP_NEQ:
3✔
3347
         return emit_const(vtype_bool(), lconst != rconst);
3✔
3348
      case VCODE_CMP_LT:
6✔
3349
         return emit_const(vtype_bool(), lconst < rconst);
6✔
3350
      case VCODE_CMP_GT:
7✔
3351
         return emit_const(vtype_bool(), lconst > rconst);
7✔
3352
      case VCODE_CMP_LEQ:
×
UNCOV
3353
         return emit_const(vtype_bool(), lconst <= rconst);
×
UNCOV
3354
      case VCODE_CMP_GEQ:
×
UNCOV
3355
         return emit_const(vtype_bool(), lconst >= rconst);
×
UNCOV
3356
      default:
×
3357
         fatal_trace("cannot fold comparison %d", cmp);
3358
      }
3359
   }
3360

3361
   // Reuse any previous operation in this block with the same arguments
3362
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CMP) {
668,221✔
3363
      if (other->args.count == 2 && other->args.items[0] == lhs
24,738✔
3364
          && other->args.items[1] == rhs && other->cmp == cmp)
2,234✔
3365
         return other->result;
193✔
3366
   }
3367

3368
   op_t *op = vcode_add_op(VCODE_OP_CMP);
34,446✔
3369
   vcode_add_arg(op, lhs);
34,446✔
3370
   vcode_add_arg(op, rhs);
34,446✔
3371
   op->cmp    = cmp;
34,446✔
3372
   op->result = vcode_add_reg(vtype_bool());
34,446✔
3373

3374
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vcode_reg_type(rhs)),
34,446✔
3375
                "arguments to cmp are not the same type");
3376

3377
   return op->result;
3378
}
3379

3380
vcode_reg_t emit_fcall(ident_t func, vcode_type_t type, vcode_type_t bounds,
35,567✔
3381
                       const vcode_reg_t *args, int nargs)
3382
{
3383
   op_t *o = vcode_add_op(VCODE_OP_FCALL);
35,567✔
3384
   o->func = func;
35,567✔
3385
   o->type = type;
35,567✔
3386
   for (int i = 0; i < nargs; i++)
124,507✔
3387
      vcode_add_arg(o, args[i]);
88,940✔
3388

3389
   for (int i = 0; i < nargs; i++)
124,507✔
3390
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
88,940✔
3391
                   "invalid argument to function");
3392

3393
   if (type == VCODE_INVALID_TYPE)
35,567✔
3394
      return (o->result = VCODE_INVALID_REG);
5,488✔
3395
   else {
3396
      o->result = vcode_add_reg(type);
30,079✔
3397

3398
      reg_t *rr = vcode_reg_data(o->result);
30,079✔
3399
      rr->bounds = bounds;
30,079✔
3400

3401
      return o->result;
30,079✔
3402
   }
3403
}
3404

3405
void emit_pcall(ident_t func, const vcode_reg_t *args, int nargs,
843✔
3406
                vcode_block_t resume_bb)
3407
{
3408
   op_t *o = vcode_add_op(VCODE_OP_PCALL);
843✔
3409
   o->func = func;
843✔
3410
   for (int i = 0; i < nargs; i++)
2,845✔
3411
      vcode_add_arg(o, args[i]);
2,002✔
3412

3413
   vcode_block_array_add(&(o->targets), resume_bb);
843✔
3414

3415
   for (int i = 0; i < nargs; i++)
2,845✔
3416
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
2,002✔
3417
                   "invalid argument to procedure");
3418

3419
   VCODE_ASSERT(nargs > 0 && vcode_reg_kind(args[0]) == VCODE_TYPE_CONTEXT,
843✔
3420
                "first argument to VHDL procedure must be context pointer");
3421
}
843✔
3422

3423
vcode_reg_t emit_syscall(ident_t func, vcode_type_t type, vcode_type_t bounds,
×
3424
                         vcode_reg_t locus, const vcode_reg_t *args, int nargs)
3425
{
3426
   op_t *o = vcode_add_op(VCODE_OP_SYSCALL);
×
3427
   o->func = func;
×
UNCOV
3428
   o->type = type;
×
3429
   vcode_add_arg(o, locus);
×
UNCOV
3430
   for (int i = 0; i < nargs; i++)
×
UNCOV
3431
      vcode_add_arg(o, args[i]);
×
3432

3433
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
×
3434
                "locus argument to syscall must be a debug locus");
3435

3436
   for (int i = 0; i < nargs; i++)
×
UNCOV
3437
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG, "invalid argument to syscall");
×
3438

UNCOV
3439
   if (type == VCODE_INVALID_TYPE)
×
3440
      return (o->result = VCODE_INVALID_REG);
×
3441
   else {
UNCOV
3442
      o->result = vcode_add_reg(type);
×
3443

UNCOV
3444
      reg_t *rr = vcode_reg_data(o->result);
×
UNCOV
3445
      rr->bounds = bounds;
×
3446

UNCOV
3447
      return o->result;
×
3448
   }
3449
}
3450

3451
vcode_reg_t emit_alloc(vcode_type_t type, vcode_type_t bounds,
7,708✔
3452
                       vcode_reg_t count)
3453
{
3454
   op_t *op = vcode_add_op(VCODE_OP_ALLOC);
7,708✔
3455
   op->type    = type;
7,708✔
3456
   op->result  = vcode_add_reg(vtype_pointer(type));
7,708✔
3457
   vcode_add_arg(op, count);
7,708✔
3458

3459
   const vtype_kind_t tkind = vtype_kind(type);
7,708✔
3460
   VCODE_ASSERT(tkind != VCODE_TYPE_CARRAY && tkind != VCODE_TYPE_UARRAY,
7,708✔
3461
                "alloca element type cannot be array");
3462
   VCODE_ASSERT(count != VCODE_INVALID_REG,
7,708✔
3463
                "alloca must have valid count argument");
3464

3465
   reg_t *r = vcode_reg_data(op->result);
7,708✔
3466
   r->bounds = bounds;
7,708✔
3467

3468
   return op->result;
7,708✔
3469
}
3470

3471
vcode_reg_t emit_const(vcode_type_t type, int64_t value)
1,487,762✔
3472
{
3473
   // Reuse any previous constant in this block with the same type and value
3474
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST) {
33,238,623✔
3475
      if (other->value == value && vtype_eq(type, other->type))
11,804,687✔
3476
         return other->result;
1,014,959✔
3477
   }
3478

3479
   op_t *op = vcode_add_op(VCODE_OP_CONST);
472,803✔
3480
   op->value  = value;
472,803✔
3481
   op->type   = type;
472,803✔
3482
   op->result = vcode_add_reg(type);
472,803✔
3483

3484
   vtype_kind_t type_kind = vtype_kind(type);
472,803✔
3485
   VCODE_ASSERT(type_kind == VCODE_TYPE_INT || type_kind == VCODE_TYPE_OFFSET,
472,803✔
3486
                "constant must have integer or offset type");
3487

3488
   reg_t *r = vcode_reg_data(op->result);
472,803✔
3489
   r->bounds = vtype_int(value, value);
472,803✔
3490

3491
   return op->result;
472,803✔
3492
}
3493

3494
vcode_reg_t emit_const_real(vcode_type_t type, double value)
66,672✔
3495
{
3496
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REAL) {
1,956,330✔
3497
      if (other->real == value && other->type == type)
907,876✔
3498
         return other->result;
25,316✔
3499
   }
3500

3501
   op_t *op = vcode_add_op(VCODE_OP_CONST_REAL);
41,356✔
3502
   op->real   = value;
41,356✔
3503
   op->type   = type;
41,356✔
3504
   op->result = vcode_add_reg(op->type);
41,356✔
3505

3506
   reg_t *r = vcode_reg_data(op->result);
41,356✔
3507
   r->bounds = vtype_real(value, value);
41,356✔
3508

3509
   return op->result;
41,356✔
3510
}
3511

3512
vcode_reg_t emit_const_array(vcode_type_t type, vcode_reg_t *values, int num)
38,479✔
3513
{
3514
   vtype_kind_t kind = vtype_kind(type);
38,479✔
3515

3516
   // Reuse any previous operation in this block with the same arguments
3517
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_ARRAY) {
1,928,655✔
3518
      if (other->args.count != num)
151,363✔
3519
         continue;
90,260✔
3520
      else if (!vtype_eq(vcode_reg_type(other->result), type))
61,103✔
3521
         continue;
2,298✔
3522

3523
      bool match = true;
3524
      for (int i = 0; match && i < num; i++) {
422,393✔
3525
         if (other->args.items[i] != values[i])
363,588✔
3526
            match = false;
51,516✔
3527
      }
3528

3529
      if (match) return other->result;
58,805✔
3530
   }
3531

3532
   op_t *op = vcode_add_op(VCODE_OP_CONST_ARRAY);
31,190✔
3533
   op->result = vcode_add_reg(type);
31,190✔
3534

3535
   for (int i = 0; i < num; i++)
1,690,309✔
3536
      vcode_add_arg(op, values[i]);
1,659,119✔
3537

3538
   VCODE_ASSERT(kind == VCODE_TYPE_CARRAY,
31,190✔
3539
                "constant array must have constrained array type");
3540
   VCODE_ASSERT(vtype_size(type) == num, "expected %d elements but have %d",
31,190✔
3541
                vtype_size(type), num);
3542

3543
#ifdef DEBUG
3544
   vcode_type_t elem = vtype_elem(type);
31,190✔
3545
   for (int i = 0; i < num; i++) {
1,690,309✔
3546
      VCODE_ASSERT(vtype_eq(vcode_reg_type(values[i]), elem),
1,659,119✔
3547
                   "wrong element type for item %d", i);
3548
      vcode_assert_const(values[i], "array");
1,659,119✔
3549
   }
3550
#endif
3551

3552
   reg_t *r = vcode_reg_data(op->result);
31,190✔
3553
   r->bounds = vtype_elem(type);
31,190✔
3554

3555
   return op->result;
31,190✔
3556
}
3557

3558
vcode_reg_t emit_const_rep(vcode_type_t type, vcode_reg_t value, int rep)
631✔
3559
{
3560
   // Reuse any previous operation in this block with the same arguments
3561
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REP) {
9,091✔
3562
      if (other->args.items[0] == value && other->value == rep)
967✔
3563
         return other->result;
258✔
3564
   }
3565

3566
   op_t *op = vcode_add_op(VCODE_OP_CONST_REP);
373✔
3567
   op->value = rep;
373✔
3568
   vcode_add_arg(op, value);
373✔
3569

3570
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CARRAY,
373✔
3571
                "constant array must have constrained array type");
3572
   VCODE_ASSERT(rep >= 0, "repeat count must be non-negative");
373✔
3573

3574
   DEBUG_ONLY(vcode_assert_const(value, "repeat"));
373✔
3575

3576
   op->result = vcode_add_reg(type);
373✔
3577

3578
   reg_t *r = vcode_reg_data(op->result);
373✔
3579
   r->bounds = vtype_bounds(type);
373✔
3580

3581
   return op->result;
373✔
3582
}
3583

3584
vcode_reg_t emit_const_record(vcode_type_t type, vcode_reg_t *values, int num)
2,584✔
3585
{
3586
   // Reuse any previous constant in this block with the same type and value
3587
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_RECORD) {
39,386✔
3588
      if (other->args.count == num && vtype_eq(type, other->type)) {
1,666✔
3589
         bool same_regs = true;
3590
         for (int i = 0; same_regs && i < num; i++)
2,588✔
3591
            same_regs = other->args.items[i] == values[i];
1,526✔
3592

3593
         if (same_regs)
1,062✔
3594
            return other->result;
199✔
3595
      }
3596
   }
3597

3598
   op_t *op = vcode_add_op(VCODE_OP_CONST_RECORD);
2,385✔
3599
   op->type   = type;
2,385✔
3600
   op->result = vcode_add_reg(type);
2,385✔
3601

3602
   for (int i = 0; i < num; i++)
8,611✔
3603
      vcode_add_arg(op, values[i]);
6,226✔
3604

3605
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_RECORD,
2,385✔
3606
                "constant record must have record type");
3607

3608
   VCODE_ASSERT(vtype_fields(type) == num, "expected %d fields but have %d",
2,385✔
3609
                vtype_fields(type), num);
3610

3611
#ifdef DEBUG
3612
   for (int i = 0; i < num; i++) {
8,611✔
3613
      VCODE_ASSERT(vtype_eq(vtype_field(type, i), vcode_reg_type(values[i])),
6,226✔
3614
                   "wrong type for field %d", i);
3615
      vcode_assert_const(values[i], "record");
6,226✔
3616
   }
3617
#endif
3618

3619
   return op->result;
2,385✔
3620
}
3621

3622
vcode_reg_t emit_address_of(vcode_reg_t value)
40,051✔
3623
{
3624
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ADDRESS_OF) {
2,008,227✔
3625
      if (other->args.items[0] == value)
152,363✔
3626
         return other->result;
7,284✔
3627
   }
3628

3629
   op_t *op = vcode_add_op(VCODE_OP_ADDRESS_OF);
32,767✔
3630
   vcode_add_arg(op, value);
32,767✔
3631

3632
   vcode_type_t type = vcode_reg_type(value);
32,767✔
3633
   VCODE_ASSERT(vtype_is_composite(type),
32,767✔
3634
                "address of argument must be record or array");
3635

3636
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
32,767✔
3637
      vcode_type_t elem = vtype_elem(type);
30,970✔
3638
      op->result = vcode_add_reg(vtype_pointer(elem));
30,970✔
3639

3640
      reg_t *rr = vcode_reg_data(op->result);
30,970✔
3641
      rr->bounds = elem;
30,970✔
3642

3643
      return op->result;
30,970✔
3644
   }
3645
   else
3646
      return (op->result = vcode_add_reg(vtype_pointer(type)));
1,797✔
3647
}
3648

3649
void emit_wait(vcode_block_t target)
14,008✔
3650
{
3651
   op_t *op = vcode_add_op(VCODE_OP_WAIT);
14,008✔
3652
   vcode_add_target(op, target);
14,008✔
3653
}
14,008✔
3654

3655
void emit_jump(vcode_block_t target)
38,679✔
3656
{
3657
   op_t *op = vcode_add_op(VCODE_OP_JUMP);
38,679✔
3658
   vcode_add_target(op, target);
38,679✔
3659

3660
   VCODE_ASSERT(target != VCODE_INVALID_BLOCK, "invalid jump target");
38,679✔
3661
}
38,679✔
3662

3663
vcode_var_t emit_var(vcode_type_t type, vcode_type_t bounds, ident_t name,
70,340✔
3664
                     vcode_var_flags_t flags)
3665
{
3666
   assert(active_unit != NULL);
70,340✔
3667

3668
   vcode_var_t var = active_unit->vars.count;
70,340✔
3669
   var_t *v = var_array_alloc(&(active_unit->vars));
70,340✔
3670
   memset(v, '\0', sizeof(var_t));
70,340✔
3671
   v->type     = type;
70,340✔
3672
   v->bounds   = bounds;
70,340✔
3673
   v->name     = name;
70,340✔
3674
   v->flags    = flags;
70,340✔
3675

3676
   return var;
70,340✔
3677
}
3678

3679
vcode_reg_t emit_param(vcode_type_t type, vcode_type_t bounds, ident_t name)
32,191✔
3680
{
3681
   assert(active_unit != NULL);
32,191✔
3682

3683
   param_t *p = param_array_alloc(&(active_unit->params));
32,191✔
3684
   memset(p, '\0', sizeof(param_t));
32,191✔
3685
   p->type   = type;
32,191✔
3686
   p->bounds = bounds;
32,191✔
3687
   p->name   = name;
32,191✔
3688
   p->reg    = vcode_add_reg(type);
32,191✔
3689

3690
   reg_t *rr = vcode_reg_data(p->reg);
32,191✔
3691
   rr->bounds = bounds;
32,191✔
3692

3693
   return p->reg;
32,191✔
3694
}
3695

3696
vcode_reg_t emit_load(vcode_var_t var)
60,620✔
3697
{
3698
   // Try scanning backwards through the block for another load or store to
3699
   // this variable
3700
   enum { EAGER, CONSERVATIVE, UNSAFE } state = EAGER;
60,620✔
3701
   vcode_reg_t fold = VCODE_INVALID_REG;
60,620✔
3702
   VCODE_FOR_EACH_OP(other) {
858,203✔
3703
      switch (state) {
814,063✔
3704
      case EAGER:
321,680✔
3705
         if (other->kind == VCODE_OP_LOAD && other->address == var)
321,680✔
3706
            return other->result;
3,585✔
3707
         else if (other->kind == VCODE_OP_STORE && other->address == var)
318,095✔
3708
            return other->args.items[0];
12,895✔
3709
         else if (other->kind == VCODE_OP_FCALL
305,200✔
3710
                  || other->kind == VCODE_OP_PCALL
305,200✔
3711
                  || other->kind == VCODE_OP_FILE_READ
3712
                  || other->kind == VCODE_OP_FILE_OPEN
3713
                  || other->kind == VCODE_OP_STORE_INDIRECT
3714
                  || other->kind == VCODE_OP_DEALLOCATE)
3715
            state = CONSERVATIVE;   // May write to variable
9,877✔
3716
         break;
3717

3718
      case CONSERVATIVE:
461,788✔
3719
         if (other->kind == VCODE_OP_LOAD && other->address == var
461,788✔
3720
             && fold == VCODE_INVALID_REG)
4,567✔
3721
            fold = other->result;
3,688✔
3722
         else if (other->kind == VCODE_OP_STORE && other->address == var
458,100✔
3723
                  && fold == VCODE_INVALID_REG)
2,416✔
3724
            fold = other->args.items[0];
2,274✔
3725
         else if (other->kind == VCODE_OP_INDEX && other->address == var)
455,826✔
3726
            state = UNSAFE;
3727
         else if (other->kind == VCODE_OP_CONTEXT_UPREF && other->hops == 0)
454,457✔
3728
            state = UNSAFE;   // Nested call captures variables
120✔
3729
         break;
3730

3731
      case UNSAFE:
3732
         break;
3733
      }
3734
   }
3735

3736
   if (fold != VCODE_INVALID_REG && state != UNSAFE)
44,140✔
3737
      return fold;
3738

3739
   var_t *v = vcode_var_data(var);
38,569✔
3740

3741
   op_t *op = vcode_add_op(VCODE_OP_LOAD);
38,569✔
3742
   op->address = var;
38,569✔
3743
   op->result  = vcode_add_reg(v->type);
38,569✔
3744

3745
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot load non-scalar type");
38,569✔
3746

3747
   reg_t *r = vcode_reg_data(op->result);
38,569✔
3748
   r->bounds = v->bounds;
38,569✔
3749

3750
   return op->result;
38,569✔
3751
}
3752

3753
vcode_reg_t emit_load_indirect(vcode_reg_t reg)
106,237✔
3754
{
3755
   VCODE_FOR_EACH_OP(other) {
1,277,307✔
3756
      if (other->kind == VCODE_OP_LOAD_INDIRECT
1,202,400✔
3757
          && other->args.items[0] == reg) {
179,042✔
3758
         return other->result;
11,298✔
3759
      }
3760
      else if (other->kind == VCODE_OP_FCALL
1,191,102✔
3761
               || other->kind == VCODE_OP_PCALL
1,191,102✔
3762
               || other->kind == VCODE_OP_STORE
3763
               || other->kind == VCODE_OP_STORE_INDIRECT
3764
               || other->kind == VCODE_OP_MEMSET
3765
               || other->kind == VCODE_OP_COPY
3766
               || other->kind == VCODE_OP_FILE_READ)
3767
         break;   // May write to this pointer
3768
   }
3769

3770
   op_t *op = vcode_add_op(VCODE_OP_LOAD_INDIRECT);
94,939✔
3771
   vcode_add_arg(op, reg);
94,939✔
3772

3773
   vcode_type_t rtype = vcode_reg_type(reg);
94,939✔
3774

3775
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
94,939✔
3776
                "load indirect with non-pointer argument");
3777

3778
   vcode_type_t deref = vtype_pointed(rtype);
94,939✔
3779
   op->result = vcode_add_reg(deref);
94,939✔
3780

3781
   VCODE_ASSERT(vtype_is_scalar(deref), "cannot load non-scalar type");
94,939✔
3782

3783
   vcode_reg_data(op->result)->bounds = vcode_reg_data(reg)->bounds;
94,939✔
3784

3785
   return op->result;
94,939✔
3786
}
3787

3788
void emit_store(vcode_reg_t reg, vcode_var_t var)
75,955✔
3789
{
3790
   // Any previous store to this variable in this block is dead
3791
   VCODE_FOR_EACH_OP(other) {
1,601,670✔
3792
      if (other->kind == VCODE_OP_STORE && other->address == var) {
1,541,088✔
3793
         other->kind = VCODE_OP_COMMENT;
292✔
3794
         other->comment =
584✔
3795
            xasprintf("Dead store to %s", istr(vcode_var_name(var)));
292✔
3796
         vcode_reg_array_resize(&(other->args), 0, VCODE_INVALID_REG);
292✔
3797
      }
3798
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
1,540,796✔
3799
         break;   // Needs to get variable for display
3800
      else if ((other->kind == VCODE_OP_INDEX || other->kind == VCODE_OP_LOAD)
1,533,768✔
3801
               && other->address == var)
37,411✔
3802
         break;   // Previous value may be used
3803
   }
3804

3805
   var_t *v = vcode_var_data(var);
75,955✔
3806
   reg_t *r = vcode_reg_data(reg);
75,955✔
3807

3808
   op_t *op = vcode_add_op(VCODE_OP_STORE);
75,955✔
3809
   vcode_add_arg(op, reg);
75,955✔
3810
   op->address = var;
75,955✔
3811

3812
   VCODE_ASSERT(vtype_eq(v->type, r->type),
75,955✔
3813
                "variable and stored value do not have same type");
3814
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot store non-scalar type");
75,955✔
3815
}
75,955✔
3816

3817
void emit_store_indirect(vcode_reg_t reg, vcode_reg_t ptr)
14,914✔
3818
{
3819
   reg_t *p = vcode_reg_data(ptr);
14,914✔
3820
   reg_t *r = vcode_reg_data(reg);
14,914✔
3821

3822
   op_t *op = vcode_add_op(VCODE_OP_STORE_INDIRECT);
14,914✔
3823
   vcode_add_arg(op, reg);
14,914✔
3824
   vcode_add_arg(op, ptr);
14,914✔
3825

3826
   VCODE_ASSERT(vtype_kind(p->type) == VCODE_TYPE_POINTER,
14,914✔
3827
                "store indirect target is not a pointer");
3828
   VCODE_ASSERT(vtype_eq(vtype_pointed(p->type), r->type),
14,914✔
3829
                "pointer and stored value do not have same type");
3830
   VCODE_ASSERT(vtype_is_scalar(r->type), "cannot store non-scalar type");
14,914✔
3831
}
14,914✔
3832

3833
static vcode_reg_t emit_arith(vcode_op_t kind, vcode_reg_t lhs, vcode_reg_t rhs,
72,293✔
3834
                              vcode_reg_t locus)
3835
{
3836
   // Reuse any previous operation in this block with the same arguments
3837
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
1,670,076✔
3838
      if (other->args.items[0] == lhs && other->args.items[1] == rhs)
80,114✔
3839
         return other->result;
5,970✔
3840
   }
3841

3842
   op_t *op = vcode_add_op(kind);
66,323✔
3843
   vcode_add_arg(op, lhs);
66,323✔
3844
   vcode_add_arg(op, rhs);
66,323✔
3845
   if (locus != VCODE_INVALID_REG)
66,323✔
3846
      vcode_add_arg(op, locus);
7,428✔
3847

3848
   op->result = vcode_add_reg(vcode_reg_type(lhs));
66,323✔
3849

3850
   vcode_type_t lhs_type = vcode_reg_type(lhs);
66,323✔
3851
   vcode_type_t rhs_type = vcode_reg_type(rhs);
66,323✔
3852

3853
   VCODE_ASSERT(vtype_eq(lhs_type, rhs_type),
66,323✔
3854
                "arguments to %s are not the same type", vcode_op_string(kind));
3855

3856
   return op->result;
3857
}
3858

3859
static vcode_reg_t emit_mul_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
51,002✔
3860
                               vcode_reg_t locus)
3861
{
3862
   int64_t lconst, rconst;
51,002✔
3863
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
51,002✔
3864
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
51,002✔
3865
   if (l_is_const && r_is_const)
51,002✔
3866
      return emit_const(vcode_reg_type(lhs), lconst * rconst);
22,460✔
3867
   else if (r_is_const && rconst == 1)
28,542✔
3868
      return lhs;
3869
   else if (l_is_const && lconst == 1)
5,695✔
3870
      return rhs;
3871
   else if ((r_is_const && rconst == 0) || (l_is_const && lconst == 0))
5,193✔
3872
      return emit_const(vcode_reg_type(lhs), 0);
54✔
3873

3874
   reg_t *lhs_r = vcode_reg_data(lhs);
5,139✔
3875
   reg_t *rhs_r = vcode_reg_data(rhs);
5,139✔
3876

3877
   vtype_t *bl = vcode_type_data(lhs_r->bounds);
5,139✔
3878
   vtype_t *br = vcode_type_data(rhs_r->bounds);
5,139✔
3879

3880
   vcode_type_t vbounds;
5,139✔
3881
   if (vcode_reg_kind(lhs) == VCODE_TYPE_REAL) {
5,139✔
3882
      const double ll = bl->rlow * br->rlow;
556✔
3883
      const double lh = bl->rlow * br->rhigh;
556✔
3884
      const double hl = bl->rhigh * br->rlow;
556✔
3885
      const double hh = bl->rhigh * br->rhigh;
556✔
3886

3887
      double min = MIN(MIN(ll, lh), MIN(hl, hh));
1,301✔
3888
      double max = MAX(MAX(ll, lh), MAX(hl, hh));
1,387✔
3889

3890
      vbounds = vtype_real(min, max);
556✔
3891
   }
3892
   else {
3893
      const int64_t ll = smul64(bl->low, br->low);
4,583✔
3894
      const int64_t lh = smul64(bl->low, br->high);
4,583✔
3895
      const int64_t hl = smul64(bl->high, br->low);
4,583✔
3896
      const int64_t hh = smul64(bl->high, br->high);
4,583✔
3897

3898
      int64_t min = MIN(MIN(ll, lh), MIN(hl, hh));
4,583✔
3899
      int64_t max = MAX(MAX(ll, lh), MAX(hl, hh));
4,583✔
3900

3901
      vtype_repr_t repr = vtype_repr(lhs_r->type);
4,583✔
3902
      if (op == VCODE_OP_TRAP_MUL && vtype_clamp_to_repr(repr, &min, &max)) {
4,583✔
3903
         op = VCODE_OP_MUL;   // Cannot overflow
1,022✔
3904
         locus = VCODE_INVALID_REG;
1,022✔
3905
      }
3906

3907
      vbounds = vtype_int(min, max);
4,583✔
3908
   }
3909

3910
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
5,139✔
3911

3912
   if (vbounds != VCODE_INVALID_TYPE)
5,139✔
3913
      vcode_reg_data(reg)->bounds = vbounds;
5,139✔
3914

3915
   return reg;
3916
}
3917

3918
vcode_reg_t emit_mul(vcode_reg_t lhs, vcode_reg_t rhs)
47,864✔
3919
{
3920
   return emit_mul_op(VCODE_OP_MUL, lhs, rhs, VCODE_INVALID_REG);
47,864✔
3921
}
3922

3923
vcode_reg_t emit_trap_mul(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
3,138✔
3924
{
3925
   vcode_reg_t result = emit_mul_op(VCODE_OP_TRAP_MUL, lhs, rhs, locus);
3,138✔
3926

3927
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
3,138✔
3928
                "trapping add may only be used with integer types");
3929

3930
   return result;
3,138✔
3931
}
3932

3933
vcode_reg_t emit_div(vcode_reg_t lhs, vcode_reg_t rhs)
1,726✔
3934
{
3935
   int64_t lconst, rconst;
1,726✔
3936
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
1,726✔
3937
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
1,726✔
3938
   if (l_is_const && r_is_const && rconst != 0)
1,726✔
3939
      return emit_const(vcode_reg_type(lhs), lconst / rconst);
30✔
3940
   else if (r_is_const && rconst == 1)
1,696✔
3941
      return lhs;
3942

3943
   vcode_reg_t reg = emit_arith(VCODE_OP_DIV, lhs, rhs, VCODE_INVALID_REG);
1,693✔
3944

3945
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
1,693✔
3946

3947
   if (bl->kind == VCODE_TYPE_INT && r_is_const && rconst != 0) {
1,693✔
3948
      reg_t *rr = vcode_reg_data(reg);
1,300✔
3949
      rr->bounds = vtype_int(bl->low / rconst, bl->high / rconst);
1,300✔
3950
   }
3951
   else if (bl->kind == VCODE_TYPE_REAL) {
393✔
3952
      reg_t *rr = vcode_reg_data(reg);
317✔
3953
      rr->bounds = vtype_real(-INFINITY, INFINITY);
317✔
3954
   }
3955

3956
   return reg;
3957
}
3958

3959
vcode_reg_t emit_exp(vcode_reg_t lhs, vcode_reg_t rhs)
141✔
3960
{
3961
   return emit_arith(VCODE_OP_EXP, lhs, rhs, VCODE_INVALID_REG);
141✔
3962
}
3963

3964
vcode_reg_t emit_trap_exp(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
789✔
3965
{
3966
   int64_t rconst;
789✔
3967
   if (vcode_reg_const(rhs, &rconst)) {
789✔
3968
      if (rconst == 0)
455✔
3969
         return emit_const(vcode_reg_type(lhs), 1);
31✔
3970
      else if (rconst == 1)
424✔
3971
         return lhs;
3972
   }
3973

3974
   vcode_reg_t result = emit_arith(VCODE_OP_TRAP_EXP, lhs, rhs, locus);
757✔
3975

3976
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
757✔
3977
                "trapping exp may only be used with integer types");
3978

3979
   return result;
3980
}
3981

3982
vcode_reg_t emit_mod(vcode_reg_t lhs, vcode_reg_t rhs)
199✔
3983
{
3984
   int64_t lconst, rconst;
199✔
3985
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
199✔
3986
       && lconst > 0 && rconst > 0)
15✔
3987
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
3✔
3988

3989
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
196✔
3990
   vtype_t *br = vcode_type_data(vcode_reg_data(rhs)->bounds);
196✔
3991

3992
   if (bl->low >= 0 && br->low >= 0) {
196✔
3993
      // If both arguments are non-negative then rem is equivalent and
3994
      // cheaper to compute
3995
      vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
66✔
3996

3997
      reg_t *rr = vcode_reg_data(reg);
66✔
3998
      rr->bounds = vtype_int(0, MAX(0, br->high - 1));
66✔
3999

4000
      return reg;
66✔
4001
   }
4002
   else
4003
      return emit_arith(VCODE_OP_MOD, lhs, rhs, VCODE_INVALID_REG);
130✔
4004
}
4005

4006
vcode_reg_t emit_rem(vcode_reg_t lhs, vcode_reg_t rhs)
837✔
4007
{
4008
   int64_t lconst, rconst;
837✔
4009
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
837✔
4010
       && lconst > 0 && rconst > 0)
2✔
UNCOV
4011
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
×
4012

4013
   vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
837✔
4014

4015
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
837✔
4016
   vtype_t *br = vcode_type_data(vcode_reg_data(rhs)->bounds);
837✔
4017

4018
   if (bl->low >= 0 && br->low >= 0) {
837✔
4019
      reg_t *rr = vcode_reg_data(reg);
453✔
4020
      rr->bounds = vtype_int(0, br->high - 1);
453✔
4021
   }
4022

4023
   return reg;
4024
}
4025

4026
static vcode_reg_t emit_add_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
51,165✔
4027
                               vcode_reg_t locus)
4028
{
4029
   int64_t lconst, rconst;
51,165✔
4030
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
51,165✔
4031
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
51,165✔
4032
   if (l_is_const && r_is_const)
51,165✔
4033
      return emit_const(vcode_reg_type(lhs), lconst + rconst);
11,978✔
4034
   else if (r_is_const && rconst == 0)
39,187✔
4035
      return lhs;
4036
   else if (l_is_const && lconst == 0)
39,059✔
4037
      return rhs;
4038

4039
   vcode_type_t vbounds = VCODE_INVALID_TYPE;
20,881✔
4040
   if (vcode_reg_kind(lhs) != VCODE_TYPE_REAL) {
20,881✔
4041
      reg_t *lhs_r = vcode_reg_data(lhs);
20,557✔
4042
      reg_t *rhs_r = vcode_reg_data(rhs);
20,557✔
4043

4044
      vtype_t *bl = vcode_type_data(lhs_r->bounds);
20,557✔
4045
      vtype_t *br = vcode_type_data(rhs_r->bounds);
20,557✔
4046

4047
      int64_t rbl = sadd64(bl->low, br->low);
20,557✔
4048
      int64_t rbh = sadd64(bl->high, br->high);
20,557✔
4049

4050
      vtype_repr_t repr = vtype_repr(lhs_r->type);
20,557✔
4051
      if (op == VCODE_OP_TRAP_ADD && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
20,557✔
4052
         op = VCODE_OP_ADD;   // Cannot overflow
1,957✔
4053
         locus = VCODE_INVALID_REG;
1,957✔
4054
      }
4055

4056
      vbounds = vtype_int(rbl, rbh);
20,557✔
4057
   }
4058

4059
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
20,881✔
4060

4061
   if (vbounds != VCODE_INVALID_TYPE)
20,881✔
4062
      vcode_reg_data(reg)->bounds = vbounds;
20,557✔
4063

4064
   return reg;
4065
}
4066

4067
vcode_reg_t emit_add(vcode_reg_t lhs, vcode_reg_t rhs)
44,616✔
4068
{
4069
   return emit_add_op(VCODE_OP_ADD, lhs, rhs, VCODE_INVALID_REG);
44,616✔
4070
}
4071

4072
vcode_reg_t emit_trap_add(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
6,549✔
4073
{
4074
   vcode_reg_t result = emit_add_op(VCODE_OP_TRAP_ADD, lhs, rhs, locus);
6,549✔
4075

4076
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
6,549✔
4077
                "trapping add may only be used with integer types");
4078

4079
   return result;
6,549✔
4080
}
4081

4082
static vcode_reg_t emit_sub_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
49,172✔
4083
                               vcode_reg_t locus)
4084
{
4085
   int64_t lconst, rconst;
49,172✔
4086
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
49,172✔
4087
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
49,172✔
4088
   if (l_is_const && r_is_const)
49,172✔
4089
      return emit_const(vcode_reg_type(lhs), lconst - rconst);
8,256✔
4090
   else if (r_is_const && rconst == 0)
40,916✔
4091
      return lhs;
4092
   else if (l_is_const && lconst == 0)
35,777✔
4093
      return emit_neg(rhs);
825✔
4094

4095
   vcode_type_t vbounds = VCODE_INVALID_TYPE;
34,952✔
4096
   if (vcode_reg_kind(lhs) != VCODE_TYPE_REAL) {
34,952✔
4097
      reg_t *lhs_r = vcode_reg_data(lhs);
34,657✔
4098
      reg_t *rhs_r = vcode_reg_data(rhs);
34,657✔
4099

4100
      vtype_t *bl = vcode_type_data(lhs_r->bounds);
34,657✔
4101
      vtype_t *br = vcode_type_data(rhs_r->bounds);
34,657✔
4102

4103
      int64_t rbl = ssub64(bl->low, br->high);
34,657✔
4104
      int64_t rbh = ssub64(bl->high, br->low);
34,657✔
4105

4106
      vtype_repr_t repr = vtype_repr(lhs_r->type);
34,657✔
4107
      if (op == VCODE_OP_TRAP_SUB && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
34,657✔
4108
         op = VCODE_OP_SUB;   // Cannot overflow
5,288✔
4109
         locus = VCODE_INVALID_REG;
5,288✔
4110
      }
4111

4112
      vbounds = vtype_int(rbl, rbh);
34,657✔
4113
   }
4114

4115
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
34,952✔
4116

4117
   if (vbounds != VCODE_INVALID_TYPE)
34,952✔
4118
      vcode_reg_data(reg)->bounds = vbounds;
34,657✔
4119

4120
   return reg;
4121
}
4122

4123
vcode_reg_t emit_sub(vcode_reg_t lhs, vcode_reg_t rhs)
41,862✔
4124
{
4125
   return emit_sub_op(VCODE_OP_SUB, lhs, rhs, VCODE_INVALID_REG);
41,862✔
4126
}
4127

4128
vcode_reg_t emit_trap_sub(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
7,310✔
4129
{
4130
   vcode_reg_t result = emit_sub_op(VCODE_OP_TRAP_SUB, lhs, rhs, locus);
7,310✔
4131

4132
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
7,310✔
4133
                "trapping sub may only be used with integer types");
4134

4135
   return result;
7,310✔
4136
}
4137

4138
static void vcode_calculate_var_index_type(op_t *op, var_t *var)
78,988✔
4139
{
4140
   switch (vtype_kind(var->type)) {
78,988✔
4141
   case VCODE_TYPE_CARRAY:
22,004✔
4142
      op->type = vtype_pointer(vtype_elem(var->type));
22,004✔
4143
      op->result = vcode_add_reg(op->type);
22,004✔
4144
      vcode_reg_data(op->result)->bounds = vtype_bounds(var->type);
22,004✔
4145
      break;
22,004✔
4146

4147
   case VCODE_TYPE_RECORD:
6,050✔
4148
      op->type = vtype_pointer(var->type);
6,050✔
4149
      op->result = vcode_add_reg(op->type);
6,050✔
4150
      break;
6,050✔
4151

4152
   case VCODE_TYPE_INT:
50,934✔
4153
   case VCODE_TYPE_FILE:
4154
   case VCODE_TYPE_ACCESS:
4155
   case VCODE_TYPE_REAL:
4156
   case VCODE_TYPE_UARRAY:
4157
   case VCODE_TYPE_POINTER:
4158
   case VCODE_TYPE_SIGNAL:
4159
   case VCODE_TYPE_CONTEXT:
4160
   case VCODE_TYPE_OFFSET:
4161
   case VCODE_TYPE_TRIGGER:
4162
   case VCODE_TYPE_RESOLUTION:
4163
      op->type = vtype_pointer(var->type);
50,934✔
4164
      op->result = vcode_add_reg(op->type);
50,934✔
4165
      vcode_reg_data(op->result)->bounds = var->bounds;
50,934✔
4166
      break;
50,934✔
4167

4168
   default:
UNCOV
4169
      VCODE_ASSERT(false, "variable %s cannot be indexed",
×
4170
                   istr(var->name));
4171
   }
4172
}
78,988✔
4173

4174
vcode_reg_t emit_index(vcode_var_t var, vcode_reg_t offset)
33,884✔
4175
{
4176
   // Try to find a previous index of this var by this offset
4177
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_INDEX) {
1,378,012✔
4178
      if (other->address == var
82,778✔
4179
          && ((offset == VCODE_INVALID_REG && other->args.count == 0)
7,216✔
UNCOV
4180
              || (offset != VCODE_INVALID_REG
×
UNCOV
4181
                  && other->args.items[0] == offset)))
×
4182
         return other->result;
7,216✔
4183
   }
4184

4185
   op_t *op = vcode_add_op(VCODE_OP_INDEX);
26,668✔
4186
   op->address = var;
26,668✔
4187

4188
   if (offset != VCODE_INVALID_REG)
26,668✔
UNCOV
4189
      vcode_add_arg(op, offset);
×
4190

4191
   vcode_calculate_var_index_type(op, vcode_var_data(var));
26,668✔
4192

4193
   if (offset != VCODE_INVALID_REG)
26,668✔
UNCOV
4194
      VCODE_ASSERT(vtype_kind(vcode_reg_type(offset)) == VCODE_TYPE_OFFSET,
×
4195
                   "index offset r%d does not have offset type", offset);
4196

4197
   return op->result;
26,668✔
4198
}
4199

4200
vcode_reg_t emit_cast(vcode_type_t type, vcode_type_t bounds, vcode_reg_t reg)
252,636✔
4201
{
4202
   if (vtype_eq(vcode_reg_type(reg), type))
252,636✔
4203
      return reg;
252,636✔
4204

4205
   vtype_kind_t from = vtype_kind(vcode_reg_type(reg));
85,650✔
4206
   vtype_kind_t to   = vtype_kind(type);
85,650✔
4207

4208
   const bool integral =
171,300✔
4209
      (from == VCODE_TYPE_OFFSET || from == VCODE_TYPE_INT)
85,650✔
4210
      && (to == VCODE_TYPE_OFFSET || to == VCODE_TYPE_INT);
85,650✔
4211

4212
   int64_t value;
85,650✔
4213
   if (integral && vcode_reg_const(reg, &value))
85,650✔
4214
      return emit_const(type, value);
12,692✔
4215

4216
   // Try to find a previous cast of this register to this type
4217
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CAST) {
1,447,470✔
4218
      if (vtype_eq(other->type, type) && other->args.items[0] == reg)
146,206✔
4219
         return other->result;
15,918✔
4220
   }
4221

4222
   op_t *op = vcode_add_op(VCODE_OP_CAST);
57,040✔
4223
   vcode_add_arg(op, reg);
57,040✔
4224
   op->type   = type;
57,040✔
4225
   op->result = vcode_add_reg(type);
57,040✔
4226

4227
   static const vcode_type_t allowed[][2] = {
57,040✔
4228
      { VCODE_TYPE_INT,    VCODE_TYPE_OFFSET  },
4229
      { VCODE_TYPE_OFFSET, VCODE_TYPE_INT     },
4230
      { VCODE_TYPE_INT,    VCODE_TYPE_INT     },
4231
      { VCODE_TYPE_INT,    VCODE_TYPE_REAL    },
4232
      { VCODE_TYPE_REAL,   VCODE_TYPE_INT     },
4233
      { VCODE_TYPE_REAL,   VCODE_TYPE_REAL    },
4234
      { VCODE_TYPE_ACCESS, VCODE_TYPE_ACCESS  },
4235
   };
4236

4237
   if (integral) {
57,040✔
4238
      vtype_t *vt = vcode_type_data(type);
56,198✔
4239
      int64_t low = vt->low, high = vt->high;
56,198✔
4240

4241
      vtype_t *rt = vcode_type_data(vcode_reg_bounds(reg));
56,198✔
4242
      low = MAX(low, rt->low);
56,198✔
4243
      high = MIN(high, rt->high);
56,198✔
4244

4245
      if (bounds != VCODE_INVALID_REG) {
56,198✔
4246
         vtype_t *bt = vcode_type_data(bounds);
33,044✔
4247
         low = MAX(low, bt->low);
33,044✔
4248
         high = MIN(high, bt->high);
33,044✔
4249
      }
4250

4251
      reg_t *rr = vcode_reg_data(op->result);
56,198✔
4252
      rr->bounds = vtype_int(low, high);
56,198✔
4253
   }
4254
   else if (bounds != VCODE_INVALID_REG)
842✔
4255
      vcode_reg_data(op->result)->bounds = bounds;
842✔
4256

4257
   for (size_t i = 0; i < ARRAY_LEN(allowed); i++) {
98,996✔
4258
      if (from == allowed[i][0] && to == allowed[i][1])
98,996✔
4259
         return op->result;
57,040✔
4260
   }
4261

UNCOV
4262
   VCODE_ASSERT(false, "invalid type conversion in cast");
×
4263
}
4264

4265
void emit_return(vcode_reg_t reg)
58,111✔
4266
{
4267
   op_t *op = vcode_add_op(VCODE_OP_RETURN);
58,111✔
4268
   if (reg != VCODE_INVALID_REG) {
58,111✔
4269
      vcode_add_arg(op, reg);
25,125✔
4270

4271
      const vtype_kind_t rkind = vcode_reg_kind(reg);
25,125✔
4272
      if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY)
25,125✔
4273
         vcode_heap_allocate(reg);
4,568✔
4274

4275
      VCODE_ASSERT(active_unit->kind == VCODE_UNIT_FUNCTION
25,125✔
4276
                   || active_unit->kind == VCODE_UNIT_THUNK
4277
                   || active_unit->kind == VCODE_UNIT_PROPERTY,
4278
                   "returning value fron non-function unit");
4279
      VCODE_ASSERT((active_unit->kind == VCODE_UNIT_PROPERTY
25,125✔
4280
                    && rkind == VCODE_TYPE_INT)
4281
                   || vtype_eq(active_unit->result, vcode_reg_type(reg))
4282
                   || (vtype_kind(active_unit->result) == VCODE_TYPE_ACCESS
4283
                       && rkind == VCODE_TYPE_ACCESS),
4284
                   "return value incorrect type");
4285
   }
4286
}
58,111✔
4287

4288
void emit_sched_waveform(vcode_reg_t nets, vcode_reg_t nnets,
11,225✔
4289
                         vcode_reg_t values, vcode_reg_t reject,
4290
                         vcode_reg_t after)
4291
{
4292
   int64_t nconst;
11,225✔
4293
   if (vcode_reg_const(nnets, &nconst) && nconst == 0) {
11,225✔
4294
      emit_comment("Skip empty waveform");
9✔
4295
      return;
9✔
4296
   }
4297

4298
   op_t *op = vcode_add_op(VCODE_OP_SCHED_WAVEFORM);
11,216✔
4299
   vcode_add_arg(op, nets);
11,216✔
4300
   vcode_add_arg(op, nnets);
11,216✔
4301
   vcode_add_arg(op, values);
11,216✔
4302
   vcode_add_arg(op, reject);
11,216✔
4303
   vcode_add_arg(op, after);
11,216✔
4304

4305
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
11,216✔
4306
                "sched_waveform target is not signal");
4307
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
11,216✔
4308
                "sched_waveform net count is not offset type");
4309
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
11,216✔
4310
                "signal cannot be values argument for sched_waveform");
4311
}
4312

4313
void emit_force(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t values)
76✔
4314
{
4315
   op_t *op = vcode_add_op(VCODE_OP_FORCE);
76✔
4316
   vcode_add_arg(op, nets);
76✔
4317
   vcode_add_arg(op, nnets);
76✔
4318
   vcode_add_arg(op, values);
76✔
4319

4320
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
76✔
4321
                "force target is not signal");
4322
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
76✔
4323
                "force net count is not offset type");
4324
}
76✔
4325

4326
void emit_release(vcode_reg_t nets, vcode_reg_t nnets)
42✔
4327
{
4328
   op_t *op = vcode_add_op(VCODE_OP_RELEASE);
42✔
4329
   vcode_add_arg(op, nets);
42✔
4330
   vcode_add_arg(op, nnets);
42✔
4331

4332
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
42✔
4333
                "release target is not signal");
4334
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
42✔
4335
                "release net count is not offset type");
4336
}
42✔
4337

4338
void emit_disconnect(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t reject,
24✔
4339
                     vcode_reg_t after)
4340
{
4341
   op_t *op = vcode_add_op(VCODE_OP_DISCONNECT);
24✔
4342
   vcode_add_arg(op, nets);
24✔
4343
   vcode_add_arg(op, nnets);
24✔
4344
   vcode_add_arg(op, reject);
24✔
4345
   vcode_add_arg(op, after);
24✔
4346

4347
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
24✔
4348
                "disconnect target is not signal");
4349
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
24✔
4350
                "disconnect net count is not offset type");
4351
}
24✔
4352

4353
void emit_cond(vcode_reg_t test, vcode_block_t btrue, vcode_block_t bfalse)
33,700✔
4354
{
4355
   int64_t tconst;
33,700✔
4356
   if (vcode_reg_const(test, &tconst)) {
33,700✔
4357
      emit_jump(!!tconst ? btrue : bfalse);
3,974✔
4358
      return;
2,026✔
4359
   }
4360

4361
   op_t *op = vcode_add_op(VCODE_OP_COND);
31,674✔
4362
   vcode_add_arg(op, test);
31,674✔
4363
   vcode_add_target(op, btrue);
31,674✔
4364
   vcode_add_target(op, bfalse);
31,674✔
4365

4366
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
31,674✔
4367
                "cond test is not a bool");
4368
   VCODE_ASSERT(btrue != VCODE_INVALID_BLOCK && bfalse != VCODE_INVALID_BLOCK,
31,674✔
4369
                "invalid cond targets");
4370
}
4371

4372
vcode_reg_t emit_neg(vcode_reg_t lhs)
6,956✔
4373
{
4374
   int64_t lconst;
6,956✔
4375
   if (vcode_reg_const(lhs, &lconst))
6,956✔
UNCOV
4376
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4377

4378
   op_t *op = vcode_add_op(VCODE_OP_NEG);
6,956✔
4379
   vcode_add_arg(op, lhs);
6,956✔
4380
   op->result = vcode_add_reg(vcode_reg_type(lhs));
6,956✔
4381

4382
   return op->result;
6,956✔
4383
}
4384

4385
vcode_reg_t emit_trap_neg(vcode_reg_t lhs, vcode_reg_t locus)
467✔
4386
{
4387
   int64_t lconst;
467✔
4388
   if (vcode_reg_const(lhs, &lconst) && lconst >= 0)
467✔
UNCOV
4389
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4390
   else if (vcode_type_data(vcode_reg_data(lhs)->bounds)->low >= 0)
467✔
4391
      return emit_neg(lhs);   // Cannot overflow
210✔
4392

4393
   op_t *op = vcode_add_op(VCODE_OP_TRAP_NEG);
257✔
4394
   vcode_add_arg(op, lhs);
257✔
4395
   vcode_add_arg(op, locus);
257✔
4396

4397
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
257✔
4398
                "locus argument to trap neg must be a debug locus");
4399
   VCODE_ASSERT(vcode_reg_kind(lhs) == VCODE_TYPE_INT,
257✔
4400
                "trapping neg may only be used with integer types");
4401

4402
   return (op->result = vcode_add_reg(vcode_reg_type(lhs)));
257✔
4403
}
4404

4405
vcode_reg_t emit_abs(vcode_reg_t lhs)
686✔
4406
{
4407
   int64_t lconst;
686✔
4408
   if (vcode_reg_const(lhs, &lconst))
686✔
4409
      return emit_const(vcode_reg_type(lhs), llabs(lconst));
1✔
4410

4411
   op_t *op = vcode_add_op(VCODE_OP_ABS);
685✔
4412
   vcode_add_arg(op, lhs);
685✔
4413
   op->result = vcode_add_reg(vcode_reg_type(lhs));
685✔
4414

4415
   return op->result;
685✔
4416
}
4417

4418
void emit_comment(const char *fmt, ...)
79,373✔
4419
{
4420
#ifndef NDEBUG
4421
   va_list ap;
79,373✔
4422
   va_start(ap, fmt);
79,373✔
4423

4424
   char *buf = xvasprintf(fmt, ap);
79,373✔
4425
   for (char *p = buf + strlen(buf) - 1;
79,373✔
4426
        p >= buf && isspace_iso88591(*p); p--)
79,373✔
UNCOV
4427
      *p = '\0';
×
4428

4429
   vcode_add_op(VCODE_OP_COMMENT)->comment = buf;
79,373✔
4430
   va_end(ap);
79,373✔
4431
#endif
4432
}
79,373✔
4433

4434
vcode_reg_t emit_select(vcode_reg_t test, vcode_reg_t rtrue,
19,010✔
4435
                        vcode_reg_t rfalse)
4436
{
4437
   int64_t tconst;
19,010✔
4438
   if (vcode_reg_const(test, &tconst))
19,010✔
4439
      return !!tconst ? rtrue : rfalse;
4,759✔
4440
   else if (rtrue == rfalse)
14,251✔
4441
      return rtrue;
4442

4443
   // Find a previous identical select
4444
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_SELECT) {
312,710✔
4445
      if (other->args.items[0] == test && other->args.items[1] == rtrue
11,160✔
4446
          && other->args.items[2] == rfalse)
649✔
4447
         return other->result;
556✔
4448
   }
4449

4450
   op_t *op = vcode_add_op(VCODE_OP_SELECT);
13,520✔
4451
   vcode_add_arg(op, test);
13,520✔
4452
   vcode_add_arg(op, rtrue);
13,520✔
4453
   vcode_add_arg(op, rfalse);
13,520✔
4454
   op->result = vcode_add_reg(vcode_reg_type(rtrue));
13,520✔
4455

4456
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
13,520✔
4457
                "select test must have bool type");
4458
   VCODE_ASSERT(vtype_eq(vcode_reg_type(rtrue), vcode_reg_type(rfalse)),
13,520✔
4459
                "select arguments are not the same type");
4460

4461
   return op->result;
13,520✔
4462
}
4463

4464
static vcode_reg_t emit_logical_identity(vcode_op_t op, vcode_reg_t reg, bool b)
442✔
4465
{
4466
   switch (op) {
442✔
4467
   case VCODE_OP_AND:  return b ? reg : emit_const(vtype_bool(), 0);
45✔
4468
   case VCODE_OP_OR:   return b ? emit_const(vtype_bool(), 1) : reg;
349✔
4469
   case VCODE_OP_XOR:  return b ? emit_not(reg) : reg;
12✔
4470
   case VCODE_OP_XNOR: return b ? reg : emit_not(reg);
12✔
4471
   case VCODE_OP_NAND: return b ? emit_not(reg) : emit_const(vtype_bool(), 1);
12✔
4472
   case VCODE_OP_NOR:  return b ? emit_const(vtype_bool(), 0) : emit_not(reg);
12✔
UNCOV
4473
   default:
×
4474
      fatal_trace("missing logicial identity for %s", vcode_op_string(op));
4475
   }
4476
}
4477

4478
static vcode_reg_t emit_logical(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs)
8,172✔
4479
{
4480
   vcode_type_t vtbool = vtype_bool();
8,172✔
4481

4482
   int64_t lconst, rconst;
8,172✔
4483
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
8,172✔
4484
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
8,172✔
4485
   if (l_is_const && r_is_const) {
8,172✔
4486
      switch (op) {
6✔
4487
      case VCODE_OP_AND:  return emit_const(vtbool, lconst && rconst);
×
4488
      case VCODE_OP_OR:   return emit_const(vtbool, lconst || rconst);
×
4489
      case VCODE_OP_XOR:  return emit_const(vtbool, lconst ^ rconst);
×
4490
      case VCODE_OP_XNOR: return emit_const(vtbool, !(lconst ^ rconst));
6✔
UNCOV
4491
      case VCODE_OP_NAND: return emit_const(vtbool, !(lconst && rconst));
×
UNCOV
4492
      case VCODE_OP_NOR:  return emit_const(vtbool, !(lconst || rconst));
×
UNCOV
4493
      default:
×
4494
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
4495
      }
4496
   }
4497
   else if (l_is_const)
8,166✔
4498
      return emit_logical_identity(op, rhs, !!lconst);
342✔
4499
   else if (r_is_const)
7,824✔
4500
      return emit_logical_identity(op, lhs, !!rconst);
100✔
4501
   else if (lhs == rhs) {
7,724✔
4502
      switch (op) {
27✔
4503
      case VCODE_OP_AND:
4504
      case VCODE_OP_OR:
4505
         return lhs;
4506
      case VCODE_OP_NAND:
6✔
4507
      case VCODE_OP_NOR:
4508
         return emit_not(lhs);
6✔
4509
      case VCODE_OP_XOR:
3✔
4510
         return emit_const(vtbool, 0);
3✔
UNCOV
4511
      case VCODE_OP_XNOR:
×
UNCOV
4512
         return emit_const(vtbool, 1);
×
UNCOV
4513
      default:
×
4514
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
4515
      }
4516
   }
4517

4518
   vcode_reg_t result = emit_arith(op, lhs, rhs, VCODE_INVALID_REG);
7,697✔
4519

4520
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vtbool)
7,697✔
4521
                && vtype_eq(vcode_reg_type(rhs), vtbool),
4522
                "arguments to %s are not boolean", vcode_op_string(op));
4523

4524
   return result;
4525
}
4526

4527
vcode_reg_t emit_or(vcode_reg_t lhs, vcode_reg_t rhs)
2,395✔
4528
{
4529
   return emit_logical(VCODE_OP_OR, lhs, rhs);
2,395✔
4530
}
4531

4532
vcode_reg_t emit_and(vcode_reg_t lhs, vcode_reg_t rhs)
5,541✔
4533
{
4534
   return emit_logical(VCODE_OP_AND, lhs, rhs);
5,541✔
4535
}
4536

4537
vcode_reg_t emit_nand(vcode_reg_t lhs, vcode_reg_t rhs)
52✔
4538
{
4539
   return emit_logical(VCODE_OP_NAND, lhs, rhs);
52✔
4540
}
4541

4542
vcode_reg_t emit_nor(vcode_reg_t lhs, vcode_reg_t rhs)
53✔
4543
{
4544
   return emit_logical(VCODE_OP_NOR, lhs, rhs);
53✔
4545
}
4546

4547
vcode_reg_t emit_xor(vcode_reg_t lhs, vcode_reg_t rhs)
73✔
4548
{
4549
   return emit_logical(VCODE_OP_XOR, lhs, rhs);
73✔
4550
}
4551

4552
vcode_reg_t emit_xnor(vcode_reg_t lhs, vcode_reg_t rhs)
58✔
4553
{
4554
   return emit_logical(VCODE_OP_XNOR, lhs, rhs);
58✔
4555
}
4556

4557
vcode_reg_t emit_not(vcode_reg_t arg)
2,497✔
4558
{
4559
   int64_t cval;
2,497✔
4560
   if (vcode_reg_const(arg, &cval))
2,497✔
4561
      return emit_const(vtype_bool(), !cval);
27✔
4562

4563
   op_t *op = vcode_add_op(VCODE_OP_NOT);
2,470✔
4564
   vcode_add_arg(op, arg);
2,470✔
4565

4566
   vcode_type_t vtbool = vtype_bool();
2,470✔
4567
   VCODE_ASSERT(vtype_eq(vcode_reg_type(arg), vtbool),
2,470✔
4568
                "argument to not is not boolean");
4569

4570
   return (op->result = vcode_add_reg(vtbool));
2,470✔
4571
}
4572

4573
vcode_reg_t emit_wrap(vcode_reg_t data, const vcode_dim_t *dims, int ndims)
48,001✔
4574
{
4575
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_WRAP) {
1,759,924✔
4576
      if (other->args.count == ndims*3 + 1 && other->args.items[0] == data) {
156,388✔
4577
         bool match = true;
4578
         for (int i = 0; match && i < ndims; i++) {
22,806✔
4579
            match = other->args.items[i*3 + 1] == dims[i].left
11,435✔
4580
               && other->args.items[i*3 + 2] == dims[i].right
9,021✔
4581
               && other->args.items[i*3 + 3] == dims[i].dir;
20,189✔
4582
         }
4583
         if (match)
11,371✔
4584
            return other->result;
8,690✔
4585
      }
4586
   }
4587

4588
   op_t *op = vcode_add_op(VCODE_OP_WRAP);
39,311✔
4589
   vcode_add_arg(op, data);
39,311✔
4590
   for (int i = 0; i < ndims; i++) {
79,280✔
4591
      vcode_add_arg(op, dims[i].left);
39,969✔
4592
      vcode_add_arg(op, dims[i].right);
39,969✔
4593
      vcode_add_arg(op, dims[i].dir);
39,969✔
4594
   }
4595

4596
   vcode_type_t ptr_type = vcode_reg_type(data);
39,311✔
4597
   const vtype_kind_t ptrkind = vtype_kind(ptr_type);
39,311✔
4598
   VCODE_ASSERT(ptrkind == VCODE_TYPE_POINTER || ptrkind == VCODE_TYPE_SIGNAL,
39,311✔
4599
                "wrapped data is not pointer or signal");
4600

4601
#ifdef DEBUG
4602
   for (int i = 0; i < ndims; i++) {
79,280✔
4603
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].left)),
39,969✔
4604
                   "dimension %d left bound must be scalar", i + 1);
4605
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].right)),
39,969✔
4606
                   "dimension %d right bound must be scalar", i + 1);
4607
      VCODE_ASSERT(vtype_eq(vtype_bool(), vcode_reg_type(dims[i].dir)),
39,969✔
4608
                   "dimension %d direction must be bool", i + 1);
4609
   }
4610
#endif
4611

4612
   vcode_type_t elem = (ptrkind == VCODE_TYPE_POINTER)
78,622✔
4613
      ? vtype_pointed(ptr_type) : ptr_type;
39,311✔
4614

4615
   op->result = vcode_add_reg(
39,311✔
4616
      vtype_uarray(ndims, elem, vcode_reg_bounds(data)));
4617

4618
   return op->result;
39,311✔
4619
}
4620

4621
static vcode_reg_t emit_uarray_op(vcode_op_t o, vcode_type_t rtype,
106,263✔
4622
                                  vcode_reg_t array, unsigned dim,
4623
                                  unsigned arg_index)
4624
{
4625
   // Reuse any previous operation in this block with the same arguments
4626
   VCODE_FOR_EACH_OP(other) {
1,214,956✔
4627
      if (other->kind == o && other->args.items[0] == array && other->dim == dim
1,168,364✔
4628
          && (rtype == VCODE_INVALID_TYPE
24,683✔
4629
              || vtype_eq(rtype, vcode_reg_type(other->result))))
10,787✔
4630
         return other->result;
24,683✔
4631
      else if (other->kind == VCODE_OP_WRAP && other->result == array)
1,143,681✔
4632
         return other->args.items[1 + (dim * 3) + arg_index];
34,988✔
4633
   }
4634

4635
   op_t *op = vcode_add_op(o);
46,592✔
4636
   vcode_add_arg(op, array);
46,592✔
4637
   op->dim = dim;
46,592✔
4638

4639
   vcode_type_t atype = vcode_reg_type(array);
46,592✔
4640
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
46,592✔
4641
                "cannot use %s with non-uarray type", vcode_op_string(o));
4642

4643
   vtype_t *vt = vcode_type_data(atype);
46,592✔
4644
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
46,592✔
4645

4646
   if (rtype == VCODE_INVALID_TYPE)
46,592✔
4647
      rtype = vtype_offset();
30,126✔
4648

4649
   return (op->result = vcode_add_reg(rtype));
46,592✔
4650
}
4651

4652
vcode_reg_t emit_uarray_left(vcode_reg_t array, unsigned dim)
39,282✔
4653
{
4654
   return emit_uarray_op(VCODE_OP_UARRAY_LEFT, VCODE_INVALID_TYPE,
39,282✔
4655
                         array, dim, 0);
4656
}
4657

4658
vcode_reg_t emit_uarray_right(vcode_reg_t array, unsigned dim)
27,964✔
4659
{
4660
   return emit_uarray_op(VCODE_OP_UARRAY_RIGHT, VCODE_INVALID_TYPE,
27,964✔
4661
                         array, dim, 1);
4662
}
4663

4664
vcode_reg_t emit_uarray_dir(vcode_reg_t array, unsigned dim)
39,017✔
4665
{
4666
   return emit_uarray_op(VCODE_OP_UARRAY_DIR, vtype_bool(),
39,017✔
4667
                         array, dim, 2);
4668
}
4669

4670
vcode_reg_t emit_uarray_len(vcode_reg_t array, unsigned dim)
46,359✔
4671
{
4672
   VCODE_FOR_EACH_OP(other) {
673,960✔
4673
      if (other->kind == VCODE_OP_UARRAY_LEN) {
651,909✔
4674
         if (other->args.items[0] == array && other->dim == dim)
40,950✔
4675
            return other->result;
9,558✔
4676
      }
4677
      else if (other->kind == VCODE_OP_WRAP && other->result == array) {
610,959✔
4678
         VCODE_ASSERT(dim < (other->args.count - 1) / 3,
14,750✔
4679
                      "array dimension %d out of bounds", dim);
4680

4681
         vcode_reg_t left_reg = other->args.items[dim * 3 + 1];
14,750✔
4682
         vcode_reg_t right_reg = other->args.items[dim * 3 + 2];
14,750✔
4683
         vcode_reg_t dir_reg = other->args.items[dim * 3 + 3];
14,750✔
4684
         return emit_range_length(left_reg, right_reg, dir_reg);
14,750✔
4685
      }
4686
   }
4687

4688
   op_t *op = vcode_add_op(VCODE_OP_UARRAY_LEN);
22,051✔
4689
   vcode_add_arg(op, array);
22,051✔
4690
   op->dim = dim;
22,051✔
4691

4692
   vcode_type_t atype = vcode_reg_type(array);
22,051✔
4693
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
22,051✔
4694
                "cannot use uarray len with non-uarray type");
4695

4696
   vtype_t *vt = vcode_type_data(atype);
22,051✔
4697
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
22,051✔
4698

4699
   op->result = vcode_add_reg(vtype_offset());
22,051✔
4700

4701
   reg_t *rr = vcode_reg_data(op->result);
22,051✔
4702
   rr->bounds = vtype_int(0, INT64_MAX);
22,051✔
4703

4704
   return op->result;
22,051✔
4705
}
4706

4707
vcode_reg_t emit_unwrap(vcode_reg_t array)
36,546✔
4708
{
4709
   VCODE_FOR_EACH_OP(other) {
1,570,024✔
4710
      if (other->kind == VCODE_OP_WRAP && other->result == array)
1,543,680✔
4711
         return other->args.items[0];
8,462✔
4712
      else if (other->kind == VCODE_OP_UNWRAP && other->args.items[0] == array)
1,535,218✔
4713
         return other->result;
1,740✔
4714
   }
4715

4716
   op_t *op = vcode_add_op(VCODE_OP_UNWRAP);
26,344✔
4717
   vcode_add_arg(op, array);
26,344✔
4718

4719
   vtype_t *vt = vcode_type_data(vcode_reg_type(array));
26,344✔
4720
   VCODE_ASSERT(vt->kind == VCODE_TYPE_UARRAY,
26,344✔
4721
                "unwrap can only only be used with uarray types");
4722

4723
   vcode_type_t elem = vt->elem;
26,344✔
4724

4725
   vcode_type_t rtype = (vtype_kind(elem) == VCODE_TYPE_SIGNAL)
26,344✔
4726
      ? elem : vtype_pointer(elem);
26,344✔
4727

4728
   op->result = vcode_add_reg(rtype);
26,344✔
4729

4730
   reg_t *rr = vcode_reg_data(op->result);
26,344✔
4731
   rr->bounds = elem;
26,344✔
4732

4733
   return op->result;
26,344✔
4734
}
4735

4736
vcode_reg_t emit_range_null(vcode_reg_t left, vcode_reg_t right,
29,286✔
4737
                            vcode_reg_t dir)
4738
{
4739
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RANGE_NULL) {
1,413,171✔
UNCOV
4740
      if (other->args.items[0] == left
×
UNCOV
4741
          && other->args.items[1] == right
×
UNCOV
4742
          && other->args.items[2] == dir)
×
UNCOV
4743
         return other->result;
×
4744
   }
4745

4746
   int64_t dir_const;
29,286✔
4747
   if (vcode_reg_const(dir, &dir_const)) {
29,286✔
4748
      vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
26,279✔
4749
      vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
26,279✔
4750

4751
      if (dir_const == RANGE_TO && lbounds->low > rbounds->high)
26,279✔
4752
         return emit_const(vtype_bool(), 1);
65✔
4753
      else if (dir_const == RANGE_TO && lbounds->high <= rbounds->low)
26,214✔
4754
         return emit_const(vtype_bool(), 0);
18,278✔
4755
      else if (dir_const == RANGE_DOWNTO && rbounds->low > lbounds->high)
7,936✔
4756
         return emit_const(vtype_bool(), 1);
611✔
4757
      else if (dir_const == RANGE_DOWNTO && rbounds->high <= lbounds->low)
7,325✔
4758
         return emit_const(vtype_bool(), 0);
1,816✔
4759
      else if (dir_const == RANGE_TO)
5,509✔
4760
         return emit_cmp(VCODE_CMP_GT, left, right);
2,804✔
4761
      else
4762
         return emit_cmp(VCODE_CMP_GT, right, left);
2,705✔
4763
   }
4764

4765
   op_t *op = vcode_add_op(VCODE_OP_RANGE_NULL);
3,007✔
4766
   vcode_add_arg(op, left);
3,007✔
4767
   vcode_add_arg(op, right);
3,007✔
4768
   vcode_add_arg(op, dir);
3,007✔
4769

4770
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
3,007✔
4771
                "range left and right have different types");
4772
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
3,007✔
4773
                "dir argument to range length is not int");
4774

4775
   return (op->result = vcode_add_reg(vtype_bool()));
3,007✔
4776
}
4777

4778
vcode_reg_t emit_range_length(vcode_reg_t left, vcode_reg_t right,
14,788✔
4779
                              vcode_reg_t dir)
4780
{
4781
   vcode_reg_t left_array = VCODE_INVALID_REG,
14,788✔
4782
      right_array = VCODE_INVALID_REG,
14,788✔
4783
      dir_array = VCODE_INVALID_REG;
14,788✔
4784
   int left_dim = -1, right_dim = -1, dir_dim = -1;
14,788✔
4785

4786
   VCODE_FOR_EACH_OP(other) {
292,240✔
4787
      if (other->kind == VCODE_OP_RANGE_LENGTH
282,985✔
4788
          && other->args.items[0] == left
7,856✔
4789
          && other->args.items[1] == right
5,850✔
4790
          && other->args.items[2] == dir)
5,533✔
4791
         return other->result;
5,533✔
4792
      else if (other->kind == VCODE_OP_UARRAY_LEFT && other->result == left) {
277,452✔
4793
         left_array = other->args.items[0];
362✔
4794
         left_dim = other->dim;
362✔
4795
      }
4796
      else if (other->kind == VCODE_OP_UARRAY_RIGHT && other->result == right) {
277,090✔
4797
         right_array = other->args.items[0];
362✔
4798
         right_dim = other->dim;
362✔
4799
      }
4800
      else if (other->kind == VCODE_OP_UARRAY_DIR && other->result == dir) {
276,728✔
4801
         dir_array = other->args.items[0];
706✔
4802
         dir_dim = other->dim;
706✔
4803
      }
4804
   }
4805

4806
   if (left_array != VCODE_INVALID_REG && left_array == right_array
9,255✔
4807
       && right_array == dir_array && left_dim == right_dim
362✔
4808
       && right_dim == dir_dim)
362✔
4809
      return emit_uarray_len(left_array, left_dim);
362✔
4810

4811
   int64_t lconst, rconst, dconst;
8,893✔
4812
   if (vcode_reg_const(dir, &dconst) && vcode_reg_const(left, &lconst)
8,893✔
4813
       && vcode_reg_const(right, &rconst)) {
4,868✔
4814

4815
      int64_t diff;
1,837✔
4816
      if (dconst == RANGE_TO)
1,837✔
4817
         diff = rconst - lconst;
1,543✔
4818
      else
4819
         diff = lconst - rconst;
294✔
4820

4821
      return emit_const(vtype_offset(), diff < 0 ? 0 : diff + 1);
1,837✔
4822
   }
4823

4824
   op_t *op = vcode_add_op(VCODE_OP_RANGE_LENGTH);
7,056✔
4825
   vcode_add_arg(op, left);
7,056✔
4826
   vcode_add_arg(op, right);
7,056✔
4827
   vcode_add_arg(op, dir);
7,056✔
4828

4829
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
7,056✔
4830
                "range left and right have different types");
4831
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
7,056✔
4832
                "dir argument to range length is not int");
4833

4834
   op->result = vcode_add_reg(vtype_offset());
7,056✔
4835

4836
   reg_t *rr = vcode_reg_data(op->result);
7,056✔
4837
   rr->bounds = vtype_int(0, INT64_MAX);
7,056✔
4838

4839
   return op->result;
7,056✔
4840
}
4841

4842
vcode_reg_t emit_var_upref(int hops, vcode_var_t var)
64,652✔
4843
{
4844
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_VAR_UPREF) {
548,040✔
4845
      if (other->hops == hops && other->address == var)
74,918✔
4846
         return other->result;
12,332✔
4847
   }
4848

4849
   op_t *op = vcode_add_op(VCODE_OP_VAR_UPREF);
52,320✔
4850
   op->hops    = hops;
52,320✔
4851
   op->address = var;
52,320✔
4852

4853
   VCODE_ASSERT(hops > 0, "invalid hop count");
52,320✔
4854

4855
   vcode_unit_t vu = active_unit;
52,320✔
4856
   for (int i = 0; i < hops; i++) {
117,239✔
4857
      vu = vu->context;
64,919✔
4858
      VCODE_ASSERT(vu, "hop count is greater than depth");
64,919✔
4859
   }
4860

4861
   VCODE_ASSERT(var < vu->vars.count, "upref %d is not a variable", var);
52,320✔
4862

4863
   vcode_calculate_var_index_type(op, &(vu->vars.items[var]));
52,320✔
4864

4865
   return op->result;
52,320✔
4866
}
4867

4868
vcode_reg_t emit_init_signal(vcode_type_t type, vcode_reg_t count,
16,146✔
4869
                             vcode_reg_t size, vcode_reg_t value,
4870
                             vcode_reg_t flags, vcode_reg_t locus,
4871
                             vcode_reg_t offset)
4872
{
4873
   op_t *op = vcode_add_op(VCODE_OP_INIT_SIGNAL);
16,146✔
4874
   vcode_add_arg(op, count);
16,146✔
4875
   vcode_add_arg(op, size);
16,146✔
4876
   vcode_add_arg(op, value);
16,146✔
4877
   vcode_add_arg(op, flags);
16,146✔
4878
   vcode_add_arg(op, locus);
16,146✔
4879
   if (offset != VCODE_INVALID_REG)
16,146✔
4880
      vcode_add_arg(op, offset);
5,727✔
4881

4882
   vcode_type_t vtype = vcode_reg_type(value);
16,146✔
4883
   VCODE_ASSERT(vtype_is_scalar(type), "signal type must be scalar");
16,146✔
4884
   VCODE_ASSERT(vtype_eq(vtype, type)
16,146✔
4885
                || vtype_kind(vtype) == VCODE_TYPE_POINTER,
4886
                "init signal value type does not match signal type");
4887
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
16,146✔
4888
                "locus argument to init signal must be a debug locus");
4889
   VCODE_ASSERT(offset == VCODE_INVALID_REG
16,146✔
4890
                || vcode_reg_kind(offset) == VCODE_TYPE_POINTER,
4891
                "init signal offset argument must have pointer type");
4892

4893
   return (op->result = vcode_add_reg(vtype_signal(type)));
16,146✔
4894
}
4895

4896
void emit_resolve_signal(vcode_reg_t signal, vcode_reg_t resolution)
3,376✔
4897
{
4898
   op_t *op = vcode_add_op(VCODE_OP_RESOLVE_SIGNAL);
3,376✔
4899
   vcode_add_arg(op, signal);
3,376✔
4900
   vcode_add_arg(op, resolution);
3,376✔
4901

4902
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
3,376✔
4903
                "signal argument has wrong type");
4904

4905
   vcode_type_t rtype = vcode_reg_type(resolution);
3,376✔
4906
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
3,376✔
4907
                "resolution wrapper argument must be pointer");
4908
   VCODE_ASSERT(vtype_kind(vtype_pointed(rtype)) == VCODE_TYPE_RESOLUTION,
3,376✔
4909
                "resolution wrapper argument has wrong type");
4910
}
3,376✔
4911

4912
vcode_reg_t emit_implicit_signal(vcode_type_t type, vcode_reg_t count,
72✔
4913
                                 vcode_reg_t size, vcode_reg_t locus,
4914
                                 vcode_reg_t kind, vcode_reg_t closure,
4915
                                 vcode_reg_t delay)
4916
{
4917
   op_t *op = vcode_add_op(VCODE_OP_IMPLICIT_SIGNAL);
72✔
4918
   vcode_add_arg(op, count);
72✔
4919
   vcode_add_arg(op, size);
72✔
4920
   vcode_add_arg(op, locus);
72✔
4921
   vcode_add_arg(op, kind);
72✔
4922
   vcode_add_arg(op, closure);
72✔
4923
   vcode_add_arg(op, delay);
72✔
4924

4925
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
72✔
4926
                "count argument to implicit signal is not offset");
4927
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
72✔
4928
                "kind argument to implicit signal is not offset");
4929
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
72✔
4930
                "closure argument to implicit signal is not a closure");
4931
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
72✔
4932
                "locus argument to implicit signal must be a debug locus");
4933
   VCODE_ASSERT(vcode_reg_kind(delay) == VCODE_TYPE_INT,
72✔
4934
                "delay argument to implicit signal must be time");
4935

4936
   return (op->result = vcode_add_reg(vtype_signal(type)));
72✔
4937
}
4938

4939
void emit_map_signal(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
5,418✔
4940
{
4941
   op_t *op = vcode_add_op(VCODE_OP_MAP_SIGNAL);
5,418✔
4942
   vcode_add_arg(op, src);
5,418✔
4943
   vcode_add_arg(op, dst);
5,418✔
4944
   vcode_add_arg(op, count);
5,418✔
4945

4946
   VCODE_ASSERT(vcode_reg_kind(src) == VCODE_TYPE_SIGNAL,
5,418✔
4947
                "src argument to map signal is not a signal");
4948
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
5,418✔
4949
                "dst argument to map signal is not a signal");
4950
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
5,418✔
4951
                "count argument type to map signal is not offset");
4952
}
5,418✔
4953

4954
void emit_map_const(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
200✔
4955
{
4956
   op_t *op = vcode_add_op(VCODE_OP_MAP_CONST);
200✔
4957
   vcode_add_arg(op, src);
200✔
4958
   vcode_add_arg(op, dst);
200✔
4959
   vcode_add_arg(op, count);
200✔
4960

4961
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
200✔
4962
                "dst argument to map const is not a signal");
4963
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
200✔
4964
                "count argument type to map const is not offset");
4965
}
200✔
4966

4967
void emit_map_implicit(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
54✔
4968
{
4969
   op_t *op = vcode_add_op(VCODE_OP_MAP_IMPLICIT);
54✔
4970
   vcode_add_arg(op, src);
54✔
4971
   vcode_add_arg(op, dst);
54✔
4972
   vcode_add_arg(op, count);
54✔
4973

4974
   VCODE_ASSERT(vcode_reg_kind(src) == VCODE_TYPE_SIGNAL,
54✔
4975
                "src argument to map implicit is not a signal");
4976
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
54✔
4977
                "dst argument to map implicit is not a signal");
4978
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
54✔
4979
                "count argument type to map implicit is not offset");
4980
}
54✔
4981

4982
void emit_drive_signal(vcode_reg_t target, vcode_reg_t count)
9,468✔
4983
{
4984
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DRIVE_SIGNAL) {
117,512✔
4985
      if (other->args.items[0] == target && other->args.items[1] == count)
13,815✔
4986
         return;
4987
   }
4988

4989
   op_t *op = vcode_add_op(VCODE_OP_DRIVE_SIGNAL);
9,465✔
4990
   vcode_add_arg(op, target);
9,465✔
4991
   vcode_add_arg(op, count);
9,465✔
4992

4993
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
9,465✔
4994
                "target argument to drive signal is not a signal");
4995
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
9,465✔
4996
                "count argument type to drive signal is not offset");
4997
}
4998

4999
void emit_transfer_signal(vcode_reg_t target, vcode_reg_t source,
1,192✔
5000
                          vcode_reg_t count, vcode_reg_t reject,
5001
                          vcode_reg_t after)
5002
{
5003
   op_t *op = vcode_add_op(VCODE_OP_TRANSFER_SIGNAL);
1,192✔
5004
   vcode_add_arg(op, target);
1,192✔
5005
   vcode_add_arg(op, source);
1,192✔
5006
   vcode_add_arg(op, count);
1,192✔
5007
   vcode_add_arg(op, reject);
1,192✔
5008
   vcode_add_arg(op, after);
1,192✔
5009

5010
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
1,192✔
5011
                "target argument to transfer signal is not a signal");
5012
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
1,192✔
5013
                "count argument type to transfer signal is not offset");
5014
   VCODE_ASSERT(vcode_reg_kind(source) == VCODE_TYPE_SIGNAL,
1,192✔
5015
                "source argument to transfer signal is not a signal");
5016
}
1,192✔
5017

5018
vcode_reg_t emit_resolution_wrapper(vcode_type_t type, vcode_reg_t closure,
5,039✔
5019
                                    vcode_reg_t nlits)
5020
{
5021
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RESOLUTION_WRAPPER) {
82,631✔
5022
      if (other->args.items[0] == closure && other->args.items[1] == nlits)
11,010✔
UNCOV
5023
         return other->result;
×
5024
   }
5025

5026
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
5,039✔
5027
                "first argument to resolution wrapper must be closure");
5028

5029
   op_t *op = vcode_add_op(VCODE_OP_RESOLUTION_WRAPPER);
5,039✔
5030
   vcode_add_arg(op, closure);
5,039✔
5031
   vcode_add_arg(op, nlits);
5,039✔
5032

5033
   return (op->result = vcode_add_reg(vtype_resolution(type)));
5,039✔
5034
}
5035

5036
vcode_reg_t emit_closure(ident_t func, vcode_reg_t context, vcode_type_t rtype)
5,333✔
5037
{
5038
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CLOSURE) {
83,979✔
5039
      if (other->func == func && other->args.items[0] == context)
11,181✔
UNCOV
5040
         return other->result;
×
5041
   }
5042

5043
   op_t *op = vcode_add_op(VCODE_OP_CLOSURE);
5,333✔
5044
   vcode_add_arg(op, context);
5,333✔
5045
   op->func = func;
5,333✔
5046

5047
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
5,333✔
5048
                "invalid closure context argument");
5049

5050
   return (op->result = vcode_add_reg(vtype_closure(rtype)));
5,333✔
5051
}
5052

5053
vcode_reg_t emit_package_init(ident_t name, vcode_reg_t context)
43,504✔
5054
{
5055
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_PACKAGE_INIT) {
80,945✔
5056
      if (other->func == name)
34,942✔
5057
         return other->result;
17,298✔
5058
   }
5059

5060
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_INIT);
26,206✔
5061
   op->func = name;
26,206✔
5062
   if (context != VCODE_INVALID_REG)
26,206✔
5063
      vcode_add_arg(op, context);
190✔
5064

5065
   VCODE_ASSERT(context == VCODE_INVALID_REG
26,206✔
5066
                || vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
5067
                "invalid protected init context argument");
5068
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_INSTANCE
26,206✔
5069
                || active_unit->kind == VCODE_UNIT_PACKAGE
5070
                || active_unit->kind == VCODE_UNIT_THUNK,
5071
                "cannot use package init here");
5072
   VCODE_ASSERT(name != active_unit->name, "cyclic package init");
26,206✔
5073

5074
   return (op->result = vcode_add_reg(vtype_context(name)));
26,206✔
5075
}
5076

5077
vcode_reg_t emit_protected_init(vcode_type_t type, vcode_reg_t context,
544✔
5078
                                vcode_reg_t path_name, vcode_reg_t inst_name)
5079
{
5080
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_INIT);
544✔
5081
   vcode_add_arg(op, context);
544✔
5082
   op->func = vtype_name(type);
544✔
5083

5084
   if (path_name != VCODE_INVALID_REG && inst_name != VCODE_INVALID_REG) {
544✔
5085
      vcode_add_arg(op, path_name);
414✔
5086
      vcode_add_arg(op, inst_name);
414✔
5087

5088
      VCODE_ASSERT(vcode_reg_kind(path_name) == VCODE_TYPE_UARRAY,
414✔
5089
                   "path name argument must be uarray");
5090
      VCODE_ASSERT(vcode_reg_kind(inst_name) == VCODE_TYPE_UARRAY,
414✔
5091
                   "inst name argument must be uarray");
5092
   }
5093

5094
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CONTEXT,
544✔
5095
                "protected init type must be context");
5096
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
544✔
5097
                "invalid protected init context argument");
5098

5099
   return (op->result = vcode_add_reg(type));
544✔
5100
}
5101

5102
void emit_process_init(ident_t name, vcode_reg_t locus)
111✔
5103
{
5104
   op_t *op = vcode_add_op(VCODE_OP_PROCESS_INIT);
111✔
5105
   vcode_add_arg(op, locus);
111✔
5106
   op->func = name;
111✔
5107

5108
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
111✔
5109
                "locus argument to process init must be a debug locus");
5110
}
111✔
5111

5112
void emit_protected_free(vcode_reg_t obj)
308✔
5113
{
5114
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_FREE);
308✔
5115
   vcode_add_arg(op, obj);
308✔
5116

5117
   VCODE_ASSERT(vcode_reg_kind(obj) == VCODE_TYPE_CONTEXT,
308✔
5118
                "protected object type must be context");
5119
}
308✔
5120

5121
vcode_reg_t emit_context_upref(int hops)
19,384✔
5122
{
5123
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONTEXT_UPREF) {
132,293✔
5124
      if (other->hops == hops)
8,640✔
5125
         return other->result;
8,592✔
5126
   }
5127

5128
   op_t *op = vcode_add_op(VCODE_OP_CONTEXT_UPREF);
10,792✔
5129
   op->hops = hops;
10,792✔
5130

5131
   VCODE_ASSERT(hops >= 0, "invalid hop count");
10,792✔
5132

5133
   vcode_unit_t vu = active_unit;
10,792✔
5134
   for (int i = 0; i < hops; i++) {
18,989✔
5135
      vu = vu->context;
8,197✔
5136
      VCODE_ASSERT(vu, "hop count is greater than depth");
8,197✔
5137
   }
5138

5139
   return (op->result = vcode_add_reg(vtype_context(vu->name)));
10,792✔
5140
}
5141

5142
static vcode_reg_t emit_signal_flag(vcode_op_t opkind, vcode_reg_t nets,
658✔
5143
                                    vcode_reg_t len)
5144
{
5145
   op_t *op = vcode_add_op(opkind);
658✔
5146
   vcode_add_arg(op, nets);
658✔
5147
   vcode_add_arg(op, len);
658✔
5148

5149
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
658✔
5150
                "argument to %s is not a signal", vcode_op_string(opkind));
5151

5152
   return (op->result = vcode_add_reg(vtype_bool()));
658✔
5153
}
5154

5155
vcode_reg_t emit_event_flag(vcode_reg_t nets, vcode_reg_t len)
441✔
5156
{
5157
   return emit_signal_flag(VCODE_OP_EVENT, nets, len);
441✔
5158
}
5159

5160
vcode_reg_t emit_active_flag(vcode_reg_t nets, vcode_reg_t len)
217✔
5161
{
5162
   return emit_signal_flag(VCODE_OP_ACTIVE, nets, len);
217✔
5163
}
5164

5165
vcode_reg_t emit_record_ref(vcode_reg_t record, unsigned field)
40,051✔
5166
{
5167
   // Try scanning backwards through the block for another record ref
5168
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RECORD_REF) {
2,783,223✔
5169
      if (other->args.items[0] == record && other->field == field)
518,046✔
5170
         return other->result;
3,883✔
5171
   }
5172

5173
   op_t *op = vcode_add_op(VCODE_OP_RECORD_REF);
36,168✔
5174
   op->field = field;
36,168✔
5175
   vcode_add_arg(op, record);
36,168✔
5176

5177
   vtype_t *rptype = vcode_type_data(vcode_reg_type(record));
36,168✔
5178

5179
   VCODE_ASSERT(rptype->kind == VCODE_TYPE_POINTER,
36,168✔
5180
                "argument to record ref must be a pointer");
5181

5182
   vtype_t *rtype = vcode_type_data(rptype->pointed);
36,168✔
5183
   VCODE_ASSERT(rtype->kind == VCODE_TYPE_RECORD,
36,168✔
5184
                "argument must be pointer to record or record signal");
5185

5186
   VCODE_ASSERT(field < rtype->fields.count, "invalid field %d", field);
36,168✔
5187

5188
   vcode_type_t field_type  = rtype->fields.items[field];
36,168✔
5189
   vcode_type_t bounds_type = field_type;
36,168✔
5190
   vcode_type_t result_type = field_type;
36,168✔
5191

5192
   const vtype_kind_t fkind = vtype_kind(field_type);
36,168✔
5193
   if (fkind == VCODE_TYPE_CARRAY)
36,168✔
5194
      result_type = bounds_type = vtype_elem(field_type);
4,558✔
5195
   else if (fkind == VCODE_TYPE_UARRAY) {
31,610✔
5196
      bounds_type = vtype_elem(field_type);
2,952✔
5197
      result_type = field_type;
2,952✔
5198
   }
5199

5200
   op->result = vcode_add_reg(vtype_pointer(result_type));
36,168✔
5201

5202
   reg_t *rr = vcode_reg_data(op->result);
36,168✔
5203
   rr->bounds = bounds_type;
36,168✔
5204

5205
   return op->result;
36,168✔
5206
}
5207

5208
vcode_reg_t emit_array_ref(vcode_reg_t array, vcode_reg_t offset)
35,750✔
5209
{
5210
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ARRAY_REF) {
1,711,351✔
5211
      if (other->args.items[0] == array && other->args.items[1] == offset)
104,908✔
5212
         return other->result;
1,231✔
5213
   }
5214

5215
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_REF);
34,519✔
5216
   vcode_add_arg(op, array);
34,519✔
5217
   vcode_add_arg(op, offset);
34,519✔
5218

5219
   vcode_type_t rtype = vcode_reg_type(array);
34,519✔
5220
   VCODE_ASSERT((vtype_kind(rtype) == VCODE_TYPE_POINTER
34,519✔
5221
                 && vtype_kind(vtype_pointed(rtype)) != VCODE_TYPE_UARRAY)
5222
                || vtype_kind(rtype) == VCODE_TYPE_SIGNAL,
5223
                "argument to array ref must be a pointer or signal");
5224
   VCODE_ASSERT(vcode_reg_kind(offset) == VCODE_TYPE_OFFSET,
34,519✔
5225
                "array ref offset argument must have offset type");
5226

5227
   op->result = vcode_add_reg(rtype);
34,519✔
5228

5229
   reg_t *rr = vcode_reg_data(op->result);
34,519✔
5230
   rr->bounds = vcode_reg_bounds(array);
34,519✔
5231

5232
   return op->result;
34,519✔
5233
}
5234

5235
void emit_copy(vcode_reg_t dest, vcode_reg_t src, vcode_reg_t count)
31,027✔
5236
{
5237
   int64_t cconst;
31,027✔
5238
   if (count != VCODE_INVALID_REG && vcode_reg_const(count, &cconst)
31,027✔
5239
       && cconst == 0)
20,664✔
5240
      return;
5,359✔
5241
   else if (dest == src)
30,284✔
5242
      return;
5243

5244
   op_t *op = vcode_add_op(VCODE_OP_COPY);
25,668✔
5245
   vcode_add_arg(op, dest);
25,668✔
5246
   vcode_add_arg(op, src);
25,668✔
5247
   if (count != VCODE_INVALID_REG)
25,668✔
5248
      vcode_add_arg(op, count);
24,064✔
5249

5250
   vcode_type_t dtype = vcode_reg_type(dest);
25,668✔
5251
   vcode_type_t stype = vcode_reg_type(src);
25,668✔
5252

5253
   vtype_kind_t dkind = vtype_kind(dtype);
25,668✔
5254
   vtype_kind_t skind = vtype_kind(stype);
25,668✔
5255

5256
   VCODE_ASSERT(dkind == VCODE_TYPE_POINTER || dkind == VCODE_TYPE_ACCESS,
25,668✔
5257
                "destination type is not a pointer or access");
5258
   VCODE_ASSERT(skind == VCODE_TYPE_POINTER || skind == VCODE_TYPE_ACCESS,
25,668✔
5259
                "source type is not a pointer or access");
5260
   VCODE_ASSERT(vtype_eq(dtype, stype),
25,668✔
5261
                "source and destination types do not match");
5262
   VCODE_ASSERT(count == VCODE_INVALID_REG
25,668✔
5263
                || vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
5264
                "count is not offset type");
5265

5266
   op->type = vtype_pointed(dtype);
25,668✔
5267
}
5268

5269
void emit_sched_event(vcode_reg_t nets, vcode_reg_t n_elems)
6,112✔
5270
{
5271
   VCODE_FOR_EACH_OP(other) {
104,349✔
5272
      if (other->kind == VCODE_OP_CLEAR_EVENT)
98,291✔
5273
         break;
5274
      else if (other->kind == VCODE_OP_SCHED_EVENT
98,243✔
5275
               && other->args.items[0] == nets
4,904✔
5276
               && other->args.items[1] == n_elems)
9✔
5277
         return;
5278
   }
5279

5280
   op_t *op = vcode_add_op(VCODE_OP_SCHED_EVENT);
6,106✔
5281
   vcode_add_arg(op, nets);
6,106✔
5282
   vcode_add_arg(op, n_elems);
6,106✔
5283

5284
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
6,106✔
5285
                "nets argument to sched event must be signal");
5286
}
5287

5288
void emit_clear_event(vcode_reg_t nets, vcode_reg_t n_elems)
562✔
5289
{
5290
   VCODE_FOR_EACH_OP(other) {
2,572✔
5291
      if (other->kind == VCODE_OP_SCHED_EVENT)
2,010✔
5292
         break;
5293
      else if (other->kind == VCODE_OP_CLEAR_EVENT
2,010✔
5294
               && other->args.items[0] == nets
39✔
UNCOV
5295
               && other->args.items[1] == n_elems)
×
5296
         return;
5297
   }
5298

5299
   op_t *op = vcode_add_op(VCODE_OP_CLEAR_EVENT);
562✔
5300
   vcode_add_arg(op, nets);
562✔
5301
   vcode_add_arg(op, n_elems);
562✔
5302

5303
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
562✔
5304
                "nets argument to clear event must be signal");
5305
}
5306

5307
void emit_sched_process(vcode_reg_t delay)
5,269✔
5308
{
5309
   op_t *op = vcode_add_op(VCODE_OP_SCHED_PROCESS);
5,269✔
5310
   vcode_add_arg(op, delay);
5,269✔
5311

5312
   VCODE_ASSERT(vcode_reg_kind(delay) == VCODE_TYPE_INT,
5,269✔
5313
                "delay must have integer type");
5314
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_PROCEDURE
5,269✔
5315
                || active_unit->kind == VCODE_UNIT_PROCESS,
5316
                "sched process only allowed in process or procedure");
5317
}
5,269✔
5318

5319
void emit_resume(ident_t func)
843✔
5320
{
5321
   op_t *op = vcode_add_op(VCODE_OP_RESUME);
843✔
5322
   op->func = func;
843✔
5323

5324
   block_t *b = &(active_unit->blocks.items[active_block]);
843✔
5325
   VCODE_ASSERT(b->ops.count == 1, "resume must be first op in a block");
843✔
5326
}
843✔
5327

5328
void emit_memset(vcode_reg_t ptr, vcode_reg_t value, vcode_reg_t len)
5,557✔
5329
{
5330
   int64_t lconst;
5,557✔
5331
   if (vcode_reg_const(len, &lconst) && lconst == 0)
5,557✔
5332
      return;
32✔
5333

5334
   op_t *op = vcode_add_op(VCODE_OP_MEMSET);
5,525✔
5335
   vcode_add_arg(op, ptr);
5,525✔
5336
   vcode_add_arg(op, value);
5,525✔
5337
   vcode_add_arg(op, len);
5,525✔
5338

5339
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
5,525✔
5340
                "target of memset must have pointer type");
5341
   VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(value)),
5,525✔
5342
                "value of memset must have scalar type");
5343
   VCODE_ASSERT(vtype_kind(vcode_reg_type(len)) == VCODE_TYPE_OFFSET,
5,525✔
5344
                "length of memset must have offset type");
5345
}
5346

5347
void emit_case(vcode_reg_t value, vcode_block_t def, const vcode_reg_t *cases,
641✔
5348
               const vcode_block_t *blocks, int ncases)
5349
{
5350
   int64_t cval1, cval2;
641✔
5351
   bool is_const = vcode_reg_const(value, &cval1);
641✔
5352

5353
   for (int i = 0; i < ncases; i++) {
3,663✔
5354
      bool can_fold = false;
3,025✔
5355
      if (cases[i] == value)
3,025✔
5356
         can_fold = true;
5357
      else if (is_const && vcode_reg_const(cases[i], &cval2))
3,025✔
5358
         can_fold = (cval1 == cval2);
3✔
5359

5360
      if (can_fold) {
3✔
5361
         emit_jump(blocks[i]);
3✔
5362
         return;
6✔
5363
      }
5364
   }
5365

5366
   if (is_const) {
638✔
UNCOV
5367
      emit_jump(def);
×
UNCOV
5368
      return;
×
5369
   }
5370

5371
   op_t *op = vcode_add_op(VCODE_OP_CASE);
638✔
5372
   vcode_add_arg(op, value);
638✔
5373
   vcode_add_target(op, def);
638✔
5374

5375
   for (int i = 0; i < ncases; i++) {
3,660✔
5376
      vcode_add_arg(op, cases[i]);
3,022✔
5377
      vcode_add_target(op, blocks[i]);
3,022✔
5378

5379
#ifdef DEBUG
5380
      for (int j = 0; j < i; j++)
15,545✔
5381
         VCODE_ASSERT(cases[i] != cases[j], "duplicate case choice");
12,523✔
5382
#endif
5383
   }
5384
}
5385

5386
void emit_file_open(vcode_reg_t file, vcode_reg_t name, vcode_reg_t length,
1,219✔
5387
                    vcode_reg_t kind, vcode_reg_t status)
5388
{
5389
   op_t *op = vcode_add_op(VCODE_OP_FILE_OPEN);
1,219✔
5390
   vcode_add_arg(op, file);
1,219✔
5391
   vcode_add_arg(op, name);
1,219✔
5392
   vcode_add_arg(op, length);
1,219✔
5393
   vcode_add_arg(op, kind);
1,219✔
5394
   if (status != VCODE_INVALID_REG)
1,219✔
5395
      vcode_add_arg(op, status);
25✔
5396

5397
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
1,219✔
5398
                "file open first argument must have file pointer type");
5399
}
1,219✔
5400

5401
void emit_file_write(vcode_reg_t file, vcode_reg_t value, vcode_reg_t length)
255✔
5402
{
5403
   op_t *op = vcode_add_op(VCODE_OP_FILE_WRITE);
255✔
5404
   vcode_add_arg(op, file);
255✔
5405
   vcode_add_arg(op, value);
255✔
5406
   if (length != VCODE_INVALID_REG)
255✔
5407
      vcode_add_arg(op, length);
198✔
5408

5409
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
255✔
5410
                "file write first argument must have file pointer type");
5411
}
255✔
5412

5413
void emit_file_read(vcode_reg_t file, vcode_reg_t ptr,
90✔
5414
                    vcode_reg_t inlen, vcode_reg_t outlen)
5415
{
5416
   op_t *op = vcode_add_op(VCODE_OP_FILE_READ);
90✔
5417
   vcode_add_arg(op, file);
90✔
5418
   vcode_add_arg(op, ptr);
90✔
5419
   if (inlen != VCODE_INVALID_REG) {
90✔
5420
      vcode_add_arg(op, inlen);
42✔
5421
      if (outlen != VCODE_INVALID_REG)
42✔
5422
         vcode_add_arg(op, outlen);
33✔
5423
   }
5424

5425
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
90✔
5426
                "file read first argument must have file pointer type");
5427
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
90✔
5428
                "file read pointer argument must have pointer type");
5429
   VCODE_ASSERT(outlen == VCODE_INVALID_REG
90✔
5430
                || vtype_kind(vcode_reg_type(outlen)) == VCODE_TYPE_POINTER,
5431
                "file read outlen argument must have pointer type");
5432
}
90✔
5433

5434
vcode_reg_t emit_null(vcode_type_t type)
12,659✔
5435
{
5436
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_NULL) {
255,211✔
5437
      if (vtype_eq(vcode_reg_type(other->result), type))
7,558✔
5438
         return other->result;
4,010✔
5439
   }
5440

5441
   op_t *op = vcode_add_op(VCODE_OP_NULL);
8,649✔
5442
   op->result = vcode_add_reg(type);
8,649✔
5443

5444
   vtype_kind_t kind = vtype_kind(type);
8,649✔
5445
   VCODE_ASSERT(kind == VCODE_TYPE_POINTER || kind == VCODE_TYPE_FILE
8,649✔
5446
                || kind == VCODE_TYPE_ACCESS || kind == VCODE_TYPE_CONTEXT,
5447
                "null type must be file, access, context, or pointer");
5448

5449
   return op->result;
5450
}
5451

5452
vcode_reg_t emit_new(vcode_type_t type, vcode_reg_t length)
636✔
5453
{
5454
   op_t *op = vcode_add_op(VCODE_OP_NEW);
636✔
5455
   if (length != VCODE_INVALID_REG)
636✔
5456
      vcode_add_arg(op, length);
545✔
5457

5458
   op->result = vcode_add_reg(vtype_access(type));
636✔
5459

5460
   vtype_kind_t kind = vtype_kind(type);
636✔
5461
   VCODE_ASSERT(kind == VCODE_TYPE_INT || kind == VCODE_TYPE_RECORD
636✔
5462
                || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_ACCESS
5463
                || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_CONTEXT,
5464
                "new type must be int, real, record, access, or uarray");
5465
   VCODE_ASSERT(length == VCODE_INVALID_REG
636✔
5466
                || vtype_kind(vcode_reg_type(length)) == VCODE_TYPE_OFFSET,
5467
                "new length must have offset type");
5468

5469
   return op->result;
636✔
5470
}
5471

5472
void emit_null_check(vcode_reg_t ptr, vcode_reg_t locus)
2,896✔
5473
{
5474
   VCODE_FOR_EACH_OP(other) {
120,047✔
5475
      if (other->kind == VCODE_OP_NULL_CHECK && other->args.items[0] == ptr)
117,895✔
5476
         return;
5477
      else if (other->kind == VCODE_OP_NEW && other->result == ptr)
117,474✔
5478
         return;
5479
   }
5480

5481
   op_t *op = vcode_add_op(VCODE_OP_NULL_CHECK);
2,152✔
5482
   vcode_add_arg(op, ptr);
2,152✔
5483
   vcode_add_arg(op, locus);
2,152✔
5484

5485
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_ACCESS,
2,152✔
5486
                "null check argument must be an access");
5487
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,152✔
5488
                "locus argument to null check must be a debug locus");
5489
}
5490

5491
void emit_deallocate(vcode_reg_t ptr)
335✔
5492
{
5493
   op_t *op = vcode_add_op(VCODE_OP_DEALLOCATE);
335✔
5494
   vcode_add_arg(op, ptr);
335✔
5495

5496
   vcode_type_t ptype = vcode_reg_type(ptr);
335✔
5497
   VCODE_ASSERT(vtype_kind(ptype) == VCODE_TYPE_POINTER
335✔
5498
                && vtype_kind(vtype_pointed(ptype)) == VCODE_TYPE_ACCESS,
5499
                "deallocate argument must be pointer to access");
5500
}
335✔
5501

5502
vcode_reg_t emit_all(vcode_reg_t reg)
3,532✔
5503
{
5504
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ALL) {
168,009✔
5505
      if (other->args.items[0] == reg)
10,246✔
5506
         return other->result;
744✔
5507
   }
5508

5509
   op_t *op = vcode_add_op(VCODE_OP_ALL);
2,788✔
5510
   vcode_add_arg(op, reg);
2,788✔
5511

5512
   vcode_type_t vtype = vcode_reg_type(reg);
2,788✔
5513

5514
   VCODE_ASSERT(vtype_kind(vtype) == VCODE_TYPE_ACCESS,
2,788✔
5515
                "all argument must be an access");
5516

5517
   vcode_type_t pointed = vtype_pointed(vtype);
2,788✔
5518
   op->result = vcode_add_reg(vtype_pointer(pointed));
2,788✔
5519

5520
   reg_t *rr = vcode_reg_data(op->result);
2,788✔
5521
   rr->bounds = pointed;
2,788✔
5522

5523
   VCODE_ASSERT(vtype_kind(pointed) != VCODE_TYPE_OPAQUE,
2,788✔
5524
                "cannot dereference opaque type");
5525

5526
   return op->result;
5527
}
5528

5529
static vcode_reg_t emit_signal_data_op(vcode_op_t kind, vcode_reg_t sig)
15,298✔
5530
{
5531
   block_t *b = &(active_unit->blocks.items[active_block]);
15,298✔
5532
   for (int i = b->ops.count - 1; i >= 0; i--) {
363,133✔
5533
      const op_t *other = &(b->ops.items[i]);
348,390✔
5534
      if (other->kind == kind && other->args.items[0] == sig)
348,390✔
5535
         return other->result;
555✔
5536
   }
5537

5538
   op_t *op = vcode_add_op(kind);
14,743✔
5539
   vcode_add_arg(op, sig);
14,743✔
5540

5541
   vcode_type_t stype = vcode_reg_type(sig);
14,743✔
5542
   op->type = stype;
14,743✔
5543

5544
   VCODE_ASSERT(vtype_kind(stype) == VCODE_TYPE_SIGNAL,
14,743✔
5545
                "argument r%d to resolved is not a signal", sig);
5546

5547
   vcode_type_t rtype = vtype_base(stype);
14,743✔
5548

5549
   const vtype_kind_t rkind = vtype_kind(rtype);
14,743✔
5550
   if (rkind == VCODE_TYPE_CARRAY || rkind == VCODE_TYPE_UARRAY)
14,743✔
UNCOV
5551
      rtype = vtype_elem(rtype);
×
5552

5553
   VCODE_ASSERT(vtype_is_scalar(rtype),
14,743✔
5554
                "resolved signal base type must be scalar");
5555

5556
   op->result = vcode_add_reg(vtype_pointer(rtype));
14,743✔
5557

5558
   reg_t *rr = vcode_reg_data(op->result);
14,743✔
5559
   rr->bounds = rtype;
14,743✔
5560

5561
   return op->result;
14,743✔
5562
}
5563

5564
vcode_reg_t emit_resolved(vcode_reg_t sig, vcode_reg_t count)
15,109✔
5565
{
5566
   return emit_signal_data_op(VCODE_OP_RESOLVED, sig);
15,109✔
5567
}
5568

5569
vcode_reg_t emit_last_value(vcode_reg_t sig, vcode_reg_t count)
189✔
5570
{
5571
   return emit_signal_data_op(VCODE_OP_LAST_VALUE, sig);
189✔
5572
}
5573

5574
vcode_reg_t emit_last_event(vcode_reg_t signal, vcode_reg_t len)
42✔
5575
{
5576
   op_t *op = vcode_add_op(VCODE_OP_LAST_EVENT);
42✔
5577
   vcode_add_arg(op, signal);
42✔
5578
   if (len != VCODE_INVALID_REG)
42✔
5579
      vcode_add_arg(op, len);
9✔
5580

5581
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
42✔
5582
                "signal argument to last event must have signal type");
5583
   VCODE_ASSERT(len == VCODE_INVALID_REG
42✔
5584
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5585
                "length argument to last event must have offset type");
5586

5587
   return (op->result = vcode_add_reg(vtype_time()));
42✔
5588
}
5589

5590
vcode_reg_t emit_last_active(vcode_reg_t signal, vcode_reg_t len)
45✔
5591
{
5592
   op_t *op = vcode_add_op(VCODE_OP_LAST_ACTIVE);
45✔
5593
   vcode_add_arg(op, signal);
45✔
5594
   if (len != VCODE_INVALID_REG)
45✔
5595
      vcode_add_arg(op, len);
6✔
5596

5597
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
45✔
5598
                "signal argument to last active must have signal type");
5599
   VCODE_ASSERT(len == VCODE_INVALID_REG
45✔
5600
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5601
                "length argument to last active must have offset type");
5602

5603
   return (op->result = vcode_add_reg(vtype_time()));
45✔
5604
}
5605

5606
void emit_alias_signal(vcode_reg_t signal, vcode_reg_t locus)
4,284✔
5607
{
5608
   op_t *op = vcode_add_op(VCODE_OP_ALIAS_SIGNAL);
4,284✔
5609
   vcode_add_arg(op, signal);
4,284✔
5610
   vcode_add_arg(op, locus);
4,284✔
5611

5612
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
4,284✔
5613
                "signal argument must have signal type");
5614
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
4,284✔
5615
                "locus argument must have debug locus type");
5616
}
4,284✔
5617

5618
vcode_reg_t emit_driving_flag(vcode_reg_t signal, vcode_reg_t len)
36✔
5619
{
5620
   op_t *op = vcode_add_op(VCODE_OP_DRIVING);
36✔
5621
   vcode_add_arg(op, signal);
36✔
5622
   vcode_add_arg(op, len);
36✔
5623

5624
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
36✔
5625
                "signal argument to last active must have signal type");
5626
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
36✔
5627
                "length argument to last active must have offset type");
5628

5629
   return (op->result = vcode_add_reg(vtype_bool()));
36✔
5630
}
5631

5632
vcode_reg_t emit_driving_value(vcode_reg_t signal, vcode_reg_t len)
120✔
5633
{
5634
   op_t *op = vcode_add_op(VCODE_OP_DRIVING_VALUE);
120✔
5635
   vcode_add_arg(op, signal);
120✔
5636
   if (len != VCODE_INVALID_REG)
120✔
5637
      vcode_add_arg(op, len);
36✔
5638

5639
   vcode_type_t signal_type = vcode_reg_type(signal);
120✔
5640

5641
   VCODE_ASSERT(vtype_kind(signal_type) == VCODE_TYPE_SIGNAL,
120✔
5642
                "signal argument to last active must have signal type");
5643
   VCODE_ASSERT(len == VCODE_INVALID_REG
120✔
5644
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5645
                "length argument to last active must have offset type");
5646

5647
   vcode_type_t base_type = vtype_base(signal_type);
120✔
5648
   op->result = vcode_add_reg(vtype_pointer(base_type));
120✔
5649

5650
   reg_t *rr = vcode_reg_data(op->result);
120✔
5651
   rr->bounds = base_type;
120✔
5652

5653
   return op->result;
120✔
5654
}
5655

5656
void emit_length_check(vcode_reg_t llen, vcode_reg_t rlen, vcode_reg_t locus,
32,725✔
5657
                       vcode_reg_t dim)
5658
{
5659
   if (rlen == llen)
32,725✔
5660
      return;
5661

5662
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LENGTH_CHECK) {
197,648✔
5663
      if (other->args.items[0] == llen && other->args.items[1] == rlen)
2,634✔
5664
         return;
5665
   }
5666

5667
   op_t *op = vcode_add_op(VCODE_OP_LENGTH_CHECK);
7,238✔
5668
   vcode_add_arg(op, llen);
7,238✔
5669
   vcode_add_arg(op, rlen);
7,238✔
5670
   vcode_add_arg(op, locus);
7,238✔
5671
   if (dim != VCODE_INVALID_REG)
7,238✔
5672
      vcode_add_arg(op, dim);
27✔
5673

5674
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
7,238✔
5675
                "locus argument to length check must be a debug locus");
5676
}
5677

5678
void emit_exponent_check(vcode_reg_t exp, vcode_reg_t locus)
789✔
5679
{
5680
   int64_t cval;
789✔
5681
   if (vcode_reg_const(exp, &cval) && cval >= 0)
789✔
5682
      return;
47✔
5683

5684
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_EXPONENT_CHECK) {
6,109✔
5685
      if (other->args.items[0] == exp)
12✔
5686
         return;
5687
   }
5688

5689
   op_t *op = vcode_add_op(VCODE_OP_EXPONENT_CHECK);
742✔
5690
   vcode_add_arg(op, exp);
742✔
5691
   vcode_add_arg(op, locus);
742✔
5692

5693
   VCODE_ASSERT(vcode_reg_kind(exp) == VCODE_TYPE_INT,
742✔
5694
                "exp argument to exponent check must be a integer");
5695
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
742✔
5696
                "locus argument to exponent check must be a debug locus");
5697
}
5698

5699
void emit_zero_check(vcode_reg_t denom, vcode_reg_t locus)
2,428✔
5700
{
5701
   int64_t cval;
2,428✔
5702
   if (vcode_reg_const(denom, &cval) && cval != 0)
2,428✔
5703
      return;
2,337✔
5704

5705
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ZERO_CHECK) {
2,305✔
5706
      if (other->args.items[0] == denom)
48✔
5707
         return;
5708
   }
5709

5710
   op_t *op = vcode_add_op(VCODE_OP_ZERO_CHECK);
91✔
5711
   vcode_add_arg(op, denom);
91✔
5712
   vcode_add_arg(op, locus);
91✔
5713

5714
   VCODE_ASSERT(vcode_reg_kind(denom) == VCODE_TYPE_INT,
91✔
5715
                "denom argument to zero check must be a integer");
5716
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
91✔
5717
                "locus argument to zero check must be a debug locus");
5718
}
5719

5720
static bool vcode_can_elide_bounds(vcode_reg_t reg, vcode_reg_t left,
86,874✔
5721
                                   vcode_reg_t right, vcode_reg_t dir)
5722
{
5723
   int64_t dconst;
86,874✔
5724
   if (vcode_reg_const(dir, &dconst)) {
86,874✔
5725
      int64_t lconst, rconst;
76,377✔
5726
      if (vcode_reg_const(left, &lconst) && vcode_reg_const(right, &rconst)) {
76,377✔
5727
         const bool is_null = (dconst == RANGE_TO && lconst > rconst)
51,408✔
5728
            || (dconst == RANGE_DOWNTO && rconst > lconst);
106,546✔
5729

5730
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
55,139✔
5731

5732
         const bool ok_static =
110,278✔
5733
            (dconst == RANGE_TO
5734
             && bounds->low >= lconst && bounds->high <= rconst)
51,408✔
5735
            || (dconst == RANGE_DOWNTO
9,838✔
5736
                && bounds->low >= rconst && bounds->high <= lconst)
3,731✔
5737
            || (!is_null && (reg == left || reg == right));
61,741✔
5738

5739
         return ok_static;
73,592✔
5740
      }
5741
      else if (vcode_reg_kind(reg) == VCODE_TYPE_REAL) {
21,238✔
5742
         vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
19,154✔
5743
         vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
19,154✔
5744

5745
         assert(lbounds->kind == VCODE_TYPE_REAL);
19,154✔
5746
         assert(rbounds->kind == VCODE_TYPE_REAL);
19,154✔
5747

5748
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
19,154✔
5749
         assert(bounds->kind == VCODE_TYPE_REAL);
19,154✔
5750

5751
         if (isfinite(bounds->rlow) && lbounds->rlow == -DBL_MAX
19,154✔
5752
             && isfinite(bounds->rhigh) && rbounds->rhigh == DBL_MAX) {
18,453✔
5753
            // Covers the complete double range so can never overflow
5754
            return true;
5755
         }
5756
      }
5757
   }
5758

5759
   return false;
5760
}
5761

5762
static void emit_bounds_check(vcode_op_t kind, vcode_reg_t reg,
87,775✔
5763
                              vcode_reg_t left, vcode_reg_t right,
5764
                              vcode_reg_t dir, vcode_reg_t locus,
5765
                              vcode_reg_t hint)
5766
{
5767
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
3,666,299✔
5768
      if (other->args.items[0] == reg && other->args.items[1] == left
18,563✔
5769
          && other->args.items[2] == right && other->args.items[3] == dir)
1,067✔
5770
         return;
5771
   }
5772

5773
   if (vcode_can_elide_bounds(reg, left, right, dir)) {
86,874✔
5774
      emit_comment("Elided bounds check for r%d", reg);
66,990✔
5775
      return;
66,990✔
5776
   }
5777

5778
   op_t *op = vcode_add_op(kind);
19,884✔
5779
   vcode_add_arg(op, reg);
19,884✔
5780
   vcode_add_arg(op, left);
19,884✔
5781
   vcode_add_arg(op, right);
19,884✔
5782
   vcode_add_arg(op, dir);
19,884✔
5783
   vcode_add_arg(op, locus);
19,884✔
5784
   vcode_add_arg(op, hint);
19,884✔
5785

5786
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
19,884✔
5787
                "locus argument to bounds check must be a debug locus");
5788
   VCODE_ASSERT(vcode_reg_kind(hint) == VCODE_TYPE_DEBUG_LOCUS,
19,884✔
5789
                "hint argument to bounds check must be a debug locus");
5790
}
5791

5792
void emit_range_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
22,785✔
5793
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5794
{
5795
   emit_bounds_check(VCODE_OP_RANGE_CHECK, reg, left, right, dir, locus, hint);
22,785✔
5796
}
22,785✔
5797

5798
void emit_index_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
64,990✔
5799
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5800
{
5801
   emit_bounds_check(VCODE_OP_INDEX_CHECK, reg, left, right, dir, locus, hint);
64,990✔
5802
}
64,990✔
5803

5804
void emit_dir_check(vcode_reg_t reg, vcode_reg_t dir, vcode_reg_t locus)
3,175✔
5805
{
5806
   if (reg == dir)
3,175✔
5807
      return;
5808

5809
   op_t *op = vcode_add_op(VCODE_OP_DIR_CHECK);
2,365✔
5810
   vcode_add_arg(op, reg);
2,365✔
5811
   vcode_add_arg(op, dir);
2,365✔
5812
   vcode_add_arg(op, locus);
2,365✔
5813

5814
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,365✔
5815
                "locus argument to dir check must be a debug locus");
5816
}
5817

5818
void emit_package_scope(vcode_reg_t locus)
45✔
5819
{
5820
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_SCOPE);
45✔
5821
   vcode_add_arg(op, locus);
45✔
5822

5823
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
45✔
5824
                "locus argument to package scope must be a debug locus");
5825
}
45✔
5826

5827
void emit_array_scope(vcode_reg_t locus, vcode_type_t type)
645✔
5828
{
5829
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_SCOPE);
645✔
5830
   vcode_add_arg(op, locus);
645✔
5831
   op->type = type;
645✔
5832

5833
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
645✔
5834
                "locus argument to array scope must be a debug locus");
5835
}
645✔
5836

5837
void emit_record_scope(vcode_reg_t locus, vcode_type_t type)
1,681✔
5838
{
5839
   op_t *op = vcode_add_op(VCODE_OP_RECORD_SCOPE);
1,681✔
5840
   vcode_add_arg(op, locus);
1,681✔
5841
   op->type = type;
1,681✔
5842

5843
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,681✔
5844
                "locus argument to record scope must be a debug locus");
5845
}
1,681✔
5846

5847
void emit_pop_scope(void)
2,371✔
5848
{
5849
   vcode_add_op(VCODE_OP_POP_SCOPE);
2,371✔
5850
}
2,371✔
5851

5852
vcode_reg_t emit_debug_locus(object_t *obj)
179,517✔
5853
{
5854
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DEBUG_LOCUS) {
6,686,558✔
5855
      if (other->object == obj)
821,742✔
5856
         return other->result;
19,704✔
5857
   }
5858

5859
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_LOCUS);
159,813✔
5860
   op->object = obj;
159,813✔
5861

5862
   return (op->result = vcode_add_reg(vtype_debug_locus()));
159,813✔
5863
}
5864

5865
void emit_debug_out(vcode_reg_t reg)
×
5866
{
UNCOV
5867
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_OUT);
×
UNCOV
5868
   vcode_add_arg(op, reg);
×
UNCOV
5869
}
×
5870

5871
void emit_cover_stmt(uint32_t tag)
1,300✔
5872
{
5873
   op_t *op = vcode_add_op(VCODE_OP_COVER_STMT);
1,300✔
5874
   op->tag = tag;
1,300✔
5875
}
1,300✔
5876

5877
void emit_cover_branch(uint32_t tag)
499✔
5878
{
5879
   op_t *op = vcode_add_op(VCODE_OP_COVER_BRANCH);
499✔
5880
   op->tag = tag;
499✔
5881
}
499✔
5882

5883
void emit_cover_toggle(vcode_reg_t signal, uint32_t tag)
312✔
5884
{
5885
   op_t *op = vcode_add_op(VCODE_OP_COVER_TOGGLE);
312✔
5886
   vcode_add_arg(op, signal);
312✔
5887
   op->tag = tag;
312✔
5888
}
312✔
5889

5890
void emit_cover_state(vcode_reg_t signal, vcode_reg_t low, uint32_t tag)
12✔
5891
{
5892
   op_t *op = vcode_add_op(VCODE_OP_COVER_STATE);
12✔
5893
   vcode_add_arg(op, signal);
12✔
5894
   vcode_add_arg(op, low);
12✔
5895
   op->tag = tag;
12✔
5896
}
12✔
5897

5898
void emit_cover_expr(uint32_t tag)
887✔
5899
{
5900
   op_t *op = vcode_add_op(VCODE_OP_COVER_EXPR);
887✔
5901
   op->tag = tag;
887✔
5902
}
887✔
5903

5904
void emit_unreachable(vcode_reg_t locus)
1,347✔
5905
{
5906
   op_t *op = vcode_add_op(VCODE_OP_UNREACHABLE);
1,347✔
5907
   if (locus != VCODE_INVALID_REG)
1,347✔
5908
      vcode_add_arg(op, locus);
115✔
5909
}
1,347✔
5910

5911
vcode_reg_t emit_undefined(vcode_type_t type, vcode_type_t bounds)
63✔
5912
{
5913
   active_unit->flags |= UNIT_UNDEFINED;
63✔
5914

5915
   op_t *op = vcode_add_op(VCODE_OP_UNDEFINED);
63✔
5916
   op->result = vcode_add_reg(type);
63✔
5917
   vcode_reg_data(op->result)->bounds = bounds;
63✔
5918

5919
   return op->result;
63✔
5920
}
5921

5922
void emit_debug_info(const loc_t *loc)
2,500,574✔
5923
{
5924
   if (!loc_invalid_p(loc))
2,500,574✔
5925
      vcode_block_data()->last_loc = *loc;
2,477,206✔
5926
}
2,500,574✔
5927

5928
vcode_reg_t emit_link_var(vcode_reg_t context, ident_t name, vcode_type_t type)
8,128✔
5929
{
5930
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_VAR) {
293,581✔
5931
      if (other->args.items[0] == context && other->ident == name)
11,650✔
5932
         return other->result;
3,790✔
5933
   }
5934

5935
   op_t *op = vcode_add_op(VCODE_OP_LINK_VAR);
4,338✔
5936
   vcode_add_arg(op, context);
4,338✔
5937
   op->ident = name;
4,338✔
5938

5939
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
4,338✔
5940
                "first argument to link var must be context");
5941

5942
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
4,338✔
5943
      op->result = vcode_add_reg(vtype_pointer(vtype_elem(type)));
79✔
5944
      vcode_reg_data(op->result)->bounds = vtype_bounds(type);
79✔
5945
   }
5946
   else {
5947
      op->result = vcode_add_reg(vtype_pointer(type));
4,259✔
5948
      vcode_reg_data(op->result)->bounds = type;
4,259✔
5949
   }
5950

5951
   return op->result;
4,338✔
5952
}
5953

5954
vcode_reg_t emit_link_package(ident_t name)
12,829✔
5955
{
5956
   VCODE_FOR_EACH_OP(other) {
462,938✔
5957
      if (other->kind == VCODE_OP_LINK_PACKAGE && other->ident == name)
456,333✔
5958
         return other->result;
4,524✔
5959
      else if (other->kind == VCODE_OP_PACKAGE_INIT && other->func == name)
451,809✔
5960
         return other->result;
1,700✔
5961
   }
5962

5963
   op_t *op = vcode_add_op(VCODE_OP_LINK_PACKAGE);
6,605✔
5964
   op->ident = name;
6,605✔
5965

5966
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
6,605✔
5967

5968
   return (op->result = vcode_add_reg(vtype_context(name)));
6,605✔
5969
}
5970

5971
void emit_enter_state(vcode_reg_t state, vcode_reg_t strong)
849✔
5972
{
5973
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ENTER_STATE) {
2,046✔
UNCOV
5974
      if (other->args.items[0] == state)
×
5975
         return;
5976
   }
5977

5978
   op_t *op = vcode_add_op(VCODE_OP_ENTER_STATE);
849✔
5979
   vcode_add_arg(op, state);
849✔
5980
   if (strong != VCODE_INVALID_REG)
849✔
5981
      vcode_add_arg(op, strong);
36✔
5982

5983
   VCODE_ASSERT(vcode_reg_kind(state) == VCODE_TYPE_INT,
849✔
5984
                "state must have integer type");
5985
   VCODE_ASSERT(strong == VCODE_INVALID_REG
849✔
5986
                || vtype_eq(vcode_reg_type(strong), vtype_bool()),
5987
                "strong argument not is not boolean");
5988
}
5989

5990
vcode_reg_t emit_reflect_value(vcode_reg_t value, vcode_reg_t context,
48✔
5991
                               vcode_reg_t locus, vcode_reg_t bounds)
5992
{
5993
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_VALUE);
48✔
5994
   vcode_add_arg(op, value);
48✔
5995
   vcode_add_arg(op, context);
48✔
5996
   vcode_add_arg(op, locus);
48✔
5997
   if (bounds != VCODE_INVALID_REG)
48✔
5998
      vcode_add_arg(op, bounds);
6✔
5999

6000
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
48✔
6001
                "invalid reflect value context argument");
6002
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
48✔
6003
                "locus argument to reflect value must be a debug locus");
6004

6005
   return (op->result = vcode_add_reg(vtype_access(vtype_opaque())));
48✔
6006
}
6007

6008
vcode_reg_t emit_reflect_subtype(vcode_reg_t context, vcode_reg_t locus,
42✔
6009
                                 vcode_reg_t bounds)
6010
{
6011
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_SUBTYPE);
42✔
6012
   vcode_add_arg(op, context);
42✔
6013
   vcode_add_arg(op, locus);
42✔
6014
   if (bounds != VCODE_INVALID_REG)
42✔
UNCOV
6015
      vcode_add_arg(op, bounds);
×
6016

6017
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
42✔
6018
                "invalid reflect value context argument");
6019
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
42✔
6020
                "locus argument to reflect value must be a debug locus");
6021

6022
   return (op->result = vcode_add_reg(vtype_access(vtype_opaque())));
42✔
6023
}
6024

6025
vcode_reg_t emit_function_trigger(ident_t func, const vcode_reg_t *args,
232✔
6026
                                  int nargs)
6027
{
6028
   op_t *op = vcode_add_op(VCODE_OP_FUNCTION_TRIGGER);
232✔
6029
   op->func = func;
232✔
6030

6031
   for (int i = 0; i < nargs; i++)
579✔
6032
      vcode_add_arg(op, args[i]);
347✔
6033

6034
   return (op->result = vcode_add_reg(vtype_trigger()));
232✔
6035
}
6036

6037
vcode_reg_t emit_or_trigger(vcode_reg_t left, vcode_reg_t right)
34✔
6038
{
6039
   op_t *op = vcode_add_op(VCODE_OP_OR_TRIGGER);
34✔
6040
   vcode_add_arg(op, left);
34✔
6041
   vcode_add_arg(op, right);
34✔
6042

6043
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_TRIGGER,
34✔
6044
                "or trigger left argument must be trigger");
6045
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_TRIGGER,
34✔
6046
                "or trigger right argument must be trigger");
6047

6048
   return (op->result = vcode_add_reg(vtype_trigger()));
34✔
6049
}
6050

6051
vcode_reg_t emit_cmp_trigger(vcode_reg_t left, vcode_reg_t right)
66✔
6052
{
6053
   op_t *op = vcode_add_op(VCODE_OP_CMP_TRIGGER);
66✔
6054
   vcode_add_arg(op, left);
66✔
6055
   vcode_add_arg(op, right);
66✔
6056

6057
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_SIGNAL,
66✔
6058
                "cmp trigger left argument must be signal");
6059
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_INT,
66✔
6060
                "cmp trigger right argument must be integer");
6061

6062
   return (op->result = vcode_add_reg(vtype_trigger()));
66✔
6063
}
6064

6065
void emit_add_trigger(vcode_reg_t trigger)
398✔
6066
{
6067
   op_t *op = vcode_add_op(VCODE_OP_ADD_TRIGGER);
398✔
6068
   vcode_add_arg(op, trigger);
398✔
6069

6070
   VCODE_ASSERT(vcode_reg_kind(trigger) == VCODE_TYPE_TRIGGER,
398✔
6071
                "add trigger argument must be trigger");
6072
}
398✔
6073

6074
vcode_reg_t emit_port_conversion(vcode_reg_t driving, vcode_reg_t effective)
204✔
6075
{
6076
   op_t *op = vcode_add_op(VCODE_OP_PORT_CONVERSION);
204✔
6077
   vcode_add_arg(op, driving);
204✔
6078
   if (effective != VCODE_INVALID_REG && effective != driving)
204✔
6079
      vcode_add_arg(op, effective);
18✔
6080

6081
   VCODE_ASSERT(vcode_reg_kind(driving) == VCODE_TYPE_CLOSURE,
204✔
6082
                "port conversion argument must be a closure");
6083
   VCODE_ASSERT(effective == VCODE_INVALID_REG
204✔
6084
                || vcode_reg_kind(effective) == VCODE_TYPE_CLOSURE,
6085
                "port conversion argument must be a closure");
6086

6087
   return (op->result = vcode_add_reg(vtype_conversion()));
204✔
6088
}
6089

6090
vcode_reg_t emit_bind_external(vcode_reg_t locus, ident_t scope,
198✔
6091
                               vcode_type_t type, vcode_type_t bounds,
6092
                               const vcode_reg_t *args, int nargs)
6093
{
6094
   op_t *op = vcode_add_op(VCODE_OP_BIND_EXTERNAL);
198✔
6095
   op->type  = type;
198✔
6096
   op->ident = scope;
198✔
6097
   vcode_add_arg(op, locus);
198✔
6098
   for (int i = 0; i < nargs; i++)
246✔
6099
      vcode_add_arg(op, args[i]);
48✔
6100

6101
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
198✔
6102
                "bind external argument must be locus");
6103

6104
   op->result = vcode_add_reg(vtype_pointer(type));
198✔
6105
   vcode_reg_data(op->result)->bounds = bounds;
198✔
6106
   return op->result;
198✔
6107
}
6108

6109
void emit_put_conversion(vcode_reg_t cf, vcode_reg_t target, vcode_reg_t count,
342✔
6110
                         vcode_reg_t values)
6111
{
6112
   op_t *op = vcode_add_op(VCODE_OP_PUT_CONVERSION);
342✔
6113
   vcode_add_arg(op, cf);
342✔
6114
   vcode_add_arg(op, target);
342✔
6115
   vcode_add_arg(op, count);
342✔
6116
   vcode_add_arg(op, values);
342✔
6117

6118
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
342✔
6119
                "put conversion target is not signal");
6120
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
342✔
6121
                "put conversion net count is not offset type");
6122
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
342✔
6123
                "signal cannot be values argument for put conversion");
6124
   VCODE_ASSERT(vcode_reg_kind(cf) == VCODE_TYPE_CONVERSION,
342✔
6125
                "cf argument to put conversion must be conversion function");
6126
}
342✔
6127

6128
void emit_convert_in(vcode_reg_t conv, vcode_reg_t nets, vcode_reg_t count)
282✔
6129
{
6130
   op_t *op = vcode_add_op(VCODE_OP_CONVERT_IN);
282✔
6131
   vcode_add_arg(op, conv);
282✔
6132
   vcode_add_arg(op, nets);
282✔
6133
   vcode_add_arg(op, count);
282✔
6134

6135
   VCODE_ASSERT(vcode_reg_kind(conv) == VCODE_TYPE_CONVERSION,
282✔
6136
                "conv argument to convert must be a port conversion");
6137
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
282✔
6138
                "nets argument to convert must be a signal");
6139
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
282✔
6140
                "count argument to convert must be offset");
6141
}
282✔
6142

6143
void emit_convert_out(vcode_reg_t conv, vcode_reg_t nets, vcode_reg_t count)
324✔
6144
{
6145
   op_t *op = vcode_add_op(VCODE_OP_CONVERT_OUT);
324✔
6146
   vcode_add_arg(op, conv);
324✔
6147
   vcode_add_arg(op, nets);
324✔
6148
   vcode_add_arg(op, count);
324✔
6149

6150
   VCODE_ASSERT(vcode_reg_kind(conv) == VCODE_TYPE_CONVERSION,
324✔
6151
                "conv argument to convert must be a port conversion");
6152
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
324✔
6153
                "nets argument to convert must be a signal");
6154
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
324✔
6155
                "count argument to convert must be offset");
6156
}
324✔
6157

6158
void emit_bind_foreign(vcode_reg_t spec, vcode_reg_t length, vcode_reg_t locus)
1,001✔
6159
{
6160
   op_t *op = vcode_add_op(VCODE_OP_BIND_FOREIGN);
1,001✔
6161
   vcode_add_arg(op, spec);
1,001✔
6162
   vcode_add_arg(op, length);
1,001✔
6163
   if (locus != VCODE_INVALID_REG)
1,001✔
6164
      vcode_add_arg(op, locus);
827✔
6165

6166
   VCODE_ASSERT(vcode_reg_kind(spec) == VCODE_TYPE_POINTER,
1,001✔
6167
                "spec argument to bind foreign must be a pointer");
6168
   VCODE_ASSERT(vcode_reg_kind(length) == VCODE_TYPE_OFFSET,
1,001✔
6169
                "length argument to bind foreign must be offset");
6170
   VCODE_ASSERT(locus == VCODE_INVALID_REG
1,001✔
6171
                || vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
6172
                "locus argument to bind foreign value must be a debug locus");
6173
}
1,001✔
6174

6175
vcode_reg_t emit_instance_name(vcode_reg_t kind)
767✔
6176
{
6177
   op_t *op = vcode_add_op(VCODE_OP_INSTANCE_NAME);
767✔
6178
   vcode_add_arg(op, kind);
767✔
6179

6180
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
767✔
6181
                "kind argument to instance name must be offset");
6182

6183
   vcode_type_t vchar = vtype_char();
767✔
6184
   return (op->result = vcode_add_reg(vtype_uarray(1, vchar, vchar)));
767✔
6185
}
6186

6187
void vcode_walk_dependencies(vcode_unit_t vu, vcode_dep_fn_t fn, void *ctx)
16,094✔
6188
{
6189
   vcode_state_t state;
16,094✔
6190
   vcode_state_save(&state);
16,094✔
6191

6192
   vcode_select_unit(vu);
16,094✔
6193

6194
   const int nblocks = vcode_count_blocks();
16,094✔
6195
   for (int i = 0; i < nblocks; i++) {
59,748✔
6196
      vcode_select_block(i);
43,654✔
6197

6198
      const int nops = vcode_count_ops();
43,654✔
6199
      for (int op = 0; op < nops; op++) {
722,413✔
6200
         switch (vcode_get_op(op)) {
678,759✔
6201
         case VCODE_OP_LINK_PACKAGE:
2,172✔
6202
            (*fn)(vcode_get_ident(op), ctx);
2,172✔
6203
            break;
2,172✔
6204
         case VCODE_OP_FCALL:
28,771✔
6205
         case VCODE_OP_PCALL:
6206
         case VCODE_OP_CLOSURE:
6207
         case VCODE_OP_PROTECTED_INIT:
6208
         case VCODE_OP_PACKAGE_INIT:
6209
         case VCODE_OP_FUNCTION_TRIGGER:
6210
            (*fn)(vcode_get_func(op), ctx);
28,771✔
6211
            break;
28,771✔
6212
         default:
6213
            break;
6214
         }
6215
      }
6216
   }
6217

6218
   vcode_state_restore(&state);
16,094✔
6219
}
16,094✔
6220

6221
#if VCODE_CHECK_UNIONS
6222
#define OP_USE_COUNT_U0(x)                                              \
6223
   (OP_HAS_IDENT(x) + OP_HAS_FUNC(x) + OP_HAS_ADDRESS(x))
6224
#define OP_USE_COUNT_U1(x)                                              \
6225
   (OP_HAS_CMP(x) + OP_HAS_VALUE(x) + OP_HAS_REAL(x) +                  \
6226
    OP_HAS_COMMENT(x) + OP_HAS_DIM(x) + OP_HAS_TARGET(x) +              \
6227
    OP_HAS_HOPS(x) + OP_HAS_FIELD(x) + OP_HAS_TAG(x))
6228

6229
__attribute__((constructor))
6230
static void vcode_check_unions(void)
6231
{
6232
   printf("sizeof(op_t) = %ld\n", sizeof(op_t));
6233
   for (int i = 0; i < 256; i++) {
6234
      assert(OP_USE_COUNT_U0(i) <= 1);
6235
      assert(OP_USE_COUNT_U1(i) <= 1);
6236
   }
6237
}
6238
#endif  // VCODE_CHECK_UNIONS
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc