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

nickg / nvc / 13738584171

08 Mar 2025 12:57PM UTC coverage: 92.236% (-0.05%) from 92.281%
13738584171

push

github

nickg
Add a simple pointer provenance tracking scheme

52 of 53 new or added lines in 3 files covered. (98.11%)

230 existing lines in 7 files now uncovered.

68028 of 73754 relevant lines covered (92.24%)

433200.43 hits per line

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

96.82
/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);
8,305,489✔
36
DECLARE_AND_DEFINE_ARRAY(vcode_block);
368,378✔
37
DECLARE_AND_DEFINE_ARRAY(vcode_type);
80,563✔
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 || x == VCODE_OP_CLOSURE              \
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,186,462✔
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);
31,755✔
160
DECLARE_AND_DEFINE_ARRAY(var);
324,921✔
161
DECLARE_AND_DEFINE_ARRAY(reg);
7,804,769✔
162
DECLARE_AND_DEFINE_ARRAY(block);
139,300✔
163
DECLARE_AND_DEFINE_ARRAY(vtype);
70,809,693✔
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)
31,712✔
218
{
219
   int64_t result;
31,712✔
220
   if (__builtin_add_overflow(a, b, &result))
31,712✔
221
      return b < 0 ? INT64_MIN : INT64_MAX;
12,249✔
222

223
   return result;
224
}
225

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

232
   return result;
233
}
234

235
static inline int64_t smul64(int64_t a, int64_t b)
9,200✔
236
{
237
   int64_t result;
9,200✔
238
   if (__builtin_mul_overflow(a, b, &result))
9,200✔
239
      return (a > 0 && b > 0) || (a < 0 && b < 0) ? INT64_MAX : INT64_MIN;
4,681✔
240

241
   return result;
242
}
243

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

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

254
   return reg;
1,303,510✔
255
}
256

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

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

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

273
   block_t *block = vcode_block_data();
1,647,424✔
274

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

281
   return op;
1,647,424✔
282
}
283

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

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

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

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

303
static op_t *vcode_find_definition(vcode_reg_t reg)
1,200,143✔
304
{
305
   for (int i = active_block; i >= 0; i--) {
1,247,881✔
306
      block_t *b = &(active_unit->blocks.items[i]);
1,244,951✔
307
      for (int j = b->ops.count - 1; j >= 0; j--) {
16,280,074✔
308
         if (b->ops.items[j].result == reg)
16,232,336✔
309
            return &(b->ops.items[j]);
1,197,213✔
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,171,741✔
318
{
319
   op_t *defn = vcode_find_definition(reg);
1,171,741✔
320
   VCODE_ASSERT(defn != NULL, "constant %s uses parameter r%d",
1,171,741✔
321
                what, reg);
322
   VCODE_ASSERT(defn->kind == VCODE_OP_CONST
1,171,741✔
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,171,741✔
331
#endif
332

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

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

346
   int depth = MASK_CONTEXT(type);
68,260,088✔
347
   assert(depth <= unit->depth);
68,260,088✔
348
   while (depth != unit->depth)
69,439,256✔
349
      unit = unit->context;
1,179,168✔
350

351
   return vtype_array_nth_ptr(&(unit->types), MASK_INDEX(type));
68,260,088✔
352
}
353

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

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

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

370
   switch (defn->kind) {
25,472✔
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,156✔
392
      vcode_var_data(defn->address)->flags |= VAR_HEAP;
1,156✔
393
      break;
1,156✔
394

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

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

404
         vcode_select_unit(vu);
792✔
405

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

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

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

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

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

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

431
         // Any store to this variable must be heap allocated
432
         for (int i = 0; i < active_unit->blocks.count; i++) {
21,517✔
433
            block_t *b = &(active_unit->blocks.items[i]);
19,907✔
434
            for (int j = 0; j < b->ops.count; j++) {
275,787✔
435
               op_t *op = &(b->ops.items[j]);
255,880✔
436
               if (op->kind == VCODE_OP_STORE && op->address == defn->address)
255,880✔
437
                  vcode_heap_allocate(op->args.items[0]);
1,610✔
438

439
               VCODE_ASSERT(
255,880✔
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++) {
10,959✔
449
         const vtype_kind_t rkind = vcode_reg_kind(reg);
8,344✔
450
         if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY) {
8,344✔
451
            // Function may return a pointer to its argument
452
            vcode_heap_allocate(defn->args.items[i]);
8,135✔
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:
516✔
462
      vcode_heap_allocate(defn->args.items[1]);
516✔
463
      vcode_heap_allocate(defn->args.items[2]);
516✔
464
      break;
516✔
465

466
   case VCODE_OP_LOAD_INDIRECT:
261✔
467
      {
468
         // Always OK if scalar otherwise check the pointer source
469
         const vtype_kind_t vtkind = vcode_reg_kind(reg);
261✔
470
         if (vtkind != VCODE_TYPE_INT && vtkind != VCODE_TYPE_REAL)
261✔
471
            vcode_heap_allocate(defn->args.items[0]);
241✔
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:
UNCOV
517
      VCODE_ASSERT(false, "cannot heap allocate r%d", reg);
×
518
   }
519
}
520

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

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

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

537
   if (unit == active_unit)
44,784✔
538
      vcode_close();
12,178✔
539

540
   for (vcode_unit_t it = unit->children; it != NULL; it = it->next) {
58,617✔
541
      assert(it->context == unit);
13,833✔
542
      it->context = NULL;
13,833✔
543
   }
544
   unit->children = NULL;
44,784✔
545

546
   if (unit->context != NULL) {
44,784✔
547
      vcode_unit_t *it = &(unit->context->children);
14,176✔
548
      for (; *it != NULL && *it != unit; it = &((*it)->next))
293,776✔
549
         ;
550
      assert(*it != NULL);
14,176✔
551
      *it = (*it)->next;
14,176✔
552
   }
553

554
   for (unsigned i = 0; i < unit->blocks.count; i++) {
184,062✔
555
      block_t *b = &(unit->blocks.items[i]);
139,278✔
556

557
      for (unsigned j = 0; j < b->ops.count; j++) {
1,711,380✔
558
         op_t *o = &(b->ops.items[j]);
1,572,102✔
559
         if (OP_HAS_COMMENT(o->kind))
1,572,102✔
560
            free(o->comment);
116,099✔
561
         if (OP_HAS_TARGET(o->kind))
1,572,102✔
562
            free(o->targets.items);
85,059✔
563
         free(o->args.items);
1,572,102✔
564
      }
565
      free(b->ops.items);
139,278✔
566
   }
567
   free(unit->blocks.items);
44,784✔
568

569
   for (unsigned i = 0; i < unit->types.count; i++) {
583,067✔
570
      vtype_t *vt = &(unit->types.items[i]);
538,283✔
571
      if (vt->kind == VCODE_TYPE_RECORD)
538,283✔
572
         free(vt->fields.items);
5,778✔
573
   }
574
   free(unit->types.items);
44,784✔
575

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

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

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

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

598
vcode_type_t vcode_reg_type(vcode_reg_t reg)
4,405,992✔
599
{
600
   return vcode_reg_data(reg)->type;
4,405,992✔
601
}
602

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

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

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

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

621
   vtype_t *bounds = vcode_type_data(r->bounds);
675,774✔
622

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

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

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

641
   int pruned = 0;
44,794✔
642
   do {
60,948✔
643
      memset(uses, '\0', active_unit->regs.count * sizeof(int));
60,948✔
644
      pruned = 0;
60,948✔
645

646
      for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
287,610✔
647
         block_t *b = &(active_unit->blocks.items[i]);
226,662✔
648

649
         for (int j = b->ops.count - 1; j >= 0; j--) {
3,100,893✔
650
            op_t *o = &(b->ops.items[j]);
2,874,231✔
651

652
            switch (o->kind) {
2,874,231✔
653
            case VCODE_OP_FCALL:
59,120✔
654
               if (o->result == VCODE_INVALID_REG)
59,120✔
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) {
1,887,320✔
UNCOV
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) {
1,887,320✔
700
                  if (false DEBUG_ONLY(|| o->kind != VCODE_OP_CONST)) {
146,472✔
701
                     o->comment = xasprintf("Dead %s definition of r%d",
71,519✔
702
                                            vcode_op_string(o->kind),
703
                                            o->result);
704
                     o->kind = VCODE_OP_COMMENT;
71,519✔
705
                  }
706
                  else
707
                     o->kind = (vcode_op_t)-1;
74,953✔
708
                  vcode_reg_array_resize(&(o->args), 0, VCODE_INVALID_REG);
146,472✔
709
                  pruned++;
146,472✔
710
               }
711
               uses[o->result] = -1;
1,887,320✔
712
               break;
1,887,320✔
713

714
            default:
715
               break;
716
            }
717

718
            for (int k = 0; k < o->args.count; k++) {
7,790,097✔
719
               if (o->args.items[k] != VCODE_INVALID_REG)
4,915,866✔
720
                  uses[o->args.items[k]]++;
4,868,982✔
721
            }
722
         }
723
      }
724
   } while (pruned > 0);
60,948✔
725

726
   for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
184,094✔
727
      block_t *b = &(active_unit->blocks.items[i]);
139,300✔
728
      op_t *dst = &(b->ops.items[0]);
139,300✔
729
      size_t copied = 0;
139,300✔
730
      for (int j = 0; j < b->ops.count; j++) {
1,786,724✔
731
         const op_t *src = &(b->ops.items[j]);
1,647,424✔
732
         if (src->kind != (vcode_op_t)-1) {
1,647,424✔
733
            if (src != dst) {
1,572,471✔
734
               assert(dst < src);
419,885✔
735
               *dst = *src;
419,885✔
736
            }
737
            dst++;
1,572,471✔
738
            copied++;
1,572,471✔
739
         }
740
      }
741

742
      assert(copied <= b->ops.count);
139,300✔
743
      b->ops.count = copied;
139,300✔
744
   }
745
}
44,794✔
746

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

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

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

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

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

780
   return VCODE_INVALID_VAR;
781
}
782

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

UNCOV
922
bool vcode_block_empty(void)
×
923
{
UNCOV
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,752,313✔
931
{
932
   assert(active_unit != NULL);
1,752,313✔
933
   assert(active_block != VCODE_INVALID_BLOCK);
1,752,313✔
934

935
   const block_t *b = &(active_unit->blocks.items[active_block]);
1,752,313✔
936
   if (b->ops.count == 0)
1,752,313✔
937
      return false;
938
   else {
939
      vcode_op_t kind = b->ops.items[b->ops.count - 1].kind;
1,569,040✔
940
      return kind == VCODE_OP_WAIT || kind == VCODE_OP_JUMP
1,569,040✔
941
         || kind == VCODE_OP_COND || kind == VCODE_OP_PCALL
1,569,016✔
942
         || kind == VCODE_OP_RETURN || kind == VCODE_OP_CASE
943
         || kind == VCODE_OP_UNREACHABLE;
3,138,056✔
944
   }
945
}
946

947
const char *vcode_op_string(vcode_op_t op)
71,519✔
948
{
949
   static const char *strs[] = {
71,519✔
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", "deposit signal",
975
      "map implicit", "bind external", "array scope", "record scope", "syscall",
976
      "put conversion",
977
   };
978
   if ((unsigned)op >= ARRAY_LEN(strs))
71,519✔
979
      return "???";
980
   else
981
      return strs[op];
71,519✔
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
   case VCODE_UNIT_SHAPE:     printf("shape"); break;
1193
   }
1194
   color_printf("$$\n");
1195
   if (vu->context != NULL)
1196
      color_printf("Context    $cyan$%s$$\n", istr(vu->context->name));
1197
   printf("Blocks     %d\n", vu->blocks.count);
1198
   printf("Registers  %d\n", vu->regs.count);
1199
   printf("Types      %d\n", vu->types.count);
1200

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1515
         case VCODE_OP_WAIT:
1516
            {
1517
               color_printf("%s $yellow$%d$$", vcode_op_string(op->kind),
1518
                            op->targets.items[0]);
1519
               if (op->args.items[0] != VCODE_INVALID_REG) {
1520
                  printf(" for ");
1521
                  vcode_dump_reg(op->args.items[0]);
1522
               }
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
         case VCODE_OP_DEPOSIT_SIGNAL:
1763
            {
1764
               printf("%s ", vcode_op_string(op->kind));
1765
               vcode_dump_reg(op->args.items[0]);
1766
               printf(" count ");
1767
               vcode_dump_reg(op->args.items[1]);
1768
               if (op->args.count > 2) {
1769
                  printf(" values ");
1770
                  vcode_dump_reg(op->args.items[2]);
1771
               }
1772
            }
1773
            break;
1774

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2131
         case VCODE_OP_DEBUG_OUT:
2132
            {
2133
               col += printf("%s ", vcode_op_string(op->kind));
2134
               col += vcode_dump_reg(op->args.items[0]);
2135
            }
2136
            break;
2137

2138
         case VCODE_OP_COVER_STMT:
2139
         case VCODE_OP_COVER_BRANCH:
2140
         case VCODE_OP_COVER_EXPR:
2141
            {
2142
               printf("%s %u ", vcode_op_string(op->kind), op->tag);
2143
            }
2144
            break;
2145

2146
         case VCODE_OP_COVER_TOGGLE:
2147
         case VCODE_OP_COVER_STATE:
2148
            {
2149
               printf("%s %u ", vcode_op_string(op->kind), op->tag);
2150
               vcode_dump_reg(op->args.items[0]);
2151
            }
2152
            break;
2153

2154
         case VCODE_OP_UNDEFINED:
2155
            {
2156
               col += vcode_dump_reg(op->result);
2157
               col += printf(" := %s", vcode_op_string(op->kind));
2158
               vcode_dump_result_type(col, op);
2159
            }
2160
            break;
2161

2162
         case VCODE_OP_RANGE_LENGTH:
2163
         case VCODE_OP_RANGE_NULL:
2164
            {
2165
               col += vcode_dump_reg(op->result);
2166
               col += printf(" := %s left ", vcode_op_string(op->kind));
2167
               vcode_dump_reg(op->args.items[0]);
2168
               col += printf(" right ");
2169
               vcode_dump_reg(op->args.items[1]);
2170
               col += printf(" dir ");
2171
               col += vcode_dump_reg(op->args.items[2]);
2172
               vcode_dump_result_type(col, op);
2173
            }
2174
            break;
2175

2176
         case VCODE_OP_LINK_PACKAGE:
2177
            {
2178
               col += vcode_dump_reg(op->result);
2179
               col += color_printf(" := %s $magenta$%s$$",
2180
                                   vcode_op_string(op->kind), istr(op->ident));
2181
               if (op->args.count > 0) {
2182
                  col += printf(" locus ");
2183
                  col += vcode_dump_reg(op->args.items[0]);
2184
               }
2185
               vcode_dump_result_type(col, op);
2186
            }
2187
            break;
2188

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

2199
         case VCODE_OP_UNREACHABLE:
2200
            {
2201
               printf("%s", vcode_op_string(op->kind));
2202
               if (op->args.count > 0) {
2203
                  printf(" ");
2204
                  vcode_dump_reg(op->args.items[0]);
2205
               }
2206
            }
2207
            break;
2208

2209
         case VCODE_OP_DEBUG_LOCUS:
2210
            {
2211
               col += vcode_dump_reg(op->result);
2212
               col += color_printf(" := %s $magenta$",
2213
                                   vcode_op_string(op->kind));
2214

2215
               tree_t t = tree_from_object(op->object);
2216
               if (t != NULL)
2217
                  col += printf("%s@", tree_kind_str(tree_kind(t)));
2218

2219
               col += color_printf("%p$$", op->object);
2220
               vcode_dump_result_type(col, op);
2221
            }
2222
            break;
2223

2224
         case VCODE_OP_ENTER_STATE:
2225
            {
2226
               printf("%s ", vcode_op_string(op->kind));
2227
               vcode_dump_reg(op->args.items[0]);
2228
               if (op->args.count > 1) {
2229
                  printf(" strong ");
2230
                  vcode_dump_reg(op->args.items[1]);
2231
               }
2232
            }
2233
            break;
2234

2235
         case VCODE_OP_REFLECT_VALUE:
2236
            {
2237
               col += vcode_dump_reg(op->result);
2238
               col += printf(" := %s ", vcode_op_string(op->kind));
2239
               vcode_dump_reg(op->args.items[0]);
2240
               col += printf(" context ");
2241
               vcode_dump_reg(op->args.items[1]);
2242
               col += printf(" locus ");
2243
               col += vcode_dump_reg(op->args.items[2]);
2244
               if (op->args.count > 3) {
2245
                  col += printf(" bounds ");
2246
                  col += vcode_dump_reg(op->args.items[3]);
2247
               }
2248
               vcode_dump_result_type(col, op);
2249
            }
2250
            break;
2251

2252
         case VCODE_OP_REFLECT_SUBTYPE:
2253
            {
2254
               col += vcode_dump_reg(op->result);
2255
               col += printf(" := %s context ", vcode_op_string(op->kind));
2256
               vcode_dump_reg(op->args.items[0]);
2257
               col += printf(" locus ");
2258
               col += vcode_dump_reg(op->args.items[1]);
2259
               if (op->args.count > 2) {
2260
                  col += printf(" bounds ");
2261
                  col += vcode_dump_reg(op->args.items[2]);
2262
               }
2263
               vcode_dump_result_type(col, op);
2264
            }
2265
            break;
2266

2267
         case VCODE_OP_FUNCTION_TRIGGER:
2268
            {
2269
               col += vcode_dump_reg(op->result);
2270
               col += color_printf(" := %s $magenta$%s$$ ",
2271
                                   vcode_op_string(op->kind), istr(op->func));
2272
               for (int i = 0; i < op->args.count; i++) {
2273
                  if (i > 0) col += printf(", ");
2274
                  col += vcode_dump_reg(op->args.items[i]);
2275
               }
2276
               vcode_dump_result_type(col, op);
2277
            }
2278
            break;
2279

2280
         case VCODE_OP_OR_TRIGGER:
2281
         case VCODE_OP_CMP_TRIGGER:
2282
            {
2283
               col += vcode_dump_reg(op->result);
2284
               col += color_printf(" := %s ", vcode_op_string(op->kind));
2285
               col += vcode_dump_reg(op->args.items[0]);
2286
               if (op->kind == VCODE_OP_OR_TRIGGER)
2287
                  col += printf(" || ");
2288
               else
2289
                  col += printf(" == ");
2290
               col += vcode_dump_reg(op->args.items[1]);
2291
               vcode_dump_result_type(col, op);
2292
            }
2293
            break;
2294

2295
         case VCODE_OP_ADD_TRIGGER:
2296
            {
2297
               printf("%s ", vcode_op_string(op->kind));
2298
               vcode_dump_reg(op->args.items[0]);
2299
            }
2300
            break;
2301

2302
         case VCODE_OP_PUT_CONVERSION:
2303
            {
2304
               color_printf("%s ", vcode_op_string(op->kind));
2305
               vcode_dump_reg(op->args.items[0]);
2306
               printf(" signal ");
2307
               vcode_dump_reg(op->args.items[1]);
2308
               printf(" count ");
2309
               vcode_dump_reg(op->args.items[2]);
2310
               printf(" values ");
2311
               vcode_dump_reg(op->args.items[3]);
2312
            }
2313
            break;
2314

2315
         case VCODE_OP_PORT_CONVERSION:
2316
            {
2317
               col += vcode_dump_reg(op->result);
2318
               col += color_printf(" := %s ", vcode_op_string(op->kind));
2319
               col += vcode_dump_reg(op->args.items[0]);
2320
               if (op->args.count > 1) {
2321
                  col += printf(" effective ");
2322
                  col += vcode_dump_reg(op->args.items[1]);
2323
               }
2324
               vcode_dump_result_type(col, op);
2325
            }
2326
            break;
2327

2328
         case VCODE_OP_CONVERT_IN:
2329
         case VCODE_OP_CONVERT_OUT:
2330
            {
2331
               color_printf("%s ", vcode_op_string(op->kind));
2332
               vcode_dump_reg(op->args.items[0]);
2333
               printf(" signal ");
2334
               vcode_dump_reg(op->args.items[1]);
2335
               printf(" count ");
2336
               vcode_dump_reg(op->args.items[2]);
2337
            }
2338
            break;
2339

2340
         case VCODE_OP_BIND_FOREIGN:
2341
            {
2342
               color_printf("%s ", vcode_op_string(op->kind));
2343
               vcode_dump_reg(op->args.items[0]);
2344
               printf(" length ");
2345
               vcode_dump_reg(op->args.items[1]);
2346
               if (op->args.count > 2) {
2347
                  printf(" locus ");
2348
                  vcode_dump_reg(op->args.items[1]);
2349
               }
2350
            }
2351
            break;
2352

2353
         case VCODE_OP_INSTANCE_NAME:
2354
         case VCODE_OP_BIND_EXTERNAL:
2355
            {
2356
               col += vcode_dump_reg(op->result);
2357
               col += color_printf(" := %s ", vcode_op_string(op->kind));
2358
               col += vcode_dump_reg(op->args.items[0]);
2359
               col += color_printf(" scope $magenta$%s$$", istr(op->ident));
2360
               vcode_dump_result_type(col, op);
2361
            }
2362
            break;
2363
         }
2364

2365
         if (j == mark_op && i == old_block)
2366
            color_printf("\t $red$<----$$");
2367

2368
         color_printf("$$\n");
2369

2370
         if (callback != NULL)
2371
            (*callback)(j, arg);
2372
      }
2373

2374
      if (b->ops.count == 0)
2375
         color_printf("  $yellow$%2d:$$ $red$Empty basic block$$\n", i);
2376
   }
2377

2378
   printf("\n");
2379
   fflush(stdout);
2380

2381
   active_block = old_block;
2382
}
2383
LCOV_EXCL_STOP
2384

2385
bool vtype_eq(vcode_type_t a, vcode_type_t b)
33,043,979✔
2386
{
2387
   assert(active_unit != NULL);
33,595,857✔
2388

2389
   if (a == b)
33,595,857✔
2390
      return true;
2391
   else {
2392
      const vtype_t *at = vcode_type_data(a);
30,958,454✔
2393
      const vtype_t *bt = vcode_type_data(b);
30,958,454✔
2394

2395
      if (at->kind != bt->kind)
30,958,454✔
2396
         return false;
2397

2398
      switch (at->kind) {
13,421,403✔
2399
      case VCODE_TYPE_INT:
11,325,360✔
2400
         return (at->low == bt->low) && (at->high == bt->high);
21,266,249✔
2401
      case VCODE_TYPE_REAL:
978,897✔
2402
         return (at->rlow == bt->rlow) && (at->rhigh == bt->rhigh);
1,906,116✔
2403
      case VCODE_TYPE_CARRAY:
73,852✔
2404
         return at->size == bt->size && vtype_eq(at->elem, bt->elem);
80,635✔
2405
      case VCODE_TYPE_UARRAY:
89,694✔
2406
         return at->dims == bt->dims && vtype_eq(at->elem, bt->elem);
111,661✔
2407
      case VCODE_TYPE_POINTER:
458,814✔
2408
      case VCODE_TYPE_ACCESS:
2409
         return vtype_eq(at->pointed, bt->pointed);
458,814✔
2410
      case VCODE_TYPE_OFFSET:
2411
      case VCODE_TYPE_OPAQUE:
2412
      case VCODE_TYPE_DEBUG_LOCUS:
2413
      case VCODE_TYPE_TRIGGER:
2414
      case VCODE_TYPE_CONVERSION:
2415
         return true;
2416
      case VCODE_TYPE_RESOLUTION:
93,064✔
2417
      case VCODE_TYPE_CLOSURE:
2418
      case VCODE_TYPE_SIGNAL:
2419
      case VCODE_TYPE_FILE:
2420
         return vtype_eq(at->base, bt->base);
93,064✔
2421
      case VCODE_TYPE_RECORD:
65,736✔
2422
      case VCODE_TYPE_CONTEXT:
2423
         return at->name == bt->name;
65,736✔
2424
      }
2425

UNCOV
2426
      return false;
×
2427
   }
2428
}
2429

UNCOV
2430
void vcode_dump(void)
×
2431
{
UNCOV
2432
   vcode_dump_with_mark(-1, NULL, NULL);
×
2433
}
×
2434

2435
static vcode_type_t vtype_new(vtype_t *new)
2,549,605✔
2436
{
2437
   int index = active_unit->types.count - 1;
2,549,605✔
2438
   vcode_type_t type = MAKE_HANDLE(active_unit->depth, index);
2,549,605✔
2439

2440
   for (int i = 0; i < index; i++) {
30,659,186✔
2441
      vcode_type_t this = MAKE_HANDLE(active_unit->depth, i);
30,120,709✔
2442
      if (vtype_eq(this, type)) {
30,120,709✔
2443
         active_unit->types.count--;
2,011,128✔
2444
         return this;
2,011,128✔
2445
      }
2446
   }
2447

2448
   return type;
2449
}
2450

2451
vcode_type_t vtype_int(int64_t low, int64_t high)
1,672,500✔
2452
{
2453
   assert(active_unit != NULL);
1,672,500✔
2454

2455
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
1,672,500✔
2456
   n->kind = VCODE_TYPE_INT;
1,672,500✔
2457
   n->low  = low;
1,672,500✔
2458
   n->high = high;
1,672,500✔
2459

2460
   switch (bits_for_range(low, high)) {
1,672,500✔
2461
   case 64:
129,386✔
2462
      n->repr = low < 0 ? VCODE_REPR_I64 : VCODE_REPR_U64;
129,386✔
2463
      break;
129,386✔
2464
   case 32:
509,882✔
2465
      n->repr = low < 0 ? VCODE_REPR_I32 : VCODE_REPR_U32;
509,882✔
2466
      break;
509,882✔
2467
   case 16:
3,513✔
2468
      n->repr = low < 0 ? VCODE_REPR_I16 : VCODE_REPR_U16;
3,513✔
2469
      break;
3,513✔
2470
   case 8:
445,311✔
2471
      n->repr = low < 0 ? VCODE_REPR_I8 : VCODE_REPR_U8;
445,311✔
2472
      break;
445,311✔
2473
   case 1:
584,407✔
2474
      n->repr = VCODE_REPR_U1;
584,407✔
2475
      break;
584,407✔
2476
   case 0:
1✔
2477
      n->repr = VCODE_REPR_I64;    // Null range
1✔
2478
      break;
1✔
UNCOV
2479
   default:
×
2480
      fatal_trace("cannot represent %"PRIi64"..%"PRIi64, low, high);
2481
   }
2482

2483
   return vtype_new(n);
1,672,500✔
2484
}
2485

2486
vcode_type_t vtype_bool(void)
293,480✔
2487
{
2488
   return vtype_int(0, 1);
293,480✔
2489
}
2490

2491
vcode_type_t vtype_carray(int size, vcode_type_t elem, vcode_type_t bounds)
37,162✔
2492
{
2493
   assert(active_unit != NULL);
37,162✔
2494

2495
   const vtype_kind_t ekind = vtype_kind(elem);
37,162✔
2496
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
37,162✔
2497
                "array types may not be nested");
2498

2499
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
37,162✔
2500
   memset(n, '\0', sizeof(vtype_t));
37,162✔
2501
   n->kind   = VCODE_TYPE_CARRAY;
37,162✔
2502
   n->elem   = elem;
37,162✔
2503
   n->bounds = bounds;
37,162✔
2504
   n->size   = MAX(size, 0);
37,162✔
2505

2506
   return vtype_new(n);
37,162✔
2507
}
2508

2509
vcode_type_t vtype_find_named_record(ident_t name)
38,165✔
2510
{
2511
   assert(active_unit != NULL);
38,165✔
2512

2513
   for (int i = 0; i < active_unit->types.count; i++) {
490,541✔
2514
      vtype_t *other = &(active_unit->types.items[i]);
479,004✔
2515
      if (other->kind == VCODE_TYPE_RECORD && other->name == name)
479,004✔
2516
         return MAKE_HANDLE(active_unit->depth, i);
26,628✔
2517
   }
2518

2519
   return VCODE_INVALID_TYPE;
2520
}
2521

2522
vcode_type_t vtype_named_record(ident_t name, const vcode_type_t *field_types,
11,537✔
2523
                                int nfields)
2524
{
2525
   assert(active_unit != NULL);
11,537✔
2526

2527
   vtype_t *data = NULL;
11,537✔
2528
   vcode_type_t handle = vtype_find_named_record(name);
11,537✔
2529
   if (handle == VCODE_INVALID_TYPE) {
11,537✔
2530
      data = vtype_array_alloc(&(active_unit->types));
5,778✔
2531
      memset(data, '\0', sizeof(vtype_t));
5,778✔
2532
      data->kind = VCODE_TYPE_RECORD;
5,778✔
2533
      data->name = name;
5,778✔
2534

2535
      handle = vtype_new(data);
5,778✔
2536
   }
2537
   else {
2538
      data = vcode_type_data(handle);
5,759✔
2539
      VCODE_ASSERT(data->fields.count == 0,
5,759✔
2540
                    "record type %s already defined", istr(name));
2541
   }
2542

2543
   vcode_type_array_resize(&(data->fields), 0, VCODE_INVALID_TYPE);
11,537✔
2544
   for (int i = 0; i < nfields; i++)
30,787✔
2545
      vcode_type_array_add(&(data->fields), field_types[i]);
19,250✔
2546

2547
   return handle;
11,537✔
2548
}
2549

2550
vcode_type_t vtype_uarray(int ndim, vcode_type_t elem, vcode_type_t bounds)
84,483✔
2551
{
2552
   assert(active_unit != NULL);
84,483✔
2553

2554
   const vtype_kind_t ekind = vtype_kind(elem);
84,483✔
2555
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
84,483✔
2556
                "array types may not be nested");
2557

2558
   VCODE_ASSERT(ndim > 0, "uarray must have at least one dimension");
84,483✔
2559

2560
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
84,483✔
2561
   memset(n, '\0', sizeof(vtype_t));
84,483✔
2562
   n->kind   = VCODE_TYPE_UARRAY;
84,483✔
2563
   n->elem   = elem;
84,483✔
2564
   n->bounds = bounds;
84,483✔
2565
   n->dims   = ndim;
84,483✔
2566

2567
   return vtype_new(n);
84,483✔
2568
}
2569

2570
vcode_type_t vtype_pointer(vcode_type_t to)
188,888✔
2571
{
2572
   assert(active_unit != NULL);
188,888✔
2573

2574
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
188,888✔
2575
   n->kind    = VCODE_TYPE_POINTER;
188,888✔
2576
   n->pointed = to;
188,888✔
2577

2578
   VCODE_ASSERT(vtype_kind(to) != VCODE_TYPE_CARRAY,
188,888✔
2579
                "cannot get pointer to carray type");
2580

2581
   return vtype_new(n);
188,888✔
2582
}
2583

2584
vcode_type_t vtype_access(vcode_type_t to)
4,934✔
2585
{
2586
   assert(active_unit != NULL);
4,934✔
2587

2588
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
4,934✔
2589
   n->kind    = VCODE_TYPE_ACCESS;
4,934✔
2590
   n->pointed = to;
4,934✔
2591

2592
   return vtype_new(n);
4,934✔
2593
}
2594

2595
vcode_type_t vtype_signal(vcode_type_t base)
38,815✔
2596
{
2597
   assert(active_unit != NULL);
38,815✔
2598

2599
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
38,815✔
2600
   n->kind = VCODE_TYPE_SIGNAL;
38,815✔
2601
   n->base = base;
38,815✔
2602

2603
   VCODE_ASSERT(vtype_is_scalar(base), "signal base type must be scalar");
38,815✔
2604

2605
   return vtype_new(n);
38,815✔
2606
}
2607

2608
vcode_type_t vtype_resolution(vcode_type_t base)
963✔
2609
{
2610
   assert(active_unit != NULL);
963✔
2611

2612
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
963✔
2613
   n->kind = VCODE_TYPE_RESOLUTION;
963✔
2614
   n->base = base;
963✔
2615

2616
   return vtype_new(n);
963✔
2617
}
2618

2619
vcode_type_t vtype_closure(vcode_type_t result)
1,335✔
2620
{
2621
   assert(active_unit != NULL);
1,335✔
2622

2623
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
1,335✔
2624
   n->kind = VCODE_TYPE_CLOSURE;
1,335✔
2625
   n->base = result;
1,335✔
2626

2627
   return vtype_new(n);
1,335✔
2628
}
2629

2630
vcode_type_t vtype_context(ident_t name)
52,356✔
2631
{
2632
   assert(active_unit != NULL);
52,356✔
2633
   assert(name != NULL);
52,356✔
2634

2635
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
52,356✔
2636
   n->kind = VCODE_TYPE_CONTEXT;
52,356✔
2637
   n->name = name;
52,356✔
2638

2639
   return vtype_new(n);
52,356✔
2640
}
2641

2642
vcode_type_t vtype_file(vcode_type_t base)
618✔
2643
{
2644
   assert(active_unit != NULL);
618✔
2645

2646
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
618✔
2647
   n->kind = VCODE_TYPE_FILE;
618✔
2648
   n->base = base;
618✔
2649

2650
   return vtype_new(n);
618✔
2651
}
2652

2653
vcode_type_t vtype_offset(void)
268,287✔
2654
{
2655
   assert(active_unit != NULL);
268,287✔
2656

2657
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
268,287✔
2658
   n->kind = VCODE_TYPE_OFFSET;
268,287✔
2659
   n->low  = INT64_MIN;
268,287✔
2660
   n->high = INT64_MAX;
268,287✔
2661
   n->repr = VCODE_REPR_I64;
268,287✔
2662

2663
   return vtype_new(n);
268,287✔
2664
}
2665

2666
vcode_type_t vtype_time(void)
17,468✔
2667
{
2668
   return vtype_int(INT64_MIN, INT64_MAX);
17,468✔
2669
}
2670

2671
vcode_type_t vtype_char(void)
9,306✔
2672
{
2673
   return vtype_int(0, 255);
9,306✔
2674
}
2675

2676
vcode_type_t vtype_opaque(void)
1,475✔
2677
{
2678
   assert(active_unit != NULL);
1,475✔
2679

2680
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
1,475✔
2681
   n->kind = VCODE_TYPE_OPAQUE;
1,475✔
2682

2683
   return vtype_new(n);
1,475✔
2684
}
2685

2686
vcode_type_t vtype_debug_locus(void)
110,368✔
2687
{
2688
   assert(active_unit != NULL);
110,368✔
2689

2690
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
110,368✔
2691
   n->kind = VCODE_TYPE_DEBUG_LOCUS;
110,368✔
2692

2693
   return vtype_new(n);
110,368✔
2694
}
2695

2696
vcode_type_t vtype_trigger(void)
386✔
2697
{
2698
   assert(active_unit != NULL);
386✔
2699

2700
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
386✔
2701
   n->kind = VCODE_TYPE_TRIGGER;
386✔
2702

2703
   return vtype_new(n);
386✔
2704
}
2705

2706
vcode_type_t vtype_conversion(void)
576✔
2707
{
2708
   assert(active_unit != NULL);
576✔
2709

2710
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
576✔
2711
   n->kind = VCODE_TYPE_CONVERSION;
576✔
2712

2713
   return vtype_new(n);
576✔
2714
}
2715

2716
vcode_type_t vtype_real(double low, double high)
80,681✔
2717
{
2718
   assert(active_unit != NULL);
80,681✔
2719

2720
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
80,681✔
2721
   n->kind  = VCODE_TYPE_REAL;
80,681✔
2722
   n->rlow  = low;
80,681✔
2723
   n->rhigh = high;
80,681✔
2724

2725
   return vtype_new(n);
80,681✔
2726
}
2727

2728
vtype_kind_t vtype_kind(vcode_type_t type)
4,079,015✔
2729
{
2730
   vtype_t *vt = vcode_type_data(type);
4,079,015✔
2731
   return vt->kind;
4,079,015✔
2732
}
2733

2734
vtype_repr_t vtype_repr(vcode_type_t type)
40,773✔
2735
{
2736
   vtype_t *vt = vcode_type_data(type);
40,773✔
2737
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
40,773✔
2738
   return vt->repr;
40,773✔
2739
}
2740

2741
vcode_type_t vtype_elem(vcode_type_t type)
119,319✔
2742
{
2743
   vtype_t *vt = vcode_type_data(type);
119,319✔
2744
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
119,319✔
2745
   return vt->elem;
119,319✔
2746
}
2747

2748
vcode_type_t vtype_base(vcode_type_t type)
42,322✔
2749
{
2750
   vtype_t *vt = vcode_type_data(type);
42,322✔
2751
   assert(vt->kind == VCODE_TYPE_SIGNAL || vt->kind == VCODE_TYPE_FILE
42,322✔
2752
          || vt->kind == VCODE_TYPE_RESOLUTION
2753
          || vt->kind == VCODE_TYPE_CLOSURE);
2754
   return vt->base;
42,322✔
2755
}
2756

2757
vcode_type_t vtype_bounds(vcode_type_t type)
12,809✔
2758
{
2759
   vtype_t *vt = vcode_type_data(type);
12,809✔
2760
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
12,809✔
2761
   return vt->bounds;
12,809✔
2762
}
2763

2764
unsigned vtype_dims(vcode_type_t type)
48,257✔
2765
{
2766
   vtype_t *vt = vcode_type_data(type);
48,257✔
2767
   assert(vt->kind == VCODE_TYPE_UARRAY);
48,257✔
2768
   return vt->dims;
48,257✔
2769
}
2770

2771
unsigned vtype_size(vcode_type_t type)
37,659✔
2772
{
2773
   vtype_t *vt = vcode_type_data(type);
37,659✔
2774
   assert(vt->kind == VCODE_TYPE_CARRAY);
37,659✔
2775
   return vt->size;
37,659✔
2776
}
2777

2778
int vtype_fields(vcode_type_t type)
8,006✔
2779
{
2780
   vtype_t *vt = vcode_type_data(type);
8,006✔
2781
   assert(vt->kind == VCODE_TYPE_RECORD);
8,006✔
2782
   return vt->fields.count;
8,006✔
2783
}
2784

2785
vcode_type_t vtype_field(vcode_type_t type, int field)
30,526✔
2786
{
2787
   vtype_t *vt = vcode_type_data(type);
30,526✔
2788
   assert(vt->kind == VCODE_TYPE_RECORD);
30,526✔
2789
   return vcode_type_array_nth(&(vt->fields), field);
30,526✔
2790
}
2791

2792
ident_t vtype_name(vcode_type_t type)
19,886✔
2793
{
2794
   vtype_t *vt = vcode_type_data(type);
19,886✔
2795
   assert(vt->kind == VCODE_TYPE_RECORD || vt->kind == VCODE_TYPE_CONTEXT);
19,886✔
2796
   return vt->name;
19,886✔
2797
}
2798

2799
vcode_type_t vtype_pointed(vcode_type_t type)
313,477✔
2800
{
2801
   vtype_t *vt = vcode_type_data(type);
313,477✔
2802
   assert(vt->kind == VCODE_TYPE_POINTER || vt->kind == VCODE_TYPE_ACCESS);
313,477✔
2803
   return vt->pointed;
313,477✔
2804
}
2805

2806
int64_t vtype_low(vcode_type_t type)
134,521✔
2807
{
2808
   vtype_t *vt = vcode_type_data(type);
134,521✔
2809
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
134,521✔
2810
   return vt->low;
134,521✔
2811
}
2812

2813
int64_t vtype_high(vcode_type_t type)
132,382✔
2814
{
2815
   vtype_t *vt = vcode_type_data(type);
132,382✔
2816
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
132,382✔
2817
   return vt->high;
132,382✔
2818
}
2819

2820
static bool vtype_is_pointer(vcode_type_t type, vtype_kind_t to)
462✔
2821
{
2822
   return vtype_kind(type) == VCODE_TYPE_POINTER
462✔
2823
      && vtype_kind(vtype_pointed(type)) == to;
462✔
2824
}
2825

2826
bool vtype_is_scalar(vcode_type_t type)
406,057✔
2827
{
2828
   const vtype_kind_t kind = vtype_kind(type);
406,057✔
2829
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
406,057✔
2830
      || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_POINTER
162,105✔
2831
      || kind == VCODE_TYPE_FILE || kind == VCODE_TYPE_ACCESS
2832
      || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_SIGNAL
2833
      || kind == VCODE_TYPE_CONTEXT || kind == VCODE_TYPE_TRIGGER;
406,057✔
2834
}
2835

2836
bool vtype_is_composite(vcode_type_t type)
23,215✔
2837
{
2838
   const vtype_kind_t kind = vtype_kind(type);
23,215✔
2839
   return kind == VCODE_TYPE_RECORD || kind == VCODE_TYPE_CARRAY;
23,215✔
2840
}
2841

2842
bool vtype_is_signal(vcode_type_t type)
171,121✔
2843
{
2844
   vtype_t *vt = vcode_type_data(type);
302,210✔
2845
   switch (vt->kind) {
302,210✔
2846
   case VCODE_TYPE_SIGNAL:
2847
      return true;
2848
   case VCODE_TYPE_POINTER:
71,984✔
2849
      return vtype_is_signal(vt->pointed);
71,984✔
2850
   case VCODE_TYPE_RECORD:
2851
      for (int i = 0; i < vt->fields.count; i++) {
36,734✔
2852
         if (vtype_is_signal(vt->fields.items[i]))
28,705✔
2853
            return true;
2854
      }
2855
      return false;
2856
   case VCODE_TYPE_UARRAY:
59,105✔
2857
   case VCODE_TYPE_CARRAY:
2858
      return vtype_is_signal(vt->elem);
59,105✔
2859
   default:
134,763✔
2860
      return false;
134,763✔
2861
   }
2862
}
2863

UNCOV
2864
int vtype_repr_bits(vtype_repr_t repr)
×
2865
{
UNCOV
2866
   switch (repr) {
×
2867
   case VCODE_REPR_U1: return 1;
2868
   case VCODE_REPR_U8: case VCODE_REPR_I8: return 8;
2869
   case VCODE_REPR_U16: case VCODE_REPR_I16: return 16;
2870
   case VCODE_REPR_U32: case VCODE_REPR_I32: return 32;
2871
   case VCODE_REPR_U64: case VCODE_REPR_I64: return 64;
2872
   default: return -1;
2873
   }
2874
}
2875

UNCOV
2876
bool vtype_repr_signed(vtype_repr_t repr)
×
2877
{
UNCOV
2878
   return repr == VCODE_REPR_I8 || repr == VCODE_REPR_I16
×
2879
      || repr == VCODE_REPR_I32 || repr == VCODE_REPR_I64;
×
2880
}
2881

2882
static int64_t vtype_repr_low(vtype_repr_t repr)
8,733✔
2883
{
2884
   switch (repr) {
8,733✔
2885
   case VCODE_REPR_U1:
2886
   case VCODE_REPR_U8:
2887
   case VCODE_REPR_U16:
2888
   case VCODE_REPR_U32:
2889
   case VCODE_REPR_U64: return 0;
2890
   case VCODE_REPR_I8:  return INT8_MIN;
2891
   case VCODE_REPR_I16: return INT16_MIN;
2892
   case VCODE_REPR_I32: return INT32_MIN;
2893
   case VCODE_REPR_I64: return INT64_MIN;
2894
   default:             return 0;
2895
   }
2896
}
2897

2898
static uint64_t vtype_repr_high(vtype_repr_t repr)
8,733✔
2899
{
2900
   switch (repr) {
8,733✔
2901
   case VCODE_REPR_U1:  return 1;
2902
   case VCODE_REPR_U8:  return UINT8_MAX;
2903
   case VCODE_REPR_U16: return UINT16_MAX;
2904
   case VCODE_REPR_U32: return UINT32_MAX;
2905
   case VCODE_REPR_U64: return UINT64_MAX;
2906
   case VCODE_REPR_I8:  return INT8_MAX;
2907
   case VCODE_REPR_I16: return INT16_MAX;
2908
   case VCODE_REPR_I32: return INT32_MAX;
2909
   case VCODE_REPR_I64: return INT64_MAX;
2910
   default:             return 0;
2911
   }
2912
}
2913

2914
static bool vtype_clamp_to_repr(vtype_repr_t repr, int64_t *low, int64_t *high)
8,733✔
2915
{
2916
   int64_t clamp_low = vtype_repr_low(repr);
8,733✔
2917
   uint64_t clamp_high = vtype_repr_high(repr);
8,733✔
2918

2919
   if (*low >= clamp_low && *high <= clamp_high)
8,733✔
2920
      return true;
2921
   else {
2922
      *low = MAX(clamp_low, *low);
4,642✔
2923
      *high = MIN(clamp_high, *high);
4,642✔
2924
      return false;
4,642✔
2925
   }
2926
}
2927

2928
int vcode_count_params(void)
11,274✔
2929
{
2930
   assert(active_unit != NULL);
11,274✔
2931
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
11,274✔
2932
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2933
          || active_unit->kind == VCODE_UNIT_PROPERTY
2934
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2935

2936
   return active_unit->params.count;
11,274✔
2937
}
2938

2939
vcode_type_t vcode_param_type(int param)
29,315✔
2940
{
2941
   assert(active_unit != NULL);
29,315✔
2942
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
29,315✔
2943
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2944
          || active_unit->kind == VCODE_UNIT_PROPERTY
2945
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2946
   assert(param < active_unit->params.count);
29,315✔
2947

2948
   return active_unit->params.items[param].type;
29,315✔
2949
}
2950

2951
ident_t vcode_param_name(int param)
29,315✔
2952
{
2953
   assert(active_unit != NULL);
29,315✔
2954
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
29,315✔
2955
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2956
          || active_unit->kind == VCODE_UNIT_PROPERTY
2957
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2958
   assert(param < active_unit->params.count);
29,315✔
2959

2960
   return active_unit->params.items[param].name;
29,315✔
2961
}
2962

2963
vcode_reg_t vcode_param_reg(int param)
29,335✔
2964
{
2965
   assert(active_unit != NULL);
29,335✔
2966
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
29,335✔
2967
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2968
          || active_unit->kind == VCODE_UNIT_PROPERTY
2969
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2970
   assert(param < active_unit->params.count);
29,335✔
2971

2972
   return active_unit->params.items[param].reg;
29,335✔
2973
}
2974

2975
vcode_block_t emit_block(void)
139,300✔
2976
{
2977
   assert(active_unit != NULL);
139,300✔
2978

2979
   vcode_block_t bnum = active_unit->blocks.count;
139,300✔
2980

2981
   block_t *bptr = block_array_alloc(&(active_unit->blocks));
139,300✔
2982
   memset(bptr, '\0', sizeof(block_t));
139,300✔
2983

2984
   if (active_block != VCODE_INVALID_BLOCK)
139,300✔
2985
      bptr->last_loc = active_unit->blocks.items[active_block].last_loc;
94,506✔
2986
   else
2987
      bptr->last_loc = LOC_INVALID;
44,794✔
2988

2989
   return bnum;
139,300✔
2990
}
2991

2992
void vcode_select_unit(vcode_unit_t unit)
179,072✔
2993
{
2994
   active_unit  = unit;
179,072✔
2995
   active_block = VCODE_INVALID_BLOCK;
179,072✔
2996
}
179,072✔
2997

2998
void vcode_select_block(vcode_block_t block)
390,917✔
2999
{
3000
   assert(active_unit != NULL);
390,917✔
3001
   active_block = block;
390,917✔
3002
}
390,917✔
3003

3004
vcode_block_t vcode_active_block(void)
628✔
3005
{
3006
   assert(active_unit != NULL);
628✔
3007
   assert(active_block != -1);
628✔
3008
   return active_block;
628✔
3009
}
3010

3011
const loc_t *vcode_last_loc(void)
658,700✔
3012
{
3013
   return &(vcode_block_data()->last_loc);
658,700✔
3014
}
3015

3016
vcode_unit_t vcode_active_unit(void)
875✔
3017
{
3018
   assert(active_unit != NULL);
875✔
3019
   return active_unit;
875✔
3020
}
3021

3022
ident_t vcode_unit_name(vcode_unit_t vu)
188,746✔
3023
{
3024
   assert(vu != NULL);
188,746✔
3025
   return vu->name;
188,746✔
3026
}
3027

3028
bool vcode_unit_has_undefined(vcode_unit_t vu)
12,372✔
3029
{
3030
   assert(vu != NULL);
12,372✔
3031
   return !!(vu->flags & UNIT_UNDEFINED);
12,372✔
3032
}
3033

UNCOV
3034
int vcode_unit_depth(vcode_unit_t vu)
×
3035
{
UNCOV
3036
   assert(vu != NULL);
×
UNCOV
3037
   return vu->depth;
×
3038
}
3039

3040
void vcode_set_result(vcode_type_t type)
22,157✔
3041
{
3042
   assert(active_unit != NULL);
22,157✔
3043
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
22,157✔
3044
          || active_unit->kind == VCODE_UNIT_THUNK);
3045

3046
   active_unit->result = type;
22,157✔
3047
}
22,157✔
3048

3049
vcode_type_t vcode_unit_result(vcode_unit_t vu)
21,936✔
3050
{
3051
   assert(vu != NULL);
21,936✔
3052
   assert(vu->kind == VCODE_UNIT_FUNCTION || vu->kind == VCODE_UNIT_THUNK);
21,936✔
3053
   return vu->result;
21,936✔
3054
}
3055

3056
vunit_kind_t vcode_unit_kind(vcode_unit_t vu)
163,236✔
3057
{
3058
   assert(vu != NULL);
163,236✔
3059
   return vu->kind;
163,236✔
3060
}
3061

3062
vcode_unit_t vcode_unit_context(vcode_unit_t vu)
124,695✔
3063
{
3064
   assert(vu != NULL);
124,695✔
3065
   return vu->context;
124,695✔
3066
}
3067

3068
object_t *vcode_unit_object(vcode_unit_t vu)
77,913✔
3069
{
3070
   assert(vu != NULL);
77,913✔
3071
   return vu->object;
77,913✔
3072
}
3073

3074
static unsigned vcode_unit_calc_depth(vcode_unit_t unit)
57,175✔
3075
{
3076
   int hops = 0;
57,175✔
3077
   for (; (unit = unit->context); hops++)
146,821✔
3078
      ;
3079
   return hops;
57,175✔
3080
}
3081

3082
static void vcode_add_child(vcode_unit_t context, vcode_unit_t child)
28,012✔
3083
{
3084
   assert(context->kind != VCODE_UNIT_THUNK);
28,012✔
3085

3086
   child->next = NULL;
28,012✔
3087
   if (context->children == NULL)
28,012✔
3088
      context->children = child;
11,369✔
3089
   else {
3090
      vcode_unit_t it;
3091
      for (it = context->children; it->next != NULL; it = it->next)
755,411✔
3092
         ;
3093
      it->next = child;
16,643✔
3094
   }
3095
}
28,012✔
3096

3097
vcode_unit_t emit_function(ident_t name, object_t *obj, vcode_unit_t context)
11,222✔
3098
{
3099
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
11,222✔
3100
   vu->kind     = VCODE_UNIT_FUNCTION;
11,222✔
3101
   vu->name     = name;
11,222✔
3102
   vu->context  = context;
11,222✔
3103
   vu->result   = VCODE_INVALID_TYPE;
11,222✔
3104
   vu->depth    = vcode_unit_calc_depth(vu);
11,222✔
3105
   vu->object   = obj;
11,222✔
3106

3107
   vcode_add_child(context, vu);
11,222✔
3108

3109
   vcode_select_unit(vu);
11,222✔
3110
   vcode_select_block(emit_block());
11,222✔
3111
   emit_debug_info(&(obj->loc));
11,222✔
3112

3113
   return vu;
11,222✔
3114
}
3115

3116
vcode_unit_t emit_procedure(ident_t name, object_t *obj, vcode_unit_t context)
254✔
3117
{
3118
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
254✔
3119
   vu->kind     = VCODE_UNIT_PROCEDURE;
254✔
3120
   vu->name     = name;
254✔
3121
   vu->context  = context;
254✔
3122
   vu->result   = VCODE_INVALID_TYPE;
254✔
3123
   vu->depth    = vcode_unit_calc_depth(vu);
254✔
3124
   vu->object   = obj;
254✔
3125

3126
   vcode_add_child(context, vu);
254✔
3127

3128
   vcode_select_unit(vu);
254✔
3129
   vcode_select_block(emit_block());
254✔
3130
   emit_debug_info(&(obj->loc));
254✔
3131

3132
   return vu;
254✔
3133
}
3134

3135
vcode_unit_t emit_process(ident_t name, object_t *obj, vcode_unit_t context)
9,245✔
3136
{
3137
   assert(context->kind == VCODE_UNIT_INSTANCE
9,245✔
3138
          || context->kind == VCODE_UNIT_SHAPE);
3139

3140
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
9,245✔
3141
   vu->kind     = VCODE_UNIT_PROCESS;
9,245✔
3142
   vu->name     = name;
9,245✔
3143
   vu->context  = context;
9,245✔
3144
   vu->depth    = vcode_unit_calc_depth(vu);
9,245✔
3145
   vu->result   = VCODE_INVALID_TYPE;
9,245✔
3146
   vu->object   = obj;
9,245✔
3147

3148
   vcode_add_child(context, vu);
9,245✔
3149

3150
   vcode_select_unit(vu);
9,245✔
3151
   vcode_select_block(emit_block());
9,245✔
3152
   emit_debug_info(&(obj->loc));
9,245✔
3153

3154
   return vu;
9,245✔
3155
}
3156

3157
vcode_unit_t emit_instance(ident_t name, object_t *obj, vcode_unit_t context)
9,407✔
3158
{
3159
   assert(context == NULL || context->kind == VCODE_UNIT_INSTANCE);
9,407✔
3160

3161
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
9,407✔
3162
   vu->kind     = VCODE_UNIT_INSTANCE;
9,407✔
3163
   vu->name     = name;
9,407✔
3164
   vu->context  = context;
9,407✔
3165
   vu->depth    = vcode_unit_calc_depth(vu);
9,407✔
3166
   vu->result   = VCODE_INVALID_TYPE;
9,407✔
3167
   vu->object   = obj;
9,407✔
3168

3169
   if (context != NULL)
9,407✔
3170
      vcode_add_child(context, vu);
5,807✔
3171

3172
   vcode_select_unit(vu);
9,407✔
3173
   vcode_select_block(emit_block());
9,407✔
3174
   emit_debug_info(&(obj->loc));
9,407✔
3175

3176
   return vu;
9,407✔
3177
}
3178

3179
vcode_unit_t emit_shape(ident_t name, object_t *obj, vcode_unit_t context)
89✔
3180
{
3181
   assert(context == NULL || context->kind == VCODE_UNIT_SHAPE);
89✔
3182

3183
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
89✔
3184
   vu->kind     = VCODE_UNIT_SHAPE;
89✔
3185
   vu->name     = name;
89✔
3186
   vu->context  = context;
89✔
3187
   vu->depth    = vcode_unit_calc_depth(vu);
89✔
3188
   vu->result   = VCODE_INVALID_TYPE;
89✔
3189
   vu->object   = obj;
89✔
3190

3191
   if (context != NULL)
89✔
UNCOV
3192
      vcode_add_child(context, vu);
×
3193

3194
   vcode_select_unit(vu);
89✔
3195
   vcode_select_block(emit_block());
89✔
3196
   emit_debug_info(&(obj->loc));
89✔
3197

3198
   return vu;
89✔
3199
}
3200

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

3211
   if (context != NULL)
1,811✔
3212
      vcode_add_child(context, vu);
183✔
3213

3214
   vcode_select_unit(vu);
1,811✔
3215
   vcode_select_block(emit_block());
1,811✔
3216
   emit_debug_info(&(obj->loc));
1,811✔
3217

3218
   return vu;
1,811✔
3219
}
3220

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

3231
   if (context != NULL)
175✔
3232
      vcode_add_child(context, vu);
175✔
3233

3234
   vcode_select_unit(vu);
175✔
3235
   vcode_select_block(emit_block());
175✔
3236
   emit_debug_info(&(obj->loc));
175✔
3237

3238
   return vu;
175✔
3239
}
3240

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

3251
   if (context != NULL)
210✔
3252
      vcode_add_child(context, vu);
210✔
3253

3254
   vcode_select_unit(vu);
210✔
3255
   vcode_select_block(emit_block());
210✔
3256
   emit_debug_info(&(obj->loc));
210✔
3257

3258
   return vu;
210✔
3259
}
3260

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

3272
   if (context != NULL)
12,381✔
3273
      vcode_add_child(context, vu);
916✔
3274

3275
   vcode_select_unit(vu);
12,381✔
3276
   vcode_select_block(emit_block());
12,381✔
3277

3278
   return vu;
12,381✔
3279
}
3280

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

3291
   op_t *op = vcode_add_op(VCODE_OP_ASSERT);
14,107✔
3292
   vcode_add_arg(op, value);
14,107✔
3293
   vcode_add_arg(op, severity);
14,107✔
3294
   vcode_add_arg(op, message);
14,107✔
3295
   vcode_add_arg(op, length);
14,107✔
3296
   vcode_add_arg(op, locus);
14,107✔
3297

3298
   if (hint_left != VCODE_INVALID_REG) {
14,107✔
3299
      vcode_add_arg(op, hint_left);
5,804✔
3300
      vcode_add_arg(op, hint_right);
5,804✔
3301

3302
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_left)),
5,804✔
3303
                   "left hint must be scalar");
3304
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_right)),
5,804✔
3305
                   "right hint must be scalar");
3306
   }
3307

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

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

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

3336
vcode_reg_t emit_cmp(vcode_cmp_t cmp, vcode_reg_t lhs, vcode_reg_t rhs)
38,712✔
3337
{
3338
   if (lhs == rhs) {
38,712✔
3339
      if (cmp == VCODE_CMP_EQ)
931✔
3340
         return emit_const(vtype_bool(), 1);
924✔
3341
      else if (cmp == VCODE_CMP_NEQ)
7✔
UNCOV
3342
         return emit_const(vtype_bool(), 0);
×
3343
      else if (cmp == VCODE_CMP_LEQ || cmp == VCODE_CMP_GEQ)
7✔
UNCOV
3344
         return emit_const(vtype_bool(), 1);
×
3345
      else if (cmp == VCODE_CMP_LT || cmp == VCODE_CMP_GT)
7✔
3346
         return emit_const(vtype_bool(), 0);
7✔
3347
   }
3348

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

3369
   // Reuse any previous operation in this block with the same arguments
3370
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CMP) {
661,820✔
3371
      if (other->args.count == 2 && other->args.items[0] == lhs
27,515✔
3372
          && other->args.items[1] == rhs && other->cmp == cmp)
1,176✔
3373
         return other->result;
193✔
3374
   }
3375

3376
   op_t *op = vcode_add_op(VCODE_OP_CMP);
37,073✔
3377
   vcode_add_arg(op, lhs);
37,073✔
3378
   vcode_add_arg(op, rhs);
37,073✔
3379
   op->cmp    = cmp;
37,073✔
3380
   op->result = vcode_add_reg(vtype_bool());
37,073✔
3381

3382
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vcode_reg_type(rhs)),
37,073✔
3383
                "arguments to cmp are not the same type");
3384

3385
   return op->result;
3386
}
3387

3388
vcode_reg_t emit_fcall(ident_t func, vcode_type_t type, vcode_type_t bounds,
36,485✔
3389
                       const vcode_reg_t *args, int nargs)
3390
{
3391
   op_t *o = vcode_add_op(VCODE_OP_FCALL);
36,485✔
3392
   o->func = func;
36,485✔
3393
   o->type = type;
36,485✔
3394
   for (int i = 0; i < nargs; i++)
142,968✔
3395
      vcode_add_arg(o, args[i]);
106,483✔
3396

3397
   for (int i = 0; i < nargs; i++)
142,968✔
3398
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
106,483✔
3399
                   "invalid argument to function");
3400

3401
   VCODE_ASSERT(nargs > 0 && vcode_reg_kind(args[0]) == VCODE_TYPE_CONTEXT,
36,485✔
3402
                "first argument to VHDL function must be context pointer");
3403

3404
   if (type == VCODE_INVALID_TYPE)
36,485✔
3405
      return (o->result = VCODE_INVALID_REG);
5,006✔
3406
   else {
3407
      o->result = vcode_add_reg(type);
31,479✔
3408

3409
      reg_t *rr = vcode_reg_data(o->result);
31,479✔
3410
      rr->bounds = bounds;
31,479✔
3411

3412
      return o->result;
31,479✔
3413
   }
3414
}
3415

3416
void emit_pcall(ident_t func, const vcode_reg_t *args, int nargs,
880✔
3417
                vcode_block_t resume_bb)
3418
{
3419
   op_t *o = vcode_add_op(VCODE_OP_PCALL);
880✔
3420
   o->func = func;
880✔
3421
   for (int i = 0; i < nargs; i++)
3,121✔
3422
      vcode_add_arg(o, args[i]);
2,241✔
3423

3424
   vcode_block_array_add(&(o->targets), resume_bb);
880✔
3425

3426
   for (int i = 0; i < nargs; i++)
3,121✔
3427
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
2,241✔
3428
                   "invalid argument to procedure");
3429

3430
   VCODE_ASSERT(nargs > 0 && vcode_reg_kind(args[0]) == VCODE_TYPE_CONTEXT,
880✔
3431
                "first argument to VHDL procedure must be context pointer");
3432
}
880✔
3433

3434
vcode_reg_t emit_syscall(ident_t func, vcode_type_t type, vcode_type_t bounds,
423✔
3435
                         vcode_reg_t locus, const vcode_reg_t *args, int nargs)
3436
{
3437
   op_t *o = vcode_add_op(VCODE_OP_SYSCALL);
423✔
3438
   o->func = func;
423✔
3439
   o->type = type;
423✔
3440
   vcode_add_arg(o, locus);
423✔
3441
   for (int i = 0; i < nargs; i++)
498✔
3442
      vcode_add_arg(o, args[i]);
75✔
3443

3444
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
423✔
3445
                "locus argument to syscall must be a debug locus");
3446

3447
   for (int i = 0; i < nargs; i++)
498✔
3448
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG, "invalid argument to syscall");
75✔
3449

3450
   if (type == VCODE_INVALID_TYPE)
423✔
3451
      return (o->result = VCODE_INVALID_REG);
384✔
3452
   else {
3453
      o->result = vcode_add_reg(type);
39✔
3454

3455
      reg_t *rr = vcode_reg_data(o->result);
39✔
3456
      rr->bounds = bounds;
39✔
3457

3458
      return o->result;
39✔
3459
   }
3460
}
3461

3462
vcode_reg_t emit_alloc(vcode_type_t type, vcode_type_t bounds,
7,394✔
3463
                       vcode_reg_t count)
3464
{
3465
   op_t *op = vcode_add_op(VCODE_OP_ALLOC);
7,394✔
3466
   op->type    = type;
7,394✔
3467
   op->result  = vcode_add_reg(vtype_pointer(type));
7,394✔
3468
   vcode_add_arg(op, count);
7,394✔
3469

3470
   const vtype_kind_t tkind = vtype_kind(type);
7,394✔
3471
   VCODE_ASSERT(tkind != VCODE_TYPE_CARRAY && tkind != VCODE_TYPE_UARRAY,
7,394✔
3472
                "alloca element type cannot be array");
3473
   VCODE_ASSERT(count != VCODE_INVALID_REG,
7,394✔
3474
                "alloca must have valid count argument");
3475

3476
   reg_t *r = vcode_reg_data(op->result);
7,394✔
3477
   r->bounds = bounds;
7,394✔
3478

3479
   return op->result;
7,394✔
3480
}
3481

3482
vcode_reg_t emit_const(vcode_type_t type, int64_t value)
987,538✔
3483
{
3484
   // Reuse any previous constant in this block with the same type and value
3485
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST) {
20,849,393✔
3486
      if (other->value == value && vtype_eq(type, other->type))
7,714,297✔
3487
         return other->result;
588,301✔
3488
   }
3489

3490
   op_t *op = vcode_add_op(VCODE_OP_CONST);
399,237✔
3491
   op->value  = value;
399,237✔
3492
   op->type   = type;
399,237✔
3493
   op->result = vcode_add_reg(type);
399,237✔
3494

3495
   vtype_kind_t type_kind = vtype_kind(type);
399,237✔
3496
   VCODE_ASSERT(type_kind == VCODE_TYPE_INT || type_kind == VCODE_TYPE_OFFSET,
399,237✔
3497
                "constant must have integer or offset type");
3498

3499
   reg_t *r = vcode_reg_data(op->result);
399,237✔
3500
   r->bounds = vtype_int(value, value);
399,237✔
3501

3502
   return op->result;
399,237✔
3503
}
3504

3505
vcode_reg_t emit_const_real(vcode_type_t type, double value)
39,753✔
3506
{
3507
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REAL) {
1,491,606✔
3508
      if (other->real == value && other->type == type)
932,862✔
3509
         return other->result;
13,210✔
3510
   }
3511

3512
   op_t *op = vcode_add_op(VCODE_OP_CONST_REAL);
26,543✔
3513
   op->real   = value;
26,543✔
3514
   op->type   = type;
26,543✔
3515
   op->result = vcode_add_reg(op->type);
26,543✔
3516

3517
   reg_t *r = vcode_reg_data(op->result);
26,543✔
3518
   r->bounds = vtype_real(value, value);
26,543✔
3519

3520
   return op->result;
26,543✔
3521
}
3522

3523
vcode_reg_t emit_const_array(vcode_type_t type, vcode_reg_t *values, int num)
27,559✔
3524
{
3525
   vtype_kind_t kind = vtype_kind(type);
27,559✔
3526

3527
   // Reuse any previous operation in this block with the same arguments
3528
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_ARRAY) {
1,160,158✔
3529
      if (other->args.count != num)
117,032✔
3530
         continue;
69,784✔
3531
      else if (!vtype_eq(vcode_reg_type(other->result), type))
47,248✔
3532
         continue;
646✔
3533

3534
      bool match = true;
3535
      for (int i = 0; match && i < num; i++) {
295,211✔
3536
         if (other->args.items[i] != values[i])
248,609✔
3537
            match = false;
40,522✔
3538
      }
3539

3540
      if (match) return other->result;
46,602✔
3541
   }
3542

3543
   op_t *op = vcode_add_op(VCODE_OP_CONST_ARRAY);
21,479✔
3544
   op->result = vcode_add_reg(type);
21,479✔
3545

3546
   for (int i = 0; i < num; i++)
1,186,595✔
3547
      vcode_add_arg(op, values[i]);
1,165,116✔
3548

3549
   VCODE_ASSERT(kind == VCODE_TYPE_CARRAY,
21,479✔
3550
                "constant array must have constrained array type");
3551
   VCODE_ASSERT(vtype_size(type) == num, "expected %d elements but have %d",
21,479✔
3552
                vtype_size(type), num);
3553

3554
#ifdef DEBUG
3555
   vcode_type_t elem = vtype_elem(type);
21,479✔
3556
   for (int i = 0; i < num; i++) {
1,186,595✔
3557
      VCODE_ASSERT(vtype_eq(vcode_reg_type(values[i]), elem),
1,165,116✔
3558
                   "wrong element type for item %d", i);
3559
      vcode_assert_const(values[i], "array");
1,165,116✔
3560
   }
3561
#endif
3562

3563
   reg_t *r = vcode_reg_data(op->result);
21,479✔
3564
   r->bounds = vtype_elem(type);
21,479✔
3565

3566
   return op->result;
21,479✔
3567
}
3568

3569
vcode_reg_t emit_const_rep(vcode_type_t type, vcode_reg_t value, int rep)
619✔
3570
{
3571
   // Reuse any previous operation in this block with the same arguments
3572
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REP) {
9,162✔
3573
      if (other->args.items[0] == value && other->value == rep)
972✔
3574
         return other->result;
264✔
3575
   }
3576

3577
   op_t *op = vcode_add_op(VCODE_OP_CONST_REP);
355✔
3578
   op->value = rep;
355✔
3579
   vcode_add_arg(op, value);
355✔
3580

3581
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CARRAY,
355✔
3582
                "constant array must have constrained array type");
3583

3584
   DEBUG_ONLY(vcode_assert_const(value, "repeat"));
355✔
3585

3586
   op->result = vcode_add_reg(type);
355✔
3587

3588
   reg_t *r = vcode_reg_data(op->result);
355✔
3589
   r->bounds = vtype_bounds(type);
355✔
3590

3591
   return op->result;
355✔
3592
}
3593

3594
vcode_reg_t emit_const_record(vcode_type_t type, vcode_reg_t *values, int num)
2,723✔
3595
{
3596
   // Reuse any previous constant in this block with the same type and value
3597
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_RECORD) {
39,168✔
3598
      if (other->args.count == num && vtype_eq(type, other->type)) {
1,634✔
3599
         bool same_regs = true;
3600
         for (int i = 0; same_regs && i < num; i++)
2,465✔
3601
            same_regs = other->args.items[i] == values[i];
1,475✔
3602

3603
         if (same_regs)
990✔
3604
            return other->result;
226✔
3605
      }
3606
   }
3607

3608
   op_t *op = vcode_add_op(VCODE_OP_CONST_RECORD);
2,497✔
3609
   op->type   = type;
2,497✔
3610
   op->result = vcode_add_reg(type);
2,497✔
3611

3612
   for (int i = 0; i < num; i++)
8,767✔
3613
      vcode_add_arg(op, values[i]);
6,270✔
3614

3615
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_RECORD,
2,497✔
3616
                "constant record must have record type");
3617

3618
   VCODE_ASSERT(vtype_fields(type) == num, "expected %d fields but have %d",
2,497✔
3619
                vtype_fields(type), num);
3620

3621
#ifdef DEBUG
3622
   for (int i = 0; i < num; i++) {
8,767✔
3623
      VCODE_ASSERT(vtype_eq(vtype_field(type, i), vcode_reg_type(values[i])),
6,270✔
3624
                   "wrong type for field %d", i);
3625
      vcode_assert_const(values[i], "record");
6,270✔
3626
   }
3627
#endif
3628

3629
   return op->result;
2,497✔
3630
}
3631

3632
vcode_reg_t emit_address_of(vcode_reg_t value)
29,326✔
3633
{
3634
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ADDRESS_OF) {
1,225,269✔
3635
      if (other->args.items[0] == value)
118,256✔
3636
         return other->result;
6,111✔
3637
   }
3638

3639
   op_t *op = vcode_add_op(VCODE_OP_ADDRESS_OF);
23,215✔
3640
   vcode_add_arg(op, value);
23,215✔
3641

3642
   vcode_type_t type = vcode_reg_type(value);
23,215✔
3643
   VCODE_ASSERT(vtype_is_composite(type),
23,215✔
3644
                "address of argument must be record or array");
3645

3646
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
23,215✔
3647
      vcode_type_t elem = vtype_elem(type);
21,265✔
3648
      op->result = vcode_add_reg(vtype_pointer(elem));
21,265✔
3649

3650
      reg_t *rr = vcode_reg_data(op->result);
21,265✔
3651
      rr->bounds = elem;
21,265✔
3652

3653
      return op->result;
21,265✔
3654
   }
3655
   else
3656
      return (op->result = vcode_add_reg(vtype_pointer(type)));
1,950✔
3657
}
3658

3659
void emit_wait(vcode_block_t target, vcode_reg_t time)
13,708✔
3660
{
3661
   op_t *op = vcode_add_op(VCODE_OP_WAIT);
13,708✔
3662
   vcode_add_target(op, target);
13,708✔
3663
   vcode_add_arg(op, time);
13,708✔
3664

3665
   VCODE_ASSERT(time == VCODE_INVALID_REG
13,708✔
3666
                || vcode_reg_kind(time) == VCODE_TYPE_INT,
3667
                "wait time must have integer type");
3668
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_PROCEDURE
13,708✔
3669
                || active_unit->kind == VCODE_UNIT_PROCESS,
3670
                "wait only allowed in process or procedure");
3671
}
13,708✔
3672

3673
void emit_jump(vcode_block_t target)
35,827✔
3674
{
3675
   op_t *op = vcode_add_op(VCODE_OP_JUMP);
35,827✔
3676
   vcode_add_target(op, target);
35,827✔
3677

3678
   VCODE_ASSERT(target != VCODE_INVALID_BLOCK, "invalid jump target");
35,827✔
3679
}
35,827✔
3680

3681
vcode_var_t emit_var(vcode_type_t type, vcode_type_t bounds, ident_t name,
49,069✔
3682
                     vcode_var_flags_t flags)
3683
{
3684
   assert(active_unit != NULL);
49,069✔
3685

3686
   vcode_var_t var = active_unit->vars.count;
49,069✔
3687
   var_t *v = var_array_alloc(&(active_unit->vars));
49,069✔
3688
   memset(v, '\0', sizeof(var_t));
49,069✔
3689
   v->type     = type;
49,069✔
3690
   v->bounds   = bounds;
49,069✔
3691
   v->name     = name;
49,069✔
3692
   v->flags    = flags;
49,069✔
3693

3694
   return var;
49,069✔
3695
}
3696

3697
vcode_reg_t emit_param(vcode_type_t type, vcode_type_t bounds, ident_t name)
31,755✔
3698
{
3699
   assert(active_unit != NULL);
31,755✔
3700

3701
   param_t *p = param_array_alloc(&(active_unit->params));
31,755✔
3702
   memset(p, '\0', sizeof(param_t));
31,755✔
3703
   p->type   = type;
31,755✔
3704
   p->bounds = bounds;
31,755✔
3705
   p->name   = name;
31,755✔
3706
   p->reg    = vcode_add_reg(type);
31,755✔
3707

3708
   reg_t *rr = vcode_reg_data(p->reg);
31,755✔
3709
   rr->bounds = bounds;
31,755✔
3710

3711
   return p->reg;
31,755✔
3712
}
3713

3714
vcode_reg_t emit_load(vcode_var_t var)
52,122✔
3715
{
3716
   // Try scanning backwards through the block for another load or store to
3717
   // this variable
3718
   enum { EAGER, CONSERVATIVE, UNSAFE } state = EAGER;
52,122✔
3719
   vcode_reg_t fold = VCODE_INVALID_REG;
52,122✔
3720
   VCODE_FOR_EACH_OP(other) {
728,056✔
3721
      switch (state) {
690,270✔
3722
      case EAGER:
228,669✔
3723
         if (other->kind == VCODE_OP_LOAD && other->address == var)
228,669✔
3724
            return other->result;
3,039✔
3725
         else if (other->kind == VCODE_OP_STORE && other->address == var)
225,630✔
3726
            return other->args.items[0];
11,297✔
3727
         else if (other->kind == VCODE_OP_FCALL
214,333✔
3728
                  || other->kind == VCODE_OP_PCALL
214,333✔
3729
                  || other->kind == VCODE_OP_FILE_READ
3730
                  || other->kind == VCODE_OP_FILE_OPEN
3731
                  || other->kind == VCODE_OP_STORE_INDIRECT
3732
                  || other->kind == VCODE_OP_DEALLOCATE)
3733
            state = CONSERVATIVE;   // May write to variable
8,868✔
3734
         break;
3735

3736
      case CONSERVATIVE:
437,054✔
3737
         if (other->kind == VCODE_OP_LOAD && other->address == var
437,054✔
3738
             && fold == VCODE_INVALID_REG)
4,223✔
3739
            fold = other->result;
3,376✔
3740
         else if (other->kind == VCODE_OP_STORE && other->address == var
433,678✔
3741
                  && fold == VCODE_INVALID_REG)
2,579✔
3742
            fold = other->args.items[0];
2,442✔
3743
         else if (other->kind == VCODE_OP_INDEX && other->address == var)
431,236✔
3744
            state = UNSAFE;
3745
         else if (other->kind == VCODE_OP_CONTEXT_UPREF && other->hops == 0)
430,242✔
3746
            state = UNSAFE;   // Nested call captures variables
80✔
3747
         break;
3748

3749
      case UNSAFE:
3750
         break;
3751
      }
3752
   }
3753

3754
   if (fold != VCODE_INVALID_REG && state != UNSAFE)
37,786✔
3755
      return fold;
3756

3757
   var_t *v = vcode_var_data(var);
32,315✔
3758

3759
   op_t *op = vcode_add_op(VCODE_OP_LOAD);
32,315✔
3760
   op->address = var;
32,315✔
3761
   op->result  = vcode_add_reg(v->type);
32,315✔
3762

3763
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot load non-scalar type");
32,315✔
3764

3765
   reg_t *r = vcode_reg_data(op->result);
32,315✔
3766
   r->bounds = v->bounds;
32,315✔
3767

3768
   return op->result;
32,315✔
3769
}
3770

3771
vcode_reg_t emit_load_indirect(vcode_reg_t reg)
95,471✔
3772
{
3773
   VCODE_FOR_EACH_OP(other) {
1,093,430✔
3774
      if (other->kind == VCODE_OP_LOAD_INDIRECT
1,026,031✔
3775
          && other->args.items[0] == reg) {
160,446✔
3776
         return other->result;
7,222✔
3777
      }
3778
      else if (other->kind == VCODE_OP_FCALL
1,018,809✔
3779
               || other->kind == VCODE_OP_PCALL
1,018,809✔
3780
               || other->kind == VCODE_OP_STORE
3781
               || other->kind == VCODE_OP_STORE_INDIRECT
3782
               || other->kind == VCODE_OP_MEMSET
3783
               || other->kind == VCODE_OP_COPY
3784
               || other->kind == VCODE_OP_FILE_READ)
3785
         break;   // May write to this pointer
3786
   }
3787

3788
   op_t *op = vcode_add_op(VCODE_OP_LOAD_INDIRECT);
88,249✔
3789
   vcode_add_arg(op, reg);
88,249✔
3790

3791
   vcode_type_t rtype = vcode_reg_type(reg);
88,249✔
3792

3793
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
88,249✔
3794
                "load indirect with non-pointer argument");
3795

3796
   vcode_type_t deref = vtype_pointed(rtype);
88,249✔
3797
   op->result = vcode_add_reg(deref);
88,249✔
3798

3799
   VCODE_ASSERT(vtype_is_scalar(deref), "cannot load non-scalar type");
88,249✔
3800

3801
   vcode_reg_data(op->result)->bounds = vcode_reg_data(reg)->bounds;
88,249✔
3802

3803
   return op->result;
88,249✔
3804
}
3805

3806
void emit_store(vcode_reg_t reg, vcode_var_t var)
59,114✔
3807
{
3808
   // Any previous store to this variable in this block is dead
3809
   VCODE_FOR_EACH_OP(other) {
1,127,428✔
3810
      if (other->kind == VCODE_OP_STORE && other->address == var) {
1,080,207✔
3811
         other->kind = VCODE_OP_COMMENT;
273✔
3812
         other->comment =
546✔
3813
            xasprintf("Dead store to %s", istr(vcode_var_name(var)));
273✔
3814
         vcode_reg_array_resize(&(other->args), 0, VCODE_INVALID_REG);
273✔
3815
      }
3816
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
1,079,934✔
3817
         break;   // Needs to get variable for display
3818
      else if ((other->kind == VCODE_OP_INDEX || other->kind == VCODE_OP_LOAD)
1,073,952✔
3819
               && other->address == var)
25,161✔
3820
         break;   // Previous value may be used
3821
   }
3822

3823
   var_t *v = vcode_var_data(var);
59,114✔
3824
   reg_t *r = vcode_reg_data(reg);
59,114✔
3825

3826
   op_t *op = vcode_add_op(VCODE_OP_STORE);
59,114✔
3827
   vcode_add_arg(op, reg);
59,114✔
3828
   op->address = var;
59,114✔
3829

3830
   VCODE_ASSERT(vtype_eq(v->type, r->type),
59,114✔
3831
                "variable and stored value do not have same type");
3832
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot store non-scalar type");
59,114✔
3833
}
59,114✔
3834

3835
void emit_store_indirect(vcode_reg_t reg, vcode_reg_t ptr)
13,854✔
3836
{
3837
   reg_t *p = vcode_reg_data(ptr);
13,854✔
3838
   reg_t *r = vcode_reg_data(reg);
13,854✔
3839

3840
   op_t *op = vcode_add_op(VCODE_OP_STORE_INDIRECT);
13,854✔
3841
   vcode_add_arg(op, reg);
13,854✔
3842
   vcode_add_arg(op, ptr);
13,854✔
3843

3844
   VCODE_ASSERT(vtype_kind(p->type) == VCODE_TYPE_POINTER,
13,854✔
3845
                "store indirect target is not a pointer");
3846
   VCODE_ASSERT(vtype_eq(vtype_pointed(p->type), r->type),
13,854✔
3847
                "pointer and stored value do not have same type");
3848
   VCODE_ASSERT(vtype_is_scalar(r->type), "cannot store non-scalar type");
13,854✔
3849
}
13,854✔
3850

3851
static vcode_reg_t emit_arith(vcode_op_t kind, vcode_reg_t lhs, vcode_reg_t rhs,
50,652✔
3852
                              vcode_reg_t locus)
3853
{
3854
   // Reuse any previous operation in this block with the same arguments
3855
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
1,052,739✔
3856
      if (other->args.items[0] == lhs && other->args.items[1] == rhs)
59,399✔
3857
         return other->result;
2,885✔
3858
   }
3859

3860
   op_t *op = vcode_add_op(kind);
47,767✔
3861
   vcode_add_arg(op, lhs);
47,767✔
3862
   vcode_add_arg(op, rhs);
47,767✔
3863
   if (locus != VCODE_INVALID_REG)
47,767✔
3864
      vcode_add_arg(op, locus);
4,987✔
3865

3866
   op->result = vcode_add_reg(vcode_reg_type(lhs));
47,767✔
3867

3868
   vcode_type_t lhs_type = vcode_reg_type(lhs);
47,767✔
3869
   vcode_type_t rhs_type = vcode_reg_type(rhs);
47,767✔
3870

3871
   VCODE_ASSERT(vtype_eq(lhs_type, rhs_type),
47,767✔
3872
                "arguments to %s are not the same type", vcode_op_string(kind));
3873

3874
   return op->result;
3875
}
3876

3877
static vcode_reg_t emit_mul_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
34,711✔
3878
                               vcode_reg_t locus)
3879
{
3880
   int64_t lconst, rconst;
34,711✔
3881
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
34,711✔
3882
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
34,711✔
3883
   if (l_is_const && r_is_const)
34,711✔
3884
      return emit_const(vcode_reg_type(lhs), lconst * rconst);
19,450✔
3885
   else if (r_is_const && rconst == 1)
15,261✔
3886
      return lhs;
3887
   else if (l_is_const && lconst == 1)
3,592✔
3888
      return rhs;
3889
   else if ((r_is_const && rconst == 0) || (l_is_const && lconst == 0))
3,093✔
3890
      return emit_const(vcode_reg_type(lhs), 0);
54✔
3891

3892
   reg_t *lhs_r = vcode_reg_data(lhs);
3,039✔
3893
   reg_t *rhs_r = vcode_reg_data(rhs);
3,039✔
3894

3895
   vtype_t *bl = vcode_type_data(lhs_r->bounds);
3,039✔
3896
   vtype_t *br = vcode_type_data(rhs_r->bounds);
3,039✔
3897

3898
   vcode_type_t vbounds;
3,039✔
3899
   if (vcode_reg_kind(lhs) == VCODE_TYPE_REAL) {
3,039✔
3900
      const double ll = bl->rlow * br->rlow;
739✔
3901
      const double lh = bl->rlow * br->rhigh;
739✔
3902
      const double hl = bl->rhigh * br->rlow;
739✔
3903
      const double hh = bl->rhigh * br->rhigh;
739✔
3904

3905
      double min = MIN(MIN(ll, lh), MIN(hl, hh));
1,595✔
3906
      double max = MAX(MAX(ll, lh), MAX(hl, hh));
1,815✔
3907

3908
      vbounds = vtype_real(min, max);
739✔
3909
   }
3910
   else {
3911
      const int64_t ll = smul64(bl->low, br->low);
2,300✔
3912
      const int64_t lh = smul64(bl->low, br->high);
2,300✔
3913
      const int64_t hl = smul64(bl->high, br->low);
2,300✔
3914
      const int64_t hh = smul64(bl->high, br->high);
2,300✔
3915

3916
      int64_t min = MIN(MIN(ll, lh), MIN(hl, hh));
2,300✔
3917
      int64_t max = MAX(MAX(ll, lh), MAX(hl, hh));
2,300✔
3918

3919
      vtype_repr_t repr = vtype_repr(lhs_r->type);
2,300✔
3920
      if (op == VCODE_OP_TRAP_MUL && vtype_clamp_to_repr(repr, &min, &max)) {
2,300✔
3921
         op = VCODE_OP_MUL;   // Cannot overflow
400✔
3922
         locus = VCODE_INVALID_REG;
400✔
3923
      }
3924

3925
      vbounds = vtype_int(min, max);
2,300✔
3926
   }
3927

3928
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
3,039✔
3929

3930
   if (vbounds != VCODE_INVALID_TYPE)
3,039✔
3931
      vcode_reg_data(reg)->bounds = vbounds;
3,039✔
3932

3933
   return reg;
3934
}
3935

3936
vcode_reg_t emit_mul(vcode_reg_t lhs, vcode_reg_t rhs)
33,812✔
3937
{
3938
   return emit_mul_op(VCODE_OP_MUL, lhs, rhs, VCODE_INVALID_REG);
33,812✔
3939
}
3940

3941
vcode_reg_t emit_trap_mul(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
899✔
3942
{
3943
   vcode_reg_t result = emit_mul_op(VCODE_OP_TRAP_MUL, lhs, rhs, locus);
899✔
3944

3945
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
899✔
3946
                "trapping add may only be used with integer types");
3947

3948
   return result;
899✔
3949
}
3950

3951
vcode_reg_t emit_div(vcode_reg_t lhs, vcode_reg_t rhs)
1,016✔
3952
{
3953
   int64_t lconst, rconst;
1,016✔
3954
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
1,016✔
3955
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
1,016✔
3956
   if (l_is_const && r_is_const && rconst != 0)
1,016✔
3957
      return emit_const(vcode_reg_type(lhs), lconst / rconst);
30✔
3958
   else if (r_is_const && rconst == 1)
986✔
3959
      return lhs;
3960

3961
   vcode_reg_t reg = emit_arith(VCODE_OP_DIV, lhs, rhs, VCODE_INVALID_REG);
985✔
3962

3963
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
985✔
3964

3965
   if (bl->kind == VCODE_TYPE_INT && r_is_const && rconst != 0) {
985✔
3966
      reg_t *rr = vcode_reg_data(reg);
693✔
3967
      rr->bounds = vtype_int(bl->low / rconst, bl->high / rconst);
693✔
3968
   }
3969
   else if (bl->kind == VCODE_TYPE_REAL) {
292✔
3970
      reg_t *rr = vcode_reg_data(reg);
224✔
3971
      rr->bounds = vtype_real(-INFINITY, INFINITY);
224✔
3972
   }
3973

3974
   return reg;
3975
}
3976

3977
vcode_reg_t emit_exp(vcode_reg_t lhs, vcode_reg_t rhs)
79✔
3978
{
3979
   return emit_arith(VCODE_OP_EXP, lhs, rhs, VCODE_INVALID_REG);
79✔
3980
}
3981

3982
vcode_reg_t emit_trap_exp(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
816✔
3983
{
3984
   int64_t rconst;
816✔
3985
   if (vcode_reg_const(rhs, &rconst)) {
816✔
3986
      if (rconst == 0)
707✔
3987
         return emit_const(vcode_reg_type(lhs), 1);
223✔
3988
      else if (rconst == 1)
484✔
3989
         return lhs;
3990
   }
3991

3992
   vcode_reg_t result = emit_arith(VCODE_OP_TRAP_EXP, lhs, rhs, locus);
544✔
3993

3994
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
544✔
3995
                "trapping exp may only be used with integer types");
3996

3997
   return result;
3998
}
3999

4000
vcode_reg_t emit_mod(vcode_reg_t lhs, vcode_reg_t rhs)
222✔
4001
{
4002
   int64_t lconst, rconst;
222✔
4003
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
222✔
4004
       && lconst > 0 && rconst > 0)
15✔
4005
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
3✔
4006

4007
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
219✔
4008
   vtype_t *br = vcode_type_data(vcode_reg_data(rhs)->bounds);
219✔
4009

4010
   if (bl->low >= 0 && br->low >= 0) {
219✔
4011
      // If both arguments are non-negative then rem is equivalent and
4012
      // cheaper to compute
4013
      vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
48✔
4014

4015
      reg_t *rr = vcode_reg_data(reg);
48✔
4016
      rr->bounds = vtype_int(0, MAX(0, br->high - 1));
48✔
4017

4018
      return reg;
48✔
4019
   }
4020
   else
4021
      return emit_arith(VCODE_OP_MOD, lhs, rhs, VCODE_INVALID_REG);
171✔
4022
}
4023

4024
vcode_reg_t emit_rem(vcode_reg_t lhs, vcode_reg_t rhs)
89✔
4025
{
4026
   int64_t lconst, rconst;
89✔
4027
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
89✔
4028
       && lconst > 0 && rconst > 0)
2✔
UNCOV
4029
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
×
4030

4031
   vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
89✔
4032

4033
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
89✔
4034
   vtype_t *br = vcode_type_data(vcode_reg_data(rhs)->bounds);
89✔
4035

4036
   if (bl->low >= 0 && br->low >= 0) {
89✔
4037
      reg_t *rr = vcode_reg_data(reg);
36✔
4038
      rr->bounds = vtype_int(0, br->high - 1);
36✔
4039
   }
4040

4041
   return reg;
4042
}
4043

4044
static vcode_reg_t emit_add_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
43,418✔
4045
                               vcode_reg_t locus)
4046
{
4047
   int64_t lconst, rconst;
43,418✔
4048
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
43,418✔
4049
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
43,418✔
4050
   if (l_is_const && r_is_const)
43,418✔
4051
      return emit_const(vcode_reg_type(lhs), lconst + rconst);
17,406✔
4052
   else if (r_is_const && rconst == 0)
26,012✔
4053
      return lhs;
4054
   else if (l_is_const && lconst == 0)
26,006✔
4055
      return rhs;
4056

4057
   vcode_type_t vbounds = VCODE_INVALID_TYPE;
16,141✔
4058
   if (vcode_reg_kind(lhs) != VCODE_TYPE_REAL) {
16,141✔
4059
      reg_t *lhs_r = vcode_reg_data(lhs);
15,856✔
4060
      reg_t *rhs_r = vcode_reg_data(rhs);
15,856✔
4061

4062
      vtype_t *bl = vcode_type_data(lhs_r->bounds);
15,856✔
4063
      vtype_t *br = vcode_type_data(rhs_r->bounds);
15,856✔
4064

4065
      int64_t rbl = sadd64(bl->low, br->low);
15,856✔
4066
      int64_t rbh = sadd64(bl->high, br->high);
15,856✔
4067

4068
      vtype_repr_t repr = vtype_repr(lhs_r->type);
15,856✔
4069
      if (op == VCODE_OP_TRAP_ADD && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
15,856✔
4070
         op = VCODE_OP_ADD;   // Cannot overflow
779✔
4071
         locus = VCODE_INVALID_REG;
779✔
4072
      }
4073

4074
      vbounds = vtype_int(rbl, rbh);
15,856✔
4075
   }
4076

4077
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
16,141✔
4078

4079
   if (vbounds != VCODE_INVALID_TYPE)
16,141✔
4080
      vcode_reg_data(reg)->bounds = vbounds;
15,856✔
4081

4082
   return reg;
4083
}
4084

4085
vcode_reg_t emit_add(vcode_reg_t lhs, vcode_reg_t rhs)
40,558✔
4086
{
4087
   return emit_add_op(VCODE_OP_ADD, lhs, rhs, VCODE_INVALID_REG);
40,558✔
4088
}
4089

4090
vcode_reg_t emit_trap_add(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
2,860✔
4091
{
4092
   vcode_reg_t result = emit_add_op(VCODE_OP_TRAP_ADD, lhs, rhs, locus);
2,860✔
4093

4094
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
2,860✔
4095
                "trapping add may only be used with integer types");
4096

4097
   return result;
2,860✔
4098
}
4099

4100
static vcode_reg_t emit_sub_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
39,121✔
4101
                               vcode_reg_t locus)
4102
{
4103
   int64_t lconst, rconst;
39,121✔
4104
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
39,121✔
4105
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
39,121✔
4106
   if (l_is_const && r_is_const)
39,121✔
4107
      return emit_const(vcode_reg_type(lhs), lconst - rconst);
12,723✔
4108
   else if (r_is_const && rconst == 0)
26,398✔
4109
      return lhs;
4110
   else if (l_is_const && lconst == 0)
24,223✔
4111
      return emit_neg(rhs);
1,302✔
4112

4113
   vcode_type_t vbounds = VCODE_INVALID_TYPE;
22,921✔
4114
   if (vcode_reg_kind(lhs) != VCODE_TYPE_REAL) {
22,921✔
4115
      reg_t *lhs_r = vcode_reg_data(lhs);
22,617✔
4116
      reg_t *rhs_r = vcode_reg_data(rhs);
22,617✔
4117

4118
      vtype_t *bl = vcode_type_data(lhs_r->bounds);
22,617✔
4119
      vtype_t *br = vcode_type_data(rhs_r->bounds);
22,617✔
4120

4121
      int64_t rbl = ssub64(bl->low, br->high);
22,617✔
4122
      int64_t rbh = ssub64(bl->high, br->low);
22,617✔
4123

4124
      vtype_repr_t repr = vtype_repr(lhs_r->type);
22,617✔
4125
      if (op == VCODE_OP_TRAP_SUB && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
22,617✔
4126
         op = VCODE_OP_SUB;   // Cannot overflow
2,912✔
4127
         locus = VCODE_INVALID_REG;
2,912✔
4128
      }
4129

4130
      vbounds = vtype_int(rbl, rbh);
22,617✔
4131
   }
4132

4133
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
22,921✔
4134

4135
   if (vbounds != VCODE_INVALID_TYPE)
22,921✔
4136
      vcode_reg_data(reg)->bounds = vbounds;
22,617✔
4137

4138
   return reg;
4139
}
4140

4141
vcode_reg_t emit_sub(vcode_reg_t lhs, vcode_reg_t rhs)
33,389✔
4142
{
4143
   return emit_sub_op(VCODE_OP_SUB, lhs, rhs, VCODE_INVALID_REG);
33,389✔
4144
}
4145

4146
vcode_reg_t emit_trap_sub(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
5,732✔
4147
{
4148
   vcode_reg_t result = emit_sub_op(VCODE_OP_TRAP_SUB, lhs, rhs, locus);
5,732✔
4149

4150
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
5,732✔
4151
                "trapping sub may only be used with integer types");
4152

4153
   return result;
5,732✔
4154
}
4155

4156
static void vcode_calculate_var_index_type(op_t *op, var_t *var)
62,409✔
4157
{
4158
   switch (vtype_kind(var->type)) {
62,409✔
4159
   case VCODE_TYPE_CARRAY:
12,375✔
4160
      op->type = vtype_pointer(vtype_elem(var->type));
12,375✔
4161
      op->result = vcode_add_reg(op->type);
12,375✔
4162
      vcode_reg_data(op->result)->bounds = vtype_bounds(var->type);
12,375✔
4163
      break;
12,375✔
4164

4165
   case VCODE_TYPE_RECORD:
6,437✔
4166
      op->type = vtype_pointer(var->type);
6,437✔
4167
      op->result = vcode_add_reg(op->type);
6,437✔
4168
      break;
6,437✔
4169

4170
   case VCODE_TYPE_INT:
43,597✔
4171
   case VCODE_TYPE_FILE:
4172
   case VCODE_TYPE_ACCESS:
4173
   case VCODE_TYPE_REAL:
4174
   case VCODE_TYPE_UARRAY:
4175
   case VCODE_TYPE_POINTER:
4176
   case VCODE_TYPE_SIGNAL:
4177
   case VCODE_TYPE_CONTEXT:
4178
   case VCODE_TYPE_OFFSET:
4179
   case VCODE_TYPE_TRIGGER:
4180
      op->type = vtype_pointer(var->type);
43,597✔
4181
      op->result = vcode_add_reg(op->type);
43,597✔
4182
      vcode_reg_data(op->result)->bounds = var->bounds;
43,597✔
4183
      break;
43,597✔
4184

4185
   default:
UNCOV
4186
      VCODE_ASSERT(false, "variable %s cannot be indexed",
×
4187
                   istr(var->name));
4188
   }
4189
}
62,409✔
4190

4191
vcode_reg_t emit_index(vcode_var_t var, vcode_reg_t offset)
23,737✔
4192
{
4193
   // Try to find a previous index of this var by this offset
4194
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_INDEX) {
789,369✔
4195
      if (other->address == var
51,117✔
4196
          && ((offset == VCODE_INVALID_REG && other->args.count == 0)
7,574✔
UNCOV
4197
              || (offset != VCODE_INVALID_REG
×
UNCOV
4198
                  && other->args.items[0] == offset)))
×
4199
         return other->result;
7,574✔
4200
   }
4201

4202
   op_t *op = vcode_add_op(VCODE_OP_INDEX);
16,163✔
4203
   op->address = var;
16,163✔
4204

4205
   if (offset != VCODE_INVALID_REG)
16,163✔
4206
      vcode_add_arg(op, offset);
×
4207

4208
   vcode_calculate_var_index_type(op, vcode_var_data(var));
16,163✔
4209

4210
   if (offset != VCODE_INVALID_REG)
16,163✔
UNCOV
4211
      VCODE_ASSERT(vtype_kind(vcode_reg_type(offset)) == VCODE_TYPE_OFFSET,
×
4212
                   "index offset r%d does not have offset type", offset);
4213

4214
   return op->result;
16,163✔
4215
}
4216

4217
vcode_reg_t emit_cast(vcode_type_t type, vcode_type_t bounds, vcode_reg_t reg)
206,360✔
4218
{
4219
   if (vtype_eq(vcode_reg_type(reg), type))
206,360✔
4220
      return reg;
206,360✔
4221

4222
   vtype_kind_t from = vtype_kind(vcode_reg_type(reg));
77,294✔
4223
   vtype_kind_t to   = vtype_kind(type);
77,294✔
4224

4225
   const bool integral =
154,588✔
4226
      (from == VCODE_TYPE_OFFSET || from == VCODE_TYPE_INT)
77,294✔
4227
      && (to == VCODE_TYPE_OFFSET || to == VCODE_TYPE_INT);
77,294✔
4228

4229
   int64_t value;
77,294✔
4230
   if (integral && vcode_reg_const(reg, &value))
77,294✔
4231
      return emit_const(type, value);
15,188✔
4232

4233
   // Try to find a previous cast of this register to this type
4234
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CAST) {
1,217,682✔
4235
      if (vtype_eq(other->type, type) && other->args.items[0] == reg)
137,332✔
4236
         return other->result;
14,395✔
4237
   }
4238

4239
   op_t *op = vcode_add_op(VCODE_OP_CAST);
47,711✔
4240
   vcode_add_arg(op, reg);
47,711✔
4241
   op->type   = type;
47,711✔
4242
   op->result = vcode_add_reg(type);
47,711✔
4243

4244
   static const vcode_type_t allowed[][2] = {
47,711✔
4245
      { VCODE_TYPE_INT,    VCODE_TYPE_OFFSET  },
4246
      { VCODE_TYPE_OFFSET, VCODE_TYPE_INT     },
4247
      { VCODE_TYPE_INT,    VCODE_TYPE_INT     },
4248
      { VCODE_TYPE_INT,    VCODE_TYPE_REAL    },
4249
      { VCODE_TYPE_REAL,   VCODE_TYPE_INT     },
4250
      { VCODE_TYPE_REAL,   VCODE_TYPE_REAL    },
4251
      { VCODE_TYPE_ACCESS, VCODE_TYPE_ACCESS  },
4252
   };
4253

4254
   if (from == VCODE_TYPE_INT && bounds == VCODE_INVALID_TYPE) {
47,711✔
4255
      reg_t *rr = vcode_reg_data(op->result);
10,262✔
4256
      rr->bounds = vcode_reg_bounds(reg);
10,262✔
4257
   }
4258
   else if (to == VCODE_TYPE_INT && bounds != VCODE_INVALID_TYPE) {
37,449✔
4259
      reg_t *rr = vcode_reg_data(op->result);
31,082✔
4260
      rr->bounds = bounds;
31,082✔
4261
   }
4262

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

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

4271
void emit_return(vcode_reg_t reg)
53,612✔
4272
{
4273
   op_t *op = vcode_add_op(VCODE_OP_RETURN);
53,612✔
4274
   if (reg != VCODE_INVALID_REG) {
53,612✔
4275
      vcode_add_arg(op, reg);
28,882✔
4276

4277
      const vtype_kind_t rkind = vcode_reg_kind(reg);
28,882✔
4278
      if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY)
28,882✔
4279
         vcode_heap_allocate(reg);
8,086✔
4280

4281
      VCODE_ASSERT(active_unit->kind == VCODE_UNIT_FUNCTION
28,882✔
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
28,882✔
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
}
53,612✔
4293

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

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

4311
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
10,743✔
4312
                "sched_waveform target is not signal");
4313
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
10,743✔
4314
                "sched_waveform net count is not offset type");
4315
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
10,743✔
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)
60✔
4320
{
4321
   op_t *op = vcode_add_op(VCODE_OP_FORCE);
60✔
4322
   vcode_add_arg(op, nets);
60✔
4323
   vcode_add_arg(op, nnets);
60✔
4324
   vcode_add_arg(op, values);
60✔
4325

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

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

4338
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
30✔
4339
                "release target is not signal");
4340
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
30✔
4341
                "release net count is not offset type");
4342
}
30✔
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)
36,871✔
4360
{
4361
   int64_t tconst;
36,871✔
4362
   if (vcode_reg_const(test, &tconst)) {
36,871✔
4363
      emit_jump(!!tconst ? btrue : bfalse);
4,833✔
4364
      return;
2,855✔
4365
   }
4366

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

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

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

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

4388
   return op->result;
7,487✔
4389
}
4390

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

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

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

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

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

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

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

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

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

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

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

4449
   // Find a previous identical select
4450
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_SELECT) {
301,198✔
4451
      if (other->args.items[0] == test && other->args.items[1] == rtrue
12,448✔
4452
          && other->args.items[2] == rfalse)
690✔
4453
         return other->result;
629✔
4454
   }
4455

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

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

4467
   return op->result;
13,164✔
4468
}
4469

4470
static vcode_reg_t emit_logical_identity(vcode_op_t op, vcode_reg_t reg, bool b)
388✔
4471
{
4472
   switch (op) {
388✔
4473
   case VCODE_OP_AND:  return b ? reg : emit_const(vtype_bool(), 0);
24✔
4474
   case VCODE_OP_OR:   return b ? emit_const(vtype_bool(), 1) : reg;
316✔
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,056✔
4485
{
4486
   vcode_type_t vtbool = vtype_bool();
7,056✔
4487

4488
   int64_t lconst, rconst;
7,056✔
4489
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
7,056✔
4490
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
7,056✔
4491
   if (l_is_const && r_is_const) {
7,056✔
4492
      switch (op) {
6✔
UNCOV
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,050✔
4504
      return emit_logical_identity(op, rhs, !!lconst);
309✔
4505
   else if (r_is_const)
6,741✔
4506
      return emit_logical_identity(op, lhs, !!rconst);
79✔
4507
   else if (lhs == rhs) {
6,662✔
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,635✔
4525

4526
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vtbool)
6,635✔
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,136✔
4534
{
4535
   return emit_logical(VCODE_OP_OR, lhs, rhs);
2,136✔
4536
}
4537

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

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

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

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

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

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

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

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

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

4579
vcode_reg_t emit_wrap(vcode_reg_t data, const vcode_dim_t *dims, int ndims)
45,923✔
4580
{
4581
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_WRAP) {
1,536,207✔
4582
      if (other->args.count == ndims*3 + 1 && other->args.items[0] == data) {
144,142✔
4583
         bool match = true;
4584
         for (int i = 0; match && i < ndims; i++) {
19,302✔
4585
            match = other->args.items[i*3 + 1] == dims[i].left
9,680✔
4586
               && other->args.items[i*3 + 2] == dims[i].right
8,210✔
4587
               && other->args.items[i*3 + 3] == dims[i].dir;
17,783✔
4588
         }
4589
         if (match)
9,622✔
4590
            return other->result;
8,045✔
4591
      }
4592
   }
4593

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

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

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

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

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

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

4627
static vcode_reg_t emit_uarray_op(vcode_op_t o, vcode_type_t rtype,
109,550✔
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,186,993✔
4633
      if (other->kind == o && other->args.items[0] == array && other->dim == dim
1,136,531✔
4634
          && (rtype == VCODE_INVALID_TYPE
23,053✔
4635
              || vtype_eq(rtype, vcode_reg_type(other->result))))
9,700✔
4636
         return other->result;
23,053✔
4637
      else if (other->kind == VCODE_OP_WRAP && other->result == array)
1,113,478✔
4638
         return other->args.items[1 + (dim * 3) + arg_index];
36,035✔
4639
   }
4640

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

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

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

4652
   if (rtype == VCODE_INVALID_TYPE)
50,462✔
4653
      rtype = vtype_offset();
32,870✔
4654

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

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

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

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

4676
vcode_reg_t emit_uarray_len(vcode_reg_t array, unsigned dim)
49,949✔
4677
{
4678
   VCODE_FOR_EACH_OP(other) {
523,020✔
4679
      if (other->kind == VCODE_OP_UARRAY_LEN) {
498,725✔
4680
         if (other->args.items[0] == array && other->dim == dim)
35,386✔
4681
            return other->result;
11,512✔
4682
      }
4683
      else if (other->kind == VCODE_OP_WRAP && other->result == array) {
463,339✔
4684
         VCODE_ASSERT(dim < (other->args.count - 1) / 3,
14,142✔
4685
                      "array dimension %d out of bounds", dim);
4686

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

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

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

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

4705
   return (op->result = vcode_add_reg(vtype_offset()));
24,295✔
4706
}
4707

4708
vcode_reg_t emit_unwrap(vcode_reg_t array)
38,131✔
4709
{
4710
   VCODE_FOR_EACH_OP(other) {
1,535,771✔
4711
      if (other->kind == VCODE_OP_WRAP && other->result == array)
1,508,539✔
4712
         return other->args.items[0];
9,491✔
4713
      else if (other->kind == VCODE_OP_UNWRAP && other->args.items[0] == array)
1,499,048✔
4714
         return other->result;
1,408✔
4715
   }
4716

4717
   op_t *op = vcode_add_op(VCODE_OP_UNWRAP);
27,232✔
4718
   vcode_add_arg(op, array);
27,232✔
4719

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

4724
   vcode_type_t elem = vt->elem;
27,232✔
4725

4726
   vcode_type_t rtype = (vtype_kind(elem) == VCODE_TYPE_SIGNAL)
27,232✔
4727
      ? elem : vtype_pointer(elem);
27,232✔
4728

4729
   op->result = vcode_add_reg(rtype);
27,232✔
4730

4731
   reg_t *rr = vcode_reg_data(op->result);
27,232✔
4732
   rr->bounds = elem;
27,232✔
4733

4734
   return op->result;
27,232✔
4735
}
4736

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

4747
   int64_t dir_const;
17,657✔
4748
   if (vcode_reg_const(dir, &dir_const)) {
17,657✔
4749
      vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
12,995✔
4750
      vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
12,995✔
4751

4752
      if (dir_const == RANGE_TO && lbounds->low > rbounds->high)
12,995✔
4753
         return emit_const(vtype_bool(), 1);
50✔
4754
      else if (dir_const == RANGE_TO && lbounds->high <= rbounds->low)
12,945✔
4755
         return emit_const(vtype_bool(), 0);
6,302✔
4756
      else if (dir_const == RANGE_DOWNTO && rbounds->low > lbounds->high)
6,643✔
4757
         return emit_const(vtype_bool(), 1);
112✔
4758
      else if (dir_const == RANGE_DOWNTO && rbounds->high <= lbounds->low)
6,531✔
4759
         return emit_const(vtype_bool(), 0);
1,696✔
4760
      else if (dir_const == RANGE_TO)
4,835✔
4761
         return emit_cmp(VCODE_CMP_GT, left, right);
1,505✔
4762
      else
4763
         return emit_cmp(VCODE_CMP_GT, right, left);
3,330✔
4764
   }
4765

4766
   op_t *op = vcode_add_op(VCODE_OP_RANGE_NULL);
4,662✔
4767
   vcode_add_arg(op, left);
4,662✔
4768
   vcode_add_arg(op, right);
4,662✔
4769
   vcode_add_arg(op, dir);
4,662✔
4770

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

4776
   return (op->result = vcode_add_reg(vtype_bool()));
4,662✔
4777
}
4778

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

4787
   VCODE_FOR_EACH_OP(other) {
297,800✔
4788
      if (other->kind == VCODE_OP_RANGE_LENGTH
288,004✔
4789
          && other->args.items[0] == left
5,882✔
4790
          && other->args.items[1] == right
4,730✔
4791
          && other->args.items[2] == dir)
4,381✔
4792
         return other->result;
4,381✔
4793
      else if (other->kind == VCODE_OP_UARRAY_LEFT && other->result == left) {
283,623✔
4794
         left_array = other->args.items[0];
332✔
4795
         left_dim = other->dim;
332✔
4796
      }
4797
      else if (other->kind == VCODE_OP_UARRAY_RIGHT && other->result == right) {
283,291✔
4798
         right_array = other->args.items[0];
332✔
4799
         right_dim = other->dim;
332✔
4800
      }
4801
      else if (other->kind == VCODE_OP_UARRAY_DIR && other->result == dir) {
282,959✔
4802
         dir_array = other->args.items[0];
1,066✔
4803
         dir_dim = other->dim;
1,066✔
4804
      }
4805
   }
4806

4807
   if (left_array != VCODE_INVALID_REG && left_array == right_array
9,796✔
4808
       && right_array == dir_array && left_dim == right_dim
332✔
4809
       && right_dim == dir_dim)
332✔
4810
      return emit_uarray_len(left_array, left_dim);
332✔
4811

4812
   int64_t lconst, rconst, dconst;
9,464✔
4813
   if (vcode_reg_const(dir, &dconst) && vcode_reg_const(left, &lconst)
9,464✔
4814
       && vcode_reg_const(right, &rconst)) {
5,301✔
4815

4816
      int64_t diff;
3,181✔
4817
      if (dconst == RANGE_TO)
3,181✔
4818
         diff = rconst - lconst;
2,861✔
4819
      else
4820
         diff = lconst - rconst;
320✔
4821

4822
      return emit_const(vtype_offset(), diff < 0 ? 0 : diff + 1);
3,181✔
4823
   }
4824

4825
   op_t *op = vcode_add_op(VCODE_OP_RANGE_LENGTH);
6,283✔
4826
   vcode_add_arg(op, left);
6,283✔
4827
   vcode_add_arg(op, right);
6,283✔
4828
   vcode_add_arg(op, dir);
6,283✔
4829

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

4835
   return (op->result = vcode_add_reg(vtype_offset()));
6,283✔
4836
}
4837

4838
vcode_reg_t emit_var_upref(int hops, vcode_var_t var)
53,809✔
4839
{
4840
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_VAR_UPREF) {
458,856✔
4841
      if (other->hops == hops && other->address == var)
61,976✔
4842
         return other->result;
7,563✔
4843
   }
4844

4845
   op_t *op = vcode_add_op(VCODE_OP_VAR_UPREF);
46,246✔
4846
   op->hops    = hops;
46,246✔
4847
   op->address = var;
46,246✔
4848

4849
   VCODE_ASSERT(hops > 0, "invalid hop count");
46,246✔
4850

4851
   vcode_unit_t vu = active_unit;
46,246✔
4852
   for (int i = 0; i < hops; i++) {
103,244✔
4853
      vu = vu->context;
56,998✔
4854
      VCODE_ASSERT(vu, "hop count is greater than depth");
56,998✔
4855
   }
4856

4857
   VCODE_ASSERT(var < vu->vars.count, "upref %d is not a variable", var);
46,246✔
4858

4859
   vcode_calculate_var_index_type(op, &(vu->vars.items[var]));
46,246✔
4860

4861
   return op->result;
46,246✔
4862
}
4863

4864
vcode_reg_t emit_init_signal(vcode_type_t type, vcode_reg_t count,
15,853✔
4865
                             vcode_reg_t size, vcode_reg_t value,
4866
                             vcode_reg_t flags, vcode_reg_t locus,
4867
                             vcode_reg_t offset)
4868
{
4869
   op_t *op = vcode_add_op(VCODE_OP_INIT_SIGNAL);
15,853✔
4870
   vcode_add_arg(op, count);
15,853✔
4871
   vcode_add_arg(op, size);
15,853✔
4872
   vcode_add_arg(op, value);
15,853✔
4873
   vcode_add_arg(op, flags);
15,853✔
4874
   vcode_add_arg(op, locus);
15,853✔
4875
   if (offset != VCODE_INVALID_REG)
15,853✔
4876
      vcode_add_arg(op, offset);
5,589✔
4877

4878
   vcode_type_t vtype = vcode_reg_type(value);
15,853✔
4879
   VCODE_ASSERT(vtype_is_scalar(type), "signal type must be scalar");
15,853✔
4880
   VCODE_ASSERT(vtype_eq(vtype, type)
15,853✔
4881
                || vtype_kind(vtype) == VCODE_TYPE_POINTER,
4882
                "init signal value type does not match signal type");
4883
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
15,853✔
4884
                "locus argument to init signal must be a debug locus");
4885
   VCODE_ASSERT(offset == VCODE_INVALID_REG
15,853✔
4886
                || vcode_reg_kind(offset) == VCODE_TYPE_POINTER,
4887
                "init signal offset argument must have pointer type");
4888

4889
   return (op->result = vcode_add_reg(vtype_signal(type)));
15,853✔
4890
}
4891

4892
void emit_resolve_signal(vcode_reg_t signal, vcode_reg_t resolution)
3,323✔
4893
{
4894
   op_t *op = vcode_add_op(VCODE_OP_RESOLVE_SIGNAL);
3,323✔
4895
   vcode_add_arg(op, signal);
3,323✔
4896
   vcode_add_arg(op, resolution);
3,323✔
4897

4898
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
3,323✔
4899
                "signal argument has wrong type");
4900
   VCODE_ASSERT(vcode_reg_kind(resolution) == VCODE_TYPE_RESOLUTION,
3,323✔
4901
                "resolution wrapper argument has wrong type");
4902
}
3,323✔
4903

4904
vcode_reg_t emit_implicit_signal(vcode_type_t type, vcode_reg_t count,
75✔
4905
                                 vcode_reg_t size, vcode_reg_t locus,
4906
                                 vcode_reg_t kind, vcode_reg_t closure,
4907
                                 vcode_reg_t delay)
4908
{
4909
   op_t *op = vcode_add_op(VCODE_OP_IMPLICIT_SIGNAL);
75✔
4910
   vcode_add_arg(op, count);
75✔
4911
   vcode_add_arg(op, size);
75✔
4912
   vcode_add_arg(op, locus);
75✔
4913
   vcode_add_arg(op, kind);
75✔
4914
   vcode_add_arg(op, closure);
75✔
4915
   vcode_add_arg(op, delay);
75✔
4916

4917
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
75✔
4918
                "count argument to implicit signal is not offset");
4919
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
75✔
4920
                "kind argument to implicit signal is not offset");
4921
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
75✔
4922
                "closure argument to implicit signal is not a closure");
4923
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
75✔
4924
                "locus argument to implicit signal must be a debug locus");
4925
   VCODE_ASSERT(vcode_reg_kind(delay) == VCODE_TYPE_INT,
75✔
4926
                "delay argument to implicit signal must be time");
4927

4928
   return (op->result = vcode_add_reg(vtype_signal(type)));
75✔
4929
}
4930

4931
void emit_map_signal(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
5,305✔
4932
{
4933
   op_t *op = vcode_add_op(VCODE_OP_MAP_SIGNAL);
5,305✔
4934
   vcode_add_arg(op, src);
5,305✔
4935
   vcode_add_arg(op, dst);
5,305✔
4936
   vcode_add_arg(op, count);
5,305✔
4937

4938
   VCODE_ASSERT(vcode_reg_kind(src) == VCODE_TYPE_SIGNAL,
5,305✔
4939
                "src argument to map signal is not a signal");
4940
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
5,305✔
4941
                "dst argument to map signal is not a signal");
4942
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
5,305✔
4943
                "count argument type to map signal is not offset");
4944
}
5,305✔
4945

4946
void emit_map_const(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
219✔
4947
{
4948
   op_t *op = vcode_add_op(VCODE_OP_MAP_CONST);
219✔
4949
   vcode_add_arg(op, src);
219✔
4950
   vcode_add_arg(op, dst);
219✔
4951
   vcode_add_arg(op, count);
219✔
4952

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

4959
void emit_map_implicit(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
57✔
4960
{
4961
   op_t *op = vcode_add_op(VCODE_OP_MAP_IMPLICIT);
57✔
4962
   vcode_add_arg(op, src);
57✔
4963
   vcode_add_arg(op, dst);
57✔
4964
   vcode_add_arg(op, count);
57✔
4965

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

4974
void emit_drive_signal(vcode_reg_t target, vcode_reg_t count)
9,384✔
4975
{
4976
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DRIVE_SIGNAL) {
114,856✔
4977
      if (other->args.items[0] == target && other->args.items[1] == count)
13,835✔
4978
         return;
4979
   }
4980

4981
   op_t *op = vcode_add_op(VCODE_OP_DRIVE_SIGNAL);
9,360✔
4982
   vcode_add_arg(op, target);
9,360✔
4983
   vcode_add_arg(op, count);
9,360✔
4984

4985
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
9,360✔
4986
                "target argument to drive signal is not a signal");
4987
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
9,360✔
4988
                "count argument type to drive signal is not offset");
4989
}
4990

4991
void emit_transfer_signal(vcode_reg_t target, vcode_reg_t source,
1,209✔
4992
                          vcode_reg_t count, vcode_reg_t reject,
4993
                          vcode_reg_t after)
4994
{
4995
   op_t *op = vcode_add_op(VCODE_OP_TRANSFER_SIGNAL);
1,209✔
4996
   vcode_add_arg(op, target);
1,209✔
4997
   vcode_add_arg(op, source);
1,209✔
4998
   vcode_add_arg(op, count);
1,209✔
4999
   vcode_add_arg(op, reject);
1,209✔
5000
   vcode_add_arg(op, after);
1,209✔
5001

5002
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
1,209✔
5003
                "target argument to transfer signal is not a signal");
5004
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
1,209✔
5005
                "count argument type to transfer signal is not offset");
5006
   VCODE_ASSERT(vcode_reg_kind(source) == VCODE_TYPE_SIGNAL,
1,209✔
5007
                "source argument to transfer signal is not a signal");
5008
}
1,209✔
5009

5010
vcode_reg_t emit_resolution_wrapper(vcode_type_t type, vcode_reg_t closure,
3,209✔
5011
                                    vcode_reg_t ileft, vcode_reg_t nlits)
5012
{
5013
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RESOLUTION_WRAPPER) {
134,016✔
5014
      if (other->args.items[0] == closure
2,249✔
5015
          && other->args.items[1] == ileft
2,246✔
5016
          && other->args.items[2] == nlits)
2,246✔
5017
         return other->result;
2,246✔
5018
   }
5019

5020
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
963✔
5021
                "first argument to resolution wrapper must be closure");
5022

5023
   op_t *op = vcode_add_op(VCODE_OP_RESOLUTION_WRAPPER);
963✔
5024
   vcode_add_arg(op, closure);
963✔
5025
   vcode_add_arg(op, ileft);
963✔
5026
   vcode_add_arg(op, nlits);
963✔
5027

5028
   return (op->result = vcode_add_reg(vtype_resolution(type)));
963✔
5029
}
5030

5031
vcode_reg_t emit_closure(ident_t func, vcode_reg_t context, vcode_type_t atype,
3,581✔
5032
                         vcode_type_t rtype)
5033
{
5034
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CLOSURE) {
140,279✔
5035
      if (other->func == func && other->args.items[0] == context)
2,687✔
5036
         return other->result;
2,246✔
5037
   }
5038

5039
   op_t *op = vcode_add_op(VCODE_OP_CLOSURE);
1,335✔
5040
   vcode_add_arg(op, context);
1,335✔
5041
   op->func = func;
1,335✔
5042
   op->type = atype;
1,335✔
5043

5044
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
1,335✔
5045
                "invalid closure context argument");
5046

5047
   return (op->result = vcode_add_reg(vtype_closure(rtype)));
1,335✔
5048
}
5049

5050
vcode_reg_t emit_package_init(ident_t name, vcode_reg_t context)
30,753✔
5051
{
5052
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_PACKAGE_INIT) {
46,992✔
5053
      if (other->func == name)
23,370✔
5054
         return other->result;
12,917✔
5055
   }
5056

5057
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_INIT);
17,836✔
5058
   op->func = name;
17,836✔
5059
   if (context != VCODE_INVALID_REG)
17,836✔
5060
      vcode_add_arg(op, context);
183✔
5061

5062
   VCODE_ASSERT(context == VCODE_INVALID_REG
17,836✔
5063
                || vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
5064
                "invalid protected init context argument");
5065
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_INSTANCE
17,836✔
5066
                || active_unit->kind == VCODE_UNIT_PACKAGE
5067
                || active_unit->kind == VCODE_UNIT_THUNK,
5068
                "cannot use package init here");
5069
   VCODE_ASSERT(name != active_unit->name, "cyclic package init");
17,836✔
5070

5071
   return (op->result = vcode_add_reg(vtype_context(name)));
17,836✔
5072
}
5073

5074
vcode_reg_t emit_protected_init(vcode_type_t type, vcode_reg_t context,
163✔
5075
                                vcode_reg_t path_name, vcode_reg_t inst_name)
5076
{
5077
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_INIT);
163✔
5078
   vcode_add_arg(op, context);
163✔
5079
   op->func = vtype_name(type);
163✔
5080

5081
   if (path_name != VCODE_INVALID_REG && inst_name != VCODE_INVALID_REG) {
163✔
5082
      vcode_add_arg(op, path_name);
38✔
5083
      vcode_add_arg(op, inst_name);
38✔
5084

5085
      VCODE_ASSERT(vcode_reg_kind(path_name) == VCODE_TYPE_UARRAY,
38✔
5086
                   "path name argument must be uarray");
5087
      VCODE_ASSERT(vcode_reg_kind(inst_name) == VCODE_TYPE_UARRAY,
38✔
5088
                   "inst name argument must be uarray");
5089
   }
5090

5091
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CONTEXT,
163✔
5092
                "protected init type must be context");
5093
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
163✔
5094
                "invalid protected init context argument");
5095

5096
   return (op->result = vcode_add_reg(type));
163✔
5097
}
5098

5099
void emit_process_init(ident_t name, vcode_reg_t locus)
112✔
5100
{
5101
   op_t *op = vcode_add_op(VCODE_OP_PROCESS_INIT);
112✔
5102
   vcode_add_arg(op, locus);
112✔
5103
   op->func = name;
112✔
5104

5105
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
112✔
5106
                "locus argument to process init must be a debug locus");
5107
}
112✔
5108

5109
void emit_protected_free(vcode_reg_t obj)
7✔
5110
{
5111
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_FREE);
7✔
5112
   vcode_add_arg(op, obj);
7✔
5113

5114
   VCODE_ASSERT(vcode_reg_kind(obj) == VCODE_TYPE_CONTEXT,
7✔
5115
                "protected object type must be context");
5116
}
7✔
5117

5118
vcode_reg_t emit_context_upref(int hops)
15,728✔
5119
{
5120
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONTEXT_UPREF) {
108,521✔
5121
      if (other->hops == hops)
7,044✔
5122
         return other->result;
6,985✔
5123
   }
5124

5125
   op_t *op = vcode_add_op(VCODE_OP_CONTEXT_UPREF);
8,743✔
5126
   op->hops = hops;
8,743✔
5127

5128
   VCODE_ASSERT(hops >= 0, "invalid hop count");
8,743✔
5129

5130
   vcode_unit_t vu = active_unit;
8,743✔
5131
   for (int i = 0; i < hops; i++) {
16,754✔
5132
      vu = vu->context;
8,011✔
5133
      VCODE_ASSERT(vu, "hop count is greater than depth");
8,011✔
5134
   }
5135

5136
   return (op->result = vcode_add_reg(vtype_context(vu->name)));
8,743✔
5137
}
5138

5139
static vcode_reg_t emit_signal_flag(vcode_op_t opkind, vcode_reg_t nets,
652✔
5140
                                    vcode_reg_t len)
5141
{
5142
   op_t *op = vcode_add_op(opkind);
652✔
5143
   vcode_add_arg(op, nets);
652✔
5144
   vcode_add_arg(op, len);
652✔
5145

5146
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
652✔
5147
                "argument to %s is not a signal", vcode_op_string(opkind));
5148

5149
   return (op->result = vcode_add_reg(vtype_bool()));
652✔
5150
}
5151

5152
vcode_reg_t emit_event_flag(vcode_reg_t nets, vcode_reg_t len)
432✔
5153
{
5154
   return emit_signal_flag(VCODE_OP_EVENT, nets, len);
432✔
5155
}
5156

5157
vcode_reg_t emit_active_flag(vcode_reg_t nets, vcode_reg_t len)
220✔
5158
{
5159
   return emit_signal_flag(VCODE_OP_ACTIVE, nets, len);
220✔
5160
}
5161

5162
vcode_reg_t emit_record_ref(vcode_reg_t record, unsigned field)
41,563✔
5163
{
5164
   // Try scanning backwards through the block for another record ref
5165
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RECORD_REF) {
2,770,494✔
5166
      if (other->args.items[0] == record && other->field == field)
517,104✔
5167
         return other->result;
3,875✔
5168
   }
5169

5170
   op_t *op = vcode_add_op(VCODE_OP_RECORD_REF);
37,688✔
5171
   op->field = field;
37,688✔
5172
   vcode_add_arg(op, record);
37,688✔
5173

5174
   vtype_t *rptype = vcode_type_data(vcode_reg_type(record));
37,688✔
5175

5176
   VCODE_ASSERT(rptype->kind == VCODE_TYPE_POINTER,
37,688✔
5177
                "argument to record ref must be a pointer");
5178

5179
   vtype_t *rtype = vcode_type_data(rptype->pointed);
37,688✔
5180
   VCODE_ASSERT(rtype->kind == VCODE_TYPE_RECORD,
37,688✔
5181
                "argument must be pointer to record or record signal");
5182

5183
   VCODE_ASSERT(field < rtype->fields.count, "invalid field %d", field);
37,688✔
5184

5185
   vcode_type_t field_type  = rtype->fields.items[field];
37,688✔
5186
   vcode_type_t bounds_type = field_type;
37,688✔
5187
   vcode_type_t result_type = field_type;
37,688✔
5188

5189
   const vtype_kind_t fkind = vtype_kind(field_type);
37,688✔
5190
   if (fkind == VCODE_TYPE_CARRAY)
37,688✔
5191
      result_type = bounds_type = vtype_elem(field_type);
5,141✔
5192
   else if (fkind == VCODE_TYPE_UARRAY) {
32,547✔
5193
      bounds_type = vtype_elem(field_type);
2,718✔
5194
      result_type = field_type;
2,718✔
5195
   }
5196

5197
   op->result = vcode_add_reg(vtype_pointer(result_type));
37,688✔
5198

5199
   reg_t *rr = vcode_reg_data(op->result);
37,688✔
5200
   rr->bounds = bounds_type;
37,688✔
5201

5202
   return op->result;
37,688✔
5203
}
5204

5205
vcode_reg_t emit_array_ref(vcode_reg_t array, vcode_reg_t offset)
35,695✔
5206
{
5207
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ARRAY_REF) {
1,665,996✔
5208
      if (other->args.items[0] == array && other->args.items[1] == offset)
98,458✔
5209
         return other->result;
1,177✔
5210
   }
5211

5212
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_REF);
34,518✔
5213
   vcode_add_arg(op, array);
34,518✔
5214
   vcode_add_arg(op, offset);
34,518✔
5215

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

5224
   op->result = vcode_add_reg(rtype);
34,518✔
5225

5226
   reg_t *rr = vcode_reg_data(op->result);
34,518✔
5227
   rr->bounds = vcode_reg_bounds(array);
34,518✔
5228

5229
   return op->result;
34,518✔
5230
}
5231

5232
void emit_copy(vcode_reg_t dest, vcode_reg_t src, vcode_reg_t count)
21,042✔
5233
{
5234
   int64_t cconst;
21,042✔
5235
   if (count != VCODE_INVALID_REG && vcode_reg_const(count, &cconst)
21,042✔
5236
       && cconst == 0)
10,724✔
5237
      return;
4,937✔
5238
   else if (dest == src)
20,874✔
5239
      return;
5240

5241
   op_t *op = vcode_add_op(VCODE_OP_COPY);
16,105✔
5242
   vcode_add_arg(op, dest);
16,105✔
5243
   vcode_add_arg(op, src);
16,105✔
5244
   if (count != VCODE_INVALID_REG)
16,105✔
5245
      vcode_add_arg(op, count);
14,279✔
5246

5247
   vcode_type_t dtype = vcode_reg_type(dest);
16,105✔
5248
   vcode_type_t stype = vcode_reg_type(src);
16,105✔
5249

5250
   vtype_kind_t dkind = vtype_kind(dtype);
16,105✔
5251
   vtype_kind_t skind = vtype_kind(stype);
16,105✔
5252

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

5263
   op->type = vtype_pointed(dtype);
16,105✔
5264
}
5265

5266
void emit_sched_event(vcode_reg_t nets, vcode_reg_t n_elems)
5,913✔
5267
{
5268
   VCODE_FOR_EACH_OP(other) {
98,433✔
5269
      if (other->kind == VCODE_OP_CLEAR_EVENT)
92,556✔
5270
         break;
5271
      else if (other->kind == VCODE_OP_SCHED_EVENT
92,526✔
5272
               && other->args.items[0] == nets
4,765✔
5273
               && other->args.items[1] == n_elems)
9✔
5274
         return;
5275
   }
5276

5277
   op_t *op = vcode_add_op(VCODE_OP_SCHED_EVENT);
5,907✔
5278
   vcode_add_arg(op, nets);
5,907✔
5279
   vcode_add_arg(op, n_elems);
5,907✔
5280

5281
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
5,907✔
5282
                "nets argument to sched event must be signal");
5283
}
5284

5285
void emit_clear_event(vcode_reg_t nets, vcode_reg_t n_elems)
507✔
5286
{
5287
   VCODE_FOR_EACH_OP(other) {
2,340✔
5288
      if (other->kind == VCODE_OP_SCHED_EVENT)
1,833✔
5289
         break;
5290
      else if (other->kind == VCODE_OP_CLEAR_EVENT
1,833✔
5291
               && other->args.items[0] == nets
39✔
UNCOV
5292
               && other->args.items[1] == n_elems)
×
5293
         return;
5294
   }
5295

5296
   op_t *op = vcode_add_op(VCODE_OP_CLEAR_EVENT);
507✔
5297
   vcode_add_arg(op, nets);
507✔
5298
   vcode_add_arg(op, n_elems);
507✔
5299

5300
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
507✔
5301
                "nets argument to clear event must be signal");
5302
}
5303

5304
void emit_resume(ident_t func)
880✔
5305
{
5306
   op_t *op = vcode_add_op(VCODE_OP_RESUME);
880✔
5307
   op->func = func;
880✔
5308

5309
   block_t *b = &(active_unit->blocks.items[active_block]);
880✔
5310
   VCODE_ASSERT(b->ops.count == 1, "resume must be first op in a block");
880✔
5311
}
880✔
5312

5313
void emit_memset(vcode_reg_t ptr, vcode_reg_t value, vcode_reg_t len)
5,684✔
5314
{
5315
   int64_t lconst;
5,684✔
5316
   if (vcode_reg_const(len, &lconst) && lconst == 0)
5,684✔
5317
      return;
29✔
5318

5319
   op_t *op = vcode_add_op(VCODE_OP_MEMSET);
5,655✔
5320
   vcode_add_arg(op, ptr);
5,655✔
5321
   vcode_add_arg(op, value);
5,655✔
5322
   vcode_add_arg(op, len);
5,655✔
5323

5324
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
5,655✔
5325
                "target of memset must have pointer type");
5326
   VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(value)),
5,655✔
5327
                "value of memset must have scalar type");
5328
   VCODE_ASSERT(vtype_kind(vcode_reg_type(len)) == VCODE_TYPE_OFFSET,
5,655✔
5329
                "length of memset must have offset type");
5330
}
5331

5332
void emit_case(vcode_reg_t value, vcode_block_t def, const vcode_reg_t *cases,
644✔
5333
               const vcode_block_t *blocks, int ncases)
5334
{
5335
   int64_t cval1, cval2;
644✔
5336
   bool is_const = vcode_reg_const(value, &cval1);
644✔
5337

5338
   for (int i = 0; i < ncases; i++) {
5,359✔
5339
      bool can_fold = false;
4,719✔
5340
      if (cases[i] == value)
4,719✔
5341
         can_fold = true;
5342
      else if (is_const && vcode_reg_const(cases[i], &cval2))
4,719✔
5343
         can_fold = (cval1 == cval2);
4✔
5344

5345
      if (can_fold) {
4✔
5346
         emit_jump(blocks[i]);
4✔
5347
         return;
8✔
5348
      }
5349
   }
5350

5351
   if (is_const) {
640✔
UNCOV
5352
      emit_jump(def);
×
UNCOV
5353
      return;
×
5354
   }
5355

5356
   op_t *op = vcode_add_op(VCODE_OP_CASE);
640✔
5357
   vcode_add_arg(op, value);
640✔
5358
   vcode_add_target(op, def);
640✔
5359

5360
   for (int i = 0; i < ncases; i++) {
5,355✔
5361
      vcode_add_arg(op, cases[i]);
4,715✔
5362
      vcode_add_target(op, blocks[i]);
4,715✔
5363

5364
#ifdef DEBUG
5365
      for (int j = 0; j < i; j++)
245,211✔
5366
         VCODE_ASSERT(cases[i] != cases[j], "duplicate case choice");
240,496✔
5367
#endif
5368
   }
5369
}
5370

5371
void emit_file_open(vcode_reg_t file, vcode_reg_t name, vcode_reg_t length,
262✔
5372
                    vcode_reg_t kind, vcode_reg_t status)
5373
{
5374
   op_t *op = vcode_add_op(VCODE_OP_FILE_OPEN);
262✔
5375
   vcode_add_arg(op, file);
262✔
5376
   vcode_add_arg(op, name);
262✔
5377
   vcode_add_arg(op, length);
262✔
5378
   vcode_add_arg(op, kind);
262✔
5379
   if (status != VCODE_INVALID_REG)
262✔
5380
      vcode_add_arg(op, status);
26✔
5381

5382
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
262✔
5383
                "file open first argument must have file pointer type");
5384
}
262✔
5385

5386
void emit_file_write(vcode_reg_t file, vcode_reg_t value, vcode_reg_t length)
125✔
5387
{
5388
   op_t *op = vcode_add_op(VCODE_OP_FILE_WRITE);
125✔
5389
   vcode_add_arg(op, file);
125✔
5390
   vcode_add_arg(op, value);
125✔
5391
   if (length != VCODE_INVALID_REG)
125✔
5392
      vcode_add_arg(op, length);
68✔
5393

5394
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
125✔
5395
                "file write first argument must have file pointer type");
5396
}
125✔
5397

5398
void emit_file_read(vcode_reg_t file, vcode_reg_t ptr,
75✔
5399
                    vcode_reg_t inlen, vcode_reg_t outlen)
5400
{
5401
   op_t *op = vcode_add_op(VCODE_OP_FILE_READ);
75✔
5402
   vcode_add_arg(op, file);
75✔
5403
   vcode_add_arg(op, ptr);
75✔
5404
   if (inlen != VCODE_INVALID_REG) {
75✔
5405
      vcode_add_arg(op, inlen);
27✔
5406
      if (outlen != VCODE_INVALID_REG)
27✔
5407
         vcode_add_arg(op, outlen);
18✔
5408
   }
5409

5410
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
75✔
5411
                "file read first argument must have file pointer type");
5412
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
75✔
5413
                "file read pointer argument must have pointer type");
5414
   VCODE_ASSERT(outlen == VCODE_INVALID_REG
75✔
5415
                || vtype_kind(vcode_reg_type(outlen)) == VCODE_TYPE_POINTER,
5416
                "file read outlen argument must have pointer type");
5417
}
75✔
5418

5419
vcode_reg_t emit_null(vcode_type_t type)
9,452✔
5420
{
5421
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_NULL) {
219,276✔
5422
      if (vtype_eq(vcode_reg_type(other->result), type))
4,800✔
5423
         return other->result;
2,380✔
5424
   }
5425

5426
   op_t *op = vcode_add_op(VCODE_OP_NULL);
7,072✔
5427
   op->result = vcode_add_reg(type);
7,072✔
5428

5429
   vtype_kind_t kind = vtype_kind(type);
7,072✔
5430
   VCODE_ASSERT(kind == VCODE_TYPE_POINTER || kind == VCODE_TYPE_FILE
7,072✔
5431
                || kind == VCODE_TYPE_ACCESS || kind == VCODE_TYPE_CONTEXT,
5432
                "null type must be file, access, context, or pointer");
5433

5434
   return op->result;
5435
}
5436

5437
vcode_reg_t emit_new(vcode_type_t type, vcode_reg_t length)
428✔
5438
{
5439
   op_t *op = vcode_add_op(VCODE_OP_NEW);
428✔
5440
   if (length != VCODE_INVALID_REG)
428✔
5441
      vcode_add_arg(op, length);
337✔
5442

5443
   op->result = vcode_add_reg(vtype_access(type));
428✔
5444

5445
   vtype_kind_t kind = vtype_kind(type);
428✔
5446
   VCODE_ASSERT(kind == VCODE_TYPE_INT || kind == VCODE_TYPE_RECORD
428✔
5447
                || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_ACCESS
5448
                || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_CONTEXT,
5449
                "new type must be int, real, record, access, or uarray");
5450
   VCODE_ASSERT(length == VCODE_INVALID_REG
428✔
5451
                || vtype_kind(vcode_reg_type(length)) == VCODE_TYPE_OFFSET,
5452
                "new length must have offset type");
5453

5454
   return op->result;
428✔
5455
}
5456

5457
void emit_null_check(vcode_reg_t ptr, vcode_reg_t locus)
1,755✔
5458
{
5459
   VCODE_FOR_EACH_OP(other) {
104,961✔
5460
      if (other->kind == VCODE_OP_NULL_CHECK && other->args.items[0] == ptr)
103,838✔
5461
         return;
5462
      else if (other->kind == VCODE_OP_NEW && other->result == ptr)
103,461✔
5463
         return;
5464
   }
5465

5466
   op_t *op = vcode_add_op(VCODE_OP_NULL_CHECK);
1,123✔
5467
   vcode_add_arg(op, ptr);
1,123✔
5468
   vcode_add_arg(op, locus);
1,123✔
5469

5470
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_ACCESS,
1,123✔
5471
                "null check argument must be an access");
5472
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,123✔
5473
                "locus argument to null check must be a debug locus");
5474
}
5475

5476
void emit_deallocate(vcode_reg_t ptr)
207✔
5477
{
5478
   op_t *op = vcode_add_op(VCODE_OP_DEALLOCATE);
207✔
5479
   vcode_add_arg(op, ptr);
207✔
5480

5481
   vcode_type_t ptype = vcode_reg_type(ptr);
207✔
5482
   VCODE_ASSERT(vtype_kind(ptype) == VCODE_TYPE_POINTER
207✔
5483
                && vtype_kind(vtype_pointed(ptype)) == VCODE_TYPE_ACCESS,
5484
                "deallocate argument must be pointer to access");
5485
}
207✔
5486

5487
vcode_reg_t emit_all(vcode_reg_t reg)
2,183✔
5488
{
5489
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ALL) {
146,087✔
5490
      if (other->args.items[0] == reg)
9,251✔
5491
         return other->result;
632✔
5492
   }
5493

5494
   op_t *op = vcode_add_op(VCODE_OP_ALL);
1,551✔
5495
   vcode_add_arg(op, reg);
1,551✔
5496

5497
   vcode_type_t vtype = vcode_reg_type(reg);
1,551✔
5498

5499
   VCODE_ASSERT(vtype_kind(vtype) == VCODE_TYPE_ACCESS,
1,551✔
5500
                "all argument must be an access");
5501

5502
   vcode_type_t pointed = vtype_pointed(vtype);
1,551✔
5503
   op->result = vcode_add_reg(vtype_pointer(pointed));
1,551✔
5504

5505
   reg_t *rr = vcode_reg_data(op->result);
1,551✔
5506
   rr->bounds = pointed;
1,551✔
5507

5508
   VCODE_ASSERT(vtype_kind(pointed) != VCODE_TYPE_OPAQUE,
1,551✔
5509
                "cannot dereference opaque type");
5510

5511
   return op->result;
5512
}
5513

5514
static vcode_reg_t emit_signal_data_op(vcode_op_t kind, vcode_reg_t sig)
14,920✔
5515
{
5516
   block_t *b = &(active_unit->blocks.items[active_block]);
14,920✔
5517
   for (int i = b->ops.count - 1; i >= 0; i--) {
366,783✔
5518
      const op_t *other = &(b->ops.items[i]);
352,418✔
5519
      if (other->kind == kind && other->args.items[0] == sig)
352,418✔
5520
         return other->result;
555✔
5521
   }
5522

5523
   op_t *op = vcode_add_op(kind);
14,365✔
5524
   vcode_add_arg(op, sig);
14,365✔
5525

5526
   vcode_type_t stype = vcode_reg_type(sig);
14,365✔
5527
   op->type = stype;
14,365✔
5528

5529
   VCODE_ASSERT(vtype_kind(stype) == VCODE_TYPE_SIGNAL,
14,365✔
5530
                "argument r%d to resolved is not a signal", sig);
5531

5532
   vcode_type_t rtype = vtype_base(stype);
14,365✔
5533

5534
   const vtype_kind_t rkind = vtype_kind(rtype);
14,365✔
5535
   if (rkind == VCODE_TYPE_CARRAY || rkind == VCODE_TYPE_UARRAY)
14,365✔
UNCOV
5536
      rtype = vtype_elem(rtype);
×
5537

5538
   VCODE_ASSERT(vtype_is_scalar(rtype),
14,365✔
5539
                "resolved signal base type must be scalar");
5540

5541
   op->result = vcode_add_reg(vtype_pointer(rtype));
14,365✔
5542

5543
   reg_t *rr = vcode_reg_data(op->result);
14,365✔
5544
   rr->bounds = rtype;
14,365✔
5545

5546
   return op->result;
14,365✔
5547
}
5548

5549
vcode_reg_t emit_resolved(vcode_reg_t sig, vcode_reg_t count)
14,825✔
5550
{
5551
   return emit_signal_data_op(VCODE_OP_RESOLVED, sig);
14,825✔
5552
}
5553

5554
vcode_reg_t emit_last_value(vcode_reg_t sig, vcode_reg_t count)
95✔
5555
{
5556
   return emit_signal_data_op(VCODE_OP_LAST_VALUE, sig);
95✔
5557
}
5558

5559
vcode_reg_t emit_last_event(vcode_reg_t signal, vcode_reg_t len)
33✔
5560
{
5561
   op_t *op = vcode_add_op(VCODE_OP_LAST_EVENT);
33✔
5562
   vcode_add_arg(op, signal);
33✔
5563
   if (len != VCODE_INVALID_REG)
33✔
5564
      vcode_add_arg(op, len);
9✔
5565

5566
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
33✔
5567
                "signal argument to last event must have signal type");
5568
   VCODE_ASSERT(len == VCODE_INVALID_REG
33✔
5569
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5570
                "length argument to last event must have offset type");
5571

5572
   return (op->result = vcode_add_reg(vtype_time()));
33✔
5573
}
5574

5575
vcode_reg_t emit_last_active(vcode_reg_t signal, vcode_reg_t len)
36✔
5576
{
5577
   op_t *op = vcode_add_op(VCODE_OP_LAST_ACTIVE);
36✔
5578
   vcode_add_arg(op, signal);
36✔
5579
   if (len != VCODE_INVALID_REG)
36✔
5580
      vcode_add_arg(op, len);
6✔
5581

5582
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
36✔
5583
                "signal argument to last active must have signal type");
5584
   VCODE_ASSERT(len == VCODE_INVALID_REG
36✔
5585
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5586
                "length argument to last active must have offset type");
5587

5588
   return (op->result = vcode_add_reg(vtype_time()));
36✔
5589
}
5590

5591
void emit_alias_signal(vcode_reg_t signal, vcode_reg_t locus)
4,205✔
5592
{
5593
   op_t *op = vcode_add_op(VCODE_OP_ALIAS_SIGNAL);
4,205✔
5594
   vcode_add_arg(op, signal);
4,205✔
5595
   vcode_add_arg(op, locus);
4,205✔
5596

5597
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
4,205✔
5598
                "signal argument must have signal type");
5599
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
4,205✔
5600
                "locus argument must have debug locus type");
5601
}
4,205✔
5602

5603
vcode_reg_t emit_driving_flag(vcode_reg_t signal, vcode_reg_t len)
36✔
5604
{
5605
   op_t *op = vcode_add_op(VCODE_OP_DRIVING);
36✔
5606
   vcode_add_arg(op, signal);
36✔
5607
   vcode_add_arg(op, len);
36✔
5608

5609
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
36✔
5610
                "signal argument to last active must have signal type");
5611
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
36✔
5612
                "length argument to last active must have offset type");
5613

5614
   return (op->result = vcode_add_reg(vtype_bool()));
36✔
5615
}
5616

5617
vcode_reg_t emit_driving_value(vcode_reg_t signal, vcode_reg_t len)
140✔
5618
{
5619
   op_t *op = vcode_add_op(VCODE_OP_DRIVING_VALUE);
140✔
5620
   vcode_add_arg(op, signal);
140✔
5621
   if (len != VCODE_INVALID_REG)
140✔
5622
      vcode_add_arg(op, len);
33✔
5623

5624
   vcode_type_t signal_type = vcode_reg_type(signal);
140✔
5625

5626
   VCODE_ASSERT(vtype_kind(signal_type) == VCODE_TYPE_SIGNAL,
140✔
5627
                "signal argument to last active must have signal type");
5628
   VCODE_ASSERT(len == VCODE_INVALID_REG
140✔
5629
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5630
                "length argument to last active must have offset type");
5631

5632
   vcode_type_t base_type = vtype_base(signal_type);
140✔
5633
   op->result = vcode_add_reg(vtype_pointer(base_type));
140✔
5634

5635
   reg_t *rr = vcode_reg_data(op->result);
140✔
5636
   rr->bounds = base_type;
140✔
5637

5638
   return op->result;
140✔
5639
}
5640

5641
void emit_length_check(vcode_reg_t llen, vcode_reg_t rlen, vcode_reg_t locus,
22,011✔
5642
                       vcode_reg_t dim)
5643
{
5644
   if (rlen == llen)
22,011✔
5645
      return;
5646

5647
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LENGTH_CHECK) {
186,526✔
5648
      if (other->args.items[0] == llen && other->args.items[1] == rlen)
2,851✔
5649
         return;
5650
   }
5651

5652
   op_t *op = vcode_add_op(VCODE_OP_LENGTH_CHECK);
6,802✔
5653
   vcode_add_arg(op, llen);
6,802✔
5654
   vcode_add_arg(op, rlen);
6,802✔
5655
   vcode_add_arg(op, locus);
6,802✔
5656
   if (dim != VCODE_INVALID_REG)
6,802✔
5657
      vcode_add_arg(op, dim);
24✔
5658

5659
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
6,802✔
5660
                "locus argument to length check must be a debug locus");
5661
}
5662

5663
void emit_exponent_check(vcode_reg_t exp, vcode_reg_t locus)
816✔
5664
{
5665
   int64_t cval;
816✔
5666
   if (vcode_reg_const(exp, &cval) && cval >= 0)
816✔
5667
      return;
299✔
5668

5669
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_EXPONENT_CHECK) {
3,254✔
5670
      if (other->args.items[0] == exp)
12✔
5671
         return;
5672
   }
5673

5674
   op_t *op = vcode_add_op(VCODE_OP_EXPONENT_CHECK);
517✔
5675
   vcode_add_arg(op, exp);
517✔
5676
   vcode_add_arg(op, locus);
517✔
5677

5678
   VCODE_ASSERT(vcode_reg_kind(exp) == VCODE_TYPE_INT,
517✔
5679
                "exp argument to exponent check must be a integer");
5680
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
517✔
5681
                "locus argument to exponent check must be a debug locus");
5682
}
5683

5684
void emit_zero_check(vcode_reg_t denom, vcode_reg_t locus)
1,067✔
5685
{
5686
   int64_t cval;
1,067✔
5687
   if (vcode_reg_const(denom, &cval) && cval != 0)
1,067✔
5688
      return;
964✔
5689

5690
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ZERO_CHECK) {
2,886✔
5691
      if (other->args.items[0] == denom)
56✔
5692
         return;
5693
   }
5694

5695
   op_t *op = vcode_add_op(VCODE_OP_ZERO_CHECK);
103✔
5696
   vcode_add_arg(op, denom);
103✔
5697
   vcode_add_arg(op, locus);
103✔
5698

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

5705
static bool vcode_can_elide_bounds(vcode_reg_t reg, vcode_reg_t left,
48,884✔
5706
                                   vcode_reg_t right, vcode_reg_t dir)
5707
{
5708
   int64_t dconst;
48,884✔
5709
   if (vcode_reg_const(dir, &dconst)) {
48,884✔
5710
      int64_t lconst, rconst;
39,962✔
5711
      if (vcode_reg_const(left, &lconst) && vcode_reg_const(right, &rconst)) {
39,962✔
5712
         const bool is_null = (dconst == RANGE_TO && lconst > rconst)
30,061✔
5713
            || (dconst == RANGE_DOWNTO && rconst > lconst);
63,552✔
5714

5715
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
33,492✔
5716

5717
         const bool ok_static =
66,984✔
5718
            (dconst == RANGE_TO
5719
             && bounds->low >= lconst && bounds->high <= rconst)
30,061✔
5720
            || (dconst == RANGE_DOWNTO
7,899✔
5721
                && bounds->low >= rconst && bounds->high <= lconst)
3,431✔
5722
            || (!is_null && (reg == left || reg == right));
38,170✔
5723

5724
         return ok_static;
39,162✔
5725
      }
5726
      else if (vcode_reg_kind(reg) == VCODE_TYPE_REAL) {
6,470✔
5727
         vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
6,076✔
5728
         vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
6,076✔
5729

5730
         assert(lbounds->kind == VCODE_TYPE_REAL);
6,076✔
5731
         assert(rbounds->kind == VCODE_TYPE_REAL);
6,076✔
5732

5733
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
6,076✔
5734
         assert(bounds->kind == VCODE_TYPE_REAL);
6,076✔
5735

5736
         if (isfinite(bounds->rlow) && lbounds->rlow == -DBL_MAX
6,076✔
5737
             && isfinite(bounds->rhigh) && rbounds->rhigh == DBL_MAX) {
5,670✔
5738
            // Covers the complete double range so can never overflow
5739
            return true;
5740
         }
5741
      }
5742
   }
5743

5744
   return false;
5745
}
5746

5747
static void emit_bounds_check(vcode_op_t kind, vcode_reg_t reg,
49,457✔
5748
                              vcode_reg_t left, vcode_reg_t right,
5749
                              vcode_reg_t dir, vcode_reg_t locus,
5750
                              vcode_reg_t hint)
5751
{
5752
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
2,344,692✔
5753
      if (other->args.items[0] == reg && other->args.items[1] == left
13,354✔
5754
          && other->args.items[2] == right && other->args.items[3] == dir)
579✔
5755
         return;
5756
   }
5757

5758
   if (vcode_can_elide_bounds(reg, left, right, dir)) {
48,884✔
5759
      emit_comment("Elided bounds check for r%d", reg);
34,484✔
5760
      return;
34,484✔
5761
   }
5762

5763
   op_t *op = vcode_add_op(kind);
14,400✔
5764
   vcode_add_arg(op, reg);
14,400✔
5765
   vcode_add_arg(op, left);
14,400✔
5766
   vcode_add_arg(op, right);
14,400✔
5767
   vcode_add_arg(op, dir);
14,400✔
5768
   vcode_add_arg(op, locus);
14,400✔
5769
   vcode_add_arg(op, hint);
14,400✔
5770

5771
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
14,400✔
5772
                "locus argument to bounds check must be a debug locus");
5773
   VCODE_ASSERT(vcode_reg_kind(hint) == VCODE_TYPE_DEBUG_LOCUS,
14,400✔
5774
                "hint argument to bounds check must be a debug locus");
5775
}
5776

5777
void emit_range_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
8,807✔
5778
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5779
{
5780
   emit_bounds_check(VCODE_OP_RANGE_CHECK, reg, left, right, dir, locus, hint);
8,807✔
5781
}
8,807✔
5782

5783
void emit_index_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
40,650✔
5784
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5785
{
5786
   emit_bounds_check(VCODE_OP_INDEX_CHECK, reg, left, right, dir, locus, hint);
40,650✔
5787
}
40,650✔
5788

5789
void emit_package_scope(vcode_reg_t locus)
45✔
5790
{
5791
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_SCOPE);
45✔
5792
   vcode_add_arg(op, locus);
45✔
5793

5794
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
45✔
5795
                "locus argument to package scope must be a debug locus");
5796
}
45✔
5797

5798
void emit_array_scope(vcode_reg_t locus, vcode_type_t type)
632✔
5799
{
5800
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_SCOPE);
632✔
5801
   vcode_add_arg(op, locus);
632✔
5802
   op->type = type;
632✔
5803

5804
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
632✔
5805
                "locus argument to array scope must be a debug locus");
5806
}
632✔
5807

5808
void emit_record_scope(vcode_reg_t locus, vcode_type_t type)
1,596✔
5809
{
5810
   op_t *op = vcode_add_op(VCODE_OP_RECORD_SCOPE);
1,596✔
5811
   vcode_add_arg(op, locus);
1,596✔
5812
   op->type = type;
1,596✔
5813

5814
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,596✔
5815
                "locus argument to record scope must be a debug locus");
5816
}
1,596✔
5817

5818
void emit_pop_scope(void)
2,273✔
5819
{
5820
   vcode_add_op(VCODE_OP_POP_SCOPE);
2,273✔
5821
}
2,273✔
5822

5823
vcode_reg_t emit_debug_locus(object_t *obj)
120,473✔
5824
{
5825
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DEBUG_LOCUS) {
6,461,558✔
5826
      if (other->object == obj)
980,572✔
5827
         return other->result;
10,151✔
5828
   }
5829

5830
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_LOCUS);
110,322✔
5831
   op->object = obj;
110,322✔
5832

5833
   return (op->result = vcode_add_reg(vtype_debug_locus()));
110,322✔
5834
}
5835

UNCOV
5836
void emit_debug_out(vcode_reg_t reg)
×
5837
{
UNCOV
5838
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_OUT);
×
UNCOV
5839
   vcode_add_arg(op, reg);
×
UNCOV
5840
}
×
5841

5842
void emit_cover_stmt(uint32_t tag)
1,006✔
5843
{
5844
   op_t *op = vcode_add_op(VCODE_OP_COVER_STMT);
1,006✔
5845
   op->tag = tag;
1,006✔
5846
}
1,006✔
5847

5848
void emit_cover_branch(uint32_t tag)
495✔
5849
{
5850
   op_t *op = vcode_add_op(VCODE_OP_COVER_BRANCH);
495✔
5851
   op->tag = tag;
495✔
5852
}
495✔
5853

5854
void emit_cover_toggle(vcode_reg_t signal, uint32_t tag)
313✔
5855
{
5856
   op_t *op = vcode_add_op(VCODE_OP_COVER_TOGGLE);
313✔
5857
   vcode_add_arg(op, signal);
313✔
5858
   op->tag = tag;
313✔
5859
}
313✔
5860

5861
void emit_cover_state(vcode_reg_t signal, vcode_reg_t low, uint32_t tag)
12✔
5862
{
5863
   op_t *op = vcode_add_op(VCODE_OP_COVER_STATE);
12✔
5864
   vcode_add_arg(op, signal);
12✔
5865
   vcode_add_arg(op, low);
12✔
5866
   op->tag = tag;
12✔
5867
}
12✔
5868

5869
void emit_cover_expr(uint32_t tag)
856✔
5870
{
5871
   op_t *op = vcode_add_op(VCODE_OP_COVER_EXPR);
856✔
5872
   op->tag = tag;
856✔
5873
}
856✔
5874

5875
void emit_unreachable(vcode_reg_t locus)
617✔
5876
{
5877
   op_t *op = vcode_add_op(VCODE_OP_UNREACHABLE);
617✔
5878
   if (locus != VCODE_INVALID_REG)
617✔
5879
      vcode_add_arg(op, locus);
137✔
5880
}
617✔
5881

5882
vcode_reg_t emit_undefined(vcode_type_t type, vcode_type_t bounds)
1,457✔
5883
{
5884
   active_unit->flags |= UNIT_UNDEFINED;
1,457✔
5885

5886
   op_t *op = vcode_add_op(VCODE_OP_UNDEFINED);
1,457✔
5887
   op->result = vcode_add_reg(type);
1,457✔
5888
   vcode_reg_data(op->result)->bounds = bounds;
1,457✔
5889

5890
   return op->result;
1,457✔
5891
}
5892

5893
void emit_debug_info(const loc_t *loc)
1,373,228✔
5894
{
5895
   if (!loc_invalid_p(loc))
1,373,228✔
5896
      vcode_block_data()->last_loc = *loc;
1,345,290✔
5897
}
1,373,228✔
5898

5899
vcode_reg_t emit_link_var(vcode_reg_t context, ident_t name, vcode_type_t type)
4,174✔
5900
{
5901
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_VAR) {
155,819✔
5902
      if (other->args.items[0] == context && other->ident == name)
8,878✔
5903
         return other->result;
1,640✔
5904
   }
5905

5906
   op_t *op = vcode_add_op(VCODE_OP_LINK_VAR);
2,534✔
5907
   vcode_add_arg(op, context);
2,534✔
5908
   op->ident = name;
2,534✔
5909

5910
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
2,534✔
5911
                "first argument to link var must be context");
5912

5913
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
2,534✔
5914
      op->result = vcode_add_reg(vtype_pointer(vtype_elem(type)));
79✔
5915
      vcode_reg_data(op->result)->bounds = vtype_bounds(type);
79✔
5916
   }
5917
   else {
5918
      op->result = vcode_add_reg(vtype_pointer(type));
2,455✔
5919
      vcode_reg_data(op->result)->bounds = type;
2,455✔
5920
   }
5921

5922
   return op->result;
2,534✔
5923
}
5924

5925
vcode_reg_t emit_link_package(ident_t name)
24,886✔
5926
{
5927
   VCODE_FOR_EACH_OP(other) {
1,119,408✔
5928
      if (other->kind == VCODE_OP_LINK_PACKAGE && other->ident == name)
1,107,892✔
5929
         return other->result;
8,017✔
5930
      else if (other->kind == VCODE_OP_PACKAGE_INIT && other->func == name)
1,099,875✔
5931
         return other->result;
5,353✔
5932
   }
5933

5934
   op_t *op = vcode_add_op(VCODE_OP_LINK_PACKAGE);
11,516✔
5935
   op->ident = name;
11,516✔
5936

5937
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
11,516✔
5938

5939
   return (op->result = vcode_add_reg(vtype_context(name)));
11,516✔
5940
}
5941

5942
void emit_enter_state(vcode_reg_t state, vcode_reg_t strong)
768✔
5943
{
5944
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ENTER_STATE) {
1,836✔
UNCOV
5945
      if (other->args.items[0] == state)
×
5946
         return;
5947
   }
5948

5949
   op_t *op = vcode_add_op(VCODE_OP_ENTER_STATE);
768✔
5950
   vcode_add_arg(op, state);
768✔
5951
   if (strong != VCODE_INVALID_REG)
768✔
5952
      vcode_add_arg(op, strong);
18✔
5953

5954
   VCODE_ASSERT(vcode_reg_kind(state) == VCODE_TYPE_INT,
768✔
5955
                "state must have integer type");
5956
   VCODE_ASSERT(strong == VCODE_INVALID_REG
768✔
5957
                || vtype_eq(vcode_reg_type(strong), vtype_bool()),
5958
                "strong argument not is not boolean");
5959
}
5960

5961
vcode_reg_t emit_reflect_value(vcode_reg_t value, vcode_reg_t context,
45✔
5962
                               vcode_reg_t locus, vcode_reg_t bounds)
5963
{
5964
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_VALUE);
45✔
5965
   vcode_add_arg(op, value);
45✔
5966
   vcode_add_arg(op, context);
45✔
5967
   vcode_add_arg(op, locus);
45✔
5968
   if (bounds != VCODE_INVALID_REG)
45✔
5969
      vcode_add_arg(op, bounds);
6✔
5970

5971
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
45✔
5972
                "invalid reflect value context argument");
5973
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
45✔
5974
                "locus argument to reflect value must be a debug locus");
5975

5976
   return (op->result = vcode_add_reg(vtype_access(vtype_opaque())));
45✔
5977
}
5978

5979
vcode_reg_t emit_reflect_subtype(vcode_reg_t context, vcode_reg_t locus,
42✔
5980
                                 vcode_reg_t bounds)
5981
{
5982
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_SUBTYPE);
42✔
5983
   vcode_add_arg(op, context);
42✔
5984
   vcode_add_arg(op, locus);
42✔
5985
   if (bounds != VCODE_INVALID_REG)
42✔
UNCOV
5986
      vcode_add_arg(op, bounds);
×
5987

5988
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
42✔
5989
                "invalid reflect value context argument");
5990
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
42✔
5991
                "locus argument to reflect value must be a debug locus");
5992

5993
   return (op->result = vcode_add_reg(vtype_access(vtype_opaque())));
42✔
5994
}
5995

5996
vcode_reg_t emit_function_trigger(ident_t func, const vcode_reg_t *args,
217✔
5997
                                  int nargs)
5998
{
5999
   op_t *op = vcode_add_op(VCODE_OP_FUNCTION_TRIGGER);
217✔
6000
   op->func = func;
217✔
6001

6002
   for (int i = 0; i < nargs; i++)
576✔
6003
      vcode_add_arg(op, args[i]);
359✔
6004

6005
   return (op->result = vcode_add_reg(vtype_trigger()));
217✔
6006
}
6007

6008
vcode_reg_t emit_or_trigger(vcode_reg_t left, vcode_reg_t right)
34✔
6009
{
6010
   op_t *op = vcode_add_op(VCODE_OP_OR_TRIGGER);
34✔
6011
   vcode_add_arg(op, left);
34✔
6012
   vcode_add_arg(op, right);
34✔
6013

6014
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_TRIGGER,
34✔
6015
                "or trigger left argument must be trigger");
6016
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_TRIGGER,
34✔
6017
                "or trigger right argument must be trigger");
6018

6019
   return (op->result = vcode_add_reg(vtype_trigger()));
34✔
6020
}
6021

6022
vcode_reg_t emit_cmp_trigger(vcode_reg_t left, vcode_reg_t right)
63✔
6023
{
6024
   op_t *op = vcode_add_op(VCODE_OP_CMP_TRIGGER);
63✔
6025
   vcode_add_arg(op, left);
63✔
6026
   vcode_add_arg(op, right);
63✔
6027

6028
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_SIGNAL,
63✔
6029
                "cmp trigger left argument must be signal");
6030
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_INT,
63✔
6031
                "cmp trigger right argument must be integer");
6032

6033
   return (op->result = vcode_add_reg(vtype_trigger()));
63✔
6034
}
6035

6036
void emit_add_trigger(vcode_reg_t trigger)
365✔
6037
{
6038
   op_t *op = vcode_add_op(VCODE_OP_ADD_TRIGGER);
365✔
6039
   vcode_add_arg(op, trigger);
365✔
6040

6041
   VCODE_ASSERT(vcode_reg_kind(trigger) == VCODE_TYPE_TRIGGER,
365✔
6042
                "add trigger argument must be trigger");
6043
}
365✔
6044

6045
vcode_reg_t emit_port_conversion(vcode_reg_t driving, vcode_reg_t effective)
279✔
6046
{
6047
   op_t *op = vcode_add_op(VCODE_OP_PORT_CONVERSION);
279✔
6048
   vcode_add_arg(op, driving);
279✔
6049
   if (effective != VCODE_INVALID_REG && effective != driving)
279✔
6050
      vcode_add_arg(op, effective);
18✔
6051

6052
   VCODE_ASSERT(vcode_reg_kind(driving) == VCODE_TYPE_CLOSURE,
279✔
6053
                "port conversion argument must be a closure");
6054
   VCODE_ASSERT(effective == VCODE_INVALID_REG
279✔
6055
                || vcode_reg_kind(effective) == VCODE_TYPE_CLOSURE,
6056
                "port conversion argument must be a closure");
6057

6058
   return (op->result = vcode_add_reg(vtype_conversion()));
279✔
6059
}
6060

6061
vcode_reg_t emit_bind_external(vcode_reg_t locus, ident_t scope,
200✔
6062
                               vcode_type_t type, vcode_type_t bounds)
6063
{
6064
   op_t *op = vcode_add_op(VCODE_OP_BIND_EXTERNAL);
200✔
6065
   vcode_add_arg(op, locus);
200✔
6066
   op->type  = type;
200✔
6067
   op->ident = scope;
200✔
6068

6069
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
200✔
6070
                "bind external argument must be locus");
6071

6072
   op->result = vcode_add_reg(vtype_pointer(type));
200✔
6073
   vcode_reg_data(op->result)->bounds = bounds;
200✔
6074
   return op->result;
200✔
6075
}
6076

6077
void emit_put_conversion(vcode_reg_t cf, vcode_reg_t target, vcode_reg_t count,
414✔
6078
                         vcode_reg_t values)
6079
{
6080
   op_t *op = vcode_add_op(VCODE_OP_PUT_CONVERSION);
414✔
6081
   vcode_add_arg(op, cf);
414✔
6082
   vcode_add_arg(op, target);
414✔
6083
   vcode_add_arg(op, count);
414✔
6084
   vcode_add_arg(op, values);
414✔
6085

6086
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
414✔
6087
                "put conversion target is not signal");
6088
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
414✔
6089
                "put conversion net count is not offset type");
6090
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
414✔
6091
                "signal cannot be values argument for put conversion");
6092
   VCODE_ASSERT(vcode_reg_kind(cf) == VCODE_TYPE_CONVERSION,
414✔
6093
                "cf argument to put conversion must be conversion function");
6094
}
414✔
6095

6096
void emit_convert_in(vcode_reg_t conv, vcode_reg_t nets, vcode_reg_t count)
354✔
6097
{
6098
   op_t *op = vcode_add_op(VCODE_OP_CONVERT_IN);
354✔
6099
   vcode_add_arg(op, conv);
354✔
6100
   vcode_add_arg(op, nets);
354✔
6101
   vcode_add_arg(op, count);
354✔
6102

6103
   VCODE_ASSERT(vcode_reg_kind(conv) == VCODE_TYPE_CONVERSION,
354✔
6104
                "conv argument to convert must be a port conversion");
6105
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
354✔
6106
                "nets argument to convert must be a signal");
6107
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
354✔
6108
                "count argument to convert must be offset");
6109
}
354✔
6110

6111
void emit_convert_out(vcode_reg_t conv, vcode_reg_t nets, vcode_reg_t count)
396✔
6112
{
6113
   op_t *op = vcode_add_op(VCODE_OP_CONVERT_OUT);
396✔
6114
   vcode_add_arg(op, conv);
396✔
6115
   vcode_add_arg(op, nets);
396✔
6116
   vcode_add_arg(op, count);
396✔
6117

6118
   VCODE_ASSERT(vcode_reg_kind(conv) == VCODE_TYPE_CONVERSION,
396✔
6119
                "conv argument to convert must be a port conversion");
6120
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
396✔
6121
                "nets argument to convert must be a signal");
6122
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
396✔
6123
                "count argument to convert must be offset");
6124
}
396✔
6125

6126
void emit_bind_foreign(vcode_reg_t spec, vcode_reg_t length, vcode_reg_t locus)
276✔
6127
{
6128
   op_t *op = vcode_add_op(VCODE_OP_BIND_FOREIGN);
276✔
6129
   vcode_add_arg(op, spec);
276✔
6130
   vcode_add_arg(op, length);
276✔
6131
   if (locus != VCODE_INVALID_REG)
276✔
6132
      vcode_add_arg(op, locus);
141✔
6133

6134
   VCODE_ASSERT(vcode_reg_kind(spec) == VCODE_TYPE_POINTER,
276✔
6135
                "spec argument to bind foreign must be a pointer");
6136
   VCODE_ASSERT(vcode_reg_kind(length) == VCODE_TYPE_OFFSET,
276✔
6137
                "length argument to bind foreign must be offset");
6138
   VCODE_ASSERT(locus == VCODE_INVALID_REG
276✔
6139
                || vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
6140
                "locus argument to bind foreign value must be a debug locus");
6141
}
276✔
6142

6143
vcode_reg_t emit_instance_name(vcode_reg_t kind)
812✔
6144
{
6145
   op_t *op = vcode_add_op(VCODE_OP_INSTANCE_NAME);
812✔
6146
   vcode_add_arg(op, kind);
812✔
6147

6148
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
812✔
6149
                "kind argument to instance name must be offset");
6150

6151
   vcode_type_t vchar = vtype_char();
812✔
6152
   return (op->result = vcode_add_reg(vtype_uarray(1, vchar, vchar)));
812✔
6153
}
6154

6155
void emit_deposit_signal(vcode_reg_t signal, vcode_reg_t count,
177✔
6156
                         vcode_reg_t values)
6157
{
6158
   op_t *op = vcode_add_op(VCODE_OP_DEPOSIT_SIGNAL);
177✔
6159
   vcode_add_arg(op, signal);
177✔
6160
   vcode_add_arg(op, count);
177✔
6161
   vcode_add_arg(op, values);
177✔
6162

6163
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
177✔
6164
                "deposit signal target is not signal");
6165
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
177✔
6166
                "deposit signal count is not offset type");
6167
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
177✔
6168
                "signal cannot be values argument for deposit signal");
6169
}
177✔
6170

6171
void vcode_walk_dependencies(vcode_unit_t vu, vcode_dep_fn_t fn, void *ctx)
29,824✔
6172
{
6173
   vcode_state_t state;
29,824✔
6174
   vcode_state_save(&state);
29,824✔
6175

6176
   vcode_select_unit(vu);
29,824✔
6177

6178
   const int nblocks = vcode_count_blocks();
29,824✔
6179
   for (int i = 0; i < nblocks; i++) {
139,772✔
6180
      vcode_select_block(i);
109,948✔
6181

6182
      const int nops = vcode_count_ops();
109,948✔
6183
      for (int op = 0; op < nops; op++) {
1,520,281✔
6184
         switch (vcode_get_op(op)) {
1,410,333✔
6185
         case VCODE_OP_LINK_PACKAGE:
9,589✔
6186
            (*fn)(vcode_get_ident(op), ctx);
9,589✔
6187
            break;
9,589✔
6188
         case VCODE_OP_FCALL:
52,829✔
6189
         case VCODE_OP_PCALL:
6190
         case VCODE_OP_CLOSURE:
6191
         case VCODE_OP_PROTECTED_INIT:
6192
         case VCODE_OP_PACKAGE_INIT:
6193
         case VCODE_OP_FUNCTION_TRIGGER:
6194
            (*fn)(vcode_get_func(op), ctx);
52,829✔
6195
            break;
52,829✔
6196
         default:
6197
            break;
6198
         }
6199
      }
6200
   }
6201

6202
   vcode_state_restore(&state);
29,824✔
6203
}
29,824✔
6204

6205
#ifdef DEBUG
UNCOV
6206
static void shape_mismatch(vcode_unit_t vu, vcode_unit_t shape,
×
6207
                           const char *fmt, ...)
6208
{
UNCOV
6209
   vcode_select_unit(vu);
×
UNCOV
6210
   vcode_dump();
×
6211

UNCOV
6212
   vcode_select_unit(shape);
×
UNCOV
6213
   vcode_dump();
×
6214

UNCOV
6215
   va_list ap;
×
6216
   va_start(ap, fmt);
×
6217

UNCOV
6218
   diag_t *d = diag_new(DIAG_FATAL, NULL);
×
6219
   diag_printf(d, "instance %s does not match shape %s", istr(vu->name),
×
6220
               istr(shape->name));
UNCOV
6221
   diag_vhint(d, NULL, fmt, ap);
×
6222
   diag_emit(d);
×
6223

UNCOV
6224
   va_end(ap);
×
6225

6226
   fatal_exit(1);
×
6227
}
6228
#endif
6229

6230
void vcode_check_shape(vcode_unit_t vu, vcode_unit_t shape)
90✔
6231
{
6232
#ifdef DEBUG
6233
   assert(shape->kind == VCODE_UNIT_SHAPE);
90✔
6234
   assert(vu->kind == VCODE_UNIT_INSTANCE);
90✔
6235

6236
   if (shape->vars.count <= vu->vars.count) {
90✔
6237
      for (int i = 0; i < shape->vars.count; i++) {
371✔
6238
         var_t *v = var_array_nth_ptr(&(vu->vars), i);
281✔
6239
         var_t *s = var_array_nth_ptr(&(shape->vars), i);
281✔
6240

6241
         if (v->name != s->name)
281✔
UNCOV
6242
            shape_mismatch(vu, shape, "var %d name %s != %s", i, istr(v->name),
×
6243
                           istr(s->name));
6244
         else if (v->flags != s->flags)
281✔
UNCOV
6245
            shape_mismatch(vu, shape, "var %d flags %x != %x", i, v->flags,
×
6246
                           s->flags);
6247
         // XXX: not possible to compare types at the moment
6248
      }
6249
   }
6250
   else
UNCOV
6251
      shape_mismatch(vu, shape, "shape vars %d > unit vars %d",
×
6252
                     shape->vars.count, vu->vars.count);
6253

6254
   if (shape->context != NULL)
90✔
6255
      vcode_check_shape(vu->context, shape->context);
×
6256
#endif
6257
}
90✔
6258

6259
#if VCODE_CHECK_UNIONS
6260
#define OP_USE_COUNT_U0(x)                                              \
6261
   (OP_HAS_IDENT(x) + OP_HAS_FUNC(x) + OP_HAS_ADDRESS(x))
6262
#define OP_USE_COUNT_U1(x)                                              \
6263
   (OP_HAS_CMP(x) + OP_HAS_VALUE(x) + OP_HAS_REAL(x) +                  \
6264
    OP_HAS_COMMENT(x) + OP_HAS_DIM(x) + OP_HAS_TARGET(x) +              \
6265
    OP_HAS_HOPS(x) + OP_HAS_FIELD(x) + OP_HAS_TAG(x))
6266

6267
__attribute__((constructor))
6268
static void vcode_check_unions(void)
6269
{
6270
   printf("sizeof(op_t) = %ld\n", sizeof(op_t));
6271
   for (int i = 0; i < 256; i++) {
6272
      assert(OP_USE_COUNT_U0(i) <= 1);
6273
      assert(OP_USE_COUNT_U1(i) <= 1);
6274
   }
6275
}
6276
#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