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

nickg / nvc / 19797507074

30 Nov 2025 10:13AM UTC coverage: 92.564% (-0.002%) from 92.566%
19797507074

push

github

nickg
Avoid code generation for processes in cloned blocks

38 of 49 new or added lines in 4 files covered. (77.55%)

340 existing lines in 5 files now uncovered.

75314 of 81364 relevant lines covered (92.56%)

442082.07 hits per line

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

96.8
/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);
9,973,151✔
36
DECLARE_AND_DEFINE_ARRAY(vcode_block);
343,163✔
37
DECLARE_AND_DEFINE_ARRAY(vcode_type);
80,938✔
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);
11,805,092✔
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,159✔
160
DECLARE_AND_DEFINE_ARRAY(var);
441,758✔
161
DECLARE_AND_DEFINE_ARRAY(reg);
9,590,145✔
162
DECLARE_AND_DEFINE_ARRAY(block);
137,269✔
163
DECLARE_AND_DEFINE_ARRAY(vtype);
47,166,343✔
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)
39,196✔
218
{
219
   int64_t result;
39,196✔
220
   if (__builtin_add_overflow(a, b, &result))
39,196✔
221
      return b < 0 ? INT64_MIN : INT64_MAX;
8,261✔
222

223
   return result;
224
}
225

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

232
   return result;
233
}
234

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

241
   return result;
242
}
243

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

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

254
   return reg;
1,443,214✔
255
}
256

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

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

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

273
   block_t *block = vcode_block_data();
1,853,739✔
274

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

281
   return op;
1,853,739✔
282
}
283

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

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

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

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

303
static op_t *vcode_find_definition(vcode_reg_t reg)
1,660,232✔
304
{
305
   for (int i = active_block; i >= 0; i--) {
1,691,497✔
306
      block_t *b = &(active_unit->blocks.items[i]);
1,690,104✔
307
      for (int j = b->ops.count - 1; j >= 0; j--) {
32,854,625✔
308
         if (b->ops.items[j].result == reg)
32,823,360✔
309
            return &(b->ops.items[j]);
1,658,839✔
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,643,530✔
318
{
319
   op_t *defn = vcode_find_definition(reg);
1,643,530✔
320
   VCODE_ASSERT(defn != NULL, "constant %s uses parameter r%d",
1,643,530✔
321
                what, reg);
322
   VCODE_ASSERT(defn->kind == VCODE_OP_CONST
1,643,530✔
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,643,530✔
331
#endif
332

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

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

346
   int depth = MASK_CONTEXT(type);
7,997,014✔
347
   assert(depth <= unit->depth);
7,997,014✔
348
   while (depth != unit->depth)
8,942,162✔
349
      unit = unit->context;
945,148✔
350

351
   return vtype_array_nth_ptr(&(unit->types), MASK_INDEX(type));
7,997,014✔
352
}
353

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

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

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

370
   switch (defn->kind) {
15,309✔
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,220✔
392
      vcode_var_data(defn->address)->flags |= VAR_HEAP;
1,220✔
393
      break;
1,220✔
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,549✔
417
   case VCODE_OP_UNWRAP:
418
   case VCODE_OP_RESOLVED:
419
      vcode_heap_allocate(defn->args.items[0]);
4,549✔
420
      break;
4,549✔
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,262✔
449
         const vtype_kind_t rkind = vcode_reg_kind(reg);
4,568✔
450
         if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY) {
4,568✔
451
            // Function may return a pointer to its argument
452
            vcode_heap_allocate(defn->args.items[i]);
4,467✔
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,051✔
522
{
523
   state->unit  = active_unit;
38,051✔
524
   state->block = active_block;
38,051✔
525
}
38,051✔
526

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

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

537
   if (unit == active_unit)
50,815✔
538
      vcode_close();
11,152✔
539

540
   for (vcode_unit_t it = unit->children; it != NULL; it = it->next) {
66,017✔
541
      assert(it->context == unit);
15,202✔
542
      it->context = NULL;
15,202✔
543
   }
544
   unit->children = NULL;
50,815✔
545

546
   if (unit->context != NULL) {
50,815✔
547
      vcode_unit_t *it = &(unit->context->children);
12,581✔
548
      for (; *it != NULL && *it != unit; it = &((*it)->next))
37,109✔
549
         ;
550
      assert(*it != NULL);
12,581✔
551
      *it = (*it)->next;
12,581✔
552
   }
553

554
   for (unsigned i = 0; i < unit->blocks.count; i++) {
187,986✔
555
      block_t *b = &(unit->blocks.items[i]);
137,171✔
556

557
      for (unsigned j = 0; j < b->ops.count; j++) {
1,908,059✔
558
         op_t *o = &(b->ops.items[j]);
1,770,888✔
559
         if (OP_HAS_COMMENT(o->kind))
1,770,888✔
560
            free(o->comment);
197,628✔
561
         if (OP_HAS_TARGET(o->kind))
1,770,888✔
562
            free(o->targets.items);
80,641✔
563
         free(o->args.items);
1,770,888✔
564
      }
565
      free(b->ops.items);
137,171✔
566
   }
567
   free(unit->blocks.items);
50,815✔
568

569
   for (unsigned i = 0; i < unit->types.count; i++) {
706,425✔
570
      vtype_t *vt = &(unit->types.items[i]);
655,610✔
571
      if (vt->kind == VCODE_TYPE_RECORD)
655,610✔
572
         free(vt->fields.items);
5,777✔
573
   }
574
   free(unit->types.items);
50,815✔
575

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

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

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

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

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

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

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

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

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

621
   vtype_t *bounds = vcode_type_data(r->bounds);
838,920✔
622

623
   VCODE_ASSERT(
838,920✔
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) {
838,920✔
628
      if (value) *value = bounds->low;
471,507✔
629
      return true;
471,507✔
630
   }
631
   else
632
      return false;
633
}
634

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

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

641
   int pruned = 0;
50,841✔
642
   do {
73,378✔
643
      memset(uses, '\0', active_unit->regs.count * sizeof(int));
73,378✔
644
      pruned = 0;
73,378✔
645

646
      for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
301,182✔
647
         block_t *b = &(active_unit->blocks.items[i]);
227,804✔
648

649
         for (int j = b->ops.count - 1; j >= 0; j--) {
3,523,982✔
650
            op_t *o = &(b->ops.items[j]);
3,296,178✔
651

652
            switch (o->kind) {
3,296,178✔
653
            case VCODE_OP_FCALL:
55,799✔
654
               if (o->result == VCODE_INVALID_REG)
55,799✔
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,101,391✔
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,101,391✔
700
                  if (false DEBUG_ONLY(|| o->kind != VCODE_OP_CONST)) {
201,723✔
701
                     o->comment = xasprintf("Dead %s definition of r%d",
119,762✔
702
                                            vcode_op_string(o->kind),
703
                                            o->result);
704
                     o->kind = VCODE_OP_COMMENT;
119,762✔
705
                  }
706
                  else
707
                     o->kind = (vcode_op_t)-1;
81,961✔
708
                  vcode_reg_array_resize(&(o->args), 0, VCODE_INVALID_REG);
201,723✔
709
                  pruned++;
201,723✔
710
               }
711
               uses[o->result] = -1;
2,101,391✔
712
               break;
2,101,391✔
713

714
            default:
715
               break;
716
            }
717

718
            for (int k = 0; k < o->args.count; k++) {
9,291,662✔
719
               if (o->args.items[k] != VCODE_INVALID_REG)
5,995,484✔
720
                  uses[o->args.items[k]]++;
5,959,962✔
721
            }
722
         }
723
      }
724
   } while (pruned > 0);
73,378✔
725

726
   for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
188,110✔
727
      block_t *b = &(active_unit->blocks.items[i]);
137,269✔
728
      op_t *dst = &(b->ops.items[0]);
137,269✔
729
      size_t copied = 0;
137,269✔
730
      for (int j = 0; j < b->ops.count; j++) {
1,991,008✔
731
         const op_t *src = &(b->ops.items[j]);
1,853,739✔
732
         if (src->kind != (vcode_op_t)-1) {
1,853,739✔
733
            if (src != dst) {
1,771,778✔
734
               assert(dst < src);
582,561✔
735
               *dst = *src;
582,561✔
736
            }
737
            dst++;
1,771,778✔
738
            copied++;
1,771,778✔
739
         }
740
      }
741

742
      assert(copied <= b->ops.count);
137,269✔
743
      b->ops.count = copied;
137,269✔
744
   }
745
}
50,841✔
746

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

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

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

766
int vcode_count_vars(void)
50,789✔
767
{
768
   assert(active_unit != NULL);
50,789✔
769
   return active_unit->vars.count;
50,789✔
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)
74,537✔
784
{
785
   return vcode_var_data(var)->name;
74,537✔
786
}
787

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

895
vcode_cmp_t vcode_get_cmp(int op)
33,467✔
896
{
897
   op_t *o = vcode_op_data(op);
33,467✔
898
   assert(OP_HAS_CMP(o->kind));
33,467✔
899
   return o->cmp;
33,467✔
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,770,820✔
910
{
911
   op_t *o = vcode_op_data(op);
1,770,820✔
912
   return &(o->loc);
1,770,820✔
913
}
914

915
vcode_block_t vcode_get_target(int op, int nth)
114,517✔
916
{
917
   op_t *o = vcode_op_data(op);
114,517✔
918
   assert(OP_HAS_TARGET(o->kind));
114,517✔
919
   return vcode_block_array_nth(&(o->targets), nth);
114,517✔
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)
1,969,682✔
931
{
932
   assert(active_unit != NULL);
1,969,682✔
933
   assert(active_block != VCODE_INVALID_BLOCK);
1,969,682✔
934

935
   const block_t *b = &(active_unit->blocks.items[active_block]);
1,969,682✔
936
   if (b->ops.count == 0)
1,969,682✔
937
      return false;
938
   else {
939
      vcode_op_t kind = b->ops.items[b->ops.count - 1].kind;
1,784,180✔
940
      return kind == VCODE_OP_WAIT || kind == VCODE_OP_JUMP
1,784,180✔
941
         || kind == VCODE_OP_COND || kind == VCODE_OP_PCALL
1,784,162✔
942
         || kind == VCODE_OP_RETURN || kind == VCODE_OP_CASE
943
         || kind == VCODE_OP_UNREACHABLE;
3,568,342✔
944
   }
945
}
946

947
const char *vcode_op_string(vcode_op_t op)
119,762✔
948
{
949
   static const char *strs[] = {
119,762✔
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))
119,762✔
979
      return "???";
980
   else
981
      return strs[op];
119,762✔
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
static inline bool vtype_eq_internal(const vtype_t *at, const vtype_t *bt)
35,956,254✔
2400
{
2401
   if (at->kind != bt->kind)
35,956,254✔
2402
      return false;
2403

2404
   switch (at->kind) {
16,054,498✔
2405
   case VCODE_TYPE_INT:
13,933,963✔
2406
      return (at->low == bt->low) && (at->high == bt->high);
25,917,910✔
2407
   case VCODE_TYPE_REAL:
929,293✔
2408
      return (at->rlow == bt->rlow) && (at->rhigh == bt->rhigh);
1,789,349✔
2409
   case VCODE_TYPE_CARRAY:
101,432✔
2410
      return at->size == bt->size && vtype_eq(at->elem, bt->elem);
108,731✔
2411
   case VCODE_TYPE_UARRAY:
80,448✔
2412
      return at->dims == bt->dims && vtype_eq(at->elem, bt->elem);
100,648✔
2413
   case VCODE_TYPE_POINTER:
475,626✔
2414
   case VCODE_TYPE_ACCESS:
2415
      return vtype_eq(at->pointed, bt->pointed);
475,626✔
2416
   case VCODE_TYPE_OFFSET:
2417
   case VCODE_TYPE_OPAQUE:
2418
   case VCODE_TYPE_DEBUG_LOCUS:
2419
   case VCODE_TYPE_TRIGGER:
2420
   case VCODE_TYPE_CONVERSION:
2421
      return true;
2422
   case VCODE_TYPE_RESOLUTION:
73,604✔
2423
   case VCODE_TYPE_CLOSURE:
2424
   case VCODE_TYPE_SIGNAL:
2425
   case VCODE_TYPE_FILE:
2426
      return vtype_eq(at->base, bt->base);
73,604✔
2427
   case VCODE_TYPE_RECORD:
61,386✔
2428
   case VCODE_TYPE_CONTEXT:
2429
      return at->name == bt->name;
61,386✔
UNCOV
2430
   default:
×
2431
      should_not_reach_here();
2432
   }
2433
}
2434

2435
bool vtype_eq(vcode_type_t a, vcode_type_t b)
4,542,288✔
2436
{
2437
   assert(active_unit != NULL);
4,542,288✔
2438

2439
   if (a == b)
4,542,288✔
2440
      return true;
2441
   else if (MASK_CONTEXT(a) == MASK_CONTEXT(b))
944,408✔
2442
      return false;   // Guaranteed by vtype_new
2443
   else {
2444
      const vtype_t *at = vcode_type_data(a);
117,940✔
2445
      const vtype_t *bt = vcode_type_data(b);
117,940✔
2446

2447
      return vtype_eq_internal(at, bt);
117,940✔
2448
   }
2449
}
2450

UNCOV
2451
void vcode_dump(void)
×
2452
{
UNCOV
2453
   vcode_dump_with_mark(-1, NULL, NULL);
×
UNCOV
2454
}
×
2455

2456
static vcode_type_t vtype_new(vtype_t *new)
3,331,015✔
2457
{
2458
   const int index = active_unit->types.count - 1;
3,331,015✔
2459

2460
   for (int i = 0; i < index; i++) {
36,494,290✔
2461
      const vtype_t *cmp = vtype_array_nth_ptr(&(active_unit->types), i);
35,838,314✔
2462
      if (vtype_eq_internal(new, cmp)) {
35,838,314✔
2463
         active_unit->types.count--;
2,675,039✔
2464
         return MAKE_HANDLE(active_unit->depth, i);
2,675,039✔
2465
      }
2466
   }
2467

2468
   return MAKE_HANDLE(active_unit->depth, index);
655,976✔
2469
}
2470

2471
vcode_type_t vtype_int(int64_t low, int64_t high)
2,307,737✔
2472
{
2473
   assert(active_unit != NULL);
2,307,737✔
2474

2475
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
2,307,737✔
2476
   n->kind = VCODE_TYPE_INT;
2,307,737✔
2477
   n->low  = low;
2,307,737✔
2478
   n->high = high;
2,307,737✔
2479

2480
   switch (bits_for_range(low, high)) {
2,307,737✔
2481
   case 64:
127,959✔
2482
      n->repr = low < 0 ? VCODE_REPR_I64 : VCODE_REPR_U64;
127,959✔
2483
      break;
127,959✔
2484
   case 32:
619,938✔
2485
      n->repr = low < 0 ? VCODE_REPR_I32 : VCODE_REPR_U32;
619,938✔
2486
      break;
619,938✔
2487
   case 16:
4,310✔
2488
      n->repr = low < 0 ? VCODE_REPR_I16 : VCODE_REPR_U16;
4,310✔
2489
      break;
4,310✔
2490
   case 8:
906,024✔
2491
      n->repr = low < 0 ? VCODE_REPR_I8 : VCODE_REPR_U8;
906,024✔
2492
      break;
906,024✔
2493
   case 1:
649,505✔
2494
      n->repr = VCODE_REPR_U1;
649,505✔
2495
      break;
649,505✔
2496
   case 0:
1✔
2497
      n->repr = VCODE_REPR_I64;    // Null range
1✔
2498
      break;
1✔
UNCOV
2499
   default:
×
2500
      fatal_trace("cannot represent %"PRIi64"..%"PRIi64, low, high);
2501
   }
2502

2503
   return vtype_new(n);
2,307,737✔
2504
}
2505

2506
vcode_type_t vtype_bool(void)
333,695✔
2507
{
2508
   return vtype_int(0, 1);
333,695✔
2509
}
2510

2511
vcode_type_t vtype_carray(int size, vcode_type_t elem, vcode_type_t bounds)
54,875✔
2512
{
2513
   assert(active_unit != NULL);
54,875✔
2514

2515
   const vtype_kind_t ekind = vtype_kind(elem);
54,875✔
2516
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
54,875✔
2517
                "array types may not be nested");
2518

2519
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
54,875✔
2520
   memset(n, '\0', sizeof(vtype_t));
54,875✔
2521
   n->kind   = VCODE_TYPE_CARRAY;
54,875✔
2522
   n->elem   = elem;
54,875✔
2523
   n->bounds = bounds;
54,875✔
2524
   n->size   = MAX(size, 0);
54,875✔
2525

2526
   return vtype_new(n);
54,875✔
2527
}
2528

2529
vcode_type_t vtype_find_named_record(ident_t name)
37,584✔
2530
{
2531
   assert(active_unit != NULL);
37,584✔
2532

2533
   for (int i = 0; i < active_unit->types.count; i++) {
477,617✔
2534
      vtype_t *other = &(active_unit->types.items[i]);
466,063✔
2535
      if (other->kind == VCODE_TYPE_RECORD && other->name == name)
466,063✔
2536
         return MAKE_HANDLE(active_unit->depth, i);
26,030✔
2537
   }
2538

2539
   return VCODE_INVALID_TYPE;
2540
}
2541

2542
vcode_type_t vtype_named_record(ident_t name, const vcode_type_t *field_types,
11,554✔
2543
                                int nfields)
2544
{
2545
   assert(active_unit != NULL);
11,554✔
2546

2547
   vtype_t *data = NULL;
11,554✔
2548
   vcode_type_t handle = vtype_find_named_record(name);
11,554✔
2549
   if (handle == VCODE_INVALID_TYPE) {
11,554✔
2550
      data = vtype_array_alloc(&(active_unit->types));
5,777✔
2551
      memset(data, '\0', sizeof(vtype_t));
5,777✔
2552
      data->kind = VCODE_TYPE_RECORD;
5,777✔
2553
      data->name = name;
5,777✔
2554

2555
      handle = vtype_new(data);
5,777✔
2556
   }
2557
   else {
2558
      data = vcode_type_data(handle);
5,777✔
2559
      VCODE_ASSERT(data->fields.count == 0,
5,777✔
2560
                    "record type %s already defined", istr(name));
2561
   }
2562

2563
   vcode_type_array_resize(&(data->fields), 0, VCODE_INVALID_TYPE);
11,554✔
2564
   for (int i = 0; i < nfields; i++)
30,799✔
2565
      vcode_type_array_add(&(data->fields), field_types[i]);
19,245✔
2566

2567
   return handle;
11,554✔
2568
}
2569

2570
vcode_type_t vtype_uarray(int ndim, vcode_type_t elem, vcode_type_t bounds)
77,314✔
2571
{
2572
   assert(active_unit != NULL);
77,314✔
2573

2574
   const vtype_kind_t ekind = vtype_kind(elem);
77,314✔
2575
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
77,314✔
2576
                "array types may not be nested");
2577

2578
   VCODE_ASSERT(ndim > 0, "uarray must have at least one dimension");
77,314✔
2579

2580
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
77,314✔
2581
   memset(n, '\0', sizeof(vtype_t));
77,314✔
2582
   n->kind   = VCODE_TYPE_UARRAY;
77,314✔
2583
   n->elem   = elem;
77,314✔
2584
   n->bounds = bounds;
77,314✔
2585
   n->dims   = ndim;
77,314✔
2586

2587
   return vtype_new(n);
77,314✔
2588
}
2589

2590
vcode_type_t vtype_pointer(vcode_type_t to)
201,596✔
2591
{
2592
   assert(active_unit != NULL);
201,596✔
2593

2594
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
201,596✔
2595
   n->kind    = VCODE_TYPE_POINTER;
201,596✔
2596
   n->pointed = to;
201,596✔
2597

2598
   VCODE_ASSERT(vtype_kind(to) != VCODE_TYPE_CARRAY,
201,596✔
2599
                "cannot get pointer to carray type");
2600

2601
   return vtype_new(n);
201,596✔
2602
}
2603

2604
vcode_type_t vtype_access(vcode_type_t to)
9,393✔
2605
{
2606
   assert(active_unit != NULL);
9,393✔
2607

2608
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
9,393✔
2609
   n->kind    = VCODE_TYPE_ACCESS;
9,393✔
2610
   n->pointed = to;
9,393✔
2611

2612
   return vtype_new(n);
9,393✔
2613
}
2614

2615
vcode_type_t vtype_signal(vcode_type_t base)
39,473✔
2616
{
2617
   assert(active_unit != NULL);
39,473✔
2618

2619
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
39,473✔
2620
   n->kind = VCODE_TYPE_SIGNAL;
39,473✔
2621
   n->base = base;
39,473✔
2622

2623
   VCODE_ASSERT(vtype_is_scalar(base), "signal base type must be scalar");
39,473✔
2624

2625
   return vtype_new(n);
39,473✔
2626
}
2627

2628
vcode_type_t vtype_resolution(vcode_type_t base)
8,217✔
2629
{
2630
   assert(active_unit != NULL);
8,217✔
2631

2632
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
8,217✔
2633
   n->kind = VCODE_TYPE_RESOLUTION;
8,217✔
2634
   n->base = base;
8,217✔
2635

2636
   return vtype_new(n);
8,217✔
2637
}
2638

2639
vcode_type_t vtype_closure(vcode_type_t result)
5,354✔
2640
{
2641
   assert(active_unit != NULL);
5,354✔
2642

2643
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
5,354✔
2644
   n->kind = VCODE_TYPE_CLOSURE;
5,354✔
2645
   n->base = result;
5,354✔
2646

2647
   return vtype_new(n);
5,354✔
2648
}
2649

2650
vcode_type_t vtype_context(ident_t name)
55,162✔
2651
{
2652
   assert(active_unit != NULL);
55,162✔
2653
   assert(name != NULL);
55,162✔
2654

2655
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
55,162✔
2656
   n->kind = VCODE_TYPE_CONTEXT;
55,162✔
2657
   n->name = name;
55,162✔
2658

2659
   return vtype_new(n);
55,162✔
2660
}
2661

2662
vcode_type_t vtype_file(vcode_type_t base)
1,827✔
2663
{
2664
   assert(active_unit != NULL);
1,827✔
2665

2666
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
1,827✔
2667
   n->kind = VCODE_TYPE_FILE;
1,827✔
2668
   n->base = base;
1,827✔
2669

2670
   return vtype_new(n);
1,827✔
2671
}
2672

2673
vcode_type_t vtype_offset(void)
291,895✔
2674
{
2675
   assert(active_unit != NULL);
291,895✔
2676

2677
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
291,895✔
2678
   n->kind = VCODE_TYPE_OFFSET;
291,895✔
2679
   n->low  = INT64_MIN;
291,895✔
2680
   n->high = INT64_MAX;
291,895✔
2681
   n->repr = VCODE_REPR_I64;
291,895✔
2682

2683
   return vtype_new(n);
291,895✔
2684
}
2685

2686
vcode_type_t vtype_time(void)
14,661✔
2687
{
2688
   return vtype_int(INT64_MIN, INT64_MAX);
14,661✔
2689
}
2690

2691
vcode_type_t vtype_char(void)
8,164✔
2692
{
2693
   return vtype_int(0, 255);
8,164✔
2694
}
2695

2696
vcode_type_t vtype_opaque(void)
3,474✔
2697
{
2698
   assert(active_unit != NULL);
3,474✔
2699

2700
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
3,474✔
2701
   n->kind = VCODE_TYPE_OPAQUE;
3,474✔
2702

2703
   return vtype_new(n);
3,474✔
2704
}
2705

2706
vcode_type_t vtype_debug_locus(void)
156,545✔
2707
{
2708
   assert(active_unit != NULL);
156,545✔
2709

2710
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
156,545✔
2711
   n->kind = VCODE_TYPE_DEBUG_LOCUS;
156,545✔
2712

2713
   return vtype_new(n);
156,545✔
2714
}
2715

2716
vcode_type_t vtype_trigger(void)
386✔
2717
{
2718
   assert(active_unit != NULL);
386✔
2719

2720
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
386✔
2721
   n->kind = VCODE_TYPE_TRIGGER;
386✔
2722

2723
   return vtype_new(n);
386✔
2724
}
2725

2726
vcode_type_t vtype_conversion(void)
426✔
2727
{
2728
   assert(active_unit != NULL);
426✔
2729

2730
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
426✔
2731
   n->kind = VCODE_TYPE_CONVERSION;
426✔
2732

2733
   return vtype_new(n);
426✔
2734
}
2735

2736
vcode_type_t vtype_real(double low, double high)
111,564✔
2737
{
2738
   assert(active_unit != NULL);
111,564✔
2739

2740
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
111,564✔
2741
   n->kind  = VCODE_TYPE_REAL;
111,564✔
2742
   n->rlow  = low;
111,564✔
2743
   n->rhigh = high;
111,564✔
2744

2745
   return vtype_new(n);
111,564✔
2746
}
2747

2748
vtype_kind_t vtype_kind(vcode_type_t type)
4,787,002✔
2749
{
2750
   vtype_t *vt = vcode_type_data(type);
4,787,002✔
2751
   return vt->kind;
4,787,002✔
2752
}
2753

2754
vtype_repr_t vtype_repr(vcode_type_t type)
55,645✔
2755
{
2756
   vtype_t *vt = vcode_type_data(type);
55,645✔
2757
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
55,645✔
2758
   return vt->repr;
55,645✔
2759
}
2760

2761
vcode_type_t vtype_elem(vcode_type_t type)
159,651✔
2762
{
2763
   vtype_t *vt = vcode_type_data(type);
159,651✔
2764
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
159,651✔
2765
   return vt->elem;
159,651✔
2766
}
2767

2768
vcode_type_t vtype_base(vcode_type_t type)
52,408✔
2769
{
2770
   vtype_t *vt = vcode_type_data(type);
52,408✔
2771
   assert(vt->kind == VCODE_TYPE_SIGNAL || vt->kind == VCODE_TYPE_FILE
52,408✔
2772
          || vt->kind == VCODE_TYPE_RESOLUTION
2773
          || vt->kind == VCODE_TYPE_CLOSURE);
2774
   return vt->base;
52,408✔
2775
}
2776

2777
vcode_type_t vtype_bounds(vcode_type_t type)
22,052✔
2778
{
2779
   vtype_t *vt = vcode_type_data(type);
22,052✔
2780
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
22,052✔
2781
   return vt->bounds;
22,052✔
2782
}
2783

2784
unsigned vtype_dims(vcode_type_t type)
42,996✔
2785
{
2786
   vtype_t *vt = vcode_type_data(type);
42,996✔
2787
   assert(vt->kind == VCODE_TYPE_UARRAY);
42,996✔
2788
   return vt->dims;
42,996✔
2789
}
2790

2791
unsigned vtype_size(vcode_type_t type)
52,212✔
2792
{
2793
   vtype_t *vt = vcode_type_data(type);
52,212✔
2794
   assert(vt->kind == VCODE_TYPE_CARRAY);
52,212✔
2795
   return vt->size;
52,212✔
2796
}
2797

2798
int vtype_fields(vcode_type_t type)
7,995✔
2799
{
2800
   vtype_t *vt = vcode_type_data(type);
7,995✔
2801
   assert(vt->kind == VCODE_TYPE_RECORD);
7,995✔
2802
   return vt->fields.count;
7,995✔
2803
}
2804

2805
vcode_type_t vtype_field(vcode_type_t type, int field)
30,894✔
2806
{
2807
   vtype_t *vt = vcode_type_data(type);
30,894✔
2808
   assert(vt->kind == VCODE_TYPE_RECORD);
30,894✔
2809
   return vcode_type_array_nth(&(vt->fields), field);
30,894✔
2810
}
2811

2812
ident_t vtype_name(vcode_type_t type)
19,268✔
2813
{
2814
   vtype_t *vt = vcode_type_data(type);
19,268✔
2815
   assert(vt->kind == VCODE_TYPE_RECORD || vt->kind == VCODE_TYPE_CONTEXT);
19,268✔
2816
   return vt->name;
19,268✔
2817
}
2818

2819
vcode_type_t vtype_pointed(vcode_type_t type)
336,830✔
2820
{
2821
   vtype_t *vt = vcode_type_data(type);
336,830✔
2822
   assert(vt->kind == VCODE_TYPE_POINTER || vt->kind == VCODE_TYPE_ACCESS);
336,830✔
2823
   return vt->pointed;
336,830✔
2824
}
2825

2826
int64_t vtype_low(vcode_type_t type)
246,564✔
2827
{
2828
   vtype_t *vt = vcode_type_data(type);
246,564✔
2829
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
246,564✔
2830
   return vt->low;
246,564✔
2831
}
2832

2833
int64_t vtype_high(vcode_type_t type)
243,851✔
2834
{
2835
   vtype_t *vt = vcode_type_data(type);
243,851✔
2836
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
243,851✔
2837
   return vt->high;
243,851✔
2838
}
2839

2840
static bool vtype_is_pointer(vcode_type_t type, vtype_kind_t to)
1,564✔
2841
{
2842
   return vtype_kind(type) == VCODE_TYPE_POINTER
1,564✔
2843
      && vtype_kind(vtype_pointed(type)) == to;
1,564✔
2844
}
2845

2846
bool vtype_is_scalar(vcode_type_t type)
418,046✔
2847
{
2848
   const vtype_kind_t kind = vtype_kind(type);
418,046✔
2849
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
418,046✔
2850
      || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_POINTER
162,465✔
2851
      || kind == VCODE_TYPE_FILE || kind == VCODE_TYPE_ACCESS
2852
      || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_SIGNAL
2853
      || kind == VCODE_TYPE_CONTEXT || kind == VCODE_TYPE_TRIGGER
2854
      || kind == VCODE_TYPE_RESOLUTION;
418,046✔
2855
}
2856

2857
bool vtype_is_composite(vcode_type_t type)
31,651✔
2858
{
2859
   const vtype_kind_t kind = vtype_kind(type);
31,651✔
2860
   return kind == VCODE_TYPE_RECORD || kind == VCODE_TYPE_CARRAY;
31,651✔
2861
}
2862

2863
bool vtype_is_signal(vcode_type_t type)
160,780✔
2864
{
2865
   vtype_t *vt = vcode_type_data(type);
283,981✔
2866
   switch (vt->kind) {
283,981✔
2867
   case VCODE_TYPE_SIGNAL:
2868
      return true;
2869
   case VCODE_TYPE_POINTER:
73,234✔
2870
      return vtype_is_signal(vt->pointed);
73,234✔
2871
   case VCODE_TYPE_RECORD:
2872
      for (int i = 0; i < vt->fields.count; i++) {
34,293✔
2873
         if (vtype_is_signal(vt->fields.items[i]))
27,087✔
2874
            return true;
2875
      }
2876
      return false;
2877
   case VCODE_TYPE_UARRAY:
49,967✔
2878
   case VCODE_TYPE_CARRAY:
2879
      return vtype_is_signal(vt->elem);
49,967✔
2880
   default:
126,082✔
2881
      return false;
126,082✔
2882
   }
2883
}
2884

UNCOV
2885
int vtype_repr_bits(vtype_repr_t repr)
×
2886
{
UNCOV
2887
   switch (repr) {
×
2888
   case VCODE_REPR_U1: return 1;
2889
   case VCODE_REPR_U8: case VCODE_REPR_I8: return 8;
2890
   case VCODE_REPR_U16: case VCODE_REPR_I16: return 16;
2891
   case VCODE_REPR_U32: case VCODE_REPR_I32: return 32;
2892
   case VCODE_REPR_U64: case VCODE_REPR_I64: return 64;
2893
   default: return -1;
2894
   }
2895
}
2896

UNCOV
2897
bool vtype_repr_signed(vtype_repr_t repr)
×
2898
{
UNCOV
2899
   return repr == VCODE_REPR_I8 || repr == VCODE_REPR_I16
×
UNCOV
2900
      || repr == VCODE_REPR_I32 || repr == VCODE_REPR_I64;
×
2901
}
2902

2903
static int64_t vtype_repr_low(vtype_repr_t repr)
14,406✔
2904
{
2905
   switch (repr) {
14,406✔
2906
   case VCODE_REPR_U1:
2907
   case VCODE_REPR_U8:
2908
   case VCODE_REPR_U16:
2909
   case VCODE_REPR_U32:
2910
   case VCODE_REPR_U64: return 0;
2911
   case VCODE_REPR_I8:  return INT8_MIN;
2912
   case VCODE_REPR_I16: return INT16_MIN;
2913
   case VCODE_REPR_I32: return INT32_MIN;
2914
   case VCODE_REPR_I64: return INT64_MIN;
2915
   default:             return 0;
2916
   }
2917
}
2918

2919
static uint64_t vtype_repr_high(vtype_repr_t repr)
14,406✔
2920
{
2921
   switch (repr) {
14,406✔
2922
   case VCODE_REPR_U1:  return 1;
2923
   case VCODE_REPR_U8:  return UINT8_MAX;
2924
   case VCODE_REPR_U16: return UINT16_MAX;
2925
   case VCODE_REPR_U32: return UINT32_MAX;
2926
   case VCODE_REPR_U64: return UINT64_MAX;
2927
   case VCODE_REPR_I8:  return INT8_MAX;
2928
   case VCODE_REPR_I16: return INT16_MAX;
2929
   case VCODE_REPR_I32: return INT32_MAX;
2930
   case VCODE_REPR_I64: return INT64_MAX;
2931
   default:             return 0;
2932
   }
2933
}
2934

2935
static bool vtype_clamp_to_repr(vtype_repr_t repr, int64_t *low, int64_t *high)
14,406✔
2936
{
2937
   int64_t clamp_low = vtype_repr_low(repr);
14,406✔
2938
   uint64_t clamp_high = vtype_repr_high(repr);
14,406✔
2939

2940
   if (*low >= clamp_low && *high <= clamp_high)
14,406✔
2941
      return true;
2942
   else {
2943
      *low = MAX(clamp_low, *low);
6,362✔
2944
      *high = MIN(clamp_high, *high);
6,362✔
2945
      return false;
6,362✔
2946
   }
2947
}
2948

2949
int vcode_count_params(void)
13,470✔
2950
{
2951
   assert(active_unit != NULL);
13,470✔
2952
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
13,470✔
2953
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2954
          || active_unit->kind == VCODE_UNIT_PROPERTY
2955
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2956

2957
   return active_unit->params.count;
13,470✔
2958
}
2959

2960
vcode_type_t vcode_param_type(int param)
31,873✔
2961
{
2962
   assert(active_unit != NULL);
31,873✔
2963
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
31,873✔
2964
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2965
          || active_unit->kind == VCODE_UNIT_PROPERTY
2966
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2967
   assert(param < active_unit->params.count);
31,873✔
2968

2969
   return active_unit->params.items[param].type;
31,873✔
2970
}
2971

2972
ident_t vcode_param_name(int param)
31,873✔
2973
{
2974
   assert(active_unit != NULL);
31,873✔
2975
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
31,873✔
2976
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2977
          || active_unit->kind == VCODE_UNIT_PROPERTY
2978
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2979
   assert(param < active_unit->params.count);
31,873✔
2980

2981
   return active_unit->params.items[param].name;
31,873✔
2982
}
2983

2984
vcode_reg_t vcode_param_reg(int param)
31,873✔
2985
{
2986
   assert(active_unit != NULL);
31,873✔
2987
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
31,873✔
2988
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2989
          || active_unit->kind == VCODE_UNIT_PROPERTY
2990
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2991
   assert(param < active_unit->params.count);
31,873✔
2992

2993
   return active_unit->params.items[param].reg;
31,873✔
2994
}
2995

2996
vcode_block_t emit_block(void)
137,269✔
2997
{
2998
   assert(active_unit != NULL);
137,269✔
2999

3000
   vcode_block_t bnum = active_unit->blocks.count;
137,269✔
3001

3002
   block_t *bptr = block_array_alloc(&(active_unit->blocks));
137,269✔
3003
   memset(bptr, '\0', sizeof(block_t));
137,269✔
3004

3005
   if (active_block != VCODE_INVALID_BLOCK)
137,269✔
3006
      bptr->last_loc = active_unit->blocks.items[active_block].last_loc;
86,428✔
3007
   else
3008
      bptr->last_loc = LOC_INVALID;
50,841✔
3009

3010
   return bnum;
137,269✔
3011
}
3012

3013
void vcode_select_unit(vcode_unit_t unit)
178,697✔
3014
{
3015
   active_unit  = unit;
178,697✔
3016
   active_block = VCODE_INVALID_BLOCK;
178,697✔
3017
}
178,697✔
3018

3019
void vcode_select_block(vcode_block_t block)
321,765✔
3020
{
3021
   assert(active_unit != NULL);
321,765✔
3022
   active_block = block;
321,765✔
3023
}
321,765✔
3024

3025
vcode_block_t vcode_active_block(void)
731✔
3026
{
3027
   assert(active_unit != NULL);
731✔
3028
   assert(active_block != -1);
731✔
3029
   return active_block;
731✔
3030
}
3031

3032
const loc_t *vcode_last_loc(void)
1,177,270✔
3033
{
3034
   return &(vcode_block_data()->last_loc);
1,177,270✔
3035
}
3036

3037
vcode_unit_t vcode_active_unit(void)
731✔
3038
{
3039
   assert(active_unit != NULL);
731✔
3040
   return active_unit;
731✔
3041
}
3042

3043
ident_t vcode_unit_name(vcode_unit_t vu)
157,478✔
3044
{
3045
   assert(vu != NULL);
157,478✔
3046
   return vu->name;
157,478✔
3047
}
3048

3049
bool vcode_unit_has_undefined(vcode_unit_t vu)
11,144✔
3050
{
3051
   assert(vu != NULL);
11,144✔
3052
   return !!(vu->flags & UNIT_UNDEFINED);
11,144✔
3053
}
3054

UNCOV
3055
int vcode_unit_depth(vcode_unit_t vu)
×
3056
{
UNCOV
3057
   assert(vu != NULL);
×
UNCOV
3058
   return vu->depth;
×
3059
}
3060

3061
void vcode_set_result(vcode_type_t type)
21,532✔
3062
{
3063
   assert(active_unit != NULL);
21,532✔
3064
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
21,532✔
3065
          || active_unit->kind == VCODE_UNIT_THUNK);
3066

3067
   active_unit->result = type;
21,532✔
3068
}
21,532✔
3069

3070
vcode_type_t vcode_unit_result(vcode_unit_t vu)
23,575✔
3071
{
3072
   assert(vu != NULL);
23,575✔
3073
   assert(vu->kind == VCODE_UNIT_FUNCTION || vu->kind == VCODE_UNIT_THUNK);
23,575✔
3074
   return vu->result;
23,575✔
3075
}
3076

3077
vunit_kind_t vcode_unit_kind(vcode_unit_t vu)
140,643✔
3078
{
3079
   assert(vu != NULL);
140,643✔
3080
   return vu->kind;
140,643✔
3081
}
3082

3083
vcode_unit_t vcode_unit_context(vcode_unit_t vu)
78,260✔
3084
{
3085
   assert(vu != NULL);
78,260✔
3086
   return vu->context;
78,260✔
3087
}
3088

3089
object_t *vcode_unit_object(vcode_unit_t vu)
88,056✔
3090
{
3091
   assert(vu != NULL);
88,056✔
3092
   return vu->object;
88,056✔
3093
}
3094

3095
static unsigned vcode_unit_calc_depth(vcode_unit_t unit)
61,997✔
3096
{
3097
   int hops = 0;
61,997✔
3098
   for (; (unit = unit->context); hops++)
152,645✔
3099
      ;
3100
   return hops;
61,997✔
3101
}
3102

3103
static void vcode_add_child(vcode_unit_t context, vcode_unit_t child)
27,789✔
3104
{
3105
   assert(context->kind != VCODE_UNIT_THUNK);
27,789✔
3106

3107
   child->next = NULL;
27,789✔
3108
   if (context->children == NULL)
27,789✔
3109
      context->children = child;
12,388✔
3110
   else {
3111
      vcode_unit_t it;
3112
      for (it = context->children; it->next != NULL; it = it->next)
71,718✔
3113
         ;
3114
      it->next = child;
15,401✔
3115
   }
3116
}
27,789✔
3117

3118
vcode_unit_t emit_function(ident_t name, object_t *obj, vcode_unit_t context)
12,480✔
3119
{
3120
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
12,480✔
3121
   vu->kind     = VCODE_UNIT_FUNCTION;
12,480✔
3122
   vu->name     = name;
12,480✔
3123
   vu->context  = context;
12,480✔
3124
   vu->result   = VCODE_INVALID_TYPE;
12,480✔
3125
   vu->depth    = vcode_unit_calc_depth(vu);
12,480✔
3126
   vu->object   = obj;
12,480✔
3127

3128
   vcode_add_child(context, vu);
12,480✔
3129

3130
   vcode_select_unit(vu);
12,480✔
3131
   vcode_select_block(emit_block());
12,480✔
3132
   emit_debug_info(&(obj->loc));
12,480✔
3133

3134
   return vu;
12,480✔
3135
}
3136

3137
vcode_unit_t emit_procedure(ident_t name, object_t *obj, vcode_unit_t context)
216✔
3138
{
3139
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
216✔
3140
   vu->kind     = VCODE_UNIT_PROCEDURE;
216✔
3141
   vu->name     = name;
216✔
3142
   vu->context  = context;
216✔
3143
   vu->result   = VCODE_INVALID_TYPE;
216✔
3144
   vu->depth    = vcode_unit_calc_depth(vu);
216✔
3145
   vu->object   = obj;
216✔
3146

3147
   vcode_add_child(context, vu);
216✔
3148

3149
   vcode_select_unit(vu);
216✔
3150
   vcode_select_block(emit_block());
216✔
3151
   emit_debug_info(&(obj->loc));
216✔
3152

3153
   return vu;
216✔
3154
}
3155

3156
vcode_unit_t emit_process(ident_t name, object_t *obj, vcode_unit_t context)
7,598✔
3157
{
3158
   assert(context->kind == VCODE_UNIT_INSTANCE);
7,598✔
3159

3160
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
7,598✔
3161
   vu->kind     = VCODE_UNIT_PROCESS;
7,598✔
3162
   vu->name     = name;
7,598✔
3163
   vu->context  = context;
7,598✔
3164
   vu->depth    = vcode_unit_calc_depth(vu);
7,598✔
3165
   vu->result   = VCODE_INVALID_TYPE;
7,598✔
3166
   vu->object   = obj;
7,598✔
3167

3168
   vcode_add_child(context, vu);
7,598✔
3169

3170
   vcode_select_unit(vu);
7,598✔
3171
   vcode_select_block(emit_block());
7,598✔
3172
   emit_debug_info(&(obj->loc));
7,598✔
3173

3174
   return vu;
7,598✔
3175
}
3176

3177
vcode_unit_t emit_instance(ident_t name, object_t *obj, vcode_unit_t context)
9,996✔
3178
{
3179
   assert(context == NULL || context->kind == VCODE_UNIT_INSTANCE);
9,996✔
3180

3181
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
9,996✔
3182
   vu->kind     = VCODE_UNIT_INSTANCE;
9,996✔
3183
   vu->name     = name;
9,996✔
3184
   vu->context  = context;
9,996✔
3185
   vu->depth    = vcode_unit_calc_depth(vu);
9,996✔
3186
   vu->result   = VCODE_INVALID_TYPE;
9,996✔
3187
   vu->object   = obj;
9,996✔
3188

3189
   if (context != NULL)
9,996✔
3190
      vcode_add_child(context, vu);
6,246✔
3191

3192
   vcode_select_unit(vu);
9,996✔
3193
   vcode_select_block(emit_block());
9,996✔
3194
   emit_debug_info(&(obj->loc));
9,996✔
3195

3196
   return vu;
9,996✔
3197
}
3198

3199
vcode_unit_t emit_package(ident_t name, object_t *obj, vcode_unit_t context)
8,621✔
3200
{
3201
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
8,621✔
3202
   vu->kind     = VCODE_UNIT_PACKAGE;
8,621✔
3203
   vu->name     = name;
8,621✔
3204
   vu->context  = context;
8,621✔
3205
   vu->depth    = vcode_unit_calc_depth(vu);
8,621✔
3206
   vu->result   = VCODE_INVALID_TYPE;
8,621✔
3207
   vu->object   = obj;
8,621✔
3208

3209
   if (context != NULL)
8,621✔
3210
      vcode_add_child(context, vu);
189✔
3211

3212
   vcode_select_unit(vu);
8,621✔
3213
   vcode_select_block(emit_block());
8,621✔
3214
   emit_debug_info(&(obj->loc));
8,621✔
3215

3216
   return vu;
8,621✔
3217
}
3218

3219
vcode_unit_t emit_protected(ident_t name, object_t *obj, vcode_unit_t context)
534✔
3220
{
3221
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
534✔
3222
   vu->kind     = VCODE_UNIT_PROTECTED;
534✔
3223
   vu->name     = name;
534✔
3224
   vu->context  = context;
534✔
3225
   vu->depth    = vcode_unit_calc_depth(vu);
534✔
3226
   vu->result   = VCODE_INVALID_TYPE;
534✔
3227
   vu->object   = obj;
534✔
3228

3229
   if (context != NULL)
534✔
3230
      vcode_add_child(context, vu);
534✔
3231

3232
   vcode_select_unit(vu);
534✔
3233
   vcode_select_block(emit_block());
534✔
3234
   emit_debug_info(&(obj->loc));
534✔
3235

3236
   return vu;
534✔
3237
}
3238

3239
vcode_unit_t emit_property(ident_t name, object_t *obj, vcode_unit_t context)
240✔
3240
{
3241
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
240✔
3242
   vu->kind     = VCODE_UNIT_PROPERTY;
240✔
3243
   vu->name     = name;
240✔
3244
   vu->context  = context;
240✔
3245
   vu->depth    = vcode_unit_calc_depth(vu);
240✔
3246
   vu->result   = VCODE_INVALID_TYPE;
240✔
3247
   vu->object   = obj;
240✔
3248

3249
   if (context != NULL)
240✔
3250
      vcode_add_child(context, vu);
240✔
3251

3252
   vcode_select_unit(vu);
240✔
3253
   vcode_select_block(emit_block());
240✔
3254
   emit_debug_info(&(obj->loc));
240✔
3255

3256
   return vu;
240✔
3257
}
3258

3259
vcode_unit_t emit_thunk(ident_t name, object_t *obj, vcode_unit_t context)
11,156✔
3260
{
3261
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
11,156✔
3262
   vu->kind     = VCODE_UNIT_THUNK;
11,156✔
3263
   vu->name     = name;
11,156✔
3264
   vu->context  = context;
11,156✔
3265
   vu->depth    = vcode_unit_calc_depth(vu);
11,156✔
3266
   vu->result   = VCODE_INVALID_TYPE;
11,156✔
3267
   vu->depth    = vcode_unit_calc_depth(vu);
11,156✔
3268
   vu->object   = obj;
11,156✔
3269

3270
   if (context != NULL)
11,156✔
3271
      vcode_add_child(context, vu);
286✔
3272

3273
   vcode_select_unit(vu);
11,156✔
3274
   vcode_select_block(emit_block());
11,156✔
3275

3276
   return vu;
11,156✔
3277
}
3278

3279
void emit_assert(vcode_reg_t value, vcode_reg_t message, vcode_reg_t length,
14,573✔
3280
                 vcode_reg_t severity, vcode_reg_t locus, vcode_reg_t hint_left,
3281
                 vcode_reg_t hint_right)
3282
{
3283
   int64_t value_const;
14,573✔
3284
   if (vcode_reg_const(value, &value_const) && value_const != 0) {
14,573✔
3285
      emit_comment("Always true assertion on r%d", value);
30✔
3286
      return;
30✔
3287
   }
3288

3289
   op_t *op = vcode_add_op(VCODE_OP_ASSERT);
14,543✔
3290
   vcode_add_arg(op, value);
14,543✔
3291
   vcode_add_arg(op, severity);
14,543✔
3292
   vcode_add_arg(op, message);
14,543✔
3293
   vcode_add_arg(op, length);
14,543✔
3294
   vcode_add_arg(op, locus);
14,543✔
3295

3296
   if (hint_left != VCODE_INVALID_REG) {
14,543✔
3297
      vcode_add_arg(op, hint_left);
6,044✔
3298
      vcode_add_arg(op, hint_right);
6,044✔
3299

3300
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_left)),
6,044✔
3301
                   "left hint must be scalar");
3302
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_right)),
6,044✔
3303
                   "right hint must be scalar");
3304
   }
3305

3306
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
14,543✔
3307
                "value parameter to assert is not bool");
3308
   VCODE_ASSERT(message == VCODE_INVALID_REG
14,543✔
3309
                || vcode_reg_kind(message) == VCODE_TYPE_POINTER,
3310
                "message parameter to assert is not a pointer");
3311
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
14,543✔
3312
                "value parameter to assert is not bool");
3313
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
14,543✔
3314
                "locus argument to report must be a debug locus");
3315
}
3316

3317
void emit_report(vcode_reg_t message, vcode_reg_t length, vcode_reg_t severity,
2,065✔
3318
                 vcode_reg_t locus)
3319
{
3320
   op_t *op = vcode_add_op(VCODE_OP_REPORT);
2,065✔
3321
   vcode_add_arg(op, severity);
2,065✔
3322
   vcode_add_arg(op, message);
2,065✔
3323
   vcode_add_arg(op, length);
2,065✔
3324
   vcode_add_arg(op, locus);
2,065✔
3325

3326
   VCODE_ASSERT(vcode_reg_kind(message) == VCODE_TYPE_POINTER,
2,065✔
3327
                "message parameter to report is not a pointer");
3328
   VCODE_ASSERT(vtype_eq(vtype_pointed(vcode_reg_type(message)), vtype_char()),
2,065✔
3329
                "message parameter to report is not a character pointer");
3330
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,065✔
3331
                "locus argument to report must be a debug locus");
3332
}
2,065✔
3333

3334
vcode_reg_t emit_cmp(vcode_cmp_t cmp, vcode_reg_t lhs, vcode_reg_t rhs)
34,333✔
3335
{
3336
   if (lhs == rhs) {
34,333✔
3337
      if (cmp == VCODE_CMP_EQ)
398✔
3338
         return emit_const(vtype_bool(), 1);
242✔
3339
      else if (cmp == VCODE_CMP_NEQ)
156✔
UNCOV
3340
         return emit_const(vtype_bool(), 0);
×
3341
      else if (cmp == VCODE_CMP_LEQ || cmp == VCODE_CMP_GEQ)
156✔
UNCOV
3342
         return emit_const(vtype_bool(), 1);
×
3343
      else if (cmp == VCODE_CMP_LT || cmp == VCODE_CMP_GT)
156✔
3344
         return emit_const(vtype_bool(), 0);
156✔
3345
   }
3346

3347
   int64_t lconst, rconst;
33,935✔
3348
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)) {
33,935✔
3349
      switch (cmp) {
328✔
3350
      case VCODE_CMP_EQ:
312✔
3351
         return emit_const(vtype_bool(), lconst == rconst);
312✔
3352
      case VCODE_CMP_NEQ:
3✔
3353
         return emit_const(vtype_bool(), lconst != rconst);
3✔
3354
      case VCODE_CMP_LT:
6✔
3355
         return emit_const(vtype_bool(), lconst < rconst);
6✔
3356
      case VCODE_CMP_GT:
7✔
3357
         return emit_const(vtype_bool(), lconst > rconst);
7✔
UNCOV
3358
      case VCODE_CMP_LEQ:
×
UNCOV
3359
         return emit_const(vtype_bool(), lconst <= rconst);
×
UNCOV
3360
      case VCODE_CMP_GEQ:
×
UNCOV
3361
         return emit_const(vtype_bool(), lconst >= rconst);
×
UNCOV
3362
      default:
×
3363
         fatal_trace("cannot fold comparison %d", cmp);
3364
      }
3365
   }
3366

3367
   // Reuse any previous operation in this block with the same arguments
3368
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CMP) {
658,226✔
3369
      if (other->args.count == 2 && other->args.items[0] == lhs
24,168✔
3370
          && other->args.items[1] == rhs && other->cmp == cmp)
2,240✔
3371
         return other->result;
193✔
3372
   }
3373

3374
   op_t *op = vcode_add_op(VCODE_OP_CMP);
33,414✔
3375
   vcode_add_arg(op, lhs);
33,414✔
3376
   vcode_add_arg(op, rhs);
33,414✔
3377
   op->cmp    = cmp;
33,414✔
3378
   op->result = vcode_add_reg(vtype_bool());
33,414✔
3379

3380
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vcode_reg_type(rhs)),
33,414✔
3381
                "arguments to cmp are not the same type");
3382

3383
   return op->result;
33,414✔
3384
}
3385

3386
vcode_reg_t emit_fcall(ident_t func, vcode_type_t type, vcode_type_t bounds,
34,755✔
3387
                       const vcode_reg_t *args, int nargs)
3388
{
3389
   op_t *o = vcode_add_op(VCODE_OP_FCALL);
34,755✔
3390
   o->func = func;
34,755✔
3391
   o->type = type;
34,755✔
3392
   for (int i = 0; i < nargs; i++)
122,111✔
3393
      vcode_add_arg(o, args[i]);
87,356✔
3394

3395
   for (int i = 0; i < nargs; i++)
122,111✔
3396
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
87,356✔
3397
                   "invalid argument to function");
3398

3399
   if (type == VCODE_INVALID_TYPE)
34,755✔
3400
      return (o->result = VCODE_INVALID_REG);
5,483✔
3401
   else {
3402
      o->result = vcode_add_reg(type);
29,272✔
3403

3404
      reg_t *rr = vcode_reg_data(o->result);
29,272✔
3405
      rr->bounds = bounds;
29,272✔
3406

3407
      return o->result;
29,272✔
3408
   }
3409
}
3410

3411
void emit_pcall(ident_t func, const vcode_reg_t *args, int nargs,
843✔
3412
                vcode_block_t resume_bb)
3413
{
3414
   op_t *o = vcode_add_op(VCODE_OP_PCALL);
843✔
3415
   o->func = func;
843✔
3416
   for (int i = 0; i < nargs; i++)
2,845✔
3417
      vcode_add_arg(o, args[i]);
2,002✔
3418

3419
   vcode_block_array_add(&(o->targets), resume_bb);
843✔
3420

3421
   for (int i = 0; i < nargs; i++)
2,845✔
3422
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
2,002✔
3423
                   "invalid argument to procedure");
3424

3425
   VCODE_ASSERT(nargs > 0 && vcode_reg_kind(args[0]) == VCODE_TYPE_CONTEXT,
843✔
3426
                "first argument to VHDL procedure must be context pointer");
3427
}
843✔
3428

3429
vcode_reg_t emit_syscall(ident_t func, vcode_type_t type, vcode_type_t bounds,
×
3430
                         vcode_reg_t locus, const vcode_reg_t *args, int nargs)
3431
{
UNCOV
3432
   op_t *o = vcode_add_op(VCODE_OP_SYSCALL);
×
3433
   o->func = func;
×
UNCOV
3434
   o->type = type;
×
UNCOV
3435
   vcode_add_arg(o, locus);
×
3436
   for (int i = 0; i < nargs; i++)
×
3437
      vcode_add_arg(o, args[i]);
×
3438

3439
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
×
3440
                "locus argument to syscall must be a debug locus");
3441

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

3445
   if (type == VCODE_INVALID_TYPE)
×
UNCOV
3446
      return (o->result = VCODE_INVALID_REG);
×
3447
   else {
UNCOV
3448
      o->result = vcode_add_reg(type);
×
3449

UNCOV
3450
      reg_t *rr = vcode_reg_data(o->result);
×
UNCOV
3451
      rr->bounds = bounds;
×
3452

UNCOV
3453
      return o->result;
×
3454
   }
3455
}
3456

3457
vcode_reg_t emit_alloc(vcode_type_t type, vcode_type_t bounds,
7,261✔
3458
                       vcode_reg_t count)
3459
{
3460
   op_t *op = vcode_add_op(VCODE_OP_ALLOC);
7,261✔
3461
   op->type    = type;
7,261✔
3462
   op->result  = vcode_add_reg(vtype_pointer(type));
7,261✔
3463
   vcode_add_arg(op, count);
7,261✔
3464

3465
   const vtype_kind_t tkind = vtype_kind(type);
7,261✔
3466
   VCODE_ASSERT(tkind != VCODE_TYPE_CARRAY && tkind != VCODE_TYPE_UARRAY,
7,261✔
3467
                "alloca element type cannot be array");
3468
   VCODE_ASSERT(count != VCODE_INVALID_REG,
7,261✔
3469
                "alloca must have valid count argument");
3470

3471
   reg_t *r = vcode_reg_data(op->result);
7,261✔
3472
   r->bounds = bounds;
7,261✔
3473

3474
   return op->result;
7,261✔
3475
}
3476

3477
vcode_reg_t emit_const(vcode_type_t type, int64_t value)
1,434,436✔
3478
{
3479
   // Reuse any previous constant in this block with the same type and value
3480
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST) {
32,700,083✔
3481
      if (other->value == value && vtype_eq(type, other->type))
11,563,577✔
3482
         return other->result;
986,871✔
3483
   }
3484

3485
   op_t *op = vcode_add_op(VCODE_OP_CONST);
447,565✔
3486
   op->value  = value;
447,565✔
3487
   op->type   = type;
447,565✔
3488
   op->result = vcode_add_reg(type);
447,565✔
3489

3490
   vtype_kind_t type_kind = vtype_kind(type);
447,565✔
3491
   VCODE_ASSERT(type_kind == VCODE_TYPE_INT || type_kind == VCODE_TYPE_OFFSET,
447,565✔
3492
                "constant must have integer or offset type");
3493

3494
   reg_t *r = vcode_reg_data(op->result);
447,565✔
3495
   r->bounds = vtype_int(value, value);
447,565✔
3496

3497
   return op->result;
447,565✔
3498
}
3499

3500
vcode_reg_t emit_const_real(vcode_type_t type, double value)
66,690✔
3501
{
3502
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REAL) {
1,955,523✔
3503
      if (other->real == value && other->type == type)
907,903✔
3504
         return other->result;
25,322✔
3505
   }
3506

3507
   op_t *op = vcode_add_op(VCODE_OP_CONST_REAL);
41,368✔
3508
   op->real   = value;
41,368✔
3509
   op->type   = type;
41,368✔
3510
   op->result = vcode_add_reg(op->type);
41,368✔
3511

3512
   reg_t *r = vcode_reg_data(op->result);
41,368✔
3513
   r->bounds = vtype_real(value, value);
41,368✔
3514

3515
   return op->result;
41,368✔
3516
}
3517

3518
vcode_reg_t emit_const_array(vcode_type_t type, vcode_reg_t *values, int num)
37,156✔
3519
{
3520
   vtype_kind_t kind = vtype_kind(type);
37,156✔
3521

3522
   // Reuse any previous operation in this block with the same arguments
3523
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_ARRAY) {
1,908,090✔
3524
      if (other->args.count != num)
150,778✔
3525
         continue;
89,858✔
3526
      else if (!vtype_eq(vcode_reg_type(other->result), type))
60,920✔
3527
         continue;
2,298✔
3528

3529
      bool match = true;
3530
      for (int i = 0; match && i < num; i++) {
421,478✔
3531
         if (other->args.items[i] != values[i])
362,856✔
3532
            match = false;
51,552✔
3533
      }
3534

3535
      if (match) return other->result;
58,622✔
3536
   }
3537

3538
   op_t *op = vcode_add_op(VCODE_OP_CONST_ARRAY);
30,086✔
3539
   op->result = vcode_add_reg(type);
30,086✔
3540

3541
   for (int i = 0; i < num; i++)
1,667,353✔
3542
      vcode_add_arg(op, values[i]);
1,637,267✔
3543

3544
   VCODE_ASSERT(kind == VCODE_TYPE_CARRAY,
30,086✔
3545
                "constant array must have constrained array type");
3546
   VCODE_ASSERT(vtype_size(type) == num, "expected %d elements but have %d",
30,086✔
3547
                vtype_size(type), num);
3548

3549
#ifdef DEBUG
3550
   vcode_type_t elem = vtype_elem(type);
30,086✔
3551
   for (int i = 0; i < num; i++) {
1,667,353✔
3552
      VCODE_ASSERT(vtype_eq(vcode_reg_type(values[i]), elem),
1,637,267✔
3553
                   "wrong element type for item %d", i);
3554
      vcode_assert_const(values[i], "array");
1,637,267✔
3555
   }
3556
#endif
3557

3558
   reg_t *r = vcode_reg_data(op->result);
30,086✔
3559
   r->bounds = vtype_elem(type);
30,086✔
3560

3561
   return op->result;
30,086✔
3562
}
3563

3564
vcode_reg_t emit_const_rep(vcode_type_t type, vcode_reg_t value, int rep)
499✔
3565
{
3566
   // Reuse any previous operation in this block with the same arguments
3567
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REP) {
8,308✔
3568
      if (other->args.items[0] == value && other->value == rep)
607✔
3569
         return other->result;
198✔
3570
   }
3571

3572
   op_t *op = vcode_add_op(VCODE_OP_CONST_REP);
301✔
3573
   op->value = rep;
301✔
3574
   vcode_add_arg(op, value);
301✔
3575

3576
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CARRAY,
301✔
3577
                "constant array must have constrained array type");
3578
   VCODE_ASSERT(rep >= 0, "repeat count must be non-negative");
301✔
3579

3580
   DEBUG_ONLY(vcode_assert_const(value, "repeat"));
301✔
3581

3582
   op->result = vcode_add_reg(type);
301✔
3583

3584
   reg_t *r = vcode_reg_data(op->result);
301✔
3585
   r->bounds = vtype_bounds(type);
301✔
3586

3587
   return op->result;
301✔
3588
}
3589

3590
vcode_reg_t emit_const_record(vcode_type_t type, vcode_reg_t *values, int num)
2,512✔
3591
{
3592
   // Reuse any previous constant in this block with the same type and value
3593
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_RECORD) {
38,687✔
3594
      if (other->args.count == num && vtype_eq(type, other->type)) {
1,534✔
3595
         bool same_regs = true;
3596
         for (int i = 0; same_regs && i < num; i++)
2,504✔
3597
            same_regs = other->args.items[i] == values[i];
1,454✔
3598

3599
         if (same_regs)
1,050✔
3600
            return other->result;
187✔
3601
      }
3602
   }
3603

3604
   op_t *op = vcode_add_op(VCODE_OP_CONST_RECORD);
2,325✔
3605
   op->type   = type;
2,325✔
3606
   op->result = vcode_add_reg(type);
2,325✔
3607

3608
   for (int i = 0; i < num; i++)
8,287✔
3609
      vcode_add_arg(op, values[i]);
5,962✔
3610

3611
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_RECORD,
2,325✔
3612
                "constant record must have record type");
3613

3614
   VCODE_ASSERT(vtype_fields(type) == num, "expected %d fields but have %d",
2,325✔
3615
                vtype_fields(type), num);
3616

3617
#ifdef DEBUG
3618
   for (int i = 0; i < num; i++) {
8,287✔
3619
      VCODE_ASSERT(vtype_eq(vtype_field(type, i), vcode_reg_type(values[i])),
5,962✔
3620
                   "wrong type for field %d", i);
3621
      vcode_assert_const(values[i], "record");
5,962✔
3622
   }
3623
#endif
3624

3625
   return op->result;
2,325✔
3626
}
3627

3628
vcode_reg_t emit_address_of(vcode_reg_t value)
38,716✔
3629
{
3630
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ADDRESS_OF) {
1,981,989✔
3631
      if (other->args.items[0] == value)
151,778✔
3632
         return other->result;
7,065✔
3633
   }
3634

3635
   op_t *op = vcode_add_op(VCODE_OP_ADDRESS_OF);
31,651✔
3636
   vcode_add_arg(op, value);
31,651✔
3637

3638
   vcode_type_t type = vcode_reg_type(value);
31,651✔
3639
   VCODE_ASSERT(vtype_is_composite(type),
31,651✔
3640
                "address of argument must be record or array");
3641

3642
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
31,651✔
3643
      vcode_type_t elem = vtype_elem(type);
29,866✔
3644
      op->result = vcode_add_reg(vtype_pointer(elem));
29,866✔
3645

3646
      reg_t *rr = vcode_reg_data(op->result);
29,866✔
3647
      rr->bounds = elem;
29,866✔
3648

3649
      return op->result;
29,866✔
3650
   }
3651
   else
3652
      return (op->result = vcode_add_reg(vtype_pointer(type)));
1,785✔
3653
}
3654

3655
void emit_wait(vcode_block_t target)
12,756✔
3656
{
3657
   op_t *op = vcode_add_op(VCODE_OP_WAIT);
12,756✔
3658
   vcode_add_target(op, target);
12,756✔
3659
}
12,756✔
3660

3661
void emit_jump(vcode_block_t target)
35,888✔
3662
{
3663
   op_t *op = vcode_add_op(VCODE_OP_JUMP);
35,888✔
3664
   vcode_add_target(op, target);
35,888✔
3665

3666
   VCODE_ASSERT(target != VCODE_INVALID_BLOCK, "invalid jump target");
35,888✔
3667
}
35,888✔
3668

3669
vcode_var_t emit_var(vcode_type_t type, vcode_type_t bounds, ident_t name,
70,128✔
3670
                     vcode_var_flags_t flags)
3671
{
3672
   assert(active_unit != NULL);
70,128✔
3673

3674
   vcode_var_t var = active_unit->vars.count;
70,128✔
3675
   var_t *v = var_array_alloc(&(active_unit->vars));
70,128✔
3676
   memset(v, '\0', sizeof(var_t));
70,128✔
3677
   v->type     = type;
70,128✔
3678
   v->bounds   = bounds;
70,128✔
3679
   v->name     = name;
70,128✔
3680
   v->flags    = flags;
70,128✔
3681

3682
   return var;
70,128✔
3683
}
3684

3685
vcode_reg_t emit_param(vcode_type_t type, vcode_type_t bounds, ident_t name)
32,159✔
3686
{
3687
   assert(active_unit != NULL);
32,159✔
3688

3689
   param_t *p = param_array_alloc(&(active_unit->params));
32,159✔
3690
   memset(p, '\0', sizeof(param_t));
32,159✔
3691
   p->type   = type;
32,159✔
3692
   p->bounds = bounds;
32,159✔
3693
   p->name   = name;
32,159✔
3694
   p->reg    = vcode_add_reg(type);
32,159✔
3695

3696
   reg_t *rr = vcode_reg_data(p->reg);
32,159✔
3697
   rr->bounds = bounds;
32,159✔
3698

3699
   return p->reg;
32,159✔
3700
}
3701

3702
vcode_reg_t emit_load(vcode_var_t var)
59,700✔
3703
{
3704
   // Try scanning backwards through the block for another load or store to
3705
   // this variable
3706
   enum { EAGER, CONSERVATIVE, UNSAFE } state = EAGER;
59,700✔
3707
   vcode_reg_t fold = VCODE_INVALID_REG;
59,700✔
3708
   VCODE_FOR_EACH_OP(other) {
857,389✔
3709
      switch (state) {
813,720✔
3710
      case EAGER:
321,532✔
3711
         if (other->kind == VCODE_OP_LOAD && other->address == var)
321,532✔
3712
            return other->result;
3,591✔
3713
         else if (other->kind == VCODE_OP_STORE && other->address == var)
317,941✔
3714
            return other->args.items[0];
12,440✔
3715
         else if (other->kind == VCODE_OP_FCALL
305,501✔
3716
                  || other->kind == VCODE_OP_PCALL
305,501✔
3717
                  || other->kind == VCODE_OP_FILE_READ
3718
                  || other->kind == VCODE_OP_FILE_OPEN
3719
                  || other->kind == VCODE_OP_STORE_INDIRECT
3720
                  || other->kind == VCODE_OP_DEALLOCATE)
3721
            state = CONSERVATIVE;   // May write to variable
9,876✔
3722
         break;
3723

3724
      case CONSERVATIVE:
461,505✔
3725
         if (other->kind == VCODE_OP_LOAD && other->address == var
461,505✔
3726
             && fold == VCODE_INVALID_REG)
4,567✔
3727
            fold = other->result;
3,688✔
3728
         else if (other->kind == VCODE_OP_STORE && other->address == var
457,817✔
3729
                  && fold == VCODE_INVALID_REG)
2,407✔
3730
            fold = other->args.items[0];
2,265✔
3731
         else if (other->kind == VCODE_OP_INDEX && other->address == var)
455,552✔
3732
            state = UNSAFE;
3733
         else if (other->kind == VCODE_OP_CONTEXT_UPREF && other->hops == 0)
454,181✔
3734
            state = UNSAFE;   // Nested call captures variables
111✔
3735
         break;
3736

3737
      case UNSAFE:
3738
         break;
3739
      }
3740
   }
3741

3742
   if (fold != VCODE_INVALID_REG && state != UNSAFE)
43,669✔
3743
      return fold;
3744

3745
   var_t *v = vcode_var_data(var);
38,098✔
3746

3747
   op_t *op = vcode_add_op(VCODE_OP_LOAD);
38,098✔
3748
   op->address = var;
38,098✔
3749
   op->result  = vcode_add_reg(v->type);
38,098✔
3750

3751
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot load non-scalar type");
38,098✔
3752

3753
   reg_t *r = vcode_reg_data(op->result);
38,098✔
3754
   r->bounds = v->bounds;
38,098✔
3755

3756
   return op->result;
38,098✔
3757
}
3758

3759
vcode_reg_t emit_load_indirect(vcode_reg_t reg)
92,413✔
3760
{
3761
   VCODE_FOR_EACH_OP(other) {
1,097,308✔
3762
      if (other->kind == VCODE_OP_LOAD_INDIRECT
1,034,703✔
3763
          && other->args.items[0] == reg) {
148,770✔
3764
         return other->result;
9,869✔
3765
      }
3766
      else if (other->kind == VCODE_OP_FCALL
1,024,834✔
3767
               || other->kind == VCODE_OP_PCALL
1,024,834✔
3768
               || other->kind == VCODE_OP_STORE
3769
               || other->kind == VCODE_OP_STORE_INDIRECT
3770
               || other->kind == VCODE_OP_MEMSET
3771
               || other->kind == VCODE_OP_COPY
3772
               || other->kind == VCODE_OP_FILE_READ)
3773
         break;   // May write to this pointer
3774
   }
3775

3776
   op_t *op = vcode_add_op(VCODE_OP_LOAD_INDIRECT);
82,544✔
3777
   vcode_add_arg(op, reg);
82,544✔
3778

3779
   vcode_type_t rtype = vcode_reg_type(reg);
82,544✔
3780

3781
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
82,544✔
3782
                "load indirect with non-pointer argument");
3783

3784
   vcode_type_t deref = vtype_pointed(rtype);
82,544✔
3785
   op->result = vcode_add_reg(deref);
82,544✔
3786

3787
   VCODE_ASSERT(vtype_is_scalar(deref), "cannot load non-scalar type");
82,544✔
3788

3789
   vcode_reg_data(op->result)->bounds = vcode_reg_data(reg)->bounds;
82,544✔
3790

3791
   return op->result;
82,544✔
3792
}
3793

3794
void emit_store(vcode_reg_t reg, vcode_var_t var)
74,892✔
3795
{
3796
   // Any previous store to this variable in this block is dead
3797
   VCODE_FOR_EACH_OP(other) {
1,593,551✔
3798
      if (other->kind == VCODE_OP_STORE && other->address == var) {
1,533,108✔
3799
         other->kind = VCODE_OP_COMMENT;
291✔
3800
         other->comment =
582✔
3801
            xasprintf("Dead store to %s", istr(vcode_var_name(var)));
291✔
3802
         vcode_reg_array_resize(&(other->args), 0, VCODE_INVALID_REG);
291✔
3803
      }
3804
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
1,532,817✔
3805
         break;   // Needs to get variable for display
3806
      else if ((other->kind == VCODE_OP_INDEX || other->kind == VCODE_OP_LOAD)
1,526,458✔
3807
               && other->address == var)
37,087✔
3808
         break;   // Previous value may be used
3809
   }
3810

3811
   var_t *v = vcode_var_data(var);
74,892✔
3812
   reg_t *r = vcode_reg_data(reg);
74,892✔
3813

3814
   op_t *op = vcode_add_op(VCODE_OP_STORE);
74,892✔
3815
   vcode_add_arg(op, reg);
74,892✔
3816
   op->address = var;
74,892✔
3817

3818
   VCODE_ASSERT(vtype_eq(v->type, r->type),
74,892✔
3819
                "variable and stored value do not have same type");
3820
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot store non-scalar type");
74,892✔
3821
}
74,892✔
3822

3823
void emit_store_indirect(vcode_reg_t reg, vcode_reg_t ptr)
14,841✔
3824
{
3825
   reg_t *p = vcode_reg_data(ptr);
14,841✔
3826
   reg_t *r = vcode_reg_data(reg);
14,841✔
3827

3828
   op_t *op = vcode_add_op(VCODE_OP_STORE_INDIRECT);
14,841✔
3829
   vcode_add_arg(op, reg);
14,841✔
3830
   vcode_add_arg(op, ptr);
14,841✔
3831

3832
   VCODE_ASSERT(vtype_kind(p->type) == VCODE_TYPE_POINTER,
14,841✔
3833
                "store indirect target is not a pointer");
3834
   VCODE_ASSERT(vtype_eq(vtype_pointed(p->type), r->type),
14,841✔
3835
                "pointer and stored value do not have same type");
3836
   VCODE_ASSERT(vtype_is_scalar(r->type), "cannot store non-scalar type");
14,841✔
3837
}
14,841✔
3838

3839
static vcode_reg_t emit_arith(vcode_op_t kind, vcode_reg_t lhs, vcode_reg_t rhs,
66,938✔
3840
                              vcode_reg_t locus)
3841
{
3842
   // Reuse any previous operation in this block with the same arguments
3843
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
1,562,715✔
3844
      if (other->args.items[0] == lhs && other->args.items[1] == rhs)
77,340✔
3845
         return other->result;
5,871✔
3846
   }
3847

3848
   op_t *op = vcode_add_op(kind);
61,067✔
3849
   vcode_add_arg(op, lhs);
61,067✔
3850
   vcode_add_arg(op, rhs);
61,067✔
3851
   if (locus != VCODE_INVALID_REG)
61,067✔
3852
      vcode_add_arg(op, locus);
6,363✔
3853

3854
   op->result = vcode_add_reg(vcode_reg_type(lhs));
61,067✔
3855

3856
   vcode_type_t lhs_type = vcode_reg_type(lhs);
61,067✔
3857
   vcode_type_t rhs_type = vcode_reg_type(rhs);
61,067✔
3858

3859
   VCODE_ASSERT(vtype_eq(lhs_type, rhs_type),
61,067✔
3860
                "arguments to %s are not the same type", vcode_op_string(kind));
3861

3862
   return op->result;
61,067✔
3863
}
3864

3865
static vcode_reg_t emit_mul_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
48,240✔
3866
                               vcode_reg_t locus)
3867
{
3868
   int64_t lconst, rconst;
48,240✔
3869
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
48,240✔
3870
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
48,240✔
3871
   if (l_is_const && r_is_const)
48,240✔
3872
      return emit_const(vcode_reg_type(lhs), lconst * rconst);
22,058✔
3873
   else if (r_is_const && rconst == 1)
26,182✔
3874
      return lhs;
3875
   else if (l_is_const && lconst == 1)
4,989✔
3876
      return rhs;
3877
   else if ((r_is_const && rconst == 0) || (l_is_const && lconst == 0))
4,487✔
3878
      return emit_const(vcode_reg_type(lhs), 0);
54✔
3879

3880
   reg_t *lhs_r = vcode_reg_data(lhs);
4,433✔
3881
   reg_t *rhs_r = vcode_reg_data(rhs);
4,433✔
3882

3883
   vtype_t *bl = vcode_type_data(lhs_r->bounds);
4,433✔
3884
   vtype_t *br = vcode_type_data(rhs_r->bounds);
4,433✔
3885

3886
   vcode_type_t vbounds;
4,433✔
3887
   if (vcode_reg_kind(lhs) == VCODE_TYPE_REAL) {
4,433✔
3888
      const double ll = bl->rlow * br->rlow;
556✔
3889
      const double lh = bl->rlow * br->rhigh;
556✔
3890
      const double hl = bl->rhigh * br->rlow;
556✔
3891
      const double hh = bl->rhigh * br->rhigh;
556✔
3892

3893
      double min = MIN(MIN(ll, lh), MIN(hl, hh));
1,301✔
3894
      double max = MAX(MAX(ll, lh), MAX(hl, hh));
1,387✔
3895

3896
      vbounds = vtype_real(min, max);
556✔
3897
   }
3898
   else {
3899
      const int64_t ll = smul64(bl->low, br->low);
3,877✔
3900
      const int64_t lh = smul64(bl->low, br->high);
3,877✔
3901
      const int64_t hl = smul64(bl->high, br->low);
3,877✔
3902
      const int64_t hh = smul64(bl->high, br->high);
3,877✔
3903

3904
      int64_t min = MIN(MIN(ll, lh), MIN(hl, hh));
3,877✔
3905
      int64_t max = MAX(MAX(ll, lh), MAX(hl, hh));
3,877✔
3906

3907
      vtype_repr_t repr = vtype_repr(lhs_r->type);
3,877✔
3908
      if (op == VCODE_OP_TRAP_MUL && vtype_clamp_to_repr(repr, &min, &max)) {
3,877✔
3909
         op = VCODE_OP_MUL;   // Cannot overflow
1,001✔
3910
         locus = VCODE_INVALID_REG;
1,001✔
3911
      }
3912

3913
      vbounds = vtype_int(min, max);
3,877✔
3914
   }
3915

3916
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
4,433✔
3917

3918
   if (vbounds != VCODE_INVALID_TYPE)
4,433✔
3919
      vcode_reg_data(reg)->bounds = vbounds;
4,433✔
3920

3921
   return reg;
3922
}
3923

3924
vcode_reg_t emit_mul(vcode_reg_t lhs, vcode_reg_t rhs)
45,448✔
3925
{
3926
   return emit_mul_op(VCODE_OP_MUL, lhs, rhs, VCODE_INVALID_REG);
45,448✔
3927
}
3928

3929
vcode_reg_t emit_trap_mul(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
2,792✔
3930
{
3931
   vcode_reg_t result = emit_mul_op(VCODE_OP_TRAP_MUL, lhs, rhs, locus);
2,792✔
3932

3933
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
2,792✔
3934
                "trapping add may only be used with integer types");
3935

3936
   return result;
2,792✔
3937
}
3938

3939
vcode_reg_t emit_div(vcode_reg_t lhs, vcode_reg_t rhs)
1,732✔
3940
{
3941
   int64_t lconst, rconst;
1,732✔
3942
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
1,732✔
3943
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
1,732✔
3944
   if (l_is_const && r_is_const && rconst != 0)
1,732✔
3945
      return emit_const(vcode_reg_type(lhs), lconst / rconst);
30✔
3946
   else if (r_is_const && rconst == 1)
1,702✔
3947
      return lhs;
3948

3949
   vcode_reg_t reg = emit_arith(VCODE_OP_DIV, lhs, rhs, VCODE_INVALID_REG);
1,699✔
3950

3951
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
1,699✔
3952

3953
   if (bl->kind == VCODE_TYPE_INT && r_is_const && rconst != 0) {
1,699✔
3954
      reg_t *rr = vcode_reg_data(reg);
1,306✔
3955
      rr->bounds = vtype_int(bl->low / rconst, bl->high / rconst);
1,306✔
3956
   }
3957
   else if (bl->kind == VCODE_TYPE_REAL) {
393✔
3958
      reg_t *rr = vcode_reg_data(reg);
317✔
3959
      rr->bounds = vtype_real(-INFINITY, INFINITY);
317✔
3960
   }
3961

3962
   return reg;
3963
}
3964

3965
vcode_reg_t emit_exp(vcode_reg_t lhs, vcode_reg_t rhs)
141✔
3966
{
3967
   return emit_arith(VCODE_OP_EXP, lhs, rhs, VCODE_INVALID_REG);
141✔
3968
}
3969

3970
vcode_reg_t emit_trap_exp(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
411✔
3971
{
3972
   int64_t rconst;
411✔
3973
   if (vcode_reg_const(rhs, &rconst)) {
411✔
3974
      if (rconst == 0)
77✔
3975
         return emit_const(vcode_reg_type(lhs), 1);
31✔
3976
      else if (rconst == 1)
46✔
3977
         return lhs;
3978
   }
3979

3980
   vcode_reg_t result = emit_arith(VCODE_OP_TRAP_EXP, lhs, rhs, locus);
379✔
3981

3982
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
379✔
3983
                "trapping exp may only be used with integer types");
3984

3985
   return result;
3986
}
3987

3988
vcode_reg_t emit_mod(vcode_reg_t lhs, vcode_reg_t rhs)
199✔
3989
{
3990
   int64_t lconst, rconst;
199✔
3991
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
199✔
3992
       && lconst > 0 && rconst > 0)
15✔
3993
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
3✔
3994

3995
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
196✔
3996
   vtype_t *br = vcode_type_data(vcode_reg_data(rhs)->bounds);
196✔
3997

3998
   if (bl->low >= 0 && br->low >= 0) {
196✔
3999
      // If both arguments are non-negative then rem is equivalent and
4000
      // cheaper to compute
4001
      vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
66✔
4002

4003
      reg_t *rr = vcode_reg_data(reg);
66✔
4004
      rr->bounds = vtype_int(0, MAX(0, br->high - 1));
66✔
4005

4006
      return reg;
66✔
4007
   }
4008
   else
4009
      return emit_arith(VCODE_OP_MOD, lhs, rhs, VCODE_INVALID_REG);
130✔
4010
}
4011

4012
vcode_reg_t emit_rem(vcode_reg_t lhs, vcode_reg_t rhs)
846✔
4013
{
4014
   int64_t lconst, rconst;
846✔
4015
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
846✔
4016
       && lconst > 0 && rconst > 0)
2✔
UNCOV
4017
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
×
4018

4019
   vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
846✔
4020

4021
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
846✔
4022
   vtype_t *br = vcode_type_data(vcode_reg_data(rhs)->bounds);
846✔
4023

4024
   if (bl->low >= 0 && br->low >= 0) {
846✔
4025
      reg_t *rr = vcode_reg_data(reg);
462✔
4026
      rr->bounds = vtype_int(0, br->high - 1);
462✔
4027
   }
4028

4029
   return reg;
4030
}
4031

4032
static vcode_reg_t emit_add_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
48,225✔
4033
                               vcode_reg_t locus)
4034
{
4035
   int64_t lconst, rconst;
48,225✔
4036
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
48,225✔
4037
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
48,225✔
4038
   if (l_is_const && r_is_const)
48,225✔
4039
      return emit_const(vcode_reg_type(lhs), lconst + rconst);
11,927✔
4040
   else if (r_is_const && rconst == 0)
36,298✔
4041
      return lhs;
4042
   else if (l_is_const && lconst == 0)
36,170✔
4043
      return rhs;
4044

4045
   vcode_type_t vbounds = VCODE_INVALID_TYPE;
19,922✔
4046
   if (vcode_reg_kind(lhs) != VCODE_TYPE_REAL) {
19,922✔
4047
      reg_t *lhs_r = vcode_reg_data(lhs);
19,598✔
4048
      reg_t *rhs_r = vcode_reg_data(rhs);
19,598✔
4049

4050
      vtype_t *bl = vcode_type_data(lhs_r->bounds);
19,598✔
4051
      vtype_t *br = vcode_type_data(rhs_r->bounds);
19,598✔
4052

4053
      int64_t rbl = sadd64(bl->low, br->low);
19,598✔
4054
      int64_t rbh = sadd64(bl->high, br->high);
19,598✔
4055

4056
      vtype_repr_t repr = vtype_repr(lhs_r->type);
19,598✔
4057
      if (op == VCODE_OP_TRAP_ADD && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
19,598✔
4058
         op = VCODE_OP_ADD;   // Cannot overflow
1,963✔
4059
         locus = VCODE_INVALID_REG;
1,963✔
4060
      }
4061

4062
      vbounds = vtype_int(rbl, rbh);
19,598✔
4063
   }
4064

4065
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
19,922✔
4066

4067
   if (vbounds != VCODE_INVALID_TYPE)
19,922✔
4068
      vcode_reg_data(reg)->bounds = vbounds;
19,598✔
4069

4070
   return reg;
4071
}
4072

4073
vcode_reg_t emit_add(vcode_reg_t lhs, vcode_reg_t rhs)
42,026✔
4074
{
4075
   return emit_add_op(VCODE_OP_ADD, lhs, rhs, VCODE_INVALID_REG);
42,026✔
4076
}
4077

4078
vcode_reg_t emit_trap_add(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
6,199✔
4079
{
4080
   vcode_reg_t result = emit_add_op(VCODE_OP_TRAP_ADD, lhs, rhs, locus);
6,199✔
4081

4082
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
6,199✔
4083
                "trapping add may only be used with integer types");
4084

4085
   return result;
6,199✔
4086
}
4087

4088
static vcode_reg_t emit_sub_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
46,310✔
4089
                               vcode_reg_t locus)
4090
{
4091
   int64_t lconst, rconst;
46,310✔
4092
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
46,310✔
4093
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
46,310✔
4094
   if (l_is_const && r_is_const)
46,310✔
4095
      return emit_const(vcode_reg_type(lhs), lconst - rconst);
8,229✔
4096
   else if (r_is_const && rconst == 0)
38,081✔
4097
      return lhs;
4098
   else if (l_is_const && lconst == 0)
33,290✔
4099
      return emit_neg(rhs);
825✔
4100

4101
   vcode_type_t vbounds = VCODE_INVALID_TYPE;
32,465✔
4102
   if (vcode_reg_kind(lhs) != VCODE_TYPE_REAL) {
32,465✔
4103
      reg_t *lhs_r = vcode_reg_data(lhs);
32,170✔
4104
      reg_t *rhs_r = vcode_reg_data(rhs);
32,170✔
4105

4106
      vtype_t *bl = vcode_type_data(lhs_r->bounds);
32,170✔
4107
      vtype_t *br = vcode_type_data(rhs_r->bounds);
32,170✔
4108

4109
      int64_t rbl = ssub64(bl->low, br->high);
32,170✔
4110
      int64_t rbh = ssub64(bl->high, br->low);
32,170✔
4111

4112
      vtype_repr_t repr = vtype_repr(lhs_r->type);
32,170✔
4113
      if (op == VCODE_OP_TRAP_SUB && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
32,170✔
4114
         op = VCODE_OP_SUB;   // Cannot overflow
5,080✔
4115
         locus = VCODE_INVALID_REG;
5,080✔
4116
      }
4117

4118
      vbounds = vtype_int(rbl, rbh);
32,170✔
4119
   }
4120

4121
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
32,465✔
4122

4123
   if (vbounds != VCODE_INVALID_TYPE)
32,465✔
4124
      vcode_reg_data(reg)->bounds = vbounds;
32,170✔
4125

4126
   return reg;
4127
}
4128

4129
vcode_reg_t emit_sub(vcode_reg_t lhs, vcode_reg_t rhs)
39,214✔
4130
{
4131
   return emit_sub_op(VCODE_OP_SUB, lhs, rhs, VCODE_INVALID_REG);
39,214✔
4132
}
4133

4134
vcode_reg_t emit_trap_sub(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
7,096✔
4135
{
4136
   vcode_reg_t result = emit_sub_op(VCODE_OP_TRAP_SUB, lhs, rhs, locus);
7,096✔
4137

4138
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
7,096✔
4139
                "trapping sub may only be used with integer types");
4140

4141
   return result;
7,096✔
4142
}
4143

4144
static void vcode_calculate_var_index_type(op_t *op, var_t *var)
70,090✔
4145
{
4146
   switch (vtype_kind(var->type)) {
70,090✔
4147
   case VCODE_TYPE_CARRAY:
21,672✔
4148
      op->type = vtype_pointer(vtype_elem(var->type));
21,672✔
4149
      op->result = vcode_add_reg(op->type);
21,672✔
4150
      vcode_reg_data(op->result)->bounds = vtype_bounds(var->type);
21,672✔
4151
      break;
21,672✔
4152

4153
   case VCODE_TYPE_RECORD:
5,759✔
4154
      op->type = vtype_pointer(var->type);
5,759✔
4155
      op->result = vcode_add_reg(op->type);
5,759✔
4156
      break;
5,759✔
4157

4158
   case VCODE_TYPE_INT:
42,659✔
4159
   case VCODE_TYPE_FILE:
4160
   case VCODE_TYPE_ACCESS:
4161
   case VCODE_TYPE_REAL:
4162
   case VCODE_TYPE_UARRAY:
4163
   case VCODE_TYPE_POINTER:
4164
   case VCODE_TYPE_SIGNAL:
4165
   case VCODE_TYPE_CONTEXT:
4166
   case VCODE_TYPE_OFFSET:
4167
   case VCODE_TYPE_TRIGGER:
4168
   case VCODE_TYPE_RESOLUTION:
4169
      op->type = vtype_pointer(var->type);
42,659✔
4170
      op->result = vcode_add_reg(op->type);
42,659✔
4171
      vcode_reg_data(op->result)->bounds = var->bounds;
42,659✔
4172
      break;
42,659✔
4173

4174
   default:
UNCOV
4175
      VCODE_ASSERT(false, "variable %s cannot be indexed",
×
4176
                   istr(var->name));
4177
   }
4178
}
70,090✔
4179

4180
vcode_reg_t emit_index(vcode_var_t var, vcode_reg_t offset)
33,730✔
4181
{
4182
   // Try to find a previous index of this var by this offset
4183
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_INDEX) {
1,378,022✔
4184
      if (other->address == var
82,831✔
4185
          && ((offset == VCODE_INVALID_REG && other->args.count == 0)
7,176✔
UNCOV
4186
              || (offset != VCODE_INVALID_REG
×
UNCOV
4187
                  && other->args.items[0] == offset)))
×
4188
         return other->result;
7,176✔
4189
   }
4190

4191
   op_t *op = vcode_add_op(VCODE_OP_INDEX);
26,554✔
4192
   op->address = var;
26,554✔
4193

4194
   if (offset != VCODE_INVALID_REG)
26,554✔
UNCOV
4195
      vcode_add_arg(op, offset);
×
4196

4197
   vcode_calculate_var_index_type(op, vcode_var_data(var));
26,554✔
4198

4199
   if (offset != VCODE_INVALID_REG)
26,554✔
UNCOV
4200
      VCODE_ASSERT(vtype_kind(vcode_reg_type(offset)) == VCODE_TYPE_OFFSET,
×
4201
                   "index offset r%d does not have offset type", offset);
4202

4203
   return op->result;
26,554✔
4204
}
4205

4206
vcode_reg_t emit_cast(vcode_type_t type, vcode_type_t bounds, vcode_reg_t reg)
242,839✔
4207
{
4208
   if (vtype_eq(vcode_reg_type(reg), type))
242,839✔
4209
      return reg;
242,839✔
4210

4211
   vtype_kind_t from = vtype_kind(vcode_reg_type(reg));
81,616✔
4212
   vtype_kind_t to   = vtype_kind(type);
81,616✔
4213

4214
   const bool integral =
163,232✔
4215
      (from == VCODE_TYPE_OFFSET || from == VCODE_TYPE_INT)
81,616✔
4216
      && (to == VCODE_TYPE_OFFSET || to == VCODE_TYPE_INT);
81,616✔
4217

4218
   int64_t value;
81,616✔
4219
   if (integral && vcode_reg_const(reg, &value))
81,616✔
4220
      return emit_const(type, value);
12,653✔
4221

4222
   // Try to find a previous cast of this register to this type
4223
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CAST) {
1,365,949✔
4224
      if (vtype_eq(other->type, type) && other->args.items[0] == reg)
139,237✔
4225
         return other->result;
15,220✔
4226
   }
4227

4228
   op_t *op = vcode_add_op(VCODE_OP_CAST);
53,743✔
4229
   vcode_add_arg(op, reg);
53,743✔
4230
   op->type   = type;
53,743✔
4231
   op->result = vcode_add_reg(type);
53,743✔
4232

4233
   static const vcode_type_t allowed[][2] = {
53,743✔
4234
      { VCODE_TYPE_INT,    VCODE_TYPE_OFFSET  },
4235
      { VCODE_TYPE_OFFSET, VCODE_TYPE_INT     },
4236
      { VCODE_TYPE_INT,    VCODE_TYPE_INT     },
4237
      { VCODE_TYPE_INT,    VCODE_TYPE_REAL    },
4238
      { VCODE_TYPE_REAL,   VCODE_TYPE_INT     },
4239
      { VCODE_TYPE_REAL,   VCODE_TYPE_REAL    },
4240
      { VCODE_TYPE_ACCESS, VCODE_TYPE_ACCESS  },
4241
   };
4242

4243
   if (integral) {
53,743✔
4244
      vtype_t *vt = vcode_type_data(type);
52,901✔
4245
      int64_t low = vt->low, high = vt->high;
52,901✔
4246

4247
      vtype_t *rt = vcode_type_data(vcode_reg_bounds(reg));
52,901✔
4248
      low = MAX(low, rt->low);
52,901✔
4249
      high = MIN(high, rt->high);
52,901✔
4250

4251
      if (bounds != VCODE_INVALID_REG) {
52,901✔
4252
         vtype_t *bt = vcode_type_data(bounds);
31,636✔
4253
         low = MAX(low, bt->low);
31,636✔
4254
         high = MIN(high, bt->high);
31,636✔
4255
      }
4256

4257
      reg_t *rr = vcode_reg_data(op->result);
52,901✔
4258
      rr->bounds = vtype_int(low, high);
52,901✔
4259
   }
4260
   else if (bounds != VCODE_INVALID_REG)
842✔
4261
      vcode_reg_data(op->result)->bounds = bounds;
842✔
4262

4263
   for (size_t i = 0; i < ARRAY_LEN(allowed); i++) {
94,297✔
4264
      if (from == allowed[i][0] && to == allowed[i][1])
94,297✔
4265
         return op->result;
53,743✔
4266
   }
4267

UNCOV
4268
   VCODE_ASSERT(false, "invalid type conversion in cast");
×
4269
}
4270

4271
void emit_return(vcode_reg_t reg)
55,206✔
4272
{
4273
   op_t *op = vcode_add_op(VCODE_OP_RETURN);
55,206✔
4274
   if (reg != VCODE_INVALID_REG) {
55,206✔
4275
      vcode_add_arg(op, reg);
24,716✔
4276

4277
      const vtype_kind_t rkind = vcode_reg_kind(reg);
24,716✔
4278
      if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY)
24,716✔
4279
         vcode_heap_allocate(reg);
4,541✔
4280

4281
      VCODE_ASSERT(active_unit->kind == VCODE_UNIT_FUNCTION
24,716✔
4282
                   || active_unit->kind == VCODE_UNIT_THUNK
4283
                   || active_unit->kind == VCODE_UNIT_PROPERTY,
4284
                   "returning value fron non-function unit");
4285
      VCODE_ASSERT((active_unit->kind == VCODE_UNIT_PROPERTY
24,716✔
4286
                    && rkind == VCODE_TYPE_INT)
4287
                   || vtype_eq(active_unit->result, vcode_reg_type(reg))
4288
                   || (vtype_kind(active_unit->result) == VCODE_TYPE_ACCESS
4289
                       && rkind == VCODE_TYPE_ACCESS),
4290
                   "return value incorrect type");
4291
   }
4292
}
55,206✔
4293

4294
void emit_sched_waveform(vcode_reg_t nets, vcode_reg_t nnets,
9,182✔
4295
                         vcode_reg_t values, vcode_reg_t reject,
4296
                         vcode_reg_t after)
4297
{
4298
   int64_t nconst;
9,182✔
4299
   if (vcode_reg_const(nnets, &nconst) && nconst == 0) {
9,182✔
4300
      emit_comment("Skip empty waveform");
9✔
4301
      return;
9✔
4302
   }
4303

4304
   op_t *op = vcode_add_op(VCODE_OP_SCHED_WAVEFORM);
9,173✔
4305
   vcode_add_arg(op, nets);
9,173✔
4306
   vcode_add_arg(op, nnets);
9,173✔
4307
   vcode_add_arg(op, values);
9,173✔
4308
   vcode_add_arg(op, reject);
9,173✔
4309
   vcode_add_arg(op, after);
9,173✔
4310

4311
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
9,173✔
4312
                "sched_waveform target is not signal");
4313
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
9,173✔
4314
                "sched_waveform net count is not offset type");
4315
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
9,173✔
4316
                "signal cannot be values argument for sched_waveform");
4317
}
4318

4319
void emit_force(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t values)
70✔
4320
{
4321
   op_t *op = vcode_add_op(VCODE_OP_FORCE);
70✔
4322
   vcode_add_arg(op, nets);
70✔
4323
   vcode_add_arg(op, nnets);
70✔
4324
   vcode_add_arg(op, values);
70✔
4325

4326
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
70✔
4327
                "force target is not signal");
4328
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
70✔
4329
                "force net count is not offset type");
4330
}
70✔
4331

4332
void emit_release(vcode_reg_t nets, vcode_reg_t nnets)
42✔
4333
{
4334
   op_t *op = vcode_add_op(VCODE_OP_RELEASE);
42✔
4335
   vcode_add_arg(op, nets);
42✔
4336
   vcode_add_arg(op, nnets);
42✔
4337

4338
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
42✔
4339
                "release target is not signal");
4340
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
42✔
4341
                "release net count is not offset type");
4342
}
42✔
4343

4344
void emit_disconnect(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t reject,
24✔
4345
                     vcode_reg_t after)
4346
{
4347
   op_t *op = vcode_add_op(VCODE_OP_DISCONNECT);
24✔
4348
   vcode_add_arg(op, nets);
24✔
4349
   vcode_add_arg(op, nnets);
24✔
4350
   vcode_add_arg(op, reject);
24✔
4351
   vcode_add_arg(op, after);
24✔
4352

4353
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
24✔
4354
                "disconnect target is not signal");
4355
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
24✔
4356
                "disconnect net count is not offset type");
4357
}
24✔
4358

4359
void emit_cond(vcode_reg_t test, vcode_block_t btrue, vcode_block_t bfalse)
32,542✔
4360
{
4361
   int64_t tconst;
32,542✔
4362
   if (vcode_reg_const(test, &tconst)) {
32,542✔
4363
      emit_jump(!!tconst ? btrue : bfalse);
3,830✔
4364
      return;
1,954✔
4365
   }
4366

4367
   op_t *op = vcode_add_op(VCODE_OP_COND);
30,588✔
4368
   vcode_add_arg(op, test);
30,588✔
4369
   vcode_add_target(op, btrue);
30,588✔
4370
   vcode_add_target(op, bfalse);
30,588✔
4371

4372
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
30,588✔
4373
                "cond test is not a bool");
4374
   VCODE_ASSERT(btrue != VCODE_INVALID_BLOCK && bfalse != VCODE_INVALID_BLOCK,
30,588✔
4375
                "invalid cond targets");
4376
}
4377

4378
vcode_reg_t emit_neg(vcode_reg_t lhs)
6,956✔
4379
{
4380
   int64_t lconst;
6,956✔
4381
   if (vcode_reg_const(lhs, &lconst))
6,956✔
UNCOV
4382
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4383

4384
   op_t *op = vcode_add_op(VCODE_OP_NEG);
6,956✔
4385
   vcode_add_arg(op, lhs);
6,956✔
4386
   op->result = vcode_add_reg(vcode_reg_type(lhs));
6,956✔
4387

4388
   return op->result;
6,956✔
4389
}
4390

4391
vcode_reg_t emit_trap_neg(vcode_reg_t lhs, vcode_reg_t locus)
467✔
4392
{
4393
   int64_t lconst;
467✔
4394
   if (vcode_reg_const(lhs, &lconst) && lconst >= 0)
467✔
UNCOV
4395
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4396
   else if (vcode_type_data(vcode_reg_data(lhs)->bounds)->low >= 0)
467✔
4397
      return emit_neg(lhs);   // Cannot overflow
210✔
4398

4399
   op_t *op = vcode_add_op(VCODE_OP_TRAP_NEG);
257✔
4400
   vcode_add_arg(op, lhs);
257✔
4401
   vcode_add_arg(op, locus);
257✔
4402

4403
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
257✔
4404
                "locus argument to trap neg must be a debug locus");
4405
   VCODE_ASSERT(vcode_reg_kind(lhs) == VCODE_TYPE_INT,
257✔
4406
                "trapping neg may only be used with integer types");
4407

4408
   return (op->result = vcode_add_reg(vcode_reg_type(lhs)));
257✔
4409
}
4410

4411
vcode_reg_t emit_abs(vcode_reg_t lhs)
686✔
4412
{
4413
   int64_t lconst;
686✔
4414
   if (vcode_reg_const(lhs, &lconst))
686✔
4415
      return emit_const(vcode_reg_type(lhs), llabs(lconst));
1✔
4416

4417
   op_t *op = vcode_add_op(VCODE_OP_ABS);
685✔
4418
   vcode_add_arg(op, lhs);
685✔
4419
   op->result = vcode_add_reg(vcode_reg_type(lhs));
685✔
4420

4421
   return op->result;
685✔
4422
}
4423

4424
void emit_comment(const char *fmt, ...)
77,590✔
4425
{
4426
#ifndef NDEBUG
4427
   va_list ap;
77,590✔
4428
   va_start(ap, fmt);
77,590✔
4429

4430
   char *buf = xvasprintf(fmt, ap);
77,590✔
4431
   for (char *p = buf + strlen(buf) - 1;
77,590✔
4432
        p >= buf && isspace_iso88591(*p); p--)
77,590✔
UNCOV
4433
      *p = '\0';
×
4434

4435
   vcode_add_op(VCODE_OP_COMMENT)->comment = buf;
77,590✔
4436
   va_end(ap);
77,590✔
4437
#endif
4438
}
77,590✔
4439

4440
vcode_reg_t emit_select(vcode_reg_t test, vcode_reg_t rtrue,
18,256✔
4441
                        vcode_reg_t rfalse)
4442
{
4443
   int64_t tconst;
18,256✔
4444
   if (vcode_reg_const(test, &tconst))
18,256✔
4445
      return !!tconst ? rtrue : rfalse;
4,678✔
4446
   else if (rtrue == rfalse)
13,578✔
4447
      return rtrue;
4448

4449
   // Find a previous identical select
4450
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_SELECT) {
294,930✔
4451
      if (other->args.items[0] == test && other->args.items[1] == rtrue
10,836✔
4452
          && other->args.items[2] == rfalse)
646✔
4453
         return other->result;
553✔
4454
   }
4455

4456
   op_t *op = vcode_add_op(VCODE_OP_SELECT);
12,850✔
4457
   vcode_add_arg(op, test);
12,850✔
4458
   vcode_add_arg(op, rtrue);
12,850✔
4459
   vcode_add_arg(op, rfalse);
12,850✔
4460
   op->result = vcode_add_reg(vcode_reg_type(rtrue));
12,850✔
4461

4462
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
12,850✔
4463
                "select test must have bool type");
4464
   VCODE_ASSERT(vtype_eq(vcode_reg_type(rtrue), vcode_reg_type(rfalse)),
12,850✔
4465
                "select arguments are not the same type");
4466

4467
   return op->result;
12,850✔
4468
}
4469

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

4484
static vcode_reg_t emit_logical(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs)
7,332✔
4485
{
4486
   vcode_type_t vtbool = vtype_bool();
7,332✔
4487

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

4524
   vcode_reg_t result = emit_arith(op, lhs, rhs, VCODE_INVALID_REG);
6,857✔
4525

4526
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vtbool)
6,857✔
4527
                && vtype_eq(vcode_reg_type(rhs), vtbool),
4528
                "arguments to %s are not boolean", vcode_op_string(op));
4529

4530
   return result;
4531
}
4532

4533
vcode_reg_t emit_or(vcode_reg_t lhs, vcode_reg_t rhs)
2,389✔
4534
{
4535
   return emit_logical(VCODE_OP_OR, lhs, rhs);
2,389✔
4536
}
4537

4538
vcode_reg_t emit_and(vcode_reg_t lhs, vcode_reg_t rhs)
4,707✔
4539
{
4540
   return emit_logical(VCODE_OP_AND, lhs, rhs);
4,707✔
4541
}
4542

4543
vcode_reg_t emit_nand(vcode_reg_t lhs, vcode_reg_t rhs)
52✔
4544
{
4545
   return emit_logical(VCODE_OP_NAND, lhs, rhs);
52✔
4546
}
4547

4548
vcode_reg_t emit_nor(vcode_reg_t lhs, vcode_reg_t rhs)
53✔
4549
{
4550
   return emit_logical(VCODE_OP_NOR, lhs, rhs);
53✔
4551
}
4552

4553
vcode_reg_t emit_xor(vcode_reg_t lhs, vcode_reg_t rhs)
73✔
4554
{
4555
   return emit_logical(VCODE_OP_XOR, lhs, rhs);
73✔
4556
}
4557

4558
vcode_reg_t emit_xnor(vcode_reg_t lhs, vcode_reg_t rhs)
58✔
4559
{
4560
   return emit_logical(VCODE_OP_XNOR, lhs, rhs);
58✔
4561
}
4562

4563
vcode_reg_t emit_not(vcode_reg_t arg)
2,498✔
4564
{
4565
   int64_t cval;
2,498✔
4566
   if (vcode_reg_const(arg, &cval))
2,498✔
4567
      return emit_const(vtype_bool(), !cval);
27✔
4568

4569
   op_t *op = vcode_add_op(VCODE_OP_NOT);
2,471✔
4570
   vcode_add_arg(op, arg);
2,471✔
4571

4572
   vcode_type_t vtbool = vtype_bool();
2,471✔
4573
   VCODE_ASSERT(vtype_eq(vcode_reg_type(arg), vtbool),
2,471✔
4574
                "argument to not is not boolean");
4575

4576
   return (op->result = vcode_add_reg(vtbool));
2,471✔
4577
}
4578

4579
vcode_reg_t emit_wrap(vcode_reg_t data, const vcode_dim_t *dims, int ndims)
46,597✔
4580
{
4581
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_WRAP) {
1,726,222✔
4582
      if (other->args.count == ndims*3 + 1 && other->args.items[0] == data) {
155,713✔
4583
         bool match = true;
4584
         for (int i = 0; match && i < ndims; i++) {
22,368✔
4585
            match = other->args.items[i*3 + 1] == dims[i].left
11,216✔
4586
               && other->args.items[i*3 + 2] == dims[i].right
9,021✔
4587
               && other->args.items[i*3 + 3] == dims[i].dir;
19,970✔
4588
         }
4589
         if (match)
11,152✔
4590
            return other->result;
8,690✔
4591
      }
4592
   }
4593

4594
   op_t *op = vcode_add_op(VCODE_OP_WRAP);
37,907✔
4595
   vcode_add_arg(op, data);
37,907✔
4596
   for (int i = 0; i < ndims; i++) {
76,472✔
4597
      vcode_add_arg(op, dims[i].left);
38,565✔
4598
      vcode_add_arg(op, dims[i].right);
38,565✔
4599
      vcode_add_arg(op, dims[i].dir);
38,565✔
4600
   }
4601

4602
   vcode_type_t ptr_type = vcode_reg_type(data);
37,907✔
4603
   const vtype_kind_t ptrkind = vtype_kind(ptr_type);
37,907✔
4604
   VCODE_ASSERT(ptrkind == VCODE_TYPE_POINTER || ptrkind == VCODE_TYPE_SIGNAL,
37,907✔
4605
                "wrapped data is not pointer or signal");
4606

4607
#ifdef DEBUG
4608
   for (int i = 0; i < ndims; i++) {
76,472✔
4609
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].left)),
38,565✔
4610
                   "dimension %d left bound must be scalar", i + 1);
4611
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].right)),
38,565✔
4612
                   "dimension %d right bound must be scalar", i + 1);
4613
      VCODE_ASSERT(vtype_eq(vtype_bool(), vcode_reg_type(dims[i].dir)),
38,565✔
4614
                   "dimension %d direction must be bool", i + 1);
4615
   }
4616
#endif
4617

4618
   vcode_type_t elem = (ptrkind == VCODE_TYPE_POINTER)
75,814✔
4619
      ? vtype_pointed(ptr_type) : ptr_type;
37,907✔
4620

4621
   op->result = vcode_add_reg(
37,907✔
4622
      vtype_uarray(ndims, elem, vcode_reg_bounds(data)));
4623

4624
   return op->result;
37,907✔
4625
}
4626

4627
static vcode_reg_t emit_uarray_op(vcode_op_t o, vcode_type_t rtype,
102,724✔
4628
                                  vcode_reg_t array, unsigned dim,
4629
                                  unsigned arg_index)
4630
{
4631
   // Reuse any previous operation in this block with the same arguments
4632
   VCODE_FOR_EACH_OP(other) {
1,164,982✔
4633
      if (other->kind == o && other->args.items[0] == array && other->dim == dim
1,120,498✔
4634
          && (rtype == VCODE_INVALID_TYPE
23,378✔
4635
              || vtype_eq(rtype, vcode_reg_type(other->result))))
10,136✔
4636
         return other->result;
23,378✔
4637
      else if (other->kind == VCODE_OP_WRAP && other->result == array)
1,097,120✔
4638
         return other->args.items[1 + (dim * 3) + arg_index];
34,862✔
4639
   }
4640

4641
   op_t *op = vcode_add_op(o);
44,484✔
4642
   vcode_add_arg(op, array);
44,484✔
4643
   op->dim = dim;
44,484✔
4644

4645
   vcode_type_t atype = vcode_reg_type(array);
44,484✔
4646
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
44,484✔
4647
                "cannot use %s with non-uarray type", vcode_op_string(o));
4648

4649
   vtype_t *vt = vcode_type_data(atype);
44,484✔
4650
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
44,484✔
4651

4652
   if (rtype == VCODE_INVALID_TYPE)
44,484✔
4653
      rtype = vtype_offset();
28,724✔
4654

4655
   return (op->result = vcode_add_reg(rtype));
44,484✔
4656
}
4657

4658
vcode_reg_t emit_uarray_left(vcode_reg_t array, unsigned dim)
37,880✔
4659
{
4660
   return emit_uarray_op(VCODE_OP_UARRAY_LEFT, VCODE_INVALID_TYPE,
37,880✔
4661
                         array, dim, 0);
4662
}
4663

4664
vcode_reg_t emit_uarray_right(vcode_reg_t array, unsigned dim)
27,226✔
4665
{
4666
   return emit_uarray_op(VCODE_OP_UARRAY_RIGHT, VCODE_INVALID_TYPE,
27,226✔
4667
                         array, dim, 1);
4668
}
4669

4670
vcode_reg_t emit_uarray_dir(vcode_reg_t array, unsigned dim)
37,618✔
4671
{
4672
   return emit_uarray_op(VCODE_OP_UARRAY_DIR, vtype_bool(),
37,618✔
4673
                         array, dim, 2);
4674
}
4675

4676
vcode_reg_t emit_uarray_len(vcode_reg_t array, unsigned dim)
45,744✔
4677
{
4678
   VCODE_FOR_EACH_OP(other) {
665,816✔
4679
      if (other->kind == VCODE_OP_UARRAY_LEN) {
644,314✔
4680
         if (other->args.items[0] == array && other->dim == dim)
40,860✔
4681
            return other->result;
9,519✔
4682
      }
4683
      else if (other->kind == VCODE_OP_WRAP && other->result == array) {
603,454✔
4684
         VCODE_ASSERT(dim < (other->args.count - 1) / 3,
14,723✔
4685
                      "array dimension %d out of bounds", dim);
4686

4687
         vcode_reg_t left_reg = other->args.items[dim * 3 + 1];
14,723✔
4688
         vcode_reg_t right_reg = other->args.items[dim * 3 + 2];
14,723✔
4689
         vcode_reg_t dir_reg = other->args.items[dim * 3 + 3];
14,723✔
4690
         return emit_range_length(left_reg, right_reg, dir_reg);
14,723✔
4691
      }
4692
   }
4693

4694
   op_t *op = vcode_add_op(VCODE_OP_UARRAY_LEN);
21,502✔
4695
   vcode_add_arg(op, array);
21,502✔
4696
   op->dim = dim;
21,502✔
4697

4698
   vcode_type_t atype = vcode_reg_type(array);
21,502✔
4699
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
21,502✔
4700
                "cannot use uarray len with non-uarray type");
4701

4702
   vtype_t *vt = vcode_type_data(atype);
21,502✔
4703
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
21,502✔
4704

4705
   op->result = vcode_add_reg(vtype_offset());
21,502✔
4706

4707
   reg_t *rr = vcode_reg_data(op->result);
21,502✔
4708
   rr->bounds = vtype_int(0, INT64_MAX);
21,502✔
4709

4710
   return op->result;
21,502✔
4711
}
4712

4713
vcode_reg_t emit_unwrap(vcode_reg_t array)
35,306✔
4714
{
4715
   VCODE_FOR_EACH_OP(other) {
1,540,454✔
4716
      if (other->kind == VCODE_OP_WRAP && other->result == array)
1,515,320✔
4717
         return other->args.items[0];
8,444✔
4718
      else if (other->kind == VCODE_OP_UNWRAP && other->args.items[0] == array)
1,506,876✔
4719
         return other->result;
1,728✔
4720
   }
4721

4722
   op_t *op = vcode_add_op(VCODE_OP_UNWRAP);
25,134✔
4723
   vcode_add_arg(op, array);
25,134✔
4724

4725
   vtype_t *vt = vcode_type_data(vcode_reg_type(array));
25,134✔
4726
   VCODE_ASSERT(vt->kind == VCODE_TYPE_UARRAY,
25,134✔
4727
                "unwrap can only only be used with uarray types");
4728

4729
   vcode_type_t elem = vt->elem;
25,134✔
4730

4731
   vcode_type_t rtype = (vtype_kind(elem) == VCODE_TYPE_SIGNAL)
25,134✔
4732
      ? elem : vtype_pointer(elem);
25,134✔
4733

4734
   op->result = vcode_add_reg(rtype);
25,134✔
4735

4736
   reg_t *rr = vcode_reg_data(op->result);
25,134✔
4737
   rr->bounds = elem;
25,134✔
4738

4739
   return op->result;
25,134✔
4740
}
4741

4742
vcode_reg_t emit_range_null(vcode_reg_t left, vcode_reg_t right,
29,193✔
4743
                            vcode_reg_t dir)
4744
{
4745
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RANGE_NULL) {
1,413,437✔
UNCOV
4746
      if (other->args.items[0] == left
×
UNCOV
4747
          && other->args.items[1] == right
×
UNCOV
4748
          && other->args.items[2] == dir)
×
UNCOV
4749
         return other->result;
×
4750
   }
4751

4752
   int64_t dir_const;
29,193✔
4753
   if (vcode_reg_const(dir, &dir_const)) {
29,193✔
4754
      vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
26,207✔
4755
      vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
26,207✔
4756

4757
      if (dir_const == RANGE_TO && lbounds->low > rbounds->high)
26,207✔
4758
         return emit_const(vtype_bool(), 1);
65✔
4759
      else if (dir_const == RANGE_TO && lbounds->high <= rbounds->low)
26,142✔
4760
         return emit_const(vtype_bool(), 0);
18,209✔
4761
      else if (dir_const == RANGE_DOWNTO && rbounds->low > lbounds->high)
7,933✔
4762
         return emit_const(vtype_bool(), 1);
611✔
4763
      else if (dir_const == RANGE_DOWNTO && rbounds->high <= lbounds->low)
7,322✔
4764
         return emit_const(vtype_bool(), 0);
1,816✔
4765
      else if (dir_const == RANGE_TO)
5,506✔
4766
         return emit_cmp(VCODE_CMP_GT, left, right);
2,801✔
4767
      else
4768
         return emit_cmp(VCODE_CMP_GT, right, left);
2,705✔
4769
   }
4770

4771
   op_t *op = vcode_add_op(VCODE_OP_RANGE_NULL);
2,986✔
4772
   vcode_add_arg(op, left);
2,986✔
4773
   vcode_add_arg(op, right);
2,986✔
4774
   vcode_add_arg(op, dir);
2,986✔
4775

4776
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
2,986✔
4777
                "range left and right have different types");
4778
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
2,986✔
4779
                "dir argument to range length is not int");
4780

4781
   return (op->result = vcode_add_reg(vtype_bool()));
2,986✔
4782
}
4783

4784
vcode_reg_t emit_range_length(vcode_reg_t left, vcode_reg_t right,
14,761✔
4785
                              vcode_reg_t dir)
4786
{
4787
   vcode_reg_t left_array = VCODE_INVALID_REG,
14,761✔
4788
      right_array = VCODE_INVALID_REG,
14,761✔
4789
      dir_array = VCODE_INVALID_REG;
14,761✔
4790
   int left_dim = -1, right_dim = -1, dir_dim = -1;
14,761✔
4791

4792
   VCODE_FOR_EACH_OP(other) {
291,045✔
4793
      if (other->kind == VCODE_OP_RANGE_LENGTH
281,805✔
4794
          && other->args.items[0] == left
7,838✔
4795
          && other->args.items[1] == right
5,838✔
4796
          && other->args.items[2] == dir)
5,521✔
4797
         return other->result;
5,521✔
4798
      else if (other->kind == VCODE_OP_UARRAY_LEFT && other->result == left) {
276,284✔
4799
         left_array = other->args.items[0];
362✔
4800
         left_dim = other->dim;
362✔
4801
      }
4802
      else if (other->kind == VCODE_OP_UARRAY_RIGHT && other->result == right) {
275,922✔
4803
         right_array = other->args.items[0];
362✔
4804
         right_dim = other->dim;
362✔
4805
      }
4806
      else if (other->kind == VCODE_OP_UARRAY_DIR && other->result == dir) {
275,560✔
4807
         dir_array = other->args.items[0];
706✔
4808
         dir_dim = other->dim;
706✔
4809
      }
4810
   }
4811

4812
   if (left_array != VCODE_INVALID_REG && left_array == right_array
9,240✔
4813
       && right_array == dir_array && left_dim == right_dim
362✔
4814
       && right_dim == dir_dim)
362✔
4815
      return emit_uarray_len(left_array, left_dim);
362✔
4816

4817
   int64_t lconst, rconst, dconst;
8,878✔
4818
   if (vcode_reg_const(dir, &dconst) && vcode_reg_const(left, &lconst)
8,878✔
4819
       && vcode_reg_const(right, &rconst)) {
4,859✔
4820

4821
      int64_t diff;
1,840✔
4822
      if (dconst == RANGE_TO)
1,840✔
4823
         diff = rconst - lconst;
1,543✔
4824
      else
4825
         diff = lconst - rconst;
297✔
4826

4827
      return emit_const(vtype_offset(), diff < 0 ? 0 : diff + 1);
1,840✔
4828
   }
4829

4830
   op_t *op = vcode_add_op(VCODE_OP_RANGE_LENGTH);
7,038✔
4831
   vcode_add_arg(op, left);
7,038✔
4832
   vcode_add_arg(op, right);
7,038✔
4833
   vcode_add_arg(op, dir);
7,038✔
4834

4835
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
7,038✔
4836
                "range left and right have different types");
4837
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
7,038✔
4838
                "dir argument to range length is not int");
4839

4840
   op->result = vcode_add_reg(vtype_offset());
7,038✔
4841

4842
   reg_t *rr = vcode_reg_data(op->result);
7,038✔
4843
   rr->bounds = vtype_int(0, INT64_MAX);
7,038✔
4844

4845
   return op->result;
7,038✔
4846
}
4847

4848
vcode_reg_t emit_var_upref(int hops, vcode_var_t var)
54,379✔
4849
{
4850
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_VAR_UPREF) {
493,871✔
4851
      if (other->hops == hops && other->address == var)
66,227✔
4852
         return other->result;
10,843✔
4853
   }
4854

4855
   op_t *op = vcode_add_op(VCODE_OP_VAR_UPREF);
43,536✔
4856
   op->hops    = hops;
43,536✔
4857
   op->address = var;
43,536✔
4858

4859
   VCODE_ASSERT(hops > 0, "invalid hop count");
43,536✔
4860

4861
   vcode_unit_t vu = active_unit;
43,536✔
4862
   for (int i = 0; i < hops; i++) {
96,349✔
4863
      vu = vu->context;
52,813✔
4864
      VCODE_ASSERT(vu, "hop count is greater than depth");
52,813✔
4865
   }
4866

4867
   VCODE_ASSERT(var < vu->vars.count, "upref %d is not a variable", var);
43,536✔
4868

4869
   vcode_calculate_var_index_type(op, &(vu->vars.items[var]));
43,536✔
4870

4871
   return op->result;
43,536✔
4872
}
4873

4874
vcode_reg_t emit_init_signal(vcode_type_t type, vcode_reg_t count,
16,185✔
4875
                             vcode_reg_t size, vcode_reg_t value,
4876
                             vcode_reg_t flags, vcode_reg_t locus,
4877
                             vcode_reg_t offset)
4878
{
4879
   op_t *op = vcode_add_op(VCODE_OP_INIT_SIGNAL);
16,185✔
4880
   vcode_add_arg(op, count);
16,185✔
4881
   vcode_add_arg(op, size);
16,185✔
4882
   vcode_add_arg(op, value);
16,185✔
4883
   vcode_add_arg(op, flags);
16,185✔
4884
   vcode_add_arg(op, locus);
16,185✔
4885
   if (offset != VCODE_INVALID_REG)
16,185✔
4886
      vcode_add_arg(op, offset);
5,730✔
4887

4888
   vcode_type_t vtype = vcode_reg_type(value);
16,185✔
4889
   VCODE_ASSERT(vtype_is_scalar(type), "signal type must be scalar");
16,185✔
4890
   VCODE_ASSERT(vtype_eq(vtype, type)
16,185✔
4891
                || vtype_kind(vtype) == VCODE_TYPE_POINTER,
4892
                "init signal value type does not match signal type");
4893
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
16,185✔
4894
                "locus argument to init signal must be a debug locus");
4895
   VCODE_ASSERT(offset == VCODE_INVALID_REG
16,185✔
4896
                || vcode_reg_kind(offset) == VCODE_TYPE_POINTER,
4897
                "init signal offset argument must have pointer type");
4898

4899
   return (op->result = vcode_add_reg(vtype_signal(type)));
16,185✔
4900
}
4901

4902
void emit_resolve_signal(vcode_reg_t signal, vcode_reg_t resolution)
3,376✔
4903
{
4904
   op_t *op = vcode_add_op(VCODE_OP_RESOLVE_SIGNAL);
3,376✔
4905
   vcode_add_arg(op, signal);
3,376✔
4906
   vcode_add_arg(op, resolution);
3,376✔
4907

4908
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
3,376✔
4909
                "signal argument has wrong type");
4910

4911
   vcode_type_t rtype = vcode_reg_type(resolution);
3,376✔
4912
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
3,376✔
4913
                "resolution wrapper argument must be pointer");
4914
   VCODE_ASSERT(vtype_kind(vtype_pointed(rtype)) == VCODE_TYPE_RESOLUTION,
3,376✔
4915
                "resolution wrapper argument has wrong type");
4916
}
3,376✔
4917

4918
vcode_reg_t emit_implicit_signal(vcode_type_t type, vcode_reg_t count,
75✔
4919
                                 vcode_reg_t size, vcode_reg_t locus,
4920
                                 vcode_reg_t kind, vcode_reg_t closure,
4921
                                 vcode_reg_t delay)
4922
{
4923
   op_t *op = vcode_add_op(VCODE_OP_IMPLICIT_SIGNAL);
75✔
4924
   vcode_add_arg(op, count);
75✔
4925
   vcode_add_arg(op, size);
75✔
4926
   vcode_add_arg(op, locus);
75✔
4927
   vcode_add_arg(op, kind);
75✔
4928
   vcode_add_arg(op, closure);
75✔
4929
   vcode_add_arg(op, delay);
75✔
4930

4931
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
75✔
4932
                "count argument to implicit signal is not offset");
4933
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
75✔
4934
                "kind argument to implicit signal is not offset");
4935
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
75✔
4936
                "closure argument to implicit signal is not a closure");
4937
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
75✔
4938
                "locus argument to implicit signal must be a debug locus");
4939
   VCODE_ASSERT(vcode_reg_kind(delay) == VCODE_TYPE_INT,
75✔
4940
                "delay argument to implicit signal must be time");
4941

4942
   return (op->result = vcode_add_reg(vtype_signal(type)));
75✔
4943
}
4944

4945
void emit_map_signal(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
5,431✔
4946
{
4947
   op_t *op = vcode_add_op(VCODE_OP_MAP_SIGNAL);
5,431✔
4948
   vcode_add_arg(op, src);
5,431✔
4949
   vcode_add_arg(op, dst);
5,431✔
4950
   vcode_add_arg(op, count);
5,431✔
4951

4952
   VCODE_ASSERT(vcode_reg_kind(src) == VCODE_TYPE_SIGNAL,
5,431✔
4953
                "src argument to map signal is not a signal");
4954
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
5,431✔
4955
                "dst argument to map signal is not a signal");
4956
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
5,431✔
4957
                "count argument type to map signal is not offset");
4958
}
5,431✔
4959

4960
void emit_map_const(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
200✔
4961
{
4962
   op_t *op = vcode_add_op(VCODE_OP_MAP_CONST);
200✔
4963
   vcode_add_arg(op, src);
200✔
4964
   vcode_add_arg(op, dst);
200✔
4965
   vcode_add_arg(op, count);
200✔
4966

4967
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
200✔
4968
                "dst argument to map const is not a signal");
4969
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
200✔
4970
                "count argument type to map const is not offset");
4971
}
200✔
4972

4973
void emit_map_implicit(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
57✔
4974
{
4975
   op_t *op = vcode_add_op(VCODE_OP_MAP_IMPLICIT);
57✔
4976
   vcode_add_arg(op, src);
57✔
4977
   vcode_add_arg(op, dst);
57✔
4978
   vcode_add_arg(op, count);
57✔
4979

4980
   VCODE_ASSERT(vcode_reg_kind(src) == VCODE_TYPE_SIGNAL,
57✔
4981
                "src argument to map implicit is not a signal");
4982
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
57✔
4983
                "dst argument to map implicit is not a signal");
4984
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
57✔
4985
                "count argument type to map implicit is not offset");
4986
}
57✔
4987

4988
void emit_drive_signal(vcode_reg_t target, vcode_reg_t count)
7,216✔
4989
{
4990
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DRIVE_SIGNAL) {
91,392✔
4991
      if (other->args.items[0] == target && other->args.items[1] == count)
12,117✔
4992
         return;
4993
   }
4994

4995
   op_t *op = vcode_add_op(VCODE_OP_DRIVE_SIGNAL);
7,213✔
4996
   vcode_add_arg(op, target);
7,213✔
4997
   vcode_add_arg(op, count);
7,213✔
4998

4999
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
7,213✔
5000
                "target argument to drive signal is not a signal");
5001
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
7,213✔
5002
                "count argument type to drive signal is not offset");
5003
}
5004

5005
void emit_transfer_signal(vcode_reg_t target, vcode_reg_t source,
530✔
5006
                          vcode_reg_t count, vcode_reg_t reject,
5007
                          vcode_reg_t after)
5008
{
5009
   op_t *op = vcode_add_op(VCODE_OP_TRANSFER_SIGNAL);
530✔
5010
   vcode_add_arg(op, target);
530✔
5011
   vcode_add_arg(op, source);
530✔
5012
   vcode_add_arg(op, count);
530✔
5013
   vcode_add_arg(op, reject);
530✔
5014
   vcode_add_arg(op, after);
530✔
5015

5016
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
530✔
5017
                "target argument to transfer signal is not a signal");
5018
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
530✔
5019
                "count argument type to transfer signal is not offset");
5020
   VCODE_ASSERT(vcode_reg_kind(source) == VCODE_TYPE_SIGNAL,
530✔
5021
                "source argument to transfer signal is not a signal");
5022
}
530✔
5023

5024
vcode_reg_t emit_resolution_wrapper(vcode_type_t type, vcode_reg_t closure,
5,057✔
5025
                                    vcode_reg_t nlits)
5026
{
5027
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RESOLUTION_WRAPPER) {
82,841✔
5028
      if (other->args.items[0] == closure && other->args.items[1] == nlits)
11,040✔
UNCOV
5029
         return other->result;
×
5030
   }
5031

5032
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
5,057✔
5033
                "first argument to resolution wrapper must be closure");
5034

5035
   op_t *op = vcode_add_op(VCODE_OP_RESOLUTION_WRAPPER);
5,057✔
5036
   vcode_add_arg(op, closure);
5,057✔
5037
   vcode_add_arg(op, nlits);
5,057✔
5038

5039
   return (op->result = vcode_add_reg(vtype_resolution(type)));
5,057✔
5040
}
5041

5042
vcode_reg_t emit_closure(ident_t func, vcode_reg_t context, vcode_type_t rtype)
5,354✔
5043
{
5044
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CLOSURE) {
84,087✔
5045
      if (other->func == func && other->args.items[0] == context)
11,211✔
UNCOV
5046
         return other->result;
×
5047
   }
5048

5049
   op_t *op = vcode_add_op(VCODE_OP_CLOSURE);
5,354✔
5050
   vcode_add_arg(op, context);
5,354✔
5051
   op->func = func;
5,354✔
5052

5053
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
5,354✔
5054
                "invalid closure context argument");
5055

5056
   return (op->result = vcode_add_reg(vtype_closure(rtype)));
5,354✔
5057
}
5058

5059
vcode_reg_t emit_package_init(ident_t name, vcode_reg_t context)
35,126✔
5060
{
5061
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_PACKAGE_INIT) {
67,979✔
5062
      if (other->func == name)
28,633✔
5063
         return other->result;
13,418✔
5064
   }
5065

5066
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_INIT);
21,708✔
5067
   op->func = name;
21,708✔
5068
   if (context != VCODE_INVALID_REG)
21,708✔
5069
      vcode_add_arg(op, context);
190✔
5070

5071
   VCODE_ASSERT(context == VCODE_INVALID_REG
21,708✔
5072
                || vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
5073
                "invalid protected init context argument");
5074
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_INSTANCE
21,708✔
5075
                || active_unit->kind == VCODE_UNIT_PACKAGE
5076
                || active_unit->kind == VCODE_UNIT_THUNK,
5077
                "cannot use package init here");
5078
   VCODE_ASSERT(name != active_unit->name, "cyclic package init");
21,708✔
5079

5080
   return (op->result = vcode_add_reg(vtype_context(name)));
21,708✔
5081
}
5082

5083
vcode_reg_t emit_protected_init(vcode_type_t type, vcode_reg_t context,
544✔
5084
                                vcode_reg_t path_name, vcode_reg_t inst_name)
5085
{
5086
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_INIT);
544✔
5087
   vcode_add_arg(op, context);
544✔
5088
   op->func = vtype_name(type);
544✔
5089

5090
   if (path_name != VCODE_INVALID_REG && inst_name != VCODE_INVALID_REG) {
544✔
5091
      vcode_add_arg(op, path_name);
414✔
5092
      vcode_add_arg(op, inst_name);
414✔
5093

5094
      VCODE_ASSERT(vcode_reg_kind(path_name) == VCODE_TYPE_UARRAY,
414✔
5095
                   "path name argument must be uarray");
5096
      VCODE_ASSERT(vcode_reg_kind(inst_name) == VCODE_TYPE_UARRAY,
414✔
5097
                   "inst name argument must be uarray");
5098
   }
5099

5100
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CONTEXT,
544✔
5101
                "protected init type must be context");
5102
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
544✔
5103
                "invalid protected init context argument");
5104

5105
   return (op->result = vcode_add_reg(type));
544✔
5106
}
5107

5108
void emit_process_init(ident_t name, vcode_reg_t locus)
114✔
5109
{
5110
   op_t *op = vcode_add_op(VCODE_OP_PROCESS_INIT);
114✔
5111
   vcode_add_arg(op, locus);
114✔
5112
   op->func = name;
114✔
5113

5114
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
114✔
5115
                "locus argument to process init must be a debug locus");
5116
}
114✔
5117

5118
void emit_protected_free(vcode_reg_t obj)
308✔
5119
{
5120
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_FREE);
308✔
5121
   vcode_add_arg(op, obj);
308✔
5122

5123
   VCODE_ASSERT(vcode_reg_kind(obj) == VCODE_TYPE_CONTEXT,
308✔
5124
                "protected object type must be context");
5125
}
308✔
5126

5127
vcode_reg_t emit_context_upref(int hops)
19,378✔
5128
{
5129
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONTEXT_UPREF) {
132,126✔
5130
      if (other->hops == hops)
8,652✔
5131
         return other->result;
8,604✔
5132
   }
5133

5134
   op_t *op = vcode_add_op(VCODE_OP_CONTEXT_UPREF);
10,774✔
5135
   op->hops = hops;
10,774✔
5136

5137
   VCODE_ASSERT(hops >= 0, "invalid hop count");
10,774✔
5138

5139
   vcode_unit_t vu = active_unit;
10,774✔
5140
   for (int i = 0; i < hops; i++) {
18,961✔
5141
      vu = vu->context;
8,187✔
5142
      VCODE_ASSERT(vu, "hop count is greater than depth");
8,187✔
5143
   }
5144

5145
   return (op->result = vcode_add_reg(vtype_context(vu->name)));
10,774✔
5146
}
5147

5148
static vcode_reg_t emit_signal_flag(vcode_op_t opkind, vcode_reg_t nets,
661✔
5149
                                    vcode_reg_t len)
5150
{
5151
   op_t *op = vcode_add_op(opkind);
661✔
5152
   vcode_add_arg(op, nets);
661✔
5153
   vcode_add_arg(op, len);
661✔
5154

5155
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
661✔
5156
                "argument to %s is not a signal", vcode_op_string(opkind));
5157

5158
   return (op->result = vcode_add_reg(vtype_bool()));
661✔
5159
}
5160

5161
vcode_reg_t emit_event_flag(vcode_reg_t nets, vcode_reg_t len)
444✔
5162
{
5163
   return emit_signal_flag(VCODE_OP_EVENT, nets, len);
444✔
5164
}
5165

5166
vcode_reg_t emit_active_flag(vcode_reg_t nets, vcode_reg_t len)
217✔
5167
{
5168
   return emit_signal_flag(VCODE_OP_ACTIVE, nets, len);
217✔
5169
}
5170

5171
vcode_reg_t emit_record_ref(vcode_reg_t record, unsigned field)
36,958✔
5172
{
5173
   // Try scanning backwards through the block for another record ref
5174
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RECORD_REF) {
2,681,892✔
5175
      if (other->args.items[0] == record && other->field == field)
503,348✔
5176
         return other->result;
3,878✔
5177
   }
5178

5179
   op_t *op = vcode_add_op(VCODE_OP_RECORD_REF);
33,080✔
5180
   op->field = field;
33,080✔
5181
   vcode_add_arg(op, record);
33,080✔
5182

5183
   vtype_t *rptype = vcode_type_data(vcode_reg_type(record));
33,080✔
5184

5185
   VCODE_ASSERT(rptype->kind == VCODE_TYPE_POINTER,
33,080✔
5186
                "argument to record ref must be a pointer");
5187

5188
   vtype_t *rtype = vcode_type_data(rptype->pointed);
33,080✔
5189
   VCODE_ASSERT(rtype->kind == VCODE_TYPE_RECORD,
33,080✔
5190
                "argument must be pointer to record or record signal");
5191

5192
   VCODE_ASSERT(field < rtype->fields.count, "invalid field %d", field);
33,080✔
5193

5194
   vcode_type_t field_type  = rtype->fields.items[field];
33,080✔
5195
   vcode_type_t bounds_type = field_type;
33,080✔
5196
   vcode_type_t result_type = field_type;
33,080✔
5197

5198
   const vtype_kind_t fkind = vtype_kind(field_type);
33,080✔
5199
   if (fkind == VCODE_TYPE_CARRAY)
33,080✔
5200
      result_type = bounds_type = vtype_elem(field_type);
4,558✔
5201
   else if (fkind == VCODE_TYPE_UARRAY) {
28,522✔
5202
      bounds_type = vtype_elem(field_type);
2,946✔
5203
      result_type = field_type;
2,946✔
5204
   }
5205

5206
   op->result = vcode_add_reg(vtype_pointer(result_type));
33,080✔
5207

5208
   reg_t *rr = vcode_reg_data(op->result);
33,080✔
5209
   rr->bounds = bounds_type;
33,080✔
5210

5211
   return op->result;
33,080✔
5212
}
5213

5214
vcode_reg_t emit_array_ref(vcode_reg_t array, vcode_reg_t offset)
33,316✔
5215
{
5216
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ARRAY_REF) {
1,657,780✔
5217
      if (other->args.items[0] == array && other->args.items[1] == offset)
104,135✔
5218
         return other->result;
1,188✔
5219
   }
5220

5221
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_REF);
32,128✔
5222
   vcode_add_arg(op, array);
32,128✔
5223
   vcode_add_arg(op, offset);
32,128✔
5224

5225
   vcode_type_t rtype = vcode_reg_type(array);
32,128✔
5226
   VCODE_ASSERT((vtype_kind(rtype) == VCODE_TYPE_POINTER
32,128✔
5227
                 && vtype_kind(vtype_pointed(rtype)) != VCODE_TYPE_UARRAY)
5228
                || vtype_kind(rtype) == VCODE_TYPE_SIGNAL,
5229
                "argument to array ref must be a pointer or signal");
5230
   VCODE_ASSERT(vcode_reg_kind(offset) == VCODE_TYPE_OFFSET,
32,128✔
5231
                "array ref offset argument must have offset type");
5232

5233
   op->result = vcode_add_reg(rtype);
32,128✔
5234

5235
   reg_t *rr = vcode_reg_data(op->result);
32,128✔
5236
   rr->bounds = vcode_reg_bounds(array);
32,128✔
5237

5238
   return op->result;
32,128✔
5239
}
5240

5241
void emit_copy(vcode_reg_t dest, vcode_reg_t src, vcode_reg_t count)
30,083✔
5242
{
5243
   int64_t cconst;
30,083✔
5244
   if (count != VCODE_INVALID_REG && vcode_reg_const(count, &cconst)
30,083✔
5245
       && cconst == 0)
20,211✔
5246
      return;
5,332✔
5247
   else if (dest == src)
29,340✔
5248
      return;
5249

5250
   op_t *op = vcode_add_op(VCODE_OP_COPY);
24,751✔
5251
   vcode_add_arg(op, dest);
24,751✔
5252
   vcode_add_arg(op, src);
24,751✔
5253
   if (count != VCODE_INVALID_REG)
24,751✔
5254
      vcode_add_arg(op, count);
23,176✔
5255

5256
   vcode_type_t dtype = vcode_reg_type(dest);
24,751✔
5257
   vcode_type_t stype = vcode_reg_type(src);
24,751✔
5258

5259
   vtype_kind_t dkind = vtype_kind(dtype);
24,751✔
5260
   vtype_kind_t skind = vtype_kind(stype);
24,751✔
5261

5262
   VCODE_ASSERT(dkind == VCODE_TYPE_POINTER || dkind == VCODE_TYPE_ACCESS,
24,751✔
5263
                "destination type is not a pointer or access");
5264
   VCODE_ASSERT(skind == VCODE_TYPE_POINTER || skind == VCODE_TYPE_ACCESS,
24,751✔
5265
                "source type is not a pointer or access");
5266
   VCODE_ASSERT(vtype_eq(dtype, stype),
24,751✔
5267
                "source and destination types do not match");
5268
   VCODE_ASSERT(count == VCODE_INVALID_REG
24,751✔
5269
                || vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
5270
                "count is not offset type");
5271

5272
   op->type = vtype_pointed(dtype);
24,751✔
5273
}
5274

5275
void emit_sched_event(vcode_reg_t nets, vcode_reg_t n_elems)
4,480✔
5276
{
5277
   VCODE_FOR_EACH_OP(other) {
63,538✔
5278
      if (other->kind == VCODE_OP_CLEAR_EVENT)
59,112✔
5279
         break;
5280
      else if (other->kind == VCODE_OP_SCHED_EVENT
59,064✔
5281
               && other->args.items[0] == nets
2,597✔
5282
               && other->args.items[1] == n_elems)
9✔
5283
         return;
5284
   }
5285

5286
   op_t *op = vcode_add_op(VCODE_OP_SCHED_EVENT);
4,474✔
5287
   vcode_add_arg(op, nets);
4,474✔
5288
   vcode_add_arg(op, n_elems);
4,474✔
5289

5290
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
4,474✔
5291
                "nets argument to sched event must be signal");
5292
}
5293

5294
void emit_clear_event(vcode_reg_t nets, vcode_reg_t n_elems)
550✔
5295
{
5296
   VCODE_FOR_EACH_OP(other) {
2,524✔
5297
      if (other->kind == VCODE_OP_SCHED_EVENT)
1,974✔
5298
         break;
5299
      else if (other->kind == VCODE_OP_CLEAR_EVENT
1,974✔
5300
               && other->args.items[0] == nets
39✔
UNCOV
5301
               && other->args.items[1] == n_elems)
×
5302
         return;
5303
   }
5304

5305
   op_t *op = vcode_add_op(VCODE_OP_CLEAR_EVENT);
550✔
5306
   vcode_add_arg(op, nets);
550✔
5307
   vcode_add_arg(op, n_elems);
550✔
5308

5309
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
550✔
5310
                "nets argument to clear event must be signal");
5311
}
5312

5313
void emit_sched_process(vcode_reg_t delay)
5,236✔
5314
{
5315
   op_t *op = vcode_add_op(VCODE_OP_SCHED_PROCESS);
5,236✔
5316
   vcode_add_arg(op, delay);
5,236✔
5317

5318
   VCODE_ASSERT(vcode_reg_kind(delay) == VCODE_TYPE_INT,
5,236✔
5319
                "delay must have integer type");
5320
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_PROCEDURE
5,236✔
5321
                || active_unit->kind == VCODE_UNIT_PROCESS,
5322
                "sched process only allowed in process or procedure");
5323
}
5,236✔
5324

5325
void emit_resume(ident_t func)
843✔
5326
{
5327
   op_t *op = vcode_add_op(VCODE_OP_RESUME);
843✔
5328
   op->func = func;
843✔
5329

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

5334
void emit_memset(vcode_reg_t ptr, vcode_reg_t value, vcode_reg_t len)
5,480✔
5335
{
5336
   int64_t lconst;
5,480✔
5337
   if (vcode_reg_const(len, &lconst) && lconst == 0)
5,480✔
5338
      return;
32✔
5339

5340
   op_t *op = vcode_add_op(VCODE_OP_MEMSET);
5,448✔
5341
   vcode_add_arg(op, ptr);
5,448✔
5342
   vcode_add_arg(op, value);
5,448✔
5343
   vcode_add_arg(op, len);
5,448✔
5344

5345
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
5,448✔
5346
                "target of memset must have pointer type");
5347
   VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(value)),
5,448✔
5348
                "value of memset must have scalar type");
5349
   VCODE_ASSERT(vtype_kind(vcode_reg_type(len)) == VCODE_TYPE_OFFSET,
5,448✔
5350
                "length of memset must have offset type");
5351
}
5352

5353
void emit_case(vcode_reg_t value, vcode_block_t def, const vcode_reg_t *cases,
641✔
5354
               const vcode_block_t *blocks, int ncases)
5355
{
5356
   int64_t cval1, cval2;
641✔
5357
   bool is_const = vcode_reg_const(value, &cval1);
641✔
5358

5359
   for (int i = 0; i < ncases; i++) {
3,663✔
5360
      bool can_fold = false;
3,025✔
5361
      if (cases[i] == value)
3,025✔
5362
         can_fold = true;
5363
      else if (is_const && vcode_reg_const(cases[i], &cval2))
3,025✔
5364
         can_fold = (cval1 == cval2);
3✔
5365

5366
      if (can_fold) {
3✔
5367
         emit_jump(blocks[i]);
3✔
5368
         return;
6✔
5369
      }
5370
   }
5371

5372
   if (is_const) {
638✔
UNCOV
5373
      emit_jump(def);
×
UNCOV
5374
      return;
×
5375
   }
5376

5377
   op_t *op = vcode_add_op(VCODE_OP_CASE);
638✔
5378
   vcode_add_arg(op, value);
638✔
5379
   vcode_add_target(op, def);
638✔
5380

5381
   for (int i = 0; i < ncases; i++) {
3,660✔
5382
      vcode_add_arg(op, cases[i]);
3,022✔
5383
      vcode_add_target(op, blocks[i]);
3,022✔
5384

5385
#ifdef DEBUG
5386
      for (int j = 0; j < i; j++)
15,545✔
5387
         VCODE_ASSERT(cases[i] != cases[j], "duplicate case choice");
12,523✔
5388
#endif
5389
   }
5390
}
5391

5392
void emit_file_open(vcode_reg_t file, vcode_reg_t name, vcode_reg_t length,
1,219✔
5393
                    vcode_reg_t kind, vcode_reg_t status)
5394
{
5395
   op_t *op = vcode_add_op(VCODE_OP_FILE_OPEN);
1,219✔
5396
   vcode_add_arg(op, file);
1,219✔
5397
   vcode_add_arg(op, name);
1,219✔
5398
   vcode_add_arg(op, length);
1,219✔
5399
   vcode_add_arg(op, kind);
1,219✔
5400
   if (status != VCODE_INVALID_REG)
1,219✔
5401
      vcode_add_arg(op, status);
25✔
5402

5403
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
1,219✔
5404
                "file open first argument must have file pointer type");
5405
}
1,219✔
5406

5407
void emit_file_write(vcode_reg_t file, vcode_reg_t value, vcode_reg_t length)
255✔
5408
{
5409
   op_t *op = vcode_add_op(VCODE_OP_FILE_WRITE);
255✔
5410
   vcode_add_arg(op, file);
255✔
5411
   vcode_add_arg(op, value);
255✔
5412
   if (length != VCODE_INVALID_REG)
255✔
5413
      vcode_add_arg(op, length);
198✔
5414

5415
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
255✔
5416
                "file write first argument must have file pointer type");
5417
}
255✔
5418

5419
void emit_file_read(vcode_reg_t file, vcode_reg_t ptr,
90✔
5420
                    vcode_reg_t inlen, vcode_reg_t outlen)
5421
{
5422
   op_t *op = vcode_add_op(VCODE_OP_FILE_READ);
90✔
5423
   vcode_add_arg(op, file);
90✔
5424
   vcode_add_arg(op, ptr);
90✔
5425
   if (inlen != VCODE_INVALID_REG) {
90✔
5426
      vcode_add_arg(op, inlen);
42✔
5427
      if (outlen != VCODE_INVALID_REG)
42✔
5428
         vcode_add_arg(op, outlen);
33✔
5429
   }
5430

5431
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
90✔
5432
                "file read first argument must have file pointer type");
5433
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
90✔
5434
                "file read pointer argument must have pointer type");
5435
   VCODE_ASSERT(outlen == VCODE_INVALID_REG
90✔
5436
                || vtype_kind(vcode_reg_type(outlen)) == VCODE_TYPE_POINTER,
5437
                "file read outlen argument must have pointer type");
5438
}
90✔
5439

5440
vcode_reg_t emit_null(vcode_type_t type)
12,620✔
5441
{
5442
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_NULL) {
254,254✔
5443
      if (vtype_eq(vcode_reg_type(other->result), type))
7,543✔
5444
         return other->result;
4,007✔
5445
   }
5446

5447
   op_t *op = vcode_add_op(VCODE_OP_NULL);
8,613✔
5448
   op->result = vcode_add_reg(type);
8,613✔
5449

5450
   vtype_kind_t kind = vtype_kind(type);
8,613✔
5451
   VCODE_ASSERT(kind == VCODE_TYPE_POINTER || kind == VCODE_TYPE_FILE
8,613✔
5452
                || kind == VCODE_TYPE_ACCESS || kind == VCODE_TYPE_CONTEXT,
5453
                "null type must be file, access, context, or pointer");
5454

5455
   return op->result;
5456
}
5457

5458
vcode_reg_t emit_new(vcode_type_t type, vcode_reg_t length)
636✔
5459
{
5460
   op_t *op = vcode_add_op(VCODE_OP_NEW);
636✔
5461
   if (length != VCODE_INVALID_REG)
636✔
5462
      vcode_add_arg(op, length);
545✔
5463

5464
   op->result = vcode_add_reg(vtype_access(type));
636✔
5465

5466
   vtype_kind_t kind = vtype_kind(type);
636✔
5467
   VCODE_ASSERT(kind == VCODE_TYPE_INT || kind == VCODE_TYPE_RECORD
636✔
5468
                || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_ACCESS
5469
                || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_CONTEXT,
5470
                "new type must be int, real, record, access, or uarray");
5471
   VCODE_ASSERT(length == VCODE_INVALID_REG
636✔
5472
                || vtype_kind(vcode_reg_type(length)) == VCODE_TYPE_OFFSET,
5473
                "new length must have offset type");
5474

5475
   return op->result;
636✔
5476
}
5477

5478
void emit_null_check(vcode_reg_t ptr, vcode_reg_t locus)
2,896✔
5479
{
5480
   VCODE_FOR_EACH_OP(other) {
120,047✔
5481
      if (other->kind == VCODE_OP_NULL_CHECK && other->args.items[0] == ptr)
117,895✔
5482
         return;
5483
      else if (other->kind == VCODE_OP_NEW && other->result == ptr)
117,474✔
5484
         return;
5485
   }
5486

5487
   op_t *op = vcode_add_op(VCODE_OP_NULL_CHECK);
2,152✔
5488
   vcode_add_arg(op, ptr);
2,152✔
5489
   vcode_add_arg(op, locus);
2,152✔
5490

5491
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_ACCESS,
2,152✔
5492
                "null check argument must be an access");
5493
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,152✔
5494
                "locus argument to null check must be a debug locus");
5495
}
5496

5497
void emit_deallocate(vcode_reg_t ptr)
335✔
5498
{
5499
   op_t *op = vcode_add_op(VCODE_OP_DEALLOCATE);
335✔
5500
   vcode_add_arg(op, ptr);
335✔
5501

5502
   vcode_type_t ptype = vcode_reg_type(ptr);
335✔
5503
   VCODE_ASSERT(vtype_kind(ptype) == VCODE_TYPE_POINTER
335✔
5504
                && vtype_kind(vtype_pointed(ptype)) == VCODE_TYPE_ACCESS,
5505
                "deallocate argument must be pointer to access");
5506
}
335✔
5507

5508
vcode_reg_t emit_all(vcode_reg_t reg)
3,532✔
5509
{
5510
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ALL) {
168,009✔
5511
      if (other->args.items[0] == reg)
10,246✔
5512
         return other->result;
744✔
5513
   }
5514

5515
   op_t *op = vcode_add_op(VCODE_OP_ALL);
2,788✔
5516
   vcode_add_arg(op, reg);
2,788✔
5517

5518
   vcode_type_t vtype = vcode_reg_type(reg);
2,788✔
5519

5520
   VCODE_ASSERT(vtype_kind(vtype) == VCODE_TYPE_ACCESS,
2,788✔
5521
                "all argument must be an access");
5522

5523
   vcode_type_t pointed = vtype_pointed(vtype);
2,788✔
5524
   op->result = vcode_add_reg(vtype_pointer(pointed));
2,788✔
5525

5526
   reg_t *rr = vcode_reg_data(op->result);
2,788✔
5527
   rr->bounds = pointed;
2,788✔
5528

5529
   VCODE_ASSERT(vtype_kind(pointed) != VCODE_TYPE_OPAQUE,
2,788✔
5530
                "cannot dereference opaque type");
5531

5532
   return op->result;
5533
}
5534

5535
static vcode_reg_t emit_signal_data_op(vcode_op_t kind, vcode_reg_t sig)
13,633✔
5536
{
5537
   block_t *b = &(active_unit->blocks.items[active_block]);
13,633✔
5538
   for (int i = b->ops.count - 1; i >= 0; i--) {
325,527✔
5539
      const op_t *other = &(b->ops.items[i]);
312,449✔
5540
      if (other->kind == kind && other->args.items[0] == sig)
312,449✔
5541
         return other->result;
555✔
5542
   }
5543

5544
   op_t *op = vcode_add_op(kind);
13,078✔
5545
   vcode_add_arg(op, sig);
13,078✔
5546

5547
   vcode_type_t stype = vcode_reg_type(sig);
13,078✔
5548
   op->type = stype;
13,078✔
5549

5550
   VCODE_ASSERT(vtype_kind(stype) == VCODE_TYPE_SIGNAL,
13,078✔
5551
                "argument r%d to resolved is not a signal", sig);
5552

5553
   vcode_type_t rtype = vtype_base(stype);
13,078✔
5554

5555
   const vtype_kind_t rkind = vtype_kind(rtype);
13,078✔
5556
   if (rkind == VCODE_TYPE_CARRAY || rkind == VCODE_TYPE_UARRAY)
13,078✔
UNCOV
5557
      rtype = vtype_elem(rtype);
×
5558

5559
   VCODE_ASSERT(vtype_is_scalar(rtype),
13,078✔
5560
                "resolved signal base type must be scalar");
5561

5562
   op->result = vcode_add_reg(vtype_pointer(rtype));
13,078✔
5563

5564
   reg_t *rr = vcode_reg_data(op->result);
13,078✔
5565
   rr->bounds = rtype;
13,078✔
5566

5567
   return op->result;
13,078✔
5568
}
5569

5570
vcode_reg_t emit_resolved(vcode_reg_t sig, vcode_reg_t count)
13,444✔
5571
{
5572
   return emit_signal_data_op(VCODE_OP_RESOLVED, sig);
13,444✔
5573
}
5574

5575
vcode_reg_t emit_last_value(vcode_reg_t sig, vcode_reg_t count)
189✔
5576
{
5577
   return emit_signal_data_op(VCODE_OP_LAST_VALUE, sig);
189✔
5578
}
5579

5580
vcode_reg_t emit_last_event(vcode_reg_t signal, vcode_reg_t len)
42✔
5581
{
5582
   op_t *op = vcode_add_op(VCODE_OP_LAST_EVENT);
42✔
5583
   vcode_add_arg(op, signal);
42✔
5584
   if (len != VCODE_INVALID_REG)
42✔
5585
      vcode_add_arg(op, len);
9✔
5586

5587
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
42✔
5588
                "signal argument to last event must have signal type");
5589
   VCODE_ASSERT(len == VCODE_INVALID_REG
42✔
5590
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5591
                "length argument to last event must have offset type");
5592

5593
   return (op->result = vcode_add_reg(vtype_time()));
42✔
5594
}
5595

5596
vcode_reg_t emit_last_active(vcode_reg_t signal, vcode_reg_t len)
45✔
5597
{
5598
   op_t *op = vcode_add_op(VCODE_OP_LAST_ACTIVE);
45✔
5599
   vcode_add_arg(op, signal);
45✔
5600
   if (len != VCODE_INVALID_REG)
45✔
5601
      vcode_add_arg(op, len);
6✔
5602

5603
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
45✔
5604
                "signal argument to last active must have signal type");
5605
   VCODE_ASSERT(len == VCODE_INVALID_REG
45✔
5606
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5607
                "length argument to last active must have offset type");
5608

5609
   return (op->result = vcode_add_reg(vtype_time()));
45✔
5610
}
5611

5612
void emit_alias_signal(vcode_reg_t signal, vcode_reg_t locus)
4,290✔
5613
{
5614
   op_t *op = vcode_add_op(VCODE_OP_ALIAS_SIGNAL);
4,290✔
5615
   vcode_add_arg(op, signal);
4,290✔
5616
   vcode_add_arg(op, locus);
4,290✔
5617

5618
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
4,290✔
5619
                "signal argument must have signal type");
5620
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
4,290✔
5621
                "locus argument must have debug locus type");
5622
}
4,290✔
5623

5624
vcode_reg_t emit_driving_flag(vcode_reg_t signal, vcode_reg_t len)
36✔
5625
{
5626
   op_t *op = vcode_add_op(VCODE_OP_DRIVING);
36✔
5627
   vcode_add_arg(op, signal);
36✔
5628
   vcode_add_arg(op, len);
36✔
5629

5630
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
36✔
5631
                "signal argument to last active must have signal type");
5632
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
36✔
5633
                "length argument to last active must have offset type");
5634

5635
   return (op->result = vcode_add_reg(vtype_bool()));
36✔
5636
}
5637

5638
vcode_reg_t emit_driving_value(vcode_reg_t signal, vcode_reg_t len)
120✔
5639
{
5640
   op_t *op = vcode_add_op(VCODE_OP_DRIVING_VALUE);
120✔
5641
   vcode_add_arg(op, signal);
120✔
5642
   if (len != VCODE_INVALID_REG)
120✔
5643
      vcode_add_arg(op, len);
36✔
5644

5645
   vcode_type_t signal_type = vcode_reg_type(signal);
120✔
5646

5647
   VCODE_ASSERT(vtype_kind(signal_type) == VCODE_TYPE_SIGNAL,
120✔
5648
                "signal argument to last active must have signal type");
5649
   VCODE_ASSERT(len == VCODE_INVALID_REG
120✔
5650
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5651
                "length argument to last active must have offset type");
5652

5653
   vcode_type_t base_type = vtype_base(signal_type);
120✔
5654
   op->result = vcode_add_reg(vtype_pointer(base_type));
120✔
5655

5656
   reg_t *rr = vcode_reg_data(op->result);
120✔
5657
   rr->bounds = base_type;
120✔
5658

5659
   return op->result;
120✔
5660
}
5661

5662
void emit_length_check(vcode_reg_t llen, vcode_reg_t rlen, vcode_reg_t locus,
32,619✔
5663
                       vcode_reg_t dim)
5664
{
5665
   if (rlen == llen)
32,619✔
5666
      return;
5667

5668
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LENGTH_CHECK) {
196,954✔
5669
      if (other->args.items[0] == llen && other->args.items[1] == rlen)
2,634✔
5670
         return;
5671
   }
5672

5673
   op_t *op = vcode_add_op(VCODE_OP_LENGTH_CHECK);
7,178✔
5674
   vcode_add_arg(op, llen);
7,178✔
5675
   vcode_add_arg(op, rlen);
7,178✔
5676
   vcode_add_arg(op, locus);
7,178✔
5677
   if (dim != VCODE_INVALID_REG)
7,178✔
5678
      vcode_add_arg(op, dim);
27✔
5679

5680
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
7,178✔
5681
                "locus argument to length check must be a debug locus");
5682
}
5683

5684
void emit_exponent_check(vcode_reg_t exp, vcode_reg_t locus)
411✔
5685
{
5686
   int64_t cval;
411✔
5687
   if (vcode_reg_const(exp, &cval) && cval >= 0)
411✔
5688
      return;
47✔
5689

5690
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_EXPONENT_CHECK) {
4,195✔
5691
      if (other->args.items[0] == exp)
12✔
5692
         return;
5693
   }
5694

5695
   op_t *op = vcode_add_op(VCODE_OP_EXPONENT_CHECK);
364✔
5696
   vcode_add_arg(op, exp);
364✔
5697
   vcode_add_arg(op, locus);
364✔
5698

5699
   VCODE_ASSERT(vcode_reg_kind(exp) == VCODE_TYPE_INT,
364✔
5700
                "exp argument to exponent check must be a integer");
5701
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
364✔
5702
                "locus argument to exponent check must be a debug locus");
5703
}
5704

5705
void emit_zero_check(vcode_reg_t denom, vcode_reg_t locus)
2,443✔
5706
{
5707
   int64_t cval;
2,443✔
5708
   if (vcode_reg_const(denom, &cval) && cval != 0)
2,443✔
5709
      return;
2,352✔
5710

5711
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ZERO_CHECK) {
2,305✔
5712
      if (other->args.items[0] == denom)
48✔
5713
         return;
5714
   }
5715

5716
   op_t *op = vcode_add_op(VCODE_OP_ZERO_CHECK);
91✔
5717
   vcode_add_arg(op, denom);
91✔
5718
   vcode_add_arg(op, locus);
91✔
5719

5720
   VCODE_ASSERT(vcode_reg_kind(denom) == VCODE_TYPE_INT,
91✔
5721
                "denom argument to zero check must be a integer");
5722
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
91✔
5723
                "locus argument to zero check must be a debug locus");
5724
}
5725

5726
static bool vcode_can_elide_bounds(vcode_reg_t reg, vcode_reg_t left,
84,882✔
5727
                                   vcode_reg_t right, vcode_reg_t dir)
5728
{
5729
   int64_t dconst;
84,882✔
5730
   if (vcode_reg_const(dir, &dconst)) {
84,882✔
5731
      int64_t lconst, rconst;
75,042✔
5732
      if (vcode_reg_const(left, &lconst) && vcode_reg_const(right, &rconst)) {
75,042✔
5733
         const bool is_null = (dconst == RANGE_TO && lconst > rconst)
50,885✔
5734
            || (dconst == RANGE_DOWNTO && rconst > lconst);
104,705✔
5735

5736
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
53,821✔
5737

5738
         const bool ok_static =
107,642✔
5739
            (dconst == RANGE_TO
5740
             && bounds->low >= lconst && bounds->high <= rconst)
50,885✔
5741
            || (dconst == RANGE_DOWNTO
8,924✔
5742
                && bounds->low >= rconst && bounds->high <= lconst)
2,936✔
5743
            || (!is_null && (reg == left || reg == right));
60,115✔
5744

5745
         return ok_static;
72,281✔
5746
      }
5747
      else if (vcode_reg_kind(reg) == VCODE_TYPE_REAL) {
21,221✔
5748
         vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
19,161✔
5749
         vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
19,161✔
5750

5751
         assert(lbounds->kind == VCODE_TYPE_REAL);
19,161✔
5752
         assert(rbounds->kind == VCODE_TYPE_REAL);
19,161✔
5753

5754
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
19,161✔
5755
         assert(bounds->kind == VCODE_TYPE_REAL);
19,161✔
5756

5757
         if (isfinite(bounds->rlow) && lbounds->rlow == -DBL_MAX
19,161✔
5758
             && isfinite(bounds->rhigh) && rbounds->rhigh == DBL_MAX) {
18,460✔
5759
            // Covers the complete double range so can never overflow
5760
            return true;
5761
         }
5762
      }
5763
   }
5764

5765
   return false;
5766
}
5767

5768
static void emit_bounds_check(vcode_op_t kind, vcode_reg_t reg,
85,773✔
5769
                              vcode_reg_t left, vcode_reg_t right,
5770
                              vcode_reg_t dir, vcode_reg_t locus,
5771
                              vcode_reg_t hint)
5772
{
5773
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
3,633,736✔
5774
      if (other->args.items[0] == reg && other->args.items[1] == left
18,177✔
5775
          && other->args.items[2] == right && other->args.items[3] == dir)
1,057✔
5776
         return;
5777
   }
5778

5779
   if (vcode_can_elide_bounds(reg, left, right, dir)) {
84,882✔
5780
      emit_comment("Elided bounds check for r%d", reg);
65,987✔
5781
      return;
65,987✔
5782
   }
5783

5784
   op_t *op = vcode_add_op(kind);
18,895✔
5785
   vcode_add_arg(op, reg);
18,895✔
5786
   vcode_add_arg(op, left);
18,895✔
5787
   vcode_add_arg(op, right);
18,895✔
5788
   vcode_add_arg(op, dir);
18,895✔
5789
   vcode_add_arg(op, locus);
18,895✔
5790
   vcode_add_arg(op, hint);
18,895✔
5791

5792
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
18,895✔
5793
                "locus argument to bounds check must be a debug locus");
5794
   VCODE_ASSERT(vcode_reg_kind(hint) == VCODE_TYPE_DEBUG_LOCUS,
18,895✔
5795
                "hint argument to bounds check must be a debug locus");
5796
}
5797

5798
void emit_range_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
22,754✔
5799
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5800
{
5801
   emit_bounds_check(VCODE_OP_RANGE_CHECK, reg, left, right, dir, locus, hint);
22,754✔
5802
}
22,754✔
5803

5804
void emit_index_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
63,019✔
5805
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5806
{
5807
   emit_bounds_check(VCODE_OP_INDEX_CHECK, reg, left, right, dir, locus, hint);
63,019✔
5808
}
63,019✔
5809

5810
void emit_dir_check(vcode_reg_t reg, vcode_reg_t dir, vcode_reg_t locus)
3,169✔
5811
{
5812
   if (reg == dir)
3,169✔
5813
      return;
5814

5815
   op_t *op = vcode_add_op(VCODE_OP_DIR_CHECK);
2,359✔
5816
   vcode_add_arg(op, reg);
2,359✔
5817
   vcode_add_arg(op, dir);
2,359✔
5818
   vcode_add_arg(op, locus);
2,359✔
5819

5820
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,359✔
5821
                "locus argument to dir check must be a debug locus");
5822
}
5823

5824
void emit_package_scope(vcode_reg_t locus)
45✔
5825
{
5826
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_SCOPE);
45✔
5827
   vcode_add_arg(op, locus);
45✔
5828

5829
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
45✔
5830
                "locus argument to package scope must be a debug locus");
5831
}
45✔
5832

5833
void emit_array_scope(vcode_reg_t locus, vcode_type_t type)
648✔
5834
{
5835
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_SCOPE);
648✔
5836
   vcode_add_arg(op, locus);
648✔
5837
   op->type = type;
648✔
5838

5839
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
648✔
5840
                "locus argument to array scope must be a debug locus");
5841
}
648✔
5842

5843
void emit_record_scope(vcode_reg_t locus, vcode_type_t type)
1,684✔
5844
{
5845
   op_t *op = vcode_add_op(VCODE_OP_RECORD_SCOPE);
1,684✔
5846
   vcode_add_arg(op, locus);
1,684✔
5847
   op->type = type;
1,684✔
5848

5849
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,684✔
5850
                "locus argument to record scope must be a debug locus");
5851
}
1,684✔
5852

5853
void emit_pop_scope(void)
2,377✔
5854
{
5855
   vcode_add_op(VCODE_OP_POP_SCOPE);
2,377✔
5856
}
2,377✔
5857

5858
vcode_reg_t emit_debug_locus(object_t *obj)
175,233✔
5859
{
5860
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DEBUG_LOCUS) {
6,619,600✔
5861
      if (other->object == obj)
818,981✔
5862
         return other->result;
18,743✔
5863
   }
5864

5865
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_LOCUS);
156,490✔
5866
   op->object = obj;
156,490✔
5867

5868
   return (op->result = vcode_add_reg(vtype_debug_locus()));
156,490✔
5869
}
5870

UNCOV
5871
void emit_debug_out(vcode_reg_t reg)
×
5872
{
UNCOV
5873
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_OUT);
×
UNCOV
5874
   vcode_add_arg(op, reg);
×
UNCOV
5875
}
×
5876

5877
void emit_cover_stmt(uint32_t tag)
1,300✔
5878
{
5879
   op_t *op = vcode_add_op(VCODE_OP_COVER_STMT);
1,300✔
5880
   op->tag = tag;
1,300✔
5881
}
1,300✔
5882

5883
void emit_cover_branch(uint32_t tag)
499✔
5884
{
5885
   op_t *op = vcode_add_op(VCODE_OP_COVER_BRANCH);
499✔
5886
   op->tag = tag;
499✔
5887
}
499✔
5888

5889
void emit_cover_toggle(vcode_reg_t signal, uint32_t tag)
312✔
5890
{
5891
   op_t *op = vcode_add_op(VCODE_OP_COVER_TOGGLE);
312✔
5892
   vcode_add_arg(op, signal);
312✔
5893
   op->tag = tag;
312✔
5894
}
312✔
5895

5896
void emit_cover_state(vcode_reg_t signal, vcode_reg_t low, uint32_t tag)
12✔
5897
{
5898
   op_t *op = vcode_add_op(VCODE_OP_COVER_STATE);
12✔
5899
   vcode_add_arg(op, signal);
12✔
5900
   vcode_add_arg(op, low);
12✔
5901
   op->tag = tag;
12✔
5902
}
12✔
5903

5904
void emit_cover_expr(uint32_t tag)
887✔
5905
{
5906
   op_t *op = vcode_add_op(VCODE_OP_COVER_EXPR);
887✔
5907
   op->tag = tag;
887✔
5908
}
887✔
5909

5910
void emit_unreachable(vcode_reg_t locus)
1,350✔
5911
{
5912
   op_t *op = vcode_add_op(VCODE_OP_UNREACHABLE);
1,350✔
5913
   if (locus != VCODE_INVALID_REG)
1,350✔
5914
      vcode_add_arg(op, locus);
115✔
5915
}
1,350✔
5916

5917
vcode_reg_t emit_undefined(vcode_type_t type, vcode_type_t bounds)
63✔
5918
{
5919
   active_unit->flags |= UNIT_UNDEFINED;
63✔
5920

5921
   op_t *op = vcode_add_op(VCODE_OP_UNDEFINED);
63✔
5922
   op->result = vcode_add_reg(type);
63✔
5923
   vcode_reg_data(op->result)->bounds = bounds;
63✔
5924

5925
   return op->result;
63✔
5926
}
5927

5928
void emit_debug_info(const loc_t *loc)
2,439,849✔
5929
{
5930
   if (!loc_invalid_p(loc))
2,439,849✔
5931
      vcode_block_data()->last_loc = *loc;
2,417,754✔
5932
}
2,439,849✔
5933

5934
vcode_reg_t emit_link_var(vcode_reg_t context, ident_t name, vcode_type_t type)
8,117✔
5935
{
5936
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_VAR) {
291,908✔
5937
      if (other->args.items[0] == context && other->ident == name)
11,645✔
5938
         return other->result;
3,790✔
5939
   }
5940

5941
   op_t *op = vcode_add_op(VCODE_OP_LINK_VAR);
4,327✔
5942
   vcode_add_arg(op, context);
4,327✔
5943
   op->ident = name;
4,327✔
5944

5945
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
4,327✔
5946
                "first argument to link var must be context");
5947

5948
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
4,327✔
5949
      op->result = vcode_add_reg(vtype_pointer(vtype_elem(type)));
79✔
5950
      vcode_reg_data(op->result)->bounds = vtype_bounds(type);
79✔
5951
   }
5952
   else {
5953
      op->result = vcode_add_reg(vtype_pointer(type));
4,248✔
5954
      vcode_reg_data(op->result)->bounds = type;
4,248✔
5955
   }
5956

5957
   return op->result;
4,327✔
5958
}
5959

5960
vcode_reg_t emit_link_package(ident_t name)
12,814✔
5961
{
5962
   VCODE_FOR_EACH_OP(other) {
462,123✔
5963
      if (other->kind == VCODE_OP_LINK_PACKAGE && other->ident == name)
455,470✔
5964
         return other->result;
5,616✔
5965
      else if (other->kind == VCODE_OP_PACKAGE_INIT && other->func == name)
449,854✔
5966
         return other->result;
545✔
5967
   }
5968

5969
   op_t *op = vcode_add_op(VCODE_OP_LINK_PACKAGE);
6,653✔
5970
   op->ident = name;
6,653✔
5971

5972
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
6,653✔
5973

5974
   return (op->result = vcode_add_reg(vtype_context(name)));
6,653✔
5975
}
5976

5977
void emit_enter_state(vcode_reg_t state, vcode_reg_t strong)
849✔
5978
{
5979
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ENTER_STATE) {
2,046✔
UNCOV
5980
      if (other->args.items[0] == state)
×
5981
         return;
5982
   }
5983

5984
   op_t *op = vcode_add_op(VCODE_OP_ENTER_STATE);
849✔
5985
   vcode_add_arg(op, state);
849✔
5986
   if (strong != VCODE_INVALID_REG)
849✔
5987
      vcode_add_arg(op, strong);
36✔
5988

5989
   VCODE_ASSERT(vcode_reg_kind(state) == VCODE_TYPE_INT,
849✔
5990
                "state must have integer type");
5991
   VCODE_ASSERT(strong == VCODE_INVALID_REG
849✔
5992
                || vtype_eq(vcode_reg_type(strong), vtype_bool()),
5993
                "strong argument not is not boolean");
5994
}
5995

5996
vcode_reg_t emit_reflect_value(vcode_reg_t value, vcode_reg_t context,
48✔
5997
                               vcode_reg_t locus, vcode_reg_t bounds)
5998
{
5999
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_VALUE);
48✔
6000
   vcode_add_arg(op, value);
48✔
6001
   vcode_add_arg(op, context);
48✔
6002
   vcode_add_arg(op, locus);
48✔
6003
   if (bounds != VCODE_INVALID_REG)
48✔
6004
      vcode_add_arg(op, bounds);
6✔
6005

6006
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
48✔
6007
                "invalid reflect value context argument");
6008
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
48✔
6009
                "locus argument to reflect value must be a debug locus");
6010

6011
   return (op->result = vcode_add_reg(vtype_access(vtype_opaque())));
48✔
6012
}
6013

6014
vcode_reg_t emit_reflect_subtype(vcode_reg_t context, vcode_reg_t locus,
42✔
6015
                                 vcode_reg_t bounds)
6016
{
6017
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_SUBTYPE);
42✔
6018
   vcode_add_arg(op, context);
42✔
6019
   vcode_add_arg(op, locus);
42✔
6020
   if (bounds != VCODE_INVALID_REG)
42✔
UNCOV
6021
      vcode_add_arg(op, bounds);
×
6022

6023
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
42✔
6024
                "invalid reflect value context argument");
6025
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
42✔
6026
                "locus argument to reflect value must be a debug locus");
6027

6028
   return (op->result = vcode_add_reg(vtype_access(vtype_opaque())));
42✔
6029
}
6030

6031
vcode_reg_t emit_function_trigger(ident_t func, const vcode_reg_t *args,
202✔
6032
                                  int nargs)
6033
{
6034
   op_t *op = vcode_add_op(VCODE_OP_FUNCTION_TRIGGER);
202✔
6035
   op->func = func;
202✔
6036

6037
   for (int i = 0; i < nargs; i++)
489✔
6038
      vcode_add_arg(op, args[i]);
287✔
6039

6040
   return (op->result = vcode_add_reg(vtype_trigger()));
202✔
6041
}
6042

6043
vcode_reg_t emit_or_trigger(vcode_reg_t left, vcode_reg_t right)
34✔
6044
{
6045
   op_t *op = vcode_add_op(VCODE_OP_OR_TRIGGER);
34✔
6046
   vcode_add_arg(op, left);
34✔
6047
   vcode_add_arg(op, right);
34✔
6048

6049
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_TRIGGER,
34✔
6050
                "or trigger left argument must be trigger");
6051
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_TRIGGER,
34✔
6052
                "or trigger right argument must be trigger");
6053

6054
   return (op->result = vcode_add_reg(vtype_trigger()));
34✔
6055
}
6056

6057
vcode_reg_t emit_cmp_trigger(vcode_reg_t left, vcode_reg_t right)
66✔
6058
{
6059
   op_t *op = vcode_add_op(VCODE_OP_CMP_TRIGGER);
66✔
6060
   vcode_add_arg(op, left);
66✔
6061
   vcode_add_arg(op, right);
66✔
6062

6063
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_SIGNAL,
66✔
6064
                "cmp trigger left argument must be signal");
6065
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_INT,
66✔
6066
                "cmp trigger right argument must be integer");
6067

6068
   return (op->result = vcode_add_reg(vtype_trigger()));
66✔
6069
}
6070

6071
void emit_add_trigger(vcode_reg_t trigger)
368✔
6072
{
6073
   op_t *op = vcode_add_op(VCODE_OP_ADD_TRIGGER);
368✔
6074
   vcode_add_arg(op, trigger);
368✔
6075

6076
   VCODE_ASSERT(vcode_reg_kind(trigger) == VCODE_TYPE_TRIGGER,
368✔
6077
                "add trigger argument must be trigger");
6078
}
368✔
6079

6080
vcode_reg_t emit_port_conversion(vcode_reg_t driving, vcode_reg_t effective)
204✔
6081
{
6082
   op_t *op = vcode_add_op(VCODE_OP_PORT_CONVERSION);
204✔
6083
   vcode_add_arg(op, driving);
204✔
6084
   if (effective != VCODE_INVALID_REG && effective != driving)
204✔
6085
      vcode_add_arg(op, effective);
18✔
6086

6087
   VCODE_ASSERT(vcode_reg_kind(driving) == VCODE_TYPE_CLOSURE,
204✔
6088
                "port conversion argument must be a closure");
6089
   VCODE_ASSERT(effective == VCODE_INVALID_REG
204✔
6090
                || vcode_reg_kind(effective) == VCODE_TYPE_CLOSURE,
6091
                "port conversion argument must be a closure");
6092

6093
   return (op->result = vcode_add_reg(vtype_conversion()));
204✔
6094
}
6095

6096
vcode_reg_t emit_bind_external(vcode_reg_t locus, ident_t scope,
180✔
6097
                               vcode_type_t type, vcode_type_t bounds,
6098
                               const vcode_reg_t *args, int nargs)
6099
{
6100
   op_t *op = vcode_add_op(VCODE_OP_BIND_EXTERNAL);
180✔
6101
   op->type  = type;
180✔
6102
   op->ident = scope;
180✔
6103
   vcode_add_arg(op, locus);
180✔
6104
   for (int i = 0; i < nargs; i++)
210✔
6105
      vcode_add_arg(op, args[i]);
30✔
6106

6107
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
180✔
6108
                "bind external argument must be locus");
6109

6110
   op->result = vcode_add_reg(vtype_pointer(type));
180✔
6111
   vcode_reg_data(op->result)->bounds = bounds;
180✔
6112
   return op->result;
180✔
6113
}
6114

6115
void emit_put_conversion(vcode_reg_t cf, vcode_reg_t target, vcode_reg_t count,
342✔
6116
                         vcode_reg_t values)
6117
{
6118
   op_t *op = vcode_add_op(VCODE_OP_PUT_CONVERSION);
342✔
6119
   vcode_add_arg(op, cf);
342✔
6120
   vcode_add_arg(op, target);
342✔
6121
   vcode_add_arg(op, count);
342✔
6122
   vcode_add_arg(op, values);
342✔
6123

6124
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
342✔
6125
                "put conversion target is not signal");
6126
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
342✔
6127
                "put conversion net count is not offset type");
6128
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
342✔
6129
                "signal cannot be values argument for put conversion");
6130
   VCODE_ASSERT(vcode_reg_kind(cf) == VCODE_TYPE_CONVERSION,
342✔
6131
                "cf argument to put conversion must be conversion function");
6132
}
342✔
6133

6134
void emit_convert_in(vcode_reg_t conv, vcode_reg_t nets, vcode_reg_t count)
282✔
6135
{
6136
   op_t *op = vcode_add_op(VCODE_OP_CONVERT_IN);
282✔
6137
   vcode_add_arg(op, conv);
282✔
6138
   vcode_add_arg(op, nets);
282✔
6139
   vcode_add_arg(op, count);
282✔
6140

6141
   VCODE_ASSERT(vcode_reg_kind(conv) == VCODE_TYPE_CONVERSION,
282✔
6142
                "conv argument to convert must be a port conversion");
6143
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
282✔
6144
                "nets argument to convert must be a signal");
6145
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
282✔
6146
                "count argument to convert must be offset");
6147
}
282✔
6148

6149
void emit_convert_out(vcode_reg_t conv, vcode_reg_t nets, vcode_reg_t count)
324✔
6150
{
6151
   op_t *op = vcode_add_op(VCODE_OP_CONVERT_OUT);
324✔
6152
   vcode_add_arg(op, conv);
324✔
6153
   vcode_add_arg(op, nets);
324✔
6154
   vcode_add_arg(op, count);
324✔
6155

6156
   VCODE_ASSERT(vcode_reg_kind(conv) == VCODE_TYPE_CONVERSION,
324✔
6157
                "conv argument to convert must be a port conversion");
6158
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
324✔
6159
                "nets argument to convert must be a signal");
6160
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
324✔
6161
                "count argument to convert must be offset");
6162
}
324✔
6163

6164
void emit_bind_foreign(vcode_reg_t spec, vcode_reg_t length, vcode_reg_t locus)
1,004✔
6165
{
6166
   op_t *op = vcode_add_op(VCODE_OP_BIND_FOREIGN);
1,004✔
6167
   vcode_add_arg(op, spec);
1,004✔
6168
   vcode_add_arg(op, length);
1,004✔
6169
   if (locus != VCODE_INVALID_REG)
1,004✔
6170
      vcode_add_arg(op, locus);
830✔
6171

6172
   VCODE_ASSERT(vcode_reg_kind(spec) == VCODE_TYPE_POINTER,
1,004✔
6173
                "spec argument to bind foreign must be a pointer");
6174
   VCODE_ASSERT(vcode_reg_kind(length) == VCODE_TYPE_OFFSET,
1,004✔
6175
                "length argument to bind foreign must be offset");
6176
   VCODE_ASSERT(locus == VCODE_INVALID_REG
1,004✔
6177
                || vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
6178
                "locus argument to bind foreign value must be a debug locus");
6179
}
1,004✔
6180

6181
vcode_reg_t emit_instance_name(vcode_reg_t kind)
767✔
6182
{
6183
   op_t *op = vcode_add_op(VCODE_OP_INSTANCE_NAME);
767✔
6184
   vcode_add_arg(op, kind);
767✔
6185

6186
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
767✔
6187
                "kind argument to instance name must be offset");
6188

6189
   vcode_type_t vchar = vtype_char();
767✔
6190
   return (op->result = vcode_add_reg(vtype_uarray(1, vchar, vchar)));
767✔
6191
}
6192

6193
void vcode_walk_dependencies(vcode_unit_t vu, vcode_dep_fn_t fn, void *ctx)
15,320✔
6194
{
6195
   vcode_state_t state;
15,320✔
6196
   vcode_state_save(&state);
15,320✔
6197

6198
   vcode_select_unit(vu);
15,320✔
6199

6200
   const int nblocks = vcode_count_blocks();
15,320✔
6201
   for (int i = 0; i < nblocks; i++) {
54,652✔
6202
      vcode_select_block(i);
39,332✔
6203

6204
      const int nops = vcode_count_ops();
39,332✔
6205
      for (int op = 0; op < nops; op++) {
652,148✔
6206
         switch (vcode_get_op(op)) {
612,816✔
6207
         case VCODE_OP_LINK_PACKAGE:
2,209✔
6208
            (*fn)(vcode_get_ident(op), ctx);
2,209✔
6209
            break;
2,209✔
6210
         case VCODE_OP_FCALL:
23,874✔
6211
         case VCODE_OP_PCALL:
6212
         case VCODE_OP_CLOSURE:
6213
         case VCODE_OP_PROTECTED_INIT:
6214
         case VCODE_OP_PACKAGE_INIT:
6215
         case VCODE_OP_FUNCTION_TRIGGER:
6216
            (*fn)(vcode_get_func(op), ctx);
23,874✔
6217
            break;
23,874✔
6218
         default:
6219
            break;
6220
         }
6221
      }
6222
   }
6223

6224
   vcode_state_restore(&state);
15,320✔
6225
}
15,320✔
6226

6227
#if VCODE_CHECK_UNIONS
6228
#define OP_USE_COUNT_U0(x)                                              \
6229
   (OP_HAS_IDENT(x) + OP_HAS_FUNC(x) + OP_HAS_ADDRESS(x))
6230
#define OP_USE_COUNT_U1(x)                                              \
6231
   (OP_HAS_CMP(x) + OP_HAS_VALUE(x) + OP_HAS_REAL(x) +                  \
6232
    OP_HAS_COMMENT(x) + OP_HAS_DIM(x) + OP_HAS_TARGET(x) +              \
6233
    OP_HAS_HOPS(x) + OP_HAS_FIELD(x) + OP_HAS_TAG(x))
6234

6235
__attribute__((constructor))
6236
static void vcode_check_unions(void)
6237
{
6238
   printf("sizeof(op_t) = %ld\n", sizeof(op_t));
6239
   for (int i = 0; i < 256; i++) {
6240
      assert(OP_USE_COUNT_U0(i) <= 1);
6241
      assert(OP_USE_COUNT_U1(i) <= 1);
6242
   }
6243
}
6244
#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

© 2025 Coveralls, Inc